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"))
))
kable(head(groupData))
subject stimulation leg block trial type direction deviation.start deviation.end.x deviation.end.y amplitude latency drift.x drift.y
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

Subject metadata

# Load eye tracking data into data frame
dataFile <- here("data", "subject_info.csv")
subjectData <- read_csv2(dataFile, col_names = TRUE, progress = FALSE, col_types = cols(
  session.order = col_factor(c("first.anodal", "first.cathodal"))
))
kable(head(subjectData))
subject session.order gender age dominant.eye
S01 first.cathodal female 23 right
S02 first.anodal male 27 left
S03 first.cathodal male 34 right
S04 first.anodal male NA right
S05 first.cathodal male 24 right
S06 first.cathodal female 29 left
  • subject: subject ID
  • session.order: Whether subject had anodal stimulation in the first session (first.anodal) or cathodal stimulation in the first session (first.cathodal)
  • gender
  • age: in years
  • dominant.eye: result of eye dominance test

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

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(.)
direction type estimate statistic p.value parameter conf.low conf.high method alternative
left lateral -0.0434955 -0.9392156 0.3566066 25 -0.1388738 0.0518827 Paired t-test two.sided
left center -0.1052918 -2.3796609 0.0252737 25 -0.1964194 -0.0141643 Paired t-test two.sided
right lateral -0.0141028 -0.4198800 0.6781598 25 -0.0832780 0.0550724 Paired t-test two.sided
right center -0.0576332 -1.9185260 0.0665325 25 -0.1195025 0.0042361 Paired t-test two.sided

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(.)            
stimulation direction leg mean
anodal left tDCS 0.9149277
anodal left post.1 0.8752206
anodal left post.2 0.8978057
anodal right tDCS 0.7192357
anodal right post.1 0.7110237
anodal right post.2 0.7465372
cathodal left tDCS 0.9129682
cathodal left post.1 0.8395323
cathodal left post.2 0.8357657
cathodal right tDCS 0.7227287
cathodal right post.1 0.7062460
cathodal right post.2 0.7483820

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)

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

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

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

kable(modelKanai$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
3 leg 0.7641686 0.3907386 0.8038793 0.3951392
5 stimulation:leg 0.9959451 0.5595027 1.0819912 0.5601540
7 leg:direction 0.9745222 0.8646202 1.0558164 0.8696305
8 stimulation:leg:direction 0.8036501 0.7108179 0.8504748 0.7234385
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(.)
session.order count
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)

Effect DFn DFd F p p<.05 ges
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`)

Effect W p p<.05
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`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
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)

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

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

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

kable(modelKanaiCenter$`Sphericity Corrections`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
3 leg 0.8648128 0.1084443 0.9232826 0.1046730
5 stimulation:leg 0.9618956 0.5412918 1.0404345 0.5472793
7 leg:direction 0.7494296 0.0403283 * 0.7865648 0.0380011 *
8 stimulation:leg:direction 0.8481896 0.5328387 0.9034188 0.5428502
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(.)
stimulation estimate statistic p.value parameter conf.low conf.high method alternative
anodal 0.0223864 0.9712741 0.3407160 25 -0.0250828 0.0698555 One Sample t-test two.sided
cathodal -0.0755975 -3.1803958 0.0038987 25 -0.1245524 -0.0266426 One Sample t-test two.sided

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)

Effect DFn DFd F p p<.05 ges
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`)

Effect W p p<.05
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`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
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
bf
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"))
effect Bayes.factor
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
bf
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"))
effect Bayes.factor
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(.)
stimulation BF
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:

kable(head(stdData))
subject stimulation leg direction type std.deviation.x
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(.)
direction type estimate statistic p.value parameter conf.low conf.high method alternative
left lateral -0.0046841 -0.0964036 0.9239687 25 -0.1047541 0.0953859 Paired t-test two.sided
left center -0.0436919 -0.9898113 0.3317503 25 -0.1346033 0.0472195 Paired t-test two.sided
right lateral -0.0130790 -0.2683130 0.7906600 25 -0.1134716 0.0873137 Paired t-test two.sided
right center -0.0597899 -1.3048234 0.2038368 25 -0.1541625 0.0345827 Paired t-test two.sided

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)

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

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

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

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

Effect DFn DFd F p p<.05 ges
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`)

Effect W p p<.05
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`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
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)

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

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

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

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

Effect DFn DFd F p p<.05 ges
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`)

Effect W p p<.05
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`)
Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
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
bf
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"))
effect Bayes.factor
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
bf
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"))
effect Bayes.factor
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(.)
stimulation BF
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(.) 
stimulation estimate statistic p.value parameter conf.low conf.high method alternative
anodal 0.0477794 1.683151 0.1047947 25 -0.0106845 0.1062434 One Sample t-test two.sided
cathodal -0.0340719 -1.236236 0.2278603 25 -0.0908350 0.0226911 One Sample t-test two.sided

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