R notebook for inspection of eye tracking data in the sacc-tDCS dataset. Previous processing:

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

Load data

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

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

Inspect distributions

Histograms for each subject

histType <- ggplot(groupData, aes(latency, fill = type)) +
  facet_wrap(~subject, ncol = 5, scales = "free_y") +
  geom_histogram(binwidth = 5, color = "grey50", size = .2) +
  xlim(-50,300)
histType

Stray observations:

  • Center saccades are much faster than lateral, though not to the same degree in all subjects
  • Some have a fat short latency tail - too fast saccades that are virtually all towards the center: S10, S11, S22, S28
  • Some appear bimodal (S28), but when split for type this is generally because center saccades are faster: S05, S06, S11
  • Some look almost normally distributed (S10); others are very heavily right-skewed (S32)
  • Some are super sharp (S08); others really broad (S01)

Stimulation effects across subjects

dens <- ggplot(groupData, aes(latency, color = stimulation, linetype = leg)) +
  facet_grid(type ~ direction) +
  geom_density() +
  xlim(0, 250) +
  scale_color_brewer(palette = "Set1")
dens

Session effects in each subject

denstDCS <- ggplot(groupData[groupData$leg == 'pre' & groupData$type == "lateral", ], aes(latency, color = stimulation)) +
  facet_wrap(~subject, ncol = 5, scales ="free_y") +
  geom_density() +
  xlim(0, 250) +
  scale_color_brewer(palette = "Set1") +
  ggtitle('Lateral saccades, baseline block')
denstDCS

For most subjects, the latency distributions in both sessions are reasonably similar. Note that this is the baseline block, so we also wouldn’t expect any differences. In that light, it is a little worrisome that for some subjects the distributions differ markedly (S01, S02, S09, S12, S17, S21, S26, S29, S32).

Outliers

Outlier trials

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

Criteria for outliers:

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

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

Plot latencies of outlier trials per subject

outlierPlotTrials <- ggplot(groupData[!(groupData$outlier %in% c("none", "non.outlier")), ], aes(interaction(stimulation,leg,block,trial), latency, color = outlier, shape = type)) +
  facet_wrap(~subject, ncol = 5, scales = "free_y") +
  geom_point() +
  geom_hline(yintercept = 0) +
  geom_hline(yintercept = tooFast, linetype = "dashed") +
  geom_hline(yintercept = tooSlow, linetype = "dashed") +
  xlab('Trial') +
  theme(axis.text.x = element_blank(), # remove x-axis (just trial count)
  axis.ticks.x = element_blank())
outlierPlotTrials

Tally outlier types

outlierCount <- groupData %>%
  group_by(subject,stimulation,leg,direction,type,outlier) %>%
  summarize(outlier_count = n()) # for each condition and subject, count how many (non)outliers there are
outlierTable <- outlierCount %>%
  group_by(subject,outlier) %>%
  summarize(outlier_count = sum(outlier_count)) %>% # create column with sum across all conditions per subject
  mutate(total = sum(outlier_count[outlier != "non.outlier"])) %>% # create column with sum across all outlier types
  spread(outlier, outlier_count) %>% # one column per outlier type
  select(subject, non.outlier, total, none, fast, slow, fixation, saccade) #reorder columns
kable(outlierTable, caption = "Number of outlier saccades per subject")
subject non.outlier total none fast slow fixation saccade
S01 5414 346 166 49 70 57 4
S02 5711 49 14 13 NA 21 1
S03 5389 371 89 89 4 181 8
S04 5563 197 44 47 2 96 8
S05 5009 751 215 211 9 296 20
S06 5075 685 255 213 NA 202 15
S07 5641 119 71 31 NA 13 4
S08 5367 393 214 135 1 36 7
S09 5586 174 59 54 9 49 3
S10 4578 1182 454 352 2 363 11
S11 5177 583 280 164 13 115 11
S12 5593 167 66 54 2 40 5
S13 5191 569 394 87 2 80 6
S14 5036 724 299 119 6 279 21
S15 5279 481 329 75 3 56 18
S16 3879 1881 858 432 10 512 69
S17 5210 550 160 140 5 233 12
S18 5717 43 15 16 NA 8 4
S19 5357 403 114 141 1 141 6
S20 5110 650 272 188 9 162 19
S21 5467 293 66 41 13 168 5
S22 2898 2862 847 297 7 1707 4
S24 4568 1192 571 179 4 422 16
S25 4185 1575 514 384 NA 647 30
S26 5628 132 30 18 5 77 2
S27 5624 136 26 41 NA 63 6
S28 2781 2979 1913 329 4 694 39
S29 5223 537 148 119 12 245 13
S30 5094 666 297 230 2 137 NA
S32 5078 682 106 116 5 444 11
S33 5387 373 200 108 8 55 2

Plot outlier counts per subject and type

max_n <- nrow(filter(groupData, subject == "S01", type == "center")) # max amount of saccades in experiment
ggplot(filter(outlierCount, outlier != "non.outlier"), aes(subject, outlier_count, fill = outlier)) +
  geom_col() +
  scale_y_continuous("number of saccades", limits = c(0,max_n), sec.axis = sec_axis(~./max_n*100, name = "percent of all saccades")) +
  coord_flip() +
  facet_wrap(~type)

Stray observations:

Differences between subjects:

  • Some subjects have extremely clen data with barely any outliers (S02, S07, S18)
  • Most subjects have quite a few outliers, especially S10, S16, S22, S25 and S28
  • Only S01 has a sizable amount of slow saccades
  • Only S16 has a sizable amount of saccades to the opposite hemifield
  • Those subjects with many fast saccades also tend to have many bad fixations

General patterns:

  • Occurence of outliers seems stable throughout the session: there aren’t more/less in the beginning / end
  • There are very few inaccurate saccades (makes sense, because task is easy and criterion is not strict)
  • Most outliers are too fast saccades and bad fixations
  • Slow saccades are lateral, fast saccades are to the center, because only the latter are predictable
  • Bad fixations appear to be mostly center saccades (but this varies a lot). Perhaps the eyes already drift back towards the center, before executing the saccade?
  • Or is the source of bad fixations simply poor quality of the eye tracker data? e.g. people are actually fixating, but due to drift it appears they are not.

Tally number of non-outlier saccades

Importantly, we should also see how many saccades are left per condition after excluding outliers

trialCount <- groupData %>%
  filter(outlier == "non.outlier") %>% # keep only non-outlier saccades
  # Equally cut leg factor into 15-minute intervals, because the "post" leg is currently 30 minutes 
  mutate(leg = as.character(leg), # cannot edit leg if it's still a factor
         leg = replace(leg, leg == "post" & block <= 3, "post.1"),
         leg = replace(leg, block > 3, "post.2"),
         leg = factor(leg, levels = c("pre", "tDCS", "post.1", "post.2")) # refactor and order levels
         ) %>%
  group_by(subject,stimulation,leg,direction,type) %>%
  summarise(saccades = n()) %>% # count how many there are per subject per condition
  arrange(saccades) # sort ascending
kable(head(trialCount))
subject stimulation leg direction type saccades
S28 anodal post.1 right center 2
S28 anodal post.2 right center 2
S28 cathodal post.2 right center 3
S28 anodal post.1 left center 5
S28 anodal post.2 left center 6
S28 cathodal post.1 right center 6

List candidates for rejection

S28 should definitely be rejected, as certain conditions have only 2 useable saccades! S16 and S22 (together with S28) also have quite few saccade counts: less than 50 in some conditions. This is mostly because there are many missing saccades (none). Inspection of the data shows that this is not due to poor data quality, but because these subjects move their eyes too soon (i.e. before the stimulus even). That also explains why these low saccade counts occur almost exclusively in the center saccade condition (as there the location of the target was predictable).

subs2exclude <- c("S28","S16","S22","S21","S25") 

S21 and S25 should also be excluded. Their anodal and cathodal sessions were separated by less than 48 hours, which is in violation of the protocol.

Saccade counts for included participants

For all participants that will be included in the data analysis, compute descriptives of how many valid saccades remain for each type per cell (i.e. each stimulation, direction and leg combination used for statistical analysis)

trialCount %>%
  filter(!(subject %in% subs2exclude)) %>% # for all included participants
  group_by(type) %>%
  summarise(average = mean(saccades), standard.deviation = sd(saccades), minimum = min(saccades), maximum = max(saccades)) %>%
  kable(.)
type average standard.deviation minimum maximum
lateral 175.2284 6.244285 142 180
center 155.5529 20.816516 74 180

Let’s also look at proportion of saccades for each outlier type:

n_total <- nrow(filter(groupData, !(subject %in% subs2exclude)))  # total amount of saccades across all included sessions/subjects
outlierCount %>%
  filter(!(subject %in% subs2exclude), !(outlier %in% c("non.outlier", "none"))) %>%
  group_by(outlier) %>%
  summarise(percentage = sum(outlier_count) / n_total *100) %>%
  kable(.)
outlier percentage
fast 1.9958600
fixation 2.5848024
saccade 0.1555823
slow 0.1161859

Outliers in median latency

Next to rejecting outlier trials, we could also consider rejecting outlier subjects or certain conditions from the statistical tests. One way to detect outliers (that is itself robust to outliers, unlike the standard deviation) is the MAD-median rule (see this blogpost and this preprint). The MAD is the median absolute devian from the median.

outliersPerCondition <- groupData %>%
  filter(outlier == "non.outlier") %>% # drop all outlier trials
  group_by(subject,stimulation,leg,type,direction) %>%
  summarise(latency = median(latency)) %>% # compute median latency
  group_by(stimulation,leg,type,direction) %>%
  mutate(mad.median.rule = (abs(latency - median(latency)) / mad(latency))) %>% # deviation from the median, standardized by the MAD
  filter(mad.median.rule > 2.24) # MAD-median rule
kable(head(outliersPerCondition))
subject stimulation leg type direction latency mad.median.rule
S01 anodal pre lateral left 219.5 4.890058
S01 anodal pre lateral right 195.0 2.810378
S01 anodal pre center left 214.0 7.194568
S01 anodal pre center right 211.0 3.943177
S01 anodal tDCS lateral left 210.5 4.143300
S01 anodal tDCS lateral right 192.0 3.035208

These are all the subject-condition combinations for which the MAD-median rule is violated. If we were to reject subjects with one more more violation, we would have to remove 11 subjects.

There is some overlap with the analysis of outlier trials. For instance, there is reason to remove S28 in both analyses. But this is not always the case: S26 has very clean trial-data, but is still flagged as an outlier here because their median latencies are quite slow.

Drift correction

Calibration isn’t perfect, so there are always small offsets between the measurements and what people are actually looking at. Further, these measurement errors can increase with time away from calibration, which is known as drift.

After every 20 trials (40 saccades) there was a break in the task, in which we asked subjects to fixate the center of the screen before continueing. The offsets recorded here should thus be a good estimate of drift, since here you can trust that subjects were actually looking at fixation spot on.

To do drift correction, we simply subtract the offsets recorded in the break from the x- and y- coordinates of the eye data of interest.

# Add columns with drift-corrected values
groupData <- mutate(groupData,
                    deviation.end.x.corr = deviation.end.x - drift.x,
                    deviation.end.y.corr = deviation.end.y - drift.y)

If this does indeed work, then most trials should now have a smaller deviation.

# Calculate percentage of trials with smaller deviations after drift correction
groupData %>%
  group_by(subject, stimulation) %>% # split per subject and session
  summarize(
    trials = n(),
    smaller.drift.x = sum(abs(deviation.end.x.corr) < abs(deviation.end.x), na.rm = TRUE) / trials * 100,
    smaller.drift.y = sum(abs(deviation.end.y.corr) < abs(deviation.end.y), na.rm = TRUE) / trials * 100
  ) %>%
  
  # Plot
  ggplot(aes(smaller.drift.x, smaller.drift.y)) +
  facet_wrap(~stimulation) +
  geom_hline(yintercept = 50, linetype = "dashed") + geom_vline(xintercept = 50, linetype = "dashed") +
  geom_point(aes(color = subject)) +
  coord_fixed(xlim = c(0,100), ylim = c(0,100)) +
  #geom_text_repel(aes(label = subject, color = subject)) +
  theme(legend.position = "none")

Seems that it doesn’t really work at all, because for most subjects the errors are decreased on less than 50% of saccades! Of course, this is only a rough analysis, but this does match with SR Research’s advice in the EyeLink manual, which states that drift correction may actually deteriorate the calibration maps.

LS0tCnRpdGxlOiAic2FjYy10RENTOiBEYXRhIGluc3BlY3Rpb24iCmF1dGhvcjogIkxlb24gUmV0ZWlnIgpvdXRwdXQ6CiAgZ2l0aHViX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDIKICBodG1sX25vdGVib29rOgogICAgaGlnaGxpZ2h0OiBweWdtZW50cwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCiAgClIgbm90ZWJvb2sgZm9yIGluc3BlY3Rpb24gb2YgZXllIHRyYWNraW5nIGRhdGEgaW4gdGhlIGBzYWNjLXREQ1NgIGRhdGFzZXQuIFByZXZpb3VzIHByb2Nlc3Npbmc6CiAgCiogUmF3IGRhdGEgd2VyZSBwYXJzZWQgaW50byBldmVudHMgKHNhY2NhZGVzLCBmaXhhdGlvbnMsIGV0Yy4pIGJ5IHRoZSBFeWVMaW5rIGRhdGEgd2VyZSBjb2xsZWN0ZWQgb24uCiogRXZlbnRzIHdlcmUgZXh0cmFjdGVkIGFuZCBzYWNjYWRlIG1lYXN1cmVzIHdlcmUgY29tcHV0ZWQgd2l0aCBhIE1BVExBQiBzY3JpcHQuCgpgYGB7ciBzZXR1cH0KIyBMb2FkIHNvbWUgbGlicmFyaWVzCmxpYnJhcnkoaGVyZSkgIyBmaWxlIHBhdGhzCmxpYnJhcnkodGlkeXZlcnNlKSAjIGltcG9ydGluZywgdHJhbnNmb3JtaW5nLCBhbmQgdmlzdWFsaXppbmcgZGF0YSBmcmFtZXMKbGlicmFyeShrbml0cikgIyBSIG1hcmtkb3duIG91dHB1dCAoaHRtbCwgcGRmLCBldGMuKQojIHNldCBkZWZhdWx0IG91dHB1dCBhbmQgZmlndXJlIG9wdGlvbnMKa25pdHI6Om9wdHNfY2h1bmskc2V0KG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBmaWcud2lkdGggPSA3LCBmaWcuYXNwID0gMC42MTgsIG91dC53aWR0aCA9ICI3NSUiLCBmaWcuYWxpZ24gPSAiY2VudGVyIikKCnNlc3Npb25JbmZvKCkKYGBgCgojIExvYWQgZGF0YQoKVGhlIC5jc3YgZmlsZSB3aXRoIHRoZSBleWUgdHJhY2tpbmcgZGF0YSB3YXMgY3JlYXRlZCBpbiBNQVRMQUIuCgpgYGB7ciBMb2FkIHRoZSBkYXRhIGZyYW1lfQojIExvYWQgdGhlIGRhdGEgZnJhbWUKZGF0YUZpbGUgPC0gaGVyZSgiZGF0YSIsICJzYWNjLXREQ1NfZGF0YS5jc3YiKQpncm91cERhdGEgPC0gcmVhZF9jc3YoZGF0YUZpbGUsIGNvbF9uYW1lcyA9IFRSVUUsIG5hID0gIk5hTiIsIHByb2dyZXNzID0gRkFMU0UsIGNvbF90eXBlcyA9IGNvbHMoCiAgc3RpbXVsYXRpb24gPSBjb2xfZmFjdG9yKGMoImFub2RhbCIsImNhdGhvZGFsIikpLAogIGxlZyA9IGNvbF9mYWN0b3IoYygicHJlIiwidERDUyIsInBvc3QiKSksCiAgdHlwZSA9IGNvbF9mYWN0b3IoYygibGF0ZXJhbCIsImNlbnRlciIpKSwKICBkaXJlY3Rpb24gPSBjb2xfZmFjdG9yKGMoImxlZnQiLCJyaWdodCIpKSAKKSkKYGBgCgpgYGB7ciBTaG93IGRhdGEgZnJhbWV9CmthYmxlKGhlYWQoZ3JvdXBEYXRhKSkKYGBgCgoqIF9fc3ViamVjdF9fOiBzdWJqZWN0IElECiogX19zdGltdWxhdGlvbl9fOiBXaGV0aGVyIGRhdGEgYXJlIGZyb20gdGhlIGBhbm9kYWxgIG9yIGBjYXRob2RhbGAgc2Vzc2lvbgoqIF9fbGVnX186IFdoZXRoZXIgZGF0YSBhcmUgYmVmb3JlIChgcHJlYCksIGR1cmluZyAoYHREQ1NgKSwgb3IgYWZ0ZXIgKGBwb3N0YCkgdERDUwoqIF9fYmxvY2tfXzogQWZ0ZXIgZWFjaCBibG9jayBwYXJ0aWNpcGFudCBoYWQgYSBicmllZiBicmVhayBhbmQgdHJhY2tlciB3YXMgcmVjYWxpYnJhdGVkCiogX190cmlhbF9fOiB0cmlhbCBudW1iZXIgd2l0aGluIGEgYmxvY2sKKiBfX3R5cGVfXzoKICAgICogYGxhdGVyYWxgIC0gZml4YXRpb24gaW4gY2VudGVyIG9mIGRpc3BsYXksIHNhY2NhZGUgbWFkZSB0b3dhcmRzIHRoZSBwZXJpcGhlcnkKICAgICogYGNlbnRlcmAgLSBmaXhhdGlvbiBpbiBwZXJpcGhlcnksIHNhY2NhZGUgbWFkZSBiYWNrIHRvd2FyZHMgdGhlIGNlbnRlciBvZiB0aGUgZGlzcGxheQoqIF9fZGlyZWN0aW9uX186IGBsZWZ0YCBmb3Igc2FjY2FkZXMgdG93YXJkcyB0aGUgbGVmdCBvZiBjdXJyZW50IGZpeGF0aW9uIHBvc2l0aW9uOyBgcmlnaHRgIGZvciBzYWNjYWRlcyB0byB0aGUgcmlnaHQKKiBfX2RldmlhdGlvbi5zdGFydF9fIDogZGlzdGFuY2UgKGluIHZpc3VhbCBhbmdsZSkgZnJvbSBzYWNjYWRlIHN0YXJ0IHBvaW50IHRvIGZpeGF0aW9uCiogX19kZXZpYXRpb24uZW5kLnhfXzogZGlzdGFuY2UgKGluIHZpc3VhbCBhbmdsZSkgZnJvbSB4LWNvb3JkaW5hdGUgb2Ygc2FjY2FkZSBlbmQgcG9pbnQgdG8geC1jb29yZGluYXRlIG9mIHRhcmdldCBsb2NhdGlvbgoqIF9fZGV2aWF0aW9uLmVuZC55X186IHNhbWUgZm9yIHktY29vcmRpbmF0ZQoqIF9fYW1wbGl0dWRlX186IGRpc3RhbmNlIChpbiB2aXN1YWwgYW5nbGUpIGJldHdlZW4gc2FjY2FkZSBzdGFydCBhbmQgZW5kIHBvaW50CiogX19sYXRlbmN5X186IHRpbWUgKGluIG1zKSBmcm9tIHRhcmdldCBvbnNldCB0byBzdGFydCBvZiBzYWNjYWRlCiogX19kcmlmdC54X186IGRpc3RhbmNlIChpbiB2aXN1YWwgYW5nbGUpIGJldHdlZW4geC1jb29yZGluYXRlIG9mIGF2ZXJhZ2UgZml4YXRpb24gcG9zaXRpb24gZHVyaW5nIHRoZSBicmVhayB0byB4LWNvb3JkaW5hdGUgb2YgZml4YXRpb24gc3RpbXVsdXMuIFRoaXMgc3RpbXVsdXMgd2FzIGRpc3BsYXllZCBhdCBlYWNoIGJyZWFrIGluIHRoZSB0YXNrLCBzbyB0aGlzIGRhdGEgY2FuIGJlIHVzZWQgYXMgYW4gZXN0aW1hdGUgb2Ygb2Zmc2V0cyB0byBkbyBkcmlmdCBjb3JyZWN0aW9uLgoqIF9fZHJpZnQueV9fOiBzYW1lIGZvciB5LWNvb3JkaW5hdGUKCiMgSW5zcGVjdCBkaXN0cmlidXRpb25zCgojIyMgSGlzdG9ncmFtcyBmb3IgZWFjaCBzdWJqZWN0IAoKYGBge3IgSGlzdG9ncmFtIHBlciBzdWJqZWN0LCBmaWcud2lkdGggPSAxMH0KaGlzdFR5cGUgPC0gZ2dwbG90KGdyb3VwRGF0YSwgYWVzKGxhdGVuY3ksIGZpbGwgPSB0eXBlKSkgKwogIGZhY2V0X3dyYXAofnN1YmplY3QsIG5jb2wgPSA1LCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNSwgY29sb3IgPSAiZ3JleTUwIiwgc2l6ZSA9IC4yKSArCiAgeGxpbSgtNTAsMzAwKQpoaXN0VHlwZQpgYGAKCl9fU3RyYXkgb2JzZXJ2YXRpb25zOl9fCgoqIENlbnRlciBzYWNjYWRlcyBhcmUgbXVjaCBmYXN0ZXIgdGhhbiBsYXRlcmFsLCB0aG91Z2ggbm90IHRvIHRoZSBzYW1lIGRlZ3JlZSBpbiBhbGwgc3ViamVjdHMKKiBTb21lIGhhdmUgYSBmYXQgc2hvcnQgbGF0ZW5jeSB0YWlsIC0gdG9vIGZhc3Qgc2FjY2FkZXMgdGhhdCBhcmUgdmlydHVhbGx5IGFsbCB0b3dhcmRzIHRoZSBjZW50ZXI6IFMxMCwgUzExLCBTMjIsIFMyOAoqIFNvbWUgYXBwZWFyIGJpbW9kYWwgKFMyOCksIGJ1dCB3aGVuIHNwbGl0IGZvciB0eXBlIHRoaXMgaXMgZ2VuZXJhbGx5IGJlY2F1c2UgY2VudGVyIHNhY2NhZGVzIGFyZSBmYXN0ZXI6IFMwNSwgUzA2LCBTMTEKKiBTb21lIGxvb2sgYWxtb3N0IG5vcm1hbGx5IGRpc3RyaWJ1dGVkIChTMTApOyBvdGhlcnMgYXJlIHZlcnkgaGVhdmlseSByaWdodC1za2V3ZWQgKFMzMikKKiBTb21lIGFyZSBzdXBlciBzaGFycCAoUzA4KTsgb3RoZXJzIHJlYWxseSBicm9hZCAoUzAxKQoKIyMjIFN0aW11bGF0aW9uIGVmZmVjdHMgYWNyb3NzIHN1YmplY3RzCgpgYGB7ciBEZW5zaXR5OiBzdGltdWxhdGlvbiBhY3Jvc3Mgc3ViamVjdHN9CmRlbnMgPC0gZ2dwbG90KGdyb3VwRGF0YSwgYWVzKGxhdGVuY3ksIGNvbG9yID0gc3RpbXVsYXRpb24sIGxpbmV0eXBlID0gbGVnKSkgKwogIGZhY2V0X2dyaWQodHlwZSB+IGRpcmVjdGlvbikgKwogIGdlb21fZGVuc2l0eSgpICsKICB4bGltKDAsIDI1MCkgKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDEiKQpkZW5zCmBgYAoKIyMjIFNlc3Npb24gZWZmZWN0cyBpbiBlYWNoIHN1YmplY3QKYGBge3IgRGVuc2l0eTogYW5vZGFsIHZzLiBjYXRob2RhbCBiYXNlbGluZSBwZXIgc3ViamVjdCwgZmlnLndpZHRoID0gMTB9CmRlbnN0RENTIDwtIGdncGxvdChncm91cERhdGFbZ3JvdXBEYXRhJGxlZyA9PSAncHJlJyAmIGdyb3VwRGF0YSR0eXBlID09ICJsYXRlcmFsIiwgXSwgYWVzKGxhdGVuY3ksIGNvbG9yID0gc3RpbXVsYXRpb24pKSArCiAgZmFjZXRfd3JhcCh+c3ViamVjdCwgbmNvbCA9IDUsIHNjYWxlcyA9ImZyZWVfeSIpICsKICBnZW9tX2RlbnNpdHkoKSArCiAgeGxpbSgwLCAyNTApICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikgKwogIGdndGl0bGUoJ0xhdGVyYWwgc2FjY2FkZXMsIGJhc2VsaW5lIGJsb2NrJykKZGVuc3REQ1MKYGBgCgpGb3IgbW9zdCBzdWJqZWN0cywgdGhlIGxhdGVuY3kgZGlzdHJpYnV0aW9ucyBpbiBib3RoIHNlc3Npb25zIGFyZSByZWFzb25hYmx5IHNpbWlsYXIuIE5vdGUgdGhhdCB0aGlzIGlzIHRoZSBiYXNlbGluZSBibG9jaywgc28gd2UgYWxzbyB3b3VsZG4ndCBleHBlY3QgYW55IGRpZmZlcmVuY2VzLiBJbiB0aGF0IGxpZ2h0LCBpdCBpcyBhIGxpdHRsZSB3b3JyaXNvbWUgdGhhdCBmb3Igc29tZSBzdWJqZWN0cyB0aGUgZGlzdHJpYnV0aW9ucyBkaWZmZXIgbWFya2VkbHkgKFMwMSwgUzAyLCBTMDksIFMxMiwgUzE3LCBTMjEsIFMyNiwgUzI5LCBTMzIpLgoKIyBPdXRsaWVycwoKIyMgT3V0bGllciB0cmlhbHMKCmBgYHtyIE91dGxpZXIgY3JpdGVyaWF9CnRvb0Zhc3QgPC0gNTAKdG9vU2xvdyA8LSA0MDAKYmFkRml4IDwtIDEuOApiYWRTYWNjIDwtIDgKYGBgCgpDcml0ZXJpYSBmb3Igb3V0bGllcnM6CgoqIERpc2NhcmQgZmFzdCBzYWNjYWRlcywgd2l0aCBhIGxhdGVuY3kgb2YgYHIgdG9vRmFzdGAgbXMgb3IgbGVzcwoqIERpc2NhcmQgc2xvdyBzYWNjYWRlcywgc2FjY2FkZXMgd2l0aCBhIGxhdGVuY3kgb2YgYHIgdG9vU2xvd2AgbXMgb3IgbW9yZQoqIERpc2NhcmQgaW5hY2N1cmF0ZSBmaXhhdGlvbnMsIHdpdGggc2FjY2FkZSBzdGFydGluZyBwb2ludCBtb3JlIHRoYW4gYHIgYmFkRml4YCBkZWdyZWVzIG9yIG1vcmUgYXdheSBmcm9tIGZpeGF0aW9uCiogRGlzY2FyZCBmYXVsdHkgc2FjY2FkZXMsIHdpdGggeC1jb29yZGluYXRlIG9mIHNhY2NhZGUgZW5kIHBvaW50IGByIGJhZFNhY2NgIGRlZ3JlZSBvciBtb3JlIGF3YXkgZnJvbSB0aGUgdGFyZ2V0CgpJbiBbS2FuYWkgZXQgYWwuICgyMDEyKV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMzM4OS9mcHN5dC4yMDEyLjAwMDQ1KSwgdGhpcyB3YXM6CgoqIEZhc3Qgc2FjY2FkZXM6IDUwIG1zCiogU2xvdyBzYWNjYWRlczogNDAwIG1zCiogQmFkIGZpeGF0aW9uczogMS44IGRlZ3JlZXMKKiBGYXVsdHkgc2FjY2FkZXM6IG9wcG9zaXRlIGhlbWlmaWVsZCBvZiB0YXJnZXQgKGhlcmUsIHRoYXQgd291bGQgYmUgOCBkZWdyZWVzIGFzIHRhcmdldHMgd2VyZSB0aGF0IGVjY2VudHJpYykKCmBgYHtyIE1hcmsgdHJpYWxzIGFzIG91dGxpZXJzfQojIE1hcmsgb3V0bGllcnMKZ3JvdXBEYXRhIDwtIG11dGF0ZShncm91cERhdGEsIG91dGxpZXIgPSAibm9uLm91dGxpZXIiLCAjIGZpbGwgdmVjdG9yIGZvciBhbGwgdHJpYWxzCiAgICAgICAgICAgICAgICAgICAgb3V0bGllciA9IGlmZWxzZShsYXRlbmN5IDwgdG9vRmFzdCwgImZhc3QiLCBvdXRsaWVyKSwgIyBtYXJrIHRvbyBmYXN0IHRyaWFscyBhcyAiZmFzdCIKICAgICAgICAgICAgICAgICAgICBvdXRsaWVyID0gaWZlbHNlKGxhdGVuY3kgPiB0b29TbG93LCAic2xvdyIsIG91dGxpZXIpLCAjIG1hcmsgdG9vIHNsb3cgdHJpYWxzIGFzICJzbG93IgogICAgICAgICAgICAgICAgICAgIG91dGxpZXIgPSBpZmVsc2UoZGV2aWF0aW9uLnN0YXJ0ID4gYmFkRml4LCAiZml4YXRpb24iLCBvdXRsaWVyKSwgIyBtYXJrIGJhZCBmaXhhdGlvbnMgYXMgImZpeGF0aW9uIgogICAgICAgICAgICAgICAgICAgIG91dGxpZXIgPSBpZmVsc2UoZGV2aWF0aW9uLmVuZC54ID4gYmFkU2FjYywgInNhY2NhZGUiLCBvdXRsaWVyKSwgIyBtYXJrIGluYWNjdXJhdGUgc2FjY2FkZXMgYXMgInNhY2NhZGUiCiAgICAgICAgICAgICAgICAgICAgb3V0bGllciA9IGlmZWxzZShpcy5uYShsYXRlbmN5KSwgIm5vbmUiLCBvdXRsaWVyKSAjIG1hcmsgYWJzZW5jZSBvZiBzYWNjYWRlIGFzICJub25lIgogICAgICAgICAgICAgICAgICAgICkKYGBgCgojIyMgUGxvdCBsYXRlbmNpZXMgb2Ygb3V0bGllciB0cmlhbHMgcGVyIHN1YmplY3QKCmBgYHtyIFBsb3Qgb3V0bGllciB0cmlhbHMgcGVyIHN1YmplY3QsIGZpZy53aWR0aCA9IDEwfQpvdXRsaWVyUGxvdFRyaWFscyA8LSBnZ3Bsb3QoZ3JvdXBEYXRhWyEoZ3JvdXBEYXRhJG91dGxpZXIgJWluJSBjKCJub25lIiwgIm5vbi5vdXRsaWVyIikpLCBdLCBhZXMoaW50ZXJhY3Rpb24oc3RpbXVsYXRpb24sbGVnLGJsb2NrLHRyaWFsKSwgbGF0ZW5jeSwgY29sb3IgPSBvdXRsaWVyLCBzaGFwZSA9IHR5cGUpKSArCiAgZmFjZXRfd3JhcCh+c3ViamVjdCwgbmNvbCA9IDUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gdG9vRmFzdCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IHRvb1Nsb3csIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICB4bGFiKCdUcmlhbCcpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgIyByZW1vdmUgeC1heGlzIChqdXN0IHRyaWFsIGNvdW50KQogIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSkKb3V0bGllclBsb3RUcmlhbHMKYGBgCgojIyMgVGFsbHkgb3V0bGllciB0eXBlcyAKCmBgYHtyIFRhbGx5IG91dGxpZXJzfQpvdXRsaWVyQ291bnQgPC0gZ3JvdXBEYXRhICU+JQogIGdyb3VwX2J5KHN1YmplY3Qsc3RpbXVsYXRpb24sbGVnLGRpcmVjdGlvbix0eXBlLG91dGxpZXIpICU+JQogIHN1bW1hcml6ZShvdXRsaWVyX2NvdW50ID0gbigpKSAjIGZvciBlYWNoIGNvbmRpdGlvbiBhbmQgc3ViamVjdCwgY291bnQgaG93IG1hbnkgKG5vbilvdXRsaWVycyB0aGVyZSBhcmUKYGBgCgpgYGB7ciBUYWJsZSBvZiBvdXRsaWVyIGNvdW50cyBwZXIgc3ViamVjdCwgcmVzdWx0cz0gJ2FzaXMnfQpvdXRsaWVyVGFibGUgPC0gb3V0bGllckNvdW50ICU+JQogIGdyb3VwX2J5KHN1YmplY3Qsb3V0bGllcikgJT4lCiAgc3VtbWFyaXplKG91dGxpZXJfY291bnQgPSBzdW0ob3V0bGllcl9jb3VudCkpICU+JSAjIGNyZWF0ZSBjb2x1bW4gd2l0aCBzdW0gYWNyb3NzIGFsbCBjb25kaXRpb25zIHBlciBzdWJqZWN0CiAgbXV0YXRlKHRvdGFsID0gc3VtKG91dGxpZXJfY291bnRbb3V0bGllciAhPSAibm9uLm91dGxpZXIiXSkpICU+JSAjIGNyZWF0ZSBjb2x1bW4gd2l0aCBzdW0gYWNyb3NzIGFsbCBvdXRsaWVyIHR5cGVzCiAgc3ByZWFkKG91dGxpZXIsIG91dGxpZXJfY291bnQpICU+JSAjIG9uZSBjb2x1bW4gcGVyIG91dGxpZXIgdHlwZQogIHNlbGVjdChzdWJqZWN0LCBub24ub3V0bGllciwgdG90YWwsIG5vbmUsIGZhc3QsIHNsb3csIGZpeGF0aW9uLCBzYWNjYWRlKSAjcmVvcmRlciBjb2x1bW5zCmthYmxlKG91dGxpZXJUYWJsZSwgY2FwdGlvbiA9ICJOdW1iZXIgb2Ygb3V0bGllciBzYWNjYWRlcyBwZXIgc3ViamVjdCIpCmBgYAoKIyMjIFBsb3Qgb3V0bGllciBjb3VudHMgcGVyIHN1YmplY3QgYW5kIHR5cGUKCmBgYHtyIFBsb3Qgb3V0bGllciBjb3VudHMgcGVyIHN1YmplY3QgYW5kIHR5cGUsIGZpZy53aWR0aCA9IDd9Cm1heF9uIDwtIG5yb3coZmlsdGVyKGdyb3VwRGF0YSwgc3ViamVjdCA9PSAiUzAxIiwgdHlwZSA9PSAiY2VudGVyIikpICMgbWF4IGFtb3VudCBvZiBzYWNjYWRlcyBpbiBleHBlcmltZW50CgpnZ3Bsb3QoZmlsdGVyKG91dGxpZXJDb3VudCwgb3V0bGllciAhPSAibm9uLm91dGxpZXIiKSwgYWVzKHN1YmplY3QsIG91dGxpZXJfY291bnQsIGZpbGwgPSBvdXRsaWVyKSkgKwogIGdlb21fY29sKCkgKwogIHNjYWxlX3lfY29udGludW91cygibnVtYmVyIG9mIHNhY2NhZGVzIiwgbGltaXRzID0gYygwLG1heF9uKSwgc2VjLmF4aXMgPSBzZWNfYXhpcyh+Li9tYXhfbioxMDAsIG5hbWUgPSAicGVyY2VudCBvZiBhbGwgc2FjY2FkZXMiKSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgZmFjZXRfd3JhcCh+dHlwZSkKYGBgCgoKX19TdHJheSBvYnNlcnZhdGlvbnM6X18KCkRpZmZlcmVuY2VzIGJldHdlZW4gc3ViamVjdHM6CgoqIFNvbWUgc3ViamVjdHMgaGF2ZSBleHRyZW1lbHkgY2xlbiBkYXRhIHdpdGggYmFyZWx5IGFueSBvdXRsaWVycyAoUzAyLCBTMDcsIFMxOCkKKiBNb3N0IHN1YmplY3RzIGhhdmUgcXVpdGUgYSBmZXcgb3V0bGllcnMsIGVzcGVjaWFsbHkgUzEwLCBTMTYsIFMyMiwgUzI1IGFuZCBTMjgKKiBPbmx5IFMwMSBoYXMgYSBzaXphYmxlIGFtb3VudCBvZiBzbG93IHNhY2NhZGVzCiogT25seSBTMTYgaGFzIGEgc2l6YWJsZSBhbW91bnQgb2Ygc2FjY2FkZXMgdG8gdGhlIG9wcG9zaXRlIGhlbWlmaWVsZAoqIFRob3NlIHN1YmplY3RzIHdpdGggbWFueSBmYXN0IHNhY2NhZGVzIGFsc28gdGVuZCB0byBoYXZlIG1hbnkgYmFkIGZpeGF0aW9ucwoKR2VuZXJhbCBwYXR0ZXJuczoKCiogT2NjdXJlbmNlIG9mIG91dGxpZXJzIHNlZW1zIHN0YWJsZSB0aHJvdWdob3V0IHRoZSBzZXNzaW9uOiB0aGVyZSBhcmVuJ3QgbW9yZS9sZXNzIGluIHRoZSBiZWdpbm5pbmcgLyBlbmQKKiBUaGVyZSBhcmUgdmVyeSBmZXcgaW5hY2N1cmF0ZSBzYWNjYWRlcyAobWFrZXMgc2Vuc2UsIGJlY2F1c2UgdGFzayBpcyBlYXN5IGFuZCBjcml0ZXJpb24gaXMgbm90IHN0cmljdCkKKiBNb3N0IG91dGxpZXJzIGFyZSB0b28gZmFzdCBzYWNjYWRlcyBhbmQgYmFkIGZpeGF0aW9ucwoqIFNsb3cgc2FjY2FkZXMgYXJlIGxhdGVyYWwsIGZhc3Qgc2FjY2FkZXMgYXJlIHRvIHRoZSBjZW50ZXIsIGJlY2F1c2Ugb25seSB0aGUgbGF0dGVyIGFyZSBwcmVkaWN0YWJsZQoqIEJhZCBmaXhhdGlvbnMgYXBwZWFyIHRvIGJlIG1vc3RseSBjZW50ZXIgc2FjY2FkZXMgKGJ1dCB0aGlzIHZhcmllcyBhIGxvdCkuIFBlcmhhcHMgdGhlIGV5ZXMgYWxyZWFkeSBkcmlmdCBiYWNrIHRvd2FyZHMgdGhlIGNlbnRlciwgYmVmb3JlIGV4ZWN1dGluZyB0aGUgc2FjY2FkZT8KKiBPciBpcyB0aGUgc291cmNlIG9mIGJhZCBmaXhhdGlvbnMgc2ltcGx5IHBvb3IgcXVhbGl0eSBvZiB0aGUgZXllIHRyYWNrZXIgZGF0YT8gZS5nLiBwZW9wbGUgYXJlIGFjdHVhbGx5IGZpeGF0aW5nLCBidXQgZHVlIHRvIGRyaWZ0IGl0IGFwcGVhcnMgdGhleSBhcmUgbm90LgoKIyMjIFRhbGx5IG51bWJlciBvZiBub24tb3V0bGllciBzYWNjYWRlcwoKSW1wb3J0YW50bHksIHdlIHNob3VsZCBhbHNvIHNlZSBob3cgbWFueSBzYWNjYWRlcyBhcmUgbGVmdCBwZXIgY29uZGl0aW9uIGFmdGVyIGV4Y2x1ZGluZyBvdXRsaWVycwoKYGBge3IgVGFibGUgd2l0aCBudW1iZXIgb2Ygbm9uLW91dGxpZXIgc2FjY2FkZXN9CnRyaWFsQ291bnQgPC0gZ3JvdXBEYXRhICU+JQogIGZpbHRlcihvdXRsaWVyID09ICJub24ub3V0bGllciIpICU+JSAjIGtlZXAgb25seSBub24tb3V0bGllciBzYWNjYWRlcwogICMgRXF1YWxseSBjdXQgbGVnIGZhY3RvciBpbnRvIDE1LW1pbnV0ZSBpbnRlcnZhbHMsIGJlY2F1c2UgdGhlICJwb3N0IiBsZWcgaXMgY3VycmVudGx5IDMwIG1pbnV0ZXMgCiAgbXV0YXRlKGxlZyA9IGFzLmNoYXJhY3RlcihsZWcpLCAjIGNhbm5vdCBlZGl0IGxlZyBpZiBpdCdzIHN0aWxsIGEgZmFjdG9yCiAgICAgICAgIGxlZyA9IHJlcGxhY2UobGVnLCBsZWcgPT0gInBvc3QiICYgYmxvY2sgPD0gMywgInBvc3QuMSIpLAogICAgICAgICBsZWcgPSByZXBsYWNlKGxlZywgYmxvY2sgPiAzLCAicG9zdC4yIiksCiAgICAgICAgIGxlZyA9IGZhY3RvcihsZWcsIGxldmVscyA9IGMoInByZSIsICJ0RENTIiwgInBvc3QuMSIsICJwb3N0LjIiKSkgIyByZWZhY3RvciBhbmQgb3JkZXIgbGV2ZWxzCiAgICAgICAgICkgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCxzdGltdWxhdGlvbixsZWcsZGlyZWN0aW9uLHR5cGUpICU+JQogIHN1bW1hcmlzZShzYWNjYWRlcyA9IG4oKSkgJT4lICMgY291bnQgaG93IG1hbnkgdGhlcmUgYXJlIHBlciBzdWJqZWN0IHBlciBjb25kaXRpb24KICBhcnJhbmdlKHNhY2NhZGVzKSAjIHNvcnQgYXNjZW5kaW5nCmthYmxlKGhlYWQodHJpYWxDb3VudCkpCmBgYAoKIyMjIExpc3QgY2FuZGlkYXRlcyBmb3IgcmVqZWN0aW9uCgpTMjggc2hvdWxkIGRlZmluaXRlbHkgYmUgcmVqZWN0ZWQsIGFzIGNlcnRhaW4gY29uZGl0aW9ucyBoYXZlIG9ubHkgMiB1c2VhYmxlIHNhY2NhZGVzISBTMTYgYW5kIFMyMiAodG9nZXRoZXIgd2l0aCBTMjgpIGFsc28gaGF2ZSBxdWl0ZSBmZXcgc2FjY2FkZSBjb3VudHM6IGxlc3MgdGhhbiA1MCBpbiBzb21lIGNvbmRpdGlvbnMuIFRoaXMgaXMgbW9zdGx5IGJlY2F1c2UgdGhlcmUgYXJlIG1hbnkgbWlzc2luZyBzYWNjYWRlcyAoYG5vbmVgKS4gSW5zcGVjdGlvbiBvZiB0aGUgZGF0YSBzaG93cyB0aGF0IHRoaXMgaXMgbm90IGR1ZSB0byBwb29yIGRhdGEgcXVhbGl0eSwgYnV0IGJlY2F1c2UgdGhlc2Ugc3ViamVjdHMgbW92ZSB0aGVpciBleWVzIHRvbyBzb29uIChpLmUuIGJlZm9yZSB0aGUgc3RpbXVsdXMgZXZlbikuIFRoYXQgYWxzbyBleHBsYWlucyB3aHkgdGhlc2UgbG93IHNhY2NhZGUgY291bnRzIG9jY3VyIGFsbW9zdCBleGNsdXNpdmVseSBpbiB0aGUgX2NlbnRlcl8gc2FjY2FkZSBjb25kaXRpb24gKGFzIHRoZXJlIHRoZSBsb2NhdGlvbiBvZiB0aGUgdGFyZ2V0IHdhcyBwcmVkaWN0YWJsZSkuCgpgYGB7ciBMaXN0IHN1YmplY3RzIHRvIGV4Y2x1ZGV9CnN1YnMyZXhjbHVkZSA8LSBjKCJTMjgiLCJTMTYiLCJTMjIiLCJTMjEiLCJTMjUiKSAKYGBgCgpTMjEgYW5kIFMyNSBzaG91bGQgYWxzbyBiZSBleGNsdWRlZC4gVGhlaXIgYW5vZGFsIGFuZCBjYXRob2RhbCBzZXNzaW9ucyB3ZXJlIHNlcGFyYXRlZCBieSBsZXNzIHRoYW4gNDggaG91cnMsIHdoaWNoIGlzIGluIHZpb2xhdGlvbiBvZiB0aGUgcHJvdG9jb2wuCgojIyMgU2FjY2FkZSBjb3VudHMgZm9yIGluY2x1ZGVkIHBhcnRpY2lwYW50cwoKRm9yIGFsbCBwYXJ0aWNpcGFudHMgdGhhdCB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBkYXRhIGFuYWx5c2lzLCBjb21wdXRlIGRlc2NyaXB0aXZlcyBvZiBob3cgbWFueSB2YWxpZCBzYWNjYWRlcyByZW1haW4gZm9yIGVhY2ggdHlwZSBwZXIgY2VsbCAoaS5lLiBlYWNoIHN0aW11bGF0aW9uLCBkaXJlY3Rpb24gYW5kIGxlZyBjb21iaW5hdGlvbiB1c2VkIGZvciBzdGF0aXN0aWNhbCBhbmFseXNpcykKCmBgYHtyIHZhbGlkIHNhY2NhZGVzIHBlciBjZWxsfQp0cmlhbENvdW50ICU+JQogIGZpbHRlcighKHN1YmplY3QgJWluJSBzdWJzMmV4Y2x1ZGUpKSAlPiUgIyBmb3IgYWxsIGluY2x1ZGVkIHBhcnRpY2lwYW50cwogIGdyb3VwX2J5KHR5cGUpICU+JQogIHN1bW1hcmlzZShhdmVyYWdlID0gbWVhbihzYWNjYWRlcyksIHN0YW5kYXJkLmRldmlhdGlvbiA9IHNkKHNhY2NhZGVzKSwgbWluaW11bSA9IG1pbihzYWNjYWRlcyksIG1heGltdW0gPSBtYXgoc2FjY2FkZXMpKSAlPiUKICBrYWJsZSguKQpgYGAKCkxldCdzIGFsc28gbG9vayBhdCBwcm9wb3J0aW9uIG9mIHNhY2NhZGVzIGZvciBlYWNoIG91dGxpZXIgdHlwZToKCmBgYHtyIHByb3BvcnRpb24gb2Ygb3V0bGllciB0eXBlc30Kbl90b3RhbCA8LSBucm93KGZpbHRlcihncm91cERhdGEsICEoc3ViamVjdCAlaW4lIHN1YnMyZXhjbHVkZSkpKSAgIyB0b3RhbCBhbW91bnQgb2Ygc2FjY2FkZXMgYWNyb3NzIGFsbCBpbmNsdWRlZCBzZXNzaW9ucy9zdWJqZWN0cwpvdXRsaWVyQ291bnQgJT4lCiAgZmlsdGVyKCEoc3ViamVjdCAlaW4lIHN1YnMyZXhjbHVkZSksICEob3V0bGllciAlaW4lIGMoIm5vbi5vdXRsaWVyIiwgIm5vbmUiKSkpICU+JQogIGdyb3VwX2J5KG91dGxpZXIpICU+JQogIHN1bW1hcmlzZShwZXJjZW50YWdlID0gc3VtKG91dGxpZXJfY291bnQpIC8gbl90b3RhbCAqMTAwKSAlPiUKICBrYWJsZSguKQpgYGAKCgojIE91dGxpZXJzIGluIG1lZGlhbiBsYXRlbmN5CgpOZXh0IHRvIHJlamVjdGluZyBvdXRsaWVyIHRyaWFscywgd2UgY291bGQgYWxzbyBjb25zaWRlciByZWplY3Rpbmcgb3V0bGllciBzdWJqZWN0cyBvciBjZXJ0YWluIGNvbmRpdGlvbnMgZnJvbSB0aGUgc3RhdGlzdGljYWwgdGVzdHMuIE9uZSB3YXkgdG8gZGV0ZWN0IG91dGxpZXJzICh0aGF0IGlzIGl0c2VsZiByb2J1c3QgdG8gb3V0bGllcnMsIHVubGlrZSB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uKSBpcyB0aGUgTUFELW1lZGlhbiBydWxlIChzZWUgW3RoaXMgYmxvZ3Bvc3RdKGh0dHBzOi8vZXVyZWthc3RhdGlzdGljcy5jb20vdXNpbmctdGhlLW1lZGlhbi1hYnNvbHV0ZS1kZXZpYXRpb24tdG8tZmluZC1vdXRsaWVycy8pIGFuZCBbdGhpcyBwcmVwcmludF0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMTEwMS8xNTE4MTEpKS4gVGhlIE1BRCBpcyB0aGUgX21lZGlhbiBhYnNvbHV0ZSBkZXZpYW4gZnJvbSB0aGUgbWVkaWFuXy4KCmBgYHtyIFRhYmxlIG9mIG91dGxpZXJzIHBlciBzdWJqZWN0LWNvbmRpdGlvbiBjb21iaW5hdGlvbn0Kb3V0bGllcnNQZXJDb25kaXRpb24gPC0gZ3JvdXBEYXRhICU+JQogIGZpbHRlcihvdXRsaWVyID09ICJub24ub3V0bGllciIpICU+JSAjIGRyb3AgYWxsIG91dGxpZXIgdHJpYWxzCiAgZ3JvdXBfYnkoc3ViamVjdCxzdGltdWxhdGlvbixsZWcsdHlwZSxkaXJlY3Rpb24pICU+JQogIHN1bW1hcmlzZShsYXRlbmN5ID0gbWVkaWFuKGxhdGVuY3kpKSAlPiUgIyBjb21wdXRlIG1lZGlhbiBsYXRlbmN5CiAgZ3JvdXBfYnkoc3RpbXVsYXRpb24sbGVnLHR5cGUsZGlyZWN0aW9uKSAlPiUKICBtdXRhdGUobWFkLm1lZGlhbi5ydWxlID0gKGFicyhsYXRlbmN5IC0gbWVkaWFuKGxhdGVuY3kpKSAvIG1hZChsYXRlbmN5KSkpICU+JSAjIGRldmlhdGlvbiBmcm9tIHRoZSBtZWRpYW4sIHN0YW5kYXJkaXplZCBieSB0aGUgTUFECiAgZmlsdGVyKG1hZC5tZWRpYW4ucnVsZSA+IDIuMjQpICMgTUFELW1lZGlhbiBydWxlCmthYmxlKGhlYWQob3V0bGllcnNQZXJDb25kaXRpb24pKQpgYGAKClRoZXNlIGFyZSBhbGwgdGhlIHN1YmplY3QtY29uZGl0aW9uIGNvbWJpbmF0aW9ucyBmb3Igd2hpY2ggdGhlIE1BRC1tZWRpYW4gcnVsZSBpcyB2aW9sYXRlZC4gSWYgd2Ugd2VyZSB0byByZWplY3Qgc3ViamVjdHMgd2l0aCBvbmUgbW9yZSBtb3JlIHZpb2xhdGlvbiwgd2Ugd291bGQgaGF2ZSB0byByZW1vdmUgYHIgbGVuZ3RoKHVuaXF1ZShvdXRsaWVyc1BlckNvbmRpdGlvbiRzdWJqZWN0KSlgIHN1YmplY3RzLgoKVGhlcmUgaXMgc29tZSBvdmVybGFwIHdpdGggdGhlIGFuYWx5c2lzIG9mIG91dGxpZXIgdHJpYWxzLiBGb3IgaW5zdGFuY2UsIHRoZXJlIGlzIHJlYXNvbiB0byByZW1vdmUgUzI4IGluIGJvdGggYW5hbHlzZXMuIEJ1dCB0aGlzIGlzIG5vdCBhbHdheXMgdGhlIGNhc2U6IFMyNiBoYXMgdmVyeSBjbGVhbiB0cmlhbC1kYXRhLCBidXQgaXMgc3RpbGwgZmxhZ2dlZCBhcyBhbiBvdXRsaWVyIGhlcmUgYmVjYXVzZSB0aGVpciBtZWRpYW4gbGF0ZW5jaWVzIGFyZSBxdWl0ZSBzbG93LgoKIyBEcmlmdCBjb3JyZWN0aW9uCgpDYWxpYnJhdGlvbiBpc24ndCBwZXJmZWN0LCBzbyB0aGVyZSBhcmUgYWx3YXlzIHNtYWxsIG9mZnNldHMgYmV0d2VlbiB0aGUgbWVhc3VyZW1lbnRzIGFuZCB3aGF0IHBlb3BsZSBhcmUgYWN0dWFsbHkgbG9va2luZyBhdC4gRnVydGhlciwgdGhlc2UgbWVhc3VyZW1lbnQgZXJyb3JzIGNhbiBpbmNyZWFzZSB3aXRoIHRpbWUgYXdheSBmcm9tIGNhbGlicmF0aW9uLCB3aGljaCBpcyBrbm93biBhcyBkcmlmdC4KCkFmdGVyIGV2ZXJ5IDIwIHRyaWFscyAoNDAgc2FjY2FkZXMpIHRoZXJlIHdhcyBhIGJyZWFrIGluIHRoZSB0YXNrLCBpbiB3aGljaCB3ZSBhc2tlZCBzdWJqZWN0cyB0byBmaXhhdGUgdGhlIGNlbnRlciBvZiB0aGUgc2NyZWVuIGJlZm9yZSBjb250aW51ZWluZy4gVGhlIG9mZnNldHMgcmVjb3JkZWQgaGVyZSBzaG91bGQgdGh1cyBiZSBhIGdvb2QgZXN0aW1hdGUgb2YgZHJpZnQsIHNpbmNlIGhlcmUgeW91IGNhbiB0cnVzdCB0aGF0IHN1YmplY3RzIHdlcmUgYWN0dWFsbHkgbG9va2luZyBhdCBmaXhhdGlvbiBzcG90IG9uLiAKClRvIGRvIGRyaWZ0IGNvcnJlY3Rpb24sIHdlIHNpbXBseSBzdWJ0cmFjdCB0aGUgb2Zmc2V0cyByZWNvcmRlZCBpbiB0aGUgYnJlYWsgZnJvbSB0aGUgeC0gYW5kIHktIGNvb3JkaW5hdGVzIG9mIHRoZSBleWUgZGF0YSBvZiBpbnRlcmVzdC4KCmBgYHtyIERyaWZ0IGNvcnJlY3Rpb259CiMgQWRkIGNvbHVtbnMgd2l0aCBkcmlmdC1jb3JyZWN0ZWQgdmFsdWVzCmdyb3VwRGF0YSA8LSBtdXRhdGUoZ3JvdXBEYXRhLAogICAgICAgICAgICAgICAgICAgIGRldmlhdGlvbi5lbmQueC5jb3JyID0gZGV2aWF0aW9uLmVuZC54IC0gZHJpZnQueCwKICAgICAgICAgICAgICAgICAgICBkZXZpYXRpb24uZW5kLnkuY29yciA9IGRldmlhdGlvbi5lbmQueSAtIGRyaWZ0LnkpCmBgYAoKSWYgdGhpcyBkb2VzIGluZGVlZCB3b3JrLCB0aGVuIG1vc3QgdHJpYWxzIHNob3VsZCBub3cgaGF2ZSBhIHNtYWxsZXIgZGV2aWF0aW9uLgoKYGBge3IgQ2hlY2sgY29ycmVjdGlvbn0KIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBvZiB0cmlhbHMgd2l0aCBzbWFsbGVyIGRldmlhdGlvbnMgYWZ0ZXIgZHJpZnQgY29ycmVjdGlvbgpncm91cERhdGEgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdCwgc3RpbXVsYXRpb24pICU+JSAjIHNwbGl0IHBlciBzdWJqZWN0IGFuZCBzZXNzaW9uCiAgc3VtbWFyaXplKAogICAgdHJpYWxzID0gbigpLAogICAgc21hbGxlci5kcmlmdC54ID0gc3VtKGFicyhkZXZpYXRpb24uZW5kLnguY29ycikgPCBhYnMoZGV2aWF0aW9uLmVuZC54KSwgbmEucm0gPSBUUlVFKSAvIHRyaWFscyAqIDEwMCwKICAgIHNtYWxsZXIuZHJpZnQueSA9IHN1bShhYnMoZGV2aWF0aW9uLmVuZC55LmNvcnIpIDwgYWJzKGRldmlhdGlvbi5lbmQueSksIG5hLnJtID0gVFJVRSkgLyB0cmlhbHMgKiAxMDAKICApICU+JQogIAogICMgUGxvdAogIGdncGxvdChhZXMoc21hbGxlci5kcmlmdC54LCBzbWFsbGVyLmRyaWZ0LnkpKSArCiAgZmFjZXRfd3JhcCh+c3RpbXVsYXRpb24pICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1MCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA1MCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gc3ViamVjdCkpICsKICBjb29yZF9maXhlZCh4bGltID0gYygwLDEwMCksIHlsaW0gPSBjKDAsMTAwKSkgKwogICNnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gc3ViamVjdCwgY29sb3IgPSBzdWJqZWN0KSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgClNlZW1zIHRoYXQgaXQgZG9lc24ndCByZWFsbHkgd29yayBhdCBhbGwsIGJlY2F1c2UgZm9yIG1vc3Qgc3ViamVjdHMgdGhlIGVycm9ycyBhcmUgZGVjcmVhc2VkIG9uIGxlc3MgdGhhbiA1MCUgb2Ygc2FjY2FkZXMhIE9mIGNvdXJzZSwgdGhpcyBpcyBvbmx5IGEgcm91Z2ggYW5hbHlzaXMsIGJ1dCB0aGlzIGRvZXMgbWF0Y2ggd2l0aCBTUiBSZXNlYXJjaCdzIGFkdmljZSBpbiB0aGUgRXllTGluayBtYW51YWwsIHdoaWNoIHN0YXRlcyB0aGF0IGRyaWZ0IGNvcnJlY3Rpb24gbWF5IGFjdHVhbGx5IGRldGVyaW9yYXRlIHRoZSBjYWxpYnJhdGlvbiBtYXBzLg==