R notebook for analyses of median saccade latency in the sacc-tDCS dataset. Previous processing:

  • Raw data were parsed into events (saccades, fixations, etc.) by the EyeLink data were collected on.
  • Events were extracted and saccade measures were computed with a MATLAB script.

Load data

Eye data

The .csv file with the eye tracking data was created in MATLAB.

  • subject: subject ID
  • stimulation: Whether data are from the anodal or cathodal session
  • leg: Whether data are before (pre), during (tDCS), or after (post) tDCS
  • block: After each block participant had a brief break and tracker was recalibrated
  • trial: trial number within a block
  • type:
    • lateral - fixation in center of display, saccade made towards the periphery
    • center - fixation in periphery, saccade made back towards the center of the display
  • direction: left for saccades towards the left of current fixation position; right for saccades to the right
  • deviation.start : distance (in visual angle) from saccade start point to fixation
  • deviation.end.x: distance (in visual angle) from x-coordinate of saccade end point to x-coordinate of target location
  • deviation.end.y: same for y-coordinate
  • amplitude: distance (in visual angle) between saccade start and end point
  • latency: time (in ms) from target onset to start of saccade
  • drift.x: distance (in visual angle) between x-coordinate of average fixation position during the break to x-coordinate of fixation stimulus. This stimulus was displayed at each break in the task, so this data can be used as an estimate of offsets to do drift correction.
  • drift.y: same for y-coordinate

Subject metadata

kable(head(subjectData))
subject session.order gender age dominant.eye
S01 first.cathodal female 23 right
S02 first.anodal male 27 left
S03 first.cathodal male 34 right
S04 first.anodal male NA right
S05 first.cathodal male 24 right
S06 first.cathodal female 29 left
  • subject: subject ID
  • session.order: Whether subject had anodal stimulation in the first session (first.anodal) or cathodal stimulation in the first session (first.cathodal)
  • gender
  • age: in years
  • dominant.eye: result of eye dominance test

The main use is to see if the nuisance factor session.order covaries with the factors of interest in the design. This could indicate the presence of carryover effects between the stimulation, or a difference in subgroups within the sample (see http://www.jerrydallal.com/lhsp/crossovr.htm for an introduction to these kinds of analyses.).

Inspect median data

Remove outliers

tooFast <- 50
tooSlow <- 400
badFix <- 1.8
badSacc <- 8
subs2exclude <- c("S28","S16","S22","S21","S25")
  • S21 and S25 were tested < 48h apart
  • S16, S22 and S28 had fewer than 50 saccades per condition after trial rejection

Criteria for outlier saccades:

  • Discard fast saccades, with a latency of 50 ms or less
  • Discard slow saccades, saccades with a latency of 400 ms or more
  • Discard inaccurate fixations, with saccade starting point more than 1.8 degrees or more away from fixation
  • Discard faulty saccades, with x-coordinate of saccade end point 8 degree or more away from the target

In Kanai et al. (2012), this was:

  • Fast saccades: 50 ms
  • Slow saccades: 400 ms
  • Bad fixations: 1.8 degrees
  • Faulty saccades: opposite hemifield of target (here, that would be 8 degrees as targets were that eccentric)
# Remove outliers and subjects
groupData <- filter(groupData,
                    # outliers
                    latency >= tooFast,
                    latency <= tooSlow,
                    deviation.start <= badFix,
                    deviation.end.x <= badSacc,
                    # subjects
                    !(subject %in% subs2exclude),
                    # missing values
                    complete.cases(groupData)
)

Data per block

# Compute median in each condition
latencyMedian <- groupData %>%
  group_by(subject,stimulation,leg,block,type,direction) %>%
  summarise(latency = median(latency))

Full factorial plot

# Plot out all the data
fullPlot <- ggplot(latencyMedian, aes(interaction(block,leg), latency, color = stimulation, shape = stimulation)) +
  facet_grid(type ~ direction) +
  stat_summary(fun.y = mean, geom = "point", size = 3) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5))
fullPlot

For some reason cathodal is always a little faster than anodal. There is probably a few ms difference between them on average, also in the baseline block. This is clearly just random variation, but it could be a problem, since the effects we expect are not much bigger…

The above plot also shows a lot of variability, so it might be best to average over each 3 consecutive blocks so the data come in 15-minute intervals.

15-minute intervals (collapse 3 blocks)

# Compute median per leg
latencyMedianLeg <- groupData %>%
  group_by(subject,stimulation,direction,type) %>% 
  summarise(baseline = median(latency[leg == "pre"]), # take average of 3 blocks, make new column
            tDCS = median(latency[leg == "tDCS"]),
            post.1 = median(latency[leg == "post" & block <= 3]),
            post.2 = median(latency[leg == "post" & block >= 4])) %>%
 gather(leg,latency,baseline,tDCS,post.1,post.2) %>% # gather new columns to use as factor
 mutate(leg = factor(leg, levels = c("baseline", "tDCS", "post.1", "post.2"))) # reorder factor levels

Line plot per leg, individual subjects

Now make the same plot, but for the data collapsed over 3 blocks. Also draw the plot for each individual subject, so we can see which subjects drive the baseline difference, and in which direction the stimulation effect goes for each subject (if there is any).

kanaiSubsPlot <- ggplot(latencyMedianLeg, aes(leg, latency, color = stimulation, shape = type)) +         
  facet_wrap(~subject, ncol = 5) +
  stat_summary(fun.y = mean, geom = "point", size = 2) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5))
kanaiSubsPlot

There are a couple of subjects that show large differences in the baseline already, especially S01. The stimulation effects seem to not be very apparent, but they could also drown out at this scale.

Compute magnitude of baseline difference

Let’s look at the size of the baseline difference per subject.

baselineDiff <- latencyMedianLeg %>% 
  filter(leg == "baseline") %>% # keep only baseline data
  spread(stimulation, latency) %>% # make separate columns for anodal and cathodal
  mutate(latency.diff = anodal - cathodal) %>% # subtract the difference
  group_by(subject) %>% 
  summarise(latency.diff = mean(latency.diff))# keep the average difference per subject
kable(baselineDiff, caption = 'Difference between baseline saccade latencies in anodal and cathodal session')
subject latency.diff
S01 39.125
S02 18.625
S03 2.375
S04 -6.125
S05 -17.500
S06 -3.875
S07 5.625
S08 11.125
S09 23.875
S10 14.750
S11 1.000
S12 8.375
S13 4.000
S14 -10.375
S15 1.875
S17 -5.500
S18 -2.875
S19 1.000
S20 4.750
S24 3.625
S26 0.000
S27 0.500
S29 -13.625
S30 7.125
S32 10.875
S33 -1.625

There are a few subjects with substantial latency differences between sessions, so it’s probably a good idea to subtract the baseline for the statistical analyses. The mean difference is 3.7 ms. So on average, the cathodal session is a little faster, so the counterbalancing is not perfect, but the difference is not very high.

Median reaction time plots and analyses

Here we simply extract median RTs for each condition and use a repeated measures ANOVA for statistical analysis, following Kanai et al. (2012).

Line plot per leg over all subjects

Let’s look at the group average plot for the first time.

kanaiPlot <- ggplot(latencyMedianLeg, aes(leg, latency, color = stimulation, shape = stimulation)) +         
  facet_grid(type ~ direction) +
  stat_summary(fun.y = mean, geom = "point", size = 3) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
  stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3)
kanaiPlot

All differences between anodal & cathodal seem to be < 5 ms. Any differences that are there also 1) do not seem to differ much between the time blocks, or 2) be in the opposite direction for anodal and cathodal, with the possible exception of the first post-block in the center-right condition.

Individual subjects

Anodal session

Let’s look at the same plot for individual subjects, to see whether there are any consistent patterns or huge outliers there

kanaiPlotSubsAnodal <- ggplot(latencyMedianLeg[latencyMedianLeg$stimulation == "anodal", ], aes(leg, latency)) +
  facet_grid(type ~ direction) +
  geom_line(aes(group=subject,color=subject)) +
  stat_summary(fun.y = mean, aes(group = stimulation), geom = "line") +
  stat_summary(fun.y = mean, geom = "point") +
  ggtitle("Anodal session")
kanaiPlotSubsAnodal

There do appear to be some “outliers”, but they are fairly well balanced (below or above the average), and >80% or so of subjects seem to cluster together. I don’t see much evidence for systematic individual differences (e.g. slow subjects get faster; fast subjects get slower.)

Cathodal session

kanaiPlotSubsCathodal <- ggplot(latencyMedianLeg[latencyMedianLeg$stimulation == "cathodal", ], aes(leg, latency)) +
  facet_grid(type ~ direction) +
  geom_line(aes(group=subject,color=subject)) +
  stat_summary(fun.y = mean, aes(group = stimulation), geom = "line") +
  stat_summary(fun.y = mean, geom = "point") +
  ggtitle("Cathodal session")
kanaiPlotSubsCathodal

There seem to be less clear individual outliers, but the spread also seems a bit bigger (e.g. right-lateral)

Subtract baseline

Baseline differences (while small here) are not informative and could obscure real changes from baseline within subjects. Also it’s hard to see and compare the magnitude of the effects, also for instance because center saccades are much faster than lateral saccades. Therefore, subtract the baseline from each subsequent measurement.

latencyMedianBaseline <- latencyMedianLeg %>%
  group_by(subject,stimulation,direction,type) %>% # for each condition, subtract baseline scores and make new columns
  summarise(tDCS = latency[leg == "tDCS"] - latency[leg == "baseline"],
           post.1 = latency[leg == "post.1"] - latency[leg == "baseline"],
           post.2 = latency[leg == "post.2"] - latency[leg == "baseline"]) %>%
  gather(leg, latency, tDCS, post.1, post.2)  %>% # gather new columns to use as factor 
  mutate(leg = factor(leg, levels = c("tDCS", "post.1", "post.2"))) # reorder factor levels

Baseline data

Before we look at the change-from-baseline data, it would be good to check the baseline data itself.

Baseline reliability

Analyzing change-from-baseline only makes sense if the baseline data are not very noisy. Subtracting a noisy measure from the data will increase the noise in the data, and thereby reduce power. One way to assess this is to look at the correlation between the baseline blocks in both sessions. If there is a high correlation, the pro-saccade task produces comparable latencies each time it is performed, and thus the baseline data should on average not be very noisy.

Let’s compute the correlation between all baselines (i.e. for the factors DIRECTION and TYPE).

baselineCorr <- latencyMedianLeg %>%
  filter(leg == "baseline") %>% # keep only baseline data
  group_by(direction,type) %>% # for each of these 4 pairs
  spread(stimulation,latency) %>% # make 2 columns with baseline latencies of anodal and cathodal session
  nest() %>% # create a separate data frame of all remaining columns. These data frames are stored in a list-column named "data"
  mutate(stats = map(data, ~cor.test(formula = ~ anodal + cathodal, data =.))) %>% # run correlation test on baselines from each condition
  mutate(tidy_model = map(stats, tidy)) %>% # force the four test outputs to also be data frames in a list column ("tidy_model")
  unnest(tidy_model, .drop = TRUE)  # unpack the list-column with results, drop the list-column we used to organize the data

Now a scatter plot of the data, with the results of the test:

latencyMedianLeg %>%
  filter(leg == "baseline") %>%
  spread(stimulation,latency) %>%
  inner_join(., subjectData[ ,c("subject","session.order")], by = c("subject")) %>% # add column on session order from other data frame
  ggplot(aes(anodal,cathodal)) +
    facet_grid(type ~ direction) +
    geom_abline(intercept = 0, slope = 1, linetype = "dashed") +
    geom_smooth(method = "lm") +
    geom_point(aes(color=session.order)) +
    xlim(80,220) + ylim(80,220) +
    geom_text(data = baselineCorr, x = 100, y = 200, aes(label = paste("italic(r) == ", round(estimate,2))), parse = TRUE) +
    labs(title = "Baseline in anodal and cathodal sessions", subtitle = "scatterplot of baseline latencies")

The correlations are quite high, at least high enough for the baseline subtraction to help power rather than hurt (r’s > 0.5).

There are a few outliers though: some subjects deviate quite a bit from the idealized line (dashed).

When the data is split for session order, a clear pattern becomes apparent: latencies are generally faster in the 2nd session (for those who got cathodal first, are above the diagonal, meaning anodal < cathodal. The reverse pattern is visible for those who received anodal first). So in that sense there is a difference between two groups of subjects.

Baseline differences

If the prosaccade task is indeed reliable, there shouldn’t be any significant differences at the group-level between the baseline blocks of both sessions. If there are, this may be problematic, because all the change-scores are expressed relative to the baseline. A significant difference between two conditions in later blocks could then be driven by the differences that already occur in the baseline.

Let’s plot the baseline scores in each session for each subject:

latencyMedianLeg %>%
  filter(leg == "baseline") %>%
  ggplot(aes(stimulation, latency)) +
    facet_grid(type ~ direction) +
    stat_summary(fun.y = mean, geom = "line", aes(group = 1), size = 1.5) +
    geom_line(aes(group = subject, colour = subject), alpha = 0.5, position = position_dodge(width = 0.1)) +
    labs(title = "Baseline in anodal and cathodal sessions", subtitle = "linked stripchart of baseline latencies")

Most lines appear fairly flat. However, there is quite some variability around the mean, and some subjects show quite a steep difference. There appears to be some sort of regression to the mean also: extreme scores in either session show a steeper slope than those scores that are less extreme.

Let’s look at the pairwise differences in more detail:

latencyMedianLeg %>%
  filter(leg == "baseline") %>%
  inner_join(., subjectData[ ,c("subject","session.order")], by = c("subject")) %>% # add column on session order from other data frame
  group_by(subject,direction,type,session.order) %>%
  summarise(latency.diff = latency[stimulation == "anodal"] - latency[stimulation == "cathodal"]) %>%
  ggplot(aes(factor(0), latency.diff)) +
    facet_grid(type ~ direction) +
    geom_hline(yintercept = 0, linetype = "dashed") +
    stat_summary(fun.data = mean_cl_normal) +
    stat_summary(fun.y = mean, aes(label=round(..y.., digits=2), x = 1.3), geom = "label", alpha = 0.5) +
    geom_point(shape = 21, aes(colour = session.order), position = position_jitter(width=.1)) +
    labs(title = "Baseline in anodal and cathodal sessions", subtitle = "anodal - cathodal")

The sequence effect we observed earlier is very clear when we split the data by session order again, particularly in the lateral condition (i.e. latencies are always faster in the 2nd session).

Somewhat worryingly, the baseline differences are in the range of the tDCS effect size we expect, particularly in the center condition. That said, the differences do cluster around 0, there are really only a few subjects that fall far outside the boundary (one is really extreme).

The CIs appear to overlap with 0 though, so the differences shouldn’t be significant. Let’s test that:

latencyMedianLeg %>%
  filter(leg == "baseline") %>%
  group_by(direction,type) %>% # for each of these 4 pairs
  nest() %>% # create a separate data frame of all remaining columns. These data frames are stored in a list-column named "data"
  mutate(stats = map(data, ~t.test(formula = latency~stimulation, paired = TRUE, data =.))) %>% # run t-test on the data frames
  mutate(tidy_model = map(stats, tidy)) %>% # force the four test outputs to also be data frames in a list column ("tidy_model")
  unnest(tidy_model, .drop = TRUE) %>% # unpack the list-column with results, drop the list-column we used to organize the data
  kable(.)
direction type estimate statistic p.value parameter conf.low conf.high method alternative
left lateral 2.403846 1.024429 0.3154437 25 -2.4289077 7.236600 Paired t-test two.sided
left center 5.557692 1.910225 0.0676402 25 -0.4344207 11.549805 Paired t-test two.sided
right lateral 2.769231 1.060619 0.2990028 25 -2.6081375 8.146599 Paired t-test two.sided
right center 4.211538 1.657484 0.1099194 25 -1.0215893 9.444666 Paired t-test two.sided

Indeed, they are not, although the center conditions come close.

Line plots per leg from baseline

kanaiPlotBase <- ggplot(latencyMedianBaseline, aes(leg, latency, color = stimulation, shape = stimulation)) +         
  facet_grid(type ~ direction) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  stat_summary(fun.y = mean, geom = "point", size = 3) +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
  stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3) +
  coord_cartesian(ylim = c(-10,10))
kanaiPlotBase

Generally the differences between the stimulation conditions are small (< 4 ms). Except for the center-left condition, but this condition also had the largest baseline difference…

Individual subjects

Anodal session

kanaiPlotBaseSubsAnodal <- ggplot(latencyMedianBaseline[latencyMedianBaseline$stimulation == "anodal", ], aes(leg, latency)) +
  facet_grid(type ~ direction) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  geom_line(aes(group=subject,color=subject)) +
  stat_summary(fun.y = mean, aes(group = stimulation), geom = "line") +
  stat_summary(fun.y = mean, geom = "point") + 
  ggtitle("Anodal difference from baseline")
kanaiPlotBaseSubsAnodal

Cathodal session

kanaiPlotBaseSubsCathodal <- ggplot(latencyMedianBaseline[latencyMedianBaseline$stimulation == "cathodal", ], aes(leg, latency)) +
  facet_grid(type ~ direction) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  geom_line(aes(group=subject,color=subject)) +
  stat_summary(fun.y = mean, aes(group = stimulation), geom = "line") +
  stat_summary(fun.y = mean, geom = "point") + 
  ggtitle("Cathodal difference from baseline")
kanaiPlotBaseSubsCathodal

All of this is split pretty much 50-50, hence the average difference hovering around 0.

Contralateral saccades in the anodal session

Kanai et al. (2012) specifically found an effect of anodal tDCS on the latency changes in contralateral (here: left) lateral saccades. Let’s examine the raw numbers here:

latencyMedianBaseline %>%
  filter(type == "lateral", stimulation == "anodal", direction == "left") %>%
  group_by(leg) %>%
  summarise_at(vars(latency), funs(mean, sd)) %>%
  kable(.)
leg mean sd
tDCS -0.1730769 5.342176
post.1 -0.6153846 7.134855
post.2 0.9615385 9.651863

These changes are all < 1 ms and highly variable, so it seems there’s truly nothing there…

Statistics

# Make "subject" a factor, so we can model the repeated measures
latencyMedianBaseline <- latencyMedianBaseline %>%
  ungroup() %>% # remove grouping info, because we need to refactor
  inner_join(., subjectData[ ,c("subject","session.order")], by = c("subject")) %>% # add column from on session order from other data frame
  mutate(subject = factor(subject)) # refactor
latencyMedianLeg <- latencyMedianLeg %>%
  ungroup() %>%
  inner_join(., subjectData[ ,c("subject","session.order")], by = c("subject")) %>% # add column from on session order from other data frame
  mutate(subject = factor(subject))

Frequentist

Omnibus anova - saccade latency

Data: Outlier trials removed, collapsed into 15-minute intervals.

Dependent measure: saccadic latency

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (baseline, tDCS, post.1, post.2)
  • TYPE (lateral vs. center)
  • DIRECTION (left vs. right)
modelOmni <- ezANOVA(data = data.frame(latencyMedianLeg), # Repeated over subjects; type 3 sums of squares (cf. SPSS)
                        dv = .(latency), wid = .(subject), within = .(stimulation, leg, type, direction), type = 3)
kable(modelOmni$ANOVA)

Effect DFn DFd F p p<.05 ges
2 stimulation 1 25 1.8399816 0.1870776 0.0046328
3 leg 3 75 0.4395422 0.7253793 0.0004232
4 type 1 25 28.5410095 0.0000154 * 0.1295560
5 direction 1 25 0.5725232 0.4563300 0.0015576
6 stimulation:leg 3 75 1.4343849 0.2394786 0.0007140
7 stimulation:type 1 25 0.4929953 0.4890804 0.0003222
8 leg:type 3 75 4.7880531 0.0041682 * 0.0015673
9 stimulation:direction 1 25 0.6423151 0.4304257 0.0001620
10 leg:direction 3 75 1.6943654 0.1754445 0.0003035
11 type:direction 1 25 0.9424122 0.3409576 0.0008141
12 stimulation:leg:type 3 75 0.6925407 0.5594502 0.0000998
13 stimulation:leg:direction 3 75 2.2130816 0.0935459 0.0003838
14 stimulation:type:direction 1 25 0.3842442 0.5409498 0.0000109
15 leg:type:direction 3 75 6.8295412 0.0003940 * 0.0004416
16 stimulation:leg:type:direction 3 75 1.0933932 0.3572648 0.0000761

kable(modelOmni$`Mauchly's Test for Sphericity`)

Effect W p p<.05
3 leg 0.2579115 0.0000058 *
6 stimulation:leg 0.3762730 0.0003186 *
8 leg:type 0.1267739 0.0000000 *
10 leg:direction 0.3612309 0.0002082 *
12 stimulation:leg:type 0.5303766 0.0102889 *
13 stimulation:leg:direction 0.5729125 0.0216415 *
15 leg:type:direction 0.7933796 0.3595870
16 stimulation:leg:type:direction 0.8238579 0.4676623

kable(modelOmni$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
3 leg 0.5904749 0.6231869 0.6322248 0.6364737
6 stimulation:leg 0.5986297 0.2486500 0.6420287 0.2482301
8 leg:type 0.4789969 0.0234582 * 0.5002439 0.0218426 *
10 leg:direction 0.6068634 0.1971371 0.6519485 0.1948609
12 stimulation:leg:type 0.6922238 0.5100514 0.7560487 0.5218275
13 stimulation:leg:direction 0.7236356 0.1150365 0.7949444 0.1090952
15 leg:type:direction 0.8657955 0.0008106 * 0.9750655 0.0004504 *
16 stimulation:leg:type:direction 0.9008895 0.3541166 1.0205912 0.3572648

Main effect: type

latencyMedianLeg %>%
  group_by(subject,type) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(type, latency)) +
  stat_summary(fun.data = mean_cl_normal, size = 1) +
  geom_jitter(width = 0.25)

This simply reflects that center saccades are faster than lateral saccades, because the location of the target is known.

Interaction: leg by type

latencyMedianLeg %>%
  group_by(subject,leg,type) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(leg, latency, shape = type)) +
  stat_summary(fun.y = mean, geom = "point") +
  stat_summary(fun.y = mean, geom = "line", aes(group = type, linetype = type))

The effect of Type changes over time: lateral saccades steadily become slower; center saccades vary more randomly.

Interaction: leg by type by direction

latencyMedianLeg %>%
  group_by(subject,leg,type,direction) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(leg, latency, shape = type)) +
  facet_wrap(~direction) +
  stat_summary(fun.y = mean, geom = "point") +
  stat_summary(fun.y = mean, geom = "line", aes(group = type, linetype = type))

The effect over time looks non-linear for left-center saccades. The “tDCS” block is the deviant here, but there is no interaction with stimulation.

Also, for right-lateral saccades, there is a big change that only emerges in the 2nd post-block.

ANOVA matching Kanai et al. (2012) - lateral saccades

Without session order

Differing from the previous omnibus analysis, Kanai et al. (2012) analysed shifts from baseline and only had lateral saccades.

Data:

  • Outliers removed
  • Collapsed into 15-minute intervals
  • Subtract the baseline from each subsequent block
  • Discard center, keep only lateral saccades

Dependent measure: saccadic latency

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (tDCS, post.1, post.2)
  • DIRECTION (left vs. right)
modelKanai <- ezANOVA(data = data.frame(filter(latencyMedianBaseline, type == "lateral")),
                        dv = .(latency), wid = .(subject), within = .(stimulation,leg,direction), type = 3)
# OR, without the EZ package:
# modelKanai=aov(latency~stimulation*leg*direction + Error(subject/(stimulation*leg*direction)),data=latencyMedianBaselineLateral)
# summary(modelKanai)
kable(modelKanai$ANOVA)

Effect DFn DFd F p p<.05 ges
2 stimulation 1 25 0.8044339 0.3783271 0.0089853
3 leg 2 50 3.4589912 0.0391753 * 0.0164093
4 direction 1 25 0.0864110 0.7712172 0.0003663
5 stimulation:leg 2 50 0.4014143 0.6715104 0.0007505
6 stimulation:direction 1 25 0.5221926 0.4766141 0.0012979
7 leg:direction 2 50 3.6626747 0.0327780 * 0.0023536
8 stimulation:leg:direction 2 50 2.5875456 0.0852459 0.0029246

kable(modelKanai$`Mauchly's Test for Sphericity`)

Effect W p p<.05
3 leg 0.5213492 0.0004032 *
5 stimulation:leg 0.6360361 0.0043831 *
7 leg:direction 0.7573179 0.0355909 *
8 stimulation:leg:direction 0.9123864 0.3327710

kable(modelKanai$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
3 leg 0.6762922 0.0597258 0.7012858 0.0578252
5 stimulation:leg 0.7331572 0.6087290 0.7674993 0.6179798
7 leg:direction 0.8047111 0.0434681 * 0.8517313 0.0406111 *
8 stimulation:leg:direction 0.9194442 0.0903598 0.9889658 0.0859306
Main effect of leg
latencyMedianBaseline %>%
  filter(type == "lateral") %>%
  group_by(subject,leg) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(leg, latency)) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  stat_summary(fun.data = mean_cl_normal, size = 1) +
  stat_summary(fun.y = mean, geom = "line", aes(group = 1)) +
  geom_jitter(width = 0.25)

Saccades become slower over time with respect to the baseline. Note that this effect becomes just non-significant when correcting for sphericity.

Interaction: Leg by direction
latencyMedianBaseline %>%
  filter(type == "lateral") %>%
  group_by(subject,leg,direction) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(leg, latency, shape = direction)) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  stat_summary(fun.y = mean, geom = "point") +
  stat_summary(fun.y = mean, geom = "line", aes(group = direction, linetype = direction))

This main effect of leg is stronger for right saccades, but does not occur until the 2nd post-block.

Interaction: stimulation by leg by direction

This interaction is not significant, but it is of primary interest, so let’s still look at it in more detail.

latencyMedianBaseline %>%
  filter(type == "lateral") %>%
  group_by(subject,stimulation,leg,direction) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(leg, latency, shape = stimulation, color = stimulation)) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  facet_wrap(~direction) +
  stat_summary(fun.y = mean, geom = "point") +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation))

Interestingly, subjects get slower over time in all conditions, but this trend is reversed for left-saccades in the anodal session, as predicted. However, the effect barely reaches 1 ms…

With session order

Add an additional factor SESSION ORDER, which creates two groups: those subjects who received anodal tDCS in the first session vs. those who received cathodal tDCS in the first session. Note that these groups are not exactly balanced, which might affect (correcting for) violations of sphericity:

latencyMedianBaseline %>%
  group_by(session.order) %>%
  summarize(count = n_distinct(subject)) %>%
  kable(.)
session.order count
first.anodal 14
first.cathodal 12

Data:

  • Outliers removed
  • Collapsed into 15-minute intervals
  • Subtract the baseline from each subsequent block
  • Discard center, keep only lateral saccades

Dependent measure: saccadic latency

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (tDCS, post.1, post.2)
  • DIRECTION (left vs. right)
  • SESSION ORDER (first anodal vs. first cathodal)
modelKanaiOrder <- ezANOVA(data = data.frame(filter(latencyMedianBaseline, type == "lateral")), dv = .(latency),
          wid = .(subject), within = .(stimulation,leg,direction),  between = session.order, type = 3)
kable(modelKanaiOrder$ANOVA)

Effect DFn DFd F p p<.05 ges
2 session.order 1 24 0.1433284 0.7083227 0.0020996
3 stimulation 1 24 0.6340723 0.4336719 0.0068970
5 leg 2 48 3.1888328 0.0500837 0.0158928
7 direction 1 24 0.1014256 0.7528804 0.0004663
4 session.order:stimulation 1 24 2.9615300 0.0981361 0.0314179
6 session.order:leg 2 48 0.9521914 0.3930621 0.0047991
8 session.order:direction 1 24 0.1559521 0.6963989 0.0007169
9 stimulation:leg 2 48 0.2675333 0.7663984 0.0004736
11 stimulation:direction 1 24 0.5243058 0.4760104 0.0014194
13 leg:direction 2 48 3.4028814 0.0414916 * 0.0023321
10 session.order:stimulation:leg 2 48 3.6820297 0.0325327 * 0.0064786
12 session.order:stimulation:direction 1 24 0.0512017 0.8229013 0.0001388
14 session.order:leg:direction 2 48 0.5664097 0.5713066 0.0003889
15 stimulation:leg:direction 2 48 2.5819394 0.0860974 0.0030905
16 session.order:stimulation:leg:direction 2 48 0.7368106 0.4839727 0.0008839

kable(modelKanaiOrder$`Mauchly's Test for Sphericity`)

Effect W p p<.05
5 leg 0.5041662 0.0003798 *
6 session.order:leg 0.5041662 0.0003798 *
9 stimulation:leg 0.7028372 0.0173312 *
10 session.order:stimulation:leg 0.7028372 0.0173312 *
13 leg:direction 0.7680908 0.0481110 *
14 session.order:leg:direction 0.7680908 0.0481110 *
15 stimulation:leg:direction 0.8975070 0.2883601
16 session.order:stimulation:leg:direction 0.8975070 0.2883601

kable(modelKanaiOrder$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
5 leg 0.6685235 0.0724403 0.6933380 0.0704904
6 session.order:leg 0.6685235 0.3628233 0.6933380 0.3657030
9 stimulation:leg 0.7709133 0.7088451 0.8136384 0.7209771
10 session.order:stimulation:leg 0.7709133 0.0453943 * 0.8136384 0.0426597 *
13 leg:direction 0.8117481 0.0526303 0.8622305 0.0493806 *
14 session.order:leg:direction 0.8117481 0.5370589 0.8622305 0.5469276
15 stimulation:leg:direction 0.9070352 0.0920383 0.9770103 0.0875336
16 session.order:stimulation:leg:direction 0.9070352 0.4720869 0.9770103 0.4811399
Interaction: session order by stimulation by direction
latencyMedianBaseline %>%
  filter(type == "lateral") %>%
  group_by(subject,session.order,stimulation,direction) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(direction, latency, shape = stimulation, color = stimulation)) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  facet_wrap(~session.order) +
  stat_summary(fun.y = mean, geom = "point") +
  stat_summary(fun.y = mean, geom = "line", aes(group = stimulation))

The session order by stimulation direction interaction can be construed as a main effect of session. It appears that in the 2nd session, people slow down more than in the 1st. The difference between left and right also seems more pronounced, especially when the 2nd session is anodal.

This latter three-way interaction is very difficult to interpret though. In addition, the stimulation by direction interaction is not significant without session order, so we do not have to worry that this effect is present but confounded by session order.

ANOVA matching Kanai et al. (2012) - center saccades

Without session order

Repeat the same ANOVA, but now for center saccades (which Kanai did not have).

modelKanaiCenter <- ezANOVA(data = data.frame(filter(latencyMedianBaseline, type == "center")),
                        dv = .(latency), wid = .(subject), within = .(stimulation,leg,direction), type = 3)
kable(modelKanaiCenter$ANOVA)

Effect DFn DFd F p p<.05 ges
2 stimulation 1 25 3.0937191 0.0908311 0.0230246
3 leg 2 50 2.3789819 0.1030547 0.0062189
4 direction 1 25 4.7775590 0.0384115 * 0.0158632
5 stimulation:leg 2 50 0.1055936 0.8999904 0.0001735
6 stimulation:direction 1 25 1.8802459 0.1824903 0.0055307
7 leg:direction 2 50 3.1018543 0.0537187 0.0016853
8 stimulation:leg:direction 2 50 1.9636026 0.1510262 0.0012036

kable(modelKanaiCenter$`Mauchly's Test for Sphericity`)

Effect W p p<.05
3 leg 0.5173954 0.0003680 *
5 stimulation:leg 0.8690648 0.1856204
7 leg:direction 0.9230394 0.3825099
8 stimulation:leg:direction 0.7823535 0.0525819

kable(modelKanaiCenter$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
3 leg 0.6744887 0.1241893 0.6991962 0.1225297
5 stimulation:leg 0.8842239 0.8774896 0.9465498 0.8902341
7 leg:direction 0.9285390 0.0579604 0.9999608 0.0537210
8 stimulation:leg:direction 0.8212564 0.1600417 0.8713552 0.1575428
Main effect of direction
latencyMedianBaseline %>%
  filter(type == "center") %>%
  group_by(subject,direction) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(direction, latency)) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  stat_summary(fun.y = mean, geom = "line", aes(group = 1), size = 2) +
  geom_line(aes(colour = subject, group = subject))

This seems to be a really tiny and variable effect, but apparently left saccades get somewhat slower and right saccades somewhat faster compared to baseline.

With session order

modelKanaiCenterOrder <- ezANOVA(data = data.frame(filter(latencyMedianBaseline, type == "center")), dv = .(latency),
          wid = .(subject), within = .(stimulation,leg,direction),  between = session.order, type = 3)
kable(modelKanaiCenterOrder$ANOVA)

Effect DFn DFd F p p<.05 ges
2 session.order 1 24 0.1166399 0.7356800 0.0025860
3 stimulation 1 24 3.3377548 0.0801702 0.0258116
5 leg 2 48 2.3943806 0.1020456 0.0066197
7 direction 1 24 6.5039074 0.0175653 * 0.0189442
4 session.order:stimulation 1 24 0.9506165 0.3392880 0.0074896
6 session.order:leg 2 48 0.5737494 0.5672253 0.0015943
8 session.order:direction 1 24 5.5454061 0.0270448 * 0.0161976
9 stimulation:leg 2 48 0.0965518 0.9081388 0.0001683
11 stimulation:direction 1 24 2.4540824 0.1303112 0.0068754
13 leg:direction 2 48 2.8467499 0.0678686 0.0016019
10 session.order:stimulation:leg 2 48 0.5117829 0.6026597 0.0008915
12 session.order:stimulation:direction 1 24 3.2609785 0.0835059 0.0091154
14 session.order:leg:direction 2 48 1.1056981 0.3392615 0.0006228
15 stimulation:leg:direction 2 48 2.2553582 0.1158348 0.0013961
16 session.order:stimulation:leg:direction 2 48 1.7398007 0.1864427 0.0010773

kable(modelKanaiCenterOrder$`Mauchly's Test for Sphericity`)

Effect W p p<.05
5 leg 0.5132456 0.0004664 *
6 session.order:leg 0.5132456 0.0004664 *
9 stimulation:leg 0.8520126 0.1585365
10 session.order:stimulation:leg 0.8520126 0.1585365
13 leg:direction 0.8959726 0.2827415
14 session.order:leg:direction 0.8959726 0.2827415
15 stimulation:leg:direction 0.8087403 0.0870572
16 session.order:stimulation:leg:direction 0.8087403 0.0870572

kable(modelKanaiCenterOrder$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
5 leg 0.6726060 0.1234676 0.6980931 0.1217371
6 session.order:leg 0.6726060 0.5031425 0.6980931 0.5090948
9 stimulation:leg 0.8710897 0.8835886 0.9334806 0.8962764
10 session.order:stimulation:leg 0.8710897 0.5781127 0.9334806 0.5903977
13 leg:direction 0.9057746 0.0738118 0.9754789 0.0693693
14 session.order:leg:direction 0.9057746 0.3351508 0.9754789 0.3382625
15 stimulation:leg:direction 0.8394475 0.1256368 0.8953942 0.1221703
16 session.order:stimulation:leg:direction 0.8394475 0.1923135 0.8953942 0.1903485
Interaction: session order by direction

There is a main effect of direction in the ANOVA without session order, so this effect might be confounded.

latencyMedianBaseline %>%
  filter(type == "center") %>%
  group_by(subject,session.order,direction) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(direction, latency, shape = session.order)) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  stat_summary(fun.y = mean, geom = "point") +
  stat_summary(fun.y = mean, geom = "line", aes(group = session.order, linetype = session.order))

The main effect of direction is present for both groups, but it is much stronger in the group that first receives cathodal stimulation. This could be construed as a carryover effect, i.e. that the effect of cathodal stimulation was not yet washed-out by the second session and modulated the effect of anodal (and vice versa). Or, it could simply be that there is a difference between the two groups (anodal first vs. cathodal first) that has nothing to do with stimulation.

Bayesian

Linear mixed effects matching Kanai - saccade latency

Test against the null model

bfKanaiLateral = anovaBF(latency~stimulation*leg*direction+subject, data = data.frame(filter(latencyMedianBaseline, type == "lateral")), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
View(latencyMedianBaseline)
bfKanaiLateral = sort(bfKanaiLateral, decreasing = TRUE) # sort such that winning model is at the top

First we compare all models to the most simple (null) model, which is the intercept only + random effect model: latency ~ subject. This does not test for effects of SUBJECT but models it as a nuisance factor (whichRandom = "subject"). In addition, to decrease the model space, we do not consider models that have an interaction without the corresponding main effects (whichModels = "withmain").

kable(select(extractBF(bfKanaiLateral), bf)) # show only the Bayes factors in a table
bf
leg + subject 0.8399089
stimulation + subject 0.7416393
stimulation + leg + subject 0.6465591
direction + subject 0.1357138
direction + leg + subject 0.1114138
stimulation + direction + subject 0.0995612
stimulation + direction + leg + subject 0.0872255
stimulation + leg + stimulation:leg + subject 0.0478623
stimulation + direction + stimulation:direction + leg + subject 0.0246398
stimulation + direction + stimulation:direction + subject 0.0215074
direction + leg + direction:leg + subject 0.0110546
stimulation + direction + leg + direction:leg + subject 0.0085640
stimulation + direction + leg + stimulation:leg + subject 0.0063807
stimulation + direction + stimulation:direction + leg + direction:leg + subject 0.0018722
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 0.0014185
stimulation + direction + leg + stimulation:leg + direction:leg + subject 0.0006242
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 0.0001322
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.0000286

The winning model is the one with just a main effect of LEG, with a Bayes factor of 0.8. However, so even for this model there is less evidence than for the null model, which by definition has a Bayes Factor of 1.

The conventional interpretation for Bayes Factors is the following:

  • BF10 < 0.1: strong evidence for H0
  • 0.1 < BF10 < .33: moderate evidence for H0
  • 0.333 < BF10 < 1: anecdotal evidence for H0

  • BF10 = 1: equivalent evidence for H0 and H1

  • 1 BF10 < 3: anecdotal evidence for H1
  • 3 < BF10 < 10: moderate evidence for H1
  • BF10 > 10: strong evidence H1

So to switch between expressing the Bayes Factor as evidence for H1 (BF10) or H0 (BF01), you simply invert it (divide by 1).

We can compute the evidence for a particular effect by comparing this winning model with the best-fitting model that does not contain the effect. We can compute the evidence for absence of a particular effect by comparing the winning model with the best-fitting model that does contain the effect.

The evidence for the effect of LEG can be quantified by comparing the Bayes factors of the first and the 3rd model (because that is the first one that does not contain LEG as a factor): 1.3. This constitues only anocdotal evidence for the presence of a leg effect, even though it was significant in the classical ANOVA. But, given that the leg model itself is such a poor fit, in the Bayesian analysis this weak evidence is no surprise.

The evidence for the absence of the STIMULATION by DIRECTION interaction can be quantified by comparing the Bayes factors of the first and the 9th model (because that is the first one that does contain the interaction): 34.1. This constitues strong evidence for the absence of the interaction.

Test against the full model

Another option for quantifying evidence for a particular effect is to compare the full model to a model where that effect is omitted (whichModels = top"). The full model is stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject.

bfKanaiLateralFull = anovaBF(latency~stimulation*leg*direction+subject, data = data.frame(filter(latencyMedianBaseline, type == "lateral")), whichModels = "top", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiLateralFull
Bayes factor top-down analysis
--------------
When effect is omitted from stimulation + direction + leg + stimulation:direction + stimulation:leg + direction:leg + stimulation:direction:leg + subject , BF is...
[1] Omit direction:leg:stimulation : 5.384841 <U+00B1>5.62%
[2] Omit direction:leg             : 9.833237 <U+00B1>5.51%
[3] Omit leg:stimulation           : 13.49779 <U+00B1>5.66%
[4] Omit direction:stimulation     : 4.282142 <U+00B1>5.45%
[5] Omit leg                       : 1.191349 <U+00B1>7.91%
[6] Omit direction                 : 7.358471 <U+00B1>5.63%
[7] Omit stimulation               : 1.295222 <U+00B1>8.68%

Against denominator:
  latency ~ stimulation + direction + leg + stimulation:direction + stimulation:leg + direction:leg + stimulation:direction:leg +     subject
---
Bayes factor type: BFlinearModel, JZS

Removing the LEG effect from the model yields a higher Bayes Factor, so removing this effect actually improved the model, although only by a little bit. The evidence thus goes in the direction of the null; when expressed in favor of the alternative, the Bayes Factir becomes less than one: 1  1.191 = 0.8

Similarly, removing the DIRECTION by STIMULATION effect improves the model, and this time a bit more: in the range of moderate evidence for the null.

Bayesian model averaging

The problem with the 1st option (comparing single models, for example to the winning model) is that for designs with many factors (and therefore models), it becomes risky and a bit subjective to base conclusions on just two models. In this case, the winning model is even a bad fit, so it doesn’t seem appropriate to use it as a benchmark.

The problem with the 2nd option (comparing against the full model) is actually very apparent in this dataset: the full model is a terrible fit, as it comes in last. There is even a lot of evidence against it when compared to the null model!

One solution is to do Bayesian Model Averaging: compare multiple models and aggregate the Bayes Factors.

In the JASP stats package, this analysis is also called the “inclusion Bayes factor”. Briefly, it compares all models that include the effect of interest vs. all models that do not. For examples and a conceptual explanation, see example 5 in: Bayesian inference for psychology. Part II: Example applications with JASP.

There’s also a different way of calculating inclusion Bayes factors (conceptualized by Sebastiaan Mathot) that is currently being implemented in JASP. This is called the “inclusion Bayes factor across matched models”, and is more selective in the set of models that’s being compared than the standard inclusion BF. Briefly, the inclusion BF across matched models compares:

  • all models that include the effect of interest, but NO interactions with the effect of interest, VERSUS
  • the models that result from stripping the effect of interest from this set of models.

Let’s compare the default inclusion Bayes Factors for all effects:

# Default inclusion Bayes Factors
kable(inclusionBF(bfKanaiLateral))
effect Bayes.factor
stimulation 0.2873386
direction 0.0556146
stimulation:direction 0.0287605
leg 0.3194814
stimulation:leg 0.0327913
direction:leg 0.0128231
stimulation:direction:leg 0.0001360

Doing the analysis this way, we also find strong evidence against most of these effects; particularly the interactions.

My preferred approach is the inclusion Bayes factor across matched models. The evidence is qualitatively similar, but less strong, probably because we aren’t including as many poorly fitting models in the model comparison (which have a very large BF10 and therefore a lot of effect on the composite Bayes Factor):

kable(inclusionBF(bfKanaiLateral, models = "matched"))
effect Bayes.factor
stimulation 0.7547571
direction 0.1344014
stimulation:direction 0.2449654
leg 0.8555487
stimulation:leg 0.0733784
direction:leg 0.0962754
stimulation:direction:leg 0.2163735

Linear mixed effects matching Kanai - center saccades

bfKanaiCenter = anovaBF(latency~stimulation*leg*direction+subject, data = data.frame(filter(latencyMedianBaseline, type == "center")), whichModels="withmain", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiCenter <- sort(bfKanaiCenter, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfKanaiCenter), bf)) # show only the Bayes factors in a table
bf
stimulation + direction + subject 555.2527534
stimulation + direction + stimulation:direction + subject 401.8383357
stimulation + direction + leg + subject 94.0231519
stimulation + direction + stimulation:direction + leg + subject 71.1333686
stimulation + subject 56.4457669
stimulation + leg + subject 9.9269257
stimulation + direction + leg + direction:leg + subject 9.1764175
direction + subject 8.1385456
stimulation + direction + stimulation:direction + leg + direction:leg + subject 6.8923098
stimulation + direction + leg + stimulation:leg + subject 6.3767641
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 4.7562332
direction + leg + subject 1.2906652
stimulation + direction + leg + stimulation:leg + direction:leg + subject 0.6672675
stimulation + leg + stimulation:leg + subject 0.6516657
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 0.5806634
leg + subject 0.1579592
direction + leg + direction:leg + subject 0.1210615
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.0672617

Interestingly, there is a lot more evidence across the board, especially for the models that feature Stimulation and Direction.

kable(inclusionBF(bfKanaiCenter, models = "matched"))
effect Bayes.factor
stimulation 67.6885828
direction 9.7544628
stimulation:direction 0.7290812
leg 0.1726179
stimulation:leg 0.0681792
direction:leg 0.0981963
stimulation:direction:leg 0.1158360

There seems to be a mismatch with the classical ANOVA: An effect of stimulation receives strong support, whereas it was non-significant. The effect of direction was significant, but it is less strongly supported by the inclusion Bayes Factor (although the evidence still goes in the right direction).

Main effect of stimulation

latencyMedianBaseline %>%
  filter(type == "center") %>%
  group_by(subject,stimulation) %>%
  summarise(latency = mean(latency)) %>%
  ggplot(aes(stimulation, latency)) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  stat_summary(fun.y = mean, geom = "line", aes(group = 1), size = 2) +
  geom_line(aes(colour = subject, group = subject))

It is easy to see why this effect is non-significant: the average difference is tiny and there is a lot of variability. The plot shows one major outlier though in terms of the effect size (S01): let’s see what happens to the Bayes Factor if we take their data out.

latencyNoS01 <- latencyMedianBaseline %>%
  filter(subject != "S01") %>%
  mutate(subject = factor(subject))
bfKanaiCenterNoS01 = anovaBF(latency~stimulation*leg*direction+subject, data = data.frame(filter(latencyNoS01, type == "center")), whichModels="withmain", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiCenterNoS01 <- sort(bfKanaiCenterNoS01, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfKanaiCenterNoS01), bf)) # show only the Bayes factors in a table

bf
stimulation + direction + subject 1370.5021891
direction + subject 610.7330230
stimulation + direction + leg + subject 531.6196659
stimulation + direction + stimulation:direction + subject 352.9869220
direction + leg + subject 200.7493579
stimulation + direction + stimulation:direction + leg + subject 123.1974214
stimulation + direction + leg + direction:leg + subject 63.0498822
stimulation + direction + leg + stimulation:leg + subject 42.8446155
direction + leg + direction:leg + subject 24.4897141
stimulation + direction + stimulation:direction + leg + direction:leg + subject 14.9256981
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 8.3443542
stimulation + direction + leg + stimulation:leg + direction:leg + subject 4.0678602
stimulation + subject 1.9848227
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 1.0168697
stimulation + leg + subject 0.6129997
leg + subject 0.3006916
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.1633244
stimulation + leg + stimulation:leg + subject 0.0422355

kable(inclusionBF(bfKanaiCenterNoS01, models = "matched"))
effect Bayes.factor
stimulation 2.3502132
direction 699.4732539
stimulation:direction 0.2487328
leg 0.3664546
stimulation:leg 0.0767869
direction:leg 0.1186097
stimulation:direction:leg 0.1606149

This completely abolishes the strong support for Stimulation, and greatly enhances the support for Direction, bringing the Bayesian and the classical ANOVAs more in line. At present it is unclear why the classical and Bayesian analyses differ in this regard. When simulating this case for normally distributed data, the Bayes Factors and p-values track each other nicely (see discussion on JASP/BayesFactor forum). This suggests there must be some assumption that is not met in this particular dataset, which is causing the divergence between the analyses.

Still, let’s do some follow-up tests with all of the data (i.e. including this subject) to see whether the anodal or cathodal change scores are significantly different from 0 on their own.

Bayesian one-sample t-tests:

latencyMedianBaseline %>%
  filter(type == "center") %>% # keep only center saccades
  group_by(stimulation,subject) %>% # for each session and subject
  summarise(deviation.end = mean(latency)) %>% # average over all other variables
  spread(stimulation,deviation.end) %>% # make separate columns with test data
  summarise_if(is.numeric, funs(extractBF(ttestBF(.), onlybf = TRUE))) %>% # run Bayesian t-test on each column, keeping only the BF
  gather(stimulation,BF,anodal,cathodal) %>% # make row for each stimulation condition
  kable(.)
stimulation BF
anodal 0.3218926
cathodal 0.2840670

Frequentist one-sample t-tests:

latencyMedianBaseline %>%
  filter(type == "center") %>% # keep only center saccades
  group_by(stimulation,subject) %>% # for each session and subject
  summarise(deviation.end = mean(latency)) %>% # average over all other variables (df is now still grouped per stimulation)
  summarise_if(is.numeric, funs(list(tidy(t.test(.))))) %>%  # run one-sample t-test for each stimulation condition, return tidy data frames
  unnest() %>% # unpack the list-column with data frame for each test
  kable(.)
stimulation estimate statistic p.value parameter conf.low conf.high method alternative
anodal -1.608974 -0.9875463 0.3328370 25 -4.964508 1.746559 One Sample t-test two.sided
cathodal 1.096154 0.8335773 0.4124131 25 -1.612139 3.804446 One Sample t-test two.sided

So neither are actually significant or have a BF with evidence for the alternative.

LS0tCnRpdGxlOiAic2FjYy10RENTOiBNZWRpYW4gc2FjY2FkZSBsYXRlbmN5IgphdXRob3I6ICJMZW9uIFJldGVpZyIKb3V0cHV0OgogIGdpdGh1Yl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgaHRtbF9ub3RlYm9vazoKICAgIGhpZ2hsaWdodDogcHlnbWVudHMKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKUiBub3RlYm9vayBmb3IgYW5hbHlzZXMgb2YgbWVkaWFuIHNhY2NhZGUgbGF0ZW5jeSBpbiB0aGUgYHNhY2MtdERDU2AgZGF0YXNldC4gUHJldmlvdXMgcHJvY2Vzc2luZzoKCiogUmF3IGRhdGEgd2VyZSBwYXJzZWQgaW50byBldmVudHMgKHNhY2NhZGVzLCBmaXhhdGlvbnMsIGV0Yy4pIGJ5IHRoZSBFeWVMaW5rIGRhdGEgd2VyZSBjb2xsZWN0ZWQgb24uCiogRXZlbnRzIHdlcmUgZXh0cmFjdGVkIGFuZCBzYWNjYWRlIG1lYXN1cmVzIHdlcmUgY29tcHV0ZWQgd2l0aCBhIE1BVExBQiBzY3JpcHQuCgpgYGB7ciBzZXR1cH0KIyBMb2FkIHNvbWUgbGlicmFyaWVzCmxpYnJhcnkoaGVyZSkgIyBmaWxlIHBhdGhzCmxpYnJhcnkodGlkeXZlcnNlKSAjIGltcG9ydGluZywgdHJhbnNmb3JtaW5nLCBhbmQgdmlzdWFsaXppbmcgZGF0YSBmcmFtZXMKbGlicmFyeShleikgIyBBTk9WQQpsaWJyYXJ5KEJheWVzRmFjdG9yKSAjIEJheWVzaWFuIHN0YXRpc3RpY3MKbGlicmFyeShicm9vbSkgIyB0cmFuc2Zvcm0gbW9kZWwgb3V0cHV0IGludG8gYSBkYXRhIGZyYW1lCmxpYnJhcnkoa25pdHIpICMgUiBtYXJrZG93biBvdXRwdXQgKGh0bWwsIHBkZiwgZXRjLikKIyBzZXQgZGVmYXVsdCBvdXRwdXQgYW5kIGZpZ3VyZSBvcHRpb25zCmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLndpZHRoID0gNywgZmlnLmFzcCA9IDAuNjE4LCBvdXQud2lkdGggPSAiNzUlIiwgZmlnLmFsaWduID0gImNlbnRlciIpCgoKc291cmNlKGhlcmUoInNyYyIsICJsaWIiLCAiSW5jbHVzaW9uQkYuUiIpKQoKc2Vzc2lvbkluZm8oKQpgYGAKCiMgTG9hZCBkYXRhCgojIyBFeWUgZGF0YQoKVGhlIC5jc3YgZmlsZSB3aXRoIHRoZSBleWUgdHJhY2tpbmcgZGF0YSB3YXMgY3JlYXRlZCBpbiBNQVRMQUIuCgpgYGB7ciBMb2FkIHRoZSBkYXRhIGZyYW1lfQojIExvYWQgdGhlIGRhdGEgZnJhbWUKZGF0YUZpbGUgPC0gaGVyZSgiZGF0YSIsICJzYWNjLXREQ1NfZGF0YS5jc3YiKQpncm91cERhdGEgPC0gcmVhZF9jc3YoZGF0YUZpbGUsIGNvbF9uYW1lcyA9IFRSVUUsIG5hID0gIk5hTiIsIHByb2dyZXNzID0gRkFMU0UsIGNvbF90eXBlcyA9IGNvbHMoCiAgc3RpbXVsYXRpb24gPSBjb2xfZmFjdG9yKGMoImFub2RhbCIsImNhdGhvZGFsIikpLAogIGxlZyA9IGNvbF9mYWN0b3IoYygicHJlIiwidERDUyIsInBvc3QiKSksCiAgdHlwZSA9IGNvbF9mYWN0b3IoYygibGF0ZXJhbCIsImNlbnRlciIpKSwKICBkaXJlY3Rpb24gPSBjb2xfZmFjdG9yKGMoImxlZnQiLCJyaWdodCIpKSAKKSkKYGBgCgpgYGB7ciBTaG93IGRhdGEgZnJhbWV9CmthYmxlKGhlYWQoZ3JvdXBEYXRhKSkKYGBgCgoqIF9fc3ViamVjdF9fOiBzdWJqZWN0IElECiogX19zdGltdWxhdGlvbl9fOiBXaGV0aGVyIGRhdGEgYXJlIGZyb20gdGhlIGBhbm9kYWxgIG9yIGBjYXRob2RhbGAgc2Vzc2lvbgoqIF9fbGVnX186IFdoZXRoZXIgZGF0YSBhcmUgYmVmb3JlIChgcHJlYCksIGR1cmluZyAoYHREQ1NgKSwgb3IgYWZ0ZXIgKGBwb3N0YCkgdERDUwoqIF9fYmxvY2tfXzogQWZ0ZXIgZWFjaCBibG9jayBwYXJ0aWNpcGFudCBoYWQgYSBicmllZiBicmVhayBhbmQgdHJhY2tlciB3YXMgcmVjYWxpYnJhdGVkCiogX190cmlhbF9fOiB0cmlhbCBudW1iZXIgd2l0aGluIGEgYmxvY2sKKiBfX3R5cGVfXzoKICAgICogYGxhdGVyYWxgIC0gZml4YXRpb24gaW4gY2VudGVyIG9mIGRpc3BsYXksIHNhY2NhZGUgbWFkZSB0b3dhcmRzIHRoZSBwZXJpcGhlcnkKICAgICogYGNlbnRlcmAgLSBmaXhhdGlvbiBpbiBwZXJpcGhlcnksIHNhY2NhZGUgbWFkZSBiYWNrIHRvd2FyZHMgdGhlIGNlbnRlciBvZiB0aGUgZGlzcGxheQoqIF9fZGlyZWN0aW9uX186IGBsZWZ0YCBmb3Igc2FjY2FkZXMgdG93YXJkcyB0aGUgbGVmdCBvZiBjdXJyZW50IGZpeGF0aW9uIHBvc2l0aW9uOyBgcmlnaHRgIGZvciBzYWNjYWRlcyB0byB0aGUgcmlnaHQKKiBfX2RldmlhdGlvbi5zdGFydF9fIDogZGlzdGFuY2UgKGluIHZpc3VhbCBhbmdsZSkgZnJvbSBzYWNjYWRlIHN0YXJ0IHBvaW50IHRvIGZpeGF0aW9uCiogX19kZXZpYXRpb24uZW5kLnhfXzogZGlzdGFuY2UgKGluIHZpc3VhbCBhbmdsZSkgZnJvbSB4LWNvb3JkaW5hdGUgb2Ygc2FjY2FkZSBlbmQgcG9pbnQgdG8geC1jb29yZGluYXRlIG9mIHRhcmdldCBsb2NhdGlvbgoqIF9fZGV2aWF0aW9uLmVuZC55X186IHNhbWUgZm9yIHktY29vcmRpbmF0ZQoqIF9fYW1wbGl0dWRlX186IGRpc3RhbmNlIChpbiB2aXN1YWwgYW5nbGUpIGJldHdlZW4gc2FjY2FkZSBzdGFydCBhbmQgZW5kIHBvaW50CiogX19sYXRlbmN5X186IHRpbWUgKGluIG1zKSBmcm9tIHRhcmdldCBvbnNldCB0byBzdGFydCBvZiBzYWNjYWRlCiogX19kcmlmdC54X186IGRpc3RhbmNlIChpbiB2aXN1YWwgYW5nbGUpIGJldHdlZW4geC1jb29yZGluYXRlIG9mIGF2ZXJhZ2UgZml4YXRpb24gcG9zaXRpb24gZHVyaW5nIHRoZSBicmVhayB0byB4LWNvb3JkaW5hdGUgb2YgZml4YXRpb24gc3RpbXVsdXMuIFRoaXMgc3RpbXVsdXMgd2FzIGRpc3BsYXllZCBhdCBlYWNoIGJyZWFrIGluIHRoZSB0YXNrLCBzbyB0aGlzIGRhdGEgY2FuIGJlIHVzZWQgYXMgYW4gZXN0aW1hdGUgb2Ygb2Zmc2V0cyB0byBkbyBkcmlmdCBjb3JyZWN0aW9uLgoqIF9fZHJpZnQueV9fOiBzYW1lIGZvciB5LWNvb3JkaW5hdGUKCmBgYHtyIExvYWQgc3ViamVjdCBpbmZvIGRhdGF9CiMgTG9hZCBleWUgdHJhY2tpbmcgZGF0YSBpbnRvIGRhdGEgZnJhbWUKZGF0YUZpbGUgPC0gaGVyZSgiZGF0YSIsICJzdWJqZWN0X2luZm8uY3N2IikKc3ViamVjdERhdGEgPC0gcmVhZF9jc3YyKGRhdGFGaWxlLCBjb2xfbmFtZXMgPSBUUlVFLCBwcm9ncmVzcyA9IEZBTFNFLCBjb2xfdHlwZXMgPSBjb2xzKAogIHNlc3Npb24ub3JkZXIgPSBjb2xfZmFjdG9yKGMoImZpcnN0LmFub2RhbCIsICJmaXJzdC5jYXRob2RhbCIpKQopKQpgYGAKCiMjIFN1YmplY3QgbWV0YWRhdGEKCmBgYHtyIFNob3cgc3ViamVjdCBpbmZvIGRhdGEgZnJhbWUsIHJlc3VsdHM9J2FzaXMnfQprYWJsZShoZWFkKHN1YmplY3REYXRhKSkKYGBgCgoqIF9fc3ViamVjdF9fOiBzdWJqZWN0IElECiogX19zZXNzaW9uLm9yZGVyX186IFdoZXRoZXIgc3ViamVjdCBoYWQgYW5vZGFsIHN0aW11bGF0aW9uIGluIHRoZSBmaXJzdCBzZXNzaW9uIChgZmlyc3QuYW5vZGFsYCkgb3IgY2F0aG9kYWwgc3RpbXVsYXRpb24gaW4gdGhlIGZpcnN0IHNlc3Npb24gKGBmaXJzdC5jYXRob2RhbGApCiogX19nZW5kZXJfXwoqIF9fYWdlX186IGluIHllYXJzCiogX19kb21pbmFudC5leWVfXzogcmVzdWx0IG9mIGV5ZSBkb21pbmFuY2UgdGVzdAoKVGhlIG1haW4gdXNlIGlzIHRvIHNlZSBpZiB0aGUgbnVpc2FuY2UgZmFjdG9yIF9zZXNzaW9uLm9yZGVyXyBjb3ZhcmllcyB3aXRoIHRoZSBmYWN0b3JzIG9mIGludGVyZXN0IGluIHRoZSBkZXNpZ24uIFRoaXMgY291bGQgaW5kaWNhdGUgdGhlIHByZXNlbmNlIG9mIGNhcnJ5b3ZlciBlZmZlY3RzIGJldHdlZW4gdGhlIHN0aW11bGF0aW9uLCBvciBhIGRpZmZlcmVuY2UgaW4gc3ViZ3JvdXBzIHdpdGhpbiB0aGUgc2FtcGxlIChzZWUgPGh0dHA6Ly93d3cuamVycnlkYWxsYWwuY29tL2xoc3AvY3Jvc3NvdnIuaHRtPiBmb3IgYW4gaW50cm9kdWN0aW9uIHRvIHRoZXNlIGtpbmRzIG9mIGFuYWx5c2VzLikuCgojIEluc3BlY3QgbWVkaWFuIGRhdGEKCiMjIFJlbW92ZSBvdXRsaWVycwoKYGBge3IgT3V0bGllciBjcml0ZXJpYX0KdG9vRmFzdCA8LSA1MAp0b29TbG93IDwtIDQwMApiYWRGaXggPC0gMS44CmJhZFNhY2MgPC0gOApzdWJzMmV4Y2x1ZGUgPC0gYygiUzI4IiwiUzE2IiwiUzIyIiwiUzIxIiwiUzI1IikKYGBgCgoqIFMyMSBhbmQgUzI1IHdlcmUgdGVzdGVkIDwgNDhoIGFwYXJ0CiogUzE2LCBTMjIgYW5kIFMyOCBoYWQgZmV3ZXIgdGhhbiA1MCBzYWNjYWRlcyBwZXIgY29uZGl0aW9uIGFmdGVyIHRyaWFsIHJlamVjdGlvbgoKQ3JpdGVyaWEgZm9yIG91dGxpZXIgc2FjY2FkZXM6CgoqIERpc2NhcmQgZmFzdCBzYWNjYWRlcywgd2l0aCBhIGxhdGVuY3kgb2YgYHIgdG9vRmFzdGAgbXMgb3IgbGVzcwoqIERpc2NhcmQgc2xvdyBzYWNjYWRlcywgc2FjY2FkZXMgd2l0aCBhIGxhdGVuY3kgb2YgYHIgdG9vU2xvd2AgbXMgb3IgbW9yZQoqIERpc2NhcmQgaW5hY2N1cmF0ZSBmaXhhdGlvbnMsIHdpdGggc2FjY2FkZSBzdGFydGluZyBwb2ludCBtb3JlIHRoYW4gYHIgYmFkRml4YCBkZWdyZWVzIG9yIG1vcmUgYXdheSBmcm9tIGZpeGF0aW9uCiogRGlzY2FyZCBmYXVsdHkgc2FjY2FkZXMsIHdpdGggeC1jb29yZGluYXRlIG9mIHNhY2NhZGUgZW5kIHBvaW50IGByIGJhZFNhY2NgIGRlZ3JlZSBvciBtb3JlIGF3YXkgZnJvbSB0aGUgdGFyZ2V0CgpJbiBbS2FuYWkgZXQgYWwuICgyMDEyKV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMzM4OS9mcHN5dC4yMDEyLjAwMDQ1KSwgdGhpcyB3YXM6CgoqIEZhc3Qgc2FjY2FkZXM6IDUwIG1zCiogU2xvdyBzYWNjYWRlczogNDAwIG1zCiogQmFkIGZpeGF0aW9uczogMS44IGRlZ3JlZXMKKiBGYXVsdHkgc2FjY2FkZXM6IG9wcG9zaXRlIGhlbWlmaWVsZCBvZiB0YXJnZXQgKGhlcmUsIHRoYXQgd291bGQgYmUgOCBkZWdyZWVzIGFzIHRhcmdldHMgd2VyZSB0aGF0IGVjY2VudHJpYykKCmBgYHtyIFJlbW92ZSBvdXRsaWVyIHRyaWFscyBhbmQgc3ViamVjdHN9CiMgUmVtb3ZlIG91dGxpZXJzIGFuZCBzdWJqZWN0cwpncm91cERhdGEgPC0gZmlsdGVyKGdyb3VwRGF0YSwKICAgICAgICAgICAgICAgICAgICAjIG91dGxpZXJzCiAgICAgICAgICAgICAgICAgICAgbGF0ZW5jeSA+PSB0b29GYXN0LAogICAgICAgICAgICAgICAgICAgIGxhdGVuY3kgPD0gdG9vU2xvdywKICAgICAgICAgICAgICAgICAgICBkZXZpYXRpb24uc3RhcnQgPD0gYmFkRml4LAogICAgICAgICAgICAgICAgICAgIGRldmlhdGlvbi5lbmQueCA8PSBiYWRTYWNjLAogICAgICAgICAgICAgICAgICAgICMgc3ViamVjdHMKICAgICAgICAgICAgICAgICAgICAhKHN1YmplY3QgJWluJSBzdWJzMmV4Y2x1ZGUpLAogICAgICAgICAgICAgICAgICAgICMgbWlzc2luZyB2YWx1ZXMKICAgICAgICAgICAgICAgICAgICBjb21wbGV0ZS5jYXNlcyhncm91cERhdGEpCikKYGBgCgojIyBEYXRhIHBlciBibG9jawoKYGBge3IgQ29tcHV0ZSBtZWRpYW4gaW4gZWFjaCBjb25kaXRpb259CiMgQ29tcHV0ZSBtZWRpYW4gaW4gZWFjaCBjb25kaXRpb24KbGF0ZW5jeU1lZGlhbiA8LSBncm91cERhdGEgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzdGltdWxhdGlvbixsZWcsYmxvY2ssdHlwZSxkaXJlY3Rpb24pICU+JQogIHN1bW1hcmlzZShsYXRlbmN5ID0gbWVkaWFuKGxhdGVuY3kpKQpgYGAKCiMjIyBGdWxsIGZhY3RvcmlhbCBwbG90CgpgYGB7ciBGdWxsIGZhY3RvcmlhbCBwbG90LCBmaWcud2lkdGggPSA5fQojIFBsb3Qgb3V0IGFsbCB0aGUgZGF0YQpmdWxsUGxvdCA8LSBnZ3Bsb3QobGF0ZW5jeU1lZGlhbiwgYWVzKGludGVyYWN0aW9uKGJsb2NrLGxlZyksIGxhdGVuY3ksIGNvbG9yID0gc3RpbXVsYXRpb24sIHNoYXBlID0gc3RpbXVsYXRpb24pKSArCiAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNpemUgPSAzKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pLCBzaXplID0gMSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjIsIHZqdXN0ID0gLjUpKQpmdWxsUGxvdApgYGAKCkZvciBzb21lIHJlYXNvbiBjYXRob2RhbCBpcyBhbHdheXMgYSBsaXR0bGUgZmFzdGVyIHRoYW4gYW5vZGFsLiBUaGVyZSBpcyBwcm9iYWJseSBhIGZldyBtcyBkaWZmZXJlbmNlIGJldHdlZW4gdGhlbSBvbiBhdmVyYWdlLCBhbHNvIGluIHRoZSBiYXNlbGluZSBibG9jay4gVGhpcyBpcyBjbGVhcmx5IGp1c3QgcmFuZG9tIHZhcmlhdGlvbiwgYnV0IGl0IGNvdWxkIGJlIGEgcHJvYmxlbSwgc2luY2UgdGhlIGVmZmVjdHMgd2UgZXhwZWN0IGFyZSBub3QgbXVjaCBiaWdnZXIuLi4KClRoZSBhYm92ZSBwbG90IGFsc28gc2hvd3MgYSBsb3Qgb2YgdmFyaWFiaWxpdHksIHNvIGl0IG1pZ2h0IGJlIGJlc3QgdG8gYXZlcmFnZSBvdmVyIGVhY2ggMyBjb25zZWN1dGl2ZSBibG9ja3Mgc28gdGhlIGRhdGEgY29tZSBpbiAxNS1taW51dGUgaW50ZXJ2YWxzLgoKIyMgMTUtbWludXRlIGludGVydmFscyAoY29sbGFwc2UgMyBibG9ja3MpCgpgYGB7ciBDb21wdXRlIG1lZGlhbiwgY29sbGFwc2VkIGFjcm9zcyBibG9ja3N9CiMgQ29tcHV0ZSBtZWRpYW4gcGVyIGxlZwpsYXRlbmN5TWVkaWFuTGVnIDwtIGdyb3VwRGF0YSAlPiUKICBncm91cF9ieShzdWJqZWN0LHN0aW11bGF0aW9uLGRpcmVjdGlvbix0eXBlKSAlPiUgCiAgc3VtbWFyaXNlKGJhc2VsaW5lID0gbWVkaWFuKGxhdGVuY3lbbGVnID09ICJwcmUiXSksICMgdGFrZSBhdmVyYWdlIG9mIDMgYmxvY2tzLCBtYWtlIG5ldyBjb2x1bW4KICAgICAgICAgICAgdERDUyA9IG1lZGlhbihsYXRlbmN5W2xlZyA9PSAidERDUyJdKSwKICAgICAgICAgICAgcG9zdC4xID0gbWVkaWFuKGxhdGVuY3lbbGVnID09ICJwb3N0IiAmIGJsb2NrIDw9IDNdKSwKICAgICAgICAgICAgcG9zdC4yID0gbWVkaWFuKGxhdGVuY3lbbGVnID09ICJwb3N0IiAmIGJsb2NrID49IDRdKSkgJT4lCiBnYXRoZXIobGVnLGxhdGVuY3ksYmFzZWxpbmUsdERDUyxwb3N0LjEscG9zdC4yKSAlPiUgIyBnYXRoZXIgbmV3IGNvbHVtbnMgdG8gdXNlIGFzIGZhY3RvcgogbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC4xIiwgInBvc3QuMiIpKSkgIyByZW9yZGVyIGZhY3RvciBsZXZlbHMKYGBgCgojIyMgTGluZSBwbG90IHBlciBsZWcsIGluZGl2aWR1YWwgc3ViamVjdHMKCk5vdyBtYWtlIHRoZSBzYW1lIHBsb3QsIGJ1dCBmb3IgdGhlIGRhdGEgY29sbGFwc2VkIG92ZXIgMyBibG9ja3MuIEFsc28gZHJhdyB0aGUgcGxvdCBmb3IgZWFjaCBpbmRpdmlkdWFsIHN1YmplY3QsIHNvIHdlIGNhbiBzZWUgd2hpY2ggc3ViamVjdHMgZHJpdmUgdGhlIGJhc2VsaW5lIGRpZmZlcmVuY2UsIGFuZCBpbiB3aGljaCBkaXJlY3Rpb24gdGhlIHN0aW11bGF0aW9uIGVmZmVjdCBnb2VzIGZvciBlYWNoIHN1YmplY3QgKGlmIHRoZXJlIGlzIGFueSkuCgpgYGB7ciBMaW5lIHBsb3QgZm9yIGVhY2ggc3ViamVjdCwgZmlnLndpZHRoPTh9CmthbmFpU3Vic1Bsb3QgPC0gZ2dwbG90KGxhdGVuY3lNZWRpYW5MZWcsIGFlcyhsZWcsIGxhdGVuY3ksIGNvbG9yID0gc3RpbXVsYXRpb24sIHNoYXBlID0gdHlwZSkpICsgICAgICAgICAKICBmYWNldF93cmFwKH5zdWJqZWN0LCBuY29sID0gNSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaXplID0gMikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjIsIHZqdXN0ID0gLjUpKQprYW5haVN1YnNQbG90CmBgYAoKVGhlcmUgYXJlIGEgY291cGxlIG9mIHN1YmplY3RzIHRoYXQgc2hvdyBsYXJnZSBkaWZmZXJlbmNlcyBpbiB0aGUgYmFzZWxpbmUgYWxyZWFkeSwgZXNwZWNpYWxseSBTMDEuIFRoZSBzdGltdWxhdGlvbiBlZmZlY3RzIHNlZW0gdG8gbm90IGJlIHZlcnkgYXBwYXJlbnQsIGJ1dCB0aGV5IGNvdWxkIGFsc28gZHJvd24gb3V0IGF0IHRoaXMgc2NhbGUuCgojIyMgQ29tcHV0ZSBtYWduaXR1ZGUgb2YgYmFzZWxpbmUgZGlmZmVyZW5jZQoKTGV0J3MgbG9vayBhdCB0aGUgc2l6ZSBvZiB0aGUgYmFzZWxpbmUgZGlmZmVyZW5jZSBwZXIgc3ViamVjdC4gCgpgYGB7ciByZXN1bHRzID0gJ2FzaXMnfQpiYXNlbGluZURpZmYgPC0gbGF0ZW5jeU1lZGlhbkxlZyAlPiUgCiAgZmlsdGVyKGxlZyA9PSAiYmFzZWxpbmUiKSAlPiUgIyBrZWVwIG9ubHkgYmFzZWxpbmUgZGF0YQogIHNwcmVhZChzdGltdWxhdGlvbiwgbGF0ZW5jeSkgJT4lICMgbWFrZSBzZXBhcmF0ZSBjb2x1bW5zIGZvciBhbm9kYWwgYW5kIGNhdGhvZGFsCiAgbXV0YXRlKGxhdGVuY3kuZGlmZiA9IGFub2RhbCAtIGNhdGhvZGFsKSAlPiUgIyBzdWJ0cmFjdCB0aGUgZGlmZmVyZW5jZQogIGdyb3VwX2J5KHN1YmplY3QpICU+JSAKICBzdW1tYXJpc2UobGF0ZW5jeS5kaWZmID0gbWVhbihsYXRlbmN5LmRpZmYpKSMga2VlcCB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIHBlciBzdWJqZWN0CgprYWJsZShiYXNlbGluZURpZmYsIGNhcHRpb24gPSAnRGlmZmVyZW5jZSBiZXR3ZWVuIGJhc2VsaW5lIHNhY2NhZGUgbGF0ZW5jaWVzIGluIGFub2RhbCBhbmQgY2F0aG9kYWwgc2Vzc2lvbicpCmBgYAoKVGhlcmUgYXJlIGEgZmV3IHN1YmplY3RzIHdpdGggc3Vic3RhbnRpYWwgbGF0ZW5jeSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHNlc3Npb25zLCBzbyBpdCdzIHByb2JhYmx5IGEgZ29vZCBpZGVhIHRvIHN1YnRyYWN0IHRoZSBiYXNlbGluZSBmb3IgdGhlIHN0YXRpc3RpY2FsIGFuYWx5c2VzLiBUaGUgbWVhbiBkaWZmZXJlbmNlIGlzIGByIHJvdW5kKG1lYW4oYmFzZWxpbmVEaWZmJGxhdGVuY3kuZGlmZiksIGRpZ2l0cyA9IDEpYCBtcy4gU28gb24gYXZlcmFnZSwgdGhlIGNhdGhvZGFsIHNlc3Npb24gaXMgYSBsaXR0bGUgZmFzdGVyLCBzbyB0aGUgY291bnRlcmJhbGFuY2luZyBpcyBub3QgcGVyZmVjdCwgYnV0IHRoZSBkaWZmZXJlbmNlIGlzIG5vdCB2ZXJ5IGhpZ2guCgoKIyBNZWRpYW4gcmVhY3Rpb24gdGltZSBwbG90cyBhbmQgYW5hbHlzZXMKCkhlcmUgd2Ugc2ltcGx5IGV4dHJhY3QgbWVkaWFuIFJUcyBmb3IgZWFjaCBjb25kaXRpb24gYW5kIHVzZSBhIHJlcGVhdGVkIG1lYXN1cmVzIEFOT1ZBIGZvciBzdGF0aXN0aWNhbCBhbmFseXNpcywgZm9sbG93aW5nIFtLYW5haSBldCBhbC4gKDIwMTIpXShodHRwOi8vZHguZG9pLm9yZy8xMC4zMzg5L2Zwc3l0LjIwMTIuMDAwNDUpLgoKIyMgTGluZSBwbG90IHBlciBsZWcgb3ZlciBhbGwgc3ViamVjdHMKCkxldCdzIGxvb2sgYXQgdGhlIGdyb3VwIGF2ZXJhZ2UgcGxvdCBmb3IgdGhlIGZpcnN0IHRpbWUuCgpgYGB7ciBMaW5lIHBsb3QgcGVyIGxlZ30Ka2FuYWlQbG90IDwtIGdncGxvdChsYXRlbmN5TWVkaWFuTGVnLCBhZXMobGVnLCBsYXRlbmN5LCBjb2xvciA9IHN0aW11bGF0aW9uLCBzaGFwZSA9IHN0aW11bGF0aW9uKSkgKyAgICAgICAgIAogIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaXplID0gMykgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSwgc2l6ZSA9IDEpICsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCwgZ2VvbSA9ICJlcnJvcmJhciIsIHdpZHRoID0gMC4zKQprYW5haVBsb3QKYGBgCgpBbGwgZGlmZmVyZW5jZXMgYmV0d2VlbiBhbm9kYWwgJiBjYXRob2RhbCBzZWVtIHRvIGJlIDwgNSBtcy4gQW55IGRpZmZlcmVuY2VzIHRoYXQgYXJlIHRoZXJlIGFsc28gMSkgZG8gbm90IHNlZW0gdG8gZGlmZmVyIG11Y2ggYmV0d2VlbiB0aGUgdGltZSBibG9ja3MsIG9yIDIpIGJlIGluIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb24gZm9yIGFub2RhbCBhbmQgY2F0aG9kYWwsIHdpdGggdGhlIHBvc3NpYmxlIGV4Y2VwdGlvbiBvZiB0aGUgZmlyc3QgcG9zdC1ibG9jayBpbiB0aGUgY2VudGVyLXJpZ2h0IGNvbmRpdGlvbi4KCiMjIyBJbmRpdmlkdWFsIHN1YmplY3RzCgojIyMjIEFub2RhbCBzZXNzaW9uCgpMZXQncyBsb29rIGF0IHRoZSBzYW1lIHBsb3QgZm9yIGluZGl2aWR1YWwgc3ViamVjdHMsIHRvIHNlZSB3aGV0aGVyIHRoZXJlIGFyZSBhbnkgY29uc2lzdGVudCBwYXR0ZXJucyBvciBodWdlIG91dGxpZXJzIHRoZXJlCgpgYGB7ciBMaW5lIHBsb3QgcGVyIHN1YmplY3QgLSBhbm9kYWx9CmthbmFpUGxvdFN1YnNBbm9kYWwgPC0gZ2dwbG90KGxhdGVuY3lNZWRpYW5MZWdbbGF0ZW5jeU1lZGlhbkxlZyRzdGltdWxhdGlvbiA9PSAiYW5vZGFsIiwgXSwgYWVzKGxlZywgbGF0ZW5jeSkpICsKICBmYWNldF9ncmlkKHR5cGUgfiBkaXJlY3Rpb24pICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwPXN1YmplY3QsY29sb3I9c3ViamVjdCkpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBzdGltdWxhdGlvbiksIGdlb20gPSAibGluZSIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IikgKwogIGdndGl0bGUoIkFub2RhbCBzZXNzaW9uIikKa2FuYWlQbG90U3Vic0Fub2RhbApgYGAKClRoZXJlIGRvIGFwcGVhciB0byBiZSBzb21lICJvdXRsaWVycyIsIGJ1dCB0aGV5IGFyZSBmYWlybHkgd2VsbCBiYWxhbmNlZCAoYmVsb3cgb3IgYWJvdmUgdGhlIGF2ZXJhZ2UpLCBhbmQgPjgwJSBvciBzbyBvZiBzdWJqZWN0cyBzZWVtIHRvIGNsdXN0ZXIgdG9nZXRoZXIuIEkgZG9uJ3Qgc2VlIG11Y2ggZXZpZGVuY2UgZm9yIHN5c3RlbWF0aWMgaW5kaXZpZHVhbCBkaWZmZXJlbmNlcyAoZS5nLiBzbG93IHN1YmplY3RzIGdldCBmYXN0ZXI7IGZhc3Qgc3ViamVjdHMgZ2V0IHNsb3dlci4pCgojIyMjIENhdGhvZGFsIHNlc3Npb24KCmBgYHtyIExpbmUgcGxvdCBwZXIgc3ViamVjdCAtIGNhdGhvZGFsfQprYW5haVBsb3RTdWJzQ2F0aG9kYWwgPC0gZ2dwbG90KGxhdGVuY3lNZWRpYW5MZWdbbGF0ZW5jeU1lZGlhbkxlZyRzdGltdWxhdGlvbiA9PSAiY2F0aG9kYWwiLCBdLCBhZXMobGVnLCBsYXRlbmN5KSkgKwogIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogIGdlb21fbGluZShhZXMoZ3JvdXA9c3ViamVjdCxjb2xvcj1zdWJqZWN0KSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSwgZ2VvbSA9ICJsaW5lIikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiKSArCiAgZ2d0aXRsZSgiQ2F0aG9kYWwgc2Vzc2lvbiIpCmthbmFpUGxvdFN1YnNDYXRob2RhbApgYGAKClRoZXJlIHNlZW0gdG8gYmUgbGVzcyBjbGVhciBpbmRpdmlkdWFsIG91dGxpZXJzLCBidXQgdGhlIHNwcmVhZCBhbHNvIHNlZW1zIGEgYml0IGJpZ2dlciAoZS5nLiByaWdodC1sYXRlcmFsKQoKIyMgU3VidHJhY3QgYmFzZWxpbmUKCkJhc2VsaW5lIGRpZmZlcmVuY2VzICh3aGlsZSBzbWFsbCBoZXJlKSBhcmUgbm90IGluZm9ybWF0aXZlIGFuZCBjb3VsZCBvYnNjdXJlIHJlYWwgY2hhbmdlcyBmcm9tIGJhc2VsaW5lIHdpdGhpbiBzdWJqZWN0cy4gQWxzbyBpdCdzIGhhcmQgdG8gc2VlIGFuZCBjb21wYXJlIHRoZSBtYWduaXR1ZGUgb2YgdGhlIGVmZmVjdHMsIGFsc28gZm9yIGluc3RhbmNlIGJlY2F1c2UgY2VudGVyIHNhY2NhZGVzIGFyZSBtdWNoIGZhc3RlciB0aGFuIGxhdGVyYWwgc2FjY2FkZXMuIFRoZXJlZm9yZSwgc3VidHJhY3QgdGhlIGJhc2VsaW5lIGZyb20gZWFjaCBzdWJzZXF1ZW50IG1lYXN1cmVtZW50LgoKYGBge3IgU3VidHJhY3QgYmFzZWxpbmV9CmxhdGVuY3lNZWRpYW5CYXNlbGluZSA8LSBsYXRlbmN5TWVkaWFuTGVnICU+JQogIGdyb3VwX2J5KHN1YmplY3Qsc3RpbXVsYXRpb24sZGlyZWN0aW9uLHR5cGUpICU+JSAjIGZvciBlYWNoIGNvbmRpdGlvbiwgc3VidHJhY3QgYmFzZWxpbmUgc2NvcmVzIGFuZCBtYWtlIG5ldyBjb2x1bW5zCiAgc3VtbWFyaXNlKHREQ1MgPSBsYXRlbmN5W2xlZyA9PSAidERDUyJdIC0gbGF0ZW5jeVtsZWcgPT0gImJhc2VsaW5lIl0sIAogICAgICAgICAgIHBvc3QuMSA9IGxhdGVuY3lbbGVnID09ICJwb3N0LjEiXSAtIGxhdGVuY3lbbGVnID09ICJiYXNlbGluZSJdLAogICAgICAgICAgIHBvc3QuMiA9IGxhdGVuY3lbbGVnID09ICJwb3N0LjIiXSAtIGxhdGVuY3lbbGVnID09ICJiYXNlbGluZSJdKSAlPiUKICBnYXRoZXIobGVnLCBsYXRlbmN5LCB0RENTLCBwb3N0LjEsIHBvc3QuMikgICU+JSAjIGdhdGhlciBuZXcgY29sdW1ucyB0byB1c2UgYXMgZmFjdG9yIAogIG11dGF0ZShsZWcgPSBmYWN0b3IobGVnLCBsZXZlbHMgPSBjKCJ0RENTIiwgInBvc3QuMSIsICJwb3N0LjIiKSkpICMgcmVvcmRlciBmYWN0b3IgbGV2ZWxzCmBgYAoKIyMjIEJhc2VsaW5lIGRhdGEKCkJlZm9yZSB3ZSBsb29rIGF0IHRoZSBjaGFuZ2UtZnJvbS1iYXNlbGluZSBkYXRhLCBpdCB3b3VsZCBiZSBnb29kIHRvIGNoZWNrIHRoZSBiYXNlbGluZSBkYXRhIGl0c2VsZi4KCiMjIyMgQmFzZWxpbmUgcmVsaWFiaWxpdHkKCkFuYWx5emluZyBjaGFuZ2UtZnJvbS1iYXNlbGluZSBvbmx5IG1ha2VzIHNlbnNlIGlmIHRoZSBiYXNlbGluZSBkYXRhIGFyZSBub3QgdmVyeSBub2lzeS4gU3VidHJhY3RpbmcgYSBub2lzeSBtZWFzdXJlIGZyb20gdGhlIGRhdGEgd2lsbCBpbmNyZWFzZSB0aGUgbm9pc2UgaW4gdGhlIGRhdGEsIGFuZCB0aGVyZWJ5IFtyZWR1Y2UgcG93ZXJdKGh0dHA6Ly9kYXRhY29sYWRhLm9yZy8zOSkuIE9uZSB3YXkgdG8gYXNzZXNzIHRoaXMgaXMgdG8gbG9vayBhdCB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgYmFzZWxpbmUgYmxvY2tzIGluIGJvdGggc2Vzc2lvbnMuIElmIHRoZXJlIGlzIGEgaGlnaCBjb3JyZWxhdGlvbiwgdGhlIHByby1zYWNjYWRlIHRhc2sgcHJvZHVjZXMgY29tcGFyYWJsZSBsYXRlbmNpZXMgZWFjaCB0aW1lIGl0IGlzIHBlcmZvcm1lZCwgYW5kIHRodXMgdGhlIGJhc2VsaW5lIGRhdGEgc2hvdWxkIG9uIGF2ZXJhZ2Ugbm90IGJlIHZlcnkgbm9pc3kuCgpMZXQncyBjb21wdXRlIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGFsbCBiYXNlbGluZXMgKGkuZS4gZm9yIHRoZSBmYWN0b3JzIERJUkVDVElPTiBhbmQgVFlQRSkuCgpgYGB7ciBiYXNlbGluZSBjb3JyZWxhdGlvbnN9CmJhc2VsaW5lQ29yciA8LSBsYXRlbmN5TWVkaWFuTGVnICU+JQogIGZpbHRlcihsZWcgPT0gImJhc2VsaW5lIikgJT4lICMga2VlcCBvbmx5IGJhc2VsaW5lIGRhdGEKICBncm91cF9ieShkaXJlY3Rpb24sdHlwZSkgJT4lICMgZm9yIGVhY2ggb2YgdGhlc2UgNCBwYWlycwogIHNwcmVhZChzdGltdWxhdGlvbixsYXRlbmN5KSAlPiUgIyBtYWtlIDIgY29sdW1ucyB3aXRoIGJhc2VsaW5lIGxhdGVuY2llcyBvZiBhbm9kYWwgYW5kIGNhdGhvZGFsIHNlc3Npb24KICBuZXN0KCkgJT4lICMgY3JlYXRlIGEgc2VwYXJhdGUgZGF0YSBmcmFtZSBvZiBhbGwgcmVtYWluaW5nIGNvbHVtbnMuIFRoZXNlIGRhdGEgZnJhbWVzIGFyZSBzdG9yZWQgaW4gYSBsaXN0LWNvbHVtbiBuYW1lZCAiZGF0YSIKICBtdXRhdGUoc3RhdHMgPSBtYXAoZGF0YSwgfmNvci50ZXN0KGZvcm11bGEgPSB+IGFub2RhbCArIGNhdGhvZGFsLCBkYXRhID0uKSkpICU+JSAjIHJ1biBjb3JyZWxhdGlvbiB0ZXN0IG9uIGJhc2VsaW5lcyBmcm9tIGVhY2ggY29uZGl0aW9uCiAgbXV0YXRlKHRpZHlfbW9kZWwgPSBtYXAoc3RhdHMsIHRpZHkpKSAlPiUgIyBmb3JjZSB0aGUgZm91ciB0ZXN0IG91dHB1dHMgdG8gYWxzbyBiZSBkYXRhIGZyYW1lcyBpbiBhIGxpc3QgY29sdW1uICgidGlkeV9tb2RlbCIpCiAgdW5uZXN0KHRpZHlfbW9kZWwsIC5kcm9wID0gVFJVRSkgICMgdW5wYWNrIHRoZSBsaXN0LWNvbHVtbiB3aXRoIHJlc3VsdHMsIGRyb3AgdGhlIGxpc3QtY29sdW1uIHdlIHVzZWQgdG8gb3JnYW5pemUgdGhlIGRhdGEKYGBgCgpOb3cgYSBzY2F0dGVyIHBsb3Qgb2YgdGhlIGRhdGEsIHdpdGggdGhlIHJlc3VsdHMgb2YgdGhlIHRlc3Q6CgpgYGB7ciBiYXNlbGluZSBzY2F0dGVycGxvdHN9CmxhdGVuY3lNZWRpYW5MZWcgJT4lCiAgZmlsdGVyKGxlZyA9PSAiYmFzZWxpbmUiKSAlPiUKICBzcHJlYWQoc3RpbXVsYXRpb24sbGF0ZW5jeSkgJT4lCiAgaW5uZXJfam9pbiguLCBzdWJqZWN0RGF0YVsgLGMoInN1YmplY3QiLCJzZXNzaW9uLm9yZGVyIildLCBieSA9IGMoInN1YmplY3QiKSkgJT4lICMgYWRkIGNvbHVtbiBvbiBzZXNzaW9uIG9yZGVyIGZyb20gb3RoZXIgZGF0YSBmcmFtZQogIGdncGxvdChhZXMoYW5vZGFsLGNhdGhvZGFsKSkgKwogICAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICAgIGdlb21fcG9pbnQoYWVzKGNvbG9yPXNlc3Npb24ub3JkZXIpKSArCiAgICB4bGltKDgwLDIyMCkgKyB5bGltKDgwLDIyMCkgKwogICAgZ2VvbV90ZXh0KGRhdGEgPSBiYXNlbGluZUNvcnIsIHggPSAxMDAsIHkgPSAyMDAsIGFlcyhsYWJlbCA9IHBhc3RlKCJpdGFsaWMocikgPT0gIiwgcm91bmQoZXN0aW1hdGUsMikpKSwgcGFyc2UgPSBUUlVFKSArCiAgICBsYWJzKHRpdGxlID0gIkJhc2VsaW5lIGluIGFub2RhbCBhbmQgY2F0aG9kYWwgc2Vzc2lvbnMiLCBzdWJ0aXRsZSA9ICJzY2F0dGVycGxvdCBvZiBiYXNlbGluZSBsYXRlbmNpZXMiKQpgYGAKClRoZSBjb3JyZWxhdGlvbnMgYXJlIHF1aXRlIGhpZ2gsIGF0IGxlYXN0IGhpZ2ggZW5vdWdoIGZvciB0aGUgYmFzZWxpbmUgc3VidHJhY3Rpb24gdG8gaGVscCBwb3dlciByYXRoZXIgdGhhbiBodXJ0IChyJ3MgPiAwLjUpLgoKVGhlcmUgYXJlIGEgZmV3IG91dGxpZXJzIHRob3VnaDogc29tZSBzdWJqZWN0cyBkZXZpYXRlIHF1aXRlIGEgYml0IGZyb20gdGhlIGlkZWFsaXplZCBsaW5lIChkYXNoZWQpLgoKV2hlbiB0aGUgZGF0YSBpcyBzcGxpdCBmb3Igc2Vzc2lvbiBvcmRlciwgYSBjbGVhciBwYXR0ZXJuIGJlY29tZXMgYXBwYXJlbnQ6IGxhdGVuY2llcyBhcmUgZ2VuZXJhbGx5IGZhc3RlciBpbiB0aGUgMm5kIHNlc3Npb24gKGZvciB0aG9zZSB3aG8gZ290IGNhdGhvZGFsIGZpcnN0LCBhcmUgYWJvdmUgdGhlIGRpYWdvbmFsLCBtZWFuaW5nIGFub2RhbCA8IGNhdGhvZGFsLiBUaGUgcmV2ZXJzZSBwYXR0ZXJuIGlzIHZpc2libGUgZm9yIHRob3NlIHdobyByZWNlaXZlZCBhbm9kYWwgZmlyc3QpLiBTbyBpbiB0aGF0IHNlbnNlIHRoZXJlIGlzIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIHR3byBncm91cHMgb2Ygc3ViamVjdHMuCgojIyMjIEJhc2VsaW5lIGRpZmZlcmVuY2VzCgpJZiB0aGUgcHJvc2FjY2FkZSB0YXNrIGlzIGluZGVlZCByZWxpYWJsZSwgdGhlcmUgc2hvdWxkbid0IGJlIGFueSBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBhdCB0aGUgZ3JvdXAtbGV2ZWwgYmV0d2VlbiB0aGUgYmFzZWxpbmUgYmxvY2tzIG9mIGJvdGggc2Vzc2lvbnMuIElmIHRoZXJlIGFyZSwgdGhpcyBtYXkgYmUgcHJvYmxlbWF0aWMsIGJlY2F1c2UgYWxsIHRoZSBjaGFuZ2Utc2NvcmVzIGFyZSBleHByZXNzZWQgcmVsYXRpdmUgdG8gdGhlIGJhc2VsaW5lLiBBIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYmV0d2VlbiB0d28gY29uZGl0aW9ucyBpbiBsYXRlciBibG9ja3MgY291bGQgdGhlbiBiZSBkcml2ZW4gYnkgdGhlIGRpZmZlcmVuY2VzIHRoYXQgYWxyZWFkeSBvY2N1ciBpbiB0aGUgYmFzZWxpbmUuCgpMZXQncyBwbG90IHRoZSBiYXNlbGluZSBzY29yZXMgaW4gZWFjaCBzZXNzaW9uIGZvciBlYWNoIHN1YmplY3Q6CgpgYGB7ciBiYXNlbGluZSBsaW5rZWQgc3RyaXBjaGFydH0KbGF0ZW5jeU1lZGlhbkxlZyAlPiUKICBmaWx0ZXIobGVnID09ICJiYXNlbGluZSIpICU+JQogIGdncGxvdChhZXMoc3RpbXVsYXRpb24sIGxhdGVuY3kpKSArCiAgICBmYWNldF9ncmlkKHR5cGUgfiBkaXJlY3Rpb24pICsKICAgIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IDEpLCBzaXplID0gMS41KSArCiAgICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gc3ViamVjdCwgY29sb3VyID0gc3ViamVjdCksIGFscGhhID0gMC41LCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4xKSkgKwogICAgbGFicyh0aXRsZSA9ICJCYXNlbGluZSBpbiBhbm9kYWwgYW5kIGNhdGhvZGFsIHNlc3Npb25zIiwgc3VidGl0bGUgPSAibGlua2VkIHN0cmlwY2hhcnQgb2YgYmFzZWxpbmUgbGF0ZW5jaWVzIikKYGBgCgpNb3N0IGxpbmVzIGFwcGVhciBmYWlybHkgZmxhdC4gSG93ZXZlciwgdGhlcmUgaXMgcXVpdGUgc29tZSB2YXJpYWJpbGl0eSBhcm91bmQgdGhlIG1lYW4sIGFuZCBzb21lIHN1YmplY3RzIHNob3cgcXVpdGUgYSBzdGVlcCBkaWZmZXJlbmNlLiBUaGVyZSBhcHBlYXJzIHRvIGJlIHNvbWUgc29ydCBvZiByZWdyZXNzaW9uIHRvIHRoZSBtZWFuIGFsc286IGV4dHJlbWUgc2NvcmVzIGluIGVpdGhlciBzZXNzaW9uIHNob3cgYSBzdGVlcGVyIHNsb3BlIHRoYW4gdGhvc2Ugc2NvcmVzIHRoYXQgYXJlIGxlc3MgZXh0cmVtZS4KCkxldCdzIGxvb2sgYXQgdGhlIHBhaXJ3aXNlIGRpZmZlcmVuY2VzIGluIG1vcmUgZGV0YWlsOgoKYGBge3IgYmFzZWxpbmUgZGlmZmVyZW5jZSBzdHJpcGNoYXJ0fQpsYXRlbmN5TWVkaWFuTGVnICU+JQogIGZpbHRlcihsZWcgPT0gImJhc2VsaW5lIikgJT4lCiAgaW5uZXJfam9pbiguLCBzdWJqZWN0RGF0YVsgLGMoInN1YmplY3QiLCJzZXNzaW9uLm9yZGVyIildLCBieSA9IGMoInN1YmplY3QiKSkgJT4lICMgYWRkIGNvbHVtbiBvbiBzZXNzaW9uIG9yZGVyIGZyb20gb3RoZXIgZGF0YSBmcmFtZQogIGdyb3VwX2J5KHN1YmplY3QsZGlyZWN0aW9uLHR5cGUsc2Vzc2lvbi5vcmRlcikgJT4lCiAgc3VtbWFyaXNlKGxhdGVuY3kuZGlmZiA9IGxhdGVuY3lbc3RpbXVsYXRpb24gPT0gImFub2RhbCJdIC0gbGF0ZW5jeVtzdGltdWxhdGlvbiA9PSAiY2F0aG9kYWwiXSkgJT4lCiAgZ2dwbG90KGFlcyhmYWN0b3IoMCksIGxhdGVuY3kuZGlmZikpICsKICAgIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ub3JtYWwpICsKICAgIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhsYWJlbD1yb3VuZCguLnkuLiwgZGlnaXRzPTIpLCB4ID0gMS4zKSwgZ2VvbSA9ICJsYWJlbCIsIGFscGhhID0gMC41KSArCiAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGFlcyhjb2xvdXIgPSBzZXNzaW9uLm9yZGVyKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGg9LjEpKSArCiAgICBsYWJzKHRpdGxlID0gIkJhc2VsaW5lIGluIGFub2RhbCBhbmQgY2F0aG9kYWwgc2Vzc2lvbnMiLCBzdWJ0aXRsZSA9ICJhbm9kYWwgLSBjYXRob2RhbCIpCmBgYAoKVGhlIHNlcXVlbmNlIGVmZmVjdCB3ZSBvYnNlcnZlZCBlYXJsaWVyIGlzIHZlcnkgY2xlYXIgd2hlbiB3ZSBzcGxpdCB0aGUgZGF0YSBieSBzZXNzaW9uIG9yZGVyIGFnYWluLCBwYXJ0aWN1bGFybHkgaW4gdGhlIGxhdGVyYWwgY29uZGl0aW9uIChpLmUuIGxhdGVuY2llcyBhcmUgYWx3YXlzIGZhc3RlciBpbiB0aGUgMm5kIHNlc3Npb24pLgoKU29tZXdoYXQgd29ycnlpbmdseSwgdGhlIGJhc2VsaW5lIGRpZmZlcmVuY2VzIGFyZSBpbiB0aGUgcmFuZ2Ugb2YgdGhlIHREQ1MgZWZmZWN0IHNpemUgd2UgZXhwZWN0LCBwYXJ0aWN1bGFybHkgaW4gdGhlIGNlbnRlciBjb25kaXRpb24uIFRoYXQgc2FpZCwgdGhlIGRpZmZlcmVuY2VzIGRvIGNsdXN0ZXIgYXJvdW5kIDAsIHRoZXJlIGFyZSByZWFsbHkgb25seSBhIGZldyBzdWJqZWN0cyB0aGF0IGZhbGwgZmFyIG91dHNpZGUgdGhlIGJvdW5kYXJ5IChvbmUgaXMgcmVhbGx5IGV4dHJlbWUpLiAKClRoZSBDSXMgYXBwZWFyIHRvIG92ZXJsYXAgd2l0aCAwIHRob3VnaCwgc28gdGhlIGRpZmZlcmVuY2VzIHNob3VsZG4ndCBiZSBzaWduaWZpY2FudC4gTGV0J3MgdGVzdCB0aGF0OgoKYGBge3IgdC10ZXN0cyBvZiBiYXNlbGluZSBkaWZmZXJlbmNlfQpsYXRlbmN5TWVkaWFuTGVnICU+JQogIGZpbHRlcihsZWcgPT0gImJhc2VsaW5lIikgJT4lCiAgZ3JvdXBfYnkoZGlyZWN0aW9uLHR5cGUpICU+JSAjIGZvciBlYWNoIG9mIHRoZXNlIDQgcGFpcnMKICBuZXN0KCkgJT4lICMgY3JlYXRlIGEgc2VwYXJhdGUgZGF0YSBmcmFtZSBvZiBhbGwgcmVtYWluaW5nIGNvbHVtbnMuIFRoZXNlIGRhdGEgZnJhbWVzIGFyZSBzdG9yZWQgaW4gYSBsaXN0LWNvbHVtbiBuYW1lZCAiZGF0YSIKICBtdXRhdGUoc3RhdHMgPSBtYXAoZGF0YSwgfnQudGVzdChmb3JtdWxhID0gbGF0ZW5jeX5zdGltdWxhdGlvbiwgcGFpcmVkID0gVFJVRSwgZGF0YSA9LikpKSAlPiUgIyBydW4gdC10ZXN0IG9uIHRoZSBkYXRhIGZyYW1lcwogIG11dGF0ZSh0aWR5X21vZGVsID0gbWFwKHN0YXRzLCB0aWR5KSkgJT4lICMgZm9yY2UgdGhlIGZvdXIgdGVzdCBvdXRwdXRzIHRvIGFsc28gYmUgZGF0YSBmcmFtZXMgaW4gYSBsaXN0IGNvbHVtbiAoInRpZHlfbW9kZWwiKQogIHVubmVzdCh0aWR5X21vZGVsLCAuZHJvcCA9IFRSVUUpICU+JSAjIHVucGFjayB0aGUgbGlzdC1jb2x1bW4gd2l0aCByZXN1bHRzLCBkcm9wIHRoZSBsaXN0LWNvbHVtbiB3ZSB1c2VkIHRvIG9yZ2FuaXplIHRoZSBkYXRhCiAga2FibGUoLikKYGBgCgpJbmRlZWQsIHRoZXkgYXJlIG5vdCwgYWx0aG91Z2ggdGhlIGNlbnRlciBjb25kaXRpb25zIGNvbWUgY2xvc2UuCgojIyMgTGluZSBwbG90cyBwZXIgbGVnIGZyb20gYmFzZWxpbmUKCmBgYHtyIExpbmUgcGxvdCBmcm9tIGJhc2VsaW5lfQprYW5haVBsb3RCYXNlIDwtIGdncGxvdChsYXRlbmN5TWVkaWFuQmFzZWxpbmUsIGFlcyhsZWcsIGxhdGVuY3ksIGNvbG9yID0gc3RpbXVsYXRpb24sIHNoYXBlID0gc3RpbXVsYXRpb24pKSArICAgICAgICAgCiAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaXplID0gMykgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSwgc2l6ZSA9IDEpICsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCwgZ2VvbSA9ICJlcnJvcmJhciIsIHdpZHRoID0gMC4zKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0xMCwxMCkpCmthbmFpUGxvdEJhc2UKYGBgCgpHZW5lcmFsbHkgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHN0aW11bGF0aW9uIGNvbmRpdGlvbnMgYXJlIHNtYWxsICg8IDQgbXMpLiBFeGNlcHQgZm9yIHRoZSBjZW50ZXItbGVmdCBjb25kaXRpb24sIGJ1dCB0aGlzIGNvbmRpdGlvbiBhbHNvIGhhZCB0aGUgbGFyZ2VzdCBiYXNlbGluZSBkaWZmZXJlbmNlLi4uCgojIyMgSW5kaXZpZHVhbCBzdWJqZWN0cwoKIyMjIyBBbm9kYWwgc2Vzc2lvbgoKYGBge3IgTGluZSBwbG90IGZyb20gYmFzZWxpbmUgcGVyIHN1YmplY3QgLSBhbm9kYWx9CmthbmFpUGxvdEJhc2VTdWJzQW5vZGFsIDwtIGdncGxvdChsYXRlbmN5TWVkaWFuQmFzZWxpbmVbbGF0ZW5jeU1lZGlhbkJhc2VsaW5lJHN0aW11bGF0aW9uID09ICJhbm9kYWwiLCBdLCBhZXMobGVnLCBsYXRlbmN5KSkgKwogIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwPXN1YmplY3QsY29sb3I9c3ViamVjdCkpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBzdGltdWxhdGlvbiksIGdlb20gPSAibGluZSIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IikgKyAKICBnZ3RpdGxlKCJBbm9kYWwgZGlmZmVyZW5jZSBmcm9tIGJhc2VsaW5lIikKa2FuYWlQbG90QmFzZVN1YnNBbm9kYWwKYGBgCgojIyMjIENhdGhvZGFsIHNlc3Npb24KCmBgYHtyIExpbmUgcGxvdCBmcm9tIGJhc2VsaW5lIHBlciBzdWJqZWN0IC0gY2F0aG9kYWx9CmthbmFpUGxvdEJhc2VTdWJzQ2F0aG9kYWwgPC0gZ2dwbG90KGxhdGVuY3lNZWRpYW5CYXNlbGluZVtsYXRlbmN5TWVkaWFuQmFzZWxpbmUkc3RpbXVsYXRpb24gPT0gImNhdGhvZGFsIiwgXSwgYWVzKGxlZywgbGF0ZW5jeSkpICsKICBmYWNldF9ncmlkKHR5cGUgfiBkaXJlY3Rpb24pICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cD1zdWJqZWN0LGNvbG9yPXN1YmplY3QpKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pLCBnZW9tID0gImxpbmUiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIpICsgCiAgZ2d0aXRsZSgiQ2F0aG9kYWwgZGlmZmVyZW5jZSBmcm9tIGJhc2VsaW5lIikKa2FuYWlQbG90QmFzZVN1YnNDYXRob2RhbApgYGAKCkFsbCBvZiB0aGlzIGlzIHNwbGl0IHByZXR0eSBtdWNoIDUwLTUwLCBoZW5jZSB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIGhvdmVyaW5nIGFyb3VuZCAwLgoKIyMjIENvbnRyYWxhdGVyYWwgc2FjY2FkZXMgaW4gdGhlIGFub2RhbCBzZXNzaW9uCgpbS2FuYWkgZXQgYWwuICgyMDEyKV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMzM4OS9mcHN5dC4yMDEyLjAwMDQ1KSBzcGVjaWZpY2FsbHkgZm91bmQgYW4gZWZmZWN0IG9mIF9hbm9kYWxfIHREQ1Mgb24gdGhlIGxhdGVuY3kgY2hhbmdlcyBpbiBfY29udHJhbGF0ZXJhbF8gKGhlcmU6IGxlZnQpIF9sYXRlcmFsXyBzYWNjYWRlcy4gTGV0J3MgZXhhbWluZSB0aGUgcmF3IG51bWJlcnMgaGVyZToKCmBgYHtyIEFub2RhbCBsZWZ0IGxhdGVyYWwgc2FjY2FkZXN9CmxhdGVuY3lNZWRpYW5CYXNlbGluZSAlPiUKICBmaWx0ZXIodHlwZSA9PSAibGF0ZXJhbCIsIHN0aW11bGF0aW9uID09ICJhbm9kYWwiLCBkaXJlY3Rpb24gPT0gImxlZnQiKSAlPiUKICBncm91cF9ieShsZWcpICU+JQogIHN1bW1hcmlzZV9hdCh2YXJzKGxhdGVuY3kpLCBmdW5zKG1lYW4sIHNkKSkgJT4lCiAga2FibGUoLikKYGBgCgpUaGVzZSBjaGFuZ2VzIGFyZSBhbGwgPCAxIG1zIGFuZCBoaWdobHkgdmFyaWFibGUsIHNvIGl0IHNlZW1zIHRoZXJlJ3MgdHJ1bHkgbm90aGluZyB0aGVyZS4uLgoKIyBTdGF0aXN0aWNzCgpgYGB7ciBQcmVwYXJlIGRhdGEgZnJhbWVzfQojIE1ha2UgInN1YmplY3QiIGEgZmFjdG9yLCBzbyB3ZSBjYW4gbW9kZWwgdGhlIHJlcGVhdGVkIG1lYXN1cmVzCmxhdGVuY3lNZWRpYW5CYXNlbGluZSA8LSBsYXRlbmN5TWVkaWFuQmFzZWxpbmUgJT4lCiAgdW5ncm91cCgpICU+JSAjIHJlbW92ZSBncm91cGluZyBpbmZvLCBiZWNhdXNlIHdlIG5lZWQgdG8gcmVmYWN0b3IKICBpbm5lcl9qb2luKC4sIHN1YmplY3REYXRhWyAsYygic3ViamVjdCIsInNlc3Npb24ub3JkZXIiKV0sIGJ5ID0gYygic3ViamVjdCIpKSAlPiUgIyBhZGQgY29sdW1uIGZyb20gb24gc2Vzc2lvbiBvcmRlciBmcm9tIG90aGVyIGRhdGEgZnJhbWUKICBtdXRhdGUoc3ViamVjdCA9IGZhY3RvcihzdWJqZWN0KSkgIyByZWZhY3RvcgoKbGF0ZW5jeU1lZGlhbkxlZyA8LSBsYXRlbmN5TWVkaWFuTGVnICU+JQogIHVuZ3JvdXAoKSAlPiUKICBpbm5lcl9qb2luKC4sIHN1YmplY3REYXRhWyAsYygic3ViamVjdCIsInNlc3Npb24ub3JkZXIiKV0sIGJ5ID0gYygic3ViamVjdCIpKSAlPiUgIyBhZGQgY29sdW1uIGZyb20gb24gc2Vzc2lvbiBvcmRlciBmcm9tIG90aGVyIGRhdGEgZnJhbWUKICBtdXRhdGUoc3ViamVjdCA9IGZhY3RvcihzdWJqZWN0KSkKYGBgCgojIyBGcmVxdWVudGlzdCAKCiMjIyBPbW5pYnVzIGFub3ZhIC0gc2FjY2FkZSBsYXRlbmN5CgpfX0RhdGFfXzogT3V0bGllciB0cmlhbHMgcmVtb3ZlZCwgY29sbGFwc2VkIGludG8gMTUtbWludXRlIGludGVydmFscy4gCgpfX0RlcGVuZGVudCBtZWFzdXJlX186IHNhY2NhZGljIGxhdGVuY3kKCl9fRmFjdG9yc19fOgoKKiBTVElNVUxBVElPTiAoYW5vZGFsIHZzLiBjYXRob2RhbCkKKiBMRUcgKGJhc2VsaW5lLCB0RENTLCBwb3N0LjEsIHBvc3QuMikKKiBUWVBFIChsYXRlcmFsIHZzLiBjZW50ZXIpCiogRElSRUNUSU9OIChsZWZ0IHZzLiByaWdodCkKCmBgYHtyIE9tbmlidXMgQU5PVkEsIHJlc3VsdHM9J2FzaXMnfQptb2RlbE9tbmkgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShsYXRlbmN5TWVkaWFuTGVnKSwgIyBSZXBlYXRlZCBvdmVyIHN1YmplY3RzOyB0eXBlIDMgc3VtcyBvZiBzcXVhcmVzIChjZi4gU1BTUykKICAgICAgICAgICAgICAgICAgICAgICAgZHYgPSAuKGxhdGVuY3kpLCB3aWQgPSAuKHN1YmplY3QpLCB3aXRoaW4gPSAuKHN0aW11bGF0aW9uLCBsZWcsIHR5cGUsIGRpcmVjdGlvbiksIHR5cGUgPSAzKQprYWJsZShtb2RlbE9tbmkkQU5PVkEpCmthYmxlKG1vZGVsT21uaSRgTWF1Y2hseSdzIFRlc3QgZm9yIFNwaGVyaWNpdHlgKQprYWJsZShtb2RlbE9tbmkkYFNwaGVyaWNpdHkgQ29ycmVjdGlvbnNgKQpgYGAKCiMjIyMgTWFpbiBlZmZlY3Q6IHR5cGUKCmBgYHtyIE9tbmkgTWFpbiBlZmZlY3Qgb2YgdHlwZX0KbGF0ZW5jeU1lZGlhbkxlZyAlPiUKICBncm91cF9ieShzdWJqZWN0LHR5cGUpICU+JQogIHN1bW1hcmlzZShsYXRlbmN5ID0gbWVhbihsYXRlbmN5KSkgJT4lCiAgZ2dwbG90KGFlcyh0eXBlLCBsYXRlbmN5KSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfbm9ybWFsLCBzaXplID0gMSkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4yNSkKYGBgCgpUaGlzIHNpbXBseSByZWZsZWN0cyB0aGF0IGNlbnRlciBzYWNjYWRlcyBhcmUgZmFzdGVyIHRoYW4gbGF0ZXJhbCBzYWNjYWRlcywgYmVjYXVzZSB0aGUgbG9jYXRpb24gb2YgdGhlIHRhcmdldCBpcyBrbm93bi4KCiMjIyMgSW50ZXJhY3Rpb246IGxlZyBieSB0eXBlCgpgYGB7ciBPbW5pIEludGVyYWN0aW9uIGxlZyBieSB0eXBlfQpsYXRlbmN5TWVkaWFuTGVnICU+JQogIGdyb3VwX2J5KHN1YmplY3QsbGVnLHR5cGUpICU+JQogIHN1bW1hcmlzZShsYXRlbmN5ID0gbWVhbihsYXRlbmN5KSkgJT4lCiAgZ2dwbG90KGFlcyhsZWcsIGxhdGVuY3ksIHNoYXBlID0gdHlwZSkpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IHR5cGUsIGxpbmV0eXBlID0gdHlwZSkpCmBgYAoKVGhlIGVmZmVjdCBvZiBUeXBlIGNoYW5nZXMgb3ZlciB0aW1lOiBsYXRlcmFsIHNhY2NhZGVzIHN0ZWFkaWx5IGJlY29tZSBzbG93ZXI7IGNlbnRlciBzYWNjYWRlcyB2YXJ5IG1vcmUgcmFuZG9tbHkuCgojIyMjIEludGVyYWN0aW9uOiBsZWcgYnkgdHlwZSBieSBkaXJlY3Rpb24KCmBgYHtyIE9tbmkgSW50ZXJhY3Rpb24gbGVnIGJ5IHR5cGUgYnkgZGlyZWN0aW9ufQpsYXRlbmN5TWVkaWFuTGVnICU+JQogIGdyb3VwX2J5KHN1YmplY3QsbGVnLHR5cGUsZGlyZWN0aW9uKSAlPiUKICBzdW1tYXJpc2UobGF0ZW5jeSA9IG1lYW4obGF0ZW5jeSkpICU+JQogIGdncGxvdChhZXMobGVnLCBsYXRlbmN5LCBzaGFwZSA9IHR5cGUpKSArCiAgZmFjZXRfd3JhcCh+ZGlyZWN0aW9uKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gImxpbmUiLCBhZXMoZ3JvdXAgPSB0eXBlLCBsaW5ldHlwZSA9IHR5cGUpKQpgYGAKClRoZSBlZmZlY3Qgb3ZlciB0aW1lIGxvb2tzIG5vbi1saW5lYXIgZm9yIGxlZnQtY2VudGVyIHNhY2NhZGVzLiBUaGUgInREQ1MiIGJsb2NrIGlzIHRoZSBkZXZpYW50IGhlcmUsIGJ1dCB0aGVyZSBpcyBubyBpbnRlcmFjdGlvbiB3aXRoIHN0aW11bGF0aW9uLgoKQWxzbywgZm9yIHJpZ2h0LWxhdGVyYWwgc2FjY2FkZXMsIHRoZXJlIGlzIGEgYmlnIGNoYW5nZSB0aGF0IG9ubHkgZW1lcmdlcyBpbiB0aGUgMm5kIHBvc3QtYmxvY2suCgojIyMgQU5PVkEgbWF0Y2hpbmcgS2FuYWkgZXQgYWwuICgyMDEyKSAtIGxhdGVyYWwgc2FjY2FkZXMgey50YWJzZXQgLnRhYnNldC1mYWRlfQoKIyMjIyBXaXRob3V0IHNlc3Npb24gb3JkZXIKCkRpZmZlcmluZyBmcm9tIHRoZSBwcmV2aW91cyBvbW5pYnVzIGFuYWx5c2lzLCBbS2FuYWkgZXQgYWwuICgyMDEyKV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMzM4OS9mcHN5dC4yMDEyLjAwMDQ1KSBhbmFseXNlZCBzaGlmdHMgZnJvbSBiYXNlbGluZSBhbmQgb25seSBoYWQgbGF0ZXJhbCBzYWNjYWRlcy4KCl9fRGF0YV9fOiAKCiogT3V0bGllcnMgcmVtb3ZlZAoqIENvbGxhcHNlZCBpbnRvIDE1LW1pbnV0ZSBpbnRlcnZhbHMKKiBTdWJ0cmFjdCB0aGUgYmFzZWxpbmUgZnJvbSBlYWNoIHN1YnNlcXVlbnQgYmxvY2sKKiBEaXNjYXJkIGNlbnRlciwga2VlcCBvbmx5IGxhdGVyYWwgc2FjY2FkZXMKCl9fRGVwZW5kZW50IG1lYXN1cmVfXzogc2FjY2FkaWMgbGF0ZW5jeQoKX19GYWN0b3JzX186CgoqIFNUSU1VTEFUSU9OIChhbm9kYWwgdnMuIGNhdGhvZGFsKQoqIExFRyAodERDUywgcG9zdC4xLCBwb3N0LjIpCiogRElSRUNUSU9OIChsZWZ0IHZzLiByaWdodCkKCmBgYHtyIEthbmFpIEFOT1ZBLCByZXN1bHRzPSdhc2lzJ30KCm1vZGVsS2FuYWkgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShmaWx0ZXIobGF0ZW5jeU1lZGlhbkJhc2VsaW5lLCB0eXBlID09ICJsYXRlcmFsIikpLAogICAgICAgICAgICAgICAgICAgICAgICBkdiA9IC4obGF0ZW5jeSksIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sbGVnLGRpcmVjdGlvbiksIHR5cGUgPSAzKQoKIyBPUiwgd2l0aG91dCB0aGUgRVogcGFja2FnZToKIyBtb2RlbEthbmFpPWFvdihsYXRlbmN5fnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24gKyBFcnJvcihzdWJqZWN0LyhzdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uKSksZGF0YT1sYXRlbmN5TWVkaWFuQmFzZWxpbmVMYXRlcmFsKQojIHN1bW1hcnkobW9kZWxLYW5haSkKCmthYmxlKG1vZGVsS2FuYWkkQU5PVkEpCmthYmxlKG1vZGVsS2FuYWkkYE1hdWNobHkncyBUZXN0IGZvciBTcGhlcmljaXR5YCkKa2FibGUobW9kZWxLYW5haSRgU3BoZXJpY2l0eSBDb3JyZWN0aW9uc2ApCmBgYAoKIyMjIyMgTWFpbiBlZmZlY3Qgb2YgbGVnCgpgYGB7ciBLYW5haSBNYWluIGVmZmVjdCBvZiBsZWd9CmxhdGVuY3lNZWRpYW5CYXNlbGluZSAlPiUKICBmaWx0ZXIodHlwZSA9PSAibGF0ZXJhbCIpICU+JQogIGdyb3VwX2J5KHN1YmplY3QsbGVnKSAlPiUKICBzdW1tYXJpc2UobGF0ZW5jeSA9IG1lYW4obGF0ZW5jeSkpICU+JQogIGdncGxvdChhZXMobGVnLCBsYXRlbmN5KSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCwgc2l6ZSA9IDEpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gImxpbmUiLCBhZXMoZ3JvdXAgPSAxKSkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4yNSkKYGBgCgpTYWNjYWRlcyBiZWNvbWUgc2xvd2VyIG92ZXIgdGltZSB3aXRoIHJlc3BlY3QgdG8gdGhlIGJhc2VsaW5lLiBOb3RlIHRoYXQgdGhpcyBlZmZlY3QgYmVjb21lcyBqdXN0IG5vbi1zaWduaWZpY2FudCB3aGVuIGNvcnJlY3RpbmcgZm9yIHNwaGVyaWNpdHkuCgojIyMjIyBJbnRlcmFjdGlvbjogTGVnIGJ5IGRpcmVjdGlvbgoKYGBge3IgS2FuYWkgSW50ZXJhY3Rpb24gbGVnIGJ5IGRpcmVjdGlvbn0KbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIGZpbHRlcih0eXBlID09ICJsYXRlcmFsIikgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxsZWcsZGlyZWN0aW9uKSAlPiUKICBzdW1tYXJpc2UobGF0ZW5jeSA9IG1lYW4obGF0ZW5jeSkpICU+JQogIGdncGxvdChhZXMobGVnLCBsYXRlbmN5LCBzaGFwZSA9IGRpcmVjdGlvbikpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gImxpbmUiLCBhZXMoZ3JvdXAgPSBkaXJlY3Rpb24sIGxpbmV0eXBlID0gZGlyZWN0aW9uKSkKYGBgCgpUaGlzIG1haW4gZWZmZWN0IG9mIGxlZyBpcyBzdHJvbmdlciBmb3IgcmlnaHQgc2FjY2FkZXMsIGJ1dCBkb2VzIG5vdCBvY2N1ciB1bnRpbCB0aGUgMm5kIHBvc3QtYmxvY2suCgojIyMjIyBJbnRlcmFjdGlvbjogc3RpbXVsYXRpb24gYnkgbGVnIGJ5IGRpcmVjdGlvbgoKVGhpcyBpbnRlcmFjdGlvbiBpcyBub3Qgc2lnbmlmaWNhbnQsIGJ1dCBpdCBpcyBvZiBwcmltYXJ5IGludGVyZXN0LCBzbyBsZXQncyBzdGlsbCBsb29rIGF0IGl0IGluIG1vcmUgZGV0YWlsLgoKYGBge3IgS2FuYWkgSW50ZXJhY3Rpb24gc3RpbXVsYXRpb24gYnkgbGVnIGJ5IGRpcmVjdGlvbn0KbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIGZpbHRlcih0eXBlID09ICJsYXRlcmFsIikgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzdGltdWxhdGlvbixsZWcsZGlyZWN0aW9uKSAlPiUKICBzdW1tYXJpc2UobGF0ZW5jeSA9IG1lYW4obGF0ZW5jeSkpICU+JQogIGdncGxvdChhZXMobGVnLCBsYXRlbmN5LCBzaGFwZSA9IHN0aW11bGF0aW9uLCBjb2xvciA9IHN0aW11bGF0aW9uKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBmYWNldF93cmFwKH5kaXJlY3Rpb24pICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSkKYGBgCgpJbnRlcmVzdGluZ2x5LCBzdWJqZWN0cyBnZXQgc2xvd2VyIG92ZXIgdGltZSBpbiBhbGwgY29uZGl0aW9ucywgYnV0IHRoaXMgdHJlbmQgaXMgcmV2ZXJzZWQgZm9yIGxlZnQtc2FjY2FkZXMgaW4gdGhlIGFub2RhbCBzZXNzaW9uLCBhcyBwcmVkaWN0ZWQuIEhvd2V2ZXIsIHRoZSBlZmZlY3QgYmFyZWx5IHJlYWNoZXMgMSBtcy4uLgoKIyMjIyBXaXRoIHNlc3Npb24gb3JkZXIKCkFkZCBhbiBhZGRpdGlvbmFsIGZhY3RvciBTRVNTSU9OIE9SREVSLCB3aGljaCBjcmVhdGVzIHR3byBncm91cHM6IHRob3NlIHN1YmplY3RzIHdobyByZWNlaXZlZCBhbm9kYWwgdERDUyBpbiB0aGUgZmlyc3Qgc2Vzc2lvbiB2cy4gdGhvc2Ugd2hvIHJlY2VpdmVkIGNhdGhvZGFsIHREQ1MgaW4gdGhlIGZpcnN0IHNlc3Npb24uIE5vdGUgdGhhdCB0aGVzZSBncm91cHMgYXJlIG5vdCBleGFjdGx5IGJhbGFuY2VkLCB3aGljaCBtaWdodCBhZmZlY3QgKGNvcnJlY3RpbmcgZm9yKSB2aW9sYXRpb25zIG9mIHNwaGVyaWNpdHk6CgpgYGB7ciBVbmJhbGFuY2VkIHNlc3Npb24gb3JkZXJzLCByZXN1bHRzPSdhc2lzJ30KbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIGdyb3VwX2J5KHNlc3Npb24ub3JkZXIpICU+JQogIHN1bW1hcml6ZShjb3VudCA9IG5fZGlzdGluY3Qoc3ViamVjdCkpICU+JQogIGthYmxlKC4pCmBgYAoKX19EYXRhX186IAoKKiBPdXRsaWVycyByZW1vdmVkCiogQ29sbGFwc2VkIGludG8gMTUtbWludXRlIGludGVydmFscwoqIFN1YnRyYWN0IHRoZSBiYXNlbGluZSBmcm9tIGVhY2ggc3Vic2VxdWVudCBibG9jawoqIERpc2NhcmQgY2VudGVyLCBrZWVwIG9ubHkgbGF0ZXJhbCBzYWNjYWRlcwoKX19EZXBlbmRlbnQgbWVhc3VyZV9fOiBzYWNjYWRpYyBsYXRlbmN5CgpfX0ZhY3RvcnNfXzoKCiogU1RJTVVMQVRJT04gKGFub2RhbCB2cy4gY2F0aG9kYWwpCiogTEVHICh0RENTLCBwb3N0LjEsIHBvc3QuMikKKiBESVJFQ1RJT04gKGxlZnQgdnMuIHJpZ2h0KQoqIFNFU1NJT04gT1JERVIgKGZpcnN0IGFub2RhbCB2cy4gZmlyc3QgY2F0aG9kYWwpCgpgYGB7ciBLYW5haSBBTk9WQSBsYXRlcmFsIHNlc3Npb24gb3JkZXIsIHJlc3VsdHM9J2FzaXMnfQptb2RlbEthbmFpT3JkZXIgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShmaWx0ZXIobGF0ZW5jeU1lZGlhbkJhc2VsaW5lLCB0eXBlID09ICJsYXRlcmFsIikpLCBkdiA9IC4obGF0ZW5jeSksIAogICAgICAgICAgd2lkID0gLihzdWJqZWN0KSwgd2l0aGluID0gLihzdGltdWxhdGlvbixsZWcsZGlyZWN0aW9uKSwgIGJldHdlZW4gPSBzZXNzaW9uLm9yZGVyLCB0eXBlID0gMykKa2FibGUobW9kZWxLYW5haU9yZGVyJEFOT1ZBKQprYWJsZShtb2RlbEthbmFpT3JkZXIkYE1hdWNobHkncyBUZXN0IGZvciBTcGhlcmljaXR5YCkKa2FibGUobW9kZWxLYW5haU9yZGVyJGBTcGhlcmljaXR5IENvcnJlY3Rpb25zYCkKYGBgCgojIyMjIyBJbnRlcmFjdGlvbjogc2Vzc2lvbiBvcmRlciBieSBzdGltdWxhdGlvbiBieSBkaXJlY3Rpb24KCmBgYHtyIEthbmFpIEludGVyYWN0aW9uIHNlc3Npb24gb3JkZXIgYnkgc3RpbXVsYXRpb24gYnkgZGlyZWN0aW9ufQoKbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIGZpbHRlcih0eXBlID09ICJsYXRlcmFsIikgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzZXNzaW9uLm9yZGVyLHN0aW11bGF0aW9uLGRpcmVjdGlvbikgJT4lCiAgc3VtbWFyaXNlKGxhdGVuY3kgPSBtZWFuKGxhdGVuY3kpKSAlPiUKICBnZ3Bsb3QoYWVzKGRpcmVjdGlvbiwgbGF0ZW5jeSwgc2hhcGUgPSBzdGltdWxhdGlvbiwgY29sb3IgPSBzdGltdWxhdGlvbikpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZmFjZXRfd3JhcCh+c2Vzc2lvbi5vcmRlcikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pKQpgYGAKClRoZSBzZXNzaW9uIG9yZGVyIGJ5IHN0aW11bGF0aW9uIGRpcmVjdGlvbiBpbnRlcmFjdGlvbiBjYW4gYmUgY29uc3RydWVkIGFzIGEgbWFpbiBlZmZlY3Qgb2Ygc2Vzc2lvbi4gSXQgYXBwZWFycyB0aGF0IGluIHRoZSAybmQgc2Vzc2lvbiwgcGVvcGxlIHNsb3cgZG93biBtb3JlIHRoYW4gaW4gdGhlIDFzdC4gVGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBsZWZ0IGFuZCByaWdodCBhbHNvIHNlZW1zIG1vcmUgcHJvbm91bmNlZCwgZXNwZWNpYWxseSB3aGVuIHRoZSAybmQgc2Vzc2lvbiBpcyBhbm9kYWwuCgpUaGlzIGxhdHRlciB0aHJlZS13YXkgaW50ZXJhY3Rpb24gaXMgdmVyeSBkaWZmaWN1bHQgdG8gaW50ZXJwcmV0IHRob3VnaC4gSW4gYWRkaXRpb24sIHRoZSBzdGltdWxhdGlvbiBieSBkaXJlY3Rpb24gaW50ZXJhY3Rpb24gaXMgbm90IHNpZ25pZmljYW50IHdpdGhvdXQgc2Vzc2lvbiBvcmRlciwgc28gd2UgZG8gbm90IGhhdmUgdG8gd29ycnkgdGhhdCB0aGlzIGVmZmVjdCBpcyBwcmVzZW50IGJ1dCBjb25mb3VuZGVkIGJ5IHNlc3Npb24gb3JkZXIuCgojIyMgQU5PVkEgbWF0Y2hpbmcgS2FuYWkgZXQgYWwuICgyMDEyKSAtIGNlbnRlciBzYWNjYWRlcyB7LnRhYnNldCAudGFic2V0LWZhZGV9CgojIyMjIFdpdGhvdXQgc2Vzc2lvbiBvcmRlcgoKUmVwZWF0IHRoZSBzYW1lIEFOT1ZBLCBidXQgbm93IGZvciBjZW50ZXIgc2FjY2FkZXMgKHdoaWNoIEthbmFpIGRpZCBub3QgaGF2ZSkuCgpgYGB7ciBLYW5haSBBTk9WQSBjZW50ZXIsIHJlc3VsdHM9J2FzaXMnfQoKbW9kZWxLYW5haUNlbnRlciA8LSBlekFOT1ZBKGRhdGEgPSBkYXRhLmZyYW1lKGZpbHRlcihsYXRlbmN5TWVkaWFuQmFzZWxpbmUsIHR5cGUgPT0gImNlbnRlciIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgZHYgPSAuKGxhdGVuY3kpLCB3aWQgPSAuKHN1YmplY3QpLCB3aXRoaW4gPSAuKHN0aW11bGF0aW9uLGxlZyxkaXJlY3Rpb24pLCB0eXBlID0gMykKCmthYmxlKG1vZGVsS2FuYWlDZW50ZXIkQU5PVkEpCmthYmxlKG1vZGVsS2FuYWlDZW50ZXIkYE1hdWNobHkncyBUZXN0IGZvciBTcGhlcmljaXR5YCkKa2FibGUobW9kZWxLYW5haUNlbnRlciRgU3BoZXJpY2l0eSBDb3JyZWN0aW9uc2ApCmBgYAoKIyMjIyMgTWFpbiBlZmZlY3Qgb2YgZGlyZWN0aW9uCgpgYGB7ciBLYW5haS1DZW50ZXIgTWFpbiBlZmZlY3Qgb2YgZGlyZWN0aW9ufQpsYXRlbmN5TWVkaWFuQmFzZWxpbmUgJT4lCiAgZmlsdGVyKHR5cGUgPT0gImNlbnRlciIpICU+JQogIGdyb3VwX2J5KHN1YmplY3QsZGlyZWN0aW9uKSAlPiUKICBzdW1tYXJpc2UobGF0ZW5jeSA9IG1lYW4obGF0ZW5jeSkpICU+JQogIGdncGxvdChhZXMoZGlyZWN0aW9uLCBsYXRlbmN5KSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gImxpbmUiLCBhZXMoZ3JvdXAgPSAxKSwgc2l6ZSA9IDIpICsKICBnZW9tX2xpbmUoYWVzKGNvbG91ciA9IHN1YmplY3QsIGdyb3VwID0gc3ViamVjdCkpCmBgYAoKVGhpcyBzZWVtcyB0byBiZSBhIHJlYWxseSB0aW55IGFuZCB2YXJpYWJsZSBlZmZlY3QsIGJ1dCBhcHBhcmVudGx5IGxlZnQgc2FjY2FkZXMgZ2V0IHNvbWV3aGF0IHNsb3dlciBhbmQgcmlnaHQgc2FjY2FkZXMgc29tZXdoYXQgZmFzdGVyIGNvbXBhcmVkIHRvIGJhc2VsaW5lLgoKIyMjIyBXaXRoIHNlc3Npb24gb3JkZXIKCmBgYHtyIEthbmFpIEFOT1ZBIGNlbnRlciBzZXNzaW9uIG9yZGVyLCByZXN1bHRzPSdhc2lzJ30KbW9kZWxLYW5haUNlbnRlck9yZGVyIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUoZmlsdGVyKGxhdGVuY3lNZWRpYW5CYXNlbGluZSwgdHlwZSA9PSAiY2VudGVyIikpLCBkdiA9IC4obGF0ZW5jeSksIAogICAgICAgICAgd2lkID0gLihzdWJqZWN0KSwgd2l0aGluID0gLihzdGltdWxhdGlvbixsZWcsZGlyZWN0aW9uKSwgIGJldHdlZW4gPSBzZXNzaW9uLm9yZGVyLCB0eXBlID0gMykKa2FibGUobW9kZWxLYW5haUNlbnRlck9yZGVyJEFOT1ZBKQprYWJsZShtb2RlbEthbmFpQ2VudGVyT3JkZXIkYE1hdWNobHkncyBUZXN0IGZvciBTcGhlcmljaXR5YCkKa2FibGUobW9kZWxLYW5haUNlbnRlck9yZGVyJGBTcGhlcmljaXR5IENvcnJlY3Rpb25zYCkKYGBgCgojIyMjIyMgSW50ZXJhY3Rpb246IHNlc3Npb24gb3JkZXIgYnkgZGlyZWN0aW9uCgpUaGVyZSBpcyBhIG1haW4gZWZmZWN0IG9mIGRpcmVjdGlvbiBpbiB0aGUgQU5PVkEgd2l0aG91dCBzZXNzaW9uIG9yZGVyLCBzbyB0aGlzIGVmZmVjdCBtaWdodCBiZSBjb25mb3VuZGVkLgoKYGBge3IgS2FuYWktQ2VudGVyLVNlc3Npb24tb3JkZXIgSW50ZXJhY3Rpb24gd2l0aCBkaXJlY3Rpb259CmxhdGVuY3lNZWRpYW5CYXNlbGluZSAlPiUKICBmaWx0ZXIodHlwZSA9PSAiY2VudGVyIikgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzZXNzaW9uLm9yZGVyLGRpcmVjdGlvbikgJT4lCiAgc3VtbWFyaXNlKGxhdGVuY3kgPSBtZWFuKGxhdGVuY3kpKSAlPiUKICBnZ3Bsb3QoYWVzKGRpcmVjdGlvbiwgbGF0ZW5jeSwgc2hhcGUgPSBzZXNzaW9uLm9yZGVyKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IHNlc3Npb24ub3JkZXIsIGxpbmV0eXBlID0gc2Vzc2lvbi5vcmRlcikpCmBgYAoKVGhlIG1haW4gZWZmZWN0IG9mIGRpcmVjdGlvbiBpcyBwcmVzZW50IGZvciBib3RoIGdyb3VwcywgYnV0IGl0IGlzIG11Y2ggc3Ryb25nZXIgaW4gdGhlIGdyb3VwIHRoYXQgZmlyc3QgcmVjZWl2ZXMgY2F0aG9kYWwgc3RpbXVsYXRpb24uIFRoaXMgY291bGQgYmUgY29uc3RydWVkIGFzIGEgX2NhcnJ5b3Zlcl8gZWZmZWN0LCBpLmUuIHRoYXQgdGhlIGVmZmVjdCBvZiBjYXRob2RhbCBzdGltdWxhdGlvbiB3YXMgbm90IHlldCB3YXNoZWQtb3V0IGJ5IHRoZSBzZWNvbmQgc2Vzc2lvbiBhbmQgbW9kdWxhdGVkIHRoZSBlZmZlY3Qgb2YgYW5vZGFsIChhbmQgdmljZSB2ZXJzYSkuIE9yLCBpdCBjb3VsZCBzaW1wbHkgYmUgdGhhdCB0aGVyZSBpcyBhIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIGdyb3VwcyAoYW5vZGFsIGZpcnN0IHZzLiBjYXRob2RhbCBmaXJzdCkgdGhhdCBoYXMgbm90aGluZyB0byBkbyB3aXRoIHN0aW11bGF0aW9uLgoKIyMgQmF5ZXNpYW4KCiMjIyBMaW5lYXIgbWl4ZWQgZWZmZWN0cyBtYXRjaGluZyBLYW5haSAtIHNhY2NhZGUgbGF0ZW5jeQoKIyMjIyBUZXN0IGFnYWluc3QgdGhlIG51bGwgbW9kZWwKCmBgYHtyIENvbXB1dGUgQmF5ZXMgRmFjdG9ycyBjZi4gbnVsbCBtb2RlbH0KYmZLYW5haUxhdGVyYWwgPSBhbm92YUJGKGxhdGVuY3l+c3RpbXVsYXRpb24qbGVnKmRpcmVjdGlvbitzdWJqZWN0LCBkYXRhID0gZGF0YS5mcmFtZShmaWx0ZXIobGF0ZW5jeU1lZGlhbkJhc2VsaW5lLCB0eXBlID09ICJsYXRlcmFsIikpLCB3aGljaE1vZGVscyA9ICJ3aXRobWFpbiIsIHdoaWNoUmFuZG9tID0gInN1YmplY3QiLCBwcm9ncmVzcyA9IEZBTFNFLCBpdGVyYXRpb25zID0gMTAwMDAwKSAjIGNvbXB1dGUgQmF5ZXMgRmFjdG9ycwpiZkthbmFpTGF0ZXJhbCA9IHNvcnQoYmZLYW5haUxhdGVyYWwsIGRlY3JlYXNpbmcgPSBUUlVFKSAjIHNvcnQgc3VjaCB0aGF0IHdpbm5pbmcgbW9kZWwgaXMgYXQgdGhlIHRvcApgYGAKCkZpcnN0IHdlIGNvbXBhcmUgYWxsIG1vZGVscyB0byB0aGUgbW9zdCBzaW1wbGUgKG51bGwpIG1vZGVsLCB3aGljaCBpcyB0aGUgaW50ZXJjZXB0IG9ubHkgKyByYW5kb20gZWZmZWN0IG1vZGVsOiBgbGF0ZW5jeSB+IHN1YmplY3RgLiBUaGlzIGRvZXMgbm90IHRlc3QgZm9yIGVmZmVjdHMgb2YgU1VCSkVDVCBidXQgbW9kZWxzIGl0IGFzIGEgbnVpc2FuY2UgZmFjdG9yIChgd2hpY2hSYW5kb20gPSAic3ViamVjdCJgKS4gSW4gYWRkaXRpb24sIHRvIGRlY3JlYXNlIHRoZSBtb2RlbCBzcGFjZSwgd2UgZG8gbm90IGNvbnNpZGVyIG1vZGVscyB0aGF0IGhhdmUgYW4gaW50ZXJhY3Rpb24gd2l0aG91dCB0aGUgY29ycmVzcG9uZGluZyBtYWluIGVmZmVjdHMgKGB3aGljaE1vZGVscyA9ICJ3aXRobWFpbiJgKS4KCmBgYHtyIEV4dHJhY3QgQmF5ZXMgRmFjdG9ycyB3aXRoTWFpbiwgcmVzdWx0cz0nYXNpcyd9CmthYmxlKHNlbGVjdChleHRyYWN0QkYoYmZLYW5haUxhdGVyYWwpLCBiZikpICMgc2hvdyBvbmx5IHRoZSBCYXllcyBmYWN0b3JzIGluIGEgdGFibGUKYGBgCgpUaGUgd2lubmluZyBtb2RlbCBpcyB0aGUgb25lIHdpdGgganVzdCBhIG1haW4gZWZmZWN0IG9mIExFRywgd2l0aCBhIEJheWVzIGZhY3RvciBvZiBgciByb3VuZChleHRyYWN0QkYoYmZLYW5haUxhdGVyYWxbMV0sIG9ubHliZiA9IFRSVUUpLCBkaWdpdHMgPSAxKWAuIEhvd2V2ZXIsIHNvIGV2ZW4gZm9yIHRoaXMgbW9kZWwgdGhlcmUgaXMgbGVzcyBldmlkZW5jZSB0aGFuIGZvciB0aGUgbnVsbCBtb2RlbCwgd2hpY2ggYnkgZGVmaW5pdGlvbiBoYXMgYSBCYXllcyBGYWN0b3Igb2YgMS4KClRoZSBjb252ZW50aW9uYWwgaW50ZXJwcmV0YXRpb24gZm9yIEJheWVzIEZhY3RvcnMgaXMgdGhlIGZvbGxvd2luZzoKCiogQkZ+MTB+IDwgMC4xOiBzdHJvbmcgZXZpZGVuY2UgZm9yIEgwCiogMC4xIDwgQkZ+MTB+IDwgLjMzOiBtb2RlcmF0ZSBldmlkZW5jZSBmb3IgSDAKKiAwLjMzMyA8IEJGfjEwfiA8IDE6IGFuZWNkb3RhbCBldmlkZW5jZSBmb3IgSDAKCiogQkZ+MTB+ID0gMTogZXF1aXZhbGVudCBldmlkZW5jZSBmb3IgSDAgYW5kIEgxCgoqIDEgQkZ+MTB+IDwgMzogYW5lY2RvdGFsIGV2aWRlbmNlIGZvciBIMQoqIDMgPCBCRn4xMH4gPCAxMDogbW9kZXJhdGUgZXZpZGVuY2UgZm9yIEgxCiogQkZ+MTB+ID4gMTA6IHN0cm9uZyBldmlkZW5jZSBIMSAKClNvIHRvIHN3aXRjaCBiZXR3ZWVuIGV4cHJlc3NpbmcgdGhlIEJheWVzIEZhY3RvciBhcyBldmlkZW5jZSBmb3IgSDEgKEJGfjEwfikgb3IgSDAgKEJGfjAxfiksIHlvdSBzaW1wbHkgaW52ZXJ0IGl0IChkaXZpZGUgYnkgMSkuCgpXZSBjYW4gY29tcHV0ZSB0aGUgZXZpZGVuY2UgZm9yIGEgcGFydGljdWxhciBlZmZlY3QgYnkgY29tcGFyaW5nIHRoaXMgd2lubmluZyBtb2RlbCB3aXRoIHRoZSBiZXN0LWZpdHRpbmcgbW9kZWwgdGhhdCBkb2VzIF9ub3RfIGNvbnRhaW4gdGhlIGVmZmVjdC4gV2UgY2FuIGNvbXB1dGUgdGhlIGV2aWRlbmNlIGZvciBfYWJzZW5jZV8gb2YgYSBwYXJ0aWN1bGFyIGVmZmVjdCBieSBjb21wYXJpbmcgdGhlIHdpbm5pbmcgbW9kZWwgd2l0aCB0aGUgYmVzdC1maXR0aW5nIG1vZGVsIHRoYXQgX2RvZXNfIGNvbnRhaW4gdGhlIGVmZmVjdC4KClRoZSBldmlkZW5jZSBmb3IgdGhlIGVmZmVjdCBvZiBMRUcgY2FuIGJlIHF1YW50aWZpZWQgYnkgY29tcGFyaW5nIHRoZSBCYXllcyBmYWN0b3JzIG9mIHRoZSBmaXJzdCBhbmQgdGhlIDNyZCBtb2RlbCAoYmVjYXVzZSB0aGF0IGlzIHRoZSBmaXJzdCBvbmUgdGhhdCBkb2VzIF9ub3RfIGNvbnRhaW4gTEVHIGFzIGEgZmFjdG9yKTogYHIgcm91bmQoZXh0cmFjdEJGKGJmS2FuYWlMYXRlcmFsWzFdIC8gYmZLYW5haUxhdGVyYWxbM10sIG9ubHliZiA9IFRSVUUpLCBkaWdpdHMgPSAxKWAuIFRoaXMgY29uc3RpdHVlcyBvbmx5IGFub2Nkb3RhbCBldmlkZW5jZSBmb3IgdGhlIHByZXNlbmNlIG9mIGEgbGVnIGVmZmVjdCwgZXZlbiB0aG91Z2ggaXQgd2FzIHNpZ25pZmljYW50IGluIHRoZSBjbGFzc2ljYWwgQU5PVkEuIEJ1dCwgZ2l2ZW4gdGhhdCB0aGUgbGVnIG1vZGVsIGl0c2VsZiBpcyBzdWNoIGEgcG9vciBmaXQsIGluIHRoZSBCYXllc2lhbiBhbmFseXNpcyB0aGlzIHdlYWsgZXZpZGVuY2UgaXMgbm8gc3VycHJpc2UuCgpUaGUgZXZpZGVuY2UgZm9yIHRoZSBfYWJzZW5jZV8gb2YgdGhlIFNUSU1VTEFUSU9OIGJ5IERJUkVDVElPTiBpbnRlcmFjdGlvbiBjYW4gYmUgcXVhbnRpZmllZCBieSBjb21wYXJpbmcgdGhlIEJheWVzIGZhY3RvcnMgb2YgdGhlIGZpcnN0IGFuZCB0aGUgOXRoIG1vZGVsIChiZWNhdXNlIHRoYXQgaXMgdGhlIGZpcnN0IG9uZSB0aGF0IF9kb2VzXyBjb250YWluIHRoZSBpbnRlcmFjdGlvbik6IGByIHJvdW5kKGV4dHJhY3RCRihiZkthbmFpTGF0ZXJhbFsxXSAvIGJmS2FuYWlMYXRlcmFsWzldLCBvbmx5YmYgPSBUUlVFKSwgZGlnaXRzID0gMSlgLiBUaGlzIGNvbnN0aXR1ZXMgc3Ryb25nIGV2aWRlbmNlIGZvciB0aGUgYWJzZW5jZSBvZiB0aGUgaW50ZXJhY3Rpb24uCgojIyMjIFRlc3QgYWdhaW5zdCB0aGUgZnVsbCBtb2RlbAoKQW5vdGhlciBvcHRpb24gZm9yIHF1YW50aWZ5aW5nIGV2aWRlbmNlIGZvciBhIHBhcnRpY3VsYXIgZWZmZWN0IGlzIHRvIGNvbXBhcmUgdGhlIGZ1bGwgbW9kZWwgdG8gYSBtb2RlbCB3aGVyZSB0aGF0IGVmZmVjdCBpcyBvbWl0dGVkIChgd2hpY2hNb2RlbHMgPSB0b3AiKWAuIFRoZSBmdWxsIG1vZGVsIGlzIGBzdGltdWxhdGlvbiArIGRpcmVjdGlvbiArIHN0aW11bGF0aW9uOmRpcmVjdGlvbiArIGxlZyArIHN0aW11bGF0aW9uOmxlZyArIGRpcmVjdGlvbjpsZWcgKyBzdGltdWxhdGlvbjpkaXJlY3Rpb246bGVnICsgc3ViamVjdGAuCgpgYGB7ciBDb21wdXRlIEJheWVzIEZhY3RvcnMgY2YuIGZ1bGwgbW9kZWx9CmJmS2FuYWlMYXRlcmFsRnVsbCA9IGFub3ZhQkYobGF0ZW5jeX5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uK3N1YmplY3QsIGRhdGEgPSBkYXRhLmZyYW1lKGZpbHRlcihsYXRlbmN5TWVkaWFuQmFzZWxpbmUsIHR5cGUgPT0gImxhdGVyYWwiKSksIHdoaWNoTW9kZWxzID0gInRvcCIsIHdoaWNoUmFuZG9tID0gInN1YmplY3QiLCBwcm9ncmVzcyA9IEZBTFNFLCBpdGVyYXRpb25zID0gMTAwMDAwKSAjIGNvbXB1dGUgQmF5ZXMgRmFjdG9ycwpiZkthbmFpTGF0ZXJhbEZ1bGwKYGBgCgpSZW1vdmluZyB0aGUgTEVHIGVmZmVjdCBmcm9tIHRoZSBtb2RlbCB5aWVsZHMgYSBoaWdoZXIgQmF5ZXMgRmFjdG9yLCBzbyByZW1vdmluZyB0aGlzIGVmZmVjdCBhY3R1YWxseSBpbXByb3ZlZCB0aGUgbW9kZWwsIGFsdGhvdWdoIG9ubHkgYnkgYSBsaXR0bGUgYml0LiBUaGUgZXZpZGVuY2UgdGh1cyBnb2VzIGluIHRoZSBkaXJlY3Rpb24gb2YgdGhlIG51bGw7IHdoZW4gZXhwcmVzc2VkIGluIGZhdm9yIG9mIHRoZSBhbHRlcm5hdGl2ZSwgdGhlIEJheWVzIEZhY3RpciBiZWNvbWVzIGxlc3MgdGhhbiBvbmU6IDEgXCBgciByb3VuZChleHRyYWN0QkYoYmZLYW5haUxhdGVyYWxGdWxsWzVdLCBvbmx5YmYgPSBUUlVFKSwgZGlnaXRzID0gMylgIGAgPSBgIGByIHJvdW5kKGV4dHJhY3RCRigxL2JmS2FuYWlMYXRlcmFsRnVsbFs1XSwgb25seWJmID0gVFJVRSksIGRpZ2l0cyA9IDEpYCAKClNpbWlsYXJseSwgcmVtb3ZpbmcgdGhlIERJUkVDVElPTiBieSBTVElNVUxBVElPTiBlZmZlY3QgaW1wcm92ZXMgdGhlIG1vZGVsLCBhbmQgdGhpcyB0aW1lIGEgYml0IG1vcmU6IGluIHRoZSByYW5nZSBvZiBtb2RlcmF0ZSBldmlkZW5jZSBmb3IgdGhlIG51bGwuCgojIyMjIEJheWVzaWFuIG1vZGVsIGF2ZXJhZ2luZwoKVGhlIHByb2JsZW0gd2l0aCB0aGUgMXN0IG9wdGlvbiAoY29tcGFyaW5nIHNpbmdsZSBtb2RlbHMsIGZvciBleGFtcGxlIHRvIHRoZSB3aW5uaW5nIG1vZGVsKSBpcyB0aGF0IGZvciBkZXNpZ25zIHdpdGggbWFueSBmYWN0b3JzIChhbmQgdGhlcmVmb3JlIG1vZGVscyksIGl0IGJlY29tZXMgcmlza3kgYW5kIGEgYml0IHN1YmplY3RpdmUgdG8gYmFzZSBjb25jbHVzaW9ucyBvbiBqdXN0IHR3byBtb2RlbHMuIEluIHRoaXMgY2FzZSwgdGhlIHdpbm5pbmcgbW9kZWwgaXMgZXZlbiBhIGJhZCBmaXQsIHNvIGl0IGRvZXNuJ3Qgc2VlbSBhcHByb3ByaWF0ZSB0byB1c2UgaXQgYXMgYSBiZW5jaG1hcmsuCgpUaGUgcHJvYmxlbSB3aXRoIHRoZSAybmQgb3B0aW9uIChjb21wYXJpbmcgYWdhaW5zdCB0aGUgZnVsbCBtb2RlbCkgaXMgYWN0dWFsbHkgdmVyeSBhcHBhcmVudCBpbiB0aGlzIGRhdGFzZXQ6IHRoZSBmdWxsIG1vZGVsIGlzIGEgdGVycmlibGUgZml0LCBhcyBpdCBjb21lcyBpbiBsYXN0LiBUaGVyZSBpcyBldmVuIGEgbG90IG9mIGV2aWRlbmNlIGFnYWluc3QgaXQgd2hlbiBjb21wYXJlZCB0byB0aGUgbnVsbCBtb2RlbCEKCk9uZSBzb2x1dGlvbiBpcyB0byBkbyBCYXllc2lhbiBNb2RlbCBBdmVyYWdpbmc6IGNvbXBhcmUgbXVsdGlwbGUgbW9kZWxzIGFuZCBhZ2dyZWdhdGUgdGhlIEJheWVzIEZhY3RvcnMuCgpJbiB0aGUgW0pBU1Agc3RhdHMgcGFja2FnZV0oaHR0cDovL2phc3Atc3RhdHMub3JnKSwgdGhpcyBhbmFseXNpcyBpcyBhbHNvIGNhbGxlZCB0aGUgImluY2x1c2lvbiBCYXllcyBmYWN0b3IiLiBCcmllZmx5LCBpdCBjb21wYXJlcyBhbGwgbW9kZWxzIHRoYXQgaW5jbHVkZSB0aGUgZWZmZWN0IG9mIGludGVyZXN0IHZzLiBhbGwgbW9kZWxzIHRoYXQgZG8gbm90LiBGb3IgZXhhbXBsZXMgYW5kIGEgY29uY2VwdHVhbCBleHBsYW5hdGlvbiwgc2VlIGV4YW1wbGUgNSBpbjogW0JheWVzaWFuIGluZmVyZW5jZSBmb3IgcHN5Y2hvbG9neS4gUGFydCBJSTogRXhhbXBsZSBhcHBsaWNhdGlvbnMgd2l0aCBKQVNQXShodHRwczovL2RvaS5vcmcvMTAuMzc1OC9zMTM0MjMtMDE3LTEzMjMtNykuCgpUaGVyZSdzIGFsc28gYSBkaWZmZXJlbnQgd2F5IG9mIGNhbGN1bGF0aW5nIGluY2x1c2lvbiBCYXllcyBmYWN0b3JzIChbY29uY2VwdHVhbGl6ZWQgYnkgU2ViYXN0aWFhbiBNYXRob3RdKGh0dHBzOi8vd3d3LmNvZ3NjaS5ubC9ibG9nL2ludGVycHJldGluZy1iYXllc2lhbi1yZXBlYXRlZC1tZWFzdXJlcy1pbi1qYXNwKSkgdGhhdCBpcyBjdXJyZW50bHkgYmVpbmcgaW1wbGVtZW50ZWQgaW4gSkFTUC4gVGhpcyBpcyBjYWxsZWQgdGhlICJpbmNsdXNpb24gQmF5ZXMgZmFjdG9yIGFjcm9zcyBtYXRjaGVkIG1vZGVscyIsIGFuZCBpcyBtb3JlIHNlbGVjdGl2ZSBpbiB0aGUgc2V0IG9mIG1vZGVscyB0aGF0J3MgYmVpbmcgY29tcGFyZWQgdGhhbiB0aGUgc3RhbmRhcmQgaW5jbHVzaW9uIEJGLiBCcmllZmx5LCB0aGUgaW5jbHVzaW9uIEJGIGFjcm9zcyBtYXRjaGVkIG1vZGVscyBjb21wYXJlczoKCiogYWxsIG1vZGVscyB0aGF0IGluY2x1ZGUgdGhlIGVmZmVjdCBvZiBpbnRlcmVzdCwgYnV0IE5PIGludGVyYWN0aW9ucyB3aXRoIHRoZSBlZmZlY3Qgb2YgaW50ZXJlc3QsIFZFUlNVUwoqIHRoZSBtb2RlbHMgdGhhdCByZXN1bHQgZnJvbSBzdHJpcHBpbmcgdGhlIGVmZmVjdCBvZiBpbnRlcmVzdCBmcm9tIHRoaXMgc2V0IG9mIG1vZGVscy4KCkxldCdzIGNvbXBhcmUgdGhlIGRlZmF1bHQgaW5jbHVzaW9uIEJheWVzIEZhY3RvcnMgZm9yIGFsbCBlZmZlY3RzOgoKYGBge3IgSW5jbHVzaW9uIEJGIGRlZmF1bHR9CiMgRGVmYXVsdCBpbmNsdXNpb24gQmF5ZXMgRmFjdG9ycwprYWJsZShpbmNsdXNpb25CRihiZkthbmFpTGF0ZXJhbCkpCmBgYAoKRG9pbmcgdGhlIGFuYWx5c2lzIHRoaXMgd2F5LCB3ZSBhbHNvIGZpbmQgc3Ryb25nIGV2aWRlbmNlIGFnYWluc3QgbW9zdCBvZiB0aGVzZSBlZmZlY3RzOyBwYXJ0aWN1bGFybHkgdGhlIGludGVyYWN0aW9ucy4KCk15IHByZWZlcnJlZCBhcHByb2FjaCBpcyB0aGUgaW5jbHVzaW9uIEJheWVzIGZhY3RvciBhY3Jvc3MgbWF0Y2hlZCBtb2RlbHMuIFRoZSBldmlkZW5jZSBpcyBxdWFsaXRhdGl2ZWx5IHNpbWlsYXIsIGJ1dCBsZXNzIHN0cm9uZywgcHJvYmFibHkgYmVjYXVzZSB3ZSBhcmVuJ3QgaW5jbHVkaW5nIGFzIG1hbnkgcG9vcmx5IGZpdHRpbmcgbW9kZWxzIGluIHRoZSBtb2RlbCBjb21wYXJpc29uICh3aGljaCBoYXZlIGEgdmVyeSBsYXJnZSBCRn4xMH4gYW5kIHRoZXJlZm9yZSBhIGxvdCBvZiBlZmZlY3Qgb24gdGhlIGNvbXBvc2l0ZSBCYXllcyBGYWN0b3IpOgoKYGBge3IgSW5jbHVzaW9uIEJGIG1hdGNoZWQgbW9kZWxzfQprYWJsZShpbmNsdXNpb25CRihiZkthbmFpTGF0ZXJhbCwgbW9kZWxzID0gIm1hdGNoZWQiKSkKYGBgCgojIyMgTGluZWFyIG1peGVkIGVmZmVjdHMgbWF0Y2hpbmcgS2FuYWkgLSBjZW50ZXIgc2FjY2FkZXMKCmBgYHtyIEJheWVzIEZhY3RvciBLYW5haSBjZW50ZXJ9CmJmS2FuYWlDZW50ZXIgPSBhbm92YUJGKGxhdGVuY3l+c3RpbXVsYXRpb24qbGVnKmRpcmVjdGlvbitzdWJqZWN0LCBkYXRhID0gZGF0YS5mcmFtZShmaWx0ZXIobGF0ZW5jeU1lZGlhbkJhc2VsaW5lLCB0eXBlID09ICJjZW50ZXIiKSksIHdoaWNoTW9kZWxzPSJ3aXRobWFpbiIsIHdoaWNoUmFuZG9tID0gInN1YmplY3QiLCBwcm9ncmVzcyA9IEZBTFNFLCBpdGVyYXRpb25zID0gMTAwMDAwKSAjIGNvbXB1dGUgQmF5ZXMgRmFjdG9ycwpiZkthbmFpQ2VudGVyIDwtIHNvcnQoYmZLYW5haUNlbnRlciwgZGVjcmVhc2luZyA9IFRSVUUpICMgc29ydCBzdWNoIHRoYXQgd2lubmluZyBtb2RlbCBpcyBhdCB0aGUgdG9wCmBgYAoKYGBge3J9CmthYmxlKHNlbGVjdChleHRyYWN0QkYoYmZLYW5haUNlbnRlciksIGJmKSkgIyBzaG93IG9ubHkgdGhlIEJheWVzIGZhY3RvcnMgaW4gYSB0YWJsZQpgYGAKCkludGVyZXN0aW5nbHksIHRoZXJlIGlzIGEgbG90IG1vcmUgZXZpZGVuY2UgYWNyb3NzIHRoZSBib2FyZCwgZXNwZWNpYWxseSBmb3IgdGhlIG1vZGVscyB0aGF0IGZlYXR1cmUgU3RpbXVsYXRpb24gYW5kIERpcmVjdGlvbi4KCmBgYHtyIEluY2x1c2lvbiBCRiBtYXRjaGVkIG1vZGVscyAtIGNlbnRlciBzYWNjYWRlc30Ka2FibGUoaW5jbHVzaW9uQkYoYmZLYW5haUNlbnRlciwgbW9kZWxzID0gIm1hdGNoZWQiKSkKYGBgCgpUaGVyZSBzZWVtcyB0byBiZSBhIG1pc21hdGNoIHdpdGggdGhlIGNsYXNzaWNhbCBBTk9WQTogQW4gZWZmZWN0IG9mIHN0aW11bGF0aW9uIHJlY2VpdmVzIHN0cm9uZyBzdXBwb3J0LCB3aGVyZWFzIGl0IHdhcyBub24tc2lnbmlmaWNhbnQuIFRoZSBlZmZlY3Qgb2YgZGlyZWN0aW9uIHdhcyBzaWduaWZpY2FudCwgYnV0IGl0IGlzIGxlc3Mgc3Ryb25nbHkgc3VwcG9ydGVkIGJ5IHRoZSBpbmNsdXNpb24gQmF5ZXMgRmFjdG9yIChhbHRob3VnaCB0aGUgZXZpZGVuY2Ugc3RpbGwgZ29lcyBpbiB0aGUgcmlnaHQgZGlyZWN0aW9uKS4KCiMjIyMgTWFpbiBlZmZlY3Qgb2Ygc3RpbXVsYXRpb24KCmBgYHtyIEJGIEthbmFpLUNlbnRlciBNYWluIGVmZmVjdCBvZiBzdGltdWxhdGlvbn0KbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIGZpbHRlcih0eXBlID09ICJjZW50ZXIiKSAlPiUKICBncm91cF9ieShzdWJqZWN0LHN0aW11bGF0aW9uKSAlPiUKICBzdW1tYXJpc2UobGF0ZW5jeSA9IG1lYW4obGF0ZW5jeSkpICU+JQogIGdncGxvdChhZXMoc3RpbXVsYXRpb24sIGxhdGVuY3kpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IDEpLCBzaXplID0gMikgKwogIGdlb21fbGluZShhZXMoY29sb3VyID0gc3ViamVjdCwgZ3JvdXAgPSBzdWJqZWN0KSkKYGBgCgpJdCBpcyBlYXN5IHRvIHNlZSB3aHkgdGhpcyBlZmZlY3QgaXMgbm9uLXNpZ25pZmljYW50OiB0aGUgYXZlcmFnZSBkaWZmZXJlbmNlIGlzIHRpbnkgYW5kIHRoZXJlIGlzIGEgbG90IG9mIHZhcmlhYmlsaXR5LiBUaGUgcGxvdCBzaG93cyBvbmUgbWFqb3Igb3V0bGllciB0aG91Z2ggaW4gdGVybXMgb2YgdGhlIGVmZmVjdCBzaXplIChTMDEpOiBsZXQncyBzZWUgd2hhdCBoYXBwZW5zIHRvIHRoZSBCYXllcyBGYWN0b3IgaWYgd2UgdGFrZSB0aGVpciBkYXRhIG91dC4KCmBgYHtyfQpsYXRlbmN5Tm9TMDEgPC0gbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIGZpbHRlcihzdWJqZWN0ICE9ICJTMDEiKSAlPiUKICBtdXRhdGUoc3ViamVjdCA9IGZhY3RvcihzdWJqZWN0KSkKCmJmS2FuYWlDZW50ZXJOb1MwMSA9IGFub3ZhQkYobGF0ZW5jeX5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uK3N1YmplY3QsIGRhdGEgPSBkYXRhLmZyYW1lKGZpbHRlcihsYXRlbmN5Tm9TMDEsIHR5cGUgPT0gImNlbnRlciIpKSwgd2hpY2hNb2RlbHM9IndpdGhtYWluIiwgd2hpY2hSYW5kb20gPSAic3ViamVjdCIsIHByb2dyZXNzID0gRkFMU0UsIGl0ZXJhdGlvbnMgPSAxMDAwMDApICMgY29tcHV0ZSBCYXllcyBGYWN0b3JzCmJmS2FuYWlDZW50ZXJOb1MwMSA8LSBzb3J0KGJmS2FuYWlDZW50ZXJOb1MwMSwgZGVjcmVhc2luZyA9IFRSVUUpICMgc29ydCBzdWNoIHRoYXQgd2lubmluZyBtb2RlbCBpcyBhdCB0aGUgdG9wCmthYmxlKHNlbGVjdChleHRyYWN0QkYoYmZLYW5haUNlbnRlck5vUzAxKSwgYmYpKSAjIHNob3cgb25seSB0aGUgQmF5ZXMgZmFjdG9ycyBpbiBhIHRhYmxlCmthYmxlKGluY2x1c2lvbkJGKGJmS2FuYWlDZW50ZXJOb1MwMSwgbW9kZWxzID0gIm1hdGNoZWQiKSkKYGBgCgpUaGlzIGNvbXBsZXRlbHkgYWJvbGlzaGVzIHRoZSBzdHJvbmcgc3VwcG9ydCBmb3IgU3RpbXVsYXRpb24sIGFuZCBncmVhdGx5IGVuaGFuY2VzIHRoZSBzdXBwb3J0IGZvciBEaXJlY3Rpb24sIGJyaW5naW5nIHRoZSBCYXllc2lhbiBhbmQgdGhlIGNsYXNzaWNhbCBBTk9WQXMgbW9yZSBpbiBsaW5lLiBBdCBwcmVzZW50IGl0IGlzIHVuY2xlYXIgd2h5IHRoZSBjbGFzc2ljYWwgYW5kIEJheWVzaWFuIGFuYWx5c2VzIGRpZmZlciBpbiB0aGlzIHJlZ2FyZC4gV2hlbiBzaW11bGF0aW5nIHRoaXMgY2FzZSBmb3Igbm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YSwgdGhlIEJheWVzIEZhY3RvcnMgYW5kIHAtdmFsdWVzIHRyYWNrIGVhY2ggb3RoZXIgbmljZWx5IChzZWUgW2Rpc2N1c3Npb24gb24gSkFTUC9CYXllc0ZhY3RvciBmb3J1bV0oaHR0cDovL2ZvcnVtLmNvZ3NjaS5ubC9pbmRleC5waHA/cD0vZGlzY3Vzc2lvbi8zNTk2L2xhcmdlLWJheWVzLWZhY3Rvci1jaGFuZ2VzLXdpdGgtZXhjbHVzaW9uLW9mLXNpbmdsZS1zdWJqZWN0LWJheWVzaWFuLWFub3ZhKSkuIFRoaXMgc3VnZ2VzdHMgdGhlcmUgbXVzdCBiZSBzb21lIGFzc3VtcHRpb24gdGhhdCBpcyBub3QgbWV0IGluIHRoaXMgcGFydGljdWxhciBkYXRhc2V0LCB3aGljaCBpcyBjYXVzaW5nIHRoZSBkaXZlcmdlbmNlIGJldHdlZW4gdGhlIGFuYWx5c2VzLgoKU3RpbGwsIGxldCdzIGRvIHNvbWUgZm9sbG93LXVwIHRlc3RzIHdpdGggYWxsIG9mIHRoZSBkYXRhIChpLmUuIGluY2x1ZGluZyB0aGlzIHN1YmplY3QpIHRvIHNlZSB3aGV0aGVyIHRoZSBhbm9kYWwgb3IgY2F0aG9kYWwgY2hhbmdlIHNjb3JlcyBhcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSAwIG9uIHRoZWlyIG93bi4KCkJheWVzaWFuIG9uZS1zYW1wbGUgdC10ZXN0czoKCmBgYHtyIEJheWVzaWFuIGZvbGxvdy11cCB0ZXN0LCByZXN1bHRzPSdhc2lzJ30KbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIGZpbHRlcih0eXBlID09ICJjZW50ZXIiKSAlPiUgIyBrZWVwIG9ubHkgY2VudGVyIHNhY2NhZGVzCiAgZ3JvdXBfYnkoc3RpbXVsYXRpb24sc3ViamVjdCkgJT4lICMgZm9yIGVhY2ggc2Vzc2lvbiBhbmQgc3ViamVjdAogIHN1bW1hcmlzZShkZXZpYXRpb24uZW5kID0gbWVhbihsYXRlbmN5KSkgJT4lICMgYXZlcmFnZSBvdmVyIGFsbCBvdGhlciB2YXJpYWJsZXMKICBzcHJlYWQoc3RpbXVsYXRpb24sZGV2aWF0aW9uLmVuZCkgJT4lICMgbWFrZSBzZXBhcmF0ZSBjb2x1bW5zIHdpdGggdGVzdCBkYXRhCiAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIGZ1bnMoZXh0cmFjdEJGKHR0ZXN0QkYoLiksIG9ubHliZiA9IFRSVUUpKSkgJT4lICMgcnVuIEJheWVzaWFuIHQtdGVzdCBvbiBlYWNoIGNvbHVtbiwga2VlcGluZyBvbmx5IHRoZSBCRgogIGdhdGhlcihzdGltdWxhdGlvbixCRixhbm9kYWwsY2F0aG9kYWwpICU+JSAjIG1ha2Ugcm93IGZvciBlYWNoIHN0aW11bGF0aW9uIGNvbmRpdGlvbgogIGthYmxlKC4pCmBgYAoKRnJlcXVlbnRpc3Qgb25lLXNhbXBsZSB0LXRlc3RzOgoKYGBge3IgQ2xhc3NpY2FsIGZvbGxvdy11cCB0ZXN0LCByZXN1bHRzPSdhc2lzJ30KbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIGZpbHRlcih0eXBlID09ICJjZW50ZXIiKSAlPiUgIyBrZWVwIG9ubHkgY2VudGVyIHNhY2NhZGVzCiAgZ3JvdXBfYnkoc3RpbXVsYXRpb24sc3ViamVjdCkgJT4lICMgZm9yIGVhY2ggc2Vzc2lvbiBhbmQgc3ViamVjdAogIHN1bW1hcmlzZShkZXZpYXRpb24uZW5kID0gbWVhbihsYXRlbmN5KSkgJT4lICMgYXZlcmFnZSBvdmVyIGFsbCBvdGhlciB2YXJpYWJsZXMgKGRmIGlzIG5vdyBzdGlsbCBncm91cGVkIHBlciBzdGltdWxhdGlvbikKICBzdW1tYXJpc2VfaWYoaXMubnVtZXJpYywgZnVucyhsaXN0KHRpZHkodC50ZXN0KC4pKSkpKSAlPiUgICMgcnVuIG9uZS1zYW1wbGUgdC10ZXN0IGZvciBlYWNoIHN0aW11bGF0aW9uIGNvbmRpdGlvbiwgcmV0dXJuIHRpZHkgZGF0YSBmcmFtZXMKICB1bm5lc3QoKSAlPiUgIyB1bnBhY2sgdGhlIGxpc3QtY29sdW1uIHdpdGggZGF0YSBmcmFtZSBmb3IgZWFjaCB0ZXN0CiAga2FibGUoLikKYGBgCgpTbyBuZWl0aGVyIGFyZSBhY3R1YWxseSBzaWduaWZpY2FudCBvciBoYXZlIGEgQkYgd2l0aCBldmlkZW5jZSBmb3IgdGhlIGFsdGVybmF0aXZlLgo=