.Rmd
documents
With RMarkdown it is easy to create documents or webpages that include text, code and plots. During the practical sessions we will work with RMarkdown, and not with R
scripts. RMarkdown allows you to combine the code required to produce an analysis, its results, visualizations and descriptive text all in one document.
For a detailed guide on RMarkdown see R Markdown: The Definitive Guide. Most of the contents discussed here come from that source.
Compiling an R Markdown file
Essentially, an .Rmd file is just a plain text file used to store all your text and code needed to produce your final report. Although RStudio allows you to preview the output of your code, the output is not itself part of the .Rmd file. When you save and close your Rmd file and open it again later or send it to someone, the output will have disappeared (although also here, RStudio has some tricks to keep the output). The way to properly generate the output version of your Rmd file is by compiling it. This can be done in RStudio by pressing the Knit
button in the toolbar, or by pressing Shift + Ctrl + K
(Mac: Shift + Cmd + K
). This will produce an HTML file with the same name as your Rmd and located in the same folder. You can open this file in any internet browser (you don’t need an internet connection since it’s a local file) and marvel at the nicely formatted output of your hard work. Another advantage of working with RStudio is that it will open this file automatically, either in a new window or in the “Viewer” pane (you can change this in the RStudio settings).
Important: saving your Rmd file does not update the corresponding HTML file automatically. In contrast, when you compile (“Knit”), your Rmd file will be saved first.
While editing you generally want to save often (you don’t want to lose stuff if something goes wrong) but you don’t need to compile every time you make a minor change, unless you want to see what the output will look like.
Formatting text
Bold and italic text
Text in an R Markdown document (i.e. everything that is not considered code) is written in Markdown syntax. This enables you to format text by surrounding it with special characters.
Italic text is generated by surrounding the text with a pair of either underscores (_text_
) or asterisks (*text*
). Bold text uses a pair of double underscores (__text__
) or asterisks (**text**
). Bold italic text can be achieved by using a combination of the two (__*text*__
).
Lists
Unordered list items start with *
, -
, or +
, and you can nest one list within another list by indenting the sub-list, for example:
- one item
- one item
- one item
* one more item
* one more item
* one more item
The output of the above syntax would be:
- one item
- one item
- one item
- one more item
- one more item
- one more item
A numbered list can be created by starting each item with a number:
1. the first item
2. the second item
3. the third item
Output:
- the first item
- the second item
- the third item
Note: make sure to leave an empty line between text and a list for correct formatting.
Main section title: first level
Subsection: second level
Sub-subsection: third level
Sub-sub-subsection: fourth level
In general it’s not recommended to go further than 4 sub-levels of sections.
Note that you can also include a table of contents at the top of your file by specifying toc: true
in the YAML header.
Integrating text and R code
You can insert chunks of R code in your RMarkdown file by wrapping a code block inside ```{r}
and ```
.
In RStudio this is easily done by using the Insert
button in the toolbar or the keyboard shorcut Ctrl + Alt + I
(Cmd + Option + I
on macOS).
For more information, see section 2.6 of The Definitive Guide
We will demonstrete the use of R-code with various examples in the sections below so that you can familiarise yourself with the syntax.
Basic R stuff
Simple calculations
R can be used as a simple calculator. Executing code can be done in various ways. To execute the entire chunk of code:
- In RStudio: click the green arrow in the upper right corner of the code chunk
- Place your cursor inside the chunk and press
Shift + Ctrl + Enter
(Mac: Shift + Cmd + Enter
)
Code can also be run line by line by selecting a line with your cursor and pressing Ctrl + Enter
(Mac: Cmd + Enter
).
Try executing the code below using both ways: line-by-line and the entire chunk.
## [1] 2
## [1] 37
The output should be displayed either right below the code chunk or in the R console. You can change this behaviour by selecting the settings gear in the RStudio toolbar and selecting Chunk Output Inline
or Chunk Output in Console
.
You can also run all chunks in you Rmd file by pressing the Run
button in the toolbar (upper right) and then select Run All
(or using the keyboard shortcut Shift + Ctrl + R
on Windows or Shift + Cmd + R
on Mac). Note that this menu also provides additional ways of running R chunks, the most useful ones being:
Run All Chunks Above
: this executes all code chunks preceding your cursor location, starting at the top and tehn running down.
Restart R and Run All Chunks
: this will restart R and re-run your entire document. Note that this will remove all current objects and data from memory and re-starting R in a blank state. This means that any code that was run in the console and not saved in a code chunk will be lost. This might seem scary at first, but there are very good reasons to do this often. You can read more about this workflow here.
Functions
Functions are commands in R that perform certain tasks. They take inputs in the form of arguments and return their results as output. They are called using their name, followed by parentheses ()
in which the arguments are specified. There are many built-in functions in R. In addition, you can write your own functions or load other functins through the use of packages (more on that later).
As an example, we can use the function rnorm
to sample 100 draws from a Normal distribution. We assign the result (a vector of 100 random numbers) to a new variable draws
and display the first 6 values by caling the function head
on this new variable.
# sample 100 numbers from a standard normal distribution
# (mean = 0, standard deviation = 1)
draws <- rnorm(100)
head(draws)
## [1] 0.2821262847 -0.1542399503 -1.1655695370 1.2951836232 0.2953700467
## [6] -0.0005475743
Getting help in R: ?
What if instead of drawing from the standard normal distribution we want to sample from a normal with a mean of 5 and a standard deviation of 2? Knowing that rnorm
is the function to generate normally distributed numbers, we can get more information on it by executing ?rnorm
(usually you would do this in the Console, but for demonstration, we run it inside a code chunk here). This will open up the help page for the “The Normal Distribution” and all its related functions inside R, one of which is rnorm
.
Read through the documentation, can you figure out how to change the mean and standard deviation?
The solution is to specify the mean
and sd
arguments.
draws2 <- rnorm(100, mean = 5, sd = 2)
head(draws2)
## [1] 2.244972 6.682070 1.659189 2.248990 4.843019 6.949700
Each built-in R function or functions loaded through a package has a help page. In addition, there is a wealth of information through the wonderful magic of Google. Another great place to look for answers or ask questions yourself is StackOverflow.
Tidyverse
The tidyverse is a set of packages designed to make data science in R more user-friendly. It shares a common philosophy and grammar of doing data science, which can change somewhat from how base R works (though it shouldn’t be an excuse to learn how to use base R!!!).
Instead of installing each tidyverse package individually, you can install all of them simultaneously by simply calling
install.packages("tidyverse")
Note that this code won’t be executed when compiling this report, because I specified eval=FALSE
in the chunk options. Instead it should be called manually, for example in an R console.
For more information see
Visualizations
Base R
A picture often says more than words (or lines of code output) and R has a rich visualization toolbox that allows us to make powerful visualizations of our data.
For example, to visually verify that the random numbers we generated earlier (which are still stored in memory under the variables draws
and draws2
) are indeed normally distributed, we could make a histogram of them, using the hist
function.
# draws comes from a standard normal (mean = 0, sd = 1)
hist(draws)
# draws 2 comes from a normal with mean = 5, sd = 2
hist(draws2)
Note that you can customize these plots in a lot of ways. Looking at the help page of hist
or doing a quick internet search will take you a long way!
ggplot2
Although powerful, the base R visualization framework can be somewhat challenging to work with. A good alternative is the ggplot2
package, part of the larger tidyverse
which includes more useful packages for data manipulation and analysis. ggplot2
uses a visualization framework based on the grammar of graphics philosophy, which we won’t get further into here but which can be quite an intuitive way to think about data visualizations.
ggplot2
works best with a data.frame
as input. As an example, we’ll use the mtcars
data, which is available by default in every R installation (for more info on this data set, see ?mtcars
). With just a few lines, we can create already quite elegant visualizations:
library(ggplot2)
ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point()
You could perfectly recreate this plot with base R, but it’s going to take more lines of code and potential headaches. Still, both frameworks have their strengths and weaknesses and they are complementary in many ways, so it pays to learn both of them rather than stubbornly sticking to one.
There are tons of documentation and tutorials on ggplot2
to be found online. A good place to start is https://ggplot2.tidyverse.org/.
Importing data
See https://r4ds.had.co.nz/data-import.html.
Note that both the base read.csv
and the tidyverse equivalent readr::read_csv()
can both use URLs to read in data. That way you don’t have to download the data locally on your machine or worry about different versions.
## Example from HDA2020 course (https://statomics.github.io/HDA2020/)
uk_foods <- readr::read_csv(
file = "https://raw.githubusercontent.com/statOmics/HDA2020/data/ukFoods.csv",
col_names = TRUE
)
## New names:
## * `` -> ...1
## Rows: 17 Columns: 5
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): ...1
## dbl (4): England, Wales, Scotland, N.Ireland
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Summary of data
To get a quick summary of the data, you can use the summary
function. This will return some summary statistics for the columns present in the data.
## iris is a default data set available in R
## To get more info, use `?iris`
summary(iris)
## Sepal.Length Sepal.Width Petal.Length Petal.Width
## Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100
## 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300
## Median :5.800 Median :3.000 Median :4.350 Median :1.300
## Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
## 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
## Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
## Species
## setosa :50
## versicolor:50
## virginica :50
##
##
##
## [1] "data.frame"
Subsetting data
You can select subsets of a data.frame
by using square brackets []
and specifying the number(s) of the row(s) or column(s) you want to select. Alternatively, you can use the dollar sign $
to select a column using its name.
To reduce the output printed out, we will first make a subset of the iris
data containing just the first 10 rows.
# make subset of data to prevent long outputs
iris_sub <- iris[1:10, ]
iris_sub
# Select first column, single brackets returns data.frame
iris_sub[1]
# double brackets returns vector
iris_sub[[1]]
## [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9
iris_sub[["Sepal.Length"]]
## [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9
# using the dollar sign, also returns vector
iris_sub$Sepal.Length
## [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9
# Select all columns except the first one
iris_sub[-1]
# Selecting rows
iris_sub[1, ] # Select the first row
iris_sub[1:5,] # Select the first five rows
iris_sub[c(2, 4), ] # select the second and fourth rows
# columns and rows
iris_sub[1:5, "Sepal.Length"] # first 5 rows of "Sepal.Length" column
## [1] 5.1 4.9 4.7 4.6 5.0
iris_sub[3, 2] # third row, second column
## [1] 3.2
Including R object values or results in the text
You can add inline R code results by wrapping them inside `r `
. This is useful for discussing the value of a result in your text. Instead of having to copy the value of a result (which is prone to error and not robust to changes), you can just call it inside the text. For example, we could calculate the mean sepal length of the iris flowers as follow:
## [1] 5.843333
We could copy the value inside our text, but a better way is by just running the code inline as mean(iris$Sepal.Length)
surrounded by `r
and `
. So we could say that the iris flowers in our data have a mean length of 5.8433333.
Note: to actually see the value of the inline code, place your cursor inside the backticks ` `r
and press Ctrl + Enter
or Cmd + Enter
. When you knit your Rmd file and build the HTML output, the inline R code will be replaced by its output value.
Including equations
Finally, you can include equations in your text using LaTeX syntax and surrounding it by a pair of double dollar signs $$
. This is useful to specify models. For example, we can write the equation of a linear model as
$$
y_i = \beta_0 + \beta_1 x_i + \epsilon_i
$$
Which will be converted to the following output:
\[
y_i = \beta_0 + \beta_1 x_i + \epsilon_i
\]
Note that RStudio will give you a preview of what your equation will look like in the final document.
You can also include inline \(\LaTeX\) equations by using a pair of single $
signs. For example, the following sentence:
The sample mean of $y$ is given by $\bar{y}=\sum\limits_{i=1}^{n}\frac{y_i}{n}$
Will be converted to:
The sample mean of \(y\) is given by \(\bar{y}=\sum\limits_{i=1}^{n}\frac{y_i}{n}\)
Session Info
Finally, it’s always good practice to include the Session Info for your R session in your document. That way, other persons (including your future self) looking at your document can see what versions of R and loaded packages were used, which can be quite essential for reproducibility.
You can also include the date with Sys.time()
so you have a time stamp of when the report was compiled.
## [1] "2022-01-25 11:16:58 UTC"
## R version 4.1.2 (2021-11-01)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.3 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
##
## locale:
## [1] LC_CTYPE=C.UTF-8 LC_NUMERIC=C LC_TIME=C.UTF-8
## [4] LC_COLLATE=C.UTF-8 LC_MONETARY=C.UTF-8 LC_MESSAGES=C.UTF-8
## [7] LC_PAPER=C.UTF-8 LC_NAME=C LC_ADDRESS=C
## [10] LC_TELEPHONE=C LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C
##
## attached base packages:
## [1] stats graphics grDevices datasets utils methods base
##
## other attached packages:
## [1] ggplot2_3.3.5
##
## loaded via a namespace (and not attached):
## [1] tidyselect_1.1.1 xfun_0.25 bslib_0.3.0
## [4] purrr_0.3.4 colorspace_2.0-2 vctrs_0.3.8
## [7] generics_0.1.0 htmltools_0.5.2 yaml_2.2.1
## [10] utf8_1.2.2 rlang_0.4.11 jquerylib_0.1.4
## [13] pillar_1.6.3 glue_1.4.2 withr_2.4.2
## [16] DBI_1.1.1 bit64_4.0.5 lifecycle_1.0.1
## [19] stringr_1.4.0 munsell_0.5.0 gtable_0.3.0
## [22] evaluate_0.14 labeling_0.4.2 knitr_1.33
## [25] tzdb_0.1.2 fastmap_1.1.0 parallel_4.1.2
## [28] curl_4.3.2 fansi_0.5.0 highr_0.9
## [31] readr_2.0.1 renv_0.15.2 scales_1.1.1
## [34] BiocManager_1.30.16 vroom_1.5.4 jsonlite_1.7.2
## [37] farver_2.1.0 bit_4.0.4 hms_1.1.1
## [40] digest_0.6.28 stringi_1.7.4 dplyr_1.0.7
## [43] grid_4.1.2 cli_3.1.1 tools_4.1.2
## [46] magrittr_2.0.1 sass_0.4.0 tibble_3.1.5
## [49] crayon_1.4.1 pkgconfig_2.0.3 ellipsis_0.3.2
## [52] assertthat_0.2.1 rmarkdown_2.10 R6_2.5.1
## [55] compiler_4.1.2
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIFJNYXJrZG93biIKYXV0aG9yOiAiTWlsYW4gTWFsZmFpdCIKZGF0ZTogJ2ByIGZvcm1hdChTeXMuRGF0ZSgpLCAiJUIgJWQsICVZIilgJwotLS0KCiMgYC5SbWRgIGRvY3VtZW50cwoKV2l0aCBSTWFya2Rvd24gaXQgaXMgZWFzeSB0byBjcmVhdGUgZG9jdW1lbnRzIG9yIHdlYnBhZ2VzIHRoYXQgaW5jbHVkZSB0ZXh0LCBjb2RlIGFuZCBwbG90cy4gRHVyaW5nIHRoZSBwcmFjdGljYWwgc2Vzc2lvbnMgd2Ugd2lsbCB3b3JrIHdpdGggUk1hcmtkb3duLCBhbmQgbm90IHdpdGggYFJgIHNjcmlwdHMuIFJNYXJrZG93biBhbGxvd3MgeW91IHRvIGNvbWJpbmUgdGhlIGNvZGUgcmVxdWlyZWQgdG8gcHJvZHVjZSBhbiBhbmFseXNpcywgaXRzIHJlc3VsdHMsIHZpc3VhbGl6YXRpb25zIGFuZCBkZXNjcmlwdGl2ZSB0ZXh0IGFsbCBpbiBvbmUgZG9jdW1lbnQuCgpGb3IgYSBkZXRhaWxlZCBndWlkZSBvbiBSTWFya2Rvd24gc2VlIFtSIE1hcmtkb3duOiBUaGUgRGVmaW5pdGl2ZSBHdWlkZV0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLykuIE1vc3Qgb2YgdGhlIGNvbnRlbnRzIGRpc2N1c3NlZCBoZXJlIGNvbWUgZnJvbSB0aGF0IHNvdXJjZS4KCiMjIE1ldGFkYXRhCgpUaGUgbWFya2Rvd24gbm90ZWJvb2sgd2lsbCBzdGFydCB3aXRoIGEgW1lBTUxdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1lBTUwpIGhlYWRlciwgd2hpY2ggaW5jbHVkZXMgdGhlIHRpdGxlLCBuYW1lcyBvZiB0aGUgYXV0aG9ycyBhbmQgdHlwZSBvZiBSTWFya2Rvd24gZmlsZS4gV2UgdHlwaWNhbGx5IHdvcmsgd2l0aCBgaHRtbF9kb2N1bWVudGAgKHRoZSBkZWZhdWx0KS4KCmBgYCB5YW1sCi0tLQp0aXRsZTogIlRpdGxlIgphdXRob3I6ICJBdXRob3IgbmFtZXMiCmRhdGU6ICJEYXRlIgpvdXRwdXQ6ICBodG1sX2RvY3VtZW50Ci0tLQpgYGAKClRoZSBgaHRtbF9kb2N1bWVudGAgb3V0cHV0IHNwZWNpZmllcyB0aGF0IHlvdXIgZG9jdW1lbnQgd2lsbCBiZSBjb252ZXJ0ZWQgdG8gSFRNTCB3aGVuIHlvdSAia25pdCIgb3IgY29tcGlsZSBpdC4KCgojIyBDb21waWxpbmcgYW4gUiBNYXJrZG93biBmaWxlCgpFc3NlbnRpYWxseSwgYW4gLlJtZCBmaWxlIGlzIGp1c3QgYSBwbGFpbiB0ZXh0IGZpbGUgdXNlZCB0byBzdG9yZSBhbGwgeW91ciB0ZXh0IGFuZCBjb2RlIG5lZWRlZCB0byBwcm9kdWNlIHlvdXIgZmluYWwgcmVwb3J0LiBBbHRob3VnaCBSU3R1ZGlvIGFsbG93cyB5b3UgdG8gcHJldmlldyB0aGUgb3V0cHV0IG9mIHlvdXIgY29kZSwgdGhlIG91dHB1dCBpcyBub3QgaXRzZWxmIHBhcnQgb2YgdGhlIC5SbWQgZmlsZS4gV2hlbiB5b3Ugc2F2ZSBhbmQgY2xvc2UgeW91ciBSbWQgZmlsZSBhbmQgb3BlbiBpdCBhZ2FpbiBsYXRlciBvciBzZW5kIGl0IHRvIHNvbWVvbmUsIHRoZSBvdXRwdXQgd2lsbCBoYXZlIGRpc2FwcGVhcmVkIChhbHRob3VnaCBhbHNvIGhlcmUsIFJTdHVkaW8gaGFzIHNvbWUgdHJpY2tzIHRvIGtlZXAgdGhlIG91dHB1dCkuIFRoZSB3YXkgdG8gcHJvcGVybHkgZ2VuZXJhdGUgdGhlIG91dHB1dCB2ZXJzaW9uIG9mIHlvdXIgUm1kIGZpbGUgaXMgYnkgX19jb21waWxpbmdfXyBpdC4gVGhpcyBjYW4gYmUgZG9uZSBpbiBSU3R1ZGlvIGJ5IHByZXNzaW5nIHRoZSBgS25pdGAgYnV0dG9uIGluIHRoZSB0b29sYmFyLCBvciBieSBwcmVzc2luZyBgU2hpZnQgKyBDdHJsICsgS2AgKE1hYzogYFNoaWZ0ICsgQ21kICsgS2ApLiBUaGlzIHdpbGwgcHJvZHVjZSBhbiBIVE1MIGZpbGUgd2l0aCB0aGUgc2FtZSBuYW1lIGFzIHlvdXIgUm1kIGFuZCBsb2NhdGVkIGluIHRoZSBzYW1lIGZvbGRlci4gWW91IGNhbiBvcGVuIHRoaXMgZmlsZSBpbiBhbnkgaW50ZXJuZXQgYnJvd3NlciAoeW91IGRvbid0IG5lZWQgYW4gaW50ZXJuZXQgY29ubmVjdGlvbiBzaW5jZSBpdCdzIGEgbG9jYWwgZmlsZSkgYW5kIG1hcnZlbCBhdCB0aGUgbmljZWx5IGZvcm1hdHRlZCBvdXRwdXQgb2YgeW91ciBoYXJkIHdvcmsuIEFub3RoZXIgYWR2YW50YWdlIG9mIHdvcmtpbmcgd2l0aCBSU3R1ZGlvIGlzIHRoYXQgaXQgd2lsbCBvcGVuIHRoaXMgZmlsZSBhdXRvbWF0aWNhbGx5LCBlaXRoZXIgaW4gYSBuZXcgd2luZG93IG9yIGluIHRoZSAiVmlld2VyIiBwYW5lICh5b3UgY2FuIGNoYW5nZSB0aGlzIGluIHRoZSBSU3R1ZGlvIHNldHRpbmdzKS4KCl9fSW1wb3J0YW50X186IHNhdmluZyB5b3VyIFJtZCBmaWxlIGRvZXMgX19ub3RfXyB1cGRhdGUgdGhlIGNvcnJlc3BvbmRpbmcgSFRNTCBmaWxlIGF1dG9tYXRpY2FsbHkuIEluIGNvbnRyYXN0LCB3aGVuIHlvdSBjb21waWxlICgiS25pdCIpLCB5b3VyIFJtZCBmaWxlIHdpbGwgYmUgc2F2ZWQgZmlyc3QuCgpXaGlsZSBlZGl0aW5nIHlvdSBnZW5lcmFsbHkgd2FudCB0byBzYXZlIG9mdGVuICh5b3UgZG9uJ3Qgd2FudCB0byBsb3NlIHN0dWZmIGlmIHNvbWV0aGluZyBnb2VzIHdyb25nKSBidXQgeW91IGRvbid0IG5lZWQgdG8gY29tcGlsZSBldmVyeSB0aW1lIHlvdSBtYWtlIGEgbWlub3IgY2hhbmdlLCB1bmxlc3MgeW91ICB3YW50IHRvIHNlZSB3aGF0IHRoZSBvdXRwdXQgd2lsbCBsb29rIGxpa2UuCgoKIyMgRm9ybWF0dGluZyB0ZXh0CgojIyMgQm9sZCBhbmQgaXRhbGljIHRleHQKClRleHQgaW4gYW4gUiBNYXJrZG93biBkb2N1bWVudCAoaS5lLiBldmVyeXRoaW5nIHRoYXQgaXMgbm90IGNvbnNpZGVyZWQgY29kZSkgaXMgd3JpdHRlbiBpbiBbTWFya2Rvd24gc3ludGF4XShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vbWFya2Rvd24tc3ludGF4Lmh0bWwpLiBUaGlzIGVuYWJsZXMgeW91IHRvIGZvcm1hdCB0ZXh0IGJ5IHN1cnJvdW5kaW5nIGl0IHdpdGggc3BlY2lhbCBjaGFyYWN0ZXJzLgoKKkl0YWxpYyB0ZXh0KiBpcyBnZW5lcmF0ZWQgYnkgc3Vycm91bmRpbmcgdGhlIHRleHQgd2l0aCBhIHBhaXIgb2YgZWl0aGVyIHVuZGVyc2NvcmVzIChgX3RleHRfYCkgb3IgYXN0ZXJpc2tzIChgKnRleHQqYCkuICoqQm9sZCB0ZXh0KiogdXNlcyBhIHBhaXIgb2YgZG91YmxlIHVuZGVyc2NvcmVzIChgX190ZXh0X19gKSBvciBhc3Rlcmlza3MgKGAqKnRleHQqKmApLiBfXypCb2xkIGl0YWxpYyB0ZXh0Kl9fIGNhbiBiZSBhY2hpZXZlZCBieSB1c2luZyBhIGNvbWJpbmF0aW9uIG9mIHRoZSB0d28gKGBfXyp0ZXh0Kl9fYCkuCgojIyMgTGlzdHMKClVub3JkZXJlZCBsaXN0IGl0ZW1zIHN0YXJ0IHdpdGggYCpgLCBgLWAsIG9yIGArYCwgYW5kIHlvdSBjYW4gbmVzdCBvbmUgbGlzdCB3aXRoaW4gYW5vdGhlciBsaXN0IGJ5IGluZGVudGluZyB0aGUgc3ViLWxpc3QsIGZvciBleGFtcGxlOgoKYGBgbWFya2Rvd24KLSBvbmUgaXRlbQotIG9uZSBpdGVtCi0gb25lIGl0ZW0KICAgICogb25lIG1vcmUgaXRlbQogICAgKiBvbmUgbW9yZSBpdGVtCiAgICAqIG9uZSBtb3JlIGl0ZW0KYGBgCgpUaGUgb3V0cHV0IG9mIHRoZSBhYm92ZSBzeW50YXggd291bGQgYmU6CgotIG9uZSBpdGVtCi0gb25lIGl0ZW0KLSBvbmUgaXRlbQogICAgKiBvbmUgbW9yZSBpdGVtCiAgICAqIG9uZSBtb3JlIGl0ZW0KICAgICogb25lIG1vcmUgaXRlbQoKCkEgbnVtYmVyZWQgbGlzdCBjYW4gYmUgY3JlYXRlZCBieSBzdGFydGluZyBlYWNoIGl0ZW0gd2l0aCBhIG51bWJlcjoKCmBgYG1hcmtkb3duCjEuIHRoZSBmaXJzdCBpdGVtCjIuIHRoZSBzZWNvbmQgaXRlbQozLiB0aGUgdGhpcmQgaXRlbQpgYGAKCk91dHB1dDoKCjEuIHRoZSBmaXJzdCBpdGVtCjIuIHRoZSBzZWNvbmQgaXRlbQozLiB0aGUgdGhpcmQgaXRlbQoKX19Ob3RlOl9fIG1ha2Ugc3VyZSB0byBsZWF2ZSBhbiBlbXB0eSBsaW5lIGJldHdlZW4gdGV4dCBhbmQgYSBsaXN0IGZvciBjb3JyZWN0IGZvcm1hdHRpbmcuCgoKIyMjIFNlY3Rpb24gaGVhZGVycwoKU2VjdGlvbiBoZWFkZXJzIGNhbiBiZSB3cml0dGVuIHVzaW5nIGEgbnVtYmVyIG9mIFwjIHNpZ25zLCB3aGVyZSB0aGUgYW1vdW50IG9mIFwjJ3Mgc3BlY2lmaWVzIHRoZSBsZXZlbDoKCmBgYG1hcmtkb3duCiMgTWFpbiBzZWN0aW9uIHRpdGxlOiBmaXJzdCBsZXZlbAoKIyMgU3Vic2VjdGlvbjogc2Vjb25kIGxldmVsCgojIyMgU3ViLXN1YnNlY3Rpb246IHRoaXJkIGxldmVsCgojIyMjIFN1Yi1zdWItc3Vic2VjdGlvbjogZm91cnRoIGxldmVsCmBgYAoKVGhlIG91dHB1dDoKCiMgTWFpbiBzZWN0aW9uIHRpdGxlOiBmaXJzdCBsZXZlbCB7LX0KCiMjIFN1YnNlY3Rpb246IHNlY29uZCBsZXZlbCB7LX0KCiMjIyBTdWItc3Vic2VjdGlvbjogdGhpcmQgbGV2ZWwgey19CgojIyMjIFN1Yi1zdWItc3Vic2VjdGlvbjogZm91cnRoIGxldmVsIHstfQoKSW4gZ2VuZXJhbCBpdCdzIG5vdCByZWNvbW1lbmRlZCB0byBnbyBmdXJ0aGVyIHRoYW4gNCBzdWItbGV2ZWxzIG9mIHNlY3Rpb25zLgoKTm90ZSB0aGF0IHlvdSBjYW4gYWxzbyBpbmNsdWRlIGEgW3RhYmxlIG9mIGNvbnRlbnRzXShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vaHRtbC1kb2N1bWVudC5odG1sI3RhYmxlLW9mLWNvbnRlbnRzKSBhdCB0aGUgdG9wIG9mIHlvdXIgZmlsZSBieSBzcGVjaWZ5aW5nIGB0b2M6IHRydWVgIGluIHRoZSBZQU1MIGhlYWRlci4KCgojIyBJbnRlZ3JhdGluZyB0ZXh0IGFuZCBSIGNvZGUKCllvdSBjYW4gaW5zZXJ0IGNodW5rcyBvZiBSIGNvZGUgaW4geW91ciBSTWFya2Rvd24gZmlsZSBieSB3cmFwcGluZyBhIGNvZGUgYmxvY2sgaW5zaWRlIGBgYGAgYGBge3J9IGBgYGAgYW5kIGBgYGAgYGBgIGBgYGAuCgpJbiBSU3R1ZGlvIHRoaXMgaXMgZWFzaWx5IGRvbmUgYnkgdXNpbmcgdGhlIGBJbnNlcnRgIGJ1dHRvbiBpbiB0aGUgdG9vbGJhciBvciB0aGUga2V5Ym9hcmQgc2hvcmN1dCBgQ3RybCArIEFsdCArIElgIChgQ21kICsgT3B0aW9uICsgSWAgb24gbWFjT1MpLgoKRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZSBbc2VjdGlvbiAyLjZdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9yLWNvZGUuaHRtbCkgb2YgKlRoZSBEZWZpbml0aXZlIEd1aWRlKgoKV2Ugd2lsbCBkZW1vbnN0cmV0ZSB0aGUgdXNlIG9mIFItY29kZSB3aXRoIHZhcmlvdXMgZXhhbXBsZXMgaW4gdGhlIHNlY3Rpb25zIGJlbG93IHNvIHRoYXQgeW91IGNhbiBmYW1pbGlhcmlzZSB5b3Vyc2VsZiB3aXRoIHRoZSBzeW50YXguCgoKIyBCYXNpYyBSIHN0dWZmCgojIyBTaW1wbGUgY2FsY3VsYXRpb25zCgpSIGNhbiBiZSB1c2VkIGFzIGEgc2ltcGxlIGNhbGN1bGF0b3IuIEV4ZWN1dGluZyBjb2RlIGNhbiBiZSBkb25lIGluIHZhcmlvdXMgd2F5cy4gVG8gZXhlY3V0ZSB0aGUgZW50aXJlIGNodW5rIG9mIGNvZGU6CgogLSBJbiBSU3R1ZGlvOiBjbGljayB0aGUgZ3JlZW4gYXJyb3cgaW4gdGhlIHVwcGVyIHJpZ2h0IGNvcm5lciBvZiB0aGUgY29kZSBjaHVuawogLSBQbGFjZSB5b3VyIGN1cnNvciBpbnNpZGUgdGhlIGNodW5rIGFuZCBwcmVzcyBgU2hpZnQgKyBDdHJsICsgRW50ZXJgIChNYWM6IGBTaGlmdCArIENtZCArIEVudGVyYCkKCkNvZGUgY2FuIGFsc28gYmUgcnVuIGxpbmUgYnkgbGluZSBieSBzZWxlY3RpbmcgYSBsaW5lIHdpdGggeW91ciBjdXJzb3IgYW5kIHByZXNzaW5nIGBDdHJsICsgRW50ZXJgIChNYWM6IGBDbWQgKyBFbnRlcmApLgoKVHJ5IGV4ZWN1dGluZyB0aGUgY29kZSBiZWxvdyB1c2luZyBib3RoIHdheXM6IGxpbmUtYnktbGluZSBhbmQgdGhlIGVudGlyZSBjaHVuay4KCmBgYHtyfQoxKzEKKDUtMykrNyoxMC8yCmBgYAoKVGhlIG91dHB1dCBzaG91bGQgYmUgZGlzcGxheWVkIGVpdGhlciByaWdodCBiZWxvdyB0aGUgY29kZSBjaHVuayBvciBpbiB0aGUgUiBjb25zb2xlLiBZb3UgY2FuIGNoYW5nZSB0aGlzIGJlaGF2aW91ciBieSBzZWxlY3RpbmcgdGhlIHNldHRpbmdzIGdlYXIgaW4gdGhlIFJTdHVkaW8gdG9vbGJhciBhbmQgc2VsZWN0aW5nIGBDaHVuayBPdXRwdXQgSW5saW5lYCBvciBgQ2h1bmsgT3V0cHV0IGluIENvbnNvbGVgLgoKWW91IGNhbiBhbHNvIHJ1biBhbGwgY2h1bmtzIGluIHlvdSBSbWQgZmlsZSBieSBwcmVzc2luZyB0aGUgYFJ1bmAgYnV0dG9uIGluIHRoZSB0b29sYmFyICh1cHBlciByaWdodCkgYW5kIHRoZW4gc2VsZWN0IGBSdW4gQWxsYCAob3IgdXNpbmcgdGhlIGtleWJvYXJkIHNob3J0Y3V0IGBTaGlmdCArIEN0cmwgKyBSYCBvbiBXaW5kb3dzIG9yIGBTaGlmdCArIENtZCArIFJgIG9uIE1hYykuIE5vdGUgdGhhdCB0aGlzIG1lbnUgYWxzbyBwcm92aWRlcyBhZGRpdGlvbmFsIHdheXMgb2YgcnVubmluZyBSIGNodW5rcywgdGhlIG1vc3QgdXNlZnVsIG9uZXMgYmVpbmc6CgogICogYFJ1biBBbGwgQ2h1bmtzIEFib3ZlYDogdGhpcyBleGVjdXRlcyBhbGwgY29kZSBjaHVua3MgcHJlY2VkaW5nIHlvdXIgY3Vyc29yIGxvY2F0aW9uLCBzdGFydGluZyBhdCB0aGUgdG9wIGFuZCB0ZWhuIHJ1bm5pbmcgZG93bi4KICAqIGBSZXN0YXJ0IFIgYW5kIFJ1biBBbGwgQ2h1bmtzYDogdGhpcyB3aWxsIHJlc3RhcnQgUiBhbmQgcmUtcnVuIHlvdXIgZW50aXJlIGRvY3VtZW50LiBOb3RlIHRoYXQgdGhpcyB3aWxsIF9fcmVtb3ZlIGFsbCBjdXJyZW50IG9iamVjdHMgYW5kIGRhdGEgZnJvbSBtZW1vcnlfXyBhbmQgcmUtc3RhcnRpbmcgUiBpbiBhIGJsYW5rIHN0YXRlLiBUaGlzIG1lYW5zIHRoYXQgYW55IGNvZGUgdGhhdCB3YXMgcnVuIGluIHRoZSBjb25zb2xlIGFuZCBub3Qgc2F2ZWQgaW4gYSBjb2RlIGNodW5rIHdpbGwgYmUgbG9zdC4gVGhpcyBtaWdodCBzZWVtIHNjYXJ5IGF0IGZpcnN0LCBidXQgdGhlcmUgYXJlIHZlcnkgZ29vZCByZWFzb25zIHRvIGRvIHRoaXMgb2Z0ZW4uIFlvdSBjYW4gcmVhZCBtb3JlIGFib3V0IHRoaXMgd29ya2Zsb3cgW2hlcmVdKGh0dHBzOi8vcnN0YXRzLnd0Zi9zYXZlLXNvdXJjZS5odG1sI3Jlc3RhcnQtci1vZnRlbi1kdXJpbmctZGV2ZWxvcG1lbnQpLgoKIyMgQ29tbWVudGluZyBSIGNvZGUKCllvdSBjYW4gYWRkIGNvbW1lbnRzIHRvIHlvdXIgUiBjb2RlIGJ5IHN0YXJ0aW5nIGEgbGluZSB3aXRoIFwjLiBUaGlzIGlzIHVzZWZ1bCB0byBkZXNjcmliZSB3aGF0IHlvdXIgY29kZSBpcyBkb2luZyAob3Igc2hvdWxkIGJlIGRvaW5nKS4gQW5ub3RhdGluZyB5b3VyIGNvZGUgdGhpcyB3YXkgaXMgdmVyeSB1c2VmdWwgdG8gY29tbXVuaWNhdGUgYm90aCB3aXRoIG90aGVycyBhbmQgeW91ciBmdXR1cmUgc2VsZi4gVHJ5IHRvIGtlZXAgdGhlc2UgY29tbWVudHMgY2xlYXIgYnV0IHNob3J0LiBMb25nZXIgZGVzY3JpcHRpb25zIHNob3VsZCBnbyBpbiB0aGUgbWFpbiB0ZXh0IG9mIHlvdXIgUk1hcmtkb3duIGZpbGUuIENvbW1lbnRpbmcgYWxzbyBwcm92aWRlcyBhIHdheSBvZiAiZGlzYWJsaW5nIiBjb2RlIHdpdGhvdXQgaGF2aW5nIHRvIHJlbW92ZSBpdC4gTm90ZSB0aGF0IGVhY2ggbmV3IGxpbmUgb2YgYSBjb21tZW50IHNob3VsZCBiZSBwcmVjZWRlZCBieSBhIFwjLiBZb3UgY2FuIGVhc2lseSAiY29tbWVudCBvdXQiIG11bHRpcGxlIGxpbmVzIGJ5IHNlbGVjdGluZyB0aGVtIGFuZCBwcmVzc2luZyBgU2hpZnQgKyBDdHJsICsgQ2AgKE1hYzogYFNoaWZ0ICsgQ21kICsgQ2ApLgoKVHJ5IHJ1bm5pbmcgdGhlIGNodW5rIGJlbG93IGFuZCB2ZXJpZnkgdGhhdCBpdCBkb2VzIG5vdCBwcm9kdWNlIGFueSBvdXRwdXQuIFdoYXQgaGFwcGVucyBpZiB5b3UgcmVtb3ZlIG9uZSBvZiB0aGUgXCMgc2lnbnM/CgpgYGB7cn0KIyBUaGlzIGlzIGEgY29tbWVudAoKIyBUaGlzIGlzIGEgdmVyeSBsb25nIGNvbW1lbnQgc3BsaXQgb3ZlcgojIG11bHRpcGxlIGxpbmVzCgojIENvZGUgaW5zaWRlIGEgY29tbWVudCBpcyBub3QgZXhlY3V0ZWQKIyAxKzEKYGBgCgoKIyMgQXNzaWduaW5nIG9iamVjdHMgdG8gc2F2ZSByZXN1bHRzIGFuZCBwZXJmb3JtIGNhbGN1bGF0aW9ucwoKWW91IGNhbiBzYXZlIHJlc3VsdHMgb2YgZnVuY3Rpb24gY2FsbHMgb3IgY2FsY3VsYXRpb25zIGJ5IGFzc2lnbmluZyB0aGUgdmFsdWUgdG8gYSAqdmFyaWFibGUqIHVzaW5nIHRoZSBhc3NpZ24gb3BlcmF0b3IgYDwtYC4KClJ1biB0aGUgY29kZSBiZWxvdyBhbmQgdmVyaWZ5IHRoZSB2YWx1ZSBvZiBgY2AuIFlvdSBjYW4gYWxzbyBjaGVjayB0aGUgdmFsdWUgb2YgYSB2YXJpYWJsZSBieSBlbnRlcmluZyBpdCBpbiB0aGUgQ29uc29sZSBhbmQgcHJlc3NpbmcgYEVudGVyYC4KCmBgYHtyfQphIDwtIDIKYiA8LSAzCmMgPC0gYSArIGIKYwpgYGAKCk5vdGUgdGhhdCBpbiBwcmluY2lwbGUsIHlvdSBjYW4gYWxzbyB1c2UgYD1gIGZvciBhc3NpZ25tZW50LCBidXQgdGhpcyBpcyBjb25zaWRlcmVkIHRvIGJlIGJhZCBwcmFjdGljZSBiZWNhdXNlIHRoZSBlcXVhbCBzaWduIGlzIHJlc2VydmVkIGZvciBmdW5jdGlvbiBhcmd1bWVudHMgKHNlZSBuZXh0IHNlY3Rpb24pLiBTbyB5b3Ugc2hvdWxkIGFsd2F5cyB1c2UgYDwtYCBmb3IgYXNzaWdubWVudC4KCioqSGludDoqKiBhIHF1aWNrIGFuZCBlYXN5IHdheSB0byB0eXBlIGA8LWAgaW4gUlN0dWRpbyBpcyBieSB1c2luZyB0aGUgc2hvcnRjdXQgYEFsdCArIC1gIChNYWM6IGBPcHRpb24gKyAtYCkuCgoKIyMgRnVuY3Rpb25zCgpGdW5jdGlvbnMgYXJlIGNvbW1hbmRzIGluIFIgdGhhdCBwZXJmb3JtIGNlcnRhaW4gdGFza3MuIFRoZXkgdGFrZSBpbnB1dHMgaW4gdGhlIGZvcm0gb2YgKmFyZ3VtZW50cyogYW5kIHJldHVybiB0aGVpciByZXN1bHRzIGFzICpvdXRwdXQqLiBUaGV5IGFyZSBjYWxsZWQgdXNpbmcgdGhlaXIgbmFtZSwgZm9sbG93ZWQgYnkgcGFyZW50aGVzZXMgYCgpYCBpbiB3aGljaCB0aGUgYXJndW1lbnRzIGFyZSBzcGVjaWZpZWQuIFRoZXJlIGFyZSBtYW55IGJ1aWx0LWluIGZ1bmN0aW9ucyBpbiBSLiBJbiBhZGRpdGlvbiwgeW91IGNhbiB3cml0ZSB5b3VyIG93biBmdW5jdGlvbnMgb3IgbG9hZCBvdGhlciBmdW5jdGlucyB0aHJvdWdoIHRoZSB1c2Ugb2YgKnBhY2thZ2VzKiAobW9yZSBvbiB0aGF0IGxhdGVyKS4KCkFzIGFuIGV4YW1wbGUsIHdlIGNhbiB1c2UgdGhlIGZ1bmN0aW9uIGBybm9ybWAgdG8gc2FtcGxlIDEwMCBkcmF3cyBmcm9tIGEgTm9ybWFsIGRpc3RyaWJ1dGlvbi4gV2UgYXNzaWduIHRoZSByZXN1bHQgKGEgdmVjdG9yIG9mIDEwMCByYW5kb20gbnVtYmVycykgdG8gYSBuZXcgdmFyaWFibGUgYGRyYXdzYCBhbmQgZGlzcGxheSB0aGUgZmlyc3QgNiB2YWx1ZXMgYnkgY2FsaW5nIHRoZSBmdW5jdGlvbiBgaGVhZGAgb24gdGhpcyBuZXcgdmFyaWFibGUuCgpgYGB7cn0KIyBzYW1wbGUgMTAwIG51bWJlcnMgZnJvbSBhIHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24KIyAobWVhbiA9IDAsIHN0YW5kYXJkIGRldmlhdGlvbiA9IDEpCmRyYXdzIDwtIHJub3JtKDEwMCkKaGVhZChkcmF3cykKYGBgCgoKIyMgR2V0dGluZyBoZWxwIGluIFI6IGA/YAoKV2hhdCBpZiBpbnN0ZWFkIG9mIGRyYXdpbmcgZnJvbSB0aGUgc3RhbmRhcmQgbm9ybWFsIGRpc3RyaWJ1dGlvbiB3ZSB3YW50IHRvIHNhbXBsZSBmcm9tIGEgbm9ybWFsIHdpdGggYSBtZWFuIG9mIDUgYW5kIGEgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIDI/IEtub3dpbmcgdGhhdCBgcm5vcm1gIGlzIHRoZSBmdW5jdGlvbiB0byBnZW5lcmF0ZSBub3JtYWxseSBkaXN0cmlidXRlZCBudW1iZXJzLCB3ZSBjYW4gZ2V0IG1vcmUgaW5mb3JtYXRpb24gb24gaXQgYnkgZXhlY3V0aW5nIGA/cm5vcm1gICh1c3VhbGx5IHlvdSB3b3VsZCBkbyB0aGlzIGluIHRoZSBDb25zb2xlLCBidXQgZm9yIGRlbW9uc3RyYXRpb24sIHdlIHJ1biBpdCBpbnNpZGUgYSBjb2RlIGNodW5rIGhlcmUpLiBUaGlzIHdpbGwgb3BlbiB1cCB0aGUgKmhlbHAqIHBhZ2UgZm9yIHRoZSAiVGhlIE5vcm1hbCBEaXN0cmlidXRpb24iIGFuZCBhbGwgaXRzIHJlbGF0ZWQgZnVuY3Rpb25zIGluc2lkZSBSLCBvbmUgb2Ygd2hpY2ggaXMgYHJub3JtYC4KCmBgYHtyLCBldmFsID0gRkFMU0V9Cj9ybm9ybQpgYGAKClJlYWQgdGhyb3VnaCB0aGUgZG9jdW1lbnRhdGlvbiwgY2FuIHlvdSBmaWd1cmUgb3V0IGhvdyB0byBjaGFuZ2UgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbj8KClRoZSBzb2x1dGlvbiBpcyB0byBzcGVjaWZ5IHRoZSBgbWVhbmAgYW5kIGBzZGAgYXJndW1lbnRzLgoKYGBge3J9CmRyYXdzMiA8LSBybm9ybSgxMDAsIG1lYW4gPSA1LCBzZCA9IDIpCmhlYWQoZHJhd3MyKQpgYGAKCkVhY2ggYnVpbHQtaW4gUiBmdW5jdGlvbiBvciBmdW5jdGlvbnMgbG9hZGVkIHRocm91Z2ggYSBwYWNrYWdlIGhhcyBhIGhlbHAgcGFnZS4gSW4gYWRkaXRpb24sIHRoZXJlIGlzIGEgd2VhbHRoIG9mIGluZm9ybWF0aW9uIHRocm91Z2ggdGhlIHdvbmRlcmZ1bCBtYWdpYyBvZiBbR29vZ2xlXShodHRwczovL3d3dy5nb29nbGUuY29tLykuIEFub3RoZXIgZ3JlYXQgcGxhY2UgdG8gbG9vayBmb3IgYW5zd2VycyBvciBhc2sgcXVlc3Rpb25zIHlvdXJzZWxmIGlzIFtTdGFja092ZXJmbG93XShodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tLykuCgoKIyMgVGlkeXZlcnNlCgpUaGUgKnRpZHl2ZXJzZSogaXMgYSBzZXQgb2YgcGFja2FnZXMgZGVzaWduZWQgdG8gbWFrZSBkYXRhIHNjaWVuY2UgaW4gUiBtb3JlIHVzZXItZnJpZW5kbHkuCkl0IHNoYXJlcyBhIGNvbW1vbiBwaGlsb3NvcGh5IGFuZCBncmFtbWFyIG9mIGRvaW5nIGRhdGEgc2NpZW5jZSwgd2hpY2ggY2FuIGNoYW5nZSBzb21ld2hhdCBmcm9tIGhvdyBiYXNlIFIgd29ya3MgKHRob3VnaCBpdCBzaG91bGRuJ3QgYmUgYW4gZXhjdXNlIHRvIGxlYXJuIGhvdyB0byB1c2UgYmFzZSBSISEhKS4KCkluc3RlYWQgb2YgaW5zdGFsbGluZyBlYWNoICp0aWR5dmVyc2UqIHBhY2thZ2UgaW5kaXZpZHVhbGx5LCB5b3UgY2FuIGluc3RhbGwgYWxsIG9mIHRoZW0gc2ltdWx0YW5lb3VzbHkgYnkgc2ltcGx5IGNhbGxpbmcKCmBgYHtyLCBldmFsPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQpgYGAKCk5vdGUgdGhhdCB0aGlzIGNvZGUgd29uJ3QgYmUgZXhlY3V0ZWQgd2hlbiBjb21waWxpbmcgdGhpcyByZXBvcnQsIGJlY2F1c2UgSSBzcGVjaWZpZWQgYGV2YWw9RkFMU0VgIGluIHRoZSBbY2h1bmsgb3B0aW9uc10oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duL3ItY29kZS5odG1sKS4KSW5zdGVhZCBpdCBzaG91bGQgYmUgY2FsbGVkIG1hbnVhbGx5LCBmb3IgZXhhbXBsZSBpbiBhbiBSIGNvbnNvbGUuCgoKRm9yIG1vcmUgaW5mb3JtYXRpb24gc2VlCgotIDxodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLz4KLSA8aHR0cHM6Ly9yYWZhbGFiLmdpdGh1Yi5pby9kc2Jvb2svdGlkeXZlcnNlLmh0bWw+Ci0gPGh0dHBzOi8vcjRkcy5oYWQuY28ubnovPgoKCgojIyBWaXN1YWxpemF0aW9ucwoKIyMjIEJhc2UgUgoKQSBwaWN0dXJlIG9mdGVuIHNheXMgbW9yZSB0aGFuIHdvcmRzIChvciBsaW5lcyBvZiBjb2RlIG91dHB1dCkgYW5kIFIgaGFzIGEgcmljaCBbdmlzdWFsaXphdGlvbiB0b29sYm94XShodHRwczovL3JzdHVkaW8tcHVicy1zdGF0aWMuczMuYW1hem9uYXdzLmNvbS83OTUzXzRlM2VmZDViOTQxNTQ0NGNhMDY1YjExNjc4NjJjMzQ5Lmh0bWwpIHRoYXQgYWxsb3dzIHVzIHRvIG1ha2UgcG93ZXJmdWwgdmlzdWFsaXphdGlvbnMgb2Ygb3VyIGRhdGEuCgpGb3IgZXhhbXBsZSwgdG8gdmlzdWFsbHkgdmVyaWZ5IHRoYXQgdGhlIHJhbmRvbSBudW1iZXJzIHdlIGdlbmVyYXRlZCBlYXJsaWVyICh3aGljaCBhcmUgc3RpbGwgc3RvcmVkIGluIG1lbW9yeSB1bmRlciB0aGUgdmFyaWFibGVzIGBkcmF3c2AgYW5kIGBkcmF3czJgKSBhcmUgaW5kZWVkIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCB3ZSBjb3VsZCBtYWtlIGEgaGlzdG9ncmFtIG9mIHRoZW0sIHVzaW5nIHRoZSBgaGlzdGAgZnVuY3Rpb24uCgpgYGB7cn0KIyBkcmF3cyBjb21lcyBmcm9tIGEgc3RhbmRhcmQgbm9ybWFsIChtZWFuID0gMCwgc2QgPSAxKQpoaXN0KGRyYXdzKQoKIyBkcmF3cyAyIGNvbWVzIGZyb20gYSBub3JtYWwgd2l0aCBtZWFuID0gNSwgc2QgPSAyCmhpc3QoZHJhd3MyKQpgYGAKCk5vdGUgdGhhdCB5b3UgY2FuIGN1c3RvbWl6ZSB0aGVzZSBwbG90cyBpbiBhIGxvdCBvZiB3YXlzLiBMb29raW5nIGF0IHRoZSBoZWxwIHBhZ2Ugb2YgYGhpc3RgIG9yIGRvaW5nIGEgcXVpY2sgaW50ZXJuZXQgc2VhcmNoIHdpbGwgdGFrZSB5b3UgYSBsb25nIHdheSEKCgojIyMgZ2dwbG90MgoKQWx0aG91Z2ggcG93ZXJmdWwsIHRoZSBiYXNlIFIgdmlzdWFsaXphdGlvbiBmcmFtZXdvcmsgY2FuIGJlIHNvbWV3aGF0IGNoYWxsZW5naW5nIHRvIHdvcmsgd2l0aC4KQSBnb29kIGFsdGVybmF0aXZlIGlzIHRoZSBbYGdncGxvdDJgIHBhY2thZ2VdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyksIHBhcnQgb2YgdGhlIGxhcmdlciBgdGlkeXZlcnNlYCB3aGljaCBpbmNsdWRlcyBtb3JlIHVzZWZ1bCBwYWNrYWdlcyBmb3IgZGF0YSBtYW5pcHVsYXRpb24gYW5kIGFuYWx5c2lzLgpgZ2dwbG90MmAgdXNlcyBhIHZpc3VhbGl6YXRpb24gZnJhbWV3b3JrIGJhc2VkIG9uIHRoZSBbKmdyYW1tYXIgb2YgZ3JhcGhpY3MqIHBoaWxvc29waHldKGh0dHBzOi8vZ2dwbG90Mi1ib29rLm9yZy9pbnRyb2R1Y3Rpb24uaHRtbCN3aGF0LWlzLXRoZS1ncmFtbWFyLW9mLWdyYXBoaWNzKSwgd2hpY2ggd2Ugd29uJ3QgZ2V0IGZ1cnRoZXIgaW50byBoZXJlIGJ1dCB3aGljaCBjYW4gYmUgcXVpdGUgYW4gaW50dWl0aXZlIHdheSB0byB0aGluayBhYm91dCBkYXRhIHZpc3VhbGl6YXRpb25zLgoKYGdncGxvdDJgIHdvcmtzIGJlc3Qgd2l0aCBhIGBkYXRhLmZyYW1lYCBhcyBpbnB1dC4KQXMgYW4gZXhhbXBsZSwgd2UnbGwgdXNlIHRoZSBgbXRjYXJzYCBkYXRhLCB3aGljaCBpcyBhdmFpbGFibGUgYnkgZGVmYXVsdCBpbiBldmVyeSBSIGluc3RhbGxhdGlvbiAoZm9yIG1vcmUgaW5mbyBvbiB0aGlzIGRhdGEgc2V0LCBzZWUgYD9tdGNhcnNgKS4KV2l0aCBqdXN0IGEgZmV3IGxpbmVzLCB3ZSBjYW4gY3JlYXRlIGFscmVhZHkgcXVpdGUgZWxlZ2FudCB2aXN1YWxpemF0aW9uczoKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgpnZ3Bsb3QobXBnLCBhZXMoZGlzcGwsIGh3eSwgY29sb3VyID0gY2xhc3MpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKWW91IGNvdWxkIHBlcmZlY3RseSByZWNyZWF0ZSB0aGlzIHBsb3Qgd2l0aCBiYXNlIFIsIGJ1dCBpdCdzIGdvaW5nIHRvIHRha2UgbW9yZSBsaW5lcyBvZiBjb2RlIGFuZCBwb3RlbnRpYWwgaGVhZGFjaGVzLgpTdGlsbCwgYm90aCBmcmFtZXdvcmtzIGhhdmUgdGhlaXIgc3RyZW5ndGhzIGFuZCB3ZWFrbmVzc2VzIGFuZCB0aGV5IGFyZSBjb21wbGVtZW50YXJ5IGluIG1hbnkgd2F5cywgc28gaXQgcGF5cyB0byBsZWFybiBib3RoIG9mIHRoZW0gcmF0aGVyIHRoYW4gc3R1YmJvcm5seSBzdGlja2luZyB0byBvbmUuCgpUaGVyZSBhcmUgdG9ucyBvZiBkb2N1bWVudGF0aW9uIGFuZCB0dXRvcmlhbHMgb24gYGdncGxvdDJgIHRvIGJlIGZvdW5kIG9ubGluZS4KQSBnb29kIHBsYWNlIHRvIHN0YXJ0IGlzIDxodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy8+LgoKCiMjIEltcG9ydGluZyBkYXRhCgpTZWUgPGh0dHBzOi8vcjRkcy5oYWQuY28ubnovZGF0YS1pbXBvcnQuaHRtbD4uCgpOb3RlIHRoYXQgYm90aCB0aGUgYmFzZSBgcmVhZC5jc3ZgIGFuZCB0aGUgKnRpZHl2ZXJzZSogZXF1aXZhbGVudCBgcmVhZHI6OnJlYWRfY3N2KClgIGNhbiBib3RoIHVzZSBVUkxzIHRvIHJlYWQgaW4gZGF0YS4KVGhhdCB3YXkgeW91IGRvbid0IGhhdmUgdG8gZG93bmxvYWQgdGhlIGRhdGEgbG9jYWxseSBvbiB5b3VyIG1hY2hpbmUgb3Igd29ycnkgYWJvdXQgZGlmZmVyZW50IHZlcnNpb25zLgoKYGBge3J9CiMjIEV4YW1wbGUgZnJvbSBIREEyMDIwIGNvdXJzZSAoaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvL0hEQTIwMjAvKQp1a19mb29kcyA8LSByZWFkcjo6cmVhZF9jc3YoCiAgZmlsZSA9ICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL0hEQTIwMjAvZGF0YS91a0Zvb2RzLmNzdiIsCiAgY29sX25hbWVzID0gVFJVRQopCnVrX2Zvb2RzCmBgYAoKCgojIyBTdW1tYXJ5IG9mIGRhdGEKClRvIGdldCBhIHF1aWNrIHN1bW1hcnkgb2YgdGhlIGRhdGEsIHlvdSBjYW4gdXNlIHRoZSBgc3VtbWFyeWAgZnVuY3Rpb24uIFRoaXMgd2lsbCByZXR1cm4gc29tZSBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHRoZSBjb2x1bW5zIHByZXNlbnQgaW4gdGhlIGRhdGEuCgpgYGB7cn0KIyMgaXJpcyBpcyBhIGRlZmF1bHQgZGF0YSBzZXQgYXZhaWxhYmxlIGluIFIKIyMgVG8gZ2V0IG1vcmUgaW5mbywgdXNlIGA/aXJpc2AKc3VtbWFyeShpcmlzKQpjbGFzcyhpcmlzKQpgYGAKCgojIyBTdWJzZXR0aW5nIGRhdGEKCllvdSBjYW4gc2VsZWN0IHN1YnNldHMgb2YgYSBgZGF0YS5mcmFtZWAgYnkgdXNpbmcgc3F1YXJlIGJyYWNrZXRzIGBbXWAgYW5kIHNwZWNpZnlpbmcgdGhlIG51bWJlcihzKSBvZiB0aGUgcm93KHMpIG9yIGNvbHVtbihzKSB5b3Ugd2FudCB0byBzZWxlY3QuIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gdXNlIHRoZSBkb2xsYXIgc2lnbiBgJGAgdG8gc2VsZWN0IGEgY29sdW1uIHVzaW5nIGl0cyBuYW1lLgoKVG8gcmVkdWNlIHRoZSBvdXRwdXQgcHJpbnRlZCBvdXQsIHdlIHdpbGwgZmlyc3QgbWFrZSBhIHN1YnNldCBvZiB0aGUgYGlyaXNgIGRhdGEgY29udGFpbmluZyBqdXN0IHRoZSBmaXJzdCAxMCByb3dzLgoKYGBge3J9CiMgbWFrZSBzdWJzZXQgb2YgZGF0YSB0byBwcmV2ZW50IGxvbmcgb3V0cHV0cwppcmlzX3N1YiA8LSBpcmlzWzE6MTAsIF0KaXJpc19zdWIKCiMgU2VsZWN0IGZpcnN0IGNvbHVtbiwgc2luZ2xlIGJyYWNrZXRzIHJldHVybnMgZGF0YS5mcmFtZQppcmlzX3N1YlsxXQppcmlzX3N1YlsiU2VwYWwuTGVuZ3RoIl0KIyBkb3VibGUgYnJhY2tldHMgcmV0dXJucyB2ZWN0b3IKaXJpc19zdWJbWzFdXQppcmlzX3N1YltbIlNlcGFsLkxlbmd0aCJdXQojIHVzaW5nIHRoZSBkb2xsYXIgc2lnbiwgYWxzbyByZXR1cm5zIHZlY3RvcgppcmlzX3N1YiRTZXBhbC5MZW5ndGgKCiMgU2VsZWN0IGFsbCBjb2x1bW5zIGV4Y2VwdCB0aGUgZmlyc3Qgb25lCmlyaXNfc3ViWy0xXQoKIyBTZWxlY3Rpbmcgcm93cwppcmlzX3N1YlsxLCBdICMgU2VsZWN0IHRoZSBmaXJzdCByb3cKaXJpc19zdWJbMTo1LF0gIyBTZWxlY3QgdGhlIGZpcnN0IGZpdmUgcm93cwppcmlzX3N1YltjKDIsIDQpLCBdICMgc2VsZWN0IHRoZSBzZWNvbmQgYW5kIGZvdXJ0aCByb3dzCgojIGNvbHVtbnMgYW5kIHJvd3MKaXJpc19zdWJbMTo1LCAiU2VwYWwuTGVuZ3RoIl0gIyBmaXJzdCA1IHJvd3Mgb2YgIlNlcGFsLkxlbmd0aCIgY29sdW1uCmlyaXNfc3ViWzMsIDJdICAjIHRoaXJkIHJvdywgc2Vjb25kIGNvbHVtbgpgYGAKCgojIyBJbmNsdWRpbmcgUiBvYmplY3QgdmFsdWVzIG9yIHJlc3VsdHMgaW4gdGhlIHRleHQKCllvdSBjYW4gYWRkIGlubGluZSBSIGNvZGUgcmVzdWx0cyBieSB3cmFwcGluZyB0aGVtIGluc2lkZSBgYCBgciBgIGBgLiBUaGlzIGlzIHVzZWZ1bCBmb3IgZGlzY3Vzc2luZyB0aGUgdmFsdWUgb2YgYSByZXN1bHQgaW4geW91ciB0ZXh0LiBJbnN0ZWFkIG9mIGhhdmluZyB0byBjb3B5IHRoZSB2YWx1ZSBvZiBhIHJlc3VsdCAod2hpY2ggaXMgcHJvbmUgdG8gZXJyb3IgYW5kIG5vdCByb2J1c3QgdG8gY2hhbmdlcyksIHlvdSBjYW4ganVzdCBjYWxsIGl0IGluc2lkZSB0aGUgdGV4dC4gRm9yIGV4YW1wbGUsIHdlIGNvdWxkIGNhbGN1bGF0ZSB0aGUgbWVhbiBzZXBhbCBsZW5ndGggb2YgdGhlIGlyaXMgZmxvd2VycyBhcyBmb2xsb3c6CgpgYGB7cn0KbWVhbihpcmlzJFNlcGFsLkxlbmd0aCkKYGBgCgpXZSBjb3VsZCBjb3B5IHRoZSB2YWx1ZSBpbnNpZGUgb3VyIHRleHQsIGJ1dCBhIGJldHRlciB3YXkgaXMgYnkganVzdCBydW5uaW5nIHRoZSBjb2RlIGlubGluZSBhcyBgbWVhbihpcmlzJFNlcGFsLkxlbmd0aClgIHN1cnJvdW5kZWQgYnkgYGAgYHIgYGAgYW5kIGBgIGAgYGAuIFNvIHdlIGNvdWxkIHNheSB0aGF0IHRoZSBpcmlzIGZsb3dlcnMgaW4gb3VyIGRhdGEgaGF2ZSBhIG1lYW4gbGVuZ3RoIG9mIGByIG1lYW4oaXJpcyRTZXBhbC5MZW5ndGgpYC4KCk5vdGU6IHRvIGFjdHVhbGx5IHNlZSB0aGUgdmFsdWUgb2YgdGhlIGlubGluZSBjb2RlLCBwbGFjZSB5b3VyIGN1cnNvciBpbnNpZGUgdGhlIGJhY2t0aWNrcyBgYCBgIGByIGBgIGFuZCBwcmVzcyBgQ3RybCArIEVudGVyYCBvciBgQ21kICsgRW50ZXJgLiBXaGVuIHlvdSBrbml0IHlvdXIgUm1kIGZpbGUgYW5kIGJ1aWxkIHRoZSBIVE1MIG91dHB1dCwgdGhlIGlubGluZSBSIGNvZGUgd2lsbCBiZSByZXBsYWNlZCBieSBpdHMgb3V0cHV0IHZhbHVlLgoKCiMjIEluY2x1ZGluZyBlcXVhdGlvbnMKCkZpbmFsbHksIHlvdSBjYW4gaW5jbHVkZSBlcXVhdGlvbnMgaW4geW91ciB0ZXh0IHVzaW5nIFtMYVRlWF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGFUZVgpIHN5bnRheCBhbmQgc3Vycm91bmRpbmcgaXQgYnkgIGEgcGFpciBvZiBkb3VibGUgZG9sbGFyIHNpZ25zIGAkJGAuIFRoaXMgaXMgdXNlZnVsIHRvIHNwZWNpZnkgbW9kZWxzLiBGb3IgZXhhbXBsZSwgd2UgY2FuIHdyaXRlIHRoZSBlcXVhdGlvbiBvZiBhIGxpbmVhciBtb2RlbCBhcwoKYGBgCiQkCnlfaSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfaSArIFxlcHNpbG9uX2kKJCQKYGBgCgpXaGljaCB3aWxsIGJlIGNvbnZlcnRlZCB0byB0aGUgZm9sbG93aW5nIG91dHB1dDoKCiQkCnlfaSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfaSArIFxlcHNpbG9uX2kKJCQKCk5vdGUgdGhhdCBSU3R1ZGlvIHdpbGwgZ2l2ZSB5b3UgYSBwcmV2aWV3IG9mIHdoYXQgeW91ciBlcXVhdGlvbiB3aWxsIGxvb2sgbGlrZSBpbiB0aGUgZmluYWwgZG9jdW1lbnQuCgpZb3UgY2FuIGFsc28gaW5jbHVkZSBpbmxpbmUgJFxMYVRlWCQgZXF1YXRpb25zIGJ5IHVzaW5nIGEgcGFpciBvZiBzaW5nbGUgYCRgIHNpZ25zLiBGb3IgZXhhbXBsZSwgdGhlIGZvbGxvd2luZyBzZW50ZW5jZToKCmBUaGUgc2FtcGxlIG1lYW4gb2YgJHkkIGlzIGdpdmVuIGJ5ICRcYmFye3l9PVxzdW1cbGltaXRzX3tpPTF9XntufVxmcmFje3lfaX17bn0kYAoKV2lsbCBiZSBjb252ZXJ0ZWQgdG86CgpUaGUgc2FtcGxlIG1lYW4gb2YgJHkkIGlzIGdpdmVuIGJ5ICRcYmFye3l9PVxzdW1cbGltaXRzX3tpPTF9XntufVxmcmFje3lfaX17bn0kCgoKCiMgVXNlZnVsIHJlc291cmNlcwoKLSBbUiBNYXJrZG93bjogVGhlIERlZmluaXRpdmUgR3VpZGVdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi8pCi0gW1IgZm9yIERhdGEgU2NpZW5jZV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei8pIGJ5IEhhZGxleSBXaWNraGFtIChtYWluIGF1dGhvciBvZiB0aGUgYHRpZHl2ZXJzZWAgcGFja2FnZXMpCi0gW0ludHJvZHVjdGlvbiB0byBEYXRhIFNjaWVuY2VdKGh0dHBzOi8vcmFmYWxhYi5naXRodWIuaW8vZHNib29rLykgYnkgUmFmYWVsIElyaXphcnJ5Ci0gW1doYXQgVGhleSBGb3Jnb3QgdG8gVGVhY2ggWW91IEFib3V0IFJdKGh0dHBzOi8vcnN0YXRzLnd0Zi8pLCBmb3Igc29tZSB1c2VmdWwgImdvb2QgcHJhY3RpY2VzIiB0aXBzIHdoZW4gd29ya2luZyB3aXRoIFIKCgoKIyBTZXNzaW9uIEluZm8KCkZpbmFsbHksIGl0J3MgYWx3YXlzIGdvb2QgcHJhY3RpY2UgdG8gaW5jbHVkZSB0aGUgW1Nlc3Npb24gSW5mb10oKSBmb3IgeW91ciBSIHNlc3Npb24gaW4geW91ciBkb2N1bWVudC4KVGhhdCB3YXksIG90aGVyIHBlcnNvbnMgKGluY2x1ZGluZyB5b3VyIGZ1dHVyZSBzZWxmKSBsb29raW5nIGF0IHlvdXIgZG9jdW1lbnQgY2FuIHNlZSB3aGF0IHZlcnNpb25zIG9mIFIgYW5kIGxvYWRlZCBwYWNrYWdlcyB3ZXJlIHVzZWQsIHdoaWNoIGNhbiBiZSBxdWl0ZSBlc3NlbnRpYWwgZm9yIHJlcHJvZHVjaWJpbGl0eS4KCllvdSBjYW4gYWxzbyBpbmNsdWRlIHRoZSBkYXRlIHdpdGggYFN5cy50aW1lKClgIHNvIHlvdSBoYXZlIGEgdGltZSBzdGFtcCBvZiB3aGVuIHRoZSByZXBvcnQgd2FzIGNvbXBpbGVkLgoKYGBge3Igc2Vzc2lvbl9pbmZvLCBjYWNoZT1GQUxTRX0KU3lzLnRpbWUoKQpzZXNzaW9uSW5mbygpCmBgYAo=