Group analyses

Load data

All (meta)data are stored as .csv files in the /data folder.

Eye tracking data

Here we load the .csv file with the processed eye tracking data, which was created in MATLAB. To recreate it from the raw data, run the analysis.m script. This scripts calls the processEDF.m function to parse the raw eye tracking data.

  • 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

Metadata

Session info

kable(head(sessionData))
subject session stimulation date day time
S01 first cathodal 10/07/15 Friday 11:30:00
S01 second anodal 16/07/15 Thursday 09:00:00
S02 first anodal 10/07/15 Friday 09:00:00
S02 second cathodal 13/07/15 Monday 09:00:00
S03 first cathodal 13/07/15 Monday 11:30:00
S03 second anodal 15/07/15 Wednesday 13:00:00
  • subject: subject ID
  • session: Whether data are from the first) or second session
  • stimulation: Whether data are from the anodal or cathodal session
  • date: YY/MM/DD date the session took place
  • day: day of the week the session took place
  • time: time of day the session took place

Subject info

# Load eye tracking data into data frame
dataFile <- here("data", "subject_info.csv")
subjectData <- read_csv2(dataFile, col_names = TRUE, progress = FALSE, col_types = cols(
  session.order = col_factor(c("first.anodal", "first.cathodal"))
))
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

Preprocess eye data

See the inspection.html notebook for more explanation and exploration of preprocessing, outlier saccades and subject exclusion

Reject outlier saccades

tooFast <- 50
tooSlow <- 400
badFix <- 1.8
badSacc <- 8

Criteria for outliers:

  • 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
# Mark outliers
groupData <- mutate(groupData, outlier = "non.outlier", # fill vector for all saccades
                    outlier = ifelse(latency < tooFast, "fast", outlier), # mark too fast saccades as "fast"
                    outlier = ifelse(latency > tooSlow, "slow", outlier), # mark too slow saccades as "slow"
                    outlier = ifelse(deviation.start > badFix, "fixation", outlier), # mark bad fixations as "fixation"
                    outlier = ifelse(deviation.end.x > badSacc, "saccade", outlier), # mark inaccurate saccades as "saccade"
                    outlier = ifelse(is.na(latency), "none", outlier) # mark absence of saccade as "none"
                    )
preproc <- filter(groupData, outlier == "non.outlier")

Exclude participants

  • S21 and S25 were tested < 48h apart
  • S16, S22 and S28 have fewer than 50 saccades per condition after trial rejection
subs2exclude <- c("S21","S25","S16","S22","S28")
preproc <- filter(preproc, !(subject %in% subs2exclude))

Collapse data across 15 minute intervals

Cut the post-block into two so we have four 15-minute intervals: one before, one during, and two after stimulation.

preproc <- preproc %>%
  mutate(leg = as.character(leg), # cannot edit leg if it's still a factor
         leg = replace(leg, leg == "post" & block <= 3, "post.1"),
         leg = replace(leg, block > 3, "post.2"),
         leg = factor(leg, levels = c("pre", "tDCS", "post.1", "post.2")) # refactor and order levels
         )

Subject and session descriptives

Sample demographics

For S23, no eye data was collected because eye tracker could not be calibrated, so here we don’t include their subject/session data.

Gender of remaining participants:

subjectData %>%
  filter(!(subject %in% c(subs2exclude, "S23"))) %>% # remove rows with these subject
  group_by(gender) %>% # for each gender
  summarise(count = n_distinct(subject)) %>%
  kable(.)# count number of subjects
gender count
female 14
male 12

Age:

subjectData %>%
  filter(!(subject %in% c(subs2exclude, "S23"))) %>%
  summarise_at(vars(age), funs(mean, min, max, sd), na.rm = TRUE) %>% # apply summary functions to age column
  kable(.)
mean min max sd
25.90476 21 34 3.419134

tDCS session order

sessionData %>%
  filter(!(subject %in% c(subs2exclude, "S23"))) %>%
  group_by(session, stimulation) %>%
  summarise(count = n_distinct(subject)) %>% 
  kable(.)
session stimulation count
first anodal 14
first cathodal 12
second anodal 12
second cathodal 14

Saccade counts

Average number of saccades per type after rejection:

preproc %>%
  group_by(subject,stimulation,leg,direction,type) %>% # for each cell
  summarise(saccades = n()) %>% # count how many saccacdes there are left
  group_by(type) %>% 
  summarise_at(vars(saccades), funs(mean, min, max, sd)) %>% # compute summary statistics per type
  kable(.)
type mean min max sd
lateral 175.2284 142 180 6.244285
center 155.5529 74 180 20.816516

Percentage of outlier saccades per type out of all sacccades:

n_total <- nrow(filter(groupData, !(subject %in% subs2exclude)))  # total amount of saccades across all included sessions/subjects
groupData %>%
  filter(!(subject %in% subs2exclude), !(outlier %in% c("non.outlier", "none"))) %>%
  group_by(subject,stimulation,leg,direction,type,outlier) %>%
  summarize(outlier_count = n()) %>% # for each condition and subject, count how many (non)outliers there are
  group_by(outlier) %>% # for each outlier type
  summarise(percentage = sum(outlier_count) / n_total *100) %>% # calculate percentage
  kable(.)
outlier percentage
fast 1.9958600
fixation 2.5848024
saccade 0.1555823
slow 0.1161859

Saccade latency

See the median_latency.html notebook for more explanation and exploration of the median saccade latency data

Compute the median for each 3 blocks

latencyMedianLeg <- preproc %>%
  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.1"]),
            post.2 = median(latency[leg == "post.2"])) %>%
  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

Make a separate data frame where the median baseline latency is subtracted from subsequent blocks

latencyMedianBaseline <- latencyMedianLeg %>%
  group_by(subject,stimulation,direction,type) %>% # for each condition, subtract baseline scores and make new columns
  summarise(baseline = latency[leg == "baseline"] - latency[leg == "baseline"],
           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.baseline, 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

Figure 4

baselineLabelLatency <- latencyMedianLeg %>%
  group_by(stimulation,direction,type,leg) %>%
  filter(leg == "baseline") %>%
  summarise(latency.baseline = round(mean(latency)))

Plot median lateral saccade latency per participant

plot_sub_latency_lateral <- ggplot(filter(latencyMedianLeg, type == "lateral"), aes(leg, latency)) +
  facet_grid(stimulation ~ direction) +
  geom_line(aes(group = subject, color = subject), alpha = 0.5) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), linetype = direction), geom = "line") +
  stat_summary(fun.y = mean, geom = "point", aes(shape = stimulation)) +
  guides(colour = FALSE) +
  scale_fill_manual(values = c("#F25F5C", "#4B93B1")) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous("median latency (ms)", breaks = seq(100,200,20), limits = c(90,220)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank(), legend.position = "none") +
  ggtitle("Lateral saccades")

Plot median center saccade latency per participant

plot_sub_latency_center <- ggplot(filter(latencyMedianLeg, type == "center"), aes(leg, latency)) +
  facet_grid(stimulation ~ direction) +
  geom_line(aes(group = subject, color = subject), alpha = 0.5) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), linetype = direction), geom = "line") +
  stat_summary(fun.y = mean, geom = "point", aes(shape = stimulation)) +
  scale_fill_manual(values = c("#F25F5C", "#4B93B1")) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous("median latency (ms)", breaks = seq(100,200,20), limits = c(90,220)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank(), legend.position = "none") +
  ggtitle("Center saccades")

Plot group mean lateral saccade latency as change from baseline

plot_group_latency_lateral <- ggplot(filter(latencyMedianBaseline, type == "lateral"), aes(leg, latency.baseline)) +
  geom_hline(yintercept = 0, linetype = "dashed", size = base_line_size) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "line", position = position_dodge(width = 0.5), size = .75) + 
  stat_summary(fun.data = mean_cl_normal, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "linerange", position = position_dodge(width = 0.5), show.legend = FALSE) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, shape = stimulation), geom = "point", position = position_dodge(width = 0.5), size = 2) +
  geom_text(data = subset(baselineLabelLatency, type=="lateral"), aes(y = c(2,1,4,3), label=latency.baseline, color = stimulation), position = position_dodge(width = 0.5), size = mm_to_pt) +
  scale_colour_manual(values = c("#F25F5C", "#4B93B1")) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous("latency change from baseline (ms)", breaks = seq(-8,8,2)) +
  coord_cartesian(ylim = c(-8,8)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank())

Plot group mean center saccade latency as change from baseline

plot_group_latency_center <- ggplot(filter(latencyMedianBaseline, type == "center"), aes(leg, latency.baseline)) +
  geom_hline(yintercept = 0, linetype = "dashed", size = base_line_size) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "line", position = position_dodge(width = 0.5), size = .75) + 
  stat_summary(fun.data = mean_cl_normal, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "linerange", position = position_dodge(width = 0.5), show.legend = FALSE) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, shape = stimulation), geom = "point", position = position_dodge(width = 0.5), size = 2) +
  geom_text(data = subset(baselineLabelLatency, type=="center"), aes(y = c(2,1,3,4), label=latency.baseline, color = stimulation), position = position_dodge(width = 0.5), size = mm_to_pt) +
  scale_colour_manual(values = c("#F25F5C", "#4B93B1")) +
  scale_x_discrete(labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous("latency change from baseline (ms)", breaks = seq(-8,8,2)) +
  coord_cartesian(ylim = c(-8,8)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank())

Combine all the plots:

legend_fig4 <- get_legend(plot_group_latency_lateral)
figure_4 <- plot_grid(
  plot_sub_latency_lateral, plot_sub_latency_center,
  plot_group_latency_lateral + theme(legend.position = "none"),
  plot_group_latency_center + theme(legend.position = "none"), rel_heights = c(1,.75))
figure_4 <- plot_grid(figure_4,legend_fig4,rel_widths = c(1,1/10))
figure_4

Save the plot:

ggsave("fig/figure_4.pdf", plot = figure_4, width = 180, height = 112.5, units = "mm")
ggsave("fig/figure_4.png", plot = figure_4, width = 180, height = 112.5, units = "mm")

Statistics

Contralateral saccades in the anodal session

Means and SDs for effect of anodal tDCS on the latency changes in contralateral (here: left) lateral saccades, as this is what Kanai et al. (2012) specifically found:

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

Baseline tests

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

Lateral saccades

Classical ANOVA

Repeated measures ANOVA matching Kanai et al. (2012).

Data: Baseline subtracted, lateral saccades

Dependent measure: saccade latency

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (tDCS, post.1, post.2)
  • DIRECTION (left vs. right)

Prepare data:

medianLatencyLateralStats <- latencyMedianBaseline %>%
  ungroup() %>%
  filter(leg != "baseline", type == "lateral") %>%
  select(-type) %>%
  mutate(leg = factor(leg, levels = c("tDCS", "post.1", "post.2"))) %>%
  mutate(subject = factor(subject))
aovMedianLatencyLateral <- ezANOVA(data = data.frame(medianLatencyLateralStats), dv = latency.baseline, wid = subject, within = .(stimulation,leg,direction), type = 3)
kable(aovMedianLatencyLateral$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(aovMedianLatencyLateral$`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(aovMedianLatencyLateral$`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
Bayesian ANOVA

Same design as the classical ANOVA

Bayes factors agains the null model:

bfMedianLatencyLateral = anovaBF(latency.baseline~stimulation*leg*direction+subject, data = data.frame(medianLatencyLateralStats), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000)
bfMedianLatencyLateral = sort(bfMedianLatencyLateral, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfMedianLatencyLateral), bf)) # show only the Bayes factors in a table
bf
leg + subject 0.8352130
stimulation + subject 0.7473931
stimulation + leg + subject 0.6443968
direction + subject 0.1326109
direction + leg + subject 0.1130630
stimulation + direction + subject 0.0992967
stimulation + direction + leg + subject 0.0858565
stimulation + leg + stimulation:leg + subject 0.0474197
stimulation + direction + stimulation:direction + subject 0.0213852
stimulation + direction + stimulation:direction + leg + subject 0.0191576
direction + leg + direction:leg + subject 0.0108038
stimulation + direction + leg + direction:leg + subject 0.0083966
stimulation + direction + leg + stimulation:leg + subject 0.0064302
stimulation + direction + stimulation:direction + leg + direction:leg + subject 0.0018561
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 0.0014920
stimulation + direction + leg + stimulation:leg + direction:leg + subject 0.0006257
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 0.0001415
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.0000251

Inclusion Bayes factor across matched models:

kable(inclusionBF(bfMedianLatencyLateral, models = "matched"))
effect Bayes.factor
stimulation 0.7579226
direction 0.1335372
stimulation:direction 0.2194969
leg 0.8485524
stimulation:leg 0.0738604
direction:leg 0.0965650
stimulation:direction:leg 0.1772191

Center saccades

Classical ANOVA

Repeated measures ANOVA matching Kanai et al. (2012).

Data: Baseline subtracted, center saccades

Dependent measure: saccade latency

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (tDCS, post.1, post.2)
  • DIRECTION (left vs. right)

Prepare data:

medianLatencyCenterStats <- latencyMedianBaseline %>%
  ungroup() %>%
  filter(leg != "baseline", type == "center") %>%
  select(-type) %>%
  mutate(leg = factor(leg, levels = c("tDCS", "post.1", "post.2"))) %>%
  mutate(subject = factor(subject))
aovMedianLatencyCenter <- ezANOVA(data = data.frame(medianLatencyCenterStats), dv = latency.baseline, wid = subject, within = .(stimulation,leg,direction), type = 3)
kable(aovMedianLatencyCenter$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(aovMedianLatencyCenter$`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(aovMedianLatencyCenter$`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
Bayesian ANOVA

Same design as the classical ANOVA

Bayes factors agains the null model:

bfMedianLatencyCenter = anovaBF(latency.baseline~stimulation*leg*direction+subject, data = data.frame(medianLatencyCenterStats), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000)
bfMedianLatencyCenter = sort(bfMedianLatencyCenter, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfMedianLatencyCenter), bf)) # show only the Bayes factors in a table
bf
stimulation + direction + subject 532.4650356
stimulation + direction + stimulation:direction + subject 394.3029430
stimulation + direction + leg + subject 96.2040603
stimulation + direction + stimulation:direction + leg + subject 73.5299040
stimulation + subject 57.7975660
stimulation + direction + leg + direction:leg + subject 9.6677632
stimulation + leg + subject 9.4507885
direction + subject 7.9146682
stimulation + direction + stimulation:direction + leg + direction:leg + subject 6.8648353
stimulation + direction + leg + stimulation:leg + subject 6.2949743
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 4.9041121
direction + leg + subject 1.3039416
stimulation + leg + stimulation:leg + subject 0.6511612
stimulation + direction + leg + stimulation:leg + direction:leg + subject 0.6412998
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 0.4587427
leg + subject 0.1597575
direction + leg + direction:leg + subject 0.1261317
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.0850270
kable(select(extractBF(bfMedianLatencyCenter), bf)) # show only the Bayes factors in a table
bf
stimulation + direction + subject 532.4650356
stimulation + direction + stimulation:direction + subject 394.3029430
stimulation + direction + leg + subject 96.2040603
stimulation + direction + stimulation:direction + leg + subject 73.5299040
stimulation + subject 57.7975660
stimulation + direction + leg + direction:leg + subject 9.6677632
stimulation + leg + subject 9.4507885
direction + subject 7.9146682
stimulation + direction + stimulation:direction + leg + direction:leg + subject 6.8648353
stimulation + direction + leg + stimulation:leg + subject 6.2949743
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 4.9041121
direction + leg + subject 1.3039416
stimulation + leg + stimulation:leg + subject 0.6511612
stimulation + direction + leg + stimulation:leg + direction:leg + subject 0.6412998
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 0.4587427
leg + subject 0.1597575
direction + leg + direction:leg + subject 0.1261317
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.0850270

Inclusion Bayes factor across matched models:

kable(inclusionBF(bfMedianLatencyCenter, models = "matched"))
effect Bayes.factor
stimulation 67.1698107
direction 9.3279679
stimulation:direction 0.7439649
leg 0.1818340
stimulation:leg 0.0661683
direction:leg 0.0974488
stimulation:direction:leg 0.1853480
Without S01
medianLatencyCenterNoS01 <- medianLatencyCenterStats %>%
  filter(subject != "S01") %>%
  mutate(subject = factor(subject))
bfMedianLatencyCenterNoS01 = anovaBF(latency.baseline~stimulation*leg*direction+subject, data = data.frame(medianLatencyCenterNoS01), whichModels="withmain", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiCenterNoS01 <- sort(bfMedianLatencyCenterNoS01, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfMedianLatencyCenterNoS01), bf)) # show only the Bayes factors in a table

bf
stimulation + subject 1.9640554
direction + subject 581.5285256
stimulation + direction + subject 1377.4254509
stimulation + direction + stimulation:direction + subject 339.5023767
leg + subject 0.3012718
stimulation + leg + subject 0.6170947
direction + leg + subject 202.3563921
stimulation + direction + leg + subject 515.9118619
stimulation + direction + stimulation:direction + leg + subject 127.6249879
stimulation + leg + stimulation:leg + subject 0.0420750
stimulation + direction + leg + stimulation:leg + subject 34.0104912
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 9.1335465
direction + leg + direction:leg + subject 25.1494237
stimulation + direction + leg + direction:leg + subject 63.3338096
stimulation + direction + stimulation:direction + leg + direction:leg + subject 15.6595568
stimulation + direction + leg + stimulation:leg + direction:leg + subject 4.1945555
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 1.0390094
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.1723584

kable(inclusionBF(bfMedianLatencyCenterNoS01, models = "matched"))
effect Bayes.factor
stimulation 2.4178282
direction 690.8484746
stimulation:direction 0.2471128
leg 0.3679517
stimulation:leg 0.0669569
direction:leg 0.1230279
stimulation:direction:leg 0.1658873
Follow-up tests
Main effect of stimulation

Follow-up One-sample t-test:

medianLatencyCenterStats %>%
  group_by(stimulation,subject) %>% # for each session and subject
  summarise(latency = mean(latency.baseline)) %>% # 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

Follow-up Bayesian one-sample t-test:

medianLatencyCenterStats %>%
  group_by(stimulation,subject) %>% # for each session and subject
  summarise(latency = mean(latency.baseline)) %>% # average over all other variables
  spread(stimulation, latency) %>% # 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

Saccade endpoint deviation

See the accuracy.html notebook for more explanation and exploration of the saccade endpoint deviation data

Calculate endpoint deviation for each trial (Euclidian distance from target, defined by x- and y-coordinate deviations)

# Calculate end point deviation
accData <- preproc %>%
  group_by(subject,stimulation,leg,block,trial,direction,type) %>%
  summarise(deviation.end = sqrt(deviation.end.x^2 + deviation.end.y^2))

Compute the mean for each 3 blocks

accMeanLeg <- accData %>%
  group_by(subject,stimulation,direction,type) %>% 
  summarise(baseline = mean(deviation.end[leg == "pre"]), # take average of 3 blocks, make new column
            tDCS = mean(deviation.end[leg == "tDCS"]),
            post.1 = mean(deviation.end[leg == "post.1"]),
            post.2 = mean(deviation.end[leg == "post.2"])) %>%
  gather(leg,deviation.end,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

Make a separate data frame where the mean deviation is subtracted from subsequent blocks

accMeanBaseline <- accMeanLeg %>%
  group_by(subject,stimulation,direction,type) %>% # for each condition, subtract baseline scores and make new columns
  summarise(baseline = deviation.end[leg == "baseline"] - deviation.end[leg == "baseline"],
           tDCS = deviation.end[leg == "tDCS"] - deviation.end[leg == "baseline"],
           post.1 = deviation.end[leg == "post.1"] - deviation.end[leg == "baseline"],
           post.2 = deviation.end[leg == "post.2"] - deviation.end[leg == "baseline"]) %>%
  gather(leg, deviation.end.baseline, 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

Figure 6

baselineLabelAcc <- accMeanLeg %>%
  group_by(stimulation,direction,type,leg) %>%
  filter(leg == "baseline") %>%
  summarise(deviation.end.baseline = round(mean(deviation.end), digits = 2))

Plot mean lateral saccade deviation per participant

plot_sub_acc_lateral <- ggplot(filter(accMeanLeg, type == "lateral"), aes(leg, deviation.end)) +
  facet_grid(stimulation ~ direction) +
  geom_line(aes(group = subject, color = subject), alpha = 0.5) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), linetype = direction), geom = "line") +
  stat_summary(fun.y = mean, geom = "point", aes(shape = stimulation)) +
  guides(colour = FALSE) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous(expression("mean deviation " ( degree)), breaks = seq(0.5,2,0.5), limits = c(0.3,2.2)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank(), legend.position = "none") +
  ggtitle("Lateral saccades")

Plot mean center saccade deviation per participant

plot_sub_acc_center <- ggplot(filter(accMeanLeg, type == "center"), aes(leg, deviation.end)) +
  facet_grid(stimulation ~ direction) +
  geom_line(aes(group = subject, color = subject), alpha = 0.5) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), linetype = direction), geom = "line") +
  stat_summary(fun.y = mean, geom = "point", aes(shape = stimulation)) +
  guides(colour = FALSE) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous(expression("mean deviation " ( degree)), breaks = seq(0.5,2,0.5), limits = c(0.3,2.2)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank(), legend.position = "none") +
  ggtitle("Center saccades")

Plot group mean lateral saccade deviation as change from baseline

plot_group_acc_lateral <- ggplot(filter(accMeanBaseline, type == "lateral"), aes(leg, deviation.end.baseline)) +
  geom_hline(yintercept = 0, linetype = "dashed", size = base_line_size) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "line", position = position_dodge(width = 0.5), size = .75) + 
  stat_summary(fun.data = mean_cl_normal, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "linerange", position = position_dodge(width = 0.5), show.legend = FALSE) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, shape = stimulation), geom = "point", position = position_dodge(width = 0.5), size = 2) +
  geom_text(data = subset(baselineLabelAcc, type=="lateral"), aes(y = c(.05,.025,.1,.075), label=deviation.end.baseline, color = stimulation), position = position_dodge(width = 0.5), size = mm_to_pt) +
  scale_colour_manual(values = c("#F25F5C", "#4B93B1")) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous(expression("deviation change from baseline " ( degree)), breaks = seq(-.2,.2,.1)) +
  coord_cartesian(ylim = c(-.22,.22)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank())

Plot group mean center saccade deviation as change from baseline

plot_group_acc_center <- ggplot(filter(accMeanBaseline, type == "center"), aes(leg, deviation.end.baseline)) +
  geom_hline(yintercept = 0, linetype = "dashed", size = base_line_size) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "line", position = position_dodge(width = 0.5), size = .75) + 
  stat_summary(fun.data = mean_cl_normal, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "linerange", position = position_dodge(width = 0.5), show.legend = FALSE) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, shape = stimulation), geom = "point", position = position_dodge(width = 0.5), size = 2) +
  geom_text(data = subset(baselineLabelAcc, type=="center"), aes(y = c(.05,.025,.1,.075), label=deviation.end.baseline, color = stimulation), position = position_dodge(width = 0.5), size = mm_to_pt) +
  scale_colour_manual(values = c("#F25F5C", "#4B93B1")) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous(expression("deviation change from baseline " ( degree)), breaks = seq(-.2,.2,.1)) +
  coord_cartesian(ylim = c(-.22,.22)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank())

Combine all the plots:

legend_fig6 <- get_legend(plot_group_acc_lateral)
figure_6 <- plot_grid(
  plot_sub_acc_lateral, plot_sub_acc_center,
  plot_group_acc_lateral + theme(legend.position = "none"),
  plot_group_acc_center + theme(legend.position = "none"), rel_heights = c(1,.75))
figure_6 <- plot_grid(figure_6,legend_fig6,rel_widths = c(1,1/10))
figure_6

Save the plot:

ggsave("fig/figure_6.pdf", plot = figure_6, width = 180, height = 112.5, units = "mm")
ggsave("fig/figure_6.png", plot = figure_6, width = 180, height = 112.5, units = "mm")

Statistics

Baseline tests

accMeanLeg %>%
  filter(leg == "baseline") %>%
  group_by(direction,type) %>% 
  nest() %>% 
  mutate(stats = map(data, ~t.test(formula = deviation.end~stimulation, paired = TRUE, data =.))) %>% # run t-test on the data frames
  mutate(tidy_model = map(stats, tidy)) %>%
  unnest(tidy_model, .drop = TRUE) %>% 
  kable(.)
direction type estimate statistic p.value parameter conf.low conf.high method alternative
left lateral -0.0434955 -0.9392156 0.3566066 25 -0.1388738 0.0518827 Paired t-test two.sided
left center -0.1052918 -2.3796609 0.0252737 25 -0.1964194 -0.0141643 Paired t-test two.sided
right lateral -0.0141028 -0.4198800 0.6781598 25 -0.0832780 0.0550724 Paired t-test two.sided
right center -0.0576332 -1.9185260 0.0665325 25 -0.1195025 0.0042361 Paired t-test two.sided

Differences after baseline

Because there might be a significant baseline difference for center saccades, also print the numerical values for the blocks after, to see whether they continue to differ

accMeanLeg %>%
  filter(leg != "baseline", type == "center") %>%
  group_by(stimulation,direction,leg) %>% 
  summarise(mean = mean(deviation.end)) %>%
  kable(.)            
stimulation direction leg mean
anodal left tDCS 0.9149277
anodal left post.1 0.8752206
anodal left post.2 0.8978057
anodal right tDCS 0.7192357
anodal right post.1 0.7110237
anodal right post.2 0.7465372
cathodal left tDCS 0.9129682
cathodal left post.1 0.8395323
cathodal left post.2 0.8357657
cathodal right tDCS 0.7227287
cathodal right post.1 0.7062460
cathodal right post.2 0.7483820

Lateral saccades

Classical ANOVAs

Repeated measures ANOVA matching Kanai et al. (2012).

Data: Baseline subtracted, lateral saccades

Dependent measure: saccade endpoint deviation

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (tDCS, post.1, post.2)
  • DIRECTION (left vs. right)

Prepare data:

meanAccLateralStats <- accMeanBaseline %>%
  ungroup() %>%
  filter(leg != "baseline", type == "lateral") %>%
  select(-type) %>%
  mutate(leg = factor(leg, levels = c("tDCS", "post.1", "post.2"))) %>%
  mutate(subject = factor(subject))
aovMeanAccLateral <- ezANOVA(data = data.frame(meanAccLateralStats), dv = deviation.end.baseline, wid = subject, within = .(stimulation,leg,direction), type = 3)
kable(aovMeanAccLateral$ANOVA)

Effect DFn DFd F p p<.05 ges
2 stimulation 1 25 2.0266072 0.1669269 0.0178886
3 leg 2 50 0.8985792 0.4136202 0.0021712
4 direction 1 25 1.5739544 0.2212365 0.0059023
5 stimulation:leg 2 50 0.5863132 0.5601540 0.0015026
6 stimulation:direction 1 25 0.1283222 0.7231851 0.0005433
7 leg:direction 2 50 0.1400779 0.8696305 0.0002306
8 stimulation:leg:direction 2 50 0.2773853 0.7589209 0.0002720

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

Effect W p p<.05
3 leg 0.6913883 0.0119307 *
5 stimulation:leg 0.9959286 0.9522226
7 leg:direction 0.9738561 0.7276748
8 stimulation:leg:direction 0.7556773 0.0346766 *

kable(aovMeanAccLateral$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
3 leg 0.7641686 0.3907386 0.8038793 0.3951392
5 stimulation:leg 0.9959451 0.5595027 1.0819912 0.5601540
7 leg:direction 0.9745222 0.8646202 1.0558164 0.8696305
8 stimulation:leg:direction 0.8036501 0.7108179 0.8504748 0.7234385
Bayesian ANOVA

Same design as the classical ANOVA (without order effect)

Bayes factors agains the null model:

bfMeanAccLateral = anovaBF(deviation.end.baseline~stimulation*leg*direction+subject, data = data.frame(meanAccLateralStats), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000)
bfMeanAccLateral = sort(bfMeanAccLateral, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfMeanAccLateral), bf)) # show only the Bayes factors in a table
bf
stimulation + subject 6.3400523
stimulation + direction + subject 3.2378043
stimulation + direction + stimulation:direction + subject 0.6225693
direction + subject 0.4416518
stimulation + leg + subject 0.3429758
stimulation + direction + leg + subject 0.1648642
leg + subject 0.0534535
stimulation + direction + stimulation:direction + leg + subject 0.0298322
stimulation + leg + stimulation:leg + subject 0.0290925
direction + leg + subject 0.0236635
stimulation + direction + leg + stimulation:leg + subject 0.0131121
stimulation + direction + leg + direction:leg + subject 0.0103604
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 0.0026128
stimulation + direction + stimulation:direction + leg + direction:leg + subject 0.0021340
direction + leg + direction:leg + subject 0.0016002
stimulation + direction + leg + stimulation:leg + direction:leg + subject 0.0009068
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 0.0001694
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.0000207

Inclusion Bayes factor across matched models:

kable(inclusionBF(bfMeanAccLateral, models = "matched"))
effect Bayes.factor
stimulation 6.6405313
direction 0.4997822
stimulation:direction 0.1918029
leg 0.0528075
stimulation:leg 0.0834174
direction:leg 0.0648087
stimulation:direction:leg 0.1221503

Center saccades

Classical ANOVA

Repeated measures ANOVA matching Kanai et al. (2012).

Data: Baseline subtracted, center saccades

Dependent measure: saccade endpoint deviation

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (tDCS, post.1, post.2)
  • DIRECTION (left vs. right)

Prepare data:

meanAccCenterStats <- accMeanBaseline %>%
  ungroup() %>%
  filter(leg != "baseline", type == "center") %>%
  select(-type) %>%
  mutate(leg = factor(leg, levels = c("tDCS", "post.1", "post.2"))) %>%
  mutate(subject = factor(subject))
aovMeanAccCenter <- ezANOVA(data = data.frame(meanAccCenterStats), dv = deviation.end.baseline, wid = subject, within = .(stimulation,leg,direction), type = 3)
kable(aovMeanAccCenter$ANOVA)

Effect DFn DFd F p p<.05 ges
2 stimulation 1 25 10.3422560 0.0035735 * 0.0698321
3 leg 2 50 2.4132849 0.0998788 0.0064777
4 direction 1 25 0.4250384 0.5203830 0.0041044
5 stimulation:leg 2 50 0.6101220 0.5472793 0.0012937
6 stimulation:direction 1 25 2.7995910 0.1067576 0.0126867
7 leg:direction 2 50 3.8854661 0.0270094 * 0.0071117
8 stimulation:leg:direction 2 50 0.5883554 0.5590374 0.0011173

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

Effect W p p<.05
3 leg 0.8436804 0.1300575
5 stimulation:leg 0.9603861 0.6156733
7 leg:direction 0.6656519 0.0075677 *
8 stimulation:leg:direction 0.8210183 0.0938067

kable(aovMeanAccCenter$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
3 leg 0.8648128 0.1084443 0.9232826 0.1046730
5 stimulation:leg 0.9618956 0.5412918 1.0404345 0.5472793
7 leg:direction 0.7494296 0.0403283 * 0.7865648 0.0380011 *
8 stimulation:leg:direction 0.8481896 0.5328387 0.9034188 0.5428502
Bayesian ANOVA

Same design as the classical ANOVA

Bayes factors agains the null model:

bfMeanAccCenter = anovaBF(deviation.end.baseline~stimulation*leg*direction+subject, data = data.frame(meanAccCenterStats), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000)
bfMeanAccCenter = sort(bfMeanAccCenter, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfMeanAccCenter), bf)) # show only the Bayes factors in a table
bf
stimulation + subject 4.106449e+04
stimulation + direction + stimulation:direction + subject 1.856891e+04
stimulation + direction + subject 1.103494e+04
stimulation + leg + subject 4.229288e+03
stimulation + direction + stimulation:direction + leg + subject 1.906850e+03
stimulation + direction + leg + subject 1.075423e+03
stimulation + leg + stimulation:leg + subject 3.390460e+02
stimulation + direction + stimulation:direction + leg + direction:leg + subject 3.346668e+02
stimulation + direction + leg + direction:leg + subject 2.146401e+02
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 1.424011e+02
stimulation + direction + leg + stimulation:leg + subject 8.365876e+01
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 2.972238e+01
stimulation + direction + leg + stimulation:leg + direction:leg + subject 1.698275e+01
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 3.404441e+00
direction + subject 2.423604e-01
leg + subject 9.609780e-02
direction + leg + subject 2.243320e-02
direction + leg + direction:leg + subject 4.178900e-03

Inclusion Bayes factor across matched models:

kable(inclusionBF(bfMeanAccCenter, models = "matched"))
effect Bayes.factor
stimulation 4.220938e+04
direction 2.672197e-01
stimulation:direction 1.688649e+00
leg 1.020479e-01
stimulation:leg 7.883280e-02
direction:leg 1.857701e-01
stimulation:direction:leg 1.145413e-01
Follow-up tests
Main effect of stimulation

Follow-up One-sample t-test:

meanAccCenterStats %>%
  group_by(stimulation,subject) %>% # for each session and subject
  summarise(deviation = mean(deviation.end.baseline)) %>% # 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 0.0223864 0.9712741 0.3407160 25 -0.0250828 0.0698555 One Sample t-test two.sided
cathodal -0.0755975 -3.1803958 0.0038987 25 -0.1245524 -0.0266426 One Sample t-test two.sided

Follow-up Bayesian one-sample t-test:

meanAccCenterStats %>%
  group_by(stimulation,subject) %>% # for each session and subject
  summarise(deviation = mean(deviation.end.baseline)) %>% # average over all other variables
  spread(stimulation, deviation) %>% # 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.3173718
cathodal 10.5264920

Saccade endpoint variability

See the accuracy.html notebook for more explanation and exploration of the saccade endpoint variability data

Calculate endpoint variability, as standard deviation of the horizontal component (x-coordinate) of saccades

varMeanLeg <- preproc %>%
  group_by(subject,stimulation,leg,direction,type) %>% 
  summarise(std.deviation.x = sd(deviation.end.x)) %>% # standard deviation
  ungroup() %>%
  mutate(leg = as.character(leg), # edit leg factor to match other data frames
         leg = replace(leg, leg == "pre", "baseline"),
         leg = factor(leg, levels = c("baseline", "tDCS", "post.1", "post.2"))
         )

Make a separate data frame where the mean variability is subtracted from subsequent blocks

varMeanBaseline <- varMeanLeg %>%
  group_by(subject,stimulation,direction,type) %>% # for each condition, subtract baseline scores and make new columns
  summarise(baseline = std.deviation.x[leg == "baseline"] - std.deviation.x[leg == "baseline"],
           tDCS = std.deviation.x[leg == "tDCS"] - std.deviation.x[leg == "baseline"],
           post.1 = std.deviation.x[leg == "post.1"] - std.deviation.x[leg == "baseline"],
           post.2 = std.deviation.x[leg == "post.2"] - std.deviation.x[leg == "baseline"]) %>%
  gather(leg, std.deviation.x.baseline, 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

Figure 7

baselineLabelVar <- varMeanLeg %>%
  group_by(stimulation,direction,type,leg) %>%
  filter(leg == "baseline") %>%
  summarise(std.deviation.x.baseline = round(mean(std.deviation.x), digits = 2))

Plot mean lateral saccade variability per participant

plot_sub_var_lateral <- ggplot(filter(varMeanLeg, type == "lateral"), aes(leg, std.deviation.x)) +
  facet_grid(stimulation ~ direction) +
  geom_line(aes(group = subject, color = subject), alpha = 0.5) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), linetype = direction), geom = "line") +
  stat_summary(fun.y = mean, geom = "point", aes(shape = stimulation)) +
  guides(colour = FALSE) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous(expression("standard deviation " ( degree)), breaks = seq(0.5,2,0.5), limits = c(0,2)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank(), legend.position = "none") +
  ggtitle("Lateral saccades")

Plot mean center saccade variability per participant

plot_sub_var_center <- ggplot(filter(varMeanLeg, type == "center"), aes(leg, std.deviation.x)) +
  facet_grid(stimulation ~ direction) +
  geom_line(aes(group = subject, color = subject), alpha = 0.5) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), linetype = direction), geom = "line") +
  stat_summary(fun.y = mean, geom = "point", aes(shape = stimulation)) +
  guides(colour = FALSE) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous(expression("standard deviation " ( degree)), breaks = seq(0.5,2,0.5), limits = c(0,2)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank(), legend.position = "none") +
  ggtitle("Center saccades")

Plot group mean lateral saccade variability as change from baseline

plot_group_var_lateral <- ggplot(filter(varMeanBaseline, type == "lateral"), aes(leg, std.deviation.x.baseline)) +
  geom_hline(yintercept = 0, linetype = "dashed", size = base_line_size) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "line", position = position_dodge(width = 0.5), size = .75) + 
  stat_summary(fun.data = mean_cl_normal, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "linerange", position = position_dodge(width = 0.5), show.legend = FALSE) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, shape = stimulation), geom = "point", position = position_dodge(width = 0.5), size = 2) +
  geom_text(data = subset(baselineLabelVar, type=="lateral"), aes(y = c(.05,.025,.1,.075), label=(std.deviation.x.baseline), color = stimulation), position = position_dodge(width = 0.5), size = mm_to_pt) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_colour_manual(values = c("#F25F5C", "#4B93B1")) +
  scale_y_continuous(expression("SD change from baseline " ( degree)), breaks = seq(-.2,.2,.1)) +
  coord_cartesian(ylim = c(-.2,.2)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank())

Plot group mean center saccade variability as change from baseline

plot_group_var_center <- ggplot(filter(varMeanBaseline, type == "center"), aes(leg, std.deviation.x.baseline)) +
  geom_hline(yintercept = 0, linetype = "dashed", size = base_line_size) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "line", position = position_dodge(width = 0.5), size = .75) + 
  stat_summary(fun.data = mean_cl_normal, aes(group = interaction(stimulation, direction), color = stimulation, linetype = direction), geom = "linerange", position = position_dodge(width = 0.5), show.legend = FALSE) +
  stat_summary(fun.y = mean, aes(group = interaction(stimulation, direction), color = stimulation, shape = stimulation), geom = "point", position = position_dodge(width = 0.5), size = 2) +
  geom_text(data = subset(baselineLabelVar, type=="center"), aes(y = c(.05,.025,.1,.075), label=(std.deviation.x.baseline), color = stimulation), position = position_dodge(width = 0.5), size = mm_to_pt) +
  scale_colour_manual(values = c("#F25F5C", "#4B93B1")) +
  scale_x_discrete("time", labels = c("baseline", "tDCS", "post-1", "post-2")) +
  scale_y_continuous(expression("SD change from baseline " ( degree)), breaks = seq(-.2,.2,.1)) +
  coord_cartesian(ylim = c(-.2,.2)) +
  theme(axis.text.x = element_text(angle = 22, vjust = .5), axis.title.x = element_blank())

Combine all the plots:

legend_fig7 <- get_legend(plot_group_acc_lateral)
figure_7 <- plot_grid(
  plot_sub_var_lateral, plot_sub_var_center,
  plot_group_var_lateral + theme(legend.position = "none"),
  plot_group_var_center + theme(legend.position = "none"), rel_heights = c(1,.75))
figure_7 <- plot_grid(figure_7,legend_fig7,rel_widths = c(1,1/10))
figure_7

Save the plot:

ggsave("fig/figure_7.pdf", plot = figure_7, width = 180, height = 112.5, units = "mm")
ggsave("fig/figure_7.png", plot = figure_7, width = 180, height = 112.5, units = "mm")

Statistics

Baseline tests

varMeanLeg %>%
  filter(leg == "baseline") %>%
  group_by(direction,type) %>% 
  nest() %>% 
  mutate(stats = map(data, ~t.test(formula = std.deviation.x~stimulation, paired = TRUE, data =.))) %>% # run t-test on the data frames
  mutate(tidy_model = map(stats, tidy)) %>%
  unnest(tidy_model, .drop = TRUE) %>% 
  kable(.)
direction type estimate statistic p.value parameter conf.low conf.high method alternative
left lateral -0.0046841 -0.0964036 0.9239687 25 -0.1047541 0.0953859 Paired t-test two.sided
left center -0.0436919 -0.9898113 0.3317503 25 -0.1346033 0.0472195 Paired t-test two.sided
right lateral -0.0130790 -0.2683130 0.7906600 25 -0.1134716 0.0873137 Paired t-test two.sided
right center -0.0597899 -1.3048234 0.2038368 25 -0.1541625 0.0345827 Paired t-test two.sided

Lateral saccades

Classical ANOVA

Repeated measures ANOVA matching Kanai et al. (2012).

Data: Baseline subtracted, lateral saccades

Dependent measure: saccade endpoint variability (x-coordinate standard deviation)

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (tDCS, post.1, post.2)
  • DIRECTION (left vs. right)

Prepare data:

meanVarLateralStats <- varMeanBaseline %>%
  ungroup() %>%
  filter(leg != "baseline", type == "lateral") %>%
  select(-type) %>%
  mutate(leg = factor(leg, levels = c("tDCS", "post.1", "post.2"))) %>%
  mutate(subject = factor(subject))
aovMeanVarLateral <- ezANOVA(data = data.frame(meanVarLateralStats), dv = std.deviation.x.baseline, wid = subject, within = .(stimulation,leg,direction), type = 3)
kable(aovMeanVarLateral$ANOVA)

Effect DFn DFd F p p<.05 ges
2 stimulation 1 25 1.2189602 0.2800786 0.0138324
3 leg 2 50 0.4518157 0.6390443 0.0011604
4 direction 1 25 0.2471961 0.6234009 0.0010690
5 stimulation:leg 2 50 1.1183082 0.3348684 0.0030580
6 stimulation:direction 1 25 0.1204196 0.7314841 0.0004919
7 leg:direction 2 50 0.9403214 0.3972980 0.0023341
8 stimulation:leg:direction 2 50 0.1873223 0.8297557 0.0003276

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

Effect W p p<.05
3 leg 0.994425 0.9351138
5 stimulation:leg 0.994966 0.9412372
7 leg:direction 0.908637 0.3167270
8 stimulation:leg:direction 0.903796 0.2970605

kable(aovMeanVarLateral$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
3 leg 0.9944559 0.6379765 1.0801686 0.6390443
5 stimulation:leg 0.9949912 0.3346792 1.0808237 0.3348684
7 leg:direction 0.9162854 0.3907925 0.9851512 0.3961957
8 stimulation:leg:direction 0.9122389 0.8102650 0.9802676 0.8255939
Bayesian ANOVA

Same design as the classical ANOVA

Bayes factors agains the null model:

bfMeanVarLateral = anovaBF(std.deviation.x.baseline~stimulation*leg*direction+subject, data = data.frame(meanVarLateralStats), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000)
bfMeanVarLateral = sort(bfMeanVarLateral, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfMeanVarLateral), bf)) # show only the Bayes factors in a table
bf
stimulation + subject 1.6368279
stimulation + direction + subject 0.2417691
direction + subject 0.1488644
stimulation + leg + subject 0.0689523
stimulation + direction + stimulation:direction + subject 0.0457505
leg + subject 0.0424994
stimulation + direction + leg + subject 0.0102944
stimulation + leg + stimulation:leg + subject 0.0071935
direction + leg + subject 0.0063189
stimulation + direction + stimulation:direction + leg + subject 0.0020441
stimulation + direction + leg + stimulation:leg + subject 0.0011732
stimulation + direction + leg + direction:leg + subject 0.0009725
direction + leg + direction:leg + subject 0.0006015
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 0.0002020
stimulation + direction + stimulation:direction + leg + direction:leg + subject 0.0001766
stimulation + direction + leg + stimulation:leg + direction:leg + subject 0.0000997
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 0.0000248
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.0000022

Inclusion Bayes factor across matched models:

kable(inclusionBF(bfMeanVarLateral, models = "matched"))
effect Bayes.factor
stimulation 1.6346841
direction 0.1482214
stimulation:direction 0.1895258
leg 0.0423365
stimulation:leg 0.1054485
direction:leg 0.0935982
stimulation:direction:leg 0.0890821

Center saccades

Classical ANOVA

Repeated measures ANOVA matching Kanai et al. (2012).

Data: Baseline subtracted, center saccades

Dependent measure: saccade endpoint variability (x-coordinate standard deviation)

Factors:

  • STIMULATION (anodal vs. cathodal)
  • LEG (tDCS, post.1, post.2)
  • DIRECTION (left vs. right)

Prepare data:

meanVarCenterStats <- varMeanBaseline %>%
  ungroup() %>%
  filter(leg != "baseline", type == "center") %>%
  select(-type) %>%
  mutate(leg = factor(leg, levels = c("tDCS", "post.1", "post.2"))) %>%
  mutate(subject = factor(subject))
aovMeanVarCenter <- ezANOVA(data = data.frame(meanVarCenterStats), dv = std.deviation.x.baseline, wid = subject, within = .(stimulation,leg,direction), type = 3)
kable(aovMeanVarCenter$ANOVA)

Effect DFn DFd F p p<.05 ges
2 stimulation 1 25 3.8851203 0.0598820 0.0399400
3 leg 2 50 2.7073528 0.0764935 0.0075993
4 direction 1 25 0.6021177 0.4450504 0.0033319
5 stimulation:leg 2 50 1.1805422 0.3155254 0.0036640
6 stimulation:direction 1 25 0.1745759 0.6796436 0.0010192
7 leg:direction 2 50 2.1601871 0.1259451 0.0035285
8 stimulation:leg:direction 2 50 0.4735067 0.6255786 0.0007475

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

Effect W p p<.05
3 leg 0.8960127 0.2677749
5 stimulation:leg 0.8569616 0.1568686
7 leg:direction 0.6679634 0.0078892 *
8 stimulation:leg:direction 0.8089994 0.0785921

kable(aovMeanVarCenter$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
3 leg 0.9058075 0.0824883 0.9725125 0.0781996
5 stimulation:leg 0.8748612 0.3116036 0.9353175 0.3136546
7 leg:direction 0.7507301 0.1405427 0.7880908 0.1383445
8 stimulation:leg:direction 0.8396302 0.5929099 0.8932129 0.6044505
Bayesian ANOVA

Same design as the classical ANOVA

Bayes factors agains the null model:

bfMeanVarCenter = anovaBF(std.deviation.x.baseline~stimulation*leg*direction+subject, data = data.frame(meanVarCenterStats), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000)
bfMeanVarCenter = sort(bfMeanVarCenter, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfMeanVarCenter), bf)) # show only the Bayes factors in a table
bf
stimulation + subject 143.7876035
stimulation + direction + subject 31.3002062
stimulation + leg + subject 17.5164038
stimulation + direction + stimulation:direction + subject 6.7862297
stimulation + direction + leg + subject 3.8038501
stimulation + leg + stimulation:leg + subject 1.9714300
stimulation + direction + stimulation:direction + leg + subject 0.7871364
stimulation + direction + leg + stimulation:leg + subject 0.4324661
stimulation + direction + leg + direction:leg + subject 0.4314291
direction + subject 0.2146647
leg + subject 0.1156607
stimulation + direction + stimulation:direction + leg + direction:leg + subject 0.1042781
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject 0.0871906
stimulation + direction + leg + stimulation:leg + direction:leg + subject 0.0449988
direction + leg + subject 0.0257119
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject 0.0097944
direction + leg + direction:leg + subject 0.0026869
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject 0.0011799

Inclusion Bayes factor across matched models:

kable(inclusionBF(bfMeanVarCenter, models = "matched"))
effect Bayes.factor
stimulation 144.8708224
direction 0.2176328
stimulation:direction 0.2158843
leg 0.1215190
stimulation:leg 0.1124351
direction:leg 0.1154880
stimulation:direction:leg 0.1204699
Follow-up tests
Main effect of stimulation

Follow-up One-sample t-test:

meanVarCenterStats %>%
  group_by(stimulation,subject) %>% # for each session and subject
  summarise(std.deviation.x. = mean(std.deviation.x.baseline)) %>% # 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 0.0477794 1.683151 0.1047947 25 -0.0106845 0.1062434 One Sample t-test two.sided
cathodal -0.0340719 -1.236236 0.2278603 25 -0.0908350 0.0226911 One Sample t-test two.sided

Follow-up Bayesian one-sample t-test:

meanVarCenterStats %>%
  group_by(stimulation,subject) %>% # for each session and subject
  summarise(std.deviation.x = mean(std.deviation.x.baseline)) %>% # average over all other variables
  spread(stimulation, std.deviation.x) %>% # 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.7138830
cathodal 0.4103342

Quantile analysis

See the RT_quantiles.html notebook for more explanation and exploration of the saccade latency distribution data

Estimate quantiles and compute shift function:

qData <- groupData %>%
  filter(!is.na(latency)) %>% # discard missing saccades
  group_by(subject,leg,type,direction) %>% # for each condition
  nest(stimulation,latency) %>% # make a list_column "data" out of the stimulation and latency columns. Now, each group has its own data frame consisting of the stimulation and latency columns for that group
  mutate(shift = purrr::map(data, ~ shiftdhd_pbci(., formula = latency ~ stimulation, nboot = 2000))) # for each group, estimate quantiles and compute shift function, and store as a list column in "shift"

qData <- unnest(qData,shift) # unpack the list column to get the model results for each group in the original data frame

# Alternatively, instead of "nest ...", "mutate ..." and "unnest ...", you can call shiftdhd through dplyr::do (but this is basically depreated in favor of purrr:map)
# do(shiftdhd(.[,c("stimulation","latency")], formula = latency ~ stimulation, nboot = 100)) # estimate quantiles and compute shift function

Note that this takes quite a while to compute with a large number of bootstrap samples, so we will load the result from disk in the next code chunk. By default, the chunk above will not run becuase of the eval=FALSE statement; remove this to execute it and compute the result from scratch.

qData <- read_csv(here("data", "sacc-tDCS_quantiles.csv")) %>%
  filter(!(subject %in% subs2exclude)) %>% # exclude subjects
    mutate(leg = replace(leg, leg == "pre", "baseline"), # rename and reoder levels
         leg = replace(leg, leg == "post.1", "post-1"),
         leg = replace(leg, leg == "post.2", "post-2"),
         leg = factor(leg, levels = c("baseline", "tDCS", "post-1", "post-2")))
  
qStats <- qData %>%
  group_by(subject,leg,type,direction) %>%
  mutate(deco = c(seq(1,5),seq(4,1))) %>% # add code of deciles to data frame
  group_by(leg,type,direction,q) %>% 
  mutate(anodal = mean(anodal)) %>% # mean of "anodal" quantiles OVER subjects
  group_by(leg,type,direction) %>% 
  mutate(anodal_median = median(anodal)) # median for plotting

For each quantile, count which subjects show significant effects, and in which direction

qSig <- qData %>%
  group_by(subject,leg,type,direction,q) %>%
  mutate(significance = NA,
         # If (anodal - cathodal) quantile difference is positive, latency for anodal > latency for cathodal
         significance = replace(significance, p_value < p_crit & difference > 0, "cathodal.faster"),
         # If (anodal - cathodal) quantile difference is negative, latency for anodal < latency for cathodal
         significance = replace(significance, p_value < p_crit & difference < 0, "anodal.faster")
  )

Figure 5

Shift functions for lateral saccades

plot_shift_lateral <- ggplot(filter(qStats, type == "lateral"), aes(anodal, difference)) +
   facet_grid(leg ~ direction) +
   geom_hline(yintercept = 0, linetype = "dashed", alpha = 0.5) +
   geom_vline(aes(xintercept = anodal_median), linetype = "dashed", alpha = 0.5) +
   stat_summary(fun.data = mean_cl_normal, geom = "linerange", colour = "black", size = 0.5) +
   stat_summary(fun.y = mean, geom = "line", size = 1, colour = "grey50", alpha = 0.5) +
   stat_summary(fun.y = mean, geom = "point", aes(fill = deco), size = 2, colour = "black", shape = 21) +
   scale_fill_gradient(low = "white", high = "grey30", guide = FALSE) +
   scale_x_continuous("anodal deciles (ms)", limits = c(80,200), breaks = seq(100,200,25)) +
   scale_y_continuous("anodal - cathodal deciles (ms)")

Number of subjects with signifcant difference per quantile for lateral saccades

plot_sig_lateral <- ggplot(filter(qSig, type == "lateral", !is.na(significance)), aes(q, fill = significance)) +
  facet_grid(leg ~ direction) +
  geom_bar(position = "stack") +
  stat_bin(binwidth = .1, geom = "text", size = mm_to_pt, aes(label = ..count..), position = position_stack(vjust = 0.5)) +
  scale_fill_manual(values = c("#F25F5C", "#4B93B1")) +
  scale_x_continuous("decile", breaks = seq(0.1,0.9,0.1), labels = seq(1,9,1)) +
  scale_y_continuous("number of participants with significant difference", limits = c(0, length(unique(qSig$subject))), breaks = c(0,10,20,length(unique(qSig$subject))))

Shift functions for center saccades

plot_shift_center <- ggplot(filter(qStats, type == "center"), aes(anodal, difference)) +
   facet_grid(leg ~ direction) +
   geom_hline(yintercept = 0, linetype = "dashed", alpha = 0.5) +
   geom_vline(aes(xintercept = anodal_median), linetype = "dashed", alpha = 0.5) +
   stat_summary(fun.data = mean_cl_normal, geom = "linerange", colour = "black", size = 0.5) +
   stat_summary(fun.y = mean, geom = "line", size = 1, colour = "grey50", alpha = 0.5) +
   stat_summary(fun.y = mean, geom = "point", aes(fill = deco), size = 2, colour = "black", shape = 21) +
   scale_fill_gradient(low = "white", high = "grey30", guide = FALSE) +
   scale_x_continuous("anodal deciles (ms)", limits = c(80,200), breaks = seq(100,200,25)) +
   scale_y_continuous("anodal - cathodal deciles (ms)")

Number of subjects with signifcant difference per quantile for lateral saccades

plot_sig_center <- ggplot(filter(qSig, type == "center", !is.na(significance)), aes(q, fill = significance)) +
  facet_grid(leg ~ direction) +
  geom_bar(position = "stack") +
  stat_bin(binwidth = .1, geom = "text", size = mm_to_pt, aes(label = ..count..), position = position_stack(vjust = 0.5)) +
  scale_fill_manual(values = c("#F25F5C", "#4B93B1")) +
  scale_x_continuous("decile", breaks = seq(0.1,0.9,0.1), labels = seq(1,9,1)) +
  scale_y_continuous("number of participants with significant difference", limits = c(0, length(unique(qSig$subject))), breaks = c(0,10,20,length(unique(qSig$subject))))
figure_5_lateral <- plot_grid(plot_shift_lateral, plot_sig_lateral + theme(legend.position = "none"), rel_widths = c(1.33,1)) # top row
figure_5_center <- plot_grid(plot_shift_center,plot_sig_center + theme(legend.position = "none"), rel_widths = c(1.33,1)) # bottom row
#title objects
title_lateral <- ggdraw() + draw_label("Lateral saccades", fontface = 'bold', size = base_font_size)
title_center <- ggdraw() + draw_label("Center saccades", fontface = 'bold', size = base_font_size)
#combine with titles
figure_5_lateral <- plot_grid(title_lateral, figure_5_lateral, ncol = 1, rel_heights = c(0.05, 1))
figure_5_center <- plot_grid(title_center, figure_5_center, ncol = 1, rel_heights = c(0.05, 1))
figure_5 <- plot_grid(figure_5_lateral, figure_5_center, nrow = 2)
figure_5

Save the plot:

ggsave("fig/figure_5.pdf", plot = figure_5, width = 180, height = 180, units = "mm")
ggsave("fig/figure_5.png", plot = figure_5, width = 180, height = 180 , units = "mm")

Supplementary results

tDCS adverse effect questionnaire

See the questionnaires.html notebook for more explanation and exploration of the questionnaire data

# Load the data frame
dataFile <- here("data", "tdcs_sensations.csv")
sensData <- read_csv2(dataFile, col_types = cols(
  session = col_factor(c("first","second")),
  stimulation = col_factor(c("anodal","cathodal"))
))
kable(head(sensData)) # show data frame
subject session stimulation itching tingling burning pain headache fatigue dizziness nausea conf.itching conf.tingling conf.burning conf.pain conf.headache conf.fatigue conf.dizziness conf.nausea felt.more
S01 first cathodal 2 4 4 2 0 0 0 0 3 4 4 4 0 0 0 0 cathode
S01 second anodal 1 1 1 0 0 1 0 0 4 4 4 0 0 1 0 0 anode
S02 first anodal 1 2 2 0 0 1 0 0 4 4 4 0 0 1 0 0 anode
S02 second cathodal 1 2 2 0 0 0 0 0 4 4 4 0 0 0 0 0 equal
S03 first cathodal 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 equal
S03 second anodal 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 equal

Participants were asked to which degree the following sensations were present during stimulation: tingling, itching sensation, burning sensation, pain, headache, fatigue, dizziness and nausea. Each was rated on a scale from 0-4:

  1. none
  2. a little
  3. moderate
  4. strong
  5. very strong

They also rated their confidence that the sensations were caused by the stimulation on a scale from 0-4 (columns starting with conf.):

  1. n/a (meaning they rated the sensation a 0 on the previous scale)
  2. unlikely
  3. possibly
  4. likely
  5. very likely

Factors:

  • subject: subject ID (S01, S02, etc)
  • session: Whether data are from the first or second session
  • stimulation: Whether data are from the anodal or cathodal session

Calculate how many anodal and cathodal sessions were rated:

idxComplete <- rowSums(is.na(sensData)) != ncol(sensData) - 3 # rows that do not have all NAs (except the 3 factor columns)
# calculate number of questionnaires completed per stimulation type
nAnodal <- sum(sensData$stimulation == "anodal" & idxComplete)
nCathodal <- sum(sensData$stimulation == "cathodal" & idxComplete)

Figure S1

Prepare the sensation intensity and confidence ratings.

# Make long form data frame of sensation intensity
ratings <- sensData %>%
  select(everything(), -contains("conf"), -felt.more) %>% # drop other columns
  gather(sensation, rating, itching:nausea) # make long form
# Make long form data frame of sensation confidence
confidence <- sensData %>%
  select(contains("conf"), subject, session, stimulation) %>% 
  gather(sensation, confidence, conf.itching:conf.nausea) %>%
  mutate(sensation = str_replace(sensation, "conf.", "")) # get rid of "conf." prefix so it matches the sensation intensity tibble
# Join the two data frames
sensDataLong <- dplyr::full_join(ratings,confidence)

Make plot of sensation distribution:

plot_sensation <- ggplot(sensDataLong, aes(rating, fill = stimulation)) +
    facet_wrap(~sensation, nrow = 1) +
    geom_bar(position = "stack") +
    stat_bin(binwidth = 1, geom = "text", size = mm_to_pt, aes(label = ..count..), position = position_stack(vjust = 0.5)) +
    scale_fill_manual(values = c("#F25F5C", "#4B93B1")) +
    xlim(0.5,4.5) + # exclude "0" ratings that were not present
    ylim(0,35) + # bound plot at max number of ratings
    ylab("number of sessions") +
  ggtitle("Sensation intensity")

Make plot of confidence distribution:

plot_confidence <- ggplot(sensDataLong, aes(confidence, fill = stimulation)) +
    facet_wrap(~sensation, nrow = 1) +
    geom_bar(position = "stack") +
    stat_bin(binwidth = 1, geom = "text", size = mm_to_pt, aes(label = ..count..), position = position_stack(vjust = 0.5)) +
    scale_fill_manual(values = c("#F25F5C", "#4B93B1")) +
    xlim(0.5,4.5) +
    ylim(0,35) +
    xlab("ratings") +
    ylab("number of sessions") +
    ggtitle("Confidence")

Put together and show plot:

legend_S1 <- get_legend(plot_sensation)
figure_S1 <- plot_grid(
  plot_sensation + theme(legend.position = "none"),
  plot_confidence + theme(legend.position = "none"),
  nrow = 2)
figure_S1 <- plot_grid(figure_S1,legend_S1, rel_widths = c(1,1/10))
figure_S1

Save the plot:

ggsave("fig/figure_S1.pdf", plot = figure_S1, width = 180, height = 112.5, units = "mm")
ggsave("fig/figure_S1.png", plot = figure_S1, width = 180, height = 112.5, units = "mm")

Statistics

Mann-Whitney U tests for difference in sensation intensity ratings between anodal and cathodal sessions.

sensationList <- c("itching", "tingling", "burning", "pain", "headache", "fatigue", "dizziness", "nausea")
senseTests <- data.frame(sensation = sensationList, p.value = NA) # initialize results data frame
for (item in sensationList) {
  testData <- sensData[[item]] # extract column with test dat
  tmp <- wilcox.test(testData[sensData$stimulation == "anodal"], testData[sensData$stimulation == "cathodal"])
  senseTests$p.value[senseTests$sensation %in% item] <- tmp$p.value # put p-value in row of results data frame
}
kable(senseTests)
sensation p.value
itching 0.5787360
tingling 0.3652154
burning 0.1913439
pain 0.9287263
headache 0.9648458
fatigue 0.4330014
dizziness 0.7203021
nausea NaN

Note that the p-value for “nausea” is undefined because it was never reported (i.e. all ranks are tied at 0).

Frontal eye field coordinates

See the frontal_eye_field.html notebook for more explanation and exploration of the frontal eye field coordinate data

Native space

These were determined for each subject’s scan; see neuronav_notes.md for further info.

dataFile <- here("data", "FEF_coords_native.csv")
nativeCoords <- read_csv2(dataFile)
nativeCoords %>% 
  select(-folder, -scan) %>% # drop columns with folder and scan names
  filter(!(subject %in% subs2exclude)) %>% # drop rows with excluded subjects
  kable(.)
subject native.X native.Y native.Z
S01 96 132 137
S02 89 118 132
S03 153 124 177
S04 96 127 131
S05 93 116 138
S06 101 131 182
S07 92 127 147
S08 101 123 159
S09 99 125 158
S10 94 124 125
S11 147 123 149
S12 97 121 176
S13 144 125 140
S14 87 122 129
S15 118 111 125
S17 161 135 175
S18 153 147 173
S19 146 155 172
S20 78 124 99
S24 160 134 141
S26 156 141 150
S27 148 122 156
S29 90 131 153
S30 95 125 149
S32 147 140 146
S33 159 149 168

MNI space (Table S1)

Load in the coordinates that were transformed to MNI space.

Table S1

dataFile <- here("data", "FEF_coords_MNI.csv")
mniCoords <- read_delim(dataFile, ";")
mniCoords <- filter(mniCoords, !(subject %in% subs2exclude)) # exclude subjects
mniCoords %>%
  select(-folder, -scan) %>% # drop columns with folder and scan names
  kable(.)
subject MNI_X MNI_Y MNI_Z
S01 29.4081 1.069700 54.8724
S02 33.0338 -2.245090 50.4239
S03 30.5837 -1.480360 50.5881
S04 25.7061 -3.761730 56.3648
S05 29.7780 -5.201110 55.8046
S06 29.7783 -1.120820 58.2622
S07 38.1233 2.975730 45.9613
S08 31.5014 0.526375 45.6200
S09 28.5103 3.632940 51.2804
S10 28.1080 -1.933630 50.7210
S11 30.5811 -3.787490 51.9535
S12 36.5129 -0.386049 46.7630
S13 26.2263 -1.069220 54.7079
S14 37.5005 -1.588150 52.5889
S15 31.8188 -8.357000 58.9671
S17 31.0229 -5.121250 54.3116
S18 34.9669 8.390570 49.8188
S19 28.0703 -3.834910 52.7607
S20 41.2127 -1.745790 47.5514
S24 37.3474 -0.862753 43.4371
S26 34.3288 -2.861210 49.1761
S27 27.6566 -10.061100 50.9743
S29 30.3161 -5.272910 55.2661
S30 26.8320 -3.868670 54.5619
S32 29.0049 4.888810 49.1404
S33 30.3099 -3.897600 50.9083

Descriptives

Calculate descriptive statistics over subjects:

mniCoords %>%
  gather(dimension, coord, MNI_X:MNI_Z) %>%
  group_by(dimension) %>%
  summarise_at(vars(coord), funs(mean, min, max, sd)) %>% 
  kable(.)
dimension mean min max sd
MNI_X 31.470735 25.7061 41.21270 4.036810
MNI_Y -1.806643 -10.0611 8.39057 3.931623
MNI_Z 51.645608 43.4371 58.96710 3.922225
LS0tCnRpdGxlOiAiTm8gZXZpZGVuY2UgdGhhdCBmcm9udGFsIGV5ZSBmaWVsZCB0RENTIGFmZmVjdHMgbGF0ZW5jeSBvciBhY2N1cmFjeSBvZiBwcm9zYWNjYWRlcyIKYXV0aG9yOiAiTGVvbiBSZXRlaWcsIFRvbWFzIEtuYXBlbiwgUmljaGFyZCBSaWRkZXJpbmtob2YsIEhlbGVlbiBTbGFndGVyIgpvdXRwdXQ6CiAgZ2l0aHViX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KCmBgYHtyIHNldHVwfQojIExvYWQgc29tZSBsaWJyYXJpZXMKbGlicmFyeShoZXJlKSAjIGZpbGUgcGF0aHMKbGlicmFyeSh0aWR5dmVyc2UpICMgaW1wb3J0aW5nLCB0cmFuc2Zvcm1pbmcsIGFuZCB2aXN1YWxpemluZyBkYXRhIGZyYW1lcwpsaWJyYXJ5KHN0cmluZ3IpICMgbWFuaXB1bGF0aW5nIHN0cmluZ3MKbGlicmFyeShicm9vbSkgIyAjIHRyYW5zZm9ybSBtb2RlbCBvdXRwdXQgaW50byBhIGRhdGEgZnJhbWUKbGlicmFyeShjb3dwbG90KSAjIGZvcm1hdHRpbmcgcGxvdHMKbGlicmFyeShrbml0cikgIyBSIG5vdGVib29rIG91dHB1dApsaWJyYXJ5KGV6KSAjIGNsYXNzaWNhbCBBTk9WQQpsaWJyYXJ5KEJheWVzRmFjdG9yKSAjIEJheWVzaWFuIHN0YXRpc3RpY3MKbGlicmFyeShyb2dtZSkgIyBzaGlmdCBmdW5jdGlvbnMKCiMgc2V0IGRlZmF1bHQgb3V0cHV0IGFuZCBmaWd1cmUgb3B0aW9ucwprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGZpZy53aWR0aCA9IDcsIGZpZy5hc3AgPSAwLjYxOCwgb3V0LndpZHRoID0gIjc1JSIsIGZpZy5hbGlnbiA9ICJjZW50ZXIiKQoKc291cmNlKGhlcmUoInNyYyIsICJsaWIiLCAiSW5jbHVzaW9uQkYuUiIpKQpwcmludChzZXNzaW9uSW5mbygpKQpgYGAKCmBgYHtyIE1ha2UgcGxvdCB0aGVtZX0KYmFzZV9mb250X3NpemUgPC0gOAptbV90b19wdCA8LSA3ICogMC4zNSAjIHNvIGdlb21fdGV4dCBzaXplIGlzIHNhbWUgYXMgYXhpcyB0ZXh0CmJhc2VfZm9udF9mYW1pbHkgPC0gIkhlbHZldGljYSIKYmFzZV9saW5lX3NpemUgPC0gLjI1CnRoZW1lX2N1c3RvbSA8LSB0aGVtZV9jb3dwbG90KGZvbnRfc2l6ZSA9IGJhc2VfZm9udF9zaXplLCBmb250X2ZhbWlseSA9IGJhc2VfZm9udF9mYW1pbHksIGxpbmVfc2l6ZSA9IGJhc2VfbGluZV9zaXplKQp0aGVtZV9zZXQodGhlbWVfY3VzdG9tKQpgYGAKCiMgR3JvdXAgYW5hbHlzZXMgCgojIyBMb2FkIGRhdGEKCkFsbCAobWV0YSlkYXRhIGFyZSBzdG9yZWQgYXMgYC5jc3ZgIGZpbGVzIGluIHRoZSBgL2RhdGFgIGZvbGRlci4KCiMjIyBFeWUgdHJhY2tpbmcgZGF0YQoKSGVyZSB3ZSBsb2FkIHRoZSBgLmNzdmAgZmlsZSB3aXRoIHRoZSBwcm9jZXNzZWQgZXllIHRyYWNraW5nIGRhdGEsIHdoaWNoIHdhcyBjcmVhdGVkIGluIE1BVExBQi4gVG8gcmVjcmVhdGUgaXQgZnJvbSB0aGUgcmF3IGRhdGEsIHJ1biB0aGUgYGFuYWx5c2lzLm1gIHNjcmlwdC4gVGhpcyBzY3JpcHRzIGNhbGxzIHRoZSBgcHJvY2Vzc0VERi5tYCBmdW5jdGlvbiB0byBwYXJzZSB0aGUgcmF3IGV5ZSB0cmFja2luZyBkYXRhLgoKYGBge3IgTG9hZCBleWUgdHJhY2tpbmcgZGF0YX0KIyBMb2FkIGV5ZSB0cmFja2luZyBkYXRhIGludG8gZGF0YSBmcmFtZQpkYXRhRmlsZSA8LSBoZXJlKCJkYXRhIiwgInNhY2MtdERDU19kYXRhLmNzdiIpCmdyb3VwRGF0YSA8LSByZWFkX2NzdihkYXRhRmlsZSwgY29sX25hbWVzID0gVFJVRSwgbmEgPSAiTmFOIiwgcHJvZ3Jlc3MgPSBGQUxTRSwgY29sX3R5cGVzID0gY29scygKICBzdGltdWxhdGlvbiA9IGNvbF9mYWN0b3IoYygiYW5vZGFsIiwiY2F0aG9kYWwiKSksCiAgbGVnID0gY29sX2ZhY3RvcihjKCJwcmUiLCJ0RENTIiwicG9zdCIpKSwKICB0eXBlID0gY29sX2ZhY3RvcihjKCJsYXRlcmFsIiwiY2VudGVyIikpLAogIGRpcmVjdGlvbiA9IGNvbF9mYWN0b3IoYygibGVmdCIsInJpZ2h0IikpIAopKQpgYGAKCmBgYHtyIFNob3cgZXllIHRyYWNraW5nIGRhdGEgZnJhbWV9CmthYmxlKGhlYWQoZ3JvdXBEYXRhKSkKYGBgCgoqIF9fc3ViamVjdF9fOiBzdWJqZWN0IElECiogX19zdGltdWxhdGlvbl9fOiBXaGV0aGVyIGRhdGEgYXJlIGZyb20gdGhlIGBhbm9kYWxgIG9yIGBjYXRob2RhbGAgc2Vzc2lvbgoqIF9fbGVnX186IFdoZXRoZXIgZGF0YSBhcmUgYmVmb3JlIChgcHJlYCksIGR1cmluZyAoYHREQ1NgKSwgb3IgYWZ0ZXIgKGBwb3N0YCkgdERDUwoqIF9fYmxvY2tfXzogQWZ0ZXIgZWFjaCBibG9jayBwYXJ0aWNpcGFudCBoYWQgYSBicmllZiBicmVhayBhbmQgdHJhY2tlciB3YXMgcmVjYWxpYnJhdGVkCiogX190cmlhbF9fOiB0cmlhbCBudW1iZXIgd2l0aGluIGEgYmxvY2sKKiBfX3R5cGVfXzoKICAgICogYGxhdGVyYWxgIC0gZml4YXRpb24gaW4gY2VudGVyIG9mIGRpc3BsYXksIHNhY2NhZGUgbWFkZSB0b3dhcmRzIHRoZSBwZXJpcGhlcnkKICAgICogYGNlbnRlcmAgLSBmaXhhdGlvbiBpbiBwZXJpcGhlcnksIHNhY2NhZGUgbWFkZSBiYWNrIHRvd2FyZHMgdGhlIGNlbnRlciBvZiB0aGUgZGlzcGxheQoqIF9fZGlyZWN0aW9uX186IGBsZWZ0YCBmb3Igc2FjY2FkZXMgdG93YXJkcyB0aGUgbGVmdCBvZiBjdXJyZW50IGZpeGF0aW9uIHBvc2l0aW9uOyBgcmlnaHRgIGZvciBzYWNjYWRlcyB0byB0aGUgcmlnaHQKKiBfX2RldmlhdGlvbi5zdGFydF9fIDogZGlzdGFuY2UgKGluIHZpc3VhbCBhbmdsZSkgZnJvbSBzYWNjYWRlIHN0YXJ0IHBvaW50IHRvIGZpeGF0aW9uCiogX19kZXZpYXRpb24uZW5kLnhfXzogZGlzdGFuY2UgKGluIHZpc3VhbCBhbmdsZSkgZnJvbSB4LWNvb3JkaW5hdGUgb2Ygc2FjY2FkZSBlbmQgcG9pbnQgdG8geC1jb29yZGluYXRlIG9mIHRhcmdldCBsb2NhdGlvbgoqIF9fZGV2aWF0aW9uLmVuZC55X186IHNhbWUgZm9yIHktY29vcmRpbmF0ZQoqIF9fYW1wbGl0dWRlX186IGRpc3RhbmNlIChpbiB2aXN1YWwgYW5nbGUpIGJldHdlZW4gc2FjY2FkZSBzdGFydCBhbmQgZW5kIHBvaW50CiogX19sYXRlbmN5X186IHRpbWUgKGluIG1zKSBmcm9tIHRhcmdldCBvbnNldCB0byBzdGFydCBvZiBzYWNjYWRlCiogX19kcmlmdC54X186IGRpc3RhbmNlIChpbiB2aXN1YWwgYW5nbGUpIGJldHdlZW4geC1jb29yZGluYXRlIG9mIGF2ZXJhZ2UgZml4YXRpb24gcG9zaXRpb24gZHVyaW5nIHRoZSBicmVhayB0byB4LWNvb3JkaW5hdGUgb2YgZml4YXRpb24gc3RpbXVsdXMuIFRoaXMgc3RpbXVsdXMgd2FzIGRpc3BsYXllZCBhdCBlYWNoIGJyZWFrIGluIHRoZSB0YXNrLCBzbyB0aGlzIGRhdGEgY2FuIGJlIHVzZWQgYXMgYW4gZXN0aW1hdGUgb2Ygb2Zmc2V0cyB0byBkbyBkcmlmdCBjb3JyZWN0aW9uLgoqIF9fZHJpZnQueV9fOiBzYW1lIGZvciB5LWNvb3JkaW5hdGUKCiMjIyBNZXRhZGF0YQoKIyMjIyBTZXNzaW9uIGluZm8KCmBgYHtyIExvYWQgc2Vzc2lvbiBpbmZvIGRhdGF9CiMgTG9hZCBleWUgdHJhY2tpbmcgZGF0YSBpbnRvIGRhdGEgZnJhbWUKZGF0YUZpbGUgPC0gaGVyZSgiZGF0YSIsICJzZXNzaW9uX2luZm8uY3N2IikKc2Vzc2lvbkRhdGEgPC0gcmVhZF9jc3YyKGRhdGFGaWxlLCBjb2xfbmFtZXMgPSBUUlVFLCBwcm9ncmVzcyA9IEZBTFNFLCBjb2xfdHlwZXMgPSBjb2xzKAogIHNlc3Npb24gPSBjb2xfZmFjdG9yKGMoImZpcnN0Iiwic2Vjb25kIikpLAogIHN0aW11bGF0aW9uID0gY29sX2ZhY3RvcihjKCJhbm9kYWwiLCJjYXRob2RhbCIpKQopKQpgYGAKCmBgYHtyIFNob3cgc2Vzc2lvbiBpbmZvIGRhdGEgZnJhbWUsIHJlc3VsdHM9J2FzaXMnfQprYWJsZShoZWFkKHNlc3Npb25EYXRhKSkKYGBgCgoqIF9fc3ViamVjdF9fOiBzdWJqZWN0IElECiogX19zZXNzaW9uX186IFdoZXRoZXIgZGF0YSBhcmUgZnJvbSB0aGUgYGZpcnN0YCkgb3IgYHNlY29uZGAgc2Vzc2lvbgoqIF9fc3RpbXVsYXRpb25fXzogV2hldGhlciBkYXRhIGFyZSBmcm9tIHRoZSBgYW5vZGFsYCBvciBgY2F0aG9kYWxgIHNlc3Npb24KKiBfX2RhdGVfXzogWVkvTU0vREQgZGF0ZSB0aGUgc2Vzc2lvbiB0b29rIHBsYWNlCiogX19kYXlfXzogZGF5IG9mIHRoZSB3ZWVrIHRoZSBzZXNzaW9uIHRvb2sgcGxhY2UKKiBfX3RpbWVfXzogdGltZSBvZiBkYXkgdGhlIHNlc3Npb24gdG9vayBwbGFjZQoKIyMjIyBTdWJqZWN0IGluZm8KCmBgYHtyIExvYWQgc3ViamVjdCBpbmZvIGRhdGF9CiMgTG9hZCBleWUgdHJhY2tpbmcgZGF0YSBpbnRvIGRhdGEgZnJhbWUKZGF0YUZpbGUgPC0gaGVyZSgiZGF0YSIsICJzdWJqZWN0X2luZm8uY3N2IikKc3ViamVjdERhdGEgPC0gcmVhZF9jc3YyKGRhdGFGaWxlLCBjb2xfbmFtZXMgPSBUUlVFLCBwcm9ncmVzcyA9IEZBTFNFLCBjb2xfdHlwZXMgPSBjb2xzKAogIHNlc3Npb24ub3JkZXIgPSBjb2xfZmFjdG9yKGMoImZpcnN0LmFub2RhbCIsICJmaXJzdC5jYXRob2RhbCIpKQopKQpgYGAKCmBgYHtyIFNob3cgc3ViamVjdCBpbmZvIGRhdGEgZnJhbWUsIHJlc3VsdHM9J2FzaXMnfQprYWJsZShoZWFkKHN1YmplY3REYXRhKSkKYGBgCgoqIF9fc3ViamVjdF9fOiBzdWJqZWN0IElECiogX19zZXNzaW9uLm9yZGVyX186IFdoZXRoZXIgc3ViamVjdCBoYWQgYW5vZGFsIHN0aW11bGF0aW9uIGluIHRoZSBmaXJzdCBzZXNzaW9uIChgZmlyc3QuYW5vZGFsYCkgb3IgY2F0aG9kYWwgc3RpbXVsYXRpb24gaW4gdGhlIGZpcnN0IHNlc3Npb24gKGBmaXJzdC5jYXRob2RhbGApCiogX19nZW5kZXJfXwoqIF9fYWdlX186IGluIHllYXJzCiogX19kb21pbmFudC5leWVfXzogcmVzdWx0IG9mIGV5ZSBkb21pbmFuY2UgdGVzdAoKIyMgUHJlcHJvY2VzcyBleWUgZGF0YQoKX1NlZSB0aGUgYGluc3BlY3Rpb24ubmIuaHRtbGAgbm90ZWJvb2sgZm9yIG1vcmUgZXhwbGFuYXRpb24gYW5kIGV4cGxvcmF0aW9uIG9mIHByZXByb2Nlc3NpbmcsIG91dGxpZXIgc2FjY2FkZXMgYW5kIHN1YmplY3QgZXhjbHVzaW9uXwoKIyMjIFJlamVjdCBvdXRsaWVyIHNhY2NhZGVzCgpgYGB7ciBPdXRsaWVyIGNyaXRlcmlhfQp0b29GYXN0IDwtIDUwCnRvb1Nsb3cgPC0gNDAwCmJhZEZpeCA8LSAxLjgKYmFkU2FjYyA8LSA4CmBgYAoKQ3JpdGVyaWEgZm9yIG91dGxpZXJzOgoKKiBEaXNjYXJkIGZhc3Qgc2FjY2FkZXMsIHdpdGggYSBsYXRlbmN5IG9mIGByIHRvb0Zhc3RgIG1zIG9yIGxlc3MKKiBEaXNjYXJkIHNsb3cgc2FjY2FkZXMsIHNhY2NhZGVzIHdpdGggYSBsYXRlbmN5IG9mIGByIHRvb1Nsb3dgIG1zIG9yIG1vcmUKKiBEaXNjYXJkIGluYWNjdXJhdGUgZml4YXRpb25zLCB3aXRoIHNhY2NhZGUgc3RhcnRpbmcgcG9pbnQgbW9yZSB0aGFuIGByIGJhZEZpeGAgZGVncmVlcyBvciBtb3JlIGF3YXkgZnJvbSBmaXhhdGlvbgoqIERpc2NhcmQgZmF1bHR5IHNhY2NhZGVzLCB3aXRoIHgtY29vcmRpbmF0ZSBvZiBzYWNjYWRlIGVuZCBwb2ludCBgciBiYWRTYWNjYCBkZWdyZWUgb3IgbW9yZSBhd2F5IGZyb20gdGhlIHRhcmdldAoKYGBge3IgTWFyayBzYWNjYWRlcyBhcyBvdXRsaWVyc30KIyBNYXJrIG91dGxpZXJzCmdyb3VwRGF0YSA8LSBtdXRhdGUoZ3JvdXBEYXRhLCBvdXRsaWVyID0gIm5vbi5vdXRsaWVyIiwgIyBmaWxsIHZlY3RvciBmb3IgYWxsIHNhY2NhZGVzCiAgICAgICAgICAgICAgICAgICAgb3V0bGllciA9IGlmZWxzZShsYXRlbmN5IDwgdG9vRmFzdCwgImZhc3QiLCBvdXRsaWVyKSwgIyBtYXJrIHRvbyBmYXN0IHNhY2NhZGVzIGFzICJmYXN0IgogICAgICAgICAgICAgICAgICAgIG91dGxpZXIgPSBpZmVsc2UobGF0ZW5jeSA+IHRvb1Nsb3csICJzbG93Iiwgb3V0bGllciksICMgbWFyayB0b28gc2xvdyBzYWNjYWRlcyBhcyAic2xvdyIKICAgICAgICAgICAgICAgICAgICBvdXRsaWVyID0gaWZlbHNlKGRldmlhdGlvbi5zdGFydCA+IGJhZEZpeCwgImZpeGF0aW9uIiwgb3V0bGllciksICMgbWFyayBiYWQgZml4YXRpb25zIGFzICJmaXhhdGlvbiIKICAgICAgICAgICAgICAgICAgICBvdXRsaWVyID0gaWZlbHNlKGRldmlhdGlvbi5lbmQueCA+IGJhZFNhY2MsICJzYWNjYWRlIiwgb3V0bGllciksICMgbWFyayBpbmFjY3VyYXRlIHNhY2NhZGVzIGFzICJzYWNjYWRlIgogICAgICAgICAgICAgICAgICAgIG91dGxpZXIgPSBpZmVsc2UoaXMubmEobGF0ZW5jeSksICJub25lIiwgb3V0bGllcikgIyBtYXJrIGFic2VuY2Ugb2Ygc2FjY2FkZSBhcyAibm9uZSIKICAgICAgICAgICAgICAgICAgICApCmBgYAoKYGBge3IgUmVtb3ZlIG91dGxpZXIgc2FjY2FkZXMgZnJvbSBkYXRhfQpwcmVwcm9jIDwtIGZpbHRlcihncm91cERhdGEsIG91dGxpZXIgPT0gIm5vbi5vdXRsaWVyIikKYGBgCgojIyMgRXhjbHVkZSBwYXJ0aWNpcGFudHMKCiogUzIxIGFuZCBTMjUgd2VyZSB0ZXN0ZWQgPCA0OGggYXBhcnQKKiBTMTYsIFMyMiBhbmQgUzI4IGhhdmUgZmV3ZXIgdGhhbiA1MCBzYWNjYWRlcyBwZXIgY29uZGl0aW9uIGFmdGVyIHRyaWFsIHJlamVjdGlvbgoKYGBge3IgTGlzdCBvZiBzdWJqZWN0cyB0byBleGNsdWRlfQpzdWJzMmV4Y2x1ZGUgPC0gYygiUzIxIiwiUzI1IiwiUzE2IiwiUzIyIiwiUzI4IikKYGBgCgpgYGB7ciBSZW1vdmUgZXhjbHVkZWQgcGFydGljaXBhbnRzIGZyb20gZGF0YX0KcHJlcHJvYyA8LSBmaWx0ZXIocHJlcHJvYywgIShzdWJqZWN0ICVpbiUgc3ViczJleGNsdWRlKSkKYGBgCgojIyMgQ29sbGFwc2UgZGF0YSBhY3Jvc3MgMTUgbWludXRlIGludGVydmFscwoKQ3V0IHRoZSBwb3N0LWJsb2NrIGludG8gdHdvIHNvIHdlIGhhdmUgZm91ciAxNS1taW51dGUgaW50ZXJ2YWxzOiBvbmUgYmVmb3JlLCBvbmUgZHVyaW5nLCBhbmQgdHdvIGFmdGVyIHN0aW11bGF0aW9uLgoKYGBge3IgQ3V0IGludG8gMTUtbWludXRlIGludGVydmFsc30KcHJlcHJvYyA8LSBwcmVwcm9jICU+JQogIG11dGF0ZShsZWcgPSBhcy5jaGFyYWN0ZXIobGVnKSwgIyBjYW5ub3QgZWRpdCBsZWcgaWYgaXQncyBzdGlsbCBhIGZhY3RvcgogICAgICAgICBsZWcgPSByZXBsYWNlKGxlZywgbGVnID09ICJwb3N0IiAmIGJsb2NrIDw9IDMsICJwb3N0LjEiKSwKICAgICAgICAgbGVnID0gcmVwbGFjZShsZWcsIGJsb2NrID4gMywgInBvc3QuMiIpLAogICAgICAgICBsZWcgPSBmYWN0b3IobGVnLCBsZXZlbHMgPSBjKCJwcmUiLCAidERDUyIsICJwb3N0LjEiLCAicG9zdC4yIikpICMgcmVmYWN0b3IgYW5kIG9yZGVyIGxldmVscwogICAgICAgICApCmBgYAoKIyMgU3ViamVjdCBhbmQgc2Vzc2lvbiBkZXNjcmlwdGl2ZXMKCiMjIyBTYW1wbGUgZGVtb2dyYXBoaWNzCgpGb3IgUzIzLCBubyBleWUgZGF0YSB3YXMgY29sbGVjdGVkIGJlY2F1c2UgZXllIHRyYWNrZXIgY291bGQgbm90IGJlIGNhbGlicmF0ZWQsIHNvIGhlcmUgd2UgZG9uJ3QgaW5jbHVkZSB0aGVpciBzdWJqZWN0L3Nlc3Npb24gZGF0YS4KCl9fR2VuZGVyIG9mIHJlbWFpbmluZyBwYXJ0aWNpcGFudHM6X18KCmBgYHtyIHN1YmplY3QgZ2VuZGVyfQpzdWJqZWN0RGF0YSAlPiUKICBmaWx0ZXIoIShzdWJqZWN0ICVpbiUgYyhzdWJzMmV4Y2x1ZGUsICJTMjMiKSkpICU+JSAjIHJlbW92ZSByb3dzIHdpdGggdGhlc2Ugc3ViamVjdAogIGdyb3VwX2J5KGdlbmRlcikgJT4lICMgZm9yIGVhY2ggZ2VuZGVyCiAgc3VtbWFyaXNlKGNvdW50ID0gbl9kaXN0aW5jdChzdWJqZWN0KSkgJT4lCiAga2FibGUoLikjIGNvdW50IG51bWJlciBvZiBzdWJqZWN0cwpgYGAKCl9fQWdlOl9fCgpgYGB7ciBzdWJqZWN0IGFnZX0Kc3ViamVjdERhdGEgJT4lCiAgZmlsdGVyKCEoc3ViamVjdCAlaW4lIGMoc3ViczJleGNsdWRlLCAiUzIzIikpKSAlPiUKICBzdW1tYXJpc2VfYXQodmFycyhhZ2UpLCBmdW5zKG1lYW4sIG1pbiwgbWF4LCBzZCksIG5hLnJtID0gVFJVRSkgJT4lICMgYXBwbHkgc3VtbWFyeSBmdW5jdGlvbnMgdG8gYWdlIGNvbHVtbgogIGthYmxlKC4pCmBgYAoKIyMjIHREQ1Mgc2Vzc2lvbiBvcmRlcgoKYGBge3Igc2Vzc2lvbiBvcmRlcn0Kc2Vzc2lvbkRhdGEgJT4lCiAgZmlsdGVyKCEoc3ViamVjdCAlaW4lIGMoc3ViczJleGNsdWRlLCAiUzIzIikpKSAlPiUKICBncm91cF9ieShzZXNzaW9uLCBzdGltdWxhdGlvbikgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbl9kaXN0aW5jdChzdWJqZWN0KSkgJT4lIAogIGthYmxlKC4pCmBgYAoKIyMjIFNhY2NhZGUgY291bnRzCgpBdmVyYWdlIG51bWJlciBvZiBzYWNjYWRlcyBwZXIgdHlwZSBhZnRlciByZWplY3Rpb246CgpgYGB7ciB2YWxpZCBzYWNjYWRlcyBwZXIgY2VsbH0KcHJlcHJvYyAlPiUKICBncm91cF9ieShzdWJqZWN0LHN0aW11bGF0aW9uLGxlZyxkaXJlY3Rpb24sdHlwZSkgJT4lICMgZm9yIGVhY2ggY2VsbAogIHN1bW1hcmlzZShzYWNjYWRlcyA9IG4oKSkgJT4lICMgY291bnQgaG93IG1hbnkgc2FjY2FjZGVzIHRoZXJlIGFyZSBsZWZ0CiAgZ3JvdXBfYnkodHlwZSkgJT4lIAogIHN1bW1hcmlzZV9hdCh2YXJzKHNhY2NhZGVzKSwgZnVucyhtZWFuLCBtaW4sIG1heCwgc2QpKSAlPiUgIyBjb21wdXRlIHN1bW1hcnkgc3RhdGlzdGljcyBwZXIgdHlwZQogIGthYmxlKC4pCmBgYAoKUGVyY2VudGFnZSBvZiBvdXRsaWVyIHNhY2NhZGVzIHBlciB0eXBlIG91dCBvZiBhbGwgc2FjY2NhZGVzOgoKYGBge3IgcHJvcG9ydGlvbiBvZiBvdXRsaWVyIHR5cGVzfQpuX3RvdGFsIDwtIG5yb3coZmlsdGVyKGdyb3VwRGF0YSwgIShzdWJqZWN0ICVpbiUgc3ViczJleGNsdWRlKSkpICAjIHRvdGFsIGFtb3VudCBvZiBzYWNjYWRlcyBhY3Jvc3MgYWxsIGluY2x1ZGVkIHNlc3Npb25zL3N1YmplY3RzCgpncm91cERhdGEgJT4lCiAgZmlsdGVyKCEoc3ViamVjdCAlaW4lIHN1YnMyZXhjbHVkZSksICEob3V0bGllciAlaW4lIGMoIm5vbi5vdXRsaWVyIiwgIm5vbmUiKSkpICU+JQogIGdyb3VwX2J5KHN1YmplY3Qsc3RpbXVsYXRpb24sbGVnLGRpcmVjdGlvbix0eXBlLG91dGxpZXIpICU+JQogIHN1bW1hcml6ZShvdXRsaWVyX2NvdW50ID0gbigpKSAlPiUgIyBmb3IgZWFjaCBjb25kaXRpb24gYW5kIHN1YmplY3QsIGNvdW50IGhvdyBtYW55IChub24pb3V0bGllcnMgdGhlcmUgYXJlCiAgZ3JvdXBfYnkob3V0bGllcikgJT4lICMgZm9yIGVhY2ggb3V0bGllciB0eXBlCiAgc3VtbWFyaXNlKHBlcmNlbnRhZ2UgPSBzdW0ob3V0bGllcl9jb3VudCkgLyBuX3RvdGFsICoxMDApICU+JSAjIGNhbGN1bGF0ZSBwZXJjZW50YWdlCiAga2FibGUoLikKYGBgCgojIyBTYWNjYWRlIGxhdGVuY3kKCl9TZWUgdGhlIGBtZWRpYW5fbGF0ZW5jeS5uYi5odG1sYCBub3RlYm9vayBmb3IgbW9yZSBleHBsYW5hdGlvbiBhbmQgZXhwbG9yYXRpb24gb2YgdGhlIG1lZGlhbiBzYWNjYWRlIGxhdGVuY3kgZGF0YV8KCkNvbXB1dGUgdGhlIG1lZGlhbiBmb3IgZWFjaCAzIGJsb2NrcwoKYGBge3IgQ29tcHV0ZSBtZWRpYW4gbGF0ZW5jeSBvdmVyIGJsb2Nrc30KbGF0ZW5jeU1lZGlhbkxlZyA8LSBwcmVwcm9jICU+JQogIGdyb3VwX2J5KHN1YmplY3Qsc3RpbXVsYXRpb24sZGlyZWN0aW9uLHR5cGUpICU+JSAKICBzdW1tYXJpc2UoYmFzZWxpbmUgPSBtZWRpYW4obGF0ZW5jeVtsZWcgPT0gInByZSJdKSwgIyB0YWtlIGF2ZXJhZ2Ugb2YgMyBibG9ja3MsIG1ha2UgbmV3IGNvbHVtbgogICAgICAgICAgICB0RENTID0gbWVkaWFuKGxhdGVuY3lbbGVnID09ICJ0RENTIl0pLAogICAgICAgICAgICBwb3N0LjEgPSBtZWRpYW4obGF0ZW5jeVtsZWcgPT0gInBvc3QuMSJdKSwKICAgICAgICAgICAgcG9zdC4yID0gbWVkaWFuKGxhdGVuY3lbbGVnID09ICJwb3N0LjIiXSkpICU+JQogIGdhdGhlcihsZWcsbGF0ZW5jeSxiYXNlbGluZSx0RENTLHBvc3QuMSxwb3N0LjIpICU+JSAjIGdhdGhlciBuZXcgY29sdW1ucyB0byB1c2UgYXMgZmFjdG9yCiAgbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC4xIiwgInBvc3QuMiIpKSkgIyByZW9yZGVyIGZhY3RvciBsZXZlbHMKYGBgCgpNYWtlIGEgc2VwYXJhdGUgZGF0YSBmcmFtZSB3aGVyZSB0aGUgbWVkaWFuIGJhc2VsaW5lIGxhdGVuY3kgaXMgc3VidHJhY3RlZCBmcm9tIHN1YnNlcXVlbnQgYmxvY2tzCgpgYGB7ciBTdWJ0cmFjdCBiYXNlbGluZSBsYXRlbmN5fQpsYXRlbmN5TWVkaWFuQmFzZWxpbmUgPC0gbGF0ZW5jeU1lZGlhbkxlZyAlPiUKICBncm91cF9ieShzdWJqZWN0LHN0aW11bGF0aW9uLGRpcmVjdGlvbix0eXBlKSAlPiUgIyBmb3IgZWFjaCBjb25kaXRpb24sIHN1YnRyYWN0IGJhc2VsaW5lIHNjb3JlcyBhbmQgbWFrZSBuZXcgY29sdW1ucwogIHN1bW1hcmlzZShiYXNlbGluZSA9IGxhdGVuY3lbbGVnID09ICJiYXNlbGluZSJdIC0gbGF0ZW5jeVtsZWcgPT0gImJhc2VsaW5lIl0sCiAgICAgICAgICAgdERDUyA9IGxhdGVuY3lbbGVnID09ICJ0RENTIl0gLSBsYXRlbmN5W2xlZyA9PSAiYmFzZWxpbmUiXSwKICAgICAgICAgICBwb3N0LjEgPSBsYXRlbmN5W2xlZyA9PSAicG9zdC4xIl0gLSBsYXRlbmN5W2xlZyA9PSAiYmFzZWxpbmUiXSwKICAgICAgICAgICBwb3N0LjIgPSBsYXRlbmN5W2xlZyA9PSAicG9zdC4yIl0gLSBsYXRlbmN5W2xlZyA9PSAiYmFzZWxpbmUiXSkgJT4lCiAgZ2F0aGVyKGxlZywgbGF0ZW5jeS5iYXNlbGluZSwgYmFzZWxpbmUsIHREQ1MsIHBvc3QuMSwgcG9zdC4yKSAgJT4lICMgZ2F0aGVyIG5ldyBjb2x1bW5zIHRvIHVzZSBhcyBmYWN0b3IgCiAgbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC4xIiwgInBvc3QuMiIpKSkgIyByZW9yZGVyIGZhY3RvciBsZXZlbHMKYGBgCgojIyMgRmlndXJlIDQKCmBgYHtyIENyZWF0ZSBiYXNlbGluZSBsYXRlbmN5IHBsb3QgbGFiZWxzfQpiYXNlbGluZUxhYmVsTGF0ZW5jeSA8LSBsYXRlbmN5TWVkaWFuTGVnICU+JQogIGdyb3VwX2J5KHN0aW11bGF0aW9uLGRpcmVjdGlvbix0eXBlLGxlZykgJT4lCiAgZmlsdGVyKGxlZyA9PSAiYmFzZWxpbmUiKSAlPiUKICBzdW1tYXJpc2UobGF0ZW5jeS5iYXNlbGluZSA9IHJvdW5kKG1lYW4obGF0ZW5jeSkpKQpgYGAKClBsb3QgbWVkaWFuIF9sYXRlcmFsIHNhY2NhZGVfIGxhdGVuY3kgcGVyIHBhcnRpY2lwYW50CgpgYGB7ciBNZWRpYW4gbGF0ZW5jeSBsYXRlcmFsIHNhY2NhZGVzfQpwbG90X3N1Yl9sYXRlbmN5X2xhdGVyYWwgPC0gZ2dwbG90KGZpbHRlcihsYXRlbmN5TWVkaWFuTGVnLCB0eXBlID09ICJsYXRlcmFsIiksIGFlcyhsZWcsIGxhdGVuY3kpKSArCiAgZmFjZXRfZ3JpZChzdGltdWxhdGlvbiB+IGRpcmVjdGlvbikgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzdWJqZWN0LCBjb2xvciA9IHN1YmplY3QpLCBhbHBoYSA9IDAuNSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhncm91cCA9IGludGVyYWN0aW9uKHN0aW11bGF0aW9uLCBkaXJlY3Rpb24pLCBsaW5ldHlwZSA9IGRpcmVjdGlvbiksIGdlb20gPSAibGluZSIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IiwgYWVzKHNoYXBlID0gc3RpbXVsYXRpb24pKSArCiAgZ3VpZGVzKGNvbG91ciA9IEZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0YyNUY1QyIsICIjNEI5M0IxIikpICsKICBzY2FsZV94X2Rpc2NyZXRlKCJ0aW1lIiwgbGFiZWxzID0gYygiYmFzZWxpbmUiLCAidERDUyIsICJwb3N0LTEiLCAicG9zdC0yIikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoIm1lZGlhbiBsYXRlbmN5IChtcykiLCBicmVha3MgPSBzZXEoMTAwLDIwMCwyMCksIGxpbWl0cyA9IGMoOTAsMjIwKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjIsIHZqdXN0ID0gLjUpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGdndGl0bGUoIkxhdGVyYWwgc2FjY2FkZXMiKQpgYGAKClBsb3QgbWVkaWFuIF9jZW50ZXIgc2FjY2FkZV8gbGF0ZW5jeSBwZXIgcGFydGljaXBhbnQKCmBgYHtyIE1lZGlhbiBsYXRlbmN5IGNlbnRlciBzYWNjYWRlc30KcGxvdF9zdWJfbGF0ZW5jeV9jZW50ZXIgPC0gZ2dwbG90KGZpbHRlcihsYXRlbmN5TWVkaWFuTGVnLCB0eXBlID09ICJjZW50ZXIiKSwgYWVzKGxlZywgbGF0ZW5jeSkpICsKICBmYWNldF9ncmlkKHN0aW11bGF0aW9uIH4gZGlyZWN0aW9uKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHN1YmplY3QsIGNvbG9yID0gc3ViamVjdCksIGFscGhhID0gMC41KSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgYWVzKGdyb3VwID0gaW50ZXJhY3Rpb24oc3RpbXVsYXRpb24sIGRpcmVjdGlvbiksIGxpbmV0eXBlID0gZGlyZWN0aW9uKSwgZ2VvbSA9ICJsaW5lIikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBhZXMoc2hhcGUgPSBzdGltdWxhdGlvbikpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRjI1RjVDIiwgIiM0QjkzQjEiKSkgKwogIHNjYWxlX3hfZGlzY3JldGUoInRpbWUiLCBsYWJlbHMgPSBjKCJiYXNlbGluZSIsICJ0RENTIiwgInBvc3QtMSIsICJwb3N0LTIiKSkgKwogIHNjYWxlX3lfY29udGludW91cygibWVkaWFuIGxhdGVuY3kgKG1zKSIsIGJyZWFrcyA9IHNlcSgxMDAsMjAwLDIwKSwgbGltaXRzID0gYyg5MCwyMjApKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyMiwgdmp1c3QgPSAuNSksIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgZ2d0aXRsZSgiQ2VudGVyIHNhY2NhZGVzIikKYGBgCgpQbG90IGdyb3VwIG1lYW4gX2xhdGVyYWwgc2FjY2FkZV8gbGF0ZW5jeSBhcyBjaGFuZ2UgZnJvbSBiYXNlbGluZQoKYGBge3IgR3JvdXAgbWVhbiBsYXRlbmN5IGxhdGVyYWwgc2FjY2FkZXN9CnBsb3RfZ3JvdXBfbGF0ZW5jeV9sYXRlcmFsIDwtIGdncGxvdChmaWx0ZXIobGF0ZW5jeU1lZGlhbkJhc2VsaW5lLCB0eXBlID09ICJsYXRlcmFsIiksIGFlcyhsZWcsIGxhdGVuY3kuYmFzZWxpbmUpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IGJhc2VfbGluZV9zaXplKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgYWVzKGdyb3VwID0gaW50ZXJhY3Rpb24oc3RpbXVsYXRpb24sIGRpcmVjdGlvbiksIGNvbG9yID0gc3RpbXVsYXRpb24sIGxpbmV0eXBlID0gZGlyZWN0aW9uKSwgZ2VvbSA9ICJsaW5lIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIHNpemUgPSAuNzUpICsgCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ub3JtYWwsIGFlcyhncm91cCA9IGludGVyYWN0aW9uKHN0aW11bGF0aW9uLCBkaXJlY3Rpb24pLCBjb2xvciA9IHN0aW11bGF0aW9uLCBsaW5ldHlwZSA9IGRpcmVjdGlvbiksIGdlb20gPSAibGluZXJhbmdlIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBpbnRlcmFjdGlvbihzdGltdWxhdGlvbiwgZGlyZWN0aW9uKSwgY29sb3IgPSBzdGltdWxhdGlvbiwgc2hhcGUgPSBzdGltdWxhdGlvbiksIGdlb20gPSAicG9pbnQiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgc2l6ZSA9IDIpICsKICBnZW9tX3RleHQoZGF0YSA9IHN1YnNldChiYXNlbGluZUxhYmVsTGF0ZW5jeSwgdHlwZT09ImxhdGVyYWwiKSwgYWVzKHkgPSBjKDIsMSw0LDMpLCBsYWJlbD1sYXRlbmN5LmJhc2VsaW5lLCBjb2xvciA9IHN0aW11bGF0aW9uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIHNpemUgPSBtbV90b19wdCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0YyNUY1QyIsICIjNEI5M0IxIikpICsKICBzY2FsZV94X2Rpc2NyZXRlKCJ0aW1lIiwgbGFiZWxzID0gYygiYmFzZWxpbmUiLCAidERDUyIsICJwb3N0LTEiLCAicG9zdC0yIikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoImxhdGVuY3kgY2hhbmdlIGZyb20gYmFzZWxpbmUgKG1zKSIsIGJyZWFrcyA9IHNlcSgtOCw4LDIpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC04LDgpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyMiwgdmp1c3QgPSAuNSksIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpQbG90IGdyb3VwIG1lYW4gX2NlbnRlciBzYWNjYWRlXyBsYXRlbmN5IGFzIGNoYW5nZSBmcm9tIGJhc2VsaW5lCgpgYGB7ciBHcm91cCBtZWFuIGxhdGVuY3kgY2VudGVyIHNhY2NhZGVzfQpwbG90X2dyb3VwX2xhdGVuY3lfY2VudGVyIDwtIGdncGxvdChmaWx0ZXIobGF0ZW5jeU1lZGlhbkJhc2VsaW5lLCB0eXBlID09ICJjZW50ZXIiKSwgYWVzKGxlZywgbGF0ZW5jeS5iYXNlbGluZSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBzaXplID0gYmFzZV9saW5lX3NpemUpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBpbnRlcmFjdGlvbihzdGltdWxhdGlvbiwgZGlyZWN0aW9uKSwgY29sb3IgPSBzdGltdWxhdGlvbiwgbGluZXR5cGUgPSBkaXJlY3Rpb24pLCBnZW9tID0gImxpbmUiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgc2l6ZSA9IC43NSkgKyAKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCwgYWVzKGdyb3VwID0gaW50ZXJhY3Rpb24oc3RpbXVsYXRpb24sIGRpcmVjdGlvbiksIGNvbG9yID0gc3RpbXVsYXRpb24sIGxpbmV0eXBlID0gZGlyZWN0aW9uKSwgZ2VvbSA9ICJsaW5lcmFuZ2UiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhncm91cCA9IGludGVyYWN0aW9uKHN0aW11bGF0aW9uLCBkaXJlY3Rpb24pLCBjb2xvciA9IHN0aW11bGF0aW9uLCBzaGFwZSA9IHN0aW11bGF0aW9uKSwgZ2VvbSA9ICJwb2ludCIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLCBzaXplID0gMikgKwogIGdlb21fdGV4dChkYXRhID0gc3Vic2V0KGJhc2VsaW5lTGFiZWxMYXRlbmN5LCB0eXBlPT0iY2VudGVyIiksIGFlcyh5ID0gYygyLDEsMyw0KSwgbGFiZWw9bGF0ZW5jeS5iYXNlbGluZSwgY29sb3IgPSBzdGltdWxhdGlvbiksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLCBzaXplID0gbW1fdG9fcHQpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNGMjVGNUMiLCAiIzRCOTNCMSIpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBjKCJiYXNlbGluZSIsICJ0RENTIiwgInBvc3QtMSIsICJwb3N0LTIiKSkgKwogIHNjYWxlX3lfY29udGludW91cygibGF0ZW5jeSBjaGFuZ2UgZnJvbSBiYXNlbGluZSAobXMpIiwgYnJlYWtzID0gc2VxKC04LDgsMikpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLTgsOCkpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDIyLCB2anVzdCA9IC41KSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCkNvbWJpbmUgYWxsIHRoZSBwbG90czoKCmBgYHtyIEZpZ3VyZSA0fQpsZWdlbmRfZmlnNCA8LSBnZXRfbGVnZW5kKHBsb3RfZ3JvdXBfbGF0ZW5jeV9sYXRlcmFsKQpmaWd1cmVfNCA8LSBwbG90X2dyaWQoCiAgcGxvdF9zdWJfbGF0ZW5jeV9sYXRlcmFsLCBwbG90X3N1Yl9sYXRlbmN5X2NlbnRlciwKICBwbG90X2dyb3VwX2xhdGVuY3lfbGF0ZXJhbCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksCiAgcGxvdF9ncm91cF9sYXRlbmN5X2NlbnRlciArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksIHJlbF9oZWlnaHRzID0gYygxLC43NSkpCmZpZ3VyZV80IDwtIHBsb3RfZ3JpZChmaWd1cmVfNCxsZWdlbmRfZmlnNCxyZWxfd2lkdGhzID0gYygxLDEvMTApKQpmaWd1cmVfNApgYGAKClNhdmUgdGhlIHBsb3Q6CgpgYGB7ciBTYXZlIGZpZ3VyZSA0LCBldmFsPUZBTFNFfQpnZ3NhdmUoImZpZy9maWd1cmVfNC5wZGYiLCBwbG90ID0gZmlndXJlXzQsIHdpZHRoID0gMTgwLCBoZWlnaHQgPSAxMTIuNSwgdW5pdHMgPSAibW0iKQpnZ3NhdmUoImZpZy9maWd1cmVfNC5wbmciLCBwbG90ID0gZmlndXJlXzQsIHdpZHRoID0gMTgwLCBoZWlnaHQgPSAxMTIuNSwgdW5pdHMgPSAibW0iKQpgYGAKCiMjIyBTdGF0aXN0aWNzCgojIyMjIENvbnRyYWxhdGVyYWwgc2FjY2FkZXMgaW4gdGhlIGFub2RhbCBzZXNzaW9uCgpNZWFucyBhbmQgU0RzIGZvciBlZmZlY3Qgb2YgX2Fub2RhbF8gdERDUyBvbiB0aGUgbGF0ZW5jeSBjaGFuZ2VzIGluIF9jb250cmFsYXRlcmFsXyAoaGVyZTogbGVmdCkgX2xhdGVyYWxfIHNhY2NhZGVzLCBhcyB0aGlzIGlzIHdoYXQgW0thbmFpIGV0IGFsLiAoMjAxMildKGh0dHA6Ly9keC5kb2kub3JnLzEwLjMzODkvZnBzeXQuMjAxMi4wMDA0NSkgc3BlY2lmaWNhbGx5IGZvdW5kOgoKYGBge3IgQW5vZGFsIGxlZnQgbGF0ZXJhbCBzYWNjYWRlc30KbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIGZpbHRlcih0eXBlID09ICJsYXRlcmFsIiwgc3RpbXVsYXRpb24gPT0gImFub2RhbCIsIGRpcmVjdGlvbiA9PSAibGVmdCIsIGxlZyAhPSAiYmFzZWxpbmUiKSAlPiUKICBncm91cF9ieShsZWcpICU+JQogIHN1bW1hcmlzZV9hdCh2YXJzKGxhdGVuY3kuYmFzZWxpbmUpLCBmdW5zKG1lYW4sIHNkKSkgJT4lCiAga2FibGUoLikKYGBgCgojIyMjIEJhc2VsaW5lIHRlc3RzIAoKYGBge3IgdC10ZXN0cyBvZiBiYXNlbGluZSBkaWZmZXJlbmNlIC0gbGF0ZW5jeX0KbGF0ZW5jeU1lZGlhbkxlZyAlPiUKICBmaWx0ZXIobGVnID09ICJiYXNlbGluZSIpICU+JQogIGdyb3VwX2J5KGRpcmVjdGlvbix0eXBlKSAlPiUgIyBmb3IgZWFjaCBvZiB0aGVzZSA0IHBhaXJzCiAgbmVzdCgpICU+JSAjIGNyZWF0ZSBhIHNlcGFyYXRlIGRhdGEgZnJhbWUgb2YgYWxsIHJlbWFpbmluZyBjb2x1bW5zLiBUaGVzZSBkYXRhIGZyYW1lcyBhcmUgc3RvcmVkIGluIGEgbGlzdC1jb2x1bW4gbmFtZWQgImRhdGEiCiAgbXV0YXRlKHN0YXRzID0gbWFwKGRhdGEsIH50LnRlc3QoZm9ybXVsYSA9IGxhdGVuY3l+c3RpbXVsYXRpb24sIHBhaXJlZCA9IFRSVUUsIGRhdGEgPS4pKSkgJT4lICMgcnVuIHQtdGVzdCBvbiB0aGUgZGF0YSBmcmFtZXMKICBtdXRhdGUodGlkeV9tb2RlbCA9IG1hcChzdGF0cywgdGlkeSkpICU+JSAjIGZvcmNlIHRoZSBmb3VyIHRlc3Qgb3V0cHV0cyB0byBhbHNvIGJlIGRhdGEgZnJhbWVzIGluIGEgbGlzdCBjb2x1bW4gKCJ0aWR5X21vZGVsIikKICB1bm5lc3QodGlkeV9tb2RlbCwgLmRyb3AgPSBUUlVFKSAlPiUgIyB1bnBhY2sgdGhlIGxpc3QtY29sdW1uIHdpdGggcmVzdWx0cywgZHJvcCB0aGUgbGlzdC1jb2x1bW4gd2UgdXNlZCB0byBvcmdhbml6ZSB0aGUgZGF0YQogIGthYmxlKC4pCmBgYAoKIyMjIyBMYXRlcmFsIHNhY2NhZGVzIHsudGFic2V0IC50YWJzZXQtZmFkZX0KCiMjIyMjIENsYXNzaWNhbCBBTk9WQQoKUmVwZWF0ZWQgbWVhc3VyZXMgQU5PVkEgbWF0Y2hpbmcgW0thbmFpIGV0IGFsLiAoMjAxMildKGh0dHA6Ly9keC5kb2kub3JnLzEwLjMzODkvZnBzeXQuMjAxMi4wMDA0NSkuCgpfX0RhdGFfXzogQmFzZWxpbmUgc3VidHJhY3RlZCwgbGF0ZXJhbCBzYWNjYWRlcwoKX19EZXBlbmRlbnQgbWVhc3VyZV9fOiBzYWNjYWRlIGxhdGVuY3kKCl9fRmFjdG9yc19fOgoKKiBTVElNVUxBVElPTiAoYW5vZGFsIHZzLiBjYXRob2RhbCkKKiBMRUcgKHREQ1MsIHBvc3QuMSwgcG9zdC4yKQoqIERJUkVDVElPTiAobGVmdCB2cy4gcmlnaHQpCgpQcmVwYXJlIGRhdGE6IAoKYGBge3IgdGVzdCBkYXRhIG1lZGlhbiBsYXRlbmN5IGxhdGVyYWx9Cm1lZGlhbkxhdGVuY3lMYXRlcmFsU3RhdHMgPC0gbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIobGVnICE9ICJiYXNlbGluZSIsIHR5cGUgPT0gImxhdGVyYWwiKSAlPiUKICBzZWxlY3QoLXR5cGUpICU+JQogIG11dGF0ZShsZWcgPSBmYWN0b3IobGVnLCBsZXZlbHMgPSBjKCJ0RENTIiwgInBvc3QuMSIsICJwb3N0LjIiKSkpICU+JQogIG11dGF0ZShzdWJqZWN0ID0gZmFjdG9yKHN1YmplY3QpKQpgYGAKCmBgYHtyIHJtQU5PVkEgbWVkaWFuIGxhdGVuY3kgbGF0ZXJhbCwgcmVzdWx0cz0nYXNpcyd9CmFvdk1lZGlhbkxhdGVuY3lMYXRlcmFsIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUobWVkaWFuTGF0ZW5jeUxhdGVyYWxTdGF0cyksIGR2ID0gbGF0ZW5jeS5iYXNlbGluZSwgd2lkID0gc3ViamVjdCwgd2l0aGluID0gLihzdGltdWxhdGlvbixsZWcsZGlyZWN0aW9uKSwgdHlwZSA9IDMpCgprYWJsZShhb3ZNZWRpYW5MYXRlbmN5TGF0ZXJhbCRBTk9WQSkKa2FibGUoYW92TWVkaWFuTGF0ZW5jeUxhdGVyYWwkYE1hdWNobHkncyBUZXN0IGZvciBTcGhlcmljaXR5YCkKa2FibGUoYW92TWVkaWFuTGF0ZW5jeUxhdGVyYWwkYFNwaGVyaWNpdHkgQ29ycmVjdGlvbnNgKQpgYGAKCiMjIyMjIEJheWVzaWFuIEFOT1ZBCgpTYW1lIGRlc2lnbiBhcyB0aGUgY2xhc3NpY2FsIEFOT1ZBCgpCYXllcyBmYWN0b3JzIGFnYWlucyB0aGUgbnVsbCBtb2RlbDoKCmBgYHtyIEJheWVzaWFuIEFOT1ZBIG1lZGlhbiBsYXRlbmN5IGxhdGVyYWx9CmJmTWVkaWFuTGF0ZW5jeUxhdGVyYWwgPSBhbm92YUJGKGxhdGVuY3kuYmFzZWxpbmV+c3RpbXVsYXRpb24qbGVnKmRpcmVjdGlvbitzdWJqZWN0LCBkYXRhID0gZGF0YS5mcmFtZShtZWRpYW5MYXRlbmN5TGF0ZXJhbFN0YXRzKSwgd2hpY2hNb2RlbHMgPSAid2l0aG1haW4iLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgCmJmTWVkaWFuTGF0ZW5jeUxhdGVyYWwgPSBzb3J0KGJmTWVkaWFuTGF0ZW5jeUxhdGVyYWwsIGRlY3JlYXNpbmcgPSBUUlVFKSAjIHNvcnQgc3VjaCB0aGF0IHdpbm5pbmcgbW9kZWwgaXMgYXQgdGhlIHRvcApgYGAKCmBgYHtyfQprYWJsZShzZWxlY3QoZXh0cmFjdEJGKGJmTWVkaWFuTGF0ZW5jeUxhdGVyYWwpLCBiZikpICMgc2hvdyBvbmx5IHRoZSBCYXllcyBmYWN0b3JzIGluIGEgdGFibGUKYGBgCgpJbmNsdXNpb24gQmF5ZXMgZmFjdG9yIGFjcm9zcyBtYXRjaGVkIG1vZGVsczoKCmBgYHtyIGluY2x1c2lvbiBCRiBBTk9WQSBtZWRpYW4gbGF0ZW5jeSBsYXRlcmFsfQprYWJsZShpbmNsdXNpb25CRihiZk1lZGlhbkxhdGVuY3lMYXRlcmFsLCBtb2RlbHMgPSAibWF0Y2hlZCIpKQpgYGAKCiMjIyMgQ2VudGVyIHNhY2NhZGVzIHsudGFic2V0IC50YWJzZXQtZmFkZX0KCiMjIyMjIENsYXNzaWNhbCBBTk9WQQoKUmVwZWF0ZWQgbWVhc3VyZXMgQU5PVkEgbWF0Y2hpbmcgW0thbmFpIGV0IGFsLiAoMjAxMildKGh0dHA6Ly9keC5kb2kub3JnLzEwLjMzODkvZnBzeXQuMjAxMi4wMDA0NSkuCgpfX0RhdGFfXzogQmFzZWxpbmUgc3VidHJhY3RlZCwgY2VudGVyIHNhY2NhZGVzCgpfX0RlcGVuZGVudCBtZWFzdXJlX186IHNhY2NhZGUgbGF0ZW5jeQoKX19GYWN0b3JzX186CgoqIFNUSU1VTEFUSU9OIChhbm9kYWwgdnMuIGNhdGhvZGFsKQoqIExFRyAodERDUywgcG9zdC4xLCBwb3N0LjIpCiogRElSRUNUSU9OIChsZWZ0IHZzLiByaWdodCkKClByZXBhcmUgZGF0YTogCgpgYGB7ciB0ZXN0IGRhdGEgbWVkaWFuIGxhdGVuY3kgY2VudGVyfQptZWRpYW5MYXRlbmN5Q2VudGVyU3RhdHMgPC0gbGF0ZW5jeU1lZGlhbkJhc2VsaW5lICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIobGVnICE9ICJiYXNlbGluZSIsIHR5cGUgPT0gImNlbnRlciIpICU+JQogIHNlbGVjdCgtdHlwZSkgJT4lCiAgbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoInREQ1MiLCAicG9zdC4xIiwgInBvc3QuMiIpKSkgJT4lCiAgbXV0YXRlKHN1YmplY3QgPSBmYWN0b3Ioc3ViamVjdCkpCmBgYAoKYGBge3Igcm1BTk9WQSBtZWRpYW4gbGF0ZW5jeSBjZW50ZXIsIHJlc3VsdHM9J2FzaXMnfQphb3ZNZWRpYW5MYXRlbmN5Q2VudGVyIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUobWVkaWFuTGF0ZW5jeUNlbnRlclN0YXRzKSwgZHYgPSBsYXRlbmN5LmJhc2VsaW5lLCB3aWQgPSBzdWJqZWN0LCB3aXRoaW4gPSAuKHN0aW11bGF0aW9uLGxlZyxkaXJlY3Rpb24pLCB0eXBlID0gMykKCmthYmxlKGFvdk1lZGlhbkxhdGVuY3lDZW50ZXIkQU5PVkEpCmthYmxlKGFvdk1lZGlhbkxhdGVuY3lDZW50ZXIkYE1hdWNobHkncyBUZXN0IGZvciBTcGhlcmljaXR5YCkKa2FibGUoYW92TWVkaWFuTGF0ZW5jeUNlbnRlciRgU3BoZXJpY2l0eSBDb3JyZWN0aW9uc2ApCmBgYAoKIyMjIyMgQmF5ZXNpYW4gQU5PVkEKClNhbWUgZGVzaWduIGFzIHRoZSBjbGFzc2ljYWwgQU5PVkEKCkJheWVzIGZhY3RvcnMgYWdhaW5zIHRoZSBudWxsIG1vZGVsOgoKYGBge3IgQmF5ZXNpYW4gQU5PVkEgbWVkaWFuIGxhdGVuY3kgY2VudGVyfQpiZk1lZGlhbkxhdGVuY3lDZW50ZXIgPSBhbm92YUJGKGxhdGVuY3kuYmFzZWxpbmV+c3RpbXVsYXRpb24qbGVnKmRpcmVjdGlvbitzdWJqZWN0LCBkYXRhID0gZGF0YS5mcmFtZShtZWRpYW5MYXRlbmN5Q2VudGVyU3RhdHMpLCB3aGljaE1vZGVscyA9ICJ3aXRobWFpbiIsIHdoaWNoUmFuZG9tID0gInN1YmplY3QiLCBwcm9ncmVzcyA9IEZBTFNFLCBpdGVyYXRpb25zID0gMTAwMDAwKSAKYmZNZWRpYW5MYXRlbmN5Q2VudGVyID0gc29ydChiZk1lZGlhbkxhdGVuY3lDZW50ZXIsIGRlY3JlYXNpbmcgPSBUUlVFKSAjIHNvcnQgc3VjaCB0aGF0IHdpbm5pbmcgbW9kZWwgaXMgYXQgdGhlIHRvcAoKa2FibGUoc2VsZWN0KGV4dHJhY3RCRihiZk1lZGlhbkxhdGVuY3lDZW50ZXIpLCBiZikpICMgc2hvdyBvbmx5IHRoZSBCYXllcyBmYWN0b3JzIGluIGEgdGFibGUKYGBgCgpgYGB7cn0Ka2FibGUoc2VsZWN0KGV4dHJhY3RCRihiZk1lZGlhbkxhdGVuY3lDZW50ZXIpLCBiZikpICMgc2hvdyBvbmx5IHRoZSBCYXllcyBmYWN0b3JzIGluIGEgdGFibGUKYGBgCgpJbmNsdXNpb24gQmF5ZXMgZmFjdG9yIGFjcm9zcyBtYXRjaGVkIG1vZGVsczoKCmBgYHtyIGluY2x1c2lvbiBCRiBBTk9WQSBtZWRpYW4gbGF0ZW5jeSBjZW50ZXJ9CmthYmxlKGluY2x1c2lvbkJGKGJmTWVkaWFuTGF0ZW5jeUNlbnRlciwgbW9kZWxzID0gIm1hdGNoZWQiKSkKYGBgCgojIyMjIyMgV2l0aG91dCBTMDEKCmBgYHtyIEJGIEFOT1ZBIG1lZGlhbiBsYXRlbmN5IGNlbnRlciAtIHdpdGhvdXQgUzAxfQptZWRpYW5MYXRlbmN5Q2VudGVyTm9TMDEgPC0gbWVkaWFuTGF0ZW5jeUNlbnRlclN0YXRzICU+JQogIGZpbHRlcihzdWJqZWN0ICE9ICJTMDEiKSAlPiUKICBtdXRhdGUoc3ViamVjdCA9IGZhY3RvcihzdWJqZWN0KSkKCmJmTWVkaWFuTGF0ZW5jeUNlbnRlck5vUzAxID0gYW5vdmFCRihsYXRlbmN5LmJhc2VsaW5lfnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24rc3ViamVjdCwgZGF0YSA9IGRhdGEuZnJhbWUobWVkaWFuTGF0ZW5jeUNlbnRlck5vUzAxKSwgd2hpY2hNb2RlbHM9IndpdGhtYWluIiwgd2hpY2hSYW5kb20gPSAic3ViamVjdCIsIHByb2dyZXNzID0gRkFMU0UsIGl0ZXJhdGlvbnMgPSAxMDAwMDApICMgY29tcHV0ZSBCYXllcyBGYWN0b3JzCmJmS2FuYWlDZW50ZXJOb1MwMSA8LSBzb3J0KGJmTWVkaWFuTGF0ZW5jeUNlbnRlck5vUzAxLCBkZWNyZWFzaW5nID0gVFJVRSkgIyBzb3J0IHN1Y2ggdGhhdCB3aW5uaW5nIG1vZGVsIGlzIGF0IHRoZSB0b3AKa2FibGUoc2VsZWN0KGV4dHJhY3RCRihiZk1lZGlhbkxhdGVuY3lDZW50ZXJOb1MwMSksIGJmKSkgIyBzaG93IG9ubHkgdGhlIEJheWVzIGZhY3RvcnMgaW4gYSB0YWJsZQprYWJsZShpbmNsdXNpb25CRihiZk1lZGlhbkxhdGVuY3lDZW50ZXJOb1MwMSwgbW9kZWxzID0gIm1hdGNoZWQiKSkKYGBgCgojIyMjIyBGb2xsb3ctdXAgdGVzdHMKCiMjIyMjIyBNYWluIGVmZmVjdCBvZiBzdGltdWxhdGlvbgoKRm9sbG93LXVwIE9uZS1zYW1wbGUgdC10ZXN0OgoKYGBge3IgQ2xhc3NpY2FsIGZvbGxvdy11cCB0ZXN0IC0gbGF0ZW5jeX0KbWVkaWFuTGF0ZW5jeUNlbnRlclN0YXRzICU+JQogIGdyb3VwX2J5KHN0aW11bGF0aW9uLHN1YmplY3QpICU+JSAjIGZvciBlYWNoIHNlc3Npb24gYW5kIHN1YmplY3QKICBzdW1tYXJpc2UobGF0ZW5jeSA9IG1lYW4obGF0ZW5jeS5iYXNlbGluZSkpICU+JSAjIGF2ZXJhZ2Ugb3ZlciBhbGwgb3RoZXIgdmFyaWFibGVzIChkZiBpcyBub3cgc3RpbGwgZ3JvdXBlZCBwZXIgc3RpbXVsYXRpb24pCiAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIGZ1bnMobGlzdCh0aWR5KHQudGVzdCguKSkpKSkgJT4lICAjIHJ1biBvbmUtc2FtcGxlIHQtdGVzdCBmb3IgZWFjaCBzdGltdWxhdGlvbiBjb25kaXRpb24sIHJldHVybiB0aWR5IGRhdGEgZnJhbWVzCiAgdW5uZXN0KCkgJT4lICMgdW5wYWNrIHRoZSBsaXN0LWNvbHVtbiB3aXRoIGRhdGEgZnJhbWUgZm9yIGVhY2ggdGVzdAogIGthYmxlKC4pCmBgYAoKRm9sbG93LXVwIEJheWVzaWFuIG9uZS1zYW1wbGUgdC10ZXN0OgoKYGBge3IgQmF5ZXNpYW4gZm9sbG93LXVwIHRlc3QgLSBsYXRlbmN5fQptZWRpYW5MYXRlbmN5Q2VudGVyU3RhdHMgJT4lCiAgZ3JvdXBfYnkoc3RpbXVsYXRpb24sc3ViamVjdCkgJT4lICMgZm9yIGVhY2ggc2Vzc2lvbiBhbmQgc3ViamVjdAogIHN1bW1hcmlzZShsYXRlbmN5ID0gbWVhbihsYXRlbmN5LmJhc2VsaW5lKSkgJT4lICMgYXZlcmFnZSBvdmVyIGFsbCBvdGhlciB2YXJpYWJsZXMKICBzcHJlYWQoc3RpbXVsYXRpb24sIGxhdGVuY3kpICU+JSAjIG1ha2Ugc2VwYXJhdGUgY29sdW1ucyB3aXRoIHRlc3QgZGF0YQogIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBmdW5zKGV4dHJhY3RCRih0dGVzdEJGKC4pLCBvbmx5YmYgPSBUUlVFKSkpICU+JSAjIHJ1biBCYXllc2lhbiB0LXRlc3Qgb24gZWFjaCBjb2x1bW4sIGtlZXBpbmcgb25seSB0aGUgQkYKICBnYXRoZXIoc3RpbXVsYXRpb24sQkYsYW5vZGFsLGNhdGhvZGFsKSAlPiUgIyBtYWtlIHJvdyBmb3IgZWFjaCBzdGltdWxhdGlvbiBjb25kaXRpb24KICBrYWJsZSguKQpgYGAKCiMjIFNhY2NhZGUgZW5kcG9pbnQgZGV2aWF0aW9uCgpfU2VlIHRoZSBgYWNjdXJhY3kubmIuaHRtbGAgbm90ZWJvb2sgZm9yIG1vcmUgZXhwbGFuYXRpb24gYW5kIGV4cGxvcmF0aW9uIG9mIHRoZSBzYWNjYWRlIGVuZHBvaW50IGRldmlhdGlvbiBkYXRhXwoKQ2FsY3VsYXRlIGVuZHBvaW50IGRldmlhdGlvbiBmb3IgZWFjaCB0cmlhbCAoRXVjbGlkaWFuIGRpc3RhbmNlIGZyb20gdGFyZ2V0LCBkZWZpbmVkIGJ5IHgtIGFuZCB5LWNvb3JkaW5hdGUgZGV2aWF0aW9ucykKCmBgYHtyIENhbGN1bGF0ZSBlbmQgcG9pbnQgZGV2aWF0aW9ufQojIENhbGN1bGF0ZSBlbmQgcG9pbnQgZGV2aWF0aW9uCmFjY0RhdGEgPC0gcHJlcHJvYyAlPiUKICBncm91cF9ieShzdWJqZWN0LHN0aW11bGF0aW9uLGxlZyxibG9jayx0cmlhbCxkaXJlY3Rpb24sdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGRldmlhdGlvbi5lbmQgPSBzcXJ0KGRldmlhdGlvbi5lbmQueF4yICsgZGV2aWF0aW9uLmVuZC55XjIpKQpgYGAKCkNvbXB1dGUgdGhlIG1lYW4gZm9yIGVhY2ggMyBibG9ja3MKCmBgYHtyIENvbXB1dGUgbWVhbiBkZXZpYXRpb24gb3ZlciBibG9ja3N9CmFjY01lYW5MZWcgPC0gYWNjRGF0YSAlPiUKICBncm91cF9ieShzdWJqZWN0LHN0aW11bGF0aW9uLGRpcmVjdGlvbix0eXBlKSAlPiUgCiAgc3VtbWFyaXNlKGJhc2VsaW5lID0gbWVhbihkZXZpYXRpb24uZW5kW2xlZyA9PSAicHJlIl0pLCAjIHRha2UgYXZlcmFnZSBvZiAzIGJsb2NrcywgbWFrZSBuZXcgY29sdW1uCiAgICAgICAgICAgIHREQ1MgPSBtZWFuKGRldmlhdGlvbi5lbmRbbGVnID09ICJ0RENTIl0pLAogICAgICAgICAgICBwb3N0LjEgPSBtZWFuKGRldmlhdGlvbi5lbmRbbGVnID09ICJwb3N0LjEiXSksCiAgICAgICAgICAgIHBvc3QuMiA9IG1lYW4oZGV2aWF0aW9uLmVuZFtsZWcgPT0gInBvc3QuMiJdKSkgJT4lCiAgZ2F0aGVyKGxlZyxkZXZpYXRpb24uZW5kLGJhc2VsaW5lLHREQ1MscG9zdC4xLHBvc3QuMikgJT4lICMgZ2F0aGVyIG5ldyBjb2x1bW5zIHRvIHVzZSBhcyBmYWN0b3IKICBtdXRhdGUobGVnID0gZmFjdG9yKGxlZywgbGV2ZWxzID0gYygiYmFzZWxpbmUiLCAidERDUyIsICJwb3N0LjEiLCAicG9zdC4yIikpKSAjIHJlb3JkZXIgZmFjdG9yIGxldmVscwpgYGAKCk1ha2UgYSBzZXBhcmF0ZSBkYXRhIGZyYW1lIHdoZXJlIHRoZSBtZWFuIGRldmlhdGlvbiBpcyBzdWJ0cmFjdGVkIGZyb20gc3Vic2VxdWVudCBibG9ja3MKCmBgYHtyIFN1YnRyYWN0IGJhc2VsaW5lIGRldmlhdGlvbn0KYWNjTWVhbkJhc2VsaW5lIDwtIGFjY01lYW5MZWcgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzdGltdWxhdGlvbixkaXJlY3Rpb24sdHlwZSkgJT4lICMgZm9yIGVhY2ggY29uZGl0aW9uLCBzdWJ0cmFjdCBiYXNlbGluZSBzY29yZXMgYW5kIG1ha2UgbmV3IGNvbHVtbnMKICBzdW1tYXJpc2UoYmFzZWxpbmUgPSBkZXZpYXRpb24uZW5kW2xlZyA9PSAiYmFzZWxpbmUiXSAtIGRldmlhdGlvbi5lbmRbbGVnID09ICJiYXNlbGluZSJdLAogICAgICAgICAgIHREQ1MgPSBkZXZpYXRpb24uZW5kW2xlZyA9PSAidERDUyJdIC0gZGV2aWF0aW9uLmVuZFtsZWcgPT0gImJhc2VsaW5lIl0sCiAgICAgICAgICAgcG9zdC4xID0gZGV2aWF0aW9uLmVuZFtsZWcgPT0gInBvc3QuMSJdIC0gZGV2aWF0aW9uLmVuZFtsZWcgPT0gImJhc2VsaW5lIl0sCiAgICAgICAgICAgcG9zdC4yID0gZGV2aWF0aW9uLmVuZFtsZWcgPT0gInBvc3QuMiJdIC0gZGV2aWF0aW9uLmVuZFtsZWcgPT0gImJhc2VsaW5lIl0pICU+JQogIGdhdGhlcihsZWcsIGRldmlhdGlvbi5lbmQuYmFzZWxpbmUsIGJhc2VsaW5lLCB0RENTLCBwb3N0LjEsIHBvc3QuMikgICU+JSAjIGdhdGhlciBuZXcgY29sdW1ucyB0byB1c2UgYXMgZmFjdG9yIAogIG11dGF0ZShsZWcgPSBmYWN0b3IobGVnLCBsZXZlbHMgPSBjKCJiYXNlbGluZSIsICJ0RENTIiwgInBvc3QuMSIsICJwb3N0LjIiKSkpICMgcmVvcmRlciBmYWN0b3IgbGV2ZWxzCmBgYAoKIyMjIEZpZ3VyZSA2CgpgYGB7ciBDcmVhdGUgYmFzZWxpbmUgZGV2aWF0aW9uIHBsb3QgbGFiZWxzfQpiYXNlbGluZUxhYmVsQWNjIDwtIGFjY01lYW5MZWcgJT4lCiAgZ3JvdXBfYnkoc3RpbXVsYXRpb24sZGlyZWN0aW9uLHR5cGUsbGVnKSAlPiUKICBmaWx0ZXIobGVnID09ICJiYXNlbGluZSIpICU+JQogIHN1bW1hcmlzZShkZXZpYXRpb24uZW5kLmJhc2VsaW5lID0gcm91bmQobWVhbihkZXZpYXRpb24uZW5kKSwgZGlnaXRzID0gMikpCmBgYAoKUGxvdCBtZWFuIF9sYXRlcmFsIHNhY2NhZGVfIGRldmlhdGlvbiBwZXIgcGFydGljaXBhbnQKCmBgYHtyIE1lYW4gZGV2aWF0aW9uIGxhdGVyYWwgc2FjY2FkZXN9CnBsb3Rfc3ViX2FjY19sYXRlcmFsIDwtIGdncGxvdChmaWx0ZXIoYWNjTWVhbkxlZywgdHlwZSA9PSAibGF0ZXJhbCIpLCBhZXMobGVnLCBkZXZpYXRpb24uZW5kKSkgKwogIGZhY2V0X2dyaWQoc3RpbXVsYXRpb24gfiBkaXJlY3Rpb24pICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gc3ViamVjdCwgY29sb3IgPSBzdWJqZWN0KSwgYWxwaGEgPSAwLjUpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBpbnRlcmFjdGlvbihzdGltdWxhdGlvbiwgZGlyZWN0aW9uKSwgbGluZXR5cGUgPSBkaXJlY3Rpb24pLCBnZW9tID0gImxpbmUiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIGFlcyhzaGFwZSA9IHN0aW11bGF0aW9uKSkgKwogIGd1aWRlcyhjb2xvdXIgPSBGQUxTRSkgKwogIHNjYWxlX3hfZGlzY3JldGUoInRpbWUiLCBsYWJlbHMgPSBjKCJiYXNlbGluZSIsICJ0RENTIiwgInBvc3QtMSIsICJwb3N0LTIiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHByZXNzaW9uKCJtZWFuIGRldmlhdGlvbiAiICggZGVncmVlKSksIGJyZWFrcyA9IHNlcSgwLjUsMiwwLjUpLCBsaW1pdHMgPSBjKDAuMywyLjIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAyMiwgdmp1c3QgPSAuNSksIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgZ2d0aXRsZSgiTGF0ZXJhbCBzYWNjYWRlcyIpCmBgYAoKUGxvdCBtZWFuIF9jZW50ZXIgc2FjY2FkZV8gZGV2aWF0aW9uIHBlciBwYXJ0aWNpcGFudAoKYGBge3IgTWVhbiBkZXZpYXRpb24gY2VudGVyIHNhY2NhZGVzfQpwbG90X3N1Yl9hY2NfY2VudGVyIDwtIGdncGxvdChmaWx0ZXIoYWNjTWVhbkxlZywgdHlwZSA9PSAiY2VudGVyIiksIGFlcyhsZWcsIGRldmlhdGlvbi5lbmQpKSArCiAgZmFjZXRfZ3JpZChzdGltdWxhdGlvbiB+IGRpcmVjdGlvbikgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzdWJqZWN0LCBjb2xvciA9IHN1YmplY3QpLCBhbHBoYSA9IDAuNSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhncm91cCA9IGludGVyYWN0aW9uKHN0aW11bGF0aW9uLCBkaXJlY3Rpb24pLCBsaW5ldHlwZSA9IGRpcmVjdGlvbiksIGdlb20gPSAibGluZSIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IiwgYWVzKHNoYXBlID0gc3RpbXVsYXRpb24pKSArCiAgZ3VpZGVzKGNvbG91ciA9IEZBTFNFKSArCiAgc2NhbGVfeF9kaXNjcmV0ZSgidGltZSIsIGxhYmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC0xIiwgInBvc3QtMiIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cHJlc3Npb24oIm1lYW4gZGV2aWF0aW9uICIgKCBkZWdyZWUpKSwgYnJlYWtzID0gc2VxKDAuNSwyLDAuNSksIGxpbWl0cyA9IGMoMC4zLDIuMikpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDIyLCB2anVzdCA9IC41KSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBnZ3RpdGxlKCJDZW50ZXIgc2FjY2FkZXMiKQpgYGAKClBsb3QgZ3JvdXAgbWVhbiBfbGF0ZXJhbCBzYWNjYWRlXyBkZXZpYXRpb24gYXMgY2hhbmdlIGZyb20gYmFzZWxpbmUKCmBgYHtyIEdyb3VwIG1lYW4gZGV2aWF0aW9uIGxhdGVyYWwgc2FjY2FkZXN9CnBsb3RfZ3JvdXBfYWNjX2xhdGVyYWwgPC0gZ2dwbG90KGZpbHRlcihhY2NNZWFuQmFzZWxpbmUsIHR5cGUgPT0gImxhdGVyYWwiKSwgYWVzKGxlZywgZGV2aWF0aW9uLmVuZC5iYXNlbGluZSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBzaXplID0gYmFzZV9saW5lX3NpemUpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBpbnRlcmFjdGlvbihzdGltdWxhdGlvbiwgZGlyZWN0aW9uKSwgY29sb3IgPSBzdGltdWxhdGlvbiwgbGluZXR5cGUgPSBkaXJlY3Rpb24pLCBnZW9tID0gImxpbmUiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgc2l6ZSA9IC43NSkgKyAKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCwgYWVzKGdyb3VwID0gaW50ZXJhY3Rpb24oc3RpbXVsYXRpb24sIGRpcmVjdGlvbiksIGNvbG9yID0gc3RpbXVsYXRpb24sIGxpbmV0eXBlID0gZGlyZWN0aW9uKSwgZ2VvbSA9ICJsaW5lcmFuZ2UiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhncm91cCA9IGludGVyYWN0aW9uKHN0aW11bGF0aW9uLCBkaXJlY3Rpb24pLCBjb2xvciA9IHN0aW11bGF0aW9uLCBzaGFwZSA9IHN0aW11bGF0aW9uKSwgZ2VvbSA9ICJwb2ludCIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLCBzaXplID0gMikgKwogIGdlb21fdGV4dChkYXRhID0gc3Vic2V0KGJhc2VsaW5lTGFiZWxBY2MsIHR5cGU9PSJsYXRlcmFsIiksIGFlcyh5ID0gYyguMDUsLjAyNSwuMSwuMDc1KSwgbGFiZWw9ZGV2aWF0aW9uLmVuZC5iYXNlbGluZSwgY29sb3IgPSBzdGltdWxhdGlvbiksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLCBzaXplID0gbW1fdG9fcHQpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNGMjVGNUMiLCAiIzRCOTNCMSIpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZSgidGltZSIsIGxhYmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC0xIiwgInBvc3QtMiIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cHJlc3Npb24oImRldmlhdGlvbiBjaGFuZ2UgZnJvbSBiYXNlbGluZSAiICggZGVncmVlKSksIGJyZWFrcyA9IHNlcSgtLjIsLjIsLjEpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0uMjIsLjIyKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjIsIHZqdXN0ID0gLjUpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKUGxvdCBncm91cCBtZWFuIF9jZW50ZXIgc2FjY2FkZV8gZGV2aWF0aW9uIGFzIGNoYW5nZSBmcm9tIGJhc2VsaW5lCgpgYGB7ciBHcm91cCBtZWFuIGRldmlhdGlvbiBjZW50ZXIgc2FjY2FkZXN9CnBsb3RfZ3JvdXBfYWNjX2NlbnRlciA8LSBnZ3Bsb3QoZmlsdGVyKGFjY01lYW5CYXNlbGluZSwgdHlwZSA9PSAiY2VudGVyIiksIGFlcyhsZWcsIGRldmlhdGlvbi5lbmQuYmFzZWxpbmUpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IGJhc2VfbGluZV9zaXplKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgYWVzKGdyb3VwID0gaW50ZXJhY3Rpb24oc3RpbXVsYXRpb24sIGRpcmVjdGlvbiksIGNvbG9yID0gc3RpbXVsYXRpb24sIGxpbmV0eXBlID0gZGlyZWN0aW9uKSwgZ2VvbSA9ICJsaW5lIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIHNpemUgPSAuNzUpICsgCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ub3JtYWwsIGFlcyhncm91cCA9IGludGVyYWN0aW9uKHN0aW11bGF0aW9uLCBkaXJlY3Rpb24pLCBjb2xvciA9IHN0aW11bGF0aW9uLCBsaW5ldHlwZSA9IGRpcmVjdGlvbiksIGdlb20gPSAibGluZXJhbmdlIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBpbnRlcmFjdGlvbihzdGltdWxhdGlvbiwgZGlyZWN0aW9uKSwgY29sb3IgPSBzdGltdWxhdGlvbiwgc2hhcGUgPSBzdGltdWxhdGlvbiksIGdlb20gPSAicG9pbnQiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgc2l6ZSA9IDIpICsKICBnZW9tX3RleHQoZGF0YSA9IHN1YnNldChiYXNlbGluZUxhYmVsQWNjLCB0eXBlPT0iY2VudGVyIiksIGFlcyh5ID0gYyguMDUsLjAyNSwuMSwuMDc1KSwgbGFiZWw9ZGV2aWF0aW9uLmVuZC5iYXNlbGluZSwgY29sb3IgPSBzdGltdWxhdGlvbiksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLCBzaXplID0gbW1fdG9fcHQpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNGMjVGNUMiLCAiIzRCOTNCMSIpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZSgidGltZSIsIGxhYmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC0xIiwgInBvc3QtMiIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cHJlc3Npb24oImRldmlhdGlvbiBjaGFuZ2UgZnJvbSBiYXNlbGluZSAiICggZGVncmVlKSksIGJyZWFrcyA9IHNlcSgtLjIsLjIsLjEpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0uMjIsLjIyKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjIsIHZqdXN0ID0gLjUpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKQ29tYmluZSBhbGwgdGhlIHBsb3RzOgoKYGBge3IgRmlndXJlIDZ9CmxlZ2VuZF9maWc2IDwtIGdldF9sZWdlbmQocGxvdF9ncm91cF9hY2NfbGF0ZXJhbCkKZmlndXJlXzYgPC0gcGxvdF9ncmlkKAogIHBsb3Rfc3ViX2FjY19sYXRlcmFsLCBwbG90X3N1Yl9hY2NfY2VudGVyLAogIHBsb3RfZ3JvdXBfYWNjX2xhdGVyYWwgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLAogIHBsb3RfZ3JvdXBfYWNjX2NlbnRlciArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksIHJlbF9oZWlnaHRzID0gYygxLC43NSkpCmZpZ3VyZV82IDwtIHBsb3RfZ3JpZChmaWd1cmVfNixsZWdlbmRfZmlnNixyZWxfd2lkdGhzID0gYygxLDEvMTApKQpmaWd1cmVfNgpgYGAKClNhdmUgdGhlIHBsb3Q6CgpgYGB7ciBTYXZlIGZpZ3VyZSA2LCBldmFsPUZBTFNFfQpnZ3NhdmUoImZpZy9maWd1cmVfNi5wZGYiLCBwbG90ID0gZmlndXJlXzYsIHdpZHRoID0gMTgwLCBoZWlnaHQgPSAxMTIuNSwgdW5pdHMgPSAibW0iKQpnZ3NhdmUoImZpZy9maWd1cmVfNi5wbmciLCBwbG90ID0gZmlndXJlXzYsIHdpZHRoID0gMTgwLCBoZWlnaHQgPSAxMTIuNSwgdW5pdHMgPSAibW0iKQpgYGAKCiMjIyBTdGF0aXN0aWNzCgojIyMjIEJhc2VsaW5lIHRlc3RzCgpgYGB7ciB0LXRlc3RzIG9mIGJhc2VsaW5lIGRpZmZlcmVuY2UgLSBkZXZpYXRpb259CmFjY01lYW5MZWcgJT4lCiAgZmlsdGVyKGxlZyA9PSAiYmFzZWxpbmUiKSAlPiUKICBncm91cF9ieShkaXJlY3Rpb24sdHlwZSkgJT4lIAogIG5lc3QoKSAlPiUgCiAgbXV0YXRlKHN0YXRzID0gbWFwKGRhdGEsIH50LnRlc3QoZm9ybXVsYSA9IGRldmlhdGlvbi5lbmR+c3RpbXVsYXRpb24sIHBhaXJlZCA9IFRSVUUsIGRhdGEgPS4pKSkgJT4lICMgcnVuIHQtdGVzdCBvbiB0aGUgZGF0YSBmcmFtZXMKICBtdXRhdGUodGlkeV9tb2RlbCA9IG1hcChzdGF0cywgdGlkeSkpICU+JQogIHVubmVzdCh0aWR5X21vZGVsLCAuZHJvcCA9IFRSVUUpICU+JSAKICBrYWJsZSguKQpgYGAKCiMjIyMgRGlmZmVyZW5jZXMgYWZ0ZXIgYmFzZWxpbmUKCkJlY2F1c2UgdGhlcmUgbWlnaHQgYmUgYSBzaWduaWZpY2FudCBiYXNlbGluZSBkaWZmZXJlbmNlIGZvciBjZW50ZXIgc2FjY2FkZXMsIGFsc28gcHJpbnQgdGhlIG51bWVyaWNhbCB2YWx1ZXMgZm9yIHRoZSBibG9ja3MgYWZ0ZXIsIHRvIHNlZSB3aGV0aGVyIHRoZXkgY29udGludWUgdG8gZGlmZmVyCgpgYGB7ciB0aW1lIHBlcmlvZHMgYWZ0ZXIgYmFzZWxpbmV9CmFjY01lYW5MZWcgJT4lCiAgZmlsdGVyKGxlZyAhPSAiYmFzZWxpbmUiLCB0eXBlID09ICJjZW50ZXIiKSAlPiUKICBncm91cF9ieShzdGltdWxhdGlvbixkaXJlY3Rpb24sbGVnKSAlPiUgCiAgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKGRldmlhdGlvbi5lbmQpKSAlPiUKICBrYWJsZSguKSAgICAgICAgICAgIApgYGAKCiMjIyMgTGF0ZXJhbCBzYWNjYWRlcyB7LnRhYnNldCAudGFic2V0LWZhZGV9CgojIyMjIyBDbGFzc2ljYWwgQU5PVkFzCgpSZXBlYXRlZCBtZWFzdXJlcyBBTk9WQSBtYXRjaGluZyBbS2FuYWkgZXQgYWwuICgyMDEyKV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMzM4OS9mcHN5dC4yMDEyLjAwMDQ1KS4KCl9fRGF0YV9fOiBCYXNlbGluZSBzdWJ0cmFjdGVkLCBsYXRlcmFsIHNhY2NhZGVzCgpfX0RlcGVuZGVudCBtZWFzdXJlX186IHNhY2NhZGUgZW5kcG9pbnQgZGV2aWF0aW9uCgpfX0ZhY3RvcnNfXzoKCiogU1RJTVVMQVRJT04gKGFub2RhbCB2cy4gY2F0aG9kYWwpCiogTEVHICh0RENTLCBwb3N0LjEsIHBvc3QuMikKKiBESVJFQ1RJT04gKGxlZnQgdnMuIHJpZ2h0KQoKUHJlcGFyZSBkYXRhOiAKCmBgYHtyIHRlc3QgZGF0YSBtZWFuIGRldmlhdGlvbiBsYXRlcmFsfQptZWFuQWNjTGF0ZXJhbFN0YXRzIDwtIGFjY01lYW5CYXNlbGluZSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKGxlZyAhPSAiYmFzZWxpbmUiLCB0eXBlID09ICJsYXRlcmFsIikgJT4lCiAgc2VsZWN0KC10eXBlKSAlPiUKICBtdXRhdGUobGVnID0gZmFjdG9yKGxlZywgbGV2ZWxzID0gYygidERDUyIsICJwb3N0LjEiLCAicG9zdC4yIikpKSAlPiUKICBtdXRhdGUoc3ViamVjdCA9IGZhY3RvcihzdWJqZWN0KSkKYGBgCgpgYGB7ciBybUFOT1ZBIG1lYW4gZGV2aWF0aW9uIGxhdGVyYWwsIHJlc3VsdHM9J2FzaXMnfQphb3ZNZWFuQWNjTGF0ZXJhbCA8LSBlekFOT1ZBKGRhdGEgPSBkYXRhLmZyYW1lKG1lYW5BY2NMYXRlcmFsU3RhdHMpLCBkdiA9IGRldmlhdGlvbi5lbmQuYmFzZWxpbmUsIHdpZCA9IHN1YmplY3QsIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sbGVnLGRpcmVjdGlvbiksIHR5cGUgPSAzKQoKa2FibGUoYW92TWVhbkFjY0xhdGVyYWwkQU5PVkEpCmthYmxlKGFvdk1lYW5BY2NMYXRlcmFsJGBNYXVjaGx5J3MgVGVzdCBmb3IgU3BoZXJpY2l0eWApCmthYmxlKGFvdk1lYW5BY2NMYXRlcmFsJGBTcGhlcmljaXR5IENvcnJlY3Rpb25zYCkKYGBgCgojIyMjIyBCYXllc2lhbiBBTk9WQSAKClNhbWUgZGVzaWduIGFzIHRoZSBjbGFzc2ljYWwgQU5PVkEgKHdpdGhvdXQgb3JkZXIgZWZmZWN0KQoKQmF5ZXMgZmFjdG9ycyBhZ2FpbnMgdGhlIG51bGwgbW9kZWw6CgpgYGB7ciBCYXllc2lhbiBBTk9WQSBtZWFuIGRldmlhdGlvbiBsYXRlcmFsfQpiZk1lYW5BY2NMYXRlcmFsID0gYW5vdmFCRihkZXZpYXRpb24uZW5kLmJhc2VsaW5lfnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24rc3ViamVjdCwgZGF0YSA9IGRhdGEuZnJhbWUobWVhbkFjY0xhdGVyYWxTdGF0cyksIHdoaWNoTW9kZWxzID0gIndpdGhtYWluIiwgd2hpY2hSYW5kb20gPSAic3ViamVjdCIsIHByb2dyZXNzID0gRkFMU0UsIGl0ZXJhdGlvbnMgPSAxMDAwMDApIApiZk1lYW5BY2NMYXRlcmFsID0gc29ydChiZk1lYW5BY2NMYXRlcmFsLCBkZWNyZWFzaW5nID0gVFJVRSkgIyBzb3J0IHN1Y2ggdGhhdCB3aW5uaW5nIG1vZGVsIGlzIGF0IHRoZSB0b3AKYGBgCgpgYGB7cn0Ka2FibGUoc2VsZWN0KGV4dHJhY3RCRihiZk1lYW5BY2NMYXRlcmFsKSwgYmYpKSAjIHNob3cgb25seSB0aGUgQmF5ZXMgZmFjdG9ycyBpbiBhIHRhYmxlCmBgYAoKSW5jbHVzaW9uIEJheWVzIGZhY3RvciBhY3Jvc3MgbWF0Y2hlZCBtb2RlbHM6CgpgYGB7ciBpbmNsdXNpb24gQkYgQU5PVkEgbWVhbiBkZXZpYXRpb24gbGF0ZXJhbH0Ka2FibGUoaW5jbHVzaW9uQkYoYmZNZWFuQWNjTGF0ZXJhbCwgbW9kZWxzID0gIm1hdGNoZWQiKSkKYGBgCgojIyMjIENlbnRlciBzYWNjYWRlcyB7LnRhYnNldCAudGFic2V0LWZhZGV9CgojIyMjIyBDbGFzc2ljYWwgQU5PVkEKClJlcGVhdGVkIG1lYXN1cmVzIEFOT1ZBIG1hdGNoaW5nIFtLYW5haSBldCBhbC4gKDIwMTIpXShodHRwOi8vZHguZG9pLm9yZy8xMC4zMzg5L2Zwc3l0LjIwMTIuMDAwNDUpLgoKX19EYXRhX186IEJhc2VsaW5lIHN1YnRyYWN0ZWQsIGNlbnRlciBzYWNjYWRlcwoKX19EZXBlbmRlbnQgbWVhc3VyZV9fOiBzYWNjYWRlIGVuZHBvaW50IGRldmlhdGlvbgoKX19GYWN0b3JzX186CgoqIFNUSU1VTEFUSU9OIChhbm9kYWwgdnMuIGNhdGhvZGFsKQoqIExFRyAodERDUywgcG9zdC4xLCBwb3N0LjIpCiogRElSRUNUSU9OIChsZWZ0IHZzLiByaWdodCkKClByZXBhcmUgZGF0YTogCgpgYGB7ciB0ZXN0IGRhdGEgbWVhbiBkZXZpYXRpb24gY2VudGVyfQptZWFuQWNjQ2VudGVyU3RhdHMgPC0gYWNjTWVhbkJhc2VsaW5lICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIobGVnICE9ICJiYXNlbGluZSIsIHR5cGUgPT0gImNlbnRlciIpICU+JQogIHNlbGVjdCgtdHlwZSkgJT4lCiAgbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoInREQ1MiLCAicG9zdC4xIiwgInBvc3QuMiIpKSkgJT4lCiAgbXV0YXRlKHN1YmplY3QgPSBmYWN0b3Ioc3ViamVjdCkpCmBgYAoKYGBge3Igcm1BTk9WQSBtZWFuIGRldmlhdGlvbiBjZW50ZXIsIHJlc3VsdHM9J2FzaXMnfQphb3ZNZWFuQWNjQ2VudGVyIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUobWVhbkFjY0NlbnRlclN0YXRzKSwgZHYgPSBkZXZpYXRpb24uZW5kLmJhc2VsaW5lLCB3aWQgPSBzdWJqZWN0LCB3aXRoaW4gPSAuKHN0aW11bGF0aW9uLGxlZyxkaXJlY3Rpb24pLCB0eXBlID0gMykKCmthYmxlKGFvdk1lYW5BY2NDZW50ZXIkQU5PVkEpCmthYmxlKGFvdk1lYW5BY2NDZW50ZXIkYE1hdWNobHkncyBUZXN0IGZvciBTcGhlcmljaXR5YCkKa2FibGUoYW92TWVhbkFjY0NlbnRlciRgU3BoZXJpY2l0eSBDb3JyZWN0aW9uc2ApCmBgYAoKIyMjIyMgQmF5ZXNpYW4gQU5PVkEgCgpTYW1lIGRlc2lnbiBhcyB0aGUgY2xhc3NpY2FsIEFOT1ZBCgpCYXllcyBmYWN0b3JzIGFnYWlucyB0aGUgbnVsbCBtb2RlbDoKCmBgYHtyIEJheWVzaWFuIEFOT1ZBIG1lYW4gZGV2aWF0aW9uIGNlbnRlcn0KYmZNZWFuQWNjQ2VudGVyID0gYW5vdmFCRihkZXZpYXRpb24uZW5kLmJhc2VsaW5lfnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24rc3ViamVjdCwgZGF0YSA9IGRhdGEuZnJhbWUobWVhbkFjY0NlbnRlclN0YXRzKSwgd2hpY2hNb2RlbHMgPSAid2l0aG1haW4iLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgCmJmTWVhbkFjY0NlbnRlciA9IHNvcnQoYmZNZWFuQWNjQ2VudGVyLCBkZWNyZWFzaW5nID0gVFJVRSkgIyBzb3J0IHN1Y2ggdGhhdCB3aW5uaW5nIG1vZGVsIGlzIGF0IHRoZSB0b3AKYGBgCgpgYGB7cn0Ka2FibGUoc2VsZWN0KGV4dHJhY3RCRihiZk1lYW5BY2NDZW50ZXIpLCBiZikpICMgc2hvdyBvbmx5IHRoZSBCYXllcyBmYWN0b3JzIGluIGEgdGFibGUKYGBgCgpJbmNsdXNpb24gQmF5ZXMgZmFjdG9yIGFjcm9zcyBtYXRjaGVkIG1vZGVsczoKCmBgYHtyIGluY2x1c2lvbiBCRiBBTk9WQSBtZWFuIGRldmlhdGlvbiBjZW50ZXJ9CmthYmxlKGluY2x1c2lvbkJGKGJmTWVhbkFjY0NlbnRlciwgbW9kZWxzID0gIm1hdGNoZWQiKSkKYGBgCgojIyMjIyBGb2xsb3ctdXAgdGVzdHMKCiMjIyMjIyBNYWluIGVmZmVjdCBvZiBzdGltdWxhdGlvbgoKRm9sbG93LXVwIE9uZS1zYW1wbGUgdC10ZXN0OgoKYGBge3IgQ2xhc3NpY2FsIGZvbGxvdy11cCB0ZXN0IC0gZGV2aWF0aW9ufQptZWFuQWNjQ2VudGVyU3RhdHMgJT4lCiAgZ3JvdXBfYnkoc3RpbXVsYXRpb24sc3ViamVjdCkgJT4lICMgZm9yIGVhY2ggc2Vzc2lvbiBhbmQgc3ViamVjdAogIHN1bW1hcmlzZShkZXZpYXRpb24gPSBtZWFuKGRldmlhdGlvbi5lbmQuYmFzZWxpbmUpKSAlPiUgIyBhdmVyYWdlIG92ZXIgYWxsIG90aGVyIHZhcmlhYmxlcyAoZGYgaXMgbm93IHN0aWxsIGdyb3VwZWQgcGVyIHN0aW11bGF0aW9uKQogIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBmdW5zKGxpc3QodGlkeSh0LnRlc3QoLikpKSkpICU+JSAgIyBydW4gb25lLXNhbXBsZSB0LXRlc3QgZm9yIGVhY2ggc3RpbXVsYXRpb24gY29uZGl0aW9uLCByZXR1cm4gdGlkeSBkYXRhIGZyYW1lcwogIHVubmVzdCgpICU+JSAjIHVucGFjayB0aGUgbGlzdC1jb2x1bW4gd2l0aCBkYXRhIGZyYW1lIGZvciBlYWNoIHRlc3QKICBrYWJsZSguKQpgYGAKCkZvbGxvdy11cCBCYXllc2lhbiBvbmUtc2FtcGxlIHQtdGVzdDoKCmBgYHtyIEJheWVzaWFuIGZvbGxvdy11cCB0ZXN0IC0gZGV2aWF0aW9ufQptZWFuQWNjQ2VudGVyU3RhdHMgJT4lCiAgZ3JvdXBfYnkoc3RpbXVsYXRpb24sc3ViamVjdCkgJT4lICMgZm9yIGVhY2ggc2Vzc2lvbiBhbmQgc3ViamVjdAogIHN1bW1hcmlzZShkZXZpYXRpb24gPSBtZWFuKGRldmlhdGlvbi5lbmQuYmFzZWxpbmUpKSAlPiUgIyBhdmVyYWdlIG92ZXIgYWxsIG90aGVyIHZhcmlhYmxlcwogIHNwcmVhZChzdGltdWxhdGlvbiwgZGV2aWF0aW9uKSAlPiUgIyBtYWtlIHNlcGFyYXRlIGNvbHVtbnMgd2l0aCB0ZXN0IGRhdGEKICBzdW1tYXJpc2VfaWYoaXMubnVtZXJpYywgZnVucyhleHRyYWN0QkYodHRlc3RCRiguKSwgb25seWJmID0gVFJVRSkpKSAlPiUgIyBydW4gQmF5ZXNpYW4gdC10ZXN0IG9uIGVhY2ggY29sdW1uLCBrZWVwaW5nIG9ubHkgdGhlIEJGCiAgZ2F0aGVyKHN0aW11bGF0aW9uLEJGLGFub2RhbCxjYXRob2RhbCkgJT4lICMgbWFrZSByb3cgZm9yIGVhY2ggc3RpbXVsYXRpb24gY29uZGl0aW9uCiAga2FibGUoLikKYGBgCgojIyBTYWNjYWRlIGVuZHBvaW50IHZhcmlhYmlsaXR5CgpfU2VlIHRoZSBgYWNjdXJhY3kubmIuaHRtbGAgbm90ZWJvb2sgZm9yIG1vcmUgZXhwbGFuYXRpb24gYW5kIGV4cGxvcmF0aW9uIG9mIHRoZSBzYWNjYWRlIGVuZHBvaW50IHZhcmlhYmlsaXR5IGRhdGFfCgpDYWxjdWxhdGUgZW5kcG9pbnQgdmFyaWFiaWxpdHksIGFzIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgaG9yaXpvbnRhbCBjb21wb25lbnQgKHgtY29vcmRpbmF0ZSkgb2Ygc2FjY2FkZXMKCmBgYHtyIGNhbGN1bGF0ZSBzdGFuZGFyZCBkZXZpYXRpb259CnZhck1lYW5MZWcgPC0gcHJlcHJvYyAlPiUKICBncm91cF9ieShzdWJqZWN0LHN0aW11bGF0aW9uLGxlZyxkaXJlY3Rpb24sdHlwZSkgJT4lIAogIHN1bW1hcmlzZShzdGQuZGV2aWF0aW9uLnggPSBzZChkZXZpYXRpb24uZW5kLngpKSAlPiUgIyBzdGFuZGFyZCBkZXZpYXRpb24KICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGxlZyA9IGFzLmNoYXJhY3RlcihsZWcpLCAjIGVkaXQgbGVnIGZhY3RvciB0byBtYXRjaCBvdGhlciBkYXRhIGZyYW1lcwogICAgICAgICBsZWcgPSByZXBsYWNlKGxlZywgbGVnID09ICJwcmUiLCAiYmFzZWxpbmUiKSwKICAgICAgICAgbGVnID0gZmFjdG9yKGxlZywgbGV2ZWxzID0gYygiYmFzZWxpbmUiLCAidERDUyIsICJwb3N0LjEiLCAicG9zdC4yIikpCiAgICAgICAgICkKYGBgCgpNYWtlIGEgc2VwYXJhdGUgZGF0YSBmcmFtZSB3aGVyZSB0aGUgbWVhbiB2YXJpYWJpbGl0eSBpcyBzdWJ0cmFjdGVkIGZyb20gc3Vic2VxdWVudCBibG9ja3MKCmBgYHtyIFN1YnRyYWN0IGJhc2VsaW5lIHZhcmlhYmlsaXR5fQp2YXJNZWFuQmFzZWxpbmUgPC0gdmFyTWVhbkxlZyAlPiUKICBncm91cF9ieShzdWJqZWN0LHN0aW11bGF0aW9uLGRpcmVjdGlvbix0eXBlKSAlPiUgIyBmb3IgZWFjaCBjb25kaXRpb24sIHN1YnRyYWN0IGJhc2VsaW5lIHNjb3JlcyBhbmQgbWFrZSBuZXcgY29sdW1ucwogIHN1bW1hcmlzZShiYXNlbGluZSA9IHN0ZC5kZXZpYXRpb24ueFtsZWcgPT0gImJhc2VsaW5lIl0gLSBzdGQuZGV2aWF0aW9uLnhbbGVnID09ICJiYXNlbGluZSJdLAogICAgICAgICAgIHREQ1MgPSBzdGQuZGV2aWF0aW9uLnhbbGVnID09ICJ0RENTIl0gLSBzdGQuZGV2aWF0aW9uLnhbbGVnID09ICJiYXNlbGluZSJdLAogICAgICAgICAgIHBvc3QuMSA9IHN0ZC5kZXZpYXRpb24ueFtsZWcgPT0gInBvc3QuMSJdIC0gc3RkLmRldmlhdGlvbi54W2xlZyA9PSAiYmFzZWxpbmUiXSwKICAgICAgICAgICBwb3N0LjIgPSBzdGQuZGV2aWF0aW9uLnhbbGVnID09ICJwb3N0LjIiXSAtIHN0ZC5kZXZpYXRpb24ueFtsZWcgPT0gImJhc2VsaW5lIl0pICU+JQogIGdhdGhlcihsZWcsIHN0ZC5kZXZpYXRpb24ueC5iYXNlbGluZSwgYmFzZWxpbmUsIHREQ1MsIHBvc3QuMSwgcG9zdC4yKSAgJT4lICMgZ2F0aGVyIG5ldyBjb2x1bW5zIHRvIHVzZSBhcyBmYWN0b3IgCiAgbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC4xIiwgInBvc3QuMiIpKSkgIyByZW9yZGVyIGZhY3RvciBsZXZlbHMKYGBgCgojIyMgRmlndXJlIDcKCmBgYHtyIENyZWF0ZSBiYXNlbGluZSB2YXJpYWJpbGl0eSBwbG90IGxhYmVsc30KYmFzZWxpbmVMYWJlbFZhciA8LSB2YXJNZWFuTGVnICU+JQogIGdyb3VwX2J5KHN0aW11bGF0aW9uLGRpcmVjdGlvbix0eXBlLGxlZykgJT4lCiAgZmlsdGVyKGxlZyA9PSAiYmFzZWxpbmUiKSAlPiUKICBzdW1tYXJpc2Uoc3RkLmRldmlhdGlvbi54LmJhc2VsaW5lID0gcm91bmQobWVhbihzdGQuZGV2aWF0aW9uLngpLCBkaWdpdHMgPSAyKSkKYGBgCgpQbG90IG1lYW4gX2xhdGVyYWwgc2FjY2FkZV8gdmFyaWFiaWxpdHkgcGVyIHBhcnRpY2lwYW50CgpgYGB7ciBNZWFuIHZhcmlhYmlsaXR5IGxhdGVyYWwgc2FjY2FkZXN9CnBsb3Rfc3ViX3Zhcl9sYXRlcmFsIDwtIGdncGxvdChmaWx0ZXIodmFyTWVhbkxlZywgdHlwZSA9PSAibGF0ZXJhbCIpLCBhZXMobGVnLCBzdGQuZGV2aWF0aW9uLngpKSArCiAgZmFjZXRfZ3JpZChzdGltdWxhdGlvbiB+IGRpcmVjdGlvbikgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzdWJqZWN0LCBjb2xvciA9IHN1YmplY3QpLCBhbHBoYSA9IDAuNSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhncm91cCA9IGludGVyYWN0aW9uKHN0aW11bGF0aW9uLCBkaXJlY3Rpb24pLCBsaW5ldHlwZSA9IGRpcmVjdGlvbiksIGdlb20gPSAibGluZSIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IiwgYWVzKHNoYXBlID0gc3RpbXVsYXRpb24pKSArCiAgZ3VpZGVzKGNvbG91ciA9IEZBTFNFKSArCiAgc2NhbGVfeF9kaXNjcmV0ZSgidGltZSIsIGxhYmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC0xIiwgInBvc3QtMiIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cHJlc3Npb24oInN0YW5kYXJkIGRldmlhdGlvbiAiICggZGVncmVlKSksIGJyZWFrcyA9IHNlcSgwLjUsMiwwLjUpLCBsaW1pdHMgPSBjKDAsMikpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDIyLCB2anVzdCA9IC41KSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBnZ3RpdGxlKCJMYXRlcmFsIHNhY2NhZGVzIikKYGBgCgpQbG90IG1lYW4gX2NlbnRlciBzYWNjYWRlXyB2YXJpYWJpbGl0eSBwZXIgcGFydGljaXBhbnQKCmBgYHtyIE1lYW4gdmFyaWFiaWxpdHkgY2VudGVyIHNhY2NhZGVzfQpwbG90X3N1Yl92YXJfY2VudGVyIDwtIGdncGxvdChmaWx0ZXIodmFyTWVhbkxlZywgdHlwZSA9PSAiY2VudGVyIiksIGFlcyhsZWcsIHN0ZC5kZXZpYXRpb24ueCkpICsKICBmYWNldF9ncmlkKHN0aW11bGF0aW9uIH4gZGlyZWN0aW9uKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHN1YmplY3QsIGNvbG9yID0gc3ViamVjdCksIGFscGhhID0gMC41KSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgYWVzKGdyb3VwID0gaW50ZXJhY3Rpb24oc3RpbXVsYXRpb24sIGRpcmVjdGlvbiksIGxpbmV0eXBlID0gZGlyZWN0aW9uKSwgZ2VvbSA9ICJsaW5lIikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBhZXMoc2hhcGUgPSBzdGltdWxhdGlvbikpICsKICBndWlkZXMoY29sb3VyID0gRkFMU0UpICsKICBzY2FsZV94X2Rpc2NyZXRlKCJ0aW1lIiwgbGFiZWxzID0gYygiYmFzZWxpbmUiLCAidERDUyIsICJwb3N0LTEiLCAicG9zdC0yIikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwcmVzc2lvbigic3RhbmRhcmQgZGV2aWF0aW9uICIgKCBkZWdyZWUpKSwgYnJlYWtzID0gc2VxKDAuNSwyLDAuNSksIGxpbWl0cyA9IGMoMCwyKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjIsIHZqdXN0ID0gLjUpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGdndGl0bGUoIkNlbnRlciBzYWNjYWRlcyIpCmBgYAoKUGxvdCBncm91cCBtZWFuIF9sYXRlcmFsIHNhY2NhZGVfIHZhcmlhYmlsaXR5IGFzIGNoYW5nZSBmcm9tIGJhc2VsaW5lCgpgYGB7ciBHcm91cCBtZWFuIHZhcmlhYmlsaXR5IGxhdGVyYWwgc2FjY2FkZXN9CnBsb3RfZ3JvdXBfdmFyX2xhdGVyYWwgPC0gZ2dwbG90KGZpbHRlcih2YXJNZWFuQmFzZWxpbmUsIHR5cGUgPT0gImxhdGVyYWwiKSwgYWVzKGxlZywgc3RkLmRldmlhdGlvbi54LmJhc2VsaW5lKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSBiYXNlX2xpbmVfc2l6ZSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhncm91cCA9IGludGVyYWN0aW9uKHN0aW11bGF0aW9uLCBkaXJlY3Rpb24pLCBjb2xvciA9IHN0aW11bGF0aW9uLCBsaW5ldHlwZSA9IGRpcmVjdGlvbiksIGdlb20gPSAibGluZSIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLCBzaXplID0gLjc1KSArIAogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfbm9ybWFsLCBhZXMoZ3JvdXAgPSBpbnRlcmFjdGlvbihzdGltdWxhdGlvbiwgZGlyZWN0aW9uKSwgY29sb3IgPSBzdGltdWxhdGlvbiwgbGluZXR5cGUgPSBkaXJlY3Rpb24pLCBnZW9tID0gImxpbmVyYW5nZSIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgYWVzKGdyb3VwID0gaW50ZXJhY3Rpb24oc3RpbXVsYXRpb24sIGRpcmVjdGlvbiksIGNvbG9yID0gc3RpbXVsYXRpb24sIHNoYXBlID0gc3RpbXVsYXRpb24pLCBnZW9tID0gInBvaW50IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIHNpemUgPSAyKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBzdWJzZXQoYmFzZWxpbmVMYWJlbFZhciwgdHlwZT09ImxhdGVyYWwiKSwgYWVzKHkgPSBjKC4wNSwuMDI1LC4xLC4wNzUpLCBsYWJlbD0oc3RkLmRldmlhdGlvbi54LmJhc2VsaW5lKSwgY29sb3IgPSBzdGltdWxhdGlvbiksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpLCBzaXplID0gbW1fdG9fcHQpICsKICBzY2FsZV94X2Rpc2NyZXRlKCJ0aW1lIiwgbGFiZWxzID0gYygiYmFzZWxpbmUiLCAidERDUyIsICJwb3N0LTEiLCAicG9zdC0yIikpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNGMjVGNUMiLCAiIzRCOTNCMSIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cHJlc3Npb24oIlNEIGNoYW5nZSBmcm9tIGJhc2VsaW5lICIgKCBkZWdyZWUpKSwgYnJlYWtzID0gc2VxKC0uMiwuMiwuMSkpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoLS4yLC4yKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMjIsIHZqdXN0ID0gLjUpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKUGxvdCBncm91cCBtZWFuIF9jZW50ZXIgc2FjY2FkZV8gdmFyaWFiaWxpdHkgYXMgY2hhbmdlIGZyb20gYmFzZWxpbmUKCmBgYHtyIEdyb3VwIG1lYW4gdmFyaWFiaWxpdHkgY2VudGVyIHNhY2NhZGVzfQpwbG90X2dyb3VwX3Zhcl9jZW50ZXIgPC0gZ2dwbG90KGZpbHRlcih2YXJNZWFuQmFzZWxpbmUsIHR5cGUgPT0gImNlbnRlciIpLCBhZXMobGVnLCBzdGQuZGV2aWF0aW9uLnguYmFzZWxpbmUpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IGJhc2VfbGluZV9zaXplKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgYWVzKGdyb3VwID0gaW50ZXJhY3Rpb24oc3RpbXVsYXRpb24sIGRpcmVjdGlvbiksIGNvbG9yID0gc3RpbXVsYXRpb24sIGxpbmV0eXBlID0gZGlyZWN0aW9uKSwgZ2VvbSA9ICJsaW5lIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIHNpemUgPSAuNzUpICsgCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ub3JtYWwsIGFlcyhncm91cCA9IGludGVyYWN0aW9uKHN0aW11bGF0aW9uLCBkaXJlY3Rpb24pLCBjb2xvciA9IHN0aW11bGF0aW9uLCBsaW5ldHlwZSA9IGRpcmVjdGlvbiksIGdlb20gPSAibGluZXJhbmdlIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSksIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBpbnRlcmFjdGlvbihzdGltdWxhdGlvbiwgZGlyZWN0aW9uKSwgY29sb3IgPSBzdGltdWxhdGlvbiwgc2hhcGUgPSBzdGltdWxhdGlvbiksIGdlb20gPSAicG9pbnQiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgc2l6ZSA9IDIpICsKICBnZW9tX3RleHQoZGF0YSA9IHN1YnNldChiYXNlbGluZUxhYmVsVmFyLCB0eXBlPT0iY2VudGVyIiksIGFlcyh5ID0gYyguMDUsLjAyNSwuMSwuMDc1KSwgbGFiZWw9KHN0ZC5kZXZpYXRpb24ueC5iYXNlbGluZSksIGNvbG9yID0gc3RpbXVsYXRpb24pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSwgc2l6ZSA9IG1tX3RvX3B0KSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjRjI1RjVDIiwgIiM0QjkzQjEiKSkgKwogIHNjYWxlX3hfZGlzY3JldGUoInRpbWUiLCBsYWJlbHMgPSBjKCJiYXNlbGluZSIsICJ0RENTIiwgInBvc3QtMSIsICJwb3N0LTIiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHByZXNzaW9uKCJTRCBjaGFuZ2UgZnJvbSBiYXNlbGluZSAiICggZGVncmVlKSksIGJyZWFrcyA9IHNlcSgtLjIsLjIsLjEpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKC0uMiwuMikpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDIyLCB2anVzdCA9IC41KSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCkNvbWJpbmUgYWxsIHRoZSBwbG90czoKCmBgYHtyIEZpZ3VyZSA3fQpsZWdlbmRfZmlnNyA8LSBnZXRfbGVnZW5kKHBsb3RfZ3JvdXBfYWNjX2xhdGVyYWwpCmZpZ3VyZV83IDwtIHBsb3RfZ3JpZCgKICBwbG90X3N1Yl92YXJfbGF0ZXJhbCwgcGxvdF9zdWJfdmFyX2NlbnRlciwKICBwbG90X2dyb3VwX3Zhcl9sYXRlcmFsICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSwKICBwbG90X2dyb3VwX3Zhcl9jZW50ZXIgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLCByZWxfaGVpZ2h0cyA9IGMoMSwuNzUpKQpmaWd1cmVfNyA8LSBwbG90X2dyaWQoZmlndXJlXzcsbGVnZW5kX2ZpZzcscmVsX3dpZHRocyA9IGMoMSwxLzEwKSkKZmlndXJlXzcKYGBgCgpTYXZlIHRoZSBwbG90OgoKYGBge3IgU2F2ZSBmaWd1cmUgNywgZXZhbD1GQUxTRX0KZ2dzYXZlKCJmaWcvZmlndXJlXzcucGRmIiwgcGxvdCA9IGZpZ3VyZV83LCB3aWR0aCA9IDE4MCwgaGVpZ2h0ID0gMTEyLjUsIHVuaXRzID0gIm1tIikKZ2dzYXZlKCJmaWcvZmlndXJlXzcucG5nIiwgcGxvdCA9IGZpZ3VyZV83LCB3aWR0aCA9IDE4MCwgaGVpZ2h0ID0gMTEyLjUsIHVuaXRzID0gIm1tIikKYGBgCgojIyMgU3RhdGlzdGljcyAKCiMjIyMgQmFzZWxpbmUgdGVzdHMgCgpgYGB7ciB0LXRlc3RzIG9mIGJhc2VsaW5lIGRpZmZlcmVuY2UgLSB2YXJpYWJpbGl0eX0KdmFyTWVhbkxlZyAlPiUKICBmaWx0ZXIobGVnID09ICJiYXNlbGluZSIpICU+JQogIGdyb3VwX2J5KGRpcmVjdGlvbix0eXBlKSAlPiUgCiAgbmVzdCgpICU+JSAKICBtdXRhdGUoc3RhdHMgPSBtYXAoZGF0YSwgfnQudGVzdChmb3JtdWxhID0gc3RkLmRldmlhdGlvbi54fnN0aW11bGF0aW9uLCBwYWlyZWQgPSBUUlVFLCBkYXRhID0uKSkpICU+JSAjIHJ1biB0LXRlc3Qgb24gdGhlIGRhdGEgZnJhbWVzCiAgbXV0YXRlKHRpZHlfbW9kZWwgPSBtYXAoc3RhdHMsIHRpZHkpKSAlPiUKICB1bm5lc3QodGlkeV9tb2RlbCwgLmRyb3AgPSBUUlVFKSAlPiUgCiAga2FibGUoLikKYGBgCgojIyMjIExhdGVyYWwgc2FjY2FkZXMgey50YWJzZXQgLnRhYnNldC1mYWRlfQoKIyMjIyMgQ2xhc3NpY2FsIEFOT1ZBCgpSZXBlYXRlZCBtZWFzdXJlcyBBTk9WQSBtYXRjaGluZyBbS2FuYWkgZXQgYWwuICgyMDEyKV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMzM4OS9mcHN5dC4yMDEyLjAwMDQ1KS4KCl9fRGF0YV9fOiBCYXNlbGluZSBzdWJ0cmFjdGVkLCBsYXRlcmFsIHNhY2NhZGVzCgpfX0RlcGVuZGVudCBtZWFzdXJlX186IHNhY2NhZGUgZW5kcG9pbnQgdmFyaWFiaWxpdHkgKHgtY29vcmRpbmF0ZSBzdGFuZGFyZCBkZXZpYXRpb24pCgpfX0ZhY3RvcnNfXzoKCiogU1RJTVVMQVRJT04gKGFub2RhbCB2cy4gY2F0aG9kYWwpCiogTEVHICh0RENTLCBwb3N0LjEsIHBvc3QuMikKKiBESVJFQ1RJT04gKGxlZnQgdnMuIHJpZ2h0KQoKUHJlcGFyZSBkYXRhOiAKCmBgYHtyIHRlc3QgZGF0YSBtZWFuIHZhcmlhYmlsaXR5IGxhdGVyYWx9Cm1lYW5WYXJMYXRlcmFsU3RhdHMgPC0gdmFyTWVhbkJhc2VsaW5lICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIobGVnICE9ICJiYXNlbGluZSIsIHR5cGUgPT0gImxhdGVyYWwiKSAlPiUKICBzZWxlY3QoLXR5cGUpICU+JQogIG11dGF0ZShsZWcgPSBmYWN0b3IobGVnLCBsZXZlbHMgPSBjKCJ0RENTIiwgInBvc3QuMSIsICJwb3N0LjIiKSkpICU+JQogIG11dGF0ZShzdWJqZWN0ID0gZmFjdG9yKHN1YmplY3QpKQpgYGAKCmBgYHtyIHJtQU5PVkEgbWVhbiB2YXJpYWJpbGl0eSBsYXRlcmFsLCByZXN1bHRzPSdhc2lzJ30KYW92TWVhblZhckxhdGVyYWwgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShtZWFuVmFyTGF0ZXJhbFN0YXRzKSwgZHYgPSBzdGQuZGV2aWF0aW9uLnguYmFzZWxpbmUsIHdpZCA9IHN1YmplY3QsIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sbGVnLGRpcmVjdGlvbiksIHR5cGUgPSAzKQoKa2FibGUoYW92TWVhblZhckxhdGVyYWwkQU5PVkEpCmthYmxlKGFvdk1lYW5WYXJMYXRlcmFsJGBNYXVjaGx5J3MgVGVzdCBmb3IgU3BoZXJpY2l0eWApCmthYmxlKGFvdk1lYW5WYXJMYXRlcmFsJGBTcGhlcmljaXR5IENvcnJlY3Rpb25zYCkKYGBgCgojIyMjIyBCYXllc2lhbiBBTk9WQQoKU2FtZSBkZXNpZ24gYXMgdGhlIGNsYXNzaWNhbCBBTk9WQQoKQmF5ZXMgZmFjdG9ycyBhZ2FpbnMgdGhlIG51bGwgbW9kZWw6CgpgYGB7ciBCYXllc2lhbiBBTk9WQSBtZWFuIHZhcmlhYmlsaXR5IGxhdGVyYWx9CmJmTWVhblZhckxhdGVyYWwgPSBhbm92YUJGKHN0ZC5kZXZpYXRpb24ueC5iYXNlbGluZX5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uK3N1YmplY3QsIGRhdGEgPSBkYXRhLmZyYW1lKG1lYW5WYXJMYXRlcmFsU3RhdHMpLCB3aGljaE1vZGVscyA9ICJ3aXRobWFpbiIsIHdoaWNoUmFuZG9tID0gInN1YmplY3QiLCBwcm9ncmVzcyA9IEZBTFNFLCBpdGVyYXRpb25zID0gMTAwMDAwKSAKYmZNZWFuVmFyTGF0ZXJhbCA9IHNvcnQoYmZNZWFuVmFyTGF0ZXJhbCwgZGVjcmVhc2luZyA9IFRSVUUpICMgc29ydCBzdWNoIHRoYXQgd2lubmluZyBtb2RlbCBpcyBhdCB0aGUgdG9wCmBgYAoKYGBge3J9CmthYmxlKHNlbGVjdChleHRyYWN0QkYoYmZNZWFuVmFyTGF0ZXJhbCksIGJmKSkgIyBzaG93IG9ubHkgdGhlIEJheWVzIGZhY3RvcnMgaW4gYSB0YWJsZQpgYGAKCkluY2x1c2lvbiBCYXllcyBmYWN0b3IgYWNyb3NzIG1hdGNoZWQgbW9kZWxzOgoKYGBge3IgaW5jbHVzaW9uIEJGIEFOT1ZBIG1lYW4gdmFyaWFiaWxpdHkgbGF0ZXJhbH0Ka2FibGUoaW5jbHVzaW9uQkYoYmZNZWFuVmFyTGF0ZXJhbCwgbW9kZWxzID0gIm1hdGNoZWQiKSkKYGBgCgojIyMjIENlbnRlciBzYWNjYWRlcyB7LnRhYnNldCAudGFic2V0LWZhZGV9CgojIyMjIyBDbGFzc2ljYWwgQU5PVkEKClJlcGVhdGVkIG1lYXN1cmVzIEFOT1ZBIG1hdGNoaW5nIFtLYW5haSBldCBhbC4gKDIwMTIpXShodHRwOi8vZHguZG9pLm9yZy8xMC4zMzg5L2Zwc3l0LjIwMTIuMDAwNDUpLgoKX19EYXRhX186IEJhc2VsaW5lIHN1YnRyYWN0ZWQsIGNlbnRlciBzYWNjYWRlcwoKX19EZXBlbmRlbnQgbWVhc3VyZV9fOiBzYWNjYWRlIGVuZHBvaW50IHZhcmlhYmlsaXR5ICh4LWNvb3JkaW5hdGUgc3RhbmRhcmQgZGV2aWF0aW9uKQoKX19GYWN0b3JzX186CgoqIFNUSU1VTEFUSU9OIChhbm9kYWwgdnMuIGNhdGhvZGFsKQoqIExFRyAodERDUywgcG9zdC4xLCBwb3N0LjIpCiogRElSRUNUSU9OIChsZWZ0IHZzLiByaWdodCkKClByZXBhcmUgZGF0YTogCgpgYGB7ciB0ZXN0IGRhdGEgbWVhbiB2YXJpYWJpbGl0eSBjZW50ZXJ9Cm1lYW5WYXJDZW50ZXJTdGF0cyA8LSB2YXJNZWFuQmFzZWxpbmUgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcihsZWcgIT0gImJhc2VsaW5lIiwgdHlwZSA9PSAiY2VudGVyIikgJT4lCiAgc2VsZWN0KC10eXBlKSAlPiUKICBtdXRhdGUobGVnID0gZmFjdG9yKGxlZywgbGV2ZWxzID0gYygidERDUyIsICJwb3N0LjEiLCAicG9zdC4yIikpKSAlPiUKICBtdXRhdGUoc3ViamVjdCA9IGZhY3RvcihzdWJqZWN0KSkKYGBgCgpgYGB7ciBybUFOT1ZBIG1lYW4gdmFyaWFiaWxpdHkgY2VudGVyLCByZXN1bHRzPSdhc2lzJ30KYW92TWVhblZhckNlbnRlciA8LSBlekFOT1ZBKGRhdGEgPSBkYXRhLmZyYW1lKG1lYW5WYXJDZW50ZXJTdGF0cyksIGR2ID0gc3RkLmRldmlhdGlvbi54LmJhc2VsaW5lLCB3aWQgPSBzdWJqZWN0LCB3aXRoaW4gPSAuKHN0aW11bGF0aW9uLGxlZyxkaXJlY3Rpb24pLCB0eXBlID0gMykKCmthYmxlKGFvdk1lYW5WYXJDZW50ZXIkQU5PVkEpCmthYmxlKGFvdk1lYW5WYXJDZW50ZXIkYE1hdWNobHkncyBUZXN0IGZvciBTcGhlcmljaXR5YCkKa2FibGUoYW92TWVhblZhckNlbnRlciRgU3BoZXJpY2l0eSBDb3JyZWN0aW9uc2ApCmBgYAoKIyMjIyMgQmF5ZXNpYW4gQU5PVkEKClNhbWUgZGVzaWduIGFzIHRoZSBjbGFzc2ljYWwgQU5PVkEKCkJheWVzIGZhY3RvcnMgYWdhaW5zIHRoZSBudWxsIG1vZGVsOgoKYGBge3IgQmF5ZXNpYW4gQU5PVkEgbWVhbiB2YXJpYWJpbGl0eSBjZW50ZXJ9CmJmTWVhblZhckNlbnRlciA9IGFub3ZhQkYoc3RkLmRldmlhdGlvbi54LmJhc2VsaW5lfnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24rc3ViamVjdCwgZGF0YSA9IGRhdGEuZnJhbWUobWVhblZhckNlbnRlclN0YXRzKSwgd2hpY2hNb2RlbHMgPSAid2l0aG1haW4iLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgCmJmTWVhblZhckNlbnRlciA9IHNvcnQoYmZNZWFuVmFyQ2VudGVyLCBkZWNyZWFzaW5nID0gVFJVRSkgIyBzb3J0IHN1Y2ggdGhhdCB3aW5uaW5nIG1vZGVsIGlzIGF0IHRoZSB0b3AKYGBgCgpgYGB7cn0Ka2FibGUoc2VsZWN0KGV4dHJhY3RCRihiZk1lYW5WYXJDZW50ZXIpLCBiZikpICMgc2hvdyBvbmx5IHRoZSBCYXllcyBmYWN0b3JzIGluIGEgdGFibGUKYGBgCgpJbmNsdXNpb24gQmF5ZXMgZmFjdG9yIGFjcm9zcyBtYXRjaGVkIG1vZGVsczoKCmBgYHtyIGluY2x1c2lvbiBCRiBBTk9WQSBtZWFuIHZhcmlhYmlsaXR5IGNlbnRlcn0Ka2FibGUoaW5jbHVzaW9uQkYoYmZNZWFuVmFyQ2VudGVyLCBtb2RlbHMgPSAibWF0Y2hlZCIpKQpgYGAKCiMjIyMjIEZvbGxvdy11cCB0ZXN0cwoKIyMjIyMjIE1haW4gZWZmZWN0IG9mIHN0aW11bGF0aW9uCgpGb2xsb3ctdXAgT25lLXNhbXBsZSB0LXRlc3Q6CgpgYGB7ciBDbGFzc2ljYWwgZm9sbG93LXVwIHRlc3QgLSB2YXJpYWJpbGl0eX0KbWVhblZhckNlbnRlclN0YXRzICU+JQogIGdyb3VwX2J5KHN0aW11bGF0aW9uLHN1YmplY3QpICU+JSAjIGZvciBlYWNoIHNlc3Npb24gYW5kIHN1YmplY3QKICBzdW1tYXJpc2Uoc3RkLmRldmlhdGlvbi54LiA9IG1lYW4oc3RkLmRldmlhdGlvbi54LmJhc2VsaW5lKSkgJT4lICMgYXZlcmFnZSBvdmVyIGFsbCBvdGhlciB2YXJpYWJsZXMgKGRmIGlzIG5vdyBzdGlsbCBncm91cGVkIHBlciBzdGltdWxhdGlvbikKICBzdW1tYXJpc2VfaWYoaXMubnVtZXJpYywgZnVucyhsaXN0KHRpZHkodC50ZXN0KC4pKSkpKSAlPiUgICMgcnVuIG9uZS1zYW1wbGUgdC10ZXN0IGZvciBlYWNoIHN0aW11bGF0aW9uIGNvbmRpdGlvbiwgcmV0dXJuIHRpZHkgZGF0YSBmcmFtZXMKICB1bm5lc3QoKSAlPiUgIyB1bnBhY2sgdGhlIGxpc3QtY29sdW1uIHdpdGggZGF0YSBmcmFtZSBmb3IgZWFjaCB0ZXN0CiAga2FibGUoLikKYGBgCgpGb2xsb3ctdXAgQmF5ZXNpYW4gb25lLXNhbXBsZSB0LXRlc3Q6CgpgYGB7ciBCYXllc2lhbiBmb2xsb3ctdXAgdGVzdCAtIHZhcmlhYmlsaXR5fQptZWFuVmFyQ2VudGVyU3RhdHMgJT4lCiAgZ3JvdXBfYnkoc3RpbXVsYXRpb24sc3ViamVjdCkgJT4lICMgZm9yIGVhY2ggc2Vzc2lvbiBhbmQgc3ViamVjdAogIHN1bW1hcmlzZShzdGQuZGV2aWF0aW9uLnggPSBtZWFuKHN0ZC5kZXZpYXRpb24ueC5iYXNlbGluZSkpICU+JSAjIGF2ZXJhZ2Ugb3ZlciBhbGwgb3RoZXIgdmFyaWFibGVzCiAgc3ByZWFkKHN0aW11bGF0aW9uLCBzdGQuZGV2aWF0aW9uLngpICU+JSAjIG1ha2Ugc2VwYXJhdGUgY29sdW1ucyB3aXRoIHRlc3QgZGF0YQogIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBmdW5zKGV4dHJhY3RCRih0dGVzdEJGKC4pLCBvbmx5YmYgPSBUUlVFKSkpICU+JSAjIHJ1biBCYXllc2lhbiB0LXRlc3Qgb24gZWFjaCBjb2x1bW4sIGtlZXBpbmcgb25seSB0aGUgQkYKICBnYXRoZXIoc3RpbXVsYXRpb24sQkYsYW5vZGFsLGNhdGhvZGFsKSAlPiUgIyBtYWtlIHJvdyBmb3IgZWFjaCBzdGltdWxhdGlvbiBjb25kaXRpb24KICBrYWJsZSguKQpgYGAKCiMgUXVhbnRpbGUgYW5hbHlzaXMKCl9TZWUgdGhlIGBSVF9xdWFudGlsZXMubmIuaHRtbGAgbm90ZWJvb2sgZm9yIG1vcmUgZXhwbGFuYXRpb24gYW5kIGV4cGxvcmF0aW9uIG9mIHRoZSBzYWNjYWRlIGxhdGVuY3kgZGlzdHJpYnV0aW9uIGRhdGFfCgpFc3RpbWF0ZSBxdWFudGlsZXMgYW5kIGNvbXB1dGUgc2hpZnQgZnVuY3Rpb246IAoKYGBge3IgUXVhbnRpbGVzIGFuZCBzaGlmdCBmdW5jdGlvbiwgZXZhbD1GQUxTRX0KcURhdGEgPC0gZ3JvdXBEYXRhICU+JQogIGZpbHRlcighaXMubmEobGF0ZW5jeSkpICU+JSAjIGRpc2NhcmQgbWlzc2luZyBzYWNjYWRlcwogIGdyb3VwX2J5KHN1YmplY3QsbGVnLHR5cGUsZGlyZWN0aW9uKSAlPiUgIyBmb3IgZWFjaCBjb25kaXRpb24KICBuZXN0KHN0aW11bGF0aW9uLGxhdGVuY3kpICU+JSAjIG1ha2UgYSBsaXN0X2NvbHVtbiAiZGF0YSIgb3V0IG9mIHRoZSBzdGltdWxhdGlvbiBhbmQgbGF0ZW5jeSBjb2x1bW5zLiBOb3csIGVhY2ggZ3JvdXAgaGFzIGl0cyBvd24gZGF0YSBmcmFtZSBjb25zaXN0aW5nIG9mIHRoZSBzdGltdWxhdGlvbiBhbmQgbGF0ZW5jeSBjb2x1bW5zIGZvciB0aGF0IGdyb3VwCiAgbXV0YXRlKHNoaWZ0ID0gcHVycnI6Om1hcChkYXRhLCB+IHNoaWZ0ZGhkX3BiY2koLiwgZm9ybXVsYSA9IGxhdGVuY3kgfiBzdGltdWxhdGlvbiwgbmJvb3QgPSAyMDAwKSkpICMgZm9yIGVhY2ggZ3JvdXAsIGVzdGltYXRlIHF1YW50aWxlcyBhbmQgY29tcHV0ZSBzaGlmdCBmdW5jdGlvbiwgYW5kIHN0b3JlIGFzIGEgbGlzdCBjb2x1bW4gaW4gInNoaWZ0IgoKcURhdGEgPC0gdW5uZXN0KHFEYXRhLHNoaWZ0KSAjIHVucGFjayB0aGUgbGlzdCBjb2x1bW4gdG8gZ2V0IHRoZSBtb2RlbCByZXN1bHRzIGZvciBlYWNoIGdyb3VwIGluIHRoZSBvcmlnaW5hbCBkYXRhIGZyYW1lCgojIEFsdGVybmF0aXZlbHksIGluc3RlYWQgb2YgIm5lc3QgLi4uIiwgIm11dGF0ZSAuLi4iIGFuZCAidW5uZXN0IC4uLiIsIHlvdSBjYW4gY2FsbCBzaGlmdGRoZCB0aHJvdWdoIGRwbHlyOjpkbyAoYnV0IHRoaXMgaXMgYmFzaWNhbGx5IGRlcHJlYXRlZCBpbiBmYXZvciBvZiBwdXJycjptYXApCiMgZG8oc2hpZnRkaGQoLlssYygic3RpbXVsYXRpb24iLCJsYXRlbmN5IildLCBmb3JtdWxhID0gbGF0ZW5jeSB+IHN0aW11bGF0aW9uLCBuYm9vdCA9IDEwMCkpICMgZXN0aW1hdGUgcXVhbnRpbGVzIGFuZCBjb21wdXRlIHNoaWZ0IGZ1bmN0aW9uCmBgYAoKTm90ZSB0aGF0IHRoaXMgdGFrZXMgcXVpdGUgYSB3aGlsZSB0byBjb21wdXRlIHdpdGggYSBsYXJnZSBudW1iZXIgb2YgYm9vdHN0cmFwIHNhbXBsZXMsIHNvIHdlIHdpbGwgbG9hZCB0aGUgcmVzdWx0IGZyb20gZGlzayBpbiB0aGUgbmV4dCBjb2RlIGNodW5rLiBCeSBkZWZhdWx0LCB0aGUgY2h1bmsgYWJvdmUgd2lsbCBub3QgcnVuIGJlY3Vhc2Ugb2YgdGhlIGBldmFsPUZBTFNFYCBzdGF0ZW1lbnQ7IHJlbW92ZSB0aGlzIHRvIGV4ZWN1dGUgaXQgYW5kIGNvbXB1dGUgdGhlIHJlc3VsdCBmcm9tIHNjcmF0Y2guCgpgYGB7ciBMb2FkIHF1YW50aWxlIGRhdGF9CnFEYXRhIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEiLCAic2FjYy10RENTX3F1YW50aWxlcy5jc3YiKSkgJT4lCiAgZmlsdGVyKCEoc3ViamVjdCAlaW4lIHN1YnMyZXhjbHVkZSkpICU+JSAjIGV4Y2x1ZGUgc3ViamVjdHMKICAgIG11dGF0ZShsZWcgPSByZXBsYWNlKGxlZywgbGVnID09ICJwcmUiLCAiYmFzZWxpbmUiKSwgIyByZW5hbWUgYW5kIHJlb2RlciBsZXZlbHMKICAgICAgICAgbGVnID0gcmVwbGFjZShsZWcsIGxlZyA9PSAicG9zdC4xIiwgInBvc3QtMSIpLAogICAgICAgICBsZWcgPSByZXBsYWNlKGxlZywgbGVnID09ICJwb3N0LjIiLCAicG9zdC0yIiksCiAgICAgICAgIGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC0xIiwgInBvc3QtMiIpKSkKICAKYGBgCgpgYGB7ciBBdmVyYWdlIGFub2RhbCBkZWNpbGVzfQpxU3RhdHMgPC0gcURhdGEgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxsZWcsdHlwZSxkaXJlY3Rpb24pICU+JQogIG11dGF0ZShkZWNvID0gYyhzZXEoMSw1KSxzZXEoNCwxKSkpICU+JSAjIGFkZCBjb2RlIG9mIGRlY2lsZXMgdG8gZGF0YSBmcmFtZQogIGdyb3VwX2J5KGxlZyx0eXBlLGRpcmVjdGlvbixxKSAlPiUgCiAgbXV0YXRlKGFub2RhbCA9IG1lYW4oYW5vZGFsKSkgJT4lICMgbWVhbiBvZiAiYW5vZGFsIiBxdWFudGlsZXMgT1ZFUiBzdWJqZWN0cwogIGdyb3VwX2J5KGxlZyx0eXBlLGRpcmVjdGlvbikgJT4lIAogIG11dGF0ZShhbm9kYWxfbWVkaWFuID0gbWVkaWFuKGFub2RhbCkpICMgbWVkaWFuIGZvciBwbG90dGluZwpgYGAKCkZvciBlYWNoIHF1YW50aWxlLCBjb3VudCB3aGljaCBzdWJqZWN0cyBzaG93IHNpZ25pZmljYW50IGVmZmVjdHMsIGFuZCBpbiB3aGljaCBkaXJlY3Rpb24KCmBgYHtyIENvdW50IHNpZ25pZmljYW5jZSBvZiBkZWNpbGVzfQpxU2lnIDwtIHFEYXRhICU+JQogIGdyb3VwX2J5KHN1YmplY3QsbGVnLHR5cGUsZGlyZWN0aW9uLHEpICU+JQogIG11dGF0ZShzaWduaWZpY2FuY2UgPSBOQSwKICAgICAgICAgIyBJZiAoYW5vZGFsIC0gY2F0aG9kYWwpIHF1YW50aWxlIGRpZmZlcmVuY2UgaXMgcG9zaXRpdmUsIGxhdGVuY3kgZm9yIGFub2RhbCA+IGxhdGVuY3kgZm9yIGNhdGhvZGFsCiAgICAgICAgIHNpZ25pZmljYW5jZSA9IHJlcGxhY2Uoc2lnbmlmaWNhbmNlLCBwX3ZhbHVlIDwgcF9jcml0ICYgZGlmZmVyZW5jZSA+IDAsICJjYXRob2RhbC5mYXN0ZXIiKSwKICAgICAgICAgIyBJZiAoYW5vZGFsIC0gY2F0aG9kYWwpIHF1YW50aWxlIGRpZmZlcmVuY2UgaXMgbmVnYXRpdmUsIGxhdGVuY3kgZm9yIGFub2RhbCA8IGxhdGVuY3kgZm9yIGNhdGhvZGFsCiAgICAgICAgIHNpZ25pZmljYW5jZSA9IHJlcGxhY2Uoc2lnbmlmaWNhbmNlLCBwX3ZhbHVlIDwgcF9jcml0ICYgZGlmZmVyZW5jZSA8IDAsICJhbm9kYWwuZmFzdGVyIikKICApCmBgYAoKIyMgRmlndXJlIDUKClNoaWZ0IGZ1bmN0aW9ucyBmb3IgX2xhdGVyYWwgc2FjY2FkZXNfCgpgYGB7ciBTaGlmdCBmdW5jdGlvbiBsYXRlcmFsfQpwbG90X3NoaWZ0X2xhdGVyYWwgPC0gZ2dwbG90KGZpbHRlcihxU3RhdHMsIHR5cGUgPT0gImxhdGVyYWwiKSwgYWVzKGFub2RhbCwgZGlmZmVyZW5jZSkpICsKICAgZmFjZXRfZ3JpZChsZWcgfiBkaXJlY3Rpb24pICsKICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgYWxwaGEgPSAwLjUpICsKICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IGFub2RhbF9tZWRpYW4pLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYSA9IDAuNSkgKwogICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCwgZ2VvbSA9ICJsaW5lcmFuZ2UiLCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMC41KSArCiAgIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIHNpemUgPSAxLCBjb2xvdXIgPSAiZ3JleTUwIiwgYWxwaGEgPSAwLjUpICsKICAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIGFlcyhmaWxsID0gZGVjbyksIHNpemUgPSAyLCBjb2xvdXIgPSAiYmxhY2siLCBzaGFwZSA9IDIxKSArCiAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJncmV5MzAiLCBndWlkZSA9IEZBTFNFKSArCiAgIHNjYWxlX3hfY29udGludW91cygiYW5vZGFsIGRlY2lsZXMgKG1zKSIsIGxpbWl0cyA9IGMoODAsMjAwKSwgYnJlYWtzID0gc2VxKDEwMCwyMDAsMjUpKSArCiAgIHNjYWxlX3lfY29udGludW91cygiYW5vZGFsIC0gY2F0aG9kYWwgZGVjaWxlcyAobXMpIikKYGBgCgpOdW1iZXIgb2Ygc3ViamVjdHMgd2l0aCBzaWduaWZjYW50IGRpZmZlcmVuY2UgcGVyIHF1YW50aWxlIGZvciBsYXRlcmFsIHNhY2NhZGVzCgpgYGB7ciBTaWduaWZpY2FuY2Ugc2hpZnQgZnVuY3Rpb24gbGF0ZXJhbH0KcGxvdF9zaWdfbGF0ZXJhbCA8LSBnZ3Bsb3QoZmlsdGVyKHFTaWcsIHR5cGUgPT0gImxhdGVyYWwiLCAhaXMubmEoc2lnbmlmaWNhbmNlKSksIGFlcyhxLCBmaWxsID0gc2lnbmlmaWNhbmNlKSkgKwogIGZhY2V0X2dyaWQobGVnIH4gZGlyZWN0aW9uKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siKSArCiAgc3RhdF9iaW4oYmlud2lkdGggPSAuMSwgZ2VvbSA9ICJ0ZXh0Iiwgc2l6ZSA9IG1tX3RvX3B0LCBhZXMobGFiZWwgPSAuLmNvdW50Li4pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGMjVGNUMiLCAiIzRCOTNCMSIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKCJkZWNpbGUiLCBicmVha3MgPSBzZXEoMC4xLDAuOSwwLjEpLCBsYWJlbHMgPSBzZXEoMSw5LDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCJudW1iZXIgb2YgcGFydGljaXBhbnRzIHdpdGggc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSIsIGxpbWl0cyA9IGMoMCwgbGVuZ3RoKHVuaXF1ZShxU2lnJHN1YmplY3QpKSksIGJyZWFrcyA9IGMoMCwxMCwyMCxsZW5ndGgodW5pcXVlKHFTaWckc3ViamVjdCkpKSkKYGBgCgpTaGlmdCBmdW5jdGlvbnMgZm9yIF9jZW50ZXIgc2FjY2FkZXNfCgpgYGB7ciBTaGlmdCBmdW5jdGlvbiBjZW50ZXJ9CnBsb3Rfc2hpZnRfY2VudGVyIDwtIGdncGxvdChmaWx0ZXIocVN0YXRzLCB0eXBlID09ICJjZW50ZXIiKSwgYWVzKGFub2RhbCwgZGlmZmVyZW5jZSkpICsKICAgZmFjZXRfZ3JpZChsZWcgfiBkaXJlY3Rpb24pICsKICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgYWxwaGEgPSAwLjUpICsKICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IGFub2RhbF9tZWRpYW4pLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYSA9IDAuNSkgKwogICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCwgZ2VvbSA9ICJsaW5lcmFuZ2UiLCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMC41KSArCiAgIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIHNpemUgPSAxLCBjb2xvdXIgPSAiZ3JleTUwIiwgYWxwaGEgPSAwLjUpICsKICAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIGFlcyhmaWxsID0gZGVjbyksIHNpemUgPSAyLCBjb2xvdXIgPSAiYmxhY2siLCBzaGFwZSA9IDIxKSArCiAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJncmV5MzAiLCBndWlkZSA9IEZBTFNFKSArCiAgIHNjYWxlX3hfY29udGludW91cygiYW5vZGFsIGRlY2lsZXMgKG1zKSIsIGxpbWl0cyA9IGMoODAsMjAwKSwgYnJlYWtzID0gc2VxKDEwMCwyMDAsMjUpKSArCiAgIHNjYWxlX3lfY29udGludW91cygiYW5vZGFsIC0gY2F0aG9kYWwgZGVjaWxlcyAobXMpIikKYGBgCgoKTnVtYmVyIG9mIHN1YmplY3RzIHdpdGggc2lnbmlmY2FudCBkaWZmZXJlbmNlIHBlciBxdWFudGlsZSBmb3IgbGF0ZXJhbCBzYWNjYWRlcwoKYGBge3IgU2lnbmlmaWNhbmNlIHNoaWZ0IGZ1bmN0aW9uIGNlbnRlcn0KcGxvdF9zaWdfY2VudGVyIDwtIGdncGxvdChmaWx0ZXIocVNpZywgdHlwZSA9PSAiY2VudGVyIiwgIWlzLm5hKHNpZ25pZmljYW5jZSkpLCBhZXMocSwgZmlsbCA9IHNpZ25pZmljYW5jZSkpICsKICBmYWNldF9ncmlkKGxlZyB+IGRpcmVjdGlvbikgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIikgKwogIHN0YXRfYmluKGJpbndpZHRoID0gLjEsIGdlb20gPSAidGV4dCIsIHNpemUgPSBtbV90b19wdCwgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRjI1RjVDIiwgIiM0QjkzQjEiKSkgKwogIHNjYWxlX3hfY29udGludW91cygiZGVjaWxlIiwgYnJlYWtzID0gc2VxKDAuMSwwLjksMC4xKSwgbGFiZWxzID0gc2VxKDEsOSwxKSkgKwogIHNjYWxlX3lfY29udGludW91cygibnVtYmVyIG9mIHBhcnRpY2lwYW50cyB3aXRoIHNpZ25pZmljYW50IGRpZmZlcmVuY2UiLCBsaW1pdHMgPSBjKDAsIGxlbmd0aCh1bmlxdWUocVNpZyRzdWJqZWN0KSkpLCBicmVha3MgPSBjKDAsMTAsMjAsbGVuZ3RoKHVuaXF1ZShxU2lnJHN1YmplY3QpKSkpCmBgYAoKYGBge3IgRmlndXJlIDUsIGZpZy53aWR0aCA9IDh9CmZpZ3VyZV81X2xhdGVyYWwgPC0gcGxvdF9ncmlkKHBsb3Rfc2hpZnRfbGF0ZXJhbCwgcGxvdF9zaWdfbGF0ZXJhbCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksIHJlbF93aWR0aHMgPSBjKDEuMzMsMSkpICMgdG9wIHJvdwpmaWd1cmVfNV9jZW50ZXIgPC0gcGxvdF9ncmlkKHBsb3Rfc2hpZnRfY2VudGVyLHBsb3Rfc2lnX2NlbnRlciArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksIHJlbF93aWR0aHMgPSBjKDEuMzMsMSkpICMgYm90dG9tIHJvdwoKI3RpdGxlIG9iamVjdHMKdGl0bGVfbGF0ZXJhbCA8LSBnZ2RyYXcoKSArIGRyYXdfbGFiZWwoIkxhdGVyYWwgc2FjY2FkZXMiLCBmb250ZmFjZSA9ICdib2xkJywgc2l6ZSA9IGJhc2VfZm9udF9zaXplKQp0aXRsZV9jZW50ZXIgPC0gZ2dkcmF3KCkgKyBkcmF3X2xhYmVsKCJDZW50ZXIgc2FjY2FkZXMiLCBmb250ZmFjZSA9ICdib2xkJywgc2l6ZSA9IGJhc2VfZm9udF9zaXplKQoKI2NvbWJpbmUgd2l0aCB0aXRsZXMKZmlndXJlXzVfbGF0ZXJhbCA8LSBwbG90X2dyaWQodGl0bGVfbGF0ZXJhbCwgZmlndXJlXzVfbGF0ZXJhbCwgbmNvbCA9IDEsIHJlbF9oZWlnaHRzID0gYygwLjA1LCAxKSkKZmlndXJlXzVfY2VudGVyIDwtIHBsb3RfZ3JpZCh0aXRsZV9jZW50ZXIsIGZpZ3VyZV81X2NlbnRlciwgbmNvbCA9IDEsIHJlbF9oZWlnaHRzID0gYygwLjA1LCAxKSkKZmlndXJlXzUgPC0gcGxvdF9ncmlkKGZpZ3VyZV81X2xhdGVyYWwsIGZpZ3VyZV81X2NlbnRlciwgbnJvdyA9IDIpCmZpZ3VyZV81CmBgYAoKU2F2ZSB0aGUgcGxvdDoKCmBgYHtyIFNhdmUgZmlndXJlIDUsIGV2YWw9RkFMU0V9Cmdnc2F2ZSgiZmlnL2ZpZ3VyZV81LnBkZiIsIHBsb3QgPSBmaWd1cmVfNSwgd2lkdGggPSAxODAsIGhlaWdodCA9IDE4MCwgdW5pdHMgPSAibW0iKQpnZ3NhdmUoImZpZy9maWd1cmVfNS5wbmciLCBwbG90ID0gZmlndXJlXzUsIHdpZHRoID0gMTgwLCBoZWlnaHQgPSAxODAgLCB1bml0cyA9ICJtbSIpCmBgYAoKIyBTdXBwbGVtZW50YXJ5IHJlc3VsdHMKCiMjIHREQ1MgYWR2ZXJzZSBlZmZlY3QgcXVlc3Rpb25uYWlyZQoKX1NlZSB0aGUgYHF1ZXN0aW9ubmFpcmVzLm5iLmh0bWxgIG5vdGVib29rIGZvciBtb3JlIGV4cGxhbmF0aW9uIGFuZCBleHBsb3JhdGlvbiBvZiB0aGUgcXVlc3Rpb25uYWlyZSBkYXRhXwoKYGBge3IgTG9hZCB0RENTIHNlbnNhdGlvbnMgZGF0YX0KIyBMb2FkIHRoZSBkYXRhIGZyYW1lCmRhdGFGaWxlIDwtIGhlcmUoImRhdGEiLCAidGRjc19zZW5zYXRpb25zLmNzdiIpCnNlbnNEYXRhIDwtIHJlYWRfY3N2MihkYXRhRmlsZSwgY29sX3R5cGVzID0gY29scygKICBzZXNzaW9uID0gY29sX2ZhY3RvcihjKCJmaXJzdCIsInNlY29uZCIpKSwKICBzdGltdWxhdGlvbiA9IGNvbF9mYWN0b3IoYygiYW5vZGFsIiwiY2F0aG9kYWwiKSkKKSkKa2FibGUoaGVhZChzZW5zRGF0YSkpICMgc2hvdyBkYXRhIGZyYW1lCmBgYAoKUGFydGljaXBhbnRzIHdlcmUgYXNrZWQgdG8gd2hpY2ggZGVncmVlIHRoZSBmb2xsb3dpbmcgc2Vuc2F0aW9ucyB3ZXJlIHByZXNlbnQgZHVyaW5nIHN0aW11bGF0aW9uOiBfdGluZ2xpbmdfLCBfaXRjaGluZyBzZW5zYXRpb25fLCBfYnVybmluZyBzZW5zYXRpb25fLCBfcGFpbl8sIF9oZWFkYWNoZV8sIF9mYXRpZ3VlXywgX2RpenppbmVzc18gYW5kIF9uYXVzZWFfLiBFYWNoIHdhcyByYXRlZCBvbiBhIHNjYWxlIGZyb20gMC00OgoKMC4gbm9uZQoxLiBhIGxpdHRsZQoyLiBtb2RlcmF0ZQozLiBzdHJvbmcKNC4gdmVyeSBzdHJvbmcKClRoZXkgYWxzbyByYXRlZCB0aGVpciBjb25maWRlbmNlIF90aGF0IHRoZSBzZW5zYXRpb25zIHdlcmUgY2F1c2VkIGJ5IHRoZSBzdGltdWxhdGlvbl8gb24gYSBzY2FsZSBmcm9tIDAtNCAoY29sdW1ucyBzdGFydGluZyB3aXRoIGBjb25mLmApOgoKMC4gbi9hIChtZWFuaW5nIHRoZXkgcmF0ZWQgdGhlIHNlbnNhdGlvbiBhIDAgb24gdGhlIHByZXZpb3VzIHNjYWxlKQoxLiB1bmxpa2VseQoyLiBwb3NzaWJseQozLiBsaWtlbHkKNC4gdmVyeSBsaWtlbHkKCl9fRmFjdG9yc19fOgoKKiBfc3ViamVjdF86IHN1YmplY3QgSUQgKGBTMDFgLCBgUzAyYCwgZXRjKQoqIF9zZXNzaW9uXzogV2hldGhlciBkYXRhIGFyZSBmcm9tIHRoZSBgZmlyc3RgIG9yIGBzZWNvbmRgIHNlc3Npb24KKiBfc3RpbXVsYXRpb25fOiBXaGV0aGVyIGRhdGEgYXJlIGZyb20gdGhlIGBhbm9kYWxgIG9yIGBjYXRob2RhbGAgc2Vzc2lvbgoKQ2FsY3VsYXRlIGhvdyBtYW55IGFub2RhbCBhbmQgY2F0aG9kYWwgc2Vzc2lvbnMgd2VyZSByYXRlZDoKCmBgYHtyIFRhbGx5IGNhc2VzfQppZHhDb21wbGV0ZSA8LSByb3dTdW1zKGlzLm5hKHNlbnNEYXRhKSkgIT0gbmNvbChzZW5zRGF0YSkgLSAzICMgcm93cyB0aGF0IGRvIG5vdCBoYXZlIGFsbCBOQXMgKGV4Y2VwdCB0aGUgMyBmYWN0b3IgY29sdW1ucykKIyBjYWxjdWxhdGUgbnVtYmVyIG9mIHF1ZXN0aW9ubmFpcmVzIGNvbXBsZXRlZCBwZXIgc3RpbXVsYXRpb24gdHlwZQpuQW5vZGFsIDwtIHN1bShzZW5zRGF0YSRzdGltdWxhdGlvbiA9PSAiYW5vZGFsIiAmIGlkeENvbXBsZXRlKSAKbkNhdGhvZGFsIDwtIHN1bShzZW5zRGF0YSRzdGltdWxhdGlvbiA9PSAiY2F0aG9kYWwiICYgaWR4Q29tcGxldGUpCmBgYAoKIyMjIEZpZ3VyZSBTMQoKUHJlcGFyZSB0aGUgc2Vuc2F0aW9uIGludGVuc2l0eSBhbmQgY29uZmlkZW5jZSByYXRpbmdzLgoKYGBge3IgTWFrZSBsb25nIGZvcm0gZGF0YSBmcmFtZX0KIyBNYWtlIGxvbmcgZm9ybSBkYXRhIGZyYW1lIG9mIHNlbnNhdGlvbiBpbnRlbnNpdHkKcmF0aW5ncyA8LSBzZW5zRGF0YSAlPiUKICBzZWxlY3QoZXZlcnl0aGluZygpLCAtY29udGFpbnMoImNvbmYiKSwgLWZlbHQubW9yZSkgJT4lICMgZHJvcCBvdGhlciBjb2x1bW5zCiAgZ2F0aGVyKHNlbnNhdGlvbiwgcmF0aW5nLCBpdGNoaW5nOm5hdXNlYSkgIyBtYWtlIGxvbmcgZm9ybQoKIyBNYWtlIGxvbmcgZm9ybSBkYXRhIGZyYW1lIG9mIHNlbnNhdGlvbiBjb25maWRlbmNlCmNvbmZpZGVuY2UgPC0gc2Vuc0RhdGEgJT4lCiAgc2VsZWN0KGNvbnRhaW5zKCJjb25mIiksIHN1YmplY3QsIHNlc3Npb24sIHN0aW11bGF0aW9uKSAlPiUgCiAgZ2F0aGVyKHNlbnNhdGlvbiwgY29uZmlkZW5jZSwgY29uZi5pdGNoaW5nOmNvbmYubmF1c2VhKSAlPiUKICBtdXRhdGUoc2Vuc2F0aW9uID0gc3RyX3JlcGxhY2Uoc2Vuc2F0aW9uLCAiY29uZi4iLCAiIikpICMgZ2V0IHJpZCBvZiAiY29uZi4iIHByZWZpeCBzbyBpdCBtYXRjaGVzIHRoZSBzZW5zYXRpb24gaW50ZW5zaXR5IHRpYmJsZQoKIyBKb2luIHRoZSB0d28gZGF0YSBmcmFtZXMKc2Vuc0RhdGFMb25nIDwtIGRwbHlyOjpmdWxsX2pvaW4ocmF0aW5ncyxjb25maWRlbmNlKQpgYGAKCk1ha2UgcGxvdCBvZiBzZW5zYXRpb24gZGlzdHJpYnV0aW9uOgoKYGBge3IgcGxvdCB0RENTIHNlbnNhdGlvbiBkaXN0cmlidXRpb25zfQpwbG90X3NlbnNhdGlvbiA8LSBnZ3Bsb3Qoc2Vuc0RhdGFMb25nLCBhZXMocmF0aW5nLCBmaWxsID0gc3RpbXVsYXRpb24pKSArCiAgICBmYWNldF93cmFwKH5zZW5zYXRpb24sIG5yb3cgPSAxKSArCiAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIpICsKICAgIHN0YXRfYmluKGJpbndpZHRoID0gMSwgZ2VvbSA9ICJ0ZXh0Iiwgc2l6ZSA9IG1tX3RvX3B0LCBhZXMobGFiZWwgPSAuLmNvdW50Li4pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0YyNUY1QyIsICIjNEI5M0IxIikpICsKICAgIHhsaW0oMC41LDQuNSkgKyAjIGV4Y2x1ZGUgIjAiIHJhdGluZ3MgdGhhdCB3ZXJlIG5vdCBwcmVzZW50CiAgICB5bGltKDAsMzUpICsgIyBib3VuZCBwbG90IGF0IG1heCBudW1iZXIgb2YgcmF0aW5ncwogICAgeWxhYigibnVtYmVyIG9mIHNlc3Npb25zIikgKwogIGdndGl0bGUoIlNlbnNhdGlvbiBpbnRlbnNpdHkiKQpgYGAKCk1ha2UgcGxvdCBvZiBjb25maWRlbmNlIGRpc3RyaWJ1dGlvbjoKCmBgYHtyIHBsb3QgdERDUyBjb25maWRlbmNlIGRpc3RyaWJ1dGlvbnN9CnBsb3RfY29uZmlkZW5jZSA8LSBnZ3Bsb3Qoc2Vuc0RhdGFMb25nLCBhZXMoY29uZmlkZW5jZSwgZmlsbCA9IHN0aW11bGF0aW9uKSkgKwogICAgZmFjZXRfd3JhcCh+c2Vuc2F0aW9uLCBucm93ID0gMSkgKwogICAgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siKSArCiAgICBzdGF0X2JpbihiaW53aWR0aCA9IDEsIGdlb20gPSAidGV4dCIsIHNpemUgPSBtbV90b19wdCwgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGMjVGNUMiLCAiIzRCOTNCMSIpKSArCiAgICB4bGltKDAuNSw0LjUpICsKICAgIHlsaW0oMCwzNSkgKwogICAgeGxhYigicmF0aW5ncyIpICsKICAgIHlsYWIoIm51bWJlciBvZiBzZXNzaW9ucyIpICsKICAgIGdndGl0bGUoIkNvbmZpZGVuY2UiKQpgYGAKClB1dCB0b2dldGhlciBhbmQgc2hvdyBwbG90OgoKYGBge3IgdERDUyBBRSBwbG90LCBmaWcuaGVpZ2h0ID0gNX0gCmxlZ2VuZF9TMSA8LSBnZXRfbGVnZW5kKHBsb3Rfc2Vuc2F0aW9uKQpmaWd1cmVfUzEgPC0gcGxvdF9ncmlkKAogIHBsb3Rfc2Vuc2F0aW9uICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSwKICBwbG90X2NvbmZpZGVuY2UgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLAogIG5yb3cgPSAyKQpmaWd1cmVfUzEgPC0gcGxvdF9ncmlkKGZpZ3VyZV9TMSxsZWdlbmRfUzEsIHJlbF93aWR0aHMgPSBjKDEsMS8xMCkpCmZpZ3VyZV9TMQpgYGAKClNhdmUgdGhlIHBsb3Q6CgpgYGB7ciBTYXZlIGZpZ3VyZSBTMSwgZXZhbD1GQUxTRX0KZ2dzYXZlKCJmaWcvZmlndXJlX1MxLnBkZiIsIHBsb3QgPSBmaWd1cmVfUzEsIHdpZHRoID0gMTgwLCBoZWlnaHQgPSAxMTIuNSwgdW5pdHMgPSAibW0iKQpnZ3NhdmUoImZpZy9maWd1cmVfUzEucG5nIiwgcGxvdCA9IGZpZ3VyZV9TMSwgd2lkdGggPSAxODAsIGhlaWdodCA9IDExMi41LCB1bml0cyA9ICJtbSIpCmBgYAoKIyMjIFN0YXRpc3RpY3MKCk1hbm4tV2hpdG5leSBVIHRlc3RzIGZvciBkaWZmZXJlbmNlIGluIHNlbnNhdGlvbiBpbnRlbnNpdHkgcmF0aW5ncyBiZXR3ZWVuIGFub2RhbCBhbmQgY2F0aG9kYWwgc2Vzc2lvbnMuCgpgYGB7ciBUZXN0IHNlbnNhdGlvbnMgYW5vZGFsIHZzLiBjYXRob2RhbCwgcmVzdWx0cz0nYXNpcyd9CnNlbnNhdGlvbkxpc3QgPC0gYygiaXRjaGluZyIsICJ0aW5nbGluZyIsICJidXJuaW5nIiwgInBhaW4iLCAiaGVhZGFjaGUiLCAiZmF0aWd1ZSIsICJkaXp6aW5lc3MiLCAibmF1c2VhIikKc2Vuc2VUZXN0cyA8LSBkYXRhLmZyYW1lKHNlbnNhdGlvbiA9IHNlbnNhdGlvbkxpc3QsIHAudmFsdWUgPSBOQSkgIyBpbml0aWFsaXplIHJlc3VsdHMgZGF0YSBmcmFtZQpmb3IgKGl0ZW0gaW4gc2Vuc2F0aW9uTGlzdCkgewogIHRlc3REYXRhIDwtIHNlbnNEYXRhW1tpdGVtXV0gIyBleHRyYWN0IGNvbHVtbiB3aXRoIHRlc3QgZGF0CiAgdG1wIDwtIHdpbGNveC50ZXN0KHRlc3REYXRhW3NlbnNEYXRhJHN0aW11bGF0aW9uID09ICJhbm9kYWwiXSwgdGVzdERhdGFbc2Vuc0RhdGEkc3RpbXVsYXRpb24gPT0gImNhdGhvZGFsIl0pCiAgc2Vuc2VUZXN0cyRwLnZhbHVlW3NlbnNlVGVzdHMkc2Vuc2F0aW9uICVpbiUgaXRlbV0gPC0gdG1wJHAudmFsdWUgIyBwdXQgcC12YWx1ZSBpbiByb3cgb2YgcmVzdWx0cyBkYXRhIGZyYW1lCn0Ka2FibGUoc2Vuc2VUZXN0cykKYGBgCgpOb3RlIHRoYXQgdGhlIHAtdmFsdWUgZm9yICJuYXVzZWEiIGlzIHVuZGVmaW5lZCBiZWNhdXNlIGl0IHdhcyBuZXZlciByZXBvcnRlZCAoaS5lLiBhbGwgcmFua3MgYXJlIHRpZWQgYXQgMCkuCgojIyBGcm9udGFsIGV5ZSBmaWVsZCBjb29yZGluYXRlcwoKX1NlZSB0aGUgYGZyb250YWxfZXllX2ZpZWxkLm5iLmh0bWxgIG5vdGVib29rIGZvciBtb3JlIGV4cGxhbmF0aW9uIGFuZCBleHBsb3JhdGlvbiBvZiB0aGUgZnJvbnRhbCBleWUgZmllbGQgY29vcmRpbmF0ZSBkYXRhXwoKIyMjIE5hdGl2ZSBzcGFjZQoKVGhlc2Ugd2VyZSBkZXRlcm1pbmVkIGZvciBlYWNoIHN1YmplY3QncyBzY2FuOyBzZWUgYG5ldXJvbmF2X25vdGVzLm1kYCBmb3IgZnVydGhlciBpbmZvLgoKYGBge3IgU2hvdyBuYXRpdmUgY29vcmRzLCByZXN1bHRzPSdhc2lzJ30KZGF0YUZpbGUgPC0gaGVyZSgiZGF0YSIsICJGRUZfY29vcmRzX25hdGl2ZS5jc3YiKQpuYXRpdmVDb29yZHMgPC0gcmVhZF9jc3YyKGRhdGFGaWxlKQpuYXRpdmVDb29yZHMgJT4lIAogIHNlbGVjdCgtZm9sZGVyLCAtc2NhbikgJT4lICMgZHJvcCBjb2x1bW5zIHdpdGggZm9sZGVyIGFuZCBzY2FuIG5hbWVzCiAgZmlsdGVyKCEoc3ViamVjdCAlaW4lIHN1YnMyZXhjbHVkZSkpICU+JSAjIGRyb3Agcm93cyB3aXRoIGV4Y2x1ZGVkIHN1YmplY3RzCiAga2FibGUoLikKYGBgCgojIyMgTU5JIHNwYWNlIChUYWJsZSBTMSkKCkxvYWQgaW4gdGhlIGNvb3JkaW5hdGVzIHRoYXQgd2VyZSB0cmFuc2Zvcm1lZCB0byBNTkkgc3BhY2UuCgojIyMjIFRhYmxlIFMxCgpgYGB7ciBzaG93IE1OSSBjb29yZHMsIHJlc3VsdHM9J2FzaXMnfQpkYXRhRmlsZSA8LSBoZXJlKCJkYXRhIiwgIkZFRl9jb29yZHNfTU5JLmNzdiIpCm1uaUNvb3JkcyA8LSByZWFkX2RlbGltKGRhdGFGaWxlLCAiOyIpCm1uaUNvb3JkcyA8LSBmaWx0ZXIobW5pQ29vcmRzLCAhKHN1YmplY3QgJWluJSBzdWJzMmV4Y2x1ZGUpKSAjIGV4Y2x1ZGUgc3ViamVjdHMKbW5pQ29vcmRzICU+JQogIHNlbGVjdCgtZm9sZGVyLCAtc2NhbikgJT4lICMgZHJvcCBjb2x1bW5zIHdpdGggZm9sZGVyIGFuZCBzY2FuIG5hbWVzCiAga2FibGUoLikKYGBgCgojIyMjIERlc2NyaXB0aXZlcwoKQ2FsY3VsYXRlIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3Mgb3ZlciBzdWJqZWN0czoKCmBgYHtyIERlc2NyaXB0aXZlcyBvZiBNTkkgY29vcmRpbmF0ZXMsIHJlc3VsdHM9J2FzaXMnfQptbmlDb29yZHMgJT4lCiAgZ2F0aGVyKGRpbWVuc2lvbiwgY29vcmQsIE1OSV9YOk1OSV9aKSAlPiUKICBncm91cF9ieShkaW1lbnNpb24pICU+JQogIHN1bW1hcmlzZV9hdCh2YXJzKGNvb3JkKSwgZnVucyhtZWFuLCBtaW4sIG1heCwgc2QpKSAlPiUgCiAga2FibGUoLikKYGBgCg==