1. Why to use R?

Free and cross-platform
R is a programming language and open source software dedicated to statistics and data science supported by the R Foundation for Statistical Computing. R is cross-platform and can therefore be installed on Windows, Mac OS or GNU/Linux.



Polyvalent
R allows you to manipulate all types of objects. It is for one of these reasons that it competes, complements or replaces a whole range of pre-existing software and languages, including in very specific fields, for example: textual statistics, graph analysis, cartography, spatial statistics, webscraping, document production, web applications, etc. It also competes with other languages widely used for scientific calculation and data analysis, in particular with Python.



Expandable
R is composed of a common base r-base (standard statistical and graphical functions, called primitive functions) on which is grafted a set of extensions called packages. A package is a library of functions implemented by users and made available to all through repositories grouped under the Comprehensive R Archive Network (CRAN). This modular structure explains the wide range of possible applications: the expansion of the software is only limited by the work that users worldwide make available to all other users (12809 packages are on CRAN as of July 30, 2018).



Reproducible
The entire processing chain can thus be carried out under R. This integrated workflow is more efficient and secure: no more imports and exports from one software package to another, and the archiving, dissemination and reproducibility of the integrity of its work and methodology are ensured.

2. A little history of R


Let’s start by recalling some important points in R’s history.


R was founded in the early 1990s in New Zealand and has been growing ever since. Since 1997, a group of researchers called “R Core Team” composed today of 20 people has the authorization to modify the source code of R. Of course anyone can submit packages but the core of the software is managed by these 20 people. Two other structures are important for R, the R foundation and the CRAN.

THE R FOUNDATION
It is a non-profit organization created by the R Core Team to provide support for the development of the R project. It serves as an interlocutor for those who would like to support or interact with the R software developer community. This foundation owns and administers the copyright of the R software and related documentation.
THE CRAN
It is the “Comprehensive R Archive Network”, a network of web servers hosted in different locations around the world that stores R’s code and documentation in order to make R quickly accessible from anywhere in the world. It is also the place where new packages are submitted to be made available to R users.


3. Learn to use R

Objective 1: Master your work environment

General features of R studio

Rstudio’s interface is divided into 4 graphic windows: * One area allows the editing of R source files (with syntax highlighting and autocompletion of function and object names with the tab key).

  • An other area displays the console with the current R session running. Using the shortcut Ctrl+Enter allows you to execute a line or selection directly from the source file.

  • A third area allows you to switch between displaying the objects in the current workspace and the history of the commands executed. You can even visually inspect the contents of some objects.

  • Finally, a fourth zone allows you to switch between:
    -a file browser
    -the graphs display and export window
    -a list of installed extensions, which allows you to load them into memory or install new ones very easily
    -a help browser that allows both navigation in the online help integrated in R and the display of the help pages for the various functions


R studio

R studio

The working directory and Projects in RStudio

Working directory

Each time R is asked to load or save a file (especially when trying to import data), R will evaluate the name of the file sent to it against the currently defined working directory, which corresponds to the directory in which R is currently running.

To know the current working directory, we can use the getwd function :

getwd()

To define the working directory:

setwd()

Projects

RStudio has a very practical feature to organize its work into different projects.

The main idea is to gather all the files / documents related to the same project (data, scripts, automated reports…) in a dedicated directory.

You can create an RStudio project:

  • In a brand new directory
  • In an existing directory where you already have R code and data
  • By cloning a version control (Git or Subversion) repository

When a project is opened within RStudio the following actions are taken:

A new R session (process) is started:
* The .Rprofile file in the project’s main directory (if any) is sourced by R
* The .RData file in the project’s main directory is loaded (if project options indicate that it should be loaded).
* The .Rhistory file in the project’s main directory is loaded into the RStudio History pane (and used for Console Up/Down arrow command history).
* The current working directory is set to the project directory.
* Previously edited source documents are restored into editor tabs
* Other RStudio settings (e.g. active tabs, splitter positions, etc.) are restored to where they were the last time the project was closed.

Help in R

The help(ma_function) command where ?ma_function allows you to access using the ma_function function . The help page automatically appears in the Help tab, at the bottom right of the RStudio interface. There are:

  • the description of the function,
  • its arguments (mandatory and optional),
  • references,
  • examples of how to apply the function.

Example : Executing the following command takes you to the help page of the log() function:

help(log)

Installation of packages

An R package is a library of functions that perform particular operations. To use a package, it must have been previously installed and loaded. During the installation of R, a number of packages are pre-installed. When RStudio is launched, some of these packages are loaded by default. This is the case, for example, of the stats package.

It is possible to view the list of packages already installed on your computer via the RStudio Packages tab.

When it is necessary to use a non pre-installed package, it is possible to install it manually via the Menu Tools→Install Packages. Once the package is installed, it is loaded by the library() instruction.

Organize your script

  • Keep track of who wrote your code and its intended purpose

Starting your code with an annotated description of what the code does when it is run will help you when you have to look at or change it in the future. Just one or two lines at the beginning of the file can save you or someone else a lot of time and effort when trying to understand what a particular script does.

# it's a wonderful script that will take you to other worlds
# L . Lospin & J.C
# 18 brumaire de l'an 205
  • Be explicit about the requirements and dependencies of your code Loading all of the packages that will be necessary to run your code (using library) is a nice way of indicating which packages are necessary to run your code. It can be frustrating to make it two-thirds of the way through a long-running script only to find out that a dependency hasn’t been installed.
library(ggplot2)
library(reshape)

# OR
x<-c("data.table","tidyverse","magrittr")
lapply(x, require, character.only = TRUE)
  • Another way you can be explicit about the requirements of your code and improve it’s reproducibility is to limit the “hard-coding” of the input and output files for your script. If your code will read in data from a file, define a variable early in your code that stores the path to that file. For example
input_file <- "data/data.csv" 
output_file <- "data/results.csv"

# read input
input_data <- read.csv(input_file)
# get number of samples in data
sample_number <- nrow(input_data)
# generate results
results <- some_other_function(input_file, sample_number)
# write results
write.table(results, results_file)


is preferable to:

# check
input_data <- read.csv("monOrdi/mes fichiers/data/data.csv")
# get number of samples in data
sample_number <- nrow(input_data)
# generate results
results <- some_other_function("monOrdi/mes fichiers/data/data.csv", sample_number)
# write results
write.table("data/results.csv", results_file)
  • Identify and segregate distinct components in your code
    It’s easy to annotate and mark your code using # or #- to set off sections of your code and to make finding specific parts of your code easier. For example, it’s often helpful when writing code to separate the function definitions. If you create only one or a few custom functions in your script, put them toward the top of your code. If you have written many functions, put them all in their own .R file and then source those files. source will define all of these functions so that your code can make use of them as needed.
source("my_genius_fxns.R")

Other ideas: * Use a consistent style within your code. For example, name all matrices something ending in _mat. Consistency makes code easier to read and problems easier to spot.

  • Keep your code in bite-sized chunks. If a single function or loop gets too long, consider looking for ways to break it into smaller pieces.

  • Don’t repeat yourself–automate! If you are repeating the same code over and over, use a loop or a function to repeat that code for you. Needless repetition doesn’t just waste time–it also increases the likelihood you’ll make a costly mistake!

  • Keep all of your source files for a project in the same directory, then use relative paths as necessary to access them. For example, use

dat <- read.csv(file = "files/dataset-2013-01.csv", header = TRUE)

rather than:

dat <- read.csv(file = "/Users/Karthik/Documents/sannic-project/files/dataset-2013-01.csv", header = TRUE)

Objective 2: The R objects

General features

Everything in the R language is an object: variables containing data, functions, operators, even the symbol representing the name of an object is itself an object. Objects have at least one mode and one length and some may have one or more attributes.

The mode of an object is obtained with the mode function :

 v <- c(1, 2, 5, 9)
 mode(v)
[1] "numeric"

The length of an object is obtained with the length function:

> length(v)
[1] 4

Objects

Vectors

In R, for all practical purposes, everything is a vector. The vector is the basic unit in the calculations.

In a simple vector, all elements must be in the same mode. We restrict ourselves to this type of vectors for the moment. The basic functions for creating vectors are:

c (concatenation) ; numeric (numeric mode vector) ; logical (logical mode vector) ; character (character mode vector). It is possible (and often desirable) to give a label to each of the elements of a vector.

v <- c(a = 1, b = 2, c = 5)
v
a b c 
1 2 5 
v <- c(1, 2, 5)
names(v) <- c("a", "b", "c")
v
a b c 
1 2 5 

These labels are then part of the attributes of the vector.

The indication in a vector is done with the brackets [ ]. An element can be extracted from a vector by its position or label, if it exists (in which case this approach is much safer).

v[3]
v["c"]

Matrices and array

As R is a specialized language for mathematical calculations, it naturally and intuitively supports matrices and, more generally, multidimensional tables.

A matrix is a vector with a dim attribute of length 2. This implicitly changes the object class to “matrix” and, as a result, the way the object is displayed and its interaction with several operators and functions. The basic function for creating matrices is matrix :

matrix(1:6, nrow = 2, ncol = 3)
matrix(1:6, nrow = 2, ncol = 3, byrow = TRUE)

The generalization of a matrix to more than two dimensions is an array. The number of dimensions of the array is always equal to the length of the dim attribute, the implicit class of an array is “array”.

The basic function to create arrays is array:

array(1:24, dim = c(3, 4, 2))

Lists

The list is the most general and versatile storage mode of the R language. It is a type of special vector whose elements can be of any mode, including the list mode. This allows lists to be nested, hence the term recursive for this type of object.

The basic function for creating lists is list:

x <- list(size = c(1, 5, 2), user = "Joe", new = TRUE)
x
$size
[1] 1 5 2

$user
[1] "Joe"

$new
[1] TRUE

Data frames

Vectors, matrices, tables and lists are the most common object types used in R programming. However, many statistical procedures - think of linear regression, for example - rely more on data frames for data storage.

Although visually similar to a matrix, a data frame is more general since the columns can be in different modes; think of a table with names (character mode) in one column and notes (numeric mode) in another.

A data frame is created with the data.frame function or, to convert another type of object into a data frame, with as.data.frame.

Logical operators

We have the following types of operators in R programming:

  • Arithmetic Operators
  • Relational Operators
  • Logical Operators
  • Assignment Operators
  • Miscellaneous Operator

Arithmetic Operators

‘+’ Adds two vectors

v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v+t)
[1] 10.0  8.5 10.0

‘−’ Subtracts second vector from the first

v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v-t)
[1] -6.0  2.5  2.0

’*’ Multiplies both vectors

v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v*t)
[1] 16.0 16.5 24.0

‘/’ Divide the first vector with the second

v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v/t)
[1] 0.250000 1.833333 1.500000

‘%%’ Give the remainder of the first vector with the second

v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v%%t)
[1] 2.0 2.5 2.0

‘%/%’ The result of division of first vector with second (quotient)

v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v%/%t)
[1] 0 1 1

‘^’ The first vector raised to the exponent of second vector

v <- c( 2,5.5,6)
t <- c(8, 3, 4)
print(v^t)
[1]  256.000  166.375 1296.000

Relational Operators

‘>’ Checks if each element of the first vector is greater than the corresponding element of the second vector.

v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v>t)
[1] FALSE  TRUE FALSE FALSE

‘<’ Checks if each element of the first vector is less than the corresponding element of the second vector.

v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v < t)
[1]  TRUE FALSE  TRUE FALSE

‘==’ Checks if each element of the first vector is equal to the corresponding element of the second vector.

v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v == t)
[1] FALSE FALSE FALSE  TRUE

‘<=’ Checks if each element of the first vector is less than or equal to the corresponding element of the second vector.

v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v<=t)
[1]  TRUE FALSE  TRUE  TRUE

‘>=’ Checks if each element of the first vector is greater than or equal to the corresponding element of the second vector.

v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v>=t)
[1] FALSE  TRUE FALSE  TRUE

‘!=’ Checks if each element of the first vector is unequal to the corresponding element of the second vector. Live Demo

v <- c(2,5.5,6,9)
t <- c(8,2.5,14,9)
print(v!=t)
[1]  TRUE  TRUE  TRUE FALSE

Objective 3: Loops and Functions

Loops

Many times we are interested in repeating some calculations. In R, there are many methods to do this, including the use of loops.

K1 <- c(4,2,8,5)
L1 <- c(1,3,4,2)
M1 <- 0*1:4  # This in the object where we will place the answer to our query
M1

This loop finds the maximum of K1 and L1 at each position

for (j in 1:4){
  M1[j] <- max(K1[j],L1[j])
}

M1

if else

general form : ifelse(test_expression, x, y)

Here, test_expression must be a logical vector (or an object that can be coerced to logical). The return value is a vector with the same length as test_expression.

This returned vector has element from x if the corresponding value of test_expression is TRUE or from y if the corresponding value of test_expression is FALSE.

x <- c("what","is","truth")
if("Truth" %in% x) {
   print("Truth is found")
} else {
   print("Truth is not found")
}
[1] "Truth is not found"

Functions

In programming, you use functions to incorporate sets of instructions that you want to use repeatedly or that, because of their complexity, are better self-contained in a sub program and called when needed. A function is a piece of code written to carry out a specified task; it can or can not accept arguments or parameters and it can or can not return one or more values.

General

The absolute value of “x”

abs(x)

A generic function which combines its arguments

c(x) 

Combine vectors by row/column (cf. “paste” in Unix)

cbind()  

Returns suitably lagged and iterated differences

diff(x)  

Pattern matching

grep()  

Test if 2 objects are exactly equal

identical() 

Add a small amount of noise to a numeric vector

jitter()

Return no. of elements in vector x

length(x) 

List objects in current environment

ls()  

Concatenate vectors after converting to character

paste(x) 

Returns the minimum and maximum of x

range(x) 

Repeat the number 1 five times

rep(1,5) 

List the elements of “x” in reverse order

rev(x)

Generate a sequence (1 -> 10, spaced by 0.4)

seq(1,10,0.4) 

Create a vector of sequences

sequence() 

Returns the signs of the elements of x

sign(x) 

Sort the vector x

sort(x) 

list sorted element numbers of x

order(x)

Convert string to lower/upper case letters

tolower()
toupper()

unique(x) # Remove duplicate entries from vector

unique(x) 

rounding functions

trunc(x) 
round(x)

Return system date

Sys.Date() 

Return working directory

getwd() 

Set working directory

setwd()

User defined functions

The different parts of a function are :

  • Function Name − This is the actual name of the function. It is stored in R environment as an object with this name.

  • Arguments − An argument is a placeholder. When a function is invoked, you pass a value to the argument. Arguments are optional; that is, a function may contain no arguments. Also arguments can have default values.

  • Function Body − The function body contains a collection of statements that defines what the function does.

  • Return Value − The return value of a function is the last expression in the function body to be evaluated.

new.function <- function(a, b) {
   print(a^2)
   print(a)
   print(b)
}
new.function(2,4)
[1] 4
[1] 2
[1] 4

Objective 4: Load files and Check Your Data

Load the data

R has a function dedicated to reading comma-separated files. To import a local CSV file named filename.txt and store the data into one R variable named mydata, the syntax would be

mydata = read.csv("~/Documents/Course/Yield_Winterschool.csv")  # read csv file 

If your data use another character to separate the fields, not a comma, R also has the more general read.table function. So if your separator is a tab, for instance, this would work:

mydata <- read.table("~/Documents/Course/Yield_Winterschool.csv", sep="\t", header=TRUE) # but it is not the case here!

There is often more than one way to read data into R. Even a simple .csv file can be imported using a range of methods, with implications for computational efficiency. This section looks at three approaches: base R’s reading functions such as read.csv, which are derived from read.table; the data.table approach, which uses the function fread; and the new readr package which provides read_csv and other read_ functions such as read_tsv.

mydata <- fread("~/Documents/Course/Yield_Winterschool.csv", header=TRUE)
Efficiency of packages to load files

Efficiency of packages to load files

The data import features can be accessed from the environment pane or from the tools menu. The importers are grouped into 3 categories: Text data, Excel data and statistical data. To access this feature, use the “Import Dataset” dropdown from the “Environment” pane:

R studio load

R studio load

Check the data

You can invoke the viewer in a console by calling the View function on the data frame you want to look at. For instance, to view the built-in iris dataset, run these commands:

View(mydata)

Useful Functions for Exploring Data Frames
Use dim() to obtain the dimensions of the data frame (number of rows and number of columns). The output is a vector.

 dim(mydata)

Use nrow() and ncol() to get the number of rows and number of columns, respectively. You can get the same information by extracting the first and second element of the output vector from dim().

nrow(mydata) 
# same as dim(InsectSprays)[1]

 ncol(mydata)
# same as dim(InsectSprays)[2]

Use head() to obtain the first n observations and tail() to obtain the last n observations; by default, n = 6. These are good commands for obtaining an intuitive idea of what the data look like without revealing the entire data set, which could have millions of rows and thousands of columns.

head(mydata, n = 5)

For example, the following command will return the last 10 observations.

tail(mydata, n = 5)

The names() function will return the column headers.

names(mydata)

The str() function returns many useful pieces of information, including the above useful outputs and the types of data for each column. In this example, “num” denotes that the variable “count” is numeric (continuous), and “Factor” denotes that the variable “spray” is categorical with 6 categories or levels.

str(mydata)

To obtain all of the categories or levels of a categorical variable, use the levels() function.

mydata$departement<-as.factor(mydata$departement)
levels(mydata$departement)

When applied to a data frame, the summary() function is essentially applied to each column, and the results for all columns are shown together.
For a continuous (numeric) variable like “yield”, it returns the 5-number summary. If there are any missing values (denoted by “NA” for a particular datum), it would also provide a count for them. In this example, there are no missing values for “count”, so there is no display for the number of NA’s. For a categorical variable like “departement”, it returns the levels and the number of data in each level.

summary(mydata)

Create new variables

Use the assignment operator <- to create new variables. A wide array of operators and functions are available here.

mydata$sum <- mydata$Tmean_1 + mydata$Tmean_2
mydata$mean <- (mydata$Tmean_1 + mydata$Tmean_2)/2

We can also delete the variable by using command NULL:

mydata$sum <- NULL
mydata$mean <- NULL

Objective 5: Selection of data and basics plots

Data Selection

you can select data:

mysubset<- mydata[departement=="AIN"]
# is equivalent to
mysubset<- subset(mydata,departement=="AIN")
# is equivalent to
#install.packages("dplyr")
library(dplyr)
mysubset <- mysubset %>% filter(departement=="AIN")
                  

The following is an introduction for producing simple graphs with the R Programming Language.

linecharts

Graph the yield vector with all defaults

plot(mysubset$yield)

Let’s add a title, a line to connect the points, and some color:

# Graph cars using blue points overlayed by a line 
plot(mysubset$yield,type="o", col="blue")
# Create a title with a red, bold/italic font
title(main="Yield", col.main="red", font.main=4)

Now let’s add a red line for an other department and specify the y-axis range directly so it will be large enough to fit all the data:

# Graph cars using a y axis that ranges from 0 to 12
plot(mysubset$yield, type="o", col="blue", ylim=c(0,12))
# Graph trucks with red dashed line and square points
lines(mydata[departement=="AISNE"]$yield, type="o", pch=22, lty=2, col="red")
# Create a title with a red, bold/italic font
title(main="Yield", col.main="red", font.main=4)

Next let’s change the axes labels to match our data and add a legend. We’ll also compute the y-axis values using the max function so any changes to our data will be automatically reflected in our graph.

# Calculate range from 0 to max value of cars and trucks
g_range <- range(0, mydata$yield)
# Graph autos using y axis that ranges from 0 to max 
# value in cars or trucks vector.  Turn off axes and 
# annotations (axis labels) so we can specify them ourself
plot(mysubset$year_harvest,mysubset$yield, type="o", col="blue", ylim=g_range,ann=FALSE)
# Graph trucks with red dashed line and square points
lines(mysubset$year_harvest,mydata[departement=="AISNE"]$yield, type="o", pch=22, lty=2, col="red")
# Create a title with a red, bold/italic font
title(main="Yield", col.main="red", font.main=4)
# Label the x and y axes with dark green text
title(xlab="years", col.lab=rgb(0,0.5,0))
title(ylab="YIELD", col.lab=rgb(0,0.5,0))
# Create a legend at (1, g_range[2]) that is slightly smaller 
# (cex) and uses the same line colors and points used by 
# the actual plots 
legend(1960, 1, c("AIN","AISNE"), cex=0.8, 
   col=c("blue","red"), pch=21:22, lty=1:2);

NA

barcharts

Let’s start with a simple bar chart graphing the yield vector:

Let’s now add labels, blue borders around the bars, and density lines:

 
barplot(mysubset2$yield, main="yield", xlab="years",  
   ylab="yields", names.arg=c("best_years","2001","2002","2003","2004","2005"), 
   border="blue", density=c(10,20,30,40,50, 60))

dotcharts

Let’s start with a simple dotchart graphing the autos data:

mysubset3<- mydata[year_harvest %in% c(2003:2005),]
mysubset3<- mysubset3[departement %in% c("AIN", "AISNE"),]
mysubset3<- mysubset3[,c("year_harvest","departement","yield")]
library("reshape")
mysubset3$year_harvest<-as.factor(mysubset3$year_harvest)
mysubset3<-cast(mysubset3, year_harvest ~ departement, mean, value = 'yield')
dotchart(t(mysubset3))

Let’s make the dotchart a little more colorful:

dotchart(t(mysubset3), color=c("red","blue","darkgreen"),
   main="yield", cex=0.8)

Objective 6: Linear regression

The function used for building linear models is lm(). The lm() function takes in two main arguments, namely: 1. Formula 2. Data. The data is typically a data.frame and the formula is a object of class formula. But the most common convention is to write out the formula directly in place of the argument as written below.

linearMod <- lm(yield ~ year_harvest, data=mysubset)  # build linear regression model on full data
print(linearMod)

Call:
lm(formula = yield ~ year_harvest, data = mysubset)

Coefficients:
 (Intercept)  year_harvest  
   -140.3625        0.0722  

plot the curve

mysubset$pred<- predict(linearMod)
plot(mysubset$year_harvest, mysubset$yield)
lines(mysubset$year_harvest,mysubset$pred)

References

There are many resources available on R. Here are some of them in open access, some of which have been widely used to produce this document:

LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIFIiCmF1dGhvcjogIkRhbWllbiBCZWlsbG91aW4iCmRhdGU6ICcyNi0wMS0yMDE5JwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICBodG1sX2RvY3VtZW50OgogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQogICAgdGhlbWU6IHNwYWNlbGFiCiAgICB0b2M6IHllcwphbHdheXNfYWxsb3dfaHRtbDogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KHJvb3QuZGlyID0gJy9Vc2Vycy9EYW1pZW5fQmVpbGxvdWluL0RvY3VtZW50cy9Db3Vyc2UvJykKYGBgCgojMS4gV2h5IHRvIHVzZSBSPwoKRnJlZSBhbmQgY3Jvc3MtcGxhdGZvcm0gPGJyLz4KUiBpcyBhIHByb2dyYW1taW5nIGxhbmd1YWdlIGFuZCBvcGVuIHNvdXJjZSBzb2Z0d2FyZSBkZWRpY2F0ZWQgdG8gc3RhdGlzdGljcyBhbmQgZGF0YSBzY2llbmNlIHN1cHBvcnRlZCBieSB0aGUgUiBGb3VuZGF0aW9uIGZvciBTdGF0aXN0aWNhbCBDb21wdXRpbmcuClIgaXMgY3Jvc3MtcGxhdGZvcm0gYW5kIGNhbiB0aGVyZWZvcmUgYmUgaW5zdGFsbGVkIG9uIFdpbmRvd3MsIE1hYyBPUyBvciBHTlUvTGludXguCgo8YnIvPjxici8+CgpQb2x5dmFsZW50IDxici8+ClIgYWxsb3dzIHlvdSB0byBtYW5pcHVsYXRlIGFsbCB0eXBlcyBvZiBvYmplY3RzLiBJdCBpcyBmb3Igb25lIG9mIHRoZXNlIHJlYXNvbnMgdGhhdCBpdCBjb21wZXRlcywgY29tcGxlbWVudHMgb3IgcmVwbGFjZXMgYSB3aG9sZSByYW5nZSBvZiBwcmUtZXhpc3Rpbmcgc29mdHdhcmUgYW5kIGxhbmd1YWdlcywgaW5jbHVkaW5nIGluIHZlcnkgc3BlY2lmaWMgZmllbGRzLCBmb3IgZXhhbXBsZTogdGV4dHVhbCBzdGF0aXN0aWNzLCBncmFwaCBhbmFseXNpcywgY2FydG9ncmFwaHksIHNwYXRpYWwgc3RhdGlzdGljcywgd2Vic2NyYXBpbmcsIGRvY3VtZW50IHByb2R1Y3Rpb24sIHdlYiBhcHBsaWNhdGlvbnMsIGV0Yy4gSXQgYWxzbyBjb21wZXRlcyB3aXRoIG90aGVyIGxhbmd1YWdlcyB3aWRlbHkgdXNlZCBmb3Igc2NpZW50aWZpYyBjYWxjdWxhdGlvbiBhbmQgZGF0YSBhbmFseXNpcywgaW4gcGFydGljdWxhciB3aXRoIFB5dGhvbi4KCjxici8+PGJyLz4KRXhwYW5kYWJsZTxici8+ClIgaXMgY29tcG9zZWQgb2YgYSBjb21tb24gYmFzZSByLWJhc2UgKHN0YW5kYXJkIHN0YXRpc3RpY2FsIGFuZCBncmFwaGljYWwgZnVuY3Rpb25zLCBjYWxsZWQgcHJpbWl0aXZlIGZ1bmN0aW9ucykgb24gd2hpY2ggaXMgZ3JhZnRlZCBhIHNldCBvZiBleHRlbnNpb25zIGNhbGxlZCBwYWNrYWdlcy4gQSBwYWNrYWdlIGlzIGEgbGlicmFyeSBvZiBmdW5jdGlvbnMgaW1wbGVtZW50ZWQgYnkgdXNlcnMgYW5kIG1hZGUgYXZhaWxhYmxlIHRvIGFsbCB0aHJvdWdoIHJlcG9zaXRvcmllcyBncm91cGVkIHVuZGVyIHRoZSBDb21wcmVoZW5zaXZlIFIgQXJjaGl2ZSBOZXR3b3JrIChDUkFOKS4gVGhpcyBtb2R1bGFyIHN0cnVjdHVyZSBleHBsYWlucyB0aGUgd2lkZSByYW5nZSBvZiBwb3NzaWJsZSBhcHBsaWNhdGlvbnM6IHRoZSBleHBhbnNpb24gb2YgdGhlIHNvZnR3YXJlIGlzIG9ubHkgbGltaXRlZCBieSB0aGUgd29yayB0aGF0IHVzZXJzIHdvcmxkd2lkZSBtYWtlIGF2YWlsYWJsZSB0byBhbGwgb3RoZXIgdXNlcnMgKDEyODA5IHBhY2thZ2VzIGFyZSBvbiBDUkFOIGFzIG9mIEp1bHkgMzAsIDIwMTgpLgoKPGJyLz48YnIvPgpSZXByb2R1Y2libGU8YnIvPgpUaGUgZW50aXJlIHByb2Nlc3NpbmcgY2hhaW4gY2FuIHRodXMgYmUgY2FycmllZCBvdXQgdW5kZXIgUi4gVGhpcyBpbnRlZ3JhdGVkIHdvcmtmbG93IGlzIG1vcmUgZWZmaWNpZW50IGFuZCBzZWN1cmU6IG5vIG1vcmUgaW1wb3J0cyBhbmQgZXhwb3J0cyBmcm9tIG9uZSBzb2Z0d2FyZSBwYWNrYWdlIHRvIGFub3RoZXIsIGFuZCB0aGUgYXJjaGl2aW5nLCBkaXNzZW1pbmF0aW9uIGFuZCByZXByb2R1Y2liaWxpdHkgb2YgdGhlIGludGVncml0eSBvZiBpdHMgd29yayBhbmQgbWV0aG9kb2xvZ3kgYXJlIGVuc3VyZWQuCgoKIyAyLiBBIGxpdHRsZSBoaXN0b3J5IG9mIFIKPGJyLz4KTGV0J3Mgc3RhcnQgYnkgcmVjYWxsaW5nIHNvbWUgaW1wb3J0YW50IHBvaW50cyBpbiBSJ3MgaGlzdG9yeS4KCjxici8+ClIgd2FzIGZvdW5kZWQgaW4gdGhlIGVhcmx5IDE5OTBzIGluIE5ldyBaZWFsYW5kIGFuZCBoYXMgYmVlbiBncm93aW5nIGV2ZXIgc2luY2UuIFNpbmNlIDE5OTcsIGEgZ3JvdXAgb2YgcmVzZWFyY2hlcnMgY2FsbGVkICJSIENvcmUgVGVhbSIgY29tcG9zZWQgdG9kYXkgb2YgMjAgcGVvcGxlIGhhcyB0aGUgYXV0aG9yaXphdGlvbiB0byBtb2RpZnkgdGhlIHNvdXJjZSBjb2RlIG9mIFIuIE9mIGNvdXJzZSBhbnlvbmUgY2FuIHN1Ym1pdCBwYWNrYWdlcyBidXQgdGhlIGNvcmUgb2YgdGhlIHNvZnR3YXJlIGlzIG1hbmFnZWQgYnkgdGhlc2UgMjAgcGVvcGxlLiBUd28gb3RoZXIgc3RydWN0dXJlcyBhcmUgaW1wb3J0YW50IGZvciBSLCB0aGUgUiBmb3VuZGF0aW9uIGFuZCB0aGUgQ1JBTi4KPGJyLz48YnIvPgpUSEUgUiBGT1VOREFUSU9OIDxici8+Ckl0IGlzIGEgbm9uLXByb2ZpdCBvcmdhbml6YXRpb24gY3JlYXRlZCBieSB0aGUgUiBDb3JlIFRlYW0gdG8gcHJvdmlkZSBzdXBwb3J0IGZvciB0aGUgZGV2ZWxvcG1lbnQgb2YgdGhlIFIgcHJvamVjdC4gSXQgc2VydmVzIGFzIGFuIGludGVybG9jdXRvciBmb3IgdGhvc2Ugd2hvIHdvdWxkIGxpa2UgdG8gc3VwcG9ydCBvciBpbnRlcmFjdCB3aXRoIHRoZSBSIHNvZnR3YXJlIGRldmVsb3BlciBjb21tdW5pdHkuIFRoaXMgZm91bmRhdGlvbiBvd25zIGFuZCBhZG1pbmlzdGVycyB0aGUgY29weXJpZ2h0IG9mIHRoZSBSIHNvZnR3YXJlIGFuZCByZWxhdGVkIGRvY3VtZW50YXRpb24uPGJyLz4KVEhFIENSQU48YnIvPgpJdCBpcyB0aGUgIkNvbXByZWhlbnNpdmUgUiBBcmNoaXZlIE5ldHdvcmsiLCBhIG5ldHdvcmsgb2Ygd2ViIHNlcnZlcnMgaG9zdGVkIGluIGRpZmZlcmVudCBsb2NhdGlvbnMgYXJvdW5kIHRoZSB3b3JsZCB0aGF0IHN0b3JlcyBSJ3MgY29kZSBhbmQgZG9jdW1lbnRhdGlvbiBpbiBvcmRlciB0byBtYWtlIFIgcXVpY2tseSBhY2Nlc3NpYmxlIGZyb20gYW55d2hlcmUgaW4gdGhlIHdvcmxkLiBJdCBpcyBhbHNvIHRoZSBwbGFjZSB3aGVyZSBuZXcgcGFja2FnZXMgYXJlIHN1Ym1pdHRlZCB0byBiZSBtYWRlIGF2YWlsYWJsZSB0byBSIHVzZXJzLgoKPGJyLz4KCiMgMy4gTGVhcm4gdG8gdXNlIFIKCiMjIE9iamVjdGl2ZSAxOiBNYXN0ZXIgeW91ciB3b3JrIGVudmlyb25tZW50CgojIyMgR2VuZXJhbCBmZWF0dXJlcyBvZiBSIHN0dWRpbwoKUnN0dWRpbydzIGludGVyZmFjZSBpcyBkaXZpZGVkIGludG8gNCBncmFwaGljIHdpbmRvd3M6CiogT25lIGFyZWEgYWxsb3dzIHRoZSBlZGl0aW5nIG9mIFIgc291cmNlIGZpbGVzICh3aXRoIHN5bnRheCBoaWdobGlnaHRpbmcgYW5kIGF1dG9jb21wbGV0aW9uIG9mIGZ1bmN0aW9uIGFuZCBvYmplY3QgbmFtZXMgd2l0aCB0aGUgdGFiIGtleSkuPGJyLz4KCiogQW4gb3RoZXIgYXJlYSBkaXNwbGF5cyB0aGUgY29uc29sZSB3aXRoIHRoZSBjdXJyZW50IFIgc2Vzc2lvbiBydW5uaW5nLiBVc2luZyB0aGUgc2hvcnRjdXQgQ3RybCtFbnRlciBhbGxvd3MgeW91IHRvIGV4ZWN1dGUgYSBsaW5lIG9yIHNlbGVjdGlvbiBkaXJlY3RseSBmcm9tIHRoZSBzb3VyY2UgZmlsZS48YnIvPgoKKiBBIHRoaXJkIGFyZWEgYWxsb3dzIHlvdSB0byBzd2l0Y2ggYmV0d2VlbiBkaXNwbGF5aW5nIHRoZSBvYmplY3RzIGluIHRoZSBjdXJyZW50IHdvcmtzcGFjZSBhbmQgdGhlIGhpc3Rvcnkgb2YgdGhlIGNvbW1hbmRzIGV4ZWN1dGVkLiBZb3UgY2FuIGV2ZW4gdmlzdWFsbHkgaW5zcGVjdCB0aGUgY29udGVudHMgb2Ygc29tZSBvYmplY3RzLiA8YnIvPgogCiogRmluYWxseSwgYSBmb3VydGggem9uZSBhbGxvd3MgeW91IHRvIHN3aXRjaCBiZXR3ZWVuOjxici8+Ci1hIGZpbGUgYnJvd3NlciA8YnIvPgotdGhlIGdyYXBocyBkaXNwbGF5IGFuZCBleHBvcnQgd2luZG93PGJyLz4KLWEgbGlzdCBvZiBpbnN0YWxsZWQgZXh0ZW5zaW9ucywgd2hpY2ggYWxsb3dzIHlvdSB0byBsb2FkIHRoZW0gaW50byBtZW1vcnkgb3IgaW5zdGFsbCBuZXcgb25lcyB2ZXJ5IGVhc2lseTxici8+Ci1hIGhlbHAgYnJvd3NlciB0aGF0IGFsbG93cyBib3RoIG5hdmlnYXRpb24gaW4gdGhlIG9ubGluZSBoZWxwIGludGVncmF0ZWQgaW4gUiBhbmQgdGhlIGRpc3BsYXkgb2YgdGhlIGhlbHAgcGFnZXMgZm9yIHRoZSB2YXJpb3VzIGZ1bmN0aW9uczxici8+Cgo8YnIvPgoKCiFbUiBzdHVkaW9dKGh0dHA6Ly9xdWFudGkuaHlwb3RoZXNlcy5vcmcvZmlsZXMvMjAxMS8wMy93cGlkLTIwMTEwMzA3X3JzdHVkaW8xLnBuZykKCgojIyMgIFRoZSB3b3JraW5nIGRpcmVjdG9yeSBhbmQgUHJvamVjdHMgaW4gUlN0dWRpbwoKIyMjIyBXb3JraW5nIGRpcmVjdG9yeQpFYWNoIHRpbWUgUiBpcyBhc2tlZCB0byBsb2FkIG9yIHNhdmUgYSBmaWxlIChlc3BlY2lhbGx5IHdoZW4gdHJ5aW5nIHRvIGltcG9ydCBkYXRhKSwgUiB3aWxsIGV2YWx1YXRlIHRoZSBuYW1lIG9mIHRoZSBmaWxlIHNlbnQgdG8gaXQgYWdhaW5zdCB0aGUgY3VycmVudGx5IGRlZmluZWQgd29ya2luZyBkaXJlY3RvcnksIHdoaWNoIGNvcnJlc3BvbmRzIHRvIHRoZSBkaXJlY3RvcnkgaW4gd2hpY2ggUiBpcyBjdXJyZW50bHkgcnVubmluZy4KClRvIGtub3cgdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnksIHdlIGNhbiB1c2UgdGhlIGdldHdkIGZ1bmN0aW9uIDoKCmBgYApnZXR3ZCgpCmBgYApUbyBkZWZpbmUgdGhlIHdvcmtpbmcgZGlyZWN0b3J5OgpgYGAKc2V0d2QoKQpgYGAKIyMjI1Byb2plY3RzClJTdHVkaW8gaGFzIGEgdmVyeSBwcmFjdGljYWwgZmVhdHVyZSB0byBvcmdhbml6ZSBpdHMgd29yayBpbnRvIGRpZmZlcmVudCBwcm9qZWN0cy4KClRoZSBtYWluIGlkZWEgaXMgdG8gZ2F0aGVyIGFsbCB0aGUgZmlsZXMgLyBkb2N1bWVudHMgcmVsYXRlZCB0byB0aGUgc2FtZSBwcm9qZWN0IChkYXRhLCBzY3JpcHRzLCBhdXRvbWF0ZWQgcmVwb3J0cy4uLikgaW4gYSBkZWRpY2F0ZWQgZGlyZWN0b3J5LgoKIFlvdSBjYW4gY3JlYXRlIGFuIFJTdHVkaW8gcHJvamVjdDoKCiogSW4gYSBicmFuZCBuZXcgZGlyZWN0b3J5CiogSW4gYW4gZXhpc3RpbmcgZGlyZWN0b3J5IHdoZXJlIHlvdSBhbHJlYWR5IGhhdmUgUiBjb2RlIGFuZCBkYXRhCiogQnkgY2xvbmluZyBhIHZlcnNpb24gY29udHJvbCAoR2l0IG9yIFN1YnZlcnNpb24pIHJlcG9zaXRvcnkKCldoZW4gYSBwcm9qZWN0IGlzIG9wZW5lZCB3aXRoaW4gUlN0dWRpbyB0aGUgZm9sbG93aW5nIGFjdGlvbnMgYXJlIHRha2VuOgoKQSBuZXcgUiBzZXNzaW9uIChwcm9jZXNzKSBpcyBzdGFydGVkOjxici8+CiogVGhlIC5ScHJvZmlsZSBmaWxlIGluIHRoZSBwcm9qZWN0J3MgbWFpbiBkaXJlY3RvcnkgKGlmIGFueSkgaXMgc291cmNlZCBieSBSPGJyLz4KKiBUaGUgLlJEYXRhIGZpbGUgaW4gdGhlIHByb2plY3QncyBtYWluIGRpcmVjdG9yeSBpcyBsb2FkZWQgKGlmIHByb2plY3Qgb3B0aW9ucyBpbmRpY2F0ZSB0aGF0IGl0IHNob3VsZCBiZSBsb2FkZWQpLjxici8+CiogVGhlIC5SaGlzdG9yeSBmaWxlIGluIHRoZSBwcm9qZWN0J3MgbWFpbiBkaXJlY3RvcnkgaXMgbG9hZGVkIGludG8gdGhlIFJTdHVkaW8gSGlzdG9yeSBwYW5lIChhbmQgdXNlZCBmb3IgQ29uc29sZSBVcC9Eb3duIGFycm93IGNvbW1hbmQgaGlzdG9yeSkuPGJyLz4KKiBUaGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSBpcyBzZXQgdG8gdGhlIHByb2plY3QgZGlyZWN0b3J5Ljxici8+CiogUHJldmlvdXNseSBlZGl0ZWQgc291cmNlIGRvY3VtZW50cyBhcmUgcmVzdG9yZWQgaW50byBlZGl0b3IgdGFiczxici8+CiogT3RoZXIgUlN0dWRpbyBzZXR0aW5ncyAoZS5nLiBhY3RpdmUgdGFicywgc3BsaXR0ZXIgcG9zaXRpb25zLCBldGMuKSBhcmUgcmVzdG9yZWQgdG8gd2hlcmUgdGhleSB3ZXJlIHRoZSBsYXN0IHRpbWUgdGhlIHByb2plY3Qgd2FzIGNsb3NlZC48YnIvPgoKCiMjIyBIZWxwIGluIFIKClRoZSBoZWxwKG1hX2Z1bmN0aW9uKSBjb21tYW5kIHdoZXJlID9tYV9mdW5jdGlvbiBhbGxvd3MgeW91IHRvIGFjY2VzcyB1c2luZyB0aGUgbWFfZnVuY3Rpb24gZnVuY3Rpb24gLiBUaGUgaGVscCBwYWdlIGF1dG9tYXRpY2FsbHkgYXBwZWFycyBpbiB0aGUgSGVscCB0YWIsIGF0IHRoZSBib3R0b20gcmlnaHQgb2YgdGhlIFJTdHVkaW8gaW50ZXJmYWNlLiBUaGVyZSBhcmU6CgoqIHRoZSBkZXNjcmlwdGlvbiBvZiB0aGUgZnVuY3Rpb24sCiogaXRzIGFyZ3VtZW50cyAobWFuZGF0b3J5IGFuZCBvcHRpb25hbCksCiogcmVmZXJlbmNlcywKKiBleGFtcGxlcyBvZiBob3cgdG8gYXBwbHkgdGhlIGZ1bmN0aW9uLgoKRXhhbXBsZSA6CkV4ZWN1dGluZyB0aGUgZm9sbG93aW5nIGNvbW1hbmQgdGFrZXMgeW91IHRvIHRoZSBoZWxwIHBhZ2Ugb2YgdGhlIGxvZygpIGZ1bmN0aW9uOgoKYGBgCmhlbHAobG9nKQpgYGAKCiMjIyBJbnN0YWxsYXRpb24gb2YgcGFja2FnZXMKQW4gUiBwYWNrYWdlIGlzIGEgbGlicmFyeSBvZiBmdW5jdGlvbnMgdGhhdCBwZXJmb3JtIHBhcnRpY3VsYXIgb3BlcmF0aW9ucy4gVG8gdXNlIGEgcGFja2FnZSwgaXQgbXVzdCBoYXZlIGJlZW4gcHJldmlvdXNseSBpbnN0YWxsZWQgYW5kIGxvYWRlZC4gRHVyaW5nIHRoZSBpbnN0YWxsYXRpb24gb2YgUiwgYSBudW1iZXIgb2YgcGFja2FnZXMgYXJlIHByZS1pbnN0YWxsZWQuIFdoZW4gUlN0dWRpbyBpcyBsYXVuY2hlZCwgc29tZSBvZiB0aGVzZSBwYWNrYWdlcyBhcmUgbG9hZGVkIGJ5IGRlZmF1bHQuIFRoaXMgaXMgdGhlIGNhc2UsIGZvciBleGFtcGxlLCBvZiB0aGUgc3RhdHMgcGFja2FnZS4KCkl0IGlzIHBvc3NpYmxlIHRvIHZpZXcgdGhlIGxpc3Qgb2YgcGFja2FnZXMgYWxyZWFkeSBpbnN0YWxsZWQgb24geW91ciBjb21wdXRlciB2aWEgdGhlIFJTdHVkaW8gUGFja2FnZXMgdGFiLgoKV2hlbiBpdCBpcyBuZWNlc3NhcnkgdG8gdXNlIGEgbm9uIHByZS1pbnN0YWxsZWQgcGFja2FnZSwgaXQgaXMgcG9zc2libGUgdG8gaW5zdGFsbCBpdCBtYW51YWxseSB2aWEgdGhlIE1lbnUgVG9vbHPihpJJbnN0YWxsIFBhY2thZ2VzLiBPbmNlIHRoZSBwYWNrYWdlIGlzIGluc3RhbGxlZCwgaXQgaXMgbG9hZGVkIGJ5IHRoZSBsaWJyYXJ5KCkgaW5zdHJ1Y3Rpb24uCgojIyMgT3JnYW5pemUgeW91ciBzY3JpcHQgCgoqIEtlZXAgdHJhY2sgb2Ygd2hvIHdyb3RlIHlvdXIgY29kZSBhbmQgaXRzIGludGVuZGVkIHB1cnBvc2UgICA8YnIvPgoKU3RhcnRpbmcgeW91ciBjb2RlIHdpdGggYW4gYW5ub3RhdGVkIGRlc2NyaXB0aW9uIG9mIHdoYXQgdGhlIGNvZGUgZG9lcyB3aGVuIGl0IGlzIHJ1biB3aWxsIGhlbHAgeW91IHdoZW4geW91IGhhdmUgdG8gbG9vayBhdCBvciBjaGFuZ2UgaXQgaW4gdGhlIGZ1dHVyZS4gSnVzdCBvbmUgb3IgdHdvIGxpbmVzIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIGZpbGUgY2FuIHNhdmUgeW91IG9yIHNvbWVvbmUgZWxzZSBhIGxvdCBvZiB0aW1lIGFuZCBlZmZvcnQgd2hlbiB0cnlpbmcgdG8gdW5kZXJzdGFuZCB3aGF0IGEgcGFydGljdWxhciBzY3JpcHQgZG9lcy4KCmBgYAojIGl0J3MgYSB3b25kZXJmdWwgc2NyaXB0IHRoYXQgd2lsbCB0YWtlIHlvdSB0byBvdGhlciB3b3JsZHMKIyBMIC4gTG9zcGluICYgSi5DCiMgMTggYnJ1bWFpcmUgZGUgbCdhbiAyMDUKYGBgCgoqIEJlIGV4cGxpY2l0IGFib3V0IHRoZSByZXF1aXJlbWVudHMgYW5kIGRlcGVuZGVuY2llcyBvZiB5b3VyIGNvZGUKTG9hZGluZyBhbGwgb2YgdGhlIHBhY2thZ2VzIHRoYXQgd2lsbCBiZSBuZWNlc3NhcnkgdG8gcnVuIHlvdXIgY29kZSAodXNpbmcgbGlicmFyeSkgaXMgYSBuaWNlIHdheSBvZiBpbmRpY2F0aW5nIHdoaWNoIHBhY2thZ2VzIGFyZSBuZWNlc3NhcnkgdG8gcnVuIHlvdXIgY29kZS4gSXQgY2FuIGJlIGZydXN0cmF0aW5nIHRvIG1ha2UgaXQgdHdvLXRoaXJkcyBvZiB0aGUgd2F5IHRocm91Z2ggYSBsb25nLXJ1bm5pbmcgc2NyaXB0IG9ubHkgdG8gZmluZCBvdXQgdGhhdCBhIGRlcGVuZGVuY3kgaGFzbuKAmXQgYmVlbiBpbnN0YWxsZWQuCgoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShyZXNoYXBlKQoKIyBPUgp4PC1jKCJkYXRhLnRhYmxlIiwidGlkeXZlcnNlIiwibWFncml0dHIiKQpsYXBwbHkoeCwgcmVxdWlyZSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQpgYGAKCiogQW5vdGhlciB3YXkgeW91IGNhbiBiZSBleHBsaWNpdCBhYm91dCB0aGUgcmVxdWlyZW1lbnRzIG9mIHlvdXIgY29kZSBhbmQgaW1wcm92ZSBpdOKAmXMgcmVwcm9kdWNpYmlsaXR5IGlzIHRvIGxpbWl0IHRoZSDigJxoYXJkLWNvZGluZ+KAnSBvZiB0aGUgaW5wdXQgYW5kIG91dHB1dCBmaWxlcyBmb3IgeW91ciBzY3JpcHQuIElmIHlvdXIgY29kZSB3aWxsIHJlYWQgaW4gZGF0YSBmcm9tIGEgZmlsZSwgZGVmaW5lIGEgdmFyaWFibGUgZWFybHkgaW4geW91ciBjb2RlIHRoYXQgc3RvcmVzIHRoZSBwYXRoIHRvIHRoYXQgZmlsZS4gRm9yIGV4YW1wbGUKCmBgYAppbnB1dF9maWxlIDwtICJkYXRhL2RhdGEuY3N2IiAKb3V0cHV0X2ZpbGUgPC0gImRhdGEvcmVzdWx0cy5jc3YiCgojIHJlYWQgaW5wdXQKaW5wdXRfZGF0YSA8LSByZWFkLmNzdihpbnB1dF9maWxlKQojIGdldCBudW1iZXIgb2Ygc2FtcGxlcyBpbiBkYXRhCnNhbXBsZV9udW1iZXIgPC0gbnJvdyhpbnB1dF9kYXRhKQojIGdlbmVyYXRlIHJlc3VsdHMKcmVzdWx0cyA8LSBzb21lX290aGVyX2Z1bmN0aW9uKGlucHV0X2ZpbGUsIHNhbXBsZV9udW1iZXIpCiMgd3JpdGUgcmVzdWx0cwp3cml0ZS50YWJsZShyZXN1bHRzLCByZXN1bHRzX2ZpbGUpCmBgYAogPGJyLz4KaXMgcHJlZmVyYWJsZSB0bzoKIDxici8+CiAKYGBgCiMgY2hlY2sKaW5wdXRfZGF0YSA8LSByZWFkLmNzdigibW9uT3JkaS9tZXMgZmljaGllcnMvZGF0YS9kYXRhLmNzdiIpCiMgZ2V0IG51bWJlciBvZiBzYW1wbGVzIGluIGRhdGEKc2FtcGxlX251bWJlciA8LSBucm93KGlucHV0X2RhdGEpCiMgZ2VuZXJhdGUgcmVzdWx0cwpyZXN1bHRzIDwtIHNvbWVfb3RoZXJfZnVuY3Rpb24oIm1vbk9yZGkvbWVzIGZpY2hpZXJzL2RhdGEvZGF0YS5jc3YiLCBzYW1wbGVfbnVtYmVyKQojIHdyaXRlIHJlc3VsdHMKd3JpdGUudGFibGUoImRhdGEvcmVzdWx0cy5jc3YiLCByZXN1bHRzX2ZpbGUpCmBgYAoKKiBJZGVudGlmeSBhbmQgc2VncmVnYXRlIGRpc3RpbmN0IGNvbXBvbmVudHMgaW4geW91ciBjb2RlICA8YnIvPgpJdOKAmXMgZWFzeSB0byBhbm5vdGF0ZSBhbmQgbWFyayB5b3VyIGNvZGUgdXNpbmcgIyBvciAjLSB0byBzZXQgb2ZmIHNlY3Rpb25zIG9mIHlvdXIgY29kZSBhbmQgdG8gbWFrZSBmaW5kaW5nIHNwZWNpZmljIHBhcnRzIG9mIHlvdXIgY29kZSBlYXNpZXIuIEZvciBleGFtcGxlLCBpdOKAmXMgb2Z0ZW4gaGVscGZ1bCB3aGVuIHdyaXRpbmcgY29kZSB0byBzZXBhcmF0ZSB0aGUgZnVuY3Rpb24gZGVmaW5pdGlvbnMuIElmIHlvdSBjcmVhdGUgb25seSBvbmUgb3IgYSBmZXcgY3VzdG9tIGZ1bmN0aW9ucyBpbiB5b3VyIHNjcmlwdCwgcHV0IHRoZW0gdG93YXJkIHRoZSB0b3Agb2YgeW91ciBjb2RlLiBJZiB5b3UgaGF2ZSB3cml0dGVuIG1hbnkgZnVuY3Rpb25zLCBwdXQgdGhlbSBhbGwgaW4gdGhlaXIgb3duIC5SIGZpbGUgYW5kIHRoZW4gc291cmNlIHRob3NlIGZpbGVzLiBzb3VyY2Ugd2lsbCBkZWZpbmUgYWxsIG9mIHRoZXNlIGZ1bmN0aW9ucyBzbyB0aGF0IHlvdXIgY29kZSBjYW4gbWFrZSB1c2Ugb2YgdGhlbSBhcyBuZWVkZWQuCgogCmBgYApzb3VyY2UoIm15X2dlbml1c19meG5zLlIiKQpgYGAKCk90aGVyIGlkZWFzOiAKKiBVc2UgYSBjb25zaXN0ZW50IHN0eWxlIHdpdGhpbiB5b3VyIGNvZGUuIEZvciBleGFtcGxlLCBuYW1lIGFsbCBtYXRyaWNlcyBzb21ldGhpbmcgZW5kaW5nIGluIF9tYXQuIENvbnNpc3RlbmN5IG1ha2VzIGNvZGUgZWFzaWVyIHRvIHJlYWQgYW5kIHByb2JsZW1zIGVhc2llciB0byBzcG90LgoKKiBLZWVwIHlvdXIgY29kZSBpbiBiaXRlLXNpemVkIGNodW5rcy4gSWYgYSBzaW5nbGUgZnVuY3Rpb24gb3IgbG9vcCBnZXRzIHRvbyBsb25nLCBjb25zaWRlciBsb29raW5nIGZvciB3YXlzIHRvIGJyZWFrIGl0IGludG8gc21hbGxlciBwaWVjZXMuCgoqIERvbuKAmXQgcmVwZWF0IHlvdXJzZWxm4oCTYXV0b21hdGUhIElmIHlvdSBhcmUgcmVwZWF0aW5nIHRoZSBzYW1lIGNvZGUgb3ZlciBhbmQgb3ZlciwgdXNlIGEgbG9vcCBvciBhIGZ1bmN0aW9uIHRvIHJlcGVhdCB0aGF0IGNvZGUgZm9yIHlvdS4gTmVlZGxlc3MgcmVwZXRpdGlvbiBkb2VzbuKAmXQganVzdCB3YXN0ZSB0aW1l4oCTaXQgYWxzbyBpbmNyZWFzZXMgdGhlIGxpa2VsaWhvb2QgeW914oCZbGwgbWFrZSBhIGNvc3RseSBtaXN0YWtlIQoKKiBLZWVwIGFsbCBvZiB5b3VyIHNvdXJjZSBmaWxlcyBmb3IgYSBwcm9qZWN0IGluIHRoZSBzYW1lIGRpcmVjdG9yeSwgdGhlbiB1c2UgcmVsYXRpdmUgcGF0aHMgYXMgbmVjZXNzYXJ5IHRvIGFjY2VzcyB0aGVtLiBGb3IgZXhhbXBsZSwgdXNlCgpgYGAKZGF0IDwtIHJlYWQuY3N2KGZpbGUgPSAiZmlsZXMvZGF0YXNldC0yMDEzLTAxLmNzdiIsIGhlYWRlciA9IFRSVUUpCmBgYAoKcmF0aGVyIHRoYW46CgpgYGAKZGF0IDwtIHJlYWQuY3N2KGZpbGUgPSAiL1VzZXJzL0thcnRoaWsvRG9jdW1lbnRzL3Nhbm5pYy1wcm9qZWN0L2ZpbGVzL2RhdGFzZXQtMjAxMy0wMS5jc3YiLCBoZWFkZXIgPSBUUlVFKQpgYGAKCiMjIE9iamVjdGl2ZSAyOiAgIFRoZSBSIG9iamVjdHMKCiMjIyBHZW5lcmFsIGZlYXR1cmVzCkV2ZXJ5dGhpbmcgaW4gdGhlIFIgbGFuZ3VhZ2UgaXMgYW4gb2JqZWN0OiB2YXJpYWJsZXMgY29udGFpbmluZyBkYXRhLCBmdW5jdGlvbnMsIG9wZXJhdG9ycywgZXZlbiB0aGUgc3ltYm9sIHJlcHJlc2VudGluZyB0aGUgbmFtZSBvZiBhbiBvYmplY3QgaXMgaXRzZWxmIGFuIG9iamVjdC4gT2JqZWN0cyBoYXZlIGF0IGxlYXN0IG9uZSBtb2RlIGFuZCBvbmUgbGVuZ3RoIGFuZCBzb21lIG1heSBoYXZlIG9uZSBvciBtb3JlIGF0dHJpYnV0ZXMuCgpUaGUgbW9kZSBvZiBhbiBvYmplY3QgaXMgb2J0YWluZWQgd2l0aCB0aGUgbW9kZSBmdW5jdGlvbiA6CgpgYGAKIHYgPC0gYygxLCAyLCA1LCA5KQogbW9kZSh2KQpbMV0gIm51bWVyaWMiCmBgYAoKVGhlIGxlbmd0aCBvZiBhbiBvYmplY3QgaXMgb2J0YWluZWQgd2l0aCB0aGUgbGVuZ3RoIGZ1bmN0aW9uOgoKYGBgCj4gbGVuZ3RoKHYpClsxXSA0CmBgYAoKIyMjIE9iamVjdHMKCiMjIyNWZWN0b3JzCgpJbiBSLCBmb3IgYWxsIHByYWN0aWNhbCBwdXJwb3NlcywgZXZlcnl0aGluZyBpcyBhIHZlY3Rvci4gVGhlIHZlY3RvciBpcyB0aGUgYmFzaWMgdW5pdCBpbiB0aGUgY2FsY3VsYXRpb25zLgoKSW4gYSBzaW1wbGUgdmVjdG9yLCBhbGwgZWxlbWVudHMgbXVzdCBiZSBpbiB0aGUgc2FtZSBtb2RlLiBXZSByZXN0cmljdCBvdXJzZWx2ZXMgdG8gdGhpcyB0eXBlIG9mIHZlY3RvcnMgZm9yIHRoZSBtb21lbnQuClRoZSBiYXNpYyBmdW5jdGlvbnMgZm9yIGNyZWF0aW5nIHZlY3RvcnMgYXJlOgoKYyAoY29uY2F0ZW5hdGlvbikgOwpudW1lcmljIChudW1lcmljIG1vZGUgdmVjdG9yKSA7CmxvZ2ljYWwgKGxvZ2ljYWwgbW9kZSB2ZWN0b3IpIDsKY2hhcmFjdGVyIChjaGFyYWN0ZXIgbW9kZSB2ZWN0b3IpLgpJdCBpcyBwb3NzaWJsZSAoYW5kIG9mdGVuIGRlc2lyYWJsZSkgdG8gZ2l2ZSBhIGxhYmVsIHRvIGVhY2ggb2YgdGhlIGVsZW1lbnRzIG9mIGEgdmVjdG9yLgoKYGBge3J9CnYgPC0gYyhhID0gMSwgYiA9IDIsIGMgPSA1KQp2CnYgPC0gYygxLCAyLCA1KQpuYW1lcyh2KSA8LSBjKCJhIiwgImIiLCAiYyIpCnYKYGBgCgpUaGVzZSBsYWJlbHMgYXJlIHRoZW4gcGFydCBvZiB0aGUgYXR0cmlidXRlcyBvZiB0aGUgdmVjdG9yLgoKVGhlIGluZGljYXRpb24gaW4gYSB2ZWN0b3IgaXMgZG9uZSB3aXRoIHRoZSBicmFja2V0cyBbIF0uIEFuIGVsZW1lbnQgY2FuIGJlIGV4dHJhY3RlZCBmcm9tIGEgdmVjdG9yIGJ5IGl0cyBwb3NpdGlvbiBvciBsYWJlbCwgaWYgaXQgZXhpc3RzIChpbiB3aGljaCBjYXNlIHRoaXMgYXBwcm9hY2ggaXMgbXVjaCBzYWZlcikuCgpgYGAKdlszXQp2WyJjIl0KYGBgCgoKIyMjIyBNYXRyaWNlcyBhbmQgYXJyYXkKQXMgUiBpcyBhIHNwZWNpYWxpemVkIGxhbmd1YWdlIGZvciBtYXRoZW1hdGljYWwgY2FsY3VsYXRpb25zLCBpdCBuYXR1cmFsbHkgYW5kIGludHVpdGl2ZWx5IHN1cHBvcnRzIG1hdHJpY2VzIGFuZCwgbW9yZSBnZW5lcmFsbHksIG11bHRpZGltZW5zaW9uYWwgdGFibGVzLgoKQSBtYXRyaXggaXMgYSB2ZWN0b3Igd2l0aCBhIGRpbSBhdHRyaWJ1dGUgb2YgbGVuZ3RoIDIuIFRoaXMgaW1wbGljaXRseSBjaGFuZ2VzIHRoZSBvYmplY3QgY2xhc3MgdG8gIm1hdHJpeCIgYW5kLCBhcyBhIHJlc3VsdCwgdGhlIHdheSB0aGUgb2JqZWN0IGlzIGRpc3BsYXllZCBhbmQgaXRzIGludGVyYWN0aW9uIHdpdGggc2V2ZXJhbCBvcGVyYXRvcnMgYW5kIGZ1bmN0aW9ucy4KVGhlIGJhc2ljIGZ1bmN0aW9uIGZvciBjcmVhdGluZyBtYXRyaWNlcyBpcyBtYXRyaXggOgoKYGBgCm1hdHJpeCgxOjYsIG5yb3cgPSAyLCBuY29sID0gMykKbWF0cml4KDE6NiwgbnJvdyA9IDIsIG5jb2wgPSAzLCBieXJvdyA9IFRSVUUpCmBgYAoKVGhlIGdlbmVyYWxpemF0aW9uIG9mIGEgbWF0cml4IHRvIG1vcmUgdGhhbiB0d28gZGltZW5zaW9ucyBpcyBhbiBhcnJheS4gVGhlIG51bWJlciBvZiBkaW1lbnNpb25zIG9mIHRoZSBhcnJheSBpcyBhbHdheXMgZXF1YWwgdG8gdGhlIGxlbmd0aCBvZiB0aGUgZGltIGF0dHJpYnV0ZSwgdGhlIGltcGxpY2l0IGNsYXNzIG9mIGFuIGFycmF5IGlzICJhcnJheSIuCgpUaGUgYmFzaWMgZnVuY3Rpb24gdG8gY3JlYXRlIGFycmF5cyBpcyBhcnJheToKCmBgYAphcnJheSgxOjI0LCBkaW0gPSBjKDMsIDQsIDIpKQpgYGAKCiMjIyMgTGlzdHMKVGhlIGxpc3QgaXMgdGhlIG1vc3QgZ2VuZXJhbCBhbmQgdmVyc2F0aWxlIHN0b3JhZ2UgbW9kZSBvZiB0aGUgUiBsYW5ndWFnZS4gSXQgaXMgYSB0eXBlIG9mIHNwZWNpYWwgdmVjdG9yIHdob3NlIGVsZW1lbnRzIGNhbiBiZSBvZiBhbnkgbW9kZSwgaW5jbHVkaW5nIHRoZSBsaXN0IG1vZGUuIFRoaXMgYWxsb3dzIGxpc3RzIHRvIGJlIG5lc3RlZCwgaGVuY2UgdGhlIHRlcm0gcmVjdXJzaXZlIGZvciB0aGlzIHR5cGUgb2Ygb2JqZWN0LgoKVGhlIGJhc2ljIGZ1bmN0aW9uIGZvciBjcmVhdGluZyBsaXN0cyBpcyBsaXN0OgoKYGBge3J9CnggPC0gbGlzdChzaXplID0gYygxLCA1LCAyKSwgdXNlciA9ICJKb2UiLCBuZXcgPSBUUlVFKQp4CmBgYCAKIyMjIyBEYXRhIGZyYW1lcwpWZWN0b3JzLCBtYXRyaWNlcywgdGFibGVzIGFuZCBsaXN0cyBhcmUgdGhlIG1vc3QgY29tbW9uIG9iamVjdCB0eXBlcyB1c2VkIGluIFIgcHJvZ3JhbW1pbmcuIEhvd2V2ZXIsIG1hbnkgc3RhdGlzdGljYWwgcHJvY2VkdXJlcyAtIHRoaW5rIG9mIGxpbmVhciByZWdyZXNzaW9uLCBmb3IgZXhhbXBsZSAtIHJlbHkgbW9yZSBvbiBkYXRhIGZyYW1lcyBmb3IgZGF0YSBzdG9yYWdlLgoKQWx0aG91Z2ggdmlzdWFsbHkgc2ltaWxhciB0byBhIG1hdHJpeCwgYSBkYXRhIGZyYW1lIGlzIG1vcmUgZ2VuZXJhbCBzaW5jZSB0aGUgY29sdW1ucyBjYW4gYmUgaW4gZGlmZmVyZW50IG1vZGVzOyB0aGluayBvZiBhIHRhYmxlIHdpdGggbmFtZXMgKGNoYXJhY3RlciBtb2RlKSBpbiBvbmUgY29sdW1uIGFuZCBub3RlcyAobnVtZXJpYyBtb2RlKSBpbiBhbm90aGVyLgoKQSBkYXRhIGZyYW1lIGlzIGNyZWF0ZWQgd2l0aCB0aGUgZGF0YS5mcmFtZSBmdW5jdGlvbiBvciwgdG8gY29udmVydCBhbm90aGVyIHR5cGUgb2Ygb2JqZWN0IGludG8gYSBkYXRhIGZyYW1lLCB3aXRoIGFzLmRhdGEuZnJhbWUuCgojIyMgTG9naWNhbCBvcGVyYXRvcnMKCldlIGhhdmUgdGhlIGZvbGxvd2luZyB0eXBlcyBvZiBvcGVyYXRvcnMgaW4gUiBwcm9ncmFtbWluZzoKCiogQXJpdGhtZXRpYyBPcGVyYXRvcnMKKiBSZWxhdGlvbmFsIE9wZXJhdG9ycwoqIExvZ2ljYWwgT3BlcmF0b3JzCiogQXNzaWdubWVudCBPcGVyYXRvcnMKKiBNaXNjZWxsYW5lb3VzIE9wZXJhdG9yCgojIyMjQXJpdGhtZXRpYyBPcGVyYXRvcnMKCicrJwlBZGRzIHR3byB2ZWN0b3JzCQpgYGB7cn0KdiA8LSBjKCAyLDUuNSw2KQp0IDwtIGMoOCwgMywgNCkKcHJpbnQodit0KQpgYGAKCgon4oiSJwlTdWJ0cmFjdHMgc2Vjb25kIHZlY3RvciBmcm9tIHRoZSBmaXJzdApgYGB7cn0KdiA8LSBjKCAyLDUuNSw2KQp0IDwtIGMoOCwgMywgNCkKcHJpbnQodi10KQpgYGAKCicqJwlNdWx0aXBsaWVzIGJvdGggdmVjdG9ycwoKYGBge3J9CnYgPC0gYyggMiw1LjUsNikKdCA8LSBjKDgsIDMsIDQpCnByaW50KHYqdCkKYGBgCgonLycJRGl2aWRlIHRoZSBmaXJzdCB2ZWN0b3Igd2l0aCB0aGUgc2Vjb25kCgpgYGB7cn0KdiA8LSBjKCAyLDUuNSw2KQp0IDwtIGMoOCwgMywgNCkKcHJpbnQodi90KQpgYGAKCiclJScJR2l2ZSB0aGUgcmVtYWluZGVyIG9mIHRoZSBmaXJzdCB2ZWN0b3Igd2l0aCB0aGUgc2Vjb25kCQpgYGB7cn0KdiA8LSBjKCAyLDUuNSw2KQp0IDwtIGMoOCwgMywgNCkKcHJpbnQodiUldCkKYGBgCgonJS8lJwlUaGUgcmVzdWx0IG9mIGRpdmlzaW9uIG9mIGZpcnN0IHZlY3RvciB3aXRoIHNlY29uZCAocXVvdGllbnQpCgpgYGB7cn0KdiA8LSBjKCAyLDUuNSw2KQp0IDwtIGMoOCwgMywgNCkKcHJpbnQodiUvJXQpCmBgYAoKJ14nCVRoZSBmaXJzdCB2ZWN0b3IgcmFpc2VkIHRvIHRoZSBleHBvbmVudCBvZiBzZWNvbmQgdmVjdG9yCQoKYGBge3J9CnYgPC0gYyggMiw1LjUsNikKdCA8LSBjKDgsIDMsIDQpCnByaW50KHZedCkKYGBgCgojIyMjUmVsYXRpb25hbCBPcGVyYXRvcnMKCic+JyAJQ2hlY2tzIGlmIGVhY2ggZWxlbWVudCBvZiB0aGUgZmlyc3QgdmVjdG9yIGlzIGdyZWF0ZXIgdGhhbiB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IG9mIHRoZSBzZWNvbmQgdmVjdG9yLgoKYGBge3J9CnYgPC0gYygyLDUuNSw2LDkpCnQgPC0gYyg4LDIuNSwxNCw5KQpwcmludCh2PnQpCmBgYAoKJzwnCUNoZWNrcyBpZiBlYWNoIGVsZW1lbnQgb2YgdGhlIGZpcnN0IHZlY3RvciBpcyBsZXNzIHRoYW4gdGhlIGNvcnJlc3BvbmRpbmcgZWxlbWVudCBvZiB0aGUgc2Vjb25kIHZlY3Rvci4JIApgYGB7cn0KdiA8LSBjKDIsNS41LDYsOSkKdCA8LSBjKDgsMi41LDE0LDkpCnByaW50KHYgPCB0KQpgYGAKCic9PScJQ2hlY2tzIGlmIGVhY2ggZWxlbWVudCBvZiB0aGUgZmlyc3QgdmVjdG9yIGlzIGVxdWFsIHRvIHRoZSBjb3JyZXNwb25kaW5nIGVsZW1lbnQgb2YgdGhlIHNlY29uZCB2ZWN0b3IuCSAKYGBge3J9CnYgPC0gYygyLDUuNSw2LDkpCnQgPC0gYyg4LDIuNSwxNCw5KQpwcmludCh2ID09IHQpCmBgYAoKJzw9JwlDaGVja3MgaWYgZWFjaCBlbGVtZW50IG9mIHRoZSBmaXJzdCB2ZWN0b3IgaXMgbGVzcyB0aGFuIG9yIGVxdWFsIHRvIHRoZSBjb3JyZXNwb25kaW5nIGVsZW1lbnQgb2YgdGhlIHNlY29uZCB2ZWN0b3IuCQoKYGBge3J9CnYgPC0gYygyLDUuNSw2LDkpCnQgPC0gYyg4LDIuNSwxNCw5KQpwcmludCh2PD10KQpgYGAKCic+PScgQ2hlY2tzIGlmIGVhY2ggZWxlbWVudCBvZiB0aGUgZmlyc3QgdmVjdG9yIGlzIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IG9mIHRoZSBzZWNvbmQgdmVjdG9yLgkKCmBgYHtyfQp2IDwtIGMoMiw1LjUsNiw5KQp0IDwtIGMoOCwyLjUsMTQsOSkKcHJpbnQodj49dCkKYGBgCgonIT0nCUNoZWNrcyBpZiBlYWNoIGVsZW1lbnQgb2YgdGhlIGZpcnN0IHZlY3RvciBpcyB1bmVxdWFsIHRvIHRoZSBjb3JyZXNwb25kaW5nIGVsZW1lbnQgb2YgdGhlIHNlY29uZCB2ZWN0b3IuCSBMaXZlIERlbW8KYGBge3J9CnYgPC0gYygyLDUuNSw2LDkpCnQgPC0gYyg4LDIuNSwxNCw5KQpwcmludCh2IT10KQpgYGAKCiMjIE9iamVjdGl2ZSAzOiAgTG9vcHMgYW5kIEZ1bmN0aW9ucwoKIyMjTG9vcHMKTWFueSB0aW1lcyB3ZSBhcmUgaW50ZXJlc3RlZCBpbiByZXBlYXRpbmcgc29tZSBjYWxjdWxhdGlvbnMuIEluIFIsIHRoZXJlIGFyZSBtYW55IG1ldGhvZHMgdG8gZG8gdGhpcywgaW5jbHVkaW5nIHRoZSB1c2Ugb2YgbG9vcHMuIAoKYGBgCksxIDwtIGMoNCwyLDgsNSkKTDEgPC0gYygxLDMsNCwyKQpNMSA8LSAwKjE6NCAgIyBUaGlzIGluIHRoZSBvYmplY3Qgd2hlcmUgd2Ugd2lsbCBwbGFjZSB0aGUgYW5zd2VyIHRvIG91ciBxdWVyeQpNMQpgYGAKCiBUaGlzIGxvb3AgZmluZHMgdGhlIG1heGltdW0gb2YgSzEgYW5kIEwxIGF0IGVhY2ggcG9zaXRpb24KCmBgYApmb3IgKGogaW4gMTo0KXsKICBNMVtqXSA8LSBtYXgoSzFbal0sTDFbal0pCn0KCk0xCmBgYAojIyMgaWYgZWxzZQoKZ2VuZXJhbCBmb3JtIDogaWZlbHNlKHRlc3RfZXhwcmVzc2lvbiwgeCwgeSkgPGJyLz4KCkhlcmUsIHRlc3RfZXhwcmVzc2lvbiBtdXN0IGJlIGEgbG9naWNhbCB2ZWN0b3IgKG9yIGFuIG9iamVjdCB0aGF0IGNhbiBiZSBjb2VyY2VkIHRvIGxvZ2ljYWwpLiBUaGUgcmV0dXJuIHZhbHVlIGlzIGEgdmVjdG9yIHdpdGggdGhlIHNhbWUgbGVuZ3RoIGFzIHRlc3RfZXhwcmVzc2lvbi4gPGJyLz4KClRoaXMgcmV0dXJuZWQgdmVjdG9yIGhhcyBlbGVtZW50IGZyb20geCBpZiB0aGUgY29ycmVzcG9uZGluZyB2YWx1ZSBvZiB0ZXN0X2V4cHJlc3Npb24gaXMgVFJVRSBvciBmcm9tIHkgaWYgdGhlIGNvcnJlc3BvbmRpbmcgdmFsdWUgb2YgdGVzdF9leHByZXNzaW9uIGlzIEZBTFNFLjxici8+CgpgYGB7cn0KeCA8LSBjKCJ3aGF0IiwiaXMiLCJ0cnV0aCIpCgppZigiVHJ1dGgiICVpbiUgeCkgewogICBwcmludCgiVHJ1dGggaXMgZm91bmQiKQp9IGVsc2UgewogICBwcmludCgiVHJ1dGggaXMgbm90IGZvdW5kIikKfQoKYGBgCgojIyMgRnVuY3Rpb25zIAoKSW4gcHJvZ3JhbW1pbmcsIHlvdSB1c2UgZnVuY3Rpb25zIHRvIGluY29ycG9yYXRlIHNldHMgb2YgaW5zdHJ1Y3Rpb25zIHRoYXQgeW91IHdhbnQgdG8gdXNlIHJlcGVhdGVkbHkgb3IgdGhhdCwgYmVjYXVzZSBvZiB0aGVpciBjb21wbGV4aXR5LCBhcmUgYmV0dGVyIHNlbGYtY29udGFpbmVkIGluIGEgc3ViIHByb2dyYW0gYW5kIGNhbGxlZCB3aGVuIG5lZWRlZC4gQSBmdW5jdGlvbiBpcyBhIHBpZWNlIG9mIGNvZGUgd3JpdHRlbiB0byBjYXJyeSBvdXQgYSBzcGVjaWZpZWQgdGFzazsgaXQgY2FuIG9yIGNhbiBub3QgYWNjZXB0IGFyZ3VtZW50cyBvciBwYXJhbWV0ZXJzIGFuZCBpdCBjYW4gb3IgY2FuIG5vdCByZXR1cm4gb25lIG9yIG1vcmUgdmFsdWVzLgoKCiMjIyNHZW5lcmFsCgpUaGUgYWJzb2x1dGUgdmFsdWUgb2YgIngiCmBgYAphYnMoeCkKYGBgCgpBIGdlbmVyaWMgZnVuY3Rpb24gd2hpY2ggY29tYmluZXMgaXRzIGFyZ3VtZW50cyAKYGBgCmMoeCkgCmBgYAoKQ29tYmluZSB2ZWN0b3JzIGJ5IHJvdy9jb2x1bW4gKGNmLiAicGFzdGUiIGluIFVuaXgpCgpgYGAKY2JpbmQoKSAgCmBgYApSZXR1cm5zIHN1aXRhYmx5IGxhZ2dlZCBhbmQgaXRlcmF0ZWQgZGlmZmVyZW5jZXMKCmBgYApkaWZmKHgpICAKYGBgCgpQYXR0ZXJuIG1hdGNoaW5nCgpgYGAKZ3JlcCgpICAKYGBgClRlc3QgaWYgMiBvYmplY3RzIGFyZSBleGFjdGx5IGVxdWFsCmBgYAppZGVudGljYWwoKSAKYGBgCgogQWRkIGEgc21hbGwgYW1vdW50IG9mIG5vaXNlIHRvIGEgbnVtZXJpYyB2ZWN0b3IKYGBgCmppdHRlcigpCmBgYAoKUmV0dXJuIG5vLiBvZiBlbGVtZW50cyBpbiB2ZWN0b3IgeApgYGAKbGVuZ3RoKHgpIApgYGAKTGlzdCBvYmplY3RzIGluIGN1cnJlbnQgZW52aXJvbm1lbnQKYGBgCmxzKCkgIApgYGAKCkNvbmNhdGVuYXRlIHZlY3RvcnMgYWZ0ZXIgY29udmVydGluZyB0byBjaGFyYWN0ZXIKCmBgYApwYXN0ZSh4KSAKYGBgCgpSZXR1cm5zIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIG9mIHgKCmBgYApyYW5nZSh4KSAKYGBgCgpSZXBlYXQgdGhlIG51bWJlciAxIGZpdmUgdGltZXMKYGBgCnJlcCgxLDUpIApgYGAKCkxpc3QgdGhlIGVsZW1lbnRzIG9mICJ4IiBpbiByZXZlcnNlIG9yZGVyCmBgYApyZXYoeCkKYGBgCgpHZW5lcmF0ZSBhIHNlcXVlbmNlICgxIC0+IDEwLCBzcGFjZWQgYnkgMC40KQpgYGAKc2VxKDEsMTAsMC40KSAKYGBgCgpDcmVhdGUgYSB2ZWN0b3Igb2Ygc2VxdWVuY2VzCmBgYApzZXF1ZW5jZSgpIApgYGAKClJldHVybnMgdGhlIHNpZ25zIG9mIHRoZSBlbGVtZW50cyBvZiB4CmBgYApzaWduKHgpIApgYGAKClNvcnQgdGhlIHZlY3RvciB4CmBgYApzb3J0KHgpIApgYGAKCmxpc3Qgc29ydGVkIGVsZW1lbnQgbnVtYmVycyBvZiB4CmBgYApvcmRlcih4KQpgYGAKCkNvbnZlcnQgc3RyaW5nIHRvIGxvd2VyL3VwcGVyIGNhc2UgbGV0dGVycwpgYGAKdG9sb3dlcigpCnRvdXBwZXIoKQpgYGAKCnVuaXF1ZSh4KSAgICAgICMgUmVtb3ZlIGR1cGxpY2F0ZSBlbnRyaWVzIGZyb20gdmVjdG9yCmBgYAp1bmlxdWUoeCkgCmBgYAoKcm91bmRpbmcgZnVuY3Rpb25zCmBgYAp0cnVuYyh4KSAKcm91bmQoeCkKYGBgCgpSZXR1cm4gc3lzdGVtIGRhdGUKYGBgClN5cy5EYXRlKCkgCmBgYApSZXR1cm4gd29ya2luZyBkaXJlY3RvcnkKYGBgCmdldHdkKCkgCmBgYApTZXQgd29ya2luZyBkaXJlY3RvcnkKYGBgCnNldHdkKCkKYGBgCgoKIyMjI1VzZXIgZGVmaW5lZCBmdW5jdGlvbnMKCgpUaGUgZGlmZmVyZW50IHBhcnRzIG9mIGEgZnVuY3Rpb24gYXJlIDoKCiogRnVuY3Rpb24gTmFtZSDiiJIgVGhpcyBpcyB0aGUgYWN0dWFsIG5hbWUgb2YgdGhlIGZ1bmN0aW9uLiBJdCBpcyBzdG9yZWQgaW4gUiBlbnZpcm9ubWVudCBhcyBhbiBvYmplY3Qgd2l0aCB0aGlzIG5hbWUuCgoqIEFyZ3VtZW50cyDiiJIgQW4gYXJndW1lbnQgaXMgYSBwbGFjZWhvbGRlci4gV2hlbiBhIGZ1bmN0aW9uIGlzIGludm9rZWQsIHlvdSBwYXNzIGEgdmFsdWUgdG8gdGhlIGFyZ3VtZW50LiBBcmd1bWVudHMgYXJlIG9wdGlvbmFsOyB0aGF0IGlzLCBhIGZ1bmN0aW9uIG1heSBjb250YWluIG5vIGFyZ3VtZW50cy4gQWxzbyBhcmd1bWVudHMgY2FuIGhhdmUgZGVmYXVsdCB2YWx1ZXMuCgoqIEZ1bmN0aW9uIEJvZHkg4oiSIFRoZSBmdW5jdGlvbiBib2R5IGNvbnRhaW5zIGEgY29sbGVjdGlvbiBvZiBzdGF0ZW1lbnRzIHRoYXQgZGVmaW5lcyB3aGF0IHRoZSBmdW5jdGlvbiBkb2VzLgoKKiBSZXR1cm4gVmFsdWUg4oiSIFRoZSByZXR1cm4gdmFsdWUgb2YgYSBmdW5jdGlvbiBpcyB0aGUgbGFzdCBleHByZXNzaW9uIGluIHRoZSBmdW5jdGlvbiBib2R5IHRvIGJlIGV2YWx1YXRlZC4KCgpgYGB7cn0KbmV3LmZ1bmN0aW9uIDwtIGZ1bmN0aW9uKGEsIGIpIHsKICAgcHJpbnQoYV4yKQogICBwcmludChhKQogICBwcmludChiKQp9CgpuZXcuZnVuY3Rpb24oMiw0KQpgYGAKCgojIyBPYmplY3RpdmUgNDogTG9hZCBmaWxlcyBhbmQgQ2hlY2sgWW91ciBEYXRhCgojIyMgTG9hZCB0aGUgZGF0YSAKClIgaGFzIGEgZnVuY3Rpb24gZGVkaWNhdGVkIHRvIHJlYWRpbmcgY29tbWEtc2VwYXJhdGVkIGZpbGVzLiBUbyBpbXBvcnQgYSBsb2NhbCBDU1YgZmlsZSBuYW1lZCBmaWxlbmFtZS50eHQgYW5kIHN0b3JlIHRoZSBkYXRhIGludG8gb25lIFIgdmFyaWFibGUgbmFtZWQgbXlkYXRhLCB0aGUgc3ludGF4IHdvdWxkIGJlCgpgYGB7cn0KbXlkYXRhID0gcmVhZC5jc3YoIn4vRG9jdW1lbnRzL0NvdXJzZS9ZaWVsZF9XaW50ZXJzY2hvb2wuY3N2IikgICMgcmVhZCBjc3YgZmlsZSAKCmBgYAoKSWYgeW91ciBkYXRhIHVzZSBhbm90aGVyIGNoYXJhY3RlciB0byBzZXBhcmF0ZSB0aGUgZmllbGRzLCBub3QgYSBjb21tYSwgUiBhbHNvIGhhcyB0aGUgbW9yZSBnZW5lcmFsIHJlYWQudGFibGUgZnVuY3Rpb24uIFNvIGlmIHlvdXIgc2VwYXJhdG9yIGlzIGEgdGFiLCBmb3IgaW5zdGFuY2UsIHRoaXMgd291bGQgd29yazoKCmBgYApteWRhdGEgPC0gcmVhZC50YWJsZSgifi9Eb2N1bWVudHMvQ291cnNlL1lpZWxkX1dpbnRlcnNjaG9vbC5jc3YiLCBzZXA9Ilx0IiwgaGVhZGVyPVRSVUUpICMgYnV0IGl0IGlzIG5vdCB0aGUgY2FzZSBoZXJlIQpgYGAKClRoZXJlIGlzIG9mdGVuIG1vcmUgdGhhbiBvbmUgd2F5IHRvIHJlYWQgZGF0YSBpbnRvIFIuIEV2ZW4gYSBzaW1wbGUgLmNzdiBmaWxlIGNhbiBiZSBpbXBvcnRlZCB1c2luZyBhIHJhbmdlIG9mIG1ldGhvZHMsIHdpdGggaW1wbGljYXRpb25zIGZvciBjb21wdXRhdGlvbmFsIGVmZmljaWVuY3kuIFRoaXMgc2VjdGlvbiBsb29rcyBhdCB0aHJlZSBhcHByb2FjaGVzOiBiYXNlIFLigJlzIHJlYWRpbmcgZnVuY3Rpb25zIHN1Y2ggYXMgcmVhZC5jc3YsIHdoaWNoIGFyZSBkZXJpdmVkIGZyb20gIHJlYWQudGFibGU7IHRoZSBkYXRhLnRhYmxlIGFwcHJvYWNoLCB3aGljaCB1c2VzIHRoZSBmdW5jdGlvbiBmcmVhZDsgYW5kIHRoZSBuZXcgcmVhZHIgcGFja2FnZSB3aGljaCBwcm92aWRlcyByZWFkX2NzdiBhbmQgb3RoZXIgIHJlYWRfIGZ1bmN0aW9ucyBzdWNoIGFzIHJlYWRfdHN2LgoKYGBge3J9Cm15ZGF0YSA8LSBmcmVhZCgifi9Eb2N1bWVudHMvQ291cnNlL1lpZWxkX1dpbnRlcnNjaG9vbC5jc3YiLCBoZWFkZXI9VFJVRSkKYGBgCgohW0VmZmljaWVuY3kgb2YgcGFja2FnZXMgdG8gbG9hZCBmaWxlc10oaHR0cHM6Ly9jc2dpbGxlc3BpZS5naXRodWIuaW8vZWZmaWNpZW50Ui9fbWFpbl9maWxlcy9maWd1cmUtaHRtbC9yZWFkci12cy1iYXNlLTEucG5nKQoKClRoZSBkYXRhIGltcG9ydCBmZWF0dXJlcyBjYW4gYmUgYWNjZXNzZWQgZnJvbSB0aGUgZW52aXJvbm1lbnQgcGFuZSBvciBmcm9tIHRoZSB0b29scyBtZW51LiBUaGUgaW1wb3J0ZXJzIGFyZSBncm91cGVkIGludG8gMyBjYXRlZ29yaWVzOiBUZXh0IGRhdGEsIEV4Y2VsIGRhdGEgYW5kIHN0YXRpc3RpY2FsIGRhdGEuIFRvIGFjY2VzcyB0aGlzIGZlYXR1cmUsIHVzZSB0aGUgIkltcG9ydCBEYXRhc2V0IiBkcm9wZG93biBmcm9tIHRoZSAiRW52aXJvbm1lbnQiIHBhbmU6CgohW1Igc3R1ZGlvIGxvYWRdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9hcnRpY2xlX2F0dGFjaG1lbnRzLzM2MDAxNzMzMjQzNC9TY3JlZW5fU2hvdF8yMDE4LTEwLTMxX2F0XzkuMjQuMjJfUE0ucG5nKQoKIyMjIENoZWNrIHRoZSBkYXRhCgpZb3UgY2FuIGludm9rZSB0aGUgdmlld2VyIGluIGEgY29uc29sZSBieSBjYWxsaW5nIHRoZSBWaWV3IGZ1bmN0aW9uIG9uIHRoZSBkYXRhIGZyYW1lIHlvdSB3YW50IHRvIGxvb2sgYXQuIEZvciBpbnN0YW5jZSwgdG8gdmlldyB0aGUgYnVpbHQtaW4gaXJpcyBkYXRhc2V0LCBydW4gdGhlc2UgY29tbWFuZHM6CgpgYGAKVmlldyhteWRhdGEpCmBgYAoKVXNlZnVsIEZ1bmN0aW9ucyBmb3IgRXhwbG9yaW5nIERhdGEgRnJhbWVzICA8YnIvPgpVc2UgZGltKCkgdG8gb2J0YWluIHRoZSBkaW1lbnNpb25zIG9mIHRoZSBkYXRhIGZyYW1lIChudW1iZXIgb2Ygcm93cyBhbmQgbnVtYmVyIG9mIGNvbHVtbnMpLiAgVGhlIG91dHB1dCBpcyBhIHZlY3Rvci4KCmBgYHtyfQogZGltKG15ZGF0YSkKYGBgCgpVc2UgbnJvdygpIGFuZCBuY29sKCkgdG8gZ2V0IHRoZSBudW1iZXIgb2Ygcm93cyBhbmQgbnVtYmVyIG9mIGNvbHVtbnMsIHJlc3BlY3RpdmVseS4gIFlvdSBjYW4gZ2V0IHRoZSBzYW1lIGluZm9ybWF0aW9uIGJ5IGV4dHJhY3RpbmcgdGhlIGZpcnN0IGFuZCBzZWNvbmQgZWxlbWVudCBvZiB0aGUgb3V0cHV0IHZlY3RvciBmcm9tIGRpbSgpLiAKCgpgYGB7cn0KbnJvdyhteWRhdGEpIAojIHNhbWUgYXMgZGltKEluc2VjdFNwcmF5cylbMV0KCiBuY29sKG15ZGF0YSkKIyBzYW1lIGFzIGRpbShJbnNlY3RTcHJheXMpWzJdCmBgYAoKClVzZSBoZWFkKCkgdG8gb2J0YWluIHRoZSBmaXJzdCBuIG9ic2VydmF0aW9ucyBhbmQgdGFpbCgpIHRvIG9idGFpbiB0aGUgbGFzdCBuIG9ic2VydmF0aW9uczsgYnkgZGVmYXVsdCwgbiA9IDYuICBUaGVzZSBhcmUgZ29vZCBjb21tYW5kcyBmb3Igb2J0YWluaW5nIGFuIGludHVpdGl2ZSBpZGVhIG9mIHdoYXQgdGhlIGRhdGEgbG9vayBsaWtlIHdpdGhvdXQgcmV2ZWFsaW5nIHRoZSBlbnRpcmUgZGF0YSBzZXQsIHdoaWNoIGNvdWxkIGhhdmUgbWlsbGlvbnMgb2Ygcm93cyBhbmQgdGhvdXNhbmRzIG9mIGNvbHVtbnMuCgpgYGB7cn0KaGVhZChteWRhdGEsIG4gPSA1KQpgYGAKICBGb3IgZXhhbXBsZSwgdGhlIGZvbGxvd2luZyBjb21tYW5kIHdpbGwgcmV0dXJuIHRoZSBsYXN0IDEwIG9ic2VydmF0aW9ucy4KCmBgYHtyfQp0YWlsKG15ZGF0YSwgbiA9IDUpCmBgYAoKClRoZSBuYW1lcygpIGZ1bmN0aW9uIHdpbGwgcmV0dXJuIHRoZSBjb2x1bW4gaGVhZGVycy4KCmBgYHtyfQpuYW1lcyhteWRhdGEpCmBgYAoKClRoZSBzdHIoKSBmdW5jdGlvbiByZXR1cm5zIG1hbnkgdXNlZnVsIHBpZWNlcyBvZiBpbmZvcm1hdGlvbiwgaW5jbHVkaW5nIHRoZSBhYm92ZSB1c2VmdWwgb3V0cHV0cyBhbmQgdGhlIHR5cGVzIG9mIGRhdGEgZm9yIGVhY2ggY29sdW1uLiAgSW4gdGhpcyBleGFtcGxlLCDigJxudW3igJ0gZGVub3RlcyB0aGF0IHRoZSB2YXJpYWJsZSDigJxjb3VudOKAnSBpcyBudW1lcmljIChjb250aW51b3VzKSwgYW5kIOKAnEZhY3RvcuKAnSBkZW5vdGVzIHRoYXQgdGhlIHZhcmlhYmxlIOKAnHNwcmF54oCdIGlzIGNhdGVnb3JpY2FsIHdpdGggNiBjYXRlZ29yaWVzIG9yIGxldmVscy4gIAoKCmBgYHtyfQpzdHIobXlkYXRhKQpgYGAKCgpUbyBvYnRhaW4gYWxsIG9mIHRoZSBjYXRlZ29yaWVzIG9yIGxldmVscyBvZiBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLCB1c2UgdGhlIGxldmVscygpIGZ1bmN0aW9uLgoKYGBge3J9Cm15ZGF0YSRkZXBhcnRlbWVudDwtYXMuZmFjdG9yKG15ZGF0YSRkZXBhcnRlbWVudCkKbGV2ZWxzKG15ZGF0YSRkZXBhcnRlbWVudCkKYGBgCgoKV2hlbiBhcHBsaWVkIHRvIGEgZGF0YSBmcmFtZSwgdGhlIHN1bW1hcnkoKSBmdW5jdGlvbiBpcyBlc3NlbnRpYWxseSBhcHBsaWVkIHRvIGVhY2ggY29sdW1uLCBhbmQgdGhlIHJlc3VsdHMgZm9yIGFsbCBjb2x1bW5zIGFyZSBzaG93biB0b2dldGhlci48YnIvPgpGb3IgYSBjb250aW51b3VzIChudW1lcmljKSB2YXJpYWJsZSBsaWtlIOKAnHlpZWxk4oCdLCBpdCByZXR1cm5zIHRoZSA1LW51bWJlciBzdW1tYXJ5LiAgICBJZiB0aGVyZSBhcmUgYW55IG1pc3NpbmcgdmFsdWVzIChkZW5vdGVkIGJ5IOKAnE5B4oCdIGZvciBhIHBhcnRpY3VsYXIgZGF0dW0pLCBpdCB3b3VsZCBhbHNvIHByb3ZpZGUgYSBjb3VudCBmb3IgdGhlbS4gIEluIHRoaXMgZXhhbXBsZSwgdGhlcmUgYXJlIG5vIG1pc3NpbmcgdmFsdWVzIGZvciDigJxjb3VudOKAnSwgc28gdGhlcmUgaXMgbm8gZGlzcGxheSBmb3IgdGhlIG51bWJlciBvZiBOQeKAmXMuICBGb3IgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBsaWtlIOKAnGRlcGFydGVtZW504oCdLCBpdCByZXR1cm5zIHRoZSBsZXZlbHMgYW5kIHRoZSBudW1iZXIgb2YgZGF0YSBpbiBlYWNoIGxldmVsLiAgCgoKYGBge3J9CnN1bW1hcnkobXlkYXRhKQpgYGAKCiMjIyBDcmVhdGUgbmV3IHZhcmlhYmxlcwoKVXNlIHRoZSBhc3NpZ25tZW50IG9wZXJhdG9yIDwtIHRvIGNyZWF0ZSBuZXcgdmFyaWFibGVzLiBBIHdpZGUgYXJyYXkgb2Ygb3BlcmF0b3JzIGFuZCBmdW5jdGlvbnMgYXJlIGF2YWlsYWJsZSBoZXJlLgoKCmBgYHtyfQpteWRhdGEkc3VtIDwtIG15ZGF0YSRUbWVhbl8xICsgbXlkYXRhJFRtZWFuXzIKbXlkYXRhJG1lYW4gPC0gKG15ZGF0YSRUbWVhbl8xICsgbXlkYXRhJFRtZWFuXzIpLzIKYGBgCgpXZSBjYW4gYWxzbyBkZWxldGUgdGhlIHZhcmlhYmxlIGJ5IHVzaW5nIGNvbW1hbmQgTlVMTDoKCmBgYHtyfQpteWRhdGEkc3VtIDwtIE5VTEwKbXlkYXRhJG1lYW4gPC0gTlVMTApgYGAKCiMjIE9iamVjdGl2ZSA1OiBTZWxlY3Rpb24gb2YgZGF0YSBhbmQgYmFzaWNzIHBsb3RzCgojIyMgRGF0YSBTZWxlY3Rpb24KCnlvdSBjYW4gc2VsZWN0IGRhdGE6CmBgYHtyfQpteXN1YnNldDwtIG15ZGF0YVtkZXBhcnRlbWVudD09IkFJTiJdCiMgaXMgZXF1aXZhbGVudCB0bwpteXN1YnNldDwtIHN1YnNldChteWRhdGEsZGVwYXJ0ZW1lbnQ9PSJBSU4iKQojIGlzIGVxdWl2YWxlbnQgdG8KI2luc3RhbGwucGFja2FnZXMoImRwbHlyIikKbGlicmFyeShkcGx5cikKbXlzdWJzZXQgPC0gbXlzdWJzZXQgJT4lIGZpbHRlcihkZXBhcnRlbWVudD09IkFJTiIpCiAgICAgICAgICAgICAgICAgIApgYGAKClRoZSBmb2xsb3dpbmcgaXMgYW4gaW50cm9kdWN0aW9uIGZvciBwcm9kdWNpbmcgc2ltcGxlIGdyYXBocyB3aXRoIHRoZSBSIFByb2dyYW1taW5nIExhbmd1YWdlLgoKCiMjIyBsaW5lY2hhcnRzCgogR3JhcGggdGhlIHlpZWxkIHZlY3RvciB3aXRoIGFsbCBkZWZhdWx0cwoKYGBge3J9CnBsb3QobXlzdWJzZXQkeWllbGQpCmBgYAoKTGV0J3MgYWRkIGEgdGl0bGUsIGEgbGluZSB0byBjb25uZWN0IHRoZSBwb2ludHMsIGFuZCBzb21lIGNvbG9yOgoKYGBge3J9CiMgR3JhcGggeWllbGQgdXNpbmcgYmx1ZSBwb2ludHMgb3ZlcmxheWVkIGJ5IGEgbGluZSAKcGxvdChteXN1YnNldCR5aWVsZCx0eXBlPSJvIiwgY29sPSJibHVlIikKCiMgQ3JlYXRlIGEgdGl0bGUgd2l0aCBhIHJlZCwgYm9sZC9pdGFsaWMgZm9udAp0aXRsZShtYWluPSJZaWVsZCIsIGNvbC5tYWluPSJyZWQiLCBmb250Lm1haW49NCkKYGBgCgpOb3cgbGV0J3MgYWRkIGEgcmVkIGxpbmUgZm9yIGFuIG90aGVyIGRlcGFydG1lbnQgYW5kIHNwZWNpZnkgdGhlIHktYXhpcyByYW5nZSBkaXJlY3RseSBzbyBpdCB3aWxsIGJlIGxhcmdlIGVub3VnaCB0byBmaXQgYWxsIHRoZSBkYXRhOgoKYGBge3J9CiMgR3JhcGggeWllbGQgdXNpbmcgYSB5IGF4aXMgdGhhdCByYW5nZXMgZnJvbSAwIHRvIDEyCnBsb3QobXlzdWJzZXQkeWllbGQsIHR5cGU9Im8iLCBjb2w9ImJsdWUiLCB5bGltPWMoMCwxMikpCgojIEdyYXBoIHRydWNrcyB3aXRoIHJlZCBkYXNoZWQgbGluZSBhbmQgc3F1YXJlIHBvaW50cwpsaW5lcyhteWRhdGFbZGVwYXJ0ZW1lbnQ9PSJBSVNORSJdJHlpZWxkLCB0eXBlPSJvIiwgcGNoPTIyLCBsdHk9MiwgY29sPSJyZWQiKQoKIyBDcmVhdGUgYSB0aXRsZSB3aXRoIGEgcmVkLCBib2xkL2l0YWxpYyBmb250CnRpdGxlKG1haW49IllpZWxkIiwgY29sLm1haW49InJlZCIsIGZvbnQubWFpbj00KQpgYGAKTmV4dCBsZXQncyBjaGFuZ2UgdGhlIGF4ZXMgbGFiZWxzIHRvIG1hdGNoIG91ciBkYXRhIGFuZCBhZGQgYSBsZWdlbmQuIFdlJ2xsIGFsc28gY29tcHV0ZSB0aGUgeS1heGlzIHZhbHVlcyB1c2luZyB0aGUgbWF4IGZ1bmN0aW9uIHNvIGFueSBjaGFuZ2VzIHRvIG91ciBkYXRhIHdpbGwgYmUgYXV0b21hdGljYWxseSByZWZsZWN0ZWQgaW4gb3VyIGdyYXBoLgoKYGBge3J9CgojIENhbGN1bGF0ZSByYW5nZSBmcm9tIDAgdG8gbWF4IHZhbHVlIG9mIHlpZWxkcwpnX3JhbmdlIDwtIHJhbmdlKDAsIG15ZGF0YSR5aWVsZCkKCgojIGFubm90YXRpb25zIChheGlzIGxhYmVscykgc28gd2UgY2FuIHNwZWNpZnkgdGhlbSBvdXJzZWxmCnBsb3QobXlzdWJzZXQkeWVhcl9oYXJ2ZXN0LG15c3Vic2V0JHlpZWxkLCB0eXBlPSJvIiwgY29sPSJibHVlIiwgeWxpbT1nX3JhbmdlLGFubj1GQUxTRSkKCiMgR3JhcGggdHJ1Y2tzIHdpdGggcmVkIGRhc2hlZCBsaW5lIGFuZCBzcXVhcmUgcG9pbnRzCmxpbmVzKG15c3Vic2V0JHllYXJfaGFydmVzdCxteWRhdGFbZGVwYXJ0ZW1lbnQ9PSJBSVNORSJdJHlpZWxkLCB0eXBlPSJvIiwgcGNoPTIyLCBsdHk9MiwgY29sPSJyZWQiKQoKIyBDcmVhdGUgYSB0aXRsZSB3aXRoIGEgcmVkLCBib2xkL2l0YWxpYyBmb250CnRpdGxlKG1haW49IllpZWxkIiwgY29sLm1haW49InJlZCIsIGZvbnQubWFpbj00KQoKIyBMYWJlbCB0aGUgeCBhbmQgeSBheGVzIHdpdGggZGFyayBncmVlbiB0ZXh0CnRpdGxlKHhsYWI9InllYXJzIiwgY29sLmxhYj1yZ2IoMCwwLjUsMCkpCnRpdGxlKHlsYWI9IllJRUxEIiwgY29sLmxhYj1yZ2IoMCwwLjUsMCkpCgojIENyZWF0ZSBhIGxlZ2VuZCBhdCAoMSwgZ19yYW5nZVsyXSkgdGhhdCBpcyBzbGlnaHRseSBzbWFsbGVyIAojIChjZXgpIGFuZCB1c2VzIHRoZSBzYW1lIGxpbmUgY29sb3JzIGFuZCBwb2ludHMgdXNlZCBieSAKIyB0aGUgYWN0dWFsIHBsb3RzIApsZWdlbmQoMTk2MCwgMSwgYygiQUlOIiwiQUlTTkUiKSwgY2V4PTAuOCwgCiAgIGNvbD1jKCJibHVlIiwicmVkIiksIHBjaD0yMToyMiwgbHR5PTE6Mik7CiAgCmBgYAoKIyMjIGJhcmNoYXJ0cwoKTGV0J3Mgc3RhcnQgd2l0aCBhIHNpbXBsZSBiYXIgY2hhcnQgZ3JhcGhpbmcgdGhlIHlpZWxkIHZlY3RvcjoKCgpgYGB7cn0KIyBHcmFwaCB5aWVsZHMKbXlzdWJzZXQyIDwtIG15c3Vic2V0ICU+JSAgZmlsdGVyKCB5ZWFyX2hhcnZlc3QgJWluJSBjKDIwMDA6MjAwNSkpCmJhcnBsb3QobXlzdWJzZXQyJHlpZWxkKQpgYGAKCkxldCdzIG5vdyBhZGQgbGFiZWxzLCBibHVlIGJvcmRlcnMgYXJvdW5kIHRoZSBiYXJzLCBhbmQgZGVuc2l0eSBsaW5lczoKCmBgYHtyfQogCmJhcnBsb3QobXlzdWJzZXQyJHlpZWxkLCBtYWluPSJ5aWVsZCIsIHhsYWI9InllYXJzIiwgIAogICB5bGFiPSJ5aWVsZHMiLCBuYW1lcy5hcmc9YygiYmVzdF95ZWFyIiwiMjAwMSIsIjIwMDIiLCIyMDAzIiwiMjAwNCIsIjIwMDUiKSwgCiAgIGJvcmRlcj0iYmx1ZSIsIGRlbnNpdHk9YygxMCwyMCwzMCw0MCw1MCwgNjApKQpgYGAKCgoKIyMjZG90Y2hhcnRzCgpMZXQncyBzdGFydCB3aXRoIGEgc2ltcGxlIGRvdGNoYXJ0IGdyYXBoaW5nIHRoZSBhdXRvcyBkYXRhOgpgYGB7cn0KbXlzdWJzZXQzPC0gbXlkYXRhW3llYXJfaGFydmVzdCAlaW4lIGMoMjAwMzoyMDA1KSxdCm15c3Vic2V0MzwtIG15c3Vic2V0M1tkZXBhcnRlbWVudCAlaW4lIGMoIkFJTiIsICJBSVNORSIpLF0KbXlzdWJzZXQzPC0gbXlzdWJzZXQzWyxjKCJ5ZWFyX2hhcnZlc3QiLCJkZXBhcnRlbWVudCIsInlpZWxkIildCmxpYnJhcnkoInJlc2hhcGUiKQpteXN1YnNldDMkeWVhcl9oYXJ2ZXN0PC1hcy5mYWN0b3IobXlzdWJzZXQzJHllYXJfaGFydmVzdCkKbXlzdWJzZXQzPC1jYXN0KG15c3Vic2V0MywgeWVhcl9oYXJ2ZXN0IH4gZGVwYXJ0ZW1lbnQsIG1lYW4sIHZhbHVlID0gJ3lpZWxkJykKZG90Y2hhcnQodChteXN1YnNldDMpKQoKYGBgCgpMZXQncyBtYWtlIHRoZSBkb3RjaGFydCBhIGxpdHRsZSBtb3JlIGNvbG9yZnVsOgoKYGBge3J9CmRvdGNoYXJ0KHQobXlzdWJzZXQzKSwgY29sb3I9YygicmVkIiwiYmx1ZSIsImRhcmtncmVlbiIpLAogICBtYWluPSJ5aWVsZCIsIGNleD0wLjgpCmBgYAoKIyMgT2JqZWN0aXZlIDY6IExpbmVhciByZWdyZXNzaW9uCgpUaGUgZnVuY3Rpb24gdXNlZCBmb3IgYnVpbGRpbmcgbGluZWFyIG1vZGVscyBpcyBsbSgpLiBUaGUgbG0oKSBmdW5jdGlvbiB0YWtlcyBpbiB0d28gbWFpbiBhcmd1bWVudHMsIG5hbWVseTogMS4gRm9ybXVsYSAyLiBEYXRhLiBUaGUgZGF0YSBpcyB0eXBpY2FsbHkgYSBkYXRhLmZyYW1lIGFuZCB0aGUgZm9ybXVsYSBpcyBhIG9iamVjdCBvZiBjbGFzcyBmb3JtdWxhLiBCdXQgdGhlIG1vc3QgY29tbW9uIGNvbnZlbnRpb24gaXMgdG8gd3JpdGUgb3V0IHRoZSBmb3JtdWxhIGRpcmVjdGx5IGluIHBsYWNlIG9mIHRoZSBhcmd1bWVudCBhcyB3cml0dGVuIGJlbG93LgoKCmBgYHtyfQpsaW5lYXJNb2QgPC0gbG0oeWllbGQgfiB5ZWFyX2hhcnZlc3QsIGRhdGE9bXlzdWJzZXQpICAjIGJ1aWxkIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIG9uIGZ1bGwgZGF0YQpwcmludChsaW5lYXJNb2QpCmBgYAoKcGxvdCB0aGUgY3VydmUKYGBge3J9Cm15c3Vic2V0JHByZWQ8LSBwcmVkaWN0KGxpbmVhck1vZCkKcGxvdChteXN1YnNldCR5ZWFyX2hhcnZlc3QsIG15c3Vic2V0JHlpZWxkKQpsaW5lcyhteXN1YnNldCR5ZWFyX2hhcnZlc3QsbXlzdWJzZXQkcHJlZCkKYGBgCgoKIyBSZWZlcmVuY2VzIAoKClRoZXJlIGFyZSBtYW55IHJlc291cmNlcyBhdmFpbGFibGUgb24gUi4gSGVyZSBhcmUgc29tZSBvZiB0aGVtIGluIG9wZW4gYWNjZXNzLCBzb21lIG9mIHdoaWNoIGhhdmUgYmVlbiB3aWRlbHkgdXNlZCB0byBwcm9kdWNlIHRoaXMgZG9jdW1lbnQ6CgoqIFIgZXQgZXNwYWNlLCBncm91cGUgRWxlbWVudFIKKiBJbnRyb2R1Y3Rpb24gw6AgUiBldCBhdSB0aWR5dmVyc2UsIEp1bGllbiBCYXJuaWVyCiogYW5hbHlzZS1SLCBKb3NlcGggTGFybWFyYW5nZSAmIGFsCiogci1ibG9nZ2Vycy5jb20sIEZvdW5kYXRpb24gZm9yIE9wZW4gQWNjZXNzIFN0YXRpc3RpY3MuCiogc3RhdG1ldGhvZHMubmV0LCBSb2JlcnQgSS4gS2FiYWNvZmYKKiBOb3Rpb25zIHN0YXRpc3RpcXVlcyBldCBjb21tYW5kZXMgZGUgYmFzZSwgVGltb3Row6llIEdpcmF1ZAoqIEJsb2cgUmdlb21hdGljLCBUaW1vdGjDqWUgR2lyYXVkCiogQW5hbHlzZSBkZSBjb3Jyw6lsYXRpb24sIFJpY2NvIFJha290b21hbGFsYQoqIFIgcG91ciBsZXMgZMOpYnV0YW50cywgRW1tYW51ZWwgUGFyYWRpcwoqIFN0YXRpc3RpcXVlcyBldCBsb2dpY2llbCBSLCBDbGFpcmUgRGVsbGEgVmVkb3ZhCiogci1zdGF0aXN0aWNzLmNvLCBTZWx2YSBQcmFiaGFrYXJhbgoqIEJsb2cgUi1hdGlxdWUsIExpc2UgVmF1ZG9yCiogQUlERSBNw4lNT0lSRSBSLCBNYXlldWwgS0FVRkZNQU5OCiogQ2hlYXQgU2hlZXRzLCBkZSBSU3R1ZGlvCgoKCg==