Notes on updates

All that has been changed compared with previous script posted 18.06.17 (https://rstudio-pubs-static.s3.amazonaws.com/285969_da2f695ddb9540ac85089744626ca729.html) is that a menu has been added, some points about conditions have been clarified, and typos have been fixed. (Note in particular there as a typo re BF factors line 26)

General Notes

This contains planned analyses as of 18/06/2017 for a data set which we will start to collect on 19/06/2017. Plans may change as a result of statistical consultation (we are currently seeking advice on some details).

The study is a training study to be conducted with Year 3 (7-8 year old) children with no previous knowledge of Mandarin or any other tonal language, training them on the four tones (6 tone contrasts) in Mandarin. There will initially 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 accompanied by pictures of the four diacritics. [If resources permit, we may later run a diacritics only condition]. Data will be collected from the training task and from some test tasks conducted pre and post training.

Our main analyses will be Bayesian and we will compute Bayes factors using the method advocated by Dienes (2008, 2015); we will also alongside 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 - (i) we counterbalance trained/untrained wordlists across participants; (ii) it is not common for by items analyses to be included for work in this area; (iii) increasing the number of items in a learning study of this type with children is not feasible). We will use full random slopes structure for predictors of interest (generally, condition and session/pre->post). Factors such as tone contrast for the trial will be included as fixed factors but we will not include random slopes for these.

For the Bayesian analyses, we will continue to work in log odds space (as for frequentist analyses) 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 for H0 is BF<.33 [TYPO FIXED HERE FROM PREVIOUS]

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 undergraduate student projects. None were exactly the same as the experiment 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 analyses, we conducted the analyses as though for (near equivalent) t-tests over by subject proportions. This means that the values are only approximate, but since our main analyses are BF factors our aim here is to get an idea of approximate suitable sample sizes.

In addition to power analyses, where possible we also conducted Bayesian analyses on relevant parts of the pilot data to see if 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 varies as square root (N).

The analyses below suggest that there are cases where a sample of 20 participants per condition could be sufficient to achieve 90% power. Interactions with condition will be harder to power; as discussed below, there may be situations where there is evidence of H1 (i.e. data reflects learning) in condition1 but evidence for H0 (no evidence of learning in this data) for condition2. If so, we will deem this sufficient to draw conclusions about the different training methods.

Our policy will be as follows: we will inspect the data after we have approximately 20 participants in each condition (Note: this is approximate since we aim to collect this data by the end of the current academic year (July 2017); if we don’t quite get this many children, we will still look at the sample we have). If results for key analyses 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 word repetition training

session2 training post-tests: discrimination and word repetition 2AFC pic test/ 2AFC tone test session3 training

session4 training post-tests: discrimination and word repetition 2AFC pic test/ 2AFC tone test

For our first inspection of the data, we will conduct analyses both on session2 data and session4 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 the extra two sessions (session3 and session4) does not affect the key pattern of results, given the large expenditure of resources per participant, we will drop the final two sessions for ongoing participant collection.

Note that frequentist analyses will not be valid at .05 level, due to stopping problem. The current plan is to nevertheless report with that caveat; BF will be considered the critical analyses.

Load Packages and Helper Functions

Packages

rm(list=ls())
#suppressPackageStartupMessages(library(stringdist))
#library(languageR)
library(lattice)
suppressPackageStartupMessages(library(lme4))
library(plotrix)
#suppressPackageStartupMessages(library(irr))
library(plyr)
library(knitr)
library(ggplot2)    #for graphs
#library(reshape)
library(reshape2)
library(lsr)
library(pwr)

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 the names of the 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-subjects 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 summarized
  • 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 function 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 summarized
  • 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 outputs the centered values of a variable, which can be a numeric variable, a factor, or a data frame. It was taken from Florian Jaeger’s 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 data frame.

  • 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 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 object of type lmerMod or glmerMod)
  • list: a list of the 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 function 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 and run lmes on relevant pilot data

The child data below comes from a two session study where children 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 the comparison is somewhat different).

Note: tone contrast is a fixed effect with 6 levels (six possible contrasts). It is expected to contribute to the 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

Prediction 1: Children will show overall above chance performance across training in both condition1 and condition2

Based on:

We saw this in the pilot data from the seven year olds above, which was in a condition like the pictures-only condition. The pictures+diacritics condition contains the same information (plus some additional information) so we predict (at least - see below) above chance performance here too.

mean: 53.9%; log odds (beta from lme): 0.1572362; odds (exp(beta)):1.1702719;

Planned Analyses: Frequentist

We plan to use an lme model similar to that used on the 7-year-old pilot data above but with data from both conditions (pictures-only vs. pictures+diacritics). We will fit separate intercepts for each condition and compare each to chance = .50 (i.e. default value returned). Note that since all predictors are centered, the intercept reflects the overall average (rather than at base levels of a factor).

We will do this both for a model with just first two sessions and for a model with all data (with session then having four possible values and coded as a centered numerical factor).

Planned Analyses: BF

Summary of data for each condition: mean and SE for intercept from lme; value to inform H1: estimate from above pilot data for seven year olds 0.1579623

NOTE: If (e.g.) we find an effect for condition1, we can also use the estimate of the intercept 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

Look at the sample size required to obtain different levels of power with pilot data from 7 year olds:

dataS = as.numeric(with(droplevels(child.train.7), tapply(result,list(subject), mean, na.rm=T)))
d = cohensD(x = dataS, mu=0.5)
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .9, type = c("one.sample"), alternative = c( "greater"))

     One-sample t test power calculation 

              n = 20.5642
              d = 0.6690231
      sig.level = 0.05
          power = 0.9
    alternative = greater
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .8, type = c("one.sample"), alternative = c( "greater"))

     One-sample t test power calculation 

              n = 15.26043
              d = 0.6690231
      sig.level = 0.05
          power = 0.8
    alternative = greater
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .7, type = c("one.sample"), alternative = c( "greater"))

     One-sample t test power calculation 

              n = 11.97662
              d = 0.6690231
      sig.level = 0.05
          power = 0.7
    alternative = greater
rm(dataS)
rm(d)

Required sample for BF analyses:

Here we look at the pilot data from 7 year olds, using H1 informed by the estimate for 11 year olds. In our actual analyses with new data for 7 year olds we will be using an estimate from the current pilot data with 7 year olds to inform H1

meanBF = summary(child.train.7.mod)$coefficients["(Intercept)", "Estimate"]
seBF = summary(child.train.7.mod)$coefficients["(Intercept)", "Std. Error"]
h1mean = summary(child.train.11.mod)$coefficients["(Intercept)", "Estimate"]
Bf(seBF, meanBF, uniform = 0, meanoftheory = 0, sdtheory = h1mean, tail = 1)
$LikelihoodTheory
[1] 1.408113

$Likelihoodnull
[1] 0.1968384

$BayesFactor
[1] 7.153651
rm(meanBF)
rm(seBF)

We could reject H0 with the current sample of N = 15.

Prediction2: Improvement with session in each condition

Based on:

We saw this in the 7 year olds in the pilot 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

We will use an lme model similar to that used on the pilot data above but with data from both conditions (pictures-only vs. pictures+diacritics). We will fit separate slopes for session for each condition. We will do this both for a model with just the 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 analyses for c2 data with H1 informed by the estimate from c1 (this is a better estimate than the pilot data 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*
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*
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 the estimate for 11 year olds. In our actual analyses will be using an 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 the basis of current sample.

Prediction3: Greater performance in picture+diacritic condition with just picture condition

Based on:

We don’t have any pilot data with this type of manipulation for children.

This prediction is made on the basis of a related effect seen in adult data: they showed greater overall performance in a condition where they saw just diacritics rather than just pictures. Note that iconicity means that you can potentially respond when they are present. It is possible that having the diacritics present will help children too; though (a) children could well be different (diacritics might be too abstract) (b) it could be that having the picture there as well as the diacritic changes things.

Means from the pilot:

adult means : 0.67, 0.75 adult log odds (beta from lme): 0.4156183 adult odd (exp(beta))1.626952

Planned Analyses: Frequentist

WE will run an lme model similar to that used on pilot data above but with data from both conditions; We will look for a fixed effect of 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: mean and SE for condition.ct value to inform H1: estimate from above ADULT pilot data 0.4156183

There is a caveat here since this value comes from adults and will likely overestimate any difference for children (making it a conservative estimate, biasing evidence for H0).

Required Sample Analyses

Frequentists power

NOTE: this is based on ADULT data. It likely underestimates the power required to see this difference.

dataS = with(droplevels(adult.train), tapply(result,list(subject,condition), mean, na.rm=T))
d = cohensD(x = dataS[,1], y = dataS[,2], method = "pooled")
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .9, type = c("two.sample"), alternative = c("greater"))

     Two-sample t test power calculation 

              n = 58.37074
              d = 0.5449171
      sig.level = 0.05
          power = 0.9
    alternative = greater

NOTE: n is number in *each* group
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .8, type = c("two.sample"), alternative = c("greater"))

     Two-sample t test power calculation 

              n = 42.3355
              d = 0.5449171
      sig.level = 0.05
          power = 0.8
    alternative = greater

NOTE: n is number in *each* group
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .7, type = c("two.sample"), alternative = c("greater"))

     Two-sample t test power calculation 

              n = 32.39217
              d = 0.5449171
      sig.level = 0.05
          power = 0.7
    alternative = greater

NOTE: n is number in *each* group
rm(dataS)
rm(d)

Suggests that for adults we would need 58 per condition to get 90% power. We would be likely to need more with children.

Given practical constraints, we are unlikely to obtain a sufficient sample for this. However this effect isn’t critical in terms of demonstrating what leads to greater learning. (It is therefore more important to demonstrate that they are above chance in each condition).

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 lead to different learning slopes. One possibility is that children may show greater learning in the condition with diacritics, 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 diacritics (labelled “e” for explicit) (though the conditions were not exactly the same, see above) though it wasn’t significant.

adult means : 0.62, 0.71, 0.72, 0.79 beta: -0.0321743

Planned Analyses: Frequentist

We will use an lme model similar to that used on pilot data above but with data from both conditions; we will look for a 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 between session and condition (session.ct by condition.ct) value to inform H1: estimate of session from the same model (e.g. summary(model.newdata)$coefficients[“session.ct” ,“Estimate”].

This will provide a relatively high estimate of likely effect of interaction (if one is present) given the actual data set (so again, a conservative estimate)

[Note: we are checking this with a statistics consultant]

Required Sample Analyses

Frequentist power

Nothing to base power analysis on here (as there was no effect in the pilot 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 the 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)

We use tail = 2 here as we don’t have a clear direction for this hypothesis

So, 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 an effect of session in the other condition. If so, we will deem this sufficient to address this prediction.

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 the rest 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 pictures-only test will get just 2AFC pictures but will get it twice (so that total exposure doesn’t differ across conditions).

Where we just look at conditions separately, for the 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.

Run lmes on relevant pilot data

We didn’t do this test in the pilot studies, however the test is similar to the training task so we use a model based on just the last 24 trials 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 ~
        + 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 ~
        + 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 ~
        + 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

Prediction 1: Performance will above chance in each test in each condition.

Based on:

Training data in pilot (see above)

Planned Analyses: Frequentist

We will use an lme model similar to that for the training data. Again we fit separate intercepts for each condition and compare each to chance = .50 (i.e. default value returned). Since all predictors are centered, the intercept reflects the overall average (rather than at base levels of a factor).

We will do this both for a model with just the session 2 test and session 4 test; as discussed above, we will use the full double data set for the 2AFC picture test for the participants in the picture+diacritic condition.

Planned Analyses: BF test

Summary of data for each condition: mean and SE for intercept from lme

Value to inform H1: assuming they show learning, we will use an estimate from the equivalent lme for training data from the current data set (NOT from pilot data - unless the intercept from training set didn’t suggest above chance performance). Again note that if we find an effect for condition1, we can also use the estimate for intercept 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

Here we look at power using the values from the subset of training data from the above

dataS=as.numeric(with(droplevels(child.train.7.s2.24), tapply(result,list(subject), mean, na.rm=T)))
d= cohensD(x = dataS, mu=0.5)
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .9, type = c("one.sample"), alternative = c( "greater"))

     One-sample t test power calculation 

              n = 20.29292
              d = 0.6738353
      sig.level = 0.05
          power = 0.9
    alternative = greater
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .8, type = c("one.sample"), alternative = c( "greater"))

     One-sample t test power calculation 

              n = 15.06511
              d = 0.6738353
      sig.level = 0.05
          power = 0.8
    alternative = greater
pwr.t.test(n = NULL, d = d, sig.level = 0.05, power = .7, type = c("one.sample"), alternative = c( "greater"))

     One-sample t test power calculation 

              n = 11.82842
              d = 0.6738353
      sig.level = 0.05
          power = 0.7
    alternative = greater
rm(dataS)
rm(d)

This suggests a sample size of 21 is sufficient for 90% power.

Required sample for BF analyses:

Here we use the subset of pilot data with 7 year olds and an H1 informed by the estimate from 11 year olds whole training data set (note: in actual analyses H1 will be informed by an estimate from model of the current training data with 7 year olds )

meanBF = summary(child.train.7.s2.s4.mod)$coefficients["(Intercept)" ,"Estimate"]
seBF = summary(child.train.7.s2.s4.mod)$coefficients["(Intercept)" ,"Std. Error"]
h1mean = summary(child.train.11.mod)$coefficients["(Intercept)" ,"Estimate"]
Bf(seBF, meanBF, uniform = 0, meanoftheory = 0, sdtheory = h1mean,tail = 1)
$LikelihoodTheory
[1] 1.319399

$Likelihoodnull
[1] 0.6261729

$BayesFactor
[1] 2.107085
Bf_powercalc(seBF, meanBF, uniform = 0, meanoftheory = 0, N = 15, min = 15, max = 20, sdtheory = h1mean, tail = 1)
      x        y
[1,] 15 2.107085
[2,] 16 2.311559
[3,] 17 2.538967
[4,] 18 2.791849
[5,] 19 3.073052
[6,] 20 3.385763
rm(meanBF)
rm(seBF)

Suggests don’t currently have sufficient sample (N = 15) to get reliable evidence for H1, but could do with 19 participants.

Prediction 2: For the picture-only test, there will be greater performance in the picture-only condition

Based on

Children in the condition where diacritics are present might have become overly reliant on them during training and thus unable to do the test when they are absent, although we don’t currently have specific data to base this on.

Planned Analyses: Frequentist

We will run an lme model on 7 year olds data, looking at the effect of condition. We will do this both for a model with just day2 test and day4 test; as discussed above, we will only use the half set for the 2AFC picture test for the participants in the picture+diacritic condition.

Planned Analyses: BF test

Summary of data for each condition: mean and SE for condition from lme value to inform H1: assuming they show learning, use the estimate of intercept from the current model (note other values are centered, so this is equivalent to grand mean; it will be conservative)

(We are seeking statistical advice to confirm that this is a reasonable, if conservative, estimate for H1)

Required Sample Analyses

We don’t have any data that we can base analyses on here (comparison of conditions in the pilot adult data is too dissimilar).

Note that it may prove difficult to obtain a sufficient sample to gain evidence for H1 or H0. However, it may be that we see above chance performance only for the picture-only condition. In that case, we may look to the previous analyses (Prediction 1) and be able to show that there is evidence for H1 over H0 in one condition, but for H0 over H1 in the other. If so, we will be able to say that there is evidence of learning in one condition and not the other, and this will be deemed sufficient to address this hypothesis.

Discrimination (Three-Interval Oddity Task)

This test will be completed both pre and post test. Children will hear three frogs each produce a Mandarin word. One produces the target (“different”) word and the other two each produce the same foil word, which will be a word differing from the target only in tone (e.g. mao [t1], mao [t1], mao [t4]).

Each of the 6 one contrasts are tested. We will put tone contrast 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 hardest. 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 initial data set collected, we will consider both pre-test -> posttest1 (session 2) and pre-test -> post-test2 (session 4). If equivalent results are obtained, subsequent testing will drop the final two sessions (see note above).

Load up and run lmes on relevant pilot data

The pilot child data below comes from same two session study as the pilot training data (recall, they were trained on stimuli similar to the “picture-only” condition in the current study.)

The adult data below comes 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 of JUST of the diacritics. This is useful for considering possible effects of condition in the data (with the caveat that comparison is somewhat different).

Note that for both adults and children in the pilot experiment we included both trained and untrained items in the discrimination test. For the current experiment we will use only untrained items in this test so we remove the trained items from the analyses below.

As above, tone contrast is a 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")
child.discrim$pre_post = relevel(child.discrim$pre_post, ref="pre")
child.discrim$agegroup = as.factor(child.discrim$agegroup)
child.discrim$pre_post = relevel(child.discrim$pre_post, ref="pre")
child.discrim <- droplevels(subset(child.discrim, neworold == "newword"))
adult.discrim = read.csv ("adultsdiscrim_clean.csv")
adult.discrim$pre_post = relevel(adult.discrim$pre_post, ref="pre")
adult.discrim$condition = relevel(adult.discrim$condition, ref="i")
adult.discrim <- droplevels(subset(adult.discrim, neworold == "newword"))
child.discrim.7 = droplevels(subset(child.discrim, agegroup == "7"))
child.discrim.7 <- lizCenter(child.discrim.7, list("pre_post", "trialtype", "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
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

Prediction 1: There will be improvement from pre-post test in each condition

Based on

In the pilot data, adults show improvement with session, but 7 year olds didn’t (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 the means are reversed )

means : 0.44, 0.36; log odds (beta from lme): -0.3652203; odd (exp(beta))0.6940437

Planned Analyses: Frequentist

We will use an lme model similar to that used on the pilot data above but with data from both conditions; we will fit separate slopes for pre and post test in each condition

For the initial data set collected we will do this both to compare pre test to post-test 1 (session2) and pre-test to post-test2 (session4).

Planned Analyses: BF

Summary of data for each condition: mean and SE for pre-post from lme value to inform H1: We will use an estimate from the 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 learning in one condition we will use that to inform the 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 is included for completeness but is not really relevant since it is based on adult data. If children do show an effect, it is likely to be 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 the pilot study

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)

Here we have evidence for the null hypothesis (H0) from just 15 participants. Note however, that we are using a relatively high estimate for H1, which may make it easier to find evidence for H0.

Prediction 2: There will be more improvement in one condition than the other

Based on

We don’t have any specific evidence to base this on. The closest contrast was in the adult pilot experiment (comparing a 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 initial data set collected we will do this both to compare pre test to post-test 1 (session2) and pre-test to post-test2 (session4).

Planned Analyses: Frequentist

We will use an lme model similar to that used on the pilot data above but with data from both conditions; we will look for an 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: we will use the estimate for session from the current model (i.e. summary(new.data)$coefficients[“pre_post.ct” ,“Estimate”]`

Note: we will 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 a relatively conservative estimate for a large difference in how much the conditions lead to a change pre to post.

(We are seeking statistical advice here)

Required Sample Analyses

Frequentist Power

We have no data to look at this (since there was no sig. difference in the pilot data collected)

Required sample for BF analyses from pilot data

Here we are looking at this with adult pilot 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)

This analysis suggests that even for adults, we would need a sample of over 800 participants per condition to see this interaction. This is implausible (though may be partly because we are basing the analyses on an overly 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 way 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 completed in the pre and post tests. Children hear a word and copy it back. We will look to see if they repeat back the tone correctly (the audio recordings will be coded by native speakers who are blind 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 initial data set collected, will consider both pre-test -> posttest1 (session2) and pre-test -> post-test2 (sesion4). If equivalent results are obtained, subsequent testing will drop final two sessions (see note above).

Load up and run lmes on pilot data

The child data below come from the same two session study as the pilot training data/discrimination data (i.e. where children 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 particular student project did not 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 the pilot experiments using this test we included both trained and untrained items. For this experiment we use only untrained items in this test so we remove the trained items from the analyses below.

child.wr = read.csv("kidswordrep_clean.csv")
child.wr$pre_post = relevel(child.wr$pre_post, ref = "pre")
child.wr = droplevels(subset(child.wr, wordtype == "new"))
adult.wr = read.csv("adultswordrep_clean.csv")
adult.wr$pre_post = relevel(adult.wr$pre_post, ref = "pre")
adult.wr = droplevels(subset(adult.wr, wordtype == "Untrained"))
child.wr.7 = droplevels(subset(child.wr, Age=="young"))
child.wr.7 <- lizCenter(child.wr.7, list("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

Prediction 1: There will be an improvement from pre-post test in each each condition

Based on

Both children and adults showed this in the relevant pilot studies

7year mean :0.59, 0.65; 7year log odds (beta from lme): 0.3085348; 7year odd (exp(beta))1.3614289

adult mean : 0.7, 0.77; adult log odds (beta from lme): 0.4117959; adult odd (exp(beta))1.5095264

Planned Analyses: Frequentist

We will use an lme model similar to that used on the pilot data above but with data from both conditions; We will fit separate slopes for pre-post in each condition

For the initial 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: we will use an estimate from the 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 is included for completeness but is not really relevant since it is based on adult data. If children do show an effect, it is likely to be smaller and they will have larger SE

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 to inform H1 (whereas for actual analyses we will be using a 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 diacritics+picture condition.

Planned Analyses: Frequentist

We will us an lme model similar to that used on the pilot data above but with data from both conditions; we will look for an interaction of pre-post and condition

For the initial 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 Ananlyses: BF

Summary of data for each condition: mean and SE for pre-post*condition from lme value to inform H1: we will use an estimate for session from the model with the new data (i.e. summary(new.data)$coefficients[“pre_post.ct” ,“Estimate”]`

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 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 conclusions are possible based on which of the conditions individually provides evidence for H1/H0.

LS0tDQp0aXRsZTogIlBsYW4gZm9yIHRlc3RpbmcgWWVhciAzICg3LTggeWVhcnMpIG9uIHBpY3R1cmVzLW9ubHkgdmVyc3VzIHBpY3R1cmVzK2RpYWNyaXRpY3MiDQphdXRob3I6ICJFbGl6YWJldGggV29ubmFjb3R0Ig0KZGF0ZTogIjAzLjA3LjE3Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiANCiAgICB0b2M6IHRydWUNCiAgICB0aGVtZTogdW5pdGVkDQotLS0NCg0KIyBOb3RlcyBvbiB1cGRhdGVzDQoNCkFsbCB0aGF0IGhhcyBiZWVuIGNoYW5nZWQgY29tcGFyZWQgd2l0aCBwcmV2aW91cyBzY3JpcHQgcG9zdGVkIDE4LjA2LjE3IChodHRwczovL3JzdHVkaW8tcHVicy1zdGF0aWMuczMuYW1hem9uYXdzLmNvbS8yODU5NjlfZGEyZjY5NWRkYjk1NDBhYzg1MDg5NzQ0NjI2Y2E3MjkuaHRtbCkNCmlzIHRoYXQgYSBtZW51IGhhcyBiZWVuIGFkZGVkLCBzb21lIHBvaW50cyBhYm91dCBjb25kaXRpb25zIGhhdmUgYmVlbiBjbGFyaWZpZWQsIGFuZCB0eXBvcyBoYXZlIGJlZW4gZml4ZWQuIChOb3RlIGluIHBhcnRpY3VsYXIgdGhlcmUgYXMgYSB0eXBvIHJlIEJGIGZhY3RvcnMgbGluZSAyNikgDQoNCg0KIyBHZW5lcmFsIE5vdGVzDQoNClRoaXMgY29udGFpbnMgcGxhbm5lZCBhbmFseXNlcyBhcyBvZiAxOC8wNi8yMDE3IGZvciBhIGRhdGEgc2V0IHdoaWNoIHdlIHdpbGwgc3RhcnQgdG8gY29sbGVjdCBvbiAxOS8wNi8yMDE3Lg0KUGxhbnMgbWF5IGNoYW5nZSBhcyBhIHJlc3VsdCBvZiBzdGF0aXN0aWNhbCBjb25zdWx0YXRpb24gKHdlIGFyZSBjdXJyZW50bHkgc2Vla2luZyBhZHZpY2Ugb24gc29tZSBkZXRhaWxzKS4NCg0KVGhlIHN0dWR5IGlzIGEgdHJhaW5pbmcgc3R1ZHkgdG8gYmUgY29uZHVjdGVkIHdpdGggWWVhciAzICg3LTggeWVhciBvbGQpIGNoaWxkcmVuIHdpdGggbm8gcHJldmlvdXMga25vd2xlZGdlIG9mIE1hbmRhcmluIG9yIGFueSBvdGhlciB0b25hbCBsYW5ndWFnZSwgdHJhaW5pbmcgdGhlbSBvbiB0aGUgZm91ciB0b25lcyAoNiB0b25lIGNvbnRyYXN0cykgaW4gTWFuZGFyaW4uIFRoZXJlIHdpbGwgaW5pdGlhbGx5IGJlIHR3byBjb25kaXRpb25zOiAoMSkgcGljdHVyZXMtb25seTogdGhleSBhcmUgdHJhaW5lZCB1c2luZyBhIDJBRkMgdGFzayB3aGVyZSB0aGV5IGhlYXIgYSAocmVhbCkgTWFuZGFyaW4gd29yZCBhbmQgaWRlbnRpZnkgd2hpY2ggb2YgdHdvIHBpY3R1cmVzIGl0IHJlZmVycyB0byAob25lIGNvcnJlY3QsIG9uZSBhIGZvaWwgd2hpY2ggZGlmZmVycyBvbmx5IGJ5IHRvbmUpOyAoMikgcGljdHVyZXMrZGlhY3JpdGljcyAtIHNhbWUgdGFzayBidXQgdGhlIHBpY3R1cmVzIGFyZSBhY2NvbXBhbmllZCBieSBwaWN0dXJlcyBvZiB0aGUgZm91ciBkaWFjcml0aWNzLiBbSWYgcmVzb3VyY2VzIHBlcm1pdCwgd2UgbWF5IGxhdGVyIHJ1biBhIGRpYWNyaXRpY3Mgb25seSBjb25kaXRpb25dLiBEYXRhIHdpbGwgYmUgY29sbGVjdGVkIGZyb20gdGhlIHRyYWluaW5nIHRhc2sgYW5kIGZyb20gc29tZSB0ZXN0IHRhc2tzIGNvbmR1Y3RlZCBwcmUgYW5kIHBvc3QgdHJhaW5pbmcuDQoNCk91ciBtYWluIGFuYWx5c2VzIHdpbGwgYmUgQmF5ZXNpYW4gYW5kIHdlIHdpbGwgY29tcHV0ZSBCYXllcyBmYWN0b3JzIHVzaW5nIHRoZSBtZXRob2QgYWR2b2NhdGVkIGJ5IERpZW5lcyAoMjAwOCwgMjAxNSk7IHdlIHdpbGwgYWxzbyBhbG9uZ3NpZGUgcHJvdmlkZSBmcmVxdWVudGlzdCBzdGF0aXN0aWNzLiBGcmVxdWVudGlzdCBzdGF0aXN0aWNzIHdpbGwgY29tcHV0ZWQgdXNpbmcgbG9naXN0aWMgbWl4ZWQgZWZmZWN0IG1vZGVscywgdGhpcyBtZXRob2QgaXMgdXNlZCBzaW5jZSBpbiBlYWNoIGNhc2Ugd2UgaGF2ZSBhIGRlcGVuZGVudCB2YXJpYWJsZSBvZiBjb3JyZWN0L2luY29ycmVjdCByZXNwb25zZS4gTm90ZSB0aGF0IGFsdGhvdWdoIG1peGVkIG1vZGVscyBhbGxvdyB1cyB0byBpbmNsdWRlIGJvdGggcGFydGljaXBhbnRzIGFuZCBpdGVtcywgd2UgZG8gbm90IGludGVuZCB0byBpbmNsdWRlIGl0ZW1zIGluIHRoZSBhbmFseXNlcyBzaW5jZSBwb3dlciBvbiB0aGlzIGRpbWVuc2lvbiB3aWxsIGJlIGxvdy4gKE5CIC0gKGkpIHdlIGNvdW50ZXJiYWxhbmNlIHRyYWluZWQvdW50cmFpbmVkIHdvcmRsaXN0cyBhY3Jvc3MgcGFydGljaXBhbnRzOyAoaWkpIGl0IGlzIG5vdCBjb21tb24gZm9yIGJ5IGl0ZW1zIGFuYWx5c2VzIHRvIGJlIGluY2x1ZGVkIGZvciB3b3JrIGluIHRoaXMgYXJlYTsgKGlpaSkgaW5jcmVhc2luZyB0aGUgbnVtYmVyIG9mIGl0ZW1zIGluIGEgbGVhcm5pbmcgc3R1ZHkgb2YgdGhpcyB0eXBlIHdpdGggY2hpbGRyZW4gaXMgbm90IGZlYXNpYmxlKS4gV2Ugd2lsbCB1c2UgZnVsbCByYW5kb20gc2xvcGVzIHN0cnVjdHVyZSBmb3IgcHJlZGljdG9ycyBvZiBpbnRlcmVzdCAoZ2VuZXJhbGx5LCBjb25kaXRpb24gYW5kIHNlc3Npb24vcHJlLT5wb3N0KS4gRmFjdG9ycyBzdWNoIGFzIHRvbmUgY29udHJhc3QgZm9yIHRoZSB0cmlhbCB3aWxsIGJlIGluY2x1ZGVkIGFzIGZpeGVkIGZhY3RvcnMgYnV0IHdlIHdpbGwgbm90IGluY2x1ZGUgcmFuZG9tIHNsb3BlcyBmb3IgdGhlc2UuDQoNCkZvciB0aGUgQmF5ZXNpYW4gYW5hbHlzZXMsIHdlIHdpbGwgY29udGludWUgdG8gd29yayBpbiBsb2cgb2RkcyBzcGFjZSAoYXMgZm9yIGZyZXF1ZW50aXN0IGFuYWx5c2VzKSB0byBtZWV0IGFzc3VtcHRpb25zIG9mIG5vcm1hbGl0eSwgdXNpbmcgZXN0aW1hdGVzIGFuZCBzdGFuZGFyZCBlcnJvcnMgd2hpY2ggY29tZSBmcm9tIHRoZSBsb2dpc3RpYyBtaXhlZCBlZmZlY3RzIG1vZGVscy4gRm9sbG93aW5nIERpZW5lcyAoMjAwOCkgd2Ugd2lsbCBtb2RlbCBIMSBieSB1c2luZyBhbiBlc3RpbWF0ZSBvZiB0aGUgbWVhbiBmb3IgdGhlb3J5IChhbiBlc3RpbWF0ZSBjb21pbmcgZnJvbSBlaXRoZXIgZnJvbSBsb2dpc3RpYyBtaXhlZCBlZmZlY3RzIG1vZGVscyBydW4gb3ZlciBwaWxvdCBkYXRhLCBvciBpbiBzb21lIGNhc2VzIGZyb20gZWxzZXdoZXJlIGluIHRoZSBkYXRhKSBhcyB0aGUgU0Qgb2YgYSBoYWxmIG5vcm1hbCAoZm9yIG9uZSB0YWlsZWQpIG9yIGZ1bGwgbm9ybWFsIChmb3IgdHdvIHRhaWxlZCkgZGlzdHJpYnV0aW9uLiBXZSB3aWxsIHNheSB3ZSBoYXZlIHN1YnN0YW50aWFsIGV2aWRlbmNlIGZvciBIMSBpcyBCRj4zIGFuZCBmb3IgSDAgaXMgQkY8LjMzIFtUWVBPIEZJWEVEIEhFUkUgRlJPTSBQUkVWSU9VU10gDQoNClNlZTogaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvai5qbWwuMjAxNy4wMS4wMDUgZm9yIHB1Ymxpc2hlZCBwYXBlciB1c2luZyB0aGlzIGFwcHJvYWNoIGFuZCBSc2NyaXB0IGh0dHA6Ly9ycHVicy5jb20vZXdvbm5hY290dC8yNDI0NTQuIA0KDQpOb3RlIHRoYXQgdGhlIHBpbG90IGRhdGEgcmVmZXJyZWQgdG8gYmVsb3cgY29tZXMgZnJvbSB0aHJlZSB1bmRlcmdyYWR1YXRlIHN0dWRlbnQgcHJvamVjdHMuIE5vbmUgd2VyZSBleGFjdGx5IHRoZSBzYW1lIGFzIHRoZSBleHBlcmltZW50IHBsYW5uZWQgaGVyZSwgYnV0IG1hdGVyaWFscyB3ZXJlIHZlcnkgc2ltaWxhciBhbmQgaW4gc29tZSBjYXNlcyBzaW1pbGFyIHF1ZXN0aW9ucyB3ZXJlIGFza2VkLiBUaGUgbW9kZWxzIG9mIHRoZSBwaWxvdCBkYXRhIHByZXNlbnRlZCBiZWxvdyBhbHNvIHNlcnZlIHRvIGV4ZW1wbGlmeSB0aGUgYXBwcm9hY2ggdG8gYmUgdGFrZW4gd2l0aCB0aGUgY3VycmVudCBkYXRhLg0KDQpXaGVyZSBwb3NzaWJsZSwgd2UgY29uZHVjdGVkIHBvd2VyIGFuYWx5c2VzLCBhbHRob3VnaCBsbWUncyB3aWxsIGJlIHVzZWQgZm9yIHRoZSBhY3R1YWwgYW5hbHlzZXMsIHdlIGNvbmR1Y3RlZCB0aGUgYW5hbHlzZXMgYXMgdGhvdWdoIGZvciAobmVhciBlcXVpdmFsZW50KSB0LXRlc3RzIG92ZXIgYnkgc3ViamVjdCBwcm9wb3J0aW9ucy4gVGhpcyBtZWFucyB0aGF0IHRoZSB2YWx1ZXMgYXJlIG9ubHkgYXBwcm94aW1hdGUsIGJ1dCBzaW5jZSBvdXIgbWFpbiBhbmFseXNlcyBhcmUgQkYgZmFjdG9ycyBvdXIgYWltIGhlcmUgaXMgdG8gZ2V0IGFuIGlkZWEgb2YgYXBwcm94aW1hdGUgc3VpdGFibGUgc2FtcGxlIHNpemVzLg0KDQpJbiBhZGRpdGlvbiB0byBwb3dlciBhbmFseXNlcywgd2hlcmUgcG9zc2libGUgd2UgYWxzbyBjb25kdWN0ZWQgQmF5ZXNpYW4gYW5hbHlzZXMgb24gcmVsZXZhbnQgcGFydHMgb2YgdGhlIHBpbG90IGRhdGEgdG8gc2VlIGlmIHdlIGhhZCBhIHN1ZmZpY2llbnQgc2FtcGxlIGZvciBCRj4zIG9yIEJGPC4zMy4gV2UgYWxzbyBsb29rIHRvIHNlZSB3aGF0IHNpemUgc2FtcGxlIG1pZ2h0IGJlIGV4cGVjdGVkIHRvIGdpdmUgQkY+MyBvciBCRjwuMzMsIGdpdmVuIHRoYXQgU0UgdmFyaWVzIGFzIHNxdWFyZSByb290IChOKS4NCg0KVGhlIGFuYWx5c2VzIGJlbG93IHN1Z2dlc3QgdGhhdCB0aGVyZSBhcmUgY2FzZXMgd2hlcmUgYSBzYW1wbGUgb2YgMjAgcGFydGljaXBhbnRzIHBlciBjb25kaXRpb24gY291bGQgYmUgc3VmZmljaWVudCB0byBhY2hpZXZlIDkwJSBwb3dlci4gSW50ZXJhY3Rpb25zIHdpdGggY29uZGl0aW9uIHdpbGwgYmUgaGFyZGVyIHRvIHBvd2VyOyBhcyBkaXNjdXNzZWQgYmVsb3csIHRoZXJlIG1heSBiZSBzaXR1YXRpb25zIHdoZXJlIHRoZXJlIGlzIGV2aWRlbmNlIG9mIEgxIChpLmUuIGRhdGEgcmVmbGVjdHMgbGVhcm5pbmcpIGluIGNvbmRpdGlvbjEgYnV0IGV2aWRlbmNlIGZvciBIMCAobm8gZXZpZGVuY2Ugb2YgbGVhcm5pbmcgaW4gdGhpcyBkYXRhKSBmb3IgY29uZGl0aW9uMi4gSWYgc28sIHdlIHdpbGwgZGVlbSB0aGlzIHN1ZmZpY2llbnQgdG8gZHJhdyBjb25jbHVzaW9ucyBhYm91dCB0aGUgZGlmZmVyZW50IHRyYWluaW5nIG1ldGhvZHMuDQoNCk91ciBwb2xpY3kgd2lsbCBiZSBhcyBmb2xsb3dzOiB3ZSB3aWxsIGluc3BlY3QgdGhlIGRhdGEgYWZ0ZXIgd2UgaGF2ZSBhcHByb3hpbWF0ZWx5IDIwIHBhcnRpY2lwYW50cyBpbiBlYWNoIGNvbmRpdGlvbiAoTm90ZTogdGhpcyBpcyBhcHByb3hpbWF0ZSBzaW5jZSB3ZSBhaW0gdG8gY29sbGVjdCB0aGlzIGRhdGEgYnkgdGhlIGVuZCBvZiB0aGUgY3VycmVudCBhY2FkZW1pYyB5ZWFyIChKdWx5IDIwMTcpOyBpZiB3ZSBkb24ndCBxdWl0ZSBnZXQgdGhpcyBtYW55IGNoaWxkcmVuLCB3ZSB3aWxsIHN0aWxsIGxvb2sgYXQgdGhlIHNhbXBsZSB3ZSBoYXZlKS4gSWYgcmVzdWx0cyBmb3Iga2V5IGFuYWx5c2VzIGFyZSBpbmNvbmNsdXNpdmUsIHJlc291cmNlcyBwZXJtaXR0aW5nIHdlIHdpbGwgY29udGludWUgdG8gdGVzdCBtb3JlIHBhcnRpY2lwYW50cywgY29sbGVjdGluZyAxMCBwZXIgY29uZGl0aW9uIGF0IGVhY2ggc3RlcCBiZWZvcmUgaW5zcGVjdGluZyB0aGUgZGF0YSBhZ2FpbiBhdCBlYWNoIHN0ZXAuIFdlIHdpbGwgY29udGludWUgdW50aWwgTiBwZXIgY29uZGl0aW9uID0gNTAsIHJlc291cmNlcyBwZXJtaXR0aW5nLiANCiANCkZpbmFsIG5vdGU6IHdlIGhhdmUgZGVzaWduZWQgdGhlIGV4cGVyaW1lbnQgdG8gaGF2ZSBmb3VyIHNlc3Npb25zIGFzIGZvbGxvd3M6DQoNCnNlc3Npb24xIHByZS10ZXN0czogZGlzY3JpbWluYXRpb24gYW5kIHdvcmQgcmVwZXRpdGlvbiANCiAgICAgdHJhaW5pbmcNCg0Kc2Vzc2lvbjIgdHJhaW5pbmcNCiAgICAgcG9zdC10ZXN0czogZGlzY3JpbWluYXRpb24gYW5kIHdvcmQgcmVwZXRpdGlvbiANCiAgICAgICAgICAgMkFGQyBwaWMgdGVzdC8gMkFGQyB0b25lIHRlc3QNCnNlc3Npb24zIHRyYWluaW5nDQogICAgDQpzZXNzaW9uNCB0cmFpbmluZw0KICAgICBwb3N0LXRlc3RzOiBkaXNjcmltaW5hdGlvbiBhbmQgd29yZCByZXBldGl0aW9uIA0KICAgICAgICAgICAyQUZDIHBpYyB0ZXN0LyAyQUZDIHRvbmUgdGVzdA0KICAgICAgICAgICANCkZvciBvdXIgZmlyc3QgaW5zcGVjdGlvbiBvZiB0aGUgZGF0YSwgd2Ugd2lsbCBjb25kdWN0IGFuYWx5c2VzIGJvdGggb24gc2Vzc2lvbjIgZGF0YSBhbmQgc2Vzc2lvbjQgZGF0YSAoYm90aCBjb21wYXJlZCB0byByZWxldmFudCBwcmUtdGVzdHM7IGZvciB0cmFpbmluZyBkYXRhIGl0c2VsZiwgd2Ugd2lsbCBsb29rIGF0IHNlc3Npb25zMSBhbmQgMiB2ZXJzdXMgc2Vzc2lvbiAxLCAyLCAzICYgNCkuIElmIHVzaW5nIGRhdGEgZnJvbSB0aGUgZXh0cmEgdHdvIHNlc3Npb25zIChzZXNzaW9uMyBhbmQgc2Vzc2lvbjQpIGRvZXMgbm90IGFmZmVjdCB0aGUga2V5IHBhdHRlcm4gb2YgcmVzdWx0cywgZ2l2ZW4gdGhlIGxhcmdlIGV4cGVuZGl0dXJlIG9mIHJlc291cmNlcyBwZXIgcGFydGljaXBhbnQsIHdlIHdpbGwgZHJvcCB0aGUgZmluYWwgdHdvIHNlc3Npb25zIGZvciBvbmdvaW5nIHBhcnRpY2lwYW50IGNvbGxlY3Rpb24uDQoNCk5vdGUgdGhhdCBmcmVxdWVudGlzdCBhbmFseXNlcyB3aWxsIG5vdCBiZSB2YWxpZCBhdCAuMDUgbGV2ZWwsIGR1ZSB0byBzdG9wcGluZyBwcm9ibGVtLiBUaGUgY3VycmVudCBwbGFuIGlzIHRvIG5ldmVydGhlbGVzcyByZXBvcnQgd2l0aCB0aGF0IGNhdmVhdDsgQkYgd2lsbCBiZSBjb25zaWRlcmVkIHRoZSBjcml0aWNhbCBhbmFseXNlcy4NCg0KIyBMb2FkIFBhY2thZ2VzIGFuZCBIZWxwZXIgRnVuY3Rpb25zDQoNCiMjIFBhY2thZ2VzDQoNCmBgYHtyfQ0Kcm0obGlzdD1scygpKQ0KI3N1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KHN0cmluZ2Rpc3QpKQ0KI2xpYnJhcnkobGFuZ3VhZ2VSKQ0KbGlicmFyeShsYXR0aWNlKQ0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkobG1lNCkpDQpsaWJyYXJ5KHBsb3RyaXgpDQojc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoaXJyKSkNCmxpYnJhcnkocGx5cikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGdncGxvdDIpCSNmb3IgZ3JhcGhzDQojbGlicmFyeShyZXNoYXBlKQ0KbGlicmFyeShyZXNoYXBlMikNCmxpYnJhcnkobHNyKQ0KbGlicmFyeShwd3IpDQpgYGANCiMjIEhlbHBlciBGdW5jdGlvbnMNCg0KIyMjIFN1bW1hcnlTRQ0KDQpUaGlzIGZ1bmN0aW9uIGNhbiBiZSBmb3VuZCBvbiB0aGUgd2Vic2l0ZSAiQ29va2Jvb2sgZm9yIFIiDQoNCmh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vTWFuaXB1bGF0aW5nX2RhdGEvU3VtbWFyaXppbmdfZGF0YS8NCg0KSXQgc3VtbWFyaXplcyBkYXRhLCBnaXZpbmcgY291bnQsIG1lYW4sIHN0YW5kYXJkIGRldmlhdGlvbiwgc3RhbmRhcmQgZXJyb3Igb2YgdGhlIG1lYW4sIGFuZCBjb25maWRlbmNlIGludGVydmFsIChkZWZhdWx0IDk1JSkuDQoNCiogZGF0YTogYSBkYXRhIGZyYW1lDQoqIG1lYXN1cmV2YXI6IHRoZSBuYW1lIG9mIGEgY29sdW1uIHRoYXQgY29udGFpbnMgdGhlIHZhcmlhYmxlIHRvIGJlIHN1bW1hcml6ZWQNCiogZ3JvdXB2YXJzOiBhIHZlY3RvciBjb250YWluaW5nIHRoZSBuYW1lcyBvZiB0aGUgY29sdW1ucyB0aGF0IGNvbnRhaW4gZ3JvdXBpbmcgdmFyaWFibGVzDQoqIG5hLnJtOiBhIGJvb2xlYW4gdGhhdCBpbmRpY2F0ZXMgd2hldGhlciB0byBpZ25vcmUgTkEncw0KKiBjb25mLmludGVydmFsOiB0aGUgcGVyY2VudCByYW5nZSBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCAoZGVmYXVsdCBpcyA5NSUpDQoNCmBgYHtyfQ0Kc3VtbWFyeVNFIDwtIGZ1bmN0aW9uKGRhdGE9TlVMTCwgbWVhc3VyZXZhciwgZ3JvdXB2YXJzPU5VTEwsIG5hLnJtPUZBTFNFLA0KICAgICAgICAgICBjb25mLmludGVydmFsPS45NSwgLmRyb3A9VFJVRSkgew0KICByZXF1aXJlKHBseXIpDQoNCiAgIyBOZXcgdmVyc2lvbiBvZiBsZW5ndGggd2hpY2ggY2FuIGhhbmRsZSBOQSdzOiBpZiBuYS5ybT09VCwgZG9uJ3QgY291bnQgdGhlbQ0KICBsZW5ndGgyIDwtIGZ1bmN0aW9uICh4LCBuYS5ybT1GQUxTRSkgew0KICAgIGlmIChuYS5ybSkgc3VtKCFpcy5uYSh4KSkNCiAgICBlbHNlICAgIGxlbmd0aCh4KQ0KICB9DQoNCiAgIyBUaGlzIGRvZXMgdGhlIHN1bW1hcnkuIEZvciBlYWNoIGdyb3VwJ3MgZGF0YSBmcmFtZSwgcmV0dXJuIGEgdmVjdG9yIHdpdGgNCiAgIyBOLCBtZWFuLCBhbmQgc2QNCiAgZGF0YWMgPC0gZGRwbHkoZGF0YSwgZ3JvdXB2YXJzLCAuZHJvcD0uZHJvcCwNCiAgIC5mdW4gPSBmdW5jdGlvbih4eCwgY29sKSB7DQogICAgYyhOICA9IGxlbmd0aDIoeHhbW2NvbF1dLCBuYS5ybT1uYS5ybSksDQogICAgIG1lYW4gPSBtZWFuICAoeHhbW2NvbF1dLCBuYS5ybT1uYS5ybSksDQogICAgIHNkICA9IHNkICAgKHh4W1tjb2xdXSwgbmEucm09bmEucm0pDQogICAgKQ0KICAgfSwNCiAgIG1lYXN1cmV2YXINCiAgKQ0KDQogICMgUmVuYW1lIHRoZSAibWVhbiIgY29sdW1uICANCiAgZGF0YWMgPC0gcmVuYW1lKGRhdGFjLCBjKCJtZWFuIiA9IG1lYXN1cmV2YXIpKQ0KDQogIGRhdGFjJHNlIDwtIGRhdGFjJHNkIC8gc3FydChkYXRhYyROKSAjIENhbGN1bGF0ZSBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVhbg0KDQogICMgQ29uZmlkZW5jZSBpbnRlcnZhbCBtdWx0aXBsaWVyIGZvciBzdGFuZGFyZCBlcnJvcg0KICAjIENhbGN1bGF0ZSB0LXN0YXRpc3RpYyBmb3IgY29uZmlkZW5jZSBpbnRlcnZhbDogDQogICMgZS5nLiwgaWYgY29uZi5pbnRlcnZhbCBpcyAuOTUsIHVzZSAuOTc1IChhYm92ZS9iZWxvdyksIGFuZCB1c2UgZGY9Ti0xDQogIGNpTXVsdCA8LSBxdChjb25mLmludGVydmFsLzIgKyAuNSwgZGF0YWMkTi0xKQ0KICBkYXRhYyRjaSA8LSBkYXRhYyRzZSAqIGNpTXVsdA0KDQogIHJldHVybihkYXRhYykNCn0NCmBgYA0KDQojIyMgU3VtbWFyeVNFd2l0aGluDQoNClRoaXMgZnVuY3Rpb24gY2FuIGJlIGZvdW5kIG9uIHRoZSB3ZWJzaXRlICJDb29rYm9vayBmb3IgUiINCg0KaHR0cDovL3d3dy5jb29rYm9vay1yLmNvbS9HcmFwaHMvUGxvdHRpbmdfbWVhbnNfYW5kX2Vycm9yX2JhcnNfKGdncGxvdDIpLyNIZWxwZXIgZnVuY3Rpb25zDQoNCkZyb20gdGhhdCB3ZWJzaXRlOg0KDQpTdW1tYXJpemVzIGRhdGEsIGhhbmRsaW5nIHdpdGhpbi1zdWJqZWN0cyB2YXJpYWJsZXMgYnkgcmVtb3ZpbmcgaW50ZXItc3ViamVjdCB2YXJpYWJpbGl0eS4gSXQgd2lsbCBzdGlsbCB3b3JrIGlmIHRoZXJlIGFyZSBubyB3aXRoaW4tc3ViamVjdHMgdmFyaWFibGVzLiBHaXZlcyBjb3VudCwgdW4tbm9ybWVkIG1lYW4sIG5vcm1lZCBtZWFuICh3aXRoIHNhbWUgYmV0d2Vlbi1ncm91cCBtZWFuKSwgc3RhbmRhcmQgZGV2aWF0aW9uLCBzdGFuZGFyZCBlcnJvciBvZiB0aGUgbWVhbiwgYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWwuIElmIHRoZXJlIGFyZSB3aXRoaW4tc3ViamVjdCB2YXJpYWJsZXMsIGNhbGN1bGF0ZSBhZGp1c3RlZCB2YWx1ZXMgdXNpbmcgbWV0aG9kIGZyb20gTW9yZXkgKDIwMDgpLg0KDQoqIGRhdGE6IGEgZGF0YSBmcmFtZQ0KKiBtZWFzdXJldmFyOiB0aGUgbmFtZSBvZiBhIGNvbHVtbiB0aGF0IGNvbnRhaW5zIHRoZSB2YXJpYWJsZSB0byBiZSBzdW1tYXJpemVkDQoqIGJldHdlZW52YXJzOiBhIHZlY3RvciBjb250YWluaW5nIG5hbWVzIG9mIGNvbHVtbnMgdGhhdCBhcmUgYmV0d2Vlbi1zdWJqZWN0cyB2YXJpYWJsZXMNCiogd2l0aGludmFyczogYSB2ZWN0b3IgY29udGFpbmluZyBuYW1lcyBvZiBjb2x1bW5zIHRoYXQgYXJlIHdpdGhpbi1zdWJqZWN0cyB2YXJpYWJsZXMNCiogaWR2YXI6IHRoZSBuYW1lIG9mIGEgY29sdW1uIHRoYXQgaWRlbnRpZmllcyBlYWNoIHN1YmplY3QgKG9yIG1hdGNoZWQgc3ViamVjdHMpDQoqIG5hLnJtOiBhIGJvb2xlYW4gdGhhdCBpbmRpY2F0ZXMgd2hldGhlciB0byBpZ25vcmUgTkEncw0KKiBjb25mLmludGVydmFsOiB0aGUgcGVyY2VudCByYW5nZSBvZiB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCAoZGVmYXVsdCBpcyA5NSUpDQoNCmBgYHtyfQ0Kc3VtbWFyeVNFd2l0aGluIDwtIGZ1bmN0aW9uKGRhdGE9TlVMTCwgbWVhc3VyZXZhciwgYmV0d2VlbnZhcnM9TlVMTCwgd2l0aGludmFycz1OVUxMLA0KICAgICAgICAgICAgICBpZHZhcj1OVUxMLCBuYS5ybT1GQUxTRSwgY29uZi5pbnRlcnZhbD0uOTUsIC5kcm9wPVRSVUUpIHsNCg0KICMgRW5zdXJlIHRoYXQgdGhlIGJldHdlZW52YXJzIGFuZCB3aXRoaW52YXJzIGFyZSBmYWN0b3JzDQogZmFjdG9ydmFycyA8LSB2YXBwbHkoZGF0YVssIGMoYmV0d2VlbnZhcnMsIHdpdGhpbnZhcnMpLCBkcm9wPUZBTFNFXSwNCiAgRlVOPWlzLmZhY3RvciwgRlVOLlZBTFVFPWxvZ2ljYWwoMSkpDQoNCiBpZiAoIWFsbChmYWN0b3J2YXJzKSkgew0KICBub25mYWN0b3J2YXJzIDwtIG5hbWVzKGZhY3RvcnZhcnMpWyFmYWN0b3J2YXJzXQ0KICBtZXNzYWdlKCJBdXRvbWF0aWNhbGx5IGNvbnZlcnRpbmcgdGhlIGZvbGxvd2luZyBub24tZmFjdG9ycyB0byBmYWN0b3JzOiAiLA0KICAgICAgcGFzdGUobm9uZmFjdG9ydmFycywgY29sbGFwc2UgPSAiLCAiKSkNCiAgZGF0YVtub25mYWN0b3J2YXJzXSA8LSBsYXBwbHkoZGF0YVtub25mYWN0b3J2YXJzXSwgZmFjdG9yKQ0KIH0NCg0KICMgR2V0IHRoZSBtZWFucyBmcm9tIHRoZSB1bi1ub3JtZWQgZGF0YQ0KIGRhdGFjIDwtIHN1bW1hcnlTRShkYXRhLCBtZWFzdXJldmFyLCBncm91cHZhcnM9YyhiZXR3ZWVudmFycywgd2l0aGludmFycyksDQogICAgICAgICAgIG5hLnJtPW5hLnJtLCBjb25mLmludGVydmFsPWNvbmYuaW50ZXJ2YWwsIC5kcm9wPS5kcm9wKQ0KDQogIyBEcm9wIGFsbCB0aGUgdW51c2VkIGNvbHVtbnMgKHRoZXNlIHdpbGwgYmUgY2FsY3VsYXRlZCB3aXRoIG5vcm1lZCBkYXRhKQ0KIGRhdGFjJHNkIDwtIE5VTEwNCiBkYXRhYyRzZSA8LSBOVUxMDQogZGF0YWMkY2kgPC0gTlVMTA0KDQogIyBOb3JtIGVhY2ggc3ViamVjdCdzIGRhdGENCiBuZGF0YSA8LSBub3JtRGF0YVdpdGhpbihkYXRhLCBpZHZhciwgbWVhc3VyZXZhciwgYmV0d2VlbnZhcnMsIG5hLnJtLCAuZHJvcD0uZHJvcCkNCg0KICMgVGhpcyBpcyB0aGUgbmFtZSBvZiB0aGUgbmV3IGNvbHVtbg0KIG1lYXN1cmV2YXJfbiA8LSBwYXN0ZShtZWFzdXJldmFyLCAiX25vcm0iLCBzZXA9IiIpDQoNCiAjIENvbGxhcHNlIHRoZSBub3JtZWQgZGF0YSAtIG5vdyB3ZSBjYW4gdHJlYXQgYmV0d2VlbiBhbmQgd2l0aGluIHZhcnMgdGhlIHNhbWUNCiBuZGF0YWMgPC0gc3VtbWFyeVNFKG5kYXRhLCBtZWFzdXJldmFyX24sIGdyb3VwdmFycz1jKGJldHdlZW52YXJzLCB3aXRoaW52YXJzKSwNCiAgICAgICAgICAgbmEucm09bmEucm0sIGNvbmYuaW50ZXJ2YWw9Y29uZi5pbnRlcnZhbCwgLmRyb3A9LmRyb3ApDQoNCiAjIEFwcGx5IGNvcnJlY3Rpb24gZnJvbSBNb3JleSAoMjAwOCkgdG8gdGhlIHN0YW5kYXJkIGVycm9yIGFuZCBjb25maWRlbmNlIGludGVydmFsDQogIyBHZXQgdGhlIHByb2R1Y3Qgb2YgdGhlIG51bWJlciBvZiBjb25kaXRpb25zIG9mIHdpdGhpbi1TIHZhcmlhYmxlcw0KIG5XaXRoaW5Hcm91cHMgIDwtIHByb2QodmFwcGx5KG5kYXRhY1ssd2l0aGludmFycywgZHJvcD1GQUxTRV0sIEZVTj1ubGV2ZWxzLA0KICAgICAgICAgICAgICBGVU4uVkFMVUU9bnVtZXJpYygxKSkpDQogY29ycmVjdGlvbkZhY3RvciA8LSBzcXJ0KCBuV2l0aGluR3JvdXBzIC8gKG5XaXRoaW5Hcm91cHMtMSkgKQ0KDQogIyBBcHBseSB0aGUgY29ycmVjdGlvbiBmYWN0b3INCiBuZGF0YWMkc2QgPC0gbmRhdGFjJHNkICogY29ycmVjdGlvbkZhY3Rvcg0KIG5kYXRhYyRzZSA8LSBuZGF0YWMkc2UgKiBjb3JyZWN0aW9uRmFjdG9yDQogbmRhdGFjJGNpIDwtIG5kYXRhYyRjaSAqIGNvcnJlY3Rpb25GYWN0b3INCg0KICMgQ29tYmluZSB0aGUgdW4tbm9ybWVkIG1lYW5zIHdpdGggdGhlIG5vcm1lZCByZXN1bHRzDQogbWVyZ2UoZGF0YWMsIG5kYXRhYykNCn0NCmBgYA0KDQojIyMgbm9ybURhdGFXaXRoaW4NCg0KVGhpcyBmdW5jdGlvbiBpcyB1c2VkIGJ5IHRoZSBTdW1tYXJ5U0VXaXRoaW4gZnVuY3Rpb24gYWJvdmUuIEl0IGNhbiBiZSBmb3VuZCBvbiB0aGUgd2Vic2l0ZSAiQ29va2Jvb2sgZm9yIFIiDQoNCmh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vR3JhcGhzL1Bsb3R0aW5nX21lYW5zX2FuZF9lcnJvcl9iYXJzXyhnZ3Bsb3QyKS8jSGVscGVyIGZ1bmN0aW9ucw0KDQpGcm9tIHRoYXQgd2Vic2l0ZToNCg0KTm9ybXMgdGhlIGRhdGEgd2l0aGluIHNwZWNpZmllZCBncm91cHMgaW4gYSBkYXRhIGZyYW1lOyBpdCBub3JtYWxpemVzIGVhY2ggc3ViamVjdCAoaWRlbnRpZmllZCBieSBpZHZhcikgc28gdGhhdCB0aGV5IGhhdmUgdGhlIHNhbWUgbWVhbiwgd2l0aGluIGVhY2ggZ3JvdXAgc3BlY2lmaWVkIGJ5IGJldHdlZW52YXJzLg0KDQoqIGRhdGE6IGEgZGF0YSBmcmFtZQ0KKiBpZHZhcjogdGhlIG5hbWUgb2YgYSBjb2x1bW4gdGhhdCBpZGVudGlmaWVzIGVhY2ggc3ViamVjdCAob3IgbWF0Y2hlZCBzdWJqZWN0cykNCiogbWVhc3VyZXZhcjogdGhlIG5hbWUgb2YgYSBjb2x1bW4gdGhhdCBjb250YWlucyB0aGUgdmFyaWFibGUgdG8gYmUgc3VtbWFyaXplZA0KKiBiZXR3ZWVudmFyczogYSB2ZWN0b3IgY29udGFpbmluZyBuYW1lcyBvZiBjb2x1bW5zIHRoYXQgYXJlIGJldHdlZW4tc3ViamVjdHMgdmFyaWFibGVzDQoqIG5hLnJtOiBhIGJvb2xlYW4gdGhhdCBpbmRpY2F0ZXMgd2hldGhlciB0byBpZ25vcmUgTkEncw0KDQpgYGB7cn0NCm5vcm1EYXRhV2l0aGluIDwtIGZ1bmN0aW9uKGRhdGE9TlVMTCwgaWR2YXIsIG1lYXN1cmV2YXIsIGJldHdlZW52YXJzPU5VTEwsDQogICAgICAgICAgICAgIG5hLnJtPUZBTFNFLCAuZHJvcD1UUlVFKSB7DQogICNsaWJyYXJ5KHBseXIpDQoNCiAgIyBNZWFzdXJlIHZhciBvbiBsZWZ0LCBpZHZhciArIGJldHdlZW4gdmFycyBvbiByaWdodCBvZiBmb3JtdWxhLg0KICBkYXRhLnN1YmpNZWFuIDwtIGRkcGx5KGRhdGEsIGMoaWR2YXIsIGJldHdlZW52YXJzKSwgLmRyb3A9LmRyb3AsDQogICAuZnVuID0gZnVuY3Rpb24oeHgsIGNvbCwgbmEucm0pIHsNCiAgICBjKHN1YmpNZWFuID0gbWVhbih4eFssY29sXSwgbmEucm09bmEucm0pKQ0KICAgfSwNCiAgIG1lYXN1cmV2YXIsDQogICBuYS5ybQ0KICApDQoNCiAgIyBQdXQgdGhlIHN1YmplY3QgbWVhbnMgd2l0aCBvcmlnaW5hbCBkYXRhDQogIGRhdGEgPC0gbWVyZ2UoZGF0YSwgZGF0YS5zdWJqTWVhbikNCg0KICAjIEdldCB0aGUgbm9ybWFsaXplZCBkYXRhIGluIGEgbmV3IGNvbHVtbg0KICBtZWFzdXJlTm9ybWVkVmFyIDwtIHBhc3RlKG1lYXN1cmV2YXIsICJfbm9ybSIsIHNlcD0iIikNCiAgZGF0YVssbWVhc3VyZU5vcm1lZFZhcl0gPC0gZGF0YVssbWVhc3VyZXZhcl0gLSBkYXRhWywic3Viak1lYW4iXSArDQogICAgICAgICAgICAgICAgbWVhbihkYXRhWyxtZWFzdXJldmFyXSwgbmEucm09bmEucm0pDQoNCiAgIyBSZW1vdmUgdGhpcyBzdWJqZWN0IG1lYW4gY29sdW1uDQogIGRhdGEkc3Viak1lYW4gPC0gTlVMTA0KDQogIHJldHVybihkYXRhKQ0KfQ0KYGBgDQoNCg0KIyMjIG15Q2VudGVyDQoNClRoaXMgZnVuY3Rpb24gb3V0cHV0cyB0aGUgY2VudGVyZWQgdmFsdWVzIG9mIGEgdmFyaWFibGUsIHdoaWNoIGNhbiBiZSBhIG51bWVyaWMgdmFyaWFibGUsIGEgZmFjdG9yLCBvciBhIGRhdGEgZnJhbWUuIEl0IHdhcyB0YWtlbiBmcm9tIEZsb3JpYW4gSmFlZ2VyJ3MgYmxvZy4gDQoNCmh0dHBzOi8vaGxwbGFiLndvcmRwcmVzcy5jb20vMjAwOS8wNC8yNy9jZW50ZXJpbmctc2V2ZXJhbC12YXJpYWJsZXMvLg0KDQpGcm9tIGhpcyBibG9nOg0KDQoqIElmIHRoZSBpbnB1dCBpcyBhIG51bWVyaWMgdmFyaWFibGUsIHRoZSBvdXRwdXQgaXMgdGhlIGNlbnRlcmVkIHZhcmlhYmxlLg0KKiBJZiB0aGUgaW5wdXQgaXMgYSBmYWN0b3IsIHRoZSBvdXRwdXQgaXMgYSBudW1lcmljIHZhcmlhYmxlIHdpdGggY2VudGVyZWQgZmFjdG9yIGxldmVsIHZhbHVlcy4gVGhhdCBpcywgdGhlIGZhY3RvcidzIGxldmVscyBhcmUgY29udmVydGVkIGludG8gbnVtZXJpY2FsIHZhbHVlcyBpbiB0aGVpciBpbmhlcmVudCBvcmRlciAoaWYgbm90IHNwZWNpZmllZCBvdGhlcndpc2UsIFIgZGVmYXVsdHMgdG8gYWxwaGFudW1lcmljYWwgb3JkZXIpLiBNb3JlIHNwZWNpZmljYWxseSwgdGhpcyBjZW50ZXJzIGFueSBiaW5hcnkgZmFjdG9yIHNvIHRoYXQgdGhlIHZhbHVlIGJlbG93IDAgd2lsbCBiZSB0aGUgMXN0IGxldmVsIG9mIHRoZSBvcmlnaW5hbCBmYWN0b3IsIGFuZCB0aGUgdmFsdWUgYWJvdmUgMCB3aWxsIGJlIHRoZSAybmQgbGV2ZWwuDQoqIElmIHRoZSBpbnB1dCBpcyBhIGRhdGEgZnJhbWUgb3IgbWF0cml4LCB0aGUgb3V0cHV0IGlzIGEgbmV3IG1hdHJpeCBvZiB0aGUgc2FtZSBkaW1lbnNpb24gYW5kIHdpdGggdGhlIGNlbnRlcmVkIHZhbHVlcyBhbmQgY29sdW1uIG5hbWVzIHRoYXQgY29ycmVzcG9uZCB0byB0aGUgY29sbmFtZXMoKSBvZiB0aGUgaW5wdXQgcHJlY2VkZWQgYnkgImMiIChlLmcuICJWYXJpYWJsZTEiIHdpbGwgYmUgImNWYXJpYWJsZTEiKS4NCg0KYGBge3J9DQpteUNlbnRlcj0gZnVuY3Rpb24oeCkgew0KIGlmIChpcy5udW1lcmljKHgpKSB7IHJldHVybih4IC0gbWVhbih4LCBuYS5ybT1UKSkgfQ0KCWlmIChpcy5mYWN0b3IoeCkpIHsNCgkJeD0gYXMubnVtZXJpYyh4KQ0KCQlyZXR1cm4oeCAtIG1lYW4oeCwgbmEucm09VCkpDQoJfQ0KCWlmIChpcy5kYXRhLmZyYW1lKHgpIHx8IGlzLm1hdHJpeCh4KSkgew0KCQltPSBtYXRyaXgobnJvdz1ucm93KHgpLCBuY29sPW5jb2woeCkpDQoJCWNvbG5hbWVzKG0pPSBwYXN0ZSgiYyIsIGNvbG5hbWVzKHgpLCBzZXA9IiIpDQoJDQoJCWZvciAoaSBpbiAxOm5jb2woeCkpIHsNCgkJDQoJCQltWyxpXT0gbXlDZW50ZXIoeFssaV0pDQoJCX0NCgkJcmV0dXJuKGFzLmRhdGEuZnJhbWUobSkpDQoJfQ0KfQ0KYGBgDQoNCiMjIyBsaXpDZW50ZXINCg0KVGhpcyBmdW5jdGlvbiBwcm92aWRlcyBhIHdyYXBwZXIgYXJvdW5kIG15Q2VudGVyIGFsbG93aW5nIHlvdSB0byBjZW50ZXIgYSBzcGVjaWZpYyBsaXN0IG9mIHZhcmlhYmxlcyBmcm9tIGEgZGF0YSBmcmFtZS4gDQoNCiogeDogZGF0YSBmcmFtZQ0KKiBsaXN0Zm5hbWU6IGEgbGlzdCBvZiB0aGUgdmFyaWFibGVzIHRvIGJlIGNlbnRlcmVkIChlLmcuIGxpc3QodmFyaWFibGUxLHZhcmlhYmxlMikpDQoNClRoZSBvdXRwdXQgaXMgYSBjb3B5IG9mIHRoZSBkYXRhIGZyYW1lIHdpdGggYSBjb2x1bW4gKGFsd2F5cyBhIG51bWVyaWMgdmFyaWFibGUpIGFkZGVkIGZvciBlYWNoIG9mIHRoZSBjZW50ZXJlZCB2YXJpYWJsZXMuIFRoZXNlIGNvbHVtbnMgYXJlIGxhYmVsbGVkIHdpdGggdGhlIGNvbHVtbidzIHByZXZpb3VzIG5hbWUsIGJ1dCB3aXRoICIuY3QiIGFwcGVuZGVkIChlLmcuLCAidmFyaWFibGUxIiB3aWxsIGJlY29tZSAidmFyaWFibGUxLmN0IikuDQoNCmBgYHtyfQ0KbGl6Q2VudGVyPSBmdW5jdGlvbih4LCBsaXN0Zm5hbWUpIA0Kew0KCWZvciAoaSBpbiAxOmxlbmd0aChsaXN0Zm5hbWUpKSANCgl7DQoJCWZuYW1lID0gYXMuY2hhcmFjdGVyKGxpc3RmbmFtZVtpXSkNCgkJeFtwYXN0ZShmbmFtZSwiLmN0Iiwgc2VwPSIiKV0gPSBteUNlbnRlcih4W2ZuYW1lXSkNCgl9DQoJCQ0KCXJldHVybih4KQ0KfQ0KYGBgCQ0KDQojIyMgZ2V0X2NvZWZmcw0KDQpUaGlzIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBpbnNwZWN0IHBhcnRpY3VsYXIgY29lZmZpY2llbnRzIGZyb20gdGhlIG91dHB1dCBvZiBhbiBsbWUgbW9kZWwgYnkgcHV0dGluZyB0aGVtIGluIHRhYmxlLg0KDQoqIHg6IHRoZSBvdXRwdXQgcmV0dXJuZWQgd2hlbiBydW5uaW5nIGxtZXIgb3IgZ2xtZXIgKGkuZS4gYW4gb2JqZWN0IG9mIHR5cGUgbG1lck1vZCBvciBnbG1lck1vZCkNCiogbGlzdDogYSBsaXN0IG9mIHRoZSBuYW1lcyBvZiB0aGUgY29lZmZpY2llbnRzIHRvIGJlIGV4dHJhY3RlZCAoZS5nLiBjKCJ2YXJpYWJsZTEiLCAidmFyaWFibGUxOnZhcmlhYmxlMiIpKQ0KDQpgYGB7cn0NCiNnZXRfY29lZmZzIDwtIGZ1bmN0aW9uKHgsbGlzdCl7KGthYmxlKGFzLmRhdGEuZnJhbWUoc3VtbWFyeSh4KSRjb2VmZmljaWVudHMpW2xpc3QsXSxkaWdpdHM9MykpfQ0KZ2V0X2NvZWZmcyA8LSBmdW5jdGlvbih4LGxpc3Qpeyhhcy5kYXRhLmZyYW1lKHN1bW1hcnkoeCkkY29lZmZpY2llbnRzKVtsaXN0LF0pfQ0KYGBgIA0KDQojIyMgQmYNCg0KVGhpcyBmdW5jdGlvbiBpcyBlcXVpdmFsZW50IHRvIHRoZSBEaWVuZXMgKDIwMDgpIGNhbGN1bGF0b3Igd2hpY2ggY2FuIGJlIGZvdW5kIGhlcmU6IGh0dHA6Ly93d3cubGlmZXNjaS5zdXNzZXguYWMudWsvaG9tZS9ab2x0YW5fRGllbmVzL2luZmVyZW5jZS9CYXllcy5odG0uDQoNClRoZSBjb2RlIHdhcyBwcm92aWRlZCBieSBCYWd1ZWx5IGFuZCBLYXluZSAoMjAxMCkgYW5kIGNhbiBiZSBmb3VuZCBoZXJlOiBodHRwOi8vd3d3LmFjYWRlbWlhLmVkdS80MjcyODgvUmV2aWV3X29mX1VuZGVyc3RhbmRpbmdfcHN5Y2hvbG9neV9hc19hX3NjaWVuY2VfQW5faW50cm9kdWN0aW9uX3RvX3NjaWVudGlmaWNfYW5kX3N0YXRpc3RpY2FsX2luZmVyZW5jZQ0KDQpgYGB7cn0NCkJmPC1mdW5jdGlvbihzZCwgb2J0YWluZWQsIHVuaWZvcm0sIGxvd2VyPTAsIHVwcGVyPTEsIG1lYW5vZnRoZW9yeT0wLHNkdGhlb3J5PTEsIHRhaWw9Mil7DQogYXJlYSA8LSAwDQogaWYoaWRlbnRpY2FsKHVuaWZvcm0sIDEpKXsNCiB0aGV0YSA8LSBsb3dlcg0KIHJhbmdlIDwtIHVwcGVyIC0gbG93ZXINCiBpbmNyIDwtIHJhbmdlIC8gMjAwMA0KIGZvciAoQSBpbiAtMTAwMDoxMDAwKXsNCiAgIHRoZXRhIDwtIHRoZXRhICsgaW5jcg0KICAgZGlzdF90aGV0YSA8LSAxIC8gcmFuZ2UNCiAgIGhlaWdodCA8LSBkaXN0X3RoZXRhICogZG5vcm0ob2J0YWluZWQsIHRoZXRhLCBzZCkNCiAgIGFyZWEgPC0gYXJlYSArIGhlaWdodCAqIGluY3INCiB9DQogfWVsc2UNCiAge3RoZXRhIDwtIG1lYW5vZnRoZW9yeSAtIDUgKiBzZHRoZW9yeQ0KICBpbmNyIDwtIHNkdGhlb3J5IC8gMjAwDQogIGZvciAoQSBpbiAtMTAwMDoxMDAwKXsNCiAgIHRoZXRhIDwtIHRoZXRhICsgaW5jcg0KICAgZGlzdF90aGV0YSA8LSBkbm9ybSh0aGV0YSwgbWVhbm9mdGhlb3J5LCBzZHRoZW9yeSkNCiAgIGlmKGlkZW50aWNhbCh0YWlsLCAxKSl7DQogICAgaWYgKHRoZXRhIDw9IDApew0KICAgICBkaXN0X3RoZXRhIDwtIDANCiAgICB9IGVsc2Ugew0KICAgICBkaXN0X3RoZXRhIDwtIGRpc3RfdGhldGEgKiAyDQogICAgfQ0KICAgfQ0KICAgaGVpZ2h0IDwtIGRpc3RfdGhldGEgKiBkbm9ybShvYnRhaW5lZCwgdGhldGEsIHNkKQ0KICAgYXJlYSA8LSBhcmVhICsgaGVpZ2h0ICogaW5jcg0KICB9DQogfQ0KIExpa2VsaWhvb2RUaGVvcnkgPC0gYXJlYQ0KIExpa2VsaWhvb2RudWxsIDwtIGRub3JtKG9idGFpbmVkLCAwLCBzZCkNCiBCYXllc0ZhY3RvciA8LSBMaWtlbGlob29kVGhlb3J5IC8gTGlrZWxpaG9vZG51bGwNCiByZXQgPC0gbGlzdCgiTGlrZWxpaG9vZFRoZW9yeSIgPSBMaWtlbGlob29kVGhlb3J5LCJMaWtlbGlob29kbnVsbCIgPSBMaWtlbGlob29kbnVsbCwgIkJheWVzRmFjdG9yIiA9IEJheWVzRmFjdG9yKQ0KIHJldA0KfSANCmBgYA0KDQojIyMgQmZfcG93ZXJjYWxjDQoNClRoaXMgd29ya3Mgd2l0aCB0aGUgQmYgZnVuY3Rpb24gYWJvdmUuIEl0IHJlcXVpcmVzIHRoZSBzYW1lIHZhbHVlcyBhcyB0aGF0IGZ1bmN0aW9uIChpLmUuIHRoZSBvYnRhaW5lZCBtZWFuIGFuZCBTRSBmb3IgdGhlIGN1cnJlbnQgc2FtcGxlLCBhIHZhbHVlIGZvciB0aGUgcHJlZGljdGVkIG1lYW4sIHdoaWNoIGlzIHNldCB0byBiZSBzZHRoZW9yeSAod2l0aCBtZWFub2Z0aGVvcnk9MCksIGFuZCB0aGUgY3VycmVudCBudW1iZXIgb2YgcGFydGljaXBhbnRzIE4pLiBIb3dldmVyIHJhdGhlciB0aGFuIHJldHVybiBhIEJGIGZvciB0aGUgY3VycmVudCBzYW1wbGUsIGl0IHdvcmtzIG91dCB3aGF0IHRoZSBCRiB3b3VsZCBiZSBmb3IgYSByYW5nZSBvZiBkaWZmZXJlbnQgc3ViamVjdCBudW1iZXJzIChhc3N1bWluZyB0aGF0IHRoZSBTRSBzY2FsZXMgd2l0aCBzcXJ0KE4pKSwgDQoNCmBgYHtyfQ0KQmZfcG93ZXJjYWxjPC1mdW5jdGlvbihzZCwgb2J0YWluZWQsIHVuaWZvcm0sIGxvd2VyPTAsIHVwcGVyPTEsIG1lYW5vZnRoZW9yeT0wLCBzZHRoZW9yeT0xLCB0YWlsPTIsIE4sIG1pbiwgbWF4KQ0Kew0KIA0KIHggPSBjKDApDQogeSA9IGMoMCkNCiAgIyBub3RlOiB3b3JraW5nIG91dCB3aGF0IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gTiBhbmQgZGYgaXMgKGZvciB0aGUgY29udHJhc3QgYmV0d2VlbiB0d28gZ3JvdXBzLCB0aGlzIGlzIDI7IGZvciBjb25zdHJhaW50cyB3aGVyZSB0aGVyZSBpcyA0IGdyb3VwcyB0aGlzIHdpbGwgYmUgMywgZXRjLikgDQoNCiBmb3IobmV3TiBpbiBtaW4gOiBtYXgpDQogew0KIEIgPSBhcy5udW1lcmljKEJmKHNkID0gc2Qqc3FydChOL25ld04pLCBvYnRhaW5lZCwgdW5pZm9ybSwgbG93ZXIsIHVwcGVyLCBtZWFub2Z0aGVvcnksIHNkdGhlb3J5LCB0YWlsKVszXSkNCiB4PSBhcHBlbmQoeCxuZXdOKSANCiB5PSBhcHBlbmQoeSxCKQ0KIG91dHB1dCA9IGNiaW5kKHgseSkNCiANCiB9IA0KIG91dHB1dCA9IG91dHB1dFstMSxdIA0KIHJldHVybihvdXRwdXQpIA0KfQ0KYGBgDQoNCiMgVHJhaW5pbmcNCg0KRFY6IEVhY2ggdHJhaW5pbmcgdHJpYWwgcHJvZHVjZXMgYSBkYXRhIHBvaW50IChkaWQgdGhleSBwaWNrIHRoZSBjb3JyZWN0IHBpY3R1cmUgLSAxLzA7IG5vdGUgdGhleSBnZXQgZmVlZGJhY2sgb24gdGhpcykgDQoNCiMjIExvYWQgYW5kIHJ1biBsbWVzIG9uIHJlbGV2YW50IHBpbG90IGRhdGENCg0KVGhlIGNoaWxkIGRhdGEgYmVsb3cgY29tZXMgZnJvbSBhIHR3byBzZXNzaW9uIHN0dWR5IHdoZXJlIGNoaWxkcmVuIHdlcmUgdHJhaW5lZCBvbiBzdGltdWxpIHNpbWlsYXIgdG8gdGhlICJwaWN0dXJlLW9ubHkiIGNvbmRpdGlvbiBpbiB0aGUgY3VycmVudCBzdHVkeS4gV2UgaGF2ZSBkYXRhIGZyb20gYm90aCA3IHllYXIgb2xkcyBhbmQgMTEgeWVhciBvbGRzOyB0aGUgMTEgeWVhciBvbGQgZGF0YSBoZXJlIGFyZSByZWxldmFudCBpbiBwcm92aWRpbmcgYW4gZXN0aW1hdGUgdGhhdCBjYW4gYmUgdXNlZCB0byBpbmZvcm0gSDEgaW4gb3VyIEJGIGV4YW1wbGUgYW5hbHlzZXMuDQoNClRoZSBhZHVsdCBkYXRhIGJlbG93IGNvbWUgZnJvbSBhIHR3byBzZXNzaW9uIHN0dWR5IHdoZXJlIHRoZXJlIHdlcmUgdHdvIGNvbmRpdGlvbnM6ICgxKSB0cmFpbmVkIG9uIHN0aW11bGkgc2ltaWxhciB0byB0aGUgInBpY3R1cmUtb25seSIgY29uZGl0aW9uIGluIHRoZSBjdXJyZW50IHN0dWR5ICgyKSB0cmFpbmVkIG9uIHBpY3R1cmVzIEpVU1Qgb2YgdGhlIGRpYWNyaXRpY3MuIFRoaXMgaXMgdXNlZnVsIGZvciBjb25zaWRlcmluZyBwb3NzaWJsZSBlZmZlY3RzIG9mIGNvbmRpdGlvbiBpbiB0aGUgZGF0YSAodGhvdWdoIHdpdGggdGhlIGNhdmVhdCB0aGF0IHRoZSBjb21wYXJpc29uIGlzIHNvbWV3aGF0IGRpZmZlcmVudCkuDQoNCk5vdGU6IHRvbmUgY29udHJhc3QgaXMgYSBmaXhlZCBlZmZlY3Qgd2l0aCA2IGxldmVscyAoc2l4IHBvc3NpYmxlIGNvbnRyYXN0cykuIEl0IGlzIGV4cGVjdGVkIHRvIGNvbnRyaWJ1dGUgdG8gdGhlIG1vZGVsIGFuZCBpcyB0aHVzIGluY2x1ZGVkIGJ1dCBpc24ndCBvZiBzcGVjaWZpYyBpbnRlcmVzdC4NCg0KYGBge3J9DQpjaGlsZC50cmFpbiA9IHJlYWQuY3N2KCJraWRzdHJhaW5fY2xlYW4uY3N2IikNCmFkdWx0LnRyYWluID0gcmVhZC5jc3YgKCJhZHVsdHN0cmFpbl9jbGVhbi5jc3YiKQ0KY2hpbGQudHJhaW4kYWdlZ3JvdXAgPSByZWxldmVsKGNoaWxkLnRyYWluJGFnZWdyb3VwLCByZWY9Ijd5ZWFycyIpDQphZHVsdC50cmFpbiRjb25kaXRpb24gPSByZWxldmVsKGFkdWx0LnRyYWluJGNvbmRpdGlvbiwgcmVmPSJpIikNCmBgYA0KDQpgYGB7cn0NCmNoaWxkLnRyYWluLjcgPSBzdWJzZXQoY2hpbGQudHJhaW4sIGFnZWdyb3VwID09ICI3eWVhcnMiKQ0KY2hpbGQudHJhaW4uNyA8LSBsaXpDZW50ZXIoY2hpbGQudHJhaW4uNywgbGlzdCgic2Vzc2lvbiIsICJ0b25lY29udHJhc3QiKSkNCg0KY2hpbGQudHJhaW4uNy5tb2QgPSBnbG1lciAocmVzdWx0IH4NCiAgICAgICAgKyBzZXNzaW9uLmN0IA0KICAgICAgICArIHRvbmVjb250cmFzdC5jdA0KICAgICAgICArIChzZXNzaW9uLmN0fHN1YmplY3QpLA0KICAgICAgICBkYXRhID0gY2hpbGQudHJhaW4uNywgZmFtaWx5ID0gYmlub21pYWwsIGNvbnRyb2w9Z2xtZXJDb250cm9sKG9wdGltaXplciA9ICJib2J5cWEiKSkNCg0Kcm91bmQoc3VtbWFyeShjaGlsZC50cmFpbi43Lm1vZCkkY29lZmZpY2llbnRzLDMpDQpgYGANCg0KDQpgYGB7cn0NCmNoaWxkLnRyYWluLjExID0gc3Vic2V0KGNoaWxkLnRyYWluLCBhZ2Vncm91cCA9PSAiMTF5ZWFycyIpDQpjaGlsZC50cmFpbi4xMSA8LSBsaXpDZW50ZXIoY2hpbGQudHJhaW4uMTEsIGxpc3QoInNlc3Npb24iLCAidG9uZWNvbnRyYXN0IikpDQoNCmNoaWxkLnRyYWluLjExLm1vZCA9IGdsbWVyIChyZXN1bHQgfg0KICAgICAgICArIHNlc3Npb24uY3QgDQogICAgICAgICsgdG9uZWNvbnRyYXN0LmN0DQogICAgICAgICsgKHNlc3Npb24uY3R8c3ViamVjdCksDQogICAgICAgIGRhdGEgPSBjaGlsZC50cmFpbi4xMSwgZmFtaWx5ID0gYmlub21pYWwsIGNvbnRyb2w9Z2xtZXJDb250cm9sKG9wdGltaXplciA9ICJib2J5cWEiKSkNCg0Kcm91bmQoc3VtbWFyeShjaGlsZC50cmFpbi4xMS5tb2QpJGNvZWZmaWNpZW50cywzKQ0KYGBgDQoNCg0KYGBge3J9DQphZHVsdC50cmFpbiA8LSBsaXpDZW50ZXIoYWR1bHQudHJhaW4sIGxpc3QoInNlc3Npb24iLCAidG9uZWNvbnRyYXN0IiwgImNvbmRpdGlvbiIpKQ0KDQphZHVsdC50cmFpbi5tb2QgPSBnbG1lciAocmVzdWx0IH4NCiAgICAgICAgKyBzZXNzaW9uLmN0ICogY29uZGl0aW9uLmN0DQogICAgICAgICsgdG9uZWNvbnRyYXN0LmN0DQogICAgICAgICsgKHNlc3Npb24uY3R8c3ViamVjdCksDQogICAgICAgIGRhdGEgPSBhZHVsdC50cmFpbiwgZmFtaWx5ID0gYmlub21pYWwsIGNvbnRyb2w9Z2xtZXJDb250cm9sKG9wdGltaXplciA9ICJib2J5cWEiKSkNCg0Kcm91bmQoc3VtbWFyeShhZHVsdC50cmFpbi5tb2QpJGNvZWZmaWNpZW50cywzKQ0KYGBgDQoNCiMjIFByZWRpY3Rpb24gMTogQ2hpbGRyZW4gd2lsbCBzaG93IG92ZXJhbGwgYWJvdmUgY2hhbmNlIHBlcmZvcm1hbmNlIGFjcm9zcyB0cmFpbmluZyBpbiBib3RoIGNvbmRpdGlvbjEgYW5kIGNvbmRpdGlvbjINCg0KIyMjIEJhc2VkIG9uOiANCg0KV2Ugc2F3IHRoaXMgaW4gdGhlIHBpbG90IGRhdGEgZnJvbSB0aGUgc2V2ZW4geWVhciBvbGRzIGFib3ZlLCB3aGljaCB3YXMgaW4gYSBjb25kaXRpb24gbGlrZSB0aGUgcGljdHVyZXMtb25seSBjb25kaXRpb24uDQpUaGUgcGljdHVyZXMrZGlhY3JpdGljcyBjb25kaXRpb24gY29udGFpbnMgdGhlIHNhbWUgaW5mb3JtYXRpb24gKHBsdXMgc29tZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uKSBzbyB3ZSBwcmVkaWN0IChhdCBsZWFzdCAtIHNlZSBiZWxvdykgYWJvdmUgY2hhbmNlIHBlcmZvcm1hbmNlIGhlcmUgdG9vLiANCg0KbWVhbjogYHIgcGFzdGUocm91bmQobWVhbihjaGlsZC50cmFpbi43JHJlc3VsdCksMykgKjEwMCwgIiUiLCBzZXA9IiIpYDsNCmxvZyBvZGRzIChiZXRhIGZyb20gbG1lKTogYHIgc3VtbWFyeShjaGlsZC50cmFpbi43Lm1vZCkkY29lZmZpY2llbnRzWyIoSW50ZXJjZXB0KSIgLCJFc3RpbWF0ZSJdYDsNCm9kZHMgKGV4cChiZXRhKSk6YHIgZXhwKHN1bW1hcnkoY2hpbGQudHJhaW4uNy5tb2QpJGNvZWZmaWNpZW50c1siKEludGVyY2VwdCkiICwiRXN0aW1hdGUiXSlgOw0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogRnJlcXVlbnRpc3QgDQoNCldlIHBsYW4gdG8gdXNlIGFuIGxtZSBtb2RlbCBzaW1pbGFyIHRvIHRoYXQgdXNlZCBvbiB0aGUgNy15ZWFyLW9sZCBwaWxvdCBkYXRhIGFib3ZlIGJ1dCB3aXRoIGRhdGEgZnJvbSBib3RoIGNvbmRpdGlvbnMgKHBpY3R1cmVzLW9ubHkgdnMuIHBpY3R1cmVzK2RpYWNyaXRpY3MpLiBXZSB3aWxsIGZpdCBzZXBhcmF0ZSBpbnRlcmNlcHRzIGZvciBlYWNoIGNvbmRpdGlvbiBhbmQgY29tcGFyZSBlYWNoIHRvIGNoYW5jZSA9IC41MCAoaS5lLiBkZWZhdWx0IHZhbHVlIHJldHVybmVkKS4gTm90ZSB0aGF0IHNpbmNlIGFsbCBwcmVkaWN0b3JzIGFyZSBjZW50ZXJlZCwgdGhlIGludGVyY2VwdCByZWZsZWN0cyB0aGUgb3ZlcmFsbCBhdmVyYWdlIChyYXRoZXIgdGhhbiBhdCBiYXNlIGxldmVscyBvZiBhIGZhY3RvcikuIA0KDQpXZSB3aWxsIGRvIHRoaXMgYm90aCBmb3IgYSBtb2RlbCB3aXRoIGp1c3QgZmlyc3QgdHdvIHNlc3Npb25zIGFuZCBmb3IgYSBtb2RlbCB3aXRoIGFsbCBkYXRhICh3aXRoIHNlc3Npb24gdGhlbiBoYXZpbmcgZm91ciBwb3NzaWJsZSB2YWx1ZXMgYW5kIGNvZGVkIGFzIGEgY2VudGVyZWQgbnVtZXJpY2FsIGZhY3RvcikuDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBCRiANCg0KU3VtbWFyeSBvZiBkYXRhIGZvciBlYWNoIGNvbmRpdGlvbjogbWVhbiBhbmQgU0UgZm9yIGludGVyY2VwdCBmcm9tIGxtZTsNCnZhbHVlIHRvIGluZm9ybSBIMTogZXN0aW1hdGUgZnJvbSBhYm92ZSBwaWxvdCBkYXRhIGZvciBzZXZlbiB5ZWFyIG9sZHMgYHIgc3VtbWFyeShjaGlsZC50cmFpbi43Lm1vZCkkY29lZmZpY2llbnRzWyJzZXNzaW9uLmN0IiAsIkVzdGltYXRlIl1gDQoNCk5PVEU6IElmIChlLmcuKSB3ZSBmaW5kIGFuIGVmZmVjdCBmb3IgY29uZGl0aW9uMSwgd2UgY2FuIGFsc28gdXNlIHRoZSBlc3RpbWF0ZSBvZiB0aGUgaW50ZXJjZXB0IGZvciB0aGF0IHRvIGluZm9ybSBIMSB3aGVuIGxvb2tpbmcgYXQgZGF0YSBmcm9tIGNvbmRpdGlvbjI7IGFuZCB2aWNlIHZlcnNhLiBUaGlzIGlzIGEgYmV0dGVyIGVzdGltYXRlIHNpbmNlIHRoZSBjb25kaXRpb25zIGFyZSBtb3JlIGNsb3NlbHkgbWF0Y2hlZCB0byBlYWNoIG90aGVyIHRoYW4gZWl0aGVyIGlzIHRvIHRoZSBwaWxvdCBkYXRhLg0KDQojIyMgUmVxdWlyZWQgU2FtcGxlIEFuYWx5c2VzDQoNCiMjIyMgRnJlcXVlbnRpc3QgcG93ZXINCg0KTG9vayBhdCB0aGUgc2FtcGxlIHNpemUgcmVxdWlyZWQgdG8gb2J0YWluIGRpZmZlcmVudCBsZXZlbHMgb2YgcG93ZXIgd2l0aCBwaWxvdCBkYXRhIGZyb20gNyB5ZWFyIG9sZHM6IA0KDQpgYGB7cn0NCmRhdGFTID0gYXMubnVtZXJpYyh3aXRoKGRyb3BsZXZlbHMoY2hpbGQudHJhaW4uNyksIHRhcHBseShyZXN1bHQsbGlzdChzdWJqZWN0KSwgbWVhbiwgbmEucm09VCkpKQ0KZCA9IGNvaGVuc0QoeCA9IGRhdGFTLCBtdT0wLjUpDQoNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC45LCB0eXBlID0gYygib25lLnNhbXBsZSIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuOCwgdHlwZSA9IGMoIm9uZS5zYW1wbGUiKSwgYWx0ZXJuYXRpdmUgPSBjKCAiZ3JlYXRlciIpKQ0KcHdyLnQudGVzdChuID0gTlVMTCwgZCA9IGQsIHNpZy5sZXZlbCA9IDAuMDUsIHBvd2VyID0gLjcsIHR5cGUgPSBjKCJvbmUuc2FtcGxlIiksIGFsdGVybmF0aXZlID0gYyggImdyZWF0ZXIiKSkNCnJtKGRhdGFTKQ0Kcm0oZCkNCmBgYA0KDQojIyMjIFJlcXVpcmVkIHNhbXBsZSBmb3IgQkYgYW5hbHlzZXM6IA0KDQpIZXJlIHdlIGxvb2sgYXQgdGhlIHBpbG90IGRhdGEgZnJvbSA3IHllYXIgb2xkcywgdXNpbmcgSDEgaW5mb3JtZWQgYnkgdGhlIGVzdGltYXRlIGZvciAxMSB5ZWFyIG9sZHMuIEluIG91ciBhY3R1YWwgYW5hbHlzZXMgd2l0aCBuZXcgZGF0YSBmb3IgNyB5ZWFyIG9sZHMgd2Ugd2lsbCBiZSB1c2luZyBhbiBlc3RpbWF0ZSBmcm9tIHRoZSBjdXJyZW50IHBpbG90IGRhdGEgd2l0aCA3IHllYXIgb2xkcyB0byBpbmZvcm0gSDENCg0KYGBge3J9DQptZWFuQkYgPSBzdW1tYXJ5KGNoaWxkLnRyYWluLjcubW9kKSRjb2VmZmljaWVudHNbIihJbnRlcmNlcHQpIiwgIkVzdGltYXRlIl0NCnNlQkYgPSBzdW1tYXJ5KGNoaWxkLnRyYWluLjcubW9kKSRjb2VmZmljaWVudHNbIihJbnRlcmNlcHQpIiwgIlN0ZC4gRXJyb3IiXQ0KaDFtZWFuID0gc3VtbWFyeShjaGlsZC50cmFpbi4xMS5tb2QpJGNvZWZmaWNpZW50c1siKEludGVyY2VwdCkiLCAiRXN0aW1hdGUiXQ0KDQpCZihzZUJGLCBtZWFuQkYsIHVuaWZvcm0gPSAwLCBtZWFub2Z0aGVvcnkgPSAwLCBzZHRoZW9yeSA9IGgxbWVhbiwgdGFpbCA9IDEpDQoNCnJtKG1lYW5CRikNCnJtKHNlQkYpDQpgYGANCg0KV2UgY291bGQgcmVqZWN0IEgwIHdpdGggdGhlIGN1cnJlbnQgc2FtcGxlIG9mIE4gPSAxNS4NCg0KIyMgUHJlZGljdGlvbjI6IEltcHJvdmVtZW50IHdpdGggc2Vzc2lvbiBpbiBlYWNoIGNvbmRpdGlvbg0KDQojIyMgQmFzZWQgb246IA0KDQpXZSBzYXcgdGhpcyBpbiB0aGUgNyB5ZWFyIG9sZHMgaW4gdGhlIHBpbG90IHN0dWR5Lg0KDQo3IHllYXIgb2xkcyBtZWFucyA6IGByIHJvdW5kKCB3aXRoKGNoaWxkLnRyYWluLjcsIHRhcHBseShyZXN1bHQsIHNlc3Npb24sIG1lYW4sIG5hLnJtPVQpKSAsMilgDQo3IHllYXIgb2xkcyBsb2cgb2RkcyAoYmV0YSBmcm9tIGxtZSk6IGByIHN1bW1hcnkoY2hpbGQudHJhaW4uNy5tb2QpJGNvZWZmaWNpZW50c1sic2Vzc2lvbi5jdCIgLCJFc3RpbWF0ZSJdYA0KNyB5ZWFyIG9sZCBvZGQgKGV4cChiZXRhKSlgciBleHAoc3VtbWFyeShjaGlsZC50cmFpbi43Lm1vZCkkY29lZmZpY2llbnRzWyJzZXNzaW9uLmN0IiAsIkVzdGltYXRlIl0pYA0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogRnJlcXVlbnRpc3QgDQoNCldlIHdpbGwgdXNlIGFuIGxtZSBtb2RlbCBzaW1pbGFyIHRvIHRoYXQgdXNlZCBvbiB0aGUgcGlsb3QgZGF0YSBhYm92ZSBidXQgd2l0aCBkYXRhIGZyb20gYm90aCBjb25kaXRpb25zIChwaWN0dXJlcy1vbmx5IHZzLiBwaWN0dXJlcytkaWFjcml0aWNzKS4gV2Ugd2lsbCBmaXQgc2VwYXJhdGUgc2xvcGVzIGZvciBzZXNzaW9uIGZvciBlYWNoIGNvbmRpdGlvbi4gV2Ugd2lsbCBkbyB0aGlzIGJvdGggZm9yIGEgbW9kZWwgd2l0aCBqdXN0IHRoZSBmaXJzdCB0d28gc2Vzc2lvbnMgYW5kIGZvciBhIG1vZGVsIHdpdGggYWxsIGRhdGEuDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBCRiANCg0KU3VtbWFyeSBvZiBkYXRhIGZvciBlYWNoIGNvbmRpdGlvbjogbWVhbiBhbmQgU0UgZm9yIHNlc3Npb24uY3QgZm9yIGVhY2ggbGV2ZWwgb2YgY29uZGl0aW9uIGZyb20gbG1lDQp2YWx1ZSB0byBpbmZvcm0gSDE6IGVzdGltYXRlIGZyb20gYWJvdmUgcGlsb3QgZGF0YSBmb3Igc2V2ZW4geWVhciBvbGRzIGByIHN1bW1hcnkoY2hpbGQudHJhaW4uNy5tb2QpJGNvZWZmaWNpZW50c1sic2Vzc2lvbi5jdCIgLCJFc3RpbWF0ZSJdYA0KDQpJZiBpdCBhcHBlYXJzIHRoYXQgb25lIG9mIHRoZSBjb25kaXRpb25zIChjMSkgc2hvd3MgYSBwb3NpdGl2ZSBlZmZlY3Qgb2Ygc2Vzc2lvbiBhbmQgb25lIGRvZXNuJ3QgKGMyKSwgd2UgY2FuIGFsc28gZG8gQkYgYW5hbHlzZXMgZm9yIGMyIGRhdGEgd2l0aCBIMSBpbmZvcm1lZCBieSB0aGUgZXN0aW1hdGUgZnJvbSBjMSAodGhpcyBpcyBhIGJldHRlciBlc3RpbWF0ZSB0aGFuIHRoZSBwaWxvdCBkYXRhIHNpbmNlIHRoZSBjb25kaXRpb25zIGFyZSBtb3JlIGNsb3NlbHkgbWF0Y2hlZCB0byBlYWNoIG90aGVyIHRoYW4gZWl0aGVyIGlzIHRvIHRoZSBwaWxvdCBkYXRhKS4NCg0KIyMjIFJlcXVpcmVkIHNhbXBsZSBhbmFseXNlcw0KDQojIyMjIEZyZXF1ZW50aXN0cyBwb3dlcg0KDQpgYGB7cn0NCmRhdGFTID0gd2l0aChkcm9wbGV2ZWxzKGNoaWxkLnRyYWluLjcpLCB0YXBwbHkocmVzdWx0LGxpc3Qoc3ViamVjdCxzZXNzaW9uKSwgbWVhbiwgbmEucm09VCkpDQpkPSBjb2hlbnNEKHggPSBkYXRhU1ssMV0sIHkgPSBkYXRhU1ssMl0sIG1ldGhvZCA9ICJwYWlyZWQiKQ0KDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuOSwgdHlwZSA9IGMoInBhaXJlZCIpLCBhbHRlcm5hdGl2ZSA9IGMoImdyZWF0ZXIiKSkNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC44LCB0eXBlID0gYygicGFpcmVkIiksIGFsdGVybmF0aXZlID0gYygiZ3JlYXRlciIpKQ0KcHdyLnQudGVzdChuID0gTlVMTCwgZCA9IGQsIHNpZy5sZXZlbCA9IDAuMDUsIHBvd2VyID0gLjcsIHR5cGUgPSBjKCJwYWlyZWQiKSwgYWx0ZXJuYXRpdmUgPSBjKCAiZ3JlYXRlciIpKQ0KDQpybShkYXRhUykNCnJtKGQpDQpgYGANCg0KIyMjIyBSZXF1aXJlZCBzYW1wbGUgZm9yIEJGIGFuYWx5c2VzOiANCg0KQXMgZm9yIHByZWRpY3Rpb24gMSwgd2UgYWdhaW4gbG9vayBhdCB0aGUgcGlsb3QgZGF0YSBmcm9tIHNldmVuIHllYXIgb2xkcywgdXNpbmcgSDEgaW5mb3JtZWQgYnkgdGhlIGVzdGltYXRlIGZvciAxMSB5ZWFyIG9sZHMuIEluIG91ciBhY3R1YWwgYW5hbHlzZXMgd2lsbCBiZSB1c2luZyBhbiBlc3RpbWF0ZSBmcm9tIHRoZSBwaWxvdCBkYXRhIHRvIGluZm9ybSBIMS4NCg0KYGBge3J9DQptZWFuQkYgPSBzdW1tYXJ5KGNoaWxkLnRyYWluLjcubW9kKSRjb2VmZmljaWVudHNbInNlc3Npb24uY3QiLCAiRXN0aW1hdGUiXQ0Kc2VCRiA9IHN1bW1hcnkoY2hpbGQudHJhaW4uNy5tb2QpJGNvZWZmaWNpZW50c1sic2Vzc2lvbi5jdCIsICJTdGQuIEVycm9yIl0NCmgxbWVhbiA9IHN1bW1hcnkoY2hpbGQudHJhaW4uMTEubW9kKSRjb2VmZmljaWVudHNbInNlc3Npb24uY3QiLCAiRXN0aW1hdGUiXQ0KDQpCZihzZUJGLCBtZWFuQkYsIHVuaWZvcm0gPSAwLCBtZWFub2Z0aGVvcnkgPSAwLCBzZHRoZW9yeSA9IGgxbWVhbiwgdGFpbCA9IDEpDQoNCnJtKG1lYW5CRikNCnJtKHNlQkYpDQpgYGANCg0KV2UgaGF2ZSBzdWZmaWNpZW50IGV2aWRlbmNlIHRvIGFjY2VwdCBIMSBvdmVyIEgwIG9uIHRoZSBiYXNpcyBvZiBjdXJyZW50IHNhbXBsZS4NCg0KIyMgUHJlZGljdGlvbjM6IEdyZWF0ZXIgcGVyZm9ybWFuY2UgaW4gcGljdHVyZStkaWFjcml0aWMgY29uZGl0aW9uIHdpdGgganVzdCBwaWN0dXJlIGNvbmRpdGlvbg0KDQojIyMgQmFzZWQgb246IA0KDQpXZSBkb24ndCBoYXZlIGFueSBwaWxvdCBkYXRhIHdpdGggdGhpcyB0eXBlIG9mIG1hbmlwdWxhdGlvbiBmb3IgY2hpbGRyZW4uIA0KDQpUaGlzIHByZWRpY3Rpb24gaXMgbWFkZSBvbiB0aGUgYmFzaXMgb2YgYSByZWxhdGVkIGVmZmVjdCBzZWVuIGluIGFkdWx0IGRhdGE6IHRoZXkgc2hvd2VkIGdyZWF0ZXIgb3ZlcmFsbCBwZXJmb3JtYW5jZSBpbiBhIGNvbmRpdGlvbiB3aGVyZSB0aGV5IHNhdyBqdXN0IGRpYWNyaXRpY3MgcmF0aGVyIHRoYW4ganVzdCBwaWN0dXJlcy4gTm90ZSB0aGF0IGljb25pY2l0eSBtZWFucyB0aGF0IHlvdSBjYW4gcG90ZW50aWFsbHkgcmVzcG9uZCB3aGVuIHRoZXkgYXJlIHByZXNlbnQuIEl0IGlzIHBvc3NpYmxlIHRoYXQgaGF2aW5nIHRoZSBkaWFjcml0aWNzIHByZXNlbnQgd2lsbCBoZWxwIGNoaWxkcmVuIHRvbzsgdGhvdWdoIChhKSBjaGlsZHJlbiBjb3VsZCB3ZWxsIGJlIGRpZmZlcmVudCAoZGlhY3JpdGljcyBtaWdodCBiZSB0b28gYWJzdHJhY3QpIChiKSBpdCBjb3VsZCBiZSB0aGF0IGhhdmluZyB0aGUgcGljdHVyZSB0aGVyZSBhcyB3ZWxsIGFzIHRoZSBkaWFjcml0aWMgY2hhbmdlcyB0aGluZ3MuIA0KDQpNZWFucyBmcm9tIHRoZSBwaWxvdDoNCg0KYWR1bHQgbWVhbnMgOiBgciByb3VuZCggd2l0aChhZHVsdC50cmFpbiwgdGFwcGx5KHJlc3VsdCwgY29uZGl0aW9uLCBtZWFuLCBuYS5ybT1UKSkgLDIpYA0KYWR1bHQgbG9nIG9kZHMgKGJldGEgZnJvbSBsbWUpOiBgciBzdW1tYXJ5KGFkdWx0LnRyYWluLm1vZCkkY29lZmZpY2llbnRzWyJjb25kaXRpb24uY3QiICwiRXN0aW1hdGUiXWANCmFkdWx0IG9kZCAoZXhwKGJldGEpKWByIGV4cChzdW1tYXJ5KGFkdWx0LnRyYWluLm1vZCkkY29lZmZpY2llbnRzWyJzZXNzaW9uLmN0IiAsIkVzdGltYXRlIl0pYA0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogRnJlcXVlbnRpc3QgDQoNCldFIHdpbGwgcnVuIGFuIGxtZSBtb2RlbCBzaW1pbGFyIHRvIHRoYXQgdXNlZCBvbiBwaWxvdCBkYXRhIGFib3ZlIGJ1dCB3aXRoIGRhdGEgZnJvbSBib3RoIGNvbmRpdGlvbnM7IFdlIHdpbGwgbG9vayBmb3IgYSBmaXhlZCBlZmZlY3Qgb2YgY29uZGl0aW9uLiBXZSB3aWxsIGRvIHRoaXMgYm90aCBmb3IgYSBtb2RlbCB3aXRoIGp1c3QgZmlyc3QgdHdvIHNlc3Npb25zIGFuZCBmb3IgYSBtb2RlbCB3aXRoIGFsbCBkYXRhLg0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogQkYgDQoNClN1bW1hcnkgb2YgZGF0YTogbWVhbiBhbmQgU0UgZm9yIGNvbmRpdGlvbi5jdA0KdmFsdWUgdG8gaW5mb3JtIEgxOiBlc3RpbWF0ZSBmcm9tIGFib3ZlIEFEVUxUIHBpbG90IGRhdGEgIGByIHN1bW1hcnkoYWR1bHQudHJhaW4ubW9kKSRjb2VmZmljaWVudHNbImNvbmRpdGlvbi5jdCIgLCJFc3RpbWF0ZSJdYA0KDQpUaGVyZSBpcyBhIGNhdmVhdCBoZXJlIHNpbmNlIHRoaXMgdmFsdWUgY29tZXMgZnJvbSBhZHVsdHMgYW5kIHdpbGwgbGlrZWx5IG92ZXJlc3RpbWF0ZSBhbnkgZGlmZmVyZW5jZSBmb3IgY2hpbGRyZW4gKG1ha2luZyBpdCBhIGNvbnNlcnZhdGl2ZSBlc3RpbWF0ZSwgYmlhc2luZyBldmlkZW5jZSBmb3IgSDApLiANCg0KIyMjIFJlcXVpcmVkIFNhbXBsZSBBbmFseXNlcw0KDQojIyMjIEZyZXF1ZW50aXN0cyBwb3dlcg0KDQpOT1RFOiB0aGlzIGlzIGJhc2VkIG9uIEFEVUxUIGRhdGEuIEl0IGxpa2VseSB1bmRlcmVzdGltYXRlcyB0aGUgcG93ZXIgcmVxdWlyZWQgdG8gc2VlIHRoaXMgZGlmZmVyZW5jZS4NCg0KYGBge3J9DQpkYXRhUyA9IHdpdGgoZHJvcGxldmVscyhhZHVsdC50cmFpbiksIHRhcHBseShyZXN1bHQsbGlzdChzdWJqZWN0LGNvbmRpdGlvbiksIG1lYW4sIG5hLnJtPVQpKQ0KZCA9IGNvaGVuc0QoeCA9IGRhdGFTWywxXSwgeSA9IGRhdGFTWywyXSwgbWV0aG9kID0gInBvb2xlZCIpDQoNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC45LCB0eXBlID0gYygidHdvLnNhbXBsZSIpLCBhbHRlcm5hdGl2ZSA9IGMoImdyZWF0ZXIiKSkNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC44LCB0eXBlID0gYygidHdvLnNhbXBsZSIpLCBhbHRlcm5hdGl2ZSA9IGMoImdyZWF0ZXIiKSkNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC43LCB0eXBlID0gYygidHdvLnNhbXBsZSIpLCBhbHRlcm5hdGl2ZSA9IGMoImdyZWF0ZXIiKSkNCg0Kcm0oZGF0YVMpDQpybShkKQ0KYGBgDQoNClN1Z2dlc3RzIHRoYXQgZm9yIGFkdWx0cyB3ZSB3b3VsZCBuZWVkIDU4IHBlciBjb25kaXRpb24gdG8gZ2V0IDkwJSBwb3dlci4gV2Ugd291bGQgYmUgbGlrZWx5IHRvIG5lZWQgbW9yZSB3aXRoIGNoaWxkcmVuLg0KDQpHaXZlbiBwcmFjdGljYWwgY29uc3RyYWludHMsIHdlIGFyZSB1bmxpa2VseSB0byBvYnRhaW4gYSBzdWZmaWNpZW50IHNhbXBsZSBmb3IgdGhpcy4gSG93ZXZlciB0aGlzIGVmZmVjdCBpc24ndCBjcml0aWNhbCBpbiB0ZXJtcyBvZiBkZW1vbnN0cmF0aW5nIHdoYXQgbGVhZHMgdG8gZ3JlYXRlciBsZWFybmluZy4gKEl0IGlzIHRoZXJlZm9yZSBtb3JlIGltcG9ydGFudCB0byBkZW1vbnN0cmF0ZSB0aGF0IHRoZXkgYXJlIGFib3ZlIGNoYW5jZSBpbiBlYWNoIGNvbmRpdGlvbikuDQoNCiMjIFByZWRpY3Rpb24gNDogVGhleSB3aWxsIGltcHJvdmUgbW9yZSBpbiBvbmUgY29uZGl0aW9uIHRoYW4gdGhlIG90aGVyIChubyBwcmVkaWN0ZWQgZGlyZWN0aW9uKQ0KDQojIyMgQmFzZWQgb246DQoNCldlIGRvbid0IGhhdmUgYW55IGNsZWFyIGV2aWRlbmNlIHRvIGJhc2UgdGhpcyBvbi4gSG93ZXZlciBpdCBzZWVtcyByZWFzb25hYmxlIHRoYXQgdGhlIHR5cGUgb2YgdHJhaW5pbmcgd2lsbCBsZWFkIHRvIGRpZmZlcmVudCBsZWFybmluZyBzbG9wZXMuIE9uZSBwb3NzaWJpbGl0eSBpcyB0aGF0IGNoaWxkcmVuIG1heSBzaG93IGdyZWF0ZXIgbGVhcm5pbmcgaW4gdGhlIGNvbmRpdGlvbiB3aXRoIGRpYWNyaXRpY3MsIGR1ZSB0byBtb3JlIGluZm9ybWF0aW9uIHBlciB0cmlhbC4gSG93ZXZlciBpdCBpcyBhbHNvIHBvc3NpYmxlIHRoYXQgdGhleSBjb3VsZCBzaG93IHN0ZWVwZXIgbGVhcm5pbmcgaW4gdGhlIG90aGVyIGNvbmRpdGlvbiwgZHVlIHRvIG5lZWRpbmcgdG8gcGF5IG1vcmUgYXR0ZW50aW9uIHRvIGFuZCByZW1lbWJlciBpbmRpdmlkdWFsIHN0aW11bGkuIFdlIHNhdyBtZWFucyBpbiB0aGlzIGxhdHRlciBkaXJlY3Rpb24gaW4gdGhlIGFkdWx0IHBpbG90IGRhdGEgaS5lLiBtb3JlIGltcHJvdmVtZW50IGluIHRoZSBjb25kaXRpb24gd2l0aCBwaWN0dXJlcyAobGFiZWxsZWQgY29uZGl0aW9uICJpIiBmb3IgaW1wbGljaXQpIHRoYW4gd2l0aCBkaWFjcml0aWNzIChsYWJlbGxlZCAiZSIgZm9yIGV4cGxpY2l0KSAodGhvdWdoIHRoZSBjb25kaXRpb25zIHdlcmUgbm90IGV4YWN0bHkgdGhlIHNhbWUsIHNlZSBhYm92ZSkgdGhvdWdoIGl0IHdhc24ndCBzaWduaWZpY2FudC4NCg0KYWR1bHQgbWVhbnMgOiBgciByb3VuZCh3aXRoKGFkdWx0LnRyYWluLCB0YXBwbHkocmVzdWx0LCBsaXN0KGNvbmRpdGlvbiwgc2Vzc2lvbiksIG1lYW4sIG5hLnJtPVQpKSAsMilgDQogICAgYmV0YTogYHIgc3VtbWFyeShhZHVsdC50cmFpbi5tb2QpJGNvZWZmaWNpZW50c1sic2Vzc2lvbi5jdDpjb25kaXRpb24uY3QiLCJFc3RpbWF0ZSIgXWANCg0KIyMjIFBsYW5uZWQgQW5hbHlzZXM6IEZyZXF1ZW50aXN0IA0KDQpXZSB3aWxsIHVzZSBhbiBsbWUgbW9kZWwgc2ltaWxhciB0byB0aGF0IHVzZWQgb24gcGlsb3QgZGF0YSBhYm92ZSBidXQgd2l0aCBkYXRhIGZyb20gYm90aCBjb25kaXRpb25zOyB3ZSB3aWxsIGxvb2sgZm9yIGEgZml4ZWQgZWZmZWN0IG9mIGNvbmRpdGlvbi5jdDpzZXNzaW9uLmN0LiBXZSB3aWxsIGRvIHRoaXMgYm90aCBmb3IgYSBtb2RlbCB3aXRoIGp1c3QgZmlyc3QgdHdvIHNlc3Npb25zIGFuZCBmb3IgYSBtb2RlbCB3aXRoIGFsbCBkYXRhLg0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogQkYgDQoNClN1bW1hcnkgb2YgZGF0YTogbWVhbiBhbmQgU0UgZm9yIGludGVyYWN0aW9uIGJldHdlZW4gc2Vzc2lvbiBhbmQgY29uZGl0aW9uIChzZXNzaW9uLmN0IGJ5IGNvbmRpdGlvbi5jdCkgDQp2YWx1ZSB0byBpbmZvcm0gSDE6IGVzdGltYXRlIG9mIHNlc3Npb24gZnJvbSB0aGUgc2FtZSBtb2RlbCAoZS5nLiBzdW1tYXJ5KG1vZGVsLm5ld2RhdGEpJGNvZWZmaWNpZW50c1sic2Vzc2lvbi5jdCIgLCJFc3RpbWF0ZSJdLg0KDQpUaGlzIHdpbGwgcHJvdmlkZSBhIHJlbGF0aXZlbHkgaGlnaCBlc3RpbWF0ZSBvZiBsaWtlbHkgZWZmZWN0IG9mIGludGVyYWN0aW9uIChpZiBvbmUgaXMgcHJlc2VudCkgZ2l2ZW4gdGhlIGFjdHVhbCBkYXRhIHNldCAoc28gYWdhaW4sIGEgY29uc2VydmF0aXZlIGVzdGltYXRlKSANCg0KW05vdGU6IHdlIGFyZSBjaGVja2luZyB0aGlzIHdpdGggYSBzdGF0aXN0aWNzIGNvbnN1bHRhbnRdDQoNCiMjIyBSZXF1aXJlZCBTYW1wbGUgQW5hbHlzZXMNCg0KIyMjIyBGcmVxdWVudGlzdCBwb3dlcg0KDQpOb3RoaW5nIHRvIGJhc2UgcG93ZXIgYW5hbHlzaXMgb24gaGVyZSAoYXMgdGhlcmUgd2FzIG5vIGVmZmVjdCBpbiB0aGUgcGlsb3QgZGF0YSkuDQoNCiMjIyMgUmVxdWlyZWQgc2FtcGxlIGZvciBCRiBhbmFseXNlczogDQoNCk5vdGUgdGhpcyBpcyB3aXRoIGFkdWx0IGRhdGEgLSBpdCBleGVtcGxpZmllcyB0aGUgcHJvY2VzcyB3ZSB3aWxsIGFjdHVhbGx5IHVzZSB0byBjb25kdWN0IHBvd2VyIGFuYWx5c2VzIG9uIHRoZSBhY3R1YWwgZGF0YSANCg0KYGBge3J9DQptZWFuQkYgPSBzdW1tYXJ5KGFkdWx0LnRyYWluLm1vZCkkY29lZmZpY2llbnRzWyJzZXNzaW9uLmN0OmNvbmRpdGlvbi5jdCIsIkVzdGltYXRlIl0NCnNlQkYgPSBzdW1tYXJ5KGFkdWx0LnRyYWluLm1vZCkkY29lZmZpY2llbnRzWyJzZXNzaW9uLmN0OmNvbmRpdGlvbi5jdCIsIlN0ZC4gRXJyb3IiXQ0KaDFtZWFuID0gc3VtbWFyeShhZHVsdC50cmFpbi5tb2QpJGNvZWZmaWNpZW50c1sic2Vzc2lvbi5jdCIsIkVzdGltYXRlIl0NCkJmKHNlQkYsIG1lYW5CRiwgdW5pZm9ybSA9IDAsIG1lYW5vZnRoZW9yeSA9IDAsIHNkdGhlb3J5ID0gaDFtZWFuLCB0YWlsID0gMikNCg0Kcm0obWVhbkJGKQ0Kcm0oc2VCRikNCmBgYA0KDQpXZSB1c2UgdGFpbCA9IDIgaGVyZSBhcyB3ZSBkb24ndCBoYXZlIGEgY2xlYXIgZGlyZWN0aW9uIGZvciB0aGlzIGh5cG90aGVzaXMNCg0KU28sIHdpdGggYWR1bHQgcGlsb3QgZGF0YSB3ZSBkbyBoYXZlIGV2aWRlbmNlIGluIGZhdm9yIG9mIEgwIGZyb20gdGhlIGN1cnJlbnQgZGF0YSBzZXQuIA0KDQpPbmUgcG9zc2liaWxpdHkgd2l0aCBjaGlsZHJlbiBpcyB0aGF0IHdlIHdpbGwgbm90IGJlIGFibGUgdG8gb2J0YWluIGEgbGFyZ2UgZW5vdWdoIHNhbXBsZSB0byBwcm92aWRlIGV2aWRlbmNlIGZvci9hZ2FpbnN0IHRoZSBoeXBvdGhlc2lzIHRoYXQgdGhlcmUgaXMgbW9yZSBsZWFybmluZyBpbiBvbmUgZGlyZWN0aW9uLCBidXQgd2UgbWF5IGZpbmQgZXZpZGVuY2UgZm9yIHRoZSBIMSB0aGF0IHRoZXJlICppcyogYW4gZWZmZWN0IG9mIHNlc3Npb24gaW4gb25lIGNvbmRpdGlvbiBidXQgZm9yIHRoZSBIMCB0aGF0IHRoZXJlIGlzICpub3QqIGFuIGVmZmVjdCBvZiBzZXNzaW9uIGluIHRoZSBvdGhlciBjb25kaXRpb24uIElmIHNvLCB3ZSB3aWxsIGRlZW0gdGhpcyBzdWZmaWNpZW50IHRvIGFkZHJlc3MgdGhpcyBwcmVkaWN0aW9uLg0KDQojIDJBRkMgcGljdHVyZSBhbmQgMkFGQyBkaWFjcml0aWMNCg0KVGhlc2UgdHdvIHRlc3RzIGFyZSB2ZXJ5IHNpbWlsYXIgdG8gdHJhaW5pbmcgYnV0IHdpdGggZWl0aGVyIGp1c3QgcGljdHVyZXMgb3IganVzdCBkaWFjcml0aWNzLiBUaGUgdGVzdHMgYXJlIG9ubHkgZG9uZSBhcyBwb3N0IHRlc3RzLCBub3QgYXMgcHJlLXRlc3RzICh1bmxpa2UgdGhlIHJlc3Qgb2YgdGhlIHRlc3RzIGRpc2N1c3NlZCBhZnRlciB0aGlzIG9uZSkuDQoNCkNoaWxkcmVuIGluIHRoZSBwaWN0dXJlcytkaWFjcml0aWNzIGNvbmRpdGlvbiB3aWxsIGdldCB0aGUgMkFGQyBwaWN0dXJlcyB0ZXN0IGZvbGxvd2VkIGJ5IHRoZSAyQUZDIGRpYWNyaXRpY3MgdGVzdDsgY2hpbGRyZW4gaW4gdGhlIHBpY3R1cmVzLW9ubHkgdGVzdCB3aWxsIGdldCBqdXN0IDJBRkMgcGljdHVyZXMgYnV0IHdpbGwgZ2V0IGl0IHR3aWNlIChzbyB0aGF0IHRvdGFsIGV4cG9zdXJlIGRvZXNuJ3QgZGlmZmVyIGFjcm9zcyBjb25kaXRpb25zKS4NCg0KV2hlcmUgd2UganVzdCBsb29rIGF0IGNvbmRpdGlvbnMgc2VwYXJhdGVseSwgZm9yIHRoZSBwaWN0dXJlcyB0ZXN0LCB3ZSB3aWxsIGxvb2sgYXQgYWxsIG9mIHRoZSBkYXRhIChpLmUuIGZvciB0aGUgcGljdHVyZXMgb25seSBjb25kaXRpb24sIGZyb20gYm90aCBwYXJ0cyBvZiB0aGUgcmVwZWF0ZWQgdGVzdCkuIFdoZXJlIHdlIGNvbXBhcmUgY29uZGl0aW9ucywgd2Ugd2lsbCBsb29rIG9ubHkgdXNlIGRhdGEgZnJvbSB0aGUgZmlyc3QgMkFGQyB0ZXN0LiANCg0KIyMgUnVuIGxtZXMgb24gcmVsZXZhbnQgcGlsb3QgZGF0YQ0KDQpXZSBkaWRuJ3QgZG8gdGhpcyB0ZXN0IGluIHRoZSBwaWxvdCBzdHVkaWVzLCBob3dldmVyIHRoZSB0ZXN0IGlzIHNpbWlsYXIgdG8gdGhlIHRyYWluaW5nIHRhc2sgc28gd2UgdXNlIGEgbW9kZWwgYmFzZWQgb24ganVzdCB0aGUgbGFzdCAyNCB0cmlhbHMgb2YgdHJhaW5pbmcgZm9yIGluZm9ybWluZyBwb3dlciBkZWNpc2lvbnMuIA0KDQpgYGB7cn0NCmNoaWxkLnRyYWluLjcuczIuMjQgPSBkcm9wbGV2ZWxzKHN1YnNldChjaGlsZC50cmFpbiwgYWdlZ3JvdXAgPT0gIjd5ZWFycyIgJiBzZXNzaW9uID09InNlc3Npb24yIiAmIG9yZGVyPjcyKSkNCmNoaWxkLnRyYWluLjcuczIuMjQgPSBsaXpDZW50ZXIoY2hpbGQudHJhaW4uNy5zMi4yNCwgYygidG9uZWNvbnRyYXN0IikpDQoNCmNoaWxkLnRyYWluLjcuczIuczQubW9kID0gZ2xtZXIgKHJlc3VsdCB+DQogICAgICAgICsgdG9uZWNvbnRyYXN0LmN0DQogICAgICAgICsgKDF8c3ViamVjdCksDQogICAgICAgIGRhdGEgPSBjaGlsZC50cmFpbi43LnMyLjI0LCBmYW1pbHkgPSBiaW5vbWlhbCwgY29udHJvbD1nbG1lckNvbnRyb2wob3B0aW1pemVyID0gImJvYnlxYSIpKQ0KDQpyb3VuZChzdW1tYXJ5KGNoaWxkLnRyYWluLjcuczIuczQubW9kKSRjb2VmZmljaWVudHMsMykNCmBgYA0KDQpgYGB7cn0NCmNoaWxkLnRyYWluLjExLnMyLjI0ID0gZHJvcGxldmVscyhzdWJzZXQoY2hpbGQudHJhaW4sIGFnZWdyb3VwID09ICIxMXllYXJzIiAmIHNlc3Npb24gPT0ic2Vzc2lvbjIiICYgb3JkZXI+NzIpKQ0KY2hpbGQudHJhaW4uMTEuczIuMjQgPSBsaXpDZW50ZXIoY2hpbGQudHJhaW4uMTEuczIuMjQsIGMoInRvbmVjb250cmFzdCIpKQ0KDQpjaGlsZC50cmFpbi4xMS5zMi5zNC5tb2QgPSBnbG1lciAocmVzdWx0IH4NCiAgICAgICAgKyB0b25lY29udHJhc3QuY3QNCiAgICAgICAgKyAoMXxzdWJqZWN0KSwNCiAgICAgICAgZGF0YSA9IGNoaWxkLnRyYWluLjExLnMyLjI0LCBmYW1pbHkgPSBiaW5vbWlhbCwgY29udHJvbD1nbG1lckNvbnRyb2wob3B0aW1pemVyID0gImJvYnlxYSIpKQ0KDQpyb3VuZChzdW1tYXJ5KGNoaWxkLnRyYWluLjExLnMyLnM0Lm1vZCkkY29lZmZpY2llbnRzLDMpDQpgYGANCg0KYGBge3J9DQphZHVsdC50cmFpbi5zMi4yNCA9IHN1YnNldChhZHVsdC50cmFpbiwgc2Vzc2lvbiA9PSJzZXNzaW9uMiIgJiBvcmRlcj4yNjQpDQphZHVsdC50cmFpbi5zMi4yNCA9IGxpekNlbnRlcihhZHVsdC50cmFpbi5zMi4yNCwgbGlzdCgidG9uZWNvbnRyYXN0IikpDQoNCmFkdWx0LnRyYWluLnMyLjI0Lm1vZCA9IGdsbWVyIChyZXN1bHQgfg0KICAgICAgICArIHRvbmVjb250cmFzdC5jdA0KICAgICAgICArICgxfHN1YmplY3QpLA0KICAgICAgICBkYXRhID0gYWR1bHQudHJhaW4uczIuMjQsIGZhbWlseSA9IGJpbm9taWFsLCBjb250cm9sPWdsbWVyQ29udHJvbChvcHRpbWl6ZXIgPSAiYm9ieXFhIikpDQoNCnJvdW5kKHN1bW1hcnkoYWR1bHQudHJhaW4uczIuMjQubW9kKSRjb2VmZmljaWVudHMsMykNCmBgYA0KDQojIyBQcmVkaWN0aW9uIDE6IFBlcmZvcm1hbmNlIHdpbGwgYWJvdmUgY2hhbmNlIGluIGVhY2ggdGVzdCBpbiBlYWNoIGNvbmRpdGlvbi4NCg0KIyMjIEJhc2VkIG9uOg0KDQpUcmFpbmluZyBkYXRhIGluIHBpbG90IChzZWUgYWJvdmUpDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBGcmVxdWVudGlzdCANCg0KV2Ugd2lsbCB1c2UgYW4gbG1lIG1vZGVsIHNpbWlsYXIgdG8gdGhhdCBmb3IgdGhlIHRyYWluaW5nIGRhdGEuIEFnYWluIHdlIGZpdCBzZXBhcmF0ZSBpbnRlcmNlcHRzIGZvciBlYWNoIGNvbmRpdGlvbiBhbmQgY29tcGFyZSBlYWNoIHRvIGNoYW5jZSA9IC41MCAoaS5lLiBkZWZhdWx0IHZhbHVlIHJldHVybmVkKS4gU2luY2UgYWxsIHByZWRpY3RvcnMgYXJlIGNlbnRlcmVkLCB0aGUgaW50ZXJjZXB0IHJlZmxlY3RzIHRoZSBvdmVyYWxsIGF2ZXJhZ2UgKHJhdGhlciB0aGFuIGF0IGJhc2UgbGV2ZWxzIG9mIGEgZmFjdG9yKS4gDQoNCldlIHdpbGwgZG8gdGhpcyBib3RoIGZvciBhIG1vZGVsIHdpdGgganVzdCB0aGUgc2Vzc2lvbiAyIHRlc3QgYW5kIHNlc3Npb24gNCB0ZXN0OyBhcyBkaXNjdXNzZWQgYWJvdmUsIHdlIHdpbGwgdXNlIHRoZSBmdWxsIGRvdWJsZSBkYXRhIHNldCBmb3IgdGhlIDJBRkMgcGljdHVyZSB0ZXN0IGZvciB0aGUgcGFydGljaXBhbnRzIGluIHRoZSBwaWN0dXJlK2RpYWNyaXRpYyBjb25kaXRpb24uDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBCRiB0ZXN0IA0KDQpTdW1tYXJ5IG9mIGRhdGEgZm9yIGVhY2ggY29uZGl0aW9uOiBtZWFuIGFuZCBTRSBmb3IgaW50ZXJjZXB0IGZyb20gbG1lDQoNClZhbHVlIHRvIGluZm9ybSBIMTogYXNzdW1pbmcgdGhleSBzaG93IGxlYXJuaW5nLCB3ZSB3aWxsIHVzZSBhbiBlc3RpbWF0ZSBmcm9tIHRoZSBlcXVpdmFsZW50IGxtZSBmb3IgdHJhaW5pbmcgZGF0YSBmcm9tIHRoZSBjdXJyZW50IGRhdGEgc2V0IChOT1QgZnJvbSBwaWxvdCBkYXRhIC0gKnVubGVzcyogdGhlIGludGVyY2VwdCBmcm9tIHRyYWluaW5nIHNldCBkaWRuJ3Qgc3VnZ2VzdCBhYm92ZSBjaGFuY2UgcGVyZm9ybWFuY2UpLiBBZ2FpbiBub3RlIHRoYXQgaWYgd2UgZmluZCBhbiBlZmZlY3QgZm9yIGNvbmRpdGlvbjEsIHdlIGNhbiBhbHNvIHVzZSB0aGUgZXN0aW1hdGUgZm9yIGludGVyY2VwdCBmb3IgdGhhdCB0byBpbmZvcm0gSDEgd2hlbiBsb29raW5nIGF0IGRhdGEgZnJvbSBjb25kaXRpb24yOyBhbmQgdmljZSB2ZXJzYS4gVGhpcyBpcyBhIGJldHRlciBlc3RpbWF0ZSBzaW5jZSB0aGUgY29uZGl0aW9ucyBhcmUgbW9yZSBjbG9zZWx5IG1hdGNoZWQgdG8gZWFjaCBvdGhlciB0aGFuIGVpdGhlciBpcyB0byB0aGUgcGlsb3QgZGF0YS4NCg0KIyMjIFJlcXVpcmVkIFNhbXBsZSBBbmFseXNlcw0KDQojIyMjIEZyZXF1ZW50aXN0IHBvd2VyDQoNCkhlcmUgd2UgbG9vayBhdCBwb3dlciB1c2luZyB0aGUgdmFsdWVzIGZyb20gdGhlIHN1YnNldCBvZiB0cmFpbmluZyBkYXRhIGZyb20gdGhlIGFib3ZlDQoNCmBgYHtyfSAgICAgICAgIA0KZGF0YVM9YXMubnVtZXJpYyh3aXRoKGRyb3BsZXZlbHMoY2hpbGQudHJhaW4uNy5zMi4yNCksIHRhcHBseShyZXN1bHQsbGlzdChzdWJqZWN0KSwgbWVhbiwgbmEucm09VCkpKQ0KZD0gY29oZW5zRCh4ID0gZGF0YVMsIG11PTAuNSkNCg0KcHdyLnQudGVzdChuID0gTlVMTCwgZCA9IGQsIHNpZy5sZXZlbCA9IDAuMDUsIHBvd2VyID0gLjksIHR5cGUgPSBjKCJvbmUuc2FtcGxlIiksIGFsdGVybmF0aXZlID0gYyggImdyZWF0ZXIiKSkNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC44LCB0eXBlID0gYygib25lLnNhbXBsZSIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuNywgdHlwZSA9IGMoIm9uZS5zYW1wbGUiKSwgYWx0ZXJuYXRpdmUgPSBjKCAiZ3JlYXRlciIpKQ0KDQpybShkYXRhUykNCnJtKGQpDQpgYGANCg0KVGhpcyBzdWdnZXN0cyBhIHNhbXBsZSBzaXplIG9mIDIxIGlzIHN1ZmZpY2llbnQgZm9yIDkwJSBwb3dlci4NCg0KIyMjIyBSZXF1aXJlZCBzYW1wbGUgZm9yIEJGIGFuYWx5c2VzOiANCg0KSGVyZSB3ZSB1c2UgdGhlIHN1YnNldCBvZiBwaWxvdCBkYXRhIHdpdGggNyB5ZWFyIG9sZHMgYW5kIGFuIEgxIGluZm9ybWVkIGJ5IHRoZSBlc3RpbWF0ZSBmcm9tIDExIHllYXIgb2xkcyB3aG9sZSB0cmFpbmluZyBkYXRhIHNldCAobm90ZTogaW4gYWN0dWFsIGFuYWx5c2VzIEgxIHdpbGwgYmUgaW5mb3JtZWQgYnkgYW4gZXN0aW1hdGUgZnJvbSBtb2RlbCBvZiB0aGUgY3VycmVudCB0cmFpbmluZyBkYXRhIHdpdGggNyB5ZWFyIG9sZHMgKQ0KDQpgYGB7cn0NCm1lYW5CRiA9IHN1bW1hcnkoY2hpbGQudHJhaW4uNy5zMi5zNC5tb2QpJGNvZWZmaWNpZW50c1siKEludGVyY2VwdCkiICwiRXN0aW1hdGUiXQ0Kc2VCRiA9IHN1bW1hcnkoY2hpbGQudHJhaW4uNy5zMi5zNC5tb2QpJGNvZWZmaWNpZW50c1siKEludGVyY2VwdCkiICwiU3RkLiBFcnJvciJdDQpoMW1lYW4gPSBzdW1tYXJ5KGNoaWxkLnRyYWluLjExLm1vZCkkY29lZmZpY2llbnRzWyIoSW50ZXJjZXB0KSIgLCJFc3RpbWF0ZSJdDQoNCkJmKHNlQkYsIG1lYW5CRiwgdW5pZm9ybSA9IDAsIG1lYW5vZnRoZW9yeSA9IDAsIHNkdGhlb3J5ID0gaDFtZWFuLHRhaWwgPSAxKQ0KQmZfcG93ZXJjYWxjKHNlQkYsIG1lYW5CRiwgdW5pZm9ybSA9IDAsIG1lYW5vZnRoZW9yeSA9IDAsIE4gPSAxNSwgbWluID0gMTUsIG1heCA9IDIwLCBzZHRoZW9yeSA9IGgxbWVhbiwgdGFpbCA9IDEpDQoNCnJtKG1lYW5CRikNCnJtKHNlQkYpDQpgYGANCg0KU3VnZ2VzdHMgZG9uJ3QgY3VycmVudGx5IGhhdmUgc3VmZmljaWVudCBzYW1wbGUgKE4gPSAxNSkgdG8gZ2V0IHJlbGlhYmxlIGV2aWRlbmNlIGZvciBIMSwgYnV0IGNvdWxkIGRvIHdpdGggMTkgcGFydGljaXBhbnRzLg0KDQojIyBQcmVkaWN0aW9uIDI6IEZvciB0aGUgcGljdHVyZS1vbmx5IHRlc3QsIHRoZXJlIHdpbGwgYmUgZ3JlYXRlciBwZXJmb3JtYW5jZSBpbiB0aGUgcGljdHVyZS1vbmx5IGNvbmRpdGlvbg0KDQojIyMgQmFzZWQgb24NCg0KQ2hpbGRyZW4gaW4gdGhlIGNvbmRpdGlvbiB3aGVyZSBkaWFjcml0aWNzIGFyZSBwcmVzZW50IG1pZ2h0IGhhdmUgYmVjb21lIG92ZXJseSByZWxpYW50IG9uIHRoZW0gZHVyaW5nIHRyYWluaW5nIGFuZCB0aHVzIHVuYWJsZSB0byBkbyB0aGUgdGVzdCB3aGVuIHRoZXkgYXJlIGFic2VudCwgYWx0aG91Z2ggd2UgZG9uJ3QgY3VycmVudGx5IGhhdmUgc3BlY2lmaWMgZGF0YSB0byBiYXNlIHRoaXMgb24uDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBGcmVxdWVudGlzdCANCg0KV2Ugd2lsbCBydW4gYW4gbG1lIG1vZGVsIG9uIDcgeWVhciBvbGRzIGRhdGEsIGxvb2tpbmcgYXQgdGhlIGVmZmVjdCBvZiBjb25kaXRpb24uIFdlIHdpbGwgZG8gdGhpcyBib3RoIGZvciBhIG1vZGVsIHdpdGgganVzdCBkYXkyIHRlc3QgYW5kIGRheTQgdGVzdDsgYXMgZGlzY3Vzc2VkIGFib3ZlLCB3ZSB3aWxsIG9ubHkgdXNlIHRoZSBoYWxmIHNldCBmb3IgdGhlIDJBRkMgcGljdHVyZSB0ZXN0IGZvciB0aGUgcGFydGljaXBhbnRzIGluIHRoZSBwaWN0dXJlK2RpYWNyaXRpYyBjb25kaXRpb24uDQoNCiMjIyBQbGFubmVkIEFuYWx5c2VzOiBCRiB0ZXN0IA0KDQpTdW1tYXJ5IG9mIGRhdGEgZm9yIGVhY2ggY29uZGl0aW9uOiBtZWFuIGFuZCBTRSBmb3IgY29uZGl0aW9uIGZyb20gbG1lDQp2YWx1ZSB0byBpbmZvcm0gSDE6IGFzc3VtaW5nIHRoZXkgc2hvdyBsZWFybmluZywgdXNlIHRoZSBlc3RpbWF0ZSBvZiBpbnRlcmNlcHQgZnJvbSB0aGUgY3VycmVudCBtb2RlbCAobm90ZSBvdGhlciB2YWx1ZXMgYXJlIGNlbnRlcmVkLCBzbyB0aGlzIGlzIGVxdWl2YWxlbnQgdG8gZ3JhbmQgbWVhbjsgaXQgd2lsbCBiZSBjb25zZXJ2YXRpdmUpDQoNCihXZSBhcmUgc2Vla2luZyBzdGF0aXN0aWNhbCBhZHZpY2UgdG8gY29uZmlybSB0aGF0IHRoaXMgaXMgYSByZWFzb25hYmxlLCBpZiBjb25zZXJ2YXRpdmUsIGVzdGltYXRlIGZvciBIMSkNCg0KIyMjIFJlcXVpcmVkIFNhbXBsZSBBbmFseXNlcw0KDQpXZSBkb24ndCBoYXZlIGFueSBkYXRhIHRoYXQgd2UgY2FuIGJhc2UgYW5hbHlzZXMgb24gaGVyZSAoY29tcGFyaXNvbiBvZiBjb25kaXRpb25zIGluIHRoZSBwaWxvdCBhZHVsdCBkYXRhIGlzIHRvbyBkaXNzaW1pbGFyKS4NCg0KTm90ZSB0aGF0IGl0IG1heSBwcm92ZSBkaWZmaWN1bHQgdG8gb2J0YWluIGEgc3VmZmljaWVudCBzYW1wbGUgdG8gZ2FpbiBldmlkZW5jZSBmb3IgSDEgb3IgSDAuIEhvd2V2ZXIsIGl0IG1heSBiZSB0aGF0IHdlIHNlZSBhYm92ZSBjaGFuY2UgcGVyZm9ybWFuY2Ugb25seSBmb3IgdGhlIHBpY3R1cmUtb25seSBjb25kaXRpb24uIEluIHRoYXQgY2FzZSwgd2UgbWF5IGxvb2sgdG8gdGhlIHByZXZpb3VzIGFuYWx5c2VzIChQcmVkaWN0aW9uIDEpIGFuZCBiZSBhYmxlIHRvIHNob3cgdGhhdCB0aGVyZSBpcyBldmlkZW5jZSBmb3IgSDEgb3ZlciBIMCBpbiBvbmUgY29uZGl0aW9uLCBidXQgZm9yIEgwIG92ZXIgSDEgaW4gdGhlIG90aGVyLiBJZiBzbywgd2Ugd2lsbCBiZSBhYmxlIHRvIHNheSB0aGF0IHRoZXJlIGlzIGV2aWRlbmNlIG9mIGxlYXJuaW5nIGluIG9uZSBjb25kaXRpb24gYW5kIG5vdCB0aGUgb3RoZXIsIGFuZCB0aGlzIHdpbGwgYmUgZGVlbWVkIHN1ZmZpY2llbnQgdG8gYWRkcmVzcyB0aGlzIGh5cG90aGVzaXMuIA0KDQojIERpc2NyaW1pbmF0aW9uIChUaHJlZS1JbnRlcnZhbCBPZGRpdHkgVGFzaykNCg0KVGhpcyB0ZXN0IHdpbGwgYmUgY29tcGxldGVkIGJvdGggcHJlIGFuZCBwb3N0IHRlc3QuIENoaWxkcmVuIHdpbGwgaGVhciB0aHJlZSBmcm9ncyBlYWNoIHByb2R1Y2UgYSBNYW5kYXJpbiB3b3JkLiBPbmUgcHJvZHVjZXMgdGhlIHRhcmdldCAoImRpZmZlcmVudCIpIHdvcmQgYW5kIHRoZSBvdGhlciB0d28gZWFjaCBwcm9kdWNlIHRoZSBzYW1lIGZvaWwgd29yZCwgd2hpY2ggd2lsbCBiZSBhIHdvcmQgZGlmZmVyaW5nIGZyb20gdGhlIHRhcmdldCBvbmx5IGluIHRvbmUgKGUuZy4gbWFvIFt0MV0sIG1hbyBbdDFdLCBtYW8gW3Q0XSkuIA0KDQpFYWNoIG9mIHRoZSA2IG9uZSBjb250cmFzdHMgYXJlIHRlc3RlZC4gV2Ugd2lsbCBwdXQgdG9uZSBjb250cmFzdCBpbnRvIHRoZSBtb2RlbCwgc2luY2UgaXQgaXMgbGlrZWx5IHRvIGhhdmUgYW4gZWZmZWN0LCBidXQgZG9uJ3QgaGF2ZSBzcGVjaWZpYyBoeXBvdGhlc2VzIG9mIGludGVyZXN0IGhlcmUuIFRoZXJlIGFyZSBmb3VyIHRhbGtlcnMsIDNmIDFtLiBUcmlhbHMgaW4gd2hpY2ggdGhlIG0gaXMgdGhlIG9kZCBvbmUgb3V0IGFyZSBrbm93biB0byBiZSBlYXNpZXN0IGFuZCB0aG9zZSB3aGVyZSBvbmUgb2YgdGhlIHNwZWFrZXJzIGlzIG0gYnV0IGl0IGlzIG5vdCB0aGUgb2RkIG9uZSBvdXQgYXJlIGhhcmRlc3QuIFRoZXJlIGFyZSBhbiBlcXVhbCBudW1iZXIgb2YgZWFjaCB0cmlhbCB0eXBlIGFuZCB3ZSBwdXQgdHJpYWwgdHlwZSBpbnRvIHRoZSBtb2RlbCBhcyBhIGZhY3RvcjsgdGhvdWdoIGFnYWluIGl0IGlzbid0IGEgcXVlc3Rpb24gZm9yIHdoaWNoIHdlIGhhdmUgcHJlZGljdGlvbnMuDQoNCkZvciB0aGUgaW5pdGlhbCBkYXRhIHNldCBjb2xsZWN0ZWQsIHdlIHdpbGwgY29uc2lkZXIgYm90aCBwcmUtdGVzdCAtPiBwb3N0dGVzdDEgKHNlc3Npb24gMikgYW5kIHByZS10ZXN0IC0+IHBvc3QtdGVzdDIgKHNlc3Npb24gNCkuIElmIGVxdWl2YWxlbnQgcmVzdWx0cyBhcmUgb2J0YWluZWQsIHN1YnNlcXVlbnQgdGVzdGluZyB3aWxsIGRyb3AgdGhlIGZpbmFsIHR3byBzZXNzaW9ucyAoc2VlIG5vdGUgYWJvdmUpLg0KDQojIyBMb2FkIHVwIGFuZCBydW4gbG1lcyBvbiByZWxldmFudCBwaWxvdCBkYXRhDQoNClRoZSBwaWxvdCBjaGlsZCBkYXRhIGJlbG93IGNvbWVzIGZyb20gc2FtZSB0d28gc2Vzc2lvbiBzdHVkeSBhcyB0aGUgcGlsb3QgdHJhaW5pbmcgZGF0YSAocmVjYWxsLCB0aGV5IHdlcmUgdHJhaW5lZCBvbiBzdGltdWxpIHNpbWlsYXIgdG8gdGhlICJwaWN0dXJlLW9ubHkiIGNvbmRpdGlvbiBpbiB0aGUgY3VycmVudCBzdHVkeS4pDQoNClRoZSBhZHVsdCBkYXRhIGJlbG93IGNvbWVzIGZyb20gYSBkaWZmZXJlbnQgdHdvIHNlc3Npb24gc3R1ZHkgd2hlcmUgdGhlcmUgd2VyZSB0d28gY29uZGl0aW9uICgxKSB0cmFpbmVkIG9uIHN0aW11bGkgc2ltaWxhciB0byB0aGUgInBpY3R1cmUtb25seSIgY29uZGl0aW9uIGluIHRoZSBjdXJyZW50IHN0dWR5ICgyKSB0cmFpbmVkIG9uIHBpY3R1cmVzIG9mIEpVU1Qgb2YgdGhlIGRpYWNyaXRpY3MuIFRoaXMgaXMgdXNlZnVsIGZvciBjb25zaWRlcmluZyBwb3NzaWJsZSBlZmZlY3RzIG9mIGNvbmRpdGlvbiBpbiB0aGUgZGF0YSAod2l0aCB0aGUgY2F2ZWF0IHRoYXQgY29tcGFyaXNvbiBpcyBzb21ld2hhdCBkaWZmZXJlbnQpLg0KDQpOb3RlIHRoYXQgZm9yIGJvdGggYWR1bHRzIGFuZCBjaGlsZHJlbiBpbiB0aGUgcGlsb3QgZXhwZXJpbWVudCB3ZSBpbmNsdWRlZCBib3RoIHRyYWluZWQgYW5kIHVudHJhaW5lZCBpdGVtcyBpbiB0aGUgZGlzY3JpbWluYXRpb24gdGVzdC4gRm9yIHRoZSBjdXJyZW50IGV4cGVyaW1lbnQgd2Ugd2lsbCB1c2Ugb25seSB1bnRyYWluZWQgaXRlbXMgaW4gdGhpcyB0ZXN0IHNvIHdlIHJlbW92ZSB0aGUgdHJhaW5lZCBpdGVtcyBmcm9tIHRoZSBhbmFseXNlcyBiZWxvdy4NCg0KQXMgYWJvdmUsIHRvbmUgY29udHJhc3QgaXMgYSBmaXhlZCBlZmZlY3Qgd2l0aCA2IGxldmVscyAoc2l4IHBvc3NpYmxlIGNvbnRyYXN0cykuIEl0IGlzIGV4cGVjdGVkIHRvIGNvbnRyaWJ1dGUgdG8gbW9kZWwgYW5kIGlzIHRodXMgaW5jbHVkZWQgYnV0IGlzbid0IG9mIHNwZWNpZmljIGludGVyZXN0Lg0KDQpgYGB7cn0NCmNoaWxkLmRpc2NyaW0gPSByZWFkLmNzdigia2lkc2Rpc2NyaW1fY2xlYW4uY3N2IikNCmNoaWxkLmRpc2NyaW0kcHJlX3Bvc3QgPSByZWxldmVsKGNoaWxkLmRpc2NyaW0kcHJlX3Bvc3QsIHJlZj0icHJlIikNCmNoaWxkLmRpc2NyaW0kYWdlZ3JvdXAgPSBhcy5mYWN0b3IoY2hpbGQuZGlzY3JpbSRhZ2Vncm91cCkNCmNoaWxkLmRpc2NyaW0kcHJlX3Bvc3QgPSByZWxldmVsKGNoaWxkLmRpc2NyaW0kcHJlX3Bvc3QsIHJlZj0icHJlIikNCmNoaWxkLmRpc2NyaW0gPC0gZHJvcGxldmVscyhzdWJzZXQoY2hpbGQuZGlzY3JpbSwgbmV3b3JvbGQgPT0gIm5ld3dvcmQiKSkNCg0KYWR1bHQuZGlzY3JpbSA9IHJlYWQuY3N2ICgiYWR1bHRzZGlzY3JpbV9jbGVhbi5jc3YiKQ0KYWR1bHQuZGlzY3JpbSRwcmVfcG9zdCA9IHJlbGV2ZWwoYWR1bHQuZGlzY3JpbSRwcmVfcG9zdCwgcmVmPSJwcmUiKQ0KYWR1bHQuZGlzY3JpbSRjb25kaXRpb24gPSByZWxldmVsKGFkdWx0LmRpc2NyaW0kY29uZGl0aW9uLCByZWY9ImkiKQ0KYWR1bHQuZGlzY3JpbSA8LSBkcm9wbGV2ZWxzKHN1YnNldChhZHVsdC5kaXNjcmltLCBuZXdvcm9sZCA9PSAibmV3d29yZCIpKQ0KYGBgDQoNCmBgYHtyfQ0KY2hpbGQuZGlzY3JpbS43ID0gZHJvcGxldmVscyhzdWJzZXQoY2hpbGQuZGlzY3JpbSwgYWdlZ3JvdXAgPT0gIjciKSkNCmNoaWxkLmRpc2NyaW0uNyA8LSBsaXpDZW50ZXIoY2hpbGQuZGlzY3JpbS43LCBsaXN0KCJwcmVfcG9zdCIsICJ0cmlhbHR5cGUiLCAidG9uZWNvbnRyYXN0IikpDQoNCmNoaWxkLmRpc2NyaW0uNy5tb2QgPSBnbG1lciAoY29ycmVjdCB+DQogICAgICAgICsgcHJlX3Bvc3QuY3QNCiAgICAgICAgKyB0cmlhbHR5cGUuY3QgDQogICAgICAgICsgdG9uZWNvbnRyYXN0LmN0DQogICAgICAgICsgKHByZV9wb3N0LmN0fHBhcnRpY2lwYW50bnVtYmVyKSwNCiAgICAgICAgIGRhdGEgPSBjaGlsZC5kaXNjcmltLjcsIGZhbWlseSA9IGJpbm9taWFsLCBjb250cm9sPWdsbWVyQ29udHJvbChvcHRpbWl6ZXIgPSAiYm9ieXFhIikpDQoNCnJvdW5kKHN1bW1hcnkoY2hpbGQuZGlzY3JpbS43Lm1vZCkkY29lZmZpY2llbnRzLCAzKQ0KYGBgDQoNCmBgYHtyfQ0KYWR1bHQuZGlzY3JpbSA8LSBsaXpDZW50ZXIoYWR1bHQuZGlzY3JpbSwgbGlzdCgicHJlX3Bvc3QiLCAidHJpYWx0eXBlIiwgImNvbmRpdGlvbiIsICJ0b25lY29udHJhc3QiKSkNCg0KYWR1bHQuZGlzY3JpbS5tb2QgPSBnbG1lciAoY29ycmVjdCB+DQogICAgICAgICsgY29uZGl0aW9uLmN0ICogcHJlX3Bvc3QuY3QNCiAgICAgICAgKyB0cmlhbHR5cGUuY3QgDQogICAgICAgICsgdG9uZWNvbnRyYXN0LmN0DQogICAgICAgICsgKHByZV9wb3N0LmN0fHBhcnRpY2lwYW50bnVtYmVyKSwNCiAgICAgICAgIGRhdGEgPSBhZHVsdC5kaXNjcmltLCBmYW1pbHkgPSBiaW5vbWlhbCwgY29udHJvbD1nbG1lckNvbnRyb2wob3B0aW1pemVyID0gImJvYnlxYSIpKQ0KDQpyb3VuZChzdW1tYXJ5KGFkdWx0LmRpc2NyaW0ubW9kKSRjb2VmZmljaWVudHMsIDMpDQpgYGANCg0KIyMgUHJlZGljdGlvbiAxOiBUaGVyZSB3aWxsIGJlIGltcHJvdmVtZW50IGZyb20gcHJlLXBvc3QgdGVzdCBpbiBlYWNoIGNvbmRpdGlvbg0KDQojIyMgQmFzZWQgb24NCg0KSW4gdGhlIHBpbG90IGRhdGEsIGFkdWx0cyBzaG93IGltcHJvdmVtZW50IHdpdGggc2Vzc2lvbiwgYnV0IDcgeWVhciBvbGRzIGRpZG4ndCAobm9yIGRpZCAxMSB5ZWFyIG9sZHMpDQoNCm1lYW5zIDogYHIgcm91bmQoIHdpdGgoYWR1bHQuZGlzY3JpbSwgdGFwcGx5KGNvcnJlY3QsIHByZV9wb3N0LCBtZWFuLCBuYS5ybT1UKSkgLDIpYDsNCmxvZyBvZGRzIChiZXRhIGZyb20gbG1lKTogYHIgc3VtbWFyeShhZHVsdC5kaXNjcmltLm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdYDsNCm9kZCAoZXhwKGJldGEpKWByIGV4cChzdW1tYXJ5KGFkdWx0LmRpc2NyaW0ubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl0pYA0KDQo3eWVhciBvbGRzIChkb24ndCBzaG93IHRoaXMtIGluIGZhY3QgdGhlIG1lYW5zIGFyZSByZXZlcnNlZCApDQoNCm1lYW5zIDogYHIgcm91bmQoIHdpdGgoY2hpbGQuZGlzY3JpbS43LCB0YXBwbHkoY29ycmVjdCwgcHJlX3Bvc3QsIG1lYW4sIG5hLnJtPVQpKSAsMilgOw0KbG9nIG9kZHMgKGJldGEgZnJvbSBsbWUpOiBgciBzdW1tYXJ5KGNoaWxkLmRpc2NyaW0uNy5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXWA7DQpvZGQgKGV4cChiZXRhKSlgciBleHAoc3VtbWFyeShjaGlsZC5kaXNjcmltLjcubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl0pYA0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogRnJlcXVlbnRpc3QgDQoNCldlIHdpbGwgdXNlIGFuIGxtZSBtb2RlbCBzaW1pbGFyIHRvIHRoYXQgdXNlZCBvbiB0aGUgcGlsb3QgZGF0YSBhYm92ZSBidXQgd2l0aCBkYXRhIGZyb20gYm90aCBjb25kaXRpb25zOyB3ZSB3aWxsIGZpdCBzZXBhcmF0ZSBzbG9wZXMgZm9yIHByZSBhbmQgcG9zdCB0ZXN0IGluIGVhY2ggY29uZGl0aW9uIA0KDQpGb3IgdGhlIGluaXRpYWwgZGF0YSBzZXQgY29sbGVjdGVkIHdlIHdpbGwgZG8gdGhpcyBib3RoIHRvIGNvbXBhcmUgcHJlIHRlc3QgdG8gcG9zdC10ZXN0IDEgKHNlc3Npb24yKSBhbmQgcHJlLXRlc3QgdG8gcG9zdC10ZXN0MiAoc2Vzc2lvbjQpLg0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogQkYgDQoNClN1bW1hcnkgb2YgZGF0YSBmb3IgZWFjaCBjb25kaXRpb246IG1lYW4gYW5kIFNFIGZvciBwcmUtcG9zdCBmcm9tIGxtZQ0KdmFsdWUgdG8gaW5mb3JtIEgxOiBXZSB3aWxsIHVzZSBhbiBlc3RpbWF0ZSBmcm9tIHRoZSBhYm92ZSBwaWxvdCBkYXRhIGZvciBhZHVsdHMgaS5lLiBgciBzdW1tYXJ5KGFkdWx0LmRpc2NyaW0ubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl1gDQoNCk5vdGU6IHRoaXMgYWR1bHQgdmFsdWUgd2lsbCBsaWtlbHkgb3ZlcmVzdGltYXRlIHRoZSBtZWFucy4gQSBiZXR0ZXIgdmFsdWUgd291bGQgY29tZSBmcm9tIHRoZSBuZXcgZGF0YSBmcm9tIGNoaWxkcmVuIHRoZW1zZWx2ZXMgLSB0aGVyZWZvcmUsIGlmIHRoZXkgc2hvdyBsZWFybmluZyBpbiBvbmUgY29uZGl0aW9uIHdlIHdpbGwgdXNlIHRoYXQgdG8gaW5mb3JtIHRoZSBCRiBmb3IgdGhlIG90aGVyIGNvbmRpdGlvbiAoYW5kIGlmIGJvdGggc2hvdyBsZWFybmluZyB3ZSB3aWxsIHVzZSB0byBpbmZvcm0gQkYgZm9yIGVhY2ggb3RoZXIpLiANCg0KIyMjIFJlcXVpcmVkIFNhbXBsZSBBbmFseXNlcw0KDQojIyMjIEZyZXF1ZW50aXN0IFBvd2VyDQoNCk5vdGU6IFRoaXMgYW5hbHlzaXMgaXMgaW5jbHVkZWQgZm9yIGNvbXBsZXRlbmVzcyBidXQgaXMgbm90IHJlYWxseSByZWxldmFudCBzaW5jZSBpdCBpcyBiYXNlZCBvbiBhZHVsdCBkYXRhLiBJZiBjaGlsZHJlbiBkbyBzaG93IGFuIGVmZmVjdCwgaXQgaXMgbGlrZWx5IHRvIGJlIHNtYWxsZXIgYW5kIHRoZXkgd2lsbCBoYXZlIGxhcmdlciBTRSANCg0KYGBge3J9DQpkYXRhUyA9IHdpdGgoZHJvcGxldmVscyhhZHVsdC5kaXNjcmltKSwgdGFwcGx5KGNvcnJlY3QsbGlzdChwYXJ0aWNpcGFudG51bWJlciwgcHJlX3Bvc3QpLCBtZWFuLCBuYS5ybT1UKSkNCmQgPSBjb2hlbnNEKHggPSBhcy5udW1lcmljKGRhdGFTWywxXSkseSA9IGFzLm51bWVyaWMoZGF0YVNbLDJdKSwgbWV0aG9kID0gInBhaXJlZCIpDQoNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC45LCB0eXBlID0gYygicGFpcmVkIiksIGFsdGVybmF0aXZlID0gYyggImdyZWF0ZXIiKSkNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC44LCB0eXBlID0gYygicGFpcmVkIiksIGFsdGVybmF0aXZlID0gYyggImdyZWF0ZXIiKSkNCnB3ci50LnRlc3QobiA9IE5VTEwsIGQgPSBkLCBzaWcubGV2ZWwgPSAwLjA1LCBwb3dlciA9IC43LCB0eXBlID0gYygicGFpcmVkIiksIGFsdGVybmF0aXZlID0gYyggImdyZWF0ZXIiKSkNCg0Kcm0oZCkNCnJtKGRhdGFTKQ0KYGBgDQoNCiMjIyMgUmVxdWlyZWQgc2FtcGxlIGZvciBCRiBhbmFseXNlcyBmcm9tIHBpbG90IGRhdGENCg0KSGVyZSB3ZSBsb29rIGF0IGRhdGEgZnJvbSA3IHllYXIgb2xkcyBpbiB0aGUgcGlsb3Qgc3R1ZHkNCg0KYGBge3J9DQptZWFuQkYgPSBzdW1tYXJ5KGNoaWxkLmRpc2NyaW0uNy5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXQ0Kc2VCRiA9IHN1bW1hcnkoY2hpbGQuZGlzY3JpbS43Lm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJTdGQuIEVycm9yIl0NCmgxbWVhbiA9IHN1bW1hcnkoYWR1bHQuZGlzY3JpbS5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXQ0KDQpCZihzZUJGLCBtZWFuQkYsIHVuaWZvcm0gPSAwLCBtZWFub2Z0aGVvcnkgPSAwLCBzZHRoZW9yeSA9IGgxbWVhbiwgdGFpbCA9IDEpDQoNCnJtKG1lYW5CRikNCnJtKHNlQkYpDQpybShoMW1lYW4pDQpgYGANCg0KSGVyZSB3ZSBoYXZlIGV2aWRlbmNlIGZvciB0aGUgbnVsbCBoeXBvdGhlc2lzIChIMCkgZnJvbSBqdXN0IDE1IHBhcnRpY2lwYW50cy4gTm90ZSBob3dldmVyLCB0aGF0IHdlIGFyZSB1c2luZyBhIHJlbGF0aXZlbHkgaGlnaCBlc3RpbWF0ZSBmb3IgSDEsIHdoaWNoIG1heSBtYWtlIGl0IGVhc2llciB0byBmaW5kIGV2aWRlbmNlIGZvciBIMC4NCg0KIyMgUHJlZGljdGlvbiAyOiBUaGVyZSB3aWxsIGJlIG1vcmUgaW1wcm92ZW1lbnQgaW4gb25lIGNvbmRpdGlvbiB0aGFuIHRoZSBvdGhlcg0KDQojIyMgQmFzZWQgb24NCg0KV2UgZG9uJ3QgaGF2ZSBhbnkgc3BlY2lmaWMgZXZpZGVuY2UgdG8gYmFzZSB0aGlzIG9uLiBUaGUgY2xvc2VzdCBjb250cmFzdCB3YXMgaW4gdGhlIGFkdWx0IHBpbG90IGV4cGVyaW1lbnQgKGNvbXBhcmluZyBhIGNvbmRpdGlvbiB3aXRoIHBpY3R1cmUtb25seSB0cmFpbmluZyB2ZXJzdXMgZGlhY3JpdGljLW9ubHkgdHJhaW5pbmcpIHdoZXJlIHRoZXkgc2hvd2VkIG51bWVyaWNhbGx5IG1vcmUgaW1wcm92ZW1lbnQgaW4gdGhlIGltcGxpY2l0IGNvbmRpdGlvbiwgYnV0IHRoZSBkaWZmZXJlbmNlIHdhcyBOUy4NCg0KbWVhbnMgOiBgciByb3VuZCggd2l0aChhZHVsdC5kaXNjcmltLCB0YXBwbHkoY29ycmVjdCwgbGlzdChwcmVfcG9zdCwgY29uZGl0aW9uKSwgbWVhbiwgbmEucm09VCkpICwyKWANCmxvZyBvZGRzIChiZXRhIGZyb20gbG1lKTogYHIgc3VtbWFyeShhZHVsdC5kaXNjcmltLm1vZCkkY29lZmZpY2llbnRzWyJjb25kaXRpb24uY3Q6cHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXWANCm9kZCAoZXhwKGJldGEpKWByIGV4cChzdW1tYXJ5KGFkdWx0LmRpc2NyaW0ubW9kKSRjb2VmZmljaWVudHNbImNvbmRpdGlvbi5jdDpwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdKWANCg0KRm9yIHRoZSBpbml0aWFsIGRhdGEgc2V0IGNvbGxlY3RlZCB3ZSB3aWxsIGRvIHRoaXMgYm90aCB0byBjb21wYXJlIHByZSB0ZXN0IHRvIHBvc3QtdGVzdCAxIChzZXNzaW9uMikgYW5kIHByZS10ZXN0IHRvIHBvc3QtdGVzdDIgKHNlc3Npb240KS4NCg0KIyMjIFBsYW5uZWQgQW5hbHlzZXM6IEZyZXF1ZW50aXN0DQoNCldlIHdpbGwgdXNlIGFuIGxtZSBtb2RlbCBzaW1pbGFyIHRvIHRoYXQgdXNlZCBvbiB0aGUgcGlsb3QgZGF0YSBhYm92ZSBidXQgd2l0aCBkYXRhIGZyb20gYm90aCBjb25kaXRpb25zOyB3ZSB3aWxsIGxvb2sgZm9yIGFuIGludGVyYWN0aW9uIGJldHdlZW4gcHJlLXBvc3QgYW5kIGNvbmRpdGlvbi4NCg0KIyMjIFBsYW5uZWQgQW5hbmx5c2VzOiBCRg0KDQpTdW1tYXJ5IG9mIGRhdGEgZm9yIGVhY2ggY29uZGl0aW9uOiBtZWFuIGFuZCBTRSBmb3IgcHJlLXBvc3QqY29uZGl0aW9uIGZyb20gbG1lDQp2YWx1ZSB0byBpbmZvcm0gSDE6IHdlIHdpbGwgdXNlIHRoZSBlc3RpbWF0ZSBmb3Igc2Vzc2lvbiBmcm9tIHRoZSBjdXJyZW50IG1vZGVsICAoaS5lLiBzdW1tYXJ5KG5ldy5kYXRhKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl1gDQoNCk5vdGU6IHdlIHdpbGwgb25seSBkbyB0aGlzIGlmIHdlIGhhdmUgZXZpZGVuY2Ugb2YgYW4gZWZmZWN0IG9mIHByZS1wb3N0IGluIGF0IGxlYXN0IG9uZSBvZiB0aGUgY29uZGl0aW9ucy4gSWYgdGhleSBkb24ndCBsZWFybiBpbiBlaXRoZXIgY29uZGl0aW9uIHRoZW4gdGhpcyB0ZXN0IGlzIGluYXBwcm9wcmlhdGUuDQoNCkFsc28gbm90ZSB0aGF0IHRoaXMgd2lsbCBiZSBhIHJlbGF0aXZlbHkgY29uc2VydmF0aXZlIGVzdGltYXRlIGZvciBhIGxhcmdlIGRpZmZlcmVuY2UgaW4gaG93IG11Y2ggdGhlIGNvbmRpdGlvbnMgbGVhZCB0byBhIGNoYW5nZSBwcmUgdG8gcG9zdC4gDQoNCihXZSBhcmUgc2Vla2luZyBzdGF0aXN0aWNhbCBhZHZpY2UgaGVyZSkNCg0KIyMjIFJlcXVpcmVkIFNhbXBsZSBBbmFseXNlcw0KDQojIyMjIEZyZXF1ZW50aXN0IFBvd2VyDQoNCldlIGhhdmUgbm8gZGF0YSB0byBsb29rIGF0IHRoaXMgKHNpbmNlIHRoZXJlIHdhcyBubyBzaWcuIGRpZmZlcmVuY2UgaW4gdGhlIHBpbG90IGRhdGEgY29sbGVjdGVkKQ0KDQojIyMjIFJlcXVpcmVkIHNhbXBsZSBmb3IgQkYgYW5hbHlzZXMgZnJvbSBwaWxvdCBkYXRhDQoNCkhlcmUgd2UgYXJlIGxvb2tpbmcgYXQgdGhpcyB3aXRoIGFkdWx0IHBpbG90IGRhdGEuDQoNCmBgYHtyfQ0KbWVhbkJGID0gc3VtbWFyeShhZHVsdC5kaXNjcmltLm1vZCkkY29lZmZpY2llbnRzWyJjb25kaXRpb24uY3Q6cHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXQ0Kc2VCRiA9IHN1bW1hcnkoYWR1bHQuZGlzY3JpbS5tb2QpJGNvZWZmaWNpZW50c1siY29uZGl0aW9uLmN0OnByZV9wb3N0LmN0IiAsIlN0ZC4gRXJyb3IiXQ0KaDFtZWFuID0gc3VtbWFyeShhZHVsdC5kaXNjcmltLm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdDQoNCkJmKHNlQkYsIG1lYW5CRiwgdW5pZm9ybSA9IDAsIG1lYW5vZnRoZW9yeSA9IDAsIHNkdGhlb3J5ICA9aDFtZWFuLCB0YWlsID0gMikNCnBsb3QoQmZfcG93ZXJjYWxjKHNlQkYsIG1lYW5CRiwgdW5pZm9ybSA9IDAsIG1lYW5vZnRoZW9yeSA9IDAsIHNkdGhlb3J5ID0gaDFtZWFuLCBOID0gMTUsIG1pbiA9IDkwMCwgbWF4ID0gNTAsIHRhaWwgPSAyKSkNCmFibGluZShoID0gMykNCkJmX3Bvd2VyY2FsYyhzZUJGLCBtZWFuQkYsIHVuaWZvcm0gPSAwLCBtZWFub2Z0aGVvcnkgPSAwLCBzZHRoZW9yeSA9IGgxbWVhbiwgTiA9IDE1LCBtaW4gPSA4MTEsIG1heCA9IDgxNSwgdGFpbCA9IDIpDQoNCnJtKG1lYW5CRikNCnJtKHNlQkYpDQpybShoMW1lYW4pDQpgYGANCg0KVGhpcyBhbmFseXNpcyBzdWdnZXN0cyB0aGF0IGV2ZW4gZm9yIGFkdWx0cywgd2Ugd291bGQgbmVlZCBhIHNhbXBsZSBvZiBvdmVyIDgwMCBwYXJ0aWNpcGFudHMgcGVyIGNvbmRpdGlvbiB0byBzZWUgdGhpcyBpbnRlcmFjdGlvbi4gVGhpcyBpcyBpbXBsYXVzaWJsZSAodGhvdWdoIG1heSBiZSBwYXJ0bHkgYmVjYXVzZSB3ZSBhcmUgYmFzaW5nIHRoZSBhbmFseXNlcyBvbiBhbiBvdmVybHkgY29uc2VydmF0aXZlIHZhbHVlIGZvciBIMSkuDQoNCkhvd2V2ZXIgdGhpcyBhbmFseXNpcyBzdWdnZXN0cyBpdCB3aWxsIGJlIGRpZmZpY3VsdCB0byBnYWluIHBvd2VyIGZvciB0aGlzIGludGVyYWN0aW9uLiBPbiB0aGUgb3RoZXIgaGFuZCwgcHJldmlvdXMgYW5hbHlzZXMgbWF5IG1ha2UgaXQgY2xlYXIgdGhhdCB0aGVyZSBpcyBubyBpbXByb3ZlbWVudCBvbiB0aGlzIHRlc3QgaW4gRUlUSEVSIGNvbmRpdGlvbiAoc2VlIFByZWRpY3Rpb24gMSBhYm92ZSkuIEluIHRoYXQgd2F5IGl0IG1heSBiZSB2ZXJ5IGRpZmZpY3VsdCB0byBwb3dlciB0aGlzLiBPbmUgcG9zc2liaWxpdHkgaXMgdGhhdCB3ZSB3b24ndCBoYXZlIHBvd2VyIGZvciB0aGUgaW50ZXJhY3Rpb24gYnV0IHdpbGwgaGF2ZSBwb3dlciB0byBzYXkgd2UgaGF2ZSBldmlkZW5jZSBmb3IgbGVhcm5pbmcgaW4gb25lIGNvbmRpdGlvbiwgYnV0IGZvciB0aGUgb3RoZXIgdGhlcmUgaXMgbW9yZSBldmlkZW5jZSBmb3IgdGhlIG51bGwgdGhhbiBmb3IgSDEgYmFzZWQgb24gdGhhdCBjb25kaXRpb24uIA0KDQojIFdvcmQgcmVwZXRpdGlvbg0KDQpUaGlzIHRlc3QgaXMgY29tcGxldGVkIGluIHRoZSBwcmUgYW5kIHBvc3QgdGVzdHMuIENoaWxkcmVuIGhlYXIgYSB3b3JkIGFuZCBjb3B5IGl0IGJhY2suIFdlIHdpbGwgbG9vayB0byBzZWUgaWYgdGhleSByZXBlYXQgYmFjayB0aGUgdG9uZSBjb3JyZWN0bHkgKHRoZSBhdWRpbyByZWNvcmRpbmdzIHdpbGwgYmUgY29kZWQgYnkgbmF0aXZlIHNwZWFrZXJzIHdobyBhcmUgYmxpbmQgdG8gYm90aCBjb25kaXRpb24gYW5kIHdoYXQgdGhlIHRhcmdldCB3b3JkIGlzOyB0aGUgdG9uZSBvZiB0aGUgdHJhbnNjcmliZWQgd29yZCB3aWxsIGNvbXBhcmVkIHRvIHRvbmUgb2YgdGFyZ2V0IGFuZCB0aHVzIGNvZGVkIGFzIGNvcnJlY3QvaW5jb3JyZWN0KS4gVGhlcmUgYXJlIGVxdWFsIG51bWJlciBvZiB3b3JkcyBmb3IgZWFjaCBvZiB0aGUgZm91ciB0b25lcy4NCg0KRm9yIHRoZSBpbml0aWFsIGRhdGEgc2V0IGNvbGxlY3RlZCwgd2lsbCBjb25zaWRlciBib3RoIHByZS10ZXN0IC0+IHBvc3R0ZXN0MSAoc2Vzc2lvbjIpIGFuZCBwcmUtdGVzdCAtPiBwb3N0LXRlc3QyIChzZXNpb240KS4gSWYgZXF1aXZhbGVudCByZXN1bHRzIGFyZSBvYnRhaW5lZCwgc3Vic2VxdWVudCB0ZXN0aW5nIHdpbGwgZHJvcCBmaW5hbCB0d28gc2Vzc2lvbnMgKHNlZSBub3RlIGFib3ZlKS4NCg0KIyMgTG9hZCB1cCBhbmQgcnVuIGxtZXMgb24gcGlsb3QgZGF0YQ0KDQpUaGUgY2hpbGQgZGF0YSBiZWxvdyBjb21lIGZyb20gdGhlIHNhbWUgdHdvIHNlc3Npb24gc3R1ZHkgYXMgdGhlIHBpbG90IHRyYWluaW5nIGRhdGEvZGlzY3JpbWluYXRpb24gZGF0YSAoaS5lLiB3aGVyZSBjaGlsZHJlbiB3ZXJlIHRyYWluZWQgb24gc3RpbXVsaSBzaW1pbGFyIHRvIHRoZSAicGljdHVyZS1vbmx5IiBjb25kaXRpb24gaW4gdGhlIGN1cnJlbnQgc3R1ZHkpLg0KDQpUaGUgYWR1bHQgZGF0YSBiZWxvdyBkbyBub3QgY29tZSBmcm9tIHRoZSBzYW1lIHR3byBkYXkgcGlsb3Qgc3R1ZHkgYXMgdGhlIG90aGVyIGFkdWx0IGRhdGEgdXNlZCBhYm92ZSAodGhhdCBwYXJ0aWN1bGFyIHN0dWRlbnQgcHJvamVjdCBkaWQgbm90IGluY2x1ZGUgdGhpcyB0ZXN0KSwgYnV0IGluc3RlYWQgZnJvbSBhIG11Y2ggbG9uZ2VyIDkgc2Vzc2lvbiBleHBlcmltZW50IGNvbmR1Y3RlZCBieSBjdXJyZW50IFBoRCBzdHVkZW50LiBUaGVyZSB3YXMgbm8gY29udHJhc3Qgb2YgY29uZGl0aW9uIG9mIHRoZSB0eXBlIHJlbGV2YW50IHRvIHRoZSBjdXJyZW50IHN0dWR5IGluIHRoYXQgZGF0YS4gDQoNCk5vdGUgdGhhdCBmb3IgYm90aCBhZHVsdHMgYW5kIGNoaWxkcmVuIGluIHRoZSBwaWxvdCBleHBlcmltZW50cyB1c2luZyB0aGlzIHRlc3Qgd2UgaW5jbHVkZWQgYm90aCB0cmFpbmVkIGFuZCB1bnRyYWluZWQgaXRlbXMuIEZvciB0aGlzIGV4cGVyaW1lbnQgd2UgdXNlIG9ubHkgdW50cmFpbmVkIGl0ZW1zIGluIHRoaXMgdGVzdCBzbyB3ZSByZW1vdmUgdGhlIHRyYWluZWQgaXRlbXMgZnJvbSB0aGUgYW5hbHlzZXMgYmVsb3cuDQoNCmBgYHtyfQ0KY2hpbGQud3IgPSByZWFkLmNzdigia2lkc3dvcmRyZXBfY2xlYW4uY3N2IikNCmNoaWxkLndyJHByZV9wb3N0ID0gcmVsZXZlbChjaGlsZC53ciRwcmVfcG9zdCwgcmVmID0gInByZSIpDQpjaGlsZC53ciA9IGRyb3BsZXZlbHMoc3Vic2V0KGNoaWxkLndyLCB3b3JkdHlwZSA9PSAibmV3IikpDQoNCmFkdWx0LndyID0gcmVhZC5jc3YoImFkdWx0c3dvcmRyZXBfY2xlYW4uY3N2IikNCmFkdWx0LndyJHByZV9wb3N0ID0gcmVsZXZlbChhZHVsdC53ciRwcmVfcG9zdCwgcmVmID0gInByZSIpDQphZHVsdC53ciA9IGRyb3BsZXZlbHMoc3Vic2V0KGFkdWx0LndyLCB3b3JkdHlwZSA9PSAiVW50cmFpbmVkIikpDQpgYGANCg0KDQpgYGB7cn0NCmNoaWxkLndyLjcgPSBkcm9wbGV2ZWxzKHN1YnNldChjaGlsZC53ciwgQWdlPT0ieW91bmciKSkNCmNoaWxkLndyLjcgPC0gbGl6Q2VudGVyKGNoaWxkLndyLjcsIGxpc3QoInByZV9wb3N0IiwgImNvcnJlY3R0b25lIikpDQoNCmNoaWxkLndyLjcubW9kID0gZ2xtZXIgKHJlc3VsdHRvbmUgfg0KICAgICAgICArIHByZV9wb3N0LmN0IA0KICAgICAgICArIGNvcnJlY3R0b25lLmN0DQogICAgICAgICsgKHByZV9wb3N0LmN0fHBhcnRpY2lwYW50bmFtZSksDQogICAgICAgICBkYXRhID0gY2hpbGQud3IuNywgZmFtaWx5ID0gYmlub21pYWwsIGNvbnRyb2w9Z2xtZXJDb250cm9sKG9wdGltaXplciA9ICJib2J5cWEiKSkNCg0Kcm91bmQoc3VtbWFyeShjaGlsZC53ci43Lm1vZCkkY29lZmZpY2llbnRzLDMpDQpgYGANCg0KYGBge3J9DQphZHVsdC53ciA8LSBsaXpDZW50ZXIoYWR1bHQud3IsIGxpc3QoICJwcmVfcG9zdCIsImNvcnJlY3R0b25lIikpDQoNCmFkdWx0LndyLm1vZCA9IGdsbWVyIChyZXN1bHR0b25lIH4NCiAgICAgICAgKyBwcmVfcG9zdC5jdCANCiAgICAgICAgKyBjb3JyZWN0dG9uZS5jdA0KICAgICAgICArIChwcmVfcG9zdC5jdHxwYXJ0aWNpcGFudG5hbWUpLA0KICAgICAgICAgZGF0YSA9IGFkdWx0LndyLCBmYW1pbHkgPSBiaW5vbWlhbCwgY29udHJvbD1nbG1lckNvbnRyb2wob3B0aW1pemVyID0gImJvYnlxYSIpKQ0KDQpyb3VuZChzdW1tYXJ5KGFkdWx0LndyLm1vZCkkY29lZmZpY2llbnRzLDMpDQpgYGANCg0KIyMgUHJlZGljdGlvbiAxOiBUaGVyZSB3aWxsIGJlIGFuIGltcHJvdmVtZW50IGZyb20gcHJlLXBvc3QgdGVzdCBpbiBlYWNoIGVhY2ggY29uZGl0aW9uDQoNCiMjIyBCYXNlZCBvbiANCg0KQm90aCBjaGlsZHJlbiBhbmQgYWR1bHRzIHNob3dlZCB0aGlzIGluIHRoZSByZWxldmFudCBwaWxvdCBzdHVkaWVzDQoNCjd5ZWFyIG1lYW4gOmByIHJvdW5kKCB3aXRoKGNoaWxkLndyLjcsIHRhcHBseShyZXN1bHR0b25lLCBsaXN0KHByZV9wb3N0KSwgbWVhbiwgbmEucm09VCkpICwyKWA7DQo3eWVhciBsb2cgb2RkcyAoYmV0YSBmcm9tIGxtZSk6IGByIHN1bW1hcnkoY2hpbGQud3IuNy5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXWA7DQo3eWVhciBvZGQgKGV4cChiZXRhKSlgciBleHAoc3VtbWFyeShjaGlsZC53ci43Lm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdKWANCg0KYWR1bHQgbWVhbiA6IGByIHJvdW5kKCB3aXRoKGFkdWx0LndyLCB0YXBwbHkocmVzdWx0dG9uZSwgbGlzdChwcmVfcG9zdCksIG1lYW4sIG5hLnJtPVQpKSAsMilgOw0KYWR1bHQgbG9nIG9kZHMgKGJldGEgZnJvbSBsbWUpOiBgciBzdW1tYXJ5KGFkdWx0LndyLm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdYDsNCmFkdWx0IG9kZCAoZXhwKGJldGEpKWByIGV4cChzdW1tYXJ5KGFkdWx0LndyLm1vZCkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdKWANCg0KIyMjIFBsYW5uZWQgQW5hbHlzZXM6IEZyZXF1ZW50aXN0IA0KDQpXZSB3aWxsIHVzZSBhbiBsbWUgbW9kZWwgc2ltaWxhciB0byB0aGF0IHVzZWQgb24gdGhlIHBpbG90IGRhdGEgYWJvdmUgYnV0IHdpdGggZGF0YSBmcm9tIGJvdGggY29uZGl0aW9uczsgV2Ugd2lsbCBmaXQgc2VwYXJhdGUgc2xvcGVzIGZvciBwcmUtcG9zdCBpbiBlYWNoIGNvbmRpdGlvbiANCg0KRm9yIHRoZSBpbml0aWFsIGRhdGEgc2V0IGNvbGxlY3RlZCB3ZSB3aWxsIGRvIHRoaXMgYm90aCB0byBjb21wYXJlIHByZSB0ZXN0IHRvIHBvc3QtdGVzdCAxIGFuZCBwcmUtdGVzdCB0byBwb3N0LXRlc3QyIChzZWUgbm90ZXMgYWJvdmUpLg0KDQojIyMgUGxhbm5lZCBBbmFseXNlczogQkYgDQoNClN1bW1hcnkgb2YgZGF0YSBmb3IgZWFjaCBjb25kaXRpb246IG1lYW4gYW5kIFNFIGZvciBwcmUtcG9zdCBmcm9tIGxtZQ0KdmFsdWUgdG8gaW5mb3JtIEgxOiB3ZSB3aWxsIHVzZSBhbiBlc3RpbWF0ZSBmcm9tIHRoZSBhYm92ZSBwaWxvdCBkYXRhIGZvciBjaGlsZHJlbiBpLmUuIGByIHN1bW1hcnkoY2hpbGQud3IuNy5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXWANCg0KTk9URTogSWYgKGUuZy4pIHdlIGZpbmQgYW4gZWZmZWN0IGZvciBjb25kaXRpb24xLCB3ZSBjYW4gYWxzbyB1c2UgdGhlIGVzdGltYXRlIGZvciBzZXNzaW9uIGZvciB0aGF0IHRvIGluZm9ybSBIMSB3aGVuIGxvb2tpbmcgYXQgZGF0YSBmcm9tIGNvbmRpdGlvbjI7IGFuZCB2aWNlIHZlcnNhLiBUaGlzIGlzIGEgYmV0dGVyIGVzdGltYXRlIHNpbmNlIHRoZSBjb25kaXRpb25zIGFyZSBtb3JlIGNsb3NlbHkgbWF0Y2hlZCB0byBlYWNoIG90aGVyIHRoYW4gZWl0aGVyIGlzIHRvIHRoZSBwaWxvdCBkYXRhLw0KDQojIyMgUmVxdWlyZWQgU2FtcGxlIEFuYWx5c2VzDQoNCiMjIyMgRnJlcXVlbnRpc3QgUG93ZXINCg0KTm90ZTogdGhpcyBhbmFseXNpcyBpcyBpbmNsdWRlZCBmb3IgY29tcGxldGVuZXNzIGJ1dCBpcyBub3QgcmVhbGx5IHJlbGV2YW50IHNpbmNlIGl0IGlzIGJhc2VkIG9uIGFkdWx0IGRhdGEuIElmIGNoaWxkcmVuIGRvIHNob3cgYW4gZWZmZWN0LCBpdCBpcyBsaWtlbHkgdG8gYmUgc21hbGxlciBhbmQgdGhleSB3aWxsIGhhdmUgbGFyZ2VyIFNFIA0KDQpgYGB7cn0NCmRhdGFTID0gd2l0aChkcm9wbGV2ZWxzKGNoaWxkLndyLjcpLCB0YXBwbHkocmVzdWx0dG9uZSwgbGlzdChwYXJ0aWNpcGFudG5hbWUscHJlX3Bvc3QpLCBtZWFuLCBuYS5ybT1UKSkNCmQgPSBjb2hlbnNEKHggPSBkYXRhU1ssMV0sIHkgPSBkYXRhU1ssMl0sIG1ldGhvZCA9ICJwYWlyZWQiKQ0KDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuOSwgdHlwZSA9IGMoInBhaXJlZCIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuOCwgdHlwZSA9IGMoInBhaXJlZCIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQpwd3IudC50ZXN0KG4gPSBOVUxMLCBkID0gZCwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSAuNywgdHlwZSA9IGMoInBhaXJlZCIpLCBhbHRlcm5hdGl2ZSA9IGMoICJncmVhdGVyIikpDQoNCnJtKGRhdGFTKQ0Kcm0oZCkNCmBgYA0KDQpTYW1wbGUgZXN0aW1hdGlvbiBzdWdnZXN0cyB0aGF0IE4gPSAzMyBwZXIgY29uZGl0aW9uIGZvciA5MCUgcG93ZXIuDQoNCiMjIyMgUmVxdWlyZWQgc2FtcGxlIGZvciBCRiBhbmFseXNlcyBmcm9tIHBpbG90IGRhdGENCg0KTm90ZSB0aGF0IGhlcmUgd2UgdXNlIHRoZSBtZWFuIGZyb20gdGhlIGFkdWx0IHBpbG90IGRhdGEgdG8gaW5mb3JtIEgxICh3aGVyZWFzIGZvciBhY3R1YWwgYW5hbHlzZXMgd2Ugd2lsbCBiZSB1c2luZyBhIHZhbHVlIGZyb20gcGlsb3QgZGF0YSB3aXRoIDcgeWVhciBvbGRzIHRvIGluZm9ybSBIMSkNCg0KYGBge3J9DQptZWFuQkYgPSBzdW1tYXJ5KGNoaWxkLndyLjcubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIkVzdGltYXRlIl0NCnNlQkYgPSBzdW1tYXJ5KGNoaWxkLndyLjcubW9kKSRjb2VmZmljaWVudHNbInByZV9wb3N0LmN0IiAsIlN0ZC4gRXJyb3IiXQ0KaDFtZWFuID0gc3VtbWFyeShhZHVsdC53ci5tb2QpJGNvZWZmaWNpZW50c1sicHJlX3Bvc3QuY3QiICwiRXN0aW1hdGUiXQ0KDQpCZihzZUJGLCBtZWFuQkYsIHVuaWZvcm0gPSAwLCBtZWFub2Z0aGVvcnkgPSAwLCBzZHRoZW9yeSA9IGgxbWVhbiwgdGFpbCA9IDEpDQoNCnJtKG1lYW5CRikNCnJtKHNlQkYpDQpgYGANCg0KV2UgaGF2ZSBzdWZmaWNpZW50IGV2aWRlbmNlIGZyb20gdGhlIHNhbXBsZSBvZiBOID0gMTUgY2hpbGRyZW4gZm9yIEgxLiANCg0KIyMgUHJlZGljdGlvbiAyOiBUaGVyZSB3aWxsIGJlIG1vcmUgaW1wcm92ZW1lbnQgaW4gb25lIGNvbmRpdGlvbiBieSBwcmUtcG9zdA0KDQojIyBCYXNlZCBvbiANCg0KV2UgaGF2ZSBubyBkYXRhIHRvIGJhc2UgdGhpcyBvbiBhcyB3ZSBoYXZlbid0IHByZXZpb3VzbHkgdXNlZCB0aGlzIHRlc3QgaW4gYW4gZXhwZXJpbWVudCBjb250cmFzdGluZyB0aGVzZSAob3Igc2ltaWxhcikgY29uZGl0aW9ucy4gSWYgdGhlIHByZXNlbmNlIG9mIHRoZSBkaWFjcml0aWNzIGJvb3N0cyBsZWFybmluZywgY2hpbGRyZW4gbWF5IGltcHJvdmUgbW9yZSBpbiB0aGUgZGlhY3JpdGljcytwaWN0dXJlIGNvbmRpdGlvbi4NCg0KIyMjIFBsYW5uZWQgQW5hbHlzZXM6IEZyZXF1ZW50aXN0IA0KDQpXZSB3aWxsIHVzIGFuIGxtZSBtb2RlbCBzaW1pbGFyIHRvIHRoYXQgdXNlZCBvbiB0aGUgcGlsb3QgZGF0YSBhYm92ZSBidXQgd2l0aCBkYXRhIGZyb20gYm90aCBjb25kaXRpb25zOyB3ZSB3aWxsIGxvb2sgZm9yIGFuIGludGVyYWN0aW9uIG9mIHByZS1wb3N0IGFuZCBjb25kaXRpb24NCg0KRm9yIHRoZSBpbml0aWFsIGRhdGEgc2V0IGNvbGxlY3RlZCB3ZSB3aWxsIGRvIHRoaXMgYm90aCB0byBjb21wYXJlIHByZSB0ZXN0IHRvIHBvc3QtdGVzdCAxIGFuZCBwcmUtdGVzdCB0byBwb3N0LXRlc3QyIChzZWUgbm90ZXMgYWJvdmUpLg0KDQojIyMgUGxhbm5lZCBBbmFubHlzZXM6IEJGDQoNClN1bW1hcnkgb2YgZGF0YSBmb3IgZWFjaCBjb25kaXRpb246IG1lYW4gYW5kIFNFIGZvciBwcmUtcG9zdCpjb25kaXRpb24gZnJvbSBsbWUNCnZhbHVlIHRvIGluZm9ybSBIMTogd2Ugd2lsbCB1c2UgYW4gZXN0aW1hdGUgZm9yIHNlc3Npb24gZnJvbSB0aGUgbW9kZWwgd2l0aCB0aGUgbmV3IGRhdGEgKGkuZS4gc3VtbWFyeShuZXcuZGF0YSkkY29lZmZpY2llbnRzWyJwcmVfcG9zdC5jdCIgLCJFc3RpbWF0ZSJdYA0KDQpXZSBvbmx5IGRvIHRoaXMgaWYgd2UgaGF2ZSBldmlkZW5jZSBvZiBhbiBlZmZlY3Qgb2YgcHJlLXBvc3QgaW4gYXQgbGVhc3Qgb25lIG9mIHRoZSBjb25kaXRpb25zLiBJZiB0aGV5IGRvbid0IGxlYXJuIGluIGVpdGhlciBjb25kaXRpb24gdGhlbiB0aGlzIHRlc3QgaXMgaW5hcHByb3ByaWF0ZS4NCg0KQWxzbyBub3RlIHRoYXQgdGhpcyB3aWxsIGJlIHJlbGF0aXZlbHkgY29uc2VydmF0aXZlIGVzdGltYXRlIGZvciBhIGxhcmdlIGRpZmZlcmVuY2UgaW4gaG93IG11Y2ggdGhlIGNvbmRpdGlvbnMgbGVhZCB0byBhIGNoYW5nZSBwcmUgdG8gcG9zdC4gDQoNCiMjIyBSZXF1aXJlZCBzYW1wbGUgYW5hbHlzZXMNCg0KV2UgaGF2ZSBubyByZWxldmFudCBkYXRhIHRvIGJhc2UgdGhpcyBvbiBmb3IgZWl0aGVyIGZyZXF1ZW50aXN0IG9yIEJGIGFuYWx5c2VzLiBPbmUgcG9zc2liaWxpdHkgaXMgdGhhdCB3ZSB3b24ndCBiZSBhYmxlIHRvIGdldCBhIHN1ZmZpY2llbnRseSBsYXJnZSBzYW1wbGUgdG8gaGF2ZSBwb3dlciBmb3IgdGhpcyBpbnRlcmFjdGlvbi4gQXMgZm9yIG90aGVyIHRlc3RzLCBoZXJlIHdlIG1heSBoYXZlIHRvIGRyYXcgd2hhdGV2ZXIgY29uY2x1c2lvbnMgYXJlIHBvc3NpYmxlIGJhc2VkIG9uIHdoaWNoIG9mIHRoZSBjb25kaXRpb25zIGluZGl2aWR1YWxseSBwcm92aWRlcyBldmlkZW5jZSBmb3IgSDEvSDAuDQo=