It’s easy to get pretty far learning R and basic statistical analysis without really encountering the concept of multilevel modeling. (At least, that’s been the case for me.) This is unfortunate, because multilevel modeling can be a useful tool when data generating processes are hierarchical in nature–a situation which can be quite common in social, ecological, and political systems. This tutorial came about as part of a personal resolution to explore some of the Bayesian and multilevel modeling techniques and philosophies discussed in the book Statistical Rethinking by Richard McElreath. (Because, what better way to try to learn something than to commit to writing a tutorial about it?) As someone who is more of a social scientist by nature, I tend to be more interested in gaining intuition around concepts versus “learning all the math”, so this tutorial is written with that framing. I unfortunately can’t claim to understand all of the math–yet. ;-) The goals are as follows:
Multilevel models perform an intriguing and delicate dance, estimating not only how observations vary within each group, but also how groups themselves vary across the context of all of the other groups in the population. By the end of this tutorial, you’ll hopefully start to agree that:
Fixed effects Bayesian model (for comparison)
Before we tackle multilevel models, let’s get used to the data, the syntax, and the Bayesian-ness of it all by running a very basic model. The main question we want to tackle in this model is: Are state employees’ wages systematically related to how many years they have worked for the state? For this analysis, let’s restrict our focus to the 25 most common jobs among state employees, just to keep things easier to visualize, and to make sure we have sufficient data from each job class. Here are the “top 25” jobs, along with the counts occupied by each gender.
top_25_job_classes <- hr_2019 %>%
group_by(JOB_TITLE) %>%
summarise(distinct_employees = length(unique(UNIQUE_ID))) %>%
arrange(desc(distinct_employees)) %>%
top_n(25) %>% select(JOB_TITLE)
top_25_job_classes <- top_25_job_classes$JOB_TITLE
hr_2019 %>%
filter(JOB_TITLE %in% top_25_job_classes) %>%
ggplot(., aes(x=JOB_TITLE, fill=GENDER)) +
geom_bar(position="stack", stat="count") +
theme(axis.text.x = element_text(angle = 90, vjust=0.5, hjust=1))

Let’s filter the dataset to focus on these job classes only, leaving us with 16,715 observations:
hr_2019_top_25_job_classes <- hr_2019 %>%
filter(JOB_TITLE %in% top_25_job_classes)
While we’re at it, let’s also turn job class into both a factor and an index variable. These are two representations of the same information–we’ll just use them slightly differently down the road, depending on which modeling approach we’re using:
hr_2019_top_25_job_classes$JOB_FACTOR <- relevel(as.factor(hr_2019_top_25_job_classes$JOB_TITLE), ref="State Patrol Trooper")
hr_2019_top_25_job_classes$JOB_INDEX <- as.integer(hr_2019_top_25_job_classes$JOB_FACTOR)
JOB_LABELS <- levels(hr_2019_top_25_job_classes$JOB_FACTOR)
For the sake of this particular exploration, we will not standardize or log scale the data, as this helps make coefficients and their units more directly interpretable at each step. This is something that we’d want to explore if we were doing this analysis beyond didactic reasons, but it can add an additional hurdle to interpreting model results that we’d prefer to avoid while we’re learning.
Pick priors
Before running the model, we need to pick three priors. Priors are simply a “starting theory”, informed by information outside of your target dataset, about what range of parameter values seem plausible for your modeling task. Before you get too worried about picking priors, note that these are simply a starting theory–they will ultimately be combined with the empirical evidence from the data itself before your model lands on its final, posterior theory. Don’t feel like you know enough to pick good priors? That’s not a huge problem–you can err on the side of picking “wider” priors and allow the evidence of the data to do more of the heavy lifting. (See: McElreath, p. 82 for a discussion on the thought process of picking these kinds of priors.) For this modeling task, however, a little basic research can give us some pretty decent priors:
Prior for mean hourly wage: For this prior, we can use the Bureau of Labor Statistic’s data on the mean hourly wage for the Twin Cities metro area, which was ~$27 per hour in 2018. We’ll round that to $30 per hour, and set the standard deviation for this prior (chosen somewhat arbitrarily) to $10. (Because it seems likely that the mean hourly wage for an average Minnesota state employee would roughly mirror the overall mean hourly wage for the state across all employment sectors, and wouldn’t be more than +/-$10 in either direction.)
Prior for the standard deviation across hourly wages: For this prior, let’s think about a reasonable range that we believe ~90% of hourly salaries are likely to lie within. On the low end, we would have minimum wage workers, who make approximately ~$10 per hour according to Minnesota law. On the high end, we can think of the types of high-paying jobs that the state tends to employ (ex: lawyers, upper-level personnel managers, IT managers, etc.). Looking at this Business Insider article as an external information source, we can get a ballpark hourly wage for these kinds of roles to help us get a sense of the upper end of the spectrum. It looks like many of these roles are somewhere in the ~$70 per hour range. So, that establishes our 90% range as $10 - 70 per hour, for a total span of $60. The 90% range represents ~3 standard deviations around the mean, so we can divide our range by 3 to yield 1 standard deviation, or $20 as our prior for the standard deviation.
Prior for the average increase in hourly wages for each additional year that the individual has worked for the state: One bit of information we can use to inform this prior is the fact that the vast majority of Minnesota public employees are represented by labor bargaining units. So for this prior, we can do a little digging into the bargaining units. It looks like the MN Association of Professional Employees is the largest single bargaining unit for state employees. In their most recent wage contract, it states that employees are subject to a first- and second-year wage adjustment stipulating that “all salary ranges and rates for classes covered in this Agreement shall be increased by two and one-quarter percent (2.25%)”. Assuming a similar arrangement was in effect for prior contracts, then for an average worker making ~$30 per hour, we could expect an annual hourly wage increase of: 30 * 0.0225 = 0.675. We will use this as our prior for the beta coefficient representing the mean annual hourly compensation rate increase for each additional year worked at the state. It also seems like it would be highly unusual for employees to see an annual absolute change in their hourly compensation rate that is more extreme than 5% in either direction from the expected mean annual increase. We’ll set $1.5 as the standard deviation for this prior, which is the equivalent of assuming that most (95%) of the time, employees will experience a fluctuation in compensation rate that is between -5% and +5%. This is the prior that we know least about, so it’s okay to keep it “wide” for now and let the data persuade the model to adjust as necessary.
hr_2019 %>%
group_by(BARGAINING_UNIT_NAME) %>%
summarise(count_of_distinct_employees = length(unique(UNIQUE_ID))) %>%
arrange(desc(count_of_distinct_employees)) %>%
top_n(5)
We can now visualize each of these priors to get a better sense of how they are “grounding” our model:
par(mfrow=c(1,3))
curve(dnorm(x, 30, 10), from=0, to=80, main="Mean hourly wage")
curve(dcauchy(x, 0, 20), from=0, to=40, main="St dev across hourly wage")
curve(dnorm(x, 0.675, 1.5), from=-3, to=5, main="Avg annual increase in hourly wage")

Run the model with specified priors
Now we can run the Bayesian regression. You will need to have the rethinking library installed and loaded. Basic Bayesian regressions like this one can be fit using the quap() function from that package. The function expects two arguments: 1) an alist object containing the model formula, and 2) the data it should be run against. The model formula is pretty verbose; see the comments below to understand what each line is doing:
model1 <- quap(
alist(
COMP_RATE_STND_HOURLY ~ dnorm( mu , sigma ), # the response variable, which we believe comes from a normal distribution centered around mu with standard deviation sigma
mu <- Intercept + b_YRS_SINCE_ORIGINAL_HIRE*YRS_SINCE_ORIGINAL_HIRE, # the 'meat' of the model--the formula that describes how the explanatory variables come together to influence the response variable
Intercept ~ dnorm(30, 10), # prior for mean hourly wage
b_YRS_SINCE_ORIGINAL_HIRE ~ dnorm(0.675, 1.5), # prior for average increase in hourly wages for each additional year worked for the state
sigma ~ dcauchy(0, 20) # prior for standard deviation across hourly wages (i.e. the remaining error after accounting for years worked for the state)
),
data = hr_2019_top_25_job_classes
)
We can use the precis() function to view the model summary:
precis(model1) # view the model summary
plot(precis(model1)) # plot the coefficients and their "credible intervals" (See: McElreath, p. 54 for discussion on "credible interval" terminology)

Run the model with default priors
What if we got lazy about doing our background research and simply decided to use the priors that the rethinking package assigns by default? We can easily give that a try and see how much it affects the modeling results. Here’s a visualization of the default priors–you can see that these are pretty nonsensical. For example, the prior for the mean hourly wage makes it look like we’re we’re just as likely to have employees making negative wages as we are to see positive wages. And the prior for the standard deviation across wages makes it seem highly unusual to see wages that are +/- $4 from the mean in either direction, when we know from our Business Insider research above that the wage range should actually be quite wide between minimum-wage hourly workers to higher-level executives. Will these default priors mess up the model?
par(mfrow=c(1,3))
curve(dnorm(x, 0, 10), from=-15, to=15, main="Mean hourly wage")
curve(dcauchy(x, 0, 2), from=0, to=5, main="St dev across hourly wages")
curve(dnorm(x, 0, 10), from=-15, to=15, main="Avg annual increase in hourly wage")

To find out, we’ll fit the same model, but this time allowing it to pick the default priors instead of our carefully-selected priors above. This time, we’ll also demonstrate the use of the glimmer function, which allows you to specify the model formula using syntax that will seem more familiar to users who are used to the lm and glm packages. This amounts to running the exact same model as above, just using different (default) priors. And surprisingly, when we look at the precis() output, the results of this model–despite the nonsensical priors–are shockingly similar to the first model we ran!
model1_default_priors_params <- glimmer(COMP_RATE_STND_HOURLY ~ YRS_SINCE_ORIGINAL_HIRE, data = hr_2019_top_25_job_classes)
alist(
COMP_RATE_STND_HOURLY ~ dnorm( mu , sigma ),
mu <- Intercept +
b_YRS_SINCE_ORIGINAL_HIRE*YRS_SINCE_ORIGINAL_HIRE,
Intercept ~ dnorm(0,10),
b_YRS_SINCE_ORIGINAL_HIRE ~ dnorm(0,10),
sigma ~ dcauchy(0,2)
)
model1_default_priors <- quap(model1_default_priors_params$f, model1_default_priors_params$d) # pass in two arguments: the function (f) and the data (d) from the parameter list defined by glimmer above
precis(model1_default_priors)
plot(precis(model1_default_priors))

How can this be? We have a lot of data going into the model, so it’s actually the data–and not the priors–that is doing the bulk of the work here. The data itself is overwhelmingly convincing that the intercept (i.e. the mean hourly wage) is somewhere around $25. I also appears that employees’ hourly salaries increase somewhere around 25 cents for every additional year they have worked for the state. And it appears that the standard deviation across wages likely lies somewhere around $9.2.
Run the model with extreme priors
We have seen that, with enough data, our model can still prevail over nonsensical priors. Now, the question remains: can we “trick” the model into behaving badly if we give it really really bad priors? It turns out that wide, flat priors are unlikely to mess up the model very much, as the data can easily persuade these priors in the right direction. To be truly diabolical, we need to give it very narrow priors. Let’s do our best to thwart the model with the following priors:
par(mfrow=c(1,3))
curve(dnorm(x, -30, 1), from=-35, to=0, main="Mean hourly wage")
curve(dcauchy(x, 0, 0.001), from=0, to=1, main="St dev across hourly wages")
curve(dnorm(x, -5, 1), from=-15, to=15, main="Avg annual increase in hourly wage")

We run the model with these extreme priors, and…
model1_extreme_priors <- quap(
alist(
COMP_RATE_STND_HOURLY ~ dnorm( mu , sigma ),
mu <- Intercept + b_YRS_SINCE_ORIGINAL_HIRE*YRS_SINCE_ORIGINAL_HIRE,
Intercept ~ dnorm(-30, 1), # prior for mean hourly wage
b_YRS_SINCE_ORIGINAL_HIRE ~ dnorm(-5, 1), # prior for average increase in hourly wages for each additional year worked for the state
sigma ~ dcauchy(0, 0.001) # prior for standard deviation across hourly wages
),
data = hr_2019_top_25_job_classes
)
precis(model1_extreme_priors)
plot(precis(model1_extreme_priors))

…the model still triumphs! The posterior parameter values are remarkably similar to the first two models, despite having used quite extreme priors this time around. This means that the evidence contained in the data is convincing enough to pull the posterior back to what we believe is closer to its “true” values!
Bonus challenge quest: Try to mess with the model even more by using even more extreme priors. At what point do the priors overwhelm the evidence of the data and manage to skew the model in the wrong direction?
LS0tCnRpdGxlOiAiTU4gUHVibGljIFNhbGFyeSBEYXRhIC0gTXVsdGlsZXZlbCBNb2RlbHMiCnN1YnRpdGxlOiAiUGFydCAxOiBGaXhlZCBlZmZlY3RzIEJheWVzaWFuIG1vZGVsIgphdXRob3I6ICJBbGlzb24gTGluayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3IgbG9hZF9saWJyYXJpZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQoKIyBJbnN0YWxsIHRoZSBgcmV0aGlua2luZ2AgcGFja2FnZToKIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInJtY2VscmVhdGgvcmV0aGlua2luZyIpCmxpYnJhcnkocmV0aGlua2luZykgCmBgYAoKCkl0J3MgZWFzeSB0byBnZXQgcHJldHR5IGZhciBsZWFybmluZyBSIGFuZCBiYXNpYyBzdGF0aXN0aWNhbCBhbmFseXNpcyB3aXRob3V0IHJlYWxseSBlbmNvdW50ZXJpbmcgdGhlIGNvbmNlcHQgb2YgbXVsdGlsZXZlbCBtb2RlbGluZy4gKEF0IGxlYXN0LCB0aGF0J3MgYmVlbiB0aGUgY2FzZSBmb3IgbWUuKSAgVGhpcyBpcyB1bmZvcnR1bmF0ZSwgYmVjYXVzZSAqKm11bHRpbGV2ZWwgbW9kZWxpbmcgY2FuIGJlIGEgdXNlZnVsIHRvb2wgd2hlbiBkYXRhIGdlbmVyYXRpbmcgcHJvY2Vzc2VzIGFyZSBoaWVyYXJjaGljYWwgaW4gbmF0dXJlLS1hIHNpdHVhdGlvbiB3aGljaCBjYW4gYmUgcXVpdGUgY29tbW9uIGluIHNvY2lhbCwgZWNvbG9naWNhbCwgYW5kIHBvbGl0aWNhbCBzeXN0ZW1zKiouICBUaGlzIHR1dG9yaWFsIGNhbWUgYWJvdXQgYXMgcGFydCBvZiBhIHBlcnNvbmFsIHJlc29sdXRpb24gdG8gZXhwbG9yZSBzb21lIG9mIHRoZSBCYXllc2lhbiBhbmQgbXVsdGlsZXZlbCBtb2RlbGluZyB0ZWNobmlxdWVzIGFuZCBwaGlsb3NvcGhpZXMgZGlzY3Vzc2VkIGluIHRoZSBib29rIFtfU3RhdGlzdGljYWwgUmV0aGlua2luZ19dKGh0dHBzOi8vd3d3LnJvdXRsZWRnZS5jb20vU3RhdGlzdGljYWwtUmV0aGlua2luZy1BLUJheWVzaWFuLUNvdXJzZS13aXRoLUV4YW1wbGVzLWluLVItYW5kLVNUQU4vTWNFbHJlYXRoL3AvYm9vay85NzgwMzY3MTM5OTE5KSBieSBSaWNoYXJkIE1jRWxyZWF0aC4gIChCZWNhdXNlLCB3aGF0IGJldHRlciB3YXkgdG8gdHJ5IHRvIGxlYXJuIHNvbWV0aGluZyB0aGFuIHRvIGNvbW1pdCB0byB3cml0aW5nIGEgdHV0b3JpYWwgYWJvdXQgaXQ/KSAgQXMgc29tZW9uZSB3aG8gaXMgbW9yZSBvZiBhIHNvY2lhbCBzY2llbnRpc3QgYnkgbmF0dXJlLCBJIHRlbmQgdG8gYmUgbW9yZSBpbnRlcmVzdGVkIGluIGdhaW5pbmcgaW50dWl0aW9uIGFyb3VuZCBjb25jZXB0cyB2ZXJzdXMgImxlYXJuaW5nIGFsbCB0aGUgbWF0aCIsIHNvIHRoaXMgdHV0b3JpYWwgaXMgd3JpdHRlbiB3aXRoIHRoYXQgZnJhbWluZy4gIEkgdW5mb3J0dW5hdGVseSBjYW4ndCBjbGFpbSB0byB1bmRlcnN0YW5kIF9hbGxfIG9mIHRoZSBtYXRoLS15ZXQuICA7LSkgIFRoZSBnb2FscyBhcmUgYXMgZm9sbG93czoKCi0gR2FpbiBiYXNpYyBmYW1pbGlhcml0eSB3aXRoIEJheWVzaWFuIG1vZGVsaW5nIHByaW5jaXBsZXMKLSBMZWFybiBhYm91dCBtdWx0aWxldmVsIG1vZGVsaW5nIGFuZCB3aHkgaXQgY2FuIGJlIGEgdXNlZnVsIHRvb2wKLSBMb29rIGF0IGhvdyB0aGVzZSBjb25jZXB0cyBjYW4gYmUgYXBwbGllZCB0byBhIFtwdWJsaWMgc2FsYXJpZXMgZGF0YXNldCBvbiBNaW5uZXNvdGEgc3RhdGUgZW1wbG95ZWVzXShodHRwczovL21uLmdvdi9tbWIvdHJhbnNwYXJlbmN5LW1uL3BheXJvbGxkYXRhLmpzcCkuIChZYXkgb3BlbiBkYXRhISkKCkluICoqUGFydCAxKiosIHdlJ2xsIHBlcmZvcm0gc29tZSBtb2RlbGluZyBvbiB0aGUgTWlubmVzb3RhIHB1YmxpYyBlbXBsb3llZXMgc2FsYXJpZXMgZGF0YSB3aXRoaW4gYSBCYXllc2lhbiBmcmFtZXdvcmssIHVzaW5nIHRoZSBzeW50YXggYW5kIGFwcHJvYWNoIGludHJvZHVjZWQgYnkgTWNFbHJlYXRoIGluIGhpcyBib29rIF9TdGF0aXN0aWNhbCBSZXRoaW5raW5nXyAoMm5kIEVkaXRpb24pLiAgVGhpcyBzeW50YXggaXMgcXVpdGUgZGlmZmVyZW50IGZyb20gdGhlIHJlZ3Jlc3Npb24gZm9ybXVsYXMgeW91J3JlIHByb2JhYmx5IHVzZWQgdG8gdXNpbmcgaW4gUiwgc28gaXQncyB3b3J0aCB0YWtpbmcgc29tZSB0aW1lIHRvIHVuZGVyc3RhbmQgdGhlIHN5bnRheCBhbmQgaG93IHRvIGxldmVyYWdlIGl0IHRvIGdpdmUgeW91ciByZWdyZXNzaW9ucyBzb21lIG9mIHRoYXQgZXhjaXRpbmcgIkJheWVzaWFuIiBmbGF2b3IuCgpJbiAqKlBhcnRzIDIgYW5kIDMqKiwgd2UnbGwgbG9vayBhdCBob3cgdG8gYXBwcm9hY2ggdGhpcyBkYXRhIHRocm91Z2ggYSBtdWx0aWxldmVsIG1vZGVsaW5nIGxlbnMuICBBdCB0aGUgcmlzayBvZiBzb3VuZGluZyBsaWtlIGFuIGluZm9tZXJjaWFsLCBsZXQncyBqdXN0IHNheSB0aGF0IG11bHRpbGV2ZWwgbW9kZWxpbmcgaXMgdGhlIGNvb2xlc3QgdG9vbCB5b3UgcHJvYmFibHkgbmV2ZXIgcmVhbGl6ZWQgeW91IG5lZWRlZC4uLnVudGlsIG5vdyEgIE11bHRpbGV2ZWwgbW9kZWxzIGFyZSwgZmlyc3QgYW5kIGZvcmVtb3N0LCBhbiBlbGVnYW50bHkgaW50dWl0aXZlIHdheSBvZiBtb2RlbGluZyBoaWVyYXJjaGljYWwgb3IgIm5lc3RlZCIgZGF0YSBnZW5lcmF0aW5nIHByb2Nlc3Nlcy4gIE5vdCBvbmx5IHRoYXQsIGJ1dCBtdWx0aWxldmVsIG1vZGVscyBjYW4gYWN0dWFsbHkgYmUgYmV0dGVyIGF0IHBlcmZvcm1pbmcgdGhlIGJpYXMtdmFyaWFuY2UgdHJhZGVvZmYgdGhhdCBpcyB0aGUgY3J1eCBvZiBhIG1vZGVsZXIncyB3b2VzISAgVGhleSBhcmUgZ29vZCBhdCB3ZWlnaGluZyBob3cgbXVjaCBpbmZvcm1hdGlvbiB0byBzaGFyZSBhY3Jvc3MgZGlmZmVyZW50IGdyb3VwcyB3aXRoaW4gYSBtb2RlbCwgd2hpY2ggZ2l2ZXMgdGhlbSBhIGJ1aWx0LWluIHJlZ3VsYXJpemluZyBlZmZlY3QuICBUaGlzIHBoZW5vbWVub24gaXMgY2FsbGVkICoqcG9vbGluZyoqLCB3aGVyZSAiZWFjaCBzZXBhcmF0ZSBbZ3JvdXBdIGluIHRoZSBtb2RlbCBwcm92aWRlcyBpbmZvcm1hdGlvbiB0aGF0IGNhbiBiZSB1c2VkIHRvIGltcHJvdmUgdGhlIGVzdGltYXRlcyBmb3IgYWxsIG90aGVyIFtncm91cHNdIiAoTWNFbHJhdGgsIHAuIDQwNSkuICBBcyB3ZSBnbyBhbG9uZywgd2UnbGwgZXhwbG9yZSB0d28gZGlmZmVyZW50IHBhY2thZ2VzIHRoYXQgZW1wb3dlciBkaWZmZXJlbnQgYXBwcm9hY2hlcyB0byBtdWx0aWxldmVsIG1vZGVsaW5nOiAKCi0gKipsbWVyIChsbWU0L2xtZXJUZXN0KSoqIAogIC0gUHJvczogUG9wdWxhciBtdWx0aWxldmVsIG1vZGVsaW5nIHBhY2thZ2UgZm9yIFIuIEZvcm11bGEgc3ludGF4IHNpbWlsYXIgdG8gYGxtYC9gZ2xtYCBmdW5jdGlvbnMuIAogIC0gQ29uczogTm90IEJheWVzaWFuCi0gKipyZXRoaW5raW5nKiogCiAgLSBQcm9zOiBCYXllc2lhbi4gQWxsb3dzIHlvdSB0byBzcGVjaWZ5IHByaW9ycyBmb3IgYWxsIHRoZSB0aGluZ3MuCiAgLSBDb25zOiBDYW4gYmUgaGFyZCB0byBpbnN0YWxsLiBUYWtlcyBmb3JldmVyIHRvIGZpdC4KCldoZW4gaWxsdXN0cmF0aW5nIG11bHRpbGV2ZWwgbW9kZWxpbmcgYXBwcm9hY2hlcywgd2UnbGwgYWx3YXlzIHN0YXJ0IHdpdGggYGxtZXJgIG1vZGVscyBmaXJzdCB0byBoZWxwIGdldCBpbnNpZ2h0cyBpbnRvIHRoZSBtdWx0aWxldmVsIG5hdHVyZSBvZiB0aGUgZGF0YS4gIGBsbWVyYCBpcyBiZXR0ZXIgZm9yIGdldHRpbmcgb3VyIGZlZXQgd2V0LCBiZWNhdXNlIHRoZSBzeW50YXggaXMgbXVjaCBtb3JlIGludHVpdGl2ZSBmb3IgYSB1c2VyIHdobyBpcyB1c2VkIHRvIFIgbW9kZWwgZm9ybXVsYXMsIGFuZCB0aGUgbW9kZWxzIHRoZW1zZWx2ZXMgYXJlIGZhc3QgdG8gcnVuLiAgV2hlbiB3ZSdyZSBjb21mb3J0YWJsZSB3aXRoIHRoZSBiYXNpYyBjb25jZXB0cywgd2Ugd2lsbCB0YWtlIGEgYnJpZWYgZm9yYXkgaW50byB0aGUgQmF5ZXNpYW4gdmVyc2lvbiBvZiB0aGVzZSBtb2RlbHMsIHdoaWNoIGZlYXR1cmUgbW9yZSBjb21wbGV4IHN5bnRheCBhbmQgYXJlIG1vcmUgY29tcHV0YXRpb25hbGx5IGludGVuc2l2ZSB0byBydW4uCgpNdWx0aWxldmVsIG1vZGVscyBwZXJmb3JtIGFuIGludHJpZ3VpbmcgYW5kIGRlbGljYXRlIGRhbmNlLCBlc3RpbWF0aW5nIG5vdCBvbmx5IGhvdyBvYnNlcnZhdGlvbnMgdmFyeSBfd2l0aGluXyBlYWNoIGdyb3VwLCBidXQgYWxzbyBob3cgZ3JvdXBzIHRoZW1zZWx2ZXMgdmFyeSBfYWNyb3NzXyB0aGUgY29udGV4dCBvZiBhbGwgb2YgdGhlIG90aGVyIGdyb3VwcyBpbiB0aGUgcG9wdWxhdGlvbi4gIEJ5IHRoZSBlbmQgb2YgdGhpcyB0dXRvcmlhbCwgeW91J2xsIGhvcGVmdWxseSBzdGFydCB0byBhZ3JlZSB0aGF0OgoKPiBXaGVuIGl0IGNvbWVzIHRvIHJlZ3Jlc3Npb24sIG11bHRpbGV2ZWwgcmVncmVzc2lvbiBkZXNlcnZlcyB0byBiZSB0aGUgZGVmYXVsdCBhcHByb2FjaC4gVGhlcmUgYXJlIGNlcnRhaW5seSBjb250ZXh0cyBpbiB3aGljaCBpdCB3b3VsZCBiZSBiZXR0ZXIgdG8gdXNlIGFuIG9sZC1mYXNoaW9uZWQgc2luZ2xlLWxldmVsIG1vZGVsLiBCdXQgdGhlIGNvbnRleHRzIGluIHdoaWNoIG11bHRpbGV2ZWwgbW9kZWxzIGFyZSBzdXBlcmlvciBhcmUgbXVjaCBtb3JlIG51bWVyb3VzLiBJdCBpcyBiZXR0ZXIgdG8gYmVnaW4gdG8gYnVpbGQgYSBtdWx0aWxldmVsIGFuYWx5c2lzLCBhbmQgdGhlbiByZWFsaXplIGl0J3MgdW5uZWNlc3NhcnksIHRoYW4gdG8gb3Zlcmxvb2sgaXQuIH4gTWNFbHJlYXRoLCBwLiA0MDAKCgoqKioKCiMjIEZpeGVkIGVmZmVjdHMgQmF5ZXNpYW4gbW9kZWwgKGZvciBjb21wYXJpc29uKQoKQmVmb3JlIHdlIHRhY2tsZSBtdWx0aWxldmVsIG1vZGVscywgbGV0J3MgZ2V0IHVzZWQgdG8gdGhlIGRhdGEsIHRoZSBzeW50YXgsIGFuZCB0aGUgQmF5ZXNpYW4tbmVzcyBvZiBpdCBhbGwgYnkgcnVubmluZyBhIHZlcnkgYmFzaWMgbW9kZWwuICBUaGUgbWFpbiBxdWVzdGlvbiB3ZSB3YW50IHRvIHRhY2tsZSBpbiB0aGlzIG1vZGVsIGlzOiAqKkFyZSBzdGF0ZSBlbXBsb3llZXMnIHdhZ2VzIHN5c3RlbWF0aWNhbGx5IHJlbGF0ZWQgdG8gaG93IG1hbnkgeWVhcnMgdGhleSBoYXZlIHdvcmtlZCBmb3IgdGhlIHN0YXRlPyoqICBGb3IgdGhpcyBhbmFseXNpcywgbGV0J3MgcmVzdHJpY3Qgb3VyIGZvY3VzIHRvIHRoZSAyNSBtb3N0IGNvbW1vbiBqb2JzIGFtb25nIHN0YXRlIGVtcGxveWVlcywganVzdCB0byBrZWVwIHRoaW5ncyBlYXNpZXIgdG8gdmlzdWFsaXplLCBhbmQgdG8gbWFrZSBzdXJlIHdlIGhhdmUgc3VmZmljaWVudCBkYXRhIGZyb20gZWFjaCBqb2IgY2xhc3MuICBIZXJlIGFyZSB0aGUgInRvcCAyNSIgam9icywgYWxvbmcgd2l0aCB0aGUgY291bnRzIG9jY3VwaWVkIGJ5IGVhY2ggZ2VuZGVyLgoKYGBge3IgdG9wXzI1X2pvYnMsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CnRvcF8yNV9qb2JfY2xhc3NlcyA8LSBocl8yMDE5ICU+JQogIGdyb3VwX2J5KEpPQl9USVRMRSkgJT4lCiAgc3VtbWFyaXNlKGRpc3RpbmN0X2VtcGxveWVlcyA9IGxlbmd0aCh1bmlxdWUoVU5JUVVFX0lEKSkpICU+JQogIGFycmFuZ2UoZGVzYyhkaXN0aW5jdF9lbXBsb3llZXMpKSAlPiUKICB0b3BfbigyNSkgJT4lIHNlbGVjdChKT0JfVElUTEUpCgp0b3BfMjVfam9iX2NsYXNzZXMgPC0gdG9wXzI1X2pvYl9jbGFzc2VzJEpPQl9USVRMRQoKaHJfMjAxOSAlPiUKICBmaWx0ZXIoSk9CX1RJVExFICVpbiUgdG9wXzI1X2pvYl9jbGFzc2VzKSAlPiUKZ2dwbG90KC4sIGFlcyh4PUpPQl9USVRMRSwgZmlsbD1HRU5ERVIpKSArCiAgZ2VvbV9iYXIocG9zaXRpb249InN0YWNrIiwgc3RhdD0iY291bnQiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3Q9MC41LCBoanVzdD0xKSkKYGBgCgpMZXQncyBmaWx0ZXIgdGhlIGRhdGFzZXQgdG8gZm9jdXMgb24gdGhlc2Ugam9iIGNsYXNzZXMgb25seSwgbGVhdmluZyB1cyB3aXRoIDE2LDcxNSBvYnNlcnZhdGlvbnM6CgpgYGB7ciBmaWx0ZXJfdG9wMjVfam9ic30KaHJfMjAxOV90b3BfMjVfam9iX2NsYXNzZXMgPC0gaHJfMjAxOSAlPiUKICBmaWx0ZXIoSk9CX1RJVExFICVpbiUgdG9wXzI1X2pvYl9jbGFzc2VzKQpgYGAKCldoaWxlIHdlJ3JlIGF0IGl0LCBsZXQncyBhbHNvIHR1cm4gam9iIGNsYXNzIGludG8gYm90aCBhIGZhY3RvciBhbmQgYW4gaW5kZXggdmFyaWFibGUuICBUaGVzZSBhcmUgdHdvIHJlcHJlc2VudGF0aW9ucyBvZiB0aGUgc2FtZSBpbmZvcm1hdGlvbi0td2UnbGwganVzdCB1c2UgdGhlbSBzbGlnaHRseSBkaWZmZXJlbnRseSBkb3duIHRoZSByb2FkLCBkZXBlbmRpbmcgb24gd2hpY2ggbW9kZWxpbmcgYXBwcm9hY2ggd2UncmUgdXNpbmc6CgpgYGB7ciB0cmFuc2Zvcm1fam9iX2ZhY3Rvcn0KaHJfMjAxOV90b3BfMjVfam9iX2NsYXNzZXMkSk9CX0ZBQ1RPUiA8LSByZWxldmVsKGFzLmZhY3Rvcihocl8yMDE5X3RvcF8yNV9qb2JfY2xhc3NlcyRKT0JfVElUTEUpLCByZWY9IlN0YXRlIFBhdHJvbCBUcm9vcGVyIikKaHJfMjAxOV90b3BfMjVfam9iX2NsYXNzZXMkSk9CX0lOREVYIDwtIGFzLmludGVnZXIoaHJfMjAxOV90b3BfMjVfam9iX2NsYXNzZXMkSk9CX0ZBQ1RPUikKCkpPQl9MQUJFTFMgPC0gbGV2ZWxzKGhyXzIwMTlfdG9wXzI1X2pvYl9jbGFzc2VzJEpPQl9GQUNUT1IpCmBgYAoKRm9yIHRoZSBzYWtlIG9mIHRoaXMgcGFydGljdWxhciBleHBsb3JhdGlvbiwgd2UgX3dpbGwgbm90XyBzdGFuZGFyZGl6ZSBvciBsb2cgc2NhbGUgdGhlIGRhdGEsIGFzIHRoaXMgaGVscHMgbWFrZSBjb2VmZmljaWVudHMgYW5kIHRoZWlyIHVuaXRzIG1vcmUgZGlyZWN0bHkgaW50ZXJwcmV0YWJsZSBhdCBlYWNoIHN0ZXAuICBUaGlzIGlzIHNvbWV0aGluZyB0aGF0IHdlJ2Qgd2FudCB0byBleHBsb3JlIGlmIHdlIHdlcmUgZG9pbmcgdGhpcyBhbmFseXNpcyBiZXlvbmQgZGlkYWN0aWMgcmVhc29ucywgYnV0IGl0IGNhbiBhZGQgYW4gYWRkaXRpb25hbCBodXJkbGUgdG8gaW50ZXJwcmV0aW5nIG1vZGVsIHJlc3VsdHMgdGhhdCB3ZSdkIHByZWZlciB0byBhdm9pZCB3aGlsZSB3ZSdyZSBsZWFybmluZy4KCgojIyMgUGljayBwcmlvcnMKCkJlZm9yZSBydW5uaW5nIHRoZSBtb2RlbCwgd2UgbmVlZCB0byBwaWNrIHRocmVlICoqcHJpb3JzKiouICBQcmlvcnMgYXJlIHNpbXBseSBhICJzdGFydGluZyB0aGVvcnkiLCBpbmZvcm1lZCBieSBpbmZvcm1hdGlvbiBfb3V0c2lkZV8gb2YgeW91ciB0YXJnZXQgZGF0YXNldCwgYWJvdXQgd2hhdCByYW5nZSBvZiBwYXJhbWV0ZXIgdmFsdWVzIHNlZW0gcGxhdXNpYmxlIGZvciB5b3VyIG1vZGVsaW5nIHRhc2suICBCZWZvcmUgeW91IGdldCB0b28gd29ycmllZCBhYm91dCBwaWNraW5nIHByaW9ycywgbm90ZSB0aGF0IHRoZXNlIGFyZSBzaW1wbHkgYSBfc3RhcnRpbmdfIHRoZW9yeS0tdGhleSB3aWxsIHVsdGltYXRlbHkgYmUgY29tYmluZWQgd2l0aCB0aGUgZW1waXJpY2FsIGV2aWRlbmNlIGZyb20gdGhlIGRhdGEgaXRzZWxmIGJlZm9yZSB5b3VyIG1vZGVsIGxhbmRzIG9uIGl0cyBmaW5hbCwgKipwb3N0ZXJpb3IqKiB0aGVvcnkuICBEb24ndCBmZWVsIGxpa2UgeW91IGtub3cgZW5vdWdoIHRvIHBpY2sgZ29vZCBwcmlvcnM/ICBUaGF0J3Mgbm90IGEgaHVnZSBwcm9ibGVtLS15b3UgY2FuIGVyciBvbiB0aGUgc2lkZSBvZiBwaWNraW5nICJ3aWRlciIgcHJpb3JzIGFuZCBhbGxvdyB0aGUgZXZpZGVuY2Ugb2YgdGhlIGRhdGEgdG8gZG8gbW9yZSBvZiB0aGUgaGVhdnkgbGlmdGluZy4gIChTZWU6IE1jRWxyZWF0aCwgcC4gODIgZm9yIGEgZGlzY3Vzc2lvbiBvbiB0aGUgdGhvdWdodCBwcm9jZXNzIG9mIHBpY2tpbmcgdGhlc2Uga2luZHMgb2YgcHJpb3JzLikgIEZvciB0aGlzIG1vZGVsaW5nIHRhc2ssIGhvd2V2ZXIsIGEgbGl0dGxlIGJhc2ljIHJlc2VhcmNoIGNhbiBnaXZlIHVzIHNvbWUgcHJldHR5IGRlY2VudCBwcmlvcnM6CgoxLiAqKlByaW9yIGZvciBtZWFuIGhvdXJseSB3YWdlOioqIEZvciB0aGlzIHByaW9yLCB3ZSBjYW4gdXNlIHRoZSBbQnVyZWF1IG9mIExhYm9yIFN0YXRpc3RpYydzIGRhdGFdKGh0dHBzOi8vd3d3LmJscy5nb3YvcmVnaW9ucy9taWR3ZXN0L25ld3MtcmVsZWFzZS9vY2N1cGF0aW9uYWxlbXBsb3ltZW50YW5kd2FnZXNfbWlubmVhcG9saXMuaHRtKSBvbiB0aGUgbWVhbiBob3VybHkgd2FnZSBmb3IgdGhlIFR3aW4gQ2l0aWVzIG1ldHJvIGFyZWEsIHdoaWNoIHdhcyB+JDI3IHBlciBob3VyIGluIDIwMTguICBXZSdsbCByb3VuZCB0aGF0IHRvIFwkMzAgcGVyIGhvdXIsIGFuZCBzZXQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBmb3IgdGhpcyBwcmlvciAoY2hvc2VuIHNvbWV3aGF0IGFyYml0cmFyaWx5KSB0byBcJDEwLiAgKEJlY2F1c2UgaXQgc2VlbXMgbGlrZWx5IHRoYXQgdGhlIG1lYW4gaG91cmx5IHdhZ2UgZm9yIGFuIGF2ZXJhZ2UgTWlubmVzb3RhIHN0YXRlIGVtcGxveWVlIHdvdWxkIHJvdWdobHkgbWlycm9yIHRoZSBvdmVyYWxsIG1lYW4gaG91cmx5IHdhZ2UgZm9yIHRoZSBzdGF0ZSBhY3Jvc3MgYWxsIGVtcGxveW1lbnQgc2VjdG9ycywgYW5kIHdvdWxkbid0IGJlIG1vcmUgdGhhbiArLy1cJDEwIGluIGVpdGhlciBkaXJlY3Rpb24uKQoKMi4gKipQcmlvciBmb3IgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBhY3Jvc3MgaG91cmx5IHdhZ2VzOioqIEZvciB0aGlzIHByaW9yLCBsZXQncyB0aGluayBhYm91dCBhIHJlYXNvbmFibGUgcmFuZ2UgdGhhdCB3ZSBiZWxpZXZlIH45MCUgb2YgaG91cmx5IHNhbGFyaWVzIGFyZSBsaWtlbHkgdG8gbGllIHdpdGhpbi4gIE9uIHRoZSBsb3cgZW5kLCB3ZSB3b3VsZCBoYXZlIG1pbmltdW0gd2FnZSB3b3JrZXJzLCB3aG8gbWFrZSBhcHByb3hpbWF0ZWx5IH5cJDEwIHBlciBob3VyIFthY2NvcmRpbmcgdG8gTWlubmVzb3RhIGxhd10oaHR0cHM6Ly93d3cuZGxpLm1uLmdvdi9idXNpbmVzcy9lbXBsb3ltZW50LXByYWN0aWNlcy9taW5pbXVtLXdhZ2UtbWlubmVzb3RhKS4gIE9uIHRoZSBoaWdoIGVuZCwgd2UgY2FuIHRoaW5rIG9mIHRoZSB0eXBlcyBvZiBoaWdoLXBheWluZyBqb2JzIHRoYXQgdGhlIHN0YXRlIHRlbmRzIHRvIGVtcGxveSAoZXg6IGxhd3llcnMsIHVwcGVyLWxldmVsIHBlcnNvbm5lbCBtYW5hZ2VycywgSVQgbWFuYWdlcnMsIGV0Yy4pLiAgTG9va2luZyBhdCBbdGhpcyBCdXNpbmVzcyBJbnNpZGVyIGFydGljbGVdKGh0dHBzOi8vd3d3LmJ1c2luZXNzaW5zaWRlci5jb20vaG91cmx5LXNhbGFyaWVzLXN1cmdlb25zLWxhd3llcnMtMjAxNi05KSBhcyBhbiBleHRlcm5hbCBpbmZvcm1hdGlvbiBzb3VyY2UsIHdlIGNhbiBnZXQgYSBiYWxscGFyayBob3VybHkgd2FnZSBmb3IgdGhlc2Uga2luZHMgb2Ygcm9sZXMgdG8gaGVscCB1cyBnZXQgYSBzZW5zZSBvZiB0aGUgdXBwZXIgZW5kIG9mIHRoZSBzcGVjdHJ1bS4gIEl0IGxvb2tzIGxpa2UgbWFueSBvZiB0aGVzZSByb2xlcyBhcmUgc29tZXdoZXJlIGluIHRoZSB+XCQ3MCBwZXIgaG91ciByYW5nZS4gU28sIHRoYXQgZXN0YWJsaXNoZXMgb3VyIDkwJSByYW5nZSBhcyBcJDEwIC0gNzAgcGVyIGhvdXIsIGZvciBhIHRvdGFsIHNwYW4gb2YgXCQ2MC4gIFRoZSA5MCUgcmFuZ2UgcmVwcmVzZW50cyB+MyBzdGFuZGFyZCBkZXZpYXRpb25zIGFyb3VuZCB0aGUgbWVhbiwgc28gd2UgY2FuIGRpdmlkZSBvdXIgcmFuZ2UgYnkgMyB0byB5aWVsZCAxIHN0YW5kYXJkIGRldmlhdGlvbiwgb3IgJDIwIGFzIG91ciBwcmlvciBmb3IgdGhlIHN0YW5kYXJkIGRldmlhdGlvbi4KCjMuICoqUHJpb3IgZm9yIHRoZSBhdmVyYWdlIGluY3JlYXNlIGluIGhvdXJseSB3YWdlcyBmb3IgZWFjaCBhZGRpdGlvbmFsIHllYXIgdGhhdCB0aGUgaW5kaXZpZHVhbCBoYXMgd29ya2VkIGZvciB0aGUgc3RhdGU6KiogIE9uZSBiaXQgb2YgaW5mb3JtYXRpb24gd2UgY2FuIHVzZSB0byBpbmZvcm0gdGhpcyBwcmlvciBpcyB0aGUgZmFjdCB0aGF0IHRoZSB2YXN0IG1ham9yaXR5IG9mIE1pbm5lc290YSBwdWJsaWMgZW1wbG95ZWVzIGFyZSByZXByZXNlbnRlZCBieSBsYWJvciBiYXJnYWluaW5nIHVuaXRzLiAgU28gZm9yIHRoaXMgcHJpb3IsIHdlIGNhbiBkbyBhIGxpdHRsZSBkaWdnaW5nIGludG8gdGhlIGJhcmdhaW5pbmcgdW5pdHMuICBJdCBsb29rcyBsaWtlIHRoZSBNTiBBc3NvY2lhdGlvbiBvZiBQcm9mZXNzaW9uYWwgRW1wbG95ZWVzIGlzIHRoZSBsYXJnZXN0IHNpbmdsZSBiYXJnYWluaW5nIHVuaXQgZm9yIHN0YXRlIGVtcGxveWVlcy4gIEluIFt0aGVpciBtb3N0IHJlY2VudCB3YWdlIGNvbnRyYWN0XShodHRwczovL21hcGUub3JnL21hcGVzLWNvbnRyYWN0LXdvcmtpbmcvYXJ0aWNsZS0yNC13YWdlcyksIGl0IHN0YXRlcyB0aGF0IGVtcGxveWVlcyBhcmUgc3ViamVjdCB0byBhIGZpcnN0LSBhbmQgc2Vjb25kLXllYXIgd2FnZSBhZGp1c3RtZW50IHN0aXB1bGF0aW5nIHRoYXQgImFsbCBzYWxhcnkgcmFuZ2VzIGFuZCByYXRlcyBmb3IgY2xhc3NlcyBjb3ZlcmVkIGluIHRoaXMgQWdyZWVtZW50IHNoYWxsIGJlIGluY3JlYXNlZCBieSB0d28gYW5kIG9uZS1xdWFydGVyIHBlcmNlbnQgKDIuMjUlKSIuICBBc3N1bWluZyBhIHNpbWlsYXIgYXJyYW5nZW1lbnQgd2FzIGluIGVmZmVjdCBmb3IgcHJpb3IgY29udHJhY3RzLCB0aGVuIGZvciBhbiBhdmVyYWdlIHdvcmtlciBtYWtpbmcgflwkMzAgcGVyIGhvdXIsIHdlIGNvdWxkIGV4cGVjdCBhbiBhbm51YWwgaG91cmx5IHdhZ2UgaW5jcmVhc2Ugb2Y6IGAzMCAqIDAuMDIyNSA9YCBgciAzMCAqIDAuMDIyNWAuICBXZSB3aWxsIHVzZSB0aGlzIGFzIG91ciBwcmlvciBmb3IgdGhlIGJldGEgY29lZmZpY2llbnQgcmVwcmVzZW50aW5nIHRoZSBtZWFuIGFubnVhbCBob3VybHkgY29tcGVuc2F0aW9uIHJhdGUgaW5jcmVhc2UgZm9yIGVhY2ggYWRkaXRpb25hbCB5ZWFyIHdvcmtlZCBhdCB0aGUgc3RhdGUuICBJdCBhbHNvIHNlZW1zIGxpa2UgaXQgd291bGQgYmUgaGlnaGx5IHVudXN1YWwgZm9yIGVtcGxveWVlcyB0byBzZWUgYW4gYW5udWFsIGFic29sdXRlIGNoYW5nZSBpbiB0aGVpciBob3VybHkgY29tcGVuc2F0aW9uIHJhdGUgdGhhdCBpcyBtb3JlIGV4dHJlbWUgdGhhbiA1JSBpbiBlaXRoZXIgZGlyZWN0aW9uIGZyb20gdGhlIGV4cGVjdGVkIG1lYW4gYW5udWFsIGluY3JlYXNlLiAgV2UnbGwgc2V0IFwkMS41IGFzIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIHRoaXMgcHJpb3IsIHdoaWNoIGlzIHRoZSBlcXVpdmFsZW50IG9mIGFzc3VtaW5nIHRoYXQgbW9zdCAoOTUlKSBvZiB0aGUgdGltZSwgZW1wbG95ZWVzIHdpbGwgZXhwZXJpZW5jZSBhIGZsdWN0dWF0aW9uIGluIGNvbXBlbnNhdGlvbiByYXRlIHRoYXQgaXMgYmV0d2VlbiAtNSUgYW5kICs1JS4gIFRoaXMgaXMgdGhlIHByaW9yIHRoYXQgd2Uga25vdyBsZWFzdCBhYm91dCwgc28gaXQncyBva2F5IHRvIGtlZXAgaXQgIndpZGUiIGZvciBub3cgYW5kIGxldCB0aGUgZGF0YSBwZXJzdWFkZSB0aGUgbW9kZWwgdG8gYWRqdXN0IGFzIG5lY2Vzc2FyeS4KCmBgYHtyIHZpZXdfYmFyZ2FpbmluZ191bml0LCBldmFsID0gRkFMU0V9CmhyXzIwMTkgJT4lIAogIGdyb3VwX2J5KEJBUkdBSU5JTkdfVU5JVF9OQU1FKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50X29mX2Rpc3RpbmN0X2VtcGxveWVlcyA9IGxlbmd0aCh1bmlxdWUoVU5JUVVFX0lEKSkpICU+JQogIGFycmFuZ2UoZGVzYyhjb3VudF9vZl9kaXN0aW5jdF9lbXBsb3llZXMpKSAlPiUKICB0b3Bfbig1KQpgYGAKCldlIGNhbiBub3cgdmlzdWFsaXplIGVhY2ggb2YgdGhlc2UgcHJpb3JzIHRvIGdldCBhIGJldHRlciBzZW5zZSBvZiBob3cgdGhleSBhcmUgImdyb3VuZGluZyIgb3VyIG1vZGVsOgoKYGBge3Igdmlld19wcmlvcnMsIHdhcm5pbmdzPUZBTFNFfQpwYXIobWZyb3c9YygxLDMpKQpjdXJ2ZShkbm9ybSh4LCAzMCwgMTApLCBmcm9tPTAsIHRvPTgwLCBtYWluPSJNZWFuIGhvdXJseSB3YWdlIikKY3VydmUoZGNhdWNoeSh4LCAwLCAyMCksIGZyb209MCwgdG89NDAsIG1haW49IlN0IGRldiBhY3Jvc3MgaG91cmx5IHdhZ2UiKQpjdXJ2ZShkbm9ybSh4LCAwLjY3NSwgMS41KSwgZnJvbT0tMywgdG89NSwgbWFpbj0iQXZnIGFubnVhbCBpbmNyZWFzZSBpbiBob3VybHkgd2FnZSIpCmBgYAoKCiMjIyBSdW4gdGhlIG1vZGVsIHdpdGggc3BlY2lmaWVkIHByaW9ycwoKTm93IHdlIGNhbiBydW4gdGhlIEJheWVzaWFuIHJlZ3Jlc3Npb24uICBZb3Ugd2lsbCBuZWVkIHRvIGhhdmUgdGhlIGByZXRoaW5raW5nYCBsaWJyYXJ5IGluc3RhbGxlZCBhbmQgbG9hZGVkLiAgQmFzaWMgQmF5ZXNpYW4gcmVncmVzc2lvbnMgbGlrZSB0aGlzIG9uZSBjYW4gYmUgZml0IHVzaW5nIHRoZSBgcXVhcCgpYCBmdW5jdGlvbiBmcm9tIHRoYXQgcGFja2FnZS4gIFRoZSBmdW5jdGlvbiBleHBlY3RzIHR3byBhcmd1bWVudHM6IDEpIGFuIGBhbGlzdGAgb2JqZWN0IGNvbnRhaW5pbmcgdGhlIG1vZGVsIGZvcm11bGEsIGFuZCAyKSB0aGUgZGF0YSBpdCBzaG91bGQgYmUgcnVuIGFnYWluc3QuICBUaGUgbW9kZWwgZm9ybXVsYSBpcyBwcmV0dHkgdmVyYm9zZTsgc2VlIHRoZSBjb21tZW50cyBiZWxvdyB0byB1bmRlcnN0YW5kIHdoYXQgZWFjaCBsaW5lIGlzIGRvaW5nOgoKYGBge3IgcnVuX2JheWVzX21vZGVsfQptb2RlbDEgPC0gcXVhcCgKICBhbGlzdCgKICAgIENPTVBfUkFURV9TVE5EX0hPVVJMWSB+IGRub3JtKCBtdSAsIHNpZ21hICksICMgdGhlIHJlc3BvbnNlIHZhcmlhYmxlLCB3aGljaCB3ZSBiZWxpZXZlIGNvbWVzIGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uIGNlbnRlcmVkIGFyb3VuZCBtdSB3aXRoIHN0YW5kYXJkIGRldmlhdGlvbiBzaWdtYQogICAgbXUgPC0gSW50ZXJjZXB0ICsgYl9ZUlNfU0lOQ0VfT1JJR0lOQUxfSElSRSpZUlNfU0lOQ0VfT1JJR0lOQUxfSElSRSwgIyB0aGUgJ21lYXQnIG9mIHRoZSBtb2RlbC0tdGhlIGZvcm11bGEgdGhhdCBkZXNjcmliZXMgaG93IHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMgY29tZSB0b2dldGhlciB0byBpbmZsdWVuY2UgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIAogICAgSW50ZXJjZXB0IH4gZG5vcm0oMzAsIDEwKSwgIyBwcmlvciBmb3IgbWVhbiBob3VybHkgd2FnZQogICAgYl9ZUlNfU0lOQ0VfT1JJR0lOQUxfSElSRSB+IGRub3JtKDAuNjc1LCAxLjUpLCAjIHByaW9yIGZvciBhdmVyYWdlIGluY3JlYXNlIGluIGhvdXJseSB3YWdlcyBmb3IgZWFjaCBhZGRpdGlvbmFsIHllYXIgd29ya2VkIGZvciB0aGUgc3RhdGUKICAgIHNpZ21hIH4gZGNhdWNoeSgwLCAyMCkgIyBwcmlvciBmb3Igc3RhbmRhcmQgZGV2aWF0aW9uIGFjcm9zcyBob3VybHkgd2FnZXMgKGkuZS4gdGhlIHJlbWFpbmluZyBlcnJvciBhZnRlciBhY2NvdW50aW5nIGZvciB5ZWFycyB3b3JrZWQgZm9yIHRoZSBzdGF0ZSkKICApLAogIGRhdGEgPSBocl8yMDE5X3RvcF8yNV9qb2JfY2xhc3NlcwopCmBgYAoKV2UgY2FuIHVzZSB0aGUgYHByZWNpcygpYCBmdW5jdGlvbiB0byB2aWV3IHRoZSBtb2RlbCBzdW1tYXJ5OgoKYGBge3J9CnByZWNpcyhtb2RlbDEpICMgdmlldyB0aGUgbW9kZWwgc3VtbWFyeQpwbG90KHByZWNpcyhtb2RlbDEpKSAjIHBsb3QgdGhlIGNvZWZmaWNpZW50cyBhbmQgdGhlaXIgImNyZWRpYmxlIGludGVydmFscyIgKFNlZTogTWNFbHJlYXRoLCBwLiA1NCBmb3IgZGlzY3Vzc2lvbiBvbiAiY3JlZGlibGUgaW50ZXJ2YWwiIHRlcm1pbm9sb2d5KQpgYGAKCgojIyMgUnVuIHRoZSBtb2RlbCB3aXRoIGRlZmF1bHQgcHJpb3JzCgpXaGF0IGlmIHdlIGdvdCBsYXp5IGFib3V0IGRvaW5nIG91ciBiYWNrZ3JvdW5kIHJlc2VhcmNoIGFuZCBzaW1wbHkgZGVjaWRlZCB0byB1c2UgdGhlIHByaW9ycyB0aGF0IHRoZSBgcmV0aGlua2luZ2AgcGFja2FnZSBhc3NpZ25zIGJ5IGRlZmF1bHQ/ICBXZSBjYW4gZWFzaWx5IGdpdmUgdGhhdCBhIHRyeSBhbmQgc2VlIGhvdyBtdWNoIGl0IGFmZmVjdHMgdGhlIG1vZGVsaW5nIHJlc3VsdHMuICBIZXJlJ3MgYSB2aXN1YWxpemF0aW9uIG9mIHRoZSBkZWZhdWx0IHByaW9ycy0teW91IGNhbiBzZWUgdGhhdCB0aGVzZSBhcmUgcHJldHR5IG5vbnNlbnNpY2FsLiAgRm9yIGV4YW1wbGUsIHRoZSBwcmlvciBmb3IgdGhlIG1lYW4gaG91cmx5IHdhZ2UgbWFrZXMgaXQgbG9vayBsaWtlIHdlJ3JlIHdlJ3JlIGp1c3QgYXMgbGlrZWx5IHRvIGhhdmUgZW1wbG95ZWVzIG1ha2luZyBfbmVnYXRpdmVfIHdhZ2VzIGFzIHdlIGFyZSB0byBzZWUgcG9zaXRpdmUgd2FnZXMuICBBbmQgdGhlIHByaW9yIGZvciB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIGFjcm9zcyB3YWdlcyBtYWtlcyBpdCBzZWVtIGhpZ2hseSB1bnVzdWFsIHRvIHNlZSB3YWdlcyB0aGF0IGFyZSArLy0gXCQ0IGZyb20gdGhlIG1lYW4gaW4gZWl0aGVyIGRpcmVjdGlvbiwgd2hlbiB3ZSBrbm93IGZyb20gb3VyIEJ1c2luZXNzIEluc2lkZXIgcmVzZWFyY2ggYWJvdmUgdGhhdCB0aGUgd2FnZSByYW5nZSBzaG91bGQgYWN0dWFsbHkgYmUgcXVpdGUgd2lkZSBiZXR3ZWVuIG1pbmltdW0td2FnZSBob3VybHkgd29ya2VycyB0byBoaWdoZXItbGV2ZWwgZXhlY3V0aXZlcy4gIFdpbGwgdGhlc2UgZGVmYXVsdCBwcmlvcnMgbWVzcyB1cCB0aGUgbW9kZWw/CgpgYGB7ciBzaG93X2RlZmF1bHRfcHJpb3JzLCB3YXJuaW5ncz1GQUxTRX0KcGFyKG1mcm93PWMoMSwzKSkKY3VydmUoZG5vcm0oeCwgMCwgMTApLCBmcm9tPS0xNSwgdG89MTUsIG1haW49Ik1lYW4gaG91cmx5IHdhZ2UiKQpjdXJ2ZShkY2F1Y2h5KHgsIDAsIDIpLCBmcm9tPTAsIHRvPTUsIG1haW49IlN0IGRldiBhY3Jvc3MgaG91cmx5IHdhZ2VzIikKY3VydmUoZG5vcm0oeCwgMCwgMTApLCBmcm9tPS0xNSwgdG89MTUsIG1haW49IkF2ZyBhbm51YWwgaW5jcmVhc2UgaW4gaG91cmx5IHdhZ2UiKQpgYGAKClRvIGZpbmQgb3V0LCB3ZSdsbCBmaXQgdGhlIHNhbWUgbW9kZWwsIGJ1dCB0aGlzIHRpbWUgYWxsb3dpbmcgaXQgdG8gcGljayB0aGUgZGVmYXVsdCBwcmlvcnMgaW5zdGVhZCBvZiBvdXIgY2FyZWZ1bGx5LXNlbGVjdGVkIHByaW9ycyBhYm92ZS4gIFRoaXMgdGltZSwgd2UnbGwgYWxzbyBkZW1vbnN0cmF0ZSB0aGUgdXNlIG9mIHRoZSBgZ2xpbW1lcmAgZnVuY3Rpb24sIHdoaWNoIGFsbG93cyB5b3UgdG8gc3BlY2lmeSB0aGUgbW9kZWwgZm9ybXVsYSB1c2luZyBzeW50YXggdGhhdCB3aWxsIHNlZW0gbW9yZSBmYW1pbGlhciB0byB1c2VycyB3aG8gYXJlIHVzZWQgdG8gdGhlIGBsbWAgYW5kIGBnbG1gIHBhY2thZ2VzLiAgVGhpcyBhbW91bnRzIHRvIHJ1bm5pbmcgdGhlIGV4YWN0IHNhbWUgbW9kZWwgYXMgYWJvdmUsIGp1c3QgdXNpbmcgZGlmZmVyZW50IChkZWZhdWx0KSBwcmlvcnMuICBBbmQgc3VycHJpc2luZ2x5LCB3aGVuIHdlIGxvb2sgYXQgdGhlIGBwcmVjaXMoKWAgb3V0cHV0LCB0aGUgcmVzdWx0cyBvZiB0aGlzIG1vZGVsLS1kZXNwaXRlIHRoZSBub25zZW5zaWNhbCBwcmlvcnMtLWFyZSBzaG9ja2luZ2x5IHNpbWlsYXIgdG8gdGhlIGZpcnN0IG1vZGVsIHdlIHJhbiEKCmBgYHtyIHJ1bl9iYXllc19tb2RlbF9kZWZhdWx0fQptb2RlbDFfZGVmYXVsdF9wcmlvcnNfcGFyYW1zIDwtIGdsaW1tZXIoQ09NUF9SQVRFX1NUTkRfSE9VUkxZIH4gWVJTX1NJTkNFX09SSUdJTkFMX0hJUkUsIGRhdGEgPSBocl8yMDE5X3RvcF8yNV9qb2JfY2xhc3NlcykKCm1vZGVsMV9kZWZhdWx0X3ByaW9ycyA8LSBxdWFwKG1vZGVsMV9kZWZhdWx0X3ByaW9yc19wYXJhbXMkZiwgbW9kZWwxX2RlZmF1bHRfcHJpb3JzX3BhcmFtcyRkKSAjIHBhc3MgaW4gdHdvIGFyZ3VtZW50czogdGhlIGZ1bmN0aW9uIChmKSBhbmQgdGhlIGRhdGEgKGQpIGZyb20gdGhlIHBhcmFtZXRlciBsaXN0IGRlZmluZWQgYnkgZ2xpbW1lciBhYm92ZQpgYGAKCmBgYHtyfQpwcmVjaXMobW9kZWwxX2RlZmF1bHRfcHJpb3JzKQpwbG90KHByZWNpcyhtb2RlbDFfZGVmYXVsdF9wcmlvcnMpKQpgYGAKCkhvdyBjYW4gdGhpcyBiZT8gIFdlIGhhdmUgX2EgbG90XyBvZiBkYXRhIGdvaW5nIGludG8gdGhlIG1vZGVsLCBzbyBpdCdzIGFjdHVhbGx5IHRoZSBkYXRhLS1hbmQgX25vdF8gdGhlIHByaW9ycy0tdGhhdCBpcyBkb2luZyB0aGUgYnVsayBvZiB0aGUgd29yayBoZXJlLiAgVGhlIGRhdGEgaXRzZWxmIGlzIG92ZXJ3aGVsbWluZ2x5IGNvbnZpbmNpbmcgdGhhdCB0aGUgaW50ZXJjZXB0IChpLmUuIHRoZSBtZWFuIGhvdXJseSB3YWdlKSBpcyBzb21ld2hlcmUgYXJvdW5kIFwkMjUuICBJIGFsc28gYXBwZWFycyB0aGF0IGVtcGxveWVlcycgaG91cmx5IHNhbGFyaWVzIGluY3JlYXNlIHNvbWV3aGVyZSBhcm91bmQgMjUgY2VudHMgZm9yIGV2ZXJ5IGFkZGl0aW9uYWwgeWVhciB0aGV5IGhhdmUgd29ya2VkIGZvciB0aGUgc3RhdGUuICBBbmQgaXQgYXBwZWFycyB0aGF0IHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gYWNyb3NzIHdhZ2VzIGxpa2VseSBsaWVzIHNvbWV3aGVyZSBhcm91bmQgXCQ5LjIuCgoKIyMjIFJ1biB0aGUgbW9kZWwgd2l0aCBleHRyZW1lIHByaW9ycwoKV2UgaGF2ZSBzZWVuIHRoYXQsIHdpdGggZW5vdWdoIGRhdGEsIG91ciBtb2RlbCBjYW4gc3RpbGwgcHJldmFpbCBvdmVyIG5vbnNlbnNpY2FsIHByaW9ycy4gIE5vdywgdGhlIHF1ZXN0aW9uIHJlbWFpbnM6IGNhbiB3ZSAidHJpY2siIHRoZSBtb2RlbCBpbnRvIGJlaGF2aW5nIGJhZGx5IGlmIHdlIGdpdmUgaXQgX3JlYWxseSByZWFsbHkgYmFkXyBwcmlvcnM/ICBJdCB0dXJucyBvdXQgdGhhdCB3aWRlLCBmbGF0IHByaW9ycyBhcmUgdW5saWtlbHkgdG8gbWVzcyB1cCB0aGUgbW9kZWwgdmVyeSBtdWNoLCBhcyB0aGUgZGF0YSBjYW4gZWFzaWx5IHBlcnN1YWRlIHRoZXNlIHByaW9ycyBpbiB0aGUgcmlnaHQgZGlyZWN0aW9uLiAgVG8gYmUgX3RydWx5XyBkaWFib2xpY2FsLCB3ZSBuZWVkIHRvIGdpdmUgaXQgdmVyeSBuYXJyb3cgcHJpb3JzLiAgTGV0J3MgZG8gb3VyIGJlc3QgdG8gdGh3YXJ0IHRoZSBtb2RlbCB3aXRoIHRoZSBmb2xsb3dpbmcgcHJpb3JzOgoKYGBge3Igc2hvd19leHRyZW1lX3ByaW9ycywgd2FybmluZ3M9RkFMU0V9CnBhcihtZnJvdz1jKDEsMykpCmN1cnZlKGRub3JtKHgsIC0zMCwgMSksIGZyb209LTM1LCB0bz0wLCBtYWluPSJNZWFuIGhvdXJseSB3YWdlIikKY3VydmUoZGNhdWNoeSh4LCAwLCAwLjAwMSksIGZyb209MCwgdG89MSwgbWFpbj0iU3QgZGV2IGFjcm9zcyBob3VybHkgd2FnZXMiKQpjdXJ2ZShkbm9ybSh4LCAtNSwgMSksIGZyb209LTE1LCB0bz0xNSwgbWFpbj0iQXZnIGFubnVhbCBpbmNyZWFzZSBpbiBob3VybHkgd2FnZSIpCmBgYApXZSBydW4gdGhlIG1vZGVsIHdpdGggdGhlc2UgZXh0cmVtZSBwcmlvcnMsIGFuZC4uLgoKYGBge3IgcnVuX2JheWVzX21vZGVsX2V4dHJlbWV9Cm1vZGVsMV9leHRyZW1lX3ByaW9ycyA8LSBxdWFwKAogIGFsaXN0KAogICAgQ09NUF9SQVRFX1NUTkRfSE9VUkxZIH4gZG5vcm0oIG11ICwgc2lnbWEgKSwKICAgIG11IDwtIEludGVyY2VwdCArIGJfWVJTX1NJTkNFX09SSUdJTkFMX0hJUkUqWVJTX1NJTkNFX09SSUdJTkFMX0hJUkUsCiAgICBJbnRlcmNlcHQgfiBkbm9ybSgtMzAsIDEpLCAjIHByaW9yIGZvciBtZWFuIGhvdXJseSB3YWdlCiAgICBiX1lSU19TSU5DRV9PUklHSU5BTF9ISVJFIH4gZG5vcm0oLTUsIDEpLCAjIHByaW9yIGZvciBhdmVyYWdlIGluY3JlYXNlIGluIGhvdXJseSB3YWdlcyBmb3IgZWFjaCBhZGRpdGlvbmFsIHllYXIgd29ya2VkIGZvciB0aGUgc3RhdGUKICAgIHNpZ21hIH4gZGNhdWNoeSgwLCAwLjAwMSkgIyBwcmlvciBmb3Igc3RhbmRhcmQgZGV2aWF0aW9uIGFjcm9zcyBob3VybHkgd2FnZXMKICApLAogIGRhdGEgPSBocl8yMDE5X3RvcF8yNV9qb2JfY2xhc3NlcwopCgpwcmVjaXMobW9kZWwxX2V4dHJlbWVfcHJpb3JzKQoKcGxvdChwcmVjaXMobW9kZWwxX2V4dHJlbWVfcHJpb3JzKSkKYGBgCgouLi50aGUgbW9kZWwgc3RpbGwgdHJpdW1waHMhICBUaGUgcG9zdGVyaW9yIHBhcmFtZXRlciB2YWx1ZXMgYXJlIHJlbWFya2FibHkgc2ltaWxhciB0byB0aGUgZmlyc3QgdHdvIG1vZGVscywgZGVzcGl0ZSBoYXZpbmcgdXNlZCBxdWl0ZSBleHRyZW1lIHByaW9ycyB0aGlzIHRpbWUgYXJvdW5kLiAgVGhpcyBtZWFucyB0aGF0IHRoZSBldmlkZW5jZSBjb250YWluZWQgaW4gdGhlIGRhdGEgaXMgY29udmluY2luZyBlbm91Z2ggdG8gcHVsbCB0aGUgcG9zdGVyaW9yIGJhY2sgdG8gd2hhdCB3ZSBiZWxpZXZlIGlzIGNsb3NlciB0byBpdHMgInRydWUiIHZhbHVlcyEKCioqQm9udXMgY2hhbGxlbmdlIHF1ZXN0OioqIFRyeSB0byBtZXNzIHdpdGggdGhlIG1vZGVsIGV2ZW4gbW9yZSBieSB1c2luZyBldmVuIF9tb3JlXyBleHRyZW1lIHByaW9ycy4gIEF0IHdoYXQgcG9pbnQgZG8gdGhlIHByaW9ycyBvdmVyd2hlbG0gdGhlIGV2aWRlbmNlIG9mIHRoZSBkYXRhIGFuZCBtYW5hZ2UgdG8gc2tldyB0aGUgbW9kZWwgaW4gdGhlIHdyb25nIGRpcmVjdGlvbj8KCgojIyBDb21wYXJlIHRoZSBtb2RlbHMKCldlIHdhbnQgdG8gcGF5IHBhcnRpY3VsYXIgYXR0ZW50aW9uIHRvIHR3byB2YWx1ZXMgaGVyZTogCgoxLiBUaGUgKipXQUlDIHZhbHVlKiosIHdoaWNoIGlzIGEgbW9yZSBnZW5lcmFsIHZlcnNpb24gb2YgdGhlIEFJQyBtZXRyaWMsIHdoaWNoIGVzdGltYXRlcyB0aGUgb3V0LW9mLXNhbXBsZSBwcmVkaWNhdGlvbiBlcnJvciBmb3IgYSBtb2RlbC4gIFRoaXMgYWxsb3dzIHVzIHRvIGNvbXBhcmUgYWNyb3NzIG1vZGVscyB0byBhc3Nlc3MgdGhlaXIgZ29vZG5lc3Mgb2YgZml0LiAgQSBsb3dlciBXQUlDIHJlcHJlc2VudHMgYSAiYmV0dGVyIiBtb2RlbC4gCgoyLiBUaGUgKipwV0FJQyB2YWx1ZSoqLCB3aGljaCBpcyBhIG1lYXN1cmUgb2YgdGhlIG51bWJlciBvZiBlZmZlY3RpdmUgcGFyYW1ldGVycyBpbiB0aGUgbW9kZWwuICBUaGVzZSBhcmUgImVmZmVjdGl2ZSIgcGFyYW1ldGVycy0tbm90IGEgbGl0ZXJhbCBjb3VudCBvZiBhbGwgb2YgdGhlIHBhcmFtZXRlcnMuICBGb3IgdGhlc2Ugc2ltcGxlIG1vZGVscywgd2hpY2ggYWxsIGhhdmUgdGhlIHNhbWUgYmFzaWMgc3RydWN0dXJlLCB3ZSBkb24ndCBzZWUgYSBodWdlIGRpZmZlcmVuY2UgaW4gdGhlIHBXQUlDIHZhbHVlcyBhY3Jvc3MgbW9kZWxzLiAgRm9yIG1vcmUgY29tcGxleCBtb2RlbHMsIGZvciBleGFtcGxlIHdoZW4geW91J3JlIGNvbXBhcmluZyB2YXJpb3VzIGRpZmZlcmVudCBtdWx0aWxldmVsIG1vZGVsaW5nIGFyY2hpdGVjdHVyZXMsIHlvdSdsbCBsaWtlbHkgbm90aWNlIGEgYmlnZ2VyIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgcFdBSUMgdmFsdWVzIGZvciBkaWZmZXJlbnQgbW9kZWxpbmcgYXBwcm9hY2hlcy4gIAoKYGBge3J9CmNvbXBhcmUobW9kZWwxLCBtb2RlbDFfZGVmYXVsdF9wcmlvcnMsIG1vZGVsMV9leHRyZW1lX3ByaW9ycykKYGBgCgo=