Resources
- R
Commands Document
- There is a significant amount of information pertaining to the use
of R on the internet. Listed below are only some examples of the
resources. If you are having trouble installing R and R Studio, even
after reading and following the instructions I include below, you may
want to go to some of these websites.
Installing R & R Studio
PLEASE NOTE: There are times when you may have to
re-download R (not necessarily R Studio). You will realize this is
needed if you download a package and when you run the library you get a
message that seems to indicate that the package is not for that version.
All you have to do in this case is 1. close out of R Studio; 2. download
the newer version of R and 3. install it.
For links to download R and R studio please go to the following:
Step 1 - R MUST be installed first - Download R for
Windows or Mac
Step 2 - R Studio is installed after R has finished installing -
Download R Studio
for Windows or Mac. Please note: If clicking on the
link does not work, copy and paste the following link into your browser:
https://posit.co/downloads/
For Windows:
Double click R-x.x.x-win.exe
- Click “OK” (for language)
- Click “Next” (for Information)
- Click “Next” (for Select Destination Location)
- Click “Next” (for Select Components)
- Click “Next” (for Startup options)
- Click “Next” (for Select Start Menu Folder)
- On the next screen:
- Make sure “Create a desktop shortcut” is unchecked
- Make sure “Create a Quick Launch shortcut” is unchecked
- Click “Next”
- Click “Finish”
Double click RStudio-x.x.xxxx.exe
- Click “Next”
- Click “Next” (for Choose Install Location)
- Click “Install” (for Choose Start Menu Folder)
- Click “Finish”
[Step 3 is not necessary if you are installing the
packages by running the commands below under “Installation of
Packages”]
- Packages go into:
- C:\Users\YourName\Documents\R win-library\x.x
- Accept to overwrite current packages
For Mac:
- Double click R-x.x.x.pkg
- click “Continue” (for Introduction)
- click “Continue” (for Read Me)
- click “Continue” (for License)
- click “Agree”
- click “Install” (for Installation Type)
- if asked, provide password to allow installation of software
- click “Install Software”
- When installation is complete click “Close”
- Double click RStudio-x.x.xxxx.dmg
- in window that opens up, drag RStudio icon into Applications
folder
- When installation is done, you can click on the RStudio icon in the
Launchpad
- If asked “”RStudio” is an application downloaded from the Internet.
Are you sure you want to open it?”
- If asked to install a “git” command - click “install” and then click
on “agree”
[Step 3 is not necessary if you are installing the
packages by running the commands below under “Installation of
Packages”]
- Packages go into:
- Macintosh
HD/Library/Frameworks/R.framework/Versions/version#/Resources/library
- Accept to overwrite current packages
Back to top
General Notes for R
- pound (#) sign indicates a comment - not read by the program
- console is the window in which you will run the commands
- If you click in the console, and Ctrl L - clears the console
- If ever you’re stuck with a plus (+)sign and cannot get the cursor
(>) back, press Ctrl+C (for both Macs and PCs)
- object: an object contains a graph, the data etc. - whatever you put
it in it.
- <- is equivalent to =
- object$columnname: indicates the name of the column within the
object
- install packages: run ONCE; NEED
to be connected to the internet
- Library command: run EVERYTIME you open
R-Studio
- R IS CASE SENSITIVE
- names(object) : gives the names of all the
variables in a specific object [“names” is bolded b/c it is a command
and does not change when used; only the word “object” is replaced by the
appropriate name of the object containing the data]
- levels(object$nameofcolumn) - gives the levels
within the column of interest; [“levels” is bolded b/c it is a command
and does not change when used; only the words “object” and
“nameofcolumn” are replaced by the appropriate name of the object
containing the data and the name of the column of interest
respectively]
- If ever you need to change a column into a factor because R is not
seeing the column as a factor use this command:
objectL$nameofcolumn =
as.factor(objectL$nameofcolumn)
Installation of Packages
- Installation of packages is done ONLY ONCE;
- For the installation you MUST be connected to the
internet
install.packages("ggplot2", dependencies = T) # used for generating graphs
install.packages("multcomp", dependencies = T) # used for post-hoc analysis
install.packages("pastecs", dependencies = T) # used for generating descriptive statistics
install.packages("reshape", dependencies = T) # used for generating a long version of the data from a wide version of the data
install.packages("reshape2", dependencies = T) # used to generate long form of the file; required in some cases
install.packages("nlme", dependencies = T) # used for generating ANOVAs
install.packages("car", dependencies = T)
install.packages("pwr", dependencies = T)
install.packages("dplyr", dependencies = T)
install.packages("devtools", dependencies = T)
install.packages("rms", dependencies=T) # for regression
install.packages("psych", dependencies=T)
install.packages("ggpubr", dependencies=T) # required for correlation plots
Back to top
Additional packages (not required for class)
install.packages("rmarkdown", dependencies=T) # for RMD files that allow embedding of graphs etc; not required for class
install.packages("jmv") # not required for class
install.packages("umx", dependencies=T) # For structural equation modelling
install.packages("semPlot", dependencies=T) # required for Structural Equation Modeling but not required for class
install.packages("lavaan", dependencies=T) # required for Structural Equation Modeling but not required for class; see https://lavaan.ugent.be/tutorial/index.html
install.packages("sem", dependencies=T) # required for Structural Equation Modeling but not required for class
install.packages("maps", dependencies=T) # required if making map of US - only lower 48 states
install.packages("usmap", dependencies=T) # required if making map of US - all 50 states
# install.packages("RVAideMemoire", dependencies = T) # required for the Fisher Test
install.packages("plotly", dependencies=T) # required for 3D plots
install.packages("compareGroups") # required for generation of table comparing groups
install.packages("lsmeans", dependencies=T) # for comparison of slopes
install.packages("effectsize", dependencies = T)
Loading packages
- Packages need to be loaded EVERY TIME R studio is
started.
- Copy this command and paste into the Console and then press
“Enter”.
library(ggplot2);library(multcomp);library(pastecs);library(reshape); library(reshape2); library(nlme); library(car); library(pwr); library(dplyr); library(devtools); library(rms);library(psych); library(ggpubr)
Back to top
Additional library commands (not required for class)
library(umx); library(jmv); library(sem); library(lavaan); library(semPlot); library(qgraph); library(foreign); library(usmap); library(maps); library(plotly); library(SEMfn); library(lsmeans); library(effectsize); library(roxygen2)
library(RVAideMemoire)
Copying Data from Excel into R
For PC
- Copy the command below (Ctrl+C)
- Paste command into R Studio Console (Ctrl+V)
- Change the name “object” to something that makes sense to you and is
related to the data.
- In Excel, select the data you want to analyze;
Include the header;
- Copy the data (Ctrl+C)
- Go back to R Studio and run (press “Enter”) the
command you pasted earlier (in step 2) into the console
object = read.table(file="clipboard", sep="\t", header=TRUE)
- If you have missing data points in your file that you still want
imported into the dataframe, use the following command:
object = read.csv(file="clipboard", sep="\t", header=TRUE)
Back to top
For Mac
- Copy the command below (Cmd+C)
- Paste command into R Studio Console (Cmd+V)
- Change the name “object” to something that makes sense to you and is
related to the data.
- In Excel, select the data you want to analyze;
Include the header;
- Copy the data (Cmd+C)
- Go back to R Studio and run (press “Enter”) the
command you pasted earlier (in step 2) into the console
object = read.table(pipe("pbpaste"), sep="\t", header = TRUE)
- If you have missing data points in your file that you still want
imported into the dataframe, use the following command:
object = read.csv(pipe("pbpaste"), sep="\t", header = TRUE)
Back to top
Importing Data into R from Excel (xlsx) files
Important Notes:
- If you are going to use this method, you need to make sure
that your excel file has a short name with no spaces
- If you wish to name the object containing the data
something different from the original Excel name, type in the new name
in the “Name:” box under “Import
Options”**
- If you have more than one sheet of data in the
excel file, you will need to specify which sheet the data is coming from
in the “Sheet:” box under “Import
Options” section in the “Import Excel Data
window”
Procedure:
- Go to “File>Import Data Set>From Excel…”
- R opens window called “Import Excel Data”
- Click on “Browse…”
- Select the Excel file you want to import
- R will display the data in the “Data Preview”
window; [see note above if your excel file contains more than one data
sheet or you wish to name your object something different from the excel
file name]
- Click “Import” and the data is now imported and
will be displayed
Importing Data into R from CSV files
object = read.csv(file.choose(), header=T)
- object: name of the object - call it as you wish; should be related
to the data you are importing; should simple; NO spaces; should
short.
- read.csv: tells the program you are going to import a CSV file
- file.choose (): tells the program to open a window for you to select
the file of interest
- header = T: this indicates that you CSV file has a header
- the ONLY word you need to change in this command is the name of the
object
Importing Data into R from SPSS files
- to import *.sav files from SPSS you first need to run the following
library command
library(foreign)
object = read.spss(file.choose(), to.data.frame=TRUE)
- read.spss: tells the program you are going to import an SPSS
file
- file.choose (): tells the program to open a window for you to select
the file of interest
- the ONLY word you need to change in this command is the name of the
object
Exporting from R
Exporting output to a text file
sink("outputname.txt")
# RUN THE COMMANDS YOU WISH YO BE EXPORTED TO THE TEXT FILE
sink()
getwd() # gives working directory
# to import into excel, select the file and use the "space delimited" option, and then check the space checkbox.
Exporting dataframe to a csv file
write.csv(dataframe,"name.csv")
getwd() # gives working directory
Back to top
Viewing imported data
View(object) # allows you to see the data in another tab
Back to top
Back to top
Melting data with multiple id variables and measure variables
object_L=melt(object, id.vars = c("idvar_1", "idvar_2", "idvar_n"), measure.vars = c("mvar_1", "mvar_2", "mvar_n"))
- idvar_1 etc. = replace these with the appropriate names of the
columns containing the id variables
- mvar_1 etc. = replace these with the measure variable column
names
Back to top
Selecting specific subset to analyze
var_a = object$`outcome`[object$predictor1colname=="predictor1" & object$predictor2colname=="predictor2"]
- var_a: name of variable that will contain subset
- object$predictor1colname: name of column containing “predictor1” in
object
- ==: “truly equal to”
Generating descriptive statistics in R
Weighted mean
wt <- c(w1, w2, w3, w4, etc)/(wT) # the weight for the first value = x multiplied w1/wT (e.g. if weight for w1 is 25% w1 would be 25, wT would be 100)
x <- c(x1, x2, x3, x4, etc) # values to be weighted
xm <- weighted.mean(x, wt)
Mean
mean(c(x1, x2, x3, x4...))
Descriptive statistics for WIDE version of data to
2 decimal places
round(stat.desc(object, norm=T), digits=2)
- gives the descriptive statistics for all variables to TWO decimal
place (you can adjust the number of decimal places by simply changing
the number after digits=)
- object: replace this with name of object containing the WIDE version
of the data
- ONLY used with the WIDE version of the data
Descriptive statistics for individual columns of data to 2 decimal
places in WIDE version of data
round(stat.desc(object$columnname, norm=T), digits =2)
- gives the descriptive statistics for the WIDE version of the file
but ONLY for a SPECIFIC COLUMN
- object: needs to be replaced with the name of the wide version of
the data
- columnname: needs to be replaced with the name of the column for
which you wish to generate the statistics.
Descriptive statistics for LONG version of
data
by(objectL$outcome, objectL$predictor, stat.desc, norm=T)
gives the descriptive statistics for the LONG version of the
data
objectL: replace with name of the object containing the LONG
version of data
outcome: replace with name of outcome column in objectL
predictor: replace with name of predictor column in
objectL
nbr.val: number of values/subjects in a particular group
nbr.null: number of ZERO values
nbr.na: number of MISSING values
min/max: minimum and maximum valuers in a group
respectively
range: gives you the range
sum: gives the sum of all values in a group
Measures of centrality:
- median: gives the median of values in a group
- mean: gives the average of values in a group
Measures of variability:
- SE.mean: standard error of the mean
- CI.mean.95: 95% confidence interval
- var: variance
- std.dev: standard deviation
- coef.var: coefficient of variation
Measures of normality:
- skewness: measures of level of skewness of your data, a negative
sign implies a negative skew;
- skew.2SE: indicates whether the skewness is SIGNIFICANT. Skewness is
significant if skew.2SE > +1 or <-1
- kurtosis: measure of level of kurtosis of the data. A negative sign
implies a negative kurtosis.
- kurt.2SE: indicates whether the kurtosis is SIGNIFICANT. kurtosis is
significant if kurt.2SE > +1 or <-1
- normtest.w: test for normality
- normtest.p: if normtest.p<0.05, the the data is NOT normally
distributed.
- When checking for normality - FIRST look at the
normtest.p. If this value is greater than 0.05, then you have nothing to
worry about. If this value is less than 0.05 then you need to look at
the skew.2SE and kurt.2SE in order to determine which aspect is causing
your data to not be normal. If your data is NOT normally distributed,
other statistical tests apply.
Example of output generated with previous command
Back to top
Alternative method
describeBy(outcome~predictor, data = objectL, digits=2, mat=TRUE)
Example of output generated with previous command
- this output is nice and concise but does not contain everything
included in the previous method (e.g. no indication of significance in
relation to the deviations from normality (skewness/kurtosis))
Back to top
Another Method of presenting Statistics
- this method generates presentable tables as an output
- requires “vtable” package
st(ObjectL, vars = c("column1"), add.median=TRUE, numformat=NA)
- gives stats of one column with 25th, 50th and 75th percentiles
- column1 -> replace with the name of the column for which you wish
to calculate the descriptive statistics. Output will have N, Mean and
Std.Dev., Min, and Max also.
st(ObjectL, vars = c("column1"), group = 'Group', add.median = TRUE, numformat=NA)
- gives the statistics of column1 across the group “Group”;
- replace “column1” with the name of the column for which you wish to
generate descriptive statistics;
- replace “Group” with the name of the column that has the grouping
variable e.g. “Sex”.
Descriptive statistics in cases of multiple levels
describeBy(outcome~ var1 + var2, data = object,digits=2, mat=TRUE)
# e.g. if var1 = sex (Male or Female) and var2 = class (Freshman, Sophomore, Junior, Senior)
# digits: describes number of decimal places
# mat: provide a matrix output rather than a list
Excel Commands for some descriptive Statistics - method 1
- all commands start with an equal sign
- once you select the appropriate command (after the equal sign), in
parenthesis you will need to inbput the cells on which you want to
execute that command e.g.
- =min(B2:B10) - this gives the minimum for numbers in cells B2 to
B10
- =max(B2:B10) - gives the max for numbers in cells B2 to B10
- =Average(B2:B10) - gives the average
- =Median(B2:B10) - gives the median
- =var(B2:B10) - gives the variance
- =stdev(B2:B10) - gives the standard deviation
- =B16/SQRT(B17) - gives the standard error of the mean WHEN B16
contains the standard deviation and B17 contains the N (count)
- $ sign in front of the letter (column) or number (row) of the
formula fixes the row or column
Excel Commands for some descriptive Statistics - method 2
- To give a more detailed output, click Data Analysis in the Analysis
group on the Data tab.
- If the Data Analysis command is not available, you need to load the
Analysis ToolPak add-in program.(see:Office Support)
- Select “Descriptive Statistics”
- Input the appropriate variable ranges under “Input”
- If your variables have labels (which they should) check “Labels in
First Row”
- Click on Output Range and in the associated box indicate the cell
you want the output to be generated in (make sure this cell is away from
other important data) OR simply select “New Worksheet Ply”
- Sample output is shown below:
| Mean |
12 |
| Standard Error |
0.447213595 |
| Median |
12 |
| Mode |
13 |
| Standard Deviation |
1 |
| Sample Variance |
1 |
| Kurtosis |
-3 |
| Skewness |
0 |
| Range |
2 |
| Minimum |
11 |
| Maximum |
13 |
| Sum |
60 |
| Count |
5 |
Proportions test
Proportions test: Use a proportions test to
compare/determine if the frequency/probability of an event is different
between the various groups being tested (e.g. asking if the proportion
of males reporting depression is different from females reporting
depression in a sample)
Comparing two proportions - Method 1
prop.test(x = c(c1, c2), n = c(T1, T2), alternative = "two.sided")
- c1 and c2 reflect the number of subjects in each of the categories
(e.g., number of women responding Yes and the number of men responding
Y)
- T1 and T2 reflect the number of TOTAL subjects in each
category/group (e.g., the total number of women in the sample, the total
number of men in the sample)
Comparing two proportions - Method 2
object = c(v1,v2)
- number of subjects in each of the categories (e.g. number of
Catholics in example)
Tobject = c(n1,n2)
- number of TOTAL subjects in each category/group (e.g. Total number
of representative in each party)
prop.test(object, Tobject)
- runs the proportions test
Back to top
Proportions Test Output in R
2-sample test for equality of proportions with
continuity correction
X-squared = 5.7318, df = 1, p-value = 0.01666 # X-squared (chi-squared) = the
statistic; df = degrees of freedom (n-1)
- we have 2 groups; p-value = tells us if
it is significant; IT IS SIGNIFICANT if p
< 0.05
alternative hypothesis: two.sided
95 percent confidence interval:
0.01821926 0.18098709 # If the confidence interval range has the same SIGN - there should be a significant difference
sample estimates:
prop 1 prop 2
0.3535714 0.2539683 # these are the proportions of each of the tested groups
Back to top
Writing a report from a proportions test output
A two-sample test for equality of proportion was conducted to assess
whether the proportion of Catholics in the Republican and Democratic
party were significantly different. The analysis revealed a
significantly higher proportion of Catholics in the Democratic
Party(35.4%) relative to the Republican Party(25.4%),
X2(1,N=532)= 5.73,p<0.05.
Back to top
Comparing more than two proportions - Method 1
prop.test(x = c(c1, c2, c3...), n = c(T1, T2, T3...), alternative = "two.sided")
pairwise.prop.test(x = c(c1, c2, c3...), n = c(T1, T2, T3...), alternative = "two.sided")
- c1, c2, c3… reflect the number of subjects in each of the categories
(e.g., number of women responding Yes and the number of men responding
Y)
- T1, T2, T3… reflect the number of TOTAL subjects in each
category/group (e.g., the total number of women in the sample, the total
number of men in the sample)
- prop.test runs the proportions test - provides the first part of the
output.
- pairwise.prop.test runs the pairwise test to indicate which
proportions are different from each other - this provides the second
part of the output
Comparing more than two proportions - Method 2
object = c(a,b,c,d,e,...)
- number of subjects in each of the categories (e.g. the number of
doctors of a particular faith that said they would NOT perform an
abortion; each letter would be replaced by the number of doctors of each
specific specific faith that responded “NO”)
Tobject = c(Ta,Tb,Tc,Td,Te,...)
- number of Total subjects in each category/group (e.g. the TOTAL
number of doctors of a particular faith i.e those that responded YES
(they would perform an abortion) + those that responded NO;
Replace Ta etc. with numbers representing the
individual totals)
prop.test(object,Tobject)
- runs proportions test - provides the first part of the output.
pairwise.prop.test(object,Tobject)
- runs pairwise test to indicate which proportions are different from
each other - this provides the second part of the output.
Back to top
Proportions Test Output in R (more than two proportions)
# This is the first part of the output that indicates whether there is a difference in the proportions. If there is a difference, however, it will not indicate between which proportions the difference exists.
4-sample test for equality of proportions without
continuity correction
data: object out of Tobject
X-squared = 35.169, df = 3, p-value = 1.122e-07
alternative hypothesis: two.sided
sample estimates:
prop 1 prop 2 prop 3 prop 4
0.2857143 0.5000000 0.2407407 0.7500000
# This is the second part of the output the indicates WHERE the differences are. The numbers in the top row and in the first column reflect the 4 proportions being tested comparing e.g., 1 vs 2 (not significant); 1 vs 4 (significant at p<0.001) etc., etc.
Pairwise comparisons using Pairwise comparison of proportions
data: object out of Tobject
1 2 3
2 0.32422 - -
3 0.82154 0.18128 -
4 0.00013 0.18128 9.5e-07
P value adjustment method: holm
Back to top
Writing a report from a proportions test output (more than two
proportions)
A 4-sample test for equality of proportions was conducted to assess
whether the proportion of the 4 samples provided were significantly
different. The analysis revealed an overall significant difference
X2(3,N= insert number of participants) =
35.17,p<0.001. Pairwise comparisons indicated a significant
difference between samples 1 and 4 and samples 3 and 4 (both
p<0.001). All other comparisons were not significant (p>0.05).
Back to top
Proportions Test for situations where there are very small numbers
(5 or less)
In situations where there are 5 or less values, the proportions test
will display an error. In that case, the Fisher test is the more
appropriate test to use.
Comparing two proportions - in cases of small numbers
fisher.test(matrix(c(n1, T1-n1, n2, T2-n2), ncol=2))
- n1 represents the first number to be compared, T1 is the total
number of subjects in pertaining to variable n1 etc.
Comparing more than two proportions - in cases of small numbers
- requires RVAideMemoire package
fisher.multcomp(matrix(c(n1, T1-n1, n2, T2-n2,.....), ncol=N))
- n1 represents the first number to be compared, T1 is the total
number of subjects in pertaining to variable n1 etc.
- ncol=N: replace N with the number of
variables being compared.
Odds Ratio
Odds Ratio: measures how likely an event is to occur
when exposed to something; a measure of the association between exposure
and outcome
Create Matrix
# data taken from Yang, C.-Y., Shih, Y.-H., & Lung, C.-C. (2024). The association between COVID-19 vaccine/infection and new-onset asthma in children - based on the global TriNetX database. Infection. https://doi.org/10.1007/s15010-024-02329-3 **Table S2 in Supplement 1**
# Create matrix
vax <- c('Vax', 'No Vax')
outcome <- c('Death', 'No death')
data <- matrix(c(354, 31734, 309, 159048), nrow=2, ncol=2, byrow=TRUE)
dimnames(data) <- list('Vaccinated'=vax, 'Outcome'=outcome)
#view matrix
data
Back to top
Calculate Odds Ratio
library(epitools)
#calculate odds ratio
oddsratio(data)
# From the output shown, we would interpret this to mean that the odds that child receiving the vaccine dies is ~5.74 times the odds of one who did not receive the vaccine.
Writing a report from an odds ratio test output
There was a significant difference (p<0.001) in the odds of death
associated with receiving the COVID vaccines in children aged 5-18 years
of age relative to those who did not (OR 5.74, 95% CI [4.93, 6.69]).
Back to top
Some things you may have to do
prior to generating a graph
Function and command for generating Standard Error of the Mean
(SEM)
- This function needs to be copied and run WITHOUT
MODIFICATION before generating the summary statistics using the
summarySE command.
- This code is taken from: Summarizing
Data
## Gives count, mean, standard deviation, standard error of the mean, and confidence interval (default 95%).
## data: a data frame.
## measurevar: the name of a column that contains the variable to be summariezed
## groupvars: a vector containing names of columns that contain grouping variables
## na.rm: a boolean that indicates whether to ignore NA's
## conf.interval: the percent range of the confidence interval (default is 95%)
summarySE <- function(data=NULL, measurevar, groupvars=NULL, na.rm=FALSE,
conf.interval=.95, .drop=TRUE) {
library(plyr)
# New version of length which can handle NA's: if na.rm==T, don't count them
length2 <- function (x, na.rm=FALSE) {
if (na.rm) sum(!is.na(x))
else length(x)
}
# This does the summary. For each group's data frame, return a vector with
# N, mean, and sd
datac <- ddply(data, groupvars, .drop=.drop,
.fun = function(xx, col) {
c(N = length2(xx[[col]], na.rm=na.rm),
mean = mean (xx[[col]], na.rm=na.rm),
sd = sd (xx[[col]], na.rm=na.rm)
)
},
measurevar
)
# Rename the "mean" column
datac <- rename(datac, c("mean" = measurevar))
datac$se <- datac$sd / sqrt(datac$N) # Calculate standard error of the mean
# Confidence interval multiplier for standard error
# Calculate t-statistic for confidence interval:
# e.g., if conf.interval is .95, use .975 (above/below), and use df=N-1
ciMult <- qt(conf.interval/2 + .5, datac$N-1)
datac$ci <- datac$se * ciMult
return(datac)
}
sumstats <- summarySE(objectL, measurevar="outcomevar", groupvars=c("groupvar_1","groupvar_2","groupvar_n"), na.rm=TRUE)
- sumstats: name of object that will have the summary stats. The name
of this should be changed if running for more than one data set.
- summarySE: command that runs the summary statistics
- objectL: name of object containing the long version of the data to
be analyzed/summarized
- “outcomevar”: name of the variable to be analyzed/summarized
- “groupvar_1” etc: name of the columns that contain the groups for
the variable to be analyzed e.g. Sex, Class, Age…etc.
- na.rm = TRUE: removes the empty cells (cells that have NA); Not
required if all data points are present.
Back to top
Ordering levels in a specific variable
- When plotting a graph, R will order the variables in alphabetical
order. Very often this is not the best way of plotting the graph. In
such cases, R needs to be instructed on the desired order of
variables.
- An example is the order of classes. For this example, the name of
the variable in the data (i.e. the column name) is
Class R will order them: Freshman, Graduate, Junior,
Senior, Sophomore
- This command will create an object that has the reordered
levels.
- In such a case, the name of the new object created would be the name
of the predictor that would need to be used in Part I of plotting the
graph.
- For this example Class is the original
name; Class_r is the rearranged levels
Class_r = factor (object$Class, levels=c("Freshman", "Sophomore", "Junior", "Senior", "Graduate"))
- notice how when you are indicating the name of the factor that is to
be reordered you need to give R the name of the object containing the
data (in this case “object” and the name of the column to be reordered
separated by a $ symbol)
- to adapt to any situation - “Class_r” should be renamed
appropriately; “object$Class” should be replaced with the appropriate
object name and column name to be reorganized; all the levels within the
quotes should be replaced accordingly.
Back to top
Changing variable name in a specific column
- If the variables in a particular column need to be changed e.g. from
numbers to words do the following:
- install the package stringr using the
following command:
install.packages("stringr", dependencies = T)
- ensure that you load the package stringr
using the following command:
library(stringr)
- Next, run the following command in order to preserve the original
file:
object2=object
- Next, run the following command on the new modified object
(i.e. object2) (NOTE: this will change the values in
your columns permanently.)
object2$columnname = str_replace_all(object2$columnname,"oldvalue","newvalue")
- You will need to run this command for every value
that needs to be replaced
- When plotting the graph you will need to remember to use the
NEW OBJECT i.e. object2 as
the source of the data
Back to top
Changing the column name/header in the object/dataframe containing
the data
- When you generate the long version of a file, the predictor column
will have the name variable, while the outcome
column will be labeled value.
- To change the name of a specific column use the following
commands
names(objectL)[n] <- "correctname"
- remember that this will be the name that you will need to
use in generating the graph, whenever you are
addressing the predictor/outcome
- replace the n with the number of the
column whose header you wish to change (e.g. if the data has an id
column and you want to change the variable column, this will be column
2)
- replace correctname with the name you want
to give the column/header
This is an alternative command to the one above
- To rename a single column by name
colnames(objectL)[colnames(objectL) == "old_col2"] <- "new_col2"
Back to top
Creating a pie chart, bar graph, line graph or box
plot
Generating a pie chart
object<- c(n1, n2)
labels<- c("Poor (58%)","Normal (42%)")
pie(x=object,labels = labels, radius = 1, main = "Title (n=N)", col = c("#69b3a2", "grey"))
- object: name of object containing number OR percentage of data to be
plotted
- labels: name of object containing the names of the labels of the
parts/sections of the pie chart
- pie: command that plots the pie chart
- x: indicates what is to be plotted (contained in the dataframe
“object” [replace accordingly])
- labels: indicates the labels for the sections (contained in the
dataframe “labels” [replace accordingly])
- radius - specifies radius of circle
- col - specifies colors to be used
Back to top
Example of a graph generated with previous command
Back to top
Generating a bar graph
Generating a bar graph - Part I
barobject=ggplot(objectL, aes(predictor,outcome))
- barobject: name of the entity that will contain the plot (call it
what you wish, just be clear)
- ggplot: command that enables the plotting of the graph
- objectL: is the name of the long version of your data
- aes: tells R to generate the aesthetics
- predictor: REPLACE with the name of the predictor
column in the long version of the file
- outcome: REPLACE with the name of the outcome
column in the long version of the file
- NOTE regarding predictor: If the levels have been rearraged in a new
object, the word predictor should be replaced with the name of that
specific object (in the example above, Class_r
instead of Class)
Generating a bar graph - Part II
barobject+stat_summary(fun=mean, geom="bar",fill="white",color="Black")+stat_summary(fun.data=mean_cl_normal, geom="errorbar",position=position_dodge(width=0.9), width=0.2)+labs(title="Title line1 \n Title line2", x="predictor label", y="outcome label (unit)")+theme(axis.title.x=element_text(vjust=-0.4))+theme(axis.title.y=element_text(vjust=0.3))+theme(title=element_text(vjust=+1.1))+theme(plot.title=element_text(hjust=0.5))+coord_cartesian(ylim=c(lowerlimit, upperlimit)) + guides(fill = guide_legend(title = "name"))
- barobject: name of the plot determined in the previous
command
- stat_summary(fun.y=mean,
geom=“bar”,fill=“white”,color=“Black”): plots the mean, as a bar
graph, with a white fill and a black outline - DOES NOT NEED TO
BE CHANGED unless you wish to change the colors
- stat_summary(fun.data=mean_cl_normal,
geom=“errorbar”,position=position_dodge(width=0.9), width=0.2):
plots the error bars (measure of variability) so that they do not
overlap - YOU DO NOT NEED TO CHANGE ANYTHING;
- NOTE: mean_se can replace
mean_cl_normal if you wish to plot the standard error of the
mean.
- labs(title=“Title line1 \n Title line2”,
x=“predictor label”, y=“outcome label
(unit)”):Labels the graph; title gives the name of the
main heading of the graph; x labels the x-axis; y labels the y-axis; The
“\n” places any words after it on the next line;
DOES NEED CHANGING - you need to change everything that
is in the quotation marks.
- theme(axis.title.x=element_text(vjust=-0.4))+theme(axis.title.y=element_text(vjust=0.3))+theme(title=element_text(vjust=+1.1)):
sets the vertical distance/alignment b/w the specific heading and the
axis - DOES NOT NEED CHANGING
- theme(plot.title=element_text(hjust=0.5)): centers the
title horizontally
- +coord_cartesian(ylim=c(lowerlimit, upperlimit)): you do
NOT always need to use this part of the command; It is
only needed when the y-axis limits need to be adjusted for better
viewing of the graph; If it is not being used, remove the whole command
in between the plus signs leaving only one + sign. If used, replace the
words lowerlimit and upperlimit with the appropriate numbers.
- guides(fill = guide_legend(title = “name”)): where
applicable, provides a new name for the legend (the default is the
header of the column).
Back to top
Example of a graph generated with previous command
Back to top
Generating a bar graph with different colored
bars
Generating a bar graph - Part I
barobject=ggplot(objectL, aes(predictor,outcome,fill=predictor))+scale_fill_manual(values=c("#colorcode", "#colorcode",....))
- replace barobject, objectL, predictor, outcome with appropriate
labels
- replace colorcode with appropriate color code obtained from the Hex
field at the rapidtables website - in the case of the color
selected in the example shown below, the code would be #3399FF
- add as many colors as you have variables
Generating a bar graph - Part II
barobject+stat_summary(fun=mean, geom="bar")+stat_summary(fun.data=mean_cl_normal, geom="errorbar",position=position_dodge(width=0.9), width=0.2)+labs(title="Title line1 \n Title line2", x="predictor label", y="outcome label (unit)")+theme(axis.title.x=element_text(vjust=-0.4))+theme(axis.title.y=element_text(vjust=0.3))+theme(title=element_text(vjust=+1.1))+theme(plot.title=element_text(hjust=0.5))+coord_cartesian(ylim=c(lowerlimit, upperlimit))+guides(fill = guide_legend(title = "name"))
- stat_summary(fun.y=mean, geom=“bar”): Notice how the
section “,fill=”white”,color=“Black”” has been removed because colors
are accounted for in the first command
- Everything else is per the first example of “Generating a
Graph”
Back to top
Example of a graph generated with previous command
Back to top
Creating a bar graph with one independent variable
and using the standard error of the mean for error bars
Generating a bar graph - Part I
barobject=ggplot(sumstats, aes(predictor,outcome,fill=predictor))+scale_fill_manual(values=c("#colorcode", "#colorcode",....))
Generating a bar graph - Part II
barobject+stat_summary(fun=mean, geom="bar")+geom_errorbar(aes(ymin=outcome-se, ymax=outcome+se),position=position_dodge(width=0.9), width=0.2)+labs(title="Title line1 \n Title line2", x="predictor label", y="outcome label (unit)")+theme(axis.title.x=element_text(vjust=-0.4))+theme(axis.title.y=element_text(vjust=0.3))+theme(title=element_text(vjust=+1.1))+theme(plot.title=element_text(hjust=0.5))+coord_cartesian(ylim=c(lowerlimit, upperlimit))+guides(fill = guide_legend(title = "name"))
- geom_errorbar(aes(ymin=outcome-se,
ymax=outcome+se),position=position_dodge(width=0.9), width=0.2):
This command now provides the information for the errorbars. However you
need to replace the word “outcome” with the appropriate name for the
outcome variable.
- Everything else is per the first example of Generating a bar graph
Back to top
Example of a graph generated with previous command
Back to top
Creating a bar graph with multiple independent
variables and using the standard error of the mean for error
bars
Generating a bar graph - Part I
barobject=ggplot(sumstats, aes(predictor,outcome,fill=predictor_2))+scale_fill_manual(values=c("#colorcode", "#colorcode",....))
- NOTE: sumstats is used to provide the data to be
plotted
- predictor: the main predictor that is going to be on the x-axis
- predictor_2: the predictor that provides the sub-categories within
the main predictor
- Additionally, see Generating a
bar graph with different colored bars for details
of what needs to be changed
Generating a bar graph - Part II
barobject+stat_summary(fun=mean, geom="bar",position=position_dodge(width=0.9), linewidth=3)+geom_errorbar(aes(ymin=outcome-se, ymax=outcome+se),position=position_dodge(width=0.9), width=0.2)+labs(title="Title line1 \n Title line2", x="predictor label", y="outcome label (unit)")+theme(axis.title.x=element_text(vjust=-0.4))+theme(axis.title.y=element_text(vjust=0.3))+theme(title=element_text(vjust=+1.1))+theme(plot.title=element_text(hjust=0.5))+coord_cartesian(ylim=c(lowerlimit, upperlimit))+guides(fill = guide_legend(title = "name"))
- geom_errorbar(aes(ymin=outcome-se,
ymax=outcome+se),position=position_dodge(width=0.9), width=0.2):
This command now provides the information for the errorbars. However you
need to replace the word “outcome” with the appropriate name for the
outcome variable.
- Everything else is per the first example of Generating a bar graph
Back to top
Example of a graph generated with previous command
Back to top
Creating bar graphs with multiple independent
variables, plotted as three separate graphs (one per variable)
in one grid
- Original data (contained in “objectL” contains the following
columns “Subject”, “var1”, “var2”, “var3”, “data”
Generating a grid of bar graphs - Example 1
# Make a modified copy of the original data
objectL_mod <- objectL %>%
# Rename variables within var3
# only if necessary/desired
# var3.1 etc. represent different variables within var3
# /n can be used within the names if the new name is long and it is desired to split the title into two lines
mutate(var3 = recode(var3, "oldvar3.1\nname" = "newvar3.1\nname", "oldvar3.2\nname" = "newvar3.2\nname", "oldvar3.3\nname" = "newvar3.3\nname")) # do not add spaces before and after \n or the facet title will not be centered
# Generate graph
bar_objectL=ggplot(objectL_mod, aes(var1,data,fill=var1))+scale_fill_manual(values=c("#CC0000", "#004C99"))
bar_objectL.Sub=bar_objectL+stat_summary(fun=mean, geom="bar",position=position_dodge(width=0.9), linewidth=3)+stat_summary(fun.data=mean_cl_normal, geom="errorbar",position=position_dodge(width=0.9), width=0.2)+labs(title="title", x="x axis title", y="y axis title") + theme(axis.title.x=element_text(vjust=-0.4)) + theme(axis.title.y=element_text(vjust=0.3)) + theme(title=element_text(vjust=+1.1)) + theme(plot.title=element_text(hjust=0.5))+guides(fill = guide_legend(title = "var1"))
# bar_objectL.Sub: contains the command to generate the graph with the various sub-categories present var3
# +guides(fill = guide_legend(title = "var1")): relabels the heading of the legend
# Create grid
bar_objectL.Sub+facet_grid(cols=vars(var3))
Back to top
Example of a graph generated with previous command
Back to top
Generating a grid of bar graphs - Example 1a
- Original data (contained in “objectL” contains the following
columns “Subject”, “var1”, “var2”, “var3”, “data”
- This graph is a modified version of that shown in Example 1 - See Generating a grid of
bar graphs - Example 1
- This graph uses the SEM instead of the Confidence interval to
generate the error bars and also shows the significances
# Make a modified copy of the original data
objectL_mod <- objectL %>%
# Rename variables within var3
# only if necessary/desired
# var3.1 etc. represent different variables within var3
# /n can be used within the names if the new name is long and it is desired to split the title into two lines
mutate(var3 = recode(var3, "oldvar3.1\nname" = "newvar3.1\nname", "oldvar3.2\nname" = "newvar3.2\nname", "oldvar3.3\nname" = "newvar3.3\nname")) # do not add spaces before and after \n or the facet title will not be centered
- Generate Descriptive Statistics that provide standard error of the
mean
# Generate graph
bar_object=ggplot(sumstats_object, aes(x=predictor,y=outcome))+scale_fill_manual(values=c("#CC0000", "#004C99"))
bar_object.Sub=bar_object+geom_bar(stat="identity",position=position_dodge(width=0.9), linewidth=3, aes(fill=predictor))+geom_errorbar(aes(ymin=outcome-se, ymax=outcome+se),position=position_dodge(width=0.9), width=0.2)+labs(title="Title", x="x axis title", y="y axis title") + theme(axis.title.x=element_text(vjust=-0.4)) + theme(axis.title.y=element_text(vjust=0.3)) + theme(title=element_text(vjust=+1.1)) + theme(plot.title=element_text(hjust=0.5)) + guides(fill = guide_legend(title = "predictor")) +coord_cartesian(ylim=c(lowerlimit,upperlimit))+ geom_signif(data=data.frame(predictor2=c("newvar3.1\nname","newvar3.2\nname","newvar3.3\nname")),aes(y_position=c(21.5, 24.5, -2), xmin=c(1.0, 1.0, 1.0), xmax=c(2, 2, 2),annotations = c("**","*","")), tip_length = 0, manual=T)
# The statistic that was NOT significant has been placed beyond the y-scale limit. The coord_cartesian command ensures that the axes limits are as desired and that the non-significant bar does not show up.
# outcome: under geom_errorbar - this refers to the heading of the outcome column in the descriptive statistics output.
# geom_signif: numbers shown in parenthesis need to be adjusted accordingly to accommodate for height (in relation to the y_position) and/or position relative to bars (in relation to the xmin and xmax). Additionally, the annotation needs to be appropriately corrected to reflect the appropriate significances.
# Create grid
bar_BIS.Sub+facet_grid(~BIS_Cat, scales="fixed")
# theme(axis.text.x=element_blank()) - # Removes variable label names in the x-axis if they are not desired.
# theme(axis.ticks.x=element_blank()) - # removes ticks (may be used with above command)
# https://stackoverflow.com/questions/56219468/using-ggsignif-with-grouped-bar-graphs-and-facet-wrap-not-working
Back to top
Example of a graph generated with previous command
Back to top
Generating a grid of bar graphs - Example 2
- Original data (contained in “objectL” contains the following
columns “Subject”, “var1”, “var2”, “var3”, “data”
# Make a modified copy of the original data
objectL_mod <- objectL %>%
# Rename variables within var3
# only if necessary/desired
# var3.1 etc. represent different variables within var3
# /n can be used within the names if the new name is long and it is desired to split the title into two lines
mutate(var3 = recode(var3, "oldvar3.1\nname" = "newvar3.1\nname", "oldvar3.2\nname" = "newvar3.2\nname", "oldvar3.3\nname" = "newvar3.3\nname")) # do not add spaces before and after \n or the facet title will not be centered
# Generate graph
bar_objectL=ggplot(objectL_mod, aes(var1,data,fill=var2))+scale_fill_manual(values=c("#CC0000", "#004C99"))
bar_objectL.Sub=bar_objectL+stat_summary(fun=mean, geom="bar",position=position_dodge(width=0.9), linewidth=3)+stat_summary(fun.data=mean_cl_normal, geom="errorbar",position=position_dodge(width=0.9), width=0.2)+labs(title="title", x="x axis title", y="y axis title") + theme(axis.title.x=element_text(vjust=-0.4)) + theme(axis.title.y=element_text(vjust=0.3)) + theme(title=element_text(vjust=+1.1)) + theme(plot.title=element_text(hjust=0.5))+guides(fill = guide_legend(title = "var2"))
# bar_objectL.Sub: contains the command to generate the graph with the various sub-categories present var3
# +guides(fill = guide_legend(title = "var2")): relabels the heading of the legend
# Create grid
bar_objectL.Sub+facet_grid(cols=vars(var3))
Back to top
Example of a graph generated with previous command
Back to top
Generating a bar graphs with significance shown - Example 3
- Generate Descriptive Statistics that provide standard error of the
mean
# Plot Graph
predictor.r = factor (sumstats_object$predictor.r, levels=c("level1", "level2", "level_n"))
# predictor.r : name of variable that has had levels reorganized for graphing purposes
# predictor.r: predictor that requires levels to be organized for graphic purposes
# level1, etc.: level names listed in the order that you wish them graphed
bar_object=ggplot(sumstats_object, aes(x= predictor.r,y=outcome))+ scale_fill_manual(values=c("#CC0000", "#004C99"))
bar_object+geom_bar(stat="identity",position=position_dodge(width=0.9), linewidth=3, aes(fill=predictor))+geom_errorbar(aes(ymin=Outcome-se, ymax=Outcome+se),position=position_dodge2(0.9, padding=0.6))+labs(title="Title", x="x axis title", y="y axis title") + theme(axis.title.x=element_text(vjust=-0.4)) + theme(axis.title.y=element_text(vjust=0.3)) + theme(title=element_text(vjust=+1.1)) + theme(plot.title=element_text(hjust=0.5)) + guides(fill = guide_legend(title = "Legend Title")) + geom_signif(y_position=c(30.5, 16.5, 15.5), xmin=c(0.7, 4.7, 5.7), xmax=c(1.3, 5.3, 6.3),annotation = c("***","*","**"), tip_length = 0)
# outcome: under geom_errorbar - this refers to the heading of the outcome column in the descriptive statistics output.
# geom_signif: numbers shown in parenthesis need to be adjusted accordingly to accommodate for height (in relation to the y_position) and/or position relative to bars (in relation to the xmin and xmax). Additionally, the annotation needs to be appropriately corrected to reflect the appropriate significances.
# Resources that may be of assistance
# https://statisticsglobe.com/ggsignif-package-r
# https://stackoverflow.com/questions/51443889/how-can-i-get-geom-errorbar-to-dodge-correctly-on-a-bar-chart-in-ggplot2
# https://stackoverflow.com/questions/59008974/why-is-stat-identity-necessary-in-geom-bar-in-ggplot#59009108
# http://sthda.com/english/wiki/ggplot2-error-bars-quick-start-guide-r-software-and-data-visualization
# https://stackoverflow.com/questions/61022992/manually-plotting-significance-relations-between-sub-groups-on-ggplot2-barplot
Back to top
Example of a graph generated with previous command
Back to top
Generating a bar graphs with significance shown and reordered facets
- Example 4
- Generate Descriptive Statistics that provide standard error of the
mean
# Plot Graph
# Generate graph
bar_object=ggplot(sumstatsobject.r,aes(x=predictor1,y=outcome))+scale_fill_manual(values=c("#CC0000", "#004C99"))
bar_object.Sub=bar_object+geom_bar(stat="identity",position=position_dodge(width=0.9), linewidth=3, aes(fill=predictor1)) + geom_errorbar(aes(ymin=Data-se, ymax=Data+se),position=position_dodge(width=0.9), width=0.2)+labs(title="Title Line1\nTitleLine2", x="x-label", y="y-label") + theme(axis.title.x=element_text(vjust=-0.4)) + theme(axis.title.y=element_text(vjust=0.3)) + theme(title=element_text(vjust=+1.1)) + theme(plot.title=element_text(hjust=0.5)) + theme(axis.text.x=element_blank(), axis.ticks.x=element_blank()) + guides(fill = guide_legend(title = "Legend Title")) + coord_cartesian(ylim=c(0,15)) + geom_signif(data=data.frame(ExecFn=c("factor 1", "factor 3", "factor 5", "factor 11", "factor 12")), aes(y_position = c(13.5,12.5,12.5,14,13), xmin=c(1,1,1,1,1), xmax=c(2,2,2,2,2), annotations = c("**","**","**","#","*")), tip_length = 0, manual=T)
# NOTE that only the factors that show significance are listed and the information in the aes also only relates to these.
# Create grid with reorganized factors
bar_object.Sub+facet_grid(~factor(MainPredictor, levels=c("factor 1" ,"factor 2","factor 3", "factor 4", "factor 5", "factor 6", "factor 7", "factor 8", "factor 9", "factor 10", "factor 11", "factor 12")), scales="fixed")
# MainPredictor - replace this with the name of the column that represents the x-label predictor not sub-predictors (An example of the MainPredictor is the name of the predictor that us made up of the 12 factors shown in the graph; an example of a sub-predictor is predictor1 which in this case is Yes or No)
Back to top
Example of a graph generated with previous command
Back to top
Creating a line chart
- variable y is being plotted across variable x for two groups
lp<- ggplot(SCl, aes(x=xvarname, y=yvarname, group=groupname, color=groupname)) + # x
stat_summary(fun=mean, geom="line") + # plots the line
stat_summary(fun=mean, geom="point", size=3)+ # adds points to the plot
stat_summary(fun.data=mean_se, geom="errorbar",position=position_dodge(width=0.0), width=0.2)+ #using standard error of the mean for the error bar.
scale_color_manual(values=c('darkblue','red'))+
labs(title="Title", x="x-axis label", y="y-axis label")+
theme(axis.title.x=element_text(vjust=-0.4))+
theme(axis.title.y=element_text(vjust=0.3))+
theme(title=element_text(vjust=+1.1))+
theme(plot.title=element_text(hjust=0.5))
lp # displays the lineplot
Back to top
Example of a graph generated with previous command
Back to top
Creating a simple boxplot
boxplot(Outcome~Predictor,data=objectL, main="Titleline1 \n Titleline 2",xlab="x-axis label", ylab="y-axis label")
or
# boxplot with data jittered and showing & two different colors
ggplot(objectL, aes(x=Predictor, y=Outcome, fill=Predictor)) + stat_boxplot(geom='errorbar', position=position_dodge(width=0.5),width=0.2) + geom_boxplot(width=0.4) + geom_jitter(position=position_jitter(0.15)) + scale_fill_manual(values=c("#E0E0E0", "#606060"))
Back to top
Correlation
Correlation: a correlation tests whether there is a
RELATIONSHIP between two observed variables within the same sample
(e.g. asking if the number of cups of coffee consumed is related to
amount of alertness in a sample)
Plotting a correlation with a regression line
ggscatter(object, x = "xvariable", y = "yvariable",add = "reg.line", conf.int = TRUE,cor.coef = TRUE, cor.method = "pearson",xlab = "xlabel (units)", ylab = "ylabel(units)", title="title for the graph")+theme(plot.title=element_text(hjust=0.5))
- ggscatter: plots the correlation
- object: name of the wide version of data file
- xvariable: replace with name of column of variable to be plotted in
the x-axis
- yvariable: replace with name of column of variable to be plotted in
the y-axis
- reg.line: adds the regression line
- conf.int = TRUE: plots the confidence interval (shaded area)
- cor.coef = TRUE: shows the correlation coefficient
- cor.method = “pearson”: calculates and shows the p value
- xlab: replace words in quotes with appropriate wording for the
x-label
- ylab: replace words in quotes with appropriate wording for the
y-label
- title: replace words in quotes with a proper title
- theme(plot.title=element_text(hjust=0.5)): centers the title
Back to top
Running a correlation
cor.test(object$predictor, object$outcome)
- gives the correlation coefficient
- gives the p-value (which tells you of the correlation is
significant)
- Important notes to remember from the results
- df = degrees of freedom (n-2 (for correlation))
- p value: p value of less than 0.05 is significant
- the value under “cor” = correlation coefficient
Back to top
Example of a Correlation Output
Pearson's product-moment correlation
data: ingrd$Inc and ingrd$Grd
t = 2.968, df = 12, p-value = 0.01174 ## used for report
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.1833572 0.8780885
sample estimates:
cor
0.6506389 ## used for report
Back to top
Writing a report from a correlation
A Pearson’s correlation indicated that a student’s grade was
significantly related to the family’s income, r(12)=-.65, p<.05.
Back to top
Creating a Correlation Matrix
corPlot(Object,cex = 0.8, stars=TRUE, upper=FALSE, main = "TitleLine1 \n TitleLine2",gr = colorRampPalette(c("#BB4444", "#EE9988", "#FFFFFF", "#77AADD", "#4477AA")))
- Object contains only the variables to be included
in the correlation matrix
- Replace name of Object with the appropriate name
- Replace Title information with the appropriate information
Example of a correlation plot/matrix generated with previous
command
Back to top
Regression
Regression: a regression DESCRIBES the RELATIONSHIP
between a predictor (an independent variable) and an outcome (dependent)
between two observed variables within the same sample. Regressions can
take various forms - linear (e.g. calibration of pH meter), sigmoidal
(e.g. in enzyme kinetics/receptor binding). Distinction between
correlation & regression: While a correlation can
tell you that there is a relationship between
[H3O+] in a solution and the pH value,
regression provides you with the line that best
predicts that relationship.
Types of Regression
- Logistic regression is the appropriate to conduct
when the dependent variable is dichotomous
(binary)
- Stepwise regression is appropriate when you have
many variables and you’re interested in identifying a useful subset of
the predictors.
Back to top
Simple Regression
ObjectReg=lm(outcome~predictor, data=object)
summary(ObjectReg)
- Generates the regression equation and it is stored in
“ObjectReg”
- The lm regression command
- uses WIDE form of the data
- Designate one variable as outcome and the other as predictor - Do so
in such a way that makes sense. e.g. It is more likely that family
income would predict a student’s grade than a student’s grade predicting
family income
- The summary command: gives the output of
the regression equation, from which you extract all of the statistical
information that goes into a regression report.
Back to top
Example Regression Output
Back to top
Example of a Regression Equation derived from the above output
Back to top
Writing a report from a regression output
The results indicated that Fear of Sin significantly predicted
Depression, Beta = 0.222, t(95)=2.336, p < 0.05. Fear of Sin also
explained a significant proportion of variance in Depression,
R2 = .044, F(1, 95) = 5.455, p < 0.05.
Back to top
Multiple Regression (backward elimination) (using AIC)
fitObject = lm(y~x1+x2+x3...,data=na.omit(objectL))
- lm: is the command that runs a linear model analysis
- na.omit will omit those subjects with missing data points &
therefore cannot be included in analysis.
stepObject = stepAIC(fitObject, direction="backward", trace=FALSE) # direction can be "both" or "forward"
stepObject$anova # display results with AIC
summary(stepObject) # display results with t values
Multiple Regression (backward elimination) (using F-value)
fullObject = ols(y~x1+x2+x3..., data = objectL)
fastbw(fullObject, rule = "p", sls = 0.1)
Logistic Regression
mylogit = glm(Outcome ~ Predictor1 + Predictor2 + Predictor3..., data = ObjectL, family = "binomial")
summary(mylogit) # gives Beta and p values
exp(cbind(OR = coef(mylogit), confint(mylogit))) # gives Odds Ratio(OR)
Cronbach’s alpha
- Surveys are generally divided into sections /groups of
questions
- Prior to concluding that questions related to each other, we need to
make sure that questions within a specific group of questions are
consistent with each other (i.e. highly related)
- to measure if a group of questions is consistent or not we use
cronbach’s alpha
- we will also be able to know if consistency improves or not if we
delete a question from the group of questions (this is only shown in
Method 2).
Method 1
# subjects with missing data should be removed before hand using
ObjectNA=na.omit(object)
matobject=data.matrix(object)
reliability(cov(matobject))
Example output from Method 1
$alpha
alpha
0.9403455
$st.alpha
std.alpha
0.9417464
$rel.matrix
Alpha Std.Alpha r(item, total)
D2Stop 0.9350532 0.9368506 0.7365112
Cont2A 0.9335049 0.9354005 0.7837842
AvsOthers 0.9354148 0.9366306 0.7304763
DepSleep 0.9383129 0.9398743 0.6302478
ThinkNOL 0.9353017 0.9364763 0.7397708
LkFrwrd 0.9348757 0.9361827 0.7433303
ThnkLessT 0.9424475 0.9436797 0.5152945
TrdLessT 0.9362815 0.9380178 0.6999771
RushWrk 0.9355317 0.9366959 0.7302428
NegOblig 0.9352094 0.9363647 0.7406319
AccDown 0.9334180 0.9354451 0.7853325
Escape 0.9346224 0.9362977 0.7539146
Frustration 0.9336228 0.9352146 0.7798224
attr(,"class")
[1] "reliability"
Method 2
alphaobject=alpha(object)
alphaobject # shows output
Example output from Method 2
Reliability analysis
Call: alpha(x = CIUS)
raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
0.94 0.94 0.95 0.55 16 0.0051 1.8 0.97 0.55
lower alpha upper 95% confidence boundaries
0.93 0.94 0.95
Reliability if an item is dropped:
raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
D2Stop 0.94 0.94 0.95 0.55 15 0.0056 0.0139 0.56
Cont2A 0.93 0.94 0.95 0.55 14 0.0057 0.0137 0.55
AvsOthers 0.94 0.94 0.95 0.55 15 0.0055 0.0126 0.55
DepSleep 0.94 0.94 0.95 0.57 16 0.0053 0.0135 0.57
ThinkNOL 0.94 0.94 0.95 0.55 15 0.0055 0.0139 0.55
LkFrwrd 0.93 0.94 0.95 0.55 15 0.0056 0.0124 0.55
ThnkLessT 0.94 0.94 0.95 0.58 17 0.0049 0.0077 0.56
TrdLessT 0.94 0.94 0.95 0.56 15 0.0054 0.0136 0.56
RushWrk 0.94 0.94 0.95 0.55 15 0.0055 0.0125 0.55
NegOblig 0.94 0.94 0.95 0.55 15 0.0055 0.0129 0.55
AccDown 0.93 0.94 0.94 0.55 14 0.0057 0.0130 0.55
Escape 0.93 0.94 0.95 0.55 15 0.0056 0.0130 0.56
Frustration 0.93 0.94 0.95 0.55 14 0.0057 0.0132 0.55
Item statistics
n raw.r std.r r.cor r.drop mean sd
D2Stop 299 0.78 0.78 0.76 0.74 2.29 1.3
Cont2A 299 0.82 0.82 0.81 0.78 2.19 1.3
AvsOthers 299 0.77 0.78 0.77 0.73 1.20 1.2
DepSleep 299 0.69 0.69 0.65 0.63 1.25 1.3
ThinkNOL 299 0.78 0.79 0.77 0.74 1.64 1.1
LkFrwrd 299 0.79 0.80 0.78 0.74 1.43 1.2
ThnkLessT 299 0.59 0.58 0.53 0.52 2.84 1.4
TrdLessT 299 0.75 0.74 0.72 0.70 2.12 1.4
RushWrk 299 0.77 0.78 0.77 0.73 0.93 1.1
NegOblig 299 0.78 0.79 0.77 0.74 1.12 1.1
AccDown 299 0.83 0.82 0.82 0.79 2.27 1.4
Escape 299 0.80 0.79 0.79 0.75 2.06 1.5
Frustration 299 0.82 0.82 0.81 0.78 1.41 1.3
Non missing response frequency for each item
0 1 2 3 4 miss
D2Stop 0.14 0.17 0.18 0.30 0.21 0
Cont2A 0.15 0.15 0.21 0.31 0.17 0
AvsOthers 0.37 0.24 0.23 0.13 0.03 0
DepSleep 0.40 0.19 0.22 0.14 0.05 0
ThinkNOL 0.16 0.30 0.31 0.17 0.05 0
LkFrwrd 0.30 0.25 0.22 0.18 0.05 0
ThnkLessT 0.12 0.07 0.10 0.26 0.45 0
TrdLessT 0.17 0.17 0.22 0.25 0.19 0
RushWrk 0.49 0.20 0.20 0.07 0.03 0
NegOblig 0.41 0.20 0.25 0.12 0.01 0
AccDown 0.17 0.11 0.19 0.31 0.21 0
Escape 0.24 0.13 0.15 0.28 0.19 0
Frustration 0.37 0.17 0.23 0.16 0.08 0
For additional information on interpretation please see: Reliability
Analysis
Testing for Homogeneity of variance
- The Levene Test tests whether the VARIANCES are significantly
different from each other
leveneTest(objectL$outcome, objectL$predictor, center = median)
- center: is the name of a function to compute the center of each
group. If you use “mean” instead of median - this gives the original
Levene’s test; The default is “median” which provides a more robust
test.
- if variances are significantly different (p<0.05), in the t-test
include the command: var.equal = FALSE –> calculates a more robust
t-test;
- if variances are NOT significantly different (p>0.05), in the
t-test include the command: var.equal = TRUE –> calculates regular
t-test
- p value is the number found under the Pr(>F); if p>0.05
variances are homogenous (the statistically same)
- Levene test is NOT necessary in REPEATED Measures
tests; In such cases, in a t-test you should
use var.equal = TRUE
Back to top
Conducting a t-test in R
t-test: a t-test tests whether the MEANS/AVERAGES of
TWO samples are significantly different from each other
(e.g. asking if the average depression scores of males is different from
that of females in a sample)
Method 1 - for LONG version of data
PLEASE NOTE this command is currently (10/28/24) not
working properly and giving the following error “cannot use ‘paired’
in formula method”. This page will be updated once a solution is
reported. The issue appears to be in the “paired=…” part of the
command.
t.test(outcome~predictor, data=objectL, paired=FALSE/TRUE, var.equal=FALSE/TRUE)
OR
Method 2 - for WIDE version of data
t.test(object$var1,object$var2, paired=FALSE/TRUE, var.equal=FALSE/TRUE)
- For METHOD 1:
- t.test: command to calculate a t-test
- outcome: name of the outcome column in the long version of
the data file
- predictor: name of the predictor column in the long version
of the data file
- ~ : predicted by
- data=objectL: specifies the name of the long version of the
data file. REPLACE ONLY the word objectL with the appropriate name of
the long version of the file
- For METHOD 2:
- object, var1 and var2 - “object” needs to be replaced with
appropriate name of object containing WIDE version of the data; “var1”
and “var2” need to be replaced with the appropriate names of the columns
in the WIDE version of the data.
- For BOTH:
- paired = TRUE: USED for REPEATED MEASURES,
also known as paired
- paired = FALSE: USED for INDEPENDENT
MEASURES
- var.equal = TRUE: used when the Levene Test p > 0.05
(remember p = the number under Pr(>F)); NOTE: Also
use this in the case of a repeated measures t-test when
a Levene test is not required.
- var.equal = FALSE: used when the Levene Test p <
0.05
- If var.equal = FALSE: the degrees of freedom (df) will NOT be a
whole number (because the specific t-test used uses a more conservative
way of calculating the df.)
- reporting: t(df)=tvalue,pvalue, r^2=
Back to top
Calculating the effect size (r squared)
tvalue^2/(tvalue^2+df)
- all information for the above equation is obtained from the output
of the t-test
- for the tvalue ignore negative signs
- reporting: t(df)=tvalue, p…, r^2=.
Back to top
Calculating the effect size (Cohen’s d) (alternative option)
# requires package effsize
cohen.d(data= object, group1, group2)
- If the groups are not of equal size, add the na.omit command to
group with the least numbers e.g. if group2 has less, use
“na.omit(group2)” instead of simply “group2”
- object - replace with the name of the object containing the
WIDE form of the data
- group1 or group2 - replace with the names of the columns of each of
the groups.
Back to top
t-test output in R
Paired t-test / Two Sample t-test # this title of the output
indicates whether the test you just ran is paired/repeated OR
independent measures/Two Sample t-test.
The line with the t value, df and p value is the most important
line; t: gives you the t value; df gives you the degrees of freedom and
p-values gives you the p value. ALL OF THESE NEED to be reported; the
report will include this data in the following format t(df)=tvalue,
p
output when the sex differences in vitamin D data is analyzed
CORRECTLY using an independent measures test:
t = -2.2258, df = 16, p-value = 0.04075
- output when the sex differences in vitamin D data is analyzed
WRONGLY using a repeated measures test:
t = -2.5964, df = 8, p-value = 0.03179
- If these numbers have the SAME sign it means that it is likely that
there is a significant difference:
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-18.252038 -1.081295
- In a repeated measures test, R only gives you the output for MEAN OF
THE DIFFERENCES:
sample estimates:
mean of the differences
-9.666667
- In an independent measures test, R gives you the output for the mean
for EACH GROUP:
mean in group Boys mean in group Girls
25.66667 35.33333
Back to top
Example of a t-test output and an effect size
(r2)calculation with the important data used in the report
highlighted.
Back to top
Writing a report for a t-test
An independent measures t-test was utilized to assess whether there
is a significant difference in vitamin D levels between boys and girls.
The analysis indicated a significant difference in vitamin D levels,
t(16)=-2.226, p<0.05; rsquared= , specifically girls (M= ; SEM= )
reported a significantly higher level of vitamin D then boys (M= ; SEM=
).
OR
An independent measures t-test was utilized to assess whether there
is a significant difference in vitamin D levels between boys(M= ; SEM= )
and girls(M= ; SEM= ). The analysis indicated a significant difference
in vitamin D levels, t(16)=-2.226, p<0.05; rsquared= ,specifically
girls reported a significantly higher level of vitamin D then boys.
Back to top
Conducting a t-test in excel (method 1)
- =ttest(array1,array2, tails, type)
- Array 1: first column containing the data
- Array 2: second column containing data
- tails: 1 or 2 tailed
- type: 1= Paired; 2= Two-sample equal variance; 3= two-sample unequal
variance.
Conducting a t-test in excel (method 2)
- To give a more detailed output, click Data Analysis in the Analysis
group on the Data tab.
- If the Data Analysis command is not available, you need to load the
Analysis ToolPak add-in program.(see:Office Support)
- Select the type of t-test you need to run
- Input the appropriate variable ranges under “Input”
- If your variables have labels (which they should) check
“Labels”
- Click on Output Range and in the associated box indicate the cell
you want the output to be generated in (make sure this cell is away from
other important data)
- Sample output is shown below:
| Mean |
11.75 |
11.5 |
| Variance |
46.91666667 |
33.66666667 |
| Observations |
4 |
4 |
| Pearson Correlation |
0.910007244 |
|
| Hypothesized Mean Difference |
0 |
|
| df |
3 |
|
| t Stat |
0.174077656 |
|
| P(T<=t) one-tail |
0.436444286 |
|
| t Critical one-tail |
2.353363435 |
|
| P(T<=t) two-tail |
0.872888572 |
|
| t Critical two-tail |
3.182446305 |
|
One-way ANOVA - INDEPENDENT MEASURES
ANOVA: an ANOVA tests whether the MEANS/AVERAGES of
MORE THAN TWO samples are significantly different from
each other (e.g. asking if there is a significant difference in the
average depression scores between Freshman, Sophomores, Juniors and
Seniors). ANOVAs can be complicated given that comparisons can be
carried out within groups and between groups.
- Run Levene Test: For the DF group = k-1 (k=number of
groups/treatments) = DF for the Between Treatment
- The other degrees of Freedom is DF for the WITHIN treatment = N-k
(N=sum total of subjects; k=number of treatments)
aovobject=aov(outcome~predictors, data=objectL)
- this calculates the ANOVA
- Use the long version of the file
- aovobject: name of the object that will contain the ANOVA
calculation
summary(aovobject)
- this gives the output for the ANOVA (See example output
below)
- name of predictor column: between Treatment (b/T)
- Residuals: within Treatment (w/T)
- DF: degrees of freedom (needed for reporting)
- Sum Sq: Sum of Squares (Note: needed for the calculation of the
effect size)
- Mean Sq: Mean Square = variances
- F value: test statistic (needed for reporting)
- Pr(>F): p value (needed for reporting)
- your statistics in the report should be in form: F(DF(b/T),DF(w/T))=
F value, p value, effect size)
- EFFECT SIZE: Sum Sq is used for effect size: Sum Sq(b/T)/(Sum
Sq(total))
Back to top
Example of an Independent Measures Output
Df Sum Sq Mean Sq F value Pr(>F)
variable 2 28.22 14.111 11.91 0.000256 ***
Residuals 24 28.44 1.185
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Back to top
Post-hoc analysis using Tukey Test
- A post-hoc analysis is run whenever the first part of the
ANOVA shows a p<0.05
phobject=glht(aovobject, linfct=mcp(predictor="Tukey"))
- phobject: name of the object that will contain the post-hoc Tukey
test
- aovobject: the name of the object that contains the ANOVA (see
previous ANOVA command)
- predictor: needs to be replaced with name of the PREDICTOR column in
your data file.
summary(phobject)
- gives the summary of the post-hoc analysis (see example
output below)
- Pr(>|t|): is the p value for the specific groups being
compared.
Back to top
- If the variances are not equal the Games-Howell
test is conducted (c.f. Welch test in the t-test)
- requires statix package
games_howell_test(data = objectL, formula = outcome ~ grouping_variable)
Back to top
Example of a post-hoc output for Independent Measures ANOVA
Simultaneous Tests for General Linear Hypotheses
Multiple Comparisons of Means: Tukey Contrasts
Fit: aov(formula = value ~ variable, data = migraineL)
Linear Hypotheses:
Estimate Std. Error t value Pr(>|t|)
DrugB - DrugA == 0 2.1111 0.5132 4.114 0.001063 **
DrugC - DrugA == 0 2.2222 0.5132 4.330 0.000605 ***
DrugC - DrugB == 0 0.1111 0.5132 0.217 0.974514
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Adjusted p values reported -- single-step method)
Back to top
Back to top
Writing a report from an Independent Measures ANOVA output
Pain levels were reported on a scale of 1 to 10 (1=low, 10=high)
following the administration of various pain relievers by individuals
who suffer from migraines. A One Way ANOVA indicated a significant
difference (F(2, 24) = 11.91; p<0.001; n2= 0.498) in
reported pain levels across the drugs administered. Post-hoc analysis
using Tukey test indicated that individuals reported significantly lower
pain levels following the administration of Drug A (M=3.67, SEM=0.29)
relative to both Drug B (M=5.78; SEM=0.49; p<0.01) and Drug C
(M=5.89; SEM=0.26; p<0.001). There was no significant difference
between the reported pain levels following the administration of Drugs B
and C (p>0.05).
Back to top
One-Way REPEATED MEASURES (RM) ANOVA
aovobject=aov(outcome~predictor+Error(participant/predictor), data=objectL)
- participant: replace with the label of the SUBJECT column in the
long version of the file
- predictor: replace with the name of the PREDICTOR column in the long
verstion of the file.
summary(aovobject)
- predictor: between Treatment value (b/T)
- Residuals: error
- Df: degrees of freedom (variable/predictor = k-1 where k=number of
groups. Residuals=(df(w/T)-df(b/S))); w/T = Within Treatment = N-k,
where N=Total number of “samples”/data points and k=number of groups;
b/S = Between subjects = n-1, where n = number within a group;
- Sum Sq: sum of squares (needed for the calculation of the effect
size)
- Mean Sq: variances
- F value: test statistic
- Pr(>F): p value
- your report of these statistics should be in the form of
F(df(b/T),df(error))= Fvalue, pvalue, eta squared (effect size)
Back to top
Example of a Repeated Measures Output
An Example of a Repeated measures ANOVA output with important numbers
used in report highlighted
Back to top
Post-hoc Analysis using Pairwise comparisons
- A post-hoc analysis is run whenever the first part of the
ANOVA shows a p<0.05
- The tukey test does NOT work for this type of ANOVA
command. A Pairwise comparison is used instead.
with(objectL, pairwise.t.test(outcome,predictor, p.adjust.method="bonferroni", paired=T))
- pairwise comparisons: calculate the significant differences between
the pairs of groups
Back to top
Example of a post-hoc output for Repeated Measures ANOVA
An Example of a post-hoc analysis output for a Repeated measures
ANOVA with important numbers used in report highlighted. These values
are the p-values comparing the variable in the vertical
column on the left to the horizontal row above the numbers.
Back to top
Back to top
Writing a report from a Repeated Measures ANOVA output
Repeated measures ANOVA revealed a significant overall effect across
time (F(2,24) = 20.65, p< 0.001; n2=0.63), following the
administration of drug. Post-hoc Bonferroni analysis indicated that
anxiety scores were significantly lower than pre-drug (M=8.10, SEM=0.23)
administration on both week 1 (M=6.80, SEM = 0.25; p<0.05) and week 2
(M=3.00, SEM = 0.26; p<0.001). Moreover the anxiety scores on week 2
were also significantly lower than those of week 1 (p<0.001).
Back to top
- Additional information in relation to ANOVA and some code for more
challenging ANOVAs can be found here
How to use R for multiple-select questions
- Replace OBJECT with name of the object containing the imported data
(long version)
- First column needs to be the subject number
- [This should be done in Excel] All values in the rows need to be
replaced with a 1 (implies there is a value or count) or 0 (blank)
- Replace “variable1” with the name of the column heading of that
specific variable (e.g. if counting number of people in household and/or
Intramural sports, variable1 etc would be replaced with the names of
these columns)
- This code is modified from https://stackoverflow.com/questions/11622660/how-to-use-r-for-multiple-select-questions
set.seed(1)
dat <- data.frame(OBJECT,"variable1","variable2", "variable3", "..n")
multi.freq.table = function(OBJECT, sep="", dropzero=FALSE, clean=TRUE) {
# Takes boolean multiple-response data and tabulates it according to the possible combinations of each variable.
counts = data.frame(table(OBJECT))
N = ncol(counts)
counts$Combn = apply(counts[-N] == 1, 1,
function(x) paste(names(counts[-N])[x],
collapse=sep))
if (isTRUE(dropzero)) {
counts = counts[counts$Freq != 0, ]
} else if (!isTRUE(dropzero)) {
counts = counts
}
if (isTRUE(clean)) {
counts = data.frame(Combn = counts$Combn, Freq = counts$Freq)
}
counts
}
multi.freq.table(dat[-1], sep="-")
How to count number of occurences in a column
- the counts are sorted largest to smallest
count(OBJECT, vars = Columnname, sort=TRUE)
or
- the output is sorted from lowest to highest
sort(table(OBJECT$Columnname))
Plotting map of US with data
METHOD 1: Plot map of US reflecting various levels - Only plots
lower 48
Load packages
library(ggplot2);library(maps);library(dplyr)
Copy data
- StateNumber: object containing data for number of students from
every state
- this object contains the data with the names of the states and
numbers of students from every state
- states that have no representation i.e. 0 students should be
blank
- data needs to have a column named “region” (lower
case)
StateNumber = read.table(file="clipboard", sep="\t", header=TRUE, as.is=TRUE)
Plots all states with ggplot2, using black borders and light blue
fill
ggplot()+geom_polygon(data=MainStates,aes(x=long, y=lat, group=group),color="black", fill="lightblue")
Merges Mainstates Map with StateNumber
MergedStates <- inner_join(MainStates, StateNumber, by = "region")
p <- ggplot()
p <- p + geom_polygon( data=MergedStates, aes(x=long, y=lat, group=group, fill = n), color="white", size = 0.2)
p
Changing color scheme
p <- p + scale_fill_continuous(name="Number of Students",low = "lightblue", high = "darkblue",limits = c(0,140),breaks=c(20,40,60,80,100,120,140), na.value = "grey50")+labs(title="title of graph")
p
Back to top
METHOD 2: Plot map of US reflecting various levels - Plots
all 50 states
Load packages
library(usmap)
Copy data
- StateNumber: object containing data for number of students from
every state
- this object contains the data with the names of the states and
numbers of students from every state
- states that have no representation i.e. 0 students should be
blank
- data needs to have a column named “region”
- The excel data must contain the following columns. The data below
can be copied and then pasted into excel using the “paste special/text
only” option.
- The fips column stands for the Federal Information
Processing Standard (FIPS) which provides a set of standard numeric
codes for referring to U.S. states.
- Please note that, in the FIPS column, the 0 in front of the single
digit numbers is not a requirement - this was just how I set it up.
| 01 |
Alabama |
|
| 02 |
Alaska |
|
| 04 |
Arizona |
|
| 05 |
Arkansas |
|
| 06 |
California |
|
| 08 |
Colorado |
|
| 09 |
Connecticut |
|
| 10 |
Delaware |
|
| 12 |
Florida |
|
| 13 |
Georgia |
|
| 15 |
Hawaii |
|
| 16 |
Idaho |
|
| 17 |
Illinois |
|
| 18 |
Indiana |
|
| 19 |
Iowa |
|
| 20 |
Kansas |
|
| 21 |
Kentucky |
|
| 22 |
Louisiana |
|
| 23 |
Maine |
|
| 24 |
Maryland |
|
| 25 |
Massachusetts |
|
| 26 |
Michigan |
|
| 27 |
Minnesota |
|
| 28 |
Mississippi |
|
| 29 |
Missouri |
|
| 30 |
Montana |
|
| 31 |
Nebraska |
|
| 32 |
Nevada |
|
| 33 |
New Hampshire |
|
| 34 |
New Jersey |
|
| 35 |
New Mexico |
|
| 36 |
New York |
|
| 37 |
North Carolina |
|
| 38 |
North Dakota |
|
| 39 |
Ohio |
|
| 40 |
Oklahoma |
|
| 41 |
Oregon |
|
| 42 |
Pennsylvania |
|
| 44 |
Rhode Island |
|
| 45 |
South Carolina |
|
| 46 |
South Dakota |
|
| 47 |
Tennessee |
|
| 48 |
Texas |
|
| 49 |
Utah |
|
| 50 |
Vermont |
|
| 51 |
Virginia |
|
| 53 |
Washington |
|
| 54 |
West Virginia |
|
| 55 |
Wisconsin |
|
| 56 |
Wyoming |
|
StateNumber = read.table(file="clipboard", sep="\t", header=TRUE, as.is=TRUE)
Plots blank map of all states, using black borders and grey
fill
plot_usmap(regions = "states") + labs(title = "US States",subtitle = "This is a blank map of the state of the United States.") + theme(panel.background = element_rect(color = "black", fill = "grey"))
Plots all states with a color scale reflecting numbers of students
from the specific states and places image in a black rectangle with a
light color grey fill
plot_usmap(data = StateNumber, values = "n", color = "white") + scale_fill_continuous(name="Number of Students",low = "lightblue", high = "darkblue",limits = c(0,140),breaks=c(20,40,60,80,100,120,140), na.value = "grey50")+labs(title="title of graph", subtitle = "Subtitle")+ theme(plot.title=element_text(hjust=0.5)) + theme(plot.subtitle=element_text(hjust=0.5))+ theme(legend.position = "right") + theme(panel.background = element_rect(color = "black", fill ="grey85"))
Back to top
Plotting a 3D Scatter Plot
- you may need to go into Tools/Global
Options/General/Advanced and under OS Integration (quit
required) change the Rendering Engine option to
Desktop OpenGL
Back to top
Additional Resources
R Markdown
# In R Markdown Document:
<div class="alert alert-x">
# Replace "x" with "success" for green; "info" for blue; "warning" for tan; "danger" for red.
</div>
# Creating a pdf of the rpubs website https://rpubs.com/ssammut/ResearchStats
<div class="alert alert-x">
# requires webshot package
library(webshot)
webshot(
url = "https://rpubs.com/ssammut/ResearchStats"
, file = "Output1.pdf" # replace "Output1.pdf" with appropriate name
, vwidth = 992
, vheight = 744
)
getwd () # will show in which folder the file is stored.
</div>
Back to top
Jamovi - an alternate statistical program
- This is not the program used in the class but you can feel free to
experiment with it.
- Jamovi is a program based on R that has a more user-friendly
interface
- Download Jamovi
- Advantage - can be used on all platforms Macs, PCs and
Chromebooks
- A user guide can be found here
- A tutorial is also available here
Back to top
Creating your own package
Resources:
Requires:
Creating the package
- Create folder Name_R_package
- In the folder create a folder called R
- In the folder called R, create a text file called Name_function.txt
that contains a copy the function code
- Change the extension of the text file to .R (confirm change)
- In the Name_R_package folder create a text file called
DESCRIPTION
- In the DESCRIPTION file add the following information:
Package: Name of package
Type: Package
Title: Title describing package
Version: 0.0.1.0
- Remove the .txt extension from the DESCRIPTION file (confirm
change)
- Open a new window in R so that you do not lose previous work
- Go to File/New Project.
- Click on New Directory
- Click on R Package
- Name the package
- Click “Add”
- Select the R file created above
- Click “Browse” and change the folder to select the Name_R_package
you created earlier.
- Click on “Create Project”
- Click on “Build” in the menu and select “Build Source Package”
Using the package
- Go to Tools/Install Packages
- Change “Install From” to “Package Archive File (.zip; .tar.gz)”.
This will open the window for you to select the file.
- Go to the folder Name_R_package and select the .tar.gz file
listed
- Click “Install”
- Run library using the name you gave the package in 9c.:
library(packagename)
- NOTE: Whenever you install a new version of R you
will need to re-run the installation of the package just described.
Back to top
LS0tDQp0aXRsZTogIkJhc2ljIENvbW1hbmRzIHRvIEdldCBTdGFydGVkIHdpdGggUiINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgd29yZF9kb2N1bWVudDogZGVmYXVsdA0KICB0b2M6IHllcw0KLS0tDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1kYW5nZXIiPg0KIyBUYWJsZSBvZiBDb250ZW50czoNCjEuIFtJbnN0YWxsaW5nIFIgJiBSIFN0dWRpb10NCjIuIFtJbnN0YWxsYXRpb24gb2YgUGFja2FnZXNdDQozLiBbTG9hZGluZyBQYWNrYWdlc10NCjQuIFtDb3B5aW5nIERhdGEgZnJvbSBFeGNlbCBpbnRvIFJdDQo1LiBbRXhwb3J0aW5nIGZyb20gUl0NCiAgICArIFtFeHBvcnRpbmcgb3V0cHV0IHRvIGEgdGV4dCBmaWxlXQ0KICAgICsgW0V4cG9ydGluZyBkYXRhZnJhbWUgdG8gYSBjc3YgZmlsZV0NCjYuIFtWaWV3aW5nIGltcG9ydGVkIGRhdGFdDQo3LiBbTWVsdGluZyB5b3VyIGRhdGFdDQogICAgKyBbUGVyZm9ybWluZyBhIHNpbXBsZSBtZWx0aW5nIG9mIGRhdGFdDQogICAgKyBbTWVsdGluZyBkYXRhIHdpdGggbXVsdGlwbGUgaWQgdmFyaWFibGVzIGFuZCBtZWFzdXJlIHZhcmlhYmxlc10NCjguIFtEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGZvciAqKkxvbmcqKiB2ZXJzaW9uIG9mIGRhdGFdDQo5LiBbKipQcm9wb3J0aW9ucyB0ZXN0KipdDQogICAgKyBbQ29tcGFyaW5nIHR3byBwcm9wb3J0aW9ucyAtIE1ldGhvZCAxXQ0KICAgICsgW0NvbXBhcmluZyB0d28gcHJvcG9ydGlvbnMgLSBNZXRob2QgMl0NCiAgICArIFtQcm9wb3J0aW9ucyBUZXN0IE91dHB1dCBpbiBSXQ0KICAgICsgW1dyaXRpbmcgYSByZXBvcnQgZnJvbSBhIHByb3BvcnRpb25zIHRlc3Qgb3V0cHV0XQ0KICAgICsgW0NvbXBhcmluZyBtb3JlIHRoYW4gdHdvIHByb3BvcnRpb25zIC0gTWV0aG9kIDFdDQogICAgKyBbQ29tcGFyaW5nIG1vcmUgdGhhbiB0d28gcHJvcG9ydGlvbnMgLSBNZXRob2QgMl0NCiAgICArIFtQcm9wb3J0aW9ucyBUZXN0IE91dHB1dCBpbiBSIChtb3JlIHRoYW4gdHdvIHByb3BvcnRpb25zKV0NCiAgICArIFtXcml0aW5nIGEgcmVwb3J0IGZyb20gYSBwcm9wb3J0aW9ucyB0ZXN0IG91dHB1dCAobW9yZSB0aGFuIHR3byBwcm9wb3J0aW9ucyldDQoxMC4gWyoqT2RkcyBSYXRpbyoqXQ0KICAgICsgW0NyZWF0ZSBNYXRyaXhdDQogICAgKyBbQ2FsY3VsYXRlIE9kZHMgUmF0aW9dDQogICAgKyBbV3JpdGluZyBhIHJlcG9ydCBmcm9tIGFuIG9kZHMgcmF0aW8gdGVzdCBvdXRwdXRdDQoxMS4gW1NvbWUgdGhpbmdzIHlvdSAqKiptYXkqKiogaGF2ZSB0byBkbyAqKnByaW9yIHRvIGdlbmVyYXRpbmcgYSBncmFwaCoqXQ0KICAgICsgW0Z1bmN0aW9uIGFuZCBjb21tYW5kIGZvciBnZW5lcmF0aW5nIFN0YW5kYXJkIEVycm9yIG9mIHRoZSBNZWFuIChTRU0pXQ0KICAgICsgW09yZGVyaW5nIGxldmVscyBpbiBhIHNwZWNpZmljIHZhcmlhYmxlXQ0KICAgICsgW0NoYW5naW5nIHZhcmlhYmxlIG5hbWUgaW4gYSBzcGVjaWZpYyBjb2x1bW5dDQogICAgKyBbQ2hhbmdpbmcgdGhlIGNvbHVtbiBuYW1lL2hlYWRlciBpbiB0aGUgb2JqZWN0L2RhdGFmcmFtZSBjb250YWluaW5nIHRoZSBkYXRhXQ0KMTIuIFsqKkNyZWF0aW5nIGEgcGllIGNoYXJ0LCBiYXIgZ3JhcGgsIGxpbmUgZ3JhcGggb3IgYm94IHBsb3QqKl0NCiAgICArIFtHZW5lcmF0aW5nIGEgcGllIGNoYXJ0XQ0KICAgICsgW0dlbmVyYXRpbmcgYSBiYXIgZ3JhcGhdDQogICAgKyBbR2VuZXJhdGluZyBhIGJhciBncmFwaCB3aXRoICoqZGlmZmVyZW50IGNvbG9yZWQgYmFycyoqXQ0KICAgICsgW0NyZWF0aW5nIGEgYmFyIGdyYXBoIHdpdGggKipvbmUgaW5kZXBlbmRlbnQgdmFyaWFibGUqKiBhbmQgdXNpbmcgdGhlIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBtZWFuIGZvciBlcnJvciBiYXJzXQ0KICAgICsgW0NyZWF0aW5nIGEgYmFyIGdyYXBoIHdpdGggKiptdWx0aXBsZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMqKiBhbmQgdXNpbmcgdGhlIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBtZWFuIGZvciBlcnJvciBiYXJzXQ0KICAgICsgW0NyZWF0aW5nIGJhciBncmFwaHMgd2l0aCAqKm11bHRpcGxlIGluZGVwZW5kZW50IHZhcmlhYmxlcyoqLCBwbG90dGVkIGFzIHRocmVlIHNlcGFyYXRlIGdyYXBocyAob25lIHBlciB2YXJpYWJsZSkgaW4gb25lIGdyaWRdDQogICAgKyBbQ3JlYXRpbmcgYSBsaW5lIGNoYXJ0XQ0KICAgICsgW0NyZWF0aW5nIGEgc2ltcGxlIGJveHBsb3RdDQoxMy4gWyoqQ29ycmVsYXRpb24qKl0NCiAgICArIFtQbG90dGluZyBhIGNvcnJlbGF0aW9uIHdpdGggYSByZWdyZXNzaW9uIGxpbmVdDQogICAgKyBbUnVubmluZyBhIGNvcnJlbGF0aW9uXQ0KICAgICsgW0V4YW1wbGUgb2YgYSBDb3JyZWxhdGlvbiBPdXRwdXRdDQogICAgKyBbV3JpdGluZyBhIHJlcG9ydCBmcm9tIGEgY29ycmVsYXRpb25dDQogICAgKyBbQ3JlYXRpbmcgYSBDb3JyZWxhdGlvbiBNYXRyaXhdDQoxNC4gWyoqUmVncmVzc2lvbioqXQ0KICAgICsgW1R5cGVzIG9mIFJlZ3Jlc3Npb25dDQogICAgKyBbU2ltcGxlIFJlZ3Jlc3Npb25dDQogICAgKyBbRXhhbXBsZSBSZWdyZXNzaW9uIE91dHB1dF0NCiAgICArIFtFeGFtcGxlIG9mIGEgUmVncmVzc2lvbiBFcXVhdGlvbiBkZXJpdmVkIGZyb20gdGhlIGFib3ZlIG91dHB1dF0NCiAgICArIFtXcml0aW5nIGEgcmVwb3J0IGZyb20gYSByZWdyZXNzaW9uIG91dHB1dF0NCjE1LiBbVGVzdGluZyBmb3IgSG9tb2dlbmVpdHkgb2YgdmFyaWFuY2VdDQoxNi4gWyoqQ29uZHVjdGluZyBhIHQtdGVzdCBpbiBSKipdDQogICAgKyBbTWV0aG9kIDEgLSBmb3IgKipMT05HKiogdmVyc2lvbiBvZiBkYXRhXQ0KICAgICsgW01ldGhvZCAyIC0gZm9yICoqV0lERSoqIHZlcnNpb24gb2YgZGF0YV0NCiAgICArIFtDYWxjdWxhdGluZyB0aGUgZWZmZWN0IHNpemUgKHIgc3F1YXJlZCldDQogICAgKyBbdC10ZXN0IG91dHB1dCBpbiBSXQ0KICAgICsgW0V4YW1wbGUgb2YgYSB0LXRlc3Qgb3V0cHV0IGFuZCBhbiBlZmZlY3Qgc2l6ZSAocl4yXiljYWxjdWxhdGlvbiB3aXRoIHRoZSBpbXBvcnRhbnQgZGF0YSB1c2VkIGluIHRoZSByZXBvcnQgaGlnaGxpZ2h0ZWQuXQ0KICAgICsgW1dyaXRpbmcgYSByZXBvcnQgZm9yIGEgdC10ZXN0XQ0KMTcuIFsqKk9uZS13YXkgQU5PVkEgLSBJTkRFUEVOREVOVCBNRUFTVVJFUyoqXQ0KICAgICsgW0V4YW1wbGUgb2YgYW4gSW5kZXBlbmRlbnQgTWVhc3VyZXMgT3V0cHV0XQ0KICAgICsgW1Bvc3QtaG9jIGFuYWx5c2lzIHVzaW5nIFR1a2V5IFRlc3RdDQogICAgKyBbRXhhbXBsZSBvZiBhIHBvc3QtaG9jIG91dHB1dCBmb3IgSW5kZXBlbmRlbnQgTWVhc3VyZXMgQU5PVkFdDQogICAgKyBbRXF1YXRpb24gZm9yIEV0YSBTcXVhcmVkIChlZmZlY3Qgc2l6ZSkgZm9yIEluZGVwZW5kZW50IE1lYXN1cmVzIEFOT1ZBIChpbmZvcm1hdGlvbiB0YWtlbiBmcm9tIHRoZSBmaXJzdCBzdGVwIG9mIHRoZSBBTk9WQSkuXQ0KICAgICsgW1dyaXRpbmcgYSByZXBvcnQgZnJvbSBhbiBJbmRlcGVuZGVudCBNZWFzdXJlcyBBTk9WQSBvdXRwdXRdDQoxOC4gWyoqT25lLVdheSBSRVBFQVRFRCBNRUFTVVJFUyAoUk0pIEFOT1ZBKipdDQogICAgKyBbRXhhbXBsZSBvZiBhIFJlcGVhdGVkIE1lYXN1cmVzIE91dHB1dF0NCiAgICArIFtQb3N0LWhvYyBBbmFseXNpcyB1c2luZyBQYWlyd2lzZSBjb21wYXJpc29uc10NCiAgICArIFtFeGFtcGxlIG9mIGEgcG9zdC1ob2Mgb3V0cHV0IGZvciBSZXBlYXRlZCBNZWFzdXJlcyBBTk9WQV0NCiAgICArIFtFcXVhdGlvbiBmb3IgRXRhIFNxdWFyZWQgKGVmZmVjdCBzaXplKSBmb3IgUmVwZWF0ZWQgTWVhc3VyZXMgQU5PVkEuIFRoZSBpbmZvcm1hdGlvbiBpcyBmb3VuZCB1bmRlciB0aGUgc2VjdGlvbiAqKkVycm9yOiBXaXRoaW4qKiBpbiB0aGUgZmlyc3Qgc3RlcCBvZiB0aGUgQU5PVkFdDQogICAgKyBbV3JpdGluZyBhIHJlcG9ydCBmcm9tIGEgUmVwZWF0ZWQgTWVhc3VyZXMgQU5PVkEgb3V0cHV0XQ0KMTkuIFtIb3cgdG8gdXNlIFIgZm9yIG11bHRpcGxlLXNlbGVjdCBxdWVzdGlvbnNdDQoyMC4gW0hvdyB0byBjb3VudCBudW1iZXIgb2Ygb2NjdXJlbmNlcyBpbiBhIGNvbHVtbl0NCjIxLiBbUGxvdHRpbmcgbWFwIG9mIFVTIHdpdGggZGF0YV0NCiAgICArIFtNRVRIT0QgMTogUGxvdCBtYXAgb2YgVVMgcmVmbGVjdGluZyB2YXJpb3VzIGxldmVscyAtIE9ubHkgcGxvdHMgKipsb3dlciA0OCoqXQ0KICAgICsgW01FVEhPRCAyOiBQbG90IG1hcCBvZiBVUyByZWZsZWN0aW5nIHZhcmlvdXMgbGV2ZWxzIC0gUGxvdHMgKiphbGwgNTAgc3RhdGVzKipdDQoyMi4gW0FkZGl0aW9uYWwgUmVzb3VyY2VzXQ0KICAgICsgW1IgTWFya2Rvd25dDQogICAgKyBbSmFtb3ZpIC0gYW4gYWx0ZXJuYXRlIHN0YXRpc3RpY2FsIHByb2dyYW1dDQogICAgKyBbQ3JlYXRpbmcgeW91ciBvd24gcGFja2FnZV0NCjwvZGl2Pg0KDQojIFJlc291cmNlcw0KDQogICogW1IgQ29tbWFuZHMgRG9jdW1lbnRdKGh0dHA6Ly9ycHVicy5jb20vc3NhbW11dC9SZXNlYXJjaFN0YXRzKXt0YXJnZXQ9Il9ibGFuayJ9DQogICogVGhlcmUgaXMgYSBzaWduaWZpY2FudCBhbW91bnQgb2YgaW5mb3JtYXRpb24gcGVydGFpbmluZyB0byB0aGUgdXNlIG9mIFIgb24gdGhlIGludGVybmV0LiBMaXN0ZWQgYmVsb3cgYXJlIG9ubHkgc29tZSBleGFtcGxlcyBvZiB0aGUgcmVzb3VyY2VzLiBJZiB5b3UgYXJlIGhhdmluZyB0cm91YmxlIGluc3RhbGxpbmcgUiBhbmQgUiBTdHVkaW8sIGV2ZW4gYWZ0ZXIgcmVhZGluZyBhbmQgZm9sbG93aW5nIHRoZSBpbnN0cnVjdGlvbnMgSSBpbmNsdWRlIGJlbG93LCB5b3UgbWF5IHdhbnQgdG8gZ28gdG8gc29tZSBvZiB0aGVzZSB3ZWJzaXRlcy4gDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPiAgDQojIEluc3RhbGxpbmcgUiAmIFIgU3R1ZGlvDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQoqKlBMRUFTRSBOT1RFKio6IFRoZXJlIGFyZSB0aW1lcyB3aGVuIHlvdSBtYXkgaGF2ZSB0byByZS1kb3dubG9hZCBSIChub3QgbmVjZXNzYXJpbHkgUiBTdHVkaW8pLiBZb3Ugd2lsbCByZWFsaXplIHRoaXMgaXMgbmVlZGVkIGlmIHlvdSBkb3dubG9hZCBhIHBhY2thZ2UgYW5kIHdoZW4geW91IHJ1biB0aGUgbGlicmFyeSB5b3UgZ2V0IGEgbWVzc2FnZSB0aGF0IHNlZW1zIHRvIGluZGljYXRlIHRoYXQgdGhlIHBhY2thZ2UgaXMgbm90IGZvciB0aGF0IHZlcnNpb24uIEFsbCB5b3UgaGF2ZSB0byBkbyBpbiB0aGlzIGNhc2UgaXMgMS4gY2xvc2Ugb3V0IG9mIFIgU3R1ZGlvOyAyLiBkb3dubG9hZCB0aGUgbmV3ZXIgdmVyc2lvbiBvZiBSIGFuZCAzLiBpbnN0YWxsIGl0Lg0KPC9kaXY+DQoNCkZvciBsaW5rcyB0byBkb3dubG9hZCBSIGFuZCBSIHN0dWRpbyBwbGVhc2UgZ28gdG8gdGhlIGZvbGxvd2luZzoNCg0KICAxLiBTdGVwIDEgLSBSIE1VU1QgYmUgaW5zdGFsbGVkIGZpcnN0IC0gW0Rvd25sb2FkICoqUioqIGZvciBXaW5kb3dzIG9yIE1hYyBdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnLykNCg0KICAyLiBTdGVwIDIgLSBSIFN0dWRpbyBpcyBpbnN0YWxsZWQgYWZ0ZXIgUiBoYXMgZmluaXNoZWQgaW5zdGFsbGluZyAtIFtEb3dubG9hZCAqKlIgU3R1ZGlvKiogZm9yIFdpbmRvd3Mgb3IgTWFjIF0oaHR0cHM6Ly9wb3NpdC5jby9kb3dubG9hZHMvKS4gKipQbGVhc2Ugbm90ZToqKiBJZiBjbGlja2luZyBvbiB0aGUgbGluayBkb2VzIG5vdCB3b3JrLCBjb3B5IGFuZCBwYXN0ZSB0aGUgZm9sbG93aW5nIGxpbmsgaW50byB5b3VyIGJyb3dzZXI6IGh0dHBzOi8vcG9zaXQuY28vZG93bmxvYWRzLw0KDQo8L2Rpdj4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtd2FybmluZyI+ICANCiMjIEZvciAqKldpbmRvd3MqKjoNCg0KMS4gRG91YmxlIGNsaWNrICoqUi14LngueC13aW4uZXhlKioNCg0KICAgIGEuIENsaWNrIOKAnE9L4oCdIChmb3IgbGFuZ3VhZ2UpDQogICAgYi4gQ2xpY2sg4oCcTmV4dOKAnSAoZm9yIEluZm9ybWF0aW9uKQ0KICAgIGMuIENsaWNrIOKAnE5leHTigJ0gKGZvciBTZWxlY3QgRGVzdGluYXRpb24gTG9jYXRpb24pDQogICAgZC4gQ2xpY2sg4oCcTmV4dOKAnSAoZm9yIFNlbGVjdCBDb21wb25lbnRzKQ0KICAgIGUuIENsaWNrIOKAnE5leHTigJ0gKGZvciBTdGFydHVwIG9wdGlvbnMpDQogICAgZi4gQ2xpY2sg4oCcTmV4dOKAnSAoZm9yIFNlbGVjdCBTdGFydCBNZW51IEZvbGRlcikNCiAgICBnLiBPbiB0aGUgbmV4dCBzY3JlZW46DQogICAgICAgIGkuCU1ha2Ugc3VyZSDigJxDcmVhdGUgYSBkZXNrdG9wIHNob3J0Y3V04oCdIGlzIHVuY2hlY2tlZA0KICAgICAgICBpaS4JTWFrZSBzdXJlIOKAnENyZWF0ZSBhIFF1aWNrIExhdW5jaCBzaG9ydGN1dOKAnSBpcyB1bmNoZWNrZWQNCiAgICAgICAgaWlpLglDbGljayDigJxOZXh04oCdDQogICAgaC4gQ2xpY2sg4oCcRmluaXNo4oCdDQoNCjIuIERvdWJsZSBjbGljayAqKlJTdHVkaW8teC54Lnh4eHguZXhlKioNCg0KICAgIGEuIENsaWNrIOKAnE5leHTigJ0NCiAgICBiLiBDbGljayDigJxOZXh04oCdIAkoZm9yIENob29zZSBJbnN0YWxsIExvY2F0aW9uKQ0KICAgIGMuIENsaWNrIOKAnEluc3RhbGzigJ0gCShmb3IgQ2hvb3NlIFN0YXJ0IE1lbnUgRm9sZGVyKQ0KICAgIGQuIENsaWNrIOKAnEZpbmlzaOKAnQ0KDQpbKioqU3RlcCAzIGlzIG5vdCBuZWNlc3NhcnkgaWYgeW91IGFyZSBpbnN0YWxsaW5nIHRoZSBwYWNrYWdlcyBieSBydW5uaW5nIHRoZSBjb21tYW5kcyBiZWxvdyB1bmRlciAiSW5zdGFsbGF0aW9uIG9mIFBhY2thZ2VzIioqKl0NCg0KMy4gUGFja2FnZXMgZ28gaW50bzogDQogICAgYS4gQzpcXFVzZXJzXFxZb3VyTmFtZVxcRG9jdW1lbnRzXFxSIHdpbi1saWJyYXJ5XFx4LngNCiAgICBiLiBBY2NlcHQgdG8gb3ZlcndyaXRlIGN1cnJlbnQgcGFja2FnZXMgDQoNCiMjIEZvciAqKk1hYyoqOg0KDQoxLiBEb3VibGUgY2xpY2sgKipSLXgueC54LnBrZyoqDQogICAgYS4JY2xpY2sgIkNvbnRpbnVlIiAoZm9yIEludHJvZHVjdGlvbikNCiAgICBiLgljbGljayAiQ29udGludWUiIChmb3IgUmVhZCBNZSkNCiAgICBjLgljbGljayAiQ29udGludWUiCShmb3IgTGljZW5zZSkNCiAgICBkLgljbGljayAiQWdyZWUiDQogICAgZS4JY2xpY2sgIkluc3RhbGwiCShmb3IgSW5zdGFsbGF0aW9uIFR5cGUpDQogICAgZi4JaWYgYXNrZWQsIHByb3ZpZGUgcGFzc3dvcmQgdG8gYWxsb3cgaW5zdGFsbGF0aW9uIG9mIHNvZnR3YXJlDQogICAgZy4JY2xpY2sgIkluc3RhbGwgU29mdHdhcmUiDQogICAgaC4JV2hlbiBpbnN0YWxsYXRpb24gaXMgY29tcGxldGUgY2xpY2sgIkNsb3NlIg0KDQoNCjIuIERvdWJsZSBjbGljayAqKlJTdHVkaW8teC54Lnh4eHguZG1nKioNCiAgICBhLiBpbiB3aW5kb3cgdGhhdCBvcGVucyB1cCwgZHJhZyBSU3R1ZGlvIGljb24gaW50byBBcHBsaWNhdGlvbnMgZm9sZGVyDQogICAgYi4gV2hlbiBpbnN0YWxsYXRpb24gaXMgZG9uZSwgeW91IGNhbiBjbGljayBvbiB0aGUgUlN0dWRpbyBpY29uIGluIHRoZSBMYXVuY2hwYWQNCiAgICBjLiBJZiBhc2tlZCAi4oCdUlN0dWRpb+KAnSBpcyBhbiBhcHBsaWNhdGlvbiBkb3dubG9hZGVkIGZyb20gdGhlIEludGVybmV0LiBBcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gb3BlbiBpdD8iDQogICAgZC4gSWYgYXNrZWQgdG8gaW5zdGFsbCBhICJnaXQiIGNvbW1hbmQgLSBjbGljayAiaW5zdGFsbCIgYW5kIHRoZW4gY2xpY2sgb24gImFncmVlIiANCg0KWyoqKlN0ZXAgMyBpcyBub3QgbmVjZXNzYXJ5IGlmIHlvdSBhcmUgaW5zdGFsbGluZyB0aGUgcGFja2FnZXMgYnkgcnVubmluZyB0aGUgY29tbWFuZHMgYmVsb3cgdW5kZXIgIkluc3RhbGxhdGlvbiBvZiBQYWNrYWdlcyIqKipdDQoNCjMuIFBhY2thZ2VzIGdvIGludG86DQogICAgYS4JTWFjaW50b3NoIEhEL0xpYnJhcnkvRnJhbWV3b3Jrcy9SLmZyYW1ld29yay9WZXJzaW9ucy8qdmVyc2lvbiMqL1Jlc291cmNlcy9saWJyYXJ5IA0KICAgIGIuCUFjY2VwdCB0byBvdmVyd3JpdGUgY3VycmVudCBwYWNrYWdlcw0KPC9kaXY+DQogDQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCiANCiMjIFJlc291cmNlcyBmb3IgSW5zdGFsbGluZyB0aGUgQW5hbHlzaXMgVG9vbHBhayBpbiBFeGNlbDoNCg0KSWYgY29uZHVjdGluZyBtb3JlIGRldGFpbGVkIGFuYWx5c2lzIGluICoqKkV4Y2VsKioqLCBpdCBpcyBuZWNlc3NhcnkgdG8gaW5zdGFsbCBhbmQgbG9hZCB0aGUgQW5hbHlzaXMgVG9vbHBhay4gRm9yIGluc3RydWN0aW9ucyBvbiBsb2FkaW5nIHRoZSBBbmFseXNpcyBUb29sUGFrIGluIEV4Y2VsIHNlZToNCg0KICAqIEZvciBbKipXaW5kb3dzKipdKGh0dHBzOi8vc3VwcG9ydC5vZmZpY2UuY29tL2VuLWllL2FydGljbGUvbG9hZC10aGUtYW5hbHlzaXMtdG9vbHBhay1pbi1leGNlbC02YTYzZTU5OC1jZDZkLTQyZTMtOTMxNy02YjQwYmExYTY2YjQjT2ZmaWNlVmVyc2lvbj1XaW5kb3dzKXt0YXJnZXQ9Il9ibGFuayJ9DQogICogRm9yIFsqKk1hY3MqKl0oaHR0cHM6Ly9zdXBwb3J0Lm9mZmljZS5jb20vZW4taWUvYXJ0aWNsZS9sb2FkLXRoZS1hbmFseXNpcy10b29scGFrLWluLWV4Y2VsLTZhNjNlNTk4LWNkNmQtNDJlMy05MzE3LTZiNDBiYTFhNjZiNCNPZmZpY2VWZXJzaW9uPU1hY09TKXt0YXJnZXQ9Il9ibGFuayJ9IA0KICAqIFVzZSB0aGUgW0FuYWx5c2lzIFRvb2xQYWtdKGh0dHBzOi8vc3VwcG9ydC5vZmZpY2UuY29tL2VuLXVzL2FydGljbGUvdXNlLXRoZS1hbmFseXNpcy10b29scGFrLXRvLXBlcmZvcm0tY29tcGxleC1kYXRhLWFuYWx5c2lzLTZjNjdjY2YwLWY0YTktNDg3Yy04ZGVjLWJkYjVhMmNlZmFiNil7dGFyZ2V0PSJfYmxhbmsifSB0byBwZXJmb3JtIGNvbXBsZXggZGF0YSBhbmFseXNpcw0KDQoqKioNCiMgR2VuZXJhbCBOb3RlcyBmb3IgUg0KICAqIHBvdW5kICgjKSBzaWduIGluZGljYXRlcyBhIGNvbW1lbnQgLSBub3QgcmVhZCBieSB0aGUgcHJvZ3JhbQ0KICAqIGNvbnNvbGUgaXMgdGhlIHdpbmRvdyBpbiB3aGljaCB5b3Ugd2lsbCBydW4gdGhlIGNvbW1hbmRzDQogICogSWYgeW91IGNsaWNrIGluIHRoZSBjb25zb2xlLCBhbmQgQ3RybCBMIC0gY2xlYXJzIHRoZSBjb25zb2xlDQogICogSWYgZXZlciB5b3UncmUgc3R1Y2sgd2l0aCBhIHBsdXMgKCspc2lnbiBhbmQgY2Fubm90IGdldCB0aGUgY3Vyc29yICg+KSBiYWNrLCBwcmVzcyAqKkN0cmwrQyoqIChmb3IgYm90aCBNYWNzIGFuZCBQQ3MpDQogICogb2JqZWN0OiBhbiBvYmplY3QgY29udGFpbnMgYSBncmFwaCwgdGhlIGRhdGEgZXRjLiAtIHdoYXRldmVyIHlvdSBwdXQgaXQgaW4gaXQuDQogICogPC0gaXMgZXF1aXZhbGVudCB0byA9IA0KICAqIG9iamVjdCRjb2x1bW5uYW1lOiBpbmRpY2F0ZXMgdGhlIG5hbWUgb2YgdGhlIGNvbHVtbiB3aXRoaW4gdGhlIG9iamVjdA0KICAqIGluc3RhbGwgcGFja2FnZXM6IHJ1biAqKk9OQ0UqKjsgKipORUVEKiogdG8gYmUgY29ubmVjdGVkIHRvIHRoZSBpbnRlcm5ldA0KICAqIExpYnJhcnkgY29tbWFuZDogcnVuICoqRVZFUllUSU1FKiogeW91IG9wZW4gUi1TdHVkaW8NCiAgKiBSICoqSVMgQ0FTRSBTRU5TSVRJVkUqKg0KICAqICoqbmFtZXMqKihvYmplY3QpIDogZ2l2ZXMgdGhlIG5hbWVzIG9mIGFsbCB0aGUgdmFyaWFibGVzIGluIGEgc3BlY2lmaWMgb2JqZWN0IFsibmFtZXMiIGlzIGJvbGRlZCBiL2MgaXQgaXMgYSBjb21tYW5kIGFuZCBkb2VzIG5vdCBjaGFuZ2Ugd2hlbiB1c2VkOyBvbmx5IHRoZSB3b3JkICJvYmplY3QiIGlzIHJlcGxhY2VkIGJ5IHRoZSBhcHByb3ByaWF0ZSBuYW1lIG9mIHRoZSBvYmplY3QgY29udGFpbmluZyB0aGUgZGF0YV0NCiAgKiAqKmxldmVscyoqKG9iamVjdCRuYW1lb2Zjb2x1bW4pIC0gZ2l2ZXMgdGhlIGxldmVscyB3aXRoaW4gdGhlIGNvbHVtbiBvZiBpbnRlcmVzdDsgWyJsZXZlbHMiIGlzIGJvbGRlZCBiL2MgaXQgaXMgYSBjb21tYW5kIGFuZCBkb2VzIG5vdCBjaGFuZ2Ugd2hlbiB1c2VkOyBvbmx5IHRoZSB3b3JkcyAib2JqZWN0IiBhbmQgIm5hbWVvZmNvbHVtbiIgYXJlIHJlcGxhY2VkIGJ5IHRoZSBhcHByb3ByaWF0ZSBuYW1lIG9mIHRoZSBvYmplY3QgY29udGFpbmluZyB0aGUgZGF0YSBhbmQgdGhlIG5hbWUgb2YgdGhlIGNvbHVtbiBvZiBpbnRlcmVzdCByZXNwZWN0aXZlbHldDQogICogSWYgZXZlciB5b3UgbmVlZCB0byBjaGFuZ2UgYSBjb2x1bW4gaW50byBhIGZhY3RvciBiZWNhdXNlIFIgaXMgbm90IHNlZWluZyB0aGUgY29sdW1uIGFzIGEgZmFjdG9yIHVzZSB0aGlzIGNvbW1hbmQ6ICoqKm9iamVjdExcJG5hbWVvZmNvbHVtbiA9IGFzLmZhY3RvcihvYmplY3RMXCRuYW1lb2Zjb2x1bW4pKioqDQoNCioqKg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtZGFuZ2VyIj4NCiMgSW5zdGFsbGF0aW9uIG9mIFBhY2thZ2VzDQogICogSW5zdGFsbGF0aW9uIG9mIHBhY2thZ2VzIGlzIGRvbmUgKipPTkxZIE9OQ0UqKjsgDQogICogRm9yIHRoZSBpbnN0YWxsYXRpb24geW91IE1VU1QgYmUgKioqY29ubmVjdGVkIHRvIHRoZSBpbnRlcm5ldCoqKg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIiwgZGVwZW5kZW5jaWVzID0gVCkgIyB1c2VkIGZvciBnZW5lcmF0aW5nIGdyYXBocw0KaW5zdGFsbC5wYWNrYWdlcygibXVsdGNvbXAiLCBkZXBlbmRlbmNpZXMgPSBUKSAjIHVzZWQgZm9yIHBvc3QtaG9jIGFuYWx5c2lzDQppbnN0YWxsLnBhY2thZ2VzKCJwYXN0ZWNzIiwgZGVwZW5kZW5jaWVzID0gVCkgIyB1c2VkIGZvciBnZW5lcmF0aW5nIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MNCmluc3RhbGwucGFja2FnZXMoInJlc2hhcGUiLCBkZXBlbmRlbmNpZXMgPSBUKSAjIHVzZWQgZm9yIGdlbmVyYXRpbmcgYSBsb25nIHZlcnNpb24gb2YgdGhlIGRhdGEgZnJvbSBhIHdpZGUgdmVyc2lvbiBvZiB0aGUgZGF0YQ0KaW5zdGFsbC5wYWNrYWdlcygicmVzaGFwZTIiLCBkZXBlbmRlbmNpZXMgPSBUKSAjIHVzZWQgdG8gZ2VuZXJhdGUgbG9uZyBmb3JtIG9mIHRoZSBmaWxlOyByZXF1aXJlZCBpbiBzb21lIGNhc2VzDQppbnN0YWxsLnBhY2thZ2VzKCJubG1lIiwgZGVwZW5kZW5jaWVzID0gVCkgIyB1c2VkIGZvciBnZW5lcmF0aW5nIEFOT1ZBcw0KaW5zdGFsbC5wYWNrYWdlcygiY2FyIiwgZGVwZW5kZW5jaWVzID0gVCkNCmluc3RhbGwucGFja2FnZXMoInB3ciIsIGRlcGVuZGVuY2llcyA9IFQpDQppbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIsIGRlcGVuZGVuY2llcyA9IFQpDQppbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIsIGRlcGVuZGVuY2llcyA9IFQpDQppbnN0YWxsLnBhY2thZ2VzKCJybXMiLCBkZXBlbmRlbmNpZXM9VCkgIyBmb3IgcmVncmVzc2lvbg0KaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giLCBkZXBlbmRlbmNpZXM9VCkNCmluc3RhbGwucGFja2FnZXMoImdncHViciIsIGRlcGVuZGVuY2llcz1UKSAjIHJlcXVpcmVkIGZvciBjb3JyZWxhdGlvbiBwbG90cw0KYGBgDQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQojIyBBZGRpdGlvbmFsIHBhY2thZ2VzIChub3QgcmVxdWlyZWQgZm9yIGNsYXNzKQ0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJybWFya2Rvd24iLCBkZXBlbmRlbmNpZXM9VCkgIyBmb3IgUk1EIGZpbGVzIHRoYXQgYWxsb3cgZW1iZWRkaW5nIG9mIGdyYXBocyBldGM7IG5vdCByZXF1aXJlZCBmb3IgY2xhc3MNCmluc3RhbGwucGFja2FnZXMoImptdiIpICMgbm90IHJlcXVpcmVkIGZvciBjbGFzcw0KaW5zdGFsbC5wYWNrYWdlcygidW14IiwgZGVwZW5kZW5jaWVzPVQpICMgRm9yIHN0cnVjdHVyYWwgZXF1YXRpb24gbW9kZWxsaW5nDQppbnN0YWxsLnBhY2thZ2VzKCJzZW1QbG90IiwgZGVwZW5kZW5jaWVzPVQpICMgcmVxdWlyZWQgZm9yIFN0cnVjdHVyYWwgRXF1YXRpb24gTW9kZWxpbmcgYnV0IG5vdCByZXF1aXJlZCBmb3IgY2xhc3MNCmluc3RhbGwucGFja2FnZXMoImxhdmFhbiIsIGRlcGVuZGVuY2llcz1UKSAjIHJlcXVpcmVkIGZvciBTdHJ1Y3R1cmFsIEVxdWF0aW9uIE1vZGVsaW5nIGJ1dCBub3QgcmVxdWlyZWQgZm9yIGNsYXNzOyBzZWUgaHR0cHM6Ly9sYXZhYW4udWdlbnQuYmUvdHV0b3JpYWwvaW5kZXguaHRtbA0KaW5zdGFsbC5wYWNrYWdlcygic2VtIiwgZGVwZW5kZW5jaWVzPVQpICMgcmVxdWlyZWQgZm9yIFN0cnVjdHVyYWwgRXF1YXRpb24gTW9kZWxpbmcgYnV0IG5vdCByZXF1aXJlZCBmb3IgY2xhc3MNCmluc3RhbGwucGFja2FnZXMoIm1hcHMiLCBkZXBlbmRlbmNpZXM9VCkgIyByZXF1aXJlZCBpZiBtYWtpbmcgbWFwIG9mIFVTIC0gb25seSBsb3dlciA0OCBzdGF0ZXMNCmluc3RhbGwucGFja2FnZXMoInVzbWFwIiwgZGVwZW5kZW5jaWVzPVQpICMgcmVxdWlyZWQgaWYgbWFraW5nIG1hcCBvZiBVUyAtIGFsbCA1MCBzdGF0ZXMNCiMgaW5zdGFsbC5wYWNrYWdlcygiUlZBaWRlTWVtb2lyZSIsIGRlcGVuZGVuY2llcyA9IFQpICMgcmVxdWlyZWQgZm9yIHRoZSBGaXNoZXIgVGVzdA0KaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IiwgZGVwZW5kZW5jaWVzPVQpICMgcmVxdWlyZWQgZm9yIDNEIHBsb3RzDQppbnN0YWxsLnBhY2thZ2VzKCJjb21wYXJlR3JvdXBzIikgIyByZXF1aXJlZCBmb3IgZ2VuZXJhdGlvbiBvZiB0YWJsZSBjb21wYXJpbmcgZ3JvdXBzDQppbnN0YWxsLnBhY2thZ2VzKCJsc21lYW5zIiwgZGVwZW5kZW5jaWVzPVQpICMgZm9yIGNvbXBhcmlzb24gb2Ygc2xvcGVzDQppbnN0YWxsLnBhY2thZ2VzKCJlZmZlY3RzaXplIiwgZGVwZW5kZW5jaWVzID0gVCkNCmBgYA0KDQoqKioNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIExvYWRpbmcgcGFja2FnZXMNCiAgKiBQYWNrYWdlcyBuZWVkIHRvIGJlIGxvYWRlZCAqKkVWRVJZIFRJTUUqKiBSIHN0dWRpbyBpcyBzdGFydGVkLg0KICAqIENvcHkgdGhpcyBjb21tYW5kIGFuZCBwYXN0ZSBpbnRvIHRoZSBDb25zb2xlIGFuZCB0aGVuIHByZXNzICJFbnRlciIuIA0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpO2xpYnJhcnkobXVsdGNvbXApO2xpYnJhcnkocGFzdGVjcyk7bGlicmFyeShyZXNoYXBlKTsgbGlicmFyeShyZXNoYXBlMik7IGxpYnJhcnkobmxtZSk7IGxpYnJhcnkoY2FyKTsgbGlicmFyeShwd3IpOyBsaWJyYXJ5KGRwbHlyKTsgbGlicmFyeShkZXZ0b29scyk7IGxpYnJhcnkocm1zKTtsaWJyYXJ5KHBzeWNoKTsgbGlicmFyeShnZ3B1YnIpDQpgYGANCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCiMjIEFkZGl0aW9uYWwgbGlicmFyeSBjb21tYW5kcyAobm90IHJlcXVpcmVkIGZvciBjbGFzcykNCmBgYHtyfQ0KbGlicmFyeSh1bXgpOyBsaWJyYXJ5KGptdik7IGxpYnJhcnkoc2VtKTsgbGlicmFyeShsYXZhYW4pOyBsaWJyYXJ5KHNlbVBsb3QpOyBsaWJyYXJ5KHFncmFwaCk7IGxpYnJhcnkoZm9yZWlnbik7IGxpYnJhcnkodXNtYXApOyBsaWJyYXJ5KG1hcHMpOyAgbGlicmFyeShwbG90bHkpOyBsaWJyYXJ5KFNFTWZuKTsgbGlicmFyeShsc21lYW5zKTsgbGlicmFyeShlZmZlY3RzaXplKTsgbGlicmFyeShyb3h5Z2VuMikNCg0KbGlicmFyeShSVkFpZGVNZW1vaXJlKQ0KYGBgDQoNCioqKg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtc3VjY2VzcyI+DQojIENvcHlpbmcgRGF0YSBmcm9tIEV4Y2VsIGludG8gUg0KDQojIyBGb3IgUEMNCiAgMS4gQ29weSB0aGUgY29tbWFuZCBiZWxvdyAoQ3RybCtDKQ0KICAyLiBQYXN0ZSBjb21tYW5kIGludG8gUiBTdHVkaW8gQ29uc29sZSAoQ3RybCtWKQ0KICAzLiBDaGFuZ2UgdGhlIG5hbWUgIm9iamVjdCIgdG8gc29tZXRoaW5nIHRoYXQgbWFrZXMgc2Vuc2UgdG8geW91IGFuZCBpcyByZWxhdGVkIHRvIHRoZSBkYXRhLg0KICA0LiBJbiAqKkV4Y2VsKiosIHNlbGVjdCB0aGUgZGF0YSB5b3Ugd2FudCB0byBhbmFseXplOyBJbmNsdWRlIHRoZSBoZWFkZXI7IA0KICA1LiBDb3B5IHRoZSBkYXRhIChDdHJsK0MpDQogIDYuIEdvIGJhY2sgdG8gUiBTdHVkaW8gYW5kIHJ1biAoKipwcmVzcyAiRW50ZXIiKiopIHRoZSBjb21tYW5kIHlvdSBwYXN0ZWQgZWFybGllciAoaW4gc3RlcCAyKSBpbnRvIHRoZSBjb25zb2xlIA0KYGBge3J9DQpvYmplY3QgPSByZWFkLnRhYmxlKGZpbGU9ImNsaXBib2FyZCIsIHNlcD0iXHQiLCBoZWFkZXI9VFJVRSkNCmBgYA0KDQogICogSWYgeW91IGhhdmUgbWlzc2luZyBkYXRhIHBvaW50cyBpbiB5b3VyIGZpbGUgdGhhdCB5b3Ugc3RpbGwgd2FudCBpbXBvcnRlZCBpbnRvIHRoZSBkYXRhZnJhbWUsIHVzZSB0aGUgZm9sbG93aW5nIGNvbW1hbmQ6DQpgYGB7cn0NCm9iamVjdCA9IHJlYWQuY3N2KGZpbGU9ImNsaXBib2FyZCIsIHNlcD0iXHQiLCBoZWFkZXI9VFJVRSkNCmBgYA0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtc3VjY2VzcyI+DQojIyBGb3IgTWFjDQogIDEuIENvcHkgdGhlIGNvbW1hbmQgYmVsb3cgKENtZCtDKQ0KICAyLiBQYXN0ZSBjb21tYW5kIGludG8gUiBTdHVkaW8gQ29uc29sZSAoQ21kK1YpDQogIDMuIENoYW5nZSB0aGUgbmFtZSAib2JqZWN0IiB0byBzb21ldGhpbmcgdGhhdCBtYWtlcyBzZW5zZSB0byB5b3UgYW5kIGlzIHJlbGF0ZWQgdG8gdGhlIGRhdGEuDQogIDQuIEluICoqRXhjZWwqKiwgc2VsZWN0IHRoZSBkYXRhIHlvdSB3YW50IHRvIGFuYWx5emU7IEluY2x1ZGUgdGhlIGhlYWRlcjsgDQogIDUuIENvcHkgdGhlIGRhdGEgKENtZCtDKQ0KICA2LiBHbyBiYWNrIHRvIFIgU3R1ZGlvIGFuZCBydW4gKCoqcHJlc3MgIkVudGVyIioqKSB0aGUgY29tbWFuZCB5b3UgcGFzdGVkIGVhcmxpZXIgKGluIHN0ZXAgMikgaW50byB0aGUgY29uc29sZQ0KYGBge3J9DQpvYmplY3QgPSByZWFkLnRhYmxlKHBpcGUoInBicGFzdGUiKSwgc2VwPSJcdCIsIGhlYWRlciA9IFRSVUUpDQpgYGANCg0KICAqIElmIHlvdSBoYXZlIG1pc3NpbmcgZGF0YSBwb2ludHMgaW4geW91ciBmaWxlIHRoYXQgeW91IHN0aWxsIHdhbnQgaW1wb3J0ZWQgaW50byB0aGUgZGF0YWZyYW1lLCB1c2UgdGhlIGZvbGxvd2luZyBjb21tYW5kOg0KICANCmBgYHtyfQ0Kb2JqZWN0ID0gcmVhZC5jc3YocGlwZSgicGJwYXN0ZSIpLCBzZXA9Ilx0IiwgaGVhZGVyID0gVFJVRSkNCmBgYCANCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCioqKg0KIyBJbXBvcnRpbmcgRGF0YSBpbnRvIFIgZnJvbSBFeGNlbCAoeGxzeCkgZmlsZXMNCiANCiMjIEltcG9ydGFudCBOb3RlczogDQogICogKipJZiB5b3UgYXJlIGdvaW5nIHRvIHVzZSB0aGlzIG1ldGhvZCwgeW91IG5lZWQgdG8gbWFrZSBzdXJlIHRoYXQgeW91ciBleGNlbCBmaWxlIGhhcyBhIHNob3J0IG5hbWUgd2l0aCBubyBzcGFjZXMqKg0KICAqIElmIHlvdSB3aXNoIHRvICoqbmFtZSB0aGUgb2JqZWN0KiogY29udGFpbmluZyB0aGUgZGF0YSBzb21ldGhpbmcgZGlmZmVyZW50IGZyb20gdGhlIG9yaWdpbmFsIEV4Y2VsIG5hbWUsIHR5cGUgaW4gdGhlIG5ldyBuYW1lIGluIHRoZSAqKiJOYW1lOiIqKiBib3ggdW5kZXIgKioiSW1wb3J0IE9wdGlvbnMiKioqKg0KICAqIElmIHlvdSBoYXZlICoqbW9yZSB0aGFuIG9uZSBzaGVldCBvZiBkYXRhKiogaW4gdGhlIGV4Y2VsIGZpbGUsIHlvdSB3aWxsIG5lZWQgdG8gc3BlY2lmeSB3aGljaCBzaGVldCB0aGUgZGF0YSBpcyBjb21pbmcgZnJvbSBpbiB0aGUgKioiU2hlZXQ6IioqIGJveCB1bmRlciAqKiJJbXBvcnQgT3B0aW9ucyIqKiBzZWN0aW9uIGluIHRoZSAqKiJJbXBvcnQgRXhjZWwgRGF0YSB3aW5kb3ciKioNCg0KIyMgUHJvY2VkdXJlOiANCiAgKiBHbyB0byAqKiJGaWxlPkltcG9ydCBEYXRhIFNldD5Gcm9tIEV4Y2VsLi4uIioqDQogICogUiBvcGVucyB3aW5kb3cgY2FsbGVkICoqIkltcG9ydCBFeGNlbCBEYXRhIioqDQogICogQ2xpY2sgb24gKioiQnJvd3NlLi4uIioqIA0KICAqIFNlbGVjdCB0aGUgRXhjZWwgZmlsZSB5b3Ugd2FudCB0byBpbXBvcnQNCiAgKiBSIHdpbGwgZGlzcGxheSB0aGUgZGF0YSBpbiB0aGUgKioiRGF0YSBQcmV2aWV3IioqIHdpbmRvdzsgW3NlZSBub3RlIGFib3ZlIGlmIHlvdXIgZXhjZWwgZmlsZSBjb250YWlucyBtb3JlIHRoYW4gb25lIGRhdGEgc2hlZXQgb3IgeW91IHdpc2ggdG8gbmFtZSB5b3VyIG9iamVjdCBzb21ldGhpbmcgZGlmZmVyZW50IGZyb20gdGhlIGV4Y2VsIGZpbGUgbmFtZV0NCiAgKiBDbGljayAqKiJJbXBvcnQiKiogYW5kIHRoZSBkYXRhIGlzIG5vdyBpbXBvcnRlZCBhbmQgd2lsbCBiZSBkaXNwbGF5ZWQNCg0KICANCiMgSW1wb3J0aW5nIERhdGEgaW50byBSIGZyb20gQ1NWIGZpbGVzDQpgYGB7cn0NCm9iamVjdCA9IHJlYWQuY3N2KGZpbGUuY2hvb3NlKCksIGhlYWRlcj1UKQ0KYGBgDQogICogb2JqZWN0OiBuYW1lIG9mIHRoZSBvYmplY3QgLSBjYWxsIGl0IGFzIHlvdSB3aXNoOyBzaG91bGQgYmUgcmVsYXRlZCB0byB0aGUgZGF0YSB5b3UgYXJlIGltcG9ydGluZzsgc2hvdWxkIHNpbXBsZTsgTk8gc3BhY2VzOyBzaG91bGQgc2hvcnQuDQogICogcmVhZC5jc3Y6IHRlbGxzIHRoZSBwcm9ncmFtIHlvdSBhcmUgZ29pbmcgdG8gaW1wb3J0IGEgQ1NWIGZpbGUNCiAgKiBmaWxlLmNob29zZSAoKTogdGVsbHMgdGhlIHByb2dyYW0gdG8gb3BlbiBhIHdpbmRvdyBmb3IgeW91IHRvIHNlbGVjdCB0aGUgZmlsZSBvZiBpbnRlcmVzdA0KICAqIGhlYWRlciA9IFQ6IHRoaXMgaW5kaWNhdGVzIHRoYXQgeW91IENTViBmaWxlIGhhcyBhIGhlYWRlcg0KICAqIHRoZSBPTkxZIHdvcmQgeW91IG5lZWQgdG8gY2hhbmdlIGluIHRoaXMgY29tbWFuZCBpcyB0aGUgbmFtZSBvZiB0aGUgb2JqZWN0DQogIA0KIyBJbXBvcnRpbmcgRGF0YSBpbnRvIFIgZnJvbSBTUFNTIGZpbGVzDQogICogdG8gaW1wb3J0ICouc2F2IGZpbGVzIGZyb20gU1BTUyB5b3UgZmlyc3QgbmVlZCB0byBydW4gdGhlIGZvbGxvd2luZyBsaWJyYXJ5IGNvbW1hbmQNCg0KYGBge3J9DQpsaWJyYXJ5KGZvcmVpZ24pDQpgYGANCg0KYGBge3J9DQpvYmplY3QgPSByZWFkLnNwc3MoZmlsZS5jaG9vc2UoKSwgdG8uZGF0YS5mcmFtZT1UUlVFKQ0KYGBgDQogICogcmVhZC5zcHNzOiB0ZWxscyB0aGUgcHJvZ3JhbSB5b3UgYXJlIGdvaW5nIHRvIGltcG9ydCBhbiBTUFNTIGZpbGUNCiAgKiBmaWxlLmNob29zZSAoKTogdGVsbHMgdGhlIHByb2dyYW0gdG8gb3BlbiBhIHdpbmRvdyBmb3IgeW91IHRvIHNlbGVjdCB0aGUgZmlsZSBvZiBpbnRlcmVzdA0KICAqIHRoZSBPTkxZIHdvcmQgeW91IG5lZWQgdG8gY2hhbmdlIGluIHRoaXMgY29tbWFuZCBpcyB0aGUgbmFtZSBvZiB0aGUgb2JqZWN0DQoNCioqKg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtc3VjY2VzcyI+DQoNCiMgRXhwb3J0aW5nIGZyb20gUg0KIyMgRXhwb3J0aW5nIG91dHB1dCB0byBhIHRleHQgZmlsZQ0KYGBge3J9DQpzaW5rKCJvdXRwdXRuYW1lLnR4dCIpDQoNCiMgUlVOIFRIRSBDT01NQU5EUyBZT1UgV0lTSCBZTyBCRSBFWFBPUlRFRCBUTyBUSEUgVEVYVCBGSUxFDQoNCnNpbmsoKQ0KZ2V0d2QoKSAjIGdpdmVzIHdvcmtpbmcgZGlyZWN0b3J5DQoNCiMgdG8gaW1wb3J0IGludG8gZXhjZWwsIHNlbGVjdCB0aGUgZmlsZSBhbmQgdXNlIHRoZSAic3BhY2UgZGVsaW1pdGVkIiBvcHRpb24sIGFuZCB0aGVuIGNoZWNrIHRoZSBzcGFjZSBjaGVja2JveC4NCmBgYA0KDQojIyBFeHBvcnRpbmcgZGF0YWZyYW1lIHRvIGEgY3N2IGZpbGUNCmBgYHtyfQ0Kd3JpdGUuY3N2KGRhdGFmcmFtZSwibmFtZS5jc3YiKQ0KZ2V0d2QoKSAjIGdpdmVzIHdvcmtpbmcgZGlyZWN0b3J5DQpgYGANCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCioqKg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQojIFZpZXdpbmcgaW1wb3J0ZWQgZGF0YQ0KYGBge3J9DQpWaWV3KG9iamVjdCkgIyBhbGxvd3MgeW91IHRvIHNlZSB0aGUgZGF0YSBpbiBhbm90aGVyIHRhYg0KYGBgDQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQoqKioNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPg0KIyBNZWx0aW5nIHlvdXIgZGF0YQ0KIyMgUGVyZm9ybWluZyBhIHNpbXBsZSBtZWx0aW5nIG9mIGRhdGENCmBgYHtyfQ0Kb2JqZWN0TCA9IG1lbHQob2JqZWN0LCBpZD0iaWRuYW1lIikNCmBgYA0KICAqIG1lbHQgY29udmVydHMgZmlsZSBmcm9tIHdpZGUgdG8gbG9uZyB2ZXJzaW9uDQogICogb2JqZWN0TDogTkVXIG9iamVjdCB0aGF0IHdpbGwgY29udGFpbiB0aGUgbG9uZyB2ZXJzaW9uIG9mIHRoZSBmaWxlDQogICogb2JqZWN0OiBuYW1lIG9mIHRoZSBvZiB0aGUgb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdpZGUgdmVyc2lvbiBvZiB0aGUgZGF0YQ0KICAqIGlkPSJpZG5hbWUiOiB0aGlzIGlzIG9ubHkgdXNlZCBTT01FVElNRVM7IG9ubHkgd2hlbiB5b3UgaGF2ZSBhbiBJRCBjb2x1bSAoYSBjb2x1bW4gdGhhdCBpZGVudGlmaWVzIHRoZSBzdWJqZWN0IGluIHNvbWUgd2F5IGFuZCBkb2VzIG5vdCBjaGFuZ2UvaXMgY29uc3RhbnQpDQogICogSW4gY2FzZSBvZiBhIGZpbGUgd2l0aCBhbiBJRCBjb2x1bW4sIHJlcGxhY2UgdGhlIGlkbmFtZSB3aXRoIHRoZSBhcHByb3ByaWF0ZSBuYW1lIG9mIHRoZSBjb2x1bW4NCiAgKiBJZiB0aGVyZSBpcyBOTyBJRCBDT0xVTU47IHlvdSBjYW4gc2ltcGx5ICoqZGVsZXRlKiogdGhlIHBhcnQgb2YgdGhlIGNvbW1hbmQgZnJvbSB0aGUgY29tbWEgb253YXJkcyBpLmUuLCAqLCBpZD0iaWRuYW1lIicqIGJ1dCBrZWVwIHRoZSBjbG9zZSBwYXJlbnRoZXNpcy4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPg0KIyBNZWx0aW5nIGRhdGEgd2l0aCBtdWx0aXBsZSBpZCB2YXJpYWJsZXMgYW5kIG1lYXN1cmUgdmFyaWFibGVzDQpgYGB7cn0NCm9iamVjdF9MPW1lbHQob2JqZWN0LCBpZC52YXJzID0gYygiaWR2YXJfMSIsICJpZHZhcl8yIiwgImlkdmFyX24iKSwgbWVhc3VyZS52YXJzID0gYygibXZhcl8xIiwgIm12YXJfMiIsICJtdmFyX24iKSkNCmBgYA0KICAqIGlkdmFyXzEgZXRjLiA9IHJlcGxhY2UgdGhlc2Ugd2l0aCB0aGUgYXBwcm9wcmlhdGUgbmFtZXMgb2YgdGhlIGNvbHVtbnMgY29udGFpbmluZyB0aGUgaWQgdmFyaWFibGVzDQogICogbXZhcl8xIGV0Yy4gPSByZXBsYWNlIHRoZXNlIHdpdGggdGhlIG1lYXN1cmUgdmFyaWFibGUgY29sdW1uIG5hbWVzDQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQoqKioNCiMgU2VsZWN0aW5nIHNwZWNpZmljIHN1YnNldCB0byBhbmFseXplDQoNCmBgYHtyfQ0KdmFyX2EgPSBvYmplY3QkYG91dGNvbWVgW29iamVjdCRwcmVkaWN0b3IxY29sbmFtZT09InByZWRpY3RvcjEiICYgb2JqZWN0JHByZWRpY3RvcjJjb2xuYW1lPT0icHJlZGljdG9yMiJdDQpgYGANCg0KICAqIHZhcl9hOiBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgd2lsbCBjb250YWluIHN1YnNldA0KICAqIG9iamVjdCRwcmVkaWN0b3IxY29sbmFtZTogbmFtZSBvZiBjb2x1bW4gY29udGFpbmluZyAicHJlZGljdG9yMSIgaW4gb2JqZWN0DQogICogPT06ICJ0cnVseSBlcXVhbCB0byINCiAgDQoqKioNCiMgR2VuZXJhdGluZyBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGluIFINCiMjIFdlaWdodGVkIG1lYW4NCmBgYHtyfQ0Kd3QgPC0gYyh3MSwgIHcyLCAgdzMsICB3NCwgZXRjKS8od1QpICMgdGhlIHdlaWdodCBmb3IgdGhlIGZpcnN0IHZhbHVlID0geCBtdWx0aXBsaWVkIHcxL3dUIChlLmcuIGlmIHdlaWdodCBmb3IgdzEgaXMgMjUlIHcxIHdvdWxkIGJlIDI1LCB3VCB3b3VsZCBiZSAxMDApDQp4IDwtIGMoeDEsIHgyLCB4MywgeDQsIGV0YykgIyB2YWx1ZXMgdG8gYmUgd2VpZ2h0ZWQNCnhtIDwtIHdlaWdodGVkLm1lYW4oeCwgd3QpDQpgYGANCg0KIyMgTWVhbg0KYGBge3J9DQptZWFuKGMoeDEsIHgyLCB4MywgeDQuLi4pKQ0KYGBgDQoNCiMjIERlc2NyaXB0aXZlIHN0YXRpc3RpY3MgZm9yICoqV0lERSoqIHZlcnNpb24gb2YgZGF0YSB0byAyIGRlY2ltYWwgcGxhY2VzDQpgYGB7cn0NCnJvdW5kKHN0YXQuZGVzYyhvYmplY3QsIG5vcm09VCksIGRpZ2l0cz0yKQ0KYGBgDQogICogZ2l2ZXMgdGhlIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgZm9yIGFsbCB2YXJpYWJsZXMgdG8gVFdPIGRlY2ltYWwgcGxhY2UgKHlvdSBjYW4gYWRqdXN0IHRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgYnkgc2ltcGx5IGNoYW5naW5nIHRoZSBudW1iZXIgYWZ0ZXIgZGlnaXRzPSkNCiAgKiBvYmplY3Q6IHJlcGxhY2UgdGhpcyB3aXRoIG5hbWUgb2Ygb2JqZWN0IGNvbnRhaW5pbmcgdGhlIFdJREUgdmVyc2lvbiBvZiB0aGUgZGF0YQ0KICAqIE9OTFkgdXNlZCB3aXRoIHRoZSBXSURFIHZlcnNpb24gb2YgdGhlIGRhdGENCg0KIyMgRGVzY3JpcHRpdmUgc3RhdGlzdGljcyBmb3IgaW5kaXZpZHVhbCBjb2x1bW5zIG9mIGRhdGEgdG8gMiBkZWNpbWFsIHBsYWNlcyBpbiAqKldJREUqKiB2ZXJzaW9uIG9mIGRhdGENCmBgYHtyfQ0Kcm91bmQoc3RhdC5kZXNjKG9iamVjdCRjb2x1bW5uYW1lLCBub3JtPVQpLCBkaWdpdHMgPTIpDQpgYGANCiAgKiBnaXZlcyB0aGUgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBmb3IgdGhlIFdJREUgdmVyc2lvbiBvZiB0aGUgZmlsZSBidXQgT05MWSBmb3IgYSBTUEVDSUZJQyBDT0xVTU4NCiAgKiBvYmplY3Q6IG5lZWRzIHRvIGJlIHJlcGxhY2VkIHdpdGggdGhlIG5hbWUgb2YgdGhlIHdpZGUgdmVyc2lvbiBvZiB0aGUgZGF0YQ0KICAqIGNvbHVtbm5hbWU6IG5lZWRzIHRvIGJlIHJlcGxhY2VkIHdpdGggdGhlIG5hbWUgb2YgdGhlIGNvbHVtbiBmb3Igd2hpY2ggeW91IHdpc2ggdG8gZ2VuZXJhdGUgdGhlIHN0YXRpc3RpY3MuDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGZvciAqKkxPTkcqKiB2ZXJzaW9uIG9mIGRhdGENCmBgYHtyfQ0KYnkob2JqZWN0TCRvdXRjb21lLCBvYmplY3RMJHByZWRpY3Rvciwgc3RhdC5kZXNjLCBub3JtPVQpDQpgYGANCiAgKiBnaXZlcyB0aGUgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBmb3IgdGhlIExPTkcgdmVyc2lvbiBvZiB0aGUgZGF0YQ0KICAqIG9iamVjdEw6IHJlcGxhY2Ugd2l0aCBuYW1lIG9mIHRoZSBvYmplY3QgY29udGFpbmluZyB0aGUgTE9ORyB2ZXJzaW9uIG9mIGRhdGENCiAgKiBvdXRjb21lOiByZXBsYWNlIHdpdGggbmFtZSBvZiBvdXRjb21lIGNvbHVtbiBpbiBvYmplY3RMDQogICogcHJlZGljdG9yOiByZXBsYWNlIHdpdGggbmFtZSBvZiBwcmVkaWN0b3IgY29sdW1uIGluIG9iamVjdEwNCg0KICAqIG5ici52YWw6IG51bWJlciBvZiB2YWx1ZXMvc3ViamVjdHMgaW4gYSBwYXJ0aWN1bGFyIGdyb3VwDQogICogbmJyLm51bGw6IG51bWJlciBvZiBaRVJPIHZhbHVlcw0KICAqIG5ici5uYTogbnVtYmVyIG9mIE1JU1NJTkcgdmFsdWVzDQogICogbWluL21heDogbWluaW11bSBhbmQgbWF4aW11bSB2YWx1ZXJzIGluIGEgZ3JvdXAgcmVzcGVjdGl2ZWx5DQogICogcmFuZ2U6IGdpdmVzIHlvdSB0aGUgcmFuZ2UNCiAgKiBzdW06IGdpdmVzIHRoZSBzdW0gb2YgYWxsIHZhbHVlcyBpbiBhIGdyb3VwDQoNCiMjIyBNZWFzdXJlcyBvZiBjZW50cmFsaXR5Og0KICArIG1lZGlhbjogZ2l2ZXMgdGhlIG1lZGlhbiBvZiB2YWx1ZXMgaW4gYSBncm91cA0KICArIG1lYW46IGdpdmVzIHRoZSBhdmVyYWdlIG9mIHZhbHVlcyBpbiBhIGdyb3VwDQoNCiMjIyBNZWFzdXJlcyBvZiB2YXJpYWJpbGl0eToNCiAgKyBTRS5tZWFuOiBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVhbg0KICArIENJLm1lYW4uOTU6IDk1JSBjb25maWRlbmNlIGludGVydmFsDQogICsgdmFyOiB2YXJpYW5jZQ0KICArIHN0ZC5kZXY6IHN0YW5kYXJkIGRldmlhdGlvbg0KICArIGNvZWYudmFyOiBjb2VmZmljaWVudCBvZiB2YXJpYXRpb24NCg0KIyMjIE1lYXN1cmVzIG9mIG5vcm1hbGl0eToNCiAgKyBza2V3bmVzczogbWVhc3VyZXMgb2YgbGV2ZWwgb2Ygc2tld25lc3Mgb2YgeW91ciBkYXRhLCBhIG5lZ2F0aXZlIHNpZ24gaW1wbGllcyBhIG5lZ2F0aXZlIHNrZXc7DQogICsgc2tldy4yU0U6IGluZGljYXRlcyB3aGV0aGVyIHRoZSBza2V3bmVzcyBpcyBTSUdOSUZJQ0FOVC4gU2tld25lc3MgaXMgc2lnbmlmaWNhbnQgaWYgc2tldy4yU0UgPiArMSBvciA8LTENCiAgKyBrdXJ0b3NpczogbWVhc3VyZSBvZiBsZXZlbCBvZiBrdXJ0b3NpcyBvZiB0aGUgZGF0YS4gQSBuZWdhdGl2ZSBzaWduIGltcGxpZXMgYSBuZWdhdGl2ZSBrdXJ0b3Npcy4NCiAgKyBrdXJ0LjJTRTogaW5kaWNhdGVzIHdoZXRoZXIgdGhlIGt1cnRvc2lzIGlzIFNJR05JRklDQU5ULiBrdXJ0b3NpcyBpcyBzaWduaWZpY2FudCBpZiBrdXJ0LjJTRSA+ICsxIG9yIDwtMQ0KICArIG5vcm10ZXN0Lnc6IHRlc3QgZm9yIG5vcm1hbGl0eQ0KICArIG5vcm10ZXN0LnA6IGlmIG5vcm10ZXN0LnA8MC4wNSwgdGhlIHRoZSBkYXRhIGlzIE5PVCBub3JtYWxseSBkaXN0cmlidXRlZC4NCiAgKyBXaGVuIGNoZWNraW5nIGZvciBub3JtYWxpdHkgLSAqKkZJUlNUKiogbG9vayBhdCB0aGUgbm9ybXRlc3QucC4gSWYgdGhpcyB2YWx1ZSBpcyBncmVhdGVyIHRoYW4gMC4wNSwgdGhlbiB5b3UgaGF2ZSBub3RoaW5nIHRvIHdvcnJ5IGFib3V0LiBJZiB0aGlzIHZhbHVlIGlzIGxlc3MgdGhhbiAwLjA1IHRoZW4geW91IG5lZWQgdG8gbG9vayBhdCB0aGUgc2tldy4yU0UgYW5kIGt1cnQuMlNFIGluIG9yZGVyIHRvIGRldGVybWluZSB3aGljaCBhc3BlY3QgaXMgY2F1c2luZyB5b3VyIGRhdGEgdG8gbm90IGJlIG5vcm1hbC4gSWYgeW91ciBkYXRhIGlzIE5PVCBub3JtYWxseSBkaXN0cmlidXRlZCwgb3RoZXIgc3RhdGlzdGljYWwgdGVzdHMgYXBwbHkuDQoNCiMjIyBFeGFtcGxlIG9mIG91dHB1dCBnZW5lcmF0ZWQgd2l0aCBwcmV2aW91cyBjb21tYW5kDQo8Y2VudGVyPg0KIVtdKEM6L1VzZXJzXHNzYW1tXERlc2t0b3BcU2FtbXV0XFJlc2VhcmNoXFIgTWFya2Rvd24vQnlPdXRwdXQucG5nKXt3aWR0aD02NSV9DQo8L2NlbnRlcj4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCiMjIyBBbHRlcm5hdGl2ZSBtZXRob2QNCg0KYGBge3J9DQpkZXNjcmliZUJ5KG91dGNvbWV+cHJlZGljdG9yLCBkYXRhID0gb2JqZWN0TCwgZGlnaXRzPTIsIG1hdD1UUlVFKQ0KYGBgDQojIyMgRXhhbXBsZSBvZiBvdXRwdXQgZ2VuZXJhdGVkIHdpdGggcHJldmlvdXMgY29tbWFuZA0KPGNlbnRlcj4NCiFbXShDOi9Vc2Vyc1xzc2FtbVxEZXNrdG9wXFNhbW11dFxSZXNlYXJjaFxSIE1hcmtkb3duL2Rlc2NyaWJlQnkucG5nKXt3aWR0aD03MCV9DQo8L2NlbnRlcj4NCg0KICArIHRoaXMgb3V0cHV0IGlzIG5pY2UgYW5kIGNvbmNpc2UgYnV0IGRvZXMgbm90IGNvbnRhaW4gZXZlcnl0aGluZyBpbmNsdWRlZCBpbiB0aGUgcHJldmlvdXMgbWV0aG9kIChlLmcuIG5vIGluZGljYXRpb24gb2Ygc2lnbmlmaWNhbmNlIGluIHJlbGF0aW9uIHRvIHRoZSBkZXZpYXRpb25zIGZyb20gbm9ybWFsaXR5IChza2V3bmVzcy9rdXJ0b3NpcykpDQoNCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8Y2VudGVyPg0KDQojIyMgQW5vdGhlciBNZXRob2Qgb2YgcHJlc2VudGluZyBTdGF0aXN0aWNzDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXN1Y2Nlc3MiPg0KICAqIHRoaXMgbWV0aG9kIGdlbmVyYXRlcyBwcmVzZW50YWJsZSB0YWJsZXMgYXMgYW4gb3V0cHV0DQogICogcmVxdWlyZXMgInZ0YWJsZSIgcGFja2FnZQ0KYGBge3J9DQpzdChPYmplY3RMLCB2YXJzID0gYygiY29sdW1uMSIpLCBhZGQubWVkaWFuPVRSVUUsIG51bWZvcm1hdD1OQSkgDQpgYGANCiAgKiBnaXZlcyBzdGF0cyBvZiBvbmUgY29sdW1uIHdpdGggMjV0aCwgNTB0aCBhbmQgNzV0aCBwZXJjZW50aWxlcw0KICAqIGNvbHVtbjEgLT4gcmVwbGFjZSB3aXRoIHRoZSBuYW1lIG9mIHRoZSBjb2x1bW4gZm9yIHdoaWNoIHlvdSB3aXNoIHRvIGNhbGN1bGF0ZSB0aGUgZGVzY3JpcHRpdmUgc3RhdGlzdGljcy4gT3V0cHV0IHdpbGwgaGF2ZSBOLCBNZWFuIGFuZCBTdGQuRGV2LiwgTWluLCBhbmQgTWF4IGFsc28uDQo8Y2VudGVyPg0KIVtdKEM6L1VzZXJzXHNzYW1tXERlc2t0b3BcU2FtbXV0XFJlc2VhcmNoXFIgTWFya2Rvd24vUnBsb3Qtb25lIGNvbHVtbi5wbmcpe3dpZHRoPTcwJX0NCjwvY2VudGVyPg0KDQpgYGB7cn0NCnN0KE9iamVjdEwsIHZhcnMgPSBjKCJjb2x1bW4xIiksIGdyb3VwID0gJ0dyb3VwJywgYWRkLm1lZGlhbiA9IFRSVUUsIG51bWZvcm1hdD1OQSkNCmBgYA0KICAqIGdpdmVzIHRoZSBzdGF0aXN0aWNzIG9mIGNvbHVtbjEgYWNyb3NzIHRoZSBncm91cCAiR3JvdXAiOw0KICAqIHJlcGxhY2UgImNvbHVtbjEiIHdpdGggdGhlIG5hbWUgb2YgdGhlIGNvbHVtbiBmb3Igd2hpY2ggeW91IHdpc2ggdG8gZ2VuZXJhdGUgZGVzY3JpcHRpdmUgc3RhdGlzdGljczsgDQogICogcmVwbGFjZSAiR3JvdXAiIHdpdGggdGhlIG5hbWUgb2YgdGhlIGNvbHVtbiB0aGF0IGhhcyB0aGUgZ3JvdXBpbmcgdmFyaWFibGUgZS5nLiAiU2V4Ii4NCg0KPGNlbnRlcj4NCiFbXShDOi9Vc2Vyc1xzc2FtbVxEZXNrdG9wXFNhbW11dFxSZXNlYXJjaFxSIE1hcmtkb3duL1JwbG90LWJ5IGdyb3VwLnBuZyl7d2lkdGg9NzAlfQ0KPC9jZW50ZXI+DQo8L2Rpdj4NCioqKg0KIyBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGluIGNhc2VzIG9mIG11bHRpcGxlIGxldmVscyANCmBgYHtyfQ0KZGVzY3JpYmVCeShvdXRjb21lfiB2YXIxICsgdmFyMiwgZGF0YSA9IG9iamVjdCxkaWdpdHM9MiwgbWF0PVRSVUUpDQoNCiMgZS5nLiBpZiB2YXIxID0gc2V4IChNYWxlIG9yIEZlbWFsZSkgYW5kIHZhcjIgPSBjbGFzcyAoRnJlc2htYW4sIFNvcGhvbW9yZSwgSnVuaW9yLCBTZW5pb3IpDQojIGRpZ2l0czogZGVzY3JpYmVzIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcw0KIyBtYXQ6IHByb3ZpZGUgYSBtYXRyaXggb3V0cHV0IHJhdGhlciB0aGFuIGEgbGlzdCANCmBgYA0KDQoqKioNCiMgRXhjZWwgQ29tbWFuZHMgZm9yIHNvbWUgZGVzY3JpcHRpdmUgU3RhdGlzdGljcyAtIG1ldGhvZCAxDQogICogYWxsIGNvbW1hbmRzIHN0YXJ0IHdpdGggYW4gZXF1YWwgc2lnbg0KICAqIG9uY2UgeW91IHNlbGVjdCB0aGUgYXBwcm9wcmlhdGUgY29tbWFuZCAoYWZ0ZXIgdGhlIGVxdWFsIHNpZ24pLCBpbiBwYXJlbnRoZXNpcyB5b3Ugd2lsbCBuZWVkIHRvIGluYnB1dCB0aGUgY2VsbHMgb24gd2hpY2ggeW91IHdhbnQgdG8gZXhlY3V0ZSB0aGF0IGNvbW1hbmQgZS5nLiANCiAgICArID1taW4oQjI6QjEwKSAtIHRoaXMgZ2l2ZXMgdGhlIG1pbmltdW0gZm9yIG51bWJlcnMgaW4gY2VsbHMgQjIgdG8gQjEwDQogICAgKyA9bWF4KEIyOkIxMCkgLSBnaXZlcyB0aGUgbWF4IGZvciBudW1iZXJzIGluIGNlbGxzIEIyIHRvIEIxMA0KICAgICsgPUF2ZXJhZ2UoQjI6QjEwKSAtIGdpdmVzIHRoZSBhdmVyYWdlDQogICAgKyA9TWVkaWFuKEIyOkIxMCkgLSBnaXZlcyB0aGUgbWVkaWFuDQogICAgKyA9dmFyKEIyOkIxMCkgLSBnaXZlcyB0aGUgdmFyaWFuY2UNCiAgICArID1zdGRldihCMjpCMTApIC0gZ2l2ZXMgdGhlIHN0YW5kYXJkIGRldmlhdGlvbg0KICAgICsgPUIxNi9TUVJUKEIxNykgLSBnaXZlcyB0aGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4gV0hFTiBCMTYgY29udGFpbnMgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBhbmQgQjE3IGNvbnRhaW5zIHRoZSBOIChjb3VudCkNCiAgICArICQgc2lnbiBpbiBmcm9udCBvZiB0aGUgbGV0dGVyIChjb2x1bW4pIG9yIG51bWJlciAocm93KSBvZiB0aGUgZm9ybXVsYSBmaXhlcyB0aGUgcm93IG9yIGNvbHVtbiANCg0KKioqDQojIEV4Y2VsIENvbW1hbmRzIGZvciBzb21lIGRlc2NyaXB0aXZlIFN0YXRpc3RpY3MgLSBtZXRob2QgMg0KICAqIFRvIGdpdmUgYSBtb3JlIGRldGFpbGVkIG91dHB1dCwgY2xpY2sgRGF0YSBBbmFseXNpcyBpbiB0aGUgQW5hbHlzaXMgZ3JvdXAgb24gdGhlIERhdGEgdGFiLiANCiAgKiBJZiB0aGUgRGF0YSBBbmFseXNpcyBjb21tYW5kIGlzIG5vdCBhdmFpbGFibGUsIHlvdSBuZWVkIHRvIGxvYWQgdGhlIEFuYWx5c2lzIFRvb2xQYWsgYWRkLWluIHByb2dyYW0uKHNlZTpbT2ZmaWNlIFN1cHBvcnRdKGh0dHBzOi8vc3VwcG9ydC5vZmZpY2UuY29tL2VuLWllL2FydGljbGUvbG9hZC10aGUtYW5hbHlzaXMtdG9vbHBhay1pbi1leGNlbC02YTYzZTU5OC1jZDZkLTQyZTMtOTMxNy02YjQwYmExYTY2YjQpe3RhcmdldD0iX2JsYW5rIn0pDQogICogU2VsZWN0ICJEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzIg0KICAqIElucHV0IHRoZSBhcHByb3ByaWF0ZSB2YXJpYWJsZSByYW5nZXMgdW5kZXIgIklucHV0Ig0KICAqIElmIHlvdXIgdmFyaWFibGVzIGhhdmUgbGFiZWxzICh3aGljaCB0aGV5IHNob3VsZCkgY2hlY2sgIkxhYmVscyBpbiBGaXJzdCBSb3ciDQogICogQ2xpY2sgb24gT3V0cHV0IFJhbmdlIGFuZCBpbiB0aGUgYXNzb2NpYXRlZCBib3ggaW5kaWNhdGUgdGhlIGNlbGwgeW91IHdhbnQgdGhlIG91dHB1dCB0byBiZSBnZW5lcmF0ZWQgaW4gKG1ha2Ugc3VyZSB0aGlzIGNlbGwgaXMgYXdheSBmcm9tIG90aGVyIGltcG9ydGFudCBkYXRhKSBPUiBzaW1wbHkgc2VsZWN0ICJOZXcgV29ya3NoZWV0IFBseSINCiAgKiBTYW1wbGUgb3V0cHV0IGlzIHNob3duIGJlbG93Og0KDQoNClN0YXRpc3RpYyAgICAgICAgIHwgdmFsdWUNCi0tLS0tLS0tLS0gICAgICAgIHwtLS0tLS0NCk1lYW4gICAgICAgICAgICAgIHwgMTINClN0YW5kYXJkIEVycm9yCSAgfCAwLjQ0NzIxMzU5NQ0KTWVkaWFuCSAgICAgICAgICB8IDEyDQpNb2RlCSAgICAgICAgICAgIHwgMTMNClN0YW5kYXJkIERldmlhdGlvbnwgMQ0KU2FtcGxlIFZhcmlhbmNlCSAgfCAxDQpLdXJ0b3NpcwkgICAgICAgIHwgLTMNClNrZXduZXNzICAgICAgICAgIHwgMA0KUmFuZ2UJICAgICAgICAgICAgfCAyDQpNaW5pbXVtICAgICAgICAgICB8IDExDQpNYXhpbXVtICAgICAgICAgICB8IDEzDQpTdW0JICAgICAgICAgICAgICB8IDYwDQpDb3VudAkgICAgICAgICAgICB8IDUNCg0KIyAqKlByb3BvcnRpb25zIHRlc3QqKg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQoqKlByb3BvcnRpb25zIHRlc3QqKjogVXNlIGEgcHJvcG9ydGlvbnMgdGVzdCB0byBjb21wYXJlL2RldGVybWluZSBpZiB0aGUgZnJlcXVlbmN5L3Byb2JhYmlsaXR5IG9mIGFuIGV2ZW50IGlzIGRpZmZlcmVudCBiZXR3ZWVuIHRoZSB2YXJpb3VzIGdyb3VwcyBiZWluZyB0ZXN0ZWQgKGUuZy4gYXNraW5nIGlmIHRoZSBwcm9wb3J0aW9uIG9mIG1hbGVzIHJlcG9ydGluZyBkZXByZXNzaW9uIGlzIGRpZmZlcmVudCBmcm9tIGZlbWFsZXMgcmVwb3J0aW5nIGRlcHJlc3Npb24gaW4gYSBzYW1wbGUpDQo8L2Rpdj4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtc3VjY2VzcyI+DQojIyBDb21wYXJpbmcgdHdvIHByb3BvcnRpb25zIC0gTWV0aG9kIDENCmBgYHtyfQ0KcHJvcC50ZXN0KHggPSBjKGMxLCBjMiksIG4gPSBjKFQxLCBUMiksIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpDQpgYGANCiAgKiBjMSBhbmQgYzIgcmVmbGVjdCB0aGUgbnVtYmVyIG9mIHN1YmplY3RzIGluIGVhY2ggb2YgdGhlIGNhdGVnb3JpZXMgKGUuZy4sIG51bWJlciBvZiB3b21lbiByZXNwb25kaW5nIFllcyBhbmQgdGhlIG51bWJlciBvZiBtZW4gcmVzcG9uZGluZyBZKQ0KICAqIFQxIGFuZCBUMiByZWZsZWN0IHRoZSBudW1iZXIgb2YgVE9UQUwgc3ViamVjdHMgaW4gZWFjaCBjYXRlZ29yeS9ncm91cCAoZS5nLiwgdGhlIHRvdGFsIG51bWJlciBvZiB3b21lbiBpbiB0aGUgc2FtcGxlLCB0aGUgdG90YWwgbnVtYmVyIG9mIG1lbiBpbiB0aGUgc2FtcGxlKQ0KICANCiMjIENvbXBhcmluZyB0d28gcHJvcG9ydGlvbnMgLSBNZXRob2QgMg0KDQpgYGB7cn0NCm9iamVjdCA9IGModjEsdjIpIA0KYGBgDQogICogbnVtYmVyIG9mIHN1YmplY3RzIGluIGVhY2ggb2YgdGhlIGNhdGVnb3JpZXMgKGUuZy4gbnVtYmVyIG9mIENhdGhvbGljcyBpbiBleGFtcGxlKQ0KYGBge3J9DQpUb2JqZWN0ID0gYyhuMSxuMikgDQpgYGANCiAgKiBudW1iZXIgb2YgVE9UQUwgc3ViamVjdHMgaW4gZWFjaCBjYXRlZ29yeS9ncm91cCAoZS5nLiBUb3RhbCBudW1iZXIgb2YgcmVwcmVzZW50YXRpdmUgaW4gZWFjaCBwYXJ0eSkNCmBgYHtyfQ0KcHJvcC50ZXN0KG9iamVjdCwgVG9iamVjdCkgDQpgYGANCiAgKiBydW5zIHRoZSBwcm9wb3J0aW9ucyB0ZXN0DQoNCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyBQcm9wb3J0aW9ucyBUZXN0IE91dHB1dCBpbiBSDQpgYGB7fQ0KMi1zYW1wbGUgdGVzdCBmb3IgZXF1YWxpdHkgb2YgcHJvcG9ydGlvbnMgd2l0aA0KCWNvbnRpbnVpdHkgY29ycmVjdGlvbg0KDQpYLXNxdWFyZWQgPSA1LjczMTgsIGRmID0gMSwgcC12YWx1ZSA9IDAuMDE2NjYgICAgICMgWC1zcXVhcmVkIChjaGktc3F1YXJlZCkgPSB0aGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGlzdGljOyBkZiA9IGRlZ3JlZXMgb2YgZnJlZWRvbSAobi0xKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtIHdlIGhhdmUgMiBncm91cHM7IHAtdmFsdWUgPSB0ZWxscyB1cyBpZg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdCBpcyBzaWduaWZpY2FudDsgSVQgSVMgU0lHTklGSUNBTlQgaWYgcA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8IDAuMDUNCmFsdGVybmF0aXZlIGh5cG90aGVzaXM6IHR3by5zaWRlZA0KOTUgcGVyY2VudCBjb25maWRlbmNlIGludGVydmFsOg0KICAwLjAxODIxOTI2IDAuMTgwOTg3MDkgICAgICAgICAgICAgICAgICAgICAgICAgICMgSWYgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgcmFuZ2UgaGFzIHRoZSBzYW1lIFNJR04gLSB0aGVyZSBzaG91bGQgYmUgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlDQpzYW1wbGUgZXN0aW1hdGVzOg0KICBwcm9wIDEgICAgcHJvcCAyIA0KMC4zNTM1NzE0IDAuMjUzOTY4MyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZXNlIGFyZSB0aGUgcHJvcG9ydGlvbnMgb2YgZWFjaCBvZiB0aGUgdGVzdGVkIGdyb3Vwcw0KYGBgDQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4NCiMjIFdyaXRpbmcgYSByZXBvcnQgZnJvbSBhIHByb3BvcnRpb25zIHRlc3Qgb3V0cHV0DQpBIHR3by1zYW1wbGUgdGVzdCBmb3IgZXF1YWxpdHkgb2YgcHJvcG9ydGlvbiB3YXMgY29uZHVjdGVkIHRvIGFzc2VzcyB3aGV0aGVyIHRoZSBwcm9wb3J0aW9uIG9mIENhdGhvbGljcyBpbiB0aGUgUmVwdWJsaWNhbiBhbmQgRGVtb2NyYXRpYyBwYXJ0eSB3ZXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50LiBUaGUgYW5hbHlzaXMgcmV2ZWFsZWQgYSBzaWduaWZpY2FudGx5IGhpZ2hlciBwcm9wb3J0aW9uIG9mIENhdGhvbGljcyBpbiB0aGUgRGVtb2NyYXRpYyBQYXJ0eSgzNS40JSkgcmVsYXRpdmUgdG8gdGhlIFJlcHVibGljYW4gUGFydHkoMjUuNCUpLCBYXjJeKDEsTj01MzIpPSA1LjczLHA8MC4wNS4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXN1Y2Nlc3MiPg0KIyMgQ29tcGFyaW5nIG1vcmUgdGhhbiB0d28gcHJvcG9ydGlvbnMgLSBNZXRob2QgMQ0KYGBge3J9DQpwcm9wLnRlc3QoeCA9IGMoYzEsIGMyLCBjMy4uLiksIG4gPSBjKFQxLCBUMiwgVDMuLi4pLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKQ0KcGFpcndpc2UucHJvcC50ZXN0KHggPSBjKGMxLCBjMiwgYzMuLi4pLCBuID0gYyhUMSwgVDIsIFQzLi4uKSwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikNCmBgYA0KICAqIGMxLCBjMiwgYzMuLi4gcmVmbGVjdCB0aGUgbnVtYmVyIG9mIHN1YmplY3RzIGluIGVhY2ggb2YgdGhlIGNhdGVnb3JpZXMgKGUuZy4sIG51bWJlciBvZiB3b21lbiByZXNwb25kaW5nIFllcyBhbmQgdGhlIG51bWJlciBvZiBtZW4gcmVzcG9uZGluZyBZKQ0KICAqIFQxLCBUMiwgVDMuLi4gcmVmbGVjdCB0aGUgbnVtYmVyIG9mIFRPVEFMIHN1YmplY3RzIGluIGVhY2ggY2F0ZWdvcnkvZ3JvdXAgKGUuZy4sIHRoZSB0b3RhbCBudW1iZXIgb2Ygd29tZW4gaW4gdGhlIHNhbXBsZSwgdGhlIHRvdGFsIG51bWJlciBvZiBtZW4gaW4gdGhlIHNhbXBsZSkNCiAgKiBwcm9wLnRlc3QgcnVucyB0aGUgcHJvcG9ydGlvbnMgdGVzdCAtIHByb3ZpZGVzIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBvdXRwdXQuDQogICogcGFpcndpc2UucHJvcC50ZXN0IHJ1bnMgdGhlIHBhaXJ3aXNlIHRlc3QgdG8gaW5kaWNhdGUgd2hpY2ggcHJvcG9ydGlvbnMgYXJlIGRpZmZlcmVudCBmcm9tIGVhY2ggb3RoZXIgLSB0aGlzIHByb3ZpZGVzIHRoZSBzZWNvbmQgcGFydCBvZiB0aGUgb3V0cHV0DQogIA0KIyMgQ29tcGFyaW5nIG1vcmUgdGhhbiB0d28gcHJvcG9ydGlvbnMgLSBNZXRob2QgMg0KYGBge3J9DQpvYmplY3QgPSBjKGEsYixjLGQsZSwuLi4pIA0KYGBgDQogICogbnVtYmVyIG9mIHN1YmplY3RzIGluIGVhY2ggb2YgdGhlIGNhdGVnb3JpZXMgKGUuZy4gdGhlIG51bWJlciBvZiBkb2N0b3JzIG9mIGEgcGFydGljdWxhciBmYWl0aCB0aGF0IHNhaWQgdGhleSB3b3VsZCBOT1QgcGVyZm9ybSBhbiBhYm9ydGlvbjsgZWFjaCBsZXR0ZXIgd291bGQgYmUgcmVwbGFjZWQgYnkgdGhlIG51bWJlciBvZiBkb2N0b3JzIG9mIGVhY2ggc3BlY2lmaWMgc3BlY2lmaWMgZmFpdGggdGhhdCByZXNwb25kZWQgIk5PIikNCmBgYHtyfQ0KVG9iamVjdCA9IGMoVGEsVGIsVGMsVGQsVGUsLi4uKSANCmBgYA0KICAqIG51bWJlciBvZiBUb3RhbCBzdWJqZWN0cyBpbiBlYWNoIGNhdGVnb3J5L2dyb3VwIChlLmcuIHRoZSBUT1RBTCBudW1iZXIgb2YgZG9jdG9ycyBvZiBhIHBhcnRpY3VsYXIgZmFpdGggaS5lIHRob3NlIHRoYXQgcmVzcG9uZGVkIFlFUyAodGhleSB3b3VsZCBwZXJmb3JtIGFuIGFib3J0aW9uKSArIHRob3NlIHRoYXQgcmVzcG9uZGVkIE5POyAqKlJlcGxhY2UgVGEqKiBldGMuIHdpdGggbnVtYmVycyByZXByZXNlbnRpbmcgdGhlIGluZGl2aWR1YWwgdG90YWxzKQ0KYGBge3J9DQpwcm9wLnRlc3Qob2JqZWN0LFRvYmplY3QpIA0KYGBgDQogICogcnVucyBwcm9wb3J0aW9ucyB0ZXN0IC0gcHJvdmlkZXMgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIG91dHB1dC4NCmBgYHtyfQ0KcGFpcndpc2UucHJvcC50ZXN0KG9iamVjdCxUb2JqZWN0KSANCmBgYA0KICAqIHJ1bnMgcGFpcndpc2UgdGVzdCB0byBpbmRpY2F0ZSB3aGljaCBwcm9wb3J0aW9ucyBhcmUgZGlmZmVyZW50IGZyb20gZWFjaCBvdGhlciAtIHRoaXMgcHJvdmlkZXMgdGhlIHNlY29uZCBwYXJ0IG9mIHRoZSBvdXRwdXQuDQoNCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyBQcm9wb3J0aW9ucyBUZXN0IE91dHB1dCBpbiBSIChtb3JlIHRoYW4gdHdvIHByb3BvcnRpb25zKQ0KYGBge30NCiMgVGhpcyBpcyB0aGUgZmlyc3QgcGFydCBvZiB0aGUgb3V0cHV0IHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgdGhlcmUgaXMgYSBkaWZmZXJlbmNlIGluIHRoZSBwcm9wb3J0aW9ucy4gSWYgdGhlcmUgaXMgYSBkaWZmZXJlbmNlLCBob3dldmVyLCBpdCB3aWxsIG5vdCBpbmRpY2F0ZSBiZXR3ZWVuIHdoaWNoIHByb3BvcnRpb25zIHRoZSBkaWZmZXJlbmNlIGV4aXN0cy4NCg0KNC1zYW1wbGUgdGVzdCBmb3IgZXF1YWxpdHkgb2YgcHJvcG9ydGlvbnMgd2l0aG91dA0KCWNvbnRpbnVpdHkgY29ycmVjdGlvbg0KDQpkYXRhOiAgb2JqZWN0IG91dCBvZiBUb2JqZWN0DQpYLXNxdWFyZWQgPSAzNS4xNjksIGRmID0gMywgcC12YWx1ZSA9IDEuMTIyZS0wNw0KYWx0ZXJuYXRpdmUgaHlwb3RoZXNpczogdHdvLnNpZGVkDQpzYW1wbGUgZXN0aW1hdGVzOg0KICAgcHJvcCAxICAgIHByb3AgMiAgICBwcm9wIDMgICAgcHJvcCA0IA0KMC4yODU3MTQzIDAuNTAwMDAwMCAwLjI0MDc0MDcgMC43NTAwMDAwIA0KDQojIFRoaXMgaXMgdGhlIHNlY29uZCBwYXJ0IG9mIHRoZSBvdXRwdXQgdGhlIGluZGljYXRlcyBXSEVSRSB0aGUgZGlmZmVyZW5jZXMgYXJlLiBUaGUgbnVtYmVycyBpbiB0aGUgdG9wIHJvdyBhbmQgaW4gdGhlIGZpcnN0IGNvbHVtbiByZWZsZWN0IHRoZSA0IHByb3BvcnRpb25zIGJlaW5nIHRlc3RlZCBjb21wYXJpbmcgZS5nLiwgMSB2cyAyIChub3Qgc2lnbmlmaWNhbnQpOyAxIHZzIDQgKHNpZ25pZmljYW50IGF0IHA8MC4wMDEpIGV0Yy4sIGV0Yy4NCg0KUGFpcndpc2UgY29tcGFyaXNvbnMgdXNpbmcgUGFpcndpc2UgY29tcGFyaXNvbiBvZiBwcm9wb3J0aW9ucyANCg0KZGF0YTogIG9iamVjdCBvdXQgb2YgVG9iamVjdCANCg0KICAxICAgICAgIDIgICAgICAgMyAgICAgIA0KMiAwLjMyNDIyIC0gICAgICAgLSAgICAgIA0KMyAwLjgyMTU0IDAuMTgxMjggLSAgICAgIA0KNCAwLjAwMDEzIDAuMTgxMjggOS41ZS0wNw0KDQpQIHZhbHVlIGFkanVzdG1lbnQgbWV0aG9kOiBob2xtIA0KYGBgDQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4NCiMjIFdyaXRpbmcgYSByZXBvcnQgZnJvbSBhIHByb3BvcnRpb25zIHRlc3Qgb3V0cHV0IChtb3JlIHRoYW4gdHdvIHByb3BvcnRpb25zKQ0KQSA0LXNhbXBsZSB0ZXN0IGZvciBlcXVhbGl0eSBvZiBwcm9wb3J0aW9ucyB3YXMgY29uZHVjdGVkIHRvIGFzc2VzcyB3aGV0aGVyIHRoZSBwcm9wb3J0aW9uIG9mIHRoZSA0IHNhbXBsZXMgcHJvdmlkZWQgd2VyZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudC4gVGhlIGFuYWx5c2lzIHJldmVhbGVkIGFuIG92ZXJhbGwgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBYXjJeKDMsTj0gKippbnNlcnQgbnVtYmVyIG9mIHBhcnRpY2lwYW50cyoqKSA9IDM1LjE3LHA8MC4wMDEuIFBhaXJ3aXNlIGNvbXBhcmlzb25zIGluZGljYXRlZCBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYmV0d2VlbiBzYW1wbGVzIDEgYW5kIDQgYW5kIHNhbXBsZXMgMyBhbmQgNCAoYm90aCBwPDAuMDAxKS4gQWxsIG90aGVyIGNvbXBhcmlzb25zIHdlcmUgbm90IHNpZ25pZmljYW50IChwPjAuMDUpLg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KIyBQcm9wb3J0aW9ucyBUZXN0IGZvciBzaXR1YXRpb25zIHdoZXJlIHRoZXJlIGFyZSB2ZXJ5IHNtYWxsIG51bWJlcnMgKDUgb3IgbGVzcykNCg0KSW4gc2l0dWF0aW9ucyB3aGVyZSB0aGVyZSBhcmUgNSBvciBsZXNzIHZhbHVlcywgdGhlIHByb3BvcnRpb25zIHRlc3Qgd2lsbCBkaXNwbGF5IGFuIGVycm9yLiBJbiB0aGF0IGNhc2UsIHRoZSBGaXNoZXIgdGVzdCBpcyB0aGUgbW9yZSBhcHByb3ByaWF0ZSB0ZXN0IHRvIHVzZS4NCg0KIyMgQ29tcGFyaW5nIHR3byBwcm9wb3J0aW9ucyAtIGluIGNhc2VzIG9mIHNtYWxsIG51bWJlcnMNCmBgYHtyfQ0KZmlzaGVyLnRlc3QobWF0cml4KGMobjEsIFQxLW4xLCBuMiwgVDItbjIpLCBuY29sPTIpKSANCmBgYA0KICAqIG4xIHJlcHJlc2VudHMgdGhlIGZpcnN0IG51bWJlciB0byBiZSBjb21wYXJlZCwgVDEgaXMgdGhlIHRvdGFsIG51bWJlciBvZiBzdWJqZWN0cyBpbiBwZXJ0YWluaW5nIHRvIHZhcmlhYmxlIG4xIGV0Yy4NCg0KIyMgQ29tcGFyaW5nIG1vcmUgdGhhbiB0d28gcHJvcG9ydGlvbnMgLSBpbiBjYXNlcyBvZiBzbWFsbCBudW1iZXJzDQogICogcmVxdWlyZXMgKlJWQWlkZU1lbW9pcmUqIHBhY2thZ2UNCmBgYHtyfQ0KZmlzaGVyLm11bHRjb21wKG1hdHJpeChjKG4xLCBUMS1uMSwgbjIsIFQyLW4yLC4uLi4uKSwgbmNvbD1OKSkgDQpgYGANCiAgKiBuMSByZXByZXNlbnRzIHRoZSBmaXJzdCBudW1iZXIgdG8gYmUgY29tcGFyZWQsIFQxIGlzIHRoZSB0b3RhbCBudW1iZXIgb2Ygc3ViamVjdHMgaW4gcGVydGFpbmluZyB0byB2YXJpYWJsZSBuMSBldGMuIA0KICAqIG5jb2w9TjogcmVwbGFjZSAqKipOKioqIHdpdGggdGhlIG51bWJlciBvZiB2YXJpYWJsZXMgYmVpbmcgY29tcGFyZWQuDQogIA0KIyAqKk9kZHMgUmF0aW8qKg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQoqKk9kZHMgUmF0aW8qKjogbWVhc3VyZXMgaG93IGxpa2VseSBhbiBldmVudCBpcyB0byBvY2N1ciB3aGVuIGV4cG9zZWQgdG8gc29tZXRoaW5nOyBhIG1lYXN1cmUgb2YgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gZXhwb3N1cmUgYW5kIG91dGNvbWUNCjwvZGl2Pg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1zdWNjZXNzIj4gDQojIENyZWF0ZSBNYXRyaXgNCmBgYHtyfQ0KIyBkYXRhIHRha2VuIGZyb20gWWFuZywgQy4tWS4sIFNoaWgsIFkuLUguLCAmIEx1bmcsIEMuLUMuICgyMDI0KS4gVGhlIGFzc29jaWF0aW9uIGJldHdlZW4gQ09WSUQtMTkgdmFjY2luZS9pbmZlY3Rpb24gYW5kIG5ldy1vbnNldCBhc3RobWEgaW4gY2hpbGRyZW4gLSBiYXNlZCBvbiB0aGUgZ2xvYmFsIFRyaU5ldFggZGF0YWJhc2UuIEluZmVjdGlvbi4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMDcvczE1MDEwLTAyNC0wMjMyOS0zICoqVGFibGUgUzIgaW4gU3VwcGxlbWVudCAxKioNCg0KIyBDcmVhdGUgbWF0cml4DQp2YXggPC0gYygnVmF4JywgJ05vIFZheCcpDQpvdXRjb21lIDwtIGMoJ0RlYXRoJywgJ05vIGRlYXRoJykNCmRhdGEgPC0gbWF0cml4KGMoMzU0LCAzMTczNCwgMzA5LCAxNTkwNDgpLCBucm93PTIsIG5jb2w9MiwgYnlyb3c9VFJVRSkNCmRpbW5hbWVzKGRhdGEpIDwtIGxpc3QoJ1ZhY2NpbmF0ZWQnPXZheCwgJ091dGNvbWUnPW91dGNvbWUpDQoNCiN2aWV3IG1hdHJpeA0KZGF0YQ0KDQpgYGANCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXN1Y2Nlc3MiPg0KIyBDYWxjdWxhdGUgT2RkcyBSYXRpbw0KYGBge3J9DQpsaWJyYXJ5KGVwaXRvb2xzKQ0KDQojY2FsY3VsYXRlIG9kZHMgcmF0aW8NCm9kZHNyYXRpbyhkYXRhKQ0KDQojIEZyb20gdGhlIG91dHB1dCBzaG93biwgd2Ugd291bGQgaW50ZXJwcmV0IHRoaXMgdG8gbWVhbiB0aGF0IHRoZSBvZGRzIHRoYXQgY2hpbGQgcmVjZWl2aW5nIHRoZSB2YWNjaW5lIGRpZXMgaXMgfjUuNzQgdGltZXMgdGhlIG9kZHMgb2Ygb25lIHdobyBkaWQgbm90IHJlY2VpdmUgdGhlIHZhY2NpbmUuDQpgYGANCjwvZGl2Pg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4NCiMjIFdyaXRpbmcgYSByZXBvcnQgZnJvbSBhbiBvZGRzIHJhdGlvIHRlc3Qgb3V0cHV0DQpUaGVyZSB3YXMgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIChwPDAuMDAxKSBpbiB0aGUgb2RkcyBvZiBkZWF0aCBhc3NvY2lhdGVkIHdpdGggcmVjZWl2aW5nIHRoZSBDT1ZJRCB2YWNjaW5lcyBpbiBjaGlsZHJlbiBhZ2VkIDUtMTggeWVhcnMgb2YgYWdlIHJlbGF0aXZlIHRvIHRob3NlIHdobyBkaWQgbm90IChPUiA1Ljc0LCA5NSUgQ0kgWzQuOTMsIDYuNjldKS4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCg0KKioqDQojIFNvbWUgdGhpbmdzIHlvdSAqKiptYXkqKiogaGF2ZSB0byBkbyAqKnByaW9yIHRvIGdlbmVyYXRpbmcgYSBncmFwaCoqDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC13YXJuaW5nIj4NCg0KIyMgRnVuY3Rpb24gYW5kIGNvbW1hbmQgZm9yIGdlbmVyYXRpbmcgU3RhbmRhcmQgRXJyb3Igb2YgdGhlIE1lYW4gKFNFTSkNCiAgKiBUaGlzIGZ1bmN0aW9uIG5lZWRzIHRvIGJlIGNvcGllZCBhbmQgcnVuICoqV0lUSE9VVCBNT0RJRklDQVRJT04qKiBiZWZvcmUgZ2VuZXJhdGluZyB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIHVzaW5nIHRoZSBzdW1tYXJ5U0UgY29tbWFuZC4NCiAgKiBUaGlzIGNvZGUgaXMgdGFrZW4gZnJvbTogW1N1bW1hcml6aW5nIERhdGFdKGh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vTWFuaXB1bGF0aW5nX2RhdGEvU3VtbWFyaXppbmdfZGF0YS8pDQoNCmBgYHtyfQ0KIyMgR2l2ZXMgY291bnQsIG1lYW4sIHN0YW5kYXJkIGRldmlhdGlvbiwgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4sIGFuZCBjb25maWRlbmNlIGludGVydmFsIChkZWZhdWx0IDk1JSkuDQojIyAgIGRhdGE6IGEgZGF0YSBmcmFtZS4NCiMjICAgbWVhc3VyZXZhcjogdGhlIG5hbWUgb2YgYSBjb2x1bW4gdGhhdCBjb250YWlucyB0aGUgdmFyaWFibGUgdG8gYmUgc3VtbWFyaWV6ZWQNCiMjICAgZ3JvdXB2YXJzOiBhIHZlY3RvciBjb250YWluaW5nIG5hbWVzIG9mIGNvbHVtbnMgdGhhdCBjb250YWluIGdyb3VwaW5nIHZhcmlhYmxlcw0KIyMgICBuYS5ybTogYSBib29sZWFuIHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgdG8gaWdub3JlIE5BJ3MNCiMjICAgY29uZi5pbnRlcnZhbDogdGhlIHBlcmNlbnQgcmFuZ2Ugb2YgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgKGRlZmF1bHQgaXMgOTUlKQ0Kc3VtbWFyeVNFIDwtIGZ1bmN0aW9uKGRhdGE9TlVMTCwgbWVhc3VyZXZhciwgZ3JvdXB2YXJzPU5VTEwsIG5hLnJtPUZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbmYuaW50ZXJ2YWw9Ljk1LCAuZHJvcD1UUlVFKSB7DQogICAgbGlicmFyeShwbHlyKQ0KDQogICAgIyBOZXcgdmVyc2lvbiBvZiBsZW5ndGggd2hpY2ggY2FuIGhhbmRsZSBOQSdzOiBpZiBuYS5ybT09VCwgZG9uJ3QgY291bnQgdGhlbQ0KICAgIGxlbmd0aDIgPC0gZnVuY3Rpb24gKHgsIG5hLnJtPUZBTFNFKSB7DQogICAgICAgIGlmIChuYS5ybSkgc3VtKCFpcy5uYSh4KSkNCiAgICAgICAgZWxzZSAgICAgICBsZW5ndGgoeCkNCiAgICB9DQoNCiAgICAjIFRoaXMgZG9lcyB0aGUgc3VtbWFyeS4gRm9yIGVhY2ggZ3JvdXAncyBkYXRhIGZyYW1lLCByZXR1cm4gYSB2ZWN0b3Igd2l0aA0KICAgICMgTiwgbWVhbiwgYW5kIHNkDQogICAgZGF0YWMgPC0gZGRwbHkoZGF0YSwgZ3JvdXB2YXJzLCAuZHJvcD0uZHJvcCwNCiAgICAgIC5mdW4gPSBmdW5jdGlvbih4eCwgY29sKSB7DQogICAgICAgIGMoTiAgICA9IGxlbmd0aDIoeHhbW2NvbF1dLCBuYS5ybT1uYS5ybSksDQogICAgICAgICAgbWVhbiA9IG1lYW4gICAoeHhbW2NvbF1dLCBuYS5ybT1uYS5ybSksDQogICAgICAgICAgc2QgICA9IHNkICAgICAoeHhbW2NvbF1dLCBuYS5ybT1uYS5ybSkNCiAgICAgICAgKQ0KICAgICAgfSwNCiAgICAgIG1lYXN1cmV2YXINCiAgICApDQoNCiAgICAjIFJlbmFtZSB0aGUgIm1lYW4iIGNvbHVtbiAgICANCiAgICBkYXRhYyA8LSByZW5hbWUoZGF0YWMsIGMoIm1lYW4iID0gbWVhc3VyZXZhcikpDQoNCiAgICBkYXRhYyRzZSA8LSBkYXRhYyRzZCAvIHNxcnQoZGF0YWMkTikgICMgQ2FsY3VsYXRlIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBtZWFuDQoNCiAgICAjIENvbmZpZGVuY2UgaW50ZXJ2YWwgbXVsdGlwbGllciBmb3Igc3RhbmRhcmQgZXJyb3INCiAgICAjIENhbGN1bGF0ZSB0LXN0YXRpc3RpYyBmb3IgY29uZmlkZW5jZSBpbnRlcnZhbDogDQogICAgIyBlLmcuLCBpZiBjb25mLmludGVydmFsIGlzIC45NSwgdXNlIC45NzUgKGFib3ZlL2JlbG93KSwgYW5kIHVzZSBkZj1OLTENCiAgICBjaU11bHQgPC0gcXQoY29uZi5pbnRlcnZhbC8yICsgLjUsIGRhdGFjJE4tMSkNCiAgICBkYXRhYyRjaSA8LSBkYXRhYyRzZSAqIGNpTXVsdA0KDQogICAgcmV0dXJuKGRhdGFjKQ0KfQ0KYGBgDQo8L2Rpdj4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtd2FybmluZyI+DQpgYGB7cn0NCnN1bXN0YXRzIDwtIHN1bW1hcnlTRShvYmplY3RMLCBtZWFzdXJldmFyPSJvdXRjb21ldmFyIiwgZ3JvdXB2YXJzPWMoImdyb3VwdmFyXzEiLCJncm91cHZhcl8yIiwiZ3JvdXB2YXJfbiIpLCBuYS5ybT1UUlVFKQ0KYGBgDQogICogc3Vtc3RhdHM6IG5hbWUgb2Ygb2JqZWN0IHRoYXQgd2lsbCBoYXZlIHRoZSBzdW1tYXJ5IHN0YXRzLiBUaGUgbmFtZSBvZiB0aGlzIHNob3VsZCBiZSBjaGFuZ2VkIGlmIHJ1bm5pbmcgZm9yIG1vcmUgdGhhbiBvbmUgZGF0YSBzZXQuDQogICogc3VtbWFyeVNFOiBjb21tYW5kIHRoYXQgcnVucyB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzDQogICogb2JqZWN0TDogbmFtZSBvZiBvYmplY3QgY29udGFpbmluZyB0aGUgbG9uZyB2ZXJzaW9uIG9mIHRoZSBkYXRhIHRvIGJlIGFuYWx5emVkL3N1bW1hcml6ZWQNCiAgKiAib3V0Y29tZXZhciI6IG5hbWUgb2YgdGhlIHZhcmlhYmxlIHRvIGJlIGFuYWx5emVkL3N1bW1hcml6ZWQNCiAgKiAiZ3JvdXB2YXJfMSIgZXRjOiBuYW1lIG9mIHRoZSBjb2x1bW5zIHRoYXQgY29udGFpbiB0aGUgZ3JvdXBzIGZvciB0aGUgdmFyaWFibGUgdG8gYmUgYW5hbHl6ZWQgZS5nLiBTZXgsIENsYXNzLCBBZ2UuLi5ldGMuDQogICogbmEucm0gPSBUUlVFOiByZW1vdmVzIHRoZSBlbXB0eSBjZWxscyAoY2VsbHMgdGhhdCBoYXZlIE5BKTsgTm90IHJlcXVpcmVkIGlmIGFsbCBkYXRhIHBvaW50cyBhcmUgcHJlc2VudC4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPg0KIyMgT3JkZXJpbmcgbGV2ZWxzIGluIGEgc3BlY2lmaWMgdmFyaWFibGUNCiAgKiBXaGVuIHBsb3R0aW5nIGEgZ3JhcGgsIFIgd2lsbCBvcmRlciB0aGUgdmFyaWFibGVzIGluIGFscGhhYmV0aWNhbCBvcmRlci4gVmVyeSBvZnRlbiB0aGlzIGlzIG5vdCB0aGUgYmVzdCB3YXkgb2YgcGxvdHRpbmcgdGhlIGdyYXBoLiBJbiBzdWNoIGNhc2VzLCBSIG5lZWRzIHRvIGJlIGluc3RydWN0ZWQgb24gdGhlIGRlc2lyZWQgb3JkZXIgb2YgdmFyaWFibGVzLg0KICAqIEFuIGV4YW1wbGUgaXMgdGhlIG9yZGVyIG9mIGNsYXNzZXMuIEZvciB0aGlzIGV4YW1wbGUsIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSBpbiB0aGUgZGF0YSAoaS5lLiB0aGUgY29sdW1uIG5hbWUpIGlzICoqQ2xhc3MqKiBSIHdpbGwgb3JkZXIgdGhlbTogRnJlc2htYW4sIEdyYWR1YXRlLCBKdW5pb3IsIFNlbmlvciwgU29waG9tb3JlDQogICogVGhpcyBjb21tYW5kIHdpbGwgY3JlYXRlIGFuIG9iamVjdCB0aGF0IGhhcyB0aGUgcmVvcmRlcmVkIGxldmVscy4NCiAgKiBJbiBzdWNoIGEgY2FzZSwgdGhlIG5hbWUgb2YgdGhlIG5ldyBvYmplY3QgY3JlYXRlZCB3b3VsZCBiZSB0aGUgbmFtZSBvZiB0aGUgcHJlZGljdG9yIHRoYXQgd291bGQgbmVlZCB0byBiZSB1c2VkIGluIFBhcnQgSSBvZiBwbG90dGluZyB0aGUgZ3JhcGguDQogICogRm9yIHRoaXMgZXhhbXBsZSAqKipDbGFzcyoqKiBpcyB0aGUgb3JpZ2luYWwgbmFtZTsgKioqQ2xhc3NfcioqKiBpcyB0aGUgcmVhcnJhbmdlZCBsZXZlbHMNCiAgDQpgYGB7cn0NCkNsYXNzX3IgPSBmYWN0b3IgKG9iamVjdCRDbGFzcywgbGV2ZWxzPWMoIkZyZXNobWFuIiwgIlNvcGhvbW9yZSIsICJKdW5pb3IiLCAiU2VuaW9yIiwgIkdyYWR1YXRlIikpDQpgYGANCiAgKiBub3RpY2UgaG93IHdoZW4geW91IGFyZSBpbmRpY2F0aW5nIHRoZSBuYW1lIG9mIHRoZSBmYWN0b3IgdGhhdCBpcyB0byBiZSByZW9yZGVyZWQgeW91IG5lZWQgdG8gZ2l2ZSBSIHRoZSBuYW1lIG9mIHRoZSBvYmplY3QgY29udGFpbmluZyB0aGUgZGF0YSAoaW4gdGhpcyBjYXNlICJvYmplY3QiIGFuZCB0aGUgbmFtZSBvZiB0aGUgY29sdW1uIHRvIGJlIHJlb3JkZXJlZCBzZXBhcmF0ZWQgYnkgYSAkIHN5bWJvbCkNCiAgKiB0byBhZGFwdCB0byBhbnkgc2l0dWF0aW9uIC0gIkNsYXNzX3IiIHNob3VsZCBiZSByZW5hbWVkIGFwcHJvcHJpYXRlbHk7ICJvYmplY3QkQ2xhc3MiIHNob3VsZCBiZSByZXBsYWNlZCB3aXRoIHRoZSBhcHByb3ByaWF0ZSBvYmplY3QgbmFtZSBhbmQgY29sdW1uIG5hbWUgdG8gYmUgcmVvcmdhbml6ZWQ7IGFsbCB0aGUgbGV2ZWxzIHdpdGhpbiB0aGUgcXVvdGVzIHNob3VsZCBiZSByZXBsYWNlZCBhY2NvcmRpbmdseS4gIA0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtd2FybmluZyI+DQojIyBDaGFuZ2luZyB2YXJpYWJsZSBuYW1lIGluIGEgc3BlY2lmaWMgY29sdW1uDQogICogSWYgdGhlIHZhcmlhYmxlcyBpbiBhIHBhcnRpY3VsYXIgY29sdW1uIG5lZWQgdG8gYmUgY2hhbmdlZCBlLmcuIGZyb20gbnVtYmVycyB0byB3b3JkcyBkbyB0aGUgZm9sbG93aW5nOg0KICAqIGluc3RhbGwgdGhlIHBhY2thZ2UgKioqc3RyaW5ncioqKiB1c2luZyB0aGUgZm9sbG93aW5nIGNvbW1hbmQ6DQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygic3RyaW5nciIsIGRlcGVuZGVuY2llcyA9IFQpDQpgYGANCg0KICAqIGVuc3VyZSB0aGF0IHlvdSBsb2FkIHRoZSBwYWNrYWdlICoqKnN0cmluZ3IqKiogdXNpbmcgdGhlIGZvbGxvd2luZyBjb21tYW5kOg0KICANCmBgYHtyfQ0KbGlicmFyeShzdHJpbmdyKQ0KYGBgDQoNCiAgKiBOZXh0LCBydW4gdGhlIGZvbGxvd2luZyBjb21tYW5kIGluIG9yZGVyIHRvIHByZXNlcnZlIHRoZSBvcmlnaW5hbCBmaWxlOg0KICANCmBgYHtyfQ0Kb2JqZWN0Mj1vYmplY3QNCmBgYA0KICANCiAgKiBOZXh0LCBydW4gdGhlIGZvbGxvd2luZyBjb21tYW5kIG9uIHRoZSBuZXcgbW9kaWZpZWQgb2JqZWN0IChpLmUuIG9iamVjdDIpICgqKk5PVEUqKjogdGhpcyB3aWxsIGNoYW5nZSB0aGUgdmFsdWVzIGluIHlvdXIgY29sdW1ucyBwZXJtYW5lbnRseS4pDQogIA0KYGBge3J9DQpvYmplY3QyJGNvbHVtbm5hbWUgPSBzdHJfcmVwbGFjZV9hbGwob2JqZWN0MiRjb2x1bW5uYW1lLCJvbGR2YWx1ZSIsIm5ld3ZhbHVlIikNCmBgYA0KDQogICogWW91IHdpbGwgbmVlZCB0byBydW4gdGhpcyBjb21tYW5kIGZvciAqKmV2ZXJ5KiogdmFsdWUgdGhhdCBuZWVkcyB0byBiZSByZXBsYWNlZA0KICAqIFdoZW4gcGxvdHRpbmcgdGhlIGdyYXBoIHlvdSB3aWxsIG5lZWQgdG8gcmVtZW1iZXIgdG8gdXNlIHRoZSAqKk5FVyBPQkpFQ1QqKiBpLmUuICoqKm9iamVjdDIqKiogYXMgdGhlIHNvdXJjZSBvZiB0aGUgZGF0YQ0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtd2FybmluZyI+DQojIENoYW5naW5nIHRoZSBjb2x1bW4gbmFtZS9oZWFkZXIgaW4gdGhlIG9iamVjdC9kYXRhZnJhbWUgY29udGFpbmluZyB0aGUgZGF0YQ0KICAqIFdoZW4geW91IGdlbmVyYXRlIHRoZSBsb25nIHZlcnNpb24gb2YgYSBmaWxlLCB0aGUgcHJlZGljdG9yIGNvbHVtbiB3aWxsIGhhdmUgdGhlIG5hbWUgKioqdmFyaWFibGUqKiosIHdoaWxlIHRoZSBvdXRjb21lIGNvbHVtbiB3aWxsIGJlIGxhYmVsZWQgKioqdmFsdWUqKiouIA0KICAqIFRvIGNoYW5nZSB0aGUgbmFtZSBvZiBhIHNwZWNpZmljIGNvbHVtbiB1c2UgdGhlIGZvbGxvd2luZyBjb21tYW5kcw0KYGBge3J9DQpuYW1lcyhvYmplY3RMKVtuXSA8LSAiY29ycmVjdG5hbWUiDQpgYGANCiAgKiAqKnJlbWVtYmVyIHRoYXQgdGhpcyB3aWxsIGJlIHRoZSBuYW1lIHRoYXQgeW91IHdpbGwgbmVlZCB0byB1c2UgaW4gZ2VuZXJhdGluZyB0aGUgZ3JhcGgsICoqICoqKndoZW5ldmVyIHlvdSBhcmUgYWRkcmVzc2luZyB0aGUgcHJlZGljdG9yL291dGNvbWUqKioNCiAgKiByZXBsYWNlIHRoZSAqKipuKioqIHdpdGggdGhlIG51bWJlciBvZiB0aGUgY29sdW1uIHdob3NlIGhlYWRlciB5b3Ugd2lzaCB0byBjaGFuZ2UgKGUuZy4gaWYgdGhlIGRhdGEgaGFzIGFuIGlkIGNvbHVtbiBhbmQgeW91IHdhbnQgdG8gY2hhbmdlIHRoZSB2YXJpYWJsZSBjb2x1bW4sIHRoaXMgd2lsbCBiZSBjb2x1bW4gMikNCiAgKiByZXBsYWNlICoqKmNvcnJlY3RuYW1lKioqIHdpdGggdGhlIG5hbWUgeW91IHdhbnQgdG8gZ2l2ZSB0aGUgY29sdW1uL2hlYWRlcg0KDQojIyMgVGhpcyBpcyBhbiBhbHRlcm5hdGl2ZSBjb21tYW5kIHRvIHRoZSBvbmUgYWJvdmUNCg0KICAqIFRvIHJlbmFtZSBhIHNpbmdsZSBjb2x1bW4gYnkgbmFtZQ0KYGBge3J9DQpjb2xuYW1lcyhvYmplY3RMKVtjb2xuYW1lcyhvYmplY3RMKSA9PSAib2xkX2NvbDIiXSA8LSAibmV3X2NvbDIiDQpgYGANCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCg0KIyAqKkNyZWF0aW5nIGEgcGllIGNoYXJ0LCBiYXIgZ3JhcGgsIGxpbmUgZ3JhcGggb3IgYm94IHBsb3QqKg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC13YXJuaW5nIj4NCiMgR2VuZXJhdGluZyBhIHBpZSBjaGFydA0KYGBge3J9DQpvYmplY3Q8LSBjKG4xLCBuMikNCmxhYmVsczwtIGMoIlBvb3IgKDU4JSkiLCJOb3JtYWwgKDQyJSkiKQ0KcGllKHg9b2JqZWN0LGxhYmVscyA9IGxhYmVscywgcmFkaXVzID0gMSwgbWFpbiA9ICJUaXRsZSAobj1OKSIsIGNvbCA9IGMoIiM2OWIzYTIiLCAiZ3JleSIpKQ0KYGBgDQogICogb2JqZWN0OiBuYW1lIG9mIG9iamVjdCBjb250YWluaW5nIG51bWJlciBPUiBwZXJjZW50YWdlIG9mIGRhdGEgdG8gYmUgcGxvdHRlZA0KICAqIGxhYmVsczogbmFtZSBvZiBvYmplY3QgY29udGFpbmluZyB0aGUgbmFtZXMgb2YgdGhlIGxhYmVscyBvZiB0aGUgcGFydHMvc2VjdGlvbnMgb2YgdGhlIHBpZSBjaGFydA0KICAqIHBpZTogY29tbWFuZCB0aGF0IHBsb3RzIHRoZSBwaWUgY2hhcnQNCiAgKiB4OiBpbmRpY2F0ZXMgd2hhdCBpcyB0byBiZSBwbG90dGVkIChjb250YWluZWQgaW4gdGhlIGRhdGFmcmFtZSAib2JqZWN0IiBbcmVwbGFjZSBhY2NvcmRpbmdseV0pDQogICogbGFiZWxzOiBpbmRpY2F0ZXMgdGhlIGxhYmVscyBmb3IgdGhlIHNlY3Rpb25zIChjb250YWluZWQgaW4gdGhlIGRhdGFmcmFtZSAibGFiZWxzIiBbcmVwbGFjZSBhY2NvcmRpbmdseV0pDQogICogcmFkaXVzIC0gc3BlY2lmaWVzIHJhZGl1cyBvZiBjaXJjbGUNCiAgKiBjb2wgLSBzcGVjaWZpZXMgY29sb3JzIHRvIGJlIHVzZWQNCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyMgRXhhbXBsZSBvZiBhIGdyYXBoIGdlbmVyYXRlZCB3aXRoIHByZXZpb3VzIGNvbW1hbmQNCjxjZW50ZXI+DQohW10oQzovVXNlcnNcc3NhbW1cRGVza3RvcFxTYW1tdXRcUmVzZWFyY2hcUiBNYXJrZG93bi9QaWVDaGFydC5wbmcpe3dpZHRoPTQwJX0NCjwvY2VudGVyPg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KIyBHZW5lcmF0aW5nIGEgYmFyIGdyYXBoDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC13YXJuaW5nIj4NCg0KIyMgR2VuZXJhdGluZyBhIGJhciBncmFwaCAtIFBhcnQgSSANCmBgYHtyfQ0KYmFyb2JqZWN0PWdncGxvdChvYmplY3RMLCBhZXMocHJlZGljdG9yLG91dGNvbWUpKQ0KYGBgDQogICogYmFyb2JqZWN0OiBuYW1lIG9mIHRoZSBlbnRpdHkgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIHBsb3QgKGNhbGwgaXQgd2hhdCB5b3Ugd2lzaCwganVzdCBiZSBjbGVhcikNCiAgKiBnZ3Bsb3Q6IGNvbW1hbmQgdGhhdCBlbmFibGVzIHRoZSBwbG90dGluZyBvZiB0aGUgZ3JhcGgNCiAgKiBvYmplY3RMOiBpcyB0aGUgbmFtZSBvZiB0aGUgbG9uZyB2ZXJzaW9uIG9mIHlvdXIgZGF0YQ0KICAqIGFlczogdGVsbHMgUiB0byBnZW5lcmF0ZSB0aGUgYWVzdGhldGljcw0KICAqIHByZWRpY3RvcjogKipSRVBMQUNFKiogd2l0aCB0aGUgbmFtZSBvZiB0aGUgcHJlZGljdG9yIGNvbHVtbiBpbiB0aGUgbG9uZyB2ZXJzaW9uIG9mIHRoZSBmaWxlDQogICogb3V0Y29tZTogKipSRVBMQUNFKiogd2l0aCB0aGUgbmFtZSBvZiB0aGUgb3V0Y29tZSBjb2x1bW4gaW4gdGhlIGxvbmcgdmVyc2lvbiBvZiB0aGUgZmlsZQ0KICAqIE5PVEUgcmVnYXJkaW5nIHByZWRpY3RvcjogSWYgdGhlIGxldmVscyBoYXZlIGJlZW4gcmVhcnJhZ2VkIGluIGEgbmV3IG9iamVjdCwgdGhlIHdvcmQgcHJlZGljdG9yIHNob3VsZCBiZSByZXBsYWNlZCB3aXRoIHRoZSBuYW1lIG9mIHRoYXQgc3BlY2lmaWMgb2JqZWN0IChpbiB0aGUgZXhhbXBsZSBhYm92ZSwgKioqQ2xhc3NfcioqKiBpbnN0ZWFkIG9mICoqKkNsYXNzKioqKQ0KDQojIyBHZW5lcmF0aW5nIGEgYmFyIGdyYXBoIC0gUGFydCBJSSANCmBgYHtyfQ0KYmFyb2JqZWN0K3N0YXRfc3VtbWFyeShmdW49bWVhbiwgZ2VvbT0iYmFyIixmaWxsPSJ3aGl0ZSIsY29sb3I9IkJsYWNrIikrc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhPW1lYW5fY2xfbm9ybWFsLCBnZW9tPSJlcnJvcmJhciIscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC45KSwgd2lkdGg9MC4yKStsYWJzKHRpdGxlPSJUaXRsZSBsaW5lMSBcbiBUaXRsZSBsaW5lMiIsIHg9InByZWRpY3RvciBsYWJlbCIsIHk9Im91dGNvbWUgbGFiZWwgKHVuaXQpIikrdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dCh2anVzdD0tMC40KSkrdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dCh2anVzdD0wLjMpKSt0aGVtZSh0aXRsZT1lbGVtZW50X3RleHQodmp1c3Q9KzEuMSkpK3RoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpK2Nvb3JkX2NhcnRlc2lhbih5bGltPWMobG93ZXJsaW1pdCwgdXBwZXJsaW1pdCkpICsgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAibmFtZSIpKQ0KYGBgDQogICogKmJhcm9iamVjdCo6IG5hbWUgb2YgdGhlIHBsb3QgZGV0ZXJtaW5lZCBpbiB0aGUgcHJldmlvdXMgY29tbWFuZA0KICAqICpzdGF0X3N1bW1hcnkoZnVuLnk9bWVhbiwgZ2VvbT0iYmFyIixmaWxsPSJ3aGl0ZSIsY29sb3I9IkJsYWNrIikqOiBwbG90cyB0aGUgbWVhbiwgYXMgYSBiYXIgZ3JhcGgsIHdpdGggYSB3aGl0ZSBmaWxsIGFuZCBhIGJsYWNrIG91dGxpbmUgLSAqKkRPRVMgTk9UIE5FRUQgVE8gQkUgQ0hBTkdFRCoqIHVubGVzcyB5b3Ugd2lzaCB0byBjaGFuZ2UgdGhlIGNvbG9ycw0KICAqICpzdGF0X3N1bW1hcnkoZnVuLmRhdGE9bWVhbl9jbF9ub3JtYWwsIGdlb209ImVycm9yYmFyIixwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCB3aWR0aD0wLjIpKjogcGxvdHMgdGhlIGVycm9yIGJhcnMgKG1lYXN1cmUgb2YgdmFyaWFiaWxpdHkpIHNvIHRoYXQgdGhleSBkbyBub3Qgb3ZlcmxhcCAtICoqWU9VIERPIE5PVCBORUVEIFRPIENIQU5HRSBBTllUSElORyoqOyANCiAgICAqICoqTk9URSoqOiAgICptZWFuX3NlKiBjYW4gcmVwbGFjZSAqbWVhbl9jbF9ub3JtYWwqIGlmIHlvdSB3aXNoIHRvIHBsb3QgdGhlIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBtZWFuLg0KICAqICpsYWJzKHRpdGxlPSIqKlRpdGxlIGxpbmUxIFxcbiBUaXRsZSBsaW5lMioqIiwgeD0iKipwcmVkaWN0b3IgbGFiZWwqKiIsIHk9Iioqb3V0Y29tZSBsYWJlbCAodW5pdCkqKiIpKjpMYWJlbHMgdGhlIGdyYXBoOyB0aXRsZSBnaXZlcyB0aGUgbmFtZSBvZiB0aGUgbWFpbiBoZWFkaW5nIG9mIHRoZSBncmFwaDsgeCBsYWJlbHMgdGhlIHgtYXhpczsgeSBsYWJlbHMgdGhlIHktYXhpczsgVGhlICIqKlxcbioqIiAgcGxhY2VzIGFueSB3b3JkcyBhZnRlciBpdCBvbiB0aGUgbmV4dCBsaW5lOyAqKkRPRVMgTkVFRCBDSEFOR0lORyoqIC0geW91IG5lZWQgdG8gY2hhbmdlIGV2ZXJ5dGhpbmcgdGhhdCBpcyBpbiB0aGUgcXVvdGF0aW9uIG1hcmtzLg0KICAqICp0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHZqdXN0PS0wLjQpKSt0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHZqdXN0PTAuMykpK3RoZW1lKHRpdGxlPWVsZW1lbnRfdGV4dCh2anVzdD0rMS4xKSkqOiBzZXRzIHRoZSB2ZXJ0aWNhbCBkaXN0YW5jZS9hbGlnbm1lbnQgYi93IHRoZSBzcGVjaWZpYyBoZWFkaW5nIGFuZCB0aGUgYXhpcyAtICoqRE9FUyBOT1QgTkVFRCBDSEFOR0lORyoqDQogICogKnRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpKjogY2VudGVycyB0aGUgdGl0bGUgaG9yaXpvbnRhbGx5IA0KICAqICorY29vcmRfY2FydGVzaWFuKHlsaW09Yyhsb3dlcmxpbWl0LCB1cHBlcmxpbWl0KSkqOiB5b3UgZG8gKipOT1QqKiBhbHdheXMgbmVlZCB0byB1c2UgdGhpcyBwYXJ0IG9mIHRoZSBjb21tYW5kOyBJdCBpcyBvbmx5IG5lZWRlZCB3aGVuIHRoZSB5LWF4aXMgbGltaXRzIG5lZWQgdG8gYmUgYWRqdXN0ZWQgZm9yIGJldHRlciB2aWV3aW5nIG9mIHRoZSBncmFwaDsgSWYgaXQgaXMgbm90IGJlaW5nIHVzZWQsIHJlbW92ZSB0aGUgd2hvbGUgY29tbWFuZCBpbiBiZXR3ZWVuIHRoZSBwbHVzIHNpZ25zIGxlYXZpbmcgb25seSBvbmUgKyBzaWduLiBJZiB1c2VkLCByZXBsYWNlIHRoZSB3b3JkcyBsb3dlcmxpbWl0IGFuZCB1cHBlcmxpbWl0IHdpdGggdGhlIGFwcHJvcHJpYXRlIG51bWJlcnMuDQogICogKmd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIm5hbWUiKSkqOiB3aGVyZSBhcHBsaWNhYmxlLCBwcm92aWRlcyBhIG5ldyBuYW1lIGZvciB0aGUgbGVnZW5kICh0aGUgZGVmYXVsdCBpcyB0aGUgaGVhZGVyIG9mIHRoZSBjb2x1bW4pLg0KDQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1kYW5nZXIiPg0KIyMjIEV4YW1wbGUgb2YgYSBncmFwaCBnZW5lcmF0ZWQgd2l0aCBwcmV2aW91cyBjb21tYW5kDQo8Y2VudGVyPg0KIVtdKEM6L1VzZXJzXHNzYW1tXERlc2t0b3BcU2FtbXV0XFJlc2VhcmNoXFIgTWFya2Rvd24vR3JhcGgtbm8gY29sb3IucG5nKXt3aWR0aD01MCV9DQo8L2NlbnRlcj4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCiMgR2VuZXJhdGluZyBhIGJhciBncmFwaCB3aXRoICoqZGlmZmVyZW50IGNvbG9yZWQgYmFycyoqDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC13YXJuaW5nIj4NCiAgKiBtb3JlIGluZm9ybWF0aW9uIG9uIHRoaXMgaXMgYXZhaWxhYmxlIGluIHRoZSBSIENvb2tib29rLCB1bmRlciBbQ29sb3JzIChnZ3Bsb3QyKV0oaHR0cDovL3d3dy5jb29rYm9vay1yLmNvbS9HcmFwaHMvQ29sb3JzXyhnZ3Bsb3QyKS8pe3RhcmdldD0iX2JsYW5rIn0NCiAgDQojIyBHZW5lcmF0aW5nIGEgYmFyIGdyYXBoIC0gUGFydCBJIA0KYGBge3J9DQpiYXJvYmplY3Q9Z2dwbG90KG9iamVjdEwsIGFlcyhwcmVkaWN0b3Isb3V0Y29tZSxmaWxsPXByZWRpY3RvcikpK3NjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjY29sb3Jjb2RlIiwgIiNjb2xvcmNvZGUiLC4uLi4pKQ0KYGBgDQogICogcmVwbGFjZSBiYXJvYmplY3QsIG9iamVjdEwsIHByZWRpY3Rvciwgb3V0Y29tZSB3aXRoIGFwcHJvcHJpYXRlIGxhYmVscw0KICAqIHJlcGxhY2UgY29sb3Jjb2RlIHdpdGggYXBwcm9wcmlhdGUgY29sb3IgY29kZSBvYnRhaW5lZCBmcm9tIHRoZSBIZXggZmllbGQgYXQgdGhlIFtyYXBpZHRhYmxlcyB3ZWJzaXRlXShodHRwczovL3d3dy5yYXBpZHRhYmxlcy5jb20vd2ViL2NvbG9yL1JHQl9Db2xvci5odG1sICl7dGFyZ2V0PSJfYmxhbmsifSAtIGluIHRoZSBjYXNlIG9mIHRoZSBjb2xvciBzZWxlY3RlZCBpbiB0aGUgZXhhbXBsZSBzaG93biBiZWxvdywgdGhlIGNvZGUgd291bGQgYmUgIzMzOTlGRg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1kYW5nZXIiPg0KPGNlbnRlcj4NCiFbXShDOi9Vc2Vyc1xzc2FtbVxEZXNrdG9wXFNhbW11dFxSZXNlYXJjaFxSIE1hcmtkb3duL0NvbG9ycGFsYXRlLnBuZyl7d2lkdGg9NTAlfQ0KPC9jZW50ZXI+DQo8L2Rpdj4NCiAgKiBhZGQgYXMgbWFueSBjb2xvcnMgYXMgeW91IGhhdmUgdmFyaWFibGVzDQoNCiMjIEdlbmVyYXRpbmcgYSBiYXIgZ3JhcGggLSBQYXJ0IElJIA0KYGBge3J9DQpiYXJvYmplY3Qrc3RhdF9zdW1tYXJ5KGZ1bj1tZWFuLCBnZW9tPSJiYXIiKStzdGF0X3N1bW1hcnkoZnVuLmRhdGE9bWVhbl9jbF9ub3JtYWwsIGdlb209ImVycm9yYmFyIixwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCB3aWR0aD0wLjIpK2xhYnModGl0bGU9IlRpdGxlIGxpbmUxIFxuIFRpdGxlIGxpbmUyIiwgeD0icHJlZGljdG9yIGxhYmVsIiwgeT0ib3V0Y29tZSBsYWJlbCAodW5pdCkiKSt0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHZqdXN0PS0wLjQpKSt0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHZqdXN0PTAuMykpK3RoZW1lKHRpdGxlPWVsZW1lbnRfdGV4dCh2anVzdD0rMS4xKSkrdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSkrY29vcmRfY2FydGVzaWFuKHlsaW09Yyhsb3dlcmxpbWl0LCB1cHBlcmxpbWl0KSkrZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAibmFtZSIpKQ0KYGBgDQogICogKnN0YXRfc3VtbWFyeShmdW4ueT1tZWFuLCBnZW9tPSJiYXIiKSo6IE5vdGljZSBob3cgdGhlIHNlY3Rpb24gIixmaWxsPSJ3aGl0ZSIsY29sb3I9IkJsYWNrIiIgaGFzIGJlZW4gcmVtb3ZlZCBiZWNhdXNlIGNvbG9ycyBhcmUgYWNjb3VudGVkIGZvciBpbiB0aGUgZmlyc3QgY29tbWFuZA0KICAqIEV2ZXJ5dGhpbmcgZWxzZSBpcyBwZXIgdGhlIGZpcnN0IGV4YW1wbGUgb2YgIkdlbmVyYXRpbmcgYSBHcmFwaCINCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyMgRXhhbXBsZSBvZiBhIGdyYXBoIGdlbmVyYXRlZCB3aXRoIHByZXZpb3VzIGNvbW1hbmQNCjxjZW50ZXI+DQohW10oQzovVXNlcnNcc3NhbW1cRGVza3RvcFxTYW1tdXRcUmVzZWFyY2hcUiBNYXJrZG93bi9HcmFwaC13aXRoIGNvbG9yLnBuZyl7d2lkdGg9NTAlfQ0KPC9jZW50ZXI+DQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPg0KIyMgQ3JlYXRpbmcgYSBiYXIgZ3JhcGggd2l0aCAqKm9uZSBpbmRlcGVuZGVudCB2YXJpYWJsZSoqIGFuZCB1c2luZyB0aGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4gZm9yIGVycm9yIGJhcnMNCiAgKiBZb3UgZmlyc3QgbmVlZCB0byBoYXZlIHJ1biB0aGUgZnVuY3Rpb24gYW5kIGFzc29jaWF0ZWQgc3VtbWFyeVNFIGNvbW1hbmQgcHJpb3IgdG8gY29udGludWluZyBmb3J3YXJkIChTZWUgW0Z1bmN0aW9uIGFuZCBjb21tYW5kIGZvciBnZW5lcmF0aW5nIFN0YW5kYXJkIEVycm9yIG9mIHRoZSBNZWFuIChTRU0pXSkNCiAgKiBUaGUgZXhhbXBsZSBiZWxvdyB1c2VzIHRoZSBncmFwaCB3aXRoIGNvbG9yZWQgYmFycyBpbmZvcm1hdGlvbi4gSG93ZXZlciwgdGhpcyBjYW4gYmUgYWRhcHRlZCBhbmQgYXBwbGllZCB0byBhbGwgZm9ybXMgb2YgZ3JhcGhzLg0KICANCiMjIEdlbmVyYXRpbmcgYSBiYXIgZ3JhcGggLSBQYXJ0IEkNCmBgYHtyfQ0KYmFyb2JqZWN0PWdncGxvdChzdW1zdGF0cywgYWVzKHByZWRpY3RvcixvdXRjb21lLGZpbGw9cHJlZGljdG9yKSkrc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNjb2xvcmNvZGUiLCAiI2NvbG9yY29kZSIsLi4uLikpDQpgYGANCiAgKiAqKk5PVEU6Kiogc3Vtc3RhdHMgaXMgdXNlZCB0byBwcm92aWRlIHRoZSBkYXRhIHRvIGJlIHBsb3R0ZWQNCiAgKiBBZGRpdGlvbmFsbHksIHNlZSBbR2VuZXJhdGluZyBhIGJhciBncmFwaCB3aXRoICoqZGlmZmVyZW50IGNvbG9yZWQgYmFycyoqXSBmb3IgZGV0YWlscyBvZiB3aGF0IG5lZWRzIHRvIGJlIGNoYW5nZWQNCg0KIyMgR2VuZXJhdGluZyBhIGJhciBncmFwaCAtIFBhcnQgSUkgDQpgYGB7cn0NCmJhcm9iamVjdCtzdGF0X3N1bW1hcnkoZnVuPW1lYW4sIGdlb209ImJhciIpK2dlb21fZXJyb3JiYXIoYWVzKHltaW49b3V0Y29tZS1zZSwgeW1heD1vdXRjb21lK3NlKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCB3aWR0aD0wLjIpK2xhYnModGl0bGU9IlRpdGxlIGxpbmUxIFxuIFRpdGxlIGxpbmUyIiwgeD0icHJlZGljdG9yIGxhYmVsIiwgeT0ib3V0Y29tZSBsYWJlbCAodW5pdCkiKSt0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHZqdXN0PS0wLjQpKSt0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHZqdXN0PTAuMykpK3RoZW1lKHRpdGxlPWVsZW1lbnRfdGV4dCh2anVzdD0rMS4xKSkrdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSkrY29vcmRfY2FydGVzaWFuKHlsaW09Yyhsb3dlcmxpbWl0LCB1cHBlcmxpbWl0KSkrZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAibmFtZSIpKQ0KYGBgDQogICogKmdlb21fZXJyb3JiYXIoYWVzKHltaW49b3V0Y29tZS1zZSwgeW1heD1vdXRjb21lK3NlKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCB3aWR0aD0wLjIpKjogVGhpcyBjb21tYW5kIG5vdyBwcm92aWRlcyB0aGUgaW5mb3JtYXRpb24gZm9yIHRoZSBlcnJvcmJhcnMuIEhvd2V2ZXIgeW91IG5lZWQgdG8gcmVwbGFjZSB0aGUgd29yZCAib3V0Y29tZSIgd2l0aCB0aGUgYXBwcm9wcmlhdGUgbmFtZSBmb3IgdGhlIG91dGNvbWUgdmFyaWFibGUuDQogICogRXZlcnl0aGluZyBlbHNlIGlzIHBlciB0aGUgZmlyc3QgZXhhbXBsZSBvZiBbR2VuZXJhdGluZyBhIGJhciBncmFwaF0NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyMgRXhhbXBsZSBvZiBhIGdyYXBoIGdlbmVyYXRlZCB3aXRoIHByZXZpb3VzIGNvbW1hbmQNCjxjZW50ZXI+DQohW10oQzovVXNlcnNcc3NhbW1cRGVza3RvcFxTYW1tdXRcUmVzZWFyY2hcUiBNYXJrZG93bi9HcmFwaC1vbmVpbmR2YXIucG5nKXt3aWR0aD01MCV9DQo8L2NlbnRlcj4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPg0KIyMgQ3JlYXRpbmcgYSBiYXIgZ3JhcGggd2l0aCAqKm11bHRpcGxlIGluZGVwZW5kZW50IHZhcmlhYmxlcyoqIGFuZCB1c2luZyB0aGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4gZm9yIGVycm9yIGJhcnMNCiAgKiBZb3UgZmlyc3QgbmVlZCB0byBoYXZlIHJ1biB0aGUgZnVuY3Rpb24gYW5kIGFzc29jaWF0ZWQgc3VtbWFyeVNFIGNvbW1hbmQgcHJpb3IgdG8gY29udGludWluZyBmb3J3YXJkIChTZWUgW0Z1bmN0aW9uIGFuZCBjb21tYW5kIGZvciBnZW5lcmF0aW5nIFN0YW5kYXJkIEVycm9yIG9mIHRoZSBNZWFuIChTRU0pXSkNCiAgKiBUaGUgZXhhbXBsZSBiZWxvdyB1c2VzIHRoZSBncmFwaCB3aXRoIGNvbG9yZWQgYmFycyBpbmZvcm1hdGlvbi4gSG93ZXZlciwgdGhpcyBjYW4gYmUgYWRhcHRlZCBhbmQgYXBwbGllZCB0byBhbGwgZm9ybXMgb2YgZ3JhcGhzLg0KICANCiMjIEdlbmVyYXRpbmcgYSBiYXIgZ3JhcGggLSBQYXJ0IEkNCmBgYHtyfQ0KYmFyb2JqZWN0PWdncGxvdChzdW1zdGF0cywgYWVzKHByZWRpY3RvcixvdXRjb21lLGZpbGw9cHJlZGljdG9yXzIpKStzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI2NvbG9yY29kZSIsICIjY29sb3Jjb2RlIiwuLi4uKSkNCmBgYA0KICAqICoqTk9URToqKiBzdW1zdGF0cyBpcyB1c2VkIHRvIHByb3ZpZGUgdGhlIGRhdGEgdG8gYmUgcGxvdHRlZA0KICAqIHByZWRpY3RvcjogdGhlIG1haW4gcHJlZGljdG9yIHRoYXQgaXMgZ29pbmcgdG8gYmUgb24gdGhlIHgtYXhpcw0KICAqIHByZWRpY3Rvcl8yOiB0aGUgcHJlZGljdG9yIHRoYXQgcHJvdmlkZXMgdGhlIHN1Yi1jYXRlZ29yaWVzIHdpdGhpbiB0aGUgbWFpbiBwcmVkaWN0b3INCiAgKiBBZGRpdGlvbmFsbHksIHNlZSBbR2VuZXJhdGluZyBhIGJhciBncmFwaCB3aXRoICoqZGlmZmVyZW50IGNvbG9yZWQgYmFycyoqXSBmb3IgZGV0YWlscyBvZiB3aGF0IG5lZWRzIHRvIGJlIGNoYW5nZWQNCg0KIyMgR2VuZXJhdGluZyBhIGJhciBncmFwaCAtIFBhcnQgSUkgDQpgYGB7cn0NCmJhcm9iamVjdCtzdGF0X3N1bW1hcnkoZnVuPW1lYW4sIGdlb209ImJhciIscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC45KSwgbGluZXdpZHRoPTMpK2dlb21fZXJyb3JiYXIoYWVzKHltaW49b3V0Y29tZS1zZSwgeW1heD1vdXRjb21lK3NlKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCB3aWR0aD0wLjIpK2xhYnModGl0bGU9IlRpdGxlIGxpbmUxIFxuIFRpdGxlIGxpbmUyIiwgeD0icHJlZGljdG9yIGxhYmVsIiwgeT0ib3V0Y29tZSBsYWJlbCAodW5pdCkiKSt0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHZqdXN0PS0wLjQpKSt0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHZqdXN0PTAuMykpK3RoZW1lKHRpdGxlPWVsZW1lbnRfdGV4dCh2anVzdD0rMS4xKSkrdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSkrY29vcmRfY2FydGVzaWFuKHlsaW09Yyhsb3dlcmxpbWl0LCB1cHBlcmxpbWl0KSkrZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAibmFtZSIpKQ0KYGBgDQogICogKmdlb21fZXJyb3JiYXIoYWVzKHltaW49b3V0Y29tZS1zZSwgeW1heD1vdXRjb21lK3NlKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCB3aWR0aD0wLjIpKjogVGhpcyBjb21tYW5kIG5vdyBwcm92aWRlcyB0aGUgaW5mb3JtYXRpb24gZm9yIHRoZSBlcnJvcmJhcnMuIEhvd2V2ZXIgeW91IG5lZWQgdG8gcmVwbGFjZSB0aGUgd29yZCAib3V0Y29tZSIgd2l0aCB0aGUgYXBwcm9wcmlhdGUgbmFtZSBmb3IgdGhlIG91dGNvbWUgdmFyaWFibGUuDQogICogRXZlcnl0aGluZyBlbHNlIGlzIHBlciB0aGUgZmlyc3QgZXhhbXBsZSBvZiBbR2VuZXJhdGluZyBhIGJhciBncmFwaF0NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyMgRXhhbXBsZSBvZiBhIGdyYXBoIGdlbmVyYXRlZCB3aXRoIHByZXZpb3VzIGNvbW1hbmQNCjxjZW50ZXI+DQohW10oQzovVXNlcnNcc3NhbW1cRGVza3RvcFxTYW1tdXRcUmVzZWFyY2hcUiBNYXJrZG93bi9HcmFwaC10d29pbmR2YXJzLnBuZyl7d2lkdGg9NTAlfQ0KPC9jZW50ZXI+DQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC13YXJuaW5nIj4NCiMjIENyZWF0aW5nIGJhciBncmFwaHMgd2l0aCAqKm11bHRpcGxlIGluZGVwZW5kZW50IHZhcmlhYmxlcyoqLCBwbG90dGVkIGFzIHRocmVlIHNlcGFyYXRlIGdyYXBocyAob25lIHBlciB2YXJpYWJsZSkgaW4gb25lIGdyaWQNCiAgKiAqKk9yaWdpbmFsIGRhdGEgKGNvbnRhaW5lZCBpbiAib2JqZWN0TCIgY29udGFpbnMgdGhlIGZvbGxvd2luZyBjb2x1bW5zICJTdWJqZWN0IiwgInZhcjEiLCAidmFyMiIsICJ2YXIzIiwgImRhdGEiKioNCiAgDQojIyBHZW5lcmF0aW5nIGEgZ3JpZCBvZiBiYXIgZ3JhcGhzIC0gRXhhbXBsZSAxDQpgYGB7cn0NCiMgTWFrZSBhIG1vZGlmaWVkIGNvcHkgb2YgdGhlIG9yaWdpbmFsIGRhdGENCm9iamVjdExfbW9kIDwtIG9iamVjdEwgJT4lDQoNCiMgUmVuYW1lIHZhcmlhYmxlcyB3aXRoaW4gdmFyMw0KICAjIG9ubHkgaWYgbmVjZXNzYXJ5L2Rlc2lyZWQNCiAgIyB2YXIzLjEgZXRjLiByZXByZXNlbnQgZGlmZmVyZW50IHZhcmlhYmxlcyB3aXRoaW4gdmFyMw0KICAjIC9uIGNhbiBiZSB1c2VkIHdpdGhpbiB0aGUgbmFtZXMgaWYgdGhlIG5ldyBuYW1lIGlzIGxvbmcgYW5kIGl0IGlzIGRlc2lyZWQgdG8gc3BsaXQgdGhlIHRpdGxlIGludG8gdHdvIGxpbmVzDQptdXRhdGUodmFyMyA9IHJlY29kZSh2YXIzLCAib2xkdmFyMy4xXG5uYW1lIiA9ICJuZXd2YXIzLjFcbm5hbWUiLCAib2xkdmFyMy4yXG5uYW1lIiA9ICJuZXd2YXIzLjJcbm5hbWUiLCAib2xkdmFyMy4zXG5uYW1lIiA9ICJuZXd2YXIzLjNcbm5hbWUiKSkgIyBkbyBub3QgYWRkIHNwYWNlcyBiZWZvcmUgYW5kIGFmdGVyIFxuIG9yIHRoZSBmYWNldCB0aXRsZSB3aWxsIG5vdCBiZSBjZW50ZXJlZA0KICANCiMgR2VuZXJhdGUgZ3JhcGgNCmJhcl9vYmplY3RMPWdncGxvdChvYmplY3RMX21vZCwgYWVzKHZhcjEsZGF0YSxmaWxsPXZhcjEpKStzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI0NDMDAwMCIsICIjMDA0Qzk5IikpDQoNCmJhcl9vYmplY3RMLlN1Yj1iYXJfb2JqZWN0TCtzdGF0X3N1bW1hcnkoZnVuPW1lYW4sIGdlb209ImJhciIscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC45KSwgbGluZXdpZHRoPTMpK3N0YXRfc3VtbWFyeShmdW4uZGF0YT1tZWFuX2NsX25vcm1hbCwgZ2VvbT0iZXJyb3JiYXIiLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksIHdpZHRoPTAuMikrbGFicyh0aXRsZT0idGl0bGUiLCB4PSJ4IGF4aXMgdGl0bGUiLCB5PSJ5IGF4aXMgdGl0bGUiKSArIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQodmp1c3Q9LTAuNCkpICsgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dCh2anVzdD0wLjMpKSArIHRoZW1lKHRpdGxlPWVsZW1lbnRfdGV4dCh2anVzdD0rMS4xKSkgKyB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpKStndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJ2YXIxIikpDQoNCiAgIyBiYXJfb2JqZWN0TC5TdWI6IGNvbnRhaW5zIHRoZSBjb21tYW5kIHRvIGdlbmVyYXRlIHRoZSBncmFwaCB3aXRoIHRoZSB2YXJpb3VzIHN1Yi1jYXRlZ29yaWVzIHByZXNlbnQgdmFyMw0KICAjICtndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJ2YXIxIikpOiByZWxhYmVscyB0aGUgaGVhZGluZyBvZiB0aGUgbGVnZW5kDQoNCiMgQ3JlYXRlIGdyaWQNCmJhcl9vYmplY3RMLlN1YitmYWNldF9ncmlkKGNvbHM9dmFycyh2YXIzKSkNCmBgYA0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtZGFuZ2VyIj4NCiMjIyBFeGFtcGxlIG9mIGEgZ3JhcGggZ2VuZXJhdGVkIHdpdGggcHJldmlvdXMgY29tbWFuZA0KPGNlbnRlcj4NCiFbXShDOi9Vc2Vyc1xzc2FtbVxEZXNrdG9wXFNhbW11dFxSZXNlYXJjaFxSIE1hcmtkb3duL2ZhY2V0Z3JpZCBncmFwaC5wbmcpe3dpZHRoPTUwJX0NCjwvY2VudGVyPg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtd2FybmluZyI+DQoNCiMjIEdlbmVyYXRpbmcgYSBncmlkIG9mIGJhciBncmFwaHMgLSBFeGFtcGxlIDFhDQogICogKipPcmlnaW5hbCBkYXRhIChjb250YWluZWQgaW4gIm9iamVjdEwiIGNvbnRhaW5zIHRoZSBmb2xsb3dpbmcgY29sdW1ucyAiU3ViamVjdCIsICJ2YXIxIiwgInZhcjIiLCAidmFyMyIsICJkYXRhIioqDQogICogVGhpcyBncmFwaCBpcyBhIG1vZGlmaWVkIHZlcnNpb24gb2YgdGhhdCBzaG93biBpbiBFeGFtcGxlIDEgLSBTZWUgW0dlbmVyYXRpbmcgYSBncmlkIG9mIGJhciBncmFwaHMgLSBFeGFtcGxlIDFdDQogICogVGhpcyBncmFwaCB1c2VzIHRoZSBTRU0gaW5zdGVhZCBvZiB0aGUgQ29uZmlkZW5jZSBpbnRlcnZhbCB0byBnZW5lcmF0ZSB0aGUgZXJyb3IgYmFycyBhbmQgYWxzbyBzaG93cyB0aGUgc2lnbmlmaWNhbmNlcw0KYGBge3J9DQojIE1ha2UgYSBtb2RpZmllZCBjb3B5IG9mIHRoZSBvcmlnaW5hbCBkYXRhDQpvYmplY3RMX21vZCA8LSBvYmplY3RMICU+JQ0KDQojIFJlbmFtZSB2YXJpYWJsZXMgd2l0aGluIHZhcjMNCiAgIyBvbmx5IGlmIG5lY2Vzc2FyeS9kZXNpcmVkDQogICMgdmFyMy4xIGV0Yy4gcmVwcmVzZW50IGRpZmZlcmVudCB2YXJpYWJsZXMgd2l0aGluIHZhcjMNCiAgIyAvbiBjYW4gYmUgdXNlZCB3aXRoaW4gdGhlIG5hbWVzIGlmIHRoZSBuZXcgbmFtZSBpcyBsb25nIGFuZCBpdCBpcyBkZXNpcmVkIHRvIHNwbGl0IHRoZSB0aXRsZSBpbnRvIHR3byBsaW5lcw0KbXV0YXRlKHZhcjMgPSByZWNvZGUodmFyMywgIm9sZHZhcjMuMVxubmFtZSIgPSAibmV3dmFyMy4xXG5uYW1lIiwgIm9sZHZhcjMuMlxubmFtZSIgPSAibmV3dmFyMy4yXG5uYW1lIiwgIm9sZHZhcjMuM1xubmFtZSIgPSAibmV3dmFyMy4zXG5uYW1lIikpICMgZG8gbm90IGFkZCBzcGFjZXMgYmVmb3JlIGFuZCBhZnRlciBcbiBvciB0aGUgZmFjZXQgdGl0bGUgd2lsbCBub3QgYmUgY2VudGVyZWQNCmBgYA0KKiBHZW5lcmF0ZSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzIHRoYXQgcHJvdmlkZSBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVhbiANCiAgKiBGb3IgZ2VuZXJhdGluZyBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHdpdGggc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4gcGxlYXNlIHNlZSBbRnVuY3Rpb24gYW5kIGNvbW1hbmQgZm9yIGdlbmVyYXRpbmcgU3RhbmRhcmQgRXJyb3Igb2YgdGhlIE1lYW4gKFNFTSldDQogICogc3Vtc3RhdHNfb2JqZWN0OiB0aGlzIGlzIHRoZSBuYW1lIG9mIHRoZSBvYmplY3QgdGhhdCBjb250YWlucyB0aGUgb3V0cHV0IGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgDQoNCmBgYHtyfSAgDQojIEdlbmVyYXRlIGdyYXBoDQpiYXJfb2JqZWN0PWdncGxvdChzdW1zdGF0c19vYmplY3QsIGFlcyh4PXByZWRpY3Rvcix5PW91dGNvbWUpKStzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI0NDMDAwMCIsICIjMDA0Qzk5IikpDQoNCmJhcl9vYmplY3QuU3ViPWJhcl9vYmplY3QrZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksIGxpbmV3aWR0aD0zLCBhZXMoZmlsbD1wcmVkaWN0b3IpKStnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW91dGNvbWUtc2UsIHltYXg9b3V0Y29tZStzZSkscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC45KSwgd2lkdGg9MC4yKStsYWJzKHRpdGxlPSJUaXRsZSIsIHg9InggYXhpcyB0aXRsZSIsIHk9InkgYXhpcyB0aXRsZSIpICsgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dCh2anVzdD0tMC40KSkgKyB0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHZqdXN0PTAuMykpICsgdGhlbWUodGl0bGU9ZWxlbWVudF90ZXh0KHZqdXN0PSsxLjEpKSArIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpICsgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAicHJlZGljdG9yIikpICtjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKGxvd2VybGltaXQsdXBwZXJsaW1pdCkpKyBnZW9tX3NpZ25pZihkYXRhPWRhdGEuZnJhbWUocHJlZGljdG9yMj1jKCJuZXd2YXIzLjFcbm5hbWUiLCJuZXd2YXIzLjJcbm5hbWUiLCJuZXd2YXIzLjNcbm5hbWUiKSksYWVzKHlfcG9zaXRpb249YygyMS41LCAyNC41LCAtMiksIHhtaW49YygxLjAsIDEuMCwgMS4wKSwgeG1heD1jKDIsIDIsIDIpLGFubm90YXRpb25zID0gYygiKioiLCIqIiwiIikpLCB0aXBfbGVuZ3RoID0gMCwgbWFudWFsPVQpDQoNCiAgIyBUaGUgc3RhdGlzdGljIHRoYXQgd2FzIE5PVCBzaWduaWZpY2FudCBoYXMgYmVlbiBwbGFjZWQgYmV5b25kIHRoZSB5LXNjYWxlIGxpbWl0LiBUaGUgY29vcmRfY2FydGVzaWFuIGNvbW1hbmQgZW5zdXJlcyB0aGF0IHRoZSBheGVzIGxpbWl0cyBhcmUgYXMgZGVzaXJlZCBhbmQgdGhhdCB0aGUgbm9uLXNpZ25pZmljYW50IGJhciBkb2VzIG5vdCBzaG93IHVwLg0KICAjIG91dGNvbWU6IHVuZGVyIGdlb21fZXJyb3JiYXIgLSB0aGlzIHJlZmVycyB0byB0aGUgaGVhZGluZyBvZiB0aGUgb3V0Y29tZSBjb2x1bW4gaW4gdGhlIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3Mgb3V0cHV0Lg0KICAjIGdlb21fc2lnbmlmOiBudW1iZXJzIHNob3duIGluIHBhcmVudGhlc2lzIG5lZWQgdG8gYmUgYWRqdXN0ZWQgYWNjb3JkaW5nbHkgdG8gYWNjb21tb2RhdGUgZm9yIGhlaWdodCAoaW4gcmVsYXRpb24gdG8gdGhlIHlfcG9zaXRpb24pIGFuZC9vciBwb3NpdGlvbiByZWxhdGl2ZSB0byBiYXJzIChpbiByZWxhdGlvbiB0byB0aGUgeG1pbiBhbmQgeG1heCkuIEFkZGl0aW9uYWxseSwgdGhlIGFubm90YXRpb24gbmVlZHMgdG8gYmUgYXBwcm9wcmlhdGVseSBjb3JyZWN0ZWQgdG8gcmVmbGVjdCB0aGUgYXBwcm9wcmlhdGUgc2lnbmlmaWNhbmNlcy4NCg0KIyBDcmVhdGUgZ3JpZA0KYmFyX0JJUy5TdWIrZmFjZXRfZ3JpZCh+QklTX0NhdCwgc2NhbGVzPSJmaXhlZCIpDQoNCiMgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKSAtICMgUmVtb3ZlcyB2YXJpYWJsZSBsYWJlbCBuYW1lcyBpbiB0aGUgeC1heGlzIGlmIHRoZXkgYXJlIG5vdCBkZXNpcmVkLg0KIyB0aGVtZShheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKSAtICMgcmVtb3ZlcyB0aWNrcyAobWF5IGJlIHVzZWQgd2l0aCBhYm92ZSBjb21tYW5kKQ0KDQojIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzU2MjE5NDY4L3VzaW5nLWdnc2lnbmlmLXdpdGgtZ3JvdXBlZC1iYXItZ3JhcGhzLWFuZC1mYWNldC13cmFwLW5vdC13b3JraW5nDQpgYGANCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyMgRXhhbXBsZSBvZiBhIGdyYXBoIGdlbmVyYXRlZCB3aXRoIHByZXZpb3VzIGNvbW1hbmQNCjxjZW50ZXI+DQohW10oQzovVXNlcnNcc3NhbW1cRGVza3RvcFxTYW1tdXRcUmVzZWFyY2hcUiBNYXJrZG93bi9ncmFwaCB3aXRoIHNpZ25maWNhbmNlICYgZmFjZXRzLnBuZyl7d2lkdGg9NTAlfQ0KPC9jZW50ZXI+DQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC13YXJuaW5nIj4NCiMjIEdlbmVyYXRpbmcgYSBncmlkIG9mIGJhciBncmFwaHMgLSBFeGFtcGxlIDINCiAgKiAqKk9yaWdpbmFsIGRhdGEgKGNvbnRhaW5lZCBpbiAib2JqZWN0TCIgY29udGFpbnMgdGhlIGZvbGxvd2luZyBjb2x1bW5zICJTdWJqZWN0IiwgInZhcjEiLCAidmFyMiIsICJ2YXIzIiwgImRhdGEiKioNCmBgYHtyfQ0KIyBNYWtlIGEgbW9kaWZpZWQgY29weSBvZiB0aGUgb3JpZ2luYWwgZGF0YQ0Kb2JqZWN0TF9tb2QgPC0gb2JqZWN0TCAlPiUNCg0KIyBSZW5hbWUgdmFyaWFibGVzIHdpdGhpbiB2YXIzDQogICMgb25seSBpZiBuZWNlc3NhcnkvZGVzaXJlZA0KICAjIHZhcjMuMSBldGMuIHJlcHJlc2VudCBkaWZmZXJlbnQgdmFyaWFibGVzIHdpdGhpbiB2YXIzDQogICMgL24gY2FuIGJlIHVzZWQgd2l0aGluIHRoZSBuYW1lcyBpZiB0aGUgbmV3IG5hbWUgaXMgbG9uZyBhbmQgaXQgaXMgZGVzaXJlZCB0byBzcGxpdCB0aGUgdGl0bGUgaW50byB0d28gbGluZXMNCm11dGF0ZSh2YXIzID0gcmVjb2RlKHZhcjMsICJvbGR2YXIzLjFcbm5hbWUiID0gIm5ld3ZhcjMuMVxubmFtZSIsICJvbGR2YXIzLjJcbm5hbWUiID0gIm5ld3ZhcjMuMlxubmFtZSIsICJvbGR2YXIzLjNcbm5hbWUiID0gIm5ld3ZhcjMuM1xubmFtZSIpKSAgIyBkbyBub3QgYWRkIHNwYWNlcyBiZWZvcmUgYW5kIGFmdGVyIFxuIG9yIHRoZSBmYWNldCB0aXRsZSB3aWxsIG5vdCBiZSBjZW50ZXJlZA0KICANCiMgR2VuZXJhdGUgZ3JhcGgNCmJhcl9vYmplY3RMPWdncGxvdChvYmplY3RMX21vZCwgYWVzKHZhcjEsZGF0YSxmaWxsPXZhcjIpKStzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI0NDMDAwMCIsICIjMDA0Qzk5IikpDQoNCmJhcl9vYmplY3RMLlN1Yj1iYXJfb2JqZWN0TCtzdGF0X3N1bW1hcnkoZnVuPW1lYW4sIGdlb209ImJhciIscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC45KSwgbGluZXdpZHRoPTMpK3N0YXRfc3VtbWFyeShmdW4uZGF0YT1tZWFuX2NsX25vcm1hbCwgZ2VvbT0iZXJyb3JiYXIiLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksIHdpZHRoPTAuMikrbGFicyh0aXRsZT0idGl0bGUiLCB4PSJ4IGF4aXMgdGl0bGUiLCB5PSJ5IGF4aXMgdGl0bGUiKSArIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQodmp1c3Q9LTAuNCkpICsgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dCh2anVzdD0wLjMpKSArIHRoZW1lKHRpdGxlPWVsZW1lbnRfdGV4dCh2anVzdD0rMS4xKSkgKyB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpKStndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJ2YXIyIikpDQoNCiAgIyBiYXJfb2JqZWN0TC5TdWI6IGNvbnRhaW5zIHRoZSBjb21tYW5kIHRvIGdlbmVyYXRlIHRoZSBncmFwaCB3aXRoIHRoZSB2YXJpb3VzIHN1Yi1jYXRlZ29yaWVzIHByZXNlbnQgdmFyMw0KICAjICtndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJ2YXIyIikpOiByZWxhYmVscyB0aGUgaGVhZGluZyBvZiB0aGUgbGVnZW5kDQoNCiMgQ3JlYXRlIGdyaWQNCmJhcl9vYmplY3RMLlN1YitmYWNldF9ncmlkKGNvbHM9dmFycyh2YXIzKSkNCmBgYA0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtZGFuZ2VyIj4NCiMjIyBFeGFtcGxlIG9mIGEgZ3JhcGggZ2VuZXJhdGVkIHdpdGggcHJldmlvdXMgY29tbWFuZA0KPGNlbnRlcj4NCiFbXShDOi9Vc2Vyc1xzc2FtbVxEZXNrdG9wXFNhbW11dFxSZXNlYXJjaFxSIE1hcmtkb3duL2ZhY2V0Z3JpZCBncmFwaF8xLnBuZyl7d2lkdGg9NTAlfQ0KPC9jZW50ZXI+DQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC13YXJuaW5nIj4NCiMjIEdlbmVyYXRpbmcgYSBiYXIgZ3JhcGhzIHdpdGggc2lnbmlmaWNhbmNlIHNob3duIC0gRXhhbXBsZSAzDQoNCiogR2VuZXJhdGUgRGVzY3JpcHRpdmUgU3RhdGlzdGljcyB0aGF0IHByb3ZpZGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4gDQogICogRm9yIGdlbmVyYXRpbmcgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyB3aXRoIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBtZWFuIHBsZWFzZSBzZWUgW0Z1bmN0aW9uIGFuZCBjb21tYW5kIGZvciBnZW5lcmF0aW5nIFN0YW5kYXJkIEVycm9yIG9mIHRoZSBNZWFuIChTRU0pXQ0KICAqIHN1bXN0YXRzX29iamVjdDogdGhpcyBpcyB0aGUgbmFtZSBvZiB0aGUgb2JqZWN0IHRoYXQgY29udGFpbnMgdGhlIG91dHB1dCBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIA0KDQpgYGB7cn0NCiMgUGxvdCBHcmFwaA0KDQpwcmVkaWN0b3IuciA9IGZhY3RvciAoc3Vtc3RhdHNfb2JqZWN0JHByZWRpY3Rvci5yLCBsZXZlbHM9YygibGV2ZWwxIiwgImxldmVsMiIsICJsZXZlbF9uIikpDQogICMgcHJlZGljdG9yLnIgOiBuYW1lIG9mIHZhcmlhYmxlIHRoYXQgaGFzIGhhZCBsZXZlbHMgcmVvcmdhbml6ZWQgZm9yIGdyYXBoaW5nIHB1cnBvc2VzDQogICMgcHJlZGljdG9yLnI6IHByZWRpY3RvciB0aGF0IHJlcXVpcmVzIGxldmVscyB0byBiZSBvcmdhbml6ZWQgZm9yIGdyYXBoaWMgcHVycG9zZXMNCiAgIyBsZXZlbDEsIGV0Yy46IGxldmVsIG5hbWVzIGxpc3RlZCBpbiB0aGUgb3JkZXIgdGhhdCB5b3Ugd2lzaCB0aGVtIGdyYXBoZWQNCg0KYmFyX29iamVjdD1nZ3Bsb3Qoc3Vtc3RhdHNfb2JqZWN0LCBhZXMoeD0gcHJlZGljdG9yLnIseT1vdXRjb21lKSkrIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjQ0MwMDAwIiwgIiMwMDRDOTkiKSkgDQoNCmJhcl9vYmplY3QrZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksIGxpbmV3aWR0aD0zLCBhZXMoZmlsbD1wcmVkaWN0b3IpKStnZW9tX2Vycm9yYmFyKGFlcyh5bWluPU91dGNvbWUtc2UsIHltYXg9T3V0Y29tZStzZSkscG9zaXRpb249cG9zaXRpb25fZG9kZ2UyKDAuOSwgcGFkZGluZz0wLjYpKStsYWJzKHRpdGxlPSJUaXRsZSIsIHg9InggYXhpcyB0aXRsZSIsIHk9InkgYXhpcyB0aXRsZSIpICsgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dCh2anVzdD0tMC40KSkgKyB0aGVtZShheGlzLnRpdGxlLnk9ZWxlbWVudF90ZXh0KHZqdXN0PTAuMykpICsgdGhlbWUodGl0bGU9ZWxlbWVudF90ZXh0KHZqdXN0PSsxLjEpKSArIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpICsgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiTGVnZW5kIFRpdGxlIikpICsgZ2VvbV9zaWduaWYoeV9wb3NpdGlvbj1jKDMwLjUsIDE2LjUsIDE1LjUpLCB4bWluPWMoMC43LCA0LjcsIDUuNyksIHhtYXg9YygxLjMsIDUuMywgNi4zKSxhbm5vdGF0aW9uID0gYygiKioqIiwiKiIsIioqIiksIHRpcF9sZW5ndGggPSAwKQ0KICANCiAgIyBvdXRjb21lOiB1bmRlciBnZW9tX2Vycm9yYmFyIC0gdGhpcyByZWZlcnMgdG8gdGhlIGhlYWRpbmcgb2YgdGhlIG91dGNvbWUgY29sdW1uIGluIHRoZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIG91dHB1dC4NCiAgIyBnZW9tX3NpZ25pZjogbnVtYmVycyBzaG93biBpbiBwYXJlbnRoZXNpcyBuZWVkIHRvIGJlIGFkanVzdGVkIGFjY29yZGluZ2x5IHRvIGFjY29tbW9kYXRlIGZvciBoZWlnaHQgKGluIHJlbGF0aW9uIHRvIHRoZSB5X3Bvc2l0aW9uKSBhbmQvb3IgcG9zaXRpb24gcmVsYXRpdmUgdG8gYmFycyAoaW4gcmVsYXRpb24gdG8gdGhlIHhtaW4gYW5kIHhtYXgpLiBBZGRpdGlvbmFsbHksIHRoZSBhbm5vdGF0aW9uIG5lZWRzIHRvIGJlIGFwcHJvcHJpYXRlbHkgY29ycmVjdGVkIHRvIHJlZmxlY3QgdGhlIGFwcHJvcHJpYXRlIHNpZ25pZmljYW5jZXMuDQoNCiMgUmVzb3VyY2VzIHRoYXQgbWF5IGJlIG9mIGFzc2lzdGFuY2UNCg0KIyBodHRwczovL3N0YXRpc3RpY3NnbG9iZS5jb20vZ2dzaWduaWYtcGFja2FnZS1yDQojIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzUxNDQzODg5L2hvdy1jYW4taS1nZXQtZ2VvbS1lcnJvcmJhci10by1kb2RnZS1jb3JyZWN0bHktb24tYS1iYXItY2hhcnQtaW4tZ2dwbG90Mg0KIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy81OTAwODk3NC93aHktaXMtc3RhdC1pZGVudGl0eS1uZWNlc3NhcnktaW4tZ2VvbS1iYXItaW4tZ2dwbG90IzU5MDA5MTA4DQojIGh0dHA6Ly9zdGhkYS5jb20vZW5nbGlzaC93aWtpL2dncGxvdDItZXJyb3ItYmFycy1xdWljay1zdGFydC1ndWlkZS1yLXNvZnR3YXJlLWFuZC1kYXRhLXZpc3VhbGl6YXRpb24NCiMgaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNjEwMjI5OTIvbWFudWFsbHktcGxvdHRpbmctc2lnbmlmaWNhbmNlLXJlbGF0aW9ucy1iZXR3ZWVuLXN1Yi1ncm91cHMtb24tZ2dwbG90Mi1iYXJwbG90DQpgYGANCg0KPC9jZW50ZXI+DQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1kYW5nZXIiPg0KIyMjIEV4YW1wbGUgb2YgYSBncmFwaCBnZW5lcmF0ZWQgd2l0aCBwcmV2aW91cyBjb21tYW5kDQo8Y2VudGVyPg0KIVtdKEM6L1VzZXJzXHNzYW1tXERlc2t0b3BcU2FtbXV0XFJlc2VhcmNoXFIgTWFya2Rvd24vZ3JhcGggd2l0aCBzaWduZmljYW5jZS5wbmcpe3dpZHRoPTUwJX0NCjwvY2VudGVyPg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC13YXJuaW5nIj4NCiMjIEdlbmVyYXRpbmcgYSBiYXIgZ3JhcGhzIHdpdGggc2lnbmlmaWNhbmNlIHNob3duIGFuZCByZW9yZGVyZWQgZmFjZXRzIC0gRXhhbXBsZSA0DQoNCiogR2VuZXJhdGUgRGVzY3JpcHRpdmUgU3RhdGlzdGljcyB0aGF0IHByb3ZpZGUgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4gDQogICogRm9yIGdlbmVyYXRpbmcgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyB3aXRoIHN0YW5kYXJkIGVycm9yIG9mIHRoZSBtZWFuIHBsZWFzZSBzZWUgW0Z1bmN0aW9uIGFuZCBjb21tYW5kIGZvciBnZW5lcmF0aW5nIFN0YW5kYXJkIEVycm9yIG9mIHRoZSBNZWFuIChTRU0pXQ0KICAqIHN1bXN0YXRzb2JqZWN0OiB0aGlzIGlzIHRoZSBuYW1lIG9mIHRoZSBvYmplY3QgdGhhdCBjb250YWlucyB0aGUgb3V0cHV0IGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgDQoNCmBgYHtyfQ0KIyBQbG90IEdyYXBoDQoNCiMgR2VuZXJhdGUgZ3JhcGgNCg0KYmFyX29iamVjdD1nZ3Bsb3Qoc3Vtc3RhdHNvYmplY3QucixhZXMoeD1wcmVkaWN0b3IxLHk9b3V0Y29tZSkpK3NjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjQ0MwMDAwIiwgIiMwMDRDOTkiKSkNCg0KYmFyX29iamVjdC5TdWI9YmFyX29iamVjdCtnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC45KSwgbGluZXdpZHRoPTMsIGFlcyhmaWxsPXByZWRpY3RvcjEpKSArIGdlb21fZXJyb3JiYXIoYWVzKHltaW49RGF0YS1zZSwgeW1heD1EYXRhK3NlKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCB3aWR0aD0wLjIpK2xhYnModGl0bGU9IlRpdGxlIExpbmUxXG5UaXRsZUxpbmUyIiwgeD0ieC1sYWJlbCIsIHk9InktbGFiZWwiKSArIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X3RleHQodmp1c3Q9LTAuNCkpICsgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dCh2anVzdD0wLjMpKSArIHRoZW1lKHRpdGxlPWVsZW1lbnRfdGV4dCh2anVzdD0rMS4xKSkgKyB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkgKyBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJMZWdlbmQgVGl0bGUiKSkgKyBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsMTUpKSArIGdlb21fc2lnbmlmKGRhdGE9ZGF0YS5mcmFtZShFeGVjRm49YygiZmFjdG9yIDEiLCAiZmFjdG9yIDMiLCAiZmFjdG9yIDUiLCAiZmFjdG9yIDExIiwgICJmYWN0b3IgMTIiKSksIGFlcyh5X3Bvc2l0aW9uID0gYygxMy41LDEyLjUsMTIuNSwxNCwxMyksIHhtaW49YygxLDEsMSwxLDEpLCB4bWF4PWMoMiwyLDIsMiwyKSwgYW5ub3RhdGlvbnMgPSBjKCIqKiIsIioqIiwiKioiLCIjIiwiKiIpKSwgdGlwX2xlbmd0aCA9IDAsIG1hbnVhbD1UKQ0KDQojIE5PVEUgdGhhdCBvbmx5IHRoZSBmYWN0b3JzIHRoYXQgc2hvdyBzaWduaWZpY2FuY2UgYXJlIGxpc3RlZCBhbmQgdGhlIGluZm9ybWF0aW9uIGluIHRoZSBhZXMgYWxzbyBvbmx5IHJlbGF0ZXMgdG8gdGhlc2UuDQoNCg0KIyBDcmVhdGUgZ3JpZCB3aXRoIHJlb3JnYW5pemVkIGZhY3RvcnMNCmJhcl9vYmplY3QuU3ViK2ZhY2V0X2dyaWQofmZhY3RvcihNYWluUHJlZGljdG9yLCBsZXZlbHM9YygiZmFjdG9yIDEiICwiZmFjdG9yIDIiLCJmYWN0b3IgMyIsICJmYWN0b3IgNCIsICJmYWN0b3IgNSIsICJmYWN0b3IgNiIsICJmYWN0b3IgNyIsICJmYWN0b3IgOCIsICJmYWN0b3IgOSIsICJmYWN0b3IgMTAiLCAgImZhY3RvciAxMSIsICJmYWN0b3IgMTIiKSksIHNjYWxlcz0iZml4ZWQiKSAgDQoNCiMgTWFpblByZWRpY3RvciAtIHJlcGxhY2UgdGhpcyB3aXRoIHRoZSBuYW1lIG9mIHRoZSBjb2x1bW4gdGhhdCByZXByZXNlbnRzIHRoZSB4LWxhYmVsIHByZWRpY3RvciBub3Qgc3ViLXByZWRpY3RvcnMgKEFuIGV4YW1wbGUgb2YgdGhlIE1haW5QcmVkaWN0b3IgaXMgdGhlIG5hbWUgb2YgdGhlIHByZWRpY3RvciB0aGF0IHVzIG1hZGUgdXAgb2YgdGhlIDEyIGZhY3RvcnMgc2hvd24gaW4gdGhlIGdyYXBoOyBhbiBleGFtcGxlIG9mIGEgc3ViLXByZWRpY3RvciBpcyBwcmVkaWN0b3IxIHdoaWNoIGluIHRoaXMgY2FzZSBpcyBZZXMgb3IgTm8pDQoNCmBgYA0KDQo8L2NlbnRlcj4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyMgRXhhbXBsZSBvZiBhIGdyYXBoIGdlbmVyYXRlZCB3aXRoIHByZXZpb3VzIGNvbW1hbmQNCjxjZW50ZXI+DQohW10oQzovVXNlcnNcc3NhbW1cRGVza3RvcFxTYW1tdXRcUmVzZWFyY2hcUiBNYXJrZG93bi9mYWNldGdyaWQgZ3JhcGhfcmVvcmRlcmVkIGZhY3RvcnMucG5nKXt3aWR0aD01MCV9DQo8L2NlbnRlcj4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPg0KIyMgQ3JlYXRpbmcgYSBsaW5lIGNoYXJ0DQogICogdmFyaWFibGUgeSBpcyBiZWluZyBwbG90dGVkIGFjcm9zcyB2YXJpYWJsZSB4IGZvciB0d28gZ3JvdXBzDQpgYGB7cn0NCmxwPC0gZ2dwbG90KFNDbCwgYWVzKHg9eHZhcm5hbWUsIHk9eXZhcm5hbWUsIGdyb3VwPWdyb3VwbmFtZSwgY29sb3I9Z3JvdXBuYW1lKSkgKyAjIHggDQogIHN0YXRfc3VtbWFyeShmdW49bWVhbiwgZ2VvbT0ibGluZSIpICsgIyBwbG90cyB0aGUgbGluZQ0KICBzdGF0X3N1bW1hcnkoZnVuPW1lYW4sIGdlb209InBvaW50Iiwgc2l6ZT0zKSsgIyBhZGRzIHBvaW50cyB0byB0aGUgcGxvdA0KICBzdGF0X3N1bW1hcnkoZnVuLmRhdGE9bWVhbl9zZSwgZ2VvbT0iZXJyb3JiYXIiLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuMCksIHdpZHRoPTAuMikrICN1c2luZyBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVhbiBmb3IgdGhlIGVycm9yIGJhci4NCiAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCdkYXJrYmx1ZScsJ3JlZCcpKSsNCiAgbGFicyh0aXRsZT0iVGl0bGUiLCB4PSJ4LWF4aXMgbGFiZWwiLCB5PSJ5LWF4aXMgbGFiZWwiKSsNCiAgdGhlbWUoYXhpcy50aXRsZS54PWVsZW1lbnRfdGV4dCh2anVzdD0tMC40KSkrDQogIHRoZW1lKGF4aXMudGl0bGUueT1lbGVtZW50X3RleHQodmp1c3Q9MC4zKSkrDQogIHRoZW1lKHRpdGxlPWVsZW1lbnRfdGV4dCh2anVzdD0rMS4xKSkrDQogIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpDQoNCmxwICMgZGlzcGxheXMgdGhlIGxpbmVwbG90DQpgYGANCjwvY2VudGVyPg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtZGFuZ2VyIj4NCiMjIyBFeGFtcGxlIG9mIGEgZ3JhcGggZ2VuZXJhdGVkIHdpdGggcHJldmlvdXMgY29tbWFuZA0KPGNlbnRlcj4NCiFbXShDOi9Vc2Vyc1xzc2FtbVxEZXNrdG9wXFNhbW11dFxSZXNlYXJjaFxSIE1hcmtkb3duL2xpbmVwbG90LnBuZyl7d2lkdGg9NTAlfQ0KPC9jZW50ZXI+DQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC13YXJuaW5nIj4NCiMjIENyZWF0aW5nIGEgc2ltcGxlIGJveHBsb3QNCmBgYHt9DQpib3hwbG90KE91dGNvbWV+UHJlZGljdG9yLGRhdGE9b2JqZWN0TCwgbWFpbj0iVGl0bGVsaW5lMSBcbiBUaXRsZWxpbmUgMiIseGxhYj0ieC1heGlzIGxhYmVsIiwgeWxhYj0ieS1heGlzIGxhYmVsIikNCg0Kb3IgDQoNCiMgYm94cGxvdCB3aXRoIGRhdGEgaml0dGVyZWQgYW5kIHNob3dpbmcgJiB0d28gZGlmZmVyZW50IGNvbG9ycw0KDQpnZ3Bsb3Qob2JqZWN0TCwgYWVzKHg9UHJlZGljdG9yLCB5PU91dGNvbWUsIGZpbGw9UHJlZGljdG9yKSkgKyBzdGF0X2JveHBsb3QoZ2VvbT0nZXJyb3JiYXInLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjUpLHdpZHRoPTAuMikgKyBnZW9tX2JveHBsb3Qod2lkdGg9MC40KSArIGdlb21faml0dGVyKHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcigwLjE1KSkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI0UwRTBFMCIsICIjNjA2MDYwIikpDQpgYGANCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCioqKg0KIyAqKkNvcnJlbGF0aW9uKioNCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQoqKkNvcnJlbGF0aW9uKio6IGEgY29ycmVsYXRpb24gdGVzdHMgd2hldGhlciB0aGVyZSBpcyBhIFJFTEFUSU9OU0hJUCBiZXR3ZWVuIHR3byBvYnNlcnZlZCB2YXJpYWJsZXMgd2l0aGluIHRoZSBzYW1lIHNhbXBsZSAoZS5nLiBhc2tpbmcgaWYgdGhlIG51bWJlciBvZiBjdXBzIG9mIGNvZmZlZSBjb25zdW1lZCBpcyByZWxhdGVkIHRvIGFtb3VudCBvZiBhbGVydG5lc3MgaW4gYSBzYW1wbGUpDQo8L2Rpdj4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtd2FybmluZyI+DQojIyBQbG90dGluZyBhIGNvcnJlbGF0aW9uIHdpdGggYSByZWdyZXNzaW9uIGxpbmUNCmBgYHtyfQ0KZ2dzY2F0dGVyKG9iamVjdCwgeCA9ICJ4dmFyaWFibGUiLCB5ID0gInl2YXJpYWJsZSIsYWRkID0gInJlZy5saW5lIiwgY29uZi5pbnQgPSBUUlVFLGNvci5jb2VmID0gVFJVRSwgY29yLm1ldGhvZCA9ICJwZWFyc29uIix4bGFiID0gInhsYWJlbCAodW5pdHMpIiwgeWxhYiA9ICJ5bGFiZWwodW5pdHMpIiwgdGl0bGU9InRpdGxlIGZvciB0aGUgZ3JhcGgiKSt0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpKQ0KYGBgDQogICogZ2dzY2F0dGVyOiBwbG90cyB0aGUgY29ycmVsYXRpb24NCiAgKiBvYmplY3Q6IG5hbWUgb2YgdGhlIHdpZGUgdmVyc2lvbiBvZiBkYXRhIGZpbGUNCiAgKiB4dmFyaWFibGU6IHJlcGxhY2Ugd2l0aCBuYW1lIG9mIGNvbHVtbiBvZiB2YXJpYWJsZSB0byBiZSBwbG90dGVkIGluIHRoZSB4LWF4aXMNCiAgKiB5dmFyaWFibGU6IHJlcGxhY2Ugd2l0aCBuYW1lIG9mIGNvbHVtbiBvZiB2YXJpYWJsZSB0byBiZSBwbG90dGVkIGluIHRoZSB5LWF4aXMNCiAgKiByZWcubGluZTogYWRkcyB0aGUgcmVncmVzc2lvbiBsaW5lDQogICogY29uZi5pbnQgPSBUUlVFOiBwbG90cyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCAoc2hhZGVkIGFyZWEpDQogICogY29yLmNvZWYgPSBUUlVFOiBzaG93cyB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQNCiAgKiBjb3IubWV0aG9kID0gInBlYXJzb24iOiBjYWxjdWxhdGVzIGFuZCBzaG93cyB0aGUgcCB2YWx1ZQ0KICAqIHhsYWI6IHJlcGxhY2Ugd29yZHMgaW4gcXVvdGVzIHdpdGggYXBwcm9wcmlhdGUgd29yZGluZyBmb3IgdGhlIHgtbGFiZWwNCiAgKiB5bGFiOiByZXBsYWNlIHdvcmRzIGluIHF1b3RlcyB3aXRoIGFwcHJvcHJpYXRlIHdvcmRpbmcgZm9yIHRoZSB5LWxhYmVsDQogICogdGl0bGU6IHJlcGxhY2Ugd29yZHMgaW4gcXVvdGVzIHdpdGggYSBwcm9wZXIgdGl0bGUNCiAgKiB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpKTogY2VudGVycyB0aGUgdGl0bGUNCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXN1Y2Nlc3MiPg0KIyMgUnVubmluZyBhIGNvcnJlbGF0aW9uDQpgYGB7cn0NCmNvci50ZXN0KG9iamVjdCRwcmVkaWN0b3IsIG9iamVjdCRvdXRjb21lKQ0KYGBgDQogICogZ2l2ZXMgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50DQogICogZ2l2ZXMgdGhlIHAtdmFsdWUgKHdoaWNoIHRlbGxzIHlvdSBvZiB0aGUgY29ycmVsYXRpb24gaXMgc2lnbmlmaWNhbnQpDQogICogSW1wb3J0YW50IG5vdGVzIHRvIHJlbWVtYmVyIGZyb20gdGhlIHJlc3VsdHMNCiAgICArIGRmID0gZGVncmVlcyBvZiBmcmVlZG9tIChuLTIgKGZvciBjb3JyZWxhdGlvbikpDQogICAgKyBwIHZhbHVlOiBwIHZhbHVlIG9mIGxlc3MgdGhhbiAwLjA1IGlzIHNpZ25pZmljYW50DQogICAgKyB0aGUgdmFsdWUgdW5kZXIgImNvciIgPSBjb3JyZWxhdGlvbiBjb2VmZmljaWVudA0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtZGFuZ2VyIj4NCiMjIyBFeGFtcGxlIG9mIGEgQ29ycmVsYXRpb24gT3V0cHV0DQpgYGB7fQ0KCVBlYXJzb24ncyBwcm9kdWN0LW1vbWVudCBjb3JyZWxhdGlvbg0KDQpkYXRhOiAgaW5ncmQkSW5jIGFuZCBpbmdyZCRHcmQNCnQgPSAyLjk2OCwgZGYgPSAxMiwgcC12YWx1ZSA9IDAuMDExNzQgIyMgdXNlZCBmb3IgcmVwb3J0DQphbHRlcm5hdGl2ZSBoeXBvdGhlc2lzOiB0cnVlIGNvcnJlbGF0aW9uIGlzIG5vdCBlcXVhbCB0byAwDQo5NSBwZXJjZW50IGNvbmZpZGVuY2UgaW50ZXJ2YWw6DQogMC4xODMzNTcyIDAuODc4MDg4NQ0Kc2FtcGxlIGVzdGltYXRlczoNCiAgICAgIGNvciANCjAuNjUwNjM4OSAjIyB1c2VkIGZvciByZXBvcnQNCmBgYA0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+IA0KIyMjIFdyaXRpbmcgYSByZXBvcnQgZnJvbSBhIGNvcnJlbGF0aW9uDQpBIFBlYXJzb24ncyBjb3JyZWxhdGlvbiBpbmRpY2F0ZWQgdGhhdCBhIHN0dWRlbnQncyBncmFkZSB3YXMgc2lnbmlmaWNhbnRseSByZWxhdGVkIHRvIHRoZSBmYW1pbHkncyBpbmNvbWUsIHIoMTIpPS0uNjUsIHA8LjA1Lg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtZGFuZ2VyIj4NCiMjIyBDcmVhdGluZyBhIENvcnJlbGF0aW9uIE1hdHJpeA0KDQpgYGB7cn0NCmNvclBsb3QoT2JqZWN0LGNleCA9IDAuOCwgc3RhcnM9VFJVRSwgdXBwZXI9RkFMU0UsIG1haW4gPSAiVGl0bGVMaW5lMSBcbiBUaXRsZUxpbmUyIixnciA9IGNvbG9yUmFtcFBhbGV0dGUoYygiI0JCNDQ0NCIsICIjRUU5OTg4IiwgIiNGRkZGRkYiLCAiIzc3QUFERCIsICIjNDQ3N0FBIikpKSANCmBgYA0KICAqIE9iamVjdCBjb250YWlucyAqKm9ubHkqKiB0aGUgdmFyaWFibGVzIHRvIGJlIGluY2x1ZGVkIGluIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXgNCiAgKiBSZXBsYWNlIG5hbWUgb2YgT2JqZWN0IHdpdGggdGhlIGFwcHJvcHJpYXRlIG5hbWUNCiAgKiBSZXBsYWNlIFRpdGxlIGluZm9ybWF0aW9uIHdpdGggdGhlIGFwcHJvcHJpYXRlIGluZm9ybWF0aW9uDQoNCiMjIyBFeGFtcGxlIG9mIGEgY29ycmVsYXRpb24gcGxvdC9tYXRyaXggZ2VuZXJhdGVkIHdpdGggcHJldmlvdXMgY29tbWFuZA0KPGNlbnRlcj4NCiFbXShDOi9Vc2Vyc1xzc2FtbVxEZXNrdG9wXFNhbW11dFxSZXNlYXJjaFxSIE1hcmtkb3duL0NvcnJlbGF0aW9uIE1hdHJpeC5qcGcpe3dpZHRoPTc1JX0NCjwvY2VudGVyPg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KKioqDQojICoqUmVncmVzc2lvbioqDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPg0KKipSZWdyZXNzaW9uKio6IGEgcmVncmVzc2lvbiBERVNDUklCRVMgdGhlIFJFTEFUSU9OU0hJUCBiZXR3ZWVuIGEgcHJlZGljdG9yIChhbiBpbmRlcGVuZGVudCB2YXJpYWJsZSkgYW5kIGFuIG91dGNvbWUgKGRlcGVuZGVudCkgYmV0d2VlbiB0d28gb2JzZXJ2ZWQgdmFyaWFibGVzIHdpdGhpbiB0aGUgc2FtZSBzYW1wbGUuIFJlZ3Jlc3Npb25zIGNhbiB0YWtlIHZhcmlvdXMgZm9ybXMgLSBsaW5lYXIgKGUuZy4gY2FsaWJyYXRpb24gb2YgcEggbWV0ZXIpLCBzaWdtb2lkYWwgKGUuZy4gaW4gZW56eW1lIGtpbmV0aWNzL3JlY2VwdG9yIGJpbmRpbmcpLiBEaXN0aW5jdGlvbiBiZXR3ZWVuIGNvcnJlbGF0aW9uICYgcmVncmVzc2lvbjogV2hpbGUgYSAqKmNvcnJlbGF0aW9uKiogY2FuIHRlbGwgeW91IHRoYXQgdGhlcmUgaXMgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBbSH4zfk9eK15dIGluIGEgc29sdXRpb24gYW5kIHRoZSBwSCB2YWx1ZSwgKipyZWdyZXNzaW9uKiogcHJvdmlkZXMgeW91IHdpdGggdGhlIGxpbmUgdGhhdCBiZXN0IHByZWRpY3RzIHRoYXQgcmVsYXRpb25zaGlwLg0KPC9kaXY+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXN1Y2Nlc3MiPg0KIyMgVHlwZXMgb2YgUmVncmVzc2lvbg0KICAqICoqTG9naXN0aWMgcmVncmVzc2lvbioqIGlzIHRoZSBhcHByb3ByaWF0ZSB0byBjb25kdWN0IHdoZW4gdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBpcyAqKmRpY2hvdG9tb3VzKiogKGJpbmFyeSkNCiAgKiAqKlN0ZXB3aXNlIHJlZ3Jlc3Npb24qKiBpcyBhcHByb3ByaWF0ZSB3aGVuIHlvdSBoYXZlIG1hbnkgdmFyaWFibGVzIGFuZCB5b3UncmUgaW50ZXJlc3RlZCBpbiBpZGVudGlmeWluZyBhIHVzZWZ1bCBzdWJzZXQgb2YgdGhlIHByZWRpY3RvcnMuDQoNCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXN1Y2Nlc3MiPg0KIyMgU2ltcGxlIFJlZ3Jlc3Npb24NCmBgYHtyfQ0KT2JqZWN0UmVnPWxtKG91dGNvbWV+cHJlZGljdG9yLCBkYXRhPW9iamVjdCkNCnN1bW1hcnkoT2JqZWN0UmVnKQ0KYGBgDQogICogR2VuZXJhdGVzIHRoZSByZWdyZXNzaW9uIGVxdWF0aW9uIGFuZCBpdCBpcyBzdG9yZWQgaW4gIk9iamVjdFJlZyIgDQogICogVGhlICoqKmxtKioqIHJlZ3Jlc3Npb24gY29tbWFuZA0KICAgICsgdXNlcyBXSURFIGZvcm0gb2YgdGhlIGRhdGEgDQogICAgKyBEZXNpZ25hdGUgb25lIHZhcmlhYmxlIGFzIG91dGNvbWUgYW5kIHRoZSBvdGhlciBhcyBwcmVkaWN0b3IgLSBEbyBzbyBpbiBzdWNoIGEgd2F5IHRoYXQgbWFrZXMgc2Vuc2UuIGUuZy4gSXQgaXMgbW9yZSBsaWtlbHkgdGhhdCBmYW1pbHkgaW5jb21lIHdvdWxkIHByZWRpY3QgYSBzdHVkZW50J3MgZ3JhZGUgdGhhbiBhIHN0dWRlbnQncyBncmFkZSBwcmVkaWN0aW5nIGZhbWlseSBpbmNvbWUNCiAgKiBUaGUgKioqc3VtbWFyeSoqKiBjb21tYW5kOiBnaXZlcyB0aGUgb3V0cHV0IG9mIHRoZSByZWdyZXNzaW9uIGVxdWF0aW9uLCBmcm9tIHdoaWNoIHlvdSBleHRyYWN0IGFsbCBvZiB0aGUgc3RhdGlzdGljYWwgaW5mb3JtYXRpb24gdGhhdCBnb2VzIGludG8gYSByZWdyZXNzaW9uIHJlcG9ydC4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyMgRXhhbXBsZSBSZWdyZXNzaW9uIE91dHB1dA0KPGNlbnRlcj4NCiFbXShDOi9Vc2Vyc1xzc2FtbVxEZXNrdG9wXFNhbW11dFxSZXNlYXJjaFxSIE1hcmtkb3duL1JlZ3Jlc3Npb25PdXRwdXQuanBnKXt3aWR0aD0xMDAlfQ0KPC9jZW50ZXI+DQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1kYW5nZXIiPg0KIyMjIEV4YW1wbGUgb2YgYSBSZWdyZXNzaW9uIEVxdWF0aW9uIGRlcml2ZWQgZnJvbSB0aGUgYWJvdmUgb3V0cHV0DQo8Y2VudGVyPg0KIVtdKEM6L1VzZXJzXHNzYW1tXERlc2t0b3BcU2FtbXV0XFJlc2VhcmNoXFIgTWFya2Rvd24vUmVnZXFFeC5qcGcpe3dpZHRoPTUwJX0NCjwvY2VudGVyPg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQojIyMgV3JpdGluZyBhIHJlcG9ydCBmcm9tIGEgcmVncmVzc2lvbiBvdXRwdXQNClRoZSByZXN1bHRzIGluZGljYXRlZCB0aGF0IEZlYXIgb2YgU2luIHNpZ25pZmljYW50bHkgcHJlZGljdGVkIERlcHJlc3Npb24sIEJldGEgPSAwLjIyMiwgdCg5NSk9Mi4zMzYsIHAgPCAwLjA1LiBGZWFyIG9mIFNpbiBhbHNvIGV4cGxhaW5lZCBhIHNpZ25pZmljYW50IHByb3BvcnRpb24gb2YgdmFyaWFuY2UgaW4gRGVwcmVzc2lvbiwgUl4yXiA9IC4wNDQsIEYoMSwgOTUpID0gNS40NTUsIHAgPCAwLjA1Lg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KIyMgTXVsdGlwbGUgUmVncmVzc2lvbiAoYmFja3dhcmQgZWxpbWluYXRpb24pICh1c2luZyBBSUMpDQogICogcmVxdWlyZXMgcGFja2FnZTogbGVhcHMNCg0KYGBge3J9DQpmaXRPYmplY3QgPSBsbSh5fngxK3gyK3gzLi4uLGRhdGE9bmEub21pdChvYmplY3RMKSkNCmBgYA0KICAqIGxtOiBpcyB0aGUgY29tbWFuZCB0aGF0IHJ1bnMgYSBsaW5lYXIgbW9kZWwgYW5hbHlzaXMNCiAgKiBuYS5vbWl0IHdpbGwgb21pdCB0aG9zZSBzdWJqZWN0cyB3aXRoIG1pc3NpbmcgZGF0YSBwb2ludHMgJiB0aGVyZWZvcmUgY2Fubm90IGJlIGluY2x1ZGVkIGluIGFuYWx5c2lzLg0KDQpgYGB7cn0NCnN0ZXBPYmplY3QgPSBzdGVwQUlDKGZpdE9iamVjdCwgZGlyZWN0aW9uPSJiYWNrd2FyZCIsIHRyYWNlPUZBTFNFKSAjIGRpcmVjdGlvbiBjYW4gYmUgImJvdGgiIG9yICJmb3J3YXJkIg0Kc3RlcE9iamVjdCRhbm92YSAjIGRpc3BsYXkgcmVzdWx0cyB3aXRoIEFJQw0Kc3VtbWFyeShzdGVwT2JqZWN0KSAjIGRpc3BsYXkgcmVzdWx0cyB3aXRoIHQgdmFsdWVzDQpgYGANCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtc3VjY2VzcyI+DQojIyBNdWx0aXBsZSBSZWdyZXNzaW9uIChiYWNrd2FyZCBlbGltaW5hdGlvbikgKHVzaW5nIEYtdmFsdWUpDQogICogcmVxdWlyZXMgcGFja2FnZTogcm1zDQogICogZnJvbTogaHR0cDovL3JzdHVkaW8tcHVicy1zdGF0aWMuczMuYW1hem9uYXdzLmNvbS8yODk5X2E5MTI5ZGViZjZiZDQ3ZDJhMDUwMWRlOWMwZGM1ODNkLmh0bWwNCiAgKiBvdXRwdXQgc2ltaWxhciB0byBTaWdtYXBsb3QNCmBgYHtyfQ0KZnVsbE9iamVjdCA9IG9scyh5fngxK3gyK3gzLi4uLCBkYXRhID0gb2JqZWN0TCkNCmZhc3RidyhmdWxsT2JqZWN0LCBydWxlID0gInAiLCBzbHMgPSAwLjEpDQpgYGANCjwvZGl2Pg0KDQojIyBMb2dpc3RpYyBSZWdyZXNzaW9uDQoNCiAgKiB1c2VkIHdoZW4gb3V0Y29tZSBpcyBkaWNob3RvbW91cy9iaW5hcnkNCiAgKiBhbHNvIHNlZTogaHR0cHM6Ly9zdGF0cy5pZHJlLnVjbGEuZWR1L3IvZGFlL2xvZ2l0LXJlZ3Jlc3Npb24vIGZvciBhZGRpdGlvbmFsIGluZm9ybWF0aW9uDQpgYGB7cn0gIA0KbXlsb2dpdCA9IGdsbShPdXRjb21lIH4gUHJlZGljdG9yMSArIFByZWRpY3RvcjIgKyBQcmVkaWN0b3IzLi4uLCBkYXRhID0gT2JqZWN0TCwgZmFtaWx5ID0gImJpbm9taWFsIikNCnN1bW1hcnkobXlsb2dpdCkgIyBnaXZlcyBCZXRhIGFuZCBwIHZhbHVlcw0KDQpleHAoY2JpbmQoT1IgPSBjb2VmKG15bG9naXQpLCBjb25maW50KG15bG9naXQpKSkgIyBnaXZlcyBPZGRzIFJhdGlvKE9SKQ0KYGBgDQoNCioqKg0KIyBDcm9uYmFjaCdzIGFscGhhDQogICogU3VydmV5cyBhcmUgZ2VuZXJhbGx5IGRpdmlkZWQgaW50byBzZWN0aW9ucyAvZ3JvdXBzIG9mIHF1ZXN0aW9ucyANCiAgKiBQcmlvciB0byBjb25jbHVkaW5nIHRoYXQgcXVlc3Rpb25zIHJlbGF0ZWQgdG8gZWFjaCBvdGhlciwgd2UgbmVlZCB0byBtYWtlIHN1cmUgdGhhdCBxdWVzdGlvbnMgd2l0aGluIGEgc3BlY2lmaWMgZ3JvdXAgb2YgcXVlc3Rpb25zIGFyZSBjb25zaXN0ZW50IHdpdGggZWFjaCBvdGhlciAoaS5lLiBoaWdobHkgcmVsYXRlZCkNCiAgKiB0byBtZWFzdXJlIGlmIGEgZ3JvdXAgb2YgcXVlc3Rpb25zIGlzICBjb25zaXN0ZW50IG9yIG5vdCB3ZSB1c2UgY3JvbmJhY2gncyBhbHBoYQ0KICAqIHdlIHdpbGwgYWxzbyBiZSBhYmxlIHRvIGtub3cgaWYgY29uc2lzdGVuY3kgaW1wcm92ZXMgb3Igbm90IGlmIHdlIGRlbGV0ZSBhIHF1ZXN0aW9uIGZyb20gdGhlIGdyb3VwIG9mIHF1ZXN0aW9ucyAodGhpcyBpcyBvbmx5IHNob3duIGluIE1ldGhvZCAyKS4NCg0KIyMgTWV0aG9kIDENCiAgIyBzdWJqZWN0cyB3aXRoIG1pc3NpbmcgZGF0YSBzaG91bGQgYmUgcmVtb3ZlZCBiZWZvcmUgaGFuZCB1c2luZyBPYmplY3ROQT1uYS5vbWl0KG9iamVjdCkNCmBgYHtyfQ0KbWF0b2JqZWN0PWRhdGEubWF0cml4KG9iamVjdCkNCnJlbGlhYmlsaXR5KGNvdihtYXRvYmplY3QpKQ0KYGBgDQoNCiMjIEV4YW1wbGUgb3V0cHV0IGZyb20gTWV0aG9kIDENCmBgYHt9DQokYWxwaGENCiAgICAgYWxwaGEgDQogMC45NDAzNDU1IA0KIA0KICRzdC5hbHBoYQ0KIHN0ZC5hbHBoYSANCiAwLjk0MTc0NjQgDQogDQogJHJlbC5tYXRyaXgNCiAgICAgICAgICAgICAgICAgQWxwaGEgU3RkLkFscGhhIHIoaXRlbSwgdG90YWwpDQogRDJTdG9wICAgICAgMC45MzUwNTMyIDAuOTM2ODUwNiAgICAgIDAuNzM2NTExMg0KIENvbnQyQSAgICAgIDAuOTMzNTA0OSAwLjkzNTQwMDUgICAgICAwLjc4Mzc4NDINCiBBdnNPdGhlcnMgICAwLjkzNTQxNDggMC45MzY2MzA2ICAgICAgMC43MzA0NzYzDQogRGVwU2xlZXAgICAgMC45MzgzMTI5IDAuOTM5ODc0MyAgICAgIDAuNjMwMjQ3OA0KIFRoaW5rTk9MICAgIDAuOTM1MzAxNyAwLjkzNjQ3NjMgICAgICAwLjczOTc3MDgNCiBMa0Zyd3JkICAgICAwLjkzNDg3NTcgMC45MzYxODI3ICAgICAgMC43NDMzMzAzDQogVGhua0xlc3NUICAgMC45NDI0NDc1IDAuOTQzNjc5NyAgICAgIDAuNTE1Mjk0NQ0KIFRyZExlc3NUICAgIDAuOTM2MjgxNSAwLjkzODAxNzggICAgICAwLjY5OTk3NzENCiBSdXNoV3JrICAgICAwLjkzNTUzMTcgMC45MzY2OTU5ICAgICAgMC43MzAyNDI4DQogTmVnT2JsaWcgICAgMC45MzUyMDk0IDAuOTM2MzY0NyAgICAgIDAuNzQwNjMxOQ0KIEFjY0Rvd24gICAgIDAuOTMzNDE4MCAwLjkzNTQ0NTEgICAgICAwLjc4NTMzMjUNCiBFc2NhcGUgICAgICAwLjkzNDYyMjQgMC45MzYyOTc3ICAgICAgMC43NTM5MTQ2DQogRnJ1c3RyYXRpb24gMC45MzM2MjI4IDAuOTM1MjE0NiAgICAgIDAuNzc5ODIyNA0KIA0KIGF0dHIoLCJjbGFzcyIpDQogWzFdICJyZWxpYWJpbGl0eSINCmBgYA0KDQojIyBNZXRob2QgMg0KYGBge3J9DQphbHBoYW9iamVjdD1hbHBoYShvYmplY3QpDQoNCmFscGhhb2JqZWN0ICMgc2hvd3Mgb3V0cHV0DQpgYGANCg0KIyMgRXhhbXBsZSBvdXRwdXQgZnJvbSBNZXRob2QgMg0KYGBge30NClJlbGlhYmlsaXR5IGFuYWx5c2lzICAgDQpDYWxsOiBhbHBoYSh4ID0gQ0lVUykNCg0KICByYXdfYWxwaGEgc3RkLmFscGhhIEc2KHNtYykgYXZlcmFnZV9yIFMvTiAgICBhc2UgbWVhbiAgIHNkIG1lZGlhbl9yDQogICAgICAwLjk0ICAgICAgMC45NCAgICAwLjk1ICAgICAgMC41NSAgMTYgMC4wMDUxICAxLjggMC45NyAgICAgMC41NQ0KDQogbG93ZXIgYWxwaGEgdXBwZXIgICAgIDk1JSBjb25maWRlbmNlIGJvdW5kYXJpZXMNCjAuOTMgMC45NCAwLjk1IA0KDQogUmVsaWFiaWxpdHkgaWYgYW4gaXRlbSBpcyBkcm9wcGVkOg0KICAgICAgICAgICAgcmF3X2FscGhhIHN0ZC5hbHBoYSBHNihzbWMpIGF2ZXJhZ2VfciBTL04gYWxwaGEgc2UgIHZhci5yIG1lZC5yDQpEMlN0b3AgICAgICAgICAgIDAuOTQgICAgICAwLjk0ICAgIDAuOTUgICAgICAwLjU1ICAxNSAgIDAuMDA1NiAwLjAxMzkgIDAuNTYNCkNvbnQyQSAgICAgICAgICAgMC45MyAgICAgIDAuOTQgICAgMC45NSAgICAgIDAuNTUgIDE0ICAgMC4wMDU3IDAuMDEzNyAgMC41NQ0KQXZzT3RoZXJzICAgICAgICAwLjk0ICAgICAgMC45NCAgICAwLjk1ICAgICAgMC41NSAgMTUgICAwLjAwNTUgMC4wMTI2ICAwLjU1DQpEZXBTbGVlcCAgICAgICAgIDAuOTQgICAgICAwLjk0ICAgIDAuOTUgICAgICAwLjU3ICAxNiAgIDAuMDA1MyAwLjAxMzUgIDAuNTcNClRoaW5rTk9MICAgICAgICAgMC45NCAgICAgIDAuOTQgICAgMC45NSAgICAgIDAuNTUgIDE1ICAgMC4wMDU1IDAuMDEzOSAgMC41NQ0KTGtGcndyZCAgICAgICAgICAwLjkzICAgICAgMC45NCAgICAwLjk1ICAgICAgMC41NSAgMTUgICAwLjAwNTYgMC4wMTI0ICAwLjU1DQpUaG5rTGVzc1QgICAgICAgIDAuOTQgICAgICAwLjk0ICAgIDAuOTUgICAgICAwLjU4ICAxNyAgIDAuMDA0OSAwLjAwNzcgIDAuNTYNClRyZExlc3NUICAgICAgICAgMC45NCAgICAgIDAuOTQgICAgMC45NSAgICAgIDAuNTYgIDE1ICAgMC4wMDU0IDAuMDEzNiAgMC41Ng0KUnVzaFdyayAgICAgICAgICAwLjk0ICAgICAgMC45NCAgICAwLjk1ICAgICAgMC41NSAgMTUgICAwLjAwNTUgMC4wMTI1ICAwLjU1DQpOZWdPYmxpZyAgICAgICAgIDAuOTQgICAgICAwLjk0ICAgIDAuOTUgICAgICAwLjU1ICAxNSAgIDAuMDA1NSAwLjAxMjkgIDAuNTUNCkFjY0Rvd24gICAgICAgICAgMC45MyAgICAgIDAuOTQgICAgMC45NCAgICAgIDAuNTUgIDE0ICAgMC4wMDU3IDAuMDEzMCAgMC41NQ0KRXNjYXBlICAgICAgICAgICAwLjkzICAgICAgMC45NCAgICAwLjk1ICAgICAgMC41NSAgMTUgICAwLjAwNTYgMC4wMTMwICAwLjU2DQpGcnVzdHJhdGlvbiAgICAgIDAuOTMgICAgICAwLjk0ICAgIDAuOTUgICAgICAwLjU1ICAxNCAgIDAuMDA1NyAwLjAxMzIgIDAuNTUNCg0KIEl0ZW0gc3RhdGlzdGljcyANCiAgICAgICAgICAgICAgbiByYXcuciBzdGQuciByLmNvciByLmRyb3AgbWVhbiAgc2QNCkQyU3RvcCAgICAgIDI5OSAgMC43OCAgMC43OCAgMC43NiAgIDAuNzQgMi4yOSAxLjMNCkNvbnQyQSAgICAgIDI5OSAgMC44MiAgMC44MiAgMC44MSAgIDAuNzggMi4xOSAxLjMNCkF2c090aGVycyAgIDI5OSAgMC43NyAgMC43OCAgMC43NyAgIDAuNzMgMS4yMCAxLjINCkRlcFNsZWVwICAgIDI5OSAgMC42OSAgMC42OSAgMC42NSAgIDAuNjMgMS4yNSAxLjMNClRoaW5rTk9MICAgIDI5OSAgMC43OCAgMC43OSAgMC43NyAgIDAuNzQgMS42NCAxLjENCkxrRnJ3cmQgICAgIDI5OSAgMC43OSAgMC44MCAgMC43OCAgIDAuNzQgMS40MyAxLjINClRobmtMZXNzVCAgIDI5OSAgMC41OSAgMC41OCAgMC41MyAgIDAuNTIgMi44NCAxLjQNClRyZExlc3NUICAgIDI5OSAgMC43NSAgMC43NCAgMC43MiAgIDAuNzAgMi4xMiAxLjQNClJ1c2hXcmsgICAgIDI5OSAgMC43NyAgMC43OCAgMC43NyAgIDAuNzMgMC45MyAxLjENCk5lZ09ibGlnICAgIDI5OSAgMC43OCAgMC43OSAgMC43NyAgIDAuNzQgMS4xMiAxLjENCkFjY0Rvd24gICAgIDI5OSAgMC44MyAgMC44MiAgMC44MiAgIDAuNzkgMi4yNyAxLjQNCkVzY2FwZSAgICAgIDI5OSAgMC44MCAgMC43OSAgMC43OSAgIDAuNzUgMi4wNiAxLjUNCkZydXN0cmF0aW9uIDI5OSAgMC44MiAgMC44MiAgMC44MSAgIDAuNzggMS40MSAxLjMNCg0KTm9uIG1pc3NpbmcgcmVzcG9uc2UgZnJlcXVlbmN5IGZvciBlYWNoIGl0ZW0NCiAgICAgICAgICAgICAgIDAgICAgMSAgICAyICAgIDMgICAgNCBtaXNzDQpEMlN0b3AgICAgICAwLjE0IDAuMTcgMC4xOCAwLjMwIDAuMjEgICAgMA0KQ29udDJBICAgICAgMC4xNSAwLjE1IDAuMjEgMC4zMSAwLjE3ICAgIDANCkF2c090aGVycyAgIDAuMzcgMC4yNCAwLjIzIDAuMTMgMC4wMyAgICAwDQpEZXBTbGVlcCAgICAwLjQwIDAuMTkgMC4yMiAwLjE0IDAuMDUgICAgMA0KVGhpbmtOT0wgICAgMC4xNiAwLjMwIDAuMzEgMC4xNyAwLjA1ICAgIDANCkxrRnJ3cmQgICAgIDAuMzAgMC4yNSAwLjIyIDAuMTggMC4wNSAgICAwDQpUaG5rTGVzc1QgICAwLjEyIDAuMDcgMC4xMCAwLjI2IDAuNDUgICAgMA0KVHJkTGVzc1QgICAgMC4xNyAwLjE3IDAuMjIgMC4yNSAwLjE5ICAgIDANClJ1c2hXcmsgICAgIDAuNDkgMC4yMCAwLjIwIDAuMDcgMC4wMyAgICAwDQpOZWdPYmxpZyAgICAwLjQxIDAuMjAgMC4yNSAwLjEyIDAuMDEgICAgMA0KQWNjRG93biAgICAgMC4xNyAwLjExIDAuMTkgMC4zMSAwLjIxICAgIDANCkVzY2FwZSAgICAgIDAuMjQgMC4xMyAwLjE1IDAuMjggMC4xOSAgICAwDQpGcnVzdHJhdGlvbiAwLjM3IDAuMTcgMC4yMyAwLjE2IDAuMDggICAgMA0KYGBgDQoNCkZvciBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIG9uIGludGVycHJldGF0aW9uIHBsZWFzZSBzZWU6IFsqKlJlbGlhYmlsaXR5IEFuYWx5c2lzKipdKGh0dHBzOi8vcnB1YnMuY29tL2hhdXNlbGluL3JlbGlhYmlsaXR5YW5hbHlzaXMpDQoNCioqKg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtc3VjY2VzcyI+DQojIFRlc3RpbmcgZm9yIEhvbW9nZW5laXR5IG9mIHZhcmlhbmNlDQogICogVGhlIExldmVuZSBUZXN0IHRlc3RzIHdoZXRoZXIgdGhlIFZBUklBTkNFUyBhcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSBlYWNoIG90aGVyDQpgYGB7cn0NCmxldmVuZVRlc3Qob2JqZWN0TCRvdXRjb21lLCBvYmplY3RMJHByZWRpY3RvciwgY2VudGVyID0gbWVkaWFuKQ0KYGBgDQogICogY2VudGVyOiBpcyB0aGUgbmFtZSBvZiBhIGZ1bmN0aW9uIHRvIGNvbXB1dGUgdGhlIGNlbnRlciBvZiBlYWNoIGdyb3VwLiBJZiB5b3UgdXNlICJtZWFuIiBpbnN0ZWFkIG9mIG1lZGlhbiAtIHRoaXMgZ2l2ZXMgdGhlIG9yaWdpbmFsIExldmVuZSdzIHRlc3Q7IFRoZSBkZWZhdWx0IGlzICJtZWRpYW4iIHdoaWNoIHByb3ZpZGVzIGEgbW9yZSByb2J1c3QgdGVzdC4NCiAgKiBpZiB2YXJpYW5jZXMgYXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IChwPDAuMDUpLCBpbiB0aGUgdC10ZXN0IGluY2x1ZGUgdGhlIGNvbW1hbmQ6IHZhci5lcXVhbCA9IEZBTFNFIC0tPiBjYWxjdWxhdGVzIGEgbW9yZSByb2J1c3QgdC10ZXN0Ow0KICAqIGlmIHZhcmlhbmNlcyBhcmUgTk9UIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IChwPjAuMDUpLCBpbiB0aGUgdC10ZXN0IGluY2x1ZGUgdGhlIGNvbW1hbmQ6IHZhci5lcXVhbCA9IFRSVUUgLS0+IGNhbGN1bGF0ZXMgcmVndWxhciB0LXRlc3QNCiAgKiBwIHZhbHVlIGlzIHRoZSBudW1iZXIgZm91bmQgdW5kZXIgdGhlIFByKD5GKTsgaWYgcD4wLjA1IHZhcmlhbmNlcyBhcmUgaG9tb2dlbm91cyAodGhlIHN0YXRpc3RpY2FsbHkgc2FtZSkNCiAgKiBMZXZlbmUgdGVzdCBpcyAqKk5PVCoqIG5lY2Vzc2FyeSBpbiBSRVBFQVRFRCBNZWFzdXJlcyB0ZXN0czsgSW4gc3VjaCBjYXNlcywgaW4gYSAqKip0LXRlc3QqKiogeW91IHNob3VsZCB1c2UgKip2YXIuZXF1YWwgPSBUUlVFKioNCg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KIyAqKkNvbmR1Y3RpbmcgYSB0LXRlc3QgaW4gUioqDQogIA0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQoqKnQtdGVzdCoqOiBhIHQtdGVzdCB0ZXN0cyB3aGV0aGVyIHRoZSBNRUFOUy9BVkVSQUdFUyBvZiAqKlRXTyoqIHNhbXBsZXMgYXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gZWFjaCBvdGhlciAgKGUuZy4gYXNraW5nIGlmIHRoZSBhdmVyYWdlIGRlcHJlc3Npb24gc2NvcmVzIG9mIG1hbGVzIGlzIGRpZmZlcmVudCBmcm9tIHRoYXQgb2YgZmVtYWxlcyBpbiBhIHNhbXBsZSkNCjwvZGl2Pg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1zdWNjZXNzIj4NCiMjIE1ldGhvZCAxIC0gZm9yICoqTE9ORyoqIHZlcnNpb24gb2YgZGF0YQ0KDQoqKlBMRUFTRSBOT1RFKiogdGhpcyBjb21tYW5kIGlzIGN1cnJlbnRseSAoMTAvMjgvMjQpIG5vdCB3b3JraW5nIHByb3Blcmx5IGFuZCBnaXZpbmcgdGhlIGZvbGxvd2luZyBlcnJvciAiKmNhbm5vdCB1c2UgJ3BhaXJlZCcgaW4gZm9ybXVsYSBtZXRob2QqIi4gVGhpcyBwYWdlIHdpbGwgYmUgdXBkYXRlZCBvbmNlIGEgc29sdXRpb24gaXMgcmVwb3J0ZWQuIFRoZSBpc3N1ZSBhcHBlYXJzIHRvIGJlIGluIHRoZSAicGFpcmVkPS4uLiIgcGFydCBvZiB0aGUgY29tbWFuZC4NCiAgICANCmBgYHtyfQ0KdC50ZXN0KG91dGNvbWV+cHJlZGljdG9yLCBkYXRhPW9iamVjdEwsIHBhaXJlZD1GQUxTRS9UUlVFLCB2YXIuZXF1YWw9RkFMU0UvVFJVRSkNCmBgYA0KDQo8aDMgc3R5bGUgPSJ0ZXh0LWFsaWduOmNlbnRlcjsiPioqT1IqKjwvaDM+DQoNCjwvY2VudGVyPg0KDQojIyBNZXRob2QgMiAtIGZvciAqKldJREUqKiB2ZXJzaW9uIG9mIGRhdGENCmBgYHtyfQ0KdC50ZXN0KG9iamVjdCR2YXIxLG9iamVjdCR2YXIyLCBwYWlyZWQ9RkFMU0UvVFJVRSwgdmFyLmVxdWFsPUZBTFNFL1RSVUUpDQpgYGANCg0KICAqIEZvciAqKk1FVEhPRCAxKio6DQogICAgKiAqdC50ZXN0KjogY29tbWFuZCB0byBjYWxjdWxhdGUgYSB0LXRlc3QNCiAgICAqICpvdXRjb21lKjogbmFtZSBvZiB0aGUgb3V0Y29tZSBjb2x1bW4gaW4gdGhlIGxvbmcgdmVyc2lvbiBvZiB0aGUgZGF0YSBmaWxlDQogICAgKiAqcHJlZGljdG9yKjogbmFtZSBvZiB0aGUgcHJlZGljdG9yIGNvbHVtbiBpbiB0aGUgbG9uZyB2ZXJzaW9uIG9mIHRoZSBkYXRhIGZpbGUNCiAgICAqICp+KiA6IHByZWRpY3RlZCBieQ0KICAgICogKmRhdGE9b2JqZWN0TCo6IHNwZWNpZmllcyB0aGUgbmFtZSBvZiB0aGUgbG9uZyB2ZXJzaW9uIG9mIHRoZSBkYXRhIGZpbGUuIFJFUExBQ0UgT05MWSB0aGUgd29yZCBvYmplY3RMIHdpdGggdGhlIGFwcHJvcHJpYXRlIG5hbWUgb2YgdGhlIGxvbmcgdmVyc2lvbiBvZiB0aGUgZmlsZQ0KICAqIEZvciAqKk1FVEhPRCAyKio6IA0KICAgICogKm9iamVjdCwgdmFyMSBhbmQgdmFyMiogLSAib2JqZWN0IiBuZWVkcyB0byBiZSByZXBsYWNlZCB3aXRoIGFwcHJvcHJpYXRlIG5hbWUgb2Ygb2JqZWN0IGNvbnRhaW5pbmcgV0lERSB2ZXJzaW9uIG9mIHRoZSBkYXRhOyAidmFyMSIgYW5kICJ2YXIyIiBuZWVkIHRvIGJlIHJlcGxhY2VkIHdpdGggdGhlIGFwcHJvcHJpYXRlIG5hbWVzIG9mIHRoZSBjb2x1bW5zIGluIHRoZSBXSURFIHZlcnNpb24gb2YgdGhlIGRhdGEuIA0KICAqIEZvciAqKkJPVEgqKjoNCiAgICAqICpwYWlyZWQgPSBUUlVFKjogKipVU0VEIGZvciBSRVBFQVRFRCBNRUFTVVJFUyoqLCBhbHNvIGtub3duIGFzIHBhaXJlZA0KICAgICogKnBhaXJlZCA9IEZBTFNFKjogKipVU0VEIGZvciBJTkRFUEVOREVOVCBNRUFTVVJFUyoqDQogICAgKiAqdmFyLmVxdWFsID0gVFJVRSo6IHVzZWQgd2hlbiB0aGUgTGV2ZW5lIFRlc3QgcCA+IDAuMDUgKHJlbWVtYmVyIHAgPSB0aGUgbnVtYmVyIHVuZGVyIFByKD5GKSk7ICoqTk9URToqKiBBbHNvIHVzZSB0aGlzIGluIHRoZSBjYXNlIG9mIGEgKipyZXBlYXRlZCBtZWFzdXJlcyB0LXRlc3QqKiB3aGVuIGEgTGV2ZW5lIHRlc3QgaXMgKipub3QqKiByZXF1aXJlZC4NCiAgICAqICp2YXIuZXF1YWwgPSBGQUxTRSo6IHVzZWQgd2hlbiB0aGUgTGV2ZW5lIFRlc3QgcCA8IDAuMDUNCiAgICAqIElmIHZhci5lcXVhbCA9IEZBTFNFOiB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIChkZikgd2lsbCBOT1QgYmUgYSB3aG9sZSBudW1iZXIgKGJlY2F1c2UgdGhlIHNwZWNpZmljIHQtdGVzdCB1c2VkIHVzZXMgYSBtb3JlIGNvbnNlcnZhdGl2ZSB3YXkgb2YgY2FsY3VsYXRpbmcgdGhlIGRmLikNCiAgICAqIHJlcG9ydGluZzogdChkZik9dHZhbHVlLHB2YWx1ZSwgcl4yPQ0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KKioqDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1zdWNjZXNzIj4NCiMgQ2FsY3VsYXRpbmcgdGhlIGVmZmVjdCBzaXplIChyIHNxdWFyZWQpDQpgYGB7cn0NCnR2YWx1ZV4yLyh0dmFsdWVeMitkZikNCmBgYA0KICAqIGFsbCBpbmZvcm1hdGlvbiBmb3IgdGhlIGFib3ZlIGVxdWF0aW9uIGlzIG9idGFpbmVkIGZyb20gdGhlIG91dHB1dCBvZiB0aGUgdC10ZXN0DQogICogZm9yIHRoZSB0dmFsdWUgaWdub3JlIG5lZ2F0aXZlIHNpZ25zDQogICogcmVwb3J0aW5nOiB0KGRmKT10dmFsdWUsIHAuLi4sIHJeMj0uDQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQoNCiMgQ2FsY3VsYXRpbmcgdGhlIGVmZmVjdCBzaXplIChDb2hlbidzIGQpIChhbHRlcm5hdGl2ZSBvcHRpb24pDQpgYGB7cn0NCiMgcmVxdWlyZXMgcGFja2FnZSBlZmZzaXplDQoNCmNvaGVuLmQoZGF0YT0gb2JqZWN0LCBncm91cDEsIGdyb3VwMikNCmBgYA0KICAqIElmIHRoZSBncm91cHMgYXJlIG5vdCBvZiBlcXVhbCBzaXplLCBhZGQgdGhlIG5hLm9taXQgY29tbWFuZCB0byBncm91cCB3aXRoIHRoZSBsZWFzdCBudW1iZXJzIGUuZy4gaWYgZ3JvdXAyIGhhcyBsZXNzLCB1c2UgIm5hLm9taXQoZ3JvdXAyKSIgaW5zdGVhZCBvZiBzaW1wbHkgImdyb3VwMiINCiAgKiBvYmplY3QgLSByZXBsYWNlIHdpdGggdGhlIG5hbWUgb2YgdGhlIG9iamVjdCBjb250YWluaW5nIHRoZSAqKldJREUqKiBmb3JtIG9mIHRoZSBkYXRhDQogICogZ3JvdXAxIG9yIGdyb3VwMiAtIHJlcGxhY2Ugd2l0aCB0aGUgbmFtZXMgb2YgdGhlIGNvbHVtbnMgb2YgZWFjaCBvZiB0aGUgZ3JvdXBzLg0KICANCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQoqKioNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIHQtdGVzdCBvdXRwdXQgaW4gUg0KICAqIFBhaXJlZCB0LXRlc3QgLyBUd28gU2FtcGxlIHQtdGVzdCAjIHRoaXMgdGl0bGUgb2YgdGhlIG91dHB1dCBpbmRpY2F0ZXMgd2hldGhlciB0aGUgdGVzdCB5b3UganVzdCByYW4gaXMgcGFpcmVkL3JlcGVhdGVkIE9SIGluZGVwZW5kZW50IG1lYXN1cmVzL1R3byBTYW1wbGUgdC10ZXN0Lg0KICAqIFRoZSBsaW5lIHdpdGggdGhlIHQgdmFsdWUsIGRmIGFuZCBwIHZhbHVlIGlzIHRoZSBtb3N0IGltcG9ydGFudCBsaW5lOyB0OiBnaXZlcyB5b3UgdGhlIHQgdmFsdWU7IGRmIGdpdmVzIHlvdSB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIGFuZCBwLXZhbHVlcyBnaXZlcyB5b3UgdGhlIHAgdmFsdWUuIEFMTCBPRiBUSEVTRSBORUVEIHRvIGJlIHJlcG9ydGVkOyB0aGUgcmVwb3J0IHdpbGwgaW5jbHVkZSB0aGlzIGRhdGEgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQgdChkZik9dHZhbHVlLCBwDQoNCiAgKiBvdXRwdXQgd2hlbiB0aGUgc2V4IGRpZmZlcmVuY2VzIGluIHZpdGFtaW4gRCBkYXRhIGlzIGFuYWx5emVkICoqQ09SUkVDVExZKiogdXNpbmcgYW4gaW5kZXBlbmRlbnQgbWVhc3VyZXMgdGVzdDoNCmBgYHt9DQp0ID0gLTIuMjI1OCwgZGYgPSAxNiwgcC12YWx1ZSA9IDAuMDQwNzUgDQpgYGANCiAgDQogICogb3V0cHV0IHdoZW4gdGhlIHNleCBkaWZmZXJlbmNlcyBpbiB2aXRhbWluIEQgZGF0YSBpcyBhbmFseXplZCAqKldST05HTFkqKiB1c2luZyBhIHJlcGVhdGVkIG1lYXN1cmVzIHRlc3Q6DQpgYGB7fQ0KdCA9IC0yLjU5NjQsIGRmID0gOCwgcC12YWx1ZSA9IDAuMDMxNzkNCmBgYA0KDQoNCiAgKiBJZiB0aGVzZSBudW1iZXJzIGhhdmUgdGhlIFNBTUUgc2lnbiBpdCBtZWFucyB0aGF0IGl0IGlzIGxpa2VseSB0aGF0IHRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZToNCmBgYHt9DQphbHRlcm5hdGl2ZSBoeXBvdGhlc2lzOiB0cnVlIGRpZmZlcmVuY2UgaW4gbWVhbnMgaXMgbm90IGVxdWFsIHRvIDANCjk1IHBlcmNlbnQgY29uZmlkZW5jZSBpbnRlcnZhbDoNCiAgLTE4LjI1MjAzOCAgLTEuMDgxMjk1DQpgYGANCg0KICAqIEluIGEgcmVwZWF0ZWQgbWVhc3VyZXMgdGVzdCwgUiBvbmx5IGdpdmVzIHlvdSB0aGUgb3V0cHV0IGZvciBNRUFOIE9GIFRIRSAqKkRJRkZFUkVOQ0VTKio6DQpgYGB7fQ0Kc2FtcGxlIGVzdGltYXRlczoNCiAgbWVhbiBvZiB0aGUgZGlmZmVyZW5jZXMgDQotOS42NjY2NjcgDQpgYGANCg0KICAqIEluIGFuIGluZGVwZW5kZW50IG1lYXN1cmVzIHRlc3QsIFIgZ2l2ZXMgeW91IHRoZSBvdXRwdXQgZm9yIHRoZSBtZWFuIGZvciAqKkVBQ0ggR1JPVVAqKjoNCmBgYHt9DQptZWFuIGluIGdyb3VwIEJveXMgbWVhbiBpbiBncm91cCBHaXJscyANCjI1LjY2NjY3ICAgICAgICAgICAgMzUuMzMzMzMNCmBgYA0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtZGFuZ2VyIj4NCiMjIyBFeGFtcGxlIG9mIGEgdC10ZXN0IG91dHB1dCBhbmQgYW4gZWZmZWN0IHNpemUgKHJeMl4pY2FsY3VsYXRpb24gd2l0aCB0aGUgaW1wb3J0YW50IGRhdGEgdXNlZCBpbiB0aGUgcmVwb3J0IGhpZ2hsaWdodGVkLg0KDQo8Y2VudGVyPg0KIVtdKEM6L1VzZXJzXHNzYW1tXERlc2t0b3BcU2FtbXV0XFJlc2VhcmNoXFIgTWFya2Rvd24vSW5kZXBlbmRlbnQgdC10ZXN0IG91dHB1dC5qcGcpe3dpZHRoPTYwJX0NCjwvY2VudGVyPg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQojIyBXcml0aW5nIGEgcmVwb3J0IGZvciBhIHQtdGVzdA0KQW4gaW5kZXBlbmRlbnQgbWVhc3VyZXMgdC10ZXN0IHdhcyB1dGlsaXplZCB0byBhc3Nlc3Mgd2hldGhlciB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gdml0YW1pbiBEIGxldmVscyBiZXR3ZWVuIGJveXMgYW5kIGdpcmxzLiBUaGUgYW5hbHlzaXMgaW5kaWNhdGVkIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB2aXRhbWluIEQgbGV2ZWxzLCB0KDE2KT0tMi4yMjYsIHA8MC4wNTsgcnNxdWFyZWQ9ICAgLCBzcGVjaWZpY2FsbHkgZ2lybHMgKE09IDsgU0VNPSApIHJlcG9ydGVkIGEgc2lnbmlmaWNhbnRseSBoaWdoZXIgbGV2ZWwgb2Ygdml0YW1pbiBEIHRoZW4gYm95cyAoTT0gOyBTRU09ICkuDQoNCioqT1IqKg0KDQpBbiBpbmRlcGVuZGVudCBtZWFzdXJlcyB0LXRlc3Qgd2FzIHV0aWxpemVkIHRvIGFzc2VzcyB3aGV0aGVyIHRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiB2aXRhbWluIEQgbGV2ZWxzIGJldHdlZW4gYm95cyhNPSA7IFNFTT0gKSBhbmQgZ2lybHMoTT0gOyBTRU09ICkuIFRoZSBhbmFseXNpcyBpbmRpY2F0ZWQgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHZpdGFtaW4gRCBsZXZlbHMsIHQoMTYpPS0yLjIyNiwgcDwwLjA1OyByc3F1YXJlZD0gICAsc3BlY2lmaWNhbGx5IGdpcmxzIHJlcG9ydGVkIGEgc2lnbmlmaWNhbnRseSBoaWdoZXIgbGV2ZWwgb2Ygdml0YW1pbiBEIHRoZW4gYm95cy4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCioqKg0KIyBDb25kdWN0aW5nIGEgdC10ZXN0IGluIGV4Y2VsIChtZXRob2QgMSkNCiAgKiA9dHRlc3QoYXJyYXkxLGFycmF5MiwgdGFpbHMsIHR5cGUpDQogICAgKyBBcnJheSAxOiBmaXJzdCBjb2x1bW4gY29udGFpbmluZyB0aGUgZGF0YQ0KICAgICsgQXJyYXkgMjogc2Vjb25kIGNvbHVtbiBjb250YWluaW5nIGRhdGENCiAgICArIHRhaWxzOiAxIG9yIDIgdGFpbGVkDQogICAgKyB0eXBlOiAxPSBQYWlyZWQ7IDI9IFR3by1zYW1wbGUgZXF1YWwgdmFyaWFuY2U7IDM9IHR3by1zYW1wbGUgdW5lcXVhbCB2YXJpYW5jZS4NCg0KKioqDQojIENvbmR1Y3RpbmcgYSB0LXRlc3QgaW4gZXhjZWwgKG1ldGhvZCAyKQ0KICAqIFRvIGdpdmUgYSBtb3JlIGRldGFpbGVkIG91dHB1dCwgY2xpY2sgRGF0YSBBbmFseXNpcyBpbiB0aGUgQW5hbHlzaXMgZ3JvdXAgb24gdGhlIERhdGEgdGFiLiANCiAgKiBJZiB0aGUgRGF0YSBBbmFseXNpcyBjb21tYW5kIGlzIG5vdCBhdmFpbGFibGUsIHlvdSBuZWVkIHRvIGxvYWQgdGhlIEFuYWx5c2lzIFRvb2xQYWsgYWRkLWluIHByb2dyYW0uKHNlZTpbT2ZmaWNlIFN1cHBvcnRdKGh0dHBzOi8vc3VwcG9ydC5vZmZpY2UuY29tL2VuLWllL2FydGljbGUvbG9hZC10aGUtYW5hbHlzaXMtdG9vbHBhay1pbi1leGNlbC02YTYzZTU5OC1jZDZkLTQyZTMtOTMxNy02YjQwYmExYTY2YjQpe3RhcmdldD0iX2JsYW5rIn0pDQogICogU2VsZWN0IHRoZSB0eXBlIG9mIHQtdGVzdCB5b3UgbmVlZCB0byBydW4NCiAgKiBJbnB1dCB0aGUgYXBwcm9wcmlhdGUgdmFyaWFibGUgcmFuZ2VzIHVuZGVyICJJbnB1dCINCiAgKiBJZiB5b3VyIHZhcmlhYmxlcyBoYXZlIGxhYmVscyAod2hpY2ggdGhleSBzaG91bGQpIGNoZWNrICJMYWJlbHMiDQogICogQ2xpY2sgb24gT3V0cHV0IFJhbmdlIGFuZCBpbiB0aGUgYXNzb2NpYXRlZCBib3ggaW5kaWNhdGUgdGhlIGNlbGwgeW91IHdhbnQgdGhlIG91dHB1dCB0byBiZSBnZW5lcmF0ZWQgaW4gKG1ha2Ugc3VyZSB0aGlzIGNlbGwgaXMgYXdheSBmcm9tIG90aGVyIGltcG9ydGFudCBkYXRhKQ0KICAqIFNhbXBsZSBvdXRwdXQgaXMgc2hvd24gYmVsb3c6DQoNClN0YXRpc3RpYyAgICAgICAgICAgICAgICAgICB8IFNldCA2CSAgICAgfFNldCA3DQotLS0tLS0tLS0gICAgICAgICAgICAgICAgICAgfC0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLQ0KTWVhbgkgICAgICAgICAgICAgICAgICAgICAgfDExLjc1CSAgICAgfDExLjUNClZhcmlhbmNlCSAgICAgICAgICAgICAgICAgIHw0Ni45MTY2NjY2NyB8MzMuNjY2NjY2NjcNCk9ic2VydmF0aW9ucwkgICAgICAgICAgICAgIHw0CSAgICAgICAgIHw0DQpQZWFyc29uIENvcnJlbGF0aW9uCSAgICAgICAgfDAuOTEwMDA3MjQ0CQ0KSHlwb3RoZXNpemVkIE1lYW4gRGlmZmVyZW5jZXwwCQ0KZGYJICAgICAgICAgICAgICAgICAgICAgICAgfDMJDQp0IFN0YXQJICAgICAgICAgICAgICAgICAgICB8MC4xNzQwNzc2NTYJDQpQKFQ8PXQpIG9uZS10YWlsCSAgICAgICAgICB8MC40MzY0NDQyODYJDQp0IENyaXRpY2FsIG9uZS10YWlsCSAgICAgICAgfDIuMzUzMzYzNDM1CQ0KUChUPD10KSB0d28tdGFpbAkgICAgICAgICAgfDAuODcyODg4NTcyCQ0KdCBDcml0aWNhbCB0d28tdGFpbAkgICAgICAgIHwzLjE4MjQ0NjMwNQkNCg0KKioqDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1zdWNjZXNzIj4NCiMgKipPbmUtd2F5IEFOT1ZBIC0gSU5ERVBFTkRFTlQgTUVBU1VSRVMqKg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4NCioqQU5PVkEqKjogYW4gQU5PVkEgdGVzdHMgd2hldGhlciB0aGUgTUVBTlMvQVZFUkFHRVMgb2YgKipNT1JFIFRIQU4gVFdPKiogc2FtcGxlcyBhcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSBlYWNoIG90aGVyICAoZS5nLiBhc2tpbmcgaWYgdGhlcmUgaXMgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHRoZSBhdmVyYWdlIGRlcHJlc3Npb24gc2NvcmVzIGJldHdlZW4gRnJlc2htYW4sIFNvcGhvbW9yZXMsIEp1bmlvcnMgYW5kIFNlbmlvcnMpLiBBTk9WQXMgY2FuIGJlIGNvbXBsaWNhdGVkIGdpdmVuIHRoYXQgY29tcGFyaXNvbnMgY2FuIGJlIGNhcnJpZWQgb3V0IHdpdGhpbiBncm91cHMgYW5kIGJldHdlZW4gZ3JvdXBzLg0KPC9kaXY+DQoNCiAgKiBSdW4gTGV2ZW5lIFRlc3Q6IEZvciB0aGUgREYgZ3JvdXAgPSBrLTEgKGs9bnVtYmVyIG9mIGdyb3Vwcy90cmVhdG1lbnRzKSA9IERGIGZvciB0aGUgQmV0d2VlbiBUcmVhdG1lbnQNCiAgKiBUaGUgb3RoZXIgZGVncmVlcyBvZiBGcmVlZG9tIGlzIERGIGZvciB0aGUgV0lUSElOIHRyZWF0bWVudCA9IE4tayAoTj1zdW0gdG90YWwgb2Ygc3ViamVjdHM7IGs9bnVtYmVyIG9mIHRyZWF0bWVudHMpDQpgYGB7cn0NCmFvdm9iamVjdD1hb3Yob3V0Y29tZX5wcmVkaWN0b3JzLCBkYXRhPW9iamVjdEwpDQpgYGANCiAgKiB0aGlzIGNhbGN1bGF0ZXMgdGhlIEFOT1ZBDQogICogVXNlIHRoZSBsb25nIHZlcnNpb24gb2YgdGhlIGZpbGUNCiAgKiBhb3ZvYmplY3Q6IG5hbWUgb2YgdGhlIG9iamVjdCB0aGF0IHdpbGwgY29udGFpbiB0aGUgQU5PVkEgY2FsY3VsYXRpb24NCg0KYGBge3J9DQpzdW1tYXJ5KGFvdm9iamVjdCkNCmBgYA0KICAqIHRoaXMgZ2l2ZXMgdGhlIG91dHB1dCBmb3IgdGhlIEFOT1ZBICgqKlNlZSBleGFtcGxlIG91dHB1dCBiZWxvdyoqKQ0KICAqIG5hbWUgb2YgcHJlZGljdG9yIGNvbHVtbjogYmV0d2VlbiBUcmVhdG1lbnQgKGIvVCkNCiAgKiBSZXNpZHVhbHM6IHdpdGhpbiBUcmVhdG1lbnQgKHcvVCkNCiAgKiBERjogZGVncmVlcyBvZiBmcmVlZG9tIChuZWVkZWQgZm9yIHJlcG9ydGluZykNCiAgKiBTdW0gU3E6IFN1bSBvZiBTcXVhcmVzIChOb3RlOiBuZWVkZWQgZm9yIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgZWZmZWN0IHNpemUpDQogICogTWVhbiBTcTogTWVhbiBTcXVhcmUgPSB2YXJpYW5jZXMNCiAgKiBGIHZhbHVlOiB0ZXN0IHN0YXRpc3RpYyAobmVlZGVkIGZvciByZXBvcnRpbmcpDQogICogUHIoPkYpOiBwIHZhbHVlIChuZWVkZWQgZm9yIHJlcG9ydGluZykNCiAgKiB5b3VyIHN0YXRpc3RpY3MgaW4gdGhlIHJlcG9ydCBzaG91bGQgYmUgaW4gZm9ybTogRihERihiL1QpLERGKHcvVCkpPSBGIHZhbHVlLCBwIHZhbHVlLCBlZmZlY3Qgc2l6ZSkNCiAgKiBFRkZFQ1QgU0laRTogU3VtIFNxIGlzIHVzZWQgZm9yIGVmZmVjdCBzaXplOiBTdW0gU3EoYi9UKS8oU3VtIFNxKHRvdGFsKSkNCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyMgRXhhbXBsZSBvZiBhbiBJbmRlcGVuZGVudCBNZWFzdXJlcyBPdXRwdXQgDQpgYGB7fQ0KICAgICAgICAgICAgRGYgU3VtIFNxIE1lYW4gU3EgRiB2YWx1ZSAgIFByKD5GKSAgICANCnZhcmlhYmxlICAgICAyICAyOC4yMiAgMTQuMTExICAgMTEuOTEgMC4wMDAyNTYgKioqICANClJlc2lkdWFscyAgIDI0ICAyOC40NCAgIDEuMTg1ICAgICAgICAgICAgICAgICAgICAgDQotLS0NClNpZ25pZi4gY29kZXM6ICAwIOKAmCoqKuKAmSAwLjAwMSDigJgqKuKAmSAwLjAxIOKAmCrigJkgMC4wNSDigJgu4oCZIDAuMSDigJgg4oCZIDENCmBgYA0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KKioqDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1zdWNjZXNzIj4NCiMgUG9zdC1ob2MgYW5hbHlzaXMgdXNpbmcgVHVrZXkgVGVzdA0KICAqICoqQSBwb3N0LWhvYyBhbmFseXNpcyBpcyBydW4gd2hlbmV2ZXIgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIEFOT1ZBIHNob3dzIGEgcDwwLjA1KioNCmBgYHtyfQ0KcGhvYmplY3Q9Z2xodChhb3ZvYmplY3QsIGxpbmZjdD1tY3AocHJlZGljdG9yPSJUdWtleSIpKQ0KYGBgDQogICogcGhvYmplY3Q6IG5hbWUgb2YgdGhlIG9iamVjdCB0aGF0IHdpbGwgY29udGFpbiB0aGUgcG9zdC1ob2MgVHVrZXkgdGVzdA0KICAqIGFvdm9iamVjdDogdGhlIG5hbWUgb2YgdGhlIG9iamVjdCB0aGF0IGNvbnRhaW5zIHRoZSBBTk9WQSAoc2VlIHByZXZpb3VzIEFOT1ZBIGNvbW1hbmQpDQogICogcHJlZGljdG9yOiBuZWVkcyB0byBiZSByZXBsYWNlZCB3aXRoIG5hbWUgb2YgdGhlIFBSRURJQ1RPUiBjb2x1bW4gaW4geW91ciBkYXRhIGZpbGUuDQoNCmBgYHtyfQ0Kc3VtbWFyeShwaG9iamVjdCkNCmBgYA0KICAqIGdpdmVzIHRoZSBzdW1tYXJ5IG9mIHRoZSBwb3N0LWhvYyBhbmFseXNpcyAoKipzZWUgZXhhbXBsZSBvdXRwdXQgYmVsb3cqKikNCiAgKiBQcig+fHR8KTogaXMgdGhlIHAgdmFsdWUgZm9yIHRoZSBzcGVjaWZpYyBncm91cHMgYmVpbmcgY29tcGFyZWQuDQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1zdWNjZXNzIj4NCiAgKiBJZiB0aGUgdmFyaWFuY2VzIGFyZSAqKm5vdCoqIGVxdWFsIHRoZSBHYW1lcy1Ib3dlbGwgdGVzdCBpcyBjb25kdWN0ZWQgKGMuZi4gV2VsY2ggdGVzdCBpbiB0aGUgdC10ZXN0KQ0KICAqIHJlcXVpcmVzICpzdGF0aXgqIHBhY2thZ2UNCmBgYHtyfQ0KZ2FtZXNfaG93ZWxsX3Rlc3QoZGF0YSA9IG9iamVjdEwsIGZvcm11bGEgPSBvdXRjb21lIH4gZ3JvdXBpbmdfdmFyaWFibGUpDQpgYGANCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyMgRXhhbXBsZSBvZiBhIHBvc3QtaG9jIG91dHB1dCBmb3IgSW5kZXBlbmRlbnQgTWVhc3VyZXMgQU5PVkENCmBgYHt9DQoJIFNpbXVsdGFuZW91cyBUZXN0cyBmb3IgR2VuZXJhbCBMaW5lYXIgSHlwb3RoZXNlcw0KDQpNdWx0aXBsZSBDb21wYXJpc29ucyBvZiBNZWFuczogVHVrZXkgQ29udHJhc3RzDQoNCg0KRml0OiBhb3YoZm9ybXVsYSA9IHZhbHVlIH4gdmFyaWFibGUsIGRhdGEgPSBtaWdyYWluZUwpDQoNCkxpbmVhciBIeXBvdGhlc2VzOg0KICAgICAgICAgICAgICAgICAgIEVzdGltYXRlIFN0ZC4gRXJyb3IgdCB2YWx1ZSBQcig+fHR8KSAgICANCkRydWdCIC0gRHJ1Z0EgPT0gMCAgIDIuMTExMSAgICAgMC41MTMyICAgNC4xMTQgMC4wMDEwNjMgKiogDQpEcnVnQyAtIERydWdBID09IDAgICAyLjIyMjIgICAgIDAuNTEzMiAgIDQuMzMwIDAuMDAwNjA1ICoqKg0KRHJ1Z0MgLSBEcnVnQiA9PSAwICAgMC4xMTExICAgICAwLjUxMzIgICAwLjIxNyAwLjk3NDUxNCAgICANCi0tLQ0KU2lnbmlmLiBjb2RlczogIDAg4oCYKioq4oCZIDAuMDAxIOKAmCoq4oCZIDAuMDEg4oCYKuKAmSAwLjA1IOKAmC7igJkgMC4xIOKAmCDigJkgMQ0KKEFkanVzdGVkIHAgdmFsdWVzIHJlcG9ydGVkIC0tIHNpbmdsZS1zdGVwIG1ldGhvZCkNCmBgYA0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtZGFuZ2VyIj4NCiMjIyBFcXVhdGlvbiBmb3IgRXRhIFNxdWFyZWQgKGVmZmVjdCBzaXplKSBmb3IgSW5kZXBlbmRlbnQgTWVhc3VyZXMgQU5PVkEgKGluZm9ybWF0aW9uIHRha2VuIGZyb20gdGhlIGZpcnN0IHN0ZXAgb2YgdGhlIEFOT1ZBKS4gDQoNCjxjZW50ZXI+DQohW10oQzovVXNlcnNcc3NhbW1cRGVza3RvcFxTYW1tdXRcUmVzZWFyY2hcUiBNYXJrZG93bi9FdGEgU3F1YXJlZC5qcGcpe3dpZHRoPTYwJX0NCjwvY2VudGVyPg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQojIyMgV3JpdGluZyBhIHJlcG9ydCBmcm9tIGFuIEluZGVwZW5kZW50IE1lYXN1cmVzIEFOT1ZBIG91dHB1dA0KUGFpbiBsZXZlbHMgd2VyZSByZXBvcnRlZCBvbiBhIHNjYWxlIG9mIDEgdG8gMTAgKDE9bG93LCAxMD1oaWdoKSBmb2xsb3dpbmcgdGhlIGFkbWluaXN0cmF0aW9uIG9mIHZhcmlvdXMgcGFpbiByZWxpZXZlcnMgYnkgaW5kaXZpZHVhbHMgd2hvIHN1ZmZlciBmcm9tIG1pZ3JhaW5lcy4gQSBPbmUgV2F5IEFOT1ZBIGluZGljYXRlZCBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgKEYoMiwgMjQpID0gMTEuOTE7IHA8MC4wMDE7IG5eMl49IDAuNDk4KSBpbiByZXBvcnRlZCBwYWluIGxldmVscyBhY3Jvc3MgdGhlIGRydWdzIGFkbWluaXN0ZXJlZC4gUG9zdC1ob2MgYW5hbHlzaXMgdXNpbmcgVHVrZXkgdGVzdCBpbmRpY2F0ZWQgdGhhdCBpbmRpdmlkdWFscyByZXBvcnRlZCBzaWduaWZpY2FudGx5IGxvd2VyIHBhaW4gbGV2ZWxzIGZvbGxvd2luZyB0aGUgYWRtaW5pc3RyYXRpb24gb2YgRHJ1ZyBBIChNPTMuNjcsIFNFTT0wLjI5KSByZWxhdGl2ZSB0byBib3RoIERydWcgQiAoTT01Ljc4OyBTRU09MC40OTsgcDwwLjAxKSBhbmQgRHJ1ZyBDIChNPTUuODk7IFNFTT0wLjI2OyBwPDAuMDAxKS4gVGhlcmUgd2FzIG5vIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgcmVwb3J0ZWQgcGFpbiBsZXZlbHMgZm9sbG93aW5nIHRoZSBhZG1pbmlzdHJhdGlvbiBvZiBEcnVncyBCIGFuZCBDIChwPjAuMDUpLg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KKioqDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1zdWNjZXNzIj4NCiMgKipPbmUtV2F5IFJFUEVBVEVEIE1FQVNVUkVTIChSTSkgQU5PVkEqKg0KYGBge3J9DQphb3ZvYmplY3Q9YW92KG91dGNvbWV+cHJlZGljdG9yK0Vycm9yKHBhcnRpY2lwYW50L3ByZWRpY3RvciksIGRhdGE9b2JqZWN0TCkNCmBgYA0KICAqIHBhcnRpY2lwYW50OiByZXBsYWNlIHdpdGggdGhlIGxhYmVsIG9mIHRoZSBTVUJKRUNUIGNvbHVtbiBpbiB0aGUgbG9uZyB2ZXJzaW9uIG9mIHRoZSBmaWxlDQogICogcHJlZGljdG9yOiByZXBsYWNlIHdpdGggdGhlIG5hbWUgb2YgdGhlIFBSRURJQ1RPUiBjb2x1bW4gaW4gdGhlIGxvbmcgdmVyc3Rpb24gb2YgdGhlIGZpbGUuDQoNCmBgYHtyfQ0Kc3VtbWFyeShhb3ZvYmplY3QpDQpgYGANCiAgKiBwcmVkaWN0b3I6IGJldHdlZW4gVHJlYXRtZW50IHZhbHVlIChiL1QpDQogICogUmVzaWR1YWxzOiBlcnJvcg0KICAqIERmOiBkZWdyZWVzIG9mIGZyZWVkb20gKHZhcmlhYmxlL3ByZWRpY3RvciA9IGstMSB3aGVyZSBrPW51bWJlciBvZiBncm91cHMuIFJlc2lkdWFscz0oZGYody9UKS1kZihiL1MpKSk7IHcvVCA9IFdpdGhpbiBUcmVhdG1lbnQgPSBOLWssIHdoZXJlIE49VG90YWwgbnVtYmVyIG9mICJzYW1wbGVzIi9kYXRhIHBvaW50cyBhbmQgaz1udW1iZXIgb2YgZ3JvdXBzOyBiL1MgPSBCZXR3ZWVuIHN1YmplY3RzID0gbi0xLCB3aGVyZSBuID0gbnVtYmVyIHdpdGhpbiBhIGdyb3VwOyANCiAgKiBTdW0gU3E6IHN1bSBvZiBzcXVhcmVzIChuZWVkZWQgZm9yIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgZWZmZWN0IHNpemUpDQogICogTWVhbiBTcTogdmFyaWFuY2VzDQogICogRiB2YWx1ZTogdGVzdCBzdGF0aXN0aWMNCiAgKiBQcig+Rik6IHAgdmFsdWUNCiAgKiB5b3VyIHJlcG9ydCBvZiB0aGVzZSBzdGF0aXN0aWNzIHNob3VsZCBiZSBpbiB0aGUgZm9ybSBvZiBGKGRmKGIvVCksZGYoZXJyb3IpKT0gRnZhbHVlLCBwdmFsdWUsIGV0YSBzcXVhcmVkIChlZmZlY3Qgc2l6ZSkNCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQojIyMgRXhhbXBsZSBvZiBhIFJlcGVhdGVkIE1lYXN1cmVzIE91dHB1dA0KPGNlbnRlcj4NCkFuIEV4YW1wbGUgb2YgYSBSZXBlYXRlZCBtZWFzdXJlcyBBTk9WQSBvdXRwdXQgd2l0aCBpbXBvcnRhbnQgbnVtYmVycyB1c2VkIGluIHJlcG9ydCBoaWdobGlnaHRlZA0KIVtdKEM6L1VzZXJzL3NzYW1tL0Rlc2t0b3AvU2FtbXV0L1Jlc2VhcmNoL1IgTWFya2Rvd24vUnB0ZE1lYXN1cmVzQU5PVkEtRmlyc3QgcGFydC5KUEcpe3dpZHRoPTUwJX0NCjwvY2VudGVyPg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KKioqDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1zdWNjZXNzIj4NCiMgUG9zdC1ob2MgQW5hbHlzaXMgdXNpbmcgUGFpcndpc2UgY29tcGFyaXNvbnMNCiAgKiAqKkEgcG9zdC1ob2MgYW5hbHlzaXMgaXMgcnVuIHdoZW5ldmVyIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBBTk9WQSBzaG93cyBhIHA8MC4wNSoqDQogICogKipUaGUgdHVrZXkgdGVzdCBkb2VzIE5PVCB3b3JrIGZvciB0aGlzIHR5cGUgb2YgQU5PVkEgY29tbWFuZC4qKiBBIFBhaXJ3aXNlIGNvbXBhcmlzb24gaXMgdXNlZCBpbnN0ZWFkLg0KYGBge3J9DQp3aXRoKG9iamVjdEwsIHBhaXJ3aXNlLnQudGVzdChvdXRjb21lLHByZWRpY3RvciwgcC5hZGp1c3QubWV0aG9kPSJib25mZXJyb25pIiwgcGFpcmVkPVQpKQ0KYGBgDQogICogcGFpcndpc2UgY29tcGFyaXNvbnM6IGNhbGN1bGF0ZSB0aGUgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgcGFpcnMgb2YgZ3JvdXBzDQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1kYW5nZXIiPg0KIyMjIEV4YW1wbGUgb2YgYSBwb3N0LWhvYyBvdXRwdXQgZm9yIFJlcGVhdGVkIE1lYXN1cmVzIEFOT1ZBDQo8Y2VudGVyPg0KQW4gRXhhbXBsZSBvZiBhIHBvc3QtaG9jIGFuYWx5c2lzIG91dHB1dCBmb3IgYSBSZXBlYXRlZCBtZWFzdXJlcyBBTk9WQSB3aXRoIGltcG9ydGFudCBudW1iZXJzIHVzZWQgaW4gcmVwb3J0IGhpZ2hsaWdodGVkLiBUaGVzZSB2YWx1ZXMgYXJlIHRoZSAqKnAtdmFsdWVzKiogY29tcGFyaW5nIHRoZSB2YXJpYWJsZSBpbiB0aGUgdmVydGljYWwgY29sdW1uIG9uIHRoZSBsZWZ0IHRvIHRoZSBob3Jpem9udGFsIHJvdyBhYm92ZSB0aGUgbnVtYmVycy4gDQoNCiFbXShDOi9Vc2Vyc1xzc2FtbVxEZXNrdG9wXFNhbW11dFxSZXNlYXJjaFxSIE1hcmtkb3duL1JNQU5PVkFwb3N0aG9jLkpQRyl7d2lkdGg9NTAlfQ0KPC9jZW50ZXI+DQo8L2Rpdj4NCjxhIGhyZWY9IiN0b3AiPkJhY2sgdG8gdG9wPC9hPg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1kYW5nZXIiPg0KIyMjIEVxdWF0aW9uIGZvciBFdGEgU3F1YXJlZCAoZWZmZWN0IHNpemUpIGZvciBSZXBlYXRlZCBNZWFzdXJlcyBBTk9WQS4gVGhlIGluZm9ybWF0aW9uIGlzIGZvdW5kIHVuZGVyIHRoZSBzZWN0aW9uICoqRXJyb3I6IFdpdGhpbioqIGluIHRoZSBmaXJzdCBzdGVwIG9mIHRoZSBBTk9WQQ0KDQo8Y2VudGVyPg0KIVtdKEM6L1VzZXJzXHNzYW1tXERlc2t0b3BcU2FtbXV0XFJlc2VhcmNoXFIgTWFya2Rvd24vRXRhIHNxdWFyZWQuanBnKXt3aWR0aD02MCV9DQo8L2NlbnRlcj4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPg0KIyMjIFdyaXRpbmcgYSByZXBvcnQgZnJvbSBhIFJlcGVhdGVkIE1lYXN1cmVzIEFOT1ZBIG91dHB1dA0KUmVwZWF0ZWQgbWVhc3VyZXMgQU5PVkEgcmV2ZWFsZWQgYSBzaWduaWZpY2FudCBvdmVyYWxsIGVmZmVjdCBhY3Jvc3MgdGltZSAoRigyLDI0KSA9IDIwLjY1LCBwPCAwLjAwMTsgbl4yXj0wLjYzKSwgZm9sbG93aW5nIHRoZSBhZG1pbmlzdHJhdGlvbiBvZiBkcnVnLiBQb3N0LWhvYyBCb25mZXJyb25pIGFuYWx5c2lzIGluZGljYXRlZCB0aGF0IGFueGlldHkgc2NvcmVzIHdlcmUgc2lnbmlmaWNhbnRseSBsb3dlciB0aGFuIHByZS1kcnVnIChNPTguMTAsIFNFTT0wLjIzKSBhZG1pbmlzdHJhdGlvbiBvbiBib3RoIHdlZWsgMSAoTT02LjgwLCBTRU0gPSAwLjI1OyBwPDAuMDUpIGFuZCB3ZWVrIDIgKE09My4wMCwgU0VNID0gMC4yNjsgcDwwLjAwMSkuIE1vcmVvdmVyIHRoZSBhbnhpZXR5IHNjb3JlcyBvbiB3ZWVrIDIgd2VyZSBhbHNvIHNpZ25pZmljYW50bHkgbG93ZXIgdGhhbiB0aG9zZSBvZiB3ZWVrIDEgKHA8MC4wMDEpLg0KPC9kaXY+DQo8YSBocmVmPSIjdG9wIj5CYWNrIHRvIHRvcDwvYT4NCg0KKiBBZGRpdGlvbmFsIGluZm9ybWF0aW9uIGluIHJlbGF0aW9uIHRvIEFOT1ZBIGFuZCBzb21lIGNvZGUgZm9yIG1vcmUgY2hhbGxlbmdpbmcgQU5PVkFzIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly93d3cudXZtLmVkdS9+ZGhvd2VsbC9TdGF0UGFnZXMvUi9SZXBlYXRlZE1lYXN1cmVzQW5vdmFSLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0NCg0KPGRpdj4NCioqKg0KIyBIb3cgdG8gdXNlIFIgZm9yIG11bHRpcGxlLXNlbGVjdCBxdWVzdGlvbnMNCiAgKiBSZXBsYWNlIE9CSkVDVCB3aXRoIG5hbWUgb2YgdGhlIG9iamVjdCBjb250YWluaW5nIHRoZSBpbXBvcnRlZCBkYXRhIChsb25nIHZlcnNpb24pDQogICogRmlyc3QgY29sdW1uIG5lZWRzIHRvIGJlIHRoZSBzdWJqZWN0IG51bWJlcg0KICAqIFtUaGlzIHNob3VsZCBiZSBkb25lIGluIEV4Y2VsXSBBbGwgdmFsdWVzIGluIHRoZSByb3dzIG5lZWQgdG8gYmUgcmVwbGFjZWQgd2l0aCBhIDEgKGltcGxpZXMgdGhlcmUgaXMgYSB2YWx1ZSBvciBjb3VudCkgb3IgMCAoYmxhbmspDQogICogUmVwbGFjZSAidmFyaWFibGUxIiB3aXRoIHRoZSBuYW1lIG9mIHRoZSBjb2x1bW4gaGVhZGluZyBvZiB0aGF0IHNwZWNpZmljIHZhcmlhYmxlIChlLmcuIGlmIGNvdW50aW5nIG51bWJlciBvZiBwZW9wbGUgaW4gaG91c2Vob2xkIGFuZC9vciBJbnRyYW11cmFsIHNwb3J0cywgdmFyaWFibGUxIGV0YyB3b3VsZCBiZSByZXBsYWNlZCB3aXRoIHRoZSBuYW1lcyBvZiB0aGVzZSBjb2x1bW5zKQ0KICAqIFRoaXMgY29kZSBpcyBtb2RpZmllZCBmcm9tIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzExNjIyNjYwL2hvdy10by11c2Utci1mb3ItbXVsdGlwbGUtc2VsZWN0LXF1ZXN0aW9ucw0KDQpgYGB7cn0NCnNldC5zZWVkKDEpDQpkYXQgPC0gZGF0YS5mcmFtZShPQkpFQ1QsInZhcmlhYmxlMSIsInZhcmlhYmxlMiIsICJ2YXJpYWJsZTMiLCAiLi5uIikNCiAgICAgICAgICAgICAgICAgIA0KbXVsdGkuZnJlcS50YWJsZSA9IGZ1bmN0aW9uKE9CSkVDVCwgc2VwPSIiLCBkcm9wemVybz1GQUxTRSwgY2xlYW49VFJVRSkgew0KICAjIFRha2VzIGJvb2xlYW4gbXVsdGlwbGUtcmVzcG9uc2UgZGF0YSBhbmQgdGFidWxhdGVzIGl0IGFjY29yZGluZyB0byB0aGUgcG9zc2libGUgY29tYmluYXRpb25zIG9mIGVhY2ggdmFyaWFibGUuDQogIA0KICBjb3VudHMgPSBkYXRhLmZyYW1lKHRhYmxlKE9CSkVDVCkpDQogIE4gPSBuY29sKGNvdW50cykNCiAgY291bnRzJENvbWJuID0gYXBwbHkoY291bnRzWy1OXSA9PSAxLCAxLCANCiAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgcGFzdGUobmFtZXMoY291bnRzWy1OXSlbeF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlPXNlcCkpDQogIGlmIChpc1RSVUUoZHJvcHplcm8pKSB7DQogICAgY291bnRzID0gY291bnRzW2NvdW50cyRGcmVxICE9IDAsIF0NCiAgfSBlbHNlIGlmICghaXNUUlVFKGRyb3B6ZXJvKSkgew0KICAgIGNvdW50cyA9IGNvdW50cw0KICB9DQogIGlmIChpc1RSVUUoY2xlYW4pKSB7DQogICAgY291bnRzID0gZGF0YS5mcmFtZShDb21ibiA9IGNvdW50cyRDb21ibiwgRnJlcSA9IGNvdW50cyRGcmVxKQ0KICB9IA0KICBjb3VudHMNCn0NCg0KbXVsdGkuZnJlcS50YWJsZShkYXRbLTFdLCBzZXA9Ii0iKQ0KYGBgDQoqKioNCiMgSG93IHRvIGNvdW50IG51bWJlciBvZiBvY2N1cmVuY2VzIGluIGEgY29sdW1uIA0KDQogICogdGhlIGNvdW50cyBhcmUgc29ydGVkIGxhcmdlc3QgdG8gc21hbGxlc3QNCmBgYHtyfQ0KY291bnQoT0JKRUNULCB2YXJzID0gQ29sdW1ubmFtZSwgc29ydD1UUlVFKQ0KYGBgDQoNCm9yDQoNCiAgKiB0aGUgb3V0cHV0IGlzIHNvcnRlZCBmcm9tIGxvd2VzdCB0byBoaWdoZXN0DQpgYGB7cn0NCnNvcnQodGFibGUoT0JKRUNUJENvbHVtbm5hbWUpKQ0KYGBgDQoNCioqKg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQojIFBsb3R0aW5nIG1hcCBvZiBVUyB3aXRoIGRhdGENCiMjIE1FVEhPRCAxOiBQbG90IG1hcCBvZiBVUyByZWZsZWN0aW5nIHZhcmlvdXMgbGV2ZWxzIC0gT25seSBwbG90cyAqKmxvd2VyIDQ4KioNCiogdGhlIGluZm9ybWF0aW9uIGJlbG93IGlzIG1vZGlmaWVkIGZyb20gdGhlIGZvbGxvd2luZyB3ZWJzaXRlOiBodHRwczovL3JlbWlsbGVyMTQ1MC5naXRodWIuaW8vczIzMHMxOS9JbnRyb19tYXBzLmh0bWwNCiAgDQojIyMgTG9hZCBwYWNrYWdlcw0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpO2xpYnJhcnkobWFwcyk7bGlicmFyeShkcGx5cikgDQpgYGANCg0KIyMjIExvYWQgdGhlIHN0YXRlIG1hcCBpbmZvcm1hdGlvbg0KYGBge3J9DQpNYWluU3RhdGVzIDwtIG1hcF9kYXRhKCJzdGF0ZSIpDQpgYGANCg0KIyMjIENvcHkgZGF0YQ0KKiBTdGF0ZU51bWJlcjogb2JqZWN0IGNvbnRhaW5pbmcgZGF0YSBmb3IgbnVtYmVyIG9mIHN0dWRlbnRzIGZyb20gZXZlcnkgc3RhdGUNCiogdGhpcyBvYmplY3QgY29udGFpbnMgdGhlIGRhdGEgd2l0aCB0aGUgbmFtZXMgb2YgdGhlIHN0YXRlcyBhbmQgbnVtYmVycyBvZiBzdHVkZW50cyBmcm9tIGV2ZXJ5IHN0YXRlDQoqIHN0YXRlcyB0aGF0IGhhdmUgbm8gcmVwcmVzZW50YXRpb24gaS5lLiAwIHN0dWRlbnRzIHNob3VsZCBiZSBibGFuaw0KKiBkYXRhIG5lZWRzIHRvIGhhdmUgYSBjb2x1bW4gbmFtZWQgInJlZ2lvbiIgKCoqKmxvd2VyIGNhc2UqKiopDQoNCmBgYHtyfQ0KU3RhdGVOdW1iZXIgPSByZWFkLnRhYmxlKGZpbGU9ImNsaXBib2FyZCIsIHNlcD0iXHQiLCBoZWFkZXI9VFJVRSwgYXMuaXM9VFJVRSkNCmBgYA0KDQojIyMgUGxvdHMgYWxsIHN0YXRlcyB3aXRoIGdncGxvdDIsIHVzaW5nIGJsYWNrIGJvcmRlcnMgYW5kIGxpZ2h0IGJsdWUgZmlsbA0KYGBge3J9DQpnZ3Bsb3QoKStnZW9tX3BvbHlnb24oZGF0YT1NYWluU3RhdGVzLGFlcyh4PWxvbmcsIHk9bGF0LCBncm91cD1ncm91cCksY29sb3I9ImJsYWNrIiwgZmlsbD0ibGlnaHRibHVlIikNCmBgYA0KDQojIyMgTWVyZ2VzIE1haW5zdGF0ZXMgTWFwIHdpdGggU3RhdGVOdW1iZXIgDQpgYGB7cn0NCk1lcmdlZFN0YXRlcyA8LSBpbm5lcl9qb2luKE1haW5TdGF0ZXMsIFN0YXRlTnVtYmVyLCBieSA9ICJyZWdpb24iKQ0KYGBgDQoNCmBgYHtyfQ0KcCA8LSBnZ3Bsb3QoKQ0KcCA8LSBwICsgZ2VvbV9wb2x5Z29uKCBkYXRhPU1lcmdlZFN0YXRlcywgYWVzKHg9bG9uZywgeT1sYXQsIGdyb3VwPWdyb3VwLCBmaWxsID0gbiksIGNvbG9yPSJ3aGl0ZSIsIHNpemUgPSAwLjIpIA0KcA0KYGBgDQoNCiMjIENoYW5naW5nIGNvbG9yIHNjaGVtZQ0KYGBge3J9DQpwIDwtIHAgKyBzY2FsZV9maWxsX2NvbnRpbnVvdXMobmFtZT0iTnVtYmVyIG9mIFN0dWRlbnRzIixsb3cgPSAibGlnaHRibHVlIiwgaGlnaCA9ICJkYXJrYmx1ZSIsbGltaXRzID0gYygwLDE0MCksYnJlYWtzPWMoMjAsNDAsNjAsODAsMTAwLDEyMCwxNDApLCBuYS52YWx1ZSA9ICJncmV5NTAiKStsYWJzKHRpdGxlPSJ0aXRsZSBvZiBncmFwaCIpDQpwDQpgYGANCjxjZW50ZXI+DQohW10oQzovVXNlcnNcc3NhbW1cRGVza3RvcFxTYW1tdXRcUmVzZWFyY2hcUiBNYXJrZG93bi9NYXAucG5nKXt3aWR0aD01MCV9DQo8L2NlbnRlcj4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPg0KIyMgTUVUSE9EIDI6IFBsb3QgbWFwIG9mIFVTIHJlZmxlY3RpbmcgdmFyaW91cyBsZXZlbHMgLSBQbG90cyAqKmFsbCA1MCBzdGF0ZXMqKg0KKiB0aGUgaW5mb3JtYXRpb24gYmVsb3cgaXMgbW9kaWZpZWQgZnJvbSB0aGUgZm9sbG93aW5nIHdlYnNpdGU6IGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy91c21hcC92aWduZXR0ZXMvbWFwcGluZy5odG1sDQogIA0KIyMjIExvYWQgcGFja2FnZXMNCmBgYHtyfQ0KbGlicmFyeSh1c21hcCkgDQpgYGANCg0KIyMjIENvcHkgZGF0YQ0KKiBTdGF0ZU51bWJlcjogb2JqZWN0IGNvbnRhaW5pbmcgZGF0YSBmb3IgbnVtYmVyIG9mIHN0dWRlbnRzIGZyb20gZXZlcnkgc3RhdGUNCiogdGhpcyBvYmplY3QgY29udGFpbnMgdGhlIGRhdGEgd2l0aCB0aGUgbmFtZXMgb2YgdGhlIHN0YXRlcyBhbmQgbnVtYmVycyBvZiBzdHVkZW50cyBmcm9tIGV2ZXJ5IHN0YXRlDQoqIHN0YXRlcyB0aGF0IGhhdmUgbm8gcmVwcmVzZW50YXRpb24gaS5lLiAwIHN0dWRlbnRzIHNob3VsZCBiZSBibGFuaw0KKiBkYXRhIG5lZWRzIHRvIGhhdmUgYSBjb2x1bW4gbmFtZWQgInJlZ2lvbiINCiogVGhlIGV4Y2VsIGRhdGEgbXVzdCBjb250YWluIHRoZSBmb2xsb3dpbmcgY29sdW1ucy4gVGhlIGRhdGEgYmVsb3cgY2FuIGJlIGNvcGllZCBhbmQgdGhlbiBwYXN0ZWQgaW50byBleGNlbCB1c2luZyB0aGUgInBhc3RlIHNwZWNpYWwvdGV4dCBvbmx5IiBvcHRpb24uDQoqIFRoZSAqKmZpcHMqKiBjb2x1bW4gc3RhbmRzIGZvciB0aGUgRmVkZXJhbCBJbmZvcm1hdGlvbiBQcm9jZXNzaW5nIFN0YW5kYXJkIChGSVBTKSB3aGljaCBwcm92aWRlcyBhIHNldCBvZiBzdGFuZGFyZCBudW1lcmljIGNvZGVzIGZvciByZWZlcnJpbmcgdG8gVS5TLiBzdGF0ZXMuDQoqIFBsZWFzZSBub3RlIHRoYXQsIGluIHRoZSBGSVBTIGNvbHVtbiwgdGhlIDAgaW4gZnJvbnQgb2YgdGhlIHNpbmdsZSBkaWdpdCBudW1iZXJzIGlzIG5vdCBhIHJlcXVpcmVtZW50IC0gdGhpcyB3YXMganVzdCBob3cgSSBzZXQgaXQgdXAuDQoNCmZpcHN8cmVnaW9ufCAgIG4gICB8ICANCi0tLS18LS0tLS0tfC0tLS0tLS18DQowMQl8QWxhYmFtYQ0KMDIJfEFsYXNrYQ0KMDQJfEFyaXpvbmENCjA1CXxBcmthbnNhcw0KMDYJfENhbGlmb3JuaWENCjA4CXxDb2xvcmFkbw0KMDkJfENvbm5lY3RpY3V0DQoxMAl8RGVsYXdhcmUNCjEyCXxGbG9yaWRhDQoxMwl8R2VvcmdpYQ0KMTUJfEhhd2FpaQ0KMTYJfElkYWhvDQoxNwl8SWxsaW5vaXMNCjE4CXxJbmRpYW5hDQoxOQl8SW93YQ0KMjAJfEthbnNhcw0KMjEJfEtlbnR1Y2t5DQoyMgl8TG91aXNpYW5hDQoyMwl8TWFpbmUNCjI0CXxNYXJ5bGFuZA0KMjUJfE1hc3NhY2h1c2V0dHMNCjI2CXxNaWNoaWdhbg0KMjcJfE1pbm5lc290YQ0KMjgJfE1pc3Npc3NpcHBpDQoyOQl8TWlzc291cmkNCjMwCXxNb250YW5hDQozMQl8TmVicmFza2ENCjMyCXxOZXZhZGENCjMzCXxOZXcgSGFtcHNoaXJlDQozNAl8TmV3IEplcnNleQ0KMzUJfE5ldyBNZXhpY28NCjM2CXxOZXcgWW9yaw0KMzcJfE5vcnRoIENhcm9saW5hDQozOAl8Tm9ydGggRGFrb3RhDQozOQl8T2hpbw0KNDAJfE9rbGFob21hDQo0MQl8T3JlZ29uDQo0Mgl8UGVubnN5bHZhbmlhDQo0NAl8UmhvZGUgSXNsYW5kDQo0NQl8U291dGggQ2Fyb2xpbmENCjQ2CXxTb3V0aCBEYWtvdGENCjQ3CXxUZW5uZXNzZWUNCjQ4CXxUZXhhcw0KNDkJfFV0YWgNCjUwCXxWZXJtb250DQo1MQl8VmlyZ2luaWENCjUzCXxXYXNoaW5ndG9uDQo1NAl8V2VzdCBWaXJnaW5pYQ0KNTUJfFdpc2NvbnNpbg0KNTYJfFd5b21pbmcNCg0KYGBge3J9DQpTdGF0ZU51bWJlciA9IHJlYWQudGFibGUoZmlsZT0iY2xpcGJvYXJkIiwgc2VwPSJcdCIsIGhlYWRlcj1UUlVFLCBhcy5pcz1UUlVFKQ0KYGBgDQoNCiMjIyBQbG90cyBibGFuayBtYXAgb2YgYWxsIHN0YXRlcywgdXNpbmcgYmxhY2sgYm9yZGVycyBhbmQgZ3JleSBmaWxsDQpgYGB7cn0NCnBsb3RfdXNtYXAocmVnaW9ucyA9ICJzdGF0ZXMiKSArIGxhYnModGl0bGUgPSAiVVMgU3RhdGVzIixzdWJ0aXRsZSA9ICJUaGlzIGlzIGEgYmxhbmsgbWFwIG9mIHRoZSBzdGF0ZSBvZiB0aGUgVW5pdGVkIFN0YXRlcy4iKSArIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gImdyZXkiKSkNCmBgYA0KDQojIyMgUGxvdHMgYWxsIHN0YXRlcyB3aXRoIGEgY29sb3Igc2NhbGUgcmVmbGVjdGluZyBudW1iZXJzIG9mIHN0dWRlbnRzIGZyb20gdGhlIHNwZWNpZmljIHN0YXRlcyAgYW5kIHBsYWNlcyBpbWFnZSBpbiBhIGJsYWNrIHJlY3RhbmdsZSB3aXRoIGEgbGlnaHQgY29sb3IgZ3JleSBmaWxsDQpgYGB7cn0NCnBsb3RfdXNtYXAoZGF0YSA9IFN0YXRlTnVtYmVyLCB2YWx1ZXMgPSAibiIsIGNvbG9yID0gIndoaXRlIikgKyBzY2FsZV9maWxsX2NvbnRpbnVvdXMobmFtZT0iTnVtYmVyIG9mIFN0dWRlbnRzIixsb3cgPSAibGlnaHRibHVlIiwgaGlnaCA9ICJkYXJrYmx1ZSIsbGltaXRzID0gYygwLDE0MCksYnJlYWtzPWMoMjAsNDAsNjAsODAsMTAwLDEyMCwxNDApLCBuYS52YWx1ZSA9ICJncmV5NTAiKStsYWJzKHRpdGxlPSJ0aXRsZSBvZiBncmFwaCIsIHN1YnRpdGxlID0gIlN1YnRpdGxlIikrIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpICsgdGhlbWUocGxvdC5zdWJ0aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41KSkrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSJncmV5ODUiKSkNCmBgYA0KPGNlbnRlcj4NCiFbXShDOi9Vc2Vyc1xzc2FtbVxEZXNrdG9wXFNhbW11dFxSZXNlYXJjaFxSIE1hcmtkb3duL01hcDIucG5nKXt3aWR0aD01MCV9DQo8L2NlbnRlcj4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPg0KIyMgUGxvdHRpbmcgYSAzRCBTY2F0dGVyIFBsb3QNCiAgKiB5b3UgbWF5IG5lZWQgdG8gZ28gaW50byAqKlRvb2xzL0dsb2JhbCBPcHRpb25zL0dlbmVyYWwvQWR2YW5jZWQqKiBhbmQgdW5kZXIgKipPUyBJbnRlZ3JhdGlvbiAocXVpdCByZXF1aXJlZCkqKiBjaGFuZ2UgdGhlICpSZW5kZXJpbmcgRW5naW5lKiBvcHRpb24gdG8gKipEZXNrdG9wIE9wZW5HTCoqDQoNCg0KDQo8L2NlbnRlcj4NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCiMgQWRkaXRpb25hbCBSZXNvdXJjZXMNCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtd2FybmluZyI+ICANCiMjIFIgTWFya2Rvd24NCg0KICAqIHVzZWQgdG8gInR1cm4geW91ciBhbmFseXNlcyBpbnRvIGhpZ2ggcXVhbGl0eSBkb2N1bWVudHMsIHJlcG9ydHMsIHByZXNlbnRhdGlvbnMgYW5kIGRhc2hib2FyZHMuIiBUaGlzIHBhZ2UgaXMgcHJlcGFyZWQgdXNpbmcgUiBNYXJrZG93bi4NCg0KICAqIFtSIE1hcmtkb3duIEhlbHAgYW5kIEluZm9ybWF0aW9uXShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vKXt0YXJnZXQ9Il9ibGFuayJ9DQoNCiAgKiBbUiBNYXJrZG93biBjaGVhdHNoZWV0XShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxNS8wMi9ybWFya2Rvd24tY2hlYXRzaGVldC5wZGYpe3RhcmdldD0iX2JsYW5rIn0NCiAgDQogICogW0NvbG9yZWQgQm94ZXMgaW4gUiBNYXJrZG93bl0oaHR0cHM6Ly93d3cudzNzY2hvb2xzLmNvbS9ib290c3RyYXAvYm9vdHN0cmFwX2FsZXJ0cy5hc3Ape3RhcmdldD0iX2JsYW5rIn0NCg0KYGBge3J9DQojIEluIFIgTWFya2Rvd24gRG9jdW1lbnQ6DQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC14Ij4gDQogICMgUmVwbGFjZSAieCIgd2l0aCAic3VjY2VzcyIgZm9yIGdyZWVuOyAiaW5mbyIgZm9yIGJsdWU7ICJ3YXJuaW5nIiBmb3IgdGFuOyAiZGFuZ2VyIiBmb3IgcmVkLg0KPC9kaXY+DQpgYGANCg0KYGBge3J9DQojIENyZWF0aW5nIGEgcGRmIG9mIHRoZSBycHVicyB3ZWJzaXRlIGh0dHBzOi8vcnB1YnMuY29tL3NzYW1tdXQvUmVzZWFyY2hTdGF0cw0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQteCI+IA0KICAjIHJlcXVpcmVzIHdlYnNob3QgcGFja2FnZQ0KICBsaWJyYXJ5KHdlYnNob3QpDQp3ZWJzaG90KA0KICAgIHVybCAgICAgPSAiaHR0cHM6Ly9ycHVicy5jb20vc3NhbW11dC9SZXNlYXJjaFN0YXRzIg0KICAsIGZpbGUgICAgPSAgIk91dHB1dDEucGRmIiAjIHJlcGxhY2UgIk91dHB1dDEucGRmIiB3aXRoIGFwcHJvcHJpYXRlIG5hbWUNCiAgLCB2d2lkdGggID0gOTkyDQogICwgdmhlaWdodCA9IDc0NA0KICApDQoNCmdldHdkICgpICMgd2lsbCBzaG93IGluIHdoaWNoIGZvbGRlciB0aGUgZmlsZSBpcyBzdG9yZWQuDQo8L2Rpdj4NCmBgYA0KDQoNCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPg0KIyMgSmFtb3ZpIC0gYW4gYWx0ZXJuYXRlIHN0YXRpc3RpY2FsIHByb2dyYW0NCg0KICAqIFRoaXMgaXMgbm90IHRoZSBwcm9ncmFtIHVzZWQgaW4gdGhlIGNsYXNzIGJ1dCB5b3UgY2FuIGZlZWwgZnJlZSB0byBleHBlcmltZW50IHdpdGggaXQuDQogICogSmFtb3ZpIGlzIGEgcHJvZ3JhbSBiYXNlZCBvbiBSIHRoYXQgaGFzIGEgbW9yZSB1c2VyLWZyaWVuZGx5IGludGVyZmFjZQ0KICAqIFtEb3dubG9hZCBKYW1vdmldKGh0dHBzOi8vd3d3LmphbW92aS5vcmcvZG93bmxvYWQuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifQ0KICAqIEFkdmFudGFnZSAtIGNhbiBiZSB1c2VkIG9uIGFsbCBwbGF0Zm9ybXMgTWFjcywgUENzIGFuZCBDaHJvbWVib29rcw0KICAqIEEgdXNlciBndWlkZSBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vd3d3LmphbW92aS5vcmcvdXNlci1tYW51YWwuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifQ0KICAqIEEgdHV0b3JpYWwgaXMgYWxzbyBhdmFpbGFibGUgW2hlcmVdKGh0dHBzOi8veW91dHUuYmUvbVpvbWVTMHRMeFkpe3RhcmdldD0iX2JsYW5rIn0NCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXdhcm5pbmciPg0KIyMgQ3JlYXRpbmcgeW91ciBvd24gcGFja2FnZQ0KDQogICogVGhpcyBzZWN0aW9uIG91dGxpbmVzIHRoZSBwcm9jZWR1cmUgZm9yIGNyZWF0aW5nIHlvdXIgb3duIHBhY2thZ2Ugb2YgYSBjdXJyZW50bHkgZXhpc3RpbmcgZnVuY3Rpb24gc28gdGhhdCB5b3UgZG8gbm90IGhhdmUgdG8gY29udGludW91c2x5IGNvcHkgYW5kIHBhc3RlIHRoZSBmdW5jdGlvbiB3aGVuIG5lZWRpbmcgaXQgKGUuZy4gcmU6IChzdW1tYXJ5U0UpLVtGdW5jdGlvbiBhbmQgY29tbWFuZCBmb3IgZ2VuZXJhdGluZyBTdGFuZGFyZCBFcnJvciBvZiB0aGUgTWVhbiAoU0VNKV0pDQogIA0KICAqKlJlc291cmNlczoqKg0KICANCiAgKiBodHRwczovL291cmNvZGluZ2NsdWIuZ2l0aHViLmlvL3R1dG9yaWFscy93cml0aW5nLXItcGFja2FnZS8jDQogICogaHR0cHM6Ly93ZWIubWl0LmVkdS9pbnNvbmcvd3d3L3BkZi9ycGFja2FnZV9pbnN0cnVjdGlvbnMucGRmDQoNCiAgKipSZXF1aXJlczoqKg0KICANCiAgKiBSVG9vbHM6IGh0dHBzOi8vY3Jhbi5yc3R1ZGlvLmNvbS9iaW4vd2luZG93cy9SdG9vbHMvIC0gZG93bmxvYWQgYW5kIGluc3RhbGwNCiAgKiBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpDQogICogaW5zdGFsbC5wYWNrYWdlcygicm94eWdlbjIiKQ0KDQogICoqQ3JlYXRpbmcgdGhlIHBhY2thZ2UqKg0KDQoxLiBDcmVhdGUgZm9sZGVyIE5hbWVfUl9wYWNrYWdlDQoyLiBJbiB0aGUgZm9sZGVyIGNyZWF0ZSBhIGZvbGRlciBjYWxsZWQgUg0KMy4gSW4gdGhlIGZvbGRlciBjYWxsZWQgUiwgY3JlYXRlIGEgdGV4dCBmaWxlIGNhbGxlZCBOYW1lX2Z1bmN0aW9uLnR4dCB0aGF0IGNvbnRhaW5zIGEgY29weSB0aGUgZnVuY3Rpb24gY29kZQ0KNC4gQ2hhbmdlIHRoZSBleHRlbnNpb24gb2YgdGhlIHRleHQgZmlsZSB0byAuUiAoY29uZmlybSBjaGFuZ2UpDQo1LiBJbiB0aGUgTmFtZV9SX3BhY2thZ2UgZm9sZGVyIGNyZWF0ZSBhIHRleHQgZmlsZSBjYWxsZWQgREVTQ1JJUFRJT04NCjYuIEluIHRoZSBERVNDUklQVElPTiBmaWxlIGFkZCB0aGUgZm9sbG93aW5nIGluZm9ybWF0aW9uOiANCg0KYGBgDQogIFBhY2thZ2U6IE5hbWUgb2YgcGFja2FnZQ0KICBUeXBlOiBQYWNrYWdlDQogIFRpdGxlOiBUaXRsZSBkZXNjcmliaW5nIHBhY2thZ2UNCiAgVmVyc2lvbjogMC4wLjEuMA0KYGBgDQoNCjcuIFJlbW92ZSB0aGUgLnR4dCBleHRlbnNpb24gZnJvbSB0aGUgREVTQ1JJUFRJT04gZmlsZSAoY29uZmlybSBjaGFuZ2UpDQo4LiBPcGVuIGEgbmV3IHdpbmRvdyBpbiBSIHNvIHRoYXQgeW91IGRvIG5vdCBsb3NlIHByZXZpb3VzIHdvcmsNCjkuIEdvIHRvIEZpbGUvTmV3IFByb2plY3QuIA0KCWEuIENsaWNrIG9uIE5ldyBEaXJlY3RvcnkNCgliLiBDbGljayBvbiBSIFBhY2thZ2UNCgljLiBOYW1lIHRoZSBwYWNrYWdlDQoJZC4gQ2xpY2sgIkFkZCIgDQoJZS4gU2VsZWN0IHRoZSBSIGZpbGUgY3JlYXRlZCBhYm92ZQ0KCWYuIENsaWNrICJCcm93c2UiIGFuZCBjaGFuZ2UgdGhlIGZvbGRlciB0byBzZWxlY3QgdGhlIE5hbWVfUl9wYWNrYWdlIHlvdSBjcmVhdGVkIGVhcmxpZXIuDQoJZy4gQ2xpY2sgb24gIkNyZWF0ZSBQcm9qZWN0Ig0KMTAuIENsaWNrIG9uICJCdWlsZCIgaW4gdGhlIG1lbnUgYW5kIHNlbGVjdCAiQnVpbGQgU291cmNlIFBhY2thZ2UiDQoNCiAgICoqVXNpbmcgdGhlIHBhY2thZ2UqKg0KDQoxLiBHbyB0byBUb29scy9JbnN0YWxsIFBhY2thZ2VzDQoyLiBDaGFuZ2UgIkluc3RhbGwgRnJvbSIgdG8gIlBhY2thZ2UgQXJjaGl2ZSBGaWxlICguemlwOyAudGFyLmd6KSIuIFRoaXMgd2lsbCBvcGVuIHRoZSB3aW5kb3cgZm9yIHlvdSB0byBzZWxlY3QgdGhlIGZpbGUuDQozLiBHbyB0byB0aGUgZm9sZGVyIE5hbWVfUl9wYWNrYWdlIGFuZCBzZWxlY3QgdGhlIC50YXIuZ3ogZmlsZSBsaXN0ZWQNCjQuIENsaWNrICJJbnN0YWxsIg0KNS4gUnVuIGxpYnJhcnkgdXNpbmcgdGhlIG5hbWUgeW91IGdhdmUgdGhlIHBhY2thZ2UgaW4gOWMuOiBsaWJyYXJ5KHBhY2thZ2VuYW1lKQ0KNi4gKipOT1RFKio6IFdoZW5ldmVyIHlvdSBpbnN0YWxsIGEgbmV3IHZlcnNpb24gb2YgUiB5b3Ugd2lsbCBuZWVkIHRvIHJlLXJ1biB0aGUgaW5zdGFsbGF0aW9uIG9mIHRoZSBwYWNrYWdlIGp1c3QgZGVzY3JpYmVkLg0KICANCjwvZGl2Pg0KPGEgaHJlZj0iI3RvcCI+QmFjayB0byB0b3A8L2E+DQoNCioqKg0KKioq