Setup
If you are following these notes independently (outside one of our
workshops)
From the RStudio menus, Choose the File ->
New Project option and select New Directory from the
new window
Then for the Project Type pick New Project.
It will ask you to pick a new Directory name, and where to create
that directory (e.g. your Home directory or directory where you usually
save your work)
RStudio should now refresh itself. You can now download the data
required for the workshop by copying and pasting the following into the
R console (as shown in the screenshot)
download.file("https://github.com/sheffield-bioinformatics-core/r-online/raw/master/CourseData.zip", destfile = "CourseData.zip")
The files from the zip file
can be extracted using the command:-
unzip("CourseData.zip")
Your RStudio screen should look like:-
You will need to install some R packages and download some data
before you start. You can install the packages by copying and pasting
the following into an R console and pressing ENTER
install.packages("dplyr")
install.packages("ggplot2")
install.packages("readr")
install.packages("rmarkdown")
install.packages("tidyr")
You can check that this worked by copying and pasting the
following:-
source("https://raw.githubusercontent.com/sheffield-bioinformatics-core/r-online/master/check_packages.R")
If you want to follow along with the R code on this webpage, you can
open the file part1.Rmd
from the bottom-right corner of
RStudio
There are equivalent markdown files (part2.Rmd
,
part3.Rmd
) for the other sections of the course. Enjoy!
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.
We’ll 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 try this now!
print("Hello World")
[1] "Hello World"
R can be used as a calculator to compute simple sums
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
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 .
and ‘-’. 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] -2.0690050 -0.8799215 0.8531629 -1.2221350 1.0475075 -0.1032297 1.8407880 -1.1273168 -1.2792828 0.8880592
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] 4.373978 1.360815 4.212582 3.672289 4.476515 1.957271 1.805467 2.342051 4.617946 7.654854
rnorm(10, 2, 3)
[1] 0.9384763 2.1877732 2.8970267 6.9594988 4.4298546 3.0944059 0.1522375 4.1629333 3.3335281 2.3153513
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.
Just as we can save single numbers as a variable, we can also save a
vector. In fact a single number is still a vector.
my_seq <- seq(from = 3, to = 20, by = 4)
The arithmetic operations we have seen can be applied to these
vectors; exactly the same as a single number.
my_seq + 2
[1] 5 9 13 17 21
my_seq * 2
[1] 6 14 22 30 38
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?
- i.e. not specifying the
by
argument and getting R to
work-out the intervals
- 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
## Type your code to answer the exercises in here
Saving your notebook
If you want to re-visit your code at any point, you will need to save
a copy.
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.
CRAN and Bioconductor have some level of curation so should be the
first place to look. Researchers sometimes make their packages available
on github. However, there is no
straightforward way of searching github for a particular package and no
guarentee of quality.
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 a set of tidyverse
R packages in this
practical. To install them, we would do.
## You should already have installed these as part of the course setup
install.packages("readr")
install.packages("ggplot2")
install.packages("dplyr")
# to install the entire set of tidyverse packages, we can do install.packages("tidyverse"). But this will take some time
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 readr
so
we can import some data.
## readr is a packages to import spreadsheets into R
library(readr)
Dealing with data
The tidyverse
is 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.
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.
library(readr)
gapminder_path <- "raw_data/gapminder.csv"
gapminder <- read_csv(gapminder_path)
Rows: 1704 Columns: 6── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (2): country, continent
dbl (4): year, lifeExp, pop, gdpPercap
ℹ 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.
Why would specifying gapminder_path
as
Users/Anna/Documents/workflows/workshops/r-crash-course/raw_data/gapminder.csv
be a bad idea? Would you be able to re-run the analysis
on another machine?
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.
## Make sure that you use a capital letter V
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 unusable. Consider:-
test <- read_table(gapminder_path)
── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
cols(
`"country","continent","year","lifeExp","pop","gdpPercap"` = col_character()
)
Warning: 324 parsing failures.
row col expected actual file
145 -- 1 columns 3 columns 'raw_data/gapminder.csv'
146 -- 1 columns 3 columns 'raw_data/gapminder.csv'
147 -- 1 columns 3 columns 'raw_data/gapminder.csv'
148 -- 1 columns 3 columns 'raw_data/gapminder.csv'
149 -- 1 columns 3 columns 'raw_data/gapminder.csv'
... ... ......... ......... ........................
See problems(...) for more details.
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)
We have used a nice, clean, dataset as our example for the workshop.
Other datasets out in the wild might not be so ameanable for analysis in
R. If your data look like this, you might have problems:-
We recommend the Data Carpentry materials on spreadsheet organisation
for an overview of common pitfalls - and how to address them
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 pressing 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
years <- gapminder$year
We can then use some of the functions we have seen before
min(years)
[1] 1952
max(years)
[1] 2007
median(years)
[1] 1979.5
Although we don’t have to save the values in the column as a variable
first
min(gapminder$year)
[1] 1952
Creating a new R notebook
You will probably want to create a new R notebook file to
perform your analysis. This can be done by following the menus:-
A new pane should open that includes some example code. You can
delete everything apart from lines 1 to 4
You can now insert R code chunks using the insert menu.
Before generating a report you will need to save the file with the
menu File -> Save. You will then be able to create a
report using the Preview button. N.B. you may need to install extra
software before doing this.
Exercise before the next session
- Create a new R notebook using the instructions above and create a
code chunk to read the
gapminder.csv
file. Answer the
following questions and generate a report
- 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
(Optional): 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
LS0tCnRpdGxlOiAiUiBDcmFzaCBDb3Vyc2UiCmF1dGhvcjogIk1hcmsgRHVubmluZyIKZGF0ZTogJ2ByIGZvcm1hdChTeXMudGltZSgpLCAiTGFzdCBtb2RpZmllZDogJWQgJWIgJVkiKWAnCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNzczogc3R5bGVzaGVldHMvc3R5bGVzLmNzcwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KPGltZyBzcmM9ImltYWdlcy9sb2dvLXNtLnBuZyIgc3R5bGU9InBvc2l0aW9uOmFic29sdXRlO3RvcDo0MHB4O3JpZ2h0OjEwcHg7IiB3aWR0aD0iMjAwIiAvPgoKCiMgQWNrbm93bGVkZ2VtZW50CgpJZiB5b3UgZmluZCB0aGVzZSBtYXRlcmlhbHMgdXNlZnVsIGZvciB5b3VyIHJlc2VhcmNoLCBwbGVhc2UgY29uc2lkZXIgYWNrbm93bGVkZ2luZyB0aGUgU2hlZmZpZWxkIEJpb2luZm9ybWF0aWNzIENvcmUgaW4gYW55IG91dHB1dHMgdGhhdCBhcmlzZSBmcm9tIGhhdmluZyBsZWFybnQgUi4gWW91IGNhbiBjb250YWN0IHVzIGZvciBzdXBwb3J0IG9uIHNwZWNpZmljIHByb2plY3RzIHVzaW5nOi0gYGJpb2luZm9ybWF0aWNzLWNvcmVAc2hlZmZpZWxkLmFjLnVrYAoKIyBEaXNjbGFpbWVyCgo8ZGl2IGNsYXNzPSJ3YXJuaW5nIj4KQWx0aG91Z2ggUiBpcyB3ZWxsLXJlZ2FyZGVkIGFzIGEgdG9vbCBmb3IgcGVyZm9ybWluZyBzdGF0aXN0aWNhbCBhbmFseXNpcywgdGhpcyB3b3Jrc2hvcCB3aWxsIG5vdCBleHBsaWNpdGx5IHRlYWNoIHN0YXRzLiBJbnN0ZWFkIHdlIGdpdmUgaW50cm9kdWNlIHRoZSB0b29scyB0aGF0IHdlIGFsbG93IHlvdSB0byBtYW5pcHVsYXRlIGFuZCBpbnRlcnJvZ2F0ZSB5b3VyIGRhdGEgaW50byBhIGZvcm0gd2l0aCB3aGljaCB5b3UgY2FuIGV4ZWN1dGUgc3RhdGlzdGljYWwgdGVzdHMuCgo8L2Rpdj4KCiMgU2V0dXAKCklmIHlvdSBhcmUgZm9sbG93aW5nIHRoZXNlIG5vdGVzIGluZGVwZW5kZW50bHkgKG91dHNpZGUgb25lIG9mIG91ciB3b3Jrc2hvcHMpIAoKCkZyb20gdGhlIFJTdHVkaW8gbWVudXMsIENob29zZSB0aGUgKipGaWxlKiogLT4gKipOZXcgUHJvamVjdCoqIG9wdGlvbiBhbmQgc2VsZWN0IE5ldyBEaXJlY3RvcnkgZnJvbSB0aGUgbmV3IHdpbmRvdwoKIVtdKGltYWdlcy9uZXdfcHJvajEucG5nKQoKVGhlbiBmb3IgdGhlICoqUHJvamVjdCBUeXBlKiogcGljayBOZXcgUHJvamVjdC4gIAoKIVtdKGltYWdlcy9uZXdfcHJvajIucG5nKQoKCgpJdCB3aWxsIGFzayB5b3UgdG8gcGljayBhIG5ldyBEaXJlY3RvcnkgbmFtZSwgYW5kIHdoZXJlIHRvIGNyZWF0ZSB0aGF0IGRpcmVjdG9yeSAoZS5nLiB5b3VyIEhvbWUgZGlyZWN0b3J5IG9yIGRpcmVjdG9yeSB3aGVyZSB5b3UgdXN1YWxseSBzYXZlIHlvdXIgd29yaykKCiFbXShpbWFnZXMvbmV3X3Byb2ozLnBuZykKClJTdHVkaW8gc2hvdWxkIG5vdyByZWZyZXNoIGl0c2VsZi4gWW91IGNhbiBub3cgZG93bmxvYWQgdGhlIGRhdGEgcmVxdWlyZWQgZm9yIHRoZSB3b3Jrc2hvcCBieSBjb3B5aW5nIGFuZCBwYXN0aW5nIHRoZSBmb2xsb3dpbmcgaW50byB0aGUgUiBjb25zb2xlIChhcyBzaG93biBpbiB0aGUgc2NyZWVuc2hvdCkKCmBgYHtyfQpkb3dubG9hZC5maWxlKCJodHRwczovL2dpdGh1Yi5jb20vc2hlZmZpZWxkLWJpb2luZm9ybWF0aWNzLWNvcmUvci1vbmxpbmUvcmF3L21hc3Rlci9Db3Vyc2VEYXRhLnppcCIsIGRlc3RmaWxlID0gIkNvdXJzZURhdGEuemlwIikKYGBgCgohW10oaW1hZ2VzL2RhdGFfZG93bmxvYWQucG5nKQpUaGUgZmlsZXMgZnJvbSB0aGUgemlwIGZpbGUgY2FuIGJlIGV4dHJhY3RlZCB1c2luZyB0aGUgY29tbWFuZDotCgpgYGB7cn0KdW56aXAoIkNvdXJzZURhdGEuemlwIikKYGBgCgpZb3VyIFJTdHVkaW8gc2NyZWVuIHNob3VsZCBsb29rIGxpa2U6LQoKIVtdKGltYWdlcy9kYXRhX2Rvd25sb2FkXzIucG5nKQoKCgpZb3Ugd2lsbCBuZWVkIHRvIGluc3RhbGwgc29tZSBSIHBhY2thZ2VzIGFuZCBkb3dubG9hZCBzb21lIGRhdGEgYmVmb3JlIHlvdSBzdGFydC4gWW91IGNhbiBpbnN0YWxsIHRoZSBwYWNrYWdlcyBieSBjb3B5aW5nIGFuZCBwYXN0aW5nIHRoZSBmb2xsb3dpbmcgaW50byBhbiBSIGNvbnNvbGUgYW5kIHByZXNzaW5nIEVOVEVSCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKaW5zdGFsbC5wYWNrYWdlcygicmVhZHIiKQppbnN0YWxsLnBhY2thZ2VzKCJybWFya2Rvd24iKQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5ciIpCmBgYAoKWW91IGNhbiBjaGVjayB0aGF0IHRoaXMgd29ya2VkIGJ5IGNvcHlpbmcgYW5kIHBhc3RpbmcgdGhlIGZvbGxvd2luZzotCgpgYGB7cn0Kc291cmNlKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc2hlZmZpZWxkLWJpb2luZm9ybWF0aWNzLWNvcmUvci1vbmxpbmUvbWFzdGVyL2NoZWNrX3BhY2thZ2VzLlIiKQpgYGAKCgpJZiB5b3Ugd2FudCB0byBmb2xsb3cgYWxvbmcgd2l0aCB0aGUgUiBjb2RlIG9uIHRoaXMgd2VicGFnZSwgeW91IGNhbiBvcGVuIHRoZSBmaWxlIGBwYXJ0MS5SbWRgIGZyb20gdGhlIGJvdHRvbS1yaWdodCBjb3JuZXIgb2YgUlN0dWRpbwoKIVtdKGltYWdlcy9maW5kX21hcmtkb3duLnBuZykKClRoZXJlIGFyZSBlcXVpdmFsZW50IG1hcmtkb3duIGZpbGVzIChgcGFydDIuUm1kYCwgYHBhcnQzLlJtZGApIGZvciB0aGUgb3RoZXIgc2VjdGlvbnMgb2YgdGhlIGNvdXJzZS4gRW5qb3khCgojIEVudGVyaW5nIGNvbW1hbmRzIGluIFIKClRoZSB0cmFkaXRpb25hbCB3YXkgdG8gZW50ZXIgUiBjb21tYW5kcyBpcyB2aWEgdGhlIFRlcm1pbmFsLCBvciB1c2luZyB0aGUgY29uc29sZSBpbiBSU3R1ZGlvIChib3R0b20tbGVmdCBwYW5lbCB3aGVuIFJTdHVkaW8gb3BlbnMgZm9yIGZpcnN0IHRpbWUpLiBUaGlzIGRvZXNu4oCZdCBhdXRvbWF0aWNhbGx5IGtlZXAgdHJhY2sgb2YgdGhlIHN0ZXBzIHlvdSBkaWQuCgpXZSdsbCBiZSB3b3JraW5nIGluIGFuIFsqKlIgTm90ZWJvb2sqKl0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duL25vdGVib29rLmh0bWwpLiBUaGVzZSBmaWxlIGFyZSBhbiBbUiBNYXJrZG93bl0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLykgZG9jdW1lbnQgdHlwZSwgd2hpY2ggYWxsb3cgdXMgdG8gKipjb21iaW5lIFIgY29kZSB3aXRoKiogW21hcmtkb3duXShodHRwczovL3BhbmRvYy5vcmcvTUFOVUFMLmh0bWwjcGFuZG9jcy1tYXJrZG93biksICoqYSBkb2N1bWVudGF0aW9uIGxhbmd1YWdlKiosIHByb3ZpZGluZyBhIGZyYW1ld29yayBmb3IgW2xpdGVyYXRlIHByb2dyYW1taW5nXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9MaXRlcmF0ZV9wcm9ncmFtbWluZykuICBJbiBhbiBSIE5vdGVib29rLCBSIGNvZGUgY2h1bmtzIGNhbiBiZSBleGVjdXRlZCBpbmRlcGVuZGVudGx5IGFuZCBpbnRlcmFjdGl2ZWx5LCB3aXRoIG91dHB1dCB2aXNpYmxlIGltbWVkaWF0ZWx5IGJlbmVhdGggdGhlIGlucHV0LgoKTGV04oCZcyB0cnkgdGhpcyBub3chCgpgYGB7cn0KcHJpbnQoIkhlbGxvIFdvcmxkIikKYGBgCgpSIGNhbiBiZSB1c2VkIGFzIGEgY2FsY3VsYXRvciB0byBjb21wdXRlIHNpbXBsZSBzdW1zCgoKYGBge3J9CjIgKyAyCjIgLSAyCjQgKiAzCjEwIC8gMgpgYGAKClRoZSBhbnN3ZXIgaXMgZGlzcGxheWVkIGF0IHRoZSBjb25zb2xlIHdpdGggYSBgWzFdYCBpbiBmcm9udCBvZiBpdC4gVGhlIGAxYCBpbnNpZGUgdGhlIHNxdWFyZSBicmFja2V0cyBpcyBhIHBsYWNlLWhvbGRlciB0byBzaWduaWZ5IGhvdyBtYW55IHZhbHVlcyB3ZXJlIGluIHRoZSBhbnN3ZXIgKGluIHRoaXMgY2FzZSBvbmx5IG9uZSkuIFdlIHdpbGwgdGFsayBhYm91dCBkZWFsaW5nIHdpdGggbGlzdHMgb2YgbnVtYmVycyBzaG9ydGx5Li4uCgpJbiB0aGUgY2FzZSBvZiBleHByZXNzaW9ucyBpbnZvbHZpbmcgbXVsdGlwbGUgb3BlcmF0aW9ucywgUiByZXNwZWN0cyB0aGUgW0JPRE1BU10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvT3JkZXJfb2Zfb3BlcmF0aW9ucyNNbmVtb25pY3MpIHN5c3RlbSB0byBkZWNpZGUgdGhlIG9yZGVyIGluIHdoaWNoIG9wZXJhdGlvbnMgc2hvdWxkIGJlIHBlcmZvcm1lZC4KCmBgYHtyfQoyICsgMiAqMwoyICsgKDIgKiAzKQooMiArIDIpICogMwpgYGAKClIgaXMgY2FwYWJsZSBvZiBtb3JlIGNvbXBsaWNhdGVkIGFyaXRobWV0aWMgc3VjaCBhcyB0cmlnb25vbWV0cnkgYW5kIGxvZ2FyaXRobXM7IGxpa2UgeW91IHdvdWxkIGZpbmQgb24gYSBmYW5jeSBzY2llbnRpZmljIGNhbGN1bGF0b3IuIE9mIGNvdXJzZSwgUiBhbHNvIGhhcyBhIHBsZXRob3JhIG9mIHN0YXRpc3RpY2FsIG9wZXJhdGlvbnMgYXMgd2Ugd2lsbCBzZWUuCgoKYGBge3J9CnBpCnNpbiAocGkvMikKY29zKHBpKQp0YW4oMikKbG9nKDEpCmBgYAoKV2UgY2FuIG9ubHkgZ28gc28gZmFyIHdpdGggcGVyZm9ybWluZyBzaW1wbGUgY2FsY3VsYXRpb25zIGxpa2UgdGhpcy4gRXZlbnR1YWxseSB3ZSB3aWxsIG5lZWQgdG8gc3RvcmUgb3VyIHJlc3VsdHMgZm9yIGxhdGVyIHVzZS4gRm9yIHRoaXMsIHdlIG5lZWQgdG8gbWFrZSB1c2Ugb2YgKnZhcmlhYmxlcyouCgojIyBWYXJpYWJsZXMKCkEgdmFyaWFibGUgaXMgYSBsZXR0ZXIgb3Igd29yZCB3aGljaCB0YWtlcyAob3IgY29udGFpbnMpIGEgdmFsdWUuIFdlCnVzZSB0aGUgYXNzaWdubWVudCAnb3BlcmF0b3InLCBgPC1gIHRvIGNyZWF0ZSBhIHZhcmlhYmxlIGFuZCBzdG9yZSBzb21lIHZhbHVlIGluIGl0LiAKCmBgYHtyfQp4IDwtIDEwCngKbXlOdW1iZXIgPC0gMjUKbXlOdW1iZXIKYGBgCldlIGFsc28gY2FuIHBlcmZvcm0gYXJpdGhtZXRpYyBvbiB2YXJpYWJsZXMgdXNpbmcgZnVuY3Rpb25zOgoKYGBge3J9CnNxcnQobXlOdW1iZXIpCmBgYAoKV2UgY2FuIGFkZCB2YXJpYWJsZXMgdG9nZXRoZXI6CmBgYHtyfQp4ICsgbXlOdW1iZXIKYGBgCgoKV2UgY2FuIGNoYW5nZSB0aGUgdmFsdWUgb2YgYW4gZXhpc3RpbmcgdmFyaWFibGU6CgpgYGB7cn0KeCA8LSAyMQp4CmBgYAoKV2UgY2FuIHNldCBvbmUgdmFyaWFibGUgdG8gZXF1YWwgdGhlIHZhbHVlIG9mIGFub3RoZXIgdmFyaWFibGU6CgpgYGB7cn0KeCA8LSBteU51bWJlcgp4CmBgYAoKCldoZW4gd2UgYXJlIGZlZWxpbmcgbGF6eSB3ZSBtaWdodCBnaXZlIG91ciB2YXJpYWJsZXMgc2hvcnQgbmFtZXMgKGB4YCwgYHlgLCBgaWAuLi5ldGMpLCBidXQgYSBiZXR0ZXIgcHJhY3RpY2Ugd291bGQgYmUgdG8gZ2l2ZSB0aGVtIG1lYW5pbmdmdWwgbmFtZXMuIFRoZXJlIGFyZSBzb21lIHJlc3RyaWN0aW9ucyBvbiBjcmVhdGluZyB2YXJpYWJsZSBuYW1lcy4gVGhleSBjYW5ub3Qgc3RhcnQgd2l0aCBhIG51bWJlciBvciBjb250YWluIGNoYXJhY3RlcnMgc3VjaCBhcyBgLmAgYW5kICctJy4gTmFtaW5nIHZhcmlhYmxlcyB0aGUgc2FtZSBhcyBpbi1idWlsdCBmdW5jdGlvbnMgaW4gUiwgc3VjaCBhcyBgY2AsIGBUYCwgYG1lYW5gIHNob3VsZCBhbHNvIGJlIGF2b2lkZWQuCgpOYW1pbmcgdmFyaWFibGVzIGlzIGEgbWF0dGVyIG9mIHRhc3RlLiBTb21lIFtjb252ZW50aW9uc10oaHR0cDovL2Fkdi1yLmhhZC5jby5uei9TdHlsZS5odG1sKSBleGlzdCBzdWNoIGFzIGEgc2VwYXJhdGluZyB3b3JkcyB3aXRoIGAtYCBvciB1c2luZyAqYyphbWVsKkMqYXBzLiBXaGF0ZXZlciBjb252ZW50aW9uIHlvdSBkZWNpZGVkLCBzdGljayB3aXRoIGl0IQoKIyMgRnVuY3Rpb25zCgoqKkZ1bmN0aW9ucyoqIGluIFIgcGVyZm9ybSBvcGVyYXRpb25zIG9uICoqYXJndW1lbnRzKiogKHRoZSBpbnB1dHMocykgdG8gdGhlIGZ1bmN0aW9uKS4gV2UgaGF2ZSBhbHJlYWR5IHVzZWQ6CgpgYGB7cn0Kc2luKHgpCmBgYAoKdGhpcyByZXR1cm5zIHRoZSBzaW5lIG9mIHguIEluIHRoaXMgY2FzZSB0aGUgZnVuY3Rpb24gaGFzIG9uZSBhcmd1bWVudDogKip4KiouIEFyZ3VtZW50cyBhcmUgYWx3YXlzIGNvbnRhaW5lZCBpbiBwYXJlbnRoZXNlcyAtLSBjdXJ2ZWQgYnJhY2tldHMsICoqKCkqKiAtLSBzZXBhcmF0ZWQgYnkgY29tbWFzLgoKCkFyZ3VtZW50cyBjYW4gYmUgbmFtZWQgb3IgdW5uYW1lZCwgYnV0IGlmIHRoZXkgYXJlIHVubmFtZWQgdGhleSBtdXN0IGJlIG9yZGVyZWQgKHdlIHdpbGwgc2VlIGxhdGVyIGhvdyB0byBmaW5kIHRoZSByaWdodCBvcmRlcikuIFRoZSBuYW1lcyBvZiB0aGUgYXJndW1lbnRzIGFyZSBkZXRlcm1pbmVkIGJ5IHRoZSBhdXRob3Igb2YgdGhlIGZ1bmN0aW9uIGFuZCBjYW4gYmUgZm91bmQgaW4gdGhlIGhlbHAgcGFnZSBmb3IgdGhlIGZ1bmN0aW9uLiBXaGVuIHRlc3RpbmcgY29kZSwgaXQgaXMgZWFzaWVyIGFuZCBzYWZlciB0byBuYW1lIHRoZSBhcmd1bWVudHMuIGBzZXFgIGlzIGEgZnVuY3Rpb24gZm9yIGdlbmVyYXRpbmcgYSBudW1lcmljIHNlcXVlbmNlICpmcm9tKiBhbmQgKnRvKiBwYXJ0aWN1bGFyIG51bWJlcnMuIFR5cGUgYD9zZXFgIHRvIGdldCB0aGUgaGVscCBwYWdlIGZvciB0aGlzIGZ1bmN0aW9uLgoKYGBge3J9CnNlcShmcm9tID0gMywgdG8gPSAyMCwgYnkgPSA0KQpzZXEoMywgMjAsIDQpCmBgYAoKQXJndW1lbnRzIGNhbiBoYXZlICpkZWZhdWx0KiB2YWx1ZXMsIG1lYW5pbmcgd2UgZG8gbm90IG5lZWQgdG8gc3BlY2lmeSB2YWx1ZXMgZm9yIHRoZXNlIGluIG9yZGVyIHRvIHJ1biB0aGUgZnVuY3Rpb24uCgpgcm5vcm1gIGlzIGEgZnVuY3Rpb24gdGhhdCB3aWxsIGdlbmVyYXRlIGEgc2VyaWVzIG9mIHZhbHVlcyBmcm9tIGEgKm5vcm1hbCBkaXN0cmlidXRpb24qLiBJbiBvcmRlciB0byB1c2UgdGhlIGZ1bmN0aW9uLCB3ZSBuZWVkIHRvIHRlbGwgUiBob3cgbWFueSB2YWx1ZXMgd2Ugd2FudAoKYGBge3J9CiMjIHRoaXMgd2lsbCBwcm9kdWNlIGEgcmFuZG9tIHNldCBvZiBudW1iZXJzLCBzbyBldmVyeW9uZSB3aWxsIGdldCBhIGRpZmZlcmVudCBzZXQgb2YgbnVtYmVycwpybm9ybShuPTEwKQpgYGAKClRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIGlzIGRlZmluZWQgYnkgYSAqbWVhbiogKGF2ZXJhZ2UpIGFuZCAqc3RhbmRhcmQgZGV2aWF0aW9uKiAoc3ByZWFkKS4gSG93ZXZlciwgaW4gdGhlIGFib3ZlIGV4YW1wbGUgd2UgZGlkbid0IHRlbGwgUiB3aGF0IG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiB3ZSB3YW50ZWQuIFNvIGhvdyBkb2VzIFIga25vdyB3aGF0IHRvIGRvPyBBbGwgYXJndW1lbnRzIHRvIGEgZnVuY3Rpb24gYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzIGFyZSBsaXN0ZWQgaW4gdGhlIGhlbHAgcGFnZQoKKCpOLkIgc29tZXRpbWVzIGhlbHAgcGFnZXMgY2FuIGRlc2NyaWJlIG1vcmUgdGhhbiBvbmUgZnVuY3Rpb24qKQoKYGBge3J9Cj9ybm9ybQpgYGAKCkluIHRoaXMgY2FzZSwgd2Ugc2VlIHRoYXQgdGhlIGRlZmF1bHRzIGZvciBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gYXJlIDAgYW5kIDEuIFdlIGNhbiBjaGFuZ2UgdGhlIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIHZhbHVlcyBmcm9tIGEgZGlzdHJpYnV0aW9uIHdpdGggYSBkaWZmZXJlbnQgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIHVzaW5nIHRoZSBgbWVhbmAgYW5kIGBzZGAgKmFyZ3VtZW50cyouIEl0IGlzIGltcG9ydGFudCB0aGF0IHdlIGdldCB0aGUgc3BlbGxpbmcgb2YgdGhlc2UgYXJndW1lbnRzIGV4YWN0bHkgcmlnaHQsIG90aGVyd2lzZSBSIHdpbGwgYW4gZXJyb3IgbWVzc2FnZSwgb3IgKHdvcnNlPykgZG8gc29tZXRoaW5nIHVuZXhwZWN0ZWQuCgpgYGB7cn0Kcm5vcm0obj0xMCwgbWVhbj0yLHNkPTMpCnJub3JtKDEwLCAyLCAzKQpgYGAKCkluIHRoZSBleGFtcGxlcyBhYm92ZSwgYHNlcWAgYW5kIGBybm9ybWAgd2VyZSBib3RoIG91dHB1dHRpbmcgYSBzZXJpZXMgb2YgbnVtYmVycywgd2hpY2ggaXMgY2FsbGVkIGEgKnZlY3RvciogaW4gUiBhbmQgaXMgdGhlIG1vc3QtZnVuZGFtZW50YWwgZGF0YS10eXBlLgoKSnVzdCBhcyB3ZSBjYW4gc2F2ZSBzaW5nbGUgbnVtYmVycyBhcyBhIHZhcmlhYmxlLCB3ZSBjYW4gYWxzbyBzYXZlIGEgdmVjdG9yLiBJbiBmYWN0IGEgc2luZ2xlIG51bWJlciBpcyBzdGlsbCBhIHZlY3Rvci4KCmBgYHtyfQpteV9zZXEgPC0gc2VxKGZyb20gPSAzLCB0byA9IDIwLCBieSA9IDQpCmBgYAoKVGhlIGFyaXRobWV0aWMgb3BlcmF0aW9ucyB3ZSBoYXZlIHNlZW4gY2FuIGJlIGFwcGxpZWQgdG8gdGhlc2UgdmVjdG9yczsgZXhhY3RseSB0aGUgc2FtZSBhcyBhIHNpbmdsZSBudW1iZXIuCgpgYGB7cn0KbXlfc2VxICsgMgpgYGAKYGBge3J9Cm15X3NlcSAqIDIKYGBgCgoKKioqKioqCioqKioqKgoqKioqKioKCgoKIyMjIEV4ZXJjaXNlCgo8ZGl2IGNsYXNzPSJleGVyY2lzZSI+CgogIC0gV2hhdCBpcyB0aGUgdmFsdWUgb2YgYHBpYCB0byAzIGRlY2ltYWwgcGxhY2VzPwogICAgKyBzZWUgdGhlIGhlbHAgZm9yIGByb3VuZGAgYD9yb3VuZGAKICAtIEhvdyBjYW4gd2UgYSBjcmVhdGUgYSBzZXF1ZW5jZSBmcm9tIDIgdG8gMjAgY29tcHJpc2VkIG9mIDUgZXF1YWxseS1zcGFjZWQgbnVtYmVycz8KICAgICsgaS5lLiBub3Qgc3BlY2lmeWluZyB0aGUgYGJ5YCBhcmd1bWVudCBhbmQgZ2V0dGluZyBSIHRvIHdvcmstb3V0IHRoZSBpbnRlcnZhbHMKICAgICsgY2hlY2sgdGhlIGhlbHAgcGFnZSBmb3Igc2VxIGA/c2VxYAogIC0gQ3JlYXRlIGEgKnZhcmlhYmxlKiBjb250YWluaW5nIDEwMDAgcmFuZG9tIG51bWJlcnMgd2l0aCBhICptZWFuKiBvZiAyIGFuZCBhICpzdGFuZGFyZCBkZXZpYXRpb24qIG9mIDMKICAgICsgd2hhdCBpcyB0aGUgbWF4aW11bSBhbmQgbWluaW11bSBvZiB0aGVzZSBudW1iZXJzPwogICAgKyB3aGF0IGlzIHRoZSBhdmVyYWdlPwogICAgKyBISU5UOiBzZWUgdGhlIGhlbHAgcGFnZXMgZm9yIGZ1bmN0aW9ucyBgbWluYCwgYG1heGAgYW5kIGBtZWFuYAo8L2Rpdj4KCmBgYHtyfQojIyBUeXBlIHlvdXIgY29kZSB0byBhbnN3ZXIgdGhlIGV4ZXJjaXNlcyBpbiBoZXJlCgoKYGBgCiAgICAKICAgIAoqKioqKioKKioqKioqCioqKioqKgoKIyMgU2F2aW5nIHlvdXIgbm90ZWJvb2sKCklmIHlvdSB3YW50IHRvIHJlLXZpc2l0IHlvdXIgY29kZSBhdCBhbnkgcG9pbnQsIHlvdSB3aWxsIG5lZWQgdG8gc2F2ZSBhIGNvcHkuCgo8ZGl2IGNsYXNzPSJpbmZvcm1hdGlvbiI+CgoqKkZpbGUgPiBTYXZlID4gKiogCgo8L2Rpdj4KCgojIyBQYWNrYWdlcyBpbiBSCgpTbyBmYXIgd2UgaGF2ZSB1c2VkIGZ1bmN0aW9ucyB0aGF0IGFyZSBhdmFpbGFibGUgd2l0aCB0aGUgKmJhc2UqIGRpc3RyaWJ1dGlvbiBvZiBSOyB0aGUgZnVuY3Rpb25zIHlvdSBnZXQgd2l0aCBhIGNsZWFuIGluc3RhbGwgb2YgUi4gVGhlIG9wZW4tc291cmNlIG5hdHVyZSBvZiBSIGVuY291cmFnZXMgb3RoZXJzIHRvIHdyaXRlIHRoZWlyIG93biBmdW5jdGlvbnMgZm9yIHRoZWlyIHBhcnRpY3VsYXIgZGF0YS10eXBlIG9yIGFuYWx5c2VzLgoKUGFja2FnZXMgYXJlIGRpc3RyaWJ1dGVkIHRocm91Z2ggKnJlcG9zaXRvcmllcyouIFRoZSBtb3N0LWNvbW1vbiBvbmVzIGFyZSBDUkFOIGFuZCBCaW9jb25kdWN0b3IuIENSQU4gYWxvbmUgaGFzIG1hbnkgdGhvdXNhbmRzIG9mIHBhY2thZ2VzLgoKPGRpdiBjbGFzcz0iaW5mb3JtYXRpb24iPgotIFRoZSBbbWV0YSBjcmFuXShodHRwczovL3d3dy5yLXBrZy5vcmcvKSB3ZWJzaXRlIGNhbiBiZSB1c2VkIHRvIGJyb3dzZSBwYWNrYWdlcyBhdmFpbGFibGUgaW4gQ1JBTgotIEJpb2NvbmR1Y3RvciBwYWNrYWdlcyBjYW4gYmUgYnJvd3NlZCBbaGVyZV0oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9CaW9jVmlld3MuaHRtbCNfX19Tb2Z0d2FyZSkKPC9kaXY+CgpDUkFOIGFuZCBCaW9jb25kdWN0b3IgaGF2ZSBzb21lIGxldmVsIG9mIGN1cmF0aW9uIHNvIHNob3VsZCBiZSB0aGUgZmlyc3QgcGxhY2UgdG8gbG9vay4gUmVzZWFyY2hlcnMgc29tZXRpbWVzIG1ha2UgdGhlaXIgcGFja2FnZXMgYXZhaWxhYmxlIG9uIFtnaXRodWJdKHd3dy5naXRodWIuY29tKS4gSG93ZXZlciwgdGhlcmUgaXMgbm8gc3RyYWlnaHRmb3J3YXJkIHdheSBvZiBzZWFyY2hpbmcgZ2l0aHViIGZvciBhIHBhcnRpY3VsYXIgcGFja2FnZSBhbmQgbm8gZ3VhcmVudGVlIG9mIHF1YWxpdHkuCgpUaGUgKipQYWNrYWdlcyoqIHRhYiBpbiB0aGUgYm90dG9tLXJpZ2h0IHBhbmVsIG9mIFJTdHVkaW8gbGlzdHMgYWxsIHBhY2thZ2VzIHRoYXQgeW91IGN1cnJlbnRseSBoYXZlIGluc3RhbGxlZC4gQ2xpY2tpbmcgb24gYSBwYWNrYWdlIG5hbWUgd2lsbCBzaG93IGEgbGlzdCBvZiBmdW5jdGlvbnMgdGhhdCBhdmFpbGFibGUgb25jZSB0aGF0IHBhY2thZ2UgaGFzIGJlZW4gbG9hZGVkLiAKClRoZXJlIGFyZSBmdW5jdGlvbnMgZm9yIGluc3RhbGxpbmcgcGFja2FnZXMgd2l0aGluIFIuIElmIHlvdXIgcGFja2FnZSBpcyBwYXJ0IG9mIHRoZSBtYWluICoqQ1JBTioqIHJlcG9zaXRvcnksIHlvdSBjYW4gdXNlIGBpbnN0YWxsLnBhY2thZ2VzYC4KCldlIHdpbGwgYmUgdXNpbmcgYSBzZXQgb2YgYHRpZHl2ZXJzZWAgUiBwYWNrYWdlcyBpbiB0aGlzIHByYWN0aWNhbC4gVG8gaW5zdGFsbCB0aGVtLCB3ZSB3b3VsZCBkby4KCmBgYHtyIGV2YWw9RkFMU0V9CiMjIFlvdSBzaG91bGQgYWxyZWFkeSBoYXZlIGluc3RhbGxlZCB0aGVzZSBhcyBwYXJ0IG9mIHRoZSBjb3Vyc2Ugc2V0dXAKCmluc3RhbGwucGFja2FnZXMoInJlYWRyIikKaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCmluc3RhbGwucGFja2FnZXMoImRwbHlyIikKIyB0byBpbnN0YWxsIHRoZSBlbnRpcmUgc2V0IG9mIHRpZHl2ZXJzZSBwYWNrYWdlcywgd2UgY2FuIGRvIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpLiBCdXQgdGhpcyB3aWxsIHRha2Ugc29tZSB0aW1lCmBgYAoKCgpBIHBhY2thZ2UgbWF5IGhhdmUgc2V2ZXJhbCAqZGVwZW5kZW5jaWVzKjsgb3RoZXIgUiBwYWNrYWdlcyBmcm9tIHdoaWNoIGl0IHVzZXMgZnVuY3Rpb25zIG9yIGRhdGEgdHlwZXMgKHJlLXVzaW5nIGNvZGUgZnJvbSBvdGhlciBwYWNrYWdlcyBpcyBzdHJvbmdseS1lbmNvdXJhZ2VkKS4gSWYgdGhpcyBpcyB0aGUgY2FzZSwgdGhlIG90aGVyIFIgcGFja2FnZXMgd2lsbCBiZSBsb2NhdGVkIGFuZCBpbnN0YWxsZWQgdG9vLgoKKipTbyBsb25nIGFzIHlvdSBzdGljayB3aXRoIHRoZSBzYW1lIHZlcnNpb24gb2YgUiwgeW91IHdvbid0IG5lZWQgdG8gcmVwZWF0IHRoaXMgaW5zdGFsbCBwcm9jZXNzLioqCgoKT25jZSBhIHBhY2thZ2UgaXMgaW5zdGFsbGVkLCB0aGUgYGxpYnJhcnlgIGZ1bmN0aW9uIGlzIHVzZWQgdG8gbG9hZCBhIHBhY2thZ2UgYW5kIG1ha2UgaXQncyBmdW5jdGlvbnMgLyBkYXRhIGF2YWlsYWJsZSBpbiB5b3VyIGN1cnJlbnQgUiBzZXNzaW9uLiAqWW91IG5lZWQgdG8gZG8gdGhpcyBldmVyeSB0aW1lIHlvdSBsb2FkIGEgbmV3IFJTdHVkaW8gc2Vzc2lvbiouIExldCdzIGdvIGFoZWFkIGFuZCBsb2FkIHRoZSBgcmVhZHJgIHNvIHdlIGNhbiBpbXBvcnQgc29tZSBkYXRhLgoKCmBgYHtyIG1lc3NhZ2U9RkFMU0V9CiMjIHJlYWRyIGlzIGEgcGFja2FnZXMgdG8gaW1wb3J0IHNwcmVhZHNoZWV0cyBpbnRvIFIKbGlicmFyeShyZWFkcikKYGBgCgoKCiMgRGVhbGluZyB3aXRoIGRhdGEKClRoZSBbKioqdGlkeXZlcnNlKioqXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLykgaXMgYW4gZWNvLXN5c3RlbSBvZiBwYWNrYWdlcyB0aGF0IHByb3ZpZGVzIGEgY29uc2lzdGVudCwgaW50dWl0aXZlIHN5c3RlbSBmb3IgZGF0YSBtYW5pcHVsYXRpb24gYW5kIHZpc3VhbGlzYXRpb24gaW4gUi4KCgohW10oaHR0cHM6Ly9hYmVyZGVlbnN0dWR5Z3JvdXAuZ2l0aHViLmlvL3N0dWR5R3JvdXAvbGVzc29ucy9TRy1UMi1Kb2ludFdvcmtzaG9wL3RpZHl2ZXJzZS5wbmcpCl9JbWFnZSBDcmVkaXQ6XyBbKioqQWJlcmRlZW4gU3R1ZHkgR3JvdXAqKipdKGh0dHBzOi8vYWJlcmRlZW5zdHVkeWdyb3VwLmdpdGh1Yi5pby9zdHVkeUdyb3VwL2xlc3NvbnMvU0ctVDItSm9pbnRXb3Jrc2hvcC9Qb3B1bGF0aW9uQ2hhbmdlU3BlY2llc09jY3VycmVuY2UvKQoKV2UgYXJlIGdvaW5nIHRvIGV4cGxvcmUgc29tZSBvZiB0aGUgYmFzaWMgZmVhdHVyZXMgb2YgdGhlIGB0aWR5dmVyc2VgIHVzaW5nIGRhdGEgZnJvbSB0aGUgW2dhcG1pbmRlcl0oaHR0cHM6Ly93d3cuZ2FwbWluZGVyLm9yZy9kYXRhLykgcHJvamVjdCwgd2hpY2ggaGF2ZSBiZWVuIGJ1bmRsZWQgaW50byBhbiBbUiBwYWNrYWdlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9nYXBtaW5kZXIpLiBUaGVzZSBkYXRhIGdpdmUgdmFyaW91cyBpbmRpY2F0b3IgdmFyaWFibGVzIGZvciBkaWZmZXJlbnQgY291bnRyaWVzIGFyb3VuZCB0aGUgd29ybGQgKGxpZmUgZXhwZWN0YW5jeSwgcG9wdWxhdGlvbiBhbmQgR3Jvc3MgRG9tZXN0aWMgUHJvZHVjdCkuIFdlIGhhdmUgc2F2ZWQgdGhlc2UgZGF0YSBhcyBhIGAuY3N2YCBmaWxlIGNhbGxlZCBgZ2FwbWluZGVyLmNzdmAgaW4gYSBzdWItZGlyZWN0b3J5IGNhbGxlZCBgcmF3X2RhdGEvYCB0byBkZW1vbnN0cmF0ZSBob3cgdG8gaW1wb3J0IGRhdGEgaW50byBSLgoKCgoKCiMjIFJlYWRpbmcgaW4gZGF0YQoKQW55IGAuY3N2YCBmaWxlIGNhbiBiZSBpbXBvcnRlZCBpbnRvIFIgYnkgc3VwcGx5aW5nIHRoZSBwYXRoIHRvIHRoZSBmaWxlIHRvIGByZWFkcmAgZnVuY3Rpb24gYHJlYWRfY3N2YCBhbmQgYXNzaWduaW5nIGl0IHRvIGEgbmV3IG9iamVjdCB0byBzdG9yZSB0aGUgcmVzdWx0LiBBIHVzZWZ1bCBzYW5pdHkgY2hlY2sgaXMgdGhlIGBmaWxlLmV4aXN0c2AgZnVuY3Rpb24gd2hpY2ggd2lsbCBwcmludCBgVFJVRWAgaXMgdGhlIGZpbGUgY2FuIGJlIGZvdW5kIGluIHRoZSB3b3JraW5nIGRpcmVjdG9yeS4KCmBgYHtyfQpnYXBtaW5kZXJfcGF0aCA8LSAicmF3X2RhdGEvZ2FwbWluZGVyLmNzdiIKZmlsZS5leGlzdHMoZ2FwbWluZGVyX3BhdGgpCmBgYAoKCkFzc3VtaW5nIHRoZSBmaWxlIGNhbiBiZSBmb3VuZCwgd2UgY2FuIHVzZSBgcmVhZF9jc3ZgIHRvIGltcG9ydC4gT3RoZXIgZnVuY3Rpb25zIGNhbiBiZSB1c2VkIHRvIHJlYWQgdGFiLWRlbGltaXRlZCBmaWxlcyAoYHJlYWRfZGVsaW1gKSBvciBhIGdlbmVyaWMgYHJlYWQudGFibGVgIGZ1bmN0aW9uLiBBIGRhdGEgZnJhbWUgb2JqZWN0IGlzIGNyZWF0ZWQuCgpgYGB7cn0KbGlicmFyeShyZWFkcikKZ2FwbWluZGVyX3BhdGggPC0gInJhd19kYXRhL2dhcG1pbmRlci5jc3YiCmdhcG1pbmRlciA8LSByZWFkX2NzdihnYXBtaW5kZXJfcGF0aCkKYGBgCgo8ZGl2IGNsYXNzPSJ3YXJuaW5nIj4KCioqV2h5IHdvdWxkIHNwZWNpZnlpbmcgYGdhcG1pbmRlcl9wYXRoYCBhcyAqKgpgVXNlcnMvQW5uYS9Eb2N1bWVudHMvd29ya2Zsb3dzL3dvcmtzaG9wcy9yLWNyYXNoLWNvdXJzZS9yYXdfZGF0YS9nYXBtaW5kZXIuY3N2YCAqKmJlIGEgYmFkIGlkZWE/KiogV291bGQgeW91IGJlIGFibGUgdG8gcmUtcnVuIHRoZSBhbmFseXNpcyBvbiBhbm90aGVyIG1hY2hpbmU/Cgo8L2Rpdj4KCjxkaXYgY2xhc3M9ImluZm9ybWF0aW9uIj4KWW91IGNhbiBhbHNvIHJlYWQgZXhjZWwgKGAueGxzYCBvciBgLnhsc3hgKSBmaWxlcyBpbnRvIFIsIGJ1dCB5b3Ugd2lsbCBoYXZlIHRvIHVzZSB0aGUgYHJlYWR4bGAgcGFja2FnZSBpbnN0ZWFkLgoKYGBge3IgZXZhbD1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygicmVhZHhsIikKbGlicmFyeShyZWFkeGwpCiMjIFJlcGxhY2UgUEFUSF9UT19NWV9YTFMgd2l0aCB0aGUgbmFtZSBvZiB0aGUgZmlsZSB5b3Ugd2FudCB0byByZWFkCmRhdGEgPC0gcmVhZF94bHMoUEFUSF9UT19NWV9YTFMpCiMjIFJlcGxhY2UgUEFUSF9UT19NWV9YTFNYIHdpdGggdGhlIG5hbWUgb2YgdGhlIGZpbGUgeW91IHdhbnQgdG8gcmVhZApkYXRhIDwtIHJlYWRfeGxzeChQQVRIX1RPX01ZX1hMU1gpCmBgYAoKPC9kaXY+CgoKPGRpdiBjbGFzcz0iaW5mb3JtYXRpb24iPgpJZiB5b3UgZ2V0ICpyZWFsbHkqIHN0dWNrIGltcG9ydGluZyBkYXRhLCB0aGVyZSBpcyBhIEZpbGUgLT4gSW1wb3J0IERhdGFzZXQgb3B0aW9uIHRoYXQgc2hvdWxkIGd1aWRlIHlvdSB0aHJvdWdoIHRoZSBwcm9jZXNzLiBJdCB3aWxsIGFsc28gc2hvdyB0aGUgY29ycmVzcG9uZGluZyBSIGNvZGUgdGhhdCB5b3UgY2FuIHVzZSBpbiBmdXR1cmUuCjwvZGl2PgoKVGhlIGRhdGEgZnJhbWUgb2JqZWN0IGluIFIgYWxsb3dzIHVzIHRvIHdvcmsgd2l0aCAqKiJ0YWJ1bGFyIiBkYXRhKiosIGxpa2Ugd2UgbWlnaHQgYmUgdXNlZCB0byBkZWFsaW5nIHdpdGggaW4gRXhjZWwsIHdoZXJlIG91ciBkYXRhIGNhbiBiZSB0aG91Z2h0IG9mIGhhdmluZyAqKnJvd3MgYW5kIGNvbHVtbnMqKi4gVGhlIHZhbHVlcyBpbiAqKmVhY2ggY29sdW1uKiogaGF2ZSB0byBhbGwgYmUgb2YgdGhlICoqc2FtZSB0eXBlKiogKGkuZS4gYWxsIG51bWJlcnMgb3IgYWxsIHRleHQpLgoKSW4gUnN0dWRpbywgeW91IGNhbiAqKnZpZXcgdGhlIGNvbnRlbnRzIG9mIHRoZSBkYXRhIGZyYW1lKiogd2UgaGF2ZSBqdXN0IGNyZWF0ZWQgdXNpbmcgZnVuY3Rpb24gYFZpZXcoKWAuIFRoaXMgaXMgdXNlZnVsIGZvciBpbnRlcmFjdGl2ZSBleHBsb3JhdGlvbiBvZiB0aGUgZGF0YSwgYnV0IG5vdCBzbyB1c2VmdWwgZm9yIGF1dG9tYXRpb24sIHNjcmlwdGluZyBhbmQgYW5hbHlzZXMuCgpgYGB7ciBldmFsPUZBTFNFfQojIyBNYWtlIHN1cmUgdGhhdCB5b3UgdXNlIGEgY2FwaXRhbCBsZXR0ZXIgVgoKVmlldyhnYXBtaW5kZXIpCmBgYAoKYGBge3IsIGVjaG8gPSBGQUxTRX0KZ2FwbWluZGVyCmBgYAoKCgpXZSBzaG91bGQgKiphbHdheXMgY2hlY2sgdGhlIGRhdGEgZnJhbWUgdGhhdCB3ZSBoYXZlIGNyZWF0ZWQqKi4gU29tZXRpbWVzIFIgd2lsbCBoYXBwaWx5IHJlYWQgZGF0YSB1c2luZyBhbiBpbmFwcHJvcHJpYXRlIGZ1bmN0aW9uIGFuZCBjcmVhdGUgYW4gb2JqZWN0IHdpdGhvdXQgcmFpc2luZyBhbiBlcnJvci4gSG93ZXZlciwgdGhlIGRhdGEgbWlnaHQgYmUgdW51c2FibGUuIENvbnNpZGVyOi0KCmBgYHtyfQp0ZXN0IDwtIHJlYWRfdGFibGUoZ2FwbWluZGVyX3BhdGgpCmBgYAoKYGBge3IsIGV2YWw9Rn0KVmlldyh0ZXN0KQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CnRlc3QKYGBgCgpRdWljayBzYW5pdHkgY2hlY2tzIGNhbiBhbHNvIGJlIHBlcmZvcm1lZCBieSBpbnNwZWN0aW5nIGRldGFpbHMgaW4gdGhlIGVudmlyb25tZW50IHRhYi4gQSB1c2VmdWwgY2hlY2sgaW4gUlN0dWRpbyBpcyB0byB1c2UgdGhlIGBoZWFkYCBmdW5jdGlvbiwgd2hpY2ggcHJpbnRzIHRoZSBmaXJzdCA2IHJvd3Mgb2YgdGhlIGRhdGEgZnJhbWUgdG8gdGhlIHNjcmVlbi4KCmBgYHtyfQpoZWFkKGdhcG1pbmRlcikKYGBgCgo8ZGl2IGNsYXNzPSJ3YXJuaW5nIj4KV2UgaGF2ZSB1c2VkIGEgbmljZSwgY2xlYW4sIGRhdGFzZXQgYXMgb3VyIGV4YW1wbGUgZm9yIHRoZSB3b3Jrc2hvcC4gT3RoZXIgZGF0YXNldHMgb3V0IGluIHRoZSB3aWxkIG1pZ2h0IG5vdCBiZSBzbyBhbWVhbmFibGUgZm9yIGFuYWx5c2lzIGluIFIuIElmIHlvdXIgZGF0YSBsb29rIGxpa2UgdGhpcywgeW91IG1pZ2h0IGhhdmUgcHJvYmxlbXM6LQo8aW1nIHNyYz0iaHR0cHM6Ly9kYXRhY2FycGVudHJ5Lm9yZy8yMDE1LTA1LTI5LWdyZWF0LXBsYWlucy9zcHJlYWRzaGVldC1lY29sb2d5L2ZpZy8yX2RhdGFzaGVldF9leGFtcGxlLmpwZyIvPgoKV2UgcmVjb21tZW5kIHRoZSBEYXRhIENhcnBlbnRyeSBtYXRlcmlhbHMgb24gc3ByZWFkc2hlZXQgb3JnYW5pc2F0aW9uIGZvciBhbiBvdmVydmlldyBvZiBjb21tb24gcGl0ZmFsbHMgLSBhbmQgaG93IHRvIGFkZHJlc3MgdGhlbQoKLSBodHRwczovL2RhdGFjYXJwZW50cnkub3JnL3NwcmVhZHNoZWV0LWVjb2xvZ3ktbGVzc29uLwoKPC9kaXY+CgoKIyMgQWNjZXNzaW5nIGRhdGEgaW4gY29sdW1ucwoKSW4gdGhlIG5leHQgc2VjdGlvbiB3ZSB3aWxsIGV4cGxvcmUgaW4gbW9yZSBkZXRhaWwgaG93IHRvIGNvbnRyb2wgdGhlIGNvbHVtbnMgYW5kIHJvd3MgZnJvbSBhIGRhdGEgZnJhbWUgdGhhdCBhcmUgZGlzcGxheWVkIGluIFJTdHVkaW8uIEZvciBub3csIGFjY2Vzc2luZyBhbGwgdGhlIG9ic2VydmF0aW9ucyBmcm9tIGEgcGFydGljdWxhciBjb2x1bW4gY2FuIGJlIGFjaGlldmVkIGJ5IHR5cGluZyB0aGUgYCRgIHN5bWJvbCBhZnRlciB0aGUgbmFtZSBvZiB0aGUgZGF0YSBmcmFtZSBmb2xsb3dlZCBieSB0aGUgbmFtZSBvZiBhIGNvbHVtbiB5b3UgYXJlIGludGVyZXN0ZWQgaW4uCgpSU3R1ZGlvIGlzIGFibGUgdG8gKiJ0YWItY29tcGxldGUiKiB0aGUgY29sdW1uIG5hbWUsIHNvIHR5cGluZyB0aGUgZm9sbG93aW5nIGFuZCBwcmVzc2luZyB0aGUgKipUQUIqKiBrZXkgd2lsbCBicmluZy11cCBhIGxpc3Qgb2YgcG9zc2libGUgY29sdW1ucy4gVGhlIGNvbnRlbnRzIG9mIHRoZSBjb2x1bW4gdGhhdCB5b3Ugc2VsZWN0IGFyZSB0aGVuIHByaW50ZWQgdG8gdGhlIHNjcmVlbi4KCmBgYHtyIGV2YWw9RkFMU0V9CmdhcG1pbmRlciRjCmBgYAoKUmF0aGVyIHRoYW4gbWVyZWx5IHByaW50aW5nIHRvIHRoZSBzY3JlZW4gd2UgY2FuIGFsc28gY3JlYXRlIGEgdmFyaWFibGUKCmBgYHtyfQp5ZWFycyA8LSBnYXBtaW5kZXIkeWVhcgpgYGAKCldlIGNhbiB0aGVuIHVzZSBzb21lIG9mIHRoZSBmdW5jdGlvbnMgd2UgaGF2ZSBzZWVuIGJlZm9yZQoKYGBge3J9Cm1pbih5ZWFycykKbWF4KHllYXJzKQptZWRpYW4oeWVhcnMpCmBgYAoKQWx0aG91Z2ggd2UgZG9uJ3QgaGF2ZSB0byBzYXZlIHRoZSB2YWx1ZXMgaW4gdGhlIGNvbHVtbiBhcyBhIHZhcmlhYmxlIGZpcnN0CgpgYGB7cn0KbWluKGdhcG1pbmRlciR5ZWFyKQpgYGAKCgojIyBDcmVhdGluZyBhIG5ldyBSIG5vdGVib29rCgpZb3Ugd2lsbCBwcm9iYWJseSB3YW50IHRvIGNyZWF0ZSBhIG5ldyAqUiBub3RlYm9vayogZmlsZSB0byBwZXJmb3JtIHlvdXIgYW5hbHlzaXMuIFRoaXMgY2FuIGJlIGRvbmUgYnkgZm9sbG93aW5nIHRoZSBtZW51czotCgo8ZGl2IGNsYXNzPSJpbmZvcm1hdGlvbiI+CgoqKkZpbGUgLT4gTmV3IEZpbGUgLT4gUiBub3RlYm9vayoqIAoKPC9kaXY+CgpBIG5ldyBwYW5lIHNob3VsZCBvcGVuIHRoYXQgaW5jbHVkZXMgc29tZSBleGFtcGxlIGNvZGUuIFlvdSBjYW4gZGVsZXRlIGV2ZXJ5dGhpbmcgKiphcGFydCBmcm9tIGxpbmVzIDEgdG8gNCoqCgohW10oaW1hZ2VzL2JsYW5rX25vdGVib29rLlBORykKCllvdSBjYW4gbm93IGluc2VydCBSIGNvZGUgY2h1bmtzIHVzaW5nIHRoZSBpbnNlcnQgbWVudS4KCkJlZm9yZSBnZW5lcmF0aW5nIGEgcmVwb3J0IHlvdSB3aWxsIG5lZWQgdG8gc2F2ZSB0aGUgZmlsZSB3aXRoIHRoZSBtZW51ICoqRmlsZSAtPiBTYXZlKiouIFlvdSB3aWxsIHRoZW4gYmUgYWJsZSB0byBjcmVhdGUgYSByZXBvcnQgdXNpbmcgdGhlIFByZXZpZXcgYnV0dG9uLiBOLkIuIHlvdSBtYXkgbmVlZCB0byBpbnN0YWxsIGV4dHJhIHNvZnR3YXJlIGJlZm9yZSBkb2luZyB0aGlzLgoKKioqKioqCioqKioqKgoqKioqKioKCiMjIyBFeGVyY2lzZSBiZWZvcmUgdGhlIG5leHQgc2Vzc2lvbgoKPGRpdiBjbGFzcz0iZXhlcmNpc2UiPgotIENyZWF0ZSBhIG5ldyBSIG5vdGVib29rIHVzaW5nIHRoZSBpbnN0cnVjdGlvbnMgYWJvdmUgYW5kIGNyZWF0ZSBhIGNvZGUgY2h1bmsgdG8gcmVhZCB0aGUgYGdhcG1pbmRlci5jc3ZgIGZpbGUuIEFuc3dlciB0aGUgZm9sbG93aW5nIHF1ZXN0aW9ucyBhbmQgZ2VuZXJhdGUgYSByZXBvcnQgCiAgKyBUaGUgZnVuY3Rpb24gYHRhaWxgIGlzIHNpbWlsYXIgdG8gYGhlYWRgIGV4Y2VwdCBpdCBwcmludHMgdGhlICpsYXN0KiBsaW5lcyBpbiBhIGZpbGUuIFVzZSB0aGlzIGZ1bmN0aW9uIHRvIHByaW50IHRoZSBsYXN0ICoxMCogbGluZXMgaW4gdGhlIGRhdGEgZnJhbWUgKHlvdSB3aWxsIGhhdmUgdG8gY29uc3VsdCB0aGUgaGVscCBvbiBgdGFpbGAgdG8gc2VlIGhvdyB0byBjaGFuZ2UgdGhlIGRlZmF1bHQgYXJndW1lbnRzLikKICArIFdoYXQgaXMgdGhlIGxhcmdlc3Qgb2JzZXJ2ZWQgcG9wdWxhdGlvbj8KICArIFdoYXQgaXMgdGhlIGxvd2VzdCBsaWZlIGV4cGVjdGFuY3kKPC9kaXY+CgoKKioqKioqCioqKioqKgoqKioqKioKCgoKPGRpdiBjbGFzcz0iZXhlcmNpc2UiPgoKKE9wdGlvbmFsKTogRmFtaWxpYXJpc2UgeW91cnNlbGYgd2l0aCB0aGUgY29udGVudHMgb2YgdGhlIGRhdGEgZnJhbWUuIFdoYXQgbnVtZXJpY2FsIHN1bW1hcmllcyBjYW4geW91IHByb2R1Y2UgZnJvbSB0aGUgZGF0YXNldCAoZS5nLiBhdmVyYWdlIGxpZmUgZXhwZWN0YW5jeSBwZXIteWVhciwgY291bnRyaWVzIHRoYXQgYXJlIG1vc3Qgd2VhbHRoeSBldGMpIGFuZCB3aGF0IHBsb3RzIG1pZ2h0IGJlIG9mIGludGVyZXN0PyBEaXNjdXNzIHdpdGggeW91ciBuZWlnaGJvdXJzCgo8L2Rpdj4K