comment: toc comand not working, need to repost with headings links for ease of navigation
General notes
This contained planed analyses as of 18.06.17 for data set which we will start to collect on 19/06/17. Plans may change as a result of statsitical consulation (we are currently seeking advice on some details)
The study is a training study to be conducted with year 3 (7-8 years) children with no previous knowledge of Mandarin or any tone language, training them on the four tones (6 tone contrasts) in Mandarin. There will intially be two conditions: (1) pictures-only: they are trained using a 2AFC task where they hear a (real) Mandarin word and identify which of two pictures it refers to (one correct, one a foil which differs only by tone); (2) pictures+diacritics - same task but the pictures are acompanied by pictures of the four diacritics. [If resources permit, we may later run a diacritics only condition]. Data will be collected both from training and from some tests conducted pre and post training.
Our main analyses will be Baysean and we will computing Bayes factors using the method advocated by Dienes, 2008 ;Dienes, 2015; we will also along side provide frequentist statistics. Frequentist statistics will computed using logistic mixed effect models, this method is used since in each case we have a dependent variable of correct/incorrect response. Note that although mixed models allow us to include both participants and items, we do not intend to include items in the analyses since power on this dimension will be low. (NB - it is not common for by items analyses to be included for work in this area; increasing the number of items in a learning study of this type with children is not feasible). We use full random slopes structure for predictors of interest (generally, condition, session/pre->post). Factors such as tone contrast for the trial are included as fixed factors and we will not include random slopes for these.
For the Bayesian analsyes, we will continue to work in log odds space (as for Frequentist) to meet assumptions of normality, using estimates and standard errors which come from the logistic mixed effects models. Following Dienes (2008) we will model H1 by using an estimate of the mean for theory (an estimate coming from either from logistic mixed effects models run over pilot data, or in some cases from elsewhere in the data) as the SD of a half normal (for one tailed) or full normal (for two tailed) distribution. We will say we have substantial evidence for H1 is BF>3 and BF<.33 accepted if BF>4
See: https://doi.org/10.1016/j.jml.2017.01.005 for published paper using this approach and Rscript http://rpubs.com/ewonnacott/242454.
Note that the pilot data referred to below comes from three students projects. None were exactly the same as the experiments planned here, but materials were very similar and in some cases similar questions were asked. The models of the pilot data presented below also serve to exemplify the approach to be taken with the current data.
Where possible, we conducted power analyses, although lme’s will be used for the actual analsyes, we conducted the analsyes as though for (near equivalent) t-tests over by subject propotions. This means that the values are only approximate, but since our main analsyes are BF factors our aim here is to get an idea of approximate suitable samples.
In addition to power analyses, where possible we also conducted Bayesian analsyes on relevant parts of the pilot data to see is we had a sufficient sample for BF>3 or BF<.33. We also look to see what size sample might be expected to give BF>3 or BF<.33, given that SE varues as squareroot(N).
The analyses below suggest that there are cases where a sample of 20 participants per condition could be sufficient to acheive 90% power. Intereactions with condition will be harder to power; as discussed below, there may be situations where there is evidence of H1 (ie. data reflecs learning) in condition1 but evidence for H0 (no evidence of learning in this dat) for condition2. If so, we wil deem this sufficient to draw conculsions about the different training methods.
Our policy wil be as follows: we will inspect the data after we have approx. 20 participants in each condition (Note: this is approximate since we aim to get this by the end of the academic year; if we don’t quite get this many children, we will still look at the sample we have). If results for key analsyes are inconclusive, resources permitting we will continue to test more participants, collecting 10 per condition at each step before inspecting the data again at each step. We will continue until N per condition =50, resources permitting.
Final note: we have designed the experiment to have four sessions as follows: session1 pre-tests: discrimination and wordrepetition training session2 training post-tests: discrimination and wordrepetition 2AFC pictest/ 2AFC tonetest session3 training
session4 training post-tests: discrimination and wordrepetition 2AFC pictest/ 2AFC tonetest
For our first inspection of the data, we will conduct analsyes both on day2 data and day4 data (both compared to relevant pre-tests; for training data itself, we will look at sessions1 and 2 versus session 1,2,3&4). If using data from session4 extra two sessions do not affect the key pattern of results, given the large expeniture of resources per participant, we will drop the final two sessions for ongoing participant collection.
Note that frequentist analsyes will not be valid at .05 level, due to stopping problem. Current plan is to nevertheless report with that caveat; BF will be considered the critical analyses.)
Data will be collected from children in year 3 (aged 7-8)
Helper Functions
SummarySE
This function can be found on the website “Cookbook for R”.
http://www.cookbook-r.com/Manipulating_data/Summarizing_data/
It summarizes data, giving 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 summarized.
- 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) {
require(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)
}
SummarySEwithin
This function can be found on the website “Cookbook for R”.
http://www.cookbook-r.com/Graphs/Plotting_means_and_error_bars_(ggplot2)/#Helper functions
From that website:
Summarizes data, handling within-subjects variables by removing inter-subject variability. It will still work if there are no within-S variables. Gives count, un-normed mean, normed mean (with same between-group mean), standard deviation, standard error of the mean, and confidence interval. If there are within-subject variables, calculate adjusted values using method from Morey (2008). data: a data frame.
measurevar: the name of a column that contains the variable to be summariezed betweenvars: a vector containing names of columns that are between-subjects variables withinvars: a vector containing names of columns that are within-subjects variables idvar: the name of a column that identifies each subject (or matched subjects) na.rm: a boolean that indicates whether to ignore NA’s conf.interval: the percent range of the confidence interval (default is 95%)
summarySEwithin <- function(data=NULL, measurevar, betweenvars=NULL, withinvars=NULL,
idvar=NULL, na.rm=FALSE, conf.interval=.95, .drop=TRUE) {
# Ensure that the betweenvars and withinvars are factors
factorvars <- vapply(data[, c(betweenvars, withinvars), drop=FALSE],
FUN=is.factor, FUN.VALUE=logical(1))
if (!all(factorvars)) {
nonfactorvars <- names(factorvars)[!factorvars]
message("Automatically converting the following non-factors to factors: ",
paste(nonfactorvars, collapse = ", "))
data[nonfactorvars] <- lapply(data[nonfactorvars], factor)
}
# Get the means from the un-normed data
datac <- summarySE(data, measurevar, groupvars=c(betweenvars, withinvars),
na.rm=na.rm, conf.interval=conf.interval, .drop=.drop)
# Drop all the unused columns (these will be calculated with normed data)
datac$sd <- NULL
datac$se <- NULL
datac$ci <- NULL
# Norm each subject's data
ndata <- normDataWithin(data, idvar, measurevar, betweenvars, na.rm, .drop=.drop)
# This is the name of the new column
measurevar_n <- paste(measurevar, "_norm", sep="")
# Collapse the normed data - now we can treat between and within vars the same
ndatac <- summarySE(ndata, measurevar_n, groupvars=c(betweenvars, withinvars),
na.rm=na.rm, conf.interval=conf.interval, .drop=.drop)
# Apply correction from Morey (2008) to the standard error and confidence interval
# Get the product of the number of conditions of within-S variables
nWithinGroups <- prod(vapply(ndatac[,withinvars, drop=FALSE], FUN=nlevels,
FUN.VALUE=numeric(1)))
correctionFactor <- sqrt( nWithinGroups / (nWithinGroups-1) )
# Apply the correction factor
ndatac$sd <- ndatac$sd * correctionFactor
ndatac$se <- ndatac$se * correctionFactor
ndatac$ci <- ndatac$ci * correctionFactor
# Combine the un-normed means with the normed results
merge(datac, ndatac)
}
normDataWithin
This function is used by the SummarySEWithin fucntion above. It can be found on the website “Cookbook for R”.
http://www.cookbook-r.com/Graphs/Plotting_means_and_error_bars_(ggplot2)/#Helper functions
From that website:
Norms the data within specified groups in a data frame; it normalizes each subject (identified by idvar) so that they have the same mean, within each group specified by betweenvars. data: a data frame. idvar: the name of a column that identifies each subject (or matched subjects) measurevar: the name of a column that contains the variable to be summariezed betweenvars: a vector containing names of columns that are between-subjects variables na.rm: a boolean that indicates whether to ignore NA’s
normDataWithin <- function(data=NULL, idvar, measurevar, betweenvars=NULL,
na.rm=FALSE, .drop=TRUE) {
#library(plyr)
# Measure var on left, idvar + between vars on right of formula.
data.subjMean <- ddply(data, c(idvar, betweenvars), .drop=.drop,
.fun = function(xx, col, na.rm) {
c(subjMean = mean(xx[,col], na.rm=na.rm))
},
measurevar,
na.rm
)
# Put the subject means with original data
data <- merge(data, data.subjMean)
# Get the normalized data in a new column
measureNormedVar <- paste(measurevar, "_norm", sep="")
data[,measureNormedVar] <- data[,measurevar] - data[,"subjMean"] +
mean(data[,measurevar], na.rm=na.rm)
# Remove this subject mean column
data$subjMean <- NULL
return(data)
}
myCenter
This function ouputs the centered values of an variable, which can be a numeric variable, a factor, or a data frame. It was taken from Florian Jaegers blog
https://hlplab.wordpress.com/2009/04/27/centering-several-variables/.
From his blog:
If the input is a numeric variable, the output is the centered variable.
If the input is a factor, the output is a numeric variable with centered factor level values. That is, the factor’s levels are converted into numerical values in their inherent order (if not specified otherwise, R defaults to alphanumerical order). More specifically, this centers any binary factor so that the value below 0 will be the 1st level of the original factor, and the value above 0 will be the 2nd level.
If the input is a data frame or matrix, the output is a new matrix of the same dimension and with the centered values and column names that correspond to the colnames() of the input preceded by “c” (e.g. “Variable1” will be “cVariable1”).
myCenter= function(x) {
if (is.numeric(x)) { return(x - mean(x, na.rm=T)) }
if (is.factor(x)) {
x= as.numeric(x)
return(x - mean(x, na.rm=T))
}
if (is.data.frame(x) || is.matrix(x)) {
m= matrix(nrow=nrow(x), ncol=ncol(x))
colnames(m)= paste("c", colnames(x), sep="")
for (i in 1:ncol(x)) {
m[,i]= myCenter(x[,i])
}
return(as.data.frame(m))
}
}
lizCenter
This function provides a wrapper around myCenter allowing you to center a specific list of variables from a dataframe.
- x: data frame
- listfname: a list of the variables to be centered (e.g. list(variable1,variable2))
The output is a copy of the data frame with a column (always a numeric variable) added for each of the centered variables. These columns are labelled with the each column’s previous name, but with “.ct” appended (e.g., “variable1” will become “variable1.ct”).
lizCenter= function(x, listfname)
{
for (i in 1:length(listfname))
{
fname = as.character(listfname[i])
x[paste(fname,".ct", sep="")] = myCenter(x[fname])
}
return(x)
}
get_coeffs
This function allows us to inspect particular coefficients from the output of an lme model by putting them in table.
- x: the output returned when running lmer or glmer (i.e. an objet of type lmerMod or glmerMod)
- list: a list of names of the coefficients to be extracted (e.g. c(“variable1”,“variable1:variable2”))
#get_coeffs <- function(x,list){(kable(as.data.frame(summary(x)$coefficients)[list,],digits=3))}
get_coeffs <- function(x,list){(as.data.frame(summary(x)$coefficients)[list,])}
Bf
This function is equivalent to the Dienes (2008) calculator which can be found here: http://www.lifesci.sussex.ac.uk/home/Zoltan_Dienes/inference/Bayes.htm.
The code was provided by Baguely and Kayne (2010) and can be found here: http://www.academia.edu/427288/Review_of_Understanding_psychology_as_a_science_An_introduction_to_scientific_and_statistical_inference
Bf<-function(sd, obtained, uniform, lower=0, upper=1, meanoftheory=0,sdtheory=1, tail=2){
area <- 0
if(identical(uniform, 1)){
theta <- lower
range <- upper - lower
incr <- range / 2000
for (A in -1000:1000){
theta <- theta + incr
dist_theta <- 1 / range
height <- dist_theta * dnorm(obtained, theta, sd)
area <- area + height * incr
}
}else
{theta <- meanoftheory - 5 * sdtheory
incr <- sdtheory / 200
for (A in -1000:1000){
theta <- theta + incr
dist_theta <- dnorm(theta, meanoftheory, sdtheory)
if(identical(tail, 1)){
if (theta <= 0){
dist_theta <- 0
} else {
dist_theta <- dist_theta * 2
}
}
height <- dist_theta * dnorm(obtained, theta, sd)
area <- area + height * incr
}
}
LikelihoodTheory <- area
Likelihoodnull <- dnorm(obtained, 0, sd)
BayesFactor <- LikelihoodTheory / Likelihoodnull
ret <- list("LikelihoodTheory" = LikelihoodTheory,"Likelihoodnull" = Likelihoodnull, "BayesFactor" = BayesFactor)
ret
}
Bf_powercalc
This works with the Bf funciton above. It requires the same values as that function (i.e. the obtained mean and SE for the current sample, a value for the predicted mean, which is set to be sdtheory (with meanoftheory=0), and the current number of participants N). However rather than return a BF for the current sample, it works out what the BF would be for a range of different subject numbers (assuming that the SE scales with sqrt(N)),
Bf_powercalc<-function(sd, obtained, uniform, lower=0, upper=1, meanoftheory=0, sdtheory=1, tail=2, N, min, max)
{
x = c(0)
y = c(0)
# note: working out what the difference between N and df is (for the contrast between two groups, this is 2; for constraints where there is 4 groups this will be 3, etc.)
for(newN in min : max)
{
B = as.numeric(Bf(sd = sd*sqrt(N/newN), obtained, uniform, lower, upper, meanoftheory, sdtheory, tail)[3])
x= append(x,newN)
y= append(y,B)
output = cbind(x,y)
}
output = output[-1,]
return(output)
}
Training
DV: Each training trial produces a data point (did they pick the correct picture - 1/0; note they get feedback on this)
load up and run lmes on relevant pilot data
The child data below come from a two session study where they were trained on stimuli similar to the “picture-only” condition in the current study. We have data from both 7 year olds and 11 year olds; the 11 year old data here are relevant in providing an estimate that can be used to inform H1 in our BF example analyses.
The adult data below come from a two session study where there were two conditions: (1) trained on stimuli similar to the “picture-only” condition in the current study (2) trained on pictures JUST of the diacritics. This is useful for considering possible effects of condition in the data (though with the caveat that comparison is somewhat different).
Note: tonecontrast is fixed effect with 6 levels (six possible contrasts). It is expected to contribute to model and is thus included but isn’t of specific interest.
child.train = read.csv("kidstrain_clean.csv")
adult.train = read.csv ("adultstrain_clean.csv")
child.train$agegroup = relevel(child.train$agegroup, ref="7years")
adult.train$condition = relevel(adult.train$condition, ref="i")
child.train.7 = subset(child.train, agegroup == "7years")
child.train.7 <- lizCenter(child.train.7, list("session", "tonecontrast"))
child.train.7.mod = glmer (result ~
+ session.ct
+ tonecontrast.ct
+ (session.ct|subject),
data = child.train.7, family = binomial, control=glmerControl(optimizer = "bobyqa"))
round(summary(child.train.7.mod)$coefficients,3)
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.157 0.059 2.659 0.008
session.ct 0.158 0.077 2.062 0.039
tonecontrast.ct -0.026 0.022 -1.171 0.242
child.train.11 = subset(child.train, agegroup == "11years")
child.train.11 <- lizCenter(child.train.11, list("session", "tonecontrast"))
child.train.11.mod = glmer (result ~
+ session.ct
+ tonecontrast.ct
+ (session.ct|subject),
data = child.train.11, family = binomial, control=glmerControl(optimizer = "bobyqa"))
round(summary(child.train.11.mod)$coefficients,3)
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.538 0.096 5.602 0.000
session.ct 0.301 0.085 3.538 0.000
tonecontrast.ct -0.051 0.023 -2.233 0.026
adult.train <- lizCenter(adult.train, list("session", "tonecontrast","condition"))
adult.train.mod = glmer (result ~
+ session.ct *condition.ct
+ tonecontrast.ct
+ (session.ct|subject),
data = adult.train, family = binomial, control=glmerControl(optimizer = "bobyqa"))
round(summary(adult.train.mod)$coefficients,3)
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.961 0.091 10.555 0.000
session.ct 0.487 0.067 7.263 0.000
condition.ct 0.416 0.181 2.291 0.022
tonecontrast.ct 0.067 0.010 6.740 0.000
session.ct:condition.ct -0.032 0.133 -0.241 0.809
Prediction2: Improvement with session in each condition
Based on:
We saw this in 7 year olds in previous study.
7 year olds means : 0.52, 0.56 7 year olds log odds (beta from lme): 0.1579623 7 year old odd (exp(beta))1.171122
Planned Analyses: Frequentist
lme model similar to that on pilot data above but with data from both conditions; Fit separate slopes for session for each condition. We will do this both for a model with just first two sessions and for a model with all data.
Planned Analyses: BF
Summary of data for each condition: mean and se for session.ct for each level of condition from lme value to inform H1: estimate from above pilot data for seven year olds 0.1579623
If it appears that one of the conditions (c1) shows a positive effect of session and one doesn’t (c2), we can also do BF analsyes for c2 data with H1 informed by estimate from c1 (this is a better estimate than the pilot since the conditions are more closely matched to each other than either is to the pilot data)
Required sample analyses
Frequentists power
dataS = with(droplevels(child.train.7), tapply(result,list(subject,session), mean, na.rm=T))
d= cohensD(x = dataS[,1], y = dataS[,2], method = "paired")
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .9, type = c("paired"), alternative = c( "greater"))
Paired t test power calculation
n = 28.38133
d = 0.5634754
sig.level = 0.05
power = 0.9
alternative = greater
NOTE: n is number of *pairs*
rm(dataS)
rm(d)
dataS = with(droplevels(child.train.7), tapply(result,list(subject,session), mean, na.rm=T))
d= cohensD(x = dataS[,1], y = dataS[,2], method = "paired")
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .8, type = c("paired"), alternative = c( "greater"))
Paired t test power calculation
n = 20.89366
d = 0.5634754
sig.level = 0.05
power = 0.8
alternative = greater
NOTE: n is number of *pairs*
rm(dataS)
rm(d)
dataS = with(droplevels(child.train.7), tapply(result,list(subject,session), mean, na.rm=T))
d= cohensD(x = dataS[,1], y = dataS[,2], method = "paired")
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .7, type = c("paired"), alternative = c( "greater"))
Paired t test power calculation
n = 16.25431
d = 0.5634754
sig.level = 0.05
power = 0.7
alternative = greater
NOTE: n is number of *pairs*
rm(dataS)
rm(d)
Required sample for BF analyses:
As for prediction 1, we again look at the pilot data from seven year olds, using H1 informed by estimate for 11 year olds. In our actual analsyes will be using estimate from the pilot data to inform H1.
meanBF = summary(child.train.7.mod)$coefficients["session.ct" ,"Estimate"]
seBF = summary(child.train.7.mod)$coefficients["session.ct" ,"Std. Error"]
h1mean = summary(child.train.11.mod)$coefficients["session.ct" ,"Estimate"]
Bf(seBF, meanBF, uniform =0,meanoftheory=0,sdtheory=h1mean,tail=1)
$LikelihoodTheory
[1] 2.206111
$Likelihoodnull
[1] 0.6215463
$BayesFactor
[1] 3.549392
rm(meanBF)
rm(seBF)
We have sufficient evidence to accept H1 over H0 on basis of current sample.
Prediction 4: They will improve more in one condition than the other(no predicted direction)
Based on:
We don’t have any clear evidence to base this on. However it seems reasonable that the type of training will leed to different learning slopes. One possibility is that while they show greater learning in the condition with diacrtics, due to more information per trial. However it is also possible that they could show steeper learning in the other condition, due to needing to pay more attention to and remember individual stimuli. We saw means in this latter direction in the adult pilot data i.e. more improvement in the condition with pictures (labelled condition “i” for implicit) than with diacrticis (labelled “e” for explicit) (though conditions not exactly the same see above). though it wsn’t signficant.
adult means : 0.62, 0.71, 0.72, 0.79 beta: -0.0321743
Planned Analyses: Frequentist
lme model similar to that on pilot data above but with data from both conditions; look for fixed effect of condition.ct:session.ct We will do this both for a model with just first two sessions and for a model with all data.
Planned Analyses: BF
Summary of data: mean and se for interaction session and condition (session.ct by conditoin.ct) value to inform H1: estimate of session from the same model model (e.g. summary(model.newdata)$coefficients[“session.ct” ,“Estimate”]`.
This will provide a relatively high estiamte of likely effect of interaction (if one is present) given the actual data set (so again, a conservative estimate)
[Note: are checking this with stats consultant]
Note this is exemplified below in sample size analysis using the current data from adults:
Required sample analyses
Frequentist power
Nothing to base power analysis on here (as was no effect in original data).
Required sample for BF analyses:
Note this is with adult data - it exemplifies the process we will actually use to conduct power analyses on actual data
meanBF = summary(adult.train.mod)$coefficients["session.ct:condition.ct","Estimate"]
seBF = summary(adult.train.mod)$coefficients["session.ct:condition.ct","Std. Error"]
h1mean = summary(adult.train.mod)$coefficients["session.ct","Estimate"]
Bf(seBF, meanBF, uniform =0,meanoftheory=0,sdtheory=h1mean,tail=2)
$LikelihoodTheory
[1] 0.7889355
$Likelihoodnull
[1] 2.905926
$BayesFactor
[1] 0.271492
rm(meanBF)
rm(seBF)
Note: we use tail =2 as don’t have a clear direction for this hypothesis
So note, with adult pilot data we do have evidence in favor of H0 from the current data set.
One possibility with children is that we will not be able to obtain a large enough sample to provide evidence for/against the hypothesis that there is more learning in one direction, but we may find evidence for the H1 that there is an effect of session in one condition but for the H0 that there is not and effect of session in the other condition. If so, we will deem this sufficient to address this prediciton.
2AFC picture and 2AFC diacritic
These two tests are very similar to training but with either just pictures or just diacritics. The tests are only done as post tests, not as pre-tests (unlike all of the tests discussed after this one)
Children in the pictures+diacritics condition will get the 2AFC pictures test followed by the 2AFC diacritics test; children in the picturesonly test will get just 2AFC pictures but will get it twice (so that total exposure doesn’t differ across conditions).
Where we just look a conditions separately, for the just pictures test, we will look at all of the data (i.e. for the pictures only condition, from both parts of the repeated test). Where we compare conditions, we will look only use data from the first 2AFC test.
Note: unlike for all the tests that follow, there is no pre-test.
run lmes on relevant pilot data
We didn’t do this test in the pilot, however the test is rather similar to training test so we use model based on just last 24 sessions of training for informing power decisions.
child.train.7.s2.24 = droplevels(subset(child.train, agegroup == "7years" & session =="session2" & order>72))
child.train.7.s2.24 = lizCenter(child.train.7.s2.24, c("tonecontrast"))
child.train.7.s2.s4.mod = glmer (result ~
1+ tonecontrast.ct
+ (1|subject),
data = child.train.7.s2.24, family = binomial, control=glmerControl(optimizer = "bobyqa"))
round(summary(child.train.7.s2.s4.mod)$coefficients,3)
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.201 0.106 1.894 0.058
tonecontrast.ct 0.008 0.062 0.124 0.901
child.train.11.s2.24 = droplevels(subset(child.train, agegroup == "11years" & session =="session2" & order>72))
child.train.11.s2.24 = lizCenter(child.train.11.s2.24, c("tonecontrast"))
child.train.11.s2.s4.mod = glmer (result ~
1+ tonecontrast.ct
+ (1|subject),
data = child.train.11.s2.24, family = binomial, control=glmerControl(optimizer = "bobyqa"))
round(summary(child.train.11.s2.s4.mod)$coefficients,3)
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.686 0.117 5.839 0.000
tonecontrast.ct -0.075 0.066 -1.144 0.253
adult.train.s2.24 = subset(adult.train, session =="session2" & order>264)
adult.train.s2.24 = lizCenter(adult.train.s2.24, list("tonecontrast"))
adult.train.s2.24.mod = glmer (result ~
1+ tonecontrast.ct
+ (1|subject),
data = adult.train.s2.24, family = binomial, control=glmerControl(optimizer = "bobyqa"))
round(summary(adult.train.s2.24.mod)$coefficients,3)
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.284 0.136 9.428 0
tonecontrast.ct 0.218 0.055 3.977 0
Discrimination
This test will be given pre and post. Children will hear three frogs each produce a Mandarin word. One produces the target and the other two each produce the same foil word, which will be a word differeing from the target only in tone.
Each of the 6 one contrasts are tested. We put tonecontrast into the model, since it is likely to have an effect, but don’t have specific hypotheses of interest here. There are four talkers, 3f 1m. Trials in which the m is the odd one out are known to be easiest and those where one of the speakers is m but it is not the odd one out are eaisest. THere are an equal number of each trial type and we put trial type into the model as a factor; though again it isn’t a question for which we have predictions.
For the intial data set collected, we will consider both pre-test -> posttest1 and pre-test -> post-test2 (if equivlaent results obtaned, subsequenting testing will drop final two sessions - see note above)
load up and run lmes on relevant pilot data
The pilot child data below come from same 2-session study as pilot traning data (recall they were trained on stimuli similar to the “picture-only” condition in the current study.)
The adult data below come from a different two- session study where there were two condition (1) trained on stimuli similar to the “picture-only” condition in the current study (2) trained on pictures JUST of the diacritics. This is useful for considering possible effects of condition in the data (though with the caveat that comparison is somewhat different).
Note that for both adults and children in the pilot experiemnt we had both trained and untrained items. For this experiment we use only untrained items in this test so we remove the untrained items from the analyses below.
Note: tonecontrast is fixed effect with 6 levels (six possible contrasts). It is expected to contribute to model and is thus included but isn’t of specific interest.
child.discrim = read.csv("kidsdiscrim_clean.csv")
adult.discrim = read.csv ("adultsdiscrim_clean.csv")
child.discrim$pre_post = relevel(child.discrim$pre_post, ref="pre")
child.discrim$agegroup = as.factor(child.discrim$agegroup)
adult.discrim$pre_post = relevel(adult.discrim$pre_post, ref="pre")
adult.discrim$condition = relevel(adult.discrim$condition, ref="i")
child.discrim$pre_post = relevel(child.discrim$pre_post, ref="pre")
adult.discrim<- droplevels(subset(adult.discrim, neworold == "newword"))
child.discrim<- droplevels(subset(child.discrim, neworold == "newword"))
adult.discrim <- lizCenter(adult.discrim, list("pre_post","trialtype", "condition", "tonecontrast"))
adult.discrim.mod = glmer (correct ~
+ condition.ct * pre_post.ct
+ trialtype.ct
+ tonecontrast.ct
+ (pre_post.ct|participantnumber),
data = adult.discrim, family = binomial, control=glmerControl(optimizer = "bobyqa"))
round(summary(adult.discrim.mod)$coefficients, 3)
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.345 0.075 4.615 0.000
condition.ct -0.147 0.149 -0.984 0.325
pre_post.ct 0.287 0.099 2.897 0.004
trialtype.ct 0.066 0.054 1.232 0.218
tonecontrast.ct 0.041 0.013 3.251 0.001
condition.ct:pre_post.ct -0.071 0.198 -0.360 0.719
child.discrim.7 = droplevels(subset(child.discrim, agegroup == "7"))
child.discrim.7 <- lizCenter(child.discrim.7, list("pre_post","trialtype", "condition", "tonecontrast"))
child.discrim.7.mod = glmer (correct ~
+ pre_post.ct
+ trialtype.ct
+ tonecontrast.ct
+ (pre_post.ct|participantnumber),
data = child.discrim.7, family = binomial, control=glmerControl(optimizer = "bobyqa"))
round(summary(child.discrim.7.mod)$coefficients, 3)
Estimate Std. Error z value Pr(>|z|)
(Intercept) -0.445 0.128 -3.472 0.001
pre_post.ct -0.365 0.228 -1.604 0.109
trialtype.ct -0.252 0.139 -1.815 0.070
tonecontrast.ct 0.115 0.033 3.504 0.000
Prediction1: Improvement from pre-post test in each each condition
Based on
In the pilot data, adults show improvement with session but neither 7 year olds didn’t (nb nor did 11 year olds)
means : 0.55, 0.61; log odds (beta from lme): 0.2868916; odd (exp(beta))1.3322798
7year olds (don’t show this- in fact means reversed )
means : 0.44, 0.36; log odds (beta from lme): -0.3652203; odd (exp(beta))0.6940437
Planned Analyses: Frequentist
lme model similar to that on pilot data above but with data from both conditions; Fit separate slopes for pre-post in each condition
For the intial data set collected we will do this both to compare pre test to post-test 1 and pre-test to post-test2 (see notes above).
Planned Analyses: BF
Summary of data for each condition: mean and se for pre-post from lme value to inform H1: estimate from above pilot data for adults i.e. 0.2868916
Note: this adult value will likely overestimate the means. A better value would come from the new data from children themselves - therefore, if they show learing in one condition we will use that to inform BF for the other condition (and if both show learning we will use to inform BF for each other).
Required sample analyses
Frequentist Power
Note: this analysis included for completeness but is not really relevant since it is based on adult data. If children do show an effect, it is likely smaller and they will have larger SE
dataS=with(droplevels(adult.discrim), tapply(correct,list(participantnumber, pre_post), mean, na.rm=T))
d = cohensD(x = as.numeric(dataS[,1]),y = as.numeric(dataS[,2]), method = "paired")
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .9, type = c("paired"), alternative = c( "greater"))
Paired t test power calculation
n = 31.24664
d = 0.5356902
sig.level = 0.05
power = 0.9
alternative = greater
NOTE: n is number of *pairs*
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .8, type = c("paired"), alternative = c( "greater"))
Paired t test power calculation
n = 22.95973
d = 0.5356902
sig.level = 0.05
power = 0.8
alternative = greater
NOTE: n is number of *pairs*
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .7, type = c("paired"), alternative = c( "greater"))
Paired t test power calculation
n = 17.82436
d = 0.5356902
sig.level = 0.05
power = 0.7
alternative = greater
NOTE: n is number of *pairs*
rm(d)
rm(dataS)
Required sample for BF analyses from pilot data
Here we look at data from 7 year olds in pilot and
meanBF = summary(child.discrim.7.mod)$coefficients["pre_post.ct" ,"Estimate"]
seBF = summary(child.discrim.7.mod)$coefficients["pre_post.ct" ,"Std. Error"]
h1mean = summary(adult.discrim.mod)$coefficients["pre_post.ct" ,"Estimate"]
Bf(seBF, meanBF, uniform =0,meanoftheory=0,sdtheory=h1mean,tail=1)
$LikelihoodTheory
[1] 0.1393478
$Likelihoodnull
[1] 0.4839102
$BayesFactor
[1] 0.2879621
rm(meanBF)
rm(seBF)
rm(h1mean)
Have evidence for the null from just 15 participants. Note however, that we are relatively high estimate for H1, which may make it easier to find evidence for the null.
Prediction2: More improvement in one condition than the other
Based on
We don’t have any specific evidence to base this on. The closest contrasts was in the adult pilot experiment (comparing condition with picture only training versus diacritic only training) where they showed numerically more improvement in the implicit condition, but the difference was NS.
means : 0.56, 0.63, 0.54, 0.59 log odds (beta from lme): -0.0711115 odd (exp(beta))0.931358
For the intial data set collected Ww will do this both to compare pre test to post-test 1 and pre-test to post-test2 (see notes above).
Planned Analyses: Frequentist
lme model similar to that on pilot data above but with data from both conditions; look for interaction between pre-post and condition.
Planned Ananlyses: BF
Summary of data for each condition: mean and se for pre-post*condition from lme value to inform H1: estimate for session from the current model (i.e. summary(new.data)$coefficients[“pre_post.ct” ,“Estimate”]`
Note: we only do this if we have evidence of an effect of pre-post in at least one of the conditions. If they don’t learn in either condition then this test is inappropriate.
Also note that this will be relatively conservative estimate for a large difference in how much the conditions lead to a change pre to post. (again will seek statistial advice here)
Required sample estimates
Frequentist Power
We have no data to look at this (since was no sig. difference in data collected)
Required sample for BF analyses from pilot data
Here we are looking at this with adult data.
meanBF = summary(adult.discrim.mod)$coefficients["condition.ct:pre_post.ct" ,"Estimate"]
seBF = summary(adult.discrim.mod)$coefficients["condition.ct:pre_post.ct" ,"Std. Error"]
h1mean = summary(adult.discrim.mod)$coefficients["pre_post.ct" ,"Estimate"]
Bf(seBF, meanBF, uniform =0,meanoftheory=0,sdtheory=h1mean,tail=2)
$LikelihoodTheory
[1] 1.121749
$Likelihoodnull
[1] 1.89307
$BayesFactor
[1] 0.5925559
plot(Bf_powercalc(seBF, meanBF, uniform =0,meanoftheory=0,sdtheory=h1mean, N=15, min=900, max = 50, tail=2))
abline(h=3)

Bf_powercalc(seBF, meanBF, uniform =0,meanoftheory=0,sdtheory=h1mean, N=15, min=811, max = 815, tail=2)
x y
[1,] 811 3.007075
[2,] 812 3.018251
[3,] 813 3.029471
[4,] 814 3.040735
[5,] 815 3.052043
rm(meanBF)
rm(seBF)
rm(h1mean)
General note: this analysis suggestst that even for adults, wouldn’t need a sample of over 800 participants per condition to see this interaction. This is implausible (though may be partly because are basing on over conservative value for h1).
However this analysis suggests it will be difficult to gain power for this interaction. On the other hand, previous analyses may make it clear that there is no improvement on this test in EITHER condition (see Prediction 1 above). In that that it may be very difficult to power this. One possibility is that we won’t have power for the interaction but will have power to say we have evidence for learning in one condition, but for the other there is more evidence for the null than for H1 based on that condition.
Word repetition
This test is given pre and post. Children hear a word and copy it back. We look to see if they repeat back the tone correctly (they will be coded by native speakers who blind as to both condition and what the target word is; the tone of the transcribed word will compared to tone of target and thus coded as correct/incorrect).
There are equal number of words for each of the four tones.
For the intial data set collected, will consider both pre-test -> posttest1 and pre-test -> post-test2 (if equivalent results obtaned, subsequenting testing will drop final two sessions - see note above)
load up and run lmes on pilot data
The child data below come from same two session study as pilot traning data/discrim data (i.e where they were trained on stimuli similar to the “picture-only” condition in the current study.)
The adult data below do not come from the same two day pilot study as the other adult data used above (that student project didn’t include this test), but instead from a much longer 9 session experiment conducted by current PhD student. There was no contrast of condition of the type relevant to the current study in that data.
Note that for both adults and children in pilot experiments using this test we had both trained and untrained items. For this experiment we use only untrained items in thiis test so we remove the untrained items from the analyses below.
child.wr = read.csv("kidswordrep_clean.csv")
adult.wr = read.csv("adultswordrep_clean.csv")
child.wr = droplevels(subset(child.wr, wordtype == "new"))
adult.wr = droplevels(subset(adult.wr, wordtype == "Untrained"))
child.wr$pre_post = relevel(child.wr$pre_post, ref = "pre")
adult.wr$pre_post = relevel(adult.wr$pre_post, ref = "pre")
child.wr.7 = droplevels(subset(child.wr, Age=="young"))
child.wr.7 <- lizCenter(child.wr.7, list("Age", "pre_post","correcttone"))
child.wr.7.mod = glmer (resulttone ~
+ pre_post.ct
+ correcttone.ct
+ (pre_post.ct|participantname),
data = child.wr.7, family = binomial, control=glmerControl(optimizer = "bobyqa"))
round(summary(child.wr.7.mod)$coefficients,3)
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.553 0.147 3.764 0.000
pre_post.ct 0.309 0.141 2.183 0.029
correcttone.ct 0.066 0.043 1.537 0.124
adult.wr <- lizCenter(adult.wr, list( "pre_post","correcttone"))
adult.wr.mod = glmer (resulttone ~
+ pre_post.ct
+ correcttone.ct
+ (pre_post.ct|participantname),
data = adult.wr, family = binomial, control=glmerControl(optimizer = "bobyqa"))
round(summary(adult.wr.mod)$coefficients,3)
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.110 0.077 14.321 0
pre_post.ct 0.412 0.118 3.491 0
correcttone.ct -0.142 0.032 -4.409 0
Prediction1: Improvement from pre-post test in each each condition
Based on
Both adults and children showed this in the relevant pilot studies
adult mean : 0.7, 0.77; adult log odds (beta from lme): 0.4117959; adult odd (exp(beta))1.5095264
7year mean :0.59, 0.65; 7year log odds (beta from lme): 0.3085348; 7year odd (exp(beta))1.3614289
Planned Analyses: Frequentist
lme model similar to that on pilot data above but with data from both conditions; Fit separate slopes for pre-post in each condition
For the intial data set collected We will do this both to compare pre test to post-test 1 and pre-test to post-test2 (see notes above).
Planned Analyses: BF
Summary of data for each condition: mean and se for pre-post from lme value to inform H1: estimate from above pilot data for children i.e. 0.3085348
NOTE: If (e.g.) we find an effect for condition1, we can also use the estimate for session for that to inform H1 when looking at data from condition2; and vice versa. This is a better estimate since the conditions are more closely matched to each other than either is to the pilot data/
Required sample analyses
Frequentist Power
Note: this analysis included for completeness but is not really relevant since it is based on adult data. If children do show an effect, it is likely smaller and they will have larger SE
7
dataS = with(droplevels(child.wr.7), tapply(resulttone,list(participantname,pre_post), mean, na.rm=T))
d= cohensD(x = dataS[,1], y = dataS[,2], method = "paired")
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .9, type = c("paired"), alternative = c( "greater"))
Paired t test power calculation
n = 32.46102
d = 0.5250962
sig.level = 0.05
power = 0.9
alternative = greater
NOTE: n is number of *pairs*
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .8, type = c("paired"), alternative = c( "greater"))
Paired t test power calculation
n = 23.83549
d = 0.5250962
sig.level = 0.05
power = 0.8
alternative = greater
NOTE: n is number of *pairs*
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .7, type = c("paired"), alternative = c( "greater"))
Paired t test power calculation
n = 18.48998
d = 0.5250962
sig.level = 0.05
power = 0.7
alternative = greater
NOTE: n is number of *pairs*
rm(dataS)
rm(d)
Sample estimation suggests that N=33 per condition for 90% power.
Required sample for BF analyses from pilot data
Note that here we use the mean from the adult pilot data adults to inform H1 (whereas for actual analyses we will be using value from pilot data with 7 year olds to inform H1)
meanBF = summary(child.wr.7.mod)$coefficients["pre_post.ct" ,"Estimate"]
seBF = summary(child.wr.7.mod)$coefficients["pre_post.ct" ,"Std. Error"]
h1mean = summary(adult.wr.mod)$coefficients["pre_post.ct" ,"Estimate"]
Bf(seBF, meanBF, uniform =0,meanoftheory=0,sdtheory=h1mean,tail=1)
$LikelihoodTheory
[1] 1.398479
$Likelihoodnull
[1] 0.2603624
$BayesFactor
[1] 5.371278
rm(meanBF)
rm(seBF)
We have sufficient evidence from the sample of N=15 children for H1.
Prediction 2: There will be more improvement in one condition by pre-post
Based on
We have no data to base this on as we haven’t previously used this test in an experiment contrasting these (or similar) conditions.
If the presence of the diacritics boosts learning, children may improve more in the diacrticis+picture condition.
Planned Analyses: Frequentist
lme model similar to that on pilot data above but with data from both conditions; look for interaction of pre-post and condition
For the intial data set collected Ww will do this both to compare pre test to post-test 1 and pre-test to post-test2 (see notes above).
Planned Ananlyses: BF
Summary of data for each condition: mean and se for pre-post*condition from lme value to inform H1: estimate for session from the model with the new data (i.e. summary(new.data)$coefficients[“pre_post.ct” ,“Estimate”]`
Note: we only do this if we have evidence of an effect of pre-post in at least one of the conditions. If they don’t learn in either condition then this test is inappropriate.
Also note that this will be relatively conservative estimate for a large difference in how much the conditions lead to a change pre to post.
Required sample analyses
We have no relevant data to can base this on for either frequentist or BF analyses. One possibility is that we won’t be able to get a sufficiently large sample to have power for this interaction. As for other tests, here we may have to draw whatever conculsionsare possible based on which of the conditions individually provides evidence for H1/H0.
LS0tDQp0aXRsZTogJ1BsYW4gZm9yIHRlc3RpbmcgeWVhciAzIG9uIHBpY3R1cmVzLW9ubHkgdmVyc3VzIHBpY3R1cmVzK3RvbmVzJw0KYXV0aG9yOiAiRWxpemFiZXRoIFdvbm5hY290dCINCmRhdGU6ICIxOC4wNi4xNyINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgdG9jOiB0cnVlDQptYXgtd2lkdGg6IDMwMA0KDQotLS0NCg0KY29tbWVudDogdG9jIGNvbWFuZCBub3Qgd29ya2luZywgbmVlZCB0byByZXBvc3Qgd2l0aCBoZWFkaW5ncyBsaW5rcyBmb3IgZWFzZSBvZiBuYXZpZ2F0aW9uICANCg0KIyBHZW5lcmFsIG5vdGVzDQoNClRoaXMgY29udGFpbmVkIHBsYW5lZCBhbmFseXNlcyBhcyBvZiAxOC4wNi4xNyBmb3IgZGF0YSBzZXQgd2hpY2ggd2Ugd2lsbCBzdGFydCB0byBjb2xsZWN0IG9uIDE5LzA2LzE3Lg0KUGxhbnMgbWF5IGNoYW5nZSBhcyBhIHJlc3VsdCBvZiBzdGF0c2l0aWNhbCBjb25zdWxhdGlvbiAod2UgYXJlIGN1cnJlbnRseSBzZWVraW5nIGFkdmljZSBvbiBzb21lIGRldGFpbHMpDQoNClRoZSBzdHVkeSBpcyBhIHRyYWluaW5nIHN0dWR5IHRvIGJlIGNvbmR1Y3RlZCB3aXRoIHllYXIgMyAoNy04IHllYXJzKSBjaGlsZHJlbiB3aXRoIG5vIHByZXZpb3VzIGtub3dsZWRnZSBvZiBNYW5kYXJpbiBvciBhbnkgdG9uZSBsYW5ndWFnZSwgdHJhaW5pbmcgdGhlbSBvbiB0aGUgZm91ciB0b25lcyAoNiB0b25lIGNvbnRyYXN0cykgaW4gTWFuZGFyaW4uICBUaGVyZSB3aWxsIGludGlhbGx5IGJlIHR3byBjb25kaXRpb25zOiAoMSkgcGljdHVyZXMtb25seTogdGhleSBhcmUgdHJhaW5lZCB1c2luZyBhIDJBRkMgdGFzayB3aGVyZSB0aGV5IGhlYXIgYSAocmVhbCkgTWFuZGFyaW4gd29yZCBhbmQgaWRlbnRpZnkgd2hpY2ggb2YgdHdvIHBpY3R1cmVzIGl0IHJlZmVycyB0byAob25lIGNvcnJlY3QsIG9uZSBhIGZvaWwgd2hpY2ggZGlmZmVycyBvbmx5IGJ5IHRvbmUpOyAoMikgcGljdHVyZXMrZGlhY3JpdGljcyAtIHNhbWUgdGFzayBidXQgdGhlIHBpY3R1cmVzIGFyZSBhY29tcGFuaWVkIGJ5IHBpY3R1cmVzIG9mIHRoZSBmb3VyIGRpYWNyaXRpY3MuIFtJZiByZXNvdXJjZXMgcGVybWl0LCB3ZSBtYXkgbGF0ZXIgcnVuIGEgZGlhY3JpdGljcyBvbmx5IGNvbmRpdGlvbl0uIERhdGEgd2lsbCBiZSAgY29sbGVjdGVkIGJvdGggZnJvbSB0cmFpbmluZyBhbmQgZnJvbSBzb21lIHRlc3RzIGNvbmR1Y3RlZCBwcmUgYW5kIHBvc3QgdHJhaW5pbmcuDQogDQpPdXIgbWFpbiBhbmFseXNlcyB3aWxsIGJlIEJheXNlYW4gYW5kIHdlIHdpbGwgY29tcHV0aW5nIEJheWVzIGZhY3RvcnMgdXNpbmcgdGhlIG1ldGhvZCBhZHZvY2F0ZWQgYnkgRGllbmVzLCAyMDA4IDtEaWVuZXMsIDIwMTU7IHdlIHdpbGwgYWxzbyBhbG9uZyBzaWRlIHByb3ZpZGUgZnJlcXVlbnRpc3Qgc3RhdGlzdGljcy4gRnJlcXVlbnRpc3Qgc3RhdGlzdGljcyB3aWxsIGNvbXB1dGVkIHVzaW5nIGxvZ2lzdGljIG1peGVkIGVmZmVjdCBtb2RlbHMsIHRoaXMgbWV0aG9kIGlzIHVzZWQgc2luY2UgaW4gZWFjaCBjYXNlIHdlIGhhdmUgYSBkZXBlbmRlbnQgdmFyaWFibGUgb2YgY29ycmVjdC9pbmNvcnJlY3QgcmVzcG9uc2UuIE5vdGUgdGhhdCBhbHRob3VnaCBtaXhlZCBtb2RlbHMgYWxsb3cgdXMgdG8gaW5jbHVkZSBib3RoIHBhcnRpY2lwYW50cyBhbmQgaXRlbXMsIHdlIGRvIG5vdCBpbnRlbmQgdG8gaW5jbHVkZSBpdGVtcyBpbiB0aGUgYW5hbHlzZXMgc2luY2UgcG93ZXIgb24gdGhpcyBkaW1lbnNpb24gd2lsbCBiZSBsb3cuIChOQiAtIGl0IGlzIG5vdCBjb21tb24gZm9yIGJ5IGl0ZW1zIGFuYWx5c2VzIHRvIGJlIGluY2x1ZGVkIGZvciB3b3JrIGluIHRoaXMgYXJlYTsgaW5jcmVhc2luZyB0aGUgbnVtYmVyIG9mIGl0ZW1zIGluIGEgbGVhcm5pbmcgc3R1ZHkgb2YgdGhpcyB0eXBlIHdpdGggY2hpbGRyZW4gaXMgbm90IGZlYXNpYmxlKS4gV2UgdXNlIGZ1bGwgcmFuZG9tIHNsb3BlcyBzdHJ1Y3R1cmUgZm9yIHByZWRpY3RvcnMgb2YgaW50ZXJlc3QgKGdlbmVyYWxseSwgY29uZGl0aW9uLCBzZXNzaW9uL3ByZS0+cG9zdCkuIEZhY3RvcnMgc3VjaCBhcyB0b25lIGNvbnRyYXN0IGZvciB0aGUgdHJpYWwgYXJlIGluY2x1ZGVkIGFzIGZpeGVkIGZhY3RvcnMgYW5kIHdlIHdpbGwgbm90IGluY2x1ZGUgcmFuZG9tIHNsb3BlcyAgZm9yIHRoZXNlLg0KDQpGb3IgdGhlIEJheWVzaWFuIGFuYWxzeWVzLCB3ZSB3aWxsIGNvbnRpbnVlIHRvIHdvcmsgaW4gbG9nIG9kZHMgc3BhY2UgKGFzIGZvciBGcmVxdWVudGlzdCkgdG8gbWVldCBhc3N1bXB0aW9ucyBvZiBub3JtYWxpdHksIHVzaW5nIGVzdGltYXRlcyBhbmQgc3RhbmRhcmQgZXJyb3JzIHdoaWNoIGNvbWUgZnJvbSB0aGUgbG9naXN0aWMgbWl4ZWQgZWZmZWN0cyBtb2RlbHMuIEZvbGxvd2luZyBEaWVuZXMgKDIwMDgpIHdlIHdpbGwgbW9kZWwgSDEgYnkgdXNpbmcgYW4gZXN0aW1hdGUgb2YgdGhlIG1lYW4gZm9yIHRoZW9yeSAoYW4gZXN0aW1hdGUgY29taW5nIGZyb20gZWl0aGVyIGZyb20gbG9naXN0aWMgbWl4ZWQgZWZmZWN0cyBtb2RlbHMgcnVuIG92ZXIgcGlsb3QgZGF0YSwgb3IgaW4gc29tZSBjYXNlcyBmcm9tIGVsc2V3aGVyZSBpbiB0aGUgZGF0YSkgYXMgdGhlIFNEIG9mIGEgaGFsZiBub3JtYWwgKGZvciBvbmUgdGFpbGVkKSBvciBmdWxsIG5vcm1hbCAoZm9yIHR3byB0YWlsZWQpIGRpc3RyaWJ1dGlvbi4gV2Ugd2lsbCBzYXkgd2UgaGF2ZSBzdWJzdGFudGlhbCBldmlkZW5jZSBmb3IgSDEgaXMgQkY+MyBhbmQgQkY8LjMzIGFjY2VwdGVkIGlmIEJGPjQgDQoNClNlZTogaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvai5qbWwuMjAxNy4wMS4wMDUgZm9yIHB1Ymxpc2hlZCBwYXBlciB1c2luZyB0aGlzIGFwcHJvYWNoIGFuZCBSc2NyaXB0IGh0dHA6Ly9ycHVicy5jb20vZXdvbm5hY290dC8yNDI0NTQuIA0KDQoNCk5vdGUgdGhhdCB0aGUgcGlsb3QgZGF0YSByZWZlcnJlZCB0byBiZWxvdyBjb21lcyBmcm9tIHRocmVlIHN0dWRlbnRzIHByb2plY3RzLiBOb25lIHdlcmUgZXhhY3RseSB0aGUgc2FtZSBhcyB0aGUgZXhwZXJpbWVudHMgcGxhbm5lZCBoZXJlLCBidXQgbWF0ZXJpYWxzIHdlcmUgdmVyeSAgc2ltaWxhciBhbmQgaW4gc29tZSBjYXNlcyBzaW1pbGFyIHF1ZXN0aW9ucyB3ZXJlIGFza2VkLiBUaGUgbW9kZWxzIG9mIHRoZSBwaWxvdCBkYXRhIHByZXNlbnRlZCBiZWxvdyBhbHNvIHNlcnZlIHRvIGV4ZW1wbGlmeSB0aGUgYXBwcm9hY2ggdG8gYmUgdGFrZW4gd2l0aCB0aGUgY3VycmVudCBkYXRhLg0KDQpXaGVyZSBwb3NzaWJsZSwgd2UgY29uZHVjdGVkIHBvd2VyIGFuYWx5c2VzLCBhbHRob3VnaCBsbWUncyB3aWxsIGJlIHVzZWQgZm9yIHRoZSBhY3R1YWwgYW5hbHN5ZXMsIHdlIGNvbmR1Y3RlZCB0aGUgYW5hbHN5ZXMgYXMgdGhvdWdoIGZvciAobmVhciBlcXVpdmFsZW50KSB0LXRlc3RzIG92ZXIgYnkgc3ViamVjdCBwcm9wb3Rpb25zLiBUaGlzIG1lYW5zIHRoYXQgdGhlIHZhbHVlcyBhcmUgb25seSBhcHByb3hpbWF0ZSwgYnV0IHNpbmNlIG91ciBtYWluIGFuYWxzeWVzIGFyZSBCRiBmYWN0b3JzIG91ciBhaW0gaGVyZSBpcyB0byBnZXQgYW4gaWRlYSBvZiBhcHByb3hpbWF0ZSBzdWl0YWJsZSBzYW1wbGVzLg0KDQpJbiBhZGRpdGlvbiB0byBwb3dlciBhbmFseXNlcywgd2hlcmUgcG9zc2libGUgd2UgYWxzbyBjb25kdWN0ZWQgQmF5ZXNpYW4gYW5hbHN5ZXMgb24gcmVsZXZhbnQgcGFydHMgb2YgdGhlIHBpbG90IGRhdGEgdG8gc2VlIGlzIHdlIGhhZCBhIHN1ZmZpY2llbnQgc2FtcGxlIGZvciBCRj4zIG9yIEJGPC4zMy4gV2UgYWxzbyBsb29rIHRvIHNlZSB3aGF0IHNpemUgc2FtcGxlIG1pZ2h0IGJlIGV4cGVjdGVkIHRvIGdpdmUgQkY+MyBvciBCRjwuMzMsIGdpdmVuIHRoYXQgICBTRSB2YXJ1ZXMgYXMgc3F1YXJlcm9vdChOKS4NCg0KVGhlIGFuYWx5c2VzIGJlbG93IHN1Z2dlc3QgdGhhdCB0aGVyZSBhcmUgY2FzZXMgd2hlcmUgYSBzYW1wbGUgb2YgMjAgcGFydGljaXBhbnRzIHBlciBjb25kaXRpb24gY291bGQgYmUgc3VmZmljaWVudCB0byBhY2hlaXZlIDkwJSBwb3dlci4gSW50ZXJlYWN0aW9ucyB3aXRoIGNvbmRpdGlvbiB3aWxsIGJlIGhhcmRlciB0byBwb3dlcjsgYXMgZGlzY3Vzc2VkIGJlbG93LCB0aGVyZSBtYXkgYmUgc2l0dWF0aW9ucyB3aGVyZSB0aGVyZSBpcyBldmlkZW5jZSBvZiBIMSAoaWUuIGRhdGEgcmVmbGVjcyBsZWFybmluZykgaW4gY29uZGl0aW9uMSBidXQgZXZpZGVuY2UgZm9yIEgwIChubyBldmlkZW5jZSBvZiBsZWFybmluZyBpbiB0aGlzIGRhdCkgZm9yIGNvbmRpdGlvbjIuIElmIHNvLCB3ZSB3aWwgZGVlbSB0aGlzIHN1ZmZpY2llbnQgdG8gZHJhdyBjb25jdWxzaW9ucyBhYm91dCB0aGUgZGlmZmVyZW50IHRyYWluaW5nIG1ldGhvZHMuDQoNCk91ciBwb2xpY3kgd2lsIGJlIGFzIGZvbGxvd3M6IHdlIHdpbGwgaW5zcGVjdCB0aGUgZGF0YSBhZnRlciB3ZSBoYXZlIGFwcHJveC4gMjAgcGFydGljaXBhbnRzIGluIGVhY2ggY29uZGl0aW9uIChOb3RlOiB0aGlzIGlzIGFwcHJveGltYXRlIHNpbmNlIHdlIGFpbSAgdG8gZ2V0IHRoaXMgYnkgdGhlIGVuZCBvZiB0aGUgYWNhZGVtaWMgeWVhcjsgaWYgd2UgZG9uJ3QgcXVpdGUgZ2V0IHRoaXMgbWFueSBjaGlsZHJlbiwgd2Ugd2lsbCBzdGlsbCBsb29rIGF0IHRoZSBzYW1wbGUgd2UgaGF2ZSkuIElmIHJlc3VsdHMgZm9yIGtleSBhbmFsc3llcyBhcmUgaW5jb25jbHVzaXZlLCByZXNvdXJjZXMgcGVybWl0dGluZyB3ZSB3aWxsIGNvbnRpbnVlIHRvIHRlc3QgIG1vcmUgcGFydGljaXBhbnRzLCBjb2xsZWN0aW5nIDEwIHBlciBjb25kaXRpb24gYXQgZWFjaCBzdGVwIGJlZm9yZSBpbnNwZWN0aW5nIHRoZSBkYXRhIGFnYWluIGF0IGVhY2ggc3RlcC4gV2Ugd2lsbCBjb250aW51ZSB1bnRpbCBOIHBlciBjb25kaXRpb24gPTUwLCByZXNvdXJjZXMgcGVybWl0dGluZy4gIA0KICANCkZpbmFsIG5vdGU6IHdlIGhhdmUgZGVzaWduZWQgdGhlIGV4cGVyaW1lbnQgdG8gaGF2ZSBmb3VyIHNlc3Npb25zIGFzIGZvbGxvd3M6DQpzZXNzaW9uMSBwcmUtdGVzdHM6IGRpc2NyaW1pbmF0aW9uIGFuZCAgd29yZHJlcGV0aXRpb24gDQogICAgICAgICB0cmFpbmluZw0Kc2Vzc2lvbjIgdHJhaW5pbmcNCiAgICAgICAgIHBvc3QtdGVzdHM6IGRpc2NyaW1pbmF0aW9uIGFuZCAgd29yZHJlcGV0aXRpb24gDQogICAgICAgICAgICAgICAgICAgICAyQUZDIHBpY3Rlc3QvIDJBRkMgdG9uZXRlc3QNCnNlc3Npb24zIHRyYWluaW5nDQogICAgICAgDQpzZXNzaW9uNCB0cmFpbmluZw0KICAgICAgICAgcG9zdC10ZXN0czogZGlzY3JpbWluYXRpb24gYW5kICB3b3JkcmVwZXRpdGlvbiANCiAgICAgICAgICAgICAgICAgICAgIDJBRkMgcGljdGVzdC8gMkFGQyB0b25ldGVzdA0KICAgICAgICAgICAgICAgICAgICAgDQpGb3Igb3VyIGZpcnN0IGluc3BlY3Rpb24gb2YgdGhlIGRhdGEsIHdlIHdpbGwgY29uZHVjdCBhbmFsc3llcyBib3RoIG9uIGRheTIgZGF0YSBhbmQgZGF5NCBkYXRhIChib3RoIGNvbXBhcmVkIHRvIHJlbGV2YW50IHByZS10ZXN0czsgZm9yIHRyYWluaW5nIGRhdGEgaXRzZWxmLCB3ZSB3aWxsIGxvb2sgYXQgc2Vzc2lvbnMxIGFuZCAyIHZlcnN1cyBzZXNzaW9uIDEsMiwzJjQpLiAgSWYgdXNpbmcgZGF0YSBmcm9tIHNlc3Npb240IGV4dHJhIHR3byBzZXNzaW9ucyBkbyBub3QgYWZmZWN0IHRoZSBrZXkgcGF0dGVybiBvZiByZXN1bHRzLCBnaXZlbiB0aGUgbGFyZ2UgZXhwZW5pdHVyZSBvZiByZXNvdXJjZXMgcGVyIHBhcnRpY2lwYW50LCB3ZSB3aWxsIGRyb3AgdGhlIGZpbmFsIHR3byBzZXNzaW9ucyBmb3Igb25nb2luZyAgcGFydGljaXBhbnQgY29sbGVjdGlvbi4NCg0KTm90ZSB0aGF0IGZyZXF1ZW50aXN0IGFuYWxzeWVzIHdpbGwgbm90IGJlIHZhbGlkIGF0IC4wNSBsZXZlbCwgZHVlIHRvIHN0b3BwaW5nIHByb2JsZW0uIEN1cnJlbnQgcGxhbiBpcyB0byBuZXZlcnRoZWxlc3MgcmVwb3J0IHdpdGggdGhhdCBjYXZlYXQ7IEJGIHdpbGwgYmUgY29uc2lkZXJlZCB0aGUgIGNyaXRpY2FsIGFuYWx5c2VzLikNCg0KRGF0YSB3aWxsIGJlIGNvbGxlY3RlZCBmcm9tIGNoaWxkcmVuIGluIHllYXIgMyAoYWdlZCA3LTgpDQoNCiMgTG9hZCBwYWNrYWdlcyBhbmQgaGVscGVyIGZ1bmN0aW9ucw0KIyMgUGFja2FnZXMNCg0KYGBge3J9DQojIyBQYWNrYWdlcy4gIA0Kcm0obGlzdD1scygpKQ0KI3N1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KHN0cmluZ2Rpc3QpKQ0KI2xpYnJhcnkobGFuZ3VhZ2VSKQ0KbGlicmFyeShsYXR0aWNlKQ0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkobG1lNCkpDQpsaWJyYXJ5KHBsb3RyaXgpDQojc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoaXJyKSkNCmxpYnJhcnkocGx5cikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGdncGxvdDIpCSNmb3IgZ3JhcGhzDQojbGlicmFyeShyZXNoYXBlKQ0KbGlicmFyeShyZXNoYXBlMikNCg0KI2xpYnJhcnkocmVzaGFwZSkNCmxpYnJhcnkocmVzaGFwZTIpDQojbGlicmFyeShyZXNoYXBlKQ0KbGlicmFyeShyZXNoYXBlMikNCiNsaWJyYXJ5KGxtZXJUZXN0KQ0KI2xpYnJhcnkoc2ltcikNCmxpYnJhcnkobHNyKQ0KYGBgDQoNCg0KIyBIZWxwZXIgRnVuY3Rpb25zDQoNCiMjIyBTdW1tYXJ5U0UNCg0KVGhpcyBmdW5jdGlvbiBjYW4gYmUgZm91bmQgb24gdGhlICB3ZWJzaXRlICJDb29rYm9vayBmb3IgUiIuDQoNCmh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vTWFuaXB1bGF0aW5nX2RhdGEvU3VtbWFyaXppbmdfZGF0YS8NCg0KSXQgc3VtbWFyaXplcyBkYXRhLCBnaXZpbmcgY291bnQsIG1lYW4sIHN0YW5kYXJkIGRldmlhdGlvbiwgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4sIGFuZCBjb25maWRlbmNlIGludGVydmFsIChkZWZhdWx0IDk1JSkuDQoNCi0gZGF0YTogYSBkYXRhIGZyYW1lLiANCi0gbWVhc3VyZXZhcjogdGhlIG5hbWUgb2YgYSBjb2x1bW4gdGhhdCBjb250YWlucyB0aGUgdmFyaWFibGUgdG8gYmUgc3VtbWFyaXplZC4NCi0gZ3JvdXB2YXJzOiBhIHZlY3RvciBjb250YWluaW5nIG5hbWVzIG9mIGNvbHVtbnMgdGhhdCBjb250YWluIGdyb3VwaW5nIHZhcmlhYmxlcy4NCi0gbmEucm06IGEgYm9vbGVhbiB0aGF0IGluZGljYXRlcyB3aGV0aGVyIHRvIGlnbm9yZSBOQSdzLg0KLSBjb25mLmludGVydmFsOiB0aGUgcGVyY2VudCByYW5nZSBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCAoZGVmYXVsdCBpcyA5NSUpLg0KDQpgYGB7cn0NCnN1bW1hcnlTRSA8LSBmdW5jdGlvbihkYXRhPU5VTEwsIG1lYXN1cmV2YXIsIGdyb3VwdmFycz1OVUxMLCBuYS5ybT1GQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb25mLmludGVydmFsPS45NSwgLmRyb3A9VFJVRSkgew0KICAgIHJlcXVpcmUocGx5cikNCg0KICAgICMgTmV3IHZlcnNpb24gb2YgbGVuZ3RoIHdoaWNoIGNhbiBoYW5kbGUgTkEnczogaWYgbmEucm09PVQsIGRvbid0IGNvdW50IHRoZW0NCiAgICBsZW5ndGgyIDwtIGZ1bmN0aW9uICh4LCBuYS5ybT1GQUxTRSkgew0KICAgICAgICBpZiAobmEucm0pIHN1bSghaXMubmEoeCkpDQogICAgICAgIGVsc2UgICAgICAgbGVuZ3RoKHgpDQogICAgfQ0KDQogICAgIyBUaGlzIGRvZXMgdGhlIHN1bW1hcnkuIEZvciBlYWNoIGdyb3VwJ3MgZGF0YSBmcmFtZSwgcmV0dXJuIGEgdmVjdG9yIHdpdGgNCiAgICAjIE4sIG1lYW4sIGFuZCBzZA0KICAgIGRhdGFjIDwtIGRkcGx5KGRhdGEsIGdyb3VwdmFycywgLmRyb3A9LmRyb3AsDQogICAgICAuZnVuID0gZnVuY3Rpb24oeHgsIGNvbCkgew0KICAgICAgICBjKE4gICAgPSBsZW5ndGgyKHh4W1tjb2xdXSwgbmEucm09bmEucm0pLA0KICAgICAgICAgIG1lYW4gPSBtZWFuICAgKHh4W1tjb2xdXSwgbmEucm09bmEucm0pLA0KICAgICAgICAgIHNkICAgPSBzZCAgICAgKHh4W1tjb2xdXSwgbmEucm09bmEucm0pDQogICAgICAgICkNCiAgICAgIH0sDQogICAgICBtZWFzdXJldmFyDQogICAgKQ0KDQogICAgIyBSZW5hbWUgdGhlICJtZWFuIiBjb2x1bW4gICAgDQogICAgZGF0YWMgPC0gcmVuYW1lKGRhdGFjLCBjKCJtZWFuIiA9IG1lYXN1cmV2YXIpKQ0KDQogICAgZGF0YWMkc2UgPC0gZGF0YWMkc2QgLyBzcXJ0KGRhdGFjJE4pICAjIENhbGN1bGF0ZSBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVhbg0KDQogICAgIyBDb25maWRlbmNlIGludGVydmFsIG11bHRpcGxpZXIgZm9yIHN0YW5kYXJkIGVycm9yDQogICAgIyBDYWxjdWxhdGUgdC1zdGF0aXN0aWMgZm9yIGNvbmZpZGVuY2UgaW50ZXJ2YWw6IA0KICAgICMgZS5nLiwgaWYgY29uZi5pbnRlcnZhbCBpcyAuOTUsIHVzZSAuOTc1IChhYm92ZS9iZWxvdyksIGFuZCB1c2UgZGY9Ti0xDQogICAgY2lNdWx0IDwtIHF0KGNvbmYuaW50ZXJ2YWwvMiArIC41LCBkYXRhYyROLTEpDQogICAgZGF0YWMkY2kgPC0gZGF0YWMkc2UgKiBjaU11bHQNCg0KICAgIHJldHVybihkYXRhYykNCn0NCmBgYA0KDQojIyMgU3VtbWFyeVNFd2l0aGluDQoNClRoaXMgZnVuY3Rpb24gY2FuIGJlIGZvdW5kIG9uIHRoZSAgd2Vic2l0ZSAiQ29va2Jvb2sgZm9yIFIiLg0KDQpodHRwOi8vd3d3LmNvb2tib29rLXIuY29tL0dyYXBocy9QbG90dGluZ19tZWFuc19hbmRfZXJyb3JfYmFyc18oZ2dwbG90MikvI0hlbHBlciBmdW5jdGlvbnMNCg0KRnJvbSB0aGF0IHdlYnNpdGU6DQoNClN1bW1hcml6ZXMgZGF0YSwgaGFuZGxpbmcgd2l0aGluLXN1YmplY3RzIHZhcmlhYmxlcyBieSByZW1vdmluZyBpbnRlci1zdWJqZWN0IHZhcmlhYmlsaXR5Lg0KSXQgd2lsbCBzdGlsbCB3b3JrIGlmIHRoZXJlIGFyZSBubyB3aXRoaW4tUyB2YXJpYWJsZXMuDQpHaXZlcyBjb3VudCwgdW4tbm9ybWVkIG1lYW4sIG5vcm1lZCBtZWFuICh3aXRoIHNhbWUgYmV0d2Vlbi1ncm91cCBtZWFuKSwNCnN0YW5kYXJkIGRldmlhdGlvbiwgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4sIGFuZCBjb25maWRlbmNlIGludGVydmFsLg0KSWYgdGhlcmUgYXJlIHdpdGhpbi1zdWJqZWN0IHZhcmlhYmxlcywgY2FsY3VsYXRlIGFkanVzdGVkIHZhbHVlcyB1c2luZyBtZXRob2QgZnJvbSBNb3JleSAoMjAwOCkuDQpkYXRhOiBhIGRhdGEgZnJhbWUuDQoNCm1lYXN1cmV2YXI6IHRoZSBuYW1lIG9mIGEgY29sdW1uIHRoYXQgY29udGFpbnMgdGhlIHZhcmlhYmxlIHRvIGJlIHN1bW1hcmllemVkDQpiZXR3ZWVudmFyczogYSB2ZWN0b3IgY29udGFpbmluZyBuYW1lcyBvZiBjb2x1bW5zIHRoYXQgYXJlIGJldHdlZW4tc3ViamVjdHMgdmFyaWFibGVzDQp3aXRoaW52YXJzOiBhIHZlY3RvciBjb250YWluaW5nIG5hbWVzIG9mIGNvbHVtbnMgdGhhdCBhcmUgd2l0aGluLXN1YmplY3RzIHZhcmlhYmxlcw0KaWR2YXI6IHRoZSBuYW1lIG9mIGEgY29sdW1uIHRoYXQgaWRlbnRpZmllcyBlYWNoIHN1YmplY3QgKG9yIG1hdGNoZWQgc3ViamVjdHMpDQpuYS5ybTogYSBib29sZWFuIHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgdG8gaWdub3JlIE5BJ3MNCmNvbmYuaW50ZXJ2YWw6IHRoZSBwZXJjZW50IHJhbmdlIG9mIHRoZSBjb25maWRlbmNlIGludGVydmFsIChkZWZhdWx0IGlzIDk1JSkNCg0KYGBge3J9DQpzdW1tYXJ5U0V3aXRoaW4gPC0gZnVuY3Rpb24oZGF0YT1OVUxMLCBtZWFzdXJldmFyLCBiZXR3ZWVudmFycz1OVUxMLCB3aXRoaW52YXJzPU5VTEwsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWR2YXI9TlVMTCwgbmEucm09RkFMU0UsIGNvbmYuaW50ZXJ2YWw9Ljk1LCAuZHJvcD1UUlVFKSB7DQoNCiAgIyBFbnN1cmUgdGhhdCB0aGUgYmV0d2VlbnZhcnMgYW5kIHdpdGhpbnZhcnMgYXJlIGZhY3RvcnMNCiAgZmFjdG9ydmFycyA8LSB2YXBwbHkoZGF0YVssIGMoYmV0d2VlbnZhcnMsIHdpdGhpbnZhcnMpLCBkcm9wPUZBTFNFXSwNCiAgICBGVU49aXMuZmFjdG9yLCBGVU4uVkFMVUU9bG9naWNhbCgxKSkNCg0KICBpZiAoIWFsbChmYWN0b3J2YXJzKSkgew0KICAgIG5vbmZhY3RvcnZhcnMgPC0gbmFtZXMoZmFjdG9ydmFycylbIWZhY3RvcnZhcnNdDQogICAgbWVzc2FnZSgiQXV0b21hdGljYWxseSBjb252ZXJ0aW5nIHRoZSBmb2xsb3dpbmcgbm9uLWZhY3RvcnMgdG8gZmFjdG9yczogIiwNCiAgICAgICAgICAgIHBhc3RlKG5vbmZhY3RvcnZhcnMsIGNvbGxhcHNlID0gIiwgIikpDQogICAgZGF0YVtub25mYWN0b3J2YXJzXSA8LSBsYXBwbHkoZGF0YVtub25mYWN0b3J2YXJzXSwgZmFjdG9yKQ0KICB9DQoNCiAgIyBHZXQgdGhlIG1lYW5zIGZyb20gdGhlIHVuLW5vcm1lZCBkYXRhDQogIGRhdGFjIDwtIHN1bW1hcnlTRShkYXRhLCBtZWFzdXJldmFyLCBncm91cHZhcnM9YyhiZXR3ZWVudmFycywgd2l0aGludmFycyksDQogICAgICAgICAgICAgICAgICAgICBuYS5ybT1uYS5ybSwgY29uZi5pbnRlcnZhbD1jb25mLmludGVydmFsLCAuZHJvcD0uZHJvcCkNCg0KICAjIERyb3AgYWxsIHRoZSB1bnVzZWQgY29sdW1ucyAodGhlc2Ugd2lsbCBiZSBjYWxjdWxhdGVkIHdpdGggbm9ybWVkIGRhdGEpDQogIGRhdGFjJHNkIDwtIE5VTEwNCiAgZGF0YWMkc2UgPC0gTlVMTA0KICBkYXRhYyRjaSA8LSBOVUxMDQoNCiAgIyBOb3JtIGVhY2ggc3ViamVjdCdzIGRhdGENCiAgbmRhdGEgPC0gbm9ybURhdGFXaXRoaW4oZGF0YSwgaWR2YXIsIG1lYXN1cmV2YXIsIGJldHdlZW52YXJzLCBuYS5ybSwgLmRyb3A9LmRyb3ApDQoNCiAgIyBUaGlzIGlzIHRoZSBuYW1lIG9mIHRoZSBuZXcgY29sdW1uDQogIG1lYXN1cmV2YXJfbiA8LSBwYXN0ZShtZWFzdXJldmFyLCAiX25vcm0iLCBzZXA9IiIpDQoNCiAgIyBDb2xsYXBzZSB0aGUgbm9ybWVkIGRhdGEgLSBub3cgd2UgY2FuIHRyZWF0IGJldHdlZW4gYW5kIHdpdGhpbiB2YXJzIHRoZSBzYW1lDQogIG5kYXRhYyA8LSBzdW1tYXJ5U0UobmRhdGEsIG1lYXN1cmV2YXJfbiwgZ3JvdXB2YXJzPWMoYmV0d2VlbnZhcnMsIHdpdGhpbnZhcnMpLA0KICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPW5hLnJtLCBjb25mLmludGVydmFsPWNvbmYuaW50ZXJ2YWwsIC5kcm9wPS5kcm9wKQ0KDQogICMgQXBwbHkgY29ycmVjdGlvbiBmcm9tIE1vcmV5ICgyMDA4KSB0byB0aGUgc3RhbmRhcmQgZXJyb3IgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWwNCiAgIyAgR2V0IHRoZSBwcm9kdWN0IG9mIHRoZSBudW1iZXIgb2YgY29uZGl0aW9ucyBvZiB3aXRoaW4tUyB2YXJpYWJsZXMNCiAgbldpdGhpbkdyb3VwcyAgICA8LSBwcm9kKHZhcHBseShuZGF0YWNbLHdpdGhpbnZhcnMsIGRyb3A9RkFMU0VdLCBGVU49bmxldmVscywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTi5WQUxVRT1udW1lcmljKDEpKSkNCiAgY29ycmVjdGlvbkZhY3RvciA8LSBzcXJ0KCBuV2l0aGluR3JvdXBzIC8gKG5XaXRoaW5Hcm91cHMtMSkgKQ0KDQogICMgQXBwbHkgdGhlIGNvcnJlY3Rpb24gZmFjdG9yDQogIG5kYXRhYyRzZCA8LSBuZGF0YWMkc2QgKiBjb3JyZWN0aW9uRmFjdG9yDQogIG5kYXRhYyRzZSA8LSBuZGF0YWMkc2UgKiBjb3JyZWN0aW9uRmFjdG9yDQogIG5kYXRhYyRjaSA8LSBuZGF0YWMkY2kgKiBjb3JyZWN0aW9uRmFjdG9yDQoNCiAgIyBDb21iaW5lIHRoZSB1bi1ub3JtZWQgbWVhbnMgd2l0aCB0aGUgbm9ybWVkIHJlc3VsdHMNCiAgbWVyZ2UoZGF0YWMsIG5kYXRhYykNCn0NCmBgYA0KDQojIyMgbm9ybURhdGFXaXRoaW4NCg0KVGhpcyBmdW5jdGlvbiBpcyB1c2VkIGJ5IHRoZSBTdW1tYXJ5U0VXaXRoaW4gZnVjbnRpb24gYWJvdmUuIEl0IGNhbiBiZSBmb3VuZCBvbiB0aGUgIHdlYnNpdGUgIkNvb2tib29rIGZvciBSIi4NCg0KaHR0cDovL3d3dy5jb29rYm9vay1yLmNvbS9HcmFwaHMvUGxvdHRpbmdfbWVhbnNfYW5kX2Vycm9yX2JhcnNfKGdncGxvdDIpLyNIZWxwZXIgZnVuY3Rpb25zDQoNCkZyb20gdGhhdCB3ZWJzaXRlOg0KDQpOb3JtcyB0aGUgZGF0YSB3aXRoaW4gc3BlY2lmaWVkIGdyb3VwcyBpbiBhIGRhdGEgZnJhbWU7IGl0IG5vcm1hbGl6ZXMgZWFjaA0Kc3ViamVjdCAoaWRlbnRpZmllZCBieSBpZHZhcikgc28gdGhhdCB0aGV5IGhhdmUgdGhlIHNhbWUgbWVhbiwgd2l0aGluIGVhY2ggZ3JvdXANCnNwZWNpZmllZCBieSBiZXR3ZWVudmFycy4NCmRhdGE6IGEgZGF0YSBmcmFtZS4NCmlkdmFyOiB0aGUgbmFtZSBvZiBhIGNvbHVtbiB0aGF0IGlkZW50aWZpZXMgZWFjaCBzdWJqZWN0IChvciBtYXRjaGVkIHN1YmplY3RzKQ0KbWVhc3VyZXZhcjogdGhlIG5hbWUgb2YgYSBjb2x1bW4gdGhhdCBjb250YWlucyB0aGUgdmFyaWFibGUgdG8gYmUgc3VtbWFyaWV6ZWQNCmJldHdlZW52YXJzOiBhIHZlY3RvciBjb250YWluaW5nIG5hbWVzIG9mIGNvbHVtbnMgdGhhdCBhcmUgYmV0d2Vlbi1zdWJqZWN0cyB2YXJpYWJsZXMNCm5hLnJtOiBhIGJvb2xlYW4gdGhhdCBpbmRpY2F0ZXMgd2hldGhlciB0byBpZ25vcmUgTkEncw0KDQoNCmBgYHtyfQ0Kbm9ybURhdGFXaXRoaW4gPC0gZnVuY3Rpb24oZGF0YT1OVUxMLCBpZHZhciwgbWVhc3VyZXZhciwgYmV0d2VlbnZhcnM9TlVMTCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPUZBTFNFLCAuZHJvcD1UUlVFKSB7DQogICAgI2xpYnJhcnkocGx5cikNCg0KICAgICMgTWVhc3VyZSB2YXIgb24gbGVmdCwgaWR2YXIgKyBiZXR3ZWVuIHZhcnMgb24gcmlnaHQgb2YgZm9ybXVsYS4NCiAgICBkYXRhLnN1YmpNZWFuIDwtIGRkcGx5KGRhdGEsIGMoaWR2YXIsIGJldHdlZW52YXJzKSwgLmRyb3A9LmRyb3AsDQogICAgIC5mdW4gPSBmdW5jdGlvbih4eCwgY29sLCBuYS5ybSkgew0KICAgICAgICBjKHN1YmpNZWFuID0gbWVhbih4eFssY29sXSwgbmEucm09bmEucm0pKQ0KICAgICAgfSwNCiAgICAgIG1lYXN1cmV2YXIsDQogICAgICBuYS5ybQ0KICAgICkNCg0KICAgICMgUHV0IHRoZSBzdWJqZWN0IG1lYW5zIHdpdGggb3JpZ2luYWwgZGF0YQ0KICAgIGRhdGEgPC0gbWVyZ2UoZGF0YSwgZGF0YS5zdWJqTWVhbikNCg0KICAgICMgR2V0IHRoZSBub3JtYWxpemVkIGRhdGEgaW4gYSBuZXcgY29sdW1uDQogICAgbWVhc3VyZU5vcm1lZFZhciA8LSBwYXN0ZShtZWFzdXJldmFyLCAiX25vcm0iLCBzZXA9IiIpDQogICAgZGF0YVssbWVhc3VyZU5vcm1lZFZhcl0gPC0gZGF0YVssbWVhc3VyZXZhcl0gLSBkYXRhWywic3Viak1lYW4iXSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbihkYXRhWyxtZWFzdXJldmFyXSwgbmEucm09bmEucm0pDQoNCiAgICAjIFJlbW92ZSB0aGlzIHN1YmplY3QgbWVhbiBjb2x1bW4NCiAgICBkYXRhJHN1YmpNZWFuIDwtIE5VTEwNCg0KICAgIHJldHVybihkYXRhKQ0KfQ0KDQpgYGANCg0KDQojIyMgbXlDZW50ZXINCg0KVGhpcyBmdW5jdGlvbiBvdXB1dHMgdGhlIGNlbnRlcmVkIHZhbHVlcyBvZiBhbiB2YXJpYWJsZSwgd2hpY2ggY2FuIGJlIGEgbnVtZXJpYyB2YXJpYWJsZSwgYSBmYWN0b3IsIG9yIGEgZGF0YSBmcmFtZS4gSXQgd2FzIHRha2VuIGZyb20gRmxvcmlhbiBKYWVnZXJzIGJsb2cgDQoNCmh0dHBzOi8vaGxwbGFiLndvcmRwcmVzcy5jb20vMjAwOS8wNC8yNy9jZW50ZXJpbmctc2V2ZXJhbC12YXJpYWJsZXMvLg0KDQpGcm9tIGhpcyBibG9nOg0KDQotIElmIHRoZSBpbnB1dCBpcyBhIG51bWVyaWMgdmFyaWFibGUsIHRoZSBvdXRwdXQgaXMgdGhlIGNlbnRlcmVkIHZhcmlhYmxlLg0KDQotIElmIHRoZSBpbnB1dCBpcyBhIGZhY3RvciwgdGhlIG91dHB1dCBpcyBhIG51bWVyaWMgdmFyaWFibGUgd2l0aCBjZW50ZXJlZCBmYWN0b3IgbGV2ZWwgdmFsdWVzLiBUaGF0IGlzLCB0aGUgZmFjdG9yJ3MgbGV2ZWxzIGFyZSBjb252ZXJ0ZWQgaW50byBudW1lcmljYWwgdmFsdWVzIGluIHRoZWlyIGluaGVyZW50IG9yZGVyIChpZiBub3Qgc3BlY2lmaWVkIG90aGVyd2lzZSwgIFIgZGVmYXVsdHMgdG8gYWxwaGFudW1lcmljYWwgb3JkZXIpLiBNb3JlIHNwZWNpZmljYWxseSwgdGhpcyBjZW50ZXJzIGFueSBiaW5hcnkgZmFjdG9yIHNvIHRoYXQgdGhlIHZhbHVlIGJlbG93IDAgd2lsbCBiZSB0aGUgMXN0IGxldmVsIG9mIHRoZSBvcmlnaW5hbCBmYWN0b3IsIGFuZCB0aGUgdmFsdWUgYWJvdmUgMCB3aWxsIGJlIHRoZSAybmQgbGV2ZWwuDQoNCi0gSWYgdGhlIGlucHV0IGlzIGEgZGF0YSBmcmFtZSBvciBtYXRyaXgsIHRoZSBvdXRwdXQgaXMgYSBuZXcgbWF0cml4IG9mIHRoZSBzYW1lIGRpbWVuc2lvbiBhbmQgd2l0aCB0aGUgY2VudGVyZWQgdmFsdWVzIGFuZCBjb2x1bW4gbmFtZXMgdGhhdCBjb3JyZXNwb25kIHRvIHRoZSBjb2xuYW1lcygpIG9mIHRoZSBpbnB1dCBwcmVjZWRlZCBieSAiYyIgKGUuZy4gIlZhcmlhYmxlMSIgd2lsbCBiZSAiY1ZhcmlhYmxlMSIpLg0KDQpgYGB7cn0NCm15Q2VudGVyPSBmdW5jdGlvbih4KSB7DQogIGlmIChpcy5udW1lcmljKHgpKSB7IHJldHVybih4IC0gbWVhbih4LCBuYS5ybT1UKSkgfQ0KCWlmIChpcy5mYWN0b3IoeCkpIHsNCgkJeD0gYXMubnVtZXJpYyh4KQ0KCQlyZXR1cm4oeCAtIG1lYW4oeCwgbmEucm09VCkpDQoJfQ0KCWlmIChpcy5kYXRhLmZyYW1lKHgpIHx8IGlzLm1hdHJpeCh4KSkgew0KCQltPSBtYXRyaXgobnJvdz1ucm93KHgpLCBuY29sPW5jb2woeCkpDQoJCWNvbG5hbWVzKG0pPSBwYXN0ZSgiYyIsIGNvbG5hbWVzKHgpLCBzZXA9IiIpDQoJDQoJCWZvciAoaSBpbiAxOm5jb2woeCkpIHsNCgkJDQoJCQltWyxpXT0gbXlDZW50ZXIoeFssaV0pDQoJCX0NCgkJcmV0dXJuKGFzLmRhdGEuZnJhbWUobSkpDQoJfQ0KfQ0KYGBgDQoNCiMjIyBsaXpDZW50ZXINCg0KVGhpcyBmdW5jdGlvbiBwcm92aWRlcyBhIHdyYXBwZXIgYXJvdW5kIG15Q2VudGVyIGFsbG93aW5nIHlvdSB0byBjZW50ZXIgYSBzcGVjaWZpYyBsaXN0IG9mIHZhcmlhYmxlcyBmcm9tIGEgZGF0YWZyYW1lLiANCg0KLSB4OiBkYXRhIGZyYW1lDQotIGxpc3RmbmFtZTogYSBsaXN0IG9mIHRoZSB2YXJpYWJsZXMgdG8gYmUgY2VudGVyZWQgKGUuZy4gbGlzdCh2YXJpYWJsZTEsdmFyaWFibGUyKSkNCg0KVGhlIG91dHB1dCBpcyBhIGNvcHkgb2YgdGhlIGRhdGEgZnJhbWUgd2l0aCBhIGNvbHVtbiAoYWx3YXlzIGEgbnVtZXJpYyB2YXJpYWJsZSkgYWRkZWQgZm9yIGVhY2ggb2YgdGhlIGNlbnRlcmVkIHZhcmlhYmxlcy4gVGhlc2UgY29sdW1ucyBhcmUgbGFiZWxsZWQgd2l0aCB0aGUgZWFjaCBjb2x1bW4ncyBwcmV2aW91cyBuYW1lLCBidXQgd2l0aCAiLmN0IiBhcHBlbmRlZCAoZS5nLiwgInZhcmlhYmxlMSIgd2lsbCBiZWNvbWUgInZhcmlhYmxlMS5jdCIpLg0KDQoNCmBgYHtyfQ0KbGl6Q2VudGVyPSBmdW5jdGlvbih4LCBsaXN0Zm5hbWUpIA0Kew0KCWZvciAoaSBpbiAxOmxlbmd0aChsaXN0Zm5hbWUpKSANCgl7DQoJCWZuYW1lID0gYXMuY2hhcmFjdGVyKGxpc3RmbmFtZVtpXSkNCgkJeFtwYXN0ZShmbmFtZSwiLmN0Iiwgc2VwPSIiKV0gPSBteUNlbnRlcih4W2ZuYW1lXSkNCgl9DQoJCQ0KCXJldHVybih4KQ0KfQ0KYGBgCQ0KDQoNCiAgDQoNCiMjIyBnZXRfY29lZmZzDQoNClRoaXMgZnVuY3Rpb24gYWxsb3dzIHVzIHRvIGluc3BlY3QgcGFydGljdWxhciBjb2VmZmljaWVudHMgZnJvbSB0aGUgb3V0cHV0IG9mIGFuIGxtZSBtb2RlbCBieSBwdXR0aW5nIHRoZW0gaW4gdGFibGUuDQoNCi0geDogdGhlIG91dHB1dCByZXR1cm5lZCB3aGVuIHJ1bm5pbmcgbG1lciBvciBnbG1lciAoaS5lLiBhbiBvYmpldCBvZiB0eXBlIGxtZXJNb2Qgb3IgZ2xtZXJNb2QpDQotIGxpc3Q6IGEgbGlzdCBvZiBuYW1lcyBvZiB0aGUgY29lZmZpY2llbnRzIHRvIGJlIGV4dHJhY3RlZCAoZS5nLiBjKCJ2YXJpYWJsZTEiLCJ2YXJpYWJsZTE6dmFyaWFibGUyIikpDQoNCmBgYHtyfQ0KI2dldF9jb2VmZnMgPC0gZnVuY3Rpb24oeCxsaXN0KXsoa2FibGUoYXMuZGF0YS5mcmFtZShzdW1tYXJ5KHgpJGNvZWZmaWNpZW50cylbbGlzdCxdLGRpZ2l0cz0zKSl9DQpnZXRfY29lZmZzIDwtIGZ1bmN0aW9uKHgsbGlzdCl7KGFzLmRhdGEuZnJhbWUoc3VtbWFyeSh4KSRjb2VmZmljaWVudHMpW2xpc3QsXSl9DQpgYGAgIA0KDQojIyMgQmYNCg0KVGhpcyBmdW5jdGlvbiBpcyBlcXVpdmFsZW50IHRvIHRoZSBEaWVuZXMgKDIwMDgpIGNhbGN1bGF0b3Igd2hpY2ggY2FuIGJlIGZvdW5kIGhlcmU6IGh0dHA6Ly93d3cubGlmZXNjaS5zdXNzZXguYWMudWsvaG9tZS9ab2x0YW5fRGllbmVzL2luZmVyZW5jZS9CYXllcy5odG0uDQoNClRoZSBjb2RlIHdhcyBwcm92aWRlZCBieSBCYWd1ZWx5IGFuZCBLYXluZSAoMjAxMCkgYW5kIGNhbiBiZSBmb3VuZCBoZXJlOiBodHRwOi8vd3d3LmFjYWRlbWlhLmVkdS80MjcyODgvUmV2aWV3X29mX1VuZGVyc3RhbmRpbmdfcHN5Y2hvbG9neV9hc19hX3NjaWVuY2VfQW5faW50cm9kdWN0aW9uX3RvX3NjaWVudGlmaWNfYW5kX3N0YXRpc3RpY2FsX2luZmVyZW5jZQ0KDQpgYGB7cn0NCkJmPC1mdW5jdGlvbihzZCwgb2J0YWluZWQsIHVuaWZvcm0sIGxvd2VyPTAsIHVwcGVyPTEsIG1lYW5vZnRoZW9yeT0wLHNkdGhlb3J5PTEsIHRhaWw9Mil7DQogYXJlYSA8LSAwDQogaWYoaWRlbnRpY2FsKHVuaWZvcm0sIDEpKXsNCiAgdGhldGEgPC0gbG93ZXINCiAgcmFuZ2UgPC0gdXBwZXIgLSBsb3dlcg0KICBpbmNyIDwtIHJhbmdlIC8gMjAwMA0KICBmb3IgKEEgaW4gLTEwMDA6MTAwMCl7DQogICAgIHRoZXRhIDwtIHRoZXRhICsgaW5jcg0KICAgICBkaXN0X3RoZXRhIDwtIDEgLyByYW5nZQ0KICAgICBoZWlnaHQgPC0gZGlzdF90aGV0YSAqIGRub3JtKG9idGFpbmVkLCB0aGV0YSwgc2QpDQogICAgIGFyZWEgPC0gYXJlYSArIGhlaWdodCAqIGluY3INCiAgfQ0KIH1lbHNlDQogICB7dGhldGEgPC0gbWVhbm9mdGhlb3J5IC0gNSAqIHNkdGhlb3J5DQogICAgaW5jciA8LSBzZHRoZW9yeSAvIDIwMA0KICAgIGZvciAoQSBpbiAtMTAwMDoxMDAwKXsNCiAgICAgIHRoZXRhIDwtIHRoZXRhICsgaW5jcg0KICAgICAgZGlzdF90aGV0YSA8LSBkbm9ybSh0aGV0YSwgbWVhbm9mdGhlb3J5LCBzZHRoZW9yeSkNCiAgICAgIGlmKGlkZW50aWNhbCh0YWlsLCAxKSl7DQogICAgICAgIGlmICh0aGV0YSA8PSAwKXsNCiAgICAgICAgICBkaXN0X3RoZXRhIDwtIDANCiAgICAgICAgfSBlbHNlIHsNCiAgICAgICAgICBkaXN0X3RoZXRhIDwtIGRpc3RfdGhldGEgKiAyDQogICAgICAgIH0NCiAgICAgIH0NCiAgICAgIGhlaWdodCA8LSBkaXN0X3RoZXRhICogZG5vcm0ob2J0YWluZWQsIHRoZXRhLCBzZCkNCiAgICAgIGFyZWEgPC0gYXJlYSArIGhlaWdodCAqIGluY3INCiAgICB9DQogfQ0KIExpa2VsaWhvb2RUaGVvcnkgPC0gYXJlYQ0KIExpa2VsaWhvb2RudWxsIDwtIGRub3JtKG9idGFpbmVkLCAwLCBzZCkNCiBCYXllc0ZhY3RvciA8LSBMaWtlbGlob29kVGhlb3J5IC8gTGlrZWxpaG9vZG51bGwNCiByZXQgPC0gbGlzdCgiTGlrZWxpaG9vZFRoZW9yeSIgPSBMaWtlbGlob29kVGhlb3J5LCJMaWtlbGlob29kbnVsbCIgPSBMaWtlbGlob29kbnVsbCwgIkJheWVzRmFjdG9yIiA9IEJheWVzRmFjdG9yKQ0KIHJldA0KfSANCmBgYA0KDQojIyMgQmZfcG93ZXJjYWxjDQoNClRoaXMgd29ya3Mgd2l0aCB0aGUgQmYgZnVuY2l0b24gYWJvdmUuIEl0IHJlcXVpcmVzIHRoZSBzYW1lIHZhbHVlcyBhcyB0aGF0IGZ1bmN0aW9uIChpLmUuIHRoZSBvYnRhaW5lZCBtZWFuIGFuZCBTRSBmb3IgdGhlIGN1cnJlbnQgc2FtcGxlLCBhIHZhbHVlIGZvciB0aGUgcHJlZGljdGVkIG1lYW4sIHdoaWNoIGlzIHNldCB0byBiZSBzZHRoZW9yeSAod2l0aCBtZWFub2Z0aGVvcnk9MCksIGFuZCB0aGUgY3VycmVudCBudW1iZXIgb2YgcGFydGljaXBhbnRzIE4pLiBIb3dldmVyIHJhdGhlciB0aGFuIHJldHVybiBhIEJGIGZvciB0aGUgY3VycmVudCBzYW1wbGUsIGl0IHdvcmtzIG91dCB3aGF0IHRoZSBCRiB3b3VsZCBiZSBmb3IgYSByYW5nZSBvZiBkaWZmZXJlbnQgc3ViamVjdCBudW1iZXJzIChhc3N1bWluZyB0aGF0IHRoZSBTRSBzY2FsZXMgd2l0aCBzcXJ0KE4pKSwgDQoNCmBgYHtyfQ0KQmZfcG93ZXJjYWxjPC1mdW5jdGlvbihzZCwgb2J0YWluZWQsIHVuaWZvcm0sIGxvd2VyPTAsIHVwcGVyPTEsIG1lYW5vZnRoZW9yeT0wLCBzZHRoZW9yeT0xLCB0YWlsPTIsIE4sIG1pbiwgbWF4KQ0Kew0KIA0KIHggPSBjKDApDQogeSA9IGMoMCkNCiAgICMgbm90ZTogd29ya2luZyBvdXQgd2hhdCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIE4gYW5kIGRmIGlzIChmb3IgdGhlIGNvbnRyYXN0IGJldHdlZW4gdHdvIGdyb3VwcywgdGhpcyBpcyAyOyBmb3IgY29uc3RyYWludHMgd2hlcmUgdGhlcmUgaXMgNCBncm91cHMgdGhpcyB3aWxsIGJlIDMsIGV0Yy4pICANCg0KIGZvcihuZXdOIGluIG1pbiA6IG1heCkNCiB7DQogIEIgPSBhcy5udW1lcmljKEJmKHNkID0gc2Qqc3FydChOL25ld04pLCBvYnRhaW5lZCwgdW5pZm9ybSwgbG93ZXIsIHVwcGVyLCBtZWFub2Z0aGVvcnksIHNkdGhlb3J5LCB0YWlsKVszXSkNCiAgeD0gYXBwZW5kKHgsbmV3TikgIA0KICB5PSBhcHBlbmQoeSxCKQ0KICBvdXRwdXQgPSBjYmluZCh4LHkpDQogIA0KIH0gDQogb3V0cHV0ID0gb3V0cHV0Wy0xLF0gDQogcmV0dXJuKG91dHB1dCkgDQp9DQpgYGANCg0KDQoNCg0KDQoNCiMgVHJhaW5pbmcNCg0KRFY6IEVhY2ggdHJhaW5pbmcgdHJpYWwgcHJvZHVjZXMgYSBkYXRhIHBvaW50IChkaWQgdGhleSBwaWNrIHRoZSBjb3JyZWN0IHBpY3R1cmUgLSAxLzA7IG5vdGUgdGhleSBnZXQgZmVlZGJhY2sgb24gdGhpcykgDQoNCiMjIGxvYWQgdXAgYW5kIHJ1biBsbWVzIG9uIHJlbGV2YW50IHBpbG90IGRhdGENCg0KVGhlIGNoaWxkIGRhdGEgYmVsb3cgY29tZSBmcm9tIGEgdHdvIHNlc3Npb24gc3R1ZHkgd2hlcmUgdGhleSB3ZXJlIHRyYWluZWQgb24gc3RpbXVsaSBzaW1pbGFyIHRvIHRoZSAicGljdHVyZS1vbmx5IiBjb25kaXRpb24gaW4gdGhlIGN1cnJlbnQgc3R1ZHkuDQpXZSBoYXZlIGRhdGEgZnJvbSBib3RoIDcgeWVhciBvbGRzIGFuZCAxMSB5ZWFyIG9sZHM7IHRoZSAxMSB5ZWFyIG9sZCBkYXRhIGhlcmUgYXJlIHJlbGV2YW50IGluIHByb3ZpZGluZyBhbiBlc3RpbWF0ZSB0aGF0IGNhbiBiZSB1c2VkIHRvIGluZm9ybSBIMSBpbiBvdXIgQkYgZXhhbXBsZSBhbmFseXNlcy4NCg0KVGhlIGFkdWx0ICBkYXRhIGJlbG93IGNvbWUgZnJvbSBhIHR3byBzZXNzaW9uIHN0dWR5IHdoZXJlIHRoZXJlIHdlcmUgdHdvIGNvbmRpdGlvbnM6ICgxKSB0cmFpbmVkIG9uIHN0aW11bGkgc2ltaWxhciB0byB0aGUgInBpY3R1cmUtb25seSIgY29uZGl0aW9uIGluIHRoZSBjdXJyZW50IHN0dWR5ICgyKSB0cmFpbmVkIG9uIHBpY3R1cmVzIEpVU1Qgb2YgdGhlIGRpYWNyaXRpY3MuIFRoaXMgaXMgdXNlZnVsIGZvciBjb25zaWRlcmluZyBwb3NzaWJsZSBlZmZlY3RzIG9mIGNvbmRpdGlvbiBpbiB0aGUgZGF0YSAodGhvdWdoIHdpdGggdGhlIGNhdmVhdCB0aGF0IGNvbXBhcmlzb24gaXMgc29tZXdoYXQgZGlmZmVyZW50KS4NCg0KTm90ZTogdG9uZWNvbnRyYXN0IGlzIGZpeGVkIGVmZmVjdCB3aXRoIDYgbGV2ZWxzIChzaXggcG9zc2libGUgY29udHJhc3RzKS4gSXQgaXMgZXhwZWN0ZWQgdG8gY29udHJpYnV0ZSB0byBtb2RlbCBhbmQgaXMgdGh1cyBpbmNsdWRlZCBidXQgaXNuJ3Qgb2Ygc3BlY2lmaWMgaW50ZXJlc3QuDQoNCmBgYHtyfQ0KY2hpbGQudHJhaW4gPSByZWFkLmNzdigia2lkc3RyYWluX2NsZWFuLmNzdiIpDQphZHVsdC50cmFpbiA9IHJlYWQuY3N2ICgiYWR1bHRzdHJhaW5fY2xlYW4uY3N2IikNCmNoaWxkLnRyYWluJGFnZWdyb3VwID0gcmVsZXZlbChjaGlsZC50cmFpbiRhZ2Vncm91cCwgcmVmPSI3eWVhcnMiKQ0KYWR1bHQudHJhaW4kY29uZGl0aW9uID0gcmVsZXZlbChhZHVsdC50cmFpbiRjb25kaXRpb24sIHJlZj0iaSIpDQpgYGANCg0KYGBge3J9DQoNCmNoaWxkLnRyYWluLjcgPSBzdWJzZXQoY2hpbGQudHJhaW4sIGFnZWdyb3VwID09ICI3eWVhcnMiKQ0KY2hpbGQudHJhaW4uNyA8LSBsaXpDZW50ZXIoY2hpbGQudHJhaW4uNywgbGlzdCgic2Vzc2lvbiIsICJ0b25lY29udHJhc3QiKSkNCg0KY2hpbGQudHJhaW4uNy5tb2QgID0gZ2xtZXIgKHJlc3VsdCB+DQogICAgICAgICAgICAgICAgKyBzZXNzaW9uLmN0IA0KICAgICAgICAgICAgICAgICsgdG9uZWNvbnRyYXN0LmN0DQogICAgICAgICAgICAgICAgKyAoc2Vzc2lvbi5jdHxzdWJqZWN0KSwNCiAgICAgICAgICAgICAgICBkYXRhID0gY2hpbGQudHJhaW4uNywgIGZhbWlseSA9IGJpbm9taWFsLCBjb250cm9sPWdsbWVyQ29udHJvbChvcHRpbWl6ZXIgPSAiYm9ieXFhIikpDQoNCg0Kcm91bmQoc3VtbWFyeShjaGlsZC50cmFpbi43Lm1vZCkkY29lZmZpY2llbnRzLDMpDQpgYGANCg0KDQpgYGB7cn0NCg0KY2hpbGQudHJhaW4uMTEgPSBzdWJzZXQoY2hpbGQudHJhaW4sIGFnZWdyb3VwID09ICIxMXllYXJzIikNCmNoaWxkLnRyYWluLjExIDwtIGxpekNlbnRlcihjaGlsZC50cmFpbi4xMSwgbGlzdCgic2Vzc2lvbiIsICJ0b25lY29udHJhc3QiKSkNCg0KY2hpbGQudHJhaW4uMTEubW9kICA9IGdsbWVyIChyZXN1bHQgfg0KICAgICAgICAgICAgICAgICsgc2Vzc2lvbi5jdCANCiAgICAgICAgICAgICAgICArIHRvbmVjb250cmFzdC5jdA0KICAgICAgICAgICAgICAgICsgKHNlc3Npb24uY3R8c3ViamVjdCksDQogICAgICAgICAgICAgICAgZGF0YSA9IGNoaWxkLnRyYWluLjExLCAgZmFtaWx5ID0gYmlub21pYWwsIGNvbnRyb2w9Z2xtZXJDb250cm9sKG9wdGltaXplciA9ICJib2J5cWEiKSkNCg0KDQpyb3VuZChzdW1tYXJ5KGNoaWxkLnRyYWluLjExLm1vZCkkY29lZmZpY2llbnRzLDMpDQpgYGANCg0KDQpgYGB7cn0NCg0KYWR1bHQudHJhaW4gPC0gbGl6Q2VudGVyKGFkdWx0LnRyYWluLCBsaXN0KCJzZXNzaW9uIiwgInRvbmVjb250cmFzdCIsImNvbmRpdGlvbiIpKQ0KDQphZHVsdC50cmFpbi5tb2QgID0gZ2xtZXIgKHJlc3VsdCB+DQogICAgICAgICAgICAgICAgKyBzZXNzaW9uLmN0ICpjb25kaXRpb24uY3QNCiAgICAgICAgICAgICAgICArIHRvbmVjb250cmFzdC5jdA0KICAgICAgICAgICAgICAgICsgKHNlc3Npb24uY3R8c3ViamVjdCksDQogICAgICAgICAgICAgICAgZGF0YSA9IGFkdWx0LnRyYWluLCAgZmFtaWx5ID0gYmlub21pYWwsIGNvbnRyb2w9Z2xtZXJDb250cm9sKG9wdGltaXplciA9ICJib2J5cWEiKSkNCg0KDQpyb3VuZChzdW1tYXJ5KGFkdWx0LnRyYWluLm1vZCkkY29lZmZpY2llbnRzLDMpDQpgYGANCg0KIyMgUHJlZGljdGlvbjE6IENoaWxkcmVuIHdpbGwgc2hvdyBvdmVyYWxsIGFib3ZlIGNoYW5jZSBwZXJmb3JtYW5jZSBhY3Jvc3MgdHJhaW5pbmcgaW4gYm90aCBjb25kaXRpb24xIGFuZCBjb25kaXRpb24yDQojIyMgQmFzZWQgb246IA0KDQpXZSBzYXcgdGhpcyBpbiB0aGUgcGlsb3QgZGF0YSBmcm9tIHNldmVuIHllYXIgb2xkcyBhYm92ZSwgd2hpY2ggd2FzIGluIGEgY29uZGl0aW9uIGxpa2UgdGhlIHBpY3R1cmVzLW9ubHkgY29uZGl0aW9uLg0KVGhlIHBpY3R1cmVzK3RvbmVzIGNvbmRpdGlvbiBjb250YWlucyB0aGUgc2FtZSBpbmZvcm1hdGlvbiAocGx1cyBzb21lIGFkZGl0aW9uYWwpIHNvIHdlIHByZWRpY3QgKGF0IGxlYXN0IC0gc2VlIGJlbG93KSBhYm92ZSBjaGFuY2UgaGVyZSB0b28uIA0KDQptZWFuOiBgciBwYXN0ZShyb3VuZChtZWFuKGNoaWxkLnRyYWluLjckcmVzdWx0KSwzKSAqMTAwLCAiJSIsIHNlcD0iIilgOw0KbG9nIG9kZHMgKGJldGEgZnJvbSBsbWUpOiBgciBzdW1tYXJ5KGNoaWxkLnRyYWluLjcubW9kKSRjb2VmZmljaWVudHNbIihJbnRlcmNlcHQpIiAsIkVzdGltYXRlIl1gOw0Kb2RkcyAgKGV4cChiZXRhKSk6YHIgZXhwKHN1bW1hcnkoY2hpbGQudHJhaW4uNy5tb2QpJGNvZWZmaWNpZW50c1siKEludGVyY2VwdCkiICwiRXN0aW1hdGUiXSlgOw0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogRnJlcXVlbnRpc3QgDQoNCmxtZSBtb2RlbCBzaW1pbGFyIHRvIHRoYXQgb24gcGlsb3QgZGF0YSBhYm92ZSBidXQgd2l0aCBkYXRhIGZyb20gYm90aCBjb25kaXRpb25zOyBGaXQgc2VwYXJhdGUgaW50ZXJjZXB0cyBmb3IgZWFjaCBjb25kaXRpb24gYW5kIGNvbXBhcmUgZWFjaCB0byBjaGFuY2UgPSA1MCAoaS5lLmRlZmF1bHQgdmFsdWUgcmV0dXJuZWQpLiBOb3RlIHRoYXQgc2luY2UgYWxsIHByZWRpY3RvcnMgYXJlIGNlbnRlcmVkIGludGVyY2VwdCByZWxmZWN0cyBvdmVyYWxsIGF2ZXJhZ2UgKHJhdGhlciB0aGFuIGF0IGJhc2VsZXZlbHMgb2YgYSBmYWN0b3IpLiANCg0KV2Ugd2lsbCBkbyB0aGlzIGJvdGggZm9yIGEgbW9kZWwgd2l0aCBqdXN0IGZpcnN0IHR3byBzZXNzaW9ucyBhbmQgZm9yIGEgbW9kZWwgd2l0aCBhbGwgZGF0YSAod2l0aCBzZXNzaW9uIHRoZW4gaGF2aW5nIGZvdXIgcG9zc2libGUgdmFsdWVzIGFuZCBjb2RlZCBhcyBjZW50ZXJlZCBudW1lcmljYWwgZmFjdG9yKS4NCg0KIyMjIFBsYW5uZWQgQW5hbHlzZXM6IEJGIA0KDQpTdW1tYXJ5IG9mIGRhdGEgZm9yIGVhY2ggY29uZGl0aW9uOiBtZWFuIGFuZCBzZSBmb3IgaW50ZXJlY3B0IGZyb20gbG1lOw0KdmFsdWUgdG8gaW5mb3JtIEgxOiBlc3RpbWF0ZSBmcm9tIGFib3ZlIHBpbG90IGRhdGEgZm9yIHNldmVuIHllYXIgb2xkcyAgYHIgc3VtbWFyeShjaGlsZC50cmFpbi43Lm1vZCkkY29lZmZpY2llbnRzWyJzZXNzaW9uLmN0IiAsIkVzdGltYXRlIl1gDQoNCk5PVEU6IElmIChlLmcuKSB3ZSBmaW5kIGFuIGVmZmVjdCBmb3IgY29uZGl0aW9uMSwgd2UgY2FuIGFsc28gdXNlIHRoZSBlc3RpbWF0ZSBmb3IgaW50ZXJjZXB0IGZvciB0aGF0IHRvIGluZm9ybSBIMSB3aGVuIGxvb2tpbmcgYXQgZGF0YSBmcm9tIGNvbmRpdGlvbjI7IGFuZCB2aWNlIHZlcnNhLiBUaGlzIGlzIGEgYmV0dGVyIGVzdGltYXRlIHNpbmNlIHRoZSBjb25kaXRpb25zIGFyZSBtb3JlIGNsb3NlbHkgbWF0Y2hlZCB0byBlYWNoIG90aGVyIHRoYW4gZWl0aGVyIGlzIHRvIHRoZSBwaWxvdCBkYXRhLw0KDQojIyMgUmVxdWlyZWQgc2FtcGxlIGFuYWx5c2VzDQojIyMjIEZyZXF1ZW50aXN0cyBwb3dlcg0KDQpMb29rIGF0IHNhbXBsZSByZXF1aXJlZCB0byBvYnRhaW4gZGlmZmVyZW50IGxldmVscyBvZiBwb3dlciB3aXRoIHBpbG90IGRhdGEgd2l0aCA3IHllYXIgb2xkczogDQoNCg0KYGBge3J9DQpkYXRhUz1hcy5udW1lcmljKHdpdGgoZHJvcGxldmVscyhjaGlsZC50cmFpbi43KSwgdGFwcGx5KHJlc3VsdCxsaXN0KHN1YmplY3QpLCBtZWFuLCBuYS5ybT1UKSkpDQpkPSBjb2hlbnNEKHggPSBkYXRhUywgbXU9MC41KQ0KDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuOSwgIHR5cGUgPSBjKCJvbmUuc2FtcGxlIiksIGFsdGVybmF0aXZlID0gYyggImdyZWF0ZXIiKSkNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC44LCAgdHlwZSA9IGMoIm9uZS5zYW1wbGUiKSwgYWx0ZXJuYXRpdmUgPSBjKCAiZ3JlYXRlciIpKQ0KcHdyLnQudGVzdChuID0gTlVMTCwgZCA9IGQsIHNpZy5sZXZlbCA9IDAuMDUsIHBvd2VyID0gLjcsICB0eXBlID0gYygib25lLnNhbXBsZSIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQpybShkYXRhUykNCnJtKGQpDQpgYGANCg0KDQoNCiMjIyMgUmVxdWlyZWQgc2FtcGxlIGZvciBCRiBhbmFseXNlczogDQoNCkhlcmUsIHdlIGxvb2sgYXQgdGhlIHBpbG90IGRhdGEgZnJvbSBzZXZlbiB5ZWFyIG9sZHMsIHVzaW5nIEgxIGluZm9ybWVkIGJ5IGVzdGltYXRlIGZvciAxMSB5ZWFyIG9sZHMuIEluIG91ciBhY3R1YWwgYW5hbHN5ZXMgd2l0aCBuZXcgZGF0YSBmb3IgNyB5ZWFyIG9sZHMgd2lsbCBiZSB1c2luZyBlc3RpbWF0ZSBmcm9tIGN1cnJlbnQgcGlsb3QgZGF0YSB3aXRoIDcgeWVhciBvbGRzICB0byBpbmZvcm0gSDENCg0KYGBge3J9DQoNCm1lYW5CRiA9IHN1bW1hcnkoY2hpbGQudHJhaW4uNy5tb2QpJGNvZWZmaWNpZW50c1siKEludGVyY2VwdCkiICwiRXN0aW1hdGUiXQ0Kc2VCRiA9IHN1bW1hcnkoY2hpbGQudHJhaW4uNy5tb2QpJGNvZWZmaWNpZW50c1siKEludGVyY2VwdCkiICwiU3RkLiBFcnJvciJdDQpoMW1lYW4gPSBzdW1tYXJ5KGNoaWxkLnRyYWluLjExLm1vZCkkY29lZmZpY2llbnRzWyIoSW50ZXJjZXB0KSIgLCJFc3RpbWF0ZSJdDQoNCkJmKHNlQkYsIG1lYW5CRiwgIHVuaWZvcm0gPTAsbWVhbm9mdGhlb3J5PTAsc2R0aGVvcnk9aDFtZWFuLHRhaWw9MSkNCg0Kcm0obWVhbkJGKQ0Kcm0oc2VCRikNCg0KYGBgDQoNCldlIGNvdWxkIHJlamVjdCBIMCB3aXRoIHRoZSBjdXJyZW50IHNhbXBsZSBvZiBOPTE1Lg0KDQojIyBQcmVkaWN0aW9uMjogSW1wcm92ZW1lbnQgd2l0aCBzZXNzaW9uIGluIGVhY2ggY29uZGl0aW9uDQojIyMgQmFzZWQgb246IA0KDQpXZSBzYXcgdGhpcyBpbiA3IHllYXIgb2xkcyBpbiBwcmV2aW91cyBzdHVkeS4NCg0KNyB5ZWFyIG9sZHMgbWVhbnMgOiBgciByb3VuZCggd2l0aChjaGlsZC50cmFpbi43LCB0YXBwbHkocmVzdWx0LCBzZXNzaW9uLCBtZWFuLCBuYS5ybT1UKSkgLDIpYA0KNyB5ZWFyIG9sZHMgbG9nIG9kZHMgKGJldGEgZnJvbSBsbWUpOiBgciBzdW1tYXJ5KGNoaWxkLnRyYWluLjcubW9kKSRjb2VmZmljaWVudHNbInNlc3Npb24uY3QiICwiRXN0aW1hdGUiXWANCjcgeWVhciBvbGQgb2RkICAoZXhwKGJldGEpKWByIGV4cChzdW1tYXJ5KGNoaWxkLnRyYWluLjcubW9kKSRjb2VmZmljaWVudHNbInNlc3Npb24uY3QiICwiRXN0aW1hdGUiXSlgDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBGcmVxdWVudGlzdCANCg0KbG1lIG1vZGVsIHNpbWlsYXIgdG8gdGhhdCBvbiBwaWxvdCBkYXRhIGFib3ZlIGJ1dCB3aXRoIGRhdGEgZnJvbSBib3RoIGNvbmRpdGlvbnM7IEZpdCBzZXBhcmF0ZSBzbG9wZXMgZm9yIHNlc3Npb24gZm9yIGVhY2ggY29uZGl0aW9uLiANCldlIHdpbGwgZG8gdGhpcyBib3RoIGZvciBhIG1vZGVsIHdpdGgganVzdCBmaXJzdCB0d28gc2Vzc2lvbnMgYW5kIGZvciBhIG1vZGVsIHdpdGggYWxsIGRhdGEuDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBCRiANCg0KU3VtbWFyeSBvZiBkYXRhIGZvciBlYWNoIGNvbmRpdGlvbjogbWVhbiBhbmQgc2UgZm9yIHNlc3Npb24uY3QgZm9yIGVhY2ggbGV2ZWwgb2YgY29uZGl0aW9uIGZyb20gbG1lDQp2YWx1ZSB0byBpbmZvcm0gSDE6IGVzdGltYXRlIGZyb20gYWJvdmUgcGlsb3QgZGF0YSBmb3Igc2V2ZW4geWVhciBvbGRzICBgciBzdW1tYXJ5KGNoaWxkLnRyYWluLjcubW9kKSRjb2VmZmljaWVudHNbInNlc3Npb24uY3QiICwiRXN0aW1hdGUiXWANCg0KSWYgaXQgYXBwZWFycyB0aGF0ICBvbmUgb2YgdGhlIGNvbmRpdGlvbnMgKGMxKSBzaG93cyBhIHBvc2l0aXZlIGVmZmVjdCBvZiBzZXNzaW9uIGFuZCBvbmUgZG9lc24ndCAoYzIpLCB3ZSBjYW4gYWxzbyBkbyBCRiBhbmFsc3llcyBmb3IgYzIgZGF0YSB3aXRoICBIMSBpbmZvcm1lZCBieSBlc3RpbWF0ZSBmcm9tICBjMSAodGhpcyBpcyBhIGJldHRlciBlc3RpbWF0ZSB0aGFuIHRoZSBwaWxvdCBzaW5jZSB0aGUgY29uZGl0aW9ucyBhcmUgbW9yZSBjbG9zZWx5IG1hdGNoZWQgdG8gZWFjaCBvdGhlciB0aGFuIGVpdGhlciBpcyB0byB0aGUgcGlsb3QgZGF0YSkNCg0KDQoNCiMjIyBSZXF1aXJlZCBzYW1wbGUgYW5hbHlzZXMNCiMjIyMgRnJlcXVlbnRpc3RzIHBvd2VyDQoNCmBgYHtyfQ0KZGF0YVMgPSB3aXRoKGRyb3BsZXZlbHMoY2hpbGQudHJhaW4uNyksIHRhcHBseShyZXN1bHQsbGlzdChzdWJqZWN0LHNlc3Npb24pLCBtZWFuLCBuYS5ybT1UKSkNCmQ9IGNvaGVuc0QoeCA9IGRhdGFTWywxXSwgeSA9IGRhdGFTWywyXSwgbWV0aG9kID0gInBhaXJlZCIpDQoNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC45LCAgdHlwZSA9IGMoInBhaXJlZCIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQoNCnJtKGRhdGFTKQ0Kcm0oZCkNCmBgYA0KDQpgYGB7cn0NCmRhdGFTID0gd2l0aChkcm9wbGV2ZWxzKGNoaWxkLnRyYWluLjcpLCB0YXBwbHkocmVzdWx0LGxpc3Qoc3ViamVjdCxzZXNzaW9uKSwgbWVhbiwgbmEucm09VCkpDQpkPSBjb2hlbnNEKHggPSBkYXRhU1ssMV0sIHkgPSBkYXRhU1ssMl0sIG1ldGhvZCA9ICJwYWlyZWQiKQ0KDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuOCwgIHR5cGUgPSBjKCJwYWlyZWQiKSwgYWx0ZXJuYXRpdmUgPSBjKCAiZ3JlYXRlciIpKQ0KDQpybShkYXRhUykNCnJtKGQpDQpgYGANCg0KYGBge3J9DQpkYXRhUyA9IHdpdGgoZHJvcGxldmVscyhjaGlsZC50cmFpbi43KSwgdGFwcGx5KHJlc3VsdCxsaXN0KHN1YmplY3Qsc2Vzc2lvbiksIG1lYW4sIG5hLnJtPVQpKQ0KZD0gY29oZW5zRCh4ID0gZGF0YVNbLDFdLCB5ID0gZGF0YVNbLDJdLCBtZXRob2QgPSAicGFpcmVkIikNCg0KcHdyLnQudGVzdChuID0gTlVMTCwgZCA9IGQsIHNpZy5sZXZlbCA9IDAuMDUsIHBvd2VyID0gLjcsICB0eXBlID0gYygicGFpcmVkIiksIGFsdGVybmF0aXZlID0gYyggImdyZWF0ZXIiKSkNCg0Kcm0oZGF0YVMpDQpybShkKQ0KYGBgDQoNCg0KDQojIyMjIFJlcXVpcmVkIHNhbXBsZSBmb3IgQkYgYW5hbHlzZXM6IA0KDQpBcyBmb3IgcHJlZGljdGlvbiAxLCB3ZSBhZ2FpbiBsb29rIGF0IHRoZSBwaWxvdCBkYXRhIGZyb20gc2V2ZW4geWVhciBvbGRzLCB1c2luZyBIMSBpbmZvcm1lZCBieSBlc3RpbWF0ZSBmb3IgMTEgeWVhciBvbGRzLiBJbiBvdXIgYWN0dWFsIGFuYWxzeWVzIHdpbGwgYmUgdXNpbmcgZXN0aW1hdGUgZnJvbSB0aGUgcGlsb3QgIGRhdGEgdG8gaW5mb3JtIEgxLg0KDQoNCmBgYHtyfQ0KDQptZWFuQkYgPSBzdW1tYXJ5KGNoaWxkLnRyYWluLjcubW9kKSRjb2VmZmljaWVudHNbInNlc3Npb24uY3QiICwiRXN0aW1hdGUiXQ0Kc2VCRiA9IHN1bW1hcnkoY2hpbGQudHJhaW4uNy5tb2QpJGNvZWZmaWNpZW50c1sic2Vzc2lvbi5jdCIgLCJTdGQuIEVycm9yIl0NCmgxbWVhbiA9IHN1bW1hcnkoY2hpbGQudHJhaW4uMTEubW9kKSRjb2VmZmljaWVudHNbInNlc3Npb24uY3QiICwiRXN0aW1hdGUiXQ0KDQpCZihzZUJGLCBtZWFuQkYsICB1bmlmb3JtID0wLG1lYW5vZnRoZW9yeT0wLHNkdGhlb3J5PWgxbWVhbix0YWlsPTEpDQoNCnJtKG1lYW5CRikNCnJtKHNlQkYpDQoNCmBgYA0KDQpXZSBoYXZlIHN1ZmZpY2llbnQgZXZpZGVuY2UgdG8gYWNjZXB0IEgxIG92ZXIgSDAgb24gYmFzaXMgb2YgY3VycmVudCBzYW1wbGUuDQoNCg0KIyMgUHJlZGljdGlvbjM6IEdyZWF0ZXIgcGVyZm9ybWFuY2UgaW4gcGljdHVyZStkaWFjcml0aWMgY29uZGl0aW9uIHdpdGgganVzdCBwaWN0dXJlIGNvbmRpdGlvbg0KIyMjIEJhc2VkIG9uOiANCg0KV2UgZG9uJ3QgaGF2ZSBhbnkgcGlsb3QgZGF0YSB3aXRoIHRoaXMgdHlwZSBvZiBtYW5pcHVsYXRpb24gZm9yIGNoaWxkcmVuLiANCg0KVGhpcyBwcmVkaWN0aW9uIGlzIG1hZGUgb24gdGhlIGJhc2lzIG9mIGEgcmVsYXRlZCBlZmZlY3Qgc2VlbiBpbiBhZHVsdCBkYXRhOiB0aGV5IHNob3dlZCBncmVhdGVyIG92ZXJhbGwgcGVyZm9ybWFuY2UgaW4gYSBjb25kaXRpb24gd2hlcmUgdGhleSBzYXcganVzdCBkaWFjcml0aWMgcmF0aGVyIHRoYW4ganVzdCBwaWN0dXJlLiBOb3RlIHRoYXQgaWNvbmNpdHkgbWVhbnMgeW91IGNhbiBwb3RlbnRpYWxseSByZXNwb25kIHdoZW4gdGhleSBhcmUgcHJlc2VudC4gSXQgaXMgcG9zc2libGUgdGhhdCAgaGF2aW5nIHRoZSBkaWFjcml0aWNzIHByZXNlbnQgd2lsbCBoZWxwIGNoaWxkcmVuIHRvbzsgdGhvdWdoIChhKSBjaGlsZHJlbiBjb3VsZCB3ZWxsIGJlIGRpZmZlcmVudCAoZGlhY3RyaXRpY3MgbWlnaHQgYmUgdG9vIGFic3RyYWN0KSAoYikgaXQgY291bGQgYmUgdGhhdCBoYXZpbmcgdGhlIHBpY3R1cmUgdGhlcmUgY2hhbmdlcyB0aGluZ3MpLiANCg0KTWVhbnMgZnJvbSB0aGUgcGlsb3Q6DQoNCmFkdWx0ICBtZWFucyA6IGByIHJvdW5kKCB3aXRoKGFkdWx0LnRyYWluLCB0YXBwbHkocmVzdWx0LCBjb25kaXRpb24sIG1lYW4sIG5hLnJtPVQpKSAsMilgDQphZHVsdCAgbG9nIG9kZHMgKGJldGEgZnJvbSBsbWUpOiBgciBzdW1tYXJ5KGFkdWx0LnRyYWluLm1vZCkkY29lZmZpY2llbnRzWyJjb25kaXRpb24uY3QiICwiRXN0aW1hdGUiXWANCmFkdWx0ICBvZGQgIChleHAoYmV0YSkpYHIgZXhwKHN1bW1hcnkoYWR1bHQudHJhaW4ubW9kKSRjb2VmZmljaWVudHNbInNlc3Npb24uY3QiICwiRXN0aW1hdGUiXSlgDQoNCg0KIyMjIFBsYW5uZWQgQW5hbHlzZXM6IEZyZXF1ZW50aXN0IA0KDQpsbWUgbW9kZWwgc2ltaWxhciB0byB0aGF0IG9uIHBpbG90IGRhdGEgYWJvdmUgYnV0IHdpdGggZGF0YSBmcm9tIGJvdGggY29uZGl0aW9uczsgbG9vayBmb3IgZml4ZWQgZWZmZWN0IG9mIGNvbmRpdGlvbg0KV2Ugd2lsbCBkbyB0aGlzIGJvdGggZm9yIGEgbW9kZWwgd2l0aCBqdXN0IGZpcnN0IHR3byBzZXNzaW9ucyBhbmQgZm9yIGEgbW9kZWwgd2l0aCBhbGwgZGF0YS4NCg0KIyMjIFBsYW5uZWQgQW5hbHlzZXM6IEJGIA0KDQpTdW1tYXJ5IG9mIGRhdGE6IG1lYW4gYW5kIHNlIGZvciBjb25kaXRpb24uY3QNCnZhbHVlIHRvIGluZm9ybSBIMTogZXN0aW1hdGUgZnJvbSBhYm92ZSBBRFVMVCBwaWxvdCBkYXRhICAgYHIgc3VtbWFyeShhZHVsdC50cmFpbi5tb2QpJGNvZWZmaWNpZW50c1siY29uZGl0aW9uLmN0IiAsIkVzdGltYXRlIl1gDQoNClRoZXJlIGlzIGEgY2F2ZWF0IGhlcmUgc2luY2UgdGhpcyB2YWx1ZSBjb21lcyBmcm9tIGFkdWx0cyBhbmQgd2lsbCBsaWtlbHkgb3ZlcmVzdGltYXRlIGFueSBkaWZmZXJlbmNlIGZvciBjaGlsZHJlbiAobWFraW5nIGl0IGEgY29uc2VydmF0aXZlIGVzdGltYXRlLCBiaWFzaW5nIGV2aWRlbmNlIGZvciBIMCkuIA0KDQojIyMgUmVxdWlyZWQgc2FtcGxlIGFuYWx5c2VzDQojIyMjIEZyZXF1ZW50aXN0cyBwb3dlcg0KDQpOT1RFOiB0aGlzIGlzIGJhc2VkIG9uIEFEVUxUIGRhdGEuIEl0IGxpa2VseSB1bmRlcmVzdGltYXRlcyB0aGUgcG93ZXIgcmVxdWlyZWQgdG8gc2VlIHRoaXMgZGlmZmVyZW5jZS4NCmBgYHtyfQ0KDQpkYXRhUyA9IHdpdGgoZHJvcGxldmVscyhhZHVsdC50cmFpbiksIHRhcHBseShyZXN1bHQsbGlzdChzdWJqZWN0LGNvbmRpdGlvbiksIG1lYW4sIG5hLnJtPVQpKQ0KZD0gY29oZW5zRCh4ID0gZGF0YVNbLDFdLCB5ID0gZGF0YVNbLDJdLCBtZXRob2QgPSAicG9vbGVkIikNCg0KcHdyLnQudGVzdChuID0gTlVMTCwgZCA9IGQsIHNpZy5sZXZlbCA9IDAuMDUsIHBvd2VyID0gLjksICB0eXBlID0gYygidHdvLnNhbXBsZSIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQpybShkYXRhUykNCnJtKGQpDQpgYGANCg0KDQpgYGB7cn0NCg0KZGF0YVMgPSB3aXRoKGRyb3BsZXZlbHMoYWR1bHQudHJhaW4pLCB0YXBwbHkocmVzdWx0LGxpc3Qoc3ViamVjdCxjb25kaXRpb24pLCBtZWFuLCBuYS5ybT1UKSkNCmQ9IGNvaGVuc0QoeCA9IGRhdGFTWywxXSwgeSA9IGRhdGFTWywyXSwgbWV0aG9kID0gInBvb2xlZCIpDQoNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC44LCAgdHlwZSA9IGMoInR3by5zYW1wbGUiKSwgYWx0ZXJuYXRpdmUgPSBjKCAiZ3JlYXRlciIpKQ0Kcm0oZGF0YVMpDQpybShkKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YVMgPSB3aXRoKGRyb3BsZXZlbHMoYWR1bHQudHJhaW4pLCB0YXBwbHkocmVzdWx0LGxpc3Qoc3ViamVjdCxjb25kaXRpb24pLCBtZWFuLCBuYS5ybT1UKSkNCmQ9IGNvaGVuc0QoeCA9IGRhdGFTWywxXSwgeSA9IGRhdGFTWywyXSwgbWV0aG9kID0gInBvb2xlZCIpDQoNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC43LCAgdHlwZSA9IGMoInR3by5zYW1wbGUiKSwgYWx0ZXJuYXRpdmUgPSBjKCAiZ3JlYXRlciIpKQ0Kcm0oZGF0YVMpDQpybShkKQ0KYGBgDQoNClN1Z2dlc3RzIHRoYXQgZm9yIGFkdWx0cyB3ZSB3b3VsZCBuZWVkIDU4IHBlciBjb25kaXRpb24gdG8gZ2V0IDkwJSBwb3dlci4gV2Ugd291bGQgYmUgbGlrZWx5IHRvIG5lZWQgbW9yZSB3aXRoIGNoaWxkcmVuLg0KDQpHaXZlbiBwcmFjdGljYWwgY29uc3RyYWludHMsIHdlIGFyZSB1bmxpa2VseSB0byBvYnRhaW4gYSBzdWZmaWNpZW50IHNhbXBsZSBmb3IgdGhpcy4gSG93ZXZlciB0aGlzIGVmZmVjdCBpc24ndCBjcml0aWNhbCBpbiB0ZXJtcyBvZiBkZW1vbnN0cmF0aW5nIHdoYXQgbGVhZHMgdG8gZ3JlYXRlciBsZWFybmluZy4gKEl0IGlzIHRoZXJlZm9yZSBtb3JlIGltcG9ydGFudCB0byBkZW1vbnN0cmF0ZSB0aGF0IHRoZXkgYXJlIGFib3ZlIGNoYW5jZSBpbiBlYWNoIGNvbmRpdGlvbikvDQoNCiMjIFByZWRpY3Rpb24gNDogVGhleSB3aWxsIGltcHJvdmUgbW9yZSBpbiBvbmUgY29uZGl0aW9uIHRoYW4gdGhlIG90aGVyKG5vIHByZWRpY3RlZCBkaXJlY3Rpb24pDQojIyMgQmFzZWQgb246DQoNCldlIGRvbid0IGhhdmUgYW55IGNsZWFyIGV2aWRlbmNlIHRvIGJhc2UgdGhpcyBvbi4gSG93ZXZlciBpdCBzZWVtcyByZWFzb25hYmxlIHRoYXQgdGhlIHR5cGUgb2YgdHJhaW5pbmcgd2lsbCBsZWVkIHRvIGRpZmZlcmVudCBsZWFybmluZyBzbG9wZXMuIE9uZSBwb3NzaWJpbGl0eSBpcyB0aGF0IHdoaWxlIHRoZXkgc2hvdyBncmVhdGVyIGxlYXJuaW5nIGluIHRoZSBjb25kaXRpb24gd2l0aCBkaWFjcnRpY3MsIGR1ZSB0byBtb3JlIGluZm9ybWF0aW9uIHBlciB0cmlhbC4gSG93ZXZlciBpdCBpcyBhbHNvIHBvc3NpYmxlIHRoYXQgdGhleSBjb3VsZCBzaG93IHN0ZWVwZXIgbGVhcm5pbmcgaW4gdGhlIG90aGVyIGNvbmRpdGlvbiwgZHVlIHRvIG5lZWRpbmcgdG8gcGF5IG1vcmUgYXR0ZW50aW9uIHRvIGFuZCByZW1lbWJlciBpbmRpdmlkdWFsIHN0aW11bGkuIFdlIHNhdyBtZWFucyBpbiB0aGlzIGxhdHRlciBkaXJlY3Rpb24gaW4gdGhlIGFkdWx0IHBpbG90IGRhdGEgaS5lLiBtb3JlIGltcHJvdmVtZW50IGluIHRoZSBjb25kaXRpb24gd2l0aCBwaWN0dXJlcyAobGFiZWxsZWQgY29uZGl0aW9uICJpIiBmb3IgaW1wbGljaXQpIHRoYW4gd2l0aCBkaWFjcnRpY2lzIChsYWJlbGxlZCAiZSIgZm9yIGV4cGxpY2l0KSAodGhvdWdoIGNvbmRpdGlvbnMgbm90IGV4YWN0bHkgdGhlIHNhbWUgc2VlIGFib3ZlKS4gdGhvdWdoIGl0IHdzbid0IHNpZ25maWNhbnQuDQoNCmFkdWx0ICBtZWFucyA6IGByIHJvdW5kKHdpdGgoYWR1bHQudHJhaW4sIHRhcHBseShyZXN1bHQsIGxpc3QoY29uZGl0aW9uLCBzZXNzaW9uKSwgbWVhbiwgbmEucm09VCkpICwyKWANCiAgICAgICBiZXRhOiBgciBzdW1tYXJ5KGFkdWx0LnRyYWluLm1vZCkkY29lZmZpY2llbnRzWyJzZXNzaW9uLmN0OmNvbmRpdGlvbi5jdCIsIkVzdGltYXRlIiBdYA0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogRnJlcXVlbnRpc3QgDQoNCmxtZSBtb2RlbCBzaW1pbGFyIHRvIHRoYXQgb24gcGlsb3QgZGF0YSBhYm92ZSBidXQgd2l0aCBkYXRhIGZyb20gYm90aCBjb25kaXRpb25zOyBsb29rIGZvciBmaXhlZCBlZmZlY3Qgb2YgY29uZGl0aW9uLmN0OnNlc3Npb24uY3QNCldlIHdpbGwgZG8gdGhpcyBib3RoIGZvciBhIG1vZGVsIHdpdGgganVzdCBmaXJzdCB0d28gc2Vzc2lvbnMgYW5kIGZvciBhIG1vZGVsIHdpdGggYWxsIGRhdGEuDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBCRiANCg0KU3VtbWFyeSBvZiBkYXRhOiBtZWFuIGFuZCBzZSBmb3IgaW50ZXJhY3Rpb24gc2Vzc2lvbiBhbmQgY29uZGl0aW9uIChzZXNzaW9uLmN0IGJ5IGNvbmRpdG9pbi5jdCkgDQp2YWx1ZSB0byBpbmZvcm0gSDE6IGVzdGltYXRlIG9mIHNlc3Npb24gZnJvbSB0aGUgc2FtZSBtb2RlbCBtb2RlbCAoZS5nLiBzdW1tYXJ5KG1vZGVsLm5ld2RhdGEpJGNvZWZmaWNpZW50c1sic2Vzc2lvbi5jdCIgLCJFc3RpbWF0ZSJdYC4gDQoNClRoaXMgd2lsbCBwcm92aWRlIGEgcmVsYXRpdmVseSBoaWdoIGVzdGlhbXRlIG9mIGxpa2VseSBlZmZlY3Qgb2YgaW50ZXJhY3Rpb24gKGlmIG9uZSBpcyBwcmVzZW50KSBnaXZlbiB0aGUgYWN0dWFsIGRhdGEgc2V0IChzbyBhZ2FpbiwgYSBjb25zZXJ2YXRpdmUgZXN0aW1hdGUpICANCg0KW05vdGU6IGFyZSBjaGVja2luZyB0aGlzIHdpdGggc3RhdHMgY29uc3VsdGFudF0NCg0KTm90ZSB0aGlzIGlzIGV4ZW1wbGlmaWVkIGJlbG93IGluIHNhbXBsZSBzaXplIGFuYWx5c2lzIHVzaW5nIHRoZSBjdXJyZW50IGRhdGEgZnJvbSBhZHVsdHM6DQoNCg0KIyMjIFJlcXVpcmVkIHNhbXBsZSBhbmFseXNlcw0KDQojIyMjIEZyZXF1ZW50aXN0IHBvd2VyDQpOb3RoaW5nIHRvIGJhc2UgcG93ZXIgYW5hbHlzaXMgb24gaGVyZSAoYXMgd2FzIG5vIGVmZmVjdCBpbiBvcmlnaW5hbCBkYXRhKS4NCg0KIyMjIyBSZXF1aXJlZCBzYW1wbGUgZm9yIEJGIGFuYWx5c2VzOiANCg0KTm90ZSB0aGlzIGlzIHdpdGggYWR1bHQgZGF0YSAtIGl0IGV4ZW1wbGlmaWVzIHRoZSBwcm9jZXNzIHdlIHdpbGwgYWN0dWFsbHkgdXNlIHRvIGNvbmR1Y3QgcG93ZXIgYW5hbHlzZXMgb24gYWN0dWFsIGRhdGEgDQpgYGB7cn0NCg0KbWVhbkJGID0gc3VtbWFyeShhZHVsdC50cmFpbi5tb2QpJGNvZWZmaWNpZW50c1sic2Vzc2lvbi5jdDpjb25kaXRpb24uY3QiLCJFc3RpbWF0ZSJdDQpzZUJGID0gc3VtbWFyeShhZHVsdC50cmFpbi5tb2QpJGNvZWZmaWNpZW50c1sic2Vzc2lvbi5jdDpjb25kaXRpb24uY3QiLCJTdGQuIEVycm9yIl0NCmgxbWVhbiA9IHN1bW1hcnkoYWR1bHQudHJhaW4ubW9kKSRjb2VmZmljaWVudHNbInNlc3Npb24uY3QiLCJFc3RpbWF0ZSJdDQpCZihzZUJGLCBtZWFuQkYsICB1bmlmb3JtID0wLG1lYW5vZnRoZW9yeT0wLHNkdGhlb3J5PWgxbWVhbix0YWlsPTIpDQoNCnJtKG1lYW5CRikNCnJtKHNlQkYpDQoNCmBgYA0KTm90ZTogd2UgdXNlIHRhaWwgPTIgYXMgZG9uJ3QgaGF2ZSBhIGNsZWFyIGRpcmVjdGlvbiBmb3IgdGhpcyBoeXBvdGhlc2lzDQoNClNvIG5vdGUsIHdpdGggYWR1bHQgcGlsb3QgZGF0YSB3ZSBkbyBoYXZlIGV2aWRlbmNlIGluIGZhdm9yIG9mIEgwIGZyb20gdGhlIGN1cnJlbnQgZGF0YSBzZXQuIA0KDQoNCk9uZSBwb3NzaWJpbGl0eSB3aXRoIGNoaWxkcmVuIGlzIHRoYXQgd2Ugd2lsbCBub3QgYmUgYWJsZSB0byBvYnRhaW4gYSBsYXJnZSBlbm91Z2ggc2FtcGxlIHRvIHByb3ZpZGUgZXZpZGVuY2UgZm9yL2FnYWluc3QgdGhlIGh5cG90aGVzaXMgdGhhdCB0aGVyZSBpcyBtb3JlIGxlYXJuaW5nIGluIG9uZSBkaXJlY3Rpb24sIGJ1dCB3ZSBtYXkgZmluZCBldmlkZW5jZSBmb3IgdGhlIEgxIHRoYXQgdGhlcmUgKmlzKiBhbiBlZmZlY3Qgb2Ygc2Vzc2lvbiBpbiBvbmUgY29uZGl0aW9uIGJ1dCBmb3IgdGhlIEgwIHRoYXQgdGhlcmUgaXMgKm5vdCogYW5kIGVmZmVjdCBvZiBzZXNzaW9uIGluIHRoZSBvdGhlciBjb25kaXRpb24uIElmIHNvLCB3ZSB3aWxsIGRlZW0gdGhpcyBzdWZmaWNpZW50IHRvIGFkZHJlc3MgdGhpcyBwcmVkaWNpdG9uLg0KDQoNCg0KIyAyQUZDIHBpY3R1cmUgYW5kIDJBRkMgZGlhY3JpdGljDQoNClRoZXNlIHR3byB0ZXN0cyBhcmUgdmVyeSBzaW1pbGFyIHRvIHRyYWluaW5nIGJ1dCB3aXRoIGVpdGhlciBqdXN0IHBpY3R1cmVzIG9yIGp1c3QgZGlhY3JpdGljcy4gVGhlIHRlc3RzIGFyZSBvbmx5IGRvbmUgYXMgcG9zdCB0ZXN0cywgbm90IGFzIHByZS10ZXN0cyAodW5saWtlIGFsbCBvZiB0aGUgdGVzdHMgZGlzY3Vzc2VkIGFmdGVyIHRoaXMgb25lKQ0KDQpDaGlsZHJlbiBpbiB0aGUgcGljdHVyZXMrZGlhY3JpdGljcyBjb25kaXRpb24gd2lsbCBnZXQgdGhlIDJBRkMgcGljdHVyZXMgdGVzdCBmb2xsb3dlZCBieSB0aGUgMkFGQyBkaWFjcml0aWNzIHRlc3Q7IGNoaWxkcmVuIGluIHRoZSBwaWN0dXJlc29ubHkgdGVzdCB3aWxsIGdldCBqdXN0IDJBRkMgcGljdHVyZXMgYnV0IHdpbGwgZ2V0IGl0IHR3aWNlIChzbyB0aGF0IHRvdGFsIGV4cG9zdXJlIGRvZXNuJ3QgZGlmZmVyIGFjcm9zcyBjb25kaXRpb25zKS4NCg0KV2hlcmUgd2UganVzdCBsb29rIGEgY29uZGl0aW9ucyBzZXBhcmF0ZWx5LCBmb3IgdGhlIGp1c3QgcGljdHVyZXMgdGVzdCwgd2Ugd2lsbCBsb29rIGF0IGFsbCBvZiB0aGUgZGF0YSAoaS5lLiBmb3IgdGhlIHBpY3R1cmVzIG9ubHkgY29uZGl0aW9uLCBmcm9tIGJvdGggcGFydHMgb2YgdGhlIHJlcGVhdGVkIHRlc3QpLiBXaGVyZSB3ZSBjb21wYXJlIGNvbmRpdGlvbnMsIHdlIHdpbGwgbG9vayBvbmx5IHVzZSBkYXRhIGZyb20gdGhlIGZpcnN0IDJBRkMgdGVzdC4gDQoNCk5vdGU6IHVubGlrZSBmb3IgYWxsIHRoZSB0ZXN0cyB0aGF0IGZvbGxvdywgdGhlcmUgaXMgbm8gcHJlLXRlc3QuDQoNCiMjIHJ1biBsbWVzIG9uIHJlbGV2YW50IHBpbG90IGRhdGENCg0KV2UgZGlkbid0IGRvIHRoaXMgdGVzdCBpbiB0aGUgcGlsb3QsIGhvd2V2ZXIgdGhlIHRlc3QgaXMgcmF0aGVyIHNpbWlsYXIgdG8gdHJhaW5pbmcgdGVzdCBzbyB3ZSB1c2UgbW9kZWwgYmFzZWQgb24ganVzdCBsYXN0IDI0IHNlc3Npb25zIG9mIHRyYWluaW5nIGZvciBpbmZvcm1pbmcgcG93ZXIgZGVjaXNpb25zLiANCg0KYGBge3J9DQpjaGlsZC50cmFpbi43LnMyLjI0ID0gZHJvcGxldmVscyhzdWJzZXQoY2hpbGQudHJhaW4sIGFnZWdyb3VwID09ICI3eWVhcnMiICYgc2Vzc2lvbiA9PSJzZXNzaW9uMiIgJiBvcmRlcj43MikpDQpjaGlsZC50cmFpbi43LnMyLjI0ID0gbGl6Q2VudGVyKGNoaWxkLnRyYWluLjcuczIuMjQsIGMoInRvbmVjb250cmFzdCIpKQ0KY2hpbGQudHJhaW4uNy5zMi5zNC5tb2QgPSBnbG1lciAocmVzdWx0IH4NCiAgICAgICAgICAgICAgICAgMSsgdG9uZWNvbnRyYXN0LmN0DQogICAgICAgICAgICAgICAgKyAoMXxzdWJqZWN0KSwNCiAgICAgICAgICAgICAgICBkYXRhID0gY2hpbGQudHJhaW4uNy5zMi4yNCwgIGZhbWlseSA9IGJpbm9taWFsLCBjb250cm9sPWdsbWVyQ29udHJvbChvcHRpbWl6ZXIgPSAiYm9ieXFhIikpDQoNCnJvdW5kKHN1bW1hcnkoY2hpbGQudHJhaW4uNy5zMi5zNC5tb2QpJGNvZWZmaWNpZW50cywzKQ0KYGBgDQoNCmBgYHtyfQ0KDQpjaGlsZC50cmFpbi4xMS5zMi4yNCA9IGRyb3BsZXZlbHMoc3Vic2V0KGNoaWxkLnRyYWluLCBhZ2Vncm91cCA9PSAiMTF5ZWFycyIgJiBzZXNzaW9uID09InNlc3Npb24yIiAmIG9yZGVyPjcyKSkNCmNoaWxkLnRyYWluLjExLnMyLjI0ID0gbGl6Q2VudGVyKGNoaWxkLnRyYWluLjExLnMyLjI0LCBjKCJ0b25lY29udHJhc3QiKSkNCmNoaWxkLnRyYWluLjExLnMyLnM0Lm1vZCA9IGdsbWVyIChyZXN1bHQgfg0KICAgICAgICAgICAgICAgICAxKyB0b25lY29udHJhc3QuY3QNCiAgICAgICAgICAgICAgICArICgxfHN1YmplY3QpLA0KICAgICAgICAgICAgICAgIGRhdGEgPSBjaGlsZC50cmFpbi4xMS5zMi4yNCwgIGZhbWlseSA9IGJpbm9taWFsLCBjb250cm9sPWdsbWVyQ29udHJvbChvcHRpbWl6ZXIgPSAiYm9ieXFhIikpDQoNCnJvdW5kKHN1bW1hcnkoY2hpbGQudHJhaW4uMTEuczIuczQubW9kKSRjb2VmZmljaWVudHMsMykNCmBgYA0KDQoNCmBgYHtyfQ0KYWR1bHQudHJhaW4uczIuMjQgPSBzdWJzZXQoYWR1bHQudHJhaW4sIHNlc3Npb24gPT0ic2Vzc2lvbjIiICYgb3JkZXI+MjY0KQ0KYWR1bHQudHJhaW4uczIuMjQgPSBsaXpDZW50ZXIoYWR1bHQudHJhaW4uczIuMjQsIGxpc3QoInRvbmVjb250cmFzdCIpKQ0KDQphZHVsdC50cmFpbi5zMi4yNC5tb2QgPSBnbG1lciAocmVzdWx0IH4NCiAgICAgICAgICAgICAgICAgMSsgdG9uZWNvbnRyYXN0LmN0DQogICAgICAgICAgICAgICAgKyAoMXxzdWJqZWN0KSwNCiAgICAgICAgICAgICAgICBkYXRhID0gYWR1bHQudHJhaW4uczIuMjQsICBmYW1pbHkgPSBiaW5vbWlhbCwgY29udHJvbD1nbG1lckNvbnRyb2wob3B0aW1pemVyID0gImJvYnlxYSIpKQ0KDQpyb3VuZChzdW1tYXJ5KGFkdWx0LnRyYWluLnMyLjI0Lm1vZCkkY29lZmZpY2llbnRzLDMpDQpgYGANCg0KIyMgUHJlZGljdGlvbjE6IFBlcmZvcm1hbmNlIHdpbGwgYWJvdmUgY2hhbmNlIGluIGVhY2ggdGVzdCBpbiBlYWNoIGNvbmRpdGlvbi4NCiMjIyBCYXNlZCBvbjoNClRyYWluaW5nIGRhdGEgaW4gcGlsb3QgKHNlZSBhYm92ZSkNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBGcmVxdWVudGlzdCANCg0KbG1lIG1vZGVsIHNpbWlsYXIgdG8gdGhhdCBmb3IgdHJhaW5pbmcgZGF0YS4gQWdhaW4gZml0IHNlcGFyYXRlIGludGVyY2VwdHMgZm9yIGVhY2ggY29uZGl0aW9uIGFuZCBjb21wYXJlIGVhY2ggdG8gY2hhbmNlID0gNTAgKGkuZS5kZWZhdWx0IHZhbHVlIHJldHVybmVkKS4gTm90ZSB0aGF0IHNpbmNlIGFsbCBwcmVkaWN0b3JzIGFyZSBjZW50ZXJlZCwgdGhlIGludGVyY2VwdCByZWxmZWN0cyBvdmVyYWxsIGF2ZXJhZ2UgKHJhdGhlciB0aGFuIGF0IGJhc2VsZXZlbHMgb2YgYSBmYWN0b3IpLiANCg0KKFdlIHdpbGwgZG8gdGhpcyBib3RoIGZvciBhIG1vZGVsIHdpdGgganVzdCBkYXkyIHRlc3QgYW5kIGRheTQgdGVzdDsgYXMgZGlzY3Vzc2VkIGFib3ZlLCB3ZSB3aWxsIHVzZSB0aGUgZnVsbCBkb3VibGUgZGF0YSBzZXQgZm9yIHRoZSAyQUZDIHBpY3R1cmUgdGVzdCBmb3IgdGhlIHBhcnRpY2lwYW50cyBpbiB0aGUgcGljdHVyZStkaWFjcml0aWMgY29uZGl0aW9uKS4NCg0KIyMjIFBsYW5uZWQgQW5hbHlzZXM6IEJGIHRlc3QgDQoNClN1bW1hcnkgb2YgZGF0YSBmb3IgZWFjaCBjb25kaXRpb246IG1lYW4gYW5kIHNlIGZvciBpbnRlcmVjcHQgZnJvbSBsbWUNCg0KdmFsdWUgdG8gaW5mb3JtIEgxOiBhc3N1bWluZyB0aGV5IHNob3cgbGVhcm5pbmcsIGVzdGltYXRlIGZyb20gdGhlIGVxdWl2YWxlbnQgbG1lIGZvciB0cmFpbmluZyBkYXRhIGZyb20gY3VycmVudCBkYXRhIHNldCAoTk9UIGZyb20gcGlsb3QgZGF0YSAtICp1bmxlc3MqIHRoZSBpbnRlcmNlcHQgZnJvbSB0cmFpbmluZyBzZXQgZGlkbid0IHN1Z2dlc3QgYWJvdmUgY2hhbmNlIHBlZm9ybWFuY2UpLiBBZ2FpbiBub3RlIHRoYXQgaWYgd2UgZmluZCBhbiBlZmZlY3QgZm9yIGNvbmRpdGlvbjEsIHdlIGNhbiBhbHNvIHVzZSB0aGUgZXN0aW1hdGUgZm9yIGludGVyY2VwdCBmb3IgdGhhdCB0byBpbmZvcm0gSDEgd2hlbiBsb29raW5nIGF0IGRhdGEgZnJvbSBjb25kaXRpb24yOyBhbmQgdmljZSB2ZXJzYS4gVGhpcyBpcyBhIGJldHRlciBlc3RpbWF0ZSBzaW5jZSB0aGUgY29uZGl0aW9ucyBhcmUgbW9yZSBjbG9zZWx5IG1hdGNoZWQgdG8gZWFjaCBvdGhlciB0aGFuIGVpdGhlciBpcyB0byB0aGUgcGlsb3QgZGF0YS4NCg0KIyMjIFJlcXVpcmVkIHNhbXBsZSBhbmFseXNlcw0KIyMjIyBGcmVxdWVudGlzdCBwb3dlcg0KDQpIZXJlIHdlIGxvb2sgYXQgcG93ZXIgdXNpbmcgdGhlIHZhbHVlcyBmcm9tIHRoZSBzdWJzZXQgb2YgdHJhaW5pbmcgZGF0YSBmcm9tIHRoZSBhYm92ZQ0KDQpgYGB7cn0gICAgICAgICAgICAgICAgIA0KDQpkYXRhUz1hcy5udW1lcmljKHdpdGgoZHJvcGxldmVscyhjaGlsZC50cmFpbi43LnMyLjI0KSwgdGFwcGx5KHJlc3VsdCxsaXN0KHN1YmplY3QpLCBtZWFuLCBuYS5ybT1UKSkpDQpkPSBjb2hlbnNEKHggPSBkYXRhUywgbXU9MC41KQ0KcHdyLnQudGVzdChuID0gTlVMTCwgZCA9IGQsIHNpZy5sZXZlbCA9IDAuMDUsIHBvd2VyID0gLjksICB0eXBlID0gYygib25lLnNhbXBsZSIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuOCwgIHR5cGUgPSBjKCJvbmUuc2FtcGxlIiksIGFsdGVybmF0aXZlID0gYyggImdyZWF0ZXIiKSkNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC43LCAgdHlwZSA9IGMoIm9uZS5zYW1wbGUiKSwgYWx0ZXJuYXRpdmUgPSBjKCAiZ3JlYXRlciIpKQ0Kcm0oZGF0YVMpDQpybShkKQ0KYGBgDQoNClRoaXMgc3VnZ2VzdHMgYSBzYW1wbGUgb2YgMjEgaXMgc3VmZmljaWVudCBmb3IgOTAlIHBvd2VyLg0KDQojIyMjIFJlcXVpcmVkIHNhbXBsZSBmb3IgQkYgYW5hbHlzZXM6IA0KDQpIZXJlIHdlIHVzZSB0aGUgc3Vic2V0IG9mIHBpbG90IGRhdGEgd2l0aCA3IHllYXIgb2xkcyBhbmQgYW4gSDEgaW5mb3JtZWQgYnkgZXN0aW1hdGUgZnJvbSAxMSB5ZWFyIG9sZHMgd2hvbGUgdHJhaW5pbmcgZGF0YSBzZXQgKG5vdGU6IGluIGFjdHVhbCBhbmFseXNlcyBIMSB3aWxsIGJlIGluZm9ybWVkIGJ5IGVzdGltYXRlIGZyb20gbW9kZWwgb2YgdGhlIGN1cnJlbnQgdHJhaW5pbmcgZGF0YSB3aXRoIDcgeWVhciBvbGRzICkNCg0KYGBge3J9DQoNCm1lYW5CRiA9IHN1bW1hcnkoY2hpbGQudHJhaW4uNy5zMi5zNC5tb2QpJGNvZWZmaWNpZW50c1siKEludGVyY2VwdCkiICwiRXN0aW1hdGUiXQ0Kc2VCRiA9IHN1bW1hcnkoY2hpbGQudHJhaW4uNy5zMi5zNC5tb2QpJGNvZWZmaWNpZW50c1siKEludGVyY2VwdCkiICwiU3RkLiBFcnJvciJdDQpoMW1lYW4gPSBzdW1tYXJ5KGNoaWxkLnRyYWluLjExLm1vZCkkY29lZmZpY2llbnRzWyIoSW50ZXJjZXB0KSIgLCJFc3RpbWF0ZSJdDQoNCkJmKHNlQkYsIG1lYW5CRiwgIHVuaWZvcm0gPTAsbWVhbm9mdGhlb3J5PTAsc2R0aGVvcnk9aDFtZWFuLHRhaWw9MSkNCkJmX3Bvd2VyY2FsYyhzZUJGLCBtZWFuQkYsICB1bmlmb3JtID0wLG1lYW5vZnRoZW9yeT0wLE49MTUsIG1pbj0xNSwgbWF4PTIwLHNkdGhlb3J5PWgxbWVhbix0YWlsPTEpDQoNCnJtKG1lYW5CRikNCnJtKHNlQkYpDQoNCmBgYA0KDQpTdWdnZXN0cyBkb24ndCBjdXJyZW50bHkgaGF2ZSBzdWZmaWNpZW50IHNhbXBsZSB0byBnZXQgcmVsaWFibGUgZXZpZGVuY2UgZm9yIEgxLCBidXQgY291bGQgZG8gd2l0aCAxOSBwYXJ0aWNpcGFudHMuDQoNCiMjIFByZWRpY3Rpb24gMjogRm9yIHBpY3R1cmUtb25seSB0ZXN0LCB0aGVyZSB3aWxsIGJlIGdyZWF0ZXIgcGVyZm9ybWFuY2UgaW4gdGhlIHBpY3R1cmUtb25seSBjb25kaXRpb24NCiMjIyBiYXNlZCBvbg0KQ2hpbGRyZW4gaW4gdGhlIGNvbmRpdGlvbiB3aGVyZSBkaWFjcml0aWNzIGFyZSBwcmVzZW50IG1pZ2h0IGhhdmUgYmVjb21lIG92ZXJseSByZWxpYW50IG9uIHRoZW0gZHVyaW5nIHRyYWluaW5nIGFuZCB0aHVzIHVuYWJsZSB0byBkbyB0aGUgdGVzdCB3aGVuIHRoZXkgYXJlIGFic2VudC4NCkRvbid0IGN1cnJlbnRseSBoYXZlIHNwZWNpZmljIGRhdGEgdG8gYmFzZSB0aGlzIG9uLg0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogRnJlcXVlbnRpc3QgDQpsbWUgbW9kZWwgb24gNyB5ZWFyIG9sZHMgZGF0YSwgbG9vayBhdCBlZmZlY3Qgb2YgY29uZGl0aW9uLg0KDQooV2Ugd2lsbCBkbyB0aGlzIGJvdGggZm9yIGEgbW9kZWwgd2l0aCBqdXN0IGRheTIgdGVzdCBhbmQgZGF5NCB0ZXN0OyBhcyBkaXNjdXNzZWQgYWJvdmUsIHdlIHdpbGwgb25seSB1ZSB0aGUgaGFsZiBzZXQgZm9yIHRoZSAyQUZDIHBpY3R1cmUgdGVzdCBmb3IgdGhlIHBhcnRpY2lwYW50cyBpbiB0aGUgcGljdHVyZStkaWFjcml0aWMgY29uZGl0aW9uKS4NCg0KIyMjIFBsYW5uZWQgQW5hbHlzZXM6IEJGIHRlc3QgDQoNClN1bW1hcnkgb2YgZGF0YSBmb3IgZWFjaCBjb25kaXRpb246IG1lYW4gYW5kIHNlIGZvciBjb25kaXRpb24gZnJvbSBsbWUNCnZhbHVlIHRvIGluZm9ybSBIMTogYXNzdW1pbmcgdGhleSBzaG93IGxlYXJuaW5nLCBlc3RpbWF0ZSBvZiBpbnRlcmNlcHQgZnJvbSB0aGUgY3VycmVudCBtb2RlbCAobm90ZSBvdGhlciB2YWx1ZXMgYXJlIGNlbnRlcmVkLCBzbyB0aGlzIGlzIGVxdWl2bGFlbnQgdG8gZ3JhbmQgbWVhbjsgaXQgd2lsbCBiZSBjb25zZXJ2YXRpdmUpDQoNCihBbSBzZWVraW5nIHN0YXRpc3RpY2FsIGFkdmljZSB0byBjb25maXJtIHRoYXQgdGhpcyBpcyBhIHJlYXNvbmFibGUsIGlmIGNvbnNlcnZhdGl2ZSwgZXN0aW1hdGUgZm9yIEgxKQ0KDQojIyMgUmVxdWlyZWQgc2FtcGxlIGFuYWx5c2VzDQoNCk5vdGhpbmcgd2UgY2FuIHJlYWxseSBiYXNlIGFuYWx5c2VzIG9uIGhlcmUgKGNvbXBhcmlzb24gb2YgY29uZGl0aW9uIGluIHByZXZpb3VzIGFkdWx0IGRhdGEgaXMgdG9vIGRpc3NpbWlsYXIpLg0KDQpOb3RlIHRoYXQgaXQgbWF5IHByb3ZlIGRpZmZpY3VsdCB0byBvYnRhaW5hIHN1ZmZpY2llbnQgc2FtcGxlIHRvIGdhaW4gZXZpZGVuY2UgZm9yIEgxIG9yIGgwLiAgSG93ZXZlciBpdCBtYXkgYmUgdGhhdCB3ZSBzZWUgYWJvdmUgY2hhbmNlIHBlcmZvcm1hbmNlIG9ubHkgZm9yIHRoZSBwaWN0dXJlLW9ubHkgY29uZGl0aW9uLiBJbiB0aGF0IGNhc2UsIHdlIG1heSBiZSBsb29rIHRvIHRoZSBwcmV2aW91cyBhbmFseXNlcyAoUHJlZGljdGlvbiAxKSBhbmQgYmUgYWJsZSB0byBzaG93IHRoYXQgdGhlcmUgaXMgZXZpZGVuY2UgZm9yIEgxIG92ZXIgSDAgaW4gb25lIGNvbmRpdGlvbiwgYnV0IGZvciBIMCBvdmVyIEgxIGluIHRoZSBvdGhlci4gSWYgc28sIHdlIHdpbGwgYmUgYWJsZSB0byBzYXkgdGhhdCB0aGVyZSBpcyBldmlkZW5jZSBvZiBsZWFybmluZyBpbiBvbmUgY29uZGl0aW9uIGFuZCBub3QgdGhlIG90aGVyLCBhbmQgdGhpcyB3aWxsIGJlIGRlZW1lZCBzdWZmaWNpZW50IHRvIGFkZHJlc3MgdGhpcyBoeXBvdGhlc2lzLiAgDQoNCiMgRGlzY3JpbWluYXRpb24NClRoaXMgdGVzdCB3aWxsIGJlIGdpdmVuIHByZSBhbmQgcG9zdC4gQ2hpbGRyZW4gd2lsbCBoZWFyIHRocmVlIGZyb2dzIGVhY2ggcHJvZHVjZSBhIE1hbmRhcmluIHdvcmQuIE9uZSBwcm9kdWNlcyB0aGUgdGFyZ2V0IGFuZCB0aGUgb3RoZXIgdHdvIGVhY2ggcHJvZHVjZSB0aGUgc2FtZSBmb2lsIHdvcmQsIHdoaWNoIHdpbGwgYmUgYSB3b3JkIGRpZmZlcmVpbmcgZnJvbSB0aGUgdGFyZ2V0IG9ubHkgaW4gdG9uZS4gDQoNCkVhY2ggb2YgdGhlIDYgb25lIGNvbnRyYXN0cyBhcmUgdGVzdGVkLiBXZSBwdXQgdG9uZWNvbnRyYXN0IGludG8gdGhlIG1vZGVsLCBzaW5jZSBpdCBpcyBsaWtlbHkgdG8gaGF2ZSBhbiBlZmZlY3QsIGJ1dCBkb24ndCBoYXZlIHNwZWNpZmljIGh5cG90aGVzZXMgb2YgaW50ZXJlc3QgaGVyZS4gVGhlcmUgYXJlIGZvdXIgdGFsa2VycywgM2YgMW0uIFRyaWFscyBpbiB3aGljaCB0aGUgbSBpcyB0aGUgb2RkIG9uZSBvdXQgYXJlIGtub3duIHRvIGJlIGVhc2llc3QgYW5kIHRob3NlIHdoZXJlIG9uZSBvZiB0aGUgc3BlYWtlcnMgaXMgbSBidXQgaXQgaXMgbm90IHRoZSBvZGQgb25lIG91dCBhcmUgZWFpc2VzdC4gVEhlcmUgYXJlIGFuIGVxdWFsIG51bWJlciBvZiBlYWNoIHRyaWFsIHR5cGUgYW5kIHdlIHB1dCAgdHJpYWwgdHlwZSBpbnRvIHRoZSBtb2RlbCBhcyBhIGZhY3RvcjsgdGhvdWdoIGFnYWluIGl0IGlzbid0IGEgcXVlc3Rpb24gZm9yIHdoaWNoIHdlIGhhdmUgcHJlZGljdGlvbnMuDQoNCkZvciB0aGUgaW50aWFsIGRhdGEgc2V0IGNvbGxlY3RlZCwgd2Ugd2lsbCBjb25zaWRlciBib3RoIHByZS10ZXN0IC0+IHBvc3R0ZXN0MSBhbmQgcHJlLXRlc3QgLT4gcG9zdC10ZXN0MiAoaWYgZXF1aXZsYWVudCByZXN1bHRzIG9idGFuZWQsIHN1YnNlcXVlbnRpbmcgdGVzdGluZyB3aWxsIGRyb3AgZmluYWwgdHdvIHNlc3Npb25zIC0gc2VlIG5vdGUgYWJvdmUpDQoNCiMjIGxvYWQgdXAgYW5kIHJ1biBsbWVzIG9uIHJlbGV2YW50IHBpbG90IGRhdGENCg0KVGhlIHBpbG90IGNoaWxkIGRhdGEgYmVsb3cgY29tZSBmcm9tIHNhbWUgMi1zZXNzaW9uIHN0dWR5IGFzIHBpbG90IHRyYW5pbmcgZGF0YSAocmVjYWxsIHRoZXkgd2VyZSB0cmFpbmVkIG9uIHN0aW11bGkgc2ltaWxhciB0byB0aGUgInBpY3R1cmUtb25seSIgY29uZGl0aW9uIGluIHRoZSBjdXJyZW50IHN0dWR5LikNCg0KVGhlIGFkdWx0ICBkYXRhIGJlbG93IGNvbWUgZnJvbSBhIGRpZmZlcmVudCB0d28tIHNlc3Npb24gc3R1ZHkgd2hlcmUgdGhlcmUgd2VyZSB0d28gY29uZGl0aW9uICgxKSB0cmFpbmVkIG9uIHN0aW11bGkgc2ltaWxhciB0byB0aGUgInBpY3R1cmUtb25seSIgY29uZGl0aW9uIGluIHRoZSBjdXJyZW50IHN0dWR5ICgyKSB0cmFpbmVkIG9uIHBpY3R1cmVzIEpVU1Qgb2YgdGhlIGRpYWNyaXRpY3MuIFRoaXMgaXMgdXNlZnVsIGZvciBjb25zaWRlcmluZyBwb3NzaWJsZSBlZmZlY3RzIG9mIGNvbmRpdGlvbiBpbiB0aGUgZGF0YSAodGhvdWdoIHdpdGggdGhlIGNhdmVhdCB0aGF0IGNvbXBhcmlzb24gaXMgc29tZXdoYXQgZGlmZmVyZW50KS4NCg0KTm90ZSB0aGF0IGZvciBib3RoIGFkdWx0cyBhbmQgY2hpbGRyZW4gaW4gdGhlIHBpbG90IGV4cGVyaWVtbnQgd2UgaGFkIGJvdGggdHJhaW5lZCBhbmQgdW50cmFpbmVkIGl0ZW1zLiBGb3IgdGhpcyBleHBlcmltZW50IHdlIHVzZSBvbmx5IHVudHJhaW5lZCBpdGVtcyBpbiB0aGlzIHRlc3Qgc28gd2UgcmVtb3ZlIHRoZSB1bnRyYWluZWQgaXRlbXMgZnJvbSB0aGUgYW5hbHlzZXMgYmVsb3cuDQoNCk5vdGU6IHRvbmVjb250cmFzdCBpcyBmaXhlZCBlZmZlY3Qgd2l0aCA2IGxldmVscyAoc2l4IHBvc3NpYmxlIGNvbnRyYXN0cykuIEl0IGlzIGV4cGVjdGVkIHRvIGNvbnRyaWJ1dGUgdG8gbW9kZWwgYW5kIGlzIHRodXMgaW5jbHVkZWQgYnV0IGlzbid0IG9mIHNwZWNpZmljIGludGVyZXN0Lg0KYGBge3J9DQpjaGlsZC5kaXNjcmltID0gcmVhZC5jc3YoImtpZHNkaXNjcmltX2NsZWFuLmNzdiIpDQphZHVsdC5kaXNjcmltID0gcmVhZC5jc3YgKCJhZHVsdHNkaXNjcmltX2NsZWFuLmNzdiIpDQpjaGlsZC5kaXNjcmltJHByZV9wb3N0ID0gcmVsZXZlbChjaGlsZC5kaXNjcmltJHByZV9wb3N0LCByZWY9InByZSIpDQpjaGlsZC5kaXNjcmltJGFnZWdyb3VwID0gYXMuZmFjdG9yKGNoaWxkLmRpc2NyaW0kYWdlZ3JvdXApDQoNCmFkdWx0LmRpc2NyaW0kcHJlX3Bvc3QgPSByZWxldmVsKGFkdWx0LmRpc2NyaW0kcHJlX3Bvc3QsIHJlZj0icHJlIikNCmFkdWx0LmRpc2NyaW0kY29uZGl0aW9uID0gcmVsZXZlbChhZHVsdC5kaXNjcmltJGNvbmRpdGlvbiwgcmVmPSJpIikNCg0KY2hpbGQuZGlzY3JpbSRwcmVfcG9zdCA9IHJlbGV2ZWwoY2hpbGQuZGlzY3JpbSRwcmVfcG9zdCwgcmVmPSJwcmUiKQ0KDQphZHVsdC5kaXNjcmltPC0gZHJvcGxldmVscyhzdWJzZXQoYWR1bHQuZGlzY3JpbSwgbmV3b3JvbGQgPT0gIm5ld3dvcmQiKSkNCmNoaWxkLmRpc2NyaW08LSBkcm9wbGV2ZWxzKHN1YnNldChjaGlsZC5kaXNjcmltLCBuZXdvcm9sZCA9PSAibmV3d29yZCIpKQ0KYGBgDQoNCg0KYGBge3J9DQphZHVsdC5kaXNjcmltIDwtIGxpekNlbnRlcihhZHVsdC5kaXNjcmltLCBsaXN0KCJwcmVfcG9zdCIsInRyaWFsdHlwZSIsICJjb25kaXRpb24iLCAidG9uZWNvbnRyYXN0IikpDQoNCmFkdWx0LmRpc2NyaW0ubW9kID0gZ2xtZXIgKGNvcnJlY3Qgfg0KICAgICAgICAgICAgICAgICsgY29uZGl0aW9uLmN0ICogcHJlX3Bvc3QuY3QNCiAgICAgICAgICAgICAgICArIHRyaWFsdHlwZS5jdCANCiAgICAgICAgICAgICAgICArIHRvbmVjb250cmFzdC5jdA0KICAgICAgICAgICAgICAgICsgKHByZV9wb3N0LmN0fHBhcnRpY2lwYW50bnVtYmVyKSwNCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBhZHVsdC5kaXNjcmltLCAgZmFtaWx5ID0gYmlub21pYWwsIGNvbnRyb2w9Z2xtZXJDb250cm9sKG9wdGltaXplciA9ICJib2J5cWEiKSkNCg0Kcm91bmQoc3VtbWFyeShhZHVsdC5kaXNjcmltLm1vZCkkY29lZmZpY2llbnRzLCAzKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCmNoaWxkLmRpc2NyaW0uNyA9IGRyb3BsZXZlbHMoc3Vic2V0KGNoaWxkLmRpc2NyaW0sIGFnZWdyb3VwID09ICI3IikpDQoNCmNoaWxkLmRpc2NyaW0uNyA8LSBsaXpDZW50ZXIoY2hpbGQuZGlzY3JpbS43LCBsaXN0KCJwcmVfcG9zdCIsInRyaWFsdHlwZSIsICJjb25kaXRpb24iLCAidG9uZWNvbnRyYXN0IikpDQoNCmNoaWxkLmRpc2NyaW0uNy5tb2QgPSBnbG1lciAoY29ycmVjdCB+DQogICAgICAgICAgICAgICAgKyBwcmVfcG9zdC5jdA0KICAgICAgICAgICAgICAgICsgdHJpYWx0eXBlLmN0IA0KICAgICAgICAgICAgICAgICsgdG9uZWNvbnRyYXN0LmN0DQogICAgICAgICAgICAgICAgKyAocHJlX3Bvc3QuY3R8cGFydGljaXBhbnRudW1iZXIpLA0KICAgICAgICAgICAgICAgICAgZGF0YSA9IGNoaWxkLmRpc2NyaW0uNywgIGZhbWlseSA9IGJpbm9taWFsLCBjb250cm9sPWdsbWVyQ29udHJvbChvcHRpbWl6ZXIgPSAiYm9ieXFhIikpDQoNCnJvdW5kKHN1bW1hcnkoY2hpbGQuZGlzY3JpbS43Lm1vZCkkY29lZmZpY2llbnRzLCAzKQ0KDQoNCmBgYA0KDQoNCg0KIyMgUHJlZGljdGlvbjE6IEltcHJvdmVtZW50IGZyb20gcHJlLXBvc3QgdGVzdCBpbiBlYWNoICBlYWNoIGNvbmRpdGlvbg0KIyMjIEJhc2VkIG9uDQoNCkluIHRoZSBwaWxvdCBkYXRhLCBhZHVsdHMgc2hvdyBpbXByb3ZlbWVudCB3aXRoIHNlc3Npb24gYnV0IG5laXRoZXIgNyB5ZWFyIG9sZHMgZGlkbid0IChuYiBub3IgZGlkIDExIHllYXIgb2xkcykNCg0KbWVhbnMgOiBgciByb3VuZCggd2l0aChhZHVsdC5kaXNjcmltLCB0YXBwbHkoY29ycmVjdCwgcHJlX3Bvc3QsIG1lYW4sIG5hLnJtPVQpKSAsMilgOw0KbG9nIG9kZHMgKGJldGEgZnJvbSBsbWUpOiBgciBzdW1tYXJ5KGFkdWx0LmRpc2NyaW0ubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl1gOw0Kb2RkICAoZXhwKGJldGEpKWByIGV4cChzdW1tYXJ5KGFkdWx0LmRpc2NyaW0ubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl0pYA0KDQo3eWVhciBvbGRzIChkb24ndCBzaG93IHRoaXMtIGluIGZhY3QgbWVhbnMgcmV2ZXJzZWQgKQ0KDQptZWFucyA6IGByIHJvdW5kKCB3aXRoKGNoaWxkLmRpc2NyaW0uNywgdGFwcGx5KGNvcnJlY3QsIHByZV9wb3N0LCBtZWFuLCBuYS5ybT1UKSkgLDIpYDsNCmxvZyBvZGRzIChiZXRhIGZyb20gbG1lKTogYHIgc3VtbWFyeShjaGlsZC5kaXNjcmltLjcubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl1gOw0Kb2RkICAoZXhwKGJldGEpKWByIGV4cChzdW1tYXJ5KGNoaWxkLmRpc2NyaW0uNy5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXSlgDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBGcmVxdWVudGlzdCANCmxtZSBtb2RlbCBzaW1pbGFyIHRvIHRoYXQgb24gcGlsb3QgZGF0YSBhYm92ZSBidXQgd2l0aCBkYXRhIGZyb20gYm90aCBjb25kaXRpb25zOyBGaXQgc2VwYXJhdGUgc2xvcGVzIGZvciBwcmUtcG9zdCBpbiBlYWNoIGNvbmRpdGlvbiANCg0KRm9yIHRoZSBpbnRpYWwgZGF0YSBzZXQgY29sbGVjdGVkIHdlIHdpbGwgZG8gdGhpcyBib3RoIHRvIGNvbXBhcmUgcHJlIHRlc3QgdG8gcG9zdC10ZXN0IDEgYW5kIHByZS10ZXN0IHRvIHBvc3QtdGVzdDIgKHNlZSBub3RlcyBhYm92ZSkuDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBCRiANCg0KU3VtbWFyeSBvZiBkYXRhIGZvciBlYWNoIGNvbmRpdGlvbjogbWVhbiBhbmQgc2UgZm9yIHByZS1wb3N0IGZyb20gbG1lDQp2YWx1ZSB0byBpbmZvcm0gSDE6IGVzdGltYXRlIGZyb20gYWJvdmUgcGlsb3QgZGF0YSBmb3IgYWR1bHRzIGkuZS4gYHIgc3VtbWFyeShhZHVsdC5kaXNjcmltLm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdYA0KDQpOb3RlOiB0aGlzIGFkdWx0IHZhbHVlIHdpbGwgbGlrZWx5IG92ZXJlc3RpbWF0ZSB0aGUgbWVhbnMuIEEgYmV0dGVyIHZhbHVlIHdvdWxkIGNvbWUgZnJvbSB0aGUgbmV3IGRhdGEgZnJvbSBjaGlsZHJlbiB0aGVtc2VsdmVzIC0gdGhlcmVmb3JlLCBpZiB0aGV5IHNob3cgbGVhcmluZyBpbiBvbmUgY29uZGl0aW9uIHdlIHdpbGwgdXNlIHRoYXQgdG8gaW5mb3JtIEJGIGZvciB0aGUgb3RoZXIgY29uZGl0aW9uIChhbmQgaWYgYm90aCBzaG93IGxlYXJuaW5nIHdlIHdpbGwgdXNlIHRvIGluZm9ybSBCRiBmb3IgZWFjaCBvdGhlcikuIA0KDQoNCg0KDQojIyMgUmVxdWlyZWQgc2FtcGxlIGFuYWx5c2VzDQojIyMjIEZyZXF1ZW50aXN0IFBvd2VyDQoNCk5vdGU6IHRoaXMgYW5hbHlzaXMgaW5jbHVkZWQgZm9yIGNvbXBsZXRlbmVzcyBidXQgaXMgbm90IHJlYWxseSByZWxldmFudCBzaW5jZSBpdCBpcyBiYXNlZCBvbiBhZHVsdCBkYXRhLiBJZiBjaGlsZHJlbiBkbyBzaG93IGFuIGVmZmVjdCwgaXQgaXMgbGlrZWx5IHNtYWxsZXIgYW5kIHRoZXkgd2lsbCBoYXZlIGxhcmdlciBTRSAgDQoNCmBgYHtyfQ0KZGF0YVM9d2l0aChkcm9wbGV2ZWxzKGFkdWx0LmRpc2NyaW0pLCB0YXBwbHkoY29ycmVjdCxsaXN0KHBhcnRpY2lwYW50bnVtYmVyLCBwcmVfcG9zdCksIG1lYW4sIG5hLnJtPVQpKQ0KZCA9IGNvaGVuc0QoeCA9IGFzLm51bWVyaWMoZGF0YVNbLDFdKSx5ID0gYXMubnVtZXJpYyhkYXRhU1ssMl0pLCBtZXRob2QgPSAicGFpcmVkIikNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC45LCAgdHlwZSA9IGMoInBhaXJlZCIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuOCwgIHR5cGUgPSBjKCJwYWlyZWQiKSwgYWx0ZXJuYXRpdmUgPSBjKCAiZ3JlYXRlciIpKQ0KcHdyLnQudGVzdChuID0gTlVMTCwgZCA9IGQsIHNpZy5sZXZlbCA9IDAuMDUsIHBvd2VyID0gLjcsICB0eXBlID0gYygicGFpcmVkIiksIGFsdGVybmF0aXZlID0gYyggImdyZWF0ZXIiKSkNCg0Kcm0oZCkNCnJtKGRhdGFTKQ0KYGBgDQoNCg0KIyMjIyBSZXF1aXJlZCBzYW1wbGUgZm9yIEJGIGFuYWx5c2VzIGZyb20gcGlsb3QgZGF0YQ0KDQpIZXJlIHdlIGxvb2sgYXQgZGF0YSBmcm9tIDcgeWVhciBvbGRzIGluIHBpbG90ICBhbmQgDQpgYGB7cn0NCm1lYW5CRiA9IHN1bW1hcnkoY2hpbGQuZGlzY3JpbS43Lm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdDQpzZUJGID0gc3VtbWFyeShjaGlsZC5kaXNjcmltLjcubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIlN0ZC4gRXJyb3IiXQ0KaDFtZWFuID0gc3VtbWFyeShhZHVsdC5kaXNjcmltLm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdDQoNCkJmKHNlQkYsIG1lYW5CRiwgIHVuaWZvcm0gPTAsbWVhbm9mdGhlb3J5PTAsc2R0aGVvcnk9aDFtZWFuLHRhaWw9MSkNCg0Kcm0obWVhbkJGKQ0Kcm0oc2VCRikNCnJtKGgxbWVhbikNCmBgYA0KSGF2ZSBldmlkZW5jZSBmb3IgdGhlIG51bGwgZnJvbSBqdXN0IDE1IHBhcnRpY2lwYW50cy4gTm90ZSBob3dldmVyLCB0aGF0IHdlIGFyZSByZWxhdGl2ZWx5IGhpZ2ggZXN0aW1hdGUgZm9yIEgxLCB3aGljaCBtYXkgbWFrZSBpdCBlYXNpZXIgdG8gZmluZCBldmlkZW5jZSBmb3IgdGhlIG51bGwuDQoNCg0KIyMgUHJlZGljdGlvbjI6IE1vcmUgaW1wcm92ZW1lbnQgaW4gb25lIGNvbmRpdGlvbiB0aGFuIHRoZSBvdGhlcg0KDQojIyMgQmFzZWQgb24NCg0KV2UgZG9uJ3QgaGF2ZSBhbnkgc3BlY2lmaWMgZXZpZGVuY2UgdG8gYmFzZSB0aGlzIG9uLiBUaGUgY2xvc2VzdCBjb250cmFzdHMgd2FzIGluIHRoZSBhZHVsdCBwaWxvdCBleHBlcmltZW50IChjb21wYXJpbmcgY29uZGl0aW9uIHdpdGggcGljdHVyZSBvbmx5IHRyYWluaW5nIHZlcnN1cyBkaWFjcml0aWMgb25seSB0cmFpbmluZykgd2hlcmUgdGhleSBzaG93ZWQgbnVtZXJpY2FsbHkgbW9yZSBpbXByb3ZlbWVudCBpbiB0aGUgaW1wbGljaXQgY29uZGl0aW9uLCBidXQgdGhlIGRpZmZlcmVuY2Ugd2FzIE5TLg0KDQptZWFucyA6IGByIHJvdW5kKCB3aXRoKGFkdWx0LmRpc2NyaW0sIHRhcHBseShjb3JyZWN0LCBsaXN0KHByZV9wb3N0LCBjb25kaXRpb24pLCBtZWFuLCBuYS5ybT1UKSkgLDIpYA0KbG9nIG9kZHMgKGJldGEgZnJvbSBsbWUpOiBgciBzdW1tYXJ5KGFkdWx0LmRpc2NyaW0ubW9kKSRjb2VmZmljaWVudHNbImNvbmRpdGlvbi5jdDpwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdYA0Kb2RkICAoZXhwKGJldGEpKWByIGV4cChzdW1tYXJ5KGFkdWx0LmRpc2NyaW0ubW9kKSRjb2VmZmljaWVudHNbImNvbmRpdGlvbi5jdDpwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdKWANCg0KDQpGb3IgdGhlIGludGlhbCBkYXRhIHNldCBjb2xsZWN0ZWQgV3cgd2lsbCBkbyB0aGlzIGJvdGggdG8gY29tcGFyZSBwcmUgdGVzdCB0byBwb3N0LXRlc3QgMSBhbmQgcHJlLXRlc3QgdG8gcG9zdC10ZXN0MiAoc2VlIG5vdGVzIGFib3ZlKS4NCg0KIyMjIFBsYW5uZWQgQW5hbHlzZXM6IEZyZXF1ZW50aXN0DQoNCmxtZSBtb2RlbCBzaW1pbGFyIHRvIHRoYXQgb24gcGlsb3QgZGF0YSBhYm92ZSBidXQgd2l0aCBkYXRhIGZyb20gYm90aCBjb25kaXRpb25zOyBsb29rIGZvciBpbnRlcmFjdGlvbiBiZXR3ZWVuIHByZS1wb3N0IGFuZCBjb25kaXRpb24uDQoNCiMjIyBQbGFubmVkIEFuYW5seXNlczogQkYNClN1bW1hcnkgb2YgZGF0YSBmb3IgZWFjaCBjb25kaXRpb246IG1lYW4gYW5kIHNlIGZvciBwcmUtcG9zdCpjb25kaXRpb24gZnJvbSBsbWUNCnZhbHVlIHRvIGluZm9ybSBIMTogZXN0aW1hdGUgZm9yIHNlc3Npb24gZnJvbSB0aGUgY3VycmVudCBtb2RlbCAgIChpLmUuIHN1bW1hcnkobmV3LmRhdGEpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXWANCg0KTm90ZTogd2Ugb25seSBkbyB0aGlzIGlmIHdlIGhhdmUgZXZpZGVuY2Ugb2YgYW4gZWZmZWN0IG9mIHByZS1wb3N0IGluIGF0IGxlYXN0IG9uZSBvZiB0aGUgY29uZGl0aW9ucy4gSWYgdGhleSBkb24ndCBsZWFybiBpbiBlaXRoZXIgY29uZGl0aW9uIHRoZW4gdGhpcyB0ZXN0IGlzIGluYXBwcm9wcmlhdGUuDQoNCkFsc28gbm90ZSB0aGF0IHRoaXMgd2lsbCBiZSByZWxhdGl2ZWx5IGNvbnNlcnZhdGl2ZSBlc3RpbWF0ZSBmb3IgYSBsYXJnZSBkaWZmZXJlbmNlIGluIGhvdyBtdWNoIHRoZSBjb25kaXRpb25zIGxlYWQgdG8gYSBjaGFuZ2UgcHJlIHRvIHBvc3QuIA0KKGFnYWluIHdpbGwgc2VlayBzdGF0aXN0aWFsIGFkdmljZSBoZXJlKQ0KDQojIyMgUmVxdWlyZWQgc2FtcGxlIGVzdGltYXRlcw0KIyMjIyBGcmVxdWVudGlzdCBQb3dlcg0KV2UgaGF2ZSBubyBkYXRhIHRvIGxvb2sgYXQgdGhpcyAoc2luY2Ugd2FzIG5vIHNpZy4gZGlmZmVyZW5jZSBpbiBkYXRhIGNvbGxlY3RlZCkNCg0KIyMjIyBSZXF1aXJlZCBzYW1wbGUgZm9yIEJGIGFuYWx5c2VzIGZyb20gcGlsb3QgZGF0YQ0KDQpIZXJlIHdlIGFyZSBsb29raW5nIGF0IHRoaXMgd2l0aCBhZHVsdCBkYXRhLg0KDQpgYGB7cn0NCm1lYW5CRiA9IHN1bW1hcnkoYWR1bHQuZGlzY3JpbS5tb2QpJGNvZWZmaWNpZW50c1siY29uZGl0aW9uLmN0OnByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl0NCnNlQkYgPSBzdW1tYXJ5KGFkdWx0LmRpc2NyaW0ubW9kKSRjb2VmZmljaWVudHNbImNvbmRpdGlvbi5jdDpwcmVfcG9zdC5jdCIgLCJTdGQuIEVycm9yIl0NCmgxbWVhbiA9IHN1bW1hcnkoYWR1bHQuZGlzY3JpbS5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXQ0KDQpCZihzZUJGLCBtZWFuQkYsICB1bmlmb3JtID0wLG1lYW5vZnRoZW9yeT0wLHNkdGhlb3J5PWgxbWVhbix0YWlsPTIpDQpwbG90KEJmX3Bvd2VyY2FsYyhzZUJGLCBtZWFuQkYsICB1bmlmb3JtID0wLG1lYW5vZnRoZW9yeT0wLHNkdGhlb3J5PWgxbWVhbiwgTj0xNSwgbWluPTkwMCwgbWF4ID0gNTAsIHRhaWw9MikpDQphYmxpbmUoaD0zKQ0KQmZfcG93ZXJjYWxjKHNlQkYsIG1lYW5CRiwgIHVuaWZvcm0gPTAsbWVhbm9mdGhlb3J5PTAsc2R0aGVvcnk9aDFtZWFuLCBOPTE1LCBtaW49ODExLCBtYXggPSA4MTUsIHRhaWw9MikNCg0Kcm0obWVhbkJGKQ0Kcm0oc2VCRikNCnJtKGgxbWVhbikNCmBgYA0KDQpHZW5lcmFsIG5vdGU6IHRoaXMgYW5hbHlzaXMgc3VnZ2VzdHN0IHRoYXQgZXZlbiBmb3IgYWR1bHRzLCB3b3VsZG4ndCBuZWVkIGEgc2FtcGxlIG9mIG92ZXIgODAwIHBhcnRpY2lwYW50cyBwZXIgY29uZGl0aW9uIHRvIHNlZSB0aGlzIGludGVyYWN0aW9uLiBUaGlzIGlzIGltcGxhdXNpYmxlICh0aG91Z2ggbWF5IGJlIHBhcnRseSBiZWNhdXNlIGFyZSBiYXNpbmcgb24gb3ZlciBjb25zZXJ2YXRpdmUgdmFsdWUgZm9yIGgxKS4NCg0KSG93ZXZlciB0aGlzIGFuYWx5c2lzIHN1Z2dlc3RzIGl0IHdpbGwgYmUgZGlmZmljdWx0IHRvIGdhaW4gcG93ZXIgZm9yIHRoaXMgaW50ZXJhY3Rpb24uIE9uIHRoZSBvdGhlciBoYW5kLCBwcmV2aW91cyBhbmFseXNlcyBtYXkgbWFrZSBpdCBjbGVhciB0aGF0IHRoZXJlIGlzIG5vIGltcHJvdmVtZW50IG9uIHRoaXMgdGVzdCBpbiBFSVRIRVIgY29uZGl0aW9uIChzZWUgUHJlZGljdGlvbiAxIGFib3ZlKS4gSW4gdGhhdCB0aGF0IGl0IG1heSBiZSB2ZXJ5IGRpZmZpY3VsdCB0byBwb3dlciB0aGlzLiBPbmUgcG9zc2liaWxpdHkgaXMgdGhhdCB3ZSB3b24ndCBoYXZlIHBvd2VyIGZvciB0aGUgaW50ZXJhY3Rpb24gYnV0IHdpbGwgaGF2ZSBwb3dlciB0byBzYXkgd2UgaGF2ZSAgZXZpZGVuY2UgZm9yIGxlYXJuaW5nIGluIG9uZSBjb25kaXRpb24sIGJ1dCBmb3IgdGhlIG90aGVyIHRoZXJlIGlzIG1vcmUgZXZpZGVuY2UgZm9yIHRoZSBudWxsIHRoYW4gZm9yIEgxIGJhc2VkIG9uIHRoYXQgY29uZGl0aW9uLiANCg0KDQojIFdvcmQgcmVwZXRpdGlvbg0KDQpUaGlzIHRlc3QgaXMgZ2l2ZW4gcHJlIGFuZCBwb3N0LiBDaGlsZHJlbiBoZWFyIGEgd29yZCBhbmQgY29weSBpdCBiYWNrLiBXZSBsb29rIHRvIHNlZSBpZiB0aGV5IHJlcGVhdCBiYWNrIHRoZSB0b25lIGNvcnJlY3RseSAodGhleSB3aWxsIGJlIGNvZGVkIGJ5IG5hdGl2ZSBzcGVha2VycyB3aG8gYmxpbmQgYXMgdG8gYm90aCBjb25kaXRpb24gYW5kIHdoYXQgdGhlIHRhcmdldCB3b3JkIGlzOyAgdGhlIHRvbmUgb2YgdGhlIHRyYW5zY3JpYmVkIHdvcmQgd2lsbCBjb21wYXJlZCB0byB0b25lIG9mIHRhcmdldCBhbmQgdGh1cyBjb2RlZCBhcyBjb3JyZWN0L2luY29ycmVjdCkuDQoNClRoZXJlIGFyZSBlcXVhbCBudW1iZXIgb2Ygd29yZHMgZm9yIGVhY2ggb2YgdGhlIGZvdXIgdG9uZXMuDQoNCkZvciB0aGUgaW50aWFsIGRhdGEgc2V0IGNvbGxlY3RlZCwgd2lsbCBjb25zaWRlciBib3RoIHByZS10ZXN0IC0+IHBvc3R0ZXN0MSBhbmQgcHJlLXRlc3QgLT4gcG9zdC10ZXN0MiAoaWYgZXF1aXZhbGVudCByZXN1bHRzIG9idGFuZWQsIHN1YnNlcXVlbnRpbmcgdGVzdGluZyB3aWxsIGRyb3AgZmluYWwgdHdvIHNlc3Npb25zIC0gc2VlIG5vdGUgYWJvdmUpDQoNCg0KIyMgbG9hZCB1cCBhbmQgcnVuIGxtZXMgb24gcGlsb3QgZGF0YQ0KDQpUaGUgY2hpbGQgZGF0YSBiZWxvdyBjb21lIGZyb20gc2FtZSB0d28gc2Vzc2lvbiBzdHVkeSBhcyBwaWxvdCB0cmFuaW5nIGRhdGEvZGlzY3JpbSBkYXRhIChpLmUgIHdoZXJlIHRoZXkgd2VyZSB0cmFpbmVkIG9uIHN0aW11bGkgc2ltaWxhciB0byB0aGUgInBpY3R1cmUtb25seSIgY29uZGl0aW9uIGluIHRoZSBjdXJyZW50IHN0dWR5LikNCg0KDQpUaGUgYWR1bHQgZGF0YSBiZWxvdyBkbyBub3QgY29tZSBmcm9tIHRoZSBzYW1lIHR3byBkYXkgcGlsb3Qgc3R1ZHkgYXMgdGhlIG90aGVyIGFkdWx0IGRhdGEgdXNlZCBhYm92ZSAodGhhdCBzdHVkZW50IHByb2plY3QgZGlkbid0IGluY2x1ZGUgdGhpcyB0ZXN0KSwgYnV0IGluc3RlYWQgZnJvbSBhIG11Y2ggbG9uZ2VyIDkgc2Vzc2lvbiBleHBlcmltZW50IGNvbmR1Y3RlZCBieSBjdXJyZW50IFBoRCBzdHVkZW50LiBUaGVyZSB3YXMgbm8gY29udHJhc3Qgb2YgY29uZGl0aW9uIG9mIHRoZSB0eXBlIHJlbGV2YW50IHRvIHRoZSBjdXJyZW50IHN0dWR5IGluIHRoYXQgZGF0YS4gDQoNCk5vdGUgdGhhdCBmb3IgYm90aCBhZHVsdHMgYW5kIGNoaWxkcmVuIGluIHBpbG90IGV4cGVyaW1lbnRzIHVzaW5nIHRoaXMgdGVzdCAgd2UgaGFkIGJvdGggdHJhaW5lZCBhbmQgdW50cmFpbmVkIGl0ZW1zLiBGb3IgdGhpcyBleHBlcmltZW50IHdlIHVzZSBvbmx5IHVudHJhaW5lZCBpdGVtcyBpbiB0aGlpcyB0ZXN0IHNvIHdlIHJlbW92ZSB0aGUgdW50cmFpbmVkIGl0ZW1zIGZyb20gdGhlIGFuYWx5c2VzIGJlbG93Lg0KDQoNCmBgYHtyfQ0KDQpjaGlsZC53ciA9IHJlYWQuY3N2KCJraWRzd29yZHJlcF9jbGVhbi5jc3YiKQ0KYWR1bHQud3IgPSByZWFkLmNzdigiYWR1bHRzd29yZHJlcF9jbGVhbi5jc3YiKQ0KDQpjaGlsZC53ciA9IGRyb3BsZXZlbHMoc3Vic2V0KGNoaWxkLndyLCB3b3JkdHlwZSA9PSAibmV3IikpDQoNCmFkdWx0LndyID0gZHJvcGxldmVscyhzdWJzZXQoYWR1bHQud3IsIHdvcmR0eXBlID09ICJVbnRyYWluZWQiKSkNCg0KY2hpbGQud3IkcHJlX3Bvc3QgPSByZWxldmVsKGNoaWxkLndyJHByZV9wb3N0LCByZWYgPSAicHJlIikNCmFkdWx0LndyJHByZV9wb3N0ID0gcmVsZXZlbChhZHVsdC53ciRwcmVfcG9zdCwgcmVmID0gInByZSIpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KDQpjaGlsZC53ci43ID0gZHJvcGxldmVscyhzdWJzZXQoY2hpbGQud3IsIEFnZT09InlvdW5nIikpDQoNCmNoaWxkLndyLjcgPC0gbGl6Q2VudGVyKGNoaWxkLndyLjcsIGxpc3QoIkFnZSIsICJwcmVfcG9zdCIsImNvcnJlY3R0b25lIikpDQoNCmNoaWxkLndyLjcubW9kID0gZ2xtZXIgKHJlc3VsdHRvbmUgfg0KICAgICAgICAgICAgICAgICsgcHJlX3Bvc3QuY3QgDQogICAgICAgICAgICAgICAgKyBjb3JyZWN0dG9uZS5jdA0KICAgICAgICAgICAgICAgICsgKHByZV9wb3N0LmN0fHBhcnRpY2lwYW50bmFtZSksDQogICAgICAgICAgICAgICAgICBkYXRhID0gY2hpbGQud3IuNywgIGZhbWlseSA9IGJpbm9taWFsLCBjb250cm9sPWdsbWVyQ29udHJvbChvcHRpbWl6ZXIgPSAiYm9ieXFhIikpDQoNCg0Kcm91bmQoc3VtbWFyeShjaGlsZC53ci43Lm1vZCkkY29lZmZpY2llbnRzLDMpDQoNCg0KYGBgDQoNCg0KDQoNCg0KYGBge3J9DQoNCmFkdWx0LndyIDwtIGxpekNlbnRlcihhZHVsdC53ciwgbGlzdCggInByZV9wb3N0IiwiY29ycmVjdHRvbmUiKSkNCg0KYWR1bHQud3IubW9kID0gZ2xtZXIgKHJlc3VsdHRvbmUgfg0KICAgICAgICAgICAgICAgICsgcHJlX3Bvc3QuY3QgDQogICAgICAgICAgICAgICAgKyBjb3JyZWN0dG9uZS5jdA0KICAgICAgICAgICAgICAgICsgKHByZV9wb3N0LmN0fHBhcnRpY2lwYW50bmFtZSksDQogICAgICAgICAgICAgICAgICBkYXRhID0gYWR1bHQud3IsICBmYW1pbHkgPSBiaW5vbWlhbCwgY29udHJvbD1nbG1lckNvbnRyb2wob3B0aW1pemVyID0gImJvYnlxYSIpKQ0KDQoNCnJvdW5kKHN1bW1hcnkoYWR1bHQud3IubW9kKSRjb2VmZmljaWVudHMsMykNCg0KDQpgYGANCiMjIFByZWRpY3Rpb24xOiBJbXByb3ZlbWVudCBmcm9tIHByZS1wb3N0IHRlc3QgaW4gZWFjaCAgZWFjaCBjb25kaXRpb24NCg0KIyMjIEJhc2VkIG9uIA0KDQpCb3RoIGFkdWx0cyBhbmQgY2hpbGRyZW4gc2hvd2VkIHRoaXMgaW4gdGhlIHJlbGV2YW50IHBpbG90IHN0dWRpZXMNCg0KYWR1bHQgbWVhbiA6IGByIHJvdW5kKCB3aXRoKGFkdWx0LndyLCB0YXBwbHkocmVzdWx0dG9uZSwgbGlzdChwcmVfcG9zdCksIG1lYW4sIG5hLnJtPVQpKSAsMilgOw0KYWR1bHQgIGxvZyBvZGRzIChiZXRhIGZyb20gbG1lKTogYHIgc3VtbWFyeShhZHVsdC53ci5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXWA7DQphZHVsdCAgb2RkICAoZXhwKGJldGEpKWByIGV4cChzdW1tYXJ5KGFkdWx0LndyLm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdKWANCg0KN3llYXIgbWVhbiA6YHIgcm91bmQoIHdpdGgoY2hpbGQud3IuNywgdGFwcGx5KHJlc3VsdHRvbmUsIGxpc3QocHJlX3Bvc3QpLCBtZWFuLCBuYS5ybT1UKSkgLDIpYDsNCjd5ZWFyICBsb2cgb2RkcyAoYmV0YSBmcm9tIGxtZSk6IGByIHN1bW1hcnkoY2hpbGQud3IuNy5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXWA7DQo3eWVhciAgb2RkICAoZXhwKGJldGEpKWByIGV4cChzdW1tYXJ5KGNoaWxkLndyLjcubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl0pYA0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogRnJlcXVlbnRpc3QgDQpsbWUgbW9kZWwgc2ltaWxhciB0byB0aGF0IG9uIHBpbG90IGRhdGEgYWJvdmUgYnV0IHdpdGggZGF0YSBmcm9tIGJvdGggY29uZGl0aW9uczsgRml0IHNlcGFyYXRlIHNsb3BlcyBmb3IgcHJlLXBvc3QgaW4gZWFjaCBjb25kaXRpb24gDQoNCkZvciB0aGUgaW50aWFsIGRhdGEgc2V0IGNvbGxlY3RlZCBXZSB3aWxsIGRvIHRoaXMgYm90aCB0byBjb21wYXJlIHByZSB0ZXN0IHRvIHBvc3QtdGVzdCAxIGFuZCBwcmUtdGVzdCB0byBwb3N0LXRlc3QyIChzZWUgbm90ZXMgYWJvdmUpLg0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogQkYgDQpTdW1tYXJ5IG9mIGRhdGEgZm9yIGVhY2ggY29uZGl0aW9uOiBtZWFuIGFuZCBzZSBmb3IgcHJlLXBvc3QgZnJvbSBsbWUNCnZhbHVlIHRvIGluZm9ybSBIMTogZXN0aW1hdGUgZnJvbSBhYm92ZSBwaWxvdCBkYXRhIGZvciBjaGlsZHJlbiBpLmUuIGByIHN1bW1hcnkoY2hpbGQud3IuNy5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXWANCg0KTk9URTogSWYgKGUuZy4pIHdlIGZpbmQgYW4gZWZmZWN0IGZvciBjb25kaXRpb24xLCB3ZSBjYW4gYWxzbyB1c2UgdGhlIGVzdGltYXRlIGZvciBzZXNzaW9uIGZvciB0aGF0IHRvIGluZm9ybSBIMSB3aGVuIGxvb2tpbmcgYXQgZGF0YSBmcm9tIGNvbmRpdGlvbjI7IGFuZCB2aWNlIHZlcnNhLiBUaGlzIGlzIGEgYmV0dGVyIGVzdGltYXRlIHNpbmNlIHRoZSBjb25kaXRpb25zIGFyZSBtb3JlIGNsb3NlbHkgbWF0Y2hlZCB0byBlYWNoIG90aGVyIHRoYW4gZWl0aGVyIGlzIHRvIHRoZSBwaWxvdCBkYXRhLw0KDQojIyMgUmVxdWlyZWQgc2FtcGxlIGFuYWx5c2VzDQojIyMjIEZyZXF1ZW50aXN0IFBvd2VyDQoNCk5vdGU6IHRoaXMgYW5hbHlzaXMgaW5jbHVkZWQgZm9yIGNvbXBsZXRlbmVzcyBidXQgaXMgbm90IHJlYWxseSByZWxldmFudCBzaW5jZSBpdCBpcyBiYXNlZCBvbiBhZHVsdCBkYXRhLiBJZiBjaGlsZHJlbiBkbyBzaG93IGFuIGVmZmVjdCwgaXQgaXMgbGlrZWx5IHNtYWxsZXIgYW5kIHRoZXkgd2lsbCBoYXZlIGxhcmdlciBTRSAgDQoNCjcNCmBgYHtyfQ0KZGF0YVMgPSB3aXRoKGRyb3BsZXZlbHMoY2hpbGQud3IuNyksIHRhcHBseShyZXN1bHR0b25lLGxpc3QocGFydGljaXBhbnRuYW1lLHByZV9wb3N0KSwgbWVhbiwgbmEucm09VCkpDQpkPSBjb2hlbnNEKHggPSBkYXRhU1ssMV0sIHkgPSBkYXRhU1ssMl0sIG1ldGhvZCA9ICJwYWlyZWQiKQ0KcHdyLnQudGVzdChuID0gTlVMTCwgZCA9IGQsIHNpZy5sZXZlbCA9IDAuMDUsIHBvd2VyID0gLjksICB0eXBlID0gYygicGFpcmVkIiksIGFsdGVybmF0aXZlID0gYyggImdyZWF0ZXIiKSkNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC44LCAgdHlwZSA9IGMoInBhaXJlZCIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuNywgIHR5cGUgPSBjKCJwYWlyZWQiKSwgYWx0ZXJuYXRpdmUgPSBjKCAiZ3JlYXRlciIpKQ0KDQpybShkYXRhUykNCnJtKGQpDQpgYGANCg0KU2FtcGxlIGVzdGltYXRpb24gc3VnZ2VzdHMgdGhhdCBOPTMzIHBlciBjb25kaXRpb24gZm9yIDkwJSBwb3dlci4NCg0KIyMjIyBSZXF1aXJlZCBzYW1wbGUgZm9yIEJGIGFuYWx5c2VzIGZyb20gcGlsb3QgZGF0YQ0KDQpOb3RlIHRoYXQgaGVyZSB3ZSB1c2UgdGhlIG1lYW4gZnJvbSB0aGUgYWR1bHQgcGlsb3QgZGF0YSBhZHVsdHMgdG8gaW5mb3JtIEgxICh3aGVyZWFzIGZvciBhY3R1YWwgYW5hbHlzZXMgd2Ugd2lsbCBiZSB1c2luZyB2YWx1ZSBmcm9tIHBpbG90IGRhdGEgd2l0aCA3IHllYXIgb2xkcyB0byBpbmZvcm0gSDEpDQpgYGB7cn0NCg0KbWVhbkJGID0gc3VtbWFyeShjaGlsZC53ci43Lm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdDQpzZUJGID0gc3VtbWFyeShjaGlsZC53ci43Lm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJTdGQuIEVycm9yIl0NCmgxbWVhbiA9IHN1bW1hcnkoYWR1bHQud3IubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl0NCg0KQmYoc2VCRiwgbWVhbkJGLCAgdW5pZm9ybSA9MCxtZWFub2Z0aGVvcnk9MCxzZHRoZW9yeT1oMW1lYW4sdGFpbD0xKQ0KDQoNCnJtKG1lYW5CRikNCnJtKHNlQkYpDQoNCmBgYA0KDQpXZSBoYXZlIHN1ZmZpY2llbnQgZXZpZGVuY2UgZnJvbSB0aGUgc2FtcGxlIG9mIE49MTUgY2hpbGRyZW4gZm9yIEgxLiANCg0KIyMgUHJlZGljdGlvbiAyOiBUaGVyZSB3aWxsIGJlIG1vcmUgaW1wcm92ZW1lbnQgaW4gb25lICBjb25kaXRpb24gYnkgcHJlLXBvc3QNCiMjIEJhc2VkIG9uIA0KV2UgaGF2ZSBubyBkYXRhIHRvIGJhc2UgdGhpcyBvbiBhcyB3ZSBoYXZlbid0IHByZXZpb3VzbHkgdXNlZCB0aGlzIHRlc3QgaW4gYW4gZXhwZXJpbWVudCBjb250cmFzdGluZyB0aGVzZSAob3Igc2ltaWxhcikgY29uZGl0aW9ucy4NCg0KSWYgdGhlIHByZXNlbmNlIG9mIHRoZSBkaWFjcml0aWNzIGJvb3N0cyBsZWFybmluZywgY2hpbGRyZW4gbWF5IGltcHJvdmUgbW9yZSBpbiB0aGUgZGlhY3J0aWNpcytwaWN0dXJlIGNvbmRpdGlvbi4NCg0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogRnJlcXVlbnRpc3QgDQpsbWUgbW9kZWwgc2ltaWxhciB0byB0aGF0IG9uIHBpbG90IGRhdGEgYWJvdmUgYnV0IHdpdGggZGF0YSBmcm9tIGJvdGggY29uZGl0aW9uczsgbG9vayBmb3IgaW50ZXJhY3Rpb24gb2YgcHJlLXBvc3QgYW5kIGNvbmRpdGlvbg0KDQpGb3IgdGhlIGludGlhbCBkYXRhIHNldCBjb2xsZWN0ZWQgV3cgd2lsbCBkbyB0aGlzIGJvdGggdG8gY29tcGFyZSBwcmUgdGVzdCB0byBwb3N0LXRlc3QgMSBhbmQgcHJlLXRlc3QgdG8gcG9zdC10ZXN0MiAoc2VlIG5vdGVzIGFib3ZlKS4NCg0KIyMjIFBsYW5uZWQgQW5hbmx5c2VzOiBCRg0KU3VtbWFyeSBvZiBkYXRhIGZvciBlYWNoIGNvbmRpdGlvbjogbWVhbiBhbmQgc2UgZm9yIHByZS1wb3N0KmNvbmRpdGlvbiBmcm9tIGxtZQ0KdmFsdWUgdG8gaW5mb3JtIEgxOiBlc3RpbWF0ZSBmb3Igc2Vzc2lvbiBmcm9tIHRoZSBtb2RlbCB3aXRoIHRoZSBuZXcgZGF0YSAgKGkuZS4gc3VtbWFyeShuZXcuZGF0YSkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdYA0KDQpOb3RlOiB3ZSBvbmx5IGRvIHRoaXMgaWYgd2UgaGF2ZSBldmlkZW5jZSBvZiBhbiBlZmZlY3Qgb2YgcHJlLXBvc3QgaW4gYXQgbGVhc3Qgb25lIG9mIHRoZSBjb25kaXRpb25zLiBJZiB0aGV5IGRvbid0IGxlYXJuIGluIGVpdGhlciBjb25kaXRpb24gdGhlbiB0aGlzIHRlc3QgaXMgaW5hcHByb3ByaWF0ZS4NCg0KQWxzbyBub3RlIHRoYXQgdGhpcyB3aWxsIGJlIHJlbGF0aXZlbHkgY29uc2VydmF0aXZlIGVzdGltYXRlIGZvciBhIGxhcmdlIGRpZmZlcmVuY2UgaW4gaG93IG11Y2ggdGhlIGNvbmRpdGlvbnMgbGVhZCB0byBhIGNoYW5nZSBwcmUgdG8gcG9zdC4gDQoNCg0KIyMjIFJlcXVpcmVkIHNhbXBsZSBhbmFseXNlcw0KV2UgaGF2ZSBubyByZWxldmFudCBkYXRhIHRvIGNhbiBiYXNlIHRoaXMgb24gZm9yIGVpdGhlciBmcmVxdWVudGlzdCBvciBCRiBhbmFseXNlcy4gT25lIHBvc3NpYmlsaXR5IGlzIHRoYXQgd2Ugd29uJ3QgYmUgYWJsZSB0byBnZXQgYSBzdWZmaWNpZW50bHkgbGFyZ2Ugc2FtcGxlIHRvIGhhdmUgIHBvd2VyIGZvciB0aGlzIGludGVyYWN0aW9uLiBBcyBmb3Igb3RoZXIgdGVzdHMsIGhlcmUgd2UgbWF5IGhhdmUgdG8gZHJhdyB3aGF0ZXZlciBjb25jdWxzaW9uc2FyZSBwb3NzaWJsZSBiYXNlZCBvbiB3aGljaCBvZiB0aGUgY29uZGl0aW9ucyBpbmRpdmlkdWFsbHkgcHJvdmlkZXMgZXZpZGVuY2UgZm9yIEgxL0gwLg0K