Introduction to Basics
Arithmetic with R
In its most basic form, R can be used as a simple calculator. Consider the following arithmetic operators:
- Addition:
+
- Subtraction:
-
- Multiplication:
*
- Division:
/
- Exponentiation:
^
- Modulo:
%%
The last two might need some explaining:
- The
^
operator raises the number to its left to the power of the number to its right: for example 3^2
is 9.
- The modulo returns the remainder of the division of the number to the left by the number on its right, for example 5 modulo 3 or
5 %% 3
is 2.
With this knowledge, follow the instructions below to complete the exercise.
Exercise
- Type
2^5
in the editor to calculate 2 to the power 5.
- Type
28 %% 6
to calculate 28 modulo 6.
- Note how the
#
symbol is used to add comments on the R code.
# An addition
5 + 5
# A subtraction
5 - 5
# A multiplication
3 * 5
# A division
(5 + 5) / 2
# Exponentiation
# Modulo
Variable assignment
A basic concept in (statistical) programming is called a variable.
A variable allows you to store a value (e.g. 4) or an object (e.g. a function description) in R. You can then later use this variable’s name to easily access the value or the object that is stored within this variable.
You can assign a value 4 to a variable my_var
with the command
my_var <- 4
Exercise
Over to you: complete the code in the editor such that it assigns the value 42 to the variable x
in the editor. Notice that when you ask R to print x
, the value 42 appears.
# Assign the value 42 to x
x <-
# Print out the value of the variable x
x
Variable assignment (2)
Suppose you have a fruit basket with five apples. As a data analyst in training, you want to store the number of apples in a variable with the name my_apples
.
Exercise
Type the following code in the editor: my_apples <- 5
. This will assign the value 5 to my_apples
. Type: my_apples
below the second comment. This will print out the value of my_apples
. Look at the console: you see that the number 5 is printed. So R now links the variable my_apples
to the value 5.
# Assign the value 5 to the variable my_apples
# Print out the value of the variable my_apples
Variable assignment (3)
Every tasty fruit basket needs oranges, so you decide to add six oranges. As a data analyst, your reflex is to immediately create the variable my_oranges
and assign the value 6 to it. Next, you want to calculate how many pieces of fruit you have in total. Since you have given meaningful names to these values, you can now code this in a clear way:
my_apples + my_oranges
Exercise
Assign to my_oranges
the value 6. Add the variables my_apples
and my_oranges
and have R simply print the result. Assign the result of adding my_apples
and my_oranges
to a new variable my_fruit
.
# Assign a value to the variables my_apples and my_oranges
my_apples <- 5
# Add these two variables together
# Create the variable my_fruit
Apples and oranges
Common knowledge tells you not to add apples and oranges. But hey, that is what you just did, no :-)? The my_apples
and my_oranges
variables both contained a number in the previous exercise. The +
operator works with numeric variables in R. If you really tried to add “apples” and “oranges”, and assigned a text value to the variable my_oranges
(see the editor), you would be trying to assign the addition of a numeric and a character variable to the variable my_fruit
. This is not possible.
Exercise
Click ‘Run’ and read the error message. Make sure to understand why this did not work. Adjust the code so that R knows you have 6 oranges and thus a fruit basket with 11 pieces of fruit.
# Assign a value to the variable my_apples
my_apples <- 5
# Fix the assignment of my_oranges
my_oranges <- "six"
# Create the variable my_fruit and print it out
my_fruit <- my_apples + my_oranges
my_fruit
Basic data types in R
R works with numerous data types. Some of the most basic types to get started are:
- Decimals values like
4.5
are called numerics.
- Natural numbers like
4
are called integers. Integers are also numerics.
- Boolean values (
TRUE
or FALSE
) are called logical.
- Text (or string) values are called characters.
Note how the quotation marks on the right indicate that “some text” is a character.
Exercise
Change the value of the:
my_numeric
variable to 42.
my_character
variable to “universe”. Note that the quotation marks indicate that “universe” is a character.
my_logical
variable to FALSE
.
- Note that R is case sensitive!
# Change my_numeric to be 42
my_numeric <- 42.5
# Change my_character to be "universe"
my_character <- "some text"
# Change my_logical to be FALSE
my_logical <- TRUE
What’s that data type?
Do you remember that when you added 5 + "six"
, you got an error due to a mismatch in data types? You can avoid such embarrassing situations by checking the data type of a variable beforehand. You can do this with the class()
function, as the code below shows.
Exercise
Complete the code in the editor and also print out the classes of my_character
and my_logical
.
# Declare variables of different types
my_numeric <- 42
my_character <- "universe"
my_logical <- FALSE
# Check class of my_numeric
class(my_numeric)
# Check class of my_character
# Check class of my_logical
Vectors
Create a vector
Feeling lucky? You better, because this chapter takes you on a trip to the City of Sins, also known as Statisticians Paradise!
Thanks to R and your new data-analytical skills, you will learn how to uplift your performance at the tables and fire off your career as a professional gambler. This chapter will show how you can easily keep track of your betting progress and how you can do some simple analyses on past actions. Next stop, Vegas Baby… VEGAS!!
Exercise
Do you still remember what you have learned in the first chapter? Assign the value "Go!"
to the variable vegas
. Remember: R is case sensitive!
# Define the variable vegas
vegas <-
Create a vector (2)
Let us focus first!
On your way from rags to riches, you will make extensive use of vectors. Vectors are one-dimension arrays that can hold numeric data, character data, or logical data. In other words, a vector is a simple tool to store data. For example, you can store your daily gains and losses in the casinos.
In R, you create a vector with the combine function c()
. You place the vector elements separated by a comma between the parentheses. For example:
numeric_vector <- c(1, 2, 3)
character_vector <- c("a", "b", "c")
Once you have created these vectors in R, you can use them to do calculations.
Exercise
Complete the code such that boolean_vector
contains the three elements: TRUE
, FALSE
and TRUE
(in that order).
numeric_vector <- c(1, 10, 49)
character_vector <- c("a", "b", "c")
# Complete the code for boolean_vector
boolean_vector <-
Create a vector (3)
After one week in Las Vegas and still zero Ferraris in your garage, you decide that it is time to start using your data analytical superpowers.
Before doing a first analysis, you decide to first collect all the winnings and losses for the last week:
For poker_vector
:
- On Monday you won $140
- Tuesday you lost $50
- Wednesday you won $20
- Thursday you lost $120
- Friday you won $240
For roulette_vector
:
- On Monday you lost $24
- Tuesday you lost $50
- Wednesday you won $100
- Thursday you lost $350
- Friday you won $10
You only played poker and roulette, since there was a delegation of mediums that occupied the craps tables. To be able to use this data in R, you decide to create the variables poker_vector
and roulette_vector
.
Exercise
Assign the winnings/losses for roulette to the variable roulette_vector
.
# Poker winnings from Monday to Friday
poker_vector <- c(140, -50, 20, -120, 240)
# Roulette winnings from Monday to Friday
roulette_vector <-
Naming a vector
As a data analyst, it is important to have a clear view on the data that you are using. Understanding what each element refers to is therefore essential.
In the previous exercise, we created a vector with your winnings over the week. Each vector element refers to a day of the week but it is hard to tell which element belongs to which day. It would be nice if you could show that in the vector itself.
You can give a name to the elements of a vector with the names()
function. Have a look at this example:
some_vector <- c("John Doe", "poker player")
names(some_vector) <- c("Name", "Profession")
This code first creates a vector some_vector
and then gives the two elements a name. The first element is assigned the name Name
, while the second element is labeled Profession
. Printing the contents to the console yields following output:
Name Profession
"John Doe" "poker player"
Exercise
The code on the right names the elements in poker_vector
with the days of the week. Add code to do the same thing for roulette_vector
.
# Poker winnings from Monday to Friday
poker_vector <- c(140, -50, 20, -120, 240)
# Roulette winnings from Monday to Friday
roulette_vector <- c(-24, -50, 100, -350, 10)
# Assign days as names of poker_vector
names(poker_vector) <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
# Assign days as names of roulette_vectors
Naming a vector (2)
If you want to become a good statistician, you have to become lazy. (If you are already lazy, chances are high you are one of those exceptional, natural-born statistical talents.)
In the previous exercises you probably experienced that it is boring and frustrating to type and retype information such as the days of the week. However, when you look at it from a higher perspective, there is a more efficient way to do this, namely, to assign the days of the week vector to a variable!
Just like you did with your poker and roulette returns, you can also create a variable that contains the days of the week. This way you can use and re-use it.
Exercise
A variable days_vector
that contains the days of the week has already been created for you. Use days_vector
to set the names of poker_vector
and roulette_vector
.
# Poker winnings from Monday to Friday
poker_vector <- c(140, -50, 20, -120, 240)
# Roulette winnings from Monday to Friday
roulette_vector <- c(-24, -50, 100, -350, 10)
# The variable days_vector
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
# Assign the names of the day to roulette_vector and poker_vector
names(poker_vector) <-
names(roulette_vector) <-
Calculating total winnings
Now that you have the poker and roulette winnings nicely as named vectors, you can start doing some data analytical magic.
You want to find out the following type of information:
- How much has been your overall profit or loss per day of the week?
- Have you lost money over the week in total?
- Are you winning/losing money on poker or on roulette?
To get the answers, you have to do arithmetic calculations on vectors.
It is important to know that if you sum two vectors in R, it takes the element-wise sum. For example, the following three statements are completely equivalent:
c(1, 2, 3) + c(4, 5, 6)
c(1 + 4, 2 + 5, 3 + 6)
c(5, 7, 9)
You can also do the calculations with variables that represent vectors:
a <- c(1, 2, 3)
b <- c(4, 5, 6)
c <- a + b
Exercise
Take the sum of the variables A_vector
and B_vector
and it assign to total_vector
. Inspect the result by printing out total_vector
.
A_vector <- c(1, 2, 3)
B_vector <- c(4, 5, 6)
# Take the sum of A_vector and B_vector
total_vector <-
# Print out total_vector
Calculating total winnings (2)
Now you understand how R does arithmetic with vectors, it is time to get those Ferraris in your garage! First, you need to understand what the overall profit or loss per day of the week was. The total daily profit is the sum of the profit/loss you realized on poker per day, and the profit/loss you realized on roulette per day.
In R, this is just the sum of roulette_vector
and poker_vector
.
Exercise
Assign to the variable total_daily
how much you won or lost on each day in total (poker and roulette combined).
# Poker and roulette winnings from Monday to Friday:
poker_vector <- c(140, -50, 20, -120, 240)
roulette_vector <- c(-24, -50, 100, -350, 10)
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
names(poker_vector) <- days_vector
names(roulette_vector) <- days_vector
# Assign to total_daily how much you won/lost on each day
total_daily <-
Calculating total winnings (3)
Based on the previous analysis, it looks like you had a mix of good and bad days. This is not what your ego expected, and you wonder if there may be a very tiny chance you have lost money over the week in total?
A function that helps you to answer this question is sum()
. It calculates the sum of all elements of a vector. For example, to calculate the total amount of money you have lost/won with poker you do:
total_poker <- sum(poker_vector)
Exercise
- Calculate the total amount of money that you have won/lost with roulette and assign to the variable
total_roulette
.
- Now that you have the totals for roulette and poker, you can easily calculate
total_week
(which is the sum of all gains and losses of the week).
- Print out
total_week
.
# Poker and roulette winnings from Monday to Friday:
poker_vector <- c(140, -50, 20, -120, 240)
roulette_vector <- c(-24, -50, 100, -350, 10)
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
names(poker_vector) <- days_vector
names(roulette_vector) <- days_vector
# Total winnings with poker
total_poker <- sum(poker_vector)
# Total winnings with roulette
total_roulette <-
# Total winnings overall
total_week <-
# Print out total_week
Comparing total winnings
Oops, it seems like you are losing money. Time to rethink and adapt your strategy! This will require some deeper analysis…
After a short brainstorm in your hotel’s jacuzzi, you realize that a possible explanation might be that your skills in roulette are not as well developed as your skills in poker. So maybe your total gains in poker are higher (or >
) than in roulette.
Exercise
- Calculate
total_poker
and total_roulette
as in the previous exercise. Use the sum()
function twice.
- Check if your total gains in poker are higher than for roulette by using a comparison. Simply print out the result of this comparison. What do you conclude, should you focus on roulette or on poker?
# Poker and roulette winnings from Monday to Friday:
poker_vector <- c(140, -50, 20, -120, 240)
roulette_vector <- c(-24, -50, 100, -350, 10)
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
names(poker_vector) <- days_vector
names(roulette_vector) <- days_vector
# Calculate total gains for poker and roulette
total_poker <-
total_roulette <-
# Check if you realized higher total gains in poker than in roulette
Vector selection: the good times
Your hunch seemed to be right. It appears that the poker game is more your cup of tea than roulette.
Another possible route for investigation is your performance at the beginning of the working week compared to the end of it. You did have a couple of Margarita cocktails at the end of the week…
To answer that question, you only want to focus on a selection of the total_vector
. In other words, our goal is to select specific elements of the vector. To select elements of a vector (and later matrices, data frames, …), you can use square brackets. Between the square brackets, you indicate what elements to select. For example, to select the first element of the vector, you type poker_vector[1]
. To select the second element of the vector, you type poker_vector[2]
, etc. Notice that the first element in a vector has index 1, not 0 as in many other programming languages.
Exercise
Assign the poker results of Wednesday to the variable poker_wednesday
.
# Poker and roulette winnings from Monday to Friday:
poker_vector <- c(140, -50, 20, -120, 240)
roulette_vector <- c(-24, -50, 100, -350, 10)
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
names(poker_vector) <- days_vector
names(roulette_vector) <- days_vector
# Define a new variable based on a selection
poker_wednesday <-
Vector selection: the good times (2)
How about analyzing your midweek results?
To select multiple elements from a vector, you can add square brackets at the end of it. You can indicate between the brackets what elements should be selected. For example: suppose you want to select the first and the fifth day of the week: use the vector c(1, 5)
between the square brackets. For example, the code below selects the first and fifth element of poker_vector
:
poker_vector[c(1, 5)]
Exercise
Assign the poker results of Tuesday, Wednesday and Thursday to the variable poker_midweek
.
# Poker and roulette winnings from Monday to Friday:
poker_vector <- c(140, -50, 20, -120, 240)
roulette_vector <- c(-24, -50, 100, -350, 10)
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
names(poker_vector) <- days_vector
names(roulette_vector) <- days_vector
# Define a new variable based on a selection
poker_midweek <-
Vector selection: the good times (3)
Selecting multiple elements of poker_vector
with c(2, 3, 4)
is not very convenient. Many statisticians are lazy people by nature, so they created an easier way to do this: c(2, 3, 4)
can be abbreviated to 2:4
, which generates a vector with all natural numbers from 2 up to 4.
So, another way to find the mid-week results is poker_vector[2:4]
. Notice how the vector 2:4
is placed between the square brackets to select element 2 up to 4.
Exercise
Assign to roulette_selection_vector
the roulette results from Tuesday up to Friday; make use of :
if it makes things easier for you.
# Poker and roulette winnings from Monday to Friday:
poker_vector <- c(140, -50, 20, -120, 240)
roulette_vector <- c(-24, -50, 100, -350, 10)
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
names(poker_vector) <- days_vector
names(roulette_vector) <- days_vector
# Define a new variable based on a selection
roulette_selection_vector <-
Vector selection: the good times (4)
Another way to tackle the previous exercise is by using the names of the vector elements (Monday, Tuesday, …) instead of their numeric positions. For example,
poker_vector["Monday"]
will select the first element of poker_vector
since “Monday” is the name of that first element.
Just like you did in the previous exercise with numerics, you can also use the element names to select multiple elements, for example:
poker_vector[c("Monday","Tuesday")]
Exercise
- Select the first three elements in
poker_vector
by using their names: "Monday"
, "Tuesday"
and "Wednesday"
. Assign the result of the selection to poker_start
.
- Calculate the average of the values in
poker_start
with the mean()
function. Simply print out the result so you can inspect it.
# Poker and roulette winnings from Monday to Friday:
poker_vector <- c(140, -50, 20, -120, 240)
roulette_vector <- c(-24, -50, 100, -350, 10)
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
names(poker_vector) <- days_vector
names(roulette_vector) <- days_vector
# Select poker results for Monday, Tuesday and Wednesday
poker_start <-
# Calculate the average of the elements in poker_start
Selection by comparison - Step 1
By making use of comparison operators, we can approach the previous question in a more proactive way.
The (logical) comparison operators known to R are:
<
for less than
>
for greater than
<=
for less than or equal to
>=
for greater than or equal to
==
for equal to each other
!=
not equal to each other
As seen in the previous chapter, stating 6 > 5
returns TRUE
. The nice thing about R is that you can use these comparison operators also on vectors. For example:
> c(4, 5, 6) > 5
[1] FALSE FALSE TRUE
This command tests for every element of the vector if the condition stated by the comparison operator is TRUE
or FALSE
.
Exercise
- Check which elements in
poker_vector
are positive (i.e. > 0) and assign this to selection_vector
.
- Print out
selection_vector
so you can inspect it. The printout tells you whether you won (TRUE
) or lost (FALSE
) any money for each day.
# Poker and roulette winnings from Monday to Friday:
poker_vector <- c(140, -50, 20, -120, 240)
roulette_vector <- c(-24, -50, 100, -350, 10)
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
names(poker_vector) <- days_vector
names(roulette_vector) <- days_vector
# Which days did you make money on poker?
selection_vector <-
# Print out selection_vector
Selection by comparison - Step 2
Working with comparisons will make your data analytical life easier. Instead of selecting a subset of days to investigate yourself (like before), you can simply ask R to return only those days where you realized a positive return for poker.
In the previous exercises you used selection_vector <- poker_vector > 0
to find the days on which you had a positive poker return. Now, you would like to know not only the days on which you won, but also how much you won on those days.
You can select the desired elements, by putting selection_vector
between the square brackets that follow poker_vector
:
poker_vector[selection_vector]
R knows what to do when you pass a logical vector in square brackets: it will only select the elements that correspond to TRUE
in selection_vector
.
Exercise
Use selection_vector
in square brackets to assign the amounts that you won on the profitable days to the variable poker_winning_days
.
# Poker and roulette winnings from Monday to Friday:
poker_vector <- c(140, -50, 20, -120, 240)
roulette_vector <- c(-24, -50, 100, -350, 10)
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
names(poker_vector) <- days_vector
names(roulette_vector) <- days_vector
# Which days did you make money on poker?
selection_vector <- poker_vector > 0
# Select from poker_vector these days
poker_winning_days <-
Advanced selection
Just like you did for poker, you also want to know those days where you realized a positive return for roulette.
Exercise
- Create the variable
selection_vector
, this time to see if you made profit with roulette for different days.
- Assign the amounts that you made on the days that you ended positively for roulette to the variable
roulette_winning_days
. This vector thus contains the positive winnings of roulette_vector
.
# Poker and roulette winnings from Monday to Friday:
poker_vector <- c(140, -50, 20, -120, 240)
roulette_vector <- c(-24, -50, 100, -350, 10)
days_vector <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
names(poker_vector) <- days_vector
names(roulette_vector) <- days_vector
# Which days did you make money on roulette?
selection_vector <-
# Select from roulette_vector these days
roulette_winning_days <-
Matrices
What’s a matrix?
In R, a matrix is a collection of elements of the same data type (numeric, character, or logical) arranged into a fixed number of rows and columns. Since you are only working with rows and columns, a matrix is called two-dimensional.
You can construct a matrix in R with the matrix()
function. Consider the following example:
matrix(1:9, byrow = TRUE, nrow = 3)
In the matrix()
function:
- The first argument is the collection of elements that R will arrange into the rows and columns of the matrix. Here, we use
1:9
which is a shortcut for c(1, 2, 3, 4, 5, 6, 7, 8, 9)
.
- The argument
byrow
indicates that the matrix is filled by the rows. If we want the matrix to be filled by the columns, we just place byrow = FALSE
.
- The third argument
nrow
indicates that the matrix should have three rows.
Exercise
Construct a matrix with 3 rows containing the numbers 1 up to 9, filled row-wise.
# Construct a matrix with 3 rows that contain the numbers 1 up to 9
Analyzing matrices, you shall
It is now time to get your hands dirty. In the following exercises you will analyze the box office numbers of the Star Wars franchise. May the force be with you!
In the editor, three vectors are defined. Each one represents the box office numbers from the first three Star Wars movies. The first element of each vector indicates the US box office revenue, the second element refers to the Non-US box office (source: Wikipedia).
In this exercise, you’ll combine all these figures into a single vector. Next, you’ll build a matrix from this vector.
Exercise
- Use
c(new_hope, empire_strikes, return_jedi)
to combine the three vectors into one vector. Call this vector box_office
.
- Construct a matrix with 3 rows, where each row represents a movie. Use the
matrix()
function to this. The first argument is the vector box_office
, containing all box office figures. Next, you’ll have to specify nrow = 3
and byrow = TRUE
. Name the resulting matrix star_wars_matrix
.
# Box office Star Wars (in millions!)
new_hope <- c(460.998, 314.4)
empire_strikes <- c(290.475, 247.900)
return_jedi <- c(309.306, 165.8)
# Create box_office
box_office <-
# Construct star_wars_matrix
star_wars_matrix <-
Naming a matrix
To help you remember what is stored in star_wars_matrix
, you would like to add the names of the movies for the rows. Not only does this help you to read the data, but it is also useful to select certain elements from the matrix.
Similar to vectors, you can add names for the rows and the columns of a matrix
rownames(my_matrix) <- row_names_vector
colnames(my_matrix) <- col_names_vector
We went ahead and prepared two vectors for you: region
, and titles
. You will need these vectors to name the columns and rows of star_wars_matrix
, respectively.
Exercise
- Use
colnames()
to name the columns of star_wars_matrix
with the region
vector.
- Use
rownames()
to name the rows of star_wars_matrix
with the titles
vector.
- Print out
star_wars_matrix
to see the result of your work.
# Box office Star Wars (in millions!)
new_hope <- c(460.998, 314.4)
empire_strikes <- c(290.475, 247.900)
return_jedi <- c(309.306, 165.8)
# Construct matrix
star_wars_matrix <- matrix(c(new_hope, empire_strikes, return_jedi), nrow = 3, byrow = TRUE)
# Vectors region and titles, used for naming
region <- c("US", "non-US")
titles <- c("A New Hope", "The Empire Strikes Back", "Return of the Jedi")
# Name the columns with region
# Name the rows with titles
# Print out star_wars_matrix
Calculating the worldwide box office
The single most important thing for a movie in order to become an instant legend in Tinseltown is its worldwide box office figures.
To calculate the total box office revenue for the three Star Wars movies, you have to take the sum of the US revenue column and the non-US revenue column.
In R, the function rowSums()
conveniently calculates the totals for each row of a matrix. This function creates a new vector:
rowSums(my_matrix)
Exercise
Calculate the worldwide box office figures for the three movies and put these in the vector named worldwide_vector
.
# Construct star_wars_matrix
box_office <- c(460.998, 314.4, 290.475, 247.900, 309.306, 165.8)
star_wars_matrix <- matrix(box_office, nrow = 3, byrow = TRUE,
dimnames = list(c("A New Hope", "The Empire Strikes Back", "Return of the Jedi"),
c("US", "non-US")))
# Calculate worldwide box office figures
worldwide_vector <-
Adding a column for the Worldwide box office
In the previous exercise you calculated the vector that contained the worldwide box office receipt for each of the three Star Wars movies. However, this vector is not yet part of star_wars_matrix
.
You can add a column or multiple columns to a matrix with the cbind()
function, which merges matrices and/or vectors together by column. For example:
big_matrix <- cbind(matrix1, matrix2, vector1 ...)
Exercise
Add worldwide_vector
as a new column to the star_wars_matrix
and assign the result to all_wars_matrix
. Use the cbind()
function.
# Construct star_wars_matrix
box_office <- c(460.998, 314.4, 290.475, 247.900, 309.306, 165.8)
star_wars_matrix <- matrix(box_office, nrow = 3, byrow = TRUE,
dimnames = list(c("A New Hope", "The Empire Strikes Back", "Return of the Jedi"),
c("US", "non-US")))
# The worldwide box office figures
worldwide_vector <- rowSums(star_wars_matrix)
# Bind the new variable worldwide_vector as a column to star_wars_matrix
all_wars_matrix <-
Adding a row
Just like every action has a reaction, every cbind()
has an rbind()
. (We admit, we are pretty bad with metaphors.)
Your R workspace, where all variables you defined ‘live’ (check out what a workspace is), has already been initialized and contains two matrices:
star_wars_matrix
that we have used all along, with data on the first trilogy,
star_wars_matrix2
, with similar data for the second trilogy.
Type the name of these matrices in the console and hit Enter if you want to have a closer look. If you want to check out the contents of the workspace, you can type ls()
in the console.
Exercise
Use rbind()
to paste together star_wars_matrix
and star_wars_matrix2
, in this order. Assign the resulting matrix to all_wars_matrix
.
# star_wars_matrix and star_wars_matrix2 are available in your workspace
star_wars_matrix <- structure(c(461, 290.5, 309.3, 314.4, 247.9, 165.8), .Dim = c(3L, 2L), .Dimnames = list(c("A New Hope", "The Empire Strikes Back", "Return of the Jedi"), c("US", "non-US")))
star_wars_matrix2 <- structure(c(474.5, 310.7, 380.3, 552.5, 338.7, 468.5), .Dim = c(3L, 2L), .Dimnames = list(c("The Phantom Menace", "Attack of the Clones", "Revenge of the Sith"), c("US", "non-US")))
# Combine both Star Wars trilogies in one matrix
all_wars_matrix <-
The total box office revenue for the entire saga
Just like every cbind()
has a rbind()
, every colSums()
has a rowSums()
. Your R workspace already contains the all_wars_matrix
that you constructed in the previous exercise; type all_wars_matrix
to have another look. Let’s now calculate the total box office revenue for the entire saga.
Exercise
- Calculate the total revenue for the US and the non-US region and assign
total_revenue_vector
. You can use the colSums()
function.
- Print out
total_revenue_vector
to have a look at the results.
# all_wars_matrix is available in your workspace
all_wars_matrix
# Total revenue for US and non-US
total_revenue_vector <-
# Print out total_revenue_vector
Selection of matrix elements
Similar to vectors, you can use the square brackets [
]
to select one or multiple elements from a matrix. Whereas vectors have one dimension, matrices have two dimensions. You should therefore use a comma to separate that what to select from the rows from that what you want to select from the columns. For example:
my_matrix[1,2]
selects the element at the first row and second column.
my_matrix[1:3,2:4]
results in a matrix with the data on the rows 1, 2, 3 and columns 2, 3, 4.
If you want to select all elements of a row or a column, no number is needed before or after the comma, respectively:
my_matrix[,1]
selects all elements of the first column.
my_matrix[1,]
selects all elements of the first row.
Back to Star Wars with this newly acquired knowledge! As in the previous exercise, all_wars_matrix
is already available in your workspace.
Exercise
- Select the non-US revenue for all movies (the entire second column of all_wars_matrix), store the result as
non_us_all
.
- Use
mean()
on non_us_all
to calculate the average non-US revenue for all movies. Simply print out the result.
- This time, select the non-US revenue for the first two movies in
all_wars_matrix
. Store the result as non_us_some
.
- Use
mean()
again to print out the average of the values in non_us_some
.
# all_wars_matrix is available in your workspace
all_wars_matrix
# Select the non-US revenue for all movies
non_us_all <-
# Average non-US revenue
# Select the non-US revenue for first two movies
non_us_some <-
# Average non-US revenue for first two movies
A little arithmetic with matrices
Similar to what you have learned with vectors, the standard operators like +
, -
, /
, *
, etc. work in an element-wise way on matrices in R.
For example, 2 * my_matrix
multiplies each element of my_matrix
by two.
As a newly-hired data analyst for Lucasfilm, it is your job is to find out how many visitors went to each movie for each geographical area. You already have the total revenue figures in all_wars_matrix
. Assume that the price of a ticket was 5 dollars. Simply dividing the box office numbers by this ticket price gives you the number of visitors.
Exercise
- Divide
all_wars_matrix
by 5, giving you the number of visitors in millions. Assign the resulting matrix to visitors
.
- Print out
visitors
so you can have a look.
# all_wars_matrix is available in your workspace
all_wars_matrix
# Estimate the visitors
visitors <-
# Print the estimate to the console
A little arithmetic with matrices (2)
Just like 2 * my_matrix
multiplied every element of my_matrix
by two, my_matrix1 * my_matrix2
creates a matrix where each element is the product of the corresponding elements in my_matrix1
and my_matrix2
.
After looking at the result of the previous exercise, big boss Lucas points out that the ticket prices went up over time. He asks to redo the analysis based on the prices you can find in ticket_prices_matrix
(source: imagination).
Those who are familiar with matrices should note that this is not the standard matrix multiplication for which you should use %*%
in R.
Exercise
- Divide
all_wars_matrix
by ticket_prices_matrix
to get the estimated number of US and non-US visitors for the six movies. Assign the result to visitors
.
- From the
visitors
matrix, select the entire first column, representing the number of visitors in the US. Store this selection as us_visitors
.
- Calculate the average number of US visitors; print out the result.
# all_wars_matrix and ticket_prices_matrix are available in your workspace
all_wars_matrix
ticket_prices_matrix <- structure(c(5, 6, 7, 4, 4.5, 4.9, 5, 6, 7, 4, 4.5, 4.9), .Dim = c(6L, 2L), .Dimnames = list(c("A New Hope", "The Empire Strikes Back", "Return of the Jedi", "The Phantom Menace", "Attack of the Clones", "Revenge of the Sith"), c("US", "non-US")))
# Estimated number of visitors
visitors <-
# US visitors
us_visitors <-
# Average number of US visitors
Factors
What’s a factor and why would you use it?
In this chapter you dive into the wonderful world of factors.
The term factor refers to a statistical data type used to store categorical variables. The difference between a categorical variable and a continuous variable is that a categorical variable can belong to a limited number of categories. A continuous variable, on the other hand, can correspond to an infinite number of values.
It is important that R knows whether it is dealing with a continuous or a categorical variable, as the statistical models you will develop in the future treat both types differently. (You will see later why this is the case.)
A good example of a categorical variable is the variable ‘Gender’. A human individual can either be “Male” or “Female”, making abstraction of inter-sexes. So here “Male” and “Female” are, in a simplified sense, the two values of the categorical variable “Gender”, and every observation can be assigned to either the value “Male” of “Female”.
Exercise
Assign to variable theory
the value "factors for categorical variables"
.
# Assign to the variable theory what this chapter is about!
What’s a factor and why would you use it? (2)
To create factors in R, you make use of the function factor()
. First thing that you have to do is create a vector that contains all the observations that belong to a limited number of categories. For example, gender_vector
contains the sex of 5 different individuals:
gender_vector <- c("Male","Female","Female","Male","Male")
It is clear that there are two categories, or in R-terms ‘factor levels’, at work here: “Male” and “Female”.
The function factor()
will encode the vector as a factor:
factor_gender_vector <- factor(gender_vector)
Exercise
- Convert the character vector
gender_vector
to a factor with factor()
and assign the result to factor_gender_vector
- Print out
factor_gender_vector
and assert that R prints out the factor levels below the actual values.
# Gender vector
gender_vector <- c("Male", "Female", "Female", "Male", "Male")
# Convert gender_vector to a factor
factor_gender_vector <-
# Print out factor_gender_vector
What’s a factor and why would you use it? (3)
There are two types of categorical variables: a nominal categorical variable and an ordinal categorical variable.
A nominal variable is a categorical variable without an implied order. This means that it is impossible to say that ‘one is worth more than the other’. For example, think of the categorical variable animals_vector
with the categories "Elephant"
, "Giraffe"
, "Donkey"
and "Horse"
. Here, it is impossible to say that one stands above or below the other. (Note that some of you might disagree ;-) ).
In contrast, ordinal variables do have a natural ordering. Consider for example the categorical variable temperature_vector
with the categories: "Low"
, "Medium"
and "High"
. Here it is obvious that "Medium"
stands above "Low"
, and "High"
stands above "Medium"
.
Exercise
- Click ‘Run’ to check how R constructs and prints nominal and ordinal variables. Do not worry if you do not understand all the code just yet, we will get to that.
# Animals
animals_vector <- c("Elephant", "Giraffe", "Donkey", "Horse")
factor_animals_vector <- factor(animals_vector)
factor_animals_vector
# Temperature
temperature_vector <- c("High", "Low", "High","Low", "Medium")
factor_temperature_vector <- factor(temperature_vector, order = TRUE, levels = c("Low", "Medium", "High"))
factor_temperature_vector
Factor levels
When you first get a data set, you will often notice that it contains factors with specific factor levels. However, sometimes you will want to change the names of these levels for clarity or other reasons. R allows you to do this with the function levels()
:
levels(factor_vector) <- c("name1", "name2",...)
A good illustration is the raw data that is provided to you by a survey. A standard question for every questionnaire is the gender of the respondent. You remember from the previous question that this is a factor and when performing the questionnaire on the streets its levels are often coded as "M"
and "F"
.
survey_vector <- c("M", "F", "F", "M", "M")
Next, when you want to start your data analysis, your main concern is to keep a nice overview of all the variables and what they mean. At that point, you will often want to change the factor levels to "Male"
and "Female"
instead of "M"
and "F"
to make your life easier.
Watch out: the order with which you assign the levels is important. If you type levels(factor_survey_vector)
, you’ll see that it outputs [1] "F" "M"
. If you don’t specify the levels of the factor when creating the vector, R will automatically assign them alphabetically. To correctly map "F"
to "Female"
and "M"
to "Male"
, the levels should be set to c("Female", "Male")
, in this order order.
Exercise
- Check out the code that builds a factor vector from
survey_vector
. You should use factor_survey_vector
in the next instruction.
- Change the factor levels of
factor_survey_vector
to c("Female", "Male")
. Mind the order of the vector elements here.
# Code to build factor_survey_vector
survey_vector <- c("M", "F", "F", "M", "M")
factor_survey_vector <- factor(survey_vector)
# Specify the levels of factor_survey_vector
levels(factor_survey_vector) <-
factor_survey_vector
Summarizing a factor
After finishing this course, one of your favorite functions in R will be summary()
. This will give you a quick overview of the contents of a variable:
summary(my_var)
Going back to our survey, you would like to know how many "Male"
responses you have in your study, and how many "Female"
responses. The summary()
function gives you the answer to this question.
Exercise
Ask a summary()
of the survey_vector
and factor_survey_vector
. Interpret the results of both vectors. Are they both equally useful in this case?
# Build factor_survey_vector with clean levels
survey_vector <- c("M", "F", "F", "M", "M")
factor_survey_vector <- factor(survey_vector)
levels(factor_survey_vector) <- c("Female", "Male")
factor_survey_vector
# Generate summary for survey_vector
# Generate summary for factor_survey_vector
Battle of the sexes
In factor_survey_vector
we have a factor with two levels: Male
and Female
. But how does R value these relatively to each other? In other words, who does R think is better, males or females?
Exercise
Read the code in the editor and click ‘Run’ to see whether males are worth more than females.
# Build factor_survey_vector with clean levels
survey_vector <- c("M", "F", "F", "M", "M")
factor_survey_vector <- factor(survey_vector)
levels(factor_survey_vector) <- c("Female", "Male")
# Male
male <- factor_survey_vector[1]
# Female
female <- factor_survey_vector[2]
# Battle of the sexes: Male 'larger' than female?
male > female
Ordered factors
Since "Male"
and "Female"
are unordered (or nominal) factor levels, R returns a warning message, telling you that the greater than operator is not meaningful. As seen before, R attaches an equal value to the levels for such factors.
But this is not always the case! Sometimes you will also deal with factors that do have a natural ordering between its categories. If this is the case, we have to make sure that we pass this information to R…
Let us say that you are leading a research team of five data analysts and that you want to evaluate their performance. To do this, you track their speed, evaluate each analyst as "slow"
, "fast"
or "insane"
, and save the results in speed_vector
.
Exercise
As a first step, assign speed_vector
a vector with 5 entries, one for each analyst. Each entry should be either "slow"
, "fast"
, or "insane"
. Use the list below:
- Analyst 1 is
fast
,
- Analyst 2 is
slow
,
- Analyst 3 is
slow
,
- Analyst 4 is
fast
and
- Analyst 5 is
insane
.
No need to specify these are factors yet.
# Create speed_vector
speed_vector <-
Ordered factors (2)
speed_vector
should be converted to an ordinal factor since its categories have a natural ordering. By default, the function factor()
transforms speed_vector
into an unordered factor. To create an ordered factor, you have to add two additional arguments: ordered
and levels
.
factor(some_vector,
ordered = TRUE,
levels = c("lev1", "lev2", ...))
By setting the argument ordered
to TRUE
in the function factor()
, you indicate that the factor is ordered. With the argument levels you give the values of the factor in the correct order.
Exercise
From speed_vector
, create an ordered factor vector: factor_speed_vector
. Set ordered to TRUE
, and set levels
to c("slow", "fast", "insane")
.
# Create speed_vector
speed_vector <- c("fast", "slow", "slow", "fast", "insane")
# Convert speed_vector to ordered factor vector
factor_speed_vector <-
# Print factor_speed_vector
factor_speed_vector
summary(factor_speed_vector)
Comparing ordered factors
Having a bad day at work, ‘data analyst number two’ enters your office and starts complaining that ‘data analyst number five’ is slowing down the entire project. Since you know that ‘data analyst number two’ has the reputation of being a smarty-pants, you first decide to check if his statement is true.
The fact that factor_speed_vector
is now ordered enables us to compare different elements (the data analysts in this case). You can simply do this by using the well-known operators.
Exercise
- Use
[2]
to select from factor_speed_vector
the factor value for the second data analyst. Store it as da2
.
- Use
[5]
to select the factor_speed_vector
factor value for the fifth data analyst. Store it as da5
.
- Check if
da2
is greater than da5
; simply print out the result. Remember that you can use the >
operator to check whether one element is larger than the other.
# Create factor_speed_vector
speed_vector <- c("fast", "slow", "slow", "fast", "insane")
factor_speed_vector <- factor(speed_vector, ordered = TRUE, levels = c("slow", "fast", "insane"))
# Factor value for second data analyst
da2 <-
# Factor value for fifth data analyst
da5 <-
# Is data analyst 2 faster than data analyst 5?
Data Frames
What’s a data frame?
You may remember from the chapter about matrices that all the elements that you put in a matrix should be of the same type. Back then, your data set on Star Wars only contained numeric elements.
When doing a market research survey, however, you often have questions such as:
- ‘Are your married?’ or ‘yes/no’ questions (
logical
)
- ‘How old are you?’ (
numeric
)
- ‘What is your opinion on this product?’ or other ‘open-ended’ questions (
character
)
- …
The output, namely the respondents’ answers to the questions formulated above, is a data set of different data types. You will often find yourself working with data sets that contain different data types instead of only one.
A data frame has the variables of a data set as columns and the observations as rows. This will be a familiar concept for those coming from different statistical software packages such as SAS or SPSS.
Exercise
- Click ‘Run’. The data from the built-in example data frame
mtcars
will be printed to the console.
# Print out built-in R data frame
mtcars
Quick, have a look at your data set
Wow, that is a lot of cars!
Working with large data sets is not uncommon in data analysis. When you work with (extremely) large data sets and data frames, your first task as a data analyst is to develop a clear understanding of its structure and main elements. Therefore, it is often useful to show only a small part of the entire data set.
So how to do this in R? Well, the function head()
enables you to show the first observations of a data frame. Similarly, the function tail()
prints out the last observations in your data set.
Both head()
and tail()
print a top line called the ‘header’, which contains the names of the different variables in your data set.
Exercise
Call head()
on the mtcars
data set to have a look at the header and the first observations.
Have a look at the structure
Another method that is often used to get a rapid overview of your data is the function str()
. The function str()
shows you the structure of your data set. For a data frame it tells you:
- The total number of observations (e.g. 32 car types)
- The total number of variables (e.g. 11 car features)
- A full list of the variables names (e.g.
mpg
, cyl
… )
- The data type of each variable (e.g.
num
)
- The first observations
Applying the str()
function will often be the first thing that you do when receiving a new data set or data frame. It is a great way to get more insight in your data set before diving into the real analysis.
Exercise
Investigate the structure of mtcars
. Make sure that you see the same numbers, variables and data types as mentioned above.
# Investigate the structure of mtcars
Creating a data frame
Since using built-in data sets is not even half the fun of creating your own data sets, the rest of this chapter is based on your personally developed data set. Put your jet pack on because it is time for some space exploration!
As a first goal, you want to construct a data frame that describes the main characteristics of eight planets in our solar system. According to your good friend Buzz, the main features of a planet are:
- The type of planet (Terrestrial or Gas Giant).
- The planet’s diameter relative to the diameter of the Earth.
- The planet’s rotation across the sun relative to that of the Earth.
- If the planet has rings or not (TRUE or FALSE).
After doing some high-quality research on Wikipedia, you feel confident enough to create the necessary vectors: name
, type
, diameter
, rotation
and rings
; these vectors have already been coded up on the right. The first element in each of these vectors correspond to the first observation.
You construct a data frame with the data.frame()
function. As arguments, you pass the vectors from before: they will become the different columns of your data frame. Because every column has the same length, the vectors you pass should also have the same length. But don’t forget that it is possible (and likely) that they contain different types of data.
Exercise
Use the function data.frame()
to construct a data frame. Pass the vectors name
, type
, diameter
, rotation
and rings
as arguments to data.frame()
, in this order. Call the resulting data frame planets_df
.
# Definition of vectors
name <- c("Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune")
type <- c("Terrestrial planet", "Terrestrial planet", "Terrestrial planet",
"Terrestrial planet", "Gas giant", "Gas giant", "Gas giant", "Gas giant")
diameter <- c(0.382, 0.949, 1, 0.532, 11.209, 9.449, 4.007, 3.883)
rotation <- c(58.64, -243.02, 1, 1.03, 0.41, 0.43, -0.72, 0.67)
rings <- c(FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE)
# Create a data frame from the vectors
planets_df <-
Creating a data frame (2)
The planets_df
data frame should have 8 observations and 5 variables. It has been made available in the workspace, so you can directly use it.
Exercise
Use str()
to investigate the structure of the new planets_df
variable.
# Check the structure of planets_df
Selection of data frame elements
Similar to vectors and matrices, you select elements from a data frame with the help of square brackets [
]
. By using a comma, you can indicate what to select from the rows and the columns respectively. For example:
my_df[1,2]
selects the value at the first row and select element in my_df
.
my_df[1:3,2:4]
selects rows 1, 2, 3 and columns 2, 3, 4 in my_df
.
Sometimes you want to select all elements of a row or column. For example, my_df[1, ]
selects all elements of the first row. Let us now apply this technique on planets_df
!
Exercise
- From
planets_df
, select the diameter of Mercury: this is the value at the first row and the third column. Simply print out the result.
- From
planets_df
, select all data on Mars (the fourth row). Simply print out the result.
# The planets_df data frame from the previous exercise is pre-loaded
# Print out diameter of Mercury (row 1, column 3)
# Print out data for Mars (entire fourth row)
Selection of data frame elements (2)
Instead of using numerics to select elements of a data frame, you can also use the variable names to select columns of a data frame.
Suppose you want to select the first three elements of the type
column. One way to do this is
planets_df[1:3,1]
A possible disadvantage of this approach is that you have to know (or look up) the column number of type
, which gets hard if you have a lot of variables. It is often easier to just make use of the variable name:
planets_df[1:3,"type"]
Exercise
Select and print out the first 5 values in the "diameter"
column of planets_df
.
# The planets_df data frame from the previous exercise is pre-loaded
# Select first 5 values of diameter column
Only planets with rings
You will often want to select an entire column, namely one specific variable from a data frame. If you want to select all elements of the variable diameter
, for example, both of these will do the trick:
planets_df[,3]
planets_df[,"diameter"]
However, there is a short-cut. If your columns have names, you can use the $
sign:
planets_df$diameter
Exercise
- Use the
$
sign to select the rings
variable from planets_df
. Store the vector that results as rings_vector
.
- Print out
rings_vector
to see if you got it right.
# planets_df is pre-loaded in your workspace
# Select the rings variable from planets_df
rings_vector <-
# Print out rings_vector
Only planets with rings (2)
You probably remember from high school that some planets in our solar system have rings and others do not. But due to other priorities at that time (read: puberty) you can not recall their names, let alone their rotation speed, etc.
Could R help you out?
If you type rings_vector
in the console, you get:
[1] FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE
This means that the first four observations (or planets) do not have a ring (FALSE
), but the other four do (TRUE
). However, you do not get a nice overview of the names of these planets, their diameter, etc. Let’s try to use rings_vector
to select the data for the four planets with rings.
Exercise
The code on the right selects the name
column of all planets that have rings. Adapt the code so that instead of only the name
column, all columns for planets that have rings are selected.
# planets_df and rings_vector are pre-loaded in your workspace
# Adapt the code to select all columns for planets with rings
planets_df[rings_vector, "name"]
Only planets with rings but shorter
So what exactly did you learn in the previous exercises? You selected a subset from a data frame (planets_df
) based on whether or not a certain condition was true (rings or no rings), and you managed to pull out all relevant data. Pretty awesome! By now, NASA is probably already flirting with your CV ;-).
Now, let us move up one level and use the function subset()
. You should see the subset()
function as a short-cut to do exactly the same as what you did in the previous exercises.
subset(my_df, subset = some_condition)
The first argument of subset()
specifies the data set for which you want a subset. By adding the second argument, you give R the necessary information and conditions to select the correct subset.
The code below will give the exact same result as you got in the previous exercise, but this time, you didn’t need the rings_vector
!
subset(planets_df, subset = rings)
Exercise
Use subset()
on planets_df
to select planets that have a diameter smaller than Earth. Because the diameter
variable is a relative measure of the planet’s diameter w.r.t that of planet Earth, your condition is diameter < 1
.
# planets_df is pre-loaded in your workspace
# Select planets with diameter < 1
Sorting
Making and creating rankings is one of mankind’s favorite affairs. These rankings can be useful (best universities in the world), entertaining (most influential movie stars) or pointless (best 007 look-a-like).
In data analysis you can sort your data according to a certain variable in the data set. In R, this is done with the help of the function order()
.
order()
is a function that gives you the ranked position of each element when it is applied on a variable, such as a vector for example:
> a <- c(100, 10, 1000)
> order(a)
[1] 2 1 3
10, which is the second element in a
, is the smallest element, so 2 comes first in the output of order(a)
. 100, which is the first element in a
is the second smallest element, so 1 comes second in the output of order(a)
.
This means we can use the output of order(a)
to reshuffle a
:
> a[order(a)]
[1] 10 100 1000
Exercise
Experiment with the order()
function in the console.
# Play around with the order function in the console
Sorting your data frame
Alright, now that you understand the order()
function, let us do something useful with it. You would like to rearrange your data frame such that it starts with the smallest planet and ends with the largest one. A sort on the diameter
column.
Exercise
- Call
order()
on planets_df$diameter
(the diameter
column of planets_df
). Store the result as positions
.
- Now reshuffle
planets_df
with the positions
vector as row indexes inside square brackets. Keep all columns. Simply print out the result.
# planets_df is pre-loaded in your workspace
# Use order() to create positions
positions <-
# Use positions to sort planets_df
Lists
Lists, why would you need them?
Congratulations! At this point in the course you are already familiar with:
- Vectors (one dimensional array): can hold numeric, character or logical values. The elements in a vector all have the same data type.
- Matrices (two dimensional array): can hold numeric, character or logical values. The elements in a matrix all have the same data type.
- Data frames (two-dimensional objects): can hold numeric, character or logical values. Within a column all elements have the same data type, but different columns can be of different data type. Pretty sweet for an R newbie, right? ;-)
Exercise
Click ‘Run’ to start learning everything about lists!
# Just click the 'Run' button.
Lists, why would you need them? (2)
A list in R is similar to your to-do list at work or school: the different items on that list most likely differ in length, characteristic, type of activity that has to do be done, …
A list in R allows you to gather a variety of objects under one name (that is, the name of the list) in an ordered way. These objects can be matrices, vectors, data frames, even other lists, etc. It is not even required that these objects are related to each other in any way.
You could say that a list is some kind super data type: you can store practically any piece of information in it!
Exercise
Click ‘Run’ to start the first exercise on lists.
# Click 'Run' to start the first exercise on lists.
Creating a list
Let us create our first list! To construct a list you use the function list()
:
my_list <- list(comp1, comp2 ...)
The arguments to the list function are the list components. Remember, these components can be matrices, vectors, other lists, …
Exercie
Construct a list, named my_list
, that contains the variables my_vector
, my_matrix
and my_df
as list components.
# Vector with numerics from 1 up to 10
my_vector <- 1:10
# Matrix with numerics from 1 up to 9
my_matrix <- matrix(1:9, ncol = 3)
# First 10 elements of the built-in data frame mtcars
my_df <- mtcars[1:10,]
# Construct list with these different elements:
my_list <-
Creating a named list
Well done, you’re on a roll!
Just like on your to-do list, you want to avoid not knowing or remembering what the components of your list stand for. That is why you should give names to them:
my_list <- list(name1 = your_comp1,
name2 = your_comp2)
This creates a list with components that are named name1
, name2
, and so on. If you want to name your lists after you’ve created them, you can use the names()
function as you did with vectors. The following commands are fully equivalent to the assignment above:
my_list <- list(your_comp1, your_comp2)
names(my_list) <- c("name1", "name2")
Exercise
- Change the code of the previous exercise (see editor) by adding names to the components. Use for
my_vector
the name vec
, for my_matrix
the name mat
and for my_df
the name df
.
- Print out
my_list
so you can inspect the output.
# Vector with numerics from 1 up to 10
my_vector <- 1:10
# Matrix with numerics from 1 up to 9
my_matrix <- matrix(1:9, ncol = 3)
# First 10 elements of the built-in data frame mtcars
my_df <- mtcars[1:10,]
# Adapt list() call to give the components names
my_list <- list(my_vector, my_matrix, my_df)
# Print out my_list
Creating a named list (2)
Being a huge movie fan (remember your job at LucasFilms), you decide to start storing information on good movies with the help of lists.
Start by creating a list for the movie “The Shining”. We have already created the variables mov
, act
and rev
in your R workspace. Feel free to check them out in the console.
Exercise
Complete the code on the right to create shining_list
; it contains three elements:
- moviename: a character string with the movie title (stored in
mov
)
- actors: a vector with the main actors’ names (stored in
act
)
- reviews: a data frame that contains some reviews (stored in
rev
)
Do not forget to name the list components accordingly (names are moviename, actors and reviews).
# The variables mov, act and rev are available
mov <- "The Shining"
act <- c("Jack Nicholson", "Shelley Duvall", "Danny Lloyd", "Scatman Crothers", "Barry Nelson")
rev <- data.frame(scores = c(4.5, 4, 5), sources = c("IMDb1", "IMDb2", "IMDb3"), comments = c("A masterpiece of psychological horror", "A truly brilliant and scary film from Stanley Kubrick", "Best Horror Film I Have Ever Seen"))
# Finish the code to build shining_list
shining_list <- list(moviename = mov)
Selecting elements from a list
Your list will often be built out of numerous elements and components. Therefore, getting a single element, multiple elements, or a component out of it is not always straightforward.
One way to select a component is using the numbered position of that component. For example, to “grab” the first component of shining_list
you type
shining_list[[1]]
A quick way to check this out is typing it in the console. Important to remember: to select elements from vectors, you use single square brackets: [
]
. Don’t mix them up!
You can also refer to the names of the components, with [[
]]
or with the $
sign. Both will select the data frame representing the reviews:
shining_list[["reviews"]]
shining_list$reviews
Besides selecting components, you often need to select specific elements out of these components. For example, with shining_list[[2]][1]
you select from the second component, actors
(shining_list[[2]]
), the first element ([1]
). When you type this in the console, you will see the answer is Jack Nicholson.
Exercise
- Select from
shining_list
the vector representing the actors. Simply print out this vector.
- Select from
shining_list
the second element in the vector representing the actors. Do a printout like before.
# shining_list is already pre-loaded in the workspace
# Print out the vector representing the actors
# Print the second element of the vector representing the actors
LS0tDQp0aXRsZTogIkludHJvZHVjdGlvbiB0byBSIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnMicNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBjZXJ1bGVhbg0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAyDQotLS0NCg0KIyBJbnRyb2R1Y3Rpb24gdG8gQmFzaWNzDQoNCiMjIEFyaXRobWV0aWMgd2l0aCBSDQoNCkluIGl0cyBtb3N0IGJhc2ljIGZvcm0sIFIgY2FuIGJlIHVzZWQgYXMgYSBzaW1wbGUgY2FsY3VsYXRvci4gQ29uc2lkZXIgdGhlIGZvbGxvd2luZyBhcml0aG1ldGljIG9wZXJhdG9yczoNCg0KLSBBZGRpdGlvbjogYCtgDQotIFN1YnRyYWN0aW9uOiBgLWANCi0gTXVsdGlwbGljYXRpb246IGAqYA0KLSBEaXZpc2lvbjogYC9gDQotIEV4cG9uZW50aWF0aW9uOiBgXmANCi0gTW9kdWxvOiBgJSVgDQoNClRoZSBsYXN0IHR3byBtaWdodCBuZWVkIHNvbWUgZXhwbGFpbmluZzoNCg0KLSBUaGUgYF5gIG9wZXJhdG9yIHJhaXNlcyB0aGUgbnVtYmVyIHRvIGl0cyBsZWZ0IHRvIHRoZSBwb3dlciBvZiB0aGUgbnVtYmVyIHRvIGl0cyByaWdodDogZm9yIGV4YW1wbGUgYDNeMmAgaXMgOS4NCi0gVGhlIG1vZHVsbyByZXR1cm5zIHRoZSByZW1haW5kZXIgb2YgdGhlIGRpdmlzaW9uIG9mIHRoZSBudW1iZXIgdG8gdGhlIGxlZnQgYnkgdGhlIG51bWJlciBvbiBpdHMgcmlnaHQsIGZvciBleGFtcGxlIDUgbW9kdWxvIDMgb3IgYDUgJSUgM2AgaXMgMi4NCg0KV2l0aCB0aGlzIGtub3dsZWRnZSwgZm9sbG93IHRoZSBpbnN0cnVjdGlvbnMgYmVsb3cgdG8gY29tcGxldGUgdGhlIGV4ZXJjaXNlLg0KDQojIyMgRXhlcmNpc2UNCi0gVHlwZSBgMl41YCBpbiB0aGUgZWRpdG9yIHRvIGNhbGN1bGF0ZSAyIHRvIHRoZSBwb3dlciA1Lg0KLSBUeXBlIGAyOCAlJSA2YCB0byBjYWxjdWxhdGUgMjggbW9kdWxvIDYuDQotIE5vdGUgaG93IHRoZSBgI2Agc3ltYm9sIGlzIHVzZWQgdG8gYWRkIGNvbW1lbnRzIG9uIHRoZSBSIGNvZGUuDQoNCmBgYHtyfQ0KIyBBbiBhZGRpdGlvbg0KNSArIDUgDQoNCiMgQSBzdWJ0cmFjdGlvbg0KNSAtIDUgDQoNCiMgQSBtdWx0aXBsaWNhdGlvbg0KMyAqIDUNCg0KICMgQSBkaXZpc2lvbg0KKDUgKyA1KSAvIDIgDQoNCiMgRXhwb25lbnRpYXRpb24NCg0KDQojIE1vZHVsbw0KDQpgYGANCg0KDQojIyBWYXJpYWJsZSBhc3NpZ25tZW50DQoNCkEgYmFzaWMgY29uY2VwdCBpbiAoc3RhdGlzdGljYWwpIHByb2dyYW1taW5nIGlzIGNhbGxlZCBhIHZhcmlhYmxlLg0KDQpBIHZhcmlhYmxlIGFsbG93cyB5b3UgdG8gc3RvcmUgYSB2YWx1ZSAoZS5nLiA0KSBvciBhbiBvYmplY3QgKGUuZy4gYSBmdW5jdGlvbiBkZXNjcmlwdGlvbikgaW4gUi4gWW91IGNhbiB0aGVuIGxhdGVyIHVzZSB0aGlzIHZhcmlhYmxlJ3MgbmFtZSB0byBlYXNpbHkgYWNjZXNzIHRoZSB2YWx1ZSBvciB0aGUgb2JqZWN0IHRoYXQgaXMgc3RvcmVkIHdpdGhpbiB0aGlzIHZhcmlhYmxlLg0KDQpZb3UgY2FuIGFzc2lnbiBhIHZhbHVlIDQgdG8gYSB2YXJpYWJsZSBgbXlfdmFyYCB3aXRoIHRoZSBjb21tYW5kDQoNCmBteV92YXIgPC0gNGANCg0KIyMjIEV4ZXJjaXNlDQpPdmVyIHRvIHlvdTogY29tcGxldGUgdGhlIGNvZGUgaW4gdGhlIGVkaXRvciBzdWNoIHRoYXQgaXQgYXNzaWducyB0aGUgdmFsdWUgNDIgdG8gdGhlIHZhcmlhYmxlIGB4YCBpbiB0aGUgZWRpdG9yLiBOb3RpY2UgdGhhdCB3aGVuIHlvdSBhc2sgUiB0byBwcmludCBgeGAsIHRoZSB2YWx1ZSA0MiBhcHBlYXJzLg0KDQpgYGB7cn0NCiMgQXNzaWduIHRoZSB2YWx1ZSA0MiB0byB4DQp4IDwtIA0KDQojIFByaW50IG91dCB0aGUgdmFsdWUgb2YgdGhlIHZhcmlhYmxlIHgNCngNCmBgYA0KDQoNCiMjIFZhcmlhYmxlIGFzc2lnbm1lbnQgKDIpDQoNClN1cHBvc2UgeW91IGhhdmUgYSBmcnVpdCBiYXNrZXQgd2l0aCBmaXZlIGFwcGxlcy4gQXMgYSBkYXRhIGFuYWx5c3QgaW4gdHJhaW5pbmcsIHlvdSB3YW50IHRvIHN0b3JlIHRoZSBudW1iZXIgb2YgYXBwbGVzIGluIGEgdmFyaWFibGUgd2l0aCB0aGUgbmFtZSBgbXlfYXBwbGVzYC4NCg0KIyMjIEV4ZXJjaXNlDQpUeXBlIHRoZSBmb2xsb3dpbmcgY29kZSBpbiB0aGUgZWRpdG9yOiBgbXlfYXBwbGVzIDwtIDVgLiBUaGlzIHdpbGwgYXNzaWduIHRoZSB2YWx1ZSA1IHRvIGBteV9hcHBsZXNgLg0KVHlwZTogYG15X2FwcGxlc2AgYmVsb3cgdGhlIHNlY29uZCBjb21tZW50LiBUaGlzIHdpbGwgcHJpbnQgb3V0IHRoZSB2YWx1ZSBvZiBgbXlfYXBwbGVzYC4NCkxvb2sgYXQgdGhlIGNvbnNvbGU6IHlvdSBzZWUgdGhhdCB0aGUgbnVtYmVyIDUgaXMgcHJpbnRlZC4gU28gUiBub3cgbGlua3MgdGhlIHZhcmlhYmxlIGBteV9hcHBsZXNgIHRvIHRoZSB2YWx1ZSA1Lg0KDQoNCmBgYHtyfQ0KIyBBc3NpZ24gdGhlIHZhbHVlIDUgdG8gdGhlIHZhcmlhYmxlIG15X2FwcGxlcw0KDQoNCiMgUHJpbnQgb3V0IHRoZSB2YWx1ZSBvZiB0aGUgdmFyaWFibGUgbXlfYXBwbGVzDQoNCmBgYA0KDQoNCiMjIFZhcmlhYmxlIGFzc2lnbm1lbnQgKDMpDQoNCkV2ZXJ5IHRhc3R5IGZydWl0IGJhc2tldCBuZWVkcyBvcmFuZ2VzLCBzbyB5b3UgZGVjaWRlIHRvIGFkZCBzaXggb3Jhbmdlcy4gQXMgYSBkYXRhIGFuYWx5c3QsIHlvdXIgcmVmbGV4IGlzIHRvIGltbWVkaWF0ZWx5IGNyZWF0ZSB0aGUgdmFyaWFibGUgYG15X29yYW5nZXNgIGFuZCBhc3NpZ24gdGhlIHZhbHVlIDYgdG8gaXQuIE5leHQsIHlvdSB3YW50IHRvIGNhbGN1bGF0ZSBob3cgbWFueSBwaWVjZXMgb2YgZnJ1aXQgeW91IGhhdmUgaW4gdG90YWwuIFNpbmNlIHlvdSBoYXZlIGdpdmVuIG1lYW5pbmdmdWwgbmFtZXMgdG8gdGhlc2UgdmFsdWVzLCB5b3UgY2FuIG5vdyBjb2RlIHRoaXMgaW4gYSBjbGVhciB3YXk6DQoNCmBteV9hcHBsZXMgKyBteV9vcmFuZ2VzYA0KDQojIyMgRXhlcmNpc2UNCg0KQXNzaWduIHRvIGBteV9vcmFuZ2VzYCB0aGUgdmFsdWUgNi4NCkFkZCB0aGUgdmFyaWFibGVzIGBteV9hcHBsZXNgIGFuZCBgbXlfb3Jhbmdlc2AgYW5kIGhhdmUgUiBzaW1wbHkgcHJpbnQgdGhlIHJlc3VsdC4NCkFzc2lnbiB0aGUgcmVzdWx0IG9mIGFkZGluZyBgbXlfYXBwbGVzYCBhbmQgYG15X29yYW5nZXNgIHRvIGEgbmV3IHZhcmlhYmxlIGBteV9mcnVpdGAuDQoNCmBgYHtyfQ0KIyBBc3NpZ24gYSB2YWx1ZSB0byB0aGUgdmFyaWFibGVzIG15X2FwcGxlcyBhbmQgbXlfb3Jhbmdlcw0KbXlfYXBwbGVzIDwtIDUNCg0KDQojIEFkZCB0aGVzZSB0d28gdmFyaWFibGVzIHRvZ2V0aGVyDQoNCg0KIyBDcmVhdGUgdGhlIHZhcmlhYmxlIG15X2ZydWl0DQoNCmBgYA0KDQoNCiMjIEFwcGxlcyBhbmQgb3Jhbmdlcw0KDQpDb21tb24ga25vd2xlZGdlIHRlbGxzIHlvdSBub3QgdG8gYWRkIGFwcGxlcyBhbmQgb3Jhbmdlcy4gQnV0IGhleSwgdGhhdCBpcyB3aGF0IHlvdSBqdXN0IGRpZCwgbm8gOi0pPyBUaGUgYG15X2FwcGxlc2AgYW5kIGBteV9vcmFuZ2VzYCB2YXJpYWJsZXMgYm90aCBjb250YWluZWQgYSBudW1iZXIgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlLiBUaGUgYCtgIG9wZXJhdG9yIHdvcmtzIHdpdGggbnVtZXJpYyB2YXJpYWJsZXMgaW4gUi4gSWYgeW91IHJlYWxseSB0cmllZCB0byBhZGQgImFwcGxlcyIgYW5kICJvcmFuZ2VzIiwgYW5kIGFzc2lnbmVkIGEgdGV4dCB2YWx1ZSB0byB0aGUgdmFyaWFibGUgYG15X29yYW5nZXNgIChzZWUgdGhlIGVkaXRvciksIHlvdSB3b3VsZCBiZSB0cnlpbmcgdG8gYXNzaWduIHRoZSBhZGRpdGlvbiBvZiBhIG51bWVyaWMgYW5kIGEgY2hhcmFjdGVyIHZhcmlhYmxlIHRvIHRoZSB2YXJpYWJsZSBgbXlfZnJ1aXRgLiBUaGlzIGlzIG5vdCBwb3NzaWJsZS4NCg0KIyMjIEV4ZXJjaXNlDQoNCkNsaWNrICdSdW4nIGFuZCByZWFkIHRoZSBlcnJvciBtZXNzYWdlLiBNYWtlIHN1cmUgdG8gdW5kZXJzdGFuZCB3aHkgdGhpcyBkaWQgbm90IHdvcmsuDQpBZGp1c3QgdGhlIGNvZGUgc28gdGhhdCBSIGtub3dzIHlvdSBoYXZlIDYgb3JhbmdlcyBhbmQgdGh1cyBhIGZydWl0IGJhc2tldCB3aXRoIDExIHBpZWNlcyBvZiBmcnVpdC4NCg0KYGBge3J9DQojIEFzc2lnbiBhIHZhbHVlIHRvIHRoZSB2YXJpYWJsZSBteV9hcHBsZXMNCm15X2FwcGxlcyA8LSA1IA0KDQojIEZpeCB0aGUgYXNzaWdubWVudCBvZiBteV9vcmFuZ2VzDQpteV9vcmFuZ2VzIDwtICJzaXgiIA0KDQojIENyZWF0ZSB0aGUgdmFyaWFibGUgbXlfZnJ1aXQgYW5kIHByaW50IGl0IG91dA0KbXlfZnJ1aXQgPC0gbXlfYXBwbGVzICsgbXlfb3JhbmdlcyANCm15X2ZydWl0DQpgYGANCg0KDQojIyBCYXNpYyBkYXRhIHR5cGVzIGluIFINCg0KUiB3b3JrcyB3aXRoIG51bWVyb3VzIGRhdGEgdHlwZXMuIFNvbWUgb2YgdGhlIG1vc3QgYmFzaWMgdHlwZXMgdG8gZ2V0IHN0YXJ0ZWQgYXJlOg0KDQotIERlY2ltYWxzIHZhbHVlcyBsaWtlIGA0LjVgIGFyZSBjYWxsZWQgKipudW1lcmljcyoqLg0KLSBOYXR1cmFsIG51bWJlcnMgbGlrZSBgNGAgYXJlIGNhbGxlZCAqKmludGVnZXJzKiouIEludGVnZXJzIGFyZSBhbHNvIG51bWVyaWNzLg0KLSBCb29sZWFuIHZhbHVlcyAoYFRSVUVgIG9yIGBGQUxTRWApIGFyZSBjYWxsZWQgKipsb2dpY2FsKiouDQotIFRleHQgKG9yIHN0cmluZykgdmFsdWVzIGFyZSBjYWxsZWQgKipjaGFyYWN0ZXJzKiouDQoNCk5vdGUgaG93IHRoZSBxdW90YXRpb24gbWFya3Mgb24gdGhlIHJpZ2h0IGluZGljYXRlIHRoYXQgInNvbWUgdGV4dCIgaXMgYSBjaGFyYWN0ZXIuDQoNCiMjIyBFeGVyY2lzZQ0KDQpDaGFuZ2UgdGhlIHZhbHVlIG9mIHRoZToNCg0KLSBgbXlfbnVtZXJpY2AgdmFyaWFibGUgdG8gNDIuDQotIGBteV9jaGFyYWN0ZXJgIHZhcmlhYmxlIHRvICJ1bml2ZXJzZSIuIE5vdGUgdGhhdCB0aGUgcXVvdGF0aW9uIG1hcmtzIGluZGljYXRlIHRoYXQgInVuaXZlcnNlIiBpcyBhIGNoYXJhY3Rlci4NCi0gYG15X2xvZ2ljYWxgIHZhcmlhYmxlIHRvIGBGQUxTRWAuDQotIE5vdGUgdGhhdCBSIGlzIGNhc2Ugc2Vuc2l0aXZlIQ0KDQpgYGB7cn0NCiMgQ2hhbmdlIG15X251bWVyaWMgdG8gYmUgNDINCm15X251bWVyaWMgPC0gNDIuNQ0KDQojIENoYW5nZSBteV9jaGFyYWN0ZXIgdG8gYmUgInVuaXZlcnNlIg0KbXlfY2hhcmFjdGVyIDwtICJzb21lIHRleHQiDQoNCiMgQ2hhbmdlIG15X2xvZ2ljYWwgdG8gYmUgRkFMU0UNCm15X2xvZ2ljYWwgPC0gVFJVRQ0KYGBgDQoNCg0KIyMgV2hhdCdzIHRoYXQgZGF0YSB0eXBlPw0KDQpEbyB5b3UgcmVtZW1iZXIgdGhhdCB3aGVuIHlvdSBhZGRlZCBgNSArICJzaXgiYCwgeW91IGdvdCBhbiBlcnJvciBkdWUgdG8gYSBtaXNtYXRjaCBpbiBkYXRhIHR5cGVzPyBZb3UgY2FuIGF2b2lkIHN1Y2ggZW1iYXJyYXNzaW5nIHNpdHVhdGlvbnMgYnkgY2hlY2tpbmcgdGhlIGRhdGEgdHlwZSBvZiBhIHZhcmlhYmxlIGJlZm9yZWhhbmQuIFlvdSBjYW4gZG8gdGhpcyB3aXRoIHRoZSBgY2xhc3MoKWAgZnVuY3Rpb24sIGFzIHRoZSBjb2RlIGJlbG93IHNob3dzLg0KDQojIyMgRXhlcmNpc2UNCkNvbXBsZXRlIHRoZSBjb2RlIGluIHRoZSBlZGl0b3IgYW5kIGFsc28gcHJpbnQgb3V0IHRoZSBjbGFzc2VzIG9mIGBteV9jaGFyYWN0ZXJgIGFuZCBgbXlfbG9naWNhbGAuDQoNCmBgYHtyfQ0KIyBEZWNsYXJlIHZhcmlhYmxlcyBvZiBkaWZmZXJlbnQgdHlwZXMNCm15X251bWVyaWMgPC0gNDINCm15X2NoYXJhY3RlciA8LSAidW5pdmVyc2UiDQpteV9sb2dpY2FsIDwtIEZBTFNFIA0KDQojIENoZWNrIGNsYXNzIG9mIG15X251bWVyaWMNCmNsYXNzKG15X251bWVyaWMpDQoNCiMgQ2hlY2sgY2xhc3Mgb2YgbXlfY2hhcmFjdGVyDQoNCg0KIyBDaGVjayBjbGFzcyBvZiBteV9sb2dpY2FsDQoNCmBgYA0KDQoNCiMgVmVjdG9ycw0KDQojIyBDcmVhdGUgYSB2ZWN0b3INCg0KRmVlbGluZyBsdWNreT8gWW91IGJldHRlciwgYmVjYXVzZSB0aGlzIGNoYXB0ZXIgdGFrZXMgeW91IG9uIGEgdHJpcCB0byB0aGUgQ2l0eSBvZiBTaW5zLCBhbHNvIGtub3duIGFzIFN0YXRpc3RpY2lhbnMgUGFyYWRpc2UhDQoNClRoYW5rcyB0byBSIGFuZCB5b3VyIG5ldyBkYXRhLWFuYWx5dGljYWwgc2tpbGxzLCB5b3Ugd2lsbCBsZWFybiBob3cgdG8gdXBsaWZ0IHlvdXIgcGVyZm9ybWFuY2UgYXQgdGhlIHRhYmxlcyBhbmQgZmlyZSBvZmYgeW91ciBjYXJlZXIgYXMgYSBwcm9mZXNzaW9uYWwgZ2FtYmxlci4gVGhpcyBjaGFwdGVyIHdpbGwgc2hvdyBob3cgeW91IGNhbiBlYXNpbHkga2VlcCB0cmFjayBvZiB5b3VyIGJldHRpbmcgcHJvZ3Jlc3MgYW5kIGhvdyB5b3UgY2FuIGRvIHNvbWUgc2ltcGxlIGFuYWx5c2VzIG9uIHBhc3QgYWN0aW9ucy4gTmV4dCBzdG9wLCBWZWdhcyBCYWJ5Li4uIFZFR0FTISENCg0KIyMjIEV4ZXJjaXNlDQpEbyB5b3Ugc3RpbGwgcmVtZW1iZXIgd2hhdCB5b3UgaGF2ZSBsZWFybmVkIGluIHRoZSBmaXJzdCBjaGFwdGVyPyBBc3NpZ24gdGhlIHZhbHVlIGAiR28hImAgdG8gdGhlIHZhcmlhYmxlIGB2ZWdhc2AuIFJlbWVtYmVyOiBSIGlzIGNhc2Ugc2Vuc2l0aXZlIQ0KDQpgYGB7cn0NCiMgRGVmaW5lIHRoZSB2YXJpYWJsZSB2ZWdhcw0KdmVnYXMgPC0gDQpgYGANCg0KDQojIyBDcmVhdGUgYSB2ZWN0b3IgKDIpDQoNCkxldCB1cyBmb2N1cyBmaXJzdCENCg0KT24geW91ciB3YXkgZnJvbSByYWdzIHRvIHJpY2hlcywgeW91IHdpbGwgbWFrZSBleHRlbnNpdmUgdXNlIG9mIHZlY3RvcnMuIFZlY3RvcnMgYXJlIG9uZS1kaW1lbnNpb24gYXJyYXlzIHRoYXQgY2FuIGhvbGQgbnVtZXJpYyBkYXRhLCBjaGFyYWN0ZXIgZGF0YSwgb3IgbG9naWNhbCBkYXRhLiBJbiBvdGhlciB3b3JkcywgYSB2ZWN0b3IgaXMgYSBzaW1wbGUgdG9vbCB0byBzdG9yZSBkYXRhLiBGb3IgZXhhbXBsZSwgeW91IGNhbiBzdG9yZSB5b3VyIGRhaWx5IGdhaW5zIGFuZCBsb3NzZXMgaW4gdGhlIGNhc2lub3MuDQoNCkluIFIsIHlvdSBjcmVhdGUgYSB2ZWN0b3Igd2l0aCB0aGUgY29tYmluZSBmdW5jdGlvbiBgYygpYC4gWW91IHBsYWNlIHRoZSB2ZWN0b3IgZWxlbWVudHMgc2VwYXJhdGVkIGJ5IGEgY29tbWEgYmV0d2VlbiB0aGUgcGFyZW50aGVzZXMuIEZvciBleGFtcGxlOg0KDQpgYGB7cn0NCm51bWVyaWNfdmVjdG9yIDwtIGMoMSwgMiwgMykNCmNoYXJhY3Rlcl92ZWN0b3IgPC0gYygiYSIsICJiIiwgImMiKQ0KYGBgDQoNCk9uY2UgeW91IGhhdmUgY3JlYXRlZCB0aGVzZSB2ZWN0b3JzIGluIFIsIHlvdSBjYW4gdXNlIHRoZW0gdG8gZG8gY2FsY3VsYXRpb25zLg0KDQojIyMgRXhlcmNpc2UNCg0KQ29tcGxldGUgdGhlIGNvZGUgc3VjaCB0aGF0IGBib29sZWFuX3ZlY3RvcmAgY29udGFpbnMgdGhlIHRocmVlIGVsZW1lbnRzOiBgVFJVRWAsIGBGQUxTRWAgYW5kIGBUUlVFYCAoaW4gdGhhdCBvcmRlcikuDQoNCmBgYHtyfQ0KbnVtZXJpY192ZWN0b3IgPC0gYygxLCAxMCwgNDkpDQpjaGFyYWN0ZXJfdmVjdG9yIDwtIGMoImEiLCAiYiIsICJjIikNCg0KIyBDb21wbGV0ZSB0aGUgY29kZSBmb3IgYm9vbGVhbl92ZWN0b3INCmJvb2xlYW5fdmVjdG9yIDwtDQpgYGANCg0KDQojIyBDcmVhdGUgYSB2ZWN0b3IgKDMpDQoNCkFmdGVyIG9uZSB3ZWVrIGluIExhcyBWZWdhcyBhbmQgc3RpbGwgemVybyBGZXJyYXJpcyBpbiB5b3VyIGdhcmFnZSwgeW91IGRlY2lkZSB0aGF0IGl0IGlzIHRpbWUgdG8gc3RhcnQgdXNpbmcgeW91ciBkYXRhIGFuYWx5dGljYWwgc3VwZXJwb3dlcnMuDQoNCkJlZm9yZSBkb2luZyBhIGZpcnN0IGFuYWx5c2lzLCB5b3UgZGVjaWRlIHRvIGZpcnN0IGNvbGxlY3QgYWxsIHRoZSB3aW5uaW5ncyBhbmQgbG9zc2VzIGZvciB0aGUgbGFzdCB3ZWVrOg0KDQpGb3IgYHBva2VyX3ZlY3RvcmA6DQoNCi0gT24gTW9uZGF5IHlvdSB3b24gJDE0MA0KLSBUdWVzZGF5IHlvdSBsb3N0ICQ1MA0KLSBXZWRuZXNkYXkgeW91IHdvbiAkMjANCi0gVGh1cnNkYXkgeW91IGxvc3QgJDEyMA0KLSBGcmlkYXkgeW91IHdvbiAkMjQwDQoNCkZvciBgcm91bGV0dGVfdmVjdG9yYDoNCg0KLSBPbiBNb25kYXkgeW91IGxvc3QgJDI0DQotIFR1ZXNkYXkgeW91IGxvc3QgJDUwDQotIFdlZG5lc2RheSB5b3Ugd29uICQxMDANCi0gVGh1cnNkYXkgeW91IGxvc3QgJDM1MA0KLSBGcmlkYXkgeW91IHdvbiAkMTANCg0KWW91IG9ubHkgcGxheWVkIHBva2VyIGFuZCByb3VsZXR0ZSwgc2luY2UgdGhlcmUgd2FzIGEgZGVsZWdhdGlvbiBvZiBtZWRpdW1zIHRoYXQgb2NjdXBpZWQgdGhlIGNyYXBzIHRhYmxlcy4gVG8gYmUgYWJsZSB0byB1c2UgdGhpcyBkYXRhIGluIFIsIHlvdSBkZWNpZGUgdG8gY3JlYXRlIHRoZSB2YXJpYWJsZXMgYHBva2VyX3ZlY3RvcmAgYW5kIGByb3VsZXR0ZV92ZWN0b3JgLg0KDQojIyMgRXhlcmNpc2UNCg0KQXNzaWduIHRoZSB3aW5uaW5ncy9sb3NzZXMgZm9yIHJvdWxldHRlIHRvIHRoZSB2YXJpYWJsZSBgcm91bGV0dGVfdmVjdG9yYC4NCg0KYGBge3J9DQojIFBva2VyIHdpbm5pbmdzIGZyb20gTW9uZGF5IHRvIEZyaWRheQ0KcG9rZXJfdmVjdG9yIDwtIGMoMTQwLCAtNTAsIDIwLCAtMTIwLCAyNDApDQoNCiMgUm91bGV0dGUgd2lubmluZ3MgZnJvbSBNb25kYXkgdG8gRnJpZGF5DQpyb3VsZXR0ZV92ZWN0b3IgPC0gIA0KYGBgDQoNCg0KIyMgTmFtaW5nIGEgdmVjdG9yDQoNCkFzIGEgZGF0YSBhbmFseXN0LCBpdCBpcyBpbXBvcnRhbnQgdG8gaGF2ZSBhIGNsZWFyIHZpZXcgb24gdGhlIGRhdGEgdGhhdCB5b3UgYXJlIHVzaW5nLiBVbmRlcnN0YW5kaW5nIHdoYXQgZWFjaCBlbGVtZW50IHJlZmVycyB0byBpcyB0aGVyZWZvcmUgZXNzZW50aWFsLg0KDQpJbiB0aGUgcHJldmlvdXMgZXhlcmNpc2UsIHdlIGNyZWF0ZWQgYSB2ZWN0b3Igd2l0aCB5b3VyIHdpbm5pbmdzIG92ZXIgdGhlIHdlZWsuIEVhY2ggdmVjdG9yIGVsZW1lbnQgcmVmZXJzIHRvIGEgZGF5IG9mIHRoZSB3ZWVrIGJ1dCBpdCBpcyBoYXJkIHRvIHRlbGwgd2hpY2ggZWxlbWVudCBiZWxvbmdzIHRvIHdoaWNoIGRheS4gSXQgd291bGQgYmUgbmljZSBpZiB5b3UgY291bGQgc2hvdyB0aGF0IGluIHRoZSB2ZWN0b3IgaXRzZWxmLg0KDQpZb3UgY2FuIGdpdmUgYSBuYW1lIHRvIHRoZSBlbGVtZW50cyBvZiBhIHZlY3RvciB3aXRoIHRoZSBgbmFtZXMoKWAgZnVuY3Rpb24uIEhhdmUgYSBsb29rIGF0IHRoaXMgZXhhbXBsZToNCg0KYGBgDQpzb21lX3ZlY3RvciA8LSBjKCJKb2huIERvZSIsICJwb2tlciBwbGF5ZXIiKQ0KbmFtZXMoc29tZV92ZWN0b3IpIDwtIGMoIk5hbWUiLCAiUHJvZmVzc2lvbiIpDQpgYGANCg0KVGhpcyBjb2RlIGZpcnN0IGNyZWF0ZXMgYSB2ZWN0b3IgYHNvbWVfdmVjdG9yYCBhbmQgdGhlbiBnaXZlcyB0aGUgdHdvIGVsZW1lbnRzIGEgbmFtZS4gVGhlIGZpcnN0IGVsZW1lbnQgaXMgYXNzaWduZWQgdGhlIG5hbWUgYE5hbWVgLCB3aGlsZSB0aGUgc2Vjb25kIGVsZW1lbnQgaXMgbGFiZWxlZCBgUHJvZmVzc2lvbmAuIFByaW50aW5nIHRoZSBjb250ZW50cyB0byB0aGUgY29uc29sZSB5aWVsZHMgZm9sbG93aW5nIG91dHB1dDoNCmBgYA0KICAgICAgICAgIE5hbWUgICAgIFByb2Zlc3Npb24gDQogICAgIkpvaG4gRG9lIiAicG9rZXIgcGxheWVyIg0KYGBgDQoNCiMjIyBFeGVyY2lzZQ0KVGhlIGNvZGUgb24gdGhlIHJpZ2h0IG5hbWVzIHRoZSBlbGVtZW50cyBpbiBgcG9rZXJfdmVjdG9yYCB3aXRoIHRoZSBkYXlzIG9mIHRoZSB3ZWVrLiBBZGQgY29kZSB0byBkbyB0aGUgc2FtZSB0aGluZyBmb3IgYHJvdWxldHRlX3ZlY3RvcmAuDQoNCmBgYHtyfQ0KIyBQb2tlciB3aW5uaW5ncyBmcm9tIE1vbmRheSB0byBGcmlkYXkNCnBva2VyX3ZlY3RvciA8LSBjKDE0MCwgLTUwLCAyMCwgLTEyMCwgMjQwKQ0KDQojIFJvdWxldHRlIHdpbm5pbmdzIGZyb20gTW9uZGF5IHRvIEZyaWRheQ0Kcm91bGV0dGVfdmVjdG9yIDwtIGMoLTI0LCAtNTAsIDEwMCwgLTM1MCwgMTApDQoNCiMgQXNzaWduIGRheXMgYXMgbmFtZXMgb2YgcG9rZXJfdmVjdG9yDQpuYW1lcyhwb2tlcl92ZWN0b3IpIDwtIGMoIk1vbmRheSIsICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIsICJGcmlkYXkiKQ0KDQojIEFzc2lnbiBkYXlzIGFzIG5hbWVzIG9mIHJvdWxldHRlX3ZlY3RvcnMNCmBgYA0KDQoNCiMjIE5hbWluZyBhIHZlY3RvciAoMikNCg0KSWYgeW91IHdhbnQgdG8gYmVjb21lIGEgZ29vZCBzdGF0aXN0aWNpYW4sIHlvdSBoYXZlIHRvIGJlY29tZSBsYXp5LiAoSWYgeW91IGFyZSBhbHJlYWR5IGxhenksIGNoYW5jZXMgYXJlIGhpZ2ggeW91IGFyZSBvbmUgb2YgdGhvc2UgZXhjZXB0aW9uYWwsIG5hdHVyYWwtYm9ybiBzdGF0aXN0aWNhbCB0YWxlbnRzLikNCg0KSW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlcyB5b3UgcHJvYmFibHkgZXhwZXJpZW5jZWQgdGhhdCBpdCBpcyBib3JpbmcgYW5kIGZydXN0cmF0aW5nIHRvIHR5cGUgYW5kIHJldHlwZSBpbmZvcm1hdGlvbiBzdWNoIGFzIHRoZSBkYXlzIG9mIHRoZSB3ZWVrLiBIb3dldmVyLCB3aGVuIHlvdSBsb29rIGF0IGl0IGZyb20gYSBoaWdoZXIgcGVyc3BlY3RpdmUsIHRoZXJlIGlzIGEgbW9yZSBlZmZpY2llbnQgd2F5IHRvIGRvIHRoaXMsIG5hbWVseSwgdG8gYXNzaWduIHRoZSBkYXlzIG9mIHRoZSB3ZWVrIHZlY3RvciB0byBhIHZhcmlhYmxlIQ0KDQpKdXN0IGxpa2UgeW91IGRpZCB3aXRoIHlvdXIgcG9rZXIgYW5kIHJvdWxldHRlIHJldHVybnMsIHlvdSBjYW4gYWxzbyBjcmVhdGUgYSB2YXJpYWJsZSB0aGF0IGNvbnRhaW5zIHRoZSBkYXlzIG9mIHRoZSB3ZWVrLiBUaGlzIHdheSB5b3UgY2FuIHVzZSBhbmQgcmUtdXNlIGl0Lg0KDQojIyMgRXhlcmNpc2UNCkEgdmFyaWFibGUgYGRheXNfdmVjdG9yYCB0aGF0IGNvbnRhaW5zIHRoZSBkYXlzIG9mIHRoZSB3ZWVrIGhhcyBhbHJlYWR5IGJlZW4gY3JlYXRlZCBmb3IgeW91Lg0KVXNlIGBkYXlzX3ZlY3RvcmAgdG8gc2V0IHRoZSBuYW1lcyBvZiBgcG9rZXJfdmVjdG9yYCBhbmQgYHJvdWxldHRlX3ZlY3RvcmAuDQoNCmBgYHtyfQ0KIyBQb2tlciB3aW5uaW5ncyBmcm9tIE1vbmRheSB0byBGcmlkYXkNCnBva2VyX3ZlY3RvciA8LSBjKDE0MCwgLTUwLCAyMCwgLTEyMCwgMjQwKQ0KDQojIFJvdWxldHRlIHdpbm5pbmdzIGZyb20gTW9uZGF5IHRvIEZyaWRheQ0Kcm91bGV0dGVfdmVjdG9yIDwtIGMoLTI0LCAtNTAsIDEwMCwgLTM1MCwgMTApDQoNCiMgVGhlIHZhcmlhYmxlIGRheXNfdmVjdG9yDQpkYXlzX3ZlY3RvciA8LSBjKCJNb25kYXkiLCAiVHVlc2RheSIsICJXZWRuZXNkYXkiLCAiVGh1cnNkYXkiLCAiRnJpZGF5IikNCiANCiMgQXNzaWduIHRoZSBuYW1lcyBvZiB0aGUgZGF5IHRvIHJvdWxldHRlX3ZlY3RvciBhbmQgcG9rZXJfdmVjdG9yDQpuYW1lcyhwb2tlcl92ZWN0b3IpIDwtICAgDQpuYW1lcyhyb3VsZXR0ZV92ZWN0b3IpIDwtDQpgYGANCg0KDQojIyBDYWxjdWxhdGluZyB0b3RhbCB3aW5uaW5ncw0KDQpOb3cgdGhhdCB5b3UgaGF2ZSB0aGUgcG9rZXIgYW5kIHJvdWxldHRlIHdpbm5pbmdzIG5pY2VseSBhcyBuYW1lZCB2ZWN0b3JzLCB5b3UgY2FuIHN0YXJ0IGRvaW5nIHNvbWUgZGF0YSBhbmFseXRpY2FsIG1hZ2ljLg0KDQpZb3Ugd2FudCB0byBmaW5kIG91dCB0aGUgZm9sbG93aW5nIHR5cGUgb2YgaW5mb3JtYXRpb246DQoNCi0gSG93IG11Y2ggaGFzIGJlZW4geW91ciBvdmVyYWxsIHByb2ZpdCBvciBsb3NzIHBlciBkYXkgb2YgdGhlIHdlZWs/DQotIEhhdmUgeW91IGxvc3QgbW9uZXkgb3ZlciB0aGUgd2VlayBpbiB0b3RhbD8NCi0gQXJlIHlvdSB3aW5uaW5nL2xvc2luZyBtb25leSBvbiBwb2tlciBvciBvbiByb3VsZXR0ZT8NCg0KVG8gZ2V0IHRoZSBhbnN3ZXJzLCB5b3UgaGF2ZSB0byBkbyBhcml0aG1ldGljIGNhbGN1bGF0aW9ucyBvbiB2ZWN0b3JzLg0KDQpJdCBpcyBpbXBvcnRhbnQgdG8ga25vdyB0aGF0IGlmIHlvdSBzdW0gdHdvIHZlY3RvcnMgaW4gUiwgaXQgdGFrZXMgdGhlIGVsZW1lbnQtd2lzZSBzdW0uIEZvciBleGFtcGxlLCB0aGUgZm9sbG93aW5nIHRocmVlIHN0YXRlbWVudHMgYXJlIGNvbXBsZXRlbHkgZXF1aXZhbGVudDoNCg0KYGBge3J9DQpjKDEsIDIsIDMpICsgYyg0LCA1LCA2KQ0KYygxICsgNCwgMiArIDUsIDMgKyA2KQ0KYyg1LCA3LCA5KQ0KYGBgDQoNCllvdSBjYW4gYWxzbyBkbyB0aGUgY2FsY3VsYXRpb25zIHdpdGggdmFyaWFibGVzIHRoYXQgcmVwcmVzZW50IHZlY3RvcnM6DQoNCmBgYHtyfQ0KYSA8LSBjKDEsIDIsIDMpIA0KYiA8LSBjKDQsIDUsIDYpDQpjIDwtIGEgKyBiDQpgYGANCg0KIyMjIEV4ZXJjaXNlDQoNClRha2UgdGhlIHN1bSBvZiB0aGUgdmFyaWFibGVzIGBBX3ZlY3RvcmAgYW5kIGBCX3ZlY3RvcmAgYW5kIGl0IGFzc2lnbiB0byBgdG90YWxfdmVjdG9yYC4NCkluc3BlY3QgdGhlIHJlc3VsdCBieSBwcmludGluZyBvdXQgYHRvdGFsX3ZlY3RvcmAuDQoNCmBgYHtyfQ0KQV92ZWN0b3IgPC0gYygxLCAyLCAzKQ0KQl92ZWN0b3IgPC0gYyg0LCA1LCA2KQ0KDQojIFRha2UgdGhlIHN1bSBvZiBBX3ZlY3RvciBhbmQgQl92ZWN0b3INCnRvdGFsX3ZlY3RvciA8LSANCiAgDQojIFByaW50IG91dCB0b3RhbF92ZWN0b3INCg0KYGBgDQoNCg0KIyMgQ2FsY3VsYXRpbmcgdG90YWwgd2lubmluZ3MgKDIpDQoNCk5vdyB5b3UgdW5kZXJzdGFuZCBob3cgUiBkb2VzIGFyaXRobWV0aWMgd2l0aCB2ZWN0b3JzLCBpdCBpcyB0aW1lIHRvIGdldCB0aG9zZSBGZXJyYXJpcyBpbiB5b3VyIGdhcmFnZSEgRmlyc3QsIHlvdSBuZWVkIHRvIHVuZGVyc3RhbmQgd2hhdCB0aGUgb3ZlcmFsbCBwcm9maXQgb3IgbG9zcyBwZXIgZGF5IG9mIHRoZSB3ZWVrIHdhcy4gVGhlIHRvdGFsIGRhaWx5IHByb2ZpdCBpcyB0aGUgc3VtIG9mIHRoZSBwcm9maXQvbG9zcyB5b3UgcmVhbGl6ZWQgb24gcG9rZXIgcGVyIGRheSwgYW5kIHRoZSBwcm9maXQvbG9zcyB5b3UgcmVhbGl6ZWQgb24gcm91bGV0dGUgcGVyIGRheS4NCg0KSW4gUiwgdGhpcyBpcyBqdXN0IHRoZSBzdW0gb2YgYHJvdWxldHRlX3ZlY3RvcmAgYW5kIGBwb2tlcl92ZWN0b3JgLg0KDQojIyMgRXhlcmNpc2UNCg0KQXNzaWduIHRvIHRoZSB2YXJpYWJsZSBgdG90YWxfZGFpbHlgIGhvdyBtdWNoIHlvdSB3b24gb3IgbG9zdCBvbiBlYWNoIGRheSBpbiB0b3RhbCAocG9rZXIgYW5kIHJvdWxldHRlIGNvbWJpbmVkKS4NCg0KYGBge3J9DQojIFBva2VyIGFuZCByb3VsZXR0ZSB3aW5uaW5ncyBmcm9tIE1vbmRheSB0byBGcmlkYXk6DQpwb2tlcl92ZWN0b3IgPC0gYygxNDAsIC01MCwgMjAsIC0xMjAsIDI0MCkNCnJvdWxldHRlX3ZlY3RvciA8LSBjKC0yNCwgLTUwLCAxMDAsIC0zNTAsIDEwKQ0KZGF5c192ZWN0b3IgPC0gYygiTW9uZGF5IiwgIlR1ZXNkYXkiLCAiV2VkbmVzZGF5IiwgIlRodXJzZGF5IiwgIkZyaWRheSIpDQpuYW1lcyhwb2tlcl92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQpuYW1lcyhyb3VsZXR0ZV92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQoNCiMgQXNzaWduIHRvIHRvdGFsX2RhaWx5IGhvdyBtdWNoIHlvdSB3b24vbG9zdCBvbiBlYWNoIGRheQ0KdG90YWxfZGFpbHkgPC0gDQpgYGANCg0KDQojIyBDYWxjdWxhdGluZyB0b3RhbCB3aW5uaW5ncyAoMykNCg0KQmFzZWQgb24gdGhlIHByZXZpb3VzIGFuYWx5c2lzLCBpdCBsb29rcyBsaWtlIHlvdSBoYWQgYSBtaXggb2YgZ29vZCBhbmQgYmFkIGRheXMuIFRoaXMgaXMgbm90IHdoYXQgeW91ciBlZ28gZXhwZWN0ZWQsIGFuZCB5b3Ugd29uZGVyIGlmIHRoZXJlIG1heSBiZSBhIHZlcnkgdGlueSBjaGFuY2UgeW91IGhhdmUgbG9zdCBtb25leSBvdmVyIHRoZSB3ZWVrIGluIHRvdGFsPw0KDQpBIGZ1bmN0aW9uIHRoYXQgaGVscHMgeW91IHRvIGFuc3dlciB0aGlzIHF1ZXN0aW9uIGlzIGBzdW0oKWAuIEl0IGNhbGN1bGF0ZXMgdGhlIHN1bSBvZiBhbGwgZWxlbWVudHMgb2YgYSB2ZWN0b3IuIEZvciBleGFtcGxlLCB0byBjYWxjdWxhdGUgdGhlIHRvdGFsIGFtb3VudCBvZiBtb25leSB5b3UgaGF2ZSBsb3N0L3dvbiB3aXRoIHBva2VyIHlvdSBkbzoNCg0KYHRvdGFsX3Bva2VyIDwtIHN1bShwb2tlcl92ZWN0b3IpYA0KDQojIyMgRXhlcmNpc2UNCg0KLSBDYWxjdWxhdGUgdGhlIHRvdGFsIGFtb3VudCBvZiBtb25leSB0aGF0IHlvdSBoYXZlIHdvbi9sb3N0IHdpdGggcm91bGV0dGUgYW5kIGFzc2lnbiB0byB0aGUgdmFyaWFibGUgYHRvdGFsX3JvdWxldHRlYC4NCi0gTm93IHRoYXQgeW91IGhhdmUgdGhlIHRvdGFscyBmb3Igcm91bGV0dGUgYW5kIHBva2VyLCB5b3UgY2FuIGVhc2lseSBjYWxjdWxhdGUgYHRvdGFsX3dlZWtgICh3aGljaCBpcyB0aGUgc3VtIG9mIGFsbCBnYWlucyBhbmQgbG9zc2VzIG9mIHRoZSB3ZWVrKS4NCi0gUHJpbnQgb3V0IGB0b3RhbF93ZWVrYC4NCg0KYGBge3J9DQojIFBva2VyIGFuZCByb3VsZXR0ZSB3aW5uaW5ncyBmcm9tIE1vbmRheSB0byBGcmlkYXk6DQpwb2tlcl92ZWN0b3IgPC0gYygxNDAsIC01MCwgMjAsIC0xMjAsIDI0MCkNCnJvdWxldHRlX3ZlY3RvciA8LSBjKC0yNCwgLTUwLCAxMDAsIC0zNTAsIDEwKQ0KZGF5c192ZWN0b3IgPC0gYygiTW9uZGF5IiwgIlR1ZXNkYXkiLCAiV2VkbmVzZGF5IiwgIlRodXJzZGF5IiwgIkZyaWRheSIpDQpuYW1lcyhwb2tlcl92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQpuYW1lcyhyb3VsZXR0ZV92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQoNCiMgVG90YWwgd2lubmluZ3Mgd2l0aCBwb2tlcg0KdG90YWxfcG9rZXIgPC0gc3VtKHBva2VyX3ZlY3RvcikNCg0KIyBUb3RhbCB3aW5uaW5ncyB3aXRoIHJvdWxldHRlDQp0b3RhbF9yb3VsZXR0ZSA8LSAgDQoNCiMgVG90YWwgd2lubmluZ3Mgb3ZlcmFsbA0KdG90YWxfd2VlayA8LSANCg0KIyBQcmludCBvdXQgdG90YWxfd2Vlaw0KICANCmBgYA0KDQoNCiMjIENvbXBhcmluZyB0b3RhbCB3aW5uaW5ncw0KDQpPb3BzLCBpdCBzZWVtcyBsaWtlIHlvdSBhcmUgbG9zaW5nIG1vbmV5LiBUaW1lIHRvIHJldGhpbmsgYW5kIGFkYXB0IHlvdXIgc3RyYXRlZ3khIFRoaXMgd2lsbCByZXF1aXJlIHNvbWUgZGVlcGVyIGFuYWx5c2lzLi4uDQoNCkFmdGVyIGEgc2hvcnQgYnJhaW5zdG9ybSBpbiB5b3VyIGhvdGVsJ3MgamFjdXp6aSwgeW91IHJlYWxpemUgdGhhdCBhIHBvc3NpYmxlIGV4cGxhbmF0aW9uIG1pZ2h0IGJlIHRoYXQgeW91ciBza2lsbHMgaW4gcm91bGV0dGUgYXJlIG5vdCBhcyB3ZWxsIGRldmVsb3BlZCBhcyB5b3VyIHNraWxscyBpbiBwb2tlci4gU28gbWF5YmUgeW91ciB0b3RhbCBnYWlucyBpbiBwb2tlciBhcmUgaGlnaGVyIChvciBgPmAgKSB0aGFuIGluIHJvdWxldHRlLg0KDQojIyMgRXhlcmNpc2UNCg0KLSBDYWxjdWxhdGUgYHRvdGFsX3Bva2VyYCBhbmQgYHRvdGFsX3JvdWxldHRlYCBhcyBpbiB0aGUgcHJldmlvdXMgZXhlcmNpc2UuIFVzZSB0aGUgYHN1bSgpYCBmdW5jdGlvbiB0d2ljZS4NCi0gQ2hlY2sgaWYgeW91ciB0b3RhbCBnYWlucyBpbiBwb2tlciBhcmUgaGlnaGVyIHRoYW4gZm9yIHJvdWxldHRlIGJ5IHVzaW5nIGEgY29tcGFyaXNvbi4gU2ltcGx5IHByaW50IG91dCB0aGUgcmVzdWx0IG9mIHRoaXMgY29tcGFyaXNvbi4gV2hhdCBkbyB5b3UgY29uY2x1ZGUsIHNob3VsZCB5b3UgZm9jdXMgb24gcm91bGV0dGUgb3Igb24gcG9rZXI/DQoNCmBgYHtyfQ0KIyBQb2tlciBhbmQgcm91bGV0dGUgd2lubmluZ3MgZnJvbSBNb25kYXkgdG8gRnJpZGF5Og0KcG9rZXJfdmVjdG9yIDwtIGMoMTQwLCAtNTAsIDIwLCAtMTIwLCAyNDApDQpyb3VsZXR0ZV92ZWN0b3IgPC0gYygtMjQsIC01MCwgMTAwLCAtMzUwLCAxMCkNCmRheXNfdmVjdG9yIDwtIGMoIk1vbmRheSIsICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIsICJGcmlkYXkiKQ0KbmFtZXMocG9rZXJfdmVjdG9yKSA8LSBkYXlzX3ZlY3Rvcg0KbmFtZXMocm91bGV0dGVfdmVjdG9yKSA8LSBkYXlzX3ZlY3Rvcg0KDQojIENhbGN1bGF0ZSB0b3RhbCBnYWlucyBmb3IgcG9rZXIgYW5kIHJvdWxldHRlDQp0b3RhbF9wb2tlciA8LQ0KdG90YWxfcm91bGV0dGUgPC0NCg0KIyBDaGVjayBpZiB5b3UgcmVhbGl6ZWQgaGlnaGVyIHRvdGFsIGdhaW5zIGluIHBva2VyIHRoYW4gaW4gcm91bGV0dGUgDQoNCmBgYA0KDQoNCiMjIFZlY3RvciBzZWxlY3Rpb246IHRoZSBnb29kIHRpbWVzDQoNCllvdXIgaHVuY2ggc2VlbWVkIHRvIGJlIHJpZ2h0LiBJdCBhcHBlYXJzIHRoYXQgdGhlIHBva2VyIGdhbWUgaXMgbW9yZSB5b3VyIGN1cCBvZiB0ZWEgdGhhbiByb3VsZXR0ZS4NCg0KQW5vdGhlciBwb3NzaWJsZSByb3V0ZSBmb3IgaW52ZXN0aWdhdGlvbiBpcyB5b3VyIHBlcmZvcm1hbmNlIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHdvcmtpbmcgd2VlayBjb21wYXJlZCB0byB0aGUgZW5kIG9mIGl0LiBZb3UgZGlkIGhhdmUgYSBjb3VwbGUgb2YgTWFyZ2FyaXRhIGNvY2t0YWlscyBhdCB0aGUgZW5kIG9mIHRoZSB3ZWVrLi4uDQoNClRvIGFuc3dlciB0aGF0IHF1ZXN0aW9uLCB5b3Ugb25seSB3YW50IHRvIGZvY3VzIG9uIGEgc2VsZWN0aW9uIG9mIHRoZSBgdG90YWxfdmVjdG9yYC4gSW4gb3RoZXIgd29yZHMsIG91ciBnb2FsIGlzIHRvIHNlbGVjdCBzcGVjaWZpYyBlbGVtZW50cyBvZiB0aGUgdmVjdG9yLiBUbyBzZWxlY3QgZWxlbWVudHMgb2YgYSB2ZWN0b3IgKGFuZCBsYXRlciBtYXRyaWNlcywgZGF0YSBmcmFtZXMsIC4uLiksIHlvdSBjYW4gdXNlIHNxdWFyZSBicmFja2V0cy4gQmV0d2VlbiB0aGUgc3F1YXJlIGJyYWNrZXRzLCB5b3UgaW5kaWNhdGUgd2hhdCBlbGVtZW50cyB0byBzZWxlY3QuIEZvciBleGFtcGxlLCB0byBzZWxlY3QgdGhlIGZpcnN0IGVsZW1lbnQgb2YgdGhlIHZlY3RvciwgeW91IHR5cGUgYHBva2VyX3ZlY3RvclsxXWAuIFRvIHNlbGVjdCB0aGUgc2Vjb25kIGVsZW1lbnQgb2YgdGhlIHZlY3RvciwgeW91IHR5cGUgYHBva2VyX3ZlY3RvclsyXWAsIGV0Yy4gTm90aWNlIHRoYXQgdGhlIGZpcnN0IGVsZW1lbnQgaW4gYSB2ZWN0b3IgaGFzIGluZGV4IDEsIG5vdCAwIGFzIGluIG1hbnkgb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzLg0KDQojIyMgRXhlcmNpc2UNCg0KQXNzaWduIHRoZSBwb2tlciByZXN1bHRzIG9mIFdlZG5lc2RheSB0byB0aGUgdmFyaWFibGUgYHBva2VyX3dlZG5lc2RheWAuDQoNCmBgYHtyfQ0KIyBQb2tlciBhbmQgcm91bGV0dGUgd2lubmluZ3MgZnJvbSBNb25kYXkgdG8gRnJpZGF5Og0KcG9rZXJfdmVjdG9yIDwtIGMoMTQwLCAtNTAsIDIwLCAtMTIwLCAyNDApDQpyb3VsZXR0ZV92ZWN0b3IgPC0gYygtMjQsIC01MCwgMTAwLCAtMzUwLCAxMCkNCmRheXNfdmVjdG9yIDwtIGMoIk1vbmRheSIsICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIsICJGcmlkYXkiKQ0KbmFtZXMocG9rZXJfdmVjdG9yKSA8LSBkYXlzX3ZlY3Rvcg0KbmFtZXMocm91bGV0dGVfdmVjdG9yKSA8LSBkYXlzX3ZlY3Rvcg0KDQojIERlZmluZSBhIG5ldyB2YXJpYWJsZSBiYXNlZCBvbiBhIHNlbGVjdGlvbg0KcG9rZXJfd2VkbmVzZGF5IDwtIA0KYGBgDQoNCg0KIyMgVmVjdG9yIHNlbGVjdGlvbjogdGhlIGdvb2QgdGltZXMgKDIpDQoNCkhvdyBhYm91dCBhbmFseXppbmcgeW91ciBtaWR3ZWVrIHJlc3VsdHM/DQoNClRvIHNlbGVjdCBtdWx0aXBsZSBlbGVtZW50cyBmcm9tIGEgdmVjdG9yLCB5b3UgY2FuIGFkZCBzcXVhcmUgYnJhY2tldHMgYXQgdGhlIGVuZCBvZiBpdC4gWW91IGNhbiBpbmRpY2F0ZSBiZXR3ZWVuIHRoZSBicmFja2V0cyB3aGF0IGVsZW1lbnRzIHNob3VsZCBiZSBzZWxlY3RlZC4gRm9yIGV4YW1wbGU6IHN1cHBvc2UgeW91IHdhbnQgdG8gc2VsZWN0IHRoZSBmaXJzdCBhbmQgdGhlIGZpZnRoIGRheSBvZiB0aGUgd2VlazogdXNlIHRoZSB2ZWN0b3IgYGMoMSwgNSlgIGJldHdlZW4gdGhlIHNxdWFyZSBicmFja2V0cy4gRm9yIGV4YW1wbGUsIHRoZSBjb2RlIGJlbG93IHNlbGVjdHMgdGhlIGZpcnN0IGFuZCBmaWZ0aCBlbGVtZW50IG9mIGBwb2tlcl92ZWN0b3JgOg0KDQpgcG9rZXJfdmVjdG9yW2MoMSwgNSldYA0KDQojIyMgRXhlcmNpc2UNCg0KQXNzaWduIHRoZSBwb2tlciByZXN1bHRzIG9mIFR1ZXNkYXksIFdlZG5lc2RheSBhbmQgVGh1cnNkYXkgdG8gdGhlIHZhcmlhYmxlIGBwb2tlcl9taWR3ZWVrYC4NCg0KYGBge3J9DQojIFBva2VyIGFuZCByb3VsZXR0ZSB3aW5uaW5ncyBmcm9tIE1vbmRheSB0byBGcmlkYXk6DQpwb2tlcl92ZWN0b3IgPC0gYygxNDAsIC01MCwgMjAsIC0xMjAsIDI0MCkNCnJvdWxldHRlX3ZlY3RvciA8LSBjKC0yNCwgLTUwLCAxMDAsIC0zNTAsIDEwKQ0KZGF5c192ZWN0b3IgPC0gYygiTW9uZGF5IiwgIlR1ZXNkYXkiLCAiV2VkbmVzZGF5IiwgIlRodXJzZGF5IiwgIkZyaWRheSIpDQpuYW1lcyhwb2tlcl92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQpuYW1lcyhyb3VsZXR0ZV92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQoNCiMgRGVmaW5lIGEgbmV3IHZhcmlhYmxlIGJhc2VkIG9uIGEgc2VsZWN0aW9uDQpwb2tlcl9taWR3ZWVrIDwtIA0KYGBgDQoNCg0KIyMgVmVjdG9yIHNlbGVjdGlvbjogdGhlIGdvb2QgdGltZXMgKDMpDQoNClNlbGVjdGluZyBtdWx0aXBsZSBlbGVtZW50cyBvZiBgcG9rZXJfdmVjdG9yYCB3aXRoIGBjKDIsIDMsIDQpYCBpcyBub3QgdmVyeSBjb252ZW5pZW50LiBNYW55IHN0YXRpc3RpY2lhbnMgYXJlIGxhenkgcGVvcGxlIGJ5IG5hdHVyZSwgc28gdGhleSBjcmVhdGVkIGFuIGVhc2llciB3YXkgdG8gZG8gdGhpczogYGMoMiwgMywgNClgIGNhbiBiZSBhYmJyZXZpYXRlZCB0byBgMjo0YCwgd2hpY2ggZ2VuZXJhdGVzIGEgdmVjdG9yIHdpdGggYWxsIG5hdHVyYWwgbnVtYmVycyBmcm9tIDIgdXAgdG8gNC4NCg0KU28sIGFub3RoZXIgd2F5IHRvIGZpbmQgdGhlIG1pZC13ZWVrIHJlc3VsdHMgaXMgYHBva2VyX3ZlY3RvclsyOjRdYC4gTm90aWNlIGhvdyB0aGUgdmVjdG9yIGAyOjRgIGlzIHBsYWNlZCBiZXR3ZWVuIHRoZSBzcXVhcmUgYnJhY2tldHMgdG8gc2VsZWN0IGVsZW1lbnQgMiB1cCB0byA0Lg0KDQojIyMgRXhlcmNpc2UNCkFzc2lnbiB0byBgcm91bGV0dGVfc2VsZWN0aW9uX3ZlY3RvcmAgdGhlIHJvdWxldHRlIHJlc3VsdHMgZnJvbSBUdWVzZGF5IHVwIHRvIEZyaWRheTsgbWFrZSB1c2Ugb2YgYDpgIGlmIGl0IG1ha2VzIHRoaW5ncyBlYXNpZXIgZm9yIHlvdS4NCg0KYGBge3J9DQojIFBva2VyIGFuZCByb3VsZXR0ZSB3aW5uaW5ncyBmcm9tIE1vbmRheSB0byBGcmlkYXk6DQpwb2tlcl92ZWN0b3IgPC0gYygxNDAsIC01MCwgMjAsIC0xMjAsIDI0MCkNCnJvdWxldHRlX3ZlY3RvciA8LSBjKC0yNCwgLTUwLCAxMDAsIC0zNTAsIDEwKQ0KZGF5c192ZWN0b3IgPC0gYygiTW9uZGF5IiwgIlR1ZXNkYXkiLCAiV2VkbmVzZGF5IiwgIlRodXJzZGF5IiwgIkZyaWRheSIpDQpuYW1lcyhwb2tlcl92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQpuYW1lcyhyb3VsZXR0ZV92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQoNCiMgRGVmaW5lIGEgbmV3IHZhcmlhYmxlIGJhc2VkIG9uIGEgc2VsZWN0aW9uDQpyb3VsZXR0ZV9zZWxlY3Rpb25fdmVjdG9yIDwtIA0KYGBgDQoNCiMjIFZlY3RvciBzZWxlY3Rpb246IHRoZSBnb29kIHRpbWVzICg0KQ0KDQpBbm90aGVyIHdheSB0byB0YWNrbGUgdGhlIHByZXZpb3VzIGV4ZXJjaXNlIGlzIGJ5IHVzaW5nIHRoZSBuYW1lcyBvZiB0aGUgdmVjdG9yIGVsZW1lbnRzIChNb25kYXksIFR1ZXNkYXksIC4uLikgaW5zdGVhZCBvZiB0aGVpciBudW1lcmljIHBvc2l0aW9ucy4gRm9yIGV4YW1wbGUsDQoNCmBwb2tlcl92ZWN0b3JbIk1vbmRheSJdYA0KDQp3aWxsIHNlbGVjdCB0aGUgZmlyc3QgZWxlbWVudCBvZiBgcG9rZXJfdmVjdG9yYCBzaW5jZSAiTW9uZGF5IiBpcyB0aGUgbmFtZSBvZiB0aGF0IGZpcnN0IGVsZW1lbnQuDQoNCkp1c3QgbGlrZSB5b3UgZGlkIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZSB3aXRoIG51bWVyaWNzLCB5b3UgY2FuIGFsc28gdXNlIHRoZSBlbGVtZW50IG5hbWVzIHRvIHNlbGVjdCBtdWx0aXBsZSBlbGVtZW50cywgZm9yIGV4YW1wbGU6DQoNCmBwb2tlcl92ZWN0b3JbYygiTW9uZGF5IiwiVHVlc2RheSIpXWANCg0KIyMjIEV4ZXJjaXNlDQoNCi0gU2VsZWN0IHRoZSBmaXJzdCB0aHJlZSBlbGVtZW50cyBpbiBgcG9rZXJfdmVjdG9yYCBieSB1c2luZyB0aGVpciBuYW1lczogYCJNb25kYXkiYCwgYCJUdWVzZGF5ImAgYW5kIGAiV2VkbmVzZGF5ImAuIEFzc2lnbiB0aGUgcmVzdWx0IG9mIHRoZSBzZWxlY3Rpb24gdG8gYHBva2VyX3N0YXJ0YC4NCi0gQ2FsY3VsYXRlIHRoZSBhdmVyYWdlIG9mIHRoZSB2YWx1ZXMgaW4gYHBva2VyX3N0YXJ0YCB3aXRoIHRoZSBgbWVhbigpYCBmdW5jdGlvbi4gU2ltcGx5IHByaW50IG91dCB0aGUgcmVzdWx0IHNvIHlvdSBjYW4gaW5zcGVjdCBpdC4NCg0KYGBge3J9DQojIFBva2VyIGFuZCByb3VsZXR0ZSB3aW5uaW5ncyBmcm9tIE1vbmRheSB0byBGcmlkYXk6DQpwb2tlcl92ZWN0b3IgPC0gYygxNDAsIC01MCwgMjAsIC0xMjAsIDI0MCkNCnJvdWxldHRlX3ZlY3RvciA8LSBjKC0yNCwgLTUwLCAxMDAsIC0zNTAsIDEwKQ0KZGF5c192ZWN0b3IgPC0gYygiTW9uZGF5IiwgIlR1ZXNkYXkiLCAiV2VkbmVzZGF5IiwgIlRodXJzZGF5IiwgIkZyaWRheSIpDQpuYW1lcyhwb2tlcl92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQpuYW1lcyhyb3VsZXR0ZV92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQoNCiMgU2VsZWN0IHBva2VyIHJlc3VsdHMgZm9yIE1vbmRheSwgVHVlc2RheSBhbmQgV2VkbmVzZGF5DQpwb2tlcl9zdGFydCA8LSANCiAgDQojIENhbGN1bGF0ZSB0aGUgYXZlcmFnZSBvZiB0aGUgZWxlbWVudHMgaW4gcG9rZXJfc3RhcnQNCg0KYGBgDQoNCg0KIyMgU2VsZWN0aW9uIGJ5IGNvbXBhcmlzb24gLSBTdGVwIDENCg0KQnkgbWFraW5nIHVzZSBvZiBjb21wYXJpc29uIG9wZXJhdG9ycywgd2UgY2FuIGFwcHJvYWNoIHRoZSBwcmV2aW91cyBxdWVzdGlvbiBpbiBhIG1vcmUgcHJvYWN0aXZlIHdheS4NCg0KVGhlIChsb2dpY2FsKSBjb21wYXJpc29uIG9wZXJhdG9ycyBrbm93biB0byBSIGFyZToNCg0KLSBgPGAgZm9yIGxlc3MgdGhhbg0KLSBgPmAgZm9yIGdyZWF0ZXIgdGhhbg0KLSBgPD1gIGZvciBsZXNzIHRoYW4gb3IgZXF1YWwgdG8NCi0gYD49YCBmb3IgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvDQotIGA9PWAgZm9yIGVxdWFsIHRvIGVhY2ggb3RoZXINCi0gYCE9YCBub3QgZXF1YWwgdG8gZWFjaCBvdGhlcg0KDQpBcyBzZWVuIGluIHRoZSBwcmV2aW91cyBjaGFwdGVyLCBzdGF0aW5nIGA2ID4gNWAgcmV0dXJucyBgVFJVRWAuIFRoZSBuaWNlIHRoaW5nIGFib3V0IFIgaXMgdGhhdCB5b3UgY2FuIHVzZSB0aGVzZSBjb21wYXJpc29uIG9wZXJhdG9ycyBhbHNvIG9uIHZlY3RvcnMuIEZvciBleGFtcGxlOg0KDQpgYGB7dGV4dH0NCj4gYyg0LCA1LCA2KSA+IDUNClsxXSBGQUxTRSBGQUxTRSBUUlVFDQpgYGANCg0KVGhpcyBjb21tYW5kIHRlc3RzIGZvciBldmVyeSBlbGVtZW50IG9mIHRoZSB2ZWN0b3IgaWYgdGhlIGNvbmRpdGlvbiBzdGF0ZWQgYnkgdGhlIGNvbXBhcmlzb24gb3BlcmF0b3IgaXMgYFRSVUVgIG9yIGBGQUxTRWAuDQoNCiMjIyBFeGVyY2lzZQ0KDQotIENoZWNrIHdoaWNoIGVsZW1lbnRzIGluIGBwb2tlcl92ZWN0b3JgIGFyZSBwb3NpdGl2ZSAoaS5lLiA+IDApIGFuZCBhc3NpZ24gdGhpcyB0byBgc2VsZWN0aW9uX3ZlY3RvcmAuDQotIFByaW50IG91dCBgc2VsZWN0aW9uX3ZlY3RvcmAgc28geW91IGNhbiBpbnNwZWN0IGl0LiBUaGUgcHJpbnRvdXQgdGVsbHMgeW91IHdoZXRoZXIgeW91IHdvbiAoYFRSVUVgKSBvciBsb3N0IChgRkFMU0VgKSBhbnkgbW9uZXkgZm9yIGVhY2ggZGF5Lg0KDQpgYGB7cn0NCiMgUG9rZXIgYW5kIHJvdWxldHRlIHdpbm5pbmdzIGZyb20gTW9uZGF5IHRvIEZyaWRheToNCnBva2VyX3ZlY3RvciA8LSBjKDE0MCwgLTUwLCAyMCwgLTEyMCwgMjQwKQ0Kcm91bGV0dGVfdmVjdG9yIDwtIGMoLTI0LCAtNTAsIDEwMCwgLTM1MCwgMTApDQpkYXlzX3ZlY3RvciA8LSBjKCJNb25kYXkiLCAiVHVlc2RheSIsICJXZWRuZXNkYXkiLCAiVGh1cnNkYXkiLCAiRnJpZGF5IikNCm5hbWVzKHBva2VyX3ZlY3RvcikgPC0gZGF5c192ZWN0b3INCm5hbWVzKHJvdWxldHRlX3ZlY3RvcikgPC0gZGF5c192ZWN0b3INCg0KIyBXaGljaCBkYXlzIGRpZCB5b3UgbWFrZSBtb25leSBvbiBwb2tlcj8NCnNlbGVjdGlvbl92ZWN0b3IgPC0gDQogIA0KIyBQcmludCBvdXQgc2VsZWN0aW9uX3ZlY3Rvcg0KDQpgYGANCg0KDQojIyBTZWxlY3Rpb24gYnkgY29tcGFyaXNvbiAtIFN0ZXAgMg0KDQpXb3JraW5nIHdpdGggY29tcGFyaXNvbnMgd2lsbCBtYWtlIHlvdXIgZGF0YSBhbmFseXRpY2FsIGxpZmUgZWFzaWVyLiBJbnN0ZWFkIG9mIHNlbGVjdGluZyBhIHN1YnNldCBvZiBkYXlzIHRvIGludmVzdGlnYXRlIHlvdXJzZWxmIChsaWtlIGJlZm9yZSksIHlvdSBjYW4gc2ltcGx5IGFzayBSIHRvIHJldHVybiBvbmx5IHRob3NlIGRheXMgd2hlcmUgeW91IHJlYWxpemVkIGEgcG9zaXRpdmUgcmV0dXJuIGZvciBwb2tlci4NCg0KSW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlcyB5b3UgdXNlZCBgc2VsZWN0aW9uX3ZlY3RvciA8LSBwb2tlcl92ZWN0b3IgPiAwYCB0byBmaW5kIHRoZSBkYXlzIG9uIHdoaWNoIHlvdSBoYWQgYSBwb3NpdGl2ZSBwb2tlciByZXR1cm4uIE5vdywgeW91IHdvdWxkIGxpa2UgdG8ga25vdyBub3Qgb25seSB0aGUgZGF5cyBvbiB3aGljaCB5b3Ugd29uLCBidXQgYWxzbyBob3cgbXVjaCB5b3Ugd29uIG9uIHRob3NlIGRheXMuDQoNCllvdSBjYW4gc2VsZWN0IHRoZSBkZXNpcmVkIGVsZW1lbnRzLCBieSBwdXR0aW5nIGBzZWxlY3Rpb25fdmVjdG9yYCBiZXR3ZWVuIHRoZSBzcXVhcmUgYnJhY2tldHMgdGhhdCBmb2xsb3cgYHBva2VyX3ZlY3RvcmA6DQoNCmBwb2tlcl92ZWN0b3Jbc2VsZWN0aW9uX3ZlY3Rvcl1gDQoNClIga25vd3Mgd2hhdCB0byBkbyB3aGVuIHlvdSBwYXNzIGEgbG9naWNhbCB2ZWN0b3IgaW4gc3F1YXJlIGJyYWNrZXRzOiBpdCB3aWxsIG9ubHkgc2VsZWN0IHRoZSBlbGVtZW50cyB0aGF0IGNvcnJlc3BvbmQgdG8gYFRSVUVgIGluIGBzZWxlY3Rpb25fdmVjdG9yYC4NCg0KIyMjIEV4ZXJjaXNlDQoNClVzZSBgc2VsZWN0aW9uX3ZlY3RvcmAgaW4gc3F1YXJlIGJyYWNrZXRzIHRvIGFzc2lnbiB0aGUgYW1vdW50cyB0aGF0IHlvdSB3b24gb24gdGhlIHByb2ZpdGFibGUgZGF5cyB0byB0aGUgdmFyaWFibGUgYHBva2VyX3dpbm5pbmdfZGF5c2AuDQoNCmBgYHtyfQ0KIyBQb2tlciBhbmQgcm91bGV0dGUgd2lubmluZ3MgZnJvbSBNb25kYXkgdG8gRnJpZGF5Og0KcG9rZXJfdmVjdG9yIDwtIGMoMTQwLCAtNTAsIDIwLCAtMTIwLCAyNDApDQpyb3VsZXR0ZV92ZWN0b3IgPC0gYygtMjQsIC01MCwgMTAwLCAtMzUwLCAxMCkNCmRheXNfdmVjdG9yIDwtIGMoIk1vbmRheSIsICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIsICJGcmlkYXkiKQ0KbmFtZXMocG9rZXJfdmVjdG9yKSA8LSBkYXlzX3ZlY3Rvcg0KbmFtZXMocm91bGV0dGVfdmVjdG9yKSA8LSBkYXlzX3ZlY3Rvcg0KDQojIFdoaWNoIGRheXMgZGlkIHlvdSBtYWtlIG1vbmV5IG9uIHBva2VyPw0Kc2VsZWN0aW9uX3ZlY3RvciA8LSBwb2tlcl92ZWN0b3IgPiAwDQoNCiMgU2VsZWN0IGZyb20gcG9rZXJfdmVjdG9yIHRoZXNlIGRheXMNCnBva2VyX3dpbm5pbmdfZGF5cyA8LSANCmBgYA0KDQoNCiMjIEFkdmFuY2VkIHNlbGVjdGlvbg0KDQpKdXN0IGxpa2UgeW91IGRpZCBmb3IgcG9rZXIsIHlvdSBhbHNvIHdhbnQgdG8ga25vdyB0aG9zZSBkYXlzIHdoZXJlIHlvdSByZWFsaXplZCBhIHBvc2l0aXZlIHJldHVybiBmb3Igcm91bGV0dGUuDQoNCiMjIyBFeGVyY2lzZQ0KDQotIENyZWF0ZSB0aGUgdmFyaWFibGUgYHNlbGVjdGlvbl92ZWN0b3JgLCB0aGlzIHRpbWUgdG8gc2VlIGlmIHlvdSBtYWRlIHByb2ZpdCB3aXRoIHJvdWxldHRlIGZvciBkaWZmZXJlbnQgZGF5cy4NCi0gQXNzaWduIHRoZSBhbW91bnRzIHRoYXQgeW91IG1hZGUgb24gdGhlIGRheXMgdGhhdCB5b3UgZW5kZWQgcG9zaXRpdmVseSBmb3Igcm91bGV0dGUgdG8gdGhlIHZhcmlhYmxlIGByb3VsZXR0ZV93aW5uaW5nX2RheXNgLiBUaGlzIHZlY3RvciB0aHVzIGNvbnRhaW5zIHRoZSBwb3NpdGl2ZSB3aW5uaW5ncyBvZiBgcm91bGV0dGVfdmVjdG9yYC4NCg0KYGBge3J9DQojIFBva2VyIGFuZCByb3VsZXR0ZSB3aW5uaW5ncyBmcm9tIE1vbmRheSB0byBGcmlkYXk6DQpwb2tlcl92ZWN0b3IgPC0gYygxNDAsIC01MCwgMjAsIC0xMjAsIDI0MCkNCnJvdWxldHRlX3ZlY3RvciA8LSBjKC0yNCwgLTUwLCAxMDAsIC0zNTAsIDEwKQ0KZGF5c192ZWN0b3IgPC0gYygiTW9uZGF5IiwgIlR1ZXNkYXkiLCAiV2VkbmVzZGF5IiwgIlRodXJzZGF5IiwgIkZyaWRheSIpDQpuYW1lcyhwb2tlcl92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQpuYW1lcyhyb3VsZXR0ZV92ZWN0b3IpIDwtIGRheXNfdmVjdG9yDQoNCiMgV2hpY2ggZGF5cyBkaWQgeW91IG1ha2UgbW9uZXkgb24gcm91bGV0dGU/DQpzZWxlY3Rpb25fdmVjdG9yIDwtDQoNCiMgU2VsZWN0IGZyb20gcm91bGV0dGVfdmVjdG9yIHRoZXNlIGRheXMNCnJvdWxldHRlX3dpbm5pbmdfZGF5cyA8LSANCmBgYA0KDQoNCg0KIyBNYXRyaWNlcw0KDQojIyBXaGF0J3MgYSBtYXRyaXg/DQoNCkluIFIsIGEgbWF0cml4IGlzIGEgY29sbGVjdGlvbiBvZiBlbGVtZW50cyBvZiB0aGUgc2FtZSBkYXRhIHR5cGUgKG51bWVyaWMsIGNoYXJhY3Rlciwgb3IgbG9naWNhbCkgYXJyYW5nZWQgaW50byBhIGZpeGVkIG51bWJlciBvZiByb3dzIGFuZCBjb2x1bW5zLiBTaW5jZSB5b3UgYXJlIG9ubHkgd29ya2luZyB3aXRoIHJvd3MgYW5kIGNvbHVtbnMsIGEgbWF0cml4IGlzIGNhbGxlZCB0d28tZGltZW5zaW9uYWwuDQoNCllvdSBjYW4gY29uc3RydWN0IGEgbWF0cml4IGluIFIgd2l0aCB0aGUgYG1hdHJpeCgpYCBmdW5jdGlvbi4gQ29uc2lkZXIgdGhlIGZvbGxvd2luZyBleGFtcGxlOg0KDQpgbWF0cml4KDE6OSwgYnlyb3cgPSBUUlVFLCBucm93ID0gMylgDQoNCkluIHRoZSBgbWF0cml4KClgIGZ1bmN0aW9uOg0KDQotIFRoZSBmaXJzdCBhcmd1bWVudCBpcyB0aGUgY29sbGVjdGlvbiBvZiBlbGVtZW50cyB0aGF0IFIgd2lsbCBhcnJhbmdlIGludG8gdGhlIHJvd3MgYW5kIGNvbHVtbnMgb2YgdGhlIG1hdHJpeC4gSGVyZSwgd2UgdXNlIGAxOjlgIHdoaWNoIGlzIGEgc2hvcnRjdXQgZm9yIGBjKDEsIDIsIDMsIDQsIDUsIDYsIDcsIDgsIDkpYC4NCi0gVGhlIGFyZ3VtZW50IGBieXJvd2AgaW5kaWNhdGVzIHRoYXQgdGhlIG1hdHJpeCBpcyBmaWxsZWQgYnkgdGhlIHJvd3MuIElmIHdlIHdhbnQgdGhlIG1hdHJpeCB0byBiZSBmaWxsZWQgYnkgdGhlIGNvbHVtbnMsIHdlIGp1c3QgcGxhY2UgYGJ5cm93ID0gRkFMU0VgLg0KLSBUaGUgdGhpcmQgYXJndW1lbnQgYG5yb3dgIGluZGljYXRlcyB0aGF0IHRoZSBtYXRyaXggc2hvdWxkIGhhdmUgdGhyZWUgcm93cy4NCg0KIyMjIEV4ZXJjaXNlDQoNCkNvbnN0cnVjdCBhIG1hdHJpeCB3aXRoIDMgcm93cyBjb250YWluaW5nIHRoZSBudW1iZXJzIDEgdXAgdG8gOSwgZmlsbGVkIHJvdy13aXNlLg0KDQpgYGB7cn0NCiMgQ29uc3RydWN0IGEgbWF0cml4IHdpdGggMyByb3dzIHRoYXQgY29udGFpbiB0aGUgbnVtYmVycyAxIHVwIHRvIDkNCmBgYA0KDQoNCiMjIEFuYWx5emluZyBtYXRyaWNlcywgeW91IHNoYWxsDQoNCkl0IGlzIG5vdyB0aW1lIHRvIGdldCB5b3VyIGhhbmRzIGRpcnR5LiBJbiB0aGUgZm9sbG93aW5nIGV4ZXJjaXNlcyB5b3Ugd2lsbCBhbmFseXplIHRoZSBib3ggb2ZmaWNlIG51bWJlcnMgb2YgdGhlIFN0YXIgV2FycyBmcmFuY2hpc2UuIE1heSB0aGUgZm9yY2UgYmUgd2l0aCB5b3UhDQoNCkluIHRoZSBlZGl0b3IsIHRocmVlIHZlY3RvcnMgYXJlIGRlZmluZWQuIEVhY2ggb25lIHJlcHJlc2VudHMgdGhlIGJveCBvZmZpY2UgbnVtYmVycyBmcm9tIHRoZSBmaXJzdCB0aHJlZSBTdGFyIFdhcnMgbW92aWVzLiBUaGUgZmlyc3QgZWxlbWVudCBvZiBlYWNoIHZlY3RvciBpbmRpY2F0ZXMgdGhlIFVTIGJveCBvZmZpY2UgcmV2ZW51ZSwgdGhlIHNlY29uZCBlbGVtZW50IHJlZmVycyB0byB0aGUgTm9uLVVTIGJveCBvZmZpY2UgKHNvdXJjZTogV2lraXBlZGlhKS4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIGNvbWJpbmUgYWxsIHRoZXNlIGZpZ3VyZXMgaW50byBhIHNpbmdsZSB2ZWN0b3IuIE5leHQsIHlvdSdsbCBidWlsZCBhIG1hdHJpeCBmcm9tIHRoaXMgdmVjdG9yLg0KDQojIyMgRXhlcmNpc2UNCg0KLSBVc2UgYGMobmV3X2hvcGUsIGVtcGlyZV9zdHJpa2VzLCByZXR1cm5famVkaSlgIHRvIGNvbWJpbmUgdGhlIHRocmVlIHZlY3RvcnMgaW50byBvbmUgdmVjdG9yLiBDYWxsIHRoaXMgdmVjdG9yIGBib3hfb2ZmaWNlYC4NCi0gQ29uc3RydWN0IGEgbWF0cml4IHdpdGggMyByb3dzLCB3aGVyZSBlYWNoIHJvdyByZXByZXNlbnRzIGEgbW92aWUuIFVzZSB0aGUgYG1hdHJpeCgpYCBmdW5jdGlvbiB0byB0aGlzLiBUaGUgZmlyc3QgYXJndW1lbnQgaXMgdGhlIGB2ZWN0b3IgYm94X29mZmljZWAsIGNvbnRhaW5pbmcgYWxsIGJveCBvZmZpY2UgZmlndXJlcy4gTmV4dCwgeW91J2xsIGhhdmUgdG8gc3BlY2lmeSBgbnJvdyA9IDNgIGFuZCBgYnlyb3cgPSBUUlVFYC4gTmFtZSB0aGUgcmVzdWx0aW5nIG1hdHJpeCBgc3Rhcl93YXJzX21hdHJpeGAuDQoNCmBgYHtyfQ0KIyBCb3ggb2ZmaWNlIFN0YXIgV2FycyAoaW4gbWlsbGlvbnMhKQ0KbmV3X2hvcGUgPC0gYyg0NjAuOTk4LCAzMTQuNCkNCmVtcGlyZV9zdHJpa2VzIDwtIGMoMjkwLjQ3NSwgMjQ3LjkwMCkNCnJldHVybl9qZWRpIDwtIGMoMzA5LjMwNiwgMTY1LjgpDQoNCiMgQ3JlYXRlIGJveF9vZmZpY2UNCmJveF9vZmZpY2UgPC0gDQoNCiMgQ29uc3RydWN0IHN0YXJfd2Fyc19tYXRyaXgNCnN0YXJfd2Fyc19tYXRyaXggPC0gDQpgYGANCg0KDQojIyBOYW1pbmcgYSBtYXRyaXgNCg0KVG8gaGVscCB5b3UgcmVtZW1iZXIgd2hhdCBpcyBzdG9yZWQgaW4gYHN0YXJfd2Fyc19tYXRyaXhgLCB5b3Ugd291bGQgbGlrZSB0byBhZGQgdGhlIG5hbWVzIG9mIHRoZSBtb3ZpZXMgZm9yIHRoZSByb3dzLiBOb3Qgb25seSBkb2VzIHRoaXMgaGVscCB5b3UgdG8gcmVhZCB0aGUgZGF0YSwgYnV0IGl0IGlzIGFsc28gdXNlZnVsIHRvIHNlbGVjdCBjZXJ0YWluIGVsZW1lbnRzIGZyb20gdGhlIG1hdHJpeC4NCg0KU2ltaWxhciB0byB2ZWN0b3JzLCB5b3UgY2FuIGFkZCBuYW1lcyBmb3IgdGhlIHJvd3MgYW5kIHRoZSBjb2x1bW5zIG9mIGEgbWF0cml4DQoNCmBgYHtyfQ0Kcm93bmFtZXMobXlfbWF0cml4KSA8LSByb3dfbmFtZXNfdmVjdG9yDQpjb2xuYW1lcyhteV9tYXRyaXgpIDwtIGNvbF9uYW1lc192ZWN0b3INCmBgYA0KDQpXZSB3ZW50IGFoZWFkIGFuZCBwcmVwYXJlZCB0d28gdmVjdG9ycyBmb3IgeW91OiBgcmVnaW9uYCwgYW5kIGB0aXRsZXNgLiBZb3Ugd2lsbCBuZWVkIHRoZXNlIHZlY3RvcnMgdG8gbmFtZSB0aGUgY29sdW1ucyBhbmQgcm93cyBvZiBgc3Rhcl93YXJzX21hdHJpeGAsIHJlc3BlY3RpdmVseS4NCg0KIyMjIEV4ZXJjaXNlDQoNCi0gVXNlIGBjb2xuYW1lcygpYCB0byBuYW1lIHRoZSBjb2x1bW5zIG9mIGBzdGFyX3dhcnNfbWF0cml4YCB3aXRoIHRoZSBgcmVnaW9uYCB2ZWN0b3IuDQotIFVzZSBgcm93bmFtZXMoKWAgdG8gbmFtZSB0aGUgcm93cyBvZiBgc3Rhcl93YXJzX21hdHJpeGAgd2l0aCB0aGUgYHRpdGxlc2AgdmVjdG9yLg0KLSBQcmludCBvdXQgYHN0YXJfd2Fyc19tYXRyaXhgIHRvIHNlZSB0aGUgcmVzdWx0IG9mIHlvdXIgd29yay4NCg0KYGBge3J9DQojIEJveCBvZmZpY2UgU3RhciBXYXJzIChpbiBtaWxsaW9ucyEpDQpuZXdfaG9wZSA8LSBjKDQ2MC45OTgsIDMxNC40KQ0KZW1waXJlX3N0cmlrZXMgPC0gYygyOTAuNDc1LCAyNDcuOTAwKQ0KcmV0dXJuX2plZGkgPC0gYygzMDkuMzA2LCAxNjUuOCkNCg0KIyBDb25zdHJ1Y3QgbWF0cml4DQpzdGFyX3dhcnNfbWF0cml4IDwtIG1hdHJpeChjKG5ld19ob3BlLCBlbXBpcmVfc3RyaWtlcywgcmV0dXJuX2plZGkpLCBucm93ID0gMywgYnlyb3cgPSBUUlVFKQ0KDQojIFZlY3RvcnMgcmVnaW9uIGFuZCB0aXRsZXMsIHVzZWQgZm9yIG5hbWluZw0KcmVnaW9uIDwtIGMoIlVTIiwgIm5vbi1VUyIpDQp0aXRsZXMgPC0gYygiQSBOZXcgSG9wZSIsICJUaGUgRW1waXJlIFN0cmlrZXMgQmFjayIsICJSZXR1cm4gb2YgdGhlIEplZGkiKQ0KDQojIE5hbWUgdGhlIGNvbHVtbnMgd2l0aCByZWdpb24NCg0KDQojIE5hbWUgdGhlIHJvd3Mgd2l0aCB0aXRsZXMNCg0KDQojIFByaW50IG91dCBzdGFyX3dhcnNfbWF0cml4DQpgYGANCg0KDQojIyBDYWxjdWxhdGluZyB0aGUgd29ybGR3aWRlIGJveCBvZmZpY2UNCg0KVGhlIHNpbmdsZSBtb3N0IGltcG9ydGFudCB0aGluZyBmb3IgYSBtb3ZpZSBpbiBvcmRlciB0byBiZWNvbWUgYW4gaW5zdGFudCBsZWdlbmQgaW4gVGluc2VsdG93biBpcyBpdHMgd29ybGR3aWRlIGJveCBvZmZpY2UgZmlndXJlcy4NCg0KVG8gY2FsY3VsYXRlIHRoZSB0b3RhbCBib3ggb2ZmaWNlIHJldmVudWUgZm9yIHRoZSB0aHJlZSBTdGFyIFdhcnMgbW92aWVzLCB5b3UgaGF2ZSB0byB0YWtlIHRoZSBzdW0gb2YgdGhlIFVTIHJldmVudWUgY29sdW1uIGFuZCB0aGUgbm9uLVVTIHJldmVudWUgY29sdW1uLg0KDQpJbiBSLCB0aGUgZnVuY3Rpb24gYHJvd1N1bXMoKWAgY29udmVuaWVudGx5IGNhbGN1bGF0ZXMgdGhlIHRvdGFscyBmb3IgZWFjaCByb3cgb2YgYSBtYXRyaXguIFRoaXMgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyB2ZWN0b3I6DQoNCmByb3dTdW1zKG15X21hdHJpeClgDQoNCiMjIyBFeGVyY2lzZQ0KDQpDYWxjdWxhdGUgdGhlIHdvcmxkd2lkZSBib3ggb2ZmaWNlIGZpZ3VyZXMgZm9yIHRoZSB0aHJlZSBtb3ZpZXMgYW5kIHB1dCB0aGVzZSBpbiB0aGUgdmVjdG9yIG5hbWVkIGB3b3JsZHdpZGVfdmVjdG9yYC4NCg0KYGBge3J9DQojIENvbnN0cnVjdCBzdGFyX3dhcnNfbWF0cml4DQpib3hfb2ZmaWNlIDwtIGMoNDYwLjk5OCwgMzE0LjQsIDI5MC40NzUsIDI0Ny45MDAsIDMwOS4zMDYsIDE2NS44KQ0Kc3Rhcl93YXJzX21hdHJpeCA8LSBtYXRyaXgoYm94X29mZmljZSwgbnJvdyA9IDMsIGJ5cm93ID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbW5hbWVzID0gbGlzdChjKCJBIE5ldyBIb3BlIiwgIlRoZSBFbXBpcmUgU3RyaWtlcyBCYWNrIiwgIlJldHVybiBvZiB0aGUgSmVkaSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJVUyIsICJub24tVVMiKSkpDQoNCiMgQ2FsY3VsYXRlIHdvcmxkd2lkZSBib3ggb2ZmaWNlIGZpZ3VyZXMNCndvcmxkd2lkZV92ZWN0b3IgPC0gDQpgYGANCg0KDQojIyBBZGRpbmcgYSBjb2x1bW4gZm9yIHRoZSBXb3JsZHdpZGUgYm94IG9mZmljZQ0KDQpJbiB0aGUgcHJldmlvdXMgZXhlcmNpc2UgeW91IGNhbGN1bGF0ZWQgdGhlIHZlY3RvciB0aGF0IGNvbnRhaW5lZCB0aGUgd29ybGR3aWRlIGJveCBvZmZpY2UgcmVjZWlwdCBmb3IgZWFjaCBvZiB0aGUgdGhyZWUgU3RhciBXYXJzIG1vdmllcy4gSG93ZXZlciwgdGhpcyB2ZWN0b3IgaXMgbm90IHlldCBwYXJ0IG9mIGBzdGFyX3dhcnNfbWF0cml4YC4NCg0KWW91IGNhbiBhZGQgYSBjb2x1bW4gb3IgbXVsdGlwbGUgY29sdW1ucyB0byBhIG1hdHJpeCB3aXRoIHRoZSBgY2JpbmQoKWAgZnVuY3Rpb24sIHdoaWNoIG1lcmdlcyBtYXRyaWNlcyBhbmQvb3IgdmVjdG9ycyB0b2dldGhlciBieSBjb2x1bW4uIEZvciBleGFtcGxlOg0KDQpgYmlnX21hdHJpeCA8LSBjYmluZChtYXRyaXgxLCBtYXRyaXgyLCB2ZWN0b3IxIC4uLilgDQoNCiMjIyBFeGVyY2lzZQ0KDQpBZGQgYHdvcmxkd2lkZV92ZWN0b3JgIGFzIGEgbmV3IGNvbHVtbiB0byB0aGUgYHN0YXJfd2Fyc19tYXRyaXhgIGFuZCBhc3NpZ24gdGhlIHJlc3VsdCB0byBgYWxsX3dhcnNfbWF0cml4YC4gVXNlIHRoZSBgY2JpbmQoKWAgZnVuY3Rpb24uDQoNCmBgYHtyfQ0KIyBDb25zdHJ1Y3Qgc3Rhcl93YXJzX21hdHJpeA0KYm94X29mZmljZSA8LSBjKDQ2MC45OTgsIDMxNC40LCAyOTAuNDc1LCAyNDcuOTAwLCAzMDkuMzA2LCAxNjUuOCkNCnN0YXJfd2Fyc19tYXRyaXggPC0gbWF0cml4KGJveF9vZmZpY2UsIG5yb3cgPSAzLCBieXJvdyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBkaW1uYW1lcyA9IGxpc3QoYygiQSBOZXcgSG9wZSIsICJUaGUgRW1waXJlIFN0cmlrZXMgQmFjayIsICJSZXR1cm4gb2YgdGhlIEplZGkiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiVVMiLCAibm9uLVVTIikpKQ0KDQojIFRoZSB3b3JsZHdpZGUgYm94IG9mZmljZSBmaWd1cmVzDQp3b3JsZHdpZGVfdmVjdG9yIDwtIHJvd1N1bXMoc3Rhcl93YXJzX21hdHJpeCkNCg0KIyBCaW5kIHRoZSBuZXcgdmFyaWFibGUgd29ybGR3aWRlX3ZlY3RvciBhcyBhIGNvbHVtbiB0byBzdGFyX3dhcnNfbWF0cml4DQphbGxfd2Fyc19tYXRyaXggPC0gDQpgYGANCg0KDQojIyBBZGRpbmcgYSByb3cNCg0KSnVzdCBsaWtlIGV2ZXJ5IGFjdGlvbiBoYXMgYSByZWFjdGlvbiwgZXZlcnkgYGNiaW5kKClgIGhhcyBhbiBgcmJpbmQoKWAuIChXZSBhZG1pdCwgd2UgYXJlIHByZXR0eSBiYWQgd2l0aCBtZXRhcGhvcnMuKQ0KDQpZb3VyIFIgd29ya3NwYWNlLCB3aGVyZSBhbGwgdmFyaWFibGVzIHlvdSBkZWZpbmVkICdsaXZlJyAoY2hlY2sgb3V0IHdoYXQgYSB3b3Jrc3BhY2UgaXMpLCBoYXMgYWxyZWFkeSBiZWVuIGluaXRpYWxpemVkIGFuZCBjb250YWlucyB0d28gbWF0cmljZXM6DQoNCi0gYHN0YXJfd2Fyc19tYXRyaXhgIHRoYXQgd2UgaGF2ZSB1c2VkIGFsbCBhbG9uZywgd2l0aCBkYXRhIG9uIHRoZSBmaXJzdCB0cmlsb2d5LA0KLSBgc3Rhcl93YXJzX21hdHJpeDJgLCB3aXRoIHNpbWlsYXIgZGF0YSBmb3IgdGhlIHNlY29uZCB0cmlsb2d5Lg0KDQpUeXBlIHRoZSBuYW1lIG9mIHRoZXNlIG1hdHJpY2VzIGluIHRoZSBjb25zb2xlIGFuZCBoaXQgRW50ZXIgaWYgeW91IHdhbnQgdG8gaGF2ZSBhIGNsb3NlciBsb29rLiBJZiB5b3Ugd2FudCB0byBjaGVjayBvdXQgdGhlIGNvbnRlbnRzIG9mIHRoZSB3b3Jrc3BhY2UsIHlvdSBjYW4gdHlwZSBgbHMoKWAgaW4gdGhlIGNvbnNvbGUuDQoNCiMjIyBFeGVyY2lzZQ0KVXNlIGByYmluZCgpYCB0byBwYXN0ZSB0b2dldGhlciBgc3Rhcl93YXJzX21hdHJpeGAgYW5kIGBzdGFyX3dhcnNfbWF0cml4MmAsIGluIHRoaXMgb3JkZXIuIEFzc2lnbiB0aGUgcmVzdWx0aW5nIG1hdHJpeCB0byBgYWxsX3dhcnNfbWF0cml4YC4NCg0KYGBge3J9DQojIHN0YXJfd2Fyc19tYXRyaXggYW5kIHN0YXJfd2Fyc19tYXRyaXgyIGFyZSBhdmFpbGFibGUgaW4geW91ciB3b3Jrc3BhY2UNCnN0YXJfd2Fyc19tYXRyaXggPC0gc3RydWN0dXJlKGMoNDYxLCAyOTAuNSwgMzA5LjMsIDMxNC40LCAyNDcuOSwgMTY1LjgpLCAuRGltID0gYygzTCwgMkwpLCAuRGltbmFtZXMgPSBsaXN0KGMoIkEgTmV3IEhvcGUiLCAiVGhlIEVtcGlyZSBTdHJpa2VzIEJhY2siLCAiUmV0dXJuIG9mIHRoZSBKZWRpIiksIGMoIlVTIiwgIm5vbi1VUyIpKSkNCnN0YXJfd2Fyc19tYXRyaXgyIDwtIHN0cnVjdHVyZShjKDQ3NC41LCAzMTAuNywgMzgwLjMsIDU1Mi41LCAzMzguNywgNDY4LjUpLCAuRGltID0gYygzTCwgMkwpLCAuRGltbmFtZXMgPSBsaXN0KGMoIlRoZSBQaGFudG9tIE1lbmFjZSIsICJBdHRhY2sgb2YgdGhlIENsb25lcyIsICJSZXZlbmdlIG9mIHRoZSBTaXRoIiksIGMoIlVTIiwgIm5vbi1VUyIpKSkNCg0KIyBDb21iaW5lIGJvdGggU3RhciBXYXJzIHRyaWxvZ2llcyBpbiBvbmUgbWF0cml4DQphbGxfd2Fyc19tYXRyaXggPC0gDQpgYGANCg0KDQojIyBUaGUgdG90YWwgYm94IG9mZmljZSByZXZlbnVlIGZvciB0aGUgZW50aXJlIHNhZ2ENCg0KSnVzdCBsaWtlIGV2ZXJ5IGBjYmluZCgpYCBoYXMgYSBgcmJpbmQoKWAsIGV2ZXJ5IGBjb2xTdW1zKClgIGhhcyBhIGByb3dTdW1zKClgLiBZb3VyIFIgd29ya3NwYWNlIGFscmVhZHkgY29udGFpbnMgdGhlIGBhbGxfd2Fyc19tYXRyaXhgIHRoYXQgeW91IGNvbnN0cnVjdGVkIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZTsgdHlwZSBgYWxsX3dhcnNfbWF0cml4YCB0byBoYXZlIGFub3RoZXIgbG9vay4gTGV0J3Mgbm93IGNhbGN1bGF0ZSB0aGUgdG90YWwgYm94IG9mZmljZSByZXZlbnVlIGZvciB0aGUgZW50aXJlIHNhZ2EuDQoNCiMjIyBFeGVyY2lzZQ0KDQotIENhbGN1bGF0ZSB0aGUgdG90YWwgcmV2ZW51ZSBmb3IgdGhlIFVTIGFuZCB0aGUgbm9uLVVTIHJlZ2lvbiBhbmQgYXNzaWduIGB0b3RhbF9yZXZlbnVlX3ZlY3RvcmAuIFlvdSBjYW4gdXNlIHRoZSBgY29sU3VtcygpYCBmdW5jdGlvbi4NCi0gUHJpbnQgb3V0IGB0b3RhbF9yZXZlbnVlX3ZlY3RvcmAgdG8gaGF2ZSBhIGxvb2sgYXQgdGhlIHJlc3VsdHMuDQoNCmBgYHtyfQ0KIyBhbGxfd2Fyc19tYXRyaXggaXMgYXZhaWxhYmxlIGluIHlvdXIgd29ya3NwYWNlDQphbGxfd2Fyc19tYXRyaXgNCg0KIyBUb3RhbCByZXZlbnVlIGZvciBVUyBhbmQgbm9uLVVTDQp0b3RhbF9yZXZlbnVlX3ZlY3RvciA8LSANCiAgDQojIFByaW50IG91dCB0b3RhbF9yZXZlbnVlX3ZlY3Rvcg0KYGBgDQoNCg0KIyMgU2VsZWN0aW9uIG9mIG1hdHJpeCBlbGVtZW50cw0KDQpTaW1pbGFyIHRvIHZlY3RvcnMsIHlvdSBjYW4gdXNlIHRoZSBzcXVhcmUgYnJhY2tldHMgYFtgIGBdYCB0byBzZWxlY3Qgb25lIG9yIG11bHRpcGxlIGVsZW1lbnRzIGZyb20gYSBtYXRyaXguIFdoZXJlYXMgdmVjdG9ycyBoYXZlIG9uZSBkaW1lbnNpb24sIG1hdHJpY2VzIGhhdmUgdHdvIGRpbWVuc2lvbnMuIFlvdSBzaG91bGQgdGhlcmVmb3JlIHVzZSBhIGNvbW1hIHRvIHNlcGFyYXRlIHRoYXQgd2hhdCB0byBzZWxlY3QgZnJvbSB0aGUgcm93cyBmcm9tIHRoYXQgd2hhdCB5b3Ugd2FudCB0byBzZWxlY3QgZnJvbSB0aGUgY29sdW1ucy4gRm9yIGV4YW1wbGU6DQoNCi0gYG15X21hdHJpeFsxLDJdYCBzZWxlY3RzIHRoZSBlbGVtZW50IGF0IHRoZSBmaXJzdCByb3cgYW5kIHNlY29uZCBjb2x1bW4uDQotIGBteV9tYXRyaXhbMTozLDI6NF1gIHJlc3VsdHMgaW4gYSBtYXRyaXggd2l0aCB0aGUgZGF0YSBvbiB0aGUgcm93cyAxLCAyLCAzIGFuZCBjb2x1bW5zIDIsIDMsIDQuDQoNCklmIHlvdSB3YW50IHRvIHNlbGVjdCBhbGwgZWxlbWVudHMgb2YgYSByb3cgb3IgYSBjb2x1bW4sIG5vIG51bWJlciBpcyBuZWVkZWQgYmVmb3JlIG9yIGFmdGVyIHRoZSBjb21tYSwgcmVzcGVjdGl2ZWx5Og0KDQotIGBteV9tYXRyaXhbLDFdYCBzZWxlY3RzIGFsbCBlbGVtZW50cyBvZiB0aGUgZmlyc3QgY29sdW1uLg0KLSBgbXlfbWF0cml4WzEsXWAgc2VsZWN0cyBhbGwgZWxlbWVudHMgb2YgdGhlIGZpcnN0IHJvdy4NCg0KQmFjayB0byBTdGFyIFdhcnMgd2l0aCB0aGlzIG5ld2x5IGFjcXVpcmVkIGtub3dsZWRnZSEgQXMgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlLCBgYWxsX3dhcnNfbWF0cml4YCBpcyBhbHJlYWR5IGF2YWlsYWJsZSBpbiB5b3VyIHdvcmtzcGFjZS4NCg0KIyMjIEV4ZXJjaXNlDQoNCi0gU2VsZWN0IHRoZSBub24tVVMgcmV2ZW51ZSBmb3IgYWxsIG1vdmllcyAodGhlIGVudGlyZSBzZWNvbmQgY29sdW1uIG9mIGFsbF93YXJzX21hdHJpeCksIHN0b3JlIHRoZSByZXN1bHQgYXMgYG5vbl91c19hbGxgLg0KLSBVc2UgYG1lYW4oKWAgb24gYG5vbl91c19hbGxgIHRvIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBub24tVVMgcmV2ZW51ZSBmb3IgYWxsIG1vdmllcy4gU2ltcGx5IHByaW50IG91dCB0aGUgcmVzdWx0Lg0KLSBUaGlzIHRpbWUsIHNlbGVjdCB0aGUgbm9uLVVTIHJldmVudWUgZm9yIHRoZSBmaXJzdCB0d28gbW92aWVzIGluIGBhbGxfd2Fyc19tYXRyaXhgLiBTdG9yZSB0aGUgcmVzdWx0IGFzIGBub25fdXNfc29tZWAuDQotIFVzZSBgbWVhbigpYCBhZ2FpbiB0byBwcmludCBvdXQgdGhlIGF2ZXJhZ2Ugb2YgdGhlIHZhbHVlcyBpbiBgbm9uX3VzX3NvbWVgLg0KDQpgYGB7cn0NCiMgYWxsX3dhcnNfbWF0cml4IGlzIGF2YWlsYWJsZSBpbiB5b3VyIHdvcmtzcGFjZQ0KYWxsX3dhcnNfbWF0cml4DQoNCiMgU2VsZWN0IHRoZSBub24tVVMgcmV2ZW51ZSBmb3IgYWxsIG1vdmllcw0Kbm9uX3VzX2FsbCA8LSANCiAgDQojIEF2ZXJhZ2Ugbm9uLVVTIHJldmVudWUNCg0KICANCiMgU2VsZWN0IHRoZSBub24tVVMgcmV2ZW51ZSBmb3IgZmlyc3QgdHdvIG1vdmllcw0Kbm9uX3VzX3NvbWUgPC0gDQogIA0KIyBBdmVyYWdlIG5vbi1VUyByZXZlbnVlIGZvciBmaXJzdCB0d28gbW92aWVzDQoNCmBgYA0KDQoNCiMjIEEgbGl0dGxlIGFyaXRobWV0aWMgd2l0aCBtYXRyaWNlcw0KDQpTaW1pbGFyIHRvIHdoYXQgeW91IGhhdmUgbGVhcm5lZCB3aXRoIHZlY3RvcnMsIHRoZSBzdGFuZGFyZCBvcGVyYXRvcnMgbGlrZSBgK2AsIGAtYCwgYC9gLCBgKmAsIGV0Yy4gd29yayBpbiBhbiBlbGVtZW50LXdpc2Ugd2F5IG9uIG1hdHJpY2VzIGluIFIuDQoNCkZvciBleGFtcGxlLCBgMiAqIG15X21hdHJpeGAgbXVsdGlwbGllcyBlYWNoIGVsZW1lbnQgb2YgYG15X21hdHJpeGAgYnkgdHdvLg0KDQpBcyBhIG5ld2x5LWhpcmVkIGRhdGEgYW5hbHlzdCBmb3IgTHVjYXNmaWxtLCBpdCBpcyB5b3VyIGpvYiBpcyB0byBmaW5kIG91dCBob3cgbWFueSB2aXNpdG9ycyB3ZW50IHRvIGVhY2ggbW92aWUgZm9yIGVhY2ggZ2VvZ3JhcGhpY2FsIGFyZWEuIFlvdSBhbHJlYWR5IGhhdmUgdGhlIHRvdGFsIHJldmVudWUgZmlndXJlcyBpbiBgYWxsX3dhcnNfbWF0cml4YC4gQXNzdW1lIHRoYXQgdGhlIHByaWNlIG9mIGEgdGlja2V0IHdhcyA1IGRvbGxhcnMuIFNpbXBseSBkaXZpZGluZyB0aGUgYm94IG9mZmljZSBudW1iZXJzIGJ5IHRoaXMgdGlja2V0IHByaWNlIGdpdmVzIHlvdSB0aGUgbnVtYmVyIG9mIHZpc2l0b3JzLg0KDQojIyMgRXhlcmNpc2UNCg0KLSBEaXZpZGUgYGFsbF93YXJzX21hdHJpeGAgYnkgNSwgZ2l2aW5nIHlvdSB0aGUgbnVtYmVyIG9mIHZpc2l0b3JzIGluIG1pbGxpb25zLiBBc3NpZ24gdGhlIHJlc3VsdGluZyBtYXRyaXggdG8gYHZpc2l0b3JzYC4NCi0gUHJpbnQgb3V0IGB2aXNpdG9yc2Agc28geW91IGNhbiBoYXZlIGEgbG9vay4NCg0KYGBge3J9DQojIGFsbF93YXJzX21hdHJpeCBpcyBhdmFpbGFibGUgaW4geW91ciB3b3Jrc3BhY2UNCmFsbF93YXJzX21hdHJpeA0KDQojIEVzdGltYXRlIHRoZSB2aXNpdG9ycw0KdmlzaXRvcnMgPC0gDQogIA0KIyBQcmludCB0aGUgZXN0aW1hdGUgdG8gdGhlIGNvbnNvbGUNCg0KYGBgDQoNCg0KIyMgQSBsaXR0bGUgYXJpdGhtZXRpYyB3aXRoIG1hdHJpY2VzICgyKQ0KDQpKdXN0IGxpa2UgYDIgKiBteV9tYXRyaXhgIG11bHRpcGxpZWQgZXZlcnkgZWxlbWVudCBvZiBgbXlfbWF0cml4YCBieSB0d28sIGBteV9tYXRyaXgxICogbXlfbWF0cml4MmAgY3JlYXRlcyBhIG1hdHJpeCB3aGVyZSBlYWNoIGVsZW1lbnQgaXMgdGhlIHByb2R1Y3Qgb2YgdGhlIGNvcnJlc3BvbmRpbmcgZWxlbWVudHMgaW4gYG15X21hdHJpeDFgIGFuZCBgbXlfbWF0cml4MmAuDQoNCkFmdGVyIGxvb2tpbmcgYXQgdGhlIHJlc3VsdCBvZiB0aGUgcHJldmlvdXMgZXhlcmNpc2UsIGJpZyBib3NzIEx1Y2FzIHBvaW50cyBvdXQgdGhhdCB0aGUgdGlja2V0IHByaWNlcyB3ZW50IHVwIG92ZXIgdGltZS4gSGUgYXNrcyB0byByZWRvIHRoZSBhbmFseXNpcyBiYXNlZCBvbiB0aGUgcHJpY2VzIHlvdSBjYW4gZmluZCBpbiBgdGlja2V0X3ByaWNlc19tYXRyaXhgIChzb3VyY2U6IGltYWdpbmF0aW9uKS4NCg0KVGhvc2Ugd2hvIGFyZSBmYW1pbGlhciB3aXRoIG1hdHJpY2VzIHNob3VsZCBub3RlIHRoYXQgdGhpcyBpcyBub3QgdGhlIHN0YW5kYXJkIG1hdHJpeCBtdWx0aXBsaWNhdGlvbiBmb3Igd2hpY2ggeW91IHNob3VsZCB1c2UgYCUqJWAgaW4gUi4NCg0KIyMjIEV4ZXJjaXNlIA0KDQotIERpdmlkZSBgYWxsX3dhcnNfbWF0cml4YCBieSBgdGlja2V0X3ByaWNlc19tYXRyaXhgIHRvIGdldCB0aGUgZXN0aW1hdGVkIG51bWJlciBvZiBVUyBhbmQgbm9uLVVTIHZpc2l0b3JzIGZvciB0aGUgc2l4IG1vdmllcy4gQXNzaWduIHRoZSByZXN1bHQgdG8gYHZpc2l0b3JzYC4NCi0gRnJvbSB0aGUgYHZpc2l0b3JzYCBtYXRyaXgsIHNlbGVjdCB0aGUgZW50aXJlIGZpcnN0IGNvbHVtbiwgcmVwcmVzZW50aW5nIHRoZSBudW1iZXIgb2YgdmlzaXRvcnMgaW4gdGhlIFVTLiBTdG9yZSB0aGlzIHNlbGVjdGlvbiBhcyBgdXNfdmlzaXRvcnNgLg0KLSBDYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIFVTIHZpc2l0b3JzOyBwcmludCBvdXQgdGhlIHJlc3VsdC4NCg0KYGBge3J9DQojIGFsbF93YXJzX21hdHJpeCBhbmQgdGlja2V0X3ByaWNlc19tYXRyaXggYXJlIGF2YWlsYWJsZSBpbiB5b3VyIHdvcmtzcGFjZQ0KYWxsX3dhcnNfbWF0cml4DQp0aWNrZXRfcHJpY2VzX21hdHJpeCA8LSBzdHJ1Y3R1cmUoYyg1LCA2LCA3LCA0LCA0LjUsIDQuOSwgNSwgNiwgNywgNCwgNC41LCA0LjkpLCAuRGltID0gYyg2TCwgMkwpLCAuRGltbmFtZXMgPSBsaXN0KGMoIkEgTmV3IEhvcGUiLCAiVGhlIEVtcGlyZSBTdHJpa2VzIEJhY2siLCAgIlJldHVybiBvZiB0aGUgSmVkaSIsICJUaGUgUGhhbnRvbSBNZW5hY2UiLCAiQXR0YWNrIG9mIHRoZSBDbG9uZXMiLCAiUmV2ZW5nZSBvZiB0aGUgU2l0aCIpLCBjKCJVUyIsICJub24tVVMiKSkpDQoNCiMgRXN0aW1hdGVkIG51bWJlciBvZiB2aXNpdG9ycw0KdmlzaXRvcnMgPC0gDQoNCiMgVVMgdmlzaXRvcnMNCnVzX3Zpc2l0b3JzIDwtIA0KDQojIEF2ZXJhZ2UgbnVtYmVyIG9mIFVTIHZpc2l0b3JzDQoNCmBgYA0KDQoNCg0KIyBGYWN0b3JzDQoNCiMjIFdoYXQncyBhIGZhY3RvciBhbmQgd2h5IHdvdWxkIHlvdSB1c2UgaXQ/DQoNCkluIHRoaXMgY2hhcHRlciB5b3UgZGl2ZSBpbnRvIHRoZSB3b25kZXJmdWwgd29ybGQgb2YgKipmYWN0b3JzKiouDQoNClRoZSB0ZXJtIGZhY3RvciByZWZlcnMgdG8gYSBzdGF0aXN0aWNhbCBkYXRhIHR5cGUgdXNlZCB0byBzdG9yZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuIFRoZSBkaWZmZXJlbmNlIGJldHdlZW4gYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBhbmQgYSBjb250aW51b3VzIHZhcmlhYmxlIGlzIHRoYXQgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBjYW4gYmVsb25nIHRvIGEgKipsaW1pdGVkIG51bWJlciBvZiBjYXRlZ29yaWVzKiouIEEgY29udGludW91cyB2YXJpYWJsZSwgb24gdGhlIG90aGVyIGhhbmQsIGNhbiBjb3JyZXNwb25kIHRvIGFuIGluZmluaXRlIG51bWJlciBvZiB2YWx1ZXMuDQoNCkl0IGlzIGltcG9ydGFudCB0aGF0IFIga25vd3Mgd2hldGhlciBpdCBpcyBkZWFsaW5nIHdpdGggYSBjb250aW51b3VzIG9yIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUsIGFzIHRoZSBzdGF0aXN0aWNhbCBtb2RlbHMgeW91IHdpbGwgZGV2ZWxvcCBpbiB0aGUgZnV0dXJlIHRyZWF0IGJvdGggdHlwZXMgZGlmZmVyZW50bHkuIChZb3Ugd2lsbCBzZWUgbGF0ZXIgd2h5IHRoaXMgaXMgdGhlIGNhc2UuKQ0KDQpBIGdvb2QgZXhhbXBsZSBvZiBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGlzIHRoZSB2YXJpYWJsZSAnR2VuZGVyJy4gQSBodW1hbiBpbmRpdmlkdWFsIGNhbiBlaXRoZXIgYmUgIk1hbGUiIG9yICJGZW1hbGUiLCBtYWtpbmcgYWJzdHJhY3Rpb24gb2YgaW50ZXItc2V4ZXMuIFNvIGhlcmUgIk1hbGUiIGFuZCAiRmVtYWxlIiBhcmUsIGluIGEgc2ltcGxpZmllZCBzZW5zZSwgdGhlIHR3byB2YWx1ZXMgb2YgdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlICJHZW5kZXIiLCBhbmQgZXZlcnkgb2JzZXJ2YXRpb24gY2FuIGJlIGFzc2lnbmVkIHRvIGVpdGhlciB0aGUgdmFsdWUgIk1hbGUiIG9mICJGZW1hbGUiLg0KDQojIyMgRXhlcmNpc2UNCg0KQXNzaWduIHRvIHZhcmlhYmxlIGB0aGVvcnlgIHRoZSB2YWx1ZSBgImZhY3RvcnMgZm9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyJgLg0KDQpgYGB7cn0NCiMgQXNzaWduIHRvIHRoZSB2YXJpYWJsZSB0aGVvcnkgd2hhdCB0aGlzIGNoYXB0ZXIgaXMgYWJvdXQhDQpgYGANCg0KDQojIyBXaGF0J3MgYSBmYWN0b3IgYW5kIHdoeSB3b3VsZCB5b3UgdXNlIGl0PyAoMikNCg0KVG8gY3JlYXRlIGZhY3RvcnMgaW4gUiwgeW91IG1ha2UgdXNlIG9mIHRoZSBmdW5jdGlvbiBgZmFjdG9yKClgLiBGaXJzdCB0aGluZyB0aGF0IHlvdSBoYXZlIHRvIGRvIGlzIGNyZWF0ZSBhIHZlY3RvciB0aGF0IGNvbnRhaW5zIGFsbCB0aGUgb2JzZXJ2YXRpb25zIHRoYXQgYmVsb25nIHRvIGEgbGltaXRlZCBudW1iZXIgb2YgY2F0ZWdvcmllcy4gRm9yIGV4YW1wbGUsIGBnZW5kZXJfdmVjdG9yYCBjb250YWlucyB0aGUgc2V4IG9mIDUgZGlmZmVyZW50IGluZGl2aWR1YWxzOg0KDQpgZ2VuZGVyX3ZlY3RvciA8LSBjKCJNYWxlIiwiRmVtYWxlIiwiRmVtYWxlIiwiTWFsZSIsIk1hbGUiKWANCg0KSXQgaXMgY2xlYXIgdGhhdCB0aGVyZSBhcmUgdHdvIGNhdGVnb3JpZXMsIG9yIGluIFItdGVybXMgKionZmFjdG9yIGxldmVscycqKiwgYXQgd29yayBoZXJlOiAiTWFsZSIgYW5kICJGZW1hbGUiLg0KDQpUaGUgZnVuY3Rpb24gYGZhY3RvcigpYCB3aWxsIGVuY29kZSB0aGUgdmVjdG9yIGFzIGEgZmFjdG9yOg0KDQpgZmFjdG9yX2dlbmRlcl92ZWN0b3IgPC0gZmFjdG9yKGdlbmRlcl92ZWN0b3IpYA0KDQojIyMgRXhlcmNpc2UNCg0KLSBDb252ZXJ0IHRoZSBjaGFyYWN0ZXIgdmVjdG9yIGBnZW5kZXJfdmVjdG9yYCB0byBhIGZhY3RvciB3aXRoIGBmYWN0b3IoKWAgYW5kIGFzc2lnbiB0aGUgcmVzdWx0IHRvIGBmYWN0b3JfZ2VuZGVyX3ZlY3RvcmANCi0gUHJpbnQgb3V0IGBmYWN0b3JfZ2VuZGVyX3ZlY3RvcmAgYW5kIGFzc2VydCB0aGF0IFIgcHJpbnRzIG91dCB0aGUgZmFjdG9yIGxldmVscyBiZWxvdyB0aGUgYWN0dWFsIHZhbHVlcy4NCg0KYGBge3J9DQojIEdlbmRlciB2ZWN0b3INCmdlbmRlcl92ZWN0b3IgPC0gYygiTWFsZSIsICJGZW1hbGUiLCAiRmVtYWxlIiwgIk1hbGUiLCAiTWFsZSIpDQoNCiMgQ29udmVydCBnZW5kZXJfdmVjdG9yIHRvIGEgZmFjdG9yDQpmYWN0b3JfZ2VuZGVyX3ZlY3RvciA8LQ0KDQojIFByaW50IG91dCBmYWN0b3JfZ2VuZGVyX3ZlY3Rvcg0KDQpgYGANCg0KDQojIyBXaGF0J3MgYSBmYWN0b3IgYW5kIHdoeSB3b3VsZCB5b3UgdXNlIGl0PyAoMykNCg0KVGhlcmUgYXJlIHR3byB0eXBlcyBvZiBjYXRlZ29yaWNhbCB2YXJpYWJsZXM6IGEgKipub21pbmFsIGNhdGVnb3JpY2FsIHZhcmlhYmxlKiogYW5kIGFuICoqb3JkaW5hbCBjYXRlZ29yaWNhbCB2YXJpYWJsZSoqLg0KDQpBIG5vbWluYWwgdmFyaWFibGUgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSB3aXRob3V0IGFuIGltcGxpZWQgb3JkZXIuIFRoaXMgbWVhbnMgdGhhdCBpdCBpcyBpbXBvc3NpYmxlIHRvIHNheSB0aGF0ICdvbmUgaXMgd29ydGggbW9yZSB0aGFuIHRoZSBvdGhlcicuIEZvciBleGFtcGxlLCB0aGluayBvZiB0aGUgY2F0ZWdvcmljYWwgdmFyaWFibGUgYGFuaW1hbHNfdmVjdG9yYCB3aXRoIHRoZSBjYXRlZ29yaWVzIGAiRWxlcGhhbnQiYCwgYCJHaXJhZmZlImAsIGAiRG9ua2V5ImAgYW5kIGAiSG9yc2UiYC4gSGVyZSwgaXQgaXMgaW1wb3NzaWJsZSB0byBzYXkgdGhhdCBvbmUgc3RhbmRzIGFib3ZlIG9yIGJlbG93IHRoZSBvdGhlci4gKE5vdGUgdGhhdCBzb21lIG9mIHlvdSBtaWdodCBkaXNhZ3JlZSA7LSkgKS4NCg0KSW4gY29udHJhc3QsIG9yZGluYWwgdmFyaWFibGVzIGRvIGhhdmUgYSBuYXR1cmFsIG9yZGVyaW5nLiBDb25zaWRlciBmb3IgZXhhbXBsZSB0aGUgY2F0ZWdvcmljYWwgdmFyaWFibGUgYHRlbXBlcmF0dXJlX3ZlY3RvcmAgd2l0aCB0aGUgY2F0ZWdvcmllczogYCJMb3ciYCwgYCJNZWRpdW0iYCBhbmQgYCJIaWdoImAuIEhlcmUgaXQgaXMgb2J2aW91cyB0aGF0IGAiTWVkaXVtImAgc3RhbmRzIGFib3ZlIGAiTG93ImAsIGFuZCBgIkhpZ2giYCBzdGFuZHMgYWJvdmUgYCJNZWRpdW0iYC4NCg0KIyMjIEV4ZXJjaXNlDQoNCi0gQ2xpY2sgJ1J1bicgdG8gY2hlY2sgaG93IFIgY29uc3RydWN0cyBhbmQgcHJpbnRzIG5vbWluYWwgYW5kIG9yZGluYWwgdmFyaWFibGVzLiBEbyBub3Qgd29ycnkgaWYgeW91IGRvIG5vdCB1bmRlcnN0YW5kIGFsbCB0aGUgY29kZSBqdXN0IHlldCwgd2Ugd2lsbCBnZXQgdG8gdGhhdC4NCg0KYGBge3J9DQojIEFuaW1hbHMNCmFuaW1hbHNfdmVjdG9yIDwtIGMoIkVsZXBoYW50IiwgIkdpcmFmZmUiLCAiRG9ua2V5IiwgIkhvcnNlIikNCmZhY3Rvcl9hbmltYWxzX3ZlY3RvciA8LSBmYWN0b3IoYW5pbWFsc192ZWN0b3IpDQpmYWN0b3JfYW5pbWFsc192ZWN0b3INCg0KIyBUZW1wZXJhdHVyZQ0KdGVtcGVyYXR1cmVfdmVjdG9yIDwtIGMoIkhpZ2giLCAiTG93IiwgIkhpZ2giLCJMb3ciLCAiTWVkaXVtIikNCmZhY3Rvcl90ZW1wZXJhdHVyZV92ZWN0b3IgPC0gZmFjdG9yKHRlbXBlcmF0dXJlX3ZlY3Rvciwgb3JkZXIgPSBUUlVFLCBsZXZlbHMgPSBjKCJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSkNCmZhY3Rvcl90ZW1wZXJhdHVyZV92ZWN0b3INCmBgYA0KDQoNCiMjIEZhY3RvciBsZXZlbHMNCg0KV2hlbiB5b3UgZmlyc3QgZ2V0IGEgZGF0YSBzZXQsIHlvdSB3aWxsIG9mdGVuIG5vdGljZSB0aGF0IGl0IGNvbnRhaW5zIGZhY3RvcnMgd2l0aCBzcGVjaWZpYyBmYWN0b3IgbGV2ZWxzLiBIb3dldmVyLCBzb21ldGltZXMgeW91IHdpbGwgd2FudCB0byBjaGFuZ2UgdGhlIG5hbWVzIG9mIHRoZXNlIGxldmVscyBmb3IgY2xhcml0eSBvciBvdGhlciByZWFzb25zLiBSIGFsbG93cyB5b3UgdG8gZG8gdGhpcyB3aXRoIHRoZSBmdW5jdGlvbiBgbGV2ZWxzKClgOg0KDQpgbGV2ZWxzKGZhY3Rvcl92ZWN0b3IpIDwtIGMoIm5hbWUxIiwgIm5hbWUyIiwuLi4pYA0KDQpBIGdvb2QgaWxsdXN0cmF0aW9uIGlzIHRoZSByYXcgZGF0YSB0aGF0IGlzIHByb3ZpZGVkIHRvIHlvdSBieSBhIHN1cnZleS4gQSBzdGFuZGFyZCBxdWVzdGlvbiBmb3IgZXZlcnkgcXVlc3Rpb25uYWlyZSBpcyB0aGUgZ2VuZGVyIG9mIHRoZSByZXNwb25kZW50LiBZb3UgcmVtZW1iZXIgZnJvbSB0aGUgcHJldmlvdXMgcXVlc3Rpb24gdGhhdCB0aGlzIGlzIGEgZmFjdG9yIGFuZCB3aGVuIHBlcmZvcm1pbmcgdGhlIHF1ZXN0aW9ubmFpcmUgb24gdGhlIHN0cmVldHMgaXRzIGxldmVscyBhcmUgb2Z0ZW4gY29kZWQgYXMgYCJNImAgYW5kIGAiRiJgLg0KDQpgc3VydmV5X3ZlY3RvciA8LSBjKCJNIiwgIkYiLCAiRiIsICJNIiwgIk0iKWANCg0KTmV4dCwgd2hlbiB5b3Ugd2FudCB0byBzdGFydCB5b3VyIGRhdGEgYW5hbHlzaXMsIHlvdXIgbWFpbiBjb25jZXJuIGlzIHRvIGtlZXAgYSBuaWNlIG92ZXJ2aWV3IG9mIGFsbCB0aGUgdmFyaWFibGVzIGFuZCB3aGF0IHRoZXkgbWVhbi4gQXQgdGhhdCBwb2ludCwgeW91IHdpbGwgb2Z0ZW4gd2FudCB0byBjaGFuZ2UgdGhlIGZhY3RvciBsZXZlbHMgdG8gYCJNYWxlImAgYW5kIGAiRmVtYWxlImAgaW5zdGVhZCBvZiBgIk0iYCBhbmQgYCJGImAgdG8gbWFrZSB5b3VyIGxpZmUgZWFzaWVyLg0KDQoqKldhdGNoIG91dCoqOiB0aGUgb3JkZXIgd2l0aCB3aGljaCB5b3UgYXNzaWduIHRoZSBsZXZlbHMgaXMgaW1wb3J0YW50LiBJZiB5b3UgdHlwZSBgbGV2ZWxzKGZhY3Rvcl9zdXJ2ZXlfdmVjdG9yKWAsIHlvdSdsbCBzZWUgdGhhdCBpdCBvdXRwdXRzIGBbMV0gIkYiICJNImAuIElmIHlvdSBkb24ndCBzcGVjaWZ5IHRoZSBsZXZlbHMgb2YgdGhlIGZhY3RvciB3aGVuIGNyZWF0aW5nIHRoZSB2ZWN0b3IsIFIgd2lsbCBhdXRvbWF0aWNhbGx5IGFzc2lnbiB0aGVtIGFscGhhYmV0aWNhbGx5LiBUbyBjb3JyZWN0bHkgbWFwIGAiRiJgIHRvIGAiRmVtYWxlImAgYW5kIGAiTSJgIHRvIGAiTWFsZSJgLCB0aGUgbGV2ZWxzIHNob3VsZCBiZSBzZXQgdG8gYGMoIkZlbWFsZSIsICJNYWxlIilgLCBpbiB0aGlzIG9yZGVyIG9yZGVyLg0KDQojIyMgRXhlcmNpc2UNCg0KLSBDaGVjayBvdXQgdGhlIGNvZGUgdGhhdCBidWlsZHMgYSBmYWN0b3IgdmVjdG9yIGZyb20gYHN1cnZleV92ZWN0b3JgLiBZb3Ugc2hvdWxkIHVzZSBgZmFjdG9yX3N1cnZleV92ZWN0b3JgIGluIHRoZSBuZXh0IGluc3RydWN0aW9uLg0KLSBDaGFuZ2UgdGhlIGZhY3RvciBsZXZlbHMgb2YgYGZhY3Rvcl9zdXJ2ZXlfdmVjdG9yYCB0byBgYygiRmVtYWxlIiwgIk1hbGUiKWAuIE1pbmQgdGhlIG9yZGVyIG9mIHRoZSB2ZWN0b3IgZWxlbWVudHMgaGVyZS4NCg0KYGBge3J9DQojIENvZGUgdG8gYnVpbGQgZmFjdG9yX3N1cnZleV92ZWN0b3INCnN1cnZleV92ZWN0b3IgPC0gYygiTSIsICJGIiwgIkYiLCAiTSIsICJNIikNCmZhY3Rvcl9zdXJ2ZXlfdmVjdG9yIDwtIGZhY3RvcihzdXJ2ZXlfdmVjdG9yKQ0KDQojIFNwZWNpZnkgdGhlIGxldmVscyBvZiBmYWN0b3Jfc3VydmV5X3ZlY3Rvcg0KbGV2ZWxzKGZhY3Rvcl9zdXJ2ZXlfdmVjdG9yKSA8LQ0KDQpmYWN0b3Jfc3VydmV5X3ZlY3Rvcg0KYGBgDQoNCg0KIyMgU3VtbWFyaXppbmcgYSBmYWN0b3INCg0KQWZ0ZXIgZmluaXNoaW5nIHRoaXMgY291cnNlLCBvbmUgb2YgeW91ciBmYXZvcml0ZSBmdW5jdGlvbnMgaW4gUiB3aWxsIGJlIGBzdW1tYXJ5KClgLiBUaGlzIHdpbGwgZ2l2ZSB5b3UgYSBxdWljayBvdmVydmlldyBvZiB0aGUgY29udGVudHMgb2YgYSB2YXJpYWJsZToNCg0KYHN1bW1hcnkobXlfdmFyKWANCg0KR29pbmcgYmFjayB0byBvdXIgc3VydmV5LCB5b3Ugd291bGQgbGlrZSB0byBrbm93IGhvdyBtYW55IGAiTWFsZSJgIHJlc3BvbnNlcyB5b3UgaGF2ZSBpbiB5b3VyIHN0dWR5LCBhbmQgaG93IG1hbnkgYCJGZW1hbGUiYCByZXNwb25zZXMuIFRoZSBgc3VtbWFyeSgpYCBmdW5jdGlvbiBnaXZlcyB5b3UgdGhlIGFuc3dlciB0byB0aGlzIHF1ZXN0aW9uLg0KDQojIyMgRXhlcmNpc2UNCg0KQXNrIGEgYHN1bW1hcnkoKWAgb2YgdGhlIGBzdXJ2ZXlfdmVjdG9yYCBhbmQgYGZhY3Rvcl9zdXJ2ZXlfdmVjdG9yYC4gSW50ZXJwcmV0IHRoZSByZXN1bHRzIG9mIGJvdGggdmVjdG9ycy4gQXJlIHRoZXkgYm90aCBlcXVhbGx5IHVzZWZ1bCBpbiB0aGlzIGNhc2U/DQoNCmBgYHtyfQ0KIyBCdWlsZCBmYWN0b3Jfc3VydmV5X3ZlY3RvciB3aXRoIGNsZWFuIGxldmVscw0Kc3VydmV5X3ZlY3RvciA8LSBjKCJNIiwgIkYiLCAiRiIsICJNIiwgIk0iKQ0KZmFjdG9yX3N1cnZleV92ZWN0b3IgPC0gZmFjdG9yKHN1cnZleV92ZWN0b3IpDQpsZXZlbHMoZmFjdG9yX3N1cnZleV92ZWN0b3IpIDwtIGMoIkZlbWFsZSIsICJNYWxlIikNCmZhY3Rvcl9zdXJ2ZXlfdmVjdG9yDQoNCiMgR2VuZXJhdGUgc3VtbWFyeSBmb3Igc3VydmV5X3ZlY3Rvcg0KDQoNCiMgR2VuZXJhdGUgc3VtbWFyeSBmb3IgZmFjdG9yX3N1cnZleV92ZWN0b3INCg0KYGBgDQoNCg0KIyMgQmF0dGxlIG9mIHRoZSBzZXhlcw0KDQpJbiBgZmFjdG9yX3N1cnZleV92ZWN0b3JgIHdlIGhhdmUgYSBmYWN0b3Igd2l0aCB0d28gbGV2ZWxzOiBgTWFsZWAgYW5kIGBGZW1hbGVgLiBCdXQgaG93IGRvZXMgUiB2YWx1ZSB0aGVzZSByZWxhdGl2ZWx5IHRvIGVhY2ggb3RoZXI/IEluIG90aGVyIHdvcmRzLCB3aG8gZG9lcyBSIHRoaW5rIGlzIGJldHRlciwgbWFsZXMgb3IgZmVtYWxlcz8NCg0KIyMjIEV4ZXJjaXNlDQoNClJlYWQgdGhlIGNvZGUgaW4gdGhlIGVkaXRvciBhbmQgY2xpY2sgJ1J1bicgdG8gc2VlIHdoZXRoZXIgbWFsZXMgYXJlIHdvcnRoIG1vcmUgdGhhbiBmZW1hbGVzLg0KDQpgYGB7cn0NCiMgQnVpbGQgZmFjdG9yX3N1cnZleV92ZWN0b3Igd2l0aCBjbGVhbiBsZXZlbHMNCnN1cnZleV92ZWN0b3IgPC0gYygiTSIsICJGIiwgIkYiLCAiTSIsICJNIikNCmZhY3Rvcl9zdXJ2ZXlfdmVjdG9yIDwtIGZhY3RvcihzdXJ2ZXlfdmVjdG9yKQ0KbGV2ZWxzKGZhY3Rvcl9zdXJ2ZXlfdmVjdG9yKSA8LSBjKCJGZW1hbGUiLCAiTWFsZSIpDQoNCiMgTWFsZQ0KbWFsZSA8LSBmYWN0b3Jfc3VydmV5X3ZlY3RvclsxXQ0KDQojIEZlbWFsZQ0KZmVtYWxlIDwtIGZhY3Rvcl9zdXJ2ZXlfdmVjdG9yWzJdDQoNCiMgQmF0dGxlIG9mIHRoZSBzZXhlczogTWFsZSAnbGFyZ2VyJyB0aGFuIGZlbWFsZT8NCm1hbGUgPiBmZW1hbGUNCmBgYA0KDQojIyBPcmRlcmVkIGZhY3RvcnMNCg0KU2luY2UgYCJNYWxlImAgYW5kIGAiRmVtYWxlImAgYXJlIHVub3JkZXJlZCAob3Igbm9taW5hbCkgZmFjdG9yIGxldmVscywgUiByZXR1cm5zIGEgd2FybmluZyBtZXNzYWdlLCB0ZWxsaW5nIHlvdSB0aGF0IHRoZSBncmVhdGVyIHRoYW4gb3BlcmF0b3IgaXMgbm90IG1lYW5pbmdmdWwuIEFzIHNlZW4gYmVmb3JlLCBSIGF0dGFjaGVzIGFuIGVxdWFsIHZhbHVlIHRvIHRoZSBsZXZlbHMgZm9yIHN1Y2ggZmFjdG9ycy4NCg0KQnV0IHRoaXMgaXMgbm90IGFsd2F5cyB0aGUgY2FzZSEgU29tZXRpbWVzIHlvdSB3aWxsIGFsc28gZGVhbCB3aXRoIGZhY3RvcnMgdGhhdCBkbyBoYXZlIGEgbmF0dXJhbCBvcmRlcmluZyBiZXR3ZWVuIGl0cyBjYXRlZ29yaWVzLiBJZiB0aGlzIGlzIHRoZSBjYXNlLCB3ZSBoYXZlIHRvIG1ha2Ugc3VyZSB0aGF0IHdlIHBhc3MgdGhpcyBpbmZvcm1hdGlvbiB0byBSLi4uDQoNCkxldCB1cyBzYXkgdGhhdCB5b3UgYXJlIGxlYWRpbmcgYSByZXNlYXJjaCB0ZWFtIG9mIGZpdmUgZGF0YSBhbmFseXN0cyBhbmQgdGhhdCB5b3Ugd2FudCB0byBldmFsdWF0ZSB0aGVpciBwZXJmb3JtYW5jZS4gVG8gZG8gdGhpcywgeW91IHRyYWNrIHRoZWlyIHNwZWVkLCBldmFsdWF0ZSBlYWNoIGFuYWx5c3QgYXMgYCJzbG93ImAsIGAiZmFzdCJgIG9yIGAiaW5zYW5lImAsIGFuZCBzYXZlIHRoZSByZXN1bHRzIGluIGBzcGVlZF92ZWN0b3JgLg0KDQojIyMgRXhlcmNpc2UNCg0KQXMgYSBmaXJzdCBzdGVwLCBhc3NpZ24gYHNwZWVkX3ZlY3RvcmAgYSB2ZWN0b3Igd2l0aCA1IGVudHJpZXMsIG9uZSBmb3IgZWFjaCBhbmFseXN0LiBFYWNoIGVudHJ5IHNob3VsZCBiZSBlaXRoZXIgYCJzbG93ImAsIGAiZmFzdCJgLCBvciBgImluc2FuZSJgLiBVc2UgdGhlIGxpc3QgYmVsb3c6DQoNCi0gQW5hbHlzdCAxIGlzIGBmYXN0YCwNCi0gQW5hbHlzdCAyIGlzIGBzbG93YCwNCi0gQW5hbHlzdCAzIGlzIGBzbG93YCwNCi0gQW5hbHlzdCA0IGlzIGBmYXN0YCBhbmQNCi0gQW5hbHlzdCA1IGlzIGBpbnNhbmVgLg0KDQpObyBuZWVkIHRvIHNwZWNpZnkgdGhlc2UgYXJlIGZhY3RvcnMgeWV0Lg0KDQpgYGB7cn0NCiMgQ3JlYXRlIHNwZWVkX3ZlY3Rvcg0Kc3BlZWRfdmVjdG9yIDwtDQpgYGANCg0KDQojIyBPcmRlcmVkIGZhY3RvcnMgKDIpDQoNCmBzcGVlZF92ZWN0b3JgIHNob3VsZCBiZSBjb252ZXJ0ZWQgdG8gYW4gb3JkaW5hbCBmYWN0b3Igc2luY2UgaXRzIGNhdGVnb3JpZXMgaGF2ZSBhIG5hdHVyYWwgb3JkZXJpbmcuIEJ5IGRlZmF1bHQsIHRoZSBmdW5jdGlvbiBgZmFjdG9yKClgIHRyYW5zZm9ybXMgYHNwZWVkX3ZlY3RvcmAgaW50byBhbiB1bm9yZGVyZWQgZmFjdG9yLiBUbyBjcmVhdGUgYW4gb3JkZXJlZCBmYWN0b3IsIHlvdSBoYXZlIHRvIGFkZCB0d28gYWRkaXRpb25hbCBhcmd1bWVudHM6IGBvcmRlcmVkYCBhbmQgYGxldmVsc2AuDQoNCmBgYA0KZmFjdG9yKHNvbWVfdmVjdG9yLA0KICAgICAgIG9yZGVyZWQgPSBUUlVFLA0KICAgICAgIGxldmVscyA9IGMoImxldjEiLCAibGV2MiIsIC4uLikpDQpgYGANCg0KQnkgc2V0dGluZyB0aGUgYXJndW1lbnQgYG9yZGVyZWRgIHRvIGBUUlVFYCBpbiB0aGUgZnVuY3Rpb24gYGZhY3RvcigpYCwgeW91IGluZGljYXRlIHRoYXQgdGhlIGZhY3RvciBpcyBvcmRlcmVkLiBXaXRoIHRoZSBhcmd1bWVudCBsZXZlbHMgeW91IGdpdmUgdGhlIHZhbHVlcyBvZiB0aGUgZmFjdG9yIGluIHRoZSBjb3JyZWN0IG9yZGVyLg0KDQojIyMgRXhlcmNpc2UNCg0KRnJvbSBgc3BlZWRfdmVjdG9yYCwgY3JlYXRlIGFuIG9yZGVyZWQgZmFjdG9yIHZlY3RvcjogYGZhY3Rvcl9zcGVlZF92ZWN0b3JgLiBTZXQgb3JkZXJlZCB0byBgVFJVRWAsIGFuZCBzZXQgYGxldmVsc2AgdG8gYGMoInNsb3ciLCAiZmFzdCIsICJpbnNhbmUiKWAuDQoNCmBgYHtyfQ0KIyBDcmVhdGUgc3BlZWRfdmVjdG9yDQpzcGVlZF92ZWN0b3IgPC0gYygiZmFzdCIsICJzbG93IiwgInNsb3ciLCAiZmFzdCIsICJpbnNhbmUiKQ0KDQojIENvbnZlcnQgc3BlZWRfdmVjdG9yIHRvIG9yZGVyZWQgZmFjdG9yIHZlY3Rvcg0KZmFjdG9yX3NwZWVkX3ZlY3RvciA8LQ0KDQojIFByaW50IGZhY3Rvcl9zcGVlZF92ZWN0b3INCmZhY3Rvcl9zcGVlZF92ZWN0b3INCnN1bW1hcnkoZmFjdG9yX3NwZWVkX3ZlY3RvcikNCmBgYA0KDQoNCiMjIENvbXBhcmluZyBvcmRlcmVkIGZhY3RvcnMNCg0KSGF2aW5nIGEgYmFkIGRheSBhdCB3b3JrLCAnZGF0YSBhbmFseXN0IG51bWJlciB0d28nIGVudGVycyB5b3VyIG9mZmljZSBhbmQgc3RhcnRzIGNvbXBsYWluaW5nIHRoYXQgJ2RhdGEgYW5hbHlzdCBudW1iZXIgZml2ZScgaXMgc2xvd2luZyBkb3duIHRoZSBlbnRpcmUgcHJvamVjdC4gU2luY2UgeW91IGtub3cgdGhhdCAnZGF0YSBhbmFseXN0IG51bWJlciB0d28nIGhhcyB0aGUgcmVwdXRhdGlvbiBvZiBiZWluZyBhIHNtYXJ0eS1wYW50cywgeW91IGZpcnN0IGRlY2lkZSB0byBjaGVjayBpZiBoaXMgc3RhdGVtZW50IGlzIHRydWUuDQoNClRoZSBmYWN0IHRoYXQgYGZhY3Rvcl9zcGVlZF92ZWN0b3JgIGlzIG5vdyBvcmRlcmVkIGVuYWJsZXMgdXMgdG8gY29tcGFyZSBkaWZmZXJlbnQgZWxlbWVudHMgKHRoZSBkYXRhIGFuYWx5c3RzIGluIHRoaXMgY2FzZSkuIFlvdSBjYW4gc2ltcGx5IGRvIHRoaXMgYnkgdXNpbmcgdGhlIHdlbGwta25vd24gb3BlcmF0b3JzLg0KDQojIyMgRXhlcmNpc2UNCi0gVXNlIGBbMl1gIHRvIHNlbGVjdCBmcm9tIGBmYWN0b3Jfc3BlZWRfdmVjdG9yYCB0aGUgZmFjdG9yIHZhbHVlIGZvciB0aGUgc2Vjb25kIGRhdGEgYW5hbHlzdC4gU3RvcmUgaXQgYXMgYGRhMmAuDQotIFVzZSBgWzVdYCB0byBzZWxlY3QgdGhlIGBmYWN0b3Jfc3BlZWRfdmVjdG9yYCBmYWN0b3IgdmFsdWUgZm9yIHRoZSBmaWZ0aCBkYXRhIGFuYWx5c3QuIFN0b3JlIGl0IGFzIGBkYTVgLg0KLSBDaGVjayBpZiBgZGEyYCBpcyBncmVhdGVyIHRoYW4gYGRhNWA7IHNpbXBseSBwcmludCBvdXQgdGhlIHJlc3VsdC4gUmVtZW1iZXIgdGhhdCB5b3UgY2FuIHVzZSB0aGUgYD5gIG9wZXJhdG9yIHRvIGNoZWNrIHdoZXRoZXIgb25lIGVsZW1lbnQgaXMgbGFyZ2VyIHRoYW4gdGhlIG90aGVyLg0KDQpgYGB7cn0NCiMgQ3JlYXRlIGZhY3Rvcl9zcGVlZF92ZWN0b3INCnNwZWVkX3ZlY3RvciA8LSBjKCJmYXN0IiwgInNsb3ciLCAic2xvdyIsICJmYXN0IiwgImluc2FuZSIpDQpmYWN0b3Jfc3BlZWRfdmVjdG9yIDwtIGZhY3RvcihzcGVlZF92ZWN0b3IsIG9yZGVyZWQgPSBUUlVFLCBsZXZlbHMgPSBjKCJzbG93IiwgImZhc3QiLCAiaW5zYW5lIikpDQoNCiMgRmFjdG9yIHZhbHVlIGZvciBzZWNvbmQgZGF0YSBhbmFseXN0DQpkYTIgPC0NCg0KIyBGYWN0b3IgdmFsdWUgZm9yIGZpZnRoIGRhdGEgYW5hbHlzdA0KZGE1IDwtDQoNCiMgSXMgZGF0YSBhbmFseXN0IDIgZmFzdGVyIHRoYW4gZGF0YSBhbmFseXN0IDU/DQoNCmBgYA0KDQoNCg0KDQojIERhdGEgRnJhbWVzDQoNCiMjIFdoYXQncyBhIGRhdGEgZnJhbWU/DQoNCllvdSBtYXkgcmVtZW1iZXIgZnJvbSB0aGUgY2hhcHRlciBhYm91dCBtYXRyaWNlcyB0aGF0IGFsbCB0aGUgZWxlbWVudHMgdGhhdCB5b3UgcHV0IGluIGEgbWF0cml4IHNob3VsZCBiZSBvZiB0aGUgc2FtZSB0eXBlLiBCYWNrIHRoZW4sIHlvdXIgZGF0YSBzZXQgb24gU3RhciBXYXJzIG9ubHkgY29udGFpbmVkIG51bWVyaWMgZWxlbWVudHMuDQoNCldoZW4gZG9pbmcgYSBtYXJrZXQgcmVzZWFyY2ggc3VydmV5LCBob3dldmVyLCB5b3Ugb2Z0ZW4gaGF2ZSBxdWVzdGlvbnMgc3VjaCBhczoNCg0KLSAnQXJlIHlvdXIgbWFycmllZD8nIG9yICd5ZXMvbm8nIHF1ZXN0aW9ucyAoYGxvZ2ljYWxgKQ0KLSAnSG93IG9sZCBhcmUgeW91PycgKGBudW1lcmljYCkNCi0gJ1doYXQgaXMgeW91ciBvcGluaW9uIG9uIHRoaXMgcHJvZHVjdD8nIG9yIG90aGVyICdvcGVuLWVuZGVkJyBxdWVzdGlvbnMgKGBjaGFyYWN0ZXJgKQ0KLSAuLi4NCg0KVGhlIG91dHB1dCwgbmFtZWx5IHRoZSByZXNwb25kZW50cycgYW5zd2VycyB0byB0aGUgcXVlc3Rpb25zIGZvcm11bGF0ZWQgYWJvdmUsIGlzIGEgZGF0YSBzZXQgb2YgZGlmZmVyZW50IGRhdGEgdHlwZXMuIFlvdSB3aWxsIG9mdGVuIGZpbmQgeW91cnNlbGYgd29ya2luZyB3aXRoIGRhdGEgc2V0cyB0aGF0IGNvbnRhaW4gZGlmZmVyZW50IGRhdGEgdHlwZXMgaW5zdGVhZCBvZiBvbmx5IG9uZS4NCg0KQSBkYXRhIGZyYW1lIGhhcyB0aGUgdmFyaWFibGVzIG9mIGEgZGF0YSBzZXQgYXMgY29sdW1ucyBhbmQgdGhlIG9ic2VydmF0aW9ucyBhcyByb3dzLiBUaGlzIHdpbGwgYmUgYSBmYW1pbGlhciBjb25jZXB0IGZvciB0aG9zZSBjb21pbmcgZnJvbSBkaWZmZXJlbnQgc3RhdGlzdGljYWwgc29mdHdhcmUgcGFja2FnZXMgc3VjaCBhcyBTQVMgb3IgU1BTUy4NCg0KIyMjIEV4ZXJjaXNlDQoNCi0gQ2xpY2sgJ1J1bicuIFRoZSBkYXRhIGZyb20gdGhlIGJ1aWx0LWluIGV4YW1wbGUgZGF0YSBmcmFtZSBgbXRjYXJzYCB3aWxsIGJlIHByaW50ZWQgdG8gdGhlIGNvbnNvbGUuDQoNCmBgYHtyfQ0KIyBQcmludCBvdXQgYnVpbHQtaW4gUiBkYXRhIGZyYW1lDQptdGNhcnMgDQpgYGANCg0KDQojIyBRdWljaywgaGF2ZSBhIGxvb2sgYXQgeW91ciBkYXRhIHNldA0KDQpXb3csIHRoYXQgaXMgYSBsb3Qgb2YgY2FycyENCg0KV29ya2luZyB3aXRoIGxhcmdlIGRhdGEgc2V0cyBpcyBub3QgdW5jb21tb24gaW4gZGF0YSBhbmFseXNpcy4gV2hlbiB5b3Ugd29yayB3aXRoIChleHRyZW1lbHkpIGxhcmdlIGRhdGEgc2V0cyBhbmQgZGF0YSBmcmFtZXMsIHlvdXIgZmlyc3QgdGFzayBhcyBhIGRhdGEgYW5hbHlzdCBpcyB0byBkZXZlbG9wIGEgY2xlYXIgdW5kZXJzdGFuZGluZyBvZiBpdHMgc3RydWN0dXJlIGFuZCBtYWluIGVsZW1lbnRzLiBUaGVyZWZvcmUsIGl0IGlzIG9mdGVuIHVzZWZ1bCB0byBzaG93IG9ubHkgYSBzbWFsbCBwYXJ0IG9mIHRoZSBlbnRpcmUgZGF0YSBzZXQuDQoNClNvIGhvdyB0byBkbyB0aGlzIGluIFI/IFdlbGwsIHRoZSBmdW5jdGlvbiBgaGVhZCgpYCBlbmFibGVzIHlvdSB0byBzaG93IHRoZSBmaXJzdCBvYnNlcnZhdGlvbnMgb2YgYSBkYXRhIGZyYW1lLiBTaW1pbGFybHksIHRoZSBmdW5jdGlvbiBgdGFpbCgpYCBwcmludHMgb3V0IHRoZSBsYXN0IG9ic2VydmF0aW9ucyBpbiB5b3VyIGRhdGEgc2V0Lg0KDQpCb3RoIGBoZWFkKClgIGFuZCBgdGFpbCgpYCBwcmludCBhIHRvcCBsaW5lIGNhbGxlZCB0aGUgJ2hlYWRlcicsIHdoaWNoIGNvbnRhaW5zIHRoZSBuYW1lcyBvZiB0aGUgZGlmZmVyZW50IHZhcmlhYmxlcyBpbiB5b3VyIGRhdGEgc2V0Lg0KDQojIyMgRXhlcmNpc2UNCkNhbGwgYGhlYWQoKWAgb24gdGhlIGBtdGNhcnNgIGRhdGEgc2V0IHRvIGhhdmUgYSBsb29rIGF0IHRoZSBoZWFkZXIgYW5kIHRoZSBmaXJzdCBvYnNlcnZhdGlvbnMuDQoNCmBgYHtyfQ0KIyBDYWxsIGhlYWQoKSBvbiBtdGNhcnMNCg0KYGBgDQoNCg0KIyMgSGF2ZSBhIGxvb2sgYXQgdGhlIHN0cnVjdHVyZQ0KDQpBbm90aGVyIG1ldGhvZCB0aGF0IGlzIG9mdGVuIHVzZWQgdG8gZ2V0IGEgcmFwaWQgb3ZlcnZpZXcgb2YgeW91ciBkYXRhIGlzIHRoZSBmdW5jdGlvbiBgc3RyKClgLiBUaGUgZnVuY3Rpb24gYHN0cigpYCBzaG93cyB5b3UgdGhlIHN0cnVjdHVyZSBvZiB5b3VyIGRhdGEgc2V0LiBGb3IgYSBkYXRhIGZyYW1lIGl0IHRlbGxzIHlvdToNCg0KLSBUaGUgdG90YWwgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyAoZS5nLiAzMiBjYXIgdHlwZXMpDQotIFRoZSB0b3RhbCBudW1iZXIgb2YgdmFyaWFibGVzIChlLmcuIDExIGNhciBmZWF0dXJlcykNCi0gQSBmdWxsIGxpc3Qgb2YgdGhlIHZhcmlhYmxlcyBuYW1lcyAoZS5nLiBgbXBnYCwgYGN5bGAgLi4uICkNCi0gVGhlIGRhdGEgdHlwZSBvZiBlYWNoIHZhcmlhYmxlIChlLmcuIGBudW1gKQ0KLSBUaGUgZmlyc3Qgb2JzZXJ2YXRpb25zDQoNCkFwcGx5aW5nIHRoZSBgc3RyKClgIGZ1bmN0aW9uIHdpbGwgb2Z0ZW4gYmUgdGhlIGZpcnN0IHRoaW5nIHRoYXQgeW91IGRvIHdoZW4gcmVjZWl2aW5nIGEgbmV3IGRhdGEgc2V0IG9yIGRhdGEgZnJhbWUuIEl0IGlzIGEgZ3JlYXQgd2F5IHRvIGdldCBtb3JlIGluc2lnaHQgaW4geW91ciBkYXRhIHNldCBiZWZvcmUgZGl2aW5nIGludG8gdGhlIHJlYWwgYW5hbHlzaXMuDQoNCiMjIyBFeGVyY2lzZQ0KDQpJbnZlc3RpZ2F0ZSB0aGUgc3RydWN0dXJlIG9mIGBtdGNhcnNgLiBNYWtlIHN1cmUgdGhhdCB5b3Ugc2VlIHRoZSBzYW1lIG51bWJlcnMsIHZhcmlhYmxlcyBhbmQgZGF0YSB0eXBlcyBhcyBtZW50aW9uZWQgYWJvdmUuDQoNCmBgYHtyfQ0KIyBJbnZlc3RpZ2F0ZSB0aGUgc3RydWN0dXJlIG9mIG10Y2Fycw0KYGBgDQoNCg0KIyMgQ3JlYXRpbmcgYSBkYXRhIGZyYW1lDQoNClNpbmNlIHVzaW5nIGJ1aWx0LWluIGRhdGEgc2V0cyBpcyBub3QgZXZlbiBoYWxmIHRoZSBmdW4gb2YgY3JlYXRpbmcgeW91ciBvd24gZGF0YSBzZXRzLCB0aGUgcmVzdCBvZiB0aGlzIGNoYXB0ZXIgaXMgYmFzZWQgb24geW91ciBwZXJzb25hbGx5IGRldmVsb3BlZCBkYXRhIHNldC4gUHV0IHlvdXIgamV0IHBhY2sgb24gYmVjYXVzZSBpdCBpcyB0aW1lIGZvciBzb21lIHNwYWNlIGV4cGxvcmF0aW9uIQ0KDQpBcyBhIGZpcnN0IGdvYWwsIHlvdSB3YW50IHRvIGNvbnN0cnVjdCBhIGRhdGEgZnJhbWUgdGhhdCBkZXNjcmliZXMgdGhlIG1haW4gY2hhcmFjdGVyaXN0aWNzIG9mIGVpZ2h0IHBsYW5ldHMgaW4gb3VyIHNvbGFyIHN5c3RlbS4gQWNjb3JkaW5nIHRvIHlvdXIgZ29vZCBmcmllbmQgQnV6eiwgdGhlIG1haW4gZmVhdHVyZXMgb2YgYSBwbGFuZXQgYXJlOg0KDQotIFRoZSB0eXBlIG9mIHBsYW5ldCAoVGVycmVzdHJpYWwgb3IgR2FzIEdpYW50KS4NCi0gVGhlIHBsYW5ldCdzIGRpYW1ldGVyIHJlbGF0aXZlIHRvIHRoZSBkaWFtZXRlciBvZiB0aGUgRWFydGguDQotIFRoZSBwbGFuZXQncyByb3RhdGlvbiBhY3Jvc3MgdGhlIHN1biByZWxhdGl2ZSB0byB0aGF0IG9mIHRoZSBFYXJ0aC4NCi0gSWYgdGhlIHBsYW5ldCBoYXMgcmluZ3Mgb3Igbm90IChUUlVFIG9yIEZBTFNFKS4NCg0KQWZ0ZXIgZG9pbmcgc29tZSBoaWdoLXF1YWxpdHkgcmVzZWFyY2ggb24gW1dpa2lwZWRpYV0oaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QbGFuZXQpLCB5b3UgZmVlbCBjb25maWRlbnQgZW5vdWdoIHRvIGNyZWF0ZSB0aGUgbmVjZXNzYXJ5IHZlY3RvcnM6IGBuYW1lYCwgYHR5cGVgLCBgZGlhbWV0ZXJgLCBgcm90YXRpb25gIGFuZCBgcmluZ3NgOyB0aGVzZSB2ZWN0b3JzIGhhdmUgYWxyZWFkeSBiZWVuIGNvZGVkIHVwIG9uIHRoZSByaWdodC4gVGhlIGZpcnN0IGVsZW1lbnQgaW4gZWFjaCBvZiB0aGVzZSB2ZWN0b3JzIGNvcnJlc3BvbmQgdG8gdGhlIGZpcnN0IG9ic2VydmF0aW9uLg0KDQpZb3UgY29uc3RydWN0IGEgZGF0YSBmcmFtZSB3aXRoIHRoZSBgZGF0YS5mcmFtZSgpYCBmdW5jdGlvbi4gQXMgYXJndW1lbnRzLCB5b3UgcGFzcyB0aGUgdmVjdG9ycyBmcm9tIGJlZm9yZTogdGhleSB3aWxsIGJlY29tZSB0aGUgZGlmZmVyZW50IGNvbHVtbnMgb2YgeW91ciBkYXRhIGZyYW1lLiBCZWNhdXNlIGV2ZXJ5IGNvbHVtbiBoYXMgdGhlIHNhbWUgbGVuZ3RoLCB0aGUgdmVjdG9ycyB5b3UgcGFzcyBzaG91bGQgYWxzbyBoYXZlIHRoZSBzYW1lIGxlbmd0aC4gQnV0IGRvbid0IGZvcmdldCB0aGF0IGl0IGlzIHBvc3NpYmxlIChhbmQgbGlrZWx5KSB0aGF0IHRoZXkgY29udGFpbiBkaWZmZXJlbnQgdHlwZXMgb2YgZGF0YS4NCg0KIyMjIEV4ZXJjaXNlDQoNClVzZSB0aGUgZnVuY3Rpb24gYGRhdGEuZnJhbWUoKWAgdG8gY29uc3RydWN0IGEgZGF0YSBmcmFtZS4gUGFzcyB0aGUgdmVjdG9ycyBgbmFtZWAsIGB0eXBlYCwgYGRpYW1ldGVyYCwgYHJvdGF0aW9uYCBhbmQgYHJpbmdzYCBhcyBhcmd1bWVudHMgdG8gYGRhdGEuZnJhbWUoKWAsIGluIHRoaXMgb3JkZXIuIENhbGwgdGhlIHJlc3VsdGluZyBkYXRhIGZyYW1lIGBwbGFuZXRzX2RmYC4NCg0KYGBge3J9DQojIERlZmluaXRpb24gb2YgdmVjdG9ycw0KbmFtZSA8LSBjKCJNZXJjdXJ5IiwgIlZlbnVzIiwgIkVhcnRoIiwgIk1hcnMiLCAiSnVwaXRlciIsICJTYXR1cm4iLCAiVXJhbnVzIiwgIk5lcHR1bmUiKQ0KdHlwZSA8LSBjKCJUZXJyZXN0cmlhbCBwbGFuZXQiLCAiVGVycmVzdHJpYWwgcGxhbmV0IiwgIlRlcnJlc3RyaWFsIHBsYW5ldCIsIA0KICAgICAgICAgICJUZXJyZXN0cmlhbCBwbGFuZXQiLCAiR2FzIGdpYW50IiwgIkdhcyBnaWFudCIsICJHYXMgZ2lhbnQiLCAiR2FzIGdpYW50IikNCmRpYW1ldGVyIDwtIGMoMC4zODIsIDAuOTQ5LCAxLCAwLjUzMiwgMTEuMjA5LCA5LjQ0OSwgNC4wMDcsIDMuODgzKQ0Kcm90YXRpb24gPC0gYyg1OC42NCwgLTI0My4wMiwgMSwgMS4wMywgMC40MSwgMC40MywgLTAuNzIsIDAuNjcpDQpyaW5ncyA8LSBjKEZBTFNFLCBGQUxTRSwgRkFMU0UsIEZBTFNFLCBUUlVFLCBUUlVFLCBUUlVFLCBUUlVFKQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZnJvbSB0aGUgdmVjdG9ycw0KcGxhbmV0c19kZiA8LQ0KDQpgYGANCg0KDQojIyBDcmVhdGluZyBhIGRhdGEgZnJhbWUgKDIpDQoNClRoZSBgcGxhbmV0c19kZmAgZGF0YSBmcmFtZSBzaG91bGQgaGF2ZSA4IG9ic2VydmF0aW9ucyBhbmQgNSB2YXJpYWJsZXMuIEl0IGhhcyBiZWVuIG1hZGUgYXZhaWxhYmxlIGluIHRoZSB3b3Jrc3BhY2UsIHNvIHlvdSBjYW4gZGlyZWN0bHkgdXNlIGl0Lg0KDQojIyMgRXhlcmNpc2UNCg0KVXNlIGBzdHIoKWAgdG8gaW52ZXN0aWdhdGUgdGhlIHN0cnVjdHVyZSBvZiB0aGUgbmV3IGBwbGFuZXRzX2RmYCB2YXJpYWJsZS4NCg0KYGBge3J9DQojIENoZWNrIHRoZSBzdHJ1Y3R1cmUgb2YgcGxhbmV0c19kZg0KYGBgDQoNCg0KIyMgU2VsZWN0aW9uIG9mIGRhdGEgZnJhbWUgZWxlbWVudHMNCg0KU2ltaWxhciB0byB2ZWN0b3JzIGFuZCBtYXRyaWNlcywgeW91IHNlbGVjdCBlbGVtZW50cyBmcm9tIGEgZGF0YSBmcmFtZSB3aXRoIHRoZSBoZWxwIG9mIHNxdWFyZSBicmFja2V0cyBgW2AgYF1gLiBCeSB1c2luZyBhIGNvbW1hLCB5b3UgY2FuIGluZGljYXRlIHdoYXQgdG8gc2VsZWN0IGZyb20gdGhlIHJvd3MgYW5kIHRoZSBjb2x1bW5zIHJlc3BlY3RpdmVseS4gRm9yIGV4YW1wbGU6DQoNCi0gYG15X2RmWzEsMl1gIHNlbGVjdHMgdGhlIHZhbHVlIGF0IHRoZSBmaXJzdCByb3cgYW5kIHNlbGVjdCBlbGVtZW50IGluIGBteV9kZmAuDQotIGBteV9kZlsxOjMsMjo0XWAgc2VsZWN0cyByb3dzIDEsIDIsIDMgYW5kIGNvbHVtbnMgMiwgMywgNCBpbiBgbXlfZGZgLg0KDQpTb21ldGltZXMgeW91IHdhbnQgdG8gc2VsZWN0IGFsbCBlbGVtZW50cyBvZiBhIHJvdyBvciBjb2x1bW4uIEZvciBleGFtcGxlLCBgbXlfZGZbMSwgXWAgc2VsZWN0cyBhbGwgZWxlbWVudHMgb2YgdGhlIGZpcnN0IHJvdy4gTGV0IHVzIG5vdyBhcHBseSB0aGlzIHRlY2huaXF1ZSBvbiBgcGxhbmV0c19kZmAhDQoNCiMjIyBFeGVyY2lzZQ0KDQotIEZyb20gYHBsYW5ldHNfZGZgLCBzZWxlY3QgdGhlIGRpYW1ldGVyIG9mIE1lcmN1cnk6IHRoaXMgaXMgdGhlIHZhbHVlIGF0IHRoZSBmaXJzdCByb3cgYW5kIHRoZSB0aGlyZCBjb2x1bW4uIFNpbXBseSBwcmludCBvdXQgdGhlIHJlc3VsdC4NCi0gRnJvbSBgcGxhbmV0c19kZmAsIHNlbGVjdCBhbGwgZGF0YSBvbiBNYXJzICh0aGUgZm91cnRoIHJvdykuIFNpbXBseSBwcmludCBvdXQgdGhlIHJlc3VsdC4NCg0KYGBge3J9DQojIFRoZSBwbGFuZXRzX2RmIGRhdGEgZnJhbWUgZnJvbSB0aGUgcHJldmlvdXMgZXhlcmNpc2UgaXMgcHJlLWxvYWRlZA0KDQojIFByaW50IG91dCBkaWFtZXRlciBvZiBNZXJjdXJ5IChyb3cgMSwgY29sdW1uIDMpDQoNCg0KIyBQcmludCBvdXQgZGF0YSBmb3IgTWFycyAoZW50aXJlIGZvdXJ0aCByb3cpDQoNCmBgYA0KDQoNCiMjIFNlbGVjdGlvbiBvZiBkYXRhIGZyYW1lIGVsZW1lbnRzICgyKQ0KDQpJbnN0ZWFkIG9mIHVzaW5nIG51bWVyaWNzIHRvIHNlbGVjdCBlbGVtZW50cyBvZiBhIGRhdGEgZnJhbWUsIHlvdSBjYW4gYWxzbyB1c2UgdGhlIHZhcmlhYmxlIG5hbWVzIHRvIHNlbGVjdCBjb2x1bW5zIG9mIGEgZGF0YSBmcmFtZS4NCg0KU3VwcG9zZSB5b3Ugd2FudCB0byBzZWxlY3QgdGhlIGZpcnN0IHRocmVlIGVsZW1lbnRzIG9mIHRoZSBgdHlwZWAgY29sdW1uLiBPbmUgd2F5IHRvIGRvIHRoaXMgaXMNCg0KYHBsYW5ldHNfZGZbMTozLDFdYA0KDQpBIHBvc3NpYmxlIGRpc2FkdmFudGFnZSBvZiB0aGlzIGFwcHJvYWNoIGlzIHRoYXQgeW91IGhhdmUgdG8ga25vdyAob3IgbG9vayB1cCkgdGhlIGNvbHVtbiBudW1iZXIgb2YgYHR5cGVgLCB3aGljaCBnZXRzIGhhcmQgaWYgeW91IGhhdmUgYSBsb3Qgb2YgdmFyaWFibGVzLiBJdCBpcyBvZnRlbiBlYXNpZXIgdG8ganVzdCBtYWtlIHVzZSBvZiB0aGUgdmFyaWFibGUgbmFtZToNCg0KYHBsYW5ldHNfZGZbMTozLCJ0eXBlIl1gDQoNCiMjIyBFeGVyY2lzZQ0KDQpTZWxlY3QgYW5kIHByaW50IG91dCB0aGUgZmlyc3QgNSB2YWx1ZXMgaW4gdGhlIGAiZGlhbWV0ZXIiYCBjb2x1bW4gb2YgYHBsYW5ldHNfZGZgLg0KDQpgYGB7cn0NCiMgVGhlIHBsYW5ldHNfZGYgZGF0YSBmcmFtZSBmcm9tIHRoZSBwcmV2aW91cyBleGVyY2lzZSBpcyBwcmUtbG9hZGVkDQoNCiMgU2VsZWN0IGZpcnN0IDUgdmFsdWVzIG9mIGRpYW1ldGVyIGNvbHVtbg0KDQpgYGANCg0KDQojIyBPbmx5IHBsYW5ldHMgd2l0aCByaW5ncw0KDQpZb3Ugd2lsbCBvZnRlbiB3YW50IHRvIHNlbGVjdCBhbiBlbnRpcmUgY29sdW1uLCBuYW1lbHkgb25lIHNwZWNpZmljIHZhcmlhYmxlIGZyb20gYSBkYXRhIGZyYW1lLiBJZiB5b3Ugd2FudCB0byBzZWxlY3QgYWxsIGVsZW1lbnRzIG9mIHRoZSB2YXJpYWJsZSBgZGlhbWV0ZXJgLCBmb3IgZXhhbXBsZSwgYm90aCBvZiB0aGVzZSB3aWxsIGRvIHRoZSB0cmljazoNCg0KYGBgDQpwbGFuZXRzX2RmWywzXQ0KcGxhbmV0c19kZlssImRpYW1ldGVyIl0NCmBgYA0KDQpIb3dldmVyLCB0aGVyZSBpcyBhIHNob3J0LWN1dC4gSWYgeW91ciBjb2x1bW5zIGhhdmUgbmFtZXMsIHlvdSBjYW4gdXNlIHRoZSBgJGAgc2lnbjoNCg0KYHBsYW5ldHNfZGYkZGlhbWV0ZXJgDQoNCiMjIyBFeGVyY2lzZQ0KDQotIFVzZSB0aGUgYCRgIHNpZ24gdG8gc2VsZWN0IHRoZSBgcmluZ3NgIHZhcmlhYmxlIGZyb20gYHBsYW5ldHNfZGZgLiBTdG9yZSB0aGUgdmVjdG9yIHRoYXQgcmVzdWx0cyBhcyBgcmluZ3NfdmVjdG9yYC4NCi0gUHJpbnQgb3V0IGByaW5nc192ZWN0b3JgIHRvIHNlZSBpZiB5b3UgZ290IGl0IHJpZ2h0Lg0KDQpgYGB7cn0NCiMgcGxhbmV0c19kZiBpcyBwcmUtbG9hZGVkIGluIHlvdXIgd29ya3NwYWNlDQoNCiMgU2VsZWN0IHRoZSByaW5ncyB2YXJpYWJsZSBmcm9tIHBsYW5ldHNfZGYNCnJpbmdzX3ZlY3RvciA8LSANCiAgDQojIFByaW50IG91dCByaW5nc192ZWN0b3INCmBgYA0KDQoNCiMjIE9ubHkgcGxhbmV0cyB3aXRoIHJpbmdzICgyKQ0KDQpZb3UgcHJvYmFibHkgcmVtZW1iZXIgZnJvbSBoaWdoIHNjaG9vbCB0aGF0IHNvbWUgcGxhbmV0cyBpbiBvdXIgc29sYXIgc3lzdGVtIGhhdmUgcmluZ3MgYW5kIG90aGVycyBkbyBub3QuIEJ1dCBkdWUgdG8gb3RoZXIgcHJpb3JpdGllcyBhdCB0aGF0IHRpbWUgKHJlYWQ6IHB1YmVydHkpIHlvdSBjYW4gbm90IHJlY2FsbCB0aGVpciBuYW1lcywgbGV0IGFsb25lIHRoZWlyIHJvdGF0aW9uIHNwZWVkLCBldGMuDQoNCkNvdWxkIFIgaGVscCB5b3Ugb3V0Pw0KDQpJZiB5b3UgdHlwZSBgcmluZ3NfdmVjdG9yYCBpbiB0aGUgY29uc29sZSwgeW91IGdldDoNCg0KYFsxXSBGQUxTRSBGQUxTRSBGQUxTRSBGQUxTRSAgVFJVRSAgVFJVRSAgVFJVRSAgVFJVRWANCg0KVGhpcyBtZWFucyB0aGF0IHRoZSBmaXJzdCBmb3VyIG9ic2VydmF0aW9ucyAob3IgcGxhbmV0cykgZG8gbm90IGhhdmUgYSByaW5nIChgRkFMU0VgKSwgYnV0IHRoZSBvdGhlciBmb3VyIGRvIChgVFJVRWApLiBIb3dldmVyLCB5b3UgZG8gbm90IGdldCBhIG5pY2Ugb3ZlcnZpZXcgb2YgdGhlIG5hbWVzIG9mIHRoZXNlIHBsYW5ldHMsIHRoZWlyIGRpYW1ldGVyLCBldGMuIExldCdzIHRyeSB0byB1c2UgYHJpbmdzX3ZlY3RvcmAgdG8gc2VsZWN0IHRoZSBkYXRhIGZvciB0aGUgZm91ciBwbGFuZXRzIHdpdGggcmluZ3MuDQoNCiMjIyBFeGVyY2lzZQ0KDQpUaGUgY29kZSBvbiB0aGUgcmlnaHQgc2VsZWN0cyB0aGUgYG5hbWVgIGNvbHVtbiBvZiBhbGwgcGxhbmV0cyB0aGF0IGhhdmUgcmluZ3MuIEFkYXB0IHRoZSBjb2RlIHNvIHRoYXQgaW5zdGVhZCBvZiBvbmx5IHRoZSBgbmFtZWAgY29sdW1uLCAqYWxsKiBjb2x1bW5zIGZvciBwbGFuZXRzIHRoYXQgaGF2ZSByaW5ncyBhcmUgc2VsZWN0ZWQuDQoNCg0KYGBge3J9DQojIHBsYW5ldHNfZGYgYW5kIHJpbmdzX3ZlY3RvciBhcmUgcHJlLWxvYWRlZCBpbiB5b3VyIHdvcmtzcGFjZQ0KDQojIEFkYXB0IHRoZSBjb2RlIHRvIHNlbGVjdCBhbGwgY29sdW1ucyBmb3IgcGxhbmV0cyB3aXRoIHJpbmdzDQpwbGFuZXRzX2RmW3JpbmdzX3ZlY3RvciwgIm5hbWUiXQ0KYGBgDQoNCg0KIyMgT25seSBwbGFuZXRzIHdpdGggcmluZ3MgYnV0IHNob3J0ZXINCg0KU28gd2hhdCBleGFjdGx5IGRpZCB5b3UgbGVhcm4gaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlcz8gWW91IHNlbGVjdGVkIGEgc3Vic2V0IGZyb20gYSBkYXRhIGZyYW1lIChgcGxhbmV0c19kZmApIGJhc2VkIG9uIHdoZXRoZXIgb3Igbm90IGEgY2VydGFpbiBjb25kaXRpb24gd2FzIHRydWUgKHJpbmdzIG9yIG5vIHJpbmdzKSwgYW5kIHlvdSBtYW5hZ2VkIHRvIHB1bGwgb3V0IGFsbCByZWxldmFudCBkYXRhLiBQcmV0dHkgYXdlc29tZSEgQnkgbm93LCBOQVNBIGlzIHByb2JhYmx5IGFscmVhZHkgZmxpcnRpbmcgd2l0aCB5b3VyIENWIDstKS4NCg0KTm93LCBsZXQgdXMgbW92ZSB1cCBvbmUgbGV2ZWwgYW5kIHVzZSB0aGUgZnVuY3Rpb24gYHN1YnNldCgpYC4gWW91IHNob3VsZCBzZWUgdGhlIGBzdWJzZXQoKWAgZnVuY3Rpb24gYXMgYSBzaG9ydC1jdXQgdG8gZG8gZXhhY3RseSB0aGUgc2FtZSBhcyB3aGF0IHlvdSBkaWQgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlcy4NCg0KYHN1YnNldChteV9kZiwgc3Vic2V0ID0gc29tZV9jb25kaXRpb24pYA0KDQpUaGUgZmlyc3QgYXJndW1lbnQgb2YgYHN1YnNldCgpYCBzcGVjaWZpZXMgdGhlIGRhdGEgc2V0IGZvciB3aGljaCB5b3Ugd2FudCBhIHN1YnNldC4gQnkgYWRkaW5nIHRoZSBzZWNvbmQgYXJndW1lbnQsIHlvdSBnaXZlIFIgdGhlIG5lY2Vzc2FyeSBpbmZvcm1hdGlvbiBhbmQgY29uZGl0aW9ucyB0byBzZWxlY3QgdGhlIGNvcnJlY3Qgc3Vic2V0Lg0KDQpUaGUgY29kZSBiZWxvdyB3aWxsIGdpdmUgdGhlIGV4YWN0IHNhbWUgcmVzdWx0IGFzIHlvdSBnb3QgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlLCBidXQgdGhpcyB0aW1lLCB5b3UgZGlkbid0IG5lZWQgdGhlIGByaW5nc192ZWN0b3JgIQ0KDQpgc3Vic2V0KHBsYW5ldHNfZGYsIHN1YnNldCA9IHJpbmdzKWANCg0KIyMjIEV4ZXJjaXNlDQoNClVzZSBgc3Vic2V0KClgIG9uIGBwbGFuZXRzX2RmYCB0byBzZWxlY3QgcGxhbmV0cyB0aGF0IGhhdmUgYSBkaWFtZXRlciBzbWFsbGVyIHRoYW4gRWFydGguIEJlY2F1c2UgdGhlIGBkaWFtZXRlcmAgdmFyaWFibGUgaXMgYSByZWxhdGl2ZSBtZWFzdXJlIG9mIHRoZSBwbGFuZXQncyBkaWFtZXRlciB3LnIudCB0aGF0IG9mIHBsYW5ldCBFYXJ0aCwgeW91ciBjb25kaXRpb24gaXMgYGRpYW1ldGVyIDwgMWAuDQoNCmBgYHtyfQ0KIyBwbGFuZXRzX2RmIGlzIHByZS1sb2FkZWQgaW4geW91ciB3b3Jrc3BhY2UNCg0KIyBTZWxlY3QgcGxhbmV0cyB3aXRoIGRpYW1ldGVyIDwgMQ0KDQpgYGANCg0KDQojIyBTb3J0aW5nDQoNCk1ha2luZyBhbmQgY3JlYXRpbmcgcmFua2luZ3MgaXMgb25lIG9mIG1hbmtpbmQncyBmYXZvcml0ZSBhZmZhaXJzLiBUaGVzZSByYW5raW5ncyBjYW4gYmUgdXNlZnVsIChiZXN0IHVuaXZlcnNpdGllcyBpbiB0aGUgd29ybGQpLCBlbnRlcnRhaW5pbmcgKG1vc3QgaW5mbHVlbnRpYWwgbW92aWUgc3RhcnMpIG9yIHBvaW50bGVzcyAoYmVzdCAwMDcgbG9vay1hLWxpa2UpLg0KDQpJbiBkYXRhIGFuYWx5c2lzIHlvdSBjYW4gc29ydCB5b3VyIGRhdGEgYWNjb3JkaW5nIHRvIGEgY2VydGFpbiB2YXJpYWJsZSBpbiB0aGUgZGF0YSBzZXQuIEluIFIsIHRoaXMgaXMgZG9uZSB3aXRoIHRoZSBoZWxwIG9mIHRoZSBmdW5jdGlvbiBgb3JkZXIoKWAuDQoNCmBvcmRlcigpYCBpcyBhIGZ1bmN0aW9uIHRoYXQgZ2l2ZXMgeW91IHRoZSByYW5rZWQgcG9zaXRpb24gb2YgZWFjaCBlbGVtZW50IHdoZW4gaXQgaXMgYXBwbGllZCBvbiBhIHZhcmlhYmxlLCBzdWNoIGFzIGEgdmVjdG9yIGZvciBleGFtcGxlOg0KDQpgYGANCj4gYSA8LSBjKDEwMCwgMTAsIDEwMDApDQo+IG9yZGVyKGEpDQpbMV0gMiAxIDMNCmBgYA0KDQoxMCwgd2hpY2ggaXMgdGhlIHNlY29uZCBlbGVtZW50IGluIGBhYCwgaXMgdGhlIHNtYWxsZXN0IGVsZW1lbnQsIHNvIDIgY29tZXMgZmlyc3QgaW4gdGhlIG91dHB1dCBvZiBgb3JkZXIoYSlgLiAxMDAsIHdoaWNoIGlzIHRoZSBmaXJzdCBlbGVtZW50IGluIGBhYCBpcyB0aGUgc2Vjb25kIHNtYWxsZXN0IGVsZW1lbnQsIHNvIDEgY29tZXMgc2Vjb25kIGluIHRoZSBvdXRwdXQgb2YgYG9yZGVyKGEpYC4NCg0KVGhpcyBtZWFucyB3ZSBjYW4gdXNlIHRoZSBvdXRwdXQgb2YgYG9yZGVyKGEpYCB0byByZXNodWZmbGUgYGFgOg0KDQpgYGANCj4gYVtvcmRlcihhKV0NClsxXSAgIDEwICAxMDAgMTAwMA0KYGBgDQoNCiMjIyBFeGVyY2lzZQ0KDQpFeHBlcmltZW50IHdpdGggdGhlIGBvcmRlcigpYCBmdW5jdGlvbiBpbiB0aGUgY29uc29sZS4gDQoNCmBgYHtyfQ0KIyBQbGF5IGFyb3VuZCB3aXRoIHRoZSBvcmRlciBmdW5jdGlvbiBpbiB0aGUgY29uc29sZQ0KYGBgDQoNCg0KIyMgU29ydGluZyB5b3VyIGRhdGEgZnJhbWUNCg0KQWxyaWdodCwgbm93IHRoYXQgeW91IHVuZGVyc3RhbmQgdGhlIGBvcmRlcigpYCBmdW5jdGlvbiwgbGV0IHVzIGRvIHNvbWV0aGluZyB1c2VmdWwgd2l0aCBpdC4gWW91IHdvdWxkIGxpa2UgdG8gcmVhcnJhbmdlIHlvdXIgZGF0YSBmcmFtZSBzdWNoIHRoYXQgaXQgc3RhcnRzIHdpdGggdGhlIHNtYWxsZXN0IHBsYW5ldCBhbmQgZW5kcyB3aXRoIHRoZSBsYXJnZXN0IG9uZS4gQSBzb3J0IG9uIHRoZSBgZGlhbWV0ZXJgIGNvbHVtbi4NCg0KIyMjIEV4ZXJjaXNlIA0KLSBDYWxsIGBvcmRlcigpYCBvbiBgcGxhbmV0c19kZiRkaWFtZXRlcmAgKHRoZSBgZGlhbWV0ZXJgIGNvbHVtbiBvZiBgcGxhbmV0c19kZmApLiBTdG9yZSB0aGUgcmVzdWx0IGFzIGBwb3NpdGlvbnNgLg0KLSBOb3cgcmVzaHVmZmxlIGBwbGFuZXRzX2RmYCB3aXRoIHRoZSBgcG9zaXRpb25zYCB2ZWN0b3IgYXMgcm93IGluZGV4ZXMgaW5zaWRlIHNxdWFyZSBicmFja2V0cy4gS2VlcCBhbGwgY29sdW1ucy4gU2ltcGx5IHByaW50IG91dCB0aGUgcmVzdWx0Lg0KDQpgYGB7cn0NCiMgcGxhbmV0c19kZiBpcyBwcmUtbG9hZGVkIGluIHlvdXIgd29ya3NwYWNlDQoNCiMgVXNlIG9yZGVyKCkgdG8gY3JlYXRlIHBvc2l0aW9ucw0KcG9zaXRpb25zIDwtICANCg0KIyBVc2UgcG9zaXRpb25zIHRvIHNvcnQgcGxhbmV0c19kZg0KDQpgYGANCg0KDQoNCiMgTGlzdHMNCg0KIyMgTGlzdHMsIHdoeSB3b3VsZCB5b3UgbmVlZCB0aGVtPw0KDQpDb25ncmF0dWxhdGlvbnMhIEF0IHRoaXMgcG9pbnQgaW4gdGhlIGNvdXJzZSB5b3UgYXJlIGFscmVhZHkgZmFtaWxpYXIgd2l0aDoNCg0KLSAqKlZlY3RvcnMqKiAob25lIGRpbWVuc2lvbmFsIGFycmF5KTogY2FuIGhvbGQgbnVtZXJpYywgY2hhcmFjdGVyIG9yIGxvZ2ljYWwgdmFsdWVzLiBUaGUgZWxlbWVudHMgaW4gYSB2ZWN0b3IgYWxsIGhhdmUgdGhlIHNhbWUgZGF0YSB0eXBlLg0KLSAqKk1hdHJpY2VzKiogKHR3byBkaW1lbnNpb25hbCBhcnJheSk6IGNhbiBob2xkIG51bWVyaWMsIGNoYXJhY3RlciBvciBsb2dpY2FsIHZhbHVlcy4gVGhlIGVsZW1lbnRzIGluIGEgbWF0cml4IGFsbCBoYXZlIHRoZSBzYW1lIGRhdGEgdHlwZS4NCi0gKipEYXRhIGZyYW1lcyoqICh0d28tZGltZW5zaW9uYWwgb2JqZWN0cyk6IGNhbiBob2xkIG51bWVyaWMsIGNoYXJhY3RlciBvciBsb2dpY2FsIHZhbHVlcy4gV2l0aGluIGEgY29sdW1uIGFsbCBlbGVtZW50cyBoYXZlIHRoZSBzYW1lIGRhdGEgdHlwZSwgYnV0IGRpZmZlcmVudCBjb2x1bW5zIGNhbiBiZSBvZiBkaWZmZXJlbnQgZGF0YSB0eXBlLg0KUHJldHR5IHN3ZWV0IGZvciBhbiBSIG5ld2JpZSwgcmlnaHQ/IDstKQ0KDQojIyMgRXhlcmNpc2UNCkNsaWNrICdSdW4nIHRvIHN0YXJ0IGxlYXJuaW5nIGV2ZXJ5dGhpbmcgYWJvdXQgbGlzdHMhDQoNCmBgYHtyfQ0KIyBKdXN0IGNsaWNrIHRoZSAnUnVuJyBidXR0b24uDQpgYGANCg0KDQojIyBMaXN0cywgd2h5IHdvdWxkIHlvdSBuZWVkIHRoZW0/ICgyKQ0KDQpBICoqbGlzdCoqIGluIFIgaXMgc2ltaWxhciB0byB5b3VyIHRvLWRvIGxpc3QgYXQgd29yayBvciBzY2hvb2w6IHRoZSBkaWZmZXJlbnQgaXRlbXMgb24gdGhhdCBsaXN0IG1vc3QgbGlrZWx5IGRpZmZlciBpbiBsZW5ndGgsIGNoYXJhY3RlcmlzdGljLCB0eXBlIG9mIGFjdGl2aXR5IHRoYXQgaGFzIHRvIGRvIGJlIGRvbmUsIC4uLg0KDQpBIGxpc3QgaW4gUiBhbGxvd3MgeW91IHRvIGdhdGhlciBhIHZhcmlldHkgb2Ygb2JqZWN0cyB1bmRlciBvbmUgbmFtZSAodGhhdCBpcywgdGhlIG5hbWUgb2YgdGhlIGxpc3QpIGluIGFuIG9yZGVyZWQgd2F5LiBUaGVzZSBvYmplY3RzIGNhbiBiZSBtYXRyaWNlcywgdmVjdG9ycywgZGF0YSBmcmFtZXMsIGV2ZW4gb3RoZXIgbGlzdHMsIGV0Yy4gSXQgaXMgbm90IGV2ZW4gcmVxdWlyZWQgdGhhdCB0aGVzZSBvYmplY3RzIGFyZSByZWxhdGVkIHRvIGVhY2ggb3RoZXIgaW4gYW55IHdheS4NCg0KWW91IGNvdWxkIHNheSB0aGF0IGEgbGlzdCBpcyBzb21lIGtpbmQgc3VwZXIgZGF0YSB0eXBlOiB5b3UgY2FuIHN0b3JlIHByYWN0aWNhbGx5IGFueSBwaWVjZSBvZiBpbmZvcm1hdGlvbiBpbiBpdCENCg0KIyMjIEV4ZXJjaXNlDQpDbGljayAnUnVuJyB0byBzdGFydCB0aGUgZmlyc3QgZXhlcmNpc2Ugb24gbGlzdHMuDQoNCmBgYHtyfQ0KIyBDbGljayAnUnVuJyB0byBzdGFydCB0aGUgZmlyc3QgZXhlcmNpc2Ugb24gbGlzdHMuDQpgYGANCg0KDQojIyBDcmVhdGluZyBhIGxpc3QNCg0KTGV0IHVzIGNyZWF0ZSBvdXIgZmlyc3QgbGlzdCEgVG8gY29uc3RydWN0IGEgbGlzdCB5b3UgdXNlIHRoZSBmdW5jdGlvbiBgbGlzdCgpYDoNCg0KYG15X2xpc3QgPC0gbGlzdChjb21wMSwgY29tcDIgLi4uKWANCg0KVGhlIGFyZ3VtZW50cyB0byB0aGUgbGlzdCBmdW5jdGlvbiBhcmUgdGhlIGxpc3QgY29tcG9uZW50cy4gUmVtZW1iZXIsIHRoZXNlIGNvbXBvbmVudHMgY2FuIGJlIG1hdHJpY2VzLCB2ZWN0b3JzLCBvdGhlciBsaXN0cywgLi4uDQoNCiMjIyBFeGVyY2llDQoNCkNvbnN0cnVjdCBhIGxpc3QsIG5hbWVkIGBteV9saXN0YCwgdGhhdCBjb250YWlucyB0aGUgdmFyaWFibGVzIGBteV92ZWN0b3JgLCBgbXlfbWF0cml4YCBhbmQgYG15X2RmYCBhcyBsaXN0IGNvbXBvbmVudHMuDQoNCmBgYHtyfQ0KIyBWZWN0b3Igd2l0aCBudW1lcmljcyBmcm9tIDEgdXAgdG8gMTANCm15X3ZlY3RvciA8LSAxOjEwIA0KDQojIE1hdHJpeCB3aXRoIG51bWVyaWNzIGZyb20gMSB1cCB0byA5DQpteV9tYXRyaXggPC0gbWF0cml4KDE6OSwgbmNvbCA9IDMpDQoNCiMgRmlyc3QgMTAgZWxlbWVudHMgb2YgdGhlIGJ1aWx0LWluIGRhdGEgZnJhbWUgbXRjYXJzDQpteV9kZiA8LSBtdGNhcnNbMToxMCxdDQoNCiMgQ29uc3RydWN0IGxpc3Qgd2l0aCB0aGVzZSBkaWZmZXJlbnQgZWxlbWVudHM6DQpteV9saXN0IDwtIA0KYGBgDQoNCg0KIyMgQ3JlYXRpbmcgYSBuYW1lZCBsaXN0DQoNCldlbGwgZG9uZSwgeW91J3JlIG9uIGEgcm9sbCENCg0KSnVzdCBsaWtlIG9uIHlvdXIgdG8tZG8gbGlzdCwgeW91IHdhbnQgdG8gYXZvaWQgbm90IGtub3dpbmcgb3IgcmVtZW1iZXJpbmcgd2hhdCB0aGUgY29tcG9uZW50cyBvZiB5b3VyIGxpc3Qgc3RhbmQgZm9yLiBUaGF0IGlzIHdoeSB5b3Ugc2hvdWxkIGdpdmUgbmFtZXMgdG8gdGhlbToNCg0KYGBgDQpteV9saXN0IDwtIGxpc3QobmFtZTEgPSB5b3VyX2NvbXAxLCANCiAgICAgICAgICAgICAgICBuYW1lMiA9IHlvdXJfY29tcDIpDQpgYGANCg0KVGhpcyBjcmVhdGVzIGEgbGlzdCB3aXRoIGNvbXBvbmVudHMgdGhhdCBhcmUgbmFtZWQgYG5hbWUxYCwgYG5hbWUyYCwgYW5kIHNvIG9uLiBJZiB5b3Ugd2FudCB0byBuYW1lIHlvdXIgbGlzdHMgYWZ0ZXIgeW91J3ZlIGNyZWF0ZWQgdGhlbSwgeW91IGNhbiB1c2UgdGhlIGBuYW1lcygpYCBmdW5jdGlvbiBhcyB5b3UgZGlkIHdpdGggdmVjdG9ycy4gVGhlIGZvbGxvd2luZyBjb21tYW5kcyBhcmUgZnVsbHkgZXF1aXZhbGVudCB0byB0aGUgYXNzaWdubWVudCBhYm92ZToNCg0KYGBgDQpteV9saXN0IDwtIGxpc3QoeW91cl9jb21wMSwgeW91cl9jb21wMikNCm5hbWVzKG15X2xpc3QpIDwtIGMoIm5hbWUxIiwgIm5hbWUyIikNCmBgYA0KDQojIyMgRXhlcmNpc2UNCg0KLSBDaGFuZ2UgdGhlIGNvZGUgb2YgdGhlIHByZXZpb3VzIGV4ZXJjaXNlIChzZWUgZWRpdG9yKSBieSBhZGRpbmcgbmFtZXMgdG8gdGhlIGNvbXBvbmVudHMuIFVzZSBmb3IgYG15X3ZlY3RvcmAgdGhlIG5hbWUgYHZlY2AsIGZvciBgbXlfbWF0cml4YCB0aGUgbmFtZSBgbWF0YCBhbmQgZm9yIGBteV9kZmAgdGhlIG5hbWUgYGRmYC4NCi0gUHJpbnQgb3V0IGBteV9saXN0YCBzbyB5b3UgY2FuIGluc3BlY3QgdGhlIG91dHB1dC4NCg0KYGBge3J9DQojIFZlY3RvciB3aXRoIG51bWVyaWNzIGZyb20gMSB1cCB0byAxMA0KbXlfdmVjdG9yIDwtIDE6MTAgDQoNCiMgTWF0cml4IHdpdGggbnVtZXJpY3MgZnJvbSAxIHVwIHRvIDkNCm15X21hdHJpeCA8LSBtYXRyaXgoMTo5LCBuY29sID0gMykNCg0KIyBGaXJzdCAxMCBlbGVtZW50cyBvZiB0aGUgYnVpbHQtaW4gZGF0YSBmcmFtZSBtdGNhcnMNCm15X2RmIDwtIG10Y2Fyc1sxOjEwLF0NCg0KIyBBZGFwdCBsaXN0KCkgY2FsbCB0byBnaXZlIHRoZSBjb21wb25lbnRzIG5hbWVzDQpteV9saXN0IDwtIGxpc3QobXlfdmVjdG9yLCBteV9tYXRyaXgsIG15X2RmKQ0KDQojIFByaW50IG91dCBteV9saXN0DQoNCmBgYA0KDQoNCiMjIENyZWF0aW5nIGEgbmFtZWQgbGlzdCAoMikNCg0KQmVpbmcgYSBodWdlIG1vdmllIGZhbiAocmVtZW1iZXIgeW91ciBqb2IgYXQgTHVjYXNGaWxtcyksIHlvdSBkZWNpZGUgdG8gc3RhcnQgc3RvcmluZyBpbmZvcm1hdGlvbiBvbiBnb29kIG1vdmllcyB3aXRoIHRoZSBoZWxwIG9mIGxpc3RzLg0KDQpTdGFydCBieSBjcmVhdGluZyBhIGxpc3QgZm9yIHRoZSBtb3ZpZSAiVGhlIFNoaW5pbmciLiBXZSBoYXZlIGFscmVhZHkgY3JlYXRlZCB0aGUgdmFyaWFibGVzIGBtb3ZgLCBgYWN0YCBhbmQgYHJldmAgaW4geW91ciBSIHdvcmtzcGFjZS4gRmVlbCBmcmVlIHRvIGNoZWNrIHRoZW0gb3V0IGluIHRoZSBjb25zb2xlLg0KDQojIyMgRXhlcmNpc2UNCg0KQ29tcGxldGUgdGhlIGNvZGUgb24gdGhlIHJpZ2h0IHRvIGNyZWF0ZSBgc2hpbmluZ19saXN0YDsgaXQgY29udGFpbnMgdGhyZWUgZWxlbWVudHM6DQoNCi0gbW92aWVuYW1lOiBhIGNoYXJhY3RlciBzdHJpbmcgd2l0aCB0aGUgbW92aWUgdGl0bGUgKHN0b3JlZCBpbiBgbW92YCkNCi0gYWN0b3JzOiBhIHZlY3RvciB3aXRoIHRoZSBtYWluIGFjdG9ycycgbmFtZXMgKHN0b3JlZCBpbiBgYWN0YCkNCi0gcmV2aWV3czogYSBkYXRhIGZyYW1lIHRoYXQgY29udGFpbnMgc29tZSByZXZpZXdzIChzdG9yZWQgaW4gYHJldmApDQoNCkRvIG5vdCBmb3JnZXQgdG8gbmFtZSB0aGUgbGlzdCBjb21wb25lbnRzIGFjY29yZGluZ2x5IChuYW1lcyBhcmUgbW92aWVuYW1lLCBhY3RvcnMgYW5kIHJldmlld3MpLg0KDQpgYGB7cn0NCiMgVGhlIHZhcmlhYmxlcyBtb3YsIGFjdCBhbmQgcmV2IGFyZSBhdmFpbGFibGUNCm1vdiA8LSAiVGhlIFNoaW5pbmciDQphY3QgPC0gYygiSmFjayBOaWNob2xzb24iLCAiU2hlbGxleSBEdXZhbGwiLCAiRGFubnkgTGxveWQiLCAiU2NhdG1hbiBDcm90aGVycyIsICJCYXJyeSBOZWxzb24iKQ0KcmV2IDwtIGRhdGEuZnJhbWUoc2NvcmVzID0gYyg0LjUsIDQsIDUpLCBzb3VyY2VzID0gYygiSU1EYjEiLCAiSU1EYjIiLCAiSU1EYjMiKSwgY29tbWVudHMgPSBjKCJBIG1hc3RlcnBpZWNlIG9mIHBzeWNob2xvZ2ljYWwgaG9ycm9yIiwgIkEgdHJ1bHkgYnJpbGxpYW50IGFuZCBzY2FyeSBmaWxtIGZyb20gU3RhbmxleSBLdWJyaWNrIiwgIkJlc3QgSG9ycm9yIEZpbG0gSSBIYXZlIEV2ZXIgU2VlbiIpKQ0KDQojIEZpbmlzaCB0aGUgY29kZSB0byBidWlsZCBzaGluaW5nX2xpc3QNCnNoaW5pbmdfbGlzdCA8LSBsaXN0KG1vdmllbmFtZSA9IG1vdikNCmBgYA0KDQoNCiMjIFNlbGVjdGluZyBlbGVtZW50cyBmcm9tIGEgbGlzdA0KDQpZb3VyIGxpc3Qgd2lsbCBvZnRlbiBiZSBidWlsdCBvdXQgb2YgbnVtZXJvdXMgZWxlbWVudHMgYW5kIGNvbXBvbmVudHMuIFRoZXJlZm9yZSwgZ2V0dGluZyBhIHNpbmdsZSBlbGVtZW50LCBtdWx0aXBsZSBlbGVtZW50cywgb3IgYSBjb21wb25lbnQgb3V0IG9mIGl0IGlzIG5vdCBhbHdheXMgc3RyYWlnaHRmb3J3YXJkLg0KDQpPbmUgd2F5IHRvIHNlbGVjdCBhIGNvbXBvbmVudCBpcyB1c2luZyB0aGUgbnVtYmVyZWQgcG9zaXRpb24gb2YgdGhhdCBjb21wb25lbnQuIEZvciBleGFtcGxlLCB0byAiZ3JhYiIgdGhlIGZpcnN0IGNvbXBvbmVudCBvZiBgc2hpbmluZ19saXN0YCB5b3UgdHlwZQ0KDQpgc2hpbmluZ19saXN0W1sxXV1gDQoNCkEgcXVpY2sgd2F5IHRvIGNoZWNrIHRoaXMgb3V0IGlzIHR5cGluZyBpdCBpbiB0aGUgY29uc29sZS4gSW1wb3J0YW50IHRvIHJlbWVtYmVyOiB0byBzZWxlY3QgZWxlbWVudHMgZnJvbSB2ZWN0b3JzLCB5b3UgdXNlIHNpbmdsZSBzcXVhcmUgYnJhY2tldHM6IGBbYCBgXWAuIERvbid0IG1peCB0aGVtIHVwIQ0KDQpZb3UgY2FuIGFsc28gcmVmZXIgdG8gdGhlIG5hbWVzIG9mIHRoZSBjb21wb25lbnRzLCB3aXRoIGBbW2AgYF1dYCBvciB3aXRoIHRoZSBgJGAgc2lnbi4gQm90aCB3aWxsIHNlbGVjdCB0aGUgZGF0YSBmcmFtZSByZXByZXNlbnRpbmcgdGhlIHJldmlld3M6DQoNCmBgYA0Kc2hpbmluZ19saXN0W1sicmV2aWV3cyJdXQ0Kc2hpbmluZ19saXN0JHJldmlld3MNCmBgYA0KDQpCZXNpZGVzIHNlbGVjdGluZyBjb21wb25lbnRzLCB5b3Ugb2Z0ZW4gbmVlZCB0byBzZWxlY3Qgc3BlY2lmaWMgZWxlbWVudHMgb3V0IG9mIHRoZXNlIGNvbXBvbmVudHMuIEZvciBleGFtcGxlLCB3aXRoIGBzaGluaW5nX2xpc3RbWzJdXVsxXWAgeW91IHNlbGVjdCBmcm9tIHRoZSBzZWNvbmQgY29tcG9uZW50LCBgYWN0b3JzYCAoYHNoaW5pbmdfbGlzdFtbMl1dYCksIHRoZSBmaXJzdCBlbGVtZW50IChgWzFdYCkuIFdoZW4geW91IHR5cGUgdGhpcyBpbiB0aGUgY29uc29sZSwgeW91IHdpbGwgc2VlIHRoZSBhbnN3ZXIgaXMgSmFjayBOaWNob2xzb24uDQoNCiMjIyBFeGVyY2lzZQ0KLSBTZWxlY3QgZnJvbSBgc2hpbmluZ19saXN0YCB0aGUgdmVjdG9yIHJlcHJlc2VudGluZyB0aGUgYWN0b3JzLiBTaW1wbHkgcHJpbnQgb3V0IHRoaXMgdmVjdG9yLg0KLSBTZWxlY3QgZnJvbSBgc2hpbmluZ19saXN0YCB0aGUgc2Vjb25kIGVsZW1lbnQgaW4gdGhlIHZlY3RvciByZXByZXNlbnRpbmcgdGhlIGFjdG9ycy4gRG8gYSBwcmludG91dCBsaWtlIGJlZm9yZS4NCg0KYGBge3J9DQojIHNoaW5pbmdfbGlzdCBpcyBhbHJlYWR5IHByZS1sb2FkZWQgaW4gdGhlIHdvcmtzcGFjZQ0KDQojIFByaW50IG91dCB0aGUgdmVjdG9yIHJlcHJlc2VudGluZyB0aGUgYWN0b3JzDQoNCg0KIyBQcmludCB0aGUgc2Vjb25kIGVsZW1lbnQgb2YgdGhlIHZlY3RvciByZXByZXNlbnRpbmcgdGhlIGFjdG9ycw0KDQpgYGANCg0KDQojIyBBZGRpbmcgbW9yZSBtb3ZpZSBpbmZvcm1hdGlvbiB0byB0aGUgbGlzdA0KDQpCZWluZyBwcm91ZCBvZiB5b3VyIGZpcnN0IGxpc3QsIHlvdSBzaGFyZWQgaXQgd2l0aCB0aGUgbWVtYmVycyBvZiB5b3VyIG1vdmllIGhvYmJ5IGNsdWIuIEhvd2V2ZXIsIG9uZSBvZiB0aGUgc2VuaW9yIG1lbWJlcnMsIGEgZ3V5IG5hbWVkIE0uIE1jRG93ZWxsLCBub3RlZCB0aGF0IHlvdSBmb3Jnb3QgdG8gYWRkIHRoZSByZWxlYXNlIHllYXIuIEdpdmVuIHlvdXIgYW1iaXRpb25zIHRvIGJlY29tZSBuZXh0IHllYXIncyBwcmVzaWRlbnQgb2YgdGhlIGNsdWIsIHlvdSBkZWNpZGUgdG8gYWRkIHRoaXMgaW5mb3JtYXRpb24gdG8gdGhlIGxpc3QuDQoNClRvIGNvbnZlbmllbnRseSBhZGQgZWxlbWVudHMgdG8gbGlzdHMgeW91IGNhbiB1c2UgdGhlIGBjKClgIGZ1bmN0aW9uLCB0aGF0IHlvdSBhbHNvIHVzZWQgdG8gYnVpbGQgdmVjdG9yczoNCg0KYGV4dF9saXN0IDwtIGMobXlfbGlzdCAsIG15X3ZhbClgDQoNClRoaXMgd2lsbCBzaW1wbHkgZXh0ZW5kIHRoZSBvcmlnaW5hbCBsaXN0LCBgbXlfbGlzdGAsIHdpdGggdGhlIGNvbXBvbmVudCBgbXlfdmFsYC4gVGhpcyBjb21wb25lbnQgZ2V0cyBhcHBlbmRlZCB0byB0aGUgZW5kIG9mIHRoZSBsaXN0LiBJZiB5b3Ugd2FudCB0byBnaXZlIHRoZSBuZXcgbGlzdCBpdGVtIGEgbmFtZSwgeW91IGp1c3QgYWRkIHRoZSBuYW1lIGFzIHlvdSBkaWQgYmVmb3JlOg0KDQpgZXh0X2xpc3QgPC0gYyhteV9saXN0LCBteV9uYW1lID0gbXlfdmFsKWANCg0KIyMjIEV4ZXJjaXNlDQoNCi0gQ29tcGxldGUgdGhlIGNvZGUgYmVsb3cgc3VjaCB0aGF0IGFuIGl0ZW0gbmFtZWQgYHllYXJgIGlzIGFkZGVkIHRvIHRoZSBgc2hpbmluZ19saXN0YCB3aXRoIHRoZSB2YWx1ZSAxOTgwLiBBc3NpZ24gdGhlIHJlc3VsdCB0byBgc2hpbmluZ19saXN0X2Z1bGxgLg0KLSBGaW5hbGx5LCBoYXZlIGEgbG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIGBzaGluaW5nX2xpc3RfZnVsbGAgd2l0aCB0aGUgYHN0cigpYCBmdW5jdGlvbi4NCg0KYGBge3J9DQojIHNoaW5pbmdfbGlzdCwgdGhlIGxpc3QgY29udGFpbmluZyBtb3ZpZSBuYW1lLCBhY3RvcnMgYW5kIHJldmlld3MsIGlzIHByZS1sb2FkZWQgaW4gdGhlIHdvcmtzcGFjZQ0KDQojIFdlIGZvcmdvdCBzb21ldGhpbmc7IGFkZCB0aGUgeWVhciB0byBzaGluaW5nX2xpc3QNCnNoaW5pbmdfbGlzdF9mdWxsIDwtIA0KDQojIEhhdmUgYSBsb29rIGF0IHNoaW5pbmdfbGlzdF9mdWxsDQoNCmBgYA0KDQoNCg0KDQoNCg0KDQo=