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

  1. 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.
  1. Print the 3rd and 6th elements of x with a single command.
  1. 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.

  1. 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=