1 Intro R Markdown

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 the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

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).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

2 R and R Studio

2.1 R

R is the most influential statistical software that is widely used in data science. The R Project for Statistical Computing. R allows the user to take control of their analyses and being open about how the data were analysed, etc. R encourages transparency and reproducible research.

2.1.1 Downloading base R

If you are a windows user, download the latest version here R version 3.5.1. If you are a MacX user, download the latest version here R version 3.5.1. Other Linux versions available here.

Using up-to-date versions of R is important as this allows you to use the latest developments of the software. You can have a look at what is new in this latest release here. One of the major changes in versions post 3.5.0 is the speed of computations. In many cases, these are invisible, but with heavy computations, e.g., (Generalised-)Linear Mixed Effects using lme4, Cumulative Logit Mixed Effects using ordinal, Conditional Variable Importance in Random Forests using party, etc. you will see a difference in how fast the computations are (i.e., rather than 4-5 hours running of a script, these will be finished in around 1 hour or less!). R by default uses 1 core on your machine. You can use parallel computing with specialised packages using foreach, doSNOW, parallel, etc. or see below.

2.1.2 Upgrading your current R installation

You can download the latest version from above and update. Or you can use the package installr and upgrade to the latest available version. If the package is not installed, use this: install.packages("installr") and then run with library(installr) then type installr in the console (what? what’s a console?).. We’ll come to this later on!

2.1.3 Downloading Mcrosoft R Open

If you are after more speed, then use Microsoft R Open distribution. This is an enhanced version of R that allows for multicore and multithreading by default. This means you will have an increase in speech on how various analyses are computed. You can download it here. This used to be part of Revolution R Open that was bought by Microsoft. It is an Open source distribution (and I use it all the time). This is compatible with any Operating System (Windows, Mac, Linux), but it was shown to have a major impact with windows OS…

This distribution usually takes a couple of weeks to be updated after an R update and the packages are fixed in time, i.e., any updates to packages will not occur until the next official release. This is not an issue as package updates are not too frequent.

2.2 R Studio

R Studio is one of the mostly used free and open-source integrated development environment for R. It allows the user to have access to various information at the same time, e.g., the Source, the Console, the Environment and the Files, etc. When you open R studio, and if you have installed R appropriately, then R Studio will “talk” to R by sending it messages to execute commands.

You can set up the layout to suit your needs. I always find the following layout best for my needs:

  1. The Source pane: the file where you write your code
  2. The Console where actual code is run
  3. The Environment pane, which shows you all variables/datasets, with the history of executed code, etc.
  4. The Files/Viewer pane, which shows you the files in the current folder, the plots, the installed packages, and help files, etc.

If you click on Tools and Global options, then Pane Layout, you can change the order, and add/remove options from the two panes below

2.3 Other options?

2.3.1 Text Editors

I use Sublime Text to run Python, Praat and write in \(\LaTeX\). I use R Markdown in R to publish my code and write notebooks. I am in the process of writing my first article with R Markdown for a fully reproducible research.

There are many development environments that can be used to “talk” to R: TinnR, Visual Studio, etc…

2.3.2 R GUIs

GUIs (for Graphical User Interface) for R are available. I list below a few. However, after trying some of these, I found it much easier to get to code directly in R. I don’t remember all codes! I use these to my advantage, by saving my code into a script and using it later on in other scripts.

Some of the GUIs are meant to make R like excel or SPSS, while others are more specialised. Here is a list of some of these GUIs…

  1. RCommander is the first GUI I used (and hated!). It is the one used in Discovering Statistics using R by Andy Field. There are compatibility issues between RCommander and RStudio… You are only able to run RCommander from within R directly (using library(Rcmdr) from within R)
  2. rattle is more of use for data mining and advanced statistics (use library(rattle) then rattle() to run)
  3. Deducer. For basic and advanced statistics (run with library(Deducer) after installation)
  4. RKWard. For basic and advanced statistics. Not available on CRAN and should be downloaded and installed.
  5. Etc.

You can always start by using any of the above to familiarise yourself with the code, and then move to using R fully via code. My recommendation is to start coding first thing and search for help on how to write the specific code you are after.

3 Am I ready to use R now?

Well almost. There is one thing we need to consider: telling R where is our working directory. By default R saves this to your documents (or somewhere else). For this workshop, this is generally OK, though when working on your own data, things get more complicated.

There are two schools of thought here. 1. Create R scripts that run the analyses and saves the output(s) directly to your working directory. Does not save the .RData image at the end 2. Create a project: a self-contained folder, where all your scripts, figures, etc. will be automatically saved. Saves the .RData at the end

I subscribe to the second, as some of the computations I run take ages to finish.

3.1 Setting working directory

Click the menu Session -> Set Workign Directory -> Choose Directory or use setwd("path/to/directory") (choose the location where you want to save the results)

You can also use getwd()

3.2 Creating a project

Look at the top-right hand where you can see Projects (none). You can create a new project in a new path or based on a specific folder.

4 How to use packages?

4.1 Installation

The best option is to use the menu above (under Tools) and click Install packages, or type in install.packages(“package.name”). Make sure to always have install dependencies ticked (using the first option).

4.2 Loading

Use the following to load a package: library(package.name). Once the package is loaded, you can use any of its functions directly into your code. Sometimes you may need to specify to use a particular function from within a particular package, in this case use: package.name::function. We will most probably not use this today, but this is something you need to know about otherwise undesirable results may occur (or even errors!).

4.3 Finding packages and help

Under the Files pane (right bottom), click on the menu Packages and you will have access to all installed packages. Click on a package and you can see the associated help files. You can also type the following to find help: ?package.name. ??function e.g.,

?stats
??MASS

Or try clicking on the function name to find details of what to specify: e.g., scroll on lmer (assuming lme4 is installed). Do a Ctrl/Cmd + left mouse click on a function to display options.

lme4::lmer
function (formula, data = NULL, REML = TRUE, control = lmerControl(), 
    start = NULL, verbose = 0L, subset, weights, na.action, offset, 
    contrasts = NULL, devFunOnly = FALSE, ...) 
{
    mc <- mcout <- match.call()
    missCtrl <- missing(control)
    if (!missCtrl && !inherits(control, "lmerControl")) {
        if (!is.list(control)) 
            stop("'control' is not a list; use lmerControl()")
        warning("passing control as list is deprecated: please use lmerControl() instead", 
            immediate. = TRUE)
        control <- do.call(lmerControl, control)
    }
    if (!is.null(list(...)[["family"]])) {
        warning("calling lmer with 'family' is deprecated; please use glmer() instead")
        mc[[1]] <- quote(lme4::glmer)
        if (missCtrl) 
            mc$control <- glmerControl()
        return(eval(mc, parent.frame(1L)))
    }
    mc$control <- control
    mc[[1]] <- quote(lme4::lFormula)
    lmod <- eval(mc, parent.frame(1L))
    mcout$formula <- lmod$formula
    lmod$formula <- NULL
    devfun <- do.call(mkLmerDevfun, c(lmod, list(start = start, 
        verbose = verbose, control = control)))
    if (devFunOnly) 
        return(devfun)
    if (identical(control$optimizer, "none")) 
        stop("deprecated use of optimizer=='none'; use NULL instead")
    opt <- if (length(control$optimizer) == 0) {
        s <- getStart(start, environment(devfun)$lower, environment(devfun)$pp)
        list(par = s, fval = devfun(s), conv = 1000, message = "no optimization")
    }
    else {
        optimizeLmer(devfun, optimizer = control$optimizer, restart_edge = control$restart_edge, 
            boundary.tol = control$boundary.tol, control = control$optCtrl, 
            verbose = verbose, start = start, calc.derivs = control$calc.derivs, 
            use.last.params = control$use.last.params)
    }
    cc <- checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, 
        lbound = environment(devfun)$lower)
    mkMerMod(environment(devfun), opt, lmod$reTrms, fr = lmod$fr, 
        mc = mcout, lme4conv = cc)
}
<bytecode: 0x00000000382f84e0>
<environment: namespace:lme4>

4.4 Up to you…

Install a package and search for help.

5 Let’s get started with R

5.1 R as a calculator

5.1.1 Simple calculations

R can be used as a calculator. Try some of the following below:

1 + 2
[1] 3
1+2*3
[1] 7

Well wait a second! were you all expecting the result to be 7? how many expected the result to be 9? Check the following:

(1+2)*3
[1] 9
1+(2*3)
[1] 7

So parenthesis are important! Always use these to tell R (and any other software) the order of operations. This is the order: 1. Parentheses 2. Exponents 3. Multiplication and Division (from left to right) 4. Addition and Subtraction (from left to right)

5.1.2 Functions

There are many built-in functions in R to do some complicated mathematical calculations.

5.1.2.1 Basic functions

Run some of the following.

sqrt(3)
[1] 1.732051
3^2
[1] 9
log(3)
[1] 1.098612

5.1.2.2 Creating variables

We can also create variables (aka temporary place holders).

x <- 2
y <- 5
b <- x*y
x
[1] 2
y
[1] 5
b
[1] 10
b+log(y)*x^2
[1] 16.43775

When you create a variable and assign to it a number (or characters), you can use it later on.

5.1.2.3 Sequences

We can also create sequences of numbers

seq(1,10,2)
[1] 1 3 5 7 9
z <- 1:10

And we can do the following.. Can you explain what we have done here?

z2 <- z+1
z*z2
 [1]   2   6  12  20  30  42  56  72  90 110

Up to you… Write some more complex maths here just for fun!

# Add below

5.2 Objects

5.2.1 Basic objects

Objects are related to variables (we created above), but can also be dataframes, and other things we create in R. All of these are stored in memory and are shown below (under environment). You can check the type of the “object” below in the list (look at “Type”) or by using class().

Let’s look at the variables we created so far.. We will create another one as well…

class(b)
[1] "numeric"
class(x)
[1] "numeric"
class(y)
[1] "numeric"
class(z)
[1] "integer"
class(z2)
[1] "numeric"
a <- "test"
class(a)
[1] "character"

When we do calculations in R, we need to make sure we use numeric/integer variables only.. Try some of the below

x+y
[1] 7
two <- "2"
x + two
Error in x + two : non-numeric argument to binary operator

Can you explain the error?

We have tried to add a number to a (character) string which is clearly impossible. To do the maths, we need to change the class using any of the following commands: as.character, as.integer, as.numeric, as.factor, e.g.:

two <- as.numeric(two)
x + two
[1] 4

5.2.2 Other functions and objects

5.2.2.1 Some more calculations

We can create a vector of objects to do various things on.. We use the function c() and do various things on:

numbers <- c(1,4,5,12,55,13,45,38,77,836,543)
class(numbers)
[1] "numeric"
mean(numbers)
[1] 148.0909
sd(numbers)
[1] 276.6375
median(numbers)
[1] 38
min(numbers)
[1] 1
max(numbers)
[1] 836
range(numbers)
[1]   1 836

5.2.2.2 Referring to a specific position

Sometimes we may want to refer to a specific position in the list of numbers we just created… Use the following:

numbers[2]
[1] 4
numbers[3:5]
[1]  5 12 55
numbers[-4]
 [1]   1   4   5  55  13  45  38  77 836 543
numbers+numbers[6]
 [1]  14  17  18  25  68  26  58  51  90 849 556

Can you explain what we have done in the last operation?

5.2.3 Dataframes

A dataframe is the most important object we will be using over and over again… It is an object that contains information in both rows and columns.

5.2.3.1 Creating a dataframe from scratch

In this exercise, we will create a 4*9 dataframe. The code below creates four variables, and combines them together to make a dataframe. As you can see, variables can also be characters. To create the dataframe, we use the functions as.data.frame and cbind.

word <- c("a", "the", "lamp", "not", "jump", "it", "coffee", "walk", "on")
freq <- c(500, 600, 7, 200, 30, 450, 130, 33, 300)  # note this is completely made up!!
functionword <- c("y", "y", "n", "y", "n", "y", "n", "n", "y")
length <- c(1, 3, 4, 3, 4, 2, 6, 4, 2)
df <- as.data.frame(cbind(word,freq,functionword,length))

5.2.3.2 Deleting variables from the Environment

If you have created various variables you do not need any more, you can use rm to remove these

rm(word,freq,functionword,length)

BUT wait, did I remove these from my dataframe? Well no.. We have removed objects from within the R environment and not from the actual dataframe. Let’s check this up

df

5.2.3.3 Saving and reading the dataframe

5.2.3.3.1 Reading and Saving in .csv

The code below allows you to save the dataframe and read it again. The extension .csv is for “comma delimited files”. This is the best format to use as it is simply a text file with no additional formatting.

write.csv(df,"df.csv")
dfNew <- read.csv("df.csv")
df
dfNew

The newly created object contains 5 columns rather than the 4 we initially created. This is normal. By default, R add a column that reflects the order of the list before it was saved. You can simply delete the column or keep as is (but be careful as this means you need to adjust any references to columns that we will use later on).

5.2.3.3.2 Reading and saving other formats

R allows us to read data in any format. If you have a .txt, .sav, .xls, .xlsx, etc., then there are packages specific to do that (e.g., package xlsx to read/save .xlsx files, or the function haven from the package tidyverse to read/save .sav files).

You can use the built-in plugin in RStudio to import your dataset. See Import Dataset within the Environment.

In general, any specific formatting is kept, but sometimes variable names associated with numbers (as in .sav files) will be lost. Hence, it is always preferable to do minimal formatting on the data.. Start with a .csv file, import it to R and do the magic!

5.2.3.4 Checking the structure

The first thing we will do is to check the structure of our created dataset. We will use the originally created one (i.e., df and not the imported one (i.e., dfNew).

str(df)
'data.frame':   9 obs. of  4 variables:
 $ word        : Factor w/ 9 levels "a","coffee","it",..: 1 8 5 6 4 3 2 9 7
 $ freq        : Factor w/ 9 levels "130","200","30",..: 7 8 9 2 3 6 1 5 4
 $ functionword: Factor w/ 2 levels "n","y": 2 2 1 2 1 2 1 1 2
 $ length      : Factor w/ 5 levels "1","2","3","4",..: 1 3 4 3 4 2 5 4 2

The function str gives us the following information: 1. How many observations (i.e., rows) and variables (i.e., columns) 2. The name of each variable (look at $ and what comes after it) 3. Within each variable, we have the class with number of levels

5.2.3.4.1 Changing the class of a variable

As we can see, the four created variables were added to the dataframe as factors. We need to change the class of the numeric variables: freq and length. Let’s do that:

df$freq <- as.numeric(df$freq)
df$length <- as.numeric(df$length)
str(df)
'data.frame':   9 obs. of  4 variables:
 $ word        : Factor w/ 9 levels "a","coffee","it",..: 1 8 5 6 4 3 2 9 7
 $ freq        : num  7 8 9 2 3 6 1 5 4
 $ functionword: Factor w/ 2 levels "n","y": 2 2 1 2 1 2 1 1 2
 $ length      : num  1 3 4 3 4 2 5 4 2
5.2.3.4.2 Referring to particular variables, observations

As you can see from the above, we can refer to a particular variable in the dataframe by its name and adding $. There are additional options to do that. Let’s see what we can do. Can you tell what each of the below does? chat to your neighbour….

df[1]
df[,1]
[1] a      the    lamp   not    jump   it     coffee walk   on    
Levels: a coffee it jump lamp not on the walk
df[1,]
df[1,1]
[1] a
Levels: a coffee it jump lamp not on the walk

Here are the answers: 1. Refers to the full column 1 2. Refers to first variable 3. Refers to first row 4. Refers to first observation in first column

Practice a bit and use other specifications to obtain specific observations, columns or rows…

# write here

5.2.3.5 Basic summaries, tables

We can use the function summary to do some basic summaries

summary(df)
      word        freq   functionword     length     
 a      :1   Min.   :1   n:4          Min.   :1.000  
 coffee :1   1st Qu.:3   y:5          1st Qu.:2.000  
 it     :1   Median :5                Median :3.000  
 jump   :1   Mean   :5                Mean   :3.111  
 lamp   :1   3rd Qu.:7                3rd Qu.:4.000  
 not    :1   Max.   :9                Max.   :5.000  
 (Other):3                                           

We can create a table with the function table

table(df$functionword,df$freq)
   
    1 2 3 4 5 6 7 8 9
  n 1 0 1 0 1 0 0 0 1
  y 0 1 0 1 0 1 1 1 0

5.2.3.6 Basic manipulations

5.2.3.6.1 Creating variables

We sometimes need to create and/or delete new variables.. Do you know how to do that?

Let’s look at the structure again:

str(df)
'data.frame':   9 obs. of  4 variables:
 $ word        : Factor w/ 9 levels "a","coffee","it",..: 1 8 5 6 4 3 2 9 7
 $ freq        : num  7 8 9 2 3 6 1 5 4
 $ functionword: Factor w/ 2 levels "n","y": 2 2 1 2 1 2 1 1 2
 $ length      : num  1 3 4 3 4 2 5 4 2

We said earlier that we can refer to a specific variable by using $ + the name of the variable. Let’s use this again and add a new name of variable not in the list of variables above

df$newVariable
NULL

What does NULL mean? The variable does not exist! Let’s do something else

df$newVariable <- NA

Ah no error messages! Let’s check the structure

str(df)
'data.frame':   9 obs. of  5 variables:
 $ word        : Factor w/ 9 levels "a","coffee","it",..: 1 8 5 6 4 3 2 9 7
 $ freq        : num  7 8 9 2 3 6 1 5 4
 $ functionword: Factor w/ 2 levels "n","y": 2 2 1 2 1 2 1 1 2
 $ length      : num  1 3 4 3 4 2 5 4 2
 $ newVariable : logi  NA NA NA NA NA NA ...

So we now have five variables and the last one is named “newVariable” and assigned “NA”. “NA” is used in R to refer to missing data or is a place holder. We can replace these with any calculations, or anything else. Let’s do that:

df$newVariable <- log(df$freq)
str(df)
'data.frame':   9 obs. of  5 variables:
 $ word        : Factor w/ 9 levels "a","coffee","it",..: 1 8 5 6 4 3 2 9 7
 $ freq        : num  7 8 9 2 3 6 1 5 4
 $ functionword: Factor w/ 2 levels "n","y": 2 2 1 2 1 2 1 1 2
 $ length      : num  1 3 4 3 4 2 5 4 2
 $ newVariable : num  1.946 2.079 2.197 0.693 1.099 ...

We replaced “NA” with the log of the frequencies. Let’s check that this is correct only for one observation. Can you dissect the code below? what did I use to ask R to compute the log of the frequency (freq)? Remember rows and columns

log(df[1,2])
[1] 1.94591
df[1,5]
[1] 1.94591

So they are the same values.

5.2.3.6.2 Changing column names

Now we need to change the name of the variable to reflect the computations. “newVariable” is meaningless as a name, but “logFreq” is informative.

colnames(df)[5] <- "logFreq"
str(df)
'data.frame':   9 obs. of  5 variables:
 $ word        : Factor w/ 9 levels "a","coffee","it",..: 1 8 5 6 4 3 2 9 7
 $ freq        : num  7 8 9 2 3 6 1 5 4
 $ functionword: Factor w/ 2 levels "n","y": 2 2 1 2 1 2 1 1 2
 $ length      : num  1 3 4 3 4 2 5 4 2
 $ logFreq     : num  1.946 2.079 2.197 0.693 1.099 ...

As can be seen from the above, using the command colnames(df)[5] <- "logFreq" allows us to change the column name in position 5 of the dataframe. If we were to change all of the columns names, we could use colnames(df) <- c("col1","col2",...)“. As an exercise, let’s do that now. Change the names of all columns:

## change column names here
5.2.3.6.3 Deleting variables

Let us now create a new compound variable that we later delete. This new compound variable will the multiplication of two numeric variables. The result is meaningless of course, but will be used for this exercise.

df$madeUpVariable <- df$freq*df$length
str(df)
'data.frame':   9 obs. of  6 variables:
 $ word          : Factor w/ 9 levels "a","coffee","it",..: 1 8 5 6 4 3 2 9 7
 $ freq          : num  7 8 9 2 3 6 1 5 4
 $ functionword  : Factor w/ 2 levels "n","y": 2 2 1 2 1 2 1 1 2
 $ length        : num  1 3 4 3 4 2 5 4 2
 $ logFreq       : num  1.946 2.079 2.197 0.693 1.099 ...
 $ madeUpVariable: num  7 24 36 6 12 12 5 20 8

Let us now delete this variable given that we are not interested in. Do you know how to do that? Think about how we referred to a variable before? We use df[colNumber]. What if we use df[-colNumebr], what would be the result?

df[-6]

This shows all columns minus the one we are not interested in. If we rewrite the variable df and assign to it the newly created dataframe we just used above (with the minus sign), then the column we are not interested in will be deleted.

df <- df[-6]
str(df)
'data.frame':   9 obs. of  5 variables:
 $ word        : Factor w/ 9 levels "a","coffee","it",..: 1 8 5 6 4 3 2 9 7
 $ freq        : num  7 8 9 2 3 6 1 5 4
 $ functionword: Factor w/ 2 levels "n","y": 2 2 1 2 1 2 1 1 2
 $ length      : num  1 3 4 3 4 2 5 4 2
 $ logFreq     : num  1.946 2.079 2.197 0.693 1.099 ...
5.2.3.6.4 Changing names of observations

Let’s say that we want to change the names of our observations. For instance, the variable “functionword” has the levels “y” and “n”. Let us change the names to become “yes” and “no”. We first need to change the factor level variable into character and then change the observations. Then we need to transform back to a factor

df$functionword <- as.character(df$functionword)
df$functionword[df$functionword == "y"] <- "yes"
df$functionword[df$functionword == "n"] <- "no"
df$functionword <- as.factor(df$functionword)
str(df)
'data.frame':   9 obs. of  5 variables:
 $ word        : Factor w/ 9 levels "a","coffee","it",..: 1 8 5 6 4 3 2 9 7
 $ freq        : num  7 8 9 2 3 6 1 5 4
 $ functionword: Factor w/ 2 levels "no","yes": 2 2 1 2 1 2 1 1 2
 $ length      : num  1 3 4 3 4 2 5 4 2
 $ logFreq     : num  1.946 2.079 2.197 0.693 1.099 ...
5.2.3.6.5 Checking levels of factors

We can also check the levels of factor and change the reference value. This is useful when doing any type of statistics or when plotting the data. We use levels, relevel and ref

levels(df$functionword)
[1] "no"  "yes"
df$functionword <-relevel(df$functionword, ref = "yes")
levels(df$functionword)
[1] "yes" "no" 

We can also use the following code to change the order of the levels of a multilevel factor

levels(df$word)
[1] "a"      "coffee" "it"     "jump"   "lamp"   "not"    "on"    
[8] "the"    "walk"  
df$word <- factor(df$word, levels = c("a","coffee","jump","lamp","not","it","on","walk","the"))
levels(df$word)
[1] "a"      "coffee" "jump"   "lamp"   "not"    "it"     "on"    
[8] "walk"   "the"   
5.2.3.6.6 Subsetting the dataframe

We may sometimes need to subset the dataframe and use parts of it. We use the function subset or which.

df_Yes1 <- df[which(df$functionword == 'yes'),]
#or
df_Yes2 <- subset(df, functionword=="yes")
str(df_Yes1)
'data.frame':   5 obs. of  5 variables:
 $ word        : Factor w/ 9 levels "a","coffee","jump",..: 1 9 5 6 7
 $ freq        : num  7 8 2 6 4
 $ functionword: Factor w/ 2 levels "yes","no": 1 1 1 1 1
 $ length      : num  1 3 3 2 2
 $ logFreq     : num  1.946 2.079 0.693 1.792 1.386
str(df_Yes2)
'data.frame':   5 obs. of  5 variables:
 $ word        : Factor w/ 9 levels "a","coffee","jump",..: 1 9 5 6 7
 $ freq        : num  7 8 2 6 4
 $ functionword: Factor w/ 2 levels "yes","no": 1 1 1 1 1
 $ length      : num  1 3 3 2 2
 $ logFreq     : num  1.946 2.079 0.693 1.792 1.386

When we subset the data, the levels of a factor are kept as they are.

levels(df_Yes1$functionword)
[1] "yes" "no" 
levels(df_Yes2$functionword)
[1] "yes" "no" 

But we only have one level of our factor..

df_Yes1$functionword
[1] yes yes yes yes yes
Levels: yes no
df_Yes2$functionword
[1] yes yes yes yes yes
Levels: yes no

By default, R keeps the levels of the factor as they are unless we change it by using the following:

df_Yes1$functionword <- factor(df_Yes1$functionword)
df_Yes2$functionword <- factor(df_Yes2$functionword)
df_Yes1$functionword
[1] yes yes yes yes yes
Levels: yes
df_Yes2$functionword
[1] yes yes yes yes yes
Levels: yes

5.3 Basic plotting

In most cases, we want to visualise our data. We will use the power of the base R plotting.

5.3.1 Built-in datasets

We will use one of the built in R. You can check all available datasets in R using the following:

data()
# or below for all datasets available in all installed packages
data(package = .packages(all.available = TRUE))
datasets have been moved from package 'base' to package 'datasets'datasets have been moved from package 'stats' to package 'datasets'

We will use the iris dataset from the package MASS

5.3.2 Checking structure and summaries

str(iris)
'data.frame':   150 obs. of  5 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

We have a dataframe with 150 observations and 5 variables; 4 numeric and 1 factor with 3 levels.

We summarise the data to see the trends:

summary(iris)
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
 Median :5.800   Median :3.000   Median :4.350   Median :1.300  
 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
       Species  
 setosa    :50  
 versicolor:50  
 virginica :50  
                
                
                

So we have an equal dataframe (50 observations under each level of the factor Species), with no missing values (aka NA).

5.3.3 Types of plots

5.3.3.1 Histogram

This is useful to get a sense of the shape of a distribution. It’s not too informative here but will be useful for bigger datasets

hist(iris$Sepal.Length)

5.3.3.2 Scatterplot

This allows us to visualise any relationships between two numeric variables

plot(iris$Sepal.Length, iris$Petal.Length)

5.3.3.3 Boxplots

We can plot a boxplot. This allows us to visualise the median, and quantiles in addition to the standard deviation and any outliers… All in the same plot!

plot(iris$Species, iris$Sepal.Length) 

#or
boxplot(iris$Sepal.Length ~ iris$Species) # ~ to be read as "as a function of"

5.3.3.4 Labelling plots

We can add labels to our plots

boxplot(iris$Sepal.Length ~ iris$Species, xlab = "Species", ylab="Length", main="A boxplot of the Iris dataset")

5.3.3.5 Trend lines

We can also add a trend line to our plot

boxplot(iris$Sepal.Length ~ iris$Species, xlab = "Species", ylab="Length", main="A boxplot of the Iris dataset with a linear trend")
lines(iris$Species, fitted(lm(Sepal.Length~Species, data=iris)),col="blue")

We can also use the plot above on the two numeric variables to plot a trend line

plot(iris$Sepal.Length, iris$Petal.Length, xlab = "Sepal Length", ylab="Petal Length", main="A plot of the linear association between Sepal and Petal Length")
abline(lm(Petal.Length~Sepal.Length, data=iris),col="blue")

We can of course add any other trend lines here…

5.3.3.6 With ggplot2

We can use the code below to plot the data

library(ggplot2)
ggplot(data = iris, aes(x=Species, y = Sepal.Length))+
  geom_boxplot() +
  labs(x="Species",y="Length",title="Boxplot and trend line",subtitle="with ggplot2") + 
  theme_set(theme_bw()) + theme(text=element_text(size=15))+
  geom_smooth(aes(x = as.numeric(Species), y = Sepal.Length))

5.3.3.7 Up to you…

Do a couple of plots based on the datasets available

## here

5.4 Basic statistics

We are all after running some statistics to appreciate our results. We will use the dataset iris to do basic statistics

5.4.1 Correlation tests

We use the function cor to obtain the pearson correlation and cor.test to run a basic correlation test on our data with significance testing

cor(iris$Sepal.Length,iris$Sepal.Width,method = "pearson")
[1] -0.1175698
cor(iris$Sepal.Length,iris$Petal.Length,method = "pearson")
[1] 0.8717538
cor(iris$Sepal.Length,iris$Petal.Width,method = "pearson")
[1] 0.8179411
cor.test(iris$Sepal.Length,iris$Petal.Width)

    Pearson's product-moment correlation

data:  iris$Sepal.Length and iris$Petal.Width
t = 17.296, df = 148, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.7568971 0.8648361
sample estimates:
      cor 
0.8179411 

5.4.2 Basic t-tests

We can run a basic t-test on our data, using the function t-test

t.test(iris$Sepal.Length,iris$Petal.Width)

    Welch Two Sample t-test

data:  iris$Sepal.Length and iris$Petal.Width
t = 50.536, df = 295.98, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 4.46315 4.82485
sample estimates:
mean of x mean of y 
 5.843333  1.199333 

5.4.3 Basic ANOVA

We can use the function aov to run an Analysis of Variance

summary(aov(Sepal.Length~Species, data=iris))
             Df Sum Sq Mean Sq F value Pr(>F)    
Species       2  63.21  31.606   119.3 <2e-16 ***
Residuals   147  38.96   0.265                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

5.4.4 A linear model

We can use the function lm to run a linear model

summary(lm(Sepal.Length~Species, data=iris))

Call:
lm(formula = Sepal.Length ~ Species, data = iris)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.6880 -0.3285 -0.0060  0.3120  1.3120 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)         5.0060     0.0728  68.762  < 2e-16 ***
Speciesversicolor   0.9300     0.1030   9.033 8.77e-16 ***
Speciesvirginica    1.5820     0.1030  15.366  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.5148 on 147 degrees of freedom
Multiple R-squared:  0.6187,    Adjusted R-squared:  0.6135 
F-statistic: 119.3 on 2 and 147 DF,  p-value: < 2.2e-16

But wait… How is the linear model comparable to the analysis of variance we ran above? This linear model derives the analysis of variance we saw above, use anova on your linear model..

Here are the results of the initial Analysis of variance:

summary(aov(Sepal.Length~Species, data=iris))
             Df Sum Sq Mean Sq F value Pr(>F)    
Species       2  63.21  31.606   119.3 <2e-16 ***
Residuals   147  38.96   0.265                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

And here are the results of the linear model with the anova function

anova(lm(Sepal.Length~Species, data=iris))
Analysis of Variance Table

Response: Sepal.Length
           Df Sum Sq Mean Sq F value    Pr(>F)    
Species     2 63.212  31.606  119.26 < 2.2e-16 ***
Residuals 147 38.956   0.265                      
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

They are exactly the same… The underlying of an Analysis of variance is a linear model..

6 End of the session

This is the end of this first session. We have looked at the various R distributions, the GUIs to R, installing and using packages, then R as a calculator, with basic and more advanced calculations. We then looked at the various object types, and created a dataframe from scratch. We did some manipulations of the dataframe, by creating a new variable, renaming a column, deleting one, and changing the levels of a variable. We then created some basic plots, and ran some basic statistics.

This whole workshop relied on the base R. Many researchers prefer to only use base R as this is stable and the code rarely changes (well it does change!). Others prefer using many of the R packages to speed up analyses or create lovely plots. I usually use a combination of base R plots, and plots created with ggplot2 or lattice.

LS0tDQp0aXRsZTogIkludHJvZHVjdGlvbiB0byBSIg0KYXV0aG9yOiANCiAgbmFtZTogIkphbGFsIEFsLVRhbWltaSINCiAgYWZmaWxpYXRpb246ICJOZXdjYXN0bGUgVW5pdmVyc2l0eSINCmRhdGU6ICIyMCBOb3ZlbWJlciAyMDE4Ig0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNg0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogeWVzDQotLS0NCiMgSW50cm8gUiBNYXJrZG93bg0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KYGBge3J9DQpwbG90KGNhcnMpDQpgYGANCg0KQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLg0KDQpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4NCg0KVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLg0KDQojIFIgYW5kIFIgU3R1ZGlvDQoNCiMjIFINCg0KYFJgIGlzIHRoZSBtb3N0IGluZmx1ZW50aWFsIHN0YXRpc3RpY2FsIHNvZnR3YXJlIHRoYXQgaXMgd2lkZWx5IHVzZWQgaW4gZGF0YSBzY2llbmNlLiBbVGhlIFIgUHJvamVjdCBmb3IgU3RhdGlzdGljYWwgQ29tcHV0aW5nXShodHRwczovL3d3dy5yLXByb2plY3Qub3JnLykuIFIgYWxsb3dzIHRoZSB1c2VyIHRvIHRha2UgY29udHJvbCBvZiB0aGVpciBhbmFseXNlcyBhbmQgYmVpbmcgb3BlbiBhYm91dCBob3cgdGhlIGRhdGEgd2VyZSBhbmFseXNlZCwgZXRjLiBgUmAgZW5jb3VyYWdlcyB0cmFuc3BhcmVuY3kgYW5kIHJlcHJvZHVjaWJsZSByZXNlYXJjaC4NCg0KIyMjIERvd25sb2FkaW5nIGJhc2UgUg0KDQpJZiB5b3UgYXJlIGEgd2luZG93cyB1c2VyLCBkb3dubG9hZCB0aGUgbGF0ZXN0IHZlcnNpb24gaGVyZSBbUiB2ZXJzaW9uIDMuNS4xXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9iaW4vd2luZG93cy9iYXNlLykuDQpJZiB5b3UgYXJlIGEgTWFjWCB1c2VyLCBkb3dubG9hZCB0aGUgbGF0ZXN0IHZlcnNpb24gaGVyZSBbUiB2ZXJzaW9uIDMuNS4xXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9iaW4vbWFjb3N4LykuIE90aGVyIExpbnV4IHZlcnNpb25zIGF2YWlsYWJsZSBbaGVyZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvYmluL2xpbnV4LykuDQoNClVzaW5nIHVwLXRvLWRhdGUgdmVyc2lvbnMgb2YgYFJgIGlzIGltcG9ydGFudCBhcyB0aGlzIGFsbG93cyB5b3UgdG8gdXNlIHRoZSBsYXRlc3QgZGV2ZWxvcG1lbnRzIG9mIHRoZSBzb2Z0d2FyZS4gWW91IGNhbiBoYXZlIGEgbG9vayBhdCB3aGF0IGlzIG5ldyBpbiB0aGlzIGxhdGVzdCByZWxlYXNlIFtoZXJlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9iaW4vd2luZG93cy9iYXNlL05FV1MuUi0zLjUuMS5odG1sKS4gT25lIG9mIHRoZSBtYWpvciBjaGFuZ2VzIGluIHZlcnNpb25zIHBvc3QgMy41LjAgaXMgdGhlIHNwZWVkIG9mIGNvbXB1dGF0aW9ucy4gSW4gbWFueSBjYXNlcywgdGhlc2UgYXJlIGludmlzaWJsZSwgYnV0IHdpdGggaGVhdnkgY29tcHV0YXRpb25zLCBlLmcuLCAoR2VuZXJhbGlzZWQtKUxpbmVhciBNaXhlZCBFZmZlY3RzIHVzaW5nIGBsbWU0YCwgQ3VtdWxhdGl2ZSBMb2dpdCBNaXhlZCBFZmZlY3RzIHVzaW5nIGBvcmRpbmFsYCwgQ29uZGl0aW9uYWwgVmFyaWFibGUgSW1wb3J0YW5jZSBpbiBSYW5kb20gRm9yZXN0cyB1c2luZyBgcGFydHlgLCBldGMuIHlvdSB3aWxsIHNlZSBhIGRpZmZlcmVuY2UgaW4gaG93IGZhc3QgdGhlIGNvbXB1dGF0aW9ucyBhcmUgKGkuZS4sIHJhdGhlciB0aGFuIDQtNSBob3VycyBydW5uaW5nIG9mIGEgc2NyaXB0LCB0aGVzZSB3aWxsIGJlIGZpbmlzaGVkIGluIGFyb3VuZCAxIGhvdXIgb3IgbGVzcyEpLg0KYFJgIGJ5IGRlZmF1bHQgdXNlcyAxIGNvcmUgb24geW91ciBtYWNoaW5lLiBZb3UgY2FuIHVzZSBwYXJhbGxlbCBjb21wdXRpbmcgIHdpdGggc3BlY2lhbGlzZWQgcGFja2FnZXMgdXNpbmcgYGZvcmVhY2hgLCBgZG9TTk9XYCwgYHBhcmFsbGVsYCwgZXRjLiBvciBzZWUgYmVsb3cuDQoNCiMjIyBVcGdyYWRpbmcgeW91ciBjdXJyZW50IFIgaW5zdGFsbGF0aW9uDQoNCllvdSBjYW4gZG93bmxvYWQgdGhlIGxhdGVzdCB2ZXJzaW9uIGZyb20gYWJvdmUgYW5kIHVwZGF0ZS4gT3IgeW91IGNhbiB1c2UgdGhlIHBhY2thZ2UgYGluc3RhbGxyYCBhbmQgdXBncmFkZSB0byB0aGUgbGF0ZXN0IGF2YWlsYWJsZSB2ZXJzaW9uLiBJZiB0aGUgcGFja2FnZSBpcyBub3QgaW5zdGFsbGVkLCB1c2UgdGhpczogYGluc3RhbGwucGFja2FnZXMoImluc3RhbGxyIilgIGFuZCB0aGVuIHJ1biB3aXRoIGBsaWJyYXJ5KGluc3RhbGxyKWAgdGhlbiB0eXBlIGBpbnN0YWxscmAgaW4gdGhlIGNvbnNvbGUgKHdoYXQ/IHdoYXQncyBhIGNvbnNvbGU/KS4uIFdlJ2xsIGNvbWUgdG8gdGhpcyBsYXRlciBvbiENCg0KIyMjIERvd25sb2FkaW5nIE1jcm9zb2Z0IFIgT3Blbg0KDQpJZiB5b3UgYXJlIGFmdGVyIG1vcmUgc3BlZWQsIHRoZW4gdXNlIGBNaWNyb3NvZnQgUiBPcGVuYCBkaXN0cmlidXRpb24uIFRoaXMgaXMgYW4gZW5oYW5jZWQgdmVyc2lvbiBvZiBgUmAgdGhhdCBhbGxvd3MgZm9yIG11bHRpY29yZSBhbmQgbXVsdGl0aHJlYWRpbmcgKipieSBkZWZhdWx0KiouIFRoaXMgbWVhbnMgeW91IHdpbGwgaGF2ZSBhbiBpbmNyZWFzZSBpbiBzcGVlY2ggb24gaG93IHZhcmlvdXMgYW5hbHlzZXMgYXJlIGNvbXB1dGVkLiANCllvdSBjYW4gZG93bmxvYWQgaXQgW2hlcmVdKGh0dHBzOi8vbXJhbi5taWNyb3NvZnQuY29tLykuIFRoaXMgdXNlZCB0byBiZSBwYXJ0IG9mIGBSZXZvbHV0aW9uIFIgT3BlbmAgdGhhdCB3YXMgYm91Z2h0IGJ5IE1pY3Jvc29mdC4gSXQgaXMgYW4gT3BlbiBzb3VyY2UgZGlzdHJpYnV0aW9uIChhbmQgSSB1c2UgaXQgYWxsIHRoZSB0aW1lKS4gVGhpcyBpcyBjb21wYXRpYmxlIHdpdGggYW55IE9wZXJhdGluZyBTeXN0ZW0gKFdpbmRvd3MsIE1hYywgTGludXgpLCBidXQgaXQgd2FzIHNob3duIHRvIGhhdmUgYSBtYWpvciBpbXBhY3Qgd2l0aCB3aW5kb3dzIE9TLi4uDQoNClRoaXMgZGlzdHJpYnV0aW9uIHVzdWFsbHkgdGFrZXMgYSBjb3VwbGUgb2Ygd2Vla3MgdG8gYmUgdXBkYXRlZCBhZnRlciBhbiBgUmAgdXBkYXRlIGFuZCB0aGUgcGFja2FnZXMgYXJlIGZpeGVkIGluIHRpbWUsIGkuZS4sIGFueSB1cGRhdGVzIHRvIHBhY2thZ2VzIHdpbGwgbm90IG9jY3VyIHVudGlsIHRoZSBuZXh0IG9mZmljaWFsIHJlbGVhc2UuIFRoaXMgaXMgbm90IGFuIGlzc3VlIGFzIHBhY2thZ2UgdXBkYXRlcyBhcmUgbm90IHRvbyBmcmVxdWVudC4NCg0KIyMgUiBTdHVkaW8NCg0KW1IgU3R1ZGlvXShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS8pIGlzIG9uZSBvZiB0aGUgbW9zdGx5IHVzZWQgZnJlZSBhbmQgb3Blbi1zb3VyY2UgaW50ZWdyYXRlZCBkZXZlbG9wbWVudCBlbnZpcm9ubWVudCBmb3IgYFJgLiBJdCBhbGxvd3MgdGhlIHVzZXIgdG8gaGF2ZSBhY2Nlc3MgdG8gdmFyaW91cyBpbmZvcm1hdGlvbiBhdCB0aGUgc2FtZSB0aW1lLCBlLmcuLCB0aGUgYFNvdXJjZWAsIHRoZSBgQ29uc29sZWAsIHRoZSBgRW52aXJvbm1lbnRgIGFuZCB0aGUgYEZpbGVzYCwgZXRjLiBXaGVuIHlvdSBvcGVuIGBSIHN0dWRpb2AsIGFuZCBpZiB5b3UgaGF2ZSBpbnN0YWxsZWQgYFJgIGFwcHJvcHJpYXRlbHksIHRoZW4gYFJgIFN0dWRpbyB3aWxsICJ0YWxrIiB0byBgUmAgYnkgc2VuZGluZyBpdCBtZXNzYWdlcyB0byBleGVjdXRlIGNvbW1hbmRzLiANCg0KWW91IGNhbiBzZXQgdXAgdGhlIGxheW91dCB0byBzdWl0IHlvdXIgbmVlZHMuIEkgYWx3YXlzIGZpbmQgdGhlIGZvbGxvd2luZyBsYXlvdXQgYmVzdCBmb3IgbXkgbmVlZHM6IA0KDQoxLiBUaGUgYFNvdXJjZWAgcGFuZTogdGhlIGZpbGUgd2hlcmUgeW91IHdyaXRlIHlvdXIgY29kZSANCjIuIFRoZSBgQ29uc29sZWAgd2hlcmUgYWN0dWFsIGNvZGUgaXMgcnVuIA0KMy4gVGhlIGBFbnZpcm9ubWVudGAgcGFuZSwgd2hpY2ggc2hvd3MgeW91IGFsbCB2YXJpYWJsZXMvZGF0YXNldHMsIHdpdGggdGhlIGhpc3Rvcnkgb2YgZXhlY3V0ZWQgY29kZSwgZXRjLiANCjQuIFRoZSBgRmlsZXMvVmlld2VyYCBwYW5lLCB3aGljaCBzaG93cyB5b3UgdGhlIGZpbGVzIGluIHRoZSBjdXJyZW50IGZvbGRlciwgdGhlIHBsb3RzLCB0aGUgaW5zdGFsbGVkIHBhY2thZ2VzLCBhbmQgaGVscCBmaWxlcywgZXRjLg0KDQpJZiB5b3UgY2xpY2sgb24gVG9vbHMgYW5kIEdsb2JhbCBvcHRpb25zLCB0aGVuIFBhbmUgTGF5b3V0LCB5b3UgY2FuIGNoYW5nZSB0aGUgb3JkZXIsIGFuZCBhZGQvcmVtb3ZlIG9wdGlvbnMgZnJvbSB0aGUgdHdvIHBhbmVzIGJlbG93IA0KDQojIyBPdGhlciBvcHRpb25zPw0KDQojIyMgVGV4dCBFZGl0b3JzDQoNCkkgdXNlIFtTdWJsaW1lIFRleHRdKGh0dHBzOi8vd3d3LnN1YmxpbWV0ZXh0LmNvbS8pIHRvIHJ1biBQeXRob24sIFByYWF0IGFuZCB3cml0ZSBpbiAkXExhVGVYJC4gSSB1c2UgUiBNYXJrZG93biBpbiBSIHRvIHB1Ymxpc2ggbXkgY29kZSBhbmQgd3JpdGUgbm90ZWJvb2tzLiBJIGFtIGluIHRoZSBwcm9jZXNzIG9mIHdyaXRpbmcgbXkgZmlyc3QgYXJ0aWNsZSB3aXRoIFIgTWFya2Rvd24gZm9yIGEgZnVsbHkgcmVwcm9kdWNpYmxlIHJlc2VhcmNoLg0KDQpUaGVyZSBhcmUgbWFueSBkZXZlbG9wbWVudCBlbnZpcm9ubWVudHMgdGhhdCBjYW4gYmUgdXNlZCB0byAidGFsayIgdG8gUjogW1Rpbm5SXShodHRwczovL3NvdXJjZWZvcmdlLm5ldC9wL3Rpbm4tci93aWtpL0hvbWUvKSwgW1Zpc3VhbCBTdHVkaW9dKGh0dHBzOi8vdmlzdWFsc3R1ZGlvLm1pY3Jvc29mdC5jb20vKSwgZXRjLi4uDQoNCiMjIyBSIEdVSXMNCg0KR1VJcyAoZm9yIEdyYXBoaWNhbCBVc2VyIEludGVyZmFjZSkgZm9yIGBSYCBhcmUgYXZhaWxhYmxlLiBJIGxpc3QgYmVsb3cgYSBmZXcuIEhvd2V2ZXIsIGFmdGVyIHRyeWluZyBzb21lIG9mIHRoZXNlLCBJIGZvdW5kIGl0IG11Y2ggZWFzaWVyIHRvIGdldCB0byBjb2RlIGRpcmVjdGx5IGluIFIuIEkgZG9uJ3QgcmVtZW1iZXIgYWxsIGNvZGVzISBJIHVzZSB0aGVzZSB0byBteSBhZHZhbnRhZ2UsIGJ5IHNhdmluZyBteSBjb2RlIGludG8gYSBzY3JpcHQgYW5kIHVzaW5nIGl0IGxhdGVyIG9uIGluIG90aGVyIHNjcmlwdHMuIA0KDQpTb21lIG9mIHRoZSBHVUlzIGFyZSBtZWFudCB0byBtYWtlIGBSYCBsaWtlIGV4Y2VsIG9yIFNQU1MsIHdoaWxlIG90aGVycyBhcmUgbW9yZSBzcGVjaWFsaXNlZC4gSGVyZSBpcyBhIGxpc3Qgb2Ygc29tZSBvZiB0aGVzZSBHVUlzLi4uIA0KDQoxLiBbUkNvbW1hbmRlcl0oaHR0cHM6Ly93d3cucmNvbW1hbmRlci5jb20vKSBpcyB0aGUgZmlyc3QgR1VJIEkgdXNlZCAoYW5kIGhhdGVkISkuIEl0IGlzIHRoZSBvbmUgdXNlZCBpbiBEaXNjb3ZlcmluZyBTdGF0aXN0aWNzIHVzaW5nIFIgYnkgQW5keSBGaWVsZC4gVGhlcmUgYXJlIGNvbXBhdGliaWxpdHkgaXNzdWVzIGJldHdlZW4gUkNvbW1hbmRlciBhbmQgUlN0dWRpby4uLiBZb3UgYXJlIG9ubHkgYWJsZSB0byBydW4gUkNvbW1hbmRlciBmcm9tIHdpdGhpbiBgUmAgZGlyZWN0bHkgKHVzaW5nIGBsaWJyYXJ5KFJjbWRyKWAgZnJvbSB3aXRoaW4gYFJgKQ0KMi4gW3JhdHRsZV0oaHR0cHM6Ly9yYXR0bGUudG9nYXdhcmUuY29tLykgaXMgbW9yZSBvZiB1c2UgZm9yIGRhdGEgbWluaW5nIGFuZCBhZHZhbmNlZCBzdGF0aXN0aWNzICh1c2UgYGxpYnJhcnkocmF0dGxlKWAgdGhlbiBgcmF0dGxlKClgIHRvIHJ1bikNCjMuIFtEZWR1Y2VyXShodHRwOi8vd3d3LmRlZHVjZXIub3JnL3Btd2lraS9pbmRleC5waHA/bj1NYWluLkRlZHVjZXJNYW51YWw/ZnJvbT1NYWluLkhvbWVQYWdlKS4gRm9yIGJhc2ljIGFuZCBhZHZhbmNlZCBzdGF0aXN0aWNzIChydW4gd2l0aCBgbGlicmFyeShEZWR1Y2VyKWAgYWZ0ZXIgaW5zdGFsbGF0aW9uKQ0KNC4gW1JLV2FyZF0oaHR0cHM6Ly9ya3dhcmQua2RlLm9yZy8pLiBGb3IgYmFzaWMgYW5kIGFkdmFuY2VkIHN0YXRpc3RpY3MuIE5vdCBhdmFpbGFibGUgb24gQ1JBTiBhbmQgc2hvdWxkIGJlIGRvd25sb2FkZWQgYW5kIGluc3RhbGxlZC4gDQo1LiBFdGMuDQoNCllvdSBjYW4gYWx3YXlzIHN0YXJ0IGJ5IHVzaW5nIGFueSBvZiB0aGUgYWJvdmUgdG8gZmFtaWxpYXJpc2UgeW91cnNlbGYgd2l0aCB0aGUgY29kZSwgYW5kIHRoZW4gbW92ZSB0byB1c2luZyBgUmAgZnVsbHkgdmlhIGNvZGUuIE15IHJlY29tbWVuZGF0aW9uIGlzIHRvIHN0YXJ0IGNvZGluZyBmaXJzdCB0aGluZyBhbmQgc2VhcmNoIGZvciBoZWxwIG9uIGhvdyB0byB3cml0ZSB0aGUgc3BlY2lmaWMgY29kZSB5b3UgYXJlIGFmdGVyLiANCg0KIyBBbSBJIHJlYWR5IHRvIHVzZSBSIG5vdz8NCg0KV2VsbCBhbG1vc3QuIFRoZXJlIGlzIG9uZSB0aGluZyB3ZSBuZWVkIHRvIGNvbnNpZGVyOiB0ZWxsaW5nIGBSYCB3aGVyZSBpcyBvdXIgd29ya2luZyBkaXJlY3RvcnkuIEJ5IGRlZmF1bHQgYFJgIHNhdmVzIHRoaXMgdG8geW91ciBkb2N1bWVudHMgKG9yIHNvbWV3aGVyZSBlbHNlKS4gRm9yIHRoaXMgd29ya3Nob3AsIHRoaXMgaXMgZ2VuZXJhbGx5IE9LLCB0aG91Z2ggd2hlbiB3b3JraW5nIG9uIHlvdXIgb3duIGRhdGEsIHRoaW5ncyBnZXQgbW9yZSBjb21wbGljYXRlZC4gDQoNClRoZXJlIGFyZSB0d28gc2Nob29scyBvZiB0aG91Z2h0IGhlcmUuDQoxLiBDcmVhdGUgYFJgIHNjcmlwdHMgdGhhdCBydW4gdGhlIGFuYWx5c2VzIGFuZCBzYXZlcyB0aGUgb3V0cHV0KHMpIGRpcmVjdGx5IHRvIHlvdXIgd29ya2luZyBkaXJlY3RvcnkuIERvZXMgbm90IHNhdmUgdGhlIGAuUkRhdGFgIGltYWdlIGF0IHRoZSBlbmQNCjIuIENyZWF0ZSBhIHByb2plY3Q6IGEgc2VsZi1jb250YWluZWQgZm9sZGVyLCB3aGVyZSBhbGwgeW91ciBzY3JpcHRzLCBmaWd1cmVzLCBldGMuIHdpbGwgYmUgYXV0b21hdGljYWxseSBzYXZlZC4gU2F2ZXMgdGhlIGAuUkRhdGFgIGF0IHRoZSBlbmQNCg0KSSBzdWJzY3JpYmUgdG8gdGhlIHNlY29uZCwgYXMgc29tZSBvZiB0aGUgY29tcHV0YXRpb25zIEkgcnVuIHRha2UgYWdlcyB0byBmaW5pc2guDQoNCiMjIFNldHRpbmcgd29ya2luZyBkaXJlY3RvcnkNCg0KQ2xpY2sgdGhlIG1lbnUgYFNlc3Npb24gLT4gU2V0IFdvcmtpZ24gRGlyZWN0b3J5IC0+IENob29zZSBEaXJlY3RvcnlgIG9yIHVzZSBgc2V0d2QoInBhdGgvdG8vZGlyZWN0b3J5IilgIChjaG9vc2UgdGhlIGxvY2F0aW9uIHdoZXJlIHlvdSB3YW50IHRvIHNhdmUgdGhlIHJlc3VsdHMpDQoNCllvdSBjYW4gYWxzbyB1c2UgYGdldHdkKClgDQoNCiMjIENyZWF0aW5nIGEgcHJvamVjdA0KDQpMb29rIGF0IHRoZSB0b3AtcmlnaHQgaGFuZCB3aGVyZSB5b3UgY2FuIHNlZSBgUHJvamVjdHMgKG5vbmUpYC4gWW91IGNhbiBjcmVhdGUgYSBuZXcgcHJvamVjdCBpbiBhIG5ldyBwYXRoIG9yIGJhc2VkIG9uIGEgc3BlY2lmaWMgZm9sZGVyLiANCg0KIyBIb3cgdG8gdXNlIHBhY2thZ2VzPw0KDQojIyBJbnN0YWxsYXRpb24NCg0KVGhlIGJlc3Qgb3B0aW9uIGlzIHRvIHVzZSB0aGUgbWVudSBhYm92ZSAodW5kZXIgVG9vbHMpIGFuZCBjbGljayBgSW5zdGFsbCBwYWNrYWdlc2AsIG9yIHR5cGUgaW4gaW5zdGFsbC5wYWNrYWdlcygicGFja2FnZS5uYW1lIikuIE1ha2Ugc3VyZSB0byBhbHdheXMgaGF2ZSBgaW5zdGFsbCBkZXBlbmRlbmNpZXNgIHRpY2tlZCAodXNpbmcgdGhlIGZpcnN0IG9wdGlvbikuIA0KDQojIyBMb2FkaW5nDQoNClVzZSB0aGUgZm9sbG93aW5nIHRvIGxvYWQgYSBwYWNrYWdlOiBgbGlicmFyeShwYWNrYWdlLm5hbWUpYC4gT25jZSB0aGUgcGFja2FnZSBpcyBsb2FkZWQsIHlvdSBjYW4gdXNlIGFueSBvZiBpdHMgZnVuY3Rpb25zIGRpcmVjdGx5IGludG8geW91ciBjb2RlLiBTb21ldGltZXMgeW91IG1heSBuZWVkIHRvIHNwZWNpZnkgdG8gdXNlIGEgcGFydGljdWxhciBmdW5jdGlvbiBmcm9tIHdpdGhpbiBhIHBhcnRpY3VsYXIgcGFja2FnZSwgaW4gdGhpcyBjYXNlIHVzZTogYHBhY2thZ2UubmFtZTo6ZnVuY3Rpb25gLiBXZSB3aWxsIG1vc3QgcHJvYmFibHkgbm90IHVzZSB0aGlzIHRvZGF5LCBidXQgdGhpcyBpcyBzb21ldGhpbmcgeW91IG5lZWQgdG8ga25vdyBhYm91dCBvdGhlcndpc2UgdW5kZXNpcmFibGUgcmVzdWx0cyBtYXkgb2NjdXIgKG9yIGV2ZW4gZXJyb3JzISkuDQoNCiMjIEZpbmRpbmcgcGFja2FnZXMgYW5kIGhlbHAgDQoNClVuZGVyIHRoZSBGaWxlcyBwYW5lIChyaWdodCBib3R0b20pLCBjbGljayBvbiB0aGUgbWVudSBQYWNrYWdlcyBhbmQgeW91IHdpbGwgaGF2ZSBhY2Nlc3MgdG8gYWxsICoqaW5zdGFsbGVkKiogcGFja2FnZXMuIENsaWNrIG9uIGEgcGFja2FnZSBhbmQgeW91IGNhbiBzZWUgdGhlIGFzc29jaWF0ZWQgaGVscCBmaWxlcy4gDQpZb3UgY2FuIGFsc28gdHlwZSB0aGUgZm9sbG93aW5nIHRvIGZpbmQgaGVscDoNCj9wYWNrYWdlLm5hbWUuIA0KPz9mdW5jdGlvbg0KZS5nLiwgDQoNCmBgYHtyfQ0KP3N0YXRzDQpgYGANCg0KDQpgYGB7cn0NCj8/TUFTUw0KYGBgDQoNCk9yIHRyeSBjbGlja2luZyBvbiB0aGUgZnVuY3Rpb24gbmFtZSB0byBmaW5kIGRldGFpbHMgb2Ygd2hhdCB0byBzcGVjaWZ5OiBlLmcuLCBzY3JvbGwgb24gYGxtZXJgIChhc3N1bWluZyBgbG1lNGAgaXMgaW5zdGFsbGVkKS4gRG8gYSBDdHJsL0NtZCArIGxlZnQgbW91c2UgY2xpY2sgb24gYSBmdW5jdGlvbiB0byBkaXNwbGF5IG9wdGlvbnMuDQoNCmBgYHtyfQ0KbG1lNDo6bG1lcg0KYGBgDQoNCiMjIFVwIHRvIHlvdS4uLg0KDQpJbnN0YWxsIGEgcGFja2FnZSBhbmQgc2VhcmNoIGZvciBoZWxwLiANCg0KIyBMZXQncyBnZXQgc3RhcnRlZCB3aXRoIFINCg0KIyMgUiBhcyBhIGNhbGN1bGF0b3INCg0KIyMjIFNpbXBsZSBjYWxjdWxhdGlvbnMNCg0KYFJgIGNhbiBiZSB1c2VkIGFzIGEgY2FsY3VsYXRvci4gVHJ5IHNvbWUgb2YgdGhlIGZvbGxvd2luZyBiZWxvdzoNCg0KYGBge3J9DQoxICsgMg0KYGBgDQoNCmBgYHtyfQ0KMSsyKjMNCmBgYA0KDQpXZWxsIHdhaXQgYSBzZWNvbmQhIHdlcmUgeW91IGFsbCBleHBlY3RpbmcgdGhlIHJlc3VsdCB0byBiZSA3PyBob3cgbWFueSBleHBlY3RlZCB0aGUgcmVzdWx0IHRvIGJlIDk/DQpDaGVjayB0aGUgZm9sbG93aW5nOg0KDQpgYGB7cn0NCigxKzIpKjMNCmBgYA0KDQpgYGB7cn0NCjErKDIqMykNCmBgYA0KDQpTbyBwYXJlbnRoZXNpcyBhcmUgaW1wb3J0YW50ISBBbHdheXMgdXNlIHRoZXNlIHRvIHRlbGwgUiAoYW5kIGFueSBvdGhlciBzb2Z0d2FyZSkgdGhlIG9yZGVyIG9mIG9wZXJhdGlvbnMuIFRoaXMgaXMgdGhlIG9yZGVyOg0KMS4gUGFyZW50aGVzZXMNCjIuIEV4cG9uZW50cw0KMy4gTXVsdGlwbGljYXRpb24gYW5kIERpdmlzaW9uIChmcm9tIGxlZnQgdG8gcmlnaHQpDQo0LiBBZGRpdGlvbiBhbmQgU3VidHJhY3Rpb24gKGZyb20gbGVmdCB0byByaWdodCkNCg0KIyMjIEZ1bmN0aW9ucw0KDQpUaGVyZSBhcmUgbWFueSBidWlsdC1pbiBmdW5jdGlvbnMgaW4gUiB0byBkbyBzb21lIGNvbXBsaWNhdGVkIG1hdGhlbWF0aWNhbCBjYWxjdWxhdGlvbnMuIA0KDQojIyMjIEJhc2ljIGZ1bmN0aW9ucw0KDQpSdW4gc29tZSBvZiB0aGUgZm9sbG93aW5nLg0KDQpgYGB7cn0NCnNxcnQoMykNCmBgYA0KDQpgYGB7cn0NCjNeMg0KYGBgDQoNCmBgYHtyfQ0KbG9nKDMpDQpgYGANCg0KIyMjIyBDcmVhdGluZyB2YXJpYWJsZXMgDQoNCldlIGNhbiBhbHNvIGNyZWF0ZSB2YXJpYWJsZXMgKGFrYSB0ZW1wb3JhcnkgcGxhY2UgaG9sZGVycykuDQoNCmBgYHtyfQ0KeCA8LSAyDQp5IDwtIDUNCmIgPC0geCp5DQp4DQp5DQpiDQpiK2xvZyh5KSp4XjINCmBgYA0KDQpXaGVuIHlvdSBjcmVhdGUgYSB2YXJpYWJsZSBhbmQgYXNzaWduIHRvIGl0IGEgbnVtYmVyIChvciBjaGFyYWN0ZXJzKSwgeW91IGNhbiB1c2UgaXQgbGF0ZXIgb24uDQoNCiMjIyMgU2VxdWVuY2VzDQoNCldlIGNhbiBhbHNvIGNyZWF0ZSBzZXF1ZW5jZXMgb2YgbnVtYmVycw0KDQpgYGB7cn0NCnNlcSgxLDEwLDIpDQpgYGANCg0KYGBge3J9DQp6IDwtIDE6MTANCmBgYA0KDQpBbmQgd2UgY2FuIGRvIHRoZSBmb2xsb3dpbmcuLiBDYW4geW91IGV4cGxhaW4gd2hhdCB3ZSBoYXZlIGRvbmUgaGVyZT8NCg0KYGBge3J9DQp6MiA8LSB6KzENCnoqejINCmBgYA0KDQoNClVwIHRvIHlvdS4uLiBXcml0ZSBzb21lIG1vcmUgY29tcGxleCBtYXRocyBoZXJlIGp1c3QgZm9yIGZ1biENCg0KYGBge3J9DQojIEFkZCBiZWxvdw0KDQoNCmBgYA0KDQojIyBPYmplY3RzDQoNCiMjIyBCYXNpYyBvYmplY3RzDQoNCk9iamVjdHMgYXJlIHJlbGF0ZWQgdG8gdmFyaWFibGVzICh3ZSBjcmVhdGVkIGFib3ZlKSwgYnV0IGNhbiBhbHNvIGJlIGRhdGFmcmFtZXMsIGFuZCBvdGhlciB0aGluZ3Mgd2UgY3JlYXRlIGluIFIuIEFsbCBvZiB0aGVzZSBhcmUgc3RvcmVkIGluIG1lbW9yeSBhbmQgYXJlIHNob3duIGJlbG93ICh1bmRlciBlbnZpcm9ubWVudCkuIFlvdSBjYW4gY2hlY2sgdGhlIHR5cGUgb2YgdGhlICJvYmplY3QiIGJlbG93IGluIHRoZSBsaXN0IChsb29rIGF0ICJUeXBlIikgb3IgYnkgdXNpbmcgYGNsYXNzKClgLg0KDQpMZXQncyBsb29rIGF0IHRoZSB2YXJpYWJsZXMgd2UgY3JlYXRlZCBzbyBmYXIuLiBXZSB3aWxsIGNyZWF0ZSBhbm90aGVyIG9uZSBhcyB3ZWxsLi4uIA0KDQpgYGB7cn0NCmNsYXNzKGIpDQpjbGFzcyh4KQ0KY2xhc3MoeSkNCmNsYXNzKHopDQpjbGFzcyh6MikNCg0KYSA8LSAidGVzdCINCg0KY2xhc3MoYSkNCmBgYA0KDQpXaGVuIHdlIGRvIGNhbGN1bGF0aW9ucyBpbiBSLCB3ZSBuZWVkIHRvIG1ha2Ugc3VyZSB3ZSB1c2UgbnVtZXJpYy9pbnRlZ2VyIHZhcmlhYmxlcyBvbmx5Li4gVHJ5IHNvbWUgb2YgdGhlIGJlbG93DQoNCmBgYHtyfQ0KeCt5DQp0d28gPC0gIjIiDQp4ICsgdHdvDQpgYGANCg0KQ2FuIHlvdSBleHBsYWluIHRoZSBlcnJvcj8gDQoNCldlIGhhdmUgdHJpZWQgdG8gYWRkIGEgbnVtYmVyIHRvIGEgKGNoYXJhY3Rlcikgc3RyaW5nIHdoaWNoIGlzIGNsZWFybHkgaW1wb3NzaWJsZS4gDQpUbyBkbyB0aGUgbWF0aHMsIHdlIG5lZWQgdG8gY2hhbmdlIHRoZSBjbGFzcyB1c2luZyBhbnkgb2YgdGhlIGZvbGxvd2luZyBjb21tYW5kczogYGFzLmNoYXJhY3RlcmAsIGBhcy5pbnRlZ2VyYCwgYGFzLm51bWVyaWNgLCBgYXMuZmFjdG9yYCwgZS5nLjoNCg0KYGBge3J9DQp0d28gPC0gYXMubnVtZXJpYyh0d28pDQp4ICsgdHdvDQpgYGANCg0KIyMjIE90aGVyIGZ1bmN0aW9ucyBhbmQgb2JqZWN0cw0KDQojIyMjIFNvbWUgbW9yZSBjYWxjdWxhdGlvbnMNCg0KV2UgY2FuIGNyZWF0ZSBhIHZlY3RvciBvZiBvYmplY3RzIHRvIGRvIHZhcmlvdXMgdGhpbmdzIG9uLi4gV2UgdXNlIHRoZSBmdW5jdGlvbiBgYygpYCBhbmQgZG8gdmFyaW91cyB0aGluZ3Mgb246DQoNCmBgYHtyfQ0KbnVtYmVycyA8LSBjKDEsNCw1LDEyLDU1LDEzLDQ1LDM4LDc3LDgzNiw1NDMpDQpjbGFzcyhudW1iZXJzKQ0KbWVhbihudW1iZXJzKQ0Kc2QobnVtYmVycykNCm1lZGlhbihudW1iZXJzKQ0KbWluKG51bWJlcnMpDQptYXgobnVtYmVycykNCnJhbmdlKG51bWJlcnMpDQpgYGANCg0KIyMjIyBSZWZlcnJpbmcgdG8gYSBzcGVjaWZpYyBwb3NpdGlvbg0KDQpTb21ldGltZXMgd2UgbWF5IHdhbnQgdG8gcmVmZXIgdG8gYSBzcGVjaWZpYyBwb3NpdGlvbiBpbiB0aGUgbGlzdCBvZiBudW1iZXJzIHdlIGp1c3QgY3JlYXRlZC4uLiBVc2UgdGhlIGZvbGxvd2luZzoNCg0KYGBge3J9DQpudW1iZXJzWzJdDQpudW1iZXJzWzM6NV0NCm51bWJlcnNbLTRdDQpudW1iZXJzK251bWJlcnNbNl0NCmBgYA0KDQpDYW4geW91IGV4cGxhaW4gd2hhdCB3ZSBoYXZlIGRvbmUgaW4gdGhlIGxhc3Qgb3BlcmF0aW9uPw0KDQojIyMgRGF0YWZyYW1lcw0KDQpBIGRhdGFmcmFtZSBpcyB0aGUgbW9zdCBpbXBvcnRhbnQgb2JqZWN0IHdlIHdpbGwgYmUgdXNpbmcgb3ZlciBhbmQgb3ZlciBhZ2Fpbi4uLiBJdCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBpbmZvcm1hdGlvbiBpbiBib3RoIHJvd3MgYW5kIGNvbHVtbnMuIA0KDQojIyMjIENyZWF0aW5nIGEgZGF0YWZyYW1lIGZyb20gc2NyYXRjaCANCg0KSW4gdGhpcyBleGVyY2lzZSwgd2Ugd2lsbCBjcmVhdGUgYSA0KjkgZGF0YWZyYW1lLiBUaGUgY29kZSBiZWxvdyBjcmVhdGVzIGZvdXIgdmFyaWFibGVzLCBhbmQgY29tYmluZXMgdGhlbSB0b2dldGhlciB0byBtYWtlIGEgZGF0YWZyYW1lLiBBcyB5b3UgY2FuIHNlZSwgdmFyaWFibGVzIGNhbiBhbHNvIGJlIGNoYXJhY3RlcnMuDQpUbyBjcmVhdGUgdGhlIGRhdGFmcmFtZSwgd2UgdXNlIHRoZSBmdW5jdGlvbnMgYGFzLmRhdGEuZnJhbWVgIGFuZCBgY2JpbmRgLg0KDQpgYGB7cn0NCndvcmQgPC0gYygiYSIsICJ0aGUiLCAibGFtcCIsICJub3QiLCAianVtcCIsICJpdCIsICJjb2ZmZWUiLCAid2FsayIsICJvbiIpDQpmcmVxIDwtIGMoNTAwLCA2MDAsIDcsIDIwMCwgMzAsIDQ1MCwgMTMwLCAzMywgMzAwKSAgIyBub3RlIHRoaXMgaXMgY29tcGxldGVseSBtYWRlIHVwISENCmZ1bmN0aW9ud29yZCA8LSBjKCJ5IiwgInkiLCAibiIsICJ5IiwgIm4iLCAieSIsICJuIiwgIm4iLCAieSIpDQpsZW5ndGggPC0gYygxLCAzLCA0LCAzLCA0LCAyLCA2LCA0LCAyKQ0KZGYgPC0gYXMuZGF0YS5mcmFtZShjYmluZCh3b3JkLGZyZXEsZnVuY3Rpb253b3JkLGxlbmd0aCkpDQpgYGANCg0KIyMjIyBEZWxldGluZyB2YXJpYWJsZXMgZnJvbSB0aGUgYEVudmlyb25tZW50YA0KDQpJZiB5b3UgaGF2ZSBjcmVhdGVkIHZhcmlvdXMgdmFyaWFibGVzIHlvdSBkbyBub3QgbmVlZCBhbnkgbW9yZSwgeW91IGNhbiB1c2UgYHJtYCB0byByZW1vdmUgdGhlc2UNCg0KYGBge3J9DQpybSh3b3JkLGZyZXEsZnVuY3Rpb253b3JkLGxlbmd0aCkNCmBgYA0KDQpCVVQgd2FpdCwgZGlkIEkgcmVtb3ZlIHRoZXNlIGZyb20gbXkgZGF0YWZyYW1lPyBXZWxsIG5vLi4gV2UgaGF2ZSByZW1vdmVkIG9iamVjdHMgZnJvbSB3aXRoaW4gdGhlIGBSYCBlbnZpcm9ubWVudCBhbmQgbm90IGZyb20gdGhlIGFjdHVhbCBkYXRhZnJhbWUuIExldCdzIGNoZWNrIHRoaXMgdXANCg0KYGBge3J9DQpkZg0KYGBgDQoNCiMjIyMgU2F2aW5nIGFuZCByZWFkaW5nIHRoZSBkYXRhZnJhbWUNCg0KIyMjIyMgUmVhZGluZyBhbmQgU2F2aW5nIGluIC5jc3YNCg0KVGhlIGNvZGUgYmVsb3cgYWxsb3dzIHlvdSB0byBzYXZlIHRoZSBkYXRhZnJhbWUgYW5kIHJlYWQgaXQgYWdhaW4uIFRoZSBleHRlbnNpb24gYC5jc3ZgIGlzIGZvciAiY29tbWEgZGVsaW1pdGVkIGZpbGVzIi4gVGhpcyBpcyB0aGUgYmVzdCBmb3JtYXQgdG8gdXNlIGFzIGl0IGlzIHNpbXBseSBhIHRleHQgZmlsZSB3aXRoIG5vIGFkZGl0aW9uYWwgZm9ybWF0dGluZy4NCg0KYGBge3J9DQp3cml0ZS5jc3YoZGYsImRmLmNzdiIpDQpkZk5ldyA8LSByZWFkLmNzdigiZGYuY3N2IikNCmRmDQpkZk5ldw0KYGBgDQoNClRoZSBuZXdseSBjcmVhdGVkIG9iamVjdCBjb250YWlucyA1IGNvbHVtbnMgcmF0aGVyIHRoYW4gdGhlIDQgd2UgaW5pdGlhbGx5IGNyZWF0ZWQuIFRoaXMgaXMgbm9ybWFsLiBCeSBkZWZhdWx0LCBgUmAgYWRkIGEgY29sdW1uIHRoYXQgcmVmbGVjdHMgdGhlIG9yZGVyIG9mIHRoZSBsaXN0ICpiZWZvcmUqIGl0IHdhcyBzYXZlZC4gWW91IGNhbiBzaW1wbHkgZGVsZXRlIHRoZSBjb2x1bW4gb3Iga2VlcCBhcyBpcyAoYnV0IGJlIGNhcmVmdWwgYXMgdGhpcyBtZWFucyB5b3UgbmVlZCB0byBhZGp1c3QgYW55IHJlZmVyZW5jZXMgdG8gY29sdW1ucyB0aGF0IHdlIHdpbGwgdXNlIGxhdGVyIG9uKS4NCg0KIyMjIyMgUmVhZGluZyBhbmQgc2F2aW5nIG90aGVyIGZvcm1hdHMNCg0KYFJgIGFsbG93cyB1cyB0byByZWFkIGRhdGEgaW4gYW55IGZvcm1hdC4gSWYgeW91IGhhdmUgYSBgLnR4dGAsIGAuc2F2YCwgYC54bHNgLCBgLnhsc3hgLCBldGMuLCB0aGVuIHRoZXJlIGFyZSBwYWNrYWdlcyBzcGVjaWZpYyB0byBkbyB0aGF0IChlLmcuLCBwYWNrYWdlIGB4bHN4YCB0byByZWFkL3NhdmUgYC54bHN4YCBmaWxlcywgb3IgdGhlIGZ1bmN0aW9uIGBoYXZlbmAgZnJvbSB0aGUgcGFja2FnZSAgYHRpZHl2ZXJzZWAgdG8gcmVhZC9zYXZlIGAuc2F2YCBmaWxlcykuIA0KDQpZb3UgY2FuIHVzZSB0aGUgYnVpbHQtaW4gcGx1Z2luIGluIGBSU3R1ZGlvYCB0byAqKmltcG9ydCoqIHlvdXIgZGF0YXNldC4gU2VlIGBJbXBvcnQgRGF0YXNldGAgd2l0aGluIHRoZSBgRW52aXJvbm1lbnRgLg0KDQpJbiBnZW5lcmFsLCBhbnkgc3BlY2lmaWMgZm9ybWF0dGluZyBpcyBrZXB0LCBidXQgc29tZXRpbWVzIHZhcmlhYmxlIG5hbWVzIGFzc29jaWF0ZWQgd2l0aCBudW1iZXJzIChhcyBpbiBgLnNhdmAgZmlsZXMpIHdpbGwgYmUgbG9zdC4gSGVuY2UsIGl0IGlzIGFsd2F5cyBwcmVmZXJhYmxlIHRvIGRvIG1pbmltYWwgZm9ybWF0dGluZyBvbiB0aGUgZGF0YS4uIFN0YXJ0IHdpdGggYSBgLmNzdmAgZmlsZSwgaW1wb3J0IGl0IHRvIGBSYCBhbmQgZG8gdGhlIG1hZ2ljIQ0KDQojIyMjIENoZWNraW5nIHRoZSBzdHJ1Y3R1cmUNCg0KVGhlIGZpcnN0IHRoaW5nIHdlIHdpbGwgZG8gaXMgdG8gY2hlY2sgdGhlIHN0cnVjdHVyZSBvZiBvdXIgY3JlYXRlZCBkYXRhc2V0LiBXZSB3aWxsIHVzZSB0aGUgb3JpZ2luYWxseSBjcmVhdGVkIG9uZSAoaS5lLiwgYGRmYCBhbmQgbm90IHRoZSBpbXBvcnRlZCBvbmUgKGkuZS4sIGBkZk5ld2ApLg0KDQpgYGB7cn0NCnN0cihkZikNCmBgYA0KDQpUaGUgZnVuY3Rpb24gYHN0cmAgZ2l2ZXMgdXMgdGhlIGZvbGxvd2luZyBpbmZvcm1hdGlvbjoNCjEuIEhvdyBtYW55IG9ic2VydmF0aW9ucyAoaS5lLiwgcm93cykgYW5kIHZhcmlhYmxlcyAoaS5lLiwgY29sdW1ucykNCjIuIFRoZSBuYW1lIG9mIGVhY2ggdmFyaWFibGUgKGxvb2sgYXQgYCRgIGFuZCB3aGF0IGNvbWVzIGFmdGVyIGl0KQ0KMy4gV2l0aGluIGVhY2ggdmFyaWFibGUsIHdlIGhhdmUgdGhlIGNsYXNzIHdpdGggbnVtYmVyIG9mIGxldmVscw0KDQojIyMjIyBDaGFuZ2luZyB0aGUgYGNsYXNzYCBvZiBhIHZhcmlhYmxlDQpBcyB3ZSBjYW4gc2VlLCB0aGUgZm91ciBjcmVhdGVkIHZhcmlhYmxlcyB3ZXJlIGFkZGVkIHRvIHRoZSBkYXRhZnJhbWUgYXMgYGZhY3RvcnNgLiBXZSBuZWVkIHRvIGNoYW5nZSB0aGUgYGNsYXNzYCBvZiB0aGUgKipudW1lcmljKiogdmFyaWFibGVzOiBmcmVxIGFuZCBsZW5ndGguIExldCdzIGRvIHRoYXQ6DQoNCmBgYHtyfQ0KZGYkZnJlcSA8LSBhcy5udW1lcmljKGRmJGZyZXEpDQpkZiRsZW5ndGggPC0gYXMubnVtZXJpYyhkZiRsZW5ndGgpDQpzdHIoZGYpDQpgYGANCg0KIyMjIyMgUmVmZXJyaW5nIHRvIHBhcnRpY3VsYXIgdmFyaWFibGVzLCBvYnNlcnZhdGlvbnMNCg0KQXMgeW91IGNhbiBzZWUgZnJvbSB0aGUgYWJvdmUsIHdlIGNhbiByZWZlciB0byBhIHBhcnRpY3VsYXIgdmFyaWFibGUgaW4gdGhlIGRhdGFmcmFtZSBieSBpdHMgbmFtZSBhbmQgYWRkaW5nIGAkYC4gVGhlcmUgYXJlIGFkZGl0aW9uYWwgb3B0aW9ucyB0byBkbyB0aGF0LiBMZXQncyBzZWUgd2hhdCB3ZSBjYW4gZG8uIENhbiB5b3UgdGVsbCB3aGF0IGVhY2ggb2YgdGhlIGJlbG93IGRvZXM/IGNoYXQgdG8geW91ciBuZWlnaGJvdXIuLi4uDQoNCmBgYHtyfQ0KZGZbMV0NCmRmWywxXQ0KZGZbMSxdDQpkZlsxLDFdDQpgYGANCg0KSGVyZSBhcmUgdGhlIGFuc3dlcnM6DQoxLiBSZWZlcnMgdG8gdGhlIGZ1bGwgY29sdW1uIDENCjIuIFJlZmVycyB0byBmaXJzdCB2YXJpYWJsZQ0KMy4gUmVmZXJzIHRvIGZpcnN0IHJvdw0KNC4gUmVmZXJzIHRvIGZpcnN0IG9ic2VydmF0aW9uIGluIGZpcnN0IGNvbHVtbg0KDQpQcmFjdGljZSBhIGJpdCBhbmQgdXNlIG90aGVyIHNwZWNpZmljYXRpb25zIHRvIG9idGFpbiBzcGVjaWZpYyBvYnNlcnZhdGlvbnMsIGNvbHVtbnMgb3Igcm93cy4uLg0KDQpgYGB7cn0NCiMgd3JpdGUgaGVyZQ0KDQpgYGANCg0KIyMjIyBCYXNpYyBzdW1tYXJpZXMsIHRhYmxlcw0KDQpXZSBjYW4gdXNlIHRoZSBmdW5jdGlvbiBgc3VtbWFyeWAgdG8gZG8gc29tZSBiYXNpYyBzdW1tYXJpZXMNCg0KYGBge3J9DQpzdW1tYXJ5KGRmKQ0KYGBgDQoNCldlIGNhbiBjcmVhdGUgYSB0YWJsZSB3aXRoIHRoZSBmdW5jdGlvbiBgdGFibGVgDQoNCmBgYHtyfQ0KdGFibGUoZGYkZnVuY3Rpb253b3JkLGRmJGZyZXEpDQpgYGANCg0KIyMjIyBCYXNpYyBtYW5pcHVsYXRpb25zDQoNCiMjIyMjIENyZWF0aW5nIHZhcmlhYmxlcw0KDQpXZSBzb21ldGltZXMgbmVlZCB0byBjcmVhdGUgYW5kL29yIGRlbGV0ZSBuZXcgdmFyaWFibGVzLi4gRG8geW91IGtub3cgaG93IHRvIGRvIHRoYXQ/DQoNCkxldCdzIGxvb2sgYXQgdGhlIHN0cnVjdHVyZSBhZ2FpbjoNCg0KYGBge3J9DQpzdHIoZGYpDQpgYGANCg0KV2Ugc2FpZCBlYXJsaWVyIHRoYXQgd2UgY2FuIHJlZmVyIHRvIGEgc3BlY2lmaWMgdmFyaWFibGUgYnkgdXNpbmcgYCRgICsgdGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlLiBMZXQncyB1c2UgdGhpcyBhZ2FpbiBhbmQgYWRkIGEgbmV3IG5hbWUgb2YgdmFyaWFibGUgbm90IGluIHRoZSBsaXN0IG9mIHZhcmlhYmxlcyBhYm92ZQ0KDQpgYGB7cn0NCmRmJG5ld1ZhcmlhYmxlDQpgYGANCg0KV2hhdCBkb2VzIGBOVUxMYCBtZWFuPyBUaGUgdmFyaWFibGUgZG9lcyBub3QgZXhpc3QhDQpMZXQncyBkbyBzb21ldGhpbmcgZWxzZQ0KDQpgYGB7cn0NCmRmJG5ld1ZhcmlhYmxlIDwtIE5BDQpgYGANCg0KQWggbm8gZXJyb3IgbWVzc2FnZXMhIExldCdzIGNoZWNrIHRoZSBzdHJ1Y3R1cmUNCg0KYGBge3J9DQpzdHIoZGYpDQpgYGANCg0KU28gd2Ugbm93IGhhdmUgZml2ZSB2YXJpYWJsZXMgYW5kIHRoZSBsYXN0IG9uZSBpcyBuYW1lZCAibmV3VmFyaWFibGUiIGFuZCBhc3NpZ25lZCAiTkEiLiAiTkEiIGlzIHVzZWQgaW4gYFJgIHRvIHJlZmVyIHRvIG1pc3NpbmcgZGF0YSBvciBpcyBhIHBsYWNlIGhvbGRlci4gV2UgY2FuIHJlcGxhY2UgdGhlc2Ugd2l0aCBhbnkgY2FsY3VsYXRpb25zLCBvciBhbnl0aGluZyBlbHNlLiBMZXQncyBkbyB0aGF0Og0KDQpgYGB7cn0NCmRmJG5ld1ZhcmlhYmxlIDwtIGxvZyhkZiRmcmVxKQ0Kc3RyKGRmKQ0KYGBgDQoNCldlIHJlcGxhY2VkICJOQSIgd2l0aCB0aGUgbG9nIG9mIHRoZSBmcmVxdWVuY2llcy4gTGV0J3MgY2hlY2sgdGhhdCB0aGlzIGlzIGNvcnJlY3Qgb25seSBmb3Igb25lIG9ic2VydmF0aW9uLiBDYW4geW91IGRpc3NlY3QgdGhlIGNvZGUgYmVsb3c/IHdoYXQgZGlkIEkgdXNlIHRvIGFzayBgUmAgdG8gY29tcHV0ZSB0aGUgbG9nIG9mIHRoZSBmcmVxdWVuY3kgKGZyZXEpPyBSZW1lbWJlciByb3dzIGFuZCBjb2x1bW5zDQoNCmBgYHtyfQ0KbG9nKGRmWzEsMl0pDQpkZlsxLDVdDQpgYGANCg0KU28gdGhleSBhcmUgdGhlIHNhbWUgdmFsdWVzLiANCg0KIyMjIyMgQ2hhbmdpbmcgY29sdW1uIG5hbWVzDQoNCk5vdyB3ZSBuZWVkIHRvIGNoYW5nZSB0aGUgbmFtZSBvZiB0aGUgdmFyaWFibGUgdG8gcmVmbGVjdCB0aGUgY29tcHV0YXRpb25zLiAibmV3VmFyaWFibGUiIGlzIG1lYW5pbmdsZXNzIGFzIGEgbmFtZSwgYnV0ICJsb2dGcmVxIiBpcyBpbmZvcm1hdGl2ZS4NCg0KYGBge3J9DQpjb2xuYW1lcyhkZilbNV0gPC0gImxvZ0ZyZXEiDQpzdHIoZGYpDQpgYGANCg0KQXMgY2FuIGJlIHNlZW4gZnJvbSB0aGUgYWJvdmUsIHVzaW5nIHRoZSBjb21tYW5kIGBjb2xuYW1lcyhkZilbNV0gPC0gImxvZ0ZyZXEiYCBhbGxvd3MgdXMgdG8gY2hhbmdlIHRoZSBjb2x1bW4gbmFtZSBpbiBwb3NpdGlvbiA1IG9mIHRoZSBkYXRhZnJhbWUuIElmIHdlIHdlcmUgdG8gY2hhbmdlIGFsbCBvZiB0aGUgY29sdW1ucyBuYW1lcywgd2UgY291bGQgdXNlIGBjb2xuYW1lcyhkZikgPC0gYygiY29sMSIsImNvbDIiLC4uLilgIi4gQXMgYW4gZXhlcmNpc2UsIGxldCdzIGRvIHRoYXQgbm93LiBDaGFuZ2UgdGhlIG5hbWVzIG9mIGFsbCBjb2x1bW5zOg0KDQpgYGB7cn0NCiMjIGNoYW5nZSBjb2x1bW4gbmFtZXMgaGVyZQ0KDQpgYGANCg0KIyMjIyMgRGVsZXRpbmcgdmFyaWFibGVzDQoNCkxldCB1cyBub3cgY3JlYXRlIGEgbmV3IGNvbXBvdW5kIHZhcmlhYmxlIHRoYXQgd2UgbGF0ZXIgZGVsZXRlLiBUaGlzIG5ldyBjb21wb3VuZCB2YXJpYWJsZSB3aWxsIHRoZSBtdWx0aXBsaWNhdGlvbiBvZiB0d28gbnVtZXJpYyB2YXJpYWJsZXMuIFRoZSByZXN1bHQgaXMgbWVhbmluZ2xlc3Mgb2YgY291cnNlLCBidXQgd2lsbCBiZSB1c2VkIGZvciB0aGlzIGV4ZXJjaXNlLiANCg0KYGBge3J9DQpkZiRtYWRlVXBWYXJpYWJsZSA8LSBkZiRmcmVxKmRmJGxlbmd0aA0Kc3RyKGRmKQ0KYGBgDQoNCkxldCB1cyBub3cgZGVsZXRlIHRoaXMgdmFyaWFibGUgZ2l2ZW4gdGhhdCB3ZSBhcmUgbm90IGludGVyZXN0ZWQgaW4uIERvIHlvdSBrbm93IGhvdyB0byBkbyB0aGF0PyBUaGluayBhYm91dCBob3cgd2UgcmVmZXJyZWQgdG8gYSB2YXJpYWJsZSBiZWZvcmU/IFdlIHVzZSBgZGZbY29sTnVtYmVyXWAuIFdoYXQgaWYgd2UgdXNlIGBkZlstY29sTnVtZWJyXWAsIHdoYXQgd291bGQgYmUgdGhlIHJlc3VsdD8gDQoNCmBgYHtyfQ0KZGZbLTZdDQpgYGANCg0KVGhpcyBzaG93cyBhbGwgY29sdW1ucyAqbWludXMqIHRoZSBvbmUgd2UgYXJlIG5vdCBpbnRlcmVzdGVkIGluLiBJZiB3ZSByZXdyaXRlIHRoZSB2YXJpYWJsZSBgZGZgIGFuZCBhc3NpZ24gdG8gaXQgdGhlIG5ld2x5IGNyZWF0ZWQgZGF0YWZyYW1lIHdlIGp1c3QgdXNlZCBhYm92ZSAod2l0aCB0aGUgbWludXMgc2lnbiksIHRoZW4gdGhlIGNvbHVtbiB3ZSBhcmUgbm90IGludGVyZXN0ZWQgaW4gd2lsbCBiZSBkZWxldGVkLiANCg0KDQpgYGB7cn0NCmRmIDwtIGRmWy02XQ0Kc3RyKGRmKQ0KYGBgDQoNCiMjIyMjIENoYW5naW5nIG5hbWVzIG9mIG9ic2VydmF0aW9ucw0KDQpMZXQncyBzYXkgdGhhdCB3ZSB3YW50IHRvIGNoYW5nZSB0aGUgbmFtZXMgb2Ygb3VyIG9ic2VydmF0aW9ucy4gRm9yIGluc3RhbmNlLCB0aGUgdmFyaWFibGUgImZ1bmN0aW9ud29yZCIgaGFzIHRoZSBsZXZlbHMgInkiIGFuZCAibiIuIExldCB1cyBjaGFuZ2UgdGhlIG5hbWVzIHRvIGJlY29tZSAieWVzIiBhbmQgIm5vIi4gV2UgZmlyc3QgbmVlZCB0byBjaGFuZ2UgdGhlIGBmYWN0b3JgIGxldmVsIHZhcmlhYmxlIGludG8gY2hhcmFjdGVyIGFuZCB0aGVuIGNoYW5nZSB0aGUgb2JzZXJ2YXRpb25zLiBUaGVuIHdlIG5lZWQgdG8gdHJhbnNmb3JtIGJhY2sgdG8gYSBmYWN0b3INCg0KYGBge3J9DQpkZiRmdW5jdGlvbndvcmQgPC0gYXMuY2hhcmFjdGVyKGRmJGZ1bmN0aW9ud29yZCkNCmRmJGZ1bmN0aW9ud29yZFtkZiRmdW5jdGlvbndvcmQgPT0gInkiXSA8LSAieWVzIg0KZGYkZnVuY3Rpb253b3JkW2RmJGZ1bmN0aW9ud29yZCA9PSAibiJdIDwtICJubyINCmRmJGZ1bmN0aW9ud29yZCA8LSBhcy5mYWN0b3IoZGYkZnVuY3Rpb253b3JkKQ0Kc3RyKGRmKQ0KYGBgDQoNCiMjIyMjIENoZWNraW5nIGxldmVscyBvZiBmYWN0b3JzDQoNCldlIGNhbiBhbHNvIGNoZWNrIHRoZSBsZXZlbHMgb2YgIGZhY3RvciBhbmQgY2hhbmdlIHRoZSByZWZlcmVuY2UgdmFsdWUuIFRoaXMgaXMgdXNlZnVsIHdoZW4gZG9pbmcgYW55IHR5cGUgb2Ygc3RhdGlzdGljcyBvciB3aGVuIHBsb3R0aW5nIHRoZSBkYXRhLiBXZSB1c2UgYGxldmVsc2AsIGByZWxldmVsYCBhbmQgYHJlZmANCg0KYGBge3J9DQpsZXZlbHMoZGYkZnVuY3Rpb253b3JkKQ0KZGYkZnVuY3Rpb253b3JkIDwtcmVsZXZlbChkZiRmdW5jdGlvbndvcmQsIHJlZiA9ICJ5ZXMiKQ0KbGV2ZWxzKGRmJGZ1bmN0aW9ud29yZCkNCmBgYA0KDQoNCldlIGNhbiBhbHNvIHVzZSB0aGUgZm9sbG93aW5nIGNvZGUgdG8gY2hhbmdlIHRoZSBvcmRlciBvZiB0aGUgbGV2ZWxzIG9mIGEgbXVsdGlsZXZlbCBmYWN0b3INCg0KYGBge3J9DQpsZXZlbHMoZGYkd29yZCkNCmRmJHdvcmQgPC0gZmFjdG9yKGRmJHdvcmQsIGxldmVscyA9IGMoImEiLCJjb2ZmZWUiLCJqdW1wIiwibGFtcCIsIm5vdCIsIml0Iiwib24iLCJ3YWxrIiwidGhlIikpDQpsZXZlbHMoZGYkd29yZCkNCmBgYA0KDQojIyMjIyBTdWJzZXR0aW5nIHRoZSBkYXRhZnJhbWUNCg0KV2UgbWF5IHNvbWV0aW1lcyBuZWVkIHRvIHN1YnNldCB0aGUgZGF0YWZyYW1lIGFuZCB1c2UgcGFydHMgb2YgaXQuIFdlIHVzZSB0aGUgZnVuY3Rpb24gYHN1YnNldGAgb3IgYHdoaWNoYC4gDQoNCmBgYHtyfQ0KZGZfWWVzMSA8LSBkZlt3aGljaChkZiRmdW5jdGlvbndvcmQgPT0gJ3llcycpLF0NCiNvcg0KZGZfWWVzMiA8LSBzdWJzZXQoZGYsIGZ1bmN0aW9ud29yZD09InllcyIpDQpzdHIoZGZfWWVzMSkNCnN0cihkZl9ZZXMyKQ0KYGBgDQoNCldoZW4gd2Ugc3Vic2V0IHRoZSBkYXRhLCB0aGUgbGV2ZWxzIG9mIGEgZmFjdG9yIGFyZSBrZXB0IGFzIHRoZXkgYXJlLiANCg0KYGBge3J9DQpsZXZlbHMoZGZfWWVzMSRmdW5jdGlvbndvcmQpDQpsZXZlbHMoZGZfWWVzMiRmdW5jdGlvbndvcmQpDQpgYGANCg0KQnV0IHdlIG9ubHkgaGF2ZSBvbmUgbGV2ZWwgb2Ygb3VyIGZhY3Rvci4uIA0KDQpgYGB7cn0NCmRmX1llczEkZnVuY3Rpb253b3JkDQpkZl9ZZXMyJGZ1bmN0aW9ud29yZA0KYGBgDQoNCkJ5IGRlZmF1bHQsIGBSYCBrZWVwcyB0aGUgbGV2ZWxzIG9mIHRoZSBmYWN0b3IgYXMgdGhleSBhcmUgdW5sZXNzIHdlIGNoYW5nZSBpdCBieSB1c2luZyB0aGUgZm9sbG93aW5nOg0KDQpgYGB7cn0NCmRmX1llczEkZnVuY3Rpb253b3JkIDwtIGZhY3RvcihkZl9ZZXMxJGZ1bmN0aW9ud29yZCkNCmRmX1llczIkZnVuY3Rpb253b3JkIDwtIGZhY3RvcihkZl9ZZXMyJGZ1bmN0aW9ud29yZCkNCmRmX1llczEkZnVuY3Rpb253b3JkDQpkZl9ZZXMyJGZ1bmN0aW9ud29yZA0KYGBgDQoNCg0KIyMgQmFzaWMgcGxvdHRpbmcNCg0KSW4gbW9zdCBjYXNlcywgd2Ugd2FudCB0byB2aXN1YWxpc2Ugb3VyIGRhdGEuIFdlIHdpbGwgdXNlIHRoZSBwb3dlciBvZiB0aGUgYmFzZSBgUmAgcGxvdHRpbmcuIA0KDQojIyMgQnVpbHQtaW4gZGF0YXNldHMNCg0KV2Ugd2lsbCB1c2Ugb25lIG9mIHRoZSBidWlsdCBpbiBgUmAuIFlvdSBjYW4gY2hlY2sgYWxsIGF2YWlsYWJsZSBkYXRhc2V0cyBpbiBgUmAgdXNpbmcgdGhlIGZvbGxvd2luZzoNCg0KYGBge3J9DQpkYXRhKCkNCiMgb3IgYmVsb3cgZm9yIGFsbCBkYXRhc2V0cyBhdmFpbGFibGUgaW4gYWxsIGluc3RhbGxlZCBwYWNrYWdlcw0KZGF0YShwYWNrYWdlID0gLnBhY2thZ2VzKGFsbC5hdmFpbGFibGUgPSBUUlVFKSkNCmBgYA0KDQpXZSB3aWxsIHVzZSB0aGUgYGlyaXNgIGRhdGFzZXQgZnJvbSB0aGUgcGFja2FnZSBgTUFTU2ANCg0KIyMjIENoZWNraW5nIHN0cnVjdHVyZSBhbmQgc3VtbWFyaWVzDQoNCmBgYHtyfQ0Kc3RyKGlyaXMpDQpgYGANCg0KV2UgaGF2ZSBhIGRhdGFmcmFtZSB3aXRoIDE1MCBvYnNlcnZhdGlvbnMgYW5kIDUgdmFyaWFibGVzOyA0IG51bWVyaWMgYW5kIDEgZmFjdG9yIHdpdGggMyBsZXZlbHMuIA0KDQpXZSBzdW1tYXJpc2UgdGhlIGRhdGEgdG8gc2VlIHRoZSB0cmVuZHM6DQoNCmBgYHtyfQ0Kc3VtbWFyeShpcmlzKQ0KYGBgDQoNClNvIHdlIGhhdmUgYW4gZXF1YWwgZGF0YWZyYW1lICg1MCBvYnNlcnZhdGlvbnMgdW5kZXIgZWFjaCBsZXZlbCBvZiB0aGUgZmFjdG9yIGBTcGVjaWVzYCksIHdpdGggbm8gbWlzc2luZyB2YWx1ZXMgKGFrYSBgTkFgKS4NCg0KIyMjIFR5cGVzIG9mIHBsb3RzDQoNCiMjIyMgSGlzdG9ncmFtDQoNClRoaXMgaXMgdXNlZnVsIHRvIGdldCBhIHNlbnNlIG9mIHRoZSBzaGFwZSBvZiBhIGRpc3RyaWJ1dGlvbi4gICBJdCdzIG5vdCB0b28gaW5mb3JtYXRpdmUgaGVyZSBidXQgd2lsbCBiZSB1c2VmdWwgZm9yIGJpZ2dlciBkYXRhc2V0cw0KDQpgYGB7cn0NCmhpc3QoaXJpcyRTZXBhbC5MZW5ndGgpDQpgYGANCg0KIyMjIyBTY2F0dGVycGxvdA0KDQpUaGlzIGFsbG93cyB1cyB0byB2aXN1YWxpc2UgYW55IHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0d28gbnVtZXJpYyB2YXJpYWJsZXMNCg0KYGBge3J9DQpwbG90KGlyaXMkU2VwYWwuTGVuZ3RoLCBpcmlzJFBldGFsLkxlbmd0aCkNCmBgYA0KDQojIyMjIEJveHBsb3RzDQpXZSBjYW4gcGxvdCBhIGJveHBsb3QuIFRoaXMgYWxsb3dzIHVzIHRvIHZpc3VhbGlzZSB0aGUgbWVkaWFuLCBhbmQgcXVhbnRpbGVzIGluIGFkZGl0aW9uIHRvIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gYW5kIGFueSBvdXRsaWVycy4uLiBBbGwgaW4gdGhlIHNhbWUgcGxvdCENCg0KDQpgYGB7cn0NCnBsb3QoaXJpcyRTcGVjaWVzLCBpcmlzJFNlcGFsLkxlbmd0aCkgDQojb3INCmJveHBsb3QoaXJpcyRTZXBhbC5MZW5ndGggfiBpcmlzJFNwZWNpZXMpICMgfiB0byBiZSByZWFkIGFzICJhcyBhIGZ1bmN0aW9uIG9mIg0KYGBgDQoNCiMjIyMgTGFiZWxsaW5nIHBsb3RzDQoNCldlIGNhbiBhZGQgbGFiZWxzIHRvIG91ciBwbG90cw0KDQpgYGB7cn0NCmJveHBsb3QoaXJpcyRTZXBhbC5MZW5ndGggfiBpcmlzJFNwZWNpZXMsIHhsYWIgPSAiU3BlY2llcyIsIHlsYWI9Ikxlbmd0aCIsIG1haW49IkEgYm94cGxvdCBvZiB0aGUgSXJpcyBkYXRhc2V0IikNCg0KYGBgDQoNCiMjIyMgVHJlbmQgbGluZXMNCg0KV2UgY2FuIGFsc28gYWRkIGEgdHJlbmQgbGluZSB0byBvdXIgcGxvdA0KDQpgYGB7cn0NCmJveHBsb3QoaXJpcyRTZXBhbC5MZW5ndGggfiBpcmlzJFNwZWNpZXMsIHhsYWIgPSAiU3BlY2llcyIsIHlsYWI9Ikxlbmd0aCIsIG1haW49IkEgYm94cGxvdCBvZiB0aGUgSXJpcyBkYXRhc2V0IHdpdGggYSBsaW5lYXIgdHJlbmQiKQ0KbGluZXMoaXJpcyRTcGVjaWVzLCBmaXR0ZWQobG0oU2VwYWwuTGVuZ3RoflNwZWNpZXMsIGRhdGE9aXJpcykpLGNvbD0iYmx1ZSIpDQpgYGANCg0KV2UgY2FuIGFsc28gdXNlIHRoZSBwbG90IGFib3ZlIG9uIHRoZSB0d28gbnVtZXJpYyB2YXJpYWJsZXMgdG8gcGxvdCBhIHRyZW5kIGxpbmUNCg0KYGBge3J9DQpwbG90KGlyaXMkU2VwYWwuTGVuZ3RoLCBpcmlzJFBldGFsLkxlbmd0aCwgeGxhYiA9ICJTZXBhbCBMZW5ndGgiLCB5bGFiPSJQZXRhbCBMZW5ndGgiLCBtYWluPSJBIHBsb3Qgb2YgdGhlIGxpbmVhciBhc3NvY2lhdGlvbiBiZXR3ZWVuIFNlcGFsIGFuZCBQZXRhbCBMZW5ndGgiKQ0KYWJsaW5lKGxtKFBldGFsLkxlbmd0aH5TZXBhbC5MZW5ndGgsIGRhdGE9aXJpcyksY29sPSJibHVlIikNCg0KYGBgDQoNCldlIGNhbiBvZiBjb3Vyc2UgYWRkIGFueSBvdGhlciB0cmVuZCBsaW5lcyBoZXJlLi4uDQoNCiMjIyMgV2l0aCBgZ2dwbG90MmANCg0KV2UgY2FuIHVzZSB0aGUgY29kZSBiZWxvdyB0byBwbG90IHRoZSBkYXRhDQoNCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdChkYXRhID0gaXJpcywgYWVzKHg9U3BlY2llcywgeSA9IFNlcGFsLkxlbmd0aCkpKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnMoeD0iU3BlY2llcyIseT0iTGVuZ3RoIix0aXRsZT0iQm94cGxvdCBhbmQgdHJlbmQgbGluZSIsc3VidGl0bGU9IndpdGggZ2dwbG90MiIpICsgDQogIHRoZW1lX3NldCh0aGVtZV9idygpKSArIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTUpKSsNCiAgZ2VvbV9zbW9vdGgoYWVzKHggPSBhcy5udW1lcmljKFNwZWNpZXMpLCB5ID0gU2VwYWwuTGVuZ3RoKSkNCmBgYA0KDQoNCg0KIyMjIyBVcCB0byB5b3UuLi4NCg0KRG8gYSBjb3VwbGUgb2YgcGxvdHMgYmFzZWQgb24gdGhlIGRhdGFzZXRzIGF2YWlsYWJsZQ0KDQpgYGB7cn0NCiMjIGhlcmUNCmBgYA0KDQoNCiMjIEJhc2ljIHN0YXRpc3RpY3MNCg0KV2UgYXJlIGFsbCBhZnRlciBydW5uaW5nIHNvbWUgc3RhdGlzdGljcyB0byBhcHByZWNpYXRlIG91ciByZXN1bHRzLiBXZSB3aWxsIHVzZSB0aGUgZGF0YXNldCBgaXJpc2AgdG8gZG8gYmFzaWMgc3RhdGlzdGljcw0KDQojIyMgQ29ycmVsYXRpb24gdGVzdHMNCg0KV2UgdXNlIHRoZSBmdW5jdGlvbiBgY29yYCB0byBvYnRhaW4gdGhlIHBlYXJzb24gY29ycmVsYXRpb24gYW5kIGBjb3IudGVzdGAgdG8gcnVuIGEgYmFzaWMgY29ycmVsYXRpb24gdGVzdCBvbiBvdXIgZGF0YSB3aXRoIHNpZ25pZmljYW5jZSB0ZXN0aW5nDQoNCmBgYHtyfQ0KY29yKGlyaXMkU2VwYWwuTGVuZ3RoLGlyaXMkU2VwYWwuV2lkdGgsbWV0aG9kID0gInBlYXJzb24iKQ0KY29yKGlyaXMkU2VwYWwuTGVuZ3RoLGlyaXMkUGV0YWwuTGVuZ3RoLG1ldGhvZCA9ICJwZWFyc29uIikNCmNvcihpcmlzJFNlcGFsLkxlbmd0aCxpcmlzJFBldGFsLldpZHRoLG1ldGhvZCA9ICJwZWFyc29uIikNCmNvci50ZXN0KGlyaXMkU2VwYWwuTGVuZ3RoLGlyaXMkUGV0YWwuV2lkdGgpDQpgYGANCg0KIyMjIEJhc2ljIHQtdGVzdHMNCg0KV2UgY2FuIHJ1biBhIGJhc2ljIHQtdGVzdCBvbiBvdXIgZGF0YSwgdXNpbmcgdGhlIGZ1bmN0aW9uIGB0LXRlc3RgDQoNCmBgYHtyfQ0KdC50ZXN0KGlyaXMkU2VwYWwuTGVuZ3RoLGlyaXMkUGV0YWwuV2lkdGgpDQpgYGANCg0KIyMjIEJhc2ljIEFOT1ZBDQoNCldlIGNhbiB1c2UgdGhlIGZ1bmN0aW9uIGBhb3ZgIHRvIHJ1biBhbiBBbmFseXNpcyBvZiBWYXJpYW5jZQ0KDQpgYGB7cn0NCnN1bW1hcnkoYW92KFNlcGFsLkxlbmd0aH5TcGVjaWVzLCBkYXRhPWlyaXMpKQ0KYGBgDQoNCiMjIyBBIGxpbmVhciBtb2RlbA0KDQpXZSBjYW4gdXNlIHRoZSBmdW5jdGlvbiBgbG1gIHRvIHJ1biBhIGxpbmVhciBtb2RlbA0KDQpgYGB7cn0NCnN1bW1hcnkobG0oU2VwYWwuTGVuZ3RoflNwZWNpZXMsIGRhdGE9aXJpcykpDQoNCmBgYA0KDQpCdXQgd2FpdC4uLiBIb3cgaXMgdGhlIGxpbmVhciBtb2RlbCBjb21wYXJhYmxlIHRvIHRoZSBhbmFseXNpcyBvZiB2YXJpYW5jZSB3ZSByYW4gYWJvdmU/IFRoaXMgbGluZWFyIG1vZGVsIGRlcml2ZXMgdGhlIGFuYWx5c2lzIG9mIHZhcmlhbmNlIHdlIHNhdyBhYm92ZSwgdXNlIGBhbm92YWAgb24geW91ciBsaW5lYXIgbW9kZWwuLg0KDQpIZXJlIGFyZSB0aGUgcmVzdWx0cyBvZiB0aGUgaW5pdGlhbCBBbmFseXNpcyBvZiB2YXJpYW5jZToNCg0KYGBge3J9DQpzdW1tYXJ5KGFvdihTZXBhbC5MZW5ndGh+U3BlY2llcywgZGF0YT1pcmlzKSkNCmBgYA0KDQpBbmQgaGVyZSBhcmUgdGhlIHJlc3VsdHMgb2YgdGhlIGxpbmVhciBtb2RlbCB3aXRoIHRoZSBgYW5vdmFgIGZ1bmN0aW9uDQoNCmBgYHtyfQ0KYW5vdmEobG0oU2VwYWwuTGVuZ3RoflNwZWNpZXMsIGRhdGE9aXJpcykpDQpgYGANCg0KVGhleSBhcmUgZXhhY3RseSB0aGUgc2FtZS4uLiBUaGUgdW5kZXJseWluZyBvZiBhbiBBbmFseXNpcyBvZiB2YXJpYW5jZSBpcyBhIGxpbmVhciBtb2RlbC4uDQoNCiMgRW5kIG9mIHRoZSBzZXNzaW9uDQoNClRoaXMgaXMgdGhlIGVuZCBvZiB0aGlzIGZpcnN0IHNlc3Npb24uIFdlIGhhdmUgbG9va2VkIGF0IHRoZSB2YXJpb3VzIGBSYCBkaXN0cmlidXRpb25zLCB0aGUgYEdVSXNgIHRvIGBSYCwgaW5zdGFsbGluZyBhbmQgdXNpbmcgcGFja2FnZXMsIHRoZW4gYFJgIGFzIGEgY2FsY3VsYXRvciwgd2l0aCBiYXNpYyBhbmQgbW9yZSBhZHZhbmNlZCBjYWxjdWxhdGlvbnMuIFdlIHRoZW4gbG9va2VkIGF0IHRoZSB2YXJpb3VzIG9iamVjdCB0eXBlcywgYW5kIGNyZWF0ZWQgYSBkYXRhZnJhbWUgZnJvbSBzY3JhdGNoLiBXZSBkaWQgc29tZSBtYW5pcHVsYXRpb25zIG9mIHRoZSBkYXRhZnJhbWUsIGJ5IGNyZWF0aW5nIGEgbmV3IHZhcmlhYmxlLCByZW5hbWluZyBhIGNvbHVtbiwgZGVsZXRpbmcgb25lLCBhbmQgY2hhbmdpbmcgdGhlIGxldmVscyBvZiBhIHZhcmlhYmxlLiBXZSB0aGVuIGNyZWF0ZWQgc29tZSBiYXNpYyBwbG90cywgYW5kIHJhbiBzb21lIGJhc2ljIHN0YXRpc3RpY3MuDQoNClRoaXMgd2hvbGUgd29ya3Nob3AgcmVsaWVkIG9uIHRoZSBiYXNlIGBSYC4gTWFueSByZXNlYXJjaGVycyBwcmVmZXIgdG8gb25seSB1c2UgYmFzZSBgUmAgYXMgdGhpcyBpcyBzdGFibGUgYW5kIHRoZSBjb2RlIHJhcmVseSBjaGFuZ2VzICh3ZWxsIGl0IGRvZXMgY2hhbmdlISkuIE90aGVycyBwcmVmZXIgdXNpbmcgbWFueSBvZiB0aGUgYFJgIHBhY2thZ2VzIHRvIHNwZWVkIHVwIGFuYWx5c2VzIG9yIGNyZWF0ZSBsb3ZlbHkgcGxvdHMuIEkgdXN1YWxseSB1c2UgYSBjb21iaW5hdGlvbiBvZiBiYXNlIGBSYCBwbG90cywgYW5kIHBsb3RzIGNyZWF0ZWQgd2l0aCBgZ2dwbG90MmAgb3IgYGxhdHRpY2VgLiANCg0KDQoNCg0K