Table of Contents:

  1. Installing R & R Studio
  2. Installation of Packages
  3. Loading Packages
  4. Copying Data from Excel into R
  5. Exporting from R
  6. Viewing imported data
  7. Melting your data
  8. Descriptive statistics for Long version of data
  9. Proportions test
  10. Odds Ratio
  11. Some things you may have to do prior to generating a graph
  12. Creating a pie chart, bar graph, line graph or box plot
  13. Correlation
  14. Regression
  15. Testing for Homogeneity of variance
  16. Conducting a t-test in R
  17. One-way ANOVA - INDEPENDENT MEASURES
  18. One-Way REPEATED MEASURES (RM) ANOVA
  19. How to use R for multiple-select questions
  20. How to count number of occurences in a column
  21. Plotting map of US with data
  22. Additional Resources

Resources

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:

  1. Step 1 - R MUST be installed first - Download R for Windows or Mac

  2. 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:

  1. Double click R-x.x.x-win.exe

    1. Click “OK” (for language)
    2. Click “Next” (for Information)
    3. Click “Next” (for Select Destination Location)
    4. Click “Next” (for Select Components)
    5. Click “Next” (for Startup options)
    6. Click “Next” (for Select Start Menu Folder)
    7. On the next screen:
      1. Make sure “Create a desktop shortcut” is unchecked
      2. Make sure “Create a Quick Launch shortcut” is unchecked
      3. Click “Next”
    8. Click “Finish”
  2. Double click RStudio-x.x.xxxx.exe

    1. Click “Next”
    2. Click “Next” (for Choose Install Location)
    3. Click “Install” (for Choose Start Menu Folder)
    4. Click “Finish”

[Step 3 is not necessary if you are installing the packages by running the commands below under “Installation of Packages”]

  1. Packages go into:
    1. C:\Users\YourName\Documents\R win-library\x.x
    2. Accept to overwrite current packages

For Mac:

  1. Double click R-x.x.x.pkg
    1. click “Continue” (for Introduction)
    2. click “Continue” (for Read Me)
    3. click “Continue” (for License)
    4. click “Agree”
    5. click “Install” (for Installation Type)
    6. if asked, provide password to allow installation of software
    7. click “Install Software”
    8. When installation is complete click “Close”
  2. Double click RStudio-x.x.xxxx.dmg
    1. in window that opens up, drag RStudio icon into Applications folder
    2. When installation is done, you can click on the RStudio icon in the Launchpad
    3. If asked “”RStudio” is an application downloaded from the Internet. Are you sure you want to open it?”
    4. 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”]

  1. Packages go into:
    1. Macintosh HD/Library/Frameworks/R.framework/Versions/version#/Resources/library
    2. Accept to overwrite current packages

Back to top

Resources for Installing the Analysis Toolpak in Excel:

If conducting more detailed analysis in Excel, it is necessary to install and load the Analysis Toolpak. For instructions on loading the Analysis ToolPak in Excel see:


General Notes for R


Installation of Packages

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

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

  1. Copy the command below (Ctrl+C)
  2. Paste command into R Studio Console (Ctrl+V)
  3. Change the name “object” to something that makes sense to you and is related to the data.
  4. In Excel, select the data you want to analyze; Include the header;
  5. Copy the data (Ctrl+C)
  6. 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

  1. Copy the command below (Cmd+C)
  2. Paste command into R Studio Console (Cmd+V)
  3. Change the name “object” to something that makes sense to you and is related to the data.
  4. In Excel, select the data you want to analyze; Include the header;
  5. Copy the data (Cmd+C)
  6. 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)
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)

Importing Data into R from SPSS files

library(foreign)
object = read.spss(file.choose(), to.data.frame=TRUE)

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


Melting your data

Performing a simple melting of data

objectL = melt(object, id="idname")
  • melt converts file from wide to long version
  • objectL: NEW object that will contain the long version of the file
  • object: name of the of the object containing the wide version of the data
  • id=“idname”: this is only used SOMETIMES; only when you have an ID colum (a column that identifies the subject in some way and does not change/is constant)
  • In case of a file with an ID column, replace the idname with the appropriate name of the column
  • If there is NO ID COLUMN; you can simply delete the part of the command from the comma onwards i.e., , id=“idname”’ but keep the close parenthesis.

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

Back to top


Selecting specific subset to analyze

var_a = object$`outcome`[object$predictor1colname=="predictor1" & object$predictor2colname=="predictor2"]

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


Excel Commands for some descriptive Statistics - method 2

Statistic value
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

names(objectL)[n] <- "correctname"

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

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

  • more information on this is available in the R Cookbook, under Colors (ggplot2)

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

# 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

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

  • requires package: leaps
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

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

leveneTest(objectL$outcome, objectL$predictor, center = median)

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)

Back to top

Calculating the effect size (Cohen’s d) (alternative option)

# requires package effsize

cohen.d(data= object, group1, group2)

Back to top


t-test output in R

t = -2.2258, df = 16, p-value = 0.04075 
t = -2.5964, df = 8, p-value = 0.03179
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
  -18.252038  -1.081295
sample estimates:
  mean of the differences 
-9.666667 
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)


Conducting a t-test in excel (method 2)

Statistic Set 6 Set 7
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.

aovobject=aov(outcome~predictors, data=objectL)
summary(aovobject)

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

phobject=glht(aovobject, linfct=mcp(predictor="Tukey"))
summary(phobject)

Back to top

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

Equation for Eta Squared (effect size) for Independent Measures ANOVA (information taken from the first step of the ANOVA).

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)
summary(aovobject)

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

with(objectL, pairwise.t.test(outcome,predictor, p.adjust.method="bonferroni", paired=T))

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

Equation for Eta Squared (effect size) for Repeated Measures ANOVA. The information is found under the section Error: Within in the first step of the ANOVA

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


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) 

Load the state map information

MainStates <- map_data("state")

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.
fips region n
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

  1. Create folder Name_R_package
  2. In the folder create a folder called R
  3. In the folder called R, create a text file called Name_function.txt that contains a copy the function code
  4. Change the extension of the text file to .R (confirm change)
  5. In the Name_R_package folder create a text file called DESCRIPTION
  6. In the DESCRIPTION file add the following information:
  Package: Name of package
  Type: Package
  Title: Title describing package
  Version: 0.0.1.0
  1. Remove the .txt extension from the DESCRIPTION file (confirm change)
  2. Open a new window in R so that you do not lose previous work
  3. Go to File/New Project.
    1. Click on New Directory
    2. Click on R Package
    3. Name the package
    4. Click “Add”
    5. Select the R file created above
    6. Click “Browse” and change the folder to select the Name_R_package you created earlier.
    7. Click on “Create Project”
  4. Click on “Build” in the menu and select “Build Source Package”

Using the package

  1. Go to Tools/Install Packages
  2. Change “Install From” to “Package Archive File (.zip; .tar.gz)”. This will open the window for you to select the file.
  3. Go to the folder Name_R_package and select the .tar.gz file listed
  4. Click “Install”
  5. Run library using the name you gave the package in 9c.: library(packagename)
  6. 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