Introduction
This document is the beginning of a tutorial on using R Markdown to mix prose and code together for creating reproducible scientific documents. This document is adapted from a tutorial that Mike Frank and Chris Hartgerink taught together at SIPS 2017.
In short: R Markdown allows you to create documents that are compiled with code, producing your next scientific paper.
Learning goals
By the end of this tutorial you should:
- Know what Markdown is and how the syntax works
- See how to integrate code and data in R Markdown
- Be able to knit an R Markdown document
Getting Started
Fire up Rstudio and create a new R Markdown file. File > New File > R Markdown. Name the file whatever you’d like. Under “Default Output Formats”, click the radio button next to Word.
If you click on “Knit” (or hit CMD+SHIFT+K
on a Mac or CTRL+SHIFT+K
on a PC) the R Markdown file will run and generate all results and present you with a PDF file, HTML file, or a Word file. If RStudio requests you to install packages, click yes and see whether everything works to begin with. If you haven’t already, you might be asked to save the file first.
We need that before we teach you more about R Markdown. But you should feel good if you get here already, because honestly, you’re about 80% of the way to being able to write basic R Markdown files. It’s that easy.
Structure of an R Markdown file
An R Markdown file contains several parts. Most essential are the header, the body text, and code chunks.
Body text
The body of the document is where you actually write your reports. This is primarily written in the Markdown format, which is explained in the Markdown syntax section.
The beauty of R Markdown is, however, that you can evaluate R
code right in the text. To do this, you start inline code with `r, type the code you want to run, and close it again with a `. Usually, this key is below the escape (ESC
) key or next to the left SHIFT button.
For example, if you want to have the result of 48 minus 35 in your text, you type ` r 48-35`, which returns 13. Please note that if you return a value with many decimals, it will also print these depending on your settings (for example, 3.1415927).
Code chunks
In the section above we introduced you to running code inside text, but often you need to take several steps in order to get to the result you need. And you don’t want to do data cleaning in the text! This is why there are code chunks. A simple example is a code chunk loading packages.
First, insert a code chunk by going to Code->Insert code chunk
or by pressing CMD+OPTION+I
on a Mac or CTRL+ALT+I
on a PC. Inside this code chunk you can then type for example, library(ggplot2)
and create an object x
.
library(ggplot2)
x <- 1 + 1
If you do not want to have the contents of the code chunk put into your document, you include echo=FALSE
at the start of the code chunk. We can now use the contents from the above code chunk to print results (e.g., x=2).
These code chunks can contain whatever you need, including tables, and figures (which we will go into more later). Note that all code chunks regard the location of the R Markdown as the working directory, so when you try to read in data use the relative path in.
Markdown syntax
Markdown is one of the simplest document languages around, that is an open standard and can be converted into .tex
, .docx
, .html
, .pdf
, etc. This is the main workhorse of R Markdown and is very powerful. You can learn Markdown in five (!) minutes Other resources include http://rmarkdown.rstudio.com/authoring_basics.html, and this cheat sheet.
You can do some pretty cool tricks with Markdown, but these are the basics:
- It’s easy to get
*italic*
or **bold**
.
- You can get headings using
# heading1
for first level, ## heading2
for second-level, and ### heading3
for third level. Make sure you leave a space after the #
!
- Lists are delimited with
*
for each entry.
- You can write links by writing
[here's my link](http://foo.com)
.
If you want a more extensive description of all the potential of Markdown, this introduction to Markdown is highly detailed.
The great thing about Markdown is that it works almost everywhere! Github, OSF, slack, many wikis, and even in text documents it looks pretty good.
Exercises
- Outlining using headings is a really great way to keep things organized! Try making a bunch of headings (i.e., first, second, and third level as described above) in your new markdown file, and then recompiling your document.
- Add a table of contents. This will involve going to the header of the document (the
YAML
), and adding some options to the word document
bit. You want it to look like this (indentation must be correct):
output:
word_document:
toc: true
Now recompile. Looks nice, right?
Graphs and Tables
We’re going to want more libraries loaded (for now we’re loading them inline). If you’ve never used these packages before, you might need to install them!
library(knitr)
library(ggplot2)
library(broom)
Graphs
It’s really easy to include graphs, like this one. (Using the mtcars
dataset that comes with ggplot2).
qplot(hp, mpg, col = factor(cyl), data = mtcars)

All you have to do is make the plot and it will render straight into the text.
External graphics can also be included, as follows:
knitr::include_graphics("path/to/file")
Tables
There are many ways to make good-looking tables using R Markdown, depending on your display purpose.
The knitr
package (which powers R Markdown) comes with the kable
function. It’s versatile and makes perfectly reasonable tables. It also has a digits
argument for controlling rounding.
For HTML tables, there is the DT
package, which provides datatable
– these are pretty and interactive javascript-based tables that you can click on and search in. Not great for static documents though.
For APA manuscripts, it can also be helpful to use the xtable
package, which creates very flexible LaTeX tables. These can be tricky to get right but they are completely customizable provided you want to google around and learn a bit about tex.
We recommend starting with kable
:
kable(head(mtcars), digits = 1)
Mazda RX4 |
21.0 |
6 |
160 |
110 |
3.9 |
2.6 |
16.5 |
0 |
1 |
4 |
4 |
Mazda RX4 Wag |
21.0 |
6 |
160 |
110 |
3.9 |
2.9 |
17.0 |
0 |
1 |
4 |
4 |
Datsun 710 |
22.8 |
4 |
108 |
93 |
3.9 |
2.3 |
18.6 |
1 |
1 |
4 |
1 |
Hornet 4 Drive |
21.4 |
6 |
258 |
110 |
3.1 |
3.2 |
19.4 |
1 |
0 |
3 |
1 |
Hornet Sportabout |
18.7 |
8 |
360 |
175 |
3.1 |
3.4 |
17.0 |
0 |
0 |
3 |
2 |
Valiant |
18.1 |
6 |
225 |
105 |
2.8 |
3.5 |
20.2 |
1 |
0 |
3 |
1 |
Statistics
It’s also really easy to include statistical tests of various types.
For this, an option is the broom
package, which formats the outputs of various tests really nicely. Paired with knitr’s kable
you can make very simple tables in just a few lines of code.
mod <- lm(mpg ~ hp + cyl, data = mtcars)
kable(tidy(mod), digits = 3)
(Intercept) |
36.908 |
2.191 |
16.847 |
0.000 |
hp |
-0.019 |
0.015 |
-1.275 |
0.213 |
cyl |
-2.265 |
0.576 |
-3.933 |
0.000 |
Of course, cleaning these up can take some work. For example, we’d need to rename a bunch of fields to make this table have the labels we wanted (e.g., to turn hp
into Horsepower
).
We often need APA-formatted statistics. We can compute them first, and then print them inline.
ts <- t.test(mpg ~ am, data = mtcars)
There’s a statistically-significant difference in miles per gallon for cars with automatic vs. manual transmissions (t(18.33)=−3.77, p=0.001).
To insert these stats inline I wrote e.g. round(ts$parameter, 2)
inside an inline code block.
Note that rounding can occasionally get you in trouble here, because it’s very easy to have an output of p=0 when in fact p can never be exactly equal to 0. Nonetheless, this can help you prevent rounding errors and the wrath of statcheck
.
LS0tCnRpdGxlOiAiUiBNYXJrZG93biBmb3Igd3JpdGluZyByZXByb2R1Y2libGUgc2NpZW50aWZpYyBwYXBlcnMiCmF1dGhvcjogJ0FkYXB0ZWQgZnJvbSB3b3JrIGJ5IFtNaWtlIEZyYW5rXShtYWlsdG86bWNmcmFua0BzdGFuZm9yZC5lZHUpIGFuZCBbQ2hyaXMgSGFydGdlcmlua10obWFpbHRvOmNocmlzQGxpYnNjaWUub3JnKScKZGF0ZTogCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OiBUUlVFCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFCi0tLQoKCmBgYHtyLCBlY2hvPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQpvcHRzX2NodW5rJHNldChlY2hvPVRSVUUsIAogICAgICAgICAgICAgICB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCAKICAgICAgICAgICAgICAgY2FjaGU9RkFMU0UpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KClRoaXMgZG9jdW1lbnQgaXMgdGhlIGJlZ2lubmluZyBvZiBhIHR1dG9yaWFsIG9uIHVzaW5nIFIgTWFya2Rvd24gdG8gbWl4IHByb3NlIGFuZCBjb2RlIHRvZ2V0aGVyIGZvciBjcmVhdGluZyByZXByb2R1Y2libGUgc2NpZW50aWZpYyBkb2N1bWVudHMuIFRoaXMgZG9jdW1lbnQgaXMgYWRhcHRlZCBmcm9tIFthIHR1dG9yaWFsIHRoYXQgTWlrZSBGcmFuayBhbmQgQ2hyaXMgSGFydGdlcmluayB0YXVnaHQgdG9nZXRoZXIgYXQgU0lQUyAyMDE3XShodHRwczovL2dpdGh1Yi5jb20vbWNmcmFuay9ybWFya2Rvd24td29ya3Nob3ApLgoKSW4gc2hvcnQ6IFIgTWFya2Rvd24gYWxsb3dzIHlvdSB0byBjcmVhdGUgZG9jdW1lbnRzIHRoYXQgYXJlIGNvbXBpbGVkIHdpdGggY29kZSwgcHJvZHVjaW5nIHlvdXIgbmV4dCBzY2llbnRpZmljIHBhcGVyLgoKIyMgTGVhcm5pbmcgZ29hbHMKCkJ5IHRoZSBlbmQgb2YgdGhpcyB0dXRvcmlhbCB5b3Ugc2hvdWxkOgoKKiBLbm93IHdoYXQgTWFya2Rvd24gaXMgYW5kIGhvdyB0aGUgc3ludGF4IHdvcmtzIAoqIFNlZSBob3cgdG8gaW50ZWdyYXRlIGNvZGUgYW5kIGRhdGEgaW4gUiBNYXJrZG93bgoqIEJlIGFibGUgdG8gKmtuaXQqIGFuIFIgTWFya2Rvd24gZG9jdW1lbnQKCiMgR2V0dGluZyBTdGFydGVkCgpGaXJlIHVwIFJzdHVkaW8gYW5kIGNyZWF0ZSBhIG5ldyBSIE1hcmtkb3duIGZpbGUuIEZpbGUgPiBOZXcgRmlsZSA+IFIgTWFya2Rvd24uIE5hbWUgdGhlIGZpbGUgd2hhdGV2ZXIgeW91J2QgbGlrZS4gVW5kZXIgIkRlZmF1bHQgT3V0cHV0IEZvcm1hdHMiLCBjbGljayB0aGUgcmFkaW8gYnV0dG9uIG5leHQgdG8gV29yZC4gCgpJZiB5b3UgY2xpY2sgb24gIktuaXQiIChvciBoaXQgYENNRCtTSElGVCtLYCBvbiBhIE1hYyBvciBgQ1RSTCtTSElGVCtLYCBvbiBhIFBDKSB0aGUgUiBNYXJrZG93biBmaWxlIHdpbGwgcnVuIGFuZCBnZW5lcmF0ZSBhbGwgcmVzdWx0cyBhbmQgcHJlc2VudCB5b3Ugd2l0aCBhIFBERiBmaWxlLCBIVE1MIGZpbGUsIG9yIGEgV29yZCBmaWxlLiBJZiBSU3R1ZGlvIHJlcXVlc3RzIHlvdSB0byBpbnN0YWxsIHBhY2thZ2VzLCBjbGljayB5ZXMgYW5kIHNlZSB3aGV0aGVyIGV2ZXJ5dGhpbmcgd29ya3MgdG8gYmVnaW4gd2l0aC4gSWYgeW91IGhhdmVuJ3QgYWxyZWFkeSwgeW91IG1pZ2h0IGJlIGFza2VkIHRvIHNhdmUgdGhlIGZpbGUgZmlyc3QuCgpXZSBuZWVkIHRoYXQgYmVmb3JlIHdlIHRlYWNoIHlvdSBtb3JlIGFib3V0IFIgTWFya2Rvd24uIEJ1dCB5b3Ugc2hvdWxkIGZlZWwgZ29vZCBpZiB5b3UgZ2V0IGhlcmUgYWxyZWFkeSwgYmVjYXVzZSBob25lc3RseSwgeW91J3JlIGFib3V0IDgwJSBvZiB0aGUgd2F5IHRvIGJlaW5nIGFibGUgdG8gd3JpdGUgYmFzaWMgUiBNYXJrZG93biBmaWxlcy4gSXQncyBfdGhhdF8gZWFzeS4KCiMgU3RydWN0dXJlIG9mIGFuIFIgTWFya2Rvd24gZmlsZQoKQW4gUiBNYXJrZG93biBmaWxlIGNvbnRhaW5zIHNldmVyYWwgcGFydHMuIE1vc3QgZXNzZW50aWFsIGFyZSB0aGUgaGVhZGVyLCB0aGUgYm9keSB0ZXh0LCBhbmQgY29kZSBjaHVua3MuCgojIyBIZWFkZXIKCkhlYWRlcnMgaW4gUiBNYXJrZG93biBmaWxlcyBjb250YWluIHNvbWUgbWV0YWRhdGEgYWJvdXQgeW91ciBkb2N1bWVudCwgd2hpY2ggeW91IGNhbiBjdXN0b21pemUgdG8geW91ciBsaWtpbmcuIEJlbG93IGlzIGEgc2ltcGxlIGV4YW1wbGUgdGhhdCBwdXJlbHkgc3RhdGVzIHRoZSB0aXRsZSwgYXV0aG9yIG5hbWUocyksIGRhdGUsIGFuZCBvdXRwdXQgZm9ybWF0LiAKCmBgYHlhbWwKLS0tCnRpdGxlOiAiVW50aXRsZWQiCmF1dGhvcjogIk5BTUUiCmRhdGU6ICJKdWx5IDI4LCAyMDE3IgpvdXRwdXQ6IGh0bWxfZG9jdW1lbnQKLS0tCmBgYAoKPiBQcm9UaXA6IFRoZSBoZWFkZXIgaXMgd3JpdHRlbiBpbiAiWUFNTCIsIHdoaWNoIG1lYW5zICJ5ZXQgYW5vdGhlciBtYXJrdXAgbGFuZ3VhZ2UuIiBZb3UgZG9uJ3QgbmVlZCB0byBrbm93IHRoYXQsIGFuZCBkb24ndCB3b3JyeSBhYm91dCBpdC4gSnVzdCBtYWtlIHN1cmUgeW91IGFyZSBjYXJlZnVsIHdpdGggaW5kZW50aW5nLCBhcyBZQU1MIGRvZXMgY2FyZSBhYm91dCB0aGF0LiAKCkZvciBub3csIGdvIGFoZWFkIGFuZCBtYWtlIHN1cmUgdGhhdCBgaHRtbF9kb2N1bWVudGAgaXMgc2V0IHRvIGB3b3JkX2RvY3VtZW50YCwgZXhjZXB0IGlmIHlvdSBoYXZlIHN0cm9uZyBwcmVmZXJlbmNlcyBmb3IgYEhUTUxgIG9yIGBQREZgLl5bTm90ZTogdG8gY3JlYXRlIFBERiBkb2N1bWVudHMgeW91IGFsc28gbmVlZCBhIFRlWCBpbnN0YWxsYXRpb24uIERvbid0IGtub3cgd2hhdCB0aGF0IGlzPyBZb3UgcHJvYmFibHkgZG9uJ3QgaGF2ZSBpdCB0aGVuLiBNb3JlIGluZm8gYmVsb3cuXQoKIyMgQm9keSB0ZXh0CgpUaGUgYm9keSBvZiB0aGUgZG9jdW1lbnQgaXMgd2hlcmUgeW91IGFjdHVhbGx5IHdyaXRlIHlvdXIgcmVwb3J0cy4gVGhpcyBpcyBwcmltYXJpbHkgd3JpdHRlbiBpbiB0aGUgTWFya2Rvd24gZm9ybWF0LCB3aGljaCBpcyBleHBsYWluZWQgaW4gdGhlIFtNYXJrZG93biBzeW50YXhdKCNtYXJrZG93bi1zeW50YXgpIHNlY3Rpb24uCgpUaGUgYmVhdXR5IG9mIFIgTWFya2Rvd24gaXMsIGhvd2V2ZXIsIHRoYXQgeW91IGNhbiBldmFsdWF0ZSBgUmAgY29kZSByaWdodCBpbiB0aGUgdGV4dC4gVG8gZG8gdGhpcywgeW91IHN0YXJ0IGlubGluZSBjb2RlIHdpdGggXGByLCB0eXBlIHRoZSBjb2RlIHlvdSB3YW50IHRvIHJ1biwgYW5kIGNsb3NlIGl0IGFnYWluIHdpdGggYSBcYC4gVXN1YWxseSwgdGhpcyBrZXkgaXMgYmVsb3cgdGhlIGVzY2FwZSAoYEVTQ2ApIGtleSAgb3IgbmV4dCB0byB0aGUgbGVmdCBTSElGVCBidXR0b24uCgpGb3IgZXhhbXBsZSwgaWYgeW91IHdhbnQgdG8gaGF2ZSB0aGUgcmVzdWx0IG9mIDQ4IG1pbnVzIDM1IGluIHlvdXIgdGV4dCwgeW91IHR5cGUgXGAgciA0OC0zNVxgLCB3aGljaCByZXR1cm5zIGByIDQ4IC0gMzVgLiBQbGVhc2Ugbm90ZSB0aGF0IGlmIHlvdSByZXR1cm4gYSB2YWx1ZSB3aXRoIG1hbnkgZGVjaW1hbHMsIGl0IHdpbGwgYWxzbyBwcmludCB0aGVzZSBkZXBlbmRpbmcgb24geW91ciBzZXR0aW5ncyAoZm9yIGV4YW1wbGUsIGByIHBpYCkuCgojIyBDb2RlIGNodW5rcwoKSW4gdGhlIHNlY3Rpb24gYWJvdmUgd2UgaW50cm9kdWNlZCB5b3UgdG8gcnVubmluZyBjb2RlIGluc2lkZSB0ZXh0LCBidXQgb2Z0ZW4geW91IG5lZWQgdG8gdGFrZSBzZXZlcmFsIHN0ZXBzIGluIG9yZGVyIHRvIGdldCB0byB0aGUgcmVzdWx0IHlvdSBuZWVkLiBBbmQgeW91IGRvbid0IHdhbnQgdG8gZG8gZGF0YSBjbGVhbmluZyBpbiB0aGUgdGV4dCEgVGhpcyBpcyB3aHkgdGhlcmUgYXJlIGNvZGUgY2h1bmtzLiBBIHNpbXBsZSBleGFtcGxlIGlzIGEgY29kZSBjaHVuayBsb2FkaW5nIHBhY2thZ2VzLiAKCkZpcnN0LCBpbnNlcnQgYSBjb2RlIGNodW5rIGJ5IGdvaW5nIHRvIGBDb2RlLT5JbnNlcnQgY29kZSBjaHVua2Agb3IgYnkgcHJlc3NpbmcgYENNRCtPUFRJT04rSWAgb24gYSBNYWMgb3IgYENUUkwrQUxUK0lgIG9uIGEgUEMuIEluc2lkZSB0aGlzIGNvZGUgY2h1bmsgeW91IGNhbiB0aGVuIHR5cGUgZm9yIGV4YW1wbGUsIGBsaWJyYXJ5KGdncGxvdDIpYCBhbmQgY3JlYXRlIGFuIG9iamVjdCBgeGAuIAoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKCnggPC0gMSArIDEKYGBgCgpJZiB5b3UgZG8gbm90IHdhbnQgdG8gaGF2ZSB0aGUgY29udGVudHMgb2YgdGhlIGNvZGUgY2h1bmsgcHV0IGludG8geW91ciBkb2N1bWVudCwgeW91IGluY2x1ZGUgYGVjaG89RkFMU0VgIGF0IHRoZSBzdGFydCBvZiB0aGUgY29kZSBjaHVuay4gV2UgY2FuIG5vdyB1c2UgdGhlIGNvbnRlbnRzIGZyb20gdGhlIGFib3ZlIGNvZGUgY2h1bmsgdG8gcHJpbnQgcmVzdWx0cyAoZS5nLiwgJHg9YHIgeGAkKS4KClRoZXNlIGNvZGUgY2h1bmtzIGNhbiBjb250YWluIHdoYXRldmVyIHlvdSBuZWVkLCBpbmNsdWRpbmcgdGFibGVzLCBhbmQgZmlndXJlcyAod2hpY2ggd2Ugd2lsbCBnbyBpbnRvIG1vcmUgbGF0ZXIpLiBOb3RlIHRoYXQgYWxsIGNvZGUgY2h1bmtzIHJlZ2FyZCB0aGUgbG9jYXRpb24gb2YgdGhlIFIgTWFya2Rvd24gYXMgdGhlIHdvcmtpbmcgZGlyZWN0b3J5LCBzbyB3aGVuIHlvdSB0cnkgdG8gcmVhZCBpbiBkYXRhIHVzZSB0aGUgcmVsYXRpdmUgcGF0aCBpbi4KCgojIE1hcmtkb3duIHN5bnRheAoKTWFya2Rvd24gaXMgb25lIG9mIHRoZSBzaW1wbGVzdCBkb2N1bWVudCBsYW5ndWFnZXMgYXJvdW5kLCB0aGF0IGlzIGFuIG9wZW4gc3RhbmRhcmQgYW5kIGNhbiBiZSBjb252ZXJ0ZWQgaW50byBgLnRleGAsIGAuZG9jeGAsIGAuaHRtbGAsIGAucGRmYCwgZXRjLiBUaGlzIGlzIHRoZSBtYWluIHdvcmtob3JzZSBvZiBSIE1hcmtkb3duIGFuZCBpcyB2ZXJ5IHBvd2VyZnVsLiBZb3UgY2FuIFtsZWFybiBNYXJrZG93biBpbiBmaXZlICghKSBtaW51dGVzXShodHRwczovL2xlYXJueGlueW1pbnV0ZXMuY29tL2RvY3MvbWFya2Rvd24vKSBPdGhlciByZXNvdXJjZXMgaW5jbHVkZSBbaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9hdXRob3JpbmdfYmFzaWNzLmh0bWxdKCksIGFuZCBbdGhpcyBjaGVhdCBzaGVldF0oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTUvMDIvcm1hcmtkb3duLWNoZWF0c2hlZXQucGRmKS4gCgpZb3UgY2FuIGRvIHNvbWUgcHJldHR5IGNvb2wgdHJpY2tzIHdpdGggTWFya2Rvd24sIGJ1dCB0aGVzZSBhcmUgdGhlIGJhc2ljczoKCiogSXQncyBlYXN5IHRvIGdldCBgKml0YWxpYypgIG9yIGAqKmJvbGQqKmAuIAoqIFlvdSBjYW4gZ2V0IGhlYWRpbmdzIHVzaW5nIGAjIGhlYWRpbmcxYCBmb3IgZmlyc3QgbGV2ZWwsIGAjIyBoZWFkaW5nMmAgZm9yIHNlY29uZC1sZXZlbCwgYW5kIGAjIyMgaGVhZGluZzNgIGZvciB0aGlyZCBsZXZlbC4gTWFrZSBzdXJlIHlvdSBsZWF2ZSBhIHNwYWNlIGFmdGVyIHRoZSBgI2AhCiogTGlzdHMgYXJlIGRlbGltaXRlZCB3aXRoIGAqYCBmb3IgZWFjaCBlbnRyeS4KKiBZb3UgY2FuIHdyaXRlIGxpbmtzIGJ5IHdyaXRpbmcgYFtoZXJlJ3MgbXkgbGlua10oaHR0cDovL2Zvby5jb20pYC4KCklmIHlvdSB3YW50IGEgbW9yZSBleHRlbnNpdmUgZGVzY3JpcHRpb24gb2YgYWxsIHRoZSBwb3RlbnRpYWwgb2YgTWFya2Rvd24sIFt0aGlzIGludHJvZHVjdGlvbiB0byBNYXJrZG93bl0oaHR0cHM6Ly9kYXJpbmdmaXJlYmFsbC5uZXQvcHJvamVjdHMvbWFya2Rvd24vKSBpcyBoaWdobHkgZGV0YWlsZWQuCgpUaGUgZ3JlYXQgdGhpbmcgYWJvdXQgTWFya2Rvd24gaXMgdGhhdCBpdCB3b3JrcyBhbG1vc3QgZXZlcnl3aGVyZSEgR2l0aHViLCBPU0YsIHNsYWNrLCBtYW55IHdpa2lzLCBhbmQgZXZlbiBpbiB0ZXh0IGRvY3VtZW50cyBpdCBsb29rcyBwcmV0dHkgZ29vZC4gIAoKIyMgRXhlcmNpc2VzCgoxLiBPdXRsaW5pbmcgdXNpbmcgaGVhZGluZ3MgaXMgYSByZWFsbHkgZ3JlYXQgd2F5IHRvIGtlZXAgdGhpbmdzIG9yZ2FuaXplZCEgVHJ5IG1ha2luZyBhIGJ1bmNoIG9mIGhlYWRpbmdzIChpLmUuLCAqZmlyc3QqLCAqc2Vjb25kKiwgYW5kICp0aGlyZCBsZXZlbCogYXMgZGVzY3JpYmVkIGFib3ZlKSBpbiB5b3VyIG5ldyBtYXJrZG93biBmaWxlLCBhbmQgdGhlbiByZWNvbXBpbGluZyB5b3VyIGRvY3VtZW50LiAKMi4gQWRkIGEgdGFibGUgb2YgY29udGVudHMuIFRoaXMgd2lsbCBpbnZvbHZlIGdvaW5nIHRvIHRoZSBoZWFkZXIgb2YgdGhlIGRvY3VtZW50ICh0aGUgYFlBTUxgKSwgYW5kIGFkZGluZyBzb21lIG9wdGlvbnMgdG8gdGhlIGB3b3JkIGRvY3VtZW50YCBiaXQuIFlvdSB3YW50IGl0IHRvIGxvb2sgbGlrZSB0aGlzIChpbmRlbnRhdGlvbiBtdXN0IGJlIGNvcnJlY3QpOgoKYGBgeWFtbApvdXRwdXQ6IAogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKYGBgCgpOb3cgcmVjb21waWxlLiBMb29rcyBuaWNlLCByaWdodD9eW1Byby10aXA6IHlvdSBjYW4gc3BlY2lmeSBob3cgZGVlcCB0aGUgVE9DIHNob3VsZCBnbyBieSBhZGRpbmcgYHRvY19kZXB0aDogMmAgdG8gZ28gdHdvIGxldmVscyBkZWVwXQoKIyAgR3JhcGhzIGFuZCBUYWJsZXMgCgpXZSdyZSBnb2luZyB0byB3YW50IG1vcmUgbGlicmFyaWVzIGxvYWRlZCAoZm9yIG5vdyB3ZSdyZSBsb2FkaW5nIHRoZW0gaW5saW5lKS4gSWYgeW91J3ZlIG5ldmVyIHVzZWQgdGhlc2UgcGFja2FnZXMgYmVmb3JlLCB5b3UgbWlnaHQgbmVlZCB0byBpbnN0YWxsIHRoZW0hCgpgYGB7cn0KbGlicmFyeShrbml0cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGJyb29tKQpgYGAKIyMgR3JhcGhzCgpJdCdzIHJlYWxseSBlYXN5IHRvIGluY2x1ZGUgZ3JhcGhzLCBsaWtlIHRoaXMgb25lLiAoVXNpbmcgdGhlIGBtdGNhcnNgIGRhdGFzZXQgdGhhdCBjb21lcyB3aXRoIGdncGxvdDIpLgoKYGBge3J9CnFwbG90KGhwLCBtcGcsIGNvbCA9IGZhY3RvcihjeWwpLCBkYXRhID0gbXRjYXJzKQpgYGAKCkFsbCB5b3UgaGF2ZSB0byBkbyBpcyBtYWtlIHRoZSBwbG90IGFuZCBpdCB3aWxsIHJlbmRlciBzdHJhaWdodCBpbnRvIHRoZSB0ZXh0LiAKCkV4dGVybmFsIGdyYXBoaWNzIGNhbiBhbHNvIGJlIGluY2x1ZGVkLCBhcyBmb2xsb3dzOgoKYGBge3IgZXZhbCA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygicGF0aC90by9maWxlIikKYGBgCgojIyBUYWJsZXMKClRoZXJlIGFyZSBtYW55IHdheXMgdG8gbWFrZSBnb29kLWxvb2tpbmcgdGFibGVzIHVzaW5nIFIgTWFya2Rvd24sIGRlcGVuZGluZyBvbiB5b3VyIGRpc3BsYXkgcHVycG9zZS4gCgotIFRoZSBga25pdHJgIHBhY2thZ2UgKHdoaWNoIHBvd2VycyBSIE1hcmtkb3duKSBjb21lcyB3aXRoIHRoZSBga2FibGVgIGZ1bmN0aW9uLiBJdCdzIHZlcnNhdGlsZSBhbmQgbWFrZXMgcGVyZmVjdGx5IHJlYXNvbmFibGUgdGFibGVzLiBJdCBhbHNvIGhhcyBhIGBkaWdpdHNgIGFyZ3VtZW50IGZvciBjb250cm9sbGluZyByb3VuZGluZy4gCgotIEZvciBIVE1MIHRhYmxlcywgdGhlcmUgaXMgdGhlIGBEVGAgcGFja2FnZSwgd2hpY2ggcHJvdmlkZXMgYGRhdGF0YWJsZWAgLS0gdGhlc2UgYXJlIHByZXR0eSBhbmQgaW50ZXJhY3RpdmUgamF2YXNjcmlwdC1iYXNlZCB0YWJsZXMgdGhhdCB5b3UgY2FuIGNsaWNrIG9uIGFuZCBzZWFyY2ggaW4uIE5vdCBncmVhdCBmb3Igc3RhdGljIGRvY3VtZW50cyB0aG91Z2guIAoKLSBGb3IgQVBBIG1hbnVzY3JpcHRzLCBpdCBjYW4gYWxzbyBiZSBoZWxwZnVsIHRvIHVzZSB0aGUgYHh0YWJsZWAgcGFja2FnZSwgd2hpY2ggY3JlYXRlcyB2ZXJ5IGZsZXhpYmxlIExhVGVYIHRhYmxlcy4gVGhlc2UgY2FuIGJlIHRyaWNreSB0byBnZXQgcmlnaHQgYnV0IHRoZXkgYXJlIGNvbXBsZXRlbHkgY3VzdG9taXphYmxlIHByb3ZpZGVkIHlvdSB3YW50IHRvIGdvb2dsZSBhcm91bmQgYW5kIGxlYXJuIGEgYml0IGFib3V0IHRleC4gCgpXZSByZWNvbW1lbmQgc3RhcnRpbmcgd2l0aCBga2FibGVgOgoKYGBge3J9CmthYmxlKGhlYWQobXRjYXJzKSwgZGlnaXRzID0gMSkKYGBgCgojIyBTdGF0aXN0aWNzCgpJdCdzIGFsc28gcmVhbGx5IGVhc3kgdG8gaW5jbHVkZSBzdGF0aXN0aWNhbCB0ZXN0cyBvZiB2YXJpb3VzIHR5cGVzLiAKCkZvciB0aGlzLCBhbiBvcHRpb24gaXMgdGhlIGBicm9vbWAgcGFja2FnZSwgd2hpY2ggZm9ybWF0cyB0aGUgb3V0cHV0cyBvZiB2YXJpb3VzIHRlc3RzIHJlYWxseSBuaWNlbHkuIFBhaXJlZCB3aXRoIGtuaXRyJ3MgYGthYmxlYCB5b3UgY2FuIG1ha2UgdmVyeSBzaW1wbGUgdGFibGVzIGluIGp1c3QgYSBmZXcgbGluZXMgb2YgY29kZS4gCgpgYGB7cn0KbW9kIDwtIGxtKG1wZyB+IGhwICsgY3lsLCBkYXRhID0gbXRjYXJzKQprYWJsZSh0aWR5KG1vZCksIGRpZ2l0cyA9IDMpCmBgYAoKT2YgY291cnNlLCBjbGVhbmluZyB0aGVzZSB1cCBjYW4gdGFrZSBzb21lIHdvcmsuIEZvciBleGFtcGxlLCB3ZSdkIG5lZWQgdG8gcmVuYW1lIGEgYnVuY2ggb2YgZmllbGRzIHRvIG1ha2UgdGhpcyB0YWJsZSBoYXZlIHRoZSBsYWJlbHMgd2Ugd2FudGVkIChlLmcuLCB0byB0dXJuIGBocGAgaW50byBgSG9yc2Vwb3dlcmApLiAKCldlIG9mdGVuIG5lZWQgQVBBLWZvcm1hdHRlZCBzdGF0aXN0aWNzLiBXZSBjYW4gY29tcHV0ZSB0aGVtIGZpcnN0LCBhbmQgdGhlbiBwcmludCB0aGVtIGlubGluZS4KCmBgYHtyfQp0cyA8LSB0LnRlc3QobXBnIH4gYW0sIGRhdGEgPSBtdGNhcnMpCmBgYAoKPiBUaGVyZSdzIGEgc3RhdGlzdGljYWxseS1zaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIG1pbGVzIHBlciBnYWxsb24gZm9yIGNhcnMgd2l0aCBhdXRvbWF0aWMgdnMuIG1hbnVhbCB0cmFuc21pc3Npb25zICgkdChgciByb3VuZCh0cyRwYXJhbWV0ZXIsMilgKSA9IGByIHJvdW5kKHRzJHN0YXRpc3RpYywyKWAkLCAkcCA9IGByIHJvdW5kKHRzJHAudmFsdWUsMylgJCkuIAoKVG8gaW5zZXJ0IHRoZXNlIHN0YXRzIGlubGluZSBJIHdyb3RlIGUuZy4gYHJvdW5kKHRzJHBhcmFtZXRlciwgMilgIGluc2lkZSBhbiBpbmxpbmUgY29kZSBibG9jay5eW0FQQSB3b3VsZCByZXF1aXJlIG9taXNzaW9uIG9mIHRoZSBsZWFkaW5nIHplcm8uIGBwYXBhamE6OnByaW50cCgpYCB3aWxsIGxldCB5b3UgZG8gdGhhdCwgc2VlIGJlbG93Ll0KCk5vdGUgdGhhdCByb3VuZGluZyBjYW4gb2NjYXNpb25hbGx5IGdldCB5b3UgaW4gdHJvdWJsZSBoZXJlLCBiZWNhdXNlIGl0J3MgdmVyeSBlYXN5IHRvIGhhdmUgYW4gb3V0cHV0IG9mICRwID0gMCQgd2hlbiBpbiBmYWN0ICRwJCBjYW4gbmV2ZXIgYmUgZXhhY3RseSBlcXVhbCB0byAwLiBOb25ldGhlbGVzcywgdGhpcyBjYW4gaGVscCB5b3UgcHJldmVudCByb3VuZGluZyBlcnJvcnMgYW5kIHRoZSB3cmF0aCBvZiBgc3RhdGNoZWNrYC4KCiMjIEV4ZXJjaXNlCgoxLiBVc2luZyB0aGUgYG10Y2Fyc2AgZGF0YXNldCwgaW5zZXJ0IGEgdGFibGUgYW5kIGEgZ3JhcGggb2YgeW91ciBjaG9pY2UgaW50byB0aGUgZG9jdW1lbnQuXltJZiB5b3UncmUgZmVlbGluZyB1bmluc3BpcmVkLCB0cnkgYGhpc3QobXRjYXJzJG1wZylgLl0KYGBge3J9CgoKYGBgCltTZWUgdGhlIHR1dG9yaWFsIHRoYXQgTWlrZSBGcmFuayBhbmQgQ2hyaXMgSGFydGdlcmluayB0YXVnaHQgdG9nZXRoZXIgYXQgU0lQUyAyMDE3IGZvciBhZGRpdGlvbmFsIGNvbnRlbnQhXShodHRwczovL2dpdGh1Yi5jb20vbWNmcmFuay9ybWFya2Rvd24td29ya3Nob3ApCg==