Author: Kayla Keyue Chen

Last updated: 2024.4.18

Learning objectives

  • Get familiar with R interface: (1) Create, save, and open a script. (2) Run your code. (3) Set working directory.

  • Learn how to install and load packages. We will be using “tidyverse” a lot because it offers many handy functions, and it also contains many other useful packages so we don’t need to install and load them one by one.

  • Differentiate object and function. Learn how to create and manipulate scalars, vectors, and dataframes in R. Use the environment to overview all the objects you have. Read the Console for effects of your code.

Get familiar with R interface

Create, save, and open a script

  1. Create a script: File -> New File -> R Script. In the Untitled1 file, type 1+2 in your script so we will have something to run later.

  2. Save: There are different ways to save a script: (1) File -> Save. (2) Click on the floppy disk icon. (3) Short cut: Ctrl/Command + S. If it is the first time you save the script, you need to give it a name.

  3. Open an existing script: You can open a script from RStudio interface or directly in your folder. (1) To open a script in RStudio, File -> Open File -> choose the one you want to open. (2) To open a script in your folder, you just need to double click on it

Run your code

  1. Run a line: Move the cursor to the line you want to run, and press Ctrl/Command + Enter and R will run the current line and automatically move the cursor to the next line.

  2. Run multiple lines: Highlight the lines you want to run, and press Ctrl/Command + Enter.

  3. Run the entire script: First select all lines by pressing Ctrl/Command + A, then run the code by pressing Ctrl/Command + Enter.

You can learn more keyboard shortcuts in the RStudio from their online support.

You can also click ‘Run’ in the top right corner of the Source window to run selected lines.

Set working directory

It’s very useful to set working directory at the beginning of your script so that R will know where to load and save your files. There are several ways to set working directory.

  1. You can use setwd() to set the directory and getwd() to know the current directory. Note: you need to use forward slash /.
# set working directory
setwd("D:/PLINSTAT R for linguists/2024 materials/week1")
# get working directory
getwd()
  1. You can also set working directory manually, from Session -> Set Working Directory -> Choose Directory … -> choose the folder you want to use in the pop-up window.

  2. If you have saved the script in the folder that you want to set as working directory, you can also use Session -> Set Working Directory -> To Source File Location.

  3. If you have opened the folder in the Files pane (the right bottem pane, Files tab), you can use Session -> Set Working Directory -> To Files Pane Location.

Install and load packages

An R package is simply a bunch of data (functions, help menus) stored in one neat package. Different packages have different functions that can be very useful and save a lot of trouble! You need to install (only for the first time) and load the package if you want to use the functions offered by the package.

Install packages using install.packages("name") where “name” is the name of the package. Note that you need to use quotation marks around the package name.

Load a package using library(name) where “name” is the name of the package. Here quotation marks are not needed.

# install tidyverse (you only need to install a package once)
install.packages("tidyverse")
# load tidyverse (you need to do this every time you open R)
library(tidyverse)

Create and manipulate objects in R

Objects and functions

Imagine we have a bunch of values, e.g. 2, 4, 6, 9, 13, 25. These are our objects. Now imagine we want to combine these objects into one sequence (this is called a vector) To combine objects into a vector, we use the ‘combine’ function c(). It looks like this c(x, y, z) - where c() is our function and x, y, z are placeholders for our objects. You can put as many objects into this function as you want.

# Now try the function c(x, y, z, ...) to combine 2, 4, 6, 9, 13, 25
c(2, 4, 6, 9, 13, 25)
[1]  2  4  6  9 13 25
# Check the Console: What happened? -- the code returns 2  4  6  9 13 25
# Check the Environment: Did anything happen? -- nothing 

Creating and saving objects

Now let’s look at how to create and save an object. This allows you to save them to your working space under a name. To create and save an object you:

  1. Type the name you want to give your object (e.g. pizza)

  2. Type this symbol: <-

  3. Type the function for the object you wish to create, e.g., c(2, 4, 6, 9, 13, 25)

  4. Press Ctrl/Command + Enter to run the code

After you run the code, you will see an object called pizza in the Environment pane under the Values section. It has “num [1:6] 2 4 6 9 13 25” in the second column. “num” means that this vector contains numeric data. “[1:6]” shows that there are 6 numbers in this vector, and then it shows the first several numbers for a preview.

# Now type the code to create the object pizza
pizza <- c(2, 4, 6, 9, 13, 25)
# Check the Console: What happened? -- the code didn't return the values 
# Check the Environment: Did anything happen? -- new object pizza in the Values section

# Now, call your object by typing the name, then Ctrl/Command + Enter
pizza
[1]  2  4  6  9 13 25
# Check the Environment: What do you see? -- the code returns the values 2  4  6  9 13 25

Scalars and operations

Numeric scalar

Scalar is atomic quantity that can hold only one value at a time. We can create numerical scalars. For example, let’s create a scalar called x with the value 4 and another scalar called y with the value 7.

# Create x
x <- 4

# Create y
y <- 7

# Check your Environment!

We can check what kind of scalar a given object is by using the class() function. For example: class(x) will return the the type of the object x, which is “numeric”.

# check the class of x
class(x)
[1] "numeric"
# what kind of scalar is x?

We can perform arithmetic operations on our scalars, e.g., adding (+), subtracting (-), multiplying (*), dividing (/), squaring (use ^ followed by a number, e.g., ^2), taking the root (use the function sqrt())

# try the following arithmetic operations, use any number you like

# adding
2+4 
[1] 6
# subtracting
1-100 
[1] -99
# multiplying
4*23 
[1] 92
# dividing
88/8 
[1] 11
# squaring
5^3 
[1] 125
# taking the root
sqrt(10) 
[1] 3.162278
# combination of different operations
sqrt((1+3)/2*9)^2 
[1] 18

Logical scalar

We can also create logical scalars (i.e. TRUE and FALSE). For example let’s create a scalar m that is defined as x > y, and a scalar n that is defined as x < y, and a scalar p that is defined as x = y. = is expressed as == in R language. Note: x and y are defined as the values we assigned to them earlier (x=4, and y=7).

# Define m
m <- x>y
# Define n
n <- x<y
# Define p
p <- x==y
# Check the Environment: what are the values of m, n, and p?
# m is FALSE, n is TRUE, and p is FALSE
# What kind of scalar is m? (hint: use class() function)
class(m) 
[1] "logical"

Logical operators include AND and OR. For example: x > y and x < y can be written as x > y & x < y or m & n; x > y or x < y can be written as x > y | x < y or m | n.

# Evaluate the code given as examples in the instruction
x > y & x < y 
[1] FALSE
m & n 
[1] FALSE

Character scalar

We can make character/string scalars. We must use quotation marks (either single or double) to indicate that they are characters. Create a character hello world and save it to an object named mystring.

# Create mystring
mystring <- "hello world"
# what kind of scalar is 'mystring'? (hint: use class() function)
class(mystring) 
[1] "character"

We can’t use operations on character scalars. Note that when a number is surrounded by quotation marks, it becomes a character. For example, 1 is a number, “1” is a character. You can use class() function to test if this is true.

# Try this
string1 <- "1" # ATTENTION: This is a character scalar because we put quotation marks!
string2 <- "2"
# Try adding them and see what happens :)
string1 + string2 # Error in string1 + string2 : non-numeric argument to binary operator

Vectors and operations

Create a vector

We can combine scalars into larger objects of the same data type: These are called vectors. Use c() function which has been introduced earlier.

# creates vector a which contains values 1,2,3,4 (hint: a <- c(x,y,z,...))
a <- c(1,2,3,4)
# creates vector b containing numbers from 1 to 10
b <- c(1,2,3,4,5,6,7,8,9,10)

Two useful functions to create scalar vectors with some rules.

  1. To create continuous integer numbers you can use : within c() function. For example, c(1:10) returns numbers from 1 to 10.

  2. seq(from, to, by) creates vector with sequence of values. “from” defines the starting point, “to” defines the ending point, and “by” defines the step. For example, seq(from=1,to=5,by=1) creates a vector containing 1,2,3,4,5.

  3. rep(x, times, each) creates vector with values repeated. “x” defines the vector to be repeated, “times” defines the number of repetition of the entire vector, and “each” defines the number of repetition of each element in the vector. For example, `rep(c(1,2,3),times=2,each=2)`` creates a new vector containing 1,1,2,2,3,3,1,1,2,2,3,3.

# generate numbers from 1 to 100 using c()
c(1:100)
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
 [19]  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
 [37]  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
 [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
 [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
 [91]  91  92  93  94  95  96  97  98  99 100
# create vector c with sequence of values from 1, to 20, by 2
c <- seq(from=1,to=20,by=2)
# create vector d with vector (2,4,6) repeated 2 times, with each element repeated 3 times
d <- rep(c(2,4,6),times=2,each=3)

Arithmetic operations with vectors

# Make a simple numeric vector (e)
e <- c(1,2,3)
# Make another one (f)
f <- c(5,7,9)
# Make another one (g)
g <- c(5,7,9,11)
# Check the Environment to see the length of the vectors
# e and f have 3 numbers, g has 4 numbers

We can do arithmetic operations on vectors too! If we want to do operations between two vectors, they must have the same length, or one is a multiple of the other.

# adds 6 to each value in e
e+6
[1] 7 8 9
# squaring each value of f
f^2
[1] 25 49 81
# adding e and f (each corresponding value in the sequence is summed)
e+f
[1]  6  9 12
# multiplying e and f (each corresponding value in the sequence is multiplied)
e*f
[1]  5 14 27
# Note: If you want to save these results to your Environment as vectors, you need to give them a name
# Now, try adding e and g, what happened? 
e+g # returns Warning: longer object length is not a multiple of shorter object length[1]  6  9 12 12

Logical operations with vectors

We can also do logical operations with vectors. For example, we can evaluate whether each item in the vector is larger than 10 by vector_name > 10.

# remember that we have vector b which contains integer numbers from 1 to 10
# find out whether each item in vector b is larger than 6
b > 6
 [1] FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE
# find out whether each item in vector b is larger than 5 AND smaller than 8
b > 5 & b < 8
 [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE

The %in% operation allows you to combine multiple OR comparisons to check whether given values are present in a set. For example: You have a vector that describes favourite letters fave.letters <- c('a', 't', 'a', 'b', 'z'). To check whether the each letter in fave.letters is one of ‘a’, ‘b’ or ‘c’, you can type: fave.letters %in% c('a', 'b', 'c'). The results will be TRUE FALSE TRUE TRUE FALSE, i.e., only the 2nd letter ‘t’ and the 5th letter ‘z’ are not one of ‘a’, ‘b’ or ‘c’.

This is helpful when you want to filter your participants based on their responses. For example, only keep participants whose favourite letter is one of ‘a’, ‘b’ or ‘c’.

# find out whether each item in vector b is in the set 1,7,13
b %in% c(1,7,13)
 [1]  TRUE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE
# find out whether each item in vector b is in the vector a
b %in% a
 [1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE

Note that because FALSE = 0 and TRUE = 1, we can sum() the logical vectors to find out the number of items that satisfy the operation, and use mean() to find out the proportion of items that satisfy the operation.

# find out the number of items in vector b that are larger than 6
sum(b > 6)
[1] 4
# find out the number of items in vector b that are in the set 3,5,0
sum(b %in% c(3,5,0))
[1] 2
# find out the proportion of items in vector b are larger than 5 AND smaller than 8
mean(b > 5 & b < 8)
[1] 0.2

Indexing a vector

You can ask R to return the values of specific items within your vectors by typing the vector name followed by [], and put the order number of the item into []. For example, to get the 2nd item in vector a, you write a[2]. To return multiple items, you can use c() to combine all indices you are interested in.

# remember that we have vector b which contains integer numbers from 1 to 10
# Get the 3rd item in vector b
b[3]
[1] 3
# Get the 2nd and 4th item in vector b
b[c(2,4)]
[1] 2 4
# Get the 2nd to 8th item in vector b
b[c(2:8)]
[1] 2 3 4 5 6 7 8

We can also use logical operations inside indexing []. For example, if we want to know what items in a vector is smaller than 5, we can write vector_name[vector_name < 5]. This is because vector_name < 5 returns a vector of logical values (i.e., FALSEs & TRUEs), and then indexing [] will return the items that have TRUEs.

which() function can return the indices where the value is TRUE. We can write which(vector_name < 5) to return the indices of numbers which is smaller than 5.

# find out what items in vector b are smaller than 4
b[b<4]
[1] 1 2 3
# find out what items in vector b are larger than 4 but smaller than 6
b[b>4 & b<6]
[1] 5
# find out the indices of items in vector b are smaller than 4
which(b<4) # note that because b contains integer numbers from 1 to 10, the indices are the same as number values. 
[1] 1 2 3

Dataframes

To create a dataframe, you need to specify column names and values in each column. For example, let’s create a dataframe called df1 with two columns, “sex” and “age”. We have 3 males and they are 99, 46, 23 years old, and 2 females and they are 54, 23 years old. Use data.frame() function, each argument will be in the format “column name = c(value1, value2, value3, …)”, e.g., “age = c(99,46,23,54,23)”.

# Create df1 using the data.frame() function
df1 <- data.frame(sex = c("male","male","male","female","female"), 
                  age = c(99,46,23,54,23))
# Now call on your dataframe: what does R return?
df1
     sex age
1   male  99
2   male  46
3   male  23
4 female  54
5 female  23

Your column/vector names are your variables, you call on specific variables within a dataframe with the dollar symbol $, e.g., df1$sex (this means you extract a vector from the dataframe!).

# Extract column age and sex 
df1$sex
[1] "male"   "male"   "male"   "female" "female"
df1$age
[1] 99 46 23 54 23

To get column names, you can use colnames(dataframe) function. You can change a specified column name using function rename(dataframe, new name = old name) (Note: rename() is provided by tidyverse package. Remember to load the package using library() first!). Another option is to use colnames(dataframe) <- c("xxx", "xxx", ...) to change ALL the column names at once.

#library(tidyverse) if you haven't
# Get the column names of df1
colnames(df1)
[1] "sex" "age"
# change column name "sex" to "gender" using rename()
rename(df1, "gender" = "sex")
  gender age
1   male  99
2   male  46
3   male  23
4 female  54
5 female  23
# change column names to "GENDER" and "AGE" using colnames()
colnames(df1) <- c("GENDER", "AGE")
# call on df1 to see the change
df1
  GENDER AGE
1   male  99
2   male  46
3   male  23
4 female  54
5 female  23

Factor variable

We can set the sex column to a factor variable using as.factor() function. If sex is set to a factor variable, it is categorical and new observations can only be one of the specified levels. The levels are by default arranged by alphabetical order. You can manually specify the order using function factor() (no “as”!) and argument levels = c("xxx", "xxx", ...).

Remember you must give the results back to the object to save the change! For example, a+1 will add 1 to the number scalar a, but the value of a won’t change, whereas a <- a+1 will update the value of a.

# Turn GENDER column into a factor variable using as.factor()
df1$GENDER <- as.factor(df1$GENDER)
# Set male to be level1 and female to be level2 using factor()
df1$GENDER <- factor(df1$GENDER, levels = c("male", "female"))
# Call on the GENDER column and see what levels are there in the factor (hint: use the dollor symbol $)
df1$GENDER
[1] male   male   male   female female
Levels: male female
# Add a 6th observation to the column. Can you add "female"? Can you add "other"?
# first we extract the vector GENDER <- df1$GENDER
# then try GENDER[6] <- "female" and then GENDER[6] <- "other", What happened? 
GENDER <- df1$GENDER
GENDER[6] <- "female" # works fine
GENDER[6] <- "other" # returns Warning: invalid factor level, NA generated, "other" is replaced with <NA> 

Let’s practice !

  1. Create a vector for each of the columns in the table (see the last slide for Lab1)

    • Tip 1: use the combine function c() to create the vectors

    • Tip 2: assign vectors to column names, e.g., column_name = c(value1, value2, …)

lang_name <- c('Mandarin', 'Spanish', 'English', 'Hindi', 'Portuguese', 'Bengali', 'Russian', 'Japanese')
lang_order <- c('SVO', 'SVO', 'SVO', 'SOV', 'SVO', 'SOV', 'SVO', 'SOV')
lang_popL1 <- c(921.2, 471.4, 369.9, 342.2, 232.4, 228.7, 153.7, 126.3)
lang_popL2 <- c(198.7, 71.5, 978.2, 258.3, 25.2, 39.0, 104.3, 0.12)
lang_indoeuro <- c(FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE)
  1. Combine the vectors into a dataframe

    • Tip 1: use the dataframe function data.frame() to create the dataframe

    • Tip 2: save the dataframe with the name lang_df

lang_df <- data.frame(lang_name, lang_order, lang_popL1, lang_popL2,lang_indoeuro)
  1. Have a look at the dataframe

    • Call on the entire dataframe

    • Call on specific columns (vectors) in your dataframe

    • Call on all column names

# Call on the entire dataframe
lang_df
   lang_name lang_order lang_popL1 lang_popL2 lang_indoeuro
1   Mandarin        SVO      921.2     198.70         FALSE
2    Spanish        SVO      471.4      71.50          TRUE
3    English        SVO      369.9     978.20          TRUE
4      Hindi        SOV      342.2     258.30          TRUE
5 Portuguese        SVO      232.4      25.20          TRUE
6    Bengali        SOV      228.7      39.00          TRUE
7    Russian        SVO      153.7     104.30          TRUE
8   Japanese        SOV      126.3       0.12         FALSE
# Call on specific columns (vectors) in your dataframe
lang_df$lang_name
[1] "Mandarin"   "Spanish"    "English"    "Hindi"      "Portuguese"
[6] "Bengali"    "Russian"    "Japanese"  
lang_df$lang_popL1
[1] 921.2 471.4 369.9 342.2 232.4 228.7 153.7 126.3
# return all column names
colnames(lang_df)
[1] "lang_name"     "lang_order"    "lang_popL1"    "lang_popL2"   
[5] "lang_indoeuro"
  1. Try executing the following functions on your dataframe and see what the functions return.
# head(df_name)
head(lang_df) # returns first several rows
   lang_name lang_order lang_popL1 lang_popL2 lang_indoeuro
1   Mandarin        SVO      921.2      198.7         FALSE
2    Spanish        SVO      471.4       71.5          TRUE
3    English        SVO      369.9      978.2          TRUE
4      Hindi        SOV      342.2      258.3          TRUE
5 Portuguese        SVO      232.4       25.2          TRUE
6    Bengali        SOV      228.7       39.0          TRUE
# tail(df_name)
tail(lang_df) # returns last several rows
   lang_name lang_order lang_popL1 lang_popL2 lang_indoeuro
3    English        SVO      369.9     978.20          TRUE
4      Hindi        SOV      342.2     258.30          TRUE
5 Portuguese        SVO      232.4      25.20          TRUE
6    Bengali        SOV      228.7      39.00          TRUE
7    Russian        SVO      153.7     104.30          TRUE
8   Japanese        SOV      126.3       0.12         FALSE
# View(df_name) N.B. the 'V' in View is capitalised
View(lang_df) # this will open a new tab in the Source pane and show the table of lang_df
# nrow(df_name)
nrow(lang_df) # returns total number of rows
[1] 8
# ncol(df_name)
ncol(lang_df) # returns total number of columns
[1] 5
# dim(df_name)
dim(lang_df) # returns total number of rows and columns 
[1] 8 5
# summary(df_name)
summary(lang_df) # returns a summary of values in each column
  lang_name          lang_order          lang_popL1      lang_popL2    
 Length:8           Length:8           Min.   :126.3   Min.   :  0.12  
 Class :character   Class :character   1st Qu.:209.9   1st Qu.: 35.55  
 Mode  :character   Mode  :character   Median :287.3   Median : 87.90  
                                       Mean   :355.7   Mean   :209.41  
                                       3rd Qu.:395.3   3rd Qu.:213.60  
                                       Max.   :921.2   Max.   :978.20  
 lang_indoeuro  
 Mode :logical  
 FALSE:2        
 TRUE :6        
                
                
                
# What do each of these functions do?
  1. Indexing a vector (column) in dataframe
# What is the L1 language population of the first language (ie, Mandarin)?
lang_df$lang_popL1[1]
[1] 921.2
# What are the word orders of the first 5 languages?
lang_df$lang_order[1:5]
[1] "SVO" "SVO" "SVO" "SOV" "SVO"
# Whether each L1 language population are greater than 300 million?
lang_df$lang_popL1 > 300
[1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE
# Whether each language orders are SVO? 
lang_df$lang_order == "SVO"
[1]  TRUE  TRUE  TRUE FALSE  TRUE FALSE  TRUE FALSE
# What are the names of languages with L2 population lower than 100 million?
lang_df$lang_name[lang_df$lang_popL2 < 100]
[1] "Spanish"    "Portuguese" "Bengali"    "Japanese"  
# What are the names of languages with SVO order and L2 language population more than 100 million?
lang_df$lang_name[lang_df$lang_order == "SVO" & lang_df$lang_popL2 > 100]
[1] "Mandarin" "English"  "Russian" 
  1. Counting the number of observations satisfying a specific criteria
# How many languages have SVO order? What is the proportion?
sum(lang_df$lang_order == "SVO")
[1] 5
mean(lang_df$lang_order == "SVO")
[1] 0.625
# How many languages have L2 population greater than 200 million? What is the proportion?
sum(lang_df$lang_popL2 > 200)
[1] 2
mean(lang_df$lang_popL2 > 200)
[1] 0.25
LS0tDQp0aXRsZTogIlBMSU5TVEFUIGxhYiAxOiBHZXR0aW5nIGZhbWlsaWFyIHdpdGggUiINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KcGFyYW1zOg0KICBmbGV4OiBUUlVFDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojc3R1ZGVudHM6IHRoaXMgaXMgdGhlIHNldCB1cCBjaHVuaywgaXQgY2FuIGJlIGlnbm9yZWQNCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjb21tZW50ID0gIiIpDQpsaWJyYXJ5KGtuaXRyKQ0KYGBgDQoNCkF1dGhvcjogS2F5bGEgS2V5dWUgQ2hlbg0KDQpMYXN0IHVwZGF0ZWQ6IDIwMjQuNC4xOA0KDQojIyBMZWFybmluZyBvYmplY3RpdmVzIA0KDQoqIEdldCBmYW1pbGlhciB3aXRoIFIgaW50ZXJmYWNlOiAoMSkgQ3JlYXRlLCBzYXZlLCBhbmQgb3BlbiBhIHNjcmlwdC4gKDIpIFJ1biB5b3VyIGNvZGUuICgzKSBTZXQgd29ya2luZyBkaXJlY3RvcnkuIA0KDQoqIExlYXJuIGhvdyB0byBpbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2VzLiBXZSB3aWxsIGJlIHVzaW5nICJ0aWR5dmVyc2UiIGEgbG90IGJlY2F1c2UgaXQgb2ZmZXJzIG1hbnkgaGFuZHkgZnVuY3Rpb25zLCBhbmQgaXQgYWxzbyBjb250YWlucyBtYW55IG90aGVyIHVzZWZ1bCBwYWNrYWdlcyBzbyB3ZSBkb24ndCBuZWVkIHRvIGluc3RhbGwgYW5kIGxvYWQgdGhlbSBvbmUgYnkgb25lLiANCg0KKiBEaWZmZXJlbnRpYXRlIG9iamVjdCBhbmQgZnVuY3Rpb24uIExlYXJuIGhvdyB0byBjcmVhdGUgYW5kIG1hbmlwdWxhdGUgc2NhbGFycywgdmVjdG9ycywgYW5kIGRhdGFmcmFtZXMgaW4gUi4gVXNlIHRoZSBlbnZpcm9ubWVudCB0byBvdmVydmlldyBhbGwgdGhlIG9iamVjdHMgeW91IGhhdmUuIFJlYWQgdGhlIENvbnNvbGUgZm9yIGVmZmVjdHMgb2YgeW91ciBjb2RlLiANCg0KIyMgR2V0IGZhbWlsaWFyIHdpdGggUiBpbnRlcmZhY2UNCg0KIyMjIENyZWF0ZSwgc2F2ZSwgYW5kIG9wZW4gYSBzY3JpcHQNCg0KMS4gPGI+Q3JlYXRlIGEgc2NyaXB0PC9iPjogRmlsZSAtPiBOZXcgRmlsZSAtPiBSIFNjcmlwdC4gSW4gdGhlIFVudGl0bGVkMSBmaWxlLCB0eXBlIGAxKzJgIGluIHlvdXIgc2NyaXB0IHNvIHdlIHdpbGwgaGF2ZSBzb21ldGhpbmcgdG8gcnVuIGxhdGVyLg0KDQoyLiA8Yj5TYXZlPC9iPjogVGhlcmUgYXJlIGRpZmZlcmVudCB3YXlzIHRvIHNhdmUgYSBzY3JpcHQ6ICgxKSBGaWxlIC0+IFNhdmUuICgyKSBDbGljayBvbiB0aGUgZmxvcHB5IGRpc2sgaWNvbi4gKDMpIFNob3J0IGN1dDogQ3RybC9Db21tYW5kICsgUy4gSWYgaXQgaXMgdGhlIGZpcnN0IHRpbWUgeW91IHNhdmUgdGhlIHNjcmlwdCwgeW91IG5lZWQgdG8gZ2l2ZSBpdCBhIG5hbWUuIA0KDQozLiA8Yj5PcGVuIGFuIGV4aXN0aW5nIHNjcmlwdDwvYj46IFlvdSBjYW4gb3BlbiBhIHNjcmlwdCBmcm9tIFJTdHVkaW8gaW50ZXJmYWNlIG9yIGRpcmVjdGx5IGluIHlvdXIgZm9sZGVyLiAoMSkgVG8gb3BlbiBhIHNjcmlwdCBpbiBSU3R1ZGlvLCBGaWxlIC0+IE9wZW4gRmlsZSAtPiBjaG9vc2UgdGhlIG9uZSB5b3Ugd2FudCB0byBvcGVuLiAoMikgVG8gb3BlbiBhIHNjcmlwdCBpbiB5b3VyIGZvbGRlciwgeW91IGp1c3QgbmVlZCB0byBkb3VibGUgY2xpY2sgb24gaXQgDQoNCiMjIyBSdW4geW91ciBjb2RlDQoNCjEuIDxiPlJ1biBhIGxpbmU8L2I+OiBNb3ZlIHRoZSBjdXJzb3IgdG8gdGhlIGxpbmUgeW91IHdhbnQgdG8gcnVuLCBhbmQgcHJlc3MgQ3RybC9Db21tYW5kICsgRW50ZXIgYW5kIFIgd2lsbCBydW4gdGhlIGN1cnJlbnQgbGluZSBhbmQgYXV0b21hdGljYWxseSBtb3ZlIHRoZSBjdXJzb3IgdG8gdGhlIG5leHQgbGluZS4gDQoNCjIuIDxiPlJ1biBtdWx0aXBsZSBsaW5lczwvYj46IEhpZ2hsaWdodCB0aGUgbGluZXMgeW91IHdhbnQgdG8gcnVuLCBhbmQgcHJlc3MgQ3RybC9Db21tYW5kICsgRW50ZXIuIA0KDQozLiA8Yj5SdW4gdGhlIGVudGlyZSBzY3JpcHQ8L2I+OiBGaXJzdCBzZWxlY3QgYWxsIGxpbmVzIGJ5IHByZXNzaW5nIEN0cmwvQ29tbWFuZCArIEEsIHRoZW4gcnVuIHRoZSBjb2RlIGJ5IHByZXNzaW5nIEN0cmwvQ29tbWFuZCArIEVudGVyLiANCg0KWW91IGNhbiBsZWFybiBtb3JlIGtleWJvYXJkIHNob3J0Y3V0cyBpbiB0aGUgUlN0dWRpbyBmcm9tIHRoZWlyIFtvbmxpbmUgc3VwcG9ydF0oaHR0cHM6Ly9zdXBwb3J0LnJzdHVkaW8uY29tL2hjL2VuLXVzL2FydGljbGVzLzIwMDcxMTg1My1LZXlib2FyZC1TaG9ydGN1dHMtaW4tdGhlLVJTdHVkaW8tSURFKS4NCg0KWW91IGNhbiBhbHNvIGNsaWNrIOKAmFJ1buKAmSBpbiB0aGUgdG9wIHJpZ2h0IGNvcm5lciBvZiB0aGUgU291cmNlIHdpbmRvdyB0byBydW4gc2VsZWN0ZWQgbGluZXMuIA0KDQojIyMgU2V0IHdvcmtpbmcgZGlyZWN0b3J5DQoNCkl0J3MgdmVyeSB1c2VmdWwgdG8gc2V0IHdvcmtpbmcgZGlyZWN0b3J5IGF0IHRoZSBiZWdpbm5pbmcgb2YgeW91ciBzY3JpcHQgc28gdGhhdCBSIHdpbGwga25vdyB3aGVyZSB0byBsb2FkIGFuZCBzYXZlIHlvdXIgZmlsZXMuIFRoZXJlIGFyZSBzZXZlcmFsIHdheXMgdG8gc2V0IHdvcmtpbmcgZGlyZWN0b3J5LiANCg0KMS4gWW91IGNhbiB1c2UgYHNldHdkKClgIHRvIHNldCB0aGUgZGlyZWN0b3J5IGFuZCBgZ2V0d2QoKWAgdG8ga25vdyB0aGUgY3VycmVudCBkaXJlY3RvcnkuIE5vdGU6IHlvdSBuZWVkIHRvIHVzZSBmb3J3YXJkIHNsYXNoIGAvYC4NCg0KYGBge3IgZXZhbD1GQUxTRX0NCiMgc2V0IHdvcmtpbmcgZGlyZWN0b3J5DQpzZXR3ZCgiRDovUExJTlNUQVQgUiBmb3IgbGluZ3Vpc3RzLzIwMjQgbWF0ZXJpYWxzL3dlZWsxIikNCiMgZ2V0IHdvcmtpbmcgZGlyZWN0b3J5DQpnZXR3ZCgpDQpgYGANCg0KMi4gWW91IGNhbiBhbHNvIHNldCB3b3JraW5nIGRpcmVjdG9yeSBtYW51YWxseSwgZnJvbSBTZXNzaW9uIC0+IFNldCBXb3JraW5nIERpcmVjdG9yeSAtPiBDaG9vc2UgRGlyZWN0b3J5IC4uLiAtPiBjaG9vc2UgdGhlIGZvbGRlciB5b3Ugd2FudCB0byB1c2UgaW4gdGhlIHBvcC11cCB3aW5kb3cuIA0KDQozLiBJZiB5b3UgaGF2ZSBzYXZlZCB0aGUgc2NyaXB0IGluIHRoZSBmb2xkZXIgdGhhdCB5b3Ugd2FudCB0byBzZXQgYXMgd29ya2luZyBkaXJlY3RvcnksIHlvdSBjYW4gYWxzbyB1c2UgU2Vzc2lvbiAtPiBTZXQgV29ya2luZyBEaXJlY3RvcnkgLT4gVG8gU291cmNlIEZpbGUgTG9jYXRpb24uIA0KDQo0LiBJZiB5b3UgaGF2ZSBvcGVuZWQgdGhlIGZvbGRlciBpbiB0aGUgRmlsZXMgcGFuZSAodGhlIHJpZ2h0IGJvdHRlbSBwYW5lLCBGaWxlcyB0YWIpLCB5b3UgY2FuIHVzZSBTZXNzaW9uIC0+IFNldCBXb3JraW5nIERpcmVjdG9yeSAtPiBUbyBGaWxlcyBQYW5lIExvY2F0aW9uLiAgDQoNCiMjIEluc3RhbGwgYW5kIGxvYWQgcGFja2FnZXMNCg0KQW4gUiBwYWNrYWdlIGlzIHNpbXBseSBhIGJ1bmNoIG9mIGRhdGEgKGZ1bmN0aW9ucywgaGVscCBtZW51cykgc3RvcmVkIGluIG9uZSBuZWF0IHBhY2thZ2UuIERpZmZlcmVudCBwYWNrYWdlcyBoYXZlIGRpZmZlcmVudCBmdW5jdGlvbnMgdGhhdCBjYW4gYmUgdmVyeSB1c2VmdWwgYW5kIHNhdmUgYSBsb3Qgb2YgdHJvdWJsZSEgWW91IG5lZWQgdG8gaW5zdGFsbCAob25seSBmb3IgdGhlIGZpcnN0IHRpbWUpIGFuZCBsb2FkIHRoZSBwYWNrYWdlIGlmIHlvdSB3YW50IHRvIHVzZSB0aGUgZnVuY3Rpb25zIG9mZmVyZWQgYnkgdGhlIHBhY2thZ2UuIA0KDQpJbnN0YWxsIHBhY2thZ2VzIHVzaW5nIGBpbnN0YWxsLnBhY2thZ2VzKCJuYW1lIilgIHdoZXJlIOKAnG5hbWXigJ0gaXMgdGhlIG5hbWUgb2YgdGhlIHBhY2thZ2UuIE5vdGUgdGhhdCB5b3UgbmVlZCB0byB1c2UgcXVvdGF0aW9uIG1hcmtzIGFyb3VuZCB0aGUgcGFja2FnZSBuYW1lLiANCg0KTG9hZCBhIHBhY2thZ2UgdXNpbmcgYGxpYnJhcnkobmFtZSlgIHdoZXJlIOKAnG5hbWXigJ0gaXMgdGhlIG5hbWUgb2YgdGhlIHBhY2thZ2UuIEhlcmUgcXVvdGF0aW9uIG1hcmtzIGFyZSBub3QgbmVlZGVkLiANCg0KYGBge3IgZXZhbD1GQUxTRX0NCiMgaW5zdGFsbCB0aWR5dmVyc2UgKHlvdSBvbmx5IG5lZWQgdG8gaW5zdGFsbCBhIHBhY2thZ2Ugb25jZSkNCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpgYGANCg0KYGBge3J9DQojIGxvYWQgdGlkeXZlcnNlICh5b3UgbmVlZCB0byBkbyB0aGlzIGV2ZXJ5IHRpbWUgeW91IG9wZW4gUikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCiMjIENyZWF0ZSBhbmQgbWFuaXB1bGF0ZSBvYmplY3RzIGluIFINCg0KIyMjIE9iamVjdHMgYW5kIGZ1bmN0aW9ucw0KDQpJbWFnaW5lIHdlIGhhdmUgYSBidW5jaCBvZiB2YWx1ZXMsIGUuZy4gIDIsIDQsIDYsIDksIDEzLCAyNS4gVGhlc2UgYXJlIG91ciBvYmplY3RzLiBOb3cgaW1hZ2luZSB3ZSB3YW50IHRvIGNvbWJpbmUgdGhlc2Ugb2JqZWN0cyBpbnRvIG9uZSBzZXF1ZW5jZSAodGhpcyBpcyBjYWxsZWQgYSA8Yj52ZWN0b3I8L2I+KSBUbyBjb21iaW5lIG9iamVjdHMgaW50byBhIHZlY3Rvciwgd2UgdXNlIHRoZSAnY29tYmluZScgZnVuY3Rpb24gYGMoKWAuIEl0IGxvb2tzIGxpa2UgdGhpcyBgYyh4LCB5LCB6KWAgLSB3aGVyZSBgYygpYCBpcyBvdXIgZnVuY3Rpb24gYW5kIHgsIHksIHogYXJlIHBsYWNlaG9sZGVycyBmb3Igb3VyIG9iamVjdHMuIFlvdSBjYW4gcHV0IGFzIG1hbnkgb2JqZWN0cyBpbnRvIHRoaXMgZnVuY3Rpb24gYXMgeW91IHdhbnQuIA0KDQpgYGB7cn0NCiMgTm93IHRyeSB0aGUgZnVuY3Rpb24gYyh4LCB5LCB6LCAuLi4pIHRvIGNvbWJpbmUgMiwgNCwgNiwgOSwgMTMsIDI1DQpjKDIsIDQsIDYsIDksIDEzLCAyNSkNCiMgQ2hlY2sgdGhlIENvbnNvbGU6IFdoYXQgaGFwcGVuZWQ/IC0tIHRoZSBjb2RlIHJldHVybnMgMiAgNCAgNiAgOSAxMyAyNQ0KIyBDaGVjayB0aGUgRW52aXJvbm1lbnQ6IERpZCBhbnl0aGluZyBoYXBwZW4/IC0tIG5vdGhpbmcgDQpgYGANCg0KIyMjIENyZWF0aW5nIGFuZCBzYXZpbmcgb2JqZWN0cw0KDQpOb3cgbGV0J3MgbG9vayBhdCBob3cgdG8gY3JlYXRlIGFuZCBzYXZlIGFuIG9iamVjdC4gVGhpcyBhbGxvd3MgeW91IHRvIHNhdmUgdGhlbSB0byB5b3VyIHdvcmtpbmcgc3BhY2UgdW5kZXIgYSBuYW1lLiBUbyBjcmVhdGUgYW5kIHNhdmUgYW4gb2JqZWN0IHlvdTogDQoNCjEuIFR5cGUgdGhlIG5hbWUgeW91IHdhbnQgdG8gZ2l2ZSB5b3VyIG9iamVjdCAoZS5nLiBwaXp6YSkNCg0KMi4gVHlwZSB0aGlzIHN5bWJvbDogYDwtYA0KDQozLiBUeXBlIHRoZSBmdW5jdGlvbiBmb3IgdGhlIG9iamVjdCB5b3Ugd2lzaCB0byBjcmVhdGUsIGUuZy4sIGBjKDIsIDQsIDYsIDksIDEzLCAyNSlgDQoNCjQuIFByZXNzIEN0cmwvQ29tbWFuZCArIEVudGVyIHRvIHJ1biB0aGUgY29kZQ0KDQpBZnRlciB5b3UgcnVuIHRoZSBjb2RlLCB5b3Ugd2lsbCBzZWUgYW4gb2JqZWN0IGNhbGxlZCBwaXp6YSBpbiB0aGUgRW52aXJvbm1lbnQgcGFuZSB1bmRlciB0aGUgVmFsdWVzIHNlY3Rpb24uIEl0IGhhcyAibnVtIFsxOjZdIDIgNCA2IDkgMTMgMjUiIGluIHRoZSBzZWNvbmQgY29sdW1uLiAibnVtIiBtZWFucyB0aGF0IHRoaXMgdmVjdG9yIGNvbnRhaW5zIG51bWVyaWMgZGF0YS4gIlsxOjZdIiBzaG93cyB0aGF0IHRoZXJlIGFyZSA2IG51bWJlcnMgaW4gdGhpcyB2ZWN0b3IsIGFuZCB0aGVuIGl0IHNob3dzIHRoZSBmaXJzdCBzZXZlcmFsIG51bWJlcnMgZm9yIGEgcHJldmlldy4gDQoNCmBgYHtyfQ0KIyBOb3cgdHlwZSB0aGUgY29kZSB0byBjcmVhdGUgdGhlIG9iamVjdCBwaXp6YQ0KcGl6emEgPC0gYygyLCA0LCA2LCA5LCAxMywgMjUpDQojIENoZWNrIHRoZSBDb25zb2xlOiBXaGF0IGhhcHBlbmVkPyAtLSB0aGUgY29kZSBkaWRuJ3QgcmV0dXJuIHRoZSB2YWx1ZXMgDQojIENoZWNrIHRoZSBFbnZpcm9ubWVudDogRGlkIGFueXRoaW5nIGhhcHBlbj8gLS0gbmV3IG9iamVjdCBwaXp6YSBpbiB0aGUgVmFsdWVzIHNlY3Rpb24NCg0KIyBOb3csIGNhbGwgeW91ciBvYmplY3QgYnkgdHlwaW5nIHRoZSBuYW1lLCB0aGVuIEN0cmwvQ29tbWFuZCArIEVudGVyDQpwaXp6YQ0KDQojIENoZWNrIHRoZSBFbnZpcm9ubWVudDogV2hhdCBkbyB5b3Ugc2VlPyAtLSB0aGUgY29kZSByZXR1cm5zIHRoZSB2YWx1ZXMgMiAgNCAgNiAgOSAxMyAyNQ0KYGBgDQoNCiMjIFNjYWxhcnMgYW5kIG9wZXJhdGlvbnMNCg0KIyMjIE51bWVyaWMgc2NhbGFyDQoNClNjYWxhciBpcyBhdG9taWMgcXVhbnRpdHkgdGhhdCBjYW4gaG9sZCBvbmx5IG9uZSB2YWx1ZSBhdCBhIHRpbWUuIFdlIGNhbiBjcmVhdGUgbnVtZXJpY2FsIHNjYWxhcnMuIEZvciBleGFtcGxlLCBsZXQncyBjcmVhdGUgYSBzY2FsYXIgY2FsbGVkIHggd2l0aCB0aGUgdmFsdWUgNCBhbmQgYW5vdGhlciBzY2FsYXIgY2FsbGVkIHkgd2l0aCB0aGUgdmFsdWUgNy4gDQoNCmBgYHtyfQ0KIyBDcmVhdGUgeA0KeCA8LSA0DQoNCiMgQ3JlYXRlIHkNCnkgPC0gNw0KDQojIENoZWNrIHlvdXIgRW52aXJvbm1lbnQhDQpgYGANCg0KV2UgY2FuIGNoZWNrIHdoYXQga2luZCBvZiBzY2FsYXIgYSBnaXZlbiBvYmplY3QgaXMgYnkgdXNpbmcgdGhlIGBjbGFzcygpYCBmdW5jdGlvbi4gRm9yIGV4YW1wbGU6IGBjbGFzcyh4KWAgd2lsbCByZXR1cm4gdGhlIHRoZSB0eXBlIG9mIHRoZSBvYmplY3QgeCwgd2hpY2ggaXMgIm51bWVyaWMiLiANCg0KYGBge3J9DQojIGNoZWNrIHRoZSBjbGFzcyBvZiB4DQpjbGFzcyh4KQ0KDQojIHdoYXQga2luZCBvZiBzY2FsYXIgaXMgeD8NCg0KYGBgDQoNCldlIGNhbiBwZXJmb3JtIGFyaXRobWV0aWMgb3BlcmF0aW9ucyBvbiBvdXIgc2NhbGFycywgZS5nLiwgYWRkaW5nICgrKSwgc3VidHJhY3RpbmcgKC0pLCBtdWx0aXBseWluZyAoKiksIGRpdmlkaW5nICgvKSwgc3F1YXJpbmcgKHVzZSBeIGZvbGxvd2VkIGJ5IGEgbnVtYmVyLCBlLmcuLCBeMiksIHRha2luZyB0aGUgcm9vdCAodXNlIHRoZSBmdW5jdGlvbiBgc3FydCgpYCkNCg0KYGBge3J9DQojIHRyeSB0aGUgZm9sbG93aW5nIGFyaXRobWV0aWMgb3BlcmF0aW9ucywgdXNlIGFueSBudW1iZXIgeW91IGxpa2UNCg0KIyBhZGRpbmcNCjIrNCANCiMgc3VidHJhY3RpbmcNCjEtMTAwIA0KIyBtdWx0aXBseWluZw0KNCoyMyANCiMgZGl2aWRpbmcNCjg4LzggDQojIHNxdWFyaW5nDQo1XjMgDQojIHRha2luZyB0aGUgcm9vdA0Kc3FydCgxMCkgDQojIGNvbWJpbmF0aW9uIG9mIGRpZmZlcmVudCBvcGVyYXRpb25zDQpzcXJ0KCgxKzMpLzIqOSleMiANCmBgYA0KDQojIyMgTG9naWNhbCBzY2FsYXINCg0KV2UgY2FuIGFsc28gY3JlYXRlIGxvZ2ljYWwgc2NhbGFycyAoaS5lLiBUUlVFIGFuZCBGQUxTRSkuIEZvciBleGFtcGxlIGxldCdzIGNyZWF0ZSBhIHNjYWxhciBtIHRoYXQgaXMgZGVmaW5lZCBhcyB4ID4geSwgYW5kIGEgc2NhbGFyIG4gdGhhdCBpcyBkZWZpbmVkIGFzIHggPCB5LCBhbmQgYSBzY2FsYXIgcCB0aGF0IGlzIGRlZmluZWQgYXMgeCA9IHkuIGA9YCBpcyBleHByZXNzZWQgYXMgYD09YCBpbiBSIGxhbmd1YWdlLiBOb3RlOiB4IGFuZCB5IGFyZSBkZWZpbmVkIGFzIHRoZSB2YWx1ZXMgd2UgYXNzaWduZWQgdG8gdGhlbSBlYXJsaWVyICh4PTQsIGFuZCB5PTcpLg0KDQpgYGB7cn0NCiMgRGVmaW5lIG0NCm0gPC0geD55DQojIERlZmluZSBuDQpuIDwtIHg8eQ0KIyBEZWZpbmUgcA0KcCA8LSB4PT15DQojIENoZWNrIHRoZSBFbnZpcm9ubWVudDogd2hhdCBhcmUgdGhlIHZhbHVlcyBvZiBtLCBuLCBhbmQgcD8NCiMgbSBpcyBGQUxTRSwgbiBpcyBUUlVFLCBhbmQgcCBpcyBGQUxTRQ0KIyBXaGF0IGtpbmQgb2Ygc2NhbGFyIGlzIG0/IChoaW50OiB1c2UgY2xhc3MoKSBmdW5jdGlvbikNCmNsYXNzKG0pIA0KYGBgDQoNCkxvZ2ljYWwgb3BlcmF0b3JzIGluY2x1ZGUgQU5EIGFuZCBPUi4gRm9yIGV4YW1wbGU6IHggPiB5IGFuZCB4IDwgeSBjYW4gYmUgd3JpdHRlbiBhcyBgeCA+IHkgJiB4IDwgeWAgb3IgYG0gJiBuYDsgeCA+IHkgb3IgeCA8IHkgY2FuIGJlIHdyaXR0ZW4gYXMgYHggPiB5IHwgeCA8IHlgIG9yIGBtIHwgbmAuDQoNCmBgYHtyfQ0KIyBFdmFsdWF0ZSB0aGUgY29kZSBnaXZlbiBhcyBleGFtcGxlcyBpbiB0aGUgaW5zdHJ1Y3Rpb24NCnggPiB5ICYgeCA8IHkgDQptICYgbiANCmBgYA0KDQojIyMgQ2hhcmFjdGVyIHNjYWxhciANCg0KV2UgY2FuIG1ha2UgY2hhcmFjdGVyL3N0cmluZyBzY2FsYXJzLiBXZSBtdXN0IHVzZSA8Yj5xdW90YXRpb24gbWFya3M8L2I+IChlaXRoZXIgc2luZ2xlIG9yIGRvdWJsZSkgdG8gaW5kaWNhdGUgdGhhdCB0aGV5IGFyZSBjaGFyYWN0ZXJzLiBDcmVhdGUgYSBjaGFyYWN0ZXIgYGhlbGxvIHdvcmxkYCBhbmQgc2F2ZSBpdCB0byBhbiBvYmplY3QgbmFtZWQgYG15c3RyaW5nYC4NCg0KYGBge3J9DQojIENyZWF0ZSBteXN0cmluZw0KbXlzdHJpbmcgPC0gImhlbGxvIHdvcmxkIg0KIyB3aGF0IGtpbmQgb2Ygc2NhbGFyIGlzICdteXN0cmluZyc/IChoaW50OiB1c2UgY2xhc3MoKSBmdW5jdGlvbikNCmNsYXNzKG15c3RyaW5nKSANCmBgYA0KDQpXZSBjYW4ndCB1c2Ugb3BlcmF0aW9ucyBvbiBjaGFyYWN0ZXIgc2NhbGFycy4gTm90ZSB0aGF0IHdoZW4gYSBudW1iZXIgaXMgc3Vycm91bmRlZCBieSBxdW90YXRpb24gbWFya3MsIGl0IGJlY29tZXMgYSBjaGFyYWN0ZXIuIEZvciBleGFtcGxlLCAxIGlzIGEgbnVtYmVyLCAiMSIgaXMgYSBjaGFyYWN0ZXIuIFlvdSBjYW4gdXNlIGBjbGFzcygpYCBmdW5jdGlvbiB0byB0ZXN0IGlmIHRoaXMgaXMgdHJ1ZS4gDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQojIFRyeSB0aGlzDQpzdHJpbmcxIDwtICIxIiAjIEFUVEVOVElPTjogVGhpcyBpcyBhIGNoYXJhY3RlciBzY2FsYXIgYmVjYXVzZSB3ZSBwdXQgcXVvdGF0aW9uIG1hcmtzIQ0Kc3RyaW5nMiA8LSAiMiINCiMgVHJ5IGFkZGluZyB0aGVtIGFuZCBzZWUgd2hhdCBoYXBwZW5zIDopDQpzdHJpbmcxICsgc3RyaW5nMiAjIEVycm9yIGluIHN0cmluZzEgKyBzdHJpbmcyIDogbm9uLW51bWVyaWMgYXJndW1lbnQgdG8gYmluYXJ5IG9wZXJhdG9yDQpgYGANCg0KIyMgVmVjdG9ycyBhbmQgb3BlcmF0aW9ucw0KDQojIyMgQ3JlYXRlIGEgdmVjdG9yDQoNCldlIGNhbiBjb21iaW5lIHNjYWxhcnMgaW50byBsYXJnZXIgb2JqZWN0cyBvZiB0aGUgc2FtZSBkYXRhIHR5cGU6IFRoZXNlIGFyZSBjYWxsZWQgdmVjdG9ycy4gVXNlIGBjKClgIGZ1bmN0aW9uIHdoaWNoIGhhcyBiZWVuIGludHJvZHVjZWQgZWFybGllci4gDQoNCmBgYHtyfQ0KIyBjcmVhdGVzIHZlY3RvciBhIHdoaWNoIGNvbnRhaW5zIHZhbHVlcyAxLDIsMyw0IChoaW50OiBhIDwtIGMoeCx5LHosLi4uKSkNCmEgPC0gYygxLDIsMyw0KQ0KIyBjcmVhdGVzIHZlY3RvciBiIGNvbnRhaW5pbmcgbnVtYmVycyBmcm9tIDEgdG8gMTANCmIgPC0gYygxLDIsMyw0LDUsNiw3LDgsOSwxMCkNCmBgYA0KDQpUd28gdXNlZnVsIGZ1bmN0aW9ucyB0byBjcmVhdGUgc2NhbGFyIHZlY3RvcnMgd2l0aCBzb21lIHJ1bGVzLiANCg0KMS4gVG8gY3JlYXRlIGNvbnRpbnVvdXMgaW50ZWdlciBudW1iZXJzIHlvdSBjYW4gdXNlIGA6YCB3aXRoaW4gYGMoKWAgZnVuY3Rpb24uIEZvciBleGFtcGxlLCBgYygxOjEwKWAgcmV0dXJucyBudW1iZXJzIGZyb20gMSB0byAxMC4gIA0KDQoyLiBgc2VxKGZyb20sIHRvLCBieSlgIGNyZWF0ZXMgdmVjdG9yIHdpdGggc2VxdWVuY2Ugb2YgdmFsdWVzLiAiZnJvbSIgZGVmaW5lcyB0aGUgc3RhcnRpbmcgcG9pbnQsICJ0byIgZGVmaW5lcyB0aGUgZW5kaW5nIHBvaW50LCBhbmQgImJ5IiBkZWZpbmVzIHRoZSBzdGVwLiBGb3IgZXhhbXBsZSwgYHNlcShmcm9tPTEsdG89NSxieT0xKWAgY3JlYXRlcyBhIHZlY3RvciBjb250YWluaW5nIDEsMiwzLDQsNS4gDQoNCjMuIGByZXAoeCwgdGltZXMsIGVhY2gpYCBjcmVhdGVzIHZlY3RvciB3aXRoIHZhbHVlcyByZXBlYXRlZC4gIngiIGRlZmluZXMgdGhlIHZlY3RvciB0byBiZSByZXBlYXRlZCwgInRpbWVzIiBkZWZpbmVzIHRoZSBudW1iZXIgb2YgcmVwZXRpdGlvbiBvZiB0aGUgZW50aXJlIHZlY3RvciwgYW5kICJlYWNoIiBkZWZpbmVzIHRoZSBudW1iZXIgb2YgcmVwZXRpdGlvbiBvZiBlYWNoIGVsZW1lbnQgaW4gdGhlIHZlY3Rvci4gRm9yIGV4YW1wbGUsIGByZXAoYygxLDIsMyksdGltZXM9MixlYWNoPTIpYGAgY3JlYXRlcyBhIG5ldyB2ZWN0b3IgY29udGFpbmluZyAxLDEsMiwyLDMsMywxLDEsMiwyLDMsMy4NCg0KYGBge3J9DQojIGdlbmVyYXRlIG51bWJlcnMgZnJvbSAxIHRvIDEwMCB1c2luZyBjKCkNCmMoMToxMDApDQojIGNyZWF0ZSB2ZWN0b3IgYyB3aXRoIHNlcXVlbmNlIG9mIHZhbHVlcyBmcm9tIDEsIHRvIDIwLCBieSAyDQpjIDwtIHNlcShmcm9tPTEsdG89MjAsYnk9MikNCiMgY3JlYXRlIHZlY3RvciBkIHdpdGggdmVjdG9yICgyLDQsNikgcmVwZWF0ZWQgMiB0aW1lcywgd2l0aCBlYWNoIGVsZW1lbnQgcmVwZWF0ZWQgMyB0aW1lcw0KZCA8LSByZXAoYygyLDQsNiksdGltZXM9MixlYWNoPTMpDQpgYGANCg0KIyMjIEFyaXRobWV0aWMgb3BlcmF0aW9ucyB3aXRoIHZlY3RvcnMNCg0KYGBge3J9DQojIE1ha2UgYSBzaW1wbGUgbnVtZXJpYyB2ZWN0b3IgKGUpDQplIDwtIGMoMSwyLDMpDQojIE1ha2UgYW5vdGhlciBvbmUgKGYpDQpmIDwtIGMoNSw3LDkpDQojIE1ha2UgYW5vdGhlciBvbmUgKGcpDQpnIDwtIGMoNSw3LDksMTEpDQojIENoZWNrIHRoZSBFbnZpcm9ubWVudCB0byBzZWUgdGhlIGxlbmd0aCBvZiB0aGUgdmVjdG9ycw0KIyBlIGFuZCBmIGhhdmUgMyBudW1iZXJzLCBnIGhhcyA0IG51bWJlcnMNCmBgYA0KDQpXZSBjYW4gZG8gYXJpdGhtZXRpYyBvcGVyYXRpb25zIG9uIHZlY3RvcnMgdG9vISBJZiB3ZSB3YW50IHRvIGRvIG9wZXJhdGlvbnMgYmV0d2VlbiB0d28gdmVjdG9ycywgdGhleSBtdXN0IGhhdmUgdGhlIHNhbWUgbGVuZ3RoLCBvciBvbmUgaXMgYSBtdWx0aXBsZSBvZiB0aGUgb3RoZXIuIA0KDQpgYGB7cn0NCiMgYWRkcyA2IHRvIGVhY2ggdmFsdWUgaW4gZQ0KZSs2DQojIHNxdWFyaW5nIGVhY2ggdmFsdWUgb2YgZg0KZl4yDQojIGFkZGluZyBlIGFuZCBmIChlYWNoIGNvcnJlc3BvbmRpbmcgdmFsdWUgaW4gdGhlIHNlcXVlbmNlIGlzIHN1bW1lZCkNCmUrZg0KIyBtdWx0aXBseWluZyBlIGFuZCBmIChlYWNoIGNvcnJlc3BvbmRpbmcgdmFsdWUgaW4gdGhlIHNlcXVlbmNlIGlzIG11bHRpcGxpZWQpDQplKmYNCg0KIyBOb3RlOiBJZiB5b3Ugd2FudCB0byBzYXZlIHRoZXNlIHJlc3VsdHMgdG8geW91ciBFbnZpcm9ubWVudCBhcyB2ZWN0b3JzLCB5b3UgbmVlZCB0byBnaXZlIHRoZW0gYSBuYW1lDQpgYGANCg0KYGBge3IgZXZhbD1GQUxTRX0NCiMgTm93LCB0cnkgYWRkaW5nIGUgYW5kIGcsIHdoYXQgaGFwcGVuZWQ/IA0KZStnICMgcmV0dXJucyBXYXJuaW5nOiBsb25nZXIgb2JqZWN0IGxlbmd0aCBpcyBub3QgYSBtdWx0aXBsZSBvZiBzaG9ydGVyIG9iamVjdCBsZW5ndGhbMV0gIDYgIDkgMTIgMTINCmBgYA0KDQojIyMgTG9naWNhbCBvcGVyYXRpb25zIHdpdGggdmVjdG9ycw0KDQpXZSBjYW4gYWxzbyBkbyBsb2dpY2FsIG9wZXJhdGlvbnMgd2l0aCB2ZWN0b3JzLiBGb3IgZXhhbXBsZSwgd2UgY2FuIGV2YWx1YXRlIHdoZXRoZXIgZWFjaCBpdGVtIGluIHRoZSB2ZWN0b3IgaXMgbGFyZ2VyIHRoYW4gMTAgYnkgYHZlY3Rvcl9uYW1lID4gMTBgLiANCg0KYGBge3J9DQojIHJlbWVtYmVyIHRoYXQgd2UgaGF2ZSB2ZWN0b3IgYiB3aGljaCBjb250YWlucyBpbnRlZ2VyIG51bWJlcnMgZnJvbSAxIHRvIDEwDQojIGZpbmQgb3V0IHdoZXRoZXIgZWFjaCBpdGVtIGluIHZlY3RvciBiIGlzIGxhcmdlciB0aGFuIDYNCmIgPiA2DQojIGZpbmQgb3V0IHdoZXRoZXIgZWFjaCBpdGVtIGluIHZlY3RvciBiIGlzIGxhcmdlciB0aGFuIDUgQU5EIHNtYWxsZXIgdGhhbiA4DQpiID4gNSAmIGIgPCA4DQpgYGANCg0KVGhlIGAlaW4lYCBvcGVyYXRpb24gYWxsb3dzIHlvdSB0byBjb21iaW5lIG11bHRpcGxlIE9SIGNvbXBhcmlzb25zIHRvIGNoZWNrIHdoZXRoZXIgZ2l2ZW4gdmFsdWVzIGFyZSBwcmVzZW50IGluIGEgc2V0LiBGb3IgZXhhbXBsZTogWW91IGhhdmUgYSB2ZWN0b3IgdGhhdCBkZXNjcmliZXMgZmF2b3VyaXRlIGxldHRlcnMgYGZhdmUubGV0dGVycyA8LSBjKCdhJywgJ3QnLCAnYScsICdiJywgJ3onKWAuIFRvIGNoZWNrIHdoZXRoZXIgdGhlIGVhY2ggbGV0dGVyIGluIGZhdmUubGV0dGVycyBpcyBvbmUgb2YgJ2EnLCAnYicgb3IgJ2MnLCB5b3UgY2FuIHR5cGU6IGBmYXZlLmxldHRlcnMgJWluJSBjKCdhJywgJ2InLCAnYycpYC4gVGhlIHJlc3VsdHMgd2lsbCBiZSBUUlVFIEZBTFNFIFRSVUUgVFJVRSBGQUxTRSwgaS5lLiwgb25seSB0aGUgMm5kIGxldHRlciAndCcgYW5kIHRoZSA1dGggbGV0dGVyICd6JyBhcmUgbm90IG9uZSBvZiAnYScsICdiJyBvciAnYycuDQoNClRoaXMgaXMgaGVscGZ1bCB3aGVuIHlvdSB3YW50IHRvIGZpbHRlciB5b3VyIHBhcnRpY2lwYW50cyBiYXNlZCBvbiB0aGVpciByZXNwb25zZXMuIEZvciBleGFtcGxlLCBvbmx5IGtlZXAgcGFydGljaXBhbnRzIHdob3NlIGZhdm91cml0ZSBsZXR0ZXIgaXMgb25lIG9mICdhJywgJ2InIG9yICdjJy4gDQoNCmBgYHtyfQ0KIyBmaW5kIG91dCB3aGV0aGVyIGVhY2ggaXRlbSBpbiB2ZWN0b3IgYiBpcyBpbiB0aGUgc2V0IDEsNywxMw0KYiAlaW4lIGMoMSw3LDEzKQ0KIyBmaW5kIG91dCB3aGV0aGVyIGVhY2ggaXRlbSBpbiB2ZWN0b3IgYiBpcyBpbiB0aGUgdmVjdG9yIGENCmIgJWluJSBhDQpgYGANCg0KTm90ZSB0aGF0IGJlY2F1c2UgRkFMU0UgPSAwIGFuZCBUUlVFID0gMSwgd2UgY2FuIGBzdW0oKWAgdGhlIGxvZ2ljYWwgdmVjdG9ycyB0byBmaW5kIG91dCB0aGUgbnVtYmVyIG9mIGl0ZW1zIHRoYXQgc2F0aXNmeSB0aGUgb3BlcmF0aW9uLCBhbmQgdXNlIGBtZWFuKClgIHRvIGZpbmQgb3V0IHRoZSBwcm9wb3J0aW9uIG9mIGl0ZW1zIHRoYXQgc2F0aXNmeSB0aGUgb3BlcmF0aW9uLg0KDQpgYGB7cn0NCiMgZmluZCBvdXQgdGhlIG51bWJlciBvZiBpdGVtcyBpbiB2ZWN0b3IgYiB0aGF0IGFyZSBsYXJnZXIgdGhhbiA2DQpzdW0oYiA+IDYpDQojIGZpbmQgb3V0IHRoZSBudW1iZXIgb2YgaXRlbXMgaW4gdmVjdG9yIGIgdGhhdCBhcmUgaW4gdGhlIHNldCAzLDUsMA0Kc3VtKGIgJWluJSBjKDMsNSwwKSkNCiMgZmluZCBvdXQgdGhlIHByb3BvcnRpb24gb2YgaXRlbXMgaW4gdmVjdG9yIGIgYXJlIGxhcmdlciB0aGFuIDUgQU5EIHNtYWxsZXIgdGhhbiA4DQptZWFuKGIgPiA1ICYgYiA8IDgpDQpgYGANCg0KIyMjIEluZGV4aW5nIGEgdmVjdG9yDQoNCllvdSBjYW4gYXNrIFIgdG8gcmV0dXJuIHRoZSB2YWx1ZXMgb2Ygc3BlY2lmaWMgaXRlbXMgd2l0aGluIHlvdXIgdmVjdG9ycyBieSB0eXBpbmcgdGhlIHZlY3RvciBuYW1lIGZvbGxvd2VkIGJ5IGBbXWAsIGFuZCBwdXQgdGhlIG9yZGVyIG51bWJlciBvZiB0aGUgaXRlbSBpbnRvIGBbXWAuIEZvciBleGFtcGxlLCB0byBnZXQgdGhlIDJuZCBpdGVtIGluIHZlY3RvciBhLCB5b3Ugd3JpdGUgYGFbMl1gLiBUbyByZXR1cm4gbXVsdGlwbGUgaXRlbXMsIHlvdSBjYW4gdXNlIGBjKClgIHRvIGNvbWJpbmUgYWxsIGluZGljZXMgeW91IGFyZSBpbnRlcmVzdGVkIGluLiANCg0KYGBge3J9DQojIHJlbWVtYmVyIHRoYXQgd2UgaGF2ZSB2ZWN0b3IgYiB3aGljaCBjb250YWlucyBpbnRlZ2VyIG51bWJlcnMgZnJvbSAxIHRvIDEwDQojIEdldCB0aGUgM3JkIGl0ZW0gaW4gdmVjdG9yIGINCmJbM10NCiMgR2V0IHRoZSAybmQgYW5kIDR0aCBpdGVtIGluIHZlY3RvciBiDQpiW2MoMiw0KV0NCiMgR2V0IHRoZSAybmQgdG8gOHRoIGl0ZW0gaW4gdmVjdG9yIGINCmJbYygyOjgpXQ0KYGBgDQoNCldlIGNhbiBhbHNvIHVzZSBsb2dpY2FsIG9wZXJhdGlvbnMgaW5zaWRlIGluZGV4aW5nIGBbXWAuIEZvciBleGFtcGxlLCBpZiB3ZSB3YW50IHRvIGtub3cgd2hhdCBpdGVtcyBpbiBhIHZlY3RvciBpcyBzbWFsbGVyIHRoYW4gNSwgd2UgY2FuIHdyaXRlIGB2ZWN0b3JfbmFtZVt2ZWN0b3JfbmFtZSA8IDVdYC4gVGhpcyBpcyBiZWNhdXNlIGB2ZWN0b3JfbmFtZSA8IDVgIHJldHVybnMgYSB2ZWN0b3Igb2YgbG9naWNhbCB2YWx1ZXMgKGkuZS4sIEZBTFNFcyAmIFRSVUVzKSwgYW5kIHRoZW4gaW5kZXhpbmcgYFtdYCB3aWxsIHJldHVybiB0aGUgaXRlbXMgdGhhdCBoYXZlIFRSVUVzLiANCg0KYHdoaWNoKClgIGZ1bmN0aW9uIGNhbiByZXR1cm4gdGhlIGluZGljZXMgd2hlcmUgdGhlIHZhbHVlIGlzIFRSVUUuIFdlIGNhbiB3cml0ZSBgd2hpY2godmVjdG9yX25hbWUgPCA1KWAgdG8gcmV0dXJuIHRoZSBpbmRpY2VzIG9mIG51bWJlcnMgd2hpY2ggaXMgc21hbGxlciB0aGFuIDUuIA0KDQpgYGB7cn0NCiMgZmluZCBvdXQgd2hhdCBpdGVtcyBpbiB2ZWN0b3IgYiBhcmUgc21hbGxlciB0aGFuIDQNCmJbYjw0XQ0KIyBmaW5kIG91dCB3aGF0IGl0ZW1zIGluIHZlY3RvciBiIGFyZSBsYXJnZXIgdGhhbiA0IGJ1dCBzbWFsbGVyIHRoYW4gNg0KYltiPjQgJiBiPDZdDQojIGZpbmQgb3V0IHRoZSBpbmRpY2VzIG9mIGl0ZW1zIGluIHZlY3RvciBiIGFyZSBzbWFsbGVyIHRoYW4gNA0Kd2hpY2goYjw0KSAjIG5vdGUgdGhhdCBiZWNhdXNlIGIgY29udGFpbnMgaW50ZWdlciBudW1iZXJzIGZyb20gMSB0byAxMCwgdGhlIGluZGljZXMgYXJlIHRoZSBzYW1lIGFzIG51bWJlciB2YWx1ZXMuIA0KYGBgDQoNCiMjIERhdGFmcmFtZXMNCg0KVG8gY3JlYXRlIGEgZGF0YWZyYW1lLCB5b3UgbmVlZCB0byBzcGVjaWZ5IGNvbHVtbiBuYW1lcyBhbmQgdmFsdWVzIGluIGVhY2ggY29sdW1uLiBGb3IgZXhhbXBsZSwgbGV0J3MgY3JlYXRlIGEgZGF0YWZyYW1lIGNhbGxlZCBgZGYxYCB3aXRoIHR3byBjb2x1bW5zLCAic2V4IiBhbmQgImFnZSIuIFdlIGhhdmUgMyBtYWxlcyBhbmQgdGhleSBhcmUgOTksIDQ2LCAyMyB5ZWFycyBvbGQsIGFuZCAyIGZlbWFsZXMgYW5kIHRoZXkgYXJlIDU0LCAyMyB5ZWFycyBvbGQuIFVzZSBgZGF0YS5mcmFtZSgpYCBmdW5jdGlvbiwgZWFjaCBhcmd1bWVudCB3aWxsIGJlIGluIHRoZSBmb3JtYXQgImNvbHVtbiBuYW1lID0gYyh2YWx1ZTEsIHZhbHVlMiwgdmFsdWUzLCAuLi4pIiwgZS5nLiwgImFnZSA9IGMoOTksNDYsMjMsNTQsMjMpIi4gDQoNCmBgYHtyfQ0KIyBDcmVhdGUgZGYxIHVzaW5nIHRoZSBkYXRhLmZyYW1lKCkgZnVuY3Rpb24NCmRmMSA8LSBkYXRhLmZyYW1lKHNleCA9IGMoIm1hbGUiLCJtYWxlIiwibWFsZSIsImZlbWFsZSIsImZlbWFsZSIpLCANCiAgICAgICAgICAgICAgICAgIGFnZSA9IGMoOTksNDYsMjMsNTQsMjMpKQ0KIyBOb3cgY2FsbCBvbiB5b3VyIGRhdGFmcmFtZTogd2hhdCBkb2VzIFIgcmV0dXJuPw0KZGYxDQpgYGANCg0KWW91ciBjb2x1bW4vdmVjdG9yIG5hbWVzIGFyZSB5b3VyIHZhcmlhYmxlcywgeW91IGNhbGwgb24gc3BlY2lmaWMgdmFyaWFibGVzIHdpdGhpbiBhIGRhdGFmcmFtZSB3aXRoIHRoZSBkb2xsYXIgc3ltYm9sIGAkYCwgZS5nLiwgYGRmMSRzZXhgICh0aGlzIG1lYW5zIHlvdSBleHRyYWN0IGEgPGI+dmVjdG9yPC9iPiBmcm9tIHRoZSA8Yj5kYXRhZnJhbWU8L2I+ISkuDQoNCmBgYHtyfQ0KIyBFeHRyYWN0IGNvbHVtbiBhZ2UgYW5kIHNleCANCmRmMSRzZXgNCmRmMSRhZ2UNCmBgYA0KDQpUbyBnZXQgY29sdW1uIG5hbWVzLCB5b3UgY2FuIHVzZSBgY29sbmFtZXMoZGF0YWZyYW1lKWAgZnVuY3Rpb24uIFlvdSBjYW4gY2hhbmdlIGEgc3BlY2lmaWVkIGNvbHVtbiBuYW1lIHVzaW5nIGZ1bmN0aW9uIGByZW5hbWUoZGF0YWZyYW1lLCBuZXcgbmFtZSA9IG9sZCBuYW1lKWAgKE5vdGU6IGByZW5hbWUoKWAgaXMgcHJvdmlkZWQgYnkgYHRpZHl2ZXJzZWAgcGFja2FnZS4gUmVtZW1iZXIgdG8gbG9hZCB0aGUgcGFja2FnZSB1c2luZyBgbGlicmFyeSgpYCBmaXJzdCEpLiBBbm90aGVyIG9wdGlvbiBpcyB0byB1c2UgYGNvbG5hbWVzKGRhdGFmcmFtZSkgPC0gYygieHh4IiwgInh4eCIsIC4uLilgIHRvIGNoYW5nZSBBTEwgdGhlIGNvbHVtbiBuYW1lcyBhdCBvbmNlLiANCg0KYGBge3J9DQojbGlicmFyeSh0aWR5dmVyc2UpIGlmIHlvdSBoYXZlbid0DQojIEdldCB0aGUgY29sdW1uIG5hbWVzIG9mIGRmMQ0KY29sbmFtZXMoZGYxKQ0KIyBjaGFuZ2UgY29sdW1uIG5hbWUgInNleCIgdG8gImdlbmRlciIgdXNpbmcgcmVuYW1lKCkNCnJlbmFtZShkZjEsICJnZW5kZXIiID0gInNleCIpDQojIGNoYW5nZSBjb2x1bW4gbmFtZXMgdG8gIkdFTkRFUiIgYW5kICJBR0UiIHVzaW5nIGNvbG5hbWVzKCkNCmNvbG5hbWVzKGRmMSkgPC0gYygiR0VOREVSIiwgIkFHRSIpDQojIGNhbGwgb24gZGYxIHRvIHNlZSB0aGUgY2hhbmdlDQpkZjENCmBgYA0KDQojIyMgRmFjdG9yIHZhcmlhYmxlDQoNCldlIGNhbiBzZXQgdGhlIHNleCBjb2x1bW4gdG8gYSBmYWN0b3IgdmFyaWFibGUgdXNpbmcgYGFzLmZhY3RvcigpYCBmdW5jdGlvbi4gSWYgc2V4IGlzIHNldCB0byBhIGZhY3RvciB2YXJpYWJsZSwgaXQgaXMgY2F0ZWdvcmljYWwgYW5kIG5ldyBvYnNlcnZhdGlvbnMgY2FuIG9ubHkgYmUgb25lIG9mIHRoZSBzcGVjaWZpZWQgbGV2ZWxzLiBUaGUgbGV2ZWxzIGFyZSBieSBkZWZhdWx0IGFycmFuZ2VkIGJ5IGFscGhhYmV0aWNhbCBvcmRlci4gWW91IGNhbiBtYW51YWxseSBzcGVjaWZ5IHRoZSBvcmRlciB1c2luZyBmdW5jdGlvbiBgZmFjdG9yKClgIChubyAiYXMiISkgYW5kIGFyZ3VtZW50IGBsZXZlbHMgPSBjKCJ4eHgiLCAieHh4IiwgLi4uKWAuDQoNCjxiPlJlbWVtYmVyIHlvdSBtdXN0IGdpdmUgdGhlIHJlc3VsdHMgYmFjayB0byB0aGUgb2JqZWN0IHRvIHNhdmUgdGhlIGNoYW5nZSEgPC9iPiBGb3IgZXhhbXBsZSwgYGErMWAgd2lsbCBhZGQgMSB0byB0aGUgbnVtYmVyIHNjYWxhciBgYWAsIGJ1dCB0aGUgdmFsdWUgb2YgYGFgIHdvbid0IGNoYW5nZSwgd2hlcmVhcyBgYSA8LSBhKzFgIHdpbGwgdXBkYXRlIHRoZSB2YWx1ZSBvZiBgYWAuIA0KDQpgYGB7cn0NCiMgVHVybiBHRU5ERVIgY29sdW1uIGludG8gYSBmYWN0b3IgdmFyaWFibGUgdXNpbmcgYXMuZmFjdG9yKCkNCmRmMSRHRU5ERVIgPC0gYXMuZmFjdG9yKGRmMSRHRU5ERVIpDQojIFNldCBtYWxlIHRvIGJlIGxldmVsMSBhbmQgZmVtYWxlIHRvIGJlIGxldmVsMiB1c2luZyBmYWN0b3IoKQ0KZGYxJEdFTkRFUiA8LSBmYWN0b3IoZGYxJEdFTkRFUiwgbGV2ZWxzID0gYygibWFsZSIsICJmZW1hbGUiKSkNCiMgQ2FsbCBvbiB0aGUgR0VOREVSIGNvbHVtbiBhbmQgc2VlIHdoYXQgbGV2ZWxzIGFyZSB0aGVyZSBpbiB0aGUgZmFjdG9yIChoaW50OiB1c2UgdGhlIGRvbGxvciBzeW1ib2wgJCkNCmRmMSRHRU5ERVINCmBgYA0KDQpgYGB7ciBldmFsPUZBTFNFfQ0KIyBBZGQgYSA2dGggb2JzZXJ2YXRpb24gdG8gdGhlIGNvbHVtbi4gQ2FuIHlvdSBhZGQgImZlbWFsZSI/IENhbiB5b3UgYWRkICJvdGhlciI/DQojIGZpcnN0IHdlIGV4dHJhY3QgdGhlIHZlY3RvciBHRU5ERVIgPC0gZGYxJEdFTkRFUg0KIyB0aGVuIHRyeSBHRU5ERVJbNl0gPC0gImZlbWFsZSIgYW5kIHRoZW4gR0VOREVSWzZdIDwtICJvdGhlciIsIFdoYXQgaGFwcGVuZWQ/IA0KR0VOREVSIDwtIGRmMSRHRU5ERVINCkdFTkRFUls2XSA8LSAiZmVtYWxlIiAjIHdvcmtzIGZpbmUNCkdFTkRFUls2XSA8LSAib3RoZXIiICMgcmV0dXJucyBXYXJuaW5nOiBpbnZhbGlkIGZhY3RvciBsZXZlbCwgTkEgZ2VuZXJhdGVkLCAib3RoZXIiIGlzIHJlcGxhY2VkIHdpdGggPE5BPiANCmBgYA0KDQojIyBMZXQncyBwcmFjdGljZSAhDQoNCjEuIENyZWF0ZSBhIHZlY3RvciBmb3IgZWFjaCBvZiB0aGUgY29sdW1ucyBpbiB0aGUgdGFibGUgKHNlZSB0aGUgbGFzdCBzbGlkZSBmb3IgTGFiMSkNCg0KICAgICogVGlwIDE6IHVzZSB0aGUgY29tYmluZSBmdW5jdGlvbiBgYygpYCB0byBjcmVhdGUgdGhlIHZlY3RvcnMNCg0KICAgICogVGlwIDI6IGFzc2lnbiB2ZWN0b3JzIHRvIGNvbHVtbiBuYW1lcywgZS5nLiwgY29sdW1uX25hbWUgPSBjKHZhbHVlMSwgdmFsdWUyLCAuLi4pDQoNCmBgYHtyfQ0KbGFuZ19uYW1lIDwtIGMoJ01hbmRhcmluJywgJ1NwYW5pc2gnLCAnRW5nbGlzaCcsICdIaW5kaScsICdQb3J0dWd1ZXNlJywgJ0JlbmdhbGknLCAnUnVzc2lhbicsICdKYXBhbmVzZScpDQpsYW5nX29yZGVyIDwtIGMoJ1NWTycsICdTVk8nLCAnU1ZPJywgJ1NPVicsICdTVk8nLCAnU09WJywgJ1NWTycsICdTT1YnKQ0KbGFuZ19wb3BMMSA8LSBjKDkyMS4yLCA0NzEuNCwgMzY5LjksIDM0Mi4yLCAyMzIuNCwgMjI4LjcsIDE1My43LCAxMjYuMykNCmxhbmdfcG9wTDIgPC0gYygxOTguNywgNzEuNSwgOTc4LjIsIDI1OC4zLCAyNS4yLCAzOS4wLCAxMDQuMywgMC4xMikNCmxhbmdfaW5kb2V1cm8gPC0gYyhGQUxTRSwgVFJVRSwgVFJVRSwgVFJVRSwgVFJVRSwgVFJVRSwgVFJVRSwgRkFMU0UpDQpgYGANCg0KMi4gQ29tYmluZSB0aGUgdmVjdG9ycyBpbnRvIGEgZGF0YWZyYW1lDQoNCiAgICAqIFRpcCAxOiB1c2UgdGhlIGRhdGFmcmFtZSBmdW5jdGlvbiBgZGF0YS5mcmFtZSgpYCB0byBjcmVhdGUgdGhlIGRhdGFmcmFtZQ0KDQogICAgKiBUaXAgMjogc2F2ZSB0aGUgZGF0YWZyYW1lIHdpdGggdGhlIG5hbWUgbGFuZ19kZg0KDQpgYGB7cn0NCmxhbmdfZGYgPC0gZGF0YS5mcmFtZShsYW5nX25hbWUsIGxhbmdfb3JkZXIsIGxhbmdfcG9wTDEsIGxhbmdfcG9wTDIsbGFuZ19pbmRvZXVybykNCmBgYA0KDQozLiBIYXZlIGEgbG9vayBhdCB0aGUgZGF0YWZyYW1lDQoNCiAgICAqIENhbGwgb24gdGhlIGVudGlyZSBkYXRhZnJhbWUNCg0KICAgICogQ2FsbCBvbiBzcGVjaWZpYyBjb2x1bW5zICh2ZWN0b3JzKSBpbiB5b3VyIGRhdGFmcmFtZQ0KDQogICAgKiBDYWxsIG9uIGFsbCBjb2x1bW4gbmFtZXMNCg0KYGBge3J9DQojIENhbGwgb24gdGhlIGVudGlyZSBkYXRhZnJhbWUNCmxhbmdfZGYNCg0KIyBDYWxsIG9uIHNwZWNpZmljIGNvbHVtbnMgKHZlY3RvcnMpIGluIHlvdXIgZGF0YWZyYW1lDQpsYW5nX2RmJGxhbmdfbmFtZQ0KbGFuZ19kZiRsYW5nX3BvcEwxDQoNCiMgcmV0dXJuIGFsbCBjb2x1bW4gbmFtZXMNCmNvbG5hbWVzKGxhbmdfZGYpDQpgYGANCg0KNC4gVHJ5IGV4ZWN1dGluZyB0aGUgZm9sbG93aW5nIGZ1bmN0aW9ucyBvbiB5b3VyIGRhdGFmcmFtZSBhbmQgc2VlIHdoYXQgdGhlIGZ1bmN0aW9ucyByZXR1cm4uIA0KDQpgYGB7cn0NCiMgaGVhZChkZl9uYW1lKQ0KaGVhZChsYW5nX2RmKSAjIHJldHVybnMgZmlyc3Qgc2V2ZXJhbCByb3dzDQojIHRhaWwoZGZfbmFtZSkNCnRhaWwobGFuZ19kZikgIyByZXR1cm5zIGxhc3Qgc2V2ZXJhbCByb3dzDQojIFZpZXcoZGZfbmFtZSkgTi5CLiB0aGUgJ1YnIGluIFZpZXcgaXMgY2FwaXRhbGlzZWQNClZpZXcobGFuZ19kZikgIyB0aGlzIHdpbGwgb3BlbiBhIG5ldyB0YWIgaW4gdGhlIFNvdXJjZSBwYW5lIGFuZCBzaG93IHRoZSB0YWJsZSBvZiBsYW5nX2RmDQojIG5yb3coZGZfbmFtZSkNCm5yb3cobGFuZ19kZikgIyByZXR1cm5zIHRvdGFsIG51bWJlciBvZiByb3dzDQojIG5jb2woZGZfbmFtZSkNCm5jb2wobGFuZ19kZikgIyByZXR1cm5zIHRvdGFsIG51bWJlciBvZiBjb2x1bW5zDQojIGRpbShkZl9uYW1lKQ0KZGltKGxhbmdfZGYpICMgcmV0dXJucyB0b3RhbCBudW1iZXIgb2Ygcm93cyBhbmQgY29sdW1ucyANCiMgc3VtbWFyeShkZl9uYW1lKQ0Kc3VtbWFyeShsYW5nX2RmKSAjIHJldHVybnMgYSBzdW1tYXJ5IG9mIHZhbHVlcyBpbiBlYWNoIGNvbHVtbg0KIyBXaGF0IGRvIGVhY2ggb2YgdGhlc2UgZnVuY3Rpb25zIGRvPw0KYGBgDQoNCjUuIEluZGV4aW5nIGEgdmVjdG9yIChjb2x1bW4pIGluIGRhdGFmcmFtZQ0KDQpgYGB7cn0NCiMgV2hhdCBpcyB0aGUgTDEgbGFuZ3VhZ2UgcG9wdWxhdGlvbiBvZiB0aGUgZmlyc3QgbGFuZ3VhZ2UgKGllLCBNYW5kYXJpbik/DQpsYW5nX2RmJGxhbmdfcG9wTDFbMV0NCiMgV2hhdCBhcmUgdGhlIHdvcmQgb3JkZXJzIG9mIHRoZSBmaXJzdCA1IGxhbmd1YWdlcz8NCmxhbmdfZGYkbGFuZ19vcmRlclsxOjVdDQojIFdoZXRoZXIgZWFjaCBMMSBsYW5ndWFnZSBwb3B1bGF0aW9uIGFyZSBncmVhdGVyIHRoYW4gMzAwIG1pbGxpb24/DQpsYW5nX2RmJGxhbmdfcG9wTDEgPiAzMDANCiMgV2hldGhlciBlYWNoIGxhbmd1YWdlIG9yZGVycyBhcmUgU1ZPPyANCmxhbmdfZGYkbGFuZ19vcmRlciA9PSAiU1ZPIg0KIyBXaGF0IGFyZSB0aGUgbmFtZXMgb2YgbGFuZ3VhZ2VzIHdpdGggTDIgcG9wdWxhdGlvbiBsb3dlciB0aGFuIDEwMCBtaWxsaW9uPw0KbGFuZ19kZiRsYW5nX25hbWVbbGFuZ19kZiRsYW5nX3BvcEwyIDwgMTAwXQ0KIyBXaGF0IGFyZSB0aGUgbmFtZXMgb2YgbGFuZ3VhZ2VzIHdpdGggU1ZPIG9yZGVyIGFuZCBMMiBsYW5ndWFnZSBwb3B1bGF0aW9uIG1vcmUgdGhhbiAxMDAgbWlsbGlvbj8NCmxhbmdfZGYkbGFuZ19uYW1lW2xhbmdfZGYkbGFuZ19vcmRlciA9PSAiU1ZPIiAmIGxhbmdfZGYkbGFuZ19wb3BMMiA+IDEwMF0NCmBgYA0KDQo2LiBDb3VudGluZyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBzYXRpc2Z5aW5nIGEgc3BlY2lmaWMgY3JpdGVyaWEgDQoNCmBgYHtyfQ0KIyBIb3cgbWFueSBsYW5ndWFnZXMgaGF2ZSBTVk8gb3JkZXI/IFdoYXQgaXMgdGhlIHByb3BvcnRpb24/DQpzdW0obGFuZ19kZiRsYW5nX29yZGVyID09ICJTVk8iKQ0KbWVhbihsYW5nX2RmJGxhbmdfb3JkZXIgPT0gIlNWTyIpDQojIEhvdyBtYW55IGxhbmd1YWdlcyBoYXZlIEwyIHBvcHVsYXRpb24gZ3JlYXRlciB0aGFuIDIwMCBtaWxsaW9uPyBXaGF0IGlzIHRoZSBwcm9wb3J0aW9uPw0Kc3VtKGxhbmdfZGYkbGFuZ19wb3BMMiA+IDIwMCkNCm1lYW4obGFuZ19kZiRsYW5nX3BvcEwyID4gMjAwKQ0KYGBgDQo=