Loading [MathJax]/jax/output/HTML-CSS/jax.js
  • Course Aims
  • Week 1 Schedule
  • 1. Introduction to R and its environment
    • What is R?
    • R plotting capabilities
    • Who uses R? Not just academics!
    • R can facilitate Reproducible Research
    • Getting started
    • Introduction to RStudio
    • Workflow within RStudio
    • Tip: Running segments of your code
    • Introduction to R
    • Basic concepts in R - simple arithmetic
    • Basic concepts in R - variables
    • Basic concepts in R - functions
    • Basic concepts in R - vectors
    • Basic concepts in R - vector arithmetic
    • Basic concepts in R - Character vectors and naming
    • Exercise: Body-Mass Index
    • Getting help
    • R packages
    • Installing packages
    • Example: Load packages ggplot2 and limma
    • Key points

PeterMac Data Science’s modified version of material by the University of Cambridge (Mark Dunning, Suraj Menon and Aiora Zabala, Robert Stojnić, Laurent Gatto, Rob Foy, John Davey, Dávid Molnár and Ian Roberts, original material: http://cambiotraining.github.io/r-intro) and Software Carpentry.

Course Aims

  • To introduce you to the basics of R
    • Reading data
    • Perform simple analyses
    • Producing graphs
    • How to get help!
  • Give you all the background you need to practice by yourselves
  • Introduce tools that will help you to work in a reproducible manner

Week 1 Schedule

  1. Introduction to R and its environment
  2. Data Structures

1. Introduction to R and its environment

What is R?

  • A statistical programming environment
    • based on ‘S’
    • suited to high-level data analysis
  • But offers much more than just statistics
  • Open source and cross platform
  • Extensive graphics capabilities
  • Diverse range of add-on packages
  • Active community of developers
  • Thorough documentation

http://www.r-project.org/

R screenshot

R screenshot

New York Times, Jan 2009

New York Times, Jan 2009

R can facilitate Reproducible Research

Sidney Harris - New York Times

Sidney Harris - New York Times

  • Statisticians at MD Anderson tried to reproduce results from a Duke paper and unintentionally unravelled a web of incompetence and skullduggery
    • as reported in the New York Times
New York Times, July 2011

New York Times, July 2011

  • Very entertaining talk from Keith Baggerly in Cambridge, December 2010

According to recent editorials, the reproducibility crisis is still on-going

Nature, May 2016

Nature, May 2016

Reality check on reproducibility

1,500 scientists lift the lid on reproducibility

Getting started

  • Latest release R version 3.5.1 (Feather Spray), July 2018
    • Base package and Contributed packages (general purpose extras)
    • 12756 available packages as of Sun Jul 15 18:52:10 2018
  • Download from http://mirrors.ebi.ac.uk/CRAN/
  • Windows, Mac and Linux versions available
  • Executed using command line, or a graphical user interface (GUI)
  • On this course, we use the RStudio GUI (www.rstudio.com)
rstudio

rstudio

Introduction to RStudio

(from Software Carpentry)

Throughout this lesson, we’re going to teach you some of the fundamentals of the R language. We’ll be using RStudio: a free, open source R integrated development environment. It provides a built in editor, works on all platforms (including on servers) and provides many advantages such as integration with version control and project management.

To launch RStudio, find the RStudio icon and click it.

Basic layout

When you first open RStudio, you will be greeted by three panels:

  • The interactive R console (entire left)
  • Environment/History (tabbed in upper right)
  • Files/Plots/Packages/Help/Viewer (tabbed in lower right)
RStudio layout

RStudio layout

Once you open files, such as R scripts, an editor panel will also open in the top left.

RStudio layout with .R file open

RStudio layout with .R file open

Workflow within RStudio

There are two main ways one can work within RStudio.

  1. Test and play within the interactive R console then copy code into a .R file to run later.
  • This works well when doing small tests and initially starting off.
  • It quickly becomes laborious
  1. Start writing in an .R file and use RStudio’s short cut keys for the Run command to push the current line, selected lines or modified lines to the interactive R console.
  • This is a great way to start; all your code is saved for later
  • You will be able to run the file you create from within RStudio or using R’s source() function.

Tip: Running segments of your code

RStudio offers you great flexibility in running code from within the editor window. There are buttons, menu choices, and keyboard shortcuts. To run the current line, you can 1. click on the Run button above the editor panel, or 2. select “Run Lines” from the “Code” menu, or 3. hit Ctrl+Return in Windows or Linux or +Return on OS X. (This shortcut can also be seen by hovering the mouse over the button). To run a block of code, select it and then Run. If you have modified a line of code within a block of code you have just run, there is no need to reselct the section and Run, you can use the next button along, Re-run the previous region. This will run the previous code block including the modifications you have made.

Introduction to R

Much of your time in R will be spent in the R interactive console. This is where you will run all of your code, and can be a useful environment to try out ideas before adding them to an R script file. This console in RStudio is the same as the one you would get if you typed in R in your command-line environment.

The first thing you will see in the R interactive session is a bunch of information, followed by a “>” and a blinking cursor. In many ways this is similar to the shell environment you learned about during the shell lessons: it operates on the same idea of a “Read, evaluate, print loop”: you type in commands, R tries to execute them, and then returns a result.

  • The traditional way to enter R commands is via the Terminal, or using the console in RStudio (bottom-left)
  • However, another way (not used in this course) is to use a relatively new feature called R-notebooks.
  • An R-notebook mixes plain text with R code
    • The R code can be run from inside the document and the results are displayed directly underneath
  • Each chunk of R code looks something like this.
  • Each line of R can be executed by clicking on the line and pressing CTRL and ENTER
  • Or you can press the green triangle on the right-hand side to run everything in the chunk
print("Hello World")
  • The R notebook can be rendered into a format such as PDF or HTML so they can be shared with your collaborators
  • On the course website you will see compiled versions of each session

Basic concepts in R - simple arithmetic

  • The command line can be used as a calculator and understands the usual arithmetic operators +, -, *, /
  • Try adding a few more calculations here
2 + 2
2 - 2
4 * 3
10 / 2

Note: The number in the square brackets is an indicator of the position in the output. In this case the output is a ‘vector’ of length 1 (i.e. a single number). More on vectors coming up…

In the case of expressions involving multiple operations, R respects the BODMAS system to decide the order in which operations should be performed.

2 + 2 *3
2 + (2 * 3)
(2 + 2) * 3

R is capable of more complicated arithmetic such as trigonometry and logarithms; like you would find on a fancy scientific calculator. Of course, R also has a plethora of statistical operations as we will see.

pi
sin (pi/2)
cos(pi)
tan(2)
log(1)

We can only go so far with performing simple calculations like this. Eventually we will need to store our results for later use. For this, we need to make use of variables.

Basic concepts in R - variables

  • A variable is a letter or word which takes (or contains) a value. We use the assignment operator: <-
x <- 10
x
myNumber <- 25
myNumber
  • We can perform arithmetic on variables:
sqrt(myNumber)
  • We can add variables together:
x + myNumber
  • We can change the value of an existing variable:
x <- 21
x
  • We can set one variable to equal the value of another variable:
x <- myNumber
x
  • We can modify the contents of a variable:
myNumber <- myNumber + sqrt(16)
myNumber

When we are feeling lazy we might give our variables short names (x, y, i…etc), but a better practice would be to give them meaningful names. There are some restrictions on creating variable names. They cannot start with a number or contain characters such as ., _, ‘-’. Naming variables the same as in-built functions in R, such as c, T, mean should also be avoided.

Naming variables is a matter of taste. Some conventions exist such as a separating words with - or using CamelCaps. Whatever convention you decided, stick with it!

Basic concepts in R - functions

  • Functions in R perform operations on arguments (the inputs(s) to the function). We have already used:
sin(x)
  • This returns the sine of x
    • In this case the function has one argument: x.
    • Arguments are always contained in parentheses – curved brackets, () – separated by commas.

Arguments can be named or unnamed, but if they are unnamed they must be ordered (we will see later how to find the right order). The names of the arguments are determined by the author of the function and can be found in the help page for the function. When testing code, it is easier and safer to name the arguments.

seq is a function for generating a numeric sequence from and to particular numbers.

  • Type ?seq to get the help page for this function.
  • When testing code, it is easier and safer to name the arguments
seq(from = 2, to = 20, by = 4)
seq(2, 20, 4)

Arguments can have default values, meaning we do not need to specify values for these in order to run the function.

rnorm is a function that will generate a series of values from a normal distribution. In order to use the function, we need to tell R how many values we want

rnorm(n=10)

The normal distribution is defined by a mean (average) and standard deviation (spread). However, in the above example we didn’t tell R what mean and standard deviation we wanted. So how does R know what to do? All arguments to a function and their default values are listed in the help page

(N.B sometimes help pages can describe more than one function)

?rnorm

In this case, we see that the defaults for mean and standard deviation are 0 and 1. We can change the function to generate values from a distribution with a different mean and standard deviation using the mean and sd arguments. It is important that we get the spelling of these arguments exactly right, otherwise R will an error message, or (worse?) do something unexpected.

rnorm(n=10, mean=2,sd=3)
rnorm(10, 2, 3)

In the examples above, seq and rnorm were both outputting a series of numbers, which is called a vector in R and is the most-fundamental data-type.

Basic concepts in R - vectors

  • The basic data structure in R is a vector – an ordered collection of values.
  • R treats even single values as 1-element vectors.
  • The function c combines its arguments into a vector:
x <- c(3,4,5,6)
x
  • The square brackets [] indicate the position within the vector (the index).
  • We can extract individual elements by using the [] notation:
x[1]
x[4]
  • We can even put a vector inside the square brackets (vector indexing):
  • Before executing this line of code, what do you think it will produce?
y <- c(2,3)
x[y]
  • There are a number of shortcuts to create a vector.
  • Instead of:
x <- c(3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
x
  • we can write:
x <- 3:12
x
  • or we can use the seq() function, which returns a vector:
x <- seq(2, 20, 4)
x
x <- seq(2, 20, length.out=5)
x
  • or we can use the rep() function:
y <- rep(3, 5)
y
y <- rep(1:3, 5)
y
  • We have seen some ways of extracting elements of a vector. We can use these shortcuts to make things easier (or more complex!)
x <- 3:12
# Extract elements from x:

x[3:7]
x[seq(2, 6, 2)]
x[rep(3, 2)]
  • We can add an element to a vector:
y <- c(x, 1)
y
  • We can glue vectors together:
z <- c(x, y)
z
  • We can “remove” element(s) from a vector:
    • NOTE: the vector x doesn’t get modified
    • we’re just displaying what the vector looks like without particular elements
x <- 3:12

x[-3]
x[-(5:7)]
x[-seq(2, 6, 2)]
x
  • Finally, we can modify the contents of a vector:
x[6] <- 4
x

x[3:5] <- 1
x

Remember!

  • Square brackets [ ] for indexing
  • Parentheses () for function arguments

Basic concepts in R - vector arithmetic

  • When applying all standard arithmetic operations to vectors, application is element-wise
x <- 1:10
y <- x*2
y
z <- x^2
z
  • Adding two vectors:
y + z
  • If vectors are not the same length, the shorter one will be recycled:
x + 1:2
  • But be careful if the vector lengths aren’t factors of each other:
x + 1:3
  • Sometimes R will give a warning message. It has performed the calculation you asked it to, but the results may be unexpected. You need to check the output carefully to make sure it is what you really wanted.

Basic concepts in R - Character vectors and naming

  • All the vectors we have seen so far have contained numbers, but we can also store text (/“strings”) in vector
    • this is called a character vector.
gene.names <- c("Pax6", "Beta-actin", "FoxP2", "Hox9")
gene.names
  • We can name elements of vectors using the names() function, which can be useful to keep track of the meaning of our data:
gene.expression <- c(0, 3.2, 1.2, -2)
names(gene.expression) <- gene.names
gene.expression
  • We can also use the names() function to get a vector of the names of an object:
names(gene.expression)

Exercise: Body-Mass Index

  • Let’s try some vector arithmetic. Here are the weights and heights of five individuals
Person Weight (kg) Height (cm)
Jo 65.8 192
Sam 67.9 179
Charlie 75.3 169
Frankie 61.9 175
Alex 92.4 171
  • Create weight and height vectors to hold the data in each column using the c function. Create a person vector and use this vector to name the values in the other two vectors.
  1. The body-mass index is given by the formula:- BMI=(Weight)/(Height2); where Height is given in metres
    • Create a new vector to record this, called bmi.
  2. Create a new vector bmi.sorted where the bmi values are put in increasing numeric order (HINT: look up the help on the sort function)
  3. The interquartile range (IQR) of a vector is defined as the 75% percentile of the data minus the 25% percentile. Calculate the IQR for our bmi values
    • check your answer using the IQR function
### YOUR ANSWER HERE (please) ###

Getting help

  • This is possibly the most important slide in the whole course!?!
  • To get help on any R function, type ? followed by the function name. For example:
?seq
  • This retrieves the syntax and arguments for the function. The help page shows the default order of arguments. It also tells you which package it belongs to.
  • There is typically a usage example, which you can test using the example function:
example(seq)
  • If you can’t remember the exact name, type ?? followed by your guess. R will return a list of possibilities:
??mean
  • The Packages tab in the lower-right panel of RStudio will help you locate the help pages for a particular package and its functions
    • Often there will be a user-guide or ‘vignette’ too

R packages

  • R comes ready loaded with various libraries of functions called packages. For example: the function sum() is in the base package and sd(), which calculates the standard deviation of a vector, is in the stats package
  • There are 1000s of additional packages provided by third parties, and the packages can be found in numerous server locations on the web called repositories
  • The two repositories you will come across the most are:
  • Bottomline: always first look if there is already an R package that does what you want before trying to implement it yourself

Installing packages

  • CRAN packages can be installed using install.packages()

    • or clicking on the Packages tab in RStudio
install.packages(name.of.my.package)
  • Set the Bioconductor package download tool by typing:
source("http://bioconductor.org/biocLite.R")
  • Bioconductor packages are then installed with the biocLite() function:
biocLite("PackageName")
  • ggplot2 is a commonly used graphics package:
    • in RStudio, go to ToolsInstall Packages… and type the package name
    • or use install.packages() function to install it:
install.packages("ggplot2")
source("http://www.bioconductor.org/biocLite.R")
biocLite("limma")

Example: Load packages ggplot2 and limma

  • R needs to be told to use the new functions from the installed packages. Use library(...) function to load the newly installed features:
library(ggplot2) # loads ggplot functions
library(limma)   # loads limma functions
library()        # Lists all the packages 
                 # you've got installed 

Key points

  • In programming, a variable is a letter or word which takes (or contains) a value
  • In R, the assignment operator <- is used to assign values to variables
  • The basic data structure in R is a vector – an ordered collection of values
  • A function is a unit of code that can take arguments and perform a set of instructions
  • The function c combines its arguments into a vector
  • All standard arithmetic operations are applied to vectors element-wise
  • To get help on any R function, type ? followed by the function name
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIFNvbHZpbmcgQmlvbG9naWNhbCBQcm9ibGVtcyBVc2luZyBSIC0gV2VlayAxIgpkYXRlOiAnYHIgZm9ybWF0KFN5cy50aW1lKCksICJMYXN0IG1vZGlmaWVkOiAlZCAlYiAlWSIpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKY3NzOiBteXN0eWxlLmNzcwotLS0KYGBge3IgaW5jbHVkZSA9IEZBTFNFfQpsaWJyYXJ5KGtuaXRyKQpvcHRzX2NodW5rJHNldChjb21tZW50ID0gTkEsZXZhbD1GQUxTRSkgIyBlbGltaW5hdGVzIGhhc2h0YWcgZnJvbSBSIG91dHB1dHMKYGBgCgoqUGV0ZXJNYWMgRGF0YSBTY2llbmNlJ3MgbW9kaWZpZWQgdmVyc2lvbiBvZiBtYXRlcmlhbCBieSB0aGUgVW5pdmVyc2l0eSBvZiBDYW1icmlkZ2UgKE1hcmsgRHVubmluZywgU3VyYWogTWVub24gYW5kIEFpb3JhIFphYmFsYSwgUm9iZXJ0IFN0b2puacSHLAogIExhdXJlbnQgR2F0dG8sIFJvYiBGb3ksIEpvaG4gRGF2ZXksIETDoXZpZCBNb2xuw6FyIGFuZCBJYW4gUm9iZXJ0cywgb3JpZ2luYWwgbWF0ZXJpYWw6IGh0dHA6Ly9jYW1iaW90cmFpbmluZy5naXRodWIuaW8vci1pbnRybykgYW5kIFNvZnR3YXJlIENhcnBlbnRyeS4qCgojIENvdXJzZSBBaW1zCgotIFRvIGludHJvZHVjZSB5b3UgdG8gdGhlIGJhc2ljcyBvZiBSCiAgICArIFJlYWRpbmcgZGF0YQogICAgKyBQZXJmb3JtIHNpbXBsZSBhbmFseXNlcwogICAgKyBQcm9kdWNpbmcgZ3JhcGhzCiAgICArICoqKkhvdyB0byBnZXQgaGVscCEqKioKLSBHaXZlIHlvdSBhbGwgdGhlIGJhY2tncm91bmQgeW91IG5lZWQgdG8gKioqcHJhY3RpY2UqKiogYnkgeW91cnNlbHZlcwotIEludHJvZHVjZSB0b29scyB0aGF0IHdpbGwgaGVscCB5b3UgdG8gd29yayBpbiBhICoqKnJlcHJvZHVjaWJsZSoqKiBtYW5uZXIKCiMgV2VlayAxIFNjaGVkdWxlCgoxLiBJbnRyb2R1Y3Rpb24gdG8gUiBhbmQgaXRzIGVudmlyb25tZW50CjIuIERhdGEgU3RydWN0dXJlcwoKIzEuIEludHJvZHVjdGlvbiB0byBSIGFuZCBpdHMgZW52aXJvbm1lbnQKCiMjV2hhdCBpcyBSPwoKKiBBIHN0YXRpc3RpY2FsIHByb2dyYW1taW5nIGVudmlyb25tZW50CiAgICArIGJhc2VkIG9uICdTJwogICAgKyBzdWl0ZWQgdG8gaGlnaC1sZXZlbCBkYXRhIGFuYWx5c2lzCiogQnV0IG9mZmVycyBtdWNoIG1vcmUgdGhhbiBqdXN0IHN0YXRpc3RpY3MKKiBPcGVuIHNvdXJjZSBhbmQgY3Jvc3MgcGxhdGZvcm0KKiBFeHRlbnNpdmUgZ3JhcGhpY3MgY2FwYWJpbGl0aWVzCiogRGl2ZXJzZSByYW5nZSBvZiBhZGQtb24gcGFja2FnZXMKKiBBY3RpdmUgY29tbXVuaXR5IG9mIGRldmVsb3BlcnMKKiBUaG9yb3VnaCBkb2N1bWVudGF0aW9uCgoKCmh0dHA6Ly93d3cuci1wcm9qZWN0Lm9yZy8KCiFbUiBzY3JlZW5zaG90XShpbWFnZXMvUi1wcm9qZWN0LnBuZykKCiFbTmV3IFlvcmsgVGltZXMsIEphbiAyMDA5XShpbWFnZXMvTllUaW1lc19SX0FydGljbGUucG5nKQoKCiMjUiBwbG90dGluZyBjYXBhYmlsaXRpZXMKCmh0dHBzOi8vd3d3LmZhY2Vib29rLmNvbS9ub3Rlcy9mYWNlYm9vay1lbmdpbmVlcmluZy92aXN1YWxpemluZy1mcmllbmRzaGlwcy80Njk3MTYzOTg5MTkKIVtSIGZhY2Vib29rXShpbWFnZXMvZmFjZWJvb2stbmV0d29yay5wbmcpCgojI1dobyB1c2VzIFI/IE5vdCBqdXN0IGFjYWRlbWljcyEKCmh0dHA6Ly93d3cucmV2b2x1dGlvbmFuYWx5dGljcy5jb20vY29tcGFuaWVzLXVzaW5nLXIKCi0gRmFjZWJvb2sKICAgICsgaHR0cDovL2Jsb2cucmV2b2x1dGlvbmFuYWx5dGljcy5jb20vMjAxMC8xMi9hbmFseXNpcy1vZi1mYWNlYm9vay1zdGF0dXMtdXBkYXRlcy5odG1sCi0gR29vZ2xlCiAgICArIGh0dHA6Ly9ibG9nLnJldm9sdXRpb25hbmFseXRpY3MuY29tLzIwMDkvMDUvZ29vZ2xlLXVzaW5nLXItdG8tYW5hbHl6ZS1lZmZlY3RpdmVuZXNzLW9mLXR2LWFkcy5odG1sCi0gTWljcm9zb2Z0CiAgICArIGh0dHA6Ly9ibG9nLnJldm9sdXRpb25hbmFseXRpY3MuY29tLzIwMTQvMDUvbWljcm9zb2Z0LXVzZXMtci1mb3IteGJveC1tYXRjaG1ha2luZy5odG1sCi0gTmV3IFlvcmsgVGltZXMKICAgICsgaHR0cDovL2Jsb2cucmV2b2x1dGlvbmFuYWx5dGljcy5jb20vMjAxMS8wMy9ob3ctdGhlLW5ldy15b3JrLXRpbWVzLXVzZXMtci1mb3ItZGF0YS12aXN1YWxpemF0aW9uLmh0bWwKLSBCdXp6ZmVlZAogICAgKyBodHRwOi8vYmxvZy5yZXZvbHV0aW9uYW5hbHl0aWNzLmNvbS8yMDE1LzEyL2J1enpmZWVkLXVzZXMtci1mb3ItZGF0YS1qb3VybmFsaXNtLmh0bWwKLSBOZXcgWmVhbGFuZCBUb3VyaXN0IEJvYXJkCiAgICArIGh0dHBzOi8vbWJpZW56LnNoaW55YXBwcy5pby90b3VyaXNtX2Rhc2hib2FyZF9wcm9kLwoKICAgIAojIyBSIGNhbiBmYWNpbGl0YXRlIFJlcHJvZHVjaWJsZSBSZXNlYXJjaAoKIVtTaWRuZXkgSGFycmlzIC0gTmV3IFlvcmsgVGltZXNdKGltYWdlcy9TaWRuZXlIYXJyaXNfTWlyYWNsZVdlYi5qcGcpCgoKCgotIFN0YXRpc3RpY2lhbnMgYXQgTUQgQW5kZXJzb24gdHJpZWQgdG8gcmVwcm9kdWNlIHJlc3VsdHMgZnJvbSBhIER1a2UgcGFwZXIgYW5kIHVuaW50ZW50aW9uYWxseSB1bnJhdmVsbGVkIGEgd2ViIG9mIGluY29tcGV0ZW5jZSBhbmQgc2t1bGxkdWdnZXJ5CiAgICArIGFzIHJlcG9ydGVkIGluIHRoZSAqKipOZXcgWW9yayBUaW1lcyoqKgogICAgCiFbTmV3IFlvcmsgVGltZXMsIEp1bHkgMjAxMV0oaW1hZ2VzL3JlcC1yZXNlYXJjaC1ueXQucG5nKQoKCgotIFZlcnkgZW50ZXJ0YWluaW5nIHRhbGsgZnJvbSBLZWl0aCBCYWdnZXJseSBpbiBDYW1icmlkZ2UsIERlY2VtYmVyIDIwMTAKCjxpZnJhbWUgd2lkdGg9IjU2MCIgaGVpZ2h0PSIzMTUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvN2dZSXM3dVliTW8iIGZyYW1lYm9yZGVyPSIwIiBhbGxvd2Z1bGxzY3JlZW4+PC9pZnJhbWU+CgpBY2NvcmRpbmcgdG8gcmVjZW50IGVkaXRvcmlhbHMsIHRoZSByZXByb2R1Y2liaWxpdHkgY3Jpc2lzIGlzIHN0aWxsIG9uLWdvaW5nCgohW05hdHVyZSwgTWF5IDIwMTZdKGltYWdlcy9yZXAtY3Jpc2lzLnBuZykKCgpbUmVhbGl0eSBjaGVjayBvbiByZXByb2R1Y2liaWxpdHldKGh0dHA6Ly93d3cubmF0dXJlLmNvbS9uZXdzL3JlYWxpdHktY2hlY2stb24tcmVwcm9kdWNpYmlsaXR5LTEuMTk5NjEpCgpbMSw1MDAgc2NpZW50aXN0cyBsaWZ0IHRoZSBsaWQgb24gcmVwcm9kdWNpYmlsaXR5XShodHRwOi8vd3d3Lm5hdHVyZS5jb20vbmV3cy8xLTUwMC1zY2llbnRpc3RzLWxpZnQtdGhlLWxpZC1vbi1yZXByb2R1Y2liaWxpdHktMS4xOTk3MCkKCgojI0dldHRpbmcgc3RhcnRlZAotIExhdGVzdCByZWxlYXNlIFIgdmVyc2lvbiAzLjUuMSAoRmVhdGhlciBTcHJheSksIEp1bHkgMjAxOAogICAgKyBCYXNlIHBhY2thZ2UgYW5kIENvbnRyaWJ1dGVkIHBhY2thZ2VzIChnZW5lcmFsIHB1cnBvc2UgZXh0cmFzKQogICAgKyBgciBsZW5ndGgoWE1MOjo6cmVhZEhUTUxUYWJsZSgiaHR0cDovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvYXZhaWxhYmxlX3BhY2thZ2VzX2J5X2RhdGUuaHRtbCIpW1sxXV1bWzJdXSlgIGF2YWlsYWJsZSBwYWNrYWdlcyBhcyBvZiBgciBkYXRlKClgCi0gRG93bmxvYWQgZnJvbSBodHRwOi8vbWlycm9ycy5lYmkuYWMudWsvQ1JBTi8KLSBXaW5kb3dzLCBNYWMgYW5kIExpbnV4IHZlcnNpb25zIGF2YWlsYWJsZQotIEV4ZWN1dGVkIHVzaW5nIGNvbW1hbmQgbGluZSwgb3IgYSBncmFwaGljYWwgdXNlciBpbnRlcmZhY2UgKEdVSSkKLSBPbiB0aGlzIGNvdXJzZSwgd2UgdXNlIHRoZSBSU3R1ZGlvIEdVSSAod3d3LnJzdHVkaW8uY29tKQoKIVtyc3R1ZGlvXShodHRwOi8vd3d3LnJzdHVkaW8uY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE0LzAzL2JsdWUtMTI1LnBuZykgCiAgICAKIyMgSW50cm9kdWN0aW9uIHRvIFJTdHVkaW8KCiooZnJvbSBTb2Z0d2FyZSBDYXJwZW50cnkpKgoKVGhyb3VnaG91dCB0aGlzIGxlc3Nvbiwgd2UncmUgZ29pbmcgdG8gdGVhY2ggeW91IHNvbWUgb2YgdGhlIGZ1bmRhbWVudGFscyBvZgp0aGUgUiBsYW5ndWFnZS4gV2UnbGwgYmUgdXNpbmcgUlN0dWRpbzogYSBmcmVlLCBvcGVuIHNvdXJjZSBSIGludGVncmF0ZWQgZGV2ZWxvcG1lbnQKZW52aXJvbm1lbnQuIEl0IHByb3ZpZGVzIGEgYnVpbHQgaW4gZWRpdG9yLCB3b3JrcyBvbiBhbGwgcGxhdGZvcm1zIChpbmNsdWRpbmcKb24gc2VydmVycykgYW5kIHByb3ZpZGVzIG1hbnkgYWR2YW50YWdlcyBzdWNoIGFzIGludGVncmF0aW9uIHdpdGggdmVyc2lvbgpjb250cm9sIGFuZCBwcm9qZWN0IG1hbmFnZW1lbnQuCgpUbyBsYXVuY2ggUlN0dWRpbywgZmluZCB0aGUgUlN0dWRpbyBpY29uIGFuZCBjbGljayBpdC4KCgoqKkJhc2ljIGxheW91dCoqCgpXaGVuIHlvdSBmaXJzdCBvcGVuIFJTdHVkaW8sIHlvdSB3aWxsIGJlIGdyZWV0ZWQgYnkgdGhyZWUgcGFuZWxzOgoKICAqIFRoZSBpbnRlcmFjdGl2ZSBSIGNvbnNvbGUgKGVudGlyZSBsZWZ0KQogICogRW52aXJvbm1lbnQvSGlzdG9yeSAodGFiYmVkIGluIHVwcGVyIHJpZ2h0KQogICogRmlsZXMvUGxvdHMvUGFja2FnZXMvSGVscC9WaWV3ZXIgKHRhYmJlZCBpbiBsb3dlciByaWdodCkKCiFbUlN0dWRpbyBsYXlvdXRdKGltYWdlcy8wMS1yc3R1ZGlvLnBuZykKCk9uY2UgeW91IG9wZW4gZmlsZXMsIHN1Y2ggYXMgUiBzY3JpcHRzLCBhbiBlZGl0b3IgcGFuZWwgd2lsbCBhbHNvIG9wZW4KaW4gdGhlIHRvcCBsZWZ0LgoKIVtSU3R1ZGlvIGxheW91dCB3aXRoIC5SIGZpbGUgb3Blbl0oaW1hZ2VzLzAxLXJzdHVkaW8tc2NyaXB0LnBuZykKCgojIyBXb3JrZmxvdyB3aXRoaW4gUlN0dWRpbwpUaGVyZSBhcmUgdHdvIG1haW4gd2F5cyBvbmUgY2FuIHdvcmsgd2l0aGluIFJTdHVkaW8uCgoxLiBUZXN0IGFuZCBwbGF5IHdpdGhpbiB0aGUgaW50ZXJhY3RpdmUgUiBjb25zb2xlIHRoZW4gY29weSBjb2RlIGludG8KYSAuUiBmaWxlIHRvIHJ1biBsYXRlci4KICAgKiAgVGhpcyB3b3JrcyB3ZWxsIHdoZW4gZG9pbmcgc21hbGwgdGVzdHMgYW5kIGluaXRpYWxseSBzdGFydGluZyBvZmYuCiAgICogIEl0IHF1aWNrbHkgYmVjb21lcyBsYWJvcmlvdXMKMi4gU3RhcnQgd3JpdGluZyBpbiBhbiAuUiBmaWxlIGFuZCB1c2UgUlN0dWRpbydzIHNob3J0IGN1dCBrZXlzIGZvciB0aGUgUnVuIGNvbW1hbmQKdG8gcHVzaCB0aGUgY3VycmVudCBsaW5lLCBzZWxlY3RlZCBsaW5lcyBvciBtb2RpZmllZCBsaW5lcyB0byB0aGUKaW50ZXJhY3RpdmUgUiBjb25zb2xlLgogICAqIFRoaXMgaXMgYSBncmVhdCB3YXkgdG8gc3RhcnQ7IGFsbCB5b3VyIGNvZGUgaXMgc2F2ZWQgZm9yIGxhdGVyCiAgICogWW91IHdpbGwgYmUgYWJsZSB0byBydW4gdGhlIGZpbGUgeW91IGNyZWF0ZSBmcm9tIHdpdGhpbiBSU3R1ZGlvCiAgIG9yIHVzaW5nIFIncyBgc291cmNlKClgICBmdW5jdGlvbi4KCiMjIFRpcDogUnVubmluZyBzZWdtZW50cyBvZiB5b3VyIGNvZGUKClJTdHVkaW8gb2ZmZXJzIHlvdSBncmVhdCBmbGV4aWJpbGl0eSBpbiBydW5uaW5nIGNvZGUgZnJvbSB3aXRoaW4gdGhlIGVkaXRvcgp3aW5kb3cuIFRoZXJlIGFyZSBidXR0b25zLCBtZW51IGNob2ljZXMsIGFuZCBrZXlib2FyZCBzaG9ydGN1dHMuIFRvIHJ1biB0aGUKY3VycmVudCBsaW5lLCB5b3UgY2FuIAoxLiBjbGljayBvbiB0aGUgYFJ1bmAgYnV0dG9uIGFib3ZlIHRoZSBlZGl0b3IgcGFuZWwsIG9yIAoyLiBzZWxlY3QgIlJ1biBMaW5lcyIgZnJvbSB0aGUgIkNvZGUiIG1lbnUsIG9yIAozLiBoaXQgPGtiZD5DdHJsPC9rYmQ+KzxrYmQ+UmV0dXJuPC9rYmQ+IGluIFdpbmRvd3Mgb3IgTGludXggCm9yIDxrYmQ+JiM4OTg0Ozwva2JkPis8a2JkPlJldHVybjwva2JkPiBvbiBPUyBYLgooVGhpcyBzaG9ydGN1dCBjYW4gYWxzbyBiZSBzZWVuIGJ5IGhvdmVyaW5nCnRoZSBtb3VzZSBvdmVyIHRoZSBidXR0b24pLiBUbyBydW4gYSBibG9jayBvZiBjb2RlLCBzZWxlY3QgaXQgYW5kIHRoZW4gYFJ1bmAuCklmIHlvdSBoYXZlIG1vZGlmaWVkIGEgbGluZSBvZiBjb2RlIHdpdGhpbiBhIGJsb2NrIG9mIGNvZGUgeW91IGhhdmUganVzdCBydW4sCnRoZXJlIGlzIG5vIG5lZWQgdG8gcmVzZWxjdCB0aGUgc2VjdGlvbiBhbmQgYFJ1bmAsIHlvdSBjYW4gdXNlIHRoZSBuZXh0IGJ1dHRvbgphbG9uZywgYFJlLXJ1biB0aGUgcHJldmlvdXMgcmVnaW9uYC4gVGhpcyB3aWxsIHJ1biB0aGUgcHJldmlvdXMgY29kZSBibG9jawppbmNsdWRpbmcgdGhlIG1vZGlmaWNhdGlvbnMgeW91IGhhdmUgbWFkZS4KCiMjIEludHJvZHVjdGlvbiB0byBSCgpNdWNoIG9mIHlvdXIgdGltZSBpbiBSIHdpbGwgYmUgc3BlbnQgaW4gdGhlIFIgaW50ZXJhY3RpdmUKY29uc29sZS4gVGhpcyBpcyB3aGVyZSB5b3Ugd2lsbCBydW4gYWxsIG9mIHlvdXIgY29kZSwgYW5kIGNhbiBiZSBhCnVzZWZ1bCBlbnZpcm9ubWVudCB0byB0cnkgb3V0IGlkZWFzIGJlZm9yZSBhZGRpbmcgdGhlbSB0byBhbiBSIHNjcmlwdApmaWxlLiBUaGlzIGNvbnNvbGUgaW4gUlN0dWRpbyBpcyB0aGUgc2FtZSBhcyB0aGUgb25lIHlvdSB3b3VsZCBnZXQgaWYKeW91IHR5cGVkIGluIGBSYCBpbiB5b3VyIGNvbW1hbmQtbGluZSBlbnZpcm9ubWVudC4KClRoZSBmaXJzdCB0aGluZyB5b3Ugd2lsbCBzZWUgaW4gdGhlIFIgaW50ZXJhY3RpdmUgc2Vzc2lvbiBpcyBhIGJ1bmNoCm9mIGluZm9ybWF0aW9uLCBmb2xsb3dlZCBieSBhICI+IiBhbmQgYSBibGlua2luZyBjdXJzb3IuIEluIG1hbnkgd2F5cwp0aGlzIGlzIHNpbWlsYXIgdG8gdGhlIHNoZWxsIGVudmlyb25tZW50IHlvdSBsZWFybmVkIGFib3V0IGR1cmluZyB0aGUKc2hlbGwgbGVzc29uczogaXQgb3BlcmF0ZXMgb24gdGhlIHNhbWUgaWRlYSBvZiBhICJSZWFkLCBldmFsdWF0ZSwKcHJpbnQgbG9vcCI6IHlvdSB0eXBlIGluIGNvbW1hbmRzLCBSIHRyaWVzIHRvIGV4ZWN1dGUgdGhlbSwgYW5kIHRoZW4KcmV0dXJucyBhIHJlc3VsdC4KCi0gVGhlIHRyYWRpdGlvbmFsIHdheSB0byBlbnRlciBSIGNvbW1hbmRzIGlzIHZpYSB0aGUgVGVybWluYWwsIG9yIHVzaW5nIHRoZSBjb25zb2xlIGluIFJTdHVkaW8gKGJvdHRvbS1sZWZ0KQotIEhvd2V2ZXIsIGFub3RoZXIgd2F5IChub3QgdXNlZCBpbiB0aGlzIGNvdXJzZSkgaXMgdG8gdXNlIGEgcmVsYXRpdmVseSBuZXcgZmVhdHVyZSBjYWxsZWQgKlItbm90ZWJvb2tzKi4KLSBBbiBSLW5vdGVib29rIG1peGVzIHBsYWluIHRleHQgd2l0aCBSIGNvZGUKICAgICsgVGhlIFIgY29kZSBjYW4gYmUgcnVuIGZyb20gaW5zaWRlIHRoZSBkb2N1bWVudCBhbmQgdGhlIHJlc3VsdHMgYXJlIGRpc3BsYXllZCBkaXJlY3RseSB1bmRlcm5lYXRoCi0gRWFjaCAqY2h1bmsqIG9mIFIgY29kZSBsb29rcyBzb21ldGhpbmcgbGlrZSB0aGlzLiAKLSBFYWNoIGxpbmUgb2YgUiBjYW4gYmUgZXhlY3V0ZWQgYnkgY2xpY2tpbmcgb24gdGhlIGxpbmUgYW5kIHByZXNzaW5nIENUUkwgYW5kIEVOVEVSCi0gT3IgeW91IGNhbiBwcmVzcyB0aGUgZ3JlZW4gdHJpYW5nbGUgb24gdGhlIHJpZ2h0LWhhbmQgc2lkZSB0byBydW4gZXZlcnl0aGluZyBpbiB0aGUgY2h1bmsKCmBgYHtyfQpwcmludCgiSGVsbG8gV29ybGQiKQoKYGBgCgotIFRoZSBSIG5vdGVib29rIGNhbiBiZSByZW5kZXJlZCBpbnRvIGEgZm9ybWF0IHN1Y2ggYXMgUERGIG9yIEhUTUwgc28gdGhleSBjYW4gYmUgc2hhcmVkIHdpdGggeW91ciBjb2xsYWJvcmF0b3JzCi0gT24gdGhlIGNvdXJzZSB3ZWJzaXRlIHlvdSB3aWxsIHNlZSBjb21waWxlZCB2ZXJzaW9ucyBvZiBlYWNoIHNlc3Npb24KCiMjQmFzaWMgY29uY2VwdHMgaW4gUiAtIHNpbXBsZSBhcml0aG1ldGljCgotIFRoZSBjb21tYW5kIGxpbmUgY2FuIGJlIHVzZWQgYXMgYSBjYWxjdWxhdG9yIGFuZCB1bmRlcnN0YW5kcyB0aGUgdXN1YWwgYXJpdGhtZXRpYyBvcGVyYXRvcnMgKywgLSwgKiwgLyAKLSBUcnkgYWRkaW5nIGEgZmV3IG1vcmUgY2FsY3VsYXRpb25zIGhlcmUKCmBgYHtyfQoyICsgMgoyIC0gMgo0ICogMwoxMCAvIDIKCgpgYGAKCk5vdGU6IFRoZSBudW1iZXIgaW4gdGhlIHNxdWFyZSBicmFja2V0cyBpcyBhbiBpbmRpY2F0b3Igb2YgdGhlCnBvc2l0aW9uIGluIHRoZSBvdXRwdXQuIEluIHRoaXMgY2FzZSB0aGUgb3V0cHV0IGlzIGEgJ3ZlY3Rvcicgb2YgbGVuZ3RoIDEKKGkuZS4gYSBzaW5nbGUgbnVtYmVyKS4gTW9yZSBvbiB2ZWN0b3JzIGNvbWluZyB1cC4uLgoKCkluIHRoZSBjYXNlIG9mIGV4cHJlc3Npb25zIGludm9sdmluZyBtdWx0aXBsZSBvcGVyYXRpb25zLCBSIHJlc3BlY3RzIHRoZSBbQk9ETUFTXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9PcmRlcl9vZl9vcGVyYXRpb25zI01uZW1vbmljcykgc3lzdGVtIHRvIGRlY2lkZSB0aGUgb3JkZXIgaW4gd2hpY2ggb3BlcmF0aW9ucyBzaG91bGQgYmUgcGVyZm9ybWVkLgoKYGBge3J9CjIgKyAyICozCjIgKyAoMiAqIDMpCigyICsgMikgKiAzCmBgYAoKUiBpcyBjYXBhYmxlIG9mIG1vcmUgY29tcGxpY2F0ZWQgYXJpdGhtZXRpYyBzdWNoIGFzIHRyaWdvbm9tZXRyeSBhbmQgbG9nYXJpdGhtczsgbGlrZSB5b3Ugd291bGQgZmluZCBvbiBhIGZhbmN5IHNjaWVudGlmaWMgY2FsY3VsYXRvci4gT2YgY291cnNlLCBSIGFsc28gaGFzIGEgcGxldGhvcmEgb2Ygc3RhdGlzdGljYWwgb3BlcmF0aW9ucyBhcyB3ZSB3aWxsIHNlZS4KCgpgYGB7cn0KcGkKc2luIChwaS8yKQpjb3MocGkpCnRhbigyKQpsb2coMSkKCgpgYGAKCldlIGNhbiBvbmx5IGdvIHNvIGZhciB3aXRoIHBlcmZvcm1pbmcgc2ltcGxlIGNhbGN1bGF0aW9ucyBsaWtlIHRoaXMuIEV2ZW50dWFsbHkgd2Ugd2lsbCBuZWVkIHRvIHN0b3JlIG91ciByZXN1bHRzIGZvciBsYXRlciB1c2UuIEZvciB0aGlzLCB3ZSBuZWVkIHRvIG1ha2UgdXNlIG9mICp2YXJpYWJsZXMqLgoKCiMjQmFzaWMgY29uY2VwdHMgaW4gUiAtIHZhcmlhYmxlcwoKLSBBIHZhcmlhYmxlIGlzIGEgbGV0dGVyIG9yIHdvcmQgd2hpY2ggdGFrZXMgKG9yIGNvbnRhaW5zKSBhIHZhbHVlLiBXZSB1c2UgdGhlICoqYXNzaWdubWVudCBvcGVyYXRvcjogYDwtYCoqCmBgYHtyfQp4IDwtIDEwCngKbXlOdW1iZXIgPC0gMjUKbXlOdW1iZXIKYGBgCgotIFdlIGNhbiBwZXJmb3JtIGFyaXRobWV0aWMgb24gdmFyaWFibGVzOgpgYGB7cn0Kc3FydChteU51bWJlcikKYGBgCgoKLSBXZSBjYW4gYWRkIHZhcmlhYmxlcyB0b2dldGhlcjoKYGBge3J9CnggKyBteU51bWJlcgpgYGAKCi0gV2UgY2FuIGNoYW5nZSB0aGUgdmFsdWUgb2YgYW4gZXhpc3RpbmcgdmFyaWFibGU6CgpgYGB7cn0KeCA8LSAyMQp4CmBgYAoKCi0gV2UgY2FuIHNldCBvbmUgdmFyaWFibGUgdG8gZXF1YWwgdGhlIHZhbHVlIG9mIGFub3RoZXIgdmFyaWFibGU6CmBgYHtyfQp4IDwtIG15TnVtYmVyCngKYGBgCgotIFdlIGNhbiBtb2RpZnkgdGhlIGNvbnRlbnRzIG9mIGEgdmFyaWFibGU6CgpgYGB7cn0KbXlOdW1iZXIgPC0gbXlOdW1iZXIgKyBzcXJ0KDE2KQpteU51bWJlcgpgYGAKCldoZW4gd2UgYXJlIGZlZWxpbmcgbGF6eSB3ZSBtaWdodCBnaXZlIG91ciB2YXJpYWJsZXMgc2hvcnQgbmFtZXMgKGB4YCwgYHlgLCBgaWAuLi5ldGMpLCBidXQgYSBiZXR0ZXIgcHJhY3RpY2Ugd291bGQgYmUgdG8gZ2l2ZSB0aGVtIG1lYW5pbmdmdWwgbmFtZXMuIFRoZXJlIGFyZSBzb21lIHJlc3RyaWN0aW9ucyBvbiBjcmVhdGluZyB2YXJpYWJsZSBuYW1lcy4gVGhleSBjYW5ub3Qgc3RhcnQgd2l0aCBhIG51bWJlciBvciBjb250YWluIGNoYXJhY3RlcnMgc3VjaCBhcyBgLmAsIGBfYCwgJy0nLiBOYW1pbmcgdmFyaWFibGVzIHRoZSBzYW1lIGFzIGluLWJ1aWx0IGZ1bmN0aW9ucyBpbiBSLCBzdWNoIGFzIGBjYCwgYFRgLCBgbWVhbmAgc2hvdWxkIGFsc28gYmUgYXZvaWRlZC4KCk5hbWluZyB2YXJpYWJsZXMgaXMgYSBtYXR0ZXIgb2YgdGFzdGUuIFNvbWUgW2NvbnZlbnRpb25zXShodHRwOi8vYWR2LXIuaGFkLmNvLm56L1N0eWxlLmh0bWwpIGV4aXN0IHN1Y2ggYXMgYSBzZXBhcmF0aW5nIHdvcmRzIHdpdGggYC1gIG9yIHVzaW5nICpDKmFtZWwqQyphcHMuIFdoYXRldmVyIGNvbnZlbnRpb24geW91IGRlY2lkZWQsIHN0aWNrIHdpdGggaXQhCgojI0Jhc2ljIGNvbmNlcHRzIGluIFIgLSBmdW5jdGlvbnMKCi0gKipGdW5jdGlvbnMqKiBpbiBSIHBlcmZvcm0gb3BlcmF0aW9ucyBvbiAqKmFyZ3VtZW50cyoqICh0aGUgaW5wdXRzKHMpIHRvIHRoZSBmdW5jdGlvbikuIFdlIGhhdmUgYWxyZWFkeSB1c2VkOgpgYGB7cn0Kc2luKHgpCmBgYAoKLSBUaGlzIHJldHVybnMgdGhlIHNpbmUgb2YgeAogICAgICsgSW4gdGhpcyBjYXNlIHRoZSBmdW5jdGlvbiBoYXMgb25lIGFyZ3VtZW50OiAqKngqKi4gCiAgICAgKyBBcmd1bWVudHMgYXJlIGFsd2F5cyBjb250YWluZWQgaW4gcGFyZW50aGVzZXMgLS0gY3VydmVkIGJyYWNrZXRzLCAqKigpKiogLS0gc2VwYXJhdGVkIGJ5IGNvbW1hcy4KICAgICAKICAgICAKQXJndW1lbnRzIGNhbiBiZSBuYW1lZCBvciB1bm5hbWVkLCBidXQgaWYgdGhleSBhcmUgdW5uYW1lZCB0aGV5IG11c3QgYmUgb3JkZXJlZCAod2Ugd2lsbCBzZWUgbGF0ZXIgaG93IHRvIGZpbmQgdGhlIHJpZ2h0IG9yZGVyKS4gVGhlIG5hbWVzIG9mIHRoZSBhcmd1bWVudHMgYXJlIGRldGVybWluZWQgYnkgdGhlIGF1dGhvciBvZiB0aGUgZnVuY3Rpb24gYW5kIGNhbiBiZSBmb3VuZCBpbiB0aGUgaGVscCBwYWdlIGZvciB0aGUgZnVuY3Rpb24uIFdoZW4gdGVzdGluZyBjb2RlLCBpdCBpcyBlYXNpZXIgYW5kIHNhZmVyIHRvIG5hbWUgdGhlIGFyZ3VtZW50cy4gCgpgc2VxYCBpcyBhIGZ1bmN0aW9uIGZvciBnZW5lcmF0aW5nIGEgbnVtZXJpYyBzZXF1ZW5jZSAqZnJvbSogYW5kICp0byogcGFydGljdWxhciBudW1iZXJzLiAKCi0gVHlwZSBgP3NlcWAgdG8gZ2V0IHRoZSBoZWxwIHBhZ2UgZm9yIHRoaXMgZnVuY3Rpb24uCi0gV2hlbiB0ZXN0aW5nIGNvZGUsIGl0IGlzIGVhc2llciBhbmQgc2FmZXIgdG8gbmFtZSB0aGUgYXJndW1lbnRzCgpgYGB7cn0Kc2VxKGZyb20gPSAyLCB0byA9IDIwLCBieSA9IDQpCnNlcSgyLCAyMCwgNCkKYGBgCgpBcmd1bWVudHMgY2FuIGhhdmUgKmRlZmF1bHQqIHZhbHVlcywgbWVhbmluZyB3ZSBkbyBub3QgbmVlZCB0byBzcGVjaWZ5IHZhbHVlcyBmb3IgdGhlc2UgaW4gb3JkZXIgdG8gcnVuIHRoZSBmdW5jdGlvbi4KCmBybm9ybWAgaXMgYSBmdW5jdGlvbiB0aGF0IHdpbGwgZ2VuZXJhdGUgYSBzZXJpZXMgb2YgdmFsdWVzIGZyb20gYSAqbm9ybWFsIGRpc3RyaWJ1dGlvbiouIEluIG9yZGVyIHRvIHVzZSB0aGUgZnVuY3Rpb24sIHdlIG5lZWQgdG8gdGVsbCBSIGhvdyBtYW55IHZhbHVlcyB3ZSB3YW50CgpgYGB7cn0Kcm5vcm0obj0xMCkKYGBgCgpUaGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBpcyBkZWZpbmVkIGJ5IGEgKm1lYW4qIChhdmVyYWdlKSBhbmQgKnN0YW5kYXJkIGRldmlhdGlvbiogKHNwcmVhZCkuIEhvd2V2ZXIsIGluIHRoZSBhYm92ZSBleGFtcGxlIHdlIGRpZG4ndCB0ZWxsIFIgd2hhdCBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gd2Ugd2FudGVkLiBTbyBob3cgZG9lcyBSIGtub3cgd2hhdCB0byBkbz8gQWxsIGFyZ3VtZW50cyB0byBhIGZ1bmN0aW9uIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyBhcmUgbGlzdGVkIGluIHRoZSBoZWxwIHBhZ2UKCigqTi5CIHNvbWV0aW1lcyBoZWxwIHBhZ2VzIGNhbiBkZXNjcmliZSBtb3JlIHRoYW4gb25lIGZ1bmN0aW9uKikKCmBgYHtyfQo/cm5vcm0KYGBgCgpJbiB0aGlzIGNhc2UsIHdlIHNlZSB0aGF0IHRoZSBkZWZhdWx0cyBmb3IgbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIGFyZSAwIGFuZCAxLiBXZSBjYW4gY2hhbmdlIHRoZSBmdW5jdGlvbiB0byBnZW5lcmF0ZSB2YWx1ZXMgZnJvbSBhIGRpc3RyaWJ1dGlvbiB3aXRoIGEgZGlmZmVyZW50IG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiB1c2luZyB0aGUgYG1lYW5gIGFuZCBgc2RgICphcmd1bWVudHMqLiBJdCBpcyBpbXBvcnRhbnQgdGhhdCB3ZSBnZXQgdGhlIHNwZWxsaW5nIG9mIHRoZXNlIGFyZ3VtZW50cyBleGFjdGx5IHJpZ2h0LCBvdGhlcndpc2UgUiB3aWxsIGFuIGVycm9yIG1lc3NhZ2UsIG9yICh3b3JzZT8pIGRvIHNvbWV0aGluZyB1bmV4cGVjdGVkLgoKYGBge3J9CnJub3JtKG49MTAsIG1lYW49MixzZD0zKQpybm9ybSgxMCwgMiwgMykKYGBgCgpJbiB0aGUgZXhhbXBsZXMgYWJvdmUsIGBzZXFgIGFuZCBgcm5vcm1gIHdlcmUgYm90aCBvdXRwdXR0aW5nIGEgc2VyaWVzIG9mIG51bWJlcnMsIHdoaWNoIGlzIGNhbGxlZCBhICp2ZWN0b3IqIGluIFIgYW5kIGlzIHRoZSBtb3N0LWZ1bmRhbWVudGFsIGRhdGEtdHlwZS4KCgoKIyNCYXNpYyBjb25jZXB0cyBpbiBSIC0gdmVjdG9ycwoKLSBUaGUgYmFzaWMgZGF0YSBzdHJ1Y3R1cmUgaW4gUiBpcyBhICoqdmVjdG9yKiogLS0gYW4gb3JkZXJlZCBjb2xsZWN0aW9uIG9mIHZhbHVlcy4gCi0gUiB0cmVhdHMgZXZlbiBzaW5nbGUgdmFsdWVzIGFzIDEtZWxlbWVudCB2ZWN0b3JzLiAKLSBUaGUgZnVuY3Rpb24gKipgY2AqKiAqY29tYmluZXMqIGl0cyBhcmd1bWVudHMgaW50byBhIHZlY3RvcjoKCmBgYHtyfQp4IDwtIGMoMyw0LDUsNikKeApgYGAKLSBUaGUgc3F1YXJlIGJyYWNrZXRzIGBbXWAgaW5kaWNhdGUgdGhlIHBvc2l0aW9uIHdpdGhpbiB0aGUgdmVjdG9yICh0aGUgKioqaW5kZXgqKiopLgotIFdlIGNhbiBleHRyYWN0IGluZGl2aWR1YWwgZWxlbWVudHMgYnkgdXNpbmcgdGhlIGBbXWAgbm90YXRpb246CgpgYGB7cn0KeFsxXQp4WzRdCgpgYGAKCi0gV2UgY2FuIGV2ZW4gcHV0IGEgdmVjdG9yIGluc2lkZSB0aGUgc3F1YXJlIGJyYWNrZXRzICgqdmVjdG9yIGluZGV4aW5nKik6Ci0gKipCZWZvcmUgZXhlY3V0aW5nIHRoaXMgbGluZSBvZiBjb2RlLCB3aGF0IGRvIHlvdSB0aGluayBpdCB3aWxsIHByb2R1Y2U/KioKCmBgYHtyfQp5IDwtIGMoMiwzKQp4W3ldCmBgYAoKLSBUaGVyZSBhcmUgYSBudW1iZXIgb2Ygc2hvcnRjdXRzIHRvIGNyZWF0ZSBhIHZlY3Rvci4gCi0gSW5zdGVhZCBvZjoKCmBgYHtyfQp4IDwtIGMoMywgNCwgNSwgNiwgNywgOCwgOSwgMTAsIDExLCAxMikKeApgYGAKLSB3ZSBjYW4gd3JpdGU6CgpgYGB7cn0KeCA8LSAzOjEyCngKYGBgCgotIG9yIHdlIGNhbiB1c2UgdGhlICoqYHNlcSgpYCoqIGZ1bmN0aW9uLCB3aGljaCByZXR1cm5zIGEgdmVjdG9yOgoKYGBge3J9CnggPC0gc2VxKDIsIDIwLCA0KQp4CmBgYAoKYGBge3J9CnggPC0gc2VxKDIsIDIwLCBsZW5ndGgub3V0PTUpCngKYGBgCgotIG9yIHdlIGNhbiB1c2UgdGhlICoqYHJlcCgpYCoqIGZ1bmN0aW9uOgoKCmBgYHtyfQp5IDwtIHJlcCgzLCA1KQp5CmBgYAoKYGBge3J9CnkgPC0gcmVwKDE6MywgNSkKeQpgYGAKCgotIFdlIGhhdmUgc2VlbiBzb21lIHdheXMgb2YgZXh0cmFjdGluZyBlbGVtZW50cyBvZiBhIHZlY3Rvci4gV2UgY2FuIHVzZSB0aGVzZSBzaG9ydGN1dHMgdG8gbWFrZSB0aGluZ3MgZWFzaWVyIChvciBtb3JlIGNvbXBsZXghKQoKYGBge3J9CnggPC0gMzoxMgojIEV4dHJhY3QgZWxlbWVudHMgZnJvbSB4OgoKeFszOjddCnhbc2VxKDIsIDYsIDIpXQp4W3JlcCgzLCAyKV0KYGBgCgoKLSBXZSBjYW4gYWRkIGFuIGVsZW1lbnQgdG8gYSB2ZWN0b3I6CgpgYGB7cn0KeSA8LSBjKHgsIDEpCnkKYGBgCgotIFdlIGNhbiBnbHVlIHZlY3RvcnMgdG9nZXRoZXI6CgpgYGB7cn0KeiA8LSBjKHgsIHkpCnoKYGBgCgotIFdlIGNhbiAicmVtb3ZlIiBlbGVtZW50KHMpIGZyb20gYSB2ZWN0b3I6CiAgICArIE5PVEU6IHRoZSB2ZWN0b3IgeCBkb2Vzbid0IGdldCBtb2RpZmllZAogICAgKyB3ZSdyZSBqdXN0IGRpc3BsYXlpbmcgd2hhdCB0aGUgdmVjdG9yIGxvb2tzIGxpa2Ugd2l0aG91dCBwYXJ0aWN1bGFyIGVsZW1lbnRzCiAgICAKYGBge3J9CnggPC0gMzoxMgoKeFstM10KeFstKDU6NyldCnhbLXNlcSgyLCA2LCAyKV0KeApgYGAKCi0gRmluYWxseSwgd2UgY2FuIG1vZGlmeSB0aGUgY29udGVudHMgb2YgYSB2ZWN0b3I6CgpgYGB7cn0KeFs2XSA8LSA0CngKCnhbMzo1XSA8LSAxCngKYGBgCgoqKlJlbWVtYmVyISoqCgogLSAqKlNxdWFyZSoqIGJyYWNrZXRzIFsgXSBmb3IgKioqaW5kZXhpbmcqKioKIC0gKipQYXJlbnRoZXNlcyoqICgpIGZvciBmdW5jdGlvbiAqKiphcmd1bWVudHMqKioKCiMjQmFzaWMgY29uY2VwdHMgaW4gUiAtIHZlY3RvciBhcml0aG1ldGljCgotIFdoZW4gYXBwbHlpbmcgYWxsIHN0YW5kYXJkIGFyaXRobWV0aWMgb3BlcmF0aW9ucyB0byB2ZWN0b3JzLAphcHBsaWNhdGlvbiBpcyBlbGVtZW50LXdpc2UKCmBgYHtyfQp4IDwtIDE6MTAKeSA8LSB4KjIKYGBgCgpgYGB7cn0KeQpgYGAKCmBgYHtyfQp6IDwtIHheMgpgYGAKCmBgYHtyfQp6CmBgYAoKLSBBZGRpbmcgdHdvIHZlY3RvcnM6CgpgYGB7cn0KeSArIHoKYGBgCgotIElmIHZlY3RvcnMgYXJlIG5vdCB0aGUgc2FtZSBsZW5ndGgsIHRoZSBzaG9ydGVyIG9uZSB3aWxsIGJlIHJlY3ljbGVkOgoKYGBge3J9CnggKyAxOjIKYGBgCgotIEJ1dCBiZSBjYXJlZnVsIGlmIHRoZSB2ZWN0b3IgbGVuZ3RocyBhcmVuJ3QgZmFjdG9ycyBvZiBlYWNoIG90aGVyOgoKYGBge3J9CnggKyAxOjMKYGBgCgotIFNvbWV0aW1lcyBSIHdpbGwgZ2l2ZSBhICp3YXJuaW5nKiBtZXNzYWdlLiBJdCBoYXMgcGVyZm9ybWVkIHRoZSBjYWxjdWxhdGlvbiB5b3UgYXNrZWQgaXQgdG8sIGJ1dCB0aGUgcmVzdWx0cyBtYXkgYmUgdW5leHBlY3RlZC4gWW91IG5lZWQgdG8gY2hlY2sgdGhlIG91dHB1dCBjYXJlZnVsbHkgdG8gbWFrZSBzdXJlIGl0IGlzIHdoYXQgeW91IHJlYWxseSB3YW50ZWQuCgojI0Jhc2ljIGNvbmNlcHRzIGluIFIgLSBDaGFyYWN0ZXIgdmVjdG9ycyBhbmQgbmFtaW5nCgotIEFsbCB0aGUgdmVjdG9ycyB3ZSBoYXZlIHNlZW4gc28gZmFyIGhhdmUgY29udGFpbmVkIG51bWJlcnMsIGJ1dCB3ZSBjYW4gYWxzbyBzdG9yZSB0ZXh0ICgvInN0cmluZ3MiKSBpbiB2ZWN0b3IKICAgICsgdGhpcyBpcyBjYWxsZWQgYSAqKmNoYXJhY3RlcioqIHZlY3Rvci4KCmBgYHtyfQpnZW5lLm5hbWVzIDwtIGMoIlBheDYiLCAiQmV0YS1hY3RpbiIsICJGb3hQMiIsICJIb3g5IikKZ2VuZS5uYW1lcwpgYGAKCi0gV2UgY2FuIG5hbWUgZWxlbWVudHMgb2YgdmVjdG9ycyB1c2luZyB0aGUgYG5hbWVzKClgIGZ1bmN0aW9uLCB3aGljaCBjYW4gYmUgdXNlZnVsIHRvIGtlZXAgdHJhY2sgb2YgdGhlIG1lYW5pbmcgb2Ygb3VyIGRhdGE6CgpgYGB7cn0KZ2VuZS5leHByZXNzaW9uIDwtIGMoMCwgMy4yLCAxLjIsIC0yKQpuYW1lcyhnZW5lLmV4cHJlc3Npb24pIDwtIGdlbmUubmFtZXMKZ2VuZS5leHByZXNzaW9uCgpgYGAKCi0gV2UgY2FuIGFsc28gdXNlIHRoZSBgbmFtZXMoKWAgZnVuY3Rpb24gdG8gZ2V0IGEgdmVjdG9yIG9mIHRoZSBuYW1lcyBvZiBhbiBvYmplY3Q6CmBgYHtyfQpuYW1lcyhnZW5lLmV4cHJlc3Npb24pCmBgYAoKCiMjRXhlcmNpc2U6IEJvZHktTWFzcyBJbmRleAotIExldCdzIHRyeSBzb21lIHZlY3RvciBhcml0aG1ldGljLiBIZXJlIGFyZSB0aGUgd2VpZ2h0cyBhbmQgaGVpZ2h0cyBvZiBmaXZlIGluZGl2aWR1YWxzCgp8UGVyc29uIHwgV2VpZ2h0IChrZykgfCBIZWlnaHQgKGNtKXwKfC0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tOnwtLS0tLS0tLS0tLS0tLS0tLS0tOnwKfCpKbyogICAgIHwgICAgNjUuOCAgICAgICAgICAgfCAgICAgMTkyICAgICAgICAgIHwKfCpTYW0qICAgIHwgICAgNjcuOSAgICAgICAgICAgfCAgICAgMTc5ICAgICAgICAgIHwKfCpDaGFybGllKnwgICAgNzUuMyAgICAgICAgICAgfCAgICAgMTY5ICAgICAgICAgIHwKfCpGcmFua2llKnwgICAgNjEuOSAgICAgICAgICAgfCAgICAgMTc1ICAgICAgICAgIHwKfCpBbGV4KiAgIHwgICAgOTIuNCAgICAgICAgICAgfCAgICAgMTcxICAgICAgICAgIHwKCgotIENyZWF0ZSAqd2VpZ2h0KiBhbmQgKmhlaWdodCogdmVjdG9ycyB0byBob2xkIHRoZSBkYXRhIGluIGVhY2ggY29sdW1uIHVzaW5nIHRoZSBgY2AgZnVuY3Rpb24uIENyZWF0ZSBhICpwZXJzb24qIHZlY3RvciBhbmQgdXNlIHRoaXMgdmVjdG9yIHRvIG5hbWUgdGhlIHZhbHVlcyBpbiB0aGUgb3RoZXIgdHdvIHZlY3RvcnMuCgoxLiBUaGUgYm9keS1tYXNzIGluZGV4IGlzIGdpdmVuIGJ5IHRoZSBmb3JtdWxhOi0gJEJNSSA9IChXZWlnaHQpLyhIZWlnaHReMikkOyB3aGVyZSBIZWlnaHQgaXMgZ2l2ZW4gaW4gKioqbWV0cmVzKioqCiAgICArIENyZWF0ZSBhIG5ldyB2ZWN0b3IgdG8gcmVjb3JkIHRoaXMsIGNhbGxlZCBgYm1pYC4KMi4gQ3JlYXRlIGEgbmV3IHZlY3RvciBgYm1pLnNvcnRlZGAgd2hlcmUgdGhlIGJtaSB2YWx1ZXMgYXJlIHB1dCBpbiBpbmNyZWFzaW5nIG51bWVyaWMgb3JkZXIgKEhJTlQ6IGxvb2sgdXAgdGhlIGhlbHAgb24gdGhlIGBzb3J0YCBmdW5jdGlvbikKMy4gVGhlIGludGVycXVhcnRpbGUgcmFuZ2UgKElRUikgb2YgYSB2ZWN0b3IgaXMgZGVmaW5lZCBhcyB0aGUgNzUlIHBlcmNlbnRpbGUgb2YgdGhlIGRhdGEgbWludXMgdGhlIDI1JSBwZXJjZW50aWxlLiBDYWxjdWxhdGUgdGhlIElRUiBmb3Igb3VyIGJtaSB2YWx1ZXMgCiAgICArIGNoZWNrIHlvdXIgYW5zd2VyIHVzaW5nIHRoZSBgSVFSYCBmdW5jdGlvbgogICAgCiAgICAKYGBge3J9CiMjIyBZT1VSIEFOU1dFUiBIRVJFIChwbGVhc2UpICMjIwoKYGBgCgoKCgojI0dldHRpbmcgaGVscAoKLSAqKlRoaXMgaXMgcG9zc2libHkgdGhlIG1vc3QgaW1wb3J0YW50IHNsaWRlIGluIHRoZSB3aG9sZSBjb3Vyc2UhPyEqKgotIFRvIGdldCBoZWxwIG9uIGFueSBSIGZ1bmN0aW9uLCB0eXBlICoqYD9gKiogZm9sbG93ZWQgYnkgdGhlIGZ1bmN0aW9uIG5hbWUuIEZvciBleGFtcGxlOgpgYGB7cn0KP3NlcQpgYGAKLSBUaGlzIHJldHJpZXZlcyB0aGUgc3ludGF4IGFuZCBhcmd1bWVudHMgZm9yIHRoZSBmdW5jdGlvbi4gVGhlIGhlbHAgcGFnZSBzaG93cyB0aGUgZGVmYXVsdCBvcmRlciBvZiBhcmd1bWVudHMuIEl0IGFsc28gdGVsbHMgeW91IHdoaWNoICpwYWNrYWdlKiBpdCBiZWxvbmdzIHRvLgotIFRoZXJlIGlzIHR5cGljYWxseSBhIHVzYWdlIGV4YW1wbGUsIHdoaWNoIHlvdSBjYW4gdGVzdCB1c2luZyB0aGUKYGV4YW1wbGVgIGZ1bmN0aW9uOgoKYGBge3J9CmV4YW1wbGUoc2VxKQpgYGAKCi0gSWYgeW91IGNhbid0IHJlbWVtYmVyIHRoZSBleGFjdCBuYW1lLCB0eXBlICoqYD8/YCoqIGZvbGxvd2VkIGJ5IHlvdXIgZ3Vlc3MuClIgd2lsbCByZXR1cm4gYSBsaXN0IG9mIHBvc3NpYmlsaXRpZXM6CgpgYGB7cn0KPz9tZWFuCmBgYAoKLSBUaGUgKipQYWNrYWdlcyoqIHRhYiBpbiB0aGUgbG93ZXItcmlnaHQgcGFuZWwgb2YgUlN0dWRpbyB3aWxsIGhlbHAgeW91IGxvY2F0ZSB0aGUgaGVscCBwYWdlcyBmb3IgYSBwYXJ0aWN1bGFyIHBhY2thZ2UgYW5kIGl0cyBmdW5jdGlvbnMKICAgICsgT2Z0ZW4gdGhlcmUgd2lsbCBiZSBhIHVzZXItZ3VpZGUgb3IgJyp2aWduZXR0ZSonIHRvbwoKIyMgUiBwYWNrYWdlcwoKLSBSIGNvbWVzIHJlYWR5IGxvYWRlZCB3aXRoIHZhcmlvdXMgbGlicmFyaWVzIG9mIGZ1bmN0aW9ucyBjYWxsZWQKKipwYWNrYWdlcyoqLiBGb3IgZXhhbXBsZTogdGhlIGZ1bmN0aW9uICoqYHN1bSgpYCoqIGlzIGluIHRoZSAqKmJhc2UqKiBwYWNrYWdlIGFuZAoqKmBzZCgpYCoqLCB3aGljaCBjYWxjdWxhdGVzIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgYSB2ZWN0b3IsIGlzIGluIHRoZQoqKmBzdGF0c2AqKiBwYWNrYWdlCi0gVGhlcmUgYXJlIDEwMDBzIG9mIGFkZGl0aW9uYWwgcGFja2FnZXMgcHJvdmlkZWQgYnkgdGhpcmQgcGFydGllcywKYW5kIHRoZSBwYWNrYWdlcyBjYW4gYmUgZm91bmQgaW4gbnVtZXJvdXMgc2VydmVyIGxvY2F0aW9ucyBvbiB0aGUKd2ViIGNhbGxlZCAqKnJlcG9zaXRvcmllcyoqCi0gVGhlIHR3byByZXBvc2l0b3JpZXMgeW91IHdpbGwgY29tZSBhY3Jvc3MgdGhlIG1vc3QgYXJlOgogICAgKyAqKlRoZSBDb21wcmVoZW5zaXZlIFIgQXJjaGl2ZSBOZXR3b3JrIChDUkFOKSoqCiAgICAgICAgKyBVc2UgbWV0YWNyYW4gc2VhcmNoIHRvIGZpbmQgZnVuY3Rpb25hbGl0eSB5b3UgbmVlZDogaHR0cDovL3d3dy5yLXBrZy5vcmcvCiAgICAgICAgKyBPciBsb29rIGZvciBwYWNrYWdlcyBieSB0aGVtZTogaHR0cDovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvdmlld3MvCiAgICArICoqQmlvY29uZHVjdG9yKiogc3BlY2lhbGlzZWQgaW4gZ2Vub21pY3M6IGh0dHA6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvCiAgICArICoqaHR0cHMvL2dpdGh1Yi5jb20qKiBjYW4gYWxzbyBob3N0IFIgcGFja2FnZXMsIGFuZCBob3N0cyB0aGUgZGV2ZWxvcG1lbnQgdmVyc2lvbiBvZiBtYW55IHBhY2thZ2VzCi0gQm90dG9tbGluZTogKioqYWx3YXlzKioqIGZpcnN0IGxvb2sgaWYgdGhlcmUgaXMgYWxyZWFkeSBhbiBSIHBhY2thZ2UgdGhhdCBkb2VzIHdoYXQgeW91IHdhbnQgYmVmb3JlIHRyeWluZyB0byBpbXBsZW1lbnQgaXQgeW91cnNlbGYKICAgIAojIyBJbnN0YWxsaW5nIHBhY2thZ2VzICAgIAogICAgCi0gQ1JBTiBwYWNrYWdlcyBjYW4gYmUgaW5zdGFsbGVkIHVzaW5nICoqYGluc3RhbGwucGFja2FnZXMoKWAqKgoKICAgICsgb3IgY2xpY2tpbmcgb24gdGhlICpQYWNrYWdlcyogdGFiIGluIFJTdHVkaW8KCmBgYHtyIGV2YWw9RkFMU0V9Cmluc3RhbGwucGFja2FnZXMobmFtZS5vZi5teS5wYWNrYWdlKQpgYGAKCgotIFNldCB0aGUgKkJpb2NvbmR1Y3RvciogcGFja2FnZSBkb3dubG9hZCB0b29sIGJ5IHR5cGluZzoKYGBge3IgZXZhbD1GQUxTRX0Kc291cmNlKCJodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9iaW9jTGl0ZS5SIikKYGBgCgotICpCaW9jb25kdWN0b3IqIHBhY2thZ2VzIGFyZSB0aGVuIGluc3RhbGxlZCB3aXRoIHRoZSBgYmlvY0xpdGUoKWAgZnVuY3Rpb246CmBgYHtyIGV2YWw9RkFMU0V9CmJpb2NMaXRlKCJQYWNrYWdlTmFtZSIpCmBgYAoKLSBnZ3Bsb3QyIGlzIGEgY29tbW9ubHkgdXNlZCBncmFwaGljcyBwYWNrYWdlOgogICAgKyBpbiBSU3R1ZGlvLCBnbyB0byAqKlRvb2xzKiog4oaSICoqSW5zdGFsbCBQYWNrYWdlcyoqLi4uIGFuZCB0eXBlIHRoZSBwYWNrYWdlIG5hbWUKICAgICsgb3IgdXNlIGBpbnN0YWxsLnBhY2thZ2VzKClgIGZ1bmN0aW9uIHRvIGluc3RhbGwgaXQ6CiAgCmBgYHtyIGV2YWw9RkFMU0V9Cmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQpgYGAKICAgCi0gYGxpbW1hYCBpcyBhIEJpb2NvbmR1Y3RvciBwYWNrYWdlIChodHRwOi8vd3d3LmJpb2NvbmR1Y3Rvci5vcmcpIGZvciB0aGUgYW5hbHlzaXMgb2YgbWljcm9hcnJheSBhbmQgUk5BLXNlcSBkYXRhOgoKYGBge3IgZXZhbD1GQUxTRX0Kc291cmNlKCJodHRwOi8vd3d3LmJpb2NvbmR1Y3Rvci5vcmcvYmlvY0xpdGUuUiIpCmJpb2NMaXRlKCJsaW1tYSIpCmBgYAoKIyNFeGFtcGxlOiBMb2FkIHBhY2thZ2VzIGdncGxvdDIgYW5kIGxpbW1hCgotIFIgbmVlZHMgdG8gYmUgdG9sZCB0byB1c2UgdGhlIG5ldyBmdW5jdGlvbnMgZnJvbSB0aGUgaW5zdGFsbGVkIHBhY2thZ2VzLiBVc2UgKipgbGlicmFyeSguLi4pYCoqIGZ1bmN0aW9uIHRvIGxvYWQgdGhlIG5ld2x5IGluc3RhbGxlZCBmZWF0dXJlczoKCmBgYHtyIGV2YWw9RkFMU0V9CiAKbGlicmFyeShnZ3Bsb3QyKSAjIGxvYWRzIGdncGxvdCBmdW5jdGlvbnMKbGlicmFyeShsaW1tYSkgICAjIGxvYWRzIGxpbW1hIGZ1bmN0aW9ucwpsaWJyYXJ5KCkgICAgICAgICMgTGlzdHMgYWxsIHRoZSBwYWNrYWdlcyAKICAgICAgICAgICAgICAgICAjIHlvdSd2ZSBnb3QgaW5zdGFsbGVkIApgYGAKCiMjIEtleSBwb2ludHMKCiAqIEluIHByb2dyYW1taW5nLCBhIHZhcmlhYmxlIGlzIGEgbGV0dGVyIG9yIHdvcmQgd2hpY2ggdGFrZXMgKG9yIGNvbnRhaW5zKSBhIHZhbHVlCiAqIEluIFIsIHRoZSBhc3NpZ25tZW50IG9wZXJhdG9yIDwtIGlzIHVzZWQgdG8gYXNzaWduIHZhbHVlcyB0byB2YXJpYWJsZXMKICogVGhlIGJhc2ljIGRhdGEgc3RydWN0dXJlIGluIFIgaXMgYSB2ZWN0b3Ig4oCTIGFuIG9yZGVyZWQgY29sbGVjdGlvbiBvZiB2YWx1ZXMKICogQSBmdW5jdGlvbiBpcyBhIHVuaXQgb2YgY29kZSB0aGF0IGNhbiB0YWtlIGFyZ3VtZW50cyBhbmQgcGVyZm9ybSBhIHNldCBvZiBpbnN0cnVjdGlvbnMKICogVGhlIGZ1bmN0aW9uIGMgY29tYmluZXMgaXRzIGFyZ3VtZW50cyBpbnRvIGEgdmVjdG9yCiAqIEFsbCBzdGFuZGFyZCBhcml0aG1ldGljIG9wZXJhdGlvbnMgYXJlIGFwcGxpZWQgdG8gdmVjdG9ycyBlbGVtZW50LXdpc2UKICogVG8gZ2V0IGhlbHAgb24gYW55IFIgZnVuY3Rpb24sIHR5cGUgPyBmb2xsb3dlZCBieSB0aGUgZnVuY3Rpb24gbmFtZQ==