You can import all kinds of data format in R using various packages. You simply need to tell R where to find the data in your computer – the directory or the path. Therefore, before we start loading data in R, let’s first see how can we set and change the working directory.

1 Set the Working Directory

A working directory is a hierarchical file system, or you can simple consider it as the path to the file or folder you want to use.

1.1 In an R file (not R Notebook)

#view your current working directory
getwd()

#change the working directory to your project folder
setwd("/Users/yaoyao/Documents/PLSC309/Lab1")
#view what is inside this working directory
dir()

1.2 In an R Notebook File

In R Notebook, the current working directory inside a notebook chunk is always the directory/folder containing that .Rmd file. For example, in your Lab assignment, you have created Name_Lab1.Rmd file. If you created and saved the the lab1.Rmd file inside a folder called “lab1” under “PLSC309” folder, the working directory would be the path all the way to folder “Lab1”.

What happens if you want to set the working directory elsewhere in R Notebook?

# Only changes working directory in this code chunk.  
setwd("/Users/yaoyao/Documents/PLSC309")
The working directory was changed to /Users/yaoyao/Documents/PLSC309 inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the the working directory for notebook chunks.

The warning message you see above tells us that the setwd( ) command can only change the working directory in that one code chunk. For the rest of the notebook, the working directory is still the path to the folder where you save your .Rmd file.

There is only one way to change working directory globally for all the code chunks in a notebook file. The method is shown below, and you have to use it in the setup chunk: begin with {r setup} instead of {r}:

#change working directory for all the code chunks in a notebook 
knitr::opts_knit$set(root.dir = normalizePath("/Users/yaoyao/Documents/PLSC309/Lab1")) 

This is not very intuitive! You can avoid changing the working directory if you always put the relevant files in the same folder as you save the .Rmd Notebook file.


2 Import Data

2.1 Install packages

You can import all kinds of data format in R using various packages. To use those packages, you first need to install them. You only need to do this once.

File Type Package Function
Excel (.xlsx) openslxs read.xlsx
Stata (.dta, versions 12 and earlier) foreign read.dta
Stata (.dta, versions 13 and 14) readstata13 read.dta13
SPSS (.sav) foreign read.spss
Comma separated (.csv) none read.csv
Tab delimited (.tab or .txt) none read.table
R data files (.Rdata) none load
#Install necessary packages, you only need to do this once
install.packages("openxlsx")
install.packages("foreign")
install.packages("readstata13")

2.2 Load packages and import data

Although you only need to install packages to R once, you need to load the required packages in R using the library() function before you analysis every time in the beginning of your R session.

2.2.1 Read Excel file

#You need to library() a package before using it in R. 
library(openxlsx) 

#If your data is in the current working directory, you can simply do:
data <- read.xlsx("filename.xlsx")

# If your data is not in the corrent woking directory, you need to give R the path to the data, such as 
data <- read.xlsx("/Users/yaoyao/Documents/PLSC309/Lab1/filename.xlsx") # do not run

Now you might see the reason why Notebook assumes the folder containing your current ``.Rmd’’ file as the working directory. It is a good habit to keep all the relevant files for one project in one folder.

2.2.2 Read a comma-seperated (.csv) file

# If your data is in the current working directory, you can simply do:
ANES <- read.csv("cleaned_ANES.csv")
# If your data is not in the corrent woking directory, you need to give the path to the data, such as
turnout <- read.csv("/Users/yaoyao/Documents/PLSC309/Lab1/turnout.csv")

2.2.3 Read a R data (.Rdata) file

load("filename.Rdata")

2.2.4 Read a Stata (.dta, versions 12 and earlier) file

library(foreign)
data<-read.dta("filename.dta")

2.2.5 Read a Stata (.dta, versions 13 and 14) file

The ``foreign’’ pack does not support stata data after version 12. We can use “readstat13” to import from the later versions of stata instead.

library(readstata13)
# Read from stata version 13&14
data<-read.dta13("filename.dta")

2.2.6 Read .sav (SPSS) file

library(foreign)
data <- read.spss("filename.sav", to.data.frame = TRUE)

2.2.7 Read a Tab deliminted (.tab or .txt) file

data <- read.table("JoP_R_data.txt",sep="\t")

2.3 Arguments within read function

In some cases, you need to specify additional information of the data in the data importing function to be able to load the data in R in addition to the path and file name. You can get information about the arguments and their default in the R documents using the help() function.

help("read.table")
?read.table

#You will find all the arguemtns inside the function, and see their default:
read.table(file, header = FALSE, sep = "", quote = "\"'",
           dec = ".", numerals = c("allow.loss", "warn.loss", "no.loss"),
           row.names, col.names, as.is = !stringsAsFactors,
           na.strings = "NA", colClasses = NA, nrows = -1,
           skip = 0, check.names = TRUE, fill = !blank.lines.skip,
           strip.white = FALSE, blank.lines.skip = TRUE,
           comment.char = "#",
           allowEscapes = FALSE, flush = FALSE,
           stringsAsFactors = default.stringsAsFactors(),
           fileEncoding = "", encoding = "unknown", text, skipNul = FALSE)

read.csv(file, header = TRUE, sep = ",", quote = "\"",
         dec = ".", fill = TRUE, comment.char = "", ...)
#Practice and review what arguements are there inside different data import fuctions
?read.csv
?read.xlsx
?read.spss

2.3.1 Some useful arguments within read function

1. header

The header argument tells R whether to treat the first row of the data as the variable names. In the examples above, you probably have noticed that the default header argument in read.table is FALSE, while the default header argument in read.csv is TRUE. It means that by default, read.table() function will not treat the top row of the data as the variable name. If the first row of your data is the variable name, you’d want to change the default from FALSE to TRUE:

# If the first row of your data contains the variable names, you need to specify the header argument to TRUE in read.table. You do not need to specify the header to TRUE in read.csv, as it is the default in read.csv.
read.table(file, header = TRUE)
# If the first row of your csv data is not the variable names, you need to change the default of header in read.csv to FALSE
read.csv(file, header = FALSE)

2. sep

The sep argument tell R how to separate the values in the raw data. The default of read.table is sep=“”, which tells R to separate values on one or more white spaces. For example, under this default, ``Penn State’’ will be treated as two values, and will be put into two columns in a data frame.

If your data is not white space separated, you need to change this default accordingly. In the ``Penn State’’ example, the “Penn State” might be one variable, and should be put into one column instead of two. In this case, the data is not separated by white space, but tabs. If your data is tab separated, you need to change the sep argument to \("\t"\):

read.table(file, sep="\t")

If your data is comma separated, the sep argument should be “,” which is the default in read.csv.

3. to.data.frame in read.spss

When you read a SPSS data into R, the read.spss() function does not change the format of the data as a data frame. However, as most of our analyses are on a data frame, you’d want to change this default when you read a SPSS file:

read.spss(file, to.data.frame = TRUE)

2.4 Create data frame in R

#Create your variables
PSUScore <- c(52,33,56,21,45,31)
RivalScore <- c(0,14,0,19,14,7)
Win <- c(1,1,1,1,1,1)
Against <- c("Akron","Pittsburgh","Georgia State","Iowa","Indiana","Northwestern")

#Turn those variables into a date frame
NittanyLions2017 <- data.frame(Against,PSUScore,RivalScore,Win)

3 View data

In addition to the View() function, there are many other useful functions for getting information on your data.

3.1 View some basic features

# list all the objects in your current working environment
ls()
# list the variable names
names(ANES)
# dimension of your data
dim(ANES)
# view the first 2 rows in the data
head(ANES,n=2)
# view the last 2 rows in the data
tail(ANES,n=2)
# class of an object
class(ANES)
class(ANES$NPR)
# view summary statistics of a variable
summary(turnout$NPR)

3.2 Subset data

# hand pick rows and columns of a data
ANES[c(1,2),c(2,3)] # first two rows and second and third column
# exclude certain rows and columns
ANES[-1, -c(1,2,3)] # exclude the first row and first three columns 
# select more than one variables
ANES[c("NPR","rush","hannity")]
# select based on the values of observations
ANES[which(ANES$NPR==1),]
# select based on multiple critieria
ANES[which(ANES$Dem.Pres.cand.FT >=20 & ANES$GOP.Pres.cand.FT >= 20),] # select the respondents whose feeling thermometer scores towards Clinton AND Trump are BOTH bigger or equal to 20 
ANES[which(ANES$Dem.Pres.cand.FT >=20 | ANES$GOP.Pres.cand.FT >= 20),] # select the respondents whose feeling thermometer score towards Clinton OR Trump is bigger or equal to 20 
# subet use the subset fuction
subset(ANES, ANES$Dem.Pres.cand.FT >=20 | ANES$GOP.Pres.cand.FT >= 20) 

3.3 Sort data

You can sort your data on one or more variables, and you can set the order to be ascending or descending

# the order function returns a permutation which rearranges its first argument into ascending or descending order. The default is ascending. 
order(ANES$Dem.Pres.cand.FT)
# change into descending order using the decreasing argument inside order()
order(ANES$Dem.Pres.cand.FT, decreasing = TRUE)
# Sort the turnout data based on the ascending order of ANES 
ordered.ANES <- ANES[order(ANES$Dem.Pres.cand.FT,decreasing = TRUE),]
# Note after ordering, the NAs will always be at the end no matter whether the order is ascending ot descending

4 Manipulate data

The data sets you have been using at class have already been cleaned. They are in the correct formats and contains everything you need for the class analysis. However, in reality when you use other people’s data or download data online, you might need to use several variables in the data to calculate the variable you are interested in, and you might need to correct the class of a variable, and you might need to recode the values in the data.

4.1 Create new variables

Some times, you need to use multiple variables in a date set to create a variable of your interest. Instead of calculating the value every time when you need to use the variable, it is more convenient to create such variable first and add the new variable to the data set.

# Add a new variable Diff.FT to the ANES data frame
ANES$Diff.FT <- ANES$GOP.Pres.cand.FT - ANES$Dem.Pres.cand.FT

4.2 Recode values

4.2.1 Change the class

A data set generally contains variables with different class/characteristics, such as numeric, character, factor and logical. When analyzing the data, sometimes you need to convert the class of the variable.

# check whether the variable is certain class
is.numeric()
is.character()
is.factor()
# convert to the correct class for the analysis
as.numeric()
as.character()
as.factor()

4.2.2 Change the value

When doing analysis, we often need to recode some of the values. For example, in survey data, the gender might be coded as “female” or “male” and we want to recode it as 0 and 1. We can use the recode function from the package car.

First, install and load the package Car:

# Install the car package, you only need to instal once
install.packages("car")

# Load the car package
library(car)

Second, try the recode function!

  • Change all the 1 into “female” and all the 0 into “male” in the female variable in ANES data
ANES$female <- recode(ANES$female, "1 = 'female';0 = 'male'")
  • Change a range of data into certain value: recode the feeling thermometer scores less than 25 into 1 (meaning “very negative”), 25 to 49 into 2 (meaning “somewhat negative”), 50 to 74 into 3 (meaning “somewhat positive”), and 75 to 100 into 4 (meaning “very positive”)
ANES$Dem.Pres.cand.FT <- recode(ANES$Dem.Pres.cand.FT, "0:24=1; 25:49=2;50:74=3;75:100=4;else=NA")
  • After recoding the value, always double check the recoded variable
table(ANES$female)
summary(ANES$Dem.Pres.cand.FT)

Sometimes, you might only want to change one specific cell. For example, you find the value for a NA cell. You can recode that cell by locating its row.

# For example, I find that the first missing value in the feeling thermometer towards Clinton should be 39
ANES$Dem.Pres.cand.FT[which(is.na(ANES$Dem.Pres.cand.FT))[1]] <- 39

5 Export Data

Note that the changes you made in R and R environment do not change the data in your folder. Therefore, after recoding or adding variables, you will want to save the updated data in your computer, so you do not need to repeat the data manipulation. Using the same packages, we can save/export the data you created or worked in R to your computer as various formats. However, csv format is recommended.

5.1 Save data as csv file

# write the data to the current working directory
write.csv(ANES,"updatedANES.csv")
# write the data to other folders in your computer
write.csv(ANES,"path/updatedANES.csv")

5.2 Save data as other format

# Excel
write.xlsx(ANES,"updatedANES.xlsx")
# Stata
write.dta(ANES,"updatedANES.dta")

Helpsheet made for PLSC 309 by Yaoyao Dai

LS0tCnRpdGxlOiAiSW1wb3J0LCBNYW5pcHVsYXRlIGFuZCBTYXZlIERhdGEgaW4gUiIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IAogICAgdGhlbWU6IGNlcnVsZWFuCiAgICBudW1iZXJfc2VjdGlvbnM6IFRSVUUKICAgIHRvYzogVFJVRQogICAgdG9jX2RlcHRoOiAyCiAgICB0b2NfZmxvYXQ6IAogICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICBzbW9vdGhfc2Nyb2xsOiBUUlVFCi0tLQoKKioqCllvdSBjYW4gaW1wb3J0IGFsbCBraW5kcyBvZiBkYXRhIGZvcm1hdCBpbiBSIHVzaW5nIHZhcmlvdXMgcGFja2FnZXMuIFlvdSBzaW1wbHkgbmVlZCB0byB0ZWxsIFIgd2hlcmUgdG8gZmluZCB0aGUgZGF0YSBpbiB5b3VyIGNvbXB1dGVyIC0tIHRoZSBkaXJlY3Rvcnkgb3IgdGhlIHBhdGguIFRoZXJlZm9yZSwgYmVmb3JlIHdlIHN0YXJ0IGxvYWRpbmcgZGF0YSBpbiBSLCBsZXQncyBmaXJzdCBzZWUgaG93IGNhbiB3ZSBzZXQgYW5kIGNoYW5nZSB0aGUgd29ya2luZyBkaXJlY3RvcnkuIAoKIyBTZXQgdGhlIFdvcmtpbmcgRGlyZWN0b3J5CgpBIHdvcmtpbmcgZGlyZWN0b3J5IGlzIGEgaGllcmFyY2hpY2FsIGZpbGUgc3lzdGVtLCBvciB5b3UgY2FuIHNpbXBsZSBjb25zaWRlciBpdCBhcyB0aGUgcGF0aCB0byB0aGUgZmlsZSBvciBmb2xkZXIgeW91IHdhbnQgdG8gdXNlLiAKCiMjIEluIGFuIFIgZmlsZSAobm90IFIgTm90ZWJvb2spCmBgYHtyfQojdmlldyB5b3VyIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkKZ2V0d2QoKQoKI2NoYW5nZSB0aGUgd29ya2luZyBkaXJlY3RvcnkgdG8geW91ciBwcm9qZWN0IGZvbGRlcgpzZXR3ZCgiL1VzZXJzL3lhb3lhby9Eb2N1bWVudHMvUExTQzMwOS9MYWIxIikKYGBgCmBgYHtyfQojdmlldyB3aGF0IGlzIGluc2lkZSB0aGlzIHdvcmtpbmcgZGlyZWN0b3J5CmRpcigpCmBgYAoKIyMgSW4gYW4gUiBOb3RlYm9vayBGaWxlCgpJbiBSIE5vdGVib29rLCB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSBpbnNpZGUgYSBub3RlYm9vayBjaHVuayBpcyBhbHdheXMgdGhlIGRpcmVjdG9yeS9mb2xkZXIgY29udGFpbmluZyB0aGF0IC5SbWQgZmlsZS4gRm9yIGV4YW1wbGUsIGluIHlvdXIgTGFiIGFzc2lnbm1lbnQsIHlvdSBoYXZlIGNyZWF0ZWQgTmFtZV9MYWIxLlJtZCBmaWxlLiBJZiB5b3UgY3JlYXRlZCBhbmQgc2F2ZWQgdGhlIHRoZSBsYWIxLlJtZCBmaWxlIGluc2lkZSBhIGZvbGRlciBjYWxsZWQgImxhYjEiIHVuZGVyICJQTFNDMzA5IiBmb2xkZXIsIHRoZSB3b3JraW5nIGRpcmVjdG9yeSB3b3VsZCBiZSB0aGUgcGF0aCBhbGwgdGhlIHdheSB0byBmb2xkZXIgIkxhYjEiLiAKCldoYXQgaGFwcGVucyBpZiB5b3Ugd2FudCB0byBzZXQgdGhlIHdvcmtpbmcgZGlyZWN0b3J5IGVsc2V3aGVyZSBpbiBSIE5vdGVib29rPwoKYGBge3J9CiMgT25seSBjaGFuZ2VzIHdvcmtpbmcgZGlyZWN0b3J5IGluIHRoaXMgY29kZSBjaHVuay4gIApzZXR3ZCgiL1VzZXJzL3lhb3lhby9Eb2N1bWVudHMvUExTQzMwOSIpCmBgYAoKVGhlIHdhcm5pbmcgbWVzc2FnZSB5b3Ugc2VlIGFib3ZlIHRlbGxzIHVzIHRoYXQgdGhlIHNldHdkKCApIGNvbW1hbmQgY2FuIG9ubHkgY2hhbmdlIHRoZSB3b3JraW5nIGRpcmVjdG9yeSBpbiB0aGF0IG9uZSBjb2RlIGNodW5rLiBGb3IgdGhlIHJlc3Qgb2YgdGhlIG5vdGVib29rLCB0aGUgd29ya2luZyBkaXJlY3RvcnkgaXMgc3RpbGwgdGhlIHBhdGggdG8gdGhlIGZvbGRlciB3aGVyZSB5b3Ugc2F2ZSB5b3VyIC5SbWQgZmlsZS4gCgpUaGVyZSBpcyBvbmx5IG9uZSB3YXkgdG8gY2hhbmdlIHdvcmtpbmcgZGlyZWN0b3J5IGdsb2JhbGx5IGZvciBhbGwgdGhlIGNvZGUgY2h1bmtzIGluIGEgbm90ZWJvb2sgZmlsZS4gVGhlIG1ldGhvZCBpcyBzaG93biBiZWxvdywgYW5kIHlvdSBoYXZlIHRvIHVzZSBpdCBpbiB0aGUgc2V0dXAgY2h1bms6IGJlZ2luIHdpdGggPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+e3Igc2V0dXB9PC9zcGFuPiBpbnN0ZWFkIG9mIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPntyfTwvc3Bhbj46CgpgYGB7ciBzZXR1cH0KI2NoYW5nZSB3b3JraW5nIGRpcmVjdG9yeSBmb3IgYWxsIHRoZSBjb2RlIGNodW5rcyBpbiBhIG5vdGVib29rIAprbml0cjo6b3B0c19rbml0JHNldChyb290LmRpciA9IG5vcm1hbGl6ZVBhdGgoIi9Vc2Vycy95YW95YW8vRG9jdW1lbnRzL1BMU0MzMDkvTGFiMSIpKSAKYGBgCgpUaGlzIGlzIG5vdCB2ZXJ5IGludHVpdGl2ZSEgWW91IGNhbiBhdm9pZCBjaGFuZ2luZyB0aGUgd29ya2luZyBkaXJlY3RvcnkgaWYgeW91ICphbHdheXMqIHB1dCB0aGUgcmVsZXZhbnQgZmlsZXMgaW4gdGhlIHNhbWUgZm9sZGVyIGFzIHlvdSBzYXZlIHRoZSAuUm1kIE5vdGVib29rIGZpbGUuCgoqKioKCiNJbXBvcnQgRGF0YSAKCiMjSW5zdGFsbCBwYWNrYWdlcwoKWW91IGNhbiBpbXBvcnQgYWxsIGtpbmRzIG9mIGRhdGEgZm9ybWF0IGluIFIgdXNpbmcgdmFyaW91cyBwYWNrYWdlcy4gVG8gdXNlIHRob3NlIHBhY2thZ2VzLCB5b3UgZmlyc3QgbmVlZCB0byBpbnN0YWxsIHRoZW0uIFlvdSBvbmx5IG5lZWQgdG8gZG8gdGhpcyBvbmNlLgoKRmlsZSBUeXBlIHwgUGFja2FnZSB8IEZ1bmN0aW9uCi0tLS0tLS0tLS18LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tCkV4Y2VsICgueGxzeCl8IG9wZW5zbHhzIHwgcmVhZC54bHN4ClN0YXRhICguZHRhLCB2ZXJzaW9ucyAxMiBhbmQgZWFybGllcikgfCBmb3JlaWduIHwgcmVhZC5kdGEKU3RhdGEgKC5kdGEsIHZlcnNpb25zIDEzIGFuZCAxNCkgfCByZWFkc3RhdGExMyB8cmVhZC5kdGExMwpTUFNTICguc2F2KSB8IGZvcmVpZ24gfCByZWFkLnNwc3MKQ29tbWEgc2VwYXJhdGVkICguY3N2KSB8IG5vbmUgfCByZWFkLmNzdgpUYWIgZGVsaW1pdGVkICgudGFiIG9yIC50eHQpIHwgbm9uZSB8IHJlYWQudGFibGUKUiBkYXRhIGZpbGVzICguUmRhdGEpIHwgbm9uZSB8IGxvYWQKCmBgYHtyfQojSW5zdGFsbCBuZWNlc3NhcnkgcGFja2FnZXMsIHlvdSBvbmx5IG5lZWQgdG8gZG8gdGhpcyBvbmNlCmluc3RhbGwucGFja2FnZXMoIm9wZW54bHN4IikKaW5zdGFsbC5wYWNrYWdlcygiZm9yZWlnbiIpCmluc3RhbGwucGFja2FnZXMoInJlYWRzdGF0YTEzIikKYGBgCgojIyBMb2FkIHBhY2thZ2VzIGFuZCBpbXBvcnQgZGF0YQoKQWx0aG91Z2ggeW91IG9ubHkgbmVlZCB0byBpbnN0YWxsIHBhY2thZ2VzIHRvIFIgb25jZSwgeW91IG5lZWQgdG8gbG9hZCB0aGUgcmVxdWlyZWQgcGFja2FnZXMgaW4gUiB1c2luZyB0aGUgbGlicmFyeSgpIGZ1bmN0aW9uIGJlZm9yZSB5b3UgYW5hbHlzaXMgZXZlcnkgdGltZSBpbiB0aGUgYmVnaW5uaW5nIG9mIHlvdXIgUiBzZXNzaW9uLiAgCgoKIyMjIFJlYWQgRXhjZWwgZmlsZSAKCmBgYHtyfQojWW91IG5lZWQgdG8gbGlicmFyeSgpIGEgcGFja2FnZSBiZWZvcmUgdXNpbmcgaXQgaW4gUi4gCmxpYnJhcnkob3Blbnhsc3gpIAoKI0lmIHlvdXIgZGF0YSBpcyBpbiB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSwgeW91IGNhbiBzaW1wbHkgZG86CmRhdGEgPC0gcmVhZC54bHN4KCJmaWxlbmFtZS54bHN4IikKCiMgSWYgeW91ciBkYXRhIGlzIG5vdCBpbiB0aGUgY29ycmVudCB3b2tpbmcgZGlyZWN0b3J5LCB5b3UgbmVlZCB0byBnaXZlIFIgdGhlIHBhdGggdG8gdGhlIGRhdGEsIHN1Y2ggYXMgCmRhdGEgPC0gcmVhZC54bHN4KCIvVXNlcnMveWFveWFvL0RvY3VtZW50cy9QTFNDMzA5L0xhYjEvZmlsZW5hbWUueGxzeCIpICMgZG8gbm90IHJ1bgpgYGAKTm93IHlvdSBtaWdodCBzZWUgdGhlIHJlYXNvbiB3aHkgTm90ZWJvb2sgYXNzdW1lcyB0aGUgZm9sZGVyIGNvbnRhaW5pbmcgeW91ciBjdXJyZW50IGBgLlJtZCcnIGZpbGUgYXMgdGhlIHdvcmtpbmcgZGlyZWN0b3J5LiBJdCBpcyBhIGdvb2QgaGFiaXQgdG8ga2VlcCBhbGwgdGhlIHJlbGV2YW50IGZpbGVzIGZvciBvbmUgcHJvamVjdCBpbiBvbmUgZm9sZGVyLiAKCiMjIyBSZWFkIGEgY29tbWEtc2VwZXJhdGVkICguY3N2KSBmaWxlIApgYGB7cn0KIyBJZiB5b3VyIGRhdGEgaXMgaW4gdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnksIHlvdSBjYW4gc2ltcGx5IGRvOgpBTkVTIDwtIHJlYWQuY3N2KCJjbGVhbmVkX0FORVMuY3N2IikKIyBJZiB5b3VyIGRhdGEgaXMgbm90IGluIHRoZSBjb3JyZW50IHdva2luZyBkaXJlY3RvcnksIHlvdSBuZWVkIHRvIGdpdmUgdGhlIHBhdGggdG8gdGhlIGRhdGEsIHN1Y2ggYXMKdHVybm91dCA8LSByZWFkLmNzdigiL1VzZXJzL3lhb3lhby9Eb2N1bWVudHMvUExTQzMwOS9MYWIxL3R1cm5vdXQuY3N2IikKYGBgCgojIyMgUmVhZCBhIFIgZGF0YSAoLlJkYXRhKSBmaWxlCgpgYGB7cn0KbG9hZCgiZmlsZW5hbWUuUmRhdGEiKQpgYGAKCiMjIyBSZWFkIGEgU3RhdGEgKC5kdGEsIHZlcnNpb25zIDEyIGFuZCBlYXJsaWVyKSBmaWxlIAoKYGBge3J9CmxpYnJhcnkoZm9yZWlnbikKZGF0YTwtcmVhZC5kdGEoImZpbGVuYW1lLmR0YSIpCmBgYAoKIyMjIFJlYWQgYSBTdGF0YSAoLmR0YSwgdmVyc2lvbnMgMTMgYW5kIDE0KSBmaWxlCgpUaGUgYGBmb3JlaWduJycgcGFjayBkb2VzIG5vdCBzdXBwb3J0IHN0YXRhIGRhdGEgYWZ0ZXIgdmVyc2lvbiAxMi4gV2UgY2FuIHVzZSAicmVhZHN0YXQxMyIgdG8gaW1wb3J0IGZyb20gdGhlIGxhdGVyIHZlcnNpb25zIG9mIHN0YXRhIGluc3RlYWQuCgpgYGB7cn0KbGlicmFyeShyZWFkc3RhdGExMykKIyBSZWFkIGZyb20gc3RhdGEgdmVyc2lvbiAxMyYxNApkYXRhPC1yZWFkLmR0YTEzKCJmaWxlbmFtZS5kdGEiKQpgYGAKCiMjIyBSZWFkIC5zYXYgKFNQU1MpIGZpbGUgCgpgYGB7cn0KbGlicmFyeShmb3JlaWduKQpkYXRhIDwtIHJlYWQuc3BzcygiZmlsZW5hbWUuc2F2IiwgdG8uZGF0YS5mcmFtZSA9IFRSVUUpCmBgYAoKIyMjIFJlYWQgYSBUYWIgZGVsaW1pbnRlZCAoLnRhYiBvciAudHh0KSBmaWxlCmBgYHtyfQpkYXRhIDwtIHJlYWQudGFibGUoIkpvUF9SX2RhdGEudHh0IixzZXA9Ilx0IikKYGBgCgojIyBBcmd1bWVudHMgd2l0aGluIHJlYWQgZnVuY3Rpb24KSW4gc29tZSBjYXNlcywgeW91IG5lZWQgdG8gc3BlY2lmeSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIG9mIHRoZSBkYXRhIGluIHRoZSBkYXRhIGltcG9ydGluZyBmdW5jdGlvbiB0byBiZSBhYmxlIHRvIGxvYWQgdGhlIGRhdGEgaW4gUiBpbiBhZGRpdGlvbiB0byB0aGUgcGF0aCBhbmQgZmlsZSBuYW1lLiBZb3UgY2FuIGdldCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgYXJndW1lbnRzIGFuZCB0aGVpciBkZWZhdWx0IGluIHRoZSBSIGRvY3VtZW50cyB1c2luZyB0aGUgaGVscCgpIGZ1bmN0aW9uLiAKYGBge3J9CmhlbHAoInJlYWQudGFibGUiKQo/cmVhZC50YWJsZQoKI1lvdSB3aWxsIGZpbmQgYWxsIHRoZSBhcmd1ZW10bnMgaW5zaWRlIHRoZSBmdW5jdGlvbiwgYW5kIHNlZSB0aGVpciBkZWZhdWx0OgpyZWFkLnRhYmxlKGZpbGUsIGhlYWRlciA9IEZBTFNFLCBzZXAgPSAiIiwgcXVvdGUgPSAiXCInIiwKICAgICAgICAgICBkZWMgPSAiLiIsIG51bWVyYWxzID0gYygiYWxsb3cubG9zcyIsICJ3YXJuLmxvc3MiLCAibm8ubG9zcyIpLAogICAgICAgICAgIHJvdy5uYW1lcywgY29sLm5hbWVzLCBhcy5pcyA9ICFzdHJpbmdzQXNGYWN0b3JzLAogICAgICAgICAgIG5hLnN0cmluZ3MgPSAiTkEiLCBjb2xDbGFzc2VzID0gTkEsIG5yb3dzID0gLTEsCiAgICAgICAgICAgc2tpcCA9IDAsIGNoZWNrLm5hbWVzID0gVFJVRSwgZmlsbCA9ICFibGFuay5saW5lcy5za2lwLAogICAgICAgICAgIHN0cmlwLndoaXRlID0gRkFMU0UsIGJsYW5rLmxpbmVzLnNraXAgPSBUUlVFLAogICAgICAgICAgIGNvbW1lbnQuY2hhciA9ICIjIiwKICAgICAgICAgICBhbGxvd0VzY2FwZXMgPSBGQUxTRSwgZmx1c2ggPSBGQUxTRSwKICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gZGVmYXVsdC5zdHJpbmdzQXNGYWN0b3JzKCksCiAgICAgICAgICAgZmlsZUVuY29kaW5nID0gIiIsIGVuY29kaW5nID0gInVua25vd24iLCB0ZXh0LCBza2lwTnVsID0gRkFMU0UpCgpyZWFkLmNzdihmaWxlLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIsIHF1b3RlID0gIlwiIiwKICAgICAgICAgZGVjID0gIi4iLCBmaWxsID0gVFJVRSwgY29tbWVudC5jaGFyID0gIiIsIC4uLikKYGBgCgpgYGB7cn0KI1ByYWN0aWNlIGFuZCByZXZpZXcgd2hhdCBhcmd1ZW1lbnRzIGFyZSB0aGVyZSBpbnNpZGUgZGlmZmVyZW50IGRhdGEgaW1wb3J0IGZ1Y3Rpb25zCj9yZWFkLmNzdgo/cmVhZC54bHN4Cj9yZWFkLnNwc3MKYGBgCgojIyMgU29tZSB1c2VmdWwgYXJndW1lbnRzIHdpdGhpbiByZWFkIGZ1bmN0aW9uCgoqKjEuIGhlYWRlcioqCgpUaGUgaGVhZGVyIGFyZ3VtZW50IHRlbGxzIFIgd2hldGhlciB0byB0cmVhdCB0aGUgZmlyc3Qgcm93IG9mIHRoZSBkYXRhIGFzIHRoZSB2YXJpYWJsZSBuYW1lcy4gSW4gdGhlIGV4YW1wbGVzIGFib3ZlLCB5b3UgcHJvYmFibHkgaGF2ZSBub3RpY2VkIHRoYXQgdGhlIGRlZmF1bHQgaGVhZGVyIGFyZ3VtZW50IGluIHJlYWQudGFibGUgaXMgRkFMU0UsIHdoaWxlIHRoZSBkZWZhdWx0IGhlYWRlciBhcmd1bWVudCBpbiByZWFkLmNzdiBpcyBUUlVFLiBJdCBtZWFucyB0aGF0IGJ5IGRlZmF1bHQsIHJlYWQudGFibGUoKSBmdW5jdGlvbiB3aWxsIG5vdCB0cmVhdCB0aGUgdG9wIHJvdyBvZiB0aGUgZGF0YSBhcyB0aGUgdmFyaWFibGUgbmFtZS4gSWYgdGhlIGZpcnN0IHJvdyBvZiB5b3VyIGRhdGEgaXMgdGhlIHZhcmlhYmxlIG5hbWUsIHlvdSdkIHdhbnQgdG8gY2hhbmdlIHRoZSBkZWZhdWx0IGZyb20gRkFMU0UgdG8gVFJVRToKCmBgYHtyfQojIElmIHRoZSBmaXJzdCByb3cgb2YgeW91ciBkYXRhIGNvbnRhaW5zIHRoZSB2YXJpYWJsZSBuYW1lcywgeW91IG5lZWQgdG8gc3BlY2lmeSB0aGUgaGVhZGVyIGFyZ3VtZW50IHRvIFRSVUUgaW4gcmVhZC50YWJsZS4gWW91IGRvIG5vdCBuZWVkIHRvIHNwZWNpZnkgdGhlIGhlYWRlciB0byBUUlVFIGluIHJlYWQuY3N2LCBhcyBpdCBpcyB0aGUgZGVmYXVsdCBpbiByZWFkLmNzdi4KcmVhZC50YWJsZShmaWxlLCBoZWFkZXIgPSBUUlVFKQojIElmIHRoZSBmaXJzdCByb3cgb2YgeW91ciBjc3YgZGF0YSBpcyBub3QgdGhlIHZhcmlhYmxlIG5hbWVzLCB5b3UgbmVlZCB0byBjaGFuZ2UgdGhlIGRlZmF1bHQgb2YgaGVhZGVyIGluIHJlYWQuY3N2IHRvIEZBTFNFCnJlYWQuY3N2KGZpbGUsIGhlYWRlciA9IEZBTFNFKQpgYGAKCgoqKjIuIHNlcCoqCgpUaGUgc2VwIGFyZ3VtZW50IHRlbGwgUiBob3cgdG8gc2VwYXJhdGUgdGhlIHZhbHVlcyBpbiB0aGUgcmF3IGRhdGEuIFRoZSBkZWZhdWx0IG9mIHJlYWQudGFibGUgaXMgc2VwPSIiLCB3aGljaCB0ZWxscyBSIHRvIHNlcGFyYXRlIHZhbHVlcyBvbiBvbmUgb3IgbW9yZSB3aGl0ZSBzcGFjZXMuIEZvciBleGFtcGxlLCB1bmRlciB0aGlzIGRlZmF1bHQsIGBgUGVubiBTdGF0ZScnIHdpbGwgYmUgdHJlYXRlZCBhcyB0d28gdmFsdWVzLCBhbmQgd2lsbCBiZSBwdXQgaW50byB0d28gY29sdW1ucyBpbiBhIGRhdGEgZnJhbWUuIAoKSWYgeW91ciBkYXRhIGlzIG5vdCB3aGl0ZSBzcGFjZSBzZXBhcmF0ZWQsIHlvdSBuZWVkIHRvIGNoYW5nZSB0aGlzIGRlZmF1bHQgYWNjb3JkaW5nbHkuIEluIHRoZSBgYFBlbm4gU3RhdGUnJyBleGFtcGxlLCB0aGUgIlBlbm4gU3RhdGUiIG1pZ2h0IGJlIG9uZSB2YXJpYWJsZSwgYW5kIHNob3VsZCBiZSBwdXQgaW50byBvbmUgY29sdW1uIGluc3RlYWQgb2YgdHdvLiBJbiB0aGlzIGNhc2UsIHRoZSBkYXRhIGlzIG5vdCBzZXBhcmF0ZWQgYnkgd2hpdGUgc3BhY2UsIGJ1dCB0YWJzLiBJZiB5b3VyIGRhdGEgaXMgdGFiIHNlcGFyYXRlZCwgeW91IG5lZWQgdG8gY2hhbmdlIHRoZSBzZXAgYXJndW1lbnQgdG8gJCJcdCIkOgoKYGBge3J9CnJlYWQudGFibGUoZmlsZSwgc2VwPSJcdCIpCmBgYAoKSWYgeW91ciBkYXRhIGlzIGNvbW1hIHNlcGFyYXRlZCwgdGhlIHNlcCBhcmd1bWVudCBzaG91bGQgYmUgIiwiIHdoaWNoIGlzIHRoZSBkZWZhdWx0IGluIHJlYWQuY3N2LiAKCioqMy4gdG8uZGF0YS5mcmFtZSBpbiByZWFkLnNwc3MqKgoKV2hlbiB5b3UgcmVhZCBhIFNQU1MgZGF0YSBpbnRvIFIsIHRoZSByZWFkLnNwc3MoKSBmdW5jdGlvbiBkb2VzIG5vdCBjaGFuZ2UgdGhlIGZvcm1hdCBvZiB0aGUgZGF0YSBhcyBhIGRhdGEgZnJhbWUuIEhvd2V2ZXIsIGFzIG1vc3Qgb2Ygb3VyIGFuYWx5c2VzIGFyZSBvbiBhIGRhdGEgZnJhbWUsIHlvdSdkIHdhbnQgdG8gY2hhbmdlIHRoaXMgZGVmYXVsdCB3aGVuIHlvdSByZWFkIGEgU1BTUyBmaWxlOgoKYGBge3J9CnJlYWQuc3BzcyhmaWxlLCB0by5kYXRhLmZyYW1lID0gVFJVRSkKYGBgCgoKIyMgQ3JlYXRlIGRhdGEgZnJhbWUgaW4gUgoKYGBge3J9CiNDcmVhdGUgeW91ciB2YXJpYWJsZXMKUFNVU2NvcmUgPC0gYyg1MiwzMyw1NiwyMSw0NSwzMSkKUml2YWxTY29yZSA8LSBjKDAsMTQsMCwxOSwxNCw3KQpXaW4gPC0gYygxLDEsMSwxLDEsMSkKQWdhaW5zdCA8LSBjKCJBa3JvbiIsIlBpdHRzYnVyZ2giLCJHZW9yZ2lhIFN0YXRlIiwiSW93YSIsIkluZGlhbmEiLCJOb3J0aHdlc3Rlcm4iKQoKI1R1cm4gdGhvc2UgdmFyaWFibGVzIGludG8gYSBkYXRlIGZyYW1lCk5pdHRhbnlMaW9uczIwMTcgPC0gZGF0YS5mcmFtZShBZ2FpbnN0LFBTVVNjb3JlLFJpdmFsU2NvcmUsV2luKQpgYGAKCgojVmlldyBkYXRhCgpJbiBhZGRpdGlvbiB0byB0aGUgVmlldygpIGZ1bmN0aW9uLCB0aGVyZSBhcmUgbWFueSBvdGhlciB1c2VmdWwgZnVuY3Rpb25zIGZvciBnZXR0aW5nIGluZm9ybWF0aW9uIG9uIHlvdXIgZGF0YS4KCiMjIFZpZXcgc29tZSBiYXNpYyBmZWF0dXJlcyAKCmBgYHtyfQojIGxpc3QgYWxsIHRoZSBvYmplY3RzIGluIHlvdXIgY3VycmVudCB3b3JraW5nIGVudmlyb25tZW50CmxzKCkKIyBsaXN0IHRoZSB2YXJpYWJsZSBuYW1lcwpuYW1lcyhBTkVTKQojIGRpbWVuc2lvbiBvZiB5b3VyIGRhdGEKZGltKEFORVMpCiMgdmlldyB0aGUgZmlyc3QgMiByb3dzIGluIHRoZSBkYXRhCmhlYWQoQU5FUyxuPTIpCiMgdmlldyB0aGUgbGFzdCAyIHJvd3MgaW4gdGhlIGRhdGEKdGFpbChBTkVTLG49MikKIyBjbGFzcyBvZiBhbiBvYmplY3QKY2xhc3MoQU5FUykKY2xhc3MoQU5FUyROUFIpCiMgdmlldyBzdW1tYXJ5IHN0YXRpc3RpY3Mgb2YgYSB2YXJpYWJsZQpzdW1tYXJ5KHR1cm5vdXQkTlBSKQpgYGAKCiMjIFN1YnNldCBkYXRhIAoKYGBge3J9CiMgaGFuZCBwaWNrIHJvd3MgYW5kIGNvbHVtbnMgb2YgYSBkYXRhCkFORVNbYygxLDIpLGMoMiwzKV0gIyBmaXJzdCB0d28gcm93cyBhbmQgc2Vjb25kIGFuZCB0aGlyZCBjb2x1bW4KIyBleGNsdWRlIGNlcnRhaW4gcm93cyBhbmQgY29sdW1ucwpBTkVTWy0xLCAtYygxLDIsMyldICMgZXhjbHVkZSB0aGUgZmlyc3Qgcm93IGFuZCBmaXJzdCB0aHJlZSBjb2x1bW5zIAojIHNlbGVjdCBtb3JlIHRoYW4gb25lIHZhcmlhYmxlcwpBTkVTW2MoIk5QUiIsInJ1c2giLCJoYW5uaXR5IildCiMgc2VsZWN0IGJhc2VkIG9uIHRoZSB2YWx1ZXMgb2Ygb2JzZXJ2YXRpb25zCkFORVNbd2hpY2goQU5FUyROUFI9PTEpLF0KIyBzZWxlY3QgYmFzZWQgb24gbXVsdGlwbGUgY3JpdGllcmlhCkFORVNbd2hpY2goQU5FUyREZW0uUHJlcy5jYW5kLkZUID49MjAgJiBBTkVTJEdPUC5QcmVzLmNhbmQuRlQgPj0gMjApLF0gIyBzZWxlY3QgdGhlIHJlc3BvbmRlbnRzIHdob3NlIGZlZWxpbmcgdGhlcm1vbWV0ZXIgc2NvcmVzIHRvd2FyZHMgQ2xpbnRvbiBBTkQgVHJ1bXAgYXJlIEJPVEggYmlnZ2VyIG9yIGVxdWFsIHRvIDIwIApBTkVTW3doaWNoKEFORVMkRGVtLlByZXMuY2FuZC5GVCA+PTIwIHwgQU5FUyRHT1AuUHJlcy5jYW5kLkZUID49IDIwKSxdICMgc2VsZWN0IHRoZSByZXNwb25kZW50cyB3aG9zZSBmZWVsaW5nIHRoZXJtb21ldGVyIHNjb3JlIHRvd2FyZHMgQ2xpbnRvbiBPUiBUcnVtcCBpcyBiaWdnZXIgb3IgZXF1YWwgdG8gMjAgCiMgc3ViZXQgdXNlIHRoZSBzdWJzZXQgZnVjdGlvbgpzdWJzZXQoQU5FUywgQU5FUyREZW0uUHJlcy5jYW5kLkZUID49MjAgfCBBTkVTJEdPUC5QcmVzLmNhbmQuRlQgPj0gMjApIApgYGAKCiMjIFNvcnQgZGF0YQoKWW91IGNhbiBzb3J0IHlvdXIgZGF0YSBvbiBvbmUgb3IgbW9yZSB2YXJpYWJsZXMsIGFuZCB5b3UgY2FuIHNldCB0aGUgb3JkZXIgdG8gYmUgYXNjZW5kaW5nIG9yIGRlc2NlbmRpbmcKCmBgYHtyfQojIHRoZSBvcmRlciBmdW5jdGlvbiByZXR1cm5zIGEgcGVybXV0YXRpb24gd2hpY2ggcmVhcnJhbmdlcyBpdHMgZmlyc3QgYXJndW1lbnQgaW50byBhc2NlbmRpbmcgb3IgZGVzY2VuZGluZyBvcmRlci4gVGhlIGRlZmF1bHQgaXMgYXNjZW5kaW5nLiAKb3JkZXIoQU5FUyREZW0uUHJlcy5jYW5kLkZUKQojIGNoYW5nZSBpbnRvIGRlc2NlbmRpbmcgb3JkZXIgdXNpbmcgdGhlIGRlY3JlYXNpbmcgYXJndW1lbnQgaW5zaWRlIG9yZGVyKCkKb3JkZXIoQU5FUyREZW0uUHJlcy5jYW5kLkZULCBkZWNyZWFzaW5nID0gVFJVRSkKIyBTb3J0IHRoZSB0dXJub3V0IGRhdGEgYmFzZWQgb24gdGhlIGFzY2VuZGluZyBvcmRlciBvZiBBTkVTIApvcmRlcmVkLkFORVMgPC0gQU5FU1tvcmRlcihBTkVTJERlbS5QcmVzLmNhbmQuRlQsZGVjcmVhc2luZyA9IFRSVUUpLF0KIyBOb3RlIGFmdGVyIG9yZGVyaW5nLCB0aGUgTkFzIHdpbGwgYWx3YXlzIGJlIGF0IHRoZSBlbmQgbm8gbWF0dGVyIHdoZXRoZXIgdGhlIG9yZGVyIGlzIGFzY2VuZGluZyBvdCBkZXNjZW5kaW5nCmBgYAoKIyBNYW5pcHVsYXRlIGRhdGEKClRoZSBkYXRhIHNldHMgeW91IGhhdmUgYmVlbiB1c2luZyBhdCBjbGFzcyBoYXZlIGFscmVhZHkgYmVlbiBjbGVhbmVkLiBUaGV5IGFyZSBpbiB0aGUgY29ycmVjdCBmb3JtYXRzIGFuZCBjb250YWlucyBldmVyeXRoaW5nIHlvdSBuZWVkIGZvciB0aGUgY2xhc3MgYW5hbHlzaXMuIEhvd2V2ZXIsIGluIHJlYWxpdHkgd2hlbiB5b3UgdXNlIG90aGVyIHBlb3BsZSdzIGRhdGEgb3IgZG93bmxvYWQgZGF0YSBvbmxpbmUsIHlvdSBtaWdodCBuZWVkIHRvIHVzZSBzZXZlcmFsIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSB0byBjYWxjdWxhdGUgdGhlIHZhcmlhYmxlIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiwgYW5kIHlvdSBtaWdodCBuZWVkIHRvIGNvcnJlY3QgdGhlIGNsYXNzIG9mIGEgdmFyaWFibGUsIGFuZCB5b3UgbWlnaHQgbmVlZCB0byByZWNvZGUgdGhlIHZhbHVlcyBpbiB0aGUgZGF0YS4gCgojIyBDcmVhdGUgbmV3IHZhcmlhYmxlcwoKU29tZSB0aW1lcywgeW91IG5lZWQgdG8gdXNlIG11bHRpcGxlIHZhcmlhYmxlcyBpbiBhIGRhdGUgc2V0IHRvIGNyZWF0ZSBhIHZhcmlhYmxlIG9mIHlvdXIgaW50ZXJlc3QuIEluc3RlYWQgb2YgY2FsY3VsYXRpbmcgdGhlIHZhbHVlIGV2ZXJ5IHRpbWUgd2hlbiB5b3UgbmVlZCB0byB1c2UgdGhlIHZhcmlhYmxlLCBpdCBpcyBtb3JlIGNvbnZlbmllbnQgdG8gY3JlYXRlIHN1Y2ggdmFyaWFibGUgZmlyc3QgYW5kIGFkZCB0aGUgbmV3IHZhcmlhYmxlIHRvIHRoZSBkYXRhIHNldC4gCgpgYGB7cn0KIyBBZGQgYSBuZXcgdmFyaWFibGUgRGlmZi5GVCB0byB0aGUgQU5FUyBkYXRhIGZyYW1lCkFORVMkRGlmZi5GVCA8LSBBTkVTJEdPUC5QcmVzLmNhbmQuRlQgLSBBTkVTJERlbS5QcmVzLmNhbmQuRlQKYGBgCgojIyBSZWNvZGUgdmFsdWVzCgojIyMgQ2hhbmdlIHRoZSBjbGFzcyAKCkEgZGF0YSBzZXQgZ2VuZXJhbGx5IGNvbnRhaW5zIHZhcmlhYmxlcyB3aXRoIGRpZmZlcmVudCBjbGFzcy9jaGFyYWN0ZXJpc3RpY3MsIHN1Y2ggYXMgbnVtZXJpYywgY2hhcmFjdGVyLCBmYWN0b3IgYW5kIGxvZ2ljYWwuIFdoZW4gYW5hbHl6aW5nIHRoZSBkYXRhLCBzb21ldGltZXMgeW91IG5lZWQgdG8gY29udmVydCB0aGUgY2xhc3Mgb2YgdGhlIHZhcmlhYmxlLgoKYGBge3J9CiMgY2hlY2sgd2hldGhlciB0aGUgdmFyaWFibGUgaXMgY2VydGFpbiBjbGFzcwppcy5udW1lcmljKCkKaXMuY2hhcmFjdGVyKCkKaXMuZmFjdG9yKCkKIyBjb252ZXJ0IHRvIHRoZSBjb3JyZWN0IGNsYXNzIGZvciB0aGUgYW5hbHlzaXMKYXMubnVtZXJpYygpCmFzLmNoYXJhY3RlcigpCmFzLmZhY3RvcigpCmBgYAoKIyMjIENoYW5nZSB0aGUgdmFsdWUKCldoZW4gZG9pbmcgYW5hbHlzaXMsIHdlIG9mdGVuIG5lZWQgdG8gcmVjb2RlIHNvbWUgb2YgdGhlIHZhbHVlcy4gRm9yIGV4YW1wbGUsIGluIHN1cnZleSBkYXRhLCB0aGUgZ2VuZGVyIG1pZ2h0IGJlIGNvZGVkIGFzICJmZW1hbGUiIG9yICJtYWxlIiBhbmQgd2Ugd2FudCB0byByZWNvZGUgaXQgYXMgMCBhbmQgMS4gV2UgY2FuIHVzZSB0aGUgcmVjb2RlIGZ1bmN0aW9uIGZyb20gdGhlIHBhY2thZ2UgY2FyLgoKRmlyc3QsIGluc3RhbGwgYW5kIGxvYWQgdGhlIHBhY2thZ2UgQ2FyOgpgYGB7cn0KIyBJbnN0YWxsIHRoZSBjYXIgcGFja2FnZSwgeW91IG9ubHkgbmVlZCB0byBpbnN0YWwgb25jZQppbnN0YWxsLnBhY2thZ2VzKCJjYXIiKQoKIyBMb2FkIHRoZSBjYXIgcGFja2FnZQpsaWJyYXJ5KGNhcikKYGBgCgpTZWNvbmQsIHRyeSB0aGUgcmVjb2RlIGZ1bmN0aW9uIQoKKiBDaGFuZ2UgYWxsIHRoZSAxIGludG8gImZlbWFsZSIgYW5kIGFsbCB0aGUgMCBpbnRvICJtYWxlIiBpbiB0aGUgZmVtYWxlIHZhcmlhYmxlIGluIEFORVMgZGF0YQoKYGBge3J9CkFORVMkZmVtYWxlIDwtIHJlY29kZShBTkVTJGZlbWFsZSwgIjEgPSAnZmVtYWxlJzswID0gJ21hbGUnIikKYGBgCgoqIENoYW5nZSBhIHJhbmdlIG9mIGRhdGEgaW50byBjZXJ0YWluIHZhbHVlOiByZWNvZGUgdGhlIGZlZWxpbmcgdGhlcm1vbWV0ZXIgc2NvcmVzIGxlc3MgdGhhbiAyNSBpbnRvIDEgKG1lYW5pbmcgInZlcnkgbmVnYXRpdmUiKSwgMjUgdG8gNDkgaW50byAyIChtZWFuaW5nICJzb21ld2hhdCBuZWdhdGl2ZSIpLCA1MCB0byA3NCBpbnRvIDMgKG1lYW5pbmcgInNvbWV3aGF0IHBvc2l0aXZlIiksIGFuZCA3NSB0byAxMDAgaW50byA0IChtZWFuaW5nICJ2ZXJ5IHBvc2l0aXZlIikKCmBgYHtyfQpBTkVTJERlbS5QcmVzLmNhbmQuRlQgPC0gcmVjb2RlKEFORVMkRGVtLlByZXMuY2FuZC5GVCwgIjA6MjQ9MTsgMjU6NDk9Mjs1MDo3ND0zOzc1OjEwMD00O2Vsc2U9TkEiKQpgYGAKCiogQWZ0ZXIgcmVjb2RpbmcgdGhlIHZhbHVlLCBhbHdheXMgZG91YmxlIGNoZWNrIHRoZSByZWNvZGVkIHZhcmlhYmxlCgpgYGB7cn0KdGFibGUoQU5FUyRmZW1hbGUpCnN1bW1hcnkoQU5FUyREZW0uUHJlcy5jYW5kLkZUKQpgYGAKClNvbWV0aW1lcywgeW91IG1pZ2h0IG9ubHkgd2FudCB0byBjaGFuZ2Ugb25lIHNwZWNpZmljIGNlbGwuIEZvciBleGFtcGxlLCB5b3UgZmluZCB0aGUgdmFsdWUgZm9yIGEgTkEgY2VsbC4gWW91IGNhbiByZWNvZGUgdGhhdCBjZWxsIGJ5IGxvY2F0aW5nIGl0cyByb3cuCgpgYGB7cn0KIyBGb3IgZXhhbXBsZSwgSSBmaW5kIHRoYXQgdGhlIGZpcnN0IG1pc3NpbmcgdmFsdWUgaW4gdGhlIGZlZWxpbmcgdGhlcm1vbWV0ZXIgdG93YXJkcyBDbGludG9uIHNob3VsZCBiZSAzOQpBTkVTJERlbS5QcmVzLmNhbmQuRlRbd2hpY2goaXMubmEoQU5FUyREZW0uUHJlcy5jYW5kLkZUKSlbMV1dIDwtIDM5CmBgYAoKCiNFeHBvcnQgRGF0YQoKTm90ZSB0aGF0ICoqdGhlIGNoYW5nZXMgeW91IG1hZGUgaW4gUiBhbmQgUiBlbnZpcm9ubWVudCBkbyBub3QgY2hhbmdlIHRoZSBkYXRhIGluIHlvdXIgZm9sZGVyKiouIFRoZXJlZm9yZSwgYWZ0ZXIgcmVjb2Rpbmcgb3IgYWRkaW5nIHZhcmlhYmxlcywgeW91IHdpbGwgd2FudCB0byBzYXZlIHRoZSB1cGRhdGVkIGRhdGEgaW4geW91ciBjb21wdXRlciwgc28geW91IGRvIG5vdCBuZWVkIHRvIHJlcGVhdCB0aGUgZGF0YSBtYW5pcHVsYXRpb24uIFVzaW5nIHRoZSBzYW1lIHBhY2thZ2VzLCB3ZSBjYW4gc2F2ZS9leHBvcnQgdGhlIGRhdGEgeW91IGNyZWF0ZWQgb3Igd29ya2VkIGluIFIgdG8geW91ciBjb21wdXRlciBhcyB2YXJpb3VzIGZvcm1hdHMuIEhvd2V2ZXIsIGNzdiBmb3JtYXQgaXMgcmVjb21tZW5kZWQuIAoKIyMgU2F2ZSBkYXRhIGFzIGNzdiBmaWxlCgpgYGB7cn0KIyB3cml0ZSB0aGUgZGF0YSB0byB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeQp3cml0ZS5jc3YoQU5FUywidXBkYXRlZEFORVMuY3N2IikKIyB3cml0ZSB0aGUgZGF0YSB0byBvdGhlciBmb2xkZXJzIGluIHlvdXIgY29tcHV0ZXIKd3JpdGUuY3N2KEFORVMsInBhdGgvdXBkYXRlZEFORVMuY3N2IikKYGBgCgojIyBTYXZlIGRhdGEgYXMgb3RoZXIgZm9ybWF0CgpgYGB7cn0KIyBFeGNlbAp3cml0ZS54bHN4KEFORVMsInVwZGF0ZWRBTkVTLnhsc3giKQojIFN0YXRhCndyaXRlLmR0YShBTkVTLCJ1cGRhdGVkQU5FUy5kdGEiKQpgYGAKCioqKgpIZWxwc2hlZXQgbWFkZSBmb3IgUExTQyAzMDkgYnkgWWFveWFvIERhaQo=