library(tidyverse)
library(pacman)

1 The purpose of this course

  • An introduction to basic techniques in R
  • An interdisciplinary approach to R, e.g. regression modelling for psychologists, and text analysis for digital humanities

2 Why R?

  • Open Source
    • means that analyses are (a) cutting edge and (b) accurate
  • Strong emphasis on reproducible research
    • data are (a) accurately reported (b) shareable

3 How to use an R Markdown file

This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

plot(cars)

Add a new chunk by clicking

  1. CLicking Code -> Insert on toolbar.

2. Add chunk via the command palette

  1. Press Ctrl+Alt+I
  2. Just type out the formatting, e.g. three back ticks, curly brackets containing r, and three more back ticks to finish the block

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to
preview the HTML file).

one <- 1
one

4 RStudio breakdown

4.1 Panes

RStudio shows you four panes:

  1. The ‘Source’ pane: the file where you write your code. This is the code that you will be saving to your computer on a regular basis.
  2. The ‘Console’ where actual code is run. The output is temporary and you do not tend to save this.
  3. The ‘Environment’ pane, which shows you variables / datasets
  4. The ‘Viewer’ pane, which shows you plots, help files and other useful things.

You can arrange these in any order using Tools > Global Options.

4.2 Autocomplete

RStudio has fantastic autocomplete capabilites. To autocomplete just press TAB. This is especially useful when loading files as using autocomplete will help you to identify relevant ones.

5 R basics

5.1 Setting the working directory

R needs to know which folder on your computer you are working in. There are various ways to do this.

5.1.1 The easy way, using the GUI

Within RStudio go to Session >> Set Working Directory > Choose Directory...

You also have an option to set the working directory to the most recently-loaded .R or .Rmd file.

5.1.2 The difficult way, using Code.

To do this type

setwd("path/to/directory")

Unfortunately, if you are on a windows machine you will need to change all backslashes \ to forward slashes /. This is because R follows UNIX conventions which are native to Linux and Mac computers.

If you are not sure what your working directory is type

getwd()

Getting the right path is a vital first step in R, and you really need to know how to do this. Here are some instructional videos if you get stuck…

For Windows computers refer to this YouTube video. For Macs refer to this YouTube video. If you’re on Linux then refer to this YouTube video

However this is a big problem with this approach. If you send your file to someone else who is working on a different machine, it is most likely that your path will be pointing to the wrong location

5.1.3 The difficult way (2) (but by far the best way!)

By far the best way to set the working directory is create an “R Project” in RStudio. When you do this, the RProject keeps track of the directory where the files are stored, so there is no need to set the working directory.

In addition, if you set up a project you can use it to store all the datasets and other data objects which were opened in the last session. This is quite convenient but it can take up a lot of memory, and you also run the risk that you will lose track of how the variables were created, which is a threat to reproducibility.

5.2 Using R as a calculator

We can use the console for general arithmetic


1 + 3 + 5
(2 + 9) / 7

1 + 2+ 3

We can also create variables, e.g.


x <- 10 # This is a comment
x = 10 # Does the same thing!!
y <- 21
x*y

5.3 Comments

If you’d like to comment on any code you write (i.e. you do not wish R to try to ‘run’ this code) just add a hash (#) or series of hashes in front of it, e.g.

df <- read.csv("csv_file.csv") # This reads in the main file for the experiment

It is good practice to make a lot of comments, especially when you are just starting out in R. They will help to you remind you of what the code does, and you could also use them to highlight any difficulties you have had, things you need to be careful about, useful online resources etc.

5.4 Functions

Most work in R is done using Functions. These take the following form: function(argument(s)). Here are some functions


sqrt(10)

seq(1, 10, 2)

rep(5, 10)

5.5 EX 1 & 2: Working with Functions

EX1: What do the arguments of seq and rep do? To find out more search for the relevant help file in the console by typing ?seq or by using Google.

EX2: Have a look at the following arguments called gsub and grepl. What do they do? Clue: if you’re stuck, search the help file using ?


gsub("R-studio", "Rstudio", "R-studio is a great piece of software")

grepl("chocolate", "Mary likes chocolate cookies")

5.6 DIY functions

It’s possible to create your own functions. This makes R extremely powerful and extendible. We’re not going to cover making your own functions in this course, but it’s important to be aware of this capability. There are plenty of good resources online for learning how to do this, including this one

5.7 Getting help

As we have seen above, to find out about a particular function just type ? and the name of the function into the console, e.g. ?grepl. This accesses the help files on your computer. If you’d like to search more broadly type ??grepl and your computer will look online for relevant materials on CRAN (the main R website)

Help files in R are quite densely written and not particularly aimed at beginners. Fortunately there are loads of excellent resources on the internet. Here are some really good sites:

  1. https://www.tidyverse.org/ - A brilliant set of of resources on all things related to the tidyverse, Hadley Wickham’s brilliant suite of packages
  2. https://www.statmethods.net/index.html - a quick way of looking up basic R techniques
  3. https://stats.idre.ucla.edu/r/modules/
  4. https://rseek.org/ - a search engine for all things related to R (because the word ‘R’ brings up a whole load of irrelevant stuff in Google)
  5. http://www.cookbook-r.com/ - this has lots of tips on how to do graphics.

And there are plenty more! If you find a good one share it with your colleagues via email, Twitter, or whatever social media you prefer!

6 Packages

6.1 Installation

To enhance the basic capabilities of R, we need to load packages/libraries. Most of the time, we download these from ‘CRAN’ Tools > Install packages or install.packages(). Once the package/library is installed (i.e. it is sitting somewhere on your computer), we then need to load it to the current R session using the library() function.

Remember using a package/library is a two-stage process. We

  1. Install the package/library onto your computer (from the internet)
  2. Load the package/library into your current session using the library command.

One of the most useful packages is called ‘tidyverse’.

If your first code block is called “settings” then the code for that block will be automatically run when you open the file. So it is useful to load all of your packages in this first block.

One package I always load at the start is the tidyverse

It contains a number of useful commands for plots, and data manipulation.

Note that

Install the ‘tidyverse’ package, and then load it with the following function:

library(tidyverse)

I find that a particularly easy way to load packages is via the p_load function from the pacman library. This will check if the package has been loaded into the current session. If not it will search to find out if the package has been stored in your computer. If the package is not in your computer it will automatically find it. It basically does everything you need! However, we are not going to practise using it, but just to let you know that it exists!

6.2 Obtaining help

To find out more about a package type ?package_name in the console. Alternatively you can look for the package documentation on CRAN.

6.3 Using functions from packages

Most of the functions loaded in a package should work ‘out of the box’. However occasionally you need to refer to the package first, and then the function using the format package_name::function_from_that_package. This is useful for a variety of reasons:

  1. It allows you to use a function from a package without having to load that package
  2. It helps in cases where you load two packages which contain two different functions which happen to have the same name.
  3. Sometimes, even when a package is loaded, you need to precede a function by the package name. (I am not sure why this happens…). However, most of the time this is not necessary.

6.4 EX 3 - Using packages

  1. Install and load the package ggplot2
  2. Look up the function geom_point from this package. What does it do?

7 Objects, data frames and indices

7.1 Objects

A variable is a type of ‘object’ which R stores in memory. R is capable of creating and storing a wide range of objects. To see what type of object we have created, we use the function class(), e.g.


x <- 1

class(x)

z <- "hello"

class(z)

class is one of the most useful functions in R as errors are often due to misassignment of class, e.g.


x + z

Here we have tried to add a number to a string which is clearly impossible. It’s possible to change the class of an object using commands such as as.character, as.integer, as.numeric, as.factor, e.g.

one <- "1"
x + one
one <- as.numeric(one)
x + one 

Here is a list of the main object classes in R:

  1. Numeric - a number with decimal places
  2. Integer - a number without decimal places
  3. Character - a string of letters/numbers
  4. Vector - an ordered list of numbers or characters, or multi-character strings. NB each number, character, or character string is also an object. So you can have objects within objects!
  5. Dataframe - a 2 x 2 array in which each column has a name
  6. List - this is like a vector, except it is capable of storing multiple object classes, e.g. it can contain both numbers and strings.

In order to create a vector we need to use the c function. (c = ‘combine’), e.g.

list.of.numbers <- c(1,4,54,22,43,9,0,0,21)

mean(list.of.numbers)

sd(list.of.numbers)

a.character.vector <- c("Mary", "Jane", "Ali", "Chen")

a.list <- as.list(c(1, 2, "Mary", "Jane"))

7.2 Creating a data frame from scratch

A data frame is a two-dimensional object containing variables and row numbers. It’s basically a spreadsheet.

The following code creates a data frame programmatically. It creates two variables, and combines them together to make a data frame. Note that to do this we need to use the functions as.data.frame and cbind.


list.of.movies <- c("Independence Day", "Pretty Woman", "The Godfather Part
Two", "Planet of the Apes (original)")

rotten.tomatoes.variable <- c(62, 61, 97, 89)

df <- as.data.frame(cbind(list.of.movies, rotten.tomatoes.variable)) # 'cbind' binds columns together

7.3 Viewing the contents of a data frame

To glimpse the top few rows type head(name_of_data_frame) in the console, e.g.

head(df)

To view the data frame in the ‘source’ window, type View(name_of_data_frame) in the console, .e.g.

View(df) #NB first letter is a capital letter.

7.4 Referring to variables

To refer to variables, use the following syntax data_frame_name$variable_name, e.g.

df$list.of.movies

When naming variables we can use dots and underscores, e.g. df$list.of.movies and df$list_of_movies. We can use numbers as long as they don’t come at the beginning, e.g. df$list_of_movies.v3.

If you use this convention, then the names for variables can get very long. However, it’s generally useful, as in R you often have multiple data frames loaded into memory. By specifiying both the name of the data frame and the variable, this avoids confusion.

Try to be consistent with your naming conventions. I tend to use underscores to name variables, e.g. data.frame.x$variable_y. This is also what Hadley Wickham recommends (Have a look at the Tidyverse Style Guide)

If you’d like to see all the variable names in a data frame type names(data_frame), e.g. 

names(df)

7.5 Indices

Whenever you wish to access the contents of an object with multiple values (e.g. a data frame) you use indexes. These are placed inside square brackets, e.g. [1]. Have a look at the following example:


vector = c(1, 4, 2, 99, 0.5, 10)

vector[1]

vector[2]

vector[5]

vector[2:5]

mean(vector[2:5])

Here is how we would use vectors with a datafrome

df[1,2]

df[1,] # here the second number is blank

df[,2] # here the first number is blank

7.6 EX 3 - understanding indices

What does each number refer to? What happens when we leave a blank cell?

7.7 Reading data frames from files using menus

We can use the menu in Rstudio: File > Import dataset. You can do this to import Excel, SPSS, SAS and STATA files.

7.8 Reading data frames from files using code

However, rather than use the menu, it’s much better to use actual code, as this will automate the process. Let’s import a dataset on World Happiness Report (2017), by country. The files are WHR_2017.xlsx, WHR_2017.sav, and WHR_2017.csv. Alternatively you can actually download the data set straight from the URL (below)


# This code depends on using the `tidyverse` and `haven` packages
# If you have not imported / loaded them, you need to so
# library(tidyverse)
# library(haven)

df <- readxl::read_excel("WHR_2017.xlsx") # Read an excel file

df <- haven::read_spss("WHR_2017.sav") # Read from an SPSS file

df <- read_csv("WHR_2017.csv") # Read from a .csv file

#Or to download straight from the URL!!

df <- read_csv("https://verbingnouns.github.io/AdventuresInR/docs/WHR_2017.csv")

Possibly the best data format to work in is the .csv data format (Comma-Separated Value). This is good because it is readable in Excel, small, simple, and not easily-corrupted. It’s only disadvantage is that it does not support Excel formulas or formatting (NB some would say this is an advantage as Excel formulae are not that reliability and not very consistent with scientific reproducibility)

To read .csv files we use the read.csv() function from base R, or read_csv() from the tidyverse (I would go with the latter as it also shows you a list of the variable types)

8 Subsetting a data set using (a) base R and (d) dplyr

8.1 Subsetting with base R

We’re going to subset the WHR dataset (i.e. choose only those cases/observations which fulfil a specific criterion). To do this we’re going to use the which() function. When you apply which to a variable in a dataset, it will produce indices (indexes) of the rows which fulfil a certain criterion, e.g. which(df$var_name == 2) will give you the indices of all rows where the value of the variable is 2.

8.2 EX4: Subsetting using base R

Armed with this knowledge, your task is to subset the data frame so that it only contains information from African countries.

If you’re stuck have a look at the answer below.

df.Africa <- df[which(df$region == "Africa"), ]

8.3 Piping

Okay, the above code is pretty horrible, so we’re going to explore an alternative using the package dplyr which is from the tidyverse. But before we can use dplyr we have to learn how to ‘pipe’.

Pipes are written in R as %>% (note you must use a percentage sign before and after the pipe). To demonstrate what pipes do, I have a look at the following pseudocode.

All pipes do is enable us to ‘pass’ a data frame (or another object) to a new function without having to keep on specifying the data frame. In addition, we can chain pipes together indefinitely.

Here’s how we would subset the data frame using piping:


df.Africa <- filter(df, region == "Africa") # This is the version without piping

df %>% filter(region == "Africa") -> df.Africa # This is the version with piping. It looks longer, but we can chain multiple functions together!

Note that to create a new data frame, we need a solid arrow at the end. If we don’t include that solid arrow, the results are shown in the console, but no new data frame is created. This is an incredibly useful feature of pipes. You can try before you buy!

And here is an example where we chain a series of pipes together:


df %>% 
  group_by(region) %>%
  summarise(mean.happiness = mean(happiness_score)) ->
  df.mean.happiness.by.region

NB When piping the code becomes more readable when the line ends with the pipe.

There are a couple of important points to note.

  1. We can refer to variables without specifying the data frame
  2. If we wish to store the results we must output them using and arrow ->. If we don’t store the results they will merely be displayed in the console.

Piping is a key technique in R and once you’ve learnt it you will write much more powerful and readable code.

As well as using pipes to create data frame, you can also insert pipes into both analyses and figures! Here is an example of a pipe inserted within an ANOVA.


# An ANOVA without a pipe. NB we are using the base function "aov". If you would like to conduct SPSS-style ANOVAs, the best package is called "afex".

mod <- aov(happiness_rank ~ region, data = df)

pacman::p_load(broom) # To load the "tidy" function.

tidy(mod)

# Here we use a pipe inside the analysis
mod <- aov(happiness_rank ~ region, # NB note we can break the line after a comma
           data = df %>% filter(region == "Africa" | region == "South America"))

tidy(mod)

Note how I have broken some of the lines after a comma. This makes the code more readable. Generally we can break a line when it ends in some kind of symbol, e.g. a pipe, an arrow, or a comma.

9 Loops and if-then statements

Loops and if-then statements are useful programming tools which have the same structure: FUNCTION (STATEMENT) {.....}.

9.1 Loops

for(i in 1:10){
  print(as.character(i))
}

9.2 EX5: Loops

The code below creates a sequence ranging from 0 to 30 going up in steps of 0.25. Try to achieve the same result using a loop

seq(0,30,2.5)

9.3 If-then statements

To demonstrate if-then statements, we are going to create a new variable which shows if the happiness index is above the mean

df$happiness_above_mean <- 0 # Set variable to 0
mean_happiness <- mean(df$happiness_score) # Calculate mean mpg
for (i in 1:nrow(df)){
  if(df$happiness_score[i] > mean_happiness){
    df$happiness_above_mean[i] <- 1
    }
}

And here is the same process using dplyr, which avoids the loop and the if-then statement.


df %>%
  mutate(happiness_above_mean = as.numeric(happiness_score > mean(happiness_score))) ->
  df

Note loops and if-then statements are quite verbose, and there is almost always a neater and much shorter alternatives. However, I think they are useful procedures for the relative beginner.

Here is the way to create the variable without using the tidyverse


df <- read_csv("WHR_2017.csv")

df$happiness_above_mean <- as.numeric(df$happiness_score > mean(df$happiness_score))

So how does this work? The statement in brackets evaluates to TRUE / FALSE. We then turn this into a number using as.numeric. TRUE evaluates to 1, while FALSE evaluates to 0.

It can be quite useful to chain statements. For example, if we wish to identify countries where both the happiness score and life expectancy are above the mean, we could do this….

df$happiness_and_LE_above_mean <- as.numeric((df$happiness_score > mean(df$happiness_score)) & (df$life_expectancy > mean(df$life_expectancy)))

## EX6: Creating variables

Try to identify countries where both the GDP per capita and trust in the government are above the mean.

10 Stored results

Whenever you run an analysis in R and save that to an object, the object has an internal structure. To demonstrate this, let’s do a simple regression using the mtcars dataset:


df <- read.csv("WHR_2017.csv")

head(df)

Let’s draw a plot looking at the relationship between GDP per capita and Happiness Score. We’re not going to focus on the code, which will be covered in the next session.

g <- ggplot(aes(x = df$gdp_per_capita, y = df$happiness_score), data = df)
g <- g + geom_point()
g <- g + geom_smooth()
g

Now let’s run a regression. Again, we’re not going going to focus on the code, which will be covered in the final session.


mod <- lm(happiness_score ~ gdp_per_capita, data = df) # mod = "model"

pacman::p_load(broom) # Broom is a package which produces neat tables of results

tidy(mod) # This is a broom function which tidies up the statistical results for reporting

Now, let’s have a look at the structure of this model. There are two ways to do this:

  1. Use the str function, e.g. str(mod)
  2. Type mod$, and then use autocomplete.

We can see that the $ symbol has a dual function in R: firstly, to specify variables within dataframes, and secondly to specify subcomponents of an object.

It is useful to be able to refer to subcomponents of an object so that we can integrate into our report, e.g. the regression yielded a value of

10.1 EX 6: Let’s put it all together!!!

  1. Download the data for life expectancy by country
  2. The data covers many years. Select the most recent year.
  3. Merge the data with the “WHR” data (you will need to merge using the “country” variable)
  4. Draw plots of (a) life expectancy against GDP per capita, (b) life expectancy against family values

Once you get stuck have a look at the first code chunk below. This contains the solution but with pesky errors added! See if you can sort out the errors.

whr <- read_csv("WHR_2017.csv")

le <- read_csv("WHO_life_expectancy.csv")

whr %>% # NB we need to ensure that the "country" variable has exactly the same name in both datasets
  rename(country = Country) ->
  whr

le %>% 
  filter(Year == 2015) %>% 
  merge(whr) %>% doc
  df

plot(df$`Life expectancy`, df$GDP)
plot(df$`Life expectancy`, df$family)

The code in this chunk shows the solution!


whr <- read_csv("WHR_2017.csv")

le <- read_csv("WHO_life_expectancy.csv")

whr %>% 
  rename(Country = country) ->
  whr

le %>% 
  filter(Year == 2015) %>% 
  merge(whr) ->
  df

plot(df$`Life expectancy`, df$GDP)
plot(df$`Life expectancy`, df$family)
LS0tCnRpdGxlOiAiU2Vzc2lvbiAxIC0gSW50cm9kdWN0aW9uLlJtZCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMicKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6CiAgICBkZl9wcmludDogcGFnZWQKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogbm8KLS0tCgpgYGB7ciBzZXR0aW5nc30KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocGFjbWFuKQpgYGAKCgoKIyBUaGUgcHVycG9zZSBvZiB0aGlzIGNvdXJzZQoKLSBBbiBpbnRyb2R1Y3Rpb24gdG8gYmFzaWMgdGVjaG5pcXVlcyBpbiBSCiFbXShpbWFnZXMvY3Jhd2wtd2Fsay1ydW4tZmx5LnBuZykKLSBBbiBpbnRlcmRpc2NpcGxpbmFyeSBhcHByb2FjaCB0byBSLCBlLmcuIHJlZ3Jlc3Npb24gbW9kZWxsaW5nIGZvciBwc3ljaG9sb2dpc3RzLCBhbmQgdGV4dCBhbmFseXNpcyBmb3IgZGlnaXRhbCBodW1hbml0aWVzCgojIFdoeSBSPwoKLSAqT3BlbiBTb3VyY2UqCiAgLSBtZWFucyB0aGF0IGFuYWx5c2VzIGFyZSAoYSkgY3V0dGluZyBlZGdlIGFuZCAoYikgYWNjdXJhdGUKLSAqU3Ryb25nIGVtcGhhc2lzIG9uIHJlcHJvZHVjaWJsZSByZXNlYXJjaCoKICAtIGRhdGEgYXJlIChhKSBhY2N1cmF0ZWx5IHJlcG9ydGVkIChiKSBzaGFyZWFibGUKCiMgSG93IHRvIHVzZSBhbiBSIE1hcmtkb3duIGZpbGUKClRoaXMgaXMgYW4gW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pIE5vdGVib29rLiBXaGVuIHlvdSBleGVjdXRlIGNvZGUgd2l0aGluIHRoZSBub3RlYm9vaywgdGhlIHJlc3VsdHMgYXBwZWFyIGJlbmVhdGggdGhlIGNvZGUuCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5CnBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ3RybCtTaGlmdCtFbnRlciouCgoKCmBgYHtyIHBsb3QgY2Fyc30KcGxvdChjYXJzKQpgYGAKCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZwoKMS4gQ0xpY2tpbmcgQ29kZSAtPiBJbnNlcnQgb24gdG9vbGJhci4KCiFbXShpbWFnZXMvYWRkX2NvZGVfYmxvY2tfdmlhX21lbnUucG5nKQoyLiBBZGQgY2h1bmsgdmlhIHRoZSBjb21tYW5kIHBhbGV0dGUKCiFbXShpbWFnZXMvaW5zZXJ0X2NodW5rX3ZpYV9jb21tYW5kX3BhbGV0dGUucG5nKQoKMy4gUHJlc3MgKkN0cmwrQWx0K0kqCjQuIEp1c3QgdHlwZSBvdXQgdGhlIGZvcm1hdHRpbmcsIGUuZy4gdGhyZWUgYmFjayB0aWNrcywgY3VybHkgYnJhY2tldHMgY29udGFpbmluZyBgcmAsIGFuZCB0aHJlZSBtb3JlIGJhY2sgdGlja3MgdG8gZmluaXNoIHRoZSBibG9jawoKCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ3RybCtTaGlmdCtLKiB0byAgICAKcHJldmlldyB0aGUgSFRNTCBmaWxlKS4KCmBgYHtyIGFzc2lnbiB2YWx1ZXMgdG8gYSB2YXJpYWJsZX0Kb25lIDwtIDEKb25lCmBgYAoKCiMgUlN0dWRpbyBicmVha2Rvd24KCiMjIFBhbmVzCgpSU3R1ZGlvIHNob3dzIHlvdSBmb3VyIHBhbmVzOgoKMS4gVGhlICdTb3VyY2UnIHBhbmU6IHRoZSBmaWxlIHdoZXJlIHlvdSB3cml0ZSB5b3VyIGNvZGUuIFRoaXMgaXMgdGhlIGNvZGUgdGhhdCB5b3Ugd2lsbCBiZSBzYXZpbmcgdG8geW91ciBjb21wdXRlciBvbiBhIHJlZ3VsYXIgYmFzaXMuCjIuIFRoZSAnQ29uc29sZScgd2hlcmUgYWN0dWFsIGNvZGUgaXMgcnVuLiBUaGUgb3V0cHV0IGlzIHRlbXBvcmFyeSBhbmQgeW91IGRvIG5vdCB0ZW5kIHRvIHNhdmUgdGhpcy4KMy4gVGhlICdFbnZpcm9ubWVudCcgcGFuZSwgd2hpY2ggc2hvd3MgeW91IHZhcmlhYmxlcyAvIGRhdGFzZXRzCjMuIFRoZSAnVmlld2VyJyBwYW5lLCB3aGljaCBzaG93cyB5b3UgcGxvdHMsIGhlbHAgZmlsZXMgYW5kIG90aGVyIHVzZWZ1bCB0aGluZ3MuCgohW10oaW1hZ2VzL2NvbnNvbGVfZXRjLnBuZykKCgpZb3UgY2FuIGFycmFuZ2UgdGhlc2UgaW4gYW55IG9yZGVyIHVzaW5nIFRvb2xzID4gR2xvYmFsIE9wdGlvbnMuCgohW10oaW1hZ2VzL3BhbmVzLnBuZykKCgojIyBBdXRvY29tcGxldGUKClJTdHVkaW8gaGFzIGZhbnRhc3RpYyBhdXRvY29tcGxldGUgY2FwYWJpbGl0ZXMuIFRvIGF1dG9jb21wbGV0ZSBqdXN0IHByZXNzIFRBQi4gVGhpcyBpcyBlc3BlY2lhbGx5IHVzZWZ1bCB3aGVuIGxvYWRpbmcgZmlsZXMgYXMgdXNpbmcgYXV0b2NvbXBsZXRlIHdpbGwgaGVscCB5b3UgdG8gaWRlbnRpZnkgcmVsZXZhbnQgb25lcy4KCiMgUiBiYXNpY3MKCiMjIFNldHRpbmcgdGhlIHdvcmtpbmcgZGlyZWN0b3J5CgpSIG5lZWRzIHRvIGtub3cgd2hpY2ggZm9sZGVyIG9uIHlvdXIgY29tcHV0ZXIgeW91IGFyZSB3b3JraW5nIGluLiBUaGVyZSBhcmUgdmFyaW91cyB3YXlzIHRvIGRvIHRoaXMuCgojIyMgVGhlIGVhc3kgd2F5LCB1c2luZyB0aGUgR1VJCgpXaXRoaW4gYFJTdHVkaW8gZ28gdG8gU2Vzc2lvbiA+PiBTZXQgV29ya2luZyBEaXJlY3RvcnkgPiBDaG9vc2UgRGlyZWN0b3J5Li4uYAoKIVtdKHNldHdkLnBuZykKCllvdSBhbHNvIGhhdmUgYW4gb3B0aW9uIHRvIHNldCB0aGUgd29ya2luZyBkaXJlY3RvcnkgdG8gdGhlIG1vc3QgcmVjZW50bHktbG9hZGVkIC5SIG9yIC5SbWQgZmlsZS4KCiMjIyBUaGUgZGlmZmljdWx0IHdheSwgdXNpbmcgQ29kZS4KClRvIGRvIHRoaXMgdHlwZQoKYHNldHdkKCJwYXRoL3RvL2RpcmVjdG9yeSIpYAoKVW5mb3J0dW5hdGVseSwgaWYgeW91IGFyZSBvbiBhIHdpbmRvd3MgbWFjaGluZSB5b3Ugd2lsbCBuZWVkIHRvIGNoYW5nZSBhbGwKYmFja3NsYXNoZXMgYFxgIHRvIGZvcndhcmQgc2xhc2hlcyBgL2AuIFRoaXMgaXMgYmVjYXVzZSBSIGZvbGxvd3MgVU5JWCBjb252ZW50aW9ucyB3aGljaCBhcmUgbmF0aXZlIHRvIExpbnV4IGFuZCBNYWMgY29tcHV0ZXJzLgoKSWYgeW91IGFyZSBub3Qgc3VyZSB3aGF0IHlvdXIgd29ya2luZyBkaXJlY3RvcnkgaXMgdHlwZQoKYGdldHdkKClgCgpHZXR0aW5nIHRoZSByaWdodCBwYXRoIGlzIGEgdml0YWwgZmlyc3Qgc3RlcCBpbiBSLCBhbmQgeW91IHJlYWxseSBuZWVkIHRvIGtub3cgaG93IHRvIGRvIHRoaXMuIEhlcmUgYXJlIHNvbWUgaW5zdHJ1Y3Rpb25hbCB2aWRlb3MgaWYgeW91IGdldCBzdHVjay4uLgoKRm9yIFdpbmRvd3MgY29tcHV0ZXJzIHJlZmVyIHRvIFt0aGlzIFlvdVR1YmUgdmlkZW9dKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9UXpTVjh3dkExRG8pLiBGb3IgTWFjcyByZWZlciB0byBbdGhpcyBZb3VUdWJlIHZpZGVvXShodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PTQzVzlUdVB3cWFjKS4gSWYgeW91J3JlIG9uIExpbnV4IHRoZW4gcmVmZXIgdG8gW3RoaXMgWW91VHViZSB2aWRlb10oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1kUXc0dzlXZ1hjUSkKCkhvd2V2ZXIgdGhpcyBpcyBhIGJpZyBwcm9ibGVtIHdpdGggdGhpcyBhcHByb2FjaC4gSWYgeW91IHNlbmQgeW91ciBmaWxlIHRvIHNvbWVvbmUgZWxzZSB3aG8gaXMgd29ya2luZyBvbiBhIGRpZmZlcmVudCBtYWNoaW5lLCBpdCBpcyBtb3N0IGxpa2VseSB0aGF0IHlvdXIgcGF0aCB3aWxsIGJlIHBvaW50aW5nIHRvIHRoZSB3cm9uZyBsb2NhdGlvbgoKIyMjIFRoZSBkaWZmaWN1bHQgd2F5ICgyKSAoYnV0IGJ5IGZhciB0aGUgYmVzdCB3YXkhKQoKQnkgZmFyIHRoZSBiZXN0IHdheSB0byBzZXQgdGhlIHdvcmtpbmcgZGlyZWN0b3J5IGlzIGNyZWF0ZSBhbiAiUiBQcm9qZWN0IiBpbiBSU3R1ZGlvLiBXaGVuIHlvdSBkbyB0aGlzLCB0aGUgUlByb2plY3Qga2VlcHMgdHJhY2sgb2YgdGhlIGRpcmVjdG9yeSB3aGVyZSB0aGUgZmlsZXMgYXJlIHN0b3JlZCwgc28gdGhlcmUgaXMgbm8gbmVlZCB0byBzZXQgdGhlIHdvcmtpbmcgZGlyZWN0b3J5LgoKSW4gYWRkaXRpb24sIGlmIHlvdSBzZXQgdXAgYSBwcm9qZWN0IHlvdSBjYW4gdXNlIGl0IHRvIHN0b3JlIGFsbCB0aGUgZGF0YXNldHMgYW5kIG90aGVyIGRhdGEgb2JqZWN0cyB3aGljaCB3ZXJlIG9wZW5lZCBpbiB0aGUgbGFzdCBzZXNzaW9uLiBUaGlzIGlzIHF1aXRlIGNvbnZlbmllbnQgYnV0IGl0IGNhbiB0YWtlIHVwIGEgbG90IG9mIG1lbW9yeSwgYW5kIHlvdSBhbHNvIHJ1biB0aGUgcmlzayB0aGF0IHlvdSB3aWxsIGxvc2UgdHJhY2sgb2YgaG93IHRoZSB2YXJpYWJsZXMgd2VyZSBjcmVhdGVkLCB3aGljaCBpcyBhIHRocmVhdCB0byByZXByb2R1Y2liaWxpdHkuCgojIyBVc2luZyBSIGFzIGEgY2FsY3VsYXRvcgoKV2UgY2FuIHVzZSB0aGUgY29uc29sZSBmb3IgZ2VuZXJhbCBhcml0aG1ldGljCgpgYGB7ciBzaW1wbGUgbWF0aHN9CgoxICsgMyArIDUKKDIgKyA5KSAvIDcKCjEgKyAyKyAzCgpgYGAKCldlIGNhbiBhbHNvIGNyZWF0ZSB2YXJpYWJsZXMsIGUuZy4KCmBgYHtyIGNyZWF0aW5nIHZhcmlhYmxlc30KCnggPC0gMTAgIyBUaGlzIGlzIGEgY29tbWVudAp4ID0gMTAgIyBEb2VzIHRoZSBzYW1lIHRoaW5nISEKeSA8LSAyMQp4KnkKCmBgYAoKCgojIyBDb21tZW50cwoKSWYgeW91J2QgbGlrZSB0byBjb21tZW50IG9uIGFueSBjb2RlIHlvdSB3cml0ZSAoaS5lLiB5b3UgZG8gbm90IHdpc2ggUiB0byB0cnkgdG8gJ3J1bicgdGhpcyBjb2RlKSBqdXN0IGFkZCBhIGhhc2ggKGAjYCkgb3Igc2VyaWVzIG9mIGhhc2hlcyBpbiBmcm9udCBvZiBpdCwgZS5nLgoKYGRmIDwtIHJlYWQuY3N2KCJjc3ZfZmlsZS5jc3YiKSAjIFRoaXMgcmVhZHMgaW4gdGhlIG1haW4gZmlsZSBmb3IgdGhlIGV4cGVyaW1lbnRgCgpJdCBpcyBnb29kIHByYWN0aWNlIHRvIG1ha2UgYSBsb3Qgb2YgY29tbWVudHMsIGVzcGVjaWFsbHkgd2hlbiB5b3UgYXJlIGp1c3Qgc3RhcnRpbmcgb3V0IGluIFIuIFRoZXkgd2lsbCBoZWxwIHRvIHlvdSByZW1pbmQgeW91IG9mIHdoYXQgdGhlIGNvZGUgZG9lcywgYW5kIHlvdSBjb3VsZCBhbHNvIHVzZSB0aGVtIHRvIGhpZ2hsaWdodCBhbnkgZGlmZmljdWx0aWVzIHlvdSBoYXZlIGhhZCwgdGhpbmdzIHlvdSBuZWVkIHRvIGJlIGNhcmVmdWwgYWJvdXQsIHVzZWZ1bCBvbmxpbmUgcmVzb3VyY2VzIGV0Yy4KCiFbXShpbWFnZXMvY29tbWVudHNfY2FydG9vbi5wbmcpCgojIyBGdW5jdGlvbnMKCk1vc3Qgd29yayBpbiBSIGlzIGRvbmUgdXNpbmcgX0Z1bmN0aW9uc18uIFRoZXNlIHRha2UgdGhlIGZvbGxvd2luZyBmb3JtOgpfZnVuY3Rpb24oYXJndW1lbnQocykpXy4gSGVyZSBhcmUgc29tZSBmdW5jdGlvbnMKCmBgYHtyIGV4YW1wbGVzIG9mIGZ1bmN0aW9uc30KCnNxcnQoMTApCgpzZXEoMSwgMTAsIDIpCgpyZXAoNSwgMTApCgpgYGAKCiMjIEVYIDEgJiAyOiBXb3JraW5nIHdpdGggRnVuY3Rpb25zCgpFWDE6IFdoYXQgZG8gdGhlIGFyZ3VtZW50cyBvZiBgc2VxYCBhbmQgYHJlcGAgZG8/IFRvIGZpbmQgb3V0IG1vcmUgc2VhcmNoIGZvciB0aGUgcmVsZXZhbnQgaGVscCBmaWxlIGluIHRoZSBjb25zb2xlIGJ5IHR5cGluZyBgP3NlcWAgb3IgYnkgdXNpbmcgR29vZ2xlLgoKRVgyOiBIYXZlIGEgbG9vayBhdCB0aGUgZm9sbG93aW5nIGFyZ3VtZW50cyBjYWxsZWQgYGdzdWJgIGFuZCBgZ3JlcGxgLiBXaGF0IGRvIHRoZXkgZG8/IENsdWU6IGlmIHlvdSdyZSBzdHVjaywgc2VhcmNoIHRoZSBoZWxwIGZpbGUgdXNpbmcgYD9gCmBgYHtyfQoKZ3N1YigiUi1zdHVkaW8iLCAiUnN0dWRpbyIsICJSLXN0dWRpbyBpcyBhIGdyZWF0IHBpZWNlIG9mIHNvZnR3YXJlIikKCmdyZXBsKCJjaG9jb2xhdGUiLCAiTWFyeSBsaWtlcyBjaG9jb2xhdGUgY29va2llcyIpCgpgYGAKCgojIyBESVkgZnVuY3Rpb25zCgpJdCdzIHBvc3NpYmxlIHRvICoqY3JlYXRlIHlvdXIgb3duIGZ1bmN0aW9ucyoqLiBUaGlzIG1ha2VzIFIgZXh0cmVtZWx5IHBvd2VyZnVsIGFuZCBleHRlbmRpYmxlLiBXZSdyZSBub3QgZ29pbmcgdG8gY292ZXIgbWFraW5nIHlvdXIgb3duIGZ1bmN0aW9ucyBpbiB0aGlzIGNvdXJzZSwgYnV0IGl0J3MgaW1wb3J0YW50IHRvIGJlIGF3YXJlIG9mIHRoaXMgY2FwYWJpbGl0eS4gVGhlcmUgYXJlIHBsZW50eSBvZiBnb29kIHJlc291cmNlcyBvbmxpbmUgZm9yIGxlYXJuaW5nIGhvdyB0byBkbyB0aGlzLCBpbmNsdWRpbmcgW3RoaXMgb25lXShodHRwczovL3d3dy5zdGF0bWV0aG9kcy5uZXQvbWFuYWdlbWVudC91c2VyZnVuY3Rpb25zLmh0bWwpCgojIyBHZXR0aW5nIGhlbHAKCkFzIHdlIGhhdmUgc2VlbiBhYm92ZSwgdG8gZmluZCBvdXQgYWJvdXQgYSBwYXJ0aWN1bGFyIGZ1bmN0aW9uIGp1c3QgdHlwZSBgP2AgYW5kIHRoZSBuYW1lIG9mIHRoZSBmdW5jdGlvbiBpbnRvIHRoZSBjb25zb2xlLCBlLmcuIGA/Z3JlcGxgLiBUaGlzIGFjY2Vzc2VzIHRoZSBoZWxwIGZpbGVzIG9uIHlvdXIgY29tcHV0ZXIuIElmIHlvdSdkIGxpa2UgdG8gc2VhcmNoIG1vcmUgYnJvYWRseSB0eXBlIGA/P2dyZXBsYCBhbmQgeW91ciBjb21wdXRlciB3aWxsIGxvb2sgb25saW5lIGZvciByZWxldmFudCBtYXRlcmlhbHMgb24gQ1JBTiAodGhlIG1haW4gUiB3ZWJzaXRlKQoKSGVscCBmaWxlcyBpbiBSIGFyZSBxdWl0ZSBkZW5zZWx5IHdyaXR0ZW4gYW5kIG5vdCBwYXJ0aWN1bGFybHkgYWltZWQgYXQgYmVnaW5uZXJzLiBGb3J0dW5hdGVseSB0aGVyZSBhcmUgbG9hZHMgb2YgZXhjZWxsZW50IHJlc291cmNlcyBvbiB0aGUgaW50ZXJuZXQuIEhlcmUgYXJlIHNvbWUgcmVhbGx5IGdvb2Qgc2l0ZXM6CgooYSkgW2h0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvXShodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLykgLSBBIGJyaWxsaWFudCBzZXQgb2Ygb2YgcmVzb3VyY2VzIG9uIGFsbCB0aGluZ3MgcmVsYXRlZCB0byB0aGUgdGlkeXZlcnNlLCBIYWRsZXkgV2lja2hhbSdzIGJyaWxsaWFudCBzdWl0ZSBvZiBwYWNrYWdlcwooYikgW2h0dHBzOi8vd3d3LnN0YXRtZXRob2RzLm5ldC9pbmRleC5odG1sXShodHRwczovL3d3dy5zdGF0bWV0aG9kcy5uZXQvaW5kZXguaHRtbCkgLSBhIHF1aWNrIHdheSBvZiBsb29raW5nIHVwIGJhc2ljIFIgdGVjaG5pcXVlcwooYykgW2h0dHBzOi8vc3RhdHMuaWRyZS51Y2xhLmVkdS9yL21vZHVsZXMvXShodHRwczovL3N0YXRzLmlkcmUudWNsYS5lZHUvci9tb2R1bGVzLykKKGQpIFtodHRwczovL3JzZWVrLm9yZy9dKGh0dHBzOi8vcnNlZWsub3JnLykgLSBhIHNlYXJjaCBlbmdpbmUgZm9yIGFsbCB0aGluZ3MgcmVsYXRlZCB0byBSIChiZWNhdXNlIHRoZSB3b3JkICdSJyBicmluZ3MgdXAgYSB3aG9sZSBsb2FkIG9mIGlycmVsZXZhbnQgc3R1ZmYgaW4gR29vZ2xlKQooZSkgW2h0dHA6Ly93d3cuY29va2Jvb2stci5jb20vXShodHRwOi8vd3d3LmNvb2tib29rLXIuY29tLykgLSB0aGlzIGhhcyBsb3RzIG9mIHRpcHMgb24gaG93IHRvIGRvIGdyYXBoaWNzLgoKQW5kIHRoZXJlIGFyZSBwbGVudHkgbW9yZSEgSWYgeW91IGZpbmQgYSBnb29kIG9uZSBzaGFyZSBpdCB3aXRoIHlvdXIgY29sbGVhZ3VlcyB2aWEgZW1haWwsIFR3aXR0ZXIsIG9yIHdoYXRldmVyIHNvY2lhbCBtZWRpYSB5b3UgcHJlZmVyIQoKIyBQYWNrYWdlcwoKIyMgSW5zdGFsbGF0aW9uCgpUbyBlbmhhbmNlIHRoZSBiYXNpYyBjYXBhYmlsaXRpZXMgb2YgUiwgd2UgbmVlZCB0byBsb2FkIHBhY2thZ2VzL2xpYnJhcmllcy4gTW9zdCBvZiB0aGUKdGltZSwgd2UgZG93bmxvYWQgdGhlc2UgZnJvbSAnQ1JBTicgYFRvb2xzID4gSW5zdGFsbCBwYWNrYWdlc2Agb3IgYGluc3RhbGwucGFja2FnZXMoKWAuIE9uY2UgdGhlIHBhY2thZ2UvbGlicmFyeSBpcyBpbnN0YWxsZWQgKGkuZS4gaXQgaXMgc2l0dGluZyBzb21ld2hlcmUgb24geW91ciBjb21wdXRlciksIHdlIHRoZW4gbmVlZCB0byBfbG9hZF8gaXQgdG8gdGhlIGN1cnJlbnQgUiBzZXNzaW9uIHVzaW5nIHRoZSBgbGlicmFyeSgpYCBmdW5jdGlvbi4KClJlbWVtYmVyIHVzaW5nIGEgcGFja2FnZS9saWJyYXJ5IGlzIGEgdHdvLXN0YWdlIHByb2Nlc3MuIFdlCgoxLiBgSW5zdGFsbGAgdGhlIHBhY2thZ2UvbGlicmFyeSBvbnRvIHlvdXIgY29tcHV0ZXIgKGZyb20gdGhlIGludGVybmV0KQoyLiBgTG9hZGAgdGhlIHBhY2thZ2UvbGlicmFyeSBpbnRvIHlvdXIgY3VycmVudCBzZXNzaW9uIHVzaW5nIHRoZSBsaWJyYXJ5IGNvbW1hbmQuCgpPbmUgb2YgdGhlIG1vc3QgdXNlZnVsIHBhY2thZ2VzIGlzIGNhbGxlZCAndGlkeXZlcnNlJy4KCklmIHlvdXIgZmlyc3QgY29kZSBibG9jayBpcyBjYWxsZWQgInNldHRpbmdzIiB0aGVuIHRoZSBjb2RlIGZvciB0aGF0IGJsb2NrIHdpbGwgYmUgYXV0b21hdGljYWxseSBydW4gd2hlbiB5b3Ugb3BlbiB0aGUgZmlsZS4gU28gaXQgaXMgdXNlZnVsIHRvIGxvYWQgYWxsIG9mIHlvdXIgcGFja2FnZXMgaW4gdGhpcyBmaXJzdCBibG9jay4KCk9uZSBwYWNrYWdlIEkgYWx3YXlzIGxvYWQgYXQgdGhlIHN0YXJ0IGlzIHRoZSBgdGlkeXZlcnNlYAoKIVtdKGltYWdlcy90aWR5dmVyc2UucG5nKQoKSXQgY29udGFpbnMgYSBudW1iZXIgb2YgdXNlZnVsIGNvbW1hbmRzIGZvciBwbG90cywgYW5kIGRhdGEgbWFuaXB1bGF0aW9uLgoKTm90ZSB0aGF0CgpJbnN0YWxsIHRoZSAndGlkeXZlcnNlJyBwYWNrYWdlLCBhbmQgdGhlbiBsb2FkIGl0IHdpdGggdGhlIGZvbGxvd2luZyBmdW5jdGlvbjoKCmBgYHtyIGxvYWRpbmcgdGhlIHRpZHl2ZXJzZX0KbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKSSBmaW5kIHRoYXQgYSBwYXJ0aWN1bGFybHkgZWFzeSB3YXkgdG8gbG9hZCBwYWNrYWdlcyBpcyB2aWEgdGhlIGBwX2xvYWRgIGZ1bmN0aW9uIGZyb20gdGhlIGBwYWNtYW5gIGxpYnJhcnkuIFRoaXMgd2lsbCBjaGVjayBpZiB0aGUgcGFja2FnZSBoYXMgYmVlbiBsb2FkZWQgaW50byB0aGUgY3VycmVudCBzZXNzaW9uLiBJZiBub3QgaXQgd2lsbCBzZWFyY2ggdG8gZmluZCBvdXQgaWYgdGhlIHBhY2thZ2UgaGFzIGJlZW4gc3RvcmVkIGluIHlvdXIgY29tcHV0ZXIuIElmIHRoZSBwYWNrYWdlIGlzIG5vdCBpbiB5b3VyIGNvbXB1dGVyIGl0IHdpbGwgYXV0b21hdGljYWxseSBmaW5kIGl0LiBJdCBiYXNpY2FsbHkgZG9lcyBldmVyeXRoaW5nIHlvdSBuZWVkISBIb3dldmVyLCB3ZSBhcmUgbm90IGdvaW5nIHRvIHByYWN0aXNlIHVzaW5nIGl0LCBidXQganVzdCB0byBsZXQgeW91IGtub3cgdGhhdCBpdCBleGlzdHMhCgojIyBPYnRhaW5pbmcgaGVscAoKVG8gZmluZCBvdXQgbW9yZSBhYm91dCBhIHBhY2thZ2UgdHlwZSBgP3BhY2thZ2VfbmFtZWAgaW4gdGhlIGNvbnNvbGUuIEFsdGVybmF0aXZlbHkgeW91IGNhbiBsb29rIGZvciB0aGUgcGFja2FnZSBkb2N1bWVudGF0aW9uIG9uIFtDUkFOXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy8pLgoKIyMgVXNpbmcgZnVuY3Rpb25zIGZyb20gcGFja2FnZXMKCk1vc3Qgb2YgdGhlIGZ1bmN0aW9ucyBsb2FkZWQgaW4gYSBwYWNrYWdlIHNob3VsZCB3b3JrICdvdXQgb2YgdGhlIGJveCcuIEhvd2V2ZXIgb2NjYXNpb25hbGx5IHlvdSBuZWVkIHRvIHJlZmVyIHRvIHRoZSBwYWNrYWdlIGZpcnN0LCBhbmQgdGhlbiB0aGUgZnVuY3Rpb24gdXNpbmcgdGhlIGZvcm1hdCBgcGFja2FnZV9uYW1lOjpmdW5jdGlvbl9mcm9tX3RoYXRfcGFja2FnZWAuIFRoaXMgaXMgdXNlZnVsIGZvciBhIHZhcmlldHkgb2YgcmVhc29uczoKCjEuIEl0IGFsbG93cyB5b3UgdG8gdXNlIGEgZnVuY3Rpb24gZnJvbSBhIHBhY2thZ2Ugd2l0aG91dCBoYXZpbmcgdG8gbG9hZCB0aGF0IHBhY2thZ2UKMi4gSXQgaGVscHMgaW4gY2FzZXMgd2hlcmUgeW91IGxvYWQgdHdvIHBhY2thZ2VzIHdoaWNoIGNvbnRhaW4gdHdvIGRpZmZlcmVudCBmdW5jdGlvbnMgd2hpY2ggaGFwcGVuIHRvIGhhdmUgdGhlIHNhbWUgbmFtZS4KMy4gU29tZXRpbWVzLCBldmVuIHdoZW4gYSBwYWNrYWdlIGlzIGxvYWRlZCwgeW91IG5lZWQgdG8gcHJlY2VkZSBhIGZ1bmN0aW9uIGJ5IHRoZSBwYWNrYWdlIG5hbWUuIChJIGFtIG5vdCBzdXJlIHdoeSB0aGlzIGhhcHBlbnMuLi4pLiBIb3dldmVyLCBtb3N0IG9mIHRoZSB0aW1lIHRoaXMgaXMgbm90IG5lY2Vzc2FyeS4KCiMjIEVYIDMgLSBVc2luZyBwYWNrYWdlcwoKMS4gSW5zdGFsbCBhbmQgbG9hZCB0aGUgcGFja2FnZSBgZ2dwbG90MmAKMi4gTG9vayB1cCB0aGUgZnVuY3Rpb24gYGdlb21fcG9pbnRgIGZyb20gdGhpcyBwYWNrYWdlLiBXaGF0IGRvZXMgaXQgZG8/CgojIE9iamVjdHMsIGRhdGEgZnJhbWVzIGFuZCBpbmRpY2VzCgojIyBPYmplY3RzCgpBIHZhcmlhYmxlIGlzIGEgdHlwZSBvZiAnb2JqZWN0JyB3aGljaCBSIHN0b3JlcyBpbiBtZW1vcnkuIFIgaXMgY2FwYWJsZSBvZiBjcmVhdGluZyBhbmQgc3RvcmluZyBhIHdpZGUgcmFuZ2Ugb2Ygb2JqZWN0cy4gVG8gc2VlIHdoYXQgdHlwZSBvZiBvYmplY3Qgd2UgaGF2ZSBjcmVhdGVkLCB3ZSB1c2UgdGhlIGZ1bmN0aW9uIGBjbGFzcygpYCwgZS5nLgoKYGBge3IgdmFyaWFibGUgY2xhc3NlcyAvIHR5cGVzfQoKeCA8LSAxCgpjbGFzcyh4KQoKeiA8LSAiaGVsbG8iCgpjbGFzcyh6KQoKYGBgCgoqY2xhc3MqIGlzIG9uZSBvZiB0aGUgbW9zdCB1c2VmdWwgZnVuY3Rpb25zIGluIFIgYXMgZXJyb3JzIGFyZSBvZnRlbiBkdWUgdG8gbWlzYXNzaWdubWVudCBvZiBjbGFzcywgZS5nLgoKYGBge3IgZm9yY2luZyBhbiBlcnJvciBkdWUgdG8gYSB0eXBlIGNsYXNoLCBlcnJvciA9IFRSVUV9Cgp4ICsgegoKYGBgCgpIZXJlIHdlIGhhdmUgdHJpZWQgdG8gYWRkIGEgbnVtYmVyIHRvIGEgc3RyaW5nIHdoaWNoIGlzIGNsZWFybHkgaW1wb3NzaWJsZS4gSXQncyBwb3NzaWJsZSB0byBjaGFuZ2UgdGhlIGNsYXNzIG9mIGFuIG9iamVjdCB1c2luZyBjb21tYW5kcyBzdWNoIGFzCmBhcy5jaGFyYWN0ZXJgLCBgYXMuaW50ZWdlcmAsIGBhcy5udW1lcmljYCwgYGFzLmZhY3RvcmAsIGUuZy4KCmBgYHtyIGNoYW5naW5nIHRoZSB0eXBlIG9mIGEgdmFyaWFibGUsIGVycm9yID0gVFJVRX0Kb25lIDwtICIxIgp4ICsgb25lCm9uZSA8LSBhcy5udW1lcmljKG9uZSkKeCArIG9uZSAKYGBgCgpIZXJlIGlzIGEgbGlzdCBvZiB0aGUgbWFpbiBvYmplY3QgY2xhc3NlcyBpbiBSOgoKMS4gTnVtZXJpYyAtIGEgbnVtYmVyIHdpdGggZGVjaW1hbCBwbGFjZXMKMi4gSW50ZWdlciAtIGEgbnVtYmVyIHdpdGhvdXQgZGVjaW1hbCBwbGFjZXMKMy4gQ2hhcmFjdGVyIC0gYSBzdHJpbmcgb2YgbGV0dGVycy9udW1iZXJzCjQuIFZlY3RvciAtIGFuIG9yZGVyZWQgbGlzdCBvZiBudW1iZXJzIG9yIGNoYXJhY3RlcnMsIG9yIG11bHRpLWNoYXJhY3RlciBzdHJpbmdzLiBOQiBlYWNoIG51bWJlciwgY2hhcmFjdGVyLCBvciBjaGFyYWN0ZXIgc3RyaW5nIGlzIGFsc28gYW4gb2JqZWN0LiBTbyB5b3UgY2FuIGhhdmUgb2JqZWN0cyB3aXRoaW4gb2JqZWN0cyEKNS4gRGF0YWZyYW1lIC0gYSAyIHggMiBhcnJheSBpbiB3aGljaCBlYWNoIGNvbHVtbiBoYXMgYSBuYW1lCjYuIExpc3QgLSB0aGlzIGlzIGxpa2UgYSB2ZWN0b3IsIGV4Y2VwdCBpdCBpcyBjYXBhYmxlIG9mIHN0b3JpbmcgbXVsdGlwbGUgb2JqZWN0IGNsYXNzZXMsIGUuZy4gaXQgY2FuIGNvbnRhaW4gYm90aCBudW1iZXJzIGFuZCBzdHJpbmdzLgoKSW4gb3JkZXIgdG8gY3JlYXRlIGEgdmVjdG9yIHdlIG5lZWQgdG8gdXNlIHRoZSBgY2AgZnVuY3Rpb24uIChjID0gJ2NvbWJpbmUnKSwgZS5nLgoKYGBge3IgbWFraW5nIGEgdmVjdG9yIHVzaW5nIHRoZSBjIGZ1bmN0aW9ufQpsaXN0Lm9mLm51bWJlcnMgPC0gYygxLDQsNTQsMjIsNDMsOSwwLDAsMjEpCgptZWFuKGxpc3Qub2YubnVtYmVycykKCnNkKGxpc3Qub2YubnVtYmVycykKYGBgCgpgYGB7ciB0dXJuaW5nIGEgdmVjdG9yIGludG8gYSBsaXN0fQoKYS5jaGFyYWN0ZXIudmVjdG9yIDwtIGMoIk1hcnkiLCAiSmFuZSIsICJBbGkiLCAiQ2hlbiIpCgphLmxpc3QgPC0gYXMubGlzdChjKDEsIDIsICJNYXJ5IiwgIkphbmUiKSkKCmBgYAoKCiMjIENyZWF0aW5nIGEgZGF0YSBmcmFtZSBmcm9tIHNjcmF0Y2gKCkEgZGF0YSBmcmFtZSBpcyBhIHR3by1kaW1lbnNpb25hbCBvYmplY3QgY29udGFpbmluZyB2YXJpYWJsZXMgYW5kIHJvdyBudW1iZXJzLiBJdCdzIGJhc2ljYWxseSBhIHNwcmVhZHNoZWV0LgoKVGhlIGZvbGxvd2luZyBjb2RlIGNyZWF0ZXMgYSBkYXRhIGZyYW1lIHByb2dyYW1tYXRpY2FsbHkuIEl0IGNyZWF0ZXMgdHdvIHZhcmlhYmxlcywgYW5kIGNvbWJpbmVzIHRoZW0gdG9nZXRoZXIgdG8gbWFrZSBhIGRhdGEgZnJhbWUuIE5vdGUgdGhhdCB0byBkbyB0aGlzIHdlIG5lZWQgdG8gdXNlIHRoZSBmdW5jdGlvbnMgYGFzLmRhdGEuZnJhbWVgIGFuZCBgY2JpbmRgLgoKYGBge3IgbWFraW5nIGEgZGF0YSBmcmFtZSBwcm9ncmFtbWF0aWNhbGx5fQoKbGlzdC5vZi5tb3ZpZXMgPC0gYygiSW5kZXBlbmRlbmNlIERheSIsICJQcmV0dHkgV29tYW4iLCAiVGhlIEdvZGZhdGhlciBQYXJ0ClR3byIsICJQbGFuZXQgb2YgdGhlIEFwZXMgKG9yaWdpbmFsKSIpCgpyb3R0ZW4udG9tYXRvZXMudmFyaWFibGUgPC0gYyg2MiwgNjEsIDk3LCA4OSkKCmRmIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQobGlzdC5vZi5tb3ZpZXMsIHJvdHRlbi50b21hdG9lcy52YXJpYWJsZSkpICMgJ2NiaW5kJyBiaW5kcyBjb2x1bW5zIHRvZ2V0aGVyCmBgYAoKIyMgVmlld2luZyB0aGUgY29udGVudHMgb2YgYSBkYXRhIGZyYW1lCgpUbyBnbGltcHNlIHRoZSB0b3AgZmV3IHJvd3MgdHlwZSBgaGVhZChuYW1lX29mX2RhdGFfZnJhbWUpYCBpbiB0aGUgY29uc29sZSwgZS5nLgoKYGBge3IgaGVhZCBmdW5jdGlvbn0KaGVhZChkZikKYGBgCgpUbyB2aWV3IHRoZSBkYXRhIGZyYW1lIGluIHRoZSAnc291cmNlJyB3aW5kb3csIHR5cGUgYFZpZXcobmFtZV9vZl9kYXRhX2ZyYW1lKWAgaW4gdGhlIGNvbnNvbGUsIC5lLmcuCgpgYGB7ciB2aWV3aW5nIGRhdGEgYXMgYSBzcHJlYWRzaGVldH0KVmlldyhkZikgI05CIGZpcnN0IGxldHRlciBpcyBhIGNhcGl0YWwgbGV0dGVyLgpgYGAKCiMjIFJlZmVycmluZyB0byB2YXJpYWJsZXMKClRvIHJlZmVyIHRvIHZhcmlhYmxlcywgdXNlIHRoZSBmb2xsb3dpbmcgc3ludGF4IGBkYXRhX2ZyYW1lX25hbWUkdmFyaWFibGVfbmFtZWAsIGUuZy4KYGBge3IgcmVmZXJyaW5nIHRvIHZhcmlhYmxlc30KZGYkbGlzdC5vZi5tb3ZpZXMKYGBgCldoZW4gbmFtaW5nIHZhcmlhYmxlcyB3ZSBjYW4gdXNlIGRvdHMgYW5kIHVuZGVyc2NvcmVzLCBlLmcuIGBkZiRsaXN0Lm9mLm1vdmllc2AgYW5kIGBkZiRsaXN0X29mX21vdmllc2AuIFdlIGNhbiB1c2UgbnVtYmVycyBhcyBsb25nIGFzIHRoZXkgZG9uJ3QgY29tZSBhdCB0aGUgYmVnaW5uaW5nLCBlLmcuIGBkZiRsaXN0X29mX21vdmllcy52M2AuCgpJZiB5b3UgdXNlIHRoaXMgY29udmVudGlvbiwgdGhlbiB0aGUgbmFtZXMgZm9yIHZhcmlhYmxlcyBjYW4gZ2V0IHZlcnkgbG9uZy4gSG93ZXZlciwgaXQncyBnZW5lcmFsbHkgdXNlZnVsLCBhcyBpbiBSIHlvdSBvZnRlbiBoYXZlIG11bHRpcGxlIGRhdGEgZnJhbWVzIGxvYWRlZCBpbnRvIG1lbW9yeS4gQnkgc3BlY2lmaXlpbmcgYm90aCB0aGUgbmFtZSBvZiB0aGUgZGF0YSBmcmFtZSBhbmQgdGhlIHZhcmlhYmxlLCB0aGlzIGF2b2lkcyBjb25mdXNpb24uCgpUcnkgdG8gYmUgY29uc2lzdGVudCB3aXRoIHlvdXIgbmFtaW5nIGNvbnZlbnRpb25zLiBJIHRlbmQgdG8gdXNlIHVuZGVyc2NvcmVzIHRvIG5hbWUgdmFyaWFibGVzLCBlLmcuIGBkYXRhLmZyYW1lLngkdmFyaWFibGVfeWAuIFRoaXMgaXMgYWxzbyB3aGF0IEhhZGxleSBXaWNraGFtIHJlY29tbWVuZHMgKEhhdmUgYSBsb29rIGF0IHRoZSBbVGlkeXZlcnNlIFN0eWxlIEd1aWRlXShodHRwczovL3N0eWxlLnRpZHl2ZXJzZS5vcmcvKSkKCklmIHlvdSdkIGxpa2UgdG8gc2VlIGFsbCB0aGUgdmFyaWFibGUgbmFtZXMgaW4gYSBkYXRhIGZyYW1lIHR5cGUgYG5hbWVzKGRhdGFfZnJhbWUpYCwgZS5nLiAKCmBgYHtyIHZpZXdpbmcgdmFyaWFibGUgbmFtZXN9Cm5hbWVzKGRmKQpgYGAKCiMjIEluZGljZXMKCldoZW5ldmVyIHlvdSB3aXNoIHRvIGFjY2VzcyB0aGUgY29udGVudHMgb2YgYW4gb2JqZWN0IHdpdGggbXVsdGlwbGUgdmFsdWVzIChlLmcuIGEgZGF0YSBmcmFtZSkgeW91IHVzZSBpbmRleGVzLiBUaGVzZSBhcmUgcGxhY2VkIGluc2lkZSBzcXVhcmUgYnJhY2tldHMsIGUuZy4gYFsxXWAuIEhhdmUgYSBsb29rIGF0IHRoZSBmb2xsb3dpbmcgZXhhbXBsZToKCmBgYHtyIGluZGljZXN9Cgp2ZWN0b3IgPSBjKDEsIDQsIDIsIDk5LCAwLjUsIDEwKQoKdmVjdG9yWzFdCgp2ZWN0b3JbMl0KCnZlY3Rvcls1XQoKdmVjdG9yWzI6NV0KCm1lYW4odmVjdG9yWzI6NV0pCgpgYGAKCkhlcmUgaXMgaG93IHdlIHdvdWxkIHVzZSB2ZWN0b3JzIHdpdGggYSBkYXRhZnJvbWUKCmBgYHtyIGdhcHMgaW4gaW5kaWNlc30KZGZbMSwyXQoKZGZbMSxdICMgaGVyZSB0aGUgc2Vjb25kIG51bWJlciBpcyBibGFuawoKZGZbLDJdICMgaGVyZSB0aGUgZmlyc3QgbnVtYmVyIGlzIGJsYW5rCmBgYAoKIyMgRVggMyAtIHVuZGVyc3RhbmRpbmcgaW5kaWNlcwoKV2hhdCBkb2VzIGVhY2ggbnVtYmVyIHJlZmVyIHRvPyBXaGF0IGhhcHBlbnMgd2hlbiB3ZSBsZWF2ZSBhIGJsYW5rIGNlbGw/CgojIyBSZWFkaW5nIGRhdGEgZnJhbWVzIGZyb20gZmlsZXMgdXNpbmcgbWVudXMKCldlIGNhbiB1c2UgdGhlIG1lbnUgaW4gUnN0dWRpbzogYEZpbGUgPiBJbXBvcnQgZGF0YXNldGAuIFlvdSBjYW4gZG8gdGhpcyB0byBpbXBvcnQgRXhjZWwsIFNQU1MsIFNBUyBhbmQgU1RBVEEgZmlsZXMuCgojIyBSZWFkaW5nIGRhdGEgZnJhbWVzIGZyb20gZmlsZXMgdXNpbmcgY29kZQoKSG93ZXZlciwgcmF0aGVyIHRoYW4gdXNlIHRoZSBtZW51LCBpdCdzIG11Y2ggYmV0dGVyIHRvIHVzZSBhY3R1YWwgY29kZSwgYXMgdGhpcyB3aWxsIGF1dG9tYXRlIHRoZSBwcm9jZXNzLiBMZXQncyBpbXBvcnQgYSBkYXRhc2V0IG9uIFdvcmxkIEhhcHBpbmVzcyBSZXBvcnQgKDIwMTcpLCBieSBjb3VudHJ5LiBUaGUgZmlsZXMgYXJlIFtXSFJfMjAxNy54bHN4XShXSFJfMjAxNy54bHN4KSwgW1dIUl8yMDE3LnNhdl0oV0hSXzIwMTcuc2F2KSwgYW5kIFtXSFJfMjAxNy5jc3ZdKFdIUl8yMDE3LmNzdikuIEFsdGVybmF0aXZlbHkgeW91IGNhbiBhY3R1YWxseSBkb3dubG9hZCB0aGUgZGF0YSBzZXQgc3RyYWlnaHQgZnJvbSB0aGUgVVJMIChiZWxvdykKCgpgYGB7ciBpbXBvcnRpbmcgZGF0YSwgbWVzc2FnZSA9IEZBTFNFfQoKIyBUaGlzIGNvZGUgZGVwZW5kcyBvbiB1c2luZyB0aGUgYHRpZHl2ZXJzZWAgYW5kIGBoYXZlbmAgcGFja2FnZXMKIyBJZiB5b3UgaGF2ZSBub3QgaW1wb3J0ZWQgLyBsb2FkZWQgdGhlbSwgeW91IG5lZWQgdG8gc28KIyBsaWJyYXJ5KHRpZHl2ZXJzZSkKIyBsaWJyYXJ5KGhhdmVuKQoKZGYgPC0gcmVhZHhsOjpyZWFkX2V4Y2VsKCJXSFJfMjAxNy54bHN4IikgIyBSZWFkIGFuIGV4Y2VsIGZpbGUKCmRmIDwtIGhhdmVuOjpyZWFkX3Nwc3MoIldIUl8yMDE3LnNhdiIpICMgUmVhZCBmcm9tIGFuIFNQU1MgZmlsZQoKZGYgPC0gcmVhZF9jc3YoIldIUl8yMDE3LmNzdiIpICMgUmVhZCBmcm9tIGEgLmNzdiBmaWxlCgojT3IgdG8gZG93bmxvYWQgc3RyYWlnaHQgZnJvbSB0aGUgVVJMISEKCmRmIDwtIHJlYWRfY3N2KCJodHRwczovL3ZlcmJpbmdub3Vucy5naXRodWIuaW8vQWR2ZW50dXJlc0luUi9kb2NzL1dIUl8yMDE3LmNzdiIpCgpgYGAKCgoKUG9zc2libHkgdGhlIGJlc3QgZGF0YSBmb3JtYXQgdG8gd29yayBpbiBpcyB0aGUgYC5jc3ZgIGRhdGEgZm9ybWF0IChDb21tYS1TZXBhcmF0ZWQgVmFsdWUpLiBUaGlzIGlzIGdvb2QgYmVjYXVzZSBpdCBpcyByZWFkYWJsZSBpbiBFeGNlbCwgc21hbGwsIHNpbXBsZSwgYW5kIG5vdCBlYXNpbHktY29ycnVwdGVkLiBJdCdzIG9ubHkgZGlzYWR2YW50YWdlIGlzIHRoYXQgaXQgZG9lcyBub3Qgc3VwcG9ydCBFeGNlbCBmb3JtdWxhcyBvciBmb3JtYXR0aW5nIChOQiBzb21lIHdvdWxkIHNheSB0aGlzIGlzIGFuIGFkdmFudGFnZSBhcyBFeGNlbCBmb3JtdWxhZSBhcmUgbm90IHRoYXQgcmVsaWFiaWxpdHkgYW5kIG5vdCB2ZXJ5IGNvbnNpc3RlbnQgd2l0aCBzY2llbnRpZmljIHJlcHJvZHVjaWJpbGl0eSkKClRvIHJlYWQgLmNzdiBmaWxlcyB3ZSB1c2UgdGhlIGByZWFkLmNzdigpYCBmdW5jdGlvbiBmcm9tIGJhc2UgUiwgb3IgYHJlYWRfY3N2KClgIGZyb20gdGhlIHRpZHl2ZXJzZSAoSSB3b3VsZCBnbyB3aXRoIHRoZSBsYXR0ZXIgYXMgaXQgYWxzbyBzaG93cyB5b3UgYSBsaXN0IG9mIHRoZSB2YXJpYWJsZSB0eXBlcykKCiMgU3Vic2V0dGluZyBhIGRhdGEgc2V0IHVzaW5nIChhKSBiYXNlIFIgYW5kIChkKSBkcGx5cgoKIyMgU3Vic2V0dGluZyB3aXRoIGJhc2UgUgoKV2UncmUgZ29pbmcgdG8gKnN1YnNldCogdGhlIFdIUiBkYXRhc2V0IChpLmUuIGNob29zZSBvbmx5IHRob3NlIGNhc2VzL29ic2VydmF0aW9ucyB3aGljaCBmdWxmaWwgYSBzcGVjaWZpYyBjcml0ZXJpb24pLiBUbyBkbyB0aGlzIHdlJ3JlIGdvaW5nIHRvIHVzZSB0aGUgYHdoaWNoKClgIGZ1bmN0aW9uLiBXaGVuIHlvdSBhcHBseSBgd2hpY2hgIHRvIGEgdmFyaWFibGUgaW4gYSBkYXRhc2V0LCBpdCB3aWxsIHByb2R1Y2UgaW5kaWNlcyAoaW5kZXhlcykgb2YgdGhlIHJvd3Mgd2hpY2ggZnVsZmlsIGEgY2VydGFpbiBjcml0ZXJpb24sIGUuZy4gYHdoaWNoKGRmJHZhcl9uYW1lID09IDIpYCB3aWxsIGdpdmUgeW91IHRoZSBpbmRpY2VzIG9mIGFsbCByb3dzIHdoZXJlIHRoZSB2YWx1ZSBvZiB0aGUgdmFyaWFibGUgaXMgMi4KCiMjIEVYNDogU3Vic2V0dGluZyB1c2luZyBiYXNlIFIKCkFybWVkIHdpdGggdGhpcyBrbm93bGVkZ2UsIHlvdXIgdGFzayBpcyB0byBzdWJzZXQgdGhlIGRhdGEgZnJhbWUgc28gdGhhdCBpdCBvbmx5IGNvbnRhaW5zIGluZm9ybWF0aW9uIGZyb20gQWZyaWNhbiBjb3VudHJpZXMuCgpJZiB5b3UncmUgc3R1Y2sgaGF2ZSBhIGxvb2sgYXQgdGhlIGFuc3dlciBiZWxvdy4gCgpgYGB7ciBTdWJzZXR0aW5nIHVzaW5nIGJhc2UgUn0KZGYuQWZyaWNhIDwtIGRmW3doaWNoKGRmJHJlZ2lvbiA9PSAiQWZyaWNhIiksIF0KYGBgCgojIyBQaXBpbmcKCk9rYXksIHRoZSBhYm92ZSBjb2RlIGlzIHByZXR0eSBob3JyaWJsZSwgc28gd2UncmUgZ29pbmcgdG8gZXhwbG9yZSBhbiBhbHRlcm5hdGl2ZSB1c2luZyB0aGUgcGFja2FnZSBgZHBseXJgIHdoaWNoIGlzIGZyb20gdGhlIGB0aWR5dmVyc2VgLiBCdXQgYmVmb3JlIHdlIGNhbiB1c2UgYGRwbHlyYCB3ZSBoYXZlIHRvIGxlYXJuIGhvdyB0byAncGlwZScuCgohW10oaW1hZ2VzL01hZ3JpdHRlUGlwZS5qcGcpCgpQaXBlcyBhcmUgd3JpdHRlbiBpbiBSIGFzIGAlPiVgIChub3RlIHlvdSBtdXN0IHVzZSBhIHBlcmNlbnRhZ2Ugc2lnbiBiZWZvcmUgYW5kIGFmdGVyIHRoZSBwaXBlKS4gVG8gZGVtb25zdHJhdGUgd2hhdCBwaXBlcyBkbywgSSBoYXZlIGEgbG9vayBhdCB0aGUgZm9sbG93aW5nIHBzZXVkb2NvZGUuCgohW10oaW1hZ2VzL3BpcGluZy5wbmcpCgpBbGwgcGlwZXMgZG8gaXMgZW5hYmxlIHVzIHRvICdwYXNzJyBhIGRhdGEgZnJhbWUgKG9yIGFub3RoZXIgb2JqZWN0KSB0byBhIG5ldyBmdW5jdGlvbiB3aXRob3V0IGhhdmluZyB0byBrZWVwIG9uIHNwZWNpZnlpbmcgdGhlIGRhdGEgZnJhbWUuIEluIGFkZGl0aW9uLCB3ZSBjYW4gKmNoYWluKiBwaXBlcyB0b2dldGhlciBpbmRlZmluaXRlbHkuCgpIZXJlJ3MgaG93IHdlIHdvdWxkIHN1YnNldCB0aGUgZGF0YSBmcmFtZSB1c2luZyBwaXBpbmc6CgpgYGB7ciBzdWJzZXR0aW5nIHVzaW5nIHBpcGluZ30KCmRmLkFmcmljYSA8LSBmaWx0ZXIoZGYsIHJlZ2lvbiA9PSAiQWZyaWNhIikgIyBUaGlzIGlzIHRoZSB2ZXJzaW9uIHdpdGhvdXQgcGlwaW5nCgpkZiAlPiUgZmlsdGVyKHJlZ2lvbiA9PSAiQWZyaWNhIikgLT4gZGYuQWZyaWNhICMgVGhpcyBpcyB0aGUgdmVyc2lvbiB3aXRoIHBpcGluZy4gSXQgbG9va3MgbG9uZ2VyLCBidXQgd2UgY2FuIGNoYWluIG11bHRpcGxlIGZ1bmN0aW9ucyB0b2dldGhlciEKYGBgCgpOb3RlIHRoYXQgdG8gY3JlYXRlIGEgbmV3IGRhdGEgZnJhbWUsIHdlIG5lZWQgYSBzb2xpZCBhcnJvdyBhdCB0aGUgZW5kLiBJZiB3ZSBkb24ndCBpbmNsdWRlIHRoYXQgc29saWQgYXJyb3csIHRoZSByZXN1bHRzIGFyZSBzaG93biBpbiB0aGUgY29uc29sZSwgYnV0IG5vIG5ldyBkYXRhIGZyYW1lIGlzIGNyZWF0ZWQuIFRoaXMgaXMgYW4gaW5jcmVkaWJseSB1c2VmdWwgZmVhdHVyZSBvZiBwaXBlcy4gWW91IGNhbiBgdHJ5IGJlZm9yZSB5b3UgYnV5YCEKCkFuZCBoZXJlIGlzIGFuIGV4YW1wbGUgd2hlcmUgd2UgKmNoYWluKiBhIHNlcmllcyBvZiBwaXBlcyB0b2dldGhlcjoKCmBgYHtyIGNoYWluaW5nIHBpcGVzIHRvZ2V0aGVyfQoKZGYgJT4lIAogIGdyb3VwX2J5KHJlZ2lvbikgJT4lCiAgc3VtbWFyaXNlKG1lYW4uaGFwcGluZXNzID0gbWVhbihoYXBwaW5lc3Nfc2NvcmUpKSAtPgogIGRmLm1lYW4uaGFwcGluZXNzLmJ5LnJlZ2lvbgoKYGBgCgpOQiBXaGVuIHBpcGluZyB0aGUgY29kZSBiZWNvbWVzIG1vcmUgcmVhZGFibGUgd2hlbiB0aGUgbGluZSBlbmRzIHdpdGggdGhlIHBpcGUuCgpUaGVyZSBhcmUgYSBjb3VwbGUgb2YgaW1wb3J0YW50IHBvaW50cyB0byBub3RlLgoKKDEpIFdlIGNhbiByZWZlciB0byB2YXJpYWJsZXMgd2l0aG91dCBzcGVjaWZ5aW5nIHRoZSBkYXRhIGZyYW1lCigyKSBJZiB3ZSB3aXNoIHRvIHN0b3JlIHRoZSByZXN1bHRzIHdlIG11c3Qgb3V0cHV0IHRoZW0gdXNpbmcgYW5kIGFycm93IGAtPmAuIElmIHdlIGRvbid0IHN0b3JlIHRoZSByZXN1bHRzIHRoZXkgd2lsbCBtZXJlbHkgYmUgZGlzcGxheWVkIGluIHRoZSBjb25zb2xlLgoKUGlwaW5nIGlzIGEga2V5IHRlY2huaXF1ZSBpbiBSIGFuZCBvbmNlIHlvdSd2ZSBsZWFybnQgaXQgeW91IHdpbGwgd3JpdGUgbXVjaCBtb3JlIHBvd2VyZnVsIGFuZCByZWFkYWJsZSBjb2RlLgoKQXMgd2VsbCBhcyB1c2luZyBwaXBlcyB0byBjcmVhdGUgZGF0YSBmcmFtZSwgeW91IGNhbiBhbHNvIGluc2VydCBwaXBlcyBpbnRvIGJvdGggYW5hbHlzZXMgYW5kIGZpZ3VyZXMhIEhlcmUgaXMgYW4gZXhhbXBsZSBvZiBhIHBpcGUgaW5zZXJ0ZWQgd2l0aGluIGFuIEFOT1ZBLgoKYGBge3IgZW1iZWRkaW5nIHBpcGVzIHdpdGhpbiBhbiBhbmFseXNpc30KCiMgQW4gQU5PVkEgd2l0aG91dCBhIHBpcGUuIE5CIHdlIGFyZSB1c2luZyB0aGUgYmFzZSBmdW5jdGlvbiAiYW92Ii4gSWYgeW91IHdvdWxkIGxpa2UgdG8gY29uZHVjdCBTUFNTLXN0eWxlIEFOT1ZBcywgdGhlIGJlc3QgcGFja2FnZSBpcyBjYWxsZWQgImFmZXgiLgoKbW9kIDwtIGFvdihoYXBwaW5lc3NfcmFuayB+IHJlZ2lvbiwgZGF0YSA9IGRmKQoKcGFjbWFuOjpwX2xvYWQoYnJvb20pICMgVG8gbG9hZCB0aGUgInRpZHkiIGZ1bmN0aW9uLgoKdGlkeShtb2QpCgojIEhlcmUgd2UgdXNlIGEgcGlwZSBpbnNpZGUgdGhlIGFuYWx5c2lzCm1vZCA8LSBhb3YoaGFwcGluZXNzX3JhbmsgfiByZWdpb24sICMgTkIgbm90ZSB3ZSBjYW4gYnJlYWsgdGhlIGxpbmUgYWZ0ZXIgYSBjb21tYQogICAgICAgICAgIGRhdGEgPSBkZiAlPiUgZmlsdGVyKHJlZ2lvbiA9PSAiQWZyaWNhIiB8IHJlZ2lvbiA9PSAiU291dGggQW1lcmljYSIpKQoKdGlkeShtb2QpCgoKYGBgCgpOb3RlIGhvdyBJIGhhdmUgYnJva2VuIHNvbWUgb2YgdGhlIGxpbmVzIGFmdGVyIGEgY29tbWEuIFRoaXMgbWFrZXMgdGhlIGNvZGUgbW9yZSByZWFkYWJsZS4gR2VuZXJhbGx5IHdlIGNhbiBicmVhayBhIGxpbmUgd2hlbiBpdCBlbmRzIGluIHNvbWUga2luZCBvZiBzeW1ib2wsIGUuZy4gYSBwaXBlLCBhbiBhcnJvdywgb3IgYSBjb21tYS4KCgojIExvb3BzIGFuZCBpZi10aGVuIHN0YXRlbWVudHMKCkxvb3BzIGFuZCBpZi10aGVuIHN0YXRlbWVudHMgYXJlIHVzZWZ1bCBwcm9ncmFtbWluZyB0b29scyB3aGljaCBoYXZlIHRoZSBzYW1lIHN0cnVjdHVyZTogYEZVTkNUSU9OIChTVEFURU1FTlQpIHsuLi4uLn1gLgoKIyMgTG9vcHMKCiFbXShodHRwczovL21lZGlhLmdpcGh5LmNvbS9tZWRpYS9NRFhvbXJjR3NoR3NvL2dpcGh5LmdpZikKCmBgYHtyIGV4YW1wbGUgb2YgYSBsb29wfQpmb3IoaSBpbiAxOjEwKXsKICBwcmludChhcy5jaGFyYWN0ZXIoaSkpCn0KYGBgCgoKIyMgRVg1OiBMb29wcwoKVGhlIGNvZGUgYmVsb3cgY3JlYXRlcyBhIHNlcXVlbmNlIHJhbmdpbmcgZnJvbSAwIHRvIDMwIGdvaW5nIHVwIGluIHN0ZXBzIG9mIDAuMjUuIFRyeSB0byBhY2hpZXZlIHRoZSBzYW1lIHJlc3VsdCB1c2luZyBhIGxvb3AKCmBgYHtyfQpzZXEoMCwzMCwyLjUpCmBgYAoKCiMjIElmLXRoZW4gc3RhdGVtZW50cwoKVG8gZGVtb25zdHJhdGUgaWYtdGhlbiBzdGF0ZW1lbnRzLCB3ZSBhcmUgZ29pbmcgdG8gY3JlYXRlIGEgbmV3IHZhcmlhYmxlIHdoaWNoIHNob3dzIGlmIHRoZSBoYXBwaW5lc3MgaW5kZXggaXMgYWJvdmUgdGhlIG1lYW4KCmBgYHtyIGV4YW1wbGUgb2YgYW4gaWYtdGhlbiBzdGF0ZW1lbnR9CmRmJGhhcHBpbmVzc19hYm92ZV9tZWFuIDwtIDAgIyBTZXQgdmFyaWFibGUgdG8gMAptZWFuX2hhcHBpbmVzcyA8LSBtZWFuKGRmJGhhcHBpbmVzc19zY29yZSkgIyBDYWxjdWxhdGUgbWVhbiBtcGcKZm9yIChpIGluIDE6bnJvdyhkZikpewogIGlmKGRmJGhhcHBpbmVzc19zY29yZVtpXSA+IG1lYW5faGFwcGluZXNzKXsKICAgIGRmJGhhcHBpbmVzc19hYm92ZV9tZWFuW2ldIDwtIDEKICAgIH0KfQpgYGAKCkFuZCBoZXJlIGlzIHRoZSBzYW1lIHByb2Nlc3MgdXNpbmcgYGRwbHlyYCwgd2hpY2ggYXZvaWRzIHRoZSBsb29wIGFuZCB0aGUgaWYtdGhlbiBzdGF0ZW1lbnQuCgpgYGB7ciBjcmVhdGluZyBhIHZhcmlhYmxlIHVzaW5nIHRpZHl2ZXJzZSBhbmQgYXZvaWRpbmcgaWYtdGhlbiBzdGF0ZW1lbnR9CgpkZiAlPiUKICBtdXRhdGUoaGFwcGluZXNzX2Fib3ZlX21lYW4gPSBhcy5udW1lcmljKGhhcHBpbmVzc19zY29yZSA+IG1lYW4oaGFwcGluZXNzX3Njb3JlKSkpIC0+CiAgZGYKYGBgCgpOb3RlIGxvb3BzIGFuZCBpZi10aGVuIHN0YXRlbWVudHMgYXJlIHF1aXRlIHZlcmJvc2UsIGFuZCB0aGVyZSBpcyBhbG1vc3QgYWx3YXlzIGEgbmVhdGVyIGFuZCBtdWNoIHNob3J0ZXIgYWx0ZXJuYXRpdmVzLiBIb3dldmVyLCBJIHRoaW5rIHRoZXkgYXJlIHVzZWZ1bCBwcm9jZWR1cmVzIGZvciB0aGUgcmVsYXRpdmUgYmVnaW5uZXIuCgpIZXJlIGlzIHRoZSB3YXkgdG8gY3JlYXRlIHRoZSB2YXJpYWJsZSB3aXRob3V0IHVzaW5nIHRoZSB0aWR5dmVyc2UKCmBgYHtyIGNyZWF0aW5nIGEgdmFyaWFibGUgd2l0aG91dCB0aWR5dmVyc2UsIG1lc3NhZ2UgPSBGQUxTRX0KCmRmIDwtIHJlYWRfY3N2KCJXSFJfMjAxNy5jc3YiKQoKZGYkaGFwcGluZXNzX2Fib3ZlX21lYW4gPC0gYXMubnVtZXJpYyhkZiRoYXBwaW5lc3Nfc2NvcmUgPiBtZWFuKGRmJGhhcHBpbmVzc19zY29yZSkpCmBgYAoKU28gaG93IGRvZXMgdGhpcyB3b3JrPyBUaGUgc3RhdGVtZW50IGluIGJyYWNrZXRzIGV2YWx1YXRlcyB0byBUUlVFIC8gRkFMU0UuIFdlIHRoZW4gdHVybiB0aGlzIGludG8gYSBudW1iZXIgdXNpbmcgYGFzLm51bWVyaWNgLiBUUlVFIGV2YWx1YXRlcyB0byAxLCB3aGlsZSBGQUxTRSBldmFsdWF0ZXMgdG8gMC4KCkl0IGNhbiBiZSBxdWl0ZSB1c2VmdWwgdG8gY2hhaW4gc3RhdGVtZW50cy4gRm9yIGV4YW1wbGUsIGlmIHdlIHdpc2ggdG8gaWRlbnRpZnkgY291bnRyaWVzIHdoZXJlIGJvdGggdGhlIGhhcHBpbmVzcyBzY29yZSBhbmQgbGlmZSBleHBlY3RhbmN5IGFyZSBhYm92ZSB0aGUgbWVhbiwgd2UgY291bGQgZG8gdGhpcy4uLi4KCmBgYHtyIGZ1cnRoZXIgZXhhbXBsZX0KZGYkaGFwcGluZXNzX2FuZF9MRV9hYm92ZV9tZWFuIDwtIGFzLm51bWVyaWMoKGRmJGhhcHBpbmVzc19zY29yZSA+IG1lYW4oZGYkaGFwcGluZXNzX3Njb3JlKSkgJiAoZGYkbGlmZV9leHBlY3RhbmN5ID4gbWVhbihkZiRsaWZlX2V4cGVjdGFuY3kpKSkKYGBgCgojI8KgRVg2OiBDcmVhdGluZyB2YXJpYWJsZXMKClRyeSB0byBpZGVudGlmeSBjb3VudHJpZXMgd2hlcmUgYm90aCB0aGUgR0RQIHBlciBjYXBpdGEgYW5kIHRydXN0IGluIHRoZSBnb3Zlcm5tZW50IGFyZSBhYm92ZSB0aGUgbWVhbi4KCiMgU3RvcmVkIHJlc3VsdHMKCldoZW5ldmVyIHlvdSBydW4gYW4gYW5hbHlzaXMgaW4gUiBhbmQgc2F2ZSB0aGF0IHRvIGFuIG9iamVjdCwgdGhlIG9iamVjdCBoYXMgYW4gaW50ZXJuYWwgc3RydWN0dXJlLiBUbyBkZW1vbnN0cmF0ZSB0aGlzLCBsZXQncyBkbyBhIHNpbXBsZSByZWdyZXNzaW9uIHVzaW5nIHRoZSBtdGNhcnMgZGF0YXNldDoKCmBgYHtyIHJlYWQgaW4gZGF0YSwgbWVzc2FnZSA9IEZBTFNFfQoKZGYgPC0gcmVhZC5jc3YoIldIUl8yMDE3LmNzdiIpCgpoZWFkKGRmKQoKYGBgCgpMZXQncyBkcmF3IGEgcGxvdCBsb29raW5nIGF0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBHRFAgcGVyIGNhcGl0YSBhbmQgSGFwcGluZXNzIFNjb3JlLiBXZSdyZSBub3QgZ29pbmcgdG8gZm9jdXMgb24gdGhlIGNvZGUsIHdoaWNoIHdpbGwgYmUgY292ZXJlZCBpbiB0aGUgbmV4dCBzZXNzaW9uLgoKYGBge3IgcnVuIGEgcGxvdH0KZyA8LSBnZ3Bsb3QoYWVzKHggPSBkZiRnZHBfcGVyX2NhcGl0YSwgeSA9IGRmJGhhcHBpbmVzc19zY29yZSksIGRhdGEgPSBkZikKZyA8LSBnICsgZ2VvbV9wb2ludCgpCmcgPC0gZyArIGdlb21fc21vb3RoKCkKZwpgYGAKCk5vdyBsZXQncyBydW4gYSByZWdyZXNzaW9uLiBBZ2Fpbiwgd2UncmUgbm90IGdvaW5nIGdvaW5nIHRvIGZvY3VzIG9uIHRoZSBjb2RlLCB3aGljaCB3aWxsIGJlIGNvdmVyZWQgaW4gdGhlIGZpbmFsIHNlc3Npb24uCgpgYGB7ciByZWdyZXNzaW9uIG1vZGVsc30KCm1vZCA8LSBsbShoYXBwaW5lc3Nfc2NvcmUgfiBnZHBfcGVyX2NhcGl0YSwgZGF0YSA9IGRmKSAjIG1vZCA9ICJtb2RlbCIKCnBhY21hbjo6cF9sb2FkKGJyb29tKSAjIEJyb29tIGlzIGEgcGFja2FnZSB3aGljaCBwcm9kdWNlcyBuZWF0IHRhYmxlcyBvZiByZXN1bHRzCgp0aWR5KG1vZCkgIyBUaGlzIGlzIGEgYnJvb20gZnVuY3Rpb24gd2hpY2ggdGlkaWVzIHVwIHRoZSBzdGF0aXN0aWNhbCByZXN1bHRzIGZvciByZXBvcnRpbmcKCmBgYAoKCk5vdywgbGV0J3MgaGF2ZSBhIGxvb2sgYXQgdGhlIGBzdHJ1Y3R1cmVgIG9mIHRoaXMgbW9kZWwuIFRoZXJlIGFyZSB0d28gd2F5cyB0byBkbyB0aGlzOgoKMS4gVXNlIHRoZSBgc3RyYCBmdW5jdGlvbiwgZS5nLiBgc3RyKG1vZClgCjIuIFR5cGUgYG1vZCRgLCBhbmQgdGhlbiB1c2UgYXV0b2NvbXBsZXRlLgoKV2UgY2FuIHNlZSB0aGF0IHRoZSBgJGAgc3ltYm9sIGhhcyBhIGR1YWwgZnVuY3Rpb24gaW4gUjogZmlyc3RseSwgdG8gc3BlY2lmeSB2YXJpYWJsZXMgd2l0aGluIGRhdGFmcmFtZXMsIGFuZCBzZWNvbmRseSB0byBzcGVjaWZ5IHN1YmNvbXBvbmVudHMgb2YgYW4gb2JqZWN0LgoKSXQgaXMgdXNlZnVsIHRvIGJlIGFibGUgdG8gcmVmZXIgdG8gc3ViY29tcG9uZW50cyBvZiBhbiBvYmplY3Qgc28gdGhhdCB3ZSBjYW4gaW50ZWdyYXRlIGludG8gb3VyIHJlcG9ydCwgZS5nLiB0aGUgcmVncmVzc2lvbiB5aWVsZGVkIGEgdmFsdWUgb2YgYHIgc3VtbWFyeShtb2QpJHIuc3F1YXJlZGAKCiMjIEVYIDY6IExldCdzIHB1dCBpdCBhbGwgdG9nZXRoZXIhISEKCigxKSBEb3dubG9hZCB0aGUgZGF0YSBmb3IgW2xpZmUgZXhwZWN0YW5jeSBieSBjb3VudHJ5XShXSE9fbGlmZV9leHBlY3RhbmN5LmNzdikKKDIpIFRoZSBkYXRhIGNvdmVycyBtYW55IHllYXJzLiBTZWxlY3QgdGhlIG1vc3QgcmVjZW50IHllYXIuCigzKSBNZXJnZSB0aGUgZGF0YSB3aXRoIHRoZSAiV0hSIiBkYXRhICh5b3Ugd2lsbCBuZWVkIHRvIG1lcmdlIHVzaW5nIHRoZSAiY291bnRyeSIgdmFyaWFibGUpCig0KSBEcmF3IHBsb3RzIG9mIChhKSBsaWZlIGV4cGVjdGFuY3kgYWdhaW5zdCBHRFAgcGVyIGNhcGl0YSwgKGIpIGxpZmUgZXhwZWN0YW5jeSBhZ2FpbnN0IGZhbWlseSB2YWx1ZXMKCk9uY2UgeW91IGdldCBzdHVjayBoYXZlIGEgbG9vayBhdCB0aGUgZmlyc3QgY29kZSBjaHVuayBiZWxvdy4gVGhpcyBjb250YWlucyB0aGUgc29sdXRpb24gYnV0IHdpdGggcGVza3kgZXJyb3JzIGFkZGVkISBTZWUgaWYgeW91IGNhbiBzb3J0IG91dCB0aGUgZXJyb3JzLgoKYGBge3IgZXhlcmNpc2Ugd2l0aCBlcnJvcnMsIGV2YWwgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBlcnJvcj1UUlVFfQoKd2hyIDwtIHJlYWRfY3N2KCJXSFJfMjAxNy5jc3YiKQoKbGUgPC0gcmVhZF9jc3YoIldIT19saWZlX2V4cGVjdGFuY3kuY3N2IikKCndociAlPiUgIyBOQiB3ZSBuZWVkIHRvIGVuc3VyZSB0aGF0IHRoZSAiY291bnRyeSIgdmFyaWFibGUgaGFzIGV4YWN0bHkgdGhlIHNhbWUgbmFtZSBpbiBib3RoIGRhdGFzZXRzCiAgcmVuYW1lKGNvdW50cnkgPSBDb3VudHJ5KSAtPgogIHdocgoKbGUgJT4lIAogIGZpbHRlcihZZWFyID09IDIwMTUpICU+JSAKICBtZXJnZSh3aHIpICU+JSBkb2MKICBkZgoKcGxvdChkZiRgTGlmZSBleHBlY3RhbmN5YCwgZGYkR0RQKQpwbG90KGRmJGBMaWZlIGV4cGVjdGFuY3lgLCBkZiRmYW1pbHkpCgpgYGAKClRoZSBjb2RlIGluIHRoaXMgY2h1bmsgc2hvd3MgdGhlIHNvbHV0aW9uIQoKYGBge3IgQ29ycmVjdCEsIG1lc3NhZ2UgPSBGQUxTRX0KCndociA8LSByZWFkX2NzdigiV0hSXzIwMTcuY3N2IikKCmxlIDwtIHJlYWRfY3N2KCJXSE9fbGlmZV9leHBlY3RhbmN5LmNzdiIpCgp3aHIgJT4lIAogIHJlbmFtZShDb3VudHJ5ID0gY291bnRyeSkgLT4KICB3aHIKCmxlICU+JSAKICBmaWx0ZXIoWWVhciA9PSAyMDE1KSAlPiUgCiAgbWVyZ2Uod2hyKSAtPgogIGRmCgpwbG90KGRmJGBMaWZlIGV4cGVjdGFuY3lgLCBkZiRHRFApCnBsb3QoZGYkYExpZmUgZXhwZWN0YW5jeWAsIGRmJGZhbWlseSkKCmBgYAoKCgoK