R is a programming language and software environment for statistical analysis, graphics representation and reporting. R was created by Ross Ihaka and Robert Gentleman at the University of Auckland, New Zealand, and is currently developed by the R Development Core Team. R is freely available under the GNU General Public License, and pre-compiled binary versions are provided for various operating systems like Linux, Windows and Mac. This programming language was named R, based on the first letter of first name of the two R authors (Robert Gentleman and Ross Ihaka), and partly a play on the name of the Bell Labs Language S.
Audience
This tutorial is designed for software programmers, statisticians and data miners who are looking forward for developing statistical software using R programming. If you are trying to understand the R programming language as a beginner, this tutorial will give you enough understanding on almost all the concepts of the language from where you can take yourself to higher levels of expertise.
Prerequisites
Before proceeding with this tutorial, you should have a basic understanding of Computer Programming terminologies. A basic understanding of any of the programming languages will help you in understanding the R programming concepts and move fast on the learning track.
Overview
R is a programming language and software environment for statistical analysis, graphics representation and reporting. R was created by Ross Ihaka and Robert Gentleman at the University of Auckland, New Zealand, and is currently developed by the R Development Core Team.
The core of R is an interpreted computer language which allows branching and looping as well as modular programming using functions. R allows integration with the procedures written in the C, C++, .Net, Python or FORTRAN languages for efficiency.
R is freely available under the GNU General Public License, and pre-compiled binary versions are provided for various operating systems like Linux, Windows and Mac.
R is free software distributed under a GNU-style copy left, and an official part of the GNU project called GNU S.
Evolution of R
R was initially written by Ross Ihaka and Robert Gentleman at the Department of Statistics of the University of Auckland in Auckland, New Zealand. R made its first appearance in 1993.
A large group of individuals has contributed to R by sending code and bug reports.
Since mid-1997 there has been a core group (the "R Core Team") who can modify the R source code archive.
Features of R
As stated earlier, R is a programming language and software environment for statistical analysis, graphics representation and reporting. The following are the important features of R ???
R is a well-developed, simple and effective programming language which includes conditionals, loops, user defined recursive functions and input and output facilities.
R has an effective data handling and storage facility,
R provides a suite of operators for calculations on arrays, lists, vectors and matrices.
R provides a large, coherent and integrated collection of tools for data analysis.
R provides graphical facilities for data analysis and display either directly at the computer or printing at the papers.
As a conclusion, R is world's most widely used statistics programming language. It's the # 1 choice of data scientists and supported by a vibrant and talented community of contributors. R is taught in universities and deployed in mission critical business applications. This tutorial will teach you R programming along with suitable examples in simple and easy steps.
Let’s get started.
/——————————————————————————/ ENVIRONMENT SETUP /——————————————————————————/
You can download the Windows installer version of R from R-3.2.2 for Windows (32/64 bit) and save it in a local directory.
As it is a Windows installer (.exe) with a name "R-version-win.exe". You can just double click and run the installer accepting the default settings. If your Windows is 32-bit version, it installs the 32-bit version. But if your windows is 64-bit, then it installs both the 32-bit and 64-bit versions.
After installation you can locate the icon to run the Program in a directory structure "R\R3.2.2\bin\i386\Rgui.exe" under the Windows Program Files. Clicking this icon brings up the R-GUI which is the R console to do R Programming.
This will show:
R version 3.5.1 (2018-07-02) -- "Feather Spray"
Copyright (C) 2018 The R Foundation for Statistical Computing
Platform: x86_64-w64-mingw32/x64 (64-bit)
R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.
R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.
Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.
>
/———————————————————————————–/ BASIC SYNTAX /———————————————————————————–/
As a convention, we will start learning R programming by writing a "Hello, World!" program. Depending on the needs, you can program either at R command prompt or you can use an R script file to write your program. Let's check both one by one.
R Command Prompt
Once you have R environment setup, then it's easy to start your R command prompt by just typing the following command at your command prompt:
This will launch R interpreter and you will get a prompt > where you can start typing your program as follows:
myString <- "Hello, World!"
print ( myString)
[1] "Hello, World!"
Comments
Comments are like helping text in your R program and they are ignored by the interpreter while executing your actual program. Single comment is written using # in the beginning of the statement as follows:
# My first program in R Programming
/————————————————————————————-/ DATA TYPES /————————————————————————————-/
Generally, while doing programming in any programming language, you need to use various variables to store various information. Variables are nothing but reserved memory locations to store values. This means that, when you create a variable you reserve some space in memory.
You may like to store information of various data types like character, wide character, integer, floating point, double floating point, Boolean etc. Based on the data type of a variable, the operating system allocates memory and decides what can be stored in the reserved memory.
Topics:
Logical, Numeric, Integer, Complex, character, Raw
# Logical
# Example: TRUE OR FALSE
v <- TRUE
print(class(v))
[1] "logical"
# Numeric
# Example: 12.3, 5, 999
v <- 23.5
print(class(v))
[1] "numeric"
# Integer
# Example: 2L, 34L, 0L
v <- 2L
print(class(v))
[1] "integer"
# Complex
# Example: 3 + 2i
v <- 2+5i
print(class(v))
[1] "complex"
# Character
# Example: 'a' , '"good", "TRUE", '23.4'
v <- "TRUE"
print(class(v))
[1] "character"
# Raw
# Example: "Hello" is stored as 48 65 6c 6c 6f
v <- charToRaw("Hello")
print(class(v))
[1] "raw"
Other topics:
Vectors, Lists, Matrices, Arrays, Factors, Data Frames
Vectors
When you want to create vector with more than one element, you should use c() function which means to combine the elements into a vector.
# Create a vector.
apple <- c('red','green',"yellow")
print(apple)
[1] "red" "green" "yellow"
# Get the class of the vector.
print(class(apple))
[1] "character"
Lists
A list is an R-object which can contain many different types of elements inside it like vectors, functions and even another list inside it.
# Create a list.
list1 <- list(c(2,5,3),21.3,sin)
# Print the list.
print(list1)
[[1]]
[1] 2 5 3
[[2]]
[1] 21.3
[[3]]
function (x) .Primitive("sin")
Matrices
A matrix is a two-dimensional rectangular data set. It can be created using a vector input to the matrix function.
# Create a matrix.
M = matrix( c('a','a','b','c','b','a'), nrow = 2, ncol = 3, byrow = TRUE)
print(M)
[,1] [,2] [,3]
[1,] "a" "a" "b"
[2,] "c" "b" "a"
Arrays
While matrices are confined to two dimensions, arrays can be of any number of dimensions. The array function takes a dim attribute which creates the required number of dimension. In the below example we create an array with two elements which are 3x3 matrices each.
# Create an array.
a <- array(c('green','yellow'),dim = c(3,3,2))
print(a)
, , 1
[,1] [,2] [,3]
[1,] "green" "yellow" "green"
[2,] "yellow" "green" "yellow"
[3,] "green" "yellow" "green"
, , 2
[,1] [,2] [,3]
[1,] "yellow" "green" "yellow"
[2,] "green" "yellow" "green"
[3,] "yellow" "green" "yellow"
Factors
Factors are the r-objects which are created using a vector. It stores the vector along with the distinct values of the elements in the vector as labels. The labels are always character irrespective of whether it is numeric or character or Boolean etc. in the input vector. They are useful in statistical modeling.
Factors are created using the factor() function. The nlevels functions gives the count of levels.
# Create a vector.
apple_colors <- c('green','green','yellow','red','red','red','green')
# Create a factor object.
factor_apple <- factor(apple_colors)
# Print the factor.
print(factor_apple)
[1] green green yellow red red red green
Levels: green red yellow
print(nlevels(factor_apple))
[1] 3
Data Frames
Data frames are tabular data objects. Unlike a matrix in data frame each column can contain different modes of data. The first column can be numeric while the second column can be character and third column can be logical. It is a list of vectors of equal length.
Data Frames are created using the data.frame() function.
# Create the data frame.
BMI <- data.frame(
gender = c("Male", "Male","Female"),
height = c(152, 171.5, 165),
weight = c(81,93, 78),
Age = c(42,38,26)
)
print(BMI)
/————————————————————————————–/ VARIABLES /————————————————————————————–/
A variable provides us with named storage that our programs can manipulate. A variable in R can store an atomic vector, group of atomic vectors or a combination of many Robjects. A valid variable name consists of letters, numbers and the dot or underline characters. The variable name starts with a letter or the dot not followed by a number.
Variable Assignment
The variables can be assigned values using leftward, rightward and equal to operator. The values of the variables can be printed using print() or cat() function. The cat() function combines multiple items into a continuous print output.
# Assignment using equal operator.
var.1 = c(0,1,2,3)
# Assignment using leftward operator.
var.2 <- c("learn","R")
# Assignment using rightward operator.
c(TRUE,1) -> var.3
print(var.1)
[1] 0 1 2 3
cat ("var.1 is ", var.1 ,"\n")
var.1 is 0 1 2 3
cat ("var.2 is ", var.2 ,"\n")
var.2 is learn R
cat ("var.3 is ", var.3 ,"\n")
var.3 is 1 1
Note: The vector c(TRUE,1) has a mix of logical and numeric class. So logical class is coerced to numeric class making TRUE as 1.
Data Type of a Variable
In R, a variable itself is not declared of any data type, rather it gets the data type of the R - object assigned to it. So R is called a dynamically typed language, which means that we can change a variable's data type of the same variable again and again when using it in a program.
var_x <- "Hello"
cat("The class of var_x is ",class(var_x),"\n")
The class of var_x is character
var_x <- 34.5
cat(" Now the class of var_x is ",class(var_x),"\n")
Now the class of var_x is numeric
var_x <- 27L
cat(" Next the class of var_x becomes ",class(var_x),"\n")
Next the class of var_x becomes integer
Finding Variables
To know all the variables currently available in the workspace we use the ls() function. Also the ls() function can use patterns to match the variable names.
print(ls())
[1] "a" "apple" "apple_colors" "BMI" "factor_apple" "list1" "M"
[8] "myString" "t" "v" "var.1" "var.2" "var.3" "var_x"
Deleting Variables
Variables can be deleted by using the rm() function. Below we delete the variable var.3. On printing the value of the variable error is thrown.
rm(var.3)
print(var.3)
Error in print(var.3) : object 'var.3' not found
All the variables can be deleted by using the rm() and ls() function together.
rm(list = ls())
print(ls())
character(0)
/—————————————————————————————/ Operators /—————————————————————————————/
An operator is a symbol that tells the compiler to perform specific mathematical or logical manipulations. R language is rich in built-in operators and provides following types of operators.
Types of Operators
We have the following types of operators in R programming:
Arithmetic Operators
Relational Operators
Logical Operators
Assignment Operators
Miscellaneous Operators
Arithmetic Operators
Adds two vectors
Operator: +
v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v+t)
[1] 10.0 8.5 10.0
Subtracts second vector from the first
Operator: -
v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v-t)
[1] -6.0 2.5 2.0
Multiplies both vectors
Operator: *
v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v*t)
[1] 16.0 16.5 24.0
Divide the first vector with the second
Operator: /
v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v/t)
[1] 0.250000 1.833333 1.500000
Give the remainder of the first vector with the second
Operator: %%
v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v%%t)
[1] 2.0 2.5 2.0
The result of division of first vector with second (quotient)
Operator: %/%
v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v%/%t)
[1] 0 1 1
The first vector raised to the exponent of second vector
Operator: ^
v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v^t)
[1] 256.000 166.375 1296.000
Relational Operators
Each element of the first vector is compared with the corresponding element of the second vector. The result of comparison is a Boolean value.
Operator: >
Checks if each element of the first vector is greater than the corresponding element of the second vector.
v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v>t)
[1] FALSE TRUE FALSE FALSE
Operator: <
Checks if each element of the first vector is less than the corresponding element of the second vector.
v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v < t)
[1] TRUE FALSE TRUE FALSE
Operator: ==
Checks if each element of the first vector is equal to the corresponding element of the second vector.
v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v == t)
[1] FALSE FALSE FALSE TRUE
Operator: <=
Checks if each element of the first vector is less than or equal to the corresponding element of the second vector.
v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v<=t)
[1] TRUE FALSE TRUE TRUE
Operator: >=
Checks if each element of the first vector is greater than or equal to the corresponding element of the second vector.
v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v>=t)
[1] FALSE TRUE FALSE TRUE
Operator: !=
Checks if each element of the first vector is unequal to the corresponding element of the second vector.
v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v!=t)
[1] TRUE TRUE TRUE FALSE
Logical Operators
Following table shows the logical operators supported by R language. It is applicable only to vectors of type logical, numeric or complex. All numbers greater than 1 are considered as logical value TRUE.
Each element of the first vector is compared with the corresponding element of the second vector. The result of comparison is a Boolean value.
Operator: &
It is called Element-wise Logical AND operator. It combines each element of the first vector with the corresponding element of the second vector and gives a output TRUE if both the elements are TRUE.
v <- c(3,1,TRUE,2+3i)
t <- c(4,1,FALSE,2+3i)
print(v&t)
[1] TRUE TRUE FALSE TRUE
Operator: |
It is called Element-wise Logical OR operator. It combines each element of the first vector with the corresponding element of the second vector and gives a output TRUE if one the elements is TRUE.
v <- c(3,0,TRUE,2+2i)
t <- c(4,0,FALSE,2+3i)
print(v|t)
[1] TRUE FALSE TRUE TRUE
Operator: !
It is called Logical NOT operator. Takes each element of the vector and gives the opposite logical value.
v <- c(3,0,TRUE,2+2i)
print(!v)
[1] FALSE TRUE FALSE FALSE
The logical operator && and || considers only the first element of the vectors and give a vector of single element as output.
Operator: &&
Called Logical AND operator. Takes first element of both the vectors and gives the TRUE only if both are TRUE.
v <- c(3,0,TRUE,2+2i)
t <- c(1,3,TRUE,2+3i)
print(v&&t)
[1] TRUE
Operator: !!
Called Logical OR operator. Takes first element of both the vectors and gives the TRUE if one of them is TRUE.
v <- c(0,0,TRUE,2+2i)
t <- c(0,3,TRUE,2+3i)
print(v||t)
[1] FALSE
Assignment Operators
These operators are used to assign values to vectors.
Operator: <??? or = or <<???
Called Left Assignment
v1 <- c(3,1,TRUE,2+3i)
v2 <<- c(3,1,TRUE,2+3i)
v3 = c(3,1,TRUE,2+3i)
print(v1)
[1] 3+0i 1+0i 1+0i 2+3i
print(v2)
[1] 3+0i 1+0i 1+0i 2+3i
print(v3)
[1] 3+0i 1+0i 1+0i 2+3i
Operator: -> or ->>
Called Right Assignment
c(3,1,TRUE,2+3i) -> v1
c(3,1,TRUE,2+3i) ->> v2
print(v1)
[1] 3+0i 1+0i 1+0i 2+3i
print(v2)
[1] 3+0i 1+0i 1+0i 2+3i
Miscellaneous Operators
These operators are used to for specific purpose and not general mathematical or logical computation.
Operator: :
Colon operator. It creates the series of numbers in sequence for a vector.
v <- 2:8
print(v)
[1] 2 3 4 5 6 7 8
Operator: %in%
This operator is used to identify if an element belongs to a vector.
v1 <- 8
v2 <- 12
t <- 1:10
print(v1 %in% t)
[1] TRUE
print(v2 %in% t)
[1] FALSE
Operator: %*%
This operator is used to multiply a matrix with its transpose.
M = matrix( c(2,6,5,1,10,4), nrow = 2,ncol = 3,byrow = TRUE)
t = M %*% t(M)
print(t)
[,1] [,2]
[1,] 65 82
[2,] 82 117
/—————————————————————————————/ Operators /—————————————————————————————/
Decision making structures require the programmer to specify one or more conditions to be evaluated or tested by the program, along with a statement or statements to be executed if the condition is determined to be true, and optionally, other statements to be executed if the condition is determined to be false.
If Statement
An if statement consists of a Boolean expression followed by one or more statements.
The basic syntax for creating an if statement in R is:
if(boolean_expression) {
// statement(s) will execute if the boolean expression is true.
}
x <- 30L
if(is.integer(x)) {
print("X is an Integer")
}
[1] "X is an Integer"
If…Else Statement
An if statement can be followed by an optional else statement which executes when the boolean expression is false.
The basic syntax for creating an if...else statement in R is:
if(boolean_expression) {
// statement(s) will execute if the boolean expression is true.
} else {
// statement(s) will execute if the boolean expression is false.
}
x <- c("what","is","truth")
if("Truth" %in% x) {
print("Truth is found")
} else {
print("Truth is not found")
}
[1] "Truth is not found"
The if…else if…else Statement
The basic syntax for creating an if...else if...else statement in R is:
if(boolean_expression 1) {
// Executes when the boolean expression 1 is true.
} else if( boolean_expression 2) {
// Executes when the boolean expression 2 is true.
} else if( boolean_expression 3) {
// Executes when the boolean expression 3 is true.
} else {
// executes when none of the above condition is true.
}
x <- c("what","is","truth")
if("Truth" %in% x) {
print("Truth is found the first time")
} else if ("truth" %in% x) {
print("truth is found the second time")
} else {
print("No truth found")
}
[1] "truth is found the second time"
Switch Statement
A switch statement allows a variable to be tested for equality against a list of values. Each value is called a case, and the variable being switched on is checked for each case.
The basic syntax for creating a switch statement in R is:
switch(expression, case1, case2, case3....)
x <- switch(
3,
"first",
"second",
"third",
"fourth"
)
print(x)
[1] "third"
Loops
A loop statement allows us to execute a statement or group of statements multiple times and the following is the general form of a loop statement in most of the programming languages:
Repeat Loop
The Repeat loop executes the same code again and again until a stop condition is met.
The basic syntax for creating a repeat loop in R is:
repeat {
commands
if(condition) {
break
}
}
v <- c("Hello","loop")
cnt <- 2
repeat {
print(v)
cnt <- cnt+1
if(cnt > 5) {
break
}
}
[1] "Hello" "loop"
[1] "Hello" "loop"
[1] "Hello" "loop"
[1] "Hello" "loop"
While Loop
The While loop executes the same code again and again until a stop condition is met.
The basic syntax for creating a while loop in R is:
while (test_expression) {
statement
}
v <- c("Hello","while loop")
cnt <- 2
while (cnt < 7) {
print(v)
cnt = cnt + 1
}
[1] "Hello" "while loop"
[1] "Hello" "while loop"
[1] "Hello" "while loop"
[1] "Hello" "while loop"
[1] "Hello" "while loop"
For Loop
A For loop is a repetition control structure that allows you to efficiently write a loop that needs to execute a specific number of times.
The basic syntax for creating a for loop statement in R is:
for (value in vector) {
statements
}
v <- LETTERS[1:4]
for ( i in v) {
print(i)
}
[1] "A"
[1] "B"
[1] "C"
[1] "D"
Loop Control Statements
Loop control statements change execution from its normal sequence. When execution leaves a scope, all automatic objects that were created in that scope are destroyed.
Break Statement
The break statement in R programming language has the following two usages:
When the break statement is encountered inside a loop, the loop is immediately terminated and program control resumes at the next statement following the loop.
It can be used to terminate a case in the switch statement (covered in the next chapter).
The basic syntax for creating a break statement in R is:
break
v <- c("Hello","loop")
cnt <- 2
repeat {
print(v)
cnt <- cnt + 1
if(cnt > 5) {
break
}
}
[1] "Hello" "loop"
[1] "Hello" "loop"
[1] "Hello" "loop"
[1] "Hello" "loop"
Next Statement
The next statement in R programming language is useful when we want to skip the current iteration of a loop without terminating it. On encountering next, the R parser skips further evaluation and starts next iteration of the loop.
The basic syntax for creating a next statement in R is:
next
v <- LETTERS[1:6]
for ( i in v) {
if (i == "D") {
next
}
print(i)
}
[1] "A"
[1] "B"
[1] "C"
[1] "E"
[1] "F"
LS0tDQp0aXRsZTogIlIgVHV0b3JpYWwiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KICAgIFIgaXMgYSBwcm9ncmFtbWluZyBsYW5ndWFnZSBhbmQgc29mdHdhcmUgZW52aXJvbm1lbnQgZm9yIHN0YXRpc3RpY2FsIGFuYWx5c2lzLCBncmFwaGljcyByZXByZXNlbnRhdGlvbiBhbmQgcmVwb3J0aW5nLiBSIHdhcyBjcmVhdGVkIGJ5IFJvc3MgSWhha2EgYW5kIFJvYmVydCBHZW50bGVtYW4gYXQgdGhlIFVuaXZlcnNpdHkgb2YgQXVja2xhbmQsIE5ldyBaZWFsYW5kLCBhbmQgaXMgY3VycmVudGx5IGRldmVsb3BlZCBieSB0aGUgUiBEZXZlbG9wbWVudCBDb3JlIFRlYW0uIFIgaXMgZnJlZWx5IGF2YWlsYWJsZSB1bmRlciB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCBwcmUtY29tcGlsZWQgYmluYXJ5IHZlcnNpb25zIGFyZSBwcm92aWRlZCBmb3IgdmFyaW91cyBvcGVyYXRpbmcgc3lzdGVtcyBsaWtlIExpbnV4LCBXaW5kb3dzIGFuZCBNYWMuIFRoaXMgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2Ugd2FzIG5hbWVkIFIsIGJhc2VkIG9uIHRoZSBmaXJzdCBsZXR0ZXIgb2YgZmlyc3QgbmFtZSBvZiB0aGUgdHdvIFIgYXV0aG9ycyAoUm9iZXJ0IEdlbnRsZW1hbiBhbmQgUm9zcyBJaGFrYSksIGFuZCBwYXJ0bHkgYSBwbGF5IG9uIHRoZSBuYW1lIG9mIHRoZSBCZWxsIExhYnMgTGFuZ3VhZ2UgUy4NCiAgICANCkF1ZGllbmNlDQoNCiAgICBUaGlzIHR1dG9yaWFsIGlzIGRlc2lnbmVkIGZvciBzb2Z0d2FyZSBwcm9ncmFtbWVycywgc3RhdGlzdGljaWFucyBhbmQgZGF0YSBtaW5lcnMgd2hvIGFyZSBsb29raW5nIGZvcndhcmQgZm9yIGRldmVsb3Bpbmcgc3RhdGlzdGljYWwgc29mdHdhcmUgdXNpbmcgUiBwcm9ncmFtbWluZy4gSWYgeW91IGFyZSB0cnlpbmcgdG8gdW5kZXJzdGFuZCB0aGUgUiBwcm9ncmFtbWluZyBsYW5ndWFnZSBhcyBhIGJlZ2lubmVyLCB0aGlzIHR1dG9yaWFsIHdpbGwgZ2l2ZSB5b3UgZW5vdWdoIHVuZGVyc3RhbmRpbmcgb24gYWxtb3N0IGFsbCB0aGUgY29uY2VwdHMgb2YgdGhlIGxhbmd1YWdlIGZyb20gd2hlcmUgeW91IGNhbiB0YWtlIHlvdXJzZWxmIHRvIGhpZ2hlciBsZXZlbHMgb2YgZXhwZXJ0aXNlLg0KICAgIA0KUHJlcmVxdWlzaXRlcw0KDQogICAgQmVmb3JlIHByb2NlZWRpbmcgd2l0aCB0aGlzIHR1dG9yaWFsLCB5b3Ugc2hvdWxkIGhhdmUgYSBiYXNpYyB1bmRlcnN0YW5kaW5nIG9mIENvbXB1dGVyIFByb2dyYW1taW5nIHRlcm1pbm9sb2dpZXMuIEEgYmFzaWMgdW5kZXJzdGFuZGluZyBvZiBhbnkgb2YgdGhlIHByb2dyYW1taW5nIGxhbmd1YWdlcyB3aWxsIGhlbHAgeW91IGluIHVuZGVyc3RhbmRpbmcgdGhlIFIgcHJvZ3JhbW1pbmcgY29uY2VwdHMgYW5kIG1vdmUgZmFzdCBvbiB0aGUgbGVhcm5pbmcgdHJhY2suDQoNCk92ZXJ2aWV3DQoNCiAgICBSIGlzIGEgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgYW5kIHNvZnR3YXJlIGVudmlyb25tZW50IGZvciBzdGF0aXN0aWNhbCBhbmFseXNpcywgZ3JhcGhpY3MgcmVwcmVzZW50YXRpb24gYW5kIHJlcG9ydGluZy4gUiB3YXMgY3JlYXRlZCBieSBSb3NzIEloYWthIGFuZCBSb2JlcnQgR2VudGxlbWFuIGF0IHRoZSBVbml2ZXJzaXR5IG9mIEF1Y2tsYW5kLCBOZXcgWmVhbGFuZCwgYW5kIGlzIGN1cnJlbnRseSBkZXZlbG9wZWQgYnkgdGhlIFIgRGV2ZWxvcG1lbnQgQ29yZSBUZWFtLg0KDQogICAgVGhlIGNvcmUgb2YgUiBpcyBhbiBpbnRlcnByZXRlZCBjb21wdXRlciBsYW5ndWFnZSB3aGljaCBhbGxvd3MgYnJhbmNoaW5nIGFuZCBsb29waW5nIGFzIHdlbGwgYXMgbW9kdWxhciBwcm9ncmFtbWluZyB1c2luZyBmdW5jdGlvbnMuIFIgYWxsb3dzIGludGVncmF0aW9uIHdpdGggdGhlIHByb2NlZHVyZXMgd3JpdHRlbiBpbiB0aGUgQywgQysrLCAuTmV0LCBQeXRob24gb3IgRk9SVFJBTiBsYW5ndWFnZXMgZm9yIGVmZmljaWVuY3kuDQoNCiAgICBSIGlzIGZyZWVseSBhdmFpbGFibGUgdW5kZXIgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlLCBhbmQgcHJlLWNvbXBpbGVkIGJpbmFyeSB2ZXJzaW9ucyBhcmUgcHJvdmlkZWQgZm9yIHZhcmlvdXMgb3BlcmF0aW5nIHN5c3RlbXMgbGlrZSBMaW51eCwgV2luZG93cyBhbmQgTWFjLg0KDQogICAgUiBpcyBmcmVlIHNvZnR3YXJlIGRpc3RyaWJ1dGVkIHVuZGVyIGEgR05VLXN0eWxlIGNvcHkgbGVmdCwgYW5kIGFuIG9mZmljaWFsIHBhcnQgb2YgdGhlIEdOVSBwcm9qZWN0IGNhbGxlZCBHTlUgUy4NCiAgICANCkV2b2x1dGlvbiBvZiBSDQoNCiAgICBSIHdhcyBpbml0aWFsbHkgd3JpdHRlbiBieSBSb3NzIEloYWthIGFuZCBSb2JlcnQgR2VudGxlbWFuIGF0IHRoZSBEZXBhcnRtZW50IG9mIFN0YXRpc3RpY3Mgb2YgdGhlIFVuaXZlcnNpdHkgb2YgQXVja2xhbmQgaW4gQXVja2xhbmQsIE5ldyBaZWFsYW5kLiBSIG1hZGUgaXRzIGZpcnN0IGFwcGVhcmFuY2UgaW4gMTk5My4NCg0KICAgIEEgbGFyZ2UgZ3JvdXAgb2YgaW5kaXZpZHVhbHMgaGFzIGNvbnRyaWJ1dGVkIHRvIFIgYnkgc2VuZGluZyBjb2RlIGFuZCBidWcgcmVwb3J0cy4NCg0KICAgIFNpbmNlIG1pZC0xOTk3IHRoZXJlIGhhcyBiZWVuIGEgY29yZSBncm91cCAodGhlICJSIENvcmUgVGVhbSIpIHdobyBjYW4gbW9kaWZ5IHRoZSBSIHNvdXJjZSBjb2RlIGFyY2hpdmUuDQoNCkZlYXR1cmVzIG9mIFINCg0KICAgIEFzIHN0YXRlZCBlYXJsaWVyLCBSIGlzIGEgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgYW5kIHNvZnR3YXJlIGVudmlyb25tZW50IGZvciBzdGF0aXN0aWNhbCBhbmFseXNpcywgZ3JhcGhpY3MgcmVwcmVzZW50YXRpb24gYW5kIHJlcG9ydGluZy4gVGhlIGZvbGxvd2luZyBhcmUgdGhlIGltcG9ydGFudCBmZWF0dXJlcyBvZiBSID8/Pw0KDQogICAgICBSIGlzIGEgd2VsbC1kZXZlbG9wZWQsIHNpbXBsZSBhbmQgZWZmZWN0aXZlIHByb2dyYW1taW5nIGxhbmd1YWdlIHdoaWNoIGluY2x1ZGVzIGNvbmRpdGlvbmFscywgbG9vcHMsIHVzZXIgZGVmaW5lZCByZWN1cnNpdmUgZnVuY3Rpb25zIGFuZCBpbnB1dCBhbmQgb3V0cHV0IGZhY2lsaXRpZXMuDQoNCiAgICAgIFIgaGFzIGFuIGVmZmVjdGl2ZSBkYXRhIGhhbmRsaW5nIGFuZCBzdG9yYWdlIGZhY2lsaXR5LA0KDQogICAgICBSIHByb3ZpZGVzIGEgc3VpdGUgb2Ygb3BlcmF0b3JzIGZvciBjYWxjdWxhdGlvbnMgb24gYXJyYXlzLCBsaXN0cywgdmVjdG9ycyBhbmQgbWF0cmljZXMuDQoNCiAgICAgIFIgcHJvdmlkZXMgYSBsYXJnZSwgY29oZXJlbnQgYW5kIGludGVncmF0ZWQgY29sbGVjdGlvbiBvZiB0b29scyBmb3IgZGF0YSBhbmFseXNpcy4NCg0KICAgICAgUiBwcm92aWRlcyBncmFwaGljYWwgZmFjaWxpdGllcyBmb3IgZGF0YSBhbmFseXNpcyBhbmQgZGlzcGxheSBlaXRoZXIgZGlyZWN0bHkgYXQgdGhlIGNvbXB1dGVyIG9yIHByaW50aW5nIGF0IHRoZSBwYXBlcnMuDQoNCiAgICBBcyBhIGNvbmNsdXNpb24sIFIgaXMgd29ybGQncyBtb3N0IHdpZGVseSB1c2VkIHN0YXRpc3RpY3MgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UuIEl0J3MgdGhlICMgMSBjaG9pY2Ugb2YgZGF0YSBzY2llbnRpc3RzIGFuZCBzdXBwb3J0ZWQgYnkgYSB2aWJyYW50IGFuZCB0YWxlbnRlZCBjb21tdW5pdHkgb2YgY29udHJpYnV0b3JzLiBSIGlzIHRhdWdodCBpbiB1bml2ZXJzaXRpZXMgYW5kIGRlcGxveWVkIGluIG1pc3Npb24gY3JpdGljYWwgYnVzaW5lc3MgYXBwbGljYXRpb25zLiBUaGlzIHR1dG9yaWFsIHdpbGwgdGVhY2ggeW91IFIgcHJvZ3JhbW1pbmcgYWxvbmcgd2l0aCBzdWl0YWJsZSBleGFtcGxlcyBpbiBzaW1wbGUgYW5kIGVhc3kgc3RlcHMuDQoNCkxldCdzIGdldCBzdGFydGVkLg0KDQovLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRU5WSVJPTk1FTlQgU0VUVVANCi8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0vIA0KDQogICAgWW91IGNhbiBkb3dubG9hZCB0aGUgV2luZG93cyBpbnN0YWxsZXIgdmVyc2lvbiBvZiBSIGZyb20gUi0zLjIuMiBmb3IgV2luZG93cyAoMzIvNjQgYml0KSBhbmQgc2F2ZSBpdCBpbiBhIGxvY2FsIGRpcmVjdG9yeS4NCg0KICAgIEFzIGl0IGlzIGEgV2luZG93cyBpbnN0YWxsZXIgKC5leGUpIHdpdGggYSBuYW1lICJSLXZlcnNpb24td2luLmV4ZSIuIFlvdSBjYW4ganVzdCBkb3VibGUgY2xpY2sgYW5kIHJ1biB0aGUgaW5zdGFsbGVyIGFjY2VwdGluZyB0aGUgZGVmYXVsdCBzZXR0aW5ncy4gSWYgeW91ciBXaW5kb3dzIGlzIDMyLWJpdCB2ZXJzaW9uLCBpdCBpbnN0YWxscyB0aGUgMzItYml0IHZlcnNpb24uIEJ1dCBpZiB5b3VyIHdpbmRvd3MgaXMgNjQtYml0LCB0aGVuIGl0IGluc3RhbGxzIGJvdGggdGhlIDMyLWJpdCBhbmQgNjQtYml0IHZlcnNpb25zLg0KDQogICAgQWZ0ZXIgaW5zdGFsbGF0aW9uIHlvdSBjYW4gbG9jYXRlIHRoZSBpY29uIHRvIHJ1biB0aGUgUHJvZ3JhbSBpbiBhIGRpcmVjdG9yeSBzdHJ1Y3R1cmUgIlJcUjMuMi4yXGJpblxpMzg2XFJndWkuZXhlIiB1bmRlciB0aGUgV2luZG93cyBQcm9ncmFtIEZpbGVzLiBDbGlja2luZyB0aGlzIGljb24gYnJpbmdzIHVwIHRoZSBSLUdVSSB3aGljaCBpcyB0aGUgUiBjb25zb2xlIHRvIGRvIFIgUHJvZ3JhbW1pbmcuDQogICAgVGhpcyB3aWxsIHNob3c6DQogICAgICBSIHZlcnNpb24gMy41LjEgKDIwMTgtMDctMDIpIC0tICJGZWF0aGVyIFNwcmF5Ig0KICAgICAgQ29weXJpZ2h0IChDKSAyMDE4IFRoZSBSIEZvdW5kYXRpb24gZm9yIFN0YXRpc3RpY2FsIENvbXB1dGluZw0KICAgICAgUGxhdGZvcm06IHg4Nl82NC13NjQtbWluZ3czMi94NjQgKDY0LWJpdCkNCiAgDQogICAgICBSIGlzIGZyZWUgc29mdHdhcmUgYW5kIGNvbWVzIHdpdGggQUJTT0xVVEVMWSBOTyBXQVJSQU5UWS4NCiAgICAgIFlvdSBhcmUgd2VsY29tZSB0byByZWRpc3RyaWJ1dGUgaXQgdW5kZXIgY2VydGFpbiBjb25kaXRpb25zLg0KICAgICAgVHlwZSAnbGljZW5zZSgpJyBvciAnbGljZW5jZSgpJyBmb3IgZGlzdHJpYnV0aW9uIGRldGFpbHMuDQogICAgICANCiAgICAgIFIgaXMgYSBjb2xsYWJvcmF0aXZlIHByb2plY3Qgd2l0aCBtYW55IGNvbnRyaWJ1dG9ycy4NCiAgICAgIFR5cGUgJ2NvbnRyaWJ1dG9ycygpJyBmb3IgbW9yZSBpbmZvcm1hdGlvbiBhbmQNCiAgICAgICdjaXRhdGlvbigpJyBvbiBob3cgdG8gY2l0ZSBSIG9yIFIgcGFja2FnZXMgaW4gcHVibGljYXRpb25zLg0KICAgICAgDQogICAgICBUeXBlICdkZW1vKCknIGZvciBzb21lIGRlbW9zLCAnaGVscCgpJyBmb3Igb24tbGluZSBoZWxwLCBvcg0KICAgICAgJ2hlbHAuc3RhcnQoKScgZm9yIGFuIEhUTUwgYnJvd3NlciBpbnRlcmZhY2UgdG8gaGVscC4NCiAgICAgIFR5cGUgJ3EoKScgdG8gcXVpdCBSLg0KICAgICAgPg0KDQovLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0vDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQkFTSUMgU1lOVEFYDQovLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0vDQoNCiAgICBBcyBhIGNvbnZlbnRpb24sIHdlIHdpbGwgc3RhcnQgbGVhcm5pbmcgUiBwcm9ncmFtbWluZyBieSB3cml0aW5nIGEgIkhlbGxvLCBXb3JsZCEiIHByb2dyYW0uIERlcGVuZGluZyBvbiB0aGUgbmVlZHMsIHlvdSBjYW4gcHJvZ3JhbSBlaXRoZXIgYXQgUiBjb21tYW5kIHByb21wdCBvciB5b3UgY2FuIHVzZSBhbiBSIHNjcmlwdCBmaWxlIHRvIHdyaXRlIHlvdXIgcHJvZ3JhbS4gTGV0J3MgY2hlY2sgYm90aCBvbmUgYnkgb25lLg0KICAgIA0KUiBDb21tYW5kIFByb21wdA0KDQogICAgT25jZSB5b3UgaGF2ZSBSIGVudmlyb25tZW50IHNldHVwLCB0aGVuIGl0J3MgZWFzeSB0byBzdGFydCB5b3VyIFIgY29tbWFuZCBwcm9tcHQgYnkganVzdCB0eXBpbmcgdGhlIGZvbGxvd2luZyBjb21tYW5kIGF0IHlvdXIgY29tbWFuZCBwcm9tcHQ6DQogICAgDQogICAgVGhpcyB3aWxsIGxhdW5jaCBSIGludGVycHJldGVyIGFuZCB5b3Ugd2lsbCBnZXQgYSBwcm9tcHQgPiB3aGVyZSB5b3UgY2FuIHN0YXJ0IHR5cGluZyB5b3VyIHByb2dyYW0gYXMgZm9sbG93czoNCg0KYGBge3J9DQpteVN0cmluZyA8LSAiSGVsbG8sIFdvcmxkISINCnByaW50ICggbXlTdHJpbmcpDQpgYGANCg0KQ29tbWVudHMNCg0KICAgIENvbW1lbnRzIGFyZSBsaWtlIGhlbHBpbmcgdGV4dCBpbiB5b3VyIFIgcHJvZ3JhbSBhbmQgdGhleSBhcmUgaWdub3JlZCBieSB0aGUgaW50ZXJwcmV0ZXIgd2hpbGUgZXhlY3V0aW5nIHlvdXIgYWN0dWFsIHByb2dyYW0uIFNpbmdsZSBjb21tZW50IGlzIHdyaXR0ZW4gdXNpbmcgIyBpbiB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzdGF0ZW1lbnQgYXMgZm9sbG93czoNCg0KYGBge3J9DQojIE15IGZpcnN0IHByb2dyYW0gaW4gUiBQcm9ncmFtbWluZw0KYGBgDQoNCi8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgREFUQSBUWVBFUw0KLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0vDQoNCiAgICBHZW5lcmFsbHksIHdoaWxlIGRvaW5nIHByb2dyYW1taW5nIGluIGFueSBwcm9ncmFtbWluZyBsYW5ndWFnZSwgeW91IG5lZWQgdG8gdXNlIHZhcmlvdXMgdmFyaWFibGVzIHRvIHN0b3JlIHZhcmlvdXMgaW5mb3JtYXRpb24uIFZhcmlhYmxlcyBhcmUgbm90aGluZyBidXQgcmVzZXJ2ZWQgbWVtb3J5IGxvY2F0aW9ucyB0byBzdG9yZSB2YWx1ZXMuIFRoaXMgbWVhbnMgdGhhdCwgd2hlbiB5b3UgY3JlYXRlIGEgdmFyaWFibGUgeW91IHJlc2VydmUgc29tZSBzcGFjZSBpbiBtZW1vcnkuDQoNCiAgICBZb3UgbWF5IGxpa2UgdG8gc3RvcmUgaW5mb3JtYXRpb24gb2YgdmFyaW91cyBkYXRhIHR5cGVzIGxpa2UgY2hhcmFjdGVyLCB3aWRlIGNoYXJhY3RlciwgaW50ZWdlciwgZmxvYXRpbmcgcG9pbnQsIGRvdWJsZSBmbG9hdGluZyBwb2ludCwgQm9vbGVhbiBldGMuIEJhc2VkIG9uIHRoZSBkYXRhIHR5cGUgb2YgYSB2YXJpYWJsZSwgdGhlIG9wZXJhdGluZyBzeXN0ZW0gYWxsb2NhdGVzIG1lbW9yeSBhbmQgZGVjaWRlcyB3aGF0IGNhbiBiZSBzdG9yZWQgaW4gdGhlIHJlc2VydmVkIG1lbW9yeS4NCg0KVG9waWNzOg0KDQogICAgTG9naWNhbCwgTnVtZXJpYywgSW50ZWdlciwgQ29tcGxleCwgY2hhcmFjdGVyLCBSYXcNCg0KYGBge3J9DQojIExvZ2ljYWwNCiMgRXhhbXBsZTogVFJVRSBPUiBGQUxTRQ0KdiA8LSBUUlVFIA0KcHJpbnQoY2xhc3ModikpDQpgYGANCmBgYHtyfQ0KIyBOdW1lcmljDQojIEV4YW1wbGU6IDEyLjMsIDUsIDk5OQ0KdiA8LSAyMy41DQpwcmludChjbGFzcyh2KSkNCmBgYA0KYGBge3J9DQojIEludGVnZXINCiMgRXhhbXBsZTogMkwsIDM0TCwgMEwNCnYgPC0gMkwNCnByaW50KGNsYXNzKHYpKQ0KYGBgDQpgYGB7cn0NCiMgQ29tcGxleA0KIyBFeGFtcGxlOiAzICsgMmkNCnYgPC0gMis1aQ0KcHJpbnQoY2xhc3ModikpDQpgYGANCmBgYHtyfQ0KIyBDaGFyYWN0ZXINCiMgRXhhbXBsZTogJ2EnICwgJyJnb29kIiwgIlRSVUUiLCAnMjMuNCcNCnYgPC0gIlRSVUUiDQpwcmludChjbGFzcyh2KSkNCmBgYA0KYGBge3J9DQojIFJhdw0KIyBFeGFtcGxlOiAiSGVsbG8iIGlzIHN0b3JlZCBhcyA0OCA2NSA2YyA2YyA2Zg0KdiA8LSBjaGFyVG9SYXcoIkhlbGxvIikNCnByaW50KGNsYXNzKHYpKQ0KYGBgDQoNCiAgT3RoZXIgdG9waWNzOg0KICANCiAgICBWZWN0b3JzLCBMaXN0cywgTWF0cmljZXMsIEFycmF5cywgRmFjdG9ycywgRGF0YSBGcmFtZXMNCg0KVmVjdG9ycw0KDQogICAgV2hlbiB5b3Ugd2FudCB0byBjcmVhdGUgdmVjdG9yIHdpdGggbW9yZSB0aGFuIG9uZSBlbGVtZW50LCB5b3Ugc2hvdWxkIHVzZSBjKCkgZnVuY3Rpb24gd2hpY2ggbWVhbnMgdG8gY29tYmluZSB0aGUgZWxlbWVudHMgaW50byBhIHZlY3Rvci4NCmBgYHtyfQ0KIyBDcmVhdGUgYSB2ZWN0b3IuDQphcHBsZSA8LSBjKCdyZWQnLCdncmVlbicsInllbGxvdyIpDQpwcmludChhcHBsZSkNCg0KIyBHZXQgdGhlIGNsYXNzIG9mIHRoZSB2ZWN0b3IuDQpwcmludChjbGFzcyhhcHBsZSkpDQpgYGANCg0KTGlzdHMNCg0KICAgIEEgbGlzdCBpcyBhbiBSLW9iamVjdCB3aGljaCBjYW4gY29udGFpbiBtYW55IGRpZmZlcmVudCB0eXBlcyBvZiBlbGVtZW50cyBpbnNpZGUgaXQgbGlrZSB2ZWN0b3JzLCBmdW5jdGlvbnMgYW5kIGV2ZW4gYW5vdGhlciBsaXN0IGluc2lkZSBpdC4NCg0KYGBge3J9DQojIENyZWF0ZSBhIGxpc3QuDQpsaXN0MSA8LSBsaXN0KGMoMiw1LDMpLDIxLjMsc2luKQ0KDQojIFByaW50IHRoZSBsaXN0Lg0KcHJpbnQobGlzdDEpDQpgYGANCg0KTWF0cmljZXMNCg0KICAgIEEgbWF0cml4IGlzIGEgdHdvLWRpbWVuc2lvbmFsIHJlY3Rhbmd1bGFyIGRhdGEgc2V0LiBJdCBjYW4gYmUgY3JlYXRlZCB1c2luZyBhIHZlY3RvciBpbnB1dCB0byB0aGUgbWF0cml4IGZ1bmN0aW9uLg0KDQpgYGB7cn0NCiMgQ3JlYXRlIGEgbWF0cml4Lg0KTSA9IG1hdHJpeCggYygnYScsJ2EnLCdiJywnYycsJ2InLCdhJyksIG5yb3cgPSAyLCBuY29sID0gMywgYnlyb3cgPSBUUlVFKQ0KcHJpbnQoTSkNCmBgYA0KDQpBcnJheXMNCg0KICAgIFdoaWxlIG1hdHJpY2VzIGFyZSBjb25maW5lZCB0byB0d28gZGltZW5zaW9ucywgYXJyYXlzIGNhbiBiZSBvZiBhbnkgbnVtYmVyIG9mIGRpbWVuc2lvbnMuIFRoZSBhcnJheSBmdW5jdGlvbiB0YWtlcyBhIGRpbSBhdHRyaWJ1dGUgd2hpY2ggY3JlYXRlcyB0aGUgcmVxdWlyZWQgbnVtYmVyIG9mIGRpbWVuc2lvbi4gSW4gdGhlIGJlbG93IGV4YW1wbGUgd2UgY3JlYXRlIGFuIGFycmF5IHdpdGggdHdvIGVsZW1lbnRzIHdoaWNoIGFyZSAzeDMgbWF0cmljZXMgZWFjaC4NCg0KYGBge3J9DQojIENyZWF0ZSBhbiBhcnJheS4NCmEgPC0gYXJyYXkoYygnZ3JlZW4nLCd5ZWxsb3cnKSxkaW0gPSBjKDMsMywyKSkNCnByaW50KGEpDQpgYGANCg0KRmFjdG9ycw0KDQogICAgRmFjdG9ycyBhcmUgdGhlIHItb2JqZWN0cyB3aGljaCBhcmUgY3JlYXRlZCB1c2luZyBhIHZlY3Rvci4gSXQgc3RvcmVzIHRoZSB2ZWN0b3IgYWxvbmcgd2l0aCB0aGUgZGlzdGluY3QgdmFsdWVzIG9mIHRoZSBlbGVtZW50cyBpbiB0aGUgdmVjdG9yIGFzIGxhYmVscy4gVGhlIGxhYmVscyBhcmUgYWx3YXlzIGNoYXJhY3RlciBpcnJlc3BlY3RpdmUgb2Ygd2hldGhlciBpdCBpcyBudW1lcmljIG9yIGNoYXJhY3RlciBvciBCb29sZWFuIGV0Yy4gaW4gdGhlIGlucHV0IHZlY3Rvci4gVGhleSBhcmUgdXNlZnVsIGluIHN0YXRpc3RpY2FsIG1vZGVsaW5nLg0KDQogICAgRmFjdG9ycyBhcmUgY3JlYXRlZCB1c2luZyB0aGUgZmFjdG9yKCkgZnVuY3Rpb24uIFRoZSBubGV2ZWxzIGZ1bmN0aW9ucyBnaXZlcyB0aGUgY291bnQgb2YgbGV2ZWxzLg0KYGBge3J9DQojIENyZWF0ZSBhIHZlY3Rvci4NCmFwcGxlX2NvbG9ycyA8LSBjKCdncmVlbicsJ2dyZWVuJywneWVsbG93JywncmVkJywncmVkJywncmVkJywnZ3JlZW4nKQ0KDQojIENyZWF0ZSBhIGZhY3RvciBvYmplY3QuDQpmYWN0b3JfYXBwbGUgPC0gZmFjdG9yKGFwcGxlX2NvbG9ycykNCg0KIyBQcmludCB0aGUgZmFjdG9yLg0KcHJpbnQoZmFjdG9yX2FwcGxlKQ0KcHJpbnQobmxldmVscyhmYWN0b3JfYXBwbGUpKQ0KYGBgDQoNCkRhdGEgRnJhbWVzDQoNCiAgICBEYXRhIGZyYW1lcyBhcmUgdGFidWxhciBkYXRhIG9iamVjdHMuIFVubGlrZSBhIG1hdHJpeCBpbiBkYXRhIGZyYW1lIGVhY2ggY29sdW1uIGNhbiBjb250YWluIGRpZmZlcmVudCBtb2RlcyBvZiBkYXRhLiBUaGUgZmlyc3QgY29sdW1uIGNhbiBiZSBudW1lcmljIHdoaWxlIHRoZSBzZWNvbmQgY29sdW1uIGNhbiBiZSBjaGFyYWN0ZXIgYW5kIHRoaXJkIGNvbHVtbiBjYW4gYmUgbG9naWNhbC4gSXQgaXMgYSBsaXN0IG9mIHZlY3RvcnMgb2YgZXF1YWwgbGVuZ3RoLg0KDQogICAgRGF0YSBGcmFtZXMgYXJlIGNyZWF0ZWQgdXNpbmcgdGhlIGRhdGEuZnJhbWUoKSBmdW5jdGlvbi4NCg0KYGBge3J9DQojIENyZWF0ZSB0aGUgZGF0YSBmcmFtZS4NCkJNSSA8LSAJZGF0YS5mcmFtZSgNCiAgIGdlbmRlciA9IGMoIk1hbGUiLCAiTWFsZSIsIkZlbWFsZSIpLCANCiAgIGhlaWdodCA9IGMoMTUyLCAxNzEuNSwgMTY1KSwgDQogICB3ZWlnaHQgPSBjKDgxLDkzLCA3OCksDQogICBBZ2UgPSBjKDQyLDM4LDI2KQ0KKQ0KcHJpbnQoQk1JKQ0KYGBgDQoNCi8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS8NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWQVJJQUJMRVMNCi8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS8NCg0KICAgIEEgdmFyaWFibGUgcHJvdmlkZXMgdXMgd2l0aCBuYW1lZCBzdG9yYWdlIHRoYXQgb3VyIHByb2dyYW1zIGNhbiBtYW5pcHVsYXRlLiBBIHZhcmlhYmxlIGluIFIgY2FuIHN0b3JlIGFuIGF0b21pYyB2ZWN0b3IsIGdyb3VwIG9mIGF0b21pYyB2ZWN0b3JzIG9yIGEgY29tYmluYXRpb24gb2YgbWFueSBSb2JqZWN0cy4gQSB2YWxpZCB2YXJpYWJsZSBuYW1lIGNvbnNpc3RzIG9mIGxldHRlcnMsIG51bWJlcnMgYW5kIHRoZSBkb3Qgb3IgdW5kZXJsaW5lIGNoYXJhY3RlcnMuIFRoZSB2YXJpYWJsZSBuYW1lIHN0YXJ0cyB3aXRoIGEgbGV0dGVyIG9yIHRoZSBkb3Qgbm90IGZvbGxvd2VkIGJ5IGEgbnVtYmVyLg0KICAgIA0KVmFyaWFibGUgQXNzaWdubWVudA0KDQogICAgVGhlIHZhcmlhYmxlcyBjYW4gYmUgYXNzaWduZWQgdmFsdWVzIHVzaW5nIGxlZnR3YXJkLCByaWdodHdhcmQgYW5kIGVxdWFsIHRvIG9wZXJhdG9yLiBUaGUgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZXMgY2FuIGJlIHByaW50ZWQgdXNpbmcgcHJpbnQoKSBvciBjYXQoKSBmdW5jdGlvbi4gVGhlIGNhdCgpIGZ1bmN0aW9uIGNvbWJpbmVzIG11bHRpcGxlIGl0ZW1zIGludG8gYSBjb250aW51b3VzIHByaW50IG91dHB1dC4NCiAgICANCmBgYHtyfQ0KIyBBc3NpZ25tZW50IHVzaW5nIGVxdWFsIG9wZXJhdG9yLg0KdmFyLjEgPSBjKDAsMSwyLDMpICAgICAgICAgICANCg0KIyBBc3NpZ25tZW50IHVzaW5nIGxlZnR3YXJkIG9wZXJhdG9yLg0KdmFyLjIgPC0gYygibGVhcm4iLCJSIikgICANCg0KIyBBc3NpZ25tZW50IHVzaW5nIHJpZ2h0d2FyZCBvcGVyYXRvci4gICANCmMoVFJVRSwxKSAtPiB2YXIuMyAgICAgICAgICAgDQoNCnByaW50KHZhci4xKQ0KY2F0ICgidmFyLjEgaXMgIiwgdmFyLjEgLCJcbiIpDQpjYXQgKCJ2YXIuMiBpcyAiLCB2YXIuMiAsIlxuIikNCmNhdCAoInZhci4zIGlzICIsIHZhci4zICwiXG4iKQ0KYGBgDQoNCiAgICBOb3RlOiBUaGUgdmVjdG9yIGMoVFJVRSwxKSBoYXMgYSBtaXggb2YgbG9naWNhbCBhbmQgbnVtZXJpYyBjbGFzcy4gU28gbG9naWNhbCBjbGFzcyBpcyBjb2VyY2VkIHRvIG51bWVyaWMgY2xhc3MgbWFraW5nIFRSVUUgYXMgMS4NCiAgICANCkRhdGEgVHlwZSBvZiBhIFZhcmlhYmxlDQoNCiAgICBJbiBSLCBhIHZhcmlhYmxlIGl0c2VsZiBpcyBub3QgZGVjbGFyZWQgb2YgYW55IGRhdGEgdHlwZSwgcmF0aGVyIGl0IGdldHMgdGhlIGRhdGEgdHlwZSBvZiB0aGUgUiAtIG9iamVjdCBhc3NpZ25lZCB0byBpdC4gU28gUiBpcyBjYWxsZWQgYSBkeW5hbWljYWxseSB0eXBlZCBsYW5ndWFnZSwgd2hpY2ggbWVhbnMgdGhhdCB3ZSBjYW4gY2hhbmdlIGEgdmFyaWFibGUncyBkYXRhIHR5cGUgb2YgdGhlIHNhbWUgdmFyaWFibGUgYWdhaW4gYW5kIGFnYWluIHdoZW4gdXNpbmcgaXQgaW4gYSBwcm9ncmFtLg0KICAgIA0KYGBge3J9DQp2YXJfeCA8LSAiSGVsbG8iDQpjYXQoIlRoZSBjbGFzcyBvZiB2YXJfeCBpcyAiLGNsYXNzKHZhcl94KSwiXG4iKQ0KDQp2YXJfeCA8LSAzNC41DQpjYXQoIiAgTm93IHRoZSBjbGFzcyBvZiB2YXJfeCBpcyAiLGNsYXNzKHZhcl94KSwiXG4iKQ0KDQp2YXJfeCA8LSAyN0wNCmNhdCgiICAgTmV4dCB0aGUgY2xhc3Mgb2YgdmFyX3ggYmVjb21lcyAiLGNsYXNzKHZhcl94KSwiXG4iKQ0KYGBgDQoNCkZpbmRpbmcgVmFyaWFibGVzDQoNCiAgICBUbyBrbm93IGFsbCB0aGUgdmFyaWFibGVzIGN1cnJlbnRseSBhdmFpbGFibGUgaW4gdGhlIHdvcmtzcGFjZSB3ZSB1c2UgdGhlIGxzKCkgZnVuY3Rpb24uIEFsc28gdGhlIGxzKCkgZnVuY3Rpb24gY2FuIHVzZSBwYXR0ZXJucyB0byBtYXRjaCB0aGUgdmFyaWFibGUgbmFtZXMuDQogICAgDQpgYGB7cn0NCnByaW50KGxzKCkpDQpgYGANCg0KRGVsZXRpbmcgVmFyaWFibGVzDQoNCiAgICBWYXJpYWJsZXMgY2FuIGJlIGRlbGV0ZWQgYnkgdXNpbmcgdGhlIHJtKCkgZnVuY3Rpb24uIEJlbG93IHdlIGRlbGV0ZSB0aGUgdmFyaWFibGUgdmFyLjMuIE9uIHByaW50aW5nIHRoZSB2YWx1ZSBvZiB0aGUgdmFyaWFibGUgZXJyb3IgaXMgdGhyb3duLg0KICAgIA0KYGBge3J9DQpybSh2YXIuMykNCnByaW50KHZhci4zKQ0KYGBgDQoNCiAgICBBbGwgdGhlIHZhcmlhYmxlcyBjYW4gYmUgZGVsZXRlZCBieSB1c2luZyB0aGUgcm0oKSBhbmQgbHMoKSBmdW5jdGlvbiB0b2dldGhlci4NCiAgICANCmBgYHtyfQ0Kcm0obGlzdCA9IGxzKCkpDQpwcmludChscygpKQ0KYGBgDQoNCi8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0vDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9wZXJhdG9ycw0KLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS8NCg0KICAgIEFuIG9wZXJhdG9yIGlzIGEgc3ltYm9sIHRoYXQgdGVsbHMgdGhlIGNvbXBpbGVyIHRvIHBlcmZvcm0gc3BlY2lmaWMgbWF0aGVtYXRpY2FsIG9yIGxvZ2ljYWwgbWFuaXB1bGF0aW9ucy4gUiBsYW5ndWFnZSBpcyByaWNoIGluIGJ1aWx0LWluIG9wZXJhdG9ycyBhbmQgcHJvdmlkZXMgZm9sbG93aW5nIHR5cGVzIG9mIG9wZXJhdG9ycy4NCiAgICANClR5cGVzIG9mIE9wZXJhdG9ycw0KDQogICAgV2UgaGF2ZSB0aGUgZm9sbG93aW5nIHR5cGVzIG9mIG9wZXJhdG9ycyBpbiBSIHByb2dyYW1taW5nOg0KICAgICAgQXJpdGhtZXRpYyBPcGVyYXRvcnMNCiAgICAgIFJlbGF0aW9uYWwgT3BlcmF0b3JzDQogICAgICBMb2dpY2FsIE9wZXJhdG9ycw0KICAgICAgQXNzaWdubWVudCBPcGVyYXRvcnMNCiAgICAgIE1pc2NlbGxhbmVvdXMgT3BlcmF0b3JzDQogICAgICANCkFyaXRobWV0aWMgT3BlcmF0b3JzDQoNCiAgICBBZGRzIHR3byB2ZWN0b3JzDQogICAgT3BlcmF0b3I6ICsNCiAgICANCmBgYHtyfQ0KdiA8LSBjKCAyLDUuNSw2KQ0KdCA8LSBjKDgsIDMsIDQpDQpwcmludCh2K3QpDQpgYGANCg0KICAgIFN1YnRyYWN0cyBzZWNvbmQgdmVjdG9yIGZyb20gdGhlIGZpcnN0DQogICAgT3BlcmF0b3I6IC0NCiAgICANCmBgYHtyfQ0KdiA8LSBjKCAyLDUuNSw2KQ0KdCA8LSBjKDgsIDMsIDQpDQpwcmludCh2LXQpDQpgYGANCg0KICAgIE11bHRpcGxpZXMgYm90aCB2ZWN0b3JzDQogICAgT3BlcmF0b3I6ICoNCiAgICANCmBgYHtyfQ0KdiA8LSBjKCAyLDUuNSw2KQ0KdCA8LSBjKDgsIDMsIDQpDQpwcmludCh2KnQpDQpgYGANCg0KICAgIERpdmlkZSB0aGUgZmlyc3QgdmVjdG9yIHdpdGggdGhlIHNlY29uZA0KICAgIE9wZXJhdG9yOiAvDQogICAgDQpgYGB7cn0NCnYgPC0gYyggMiw1LjUsNikNCnQgPC0gYyg4LCAzLCA0KQ0KcHJpbnQodi90KQ0KYGBgDQoNCiAgICBHaXZlIHRoZSByZW1haW5kZXIgb2YgdGhlIGZpcnN0IHZlY3RvciB3aXRoIHRoZSBzZWNvbmQNCiAgICBPcGVyYXRvcjogJSUNCiAgICANCmBgYHtyfQ0KdiA8LSBjKCAyLDUuNSw2KQ0KdCA8LSBjKDgsIDMsIDQpDQpwcmludCh2JSV0KQ0KYGBgDQoNCiAgICBUaGUgcmVzdWx0IG9mIGRpdmlzaW9uIG9mIGZpcnN0IHZlY3RvciB3aXRoIHNlY29uZCAocXVvdGllbnQpDQogICAgT3BlcmF0b3I6ICUvJQ0KICAgIA0KYGBge3J9DQp2IDwtIGMoIDIsNS41LDYpDQp0IDwtIGMoOCwgMywgNCkNCnByaW50KHYlLyV0KQ0KYGBgDQogICAgDQogICAgVGhlIGZpcnN0IHZlY3RvciByYWlzZWQgdG8gdGhlIGV4cG9uZW50IG9mIHNlY29uZCB2ZWN0b3INCiAgICBPcGVyYXRvcjogXg0KICAgIA0KYGBge3J9DQp2IDwtIGMoIDIsNS41LDYpDQp0IDwtIGMoOCwgMywgNCkNCnByaW50KHZedCkNCmBgYA0KDQpSZWxhdGlvbmFsIE9wZXJhdG9ycw0KDQogICAgRWFjaCBlbGVtZW50IG9mIHRoZSBmaXJzdCB2ZWN0b3IgaXMgY29tcGFyZWQgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IG9mIHRoZSBzZWNvbmQgdmVjdG9yLiBUaGUgcmVzdWx0IG9mIGNvbXBhcmlzb24gaXMgYSBCb29sZWFuIHZhbHVlLg0KDQpPcGVyYXRvcjogPg0KDQogICAgQ2hlY2tzIGlmIGVhY2ggZWxlbWVudCBvZiB0aGUgZmlyc3QgdmVjdG9yIGlzIGdyZWF0ZXIgdGhhbiB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IG9mIHRoZSBzZWNvbmQgdmVjdG9yLg0KDQpgYGB7cn0NCnYgPC0gYygyLDUuNSw2LDkpDQp0IDwtIGMoOCwyLjUsMTQsOSkNCnByaW50KHY+dCkNCmBgYA0KDQpPcGVyYXRvcjogPA0KDQogICAgQ2hlY2tzIGlmIGVhY2ggZWxlbWVudCBvZiB0aGUgZmlyc3QgdmVjdG9yIGlzIGxlc3MgdGhhbiB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IG9mIHRoZSBzZWNvbmQgdmVjdG9yLg0KDQpgYGB7cn0NCnYgPC0gYygyLDUuNSw2LDkpDQp0IDwtIGMoOCwyLjUsMTQsOSkNCnByaW50KHYgPCB0KQ0KYGBgDQoNCk9wZXJhdG9yOiA9PQ0KDQogICAgQ2hlY2tzIGlmIGVhY2ggZWxlbWVudCBvZiB0aGUgZmlyc3QgdmVjdG9yIGlzIGVxdWFsIHRvIHRoZSBjb3JyZXNwb25kaW5nIGVsZW1lbnQgb2YgdGhlIHNlY29uZCB2ZWN0b3IuDQoNCmBgYHtyfQ0KdiA8LSBjKDIsNS41LDYsOSkNCnQgPC0gYyg4LDIuNSwxNCw5KQ0KcHJpbnQodiA9PSB0KQ0KYGBgDQoNCk9wZXJhdG9yOiA8PQ0KDQogICAgQ2hlY2tzIGlmIGVhY2ggZWxlbWVudCBvZiB0aGUgZmlyc3QgdmVjdG9yIGlzIGxlc3MgdGhhbiBvciBlcXVhbCB0byB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IG9mIHRoZSBzZWNvbmQgdmVjdG9yLg0KDQpgYGB7cn0NCnYgPC0gYygyLDUuNSw2LDkpDQp0IDwtIGMoOCwyLjUsMTQsOSkNCnByaW50KHY8PXQpDQpgYGANCg0KT3BlcmF0b3I6ID49DQoNCiAgICBDaGVja3MgaWYgZWFjaCBlbGVtZW50IG9mIHRoZSBmaXJzdCB2ZWN0b3IgaXMgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIHRoZSBjb3JyZXNwb25kaW5nIGVsZW1lbnQgb2YgdGhlIHNlY29uZCB2ZWN0b3IuDQogICAgDQpgYGB7cn0NCnYgPC0gYygyLDUuNSw2LDkpDQp0IDwtIGMoOCwyLjUsMTQsOSkNCnByaW50KHY+PXQpDQpgYGANCg0KT3BlcmF0b3I6ICE9DQoNCiAgICBDaGVja3MgaWYgZWFjaCBlbGVtZW50IG9mIHRoZSBmaXJzdCB2ZWN0b3IgaXMgdW5lcXVhbCB0byB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IG9mIHRoZSBzZWNvbmQgdmVjdG9yLg0KICAgIA0KYGBge3J9DQp2IDwtIGMoMiw1LjUsNiw5KQ0KdCA8LSBjKDgsMi41LDE0LDkpDQpwcmludCh2IT10KQ0KYGBgDQoNCkxvZ2ljYWwgT3BlcmF0b3JzDQoNCiAgICBGb2xsb3dpbmcgdGFibGUgc2hvd3MgdGhlIGxvZ2ljYWwgb3BlcmF0b3JzIHN1cHBvcnRlZCBieSBSIGxhbmd1YWdlLiBJdCBpcyBhcHBsaWNhYmxlIG9ubHkgdG8gdmVjdG9ycyBvZiB0eXBlIGxvZ2ljYWwsIG51bWVyaWMgb3IgY29tcGxleC4gQWxsIG51bWJlcnMgZ3JlYXRlciB0aGFuIDEgYXJlIGNvbnNpZGVyZWQgYXMgbG9naWNhbCB2YWx1ZSBUUlVFLg0KDQogICAgRWFjaCBlbGVtZW50IG9mIHRoZSBmaXJzdCB2ZWN0b3IgaXMgY29tcGFyZWQgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IG9mIHRoZSBzZWNvbmQgdmVjdG9yLiBUaGUgcmVzdWx0IG9mIGNvbXBhcmlzb24gaXMgYSBCb29sZWFuIHZhbHVlLg0KDQpPcGVyYXRvcjogJg0KDQogICAgSXQgaXMgY2FsbGVkIEVsZW1lbnQtd2lzZSBMb2dpY2FsIEFORCBvcGVyYXRvci4gSXQgY29tYmluZXMgZWFjaCBlbGVtZW50IG9mIHRoZSBmaXJzdCB2ZWN0b3Igd2l0aCB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IG9mIHRoZSBzZWNvbmQgdmVjdG9yIGFuZCBnaXZlcyBhIG91dHB1dCBUUlVFIGlmIGJvdGggdGhlIGVsZW1lbnRzIGFyZSBUUlVFLg0KICAgIA0KYGBge3J9DQp2IDwtIGMoMywxLFRSVUUsMiszaSkNCnQgPC0gYyg0LDEsRkFMU0UsMiszaSkNCnByaW50KHYmdCkNCmBgYA0KDQpPcGVyYXRvcjogfA0KDQogICAgSXQgaXMgY2FsbGVkIEVsZW1lbnQtd2lzZSBMb2dpY2FsIE9SIG9wZXJhdG9yLiBJdCBjb21iaW5lcyBlYWNoIGVsZW1lbnQgb2YgdGhlIGZpcnN0IHZlY3RvciB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIGVsZW1lbnQgb2YgdGhlIHNlY29uZCB2ZWN0b3IgYW5kIGdpdmVzIGEgb3V0cHV0IFRSVUUgaWYgb25lIHRoZSBlbGVtZW50cyBpcyBUUlVFLg0KDQpgYGB7cn0NCnYgPC0gYygzLDAsVFJVRSwyKzJpKQ0KdCA8LSBjKDQsMCxGQUxTRSwyKzNpKQ0KcHJpbnQodnx0KQ0KYGBgDQoNCk9wZXJhdG9yOiAhDQoNCiAgICBJdCBpcyBjYWxsZWQgTG9naWNhbCBOT1Qgb3BlcmF0b3IuIFRha2VzIGVhY2ggZWxlbWVudCBvZiB0aGUgdmVjdG9yIGFuZCBnaXZlcyB0aGUgb3Bwb3NpdGUgbG9naWNhbCB2YWx1ZS4NCg0KYGBge3J9DQp2IDwtIGMoMywwLFRSVUUsMisyaSkNCnByaW50KCF2KQ0KYGBgDQoNCiAgICBUaGUgbG9naWNhbCBvcGVyYXRvciAmJiBhbmQgfHwgY29uc2lkZXJzIG9ubHkgdGhlIGZpcnN0IGVsZW1lbnQgb2YgdGhlIHZlY3RvcnMgYW5kIGdpdmUgYSB2ZWN0b3Igb2Ygc2luZ2xlIGVsZW1lbnQgYXMgb3V0cHV0Lg0KDQpPcGVyYXRvcjogJiYNCg0KICAgIENhbGxlZCBMb2dpY2FsIEFORCBvcGVyYXRvci4gVGFrZXMgZmlyc3QgZWxlbWVudCBvZiBib3RoIHRoZSB2ZWN0b3JzIGFuZCBnaXZlcyB0aGUgVFJVRSBvbmx5IGlmIGJvdGggYXJlIFRSVUUuDQoNCmBgYHtyfQ0KdiA8LSBjKDMsMCxUUlVFLDIrMmkpDQp0IDwtIGMoMSwzLFRSVUUsMiszaSkNCnByaW50KHYmJnQpDQpgYGANCg0KT3BlcmF0b3I6ICEhDQoNCiAgICBDYWxsZWQgTG9naWNhbCBPUiBvcGVyYXRvci4gVGFrZXMgZmlyc3QgZWxlbWVudCBvZiBib3RoIHRoZSB2ZWN0b3JzIGFuZCBnaXZlcyB0aGUgVFJVRSBpZiBvbmUgb2YgdGhlbSBpcyBUUlVFLg0KDQpgYGB7cn0NCnYgPC0gYygwLDAsVFJVRSwyKzJpKQ0KdCA8LSBjKDAsMyxUUlVFLDIrM2kpDQpwcmludCh2fHx0KQ0KYGBgDQoNCkFzc2lnbm1lbnQgT3BlcmF0b3JzDQoNCiAgICBUaGVzZSBvcGVyYXRvcnMgYXJlIHVzZWQgdG8gYXNzaWduIHZhbHVlcyB0byB2ZWN0b3JzLg0KICAgIA0KT3BlcmF0b3I6IDw/Pz8gb3IgPSBvciA8PD8/Pw0KDQogICAgQ2FsbGVkIExlZnQgQXNzaWdubWVudA0KICAgIA0KYGBge3J9DQp2MSA8LSBjKDMsMSxUUlVFLDIrM2kpDQp2MiA8PC0gYygzLDEsVFJVRSwyKzNpKQ0KdjMgPSBjKDMsMSxUUlVFLDIrM2kpDQpwcmludCh2MSkNCnByaW50KHYyKQ0KcHJpbnQodjMpDQpgYGANCg0KT3BlcmF0b3I6IC0+IG9yIC0+Pg0KDQogICAgQ2FsbGVkIFJpZ2h0IEFzc2lnbm1lbnQNCg0KYGBge3J9DQpjKDMsMSxUUlVFLDIrM2kpIC0+IHYxDQpjKDMsMSxUUlVFLDIrM2kpIC0+PiB2MiANCnByaW50KHYxKQ0KcHJpbnQodjIpDQpgYGANCg0KTWlzY2VsbGFuZW91cyBPcGVyYXRvcnMNCg0KICAgIFRoZXNlIG9wZXJhdG9ycyBhcmUgdXNlZCB0byBmb3Igc3BlY2lmaWMgcHVycG9zZSBhbmQgbm90IGdlbmVyYWwgbWF0aGVtYXRpY2FsIG9yIGxvZ2ljYWwgY29tcHV0YXRpb24uDQogICAgDQpPcGVyYXRvcjogOg0KDQogICAgCUNvbG9uIG9wZXJhdG9yLiBJdCBjcmVhdGVzIHRoZSBzZXJpZXMgb2YgbnVtYmVycyBpbiBzZXF1ZW5jZSBmb3IgYSB2ZWN0b3IuDQoNCmBgYHtyfQ0KdiA8LSAyOjgNCnByaW50KHYpIA0KYGBgDQoNCk9wZXJhdG9yOiAlaW4lDQoNCiAgICBUaGlzIG9wZXJhdG9yIGlzIHVzZWQgdG8gaWRlbnRpZnkgaWYgYW4gZWxlbWVudCBiZWxvbmdzIHRvIGEgdmVjdG9yLg0KDQpgYGB7cn0NCnYxIDwtIDgNCnYyIDwtIDEyDQp0IDwtIDE6MTANCnByaW50KHYxICVpbiUgdCkgDQpwcmludCh2MiAlaW4lIHQpDQpgYGANCg0KT3BlcmF0b3I6ICUqJQ0KDQogICAgVGhpcyBvcGVyYXRvciBpcyB1c2VkIHRvIG11bHRpcGx5IGEgbWF0cml4IHdpdGggaXRzIHRyYW5zcG9zZS4NCg0KYGBge3J9DQpNID0gbWF0cml4KCBjKDIsNiw1LDEsMTAsNCksIG5yb3cgPSAyLG5jb2wgPSAzLGJ5cm93ID0gVFJVRSkNCnQgPSBNICUqJSB0KE0pDQpwcmludCh0KQ0KYGBgDQoNCi8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0vDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9wZXJhdG9ycw0KLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS8NCg0KICAgIERlY2lzaW9uIG1ha2luZyBzdHJ1Y3R1cmVzIHJlcXVpcmUgdGhlIHByb2dyYW1tZXIgdG8gc3BlY2lmeSBvbmUgb3IgbW9yZSBjb25kaXRpb25zIHRvIGJlIGV2YWx1YXRlZCBvciB0ZXN0ZWQgYnkgdGhlIHByb2dyYW0sIGFsb25nIHdpdGggYSBzdGF0ZW1lbnQgb3Igc3RhdGVtZW50cyB0byBiZSBleGVjdXRlZCBpZiB0aGUgY29uZGl0aW9uIGlzIGRldGVybWluZWQgdG8gYmUgdHJ1ZSwgYW5kIG9wdGlvbmFsbHksIG90aGVyIHN0YXRlbWVudHMgdG8gYmUgZXhlY3V0ZWQgaWYgdGhlIGNvbmRpdGlvbiBpcyBkZXRlcm1pbmVkIHRvIGJlIGZhbHNlLg0KDQpJZiBTdGF0ZW1lbnQNCg0KICAgIEFuIGlmIHN0YXRlbWVudCBjb25zaXN0cyBvZiBhIEJvb2xlYW4gZXhwcmVzc2lvbiBmb2xsb3dlZCBieSBvbmUgb3IgbW9yZSBzdGF0ZW1lbnRzLg0KDQogICAgVGhlIGJhc2ljIHN5bnRheCBmb3IgY3JlYXRpbmcgYW4gaWYgc3RhdGVtZW50IGluIFIgaXM6DQogICAgDQogICAgICBpZihib29sZWFuX2V4cHJlc3Npb24pIHsNCiAgICAgICAgIC8vIHN0YXRlbWVudChzKSB3aWxsIGV4ZWN1dGUgaWYgdGhlIGJvb2xlYW4gZXhwcmVzc2lvbiBpcyB0cnVlLg0KICAgICAgfQ0KICAgICAgDQpgYGB7cn0NCnggPC0gMzBMDQppZihpcy5pbnRlZ2VyKHgpKSB7DQogICBwcmludCgiWCBpcyBhbiBJbnRlZ2VyIikNCn0NCmBgYA0KDQpJZi4uLkVsc2UgU3RhdGVtZW50DQoNCiAgICBBbiBpZiBzdGF0ZW1lbnQgY2FuIGJlIGZvbGxvd2VkIGJ5IGFuIG9wdGlvbmFsIGVsc2Ugc3RhdGVtZW50IHdoaWNoIGV4ZWN1dGVzIHdoZW4gdGhlIGJvb2xlYW4gZXhwcmVzc2lvbiBpcyBmYWxzZS4NCiAgICANCiAgICBUaGUgYmFzaWMgc3ludGF4IGZvciBjcmVhdGluZyBhbiBpZi4uLmVsc2Ugc3RhdGVtZW50IGluIFIgaXM6DQogICAgICANCiAgICAgIGlmKGJvb2xlYW5fZXhwcmVzc2lvbikgew0KICAgICAgICAgLy8gc3RhdGVtZW50KHMpIHdpbGwgZXhlY3V0ZSBpZiB0aGUgYm9vbGVhbiBleHByZXNzaW9uIGlzIHRydWUuDQogICAgICB9IGVsc2Ugew0KICAgICAgICAgLy8gc3RhdGVtZW50KHMpIHdpbGwgZXhlY3V0ZSBpZiB0aGUgYm9vbGVhbiBleHByZXNzaW9uIGlzIGZhbHNlLg0KICAgICAgfQ0KICAgICAgDQpgYGB7cn0NCnggPC0gYygid2hhdCIsImlzIiwidHJ1dGgiKQ0KDQppZigiVHJ1dGgiICVpbiUgeCkgew0KICAgcHJpbnQoIlRydXRoIGlzIGZvdW5kIikNCn0gZWxzZSB7DQogICBwcmludCgiVHJ1dGggaXMgbm90IGZvdW5kIikNCn0NCmBgYA0KDQpUaGUgaWYuLi5lbHNlIGlmLi4uZWxzZSBTdGF0ZW1lbnQNCg0KICAgIFRoZSBiYXNpYyBzeW50YXggZm9yIGNyZWF0aW5nIGFuIGlmLi4uZWxzZSBpZi4uLmVsc2Ugc3RhdGVtZW50IGluIFIgaXM6DQogICAgICANCiAgICAgIGlmKGJvb2xlYW5fZXhwcmVzc2lvbiAxKSB7DQogICAgICAgICAvLyBFeGVjdXRlcyB3aGVuIHRoZSBib29sZWFuIGV4cHJlc3Npb24gMSBpcyB0cnVlLg0KICAgICAgfSBlbHNlIGlmKCBib29sZWFuX2V4cHJlc3Npb24gMikgew0KICAgICAgICAgLy8gRXhlY3V0ZXMgd2hlbiB0aGUgYm9vbGVhbiBleHByZXNzaW9uIDIgaXMgdHJ1ZS4NCiAgICAgIH0gZWxzZSBpZiggYm9vbGVhbl9leHByZXNzaW9uIDMpIHsNCiAgICAgICAgIC8vIEV4ZWN1dGVzIHdoZW4gdGhlIGJvb2xlYW4gZXhwcmVzc2lvbiAzIGlzIHRydWUuDQogICAgICB9IGVsc2Ugew0KICAgICAgICAgLy8gZXhlY3V0ZXMgd2hlbiBub25lIG9mIHRoZSBhYm92ZSBjb25kaXRpb24gaXMgdHJ1ZS4NCiAgICAgIH0NCiAgICAgIA0KYGBge3J9DQp4IDwtIGMoIndoYXQiLCJpcyIsInRydXRoIikNCg0KaWYoIlRydXRoIiAlaW4lIHgpIHsNCiAgIHByaW50KCJUcnV0aCBpcyBmb3VuZCB0aGUgZmlyc3QgdGltZSIpDQp9IGVsc2UgaWYgKCJ0cnV0aCIgJWluJSB4KSB7DQogICBwcmludCgidHJ1dGggaXMgZm91bmQgdGhlIHNlY29uZCB0aW1lIikNCn0gZWxzZSB7DQogICBwcmludCgiTm8gdHJ1dGggZm91bmQiKQ0KfQ0KYGBgDQoNClN3aXRjaCBTdGF0ZW1lbnQNCg0KICAgIEEgc3dpdGNoIHN0YXRlbWVudCBhbGxvd3MgYSB2YXJpYWJsZSB0byBiZSB0ZXN0ZWQgZm9yIGVxdWFsaXR5IGFnYWluc3QgYSBsaXN0IG9mIHZhbHVlcy4gRWFjaCB2YWx1ZSBpcyBjYWxsZWQgYSBjYXNlLCBhbmQgdGhlIHZhcmlhYmxlIGJlaW5nIHN3aXRjaGVkIG9uIGlzIGNoZWNrZWQgZm9yIGVhY2ggY2FzZS4NCiAgICANCiAgICBUaGUgYmFzaWMgc3ludGF4IGZvciBjcmVhdGluZyBhIHN3aXRjaCBzdGF0ZW1lbnQgaW4gUiBpczoNCiAgICAgIA0KICAgICAgc3dpdGNoKGV4cHJlc3Npb24sIGNhc2UxLCBjYXNlMiwgY2FzZTMuLi4uKQ0KICAgICAgDQpgYGB7cn0NCnggPC0gc3dpdGNoKA0KICAgMywNCiAgICJmaXJzdCIsDQogICAic2Vjb25kIiwNCiAgICJ0aGlyZCIsDQogICAiZm91cnRoIg0KKQ0KcHJpbnQoeCkNCmBgYA0KDQpMb29wcw0KDQogICAgQSBsb29wIHN0YXRlbWVudCBhbGxvd3MgdXMgdG8gZXhlY3V0ZSBhIHN0YXRlbWVudCBvciBncm91cCBvZiBzdGF0ZW1lbnRzIG11bHRpcGxlIHRpbWVzIGFuZCB0aGUgZm9sbG93aW5nIGlzIHRoZSBnZW5lcmFsIGZvcm0gb2YgYSBsb29wIHN0YXRlbWVudCBpbiBtb3N0IG9mIHRoZSBwcm9ncmFtbWluZyBsYW5ndWFnZXM6DQogICAgDQpSZXBlYXQgTG9vcA0KDQogICAgVGhlIFJlcGVhdCBsb29wIGV4ZWN1dGVzIHRoZSBzYW1lIGNvZGUgYWdhaW4gYW5kIGFnYWluIHVudGlsIGEgc3RvcCBjb25kaXRpb24gaXMgbWV0Lg0KICAgIA0KICAgIFRoZSBiYXNpYyBzeW50YXggZm9yIGNyZWF0aW5nIGEgcmVwZWF0IGxvb3AgaW4gUiBpczoNCiAgICANCiAgICAgIHJlcGVhdCB7IA0KICAgICAgICAgY29tbWFuZHMgDQogICAgICAgICBpZihjb25kaXRpb24pIHsNCiAgICAgICAgICAgIGJyZWFrDQogICAgICAgICB9DQogICAgICB9DQogICAgICANCmBgYHtyfQ0KdiA8LSBjKCJIZWxsbyIsImxvb3AiKQ0KY250IDwtIDINCg0KcmVwZWF0IHsNCiAgIHByaW50KHYpDQogICBjbnQgPC0gY250KzENCiAgIA0KICAgaWYoY250ID4gNSkgew0KICAgICAgYnJlYWsNCiAgIH0NCn0NCmBgYA0KDQpXaGlsZSBMb29wDQoNCiAgICBUaGUgV2hpbGUgbG9vcCBleGVjdXRlcyB0aGUgc2FtZSBjb2RlIGFnYWluIGFuZCBhZ2FpbiB1bnRpbCBhIHN0b3AgY29uZGl0aW9uIGlzIG1ldC4NCiAgICANCiAgICBUaGUgYmFzaWMgc3ludGF4IGZvciBjcmVhdGluZyBhIHdoaWxlIGxvb3AgaW4gUiBpczoNCiAgICANCiAgICAgIHdoaWxlICh0ZXN0X2V4cHJlc3Npb24pIHsNCiAgICAgICAgIHN0YXRlbWVudA0KICAgICAgfQ0KICAgICAgDQpgYGB7cn0NCnYgPC0gYygiSGVsbG8iLCJ3aGlsZSBsb29wIikNCmNudCA8LSAyDQoNCndoaWxlIChjbnQgPCA3KSB7DQogICBwcmludCh2KQ0KICAgY250ID0gY250ICsgMQ0KfQ0KYGBgDQoNCkZvciBMb29wDQoNCiAgICBBIEZvciBsb29wIGlzIGEgcmVwZXRpdGlvbiBjb250cm9sIHN0cnVjdHVyZSB0aGF0IGFsbG93cyB5b3UgdG8gZWZmaWNpZW50bHkgd3JpdGUgYSBsb29wIHRoYXQgbmVlZHMgdG8gZXhlY3V0ZSBhIHNwZWNpZmljIG51bWJlciBvZiB0aW1lcy4NCiAgICANCiAgICBUaGUgYmFzaWMgc3ludGF4IGZvciBjcmVhdGluZyBhIGZvciBsb29wIHN0YXRlbWVudCBpbiBSIGlzOg0KICAgIA0KICAgICAgZm9yICh2YWx1ZSBpbiB2ZWN0b3IpIHsNCiAgICAgICAgIHN0YXRlbWVudHMNCiAgICAgIH0NCiAgICAgIA0KYGBge3J9DQp2IDwtIExFVFRFUlNbMTo0XQ0KZm9yICggaSBpbiB2KSB7DQogICBwcmludChpKQ0KfQ0KYGBgDQoNCkxvb3AgQ29udHJvbCBTdGF0ZW1lbnRzDQoNCiAgICBMb29wIGNvbnRyb2wgc3RhdGVtZW50cyBjaGFuZ2UgZXhlY3V0aW9uIGZyb20gaXRzIG5vcm1hbCBzZXF1ZW5jZS4gV2hlbiBleGVjdXRpb24gbGVhdmVzIGEgc2NvcGUsIGFsbCBhdXRvbWF0aWMgb2JqZWN0cyB0aGF0IHdlcmUgY3JlYXRlZCBpbiB0aGF0IHNjb3BlIGFyZSBkZXN0cm95ZWQuDQogICAgDQpCcmVhayBTdGF0ZW1lbnQNCg0KICAgIFRoZSBicmVhayBzdGF0ZW1lbnQgaW4gUiBwcm9ncmFtbWluZyBsYW5ndWFnZSBoYXMgdGhlIGZvbGxvd2luZyB0d28gdXNhZ2VzOg0KICAgIA0KICAgICAgV2hlbiB0aGUgYnJlYWsgc3RhdGVtZW50IGlzIGVuY291bnRlcmVkIGluc2lkZSBhIGxvb3AsIHRoZSBsb29wIGlzIGltbWVkaWF0ZWx5IHRlcm1pbmF0ZWQgYW5kIHByb2dyYW0gY29udHJvbCByZXN1bWVzIGF0IHRoZSBuZXh0IHN0YXRlbWVudCBmb2xsb3dpbmcgdGhlIGxvb3AuDQogIA0KICAgICAgSXQgY2FuIGJlIHVzZWQgdG8gdGVybWluYXRlIGEgY2FzZSBpbiB0aGUgc3dpdGNoIHN0YXRlbWVudCAoY292ZXJlZCBpbiB0aGUgbmV4dCBjaGFwdGVyKS4NCiAgICAgIA0KICAgIFRoZSBiYXNpYyBzeW50YXggZm9yIGNyZWF0aW5nIGEgYnJlYWsgc3RhdGVtZW50IGluIFIgaXM6DQogICAgICANCiAgICAgIGJyZWFrDQogICAgICANCmBgYHtyfQ0KdiA8LSBjKCJIZWxsbyIsImxvb3AiKQ0KY250IDwtIDINCg0KcmVwZWF0IHsNCiAgIHByaW50KHYpDQogICBjbnQgPC0gY250ICsgMQ0KCQ0KICAgaWYoY250ID4gNSkgew0KICAgICAgYnJlYWsNCiAgIH0NCn0NCmBgYA0KDQpOZXh0IFN0YXRlbWVudA0KDQogICAgVGhlIG5leHQgc3RhdGVtZW50IGluIFIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgaXMgdXNlZnVsIHdoZW4gd2Ugd2FudCB0byBza2lwIHRoZSBjdXJyZW50IGl0ZXJhdGlvbiBvZiBhIGxvb3Agd2l0aG91dCB0ZXJtaW5hdGluZyBpdC4gT24gZW5jb3VudGVyaW5nIG5leHQsIHRoZSBSIHBhcnNlciBza2lwcyBmdXJ0aGVyIGV2YWx1YXRpb24gYW5kIHN0YXJ0cyBuZXh0IGl0ZXJhdGlvbiBvZiB0aGUgbG9vcC4NCiAgICANCiAgICBUaGUgYmFzaWMgc3ludGF4IGZvciBjcmVhdGluZyBhIG5leHQgc3RhdGVtZW50IGluIFIgaXM6DQogICAgICANCiAgICAgIG5leHQNCiAgICAgIA0KYGBge3J9DQp2IDwtIExFVFRFUlNbMTo2XQ0KZm9yICggaSBpbiB2KSB7DQogICANCiAgIGlmIChpID09ICJEIikgew0KICAgICAgbmV4dA0KICAgfQ0KICAgcHJpbnQoaSkNCn0NCmBgYA0KDQo=