Getting started with R:
There are three parts.
- R console
- The place where the code is executed
- Text editor
- The place to write your code
- Where to go for help
- ‘?’ read the manuals
- use an AI chatbot
R is a command line program, just like python. You can open it up
from your terminal and start coding, but there are better ways to go
about this.
Even though it’s possible to work directly in the R console, most
people write their code in a separate file using a text editor that at
least has syntax highlighting.
Up until very recently, most people learned R by following tutorials,
and consulting the built in help documentation. This semester we’re
trying a more modern approach utilizing AI.
Files and Folders Basics
What are files?
A file is a saved item on your computer.
Examples of files include:
- A Word document
- A photo
- A spreadsheet
- A PDF
- An R script
In R, you may work with files such as:
.R files
.csv files
.xlsx files
.txt files
A file usually has a name and a file extension.
Example:
homework1.R
Here:
homework1 is the file name
.R is the file extension
The file extension tells the computer what kind of file it is.
What are folders?
A folder is a place where files are stored.
Folders help keep your work organized.
For example, you might have a folder called:
R_Projects
Inside that folder, you might have files like:
data.csv
homework1.R
results.txt
Folders can also contain other folders.
For example:
R_Projects
Week_1
Week_2
Data
Figures
This helps you keep related files together.
Why organization matters
When using R, it is important to know where your files are saved.
R often needs to find files on your computer.
For example, you might ask R to open a data file:
data.csv
But R needs to know where that file is located.
If R cannot find the file, you may get an error.
A common beginner problem is saving a file in one folder, but R is
looking in a different folder.
Good organization makes R easier to use.
Saving files
When you save a file, you choose:
- The file name
- The folder where it will be stored
- The file type
For example, when saving an R script, you might save it as:
week1_notes.R
You should save it inside the folder for your class or project.
Example folder:
Documents/R_Class/Week_1
It is helpful to use simple file names.
Good file names:
week1_notes.R
data_cleaning.R
survey_data.csv
Avoid file names like:
My File!!!!.R
data final final version 2.csv
homework#1.R
Simple names without spaces or special characters are easier to use
in R.
Moving files around
You can move files from one folder to another.
For example, you might move:
data.csv
from your Downloads folder into your R project folder.
This is often a good idea.
Files downloaded from the internet usually go to the Downloads folder
first.
But if you are using the file for an R project, move it into the
project folder.
Example:
Before:
Downloads/data.csv
After:
Documents/R_Class/Week_1/data.csv
This makes it easier for R to find the file.
What is the current working directory?
The current working directory is the folder where R is currently
looking for files.
You can think of it as R’s current location on your computer.
If R is currently working inside this folder:
Documents/R_Class/Week_1
then R will look there first when you ask it to open a file.
For example:
read.csv("data.csv")
R will look for data.csv inside the current working
directory.
If data.csv is not there, R may give an error.
Checking the current working directory
In R, you can check the current working directory with:
getwd()
This means “get working directory.”
It tells you the folder where R is currently looking.
Example output:
"/Users/name/Documents/R_Class/Week_1"
This means R is currently working inside the Week_1
folder.
Setting the working directory
You can change the working directory if needed.
One way is with:
setwd("/Users/name/Documents/R_Class/Week_1")
This tells R to use that folder as the current working directory.
However, beginners should be careful with setwd()
because the folder path may be different on different computers.
Simple rule for beginners
Keep related files together.
For each class, homework, or project, create one folder.
Put your R scripts and data files in that folder.
Example:
Homework_1
homework1.R
data.csv
Then open the R script in Rstudio and make sure it’s using the proper
working directory with getwd() and
setwd().
Common beginner errors
Error: R cannot find my file.
Possible reasons:
- The file is saved in a different folder
- The file name is spelled differently
- The file extension is missing or wrong
- R is using a different working directory
- The file is still in Downloads
Things to check:
- Where is the file saved?
- What is the exact file name?
- What does
getwd() say?
- Is the file inside the folder R is using?
Key takeaways
A file is a saved item on your computer.
A folder is a place where files are stored.
Files should be named clearly.
Related files should be kept together.
The current working directory is the folder where R is currently
looking for files.
Use getwd() to check the current working directory.
The main goal is simple:
Know where your files are, and keep your project files
together.
Coding Basics
R is a complete programming language. Though it was
designed specifically for statistical computing, it can do everything
the other complete languages like c++ and python can
do.
- Essential for this course
- assignments (save stuff into variables)
- variable access (use the data you’ve stored)
- mathematical operations (calculator work)
- reading/writing files (work with permanent storage)
- visualization (plot your data)
- calling functions (doing the work)
- Helpful for real world R use
- writing functions (organize operations into a reusable form)
- control (perform operations based on conditions)
- loops (repeat operations)
We’ll now go through these things in detail.
Assignments
A way to capture the output of an operation so you can use it
again.
A result can be stored into a variable with the
<- (assignment) or = (equals) operator.
x <- 3848.2834 / 19283.2 + 3762.09271
print(x)
[1] 3762.292
y = x + 100
print(y)
[1] 3862.292
myname <- "SuperlongFirstnameAndLastName"
print(myname)
[1] "SuperlongFirstnameAndLastName"
type
Variables have a class that represents the type of
data they contain. You can find out the type of a variable by
using the class() function.
class(x)
[1] "numeric"
class(myname)
[1] "character"
The common types you should be familiar with are
numeric
- a number
- a patient’s blood pressure reading (mmHg)
- a patients weight (in lbs)
integer
- a whole number
- a patient’s age (in years)
- how many children they have
character
- a string
- name
- description of their symptoms
factor
- a category with a predefined set of levels.
- place of residence (urban,rural,suburb)
- their smoking status (never, former, current)
vector
R allows you to store a collection of variables of the same type into
something called a vector with the c (combine)
command.
mynums <- c(1,2,3,4,5)
class(mynums)
[1] "numeric"
print(mynums)
[1] 1 2 3 4 5
mynames <- c("me", "you", "we", "them", "they")
class(mynames)
[1] "character"
print(mynames)
[1] "me" "you" "we" "them" "they"
list
R allows you to store a collection of variables of different types
into something called a list
mylist <- list(1,"me", 2, "we", 3)
class(mylist)
[1] "list"
print(mylist)
[[1]]
[1] 1
[[2]]
[1] "me"
[[3]]
[1] 2
[[4]]
[1] "we"
[[5]]
[1] 3
data.frame
R allows you to store a collection of lists or vectors into something
called a data.frame.
Think of this like a spreadsheet were each observation gets own row
and the variables are stored in the columns. You use the
data.frame() function and pass in the vectors or lists that
store your data and the column names you want them to appear as.
In the example below, the vector that we made earlier
mynums is going to become the first column of the new
data.frame and mynames the 2nd column. These 2 columns will
be called nums and names in the data.frame.
The whole thing is saved into a new variable called
mydata.
mydata <- data.frame(nums=mynums, names=mynames)
print(mydata)
nums names
1 1 me
2 2 you
3 3 we
4 4 them
5 5 they
matrix
A matrix is just like a data.frame except all
elements are the same type. When constructing a matrix
with the matrix() function, you can specify its dimensions
with the ncol and/or nrow parameters.
myvec = c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
print(myvec)
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
mymat = matrix(myvec, ncol=4)
print(mymat)
[,1] [,2] [,3] [,4]
[1,] 1 5 9 13
[2,] 2 6 10 14
[3,] 3 7 11 15
[4,] 4 8 12 16
naming
You can also assign names to the rows and columns of your vectors,
lists, and data.frames and matrices with the names()
function. This can make things easier for you while you code and
interpret your results.
print(mynums)
[1] 1 2 3 4 5
names(mynums) <- c("a", "b", "c", "d", "e")
print(mynums)
a b c d e
1 2 3 4 5
print(mydata)
nums names
1 1 me
2 2 you
3 3 we
4 4 them
5 5 they
rownames(mydata) <- c("first", "second", "third", "fourth", "fifth")
print(mydata)
nums names
first 1 me
second 2 you
third 3 we
fourth 4 them
fifth 5 they
rownames(mydata)
[1] "first" "second" "third" "fourth" "fifth"
colnames(mydata)
[1] "nums" "names"
Variable access
vectors & lists
Now that we know how to store our results, how do we access them?
The elements of a vector can be accessed with
[] (single brackets)
mynums
a b c d e
1 2 3 4 5
mynums[3]
c
3
The elements of a list can be accessed with
[[]] (double brackets)
mylist
[[1]]
[1] 1
[[2]]
[1] "me"
[[3]]
[1] 2
[[4]]
[1] "we"
[[5]]
[1] 3
mylist[[3]]
[1] 2
- gotcha: a list can be a collection
of anything, including other lists. If you use single brackets
[] on a list, it will return the specified element as a
list. This is probably not what you want.
mylist[3]
[[1]]
[1] 2
class(mylist[3])
[1] "list"
mylist[[3]]
[1] 2
class(mylist[[3]])
[1] "numeric"
data.frames
You can access elements of data.frames by their rows
and columns with [i,j] single brackets. The i
before the , is the row, the j after the
, is the column.
mydata
# the 4th row and 2nd column
mydata[4,2]
[1] "them"
You can also specify the location as a combination of numbers and
row/col names
mydata["fourth",2]
[1] "them"
mydata[4,"names"]
[1] "them"
mydata["fourth", "names"]
[1] "them"
multiple elements
If you want to get an entire row, leave off the j in the
[i,j] command
#get the 3rd row
mydata[3,]
If you want an entire column, leave off the i in the
[i,j] command
#get the 2nd column
mydata[,2]
[1] "me" "you" "we" "them" "they"
You can also get columns by using their specific column names with
the $ or by using [[]] double brackets.
mydata$nums
[1] 1 2 3 4 5
mydata[["nums"]]
[1] 1 2 3 4 5
In addition to single elements, you can also specify ranges when
accessing your data. The : command is shorthand notation
for a range.
The command a:b returns a vector starting from
a and ending on b. You can use this notation
within the [] command to access contiguous ranges of a
data.frame or vector.
1:5
[1] 1 2 3 4 5
5:9
[1] 5 6 7 8 9
#first 3 rows, first 2 columns
mydata[1:3, 1:2]
You can specify non contiguous ranges by using a vector
within the [] command
#this returns the first 2 columns of the first and third row
mydata[c(1,3), 1:2]
#this does the same thing
mydata[c("first", "third"), 1:2]
#what does this do?
mydata[c("third", "first"), 1:2]
If you want to remove rows or columns you can put a -
(minus) before the accessor indices
#this will return the first two columns of the data.frame, but will skip the first row
mydata[-1, 1:2]
#this will return the first two columns of the data.frame, but will skip the 2nd row
mydata[-2, 1:2]
#this will return the first two columns of the data.frame, but will skip the first 2 rows
mydata[-(1:2), 1:2]
Mathematical Operations
Every language needs support for basic mathematical operations like
+, -, *, etc. In R we have
support for vector operations which apply the operator
across every element of a vector.
Math on a single number
var1 = 5
(var1 * 2)/.3842
[1] 26.02811
Math on a vector of numbers
vec1 = c(1,2,3,4,5)
vec2 = (vec1 * 2)/.3842
vec2
[1] 5.205622 10.411244 15.616866 20.822488 26.028110
R also has support for operations like &
logical AND, | logical
OR, ! logical NOT and
comparisions < less than,
>= greater than or equals to, etc…
#which values of vec2 are less than 20?
ix = vec2 < 20
#the result of the comparisons is saved in a logical vector
ix
[1] TRUE TRUE TRUE FALSE FALSE
Often times we will access certain rows of a data.frame based on the
result of a logical operation
mydata
#give me all the rows that are TRUE from the comparison above
mydata[ix,]
You can even call logical operators on the fly within the
[i,j] accessors. Combining operators and accessors allows
you to perform more interesting and useful commands than just using them
alone.
mydata
#give me the `names` column of the rows that have a `num` greater than 2
mydata[mydata$num > 2,"names"]
[1] "we" "them" "they"
Reading/Writing files
data.frames are the most common form of data you’ll
be using in R. If your data comes from a spreadsheet with observations
along the rows and the variables along the columns, then it is very
straightforward mapping to an R data.frame.
If you want to save a data.frame into a comma
separated values(.csv) file, it can be done with
write.csv(). This is a function that has 2 main
arguments
- file: The place you want to save it
- x: the data.frame you want to save
write.csv(file="mydata.csv", x=mydata)
Reading can be done from a .csv with read.csv(). The
main argument to this function is:
- file: The place you want to read the file from
The read.csv()function returns the data.frame that you
just read in. You need to remember to save it to a variable.
mydata2 = read.csv(file="mydata.csv")
print(mydata2)
X nums names
1 first 1 me
2 second 2 you
3 third 3 we
4 fourth 4 them
5 fifth 5 they
Visualization
R is one of the most popular environments for making publication
quality graphics today.
Most visualization procedures operate on a data.frame and
have some way to tell it which columns you want to look at.
We’ll be dealing with this more in the next lectures, but here is an
example of how to call the pairs() function, which shows a
scatterplot of every combination of the columns in a data.frame.
pairs(iris[, 1:4], col = iris$Species, pch=19)

Functions
Think of these as a reusable sets of instructions. You give a
function it a set of inputs, it applies a procedure, then gives you an
output.
It’s a way of organizing your code, so you don’t have to keep
copy/pasting the same lines of code and making slight variations in
text.
Most of the work you do in R will be done through using functions
already implemented in base R or by package developers and loaded
through a library() call.
Functions are called by name, with arguments passed between a set of
() parentheses. The interesting thing about R is that you
can specify the arguments by name or by order, and the environment can
figure out which is which.
- It’s usually best to pass arguments explicitly for clarity.
foo <- function(a, b, c){
(a + b)/c
}
foo(3,6,1)
[1] 9
foo(a=3,b=6,c=1)
[1] 9
foo(b=6,c=1, 3)
[1] 9
foo(b=3,c=6, 1)
[1] 0.6666667
Control
If statement
Programming often involves the execution of code dependent on the
result of an upstream process.
R has control operations that allows us to do this.
The most straightforward to use are the if/else
statements.
result <- 7
if (result < 3){
print("you win")
}else{
print("you lose")
}
[1] "you lose"
ifelse() function
You can use the ifelse() function return a result that
is conditional on the elements of a logical vector.
- The function takes 3 parameters:
- test: a logical vector
- yes: the value to return for true elements of test
- no: return values for false
vals = c(123,453,233,54,1223,12)
ifelse(vals < 100, "small", "large")
[1] "large" "large" "large" "small" "large" "small"
Loops
for
We’ve already seen that we can wrap up a series of operations into a
function.
What if we wanted to apply this function to a 100 columns in a dataset?
Would we have to make 100 function calls?
R let’s us run commands over a set of inputs or range using a
structure known as a for loop.
for (i in 1:100){
if (i %% 2==0){
print("even")
} else{
print("odd")
}
}
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
[1] "odd"
[1] "even"
apply
Another common way of applying a function over the rows or columns of
a data.frame is with the apply function.
apply is a function that has 3 parameters arguments
- X: the data.frame you want to work with
- MARGIN: either 1 or 2.
- 1 means you want to apply over all the rows.
- 2 means to apply over all columns
- FUN: the function you want to apply
sum is a built-in function that adds up all the elements
of a vector. Below we’re computing the sum over all the rows and all the
columns using apply.
mymat
[,1] [,2] [,3] [,4]
[1,] 1 5 9 13
[2,] 2 6 10 14
[3,] 3 7 11 15
[4,] 4 8 12 16
#apply over all the rows
apply(mymat, 1, sum)
[1] 28 32 36 40
#apply over all the columns
apply(mymat, 2, sum)
[1] 10 26 42 58
sapply
a function can be applied to each element of a vector with the
sapply function.
sapply has 2 arguments
- X: the vector
- FUN: the function you want to apply
#here we're making a function that returns the negative value of its input.
sillyfunc1 <- function(val){
-val
}
mydata$nums
[1] 1 2 3 4 5
sapply(mydata$nums, sillyfunc1)
[1] -1 -2 -3 -4 -5
anonymous functions
In any of the apply-style loops you can also define a
function on the fly with the anonymous function construct
sapply(mydata$nums, function(val){
-val
})
[1] -1 -2 -3 -4 -5
by
You can apply a function across a splitting variable with the
by function
by has 3 arguments
- data: the values you want to run the function over
- INDICES: the splitting variable
- FUN: the function you want to apply
mydata
by(mydata$nums, mydata$nums < 3, sum)
mydata$nums < 3: FALSE
[1] 12
------------------------------------------------------------------------------------
mydata$nums < 3: TRUE
[1] 3
LS0tDQp0aXRsZTogIkludHJvIHRvIFIiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogNQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCi0tLQ0KDQojIyBXaGF0IGlzIFI/DQoNCkFuIGludGVyYWN0aXZlIHByb2dyYW1taW5nIGxhbmd1YWdlIGFuZCBlbnZpcm9ubWVudCBmb2N1c2luZyBvbiBzdGF0aXN0aWNzLg0KDQojIyMgSG93IGRvZXMgaXQgd29yaz8NCg0KQXQgaXRzIG1vc3QgYmFzaWMgbGV2ZWwsIHlvdSBjYW4gb3BlbiB1cCBSIGF0IHRoZSB0ZXJtaW5hbCBhbmQgdHlwZSBjb21tYW5kcy4NCg0KYGBge3J9DQoNCjIrMg0Kc2luKHBpLzIpDQpjb3MocGkvMikNCigxOjEwKSArIDEwMA0KDQoNCmBgYA0KDQpUaGluayBvZiBpdCBsaWtlIGEgY2FsY3VsYXRvciB3aXRoIGEgbG90IG1vcmUgZmVhdHVyZXMuDQoNCldlJ3JlIGdvaW5nIHRvIGxlYXJuIHNvbWUgb2YgdGhvc2UgZmVhdHVyZXMgdG9kYXkuDQoNCiMjIFdoeSBSPw0KDQpCdWlsdCBhcm91bmQgc3RhdGlzdGljcyBhbmQgZGF0YSBhbmFseXNpcyhlc3BlY2lhbGx5IG9taWNzIGFuZCBiaW9pbmZvcm1hdGljcyksIGFuZCBpcyBvbmUgb2YgdGhlIG1vc3QgcG9wdWxhciBsYW5ndWFnZXMgZm9yIHRoaXMgcHVycG9zZS4NCg0KLSBUaGVyZSBhcmUgb3RoZXIgb3B0aW9ucyB0aGF0IG9mZmVyIGRyYWcgJiBkcm9wIHN0YXRpc3RpY3MNCiAgLSBTUFNTDQogIC0gU1RBVEENCiAgLSBQcmlzbQ0KLSBCdXQuLi4NCiAgLSBUaGVzZSBwbGF0Zm9ybXMgbGFjayBtYW55IHN0YXRpc3RpY2FsIGZlYXR1cmVzDQogIC0gVGhleSBhcmUgbm90IHNjcmlwdGFibGUNCiAgICAtIGxlc3MgcmVwcm9kdWNpYmxlDQogICAgLSBoYXJkZXIgdG8gdmVyaWZ5IHJlc3VsdHMNCiAgICAtIG1hbnVhbGx5IHJlcGV0aXRpdmUNCiAgLSBSZXF1aXJlIGNsZWFuIGRhdGFzZXRzDQogIC0gQ29zdCBtb25leQ0KLSBSIGlzbuKAmXQganVzdCBhIHBvaW50ICYgY2xpY2sgc3RhdHMgcHJvZ3JhbS4gSXTigJlzIGFuIG9wZW4gc291cmNlIHByb2dyYW1taW5nIGxhbmd1YWdlIGJ1aWx0IGJ5IGEgZ2xvYmFsIGNvbW11bml0eSwgYW5kIGdpdmVzIHVzZXJzIGFjY2VzcyB0byBhIGh1Z2UgYW5kIGNvbnN0YW50bHkgZ3Jvd2luZyBzZXQgb2YgbW9kZXJuIHN0YXRpc3RpY2FsIHRvb2xzLg0KDQojIyBQcm9ncmFtbWluZyBpbiB0aGUgYWdlIG9mIEFJDQoNCllvdSBkbyBub3QgbmVlZCB0byBiZSBhbiBleHBlcnQgcHJvZ3JhbW1lciB0byB1c2UgUi4NCg0KTGFyZ2UgTGFuZ3VhZ2UgTW9kZWxzIChMTE1zKSBsaWtlIENoYXRHUFQgYW5kIENsYXVkZSBjYW4gaGVscCBnZW5lcmF0ZSwgZXhwbGFpbiwgYW5kIGRlYnVnIGNvZGUgcXVpY2tseSAtLSB3aXRoIGNhdmVhdHMuDQoNCiMjIyBXaGVyZSBBSSBoZWxwcw0KDQotIEJ1aWxkIHNpbXBsZSBhcHBzIHF1aWNrbHkNCi0gRXhwbGFpbiB0cmlja3kgY29kZQ0KLSBTdWdnZXN0IHN5bnRheA0KLSBEZWJ1ZyBlcnJvcnMNCg0KIyMjIFdoZXJlIEFJIGNhbiBmYWlsDQoNCi0gSW5jb3JyZWN0IGNvZGUNCi0gRGVsZXRlZCBvciBjaGFuZ2VkIGZpbGVzDQotIExlYWtlZCBjb25maWRlbnRpYWwgZGF0YQ0KLSBPdmVyY29uZmlkZW5jZQ0KDQpCeSB0aGUgZW5kIG9mIHRoaXMgd2VlaywgeW91IHdpbGwga25vdyBlbm91Z2ggUiB0byBkbyBzaW1wbGUgdGFza3MgeW91cnNlbGYgYW5kIG1vcmUgY29tcGxleCB0YXNrcyB3aXRoIExMTSBzdXBwb3J0Lg0KDQojIyBHZXR0aW5nIHN0YXJ0ZWQgd2l0aCBSOg0KDQpUaGVyZSBhcmUgdGhyZWUgcGFydHMuDQoNCi0gUiBjb25zb2xlDQogIC0gVGhlIHBsYWNlIHdoZXJlIHRoZSBjb2RlIGlzIGV4ZWN1dGVkDQotIFRleHQgZWRpdG9yDQogIC0gVGhlIHBsYWNlIHRvIHdyaXRlIHlvdXIgY29kZQ0KLSBXaGVyZSB0byBnbyBmb3IgaGVscA0KICAtICc/JyByZWFkIHRoZSBtYW51YWxzDQogIC0gdXNlIGFuIEFJIGNoYXRib3QNCg0KUiBpcyBhIGNvbW1hbmQgbGluZSBwcm9ncmFtLCBqdXN0IGxpa2UgcHl0aG9uLiBZb3UgY2FuIG9wZW4gaXQgdXAgZnJvbSB5b3VyIHRlcm1pbmFsIGFuZCBzdGFydCBjb2RpbmcsIGJ1dCB0aGVyZSBhcmUgYmV0dGVyIHdheXMgdG8gZ28gYWJvdXQgdGhpcy4NCg0KRXZlbiB0aG91Z2ggaXQncyBwb3NzaWJsZSB0byB3b3JrIGRpcmVjdGx5IGluIHRoZSBSIGNvbnNvbGUsIG1vc3QgcGVvcGxlIHdyaXRlIHRoZWlyIGNvZGUgaW4gYSBzZXBhcmF0ZSBmaWxlIHVzaW5nIGEgdGV4dCBlZGl0b3IgdGhhdCBhdCBsZWFzdCBoYXMgc3ludGF4IGhpZ2hsaWdodGluZy4NCg0KVXAgdW50aWwgdmVyeSByZWNlbnRseSwgbW9zdCBwZW9wbGUgbGVhcm5lZCBSIGJ5IGZvbGxvd2luZyB0dXRvcmlhbHMsIGFuZCBjb25zdWx0aW5nIHRoZSBidWlsdCBpbiBoZWxwIGRvY3VtZW50YXRpb24uIFRoaXMgc2VtZXN0ZXIgd2UncmUgdHJ5aW5nIGEgbW9yZSBtb2Rlcm4gYXBwcm9hY2ggdXRpbGl6aW5nIEFJLg0KDQojIyBJbnN0YWxsaW5nIFINCg0KSWYgeW91IHdhbnQgdG8gd29yayBsb2NhbGx5LCB5b3UnbGwgZmlyc3QgbmVlZCB0byBpbnN0YWxsIHRoZSBSIGNvbnNvbGUgb24geW91ciBjb21wdXRlci4NCg0KLSBbUiB3ZWJzaXRlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy8pDQoNCkNob29zZSB0aGUgYXBwcm9wcmlhdGUgb3B0aW9uIGJhc2VkIG9uIHlvdXIgb3BlcmF0aW5nIHN5c3RlbS4NCg0KIyMgVXNpbmcgUg0KDQpUaGVyZSBhcmUgYSBudW1iZXIgb2Ygd2F5cyB0byBpbnRlcmFjdCB3aXRoIFIuDQoNCi0gWW91IGNhbiBvcGVuIFIgYW5kIHR5cGUgZGlyZWN0bHkgaW50byB0aGUgY29uc29sZS4NCg0KLSBZb3UgY2FuIHdvcmsgd2l0aCBhIHRleHQgZWRpdG9yIG9mIHlvdXIgY2hvaWNlIGFuZCBjb3B5L3Bhc3RlIGxpbmVzIGludG8gdGhlIFIgY29uc29sZS4NCg0KLSBZb3UgY2FuIHVzZSBhbiBJREUgKEludGVncmF0ZWQgRGV2ZWxvcG1lbnQgRW52aXJvbm1lbnQgKSB0aGF0IGF1dG9tYXRpY2FsbHkgbGlua3MgYSB0ZXh0IGVkaXRvciB3aXRoIHRoZSBSIGNvbnNvbGUuDQoNCiAgLSBbUnN0dWRpb10oaHR0cHM6Ly9kb2NzLnBvc2l0LmNvL2lkZS91c2VyLyNyc3R1ZGlvLWlkZS1vc3MtZG93bmxvYWRzKSBpcyB0aGUgbW9zdCBwb3B1bGFyIGNob2ljZS4NCg0KLSBZb3UgY2FuIHVzZSBhIGNsb3VkIGJhc2VkIElERQ0KDQogIC0gW0dvb2dsZSBDb2xhYl0oaHR0cHM6Ly9jb2xhYi5yZXNlYXJjaC5nb29nbGUuY29tLykuIFRoaXMgaGFzIGV2ZXJ5dGhpbmcgdGhhdCBhIGxvY2FsIElERSBkb2VzLCBidXQgd29ya3Mgb24geW91ciBicm93c2VyIHVzaW5nIGNsb3VkIHJlc291cmNlcyBpbnN0ZWFkIG9mIHlvdXIgbG9jYWwgY29tcHV0ZXIuDQoNCllvdSBoYXZlIHRvIGNob29zZSBvbmUgb2YgdGhlc2UgdG8gdXNlIFIsIEkgc3VnZ2VzdCAqKlJzdHVkaW8qKg0KDQojIyBSIHBhY2thZ2VzDQoNClByb2dyYW1tZXJzIGFuZCBEYXRhIEFuYWx5c3RzIHdyaXRlIGNvZGUgdG8gcGVyZm9ybSBhIHRhc2sgb3Igc29sdmUgYSBwcm9ibGVtLiBJZiB5b3UgZW5jb3VudGVyIHRoZSBzYW1lIHRhc2sgYWdhaW4sIHlvdSBzaG91bGRuJ3QgaGF2ZSB0byB3cml0ZSBldmVyeXRoaW5nIGFnYWluLg0KDQotIFdoYXQgaXMgdGhlIGlkZWE/DQoNCiAgLSB3cmFwIGV2ZXJ5dGhpbmcgbmVlZGVkIHRvIHBlcmZvcm0gYSB0YXNrIGludG8gYSBjb2xsZWN0aW9uIG9mIGZpbGVzDQoNCiAgLSBtYWtlIGl0IGVhc3kgZm9yIHlvdSBvciBzb21lb25lIGVsc2UgdG8gdXNlIHRoYXQgY29sbGVjdGlvbg0KDQogIC0gcHJvdmlkZSBkb2N1bWVudGF0aW9uIG9uIGhvdyB0byB1c2UgeW91ciBjb2RlDQoNCiMjIyBXaGF0IGlzIGFuIFIgcGFja2FnZT8NCg0KUGFja2FnZXMgYXJlIHRoZSBtYWluIHN0cmVuZ3RoIG9mIFIhIEl0J3Mgbm90IHRoZSBmYXN0ZXN0IGxhbmd1YWdlLCBvciBlYXNpZXN0IHRvIHdyaXRlIGluLCBidXQgUiBoYXMgb25lIG9mIHRoZSBsYXJnZXN0IGVjb3N5c3RlbXMgb2Ygc3RhdGlzdGljYWwgYW5kIGRhdGEgc2NpZW5jZSBsaWJyYXJpZXMgb2YgYW55IHByb2dyYW1taW5nIGxhbmd1YWdlLCB3aXRoIHRlbnMgb2YgdGhvdXNhbmRzIG9mIHBhY2thZ2VzIGF2YWlsYWJsZSB0aHJvdWdoIG9wZW4gc291cmNlIHJlcG9zaXRvcmllcy4gKFx+MjNrIG9uIENSQU4sIFx+MjUwMCBvbiBCaW9jb25kdWN0b3IpLg0KDQojIyMjIEhvdyB0byB1c2UgdGhlbT8NCg0KLSBpbnN0YWxsIHRoZW0gb25jZQ0KLSBsb2FkIHRoZW0gd2hlbiB5b3UgbmVlZCB0aGVtDQoNCmBgYHtyLCBldmFsPUZ9DQoNCmluc3RhbGwucGFja2FnZXMoWU9VUlBBQ0tBR0UpDQoNCmxpYnJhcnkoWU9VUlBBQ0tBR0UpDQpgYGANCg0KIyMgRmlsZXMgYW5kIEZvbGRlcnMgQmFzaWNzDQoNCiMjIyBXaGF0IGFyZSBmaWxlcz8NCg0KQSBmaWxlIGlzIGEgc2F2ZWQgaXRlbSBvbiB5b3VyIGNvbXB1dGVyLg0KDQpFeGFtcGxlcyBvZiBmaWxlcyBpbmNsdWRlOg0KDQotIEEgV29yZCBkb2N1bWVudA0KLSBBIHBob3RvDQotIEEgc3ByZWFkc2hlZXQNCi0gQSBQREYNCi0gQW4gUiBzY3JpcHQNCg0KSW4gUiwgeW91IG1heSB3b3JrIHdpdGggZmlsZXMgc3VjaCBhczoNCg0KLSBgLlJgIGZpbGVzDQotIGAuY3N2YCBmaWxlcw0KLSBgLnhsc3hgIGZpbGVzDQotIGAudHh0YCBmaWxlcw0KDQpBIGZpbGUgdXN1YWxseSBoYXMgYSBuYW1lIGFuZCBhIGZpbGUgZXh0ZW5zaW9uLg0KDQpFeGFtcGxlOg0KDQpgaG9tZXdvcmsxLlJgDQoNCkhlcmU6DQoNCi0gYGhvbWV3b3JrMWAgaXMgdGhlIGZpbGUgbmFtZQ0KLSBgLlJgIGlzIHRoZSBmaWxlIGV4dGVuc2lvbg0KDQpUaGUgZmlsZSBleHRlbnNpb24gdGVsbHMgdGhlIGNvbXB1dGVyIHdoYXQga2luZCBvZiBmaWxlIGl0IGlzLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjIFdoYXQgYXJlIGZvbGRlcnM/DQoNCkEgZm9sZGVyIGlzIGEgcGxhY2Ugd2hlcmUgZmlsZXMgYXJlIHN0b3JlZC4NCg0KRm9sZGVycyBoZWxwIGtlZXAgeW91ciB3b3JrIG9yZ2FuaXplZC4NCg0KRm9yIGV4YW1wbGUsIHlvdSBtaWdodCBoYXZlIGEgZm9sZGVyIGNhbGxlZDoNCg0KYFJfUHJvamVjdHNgDQoNCkluc2lkZSB0aGF0IGZvbGRlciwgeW91IG1pZ2h0IGhhdmUgZmlsZXMgbGlrZToNCg0KYGBgIHRleHQNCmRhdGEuY3N2DQpob21ld29yazEuUg0KcmVzdWx0cy50eHQNCmBgYA0KDQpGb2xkZXJzIGNhbiBhbHNvIGNvbnRhaW4gb3RoZXIgZm9sZGVycy4NCg0KRm9yIGV4YW1wbGU6DQoNCmBgYCB0ZXh0DQpSX1Byb2plY3RzDQogIFdlZWtfMQ0KICBXZWVrXzINCiAgRGF0YQ0KICBGaWd1cmVzDQpgYGANCg0KVGhpcyBoZWxwcyB5b3Uga2VlcCByZWxhdGVkIGZpbGVzIHRvZ2V0aGVyLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjIFdoeSBvcmdhbml6YXRpb24gbWF0dGVycw0KDQpXaGVuIHVzaW5nIFIsIGl0IGlzIGltcG9ydGFudCB0byBrbm93IHdoZXJlIHlvdXIgZmlsZXMgYXJlIHNhdmVkLg0KDQpSIG9mdGVuIG5lZWRzIHRvIGZpbmQgZmlsZXMgb24geW91ciBjb21wdXRlci4NCg0KRm9yIGV4YW1wbGUsIHlvdSBtaWdodCBhc2sgUiB0byBvcGVuIGEgZGF0YSBmaWxlOg0KDQpgZGF0YS5jc3ZgDQoNCkJ1dCBSIG5lZWRzIHRvIGtub3cgd2hlcmUgdGhhdCBmaWxlIGlzIGxvY2F0ZWQuDQoNCklmIFIgY2Fubm90IGZpbmQgdGhlIGZpbGUsIHlvdSBtYXkgZ2V0IGFuIGVycm9yLg0KDQpBIGNvbW1vbiBiZWdpbm5lciBwcm9ibGVtIGlzIHNhdmluZyBhIGZpbGUgaW4gb25lIGZvbGRlciwgYnV0IFIgaXMgbG9va2luZyBpbiBhIGRpZmZlcmVudCBmb2xkZXIuDQoNCkdvb2Qgb3JnYW5pemF0aW9uIG1ha2VzIFIgZWFzaWVyIHRvIHVzZS4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIyBTYXZpbmcgZmlsZXMNCg0KV2hlbiB5b3Ugc2F2ZSBhIGZpbGUsIHlvdSBjaG9vc2U6DQoNCi0gVGhlIGZpbGUgbmFtZQ0KLSBUaGUgZm9sZGVyIHdoZXJlIGl0IHdpbGwgYmUgc3RvcmVkDQotIFRoZSBmaWxlIHR5cGUNCg0KRm9yIGV4YW1wbGUsIHdoZW4gc2F2aW5nIGFuIFIgc2NyaXB0LCB5b3UgbWlnaHQgc2F2ZSBpdCBhczoNCg0KYHdlZWsxX25vdGVzLlJgDQoNCllvdSBzaG91bGQgc2F2ZSBpdCBpbnNpZGUgdGhlIGZvbGRlciBmb3IgeW91ciBjbGFzcyBvciBwcm9qZWN0Lg0KDQpFeGFtcGxlIGZvbGRlcjoNCg0KYERvY3VtZW50cy9SX0NsYXNzL1dlZWtfMWANCg0KSXQgaXMgaGVscGZ1bCB0byB1c2Ugc2ltcGxlIGZpbGUgbmFtZXMuDQoNCkdvb2QgZmlsZSBuYW1lczoNCg0KYGBgIHRleHQNCndlZWsxX25vdGVzLlINCmRhdGFfY2xlYW5pbmcuUg0Kc3VydmV5X2RhdGEuY3N2DQpgYGANCg0KQXZvaWQgZmlsZSBuYW1lcyBsaWtlOg0KDQpgYGAgdGV4dA0KTXkgRmlsZSEhISEuUg0KZGF0YSBmaW5hbCBmaW5hbCB2ZXJzaW9uIDIuY3N2DQpob21ld29yayMxLlINCmBgYA0KDQpTaW1wbGUgbmFtZXMgd2l0aG91dCBzcGFjZXMgb3Igc3BlY2lhbCBjaGFyYWN0ZXJzIGFyZSBlYXNpZXIgdG8gdXNlIGluIFIuDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyMgTW92aW5nIGZpbGVzIGFyb3VuZA0KDQpZb3UgY2FuIG1vdmUgZmlsZXMgZnJvbSBvbmUgZm9sZGVyIHRvIGFub3RoZXIuDQoNCkZvciBleGFtcGxlLCB5b3UgbWlnaHQgbW92ZToNCg0KYGRhdGEuY3N2YA0KDQpmcm9tIHlvdXIgRG93bmxvYWRzIGZvbGRlciBpbnRvIHlvdXIgUiBwcm9qZWN0IGZvbGRlci4NCg0KVGhpcyBpcyBvZnRlbiBhIGdvb2QgaWRlYS4NCg0KRmlsZXMgZG93bmxvYWRlZCBmcm9tIHRoZSBpbnRlcm5ldCB1c3VhbGx5IGdvIHRvIHRoZSBEb3dubG9hZHMgZm9sZGVyIGZpcnN0Lg0KDQpCdXQgaWYgeW91IGFyZSB1c2luZyB0aGUgZmlsZSBmb3IgYW4gUiBwcm9qZWN0LCBtb3ZlIGl0IGludG8gdGhlIHByb2plY3QgZm9sZGVyLg0KDQpFeGFtcGxlOg0KDQpCZWZvcmU6DQoNCmBEb3dubG9hZHMvZGF0YS5jc3ZgDQoNCkFmdGVyOg0KDQpgRG9jdW1lbnRzL1JfQ2xhc3MvV2Vla18xL2RhdGEuY3N2YA0KDQpUaGlzIG1ha2VzIGl0IGVhc2llciBmb3IgUiB0byBmaW5kIHRoZSBmaWxlLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjIFdoYXQgaXMgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnk/DQoNClRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IGlzIHRoZSBmb2xkZXIgd2hlcmUgUiBpcyBjdXJyZW50bHkgbG9va2luZyBmb3IgZmlsZXMuDQoNCllvdSBjYW4gdGhpbmsgb2YgaXQgYXMgUuKAmXMgY3VycmVudCBsb2NhdGlvbiBvbiB5b3VyIGNvbXB1dGVyLg0KDQpJZiBSIGlzIGN1cnJlbnRseSB3b3JraW5nIGluc2lkZSB0aGlzIGZvbGRlcjoNCg0KYERvY3VtZW50cy9SX0NsYXNzL1dlZWtfMWANCg0KdGhlbiBSIHdpbGwgbG9vayB0aGVyZSBmaXJzdCB3aGVuIHlvdSBhc2sgaXQgdG8gb3BlbiBhIGZpbGUuDQoNCkZvciBleGFtcGxlOg0KDQpgYGAgcg0KcmVhZC5jc3YoImRhdGEuY3N2IikNCmBgYA0KDQpSIHdpbGwgbG9vayBmb3IgYGRhdGEuY3N2YCBpbnNpZGUgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkuDQoNCklmIGBkYXRhLmNzdmAgaXMgbm90IHRoZXJlLCBSIG1heSBnaXZlIGFuIGVycm9yLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMjIENoZWNraW5nIHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5DQoNCkluIFIsIHlvdSBjYW4gY2hlY2sgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3Rvcnkgd2l0aDoNCg0KYGBgIHINCmdldHdkKCkNCmBgYA0KDQpUaGlzIG1lYW5zIOKAnGdldCB3b3JraW5nIGRpcmVjdG9yeS7igJ0NCg0KSXQgdGVsbHMgeW91IHRoZSBmb2xkZXIgd2hlcmUgUiBpcyBjdXJyZW50bHkgbG9va2luZy4NCg0KRXhhbXBsZSBvdXRwdXQ6DQoNCmBgYCB0ZXh0DQoiL1VzZXJzL25hbWUvRG9jdW1lbnRzL1JfQ2xhc3MvV2Vla18xIg0KYGBgDQoNClRoaXMgbWVhbnMgUiBpcyBjdXJyZW50bHkgd29ya2luZyBpbnNpZGUgdGhlIGBXZWVrXzFgIGZvbGRlci4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIyBTZXR0aW5nIHRoZSB3b3JraW5nIGRpcmVjdG9yeQ0KDQpZb3UgY2FuIGNoYW5nZSB0aGUgd29ya2luZyBkaXJlY3RvcnkgaWYgbmVlZGVkLg0KDQpPbmUgd2F5IGlzIHdpdGg6DQoNCmBgYCByDQpzZXR3ZCgiL1VzZXJzL25hbWUvRG9jdW1lbnRzL1JfQ2xhc3MvV2Vla18xIikNCmBgYA0KDQpUaGlzIHRlbGxzIFIgdG8gdXNlIHRoYXQgZm9sZGVyIGFzIHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5Lg0KDQpIb3dldmVyLCBiZWdpbm5lcnMgc2hvdWxkIGJlIGNhcmVmdWwgd2l0aCBgc2V0d2QoKWAgYmVjYXVzZSB0aGUgZm9sZGVyIHBhdGggbWF5IGJlIGRpZmZlcmVudCBvbiBkaWZmZXJlbnQgY29tcHV0ZXJzLg0KDQojIyMgU2ltcGxlIHJ1bGUgZm9yIGJlZ2lubmVycw0KDQpLZWVwIHJlbGF0ZWQgZmlsZXMgdG9nZXRoZXIuDQoNCkZvciBlYWNoIGNsYXNzLCBob21ld29yaywgb3IgcHJvamVjdCwgY3JlYXRlIG9uZSBmb2xkZXIuDQoNClB1dCB5b3VyIFIgc2NyaXB0cyBhbmQgZGF0YSBmaWxlcyBpbiB0aGF0IGZvbGRlci4NCg0KRXhhbXBsZToNCg0KYGBgIHRleHQNCkhvbWV3b3JrXzENCiAgaG9tZXdvcmsxLlINCiAgZGF0YS5jc3YNCmBgYA0KDQpUaGVuIG9wZW4gdGhlIFIgc2NyaXB0IGluIFJzdHVkaW8gYW5kIG1ha2Ugc3VyZSBpdCdzIHVzaW5nIHRoZSBwcm9wZXIgd29ya2luZyBkaXJlY3Rvcnkgd2l0aCBgZ2V0d2QoKWAgYW5kIGBzZXR3ZCgpYC4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIyBDb21tb24gYmVnaW5uZXIgZXJyb3JzDQoNCkVycm9yOiBSIGNhbm5vdCBmaW5kIG15IGZpbGUuDQoNClBvc3NpYmxlIHJlYXNvbnM6DQoNCi0gVGhlIGZpbGUgaXMgc2F2ZWQgaW4gYSBkaWZmZXJlbnQgZm9sZGVyDQotIFRoZSBmaWxlIG5hbWUgaXMgc3BlbGxlZCBkaWZmZXJlbnRseQ0KLSBUaGUgZmlsZSBleHRlbnNpb24gaXMgbWlzc2luZyBvciB3cm9uZw0KLSBSIGlzIHVzaW5nIGEgZGlmZmVyZW50IHdvcmtpbmcgZGlyZWN0b3J5DQotIFRoZSBmaWxlIGlzIHN0aWxsIGluIERvd25sb2Fkcw0KDQpUaGluZ3MgdG8gY2hlY2s6DQoNCi0gV2hlcmUgaXMgdGhlIGZpbGUgc2F2ZWQ/DQotIFdoYXQgaXMgdGhlIGV4YWN0IGZpbGUgbmFtZT8NCi0gV2hhdCBkb2VzIGBnZXR3ZCgpYCBzYXk/DQotIElzIHRoZSBmaWxlIGluc2lkZSB0aGUgZm9sZGVyIFIgaXMgdXNpbmc/DQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyMgS2V5IHRha2Vhd2F5cw0KDQpBIGZpbGUgaXMgYSBzYXZlZCBpdGVtIG9uIHlvdXIgY29tcHV0ZXIuDQoNCkEgZm9sZGVyIGlzIGEgcGxhY2Ugd2hlcmUgZmlsZXMgYXJlIHN0b3JlZC4NCg0KRmlsZXMgc2hvdWxkIGJlIG5hbWVkIGNsZWFybHkuDQoNClJlbGF0ZWQgZmlsZXMgc2hvdWxkIGJlIGtlcHQgdG9nZXRoZXIuDQoNClRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5IGlzIHRoZSBmb2xkZXIgd2hlcmUgUiBpcyBjdXJyZW50bHkgbG9va2luZyBmb3IgZmlsZXMuDQoNClVzZSBgZ2V0d2QoKWAgdG8gY2hlY2sgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkuDQoNClRoZSBtYWluIGdvYWwgaXMgc2ltcGxlOg0KDQoqKktub3cgd2hlcmUgeW91ciBmaWxlcyBhcmUsIGFuZCBrZWVwIHlvdXIgcHJvamVjdCBmaWxlcyB0b2dldGhlci4qKg0KDQojIyBSc3R1ZGlvIEJhc2ljcw0KDQpUaGlzIElERSBoYXMgYSBsb3Qgb2YgdXNlZnVsIGZlYXR1cmVzIGJ1dCBjYW4gYmUgb3ZlcndoZWxtaW5nIGF0IGZpcnN0Lg0KDQpXZSdyZSBnb2luZyB0byBzcGVuZCBzb21lIHRpbWUgb24gYSBsaXZlIGRlbW8gdG8gaW50cm9kdWNlIHNvbWUgb2YgdGhlIGZlYXR1cmVzLg0KDQotIEtleSBQb2ludHMNCiAgLSBXaGVyZSBpcyB0aGUgdGV4dCBlZGl0b3I/DQogIC0gV2hlcmUgaXMgdGhlIFIgY29uc29sZT8NCiAgLSBIb3cgZG8geW91IHNlbmQgdGV4dCBmcm9tIHRoZSBlZGl0b3IgdG8gdGhlIGNvbnNvbGU/DQogIC0gSG93IGRvIHlvdSBtYWtlIGEgbmV3IGZpbGU/DQogICAgLSBzbyBtYW55IG9wdGlvbnMsIHdoaWNoIHRvIGNob29zZT8NCiAgLSBXaGF0J3MgdGhlIEVudmlyb25tZW50IHRhYi9wYW5lbCBpbiB0aGUgdG9wIHJpZ2h0IGNvcm5lcj8NCiAgLSBXaGF0J3MgdGhlIHBhbmVsIGluIHRoZSBib3R0b20gcmlnaHQgY29ybmVyPw0KICAgIC0gRmlsZXMNCiAgICAtIFBsb3RzDQogICAgLSBQYWNrYWdlcw0KICAtIEhvdyBkbyB5b3Ugc2V0IHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5Pw0KDQohW10ocGljX3JzdHVkaW8ucG5nKQ0KDQojIyBDb2RpbmcgQmFzaWNzDQoNClIgaXMgYSAqKmNvbXBsZXRlKiogcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UuIFRob3VnaCBpdCB3YXMgZGVzaWduZWQgc3BlY2lmaWNhbGx5IGZvciBzdGF0aXN0aWNhbCBjb21wdXRpbmcsIGl0IGNhbiBkbyBldmVyeXRoaW5nIHRoZSBvdGhlciAqKmNvbXBsZXRlKiogbGFuZ3VhZ2VzIGxpa2UgYysrIGFuZCBweXRob24gY2FuIGRvLg0KDQotIEVzc2VudGlhbCBmb3IgdGhpcyBjb3Vyc2UNCiAgLSBhc3NpZ25tZW50cyAoc2F2ZSBzdHVmZiBpbnRvIHZhcmlhYmxlcykNCiAgLSB2YXJpYWJsZSBhY2Nlc3MgKHVzZSB0aGUgZGF0YSB5b3UndmUgc3RvcmVkKQ0KICAtIG1hdGhlbWF0aWNhbCBvcGVyYXRpb25zIChjYWxjdWxhdG9yIHdvcmspDQogIC0gcmVhZGluZy93cml0aW5nIGZpbGVzICh3b3JrIHdpdGggcGVybWFuZW50IHN0b3JhZ2UpDQogIC0gdmlzdWFsaXphdGlvbiAocGxvdCB5b3VyIGRhdGEpDQogIC0gY2FsbGluZyBmdW5jdGlvbnMgKGRvaW5nIHRoZSB3b3JrKQ0KLSBIZWxwZnVsIGZvciByZWFsIHdvcmxkIFIgdXNlDQogIC0gd3JpdGluZyBmdW5jdGlvbnMgKG9yZ2FuaXplIG9wZXJhdGlvbnMgaW50byBhIHJldXNhYmxlIGZvcm0pDQogIC0gY29udHJvbCAocGVyZm9ybSBvcGVyYXRpb25zIGJhc2VkIG9uIGNvbmRpdGlvbnMpDQogIC0gbG9vcHMgKHJlcGVhdCBvcGVyYXRpb25zKQ0KDQpXZSdsbCBub3cgZ28gdGhyb3VnaCB0aGVzZSB0aGluZ3MgaW4gZGV0YWlsLg0KDQojIyMgQXNzaWdubWVudHMNCg0KQSB3YXkgdG8gY2FwdHVyZSB0aGUgb3V0cHV0IG9mIGFuIG9wZXJhdGlvbiBzbyB5b3UgY2FuIHVzZSBpdCBhZ2Fpbi4NCg0KQSByZXN1bHQgY2FuIGJlIHN0b3JlZCBpbnRvIGEgKnZhcmlhYmxlKiB3aXRoIHRoZSBgPC1gIChhc3NpZ25tZW50KSBvciBgPWAgKGVxdWFscykgb3BlcmF0b3IuDQoNCmBgYHtyfQ0KeCA8LSAgMzg0OC4yODM0IC8gMTkyODMuMiArIDM3NjIuMDkyNzENCnByaW50KHgpDQp5ID0geCArIDEwMCANCnByaW50KHkpDQoNCm15bmFtZSA8LSAiU3VwZXJsb25nRmlyc3RuYW1lQW5kTGFzdE5hbWUiDQpwcmludChteW5hbWUpDQpgYGANCg0KIyMjIyB0eXBlDQoNClZhcmlhYmxlcyBoYXZlIGEgKmNsYXNzKiB0aGF0IHJlcHJlc2VudHMgdGhlICp0eXBlKiBvZiBkYXRhIHRoZXkgY29udGFpbi4gWW91IGNhbiBmaW5kIG91dCB0aGUgKnR5cGUqIG9mIGEgdmFyaWFibGUgYnkgdXNpbmcgdGhlIGBjbGFzcygpYCBmdW5jdGlvbi4NCg0KYGBge3J9DQpjbGFzcyh4KQ0KY2xhc3MobXluYW1lKQ0KYGBgDQoNClRoZSBjb21tb24gdHlwZXMgeW91IHNob3VsZCBiZSBmYW1pbGlhciB3aXRoIGFyZQ0KDQojIyMjIyBudW1lcmljDQoNCi0gYSBudW1iZXINCiAgLSBhIHBhdGllbnQncyBibG9vZCBwcmVzc3VyZSByZWFkaW5nIChtbUhnKQ0KICAtIGEgcGF0aWVudHMgd2VpZ2h0IChpbiBsYnMpDQoNCiMjIyMjIGludGVnZXINCg0KLSBhIHdob2xlIG51bWJlcg0KICAtIGEgcGF0aWVudCdzIGFnZSAoaW4geWVhcnMpDQogIC0gaG93IG1hbnkgY2hpbGRyZW4gdGhleSBoYXZlDQoNCiMjIyMjIGNoYXJhY3Rlcg0KDQotIGEgc3RyaW5nDQogIC0gbmFtZQ0KICAtIGRlc2NyaXB0aW9uIG9mIHRoZWlyIHN5bXB0b21zDQoNCiMjIyMjIGZhY3Rvcg0KDQotIGEgY2F0ZWdvcnkgd2l0aCBhIHByZWRlZmluZWQgc2V0IG9mIGxldmVscy4NCiAgLSBwbGFjZSBvZiByZXNpZGVuY2UgKHVyYmFuLHJ1cmFsLHN1YnVyYikNCiAgLSB0aGVpciBzbW9raW5nIHN0YXR1cyAobmV2ZXIsIGZvcm1lciwgY3VycmVudCkNCg0KIyMjIyMgbG9naWNhbA0KDQotIGEgdHJ1ZS9mYWxzZQ0KICAtIGh5cGVydGVuc2lvbiAoeWVzL25vKQ0KDQojIyMjIHZlY3Rvcg0KDQpSIGFsbG93cyB5b3UgdG8gc3RvcmUgYSBjb2xsZWN0aW9uIG9mIHZhcmlhYmxlcyBvZiB0aGUgc2FtZSB0eXBlIGludG8gc29tZXRoaW5nIGNhbGxlZCBhICp2ZWN0b3IqIHdpdGggdGhlIGBjYCAoY29tYmluZSkgY29tbWFuZC4NCg0KYGBge3IsIGVjaG8gPSBULCBjb2xsYXBzZT1UfQ0KbXludW1zIDwtIGMoMSwyLDMsNCw1KQ0KY2xhc3MobXludW1zKQ0KcHJpbnQobXludW1zKQ0KDQpteW5hbWVzIDwtIGMoIm1lIiwgInlvdSIsICJ3ZSIsICJ0aGVtIiwgInRoZXkiKQ0KY2xhc3MobXluYW1lcykNCnByaW50KG15bmFtZXMpDQoNCmBgYA0KDQojIyMjIGxpc3QNCg0KUiBhbGxvd3MgeW91IHRvIHN0b3JlIGEgY29sbGVjdGlvbiBvZiB2YXJpYWJsZXMgb2YgZGlmZmVyZW50IHR5cGVzIGludG8gc29tZXRoaW5nIGNhbGxlZCBhICpsaXN0Kg0KDQpgYGB7cn0NCg0KbXlsaXN0IDwtIGxpc3QoMSwibWUiLCAyLCAid2UiLCAzKQ0KY2xhc3MobXlsaXN0KQ0KcHJpbnQobXlsaXN0KQ0KDQpgYGANCg0KIyMjIyBkYXRhLmZyYW1lDQoNClIgYWxsb3dzIHlvdSB0byBzdG9yZSBhIGNvbGxlY3Rpb24gb2YgbGlzdHMgb3IgdmVjdG9ycyBpbnRvIHNvbWV0aGluZyBjYWxsZWQgYSAqZGF0YS5mcmFtZSouDQoNClRoaW5rIG9mIHRoaXMgbGlrZSBhIHNwcmVhZHNoZWV0IHdlcmUgZWFjaCBvYnNlcnZhdGlvbiBnZXRzIG93biByb3cgYW5kIHRoZSB2YXJpYWJsZXMgYXJlIHN0b3JlZCBpbiB0aGUgY29sdW1ucy4gWW91IHVzZSB0aGUgYGRhdGEuZnJhbWUoKWAgZnVuY3Rpb24gYW5kIHBhc3MgaW4gdGhlIHZlY3RvcnMgb3IgbGlzdHMgdGhhdCBzdG9yZSB5b3VyIGRhdGEgYW5kIHRoZSBjb2x1bW4gbmFtZXMgeW91IHdhbnQgdGhlbSB0byBhcHBlYXIgYXMuDQoNCkluIHRoZSBleGFtcGxlIGJlbG93LCB0aGUgdmVjdG9yIHRoYXQgd2UgbWFkZSBlYXJsaWVyIGBteW51bXNgIGlzIGdvaW5nIHRvIGJlY29tZSB0aGUgZmlyc3QgY29sdW1uIG9mIHRoZSBuZXcgZGF0YS5mcmFtZSBhbmQgYG15bmFtZXNgIHRoZSAybmQgY29sdW1uLiBUaGVzZSAyIGNvbHVtbnMgd2lsbCBiZSBjYWxsZWQgYG51bXNgIGFuZCBgbmFtZXNgIGluIHRoZSBkYXRhLmZyYW1lLiBUaGUgd2hvbGUgdGhpbmcgaXMgc2F2ZWQgaW50byBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgYG15ZGF0YWAuDQoNCmBgYHtyfQ0KDQpteWRhdGEgPC0gZGF0YS5mcmFtZShudW1zPW15bnVtcywgbmFtZXM9bXluYW1lcykNCnByaW50KG15ZGF0YSkNCg0KYGBgDQoNCiMjIyMgbWF0cml4DQoNCkEgKiptYXRyaXgqKiBpcyBqdXN0IGxpa2UgYSBkYXRhLmZyYW1lIGV4Y2VwdCBhbGwgZWxlbWVudHMgYXJlIHRoZSBzYW1lIHR5cGUuIFdoZW4gY29uc3RydWN0aW5nIGEgKiptYXRyaXgqKiB3aXRoIHRoZSBgbWF0cml4KClgIGZ1bmN0aW9uLCB5b3UgY2FuIHNwZWNpZnkgaXRzIGRpbWVuc2lvbnMgd2l0aCB0aGUgYG5jb2xgIGFuZC9vciBgbnJvd2AgcGFyYW1ldGVycy4NCg0KYGBge3J9DQpteXZlYyA9IGMoMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYpDQpwcmludChteXZlYykNCg0KbXltYXQgPSBtYXRyaXgobXl2ZWMsIG5jb2w9NCkNCnByaW50KG15bWF0KQ0KDQoNCmBgYA0KDQojIyMjIG5hbWluZw0KDQpZb3UgY2FuIGFsc28gYXNzaWduIG5hbWVzIHRvIHRoZSByb3dzIGFuZCBjb2x1bW5zIG9mIHlvdXIgdmVjdG9ycywgbGlzdHMsIGFuZCBkYXRhLmZyYW1lcyBhbmQgbWF0cmljZXMgd2l0aCB0aGUgYG5hbWVzKClgIGZ1bmN0aW9uLiBUaGlzIGNhbiBtYWtlIHRoaW5ncyBlYXNpZXIgZm9yIHlvdSB3aGlsZSB5b3UgY29kZSBhbmQgaW50ZXJwcmV0IHlvdXIgcmVzdWx0cy4NCg0KYGBge3J9DQoNCnByaW50KG15bnVtcykNCm5hbWVzKG15bnVtcykgPC0gYygiYSIsICJiIiwgImMiLCAiZCIsICJlIikNCnByaW50KG15bnVtcykNCg0KcHJpbnQobXlkYXRhKQ0Kcm93bmFtZXMobXlkYXRhKSA8LSBjKCJmaXJzdCIsICJzZWNvbmQiLCAidGhpcmQiLCAiZm91cnRoIiwgImZpZnRoIikNCnByaW50KG15ZGF0YSkNCnJvd25hbWVzKG15ZGF0YSkNCmNvbG5hbWVzKG15ZGF0YSkNCmBgYA0KDQojIyMgVmFyaWFibGUgYWNjZXNzDQoNCiMjIyMgdmVjdG9ycyAmIGxpc3RzDQoNCk5vdyB0aGF0IHdlIGtub3cgaG93IHRvIHN0b3JlIG91ciByZXN1bHRzLCBob3cgZG8gd2UgYWNjZXNzIHRoZW0/DQoNClRoZSBlbGVtZW50cyBvZiBhICoqdmVjdG9yKiogY2FuIGJlIGFjY2Vzc2VkIHdpdGggYFtdYCAoc2luZ2xlIGJyYWNrZXRzKQ0KDQpgYGB7cn0NCm15bnVtcw0KbXludW1zWzNdDQoNCmBgYA0KDQpUaGUgZWxlbWVudHMgb2YgYSAqKmxpc3QqKiBjYW4gYmUgYWNjZXNzZWQgd2l0aCBgW1tdXWAgKGRvdWJsZSBicmFja2V0cykNCg0KYGBge3J9DQpteWxpc3QNCm15bGlzdFtbM11dDQpgYGANCg0KLSAqKmdvdGNoYToqKiBhICoqbGlzdCoqIGNhbiBiZSBhIGNvbGxlY3Rpb24gb2YgYW55dGhpbmcsIGluY2x1ZGluZyBvdGhlciBsaXN0cy4gSWYgeW91IHVzZSBzaW5nbGUgYnJhY2tldHMgYFtdYCBvbiBhIGxpc3QsIGl0IHdpbGwgcmV0dXJuIHRoZSBzcGVjaWZpZWQgZWxlbWVudCBhcyBhIGxpc3QuIFRoaXMgaXMgcHJvYmFibHkgbm90IHdoYXQgeW91IHdhbnQuDQoNCmBgYHtyfQ0KbXlsaXN0WzNdDQpjbGFzcyhteWxpc3RbM10pDQoNCm15bGlzdFtbM11dDQpjbGFzcyhteWxpc3RbWzNdXSkNCg0KYGBgDQoNCiMjIyMgZGF0YS5mcmFtZXMNCg0KWW91IGNhbiBhY2Nlc3MgZWxlbWVudHMgb2YgKipkYXRhLmZyYW1lcyoqIGJ5IHRoZWlyIHJvd3MgYW5kIGNvbHVtbnMgd2l0aCBgW2ksal1gIHNpbmdsZSBicmFja2V0cy4gVGhlIGBpYCBiZWZvcmUgdGhlIGAsYCBpcyB0aGUgcm93LCB0aGUgYGpgIGFmdGVyIHRoZSBgLGAgaXMgdGhlIGNvbHVtbi4NCg0KYGBge3J9DQpteWRhdGENCg0KIyB0aGUgNHRoIHJvdyBhbmQgMm5kIGNvbHVtbg0KbXlkYXRhWzQsMl0NCmBgYA0KDQpZb3UgY2FuIGFsc28gc3BlY2lmeSB0aGUgbG9jYXRpb24gYXMgYSBjb21iaW5hdGlvbiBvZiBudW1iZXJzIGFuZCByb3cvY29sIG5hbWVzDQoNCmBgYHtyfQ0KbXlkYXRhWyJmb3VydGgiLDJdDQpteWRhdGFbNCwibmFtZXMiXQ0KbXlkYXRhWyJmb3VydGgiLCAibmFtZXMiXQ0KYGBgDQoNCiMjIyMjIG11bHRpcGxlIGVsZW1lbnRzDQoNCklmIHlvdSB3YW50IHRvIGdldCBhbiBlbnRpcmUgcm93LCBsZWF2ZSBvZmYgdGhlIGBqYCBpbiB0aGUgYFtpLGpdYCBjb21tYW5kDQoNCmBgYHtyfQ0KI2dldCB0aGUgM3JkIHJvdw0KbXlkYXRhWzMsXQ0KYGBgDQoNCklmIHlvdSB3YW50IGFuIGVudGlyZSBjb2x1bW4sIGxlYXZlIG9mZiB0aGUgYGlgIGluIHRoZSBgW2ksal1gIGNvbW1hbmQNCg0KYGBge3J9DQojZ2V0IHRoZSAybmQgY29sdW1uDQpteWRhdGFbLDJdDQpgYGANCg0KWW91IGNhbiBhbHNvIGdldCBjb2x1bW5zIGJ5IHVzaW5nIHRoZWlyIHNwZWNpZmljIGNvbHVtbiBuYW1lcyB3aXRoIHRoZSBgJGAgb3IgYnkgdXNpbmcgYFtbXV1gIGRvdWJsZSBicmFja2V0cy4NCg0KYGBge3J9DQpteWRhdGEkbnVtcw0KbXlkYXRhW1sibnVtcyJdXQ0KYGBgDQoNCkluIGFkZGl0aW9uIHRvIHNpbmdsZSBlbGVtZW50cywgeW91IGNhbiBhbHNvIHNwZWNpZnkgcmFuZ2VzIHdoZW4gYWNjZXNzaW5nIHlvdXIgZGF0YS4gVGhlIGA6YCBjb21tYW5kIGlzIHNob3J0aGFuZCBub3RhdGlvbiBmb3IgYSByYW5nZS5cDQpUaGUgY29tbWFuZCBgYTpiYCByZXR1cm5zIGEgdmVjdG9yIHN0YXJ0aW5nIGZyb20gYGFgIGFuZCBlbmRpbmcgb24gYGJgLiBZb3UgY2FuIHVzZSB0aGlzIG5vdGF0aW9uIHdpdGhpbiB0aGUgYFtdYCBjb21tYW5kIHRvIGFjY2VzcyBjb250aWd1b3VzIHJhbmdlcyBvZiBhIGRhdGEuZnJhbWUgb3IgdmVjdG9yLg0KDQpgYGB7cn0NCjE6NQ0KNTo5DQoNCiNmaXJzdCAzIHJvd3MsIGZpcnN0IDIgY29sdW1ucw0KbXlkYXRhWzE6MywgMToyXQ0KYGBgDQoNCllvdSBjYW4gc3BlY2lmeSBub24gY29udGlndW91cyByYW5nZXMgYnkgdXNpbmcgYSBgdmVjdG9yYCB3aXRoaW4gdGhlIGBbXWAgY29tbWFuZA0KDQpgYGB7cn0NCiN0aGlzIHJldHVybnMgdGhlIGZpcnN0IDIgY29sdW1ucyBvZiB0aGUgIGZpcnN0IGFuZCB0aGlyZCByb3cNCm15ZGF0YVtjKDEsMyksIDE6Ml0NCg0KI3RoaXMgZG9lcyB0aGUgc2FtZSB0aGluZw0KbXlkYXRhW2MoImZpcnN0IiwgInRoaXJkIiksIDE6Ml0NCg0KI3doYXQgZG9lcyB0aGlzIGRvPw0KbXlkYXRhW2MoInRoaXJkIiwgImZpcnN0IiksIDE6Ml0NCmBgYA0KDQpJZiB5b3Ugd2FudCB0byByZW1vdmUgcm93cyBvciBjb2x1bW5zIHlvdSBjYW4gcHV0IGEgYC1gIChtaW51cyopKiBiZWZvcmUgdGhlIGFjY2Vzc29yIGluZGljZXMNCg0KYGBge3J9DQoNCiN0aGlzIHdpbGwgcmV0dXJuIHRoZSBmaXJzdCB0d28gY29sdW1ucyBvZiB0aGUgZGF0YS5mcmFtZSwgYnV0IHdpbGwgc2tpcCB0aGUgZmlyc3Qgcm93DQpteWRhdGFbLTEsIDE6Ml0NCiN0aGlzIHdpbGwgcmV0dXJuIHRoZSBmaXJzdCB0d28gY29sdW1ucyBvZiB0aGUgZGF0YS5mcmFtZSwgYnV0IHdpbGwgc2tpcCB0aGUgMm5kIHJvdw0KbXlkYXRhWy0yLCAxOjJdDQojdGhpcyB3aWxsIHJldHVybiB0aGUgZmlyc3QgdHdvIGNvbHVtbnMgb2YgdGhlIGRhdGEuZnJhbWUsIGJ1dCB3aWxsIHNraXAgdGhlIGZpcnN0IDIgcm93cw0KbXlkYXRhWy0oMToyKSwgMToyXQ0KYGBgDQoNCiMjIyBNYXRoZW1hdGljYWwgT3BlcmF0aW9ucw0KDQpFdmVyeSBsYW5ndWFnZSBuZWVkcyBzdXBwb3J0IGZvciBiYXNpYyBtYXRoZW1hdGljYWwgb3BlcmF0aW9ucyBsaWtlIGArYCwgYC1gLCBgKmAsIGV0Yy4gSW4gUiB3ZSBoYXZlIHN1cHBvcnQgZm9yICoqdmVjdG9yKiogb3BlcmF0aW9ucyB3aGljaCBhcHBseSB0aGUgb3BlcmF0b3IgYWNyb3NzIGV2ZXJ5IGVsZW1lbnQgb2YgYSB2ZWN0b3IuDQoNCiMjIyMgTWF0aCBvbiBhIHNpbmdsZSBudW1iZXINCg0KYGBge3J9DQp2YXIxID0gNQ0KKHZhcjEgKiAyKS8uMzg0Mg0KYGBgDQoNCiMjIyMgTWF0aCBvbiBhIHZlY3RvciBvZiBudW1iZXJzDQoNCmBgYHtyfQ0KdmVjMSA9IGMoMSwyLDMsNCw1KQ0KdmVjMiA9ICh2ZWMxICogMikvLjM4NDINCnZlYzINCg0KDQpgYGANCg0KUiBhbHNvIGhhcyBzdXBwb3J0IGZvciBvcGVyYXRpb25zIGxpa2UgYCZgICoqbG9naWNhbCBBTkQqKiwgYHxgICoqbG9naWNhbCBPUioqLCBgIWAgKipsb2dpY2FsIE5PVCoqIGFuZCBjb21wYXJpc2lvbnMgYDxgICoqbGVzcyB0aGFuKiosIGA+PWAgKipncmVhdGVyIHRoYW4gb3IgZXF1YWxzIHRvKiosIGV0Yy4uLg0KDQpgYGB7cn0NCg0KI3doaWNoIHZhbHVlcyBvZiB2ZWMyIGFyZSBsZXNzIHRoYW4gMjA/DQppeCA9IHZlYzIgPCAyMA0KI3RoZSByZXN1bHQgb2YgdGhlIGNvbXBhcmlzb25zIGlzIHNhdmVkIGluIGEgbG9naWNhbCB2ZWN0b3INCml4DQoNCmBgYA0KDQpPZnRlbiB0aW1lcyB3ZSB3aWxsIGFjY2VzcyBjZXJ0YWluIHJvd3Mgb2YgYSBkYXRhLmZyYW1lIGJhc2VkIG9uIHRoZSByZXN1bHQgb2YgYSBsb2dpY2FsIG9wZXJhdGlvbg0KDQpgYGB7cn0NCm15ZGF0YSANCiNnaXZlIG1lIGFsbCB0aGUgcm93cyB0aGF0IGFyZSBUUlVFIGZyb20gdGhlIGNvbXBhcmlzb24gYWJvdmUNCm15ZGF0YVtpeCxdDQpgYGANCg0KWW91IGNhbiBldmVuIGNhbGwgbG9naWNhbCBvcGVyYXRvcnMgKm9uIHRoZSBmbHkqIHdpdGhpbiB0aGUgYFtpLGpdYCBhY2Nlc3NvcnMuIENvbWJpbmluZyBvcGVyYXRvcnMgYW5kIGFjY2Vzc29ycyBhbGxvd3MgeW91IHRvIHBlcmZvcm0gbW9yZSBpbnRlcmVzdGluZyBhbmQgdXNlZnVsIGNvbW1hbmRzIHRoYW4ganVzdCB1c2luZyB0aGVtIGFsb25lLg0KDQpgYGB7cn0NCm15ZGF0YQ0KDQojZ2l2ZSBtZSB0aGUgYG5hbWVzYCBjb2x1bW4gb2YgdGhlIHJvd3MgdGhhdCBoYXZlIGEgYG51bWAgZ3JlYXRlciB0aGFuIDINCm15ZGF0YVtteWRhdGEkbnVtID4gMiwibmFtZXMiXQ0KYGBgDQoNCiMjIyBSZWFkaW5nL1dyaXRpbmcgZmlsZXMNCg0KKipkYXRhLmZyYW1lcyoqIGFyZSB0aGUgbW9zdCBjb21tb24gZm9ybSBvZiBkYXRhIHlvdSdsbCBiZSB1c2luZyBpbiBSLiBJZiB5b3VyIGRhdGEgY29tZXMgZnJvbSBhIHNwcmVhZHNoZWV0IHdpdGggb2JzZXJ2YXRpb25zIGFsb25nIHRoZSByb3dzIGFuZCB0aGUgdmFyaWFibGVzIGFsb25nIHRoZSBjb2x1bW5zLCB0aGVuIGl0IGlzIHZlcnkgc3RyYWlnaHRmb3J3YXJkIG1hcHBpbmcgdG8gYW4gUiBkYXRhLmZyYW1lLg0KDQpJZiB5b3Ugd2FudCB0byBzYXZlIGEgKipkYXRhLmZyYW1lKiogaW50byBhIGNvbW1hIHNlcGFyYXRlZCB2YWx1ZXMoLmNzdikgZmlsZSwgaXQgY2FuIGJlIGRvbmUgd2l0aCBgd3JpdGUuY3N2KClgLiBUaGlzIGlzIGEgZnVuY3Rpb24gdGhhdCBoYXMgMiBtYWluIGFyZ3VtZW50cw0KDQoNCi0gZmlsZTogVGhlIHBsYWNlIHlvdSB3YW50IHRvIHNhdmUgaXQNCi0geDogdGhlIGRhdGEuZnJhbWUgeW91IHdhbnQgdG8gc2F2ZQ0KDQpgYGB7cn0NCndyaXRlLmNzdihmaWxlPSJteWRhdGEuY3N2IiwgeD1teWRhdGEpDQoNCmBgYA0KDQpSZWFkaW5nIGNhbiBiZSBkb25lIGZyb20gYSAuY3N2IHdpdGggYHJlYWQuY3N2KClgLiBUaGUgbWFpbiBhcmd1bWVudCB0byB0aGlzIGZ1bmN0aW9uIGlzOg0KDQotIGZpbGU6IFRoZSBwbGFjZSB5b3Ugd2FudCB0byByZWFkIHRoZSBmaWxlIGZyb20NCg0KVGhlIGByZWFkLmNzdigpYGZ1bmN0aW9uIHJldHVybnMgdGhlIGRhdGEuZnJhbWUgdGhhdCB5b3UganVzdCByZWFkIGluLiBZb3UgbmVlZCB0byByZW1lbWJlciB0byBzYXZlIGl0IHRvIGEgdmFyaWFibGUuDQoNCmBgYHtyfQ0KbXlkYXRhMiA9IHJlYWQuY3N2KGZpbGU9Im15ZGF0YS5jc3YiKQ0KcHJpbnQobXlkYXRhMikNCmBgYA0KDQojIyMgVmlzdWFsaXphdGlvbg0KDQpSIGlzIG9uZSBvZiB0aGUgbW9zdCBwb3B1bGFyIGVudmlyb25tZW50cyBmb3IgbWFraW5nIHB1YmxpY2F0aW9uIHF1YWxpdHkgZ3JhcGhpY3MgdG9kYXkuDQoNCk1vc3QgdmlzdWFsaXphdGlvbiBwcm9jZWR1cmVzIG9wZXJhdGUgb24gYSAqZGF0YS5mcmFtZSogYW5kIGhhdmUgc29tZSB3YXkgdG8gdGVsbCBpdCB3aGljaCBjb2x1bW5zIHlvdSB3YW50IHRvIGxvb2sgYXQuDQoNCldlJ2xsIGJlIGRlYWxpbmcgd2l0aCB0aGlzIG1vcmUgaW4gdGhlIG5leHQgbGVjdHVyZXMsIGJ1dCBoZXJlIGlzIGFuIGV4YW1wbGUgb2YgaG93IHRvIGNhbGwgdGhlIGBwYWlycygpYCBmdW5jdGlvbiwgd2hpY2ggc2hvd3MgYSBzY2F0dGVycGxvdCBvZiBldmVyeSBjb21iaW5hdGlvbiBvZiB0aGUgY29sdW1ucyBpbiBhIGRhdGEuZnJhbWUuDQoNCmBgYHtyfQ0KcGFpcnMoaXJpc1ssIDE6NF0sIGNvbCA9IGlyaXMkU3BlY2llcywgcGNoPTE5KQ0KYGBgDQoNCiMjIyBGdW5jdGlvbnMNCg0KVGhpbmsgb2YgdGhlc2UgYXMgYSByZXVzYWJsZSBzZXRzIG9mIGluc3RydWN0aW9ucy4gWW91IGdpdmUgYSBmdW5jdGlvbiBpdCBhIHNldCBvZiBpbnB1dHMsIGl0IGFwcGxpZXMgYSBwcm9jZWR1cmUsIHRoZW4gZ2l2ZXMgeW91IGFuIG91dHB1dC4NCg0KSXQncyBhIHdheSBvZiBvcmdhbml6aW5nIHlvdXIgY29kZSwgc28geW91IGRvbid0IGhhdmUgdG8ga2VlcCBjb3B5L3Bhc3RpbmcgdGhlIHNhbWUgbGluZXMgb2YgY29kZSBhbmQgbWFraW5nIHNsaWdodCB2YXJpYXRpb25zIGluIHRleHQuDQoNCk1vc3Qgb2YgdGhlIHdvcmsgeW91IGRvIGluIFIgd2lsbCBiZSBkb25lIHRocm91Z2ggdXNpbmcgZnVuY3Rpb25zIGFscmVhZHkgaW1wbGVtZW50ZWQgaW4gYmFzZSBSIG9yIGJ5IHBhY2thZ2UgZGV2ZWxvcGVycyBhbmQgbG9hZGVkIHRocm91Z2ggYSBgbGlicmFyeSgpYCBjYWxsLg0KDQpGdW5jdGlvbnMgYXJlIGNhbGxlZCBieSBuYW1lLCB3aXRoIGFyZ3VtZW50cyBwYXNzZWQgYmV0d2VlbiBhIHNldCBvZiBgKClgIHBhcmVudGhlc2VzLiBUaGUgaW50ZXJlc3RpbmcgdGhpbmcgYWJvdXQgUiBpcyB0aGF0IHlvdSBjYW4gc3BlY2lmeSB0aGUgYXJndW1lbnRzIGJ5IG5hbWUgb3IgYnkgb3JkZXIsIGFuZCB0aGUgZW52aXJvbm1lbnQgY2FuIGZpZ3VyZSBvdXQgd2hpY2ggaXMgd2hpY2guDQoNCi0gSXQncyB1c3VhbGx5IGJlc3QgdG8gcGFzcyBhcmd1bWVudHMgZXhwbGljaXRseSBmb3IgY2xhcml0eS4NCg0KYGBge3J9DQpmb28gPC0gZnVuY3Rpb24oYSwgYiwgYyl7DQogIChhICsgYikvYw0KfQ0KDQpmb28oMyw2LDEpDQpmb28oYT0zLGI9NixjPTEpDQpmb28oYj02LGM9MSwgMykNCmZvbyhiPTMsYz02LCAxKQ0KDQpgYGANCg0KIyMjIH5+Q29udHJvbH5+DQoNCiMjIyMgYElmYCBzdGF0ZW1lbnQNCg0KUHJvZ3JhbW1pbmcgb2Z0ZW4gaW52b2x2ZXMgdGhlIGV4ZWN1dGlvbiBvZiBjb2RlIGRlcGVuZGVudCBvbiB0aGUgcmVzdWx0IG9mIGFuIHVwc3RyZWFtIHByb2Nlc3MuDQoNClIgaGFzIGNvbnRyb2wgb3BlcmF0aW9ucyB0aGF0IGFsbG93cyB1cyB0byBkbyB0aGlzLg0KDQpUaGUgbW9zdCBzdHJhaWdodGZvcndhcmQgdG8gdXNlIGFyZSB0aGUgKmlmL2Vsc2UqIHN0YXRlbWVudHMuDQoNCmBgYHtyfQ0KcmVzdWx0IDwtIDcNCmlmIChyZXN1bHQgPCAzKXsNCiAgICBwcmludCgieW91IHdpbiIpDQp9ZWxzZXsNCiAgICBwcmludCgieW91IGxvc2UiKQ0KfQ0KYGBgDQoNCiMjIyMgYGlmZWxzZSgpYCBmdW5jdGlvbg0KDQpZb3UgY2FuIHVzZSB0aGUgYGlmZWxzZSgpYCBmdW5jdGlvbiByZXR1cm4gYSByZXN1bHQgdGhhdCBpcyBjb25kaXRpb25hbCBvbiB0aGUgZWxlbWVudHMgb2YgYSBsb2dpY2FsIHZlY3Rvci4NCg0KLSBUaGUgZnVuY3Rpb24gdGFrZXMgMyBwYXJhbWV0ZXJzOg0KICAtIHRlc3Q6IGEgbG9naWNhbCB2ZWN0b3INCiAgLSB5ZXM6IHRoZSB2YWx1ZSB0byByZXR1cm4gZm9yIHRydWUgZWxlbWVudHMgb2YgdGVzdA0KICAtIG5vOiByZXR1cm4gdmFsdWVzIGZvciBmYWxzZQ0KDQpgYGB7cn0NCnZhbHMgPSBjKDEyMyw0NTMsMjMzLDU0LDEyMjMsMTIpDQppZmVsc2UodmFscyA8IDEwMCwgInNtYWxsIiwgImxhcmdlIikNCmBgYA0KDQojIyMgfn5Mb29wc35+DQoNCiMjIyMgZm9yDQoNCldlJ3ZlIGFscmVhZHkgc2VlbiB0aGF0IHdlIGNhbiB3cmFwIHVwIGEgc2VyaWVzIG9mIG9wZXJhdGlvbnMgaW50byBhIGZ1bmN0aW9uLlwNCldoYXQgaWYgd2Ugd2FudGVkIHRvIGFwcGx5IHRoaXMgZnVuY3Rpb24gdG8gYSAxMDAgY29sdW1ucyBpbiBhIGRhdGFzZXQ/IFdvdWxkIHdlIGhhdmUgdG8gbWFrZSAxMDAgZnVuY3Rpb24gY2FsbHM/DQoNClIgbGV0J3MgdXMgcnVuIGNvbW1hbmRzIG92ZXIgYSBzZXQgb2YgaW5wdXRzIG9yIHJhbmdlIHVzaW5nIGEgc3RydWN0dXJlIGtub3duIGFzIGEgYGZvciBsb29wYC4NCg0KYGBge3J9DQpmb3IgKGkgaW4gMToxMDApew0KICAgIGlmIChpICUlIDI9PTApew0KICAgICAgICBwcmludCgiZXZlbiIpDQogICAgfSBlbHNlew0KICAgICAgICBwcmludCgib2RkIikNCiAgICB9DQogICAgDQp9DQpgYGANCg0KIyMjIyBhcHBseQ0KDQpBbm90aGVyIGNvbW1vbiB3YXkgb2YgYXBwbHlpbmcgYSBmdW5jdGlvbiBvdmVyIHRoZSByb3dzIG9yIGNvbHVtbnMgb2YgYSBkYXRhLmZyYW1lIGlzIHdpdGggdGhlIGBhcHBseWAgZnVuY3Rpb24uDQoNCi0gYGFwcGx5YCBpcyBhIGZ1bmN0aW9uIHRoYXQgaGFzIDMgcGFyYW1ldGVycyBhcmd1bWVudHMNCiAgLSBYOiB0aGUgZGF0YS5mcmFtZSB5b3Ugd2FudCB0byB3b3JrIHdpdGgNCiAgLSBNQVJHSU46IGVpdGhlciAxIG9yIDIuDQogICAgLSAxIG1lYW5zIHlvdSB3YW50IHRvIGFwcGx5IG92ZXIgYWxsIHRoZSByb3dzLlwNCiAgICAtIDIgbWVhbnMgdG8gYXBwbHkgb3ZlciBhbGwgY29sdW1ucw0KICAtIEZVTjogdGhlIGZ1bmN0aW9uIHlvdSB3YW50IHRvIGFwcGx5DQoNCmBzdW1gIGlzIGEgYnVpbHQtaW4gZnVuY3Rpb24gdGhhdCBhZGRzIHVwIGFsbCB0aGUgZWxlbWVudHMgb2YgYSB2ZWN0b3IuIEJlbG93IHdlJ3JlIGNvbXB1dGluZyB0aGUgc3VtIG92ZXIgYWxsIHRoZSByb3dzIGFuZCBhbGwgdGhlIGNvbHVtbnMgdXNpbmcgYGFwcGx5YC4NCg0KYGBge3J9DQoNCm15bWF0DQojYXBwbHkgb3ZlciBhbGwgdGhlIHJvd3MNCmFwcGx5KG15bWF0LCAxLCBzdW0pDQojYXBwbHkgb3ZlciBhbGwgdGhlIGNvbHVtbnMNCmFwcGx5KG15bWF0LCAyLCBzdW0pDQpgYGANCg0KIyMjIyBzYXBwbHkNCg0KYSBmdW5jdGlvbiBjYW4gYmUgYXBwbGllZCB0byBlYWNoIGVsZW1lbnQgb2YgYSB2ZWN0b3Igd2l0aCB0aGUgYHNhcHBseWAgZnVuY3Rpb24uDQoNCi0gYHNhcHBseWAgaGFzIDIgYXJndW1lbnRzDQogIC0gWDogdGhlIHZlY3Rvcg0KICAtIEZVTjogdGhlIGZ1bmN0aW9uIHlvdSB3YW50IHRvIGFwcGx5DQoNCmBgYHtyfQ0KI2hlcmUgd2UncmUgbWFraW5nIGEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZSBuZWdhdGl2ZSB2YWx1ZSBvZiBpdHMgaW5wdXQuDQpzaWxseWZ1bmMxIDwtIGZ1bmN0aW9uKHZhbCl7DQogICAgLXZhbA0KfQ0KDQpteWRhdGEkbnVtcw0Kc2FwcGx5KG15ZGF0YSRudW1zLCBzaWxseWZ1bmMxKQ0KDQoNCmBgYA0KDQojIyMjIGFub255bW91cyBmdW5jdGlvbnMNCg0KSW4gYW55IG9mIHRoZSAqYXBwbHkqLXN0eWxlIGxvb3BzIHlvdSBjYW4gYWxzbyBkZWZpbmUgYSBmdW5jdGlvbiBvbiB0aGUgZmx5IHdpdGggdGhlICphbm9ueW1vdXMgZnVuY3Rpb24qIGNvbnN0cnVjdA0KDQpgYGB7cn0NCnNhcHBseShteWRhdGEkbnVtcywgZnVuY3Rpb24odmFsKXsNCiAgICAtdmFsDQp9KQ0KYGBgDQoNCiMjIyMgYnkNCg0KWW91IGNhbiBhcHBseSBhIGZ1bmN0aW9uIGFjcm9zcyBhIHNwbGl0dGluZyB2YXJpYWJsZSB3aXRoIHRoZSBgYnlgIGZ1bmN0aW9uDQoNCi0gYGJ5YCBoYXMgMyBhcmd1bWVudHMNCiAgLSBkYXRhOiB0aGUgdmFsdWVzIHlvdSB3YW50IHRvIHJ1biB0aGUgZnVuY3Rpb24gb3Zlcg0KICAtIElORElDRVM6IHRoZSBzcGxpdHRpbmcgdmFyaWFibGUNCiAgLSBGVU46IHRoZSBmdW5jdGlvbiB5b3Ugd2FudCB0byBhcHBseQ0KDQpgYGB7cn0NCm15ZGF0YQ0KYnkobXlkYXRhJG51bXMsIG15ZGF0YSRudW1zIDwgMywgc3VtKQ0KYGBgDQoNCiMjIFR5aW5nIGl0IGFsbCB0b2dldGhlciB3aXRoIGFuIGV4YW1wbGU6DQoNCkEgc3RhdGlzdGljcyBpbnN0cnVjdG9yIHdhbnRzIHRvIGtub3cgd2hldGhlciBzdHVkZW50cyB3aG8gdXNlZCBjaGF0R1BUIHNjb3JlZCBkaWZmZXJlbnRseSBvbiBhIHF1aXogdGhhbiBzdHVkZW50cyB3aG8gc3R1ZGllZCB1c2luZyByZWd1bGFyIG5vdGVzLg0KDQotIFRoZSBkYXRhc2V0IHJfdHRlc3RfNTBfb2JzZXJ2YXRpb25zLmNzdiBjb250YWlucyBxdWl6IHNjb3JlcyBmcm9tIDUwIHN0dWRlbnRzOg0KICAtIGlkOiBhIHVuaXF1ZSBpZGVudGlmaWVyIGZvciBlYWNoIHN0dWRlbnQNCiAgLSBncm91cDogd2hldGhlciB0aGUgc3R1ZGVudCB1c2VkIGNoYXRncHQgb3Igbm90ZXMNCiAgICAtIGNvbnRyb2w6IHJlZ3VsYXIgbm90ZXMNCiAgICAtIHRyZWF0bWVudDogY2hhdGdwdA0KICAtIHZhbHVlOiB0aGUgc3R1ZGVudCdzIHF1aXogc2NvcmUNCg0KVGhlIHJlc2VhcmNoIHF1ZXN0aW9uIGlzOg0KDQpJcyB0aGVyZSBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiBhdmVyYWdlIHF1aXogc2NvcmVzIGJldHdlZW4gdGhlIHR3byBncm91cHM/DQoNCiMjIFN1bW1hcnkNCg0KUiBpcyBncmVhdCBmb3IgZGF0YSBhbmFseXNpcy4NCg0KLSBwcm9zOg0KICAtIG1vcmUgc3RhdGlzdGljczogYSBwcm9wZXIgdGVzdCBpcyBhbG1vc3QgYWx3YXlzIGF2YWlsYWJsZSB0aHJvdWdoIHBhY2thZ2VzDQogIC0gbW9yZSBmZWF0dXJlczogZXNwZWNpYWxseSBmb3IgdmlzdWFsaXphdGlvbg0KICAtIHNjcmlwdGFibGU6IGF1dG9tYXRlIHJlcGV0aXRpdmUgdGFza3MgZW5zdXJlIGFuYWx5c2lzIGlzIHJlcHJvZHVjZWFibGUNCi0gY29uczoNCiAgLSBOb3QgYXMgZWFzeSBhcyB0aGUgZHJhZyZkcm9wIGFwcHMgbGlrZSBQcmlzbQ0KDQojIyBIb3cgZG8gd2UgZGVhbCB3aXRoIHRoZSBjb25zPw0KDQotIExlYXJuIHRoZSBiYXNpY3Mgb2YgdGhlIGxhbmd1YWdlDQotIFByYWN0aWNlIHdpdGggdGhlIGhvbWV3b3Jrcw0KLSBVc2UgQUkgdG8gZ2V0IGhlbHANCg0KIyMgV2hhdCBkbyB5b3UgbmVlZCB0byBsZWFybiBSPw0KDQpPbmNlIHlvdSBoYXZlIHRoZSByaWdodCBlbnZpcm9ubWVudCBzZXR1cCwgbGVhcm5pbmcgdGhlIGxhbmd1YWdlIChhbmQgc3RhdGlzdGljcykgY29tZXMgc21vb3RobHkuDQoNCi0gTG9jYWxseQ0KICAtIFRoZSBSIGNvbnNvbGUgKGluc3RhbGwgaXQpDQogIC0gQSBwbGFjZSB0byB3cml0ZSBjb2RlIChSc3R1ZGlvKQ0KICAtIEEgcGxhY2UgdG8gZ2V0IGhlbHAgd2l0aCBjb2RlIChjaGF0Z3B0KQ0KLSBDbG91ZCBiYXNlZA0KICAtIEdvb2dsZSBDb2xhYiBkb2VzIHRoaXMgYWxsIGluIG9uZSBwbGFjZS4NCg0KSXQncyBoYXJkIHRvIGZpZ3VyZSBldmVyeXRoaW5nIG91dCBvbiB5b3VyIG93biB3aXRob3V0IGRpcmVjdGlvbiBvciBoZWxwLiBUaGF0J3Mgd2hhdCB0aGlzIGZpcnN0IHdlZWsgaXMgZm9yLg0KDQojIyBUb2RheSdzIENoZWF0IFNoZWV0DQoNCiMjIyBJbnNwZWN0aW5nIG9iamVjdHMNCg0KfCBGdW5jdGlvbiAgIHwgUHVycG9zZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IEV4YW1wbGUgICAgICAgICB8DQp8LS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwNCnwgYHByaW50KHgpYCB8IERpc3BsYXlzIGFuIG9iamVjdCBpbiB0aGUgUiBjb25zb2xlLiAgfCBgcHJpbnQobXlkYXRhKWAgfA0KfCBgY2xhc3MoeClgIHwgU2hvd3MgdGhlIHR5cGUgb3IgY2xhc3Mgb2YgYW4gb2JqZWN0LiB8IGBjbGFzcyhteW51bXMpYCB8DQoNCiMjIyBDcmVhdGluZyBhbmQgb3JnYW5pemluZyBkYXRhDQoNCnwgRnVuY3Rpb24gfCBQdXJwb3NlIHwgRXhhbXBsZSB8DQp8LS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8IGBjKC4uLilgIHwgQ29tYmluZXMgdmFsdWVzIGludG8gYSB2ZWN0b3IuIHwgYGMoMSwgMiwgMylgIHwNCnwgYGxpc3QoLi4uKWAgfCBDcmVhdGVzIGEgbGlzdCB0aGF0IGNhbiBjb250YWluIGRpZmZlcmVudCB0eXBlcyBvZiBvYmplY3RzLiB8IGBsaXN0KDEsICJtZSIsIDIpYCB8DQp8IGBkYXRhLmZyYW1lKC4uLilgIHwgQ3JlYXRlcyBhIHRhYmxlLWxpa2UgZGF0YSBmcmFtZS4gfCBgZGF0YS5mcmFtZShudW1zID0gbXludW1zLCBuYW1lcyA9IG15bmFtZXMpYCB8DQp8IGBtYXRyaXgoLi4uKWAgfCBDcmVhdGVzIGEgbWF0cml4IHdob3NlIGVsZW1lbnRzIGFyZSBhbGwgdGhlIHNhbWUgdHlwZS4gfCBgbWF0cml4KG15dmVjLCBuY29sID0gNClgIHwNCnwgYG5hbWVzKHgpYCB8IEdldHMgb3IgYXNzaWducyBuYW1lcyB0byB0aGUgZWxlbWVudHMgb2YgYW4gb2JqZWN0LiB8IGBuYW1lcyhteW51bXMpIDwtIGMoImEiLCAiYiIsICJjIilgIHwNCnwgYHJvd25hbWVzKHgpYCB8IEdldHMgb3IgYXNzaWducyByb3cgbmFtZXMuIHwgYHJvd25hbWVzKG15ZGF0YSlgIHwNCnwgYGNvbG5hbWVzKHgpYCB8IEdldHMgb3IgYXNzaWducyBjb2x1bW4gbmFtZXMuIHwgYGNvbG5hbWVzKG15ZGF0YSlgIHwNCg0KIyMjIFBhY2thZ2VzDQoNCnwgRnVuY3Rpb24gfCBQdXJwb3NlIHwgRXhhbXBsZSB8DQp8LS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tfA0KfCBgaW5zdGFsbC5wYWNrYWdlcygpYCB8IERvd25sb2FkcyBhbmQgaW5zdGFsbHMgYW4gUiBwYWNrYWdlLiBUaGlzIHVzdWFsbHkgb25seSBuZWVkcyB0byBiZSBkb25lIG9uY2UuIHwgYGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKWAgfA0KfCBgbGlicmFyeSgpYCB8IExvYWRzIGFuIGluc3RhbGxlZCBwYWNrYWdlIGZvciB0aGUgY3VycmVudCBSIHNlc3Npb24uIHwgYGxpYnJhcnkoZ2dwbG90MilgIHwNCg0KIyMjIEZpbGVzIGFuZCBmb2xkZXJzDQoNCnwgRnVuY3Rpb24gfCBQdXJwb3NlIHwgRXhhbXBsZSB8DQp8LS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBgZ2V0d2QoKWAgfCBEaXNwbGF5cyBSJ3MgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4gfCBgZ2V0d2QoKWAgfA0KfCBgc2V0d2QoKWAgfCBDaGFuZ2VzIFIncyBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5LiB8IGBzZXR3ZCgiRG9jdW1lbnRzL1JfQ2xhc3MiKWAgfA0KfCBgcmVhZC5jc3YoKWAgfCBSZWFkcyBhIENTViBmaWxlIGFuZCByZXR1cm5zIGEgZGF0YSBmcmFtZS4gfCBgcmVhZC5jc3YoIm15ZGF0YS5jc3YiKWAgfA0KfCBgd3JpdGUuY3N2KClgIHwgU2F2ZXMgYSBkYXRhIGZyYW1lIGFzIGEgQ1NWIGZpbGUuIHwgYHdyaXRlLmNzdihteWRhdGEsICJteWRhdGEuY3N2IilgIHwNCg0KIyMjIFdyaXRpbmcgeW91ciBvd24gZnVuY3Rpb25zDQoNCnwgRnVuY3Rpb24gb3Igc3ludGF4IHwgUHVycG9zZSB8IEV4YW1wbGUgfA0KfC0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tfA0KfCBgZnVuY3Rpb24oLi4uKWAgfCBEZWZpbmVzIGEgcmV1c2FibGUgc2V0IG9mIGluc3RydWN0aW9ucy4gfCBgZnVuY3Rpb24oeCkgeyB4ICsgMSB9YCB8DQoNCiMjIyBDb25kaXRpb25hbCBvcGVyYXRpb25zDQoNCnwgRnVuY3Rpb24gb3Igc3RydWN0dXJlIHwgUHVycG9zZSB8IEV4YW1wbGUgfA0KfC0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBgaWZgIC8gYGVsc2VgIHwgUnVucyBkaWZmZXJlbnQgY29kZSBkZXBlbmRpbmcgb24gd2hldGhlciBhIGNvbmRpdGlvbiBpcyB0cnVlIG9yIGZhbHNlLiB8IGBpZiAoeCA+IDApIHByaW50KCJwb3NpdGl2ZSIpYCB8DQp8IGBpZmVsc2UoKWAgfCBSZXR1cm5zIGRpZmZlcmVudCB2YWx1ZXMgZm9yIHRoZSBUUlVFIGFuZCBGQUxTRSBlbGVtZW50cyBvZiBhIGxvZ2ljYWwgdmVjdG9yLiB8IGBpZmVsc2UodmFscyA8IDEwMCwgInNtYWxsIiwgImxhcmdlIilgIHwNCg0KIyMjIFJlcGVhdGluZyBvcGVyYXRpb25zDQoNCnwgRnVuY3Rpb24gb3Igc3RydWN0dXJlIHwgUHVycG9zZSB8IEV4YW1wbGUgfA0KfC0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLXwNCnwgYGZvcmAgfCBSZXBlYXRzIGNvZGUgZm9yIGVhY2ggdmFsdWUgaW4gYSBzZXF1ZW5jZSBvciBjb2xsZWN0aW9uLiB8IGBmb3IgKGkgaW4gMToxMCkgcHJpbnQoaSlgIHwNCnwgYGFwcGx5KClgIHwgQXBwbGllcyBhIGZ1bmN0aW9uIHRvIGVhY2ggcm93IG9yIGNvbHVtbiBvZiBhIG1hdHJpeCBvciBkYXRhIGZyYW1lLiB8IGBhcHBseShteW1hdCwgMSwgc3VtKWAgfA0KfCBgc2FwcGx5KClgIHwgQXBwbGllcyBhIGZ1bmN0aW9uIHRvIGVhY2ggZWxlbWVudCBhbmQgdHJpZXMgdG8gc2ltcGxpZnkgdGhlIHJlc3VsdCBpbnRvIGEgdmVjdG9yIG9yIG1hdHJpeC4gfCBgc2FwcGx5KG15bnVtcywgc3FydClgIHwNCnwgYGJ5KClgIHwgQXBwbGllcyBhIGZ1bmN0aW9uIHRvIGdyb3VwcyBkZWZpbmVkIGJ5IGFub3RoZXIgdmFyaWFibGUuIHwgYGJ5KG15ZGF0YSRudW1zLCBteWRhdGEkZ3JvdXAsIG1lYW4pYCB8DQp8IGBzdW0oKWAgfCBBZGRzIHRvZ2V0aGVyIHRoZSB2YWx1ZXMgaW4gYSB2ZWN0b3IuIHwgYHN1bShteW51bXMpYCB8DQoNCiMjIyBJbXBvcnRhbnQgaW5kZXhpbmcgc3ludGF4DQoNClRoZXNlIGFyZSBvcGVyYXRvcnMgcmF0aGVyIHRoYW4gZnVuY3Rpb25zLCBidXQgdGhleSBhcmUgY29tbW9ubHkgdXNlZCB0aHJvdWdob3V0IFIgY29kZS4NCg0KfCBTeW50YXggfCBQdXJwb3NlIHwgRXhhbXBsZSB8DQp8LS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tfA0KfCBgW2ldYCB8IFNlbGVjdHMgb25lIG9yIG1vcmUgZWxlbWVudHMuIHwgYG15bnVtc1szXWAgfA0KfCBgW1tpXV1gIHwgRXh0cmFjdHMgYSBzaW5nbGUgZWxlbWVudCwgY29tbW9ubHkgZnJvbSBhIGxpc3QuIHwgYG15bGlzdFtbM11dYCB8DQp8IGBbaSwgal1gIHwgU2VsZWN0cyByb3dzIGFuZCBjb2x1bW5zIGZyb20gYSBkYXRhIGZyYW1lIG9yIG1hdHJpeC4gfCBgbXlkYXRhWzQsIDJdYCB8DQp8IGAkYCB8IFNlbGVjdHMgYSBkYXRhLWZyYW1lIGNvbHVtbiBieSBuYW1lLiB8IGBteWRhdGEkbnVtc2AgfA0KfCBgOmAgfCBDcmVhdGVzIGEgY29uc2VjdXRpdmUgc2VxdWVuY2Ugb2YgbnVtYmVycy4gfCBgMToxMGAgfA0KfCBgPC1gIHwgQXNzaWducyBhIHZhbHVlIHRvIGEgdmFyaWFibGUuIHwgYHggPC0gNWAgfA0KDQojIyMgQ29tbW9uIGxvZ2ljYWwgb3BlcmF0b3JzDQoNCnwgT3BlcmF0b3IgfCBNZWFuaW5nICAgICAgICAgICAgICAgICAgfCBFeGFtcGxlICAgICAgICAgICAgICB8DQp8LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBgPGAgICAgICB8IExlc3MgdGhhbiAgICAgICAgICAgICAgICB8IGB4IDwgMTBgICAgICAgICAgICAgIHwNCnwgYD5gICAgICAgfCBHcmVhdGVyIHRoYW4gICAgICAgICAgICAgfCBgeCA+IDEwYCAgICAgICAgICAgICB8DQp8IGA8PWAgICAgIHwgTGVzcyB0aGFuIG9yIGVxdWFsIHRvICAgIHwgYHggPD0gMTBgICAgICAgICAgICAgfA0KfCBgPj1gICAgICB8IEdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB8IGB4ID49IDEwYCAgICAgICAgICAgIHwNCnwgYD09YCAgICAgfCBFcXVhbCB0byAgICAgICAgICAgICAgICAgfCBgeCA9PSAxMGAgICAgICAgICAgICB8DQp8IGAhPWAgICAgIHwgTm90IGVxdWFsIHRvICAgICAgICAgICAgIHwgYHggIT0gMTBgICAgICAgICAgICAgfA0KfCBgJmAgICAgICB8IExvZ2ljYWwgQU5EICAgICAgICAgICAgICB8IGAoeCA+IDApICYgKHggPCAxMClgIHwNCnwgYHxgICAgICAgfCBMb2dpY2FsIE9SICAgICAgICAgICAgICAgfCBgKHggPCAwKSB8ICh4ID4gMTApYCB8DQp8IGAhYCAgICAgIHwgTG9naWNhbCBOT1QgICAgICAgICAgICAgIHwgYCFpcy5uYSh4KWAgICAgICAgICAgfA0K