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")
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))
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(.)
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(.)
fast |
1.9958600 |
fixation |
2.5848024 |
saccade |
0.1555823 |
slow |
0.1161859 |
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==