Dr. Alberto Dorantes Dosamantes, Ph.D. Monterrey Tech, Queretaro
Campus Aug 8, 2022
Set up the name of your R Notebook for this workshop
Setup title and name of your Workshop
Once you have created a new R Notebook, you will see a sample R
Notebook document. You must DELETE all the lines of this sample document
except the first lines related to title and output. As title, write the
workshop # and course, and add a new line with your name. You have to
end up with something like:
title: “Workshop 1, Financial Programming”
author: YourName
output: html_notebook
Now you are ready to continue writing your first R Notebook.
You can start writing your own notes/explanations we cover in this
workshop. When you need to write lines of R Code, you need to click
Insert at the top of the RStudio Window and select R. Immediately a
chunk of R code will be set up to start writing your R code. You can
execute this piece of code by clicking in the play button (green
triangle).
Note that you can open and edit several R Notebooks, which will
appear as tabs at the top of the window. You can visualize the output
(results) of your code in the console, located at the bottom of the
window. Also, the created variables are listed in the environment,
located in the top-right pane. The bottom-right pane shows the files,
plots, installed packages, help, and viewer tabs.
Save your R Notebook file as W1-YourName.Rmd. Go to the File menu and
select Save As.
Done
Introduction to programming languages
What is a programming language? A programming language is a set of
commands or instructions that are executed by the computer usually to
automate repetitive tasks or functions that usually require intensive
data processing. Programming languages are also used to develop computer
applications. In Economics and Finance, we use programming languages
mainly to do the following:
data input and/or data collection, data cleaning, data management
including data transformation and data merging, data storing, data
processing that includes descriptive analytics and predictive models,
and finally information delivery that includes reports or documents
usually with summary tables and graphs. You can effectively perform
these programming processes in R. One of the great advantages of R as
oppose to other statistical software is that R is free. Its distribution
is available under the GNU General Public License. The R language was
initially designed for statistically computing. R is maintained by the
scientific community and its popularity has increased substantially in
recent years since the initial version released in 1995. Nowadays, both
Python and R are the two more popular programming languages for Data
Science around the world.
4.1 R objects
In R, any piece of information is stored into an object. A computer
object takes bits of memory from your computer so the information is
available to be read, manipulated, analysed, exported or deleted. In
general terms, all you have to understand is that R will take those
objects and perform the tasks indicated in the code using the data
stored in the object.
In R, each object is considered to be of a specific data class. Each
* R class* has its own data structure and attributes. In other
programming languages any piece of data is called a variable.
4.2 Assigning values to an object
R at its simplest form can be used as a calculator. We can simply
write an operation at the R console to receive the answer:
5+7
[1] 12
R can do much more than a simple calculator. We can save or assign
the result of an expression into an object (variable). We can use the
assignment operator <-, also known as the back arrow operator to
assign a value into a variable:
x <- 5+7
To view the contents of the new object x, just type x and press Enter
in the Console:
x
[1] 12
R replies printing out in the screen the value of the x variable,
which in this example is equal to 12. We can do more calculations using
x and other numbers. For example:
z <- x+5
In this case we assigned the value of x plus 5 to a new variable z.
An interesting feature of R is that it uses vectors to store single
values such as x and z.
When you try to see the content of x you can see the number 1 between
squared brackets []:
x
[1] 12
The [1] means that x is a vector of only 1 element that in this case
is equal to 12. However, a vector can have more than one element, each
of those can be of any of the following atomic classes: numeric,
character, integer, logical (true/false) or complex.
Besides vectors, R also uses matrices, data frames and lists. We
examine those type of objects in the second part of this document.
5.1 Vectors
A vector is a collection of values. The values of a vector can be of
any of the following atomic classes: numeric, character, integer,
logical (true/false) or complex. Each vector can have only one type of
data class.
Now we will create a small collection of numbers in a numeric vector.
A numeric vector is the simplest type of data structure in R. In fact,
even a single number is considered a vector of length one.
To create a vector we can use the function c() that means combine We
can define a vector with the numbers 1, 2 and 3 using the c() function
and separating each element by a comma as shown below.
y <- c(1,2,3)
y
[1] 1 2 3
We can also create an integer vector as follows:
y <- 1:3
y
[1] 1 2 3
We can do arithmetic operations with a numeric vector. For example,
we can add a number to each element of the vector and assign the result
into another numeric vector as follows:
z <- y+1
z
[1] 2 3 4
Also you can also make arithmetic operations with two or more
vectors:
w <- z-y
w
[1] 1 1 1
When given two vectors of the same length, R performs the specified
arithmetic operation (+, -, *, etc.) element-by-element. You can even
combine vectors to create new ones:
w <- c(y,"a","b")
In this case we have added two letters into the integer vector y. The
final vector w, result of this operation, will be a character vector, so
each number of the y vector was converted into a string or character
value. You can observe that the elements of this new vectors are
character since each value has quotes. A vector in R can only contain
objects of the same class, in this case it transforms from numeric to
character:
class(y)
[1] "integer"
class(w)
[1] "character"
The elements of a vector are R objects, so these element are of any
of five basic or atomic data classes:
- Numeric:
x <- c(2,3.43,4.21)
- Character:
x <- c("2", "hola", "4 gatos")
- Integer
x <- c(2L,3L,4L)
- logical (True/False)
x <- c(T,FALSE,F,TRUE)
- Complex (imaginary numbers)
z <- c(5i,4i)
Now we will learn how to access a particular element of a vector.
First we will create a vector with numbers form 101 to 105 using the
function seq() which generates a sequence of numbers according to the
arguments in the function, in this case form 101 to 105.
vector1 <- seq(from = 101, to = 105)
vector1
[1] 101 102 103 104 105
If we want to access the third element of this vector, which is 103,
we write the element number between the operator []:
vector1[3]
[1] 103
Imagine that we want to access not only one, but several element in
the vector. This is done by indicating a vector of numbers that indicate
the element number inside the original vector. We do this as
follows:
vector1[c(1,3,5)]
[1] 101 103 105
In the case that you want to modify certain element in the existing
vector `vector1, all you have to do is to assign <- the new value to
the specific vector location indicated by the value inside the square
brackets operator [].
The example below can be read as follows: the second element of the
vector vector1 gets the value 109.
vector1[2] <- 109
vector1
[1] 101 109 103 104 105
R considers all vectors as VERTICAL vectors. However, when you
display a vector on the screen you will see it as HORIZONTAL. Let’s see
an example:
vector2 <- seq(1,100)
vector2
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14
[15] 15 16 17 18 19 20 21 22 23 24 25 26 27 28
[29] 29 30 31 32 33 34 35 36 37 38 39 40 41 42
[43] 43 44 45 46 47 48 49 50 51 52 53 54 55 56
[57] 57 58 59 60 61 62 63 64 65 66 67 68 69 70
[71] 71 72 73 74 75 76 77 78 79 80 81 82 83 84
[85] 85 86 87 88 89 90 91 92 93 94 95 96 97 98
[99] 99 100
We can see that the elements of the vector are displayed
horizontally. Why is it important to know whether a vector is vertical
or horizontal? when we do matrix operations with matrices and/or vectors
we have to know whether the vector is horizontal or vertical.
When we display a vector R always shows an index [1] indicating that
the vector starts with the element 1. If the vector has many elements
that cannot be displayed in 1 row, then the vector continues in the
following row and it display the element # in the following row as [#],
where # will be the number of the first element shown in that row.
Actually, when we declare a numaric variable with only 1 value, R
define it as a vector of 1 element. Then, the simpest R object is a
vector, no matter if it has 1 or more elements.
5.2 Matrix
Matrices are vectors with a dimension attribute. A typical matrix
object has two dimensions: rows and columns. Those dimensions define the
size of the matrix and must be defined every time you create a new
matrix object.
In order to create a matrix you can use the function matrix(), the
first attribute is the the data in your matrix, the nrow attribute is
the desired number of rows while the ncol attribute is the desired
number of columns.
matrix(1:4, nrow = 2, ncol = 2)
[,1] [,2]
[1,] 1 3
[2,] 2 4
Alternatively, you can create a matrix by joining 2 or more different
vectors, using the functions rbind() or cbind(). rbind joins to vectors
as rows while cbind combines columns. In the example below, we create
two vectors v1 and v2, each having 3 elements, then we combine them
together into a matrix.
# Create vectors
v1 <- c(1,2,3)
v2 <- c(90,91,92)
# Combine vectors as VERTICAL vectors and save as `matrix1`
matrix1 <-cbind(v1,v2)
# Print object matrix1
matrix1
v1 v2
[1,] 1 90
[2,] 2 91
[3,] 3 92
# Combine vectors as HORIZONTAL vectors and save as `matrix1`
matrix2 <-rbind(v1,v2)
# Print object matrix1
matrix2
[,1] [,2] [,3]
v1 1 2 3
v2 90 91 92
Once your matrix object has been created you can check its dimensions
by using the dim() function as shown below. The dim function returns the
number of rows and columns of your matrix.
As you would expect, for this particular example we have 3 rows and 2
columns.
dim(matrix1)
[1] 3 2
To access a certain element of a matrix we will use the square
brackets operator [] after the name. The first element before the comma
indicates the row number, while the second element the square brackets
refers to the column. This way, you can point to any specific location
in the matrix and extract the value saved on this particular location.
In the case below, we are extracting the element in the first row second
column, which corresponds to the number 90
matrix1[1,2]
v2
90
We can also refer a whole column or row simply by leaving the other
element empty. In the case we want to observe the whole second row we
just write:
matrix1[2,]
v1 v2
2 91
A very important point to note is that, just as vectors, matrices can
only store one class of object, i.e. numeric objects. In other words,
you can not have both, string class elements and numeric class elements
in the same matrix. To do this, we will use a different class of object
called data frame.
5.3 Data Frames
Data frames are used to store tabular data. A data frame is like an
Excel spreadsheet kind of table. However, unlike matrices, data frames
can store different classes of objects in different columns.
You can create a data frame using the data.frame() function. In the
example shown below, we combine both, string and numeric data in the
same x object.
x <- data.frame(Student = c("Paco","Raul","Beto"), Grade = c(9, 5, 7))
x
As we did before with matrices, you can also see the dimensions of
the data frame using the dim() function.
dim(x)
[1] 3 2
You can also create a data frame object by transforming an existing
matrix via the function as.data.frame(). In the example below, we first
create a matrix called my.matrix and then transform it to be my.df. In
the third line of code we check whether the new object is actually a
data.frame class object.
my.matrix <- matrix(1:4, nrow = 2, ncol = 2)
my.df <- as.data.frame(my.matrix)
class(my.df)
[1] "data.frame"
The rbind or cbind functions can be also used to append rows or
columns to an existing data frame. In the example below I will add a new
column to the data frame x previously created, but first I will create a
copy and call it grades.df just to make it more descriptive.
# Make a copy
grades.df <- x
grades.df <- cbind(grades.df, c("Pass", "Fail", "Pass"))
grades.df
As we can see the first two columns have a name, but the third does
not mean anything. Data frames, as any object in R have attributes:
attributes(grades.df)
$names
[1] "Student"
[2] "Grade"
[3] "c(\"Pass\", \"Fail\", \"Pass\")"
$class
[1] "data.frame"
$row.names
[1] 1 2 3
In this case the data frame has 3 attributes: $names, $row.names and
$class. We can not only see those but manipulate them. The $names
attribute stores the names of the columns in your data frame, so if you
do not like the names of your columns you can always change them using
the colnames() function as follows:
colnames(grades.df) <- c("Student","Grade","Status")
You see the changes you have made, you can always print out the
attributes of the data frame:
attributes(grades.df)
$names
[1] "Student" "Grade" "Status"
$class
[1] "data.frame"
$row.names
[1] 1 2 3
Or simply get the names of the columns or rows using the functions
colnames() or rownames().
colnames(grades.df)
[1] "Student" "Grade" "Status"
rownames(grades.df)
[1] "1" "2" "3"
Changing the name of one of the column is easy, but now imagine that
we had 100 or 1,000 columns, writing all the column names again is not
practical. So we need to learn how to modify only one, to do this we
have to know how to pinpoint the element we want to modify, so again we
use the squared brackets [] to point to the specific location of the
column that will be renamed. Let’s say you want to modify the name of
the third column Status to be Pass-Fail:
colnames(grades.df)[3] <- "Pass-Fail"
# See the changes
colnames(grades.df)
[1] "Student" "Grade" "Pass-Fail"
The list data structure will be covered in the following
workshop.
LS0tCnRpdGxlOiAiRmluYW5jZSBQcm9ncmFtbWluZyAtIFdvcmtzaG9wIDEiCmF1dGhvcjogU3RlZmFuIFNjaHdlaXR6ZXIgLSBBMDEyMDk3NTUKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpEci4gQWxiZXJ0byBEb3JhbnRlcyBEb3NhbWFudGVzLCBQaC5ELgpNb250ZXJyZXkgVGVjaCwgUXVlcmV0YXJvIENhbXB1cwpBdWcgOCwgMjAyMgoKIyMgQWJzdHJhY3QKSW4gdGhpcyB3b3Jrc2hvcCB3ZSB3aWxsIGxlYXJuIHdoYXQgaXMgYSBwcm9ncmFtbWluZyBsYW5ndWFnZSBhbmQgdGhlIGJhc2ljcyBvZiBvYmplY3RzIGFuZCBkYXRhIHN0cnVjdHVyZXMgaW4gUi4KCiMgTGVhcm5pbmcgT2JqZWN0aXZlcwoxLiBVbmRlcnN0YW5kIHdoYXQgYSBwcm9ncmFtbWluZyBsYW5ndWFnZSBpcy4KMi4gVW5kZXJzdGFuZCB0aGUgd2F5IFIgbWFuYWdlcyBkYXRhOiB3aGF0IGlzIGFuIFIgb2JqZWN0LCBhbmQgd2hhdCBhcmUgdGhlIG1haW4gKGF0b21pYykgZGF0YSBjbGFzc2VzIG9mIFIgb2JqZWN0cy4KMy4gVW5kZXJzdGFuZCB0aGUgYmFzaWMgUiBkYXRhIHN0cnVjdHVyZXMgc3VjaCBhcyB2ZWN0b3JzLCBtYXRyaWNlcyBhbmQgZGF0YSBmcmFtZXMuCgojIFNldCB1cCB0aGUgbmFtZSBvZiB5b3VyIFIgTm90ZWJvb2sgZm9yIHRoaXMgd29ya3Nob3AKU2V0dXAgdGl0bGUgYW5kIG5hbWUgb2YgeW91ciBXb3Jrc2hvcAoKT25jZSB5b3UgaGF2ZSBjcmVhdGVkIGEgbmV3IFIgTm90ZWJvb2ssIHlvdSB3aWxsIHNlZSBhIHNhbXBsZSBSIE5vdGVib29rIGRvY3VtZW50LiBZb3UgbXVzdCBERUxFVEUgYWxsIHRoZSBsaW5lcyBvZiB0aGlzIHNhbXBsZSBkb2N1bWVudCBleGNlcHQgdGhlIGZpcnN0IGxpbmVzIHJlbGF0ZWQgdG8gdGl0bGUgYW5kIG91dHB1dC4gQXMgdGl0bGUsIHdyaXRlIHRoZSB3b3Jrc2hvcCAjIGFuZCBjb3Vyc2UsIGFuZCBhZGQgYSBuZXcgbGluZSB3aXRoIHlvdXIgbmFtZS4gWW91IGhhdmUgdG8gZW5kIHVwIHdpdGggc29tZXRoaW5nIGxpa2U6Cgp0aXRsZTog4oCcV29ya3Nob3AgMSwgRmluYW5jaWFsIFByb2dyYW1taW5n4oCdCgphdXRob3I6IFlvdXJOYW1lCgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKCk5vdyB5b3UgYXJlIHJlYWR5IHRvIGNvbnRpbnVlIHdyaXRpbmcgeW91ciBmaXJzdCBSIE5vdGVib29rLgoKWW91IGNhbiBzdGFydCB3cml0aW5nIHlvdXIgb3duIG5vdGVzL2V4cGxhbmF0aW9ucyB3ZSBjb3ZlciBpbiB0aGlzIHdvcmtzaG9wLiBXaGVuIHlvdSBuZWVkIHRvIHdyaXRlIGxpbmVzIG9mIFIgQ29kZSwgeW91IG5lZWQgdG8gY2xpY2sgSW5zZXJ0IGF0IHRoZSB0b3Agb2YgdGhlIFJTdHVkaW8gV2luZG93IGFuZCBzZWxlY3QgUi4gSW1tZWRpYXRlbHkgYSBjaHVuayBvZiBSIGNvZGUgd2lsbCBiZSBzZXQgdXAgdG8gc3RhcnQgd3JpdGluZyB5b3VyIFIgY29kZS4gWW91IGNhbiBleGVjdXRlIHRoaXMgcGllY2Ugb2YgY29kZSBieSBjbGlja2luZyBpbiB0aGUgcGxheSBidXR0b24gKGdyZWVuIHRyaWFuZ2xlKS4KCk5vdGUgdGhhdCB5b3UgY2FuIG9wZW4gYW5kIGVkaXQgc2V2ZXJhbCBSIE5vdGVib29rcywgd2hpY2ggd2lsbCBhcHBlYXIgYXMgdGFicyBhdCB0aGUgdG9wIG9mIHRoZSB3aW5kb3cuIFlvdSBjYW4gdmlzdWFsaXplIHRoZSBvdXRwdXQgKHJlc3VsdHMpIG9mIHlvdXIgY29kZSBpbiB0aGUgY29uc29sZSwgbG9jYXRlZCBhdCB0aGUgYm90dG9tIG9mIHRoZSB3aW5kb3cuIEFsc28sIHRoZSBjcmVhdGVkIHZhcmlhYmxlcyBhcmUgbGlzdGVkIGluIHRoZSBlbnZpcm9ubWVudCwgbG9jYXRlZCBpbiB0aGUgdG9wLXJpZ2h0IHBhbmUuIFRoZSBib3R0b20tcmlnaHQgcGFuZSBzaG93cyB0aGUgZmlsZXMsIHBsb3RzLCBpbnN0YWxsZWQgcGFja2FnZXMsIGhlbHAsIGFuZCB2aWV3ZXIgdGFicy4KClNhdmUgeW91ciBSIE5vdGVib29rIGZpbGUgYXMgVzEtWW91ck5hbWUuUm1kLiBHbyB0byB0aGUgRmlsZSBtZW51IGFuZCBzZWxlY3QgU2F2ZSBBcy4KCkRvbmUgCgojIEludHJvZHVjdGlvbiB0byBwcm9ncmFtbWluZyBsYW5ndWFnZXMKCldoYXQgaXMgYSBwcm9ncmFtbWluZyBsYW5ndWFnZT8gQSBwcm9ncmFtbWluZyBsYW5ndWFnZSBpcyBhIHNldCBvZiBjb21tYW5kcyBvciBpbnN0cnVjdGlvbnMgdGhhdCBhcmUgZXhlY3V0ZWQgYnkgdGhlIGNvbXB1dGVyIHVzdWFsbHkgdG8gYXV0b21hdGUgcmVwZXRpdGl2ZSB0YXNrcyBvciBmdW5jdGlvbnMgdGhhdCB1c3VhbGx5IHJlcXVpcmUgaW50ZW5zaXZlIGRhdGEgcHJvY2Vzc2luZy4gUHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIGFyZSBhbHNvIHVzZWQgdG8gZGV2ZWxvcCBjb21wdXRlciBhcHBsaWNhdGlvbnMuIEluIEVjb25vbWljcyBhbmQgRmluYW5jZSwgd2UgdXNlIHByb2dyYW1taW5nIGxhbmd1YWdlcyBtYWlubHkgdG8gZG8gdGhlIGZvbGxvd2luZzoKCmRhdGEgaW5wdXQgYW5kL29yIGRhdGEgY29sbGVjdGlvbiwKZGF0YSBjbGVhbmluZywKZGF0YSBtYW5hZ2VtZW50IGluY2x1ZGluZyBkYXRhIHRyYW5zZm9ybWF0aW9uIGFuZCBkYXRhIG1lcmdpbmcsCmRhdGEgc3RvcmluZywKZGF0YSBwcm9jZXNzaW5nIHRoYXQgaW5jbHVkZXMgZGVzY3JpcHRpdmUgYW5hbHl0aWNzIGFuZCBwcmVkaWN0aXZlIG1vZGVscywgYW5kIGZpbmFsbHkKaW5mb3JtYXRpb24gZGVsaXZlcnkgdGhhdCBpbmNsdWRlcyByZXBvcnRzIG9yIGRvY3VtZW50cyB1c3VhbGx5IHdpdGggc3VtbWFyeSB0YWJsZXMgYW5kIGdyYXBocy4KWW91IGNhbiBlZmZlY3RpdmVseSBwZXJmb3JtIHRoZXNlIHByb2dyYW1taW5nIHByb2Nlc3NlcyBpbiBSLgpPbmUgb2YgdGhlIGdyZWF0IGFkdmFudGFnZXMgb2YgUiBhcyBvcHBvc2UgdG8gb3RoZXIgc3RhdGlzdGljYWwgc29mdHdhcmUgaXMgdGhhdCBSIGlzIGZyZWUuIEl0cyBkaXN0cmlidXRpb24gaXMgYXZhaWxhYmxlIHVuZGVyIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZS4gVGhlIFIgbGFuZ3VhZ2Ugd2FzIGluaXRpYWxseSBkZXNpZ25lZCBmb3Igc3RhdGlzdGljYWxseSBjb21wdXRpbmcuIFIgaXMgbWFpbnRhaW5lZCBieSB0aGUgc2NpZW50aWZpYyBjb21tdW5pdHkgYW5kIGl0cyBwb3B1bGFyaXR5IGhhcyBpbmNyZWFzZWQgc3Vic3RhbnRpYWxseSBpbiByZWNlbnQgeWVhcnMgc2luY2UgdGhlIGluaXRpYWwgdmVyc2lvbiByZWxlYXNlZCBpbiAxOTk1LiBOb3dhZGF5cywgYm90aCBQeXRob24gYW5kIFIgYXJlIHRoZSB0d28gbW9yZSBwb3B1bGFyIHByb2dyYW1taW5nIGxhbmd1YWdlcyBmb3IgRGF0YSBTY2llbmNlIGFyb3VuZCB0aGUgd29ybGQuCgojIyA0LjEgUiBvYmplY3RzCgpJbiBSLCBhbnkgcGllY2Ugb2YgaW5mb3JtYXRpb24gaXMgc3RvcmVkIGludG8gYW4gb2JqZWN0LiBBIGNvbXB1dGVyIG9iamVjdCB0YWtlcyBiaXRzIG9mIG1lbW9yeSBmcm9tIHlvdXIgY29tcHV0ZXIgc28gdGhlIGluZm9ybWF0aW9uIGlzIGF2YWlsYWJsZSB0byBiZSByZWFkLCBtYW5pcHVsYXRlZCwgYW5hbHlzZWQsIGV4cG9ydGVkIG9yIGRlbGV0ZWQuIEluIGdlbmVyYWwgdGVybXMsIGFsbCB5b3UgaGF2ZSB0byB1bmRlcnN0YW5kIGlzIHRoYXQgUiB3aWxsIHRha2UgdGhvc2Ugb2JqZWN0cyBhbmQgcGVyZm9ybSB0aGUgdGFza3MgaW5kaWNhdGVkIGluIHRoZSBjb2RlIHVzaW5nIHRoZSBkYXRhIHN0b3JlZCBpbiB0aGUgb2JqZWN0LgoKSW4gUiwgZWFjaCBvYmplY3QgaXMgY29uc2lkZXJlZCB0byBiZSBvZiBhIHNwZWNpZmljIGRhdGEgY2xhc3MuIEVhY2ggKiBSIGNsYXNzKiBoYXMgaXRzIG93biBkYXRhIHN0cnVjdHVyZSBhbmQgYXR0cmlidXRlcy4gSW4gb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIGFueSBwaWVjZSBvZiBkYXRhIGlzIGNhbGxlZCBhIHZhcmlhYmxlLgoKIyMgNC4yIEFzc2lnbmluZyB2YWx1ZXMgdG8gYW4gb2JqZWN0CgpSIGF0IGl0cyBzaW1wbGVzdCBmb3JtIGNhbiBiZSB1c2VkIGFzIGEgY2FsY3VsYXRvci4gV2UgY2FuIHNpbXBseSB3cml0ZSBhbiBvcGVyYXRpb24gYXQgdGhlIFIgY29uc29sZSB0byByZWNlaXZlIHRoZSBhbnN3ZXI6CgpgYGB7cn0KNSs3CmBgYApSIGNhbiBkbyBtdWNoIG1vcmUgdGhhbiBhIHNpbXBsZSBjYWxjdWxhdG9yLiBXZSBjYW4gc2F2ZSBvciBhc3NpZ24gdGhlIHJlc3VsdCBvZiBhbiBleHByZXNzaW9uIGludG8gYW4gb2JqZWN0ICh2YXJpYWJsZSkuIFdlIGNhbiB1c2UgdGhlIGFzc2lnbm1lbnQgb3BlcmF0b3IgPC0sIGFsc28ga25vd24gYXMgdGhlIGJhY2sgYXJyb3cgb3BlcmF0b3IgdG8gYXNzaWduIGEgdmFsdWUgaW50byBhIHZhcmlhYmxlOgoKYGBge3J9CnggPC0gNSs3CmBgYAoKVG8gdmlldyB0aGUgY29udGVudHMgb2YgdGhlIG5ldyBvYmplY3QgeCwganVzdCB0eXBlIHggYW5kIHByZXNzIEVudGVyIGluIHRoZSBDb25zb2xlOgoKYGBge3J9CngKYGBgClIgcmVwbGllcyBwcmludGluZyBvdXQgaW4gdGhlIHNjcmVlbiB0aGUgdmFsdWUgb2YgdGhlIHggdmFyaWFibGUsIHdoaWNoIGluIHRoaXMgZXhhbXBsZSBpcyBlcXVhbCB0byAxMi4gV2UgY2FuIGRvIG1vcmUgY2FsY3VsYXRpb25zIHVzaW5nIHggYW5kIG90aGVyIG51bWJlcnMuIEZvciBleGFtcGxlOgoKYGBge3J9CnogPC0geCs1CmBgYAoKSW4gdGhpcyBjYXNlIHdlIGFzc2lnbmVkIHRoZSB2YWx1ZSBvZiB4IHBsdXMgNSB0byBhIG5ldyB2YXJpYWJsZSB6LiBBbiBpbnRlcmVzdGluZyBmZWF0dXJlIG9mIFIgaXMgdGhhdCBpdCB1c2VzIHZlY3RvcnMgdG8gc3RvcmUgc2luZ2xlIHZhbHVlcyBzdWNoIGFzIHggYW5kIHouCgpXaGVuIHlvdSB0cnkgdG8gc2VlIHRoZSBjb250ZW50IG9mIHggeW91IGNhbiBzZWUgdGhlIG51bWJlciAxIGJldHdlZW4gc3F1YXJlZCBicmFja2V0cyBbXToKCmBgYHtyfQp4CmBgYAoKVGhlIFsxXSBtZWFucyB0aGF0IHggaXMgYSB2ZWN0b3Igb2Ygb25seSAxIGVsZW1lbnQgdGhhdCBpbiB0aGlzIGNhc2UgaXMgZXF1YWwgdG8gMTIuIEhvd2V2ZXIsIGEgdmVjdG9yIGNhbiBoYXZlIG1vcmUgdGhhbiBvbmUgZWxlbWVudCwgZWFjaCBvZiB0aG9zZSBjYW4gYmUgb2YgYW55IG9mIHRoZSBmb2xsb3dpbmcgYXRvbWljIGNsYXNzZXM6IG51bWVyaWMsIGNoYXJhY3RlciwgaW50ZWdlciwgbG9naWNhbCAodHJ1ZS9mYWxzZSkgb3IgY29tcGxleC4KCkJlc2lkZXMgdmVjdG9ycywgUiBhbHNvIHVzZXMgbWF0cmljZXMsIGRhdGEgZnJhbWVzIGFuZCBsaXN0cy4gV2UgZXhhbWluZSB0aG9zZSB0eXBlIG9mIG9iamVjdHMgaW4gdGhlIHNlY29uZCBwYXJ0IG9mIHRoaXMgZG9jdW1lbnQuCgojIERhdGEgU3RydWN0dXJlcwoKTm93IHdlIHdpbGwgbGVhcm4gYWJvdXQgZGF0YSBzdHJ1Y3R1cmVzIGluIFIuIFRoZSBtb3N0IGNvbW1vbiBkYXRhIHN0cnVjdHVyZXMgYXJlOgoKVmVjdG9ycwpNYXRyaXgKRGF0YSBGcmFtZQpMaXN0cwoKIyA1LjEgVmVjdG9ycwpBIHZlY3RvciBpcyBhIGNvbGxlY3Rpb24gb2YgdmFsdWVzLiBUaGUgdmFsdWVzIG9mIGEgdmVjdG9yIGNhbiBiZSBvZiBhbnkgb2YgdGhlIGZvbGxvd2luZyBhdG9taWMgY2xhc3NlczogbnVtZXJpYywgY2hhcmFjdGVyLCBpbnRlZ2VyLCBsb2dpY2FsICh0cnVlL2ZhbHNlKSBvciBjb21wbGV4LiBFYWNoIHZlY3RvciBjYW4gaGF2ZSBvbmx5IG9uZSB0eXBlIG9mIGRhdGEgY2xhc3MuCgpOb3cgd2Ugd2lsbCBjcmVhdGUgYSBzbWFsbCBjb2xsZWN0aW9uIG9mIG51bWJlcnMgaW4gYSBudW1lcmljIHZlY3Rvci4gQSBudW1lcmljIHZlY3RvciBpcyB0aGUgc2ltcGxlc3QgdHlwZSBvZiBkYXRhIHN0cnVjdHVyZSBpbiBSLiBJbiBmYWN0LCBldmVuIGEgc2luZ2xlIG51bWJlciBpcyBjb25zaWRlcmVkIGEgdmVjdG9yIG9mIGxlbmd0aCBvbmUuCgpUbyBjcmVhdGUgYSB2ZWN0b3Igd2UgY2FuIHVzZSB0aGUgZnVuY3Rpb24gYygpIHRoYXQgbWVhbnMgY29tYmluZSBXZSBjYW4gZGVmaW5lIGEgdmVjdG9yIHdpdGggdGhlIG51bWJlcnMgMSwgMiBhbmQgMyB1c2luZyB0aGUgYygpIGZ1bmN0aW9uIGFuZCBzZXBhcmF0aW5nIGVhY2ggZWxlbWVudCBieSBhIGNvbW1hIGFzIHNob3duIGJlbG93LgoKYGBge3J9CnkgPC0gYygxLDIsMykKeQpgYGAKCldlIGNhbiBhbHNvIGNyZWF0ZSBhbiBpbnRlZ2VyIHZlY3RvciBhcyBmb2xsb3dzOgoKYGBge3J9CnkgPC0gMTozCnkKYGBgCgpXZSBjYW4gZG8gYXJpdGhtZXRpYyBvcGVyYXRpb25zIHdpdGggYSBudW1lcmljIHZlY3Rvci4gRm9yIGV4YW1wbGUsIHdlIGNhbiBhZGQgYSBudW1iZXIgdG8gZWFjaCBlbGVtZW50IG9mIHRoZSB2ZWN0b3IgYW5kIGFzc2lnbiB0aGUgcmVzdWx0IGludG8gYW5vdGhlciBudW1lcmljIHZlY3RvciBhcyBmb2xsb3dzOgoKYGBge3J9CnogPC0geSsxCnoKYGBgCgpBbHNvIHlvdSBjYW4gYWxzbyBtYWtlIGFyaXRobWV0aWMgb3BlcmF0aW9ucyB3aXRoIHR3byBvciBtb3JlIHZlY3RvcnM6CgpgYGB7cn0KdyA8LSB6LXkKdwpgYGAKV2hlbiBnaXZlbiB0d28gdmVjdG9ycyBvZiB0aGUgc2FtZSBsZW5ndGgsIFIgcGVyZm9ybXMgdGhlIHNwZWNpZmllZCBhcml0aG1ldGljIG9wZXJhdGlvbiAoKywgLSwgKiwgZXRjLikgZWxlbWVudC1ieS1lbGVtZW50LiBZb3UgY2FuIGV2ZW4gY29tYmluZSB2ZWN0b3JzIHRvIGNyZWF0ZSBuZXcgb25lczoKCmBgYHtyfQp3IDwtIGMoeSwiYSIsImIiKQpgYGAKCkluIHRoaXMgY2FzZSB3ZSBoYXZlIGFkZGVkIHR3byBsZXR0ZXJzIGludG8gdGhlIGludGVnZXIgdmVjdG9yIHkuIFRoZSBmaW5hbCB2ZWN0b3IgdywgcmVzdWx0IG9mIHRoaXMgb3BlcmF0aW9uLCB3aWxsIGJlIGEgY2hhcmFjdGVyIHZlY3Rvciwgc28gZWFjaCBudW1iZXIgb2YgdGhlIHkgdmVjdG9yIHdhcyBjb252ZXJ0ZWQgaW50byBhIHN0cmluZyBvciBjaGFyYWN0ZXIgdmFsdWUuIFlvdSBjYW4gb2JzZXJ2ZSB0aGF0IHRoZSBlbGVtZW50cyBvZiB0aGlzIG5ldyB2ZWN0b3JzIGFyZSBjaGFyYWN0ZXIgc2luY2UgZWFjaCB2YWx1ZSBoYXMgcXVvdGVzLiBBIHZlY3RvciBpbiBSIGNhbiBvbmx5IGNvbnRhaW4gb2JqZWN0cyBvZiB0aGUgc2FtZSBjbGFzcywgaW4gdGhpcyBjYXNlIGl0IHRyYW5zZm9ybXMgZnJvbSBudW1lcmljIHRvIGNoYXJhY3RlcjoKCmBgYHtyfQpjbGFzcyh5KQpgYGAKCmBgYHtyfQpjbGFzcyh3KQpgYGAKVGhlIGVsZW1lbnRzIG9mIGEgdmVjdG9yIGFyZSBSIG9iamVjdHMsIHNvIHRoZXNlIGVsZW1lbnQgYXJlIG9mIGFueSBvZiBmaXZlIGJhc2ljIG9yIGF0b21pYyBkYXRhIGNsYXNzZXM6CgoxLiBOdW1lcmljOgpgYGB7cn0KeCA8LSBjKDIsMy40Myw0LjIxKQpgYGAKCjIuIENoYXJhY3RlcjoKYGBge3J9CnggPC0gYygiMiIsICJob2xhIiwgIjQgZ2F0b3MiKQpgYGAKCjMuIEludGVnZXIKYGBge3J9CnggPC0gYygyTCwzTCw0TCkKYGBgCgo0LiBsb2dpY2FsIChUcnVlL0ZhbHNlKQpgYGB7cn0KeCA8LSBjKFQsRkFMU0UsRixUUlVFKQpgYGAKCjUuIENvbXBsZXggKGltYWdpbmFyeSBudW1iZXJzKQpgYGB7cn0KeiA8LSBjKDVpLDRpKQpgYGAKCk5vdyB3ZSB3aWxsIGxlYXJuIGhvdyB0byBhY2Nlc3MgYSBwYXJ0aWN1bGFyIGVsZW1lbnQgb2YgYSB2ZWN0b3IuIEZpcnN0IHdlIHdpbGwgY3JlYXRlIGEgdmVjdG9yIHdpdGggbnVtYmVycyBmb3JtIDEwMSB0byAxMDUgdXNpbmcgdGhlIGZ1bmN0aW9uIHNlcSgpIHdoaWNoIGdlbmVyYXRlcyBhIHNlcXVlbmNlIG9mIG51bWJlcnMgYWNjb3JkaW5nIHRvIHRoZSBhcmd1bWVudHMgaW4gdGhlIGZ1bmN0aW9uLCBpbiB0aGlzIGNhc2UgZm9ybSAxMDEgdG8gMTA1LgoKYGBge3J9CnZlY3RvcjEgPC0gc2VxKGZyb20gPSAxMDEsIHRvID0gMTA1KQp2ZWN0b3IxCmBgYAoKSWYgd2Ugd2FudCB0byBhY2Nlc3MgdGhlIHRoaXJkIGVsZW1lbnQgb2YgdGhpcyB2ZWN0b3IsIHdoaWNoIGlzIDEwMywgd2Ugd3JpdGUgdGhlIGVsZW1lbnQgbnVtYmVyIGJldHdlZW4gdGhlIG9wZXJhdG9yIFtdOgoKYGBge3J9CnZlY3RvcjFbM10KYGBgCkltYWdpbmUgdGhhdCB3ZSB3YW50IHRvIGFjY2VzcyBub3Qgb25seSBvbmUsIGJ1dCBzZXZlcmFsIGVsZW1lbnQgaW4gdGhlIHZlY3Rvci4gVGhpcyBpcyBkb25lIGJ5IGluZGljYXRpbmcgYSB2ZWN0b3Igb2YgbnVtYmVycyB0aGF0IGluZGljYXRlIHRoZSBlbGVtZW50IG51bWJlciBpbnNpZGUgdGhlIG9yaWdpbmFsIHZlY3Rvci4gV2UgZG8gdGhpcyBhcyBmb2xsb3dzOgpgYGB7cn0KdmVjdG9yMVtjKDEsMyw1KV0KYGBgCkluIHRoZSBjYXNlIHRoYXQgeW91IHdhbnQgdG8gbW9kaWZ5IGNlcnRhaW4gZWxlbWVudCBpbiB0aGUgZXhpc3RpbmcgdmVjdG9yIGB2ZWN0b3IxLCBhbGwgeW91IGhhdmUgdG8gZG8gaXMgdG8gYXNzaWduIDwtIHRoZSBuZXcgdmFsdWUgdG8gdGhlIHNwZWNpZmljIHZlY3RvciBsb2NhdGlvbiBpbmRpY2F0ZWQgYnkgdGhlIHZhbHVlIGluc2lkZSB0aGUgc3F1YXJlIGJyYWNrZXRzIG9wZXJhdG9yIFtdLgoKVGhlIGV4YW1wbGUgYmVsb3cgY2FuIGJlIHJlYWQgYXMgZm9sbG93czogdGhlIHNlY29uZCBlbGVtZW50IG9mIHRoZSB2ZWN0b3IgdmVjdG9yMSBnZXRzIHRoZSB2YWx1ZSAxMDkuCgpgYGB7cn0KdmVjdG9yMVsyXSA8LSAxMDkKdmVjdG9yMQpgYGAKUiBjb25zaWRlcnMgYWxsIHZlY3RvcnMgYXMgVkVSVElDQUwgdmVjdG9ycy4gSG93ZXZlciwgd2hlbiB5b3UgZGlzcGxheSBhIHZlY3RvciBvbiB0aGUgc2NyZWVuIHlvdSB3aWxsIHNlZSBpdCBhcyBIT1JJWk9OVEFMLiBMZXTigJlzIHNlZSBhbiBleGFtcGxlOgoKYGBge3J9CnZlY3RvcjIgPC0gc2VxKDEsMTAwKQp2ZWN0b3IyCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSBlbGVtZW50cyBvZiB0aGUgdmVjdG9yIGFyZSBkaXNwbGF5ZWQgaG9yaXpvbnRhbGx5LiBXaHkgaXMgaXQgaW1wb3J0YW50IHRvIGtub3cgd2hldGhlciBhIHZlY3RvciBpcyB2ZXJ0aWNhbCBvciBob3Jpem9udGFsPyB3aGVuIHdlIGRvIG1hdHJpeCBvcGVyYXRpb25zIHdpdGggbWF0cmljZXMgYW5kL29yIHZlY3RvcnMgd2UgaGF2ZSB0byBrbm93IHdoZXRoZXIgdGhlIHZlY3RvciBpcyBob3Jpem9udGFsIG9yIHZlcnRpY2FsLgoKV2hlbiB3ZSBkaXNwbGF5IGEgdmVjdG9yIFIgYWx3YXlzIHNob3dzIGFuIGluZGV4IFsxXSBpbmRpY2F0aW5nIHRoYXQgdGhlIHZlY3RvciBzdGFydHMgd2l0aCB0aGUgZWxlbWVudCAxLiBJZiB0aGUgdmVjdG9yIGhhcyBtYW55IGVsZW1lbnRzIHRoYXQgY2Fubm90IGJlIGRpc3BsYXllZCBpbiAxIHJvdywgdGhlbiB0aGUgdmVjdG9yIGNvbnRpbnVlcyBpbiB0aGUgZm9sbG93aW5nIHJvdyBhbmQgaXQgZGlzcGxheSB0aGUgZWxlbWVudCAjIGluIHRoZSBmb2xsb3dpbmcgcm93IGFzIFsjXSwgd2hlcmUgIyB3aWxsIGJlIHRoZSBudW1iZXIgb2YgdGhlIGZpcnN0IGVsZW1lbnQgc2hvd24gaW4gdGhhdCByb3cuCgpBY3R1YWxseSwgd2hlbiB3ZSBkZWNsYXJlIGEgbnVtYXJpYyB2YXJpYWJsZSB3aXRoIG9ubHkgMSB2YWx1ZSwgUiBkZWZpbmUgaXQgYXMgYSB2ZWN0b3Igb2YgMSBlbGVtZW50LiBUaGVuLCB0aGUgc2ltcGVzdCBSIG9iamVjdCBpcyBhIHZlY3Rvciwgbm8gbWF0dGVyIGlmIGl0IGhhcyAxIG9yIG1vcmUgZWxlbWVudHMuCgojIyA1LjIgTWF0cml4Ck1hdHJpY2VzIGFyZSB2ZWN0b3JzIHdpdGggYSBkaW1lbnNpb24gYXR0cmlidXRlLiBBIHR5cGljYWwgbWF0cml4IG9iamVjdCBoYXMgdHdvIGRpbWVuc2lvbnM6IHJvd3MgYW5kIGNvbHVtbnMuIFRob3NlIGRpbWVuc2lvbnMgZGVmaW5lIHRoZSBzaXplIG9mIHRoZSBtYXRyaXggYW5kIG11c3QgYmUgZGVmaW5lZCBldmVyeSB0aW1lIHlvdSBjcmVhdGUgYSBuZXcgbWF0cml4IG9iamVjdC4KCkluIG9yZGVyIHRvIGNyZWF0ZSBhIG1hdHJpeCB5b3UgY2FuIHVzZSB0aGUgZnVuY3Rpb24gbWF0cml4KCksIHRoZSBmaXJzdCBhdHRyaWJ1dGUgaXMgdGhlIHRoZSBkYXRhIGluIHlvdXIgbWF0cml4LCB0aGUgbnJvdyBhdHRyaWJ1dGUgaXMgdGhlIGRlc2lyZWQgbnVtYmVyIG9mIHJvd3Mgd2hpbGUgdGhlIG5jb2wgYXR0cmlidXRlIGlzIHRoZSBkZXNpcmVkIG51bWJlciBvZiBjb2x1bW5zLgoKYGBge3J9Cm1hdHJpeCgxOjQsIG5yb3cgPSAyLCBuY29sID0gMikKYGBgCgpBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIGNyZWF0ZSBhIG1hdHJpeCBieSBqb2luaW5nIDIgb3IgbW9yZSBkaWZmZXJlbnQgdmVjdG9ycywgdXNpbmcgdGhlIGZ1bmN0aW9ucyByYmluZCgpIG9yIGNiaW5kKCkuIHJiaW5kIGpvaW5zIHRvIHZlY3RvcnMgYXMgcm93cyB3aGlsZSBjYmluZCBjb21iaW5lcyBjb2x1bW5zLiBJbiB0aGUgZXhhbXBsZSBiZWxvdywgd2UgY3JlYXRlIHR3byB2ZWN0b3JzIHYxIGFuZCB2MiwgZWFjaCBoYXZpbmcgMyBlbGVtZW50cywgdGhlbiB3ZSBjb21iaW5lIHRoZW0gdG9nZXRoZXIgaW50byBhIG1hdHJpeC4KCmBgYHtyfQojIENyZWF0ZSB2ZWN0b3JzCnYxIDwtIGMoMSwyLDMpCnYyIDwtIGMoOTAsOTEsOTIpCgojIENvbWJpbmUgdmVjdG9ycyBhcyBWRVJUSUNBTCB2ZWN0b3JzIGFuZCBzYXZlIGFzIGBtYXRyaXgxYAptYXRyaXgxIDwtY2JpbmQodjEsdjIpCgojIFByaW50IG9iamVjdCBtYXRyaXgxCm1hdHJpeDEKYGBgCmBgYHtyfQojIENvbWJpbmUgdmVjdG9ycyBhcyBIT1JJWk9OVEFMIHZlY3RvcnMgYW5kIHNhdmUgYXMgYG1hdHJpeDFgCm1hdHJpeDIgPC1yYmluZCh2MSx2MikKCiMgUHJpbnQgb2JqZWN0IG1hdHJpeDEKbWF0cml4MgpgYGAKCk9uY2UgeW91ciBtYXRyaXggb2JqZWN0IGhhcyBiZWVuIGNyZWF0ZWQgeW91IGNhbiBjaGVjayBpdHMgZGltZW5zaW9ucyBieSB1c2luZyB0aGUgZGltKCkgZnVuY3Rpb24gYXMgc2hvd24gYmVsb3cuIFRoZSBkaW0gZnVuY3Rpb24gcmV0dXJucyB0aGUgbnVtYmVyIG9mIHJvd3MgYW5kIGNvbHVtbnMgb2YgeW91ciBtYXRyaXguCgpBcyB5b3Ugd291bGQgZXhwZWN0LCBmb3IgdGhpcyBwYXJ0aWN1bGFyIGV4YW1wbGUgd2UgaGF2ZSAzIHJvd3MgYW5kIDIgY29sdW1ucy4KYGBge3J9CmRpbShtYXRyaXgxKQpgYGAKVG8gYWNjZXNzIGEgY2VydGFpbiBlbGVtZW50IG9mIGEgbWF0cml4IHdlIHdpbGwgdXNlIHRoZSBzcXVhcmUgYnJhY2tldHMgb3BlcmF0b3IgW10gYWZ0ZXIgdGhlIG5hbWUuIFRoZSBmaXJzdCBlbGVtZW50IGJlZm9yZSB0aGUgY29tbWEgaW5kaWNhdGVzIHRoZSByb3cgbnVtYmVyLCB3aGlsZSB0aGUgc2Vjb25kIGVsZW1lbnQgdGhlIHNxdWFyZSBicmFja2V0cyByZWZlcnMgdG8gdGhlIGNvbHVtbi4gVGhpcyB3YXksIHlvdSBjYW4gcG9pbnQgdG8gYW55IHNwZWNpZmljIGxvY2F0aW9uIGluIHRoZSBtYXRyaXggYW5kIGV4dHJhY3QgdGhlIHZhbHVlIHNhdmVkIG9uIHRoaXMgcGFydGljdWxhciBsb2NhdGlvbi4gSW4gdGhlIGNhc2UgYmVsb3csIHdlIGFyZSBleHRyYWN0aW5nIHRoZSBlbGVtZW50IGluIHRoZSBmaXJzdCByb3cgc2Vjb25kIGNvbHVtbiwgd2hpY2ggY29ycmVzcG9uZHMgdG8gdGhlIG51bWJlciA5MAoKYGBge3J9Cm1hdHJpeDFbMSwyXQpgYGAKV2UgY2FuIGFsc28gcmVmZXIgYSB3aG9sZSBjb2x1bW4gb3Igcm93IHNpbXBseSBieSBsZWF2aW5nIHRoZSBvdGhlciBlbGVtZW50IGVtcHR5LiBJbiB0aGUgY2FzZSB3ZSB3YW50IHRvIG9ic2VydmUgdGhlIHdob2xlIHNlY29uZCByb3cgd2UganVzdCB3cml0ZToKYGBge3J9Cm1hdHJpeDFbMixdCmBgYApBIHZlcnkgaW1wb3J0YW50IHBvaW50IHRvIG5vdGUgaXMgdGhhdCwganVzdCBhcyB2ZWN0b3JzLCBtYXRyaWNlcyBjYW4gb25seSBzdG9yZSBvbmUgY2xhc3Mgb2Ygb2JqZWN0LCBpLmUuIG51bWVyaWMgb2JqZWN0cy4gSW4gb3RoZXIgd29yZHMsIHlvdSBjYW4gbm90IGhhdmUgYm90aCwgc3RyaW5nIGNsYXNzIGVsZW1lbnRzIGFuZCBudW1lcmljIGNsYXNzIGVsZW1lbnRzIGluIHRoZSBzYW1lIG1hdHJpeC4gVG8gZG8gdGhpcywgd2Ugd2lsbCB1c2UgYSBkaWZmZXJlbnQgY2xhc3Mgb2Ygb2JqZWN0IGNhbGxlZCBkYXRhIGZyYW1lLgoKIyMgNS4zIERhdGEgRnJhbWVzCkRhdGEgZnJhbWVzIGFyZSB1c2VkIHRvIHN0b3JlIHRhYnVsYXIgZGF0YS4gQSBkYXRhIGZyYW1lIGlzIGxpa2UgYW4gRXhjZWwgc3ByZWFkc2hlZXQga2luZCBvZiB0YWJsZS4gSG93ZXZlciwgdW5saWtlIG1hdHJpY2VzLCBkYXRhIGZyYW1lcyBjYW4gc3RvcmUgZGlmZmVyZW50IGNsYXNzZXMgb2Ygb2JqZWN0cyBpbiBkaWZmZXJlbnQgY29sdW1ucy4KCllvdSBjYW4gY3JlYXRlIGEgZGF0YSBmcmFtZSB1c2luZyB0aGUgZGF0YS5mcmFtZSgpIGZ1bmN0aW9uLiBJbiB0aGUgZXhhbXBsZSBzaG93biBiZWxvdywgd2UgY29tYmluZSBib3RoLCBzdHJpbmcgYW5kIG51bWVyaWMgZGF0YSBpbiB0aGUgc2FtZSB4IG9iamVjdC4KCmBgYHtyfQp4IDwtIGRhdGEuZnJhbWUoU3R1ZGVudCA9IGMoIlBhY28iLCJSYXVsIiwiQmV0byIpLCBHcmFkZSA9IGMoOSwgNSwgNykpCngKYGBgCgpBcyB3ZSBkaWQgYmVmb3JlIHdpdGggbWF0cmljZXMsIHlvdSBjYW4gYWxzbyBzZWUgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIGRhdGEgZnJhbWUgdXNpbmcgdGhlIGRpbSgpIGZ1bmN0aW9uLgoKYGBge3J9CmRpbSh4KQpgYGAKCllvdSBjYW4gYWxzbyBjcmVhdGUgYSBkYXRhIGZyYW1lIG9iamVjdCBieSB0cmFuc2Zvcm1pbmcgYW4gZXhpc3RpbmcgbWF0cml4IHZpYSB0aGUgZnVuY3Rpb24gYXMuZGF0YS5mcmFtZSgpLiBJbiB0aGUgZXhhbXBsZSBiZWxvdywgd2UgZmlyc3QgY3JlYXRlIGEgbWF0cml4IGNhbGxlZCBteS5tYXRyaXggYW5kIHRoZW4gdHJhbnNmb3JtIGl0IHRvIGJlIG15LmRmLiBJbiB0aGUgdGhpcmQgbGluZSBvZiBjb2RlIHdlIGNoZWNrIHdoZXRoZXIgdGhlIG5ldyBvYmplY3QgaXMgYWN0dWFsbHkgYSBkYXRhLmZyYW1lIGNsYXNzIG9iamVjdC4KCmBgYHtyfQpteS5tYXRyaXggPC0gbWF0cml4KDE6NCwgbnJvdyA9IDIsIG5jb2wgPSAyKQpteS5kZiA8LSBhcy5kYXRhLmZyYW1lKG15Lm1hdHJpeCkKY2xhc3MobXkuZGYpCmBgYApUaGUgcmJpbmQgb3IgY2JpbmQgZnVuY3Rpb25zIGNhbiBiZSBhbHNvIHVzZWQgdG8gYXBwZW5kIHJvd3Mgb3IgY29sdW1ucyB0byBhbiBleGlzdGluZyBkYXRhIGZyYW1lLiBJbiB0aGUgZXhhbXBsZSBiZWxvdyBJIHdpbGwgYWRkIGEgbmV3IGNvbHVtbiB0byB0aGUgZGF0YSBmcmFtZSB4IHByZXZpb3VzbHkgY3JlYXRlZCwgYnV0IGZpcnN0IEkgd2lsbCBjcmVhdGUgYSBjb3B5IGFuZCBjYWxsIGl0IGdyYWRlcy5kZiBqdXN0IHRvIG1ha2UgaXQgbW9yZSBkZXNjcmlwdGl2ZS4KCmBgYHtyfQojIE1ha2UgYSBjb3B5CmdyYWRlcy5kZiA8LSB4CmdyYWRlcy5kZiA8LSBjYmluZChncmFkZXMuZGYsIGMoIlBhc3MiLCAiRmFpbCIsICJQYXNzIikpCmdyYWRlcy5kZgpgYGAKCkFzIHdlIGNhbiBzZWUgdGhlIGZpcnN0IHR3byBjb2x1bW5zIGhhdmUgYSBuYW1lLCBidXQgdGhlIHRoaXJkIGRvZXMgbm90IG1lYW4gYW55dGhpbmcuIERhdGEgZnJhbWVzLCBhcyBhbnkgb2JqZWN0IGluIFIgaGF2ZSBhdHRyaWJ1dGVzOgoKYGBge3J9CmF0dHJpYnV0ZXMoZ3JhZGVzLmRmKQpgYGAKSW4gdGhpcyBjYXNlIHRoZSBkYXRhIGZyYW1lIGhhcyAzIGF0dHJpYnV0ZXM6ICRuYW1lcywgJHJvdy5uYW1lcyBhbmQgJGNsYXNzLiBXZSBjYW4gbm90IG9ubHkgc2VlIHRob3NlIGJ1dCBtYW5pcHVsYXRlIHRoZW0uIFRoZSAkbmFtZXMgYXR0cmlidXRlIHN0b3JlcyB0aGUgbmFtZXMgb2YgdGhlIGNvbHVtbnMgaW4geW91ciBkYXRhIGZyYW1lLCBzbyBpZiB5b3UgZG8gbm90IGxpa2UgdGhlIG5hbWVzIG9mIHlvdXIgY29sdW1ucyB5b3UgY2FuIGFsd2F5cyBjaGFuZ2UgdGhlbSB1c2luZyB0aGUgY29sbmFtZXMoKSBmdW5jdGlvbiBhcyBmb2xsb3dzOgoKYGBge3J9CmNvbG5hbWVzKGdyYWRlcy5kZikgPC0gYygiU3R1ZGVudCIsIkdyYWRlIiwiU3RhdHVzIikKYGBgCgpZb3Ugc2VlIHRoZSBjaGFuZ2VzIHlvdSBoYXZlIG1hZGUsIHlvdSBjYW4gYWx3YXlzIHByaW50IG91dCB0aGUgYXR0cmlidXRlcyBvZiB0aGUgZGF0YSBmcmFtZToKCmBgYHtyfQphdHRyaWJ1dGVzKGdyYWRlcy5kZikKYGBgCk9yIHNpbXBseSBnZXQgdGhlIG5hbWVzIG9mIHRoZSBjb2x1bW5zIG9yIHJvd3MgdXNpbmcgdGhlIGZ1bmN0aW9ucyBjb2xuYW1lcygpIG9yIHJvd25hbWVzKCkuCgpgYGB7cn0KY29sbmFtZXMoZ3JhZGVzLmRmKQpgYGAKYGBge3J9CnJvd25hbWVzKGdyYWRlcy5kZikKYGBgCkNoYW5naW5nIHRoZSBuYW1lIG9mIG9uZSBvZiB0aGUgY29sdW1uIGlzIGVhc3ksIGJ1dCBub3cgaW1hZ2luZSB0aGF0IHdlIGhhZCAxMDAgb3IgMSwwMDAgY29sdW1ucywgd3JpdGluZyBhbGwgdGhlIGNvbHVtbiBuYW1lcyBhZ2FpbiBpcyBub3QgcHJhY3RpY2FsLiBTbyB3ZSBuZWVkIHRvIGxlYXJuIGhvdyB0byBtb2RpZnkgb25seSBvbmUsIHRvIGRvIHRoaXMgd2UgaGF2ZSB0byBrbm93IGhvdyB0byBwaW5wb2ludCB0aGUgZWxlbWVudCB3ZSB3YW50IHRvIG1vZGlmeSwgc28gYWdhaW4gd2UgdXNlIHRoZSBzcXVhcmVkIGJyYWNrZXRzIFtdIHRvIHBvaW50IHRvIHRoZSBzcGVjaWZpYyBsb2NhdGlvbiBvZiB0aGUgY29sdW1uIHRoYXQgd2lsbCBiZSByZW5hbWVkLiBMZXTigJlzIHNheSB5b3Ugd2FudCB0byBtb2RpZnkgdGhlIG5hbWUgb2YgdGhlIHRoaXJkIGNvbHVtbiBTdGF0dXMgdG8gYmUgUGFzcy1GYWlsOgoKYGBge3J9CmNvbG5hbWVzKGdyYWRlcy5kZilbM10gPC0gIlBhc3MtRmFpbCIKCiMgU2VlIHRoZSBjaGFuZ2VzCmNvbG5hbWVzKGdyYWRlcy5kZikKYGBgClRoZSBsaXN0IGRhdGEgc3RydWN0dXJlIHdpbGwgYmUgY292ZXJlZCBpbiB0aGUgZm9sbG93aW5nIHdvcmtzaG9wLgoKCg==