This is an R Markdown
Notebook. When you execute code within the notebook, the results appear
beneath the code.
Try executing this chunk by clicking the Run button within
the chunk or by placing your cursor inside it and pressing
Cmd+Shift+Enter.
w="tigers"
"I just ran my first line of code"
[1] "I just ran my first line of code"
z="lions"
y="kittens"
x="cats"
Add a new chunk by clicking the Insert Chunk button on the
toolbar or by pressing Cmd+Option+I.
When you save the notebook, an HTML file containing the code and
output will be saved alongside it (click the Preview button or
press Cmd+Shift+K to preview the HTML file).
1. EXPLORING THE FUNCTIONALITY OF R
At its most basic, the command line is a bloated calculator. The
basic operations are
+ - * /
log sqrt ^
for add, subtract, multiply, divide, log, square root, or raise to
the exponent. Familiar calculator functions also work on the command
line. Lets start out by just using R as a calculator. Try adding,
subtracting, multiplying, powers, etc.
For example, to take the natural log of 2, enter log(2) in the chunk
below. Then try a couple operations of your own
To do anything complicated, you have to store the results from
calculations by assigning them to variables For example, to assign the
number “3” to a variable x, use
x<-4
R automatically creates the variable x and stores the result
(4) in it, but it doesn’t print anything until you call the value by
typing and submit the variable name “x”. This may seem strange,
but you’ll often be creating and manipulating huge sets of data that
would fill many screens, so the default is to skip printing the
results.
To ask R to print the value, send down (CTRL Enter)
x
[1] 4
The number in brackets [1] at the beginning of the ourput line above
is just R printing an index of element numbers; if you print a result
that displays on multiple lines, R will put an index at the beginning of
each line. You could also type print(x) to ask R to print the value of
the variable.
print(x)
[1] 4
By default, a variable created this way is a vector, and it is
numeric because we gave R a number rather than some other type of
data.
R can also assign character strings (enter using double quotes) to
named variables.
z <- "Wake up Neo" # single or double quotes needed
z
[1] "Wake up Neo"
In this above examples x is a numeric vector of length 1,
which acts just like a single number. z is a character vector of length
1. Note, however you can overwrite a variable you have named. For
example,
x <- "Wake up Neo" # single or double quotes needed
z<-4
x
[1] "Wake up Neo"
z
[1] 4
Now x is a character vector of length 1 and z is a numeric
vector of length 1.
2. NAMING VARIABLES
Variable names in R must begin with a letter, followed by letters or
numbers. You can break up long names with a period, as in
very.long.variable.number.3
or an underscore
very_long_variable_number_3
but you can’t use blank spaces in variable names (or at least it’s
not worth the trouble). Variable names in R are case sensitive, so a
variable named Abc and one named abc are different variables. In general
you should use variable names that are long enough to remember what they
represent but short enough to type easily
Avoid using c, l, q, t, C, D, F, I, and T for variable names, because
they are either built-in R functions or they are hard to tell apart.
R does calculations with variables as if they were numbers.
x<-5
y<-2
z1<-x*y ## no output
z2<-x/y ## no output
z3<-x^y ## no output
z1
[1] 10
z2
[1] 2.5
z3
[1] 25
Even though R did not display the values of x and y, it “remembers”
that it assigned values to them. You can also combine several operations
into one calculation
x<-3
y<-(x+2*sqrt(x))/(x+5*sqrt(x))
y
[1] 0.5543706
Parentheses specify the order of operations. To illustrate try the
command C<-A+2sqrt(A)/A+5sqrt(A), which should not be the
same as the one above; rather, it is equivalent to C<-A +
2(sqrt(A)/A) + 5sqrt(A).
The default order of operations is: (1) parentheses; (2)
exponentiation, or powers, (3) multiplication and division, (4) addition
and subtraction (pretty please
excuse my dear
Aunt Sally).
In complicated expressions you might start off by using parentheses
to specify explicitly what you want, such as b = 12 - (4/(2^3)) or at
least b = 12 - 4/(2^3); a few extra sets of parentheses never hurt
anything, although when you get confused it’s better to think through
the order of operations rather than flailing around adding parentheses
at random.
The help system
R has a help system, although it is generally better for providing
detail or reminding you how to do things than for basic ``how do I…?’’
questions.
You can get help on any R function by entering ? and the the function
name. For example:
?lm
?anova
?plot
library(help="lme4")
Error in find.package(pkgName, lib.loc, verbose = verbose) :
there is no package called ‘lme4’
The Help menu on the tool bar provides links to other documentation,
including the manuals and FAQs, and a Search facility (`Apropos’ on the
menu)which is useful if you sort of maybe remember part of the the name
of what it is you need help on. Typing “help.start()” opens a web
browser with help information. Typing example(command) (where command
become the function your are trying to figure out) will run any examples
that are included in the help page for command.
Typing demo(topic)runs demonstration code on topic specificed. To see
all available demos type “demo()” by itself to list all available
demos.
By default, R’s help system only provides information about functions
that are in the base system and packages that you have loaded (which we
will discuss libraries later on…dont worry about that for now). You can
also search using the command “help.search” which uses ``fuzzy
matching’’ — for example,
help.search("log")
finds 528 entries (on my particular system) including lots of
functions with plot'', which includes the letterslot’‘,
which are like ``log’’.
Typing in the command example will run the examples (if any)
given in the help for a particular function e.g. example(log). Another
search function is RSiteSearch(“topic”) which does a full-text search of
all the R documentation and the mailing list archives for information on
(you need an active internet connection).
Try out one or more of these aspects of the help system.
Working with Vectors
Vectors in R are used to represent variables. R can assign sets of
numbers or character strings to named variables using the c() command,
for the “c” stands for concatenate. (R treats a single number or
character as a vector, having just one element. If there are multiple
numbers or characters (or strings of characters) then it will treat them
as a multi-element vector).
For example contrast these three numeric vectors:
x<-12333654588
x1<-c(12333654588)
x2<- c(1,2,333,65,45,88)
x
[1] 12333654588
x1
[1] 12333654588
x2
[1] 1 2 333 65 45 88
And these three character vectors
z <- "Wake up Neo"
z1 <- c("W","a","k","e","u","p","N","e","o")
z2 <- c("Wake up Neo")
z3<-c("Wake", "up", "Neo")
z
[1] "Wake up Neo"
z1
[1] "W" "a" "k" "e" "u" "p" "N" "e" "o"
z2
[1] "Wake up Neo"
z3
[1] "Wake" "up" "Neo"
Working with vectors
In the code below we can create a vector x that has 20 elements (I
demonstrate 3 different ways to do this…). 1) we can use a colon to
generate a sequence of whole numbers. 2) Alternatively we can use the
seq command (for sequence) to specify the begining and end
values as well as the number of elements desired (seq willd divide the
range up into equal sized units). 3) Finally, you can use the
c command (for concatenate) and specify the values
manually.
#Method 1
x<-1:20
length(x)
[1] 20
print(x)
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#Method 2
x<-seq(1,20,length=20)
length(x)
[1] 20
print(x)
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
x<-seq(21,40,length=20)
length(x)
[1] 20
print(x)
[1] 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
x<-seq(1,40,length=20)
length(x)
[1] 20
print(x)
[1] 1.000000 3.052632 5.105263 7.157895 9.210526 11.263158 13.315789 15.368421 17.421053
[10] 19.473684 21.526316 23.578947 25.631579 27.684211 29.736842 31.789474 33.842105 35.894737
[19] 37.947368 40.000000
#Method 3
x<-c(1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16, 17,18,19,20)
length(x)
[1] 20
print(x)
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Subset a vector Given a vector x you can use integers in
square brackets to indicate subsets of the vector. For example to see
only the fifth value or element of the vector
x<-seq(5,100,length=20)
x[5] # fifth element
[1] 25
You can also use vectors of indices, to extract multiple elements
from a vector
x[1:3] # 1:3 is a shortcut for c(1,2,3)
[1] 5 10 15
x[c(2,4,9)]
[1] 10 20 45
Some functions of vectors yield integer results and so can be used as
indices too. For example, enter the function
length(x)
[1] 20
Since the result is an integer, it is ok to use as follows,
x[length(x)]
[1] 100
The beauty of this kind of construction when you are coding is that
it will always give the last element of a vector x no matter how many
elements x contains. This kind of thinking to make code very general
(i.e. apply to a wide array of conditions) can be useful when doing some
higher level data science or modeling applciations.
Logical operators Logical operations can also be
used to generate indicators. First, enter the following command and
compare with the contents of x,
x < 25
[1] TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[16] FALSE FALSE FALSE FALSE FALSE
Now you can use those logical outcomes about the validity of the
logical statement to subset the vector to retain only a subset of values
that meet your criteria. For instance..
x[x < 25]
[1] 5 10 15 20
#or#
x[x > 25]
[1] 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100
#or#
x[x != 25] #note here I am using != to mean "not equal" to 10
[1] 5 10 15 20 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100
x[x == 25] #note here I am using == to mean "is exactly equal" to 10
[1] 25
The which command will identify the locations of the
elements corresponding to TRUE. For example, try the following and
compare with your vector x.
which(x < 25)
[1] 1 2 3 4 5
which(x != 25) #note which number is missing from the list below
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Indicators can be used to change individual elements of the vector x.
For example, to change the fifth element of x to 0,
x[5] <- 0
x
[1] 5 10 15 20 0 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100
Calculations on Vectors R can be used as a
calculator for arrays of numbers too. Create a second numerical vector y
of the same length as x you created above. Now try out a few ordinary
mathematical operations on the whole vectors of numbers. (Hint: this is
where you can use the idea of coding for generality from above…you dont
have to know how long x is if you use the length command
-e.g. y<-seq(2,2000,length=length(x)) will generate a vector y that
has the same number of elements as x).
y<-seq(2,40,length=length(x))
z <- x * y
z
[1] 10 40 90 160 0 360 490 640 810 1000 1210 1440 1690 1960 2250 2560 2890 3240
[19] 3610 4000
z1 <- y - 2 * x
z1
[1] -8 -16 -24 -32 10 -48 -56 -64 -72 -80 -88 -96 -104 -112 -120 -128 -136 -144
[19] -152 -160
#note that the 5th element seems out of place in these if you did not change the conversion of that value to zero above in your vector x.
Examine the results to see how R behaves. It executes the operation
on the first elements of x and y, then on the corresponding second
elements, and so on. Each result is stored in the corresponding element
of z. Logical operations are the same,
z <- x >= y # >= is greater than or equal to
z
[1] TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[16] TRUE TRUE TRUE TRUE TRUE
z <- x[abs(x) <= abs(y)] # absolute values
z
[1] 0
What does R do if the two vectors are not the same length? The answer
is that the elements in the shorter vector are “recycled”, starting from
the beginning. This is basically what R does when you multiply a vector
by a single number. The single number is recycled, and so is applied to
each of the elements of x in turn.
x
[1] 5 10 15 20 0 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100
z <- 2 * x
z
[1] 10 20 30 40 0 60 70 80 90 100 110 120 130 140 150 160 170 180 190 200
y<-c(2,1)
z<-y*x
z
[1] 10 10 30 20 0 30 70 40 90 50 110 60 130 70 150 80 170 90 190 100
Challenge Questions
- Assign a set of 100 numbers to a variable x. Make sure it includes
some positive and some negative numbers. Display the contents of the
vector afterward. Is it really a vector? Enter is.vector(x) to
confirm.
- Print the 3rd and 6th elements of x with a single command.
- Print (i.e. display) all elements of x that are non-negative.
4.Change the last value of your x vector to a different number.
Change the 2nd, 6th, and 10th values of x to 1, 2, 3 with a single
command.
- For each of the following examples determine why the code does not
work and correct it. Use R’s built in help functions if you have trouble
on the second set.
my_variable <- 10
my_varıable
x<-c(2,34,61,21,NA ,32)
y<-c(5,56,789,23,3,90)
z <- mean(x*y)
z
Reading data from an external file
Working with Data Sets Data frames are the most common and
convenient data objects to work with in R. However, you may also run
across matrices and lists which are conceptually not too different from
a data frame and much of the logic you learn from working with data
frames can be translated among different data objects (More on
this in Workshop 3).
Tibbles are a type of data frame from the ‘tidyverse’ that can be
slightly easier to work with than the base R version. But in general I
have found little difference with regards to which type of data frame is
used (base R data.frame or a Tibble).
**Reading data using base R The following chunk of code provides 3
different ways in base R to read in a data file for example “mammal.csv”
into a data frame we wail call my data. The stringsAsFactors = FALSE
argument tells R to keep each character variable as-is rather than
convert to factors, which are a little harder to work with.
# base R
mydata <- read.csv(file.choose(), stringsAsFactors = FALSE) # This should call up a window where you can navigate to the file
mydata <- read.csv("../data/mammal.csv", stringsAsFactors = FALSE) #add the file path in place of "directory_name" if you have a mac add a ~ to the front end "~../data/mammal.csv"
Warning: cannot open file '../data/mammal.csv': No such file or directoryError in file(file, "rt") : cannot open the connection
mydata <- read.csv("../data/mammal.csv", stringsAsFactors = FALSE)
Warning: cannot open file '../data/mammal.csv': No such file or directoryError in file(file, "rt") : cannot open the connection
mydata <- read.csv("../data/mammal.csv", stringsAsFactors = FALSE)
To read in data using the readr package from the tidyverse,
everything should be the same as above except you use the function
read_csv().
# using readr package
mydata <- read.csv("../data/mammal.csv", stringsAsFactors = FALSE)
There also a a few optional arguments that can help save you time and
frustration. For instance, spaces are sometimes introduced accidentally
during data entry and R will treat “word” and ” word” as being different
which can lead to analytical errors (e.g. you may have too many levels
of a factor because “word” and ” word” are being read as two different
levels of a factor).
strip.white = TRUE removes spaces at the start and end
of character elements.
Another useful option is na.strings in Base R and
na in readr, both of which tell R to treat both
NA and empty strings in columns of character
data as missing values rather than as the value “NA”.
You can also replace “NA” in the code below with your own indicator
of missing data (e.g. “.” or “no_data”), For example,
read.csv("filename.csv", stringsAsFactors = FALSE,strip.white = TRUE, na.strings = c("no_data", "") )
# base R method:
mydata <- read.csv("filename.csv", stringsAsFactors = FALSE,
strip.white = TRUE, na.strings = c("NA", "") )
Warning: cannot open file 'filename.csv': No such file or directoryError in file(file, "rt") : cannot open the connection
Checking your Data
After you have imported your data there are a variety of tools that
you can use to visualize the data frame to make sure it is what you were
expecting. Here are a list of the most helpful…
To view small aspects of the data frame
mydata # if a tibble, print first few rows; otherwise prints all
print(mydata, n=5) # print the first 5 rows
head(mydata) # print the first few rows
tail(mydata) # print the last few rows
names(mydata) # see the variable names
rownames(mydata) # view row names (numbers, if you haven't assigned names)
LS0tDQp0aXRsZTogIkludHJvZHVjdGlvbiB0byBSIHByb2dyYW1taW5nIg0KYXV0aG9yOiAiTWljaGFlbCBXLiBNY0NveSINCmRhdGU6ICJMYXN0IHVwZGF0ZWQgb24gYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkNtZCtTaGlmdCtFbnRlciouIA0KDQpgYGB7cn0NCnc9InRpZ2VycyINCmBgYA0KDQoNCmBgYHtyfQ0KIkkganVzdCByYW4gbXkgZmlyc3QgbGluZSBvZiBjb2RlIg0KYGBgDQoNCg0KYGBge3J9DQp6PSJsaW9ucyINCmBgYA0KDQoNCmBgYHtyfQ0KeT0ia2l0dGVucyINCmBgYA0KDQoNCmBgYHtyfQ0KeD0iY2F0cyINCmBgYA0KDQpBZGQgYSBuZXcgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpJbnNlcnQgQ2h1bmsqIGJ1dHRvbiBvbiB0aGUgdG9vbGJhciBvciBieSBwcmVzc2luZyAqQ21kK09wdGlvbitJKi4NCg0KDQoNCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ21kK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuDQoNCioqMS4gRVhQTE9SSU5HIFRIRSBGVU5DVElPTkFMSVRZIE9GIFIqKg0KDQpBdCBpdHMgbW9zdCBiYXNpYywgdGhlIGNvbW1hbmQgbGluZSBpcyBhIGJsb2F0ZWQgY2FsY3VsYXRvci4gVGhlIGJhc2ljIG9wZXJhdGlvbnMgYXJlDQoNCmArYCAgYC1gICBgKmAgIGAvYCBgbG9nYCBgc3FydGAgYF5gDQoNCmZvciBhZGQsIHN1YnRyYWN0LCBtdWx0aXBseSwgZGl2aWRlLCBsb2csIHNxdWFyZSByb290LCBvciByYWlzZSB0byB0aGUgZXhwb25lbnQuIEZhbWlsaWFyIGNhbGN1bGF0b3IgZnVuY3Rpb25zIGFsc28gd29yayBvbiB0aGUgY29tbWFuZCBsaW5lLiBMZXRzIHN0YXJ0IG91dCBieSBqdXN0IHVzaW5nIFIgYXMgYSBjYWxjdWxhdG9yLiBUcnkgYWRkaW5nLCBzdWJ0cmFjdGluZywgbXVsdGlwbHlpbmcsIHBvd2VycywgZXRjLg0KDQpGb3IgZXhhbXBsZSwgdG8gdGFrZSB0aGUgbmF0dXJhbCBsb2cgb2YgMiwgZW50ZXIgbG9nKDIpIGluIHRoZSBjaHVuayBiZWxvdy4gVGhlbiB0cnkgYSBjb3VwbGUgb3BlcmF0aW9ucyBvZiB5b3VyIG93bg0KYGBge3IgY2FsY3VsYXRvcn0NCiANCg0KDQpgYGANCg0KVG8gZG8gYW55dGhpbmcgY29tcGxpY2F0ZWQsIHlvdSBoYXZlIHRvIHN0b3JlIHRoZSByZXN1bHRzIGZyb20gY2FsY3VsYXRpb25zIGJ5IGFzc2lnbmluZyB0aGVtIHRvIHZhcmlhYmxlcyANCkZvciBleGFtcGxlLCB0byBhc3NpZ24gdGhlIG51bWJlciDigJwz4oCdIHRvIGEgdmFyaWFibGUgeCwgdXNlDQpgYGB7cn0NCng8LTQNCmBgYA0KDQpSIGF1dG9tYXRpY2FsbHkgY3JlYXRlcyB0aGUgdmFyaWFibGUgKngqIGFuZCBzdG9yZXMgdGhlIHJlc3VsdCAoNCkgaW4gaXQsIGJ1dCBpdCBkb2Vzbid0IHByaW50IGFueXRoaW5nIHVudGlsIHlvdSBjYWxsIHRoZSB2YWx1ZSBieSB0eXBpbmcgYW5kIHN1Ym1pdCB0aGUgdmFyaWFibGUgbmFtZSAiKngqIi4gIFRoaXMgbWF5IHNlZW0gc3RyYW5nZSwgYnV0IHlvdSdsbCBvZnRlbiBiZSBjcmVhdGluZyBhbmQgbWFuaXB1bGF0aW5nIGh1Z2Ugc2V0cyBvZiBkYXRhIHRoYXQgd291bGQgZmlsbCBtYW55IHNjcmVlbnMsIHNvIHRoZSBkZWZhdWx0IGlzIHRvIHNraXAgcHJpbnRpbmcgdGhlIHJlc3VsdHMuDQoNClRvIGFzayBSIHRvIHByaW50IHRoZSB2YWx1ZSwgc2VuZCBkb3duIChDVFJMIEVudGVyKSANCmBgYHtyfQ0KeA0KYGBgDQoNClRoZSBudW1iZXIgaW4gYnJhY2tldHMgWzFdIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIG91cnB1dCBsaW5lIGFib3ZlIGlzIGp1c3QgUiBwcmludGluZyBhbiBpbmRleCBvZiBlbGVtZW50IG51bWJlcnM7IGlmIHlvdSBwcmludCBhIHJlc3VsdCB0aGF0IGRpc3BsYXlzIG9uIG11bHRpcGxlIGxpbmVzLCBSIHdpbGwgcHV0IGFuIGluZGV4IGF0IHRoZSBiZWdpbm5pbmcgb2YgZWFjaCBsaW5lLiAgWW91IGNvdWxkIGFsc28gdHlwZSBwcmludCh4KSB0byBhc2sgUiB0byBwcmludCB0aGUgdmFsdWUgb2YgdGhlIHZhcmlhYmxlLg0KDQpgYGB7cn0NCnByaW50KHgpDQoNCmBgYA0KDQpCeSBkZWZhdWx0LCBhIHZhcmlhYmxlIGNyZWF0ZWQgdGhpcyB3YXkgaXMgYSB2ZWN0b3IsIGFuZCBpdCBpcyBudW1lcmljIGJlY2F1c2Ugd2UgZ2F2ZSBSIGEgbnVtYmVyIHJhdGhlciB0aGFuIHNvbWUgb3RoZXIgdHlwZSBvZiBkYXRhLg0KDQpSIGNhbiBhbHNvIGFzc2lnbiBjaGFyYWN0ZXIgc3RyaW5ncyAoZW50ZXIgdXNpbmcgZG91YmxlIHF1b3RlcykgdG8gbmFtZWQgdmFyaWFibGVzLiANCg0KYGBge3J9DQp6IDwtICJXYWtlIHVwIE5lbyIgICMgc2luZ2xlIG9yIGRvdWJsZSBxdW90ZXMgbmVlZGVkDQp6DQoNCmBgYA0KDQpJbiB0aGlzIGFib3ZlIGV4YW1wbGVzICp4KiBpcyBhIG51bWVyaWMgdmVjdG9yIG9mIGxlbmd0aCAxLCB3aGljaCBhY3RzIGp1c3QgbGlrZSBhIHNpbmdsZSBudW1iZXIuICB6IGlzIGEgY2hhcmFjdGVyIHZlY3RvciBvZiBsZW5ndGggMS4gTm90ZSwgaG93ZXZlciB5b3UgY2FuIG92ZXJ3cml0ZSBhIHZhcmlhYmxlIHlvdSBoYXZlIG5hbWVkLiBGb3IgZXhhbXBsZSwgDQoNCmBgYHtyfQ0KeCA8LSAiV2FrZSB1cCBOZW8iICAjIHNpbmdsZSBvciBkb3VibGUgcXVvdGVzIG5lZWRlZA0KejwtNA0KeA0Keg0KYGBgDQoNCk5vdyAqeCogaXMgYSBjaGFyYWN0ZXIgdmVjdG9yIG9mIGxlbmd0aCAxIGFuZCB6IGlzIGEgbnVtZXJpYyB2ZWN0b3Igb2YgbGVuZ3RoIDEuIA0KDQogDQoqKjIuIE5BTUlORyBWQVJJQUJMRVMqKg0KDQoNClZhcmlhYmxlIG5hbWVzIGluIFIgbXVzdCBiZWdpbiB3aXRoIGEgbGV0dGVyLCBmb2xsb3dlZCBieSBsZXR0ZXJzIG9yIG51bWJlcnMuIFlvdSBjYW4gYnJlYWsgdXAgbG9uZyBuYW1lcyB3aXRoIGEgcGVyaW9kLCBhcyBpbg0KDQpgdmVyeS5sb25nLnZhcmlhYmxlLm51bWJlci4zYA0KDQpvciBhbiB1bmRlcnNjb3JlDQoNCmB2ZXJ5X2xvbmdfdmFyaWFibGVfbnVtYmVyXzNgDQoNCmJ1dCB5b3UgY2FuJ3QgdXNlIGJsYW5rIHNwYWNlcyBpbiB2YXJpYWJsZSBuYW1lcyAob3IgYXQgbGVhc3QgaXQncyBub3Qgd29ydGggdGhlIHRyb3VibGUpLiBWYXJpYWJsZSBuYW1lcyBpbiBSIGFyZSBjYXNlIHNlbnNpdGl2ZSwgc28gYSB2YXJpYWJsZSBuYW1lZCBBYmMgYW5kIG9uZSBuYW1lZCBhYmMgDQphcmUgZGlmZmVyZW50IHZhcmlhYmxlcy4gSW4gZ2VuZXJhbCB5b3Ugc2hvdWxkIHVzZSB2YXJpYWJsZSBuYW1lcyB0aGF0IGFyZSBsb25nIGVub3VnaCB0byByZW1lbWJlciB3aGF0IHRoZXkgcmVwcmVzZW50IGJ1dCBzaG9ydCBlbm91Z2ggdG8gdHlwZSBlYXNpbHkNCg0KQXZvaWQgdXNpbmcgYywgbCwgcSwgdCwgQywgRCwgRiwgSSwgYW5kIFQgZm9yIHZhcmlhYmxlIG5hbWVzLCBiZWNhdXNlIHRoZXkgYXJlIGVpdGhlciBidWlsdC1pbiBSIGZ1bmN0aW9ucyBvciB0aGV5IGFyZSBoYXJkIHRvIHRlbGwgYXBhcnQuDQoNClIgZG9lcyBjYWxjdWxhdGlvbnMgd2l0aCB2YXJpYWJsZXMgYXMgaWYgdGhleSB3ZXJlIG51bWJlcnMuDQpgYGB7cn0NCng8LTUNCnk8LTINCnoxPC14KnkgICMjIG5vIG91dHB1dA0KejI8LXgveSAgIyMgbm8gb3V0cHV0DQp6MzwteF55ICAjIyBubyBvdXRwdXQNCnoxDQp6Mg0KejMNCmBgYA0KDQpFdmVuIHRob3VnaCBSIGRpZCBub3QgZGlzcGxheSB0aGUgdmFsdWVzIG9mIHggYW5kIHksIGl0ICJyZW1lbWJlcnMiIHRoYXQgaXQgYXNzaWduZWQgdmFsdWVzIHRvIHRoZW0uIA0KWW91IGNhbiBhbHNvIGNvbWJpbmUgc2V2ZXJhbCBvcGVyYXRpb25zIGludG8gb25lIGNhbGN1bGF0aW9uDQpgYGB7cn0NCng8LTMNCnk8LSh4KzIqc3FydCh4KSkvKHgrNSpzcXJ0KHgpKQ0KeQ0KYGBgDQpQYXJlbnRoZXNlcyBzcGVjaWZ5IHRoZSBvcmRlciBvZiBvcGVyYXRpb25zLiBUbyBpbGx1c3RyYXRlIHRyeSB0aGUgY29tbWFuZCBDPC1BKzIqc3FydChBKS9BKzUqc3FydChBKSwgd2hpY2ggc2hvdWxkIG5vdCBiZSB0aGUgc2FtZSBhcyB0aGUgb25lIGFib3ZlOyByYXRoZXIsIGl0IGlzICBlcXVpdmFsZW50IHRvIEM8LUEgKyAyKihzcXJ0KEEpL0EpICsgNSpzcXJ0KEEpLg0KDQpUaGUgZGVmYXVsdCBvcmRlciBvZiBvcGVyYXRpb25zIGlzOiAoMSkgcGFyZW50aGVzZXM7ICgyKSBleHBvbmVudGlhdGlvbiwgb3IgcG93ZXJzLCAoMykgbXVsdGlwbGljYXRpb24gYW5kIGRpdmlzaW9uLCAoNCkgYWRkaXRpb24gYW5kIHN1YnRyYWN0aW9uICgqKnAqKnJldHR5ICoqcCoqbGVhc2UgKiplKip4Y3VzZSAqKm0qKnkgKipkKiplYXIgKipBKip1bnQgKipTKiphbGx5KS4NCg0KSW4gY29tcGxpY2F0ZWQgZXhwcmVzc2lvbnMgeW91IG1pZ2h0IHN0YXJ0IG9mZiBieSB1c2luZyBwYXJlbnRoZXNlcyB0byBzcGVjaWZ5IGV4cGxpY2l0bHkgd2hhdCB5b3Ugd2FudCwgc3VjaCBhcyBiID0gMTIgLSAoNC8oMl4zKSkgb3IgYXQgbGVhc3QgYiA9IDEyIC0gNC8oMl4zKTsgYSBmZXcgZXh0cmEgc2V0cyBvZiBwYXJlbnRoZXNlcyBuZXZlciBodXJ0IGFueXRoaW5nLCBhbHRob3VnaCB3aGVuIHlvdSBnZXQgY29uZnVzZWQgaXQncyBiZXR0ZXIgdG8gdGhpbmsgdGhyb3VnaCB0aGUgb3JkZXIgb2Ygb3BlcmF0aW9ucyByYXRoZXIgdGhhbiBmbGFpbGluZyBhcm91bmQgYWRkaW5nIHBhcmVudGhlc2VzIGF0IHJhbmRvbS4NCg0KDQoqKlRoZSBoZWxwIHN5c3RlbSoqDQoNClIgaGFzIGEgaGVscCBzeXN0ZW0sIGFsdGhvdWdoIGl0IGlzIGdlbmVyYWxseSBiZXR0ZXIgZm9yIHByb3ZpZGluZyBkZXRhaWwgb3IgcmVtaW5kaW5nIHlvdSBob3cgdG8gZG8gdGhpbmdzIHRoYW4gZm9yIGJhc2ljIGBgaG93IGRvIEkuLi4/JycgcXVlc3Rpb25zLg0KICANCllvdSBjYW4gZ2V0IGhlbHAgb24gYW55IFIgZnVuY3Rpb24gYnkgZW50ZXJpbmcgPyBhbmQgdGhlIHRoZSBmdW5jdGlvbiBuYW1lLiBGb3IgZXhhbXBsZToNCmBgYHtyfQ0KP2xtDQo/YW5vdmENCj9wbG90DQpsaWJyYXJ5KGhlbHA9ImxtZTQiKQ0KPz9sbWVyDQpgYGANCg0KVGhlIEhlbHAgbWVudSBvbiB0aGUgdG9vbCBiYXIgcHJvdmlkZXMgbGlua3MgdG8gb3RoZXIgZG9jdW1lbnRhdGlvbiwgaW5jbHVkaW5nIHRoZSBtYW51YWxzIGFuZCBGQVFzLCBhbmQgYSBTZWFyY2ggZmFjaWxpdHkgKGBBcHJvcG9zJyBvbiB0aGUgbWVudSl3aGljaCBpcyB1c2VmdWwgaWYgeW91IHNvcnQgb2YgbWF5YmUgcmVtZW1iZXIgcGFydCBvZiB0aGUgdGhlIG5hbWUgb2Ygd2hhdCBpdCBpcyB5b3UgbmVlZCBoZWxwIG9uLiBUeXBpbmcgImhlbHAuc3RhcnQoKSIgb3BlbnMgYSB3ZWIgYnJvd3NlciB3aXRoIGhlbHAgaW5mb3JtYXRpb24uIFR5cGluZyBleGFtcGxlKGNvbW1hbmQpICh3aGVyZSBjb21tYW5kIGJlY29tZSB0aGUgZnVuY3Rpb24geW91ciBhcmUgdHJ5aW5nIHRvIGZpZ3VyZSBvdXQpIHdpbGwgcnVuIGFueSBleGFtcGxlcyB0aGF0IGFyZSBpbmNsdWRlZCBpbiB0aGUgaGVscCBwYWdlIGZvciBjb21tYW5kLg0KDQpUeXBpbmcgZGVtbyh0b3BpYylydW5zIGRlbW9uc3RyYXRpb24gY29kZSBvbiB0b3BpYyBzcGVjaWZpY2VkLiAgVG8gc2VlIGFsbCBhdmFpbGFibGUgZGVtb3MgdHlwZSAiZGVtbygpIiBieSBpdHNlbGYgdG8gbGlzdCBhbGwgYXZhaWxhYmxlIGRlbW9zLg0KICAgICAgICAgICAgICAgICAgICANCkJ5IGRlZmF1bHQsIFIncyBoZWxwIHN5c3RlbSBvbmx5IHByb3ZpZGVzIGluZm9ybWF0aW9uIGFib3V0IGZ1bmN0aW9ucyB0aGF0IGFyZSBpbiB0aGUgYmFzZSBzeXN0ZW0gYW5kIHBhY2thZ2VzDQp0aGF0IHlvdSBoYXZlIGxvYWRlZCAod2hpY2ggd2Ugd2lsbCBkaXNjdXNzIGxpYnJhcmllcyBsYXRlciBvbi4uLmRvbnQgd29ycnkgYWJvdXQgdGhhdCBmb3Igbm93KS4gWW91IGNhbiBhbHNvIHNlYXJjaCB1c2luZyB0aGUgY29tbWFuZCAiaGVscC5zZWFyY2giIHdoaWNoICB1c2VzIGBgZnV6enkgbWF0Y2hpbmcnJyAtLS0gZm9yIGV4YW1wbGUsIA0KDQpgYGB7cn0NCmhlbHAuc2VhcmNoKCJsb2ciKQ0KYGBgDQoNCmZpbmRzIDUyOCBlbnRyaWVzIChvbiBteSBwYXJ0aWN1bGFyIHN5c3RlbSkgaW5jbHVkaW5nIGxvdHMgb2YgZnVuY3Rpb25zIHdpdGggYGBwbG90JycsIHdoaWNoIGluY2x1ZGVzIHRoZSBsZXR0ZXJzIGBgbG90JycsIHdoaWNoIGFyZSBcZW1waHthbG1vc3R9IGxpa2UgYGBsb2cnJy4gIA0KDQpUeXBpbmcgaW4gdGhlIGNvbW1hbmQgKmV4YW1wbGUqIHdpbGwgcnVuIHRoZSBleGFtcGxlcyAoaWYgYW55KSBnaXZlbiBpbiB0aGUgaGVscCBmb3IgYSBwYXJ0aWN1bGFyIGZ1bmN0aW9uIGUuZy4gZXhhbXBsZShsb2cpLiBBbm90aGVyIHNlYXJjaCBmdW5jdGlvbiBpcyBSU2l0ZVNlYXJjaCgidG9waWMiKSB3aGljaCBkb2VzIGEgZnVsbC10ZXh0IHNlYXJjaCBvZiBhbGwgdGhlIFIgZG9jdW1lbnRhdGlvbiBhbmQgdGhlIG1haWxpbmcgbGlzdCBhcmNoaXZlcyBmb3IgaW5mb3JtYXRpb24gb24gKHlvdSBuZWVkIGFuIGFjdGl2ZSBpbnRlcm5ldCBjb25uZWN0aW9uKS4gDQoNClRyeSBvdXQgb25lIG9yIG1vcmUgb2YgdGhlc2UgYXNwZWN0cyBvZiB0aGUgaGVscCBzeXN0ZW0uDQoNCioqV29ya2luZyB3aXRoIFZlY3RvcnMqKg0KDQpWZWN0b3JzIGluIFIgYXJlIHVzZWQgdG8gcmVwcmVzZW50IHZhcmlhYmxlcy4gUiBjYW4gYXNzaWduIHNldHMgb2YgbnVtYmVycyBvciBjaGFyYWN0ZXIgc3RyaW5ncyB0byBuYW1lZCB2YXJpYWJsZXMgdXNpbmcgdGhlIGMoKSBjb21tYW5kLCBmb3IgdGhlICJjIiBzdGFuZHMgZm9yIGNvbmNhdGVuYXRlLiAoUiB0cmVhdHMgYSBzaW5nbGUgbnVtYmVyIG9yIGNoYXJhY3RlciBhcyBhIHZlY3RvciwgaGF2aW5nIGp1c3Qgb25lIGVsZW1lbnQuIElmIHRoZXJlIGFyZSBtdWx0aXBsZSBudW1iZXJzIG9yIGNoYXJhY3RlcnMgKG9yIHN0cmluZ3Mgb2YgY2hhcmFjdGVycykgdGhlbiBpdCB3aWxsIHRyZWF0IHRoZW0gYXMgYSBtdWx0aS1lbGVtZW50IHZlY3RvcikuDQoNCkZvciBleGFtcGxlIGNvbnRyYXN0IHRoZXNlIHRocmVlIG51bWVyaWMgdmVjdG9yczoNCmBgYHtyfQ0KeDwtMTIzMzM2NTQ1ODgNCngxPC1jKDEyMzMzNjU0NTg4KQ0KeDI8LSBjKDEsMiwzMzMsNjUsNDUsODgpDQp4DQp4MQ0KeDINCmBgYA0KQW5kIHRoZXNlIHRocmVlIGNoYXJhY3RlciB2ZWN0b3JzDQoNCmBgYHtyfQ0KeiA8LSAiV2FrZSB1cCBOZW8iIA0KejEgPC0gYygiVyIsImEiLCJrIiwiZSIsInUiLCJwIiwiTiIsImUiLCJvIikgDQp6MiA8LSBjKCJXYWtlIHVwIE5lbyIpDQp6MzwtYygiV2FrZSIsICJ1cCIsICJOZW8iKQ0Keg0KejENCnoyDQp6Mw0KYGBgDQoNCioqV29ya2luZyB3aXRoIHZlY3RvcnMqKg0KDQpJbiB0aGUgY29kZSBiZWxvdyB3ZSBjYW4gY3JlYXRlIGEgdmVjdG9yIHggdGhhdCBoYXMgMjAgZWxlbWVudHMgKEkgZGVtb25zdHJhdGUgMyBkaWZmZXJlbnQgd2F5cyB0byBkbyB0aGlzLi4uKS4gMSkgd2UgY2FuIHVzZSBhIGNvbG9uIHRvIGdlbmVyYXRlIGEgc2VxdWVuY2Ugb2Ygd2hvbGUgbnVtYmVycy4gMikgQWx0ZXJuYXRpdmVseSB3ZSBjYW4gdXNlIHRoZSBgc2VxYCBjb21tYW5kIChmb3Igc2VxdWVuY2UpIHRvIHNwZWNpZnkgdGhlIGJlZ2luaW5nIGFuZCBlbmQgdmFsdWVzIGFzIHdlbGwgYXMgdGhlIG51bWJlciBvZiBlbGVtZW50cyBkZXNpcmVkIChzZXEgd2lsbGQgZGl2aWRlIHRoZSByYW5nZSB1cCBpbnRvIGVxdWFsIHNpemVkIHVuaXRzKS4gMykgRmluYWxseSwgeW91IGNhbiB1c2UgdGhlIGBjYCBjb21tYW5kIChmb3IgY29uY2F0ZW5hdGUpIGFuZCBzcGVjaWZ5IHRoZSB2YWx1ZXMgbWFudWFsbHkuDQpgYGB7cn0NCiNNZXRob2QgMQ0KeDwtMToyMA0KbGVuZ3RoKHgpDQpwcmludCh4KQ0KDQojTWV0aG9kIDINCng8LXNlcSgxLDIwLGxlbmd0aD0yMCkNCmxlbmd0aCh4KQ0KcHJpbnQoeCkNCng8LXNlcSgyMSw0MCxsZW5ndGg9MjApDQpsZW5ndGgoeCkNCnByaW50KHgpDQp4PC1zZXEoMSw0MCxsZW5ndGg9MjApDQpsZW5ndGgoeCkNCnByaW50KHgpDQoNCiNNZXRob2QgMw0KeDwtYygxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCA5LDEwLDExLDEyLDEzLDE0LDE1LDE2LCAxNywxOCwxOSwyMCkNCmxlbmd0aCh4KQ0KcHJpbnQoeCkNCmBgYA0KKlN1YnNldCBhIHZlY3RvcioNCkdpdmVuIGEgdmVjdG9yIHggeW91IGNhbiB1c2UgaW50ZWdlcnMgaW4gc3F1YXJlIGJyYWNrZXRzIHRvIGluZGljYXRlIHN1YnNldHMgb2YgdGhlIHZlY3Rvci4gRm9yIGV4YW1wbGUgdG8gc2VlIG9ubHkgdGhlIGZpZnRoIHZhbHVlIG9yIGVsZW1lbnQgb2YgdGhlIHZlY3Rvcg0KDQpgYGB7cn0NCng8LXNlcSg1LDEwMCxsZW5ndGg9MjApDQp4WzVdICAgICAgICAjIGZpZnRoIGVsZW1lbnQNCmBgYA0KWW91IGNhbiBhbHNvIHVzZSB2ZWN0b3JzIG9mIGluZGljZXMsIHRvIGV4dHJhY3QgbXVsdGlwbGUgZWxlbWVudHMgZnJvbSBhIHZlY3Rvcg0KDQpgYGB7cn0NCnhbMTozXSAgICAgICMgMTozIGlzIGEgc2hvcnRjdXQgZm9yIGMoMSwyLDMpDQp4W2MoMiw0LDkpXQ0KYGBgDQpTb21lIGZ1bmN0aW9ucyBvZiB2ZWN0b3JzIHlpZWxkIGludGVnZXIgcmVzdWx0cyBhbmQgc28gY2FuIGJlIHVzZWQgYXMgaW5kaWNlcyB0b28uIEZvciBleGFtcGxlLCBlbnRlciB0aGUgZnVuY3Rpb24NCg0KYGBge3J9DQpsZW5ndGgoeCkNCmBgYA0KDQpTaW5jZSB0aGUgcmVzdWx0IGlzIGFuIGludGVnZXIsIGl0IGlzIG9rIHRvIHVzZSBhcyBmb2xsb3dzLA0KDQpgYGB7cn0NCnhbbGVuZ3RoKHgpXQ0KYGBgDQpUaGUgYmVhdXR5IG9mIHRoaXMga2luZCBvZiBjb25zdHJ1Y3Rpb24gd2hlbiB5b3UgYXJlIGNvZGluZyBpcyB0aGF0IGl0IHdpbGwgYWx3YXlzIGdpdmUgdGhlIGxhc3QgZWxlbWVudCBvZiBhIHZlY3RvciB4IG5vIG1hdHRlciBob3cgbWFueSBlbGVtZW50cyB4IGNvbnRhaW5zLiBUaGlzIGtpbmQgb2YgdGhpbmtpbmcgdG8gbWFrZSBjb2RlIHZlcnkgZ2VuZXJhbCAoaS5lLiBhcHBseSB0byBhIHdpZGUgYXJyYXkgb2YgY29uZGl0aW9ucykgY2FuIGJlIHVzZWZ1bCB3aGVuIGRvaW5nIHNvbWUgaGlnaGVyIGxldmVsIGRhdGEgc2NpZW5jZSBvciBtb2RlbGluZyBhcHBsY2lhdGlvbnMuIA0KDQoqKkxvZ2ljYWwgb3BlcmF0b3JzKioNCkxvZ2ljYWwgb3BlcmF0aW9ucyBjYW4gYWxzbyBiZSB1c2VkIHRvIGdlbmVyYXRlIGluZGljYXRvcnMuIEZpcnN0LCBlbnRlciB0aGUgZm9sbG93aW5nIGNvbW1hbmQgYW5kIGNvbXBhcmUgd2l0aCB0aGUgY29udGVudHMgb2YgeCwNCg0KYGBge3J9DQogeCA8IDI1DQoNCmBgYA0KTm93IHlvdSBjYW4gdXNlIHRob3NlIGxvZ2ljYWwgb3V0Y29tZXMgYWJvdXQgdGhlIHZhbGlkaXR5IG9mIHRoZSBsb2dpY2FsIHN0YXRlbWVudCB0byBzdWJzZXQgdGhlIHZlY3RvciB0byByZXRhaW4gb25seSBhIHN1YnNldCBvZiB2YWx1ZXMgdGhhdCBtZWV0IHlvdXIgY3JpdGVyaWEuIEZvciBpbnN0YW5jZS4uDQpgYGB7cn0NCnhbeCA8IDI1XQ0KI29yIw0KeFt4ID4gMjVdDQojb3IjDQp4W3ggIT0gMjVdICNub3RlIGhlcmUgSSBhbSB1c2luZyAhPSB0byBtZWFuICJub3QgZXF1YWwiIHRvIDEwDQp4W3ggPT0gMjVdICNub3RlIGhlcmUgSSBhbSB1c2luZyA9PSB0byBtZWFuICJpcyBleGFjdGx5IGVxdWFsIiB0byAxMA0KYGBgDQpUaGUgYHdoaWNoYCBjb21tYW5kIHdpbGwgaWRlbnRpZnkgdGhlIGxvY2F0aW9ucyBvZiB0aGUgZWxlbWVudHMgY29ycmVzcG9uZGluZyB0byBUUlVFLiBGb3IgZXhhbXBsZSwgdHJ5IHRoZSBmb2xsb3dpbmcgYW5kIGNvbXBhcmUgd2l0aCB5b3VyIHZlY3RvciB4Lg0KDQpgYGB7cn0NCndoaWNoKHggPCAyNSkNCndoaWNoKHggIT0gMjUpICNub3RlIHdoaWNoIG51bWJlciBpcyBtaXNzaW5nIGZyb20gdGhlIGxpc3QgYmVsb3cNCmBgYA0KDQpJbmRpY2F0b3JzIGNhbiBiZSB1c2VkIHRvIGNoYW5nZSBpbmRpdmlkdWFsIGVsZW1lbnRzIG9mIHRoZSB2ZWN0b3IgeC4gRm9yIGV4YW1wbGUsIHRvIGNoYW5nZSB0aGUgZmlmdGggZWxlbWVudCBvZiB4IHRvIDAsDQoNCmBgYHtyfQ0KeFs1XSA8LSAwDQp4DQpgYGANCioqQ2FsY3VsYXRpb25zIG9uIFZlY3RvcnMqKg0KUiBjYW4gYmUgdXNlZCBhcyBhIGNhbGN1bGF0b3IgZm9yIGFycmF5cyBvZiBudW1iZXJzIHRvby4gQ3JlYXRlIGEgc2Vjb25kIG51bWVyaWNhbCB2ZWN0b3IgeSBvZiB0aGUgc2FtZSBsZW5ndGggYXMgeCB5b3UgY3JlYXRlZCBhYm92ZS4gTm93IHRyeSBvdXQgYSBmZXcgb3JkaW5hcnkgbWF0aGVtYXRpY2FsIG9wZXJhdGlvbnMgb24gdGhlIHdob2xlIHZlY3RvcnMgb2YgbnVtYmVycy4gKEhpbnQ6IHRoaXMgaXMgd2hlcmUgeW91IGNhbiB1c2UgdGhlIGlkZWEgb2YgY29kaW5nIGZvciBnZW5lcmFsaXR5IGZyb20gYWJvdmUuLi55b3UgZG9udCBoYXZlIHRvIGtub3cgaG93IGxvbmcgeCBpcyBpZiB5b3UgdXNlIHRoZSBgbGVuZ3RoYCBjb21tYW5kIC1lLmcuIHk8LXNlcSgyLDIwMDAsbGVuZ3RoPWxlbmd0aCh4KSkgd2lsbCBnZW5lcmF0ZSBhIHZlY3RvciB5IHRoYXQgaGFzIHRoZSBzYW1lIG51bWJlciBvZiBlbGVtZW50cyBhcyB4KS4NCg0KDQpgYGB7cn0NCnk8LXNlcSgyLDQwLGxlbmd0aD1sZW5ndGgoeCkpDQp6IDwtIHggKiB5DQp6DQp6MSA8LSB5IC0gMiAqIHgNCnoxDQojbm90ZSB0aGF0IHRoZSA1dGggZWxlbWVudCBzZWVtcyBvdXQgb2YgcGxhY2UgaW4gdGhlc2UgaWYgeW91IGRpZCBub3QgY2hhbmdlIHRoZSBjb252ZXJzaW9uIG9mIHRoYXQgdmFsdWUgdG8gemVybyBhYm92ZSBpbiB5b3VyIHZlY3RvciB4Lg0KYGBgDQpFeGFtaW5lIHRoZSByZXN1bHRzIHRvIHNlZSBob3cgUiBiZWhhdmVzLiBJdCBleGVjdXRlcyB0aGUgb3BlcmF0aW9uIG9uIHRoZSBmaXJzdCBlbGVtZW50cyBvZiB4IGFuZCB5LCB0aGVuIG9uIHRoZSBjb3JyZXNwb25kaW5nIHNlY29uZCBlbGVtZW50cywgYW5kIHNvIG9uLiBFYWNoIHJlc3VsdCBpcyBzdG9yZWQgaW4gdGhlIGNvcnJlc3BvbmRpbmcgZWxlbWVudCBvZiB6LiBMb2dpY2FsIG9wZXJhdGlvbnMgYXJlIHRoZSBzYW1lLA0KDQpgYGB7cn0NCnogPC0geCA+PSB5ICAgICAgICAgICAgICAjID49IGlzIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0bw0Keg0KeiA8LSB4W2Ficyh4KSA8PSBhYnMoeSldICAjIGFic29sdXRlIHZhbHVlcw0Keg0KYGBgDQpXaGF0IGRvZXMgUiBkbyBpZiB0aGUgdHdvIHZlY3RvcnMgYXJlIG5vdCB0aGUgc2FtZSBsZW5ndGg/IFRoZSBhbnN3ZXIgaXMgdGhhdCB0aGUgZWxlbWVudHMgaW4gdGhlIHNob3J0ZXIgdmVjdG9yIGFyZSDigJxyZWN5Y2xlZOKAnSwgc3RhcnRpbmcgZnJvbSB0aGUgYmVnaW5uaW5nLiBUaGlzIGlzIGJhc2ljYWxseSB3aGF0IFIgZG9lcyB3aGVuIHlvdSBtdWx0aXBseSBhIHZlY3RvciBieSBhIHNpbmdsZSBudW1iZXIuIFRoZSBzaW5nbGUgbnVtYmVyIGlzIHJlY3ljbGVkLCBhbmQgc28gaXMgYXBwbGllZCB0byBlYWNoIG9mIHRoZSBlbGVtZW50cyBvZiB4IGluIHR1cm4uDQoNCmBgYHtyfQ0KeA0KeiA8LSAyICogeA0Keg0KeTwtYygyLDEpDQp6PC15KngNCnoNCmBgYA0KKipDaGFsbGVuZ2UgUXVlc3Rpb25zKioNCg0KMS4gQXNzaWduIGEgc2V0IG9mIDEwMCBudW1iZXJzIHRvIGEgdmFyaWFibGUgeC4gTWFrZSBzdXJlIGl0IGluY2x1ZGVzIHNvbWUgcG9zaXRpdmUgYW5kIHNvbWUgbmVnYXRpdmUgbnVtYmVycy4gRGlzcGxheSB0aGUgY29udGVudHMgb2YgdGhlIHZlY3RvciBhZnRlcndhcmQuIElzIGl0IHJlYWxseSBhIHZlY3Rvcj8gRW50ZXIgaXMudmVjdG9yKHgpIHRvIGNvbmZpcm0uDQoNCmBgYHtyfQ0KDQpgYGANCg0KMi4gUHJpbnQgdGhlIDNyZCBhbmQgNnRoIGVsZW1lbnRzIG9mIHggd2l0aCBhIHNpbmdsZSBjb21tYW5kLg0KDQpgYGB7cn0NCg0KYGBgDQoNCjMuIFByaW50IChpLmUuIGRpc3BsYXkpIGFsbCBlbGVtZW50cyBvZiB4IHRoYXQgYXJlIG5vbi1uZWdhdGl2ZS4NCg0KYGBge3J9DQoNCmBgYA0KDQo0LkNoYW5nZSB0aGUgbGFzdCB2YWx1ZSBvZiB5b3VyIHggdmVjdG9yIHRvIGEgZGlmZmVyZW50IG51bWJlci4gQ2hhbmdlIHRoZSAybmQsIDZ0aCwgYW5kIDEwdGggdmFsdWVzIG9mIHggdG8gMSwgMiwgMyB3aXRoIGEgc2luZ2xlIGNvbW1hbmQuDQogICAgDQpgYGB7cn0NCg0KYGBgDQoNCjUuIEZvciBlYWNoIG9mIHRoZSBmb2xsb3dpbmcgZXhhbXBsZXMgZGV0ZXJtaW5lIHdoeSB0aGUgY29kZSBkb2VzIG5vdCB3b3JrIGFuZCBjb3JyZWN0IGl0LiBVc2UgUidzIGJ1aWx0IGluIGhlbHAgZnVuY3Rpb25zIGlmIHlvdSBoYXZlIHRyb3VibGUgb24gdGhlIHNlY29uZCBzZXQuDQpgYGB7cn0NCg0KbXlfdmFyaWFibGUgPC0gMTANCm15X3ZhcsSxYWJsZQ0KYGBgDQoNCmBgYHtyfQ0KeDwtYygyLDM0LDYxLDIxLE5BICwzMikNCnk8LWMoNSw1Niw3ODksMjMsMyw5MCkNCnogPC0gbWVhbih4KnkpDQp6DQpgYGANCg0KKipSZWFkaW5nIGRhdGEgZnJvbSBhbiBleHRlcm5hbCBmaWxlKioNCg0KKldvcmtpbmcgd2l0aCBEYXRhIFNldHMqDQpEYXRhIGZyYW1lcyBhcmUgdGhlIG1vc3QgY29tbW9uIGFuZCBjb252ZW5pZW50IGRhdGEgb2JqZWN0cyB0byB3b3JrIHdpdGggaW4gUi4gSG93ZXZlciwgeW91IG1heSBhbHNvIHJ1biBhY3Jvc3MgbWF0cmljZXMgYW5kIGxpc3RzIHdoaWNoIGFyZSBjb25jZXB0dWFsbHkgbm90IHRvbyBkaWZmZXJlbnQgZnJvbSBhIGRhdGEgZnJhbWUgYW5kIG11Y2ggb2YgdGhlIGxvZ2ljIHlvdSBsZWFybiBmcm9tIHdvcmtpbmcgd2l0aCBkYXRhIGZyYW1lcyBjYW4gYmUgdHJhbnNsYXRlZCBhbW9uZyBkaWZmZXJlbnQgZGF0YSBvYmplY3RzICoqKE1vcmUgb24gdGhpcyBpbiBXb3Jrc2hvcCAzKSoqLg0KDQpUaWJibGVzIGFyZSBhIHR5cGUgb2YgZGF0YSBmcmFtZSBmcm9tIHRoZSAndGlkeXZlcnNlJyB0aGF0IGNhbiBiZSBzbGlnaHRseSBlYXNpZXIgdG8gd29yayB3aXRoIHRoYW4gdGhlIGJhc2UgUiB2ZXJzaW9uLiBCdXQgaW4gZ2VuZXJhbCBJIGhhdmUgZm91bmQgbGl0dGxlIGRpZmZlcmVuY2Ugd2l0aCByZWdhcmRzIHRvIHdoaWNoIHR5cGUgb2YgZGF0YSBmcmFtZSBpcyB1c2VkIChiYXNlIFIgZGF0YS5mcmFtZSBvciBhIFRpYmJsZSkuICANCg0KKipSZWFkaW5nIGRhdGEgdXNpbmcgYmFzZSBSDQpUaGUgZm9sbG93aW5nIGNodW5rIG9mIGNvZGUgcHJvdmlkZXMgMyBkaWZmZXJlbnQgd2F5cyBpbiBiYXNlIFIgdG8gcmVhZCBpbiBhIGRhdGEgZmlsZSBmb3IgZXhhbXBsZSDigJxtYW1tYWwuY3N24oCdIGludG8gYSBkYXRhIGZyYW1lIHdlIHdhaWwgY2FsbCBteSBkYXRhLiBUaGUgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFIGFyZ3VtZW50IHRlbGxzIFIgdG8ga2VlcCBlYWNoIGNoYXJhY3RlciB2YXJpYWJsZSBhcy1pcyByYXRoZXIgdGhhbiBjb252ZXJ0IHRvIGZhY3RvcnMsIHdoaWNoIGFyZSBhIGxpdHRsZSBoYXJkZXIgdG8gd29yayB3aXRoLg0KDQpgYGB7cn0NCiMgYmFzZSBSDQpteWRhdGEgPC0gcmVhZC5jc3YoZmlsZS5jaG9vc2UoKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSAjIFRoaXMgc2hvdWxkIGNhbGwgdXAgYSB3aW5kb3cgd2hlcmUgeW91IGNhbiBuYXZpZ2F0ZSB0byB0aGUgZmlsZQ0KDQpteWRhdGEgPC0gcmVhZC5jc3YoIi4uL2RhdGEvbWFtbWFsLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkgI2FkZCB0aGUgZmlsZSBwYXRoIGluIHBsYWNlIG9mICJkaXJlY3RvcnlfbmFtZSIgaWYgeW91IGhhdmUgYSBtYWMgYWRkIGEgfiB0byB0aGUgZnJvbnQgZW5kICJ+Li4vZGF0YS9tYW1tYWwuY3N2Ig0KbXlkYXRhIDwtIHJlYWQuY3N2KCIuLi9kYXRhL21hbW1hbC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpteWRhdGEgPC0gcmVhZC5jc3YodXJsKCJodHRwOi8vbG9jYXRpb25fdXJsL2ZpbGVuYW1lLmNzdiIpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpICN0byBkb3dubG9hZCBmcm9tIHRoZSB3ZWIgb3IgYSBjbG91ZCBhcHANCmBgYA0KYGBge3J9DQpteWRhdGEgPC0gcmVhZC5jc3YoIi4uL2RhdGEvbWFtbWFsLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCmBgYA0KDQoNCmBgYHtyfQ0KbXlkYXRhIDwtIHJlYWQuY3N2KCIuLi9kYXRhL21hbW1hbC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpgYGANCg0KVG8gcmVhZCBpbiBkYXRhIHVzaW5nIHRoZSByZWFkciBwYWNrYWdlIGZyb20gdGhlIHRpZHl2ZXJzZSwgZXZlcnl0aGluZyBzaG91bGQgYmUgdGhlIHNhbWUgYXMgYWJvdmUgZXhjZXB0IHlvdSB1c2UgdGhlIGZ1bmN0aW9uIHJlYWRfY3N2KCkuDQoNCmBgYHtyfQ0KIyB1c2luZyByZWFkciBwYWNrYWdlDQpteWRhdGEgPC0gcmVhZC5jc3YoIi4uL2RhdGEvbWFtbWFsLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCg0KYGBgDQoNClRoZXJlIGFsc28gYSBhIGZldyBvcHRpb25hbCBhcmd1bWVudHMgdGhhdCBjYW4gaGVscCBzYXZlIHlvdSB0aW1lIGFuZCBmcnVzdHJhdGlvbi4gDQpGb3IgaW5zdGFuY2UsIHNwYWNlcyBhcmUgc29tZXRpbWVzIGludHJvZHVjZWQgYWNjaWRlbnRhbGx5IGR1cmluZyBkYXRhIGVudHJ5IGFuZCBSIHdpbGwgdHJlYXQg4oCcd29yZOKAnSBhbmQgIiB3b3JkIiBhcyBiZWluZyBkaWZmZXJlbnQgd2hpY2ggY2FuIGxlYWQgdG8gYW5hbHl0aWNhbCBlcnJvcnMgKGUuZy4geW91IG1heSBoYXZlIHRvbyBtYW55IGxldmVscyBvZiBhIGZhY3RvciBiZWNhdXNlIOKAnHdvcmTigJ0gYW5kICIgd29yZCIgYXJlIGJlaW5nIHJlYWQgYXMgdHdvIGRpZmZlcmVudCBsZXZlbHMgb2YgYSBmYWN0b3IpLiAgDQoNCmBzdHJpcC53aGl0ZSA9IFRSVUVgIHJlbW92ZXMgc3BhY2VzIGF0IHRoZSBzdGFydCBhbmQgZW5kIG9mIGNoYXJhY3RlciBlbGVtZW50cy4gDQoNCkFub3RoZXIgdXNlZnVsIG9wdGlvbiBpcyBgbmEuc3RyaW5nc2AgaW4gQmFzZSBSIGFuZCBgbmFgIGluIHJlYWRyLCBib3RoIG9mIHdoaWNoIHRlbGwgUiB0byB0cmVhdCBib3RoIGBOQWAgYW5kIGBlbXB0eSBzdHJpbmdzYCBpbiBjb2x1bW5zIG9mIGNoYXJhY3RlciBkYXRhIGFzIG1pc3NpbmcgdmFsdWVzIHJhdGhlciB0aGFuIGFzIHRoZSB2YWx1ZSAiTkEiLiANCg0KWW91IGNhbiBhbHNvIHJlcGxhY2UgIk5BIiBpbiB0aGUgY29kZSBiZWxvdyB3aXRoIHlvdXIgb3duIGluZGljYXRvciBvZiBtaXNzaW5nIGRhdGEgKGUuZy4gIi4iIG9yICJub19kYXRhIiksIEZvciBleGFtcGxlLCBgcmVhZC5jc3YoImZpbGVuYW1lLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSxzdHJpcC53aGl0ZSA9IFRSVUUsIG5hLnN0cmluZ3MgPSBjKCJub19kYXRhIiwgIiIpIClgDQoNCmBgYHtyfQ0KIyBiYXNlIFIgbWV0aG9kOg0KbXlkYXRhIDwtIHJlYWQuY3N2KCJmaWxlbmFtZS5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICBzdHJpcC53aGl0ZSA9IFRSVUUsIG5hLnN0cmluZ3MgPSBjKCJOQSIsICIiKSApDQojIHVzaW5nIHJlYWRyIHBhY2thZ2UNCm15ZGF0YSA8LSByZWFkX2NzdigiZmlsZW5hbWUuY3N2IiwgbmEgPSBjKCJOQSIsICIiKSkNCmBgYA0KDQoqQ2hlY2tpbmcgeW91ciBEYXRhKg0KDQpBZnRlciB5b3UgaGF2ZSBpbXBvcnRlZCB5b3VyIGRhdGEgdGhlcmUgYXJlIGEgdmFyaWV0eSBvZiB0b29scyB0aGF0IHlvdSBjYW4gdXNlIHRvIHZpc3VhbGl6ZSB0aGUgZGF0YSBmcmFtZSB0byBtYWtlIHN1cmUgaXQgaXMgd2hhdCB5b3Ugd2VyZSBleHBlY3RpbmcuIEhlcmUgYXJlIGEgbGlzdCBvZiB0aGUgbW9zdCBoZWxwZnVsLi4uDQoNClRvIHZpZXcgc21hbGwgYXNwZWN0cyBvZiB0aGUgZGF0YSBmcmFtZQ0KYGBge3J9DQpteWRhdGEgICAgICAgICAgICAgIyBpZiBhIHRpYmJsZSwgcHJpbnQgZmlyc3QgZmV3IHJvd3M7IG90aGVyd2lzZSBwcmludHMgYWxsDQpwcmludChteWRhdGEsIG49NSkgIyBwcmludCB0aGUgZmlyc3QgNSByb3dzDQpoZWFkKG15ZGF0YSkgICAgICAgIyBwcmludCB0aGUgZmlyc3QgZmV3IHJvd3MNCnRhaWwobXlkYXRhKSAgICAgICAjIHByaW50IHRoZSBsYXN0IGZldyByb3dzDQpuYW1lcyhteWRhdGEpICAgICAgIyBzZWUgdGhlIHZhcmlhYmxlIG5hbWVzDQpyb3duYW1lcyhteWRhdGEpICAgIyB2aWV3IHJvdyBuYW1lcyAobnVtYmVycywgaWYgeW91IGhhdmVuJ3QgYXNzaWduZWQgbmFtZXMpDQpgYGANCg0KDQo=