The Agenda

  1. Follow up from the last meeting.
  2. More about interpreting the model output
  3. Homework review
  4. Pitfalls to look out for, and how to address them
  5. A modelling menu

Setup

library(tidyverse)
library(ggthemes)
library(broom)
library(lsa2017)

ah <- iy_ah %>% filter(plt_vclass == "ah")
iy <- iy_ah %>% filter(plt_vclass == "iy")
ay0 <- ay %>% filter(plt_vclass == "ay0")

And, in preparation of Thursday’s meeting, go ahead and install lme4, so we can catch any problems well in advance.

install.packages("lme4")

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 birth1 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

  1. You have a sensible intercept.
  2. 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

  1. If you must model these factors independently, residualize (Gorman, 2010)
  2. Or, just pick the one that is theoretically motivated (Fruehwald, 2016).
  3. 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:

  1. Did you have the heat on this morning?
  2. Are you wearing a wooly jumper?
  3. Are you wearing a scarf?
  4. Could you see your breath when you stepped outside?
  5. Did your glasses fog up when you walked inside?
  6. Did you make yourself a big breakfast?
  7. 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:

  1. Was it cold?
  2. 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

Building up a model

When approaching how to build up a model (which predictors should be included or excluded), I would caution against “kitchen sink” models, or trying to trying to outsource your reasoning to an automated step-wise regression.

I’ll summarise Gelman & Hill’s (2006) recommendations here:

  1. “Include all input variables that, for substantive reasons, might be expected to be important in predicting the outcome.”
    • Joe addendum: I think substantive reasons include “I have a good theory” and “Previous work has included these”.
  2. “It is not always necessary to include these inputs as separate predictors-—for example, sometimes several inputs can be averaged or stunmed to create a ‘total score’ that can be used as a single predictor in the model.”
  3. “For inputs that have large effects, consider including their interactions as well.”

Their recommendation for excluding a variable from a model is more nuance. They say:

  1. “If a predictor is not statistically significant and has the expected sign, it is generally fine to keep it in. It may not help predictions dramatically hut is also probably not hurting them.”
  2. “If a predictor is not statistically significant and does not have the expected sign (for example, incumbency having a negative effect on vote share), consider removing it from the model (that is, setting its coefilcient to zero).”
  3. “If a predictor is statistically significant and does not have the expected sign, then think hard if it makes sense.”
  4. “If a predictor is statistically significant and has the expected sign, then by all means keep it in the model.”

Modelling Menu

Curves

Increasingly, people are getting dissatisfied by assuming the relationship between their variables is linear. The growing standard for fitting curvy models are GAMs (generalized additive models), but I won’t try to re-create the excellent tutorial by Jacolien van Rij here.


  1. Actually, the rescaled predictor was “age”, but in that data it had more or less a 1-to-1 relationsip to year of birth.

LS0tCnRpdGxlOiAiTW9yZSBvbiBpbnRlcnByZXRpbmcgJiBmaXR0aW5nIGxpbmVhciBtb2RlbHMiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IG5vbmUKICAgIGNzczogLi4vY3VzdG9tLmNzcwogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfZGVwdGg6IDMKLS0tCgoKCiMgVGhlIEFnZW5kYQoKMS4gRm9sbG93IHVwIGZyb20gdGhlIGxhc3QgbWVldGluZy4KMi4gTW9yZSBhYm91dCBpbnRlcnByZXRpbmcgdGhlIG1vZGVsIG91dHB1dAozLiBIb21ld29yayByZXZpZXcKMy4gUGl0ZmFsbHMgdG8gbG9vayBvdXQgZm9yLCBhbmQgaG93IHRvIGFkZHJlc3MgdGhlbQo0LiBBIG1vZGVsbGluZyBtZW51CgoKPGRpdiBjbGFzcyA9ICJib3ggYnJlYWsiPgo8c3BhbiBjbGFzcyA9ICJiaWctbGFiZWwiPlNldHVwPC9zcGFuPgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KGxzYTIwMTcpCgphaCA8LSBpeV9haCAlPiUgZmlsdGVyKHBsdF92Y2xhc3MgPT0gImFoIikKaXkgPC0gaXlfYWggJT4lIGZpbHRlcihwbHRfdmNsYXNzID09ICJpeSIpCmF5MCA8LSBheSAlPiUgZmlsdGVyKHBsdF92Y2xhc3MgPT0gImF5MCIpCmBgYAoKCkFuZCwgaW4gcHJlcGFyYXRpb24gb2YgVGh1cnNkYXkncyBtZWV0aW5nLCBnbyBhaGVhZCBhbmQgaW5zdGFsbCBgbG1lNGAsIHNvIHdlIGNhbiBjYXRjaCBhbnkgcHJvYmxlbXMgd2VsbCBpbiBhZHZhbmNlLgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoImxtZTQiKQpgYGAKCjwvZGl2PgoKIyBGb2xsb3d1cAoKVGhlIHF1ZXN0aW9uIGNhbWUgdXAgbGFzdCB0aW1lIGFib3V0IHdoeSBpdCByZWFsbHkgbWF0dGVycyB0byBjZW50ZXIgYW5kIHNjYWxlIG91ciBwcmVkaWN0b3JzLiBIZXJlIGlzIGFuIGV4YW1wbGUgb2YgYSBkYXRhIHNldCBJJ3ZlIGxvb2tlZCBhdCwgd2hpY2ggaW52b2x2ZXMgdGhlIHJhaXNpbmcgb2YgL2F5LyBiZWZvcmUgdm9pY2VsZXNzIGNvbnNvbmFudHMuIEEgdmVyeSBzdHJvbmcgcHJlZGljdG9yIGlzIHRoZSBzcGVha2VyJ3MgeWVhciBvZiBiaXJ0aC4KCgpgYGB7cn0KYXkwX21lYW5zIDwtIGF5MCAlPiUKICAgICAgICAgICAgICBtdXRhdGUoZG9iID0geWVhci1hZ2UpJT4lCiAgICAgICAgICAgICAgZ3JvdXBfYnkoaWRzdHJpbmcsZG9iLCB3b3JkKSU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZShGMV9uID0gbWVhbihGMV9uKSklPiUKICAgICAgICAgICAgICBzdW1tYXJpc2UoRjFfbiA9IG1lYW4oRjFfbikpCgpnZ3Bsb3QoYXkwX21lYW5zLCBhZXMoZG9iLCBGMV9uKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBzY2FsZV95X3JldmVyc2UoKSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKCgpCdXQgaWYgSSBqdXN0IGZpdCBhIGxpbmVhciBtb2RlbCB3aXRoIHllYXIgb2YgYmlydGggYXMgYSBwcmVkaWN0b3IsIEkgZ2V0IGFuIGVudGlyZWx5IHVuaW50ZXJwcmV0YWJsZSBpbnRlcmNlcHQgdmFsdWUgdGhhdCBpcyBhY3R1YWxseSAqaW1wb3NzaWJsZSogZ2l2ZW4gdGhlIGRhdGEuCgpgYGB7cn0KYXkwX21vZGVsIDwtIGxtKEYxX24gfiBkb2IsIGRhdGEgPSBheTBfbWVhbnMpCnN1bW1hcnkoYXkwX21vZGVsKQpgYGAKCgpgYGB7cn0KZ2dwbG90KGF5MF9tZWFucywgYWVzKGRvYiwgRjFfbikpKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGNvZWYoYXkwX21vZGVsKVsxXSwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGNvZWYoYXkwX21vZGVsKVsxXSwKICAgICAgICAgICAgICAgIHNsb3BlID0gY29lZihheTBfbW9kZWwpWzJdKSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKClRoZSBzbG9wZSBpcyBhbHNvIHRvbyBzcGVjaWZpYywgZnJvbSBhIHRoZW9yZXRpY2FsIHBlcnNwZWN0aXZlLiBXZSB3b3VsZG4ndCByZWFsaXN0aWNhbGx5IGV4cGVjdCB0byBzZWUgcmVsaWFibGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBwZW9wbGUgYm9ybiBpbiAxOTU5IGFuZCAxOTYwLiBJbiBteSBvd24gd29yaywgSSd2ZSBkaXZpZGVkIHllYXIgb2YgYmlydGggYnkgMTAsIHJlc3VsdGluZyBpbiBhIGNvZWZmaWNpZW50IHJlYWRhYmxlIGFzIGEgY2hhbmdlIHBlciBkZWNhZGUuIExhYm92ICgyMDAxKSBkaXZpZGVzIHllYXIgb2YgYmlydGheW0FjdHVhbGx5LCB0aGUgcmVzY2FsZWQgcHJlZGljdG9yIHdhcyAiYWdlIiwgYnV0IGluIHRoYXQgZGF0YSBpdCBoYWQgbW9yZSBvciBsZXNzIGEgMS10by0xIHJlbGF0aW9uc2lwIHRvIHllYXIgb2YgYmlydGguXSBieSAyNSwgdG8gdHJ5IHRvIGdldCBhIHNsb3BlIGluIHRlcm1zIG9mIGEgImdlbmVyYXRpb24iLiBFaXRoZXIgd2F5IHdvcmtzLgoKYGBge3J9CmF5MF9tZWFucyA8LSBheTBfbWVhbnMgJT4lCiAgICAgICAgICAgICAgICBtdXRhdGUoZG9iX2MgPSAoZG9iLTE5NjApLzEwKQpheTBfbW9kZWwyIDwtIGxtKEYxX24gfiBkb2JfYywgZGF0YSA9IGF5MF9tZWFucykKc3VtbWFyeShheTBfbW9kZWwyKQpgYGAKCkFub3RoZXIgaW1wb3J0YW50IGZhY3RvciBpbiBjaG9vc2luZyB3aGVyZSB5b3UgY2VudGVyIHlvdXIgcHJlZGljdG9ycyBpcyBpZiB0aGVyZSdzIGEgc3Ryb25nIGludGVyYWN0aW9uIHdpdGggc29tZSBvdGhlciBwcmVkaWN0b3IuIEZvciBleGFtcGxlLCB0aGlzIHBsb3QgY29tcGFyZXMgcHJlLXZvaWNlZCB0byBwcmUtdm9pY2VsZXNzIFtheV0uIEl0IGlzIHBvc3NpYmxlIG1vZGVsIHRoaXMgZW50aXJlIGdyYXBoIGluIG9uZSBtb2RlbCB0aGF0IGhhcyBhbiBpbnRlcmFjdGlvbiBiZXR3ZWVuIHZvaWNpbmcgYW5kIGRhdGUgb2YgYmlydGguIEJ1dCB3aGVyZSB5b3UgY2hvb3NlIHRvIGNlbnRlciBkYXRlIG9mIGJpcnRoIHdpbGwgaGF2ZSBhIGJpZyBlZmZlY3Qgb24gdGhlIGVzdGltYXRlZCBwYXJhbWV0ZXJzISBDb21wYXJlIHRoZSBtb2RlbHMgd2l0aCBET0IgY2VudGVyZWQgb24gMTg5MCB2cyAxOTUwLgoKCmBgYHtyfQpheV9tZWFucyA8LSBheSAlPiUKICAgICAgICAgICAgICBtdXRhdGUoZG9iID0geWVhci1hZ2UpJT4lCiAgICAgICAgICAgICAgZ3JvdXBfYnkoaWRzdHJpbmcsIGRvYiwgcGx0X3ZjbGFzcywgd29yZCklPiUKICAgICAgICAgICAgICBzdW1tYXJpc2UoRjFfbiA9IG1lYW4oRjFfbikpICU+JQogICAgICAgICAgICAgIHN1bW1hcmlzZShGMV9uID0gbWVhbihGMV9uKSkKCmF5X21lYW5zICU+JQogIGdncGxvdChhZXMoZG9iLCBGMV9uLCBjb2xvciA9IHBsdF92Y2xhc3MpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIHN0YXRfc21vb3RoKG1ldGhvZCA9ICdsbScpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMTg5MCwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDE5NTAsIGxpbmV0eXBlID0gMikrICAKICAgIGFubm90YXRlKGdlb20gID0gImxhYmVsIiwKICAgICAgICAgICAgIHggPSAxODkwLAogICAgICAgICAgICAgeSA9IC0wLjI1LAogICAgICAgICAgICAgbGFiZWwgPSAiYSIpKwogICAgYW5ub3RhdGUoZ2VvbSAgPSAibGFiZWwiLAogICAgICAgICAgICAgeCA9IDE5NTAsCiAgICAgICAgICAgICB5ID0gLTAuMjUsCiAgICAgICAgICAgICBsYWJlbCA9ICJiIikrICAKICAgIHNjYWxlX3lfcmV2ZXJzZSgpKwogICAgc2NhbGVfY29sb3JfY29sb3JibGluZCgpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKYGBge3J9CmF5X21lYW5zIDwtIGF5X21lYW5zICU+JQogICAgICAgICAgICAgIG11dGF0ZShkb2JfY2VudGVyX2EgPSAoZG9iIC0gMTg5MCkgLyAxMCwKICAgICAgICAgICAgICAgICAgICAgZG9iX2NlbnRlcl9iID0gKGRvYiAtIDE5NTApIC8gMTApCgpheV9tb2RlbF9hIDwtIGxtKEYxX24gfiBkb2JfY2VudGVyX2EgKiBwbHRfdmNsYXNzLCBkYXRhID0gYXlfbWVhbnMpCmF5X21vZGVsX2IgPC0gbG0oRjFfbiB+IGRvYl9jZW50ZXJfYiAqIHBsdF92Y2xhc3MsIGRhdGEgPSBheV9tZWFucykKYGBgCgo8ZGl2IHN0eWxlID0gImZsb2F0OmxlZnQ7IHdpZHRoOjEwMCUiPgo8ZGl2IHN0eWxlID0gImZsb2F0OmxlZnQ7IHdpZHRoOjQ5JSI+CgpgYGB7cn0KdGlkeShheV9tb2RlbF9hKSAlPiUgc2VsZWN0KHRlcm0sIGVzdGltYXRlLCBwLnZhbHVlKQpgYGAKPC9kaXY+CjxkaXYgc3R5bGUgPSAiZmxvYXQ6bGVmdDsgd2lkdGg6NDklIj4KYGBge3J9CnRpZHkoYXlfbW9kZWxfYikgJT4lIHNlbGVjdCh0ZXJtLCBlc3RpbWF0ZSwgcC52YWx1ZSkKYGBgCjwvZGl2Pgo8L2Rpdj4KCkluIHRoZSBtb2RlbCB3aXRoIHRoZSAxODkwIGFzIHRoZSBpbnRlcmNlcHQsIHRoZSBjb2VmZmljaWVudCBmb3IgYGF5MGAgaXMgc21hbGwsIGFuZCBub3Qgc2lnbmlmaWNhbnQhIEluIHRoZSBtb2RlbCB3aXRoIGRvYiBjZW50ZXJlZCBhdCAxOTUwLCB0aGUgY29lZmZpY2llbnQgZm9yIGBheTBgIGlzIGxhcmdlIGFuZCB2ZXJ5IHNpZ25pZmljYW50LiBUaGlzIGlzIHNpbXBseSBiZWNhdXNlIHRoZXkgYXJlIGRlc2NyaWJpbmcgZGlmZmVyZW50IGxvY2F0aW9ucyBvbiB0aGUgcGxvdC4KCiMjIFNvIHdoYXQgaXMgdGhlICJyaWdodCIgdGhpbmcgdG8gZG8/CgpBdCB0aGlzIHBvaW50IGlzIHVzdWFseSB3aGVuIHRoZSAiU28gd2hhdCdzIHRoZSByaWdodCB0aGluZyB0byBkbz8iIHF1ZXN0aW9uIGNvbWVzIHVwLiBBbmQgdGhlIGFubm95aW5nIGFuc3dlciBpcyB0aGF0IHRoZXJlIGlzbid0IGEgY2xlYXIgY3V0IGFuc3dlciBvciBkZWNpc2lvbiBwcm9jZXNzLiBZb3Ugc2hvdWxkIGd1aWRlIHlvdXIgZGVjaXNpb25zIHRvIGJlIHN1cmUgdGhhdAoKMS4gWW91IGhhdmUgYSBzZW5zaWJsZSBpbnRlcmNlcHQuCjIuIFlvdXIgc2xvcGVzIGFyZSBkZWZpbmVkIGFjcm9zcyBhIHJlYXNvbmFibGUgcmFuZ2UgZm9yIHRoZSBkYXRhLgoKRm9yIG1hbnkgZGF0YSB0eXBlcywgdGhlIEdlbG1hbiAmIEhpbGwgKDIwMDYpIHJlY29tbWVuZGF0aW9uIChzdWJ0cmFjdCB0aGUgbWVhbiwgZGl2aWRlIGJ5IDIkXHRpbWVzJCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uKSB3aWxsIGRvIHRoZSB0cmljay4gRm9yIG90aGVycywgdGhlcmUgbWF5IGJlIHNvbWUgcGVvcGxlIG1ha2luZyBhIHRvcC1kb3duIGVmZm9ydCB0byBkZWZpbmUgYSBzY2FsaW5nIChlLmcuIHRoZSBbWmlwZiBTY2FsZSBmb3Igd29yZCBmcmVxdWVuY2llc10oaHR0cDovL2Nyci51Z2VudC5iZS9hcmNoaXZlcy8xMzUyKSkuIEZvciB0aGUgcmVtYWluaW5nIGNhc2VzLCBpZiBzb21lb25lIGhhcyBkb25lIHNvbWV0aGluZyBiZWZvcmUgYW5kIGl0IGRvZXNuJ3Qgc2VlbSBvYnZpb3VzbHkgd3JvbmcsIHRyeSB0aGF0IGZvciB0aGUgc2FrZSBvZiBjb21wYXJpYmlsaXR5LiBPdGhlcndpc2UsIGl0IGludm9sdmVzIGEgbG90IG9mIGRldmVsb3BtZW50IG9mIGEgbW9kZWwtZ2Vmw7xobC4KCgojIE1vcmUgbW9kZWwgaW50ZXJwcmV0YXRpb24KCkxldCdzIGNvbWUgYmFjayB0byBtb2RlbGxpbmcgdGhlIGVmZmVjdCBvZiBkdXJhdGlvbiBvbiB0aGUgRjEgb2YgYGFoYC4gCkhlcmUsIHdlJ2xsIGZpdCB0aGUgbW9kZWwgdXNpbmcgdGhlIGNlbnRlcmVkIGxvZzIoZHVyYXRpb24pIGxpa2UgYSByZWNvbW1lbmRlZCBvbiB0aGUgaG9tZXdvcmsuCgoKYGBge3IgZmlnLndpZHRoID0gOC8yLCBmaWcuaGVpZ2h0ID0gNS8yLCBvdXQud2lkdGggPSAiNTAlIn0KYWhfdG9tb2QgPC0gYWggJT4lCiAgICAgICAgICAgICAgIG11dGF0ZShsb2cyZHVyX2MgPSBsb2cyKGR1ciktbWVkaWFuKGxvZzIoZHVyKSkpCmFoX3RvbW9kICU+JQogIGdncGxvdChhZXMobG9nMmR1cl9jLCBGMV9uKSkrCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4wNSkrCiAgICB4bGFiKCJjZW50ZXJlZCBsb2cyKGR1cmF0aW9uKSIpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKYGBge3J9CmFoX21vZGVsIDwtIGxtKEYxX24gfiBsb2cyZHVyX2MsIGRhdGEgPSBhaF90b21vZCkKc3VtbWFyeShhaF9tb2RlbCkKYGBgCgpUaGUgaW50ZXJjZXB0IGlzIHRoZSBlc3RpbWF0ZWQgRjFfbiBhdCB0aGUgbWVkaWFuIGR1cmF0aW9uLCBhbmQgdGhlIHNsb3BlIGBsb2cyZHVyX2NgIGlzIHRoZSBlc3RpbWF0ZWQgaW5jcmVhc2UgaW4gbm9ybWFsaXplZCBGMSBmb3IgZXZlcnkgZG91Ymxpbmcgb2YgZHVyYXRpb24uCkxldCdzIHdhbGsgdGhyb3VnaCB0aGVzZSByZXN1bHRzIG1vcmUgc2xvd2x5LgoKIyMgUmVzaWR1YWxzCgo8ZGl2IGNsYXNzID0gImhhbGYtaW1nIj4KIVtdKGZpZ3VyZXMvcmVzaWQucG5nKQo8L2Rpdj4KClRoaXMgaXMgYSBzby1jYWxsZWQgImZpdmUgbnVtYmVyIHN1bW1hcnkiIG9mIHRoZSByZXNpZHVhbHMgKHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGZpdHRlZCBsaW5lIGFuZCB0aGUgYWN0dWFsIGRhdGEgcG9pbnRzKS4KR2l2ZW4gdGhlIGFzc3VtcHRpb25zIHRoYXQgdGhlIG1vZGVsIG1ha2VzIChlLmcuIHRoZSBkYXRhIGNhbiBiZSBkZXNjcmliZWQgYnkgYSBsaW5lIHdpdGggc29tZSByZXNpZHVhbCBlcnJvciksIHlvdSdsbCB3YW50IHRvIHNlZSB0aGVzZSB2YWx1ZXMgYmVpbmcgZmFpcmx5IHN5bW1ldHJpY2FsLCB3aXRoIHRoZSBtZWRpYW4ganVzdCBhYm91dCAwLiBJZiB0aGlzIGlzbid0IHRoZSBjYXNlLCB0aGVuIHlvdSBzaG91bGQgcHJvYmFibHkgbWFrZSBzb21lIG1vcmUgcGxvdHMgb2YgdGhlIGRhdGEgdG8gZmlndXJlIG91dCB3aGF0J3MgZ29pbmcgb24uCgojIyBTdGFuZGFyZCBFcnJvciBhbmQgdC12YWx1ZQoKPGRpdiBjbGFzcyA9ICJoYWxmLWltZyI+CgohW10oZmlndXJlcy9zdGRlcnIucG5nKQoKPC9kaXY+CgpUaGVzZSBhcmUgZmFpcmx5IHN0cmFpZ2h0Zm9yd2FyZCBtZWFzdXJlcyBvZiB0aGUgdW5jZXJ0YWludHkgYWJvdXQgdGhlIGNvZWZmaWNpZW50IGVzdGltYXRlcyB0aGF0IHlvdSBjYW4gcmVhc29uIGFib3V0IHNhZmVseSB3aXRob3V0IGhhdmluZyB0YWtlbiBhIHBoaWxvc29waHkgY291cnNlLiBUaGUgYmlnZ2VyIHRoZSBzdGFuZGFyZCBlcnJvciwgdGhlIGxlc3MgY2VydGFpbnR5IHRoZXJlIGlzIGFib3V0IHRoZSB0aGUgcGFyYW1ldGVycy4gVGhlIHQtdmFsdWUgaXMganVzdCB0aGUgY29lZmZpY2llbnQgZGl2aWRlZCBieSB0aGUgc3RhbmRhcmQgZXJyb3IsIHNvIHRoZSBiaWdnZXIgaXQgaXMsIHRoZSBtb3JlIGNlcnRhaW50eSB0aGVyZSBpcy4gKlJvdWdobHkqIHNwZWFraW5nLCBpZiB0aGUgdC12YWx1ZSBpcyBncmVhdGVyIHRoYW4gMiwgdGhlIGVmZmVjdCBpcyBwcm9iYWJseSByZWxpYWJsZS4KCgojIyAkcl4yJAoKPGRpdiBjbGFzcyA9ICJoYWxmLWltZyI+CgohW10oZmlndXJlcy9yc3F1YXJlZC5wbmcpCgo8L2Rpdj4KClRoaXMgaXMgYSBtZWFzdXJlIG9mIGhvdyBtdWNoIG1vZGVsbGluZyB5b3VyIG91dGNvbWUgZGF0YSBhcyBhIHN0cmFpZ2h0IGxpbmUgd2l0aCB5b3VyIGNob3NlbiBwcmVkaWN0b3JzIGhhcyByZWR1Y2VkIHRoZSB2YXJpYWJpbGl0eSBpbiB0aGUgZGF0YS4gVGhpcyBpcyBhIGhlbHBmdWwgZW5vdWdoIGhldXJpc3RpYywgYnV0IGNhbid0IGJlIHRha2VuIGFzIGFuIGludHJpbnNpY2FsbHkgaW5mb3JtYXRpdmUgdmFsdWUuIFdlIGNhbiByb3VnaGx5IHZpc3VhbGl6ZSB0aGlzIGJ5IHBsb3R0aW5nIGRlbnNpdHkgZGlzdHJpYnV0aW9ucyBvZiBvdXIgZGF0YSAoY2VudGVyZWQgb24gdGhlIG1lYW4pIGFuZCB0aGUgbW9kZWwgcmVzaWR1YWxzLgoKYGBge3J9CmFoX3RvbW9kICU+JQogIGdncGxvdChhZXMobG9nMmR1cl9jLCBGMV9uKSkrCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4wNSkrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtZWFuKGFoX3RvbW9kJEYxX24pKSsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGNvZWYoYWhfbW9kZWwpWzFdLAogICAgICAgICAgICAgICAgc2xvcGUgPSBjb2VmKGFoX21vZGVsKVsyXSwKICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKCgoKYGBge3J9CmFoX3RvbW9kJHJlc2lkIDwtIHJlc2lkKGFoX21vZGVsKQphaF90b21vZCAlPiUKICBtdXRhdGUoRjFfbl9jID0gRjFfbiAtIG1lYW4oRjFfbikpJT4lCiAgZ2dwbG90KCkrCiAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSBGMV9uX2MsIGNvbG9yID0gImNlbnRlcmVkIGRhdGEiKSkrCiAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSByZXNpZCwgY29sb3IgPSAicmVzaWR1YWxzIikpKwogICAgdGhlbWVfbWluaW1hbCgpKwogICAgZ2d0aXRsZShwYXN0ZTAoInItc3F1YXJlZCA9ICIsIHJvdW5kKHN1bW1hcnkoYWhfbW9kZWwpJHIuc3F1YXJlZCwgZGlnaXRzID0gMikpKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbChOVUxMLCB2YWx1ZXMgPSBjKCJibGFjayIsICJyZWQiKSkKYGBgCgpUaGUgZGlzdHJpYnV0aW9uIG9mIHRoZSByZXNpZHVhbHMgaW4gcmVkIGlzIGp1c3Qgc2xpZ2h0bHkgbmFycm93ZXIgdGhhbiB0aGUgZGF0YSwgd2hpY2ggaXMgd2h5IHRoZSByLXNxdWFyZWQgaXMgZmFpcmx5IG1vZGVzdC4KClNvbWV0aW1lcyB5b3UgY2FuIGdldCBhIHJlYWxseSBsYXJnZSByLXNxdWFyZWQgYnkgaW5jbHVkaW5nIGEgYmlnIGFuZCBvYnZpb3VzIHByZWRpY3RvciwgdGhhdCBkb2Vzbid0IHJlYWxseSBjb250cmlidXRlIHRvIG91ciB1bmRlcnN0YW5kaW5nLiBGb3IgZXhhbXBsZSwgZm9yIHRoZSB3aG9sZSBgaXlfYWhgIGRhdGEgc2V0LCB0aGUgbGFyZ2VzdCBudW1iZXIgb25lIHByZWRpY3RvciBmb3IgdGhlIG1vZGVsIGlzIHRoZSB2b3dlbCBjbGFzcywgc2luY2UgYGl5YCBhbmQgYGFoYCBhcmUgY29udHJhc3RpdmVseSBkaWZmZXJlbnQgYWxvbmcgRjEuIAoKYGBge3J9Cml5X2FoX21vZGVsIDwtIGxtKEYxX24gfiBwbHRfdmNsYXNzLCBkYXRhID0gaXlfYWgpCnN1bW1hcnkoaXlfYWhfbW9kZWwpCmBgYAoKYGBge3J9Cml5X2FoJHJlc2lkIDwtIHJlc2lkKGl5X2FoX21vZGVsKQppeV9haCAlPiUKICBtdXRhdGUoRjFfbl9jID0gRjFfbiAtIG1lYW4oRjFfbikpJT4lCiAgICBnZ3Bsb3QoKSsKICAgICAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gRjFfbl9jLCBjb2xvciA9ICJjZW50ZXJlZCBkYXRhIikpKwogICAgICBnZW9tX2RlbnNpdHkoYWVzKHggPSByZXNpZCwgY29sb3IgPSAicmVzaWR1YWxzIikpKwogICAgICB0aGVtZV9taW5pbWFsKCkrCiAgICAgIGdndGl0bGUocGFzdGUwKCJyLXNxdWFyZWQgPSAiLCByb3VuZChzdW1tYXJ5KGl5X2FoX21vZGVsKSRyLnNxdWFyZWQsIGRpZ2l0cyA9IDIpKSkrCiAgICAgIHNjYWxlX2NvbG9yX21hbnVhbChOVUxMLCB2YWx1ZXMgPSBjKCJibGFjayIsICJyZWQiKSkKYGBgCgoKUi1zcXVhcmVkIGlzIHByb2JhYmx5IGJlc3QgdXNlZCB3aGVuICpjb21wYXJpbmcqIHR3byBtb2RlbHMuIEZvciBhbiBleGFtcGxlLCBzZWUgdGhlIGJhciBwbG90cyBvbiBbcGFnZSAxMiBvZiB0aGlzIHBhcGVyXShodHRwOi8vd3d3LnN0YXQuY29sdW1iaWEuZWR1L35nZWxtYW4vcmVzZWFyY2gvdW5wdWJsaXNoZWQvY29ob3J0X3ZvdGluZ18yMDE0MDYwNS5wZGYpLgoKIyMgSW50ZXJwcmV0aW5nIG90aGVyIHBlb3BsZSdzIG1vZGVscwoKTW9yZSBvciBsZXNzLCBpZiB5b3Ugc2VlIHNvbWVvbmUgcmVwb3J0ICpvbmx5KiB0aGUgcC12YWx1ZSBmb3IgdGhlaXIgZWZmZWN0cyB3aXRob3V0IHRoZSBjb2VmZmljaWVudHMsIGVzcGVjaWFsbHkgaWYgdGhleSdyZSB3b3JraW5nIHdpdGggYSBsb3Qgb2YgZGF0YSwgcmVhY2ggZm9yIHlvdXIgd2FsbGV0LiBJZiB5b3UgYXJlIHJldmlld2luZyBhIHBhcGVyIHdoZXJlIHRoaXMgaGFwcGVucywgbWFrZSBpdCBhIHJlcXVpcmVkIHJldmlzaW9uIHRoYXQgZWl0aGVyIHRoZXkgbmVlZCB0byBpbmNsdWRlIHRoZSBjb2VmZmljaWVudHMsIG9yIGRyb3AgdGhhdCBxdWFudGl0YXRpdmUgY29tcG9uZW50LgoKCgojIFBpdGZhbGxzIGluIE1vZGVsbGluZwoKCiMjIFR5cGUgSSBhbmQgVHlwZSBJSSBFcnJvcgoKVGhlc2UgYXJlIHBvb3JseSBuYW1lZCwgYW5kIEkgdGhpbmsgZmV3IHBlb3BsZSByZW1lbWJlciB3aGljaCBpcyB3aGljaCBjb3JyZWN0bHkgdGhlIGZpcnN0IHRpbWUuIFRoZXNlIGFyZSBlcnJvcnMgcmVsYXRlZCB0byB0aGUgdXNlIG9mIHAtdmFsdWVzLiBGaXJzdCBpdCdzIGltcG9ydGFudCB0byBkZWZpbmUgd2hhdCB0aGUgKipOdWxsIEh5cG90aGVzaXMqKiBpcy4KCi0gKipUaGUgTnVsbCBIeXBvdGhlc2lzIGlzIHRoZSBEdWxsIEh5cG90aGVzaXM6KiogVGhlIE51bGwgSHlwb3RoZXNpcyBpcyB0aGF0IHRoZXJlIGlzIG5vIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBvdXRjb21lIGFuZCBwcmVkaWN0b3JzLiBJdCBpcyAqbm90KiB3aGF0IHlvdSB0aGluayB0aGUgbW9zdCBsaWtlbHkgcmVsYXRpb25zaGlwIGlzLgoKV2l0aCB0aGF0IGluIG1pbmQsIHdlIGNhbiBkZWZpbmUgVHlwZSBJIGFuZCBUeXBlIElJIGVycm9ycy4KCi0gKipUeXBlIEkqKiAtIFlvdSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyAoYmVjYXVzZSBwIDwgMC4wNSksIGJ1dCBpbiByZWFsaXR5IHRoZXJlICppc24ndCogYSByZWxhdGlvbnNoaXAuIFRoYXQgaXMsIHlvdSBzYXkgdGhlcmUgaXMgYSByZWxpYWJsZSBlZmZlY3Qgd2hlbiB0aGVyZSBpc24ndCBvbmUuCi0gKipUeXBlIElJKiogLSBZb3UgZmFpbCB0byByZWplY3QgdGhlIG51bGwgaHlwb3RlaHNpcyB3aGVuIHRoZXJlICppcyogYW4gcmVhbCBlZmZlY3QuIAoKT3IgdG8gcHV0IGl0IGFub3RoZXIgd2F5LCB3aGVuIHlvdSBzZWUgYSBzdGF0aXN0aWNhbCByZXN1bHQgdGhhdCBpcyBzaWduaWZpY2FudCAocCA8IDAuMDUpLCBidXQgeW91IGRvbid0IHRoaW5rIGl0IGNvdWxkIHBvc3NpYmx5IGJlIHJlYWwsIHlvdSB0aGluayBhIFR5cGUgSSBlcnJvciBoYXMgb2NjdXJyZWQuCgpBbmQgd2hlbiB5b3UgZ2V0IHAgPiAwLjA1LCBidXQgeW91IHJlYWxseSB0aGluayB0aGVyZSdzIHNvbWV0aGluZyB0aGVyZSBzbyB5b3UgcHV0ICJ0cmVuZGluZyB0b3dhcmRzIHNpZ25pZmljYW5jZSIgaW4geW91ciBwYXBlciwgeW91IHRoaW5rIGEgVHlwZSBJSSBlcnJvciBoYXMgb2NjdXJyZWQuCgpUaGUgYmVzdCB3YXkgdG8gYW1lbGlvcmF0ZSBUeXBlIEkgYW5kIFR5cGUgSUkgZXJyb3JzIGlzIHRvIGVpdGhlciBjb2xsZWN0IG1vcmUgZGF0YSwgb3IgdG8gbW92ZSB0byBCYXllc2lhbiBTdGF0aXN0aWNzLCB3aGljaCB3ZSB3b24ndCBiZSBhYmxlIHRvIGNvdmVyIGluIHRoaXMgY291cnNlLCBbYnV0IEkgcmVjb21tZW5kIHRoaXMgYm9va10oaHR0cHM6Ly9zaXRlcy5nb29nbGUuY29tL3NpdGUvZG9pbmdiYXllc2lhbmRhdGFhbmFseXNpcy8pLgoKCgogCiAKIyMgVHlwZSBNIGFuZCBUeXBlIFMgZXJyb3JzCgpUaGVzZSBhcmUgZXJyb3IgdHlwZXMgW2Rpc2N1c3NlZCBieSBHZWxtYW4gYW5kIGNvbGxlYWd1ZXNdKGh0dHA6Ly93d3cuc3RhdC5jb2x1bWJpYS5lZHUvfmdlbG1hbi9yZXNlYXJjaC9wdWJsaXNoZWQvUFBTNTUxNjQyX1JFVjIucGRmKSAoYW5kIGFyZSBiZXR0ZXIgbmFtZWQpLgoKIC0gKipUeXBlIE0gRXJyb3JzKiogYXJlIGdyb3NzIG92ZXItZXN0aW1hdGlvbiBvZiB0aGUgKm1hZ25pdHVkZSogb2YgYW4gZWZmZWN0IHNpemUuCiAtICoqVHlwZSBTIEVycm9ycyoqIGdldCB0aGUgKnNpZ24qIHdyb25nIG9uIGFuIGVzdGltYXRlLiBUaGF0IGlzLCB0aGV5IHByZWRpY3QgYW4gZWZmZWN0IGluIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb24gb2Ygd2hhdCB0aGUgdHJ1ZSBlZmZlY3QgaXMuCiAKVHlwZSBNIG1pZ2h0IG5vdCBzb3VuZCBsaWtlIGEgdmVyeSBiaWcgcHJvYmxlbSwgYW5kIFR5cGUgUyBtaWdodCBzb3VuZCBhIGJpdCBvdXRsYW5kaXNoIGJ1dCB0aGVzZSBjYW4gYm90aCBoYXBwZW4sIGVzcGVjaWFsbHkgd2hlbiB3ZSBhcmUgW2V4cGxvcmluZyBmb3Igc21hbGwgZWZmZWN0cyBhbmQgZmlsdGVyaW5nIHJlc3VsdHMgYnkgdGhlaXIgcC12YWx1ZXNdKGh0dHA6Ly9ycHVicy5jb20vSm9Gcmh3bGQvMjkxNzM0KS4gR2VsbWFuIGhhcyBwcm9wb3NlZCB0aGF0IFtUeXBlIE0gZXJyb3JzIGFyZSBhIGxpa2VseSBjdWxwcml0IGluIHRoZSBzby1jYWxsZWQgImRlY2xpbmUgZWZmZWN0Il0oaHR0cDovL2FuZHJld2dlbG1hbi5jb20vMjAxMC8xMi8xMy90aGVfdHJ1dGhfd2VhcnMvKSwgd2hpY2ggaXMgYSBwaGVub21lbm9uIHNvbWUgaGF2ZSBmb3VuZCB0aGF0IGxhcmdlIGFuZCBzaWduaWZpY2FudCBlZmZlY3RzIGdyYWR1YWxseSBnZXQgc21hbGxlciBhZnRlciB0aGVpciBvcmlnaW5hbCByZXBvcnRzLgoKSGVyZSBhcmUgc29tZSB3YXlzIHRvIGd1YXJkIHlvdXNlbGYgYWdhaW5zdCBUeXBlIE0gYW5kIFR5cGUgUyBlcnJvcnMuCgotIFRyeSB0byByZWFzb24gaG93IGJpZyB0aGUgZWZmZWN0IGlzICpsaWtlbHkqIHRvIGJlLgotIFRyeSB0byBjb2xsZWN0IG9mIGhvdyBvdGhlciBmYWN0b3JzIGVmZmVjdCB0aGUgb3V0Y29tZSB5b3UncmUgaW52ZXN0aWdhdGluZywgYW5kIGhvdyBiaWcgdGhvc2UgZWZmZWN0cyBhcmUuCi0gQ29tbWl0IHRvIHRoZSAqZGlyZWN0aW9uKiBvZiB0aGUgZWZmZWN0LgoKVHlwZSBNIGFuZCBUeXBlIFMgZXJyb3JzIGFyZSBvbmx5IGdvaW5nIHRvIGdyb3cgaW4gc2V2ZXJpdHkgYXMgW3RoZSBzaXplIG9mIGRhdGEgc2V0cyBncm93XShodHRwOi8vam9mcmh3bGQuZ2l0aHViLmlvL3BhcGVycy9wbGMzOV8yMDE1LyMvKS4KCgojIyBPdmVyZml0dGluZwoKCgpgYGB7cn0KYXkwX21lYW5zICU+JQogIGdncGxvdChhZXMoZG9iLCBGMV9uKSkrCiAgICAjZ2VvbV9wb2ludCgpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xtJywgCiAgICAgICAgICAgICAgICBzZSA9IEYsCiAgICAgICAgICAgICAgICBhZXMoY29sb3IgPSAibGluZSIpKSsKICAgIHN0YXRfc21vb3RoKG1ldGhvZCA9ICdsb2VzcycsIAogICAgICAgICAgICAgICAgc2UgPSBGLAogICAgICAgICAgICAgICAgYWVzKGNvbG9yID0gImN1cnZlIikpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xvZXNzJywgCiAgICAgICAgICAgICAgICBzZSA9IEYsCiAgICAgICAgICAgICAgICBzcGFuID0gMC4xLCAKICAgICAgICAgICAgICAgIGFlcyhjb2xvciA9ICJidW1weSBjdXJ2ZSIpKSsKICAgIHNjYWxlX2NvbG9yX2JyZXdlcigibW9kZWwiLCBwYWxldHRlID0gIkRhcmsyIikrCiAgICBzY2FsZV95X3JldmVyc2UoKSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKCgoKCiMjIENvbGxpbmVhcml0eQoKIkNvbGxpbmVhcml0eSIgaXMgd2hlbiB0d28gcG90ZW50aWFsIHByZWRpY3RvcnMgYXJlIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlci4gV2hlbiB0d28gY29ycmVsYXRlZCBwcmVkaWN0b3JzIGFyZSBpbmNsdWRlZCBpbiB0aGUgc2FtZSByZWdyZXNzaW9uLCB0aGUgcmVzdWx0cyBjYW4gYmUgKndvbmt5KiBhdCBiZXN0LiBbR29ybWFuICgyMDEwKV0oaHR0cDovL3JlcG9zaXRvcnkudXBlbm4uZWR1L2NnaS92aWV3Y29udGVudC5jZ2k/YXJ0aWNsZT0xMTQ2JmNvbnRleHQ9cHdwbCkgdGFsa3MgYWJvdXQgdGhpcyBhdCBsZW5ndGggd2l0aCByZXNwZWN0IHRvIHNvY2lvZWNvbm9taWMgbWVhc3VyZXMgaW4gdGhlIExhbmd1YWdlIENoYW5nZSBhbmQgVmFyaWF0aW9uIHN0dWR5LiBGb3IgZXhhbXBsZSwgc3BlYWtlcnMnIE9jY3VwYXRpb24gd2FzIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggdGhlIHZhbHVlIG9mIHRoZWlyIFJlc2lkZW5jZS4gWW91ICpzaG91bGRuJ3QqIGluY2x1ZGUgdGhlc2UgYm90aCwgdW50cmVhdGVkLCBpbnRvIHlvdXIgbW9kZWxzLiAKCgpUaGVyZSBhcmUgYXQgbGVhc3QgdGhyZWUgZGlmZmVyZW50IHN0cmF0ZWdpZXMgZm9yIGRlYWxpbmcgd2l0aCB0aGlzIGlzc3VlCgoxLiBJZiB5b3UgKm11c3QqIG1vZGVsIHRoZXNlIGZhY3RvcnMgaW5kZXBlbmRlbnRseSwgcmVzaWR1YWxpemUgKEdvcm1hbiwgMjAxMCkKMi4gKk9yKiwganVzdCBwaWNrIHRoZSBvbmUgdGhhdCBpcyB0aGVvcmV0aWNhbGx5IG1vdGl2YXRlZCAoRnJ1ZWh3YWxkLCAyMDE2KS4KMy4gKk9yKiBnaXZlIHVwIG9uIHRyZWF0aW5nIHlvdXIgbWVhc3VyZXMgYXMgaGF2aW5nIGluZGVwZW5kZW50IHJlYWxpdHksIHJlYWxpemUgdGhleSBhcmUgcmVmbGVjdGlvbnMgb2YgbW9yZSBhYnN0cmFjdCBkaW1lbnNpb25zLCBhbmQgdHJ5IHRvIGZpZ3VyZSBvdXQgd2hhdCB0aG9zZSBhcmUgKGkuZS4gZmFjdG9yIGFuYWx5c2lzLCBXYWxrZXIgKDIwMTYpKS4KCgojIyMgUmVzaWR1YWxpemF0aW9uCgpMaWtlIHRoZSBuYW1lIHN1Z2dlc3RzLCB0aGlzIGludm9sdmVzIHRoZSByZXNpZHVhbHMgZnJvbSBhIGxpbmVhciBtb2RlbC4gSWYgeW91IHJlYWxseSB3YW50IHRvIGZpdCBhIG1vZGVsIGxpa2UgdGhpczoKCmBgYApuZWdhdGl2ZV9jb25jb3JkIH4gb2NjdXBhdGlvbiArIHJlc2lkZW5jZQpgYGAKClRoZW4gd2hhdCB5b3UgbmVlZCB0byBkbyBmaXJzdCBpcyBmaXQgdGhpcyBtb2RlbC4KCmBgYApyZXNpZGVuY2UgfiBvY2N1cGF0aW9uCmBgYAoKQW5kIHJlcGxhY2UgdGhlIGByZXNpZGVuY2VgIHRlcm0gaW4gdGhlIGZpcnN0IG1vZGVsIHdpdGggdGhlICpyZXNpZHVhbHMqIG9mIHRoZSBzZWNvbmQgbW9kZWwuIE5vdywgaXQgZG9lcyBtYXR0ZXIgd2hpY2ggb3JkZXIgeW91IHJlc2lkdWFsaXplIGluLiBIb3cgZG8geW91IGNob29zZT8gQWdhaW4sIHRoZXJlJ3Mgbm8gaGFyZCBhbmQgZmFzdCBhbnN3ZXIsIGJ1dCBwbGVhc2UgZG9uJ3QgdHJ5IGl0IGV2ZXJ5IHBvc3NpYmxlIHdheSBhbmQgdGhlbiBqdXN0IGNob29zZSB0aGUgbW9kZWwgdGhhdCBsb29rcyBiZXN0IQoKIyMjIEZhY3RvciBBbmFseXNpcwoKQW5vdGhlciBhcHByb2FjaCB3b3VsZCBiZSB0byBhYmFuZG9uIHRyeWluZyB0byBsb29rIGF0IGFsbCBvZiB0aGVzZSBwcmVkaWN0b3JzIGluZGVwZW5kZW50bHkgYW5kIHRvIHRyZWF0IHRoZW0gYWxsIGFzIHJvdWdoIG1lYXN1cmVzIGNvcnJlbGF0ZWQgdG8gYSBtb3JlIGFic3RyYWN0IHZhcmlhYmxlLCB1c2luZyBzb21ldGhpbmcgbGlrZSBhIGZhY3RvciBhbmFseXNpcy4gVGhpcyBpcyB3aGF0IFdhbGtlciAoMjAxNikgZGlkLgoKVGhlIGJlc3Qgd2F5IHRvIGV4cGxhaW4gYSBmYWN0b3IgYW5hbHlzaXMgaXMgdG8gaW1hZ2luZSBzdXJ2ZXlpbmcgYSBidW5jaCBvZiBwZW9wbGUgb24gdGhlIHN0cmVldCBhbmQgYXNraW5nIHRoZW0gdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6CgoxLiBEaWQgeW91IGhhdmUgdGhlIGhlYXQgb24gdGhpcyBtb3JuaW5nPwoyLiBBcmUgeW91IHdlYXJpbmcgYSB3b29seSBqdW1wZXI/CjMuIEFyZSB5b3Ugd2VhcmluZyBhIHNjYXJmPwo0LiBDb3VsZCB5b3Ugc2VlIHlvdXIgYnJlYXRoIHdoZW4geW91IHN0ZXBwZWQgb3V0c2lkZT8KNS4gRGlkIHlvdXIgZ2xhc3NlcyBmb2cgdXAgd2hlbiB5b3Ugd2Fsa2VkIGluc2lkZT8KNi4gRGlkIHlvdSBtYWtlIHlvdXJzZWxmIGEgYmlnIGJyZWFrZmFzdD8KNy4gV2FzIHlvdXIgc3RvbWFjaCBncm93bGluZyB3aGVuIHlvdSB3b2tlIHVwPwoKClRoaXMgbG9va3MgbGlrZSB5b3UndmUgYXNrZWQgcGVvcGxlIDcgZGlmZmVyZW50IHF1ZXN0aW9ucywgYnV0IHJlYWxseSwgeW91J3ZlIG9ubHkgZWZmZWN0aXZlbHkgYXNrZWQgMiBxdWVzdGlvbnM6IAoKMS4gV2FzIGl0IGNvbGQ/CjIuIFdlcmUgeW91IGh1bmdyeT8KCklmIHlvdSB0b29rIHRoZSByYXcgZGF0YSBmcm9tIHRoZSA3IHF1ZXN0aW9uIHN1cnZleSBhbmQgcmFuIGl0IHRocm91Z2ggYSBmYWN0b3IgYW5hbHlzaXMsIGl0IHdvdWxkIChpZGVhbGx5KSB0ZWxsIHlvdSB0aGF0IHRoZXJlIGFyZSBvbmx5IDIgZWZmZWN0aXZlIHF1ZXN0aW9ucyBpbiBpdCwgYmFzZWQgb24gaG93IHJlc3BvbnNlcyB0byBxdWVzdGlvbnMgMSB0aHJ1IDUgYXJlIGNvcnJlbGF0ZWQgd2l0aCBlYWNoIG90aGVyLCBhbmQgNiY3IGFyZSBjb3JyZWxhdGVkIHdpdGggZWFjaCBvdGhlci4KCgotLS0KCgpDb2xsaW5lYXJpdHkgb2Z0ZW4gY29tZXMgdXAgYXMgYSBwaXRmYWxsIG9mIG9mIGVzdGltYXRpbmcgZWZmZWN0cy4gQnV0IGl0J3MgYWxzbyBhbiBpc3N1ZSB3aGVuIHRyeWluZyB0byB1bmRlcnN0YW5kIG91ciBtb2RlbHMuIEEgY29tbW9uLCBhbm5veWluZywgYW5kIHVzdWFsbHkgdmFsaWQgcXVlc3Rpb24gaXM6Cgo+IENvdWxkbid0IHlvdXIgZWZmZWN0IG9mIEEgKmFjdHVhbGx5KiBiZSBhbiBlZmZlY3Qgb2YgQj8KClRoZSBiZXN0IHdheSB0byBkZWFsIHdpdGggdGhpcyBraW5kIG9mIGNvbGxpbmVhcml0eSBpcyB0byB0cnkgdG8ga2lsbCB5b3VyIGVmZmVjdHMuIERvZXMgdGhlIHNhbWUgZWZmZWN0IGhvbGQgaW4gdGhlIHNhbWUgZGlyZWN0aW9uIGZvciBpbXBvcnRhbnQgc3Vic2V0cyBvZiB0aGUgZGF0YT8gQ2FuIHlvdSBzdWJzZXQgdGhlIGRhdGEgYWNjb3JkaW5nIHRvIEIgYW5kIGZpdCBzZXBhcmF0ZSBtb2RlbHMgZm9yIEE/CgoKIyMgQWRkaXRpb25hbCBTdHJ1Y3R1cmUKCgpgYGB7ciBlY2hvID0gRn0KcmVhbF9kYXRhIDwtIGRhdGFfZnJhbWUoeCA9IHJub3JtKDIwMCksCiAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAoLTAuNSAqIHgpICsgOCArIHJub3JtKDIwMCkpCmdncGxvdChyZWFsX2RhdGEsIGFlcyh4LCB5KSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBzdGF0X3Ntb290aChtZXRob2QgPSAnbG0nKQpgYGAKCgpgYGB7ciBlY2hvID0gRn0gCnBvaW50X2xpbmVfZGlzdGFuY2UgPC0gZnVuY3Rpb24oYiwgbSwgeCwgeSkKICAoeSAtIChtKnggKyBiKSkvc3FydChtXjIgKyAxKQoKY29uZm91bmRlZF9kYXRhX2ZyYW1lIDwtIGZ1bmN0aW9uKHgsIHksIG0sIG51bV9ncnApewogIGIgPC0gMCAjIGludGVyY2VwdCBkb2Vzbid0IG1hdHRlcgogIGQgPC0gcG9pbnRfbGluZV9kaXN0YW5jZShiLCBtLCB4LCB5KQogIGRfc2NhbGVkIDwtIDAuMDAwNSArIDAuOTk5ICogKGQgLSBtaW4oZCkpLyhtYXgoZCkgLSBtaW4oZCkpICMgYXZvaWQgMCBhbmQgMQogIGRhdGEuZnJhbWUoeD14LCB5PXksIAogICAgICAgICAgICBncm91cD1hcy5mYWN0b3Ioc3ByaW50ZigiZ3JwJTAyZCIsIGNlaWxpbmcobnVtX2dycCooZF9zY2FsZWQpKSkpKQp9CgoKY29uZl9kZiA8LSBjb25mb3VuZGVkX2RhdGFfZnJhbWUocmVhbF9kYXRhJHgsIHJlYWxfZGF0YSR5LCBtID0gMSwgbnVtX2dycCA9IDMpCgoKZ2dwbG90KGNvbmZfZGYsIGFlcyh4LCB5KSkrCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGdyb3VwKSkrCiAgICBzdGF0X3Ntb290aChtZXRob2QgPSBsbSwgY29sb3IgPSAnYmxhY2snLCBsaW5ldHlwZSA9IDIpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gbG0sIGFlcyhjb2xvciA9IGdyb3VwKSkKYGBgCgoKIyBCdWlsZGluZyB1cCBhIG1vZGVsCgpXaGVuIGFwcHJvYWNoaW5nIGhvdyB0byBidWlsZCB1cCBhIG1vZGVsICh3aGljaCBwcmVkaWN0b3JzIHNob3VsZCBiZSBpbmNsdWRlZCBvciBleGNsdWRlZCksIEkgd291bGQgY2F1dGlvbiBhZ2FpbnN0ICJraXRjaGVuIHNpbmsiIG1vZGVscywgb3IgdHJ5aW5nIHRvIHRyeWluZyB0byBvdXRzb3VyY2UgeW91ciByZWFzb25pbmcgdG8gYW4gYXV0b21hdGVkIHN0ZXAtd2lzZSByZWdyZXNzaW9uLgoKSSdsbCBzdW1tYXJpc2UgR2VsbWFuICYgSGlsbCdzICgyMDA2KSByZWNvbW1lbmRhdGlvbnMgaGVyZToKCjEuICJJbmNsdWRlIGFsbCBpbnB1dCB2YXJpYWJsZXMgdGhhdCwgZm9yIHN1YnN0YW50aXZlIHJlYXNvbnMsIG1pZ2h0IGJlIGV4cGVjdGVkIHRvIGJlIGltcG9ydGFudCBpbiBwcmVkaWN0aW5nIHRoZSBvdXRjb21lLiIKICAgIC0gSm9lIGFkZGVuZHVtOiBJIHRoaW5rIHN1YnN0YW50aXZlIHJlYXNvbnMgaW5jbHVkZSAiSSBoYXZlIGEgZ29vZCB0aGVvcnkiIGFuZCAiUHJldmlvdXMgd29yayBoYXMgaW5jbHVkZWQgdGhlc2UiLgoyLiAiSXQgaXMgbm90IGFsd2F5cyBuZWNlc3NhcnkgdG8gaW5jbHVkZSB0aGVzZSBpbnB1dHMgYXMgc2VwYXJhdGUgcHJlZGljdG9ycy3igJRmb3IgZXhhbXBsZSwgc29tZXRpbWVzIHNldmVyYWwgaW5wdXRzIGNhbiBiZSBhdmVyYWdlZCBvciBzdHVubWVkIHRvIGNyZWF0ZSBhICd0b3RhbCBzY29yZScgdGhhdCBjYW4gYmUgdXNlZCBhcyBhIHNpbmdsZSBwcmVkaWN0b3IgaW4gdGhlIG1vZGVsLiIKMy4gIkZvciBpbnB1dHMgdGhhdCBoYXZlIGxhcmdlIGVmZmVjdHMsIGNvbnNpZGVyIGluY2x1ZGluZyB0aGVpciBpbnRlcmFjdGlvbnMgYXMgd2VsbC4iCgpUaGVpciByZWNvbW1lbmRhdGlvbiBmb3IgZXhjbHVkaW5nIGEgdmFyaWFibGUgZnJvbSBhIG1vZGVsIGlzIG1vcmUgbnVhbmNlLiBUaGV5IHNheToKCmEuICJJZiBhIHByZWRpY3RvciBpcyBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhbmQgaGFzIHRoZSBleHBlY3RlZCBzaWduLCBpdCBpcyBnZW5lcmFsbHkgZmluZSB0byBrZWVwIGl0IGluLiBJdCBtYXkgbm90IGhlbHAgcHJlZGljdGlvbnMgZHJhbWF0aWNhbGx5IGh1dCBpcyBhbHNvIHByb2JhYmx5IG5vdCBodXJ0aW5nIHRoZW0uIgpiLiAiSWYgYSBwcmVkaWN0b3IgaXMgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYW5kIGRvZXMgbm90IGhhdmUgdGhlIGV4cGVjdGVkIHNpZ24gKGZvciBleGFtcGxlLCBpbmN1bWJlbmN5IGhhdmluZyBhIG5lZ2F0aXZlIGVmZmVjdCBvbiB2b3RlIHNoYXJlKSwgY29uc2lkZXIgcmVtb3ZpbmcgaXQgZnJvbSB0aGUgbW9kZWwgKHRoYXQgaXMsIHNldHRpbmcgaXRzIGNvZWZpbGNpZW50IHRvIHplcm8pLiIKYy4gIklmIGEgcHJlZGljdG9yIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYW5kIGRvZXMgbm90IGhhdmUgdGhlIGV4cGVjdGVkIHNpZ24sIHRoZW4gdGhpbmsgaGFyZCBpZiBpdCBtYWtlcyBzZW5zZS4iCmQuICJJZiBhIHByZWRpY3RvciBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGFuZCBoYXMgdGhlIGV4cGVjdGVkIHNpZ24sIHRoZW4gYnkgYWxsIG1lYW5zIGtlZXAgaXQgaW4gdGhlIG1vZGVsLiIKCgoKCgojIE1vZGVsbGluZyBNZW51CgoKIyMgRGlmZmVyZW50ICJsaW5rcyIKCllvdSBtYXkgYmUgdmVyeSBsaWtlbHkgdG8gaGF2ZSBkYXRhIHlvdSB3YW50IHRvIG1vZGVsIHdoaWNoIGlzIG5vdCBsaWtlIHRoZSBmb3JtYW50IGRhdGEgaGVyZS4gCllvdSBtYXkgaGF2ZSBjYXRlZ29yaWNhbCBkYXRhIG9mIGhvdyBvZnRlbiBzb21ldGhpbmcgZGlkIG9yIGRpZG4ndCBoYXBwZW4uCk9yIHlvdSBtaWdodCBvbmx5IGhhdmUgZGF0YSBvbiBob3cgb2Z0ZW4gc29tZXRoaW5nICpkaWQqIGhhcHBlbi4KVGhlcmUgYXJlIHdheXMgdG8gZml0IHN0YXRpc3RpY2FsIG1vZGVscyB3aXRoIHRoZXNlIGtpbmRzIG9mIGRhdGEgdGhhdCBmb3IgdGhlIG1vc3QgcGFydCBpbnZvbHZlIHRoZSBzYW1lIGtpbmQgb2YgZGVjaXNpb25zIGFib3V0IHByZWRpY3RvcnMgYW5kIGludGVycHJldGF0aW9ucyBvZiB0aGUgcGFyYW1ldGVycy4KCiMjIyBCaW5hcnkgRGF0YQoKU29jaW9saW5ndWlzdHMgaGF2ZSBiZWVuIHdvcmtpbmcgd2l0aCBiaW5hcnkgZGF0YSBmb3IgYSBsb25nIHRpbWUuIEV4YW1wbGVzIGluIGNsdWRlOgoKLSAqKlREIERlbGV0aW9uKio6IG1pc3QgdnMgbWlzJwotICoqSU5HKio6IHdhbGtpbmcgdnMgd2Fsa2luJwotICoqRmlsbGVkIFBhdXNlcyoqOiB1bSB2cyB1aAoKVGhlc2UgYXJlIHVzdWFsbHkgY29kZWQgYXMgYDBgIG9yIGAxYCwgYW5kIGl0IGlzIGluYXBwcm9wcmlhdGUgdG8gZml0IGEgbGluZWFyIHJlZ3Jlc3Npb24gdG8gdGhlc2UgdmFsdWVzLiBJbnN0ZWFkLCBmaXQgYSAqKmxvZ2lzdGljIHJlZ3Jlc3Npb24qKgoKIyMjIFJhdGUgRGF0YQoKU29tZXRpbWVzLCBpdCdzIG5vdCBwb3NzaWJsZSB0byBkZXNjcmliZSBhIGxpbmd1aXN0aWMgdmFyaWFibGUgaW4gdGVybXMgb2YgaG93IG1hbnkgdGltZXMgaXQgZGlkIGFuZCBkaWRuJ3QgaGFwcGVuLiBGb3IgZXhhbXBsZSBSaWNrZm9yZCAmIFByaWNlICgyMDEzKSB3YW50ZWQgdG8gZXhwbG9yZSBjaGFuZ2VzIGFjcm9zcyB0aGUgbGlmZXNwYW4gZm9yIGNlcnRhaW4gQUFWRSBmZWF0dXJlcywgaW5jbHVkaW5nIGhhYml0dWFsLWJlLgoKLSAiSSBiZSB3YWtpbmcgdXAuLi4gYW5kIEkgYmUgZ29pbmcuIiAoKDEpIGZyb20gUmlja2ZvcmQgJiBQcmljZSAoMjAxMykpCgpBIGRpZmZpY3VsdHkgaXMgdGhhdCBpdCdzIHByb2JhYmx5IGltcG9zc2libGUgdG8gdGVsbCB3aGVuIHNvbWVvbmUgKmNvdWxkKiB1c2UgaGFiaXR1YWwtYmUsIGJ1dCBkaWRuJ3QuIFdoYXQgdGhleSBkaWQgaW5zdGVhZCB3YXMgcmVwb3J0IGhvdyBvZnRlbiB0aGVpciBzcGVha2VycyB1c2VkIGhhYml0dWFsLWJlICpwZXIgaG91ciBvZiBpbnRlcnZpZXcqLiAKCklmIHlvdXIgZGF0YSBpcyBiZXN0IGRlc2NyaWJlZCBsaWtlIHRoaXMsIG5vdCBhcyBhIHByb3BvcnRpb24gb2Ygb2NjdXJhbmNlLCBidXQgYXMgYSByYXRlLCBbbGlrZSBYIHBlciAxMDAwIHdvcmRzXShodHRwOi8vcmVwb3NpdG9yeS51cGVubi5lZHUvY2dpL3ZpZXdjb250ZW50LmNnaT9hcnRpY2xlPTE5MjYmY29udGV4dD1wd3BsKSwgdGhlbiB5b3UgY2FuIGZpdCBhICoqcG9pc3NvbiByZWdyZXNzaW9uKiouCgojIyBDdXJ2ZXMKCkluY3JlYXNpbmdseSwgcGVvcGxlIGFyZSBnZXR0aW5nIGRpc3NhdGlzZmllZCBieSBhc3N1bWluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlaXIgdmFyaWFibGVzIGlzIGxpbmVhci4gVGhlIGdyb3dpbmcgc3RhbmRhcmQgZm9yIGZpdHRpbmcgY3VydnkgbW9kZWxzIGFyZSBHQU1zIChnZW5lcmFsaXplZCBhZGRpdGl2ZSBtb2RlbHMpLCBidXQgSSB3b24ndCB0cnkgdG8gcmUtY3JlYXRlIFt0aGUgZXhjZWxsZW50IHR1dG9yaWFsIGJ5IEphY29saWVuIHZhbiBSaWpdKGh0dHA6Ly9qYWNvbGllbnZhbnJpai5jb20vVHV0b3JpYWxzL0dBTU0uaHRtbCkgaGVyZS4KCgoKCgo=