Getting started
At a basic level, we can use R as a calculator to compute simple sums with the +
, -
, *
(for multiplication) and /
(for division) symbols.
2 + 2
[1] 4
2 - 2
[1] 0
4 * 3
[1] 12
10 / 2
[1] 5
The answer is displayed at the console with a [1]
in front of it. The 1
inside the square brackets is a place-holder to signify how many values were in the answer (in this case only one). We will talk about dealing with lists of numbers shortly…
In the case of expressions involving multiple operations, R respects the BODMAS system to decide the order in which operations should be performed.
2 + 2 *3
[1] 8
2 + (2 * 3)
[1] 8
(2 + 2) * 3
[1] 12
R is capable of more complicated arithmetic such as trigonometry and logarithms; like you would find on a fancy scientific calculator. Of course, R also has a plethora of statistical operations as we will see.
pi
[1] 3.141593
sin (pi/2)
[1] 1
cos(pi)
[1] -1
tan(2)
[1] -2.18504
log(1)
[1] 0
We can only go so far with performing simple calculations like this. Eventually we will need to store our results for later use. For this, we need to make use of variables.
Variables
A variable is a letter or word which takes (or contains) a value. We use the assignment ‘operator’, <-
to create a variable and store some value in it.
x <- 10
x
[1] 10
myNumber <- 25
myNumber
[1] 25
We also can perform arithmetic on variables using functions:
sqrt(myNumber)
[1] 5
We can add variables together:
x + myNumber
[1] 35
We can change the value of an existing variable:
x <- 21
x
[1] 21
- We can set one variable to equal the value of another variable:
x <- myNumber
x
[1] 25
- We can modify the contents of a variable:
myNumber <- myNumber + sqrt(16)
myNumber
[1] 29
When we are feeling lazy we might give our variables short names (x
, y
, i
…etc), but a better practice would be to give them meaningful names. There are some restrictions on creating variable names. They cannot start with a number or contain characters such as .
, _
, ‘-’. Naming variables the same as in-built functions in R, such as c
, T
, mean
should also be avoided.
Naming variables is a matter of taste. Some conventions exist such as a separating words with -
or using camelCaps. Whatever convention you decided, stick with it!
Functions
Functions in R perform operations on arguments (the inputs(s) to the function). We have already used:
sin(x)
[1] -0.1323518
this returns the sine of x. In this case the function has one argument: x. Arguments are always contained in parentheses – curved brackets, () – separated by commas.
Arguments can be named or unnamed, but if they are unnamed they must be ordered (we will see later how to find the right order). The names of the arguments are determined by the author of the function and can be found in the help page for the function. When testing code, it is easier and safer to name the arguments. seq
is a function for generating a numeric sequence from and to particular numbers. Type ?seq
to get the help page for this function.
seq(from = 3, to = 20, by = 4)
[1] 3 7 11 15 19
seq(3, 20, 4)
[1] 3 7 11 15 19
Arguments can have default values, meaning we do not need to specify values for these in order to run the function.
rnorm
is a function that will generate a series of values from a normal distribution. In order to use the function, we need to tell R how many values we want
## this will produce a random set of numbers, so everyone will get a different set of numbers
rnorm(n=10)
[1] -1.0444762 -0.4587502 -0.9002600 0.6891900 -0.5120514 0.1593984 -1.2266543 0.1424154 -0.9325531 -0.3066442
The normal distribution is defined by a mean (average) and standard deviation (spread). However, in the above example we didn’t tell R what mean and standard deviation we wanted. So how does R know what to do? All arguments to a function and their default values are listed in the help page
(N.B sometimes help pages can describe more than one function)
?rnorm
In this case, we see that the defaults for mean and standard deviation are 0 and 1. We can change the function to generate values from a distribution with a different mean and standard deviation using the mean
and sd
arguments. It is important that we get the spelling of these arguments exactly right, otherwise R will an error message, or (worse?) do something unexpected.
rnorm(n=10, mean=2,sd=3)
[1] -0.3099690 0.5163839 -3.8762792 5.4791809 -1.0831066 1.3091548 3.4741534 3.6379110 -0.4882820 1.7940955
rnorm(10, 2, 3)
[1] 6.5798089 5.2781992 1.9500866 3.7233240 4.2476678 2.5016850 5.2422587 0.6667798 6.4085566 5.2104411
In the examples above, seq
and rnorm
were both outputting a series of numbers, which is called a vector in R and is the most-fundamental data-type.
Exercise
- What is the value of
pi
to 3 decimal places?
- see the help for
round
?round
- How can we a create a sequence from 2 to 20 comprised of 5 equally-spaced numbers?
- check the help page for seq
?seq
- Create a variable containing 1000 random numbers with a mean of 2 and a standard deviation of 3
- what is the maximum and minimum of these numbers?
- what is the average?
- HINT: see the help pages for functions
min
, max
and mean
Saving your script
If you want to re-visit your code at any point, you will need to save a copy.
File > Save As… >
choose workshop material directory and Create a New Folder called scripts
Packages in R
So far we have used functions that are available with the base distribution of R; the functions you get with a clean install of R. The open-source nature of R encourages others to write their own functions for their particular data-type or analyses.
Packages are distributed through repositories. The most-common ones are CRAN and Bioconductor. CRAN alone has many thousands of packages.
The Packages tab in the bottom-right panel of RStudio lists all packages that you currently have installed. Clicking on a package name will show a list of functions that available once that package has been loaded.
There are functions for installing packages within R. If your package is part of the main CRAN repository, you can use install.packages
We will be using the tidyverse
R package in this practical. To install it, we would do.
install.packages("tidyverse")
A package may have several dependencies; other R packages from which it uses functions or data types (re-using code from other packages is strongly-encouraged). If this is the case, the other R packages will be located and installed too.
So long as you stick with the same version of R, you won’t need to repeat this install process.
Once a package is installed, the library
function is used to load a package and make it’s functions / data available in your current R session. You need to do this every time you load a new RStudio session. Let’s go ahead and load the tidyverse
.
## tidyverse is a collection of packages for data manipulation and visualisation
library(tidyverse)
Dealing with data
The tidyverse is in fact an eco-system of packages that provides a consistent, intuitive system for data manipulation and visualisation in R.
Image Credit: Aberdeen Study Group
We are going to explore some of the basic features of the tidyverse
using data from the gapminder project, which have been bundled into an R package. These data give various indicator variables for different countries around the world (life expectancy, population and Gross Domestic Product). We have saved these data as a .csv
file called gapminder.csv
in a sub-directory called raw_data/
to demonstrate how to import data into R.
You can download these data, along with the rest of the material needed for today’s workshop and a copy of this handout here. Save the .zip
file somewhere on your computer and unzip it.
Working in Rstudio Projects
We are also going to be working in an Rstudio Project. We suggest you organize each data analysis into a project: a folder on your computer containing all files relevant to a particular piece of work.
There are a number of benefits to this practice in general, and the Rstudio implementation in particular, summarised in Jenny Bryan’s blogpost on Project-oriented workflows.
In general makes work:
RStudio fully supports Project-based workflows, making it easy to switch from one to another, have many projects open at once, re-launch recently used Projects, etc.
There are a few ways to create new Projects. We can start new Projects by creating a new directory. We can also turn an existing directory into a Project. Let’s do this with the unzipped folder containing the workshop materials we just downloaded.
File > New Project > Existing Directory > …
choose workshop material directory
We’ve now turned our workshop material folder into an Rstudio project and launched it, which means:
- a fresh R session has been launched (see how the Environment tab is now clear)
- the working directory has been set to the project root (you can check this form the header on the Console tab)
- A project specific History is initiated.
Working in R Notebooks
We’ll also be working in an R Notebook. These file are an R Markdown document type, which allow us to combine R code with markdown, a documentation language, providing a framework for literate programming. In an R Notebook, R code chunks can be executed independently and interactively, with output visible immediately beneath the input.
Let’s open an R Notebook to start work in.
File > Open File >
- Navigate to the file
notes.Rmd
in the course materials
Each chunk of R code looks something like this.
```{r}
print('hello world!')
```
New R code chunks can be inserted by:
- keyboard shortcut:
Ctrl + Alt + I
(macOS: Cmd + Option + I
)
Insert
menu in the editor toolbar.
Each line of R in the chunks can be again executed by clicking on the line or highlighting code and pressing Ctrl + Enter
(macOS: Cmd + Enter
), or you can press the green triangle on the right-hand side to run everything in the chunk.
For more details, check out this short tutorial on literate programming in R Markdown
Let’s clear everything and write our first markdown and chunk of code by creating a markdown
header with:
# Packages
and loading the tidyverse packages for the analysis in our notebook
```{r load-packages}
library("tidyverse")
```
library("tidyverse")
Reading in data
Any .csv
file can be imported into R by supplying the path to the file to readr
function read_csv
and assigning it to a new object to store the result. A useful sanity check is the file.exists
function which will print TRUE
is the file can be found in the working directory.
gapminder_path <- "raw_data/gapminder.csv"
file.exists(gapminder_path)
[1] TRUE
Assuming the file can be found, we can use read_csv
to import. Other functions can be used to read tab-delimited files (read_delim
) or a generic read.table
function. A data frame object is created.
gapminder <- read_csv(gapminder_path)
Parsed with column specification:
cols(
country = col_character(),
continent = col_character(),
year = col_integer(),
lifeExp = col_double(),
pop = col_integer(),
gdpPercap = col_double()
)
Question: Why would specifying gapminder_path
as
gapminder_path <- "/Users/Anna/Documents/workflows/workshops/r-crash-course/raw_data/gapminder.csv"
be a bad idea?
The data frame object in R allows us to work with “tabular” data, like we might be used to dealing with in Excel, where our data can be thought of having rows and columns. The values in each column have to all be of the same type (i.e. all numbers or all text).
In Rstudio, you can view the contents of the data frame we have just created using function View()
. This is useful for interactive exploration of the data, but not so useful for automation, scripting and analyses.
View(gapminder)
We should always check the data frame that we have created. Sometimes R will happily read data using an inappropriate function and create an object without raising an error. However, the data might be unsuable. Consider:-
test <- read_table(gapminder_path)
Parsed with column specification:
cols(
`"country","continent","year","lifeExp","pop","gdpPercap"` = col_character()
)
View(test)
Quick sanity checks can also be performed by inspecting details in the environment tab. A useful check in RStudio is to use the head
function, which prints the first 6 rows of the data frame to the screen.
head(gapminder)
Accessing data in columns
In the next section we will explore in more detail how to control the columns and rows from a data frame that are displayed in RStudio. For now, accessing all the observations from a particular column can be achieved by typing the $
symbol after the name of the data frame followed by the name of a column you are interested in.
RStudio is able to “tab-complete” the column name, so typing the following and presssing the TAB key will bring-up a list of possible columns. The contents of the column that you select are then printed to the screen.
gapminder$c
Rather than merely printing to the screen we can also create a variable
country_vec <- gapminder$country
Exercise
- The function
tail
is similar to head
except it prints the last lines in a file. Use this function to print the last 10 lines in the data frame (you will have to consult the help on tail
to see how to change the default arguments.)
- What is the largest observed population?
- What is the lowest life expectancy
Question: Familiarise yourself with the contents of the data frame. What numerical summaries can you produce from the dataset (e.g. average life expectancy per-year, countries that are most wealthy etc) and what plots might be of interest? Discuss with your neighbours
LS0tCnRpdGxlOiAiUiBDcmFzaCBDb3Vyc2UiCmF1dGhvcjogIk1hcmsgRHVubmluZyIKZGF0ZTogJ2ByIGZvcm1hdChTeXMudGltZSgpLCAiTGFzdCBtb2RpZmllZDogJWQgJWIgJVkiKWAnCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgojIEFja25vd2xlZGdlbWVudAoKVGhlc2UgbWF0ZXJpYWxzIGFyZSBhZGFwdGVkIGZyb20gYSBjb3Vyc2UgZGV2ZWxvcGVkIGF0IENhbmNlciBSZXNlYXJjaCBVayBDYW1icmlkZ2UgSW5zdGl0dXRlIGJ5IE1hcmsgRHVubmluZywgTWF0dGhldyBFbGRyaWRnZSBhbmQgVGhvbWFzIENhcnJvbGwuCgojIEludHJvZHVjdGlvbiB0byBSIC0gUGFydCBJCgojIyBSU3R1ZGlvCgoKCi0gUnN0dWRpbyBpcyBhIGZyZWUgZW52aXJvbm1lbnQgZm9yIFIKLSBDb252ZW5pZW50IG1lbnVzIHRvIGFjY2VzcyBzY3JpcHRzLCBkaXNwbGF5IHBsb3RzCi0gU3RpbGwgbmVlZCB0byB1c2UgKmNvbW1hbmQtbGluZSogdG8gZ2V0IHRoaW5ncyBkb25lCi0gRGV2ZWxvcGVkIGJ5IHNvbWUgb2YgdGhlIGxlYWRpbmcgUiBwcm9ncmFtbWVycwotIFVzZWQgYnkgYmVnaW5uZXJzLCBhbmQgZXhwZXJpZW5jZWQgdXNlcnMgYWxpa2UKClRvIGdldCBzdGFydGVkLCB5b3Ugd2lsbCBuZWVkIHRvIGluc3RhbGwgdGhlIFtsYXRlc3QgdmVyc2lvbiBvZiBSXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy8pIGFuZCBbUlN0dWRpbyBEZXNrdG9wXShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS9wcm9kdWN0cy9yc3R1ZGlvL2Rvd25sb2FkMy8pOyBib3RoIG9mIHdoaWNoIGFyZSAqKipmcmVlKioqLiAKCk9uY2UgaW5zdGFsbGVkLCB5b3Ugc2hvdWxkIGJlIGFibGUgdG8gbGF1bmNoIFJTdHVkaW8gYnkgY2xpY2tpbmcgb24gaXRzIGljb246LQoKCiFbXShodHRwOi8vd3d3LnJzdHVkaW8uY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE0LzAzL2JsdWUtMTI1LnBuZykKCiMjIEVudGVyaW5nIGNvbW1hbmRzIGluIFIKCi0gVGhlIHRyYWRpdGlvbmFsIHdheSB0byBlbnRlciBSIGNvbW1hbmRzIGlzIHZpYSB0aGUgVGVybWluYWwsIG9yIHVzaW5nIHRoZSBjb25zb2xlIGluIFJTdHVkaW8gKGJvdHRvbS1sZWZ0IHBhbmVsIHdoZW4gUlN0dWRpbyBvcGVucyBmb3IgZmlyc3QgdGltZSkuCiAgKyB0aGlzIGRvZXNuJ3QgYXV0b21hdGljYWxseSBrZWVwIHRyYWNrIG9mIHRoZSBzdGVwcyB5b3UgZGlkCi0gQWx0ZXJuYXRpdmUsIGFuICpSIHNjcmlwdCogY2FuIGJlIHVzZWQgdG8ga2VlcCBhIHJlY29yZCBvZiB0aGUgY29tbWFuZHMgeW91IHVzZWQuCi0gVGhlIFIgY29kZSBjYW4gYmUgcnVuIGZyb20gaW5zaWRlIHRoZSBzY3JpcHQgYW5kIHRoZSByZXN1bHRzIGFyZSBkaXNwbGF5ZWQgaW4gdGhlIGNvbnNvbGUgb3IgVmlld2VyIHBhbmVsIChlZyBwbG90cykKLSBFYWNoIGxpbmUgb2YgUiBjb2RlIGNhbiBiZSBleGVjdXRlZCBieSBjbGlja2luZyBvbiB0aGUgbGluZSBhbmQgcHJlc3NpbmcgQ1RSTCBhbmQgRU5URVIKLSBMZXQncyB0cnkgdGhpcyBub3chCgo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4KCiMjIyMgKipGaWxlIC0+IE5ldyBGaWxlIC0+IFIgc2NyaXB0ID4gKiogCgo8L2Rpdj4KCgpgYGB7cn0KcHJpbnQoIkhlbGxvIFdvcmxkIikKYGBgCgoKIyBHZXR0aW5nIHN0YXJ0ZWQKCiFbXShpbWFnZXMvMTI4cHgtU0hBUlBfRUxTSU1BVEVfRUwtVzIyMS5qcGcpCgpBdCBhIGJhc2ljIGxldmVsLCB3ZSBjYW4gdXNlIFIgYXMgYSBjYWxjdWxhdG9yIHRvIGNvbXB1dGUgc2ltcGxlIHN1bXMgd2l0aCB0aGUgYCtgLCBgLWAsIGAqYCAoZm9yIG11bHRpcGxpY2F0aW9uKSBhbmQgYC9gIChmb3IgZGl2aXNpb24pIHN5bWJvbHMuIAoKYGBge3J9CjIgKyAyCjIgLSAyCjQgKiAzCjEwIC8gMgpgYGAKClRoZSBhbnN3ZXIgaXMgZGlzcGxheWVkIGF0IHRoZSBjb25zb2xlIHdpdGggYSBgWzFdYCBpbiBmcm9udCBvZiBpdC4gVGhlIGAxYCBpbnNpZGUgdGhlIHNxdWFyZSBicmFja2V0cyBpcyBhIHBsYWNlLWhvbGRlciB0byBzaWduaWZ5IGhvdyBtYW55IHZhbHVlcyB3ZXJlIGluIHRoZSBhbnN3ZXIgKGluIHRoaXMgY2FzZSBvbmx5IG9uZSkuIFdlIHdpbGwgdGFsayBhYm91dCBkZWFsaW5nIHdpdGggbGlzdHMgb2YgbnVtYmVycyBzaG9ydGx5Li4uCgpJbiB0aGUgY2FzZSBvZiBleHByZXNzaW9ucyBpbnZvbHZpbmcgbXVsdGlwbGUgb3BlcmF0aW9ucywgUiByZXNwZWN0cyB0aGUgW0JPRE1BU10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvT3JkZXJfb2Zfb3BlcmF0aW9ucyNNbmVtb25pY3MpIHN5c3RlbSB0byBkZWNpZGUgdGhlIG9yZGVyIGluIHdoaWNoIG9wZXJhdGlvbnMgc2hvdWxkIGJlIHBlcmZvcm1lZC4KCmBgYHtyfQoyICsgMiAqMwoyICsgKDIgKiAzKQooMiArIDIpICogMwpgYGAKClIgaXMgY2FwYWJsZSBvZiBtb3JlIGNvbXBsaWNhdGVkIGFyaXRobWV0aWMgc3VjaCBhcyB0cmlnb25vbWV0cnkgYW5kIGxvZ2FyaXRobXM7IGxpa2UgeW91IHdvdWxkIGZpbmQgb24gYSBmYW5jeSBzY2llbnRpZmljIGNhbGN1bGF0b3IuIE9mIGNvdXJzZSwgUiBhbHNvIGhhcyBhIHBsZXRob3JhIG9mIHN0YXRpc3RpY2FsIG9wZXJhdGlvbnMgYXMgd2Ugd2lsbCBzZWUuCgohW10oaW1hZ2VzLzEyOHB4LUNhc2lvLWZ4MTE1RVMtNTU2NC5qcGcpCgpgYGB7cn0KcGkKc2luIChwaS8yKQpjb3MocGkpCnRhbigyKQpsb2coMSkKYGBgCgpXZSBjYW4gb25seSBnbyBzbyBmYXIgd2l0aCBwZXJmb3JtaW5nIHNpbXBsZSBjYWxjdWxhdGlvbnMgbGlrZSB0aGlzLiBFdmVudHVhbGx5IHdlIHdpbGwgbmVlZCB0byBzdG9yZSBvdXIgcmVzdWx0cyBmb3IgbGF0ZXIgdXNlLiBGb3IgdGhpcywgd2UgbmVlZCB0byBtYWtlIHVzZSBvZiAqdmFyaWFibGVzKi4KCiMjIFZhcmlhYmxlcwoKQSB2YXJpYWJsZSBpcyBhIGxldHRlciBvciB3b3JkIHdoaWNoIHRha2VzIChvciBjb250YWlucykgYSB2YWx1ZS4gV2UKdXNlIHRoZSBhc3NpZ25tZW50ICdvcGVyYXRvcicsIGA8LWAgdG8gY3JlYXRlIGEgdmFyaWFibGUgYW5kIHN0b3JlIHNvbWUgdmFsdWUgaW4gaXQuIAoKYGBge3J9CnggPC0gMTAKeApteU51bWJlciA8LSAyNQpteU51bWJlcgpgYGAKV2UgYWxzbyBjYW4gcGVyZm9ybSBhcml0aG1ldGljIG9uIHZhcmlhYmxlcyB1c2luZyBmdW5jdGlvbnM6CgpgYGB7cn0Kc3FydChteU51bWJlcikKYGBgCgpXZSBjYW4gYWRkIHZhcmlhYmxlcyB0b2dldGhlcjoKYGBge3J9CnggKyBteU51bWJlcgpgYGAKCgpXZSBjYW4gY2hhbmdlIHRoZSB2YWx1ZSBvZiBhbiBleGlzdGluZyB2YXJpYWJsZToKCmBgYHtyfQp4IDwtIDIxCngKYGBgCgotIFdlIGNhbiBzZXQgb25lIHZhcmlhYmxlIHRvIGVxdWFsIHRoZSB2YWx1ZSBvZiBhbm90aGVyIHZhcmlhYmxlOgoKYGBge3J9CnggPC0gbXlOdW1iZXIKeApgYGAKCi0gV2UgY2FuIG1vZGlmeSB0aGUgY29udGVudHMgb2YgYSB2YXJpYWJsZToKCmBgYHtyfQpteU51bWJlciA8LSBteU51bWJlciArIHNxcnQoMTYpCm15TnVtYmVyCmBgYAoKV2hlbiB3ZSBhcmUgZmVlbGluZyBsYXp5IHdlIG1pZ2h0IGdpdmUgb3VyIHZhcmlhYmxlcyBzaG9ydCBuYW1lcyAoYHhgLCBgeWAsIGBpYC4uLmV0YyksIGJ1dCBhIGJldHRlciBwcmFjdGljZSB3b3VsZCBiZSB0byBnaXZlIHRoZW0gbWVhbmluZ2Z1bCBuYW1lcy4gVGhlcmUgYXJlIHNvbWUgcmVzdHJpY3Rpb25zIG9uIGNyZWF0aW5nIHZhcmlhYmxlIG5hbWVzLiBUaGV5IGNhbm5vdCBzdGFydCB3aXRoIGEgbnVtYmVyIG9yIGNvbnRhaW4gY2hhcmFjdGVycyBzdWNoIGFzIGAuYCwgYF9gLCAnLScuIE5hbWluZyB2YXJpYWJsZXMgdGhlIHNhbWUgYXMgaW4tYnVpbHQgZnVuY3Rpb25zIGluIFIsIHN1Y2ggYXMgYGNgLCBgVGAsIGBtZWFuYCBzaG91bGQgYWxzbyBiZSBhdm9pZGVkLgoKTmFtaW5nIHZhcmlhYmxlcyBpcyBhIG1hdHRlciBvZiB0YXN0ZS4gU29tZSBbY29udmVudGlvbnNdKGh0dHA6Ly9hZHYtci5oYWQuY28ubnovU3R5bGUuaHRtbCkgZXhpc3Qgc3VjaCBhcyBhIHNlcGFyYXRpbmcgd29yZHMgd2l0aCBgLWAgb3IgdXNpbmcgKmMqYW1lbCpDKmFwcy4gV2hhdGV2ZXIgY29udmVudGlvbiB5b3UgZGVjaWRlZCwgc3RpY2sgd2l0aCBpdCEKCiMjIEZ1bmN0aW9ucwoKKipGdW5jdGlvbnMqKiBpbiBSIHBlcmZvcm0gb3BlcmF0aW9ucyBvbiAqKmFyZ3VtZW50cyoqICh0aGUgaW5wdXRzKHMpIHRvIHRoZSBmdW5jdGlvbikuIFdlIGhhdmUgYWxyZWFkeSB1c2VkOgoKYGBge3J9CnNpbih4KQpgYGAKCnRoaXMgcmV0dXJucyB0aGUgc2luZSBvZiB4LiBJbiB0aGlzIGNhc2UgdGhlIGZ1bmN0aW9uIGhhcyBvbmUgYXJndW1lbnQ6ICoqeCoqLiBBcmd1bWVudHMgYXJlIGFsd2F5cyBjb250YWluZWQgaW4gcGFyZW50aGVzZXMgLS0gY3VydmVkIGJyYWNrZXRzLCAqKigpKiogLS0gc2VwYXJhdGVkIGJ5IGNvbW1hcy4KCgpBcmd1bWVudHMgY2FuIGJlIG5hbWVkIG9yIHVubmFtZWQsIGJ1dCBpZiB0aGV5IGFyZSB1bm5hbWVkIHRoZXkgbXVzdCBiZSBvcmRlcmVkICh3ZSB3aWxsIHNlZSBsYXRlciBob3cgdG8gZmluZCB0aGUgcmlnaHQgb3JkZXIpLiBUaGUgbmFtZXMgb2YgdGhlIGFyZ3VtZW50cyBhcmUgZGV0ZXJtaW5lZCBieSB0aGUgYXV0aG9yIG9mIHRoZSBmdW5jdGlvbiBhbmQgY2FuIGJlIGZvdW5kIGluIHRoZSBoZWxwIHBhZ2UgZm9yIHRoZSBmdW5jdGlvbi4gV2hlbiB0ZXN0aW5nIGNvZGUsIGl0IGlzIGVhc2llciBhbmQgc2FmZXIgdG8gbmFtZSB0aGUgYXJndW1lbnRzLiBgc2VxYCBpcyBhIGZ1bmN0aW9uIGZvciBnZW5lcmF0aW5nIGEgbnVtZXJpYyBzZXF1ZW5jZSAqZnJvbSogYW5kICp0byogcGFydGljdWxhciBudW1iZXJzLiBUeXBlIGA/c2VxYCB0byBnZXQgdGhlIGhlbHAgcGFnZSBmb3IgdGhpcyBmdW5jdGlvbi4KCmBgYHtyfQpzZXEoZnJvbSA9IDMsIHRvID0gMjAsIGJ5ID0gNCkKc2VxKDMsIDIwLCA0KQpgYGAKCkFyZ3VtZW50cyBjYW4gaGF2ZSAqZGVmYXVsdCogdmFsdWVzLCBtZWFuaW5nIHdlIGRvIG5vdCBuZWVkIHRvIHNwZWNpZnkgdmFsdWVzIGZvciB0aGVzZSBpbiBvcmRlciB0byBydW4gdGhlIGZ1bmN0aW9uLgoKYHJub3JtYCBpcyBhIGZ1bmN0aW9uIHRoYXQgd2lsbCBnZW5lcmF0ZSBhIHNlcmllcyBvZiB2YWx1ZXMgZnJvbSBhICpub3JtYWwgZGlzdHJpYnV0aW9uKi4gSW4gb3JkZXIgdG8gdXNlIHRoZSBmdW5jdGlvbiwgd2UgbmVlZCB0byB0ZWxsIFIgaG93IG1hbnkgdmFsdWVzIHdlIHdhbnQKCmBgYHtyfQojIyB0aGlzIHdpbGwgcHJvZHVjZSBhIHJhbmRvbSBzZXQgb2YgbnVtYmVycywgc28gZXZlcnlvbmUgd2lsbCBnZXQgYSBkaWZmZXJlbnQgc2V0IG9mIG51bWJlcnMKcm5vcm0obj0xMCkKYGBgCgpUaGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBpcyBkZWZpbmVkIGJ5IGEgKm1lYW4qIChhdmVyYWdlKSBhbmQgKnN0YW5kYXJkIGRldmlhdGlvbiogKHNwcmVhZCkuIEhvd2V2ZXIsIGluIHRoZSBhYm92ZSBleGFtcGxlIHdlIGRpZG4ndCB0ZWxsIFIgd2hhdCBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gd2Ugd2FudGVkLiBTbyBob3cgZG9lcyBSIGtub3cgd2hhdCB0byBkbz8gQWxsIGFyZ3VtZW50cyB0byBhIGZ1bmN0aW9uIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyBhcmUgbGlzdGVkIGluIHRoZSBoZWxwIHBhZ2UKCigqTi5CIHNvbWV0aW1lcyBoZWxwIHBhZ2VzIGNhbiBkZXNjcmliZSBtb3JlIHRoYW4gb25lIGZ1bmN0aW9uKikKCmBgYHtyfQo/cm5vcm0KYGBgCgpJbiB0aGlzIGNhc2UsIHdlIHNlZSB0aGF0IHRoZSBkZWZhdWx0cyBmb3IgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIGFyZSAwIGFuZCAxLiBXZSBjYW4gY2hhbmdlIHRoZSBmdW5jdGlvbiB0byBnZW5lcmF0ZSB2YWx1ZXMgZnJvbSBhIGRpc3RyaWJ1dGlvbiB3aXRoIGEgZGlmZmVyZW50IG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiB1c2luZyB0aGUgYG1lYW5gIGFuZCBgc2RgICphcmd1bWVudHMqLiBJdCBpcyBpbXBvcnRhbnQgdGhhdCB3ZSBnZXQgdGhlIHNwZWxsaW5nIG9mIHRoZXNlIGFyZ3VtZW50cyBleGFjdGx5IHJpZ2h0LCBvdGhlcndpc2UgUiB3aWxsIGFuIGVycm9yIG1lc3NhZ2UsIG9yICh3b3JzZT8pIGRvIHNvbWV0aGluZyB1bmV4cGVjdGVkLgoKYGBge3J9CnJub3JtKG49MTAsIG1lYW49MixzZD0zKQpybm9ybSgxMCwgMiwgMykKYGBgCgpJbiB0aGUgZXhhbXBsZXMgYWJvdmUsIGBzZXFgIGFuZCBgcm5vcm1gIHdlcmUgYm90aCBvdXRwdXR0aW5nIGEgc2VyaWVzIG9mIG51bWJlcnMsIHdoaWNoIGlzIGNhbGxlZCBhICp2ZWN0b3IqIGluIFIgYW5kIGlzIHRoZSBtb3N0LWZ1bmRhbWVudGFsIGRhdGEtdHlwZS4KCgoqKioqKioKKioqKioqCioqKioqKgoKCgojIyMgRXhlcmNpc2UKCgogIC0gV2hhdCBpcyB0aGUgdmFsdWUgb2YgYHBpYCB0byAzIGRlY2ltYWwgcGxhY2VzPwogICAgKyBzZWUgdGhlIGhlbHAgZm9yIGByb3VuZGAgYD9yb3VuZGAKICAtIEhvdyBjYW4gd2UgYSBjcmVhdGUgYSBzZXF1ZW5jZSBmcm9tIDIgdG8gMjAgY29tcHJpc2VkIG9mIDUgZXF1YWxseS1zcGFjZWQgbnVtYmVycz8KICAgICsgY2hlY2sgdGhlIGhlbHAgcGFnZSBmb3Igc2VxIGA/c2VxYAogIC0gQ3JlYXRlIGEgKnZhcmlhYmxlKiBjb250YWluaW5nIDEwMDAgcmFuZG9tIG51bWJlcnMgd2l0aCBhICptZWFuKiBvZiAyIGFuZCBhICpzdGFuZGFyZCBkZXZpYXRpb24qIG9mIDMKICAgICsgd2hhdCBpcyB0aGUgbWF4aW11bSBhbmQgbWluaW11bSBvZiB0aGVzZSBudW1iZXJzPwogICAgKyB3aGF0IGlzIHRoZSBhdmVyYWdlPwogICAgKyBISU5UOiBzZWUgdGhlIGhlbHAgcGFnZXMgZm9yIGZ1bmN0aW9ucyBgbWluYCwgYG1heGAgYW5kIGBtZWFuYAogICAgCmBgYHtyfQoKCmBgYAogICAgCiAgICAKKioqKioqCioqKioqKgoqKioqKioKCiMjIFNhdmluZyB5b3VyIHNjcmlwdAoKSWYgeW91IHdhbnQgdG8gcmUtdmlzaXQgeW91ciBjb2RlIGF0IGFueSBwb2ludCwgeW91IHdpbGwgbmVlZCB0byBzYXZlIGEgY29weS4KCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPgoKIyMjIyAqKkZpbGUgPiBTYXZlIEFzLi4uID4gKiogCl9jaG9vc2Ugd29ya3Nob3AgbWF0ZXJpYWwgZGlyZWN0b3J5IGFuZCBDcmVhdGUgYSBOZXcgRm9sZGVyIGNhbGxlZCBgc2NyaXB0c2BfCgo8L2Rpdj4KCgojIyBQYWNrYWdlcyBpbiBSCgpTbyBmYXIgd2UgaGF2ZSB1c2VkIGZ1bmN0aW9ucyB0aGF0IGFyZSBhdmFpbGFibGUgd2l0aCB0aGUgKmJhc2UqIGRpc3RyaWJ1dGlvbiBvZiBSOyB0aGUgZnVuY3Rpb25zIHlvdSBnZXQgd2l0aCBhIGNsZWFuIGluc3RhbGwgb2YgUi4gVGhlIG9wZW4tc291cmNlIG5hdHVyZSBvZiBSIGVuY291cmFnZXMgb3RoZXJzIHRvIHdyaXRlIHRoZWlyIG93biBmdW5jdGlvbnMgZm9yIHRoZWlyIHBhcnRpY3VsYXIgZGF0YS10eXBlIG9yIGFuYWx5c2VzLgoKUGFja2FnZXMgYXJlIGRpc3RyaWJ1dGVkIHRocm91Z2ggKnJlcG9zaXRvcmllcyouIFRoZSBtb3N0LWNvbW1vbiBvbmVzIGFyZSBDUkFOIGFuZCBCaW9jb25kdWN0b3IuIENSQU4gYWxvbmUgaGFzIG1hbnkgdGhvdXNhbmRzIG9mIHBhY2thZ2VzLgoKVGhlICoqUGFja2FnZXMqKiB0YWIgaW4gdGhlIGJvdHRvbS1yaWdodCBwYW5lbCBvZiBSU3R1ZGlvIGxpc3RzIGFsbCBwYWNrYWdlcyB0aGF0IHlvdSBjdXJyZW50bHkgaGF2ZSBpbnN0YWxsZWQuIENsaWNraW5nIG9uIGEgcGFja2FnZSBuYW1lIHdpbGwgc2hvdyBhIGxpc3Qgb2YgZnVuY3Rpb25zIHRoYXQgYXZhaWxhYmxlIG9uY2UgdGhhdCBwYWNrYWdlIGhhcyBiZWVuIGxvYWRlZC4gCgpUaGVyZSBhcmUgZnVuY3Rpb25zIGZvciBpbnN0YWxsaW5nIHBhY2thZ2VzIHdpdGhpbiBSLiBJZiB5b3VyIHBhY2thZ2UgaXMgcGFydCBvZiB0aGUgbWFpbiAqKkNSQU4qKiByZXBvc2l0b3J5LCB5b3UgY2FuIHVzZSBgaW5zdGFsbC5wYWNrYWdlc2AKCldlIHdpbGwgYmUgdXNpbmcgdGhlIGB0aWR5dmVyc2VgIFIgcGFja2FnZSBpbiB0aGlzIHByYWN0aWNhbC4gVG8gaW5zdGFsbCBpdCwgd2Ugd291bGQgZG8uCgpgYGB7ciBldmFsPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQpgYGAKCgpBIHBhY2thZ2UgbWF5IGhhdmUgc2V2ZXJhbCAqZGVwZW5kZW5jaWVzKjsgb3RoZXIgUiBwYWNrYWdlcyBmcm9tIHdoaWNoIGl0IHVzZXMgZnVuY3Rpb25zIG9yIGRhdGEgdHlwZXMgKHJlLXVzaW5nIGNvZGUgZnJvbSBvdGhlciBwYWNrYWdlcyBpcyBzdHJvbmdseS1lbmNvdXJhZ2VkKS4gSWYgdGhpcyBpcyB0aGUgY2FzZSwgdGhlIG90aGVyIFIgcGFja2FnZXMgd2lsbCBiZSBsb2NhdGVkIGFuZCBpbnN0YWxsZWQgdG9vLgoKKipTbyBsb25nIGFzIHlvdSBzdGljayB3aXRoIHRoZSBzYW1lIHZlcnNpb24gb2YgUiwgeW91IHdvbid0IG5lZWQgdG8gcmVwZWF0IHRoaXMgaW5zdGFsbCBwcm9jZXNzLioqCgoKT25jZSBhIHBhY2thZ2UgaXMgaW5zdGFsbGVkLCB0aGUgYGxpYnJhcnlgIGZ1bmN0aW9uIGlzIHVzZWQgdG8gbG9hZCBhIHBhY2thZ2UgYW5kIG1ha2UgaXQncyBmdW5jdGlvbnMgLyBkYXRhIGF2YWlsYWJsZSBpbiB5b3VyIGN1cnJlbnQgUiBzZXNzaW9uLiAqWW91IG5lZWQgdG8gZG8gdGhpcyBldmVyeSB0aW1lIHlvdSBsb2FkIGEgbmV3IFJTdHVkaW8gc2Vzc2lvbiouIExldCdzIGdvIGFoZWFkIGFuZCBsb2FkIHRoZSBgdGlkeXZlcnNlYC4KCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQojIyB0aWR5dmVyc2UgaXMgYSBjb2xsZWN0aW9uIG9mIHBhY2thZ2VzIGZvciBkYXRhIG1hbmlwdWxhdGlvbiBhbmQgdmlzdWFsaXNhdGlvbgpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKCiMgRGVhbGluZyB3aXRoIGRhdGEKClRoZSBbKioqdGlkeXZlcnNlKioqXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLykgaXMgaW4gZmFjdCBhbiBlY28tc3lzdGVtIG9mIHBhY2thZ2VzIHRoYXQgcHJvdmlkZXMgYSBjb25zaXN0ZW50LCBpbnR1aXRpdmUgc3lzdGVtIGZvciBkYXRhIG1hbmlwdWxhdGlvbiBhbmQgdmlzdWFsaXNhdGlvbiBpbiBSLgoKCiFbXShodHRwczovL2FiZXJkZWVuc3R1ZHlncm91cC5naXRodWIuaW8vc3R1ZHlHcm91cC9sZXNzb25zL1NHLVQyLUpvaW50V29ya3Nob3AvdGlkeXZlcnNlLnBuZykKX0ltYWdlIENyZWRpdDpfIFsqKipBYmVyZGVlbiBTdHVkeSBHcm91cCoqKl0oaHR0cHM6Ly9hYmVyZGVlbnN0dWR5Z3JvdXAuZ2l0aHViLmlvL3N0dWR5R3JvdXAvbGVzc29ucy9TRy1UMi1Kb2ludFdvcmtzaG9wL1BvcHVsYXRpb25DaGFuZ2VTcGVjaWVzT2NjdXJyZW5jZS8pCgpXZSBhcmUgZ29pbmcgdG8gZXhwbG9yZSBzb21lIG9mIHRoZSBiYXNpYyBmZWF0dXJlcyBvZiB0aGUgYHRpZHl2ZXJzZWAgdXNpbmcgZGF0YSBmcm9tIHRoZSBbZ2FwbWluZGVyXShodHRwczovL3d3dy5nYXBtaW5kZXIub3JnL2RhdGEvKSBwcm9qZWN0LCB3aGljaCBoYXZlIGJlZW4gYnVuZGxlZCBpbnRvIGFuIFtSIHBhY2thZ2VdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2dhcG1pbmRlcikuIFRoZXNlIGRhdGEgZ2l2ZSB2YXJpb3VzIGluZGljYXRvciB2YXJpYWJsZXMgZm9yIGRpZmZlcmVudCBjb3VudHJpZXMgYXJvdW5kIHRoZSB3b3JsZCAobGlmZSBleHBlY3RhbmN5LCBwb3B1bGF0aW9uIGFuZCBHcm9zcyBEb21lc3RpYyBQcm9kdWN0KS4gV2UgaGF2ZSBzYXZlZCB0aGVzZSBkYXRhIGFzIGEgYC5jc3ZgIGZpbGUgY2FsbGVkIGBnYXBtaW5kZXIuY3N2YCBpbiBhIHN1Yi1kaXJlY3RvcnkgY2FsbGVkIGByYXdfZGF0YS9gIHRvIGRlbW9uc3RyYXRlIGhvdyB0byBpbXBvcnQgZGF0YSBpbnRvIFIuCgoKWW91IGNhbiBkb3dubG9hZCB0aGVzZSBkYXRhLCBhbG9uZyB3aXRoIHRoZSByZXN0IG9mIHRoZSBtYXRlcmlhbCBuZWVkZWQgZm9yIHRvZGF5J3Mgd29ya3Nob3AgYW5kIGEgY29weSBvZiB0aGlzIGhhbmRvdXQgIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vc2hlZmZpZWxkLWJpb2luZm9ybWF0aWNzLWNvcmUvci1jcmFzaC1jb3Vyc2UvcmF3L21hc3Rlci9Db3Vyc2VEYXRhLnppcCkuIFNhdmUgdGhlIGAuemlwYCBmaWxlIHNvbWV3aGVyZSBvbiB5b3VyIGNvbXB1dGVyIGFuZCB1bnppcCBpdC4KCgoKIyMgV29ya2luZyBpbiBSc3R1ZGlvIFByb2plY3RzCgpXZSBhcmUgYWxzbyBnb2luZyB0byBiZSB3b3JraW5nIGluIGFuIFJzdHVkaW8gW1Byb2plY3RdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA1MjYyMDctVXNpbmctUHJvamVjdHMpLiBXZSBzdWdnZXN0IHlvdSAqKm9yZ2FuaXplIGVhY2ggZGF0YSBhbmFseXNpcyBpbnRvIGEgcHJvamVjdDogYSBmb2xkZXIgb24geW91ciBjb21wdXRlciBjb250YWluaW5nIGFsbCBmaWxlcyByZWxldmFudCB0byBhIHBhcnRpY3VsYXIgcGllY2Ugb2Ygd29yay4qKgoKVGhlcmUgYXJlIGEgbnVtYmVyIG9mIGJlbmVmaXRzIHRvIHRoaXMgcHJhY3RpY2UgaW4gZ2VuZXJhbCwgYW5kIHRoZSBSc3R1ZGlvIGltcGxlbWVudGF0aW9uIGluIHBhcnRpY3VsYXIsIHN1bW1hcmlzZWQgaW4gSmVubnkgQnJ5YW4ncyBibG9ncG9zdCBvbiBbUHJvamVjdC1vcmllbnRlZCB3b3JrZmxvd3NdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvYXJ0aWNsZXMvMjAxNy8xMi93b3JrZmxvdy12cy1zY3JpcHQvKS4KCkluIGdlbmVyYWwgbWFrZXMgd29yazogCgotIFNlbGYtY29udGFpbmVkCi0gUG9ydGFibGUKClJTdHVkaW8gZnVsbHkgc3VwcG9ydHMgUHJvamVjdC1iYXNlZCB3b3JrZmxvd3MsIG1ha2luZyBpdCBlYXN5IHRvIHN3aXRjaCBmcm9tIG9uZSB0byBhbm90aGVyLCBoYXZlIG1hbnkgcHJvamVjdHMgb3BlbiBhdCBvbmNlLCByZS1sYXVuY2ggcmVjZW50bHkgdXNlZCBQcm9qZWN0cywgZXRjLgoKVGhlcmUgYXJlICoqYSBmZXcgd2F5cyB0byBjcmVhdGUgbmV3IFByb2plY3RzKiouIFdlIGNhbiBzdGFydCBuZXcgUHJvamVjdHMgYnkgY3JlYXRpbmcgYSBuZXcgZGlyZWN0b3J5LiBXZSBjYW4gYWxzbyAqKnR1cm4gYW4gZXhpc3RpbmcgZGlyZWN0b3J5IGludG8gYSBQcm9qZWN0KiouIExldCdzIGRvIHRoaXMgd2l0aCB0aGUgdW56aXBwZWQgZm9sZGVyIGNvbnRhaW5pbmcgdGhlIHdvcmtzaG9wIG1hdGVyaWFscyB3ZSBqdXN0IGRvd25sb2FkZWQuCgoKPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+CgojIyMjICoqRmlsZSA+IE5ldyBQcm9qZWN0ID4gRXhpc3RpbmcgRGlyZWN0b3J5ID4gLi4uKiogCl9jaG9vc2Ugd29ya3Nob3AgbWF0ZXJpYWwgZGlyZWN0b3J5XwoKPC9kaXY+CgpXZSd2ZSBub3cgdHVybmVkIG91ciB3b3Jrc2hvcCBtYXRlcmlhbCBmb2xkZXIgaW50byBhbiBSc3R1ZGlvIHByb2plY3QgYW5kIGxhdW5jaGVkIGl0LCB3aGljaCBtZWFuczoKCi0gYSAqKmZyZXNoIFIgc2Vzc2lvbiBoYXMgYmVlbiBsYXVuY2hlZCoqIChzZWUgaG93IHRoZSAqKkVudmlyb25tZW50KiogdGFiIGlzIG5vdyBjbGVhcikKLSB0aGUgKip3b3JraW5nIGRpcmVjdG9yeSBoYXMgYmVlbiBzZXQgdG8gdGhlIHByb2plY3Qgcm9vdCoqICh5b3UgY2FuIGNoZWNrIHRoaXMgZm9ybSB0aGUgaGVhZGVyIG9uIHRoZSBDb25zb2xlIHRhYikKLSBBIHByb2plY3Qgc3BlY2lmaWMgKipIaXN0b3J5KiogaXMgaW5pdGlhdGVkLgoKCiMjIFdvcmtpbmcgaW4gUiBOb3RlYm9va3MKCldlJ2xsIGFsc28gYmUgd29ya2luZyBpbiBhbiBbKipSIE5vdGVib29rKipdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9ub3RlYm9vay5odG1sKS4gVGhlc2UgZmlsZSBhcmUgYW4gW1IgTWFya2Rvd25dKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi8pIGRvY3VtZW50IHR5cGUsIHdoaWNoIGFsbG93IHVzIHRvICoqY29tYmluZSBSIGNvZGUgd2l0aCoqIFttYXJrZG93bl0oaHR0cHM6Ly9wYW5kb2Mub3JnL01BTlVBTC5odG1sI3BhbmRvY3MtbWFya2Rvd24pLCAqKmEgZG9jdW1lbnRhdGlvbiBsYW5ndWFnZSoqLCBwcm92aWRpbmcgYSBmcmFtZXdvcmsgZm9yIFtsaXRlcmF0ZSBwcm9ncmFtbWluZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGl0ZXJhdGVfcHJvZ3JhbW1pbmcpLiAgSW4gYW4gUiBOb3RlYm9vaywgUiBjb2RlIGNodW5rcyBjYW4gYmUgZXhlY3V0ZWQgaW5kZXBlbmRlbnRseSBhbmQgaW50ZXJhY3RpdmVseSwgd2l0aCBvdXRwdXQgdmlzaWJsZSBpbW1lZGlhdGVseSBiZW5lYXRoIHRoZSBpbnB1dC4KCioqTGV0J3Mgb3BlbiBhbiBSIE5vdGVib29rIHRvIHN0YXJ0IHdvcmsgaW4uKioKCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPgoKIyMjIyAqKkZpbGUgPiBPcGVuIEZpbGUgPioqIAoKLSBOYXZpZ2F0ZSB0byB0aGUgZmlsZSBgbm90ZXMuUm1kYCBpbiB0aGUgY291cnNlIG1hdGVyaWFscwoKPC9kaXY+CgpFYWNoIGNodW5rIG9mIFIgY29kZSBsb29rcyBzb21ldGhpbmcgbGlrZSB0aGlzLgoKICAgIGByICcnYGBgYHtyfQogICAgcHJpbnQoJ2hlbGxvIHdvcmxkIScpCiAgICBgYGAKCk5ldyBSIGNvZGUgY2h1bmtzIGNhbiBiZSBpbnNlcnRlZCBieTogCgotIGtleWJvYXJkIHNob3J0Y3V0OiBgQ3RybCArIEFsdCArIElgIChtYWNPUzogYENtZCArIE9wdGlvbiArIElgKSAKLSBgSW5zZXJ0YCBtZW51IGluIHRoZSBlZGl0b3IgdG9vbGJhci4KCkVhY2ggbGluZSBvZiBSIGluIHRoZSBjaHVua3MgY2FuIGJlIGFnYWluIGV4ZWN1dGVkIGJ5IGNsaWNraW5nIG9uIHRoZSBsaW5lIG9yIGhpZ2hsaWdodGluZyBjb2RlIGFuZCBwcmVzc2luZyBgQ3RybCArIEVudGVyYCAobWFjT1M6IGBDbWQgKyBFbnRlcmApLCBvciB5b3UgY2FuIHByZXNzIHRoZSBncmVlbiB0cmlhbmdsZSBvbiB0aGUgcmlnaHQtaGFuZCBzaWRlIHRvIHJ1biBldmVyeXRoaW5nIGluIHRoZSBjaHVuay4KCgpfRm9yIG1vcmUgZGV0YWlscywgY2hlY2sgb3V0IHRoaXMgW3Nob3J0IHR1dG9yaWFsXShodHRwczovL2FubmFrcnlzdGFsbGkubWUvbGl0ZXJhdGUtcHJvZ3JhbW1pbmcvKSBvbiBsaXRlcmF0ZSBwcm9ncmFtbWluZyBpbiBSIE1hcmtkb3duXwoKTGV0J3MgY2xlYXIgZXZlcnl0aGluZyBhbmQgd3JpdGUgb3VyIGZpcnN0IG1hcmtkb3duIGFuZCBjaHVuayBvZiBjb2RlIGJ5IGNyZWF0aW5nIGEgYG1hcmtkb3duYCBoZWFkZXIgd2l0aDoKCmBgYAojIFBhY2thZ2VzCmBgYAoKCmFuZCBsb2FkaW5nIHRoZSB0aWR5dmVyc2UgcGFja2FnZXMgZm9yIHRoZSBhbmFseXNpcyBpbiBvdXIgbm90ZWJvb2sKCiAgICBgciAnJ2BgYGB7ciBsb2FkLXBhY2thZ2VzfQogICAgbGlicmFyeSgidGlkeXZlcnNlIikKICAgIGBgYAoKYGBge3IgbG9hZC1wYWNrYWdlcywgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSgidGlkeXZlcnNlIikKYGBgCgo8YnI+CgoKCiMjIFJlYWRpbmcgaW4gZGF0YQoKQW55IGAuY3N2YCBmaWxlIGNhbiBiZSBpbXBvcnRlZCBpbnRvIFIgYnkgc3VwcGx5aW5nIHRoZSBwYXRoIHRvIHRoZSBmaWxlIHRvIGByZWFkcmAgZnVuY3Rpb24gYHJlYWRfY3N2YCBhbmQgYXNzaWduaW5nIGl0IHRvIGEgbmV3IG9iamVjdCB0byBzdG9yZSB0aGUgcmVzdWx0LiBBIHVzZWZ1bCBzYW5pdHkgY2hlY2sgaXMgdGhlIGBmaWxlLmV4aXN0c2AgZnVuY3Rpb24gd2hpY2ggd2lsbCBwcmludCBgVFJVRWAgaXMgdGhlIGZpbGUgY2FuIGJlIGZvdW5kIGluIHRoZSB3b3JraW5nIGRpcmVjdG9yeS4KCmBgYHtyfQpnYXBtaW5kZXJfcGF0aCA8LSAicmF3X2RhdGEvZ2FwbWluZGVyLmNzdiIKZmlsZS5leGlzdHMoZ2FwbWluZGVyX3BhdGgpCmBgYAoKCkFzc3VtaW5nIHRoZSBmaWxlIGNhbiBiZSBmb3VuZCwgd2UgY2FuIHVzZSBgcmVhZF9jc3ZgIHRvIGltcG9ydC4gT3RoZXIgZnVuY3Rpb25zIGNhbiBiZSB1c2VkIHRvIHJlYWQgdGFiLWRlbGltaXRlZCBmaWxlcyAoYHJlYWRfZGVsaW1gKSBvciBhIGdlbmVyaWMgYHJlYWQudGFibGVgIGZ1bmN0aW9uLiBBIGRhdGEgZnJhbWUgb2JqZWN0IGlzIGNyZWF0ZWQuCgpgYGB7cn0KZ2FwbWluZGVyIDwtIHJlYWRfY3N2KGdhcG1pbmRlcl9wYXRoKQpgYGAKCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPgoKKipRdWVzdGlvbjogV2h5IHdvdWxkIHNwZWNpZnlpbmcgYGdhcG1pbmRlcl9wYXRoYCBhcyAqKgpgYGAKZ2FwbWluZGVyX3BhdGggPC0gIi9Vc2Vycy9Bbm5hL0RvY3VtZW50cy93b3JrZmxvd3Mvd29ya3Nob3BzL3ItY3Jhc2gtY291cnNlL3Jhd19kYXRhL2dhcG1pbmRlci5jc3YiCmBgYAoKKipiZSBhIGJhZCBpZGVhPyoqCgo8L2Rpdj4KCgpUaGUgZGF0YSBmcmFtZSBvYmplY3QgaW4gUiBhbGxvd3MgdXMgdG8gd29yayB3aXRoICoqInRhYnVsYXIiIGRhdGEqKiwgbGlrZSB3ZSBtaWdodCBiZSB1c2VkIHRvIGRlYWxpbmcgd2l0aCBpbiBFeGNlbCwgd2hlcmUgb3VyIGRhdGEgY2FuIGJlIHRob3VnaHQgb2YgaGF2aW5nICoqcm93cyBhbmQgY29sdW1ucyoqLiBUaGUgdmFsdWVzIGluICoqZWFjaCBjb2x1bW4qKiBoYXZlIHRvIGFsbCBiZSBvZiB0aGUgKipzYW1lIHR5cGUqKiAoaS5lLiBhbGwgbnVtYmVycyBvciBhbGwgdGV4dCkuCgpJbiBSc3R1ZGlvLCB5b3UgY2FuICoqdmlldyB0aGUgY29udGVudHMgb2YgdGhlIGRhdGEgZnJhbWUqKiB3ZSBoYXZlIGp1c3QgY3JlYXRlZCB1c2luZyBmdW5jdGlvbiBgVmlldygpYC4gVGhpcyBpcyB1c2VmdWwgZm9yIGludGVyYWN0aXZlIGV4cGxvcmF0aW9uIG9mIHRoZSBkYXRhLCBidXQgbm90IHNvIHVzZWZ1bCBmb3IgYXV0b21hdGlvbiwgc2NyaXB0aW5nIGFuZCBhbmFseXNlcy4KCmBgYHtyIGV2YWw9RkFMU0V9ClZpZXcoZ2FwbWluZGVyKQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CmdhcG1pbmRlcgpgYGAKCgoKV2Ugc2hvdWxkICoqYWx3YXlzIGNoZWNrIHRoZSBkYXRhIGZyYW1lIHRoYXQgd2UgaGF2ZSBjcmVhdGVkKiouIFNvbWV0aW1lcyBSIHdpbGwgaGFwcGlseSByZWFkIGRhdGEgdXNpbmcgYW4gaW5hcHByb3ByaWF0ZSBmdW5jdGlvbiBhbmQgY3JlYXRlIGFuIG9iamVjdCB3aXRob3V0IHJhaXNpbmcgYW4gZXJyb3IuIEhvd2V2ZXIsIHRoZSBkYXRhIG1pZ2h0IGJlIHVuc3VhYmxlLiBDb25zaWRlcjotCgpgYGB7cn0KdGVzdCA8LSByZWFkX3RhYmxlKGdhcG1pbmRlcl9wYXRoKQpgYGAKCmBgYHtyLCBldmFsPUZ9ClZpZXcodGVzdCkKYGBgCgpgYGB7ciwgZWNobyA9IEZBTFNFfQp0ZXN0CmBgYAoKUXVpY2sgc2FuaXR5IGNoZWNrcyBjYW4gYWxzbyBiZSBwZXJmb3JtZWQgYnkgaW5zcGVjdGluZyBkZXRhaWxzIGluIHRoZSBlbnZpcm9ubWVudCB0YWIuIEEgdXNlZnVsIGNoZWNrIGluIFJTdHVkaW8gaXMgdG8gdXNlIHRoZSBgaGVhZGAgZnVuY3Rpb24sIHdoaWNoIHByaW50cyB0aGUgZmlyc3QgNiByb3dzIG9mIHRoZSBkYXRhIGZyYW1lIHRvIHRoZSBzY3JlZW4uCgpgYGB7cn0KaGVhZChnYXBtaW5kZXIpCmBgYAoKCiMjIEFjY2Vzc2luZyBkYXRhIGluIGNvbHVtbnMKCkluIHRoZSBuZXh0IHNlY3Rpb24gd2Ugd2lsbCBleHBsb3JlIGluIG1vcmUgZGV0YWlsIGhvdyB0byBjb250cm9sIHRoZSBjb2x1bW5zIGFuZCByb3dzIGZyb20gYSBkYXRhIGZyYW1lIHRoYXQgYXJlIGRpc3BsYXllZCBpbiBSU3R1ZGlvLiBGb3Igbm93LCBhY2Nlc3NpbmcgYWxsIHRoZSBvYnNlcnZhdGlvbnMgZnJvbSBhIHBhcnRpY3VsYXIgY29sdW1uIGNhbiBiZSBhY2hpZXZlZCBieSB0eXBpbmcgdGhlIGAkYCBzeW1ib2wgYWZ0ZXIgdGhlIG5hbWUgb2YgdGhlIGRhdGEgZnJhbWUgZm9sbG93ZWQgYnkgdGhlIG5hbWUgb2YgYSBjb2x1bW4geW91IGFyZSBpbnRlcmVzdGVkIGluLgoKUlN0dWRpbyBpcyBhYmxlIHRvICoidGFiLWNvbXBsZXRlIiogdGhlIGNvbHVtbiBuYW1lLCBzbyB0eXBpbmcgdGhlIGZvbGxvd2luZyBhbmQgcHJlc3NzaW5nIHRoZSAqKlRBQioqIGtleSB3aWxsIGJyaW5nLXVwIGEgbGlzdCBvZiBwb3NzaWJsZSBjb2x1bW5zLiBUaGUgY29udGVudHMgb2YgdGhlIGNvbHVtbiB0aGF0IHlvdSBzZWxlY3QgYXJlIHRoZW4gcHJpbnRlZCB0byB0aGUgc2NyZWVuLgoKYGBge3IgZXZhbD1GQUxTRX0KZ2FwbWluZGVyJGMKYGBgCgpSYXRoZXIgdGhhbiBtZXJlbHkgcHJpbnRpbmcgdG8gdGhlIHNjcmVlbiB3ZSBjYW4gYWxzbyBjcmVhdGUgYSB2YXJpYWJsZQoKYGBge3J9CmNvdW50cnlfdmVjIDwtIGdhcG1pbmRlciRjb3VudHJ5CmBgYAoKKioqKioqCioqKioqKgoqKioqKioKCgoKIyMjIEV4ZXJjaXNlCgotIFRoZSBmdW5jdGlvbiBgdGFpbGAgaXMgc2ltaWxhciB0byBgaGVhZGAgZXhjZXB0IGl0IHByaW50cyB0aGUgKmxhc3QqIGxpbmVzIGluIGEgZmlsZS4gVXNlIHRoaXMgZnVuY3Rpb24gdG8gcHJpbnQgdGhlIGxhc3QgKjEwKiBsaW5lcyBpbiB0aGUgZGF0YSBmcmFtZSAoeW91IHdpbGwgaGF2ZSB0byBjb25zdWx0IHRoZSBoZWxwIG9uIGB0YWlsYCB0byBzZWUgaG93IHRvIGNoYW5nZSB0aGUgZGVmYXVsdCBhcmd1bWVudHMuKQotIFdoYXQgaXMgdGhlIGxhcmdlc3Qgb2JzZXJ2ZWQgcG9wdWxhdGlvbj8KLSBXaGF0IGlzIHRoZSBsb3dlc3QgbGlmZSBleHBlY3RhbmN5CgoqKioqKioKKioqKioqCioqKioqKgoKCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPgoKKipRdWVzdGlvbjogRmFtaWxpYXJpc2UgeW91cnNlbGYgd2l0aCB0aGUgY29udGVudHMgb2YgdGhlIGRhdGEgZnJhbWUuIFdoYXQgbnVtZXJpY2FsIHN1bW1hcmllcyBjYW4geW91IHByb2R1Y2UgZnJvbSB0aGUgZGF0YXNldCAoZS5nLiBhdmVyYWdlIGxpZmUgZXhwZWN0YW5jeSBwZXIteWVhciwgY291bnRyaWVzIHRoYXQgYXJlIG1vc3Qgd2VhbHRoeSBldGMpIGFuZCB3aGF0IHBsb3RzIG1pZ2h0IGJlIG9mIGludGVyZXN0PyBEaXNjdXNzIHdpdGggeW91ciBuZWlnaGJvdXJzKioKCjwvZGl2Pgo=