Agenda

Today, we’re going to start with trying to understand and fit some linear regressions.

Setup

~2 Minute Setup

Create your R Notebook for today and double check that your workspace is clear from last time.

Load the important packages for today:

library("ggplot2")
library("scales")
library("lsa2017")
library("tidyverse")
library("broom")

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

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

Understanding Linear Regression

I find the best way to understand linear regressions is as recipes for drawing a graph. Let’s start off with an example relevant to my own life: the relationship between temperatures in Celcius and temperatures in Farentheit. There are two important numeric constants to convert back and forth between them:

  1. Freezing = 0°C = 32°F
  2. A change of 1°C = 1.8°F

This gives us all of the necessary components for drawing a graph of the relationship between Farentheit and Celcius. First, we know that a line plotting this relationship must cross 0 on the x-axis at 32 on the y-axis, because freezing = 0°C = 32°F.

Next, we know that for 1 every degree we move to the right, we must move up 1.8.

The line, representing this relationship, thus has the formula:

\[ y = 32 + (1.8\times x) \]

And looks like

This line has the following properties:

  1. Its Intercept, or where the line crosses 0 on the x-axis, is 32.
  2. Its Slope, is 1.8 (that is, a change of 1 on the x-axis corresponds to a change in 1.8 on the y-axis)

And, in fact, all lines, including the ones we fit using linear regression, are described in terms of their intercept (where the line crosses 0 on the x-axis) and slope.

But, let’s say you didn’t know the formula to convert back and forth between Celcius and Farentheit. Maybe you weren’t even sure that there was such a formula. And all you had were a bunch of kind of crappy thermometers that gave you both Celcius and Farentheit readings. And maybe the thermometers are kind of hard to read, or the lighting conditions are dark, or you only have limited experience in reading thermometers. In that case, the relationship between Celcius and Farentheit might look a lot more like this:

In this case, you might want to fit a linear regression. A linear regression assumes that the relationship between two variables can be captured using some line, and it tries to estimate the Intercept and Slope of this assumed line.

The way it does this is by trying to find parameters for a line that minimize the “error” or the “residuals” between the observed data, and the line. For example, here are examples of bad lines. The first assumes that all temperatures Celcius are basically 50°F. The other assumes that all temperatures in Farentheit are basically 3\(\times\)C.

Here is a plot of the best-fitting line, that has the smallest average residuals.

There are actually many different ways to figure out what the best line is (remembering that by “line” we really mean the pairing of Intercept and Slope). For example, one really simplistic approach1 would be just to draw a bunch of different lines, and see which one worked best.

However, there have been some long established methods for solving this problem, at is, for finding the one and truly best Intercept and Slope for a given set of data points.

Idiom

This isn’t R idiom, but stats idiom. Here are some translations for how people describe solving this problem.

  • analytic, closed form = “We solved it with complicated math.”
  • iterative, stochastic = “We made a bunch of guesses.”

For the sake of finishing the illustration, here is the solution that a linear regression found for this sample data:


Call:
lm(formula = f_observe ~ c_observe, data = temp_df)

Coefficients:
(Intercept)    c_observe  
     41.414        1.344  

The model has estimated that the Intercept is \(\approx\) 41 and the slope is \(\approx\) 1.3 . That is to say, based on our “sample”, it thinks 0°C = 41°F, and that every 1°C increase corresponds to a 1.3°F increase.

We are lucky to know that this is, strictly speaking, wrong, but we won’t usually, or typically, be able to in such a situation. However, the estimate of both the intercept and slope have the right sign (that is, it hasn’t guessed the intercept is -10, or the slope goes the other way), and they’re just about the right magnitude (that is, it hasn’t guessed that the slope is something like 10, or 100).

Now, let’s consider how the linear model is describing the value of this highlighted dot.

First, you take it’s value in Celcius, and multiply it by 1.3 (which is 22.55)

Then,you add 40 to it (which is 63.96)

Then, you add the residual error to give us the observed data point.

The generic formula for finding the value for any data point is

\[ F_i = 41.4 + (1.3\times C_i) + \epsilon_i. \] In this formula the \(i\) is convention for referring to some generic, \(i^{th}\) data point and \(\epsilon\) is conventional for referring to the residual errors.

Some additional conventions:

  • Referring to the outcome variable as \(y\).
  • Referring to the predictors as \(x\).
  • Referring to the remaining parameters as \(\beta\).

So you may sometimes see people referring to \(\beta_0\), or the “betas” in a model. The fully generic formula for linear regression is sometimes given as

\[ y = \beta_0 + \beta x + \epsilon \]

Idiom

  • We call the Intercept and Slopes the parameters or coefficients of the model.
  • For every data point, the value you get by only using the slopes and intercepts are called the fitted values, and they all lie along the lines you draw.
  • Almost every data point’s actual value is different from it’s fitted value, and these differences are called the residuals.

Thinking about a realer case

Here is some actual data you might work with. Below is a graph of the relationship between vowel duration and normalized F1 for the LOT vowel (i.e. "ah" in the iy_ah data frame). Each point is one vowel token. I predict that as the duration gets longer, the vowels should also get lower (i.e. have a higher F1) for a bunch of different reasons.

~5 Minute Discussion

This real data on duration and F1 is different from the example Celcius and Farentheit in a bunch of different (and important ways). In small groups, discuss what they might be.

Fitting a linear model

In R, the syntax for fitting a simple linear model is very straight forward. The function is called lm(), for linear model.

lm(outcome ~ predictor, data)

  • outcome
    • This is the variable whose value that you’re trying to predict, e.g. vowel F1.
  • predictor
    • This is the variable you’re usuing the predict the outcome value
  • data
    • the data frame that contains the data we’re modelling with.

We can fit a linear regression for the ah data set like so:

ah_model <- lm(F1_n ~ dur, data = ah)

~2 minute activity

Fit the ah_model using the code above. Then look at the summary like so:

summary(ah_model)

Call:
lm(formula = F1_n ~ dur, data = ah)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.8049 -0.3773  0.0133  0.3927  3.3113 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.60431    0.01083   55.82   <2e-16 ***
dur          3.50071    0.07421   47.17   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6302 on 21117 degrees of freedom
Multiple R-squared:  0.09533,   Adjusted R-squared:  0.09529 
F-statistic:  2225 on 1 and 21117 DF,  p-value: < 2.2e-16

Look over these numbers, and (without looking down too much further!), discuss in small groups what you understand here, and how to interpret the outcome.

Visualizing this model.

Before we even get to those “p-values” and what they even mean, let’s talk about the coefficients.

  • (Intercept) 0.60431
    • This is the intercept of the line, meaning when dur = 0, F1_n is predicted to be about 0.6.
  • dur 3.50071
    • This is the slope, meaning when dur increases by 1 second, we predict F1_n to increase by about 3.5

Here’s how that looks visualized on our data set.

Thinking about the model

Some things not so great about these coefficients:

  1. They’re overly precise.
    • At the best of times, linguistics is a one or two decimal place field.
  2. The Intercept makes no sense.
    • Not only are there no vowels with 0 duration in this data set, there can’t be a vowel with 0 duration.
  3. The slope makes very little sense.
    • It’s possible for a vowel to be 1 second long, but it’s not likely. The longest vowels in this data set (0.8s) are probably forced alignment errors. The vast majority of vowels in this data are <0.25s.

The good news is that these problems are fixable by “rescaling” or “standardizing” our predictor.

Fixing the intercept.

The simplest thing to do to fix the intercept would be to try to figure out where the line crosses the x-axis at some other value, instead of 0. Why not try to estimate where it crosses x at the median duration (0.12) instead?

The bad news that we can’t easilly make a linear model try to estimate this value. All the math surrounding fitting linear models is based on trying to estimate where the line crosses the x-axis at 0.

The good news is that we can trick the model into estimating this number, by just subtracting out the median duration from duration!

ah <- ah %>%
        mutate(dur_center = dur - median(dur))

Doing this is not only “allowed”, it is encouraged. Simply adding or subtracting a constant value from a continuous predictor won’t affect it’s statistical significance. But it does make the intercept of the model more interpretable.

ah_model_c <- lm(F1_n ~ dur_center, data = ah)
summary(ah_model_c)

Call:
lm(formula = F1_n ~ dur_center, data = ah)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.8049 -0.3773  0.0133  0.3927  3.3113 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 1.024392   0.004453  230.03   <2e-16 ***
dur_center  3.500713   0.074211   47.17   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6302 on 21117 degrees of freedom
Multiple R-squared:  0.09533,   Adjusted R-squared:  0.09529 
F-statistic:  2225 on 1 and 21117 DF,  p-value: < 2.2e-16

Fixing the slope

The next issue to deal with is the slope parameter. The interpretation of the slope parameter as it is is that for every 1 second vowel duration increases, normalize F1 increases 3.5. While this may be accurate, it’s not exactly useful, because the full range of the data, including the extreme outliers doesn’t span a whole 1 second.

summary(ah$dur)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0500  0.0900  0.1200  0.1337  0.1610  0.8700 

Again, what we would like the model to do is tell us not how much normalized F1 will change when the duration changes by 1 second, but maybe something more like 50ms. And again, we can’t directly make the model do this, but we can trick it into doing so, but dividing duration by some value.

What is standard in these circumstances is to divide the predictor variable by its standard deviation, a measure of how spread out the data is from its center point. Gelman & Hill (2006) recommend actually dividing by the standard deviation times 2.

ah <- ah %>%
          mutate(dur_z = dur_center/(sd(dur_center)*2))
ah_model_z <- lm(F1_n ~ dur_z, data = ah)
summary(ah_model_z)

Call:
lm(formula = F1_n ~ dur_z, data = ah)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.8049 -0.3773  0.0133  0.3927  3.3113 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 1.024392   0.004453  230.03   <2e-16 ***
dur_z       0.409123   0.008673   47.17   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6302 on 21117 degrees of freedom
Multiple R-squared:  0.09533,   Adjusted R-squared:  0.09529 
F-statistic:  2225 on 1 and 21117 DF,  p-value: < 2.2e-16

Now, the slope is describing how much normalized F1 increases every time the vowel duration increases 2 standard deviations, \(\approx\) 100ms

Describing what we just did

Table XX displays the estimated parameters predicting normalized F1 of /ɑ/. Duration was centered at the median and scaled by two times its standard deviation (117) per the recommendation of Gelman & Hill (2006).

term estimate std.error t_value p.value
(Intercept) 1.02 0.004 230 0
Scaled Duration 0.41 0.009 47 0

Pause for Questions/Debugging

Evaluating our model

So, is this model any good? This question can be approached from a few different angles.

  1. Is it possible that any of our model parameters are 0?
  2. How great is our uncertainty about the specific model parameters? That is, the model has estimated an intercept of 1.02. How much wiggle room is there?
  3. Do all of our model parameters have the right sign? That is, are they predicting an effect in the “right” direction?
  4. Are our model parameters a reasonable size? Is it possible that any of them are being dramatically overestimated?
summary(ah_model_z)

Call:
lm(formula = F1_n ~ dur_z, data = ah)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.8049 -0.3773  0.0133  0.3927  3.3113 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 1.024392   0.004453  230.03   <2e-16 ***
dur_z       0.409123   0.008673   47.17   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6302 on 21117 degrees of freedom
Multiple R-squared:  0.09533,   Adjusted R-squared:  0.09529 
F-statistic:  2225 on 1 and 21117 DF,  p-value: < 2.2e-16

Some of these questions fall under the rubric of “null hypothesis testing.” When people say their results are “significant”, or p<0.05 this is what they’re talking about. In its current use, people often try to divide their predictor variables into those which “have an effect” and those that “don’t have an effect” and they often use p-values to do this.

The summary of the linear model contains the p-values in the final column called Pr(>|t|). Here my best shot at a definition of p-values:

P Values

If we assume that the slope of the line is actually 0 there is no relationship present in the data, the probability we would observe a slope as extreme as, or more extreme than this, given the size of the sample and the variance of the data, is the p-value.

Typically, we take p < 0.05 as the cut off for saying it would be highly improbable to observe a slope of this size if the slope were actually 0 there was no relationship in the data, so the slope is probably not 0, we reject the null hypothesis that there is no relationship in the data.

A problem with p-values is that even if you’ve read that paragraph, you probably still don’t actually understand what p-values are. And when you do really understand what p-values are, you’ll probably forget what they really are. In fact, I tweeted out what I was planning to say about p-values, and based on the feedback I had to make some changes (as evidenced by the strike throughs).

My hypothesis is that truly understanding what p-values are requires a kind of counterfactual thinking and conditional probability that people are actually very bad at, even people who work with p-values all the time.

The fact of the matter is that you must include p-values in your writeups of your analyses because society demands it. However I think it is important to be judicious. If you have a p-value greater than 0.05, your evaluation of the effect should be downgraded. If you have a p-value less than 0.05, it’s also important not to stop there and conclude that the effect is “real”.

With that in mind it’s crucial to also ask whether the estimated effect is in the expected direction, and whether the effect size is sensible. Addressing these two questions requires having some background to draw one (previously reported effect sizes in the lit), a good theoretical reason for fitting this particular model, and perhaps some contextual info.

If you don’t have any reason to hypothesize an effect in any particular direction (could be positive, could be negative), then you might not be ready, as far as your inferences go, to use statistical modelling yet.

For our particular model, I had some pretty good reasons to assume a positive effect, which is what we got. Is 0.41 a “big” or a “small” effect? Compared to what?

Multiple Regression

We often want to figure out how multiple possible predictors influence the data we’re investigating. Such models are called “multiple regression”. For the ah regression, we’re next going to add the word context in which the vowel appears:

table(ah$context)

coextensive       final     initial    internal 
          2         239         304       20574 

We’re going to focus on just word final and word internal contexts.

ah_2 <- ah %>% filter(context %in% c("internal", "final"))

Adding context to the model is as easy as + context

ah_mod_mult <- lm(F1_n ~ dur_z + context, data = ah_2)
summary(ah_mod_mult)

Call:
lm(formula = F1_n ~ dur_z + context, data = ah_2)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.8182 -0.3768  0.0128  0.3916  3.3103 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)     0.805895   0.040797  19.754  < 2e-16 ***
dur_z           0.413973   0.008755  47.283  < 2e-16 ***
contextinternal 0.219005   0.040959   5.347 9.04e-08 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6283 on 20810 degrees of freedom
Multiple R-squared:  0.09723,   Adjusted R-squared:  0.09714 
F-statistic:  1121 on 2 and 20810 DF,  p-value: < 2.2e-16

Here’s how to interpret these results. First, when you add a categorical predictor to a model, one of the categories is chosen as a reference level.2 The (Intercept) is now the estimated F1_n when all of the predictors are 0 or the reference level. For this model, that means the predicted value when dur_z==0 and context=="final".

We can, for now, interpret the slope dur_z as being the slope for word final ah.

The effect of context=internal can be interpeted as how much offset the intercept of the line for the internal context is:

And the slope of the word internal context is the same as the word final context, as far as this model is concerned.

Evaluating this model.

~5 Minute Discussion

What do we think of this model? Does context have an effect?

summary(ah_mod_mult)

Call:
lm(formula = F1_n ~ dur_z + context, data = ah_2)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.8182 -0.3768  0.0128  0.3916  3.3103 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)     0.805895   0.040797  19.754  < 2e-16 ***
dur_z           0.413973   0.008755  47.283  < 2e-16 ***
contextinternal 0.219005   0.040959   5.347 9.04e-08 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6283 on 20810 degrees of freedom
Multiple R-squared:  0.09723,   Adjusted R-squared:  0.09714 
F-statistic:  1121 on 2 and 20810 DF,  p-value: < 2.2e-16

Interactions

The fact that the two slopes of word-final and word-internal ah were the same above was an assumption of the model. To put it another way, it didn’t find that the two slopes were different because it didn’t look. But it is possible that the slopes of these two contexts are different, and that we should explore this possibility. This is done by entering context into the model like so:

ah_mod_interact <- lm(F1_n ~ dur_z * context, data = ah_2)
summary(ah_mod_interact)

Call:
lm(formula = F1_n ~ dur_z * context, data = ah_2)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.8278 -0.3762  0.0130  0.3917  3.3104 

Coefficients:
                      Estimate Std. Error t value Pr(>|t|)    
(Intercept)            0.84728    0.04475  18.934  < 2e-16 ***
dur_z                  0.31189    0.04622   6.748 1.54e-11 ***
contextinternal        0.17721    0.04497   3.940 8.16e-05 ***
dur_z:contextinternal  0.10589    0.04707   2.249   0.0245 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6282 on 20809 degrees of freedom
Multiple R-squared:  0.09745,   Adjusted R-squared:  0.09732 
F-statistic: 748.9 on 3 and 20809 DF,  p-value: < 2.2e-16

Here’s how to interpret this model. First, the (Intercept) is the estimated F1_n for ah when dur_z==0 and context=="final".

The dur_z slope is the estimated slope for context=="final".

The effect of context=="final" is how offset the intercept for the final context is

And the interaction term is how different the slope of the final context is. That is, the dashed blue line shows the final context slope if it were the same as the internal context, the solid blue line is the estimated slope of the final context, and the difference is what is represented in the interaction term.

Reading an even Realer Example

Here is an example regression table from one of my own papers (Fruehwald 2016). I was looking at the F1 nucleus of /ay/ using the following predictors:

  • Speaker’s year of birth
  • Voicing of the following segment
  • The frequency of the word

Discussion

How should we read these results?

Next Week - Mixed Effects Models and Model Selection


  1. Actually, this “simplistic approach” is more like the sophisticated approach these days, because there are complicated maths behind making good guesses which are given semantically opaque names like “Simulated Annealing” and “Hamiltonian Monte Carlo”.

  2. There are actually other approaches to encoding categorical predictors that don’t involve choosing a reference level that we’re not going to get to.

LS0tCnRpdGxlOiAiRml0dGluZyBMaW5lYXIgTW9kZWxzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgY29kZV9mb2xkaW5nOiBub25lCiAgICBjc3M6IC4uL2N1c3RvbS5jc3MKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdG9jX2RlcHRoOiAzCi0tLQoKCiMgQWdlbmRhCgpUb2RheSwgd2UncmUgZ29pbmcgdG8gc3RhcnQgd2l0aCB0cnlpbmcgdG8gdW5kZXJzdGFuZCBhbmQgZml0IHNvbWUgbGluZWFyIHJlZ3Jlc3Npb25zLiAKCiMgU2V0dXAKCjxkaXYgY2xhc3MgPSAiYm94IGJyZWFrIj4KPHNwYW4gY2xhc3MgPSAnYmlnLWxhYmVsJz5+MiBNaW51dGUgU2V0dXA8L3NwYW4+CgpDcmVhdGUgeW91ciBSIE5vdGVib29rIGZvciB0b2RheSBhbmQgZG91YmxlIGNoZWNrIHRoYXQgeW91ciB3b3Jrc3BhY2UgaXMgY2xlYXIgZnJvbSBsYXN0IHRpbWUuCgpMb2FkIHRoZSBpbXBvcnRhbnQgcGFja2FnZXMgZm9yIHRvZGF5OgoKYGBge3J9CmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KCJzY2FsZXMiKQpsaWJyYXJ5KCJsc2EyMDE3IikKbGlicmFyeSgidGlkeXZlcnNlIikKbGlicmFyeSgiYnJvb20iKQoKaXkgPC0gaXlfYWggJT4lCiAgICAgICAgZmlsdGVyKHBsdF92Y2xhc3MgPT0gIml5IikKCmFoIDwtIGl5X2FoICU+JQogICAgICAgIGZpbHRlcihwbHRfdmNsYXNzID09ICJhaCIpCgpgYGAKCjwvZGl2PgoKIyBVbmRlcnN0YW5kaW5nIExpbmVhciBSZWdyZXNzaW9uCgoKCkkgZmluZCB0aGUgYmVzdCB3YXkgdG8gdW5kZXJzdGFuZCBsaW5lYXIgcmVncmVzc2lvbnMgaXMgYXMgcmVjaXBlcyBmb3IgZHJhd2luZyBhIGdyYXBoLiBMZXQncyBzdGFydCBvZmYgd2l0aCBhbiBleGFtcGxlIHJlbGV2YW50IHRvIG15IG93biBsaWZlOiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGVtcGVyYXR1cmVzIGluIENlbGNpdXMgYW5kIHRlbXBlcmF0dXJlcyBpbiBGYXJlbnRoZWl0LiBUaGVyZSBhcmUgdHdvIGltcG9ydGFudCBudW1lcmljIGNvbnN0YW50cyB0byBjb252ZXJ0IGJhY2sgYW5kIGZvcnRoIGJldHdlZW4gdGhlbToKCjEuIEZyZWV6aW5nID0gMCYjMTc2O0MgPSAzMiYjMTc2O0YKMi4gQSBjaGFuZ2Ugb2YgMSYjMTc2O0MgPSAxLjgmIzE3NjtGCgoKVGhpcyBnaXZlcyB1cyBhbGwgb2YgdGhlIG5lY2Vzc2FyeSBjb21wb25lbnRzIGZvciBkcmF3aW5nIGEgZ3JhcGggb2YgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIEZhcmVudGhlaXQgYW5kIENlbGNpdXMuIEZpcnN0LCB3ZSBrbm93IHRoYXQgYSBsaW5lIHBsb3R0aW5nIHRoaXMgcmVsYXRpb25zaGlwIG11c3QgY3Jvc3MgMCBvbiB0aGUgeC1heGlzIGF0IDMyIG9uIHRoZSB5LWF4aXMsIGJlY2F1c2UgZnJlZXppbmcgPSAwJiMxNzY7QyA9IDMyJiMxNzY7Ri4KCgpgYGB7ciBlY2hvID0gRn0KbGlicmFyeShncmlkKQpnZ3Bsb3QoKSsKICB4bGltKC0zLCA0MCkrCiAgeWxpbSgwLCA0MCkrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgID0gMikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgID0gMikrCiAgYW5ub3RhdGUoZ2VvbSA9ICJzZWdtZW50IiwgeCA9IDAsIHkgPSAwLCB4ZW5kID0gMCwgeWVuZCA9IDMyLAogICAgICAgICAgIHNpemUgPSAxLCBhcnJvdyA9IGFycm93KCkpKwogIGFubm90YXRlKGdlb20gPSAicG9pbnQiLCB4ID0gMCwgeSA9IDMyLCBjb2xvciA9ICdyZWQnKSsKICB4bGFiKCJDZWxjaXVzIikrCiAgeWxhYigiRmFyZW50aGVpdCIpKwogIHRoZW1lX21pbmltYWwoKSsKICBjb29yZF9maXhlZCgpCmBgYAoKTmV4dCwgd2Uga25vdyB0aGF0IGZvciAxIGV2ZXJ5IGRlZ3JlZSB3ZSBtb3ZlIHRvIHRoZSByaWdodCwgd2UgbXVzdCBtb3ZlIHVwIDEuOC4KCmBgYHtyIGVjaG8gPSBGfQoKZmMgPC0gZGF0YV9mcmFtZShjZWxjaXVzID0gYygwLCAxLCAyLCAzLCA0KSwKICAgICAgICAgICAgICAgICBmYXJlbnRoZWl0ID0gKGNlbGNpdXMgKiAxLjgpICsgMzIpCgpnZ3Bsb3QoZmMpKwogIHhsaW0oLTMsIDQwKSsKICB5bGltKDAsIDQwKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsKICBhbm5vdGF0ZShnZW9tID0gInNlZ21lbnQiLCB4ID0gMCwgeSA9IDAsIHhlbmQgPSAwLCB5ZW5kID0gMzIsCiAgICAgICAgICAgc2l6ZSA9IDEsIGFycm93ID0gYXJyb3coKSkrCiAgZ2VvbV9zdGVwKGFlcyh4ICA9IGNlbGNpdXMsIHkgPSBmYXJlbnRoZWl0KSkrICAKICBnZW9tX3BvaW50KGFlcyh4ICA9IGNlbGNpdXMsIHkgPSBmYXJlbnRoZWl0KSwgCiAgICAgICAgICAgICBjb2xvciA9ICdyZWQnKSsKICB4bGFiKCJDZWxjaXVzIikrCiAgeWxhYigiRmFyZW50aGVpdCIpKwogIHRoZW1lX21pbmltYWwoKSsKICBjb29yZF9maXhlZCgpCmBgYAoKVGhlIGxpbmUsIHJlcHJlc2VudGluZyB0aGlzIHJlbGF0aW9uc2hpcCwgdGh1cyBoYXMgdGhlIGZvcm11bGE6CgokJAp5ID0gMzIgKyAoMS44XHRpbWVzIHgpCiQkCgpBbmQgbG9va3MgbGlrZQoKYGBge3IgZWNobyA9IEZ9CgpnZ3Bsb3QoZmMpKwogIHhsaW0oLTMsIDYwKSsKICB5bGltKDAsIDYwKSsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsKICBhbm5vdGF0ZShnZW9tID0gInNlZ21lbnQiLCB4ID0gMCwgeSA9IDAsIHhlbmQgPSAwLCB5ZW5kID0gMzIsCiAgICAgICAgICAgc2l6ZSA9IDEsIGFycm93ID0gYXJyb3coKSkrCiAgZ2VvbV9zdGVwKGFlcyh4ICA9IGNlbGNpdXMsIHkgPSBmYXJlbnRoZWl0KSkrICAKICBnZW9tX3BvaW50KGFlcyh4ICA9IGNlbGNpdXMsIHkgPSBmYXJlbnRoZWl0KSwgCiAgICAgICAgICAgICBjb2xvciA9ICdyZWQnKSsKICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAzMiwgc2xvcGUgPSAxLjgsIGNvbG9yID0gJ3JlZCcpKwogIHhsYWIoIkNlbGNpdXMiKSsKICB5bGFiKCJGYXJlbnRoZWl0IikrCiAgdGhlbWVfbWluaW1hbCgpKwogIGNvb3JkX2ZpeGVkKCkKYGBgCgpUaGlzIGxpbmUgaGFzIHRoZSBmb2xsb3dpbmcgcHJvcGVydGllczoKCjEuIEl0cyAqKkludGVyY2VwdCoqLCBvciB3aGVyZSB0aGUgbGluZSBjcm9zc2VzIDAgb24gdGhlIHgtYXhpcywgaXMgMzIuCjIuIEl0cyAqKlNsb3BlKiosIGlzIDEuOCAodGhhdCBpcywgYSBjaGFuZ2Ugb2YgMSBvbiB0aGUgeC1heGlzIGNvcnJlc3BvbmRzIHRvIGEgY2hhbmdlIGluIDEuOCBvbiB0aGUgeS1heGlzKQoKCkFuZCwgaW4gZmFjdCwgKmFsbCogbGluZXMsIGluY2x1ZGluZyB0aGUgb25lcyB3ZSBmaXQgdXNpbmcgbGluZWFyIHJlZ3Jlc3Npb24sIGFyZSBkZXNjcmliZWQgaW4gdGVybXMgb2YgdGhlaXIgaW50ZXJjZXB0ICh3aGVyZSB0aGUgbGluZSBjcm9zc2VzIDAgb24gdGhlIHgtYXhpcykgYW5kIHNsb3BlLgoKCkJ1dCwgbGV0J3Mgc2F5IHlvdSBkaWRuJ3Qga25vdyB0aGUgZm9ybXVsYSB0byBjb252ZXJ0IGJhY2sgYW5kIGZvcnRoIGJldHdlZW4gQ2VsY2l1cyBhbmQgRmFyZW50aGVpdC4gTWF5YmUgeW91IHdlcmVuJ3QgZXZlbiBzdXJlIHRoYXQgdGhlcmUgd2FzIHN1Y2ggYSBmb3JtdWxhLiBBbmQgYWxsIHlvdSBoYWQgd2VyZSBhIGJ1bmNoIG9mIGtpbmQgb2YgY3JhcHB5IHRoZXJtb21ldGVycyB0aGF0IGdhdmUgeW91IGJvdGggQ2VsY2l1cyBhbmQgRmFyZW50aGVpdCByZWFkaW5ncy4gQW5kIG1heWJlIHRoZSB0aGVybW9tZXRlcnMgYXJlIGtpbmQgb2YgaGFyZCB0byByZWFkLCBvciB0aGUgbGlnaHRpbmcgY29uZGl0aW9ucyBhcmUgZGFyaywgb3IgeW91IG9ubHkgaGF2ZSBsaW1pdGVkIGV4cGVyaWVuY2UgaW4gcmVhZGluZyB0aGVybW9tZXRlcnMuIEluIHRoYXQgY2FzZSwgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIENlbGNpdXMgYW5kIEZhcmVudGhlaXQgbWlnaHQgbG9vayBhIGxvdCBtb3JlIGxpa2UgdGhpczoKCmBgYHtyLCBlY2hvID0gRn0KdHJ1ZV9jIDwtIGMoMCwgMTAsIDE2LCAyMCwgMjMsIDMwKQp0cnVlX2YgPC0gKHRydWVfYyoxLjgpICsgMzIKY19vYnNlcnZlIDwtIG1hcCh0cnVlX2MsIH5ybm9ybSgyMCwgbWVhbiA9IC54LCBzZCA9IDUpKSAlPiUgc2ltcGxpZnkoKQpmX29ic2VydmUgPC0gbWFwKHRydWVfZiwgfnJub3JtKDIwLCBtZWFuID0gLngsIHNkID0gNSoxLjgpKSAlPiUgc2ltcGxpZnkoKQoKdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGNfb2JzZXJ2ZSA9IGNfb2JzZXJ2ZSwKICAgICAgICAgICAgICAgICAgICAgIGZfb2JzZXJ2ZSA9IGZfb2JzZXJ2ZSkKCgp0ZW1wX2RmICU+JQogIGdncGxvdChhZXMoY19vYnNlcnZlLCBmX29ic2VydmUpKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlICA9IDIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgID0gMikrICAKICAgICNnZW9tX2FibGluZShpbnRlcmNlcHQgPSAzMiwgc2xvcGUgPSAxLjgsIGNvbG9yID0gImdyZXk0MCIpKwogICAgZ2VvbV9wb2ludCgpKwogICAgI3N0YXRfc21vb3RoKG1ldGhvZCA9IGxtKSsKICAgICN4bGltKC0xMCwgNDApKwogICAgeGxhYigiQ2VsY2l1cyIpKwogICAgI3lsaW0oMCwgMTAwKSsKICAgIHlsYWIoIkZhcmVudGhlaXQiKSsKICAgIGNvb3JkX2ZpeGVkKCkrCiAgICB0aGVtZV9taW5pbWFsKCkKCmBgYAoKCkluIHRoaXMgY2FzZSwgeW91IG1pZ2h0IHdhbnQgdG8gZml0IGEgKipsaW5lYXIgcmVncmVzc2lvbioqLiBBIGxpbmVhciByZWdyZXNzaW9uIGFzc3VtZXMgdGhhdCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdHdvIHZhcmlhYmxlcyBjYW4gYmUgY2FwdHVyZWQgdXNpbmcgKnNvbWUqIGxpbmUsIGFuZCBpdCB0cmllcyB0byBlc3RpbWF0ZSB0aGUgKkludGVyY2VwdCogYW5kICpTbG9wZSogb2YgdGhpcyBhc3N1bWVkIGxpbmUuCgpUaGUgd2F5IGl0IGRvZXMgdGhpcyBpcyBieSB0cnlpbmcgdG8gZmluZCBwYXJhbWV0ZXJzIGZvciBhIGxpbmUgdGhhdCBtaW5pbWl6ZSB0aGUgImVycm9yIiBvciB0aGUgInJlc2lkdWFscyIgYmV0d2VlbiB0aGUgb2JzZXJ2ZWQgZGF0YSwgYW5kIHRoZSBsaW5lLiBGb3IgZXhhbXBsZSwgaGVyZSBhcmUgZXhhbXBsZXMgb2YgKmJhZCogbGluZXMuIFRoZSBmaXJzdCBhc3N1bWVzIHRoYXQgYWxsIHRlbXBlcmF0dXJlcyBDZWxjaXVzIGFyZSBiYXNpY2FsbHkgNTAmIzE3NjtGLiBUaGUgb3RoZXIgYXNzdW1lcyB0aGF0IGFsbCB0ZW1wZXJhdHVyZXMgaW4gRmFyZW50aGVpdCBhcmUgYmFzaWNhbGx5IDMkXHRpbWVzJEMuCgo8ZGl2IHN0eWxlID0gImZsb2F0OmxlZnQ7d2lkdGggPSA0NSU7Ij4KYGBge3IgZWNobyA9IEZ9CmdncGxvdCh0ZW1wX2RmLCBhZXMoY19vYnNlcnZlLCBmX29ic2VydmUpKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlICA9IDIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgID0gMikrICAKICAgIGdlb21fc2VnbWVudChhZXMoeGVuZCA9IGNfb2JzZXJ2ZSwgeWVuZCA9IDUwKSkrCiAgICBnZW9tX3BvaW50KGNvbG9yID0gImdyZXk0MCIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gNTAsIGNvbG9yID0gJ3JlZCcpKwogICAgI3N0YXRfc21vb3RoKG1ldGhvZCA9ICdsbScsIGNvbG9yID0gJ3JlZCcsIHNlID0gRikrCiAgICB4bGFiKCJDZWxjaXVzIikrCiAgICB5bGFiKCJGYXJlbnRoZWl0IikrCiAgICB0aGVtZV9taW5pbWFsKCkrCiAgICBnZ3RpdGxlKCJGID0gNTAiKQoKYGBgCjwvZGl2Pgo8ZGl2IHN0eWxlID0gImZsb2F0OmxlZnQ7d2lkdGggPSA0NSU7Ij4KYGBge3IgZWNobyA9IEYsIHdpZHRoID0gM30KZ2dwbG90KHRlbXBfZGYsIGFlcyhjX29ic2VydmUsIGZfb2JzZXJ2ZSkpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgID0gMikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsgIAogICAgZ2VvbV9zZWdtZW50KGFlcyh4ZW5kID0gY19vYnNlcnZlLCB5ZW5kID0gY19vYnNlcnZlICogMykpKwogICAgZ2VvbV9wb2ludChjb2xvciA9ICJncmV5NDAiKSsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMywgY29sb3IgPSAicmVkIikrCiAgICAjc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xtJywgY29sb3IgPSAncmVkJywgc2UgPSBGKSsKICAgIHhsYWIoIkNlbGNpdXMiKSsKICAgIHlsYWIoIkZhcmVudGhlaXQiKSsKICAgIHRoZW1lX21pbmltYWwoKSsKICAgIGdndGl0bGUoIkYgPSAzKkMiKQoKYGBgCjwvZGl2PgoKSGVyZSBpcyBhIHBsb3Qgb2YgdGhlIGJlc3QtZml0dGluZyBsaW5lLCB0aGF0IGhhcyB0aGUgc21hbGxlc3QgYXZlcmFnZSByZXNpZHVhbHMuCmBgYHtyIGVjaG8gPSBGfQp0ZW1wX21vZCA8LSBsbShmX29ic2VydmV+Y19vYnNlcnZlLCBkYXRhID0gdGVtcF9kZikKdGVtcF9kZiRmaXR0ZWQgPC0gZml0dGVkKHRlbXBfbW9kKQoKZ2dwbG90KHRlbXBfZGYsIGFlcyhjX29ic2VydmUsIGZfb2JzZXJ2ZSkpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgID0gMikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsgIAogICAgZ2VvbV9zZWdtZW50KGFlcyh4ZW5kID0gY19vYnNlcnZlLCB5ZW5kID0gZml0dGVkKSkrCiAgICBnZW9tX3BvaW50KGNvbG9yID0gImdyZXk0MCIpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xtJywgY29sb3IgPSAncmVkJywgc2UgPSBGLCBmdWxscmFuZ2UgPSBUKSsKICAgIHhsYWIoIkNlbGNpdXMiKSsKICAgIHlsYWIoIkZhcmVudGhlaXQiKSsKICAgIHRoZW1lX21pbmltYWwoKQoKICAgIApgYGAKClRoZXJlIGFyZSBhY3R1YWxseSBtYW55IGRpZmZlcmVudCB3YXlzIHRvIGZpZ3VyZSBvdXQgd2hhdCB0aGUgYmVzdCBsaW5lIGlzIChyZW1lbWJlcmluZyB0aGF0IGJ5ICJsaW5lIiB3ZSByZWFsbHkgbWVhbiB0aGUgcGFpcmluZyBvZiBJbnRlcmNlcHQgYW5kIFNsb3BlKS4gCkZvciBleGFtcGxlLCBvbmUgcmVhbGx5IHNpbXBsaXN0aWMgYXBwcm9hY2heW0FjdHVhbGx5LCB0aGlzICJzaW1wbGlzdGljIGFwcHJvYWNoIiBpcyBtb3JlIGxpa2UgdGhlIHNvcGhpc3RpY2F0ZWQgYXBwcm9hY2ggdGhlc2UgZGF5cywgYmVjYXVzZSB0aGVyZSBhcmUgY29tcGxpY2F0ZWQgbWF0aHMgYmVoaW5kIG1ha2luZyBnb29kIGd1ZXNzZXMgd2hpY2ggYXJlIGdpdmVuIHNlbWFudGljYWxseSBvcGFxdWUgbmFtZXMgbGlrZSAiU2ltdWxhdGVkIEFubmVhbGluZyIgYW5kICJIYW1pbHRvbmlhbiBNb250ZSBDYXJsbyIuXSB3b3VsZCBiZSBqdXN0IHRvIGRyYXcgYSBidW5jaCBvZiBkaWZmZXJlbnQgbGluZXMsIGFuZCBzZWUgd2hpY2ggb25lIHdvcmtlZCBiZXN0LgoKCgpgYGB7ciBlY2hvID0gRn0KdGVtcF9jb2VmIDwtIGNvZWYodGVtcF9tb2QpCnRlbXBfU2lnbWEgPC0gdmNvdih0ZW1wX21vZCkKCm1vZF9kZiA8LSBkYXRhLmZyYW1lKGNfb2JzZXJ2ZSA9IC0xNDo0MSkKbW9kX21hdHJpeCA8LSBtb2RlbC5tYXRyaXgofmNfb2JzZXJ2ZSwgZGF0YSA9IG1vZF9kZikKCgpCZXRhIDwtIE1BU1M6Om12cm5vcm0oNiwgdGVtcF9jb2VmLCB0ZW1wX1NpZ21hICogNTApCmFzX3RpYmJsZSh0KEJldGEgJSolIHQobW9kX21hdHJpeCkpKSAlPiUKICBiaW5kX2NvbHMobW9kX2RmLCAuKSU+JQogIGdhdGhlcihrZXksIHZhbHVlLCAtY19vYnNlcnZlKSU+JQogIGdncGxvdChhZXMoY19vYnNlcnZlLCB2YWx1ZSkpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgID0gMikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsgIAogICAgZ2VvbV9wb2ludChkYXRhID0gdGVtcF9kZiwgCiAgICAgICAgICAgICAgIGFlcyh5ID0gZl9vYnNlcnZlKSwgCiAgICAgICAgICAgICAgIGdyb3VwID0gTkEsCiAgICAgICAgICAgICAgIGNvbG9yID0gImdyZXk4MCIpKwogICAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGtleSksIGNvbG9yID0gImdyZXk0MCIpKwogICAgc3RhdF9zbW9vdGgoZGF0YSA9IHRlbXBfZGYsIAogICAgICAgICAgICAgICAgYWVzKGNfb2JzZXJ2ZSwgZl9vYnNlcnZlKSwgCiAgICAgICAgICAgICAgICBjb2xvciA9ICdyZWQnLAogICAgICAgICAgICAgICAgbWV0aG9kID0gbG0sIAogICAgICAgICAgICAgICAgc2UgPSBGLAogICAgICAgICAgICAgICAgZnVsbHJhbmdlID0gVCkrCiAgICB4bGFiKCJDZWxjaXVzIikrCiAgICB5bGFiKCJGYXJlbnRoZWl0IikrICAKICAgIHRoZW1lX21pbmltYWwoKQoKYGBgCgpIb3dldmVyLCB0aGVyZSBoYXZlIGJlZW4gc29tZSBsb25nIGVzdGFibGlzaGVkIG1ldGhvZHMgZm9yICpzb2x2aW5nKiB0aGlzIHByb2JsZW0sIGF0IGlzLCBmb3IgZmluZGluZyB0aGUgb25lIGFuZCB0cnVseSBiZXN0IEludGVyY2VwdCBhbmQgU2xvcGUgZm9yIGEgZ2l2ZW4gc2V0IG9mIGRhdGEgcG9pbnRzLgoKPGRpdiBjbGFzcyA9ICJib3ggaWRpb20iPgo8c3BhbiBjbGFzcyA9ICdsYWJlbCc+SWRpb208L3NwYW4+CgpUaGlzIGlzbid0IFIgaWRpb20sIGJ1dCBzdGF0cyBpZGlvbS4gSGVyZSBhcmUgc29tZSB0cmFuc2xhdGlvbnMgZm9yIGhvdyBwZW9wbGUgZGVzY3JpYmUgc29sdmluZyB0aGlzIHByb2JsZW0uCgotICphbmFseXRpYyosICpjbG9zZWQgZm9ybSogPSAiV2Ugc29sdmVkIGl0IHdpdGggY29tcGxpY2F0ZWQgbWF0aC4iCi0gKml0ZXJhdGl2ZSosICpzdG9jaGFzdGljKiA9ICJXZSBtYWRlIGEgYnVuY2ggb2YgZ3Vlc3Nlcy4iCgo8L2Rpdj4KCkZvciB0aGUgc2FrZSBvZiBmaW5pc2hpbmcgdGhlIGlsbHVzdHJhdGlvbiwgaGVyZSBpcyB0aGUgc29sdXRpb24gdGhhdCBhIGxpbmVhciByZWdyZXNzaW9uIGZvdW5kIGZvciB0aGlzIHNhbXBsZSBkYXRhOgoKYGBge3IgZWNobyA9IEZ9CnRlbXBfbW9kCmBgYAoKVGhlIG1vZGVsIGhhcyBlc3RpbWF0ZWQgdGhhdCB0aGUgSW50ZXJjZXB0IGlzICRcYXBwcm94JCBgciByb3VuZChjb2VmKHRlbXBfbW9kKVsxXSlgICBhbmQgdGhlIHNsb3BlIGlzICRcYXBwcm94JCBgciByb3VuZChjb2VmKHRlbXBfbW9kKVsyXSwgZGlnaXRzID0gMSlgIC4gVGhhdCBpcyB0byBzYXksIGJhc2VkIG9uIG91ciAic2FtcGxlIiwgaXQgdGhpbmtzIDAmIzE3NjtDID0gYHIgcm91bmQoY29lZih0ZW1wX21vZClbMV0pYCYjMTc2O0YsIGFuZCB0aGF0IGV2ZXJ5IDEmIzE3NjtDIGluY3JlYXNlIGNvcnJlc3BvbmRzIHRvIGEgYHIgcm91bmQoY29lZih0ZW1wX21vZClbMl0sIGRpZ2l0cyA9IDEpYCYjMTc2O0YgaW5jcmVhc2UuCgpXZSBhcmUgbHVja3kgdG8ga25vdyB0aGF0IHRoaXMgaXMsIHN0cmljdGx5IHNwZWFraW5nLCB3cm9uZywgYnV0IHdlIHdvbid0IHVzdWFsbHksIG9yIHR5cGljYWxseSwgYmUgYWJsZSB0byBpbiBzdWNoIGEgc2l0dWF0aW9uLiBIb3dldmVyLCB0aGUgZXN0aW1hdGUgb2YgYm90aCB0aGUgaW50ZXJjZXB0IGFuZCBzbG9wZSBoYXZlIHRoZSByaWdodCAqc2lnbiogKHRoYXQgaXMsIGl0IGhhc24ndCBndWVzc2VkIHRoZSBpbnRlcmNlcHQgaXMgLTEwLCBvciB0aGUgc2xvcGUgZ29lcyB0aGUgb3RoZXIgd2F5KSwgYW5kIHRoZXkncmUganVzdCBhYm91dCB0aGUgcmlnaHQgKm1hZ25pdHVkZSogKHRoYXQgaXMsIGl0IGhhc24ndCBndWVzc2VkIHRoYXQgdGhlIHNsb3BlIGlzIHNvbWV0aGluZyBsaWtlIDEwLCBvciAxMDApLgoKTm93LCBsZXQncyBjb25zaWRlciBob3cgdGhlIGxpbmVhciBtb2RlbCBpcyBkZXNjcmliaW5nIHRoZSB2YWx1ZSBvZiB0aGlzIGhpZ2hsaWdodGVkIGRvdC4KYGBge3IgZWNobyA9IEZ9Cm9uZV9kb3QgPC0gdGVtcF9kZiAlPiUgCiAgICAgICAgICAgICAgICBzYW1wbGVfbigxKQoKCmdncGxvdCh0ZW1wX2RmLCBhZXMoY19vYnNlcnZlLCBmX29ic2VydmUpKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlICA9IDIpKyAgCiAgICBnZW9tX3BvaW50KGNvbG9yID0gImdyZXk0MCIpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xtJywgc2UgPSBGLCBjb2xvciA9ICdibGFjaycsIHNpemUgPSAwLjUpKwogICAgZ2VvbV9wb2ludChkYXRhID0gb25lX2RvdCwgY29sb3IgPSAncmVkJywgc2l6ZSA9IDMpKwogICAgeGxhYigiQ2VsY2l1cyIpKwogICAgeWxhYigiRmFyZW50aGVpdCIpKyAgCiAgICB0aGVtZV9taW5pbWFsKCkKYGBgCgpGaXJzdCwgeW91IHRha2UgaXQncyB2YWx1ZSBpbiBDZWxjaXVzLCBhbmQgPHNwYW4gc3R5bGUgPSAiY29sb3I6IzIxNkQ2NTtmb250LXdlaWdodDpib2xkOyI+bXVsdGlwbHkgaXQgYnkgMS4zPC9zcGFuPiAod2hpY2ggaXMgYHIgcm91bmQob25lX2RvdCRjX29ic2VydmVbMV0gKiBjb2VmKHRlbXBfbW9kKVsyXSwgZGlnaXRzID0gMilgKQoKYGBge3IgZWNobyA9IEZ9Cm9uZV9kb3QkbXVsdCA8LSBvbmVfZG90JGNfb2JzZXJ2ZSAqIGNvZWYodGVtcF9tb2QpWzJdCmdncGxvdCh0ZW1wX2RmLCBhZXMoY19vYnNlcnZlLCBmX29ic2VydmUpKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlICA9IDIpKyAgCiAgICBnZW9tX3BvaW50KGNvbG9yID0gImdyZXk0MCIpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xtJywgc2UgPSBGLCBjb2xvciA9ICdibGFjaycsIHNpemUgPSAwLjUpKwogICAgZ2VvbV9wb2ludChkYXRhID0gb25lX2RvdCwgY29sb3IgPSAncmVkJywgc2l6ZSA9IDMpKwogICAgZ2VvbV9zZWdtZW50KGRhdGEgPSBvbmVfZG90LCAKICAgICAgICAgICAgICAgICBhZXMoeGVuZCA9IGNfb2JzZXJ2ZS0wLjUsCiAgICAgICAgICAgICAgICAgICAgIHggPSBjX29ic2VydmUtMC41LAogICAgICAgICAgICAgICAgICAgICB5ID0gMCwKICAgICAgICAgICAgICAgICAgICAgeWVuZCA9IG11bHQpLAogICAgICAgICAgICAgICAgIGNvbG9yID0gIiMyMTZENjUiLAogICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3coKSkrCiAgICB4bGFiKCJDZWxjaXVzIikrCiAgICB5bGFiKCJGYXJlbnRoZWl0IikrICAKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKCgpUaGVuLDxzcGFuIHN0eWxlID0gImNvbG9yOiNCMDg1MzQ7Zm9udC13ZWlnaHQ6Ym9sZDsiPnlvdSBhZGQgNDAgdG8gaXQ8L3NwYW4+ICh3aGljaCBpcyBgciByb3VuZCgob25lX2RvdCRjX29ic2VydmVbMV0gKiBjb2VmKHRlbXBfbW9kKVsyXSkgKyBjb2VmKHRlbXBfbW9kKVsxXSwgZGlnaXRzID0gMilgKQoKYGBge3IgZWNobyA9IEZ9Cm9uZV9kb3QkYWRkIDwtIG9uZV9kb3QkbXVsdCArIGNvZWYodGVtcF9tb2QpWzFdCgpnZ3Bsb3QodGVtcF9kZiwgYWVzKGNfb2JzZXJ2ZSwgZl9vYnNlcnZlKSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgID0gMikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsgIAogICAgZ2VvbV9wb2ludChjb2xvciA9ICJncmV5NDAiKSsKICAgIHN0YXRfc21vb3RoKG1ldGhvZCA9ICdsbScsIHNlID0gRiwgY29sb3IgPSAnYmxhY2snLCBzaXplID0gMC41KSsKICAgIGdlb21fcG9pbnQoZGF0YSA9IG9uZV9kb3QsIGNvbG9yID0gJ3JlZCcsIHNpemUgPSAzKSsKICAgIGdlb21fc2VnbWVudChkYXRhID0gb25lX2RvdCwgCiAgICAgICAgICAgICAgICAgYWVzKHhlbmQgPSBjX29ic2VydmUtMC41LAogICAgICAgICAgICAgICAgICAgICB4ID0gY19vYnNlcnZlLTAuNSwKICAgICAgICAgICAgICAgICAgICAgeSA9IDAsCiAgICAgICAgICAgICAgICAgICAgIHllbmQgPSBtdWx0KSwKICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMjE2RDY1IiwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KCkpKwogICAgIGdlb21fc2VnbWVudChkYXRhID0gb25lX2RvdCwgCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gY19vYnNlcnZlLTAuNSwKICAgICAgICAgICAgICAgICAgICAgIHhlbmQgPSBjX29ic2VydmUgKyAwLjUsCiAgICAgICAgICAgICAgICAgICAgICB5ID0gbXVsdCwKICAgICAgICAgICAgICAgICAgICAgIHllbmQgPSBtdWx0KSwKICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleTIwIikrCiAgICAgZ2VvbV9zZWdtZW50KGRhdGEgPSBvbmVfZG90LCAKICAgICAgICAgICAgICAgICBhZXMoeGVuZCA9IGNfb2JzZXJ2ZSArIDAuNSwKICAgICAgICAgICAgICAgICAgICAgeCA9IGNfb2JzZXJ2ZSswLjUsCiAgICAgICAgICAgICAgICAgICAgIHkgPSBtdWx0LAogICAgICAgICAgICAgICAgICAgICB5ZW5kID0gYWRkKSwKICAgICAgICAgICAgICAgICBjb2xvciA9ICIjQjA4NTM0IiwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KCkpKwogICAgeGxhYigiQ2VsY2l1cyIpKwogICAgeWxhYigiRmFyZW50aGVpdCIpKyAgCiAgICB0aGVtZV9taW5pbWFsKCkKYGBgCgpUaGVuLCB5b3UgPHNwYW4gc3R5bGUgPSAiY29sb3I6I0FDMzMzQztmb250LXdlaWdodDpib2xkOyI+YWRkIHRoZSByZXNpZHVhbCBlcnJvcjwvc3Bhbj4gdG8gZ2l2ZSB1cyB0aGUgb2JzZXJ2ZWQgZGF0YSBwb2ludC4KCmBgYHtyIGVjaG8gPSBGfQpnZ3Bsb3QodGVtcF9kZiwgYWVzKGNfb2JzZXJ2ZSwgZl9vYnNlcnZlKSkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgID0gMikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSAgPSAyKSsgIAogICAgZ2VvbV9wb2ludChjb2xvciA9ICJncmV5NDAiKSsKICAgIHN0YXRfc21vb3RoKG1ldGhvZCA9ICdsbScsIHNlID0gRiwgY29sb3IgPSAnYmxhY2snLCBzaXplID0gMC41KSsKICAgIGdlb21fcG9pbnQoZGF0YSA9IG9uZV9kb3QsIGNvbG9yID0gJ3JlZCcsIHNpemUgPSAzKSsKICAgIGdlb21fc2VnbWVudChkYXRhID0gb25lX2RvdCwgCiAgICAgICAgICAgICAgICAgYWVzKHhlbmQgPSBjX29ic2VydmUtMC41LAogICAgICAgICAgICAgICAgICAgICB4ID0gY19vYnNlcnZlLTAuNSwKICAgICAgICAgICAgICAgICAgICAgeSA9IDAsCiAgICAgICAgICAgICAgICAgICAgIHllbmQgPSBtdWx0KSwKICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMjE2RDY1IiwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KCkpKwogICAgIGdlb21fc2VnbWVudChkYXRhID0gb25lX2RvdCwgCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gY19vYnNlcnZlLTAuNSwKICAgICAgICAgICAgICAgICAgICAgIHhlbmQgPSBjX29ic2VydmUgKyAwLjUsCiAgICAgICAgICAgICAgICAgICAgICB5ID0gbXVsdCwKICAgICAgICAgICAgICAgICAgICAgIHllbmQgPSBtdWx0KSwKICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleTIwIikrCiAgICAgZ2VvbV9zZWdtZW50KGRhdGEgPSBvbmVfZG90LCAKICAgICAgICAgICAgICAgICBhZXMoeGVuZCA9IGNfb2JzZXJ2ZSArIDAuNSwKICAgICAgICAgICAgICAgICAgICAgeCA9IGNfb2JzZXJ2ZSswLjUsCiAgICAgICAgICAgICAgICAgICAgIHkgPSBtdWx0LAogICAgICAgICAgICAgICAgICAgICB5ZW5kID0gYWRkKSwKICAgICAgICAgICAgICAgICBjb2xvciA9ICIjQjA4NTM0IiwKICAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KCkpKwogICAgIGdlb21fc2VnbWVudChkYXRhID0gb25lX2RvdCwgCiAgICAgICAgICAgICAgICAgIGFlcyh4ID0gY19vYnNlcnZlLAogICAgICAgICAgICAgICAgICAgICAgeGVuZCA9IGNfb2JzZXJ2ZSArIDAuNSwKICAgICAgICAgICAgICAgICAgICAgIHkgPSBhZGQsCiAgICAgICAgICAgICAgICAgICAgICB5ZW5kID0gYWRkKSwKICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleTIwIikrIAogIGdlb21fc2VnbWVudChkYXRhID0gb25lX2RvdCwgCiAgICAgICAgICAgICAgICAgYWVzKHhlbmQgPSBjX29ic2VydmUsCiAgICAgICAgICAgICAgICAgICAgIHggPSBjX29ic2VydmUsCiAgICAgICAgICAgICAgICAgICAgIHkgPSBhZGQsCiAgICAgICAgICAgICAgICAgICAgIHllbmQgPSBmX29ic2VydmUpLAogICAgICAgICAgICAgICAgIGNvbG9yID0gIiNBQzMzM0MiLAogICAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3coKSkrICAKICAgIHhsYWIoIkNlbGNpdXMiKSsKICAgIHlsYWIoIkZhcmVudGhlaXQiKSsgIAogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKVGhlIGdlbmVyaWMgZm9ybXVsYSBmb3IgZmluZGluZyB0aGUgdmFsdWUgZm9yICphbnkqIGRhdGEgcG9pbnQgaXMKCiQkCkZfaSA9IGByIHJvdW5kKGNvZWYodGVtcF9tb2QpWzFdLCBkaWdpdHMgPSAxKWAgKyAoYHIgcm91bmQoY29lZih0ZW1wX21vZClbMl0sIGRpZ2l0cyA9IDEpYFx0aW1lcyBDX2kpICsgXGVwc2lsb25faS4KJCQKSW4gdGhpcyBmb3JtdWxhIHRoZSAkaSQgaXMgY29udmVudGlvbiBmb3IgcmVmZXJyaW5nIHRvIHNvbWUgZ2VuZXJpYywgJGlee3RofSQgZGF0YSBwb2ludCBhbmQgJFxlcHNpbG9uJCBpcyBjb252ZW50aW9uYWwgZm9yIHJlZmVycmluZyB0byB0aGUgcmVzaWR1YWwgZXJyb3JzLgoKU29tZSBhZGRpdGlvbmFsIGNvbnZlbnRpb25zOgoKLSBSZWZlcnJpbmcgdG8gdGhlIG91dGNvbWUgdmFyaWFibGUgYXMgJHkkLgotIFJlZmVycmluZyB0byB0aGUgcHJlZGljdG9ycyBhcyAkeCQuCi0gUmVmZXJyaW5nIHRvIHRoZSByZW1haW5pbmcgcGFyYW1ldGVycyBhcyAkXGJldGEkLgoKU28geW91IG1heSBzb21ldGltZXMgc2VlIHBlb3BsZSByZWZlcnJpbmcgdG8gJFxiZXRhXzAkLCBvciB0aGUgImJldGFzIiBpbiBhIG1vZGVsLiBUaGUgZnVsbHkgZ2VuZXJpYyBmb3JtdWxhIGZvciBsaW5lYXIgcmVncmVzc2lvbiBpcyBzb21ldGltZXMgZ2l2ZW4gYXMKCiQkCnkgPSBcYmV0YV8wICsgXGJldGEgeCArIFxlcHNpbG9uCiQkCgoKPGRpdiBjbGFzcyA9ICJib3ggaWRpb20iPgo8c3BhbiBjbGFzcyA9ICdsYWJlbCc+SWRpb208L3NwYW4+CgotIFdlIGNhbGwgdGhlICpJbnRlcmNlcHQqIGFuZCAqU2xvcGVzKiB0aGUgKipwYXJhbWV0ZXJzKiogb3IgKipjb2VmZmljaWVudHMqKiBvZiB0aGUgbW9kZWwuCi0gRm9yIGV2ZXJ5IGRhdGEgcG9pbnQsIHRoZSB2YWx1ZSB5b3UgZ2V0IGJ5IG9ubHkgdXNpbmcgdGhlIHNsb3BlcyBhbmQgaW50ZXJjZXB0cyBhcmUgY2FsbGVkIHRoZSAqKmZpdHRlZCB2YWx1ZXMqKiwgYW5kIHRoZXkgYWxsIGxpZSBhbG9uZyB0aGUgbGluZXMgeW91IGRyYXcuCi0gQWxtb3N0IGV2ZXJ5IGRhdGEgcG9pbnQncyBhY3R1YWwgdmFsdWUgaXMgZGlmZmVyZW50IGZyb20gaXQncyBmaXR0ZWQgdmFsdWUsIGFuZCB0aGVzZSBkaWZmZXJlbmNlcyBhcmUgY2FsbGVkIHRoZSAqKnJlc2lkdWFscyoqLgoKPC9kaXY+CgojIyBUaGlua2luZyBhYm91dCBhIHJlYWxlciBjYXNlCgpIZXJlIGlzIHNvbWUgYWN0dWFsIGRhdGEgeW91IG1pZ2h0IHdvcmsgd2l0aC4gQmVsb3cgaXMgYSBncmFwaCBvZiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdm93ZWwgZHVyYXRpb24gYW5kIG5vcm1hbGl6ZWQgRjEgZm9yIHRoZSBMT1Qgdm93ZWwgKGkuZS4gYCJhaCJgIGluIHRoZSBgaXlfYWhgIGRhdGEgZnJhbWUpLiBFYWNoIHBvaW50IGlzIG9uZSB2b3dlbCB0b2tlbi4gSSBwcmVkaWN0IHRoYXQgYXMgdGhlIGR1cmF0aW9uIGdldHMgbG9uZ2VyLCB0aGUgdm93ZWxzIHNob3VsZCBhbHNvIGdldCBsb3dlciAoaS5lLiBoYXZlIGEgaGlnaGVyIEYxKSBmb3IgYSBidW5jaCBvZiBkaWZmZXJlbnQgcmVhc29ucy4gCgpgYGB7ciBlY2hvID0gRn0KYWggJT4lCiAgZ2dwbG90KGFlcyhkdXIsIEYxX24pKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9IDIpKyAgICAgIAogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMDYpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKPGRpdiBjbGFzcyA9ICJicmVhayBib3giPgo8c3BhbiBjbGFzcyA9ICJiaWctbGFiZWwiPn41IE1pbnV0ZSBEaXNjdXNzaW9uPC9zcGFuPgoKVGhpcyByZWFsIGRhdGEgb24gZHVyYXRpb24gYW5kIEYxIGlzIGRpZmZlcmVudCBmcm9tIHRoZSBleGFtcGxlIENlbGNpdXMgYW5kIEZhcmVudGhlaXQgaW4gYSBidW5jaCBvZiBkaWZmZXJlbnQgKGFuZCBpbXBvcnRhbnQgd2F5cykuIEluIHNtYWxsIGdyb3VwcywgZGlzY3VzcyB3aGF0IHRoZXkgbWlnaHQgYmUuCgo8L2Rpdj4KCiMgRml0dGluZyBhIGxpbmVhciBtb2RlbAoKSW4gUiwgdGhlIHN5bnRheCBmb3IgZml0dGluZyBhIHNpbXBsZSBsaW5lYXIgbW9kZWwgaXMgdmVyeSBzdHJhaWdodCBmb3J3YXJkLiBUaGUgZnVuY3Rpb24gaXMgY2FsbGVkIGBsbSgpYCwgZm9yIGxpbmVhciBtb2RlbC4KCjxkaXYgY2xhc3MgPSAiaWxsdXN0cmF0ZSI+CmxtKDxzcGFuIGNsYXNzID0gInBvcCI+b3V0Y29tZSB+IHByZWRpY3Rvcjwvc3Bhbj4sIDxzcGFuIGNsYXNzID0gInBvcCI+ZGF0YTwvc3Bhbj4pCjwvZGl2PgoKLSBgb3V0Y29tZWAKICAgIC0gVGhpcyBpcyB0aGUgdmFyaWFibGUgd2hvc2UgdmFsdWUgdGhhdCB5b3UncmUgdHJ5aW5nIHRvIHByZWRpY3QsIGUuZy4gdm93ZWwgRjEuCi0gYHByZWRpY3RvcmAKICAgIC0gVGhpcyBpcyB0aGUgdmFyaWFibGUgeW91J3JlIHVzdWluZyB0aGUgcHJlZGljdCB0aGUgb3V0Y29tZSB2YWx1ZQotIGBkYXRhYAogICAgLSB0aGUgZGF0YSBmcmFtZSB0aGF0IGNvbnRhaW5zIHRoZSBkYXRhIHdlJ3JlIG1vZGVsbGluZyB3aXRoLgogICAgCldlIGNhbiBmaXQgYSBsaW5lYXIgcmVncmVzc2lvbiBmb3IgdGhlIGBhaGAgZGF0YSBzZXQgbGlrZSBzbzoKCmBgYHtyfQphaF9tb2RlbCA8LSBsbShGMV9uIH4gZHVyLCBkYXRhID0gYWgpCmBgYAoKPGRpdiBjbGFzcyA9ICJib3ggYnJlYWsiPgo8c3BhbiBjbGFzcyA9ICJiaWctbGFiZWwiPn4yIG1pbnV0ZSBhY3Rpdml0eTwvc3Bhbj4KCkZpdCB0aGUgYGFoX21vZGVsYCB1c2luZyB0aGUgY29kZSBhYm92ZS4gVGhlbiBsb29rIGF0IHRoZSBzdW1tYXJ5IGxpa2Ugc286CgpgYGB7cn0Kc3VtbWFyeShhaF9tb2RlbCkKYGBgCgpMb29rIG92ZXIgdGhlc2UgbnVtYmVycywgYW5kICh3aXRob3V0IGxvb2tpbmcgZG93biB0b28gbXVjaCBmdXJ0aGVyISksIGRpc2N1c3MgaW4gc21hbGwgZ3JvdXBzIHdoYXQgeW91IHVuZGVyc3RhbmQgaGVyZSwgYW5kIGhvdyB0byBpbnRlcnByZXQgdGhlIG91dGNvbWUuCgo8L2Rpdj4KCgojIyBWaXN1YWxpemluZyB0aGlzIG1vZGVsLgoKQmVmb3JlIHdlIGV2ZW4gZ2V0IHRvIHRob3NlICJwLXZhbHVlcyIgYW5kIHdoYXQgdGhleSBldmVuIG1lYW4sIGxldCdzIHRhbGsgYWJvdXQgdGhlIGNvZWZmaWNpZW50cy4gCgotIGAoSW50ZXJjZXB0KSAgMC42MDQzMWAKICAgIC0gVGhpcyBpcyB0aGUgaW50ZXJjZXB0IG9mIHRoZSBsaW5lLCBtZWFuaW5nIHdoZW4gYGR1ciA9IDBgLCBGMV9uIGlzIHByZWRpY3RlZCB0byBiZSBhYm91dCAwLjYuCi0gYGR1ciAgICAgICAgICAzLjUwMDcxYAogICAgLSBUaGlzIGlzIHRoZSBzbG9wZSwgbWVhbmluZyB3aGVuIGBkdXJgIGluY3JlYXNlcyBieSAxIHNlY29uZCwgd2UgcHJlZGljdCBgRjFfbmAgdG8gaW5jcmVhc2UgYnkgYWJvdXQgMy41CgpIZXJlJ3MgaG93IHRoYXQgbG9va3MgdmlzdWFsaXplZCBvbiBvdXIgZGF0YSBzZXQuCgpgYGB7ciBlY2hvPUZ9CmFoX3NhbXBfZGYgPC0gZGF0YV9mcmFtZShkdXIgPSBjKDAsMSksCiAgICAgICAgICAgICAgICAgICAgICAgICBGMV9uID0gKGR1ciAqIGNvZWYoYWhfbW9kZWwpWzJdKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWYoYWhfbW9kZWwpWzFdKQoKYWggJT4lCiAgZ2dwbG90KGFlcyhkdXIsIEYxX24pKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9IDIpKyAgCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC4wNikrCiAgICBhbm5vdGF0ZShnZW9tID0gInNlZ21lbnQiLCAKICAgICAgICAgICAgIHggPSAwLCAKICAgICAgICAgICAgIHhlbmQgPSAwLCAKICAgICAgICAgICAgIHkgPSAwLCAKICAgICAgICAgICAgIHllbmQgPSBjb2VmKGFoX21vZGVsKVsxXSwKICAgICAgICAgICAgIGFycm93ID0gYXJyb3coKSwKICAgICAgICAgICAgIGNvbG9yID0gJ3JlZCcpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kID0gJ2xtJywKICAgICAgICAgICAgICAgIHNlID0gRiwKICAgICAgICAgICAgICAgZnVsbHJhbmdlID0gVCwKICAgICAgICAgICAgICAgc2l6ZSA9IDAuNSwKICAgICAgICAgICAgICAgY29sb3IgPSAncmVkJywKICAgICAgICAgICAgICAgbGluZXR5cGUgPSAyKSsKICAgIGdlb21fcG9pbnQoZGF0YSA9IGFoX3NhbXBfZGYsCiAgICAgICAgICAgICAgIGNvbG9yID0gJ3JlZCcsCiAgICAgICAgICAgICAgIHNpemUgPSAyKSsKICAgIGdlb21fc3RlcChkYXRhID0gYWhfc2FtcF9kZiwKICAgICAgICAgICAgICAgY29sb3IgPSAncmVkJykrICAKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKCgoKIyMgVGhpbmtpbmcgYWJvdXQgdGhlIG1vZGVsCgpTb21lIHRoaW5ncyBub3Qgc28gZ3JlYXQgYWJvdXQgdGhlc2UgY29lZmZpY2llbnRzOgoKMS4gVGhleSdyZSBvdmVybHkgcHJlY2lzZS4KICAgIC0gQXQgdGhlICpiZXN0KiBvZiB0aW1lcywgbGluZ3Vpc3RpY3MgaXMgYSBvbmUgb3IgdHdvIGRlY2ltYWwgcGxhY2UgZmllbGQuIAoyLiBUaGUgSW50ZXJjZXB0IG1ha2VzIG5vIHNlbnNlLgogICAgLSBOb3Qgb25seSBhcmUgdGhlcmUgbm8gdm93ZWxzIHdpdGggMCBkdXJhdGlvbiBpbiB0aGlzIGRhdGEgc2V0LCB0aGVyZSBjYW4ndCBiZSBhIHZvd2VsIHdpdGggMCBkdXJhdGlvbi4KMy4gVGhlIHNsb3BlIG1ha2VzIHZlcnkgbGl0dGxlIHNlbnNlLgogICAgLSBJdCdzICpwb3NzaWJsZSogZm9yIGEgdm93ZWwgdG8gYmUgMSBzZWNvbmQgbG9uZywgYnV0IGl0J3Mgbm90IGxpa2VseS4gVGhlIGxvbmdlc3Qgdm93ZWxzIGluIHRoaXMgZGF0YSBzZXQgKDAuOHMpIGFyZSBwcm9iYWJseSBmb3JjZWQgYWxpZ25tZW50IGVycm9ycy4gVGhlIHZhc3QgbWFqb3JpdHkgb2Ygdm93ZWxzIGluIHRoaXMgZGF0YSBhcmUgPDAuMjVzLgogICAgClRoZSBnb29kIG5ld3MgaXMgdGhhdCB0aGVzZSBwcm9ibGVtcyBhcmUgZml4YWJsZSBieSAicmVzY2FsaW5nIiBvciAic3RhbmRhcmRpemluZyIgb3VyIHByZWRpY3Rvci4KCiMjIyBGaXhpbmcgdGhlIGludGVyY2VwdC4KClRoZSBzaW1wbGVzdCB0aGluZyB0byBkbyB0byBmaXggdGhlIGludGVyY2VwdCB3b3VsZCBiZSB0byB0cnkgdG8gZmlndXJlIG91dCB3aGVyZSB0aGUgbGluZSBjcm9zc2VzIHRoZSB4LWF4aXMgYXQgc29tZSBvdGhlciB2YWx1ZSwgaW5zdGVhZCBvZiAwLiBXaHkgbm90IHRyeSB0byBlc3RpbWF0ZSB3aGVyZSBpdCBjcm9zc2VzIHggYXQgdGhlIG1lZGlhbiBkdXJhdGlvbiAoYHIgbWVkaWFuKGFoJGR1cilgKSBpbnN0ZWFkPwoKYGBge3IgZWNobyA9IEZ9CmFoICU+JQogIGdncGxvdChhZXMoZHVyLCBGMV9uKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9IDIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsgICAgICAKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjA2KSsKICAgIGFubm90YXRlKGdlb20gPSAic2VnbWVudCIsCiAgICAgICAgICAgICAgICAgeCA9IG1lZGlhbihhaCRkdXIpLAogICAgICAgICAgICAgICAgIHhlbmQgPSBtZWRpYW4oYWgkZHVyKSwKICAgICAgICAgICAgICAgICB5ID0gMCwKICAgICAgICAgICAgICAgICB5ZW5kID0gKG1lZGlhbihhaCRkdXIpICogY29lZihhaF9tb2RlbClbMl0pKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29lZihhaF9tb2RlbClbMV0sCiAgICAgICAgICAgICBjb2xvciA9ICdyZWQnLAogICAgICAgICAgICAgYXJyb3cgPSBhcnJvdygpKSsKICAgIHN0YXRfc21vb3RoKG1ldGhvZCA9ICdsbScsCiAgICAgICAgICAgICAgICBzZSA9IEYsCiAgICAgICAgICAgICAgIGZ1bGxyYW5nZSA9IFQsCiAgICAgICAgICAgICAgIHNpemUgPSAwLjUsCiAgICAgICAgICAgICAgIGNvbG9yID0gJ3JlZCcsCiAgICAgICAgICAgICAgIGxpbmV0eXBlID0gMikrIAogICAgeGxpbSgwLDEpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKVGhlIGJhZCBuZXdzIHRoYXQgd2UgY2FuJ3QgZWFzaWxseSAqbWFrZSogYSBsaW5lYXIgbW9kZWwgdHJ5IHRvIGVzdGltYXRlIHRoaXMgdmFsdWUuIEFsbCB0aGUgbWF0aCBzdXJyb3VuZGluZyBmaXR0aW5nIGxpbmVhciBtb2RlbHMgaXMgYmFzZWQgb24gdHJ5aW5nIHRvIGVzdGltYXRlIHdoZXJlIHRoZSBsaW5lIGNyb3NzZXMgdGhlIHgtYXhpcyBhdCAwLgoKVGhlIGdvb2QgbmV3cyBpcyB0aGF0IHdlIGNhbiAqdHJpY2sqIHRoZSBtb2RlbCBpbnRvIGVzdGltYXRpbmcgdGhpcyBudW1iZXIsIGJ5IGp1c3Qgc3VidHJhY3Rpbmcgb3V0IHRoZSBtZWRpYW4gZHVyYXRpb24gZnJvbSBkdXJhdGlvbiEKCmBgYHtyfQphaCA8LSBhaCAlPiUKICAgICAgICBtdXRhdGUoZHVyX2NlbnRlciA9IGR1ciAtIG1lZGlhbihkdXIpKQpgYGAKCmBgYHtyIGVjaG8gPSBGfQphaCAlPiUKICBnZ3Bsb3QoYWVzKGR1cl9jZW50ZXIsIEYxX24pKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9IDIpKyAgICAKICAgIGdlb21fcG9pbnQoYWxwaGEgPSAwLjA2KSsKICAgIGFubm90YXRlKGdlb20gPSAic2VnbWVudCIsCiAgICAgICAgICAgICAgICAgeCA9IDAsCiAgICAgICAgICAgICAgICAgeGVuZCA9IDAsCiAgICAgICAgICAgICAgICAgeSA9IDAsCiAgICAgICAgICAgICAgICAgeWVuZCA9IChtZWRpYW4oYWgkZHVyKSAqIGNvZWYoYWhfbW9kZWwpWzJdKSsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWYoYWhfbW9kZWwpWzFdLAogICAgICAgICAgICAgY29sb3IgPSAncmVkJywKICAgICAgICAgICAgIGFycm93ID0gYXJyb3coKSkrCiAgICBzdGF0X3Ntb290aChtZXRob2QgPSAnbG0nLAogICAgICAgICAgICAgICAgc2UgPSBGLAogICAgICAgICAgICAgICBmdWxscmFuZ2UgPSBULAogICAgICAgICAgICAgICBzaXplID0gMC41LAogICAgICAgICAgICAgICBjb2xvciA9ICdyZWQnLAogICAgICAgICAgICAgICBsaW5ldHlwZSA9IDIpKyAKICAgIHhsYWIoIihkdXIgLSAwLjEyKSIpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKRG9pbmcgdGhpcyBpcyBub3Qgb25seSAiYWxsb3dlZCIsIGl0IGlzIGVuY291cmFnZWQuIFNpbXBseSBhZGRpbmcgb3Igc3VidHJhY3RpbmcgYSBjb25zdGFudCB2YWx1ZSBmcm9tIGEgY29udGludW91cyBwcmVkaWN0b3Igd29uJ3QgYWZmZWN0IGl0J3Mgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlLiBCdXQgaXQgZG9lcyBtYWtlIHRoZSBpbnRlcmNlcHQgb2YgdGhlIG1vZGVsIG1vcmUgaW50ZXJwcmV0YWJsZS4KCmBgYHtyfQphaF9tb2RlbF9jIDwtIGxtKEYxX24gfiBkdXJfY2VudGVyLCBkYXRhID0gYWgpCnN1bW1hcnkoYWhfbW9kZWxfYykKYGBgCgojIyMgRml4aW5nIHRoZSBzbG9wZQoKVGhlIG5leHQgaXNzdWUgdG8gZGVhbCB3aXRoIGlzIHRoZSBzbG9wZSBwYXJhbWV0ZXIuIFRoZSBpbnRlcnByZXRhdGlvbiBvZiB0aGUgc2xvcGUgcGFyYW1ldGVyIGFzIGl0IGlzIGlzIHRoYXQgZm9yIGV2ZXJ5IDEgc2Vjb25kIHZvd2VsIGR1cmF0aW9uIGluY3JlYXNlcywgbm9ybWFsaXplIEYxIGluY3JlYXNlcyBgciByb3VuZChjb2VmKGFoX21vZGVsX2MpWzJdLCBkaWdpdHMgPSAxKWAuIFdoaWxlIHRoaXMgbWF5IGJlIGFjY3VyYXRlLCBpdCdzIG5vdCBleGFjdGx5IHVzZWZ1bCwgYmVjYXVzZSB0aGUgZnVsbCByYW5nZSBvZiB0aGUgZGF0YSwgaW5jbHVkaW5nIHRoZSBleHRyZW1lIG91dGxpZXJzIGRvZXNuJ3Qgc3BhbiBhIHdob2xlIDEgc2Vjb25kLgoKYGBge3J9CnN1bW1hcnkoYWgkZHVyKQpgYGAKCkFnYWluLCB3aGF0IHdlIHdvdWxkIGxpa2UgdGhlIG1vZGVsIHRvIGRvIGlzIHRlbGwgdXMgbm90IGhvdyBtdWNoIG5vcm1hbGl6ZWQgRjEgd2lsbCBjaGFuZ2Ugd2hlbiB0aGUgZHVyYXRpb24gY2hhbmdlcyBieSAxIHNlY29uZCwgYnV0IG1heWJlIHNvbWV0aGluZyBtb3JlIGxpa2UgNTBtcy4gQW5kIGFnYWluLCB3ZSBjYW4ndCBkaXJlY3RseSBtYWtlIHRoZSBtb2RlbCBkbyB0aGlzLCBidXQgd2UgY2FuIHRyaWNrIGl0IGludG8gZG9pbmcgc28sIGJ1dCAqKmRpdmlkaW5nIGR1cmF0aW9uIGJ5IHNvbWUgdmFsdWUqKi4KCldoYXQgaXMgc3RhbmRhcmQgaW4gdGhlc2UgY2lyY3Vtc3RhbmNlcyBpcyB0byBkaXZpZGUgdGhlIHByZWRpY3RvciB2YXJpYWJsZSBieSBpdHMgKnN0YW5kYXJkIGRldmlhdGlvbiosIGEgbWVhc3VyZSBvZiBob3cgc3ByZWFkIG91dCB0aGUgZGF0YSBpcyBmcm9tIGl0cyBjZW50ZXIgcG9pbnQuIEdlbG1hbiAmIEhpbGwgKDIwMDYpIHJlY29tbWVuZCBhY3R1YWxseSBkaXZpZGluZyBieSB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIHRpbWVzIDIuCgpgYGB7ciBlY2hvID0gRn0KZHVyX3NkIDwtIHNkKGFoJGR1cikKZHVyX21lYW4gPC0gbWVhbihhaCRkdXIpCgphaCAlPiUKICBnZ3Bsb3QoYWVzKGR1cikpKwogICAgc3RhdF9kZW5zaXR5KGNvbG9yID0gJ2JsYWNrJywKICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNikrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBkdXJfbWVhbikrCiAgICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwKICAgICAgICAgICAgIHggPSBkdXJfbWVhbiwgCiAgICAgICAgICAgICB5ID0gOCwKICAgICAgICAgICAgIGxhYmVsID0gIm1lYW4iKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGR1cl9tZWFuICsgZHVyX3NkKSsKICAgIGFubm90YXRlKGdlb20gPSAibGFiZWwiLAogICAgICAgICAgICAgeCA9IGR1cl9tZWFuICsgZHVyX3NkLCAKICAgICAgICAgICAgIHkgPSA3LAogICAgICAgICAgICAgbGFiZWwgPSAiKzEgc2QiKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGR1cl9tZWFuICsgKGR1cl9zZCoyKSkrCiAgICBhbm5vdGF0ZShnZW9tID0gImxhYmVsIiwKICAgICAgICAgICAgIHggPSBkdXJfbWVhbiArIChkdXJfc2QqMiksIAogICAgICAgICAgICAgeSA9IDYsCiAgICAgICAgICAgICBsYWJlbCA9ICIrMiBzZCIpKyAgCiAgICB0aGVtZV9taW5pbWFsKCkKYGBgCgoKYGBge3J9CmFoIDwtIGFoICU+JQogICAgICAgICAgbXV0YXRlKGR1cl96ID0gZHVyX2NlbnRlci8oc2QoZHVyX2NlbnRlcikqMikpCmBgYAoKYGBge3J9CmFoX21vZGVsX3ogPC0gbG0oRjFfbiB+IGR1cl96LCBkYXRhID0gYWgpCnN1bW1hcnkoYWhfbW9kZWxfeikKYGBgCgpOb3csIHRoZSBzbG9wZSBpcyBkZXNjcmliaW5nIGhvdyBtdWNoIG5vcm1hbGl6ZWQgRjEgaW5jcmVhc2VzIGV2ZXJ5IHRpbWUgdGhlIHZvd2VsIGR1cmF0aW9uIGluY3JlYXNlcyAyIHN0YW5kYXJkIGRldmlhdGlvbnMsICRcYXBwcm94JCAxMDBtcwoKYGBge3IgZWNobyA9IEZ9CnpfZGYgPC0gZGF0YV9mcmFtZShkdXJfeiA9IGMoMCwxLDIsMyksCiAgICAgICAgICAgICAgICAgICBGMV9uID0gKGR1cl96ICogY29lZihhaF9tb2RlbF96KVsyXSkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWYoYWhfbW9kZWxfeilbMV0pCgpnZ3Bsb3QoYWgsIGFlcyhkdXJfeiwgRjFfbikpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikrICAgIAogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMDYpKwogICAgZ2VvbV9wb2ludChkYXRhID0gel9kZiwgY29sb3IgPSAncmVkJykrCiAgICBnZW9tX3N0ZXAoZGF0YSA9IHpfZGYsIGNvbG9yID0gJ3JlZCcpKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJzZWdtZW50IiwKICAgICAgICAgICAgIHggPSAwLCB4ZW5kID0gMCwKICAgICAgICAgICAgIHkgPSAwLCB5ZW5kID0gY29lZihhaF9tb2RlbF96KVsxXSwKICAgICAgICAgICAgIGNvbG9yID0gJ3JlZCcsCiAgICAgICAgICAgICBhcnJvdyA9IGFycm93KCkpKwogICAgc3RhdF9zbW9vdGgobWV0aG9kPSAnbG0nLAogICAgICAgICAgICAgICAgY29sb3IgPSAncmVkJywKICAgICAgICAgICAgICAgIHNpemUgPSAwLjUsCiAgICAgICAgICAgICAgICBsaW5ldHlwZSA9IDIsCiAgICAgICAgICAgICAgICBzZSA9IEYpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMjIERlc2NyaWJpbmcgd2hhdCB3ZSBqdXN0IGRpZAoKPiBUYWJsZSBYWCBkaXNwbGF5cyB0aGUgZXN0aW1hdGVkIHBhcmFtZXRlcnMgcHJlZGljdGluZyBub3JtYWxpemVkIEYxIG9mIC/JkS8uIER1cmF0aW9uIHdhcyBjZW50ZXJlZCBhdCB0aGUgbWVkaWFuIGFuZCBzY2FsZWQgYnkgdHdvIHRpbWVzIGl0cyBzdGFuZGFyZCBkZXZpYXRpb24gKGByIHJvdW5kKChkdXJfc2QqMikqMTAwMClgKSBwZXIgdGhlIHJlY29tbWVuZGF0aW9uIG9mIEdlbG1hbiAmIEhpbGwgKDIwMDYpLgoKYGBge3IgZWNobyA9IEYsIHJlc3VsdHMgPSAnYXNpcycsIG1lc3NhZ2U9Rn0KbGlicmFyeShrbml0cikKYWhfbW9kZWxfeiAlPiUKICB0aWR5KCkgJT4lCiAgdHJhbnNtdXRlKHRlcm0gPSByZWNvZGUodGVybSwgZHVyX3ogPSAiU2NhbGVkIER1cmF0aW9uIiksCiAgICAgICAgICAgIGVzdGltYXRlID0gcm91bmQoZXN0aW1hdGUsIGRpZ2l0cyA9IDIpLAogICAgICAgICAgICBzdGQuZXJyb3IgPSByb3VuZChzdGQuZXJyb3IsIGRpZ2l0cyA9IDMpLAogICAgICAgICAgICB0X3ZhbHVlID0gcm91bmQoc3RhdGlzdGljKSwKICAgICAgICAgICAgcC52YWx1ZSA9IHAudmFsdWUpICU+JQogIGthYmxlKCkKYGBgCgoKCjxkaXYgY2xhc3MgPSAiYm94IGJyZWFrIj4KPHNwYW4gY2xhc3MgPSAnYmlnLWxhYmVsJz5QYXVzZSBmb3IgUXVlc3Rpb25zL0RlYnVnZ2luZzwvc3Bhbj4KPC9kaXY+CgojIEV2YWx1YXRpbmcgb3VyIG1vZGVsCgpTbywgaXMgdGhpcyBtb2RlbCBhbnkgZ29vZD8gVGhpcyBxdWVzdGlvbiBjYW4gYmUgYXBwcm9hY2hlZCBmcm9tIGEgZmV3IGRpZmZlcmVudCBhbmdsZXMuCgoxLiBJcyBpdCBwb3NzaWJsZSB0aGF0IGFueSBvZiBvdXIgbW9kZWwgcGFyYW1ldGVycyBhcmUgMD8KMi4gSG93IGdyZWF0IGlzIG91ciB1bmNlcnRhaW50eSBhYm91dCB0aGUgc3BlY2lmaWMgbW9kZWwgcGFyYW1ldGVycz8gVGhhdCBpcywgdGhlIG1vZGVsIGhhcyBlc3RpbWF0ZWQgYW4gaW50ZXJjZXB0IG9mIGByIHJvdW5kKGNvZWYoYWhfbW9kZWxfeilbMV0sIGRpZ2l0cyA9IDIpYC4gSG93IG11Y2ggd2lnZ2xlIHJvb20gaXMgdGhlcmU/CjMuIERvIGFsbCBvZiBvdXIgbW9kZWwgcGFyYW1ldGVycyBoYXZlIHRoZSByaWdodCBzaWduPyBUaGF0IGlzLCBhcmUgdGhleSBwcmVkaWN0aW5nIGFuIGVmZmVjdCBpbiB0aGUgInJpZ2h0IiBkaXJlY3Rpb24/CjQuIEFyZSBvdXIgbW9kZWwgcGFyYW1ldGVycyBhIHJlYXNvbmFibGUgc2l6ZT8gSXMgaXQgcG9zc2libGUgdGhhdCBhbnkgb2YgdGhlbSBhcmUgYmVpbmcgZHJhbWF0aWNhbGx5IG92ZXJlc3RpbWF0ZWQ/IAoKYGBge3J9CnN1bW1hcnkoYWhfbW9kZWxfeikKYGBgCgoKU29tZSBvZiB0aGVzZSBxdWVzdGlvbnMgZmFsbCB1bmRlciB0aGUgcnVicmljIG9mICJudWxsIGh5cG90aGVzaXMgdGVzdGluZy4iCldoZW4gcGVvcGxlIHNheSB0aGVpciByZXN1bHRzIGFyZSAic2lnbmlmaWNhbnQiLCBvciBwPDAuMDUgdGhpcyBpcyB3aGF0IHRoZXkncmUgdGFsa2luZyBhYm91dC4KSW4gaXRzIGN1cnJlbnQgdXNlLCBwZW9wbGUgb2Z0ZW4gW3RyeSB0byBkaXZpZGUgdGhlaXIgcHJlZGljdG9yIHZhcmlhYmxlc10oaHR0cDovL3d3dy5zdGF0LmNvbHVtYmlhLmVkdS9+Z2VsbWFuL3Jlc2VhcmNoL3VucHVibGlzaGVkL211cnRhdWdoMi5wZGYpIGludG8gdGhvc2Ugd2hpY2ggImhhdmUgYW4gZWZmZWN0IiBhbmQgdGhvc2UgdGhhdCAiZG9uJ3QgaGF2ZSBhbiBlZmZlY3QiIGFuZCB0aGV5IG9mdGVuIHVzZSBwLXZhbHVlcyB0byBkbyB0aGlzLgoKVGhlIHN1bW1hcnkgb2YgdGhlIGxpbmVhciBtb2RlbCBjb250YWlucyB0aGUgcC12YWx1ZXMgaW4gdGhlIGZpbmFsIGNvbHVtbiBjYWxsZWQgYFByKD58dHwpYC4gCkhlcmUgbXkgYmVzdCBzaG90IGF0IGEgZGVmaW5pdGlvbiBvZiBwLXZhbHVlczoKCjxkaXYgY2xhc3MgPSAiYm94IGlkaW9tIj4KPHNwYW4gY2xhc3MgPSAnYmlnLWxhYmVsJz5QIFZhbHVlczwvc3Bhbj4KCklmIHdlIGFzc3VtZSB0aGF0ICp+fnRoZSBzbG9wZSBvZiB0aGUgbGluZSBpcyBhY3R1YWxseSAwfn4qIHRoZXJlIGlzIG5vIHJlbGF0aW9uc2hpcCBwcmVzZW50IGluIHRoZSBkYXRhLCAgdGhlIHByb2JhYmlsaXR5IHdlIHdvdWxkIG9ic2VydmUgYSBzbG9wZSBhcyBleHRyZW1lIGFzLCBvciBtb3JlIGV4dHJlbWUgdGhhbiB0aGlzLCBnaXZlbiB0aGUgc2l6ZSBvZiB0aGUgc2FtcGxlIGFuZCB0aGUgdmFyaWFuY2Ugb2YgdGhlIGRhdGEsIGlzIHRoZSBwLXZhbHVlLgoKVHlwaWNhbGx5LCB3ZSB0YWtlIHAgPCAwLjA1IGFzIHRoZSBjdXQgb2ZmIGZvciBzYXlpbmcgaXQgd291bGQgYmUgaGlnaGx5IGltcHJvYmFibGUgdG8gb2JzZXJ2ZSBhIHNsb3BlIG9mIHRoaXMgc2l6ZSBpZiAqfn50aGUgc2xvcGUgd2VyZSBhY3R1YWxseSAwfn4qIHRoZXJlIHdhcyBubyByZWxhdGlvbnNoaXAgaW4gdGhlIGRhdGEsIHNvICp+fnRoZSBzbG9wZSBpcyBwcm9iYWJseSBub3QgMH5+Kiwgd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCB0aGVyZSBpcyBubyByZWxhdGlvbnNoaXAgaW4gdGhlIGRhdGEuCjwvZGl2PgoKCgpBIHByb2JsZW0gd2l0aCBwLXZhbHVlcyBpcyB0aGF0IGV2ZW4gaWYgeW91J3ZlIHJlYWQgdGhhdCBwYXJhZ3JhcGgsIHlvdSBwcm9iYWJseSBzdGlsbCBkb24ndCBhY3R1YWxseSB1bmRlcnN0YW5kIHdoYXQgcC12YWx1ZXMgYXJlLiBBbmQgd2hlbiB5b3UgZG8gcmVhbGx5IHVuZGVyc3RhbmQgd2hhdCBwLXZhbHVlcyBhcmUsIHlvdSdsbCBwcm9iYWJseSBmb3JnZXQgd2hhdCB0aGV5IHJlYWxseSBhcmUuIEluIGZhY3QsIEkgdHdlZXRlZCBvdXQgd2hhdCBJIHdhcyBwbGFubmluZyB0byBzYXkgYWJvdXQgcC12YWx1ZXMsIGFuZCBiYXNlZCBvbiB0aGUgZmVlZGJhY2sgSSBoYWQgdG8gbWFrZSBzb21lIGNoYW5nZXMgKGFzIGV2aWRlbmNlZCBieSB0aGUgc3RyaWtlIHRocm91Z2hzKS4gCgpNeSBoeXBvdGhlc2lzIGlzIHRoYXQgdHJ1bHkgdW5kZXJzdGFuZGluZyB3aGF0IHAtdmFsdWVzIGFyZSByZXF1aXJlcyBhIGtpbmQgb2YgY291bnRlcmZhY3R1YWwgdGhpbmtpbmcgYW5kIGNvbmRpdGlvbmFsIHByb2JhYmlsaXR5IHRoYXQgcGVvcGxlIGFyZSBhY3R1YWxseSB2ZXJ5IGJhZCBhdCwgZXZlbiBwZW9wbGUgd2hvIHdvcmsgd2l0aCBwLXZhbHVlcyBhbGwgdGhlIHRpbWUuCgpUaGUgZmFjdCBvZiB0aGUgbWF0dGVyIGlzIHRoYXQgeW91IG11c3QgaW5jbHVkZSBwLXZhbHVlcyBpbiB5b3VyIHdyaXRldXBzIG9mIHlvdXIgYW5hbHlzZXMgYmVjYXVzZSBzb2NpZXR5IGRlbWFuZHMgaXQuIEhvd2V2ZXIgSSB0aGluayBpdCAqaXMqIGltcG9ydGFudCB0byBiZSBqdWRpY2lvdXMuIElmIHlvdSBoYXZlIGEgcC12YWx1ZSBncmVhdGVyIHRoYW4gMC4wNSwgeW91ciBldmFsdWF0aW9uIG9mIHRoZSBlZmZlY3Qgc2hvdWxkIGJlIGRvd25ncmFkZWQuIElmIHlvdSBoYXZlIGEgcC12YWx1ZSBsZXNzIHRoYW4gMC4wNSwgaXQncyBhbHNvIGltcG9ydGFudCBub3QgdG8gc3RvcCB0aGVyZSBhbmQgY29uY2x1ZGUgdGhhdCB0aGUgZWZmZWN0IGlzICJyZWFsIi4KCldpdGggdGhhdCBpbiBtaW5kIGl0J3MgY3J1Y2lhbCB0byBhbHNvIGFzayB3aGV0aGVyIHRoZSBlc3RpbWF0ZWQgZWZmZWN0IGlzIGluIHRoZSBleHBlY3RlZCBkaXJlY3Rpb24sIGFuZCB3aGV0aGVyIHRoZSBlZmZlY3Qgc2l6ZSBpcyBzZW5zaWJsZS4gQWRkcmVzc2luZyB0aGVzZSB0d28gcXVlc3Rpb25zIHJlcXVpcmVzIGhhdmluZyBzb21lIGJhY2tncm91bmQgdG8gZHJhdyBvbmUgKHByZXZpb3VzbHkgcmVwb3J0ZWQgZWZmZWN0IHNpemVzIGluIHRoZSBsaXQpLCBhIGdvb2QgdGhlb3JldGljYWwgcmVhc29uIGZvciBmaXR0aW5nIHRoaXMgcGFydGljdWxhciBtb2RlbCwgYW5kIHBlcmhhcHMgc29tZSBjb250ZXh0dWFsIGluZm8uCgpJZiB5b3UgZG9uJ3QgaGF2ZSBhbnkgcmVhc29uIHRvIGh5cG90aGVzaXplIGFuIGVmZmVjdCBpbiBhbnkgcGFydGljdWxhciBkaXJlY3Rpb24gKGNvdWxkIGJlIHBvc2l0aXZlLCBjb3VsZCBiZSBuZWdhdGl2ZSksIHRoZW4geW91IG1pZ2h0IG5vdCBiZSByZWFkeSwgYXMgZmFyIGFzIHlvdXIgaW5mZXJlbmNlcyBnbywgdG8gdXNlIHN0YXRpc3RpY2FsIG1vZGVsbGluZyB5ZXQuCgpGb3Igb3VyIHBhcnRpY3VsYXIgbW9kZWwsIEkgaGFkIHNvbWUgcHJldHR5IGdvb2QgcmVhc29ucyB0byBhc3N1bWUgYSBwb3NpdGl2ZSBlZmZlY3QsIHdoaWNoIGlzIHdoYXQgd2UgZ290LiBJcyBgciByb3VuZChjb2VmKGFoX21vZGVsX3opWzJdLCBkaWdpdHMgPSAyKWAgYSAiYmlnIiBvciBhICJzbWFsbCIgZWZmZWN0PyBDb21wYXJlZCB0byB3aGF0PwoKCiMgTXVsdGlwbGUgUmVncmVzc2lvbgoKV2Ugb2Z0ZW4gd2FudCB0byBmaWd1cmUgb3V0IGhvdyBtdWx0aXBsZSBwb3NzaWJsZSBwcmVkaWN0b3JzIGluZmx1ZW5jZSB0aGUgZGF0YSB3ZSdyZSBpbnZlc3RpZ2F0aW5nLgpTdWNoIG1vZGVscyBhcmUgY2FsbGVkICJtdWx0aXBsZSByZWdyZXNzaW9uIi4KRm9yIHRoZSBgYWhgIHJlZ3Jlc3Npb24sIHdlJ3JlIG5leHQgZ29pbmcgdG8gYWRkIHRoZSB3b3JkIGNvbnRleHQgaW4gd2hpY2ggdGhlIHZvd2VsIGFwcGVhcnM6CgpgYGB7cn0KdGFibGUoYWgkY29udGV4dCkKYGBgCgpXZSdyZSBnb2luZyB0byBmb2N1cyBvbiBqdXN0IHdvcmQgZmluYWwgYW5kIHdvcmQgaW50ZXJuYWwgY29udGV4dHMuCgoKYGBge3J9CmFoXzIgPC0gYWggJT4lIGZpbHRlcihjb250ZXh0ICVpbiUgYygiaW50ZXJuYWwiLCAiZmluYWwiKSkKYGBgCgpBZGRpbmcgYGNvbnRleHRgIHRvIHRoZSBtb2RlbCBpcyBhcyBlYXN5IGFzIGArIGNvbnRleHRgCgpgYGB7cn0KYWhfbW9kX211bHQgPC0gbG0oRjFfbiB+IGR1cl96ICsgY29udGV4dCwgZGF0YSA9IGFoXzIpCnN1bW1hcnkoYWhfbW9kX211bHQpCmBgYAoKCkhlcmUncyBob3cgdG8gaW50ZXJwcmV0IHRoZXNlIHJlc3VsdHMuIApGaXJzdCwgd2hlbiB5b3UgYWRkIGEgY2F0ZWdvcmljYWwgcHJlZGljdG9yIHRvIGEgbW9kZWwsIG9uZSBvZiB0aGUgY2F0ZWdvcmllcyBpcyBjaG9zZW4gYXMgYSAqKnJlZmVyZW5jZSBsZXZlbCoqLl5bVGhlcmUgYXJlIGFjdHVhbGx5IG90aGVyIGFwcHJvYWNoZXMgdG8gZW5jb2RpbmcgY2F0ZWdvcmljYWwgcHJlZGljdG9ycyB0aGF0IGRvbid0IGludm9sdmUgY2hvb3NpbmcgYSByZWZlcmVuY2UgbGV2ZWwgdGhhdCB3ZSdyZSBub3QgZ29pbmcgdG8gZ2V0IHRvLl0KVGhlIGAoSW50ZXJjZXB0KWAgaXMgbm93IHRoZSBlc3RpbWF0ZWQgRjFfbiB3aGVuIGFsbCBvZiB0aGUgcHJlZGljdG9ycyBhcmUgMCBvciB0aGUgcmVmZXJlbmNlIGxldmVsLgpGb3IgdGhpcyBtb2RlbCwgdGhhdCBtZWFucyB0aGUgcHJlZGljdGVkIHZhbHVlIHdoZW4gYGR1cl96PT0wYCBhbmQgYGNvbnRleHQ9PSJmaW5hbCJgLgoKYGBge3IgZWNobyA9IEZ9CmxpYnJhcnkoZ2d0aGVtZXMpCnBhbCA8LSBjb2xvcmJsaW5kX3BhbCgpKDMpCgphaF8yICU+JQogIGdncGxvdChhZXMoZHVyX3osIEYxX24pKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9IDIpKyAgICAgIAogICAgI2dlb21fcG9pbnQoYWxwaGEgPSAwLjAzKSsKICAgIGFubm90YXRlKGdlb20gPSAic2VnbWVudCIsCiAgICAgICAgICAgICB4ID0gMCwgCiAgICAgICAgICAgICB4ZW5kID0gMCwKICAgICAgICAgICAgIHkgPSAwLAogICAgICAgICAgICAgeWVuZCA9IGNvZWYoYWhfbW9kX211bHQpWzFdLAogICAgICAgICAgICAgY29sb3IgPSBwYWxbMl0sCiAgICAgICAgICAgICBhcnJvdyA9IGFycm93KCkpKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJwb2ludCIsCiAgICAgICAgICAgICB4ID0gMCwgCiAgICAgICAgICAgICB5ID0gY29lZihhaF9tb2RfbXVsdClbMV0sCiAgICAgICAgICAgICBjb2xvciA9IHBhbFsyXSwKICAgICAgICAgICAgIHNpemUgPSAzKSsgIAogICAgeWxpbSgwLDIpKwogICAgeGxpbSgtMC41LCAyKSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKCldlIGNhbiwgZm9yIG5vdywgaW50ZXJwcmV0IHRoZSBzbG9wZSBgZHVyX3pgIGFzIGJlaW5nIHRoZSBzbG9wZSBmb3Igd29yZCBmaW5hbCBgYWhgLiAKCgpgYGB7ciBlY2hvID0gRn0KYWhfMiAlPiUKICBnZ3Bsb3QoYWVzKGR1cl96LCBGMV9uKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9IDIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsgICAgICAKICAgICNnZW9tX3BvaW50KGFscGhhID0gMC4wMykrCiAgICBhbm5vdGF0ZShnZW9tID0gInNlZ21lbnQiLAogICAgICAgICAgICAgeCA9IDAsIAogICAgICAgICAgICAgeGVuZCA9IDAsCiAgICAgICAgICAgICB5ID0gMCwKICAgICAgICAgICAgIHllbmQgPSBjb2VmKGFoX21vZF9tdWx0KVsxXSwKICAgICAgICAgICAgIGNvbG9yID0gcGFsWzJdLAogICAgICAgICAgICAgYXJyb3cgPSBhcnJvdygpKSsKICAgIGFubm90YXRlKGdlb20gPSAicG9pbnQiLAogICAgICAgICAgICAgeCA9IDAsIAogICAgICAgICAgICAgeSA9IGNvZWYoYWhfbW9kX211bHQpWzFdLAogICAgICAgICAgICAgY29sb3IgPSBwYWxbMl0sCiAgICAgICAgICAgICBzaXplID0gMykrICAKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGNvZWYoYWhfbW9kX211bHQpWzFdLAogICAgICAgICAgICAgICAgc2xvcGUgPSBjb2VmKGFoX21vZF9tdWx0KVsyXSwKICAgICAgICAgICAgICAgIGNvbG9yID0gcGFsWzJdKSsKICAgIGFubm90YXRlKGdlb20gPSAibGFiZWwiLAogICAgICAgICAgICAgeCA9IDAuMjUsCiAgICAgICAgICAgICB5ID0gY29lZihhaF9tb2RfbXVsdClbMV0gKyAoIGNvZWYoYWhfbW9kX211bHQpWzJdICogMC4yNSksCiAgICAgICAgICAgICBsYWJlbCA9ICJmaW5hbCIsCiAgICAgICAgICAgICBjb2xvciA9IHBhbFsyXSkrCiAgICB5bGltKDAsMikrCiAgICB4bGltKC0wLjUsIDIpKyAgCiAgICB0aGVtZV9taW5pbWFsKCkKYGBgCgpUaGUgZWZmZWN0IG9mIGBjb250ZXh0PWludGVybmFsYCBjYW4gYmUgaW50ZXJwZXRlZCBhcyBob3cgbXVjaCBvZmZzZXQgdGhlIGludGVyY2VwdCBvZiB0aGUgbGluZSBmb3IgdGhlIGludGVybmFsIGNvbnRleHQgaXM6CgpgYGB7ciBlY2hvID0gRn0KYWhfMiAlPiUKICBnZ3Bsb3QoYWVzKGR1cl96LCBGMV9uKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9IDIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsgICAgICAKICAgICNnZW9tX3BvaW50KGFscGhhID0gMC4wMykrCiAgICBhbm5vdGF0ZShnZW9tID0gInNlZ21lbnQiLAogICAgICAgICAgICAgeCA9IDAsIAogICAgICAgICAgICAgeGVuZCA9IDAsCiAgICAgICAgICAgICB5ID0gMCwKICAgICAgICAgICAgIHllbmQgPSBjb2VmKGFoX21vZF9tdWx0KVsxXSwKICAgICAgICAgICAgIGNvbG9yID0gcGFsWzJdLAogICAgICAgICAgICAgYXJyb3cgPSBhcnJvdygpKSsKICAgIGFubm90YXRlKGdlb20gPSAicG9pbnQiLAogICAgICAgICAgICAgeCA9IDAsIAogICAgICAgICAgICAgeSA9IGNvZWYoYWhfbW9kX211bHQpWzFdLAogICAgICAgICAgICAgY29sb3IgPSBwYWxbMl0sCiAgICAgICAgICAgICBzaXplID0gMykrICAKICAgIGFubm90YXRlKGdlb20gPSAic2VnbWVudCIsCiAgICAgICAgICAgICB4ID0gMCwgCiAgICAgICAgICAgICB4ZW5kID0gMCwKICAgICAgICAgICAgIHkgPSBjb2VmKGFoX21vZF9tdWx0KVsxXSwKICAgICAgICAgICAgIHllbmQgPSBjb2VmKGFoX21vZF9tdWx0KVsxXSArIGNvZWYoYWhfbW9kX211bHQpWzNdLAogICAgICAgICAgICAgY29sb3IgPSBwYWxbM10sCiAgICAgICAgICAgICBhcnJvdyA9IGFycm93KCkpKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJwb2ludCIsCiAgICAgICAgICAgICB4ID0gMCwgCiAgICAgICAgICAgICB5ID0gY29lZihhaF9tb2RfbXVsdClbMV0gKyBjb2VmKGFoX21vZF9tdWx0KVszXSwKICAgICAgICAgICAgIGNvbG9yID0gcGFsWzNdLAogICAgICAgICAgICAgc2l6ZSA9IDMpKyAgCiAgICBhbm5vdGF0ZShnZW9tID0gInBvaW50IiwKICAgICAgICAgICAgIHggPSAwLCAKICAgICAgICAgICAgIHkgPSBjb2VmKGFoX21vZF9tdWx0KVsxXSwKICAgICAgICAgICAgIGNvbG9yID0gcGFsWzJdLAogICAgICAgICAgICAgc2l6ZSA9IDMpKyAgIAogICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gY29lZihhaF9tb2RfbXVsdClbMV0sCiAgICAgICAgICAgICAgICBzbG9wZSA9IGNvZWYoYWhfbW9kX211bHQpWzJdLAogICAgICAgICAgICAgICAgY29sb3IgPSBwYWxbMl0pKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJsYWJlbCIsCiAgICAgICAgICAgICB4ID0gMC4yNSwKICAgICAgICAgICAgIHkgPSBjb2VmKGFoX21vZF9tdWx0KVsxXSArICggY29lZihhaF9tb2RfbXVsdClbMl0gKiAwLjI1KSwKICAgICAgICAgICAgIGxhYmVsID0gImZpbmFsIiwKICAgICAgICAgICAgIGNvbG9yID0gcGFsWzJdKSsgIAogICAgeWxpbSgwLDIpKwogICAgeGxpbSgtMC41LCAyKSsgIAogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKQW5kIHRoZSBzbG9wZSBvZiB0aGUgd29yZCBpbnRlcm5hbCBjb250ZXh0ICppcyB0aGUgc2FtZSogYXMgdGhlIHdvcmQgZmluYWwgY29udGV4dCwgYXMgZmFyIGFzIHRoaXMgbW9kZWwgaXMgY29uY2VybmVkLgoKYGBge3IgZWNobyA9IEZ9CmFoXzIgJT4lCiAgZ2dwbG90KGFlcyhkdXJfeiwgRjFfbikpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikrICAgICAgCiAgICAjZ2VvbV9wb2ludChhbHBoYSA9IDAuMDMpKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJzZWdtZW50IiwKICAgICAgICAgICAgIHggPSAwLCAKICAgICAgICAgICAgIHhlbmQgPSAwLAogICAgICAgICAgICAgeSA9IDAsCiAgICAgICAgICAgICB5ZW5kID0gY29lZihhaF9tb2RfbXVsdClbMV0sCiAgICAgICAgICAgICBjb2xvciA9IHBhbFsyXSwKICAgICAgICAgICAgIGFycm93ID0gYXJyb3coKSkrCiAgICBhbm5vdGF0ZShnZW9tID0gInBvaW50IiwKICAgICAgICAgICAgIHggPSAwLCAKICAgICAgICAgICAgIHkgPSBjb2VmKGFoX21vZF9tdWx0KVsxXSwKICAgICAgICAgICAgIGNvbG9yID0gcGFsWzJdLAogICAgICAgICAgICAgc2l6ZSA9IDMpKyAgCiAgICBhbm5vdGF0ZShnZW9tID0gInNlZ21lbnQiLAogICAgICAgICAgICAgeCA9IDAsIAogICAgICAgICAgICAgeGVuZCA9IDAsCiAgICAgICAgICAgICB5ID0gY29lZihhaF9tb2RfbXVsdClbMV0sCiAgICAgICAgICAgICB5ZW5kID0gY29lZihhaF9tb2RfbXVsdClbMV0gKyBjb2VmKGFoX21vZF9tdWx0KVszXSwKICAgICAgICAgICAgIGNvbG9yID0gcGFsWzNdLAogICAgICAgICAgICAgYXJyb3cgPSBhcnJvdygpKSsKICAgIGFubm90YXRlKGdlb20gPSAicG9pbnQiLAogICAgICAgICAgICAgeCA9IDAsIAogICAgICAgICAgICAgeSA9IGNvZWYoYWhfbW9kX211bHQpWzFdICsgY29lZihhaF9tb2RfbXVsdClbM10sCiAgICAgICAgICAgICBjb2xvciA9IHBhbFszXSwKICAgICAgICAgICAgIHNpemUgPSAzKSsgIAogICAgYW5ub3RhdGUoZ2VvbSA9ICJwb2ludCIsCiAgICAgICAgICAgICB4ID0gMCwgCiAgICAgICAgICAgICB5ID0gY29lZihhaF9tb2RfbXVsdClbMV0sCiAgICAgICAgICAgICBjb2xvciA9IHBhbFsyXSwKICAgICAgICAgICAgIHNpemUgPSAzKSsgICAKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGNvZWYoYWhfbW9kX211bHQpWzFdLAogICAgICAgICAgICAgICAgc2xvcGUgPSBjb2VmKGFoX21vZF9tdWx0KVsyXSwKICAgICAgICAgICAgICAgIGNvbG9yID0gcGFsWzJdKSsKICAgIGFubm90YXRlKGdlb20gPSAibGFiZWwiLAogICAgICAgICAgICAgeCA9IDAuMjUsCiAgICAgICAgICAgICB5ID0gY29lZihhaF9tb2RfbXVsdClbMV0gKyAoIGNvZWYoYWhfbW9kX211bHQpWzJdICogMC4yNSksCiAgICAgICAgICAgICBsYWJlbCA9ICJmaW5hbCIsCiAgICAgICAgICAgICBjb2xvciA9IHBhbFsyXSkrICAKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGNvZWYoYWhfbW9kX211bHQpWzFdICsgY29lZihhaF9tb2RfbXVsdClbM10sCiAgICAgICAgICAgICAgICBzbG9wZSA9IGNvZWYoYWhfbW9kX211bHQpWzJdLAogICAgICAgICAgICAgICAgY29sb3IgPSBwYWxbM10pKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJsYWJlbCIsCiAgICAgICAgICAgICB4ID0gMC4yNSwKICAgICAgICAgICAgIHkgPSBjb2VmKGFoX21vZF9tdWx0KVsxXSArICggY29lZihhaF9tb2RfbXVsdClbMl0gKiAwLjI1KSArIGNvZWYoYWhfbW9kX211bHQpWzNdLAogICAgICAgICAgICAgbGFiZWwgPSAiaW50ZXJuYWwiLAogICAgICAgICAgICAgY29sb3IgPSBwYWxbM10pKyAgICAKICAgIHlsaW0oMCwyKSsKICAgIHhsaW0oLTAuNSwgMikrICAKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKCiMjIEV2YWx1YXRpbmcgdGhpcyBtb2RlbC4KCgo8ZGl2IGNsYXNzID0gImJveCBicmVhayI+CjxzcGFuIGNsYXNzID0gImJpZy1sYWJlbCI+fjUgTWludXRlIERpc2N1c3Npb248L3NwYW4+CgpXaGF0IGRvIHdlIHRoaW5rIG9mIHRoaXMgbW9kZWw/IERvZXMgYGNvbnRleHRgIGhhdmUgYW4gZWZmZWN0PwoKYGBge3J9CnN1bW1hcnkoYWhfbW9kX211bHQpCmBgYAoKPC9kaXY+CgoKCiMjIEludGVyYWN0aW9ucwoKVGhlIGZhY3QgdGhhdCB0aGUgdHdvIHNsb3BlcyBvZiB3b3JkLWZpbmFsIGFuZCB3b3JkLWludGVybmFsIGBhaGAgd2VyZSB0aGUgc2FtZSBhYm92ZSB3YXMgYW4gKmFzc3VtcHRpb24qIG9mIHRoZSBtb2RlbC4gClRvIHB1dCBpdCBhbm90aGVyIHdheSwgaXQgZGlkbid0IGZpbmQgdGhhdCB0aGUgdHdvIHNsb3BlcyB3ZXJlIGRpZmZlcmVudCBiZWNhdXNlIGl0IGRpZG4ndCBsb29rLgpCdXQgaXQgaXMgcG9zc2libGUgdGhhdCB0aGUgc2xvcGVzIG9mIHRoZXNlIHR3byBjb250ZXh0cyAqYXJlKiBkaWZmZXJlbnQsIGFuZCB0aGF0IHdlIHNob3VsZCBleHBsb3JlIHRoaXMgcG9zc2liaWxpdHkuIApUaGlzIGlzIGRvbmUgYnkgZW50ZXJpbmcgYGNvbnRleHRgIGludG8gdGhlIG1vZGVsIGxpa2Ugc286CgpgYGB7cn0KYWhfbW9kX2ludGVyYWN0IDwtIGxtKEYxX24gfiBkdXJfeiAqIGNvbnRleHQsIGRhdGEgPSBhaF8yKQpzdW1tYXJ5KGFoX21vZF9pbnRlcmFjdCkKYGBgCgpIZXJlJ3MgaG93IHRvIGludGVycHJldCB0aGlzIG1vZGVsLiBGaXJzdCwgdGhlIGAoSW50ZXJjZXB0KWAgaXMgdGhlIGVzdGltYXRlZCBgRjFfbmAgZm9yIGBhaGAgd2hlbiBgZHVyX3o9PTBgIGFuZCBgY29udGV4dD09ImZpbmFsImAuIApgYGB7ciBlY2hvID0gRn0KYWhfMiAlPiUKICBnZ3Bsb3QoYWVzKGR1cl96LCBGMV9uKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9IDIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsgICAgICAKICAgICNnZW9tX3BvaW50KGFscGhhID0gMC4wMykrCiAgICBhbm5vdGF0ZShnZW9tID0gInNlZ21lbnQiLAogICAgICAgICAgICAgeCA9IDAsIAogICAgICAgICAgICAgeGVuZCA9IDAsCiAgICAgICAgICAgICB5ID0gMCwKICAgICAgICAgICAgIHllbmQgPSBjb2VmKGFoX21vZF9pbnRlcmFjdClbMV0sCiAgICAgICAgICAgICBjb2xvciA9IHBhbFsyXSwKICAgICAgICAgICAgIGFycm93ID0gYXJyb3coKSkrCiAgICBhbm5vdGF0ZShnZW9tID0gInBvaW50IiwKICAgICAgICAgICAgIHggPSAwLCAKICAgICAgICAgICAgIHkgPSBjb2VmKGFoX21vZF9pbnRlcmFjdClbMV0sCiAgICAgICAgICAgICBjb2xvciA9IHBhbFsyXSwKICAgICAgICAgICAgIHNpemUgPSAzKSsgIAogICAgeWxpbSgwLDIpKwogICAgeGxpbSgtMC41LCAyKSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKCgpUaGUgYGR1cl96YCBzbG9wZSBpcyB0aGUgZXN0aW1hdGVkIHNsb3BlIGZvciBgY29udGV4dD09ImZpbmFsImAuIAoKYGBge3IgZWNobyA9IEZ9CmFoXzIgJT4lCiAgZ2dwbG90KGFlcyhkdXJfeiwgRjFfbikpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikrICAgICAgCiAgICAjZ2VvbV9wb2ludChhbHBoYSA9IDAuMDMpKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJzZWdtZW50IiwKICAgICAgICAgICAgIHggPSAwLCAKICAgICAgICAgICAgIHhlbmQgPSAwLAogICAgICAgICAgICAgeSA9IDAsCiAgICAgICAgICAgICB5ZW5kID0gY29lZihhaF9tb2RfaW50ZXJhY3QpWzFdLAogICAgICAgICAgICAgY29sb3IgPSBwYWxbMl0sCiAgICAgICAgICAgICBhcnJvdyA9IGFycm93KCkpKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJwb2ludCIsCiAgICAgICAgICAgICB4ID0gMCwgCiAgICAgICAgICAgICB5ID0gY29lZihhaF9tb2RfaW50ZXJhY3QpWzFdLAogICAgICAgICAgICAgY29sb3IgPSBwYWxbMl0sCiAgICAgICAgICAgICBzaXplID0gMykrICAKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGNvZWYoYWhfbW9kX2ludGVyYWN0KVsxXSwKICAgICAgICAgICAgICAgIHNsb3BlID0gY29lZihhaF9tb2RfaW50ZXJhY3QpWzJdLAogICAgICAgICAgICAgICAgY29sb3IgPSBwYWxbMl0pKwogICAgeWxpbSgwLDIpKwogICAgeGxpbSgtMC41LCAyKSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKClRoZSBlZmZlY3Qgb2YgYGNvbnRleHQ9PSJmaW5hbCJgIGlzIGhvdyBvZmZzZXQgdGhlIGludGVyY2VwdCBmb3IgdGhlIGZpbmFsIGNvbnRleHQgaXMKCgpgYGB7ciBlY2hvID0gRn0KYWhfMiAlPiUKICBnZ3Bsb3QoYWVzKGR1cl96LCBGMV9uKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9IDIpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsgICAgICAKICAgICNnZW9tX3BvaW50KGFscGhhID0gMC4wMykrCiAgICBhbm5vdGF0ZShnZW9tID0gInNlZ21lbnQiLAogICAgICAgICAgICAgeCA9IDAsIAogICAgICAgICAgICAgeGVuZCA9IDAsCiAgICAgICAgICAgICB5ID0gMCwKICAgICAgICAgICAgIHllbmQgPSBjb2VmKGFoX21vZF9pbnRlcmFjdClbMV0sCiAgICAgICAgICAgICBjb2xvciA9IHBhbFsyXSwKICAgICAgICAgICAgIGFycm93ID0gYXJyb3coKSkrCiAgICBhbm5vdGF0ZShnZW9tID0gInBvaW50IiwKICAgICAgICAgICAgIHggPSAwLCAKICAgICAgICAgICAgIHkgPSBjb2VmKGFoX21vZF9pbnRlcmFjdClbMV0sCiAgICAgICAgICAgICBjb2xvciA9IHBhbFsyXSwKICAgICAgICAgICAgIHNpemUgPSAzKSsgIAogICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gY29lZihhaF9tb2RfaW50ZXJhY3QpWzFdLAogICAgICAgICAgICAgICAgc2xvcGUgPSBjb2VmKGFoX21vZF9pbnRlcmFjdClbMl0sCiAgICAgICAgICAgICAgICBjb2xvciA9IHBhbFsyXSkrCiAgICBhbm5vdGF0ZShnZW9tID0gInNlZ21lbnQiLAogICAgICAgICAgICAgeCA9IDAsIAogICAgICAgICAgICAgeGVuZCA9IDAsCiAgICAgICAgICAgICB5ID0gY29lZihhaF9tb2RfaW50ZXJhY3QpWzFdLAogICAgICAgICAgICAgeWVuZCA9IGNvZWYoYWhfbW9kX2ludGVyYWN0KVsxXSArIGNvZWYoYWhfbW9kX2ludGVyYWN0KVszXSwKICAgICAgICAgICAgIGNvbG9yID0gcGFsWzNdLAogICAgICAgICAgICAgYXJyb3cgPSBhcnJvdygpKSsKICAgIGFubm90YXRlKGdlb20gPSAicG9pbnQiLAogICAgICAgICAgICAgeCA9IDAsIAogICAgICAgICAgICAgeSA9IGNvZWYoYWhfbW9kX2ludGVyYWN0KVsxXSArIGNvZWYoYWhfbW9kX2ludGVyYWN0KVszXSwKICAgICAgICAgICAgIGNvbG9yID0gcGFsWzNdLAogICAgICAgICAgICAgc2l6ZSA9IDMpKyAgICAKICAgIHlsaW0oMCwyKSsKICAgIHhsaW0oLTAuNSwgMikrCiAgICB0aGVtZV9taW5pbWFsKCkKYGBgCgpBbmQgdGhlICppbnRlcmFjdGlvbiB0ZXJtKiBpcyBob3cgZGlmZmVyZW50IHRoZSBzbG9wZSBvZiB0aGUgZmluYWwgY29udGV4dCBpcy4gVGhhdCBpcywgdGhlIGRhc2hlZCBibHVlIGxpbmUgc2hvd3MgdGhlIGZpbmFsIGNvbnRleHQgc2xvcGUgaWYgaXQgd2VyZSB0aGUgc2FtZSBhcyB0aGUgaW50ZXJuYWwgY29udGV4dCwgdGhlIHNvbGlkIGJsdWUgbGluZSBpcyB0aGUgZXN0aW1hdGVkIHNsb3BlIG9mIHRoZSBmaW5hbCBjb250ZXh0LCBhbmQgdGhlICoqZGlmZmVyZW5jZSoqIGlzIHdoYXQgaXMgcmVwcmVzZW50ZWQgaW4gdGhlIGludGVyYWN0aW9uIHRlcm0uCgpgYGB7ciBlY2hvID0gRn0KCmFoXzIgJT4lCiAgZ2dwbG90KGFlcyhkdXJfeiwgRjFfbikpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAyKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikrICAgICAgCiAgICAjZ2VvbV9wb2ludChhbHBoYSA9IDAuMDMpKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJzZWdtZW50IiwKICAgICAgICAgICAgIHggPSAwLCAKICAgICAgICAgICAgIHhlbmQgPSAwLAogICAgICAgICAgICAgeSA9IDAsCiAgICAgICAgICAgICB5ZW5kID0gY29lZihhaF9tb2RfaW50ZXJhY3QpWzFdLAogICAgICAgICAgICAgY29sb3IgPSBwYWxbMl0sCiAgICAgICAgICAgICBhcnJvdyA9IGFycm93KCkpKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJwb2ludCIsCiAgICAgICAgICAgICB4ID0gMCwgCiAgICAgICAgICAgICB5ID0gY29lZihhaF9tb2RfaW50ZXJhY3QpWzFdLAogICAgICAgICAgICAgY29sb3IgPSBwYWxbMl0sCiAgICAgICAgICAgICBzaXplID0gMykrICAKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGNvZWYoYWhfbW9kX2ludGVyYWN0KVsxXSwKICAgICAgICAgICAgICAgIHNsb3BlID0gY29lZihhaF9tb2RfaW50ZXJhY3QpWzJdLAogICAgICAgICAgICAgICAgY29sb3IgPSBwYWxbMl0pKwogICAgYW5ub3RhdGUoZ2VvbSA9ICJzZWdtZW50IiwKICAgICAgICAgICAgIHggPSAwLCAKICAgICAgICAgICAgIHhlbmQgPSAwLAogICAgICAgICAgICAgeSA9IGNvZWYoYWhfbW9kX2ludGVyYWN0KVsxXSwKICAgICAgICAgICAgIHllbmQgPSBjb2VmKGFoX21vZF9pbnRlcmFjdClbMV0gKyBjb2VmKGFoX21vZF9pbnRlcmFjdClbM10sCiAgICAgICAgICAgICBjb2xvciA9IHBhbFszXSwKICAgICAgICAgICAgIGFycm93ID0gYXJyb3coKSkrCiAgICBhbm5vdGF0ZShnZW9tID0gInBvaW50IiwKICAgICAgICAgICAgIHggPSAwLCAKICAgICAgICAgICAgIHkgPSBjb2VmKGFoX21vZF9pbnRlcmFjdClbMV0gKyBjb2VmKGFoX21vZF9pbnRlcmFjdClbM10sCiAgICAgICAgICAgICBjb2xvciA9IHBhbFszXSwKICAgICAgICAgICAgIHNpemUgPSAzKSsgCiAgICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSBjb2VmKGFoX21vZF9pbnRlcmFjdClbMV0gKyBjb2VmKGFoX21vZF9pbnRlcmFjdClbM10sCiAgICAgICAgICAgICAgICBzbG9wZSA9IGNvZWYoYWhfbW9kX2ludGVyYWN0KVsyXSwKICAgICAgICAgICAgICAgIGNvbG9yID0gcGFsWzNdLAogICAgICAgICAgICAgICAgbGluZXR5cGUgPSAyKSsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IGNvZWYoYWhfbW9kX2ludGVyYWN0KVsxXSArIGNvZWYoYWhfbW9kX2ludGVyYWN0KVszXSwKICAgICAgICAgICAgICAgIHNsb3BlID0gY29lZihhaF9tb2RfaW50ZXJhY3QpWzJdICsgY29lZihhaF9tb2RfaW50ZXJhY3QpWzRdLAogICAgICAgICAgICAgICAgY29sb3IgPSBwYWxbM10pKyAgICAKICAgIHlsaW0oMCwyKSsKICAgIHhsaW0oLTAuNSwgMikrCiAgICB0aGVtZV9taW5pbWFsKCkKYGBgCgojIFJlYWRpbmcgYW4gZXZlbiBSZWFsZXIgRXhhbXBsZQoKSGVyZSBpcyBhbiBleGFtcGxlIHJlZ3Jlc3Npb24gdGFibGUgZnJvbSBvbmUgb2YgbXkgb3duIHBhcGVycyAoRnJ1ZWh3YWxkIDIwMTYpLiBJIHdhcyBsb29raW5nIGF0IHRoZSBGMSBudWNsZXVzIG9mIC9heS8gdXNpbmcgdGhlIGZvbGxvd2luZyBwcmVkaWN0b3JzOgoKLSBTcGVha2VyJ3MgeWVhciBvZiBiaXJ0aAotIFZvaWNpbmcgb2YgdGhlIGZvbGxvd2luZyBzZWdtZW50Ci0gVGhlIGZyZXF1ZW5jeSBvZiB0aGUgd29yZAoKIVtdKGZpZ3VyZXMvcmVncmVzc2lvbi5wbmcpCgo8ZGl2IGNsYXNzID0gImJveCBicmVhayI+CjxzcGFuIGNsYXNzID0gJ2JpZy1sYWJlbCc+RGlzY3Vzc2lvbjwvc3Bhbj4KCkhvdyBzaG91bGQgd2UgcmVhZCB0aGVzZSByZXN1bHRzPwoKPC9kaXY+CgoKIyBOZXh0IFdlZWsgLSBNaXhlZCBFZmZlY3RzIE1vZGVscyBhbmQgTW9kZWwgU2VsZWN0aW9uCgoK