Followup
The question came up last time about why it really matters to center and scale our predictors. Here is an example of a data set I’ve looked at, which involves the raising of /ay/ before voiceless consonants. A very strong predictor is the speaker’s year of birth.
ay0_means <- ay0 %>%
mutate(dob = year-age)%>%
group_by(idstring,dob, word)%>%
summarise(F1_n = mean(F1_n))%>%
summarise(F1_n = mean(F1_n))
ggplot(ay0_means, aes(dob, F1_n))+
geom_point()+
scale_y_reverse()+
theme_minimal()
But if I just fit a linear model with year of birth as a predictor, I get an entirely uninterpretable intercept value that is actually impossible given the data.
ay0_model <- lm(F1_n ~ dob, data = ay0_means)
summary(ay0_model)
Call:
lm(formula = F1_n ~ dob, data = ay0_means)
Residuals:
Min 1Q Median 3Q Max
-1.03831 -0.16668 -0.01521 0.16445 1.06611
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 23.2970421 1.1782669 19.77 <2e-16 ***
dob -0.0116366 0.0006059 -19.20 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.2506 on 324 degrees of freedom
Multiple R-squared: 0.5324, Adjusted R-squared: 0.5309
F-statistic: 368.8 on 1 and 324 DF, p-value: < 2.2e-16
ggplot(ay0_means, aes(dob, F1_n))+
geom_point()+
geom_vline(xintercept = 0, linetype = 2)+
geom_hline(yintercept = coef(ay0_model)[1], linetype = 2)+
geom_abline(intercept = coef(ay0_model)[1],
slope = coef(ay0_model)[2])+
theme_minimal()
The slope is also too specific, from a theoretical perspective. We wouldn’t realistically expect to see reliable differences between people born in 1959 and 1960. In my own work, I’ve divided year of birth by 10, resulting in a coefficient readable as a change per decade. Labov (2001) divides year of birth by 25, to try to get a slope in terms of a “generation”. Either way works.
ay0_means <- ay0_means %>%
mutate(dob_c = (dob-1960)/10)
ay0_model2 <- lm(F1_n ~ dob_c, data = ay0_means)
summary(ay0_model2)
Call:
lm(formula = F1_n ~ dob_c, data = ay0_means)
Residuals:
Min 1Q Median 3Q Max
-1.03831 -0.16668 -0.01521 0.16445 1.06611
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.489214 0.016775 29.16 <2e-16 ***
dob_c -0.116366 0.006059 -19.20 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.2506 on 324 degrees of freedom
Multiple R-squared: 0.5324, Adjusted R-squared: 0.5309
F-statistic: 368.8 on 1 and 324 DF, p-value: < 2.2e-16
Another important factor in choosing where you center your predictors is if there’s a strong interaction with some other predictor. For example, this plot compares pre-voiced to pre-voiceless [ay]. It is possible model this entire graph in one model that has an interaction between voicing and date of birth. But where you choose to center date of birth will have a big effect on the estimated parameters! Compare the models with DOB centered on 1890 vs 1950.
ay_means <- ay %>%
mutate(dob = year-age)%>%
group_by(idstring, dob, plt_vclass, word)%>%
summarise(F1_n = mean(F1_n)) %>%
summarise(F1_n = mean(F1_n))
ay_means %>%
ggplot(aes(dob, F1_n, color = plt_vclass))+
geom_point()+
stat_smooth(method = 'lm')+
geom_vline(xintercept = 1890, linetype = 2)+
geom_vline(xintercept = 1950, linetype = 2)+
annotate(geom = "label",
x = 1890,
y = -0.25,
label = "a")+
annotate(geom = "label",
x = 1950,
y = -0.25,
label = "b")+
scale_y_reverse()+
scale_color_colorblind()+
theme_minimal()
ay_means <- ay_means %>%
mutate(dob_center_a = (dob - 1890) / 10,
dob_center_b = (dob - 1950) / 10)
ay_model_a <- lm(F1_n ~ dob_center_a * plt_vclass, data = ay_means)
ay_model_b <- lm(F1_n ~ dob_center_b * plt_vclass, data = ay_means)
tidy(ay_model_a) %>% select(term, estimate, p.value)
tidy(ay_model_b) %>% select(term, estimate, p.value)
In the model with the 1890 as the intercept, the coefficient for ay0
is small, and not significant! In the model with dob centered at 1950, the coefficient for ay0
is large and very significant. This is simply because they are describing different locations on the plot.
So what is the “right” thing to do?
At this point is usualy when the “So what’s the right thing to do?” question comes up. And the annoying answer is that there isn’t a clear cut answer or decision process. You should guide your decisions to be sure that
- You have a sensible intercept.
- Your slopes are defined across a reasonable range for the data.
For many data types, the Gelman & Hill (2006) recommendation (subtract the mean, divide by 2\(\times\) the standard deviation) will do the trick. For others, there may be some people making a top-down effort to define a scaling (e.g. the Zipf Scale for word frequencies). For the remaining cases, if someone has done something before and it doesn’t seem obviously wrong, try that for the sake of comparibility. Otherwise, it involves a lot of development of a model-gefühl.
More model interpretation
Let’s come back to modelling the effect of duration on the F1 of ah
. Here, we’ll fit the model using the centered log2(duration) like a recommended on the homework.
ah_tomod <- ah %>%
mutate(log2dur_c = log2(dur)-median(log2(dur)))
ah_tomod %>%
ggplot(aes(log2dur_c, F1_n))+
geom_point(alpha = 0.05)+
xlab("centered log2(duration)")+
theme_minimal()
ah_model <- lm(F1_n ~ log2dur_c, data = ah_tomod)
summary(ah_model)
Call:
lm(formula = F1_n ~ log2dur_c, data = ah_tomod)
Residuals:
Min 1Q Median 3Q Max
-3.4740 -0.3717 0.0102 0.3827 3.2640
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.061795 0.004260 249.2 <2e-16 ***
log2dur_c 0.388204 0.006957 55.8 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.6185 on 21117 degrees of freedom
Multiple R-squared: 0.1285, Adjusted R-squared: 0.1285
F-statistic: 3113 on 1 and 21117 DF, p-value: < 2.2e-16
The intercept is the estimated F1_n at the median duration, and the slope log2dur_c
is the estimated increase in normalized F1 for every doubling of duration. Let’s walk through these results more slowly.
Residuals
This is a so-called “five number summary” of the residuals (the difference between the fitted line and the actual data points). Given the assumptions that the model makes (e.g. the data can be described by a line with some residual error), you’ll want to see these values being fairly symmetrical, with the median just about 0. If this isn’t the case, then you should probably make some more plots of the data to figure out what’s going on.
Standard Error and t-value
These are fairly straightforward measures of the uncertainty about the coefficient estimates that you can reason about safely without having taken a philosophy course. The bigger the standard error, the less certainty there is about the the parameters. The t-value is just the coefficient divided by the standard error, so the bigger it is, the more certainty there is. Roughly speaking, if the t-value is greater than 2, the effect is probably reliable.
\(r^2\)
This is a measure of how much modelling your outcome data as a straight line with your chosen predictors has reduced the variability in the data. This is a helpful enough heuristic, but can’t be taken as an intrinsically informative value. We can roughly visualize this by plotting density distributions of our data (centered on the mean) and the model residuals.
ah_tomod %>%
ggplot(aes(log2dur_c, F1_n))+
geom_point(alpha = 0.05)+
geom_hline(yintercept = mean(ah_tomod$F1_n))+
geom_abline(intercept = coef(ah_model)[1],
slope = coef(ah_model)[2],
color = "red")+
theme_minimal()
ah_tomod$resid <- resid(ah_model)
ah_tomod %>%
mutate(F1_n_c = F1_n - mean(F1_n))%>%
ggplot()+
geom_density(aes(x = F1_n_c, color = "centered data"))+
geom_density(aes(x = resid, color = "residuals"))+
theme_minimal()+
ggtitle(paste0("r-squared = ", round(summary(ah_model)$r.squared, digits = 2)))+
scale_color_manual(NULL, values = c("black", "red"))
The distribution of the residuals in red is just slightly narrower than the data, which is why the r-squared is fairly modest.
Sometimes you can get a really large r-squared by including a big and obvious predictor, that doesn’t really contribute to our understanding. For example, for the whole iy_ah
data set, the largest number one predictor for the model is the vowel class, since iy
and ah
are contrastively different along F1.
iy_ah_model <- lm(F1_n ~ plt_vclass, data = iy_ah)
summary(iy_ah_model)
Call:
lm(formula = F1_n ~ plt_vclass, data = iy_ah)
Residuals:
Min 1Q Median 3Q Max
-3.0714 -0.3278 -0.0125 0.3269 4.8163
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.072222 0.003850 278.5 <2e-16 ***
plt_vclassiy -2.495949 0.005294 -471.4 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.5595 on 44816 degrees of freedom
Multiple R-squared: 0.8322, Adjusted R-squared: 0.8322
F-statistic: 2.222e+05 on 1 and 44816 DF, p-value: < 2.2e-16
iy_ah$resid <- resid(iy_ah_model)
iy_ah %>%
mutate(F1_n_c = F1_n - mean(F1_n))%>%
ggplot()+
geom_density(aes(x = F1_n_c, color = "centered data"))+
geom_density(aes(x = resid, color = "residuals"))+
theme_minimal()+
ggtitle(paste0("r-squared = ", round(summary(iy_ah_model)$r.squared, digits = 2)))+
scale_color_manual(NULL, values = c("black", "red"))
R-squared is probably best used when comparing two models. For an example, see the bar plots on page 12 of this paper.
Interpreting other people’s models
More or less, if you see someone report only the p-value for their effects without the coefficients, especially if they’re working with a lot of data, reach for your wallet. If you are reviewing a paper where this happens, make it a required revision that either they need to include the coefficients, or drop that quantitative component.
Pitfalls in Modelling
Type I and Type II Error
These are poorly named, and I think few people remember which is which correctly the first time. These are errors related to the use of p-values. First it’s important to define what the Null Hypothesis is.
- The Null Hypothesis is the Dull Hypothesis: The Null Hypothesis is that there is no relationship between the outcome and predictors. It is not what you think the most likely relationship is.
With that in mind, we can define Type I and Type II errors.
- Type I - You reject the null hypothesis (because p < 0.05), but in reality there isn’t a relationship. That is, you say there is a reliable effect when there isn’t one.
- Type II - You fail to reject the null hypotehsis when there is an real effect.
Or to put it another way, when you see a statistical result that is significant (p < 0.05), but you don’t think it could possibly be real, you think a Type I error has occurred.
And when you get p > 0.05, but you really think there’s something there so you put “trending towards significance” in your paper, you think a Type II error has occurred.
The best way to ameliorate Type I and Type II errors is to either collect more data, or to move to Bayesian Statistics, which we won’t be able to cover in this course, but I recommend this book.
Type M and Type S errors
These are error types discussed by Gelman and colleagues (and are better named).
- Type M Errors are gross over-estimation of the magnitude of an effect size.
- Type S Errors get the sign wrong on an estimate. That is, they predict an effect in the opposite direction of what the true effect is.
Type M might not sound like a very big problem, and Type S might sound a bit outlandish but these can both happen, especially when we are exploring for small effects and filtering results by their p-values. Gelman has proposed that Type M errors are a likely culprit in the so-called “decline effect”, which is a phenomenon some have found that large and significant effects gradually get smaller after their original reports.
Here are some ways to guard youself against Type M and Type S errors.
- Try to reason how big the effect is likely to be.
- Try to collect of how other factors effect the outcome you’re investigating, and how big those effects are.
- Commit to the direction of the effect.
Type M and Type S errors are only going to grow in severity as the size of data sets grow.
Overfitting
Collinearity
“Collinearity” is when two potential predictors are highly correlated with each other. When two correlated predictors are included in the same regression, the results can be wonky at best. Gorman (2010) talks about this at length with respect to socioeconomic measures in the Language Change and Variation study. For example, speakers’ Occupation was highly correlated with the value of their Residence. You shouldn’t include these both, untreated, into your models.
There are at least three different strategies for dealing with this issue
- If you must model these factors independently, residualize (Gorman, 2010)
- Or, just pick the one that is theoretically motivated (Fruehwald, 2016).
- Or give up on treating your measures as having independent reality, realize they are reflections of more abstract dimensions, and try to figure out what those are (i.e. factor analysis, Walker (2016)).
Residualization
Like the name suggests, this involves the residuals from a linear model. If you really want to fit a model like this:
negative_concord ~ occupation + residence
Then what you need to do first is fit this model.
residence ~ occupation
And replace the residence
term in the first model with the residuals of the second model. Now, it does matter which order you residualize in. How do you choose? Again, there’s no hard and fast answer, but please don’t try it every possible way and then just choose the model that looks best!
Factor Analysis
Another approach would be to abandon trying to look at all of these predictors independently and to treat them all as rough measures correlated to a more abstract variable, using something like a factor analysis. This is what Walker (2016) did.
The best way to explain a factor analysis is to imagine surveying a bunch of people on the street and asking them the following questions:
- Did you have the heat on this morning?
- Are you wearing a wooly jumper?
- Are you wearing a scarf?
- Could you see your breath when you stepped outside?
- Did your glasses fog up when you walked inside?
- Did you make yourself a big breakfast?
- Was your stomach growling when you woke up?
This looks like you’ve asked people 7 different questions, but really, you’ve only effectively asked 2 questions:
- Was it cold?
- Were you hungry?
If you took the raw data from the 7 question survey and ran it through a factor analysis, it would (ideally) tell you that there are only 2 effective questions in it, based on how responses to questions 1 thru 5 are correlated with each other, and 6&7 are correlated with each other.
Collinearity often comes up as a pitfall of of estimating effects. But it’s also an issue when trying to understand our models. A common, annoying, and usually valid question is:
Couldn’t your effect of A actually be an effect of B?
The best way to deal with this kind of collinearity is to try to kill your effects. Does the same effect hold in the same direction for important subsets of the data? Can you subset the data according to B and fit separate models for A?
Additional Structure
LS0tCnRpdGxlOiAiTW9yZSBvbiBpbnRlcnByZXRpbmcgJiBmaXR0aW5nIGxpbmVhciBtb2RlbHMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IG5vbmUKICAgIGNzczogLi4vY3VzdG9tLmNzcwogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfZGVwdGg6IDMKLS0tCgoKCiMgVGhlIEFnZW5kYQoKMS4gRm9sbG93IHVwIGZyb20gdGhlIGxhc3QgbWVldGluZy4KMi4gTW9yZSBhYm91dCBpbnRlcnByZXRpbmcgdGhlIG1vZGVsIG91dHB1dAozLiBIb21ld29yayByZXZpZXcKMy4gUGl0ZmFsbHMgdG8gbG9vayBvdXQgZm9yLCBhbmQgaG93IHRvIGFkZHJlc3MgdGhlbQo0LiBBIG1vZGVsbGluZyBtZW51CgoKPGRpdiBjbGFzcyA9ICJib3ggYnJlYWsiPgo8c3BhbiBjbGFzcyA9ICJiaWctbGFiZWwiPlNldHVwPC9zcGFuPgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KGxzYTIwMTcpCgphaCA8LSBpeV9haCAlPiUgZmlsdGVyKHBsdF92Y2xhc3MgPT0gImFoIikKaXkgPC0gaXlfYWggJT4lIGZpbHRlcihwbHRfdmNsYXNzID09ICJpeSIpCmF5MCA8LSBheSAlPiUgZmlsdGVyKHBsdF92Y2xhc3MgPT0gImF5MCIpCmBgYAoKCkFuZCwgaW4gcHJlcGFyYXRpb24gb2YgVGh1cnNkYXkncyBtZWV0aW5nLCBnbyBhaGVhZCBhbmQgaW5zdGFsbCBgbG1lNGAsIHNvIHdlIGNhbiBjYXRjaCBhbnkgcHJvYmxlbXMgd2VsbCBpbiBhZHZhbmNlLgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoImxtZTQiKQpgYGAKCjwvZGl2PgoKIyBGb2xsb3d1cAoKVGhlIHF1ZXN0aW9uIGNhbWUgdXAgbGFzdCB0aW1lIGFib3V0IHdoeSBpdCByZWFsbHkgbWF0dGVycyB0byBjZW50ZXIgYW5kIHNjYWxlIG91ciBwcmVkaWN0b3JzLiBIZXJlIGlzIGFuIGV4YW1wbGUgb2YgYSBkYXRhIHNldCBJJ3ZlIGxvb2tlZCBhdCwgd2hpY2ggaW52b2x2ZXMgdGhlIHJhaXNpbmcgb2YgL2F5LyBiZWZvcmUgdm9pY2VsZXNzIGNvbnNvbmFudHMuIEEgdmVyeSBzdHJvbmcgcHJlZGljdG9yIGlzIHRoZSBzcGVha2VyJ3MgeWVhciBvZiBiaXJ0aC4KCgpgYGB7cn0KYXkwX21lYW5zIDwtIGF5MCAlPiUKICAgICAgICAgICAgICBtdXRhdGUoZG9iID0geWVhci1hZ2UpJT4lCiAgICAgICAgICAgICAgZ3JvdXBfYnkoaWRzdHJpbmcsZG9iLCB3b3JkKSU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZShGMV9uID0gbWVhbihGMV9uKSklPiUKICAgICAgICAgICAgICBzdW1tYXJpc2UoRjFfbiA9IG1lYW4oRjFfbikpCgpnZ3Bsb3QoYXkwX21lYW5zLCBhZXMoZG9iLCBGMV9uKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBzY2FsZV95X3JldmVyc2UoKSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKCgpCdXQgaWYgSSBqdXN0IGZpdCBhIGxpbmVhciBtb2RlbCB3aXRoIHllYXIgb2YgYmlydGggYXMgYSBwcmVkaWN0b3IsIEkgZ2V0IGFuIGVudGlyZWx5IHVuaW50ZXJwcmV0YWJsZSBpbnRlcmNlcHQgdmFsdWUgdGhhdCBpcyBhY3R1YWxseSAqaW1wb3NzaWJsZSogZ2l2ZW4gdGhlIGRhdGEuCgpgYGB7cn0KYXkwX21vZGVsIDwtIGxtKEYxX24gfiBkb2IsIGRhdGEgPSBheTBfbWVhbnMpCnN1bW1hcnkoYXkwX21vZGVsKQpgYGAKCgpgYGB7cn0KZ2dwbG90KGF5MF9tZWFucywgYWVzKGRvYiwgRjFfbikpKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGNvZWYoYXkwX21vZGVsKVsxXSwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGNvZWYoYXkwX21vZGVsKVsxXSwKICAgICAgICAgICAgICAgIHNsb3BlID0gY29lZihheTBfbW9kZWwpWzJdKSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKClRoZSBzbG9wZSBpcyBhbHNvIHRvbyBzcGVjaWZpYywgZnJvbSBhIHRoZW9yZXRpY2FsIHBlcnNwZWN0aXZlLiBXZSB3b3VsZG4ndCByZWFsaXN0aWNhbGx5IGV4cGVjdCB0byBzZWUgcmVsaWFibGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBwZW9wbGUgYm9ybiBpbiAxOTU5IGFuZCAxOTYwLiBJbiBteSBvd24gd29yaywgSSd2ZSBkaXZpZGVkIHllYXIgb2YgYmlydGggYnkgMTAsIHJlc3VsdGluZyBpbiBhIGNvZWZmaWNpZW50IHJlYWRhYmxlIGFzIGEgY2hhbmdlIHBlciBkZWNhZGUuIExhYm92ICgyMDAxKSBkaXZpZGVzIHllYXIgb2YgYmlydGheW0FjdHVhbGx5LCB0aGUgcmVzY2FsZWQgcHJlZGljdG9yIHdhcyAiYWdlIiwgYnV0IGluIHRoYXQgZGF0YSBpdCBoYWQgbW9yZSBvciBsZXNzIGEgMS10by0xIHJlbGF0aW9uc2lwIHRvIHllYXIgb2YgYmlydGguXSBieSAyNSwgdG8gdHJ5IHRvIGdldCBhIHNsb3BlIGluIHRlcm1zIG9mIGEgImdlbmVyYXRpb24iLiBFaXRoZXIgd2F5IHdvcmtzLgoKYGBge3J9CmF5MF9tZWFucyA8LSBheTBfbWVhbnMgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGUoZG9iX2MgPSAoZG9iLTE5NjApLzEwKQpheTBfbW9kZWwyIDwtIGxtKEYxX24gfiBkb2JfYywgZGF0YSA9IGF5MF9tZWFucykKc3VtbWFyeShheTBfbW9kZWwyKQpgYGAKCkFub3RoZXIgaW1wb3J0YW50IGZhY3RvciBpbiBjaG9vc2luZyB3aGVyZSB5b3UgY2VudGVyIHlvdXIgcHJlZGljdG9ycyBpcyBpZiB0aGVyZSdzIGEgc3Ryb25nIGludGVyYWN0aW9uIHdpdGggc29tZSBvdGhlciBwcmVkaWN0b3IuIEZvciBleGFtcGxlLCB0aGlzIHBsb3QgY29tcGFyZXMgcHJlLXZvaWNlZCB0byBwcmUtdm9pY2VsZXNzIFtheV0uIEl0IGlzIHBvc3NpYmxlIG1vZGVsIHRoaXMgZW50aXJlIGdyYXBoIGluIG9uZSBtb2RlbCB0aGF0IGhhcyBhbiBpbnRlcmFjdGlvbiBiZXR3ZWVuIHZvaWNpbmcgYW5kIGRhdGUgb2YgYmlydGguIEJ1dCB3aGVyZSB5b3UgY2hvb3NlIHRvIGNlbnRlciBkYXRlIG9mIGJpcnRoIHdpbGwgaGF2ZSBhIGJpZyBlZmZlY3Qgb24gdGhlIGVzdGltYXRlZCBwYXJhbWV0ZXJzISBDb21wYXJlIHRoZSBtb2RlbHMgd2l0aCBET0IgY2VudGVyZWQgb24gMTg5MCB2cyAxOTUwLgoKCmBgYHtyfQpheV9tZWFucyA8LSBheSAlPiUKICAgICAgICAgICAgICBtdXRhdGUoZG9iID0geWVhci1hZ2UpJT4lCiAgICAgICAgICAgICAgZ3JvdXBfYnkoaWRzdHJpbmcsIGRvYiwgcGx0X3ZjbGFzcywgd29yZCklPiUKICAgICAgICAgICAgICBzdW1tYXJpc2UoRjFfbiA9IG1lYW4oRjFfbikpICU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZShGMV9uID0gbWVhbihGMV9uKSkKCmF5X21lYW5zICU+JQogIGdncGxvdChhZXMoZG9iLCBGMV9uLCBjb2xvciA9IHBsdF92Y2xhc3MpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIHN0YXRfc21vb3RoKG1ldGhvZCA9ICdsbScpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMTg5MCwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDE5NTAsIGxpbmV0eXBlID0gMikrICAKICAgIGFubm90YXRlKGdlb20gID0gImxhYmVsIiwKICAgICAgICAgICAgIHggPSAxODkwLAogICAgICAgICAgICAgeSA9IC0wLjI1LAogICAgICAgICAgICAgbGFiZWwgPSAiYSIpKwogICAgYW5ub3RhdGUoZ2VvbSAgPSAibGFiZWwiLAogICAgICAgICAgICAgeCA9IDE5NTAsCiAgICAgICAgICAgICB5ID0gLTAuMjUsCiAgICAgICAgICAgICBsYWJlbCA9ICJiIikrICAKICAgIHNjYWxlX3lfcmV2ZXJzZSgpKwogICAgc2NhbGVfY29sb3JfY29sb3JibGluZCgpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKYGBge3J9CmF5X21lYW5zIDwtIGF5X21lYW5zICU+JQogICAgICAgICAgICAgIG11dGF0ZShkb2JfY2VudGVyX2EgPSAoZG9iIC0gMTg5MCkgLyAxMCwKICAgICAgICAgICAgICAgICAgICAgZG9iX2NlbnRlcl9iID0gKGRvYiAtIDE5NTApIC8gMTApCgpheV9tb2RlbF9hIDwtIGxtKEYxX24gfiBkb2JfY2VudGVyX2EgKiBwbHRfdmNsYXNzLCBkYXRhID0gYXlfbWVhbnMpCmF5X21vZGVsX2IgPC0gbG0oRjFfbiB+IGRvYl9jZW50ZXJfYiAqIHBsdF92Y2xhc3MsIGRhdGEgPSBheV9tZWFucykKYGBgCgo8ZGl2IHN0eWxlID0gImZsb2F0OmxlZnQ7IHdpZHRoOjEwMCUiPgo8ZGl2IHN0eWxlID0gImZsb2F0OmxlZnQ7IHdpZHRoOjQ5JSI+CgpgYGB7cn0KdGlkeShheV9tb2RlbF9hKSAlPiUgc2VsZWN0KHRlcm0sIGVzdGltYXRlLCBwLnZhbHVlKQpgYGAKPC9kaXY+CjxkaXYgc3R5bGUgPSAiZmxvYXQ6bGVmdDsgd2lkdGg6NDklIj4KYGBge3J9CnRpZHkoYXlfbW9kZWxfYikgJT4lIHNlbGVjdCh0ZXJtLCBlc3RpbWF0ZSwgcC52YWx1ZSkKYGBgCjwvZGl2Pgo8L2Rpdj4KCkluIHRoZSBtb2RlbCB3aXRoIHRoZSAxODkwIGFzIHRoZSBpbnRlcmNlcHQsIHRoZSBjb2VmZmljaWVudCBmb3IgYGF5MGAgaXMgc21hbGwsIGFuZCBub3Qgc2lnbmlmaWNhbnQhIEluIHRoZSBtb2RlbCB3aXRoIGRvYiBjZW50ZXJlZCBhdCAxOTUwLCB0aGUgY29lZmZpY2llbnQgZm9yIGBheTBgIGlzIGxhcmdlIGFuZCB2ZXJ5IHNpZ25pZmljYW50LiBUaGlzIGlzIHNpbXBseSBiZWNhdXNlIHRoZXkgYXJlIGRlc2NyaWJpbmcgZGlmZmVyZW50IGxvY2F0aW9ucyBvbiB0aGUgcGxvdC4KCiMjIFNvIHdoYXQgaXMgdGhlICJyaWdodCIgdGhpbmcgdG8gZG8/CgpBdCB0aGlzIHBvaW50IGlzIHVzdWFseSB3aGVuIHRoZSAiU28gd2hhdCdzIHRoZSByaWdodCB0aGluZyB0byBkbz8iIHF1ZXN0aW9uIGNvbWVzIHVwLiBBbmQgdGhlIGFubm95aW5nIGFuc3dlciBpcyB0aGF0IHRoZXJlIGlzbid0IGEgY2xlYXIgY3V0IGFuc3dlciBvciBkZWNpc2lvbiBwcm9jZXNzLiBZb3Ugc2hvdWxkIGd1aWRlIHlvdXIgZGVjaXNpb25zIHRvIGJlIHN1cmUgdGhhdAoKMS4gWW91IGhhdmUgYSBzZW5zaWJsZSBpbnRlcmNlcHQuCjIuIFlvdXIgc2xvcGVzIGFyZSBkZWZpbmVkIGFjcm9zcyBhIHJlYXNvbmFibGUgcmFuZ2UgZm9yIHRoZSBkYXRhLgoKRm9yIG1hbnkgZGF0YSB0eXBlcywgdGhlIEdlbG1hbiAmIEhpbGwgKDIwMDYpIHJlY29tbWVuZGF0aW9uIChzdWJ0cmFjdCB0aGUgbWVhbiwgZGl2aWRlIGJ5IDIkXHRpbWVzJCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uKSB3aWxsIGRvIHRoZSB0cmljay4gRm9yIG90aGVycywgdGhlcmUgbWF5IGJlIHNvbWUgcGVvcGxlIG1ha2luZyBhIHRvcC1kb3duIGVmZm9ydCB0byBkZWZpbmUgYSBzY2FsaW5nIChlLmcuIHRoZSBbWmlwZiBTY2FsZSBmb3Igd29yZCBmcmVxdWVuY2llc10oaHR0cDovL2Nyci51Z2VudC5iZS9hcmNoaXZlcy8xMzUyKSkuIEZvciB0aGUgcmVtYWluaW5nIGNhc2VzLCBpZiBzb21lb25lIGhhcyBkb25lIHNvbWV0aGluZyBiZWZvcmUgYW5kIGl0IGRvZXNuJ3Qgc2VlbSBvYnZpb3VzbHkgd3JvbmcsIHRyeSB0aGF0IGZvciB0aGUgc2FrZSBvZiBjb21wYXJpYmlsaXR5LiBPdGhlcndpc2UsIGl0IGludm9sdmVzIGEgbG90IG9mIGRldmVsb3BtZW50IG9mIGEgbW9kZWwtZ2Vmw7xobC4KCgojIE1vcmUgbW9kZWwgaW50ZXJwcmV0YXRpb24KCkxldCdzIGNvbWUgYmFjayB0byBtb2RlbGxpbmcgdGhlIGVmZmVjdCBvZiBkdXJhdGlvbiBvbiB0aGUgRjEgb2YgYGFoYC4gCkhlcmUsIHdlJ2xsIGZpdCB0aGUgbW9kZWwgdXNpbmcgdGhlIGNlbnRlcmVkIGxvZzIoZHVyYXRpb24pIGxpa2UgYSByZWNvbW1lbmRlZCBvbiB0aGUgaG9tZXdvcmsuCgoKYGBge3IgZmlnLndpZHRoID0gOC8yLCBmaWcuaGVpZ2h0ID0gNS8yLCBvdXQud2lkdGggPSAiNTAlIn0KYWhfdG9tb2QgPC0gYWggJT4lCiAgICAgICAgICAgICAgIG11dGF0ZShsb2cyZHVyX2MgPSBsb2cyKGR1ciktbWVkaWFuKGxvZzIoZHVyKSkpCmFoX3RvbW9kICU+JQogIGdncGxvdChhZXMobG9nMmR1cl9jLCBGMV9uKSkrCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4wNSkrCiAgICB4bGFiKCJjZW50ZXJlZCBsb2cyKGR1cmF0aW9uKSIpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKYGBge3J9CmFoX21vZGVsIDwtIGxtKEYxX24gfiBsb2cyZHVyX2MsIGRhdGEgPSBhaF90b21vZCkKc3VtbWFyeShhaF9tb2RlbCkKYGBgCgpUaGUgaW50ZXJjZXB0IGlzIHRoZSBlc3RpbWF0ZWQgRjFfbiBhdCB0aGUgbWVkaWFuIGR1cmF0aW9uLCBhbmQgdGhlIHNsb3BlIGBsb2cyZHVyX2NgIGlzIHRoZSBlc3RpbWF0ZWQgaW5jcmVhc2UgaW4gbm9ybWFsaXplZCBGMSBmb3IgZXZlcnkgZG91Ymxpbmcgb2YgZHVyYXRpb24uCkxldCdzIHdhbGsgdGhyb3VnaCB0aGVzZSByZXN1bHRzIG1vcmUgc2xvd2x5LgoKIyMgUmVzaWR1YWxzCgo8ZGl2IGNsYXNzID0gImhhbGYtaW1nIj4KIVtdKGZpZ3VyZXMvcmVzaWQucG5nKQo8L2Rpdj4KClRoaXMgaXMgYSBzby1jYWxsZWQgImZpdmUgbnVtYmVyIHN1bW1hcnkiIG9mIHRoZSByZXNpZHVhbHMgKHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGZpdHRlZCBsaW5lIGFuZCB0aGUgYWN0dWFsIGRhdGEgcG9pbnRzKS4KR2l2ZW4gdGhlIGFzc3VtcHRpb25zIHRoYXQgdGhlIG1vZGVsIG1ha2VzIChlLmcuIHRoZSBkYXRhIGNhbiBiZSBkZXNjcmliZWQgYnkgYSBsaW5lIHdpdGggc29tZSByZXNpZHVhbCBlcnJvciksIHlvdSdsbCB3YW50IHRvIHNlZSB0aGVzZSB2YWx1ZXMgYmVpbmcgZmFpcmx5IHN5bW1ldHJpY2FsLCB3aXRoIHRoZSBtZWRpYW4ganVzdCBhYm91dCAwLiBJZiB0aGlzIGlzbid0IHRoZSBjYXNlLCB0aGVuIHlvdSBzaG91bGQgcHJvYmFibHkgbWFrZSBzb21lIG1vcmUgcGxvdHMgb2YgdGhlIGRhdGEgdG8gZmlndXJlIG91dCB3aGF0J3MgZ29pbmcgb24uCgojIyBTdGFuZGFyZCBFcnJvciBhbmQgdC12YWx1ZQoKPGRpdiBjbGFzcyA9ICJoYWxmLWltZyI+CgohW10oZmlndXJlcy9zdGRlcnIucG5nKQoKPC9kaXY+CgpUaGVzZSBhcmUgZmFpcmx5IHN0cmFpZ2h0Zm9yd2FyZCBtZWFzdXJlcyBvZiB0aGUgdW5jZXJ0YWludHkgYWJvdXQgdGhlIGNvZWZmaWNpZW50IGVzdGltYXRlcyB0aGF0IHlvdSBjYW4gcmVhc29uIGFib3V0IHNhZmVseSB3aXRob3V0IGhhdmluZyB0YWtlbiBhIHBoaWxvc29waHkgY291cnNlLiBUaGUgYmlnZ2VyIHRoZSBzdGFuZGFyZCBlcnJvciwgdGhlIGxlc3MgY2VydGFpbnR5IHRoZXJlIGlzIGFib3V0IHRoZSB0aGUgcGFyYW1ldGVycy4gVGhlIHQtdmFsdWUgaXMganVzdCB0aGUgY29lZmZpY2llbnQgZGl2aWRlZCBieSB0aGUgc3RhbmRhcmQgZXJyb3IsIHNvIHRoZSBiaWdnZXIgaXQgaXMsIHRoZSBtb3JlIGNlcnRhaW50eSB0aGVyZSBpcy4gKlJvdWdobHkqIHNwZWFraW5nLCBpZiB0aGUgdC12YWx1ZSBpcyBncmVhdGVyIHRoYW4gMiwgdGhlIGVmZmVjdCBpcyBwcm9iYWJseSByZWxpYWJsZS4KCgojIyAkcl4yJAoKPGRpdiBjbGFzcyA9ICJoYWxmLWltZyI+CgohW10oZmlndXJlcy9yc3F1YXJlZC5wbmcpCgo8L2Rpdj4KClRoaXMgaXMgYSBtZWFzdXJlIG9mIGhvdyBtdWNoIG1vZGVsbGluZyB5b3VyIG91dGNvbWUgZGF0YSBhcyBhIHN0cmFpZ2h0IGxpbmUgd2l0aCB5b3VyIGNob3NlbiBwcmVkaWN0b3JzIGhhcyByZWR1Y2VkIHRoZSB2YXJpYWJpbGl0eSBpbiB0aGUgZGF0YS4gVGhpcyBpcyBhIGhlbHBmdWwgZW5vdWdoIGhldXJpc3RpYywgYnV0IGNhbid0IGJlIHRha2VuIGFzIGFuIGludHJpbnNpY2FsbHkgaW5mb3JtYXRpdmUgdmFsdWUuIFdlIGNhbiByb3VnaGx5IHZpc3VhbGl6ZSB0aGlzIGJ5IHBsb3R0aW5nIGRlbnNpdHkgZGlzdHJpYnV0aW9ucyBvZiBvdXIgZGF0YSAoY2VudGVyZWQgb24gdGhlIG1lYW4pIGFuZCB0aGUgbW9kZWwgcmVzaWR1YWxzLgoKYGBge3J9CmFoX3RvbW9kICU+JQogIGdncGxvdChhZXMobG9nMmR1cl9jLCBGMV9uKSkrCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4wNSkrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtZWFuKGFoX3RvbW9kJEYxX24pKSsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGNvZWYoYWhfbW9kZWwpWzFdLAogICAgICAgICAgICAgICAgc2xvcGUgPSBjb2VmKGFoX21vZGVsKVsyXSwKICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKCgoKYGBge3J9CmFoX3RvbW9kJHJlc2lkIDwtIHJlc2lkKGFoX21vZGVsKQphaF90b21vZCAlPiUKICBtdXRhdGUoRjFfbl9jID0gRjFfbiAtIG1lYW4oRjFfbikpJT4lCiAgZ2dwbG90KCkrCiAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSBGMV9uX2MsIGNvbG9yID0gImNlbnRlcmVkIGRhdGEiKSkrCiAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSByZXNpZCwgY29sb3IgPSAicmVzaWR1YWxzIikpKwogICAgdGhlbWVfbWluaW1hbCgpKwogICAgZ2d0aXRsZShwYXN0ZTAoInItc3F1YXJlZCA9ICIsIHJvdW5kKHN1bW1hcnkoYWhfbW9kZWwpJHIuc3F1YXJlZCwgZGlnaXRzID0gMikpKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbChOVUxMLCB2YWx1ZXMgPSBjKCJibGFjayIsICJyZWQiKSkKYGBgCgpUaGUgZGlzdHJpYnV0aW9uIG9mIHRoZSByZXNpZHVhbHMgaW4gcmVkIGlzIGp1c3Qgc2xpZ2h0bHkgbmFycm93ZXIgdGhhbiB0aGUgZGF0YSwgd2hpY2ggaXMgd2h5IHRoZSByLXNxdWFyZWQgaXMgZmFpcmx5IG1vZGVzdC4KClNvbWV0aW1lcyB5b3UgY2FuIGdldCBhIHJlYWxseSBsYXJnZSByLXNxdWFyZWQgYnkgaW5jbHVkaW5nIGEgYmlnIGFuZCBvYnZpb3VzIHByZWRpY3RvciwgdGhhdCBkb2Vzbid0IHJlYWxseSBjb250cmlidXRlIHRvIG91ciB1bmRlcnN0YW5kaW5nLiBGb3IgZXhhbXBsZSwgZm9yIHRoZSB3aG9sZSBgaXlfYWhgIGRhdGEgc2V0LCB0aGUgbGFyZ2VzdCBudW1iZXIgb25lIHByZWRpY3RvciBmb3IgdGhlIG1vZGVsIGlzIHRoZSB2b3dlbCBjbGFzcywgc2luY2UgYGl5YCBhbmQgYGFoYCBhcmUgY29udHJhc3RpdmVseSBkaWZmZXJlbnQgYWxvbmcgRjEuIAoKYGBge3J9Cml5X2FoX21vZGVsIDwtIGxtKEYxX24gfiBwbHRfdmNsYXNzLCBkYXRhID0gaXlfYWgpCnN1bW1hcnkoaXlfYWhfbW9kZWwpCmBgYAoKYGBge3J9Cml5X2FoJHJlc2lkIDwtIHJlc2lkKGl5X2FoX21vZGVsKQppeV9haCAlPiUKICBtdXRhdGUoRjFfbl9jID0gRjFfbiAtIG1lYW4oRjFfbikpJT4lCiAgICBnZ3Bsb3QoKSsKICAgICAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gRjFfbl9jLCBjb2xvciA9ICJjZW50ZXJlZCBkYXRhIikpKwogICAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSByZXNpZCwgY29sb3IgPSAicmVzaWR1YWxzIikpKwogICAgICB0aGVtZV9taW5pbWFsKCkrCiAgICAgIGdndGl0bGUocGFzdGUwKCJyLXNxdWFyZWQgPSAiLCByb3VuZChzdW1tYXJ5KGl5X2FoX21vZGVsKSRyLnNxdWFyZWQsIGRpZ2l0cyA9IDIpKSkrCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbChOVUxMLCB2YWx1ZXMgPSBjKCJibGFjayIsICJyZWQiKSkKYGBgCgoKUi1zcXVhcmVkIGlzIHByb2JhYmx5IGJlc3QgdXNlZCB3aGVuICpjb21wYXJpbmcqIHR3byBtb2RlbHMuIEZvciBhbiBleGFtcGxlLCBzZWUgdGhlIGJhciBwbG90cyBvbiBbcGFnZSAxMiBvZiB0aGlzIHBhcGVyXShodHRwOi8vd3d3LnN0YXQuY29sdW1iaWEuZWR1L35nZWxtYW4vcmVzZWFyY2gvdW5wdWJsaXNoZWQvY29ob3J0X3ZvdGluZ18yMDE0MDYwNS5wZGYpLgoKIyMgSW50ZXJwcmV0aW5nIG90aGVyIHBlb3BsZSdzIG1vZGVscwoKTW9yZSBvciBsZXNzLCBpZiB5b3Ugc2VlIHNvbWVvbmUgcmVwb3J0ICpvbmx5KiB0aGUgcC12YWx1ZSBmb3IgdGhlaXIgZWZmZWN0cyB3aXRob3V0IHRoZSBjb2VmZmljaWVudHMsIGVzcGVjaWFsbHkgaWYgdGhleSdyZSB3b3JraW5nIHdpdGggYSBsb3Qgb2YgZGF0YSwgcmVhY2ggZm9yIHlvdXIgd2FsbGV0LiBJZiB5b3UgYXJlIHJldmlld2luZyBhIHBhcGVyIHdoZXJlIHRoaXMgaGFwcGVucywgbWFrZSBpdCBhIHJlcXVpcmVkIHJldmlzaW9uIHRoYXQgZWl0aGVyIHRoZXkgbmVlZCB0byBpbmNsdWRlIHRoZSBjb2VmZmljaWVudHMsIG9yIGRyb3AgdGhhdCBxdWFudGl0YXRpdmUgY29tcG9uZW50LgoKCgojIFBpdGZhbGxzIGluIE1vZGVsbGluZwoKCiMjIFR5cGUgSSBhbmQgVHlwZSBJSSBFcnJvcgoKVGhlc2UgYXJlIHBvb3JseSBuYW1lZCwgYW5kIEkgdGhpbmsgZmV3IHBlb3BsZSByZW1lbWJlciB3aGljaCBpcyB3aGljaCBjb3JyZWN0bHkgdGhlIGZpcnN0IHRpbWUuIFRoZXNlIGFyZSBlcnJvcnMgcmVsYXRlZCB0byB0aGUgdXNlIG9mIHAtdmFsdWVzLiBGaXJzdCBpdCdzIGltcG9ydGFudCB0byBkZWZpbmUgd2hhdCB0aGUgKipOdWxsIEh5cG90aGVzaXMqKiBpcy4KCi0gKipUaGUgTnVsbCBIeXBvdGhlc2lzIGlzIHRoZSBEdWxsIEh5cG90aGVzaXM6KiogVGhlIE51bGwgSHlwb3RoZXNpcyBpcyB0aGF0IHRoZXJlIGlzIG5vIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBvdXRjb21lIGFuZCBwcmVkaWN0b3JzLiBJdCBpcyAqbm90KiB3aGF0IHlvdSB0aGluayB0aGUgbW9zdCBsaWtlbHkgcmVsYXRpb25zaGlwIGlzLgoKV2l0aCB0aGF0IGluIG1pbmQsIHdlIGNhbiBkZWZpbmUgVHlwZSBJIGFuZCBUeXBlIElJIGVycm9ycy4KCi0gKipUeXBlIEkqKiAtIFlvdSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyAoYmVjYXVzZSBwIDwgMC4wNSksIGJ1dCBpbiByZWFsaXR5IHRoZXJlICppc24ndCogYSByZWxhdGlvbnNoaXAuIFRoYXQgaXMsIHlvdSBzYXkgdGhlcmUgaXMgYSByZWxpYWJsZSBlZmZlY3Qgd2hlbiB0aGVyZSBpc24ndCBvbmUuCi0gKipUeXBlIElJKiogLSBZb3UgZmFpbCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RlaHNpcyB3aGVuIHRoZXJlICppcyogYW4gcmVhbCBlZmZlY3QuIAoKT3IgdG8gcHV0IGl0IGFub3RoZXIgd2F5LCB3aGVuIHlvdSBzZWUgYSBzdGF0aXN0aWNhbCByZXN1bHQgdGhhdCBpcyBzaWduaWZpY2FudCAocCA8IDAuMDUpLCBidXQgeW91IGRvbid0IHRoaW5rIGl0IGNvdWxkIHBvc3NpYmx5IGJlIHJlYWwsIHlvdSB0aGluayBhIFR5cGUgSSBlcnJvciBoYXMgb2NjdXJyZWQuCgpBbmQgd2hlbiB5b3UgZ2V0IHAgPiAwLjA1LCBidXQgeW91IHJlYWxseSB0aGluayB0aGVyZSdzIHNvbWV0aGluZyB0aGVyZSBzbyB5b3UgcHV0ICJ0cmVuZGluZyB0b3dhcmRzIHNpZ25pZmljYW5jZSIgaW4geW91ciBwYXBlciwgeW91IHRoaW5rIGEgVHlwZSBJSSBlcnJvciBoYXMgb2NjdXJyZWQuCgpUaGUgYmVzdCB3YXkgdG8gYW1lbGlvcmF0ZSBUeXBlIEkgYW5kIFR5cGUgSUkgZXJyb3JzIGlzIHRvIGVpdGhlciBjb2xsZWN0IG1vcmUgZGF0YSwgb3IgdG8gbW92ZSB0byBCYXllc2lhbiBTdGF0aXN0aWNzLCB3aGljaCB3ZSB3b24ndCBiZSBhYmxlIHRvIGNvdmVyIGluIHRoaXMgY291cnNlLCBbYnV0IEkgcmVjb21tZW5kIHRoaXMgYm9va10oaHR0cHM6Ly9zaXRlcy5nb29nbGUuY29tL3NpdGUvZG9pbmdiYXllc2lhbmRhdGFhbmFseXNpcy8pLgoKCgogCiAKIyMgVHlwZSBNIGFuZCBUeXBlIFMgZXJyb3JzCgpUaGVzZSBhcmUgZXJyb3IgdHlwZXMgW2Rpc2N1c3NlZCBieSBHZWxtYW4gYW5kIGNvbGxlYWd1ZXNdKGh0dHA6Ly93d3cuc3RhdC5jb2x1bWJpYS5lZHUvfmdlbG1hbi9yZXNlYXJjaC9wdWJsaXNoZWQvUFBTNTUxNjQyX1JFVjIucGRmKSAoYW5kIGFyZSBiZXR0ZXIgbmFtZWQpLgoKIC0gKipUeXBlIE0gRXJyb3JzKiogYXJlIGdyb3NzIG92ZXItZXN0aW1hdGlvbiBvZiB0aGUgKm1hZ25pdHVkZSogb2YgYW4gZWZmZWN0IHNpemUuCiAtICoqVHlwZSBTIEVycm9ycyoqIGdldCB0aGUgKnNpZ24qIHdyb25nIG9uIGFuIGVzdGltYXRlLiBUaGF0IGlzLCB0aGV5IHByZWRpY3QgYW4gZWZmZWN0IGluIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb24gb2Ygd2hhdCB0aGUgdHJ1ZSBlZmZlY3QgaXMuCiAKVHlwZSBNIG1pZ2h0IG5vdCBzb3VuZCBsaWtlIGEgdmVyeSBiaWcgcHJvYmxlbSwgYW5kIFR5cGUgUyBtaWdodCBzb3VuZCBhIGJpdCBvdXRsYW5kaXNoIGJ1dCB0aGVzZSBjYW4gYm90aCBoYXBwZW4sIGVzcGVjaWFsbHkgd2hlbiB3ZSBhcmUgW2V4cGxvcmluZyBmb3Igc21hbGwgZWZmZWN0cyBhbmQgZmlsdGVyaW5nIHJlc3VsdHMgYnkgdGhlaXIgcC12YWx1ZXNdKGh0dHA6Ly9ycHVicy5jb20vSm9Gcmh3bGQvMjkxNzM0KS4gR2VsbWFuIGhhcyBwcm9wb3NlZCB0aGF0IFtUeXBlIE0gZXJyb3JzIGFyZSBhIGxpa2VseSBjdWxwcml0IGluIHRoZSBzby1jYWxsZWQgImRlY2xpbmUgZWZmZWN0Il0oaHR0cDovL2FuZHJld2dlbG1hbi5jb20vMjAxMC8xMi8xMy90aGVfdHJ1dGhfd2VhcnMvKSwgd2hpY2ggaXMgYSBwaGVub21lbm9uIHNvbWUgaGF2ZSBmb3VuZCB0aGF0IGxhcmdlIGFuZCBzaWduaWZpY2FudCBlZmZlY3RzIGdyYWR1YWxseSBnZXQgc21hbGxlciBhZnRlciB0aGVpciBvcmlnaW5hbCByZXBvcnRzLgoKSGVyZSBhcmUgc29tZSB3YXlzIHRvIGd1YXJkIHlvdXNlbGYgYWdhaW5zdCBUeXBlIE0gYW5kIFR5cGUgUyBlcnJvcnMuCgotIFRyeSB0byByZWFzb24gaG93IGJpZyB0aGUgZWZmZWN0IGlzICpsaWtlbHkqIHRvIGJlLgotIFRyeSB0byBjb2xsZWN0IG9mIGhvdyBvdGhlciBmYWN0b3JzIGVmZmVjdCB0aGUgb3V0Y29tZSB5b3UncmUgaW52ZXN0aWdhdGluZywgYW5kIGhvdyBiaWcgdGhvc2UgZWZmZWN0cyBhcmUuCi0gQ29tbWl0IHRvIHRoZSAqZGlyZWN0aW9uKiBvZiB0aGUgZWZmZWN0LgoKVHlwZSBNIGFuZCBUeXBlIFMgZXJyb3JzIGFyZSBvbmx5IGdvaW5nIHRvIGdyb3cgaW4gc2V2ZXJpdHkgYXMgW3RoZSBzaXplIG9mIGRhdGEgc2V0cyBncm93XShodHRwOi8vam9mcmh3bGQuZ2l0aHViLmlvL3BhcGVycy9wbGMzOV8yMDE1LyMvKS4KCgojIyBPdmVyZml0dGluZwoKCgpgYGB7cn0KYXkwX21lYW5zICU+JQogIGdncGxvdChhZXMoZG9iLCBGMV9uKSkrCiAgICAjZ2VvbV9wb2ludCgpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xtJywgCiAgICAgICAgICAgICAgICBzZSA9IEYsCiAgICAgICAgICAgICAgICBhZXMoY29sb3IgPSAibGluZSIpKSsKICAgIHN0YXRfc21vb3RoKG1ldGhvZCA9ICdsb2VzcycsIAogICAgICAgICAgICAgICAgc2UgPSBGLAogICAgICAgICAgICAgICAgYWVzKGNvbG9yID0gImN1cnZlIikpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xvZXNzJywgCiAgICAgICAgICAgICAgICBzZSA9IEYsCiAgICAgICAgICAgICAgICBzcGFuID0gMC4xLCAKICAgICAgICAgICAgICAgIGFlcyhjb2xvciA9ICJidW1weSBjdXJ2ZSIpKSsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcigibW9kZWwiLCBwYWxldHRlID0gIkRhcmsyIikrCiAgICBzY2FsZV95X3JldmVyc2UoKSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKCgoKCiMjIENvbGxpbmVhcml0eQoKIkNvbGxpbmVhcml0eSIgaXMgd2hlbiB0d28gcG90ZW50aWFsIHByZWRpY3RvcnMgYXJlIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlci4gV2hlbiB0d28gY29ycmVsYXRlZCBwcmVkaWN0b3JzIGFyZSBpbmNsdWRlZCBpbiB0aGUgc2FtZSByZWdyZXNzaW9uLCB0aGUgcmVzdWx0cyBjYW4gYmUgKndvbmt5KiBhdCBiZXN0LiBbR29ybWFuICgyMDEwKV0oaHR0cDovL3JlcG9zaXRvcnkudXBlbm4uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTQ2JmNvbnRleHQ9cHdwbCkgdGFsa3MgYWJvdXQgdGhpcyBhdCBsZW5ndGggd2l0aCByZXNwZWN0IHRvIHNvY2lvZWNvbm9taWMgbWVhc3VyZXMgaW4gdGhlIExhbmd1YWdlIENoYW5nZSBhbmQgVmFyaWF0aW9uIHN0dWR5LiBGb3IgZXhhbXBsZSwgc3BlYWtlcnMnIE9jY3VwYXRpb24gd2FzIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggdGhlIHZhbHVlIG9mIHRoZWlyIFJlc2lkZW5jZS4gWW91ICpzaG91bGRuJ3QqIGluY2x1ZGUgdGhlc2UgYm90aCwgdW50cmVhdGVkLCBpbnRvIHlvdXIgbW9kZWxzLiAKCgpUaGVyZSBhcmUgYXQgbGVhc3QgdGhyZWUgZGlmZmVyZW50IHN0cmF0ZWdpZXMgZm9yIGRlYWxpbmcgd2l0aCB0aGlzIGlzc3VlCgoxLiBJZiB5b3UgKm11c3QqIG1vZGVsIHRoZXNlIGZhY3RvcnMgaW5kZXBlbmRlbnRseSwgcmVzaWR1YWxpemUgKEdvcm1hbiwgMjAxMCkKMi4gKk9yKiwganVzdCBwaWNrIHRoZSBvbmUgdGhhdCBpcyB0aGVvcmV0aWNhbGx5IG1vdGl2YXRlZCAoRnJ1ZWh3YWxkLCAyMDE2KS4KMy4gKk9yKiBnaXZlIHVwIG9uIHRyZWF0aW5nIHlvdXIgbWVhc3VyZXMgYXMgaGF2aW5nIGluZGVwZW5kZW50IHJlYWxpdHksIHJlYWxpemUgdGhleSBhcmUgcmVmbGVjdGlvbnMgb2YgbW9yZSBhYnN0cmFjdCBkaW1lbnNpb25zLCBhbmQgdHJ5IHRvIGZpZ3VyZSBvdXQgd2hhdCB0aG9zZSBhcmUgKGkuZS4gZmFjdG9yIGFuYWx5c2lzLCBXYWxrZXIgKDIwMTYpKS4KCgojIyMgUmVzaWR1YWxpemF0aW9uCgpMaWtlIHRoZSBuYW1lIHN1Z2dlc3RzLCB0aGlzIGludm9sdmVzIHRoZSByZXNpZHVhbHMgZnJvbSBhIGxpbmVhciBtb2RlbC4gSWYgeW91IHJlYWxseSB3YW50IHRvIGZpdCBhIG1vZGVsIGxpa2UgdGhpczoKCmBgYApuZWdhdGl2ZV9jb25jb3JkIH4gb2NjdXBhdGlvbiArIHJlc2lkZW5jZQpgYGAKClRoZW4gd2hhdCB5b3UgbmVlZCB0byBkbyBmaXJzdCBpcyBmaXQgdGhpcyBtb2RlbC4KCmBgYApyZXNpZGVuY2UgfiBvY2N1cGF0aW9uCmBgYAoKQW5kIHJlcGxhY2UgdGhlIGByZXNpZGVuY2VgIHRlcm0gaW4gdGhlIGZpcnN0IG1vZGVsIHdpdGggdGhlICpyZXNpZHVhbHMqIG9mIHRoZSBzZWNvbmQgbW9kZWwuIE5vdywgaXQgZG9lcyBtYXR0ZXIgd2hpY2ggb3JkZXIgeW91IHJlc2lkdWFsaXplIGluLiBIb3cgZG8geW91IGNob29zZT8gQWdhaW4sIHRoZXJlJ3Mgbm8gaGFyZCBhbmQgZmFzdCBhbnN3ZXIsIGJ1dCBwbGVhc2UgZG9uJ3QgdHJ5IGl0IGV2ZXJ5IHBvc3NpYmxlIHdheSBhbmQgdGhlbiBqdXN0IGNob29zZSB0aGUgbW9kZWwgdGhhdCBsb29rcyBiZXN0IQoKIyMjIEZhY3RvciBBbmFseXNpcwoKQW5vdGhlciBhcHByb2FjaCB3b3VsZCBiZSB0byBhYmFuZG9uIHRyeWluZyB0byBsb29rIGF0IGFsbCBvZiB0aGVzZSBwcmVkaWN0b3JzIGluZGVwZW5kZW50bHkgYW5kIHRvIHRyZWF0IHRoZW0gYWxsIGFzIHJvdWdoIG1lYXN1cmVzIGNvcnJlbGF0ZWQgdG8gYSBtb3JlIGFic3RyYWN0IHZhcmlhYmxlLCB1c2luZyBzb21ldGhpbmcgbGlrZSBhIGZhY3RvciBhbmFseXNpcy4gVGhpcyBpcyB3aGF0IFdhbGtlciAoMjAxNikgZGlkLgoKVGhlIGJlc3Qgd2F5IHRvIGV4cGxhaW4gYSBmYWN0b3IgYW5hbHlzaXMgaXMgdG8gaW1hZ2luZSBzdXJ2ZXlpbmcgYSBidW5jaCBvZiBwZW9wbGUgb24gdGhlIHN0cmVldCBhbmQgYXNraW5nIHRoZW0gdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6CgoxLiBEaWQgeW91IGhhdmUgdGhlIGhlYXQgb24gdGhpcyBtb3JuaW5nPwoyLiBBcmUgeW91IHdlYXJpbmcgYSB3b29seSBqdW1wZXI/CjMuIEFyZSB5b3Ugd2VhcmluZyBhIHNjYXJmPwo0LiBDb3VsZCB5b3Ugc2VlIHlvdXIgYnJlYXRoIHdoZW4geW91IHN0ZXBwZWQgb3V0c2lkZT8KNS4gRGlkIHlvdXIgZ2xhc3NlcyBmb2cgdXAgd2hlbiB5b3Ugd2Fsa2VkIGluc2lkZT8KNi4gRGlkIHlvdSBtYWtlIHlvdXJzZWxmIGEgYmlnIGJyZWFrZmFzdD8KNy4gV2FzIHlvdXIgc3RvbWFjaCBncm93bGluZyB3aGVuIHlvdSB3b2tlIHVwPwoKClRoaXMgbG9va3MgbGlrZSB5b3UndmUgYXNrZWQgcGVvcGxlIDcgZGlmZmVyZW50IHF1ZXN0aW9ucywgYnV0IHJlYWxseSwgeW91J3ZlIG9ubHkgZWZmZWN0aXZlbHkgYXNrZWQgMiBxdWVzdGlvbnM6IAoKMS4gV2FzIGl0IGNvbGQ/CjIuIFdlcmUgeW91IGh1bmdyeT8KCklmIHlvdSB0b29rIHRoZSByYXcgZGF0YSBmcm9tIHRoZSA3IHF1ZXN0aW9uIHN1cnZleSBhbmQgcmFuIGl0IHRocm91Z2ggYSBmYWN0b3IgYW5hbHlzaXMsIGl0IHdvdWxkIChpZGVhbGx5KSB0ZWxsIHlvdSB0aGF0IHRoZXJlIGFyZSBvbmx5IDIgZWZmZWN0aXZlIHF1ZXN0aW9ucyBpbiBpdCwgYmFzZWQgb24gaG93IHJlc3BvbnNlcyB0byBxdWVzdGlvbnMgMSB0aHJ1IDUgYXJlIGNvcnJlbGF0ZWQgd2l0aCBlYWNoIG90aGVyLCBhbmQgNiY3IGFyZSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlci4KCgotLS0KCgpDb2xsaW5lYXJpdHkgb2Z0ZW4gY29tZXMgdXAgYXMgYSBwaXRmYWxsIG9mIG9mIGVzdGltYXRpbmcgZWZmZWN0cy4gQnV0IGl0J3MgYWxzbyBhbiBpc3N1ZSB3aGVuIHRyeWluZyB0byB1bmRlcnN0YW5kIG91ciBtb2RlbHMuIEEgY29tbW9uLCBhbm5veWluZywgYW5kIHVzdWFsbHkgdmFsaWQgcXVlc3Rpb24gaXM6Cgo+IENvdWxkbid0IHlvdXIgZWZmZWN0IG9mIEEgKmFjdHVhbGx5KiBiZSBhbiBlZmZlY3Qgb2YgQj8KClRoZSBiZXN0IHdheSB0byBkZWFsIHdpdGggdGhpcyBraW5kIG9mIGNvbGxpbmVhcml0eSBpcyB0byB0cnkgdG8ga2lsbCB5b3VyIGVmZmVjdHMuIERvZXMgdGhlIHNhbWUgZWZmZWN0IGhvbGQgaW4gdGhlIHNhbWUgZGlyZWN0aW9uIGZvciBpbXBvcnRhbnQgc3Vic2V0cyBvZiB0aGUgZGF0YT8gQ2FuIHlvdSBzdWJzZXQgdGhlIGRhdGEgYWNjb3JkaW5nIHRvIEIgYW5kIGZpdCBzZXBhcmF0ZSBtb2RlbHMgZm9yIEE/CgoKIyMgQWRkaXRpb25hbCBTdHJ1Y3R1cmUKCgpgYGB7ciBlY2hvID0gRn0KcmVhbF9kYXRhIDwtIGRhdGFfZnJhbWUoeCA9IHJub3JtKDIwMCksCiAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAoLTAuNSAqIHgpICsgOCArIHJub3JtKDIwMCkpCmdncGxvdChyZWFsX2RhdGEsIGFlcyh4LCB5KSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBzdGF0X3Ntb290aChtZXRob2QgPSAnbG0nKQpgYGAKCgpgYGB7ciBlY2hvID0gRn0gCnBvaW50X2xpbmVfZGlzdGFuY2UgPC0gZnVuY3Rpb24oYiwgbSwgeCwgeSkKICAoeSAtIChtKnggKyBiKSkvc3FydChtXjIgKyAxKQoKY29uZm91bmRlZF9kYXRhX2ZyYW1lIDwtIGZ1bmN0aW9uKHgsIHksIG0sIG51bV9ncnApewogIGIgPC0gMCAjIGludGVyY2VwdCBkb2Vzbid0IG1hdHRlcgogIGQgPC0gcG9pbnRfbGluZV9kaXN0YW5jZShiLCBtLCB4LCB5KQogIGRfc2NhbGVkIDwtIDAuMDAwNSArIDAuOTk5ICogKGQgLSBtaW4oZCkpLyhtYXgoZCkgLSBtaW4oZCkpICMgYXZvaWQgMCBhbmQgMQogIGRhdGEuZnJhbWUoeD14LCB5PXksIAogICAgICAgICAgICBncm91cD1hcy5mYWN0b3Ioc3ByaW50ZigiZ3JwJTAyZCIsIGNlaWxpbmcobnVtX2dycCooZF9zY2FsZWQpKSkpKQp9CgoKY29uZl9kZiA8LSBjb25mb3VuZGVkX2RhdGFfZnJhbWUocmVhbF9kYXRhJHgsIHJlYWxfZGF0YSR5LCBtID0gMSwgbnVtX2dycCA9IDMpCgoKZ2dwbG90KGNvbmZfZGYsIGFlcyh4LCB5KSkrCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGdyb3VwKSkrCiAgICBzdGF0X3Ntb290aChtZXRob2QgPSBsbSwgY29sb3IgPSAnYmxhY2snLCBsaW5ldHlwZSA9IDIpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gbG0sIGFlcyhjb2xvciA9IGdyb3VwKSkKYGBgCgoKIyBCdWlsZGluZyB1cCBhIG1vZGVsCgpXaGVuIGFwcHJvYWNoaW5nIGhvdyB0byBidWlsZCB1cCBhIG1vZGVsICh3aGljaCBwcmVkaWN0b3JzIHNob3VsZCBiZSBpbmNsdWRlZCBvciBleGNsdWRlZCksIEkgd291bGQgY2F1dGlvbiBhZ2FpbnN0ICJraXRjaGVuIHNpbmsiIG1vZGVscywgb3IgdHJ5aW5nIHRvIHRyeWluZyB0byBvdXRzb3VyY2UgeW91ciByZWFzb25pbmcgdG8gYW4gYXV0b21hdGVkIHN0ZXAtd2lzZSByZWdyZXNzaW9uLgoKSSdsbCBzdW1tYXJpc2UgR2VsbWFuICYgSGlsbCdzICgyMDA2KSByZWNvbW1lbmRhdGlvbnMgaGVyZToKCjEuICJJbmNsdWRlIGFsbCBpbnB1dCB2YXJpYWJsZXMgdGhhdCwgZm9yIHN1YnN0YW50aXZlIHJlYXNvbnMsIG1pZ2h0IGJlIGV4cGVjdGVkIHRvIGJlIGltcG9ydGFudCBpbiBwcmVkaWN0aW5nIHRoZSBvdXRjb21lLiIKICAgIC0gSm9lIGFkZGVuZHVtOiBJIHRoaW5rIHN1YnN0YW50aXZlIHJlYXNvbnMgaW5jbHVkZSAiSSBoYXZlIGEgZ29vZCB0aGVvcnkiIGFuZCAiUHJldmlvdXMgd29yayBoYXMgaW5jbHVkZWQgdGhlc2UiLgoyLiAiSXQgaXMgbm90IGFsd2F5cyBuZWNlc3NhcnkgdG8gaW5jbHVkZSB0aGVzZSBpbnB1dHMgYXMgc2VwYXJhdGUgcHJlZGljdG9ycy3igJRmb3IgZXhhbXBsZSwgc29tZXRpbWVzIHNldmVyYWwgaW5wdXRzIGNhbiBiZSBhdmVyYWdlZCBvciBzdHVubWVkIHRvIGNyZWF0ZSBhICd0b3RhbCBzY29yZScgdGhhdCBjYW4gYmUgdXNlZCBhcyBhIHNpbmdsZSBwcmVkaWN0b3IgaW4gdGhlIG1vZGVsLiIKMy4gIkZvciBpbnB1dHMgdGhhdCBoYXZlIGxhcmdlIGVmZmVjdHMsIGNvbnNpZGVyIGluY2x1ZGluZyB0aGVpciBpbnRlcmFjdGlvbnMgYXMgd2VsbC4iCgpUaGVpciByZWNvbW1lbmRhdGlvbiBmb3IgZXhjbHVkaW5nIGEgdmFyaWFibGUgZnJvbSBhIG1vZGVsIGlzIG1vcmUgbnVhbmNlLiBUaGV5IHNheToKCmEuICJJZiBhIHByZWRpY3RvciBpcyBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhbmQgaGFzIHRoZSBleHBlY3RlZCBzaWduLCBpdCBpcyBnZW5lcmFsbHkgZmluZSB0byBrZWVwIGl0IGluLiBJdCBtYXkgbm90IGhlbHAgcHJlZGljdGlvbnMgZHJhbWF0aWNhbGx5IGh1dCBpcyBhbHNvIHByb2JhYmx5IG5vdCBodXJ0aW5nIHRoZW0uIgpiLiAiSWYgYSBwcmVkaWN0b3IgaXMgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYW5kIGRvZXMgbm90IGhhdmUgdGhlIGV4cGVjdGVkIHNpZ24gKGZvciBleGFtcGxlLCBpbmN1bWJlbmN5IGhhdmluZyBhIG5lZ2F0aXZlIGVmZmVjdCBvbiB2b3RlIHNoYXJlKSwgY29uc2lkZXIgcmVtb3ZpbmcgaXQgZnJvbSB0aGUgbW9kZWwgKHRoYXQgaXMsIHNldHRpbmcgaXRzIGNvZWZpbGNpZW50IHRvIHplcm8pLiIKYy4gIklmIGEgcHJlZGljdG9yIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYW5kIGRvZXMgbm90IGhhdmUgdGhlIGV4cGVjdGVkIHNpZ24sIHRoZW4gdGhpbmsgaGFyZCBpZiBpdCBtYWtlcyBzZW5zZS4iCmQuICJJZiBhIHByZWRpY3RvciBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGFuZCBoYXMgdGhlIGV4cGVjdGVkIHNpZ24sIHRoZW4gYnkgYWxsIG1lYW5zIGtlZXAgaXQgaW4gdGhlIG1vZGVsLiIKCgoKCgojIE1vZGVsbGluZyBNZW51CgoKIyMgRGlmZmVyZW50ICJsaW5rcyIKCllvdSBtYXkgYmUgdmVyeSBsaWtlbHkgdG8gaGF2ZSBkYXRhIHlvdSB3YW50IHRvIG1vZGVsIHdoaWNoIGlzIG5vdCBsaWtlIHRoZSBmb3JtYW50IGRhdGEgaGVyZS4gCllvdSBtYXkgaGF2ZSBjYXRlZ29yaWNhbCBkYXRhIG9mIGhvdyBvZnRlbiBzb21ldGhpbmcgZGlkIG9yIGRpZG4ndCBoYXBwZW4uCk9yIHlvdSBtaWdodCBvbmx5IGhhdmUgZGF0YSBvbiBob3cgb2Z0ZW4gc29tZXRoaW5nICpkaWQqIGhhcHBlbi4KVGhlcmUgYXJlIHdheXMgdG8gZml0IHN0YXRpc3RpY2FsIG1vZGVscyB3aXRoIHRoZXNlIGtpbmRzIG9mIGRhdGEgdGhhdCBmb3IgdGhlIG1vc3QgcGFydCBpbnZvbHZlIHRoZSBzYW1lIGtpbmQgb2YgZGVjaXNpb25zIGFib3V0IHByZWRpY3RvcnMgYW5kIGludGVycHJldGF0aW9ucyBvZiB0aGUgcGFyYW1ldGVycy4KCiMjIyBCaW5hcnkgRGF0YQoKU29jaW9saW5ndWlzdHMgaGF2ZSBiZWVuIHdvcmtpbmcgd2l0aCBiaW5hcnkgZGF0YSBmb3IgYSBsb25nIHRpbWUuIEV4YW1wbGVzIGluIGNsdWRlOgoKLSAqKlREIERlbGV0aW9uKio6IG1pc3QgdnMgbWlzJwotICoqSU5HKio6IHdhbGtpbmcgdnMgd2Fsa2luJwotICoqRmlsbGVkIFBhdXNlcyoqOiB1bSB2cyB1aAoKVGhlc2UgYXJlIHVzdWFsbHkgY29kZWQgYXMgYDBgIG9yIGAxYCwgYW5kIGl0IGlzIGluYXBwcm9wcmlhdGUgdG8gZml0IGEgbGluZWFyIHJlZ3Jlc3Npb24gdG8gdGhlc2UgdmFsdWVzLiBJbnN0ZWFkLCBmaXQgYSAqKmxvZ2lzdGljIHJlZ3Jlc3Npb24qKgoKIyMjIFJhdGUgRGF0YQoKU29tZXRpbWVzLCBpdCdzIG5vdCBwb3NzaWJsZSB0byBkZXNjcmliZSBhIGxpbmd1aXN0aWMgdmFyaWFibGUgaW4gdGVybXMgb2YgaG93IG1hbnkgdGltZXMgaXQgZGlkIGFuZCBkaWRuJ3QgaGFwcGVuLiBGb3IgZXhhbXBsZSBSaWNrZm9yZCAmIFByaWNlICgyMDEzKSB3YW50ZWQgdG8gZXhwbG9yZSBjaGFuZ2VzIGFjcm9zcyB0aGUgbGlmZXNwYW4gZm9yIGNlcnRhaW4gQUFWRSBmZWF0dXJlcywgaW5jbHVkaW5nIGhhYml0dWFsLWJlLgoKLSAiSSBiZSB3YWtpbmcgdXAuLi4gYW5kIEkgYmUgZ29pbmcuIiAoKDEpIGZyb20gUmlja2ZvcmQgJiBQcmljZSAoMjAxMykpCgpBIGRpZmZpY3VsdHkgaXMgdGhhdCBpdCdzIHByb2JhYmx5IGltcG9zc2libGUgdG8gdGVsbCB3aGVuIHNvbWVvbmUgKmNvdWxkKiB1c2UgaGFiaXR1YWwtYmUsIGJ1dCBkaWRuJ3QuIFdoYXQgdGhleSBkaWQgaW5zdGVhZCB3YXMgcmVwb3J0IGhvdyBvZnRlbiB0aGVpciBzcGVha2VycyB1c2VkIGhhYml0dWFsLWJlICpwZXIgaG91ciBvZiBpbnRlcnZpZXcqLiAKCklmIHlvdXIgZGF0YSBpcyBiZXN0IGRlc2NyaWJlZCBsaWtlIHRoaXMsIG5vdCBhcyBhIHByb3BvcnRpb24gb2Ygb2NjdXJhbmNlLCBidXQgYXMgYSByYXRlLCBbbGlrZSBYIHBlciAxMDAwIHdvcmRzXShodHRwOi8vcmVwb3NpdG9yeS51cGVubi5lZHUvY2dpL3ZpZXdjb250ZW50LmNnaT9hcnRpY2xlPTE5MjYmY29udGV4dD1wd3BsKSwgdGhlbiB5b3UgY2FuIGZpdCBhICoqcG9pc3NvbiByZWdyZXNzaW9uKiouCgojIyBDdXJ2ZXMKCkluY3JlYXNpbmdseSwgcGVvcGxlIGFyZSBnZXR0aW5nIGRpc3NhdGlzZmllZCBieSBhc3N1bWluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlaXIgdmFyaWFibGVzIGlzIGxpbmVhci4gVGhlIGdyb3dpbmcgc3RhbmRhcmQgZm9yIGZpdHRpbmcgY3VydnkgbW9kZWxzIGFyZSBHQU1zIChnZW5lcmFsaXplZCBhZGRpdGl2ZSBtb2RlbHMpLCBidXQgSSB3b24ndCB0cnkgdG8gcmUtY3JlYXRlIFt0aGUgZXhjZWxsZW50IHR1dG9yaWFsIGJ5IEphY29saWVuIHZhbiBSaWpdKGh0dHA6Ly9qYWNvbGllbnZhbnJpai5jb20vVHV0b3JpYWxzL0dBTU0uaHRtbCkgaGVyZS4KCgoKCgo=