Acknowledgement

These materials are adapted from a course developed at Cancer Research Uk Cambridge Institute by Mark Dunning, Matthew Eldridge and Thomas Carroll.

Introduction to R - Part I

RStudio

  • Rstudio is a free environment for R
  • Convenient menus to access scripts, display plots
  • Still need to use command-line to get things done
  • Developed by some of the leading R programmers
  • Used by beginners, and experienced users alike

To get started, you will need to install the latest version of R and RStudio Desktop; both of which are free.

Once installed, you should be able to launch RStudio by clicking on its icon:-

Entering commands in R

  • The traditional way to enter R commands is via the Terminal, or using the console in RStudio (bottom-left panel when RStudio opens for first time).
  • this doesn’t automatically keep track of the steps you did
  • Alternative, an R script can be used to keep a record of the commands you used.
  • The R code can be run from inside the script and the results are displayed in the console or Viewer panel (eg plots)
  • Each line of R code can be executed by clicking on the line and pressing CTRL and ENTER
  • Let’s try this now!

File -> New File -> R script >

print("Hello World")
[1] "Hello World"

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:

  • Self-contained
  • Portable

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=