So far we have mostly considered regression models containing
numerical covariates and ANOVA-type models containing factors. There is
no reason to keep these separate. A linear model can contain both
numerical covariates and factors.
Historically, models containing both were often called
general linear models. Do not confuse this with
generalised linear models, which are a broader class of
models covered later. In this lecture we are still fitting ordinary
linear models with lm().
The central question is:
When we add a factor to a regression, does it change the intercept,
the slope, or both?
We will answer this question first with simple model diagrams and
then with a data set on the falling speed of samara.
General Linear Models as Regressions
A factor is represented in a regression model using indicator
variables. This means that ANOVA models and regression models are not
fundamentally different model classes. They can all be fitted using
least squares, and fitted values and residuals continue to have their
usual meanings.
Adding a factor can allow different groups to have different
intercepts. Adding an interaction between the factor and a numerical
covariate can also allow the groups to have different slopes.
One Factor and One Covariate
Suppose that we have a response variable, y, a numerical
covariate x, and a factor A. We can build models by
asking what the factor is allowed to change:
- Does A matter at all?
- Does A shift the regression up or down, while the slope
remains common?
- Does the relationship with x depend on the level of
A, so that the slopes can differ as well?
The last two questions are the key progression in this lecture. The
factor-only and null models are useful submodels, particularly when
comparing models, but they are not the main conceptual focus here.

A Single Regression Line
The simplest regression ignores the factor:
\[Y_{ij} = \mu + \beta x_{ij} +
\varepsilon_{ij}\]
There is one intercept and one slope for all observations. The factor
A plays no role in the model.
The R formula is Y ~ x.
Parallel Regression Lines
Next, allow the factor to change the intercept, but require the slope
to remain common:
\[Y_{ij} = \mu + \alpha_i + \beta x_{ij} +
\varepsilon_{ij}\]
The slope is the same at every level of A, but the intercept
can depend on the factor level i. Under the treatment
constraint, the reference level has \(\alpha_1=0\).
The R formula is Y ~ A + x.
Geometrically, the lines are parallel. Statistically, the factor
adjusts the expected response after accounting for x, but it
does not change the expected change in Y for a one-unit
increase in x.
Separate Regression Lines
Finally, allow both the intercept and the slope to depend on the
factor level:
\[Y_{ij} = \mu + \alpha_i + \beta_i x_{ij}
+ \varepsilon_{ij}\]
The interaction term allows the slope to depend on the factor level.
Under the treatment constraint, the reference level has \(\alpha_1=0\) and its slope is represented
by the reference slope.
The R formula can be written as Y ~ A + A:x. The more
familiar shorthand is Y ~ A * x, because
A * x
means
A + x + A:x
The interaction A:x means that the effect of x
is allowed to depend on the level of A. Geometrically, the
regression lines no longer need to be parallel.
The Five Common Models
For one factor A and one covariate x, the five
models shown in the figure are:
| Null model |
Y ~ 1 |
Nothing: one common mean |
| Factor only |
Y ~ A |
The intercept can differ by level of A |
| Single line |
Y ~ x |
One common intercept and slope |
| Parallel lines |
Y ~ A + x |
Intercepts can differ; slopes are common |
| Separate lines |
Y ~ A * x |
Intercepts and slopes can differ |
The factor-only and null models are submodels that will be useful
when we compare models. The main model-building progression is:
\[Y \sim x \quad \longrightarrow \quad Y
\sim A + x \quad \longrightarrow \quad Y \sim A * x.\]
This asks, in order: does the factor do nothing, does it change the
intercept, or does it change the slope as well?
Samara
Samara are small winged fruit on maple trees. In autumn these fruit
fall to the ground, spinning as they go. Research on the aerodynamics of
the fruit has applications for helicopter design.

Linear Models for Samara Data
In one study the following variables were measured on individual
samara:
Velocity: speed of fall;
Tree: the tree from which the samara was collected,
with data from three trees; and
Load: disk loading, an aerodynamical quantity based on
each fruit’s size and weight.
We expect fall velocity to depend on disk loading, but we have
sampled samara from three different trees. This gives us two scientific
questions:
- Do the trees have different expected velocities after accounting for
load?
- Does the relationship between load and velocity itself differ among
trees?
These questions map directly onto the parallel-lines model and the
separate-lines model:
Velocity ~ Load + TreeF
Velocity ~ Load * TreeF
The first formula allows the trees to have different intercepts but a
common slope. The second also allows the slopes to differ.
Samara Data: R Code
Download samara.csv
## Samara <- read.csv(file = "samara.csv", header = TRUE)
str(Samara)
'data.frame': 35 obs. of 3 variables:
$ Tree : int 1 1 1 1 1 1 1 1 1 1 ...
$ Load : num 0.239 0.208 0.223 0.224 0.246 0.213 0.198 0.219 0.241 0.21 ...
$ Velocity: num 1.34 1.06 1.14 1.13 1.35 1.23 1.23 1.15 1.25 1.24 ...
Samara |>
mutate(TreeF = factor(Tree)) -> Samara
Tree is stored using numbers, but these numbers identify
trees rather than measure a numerical quantity. They therefore have no
meaningful ordering or spacing. We convert Tree to a factor
before modelling so that R treats it as a categorical variable.
Samara Data: Plot of Data
Samara |>
ggplot(mapping = aes(y = Velocity, x = Load)) + geom_point(mapping = aes(col = TreeF,
pch = TreeF))
Building Models for the Samara Data
We now fit the three models in the main progression.
m1 <- lm(Velocity ~ Load, data = Samara)
m2 <- lm(Velocity ~ Load + TreeF, data = Samara)
m3 <- lm(Velocity ~ Load * TreeF, data = Samara)
The models are:
m1: one regression line, so tree has no effect;
m2: parallel lines, so tree can change the intercept
but not the slope; and
m3: separate lines, so tree can change both the
intercept and the slope.
Fitted Samara Models
Before looking at any coefficient output, compare the fitted lines.
The observations, colours, symbols, axes, and scales are the same in all
three panels. Only the fitted model changes.
Moving from m1 to m2 allows the trees to
move vertically apart. Moving from m2 to m3
also allows their slopes to differ.
Looking at the three panels, predict which terms must appear in each
model and what those terms must change.
Reading the Coefficients
The coefficient structure becomes more complicated only as the fitted
lines become more flexible:
m1: Velocity ~ Load
(Intercept)
Load
m2: Velocity ~ Load + TreeF
(Intercept)
Load
TreeF2
TreeF3
m3: Velocity ~ Load * TreeF
(Intercept)
Load
TreeF2
TreeF3
Load:TreeF2
Load:TreeF3
The Load coefficient is the slope for the reference
tree. The TreeF2 and TreeF3 terms adjust the
intercept for the other two trees, so they move the fitted lines
vertically. The Load:TreeF2 and Load:TreeF3
terms adjust the slopes, so they allow those lines to rotate.
The following table shows only the coefficient part of the three
model summaries. It is a compact way to compare the terms while
retaining the estimates, standard errors, and P-values.
coefficient_table <- bind_rows(broom::tidy(m1) |>
mutate(model = "m1: Load"), broom::tidy(m2) |>
mutate(model = "m2: Load + TreeF"), broom::tidy(m3) |>
mutate(model = "m3: Load * TreeF")) |>
select(model, term, estimate, std.error, p.value)
knitr::kable(coefficient_table, digits = 3, col.names = c("Model", "Term", "Estimate",
"SE", "P-value"), caption = "Coefficient summaries for the three Samara models.")
Coefficient summaries for the three Samara models.
| m1: Load |
(Intercept) |
-0.093 |
0.107 |
0.392 |
| m1: Load |
Load |
5.820 |
0.511 |
0.000 |
| m2: Load + TreeF |
(Intercept) |
0.076 |
0.169 |
0.657 |
| m2: Load + TreeF |
Load |
5.123 |
0.739 |
0.000 |
| m2: Load + TreeF |
TreeF2 |
-0.010 |
0.034 |
0.763 |
| m2: Load + TreeF |
TreeF3 |
-0.059 |
0.046 |
0.213 |
| m3: Load * TreeF |
(Intercept) |
0.541 |
0.263 |
0.049 |
| m3: Load * TreeF |
Load |
3.063 |
1.160 |
0.013 |
| m3: Load * TreeF |
TreeF2 |
-0.841 |
0.336 |
0.018 |
| m3: Load * TreeF |
TreeF3 |
-0.299 |
0.445 |
0.508 |
| m3: Load * TreeF |
Load:TreeF2 |
3.734 |
1.500 |
0.019 |
| m3: Load * TreeF |
Load:TreeF3 |
0.820 |
2.284 |
0.722 |
This is the information about coefficients that appears in
summary(). The full output also includes residual
summaries, the residual standard error, the coefficient of
determination, and the overall F test. We can inspect the full
output for the most flexible model:
summary(m3)
Call:
lm(formula = Velocity ~ Load * TreeF, data = Samara)
Residuals:
Min 1Q Median 3Q Max
-0.120023 -0.049465 -0.001298 0.049938 0.145571
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.5414 0.2632 2.057 0.0488 *
Load 3.0629 1.1599 2.641 0.0132 *
TreeF2 -0.8408 0.3356 -2.505 0.0181 *
TreeF3 -0.2987 0.4454 -0.671 0.5078
Load:TreeF2 3.7343 1.5000 2.490 0.0188 *
Load:TreeF3 0.8205 2.2837 0.359 0.7220
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.07554 on 29 degrees of freedom
Multiple R-squared: 0.8436, Adjusted R-squared: 0.8167
F-statistic: 31.29 on 5 and 29 DF, p-value: 7.656e-11
The coefficient table for m3 now has a direct geometric
interpretation. The intercept and slope describe the reference tree,
TreeF2 and TreeF3 adjust the intercepts, and
Load:TreeF2 and Load:TreeF3 adjust the
slopes.
Two Parameterisations of the Separate-Lines Model
We have decided that we want three separate lines. There is still
more than one way to describe those same lines using coefficients. These
parameterisations describe the same fitted model, but their coefficients
answer different questions.
First, we can obtain a direct intercept and slope for each tree:
direct <- lm(Velocity ~ 0 + TreeF + TreeF:Load, data = Samara)
summary(direct)
Call:
lm(formula = Velocity ~ 0 + TreeF + TreeF:Load, data = Samara)
Residuals:
Min 1Q Median 3Q Max
-0.120023 -0.049465 -0.001298 0.049938 0.145571
Coefficients:
Estimate Std. Error t value Pr(>|t|)
TreeF1 0.5414 0.2632 2.057 0.0488 *
TreeF2 -0.2993 0.2082 -1.437 0.1613
TreeF3 0.2428 0.3593 0.676 0.5047
TreeF1:Load 3.0629 1.1599 2.641 0.0132 *
TreeF2:Load 6.7971 0.9511 7.147 7.26e-08 ***
TreeF3:Load 3.8834 1.9672 1.974 0.0580 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.07554 on 29 degrees of freedom
Multiple R-squared: 0.9963, Adjusted R-squared: 0.9956
F-statistic: 1308 on 6 and 29 DF, p-value: < 2.2e-16
Because 0 removes the common intercept, the coefficients
for TreeF1, TreeF2, and TreeF3
are the intercepts for the three trees. The coefficients for
TreeF1:Load, TreeF2:Load, and
TreeF3:Load are their slopes.
For comparison, the usual treatment-parameterised model uses Tree 1
as the reference:
reference <- lm(Velocity ~ TreeF * Load, data = Samara)
summary(reference)
Call:
lm(formula = Velocity ~ TreeF * Load, data = Samara)
Residuals:
Min 1Q Median 3Q Max
-0.120023 -0.049465 -0.001298 0.049938 0.145571
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.5414 0.2632 2.057 0.0488 *
TreeF2 -0.8408 0.3356 -2.505 0.0181 *
TreeF3 -0.2987 0.4454 -0.671 0.5078
Load 3.0629 1.1599 2.641 0.0132 *
TreeF2:Load 3.7343 1.5000 2.490 0.0188 *
TreeF3:Load 0.8205 2.2837 0.359 0.7220
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.07554 on 29 degrees of freedom
Multiple R-squared: 0.8436, Adjusted R-squared: 0.8167
F-statistic: 31.29 on 5 and 29 DF, p-value: 7.656e-11
Here the Intercept is the intercept for Tree 1, and
Load is its slope. The TreeF2 and
TreeF3 coefficients are adjustments to the Tree 1
intercept, while TreeF2:Load and TreeF3:Load
are adjustments to the Tree 1 slope.
The two coefficient tables look different because the coefficients
represent different hypotheses. For example, the direct parameterisation
can test whether the slope for Tree 2 is zero. The reference
parameterisation can test whether the slope for Tree 2 differs from the
slope for Tree 1. These are different questions, even though the fitted
model is the same.
We can verify that the fitted lines are identical:
all.equal(fitted(direct), fitted(reference))
[1] TRUE
Two parameterisations of the same model have the same fitted values,
residuals, residual sum of squares, and overall fit. Their individual
coefficients and coefficient tests can differ because the parameters
have different meanings.
The separate-lines panel above is therefore the same fitted plot for
direct and reference. The picture and
predictions do not change when we change the parameterisation; only the
coefficient table changes.
Conclusions
Using either parameterisation, the fitted model gives the following
expected velocities:
\[\begin{aligned}
&\mbox{Tree 1}&~~~E[ \mbox{Velocity}] = 0.541 +
3.06 \mbox{Load}\\
&\mbox{Tree 2}&~~~E[ \mbox{Velocity}] = -0.299 +
6.80 \mbox{Load}\\
&\mbox{Tree 3}&~~~E[ \mbox{Velocity}] = 0.242 +
3.88 \mbox{Load}
\end{aligned}\]
The important point is not which parameterisation is used to fit the
model. It is which scientific comparison each coefficient
represents:
- the direct parameterisation gives the intercept and slope for each
tree;
- the reference parameterisation gives Tree 1’s intercept and slope,
followed by differences from Tree 1; and
- both parameterisations produce the same fitted lines.
This is why parameterisation changes the interpretation of individual
coefficients and their hypothesis tests without changing the underlying
model.
LS0tDQp0aXRsZTogIkxlY3R1cmUgMjU6IFRoZSBHZW5lcmFsIExpbmVhciBNb2RlbCINCnN1YnRpdGxlOiAxNjEuMjUxIFJlZ3Jlc3Npb24gTW9kZWxsaW5nDQphdXRob3I6ICJQcmVzZW50ZWQgYnkgTmljayBLbm93bHRvbiA8Ti5Lbm93bHRvbkBtYXNzZXkuYWMubno+IiAgDQpkYXRlOiAiV2VlayA5IG9mIFNlbWVzdGVyIDIsIGByIGx1YnJpZGF0ZTo6eWVhcihsdWJyaWRhdGU6Om5vdygpKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRoZW1lOiB5ZXRpDQogICAgaGlnaGxpZ2h0X3N0eWxlOiBweWdtZW50cw0KICBodG1sX25vdGVib29rOg0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodF9zdHlsZTogcHlnbWVudHMNCiAgaW9zbGlkZXNfcHJlc2VudGF0aW9uOg0KICAgIHdpZGVzY3JlZW46IHRydWUNCiAgICBzbWFsbGVyOiB0cnVlDQogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgc2xpZHlfcHJlc2VudGF0aW9uOiANCiAgICB0aGVtZTogeWV0aQ0KICAgIGhpZ2hsaWdodF9zdHlsZTogcHlnbWVudHMNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KDQoNCg0KPCEtLS0gRGF0YSBpcyBvbg0KaHR0cHM6Ly9yLXJlc291cmNlcy5tYXNzZXkuYWMubnovZGF0YS8xNjEyNTEvDQotLS0+DQoNCmBgYHtyIHNldHVwLCBwdXJsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShrbml0cikNCm9wdHNfY2h1bmskc2V0KGRldj1jKCJwbmciLCAicGRmIikpDQpvcHRzX2NodW5rJHNldChmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD03LCBmaWcucGF0aD0iRmlndXJlcy8iLCBmaWcuYWx0PSJ1bmxhYmVsbGVkIikNCm9wdHNfY2h1bmskc2V0KGNvbW1lbnQ9IiIsIGZpZy5hbGlnbj0iY2VudGVyIiwgdGlkeT1UUlVFKQ0Kb3B0aW9ucyhrbml0ci5rYWJsZS5OQSA9ICcnKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGJyb29tKQ0KYGBgDQoNCg0KPCEtLS0gRG8gbm90IGVkaXQgYW55dGhpbmcgYWJvdmUgdGhpcyBsaW5lLiAtLS0+DQpTbyBmYXIgd2UgaGF2ZSBtb3N0bHkgY29uc2lkZXJlZCByZWdyZXNzaW9uIG1vZGVscyBjb250YWluaW5nIG51bWVyaWNhbCBjb3ZhcmlhdGVzIGFuZCBBTk9WQS10eXBlIG1vZGVscyBjb250YWluaW5nIGZhY3RvcnMuIFRoZXJlIGlzIG5vIHJlYXNvbiB0byBrZWVwIHRoZXNlIHNlcGFyYXRlLiBBIGxpbmVhciBtb2RlbCBjYW4gY29udGFpbiBib3RoIG51bWVyaWNhbCBjb3ZhcmlhdGVzIGFuZCBmYWN0b3JzLgoKSGlzdG9yaWNhbGx5LCBtb2RlbHMgY29udGFpbmluZyBib3RoIHdlcmUgb2Z0ZW4gY2FsbGVkICoqZ2VuZXJhbCBsaW5lYXIgbW9kZWxzKiouIERvIG5vdCBjb25mdXNlIHRoaXMgd2l0aCAqKmdlbmVyYWxpc2VkIGxpbmVhciBtb2RlbHMqKiwgd2hpY2ggYXJlIGEgYnJvYWRlciBjbGFzcyBvZiBtb2RlbHMgY292ZXJlZCBsYXRlci4gSW4gdGhpcyBsZWN0dXJlIHdlIGFyZSBzdGlsbCBmaXR0aW5nIG9yZGluYXJ5IGxpbmVhciBtb2RlbHMgd2l0aCBgbG0oKWAuCgpUaGUgY2VudHJhbCBxdWVzdGlvbiBpczoKCj4gV2hlbiB3ZSBhZGQgYSBmYWN0b3IgdG8gYSByZWdyZXNzaW9uLCBkb2VzIGl0IGNoYW5nZSB0aGUgaW50ZXJjZXB0LCB0aGUgc2xvcGUsIG9yIGJvdGg/CgpXZSB3aWxsIGFuc3dlciB0aGlzIHF1ZXN0aW9uIGZpcnN0IHdpdGggc2ltcGxlIG1vZGVsIGRpYWdyYW1zIGFuZCB0aGVuIHdpdGggYSBkYXRhIHNldCBvbiB0aGUgZmFsbGluZyBzcGVlZCBvZiBzYW1hcmEuCgojIyBHZW5lcmFsIExpbmVhciBNb2RlbHMgYXMgUmVncmVzc2lvbnMKCkEgZmFjdG9yIGlzIHJlcHJlc2VudGVkIGluIGEgcmVncmVzc2lvbiBtb2RlbCB1c2luZyBpbmRpY2F0b3IgdmFyaWFibGVzLiBUaGlzIG1lYW5zIHRoYXQgQU5PVkEgbW9kZWxzIGFuZCByZWdyZXNzaW9uIG1vZGVscyBhcmUgbm90IGZ1bmRhbWVudGFsbHkgZGlmZmVyZW50IG1vZGVsIGNsYXNzZXMuIFRoZXkgY2FuIGFsbCBiZSBmaXR0ZWQgdXNpbmcgbGVhc3Qgc3F1YXJlcywgYW5kIGZpdHRlZCB2YWx1ZXMgYW5kIHJlc2lkdWFscyBjb250aW51ZSB0byBoYXZlIHRoZWlyIHVzdWFsIG1lYW5pbmdzLgoKQWRkaW5nIGEgZmFjdG9yIGNhbiBhbGxvdyBkaWZmZXJlbnQgZ3JvdXBzIHRvIGhhdmUgZGlmZmVyZW50IGludGVyY2VwdHMuIEFkZGluZyBhbiBpbnRlcmFjdGlvbiBiZXR3ZWVuIHRoZSBmYWN0b3IgYW5kIGEgbnVtZXJpY2FsIGNvdmFyaWF0ZSBjYW4gYWxzbyBhbGxvdyB0aGUgZ3JvdXBzIHRvIGhhdmUgZGlmZmVyZW50IHNsb3Blcy4KCiMjIE9uZSBGYWN0b3IgYW5kIE9uZSBDb3ZhcmlhdGUKClN1cHBvc2UgdGhhdCB3ZSBoYXZlIGEgcmVzcG9uc2UgdmFyaWFibGUsICp5KiwgYSBudW1lcmljYWwgY292YXJpYXRlICp4KiwgYW5kIGEgZmFjdG9yICpBKi4gV2UgY2FuIGJ1aWxkIG1vZGVscyBieSBhc2tpbmcgd2hhdCB0aGUgZmFjdG9yIGlzIGFsbG93ZWQgdG8gY2hhbmdlOgoKMS4gRG9lcyAqQSogbWF0dGVyIGF0IGFsbD8KMi4gRG9lcyAqQSogc2hpZnQgdGhlIHJlZ3Jlc3Npb24gdXAgb3IgZG93biwgd2hpbGUgdGhlIHNsb3BlIHJlbWFpbnMgY29tbW9uPwozLiBEb2VzIHRoZSByZWxhdGlvbnNoaXAgd2l0aCAqeCogZGVwZW5kIG9uIHRoZSBsZXZlbCBvZiAqQSosIHNvIHRoYXQgdGhlIHNsb3BlcyBjYW4gZGlmZmVyIGFzIHdlbGw/CgpUaGUgbGFzdCB0d28gcXVlc3Rpb25zIGFyZSB0aGUga2V5IHByb2dyZXNzaW9uIGluIHRoaXMgbGVjdHVyZS4gVGhlIGZhY3Rvci1vbmx5IGFuZCBudWxsIG1vZGVscyBhcmUgdXNlZnVsIHN1Ym1vZGVscywgcGFydGljdWxhcmx5IHdoZW4gY29tcGFyaW5nIG1vZGVscywgYnV0IHRoZXkgYXJlIG5vdCB0aGUgbWFpbiBjb25jZXB0dWFsIGZvY3VzIGhlcmUuCgohW10oLi4vcmVzb3VyY2VzL2dsbS5wbmcpCgojIyBBIFNpbmdsZSBSZWdyZXNzaW9uIExpbmUKClRoZSBzaW1wbGVzdCByZWdyZXNzaW9uIGlnbm9yZXMgdGhlIGZhY3RvcjoKCiQkWV97aWp9ID0gXG11ICsgXGJldGEgeF97aWp9ICsgXHZhcmVwc2lsb25fe2lqfSQkCgpUaGVyZSBpcyBvbmUgaW50ZXJjZXB0IGFuZCBvbmUgc2xvcGUgZm9yIGFsbCBvYnNlcnZhdGlvbnMuIFRoZSBmYWN0b3IgKkEqIHBsYXlzIG5vIHJvbGUgaW4gdGhlIG1vZGVsLgoKVGhlIFIgZm9ybXVsYSBpcyBgWSB+IHhgLgoKIyMgUGFyYWxsZWwgUmVncmVzc2lvbiBMaW5lcwoKTmV4dCwgYWxsb3cgdGhlIGZhY3RvciB0byBjaGFuZ2UgdGhlIGludGVyY2VwdCwgYnV0IHJlcXVpcmUgdGhlIHNsb3BlIHRvIHJlbWFpbiBjb21tb246CgokJFlfe2lqfSA9IFxtdSArIFxhbHBoYV9pICsgXGJldGEgeF97aWp9ICsgXHZhcmVwc2lsb25fe2lqfSQkCgpUaGUgc2xvcGUgaXMgdGhlIHNhbWUgYXQgZXZlcnkgbGV2ZWwgb2YgKkEqLCBidXQgdGhlIGludGVyY2VwdCBjYW4gZGVwZW5kIG9uIHRoZSBmYWN0b3IgbGV2ZWwgKmkqLiBVbmRlciB0aGUgdHJlYXRtZW50IGNvbnN0cmFpbnQsIHRoZSByZWZlcmVuY2UgbGV2ZWwgaGFzICRcYWxwaGFfMT0wJC4KClRoZSBSIGZvcm11bGEgaXMgYFkgfiBBICsgeGAuCgpHZW9tZXRyaWNhbGx5LCB0aGUgbGluZXMgYXJlIHBhcmFsbGVsLiBTdGF0aXN0aWNhbGx5LCB0aGUgZmFjdG9yIGFkanVzdHMgdGhlIGV4cGVjdGVkIHJlc3BvbnNlIGFmdGVyIGFjY291bnRpbmcgZm9yICp4KiwgYnV0IGl0IGRvZXMgbm90IGNoYW5nZSB0aGUgZXhwZWN0ZWQgY2hhbmdlIGluICpZKiBmb3IgYSBvbmUtdW5pdCBpbmNyZWFzZSBpbiAqeCouCgojIyBTZXBhcmF0ZSBSZWdyZXNzaW9uIExpbmVzCgpGaW5hbGx5LCBhbGxvdyBib3RoIHRoZSBpbnRlcmNlcHQgYW5kIHRoZSBzbG9wZSB0byBkZXBlbmQgb24gdGhlIGZhY3RvciBsZXZlbDoKCiQkWV97aWp9ID0gXG11ICsgXGFscGhhX2kgKyBcYmV0YV9pIHhfe2lqfSArIFx2YXJlcHNpbG9uX3tpan0kJAoKVGhlIGludGVyYWN0aW9uIHRlcm0gYWxsb3dzIHRoZSBzbG9wZSB0byBkZXBlbmQgb24gdGhlIGZhY3RvciBsZXZlbC4gVW5kZXIgdGhlIHRyZWF0bWVudCBjb25zdHJhaW50LCB0aGUgcmVmZXJlbmNlIGxldmVsIGhhcyAkXGFscGhhXzE9MCQgYW5kIGl0cyBzbG9wZSBpcyByZXByZXNlbnRlZCBieSB0aGUgcmVmZXJlbmNlIHNsb3BlLgoKVGhlIFIgZm9ybXVsYSBjYW4gYmUgd3JpdHRlbiBhcyBgWSB+IEEgKyBBOnhgLiBUaGUgbW9yZSBmYW1pbGlhciBzaG9ydGhhbmQgaXMgYFkgfiBBICogeGAsIGJlY2F1c2UKCmBgYHIKQSAqIHgKYGBgCgptZWFucwoKYGBgcgpBICsgeCArIEE6eApgYGAKClRoZSBpbnRlcmFjdGlvbiBgQTp4YCBtZWFucyB0aGF0IHRoZSBlZmZlY3Qgb2YgKngqIGlzIGFsbG93ZWQgdG8gZGVwZW5kIG9uIHRoZSBsZXZlbCBvZiAqQSouIEdlb21ldHJpY2FsbHksIHRoZSByZWdyZXNzaW9uIGxpbmVzIG5vIGxvbmdlciBuZWVkIHRvIGJlIHBhcmFsbGVsLgoKIyMgVGhlIEZpdmUgQ29tbW9uIE1vZGVscwoKRm9yIG9uZSBmYWN0b3IgKkEqIGFuZCBvbmUgY292YXJpYXRlICp4KiwgdGhlIGZpdmUgbW9kZWxzIHNob3duIGluIHRoZSBmaWd1cmUgYXJlOgoKfCBNb2RlbCB8IFIgZm9ybXVsYSB8IFdoYXQgaXMgYWxsb3dlZCB0byB2YXJ5PyB8CnwgOi0tLS0gfCA6LS0tLS0tLS0gfCA6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwKfCBOdWxsIG1vZGVsIHwgYFkgfiAxYCB8IE5vdGhpbmc6IG9uZSBjb21tb24gbWVhbiB8CnwgRmFjdG9yIG9ubHkgfCBgWSB+IEFgIHwgVGhlIGludGVyY2VwdCBjYW4gZGlmZmVyIGJ5IGxldmVsIG9mICpBKiB8CnwgU2luZ2xlIGxpbmUgfCBgWSB+IHhgIHwgT25lIGNvbW1vbiBpbnRlcmNlcHQgYW5kIHNsb3BlIHwKfCBQYXJhbGxlbCBsaW5lcyB8IGBZIH4gQSArIHhgIHwgSW50ZXJjZXB0cyBjYW4gZGlmZmVyOyBzbG9wZXMgYXJlIGNvbW1vbiB8CnwgU2VwYXJhdGUgbGluZXMgfCBgWSB+IEEgKiB4YCB8IEludGVyY2VwdHMgYW5kIHNsb3BlcyBjYW4gZGlmZmVyIHwKClRoZSBmYWN0b3Itb25seSBhbmQgbnVsbCBtb2RlbHMgYXJlIHN1Ym1vZGVscyB0aGF0IHdpbGwgYmUgdXNlZnVsIHdoZW4gd2UgY29tcGFyZSBtb2RlbHMuIFRoZSBtYWluIG1vZGVsLWJ1aWxkaW5nIHByb2dyZXNzaW9uIGlzOgoKJCRZIFxzaW0geCBccXVhZCBcbG9uZ3JpZ2h0YXJyb3cgXHF1YWQgWSBcc2ltIEEgKyB4IFxxdWFkIFxsb25ncmlnaHRhcnJvdyBccXVhZCBZIFxzaW0gQSAqIHguJCQKClRoaXMgYXNrcywgaW4gb3JkZXI6IGRvZXMgdGhlIGZhY3RvciBkbyBub3RoaW5nLCBkb2VzIGl0IGNoYW5nZSB0aGUgaW50ZXJjZXB0LCBvciBkb2VzIGl0IGNoYW5nZSB0aGUgc2xvcGUgYXMgd2VsbD8KCiMjIFJlYWRpbmcgTGluZWFyIE1vZGVsIEZvcm11bGFlCgpUaGUgc2FtZSBpZGVhcyBleHRlbmQgdG8gbW9kZWxzIHdpdGggc2V2ZXJhbCBmYWN0b3JzIGFuZCBjb3ZhcmlhdGVzLiBUaGUgZm9ybXVsYSBvcGVyYXRvcnMgaGF2ZSB0aGUgZm9sbG93aW5nIG1lYW5pbmdzOgoKfCBGb3JtdWxhIGNvbXBvbmVudCB8IE1lYW5pbmcgfAp8IDotLS0tLS0tLS0tLS0tLS0tIHwgOi0tLS0tLSB8CnwgYEFgIHwgVGhlIGV4cGVjdGVkIHJlc3BvbnNlIGNhbiBkaWZmZXIgYmV0d2VlbiBsZXZlbHMgb2YgKkEqIHwKfCBgeGAgfCBBIGNvbW1vbiBsaW5lYXIgZWZmZWN0IG9mICp4KiB8CnwgYEE6eGAgfCBUaGUgc2xvcGUgZm9yICp4KiBjYW4gZGVwZW5kIG9uIHRoZSBsZXZlbCBvZiAqQSogfAp8IGBBICogeGAgfCBTaG9ydGhhbmQgZm9yIGBBICsgeCArIEE6eGAgfAp8IGBBICogQmAgfCBTaG9ydGhhbmQgZm9yIGBBICsgQiArIEE6QmAgfAoKRm9yIGV4YW1wbGUsIGNvbnNpZGVyIHRoZSBmb3JtdWxhCgpgYGByClkgfiBBICogQiArIEEgKiB4ICsgegpgYGAKClRoaXMgZXhwYW5kcyB0byBgQSArIEIgKyBBOkIgKyB4ICsgQTp4ICsgemAuIFRoZSBtb2RlbCBpbmNsdWRlczoKCiogbWFpbiBlZmZlY3RzIGZvciB0aGUgZmFjdG9ycyAqQSogYW5kICpCKjsKKiBhbiBpbnRlcmFjdGlvbiBiZXR3ZWVuICpBKiBhbmQgKkIqLCBzbyB0aGUgZWZmZWN0IG9mICpCKiBjYW4gZGVwZW5kIG9uICpBKjsKKiBhIGNvbW1vbiBsaW5lYXIgZWZmZWN0IG9mICp4KjsKKiBhbiBpbnRlcmFjdGlvbiBiZXR3ZWVuICpBKiBhbmQgKngqLCBzbyB0aGUgc2xvcGUgZm9yICp4KiBjYW4gZGVwZW5kIG9uICpBKjsgYW5kCiogYSBjb21tb24gbGluZWFyIGVmZmVjdCBvZiAqeiouCgpVc2luZyB0cmVhdG1lbnQgY29uc3RyYWludHMsIG9uZSB3YXkgdG8gd3JpdGUgdGhlIGNvcnJlc3BvbmRpbmcgbW9kZWwgaXMKCiQkWV97aWprbH0gPSBcbXUgKyBcYWxwaGFfaSArIFxiZXRhX2ogKyAoXGFscGhhXGJldGEpX3tpan0gKyBcZ2FtbWEgeF97aWprbH0gKyAoXGFscGhhXGdhbW1hKV9pIHhfe2lqa2x9ICsgXGRlbHRhIHpfe2lqa2x9ICsgXHZhcmVwc2lsb25fe2lqa2x9LiQkCgpIZXJlICRcZ2FtbWEkIGlzIHRoZSBzbG9wZSBmb3IgdGhlIHJlZmVyZW5jZSBsZXZlbCBvZiAqQSosIHdoaWxlICQoXGFscGhhXGdhbW1hKV9pJCBpcyB0aGUgc2xvcGUgYWRqdXN0bWVudCBmb3IgdGhlIG90aGVyIGxldmVscy4gVGhpcyBpcyB0aGUgc2FtZSBiYXNlbGluZS1wbHVzLWFkanVzdG1lbnQgaW50ZXJwcmV0YXRpb24gdXNlZCBsYXRlciBmb3IgYFZlbG9jaXR5IH4gTG9hZCAqIFRyZWVGYC4KClRoZSBmb3JtdWxhIHRlbGxzIHVzIHdoaWNoIHBhcnRzIG9mIHRoZSBtb2RlbCBjYW4gdmFyeSBiZXR3ZWVuIGdyb3Vwcy4gV2UgZG8gbm90IG5lZWQgYSBuZXcgbW9kZWwgY2xhc3MgZWFjaCB0aW1lIHdlIGFkZCBhIGZhY3RvciBvciBjb3ZhcmlhdGUuCgojIyBTYW1hcmEKClNhbWFyYSBhcmUgc21hbGwgd2luZ2VkIGZydWl0IG9uIG1hcGxlIHRyZWVzLiBJbiBhdXR1bW4gdGhlc2UgZnJ1aXQgZmFsbCB0byB0aGUgZ3JvdW5kLCBzcGlubmluZyBhcyB0aGV5IGdvLiBSZXNlYXJjaCBvbiB0aGUgYWVyb2R5bmFtaWNzIG9mIHRoZSBmcnVpdCBoYXMgYXBwbGljYXRpb25zIGZvciBoZWxpY29wdGVyIGRlc2lnbi4KCiFbXSguLi9yZXNvdXJjZXMvQWNlcl9jaXJjaW5hdHVtXzk0NjguSlBHKXt3aWR0aD04MCV9CgojIyBMaW5lYXIgTW9kZWxzIGZvciBTYW1hcmEgRGF0YQoKSW4gb25lIHN0dWR5IHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzIHdlcmUgbWVhc3VyZWQgb24gaW5kaXZpZHVhbCBzYW1hcmE6CgoxLiBgVmVsb2NpdHlgOiBzcGVlZCBvZiBmYWxsOwoyLiBgVHJlZWA6IHRoZSB0cmVlIGZyb20gd2hpY2ggdGhlIHNhbWFyYSB3YXMgY29sbGVjdGVkLCB3aXRoIGRhdGEgZnJvbSB0aHJlZSB0cmVlczsgYW5kCjMuIGBMb2FkYDogZGlzayBsb2FkaW5nLCBhbiBhZXJvZHluYW1pY2FsIHF1YW50aXR5IGJhc2VkIG9uIGVhY2ggZnJ1aXQncyBzaXplIGFuZCB3ZWlnaHQuCgpXZSBleHBlY3QgZmFsbCB2ZWxvY2l0eSB0byBkZXBlbmQgb24gZGlzayBsb2FkaW5nLCBidXQgd2UgaGF2ZSBzYW1wbGVkIHNhbWFyYSBmcm9tIHRocmVlIGRpZmZlcmVudCB0cmVlcy4gVGhpcyBnaXZlcyB1cyB0d28gc2NpZW50aWZpYyBxdWVzdGlvbnM6CgoxLiBEbyB0aGUgdHJlZXMgaGF2ZSBkaWZmZXJlbnQgZXhwZWN0ZWQgdmVsb2NpdGllcyBhZnRlciBhY2NvdW50aW5nIGZvciBsb2FkPwoyLiBEb2VzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBsb2FkIGFuZCB2ZWxvY2l0eSBpdHNlbGYgZGlmZmVyIGFtb25nIHRyZWVzPwoKVGhlc2UgcXVlc3Rpb25zIG1hcCBkaXJlY3RseSBvbnRvIHRoZSBwYXJhbGxlbC1saW5lcyBtb2RlbCBhbmQgdGhlIHNlcGFyYXRlLWxpbmVzIG1vZGVsOgoKYGBgcgpWZWxvY2l0eSB+IExvYWQgKyBUcmVlRgpWZWxvY2l0eSB+IExvYWQgKiBUcmVlRgpgYGAKClRoZSBmaXJzdCBmb3JtdWxhIGFsbG93cyB0aGUgdHJlZXMgdG8gaGF2ZSBkaWZmZXJlbnQgaW50ZXJjZXB0cyBidXQgYSBjb21tb24gc2xvcGUuIFRoZSBzZWNvbmQgYWxzbyBhbGxvd3MgdGhlIHNsb3BlcyB0byBkaWZmZXIuCgojIyBTYW1hcmEgRGF0YTogUiBDb2RlCgpgciB4ZnVuOjplbWJlZF9maWxlKCIuLi9kYXRhL3NhbWFyYS5jc3YiKWAKCmBgYHtyIGdldFNhbWFyYSwgZWNobz0tMSwgZXZhbD0tMn0KU2FtYXJhIDwtIHJlYWQuY3N2KGZpbGU9Ii4uL2RhdGEvc2FtYXJhLmNzdiIsIGhlYWRlcj1UUlVFKQpTYW1hcmEgPC0gcmVhZC5jc3YoZmlsZT0ic2FtYXJhLmNzdiIsIGhlYWRlcj1UUlVFKQpzdHIoU2FtYXJhKQpTYW1hcmEgfD4gbXV0YXRlKFRyZWVGID0gZmFjdG9yKFRyZWUpKSAtPiBTYW1hcmEKYGBgCgpgVHJlZWAgaXMgc3RvcmVkIHVzaW5nIG51bWJlcnMsIGJ1dCB0aGVzZSBudW1iZXJzIGlkZW50aWZ5IHRyZWVzIHJhdGhlciB0aGFuIG1lYXN1cmUgYSBudW1lcmljYWwgcXVhbnRpdHkuIFRoZXkgdGhlcmVmb3JlIGhhdmUgbm8gbWVhbmluZ2Z1bCBvcmRlcmluZyBvciBzcGFjaW5nLiBXZSBjb252ZXJ0IGBUcmVlYCB0byBhIGZhY3RvciBiZWZvcmUgbW9kZWxsaW5nIHNvIHRoYXQgUiB0cmVhdHMgaXQgYXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZS4KCiMjIFNhbWFyYSBEYXRhOiBQbG90IG9mIERhdGEKCmBgYHtyIFNhbWFyYVBsb3QsIGZpZy5jYXA9IlNjYXR0ZXIgcGxvdCBvZiBkYXRhIHdpdGggZGlmZmVyZW50IGNvbG91cnMgYW5kIHBsb3R0aW5nIHN5bWJvbHMgdXNlZCB0byBkaXN0aW5ndWlzaCBkYXRhIGZyb20gZGlmZmVyZW50IHRyZWVzLiJ9ClNhbWFyYSB8PgogIGdncGxvdChtYXBwaW5nID0gYWVzKHk9VmVsb2NpdHksIHg9TG9hZCkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sPVRyZWVGLCBwY2g9VHJlZUYpKQpgYGAKCiMjIEJ1aWxkaW5nIE1vZGVscyBmb3IgdGhlIFNhbWFyYSBEYXRhCgpXZSBub3cgZml0IHRoZSB0aHJlZSBtb2RlbHMgaW4gdGhlIG1haW4gcHJvZ3Jlc3Npb24uCmBgYHtyIFNhbWFyYU1vZGVsc30KbTEgPC0gbG0oVmVsb2NpdHkgfiBMb2FkLCBkYXRhID0gU2FtYXJhKQptMiA8LSBsbShWZWxvY2l0eSB+IExvYWQgKyBUcmVlRiwgZGF0YSA9IFNhbWFyYSkKbTMgPC0gbG0oVmVsb2NpdHkgfiBMb2FkICogVHJlZUYsIGRhdGEgPSBTYW1hcmEpCmBgYAoKVGhlIG1vZGVscyBhcmU6CgoqIGBtMWA6IG9uZSByZWdyZXNzaW9uIGxpbmUsIHNvIHRyZWUgaGFzIG5vIGVmZmVjdDsKKiBgbTJgOiBwYXJhbGxlbCBsaW5lcywgc28gdHJlZSBjYW4gY2hhbmdlIHRoZSBpbnRlcmNlcHQgYnV0IG5vdCB0aGUgc2xvcGU7IGFuZAoqIGBtM2A6IHNlcGFyYXRlIGxpbmVzLCBzbyB0cmVlIGNhbiBjaGFuZ2UgYm90aCB0aGUgaW50ZXJjZXB0IGFuZCB0aGUgc2xvcGUuCgojIyBGaXR0ZWQgU2FtYXJhIE1vZGVscwoKQmVmb3JlIGxvb2tpbmcgYXQgYW55IGNvZWZmaWNpZW50IG91dHB1dCwgY29tcGFyZSB0aGUgZml0dGVkIGxpbmVzLiBUaGUgb2JzZXJ2YXRpb25zLCBjb2xvdXJzLCBzeW1ib2xzLCBheGVzLCBhbmQgc2NhbGVzIGFyZSB0aGUgc2FtZSBpbiBhbGwgdGhyZWUgcGFuZWxzLiBPbmx5IHRoZSBmaXR0ZWQgbW9kZWwgY2hhbmdlcy4KCmBgYHtyIFNhbWFyYUZpdHRlZE1vZGVscywgZWNobz1GQUxTRSwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTQsIG91dC53aWR0aD0iMTAwJSIsIGZpZy5jYXA9IlRoZSBzYW1lIFNhbWFyYSBvYnNlcnZhdGlvbnMgd2l0aCBmaXR0ZWQgbGluZXMgZnJvbSB0aGUgdGhyZWUgY2FuZGlkYXRlIG1vZGVscy4ifQptb2RlbF9sYWJlbHMgPC0gYygKICBtMSA9ICJtMTogb25lIGxpbmUiLAogIG0yID0gIm0yOiBwYXJhbGxlbCBsaW5lcyIsCiAgbTMgPSAibTM6IHNlcGFyYXRlIGxpbmVzIgopCgpwbG90X2RhdGEgPC0gYmluZF9yb3dzKAogIFNhbWFyYSB8PiBtdXRhdGUobW9kZWwgPSB1bm5hbWUobW9kZWxfbGFiZWxzWyJtMSJdKSksCiAgU2FtYXJhIHw+IG11dGF0ZShtb2RlbCA9IHVubmFtZShtb2RlbF9sYWJlbHNbIm0yIl0pKSwKICBTYW1hcmEgfD4gbXV0YXRlKG1vZGVsID0gdW5uYW1lKG1vZGVsX2xhYmVsc1sibTMiXSkpCikgfD4KICBtdXRhdGUobW9kZWwgPSBmYWN0b3IobW9kZWwsIGxldmVscyA9IHVubmFtZShtb2RlbF9sYWJlbHMpKSkKCmxvYWRfZ3JpZCA8LSB0aWJibGUoCiAgTG9hZCA9IHNlcShtaW4oU2FtYXJhJExvYWQpLCBtYXgoU2FtYXJhJExvYWQpLCBsZW5ndGgub3V0ID0gMTAwKQopCgpwcmVkX20xIDwtIGxvYWRfZ3JpZCB8PgogIG11dGF0ZSgKICAgIFZlbG9jaXR5ID0gcHJlZGljdChtMSwgbmV3ZGF0YSA9IGxvYWRfZ3JpZCksCiAgICBtb2RlbCA9IHVubmFtZShtb2RlbF9sYWJlbHNbIm0xIl0pCiAgKQoKbmV3X20yIDwtIHRpZHlyOjpleHBhbmRfZ3JpZCgKICBMb2FkID0gbG9hZF9ncmlkJExvYWQsCiAgVHJlZUYgPSBsZXZlbHMoU2FtYXJhJFRyZWVGKQopCnByZWRfbTIgPC0gbmV3X20yIHw+CiAgbXV0YXRlKAogICAgVmVsb2NpdHkgPSBwcmVkaWN0KG0yLCBuZXdkYXRhID0gbmV3X20yKSwKICAgIG1vZGVsID0gdW5uYW1lKG1vZGVsX2xhYmVsc1sibTIiXSkKICApCgpuZXdfbTMgPC0gdGlkeXI6OmV4cGFuZF9ncmlkKAogIExvYWQgPSBsb2FkX2dyaWQkTG9hZCwKICBUcmVlRiA9IGxldmVscyhTYW1hcmEkVHJlZUYpCikKcHJlZF9tMyA8LSBuZXdfbTMgfD4KICBtdXRhdGUoCiAgICBWZWxvY2l0eSA9IHByZWRpY3QobTMsIG5ld2RhdGEgPSBuZXdfbTMpLAogICAgbW9kZWwgPSB1bm5hbWUobW9kZWxfbGFiZWxzWyJtMyJdKQogICkKCnNhbWFyYV9tb2RlbF9wbG90IDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KAogICAgZGF0YSA9IHBsb3RfZGF0YSwKICAgIG1hcHBpbmcgPSBhZXMoeCA9IExvYWQsIHkgPSBWZWxvY2l0eSwgY29sb3VyID0gVHJlZUYsIHNoYXBlID0gVHJlZUYpLAogICAgc2l6ZSA9IDIuMiwKICAgIGFscGhhID0gMC44CiAgKSArCiAgZ2VvbV9saW5lKAogICAgZGF0YSA9IHByZWRfbTEsCiAgICBtYXBwaW5nID0gYWVzKHggPSBMb2FkLCB5ID0gVmVsb2NpdHkpLAogICAgY29sb3VyID0gImJsYWNrIiwKICAgIGxpbmV3aWR0aCA9IDEKICApICsKICBnZW9tX2xpbmUoCiAgICBkYXRhID0gcHJlZF9tMiwKICAgIG1hcHBpbmcgPSBhZXMoeCA9IExvYWQsIHkgPSBWZWxvY2l0eSwgY29sb3VyID0gVHJlZUYsIGdyb3VwID0gVHJlZUYpLAogICAgbGluZXdpZHRoID0gMQogICkgKwogIGdlb21fbGluZSgKICAgIGRhdGEgPSBwcmVkX20zLAogICAgbWFwcGluZyA9IGFlcyh4ID0gTG9hZCwgeSA9IFZlbG9jaXR5LCBjb2xvdXIgPSBUcmVlRiwgZ3JvdXAgPSBUcmVlRiksCiAgICBsaW5ld2lkdGggPSAxCiAgKSArCiAgZmFjZXRfd3JhcCh+IG1vZGVsLCBucm93ID0gMSkgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsKICBsYWJzKHggPSAiTG9hZCIsIHkgPSAiVmVsb2NpdHkiLCBjb2xvdXIgPSAiVHJlZSIsIHNoYXBlID0gIlRyZWUiKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKc2FtYXJhX21vZGVsX3Bsb3QKYGBgCgpNb3ZpbmcgZnJvbSBgbTFgIHRvIGBtMmAgYWxsb3dzIHRoZSB0cmVlcyB0byBtb3ZlIHZlcnRpY2FsbHkgYXBhcnQuIE1vdmluZyBmcm9tIGBtMmAgdG8gYG0zYCBhbHNvIGFsbG93cyB0aGVpciBzbG9wZXMgdG8gZGlmZmVyLgoKTG9va2luZyBhdCB0aGUgdGhyZWUgcGFuZWxzLCBwcmVkaWN0IHdoaWNoIHRlcm1zIG11c3QgYXBwZWFyIGluIGVhY2ggbW9kZWwgYW5kIHdoYXQgdGhvc2UgdGVybXMgbXVzdCBjaGFuZ2UuCgojIyBSZWFkaW5nIHRoZSBDb2VmZmljaWVudHMKClRoZSBjb2VmZmljaWVudCBzdHJ1Y3R1cmUgYmVjb21lcyBtb3JlIGNvbXBsaWNhdGVkIG9ubHkgYXMgdGhlIGZpdHRlZCBsaW5lcyBiZWNvbWUgbW9yZSBmbGV4aWJsZToKCmBgYHRleHQKbTE6IFZlbG9jaXR5IH4gTG9hZAoKKEludGVyY2VwdCkKTG9hZApgYGAKCmBgYHRleHQKbTI6IFZlbG9jaXR5IH4gTG9hZCArIFRyZWVGCgooSW50ZXJjZXB0KQpMb2FkClRyZWVGMgpUcmVlRjMKYGBgCgpgYGB0ZXh0Cm0zOiBWZWxvY2l0eSB+IExvYWQgKiBUcmVlRgoKKEludGVyY2VwdCkKTG9hZApUcmVlRjIKVHJlZUYzCkxvYWQ6VHJlZUYyCkxvYWQ6VHJlZUYzCmBgYAoKVGhlIGBMb2FkYCBjb2VmZmljaWVudCBpcyB0aGUgc2xvcGUgZm9yIHRoZSByZWZlcmVuY2UgdHJlZS4gVGhlIGBUcmVlRjJgIGFuZCBgVHJlZUYzYCB0ZXJtcyBhZGp1c3QgdGhlIGludGVyY2VwdCBmb3IgdGhlIG90aGVyIHR3byB0cmVlcywgc28gdGhleSBtb3ZlIHRoZSBmaXR0ZWQgbGluZXMgdmVydGljYWxseS4gVGhlIGBMb2FkOlRyZWVGMmAgYW5kIGBMb2FkOlRyZWVGM2AgdGVybXMgYWRqdXN0IHRoZSBzbG9wZXMsIHNvIHRoZXkgYWxsb3cgdGhvc2UgbGluZXMgdG8gcm90YXRlLgoKVGhlIGZvbGxvd2luZyB0YWJsZSBzaG93cyBvbmx5IHRoZSBjb2VmZmljaWVudCBwYXJ0IG9mIHRoZSB0aHJlZSBtb2RlbCBzdW1tYXJpZXMuIEl0IGlzIGEgY29tcGFjdCB3YXkgdG8gY29tcGFyZSB0aGUgdGVybXMgd2hpbGUgcmV0YWluaW5nIHRoZSBlc3RpbWF0ZXMsIHN0YW5kYXJkIGVycm9ycywgYW5kICpQKi12YWx1ZXMuCgpgYGB7ciBTYW1hcmFDb2VmZmljaWVudHMsIHJlc3VsdHM9J2FzaXMnfQpjb2VmZmljaWVudF90YWJsZSA8LSBiaW5kX3Jvd3MoCiAgYnJvb206OnRpZHkobTEpIHw+IG11dGF0ZShtb2RlbCA9ICJtMTogTG9hZCIpLAogIGJyb29tOjp0aWR5KG0yKSB8PiBtdXRhdGUobW9kZWwgPSAibTI6IExvYWQgKyBUcmVlRiIpLAogIGJyb29tOjp0aWR5KG0zKSB8PiBtdXRhdGUobW9kZWwgPSAibTM6IExvYWQgKiBUcmVlRiIpCikgfD4KICBzZWxlY3QobW9kZWwsIHRlcm0sIGVzdGltYXRlLCBzdGQuZXJyb3IsIHAudmFsdWUpCgprbml0cjo6a2FibGUoCiAgY29lZmZpY2llbnRfdGFibGUsCiAgZGlnaXRzID0gMywKICBjb2wubmFtZXMgPSBjKCJNb2RlbCIsICJUZXJtIiwgIkVzdGltYXRlIiwgIlNFIiwgIlAtdmFsdWUiKSwKICBjYXB0aW9uID0gIkNvZWZmaWNpZW50IHN1bW1hcmllcyBmb3IgdGhlIHRocmVlIFNhbWFyYSBtb2RlbHMuIgopCmBgYAoKVGhpcyBpcyB0aGUgaW5mb3JtYXRpb24gYWJvdXQgY29lZmZpY2llbnRzIHRoYXQgYXBwZWFycyBpbiBgc3VtbWFyeSgpYC4gVGhlIGZ1bGwgb3V0cHV0IGFsc28gaW5jbHVkZXMgcmVzaWR1YWwgc3VtbWFyaWVzLCB0aGUgcmVzaWR1YWwgc3RhbmRhcmQgZXJyb3IsIHRoZSBjb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uLCBhbmQgdGhlIG92ZXJhbGwgKkYqIHRlc3QuIFdlIGNhbiBpbnNwZWN0IHRoZSBmdWxsIG91dHB1dCBmb3IgdGhlIG1vc3QgZmxleGlibGUgbW9kZWw6CgpgYGB7ciBTYW1hcmFNb2RlbFN1bW1hcnl9CnN1bW1hcnkobTMpCmBgYAoKVGhlIGNvZWZmaWNpZW50IHRhYmxlIGZvciBgbTNgIG5vdyBoYXMgYSBkaXJlY3QgZ2VvbWV0cmljIGludGVycHJldGF0aW9uLiBUaGUgaW50ZXJjZXB0IGFuZCBzbG9wZSBkZXNjcmliZSB0aGUgcmVmZXJlbmNlIHRyZWUsIGBUcmVlRjJgIGFuZCBgVHJlZUYzYCBhZGp1c3QgdGhlIGludGVyY2VwdHMsIGFuZCBgTG9hZDpUcmVlRjJgIGFuZCBgTG9hZDpUcmVlRjNgIGFkanVzdCB0aGUgc2xvcGVzLgoKIyMgVHdvIFBhcmFtZXRlcmlzYXRpb25zIG9mIHRoZSBTZXBhcmF0ZS1MaW5lcyBNb2RlbAoKV2UgaGF2ZSBkZWNpZGVkIHRoYXQgd2Ugd2FudCB0aHJlZSBzZXBhcmF0ZSBsaW5lcy4gVGhlcmUgaXMgc3RpbGwgbW9yZSB0aGFuIG9uZSB3YXkgdG8gZGVzY3JpYmUgdGhvc2Ugc2FtZSBsaW5lcyB1c2luZyBjb2VmZmljaWVudHMuIFRoZXNlIHBhcmFtZXRlcmlzYXRpb25zIGRlc2NyaWJlIHRoZSBzYW1lIGZpdHRlZCBtb2RlbCwgYnV0IHRoZWlyIGNvZWZmaWNpZW50cyBhbnN3ZXIgZGlmZmVyZW50IHF1ZXN0aW9ucy4KCkZpcnN0LCB3ZSBjYW4gb2J0YWluIGEgZGlyZWN0IGludGVyY2VwdCBhbmQgc2xvcGUgZm9yIGVhY2ggdHJlZToKCmBgYHtyIFNhbWFyYURpcmVjdH0KZGlyZWN0IDwtIGxtKAogIFZlbG9jaXR5IH4gMCArIFRyZWVGICsgVHJlZUY6TG9hZCwKICBkYXRhID0gU2FtYXJhCikKc3VtbWFyeShkaXJlY3QpCmBgYAoKQmVjYXVzZSBgMGAgcmVtb3ZlcyB0aGUgY29tbW9uIGludGVyY2VwdCwgdGhlIGNvZWZmaWNpZW50cyBmb3IgYFRyZWVGMWAsIGBUcmVlRjJgLCBhbmQgYFRyZWVGM2AgYXJlIHRoZSBpbnRlcmNlcHRzIGZvciB0aGUgdGhyZWUgdHJlZXMuIFRoZSBjb2VmZmljaWVudHMgZm9yIGBUcmVlRjE6TG9hZGAsIGBUcmVlRjI6TG9hZGAsIGFuZCBgVHJlZUYzOkxvYWRgIGFyZSB0aGVpciBzbG9wZXMuCgpGb3IgY29tcGFyaXNvbiwgdGhlIHVzdWFsIHRyZWF0bWVudC1wYXJhbWV0ZXJpc2VkIG1vZGVsIHVzZXMgVHJlZSAxIGFzIHRoZSByZWZlcmVuY2U6CgpgYGB7ciBTYW1hcmFSZWZlcmVuY2V9CnJlZmVyZW5jZSA8LSBsbSgKICBWZWxvY2l0eSB+IFRyZWVGICogTG9hZCwKICBkYXRhID0gU2FtYXJhCikKc3VtbWFyeShyZWZlcmVuY2UpCmBgYAoKSGVyZSB0aGUgYEludGVyY2VwdGAgaXMgdGhlIGludGVyY2VwdCBmb3IgVHJlZSAxLCBhbmQgYExvYWRgIGlzIGl0cyBzbG9wZS4gVGhlIGBUcmVlRjJgIGFuZCBgVHJlZUYzYCBjb2VmZmljaWVudHMgYXJlIGFkanVzdG1lbnRzIHRvIHRoZSBUcmVlIDEgaW50ZXJjZXB0LCB3aGlsZSBgVHJlZUYyOkxvYWRgIGFuZCBgVHJlZUYzOkxvYWRgIGFyZSBhZGp1c3RtZW50cyB0byB0aGUgVHJlZSAxIHNsb3BlLgoKVGhlIHR3byBjb2VmZmljaWVudCB0YWJsZXMgbG9vayBkaWZmZXJlbnQgYmVjYXVzZSB0aGUgY29lZmZpY2llbnRzIHJlcHJlc2VudCBkaWZmZXJlbnQgaHlwb3RoZXNlcy4gRm9yIGV4YW1wbGUsIHRoZSBkaXJlY3QgcGFyYW1ldGVyaXNhdGlvbiBjYW4gdGVzdCB3aGV0aGVyIHRoZSBzbG9wZSBmb3IgVHJlZSAyIGlzIHplcm8uIFRoZSByZWZlcmVuY2UgcGFyYW1ldGVyaXNhdGlvbiBjYW4gdGVzdCB3aGV0aGVyIHRoZSBzbG9wZSBmb3IgVHJlZSAyIGRpZmZlcnMgZnJvbSB0aGUgc2xvcGUgZm9yIFRyZWUgMS4gVGhlc2UgYXJlIGRpZmZlcmVudCBxdWVzdGlvbnMsIGV2ZW4gdGhvdWdoIHRoZSBmaXR0ZWQgbW9kZWwgaXMgdGhlIHNhbWUuCgpXZSBjYW4gdmVyaWZ5IHRoYXQgdGhlIGZpdHRlZCBsaW5lcyBhcmUgaWRlbnRpY2FsOgoKYGBge3IgU2FtYXJhRXF1aXZhbGVudH0KYWxsLmVxdWFsKGZpdHRlZChkaXJlY3QpLCBmaXR0ZWQocmVmZXJlbmNlKSkKYGBgCgpUd28gcGFyYW1ldGVyaXNhdGlvbnMgb2YgdGhlIHNhbWUgbW9kZWwgaGF2ZSB0aGUgc2FtZSBmaXR0ZWQgdmFsdWVzLCByZXNpZHVhbHMsIHJlc2lkdWFsIHN1bSBvZiBzcXVhcmVzLCBhbmQgb3ZlcmFsbCBmaXQuIFRoZWlyIGluZGl2aWR1YWwgY29lZmZpY2llbnRzIGFuZCBjb2VmZmljaWVudCB0ZXN0cyBjYW4gZGlmZmVyIGJlY2F1c2UgdGhlIHBhcmFtZXRlcnMgaGF2ZSBkaWZmZXJlbnQgbWVhbmluZ3MuCgpUaGUgc2VwYXJhdGUtbGluZXMgcGFuZWwgYWJvdmUgaXMgdGhlcmVmb3JlIHRoZSBzYW1lIGZpdHRlZCBwbG90IGZvciBgZGlyZWN0YCBhbmQgYHJlZmVyZW5jZWAuIFRoZSBwaWN0dXJlIGFuZCBwcmVkaWN0aW9ucyBkbyBub3QgY2hhbmdlIHdoZW4gd2UgY2hhbmdlIHRoZSBwYXJhbWV0ZXJpc2F0aW9uOyBvbmx5IHRoZSBjb2VmZmljaWVudCB0YWJsZSBjaGFuZ2VzLgoKIyMgQ29uY2x1c2lvbnMKClVzaW5nIGVpdGhlciBwYXJhbWV0ZXJpc2F0aW9uLCB0aGUgZml0dGVkIG1vZGVsIGdpdmVzIHRoZSBmb2xsb3dpbmcgZXhwZWN0ZWQgdmVsb2NpdGllczoKCiQkXGJlZ2lue2FsaWduZWR9CiAgICAmXG1ib3h7VHJlZSAxfSZ+fn5FWyBcbWJveHtWZWxvY2l0eX1dID0gIDAuNTQxICsgMy4wNiAgXG1ib3h7TG9hZH1cXAogICAgJlxtYm94e1RyZWUgMn0mfn5+RVsgXG1ib3h7VmVsb2NpdHl9XSA9IC0wLjI5OSArIDYuODAgIFxtYm94e0xvYWR9XFwKICAgICZcbWJveHtUcmVlIDN9Jn5+fkVbIFxtYm94e1ZlbG9jaXR5fV0gPSAgMC4yNDIgKyAzLjg4ICBcbWJveHtMb2FkfQpcZW5ke2FsaWduZWR9JCQKClRoZSBpbXBvcnRhbnQgcG9pbnQgaXMgbm90IHdoaWNoIHBhcmFtZXRlcmlzYXRpb24gaXMgdXNlZCB0byBmaXQgdGhlIG1vZGVsLiBJdCBpcyB3aGljaCBzY2llbnRpZmljIGNvbXBhcmlzb24gZWFjaCBjb2VmZmljaWVudCByZXByZXNlbnRzOgoKKiB0aGUgZGlyZWN0IHBhcmFtZXRlcmlzYXRpb24gZ2l2ZXMgdGhlIGludGVyY2VwdCBhbmQgc2xvcGUgZm9yIGVhY2ggdHJlZTsKKiB0aGUgcmVmZXJlbmNlIHBhcmFtZXRlcmlzYXRpb24gZ2l2ZXMgVHJlZSAxJ3MgaW50ZXJjZXB0IGFuZCBzbG9wZSwgZm9sbG93ZWQgYnkgZGlmZmVyZW5jZXMgZnJvbSBUcmVlIDE7IGFuZAoqIGJvdGggcGFyYW1ldGVyaXNhdGlvbnMgcHJvZHVjZSB0aGUgc2FtZSBmaXR0ZWQgbGluZXMuCgpUaGlzIGlzIHdoeSBwYXJhbWV0ZXJpc2F0aW9uIGNoYW5nZXMgdGhlIGludGVycHJldGF0aW9uIG9mIGluZGl2aWR1YWwgY29lZmZpY2llbnRzIGFuZCB0aGVpciBoeXBvdGhlc2lzIHRlc3RzIHdpdGhvdXQgY2hhbmdpbmcgdGhlIHVuZGVybHlpbmcgbW9kZWwuCg==