Creative Commons License

library(tidyverse)
theme_set(theme_bw())

1 Puromycin data

Data on the velocity of an enzymatic reaction were obtained by Treloar (1974). The number of counts per minute of radioactive product from the reaction was measured as a function of substrate concentration in parts per million (ppm) and from these counts the initial rate (or velocity) of the reaction was calculated (counts/min/min). The experiment was conducted once with the enzyme treated with Puromycin, and once with the enzyme untreated.

Assess if there is an association between the substrate concentration and rate for both the treated and untreated enzymes.

2 Import data

data(Puromycin)

3 Data wrangling

For a clearer interpretation of the model parameters later on, we will make the untreated state enzymes the reference category.

Puromycin <- Puromycin %>%
  mutate(state = fct_relevel(state, c("untreated", "treated")))

3.1 Data Exploration

First, we visualize the association between the concentration and the enzyme rate, for both of the enzyme states.

Puromycin %>%
  ggplot(aes(conc, rate,col=state)) +
  geom_point() +
  stat_smooth(method = "lm") +
  labs(
    x = "Substrate concentration (ppm)",
    y = "Reaction rate (counts/min/min)"
  ) +
  ggtitle("Reaction rates for puromycin-treated enzymes")
## `geom_smooth()` using formula 'y ~ x'

The plot shows that there is a relation between the velocity and the concentration, however, the relation does not seem to be linear.

We will assess the impact of log-transforming the concentration. Because the concentration is measured in ppm we will log\(_{10}\) transform the data.

Puromycin %>%
  ggplot(aes(x = log10(conc), y = rate,col=state)) +
  geom_point() +
  stat_smooth(method = "lm") +
    labs(
      x = "Substrate concentration (log10(ppm))",
      y = "Reaction rate (counts/min/min)"
    ) +
    ggtitle("Reaction rates for puromycin-treated enzymes")
## `geom_smooth()` using formula 'y ~ x'

The relation between the velocity and the log\(_{10}\) transformed concentration seems to be linear.

Puromycin <- Puromycin %>%
  mutate(log10conc = log10(conc))

4 Linear regression

We will fit the following model to the data

\(Y_i = \beta_0 + \beta_c x_c+ \beta_s x_s +\beta_{c:s}x_{c}x_{s} + \epsilon_i\)

with

  • \(Y_i\) the reaction rate,

  • \(\beta_0\) the intercept,

  • \(\beta_{c}\) the main effect for log10 concentration,

  • \(x_c\) the log10 concentration,

  • \(\beta_{p}\) the main effect for treatment ,

  • \(x_s\) a dummy variable for “state” that is 0 if the enzymes that are untreated and 1 if the enzymes are treated with Puromycin,

  • \(\beta_{c:s}\) the interaction effect between concentration and treatment state,

  • \(\epsilon_i\) i.i.d. normally distributed with mean 0 and variance \(\sigma^2\).

Note, that we write the substrate concentration with a small letter because the predictor is not random. The researchers have chosen the substrate concentrations in the design phase and it is thus no random variable.

The model implies two different regression lines

  • no treatment (\(x_s = 0\)) \[ Y_i = \beta_0 + \beta_c x_c + \epsilon \]
  • treatment (x_s = 1)

\[ Y_i = (\beta_0 + \beta_s) + (\beta_c+\beta_{c:s}) x_c + \epsilon \]

So the main effect for treatment has the interpretation as the change in intercept between treated and untreated samples.

The interaction term has the interpretation as the change in slope between treated and untreated samples.

4.1 Intermezzo: Graphical interpretation of the parameters

Simple linear model: 1 slope

This is the same model that we fit in the Chapter 6 exercise:

\[ Y_i = \beta_0 + \beta_{\text{rate}} X_{i, \text{rate}} + \epsilon_i \]

mod_simple <- lm(rate ~ log10conc, data = Puromycin)
mod_simple
## 
## Call:
## lm(formula = rate ~ log10conc, data = Puromycin)
## 
## Coefficients:
## (Intercept)    log10conc  
##      190.09        76.45
ggplot(Puromycin, aes(log10conc, rate)) +
  geom_point(aes(color = state)) +
  geom_abline(
     intercept = coef(mod_simple)[1],
     slope = coef(mod_simple)[2]
  ) +
  scale_color_manual(values = c("darkorchid", "forestgreen")) +
  ggtitle("The simple linear model")

Additive model: 2 parallel slopes

We add an additional term for the state of the reactin (treated or untreated). Note that this variable is categorical.

\[ Y_i = \beta_0 + \beta_{\text{rate}} X_{i, \text{rate}} + \beta_{\text{state}} X_{i, \text{state}} + \epsilon_i \]

mod_add <- lm(rate ~ log10conc + state, data = Puromycin)
mod_add
## 
## Call:
## lm(formula = rate ~ log10conc + state, data = Puromycin)
## 
## Coefficients:
##  (Intercept)     log10conc  statetreated  
##       175.73         74.98         25.18
ggplot(Puromycin, aes(log10conc, rate, col = state)) +
  geom_point() +
  ## Line for the untreated group
  geom_abline(
     intercept = coef(mod_add)[1],
     slope = coef(mod_add)[2],
     col = "darkorchid"
  ) +
  ## Line for the treated group
  geom_abline(
     intercept = coef(mod_add)[1] + coef(mod_add)[3],
     slope = coef(mod_add)[2],
     col = "forestgreen"
  ) +
  scale_color_manual(values = c("darkorchid", "forestgreen")) +
  ggtitle("The additive linear model with parallel slopes")

The interaction model: 2 non-parallel slopes

\[ Y_i = \beta_0 + \beta_{\text{rate}} X_{i, \text{rate}} + \beta_{\text{state}} X_{i, \text{state}} + \beta_{\text{rate:state}} X_{i, \text{rate}} X_{i, \text{state}} + \epsilon_i \]

mod_int <- lm(rate ~ log10conc * state, data = Puromycin)
mod_int
## 
## Call:
## lm(formula = rate ~ log10conc * state, data = Puromycin)
## 
## Coefficients:
##            (Intercept)               log10conc  
##                 164.59                   62.13  
##           statetreated  log10conc:statetreated  
##                  44.61                   23.32
ggplot(Puromycin, aes(log10conc, rate, col = state)) +
  geom_point() +
  ## Line for the untreated group
  geom_abline(
     intercept = coef(mod_int)[1],
     slope = coef(mod_int)[2],
     col = "darkorchid"
  ) +
  ## Line for the treated group
  geom_abline(
     intercept = coef(mod_int)[1] + coef(mod_int)[3],
     slope = coef(mod_int)[2] + coef(mod_int)[4],
     col = "forestgreen"
  ) +
  scale_color_manual(values = c("darkorchid", "forestgreen")) +
  ggtitle("The linear model with interaction: non-parallel slopes")

mod1 <- lm(rate ~ log10conc * state, Puromycin)
summary(mod1)
## 
## Call:
## lm(formula = rate ~ log10conc * state, data = Puromycin)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -17.018  -6.381  -1.005   7.616  13.323 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)             164.588      5.153  31.938  < 2e-16 ***
## log10conc                62.129      5.020  12.375 1.54e-10 ***
## statetreated             44.606      6.811   6.549 2.85e-06 ***
## log10conc:statetreated   23.321      6.763   3.448  0.00269 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 9.151 on 19 degrees of freedom
## Multiple R-squared:  0.968,  Adjusted R-squared:  0.9629 
## F-statistic: 191.3 on 3 and 19 DF,  p-value: 2.267e-14

Before we perform inference we will first assess the assumptions

4.2 Assumptions

  1. Linearity and representative sample

\[E[\hat \beta_j]=\beta_j\]

  1. Normal distribution of the residuals

\[Y_{i} \sim N(\mu_i,\sigma^2)\] \[Y_i \sim N(\beta_0 + \beta_c x_{ci}+ \beta_s x_{si} +\beta_{c:s}x_{ci}x_{si},\sigma^2) \longrightarrow \hat \beta_j \sim N(\beta_j, \sigma^2_{\hat \beta_j})\]

linear combinations of model parameter estimators are also normally distributed, e.g. \[ \longrightarrow \hat \beta_c + \hat \beta_{c:s} \sim N(\beta_c+\beta_{cs}, \sigma^2_{\hat\beta_c+\hat\beta_{c:s}}) \] \[ \longrightarrow L^T\hat \beta \sim N(L^T\beta, \sigma^2_{L^T\hat{\boldsymbol{\beta}}}) \]

  1. Independence and Homoscedasticity

We assume that the experiment was well designed and that the different reactions that were use in the experiment are independent.

\[\sigma^2_{L^T\hat{\boldsymbol{\beta}}} = c_L \sigma^2\]

  • \(\sigma^2?\)

\[\hat \sigma^2 = MSE = \sum\limits_{i=1} ^ n \frac{(Y_i - \hat Y_i)^2}{n-p}\]

\[ SE_{L^T\hat{\boldsymbol{\beta}}} = c_L \hat \sigma^2 \]

  • t-statistic

\[ T = \frac{L\hat{\boldsymbol{\beta}} - L\boldsymbol{\beta}}{\text{SE}_{L\hat{\boldsymbol{\beta}}}} \sim t_{n-p} \]

  • CI and T-test \(H_0: L\boldsymbol{\beta} = 0\) vs \(H_1: L\boldsymbol{\beta} \neq 0\)

  • F statistic follows F-distribution under \(H_0\) \[ F = \frac{MSR_2 - MSR_1}{MSE} \sim F_{p_2 - p_1,n-p_2}\]

4.2.1 Linearity

We assess linearity in a residual analysis

plot(mod1, which = 1)

The assumption of linearity is met.

4.2.2 Normality

plot(mod1, which = 2)

The QQ-plot does not show large deviations from normality.

4.2.3 Homoscedasticity: equality of the variance

We can again use the residual plot for assessing this assumption or the plot were we plot the square root of the standardized residuals in function of the fit.

plot(mod1, which = 1)

plot(mod1, which = 3)

We see that the spread of the majority of the residuals is more or less similar. As such, we may assume homoscedasticity of the data.

4.3 Inference

We first do an omnibus test to assess is there is an effect of the log10 concentration on the velocity.

mod0 <- lm(rate ~ state, data = Puromycin)
anova(mod0, mod1)

Next, we assess the interaction.

anova(mod1)

We cannot remove the interaction of the model.

Hence, we cannot study the effect of the concentration without accounting for the treatment and have to assess following research questions.

  1. the association between velocity and the concentration is significant in the untreated group

\[ H_0: \beta_c = 0 \text{ vs } H_1: \beta_c \neq 0 \]

  1. the association between velocity and the concentration is significant in the treated group

\[ H_0: \beta_c + \beta_{c:s}= 0 \text{ vs } H_1: \beta_c + \beta_{c:s}\neq 0 \]

  1. the association between velocity and the concentration is different between treated and untreated group

\[ H_0: \beta_{c:s}= 0\text{ vs }H_1: \beta_{c:s}\neq 0 \]

We can assess all these hypotheses using multcomp while correcting for multiple testing.

library(multcomp)
## Loading required package: mvtnorm
## Loading required package: survival
## Loading required package: TH.data
## Loading required package: MASS
## 
## Attaching package: 'MASS'
## The following object is masked from 'package:dplyr':
## 
##     select
## 
## Attaching package: 'TH.data'
## The following object is masked from 'package:MASS':
## 
##     geyser
mcp1 <- glht(mod1,
  linfct = c(
    "log10conc = 0",
    "log10conc + log10conc:statetreated = 0",
    "log10conc:statetreated = 0"
  )
)
summary(mcp1)
## 
##   Simultaneous Tests for General Linear Hypotheses
## 
## Fit: lm(formula = rate ~ log10conc * state, data = Puromycin)
## 
## Linear Hypotheses:
##                                         Estimate Std. Error t value
## log10conc == 0                            62.129      5.020  12.375
## log10conc + log10conc:statetreated == 0   85.450      4.531  18.858
## log10conc:statetreated == 0               23.321      6.763   3.448
##                                         Pr(>|t|)    
## log10conc == 0                           < 0.001 ***
## log10conc + log10conc:statetreated == 0  < 0.001 ***
## log10conc:statetreated == 0              0.00665 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## (Adjusted p values reported -- single-step method)
confint(mcp1)
## 
##   Simultaneous Confidence Intervals
## 
## Fit: lm(formula = rate ~ log10conc * state, data = Puromycin)
## 
## Quantile = 2.5074
## 95% family-wise confidence level
##  
## 
## Linear Hypotheses:
##                                         Estimate lwr     upr    
## log10conc == 0                          62.1285  49.5404 74.7166
## log10conc + log10conc:statetreated == 0 85.4499  74.0886 96.8113
## log10conc:statetreated == 0             23.3214   6.3644 40.2785

4.4 Conclusion

There is an extremely significant effect of the substrate concentration on the reaction rate (p<<0.001). The effect of the substrate concentration on the reaction rate is extremely significant for reactions catalysed with untreated enzymes. A reaction at a substrate concentration that is 10 times higher will have a reaction speed that is on average 62.1 counts/min higher (95% CI [49.5, 74.7] counts/min) (p << 0.001). The effect of the substrate concentration on the reaction rate is extremely significant for reactions catalysed puromycin treated enzymes (p << 0.001). A reaction at a substrate concentration that is 10 times higher will have a reaction speed that is on average 85.4 counts/min higher (95% CI [74.1, 96.8] counts/min). The effect of the substrate concentration on the reaction rate is very significantly higher for reactions catalysed with Puromycin treated enzymes than when catalysed with non-treated enzymes (p = 0.006). A reaction at a substrate concentration that is 10 times higher will have a reaction speed that is on average 23.3 counts/min higher for reactions that are catalysed with Puromycin treated enzymes than with untreated enzymes (95% CI [6.3, 40.3] counts/min).

5 Additional concepts

5.1 Interaction between two continuous predictors?

\[ Y_i = \beta_0 + \beta_v x_{iv} + \beta_w x_{iw} +\beta_s x_{is} + \beta_{vw} x_{iv}x_{iw} +\epsilon_i \]


Patient with a 1 unit difference in \(X_v\) have an average difference in lpsa of

\[ \begin{array}{l} E(Y | X_v=x_v +1, X_w=x_w, X_s=x_s) - E(Y | X_v=x_v, X_w=x_w, X_s=x_s) \\ \quad = \left[\beta_0 + \beta_v (x_{v}+1) + \beta_w x_w +\beta_s x_{s} + \beta_{vw} (x_{v}+1) x_w \right] - \left[\beta_0 + \beta_v x_{v} + \beta_w x_w + \beta_s x_{s} + \beta_{vw} (x_{v}) x_w \right]\\ \quad = \beta_v + \beta_{vw} x_w \end{array} \]

  • Slope for lcavol depends on log weight of prostate!

  • We can do the same for the lweight. Slope for lweight depends on lcavol of prostate!


lmVWS_IntVW <- lm(
  lpsa ~ lcavol +
    lweight +
    svi +
    lcavol:lweight,
  prostate)

summary(lmVWS_IntVW)
## 
## Call:
## lm(formula = lpsa ~ lcavol + lweight + svi + lcavol:lweight, 
##     data = prostate)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.65886 -0.44673  0.02082  0.50244  1.57457 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)   
## (Intercept)     -0.6430     0.7030  -0.915  0.36278   
## lcavol           1.0046     0.5427   1.851  0.06734 . 
## lweight          0.6146     0.1961   3.134  0.00232 **
## sviinvasion      0.6859     0.2114   3.244  0.00164 **
## lcavol:lweight  -0.1246     0.1478  -0.843  0.40156   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.7179 on 92 degrees of freedom
## Multiple R-squared:  0.6293, Adjusted R-squared:  0.6132 
## F-statistic: 39.05 on 4 and 92 DF,  p-value: < 2.2e-16
## Warning: no DISPLAY variable so Tk is not available

5.2 Interaction between two factors?

kpna2 <- read_tsv("https://raw.githubusercontent.com/statOmics/SGA21/master/data/kpna2.txt")
## Rows: 24 Columns: 3
## ── Column specification ──────────────────────────────────────────────
## Delimiter: "\t"
## dbl (3): grade, node, gene
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
kpna2 <- kpna2 %>%
  mutate(
    grade = as.factor(grade),
    node = as.factor(node),
    node = fct_recode(node, Unaffected = "0", Removed = "1"),
    log2gene = log2(gene)
  )
ggplot(kpna2, aes(x = grade, y = gene, fill = node)) +
  geom_boxplot(outlier.shape = NA) +
  geom_point(position = position_jitterdodge(), shape = 21, size = 2) +
  labs(
    x = "Histologic grade", y = "KPNA2 expression",
    fill = "Lymph node status"
  ) +
  ggtitle("KPNA2 gene expression in breast cancer patients")

ggplot(kpna2, aes(x = grade, y = log2gene, fill = node)) +
  geom_boxplot(outlier.shape = NA) +
  geom_point(position = position_jitterdodge(), shape = 21, size = 2) +
  labs(
    x = "Histologic grade", y = "KPNA2 log2 expression",
    fill = "Lymph node status"
  ) +
  ggtitle("KPNA2 gene expression in breast cancer patients")

fit <- lm(log2(gene) ~ grade * node, data = kpna2)
ExploreModelMatrix::VisualizeDesign(kpna2, ~ grade * node)$plotlist[[1]]

LS0tCnRpdGxlOiAiV3JhcHVwIE11bHRpcGxlIHJlZ3Jlc3Npb24iCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50LCBKZXJvZW4gR2lsaXMgYW5kIE1pbGFuIE1hbGZhaXQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCi0tLQoKPGEgcmVsPSJsaWNlbnNlIiBocmVmPSJodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktbmMtc2EvNC4wIj48aW1nIGFsdD0iQ3JlYXRpdmUgQ29tbW9ucyBMaWNlbnNlIiBzdHlsZT0iYm9yZGVyLXdpZHRoOjAiIHNyYz0iaHR0cHM6Ly9pLmNyZWF0aXZlY29tbW9ucy5vcmcvbC9ieS1uYy1zYS80LjAvODh4MzEucG5nIiAvPjwvYT4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKdGhlbWVfc2V0KHRoZW1lX2J3KCkpCmBgYAoKIyBQdXJvbXljaW4gZGF0YQoKRGF0YSBvbiB0aGUgdmVsb2NpdHkgb2YgYW4gZW56eW1hdGljIHJlYWN0aW9uIHdlcmUgb2J0YWluZWQgYnkgVHJlbG9hciAoMTk3NCkuClRoZSBudW1iZXIgb2YgY291bnRzIHBlciBtaW51dGUgb2YgcmFkaW9hY3RpdmUgcHJvZHVjdCBmcm9tIHRoZSByZWFjdGlvbiB3YXMKbWVhc3VyZWQgYXMgYSBmdW5jdGlvbiBvZiBzdWJzdHJhdGUgY29uY2VudHJhdGlvbiBpbiBwYXJ0cyBwZXIgbWlsbGlvbiAocHBtKSBhbmQKZnJvbSB0aGVzZSBjb3VudHMgdGhlIGluaXRpYWwgcmF0ZSAob3IgdmVsb2NpdHkpIG9mIHRoZSByZWFjdGlvbiB3YXMgY2FsY3VsYXRlZCAoY291bnRzL21pbi9taW4pLiBUaGUgZXhwZXJpbWVudCB3YXMgY29uZHVjdGVkIG9uY2Ugd2l0aCB0aGUgZW56eW1lIHRyZWF0ZWQKd2l0aCBQdXJvbXljaW4sIGFuZCBvbmNlIHdpdGggdGhlIGVuenltZSB1bnRyZWF0ZWQuCgpBc3Nlc3MgaWYgdGhlcmUgaXMgYW4gYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgc3Vic3RyYXRlIGNvbmNlbnRyYXRpb24gYW5kIHJhdGUKKipmb3IgYm90aCB0aGUgdHJlYXRlZCBhbmQgdW50cmVhdGVkIGVuenltZXMuKioKCiMgSW1wb3J0IGRhdGEKCmBgYHtyfQpkYXRhKFB1cm9teWNpbikKYGBgCgojIERhdGEgd3JhbmdsaW5nCgpGb3IgYSBjbGVhcmVyIGludGVycHJldGF0aW9uIG9mIHRoZSBtb2RlbCBwYXJhbWV0ZXJzIGxhdGVyIG9uLCB3ZSB3aWxsIG1ha2UKdGhlIHVudHJlYXRlZCBzdGF0ZSBlbnp5bWVzIHRoZSByZWZlcmVuY2UgY2F0ZWdvcnkuCgpgYGB7cn0KUHVyb215Y2luIDwtIFB1cm9teWNpbiAlPiUKICBtdXRhdGUoc3RhdGUgPSBmY3RfcmVsZXZlbChzdGF0ZSwgYygidW50cmVhdGVkIiwgInRyZWF0ZWQiKSkpCmBgYAoKIyMgRGF0YSBFeHBsb3JhdGlvbgoKRmlyc3QsIHdlIHZpc3VhbGl6ZSB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgY29uY2VudHJhdGlvbiBhbmQgdGhlIGVuenltZQpyYXRlLCBmb3IgYm90aCBvZiB0aGUgZW56eW1lIHN0YXRlcy4KCmBgYHtyfQpQdXJvbXljaW4gJT4lCiAgZ2dwbG90KGFlcyhjb25jLCByYXRlLGNvbD1zdGF0ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIpICsKICBsYWJzKAogICAgeCA9ICJTdWJzdHJhdGUgY29uY2VudHJhdGlvbiAocHBtKSIsCiAgICB5ID0gIlJlYWN0aW9uIHJhdGUgKGNvdW50cy9taW4vbWluKSIKICApICsKICBnZ3RpdGxlKCJSZWFjdGlvbiByYXRlcyBmb3IgcHVyb215Y2luLXRyZWF0ZWQgZW56eW1lcyIpCmBgYAoKVGhlIHBsb3Qgc2hvd3MgdGhhdCB0aGVyZSBpcyBhIHJlbGF0aW9uIGJldHdlZW4gdGhlIHZlbG9jaXR5IGFuZCB0aGUKY29uY2VudHJhdGlvbiwgaG93ZXZlciwgdGhlIHJlbGF0aW9uIGRvZXMgbm90IHNlZW0gdG8gYmUgbGluZWFyLgoKV2Ugd2lsbCBhc3Nlc3MgdGhlIGltcGFjdCBvZiBsb2ctdHJhbnNmb3JtaW5nIHRoZSBjb25jZW50cmF0aW9uLiBCZWNhdXNlIHRoZQpjb25jZW50cmF0aW9uIGlzIG1lYXN1cmVkIGluIHBwbSB3ZSB3aWxsIGxvZyRfezEwfSQgdHJhbnNmb3JtIHRoZSBkYXRhLgoKYGBge3J9ClB1cm9teWNpbiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBsb2cxMChjb25jKSwgeSA9IHJhdGUsY29sPXN0YXRlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9zbW9vdGgobWV0aG9kID0gImxtIikgKwogICAgbGFicygKICAgICAgeCA9ICJTdWJzdHJhdGUgY29uY2VudHJhdGlvbiAobG9nMTAocHBtKSkiLAogICAgICB5ID0gIlJlYWN0aW9uIHJhdGUgKGNvdW50cy9taW4vbWluKSIKICAgICkgKwogICAgZ2d0aXRsZSgiUmVhY3Rpb24gcmF0ZXMgZm9yIHB1cm9teWNpbi10cmVhdGVkIGVuenltZXMiKQpgYGAKClRoZSByZWxhdGlvbiBiZXR3ZWVuIHRoZSB2ZWxvY2l0eSBhbmQgdGhlIGxvZyRfezEwfSQgdHJhbnNmb3JtZWQgY29uY2VudHJhdGlvbgpzZWVtcyB0byBiZSBsaW5lYXIuCgpgYGB7cn0KUHVyb215Y2luIDwtIFB1cm9teWNpbiAlPiUKICBtdXRhdGUobG9nMTBjb25jID0gbG9nMTAoY29uYykpCmBgYAoKIyBMaW5lYXIgcmVncmVzc2lvbgoKV2Ugd2lsbCBmaXQgdGhlIGZvbGxvd2luZyBtb2RlbCB0byB0aGUgZGF0YQoKJFlfaSA9IFxiZXRhXzAgKyBcYmV0YV9jIHhfYysgXGJldGFfcyB4X3MgK1xiZXRhX3tjOnN9eF97Y314X3tzfSArIFxlcHNpbG9uX2kkCgp3aXRoCgotICRZX2kkIHRoZSByZWFjdGlvbiByYXRlLAoKLSAkXGJldGFfMCQgdGhlIGludGVyY2VwdCwKCi0gJFxiZXRhX3tjfSQgdGhlIG1haW4gZWZmZWN0IGZvciBsb2cxMCBjb25jZW50cmF0aW9uLAoKLSAkeF9jJCB0aGUgbG9nMTAgY29uY2VudHJhdGlvbiwKCi0gJFxiZXRhX3twfSQgdGhlIG1haW4gZWZmZWN0IGZvciB0cmVhdG1lbnQgLAoKLSAkeF9zJCBhIGR1bW15IHZhcmlhYmxlIGZvciAic3RhdGUiIHRoYXQgaXMgMCBpZiB0aGUgZW56eW1lcyB0aGF0IGFyZSB1bnRyZWF0ZWQgYW5kIDEgaWYKdGhlIGVuenltZXMgYXJlIHRyZWF0ZWQgd2l0aCBQdXJvbXljaW4sCgotICRcYmV0YV97YzpzfSQgdGhlIGludGVyYWN0aW9uIGVmZmVjdCBiZXR3ZWVuIGNvbmNlbnRyYXRpb24gYW5kIHRyZWF0bWVudCBzdGF0ZSwKCi0gJFxlcHNpbG9uX2kkIGkuaS5kLiBub3JtYWxseSBkaXN0cmlidXRlZCB3aXRoIG1lYW4gMCBhbmQgdmFyaWFuY2UgJFxzaWdtYV4yJC4KCk5vdGUsIHRoYXQgd2Ugd3JpdGUgdGhlIHN1YnN0cmF0ZSBjb25jZW50cmF0aW9uIHdpdGggYSBzbWFsbCBsZXR0ZXIgYmVjYXVzZQp0aGUgcHJlZGljdG9yIGlzIG5vdCByYW5kb20uIFRoZSByZXNlYXJjaGVycyBoYXZlIGNob3NlbiB0aGUgc3Vic3RyYXRlCmNvbmNlbnRyYXRpb25zIGluIHRoZSBkZXNpZ24gcGhhc2UgYW5kIGl0IGlzIHRodXMgbm8gcmFuZG9tIHZhcmlhYmxlLgoKVGhlIG1vZGVsIGltcGxpZXMgdHdvIGRpZmZlcmVudCByZWdyZXNzaW9uIGxpbmVzCgotIG5vIHRyZWF0bWVudCAoJHhfcyA9IDAkKQokJApZX2kgPSBcYmV0YV8wICsgXGJldGFfYyB4X2MgKyBcZXBzaWxvbgokJAotIHRyZWF0bWVudCAoeF9zID0gMSkKCiQkCllfaSA9IChcYmV0YV8wICsgXGJldGFfcykgICsgKFxiZXRhX2MrXGJldGFfe2M6c30pIHhfYyArIFxlcHNpbG9uCiQkCgpTbyB0aGUgbWFpbiBlZmZlY3QgZm9yIHRyZWF0bWVudCBoYXMgdGhlIGludGVycHJldGF0aW9uIGFzIHRoZSBjaGFuZ2UgaW4gaW50ZXJjZXB0IGJldHdlZW4gdHJlYXRlZCBhbmQgdW50cmVhdGVkIHNhbXBsZXMuCgpUaGUgaW50ZXJhY3Rpb24gdGVybSBoYXMgdGhlIGludGVycHJldGF0aW9uIGFzIHRoZSBjaGFuZ2UgaW4gc2xvcGUgYmV0d2VlbiB0cmVhdGVkIGFuZCB1bnRyZWF0ZWQgc2FtcGxlcy4KCgojIyBJbnRlcm1lenpvOiBHcmFwaGljYWwgaW50ZXJwcmV0YXRpb24gb2YgdGhlIHBhcmFtZXRlcnMKCiMjIyBTaW1wbGUgbGluZWFyIG1vZGVsOiAxIHNsb3BlIHstfQoKVGhpcyBpcyB0aGUgc2FtZSBtb2RlbCB0aGF0IHdlIGZpdCBpbiB0aGUKW0NoYXB0ZXIgNiBleGVyY2lzZV0oLi8wNl8xX3B1cm9teWNpbi5odG1sKToKCiQkIFlfaSA9IFxiZXRhXzAgKyBcYmV0YV97XHRleHR7cmF0ZX19IFhfe2ksIFx0ZXh0e3JhdGV9fSArIFxlcHNpbG9uX2kgJCQKCmBgYHtyfQptb2Rfc2ltcGxlIDwtIGxtKHJhdGUgfiBsb2cxMGNvbmMsIGRhdGEgPSBQdXJvbXljaW4pCm1vZF9zaW1wbGUKCmdncGxvdChQdXJvbXljaW4sIGFlcyhsb2cxMGNvbmMsIHJhdGUpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBzdGF0ZSkpICsKICBnZW9tX2FibGluZSgKICAgICBpbnRlcmNlcHQgPSBjb2VmKG1vZF9zaW1wbGUpWzFdLAogICAgIHNsb3BlID0gY29lZihtb2Rfc2ltcGxlKVsyXQogICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJkYXJrb3JjaGlkIiwgImZvcmVzdGdyZWVuIikpICsKICBnZ3RpdGxlKCJUaGUgc2ltcGxlIGxpbmVhciBtb2RlbCIpCmBgYAoKCiMjIyBBZGRpdGl2ZSBtb2RlbDogMiBwYXJhbGxlbCBzbG9wZXMgey19CgpXZSBhZGQgYW4gYWRkaXRpb25hbCB0ZXJtIGZvciB0aGUgc3RhdGUgb2YgdGhlIHJlYWN0aW4gKHRyZWF0ZWQgb3IgdW50cmVhdGVkKS4KTm90ZSB0aGF0IHRoaXMgdmFyaWFibGUgaXMgKipjYXRlZ29yaWNhbCoqLgoKJCQKWV9pID0gXGJldGFfMCArIFxiZXRhX3tcdGV4dHtyYXRlfX0gWF97aSwgXHRleHR7cmF0ZX19ICsKICBcYmV0YV97XHRleHR7c3RhdGV9fSBYX3tpLCBcdGV4dHtzdGF0ZX19ICsgXGVwc2lsb25faQokJAoKYGBge3J9Cm1vZF9hZGQgPC0gbG0ocmF0ZSB+IGxvZzEwY29uYyArIHN0YXRlLCBkYXRhID0gUHVyb215Y2luKQptb2RfYWRkCgpnZ3Bsb3QoUHVyb215Y2luLCBhZXMobG9nMTBjb25jLCByYXRlLCBjb2wgPSBzdGF0ZSkpICsKICBnZW9tX3BvaW50KCkgKwogICMjIExpbmUgZm9yIHRoZSB1bnRyZWF0ZWQgZ3JvdXAKICBnZW9tX2FibGluZSgKICAgICBpbnRlcmNlcHQgPSBjb2VmKG1vZF9hZGQpWzFdLAogICAgIHNsb3BlID0gY29lZihtb2RfYWRkKVsyXSwKICAgICBjb2wgPSAiZGFya29yY2hpZCIKICApICsKICAjIyBMaW5lIGZvciB0aGUgdHJlYXRlZCBncm91cAogIGdlb21fYWJsaW5lKAogICAgIGludGVyY2VwdCA9IGNvZWYobW9kX2FkZClbMV0gKyBjb2VmKG1vZF9hZGQpWzNdLAogICAgIHNsb3BlID0gY29lZihtb2RfYWRkKVsyXSwKICAgICBjb2wgPSAiZm9yZXN0Z3JlZW4iCiAgKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImRhcmtvcmNoaWQiLCAiZm9yZXN0Z3JlZW4iKSkgKwogIGdndGl0bGUoIlRoZSBhZGRpdGl2ZSBsaW5lYXIgbW9kZWwgd2l0aCBwYXJhbGxlbCBzbG9wZXMiKQpgYGAKCgojIyMgVGhlIGludGVyYWN0aW9uIG1vZGVsOiAyIG5vbi1wYXJhbGxlbCBzbG9wZXMgey19CgokJApZX2kgPSBcYmV0YV8wICsgXGJldGFfe1x0ZXh0e3JhdGV9fSBYX3tpLCBcdGV4dHtyYXRlfX0gKwogIFxiZXRhX3tcdGV4dHtzdGF0ZX19IFhfe2ksIFx0ZXh0e3N0YXRlfX0gKwogIFxiZXRhX3tcdGV4dHtyYXRlOnN0YXRlfX0gWF97aSwgXHRleHR7cmF0ZX19IFhfe2ksIFx0ZXh0e3N0YXRlfX0gKwogIFxlcHNpbG9uX2kKJCQKCmBgYHtyfQptb2RfaW50IDwtIGxtKHJhdGUgfiBsb2cxMGNvbmMgKiBzdGF0ZSwgZGF0YSA9IFB1cm9teWNpbikKbW9kX2ludAoKZ2dwbG90KFB1cm9teWNpbiwgYWVzKGxvZzEwY29uYywgcmF0ZSwgY29sID0gc3RhdGUpKSArCiAgZ2VvbV9wb2ludCgpICsKICAjIyBMaW5lIGZvciB0aGUgdW50cmVhdGVkIGdyb3VwCiAgZ2VvbV9hYmxpbmUoCiAgICAgaW50ZXJjZXB0ID0gY29lZihtb2RfaW50KVsxXSwKICAgICBzbG9wZSA9IGNvZWYobW9kX2ludClbMl0sCiAgICAgY29sID0gImRhcmtvcmNoaWQiCiAgKSArCiAgIyMgTGluZSBmb3IgdGhlIHRyZWF0ZWQgZ3JvdXAKICBnZW9tX2FibGluZSgKICAgICBpbnRlcmNlcHQgPSBjb2VmKG1vZF9pbnQpWzFdICsgY29lZihtb2RfaW50KVszXSwKICAgICBzbG9wZSA9IGNvZWYobW9kX2ludClbMl0gKyBjb2VmKG1vZF9pbnQpWzRdLAogICAgIGNvbCA9ICJmb3Jlc3RncmVlbiIKICApICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiZGFya29yY2hpZCIsICJmb3Jlc3RncmVlbiIpKSArCiAgZ2d0aXRsZSgiVGhlIGxpbmVhciBtb2RlbCB3aXRoIGludGVyYWN0aW9uOiBub24tcGFyYWxsZWwgc2xvcGVzIikKYGBgCgpgYGB7cn0KbW9kMSA8LSBsbShyYXRlIH4gbG9nMTBjb25jICogc3RhdGUsIFB1cm9teWNpbikKc3VtbWFyeShtb2QxKQpgYGAKCkJlZm9yZSB3ZSBwZXJmb3JtIGluZmVyZW5jZSB3ZSB3aWxsIGZpcnN0IGFzc2VzcyB0aGUgYXNzdW1wdGlvbnMKCiMjIEFzc3VtcHRpb25zCgoKMS4gTGluZWFyaXR5IGFuZCByZXByZXNlbnRhdGl2ZSBzYW1wbGUKClxbRVtcaGF0IFxiZXRhX2pdPVxiZXRhX2pcXQoKMi4gTm9ybWFsIGRpc3RyaWJ1dGlvbiBvZiB0aGUgcmVzaWR1YWxzCgpcW1lfe2l9IFxzaW0gTihcbXVfaSxcc2lnbWFeMilcXQpcW1lfaSBcc2ltIE4oXGJldGFfMCArIFxiZXRhX2MgeF97Y2l9KyBcYmV0YV9zIHhfe3NpfSArXGJldGFfe2M6c314X3tjaX14X3tzaX0sXHNpZ21hXjIpICBcbG9uZ3JpZ2h0YXJyb3cgXGhhdCBcYmV0YV9qIFxzaW0gTihcYmV0YV9qLCBcc2lnbWFeMl97XGhhdCBcYmV0YV9qfSlcXQoKbGluZWFyIGNvbWJpbmF0aW9ucyBvZiBtb2RlbCBwYXJhbWV0ZXIgZXN0aW1hdG9ycyBhcmUgYWxzbyBub3JtYWxseSBkaXN0cmlidXRlZCwgZS5nLgokJApcbG9uZ3JpZ2h0YXJyb3cgXGhhdCBcYmV0YV9jICsgXGhhdCBcYmV0YV97YzpzfSBcc2ltIE4oXGJldGFfYytcYmV0YV97Y3N9LCBcc2lnbWFeMl97XGhhdFxiZXRhX2MrXGhhdFxiZXRhX3tjOnN9fSkKJCQKJCQKXGxvbmdyaWdodGFycm93IExeVFxoYXQgXGJldGEgXHNpbSBOKExeVFxiZXRhLCBcc2lnbWFeMl97TF5UXGhhdHtcYm9sZHN5bWJvbHtcYmV0YX19fSkKJCQKCgoKNC4gSW5kZXBlbmRlbmNlIGFuZCBIb21vc2NlZGFzdGljaXR5CgpXZSBhc3N1bWUgdGhhdCB0aGUgZXhwZXJpbWVudCB3YXMgd2VsbCBkZXNpZ25lZCBhbmQgdGhhdCB0aGUgZGlmZmVyZW50IHJlYWN0aW9ucyB0aGF0IHdlcmUgdXNlIGluIHRoZSBleHBlcmltZW50IGFyZSBpbmRlcGVuZGVudC4KCiQkXHNpZ21hXjJfe0xeVFxoYXR7XGJvbGRzeW1ib2x7XGJldGF9fX0gPSBjX0wgXHNpZ21hXjIkJAoKCi0gJFxzaWdtYV4yPyQKCiQkXGhhdCBcc2lnbWFeMiA9IE1TRSA9IFxzdW1cbGltaXRzX3tpPTF9IF4gbiBcZnJhY3soWV9pIC0gXGhhdCBZX2kpXjJ9e24tcH0kJAoKJCQKU0Vfe0xeVFxoYXR7XGJvbGRzeW1ib2x7XGJldGF9fX0gPSBjX0wgXGhhdCBcc2lnbWFeMgokJAoKLSB0LXN0YXRpc3RpYwoKJCQKVCA9IFxmcmFje0xcaGF0e1xib2xkc3ltYm9se1xiZXRhfX0gLSBMXGJvbGRzeW1ib2x7XGJldGF9fXtcdGV4dHtTRX1fe0xcaGF0e1xib2xkc3ltYm9se1xiZXRhfX19fQogXHNpbSB0X3tuLXB9CiQkCgotIENJIGFuZCBULXRlc3QgJEhfMDogTFxib2xkc3ltYm9se1xiZXRhfSA9IDAkIHZzICAkSF8xOiBMXGJvbGRzeW1ib2x7XGJldGF9IFxuZXEgMCQKCi0gRiBzdGF0aXN0aWMgZm9sbG93cyBGLWRpc3RyaWJ1dGlvbiB1bmRlciAkSF8wJApcWyBGID0gXGZyYWN7TVNSXzIgLSBNU1JfMX17TVNFfSBcc2ltIEZfe3BfMiAtIHBfMSxuLXBfMn1cXQoKCiMjIyBMaW5lYXJpdHkKCldlIGFzc2VzcyBsaW5lYXJpdHkgaW4gYSByZXNpZHVhbCBhbmFseXNpcwoKYGBge3J9CnBsb3QobW9kMSwgd2hpY2ggPSAxKQpgYGAKClRoZSBhc3N1bXB0aW9uIG9mIGxpbmVhcml0eSBpcyBtZXQuCgojIyMgTm9ybWFsaXR5CgpgYGB7cn0KcGxvdChtb2QxLCB3aGljaCA9IDIpCmBgYAoKVGhlIFFRLXBsb3QgZG9lcyBub3Qgc2hvdyBsYXJnZSBkZXZpYXRpb25zIGZyb20gbm9ybWFsaXR5LgoKIyMjIEhvbW9zY2VkYXN0aWNpdHk6IGVxdWFsaXR5IG9mIHRoZSB2YXJpYW5jZQoKV2UgY2FuIGFnYWluIHVzZSB0aGUgcmVzaWR1YWwgcGxvdCBmb3IgYXNzZXNzaW5nIHRoaXMgYXNzdW1wdGlvbiBvciB0aGUgcGxvdAp3ZXJlIHdlIHBsb3QgdGhlIHNxdWFyZSByb290IG9mIHRoZSBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzIGluIGZ1bmN0aW9uIG9mCnRoZSBmaXQuCgpgYGB7cn0KcGxvdChtb2QxLCB3aGljaCA9IDEpCnBsb3QobW9kMSwgd2hpY2ggPSAzKQpgYGAKCldlIHNlZSB0aGF0IHRoZSBzcHJlYWQgb2YgdGhlIG1ham9yaXR5IG9mIHRoZSByZXNpZHVhbHMgaXMgbW9yZSBvciBsZXNzIHNpbWlsYXIuCkFzIHN1Y2gsIHdlIG1heSBhc3N1bWUgaG9tb3NjZWRhc3RpY2l0eSBvZiB0aGUgZGF0YS4KCgoKIyMgSW5mZXJlbmNlCgpXZSBmaXJzdCBkbyBhbiBvbW5pYnVzIHRlc3QgdG8gYXNzZXNzIGlzIHRoZXJlIGlzIGFuIGVmZmVjdCBvZiB0aGUgbG9nMTAgY29uY2VudHJhdGlvbiBvbiB0aGUgdmVsb2NpdHkuCgpgYGB7cn0KbW9kMCA8LSBsbShyYXRlIH4gc3RhdGUsIGRhdGEgPSBQdXJvbXljaW4pCmFub3ZhKG1vZDAsIG1vZDEpCmBgYAoKTmV4dCwgd2UgYXNzZXNzIHRoZSBpbnRlcmFjdGlvbi4KCmBgYHtyfQphbm92YShtb2QxKQpgYGAKCldlIGNhbm5vdCByZW1vdmUgdGhlIGludGVyYWN0aW9uIG9mIHRoZSBtb2RlbC4KCkhlbmNlLCB3ZSBjYW5ub3Qgc3R1ZHkgdGhlIGVmZmVjdCBvZiB0aGUgY29uY2VudHJhdGlvbiB3aXRob3V0IGFjY291bnRpbmcgZm9yIHRoZSB0cmVhdG1lbnQgYW5kIGhhdmUgdG8gYXNzZXNzIGZvbGxvd2luZyByZXNlYXJjaCBxdWVzdGlvbnMuCgoxLiB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiB2ZWxvY2l0eSBhbmQgdGhlIGNvbmNlbnRyYXRpb24gaXMgc2lnbmlmaWNhbnQgaW4gdGhlIHVudHJlYXRlZCBncm91cAoKJCQKSF8wOiBcYmV0YV9jID0gMCBcdGV4dHsgdnMgfSBIXzE6IFxiZXRhX2MgXG5lcSAwCiQkCgoyLiB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiB2ZWxvY2l0eSBhbmQgdGhlIGNvbmNlbnRyYXRpb24gaXMgc2lnbmlmaWNhbnQgaW4gdGhlIHRyZWF0ZWQgZ3JvdXAKCiQkCkhfMDogXGJldGFfYyArIFxiZXRhX3tjOnN9PSAwIFx0ZXh0eyB2cyB9IEhfMTogXGJldGFfYyArIFxiZXRhX3tjOnN9XG5lcSAwCiQkCgozLiB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiB2ZWxvY2l0eSBhbmQgdGhlIGNvbmNlbnRyYXRpb24gaXMgZGlmZmVyZW50IGJldHdlZW4gdHJlYXRlZCBhbmQgdW50cmVhdGVkIGdyb3VwCgokJApIXzA6IFxiZXRhX3tjOnN9PSAwXHRleHR7IHZzIH1IXzE6IFxiZXRhX3tjOnN9XG5lcSAwCiQkCgpXZSBjYW4gYXNzZXNzIGFsbCB0aGVzZSBoeXBvdGhlc2VzIHVzaW5nIG11bHRjb21wIHdoaWxlIGNvcnJlY3RpbmcgZm9yIG11bHRpcGxlIHRlc3RpbmcuCgpgYGB7cn0KbGlicmFyeShtdWx0Y29tcCkKbWNwMSA8LSBnbGh0KG1vZDEsCiAgbGluZmN0ID0gYygKICAgICJsb2cxMGNvbmMgPSAwIiwKICAgICJsb2cxMGNvbmMgKyBsb2cxMGNvbmM6c3RhdGV0cmVhdGVkID0gMCIsCiAgICAibG9nMTBjb25jOnN0YXRldHJlYXRlZCA9IDAiCiAgKQopCnN1bW1hcnkobWNwMSkKY29uZmludChtY3AxKQpgYGAKCgojIyBDb25jbHVzaW9uCgpUaGVyZSBpcyBhbiBleHRyZW1lbHkgc2lnbmlmaWNhbnQgZWZmZWN0IG9mIHRoZSBzdWJzdHJhdGUgY29uY2VudHJhdGlvbiBvbiB0aGUgcmVhY3Rpb24gcmF0ZSAocDw8MC4wMDEpLgpUaGUgZWZmZWN0IG9mIHRoZSBzdWJzdHJhdGUgY29uY2VudHJhdGlvbiBvbiB0aGUgcmVhY3Rpb24gcmF0ZSBpcyBleHRyZW1lbHkgc2lnbmlmaWNhbnQgZm9yIHJlYWN0aW9ucyBjYXRhbHlzZWQgd2l0aCB1bnRyZWF0ZWQgZW56eW1lcy4gQSByZWFjdGlvbiBhdCBhIHN1YnN0cmF0ZSBjb25jZW50cmF0aW9uIHRoYXQgaXMgMTAgdGltZXMgaGlnaGVyIHdpbGwgaGF2ZSBhIHJlYWN0aW9uIHNwZWVkIHRoYXQgaXMgb24gYXZlcmFnZSAgYHIgcm91bmQoY29uZmludChtY3AxKSRjb25maW50WzEsMV0sMSlgIGNvdW50cy9taW4gaGlnaGVyICg5NSUgQ0kgW2ByIHJvdW5kKGNvbmZpbnQobWNwMSkkY29uZmludFsxLC0xXSwxKWBdIGNvdW50cy9taW4pIChwIDw8IDAuMDAxKS4KVGhlIGVmZmVjdCBvZiB0aGUgc3Vic3RyYXRlIGNvbmNlbnRyYXRpb24gb24gdGhlIHJlYWN0aW9uIHJhdGUgaXMgZXh0cmVtZWx5IHNpZ25pZmljYW50IGZvciByZWFjdGlvbnMgY2F0YWx5c2VkIHB1cm9teWNpbiB0cmVhdGVkIGVuenltZXMgIChwIDw8IDAuMDAxKS4gQSByZWFjdGlvbiBhdCBhIHN1YnN0cmF0ZSBjb25jZW50cmF0aW9uIHRoYXQgaXMgMTAgdGltZXMgaGlnaGVyIHdpbGwgaGF2ZSBhIHJlYWN0aW9uIHNwZWVkIHRoYXQgaXMgb24gYXZlcmFnZSAgYHIgcm91bmQoY29uZmludChtY3AxKSRjb25maW50WzIsMV0sMSlgIGNvdW50cy9taW4gaGlnaGVyICg5NSUgQ0kgW2ByIHJvdW5kKGNvbmZpbnQobWNwMSkkY29uZmludFsyLC0xXSwxKWBdIGNvdW50cy9taW4pLgpUaGUgZWZmZWN0IG9mIHRoZSBzdWJzdHJhdGUgY29uY2VudHJhdGlvbiBvbiB0aGUgcmVhY3Rpb24gcmF0ZSBpcyB2ZXJ5IHNpZ25pZmljYW50bHkgaGlnaGVyIGZvciByZWFjdGlvbnMgY2F0YWx5c2VkIHdpdGggUHVyb215Y2luIHRyZWF0ZWQgZW56eW1lcyB0aGFuIHdoZW4gY2F0YWx5c2VkIHdpdGggbm9uLXRyZWF0ZWQgZW56eW1lcyAgKHAgPSBgciByb3VuZChzdW1tYXJ5KG1jcDEpJHRlc3QkcHZhbHVlWzNdLDMpYCkuIEEgcmVhY3Rpb24gYXQgYSBzdWJzdHJhdGUgY29uY2VudHJhdGlvbiB0aGF0IGlzIDEwIHRpbWVzIGhpZ2hlciB3aWxsIGhhdmUgYSByZWFjdGlvbiBzcGVlZCB0aGF0IGlzIG9uIGF2ZXJhZ2UgYHIgcm91bmQoY29uZmludChtY3AxKSRjb25maW50WzMsMV0sMSlgIGNvdW50cy9taW4gaGlnaGVyIGZvciByZWFjdGlvbnMgdGhhdCBhcmUgY2F0YWx5c2VkIHdpdGggUHVyb215Y2luIHRyZWF0ZWQgZW56eW1lcyB0aGFuIHdpdGggdW50cmVhdGVkIGVuenltZXMgKDk1JSBDSSBbYHIgcm91bmQoY29uZmludChtY3AxKSRjb25maW50WzMsLTFdLDEpYF0gY291bnRzL21pbikuCgoKIyBBZGRpdGlvbmFsIGNvbmNlcHRzCgojIyBJbnRlcmFjdGlvbiBiZXR3ZWVuIHR3byBjb250aW51b3VzIHByZWRpY3RvcnM/CgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtdWx0Y29tcCkKbGlicmFyeShHR2FsbHkpCmxpYnJhcnkoY2FyKQpwcm9zdGF0ZSA8LSByZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRvbWljcy9zYmMyMC9tYXN0ZXIvZGF0YS9wcm9zdGF0ZS5jc3YiKQpwcm9zdGF0ZSA8LSBwcm9zdGF0ZSAlPiUKICBtdXRhdGUoc3ZpID0gYXMuZmFjdG9yKHN2aSkpCgpsaWJyYXJ5KEdHYWxseSkKcHJvc3RhdGUgJT4lCiAgZHBseXI6OnNlbGVjdCgtcGdnNDUpICAlPiUKICBnZ3BhaXJzKCkKbG1WV1MgPC0gbG0obHBzYX5sY2F2b2wgKyBsd2VpZ2h0ICsgc3ZpLCBwcm9zdGF0ZSkKYGBgCgokJApZX2kgPSBcYmV0YV8wICsgXGJldGFfdiB4X3tpdn0gKyBcYmV0YV93IHhfe2l3fSArXGJldGFfcyB4X3tpc30gKyBcYmV0YV97dnd9IHhfe2l2fXhfe2l3fSArXGVwc2lsb25faQokJAoKLS0tCgpQYXRpZW50IHdpdGggYSAxIHVuaXQgZGlmZmVyZW5jZSBpbiAkWF92JCBoYXZlIGFuIGF2ZXJhZ2UgZGlmZmVyZW5jZSBpbiBscHNhIG9mCgokJApcYmVnaW57YXJyYXl9e2x9CkUoWSB8IFhfdj14X3YgKzEsIFhfdz14X3csIFhfcz14X3MpIC0gRShZIHwgWF92PXhfdiwgWF93PXhfdywgWF9zPXhfcykgXFwKXHF1YWQgPSBcbGVmdFtcYmV0YV8wICsgXGJldGFfdiAoeF97dn0rMSkgKyBcYmV0YV93IHhfdyArXGJldGFfcyB4X3tzfSArIFxiZXRhX3t2d30gKHhfe3Z9KzEpIHhfdyBccmlnaHRdIC0gXGxlZnRbXGJldGFfMCArIFxiZXRhX3YgeF97dn0gKyBcYmV0YV93IHhfdyAgKyBcYmV0YV9zIHhfe3N9ICsgXGJldGFfe3Z3fSAoeF97dn0pIHhfdyBccmlnaHRdXFwKXHF1YWQgPSBcYmV0YV92ICsgIFxiZXRhX3t2d30geF93CiBcZW5ke2FycmF5fQogJCQKCi0gU2xvcGUgZm9yIGxjYXZvbCBkZXBlbmRzIG9uIGxvZyB3ZWlnaHQgb2YgcHJvc3RhdGUhCgotIFdlIGNhbiBkbyB0aGUgc2FtZSBmb3IgdGhlIGx3ZWlnaHQuIFNsb3BlIGZvciBsd2VpZ2h0IGRlcGVuZHMgb24gbGNhdm9sIG9mIHByb3N0YXRlIQoKLS0tCgpgYGB7cn0KbG1WV1NfSW50VlcgPC0gbG0oCiAgbHBzYSB+IGxjYXZvbCArCiAgICBsd2VpZ2h0ICsKICAgIHN2aSArCiAgICBsY2F2b2w6bHdlaWdodCwKICBwcm9zdGF0ZSkKCnN1bW1hcnkobG1WV1NfSW50VlcpCmBgYAoKYGBge3Igb3V0LndpZHRoPScxMDAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CnBhcihtZnJvdz1jKDEsMikpCmxpYnJhcnkocGxvdDNEKQpncmlkLmxpbmVzID0gMTAKeDwtcHJvc3RhdGUkbGNhdm9sCnk8LXByb3N0YXRlJGx3ZWlnaHQKejwtcHJvc3RhdGUkbHBzYQpmaXQ8LWxtKHp+eCt5K3N2aSxkYXRhPXByb3N0YXRlKQp4LnByZWQgPC0gc2VxKG1pbih4KSwgbWF4KHgpLCBsZW5ndGgub3V0ID0gZ3JpZC5saW5lcykKeS5wcmVkIDwtIHNlcShtaW4oeSksIG1heCh5KSwgbGVuZ3RoLm91dCA9IGdyaWQubGluZXMpCgojIGZpdHRlZCBwb2ludHMgZm9yIGRyb3BsaW5lcyB0byBzdXJmYWNlCnRoPS0yNQpwaD01CnNjYXR0ZXIzRCh4LCB5LCB6LCBwY2ggPSAxNixjb2w9YygiZGFya2JsdWUiLCJyZWQiKVthcy5kb3VibGUocHJvc3RhdGUkc3ZpKV0sIGNleCA9IC43NSwKICAgIHRoZXRhID0gdGgsIHBoaSA9IHBoLCB0aWNrdHlwZSA9ICJkZXRhaWxlZCIsCiAgICB4bGFiID0gImxjYXZvbCIsIHlsYWIgPSAibHdlaWdodCIsIHpsYWIgPSAibHBzYSIsCiAgIGNvbHZhcj1GQUxTRSxidHkgPSAiZyIsbWFpbj0iQWRkaXRpdmUgbW9kZWwiKQoKZm9yIChpIGluIHdoaWNoKHByb3N0YXRlJHN2aT09ImhlYWx0aHkiKSkKbGluZXMzRCh4PXJlcChwcm9zdGF0ZSRsY2F2b2xbaV0sMikseT1yZXAocHJvc3RhdGUkbHdlaWdodFtpXSwyKSx6PWMocHJvc3RhdGUkbHBzYVtpXSxsbVZXUyRmaXRbaV0pLGNvbD1jKCJkYXJrYmx1ZSIsInJlZCIpW2FzLmRvdWJsZShwcm9zdGF0ZSRzdmkpW2ldXSxhZGQ9VFJVRSxsdHk9MikKCnoucHJlZDNEIDwtIG91dGVyKHgucHJlZCwgeS5wcmVkLCBmdW5jdGlvbih4LHkpIHtsbVZXUyRjb2VmWzFdK2xtVldTJGNvZWZbMl0qeCtsbVZXUyRjb2VmWzNdKnl9KQp4LnByZWQzRCA8LSBvdXRlcih4LnByZWQseS5wcmVkLGZ1bmN0aW9uKHgseSkgeCkKeS5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLHkucHJlZCxmdW5jdGlvbih4LHkpIHkpCnN1cmYzRCh4LnByZWQzRCx5LnByZWQzRCx6LnByZWQzRCxjb2w9ImJsdWUiLGZhY2V0cz1OQSxhZGQ9VFJVRSkKCgpzY2F0dGVyM0QoeCwgeSwgeiwgcGNoID0gMTYsY29sPWMoImRhcmtibHVlIiwicmVkIilbYXMuZG91YmxlKHByb3N0YXRlJHN2aSldLCBjZXggPSAuNzUsCiAgICB0aGV0YSA9IHRoLCBwaGkgPSBwaCwgdGlja3R5cGUgPSAiZGV0YWlsZWQiLAogICAgeGxhYiA9ICJsY2F2b2wiLCB5bGFiID0gImx3ZWlnaHQiLCB6bGFiID0gImxwc2EiLAogICBjb2x2YXI9RkFMU0UsYnR5ID0gImciLG1haW49Ik1vZGVsIG1ldCBsY2F2b2w6bHdlaWdodCBpbnRlcmFjdGllIikKCmZvciAoaSBpbiB3aGljaChwcm9zdGF0ZSRzdmk9PSJoZWFsdGh5IikpCmxpbmVzM0QoeD1yZXAocHJvc3RhdGUkbGNhdm9sW2ldLDIpLHk9cmVwKHByb3N0YXRlJGx3ZWlnaHRbaV0sMiksej1jKHByb3N0YXRlJGxwc2FbaV0sbG1WV1NfSW50VlckZml0W2ldKSxjb2w9YygiZGFya2JsdWUiLCJyZWQiKVthcy5kb3VibGUocHJvc3RhdGUkc3ZpKVtpXV0sYWRkPVRSVUUsbHR5PTIpCgp6LnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCx5KSB7bG1WV1NfSW50VlckY29lZlsxXStsbVZXU19JbnRWVyRjb2VmWzJdKngrbG1WV1NfSW50VlckY29lZlszXSp5K2xtVldTX0ludFZXJGNvZWZbNV0qeCp5fSkKeC5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLHkucHJlZCxmdW5jdGlvbih4LHkpIHgpCnkucHJlZDNEIDwtIG91dGVyKHgucHJlZCx5LnByZWQsZnVuY3Rpb24oeCx5KSB5KQpzdXJmM0QoeC5wcmVkM0QseS5wcmVkM0Qsei5wcmVkM0QsY29sPSJibHVlIixmYWNldHM9TkEsYWRkPVRSVUUpCmBgYAoKIyMgSW50ZXJhY3Rpb24gYmV0d2VlbiB0d28gZmFjdG9ycz8KCmBgYHtyfQprcG5hMiA8LSByZWFkX3RzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRPbWljcy9TR0EyMS9tYXN0ZXIvZGF0YS9rcG5hMi50eHQiKQprcG5hMiA8LSBrcG5hMiAlPiUKICBtdXRhdGUoCiAgICBncmFkZSA9IGFzLmZhY3RvcihncmFkZSksCiAgICBub2RlID0gYXMuZmFjdG9yKG5vZGUpLAogICAgbm9kZSA9IGZjdF9yZWNvZGUobm9kZSwgVW5hZmZlY3RlZCA9ICIwIiwgUmVtb3ZlZCA9ICIxIiksCiAgICBsb2cyZ2VuZSA9IGxvZzIoZ2VuZSkKICApCmBgYAoKYGBge3J9CmdncGxvdChrcG5hMiwgYWVzKHggPSBncmFkZSwgeSA9IGdlbmUsIGZpbGwgPSBub2RlKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoKSwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIpICsKICBsYWJzKAogICAgeCA9ICJIaXN0b2xvZ2ljIGdyYWRlIiwgeSA9ICJLUE5BMiBleHByZXNzaW9uIiwKICAgIGZpbGwgPSAiTHltcGggbm9kZSBzdGF0dXMiCiAgKSArCiAgZ2d0aXRsZSgiS1BOQTIgZ2VuZSBleHByZXNzaW9uIGluIGJyZWFzdCBjYW5jZXIgcGF0aWVudHMiKQoKZ2dwbG90KGtwbmEyLCBhZXMoeCA9IGdyYWRlLCB5ID0gbG9nMmdlbmUsIGZpbGwgPSBub2RlKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoKSwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIpICsKICBsYWJzKAogICAgeCA9ICJIaXN0b2xvZ2ljIGdyYWRlIiwgeSA9ICJLUE5BMiBsb2cyIGV4cHJlc3Npb24iLAogICAgZmlsbCA9ICJMeW1waCBub2RlIHN0YXR1cyIKICApICsKICBnZ3RpdGxlKCJLUE5BMiBnZW5lIGV4cHJlc3Npb24gaW4gYnJlYXN0IGNhbmNlciBwYXRpZW50cyIpCmBgYAoKYGBge3J9CmZpdCA8LSBsbShsb2cyKGdlbmUpIH4gZ3JhZGUgKiBub2RlLCBkYXRhID0ga3BuYTIpCkV4cGxvcmVNb2RlbE1hdHJpeDo6VmlzdWFsaXplRGVzaWduKGtwbmEyLCB+IGdyYWRlICogbm9kZSkkcGxvdGxpc3RbWzFdXQpgYGAK