R notebook for inspection of data and analyses of saccade end point deviation and variability in the sacc-tDCS
dataset. Previous processing:
- Raw data were parsed into events (saccades, fixations, etc.) by the EyeLink data were collected on.
- Events were extracted and saccade measures were computed with a MATLAB script.
# Load some libraries
library(here) # file paths
here() starts at /Volumes/psychology$/Researchers/reteig/sacc-tDCS
library(tidyverse) # importing, transforming, and visualizing data frames
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages ---------------------------------------------------------------------------------
filter(): dplyr, stats
lag(): dplyr, stats
library(forcats) # manipulatin factors
library(ez) # ANOVA
library(BayesFactor) # Bayesian statistics
Loading required package: coda
Loading required package: Matrix
Attaching package: 'Matrix'
The following object is masked from 'package:tidyr':
expand
************
Welcome to BayesFactor 0.9.12-2. If you have questions, please contact Richard Morey (richarddmorey@gmail.com).
Type BFManual() to open the manual.
************
library(broom) # transform model output into a data frame
library(knitr) # R markdown output (html, pdf, etc.)
# set default output and figure options
knitr::opts_chunk$set(message = FALSE, warning = FALSE, fig.width = 7, fig.asp = 0.618, out.width = "75%", fig.align = "center")
source(here("src", "lib", "InclusionBF.R"))
sessionInfo()
R version 3.4.0 (2017-04-21)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: OS X El Capitan 10.11.6
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.4/Resources/lib/libRlapack.dylib
locale:
[1] C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] knitr_1.15.1 broom_0.4.2 BayesFactor_0.9.12-2 Matrix_1.2-9 coda_0.19-1
[6] ez_4.4-0 forcats_0.2.0 dplyr_0.5.0 purrr_0.2.2 readr_1.1.0
[11] tidyr_0.6.1 tibble_1.3.0 ggplot2_2.2.1 tidyverse_1.1.1 here_0.1
loaded via a namespace (and not attached):
[1] gtools_3.5.0 pbapply_1.3-2 reshape2_1.4.2 splines_3.4.0 haven_1.0.0
[6] lattice_0.20-35 colorspace_1.3-2 mgcv_1.8-17 nloptr_1.0.4 foreign_0.8-67
[11] DBI_0.6-1 modelr_0.1.0 readxl_1.0.0 plyr_1.8.4 stringr_1.2.0
[16] MatrixModels_0.4-1 munsell_0.4.3 gtable_0.2.0 cellranger_1.1.0 rvest_0.3.2
[21] mvtnorm_1.0-6 psych_1.7.3.21 SparseM_1.77 quantreg_5.33 pbkrtest_0.4-7
[26] parallel_3.4.0 Rcpp_0.12.10 scales_0.4.1 backports_1.0.5 jsonlite_1.4
[31] lme4_1.1-13 mnormt_1.5-5 hms_0.3 stringi_1.1.5 grid_3.4.0
[36] rprojroot_1.2 tools_3.4.0 magrittr_1.5 lazyeval_0.2.0 car_2.1-4
[41] MASS_7.3-47 xml2_1.1.1 lubridate_1.6.0 assertthat_0.2.0 minqa_1.2.4
[46] httr_1.2.1 R6_2.2.0 nnet_7.3-12 nlme_3.1-131 compiler_3.4.0
Load data
Load eye data
The .csv file with the eye tracking data was created in MATLAB.
# Load the data frame
dataFile <- here("data", "sacc-tDCS_data.csv")
groupData <- read_csv(dataFile, col_names = TRUE, na = "NaN", progress = FALSE, col_types = cols(
stimulation = col_factor(c("anodal","cathodal")),
leg = col_factor(c("pre","tDCS","post")),
type = col_factor(c("lateral","center")),
direction = col_factor(c("left","right"))
))
S01 |
anodal |
pre |
1 |
1 |
lateral |
right |
0.462897 |
0.170455 |
-0.0080638 |
8.02463 |
433 |
0.0953736 |
0.102814 |
S01 |
anodal |
pre |
1 |
1 |
center |
left |
0.459092 |
1.032850 |
0.0665268 |
7.16262 |
439 |
0.0953736 |
0.102814 |
S01 |
anodal |
pre |
1 |
2 |
lateral |
right |
0.344561 |
-0.344967 |
0.2197400 |
7.74873 |
291 |
0.0953736 |
0.102814 |
S01 |
anodal |
pre |
1 |
2 |
center |
left |
0.550230 |
0.361201 |
0.3507760 |
7.43233 |
198 |
0.0953736 |
0.102814 |
S01 |
anodal |
pre |
1 |
3 |
lateral |
right |
0.514736 |
-0.588470 |
0.1673250 |
7.61080 |
281 |
0.0953736 |
0.102814 |
S01 |
anodal |
pre |
1 |
3 |
center |
left |
0.620728 |
1.576610 |
0.4031910 |
6.35043 |
376 |
0.0953736 |
0.102814 |
- 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
Preprocess data
Outliers
tooFast <- 50
tooSlow <- 400
badFix <- 1.8
badSacc <- 8
subs2exclude <- c("S28","S16","S22","S21","S25")
- S21 and S25 were tested < 48h apart
- S16, S22 and S28 had fewer than 50 saccades per condition after trial rejection
Criteria for outlier saccades:
- Discard fast saccades, with a latency of 50 ms or less
- Discard slow saccades, saccades with a latency of 400 ms or more
- Discard inaccurate fixations, with saccade starting point more than 1.8 degrees or more away from fixation
- Discard faulty saccades, with x-coordinate of saccade end point 8 degree or more away from the target
In Kanai et al. (2012), this was:
- Fast saccades: 50 ms
- Slow saccades: 400 ms
- Bad fixations: 1.8 degrees
- Faulty saccades: opposite hemifield of target (here, that would be 8 degrees as targets were that eccentric)
# Remove outliers and subjects
groupData <- filter(groupData,
# outliers
latency >= tooFast,
latency <= tooSlow,
deviation.start <= badFix,
deviation.end.x <= badSacc,
# subjects
!(subject %in% subs2exclude),
# missing values
complete.cases(groupData)
)
Cut into 15-minute sections
Cut the post-block into two so we have four 15-minute intervals: one before, one during, and two after stimulation.
# Split the "post" leg into two
groupData <- mutate(groupData,
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
)
Saccade end point deviation
One estimate of the accuracy of saccades is the mean landing position with respect to the target location. Kanai et al. (2012) also examined this, but found no effects of tDCS.
The simplest measure (which Kanai et al. (2012) also used) is the Euclidian distance (shortest straight line) between the saccade end point and the center of the target stimulus. We already have the deviations in the x- and y- directions in degrees of visual angle. Now we just need to calculate the length of the vector.
# Calculate end point deviation
devData <- mutate(groupData, deviation.end = sqrt(deviation.end.x^2 + deviation.end.y^2))
Prepare data frame for plotting & statistics
Average over three blocks:
devData <- devData %>%
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
Subtract the baseline from each average:
# Subtract baseline
devDataBase <- devData %>%
group_by(subject,stimulation,direction,type) %>%
# subtract baseline block from others, make new column
summarise(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, tDCS, post.1, post.2) %>% # gather new columns to use as factor
mutate(leg = factor(leg, levels = c("tDCS", "post.1", "post.2"))) # reorder factor levels
Plot
With baseline block
kanaiPlotDev <- ggplot(devData, aes(leg, deviation.end, color = stimulation, shape = stimulation)) +
facet_grid(type ~ direction) +
stat_summary(fun.y = mean, geom = "point", size = 3) +
stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3)
kanaiPlotDev
At first glance there don’t seem to be many differences that are larger than the baseline differences and/or relate clearly to the polarity or timing of stimulation.
Let’s look at the individual subject data:
kanaiPlotSubsAnodal <- ggplot(devData[devData$stimulation == "anodal", ], aes(leg, deviation.end)) +
facet_grid(type ~ direction) +
geom_line(aes(group = subject,color = subject)) +
stat_summary(fun.y = mean, aes(group = stimulation), geom = "line") +
stat_summary(fun.y = mean, geom = "point") +
ggtitle("Anodal session")
kanaiPlotSubsAnodal
kanaiPlotSubsCathodal <- ggplot(devData[devData$stimulation == "cathodal", ], aes(leg, deviation.end)) +
facet_grid(type ~ direction) +
geom_line(aes(group = subject,color = subject)) +
stat_summary(fun.y = mean, aes(group = stimulation), geom = "line") +
stat_summary(fun.y = mean, geom = "point") +
ggtitle("Cathodal session")
kanaiPlotSubsCathodal
There are definitely some outliers, but mostly in terms of overall offset / baseline differences.
Baseline reliability
Scatterplot and correlation of baseline data in the two sessions:
baselineCorrDev <- devData %>%
filter(leg == "baseline") %>%
group_by(direction,type) %>%
spread(stimulation,deviation.end) %>%
nest() %>%
mutate(stats = map(data, ~cor.test(formula = ~ anodal + cathodal, data =.))) %>% # run correlation test on baselines from each condition
mutate(tidy_model = map(stats, tidy)) %>%
unnest(tidy_model, .drop = TRUE)
devData %>%
filter(leg == "baseline") %>%
spread(stimulation,deviation.end) %>%
inner_join(., subjectData[ ,c("subject","session.order")], by = c("subject")) %>% # add column on session order from other data frame
ggplot(aes(anodal,cathodal)) +
facet_grid(type ~ direction) +
geom_abline(intercept = 0, slope = 1, linetype = "dashed") +
geom_smooth(method = "lm") +
geom_point(aes(color=session.order)) +
xlim(0,2) + ylim(0,2) +
geom_text(data = baselineCorrDev, x = 0.2, y = 1.5, aes(label = paste("italic(r) == ", round(estimate,2))), parse = TRUE) +
labs(title = "Baseline in anodal and cathodal sessions", subtitle = "scatterplot of baseline endpoint deviation")
The correlations are not as high as for the latency data, but still reasonable. The sequence effect we observed in the latency data is not so prominent, so apparently there’s less of a practice effect in saccade enpdoint deviation.
Baseline differences
devData %>%
filter(leg == "baseline") %>%
inner_join(., subjectData[ ,c("subject","session.order")], by = c("subject")) %>% # add column on session order from other data frame
group_by(subject,direction,type,session.order) %>%
summarise(deviation.end.diff = deviation.end[stimulation == "anodal"] - deviation.end[stimulation == "cathodal"]) %>%
ggplot(aes(factor(0), deviation.end.diff)) +
facet_grid(type ~ direction) +
geom_hline(yintercept = 0, linetype = "dashed") +
stat_summary(fun.data = mean_cl_normal) +
stat_summary(fun.y = mean, aes(label=round(..y.., digits=2), x = 1.3), geom = "label", alpha = 0.5) +
geom_point(shape = 21, aes(colour = session.order), position = position_jitter(width=.1)) +
labs(title = "Baseline in anodal and cathodal sessions", subtitle = "anodal - cathodal")
The baseline differences are not so extreme, except for the center (left) condition: that seems quite large and consistent over subjects.
devData %>%
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(.)
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 |
Indeed, in the center-left condition the baseline difference is significant, and it’s at trend in the center-right condition.
For the center conditions, let’s look at the raw data from Time Periods after the baseline block, to see if there are also differnences between anodal and cathodal there:
devData %>%
filter(leg != "baseline", type == "center") %>%
group_by(stimulation,direction,leg) %>%
summarise(mean = mean(deviation.end)) %>%
kable(.)
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 |
Baseline subtracted
kanaiPlotDevBase <- ggplot(devDataBase, aes(leg, deviation.end, color = stimulation, shape = stimulation)) +
facet_grid(type ~ direction) +
geom_hline(yintercept = 0, linetype = "dashed") +
stat_summary(fun.y = mean, geom = "point", size = 3) +
stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3)
kanaiPlotDevBase
This clearly shows that all the changes are quite tiny (less than 0.15 degrees of visual angle). There appears to be a clear difference in between the anodal and cathodal change scores for center saccades (and maybe for left-lateral saccades).
However, we know that the difference between anodal and cathodal is actually maximal in the baseline. Thus it remains unclear whether the baseline differences are spurious and the effect is real, or whether the “effect” is driven by the baseline difference (i.e. something akin to regression to the mean).
Statistics
# Make "subject" a factor, so we can model the repeated measures
devDataBase <- devDataBase %>%
ungroup() %>% # remove any grouping info, because we need to refactor
inner_join(., subjectData[ ,c("subject","session.order")], by = c("subject")) %>% # add column on session order from other data frame
mutate(subject = factor(subject)) # refactor
Frequentist
ANOVA matching Kanai et al. (2012) - lateral saccades
Without session order
Data:
- Outliers removed
- Collapsed into 15-minute intervals
- Subtract the baseline from each subsequent block
- Discard center, keep only lateral saccades
Dependent measure: saccade end point deviation
Factors:
- STIMULATION (anodal vs. cathodal)
- LEG (tDCS, post.1, post.2)
- DIRECTION (left vs. right)
modelKanai <- ezANOVA(data = data.frame(filter(devDataBase, type == "lateral")),
dv = .(deviation.end), wid = .(subject), within = .(stimulation,leg,direction), type = 3)
kable(modelKanai$ANOVA)
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(modelKanai$`Mauchly's Test for Sphericity`)
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(modelKanai$`Sphericity Corrections`)
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 |
|
With session order
Add an additional factor SESSION ORDER, which creates two groups: those subjects who received anodal tDCS in the first session vs. those who received cathodal tDCS in the first session. Note that these groups are not exactly balanced, which might affect (correcting for) violations of sphericity:
devDataBase %>%
group_by(session.order) %>%
summarize(count = n_distinct(subject)) %>%
kable(.)
first.anodal |
14 |
first.cathodal |
12 |
modelKanaiOrder <- ezANOVA(data = data.frame(filter(devDataBase, type == "lateral")), dv = .(deviation.end),
wid = .(subject), within = .(stimulation,leg,direction), between = session.order, type = 3)
kable(modelKanaiOrder$ANOVA)
2 |
session.order |
1 |
24 |
0.2049021 |
0.6548582 |
|
0.0033510 |
3 |
stimulation |
1 |
24 |
2.2664083 |
0.1452548 |
|
0.0204847 |
5 |
leg |
2 |
48 |
0.8688109 |
0.4259409 |
|
0.0022474 |
7 |
direction |
1 |
24 |
1.5405279 |
0.2265344 |
|
0.0062015 |
4 |
session.order:stimulation |
1 |
24 |
1.1398125 |
0.2963138 |
|
0.0104081 |
6 |
session.order:leg |
2 |
48 |
0.1072400 |
0.8985246 |
|
0.0002780 |
8 |
session.order:direction |
1 |
24 |
0.0363616 |
0.8503745 |
|
0.0001473 |
9 |
stimulation:leg |
2 |
48 |
0.6189985 |
0.5427260 |
|
0.0016790 |
11 |
stimulation:direction |
1 |
24 |
0.2640686 |
0.6120378 |
|
0.0010552 |
13 |
leg:direction |
2 |
48 |
0.0746248 |
0.9281991 |
|
0.0001222 |
10 |
session.order:stimulation:leg |
2 |
48 |
0.3828206 |
0.6839985 |
|
0.0010391 |
12 |
session.order:stimulation:direction |
1 |
24 |
3.3325860 |
0.0803899 |
|
0.0131556 |
14 |
session.order:leg:direction |
2 |
48 |
1.9582493 |
0.1522160 |
|
0.0031959 |
15 |
stimulation:leg:direction |
2 |
48 |
0.2604897 |
0.7717565 |
|
0.0002689 |
16 |
session.order:stimulation:leg:direction |
2 |
48 |
0.5209071 |
0.5973007 |
|
0.0005376 |
kable(modelKanaiOrder$`Mauchly's Test for Sphericity`)
5 |
leg |
0.6837007 |
0.0126171 |
* |
6 |
session.order:leg |
0.6837007 |
0.0126171 |
* |
9 |
stimulation:leg |
0.9937065 |
0.9299690 |
|
10 |
session.order:stimulation:leg |
0.9937065 |
0.9299690 |
|
13 |
leg:direction |
0.9622853 |
0.6426792 |
|
14 |
session.order:leg:direction |
0.9622853 |
0.6426792 |
|
15 |
stimulation:leg:direction |
0.7507047 |
0.0369739 |
* |
16 |
session.order:stimulation:leg:direction |
0.7507047 |
0.0369739 |
* |
kable(modelKanaiOrder$`Sphericity Corrections`)
5 |
leg |
0.7597056 |
0.4008100 |
|
0.8003634 |
0.4056562 |
|
6 |
session.order:leg |
0.7597056 |
0.8449885 |
|
0.8003634 |
0.8559635 |
|
9 |
stimulation:leg |
0.9937459 |
0.5417737 |
|
1.0831863 |
0.5427260 |
|
10 |
session.order:stimulation:leg |
0.9937459 |
0.6827125 |
|
1.0831863 |
0.6839985 |
|
13 |
leg:direction |
0.9636560 |
0.9226131 |
|
1.0461526 |
0.9281991 |
|
14 |
session.order:leg:direction |
0.9636560 |
0.1540577 |
|
1.0461526 |
0.1522160 |
|
15 |
stimulation:leg:direction |
0.8004512 |
0.7225967 |
|
0.8487521 |
0.7357368 |
|
16 |
session.order:stimulation:leg:direction |
0.8004512 |
0.5582804 |
|
0.8487521 |
0.5685106 |
|
ANOVA matching Kanai et al. (2012) - center saccades
Without session order
Repeat the same ANOVA, but now discard the lateral and keep only center saccades (which Kanai did not have).
modelKanaiCenter <- ezANOVA(data = data.frame(filter(devDataBase, type == "center")),
dv = .(deviation.end), wid = .(subject), within = .(stimulation,leg,direction), type = 3)
kable(modelKanaiCenter$ANOVA)
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(modelKanaiCenter$`Mauchly's Test for Sphericity`)
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(modelKanaiCenter$`Sphericity Corrections`)
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 |
|
Main effect of stimulation
devDataBase %>%
filter(type == "center") %>%
group_by(subject,stimulation) %>%
summarise(deviation.end = mean(deviation.end)) %>%
ggplot(aes(stimulation, deviation.end)) +
geom_hline(yintercept = 0, linetype = "dashed") +
stat_summary(fun.data = mean_cl_normal, size = 1) +
geom_jitter(width = 0.25)
The accuracy in the cathodal session improves from baseline for most subjects; anodal stays the same or slightly worsens.
Let’s do some follow-up tests to see whether the anodal or cathodal change scores are significantly different from 0 on their own.
Frequentist one-sample t-tests:
devDataBase %>%
filter(type == "center") %>% # keep only center saccades
group_by(stimulation,subject) %>% # for each session and subject
summarise(deviation.end = mean(deviation.end)) %>% # 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(.)
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 |
The cathodal effect is highly signifcant, but the anodal is not.
Interaction: Leg by direction
devDataBase %>%
filter(type == "center") %>%
group_by(subject,leg,direction) %>%
summarise(deviation.end = mean(deviation.end)) %>%
ggplot(aes(leg, deviation.end, shape = direction)) +
geom_hline(yintercept = 0, linetype = "dashed") +
stat_summary(fun.y = mean, geom = "point") +
stat_summary(fun.y = mean, geom = "line", aes(group = direction, linetype = direction))
The accuracy of leftward saccades is improved for left saccades in the final half hour of task performance, more so than for right saccades, for which the accuracy goes back to baseline eventually.
With session order
modelKanaiCenterOrder <- ezANOVA(data = data.frame(filter(devDataBase, type == "center")), dv = .(deviation.end),
wid = .(subject), within = .(stimulation,leg,direction), between = session.order, type = 3)
kable(modelKanaiCenterOrder$ANOVA)
2 |
session.order |
1 |
24 |
0.9091324 |
0.3498501 |
|
0.0093825 |
3 |
stimulation |
1 |
24 |
11.2906179 |
0.0025998 |
* |
0.0769854 |
5 |
leg |
2 |
48 |
2.6985313 |
0.0775127 |
|
0.0074970 |
7 |
direction |
1 |
24 |
0.3758142 |
0.5456181 |
|
0.0039524 |
4 |
session.order:stimulation |
1 |
24 |
1.7960865 |
0.1927370 |
|
0.0130944 |
6 |
session.order:leg |
2 |
48 |
1.3375601 |
0.2720914 |
|
0.0037301 |
8 |
session.order:direction |
1 |
24 |
0.1079995 |
0.7452836 |
|
0.0011390 |
9 |
stimulation:leg |
2 |
48 |
0.6721289 |
0.5153601 |
|
0.0014931 |
11 |
stimulation:direction |
1 |
24 |
3.6456189 |
0.0682423 |
|
0.0155529 |
13 |
leg:direction |
2 |
48 |
3.6359248 |
0.0338605 |
* |
0.0072533 |
10 |
session.order:stimulation:leg |
2 |
48 |
1.0528744 |
0.3568522 |
|
0.0023369 |
12 |
session.order:stimulation:direction |
1 |
24 |
3.8042220 |
0.0628957 |
|
0.0162185 |
14 |
session.order:leg:direction |
2 |
48 |
0.0826374 |
0.9208157 |
|
0.0001660 |
15 |
stimulation:leg:direction |
2 |
48 |
0.4549433 |
0.6371915 |
|
0.0008799 |
16 |
session.order:stimulation:leg:direction |
2 |
48 |
1.7824344 |
0.1791825 |
|
0.0034386 |
kable(modelKanaiCenterOrder$`Mauchly's Test for Sphericity`)
5 |
leg |
0.8326608 |
0.1217259 |
|
6 |
session.order:leg |
0.8326608 |
0.1217259 |
|
9 |
stimulation:leg |
0.9647617 |
0.6619581 |
|
10 |
session.order:stimulation:leg |
0.9647617 |
0.6619581 |
|
13 |
leg:direction |
0.6671987 |
0.0095265 |
* |
14 |
session.order:leg:direction |
0.6671987 |
0.0095265 |
* |
15 |
stimulation:leg:direction |
0.8547089 |
0.1644030 |
|
16 |
session.order:stimulation:leg:direction |
0.8547089 |
0.1644030 |
|
kable(modelKanaiCenterOrder$`Sphericity Corrections`)
5 |
leg |
0.8566490 |
0.0868332 |
|
0.9160721 |
0.0828527 |
|
6 |
session.order:leg |
0.8566490 |
0.2711195 |
|
0.9160721 |
0.2716862 |
|
9 |
stimulation:leg |
0.9659611 |
0.5105755 |
|
1.0489826 |
0.5153601 |
|
10 |
session.order:stimulation:leg |
0.9659611 |
0.3551055 |
|
1.0489826 |
0.3568522 |
|
13 |
leg:direction |
0.7502994 |
0.0482991 |
* |
0.7892425 |
0.0456985 |
* |
14 |
session.order:leg:direction |
0.7502994 |
0.8692654 |
|
0.7892425 |
0.8793191 |
|
15 |
stimulation:leg:direction |
0.8731405 |
0.6112836 |
|
0.9359565 |
0.6245419 |
|
16 |
session.order:stimulation:leg:direction |
0.8731405 |
0.1842757 |
|
0.9359565 |
0.1817943 |
|
There are some significant effects, but they do not interact with session order.
Bayesian
See the median_latency.html
notebook for more explanation of the Bayesian analyses
Linear mixed effects matching Kanai - lateral saccades
Bayesian analogue of the frequentist repeated measures ANOVA (without order effect), with the same factors.
bfKanaiLateral = anovaBF(deviation.end~stimulation*leg*direction+subject, data = data.frame(filter(devDataBase, type == "lateral")), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiLateral = sort(bfKanaiLateral, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfKanaiLateral), bf)) # show only the Bayes factors in a table
stimulation + subject |
6.3043541 |
stimulation + direction + subject |
2.8707275 |
stimulation + direction + stimulation:direction + subject |
0.5717448 |
direction + subject |
0.4352645 |
stimulation + leg + subject |
0.3421660 |
stimulation + direction + leg + subject |
0.1554643 |
leg + subject |
0.0536364 |
stimulation + leg + stimulation:leg + subject |
0.0313865 |
stimulation + direction + stimulation:direction + leg + subject |
0.0302085 |
direction + leg + subject |
0.0234973 |
stimulation + direction + leg + stimulation:leg + subject |
0.0131340 |
stimulation + direction + leg + direction:leg + subject |
0.0102116 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject |
0.0027655 |
stimulation + direction + stimulation:direction + leg + direction:leg + subject |
0.0020724 |
direction + leg + direction:leg + subject |
0.0015411 |
stimulation + direction + leg + stimulation:leg + direction:leg + subject |
0.0008682 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject |
0.0001767 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject |
0.0000193 |
Two models fare better than the null model: (1) a main effect of stimulation, and (2) a main effect of both stimulation and direction.
kable(inclusionBF(bfKanaiLateral, models = "matched"))
stimulation |
6.3958467 |
direction |
0.4524436 |
stimulation:direction |
0.1989794 |
leg |
0.0541019 |
stimulation:leg |
0.0894815 |
direction:leg |
0.0660689 |
stimulation:direction:leg |
0.1093623 |
There is moderate evidence for inclusion of an effect of stimulation, even though the classical analysis does not reach significance.
Linear mixed effects matching Kanai - center saccades
bfKanaiCenter = anovaBF(deviation.end~stimulation*leg*direction+subject, data = data.frame(filter(devDataBase, type == "center")), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiCenter = sort(bfKanaiCenter, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfKanaiCenter), bf)) # show only the Bayes factors in a table
stimulation + subject |
4.106478e+04 |
stimulation + direction + stimulation:direction + subject |
1.664631e+04 |
stimulation + direction + subject |
1.045629e+04 |
stimulation + leg + subject |
5.157159e+03 |
stimulation + direction + stimulation:direction + leg + subject |
1.762110e+03 |
stimulation + direction + leg + subject |
1.064665e+03 |
stimulation + direction + stimulation:direction + leg + direction:leg + subject |
3.519904e+02 |
stimulation + leg + stimulation:leg + subject |
3.292616e+02 |
stimulation + direction + leg + direction:leg + subject |
2.137328e+02 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject |
1.390985e+02 |
stimulation + direction + leg + stimulation:leg + subject |
8.424768e+01 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject |
2.655452e+01 |
stimulation + direction + leg + stimulation:leg + direction:leg + subject |
1.620066e+01 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject |
3.465907e+00 |
direction + subject |
2.656401e-01 |
leg + subject |
9.395870e-02 |
direction + leg + subject |
2.257760e-02 |
direction + leg + direction:leg + subject |
4.296100e-03 |
All the models with a main effect of stimulation are strongly supported.
kable(inclusionBF(bfKanaiCenter, models = "matched"))
stimulation |
4.180150e+04 |
direction |
2.493000e-01 |
stimulation:direction |
1.599142e+00 |
leg |
1.171220e-01 |
stimulation:leg |
6.963590e-02 |
direction:leg |
1.994931e-01 |
stimulation:direction:leg |
1.305204e-01 |
Overwhelming evidence for inclusion of a main effect of stimulation, which is in accord with the highly significant p-value.
Bayesian one-sample t-tests:
devDataBase %>%
filter(type == "center") %>% # keep only center saccades
group_by(stimulation,subject) %>% # for each session and subject
summarise(deviation.end = mean(deviation.end)) %>% # average over all other variables
spread(stimulation,deviation.end) %>% # make separate columns with test data
summarise_if(is.numeric, funs(extractBF(ttestBF(.), onlybf = TRUE))) %>% # run Bayesian t-test on each column, keeping only the BF
gather(stimulation,BF,anodal,cathodal) %>% # make row for each stimulation condition
kable(.)
anodal |
0.3173718 |
cathodal |
10.5264920 |
The cathodal effect on its ownhas a BF10 > 10, but the anodal effect does not.
Saccade end point variability
In the motor literature, people often look at the spread in movement endpoints, as it’s often believed that this is what the motor system is trying to optimize (i.e. minimize). Kanai et al. (2012) also examined this, but found no effects of tDCS.
Calculate endpoint variability
Kanai et al. (2012) operationalized variability as the standard deviation of the x-coordinate of the saccade end point.
stdData <- groupData %>%
group_by(subject,stimulation,leg,direction,type) %>%
summarise(std.deviation.x = sd(deviation.end.x))
This is a summary measure across trials, so we have one estimate per subject per condition:
S01 |
anodal |
pre |
left |
lateral |
0.6287700 |
S01 |
anodal |
pre |
left |
center |
0.6782264 |
S01 |
anodal |
pre |
right |
lateral |
0.5883124 |
S01 |
anodal |
pre |
right |
center |
0.4780784 |
S01 |
anodal |
tDCS |
left |
lateral |
0.5671711 |
S01 |
anodal |
tDCS |
left |
center |
0.6352989 |
Prepare data frame for plotting & statistics
stdData$leg <- fct_recode(stdData$leg, baseline = "pre") # recode factor to match deviation data frame
Subtract the baseline from each average:
# Subtract baseline
stdDataBase <- stdData %>%
group_by(subject,stimulation,direction,type) %>%
# subtract baseline block from others, make new column
summarise(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, tDCS, post.1, post.2) %>% # gather new columns to use as factor
mutate(leg = factor(leg, levels = c("tDCS", "post.1", "post.2"))) # reorder factor levels
Plot
With baseline block
kanaiPlotStd <- ggplot(stdData, aes(leg, std.deviation.x, color = stimulation, shape = stimulation)) +
facet_grid(type ~ direction) +
stat_summary(fun.y = mean, geom = "point", size = 3) +
stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3) +
ggtitle("Horizontal standard deviation")
kanaiPlotStd
The changes here seem less pronounced than in the endpoint deviation data.
Let’s look at the individual subject data:
kanaiPlotSubsAnodal <- ggplot(stdData[stdData$stimulation == "anodal", ], aes(leg, std.deviation.x)) +
facet_grid(type ~ direction) +
geom_line(aes(group = subject,color = subject)) +
stat_summary(fun.y = mean, aes(group = stimulation), geom = "line") +
stat_summary(fun.y = mean, geom = "point") +
ggtitle("Anodal session")
kanaiPlotSubsAnodal
kanaiPlotSubsCathodal <- ggplot(stdData[stdData$stimulation == "cathodal", ], aes(leg, std.deviation.x)) +
facet_grid(type ~ direction) +
geom_line(aes(group = subject,color = subject)) +
stat_summary(fun.y = mean, aes(group = stimulation), geom = "line") +
stat_summary(fun.y = mean, geom = "point") +
ggtitle("Cathodal session")
kanaiPlotSubsCathodal
This measure seems particularly variable across subjects and also subject to quite a few spikes that only show up in a few conditions.
Baseline reliability
Scatterplot and correlation of baseline data in the two sessions:
baselineCorrStd <- stdData %>%
filter(leg == "baseline") %>%
group_by(direction,type) %>%
spread(stimulation,std.deviation.x) %>%
nest() %>%
mutate(stats = map(data, ~cor.test(formula = ~ anodal + cathodal, data =.))) %>% # run correlation test on baselines from each condition
mutate(tidy_model = map(stats, tidy)) %>%
unnest(tidy_model, .drop = TRUE)
stdData %>%
filter(leg == "baseline") %>%
spread(stimulation,std.deviation.x) %>%
inner_join(., subjectData[ ,c("subject","session.order")], by = c("subject")) %>% # add column on session order from other data frame
ggplot(aes(anodal,cathodal)) +
facet_grid(type ~ direction) +
geom_abline(intercept = 0, slope = 1, linetype = "dashed") +
geom_smooth(method = "lm") +
geom_point(aes(color=session.order)) +
xlim(0.2,1.6) + ylim(0.2,1.6) +
geom_text(data = baselineCorrStd, x = 0.5, y = 1.5, aes(label = paste("italic(r) == ", round(estimate,2))), parse = TRUE) +
labs(title = "Baseline in anodal and cathodal sessions", subtitle = "scatterplot of baseline endpoint variability")
The correlations for this measure are quite low, especially for the center conditions. Apparently the standard deviation of saccade endpoints is not so reliable.
Baseline differences
stdData %>%
filter(leg == "baseline") %>%
inner_join(., subjectData[ ,c("subject","session.order")], by = c("subject")) %>% # add column on session order from other data frame
group_by(subject,direction,type,session.order) %>%
summarise(std.deviation.x.diff = std.deviation.x[stimulation == "anodal"] - std.deviation.x[stimulation == "cathodal"]) %>%
ggplot(aes(factor(0), std.deviation.x.diff)) +
facet_grid(type ~ direction) +
geom_hline(yintercept = 0, linetype = "dashed") +
stat_summary(fun.data = mean_cl_normal) +
stat_summary(fun.y = mean, aes(label=round(..y.., digits=2), x = 1.3), geom = "label", alpha = 0.5) +
geom_point(shape = 21, aes(colour = session.order), position = position_jitter(width=.1)) +
labs(title = "Baseline in anodal and cathodal sessions", subtitle = "anodal - cathodal")
The average baseline differences are small, but the spread is quite large.
stdData %>%
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(.)
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 |
On average none of the baselines differ significantly from each other.
Baseline subtracted
kanaiPlotStdBase <- ggplot(stdDataBase, aes(leg, std.deviation.x, color = stimulation, shape = stimulation)) +
facet_grid(type ~ direction) +
geom_hline(yintercept = 0, linetype = "dashed") +
stat_summary(fun.y = mean, geom = "point", size = 3) +
stat_summary(fun.y = mean, geom = "line", aes(group = stimulation), size = 1) +
stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.3)
kanaiPlotStdBase
Here the changes are even tinier than the endpoint deviation data (<.1 degree). If anything, the differences seem to grow more pronounced after tDCS.
Statistics
# Make "subject" a factor, so we can model the repeated measures
stdDataBase <- stdDataBase %>%
ungroup() %>% # remove any grouping info, because we need to refactor
inner_join(., subjectData[ ,c("subject","session.order")], by = c("subject")) %>% # add column on session order from other data frame
mutate(subject = factor(subject)) # refactor
Frequentist
ANOVA matching Kanai et al. (2012) - lateral saccades
Without session order
Data:
- Outliers removed
- Collapsed into 15-minute intervals
- Subtract the baseline from each subsequent block
- Discard center, keep only lateral saccades
Dependent measure: saccade end point variability (horizontal standard deviation)
Factors:
- STIMULATION (anodal vs. cathodal)
- LEG (tDCS, post.1, post.2)
- DIRECTION (left vs. right)
modelKanaiStd <- ezANOVA(data = data.frame(filter(stdDataBase, type == "lateral")),
dv = .(std.deviation.x), wid = .(subject), within = .(stimulation,leg,direction), type = 3)
kable(modelKanaiStd$ANOVA)
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(modelKanaiStd$`Mauchly's Test for Sphericity`)
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(modelKanaiStd$`Sphericity Corrections`)
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 |
|
With session order
modelKanaiStdOrder <- ezANOVA(data = data.frame(filter(stdDataBase, type == "lateral")), dv = .(std.deviation.x),
wid = .(subject), within = .(stimulation,leg,direction), between = session.order, type = 3)
kable(modelKanaiStdOrder$ANOVA)
2 |
session.order |
1 |
24 |
0.1607364 |
0.6920265 |
|
0.0017906 |
3 |
stimulation |
1 |
24 |
1.1906769 |
0.2860271 |
|
0.0143992 |
5 |
leg |
2 |
48 |
0.4813409 |
0.6209047 |
|
0.0013051 |
7 |
direction |
1 |
24 |
0.2831863 |
0.5995127 |
|
0.0012899 |
4 |
session.order:stimulation |
1 |
24 |
0.0246391 |
0.8765826 |
|
0.0003022 |
6 |
session.order:leg |
2 |
48 |
0.2627471 |
0.7700350 |
|
0.0007128 |
8 |
session.order:direction |
1 |
24 |
0.3163115 |
0.5790487 |
|
0.0014406 |
9 |
stimulation:leg |
2 |
48 |
1.1029347 |
0.3401590 |
|
0.0032123 |
11 |
stimulation:direction |
1 |
24 |
0.2860170 |
0.5977048 |
|
0.0010464 |
13 |
leg:direction |
2 |
48 |
0.8050343 |
0.4530163 |
|
0.0020275 |
10 |
session.order:stimulation:leg |
2 |
48 |
0.0483124 |
0.9528823 |
|
0.0001411 |
12 |
session.order:stimulation:direction |
1 |
24 |
4.5903060 |
0.0425038 |
* |
0.0165327 |
14 |
session.order:leg:direction |
2 |
48 |
1.2562264 |
0.2939184 |
|
0.0031603 |
15 |
stimulation:leg:direction |
2 |
48 |
0.2086854 |
0.8123830 |
|
0.0003866 |
16 |
session.order:stimulation:leg:direction |
2 |
48 |
0.1838631 |
0.8326329 |
|
0.0003406 |
kable(modelKanaiStdOrder$`Mauchly's Test for Sphericity`)
5 |
leg |
0.9929565 |
0.9219294 |
|
6 |
session.order:leg |
0.9929565 |
0.9219294 |
|
9 |
stimulation:leg |
0.9948738 |
0.9426101 |
|
10 |
session.order:stimulation:leg |
0.9948738 |
0.9426101 |
|
13 |
leg:direction |
0.8816782 |
0.2349990 |
|
14 |
session.order:leg:direction |
0.8816782 |
0.2349990 |
|
15 |
stimulation:leg:direction |
0.9042201 |
0.3141614 |
|
16 |
session.order:stimulation:leg:direction |
0.9042201 |
0.3141614 |
|
kable(modelKanaiStdOrder$`Sphericity Corrections`)
5 |
leg |
0.9930058 |
0.6196034 |
|
1.0822730 |
0.6209047 |
|
6 |
session.order:leg |
0.9930058 |
0.7685199 |
|
1.0822730 |
0.7700350 |
|
9 |
stimulation:leg |
0.9949000 |
0.3399524 |
|
1.0846107 |
0.3401590 |
|
10 |
session.order:stimulation:leg |
0.9949000 |
0.9522849 |
|
1.0846107 |
0.9528823 |
|
13 |
leg:direction |
0.8941970 |
0.4412480 |
|
0.9614309 |
0.4488867 |
|
14 |
session.order:leg:direction |
0.8941970 |
0.2920372 |
|
0.9614309 |
0.2933216 |
|
15 |
stimulation:leg:direction |
0.9125920 |
0.7926861 |
|
0.9837647 |
0.8089070 |
|
16 |
session.order:stimulation:leg:direction |
0.9125920 |
0.8133016 |
|
0.9837647 |
0.8292325 |
|
The interaction with session order, stimulation, and direction is significant. However, the stimulation:direction interaction was not significant in the ANOVA without the session order factor, so we should interpret this with caution. In addition, an interaction of session order and stimulation could just as well reflect a main effect of session (1 vs. 2): there’s no way to distinguish between these possibilities.
ANOVA matching Kanai et al. (2012) - center saccades
Without session order
modelKanaiStdCenter <- ezANOVA(data = data.frame(filter(stdDataBase, type == "center")),
dv = .(std.deviation.x), wid = .(subject), within = .(stimulation,leg,direction), type = 3)
kable(modelKanaiStdCenter$ANOVA)
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(modelKanaiStdCenter$`Mauchly's Test for Sphericity`)
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(modelKanaiStdCenter$`Sphericity Corrections`)
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 |
|
Main effect of stimulation
This effect is just non-significant, but let’s inspect anyway:
stdDataBase %>%
filter(type == "center") %>%
group_by(subject,stimulation) %>%
summarise(std.deviation.x = mean(std.deviation.x)) %>%
ggplot(aes(stimulation, std.deviation.x)) +
geom_hline(yintercept = 0, linetype = "dashed") +
stat_summary(fun.data = mean_cl_normal, size = 1) +
geom_jitter(width = 0.25)
This resembles the difference found for the saccade endpoint deviation, except here the larger and more consistent effect seems to be in the anodal condition.
With session order
modelKanaiStdCenterOrder <- ezANOVA(data = data.frame(filter(stdDataBase, type == "center")), dv = .(std.deviation.x),
wid = .(subject), within = .(stimulation,leg,direction), between = session.order, type = 3)
kable(modelKanaiStdCenterOrder$ANOVA)
2 |
session.order |
1 |
24 |
0.1624780 |
0.6904536 |
|
0.0015282 |
3 |
stimulation |
1 |
24 |
4.3268347 |
0.0483642 |
* |
0.0451874 |
5 |
leg |
2 |
48 |
2.8313514 |
0.0688095 |
|
0.0084055 |
7 |
direction |
1 |
24 |
0.8197631 |
0.3742496 |
|
0.0045103 |
4 |
session.order:stimulation |
1 |
24 |
1.5157716 |
0.2301895 |
|
0.0163088 |
6 |
session.order:leg |
2 |
48 |
0.6228833 |
0.5406747 |
|
0.0018614 |
8 |
session.order:direction |
1 |
24 |
2.1829361 |
0.1525517 |
|
0.0119209 |
9 |
stimulation:leg |
2 |
48 |
1.1504478 |
0.3250667 |
|
0.0038706 |
11 |
stimulation:direction |
1 |
24 |
0.2458431 |
0.6245275 |
|
0.0014926 |
13 |
leg:direction |
2 |
48 |
2.1991247 |
0.1219515 |
|
0.0036576 |
10 |
session.order:stimulation:leg |
2 |
48 |
0.0383245 |
0.9624300 |
|
0.0001294 |
12 |
session.order:stimulation:direction |
1 |
24 |
1.0500393 |
0.3157162 |
|
0.0063444 |
14 |
session.order:leg:direction |
2 |
48 |
1.5933477 |
0.2138058 |
|
0.0026527 |
15 |
stimulation:leg:direction |
2 |
48 |
0.4598347 |
0.6341403 |
|
0.0007630 |
16 |
session.order:stimulation:leg:direction |
2 |
48 |
0.7980825 |
0.4560741 |
|
0.0013235 |
kable(modelKanaiStdCenterOrder$`Mauchly's Test for Sphericity`)
5 |
leg |
0.8967279 |
0.2854944 |
|
6 |
session.order:leg |
0.8967279 |
0.2854944 |
|
9 |
stimulation:leg |
0.8553298 |
0.1657816 |
|
10 |
session.order:stimulation:leg |
0.8553298 |
0.1657816 |
|
13 |
leg:direction |
0.6851706 |
0.0129326 |
* |
14 |
session.order:leg:direction |
0.6851706 |
0.0129326 |
* |
15 |
stimulation:leg:direction |
0.7903814 |
0.0668532 |
|
16 |
session.order:stimulation:leg:direction |
0.7903814 |
0.0668532 |
|
kable(modelKanaiStdCenterOrder$`Sphericity Corrections`)
5 |
leg |
0.9063947 |
0.0747228 |
|
0.9762321 |
0.0702670 |
|
6 |
session.order:leg |
0.9063947 |
0.5258855 |
|
0.9762321 |
0.5370486 |
|
9 |
stimulation:leg |
0.8736141 |
0.3204306 |
|
0.9365284 |
0.3229043 |
|
10 |
session.order:stimulation:leg |
0.8736141 |
0.9470365 |
|
0.9365284 |
0.9553929 |
|
13 |
leg:direction |
0.7605549 |
0.1363083 |
|
0.8013684 |
0.1338319 |
|
14 |
session.order:leg:direction |
0.7605549 |
0.2189988 |
|
0.8013684 |
0.2183303 |
|
15 |
stimulation:leg:direction |
0.8267068 |
0.5980305 |
|
0.8801197 |
0.6098886 |
|
16 |
session.order:stimulation:leg:direction |
0.8267068 |
0.4356829 |
|
0.8801197 |
0.4424174 |
|
Here the effect does just reach significance, but there’s no interaction with session order.
Bayesian
Bayesian analogues of the frequentist repeated measures ANOVAs (without order effect), with the same factors.
Linear mixed effects matching Kanai - lateral saccades
bfKanaiStd = anovaBF(std.deviation.x~stimulation*leg*direction+subject, data = data.frame(filter(stdDataBase, type == "lateral")), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiStd = sort(bfKanaiStd, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfKanaiStd), bf)) # show only the Bayes factors in a table
stimulation + subject |
1.6067684 |
stimulation + direction + subject |
0.2527311 |
direction + subject |
0.1587882 |
stimulation + leg + subject |
0.0692546 |
stimulation + direction + stimulation:direction + subject |
0.0466324 |
leg + subject |
0.0423764 |
stimulation + direction + leg + subject |
0.0101754 |
stimulation + leg + stimulation:leg + subject |
0.0076393 |
direction + leg + subject |
0.0062815 |
stimulation + direction + stimulation:direction + leg + subject |
0.0018978 |
stimulation + direction + leg + stimulation:leg + subject |
0.0011028 |
stimulation + direction + leg + direction:leg + subject |
0.0009792 |
direction + leg + direction:leg + subject |
0.0005836 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject |
0.0002038 |
stimulation + direction + stimulation:direction + leg + direction:leg + subject |
0.0001863 |
stimulation + direction + leg + stimulation:leg + direction:leg + subject |
0.0001032 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject |
0.0000195 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject |
0.0000022 |
# Inclusion Bayes Factors
kable(inclusionBF(bfKanaiStd, models = "matched"))
stimulation |
1.6058451 |
direction |
0.1574002 |
stimulation:direction |
0.1846148 |
leg |
0.0424108 |
stimulation:leg |
0.1099317 |
direction:leg |
0.0952033 |
stimulation:direction:leg |
0.1138337 |
Across the board, there is only marginal support for an effect of stimulation. For the interaction between stimulation and direction, the BF approaches moderate evidence for the null.
Linear mixed effects matching Kanai - center saccades
bfKanaiStdCenter = anovaBF(std.deviation.x~stimulation*leg*direction+subject, data = data.frame(filter(stdDataBase, type == "center")), whichModels = "withmain", whichRandom = "subject", progress = FALSE, iterations = 100000) # compute Bayes Factors
bfKanaiStdCenter = sort(bfKanaiStdCenter, decreasing = TRUE) # sort such that winning model is at the top
kable(select(extractBF(bfKanaiStdCenter), bf)) # show only the Bayes factors in a table
stimulation + subject |
140.9689987 |
stimulation + direction + subject |
31.6047660 |
stimulation + leg + subject |
17.4338557 |
stimulation + direction + stimulation:direction + subject |
6.6985274 |
stimulation + direction + leg + subject |
3.9139000 |
stimulation + leg + stimulation:leg + subject |
1.9223398 |
stimulation + direction + stimulation:direction + leg + subject |
0.7738986 |
stimulation + direction + leg + stimulation:leg + subject |
0.4278358 |
stimulation + direction + leg + direction:leg + subject |
0.4136443 |
direction + subject |
0.2145949 |
leg + subject |
0.1167207 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + subject |
0.0892661 |
stimulation + direction + stimulation:direction + leg + direction:leg + subject |
0.0876314 |
stimulation + direction + leg + stimulation:leg + direction:leg + subject |
0.0527296 |
direction + leg + subject |
0.0244040 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + subject |
0.0100162 |
direction + leg + direction:leg + subject |
0.0026828 |
stimulation + direction + stimulation:direction + leg + stimulation:leg + direction:leg + stimulation:direction:leg + subject |
0.0011645 |
Like for the saccade endpoint deviation data, models with stimulation as a factor receive some support, although to a less strong degree. In contrast to endpoint deviation though, here the classical analysis was (barely) non-significant, so there is a discrepancy between the Bayesian and Frequentist approaches.
# Inclusion Bayes Factors
kable(inclusionBF(bfKanaiStdCenter, models = "matched"))
stimulation |
143.0615573 |
direction |
0.2241394 |
stimulation:direction |
0.2103470 |
leg |
0.1233485 |
stimulation:leg |
0.1106040 |
direction:leg |
0.1083709 |
stimulation:direction:leg |
0.1162597 |
Again, especially considering the non-significant p-value, the support is quite strong.
Let’s do some follow-up tests to see whether the anodal or cathodal change scores are significantly different from 0 on their own.
Bayesian one-sample t-tests:
stdDataBase %>%
filter(type == "center") %>% # keep only center saccades
group_by(stimulation,subject) %>% # for each session and subject
summarise(deviation.end = mean(std.deviation.x)) %>% # average over all other variables
spread(stimulation,deviation.end) %>% # make separate columns with test data
summarise_if(is.numeric, funs(extractBF(ttestBF(.), onlybf = TRUE))) %>% # run Bayesian t-test on each column, keeping only the BF
gather(stimulation,BF,anodal,cathodal) %>% # make row for each stimulation condition
kable(.)
anodal |
0.7138830 |
cathodal |
0.4103342 |
Frequentist one-sample t-tests:
stdDataBase %>%
filter(type == "center") %>% # keep only center saccades
group_by(stimulation,subject) %>% # for each session and subject
summarise(deviation.end = mean(std.deviation.x)) %>% # 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(.)
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 |
So neither effect holds up on their own.
LS0tCnRpdGxlOiAic2FjYy10RENTOiBTYWNjYWRlIGFjY3VyYWN5IgphdXRob3I6ICJMZW9uIFJldGVpZyIKc3VidGl0bGU6Cm91dHB1dDoKICBnaXRodWJfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwogIGh0bWxfbm90ZWJvb2s6CiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KClIgbm90ZWJvb2sgZm9yIGluc3BlY3Rpb24gb2YgZGF0YSBhbmQgYW5hbHlzZXMgb2Ygc2FjY2FkZSBlbmQgcG9pbnQgZGV2aWF0aW9uIGFuZCB2YXJpYWJpbGl0eSBpbiB0aGUgYHNhY2MtdERDU2AgZGF0YXNldC4gUHJldmlvdXMgcHJvY2Vzc2luZzoKCiogUmF3IGRhdGEgd2VyZSBwYXJzZWQgaW50byBldmVudHMgKHNhY2NhZGVzLCBmaXhhdGlvbnMsIGV0Yy4pIGJ5IHRoZSBFeWVMaW5rIGRhdGEgd2VyZSBjb2xsZWN0ZWQgb24uCiogRXZlbnRzIHdlcmUgZXh0cmFjdGVkIGFuZCBzYWNjYWRlIG1lYXN1cmVzIHdlcmUgY29tcHV0ZWQgd2l0aCBhIE1BVExBQiBzY3JpcHQuCgpgYGB7ciBzZXR1cH0KIyBMb2FkIHNvbWUgbGlicmFyaWVzCmxpYnJhcnkoaGVyZSkgIyBmaWxlIHBhdGhzCmxpYnJhcnkodGlkeXZlcnNlKSAjIGltcG9ydGluZywgdHJhbnNmb3JtaW5nLCBhbmQgdmlzdWFsaXppbmcgZGF0YSBmcmFtZXMKbGlicmFyeShmb3JjYXRzKSAjIG1hbmlwdWxhdGluIGZhY3RvcnMKbGlicmFyeShleikgIyBBTk9WQQpsaWJyYXJ5KEJheWVzRmFjdG9yKSAjIEJheWVzaWFuIHN0YXRpc3RpY3MKbGlicmFyeShicm9vbSkgIyB0cmFuc2Zvcm0gbW9kZWwgb3V0cHV0IGludG8gYSBkYXRhIGZyYW1lCmxpYnJhcnkoa25pdHIpICMgUiBtYXJrZG93biBvdXRwdXQgKGh0bWwsIHBkZiwgZXRjLikKIyBzZXQgZGVmYXVsdCBvdXRwdXQgYW5kIGZpZ3VyZSBvcHRpb25zCmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLndpZHRoID0gNywgZmlnLmFzcCA9IDAuNjE4LCBvdXQud2lkdGggPSAiNzUlIiwgZmlnLmFsaWduID0gImNlbnRlciIpCgpzb3VyY2UoaGVyZSgic3JjIiwgImxpYiIsICJJbmNsdXNpb25CRi5SIikpCgpzZXNzaW9uSW5mbygpCmBgYAoKIyBMb2FkIGRhdGEKCiMjIExvYWQgZXllIGRhdGEKClRoZSAuY3N2IGZpbGUgd2l0aCB0aGUgZXllIHRyYWNraW5nIGRhdGEgd2FzIGNyZWF0ZWQgaW4gTUFUTEFCLgoKYGBge3IgTG9hZCB0aGUgZGF0YSBmcmFtZX0KIyBMb2FkIHRoZSBkYXRhIGZyYW1lCmRhdGFGaWxlIDwtIGhlcmUoImRhdGEiLCAic2FjYy10RENTX2RhdGEuY3N2IikKZ3JvdXBEYXRhIDwtIHJlYWRfY3N2KGRhdGFGaWxlLCBjb2xfbmFtZXMgPSBUUlVFLCBuYSA9ICJOYU4iLCBwcm9ncmVzcyA9IEZBTFNFLCBjb2xfdHlwZXMgPSBjb2xzKAogIHN0aW11bGF0aW9uID0gY29sX2ZhY3RvcihjKCJhbm9kYWwiLCJjYXRob2RhbCIpKSwKICBsZWcgPSBjb2xfZmFjdG9yKGMoInByZSIsInREQ1MiLCJwb3N0IikpLAogIHR5cGUgPSBjb2xfZmFjdG9yKGMoImxhdGVyYWwiLCJjZW50ZXIiKSksCiAgZGlyZWN0aW9uID0gY29sX2ZhY3RvcihjKCJsZWZ0IiwicmlnaHQiKSkgCikpCmBgYAoKYGBge3IgU2hvdyBkYXRhIGZyYW1lLCByZXN1bHRzID0gJ2FzaXMnfQprYWJsZShoZWFkKGdyb3VwRGF0YSkpCmBgYAoKKiBfX3N1YmplY3RfXzogc3ViamVjdCBJRAoqIF9fc3RpbXVsYXRpb25fXzogV2hldGhlciBkYXRhIGFyZSBmcm9tIHRoZSBgYW5vZGFsYCBvciBgY2F0aG9kYWxgIHNlc3Npb24KKiBfX2xlZ19fOiBXaGV0aGVyIGRhdGEgYXJlIGJlZm9yZSAoYHByZWApLCBkdXJpbmcgKGB0RENTYCksIG9yIGFmdGVyIChgcG9zdGApIHREQ1MKKiBfX2Jsb2NrX186IEFmdGVyIGVhY2ggYmxvY2sgcGFydGljaXBhbnQgaGFkIGEgYnJpZWYgYnJlYWsgYW5kIHRyYWNrZXIgd2FzIHJlY2FsaWJyYXRlZAoqIF9fdHJpYWxfXzogdHJpYWwgbnVtYmVyIHdpdGhpbiBhIGJsb2NrCiogX190eXBlX186CiAgICAqIGBsYXRlcmFsYCAtIGZpeGF0aW9uIGluIGNlbnRlciBvZiBkaXNwbGF5LCBzYWNjYWRlIG1hZGUgdG93YXJkcyB0aGUgcGVyaXBoZXJ5CiAgICAqIGBjZW50ZXJgIC0gZml4YXRpb24gaW4gcGVyaXBoZXJ5LCBzYWNjYWRlIG1hZGUgYmFjayB0b3dhcmRzIHRoZSBjZW50ZXIgb2YgdGhlIGRpc3BsYXkKKiBfX2RpcmVjdGlvbl9fOiBgbGVmdGAgZm9yIHNhY2NhZGVzIHRvd2FyZHMgdGhlIGxlZnQgb2YgY3VycmVudCBmaXhhdGlvbiBwb3NpdGlvbjsgYHJpZ2h0YCBmb3Igc2FjY2FkZXMgdG8gdGhlIHJpZ2h0CiogX19kZXZpYXRpb24uc3RhcnRfXyA6IGRpc3RhbmNlIChpbiB2aXN1YWwgYW5nbGUpIGZyb20gc2FjY2FkZSBzdGFydCBwb2ludCB0byBmaXhhdGlvbgoqIF9fZGV2aWF0aW9uLmVuZC54X186IGRpc3RhbmNlIChpbiB2aXN1YWwgYW5nbGUpIGZyb20geC1jb29yZGluYXRlIG9mIHNhY2NhZGUgZW5kIHBvaW50IHRvIHgtY29vcmRpbmF0ZSBvZiB0YXJnZXQgbG9jYXRpb24KKiBfX2RldmlhdGlvbi5lbmQueV9fOiBzYW1lIGZvciB5LWNvb3JkaW5hdGUKKiBfX2FtcGxpdHVkZV9fOiBkaXN0YW5jZSAoaW4gdmlzdWFsIGFuZ2xlKSBiZXR3ZWVuIHNhY2NhZGUgc3RhcnQgYW5kIGVuZCBwb2ludAoqIF9fbGF0ZW5jeV9fOiB0aW1lIChpbiBtcykgZnJvbSB0YXJnZXQgb25zZXQgdG8gc3RhcnQgb2Ygc2FjY2FkZQoqIF9fZHJpZnQueF9fOiBkaXN0YW5jZSAoaW4gdmlzdWFsIGFuZ2xlKSBiZXR3ZWVuIHgtY29vcmRpbmF0ZSBvZiBhdmVyYWdlIGZpeGF0aW9uIHBvc2l0aW9uIGR1cmluZyB0aGUgYnJlYWsgdG8geC1jb29yZGluYXRlIG9mIGZpeGF0aW9uIHN0aW11bHVzLiBUaGlzIHN0aW11bHVzIHdhcyBkaXNwbGF5ZWQgYXQgZWFjaCBicmVhayBpbiB0aGUgdGFzaywgc28gdGhpcyBkYXRhIGNhbiBiZSB1c2VkIGFzIGFuIGVzdGltYXRlIG9mIG9mZnNldHMgdG8gZG8gZHJpZnQgY29ycmVjdGlvbi4KKiBfX2RyaWZ0LnlfXzogc2FtZSBmb3IgeS1jb29yZGluYXRlCgojIyBTdWJqZWN0IG1ldGFkYXRhCgpgYGB7ciBMb2FkIHN1YmplY3QgaW5mbyBkYXRhfQojIExvYWQgZXllIHRyYWNraW5nIGRhdGEgaW50byBkYXRhIGZyYW1lCmRhdGFGaWxlIDwtIGhlcmUoImRhdGEiLCAic3ViamVjdF9pbmZvLmNzdiIpCnN1YmplY3REYXRhIDwtIHJlYWRfY3N2MihkYXRhRmlsZSwgY29sX25hbWVzID0gVFJVRSwgcHJvZ3Jlc3MgPSBGQUxTRSwgY29sX3R5cGVzID0gY29scygKICBzZXNzaW9uLm9yZGVyID0gY29sX2ZhY3RvcihjKCJmaXJzdC5hbm9kYWwiLCAiZmlyc3QuY2F0aG9kYWwiKSkKKSkKYGBgCgpgYGB7ciBTaG93IHN1YmplY3QgaW5mbyBkYXRhIGZyYW1lLCByZXN1bHRzPSdhc2lzJ30Ka2FibGUoaGVhZChzdWJqZWN0RGF0YSkpCmBgYAoKKiBfX3N1YmplY3RfXzogc3ViamVjdCBJRAoqIF9fc2Vzc2lvbi5vcmRlcl9fOiBXaGV0aGVyIHN1YmplY3QgaGFkIGFub2RhbCBzdGltdWxhdGlvbiBpbiB0aGUgZmlyc3Qgc2Vzc2lvbiAoYGZpcnN0LmFub2RhbGApIG9yIGNhdGhvZGFsIHN0aW11bGF0aW9uIGluIHRoZSBmaXJzdCBzZXNzaW9uIChgZmlyc3QuY2F0aG9kYWxgKQoqIF9fZ2VuZGVyX18KKiBfX2FnZV9fOiBpbiB5ZWFycwoqIF9fZG9taW5hbnQuZXllX186IHJlc3VsdCBvZiBleWUgZG9taW5hbmNlIHRlc3QKClRoZSBtYWluIHVzZSBpcyB0byBzZWUgaWYgdGhlIG51aXNhbmNlIGZhY3RvciBfc2Vzc2lvbi5vcmRlcl8gY292YXJpZXMgd2l0aCB0aGUgZmFjdG9ycyBvZiBpbnRlcmVzdCBpbiB0aGUgZGVzaWduLiBUaGlzIGNvdWxkIGluZGljYXRlIHRoZSBwcmVzZW5jZSBvZiBjYXJyeW92ZXIgZWZmZWN0cyBiZXR3ZWVuIHRoZSBzdGltdWxhdGlvbiwgb3IgYSBkaWZmZXJlbmNlIGluIHN1Ymdyb3VwcyB3aXRoaW4gdGhlIHNhbXBsZSAoc2VlIDxodHRwOi8vd3d3LmplcnJ5ZGFsbGFsLmNvbS9saHNwL2Nyb3Nzb3ZyLmh0bT4gZm9yIGFuIGludHJvZHVjdGlvbiB0byB0aGVzZSBraW5kcyBvZiBhbmFseXNlcy4pLgoKIyBQcmVwcm9jZXNzIGRhdGEKCiMjIE91dGxpZXJzCgpgYGB7ciBPdXRsaWVyIGNyaXRlcmlhfQp0b29GYXN0IDwtIDUwCnRvb1Nsb3cgPC0gNDAwCmJhZEZpeCA8LSAxLjgKYmFkU2FjYyA8LSA4CnN1YnMyZXhjbHVkZSA8LSBjKCJTMjgiLCJTMTYiLCJTMjIiLCJTMjEiLCJTMjUiKQpgYGAKCiogUzIxIGFuZCBTMjUgd2VyZSB0ZXN0ZWQgPCA0OGggYXBhcnQKKiBTMTYsIFMyMiBhbmQgUzI4IGhhZCBmZXdlciB0aGFuIDUwIHNhY2NhZGVzIHBlciBjb25kaXRpb24gYWZ0ZXIgdHJpYWwgcmVqZWN0aW9uCgpDcml0ZXJpYSBmb3Igb3V0bGllciBzYWNjYWRlczoKCiogRGlzY2FyZCBmYXN0IHNhY2NhZGVzLCB3aXRoIGEgbGF0ZW5jeSBvZiBgciB0b29GYXN0YCBtcyBvciBsZXNzCiogRGlzY2FyZCBzbG93IHNhY2NhZGVzLCBzYWNjYWRlcyB3aXRoIGEgbGF0ZW5jeSBvZiBgciB0b29TbG93YCBtcyBvciBtb3JlCiogRGlzY2FyZCBpbmFjY3VyYXRlIGZpeGF0aW9ucywgd2l0aCBzYWNjYWRlIHN0YXJ0aW5nIHBvaW50IG1vcmUgdGhhbiBgciBiYWRGaXhgIGRlZ3JlZXMgb3IgbW9yZSBhd2F5IGZyb20gZml4YXRpb24KKiBEaXNjYXJkIGZhdWx0eSBzYWNjYWRlcywgd2l0aCB4LWNvb3JkaW5hdGUgb2Ygc2FjY2FkZSBlbmQgcG9pbnQgYHIgYmFkU2FjY2AgZGVncmVlIG9yIG1vcmUgYXdheSBmcm9tIHRoZSB0YXJnZXQKCkluIFtLYW5haSBldCBhbC4gKDIwMTIpXShodHRwOi8vZHguZG9pLm9yZy8xMC4zMzg5L2Zwc3l0LjIwMTIuMDAwNDUpLCB0aGlzIHdhczoKCiogRmFzdCBzYWNjYWRlczogNTAgbXMKKiBTbG93IHNhY2NhZGVzOiA0MDAgbXMKKiBCYWQgZml4YXRpb25zOiAxLjggZGVncmVlcwoqIEZhdWx0eSBzYWNjYWRlczogb3Bwb3NpdGUgaGVtaWZpZWxkIG9mIHRhcmdldCAoaGVyZSwgdGhhdCB3b3VsZCBiZSA4IGRlZ3JlZXMgYXMgdGFyZ2V0cyB3ZXJlIHRoYXQgZWNjZW50cmljKQoKYGBge3IgUmVtb3ZlIG91dGxpZXIgdHJpYWxzIGFuZCBzdWJqZWN0c30KIyBSZW1vdmUgb3V0bGllcnMgYW5kIHN1YmplY3RzCmdyb3VwRGF0YSA8LSBmaWx0ZXIoZ3JvdXBEYXRhLAogICAgICAgICAgICAgICAgICAgICMgb3V0bGllcnMKICAgICAgICAgICAgICAgICAgICBsYXRlbmN5ID49IHRvb0Zhc3QsCiAgICAgICAgICAgICAgICAgICAgbGF0ZW5jeSA8PSB0b29TbG93LAogICAgICAgICAgICAgICAgICAgIGRldmlhdGlvbi5zdGFydCA8PSBiYWRGaXgsCiAgICAgICAgICAgICAgICAgICAgZGV2aWF0aW9uLmVuZC54IDw9IGJhZFNhY2MsCiAgICAgICAgICAgICAgICAgICAgIyBzdWJqZWN0cwogICAgICAgICAgICAgICAgICAgICEoc3ViamVjdCAlaW4lIHN1YnMyZXhjbHVkZSksCiAgICAgICAgICAgICAgICAgICAgIyBtaXNzaW5nIHZhbHVlcwogICAgICAgICAgICAgICAgICAgIGNvbXBsZXRlLmNhc2VzKGdyb3VwRGF0YSkKKQpgYGAKCiMjIEN1dCBpbnRvIDE1LW1pbnV0ZSBzZWN0aW9ucwoKQ3V0IHRoZSBwb3N0LWJsb2NrIGludG8gdHdvIHNvIHdlIGhhdmUgZm91ciAxNS1taW51dGUgaW50ZXJ2YWxzOiBvbmUgYmVmb3JlLCBvbmUgZHVyaW5nLCBhbmQgdHdvIGFmdGVyIHN0aW11bGF0aW9uLgoKYGBge3IgMTUtbWludXRlIGludmVydmFsc30KIyBTcGxpdCB0aGUgInBvc3QiIGxlZyBpbnRvIHR3bwpncm91cERhdGEgPC0gbXV0YXRlKGdyb3VwRGF0YSwKICAgICAgICAgICAgICAgICAgICBsZWcgPSBhcy5jaGFyYWN0ZXIobGVnKSwgIyBjYW5ub3QgZWRpdCBsZWcgaWYgaXQncyBzdGlsbCBhIGZhY3RvcgogICAgICAgICAgICAgICAgICAgIGxlZyA9IHJlcGxhY2UobGVnLCBsZWcgPT0gInBvc3QiICYgYmxvY2sgPD0gMywgInBvc3QuMSIpLAogICAgICAgICAgICAgICAgICAgIGxlZyA9IHJlcGxhY2UobGVnLCBibG9jayA+IDMsICJwb3N0LjIiKSwKICAgICAgICAgICAgICAgICAgICBsZWcgPSBmYWN0b3IobGVnLCBsZXZlbHMgPSBjKCJwcmUiLCAidERDUyIsICJwb3N0LjEiLCAicG9zdC4yIikpICMgcmVmYWN0b3IgYW5kIG9yZGVyIGxldmVscwogICAgICAgICAgICAgICAgICAgICkKYGBgCgojIFNhY2NhZGUgZW5kIHBvaW50IGRldmlhdGlvbgoKT25lIGVzdGltYXRlIG9mIHRoZSBhY2N1cmFjeSBvZiBzYWNjYWRlcyBpcyB0aGUgbWVhbiBsYW5kaW5nIHBvc2l0aW9uIHdpdGggcmVzcGVjdCB0byB0aGUgdGFyZ2V0IGxvY2F0aW9uLiBbS2FuYWkgZXQgYWwuICgyMDEyKV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMzM4OS9mcHN5dC4yMDEyLjAwMDQ1KSBhbHNvIGV4YW1pbmVkIHRoaXMsIGJ1dCBmb3VuZCBubyBlZmZlY3RzIG9mIHREQ1MuCgpUaGUgc2ltcGxlc3QgbWVhc3VyZSAod2hpY2ggS2FuYWkgZXQgYWwuICgyMDEyKSBhbHNvIHVzZWQpIGlzIHRoZSBFdWNsaWRpYW4gZGlzdGFuY2UgKHNob3J0ZXN0IHN0cmFpZ2h0IGxpbmUpIGJldHdlZW4gdGhlIHNhY2NhZGUgZW5kIHBvaW50IGFuZCB0aGUgY2VudGVyIG9mIHRoZSB0YXJnZXQgc3RpbXVsdXMuIFdlIGFscmVhZHkgaGF2ZSB0aGUgZGV2aWF0aW9ucyBpbiB0aGUgeC0gYW5kIHktIGRpcmVjdGlvbnMgaW4gZGVncmVlcyBvZiB2aXN1YWwgYW5nbGUuIE5vdyB3ZSBqdXN0IG5lZWQgdG8gY2FsY3VsYXRlIHRoZSBsZW5ndGggb2YgdGhlIHZlY3Rvci4KCmBgYHtyIENhbGN1bGF0ZSBlbmQgcG9pbnQgZGV2aWF0aW9ufQojIENhbGN1bGF0ZSBlbmQgcG9pbnQgZGV2aWF0aW9uCmRldkRhdGEgPC0gbXV0YXRlKGdyb3VwRGF0YSwgZGV2aWF0aW9uLmVuZCA9IHNxcnQoZGV2aWF0aW9uLmVuZC54XjIgKyBkZXZpYXRpb24uZW5kLnleMikpCmBgYAoKIyMgUHJlcGFyZSBkYXRhIGZyYW1lIGZvciBwbG90dGluZyAmIHN0YXRpc3RpY3MKCkF2ZXJhZ2Ugb3ZlciB0aHJlZSBibG9ja3M6CgpgYGB7ciBNZWFuIG92ZXIgdHJpYWxzIC0gZGV2aWF0aW9ufQpkZXZEYXRhIDwtIGRldkRhdGEgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzdGltdWxhdGlvbixkaXJlY3Rpb24sdHlwZSkgJT4lIAogIHN1bW1hcmlzZShiYXNlbGluZSA9IG1lYW4oZGV2aWF0aW9uLmVuZFtsZWcgPT0gInByZSJdKSwgIyB0YWtlIGF2ZXJhZ2Ugb2YgMyBibG9ja3MsIG1ha2UgbmV3IGNvbHVtbgogICAgICAgICAgICB0RENTID0gbWVhbihkZXZpYXRpb24uZW5kW2xlZyA9PSAidERDUyJdKSwKICAgICAgICAgICAgcG9zdC4xID0gbWVhbihkZXZpYXRpb24uZW5kW2xlZyA9PSAicG9zdC4xIl0pLAogICAgICAgICAgICBwb3N0LjIgPSBtZWFuKGRldmlhdGlvbi5lbmRbbGVnID09ICJwb3N0LjIiXSkpICU+JQpnYXRoZXIobGVnLCBkZXZpYXRpb24uZW5kLCBiYXNlbGluZSwgdERDUywgcG9zdC4xLCBwb3N0LjIpICAlPiUgIyBnYXRoZXIgbmV3IGNvbHVtbnMgdG8gdXNlIGFzIGZhY3RvciAKbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoImJhc2VsaW5lIiwgInREQ1MiLCAicG9zdC4xIiwgInBvc3QuMiIpKSkgIyByZW9yZGVyIGZhY3RvciBsZXZlbHMKYGBgCgpTdWJ0cmFjdCB0aGUgYmFzZWxpbmUgZnJvbSBlYWNoIGF2ZXJhZ2U6CgpgYGB7ciBTdWJ0cmFjdCBiYXNlbGluZSAtIGRldmlhdGlvbn0KIyBTdWJ0cmFjdCBiYXNlbGluZQpkZXZEYXRhQmFzZSA8LSBkZXZEYXRhICU+JQogIGdyb3VwX2J5KHN1YmplY3Qsc3RpbXVsYXRpb24sZGlyZWN0aW9uLHR5cGUpICU+JSAKICAjIHN1YnRyYWN0IGJhc2VsaW5lIGJsb2NrIGZyb20gb3RoZXJzLCBtYWtlIG5ldyBjb2x1bW4KICBzdW1tYXJpc2UodERDUyA9IGRldmlhdGlvbi5lbmRbbGVnID09ICJ0RENTIl0gLSBkZXZpYXRpb24uZW5kW2xlZyA9PSAiYmFzZWxpbmUiXSwgCiAgICAgICAgICAgIHBvc3QuMSA9IGRldmlhdGlvbi5lbmRbbGVnID09ICJwb3N0LjEiXSAtIGRldmlhdGlvbi5lbmRbbGVnID09ICJiYXNlbGluZSJdLAogICAgICAgICAgICBwb3N0LjIgPSBkZXZpYXRpb24uZW5kW2xlZyA9PSAicG9zdC4yIl0gLSBkZXZpYXRpb24uZW5kW2xlZyA9PSAiYmFzZWxpbmUiXSkgJT4lCmdhdGhlcihsZWcsIGRldmlhdGlvbi5lbmQsIHREQ1MsIHBvc3QuMSwgcG9zdC4yKSAlPiUgIyBnYXRoZXIgbmV3IGNvbHVtbnMgdG8gdXNlIGFzIGZhY3RvciAKbXV0YXRlKGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoInREQ1MiLCAicG9zdC4xIiwgInBvc3QuMiIpKSkgIyByZW9yZGVyIGZhY3RvciBsZXZlbHMKYGBgCgojIyBQbG90CgojIyMgV2l0aCBiYXNlbGluZSBibG9jawoKYGBge3IgTGluZSBwbG90IHBlciBsZWcgLSBkZXZpYXRpb259CmthbmFpUGxvdERldiA8LSBnZ3Bsb3QoZGV2RGF0YSwgYWVzKGxlZywgZGV2aWF0aW9uLmVuZCwgY29sb3IgPSBzdGltdWxhdGlvbiwgc2hhcGUgPSBzdGltdWxhdGlvbikpICsgICAgICAgICAKICBmYWNldF9ncmlkKHR5cGUgfiBkaXJlY3Rpb24pICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50Iiwgc2l6ZSA9IDMpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gImxpbmUiLCBhZXMoZ3JvdXAgPSBzdGltdWxhdGlvbiksIHNpemUgPSAxKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ub3JtYWwsIGdlb20gPSAiZXJyb3JiYXIiLCB3aWR0aCA9IDAuMykKa2FuYWlQbG90RGV2CmBgYAoKQXQgZmlyc3QgZ2xhbmNlIHRoZXJlIGRvbid0IHNlZW0gdG8gYmUgbWFueSBkaWZmZXJlbmNlcyB0aGF0IGFyZSBsYXJnZXIgdGhhbiB0aGUgYmFzZWxpbmUgZGlmZmVyZW5jZXMgYW5kL29yIHJlbGF0ZSBjbGVhcmx5IHRvIHRoZSBwb2xhcml0eSBvciB0aW1pbmcgb2Ygc3RpbXVsYXRpb24uCgpMZXQncyBsb29rIGF0IHRoZSBpbmRpdmlkdWFsIHN1YmplY3QgZGF0YToKCmBgYHtyIExpbmUgcGxvdCBwZXIgc3ViamVjdCAtIGRldmlhdGlvbiBhbm9kYWx9CmthbmFpUGxvdFN1YnNBbm9kYWwgPC0gZ2dwbG90KGRldkRhdGFbZGV2RGF0YSRzdGltdWxhdGlvbiA9PSAiYW5vZGFsIiwgXSwgYWVzKGxlZywgZGV2aWF0aW9uLmVuZCkpICsKICBmYWNldF9ncmlkKHR5cGUgfiBkaXJlY3Rpb24pICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gc3ViamVjdCxjb2xvciA9IHN1YmplY3QpKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pLCBnZW9tID0gImxpbmUiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIpICsKICBnZ3RpdGxlKCJBbm9kYWwgc2Vzc2lvbiIpCmthbmFpUGxvdFN1YnNBbm9kYWwKYGBgCgpgYGB7ciBMaW5lIHBsb3QgcGVyIHN1YmplY3QgLSBkZXZpYXRpb24gY2F0aG9kYWx9CmthbmFpUGxvdFN1YnNDYXRob2RhbCA8LSBnZ3Bsb3QoZGV2RGF0YVtkZXZEYXRhJHN0aW11bGF0aW9uID09ICJjYXRob2RhbCIsIF0sIGFlcyhsZWcsIGRldmlhdGlvbi5lbmQpKSArCiAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHN1YmplY3QsY29sb3IgPSBzdWJqZWN0KSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSwgZ2VvbSA9ICJsaW5lIikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiKSArCiAgZ2d0aXRsZSgiQ2F0aG9kYWwgc2Vzc2lvbiIpCmthbmFpUGxvdFN1YnNDYXRob2RhbApgYGAKClRoZXJlIGFyZSBkZWZpbml0ZWx5IHNvbWUgb3V0bGllcnMsIGJ1dCBtb3N0bHkgaW4gdGVybXMgb2Ygb3ZlcmFsbCBvZmZzZXQgLyBiYXNlbGluZSBkaWZmZXJlbmNlcy4KCiMjIyMgQmFzZWxpbmUgcmVsaWFiaWxpdHkKClNjYXR0ZXJwbG90IGFuZCBjb3JyZWxhdGlvbiBvZiBiYXNlbGluZSBkYXRhIGluIHRoZSB0d28gc2Vzc2lvbnM6CgpgYGB7ciBiYXNlbGluZSBjb3JyZWxhdGlvbnMgLSBkZXZpYXRpb259CmJhc2VsaW5lQ29yckRldiA8LSBkZXZEYXRhICU+JQogIGZpbHRlcihsZWcgPT0gImJhc2VsaW5lIikgJT4lIAogIGdyb3VwX2J5KGRpcmVjdGlvbix0eXBlKSAlPiUgCiAgc3ByZWFkKHN0aW11bGF0aW9uLGRldmlhdGlvbi5lbmQpICU+JSAKICBuZXN0KCkgJT4lIAogIG11dGF0ZShzdGF0cyA9IG1hcChkYXRhLCB+Y29yLnRlc3QoZm9ybXVsYSA9IH4gYW5vZGFsICsgY2F0aG9kYWwsIGRhdGEgPS4pKSkgJT4lICMgcnVuIGNvcnJlbGF0aW9uIHRlc3Qgb24gYmFzZWxpbmVzIGZyb20gZWFjaCBjb25kaXRpb24KICBtdXRhdGUodGlkeV9tb2RlbCA9IG1hcChzdGF0cywgdGlkeSkpICU+JSAKICB1bm5lc3QodGlkeV9tb2RlbCwgLmRyb3AgPSBUUlVFKQpgYGAKCmBgYHtyIGJhc2VsaW5lIHNjYXR0ZXJwbG90cyAtIGRldmlhdGlvbn0KZGV2RGF0YSAlPiUKICBmaWx0ZXIobGVnID09ICJiYXNlbGluZSIpICU+JQogIHNwcmVhZChzdGltdWxhdGlvbixkZXZpYXRpb24uZW5kKSAlPiUKICBpbm5lcl9qb2luKC4sIHN1YmplY3REYXRhWyAsYygic3ViamVjdCIsInNlc3Npb24ub3JkZXIiKV0sIGJ5ID0gYygic3ViamVjdCIpKSAlPiUgIyBhZGQgY29sdW1uIG9uIHNlc3Npb24gb3JkZXIgZnJvbSBvdGhlciBkYXRhIGZyYW1lCiAgZ2dwbG90KGFlcyhhbm9kYWwsY2F0aG9kYWwpKSArCiAgICBmYWNldF9ncmlkKHR5cGUgfiBkaXJlY3Rpb24pICsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogICAgZ2VvbV9wb2ludChhZXMoY29sb3I9c2Vzc2lvbi5vcmRlcikpICsKICAgIHhsaW0oMCwyKSArIHlsaW0oMCwyKSArCiAgICBnZW9tX3RleHQoZGF0YSA9IGJhc2VsaW5lQ29yckRldiwgeCA9IDAuMiwgeSA9IDEuNSwgYWVzKGxhYmVsID0gcGFzdGUoIml0YWxpYyhyKSA9PSAiLCByb3VuZChlc3RpbWF0ZSwyKSkpLCBwYXJzZSA9IFRSVUUpICsKICAgIGxhYnModGl0bGUgPSAiQmFzZWxpbmUgaW4gYW5vZGFsIGFuZCBjYXRob2RhbCBzZXNzaW9ucyIsIHN1YnRpdGxlID0gInNjYXR0ZXJwbG90IG9mIGJhc2VsaW5lIGVuZHBvaW50IGRldmlhdGlvbiIpCmBgYAoKVGhlIGNvcnJlbGF0aW9ucyBhcmUgbm90IGFzIGhpZ2ggYXMgZm9yIHRoZSBsYXRlbmN5IGRhdGEsIGJ1dCBzdGlsbCByZWFzb25hYmxlLiBUaGUgc2VxdWVuY2UgZWZmZWN0IHdlIG9ic2VydmVkIGluIHRoZSBsYXRlbmN5IGRhdGEgaXMgbm90IHNvIHByb21pbmVudCwgc28gYXBwYXJlbnRseSB0aGVyZSdzIGxlc3Mgb2YgYSBwcmFjdGljZSBlZmZlY3QgaW4gc2FjY2FkZSBlbnBkb2ludCBkZXZpYXRpb24uCgojIyMjIEJhc2VsaW5lIGRpZmZlcmVuY2VzCgpgYGB7ciBiYXNlbGluZSBkaWZmZXJlbmNlIHN0cmlwY2hhcnQgLSBkZXZpYXRpb259CmRldkRhdGEgJT4lCiAgZmlsdGVyKGxlZyA9PSAiYmFzZWxpbmUiKSAlPiUKICBpbm5lcl9qb2luKC4sIHN1YmplY3REYXRhWyAsYygic3ViamVjdCIsInNlc3Npb24ub3JkZXIiKV0sIGJ5ID0gYygic3ViamVjdCIpKSAlPiUgIyBhZGQgY29sdW1uIG9uIHNlc3Npb24gb3JkZXIgZnJvbSBvdGhlciBkYXRhIGZyYW1lCiAgZ3JvdXBfYnkoc3ViamVjdCxkaXJlY3Rpb24sdHlwZSxzZXNzaW9uLm9yZGVyKSAlPiUKICBzdW1tYXJpc2UoZGV2aWF0aW9uLmVuZC5kaWZmID0gZGV2aWF0aW9uLmVuZFtzdGltdWxhdGlvbiA9PSAiYW5vZGFsIl0gLSBkZXZpYXRpb24uZW5kW3N0aW11bGF0aW9uID09ICJjYXRob2RhbCJdKSAlPiUKICBnZ3Bsb3QoYWVzKGZhY3RvcigwKSwgZGV2aWF0aW9uLmVuZC5kaWZmKSkgKwogICAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCkgKwogICAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgYWVzKGxhYmVsPXJvdW5kKC4ueS4uLCBkaWdpdHM9MiksIHggPSAxLjMpLCBnZW9tID0gImxhYmVsIiwgYWxwaGEgPSAwLjUpICsKICAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgYWVzKGNvbG91ciA9IHNlc3Npb24ub3JkZXIpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcih3aWR0aD0uMSkpICsKICAgIGxhYnModGl0bGUgPSAiQmFzZWxpbmUgaW4gYW5vZGFsIGFuZCBjYXRob2RhbCBzZXNzaW9ucyIsIHN1YnRpdGxlID0gImFub2RhbCAtIGNhdGhvZGFsIikKYGBgCgpUaGUgYmFzZWxpbmUgZGlmZmVyZW5jZXMgYXJlIG5vdCBzbyBleHRyZW1lLCBleGNlcHQgZm9yIHRoZSBjZW50ZXIgKGxlZnQpIGNvbmRpdGlvbjogdGhhdCBzZWVtcyBxdWl0ZSBsYXJnZSBhbmQgY29uc2lzdGVudCBvdmVyIHN1YmplY3RzLgoKYGBge3IgdC10ZXN0cyBvZiBiYXNlbGluZSBkaWZmZXJlbmNlIC0gZGV2aWF0aW9ufQpkZXZEYXRhICU+JQogIGZpbHRlcihsZWcgPT0gImJhc2VsaW5lIikgJT4lCiAgZ3JvdXBfYnkoZGlyZWN0aW9uLHR5cGUpICU+JSAKICBuZXN0KCkgJT4lIAogIG11dGF0ZShzdGF0cyA9IG1hcChkYXRhLCB+dC50ZXN0KGZvcm11bGEgPSBkZXZpYXRpb24uZW5kfnN0aW11bGF0aW9uLCBwYWlyZWQgPSBUUlVFLCBkYXRhID0uKSkpICU+JSAjIHJ1biB0LXRlc3Qgb24gdGhlIGRhdGEgZnJhbWVzCiAgbXV0YXRlKHRpZHlfbW9kZWwgPSBtYXAoc3RhdHMsIHRpZHkpKSAlPiUKICB1bm5lc3QodGlkeV9tb2RlbCwgLmRyb3AgPSBUUlVFKSAlPiUgCiAga2FibGUoLikKYGBgCgpJbmRlZWQsIGluIHRoZSBjZW50ZXItbGVmdCBjb25kaXRpb24gdGhlIGJhc2VsaW5lIGRpZmZlcmVuY2UgaXMgc2lnbmlmaWNhbnQsIGFuZCBpdCdzIGF0IHRyZW5kIGluIHRoZSBjZW50ZXItcmlnaHQgY29uZGl0aW9uLgoKRm9yIHRoZSBjZW50ZXIgY29uZGl0aW9ucywgbGV0J3MgbG9vayBhdCB0aGUgcmF3IGRhdGEgZnJvbSBUaW1lIFBlcmlvZHMgYWZ0ZXIgdGhlIGJhc2VsaW5lIGJsb2NrLCB0byBzZWUgaWYgdGhlcmUgYXJlIGFsc28gZGlmZmVybmVuY2VzIGJldHdlZW4gYW5vZGFsIGFuZCBjYXRob2RhbCB0aGVyZToKCmBgYHtyIHRpbWUgcGVyaW9kcyBhZnRlciBiYXNlbGluZX0KZGV2RGF0YSAlPiUKICBmaWx0ZXIobGVnICE9ICJiYXNlbGluZSIsIHR5cGUgPT0gImNlbnRlciIpICU+JQogIGdyb3VwX2J5KHN0aW11bGF0aW9uLGRpcmVjdGlvbixsZWcpICU+JSAKICBzdW1tYXJpc2UobWVhbiA9IG1lYW4oZGV2aWF0aW9uLmVuZCkpICU+JQogIGthYmxlKC4pICAgICAgICAgICAgCmBgYAoKIyMjIEJhc2VsaW5lIHN1YnRyYWN0ZWQKCmBgYHtyIExpbmUgcGxvdCBmcm9tIGJhc2VsaW5lIC0gZGV2aWF0aW9ufQprYW5haVBsb3REZXZCYXNlIDwtIGdncGxvdChkZXZEYXRhQmFzZSwgYWVzKGxlZywgZGV2aWF0aW9uLmVuZCwgY29sb3IgPSBzdGltdWxhdGlvbiwgc2hhcGUgPSBzdGltdWxhdGlvbikpICsgICAgICAKICBmYWNldF9ncmlkKHR5cGUgfiBkaXJlY3Rpb24pICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNpemUgPSAzKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pLCBzaXplID0gMSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfbm9ybWFsLCBnZW9tID0gImVycm9yYmFyIiwgd2lkdGggPSAwLjMpCmthbmFpUGxvdERldkJhc2UKYGBgCgpUaGlzIGNsZWFybHkgc2hvd3MgdGhhdCBhbGwgdGhlIGNoYW5nZXMgYXJlIHF1aXRlIHRpbnkgKGxlc3MgdGhhbiAwLjE1IGRlZ3JlZXMgb2YgdmlzdWFsIGFuZ2xlKS4gVGhlcmUgYXBwZWFycyB0byBiZSBhIGNsZWFyIGRpZmZlcmVuY2UgaW4gIGJldHdlZW4gdGhlIGFub2RhbCBhbmQgY2F0aG9kYWwgY2hhbmdlIHNjb3JlcyBmb3IgY2VudGVyIHNhY2NhZGVzIChhbmQgbWF5YmUgZm9yIGxlZnQtbGF0ZXJhbCBzYWNjYWRlcykuIAoKSG93ZXZlciwgd2Uga25vdyB0aGF0IHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gYW5vZGFsIGFuZCBjYXRob2RhbCBpcyBhY3R1YWxseSBtYXhpbWFsIGluIHRoZSBiYXNlbGluZS4gVGh1cyBpdCByZW1haW5zIHVuY2xlYXIgd2hldGhlciB0aGUgYmFzZWxpbmUgZGlmZmVyZW5jZXMgYXJlIHNwdXJpb3VzIGFuZCB0aGUgZWZmZWN0IGlzIHJlYWwsIG9yIHdoZXRoZXIgdGhlICJlZmZlY3QiIGlzIGRyaXZlbiBieSB0aGUgYmFzZWxpbmUgZGlmZmVyZW5jZSAoaS5lLiBzb21ldGhpbmcgYWtpbiB0byByZWdyZXNzaW9uIHRvIHRoZSBtZWFuKS4KCiMjIFN0YXRpc3RpY3MKCmBgYHtyIFByZXBhcmUgZGF0YSBmcmFtZXMgLSBkZXZpYXRpb259CiMgTWFrZSAic3ViamVjdCIgYSBmYWN0b3IsIHNvIHdlIGNhbiBtb2RlbCB0aGUgcmVwZWF0ZWQgbWVhc3VyZXMKZGV2RGF0YUJhc2UgPC0gZGV2RGF0YUJhc2UgJT4lCiAgdW5ncm91cCgpICU+JSAjIHJlbW92ZSBhbnkgZ3JvdXBpbmcgaW5mbywgYmVjYXVzZSB3ZSBuZWVkIHRvIHJlZmFjdG9yCiAgaW5uZXJfam9pbiguLCBzdWJqZWN0RGF0YVsgLGMoInN1YmplY3QiLCJzZXNzaW9uLm9yZGVyIildLCBieSA9IGMoInN1YmplY3QiKSkgJT4lICMgYWRkIGNvbHVtbiBvbiBzZXNzaW9uIG9yZGVyIGZyb20gb3RoZXIgZGF0YSBmcmFtZQogIG11dGF0ZShzdWJqZWN0ID0gZmFjdG9yKHN1YmplY3QpKSAjIHJlZmFjdG9yCmBgYAoKIyMjIEZyZXF1ZW50aXN0CgojIyMjIEFOT1ZBIG1hdGNoaW5nIEthbmFpIGV0IGFsLiAoMjAxMikgLSBsYXRlcmFsIHNhY2NhZGVzIHsudGFic2V0IC50YWJzZXQtZmFkZX0KCiMjIyMjIFdpdGhvdXQgc2Vzc2lvbiBvcmRlcgoKX19EYXRhX186IAoKKiBPdXRsaWVycyByZW1vdmVkCiogQ29sbGFwc2VkIGludG8gMTUtbWludXRlIGludGVydmFscwoqIFN1YnRyYWN0IHRoZSBiYXNlbGluZSBmcm9tIGVhY2ggc3Vic2VxdWVudCBibG9jawoqIERpc2NhcmQgY2VudGVyLCBrZWVwIG9ubHkgbGF0ZXJhbCBzYWNjYWRlcwoKX19EZXBlbmRlbnQgbWVhc3VyZV9fOiBzYWNjYWRlIGVuZCBwb2ludCBkZXZpYXRpb24KCl9fRmFjdG9yc19fOgoKKiBTVElNVUxBVElPTiAoYW5vZGFsIHZzLiBjYXRob2RhbCkKKiBMRUcgKHREQ1MsIHBvc3QuMSwgcG9zdC4yKQoqIERJUkVDVElPTiAobGVmdCB2cy4gcmlnaHQpCgpgYGB7ciBLYW5haSBBTk9WQSBkZXZpYXRpb24gbGF0ZXJhbCwgcmVzdWx0cz0nYXNpcyd9Cm1vZGVsS2FuYWkgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShmaWx0ZXIoZGV2RGF0YUJhc2UsIHR5cGUgPT0gImxhdGVyYWwiKSksCiAgICAgICAgICAgICAgICAgICAgICAgIGR2ID0gLihkZXZpYXRpb24uZW5kKSwgd2lkID0gLihzdWJqZWN0KSwgd2l0aGluID0gLihzdGltdWxhdGlvbixsZWcsZGlyZWN0aW9uKSwgdHlwZSA9IDMpCgprYWJsZShtb2RlbEthbmFpJEFOT1ZBKQprYWJsZShtb2RlbEthbmFpJGBNYXVjaGx5J3MgVGVzdCBmb3IgU3BoZXJpY2l0eWApCmthYmxlKG1vZGVsS2FuYWkkYFNwaGVyaWNpdHkgQ29ycmVjdGlvbnNgKQpgYGAKCiMjIyMjIFdpdGggc2Vzc2lvbiBvcmRlcgoKQWRkIGFuIGFkZGl0aW9uYWwgZmFjdG9yIFNFU1NJT04gT1JERVIsIHdoaWNoIGNyZWF0ZXMgdHdvIGdyb3VwczogdGhvc2Ugc3ViamVjdHMgd2hvIHJlY2VpdmVkIGFub2RhbCB0RENTIGluIHRoZSBmaXJzdCBzZXNzaW9uIHZzLiB0aG9zZSB3aG8gcmVjZWl2ZWQgY2F0aG9kYWwgdERDUyBpbiB0aGUgZmlyc3Qgc2Vzc2lvbi4gTm90ZSB0aGF0IHRoZXNlIGdyb3VwcyBhcmUgbm90IGV4YWN0bHkgYmFsYW5jZWQsIHdoaWNoIG1pZ2h0IGFmZmVjdCAoY29ycmVjdGluZyBmb3IpIHZpb2xhdGlvbnMgb2Ygc3BoZXJpY2l0eToKCmBgYHtyIFVuYmFsYW5jZWQgc2Vzc2lvbiBvcmRlcnMsIHJlc3VsdHM9J2FzaXMnfQpkZXZEYXRhQmFzZSAlPiUKICBncm91cF9ieShzZXNzaW9uLm9yZGVyKSAlPiUKICBzdW1tYXJpemUoY291bnQgPSBuX2Rpc3RpbmN0KHN1YmplY3QpKSAlPiUKICBrYWJsZSguKQpgYGAKCmBgYHtyIEthbmFpIEFOT1ZBIGxhdGVyYWwgZGV2aWF0aW9uIHNlc3Npb24gb3JkZXIsIHJlc3VsdHM9J2FzaXMnfQptb2RlbEthbmFpT3JkZXIgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShmaWx0ZXIoZGV2RGF0YUJhc2UsIHR5cGUgPT0gImxhdGVyYWwiKSksIGR2ID0gLihkZXZpYXRpb24uZW5kKSwgCiAgICAgICAgICB3aWQgPSAuKHN1YmplY3QpLCB3aXRoaW4gPSAuKHN0aW11bGF0aW9uLGxlZyxkaXJlY3Rpb24pLCAgYmV0d2VlbiA9IHNlc3Npb24ub3JkZXIsIHR5cGUgPSAzKQprYWJsZShtb2RlbEthbmFpT3JkZXIkQU5PVkEpCmthYmxlKG1vZGVsS2FuYWlPcmRlciRgTWF1Y2hseSdzIFRlc3QgZm9yIFNwaGVyaWNpdHlgKQprYWJsZShtb2RlbEthbmFpT3JkZXIkYFNwaGVyaWNpdHkgQ29ycmVjdGlvbnNgKQpgYGAKCiMjIyMgQU5PVkEgbWF0Y2hpbmcgS2FuYWkgZXQgYWwuICgyMDEyKSAtIGNlbnRlciBzYWNjYWRlcyB7LnRhYnNldCAudGFic2V0LWZhZGV9CgojIyMjIyBXaXRob3V0IHNlc3Npb24gb3JkZXIKClJlcGVhdCB0aGUgc2FtZSBBTk9WQSwgYnV0IG5vdyBkaXNjYXJkIHRoZSBsYXRlcmFsIGFuZCBrZWVwIG9ubHkgY2VudGVyIHNhY2NhZGVzICh3aGljaCBLYW5haSBkaWQgbm90IGhhdmUpLgoKYGBge3IgS2FuYWkgQU5PVkEgY2VudGVyLCByZXN1bHRzPSdhc2lzJ30KbW9kZWxLYW5haUNlbnRlciA8LSBlekFOT1ZBKGRhdGEgPSBkYXRhLmZyYW1lKGZpbHRlcihkZXZEYXRhQmFzZSwgdHlwZSA9PSAiY2VudGVyIikpLAogICAgICAgICAgICAgICAgICAgICAgICBkdiA9IC4oZGV2aWF0aW9uLmVuZCksIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sbGVnLGRpcmVjdGlvbiksIHR5cGUgPSAzKQoKa2FibGUobW9kZWxLYW5haUNlbnRlciRBTk9WQSkKa2FibGUobW9kZWxLYW5haUNlbnRlciRgTWF1Y2hseSdzIFRlc3QgZm9yIFNwaGVyaWNpdHlgKQprYWJsZShtb2RlbEthbmFpQ2VudGVyJGBTcGhlcmljaXR5IENvcnJlY3Rpb25zYCkKYGBgCgojIyMjIyMgTWFpbiBlZmZlY3Qgb2Ygc3RpbXVsYXRpb24KCmBgYHtyIEthbmFpLUNlbnRlciBNYWluIGVmZmVjdCBvZiBzdGltdWxhdGlvbn0KZGV2RGF0YUJhc2UgJT4lCiAgZmlsdGVyKHR5cGUgPT0gImNlbnRlciIpICU+JQogIGdyb3VwX2J5KHN1YmplY3Qsc3RpbXVsYXRpb24pICU+JQogIHN1bW1hcmlzZShkZXZpYXRpb24uZW5kID0gbWVhbihkZXZpYXRpb24uZW5kKSkgJT4lCiAgZ2dwbG90KGFlcyhzdGltdWxhdGlvbiwgZGV2aWF0aW9uLmVuZCkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ub3JtYWwsIHNpemUgPSAxKSArCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjI1KQpgYGAKClRoZSBhY2N1cmFjeSBpbiB0aGUgY2F0aG9kYWwgc2Vzc2lvbiBpbXByb3ZlcyBmcm9tIGJhc2VsaW5lIGZvciBtb3N0IHN1YmplY3RzOyBhbm9kYWwgc3RheXMgdGhlIHNhbWUgb3Igc2xpZ2h0bHkgd29yc2Vucy4KCkxldCdzIGRvIHNvbWUgZm9sbG93LXVwIHRlc3RzIHRvIHNlZSB3aGV0aGVyIHRoZSBhbm9kYWwgb3IgY2F0aG9kYWwgY2hhbmdlIHNjb3JlcyBhcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZnJvbSAwIG9uIHRoZWlyIG93bi4KCkZyZXF1ZW50aXN0IG9uZS1zYW1wbGUgdC10ZXN0czoKCmBgYHtyIENsYXNzaWNhbCBmb2xsb3ctdXAgdGVzdCAtIGRldmlhdGlvbn0KZGV2RGF0YUJhc2UgJT4lCiAgZmlsdGVyKHR5cGUgPT0gImNlbnRlciIpICU+JSAjIGtlZXAgb25seSBjZW50ZXIgc2FjY2FkZXMKICBncm91cF9ieShzdGltdWxhdGlvbixzdWJqZWN0KSAlPiUgIyBmb3IgZWFjaCBzZXNzaW9uIGFuZCBzdWJqZWN0CiAgc3VtbWFyaXNlKGRldmlhdGlvbi5lbmQgPSBtZWFuKGRldmlhdGlvbi5lbmQpKSAlPiUgIyBhdmVyYWdlIG92ZXIgYWxsIG90aGVyIHZhcmlhYmxlcyAoZGYgaXMgbm93IHN0aWxsIGdyb3VwZWQgcGVyIHN0aW11bGF0aW9uKQogIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBmdW5zKGxpc3QodGlkeSh0LnRlc3QoLikpKSkpICU+JSAgIyBydW4gb25lLXNhbXBsZSB0LXRlc3QgZm9yIGVhY2ggc3RpbXVsYXRpb24gY29uZGl0aW9uLCByZXR1cm4gdGlkeSBkYXRhIGZyYW1lcwogIHVubmVzdCgpICU+JSAjIHVucGFjayB0aGUgbGlzdC1jb2x1bW4gd2l0aCBkYXRhIGZyYW1lIGZvciBlYWNoIHRlc3QKICBrYWJsZSguKQpgYGAKClRoZSBjYXRob2RhbCBlZmZlY3QgaXMgaGlnaGx5IHNpZ25pZmNhbnQsIGJ1dCB0aGUgYW5vZGFsIGlzIG5vdC4KCiMjIyMjIyBJbnRlcmFjdGlvbjogTGVnIGJ5IGRpcmVjdGlvbgoKYGBge3IgS2FuYWkgSW50ZXJhY3Rpb24gbGVnIGJ5IGRpcmVjdGlvbn0KZGV2RGF0YUJhc2UgJT4lCiAgZmlsdGVyKHR5cGUgPT0gImNlbnRlciIpICU+JQogIGdyb3VwX2J5KHN1YmplY3QsbGVnLGRpcmVjdGlvbikgJT4lCiAgc3VtbWFyaXNlKGRldmlhdGlvbi5lbmQgPSBtZWFuKGRldmlhdGlvbi5lbmQpKSAlPiUKICBnZ3Bsb3QoYWVzKGxlZywgZGV2aWF0aW9uLmVuZCwgc2hhcGUgPSBkaXJlY3Rpb24pKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgYWVzKGdyb3VwID0gZGlyZWN0aW9uLCBsaW5ldHlwZSA9IGRpcmVjdGlvbikpCmBgYAoKVGhlIGFjY3VyYWN5IG9mIGxlZnR3YXJkIHNhY2NhZGVzIGlzIGltcHJvdmVkIGZvciBsZWZ0IHNhY2NhZGVzIGluIHRoZSBmaW5hbCBoYWxmIGhvdXIgb2YgdGFzayBwZXJmb3JtYW5jZSwgbW9yZSBzbyB0aGFuIGZvciByaWdodCBzYWNjYWRlcywgZm9yIHdoaWNoIHRoZSBhY2N1cmFjeSBnb2VzIGJhY2sgdG8gYmFzZWxpbmUgZXZlbnR1YWxseS4KCiMjIyMjIFdpdGggc2Vzc2lvbiBvcmRlcgoKYGBge3IgS2FuYWkgQU5PVkEgY2VudGVyIHNlc3Npb24gb3JkZXIsIHJlc3VsdHM9J2FzaXMnfQptb2RlbEthbmFpQ2VudGVyT3JkZXIgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShmaWx0ZXIoZGV2RGF0YUJhc2UsIHR5cGUgPT0gImNlbnRlciIpKSwgZHYgPSAuKGRldmlhdGlvbi5lbmQpLCAKICAgICAgICAgIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sbGVnLGRpcmVjdGlvbiksICBiZXR3ZWVuID0gc2Vzc2lvbi5vcmRlciwgdHlwZSA9IDMpCmthYmxlKG1vZGVsS2FuYWlDZW50ZXJPcmRlciRBTk9WQSkKa2FibGUobW9kZWxLYW5haUNlbnRlck9yZGVyJGBNYXVjaGx5J3MgVGVzdCBmb3IgU3BoZXJpY2l0eWApCmthYmxlKG1vZGVsS2FuYWlDZW50ZXJPcmRlciRgU3BoZXJpY2l0eSBDb3JyZWN0aW9uc2ApCmBgYAoKVGhlcmUgYXJlIHNvbWUgc2lnbmlmaWNhbnQgZWZmZWN0cywgYnV0IHRoZXkgZG8gbm90IGludGVyYWN0IHdpdGggc2Vzc2lvbiBvcmRlci4KCiMjIyBCYXllc2lhbgoKX1NlZSB0aGUgYG1lZGlhbl9sYXRlbmN5Lm5iLmh0bWxgIG5vdGVib29rIGZvciBtb3JlIGV4cGxhbmF0aW9uIG9mIHRoZSBCYXllc2lhbiBhbmFseXNlc18KCiMjIyMgTGluZWFyIG1peGVkIGVmZmVjdHMgbWF0Y2hpbmcgS2FuYWkgLSBsYXRlcmFsIHNhY2NhZGVzCgpCYXllc2lhbiBhbmFsb2d1ZSBvZiB0aGUgZnJlcXVlbnRpc3QgcmVwZWF0ZWQgbWVhc3VyZXMgQU5PVkEgKHdpdGhvdXQgb3JkZXIgZWZmZWN0KSwgd2l0aCB0aGUgc2FtZSBmYWN0b3JzLgoKYGBge3IgQmF5ZXMgRmFjdG9ycyBLYW5haSBsYXRlcmFsfQpiZkthbmFpTGF0ZXJhbCA9IGFub3ZhQkYoZGV2aWF0aW9uLmVuZH5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uK3N1YmplY3QsIGRhdGEgPSBkYXRhLmZyYW1lKGZpbHRlcihkZXZEYXRhQmFzZSwgdHlwZSA9PSAibGF0ZXJhbCIpKSwgd2hpY2hNb2RlbHMgPSAid2l0aG1haW4iLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgIyBjb21wdXRlIEJheWVzIEZhY3RvcnMKYmZLYW5haUxhdGVyYWwgPSBzb3J0KGJmS2FuYWlMYXRlcmFsLCBkZWNyZWFzaW5nID0gVFJVRSkgIyBzb3J0IHN1Y2ggdGhhdCB3aW5uaW5nIG1vZGVsIGlzIGF0IHRoZSB0b3AKYGBgCgpgYGB7ciByZXN1bHRzPSdhc2lzJ30Ka2FibGUoc2VsZWN0KGV4dHJhY3RCRihiZkthbmFpTGF0ZXJhbCksIGJmKSkgIyBzaG93IG9ubHkgdGhlIEJheWVzIGZhY3RvcnMgaW4gYSB0YWJsZQpgYGAKClR3byBtb2RlbHMgZmFyZSBiZXR0ZXIgdGhhbiB0aGUgbnVsbCBtb2RlbDogKDEpIGEgbWFpbiBlZmZlY3Qgb2Ygc3RpbXVsYXRpb24sIGFuZCAoMikgYSBtYWluIGVmZmVjdCBvZiBib3RoIHN0aW11bGF0aW9uIGFuZCBkaXJlY3Rpb24uIAoKYGBge3IgSW5jbHVzaW9uIEJGIG1hdGNoZWQgbW9kZWxzIC0gbGF0ZXJhbCBzYWNjYWRlc30Ka2FibGUoaW5jbHVzaW9uQkYoYmZLYW5haUxhdGVyYWwsIG1vZGVscyA9ICJtYXRjaGVkIikpCmBgYAoKVGhlcmUgaXMgbW9kZXJhdGUgZXZpZGVuY2UgZm9yIGluY2x1c2lvbiBvZiBhbiBlZmZlY3Qgb2Ygc3RpbXVsYXRpb24sIGV2ZW4gdGhvdWdoIHRoZSBjbGFzc2ljYWwgYW5hbHlzaXMgZG9lcyBub3QgcmVhY2ggc2lnbmlmaWNhbmNlLgoKIyMjIyBMaW5lYXIgbWl4ZWQgZWZmZWN0cyBtYXRjaGluZyBLYW5haSAtIGNlbnRlciBzYWNjYWRlcwoKYGBge3IgQmF5ZXMgRmFjdG9yIEthbmFpIGNlbnRlcn0KYmZLYW5haUNlbnRlciA9IGFub3ZhQkYoZGV2aWF0aW9uLmVuZH5zdGltdWxhdGlvbipsZWcqZGlyZWN0aW9uK3N1YmplY3QsIGRhdGEgPSBkYXRhLmZyYW1lKGZpbHRlcihkZXZEYXRhQmFzZSwgdHlwZSA9PSAiY2VudGVyIikpLCB3aGljaE1vZGVscyA9ICJ3aXRobWFpbiIsIHdoaWNoUmFuZG9tID0gInN1YmplY3QiLCBwcm9ncmVzcyA9IEZBTFNFLCBpdGVyYXRpb25zID0gMTAwMDAwKSAjIGNvbXB1dGUgQmF5ZXMgRmFjdG9ycwpiZkthbmFpQ2VudGVyID0gc29ydChiZkthbmFpQ2VudGVyLCBkZWNyZWFzaW5nID0gVFJVRSkgIyBzb3J0IHN1Y2ggdGhhdCB3aW5uaW5nIG1vZGVsIGlzIGF0IHRoZSB0b3AKYGBgCgpgYGB7ciByZXN1bHRzPSdhc2lzJ30Ka2FibGUoc2VsZWN0KGV4dHJhY3RCRihiZkthbmFpQ2VudGVyKSwgYmYpKSAjIHNob3cgb25seSB0aGUgQmF5ZXMgZmFjdG9ycyBpbiBhIHRhYmxlCmBgYAoKQWxsIHRoZSBtb2RlbHMgd2l0aCBhIG1haW4gZWZmZWN0IG9mIHN0aW11bGF0aW9uIGFyZSBzdHJvbmdseSBzdXBwb3J0ZWQuCgpgYGB7ciBJbmNsdXNpb24gQkYgbWF0Y2hlZCBtb2RlbHMgLSBjZW50ZXIgc2FjY2FkZXN9CmthYmxlKGluY2x1c2lvbkJGKGJmS2FuYWlDZW50ZXIsIG1vZGVscyA9ICJtYXRjaGVkIikpCmBgYAoKT3ZlcndoZWxtaW5nIGV2aWRlbmNlIGZvciBpbmNsdXNpb24gb2YgYSBtYWluIGVmZmVjdCBvZiBzdGltdWxhdGlvbiwgd2hpY2ggaXMgaW4gYWNjb3JkIHdpdGggdGhlIGhpZ2hseSBzaWduaWZpY2FudCBwLXZhbHVlLgoKQmF5ZXNpYW4gb25lLXNhbXBsZSB0LXRlc3RzOgoKYGBge3IgQmF5ZXNpYW4gZm9sbG93LXVwIHRlc3QgLSBkZXZpYXRpb259CmRldkRhdGFCYXNlICU+JSAKICBmaWx0ZXIodHlwZSA9PSAiY2VudGVyIikgJT4lICMga2VlcCBvbmx5IGNlbnRlciBzYWNjYWRlcwogIGdyb3VwX2J5KHN0aW11bGF0aW9uLHN1YmplY3QpICU+JSAjIGZvciBlYWNoIHNlc3Npb24gYW5kIHN1YmplY3QKICBzdW1tYXJpc2UoZGV2aWF0aW9uLmVuZCA9IG1lYW4oZGV2aWF0aW9uLmVuZCkpICU+JSAjIGF2ZXJhZ2Ugb3ZlciBhbGwgb3RoZXIgdmFyaWFibGVzCiAgc3ByZWFkKHN0aW11bGF0aW9uLGRldmlhdGlvbi5lbmQpICU+JSAjIG1ha2Ugc2VwYXJhdGUgY29sdW1ucyB3aXRoIHRlc3QgZGF0YQogIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBmdW5zKGV4dHJhY3RCRih0dGVzdEJGKC4pLCBvbmx5YmYgPSBUUlVFKSkpICU+JSAjIHJ1biBCYXllc2lhbiB0LXRlc3Qgb24gZWFjaCBjb2x1bW4sIGtlZXBpbmcgb25seSB0aGUgQkYKICBnYXRoZXIoc3RpbXVsYXRpb24sQkYsYW5vZGFsLGNhdGhvZGFsKSAlPiUgIyBtYWtlIHJvdyBmb3IgZWFjaCBzdGltdWxhdGlvbiBjb25kaXRpb24KICBrYWJsZSguKQpgYGAKClRoZSBjYXRob2RhbCBlZmZlY3Qgb24gaXRzIG93bmhhcyBhIEJGfjEwfiA+IDEwLCBidXQgdGhlIGFub2RhbCBlZmZlY3QgZG9lcyBub3QuCgojIFNhY2NhZGUgZW5kIHBvaW50IHZhcmlhYmlsaXR5CgpJbiB0aGUgbW90b3IgbGl0ZXJhdHVyZSwgcGVvcGxlIG9mdGVuIGxvb2sgYXQgdGhlIHNwcmVhZCBpbiBtb3ZlbWVudCBlbmRwb2ludHMsIGFzIGl0J3Mgb2Z0ZW4gYmVsaWV2ZWQgdGhhdCB0aGlzIGlzIHdoYXQgdGhlIG1vdG9yIHN5c3RlbSBpcyB0cnlpbmcgdG8gb3B0aW1pemUgKGkuZS4gbWluaW1pemUpLiBbS2FuYWkgZXQgYWwuICgyMDEyKV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMzM4OS9mcHN5dC4yMDEyLjAwMDQ1KSBhbHNvIGV4YW1pbmVkIHRoaXMsIGJ1dCBmb3VuZCBubyBlZmZlY3RzIG9mIHREQ1MuCgojIyBDYWxjdWxhdGUgZW5kcG9pbnQgdmFyaWFiaWxpdHkKCkthbmFpIGV0IGFsLiAoMjAxMikgb3BlcmF0aW9uYWxpemVkIHZhcmlhYmlsaXR5IGFzIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHgtY29vcmRpbmF0ZSBvZiB0aGUgc2FjY2FkZSBlbmQgcG9pbnQuCgpgYGB7ciBIb3Jpem9udGFsIHN0YW5kYXJkIGRldmlhdGlvbn0Kc3RkRGF0YSA8LSBncm91cERhdGEgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzdGltdWxhdGlvbixsZWcsZGlyZWN0aW9uLHR5cGUpICU+JSAKICBzdW1tYXJpc2Uoc3RkLmRldmlhdGlvbi54ID0gc2QoZGV2aWF0aW9uLmVuZC54KSkKYGBgCgpUaGlzIGlzIGEgc3VtbWFyeSBtZWFzdXJlIGFjcm9zcyB0cmlhbHMsIHNvIHdlIGhhdmUgb25lIGVzdGltYXRlIHBlciBzdWJqZWN0IHBlciBjb25kaXRpb246CgpgYGB7ciByZXN1bHRzPSdhc2lzJ30Ka2FibGUoaGVhZChzdGREYXRhKSkKYGBgCgojIyBQcmVwYXJlIGRhdGEgZnJhbWUgZm9yIHBsb3R0aW5nICYgc3RhdGlzdGljcwoKYGBge3IgcmVjb2RlIGxlZyBmYWN0b3J9CnN0ZERhdGEkbGVnIDwtIGZjdF9yZWNvZGUoc3RkRGF0YSRsZWcsIGJhc2VsaW5lID0gInByZSIpICMgcmVjb2RlIGZhY3RvciB0byBtYXRjaCBkZXZpYXRpb24gZGF0YSBmcmFtZQpgYGAKClN1YnRyYWN0IHRoZSBiYXNlbGluZSBmcm9tIGVhY2ggYXZlcmFnZToKCmBgYHtyIFN1YnRyYWN0IGJhc2VsaW5lIC0gdmFyaWFiaWxpdHl9CgojIFN1YnRyYWN0IGJhc2VsaW5lCnN0ZERhdGFCYXNlIDwtIHN0ZERhdGEgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzdGltdWxhdGlvbixkaXJlY3Rpb24sdHlwZSkgJT4lIAogICMgc3VidHJhY3QgYmFzZWxpbmUgYmxvY2sgZnJvbSBvdGhlcnMsIG1ha2UgbmV3IGNvbHVtbgogIHN1bW1hcmlzZSh0RENTID0gc3RkLmRldmlhdGlvbi54W2xlZyA9PSAidERDUyJdIC0gc3RkLmRldmlhdGlvbi54W2xlZyA9PSAiYmFzZWxpbmUiXSwgCiAgICAgICAgICAgIHBvc3QuMSA9IHN0ZC5kZXZpYXRpb24ueFtsZWcgPT0gInBvc3QuMSJdIC0gc3RkLmRldmlhdGlvbi54W2xlZyA9PSAiYmFzZWxpbmUiXSwKICAgICAgICAgICAgcG9zdC4yID0gc3RkLmRldmlhdGlvbi54W2xlZyA9PSAicG9zdC4yIl0gLSBzdGQuZGV2aWF0aW9uLnhbbGVnID09ICJiYXNlbGluZSJdKSAlPiUKZ2F0aGVyKGxlZywgc3RkLmRldmlhdGlvbi54LCB0RENTLCBwb3N0LjEsIHBvc3QuMikgJT4lICMgZ2F0aGVyIG5ldyBjb2x1bW5zIHRvIHVzZSBhcyBmYWN0b3IgCm11dGF0ZShsZWcgPSBmYWN0b3IobGVnLCBsZXZlbHMgPSBjKCJ0RENTIiwgInBvc3QuMSIsICJwb3N0LjIiKSkpICMgcmVvcmRlciBmYWN0b3IgbGV2ZWxzCmBgYAoKIyMgUGxvdAoKIyMjIFdpdGggYmFzZWxpbmUgYmxvY2sKCmBgYHtyIExpbmUgcGxvdCBwZXIgbGVnIC0gdmFyaWFiaWxpdHl9CmthbmFpUGxvdFN0ZCA8LSBnZ3Bsb3Qoc3RkRGF0YSwgYWVzKGxlZywgc3RkLmRldmlhdGlvbi54LCBjb2xvciA9IHN0aW11bGF0aW9uLCBzaGFwZSA9IHN0aW11bGF0aW9uKSkgKyAgICAgICAgIAogIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiLCBzaXplID0gMykgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAibGluZSIsIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSwgc2l6ZSA9IDEpICsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX2NsX25vcm1hbCwgZ2VvbSA9ICJlcnJvcmJhciIsIHdpZHRoID0gMC4zKSArCiAgZ2d0aXRsZSgiSG9yaXpvbnRhbCBzdGFuZGFyZCBkZXZpYXRpb24iKQprYW5haVBsb3RTdGQKYGBgCgpUaGUgY2hhbmdlcyBoZXJlIHNlZW0gbGVzcyBwcm9ub3VuY2VkIHRoYW4gaW4gdGhlIGVuZHBvaW50IGRldmlhdGlvbiBkYXRhLgoKTGV0J3MgbG9vayBhdCB0aGUgaW5kaXZpZHVhbCBzdWJqZWN0IGRhdGE6CgpgYGB7ciBMaW5lIHBsb3QgcGVyIHN1YmplY3QgLSB2YXJpYWJpbGl0eSBhbm9kYWx9CmthbmFpUGxvdFN1YnNBbm9kYWwgPC0gZ2dwbG90KHN0ZERhdGFbc3RkRGF0YSRzdGltdWxhdGlvbiA9PSAiYW5vZGFsIiwgXSwgYWVzKGxlZywgc3RkLmRldmlhdGlvbi54KSkgKwogIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzdWJqZWN0LGNvbG9yID0gc3ViamVjdCkpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBzdGltdWxhdGlvbiksIGdlb20gPSAibGluZSIpICsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tID0gInBvaW50IikgKwogIGdndGl0bGUoIkFub2RhbCBzZXNzaW9uIikKa2FuYWlQbG90U3Vic0Fub2RhbApgYGAKCmBgYHtyIExpbmUgcGxvdCBwZXIgc3ViamVjdCAtIHZhcmlhYmlsaXR5IGNhdGhvZGFsfQprYW5haVBsb3RTdWJzQ2F0aG9kYWwgPC0gZ2dwbG90KHN0ZERhdGFbc3RkRGF0YSRzdGltdWxhdGlvbiA9PSAiY2F0aG9kYWwiLCBdLCBhZXMobGVnLCBzdGQuZGV2aWF0aW9uLngpKSArCiAgZmFjZXRfZ3JpZCh0eXBlIH4gZGlyZWN0aW9uKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHN1YmplY3QsY29sb3IgPSBzdWJqZWN0KSkgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhncm91cCA9IHN0aW11bGF0aW9uKSwgZ2VvbSA9ICJsaW5lIikgKwogIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb20gPSAicG9pbnQiKSArCiAgZ2d0aXRsZSgiQ2F0aG9kYWwgc2Vzc2lvbiIpCmthbmFpUGxvdFN1YnNDYXRob2RhbApgYGAKClRoaXMgbWVhc3VyZSBzZWVtcyBwYXJ0aWN1bGFybHkgdmFyaWFibGUgYWNyb3NzIHN1YmplY3RzIGFuZCBhbHNvIHN1YmplY3QgdG8gcXVpdGUgYSBmZXcgc3Bpa2VzIHRoYXQgb25seSBzaG93IHVwIGluIGEgZmV3IGNvbmRpdGlvbnMuCgojIyMjIEJhc2VsaW5lIHJlbGlhYmlsaXR5CgpTY2F0dGVycGxvdCBhbmQgY29ycmVsYXRpb24gb2YgYmFzZWxpbmUgZGF0YSBpbiB0aGUgdHdvIHNlc3Npb25zOgoKYGBge3IgYmFzZWxpbmUgY29ycmVsYXRpb25zIC0gdmFyaWFiaWxpdHl9CmJhc2VsaW5lQ29yclN0ZCA8LSBzdGREYXRhICU+JQogIGZpbHRlcihsZWcgPT0gImJhc2VsaW5lIikgJT4lIAogIGdyb3VwX2J5KGRpcmVjdGlvbix0eXBlKSAlPiUgCiAgc3ByZWFkKHN0aW11bGF0aW9uLHN0ZC5kZXZpYXRpb24ueCkgJT4lIAogIG5lc3QoKSAlPiUgCiAgbXV0YXRlKHN0YXRzID0gbWFwKGRhdGEsIH5jb3IudGVzdChmb3JtdWxhID0gfiBhbm9kYWwgKyBjYXRob2RhbCwgZGF0YSA9LikpKSAlPiUgIyBydW4gY29ycmVsYXRpb24gdGVzdCBvbiBiYXNlbGluZXMgZnJvbSBlYWNoIGNvbmRpdGlvbgogIG11dGF0ZSh0aWR5X21vZGVsID0gbWFwKHN0YXRzLCB0aWR5KSkgJT4lIAogIHVubmVzdCh0aWR5X21vZGVsLCAuZHJvcCA9IFRSVUUpCmBgYAoKYGBge3IgYmFzZWxpbmUgc2NhdHRlcnBsb3RzIC0gdmFyaWFiaWxpdHl9CnN0ZERhdGEgJT4lCiAgZmlsdGVyKGxlZyA9PSAiYmFzZWxpbmUiKSAlPiUKICBzcHJlYWQoc3RpbXVsYXRpb24sc3RkLmRldmlhdGlvbi54KSAlPiUKICBpbm5lcl9qb2luKC4sIHN1YmplY3REYXRhWyAsYygic3ViamVjdCIsInNlc3Npb24ub3JkZXIiKV0sIGJ5ID0gYygic3ViamVjdCIpKSAlPiUgIyBhZGQgY29sdW1uIG9uIHNlc3Npb24gb3JkZXIgZnJvbSBvdGhlciBkYXRhIGZyYW1lCiAgZ2dwbG90KGFlcyhhbm9kYWwsY2F0aG9kYWwpKSArCiAgICBmYWNldF9ncmlkKHR5cGUgfiBkaXJlY3Rpb24pICsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKwogICAgZ2VvbV9wb2ludChhZXMoY29sb3I9c2Vzc2lvbi5vcmRlcikpICsKICAgIHhsaW0oMC4yLDEuNikgKyB5bGltKDAuMiwxLjYpICsKICAgIGdlb21fdGV4dChkYXRhID0gYmFzZWxpbmVDb3JyU3RkLCB4ID0gMC41LCB5ID0gMS41LCBhZXMobGFiZWwgPSBwYXN0ZSgiaXRhbGljKHIpID09ICIsIHJvdW5kKGVzdGltYXRlLDIpKSksIHBhcnNlID0gVFJVRSkgKwogICAgbGFicyh0aXRsZSA9ICJCYXNlbGluZSBpbiBhbm9kYWwgYW5kIGNhdGhvZGFsIHNlc3Npb25zIiwgc3VidGl0bGUgPSAic2NhdHRlcnBsb3Qgb2YgYmFzZWxpbmUgZW5kcG9pbnQgdmFyaWFiaWxpdHkiKQpgYGAKClRoZSBjb3JyZWxhdGlvbnMgZm9yIHRoaXMgbWVhc3VyZSBhcmUgcXVpdGUgbG93LCBlc3BlY2lhbGx5IGZvciB0aGUgY2VudGVyIGNvbmRpdGlvbnMuIEFwcGFyZW50bHkgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBzYWNjYWRlIGVuZHBvaW50cyBpcyBub3Qgc28gcmVsaWFibGUuCgojIyMjIEJhc2VsaW5lIGRpZmZlcmVuY2VzCgpgYGB7ciBiYXNlbGluZSBkaWZmZXJlbmNlIHN0cmlwY2hhcnQgLSB2YXJpYWJpbGl0eX0Kc3RkRGF0YSAlPiUKICBmaWx0ZXIobGVnID09ICJiYXNlbGluZSIpICU+JQogIGlubmVyX2pvaW4oLiwgc3ViamVjdERhdGFbICxjKCJzdWJqZWN0Iiwic2Vzc2lvbi5vcmRlciIpXSwgYnkgPSBjKCJzdWJqZWN0IikpICU+JSAjIGFkZCBjb2x1bW4gb24gc2Vzc2lvbiBvcmRlciBmcm9tIG90aGVyIGRhdGEgZnJhbWUKICBncm91cF9ieShzdWJqZWN0LGRpcmVjdGlvbix0eXBlLHNlc3Npb24ub3JkZXIpICU+JQogIHN1bW1hcmlzZShzdGQuZGV2aWF0aW9uLnguZGlmZiA9IHN0ZC5kZXZpYXRpb24ueFtzdGltdWxhdGlvbiA9PSAiYW5vZGFsIl0gLSBzdGQuZGV2aWF0aW9uLnhbc3RpbXVsYXRpb24gPT0gImNhdGhvZGFsIl0pICU+JQogIGdncGxvdChhZXMoZmFjdG9yKDApLCBzdGQuZGV2aWF0aW9uLnguZGlmZikpICsKICAgIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogICAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ub3JtYWwpICsKICAgIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhsYWJlbD1yb3VuZCguLnkuLiwgZGlnaXRzPTIpLCB4ID0gMS4zKSwgZ2VvbSA9ICJsYWJlbCIsIGFscGhhID0gMC41KSArCiAgICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIGFlcyhjb2xvdXIgPSBzZXNzaW9uLm9yZGVyKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGg9LjEpKSArCiAgICBsYWJzKHRpdGxlID0gIkJhc2VsaW5lIGluIGFub2RhbCBhbmQgY2F0aG9kYWwgc2Vzc2lvbnMiLCBzdWJ0aXRsZSA9ICJhbm9kYWwgLSBjYXRob2RhbCIpCmBgYAoKVGhlIGF2ZXJhZ2UgYmFzZWxpbmUgZGlmZmVyZW5jZXMgYXJlIHNtYWxsLCBidXQgdGhlIHNwcmVhZCBpcyBxdWl0ZSBsYXJnZS4KCmBgYHtyIHQtdGVzdHMgb2YgYmFzZWxpbmUgZGlmZmVyZW5jZSAtIHZhcmlhYmlsaXR5fQpzdGREYXRhICU+JQogIGZpbHRlcihsZWcgPT0gImJhc2VsaW5lIikgJT4lCiAgZ3JvdXBfYnkoZGlyZWN0aW9uLHR5cGUpICU+JSAKICBuZXN0KCkgJT4lIAogIG11dGF0ZShzdGF0cyA9IG1hcChkYXRhLCB+dC50ZXN0KGZvcm11bGEgPSBzdGQuZGV2aWF0aW9uLnh+c3RpbXVsYXRpb24sIHBhaXJlZCA9IFRSVUUsIGRhdGEgPS4pKSkgJT4lICMgcnVuIHQtdGVzdCBvbiB0aGUgZGF0YSBmcmFtZXMKICBtdXRhdGUodGlkeV9tb2RlbCA9IG1hcChzdGF0cywgdGlkeSkpICU+JQogIHVubmVzdCh0aWR5X21vZGVsLCAuZHJvcCA9IFRSVUUpICU+JSAKICBrYWJsZSguKQpgYGAKCk9uIGF2ZXJhZ2Ugbm9uZSBvZiB0aGUgYmFzZWxpbmVzIGRpZmZlciBzaWduaWZpY2FudGx5IGZyb20gZWFjaCBvdGhlci4KCiMjIyBCYXNlbGluZSBzdWJ0cmFjdGVkCgpgYGB7ciBMaW5lIHBsb3QgZnJvbSBiYXNlbGluZSAtIHN0YW5kYXJkIGRldmlhdGlvbn0Ka2FuYWlQbG90U3RkQmFzZSA8LSBnZ3Bsb3Qoc3RkRGF0YUJhc2UsIGFlcyhsZWcsIHN0ZC5kZXZpYXRpb24ueCwgY29sb3IgPSBzdGltdWxhdGlvbiwgc2hhcGUgPSBzdGltdWxhdGlvbikpICsgICAgICAgICAKICBmYWNldF9ncmlkKHR5cGUgfiBkaXJlY3Rpb24pICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJwb2ludCIsIHNpemUgPSAzKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbSA9ICJsaW5lIiwgYWVzKGdyb3VwID0gc3RpbXVsYXRpb24pLCBzaXplID0gMSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fY2xfbm9ybWFsLCBnZW9tID0gImVycm9yYmFyIiwgd2lkdGggPSAwLjMpCmthbmFpUGxvdFN0ZEJhc2UKYGBgCgpIZXJlIHRoZSBjaGFuZ2VzIGFyZSBldmVuIHRpbmllciB0aGFuIHRoZSBlbmRwb2ludCBkZXZpYXRpb24gZGF0YSAoPC4xIGRlZ3JlZSkuIElmIGFueXRoaW5nLCB0aGUgZGlmZmVyZW5jZXMgc2VlbSB0byBncm93IG1vcmUgcHJvbm91bmNlZCBhZnRlciB0RENTLgoKIyMgU3RhdGlzdGljcwoKYGBge3IgUHJlcGFyZSBkYXRhIGZyYW1lcyAtIHZhcmlhYmlsaXR5fQojIE1ha2UgInN1YmplY3QiIGEgZmFjdG9yLCBzbyB3ZSBjYW4gbW9kZWwgdGhlIHJlcGVhdGVkIG1lYXN1cmVzCnN0ZERhdGFCYXNlIDwtIHN0ZERhdGFCYXNlICU+JQogIHVuZ3JvdXAoKSAlPiUgIyByZW1vdmUgYW55IGdyb3VwaW5nIGluZm8sIGJlY2F1c2Ugd2UgbmVlZCB0byByZWZhY3RvcgogIGlubmVyX2pvaW4oLiwgc3ViamVjdERhdGFbICxjKCJzdWJqZWN0Iiwic2Vzc2lvbi5vcmRlciIpXSwgYnkgPSBjKCJzdWJqZWN0IikpICU+JSAjIGFkZCBjb2x1bW4gb24gc2Vzc2lvbiBvcmRlciBmcm9tIG90aGVyIGRhdGEgZnJhbWUKICBtdXRhdGUoc3ViamVjdCA9IGZhY3RvcihzdWJqZWN0KSkgIyByZWZhY3RvcgpgYGAKCiMjIyBGcmVxdWVudGlzdAoKIyMjIyBBTk9WQSBtYXRjaGluZyBLYW5haSBldCBhbC4gKDIwMTIpIC0gbGF0ZXJhbCBzYWNjYWRlcyB7LnRhYnNldCAudGFic2V0LWZhZGV9CgojIyMjIyBXaXRob3V0IHNlc3Npb24gb3JkZXIKCl9fRGF0YV9fOiAKCiogT3V0bGllcnMgcmVtb3ZlZAoqIENvbGxhcHNlZCBpbnRvIDE1LW1pbnV0ZSBpbnRlcnZhbHMKKiBTdWJ0cmFjdCB0aGUgYmFzZWxpbmUgZnJvbSBlYWNoIHN1YnNlcXVlbnQgYmxvY2sKKiBEaXNjYXJkIGNlbnRlciwga2VlcCBvbmx5IGxhdGVyYWwgc2FjY2FkZXMKCl9fRGVwZW5kZW50IG1lYXN1cmVfXzogc2FjY2FkZSBlbmQgcG9pbnQgdmFyaWFiaWxpdHkgKGhvcml6b250YWwgc3RhbmRhcmQgZGV2aWF0aW9uKQoKX19GYWN0b3JzX186CgoqIFNUSU1VTEFUSU9OIChhbm9kYWwgdnMuIGNhdGhvZGFsKQoqIExFRyAodERDUywgcG9zdC4xLCBwb3N0LjIpCiogRElSRUNUSU9OIChsZWZ0IHZzLiByaWdodCkKCmBgYHtyIEthbmFpIEFOT1ZBIHZhcmlhYmlsaXR5IGxhdGVyYWwsIHJlc3VsdHM9J2FzaXMnfQptb2RlbEthbmFpU3RkIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUoZmlsdGVyKHN0ZERhdGFCYXNlLCB0eXBlID09ICJsYXRlcmFsIikpLAogICAgICAgICAgICAgICAgICAgICAgICBkdiA9IC4oc3RkLmRldmlhdGlvbi54KSwgd2lkID0gLihzdWJqZWN0KSwgd2l0aGluID0gLihzdGltdWxhdGlvbixsZWcsZGlyZWN0aW9uKSwgdHlwZSA9IDMpCgprYWJsZShtb2RlbEthbmFpU3RkJEFOT1ZBKQprYWJsZShtb2RlbEthbmFpU3RkJGBNYXVjaGx5J3MgVGVzdCBmb3IgU3BoZXJpY2l0eWApCmthYmxlKG1vZGVsS2FuYWlTdGQkYFNwaGVyaWNpdHkgQ29ycmVjdGlvbnNgKQpgYGAKCiMjIyMjIFdpdGggc2Vzc2lvbiBvcmRlcgoKYGBge3IgS2FuYWkgQU5PVkEgbGF0ZXJhbCB2YXJpYWJpbGl0eSBzZXNzaW9uIG9yZGVyLCByZXN1bHRzPSdhc2lzJ30KbW9kZWxLYW5haVN0ZE9yZGVyIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUoZmlsdGVyKHN0ZERhdGFCYXNlLCB0eXBlID09ICJsYXRlcmFsIikpLCBkdiA9IC4oc3RkLmRldmlhdGlvbi54KSwgCiAgICAgICAgICB3aWQgPSAuKHN1YmplY3QpLCB3aXRoaW4gPSAuKHN0aW11bGF0aW9uLGxlZyxkaXJlY3Rpb24pLCAgYmV0d2VlbiA9IHNlc3Npb24ub3JkZXIsIHR5cGUgPSAzKQprYWJsZShtb2RlbEthbmFpU3RkT3JkZXIkQU5PVkEpCmthYmxlKG1vZGVsS2FuYWlTdGRPcmRlciRgTWF1Y2hseSdzIFRlc3QgZm9yIFNwaGVyaWNpdHlgKQprYWJsZShtb2RlbEthbmFpU3RkT3JkZXIkYFNwaGVyaWNpdHkgQ29ycmVjdGlvbnNgKQpgYGAKClRoZSBpbnRlcmFjdGlvbiB3aXRoIHNlc3Npb24gb3JkZXIsIHN0aW11bGF0aW9uLCBhbmQgZGlyZWN0aW9uIGlzIHNpZ25pZmljYW50LiBIb3dldmVyLCB0aGUgc3RpbXVsYXRpb246ZGlyZWN0aW9uIGludGVyYWN0aW9uIHdhcyBub3Qgc2lnbmlmaWNhbnQgaW4gdGhlIEFOT1ZBIHdpdGhvdXQgdGhlIHNlc3Npb24gb3JkZXIgZmFjdG9yLCBzbyB3ZSBzaG91bGQgaW50ZXJwcmV0IHRoaXMgd2l0aCBjYXV0aW9uLiBJbiBhZGRpdGlvbiwgYW4gaW50ZXJhY3Rpb24gb2Ygc2Vzc2lvbiBvcmRlciBhbmQgc3RpbXVsYXRpb24gY291bGQganVzdCBhcyB3ZWxsIHJlZmxlY3QgYSBtYWluIGVmZmVjdCBvZiBzZXNzaW9uICgxIHZzLiAyKTogdGhlcmUncyBubyB3YXkgdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiB0aGVzZSBwb3NzaWJpbGl0aWVzLgoKIyMjIyBBTk9WQSBtYXRjaGluZyBLYW5haSBldCBhbC4gKDIwMTIpIC0gY2VudGVyIHNhY2NhZGVzIHsudGFic2V0IC50YWJzZXQtZmFkZX0KCiMjIyMjIFdpdGhvdXQgc2Vzc2lvbiBvcmRlcgoKYGBge3IgS2FuYWkgQU5PVkEgY2VudGVyIHZhcmlhYmlsaXR5LCByZXN1bHRzPSdhc2lzJ30KCm1vZGVsS2FuYWlTdGRDZW50ZXIgPC0gZXpBTk9WQShkYXRhID0gZGF0YS5mcmFtZShmaWx0ZXIoc3RkRGF0YUJhc2UsIHR5cGUgPT0gImNlbnRlciIpKSwKICAgICAgICAgICAgICAgICAgICAgICAgZHYgPSAuKHN0ZC5kZXZpYXRpb24ueCksIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sbGVnLGRpcmVjdGlvbiksIHR5cGUgPSAzKQoKa2FibGUobW9kZWxLYW5haVN0ZENlbnRlciRBTk9WQSkKa2FibGUobW9kZWxLYW5haVN0ZENlbnRlciRgTWF1Y2hseSdzIFRlc3QgZm9yIFNwaGVyaWNpdHlgKQprYWJsZShtb2RlbEthbmFpU3RkQ2VudGVyJGBTcGhlcmljaXR5IENvcnJlY3Rpb25zYCkKYGBgCgojIyMjIyBNYWluIGVmZmVjdCBvZiBzdGltdWxhdGlvbgoKVGhpcyBlZmZlY3QgaXMganVzdCBub24tc2lnbmlmaWNhbnQsIGJ1dCBsZXQncyBpbnNwZWN0IGFueXdheToKCmBgYHtyIEthbmFpLUNlbnRlci12YXJpYWJpbGl0eSBNYWluIGVmZmVjdCBvZiBzdGltdWxhdGlvbn0Kc3RkRGF0YUJhc2UgJT4lCiAgZmlsdGVyKHR5cGUgPT0gImNlbnRlciIpICU+JQogIGdyb3VwX2J5KHN1YmplY3Qsc3RpbXVsYXRpb24pICU+JQogIHN1bW1hcmlzZShzdGQuZGV2aWF0aW9uLnggPSBtZWFuKHN0ZC5kZXZpYXRpb24ueCkpICU+JQogIGdncGxvdChhZXMoc3RpbXVsYXRpb24sIHN0ZC5kZXZpYXRpb24ueCkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9jbF9ub3JtYWwsIHNpemUgPSAxKSArCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjI1KQpgYGAKClRoaXMgcmVzZW1ibGVzIHRoZSBkaWZmZXJlbmNlIGZvdW5kIGZvciB0aGUgc2FjY2FkZSBlbmRwb2ludCBkZXZpYXRpb24sIGV4Y2VwdCBoZXJlIHRoZSBsYXJnZXIgYW5kIG1vcmUgY29uc2lzdGVudCBlZmZlY3Qgc2VlbXMgdG8gYmUgaW4gdGhlIGFub2RhbCBjb25kaXRpb24uCgojIyMjIyBXaXRoIHNlc3Npb24gb3JkZXIKCmBgYHtyIEthbmFpIEFOT1ZBIGNlbnRlciB2YXJpYWJpbGl0eSBzZXNzaW9uIG9yZGVyLCByZXN1bHRzPSdhc2lzJ30KbW9kZWxLYW5haVN0ZENlbnRlck9yZGVyIDwtIGV6QU5PVkEoZGF0YSA9IGRhdGEuZnJhbWUoZmlsdGVyKHN0ZERhdGFCYXNlLCB0eXBlID09ICJjZW50ZXIiKSksIGR2ID0gLihzdGQuZGV2aWF0aW9uLngpLCAKICAgICAgICAgIHdpZCA9IC4oc3ViamVjdCksIHdpdGhpbiA9IC4oc3RpbXVsYXRpb24sbGVnLGRpcmVjdGlvbiksICBiZXR3ZWVuID0gc2Vzc2lvbi5vcmRlciwgdHlwZSA9IDMpCmthYmxlKG1vZGVsS2FuYWlTdGRDZW50ZXJPcmRlciRBTk9WQSkKa2FibGUobW9kZWxLYW5haVN0ZENlbnRlck9yZGVyJGBNYXVjaGx5J3MgVGVzdCBmb3IgU3BoZXJpY2l0eWApCmthYmxlKG1vZGVsS2FuYWlTdGRDZW50ZXJPcmRlciRgU3BoZXJpY2l0eSBDb3JyZWN0aW9uc2ApCmBgYAoKSGVyZSB0aGUgZWZmZWN0IGRvZXMganVzdCByZWFjaCBzaWduaWZpY2FuY2UsIGJ1dCB0aGVyZSdzIG5vIGludGVyYWN0aW9uIHdpdGggc2Vzc2lvbiBvcmRlci4KCiMjIyBCYXllc2lhbgoKQmF5ZXNpYW4gYW5hbG9ndWVzIG9mIHRoZSBmcmVxdWVudGlzdCByZXBlYXRlZCBtZWFzdXJlcyBBTk9WQXMgKHdpdGhvdXQgb3JkZXIgZWZmZWN0KSwgd2l0aCB0aGUgc2FtZSBmYWN0b3JzLgoKIyMjIyBMaW5lYXIgbWl4ZWQgZWZmZWN0cyBtYXRjaGluZyBLYW5haSAtIGxhdGVyYWwgc2FjY2FkZXMKCmBgYHtyIEJheWVzIEZhY3RvcnMgS2FuYWkgdmFyaWFiaWxpdHkgbGF0ZXJhbH0KYmZLYW5haVN0ZCA9IGFub3ZhQkYoc3RkLmRldmlhdGlvbi54fnN0aW11bGF0aW9uKmxlZypkaXJlY3Rpb24rc3ViamVjdCwgZGF0YSA9IGRhdGEuZnJhbWUoZmlsdGVyKHN0ZERhdGFCYXNlLCB0eXBlID09ICJsYXRlcmFsIikpLCB3aGljaE1vZGVscyA9ICJ3aXRobWFpbiIsIHdoaWNoUmFuZG9tID0gInN1YmplY3QiLCBwcm9ncmVzcyA9IEZBTFNFLCBpdGVyYXRpb25zID0gMTAwMDAwKSAjIGNvbXB1dGUgQmF5ZXMgRmFjdG9ycwpiZkthbmFpU3RkID0gc29ydChiZkthbmFpU3RkLCBkZWNyZWFzaW5nID0gVFJVRSkgIyBzb3J0IHN1Y2ggdGhhdCB3aW5uaW5nIG1vZGVsIGlzIGF0IHRoZSB0b3AKYGBgCgpgYGB7ciByZXN1bHRzPSdhc2lzJ30Ka2FibGUoc2VsZWN0KGV4dHJhY3RCRihiZkthbmFpU3RkKSwgYmYpKSAjIHNob3cgb25seSB0aGUgQmF5ZXMgZmFjdG9ycyBpbiBhIHRhYmxlCmBgYAoKYGBge3IgSW5jbHVzaW9uIEJGIG1hdGNoZWQgbW9kZWxzIC0gdmFyaWFiaWxpdHkgbGF0ZXJhbCBzYWNjYWRlc30KIyBJbmNsdXNpb24gQmF5ZXMgRmFjdG9ycwprYWJsZShpbmNsdXNpb25CRihiZkthbmFpU3RkLCBtb2RlbHMgPSAibWF0Y2hlZCIpKQpgYGAKCkFjcm9zcyB0aGUgYm9hcmQsIHRoZXJlIGlzIG9ubHkgbWFyZ2luYWwgc3VwcG9ydCBmb3IgYW4gZWZmZWN0IG9mIHN0aW11bGF0aW9uLiBGb3IgdGhlIGludGVyYWN0aW9uIGJldHdlZW4gc3RpbXVsYXRpb24gYW5kIGRpcmVjdGlvbiwgdGhlIEJGIGFwcHJvYWNoZXMgbW9kZXJhdGUgZXZpZGVuY2UgZm9yIHRoZSBudWxsLiAKCiMjIyMgTGluZWFyIG1peGVkIGVmZmVjdHMgbWF0Y2hpbmcgS2FuYWkgLSBjZW50ZXIgc2FjY2FkZXMKCmBgYHtyIEJheWVzIEZhY3RvcnMgS2FuYWkgdmFyaWFiaWxpdHkgY2VudGVyfQpiZkthbmFpU3RkQ2VudGVyID0gYW5vdmFCRihzdGQuZGV2aWF0aW9uLnh+c3RpbXVsYXRpb24qbGVnKmRpcmVjdGlvbitzdWJqZWN0LCBkYXRhID0gZGF0YS5mcmFtZShmaWx0ZXIoc3RkRGF0YUJhc2UsIHR5cGUgPT0gImNlbnRlciIpKSwgd2hpY2hNb2RlbHMgPSAid2l0aG1haW4iLCB3aGljaFJhbmRvbSA9ICJzdWJqZWN0IiwgcHJvZ3Jlc3MgPSBGQUxTRSwgaXRlcmF0aW9ucyA9IDEwMDAwMCkgIyBjb21wdXRlIEJheWVzIEZhY3RvcnMKYmZLYW5haVN0ZENlbnRlciA9IHNvcnQoYmZLYW5haVN0ZENlbnRlciwgZGVjcmVhc2luZyA9IFRSVUUpICMgc29ydCBzdWNoIHRoYXQgd2lubmluZyBtb2RlbCBpcyBhdCB0aGUgdG9wCmBgYAoKYGBge3IgcmVzdWx0cz0nYXNpcyd9CmthYmxlKHNlbGVjdChleHRyYWN0QkYoYmZLYW5haVN0ZENlbnRlciksIGJmKSkgIyBzaG93IG9ubHkgdGhlIEJheWVzIGZhY3RvcnMgaW4gYSB0YWJsZQpgYGAKCkxpa2UgZm9yIHRoZSBzYWNjYWRlIGVuZHBvaW50IGRldmlhdGlvbiBkYXRhLCBtb2RlbHMgd2l0aCBzdGltdWxhdGlvbiBhcyBhIGZhY3RvciByZWNlaXZlIHNvbWUgc3VwcG9ydCwgYWx0aG91Z2ggdG8gYSBsZXNzIHN0cm9uZyBkZWdyZWUuIEluIGNvbnRyYXN0IHRvIGVuZHBvaW50IGRldmlhdGlvbiB0aG91Z2gsIGhlcmUgdGhlIGNsYXNzaWNhbCBhbmFseXNpcyB3YXMgKGJhcmVseSkgbm9uLXNpZ25pZmljYW50LCBzbyB0aGVyZSBpcyBhIGRpc2NyZXBhbmN5IGJldHdlZW4gdGhlIEJheWVzaWFuIGFuZCBGcmVxdWVudGlzdCBhcHByb2FjaGVzLgoKYGBge3IgSW5jbHVzaW9uIEJGIG1hdGNoZWQgbW9kZWxzIC0gdmFyaWFiaWxpdHkgY2VudGVyIHNhY2NhZGVzfQojIEluY2x1c2lvbiBCYXllcyBGYWN0b3JzCmthYmxlKGluY2x1c2lvbkJGKGJmS2FuYWlTdGRDZW50ZXIsIG1vZGVscyA9ICJtYXRjaGVkIikpCmBgYAoKQWdhaW4sIGVzcGVjaWFsbHkgY29uc2lkZXJpbmcgdGhlIG5vbi1zaWduaWZpY2FudCBwLXZhbHVlLCB0aGUgc3VwcG9ydCBpcyBxdWl0ZSBzdHJvbmcuCgpMZXQncyBkbyBzb21lIGZvbGxvdy11cCB0ZXN0cyB0byBzZWUgd2hldGhlciB0aGUgYW5vZGFsIG9yIGNhdGhvZGFsIGNoYW5nZSBzY29yZXMgYXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gMCBvbiB0aGVpciBvd24uCgpCYXllc2lhbiBvbmUtc2FtcGxlIHQtdGVzdHM6CgpgYGB7ciBCYXllc2lhbiBmb2xsb3ctdXAgdGVzdCAtIHZhcmlhYmlsaXR5fQpzdGREYXRhQmFzZSAlPiUKICBmaWx0ZXIodHlwZSA9PSAiY2VudGVyIikgJT4lICMga2VlcCBvbmx5IGNlbnRlciBzYWNjYWRlcwogIGdyb3VwX2J5KHN0aW11bGF0aW9uLHN1YmplY3QpICU+JSAjIGZvciBlYWNoIHNlc3Npb24gYW5kIHN1YmplY3QKICBzdW1tYXJpc2UoZGV2aWF0aW9uLmVuZCA9IG1lYW4oc3RkLmRldmlhdGlvbi54KSkgJT4lICMgYXZlcmFnZSBvdmVyIGFsbCBvdGhlciB2YXJpYWJsZXMKICBzcHJlYWQoc3RpbXVsYXRpb24sZGV2aWF0aW9uLmVuZCkgJT4lICMgbWFrZSBzZXBhcmF0ZSBjb2x1bW5zIHdpdGggdGVzdCBkYXRhCiAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIGZ1bnMoZXh0cmFjdEJGKHR0ZXN0QkYoLiksIG9ubHliZiA9IFRSVUUpKSkgJT4lICMgcnVuIEJheWVzaWFuIHQtdGVzdCBvbiBlYWNoIGNvbHVtbiwga2VlcGluZyBvbmx5IHRoZSBCRgogIGdhdGhlcihzdGltdWxhdGlvbixCRixhbm9kYWwsY2F0aG9kYWwpICU+JSAjIG1ha2Ugcm93IGZvciBlYWNoIHN0aW11bGF0aW9uIGNvbmRpdGlvbgogIGthYmxlKC4pCmBgYAoKRnJlcXVlbnRpc3Qgb25lLXNhbXBsZSB0LXRlc3RzOgoKYGBge3IgQ2xhc3NpY2FsIGZvbGxvdy11cCB0ZXN0IC0gdmFyaWFiaWxpdHl9CnN0ZERhdGFCYXNlICU+JQogIGZpbHRlcih0eXBlID09ICJjZW50ZXIiKSAlPiUgIyBrZWVwIG9ubHkgY2VudGVyIHNhY2NhZGVzCiAgZ3JvdXBfYnkoc3RpbXVsYXRpb24sc3ViamVjdCkgJT4lICMgZm9yIGVhY2ggc2Vzc2lvbiBhbmQgc3ViamVjdAogIHN1bW1hcmlzZShkZXZpYXRpb24uZW5kID0gbWVhbihzdGQuZGV2aWF0aW9uLngpKSAlPiUgIyBhdmVyYWdlIG92ZXIgYWxsIG90aGVyIHZhcmlhYmxlcyAoZGYgaXMgbm93IHN0aWxsIGdyb3VwZWQgcGVyIHN0aW11bGF0aW9uKQogIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBmdW5zKGxpc3QodGlkeSh0LnRlc3QoLikpKSkpICU+JSAgIyBydW4gb25lLXNhbXBsZSB0LXRlc3QgZm9yIGVhY2ggc3RpbXVsYXRpb24gY29uZGl0aW9uLCByZXR1cm4gdGlkeSBkYXRhIGZyYW1lcwogIHVubmVzdCgpICU+JSAjIHVucGFjayB0aGUgbGlzdC1jb2x1bW4gd2l0aCBkYXRhIGZyYW1lIGZvciBlYWNoIHRlc3QKICBrYWJsZSguKSAKYGBgCgpTbyBuZWl0aGVyIGVmZmVjdCBob2xkcyB1cCBvbiB0aGVpciBvd24u