Creative Commons License

1 Intro

  • Until now: one outcome \(Y\) and a single predictor \(X\).
  • Often useful to use multiple predictors to model the response. e.g
  1. Association between X and Y is affected by confounder: Smoking and age by youngsters are confounded and they both affect the lung capacity
  2. Which group of variables is associated with a given outcome. E.g Habitat and human activity on the biodiversity of the rain forest. (Size, age, height of the wood \(\rightarrow\) assess all effects simultaneously.
  3. Prediction of outcome for individuals: use as many predictive information simultaneously. E.g prediction of risk on mortality is used on a daily basis in intensive care units to prioritise patient care.

\(\rightarrow\) Extend simple linear regression to multiple predictors.


1.1 Prostate cancer example

  • Prostate specific antigen (PSA) and a number of clinical variables for 97 males with radical prostatectomy.

  • Association of PSA by

    • tumor volume (lcavol)
    • prostate weight (lweight)
    • age
    • benign prostate hypertrophy (lbph)
    • seminal vesicle invasion (svi)
    • capsular penetration (lcp)
    • Gleason score (gleason)
    • precentage gleason score 4/5 (pgg45)

prostate <- read_csv("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/prostate.csv")
prostate
prostate$svi <- as.factor(prostate$svi)


2 Additive multiple linair model

Separate simple linair models, like

\[E(Y|X_v)=\alpha+\beta_v X_v\]

  • Association between lpsa en 1 variabele e.g lcavol.
  • More accurate predictions by simultaneously accounting for multiple predictors
  • Estimate for parameter \(\beta_v\) does not only capture the effect of tumor volume.
  • \(\beta_v\) average difference for log-psa for patients that differ in 1 unit of the log tumor volume.
  • Even if lcavol is not associated with lpsa then patients with a higher tumor volume can have a higher lpsa because their semen vesicles are affected (svi status 1). \(\rightarrow\) confounding.
  • Compare patients with same svi status
  • Is posible in multiple linear model

2.1 Statistical model

  • \(p-1\) predictors \(X_1,...,X_{p-1}\) and outcome \(Y\) for \(n\) subjecten.

\[\begin{equation} Y_i =\beta_0 + \beta_1 X_{i1} + ... +\beta_{p-1} X_{ip-1} + \epsilon_i \end{equation}\]

  • \(\beta_0,\beta_1,...,\beta_{p-1}\) unknown parameters
  • \(\epsilon_i\) residuals that cannot be explained by predictors
  • Estimation by least squares method

Model allows to

  1. predict the expected outcome for subjects given their values \(x_1,...,x_{p-1}\) for the predictor variables. \(E[Y\vert X_1=x_1, \ldots X_{p-1}=x_{p-1}]=\hat{\beta}_0+\hat{\beta}_1x_1+...+\hat{\beta}_{p-1}x_{p-1}\).
  2. Does the average outcome differ between two groups of patients that differ by \(\delta\) units in predictor \(X_j\) but have the same value for the remaining variables \(\{X_k,k=1,...,p,k\ne j\}\). \[ \begin{array}{l} E(Y|X_1=x_1,...,X_j=x_j+\delta,...,X_{p-1}=x_{p-1}) \\ \quad\quad - E(Y|X_1=x_1,...,X_j=x_j,...,X_{p-1}=x_{p-1}) \\\\ \quad =\beta_0 + \beta_1 x_1 + ... + \beta_j(x_j+\delta)+...+\beta_{p-1} x_{p-1}\\ \quad\quad- \beta_0 - \beta_1 x_1 - ... - \beta_jx_j-...-\beta_{p-1} x_{p-1} \\\\ \quad= \beta_j\delta \end{array} \]

Interpretation \(\beta_j\):

  • difference in mean outcome between subjects that differ in one unit of \(X_j\), but have the same value for the remaining predictors in the model.

or

  • Effect of predictor j corrected for the remaining predictors. e.g. effect of cancer volume correct for prostate weight and the svi status.

2.1.1 Prostate example

lmV <- lm(lpsa ~ lcavol, prostate)
summary(lmV)

Call:
lm(formula = lpsa ~ lcavol, data = prostate)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.67624 -0.41648  0.09859  0.50709  1.89672 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  1.50730    0.12194   12.36   <2e-16 ***
lcavol       0.71932    0.06819   10.55   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.7875 on 95 degrees of freedom
Multiple R-squared:  0.5394,    Adjusted R-squared:  0.5346 
F-statistic: 111.3 on 1 and 95 DF,  p-value: < 2.2e-16

lmVWS <- lm(lpsa ~ lcavol + lweight + svi, prostate)
summary(lmVWS)

Call:
lm(formula = lpsa ~ lcavol + lweight + svi, data = prostate)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.72966 -0.45767  0.02814  0.46404  1.57012 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.26807    0.54350  -0.493  0.62301    
lcavol       0.55164    0.07467   7.388  6.3e-11 ***
lweight      0.50854    0.15017   3.386  0.00104 ** 
sviinvasion  0.66616    0.20978   3.176  0.00203 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.7168 on 93 degrees of freedom
Multiple R-squared:  0.6264,    Adjusted R-squared:  0.6144 
F-statistic: 51.99 on 3 and 93 DF,  p-value: < 2.2e-16


3 Inference in multiple linear models

If data are representative than the least squares estimators for the intercept and slopes are unbiased. \[E[\hat \beta_j]=\beta_j,\quad j=0,\ldots,p-1\]

  • Gain insight in the distribution of the parameter estimators so as to generalize the effect in the sample to the population.

  • Additional assumptions are needed for inference.

  1. Linearity

  2. Independence

  3. Homoscedasticity of equal variance

  4. Normality: residuals \(\epsilon_i\) are normally distributed.

Under these assumptions: \[\epsilon_i \sim N(0,\sigma^2)\] and \[Y_i\sim N(\beta_0+\beta_1 X_{i1}+\ldots+\beta_{p-1} X_{ip-1},\sigma^2)\]


  • Slopes are again more precise if the predictor values have a larger range.

  • Conditional variance (\(\sigma^2\)) can again be estimated based on the mean squared error (MSE):

\[\hat\sigma^2=MSE=\frac{\sum\limits_{i=1}^n \left(y_i-\hat\beta_0-\hat\beta_1 X_{i1}-\ldots-\hat\beta_{p-1} X_{ip-1}\right)^2}{n-p}=\frac{\sum\limits_{i=1}^n e^2_i}{n-p}\]

Again hypothesis tests and confidence intervals by \[T_k=\frac{\hat{\beta}_k-\beta_k}{SE(\hat{\beta}_k)} \text{ met } k=0, \ldots, p-1\]

If all assumptions are satisfied than the statistics \(T_k\) t-distributed with \(n-p\) degrees of freedom.


When normality thus not hold, but lineariteit, independence and homoscedasticity are valid we can again adopt the CLT that states that statistic \(T_k\) is approximately normally distributed in large samples.


We can build confidence intervals on the slopes by: \[[\hat\beta_j - t_{n-p,\alpha/2} \text{SE}_{\hat\beta_j},\hat\beta_j + t_{n-p,\alpha/2} \text{SE}_{\hat\beta_j}]\]

confint(lmVWS)
                 2.5 %    97.5 %
(Intercept) -1.3473509 0.8112061
lcavol       0.4033628 0.6999144
lweight      0.2103288 0.8067430
sviinvasion  0.2495824 1.0827342

Formal hypothesis tests: \[H_0: \beta_j=0\] \[H_1: \beta_j\neq0\]

With test statistic \[T=\frac{\hat{\beta}_j-0}{SE(\hat{\beta}_j)}\] which follows a t-distribution with \(n-p\) degrees of freedom under \(H_0\)


summary(lmVWS)

Call:
lm(formula = lpsa ~ lcavol + lweight + svi, data = prostate)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.72966 -0.45767  0.02814  0.46404  1.57012 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.26807    0.54350  -0.493  0.62301    
lcavol       0.55164    0.07467   7.388  6.3e-11 ***
lweight      0.50854    0.15017   3.386  0.00104 ** 
sviinvasion  0.66616    0.20978   3.176  0.00203 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.7168 on 93 degrees of freedom
Multiple R-squared:  0.6264,    Adjusted R-squared:  0.6144 
F-statistic: 51.99 on 3 and 93 DF,  p-value: < 2.2e-16

3.1 Assess the model assumptions

plot(lmVWS)


3.2 The non additive multiple linear model

3.2.1 Interaction between two continuous variables

The previous model is additive because the contribution of the cancer volume on lpsa does not depend on the height of the prostate weight and the svi status.

The slope for lcavol does not depend on log prostate weight and svi.

\[ \beta_0 + \beta_v (x_{v}+\delta_v) + \beta_w x_{w} +\beta_s x_{s} - \beta_0 - \beta_v x_{v} - \beta_w x_{w} -\beta_s x_s = \beta_v \delta_v \]

The svi status and the log-prostategewicht (\(x_w\)) do not influence the contribution of the log-tumor volume (\(x_v\)) to the average log-PSA and vice versa.


  • It is however possible that the association of lpsa and lcavol depends on the prostate weight.
  • The average difference in lpsa for patients that differ in one unit of the log-tumor volume can for instance can be higher for patients wiht a high tumor weight then for those with a low tumor weight.
  • The effect of the tumor volume on the PSA depends on the prostate weight.

To model this interactie or effect modification we can add a product term of both variables to the model

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

This term quantifies the interactie-effect of predictors \(x_v\) en \(x_w\) on the mean outcome.

Terms \(\beta_vx_{iv}\) and \(\beta_wx_{iw}\) are referred to as main effects of predictors \(x_v\) and \(x_w\).


The difference in lpsa for patients that differ 1 unit in \(X_v\) and have an equal log prostate weight and the same svi status now becomes:

\[ \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 = \beta_0 + \beta_v (x_{v}+1) + \beta_w x_w +\beta_s x_{s} + \beta_{vw} (x_{v}+1) x_w - \beta_0 - \beta_v x_{v} - \beta_w x_w -\beta_s x_{s} - \beta_{vw} (x_{v}) x_w \\ \quad = \beta_v + \beta_{vw} x_w \end{array} \]


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


  • Note that the interaction effect that is observed is not statistically significant (p=0.4).
  • The main effects that are involved in the interaction cannot be interpreted separately from one another.
  • We will therefore remove non-significant interaction terms from the model.
  • Upon removal of non-significant interaction terms the main effects can be interpreted.

3.3 Interaction between a continuous variable and a factor variable

Interaction between lcavol \(\leftrightarrow\) svi and lweight \(\leftrightarrow\) svi.

The model becomes

\[Y=\beta_0+\beta_vX_v+\beta_wX_w+\beta_sX_s+\beta_{vs}X_vX_s + \beta_{ws}X_wX_s +\epsilon\]


lmVWS_IntVS_WS <- lm(lpsa ~ lcavol + lweight + svi + svi:lcavol + svi:lweight, data = prostate)
summary(lmVWS_IntVS_WS)

Call:
lm(formula = lpsa ~ lcavol + lweight + svi + svi:lcavol + svi:lweight, 
    data = prostate)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.50902 -0.44807  0.06455  0.45657  1.54354 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)         -0.52642    0.56793  -0.927 0.356422    
lcavol               0.54060    0.07821   6.912 6.38e-10 ***
lweight              0.58292    0.15699   3.713 0.000353 ***
sviinvasion          3.43653    1.93954   1.772 0.079771 .  
lcavol:sviinvasion   0.13467    0.25550   0.527 0.599410    
lweight:sviinvasion -0.82740    0.52224  -1.584 0.116592    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.7147 on 91 degrees of freedom
Multiple R-squared:  0.6367,    Adjusted R-squared:  0.6167 
F-statistic: 31.89 on 5 and 91 DF,  p-value: < 2.2e-16

Because \(X_S\) is a dummy variabele we obtain to distinct regression planes:

  1. Model for \(X_s=0\): \[Y=\beta_0+\beta_vX_v+\beta_wX_w + \epsilon\] where the main effects are the slope for lcavol and lweight
  2. and model for \(X_s=1\): \[\begin{array}{lcl} Y&=&\beta_0+\beta_vX_v+\beta_s+\beta_wX_w+\beta_{vs}X_v + \beta_{ws}X_w +\epsilon\\ &=& (\beta_0+\beta_s)+(\beta_v+\beta_{vs})X_v+(\beta_w+\beta_{ws})X_w+\epsilon \end{array}\] with intercept \(\beta_0+\beta_s\) and slopes \(\beta_v+\beta_{vs}\) and \(\beta_w+\beta_{ws}\)


4 ANOVA table

The total SSTot is again

\[ \text{SSTot} = \sum_{i=1}^n (Y_i - \bar{Y})^2. \]

The residual sum of squares remains similar \[ \text{SSE} = \sum_{i=1}^n (Y_i-\hat{Y}_i)^2. \]

Again the total sum of squares can be decomposed in , \[ \text{SSTot} = \text{SSR} + \text{SSE} , \] with \[ \text{SSR} = \sum_{i=1}^n (\hat{Y}_i-\bar{Y})^2. \]


We have following degrees of freedom and mean sum of squares:

  • SSTot has \(n-1\) degrees of freedom and \(\text{SSTot}/(n-1)\) is an estimator for the total variance in \(Y\) (marginal distribution of \(Y\)).
  • SSE has \(n-p\) degrees of freedom and \(\text{MSE}=\text{SSE}/(n-p)\) is an schatter for the residual variance of \(Y\) given the predictores (i.e. an estimator for the residual variance \(\sigma^2\) of the error term \(\epsilon\)).
  • SSR has \(p-1\) degrees of freedom and \(\text{MSR}=\text{SSR}/(p-1)\) is the mean sum of squares of the regression.

The determination coefficients remains as before, i.e. \[ R^2 = 1-\frac{\text{SSE}}{\text{SSTot}} = \frac{\text{SSR}}{\text{SSTot}} \] and is the fraction of the total variability that can be explained by the regression model.

Teststatistic \(F=\text{MSR}/\text{MSE}\) is under \(H_0:\beta_1=\ldots=\beta_{p-1}=0\) distributed by an F distribution: \(F_{p-1;n-p}\).



Call:
lm(formula = lpsa ~ lcavol + lweight + svi, data = prostate)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.72966 -0.45767  0.02814  0.46404  1.57012 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.26807    0.54350  -0.493  0.62301    
lcavol       0.55164    0.07467   7.388  6.3e-11 ***
lweight      0.50854    0.15017   3.386  0.00104 ** 
sviinvasion  0.66616    0.20978   3.176  0.00203 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.7168 on 93 degrees of freedom
Multiple R-squared:  0.6264,    Adjusted R-squared:  0.6144 
F-statistic: 51.99 on 3 and 93 DF,  p-value: < 2.2e-16

4.1 Additional sums of squares

Consider 2 models for the predictors \(x_1\) en \(x_2\): \[ Y_i = \beta_0+\beta_1 x_{i1} + \epsilon_i, \] with \(\epsilon_i\text{ iid } N(0,\sigma_1^{2})\), and \[ Y_i = \beta_0+\beta_1 x_{i1}+\beta_2 x_{i2} + \epsilon_i, \] with \(\epsilon_i\text{ iid } N(0,\sigma_2^{2})\).

for the first (gereduceerde) model we have decomposition \[ \text{SSTot} = \text{SSR}_1 + \text{SSE}_1 \] en for the second non-reduced model we have \[ \text{SSTot} = \text{SSR}_2 + \text{SSE}_2 \] (SSTot is of course the same because it only depends on the response and not of the models).


Definition of additional sum of squares The additional sum of squares of predictor \(x_2\) as compared to the model with only \(x_1\) as predictor is given by \[ \text{SSR}_{2\mid 1} = \text{SSE}_1-\text{SSE}_2=\text{SSR}_2-\text{SSR}_1. \]

Note that, \(\text{SSE}_1-\text{SSE}_2=\text{SSR}_2-\text{SSR}_1\) is triviaal is because of the decomposition of the total sum of squares.

The additional sum of squares \(\text{SSR}_{2\mid 1}\) can simply be interpreted as the additional variability that can be explained by adding predictor \(x_2\) to the model with predictor \(x_1\).

With this sum of squares we can further decompose the total sum of squares \[ \text{SSTot} = \text{SSR}_1+ \text{SSR}_{2\mid 1} + \text{SSE}. \] which follows directly from the definition \(\text{SSR}_{2\mid 1}\).


Extension: (\(s<p-1\)) \[ Y_i = \beta_0 + \beta_1 x_{i1} + \cdots + \beta_{s} x_{is} + \epsilon_i \] with \(\epsilon_i\text{ iid }N(0,\sigma_1^{2})\), and (\(s< q\leq p-1\)) \[ Y_i = \beta_0 + \beta_1 x_{i1} + \cdots + \beta_{s} x_{is} + \beta_{s+1} x_{is+1} + \cdots \beta_{q}x_{iq}+ \epsilon_i \] with \(\epsilon_i\text{ iid } N(0,\sigma_2^{2})\).

The additional sum of squares of predictor \(x_{s+1}, \ldots, x_q\) compared to a model with only predictors \(x_1,\ldots, x_{s}\) is given by

\[ \text{SSR}_{s+1, \ldots, q\mid 1,\ldots, s} = \text{SSE}_1-\text{SSE}_2=\text{SSR}_2-\text{SSR}_1. \]


4.1.1 Type I Sums of Squares

Suppose that \(p-1\) predictors are considered, and suppose the following sequence of models (\(s=2,\ldots, p-1\)) \[ Y_i = \beta_0 + \sum_{j=1}^{s} \beta_j x_{ij} + \epsilon_i \] wuth \(\epsilon_i\text{ iid } N(0,\sigma^{2})\).

  • The corresponding sum of squares are denoted as \(\text{SSR}_{s}\) and \(\text{SSE}_{s}\).
  • The sequence of models gives rise to the following sums of squares: \(\text{SSR}_{s\mid 1,\ldots, s-1}\).
  • The latter sum of squares is referred to as type I sums of squares. Note that they depend on the order in which the models were added to the model.

We can show for model Model with \(s=p-1\) that \[ \text{SSTot} = \text{SSR}_1 + \text{SSR}_{2\mid 1} + \text{SSR}_{3\mid 1,2} + \cdots + \text{SSR}_{p-1\mid 1,\ldots, p-2} + \text{SSE}, \] with \(\text{SSE}\) the residual sum of squares of the model with all \(p-1\) predictors \[ \text{SSR}_1 + \text{SSR}_{2\mid 1} + \text{SSR}_{3\mid 1,2} + \cdots + \text{SSR}_{p-1\mid 1,\ldots, p-2} = \text{SSR} \] with \(\text{SSR}\) the sum of squares of all \(p-1\) predictors.

  • The interpretation of each term depends on the order of the sequence of the regression models.

  • Each type I SSR involves 1 predictor and has 1 degree of freedom (note that multiple dummies for a factor are typically removed together).
  • For each type I SSR term the mean sum of squares is defined by \(\text{MSR}_{j\mid 1,\ldots, j-1}=\text{SSR}_{j\mid 1,\ldots, j-1}/1\).
  • And teststatistic \(F=\text{MSR}_{j\mid 1,\ldots, j-1}/\text{MSE}\) follows a \(F_{1;n-(j+1)}\) distribution under \(H_0:\beta_j=0\) with \(s=j\).
  • These sums of squares are the default sum of squares in the anova function of R.

4.1.2 Type III Sums of squares

Type III sum of squares for predictor \(x_j\) are given by the additional sum of squares \[ \text{SSR}_{j \mid 1,\ldots, j-1,j+1,\ldots, p-1} = \text{SSE}_1-\text{SSE}_2 \]

  • \(\text{SSE}_2\) the sum of squares of the residuals of the model with all \(p-1\) predictors.
  • \(\text{SSE}_1\) sum of squares of the residuals with all \(p-1\) predictors, except for predictor \(x_j\).

The type III sum of squares \(\text{SSR}_{j \mid 1,\ldots, j-1,j+1,\ldots, p-1}\) quantify the contribution in the total variance of the outcome explained by \(x_j\) that cannot be explained by the remaining \(p-2\) predictors.


The type III sum of squares has 1 degree of freedom because it involves 1 \(\beta\)-parameter.

For each type III SSR term the mean sum of squares is defined by \(\text{MSR}_{j \mid 1,\ldots, j-1,j+1,\ldots, p-1}=\text{SSR}_{j \mid 1,\ldots, j-1,j+1,\ldots, p-1}/1\).

Teststatistiek \(F=\text{MSR}_{j \mid 1,\ldots, j-1,j+1,\ldots, p-1}/\text{MSE}\) is \(F_{1;n-p}\) distributed under \(H_0:\beta_j=0\).

4.2 We can obtain these sums of squares using the Anova function from the car package.

library(car)
Anova(lmVWS, type = 3)

The p-values are identical to those of two-sided t-tests

Note, however, that all dummies for factors with multiple levels will be taken out of the model at once. So then the type III sum of squares will have as many degrees of freedom as the number of dummies and an omnibus test is performed for the effect of the factor.


5 Diagnostics

5.1 Multicollinearity


Call:
lm(formula = lpsa ~ lcavol + lweight + svi, data = prostate)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.72966 -0.45767  0.02814  0.46404  1.57012 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.26807    0.54350  -0.493  0.62301    
lcavol       0.55164    0.07467   7.388  6.3e-11 ***
lweight      0.50854    0.15017   3.386  0.00104 ** 
sviinvasion  0.66616    0.20978   3.176  0.00203 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.7168 on 93 degrees of freedom
Multiple R-squared:  0.6264,    Adjusted R-squared:  0.6144 
F-statistic: 51.99 on 3 and 93 DF,  p-value: < 2.2e-16


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

  • Estimates are different from those in the additive model and the standard errors are much higher!

  • This is caused by the multicollinearity problem.

  • If 2 predictors are strongly correlated than they share a lot of information.

  • It is therefore difficult to estimate the individual contribution of each predictor on the outcome.

  • Least squares estimators become instable.

  • Standard errors become inflated.

  • As long as we only do predictions on the basis of the regression model without extrapolating beyond the range of the predictors observed in the sample multicolinearity is not problematic.

  • But for inference it is problematic.


cor(cbind(prostate$lcavol, prostate$lweight, prostate$lcavol * prostate$lweight))
          [,1]      [,2]      [,3]
[1,] 1.0000000 0.1941283 0.9893127
[2,] 0.1941283 1.0000000 0.2835608
[3,] 0.9893127 0.2835608 1.0000000
  • High correlation between log-tumor volume and interaction.
  • It is a known problem for higher order terms (interactions and quadratic terms)

  • Detect multicollinearity based on the correlation matrix or scatterplot matrix is suboptimal.
  • In models with 3 or more predictors, say X1, X2, X3 we can have high multicollinearity while alle pairswise correlations between the predictors are low.
  • We also have multicollinearity if there is a high correlation between X1 and a linair combination of X2 and X3.

5.1.1 Variance inflation factor (VIF)

For parameter \(j\) in de regression model \[\textrm{VIF}_j=\left(1-R_j^2\right)^{-1}\]

  • In this expression \(R_j^2\) is the multiple determination coefficient of the linear regression of predictor j on the remaining predictors in the model.
  • VIF is 1 if predictor j is not linear associated with the remaining predictors in the model.
  • VIF is larger than 1 in all andere cases.
  • VIF is the factor with which the observed variance inflates as compared to a model for which all predictoren would be independend.
  • VIF > 10 \(\rightarrow\) strong multicollinearity.

5.1.2 Body fat example



Call:
lm(formula = Body_fat ~ Triceps + Thigh + Midarm, data = bodyfat)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.7263 -1.6111  0.3923  1.4656  4.1277 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept)  117.085     99.782   1.173    0.258
Triceps        4.334      3.016   1.437    0.170
Thigh         -2.857      2.582  -1.106    0.285
Midarm        -2.186      1.595  -1.370    0.190

Residual standard error: 2.48 on 16 degrees of freedom
Multiple R-squared:  0.8014,    Adjusted R-squared:  0.7641 
F-statistic: 21.52 on 3 and 16 DF,  p-value: 7.343e-06

vif(lmFat)
 Triceps    Thigh   Midarm 
708.8429 564.3434 104.6060 


Call:
lm(formula = Midarm ~ Triceps + Thigh, data = bodyfat)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.58200 -0.30625  0.02592  0.29526  0.56102 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 62.33083    1.23934   50.29   <2e-16 ***
Triceps      1.88089    0.04498   41.82   <2e-16 ***
Thigh       -1.60850    0.04316  -37.26   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.377 on 17 degrees of freedom
Multiple R-squared:  0.9904,    Adjusted R-squared:  0.9893 
F-statistic: 880.7 on 2 and 17 DF,  p-value: < 2.2e-16

We evaluate the VIF in the prostate cancer example for the additive model and the model with interactie.

vif(lmVWS)
  lcavol  lweight      svi 
1.447048 1.039188 1.409189 
vif(lmVWS_IntVW)
        lcavol        lweight            svi lcavol:lweight 
     76.193815       1.767121       1.426646      80.611657 
  • Inflation in interaction terms often caused because main effect get another interpretation.

5.2 Influential observations

set.seed(112358)
nobs <- 20
sdy <- 1
x <- seq(0, 1, length = nobs)
y <- 10 + 5 * x + rnorm(nobs, sd = sdy)
x1 <- c(x, 0.5)
y1 <- c(y, 10 + 5 * 1.5 + rnorm(1, sd = sdy))
x2 <- c(x, 1.5)
y2 <- c(y, y1[21])
x3 <- c(x, 1.5)
y3 <- c(y, 11)
plot(x, y, xlim = range(c(x1, x2, x3)), ylim = range(c(y1, y2, y3)))
points(c(x1[21], x2[21], x3[21]), c(y1[21], y2[21], y3[21]), pch = as.character(1:3), col = 2:4)
abline(lm(y ~ x), lwd = 2)
abline(lm(y1 ~ x1), col = 2, lty = 2, lwd = 2)
abline(lm(y2 ~ x2), col = 3, lty = 3, lwd = 2)
abline(lm(y3 ~ x3), col = 4, lty = 4, lwd = 2)
legend("topleft", col = 1:4, lty = 1:4, legend = paste("lm", c("", as.character(1:3))), text.col = 1:4)


  • It is not desirable that a single observation largely influences the result of a linear regression analysis

  • Diagnostics allow us to detect extreme observations.

  • Studentized residuals to spot outliers

  • Leverage to spot observations with extreem covariate pattern


5.2.1 Cook’s distance

  • A statistics to assess the influence the effect of a single observation on the regression analysis

  • Cook’s distance for observation i is diagnostic measure for this particular observation on all all predictions or on all estimated parameters. \[D_i=\frac{\sum_{j=1}^n(\hat{Y}_j-\hat{Y}_{j(i)})^2}{p\textrm{MSE}}\]

  • Observation \(i\) has a large influence on the regression parameters and predictions if the Cook’s distance \(D_i\) is large.

  • Extreme Cook’s distance if it is larger than the 50% quantile of an \(F_{p+1,n-(p+1)}\)-distribution.



  • Once we established that an observation is influential we can use DFBETAS to find the parameters for which the estimates are largely affected by the observation
  • DFBETAS of observatie i is a diagnostic measure for each model parameter separately. \[\textrm{DFBETAS}_{j(i)}=\frac{\hat{\beta}_{j}-\hat{\beta}_{j(i)}}{\textrm{SD}(\hat{\beta}_{j})}\]
  • DFBETAS is extreme when it is larger than 1 in small to moderate datasets or exceeds \(2/\sqrt{n}\) in large datasets.



6 Constrasts

  • In more complex designs that are modelled using general linear models one often has to assess multiple hypotheses.
  • Moreover these hypotheses can typically not always be translated into a test on one parameter, but in a linear combination of model parameters.
  • A linear combination of model parameters is also referred to as a contrast.

6.1 NHANES example

  • Suppose that researchers want to assess the association between age and bloodpressure.

  • Possibly this association will differ for females and males.

  • They want to assess following hypotheses:

    • Is there an association between age and blood pressure for females?
    • Is there an association between age and blood pressure for males?
    • Is the association between age and blood pressure different for females and males?

6.2 Model

We fit a model for the average systolic blood pressure (BPSysAve) using age, gender and the interaction between age and gender for adult caucasians from the NHANES study.

library(NHANES)
bpData <- NHANES %>%
  filter(
    Race1 == "White" &
      Age >= 18 &
      !is.na(BPSysAve)
  )

mBp1 <- lm(BPSysAve ~ Age * Gender, bpData)
par(mfrow = c(2, 2))
plot(mBp1)

  • Assumptions are not fullfilled!

    • lineariteit is ok
    • heteroscedasticity
    • No normality: distribution is skewed to the right .
    • Large dataset so we can adopt the CLT

6.2.1 Transformation

We fit a model using log2 transformed average systolic blood pressure (BPSysAve).

mBp2 <- lm(BPSysAve %>% log2() ~ Age * Gender, bpData)
par(mfrow = c(2, 2))
plot(mBp2)

  • Residuals are still heteroscedastic.

6.2.2 Remediate for heteroscedasticity

  • If the residual plot shows a cone we can get to valid inference for large samples by modeling the variance explicitly in function of the fitted response.

  • The inverse variance for each observation can than be used as a weight in the lm function.

  1. Model standard deviation in function of mean response.
  2. Do this by modeling absolute values of residuals in function of fitted values of model.
  3. We can than estimate the variance of Y for each observation by squaring the predictions for all observations using the model for the standard deviation.
  4. Inference remains valid asymptotically.
mSd <- lm(mBp1$res %>% abs() ~ mBp2$fitted)

We estimate the model again:

mBp3 <- lm(BPSysAve ~ Age * Gender, bpData, w = 1 / mSd$fitted^2)

Residuals are still heteroscedastic.

data.frame(residuals = mBp3$residuals, fit = mBp3$fitted) %>%
  ggplot(aes(fit, residuals)) +
  geom_point()

But we accounted for that using weights! Note that if we rescale the residuals using the standard deviation (multiplying them with the square root of the weight) we obtain rescaled residuals that are homoscedastic.

The model parameters are estimated using weighted least squares:

\[ SSE = \sum\limits_{i=1}^n w_i e_i^2\]

with \(w_i = 1/\hat \sigma^2_i\).

Weighted regression will correct for heteroscedasticity.

data.frame(scaled_residuals = mBp3$residuals / mSd$fitted, fit = mBp3$fitted) %>%
  ggplot(aes(fit, scaled_residuals)) +
  geom_point()

6.2.3 Inference

summary(mBp3)

Call:
lm(formula = BPSysAve ~ Age * Gender, data = bpData, weights = 1/mSd$fitted^2)

Weighted Residuals:
    Min      1Q  Median      3Q     Max 
-4.3642 -0.8494 -0.0940  0.7605  6.5701 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)    97.59709    0.63501 153.693  < 2e-16 ***
Age             0.44082    0.01505  29.294  < 2e-16 ***
Gendermale     13.36724    1.09017  12.262  < 2e-16 ***
Age:Gendermale -0.19115    0.02420  -7.899 3.45e-15 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.319 on 4828 degrees of freedom
Multiple R-squared:  0.2182,    Adjusted R-squared:  0.2178 
F-statistic: 449.3 on 3 and 4828 DF,  p-value: < 2.2e-16

The research questions translate to following nullhypotheses:

  1. Association between blood pressure and age for females? \[H_0: \beta_\text{Age} = 0 \text{ vs } H_1: \beta_\text{Age} \neq 0 \]

  2. Association between blood pressure and age for males? \[H_0: \beta_\text{Age} + \beta_\text{Age:Gendermale} = 0 \text{ vs } H_1: \beta_\text{Age} + \beta_\text{Age:Gendermale} \neq 0 \]

  3. Is the association between blood pressure and age different for females and males? \[H_0: \beta_\text{Age:Gendermale} = 0 \text{ vs } H_1: \beta_\text{Age:Gendermale} \neq 0 \]

  • We can assess hypotheses 1 and 3 immediately using the output of the model.
  • Hypotheses 2 is a linear combination of two parameters.
  • We also need multiple tests for assessing the association between sysBp and Age.

We can again use an Anova approach.

  1. We first assess the omnibus hypothesis that there is no association between age and blood pressure. \[ H_0: \beta_\text{Age} = \beta_\text{Age} + \beta_\text{Age:Gendermale} = \beta_\text{Age:Gendermale} = 0 \]
  • which simplifies to assessing

\[ H_0: \beta_\text{Age} = \beta_\text{Age:Gendermale} = 0 \]

  • We can do this by comparing two models: the full model with an effect for Gender, Age and Gender x Age interaction against a reduced model with only Gender.
  1. If we can reject this hypothesis we can again do a posthoc analysis for each of the contrasts.

6.2.3.1 Omnibus test

mBp0 <- lm(BPSysAve ~ Gender, bpData, w = 1 / mSd$fitted^2)
anova(mBp0, mBp3)

6.2.3.2 Posthoc tests

For the posthoc tests we will again build upon the multcomp package.

library(multcomp)
bpPosthoc <- glht(mBp3, linfct = c(
  "Age = 0",
  "Age + Age:Gendermale = 0",
  "Age:Gendermale = 0"
))
bpPosthoc %>% summary()

     Simultaneous Tests for General Linear Hypotheses

Fit: lm(formula = BPSysAve ~ Age * Gender, data = bpData, weights = 1/mSd$fitted^2)

Linear Hypotheses:
                          Estimate Std. Error t value Pr(>|t|)    
Age == 0                   0.44082    0.01505  29.294   <1e-10 ***
Age + Age:Gendermale == 0  0.24967    0.01895  13.175   <1e-10 ***
Age:Gendermale == 0       -0.19115    0.02420  -7.899   <1e-10 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Adjusted p values reported -- single-step method)
bpPosthocCI <- bpPosthoc %>% confint()
bpPosthocCI

     Simultaneous Confidence Intervals

Fit: lm(formula = BPSysAve ~ Age * Gender, data = bpData, weights = 1/mSd$fitted^2)

Quantile = 2.3154
95% family-wise confidence level
 

Linear Hypotheses:
                          Estimate lwr     upr    
Age == 0                   0.4408   0.4060  0.4757
Age + Age:Gendermale == 0  0.2497   0.2058  0.2936
Age:Gendermale == 0       -0.1911  -0.2472 -0.1351

Note that the glht function allows us to define the contrasts by explicitely defining the nullhypothese using the names of the model parameters.

6.2.3.3 Conclusion

We can conclude that the association between age and blood pressure is extremely significant (p << 0.001).

The blood pressure for females that differ in age is on average 0.44 mm Hg higher per year of age difference for the eldest female and is extremely significant (p << 0.001, 95% CI [0.41, 0.48].

The blood pressure for males that differ in age is on average 0.25 mm Hg higher per year of age difference for the eldest male and is extremely significant (p << 0.001, 95% CI [0.21, 0.29].

The average blood pressure difference between subjects that differ in age is on average 0.19 mm Hg/jaar higher for females than for males (p << 0.001, 95% CI [0.14, 0.25]).

LS0tCnRpdGxlOiAiOC4gTXVsdGlwbGUgcmVncmVzc2lvbiIKYXV0aG9yOiAiTGlldmVuIENsZW1lbnQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCi0tLQoKCjxhIHJlbD0ibGljZW5zZSIgaHJlZj0iaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMCI+PGltZyBhbHQ9IkNyZWF0aXZlIENvbW1vbnMgTGljZW5zZSIgc3R5bGU9ImJvcmRlci13aWR0aDowIiBzcmM9Imh0dHBzOi8vaS5jcmVhdGl2ZWNvbW1vbnMub3JnL2wvYnktbmMtc2EvNC4wLzg4eDMxLnBuZyIgLz48L2E+CgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIGNhY2hlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsCiAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlID0gVFJVRQopCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCgojIEludHJvCgotIFVudGlsIG5vdzogb25lIG91dGNvbWUgJFkkIGFuZCBhIHNpbmdsZSAgcHJlZGljdG9yICRYJC4KLSBPZnRlbiB1c2VmdWwgdG8gdXNlIG11bHRpcGxlIHByZWRpY3RvcnMgdG8gbW9kZWwgdGhlIHJlc3BvbnNlLiBlLmcKCjEuIEFzc29jaWF0aW9uIGJldHdlZW4gWCBhbmQgWSBpcyBhZmZlY3RlZCBieSBjb25mb3VuZGVyOiBTbW9raW5nIGFuZCBhZ2UgYnkgeW91bmdzdGVycyBhcmUgY29uZm91bmRlZCBhbmQgdGhleSBib3RoIGFmZmVjdCB0aGUgbHVuZyBjYXBhY2l0eQoyLiBXaGljaCBncm91cCBvZiB2YXJpYWJsZXMgaXMgYXNzb2NpYXRlZCB3aXRoIGEgZ2l2ZW4gb3V0Y29tZS4gRS5nIEhhYml0YXQgYW5kIGh1bWFuIGFjdGl2aXR5IG9uIHRoZSBiaW9kaXZlcnNpdHkgb2YgdGhlIHJhaW4gZm9yZXN0LiAoU2l6ZSwgYWdlLCBoZWlnaHQgb2YgdGhlIHdvb2QgJFxyaWdodGFycm93JCBhc3Nlc3MgYWxsIGVmZmVjdHMgc2ltdWx0YW5lb3VzbHkuCjMuIFByZWRpY3Rpb24gb2Ygb3V0Y29tZSBmb3IgaW5kaXZpZHVhbHM6IHVzZSBhcyBtYW55IHByZWRpY3RpdmUgaW5mb3JtYXRpb24gc2ltdWx0YW5lb3VzbHkuIEUuZyBwcmVkaWN0aW9uIG9mIHJpc2sgb24gbW9ydGFsaXR5IGlzIHVzZWQgb24gYSBkYWlseSBiYXNpcyBpbiBpbnRlbnNpdmUgY2FyZSB1bml0cyB0byBwcmlvcml0aXNlIHBhdGllbnQgY2FyZS4KCiRccmlnaHRhcnJvdyQgRXh0ZW5kIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiB0byBtdWx0aXBsZSBwcmVkaWN0b3JzLgoKLS0tCgojIyBQcm9zdGF0ZSBjYW5jZXIgZXhhbXBsZQoKLSBQcm9zdGF0ZSBzcGVjaWZpYyBhbnRpZ2VuIChQU0EpIGFuZCBhIG51bWJlciBvZiBjbGluaWNhbCB2YXJpYWJsZXMgZm9yIDk3IG1hbGVzIHdpdGggcmFkaWNhbCBwcm9zdGF0ZWN0b215LgotIEFzc29jaWF0aW9uIG9mIFBTQSBieQoKICAgIC0gdHVtb3Igdm9sdW1lIChsY2F2b2wpCiAgICAtIHByb3N0YXRlIHdlaWdodCAobHdlaWdodCkKICAgIC0gYWdlCiAgICAtIGJlbmlnbiBwcm9zdGF0ZSBoeXBlcnRyb3BoeSAgKGxicGgpCiAgICAtIHNlbWluYWwgdmVzaWNsZSBpbnZhc2lvbiAoc3ZpKQogICAgLSBjYXBzdWxhciBwZW5ldHJhdGlvbiAobGNwKQogICAgLSBHbGVhc29uIHNjb3JlIChnbGVhc29uKQogICAgLSBwcmVjZW50YWdlIGdsZWFzb24gc2NvcmUgNC81IChwZ2c0NSkKCi0tLQoKYGBge3J9CnByb3N0YXRlIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vR1RQQi9QU0xTMjAvbWFzdGVyL2RhdGEvcHJvc3RhdGUuY3N2IikKcHJvc3RhdGUKcHJvc3RhdGUkc3ZpIDwtIGFzLmZhY3Rvcihwcm9zdGF0ZSRzdmkpCmBgYAoKLS0tCgpgYGB7ciAsIG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpsaWJyYXJ5KEdHYWxseSkKcHJvc3RhdGUgJT4lCiAgc2VsZWN0KC1wZ2c0NSkgJT4lCiAgZ2dwYWlycygpCmBgYAoKLS0tCgojIEFkZGl0aXZlICBtdWx0aXBsZSBsaW5haXIgbW9kZWwKClNlcGFyYXRlIHNpbXBsZSBsaW5haXIgbW9kZWxzLCBsaWtlCgokJEUoWXxYX3YpPVxhbHBoYStcYmV0YV92IFhfdiQkCgotIEFzc29jaWF0aW9uIGJldHdlZW4gbHBzYSBlbiAxIHZhcmlhYmVsZSBlLmcgbGNhdm9sLgotIE1vcmUgYWNjdXJhdGUgcHJlZGljdGlvbnMgYnkgc2ltdWx0YW5lb3VzbHkgYWNjb3VudGluZyBmb3IgbXVsdGlwbGUgcHJlZGljdG9ycwotIEVzdGltYXRlIGZvciBwYXJhbWV0ZXIgJFxiZXRhX3YkIGRvZXMgbm90IG9ubHkgY2FwdHVyZSB0aGUgZWZmZWN0IG9mIHR1bW9yIHZvbHVtZS4KLSAkXGJldGFfdiQgYXZlcmFnZSBkaWZmZXJlbmNlIGZvciBsb2ctcHNhIGZvciBwYXRpZW50cyB0aGF0IGRpZmZlciBpbiAxIHVuaXQgb2YgdGhlIGxvZyB0dW1vciB2b2x1bWUuCi0gRXZlbiBpZiBsY2F2b2wgaXMgbm90IGFzc29jaWF0ZWQgd2l0aCBscHNhIHRoZW4gcGF0aWVudHMgd2l0aCBhIGhpZ2hlciB0dW1vciB2b2x1bWUgY2FuIGhhdmUgYSBoaWdoZXIgbHBzYSBiZWNhdXNlIHRoZWlyIHNlbWVuIHZlc2ljbGVzIGFyZSBhZmZlY3RlZCAoc3ZpIHN0YXR1cyAxKS4KJFxyaWdodGFycm93JCBjb25mb3VuZGluZy4KLSBDb21wYXJlIHBhdGllbnRzIHdpdGggc2FtZSBzdmkgc3RhdHVzCi0gSXMgcG9zaWJsZSBpbiBtdWx0aXBsZSBsaW5lYXIgbW9kZWwKCi0tLQoKIyMgU3RhdGlzdGljYWwgbW9kZWwKCi0gJHAtMSQgcHJlZGljdG9ycyAkWF8xLC4uLixYX3twLTF9JCBhbmQgb3V0Y29tZSAkWSQgZm9yICRuJCBzdWJqZWN0ZW4uCgpcYmVnaW57ZXF1YXRpb259CllfaSA9XGJldGFfMCArIFxiZXRhXzEgWF97aTF9ICsgLi4uICtcYmV0YV97cC0xfSBYX3tpcC0xfSArIFxlcHNpbG9uX2kKXGVuZHtlcXVhdGlvbn0KCi0gJFxiZXRhXzAsXGJldGFfMSwuLi4sXGJldGFfe3AtMX0kIHVua25vd24gcGFyYW1ldGVycwotICRcZXBzaWxvbl9pJCByZXNpZHVhbHMgdGhhdCBjYW5ub3QgYmUgZXhwbGFpbmVkIGJ5IHByZWRpY3RvcnMKLSBFc3RpbWF0aW9uIGJ5ICpsZWFzdCBzcXVhcmVzIG1ldGhvZCoKCi0tLQoKTW9kZWwgYWxsb3dzIHRvCgoxLiBwcmVkaWN0IHRoZSBleHBlY3RlZCBvdXRjb21lIGZvciBzdWJqZWN0cyBnaXZlbiB0aGVpciB2YWx1ZXMgJHhfMSwuLi4seF97cC0xfSQgZm9yIHRoZSBwcmVkaWN0b3IgdmFyaWFibGVzLgokRVtZXHZlcnQgWF8xPXhfMSwgXGxkb3RzIFhfe3AtMX09eF97cC0xfV09XGhhdHtcYmV0YX1fMCtcaGF0e1xiZXRhfV8xeF8xKy4uLitcaGF0e1xiZXRhfV97cC0xfXhfe3AtMX0kLgoyLiBEb2VzIHRoZSBhdmVyYWdlIG91dGNvbWUgZGlmZmVyIGJldHdlZW4gdHdvIGdyb3VwcyBvZiBwYXRpZW50cyB0aGF0IGRpZmZlciBieSAkXGRlbHRhJCB1bml0cyBpbiBwcmVkaWN0b3IgJFhfaiQgYnV0IGhhdmUgdGhlIHNhbWUgdmFsdWUgZm9yIHRoZSByZW1haW5pbmcgdmFyaWFibGVzICRce1hfayxrPTEsLi4uLHAsa1xuZSBqXH0kLgokJApcYmVnaW57YXJyYXl9e2x9CkUoWXxYXzE9eF8xLC4uLixYX2o9eF9qK1xkZWx0YSwuLi4sWF97cC0xfT14X3twLTF9KSBcXApccXVhZFxxdWFkIC0gRShZfFhfMT14XzEsLi4uLFhfaj14X2osLi4uLFhfe3AtMX09eF97cC0xfSkgXFxcXApccXVhZCA9XGJldGFfMCArIFxiZXRhXzEgeF8xICsgLi4uICsgXGJldGFfaih4X2orXGRlbHRhKSsuLi4rXGJldGFfe3AtMX0geF97cC0xfVxcClxxdWFkXHF1YWQtIFxiZXRhXzAgLSBcYmV0YV8xIHhfMSAtIC4uLiAtIFxiZXRhX2p4X2otLi4uLVxiZXRhX3twLTF9IHhfe3AtMX0gXFxcXApccXVhZD0gXGJldGFfalxkZWx0YQpcZW5ke2FycmF5fQokJAoKSW50ZXJwcmV0YXRpb24gJFxiZXRhX2okOgoKLSBkaWZmZXJlbmNlIGluIG1lYW4gb3V0Y29tZSBiZXR3ZWVuIHN1YmplY3RzIHRoYXQgZGlmZmVyIGluIG9uZSB1bml0IG9mICRYX2okLCBidXQgaGF2ZSB0aGUgc2FtZSB2YWx1ZSBmb3IgdGhlIHJlbWFpbmluZyBwcmVkaWN0b3JzIGluIHRoZSBtb2RlbC4KCm9yCgotIEVmZmVjdCBvZiBwcmVkaWN0b3IgaiBjb3JyZWN0ZWQgZm9yIHRoZSByZW1haW5pbmcgcHJlZGljdG9ycy4gIGUuZy4gZWZmZWN0IG9mIGNhbmNlciB2b2x1bWUgY29ycmVjdCBmb3IgcHJvc3RhdGUgd2VpZ2h0IGFuZCB0aGUgc3ZpIHN0YXR1cy4KCi0tLQoKIyMjIFByb3N0YXRlIGV4YW1wbGUKCmBgYHtyfQpsbVYgPC0gbG0obHBzYSB+IGxjYXZvbCwgcHJvc3RhdGUpCnN1bW1hcnkobG1WKQpgYGAKCi0tLQoKYGBge3J9CmxtVldTIDwtIGxtKGxwc2EgfiBsY2F2b2wgKyBsd2VpZ2h0ICsgc3ZpLCBwcm9zdGF0ZSkKc3VtbWFyeShsbVZXUykKYGBgCgotLS0KCmBgYHtyIG91dC53aWR0aD0nODAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CmxpYnJhcnkocGxvdDNEKQpncmlkLmxpbmVzIDwtIDEwCnggPC0gcHJvc3RhdGUkbGNhdm9sCnkgPC0gcHJvc3RhdGUkbHdlaWdodAp6IDwtIHByb3N0YXRlJGxwc2EKZml0IDwtIGxtKHogfiB4ICsgeSArIHN2aSwgZGF0YSA9IHByb3N0YXRlKQp4LnByZWQgPC0gc2VxKG1pbih4KSwgbWF4KHgpLCBsZW5ndGgub3V0ID0gZ3JpZC5saW5lcykKeS5wcmVkIDwtIHNlcShtaW4oeSksIG1heCh5KSwgbGVuZ3RoLm91dCA9IGdyaWQubGluZXMpCgojIGZpdHRlZCBwb2ludHMgZm9yIGRyb3BsaW5lcyB0byBzdXJmYWNlCnRoIDwtIDIwCnBoIDwtIDUKc2NhdHRlcjNEKHgsIHksIHosCiAgcGNoID0gMTYsIGNvbCA9IGMoImRhcmtibHVlIiwgInJlZCIpW2FzLmRvdWJsZShwcm9zdGF0ZSRzdmkpXSwgY2V4ID0gLjc1LAogIHRoZXRhID0gdGgsIHBoaSA9IHBoLCB0aWNrdHlwZSA9ICJkZXRhaWxlZCIsCiAgeGxhYiA9ICJsY2F2b2wiLCB5bGFiID0gImx3ZWlnaHQiLCB6bGFiID0gImxwc2EiLAogIGNvbHZhciA9IEZBTFNFLCBidHkgPSAiZyIKKQoKZm9yIChpIGluIDE6bnJvdyhwcm9zdGF0ZSkpIHsKICBsaW5lczNEKHggPSByZXAocHJvc3RhdGUkbGNhdm9sW2ldLCAyKSwgeSA9IHJlcChwcm9zdGF0ZSRsd2VpZ2h0W2ldLCAyKSwgeiA9IGMocHJvc3RhdGUkbHBzYVtpXSwgbG1WV1MkZml0W2ldKSwgY29sID0gYygiZGFya2JsdWUiLCAicmVkIilbYXMuZG91YmxlKHByb3N0YXRlJHN2aSlbaV1dLCBhZGQgPSBUUlVFLCBsdHkgPSAyKQp9Cgp6LnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCwgeSkgewogIGxtVldTJGNvZWZbMV0gKyBsbVZXUyRjb2VmWzJdICogeCArIGxtVldTJGNvZWZbM10gKiB5Cn0pCngucHJlZDNEIDwtIG91dGVyKHgucHJlZCwgeS5wcmVkLCBmdW5jdGlvbih4LCB5KSB4KQp5LnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCwgeSkgeSkKc3VyZjNEKHgucHJlZDNELCB5LnByZWQzRCwgei5wcmVkM0QsIGNvbCA9ICJibHVlIiwgZmFjZXRzID0gTkEsIGFkZCA9IFRSVUUpCnoyLnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCwgeSkgewogIGxtVldTJGNvZWZbMV0gKyBsbVZXUyRjb2VmWzRdICsgbG1WV1MkY29lZlsyXSAqIHggKyBsbVZXUyRjb2VmWzNdICogeQp9KQpzdXJmM0QoeC5wcmVkM0QsIHkucHJlZDNELCB6Mi5wcmVkM0QsIGNvbCA9ICJyZWQiLCBmYWNldHMgPSBOQSwgYWRkID0gVFJVRSkKYGBgCgotLS0KCiMgSW5mZXJlbmNlIGluIG11bHRpcGxlIGxpbmVhciBtb2RlbHMKCklmIGRhdGEgYXJlIHJlcHJlc2VudGF0aXZlIHRoYW4gdGhlIGxlYXN0IHNxdWFyZXMgZXN0aW1hdG9ycyBmb3IgdGhlIGludGVyY2VwdCBhbmQgc2xvcGVzIGFyZSB1bmJpYXNlZC4KJCRFW1xoYXQgXGJldGFfal09XGJldGFfaixccXVhZCBqPTAsXGxkb3RzLHAtMSQkCgotIEdhaW4gaW5zaWdodCBpbiB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBwYXJhbWV0ZXIgZXN0aW1hdG9ycyBzbyBhcyB0byBnZW5lcmFsaXplIHRoZSBlZmZlY3QgaW4gdGhlIHNhbXBsZSB0byB0aGUgcG9wdWxhdGlvbi4KCi0gQWRkaXRpb25hbCBhc3N1bXB0aW9ucyBhcmUgbmVlZGVkIGZvciBpbmZlcmVuY2UuCgoxLiAqTGluZWFyaXR5KgoKMi4gKkluZGVwZW5kZW5jZSoKCjMuICpIb21vc2NlZGFzdGljaXR5KiBvZiAqZXF1YWwgdmFyaWFuY2UqCjQuICpOb3JtYWxpdHkqOiByZXNpZHVhbHMgJFxlcHNpbG9uX2kkIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZC4KClVuZGVyIHRoZXNlIGFzc3VtcHRpb25zOgokJFxlcHNpbG9uX2kgXHNpbSBOKDAsXHNpZ21hXjIpJCQKYW5kCiQkWV9pXHNpbSBOKFxiZXRhXzArXGJldGFfMSBYX3tpMX0rXGxkb3RzK1xiZXRhX3twLTF9IFhfe2lwLTF9LFxzaWdtYV4yKSQkCgotLS0KCi0gU2xvcGVzIGFyZSBhZ2FpbiBtb3JlIHByZWNpc2UgaWYgdGhlIHByZWRpY3RvciB2YWx1ZXMgaGF2ZSBhIGxhcmdlciByYW5nZS4KCi0gQ29uZGl0aW9uYWwgdmFyaWFuY2UgKCRcc2lnbWFeMiQpIGNhbiBhZ2FpbiBiZSBlc3RpbWF0ZWQgYmFzZWQgb24gdGhlICptZWFuIHNxdWFyZWQgZXJyb3IqIChNU0UpOgoKJCRcaGF0XHNpZ21hXjI9TVNFPVxmcmFje1xzdW1cbGltaXRzX3tpPTF9Xm4gXGxlZnQoeV9pLVxoYXRcYmV0YV8wLVxoYXRcYmV0YV8xIFhfe2kxfS1cbGRvdHMtXGhhdFxiZXRhX3twLTF9IFhfe2lwLTF9XHJpZ2h0KV4yfXtuLXB9PVxmcmFje1xzdW1cbGltaXRzX3tpPTF9Xm4gZV4yX2l9e24tcH0kJAoKQWdhaW4gaHlwb3RoZXNpcyB0ZXN0cyBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMgYnkKJCRUX2s9XGZyYWN7XGhhdHtcYmV0YX1fay1cYmV0YV9rfXtTRShcaGF0e1xiZXRhfV9rKX0gXHRleHR7IG1ldCB9IGs9MCwgXGxkb3RzLCBwLTEkJAoKSWYgYWxsIGFzc3VtcHRpb25zIGFyZSBzYXRpc2ZpZWQgdGhhbiB0aGUgc3RhdGlzdGljcyAkVF9rJCB0LWRpc3RyaWJ1dGVkIHdpdGggJG4tcCQgZGVncmVlcyBvZiBmcmVlZG9tLgoKLS0tCgpXaGVuIG5vcm1hbGl0eSB0aHVzIG5vdCBob2xkLCBidXQgbGluZWFyaXRlaXQsIGluZGVwZW5kZW5jZSBhbmQgaG9tb3NjZWRhc3RpY2l0eSBhcmUgdmFsaWQgd2UgY2FuIGFnYWluIGFkb3B0IHRoZSBDTFQgdGhhdCBzdGF0ZXMgdGhhdCBzdGF0aXN0aWMgJFRfayQgaXMgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZCBpbiBsYXJnZSBzYW1wbGVzLgoKLS0tCgpXZSBjYW4gYnVpbGQgY29uZmlkZW5jZSBpbnRlcnZhbHMgb24gdGhlIHNsb3BlcyBieToKJCRbXGhhdFxiZXRhX2ogLSB0X3tuLXAsXGFscGhhLzJ9IFx0ZXh0e1NFfV97XGhhdFxiZXRhX2p9LFxoYXRcYmV0YV9qICsgdF97bi1wLFxhbHBoYS8yfSBcdGV4dHtTRX1fe1xoYXRcYmV0YV9qfV0kJAoKYGBge3J9CmNvbmZpbnQobG1WV1MpCmBgYAoKLS0tCgpGb3JtYWwgaHlwb3RoZXNpcyB0ZXN0czoKJCRIXzA6IFxiZXRhX2o9MCQkCiQkSF8xOiBcYmV0YV9qXG5lcTAkJAoKV2l0aCB0ZXN0IHN0YXRpc3RpYwokJFQ9XGZyYWN7XGhhdHtcYmV0YX1fai0wfXtTRShcaGF0e1xiZXRhfV9qKX0kJAp3aGljaCBmb2xsb3dzIGEgdC1kaXN0cmlidXRpb24gd2l0aCAkbi1wJCBkZWdyZWVzIG9mIGZyZWVkb20gdW5kZXIgJEhfMCQKCi0tLQoKYGBge3J9CnN1bW1hcnkobG1WV1MpCmBgYAoKLS0tCgojIyBBc3Nlc3MgdGhlIG1vZGVsIGFzc3VtcHRpb25zCgpgYGB7cn0KcGxvdChsbVZXUykKYGBgCgotLS0KCiMjIFRoZSBub24gYWRkaXRpdmUgbXVsdGlwbGUgbGluZWFyIG1vZGVsCiMjIyBJbnRlcmFjdGlvbiBiZXR3ZWVuIHR3byBjb250aW51b3VzIHZhcmlhYmxlcwoKVGhlIHByZXZpb3VzIG1vZGVsIGlzIGFkZGl0aXZlIGJlY2F1c2UgdGhlIGNvbnRyaWJ1dGlvbiBvZiB0aGUgY2FuY2VyIHZvbHVtZSBvbiBscHNhIGRvZXMgbm90IGRlcGVuZCBvbiB0aGUgaGVpZ2h0IG9mIHRoZSBwcm9zdGF0ZSB3ZWlnaHQgYW5kIHRoZSBzdmkgc3RhdHVzLgoKVGhlIHNsb3BlIGZvciBsY2F2b2wgZG9lcyBub3QgZGVwZW5kIG9uIGxvZyBwcm9zdGF0ZSB3ZWlnaHQgYW5kIHN2aS4KCiQkClxiZXRhXzAgKyBcYmV0YV92ICh4X3t2fStcZGVsdGFfdikgKyBcYmV0YV93IHhfe3d9ICtcYmV0YV9zIHhfe3N9IC0gXGJldGFfMCAtIFxiZXRhX3YgeF97dn0gLSBcYmV0YV93IHhfe3d9IC1cYmV0YV9zIHhfcyA9IFxiZXRhX3YgXGRlbHRhX3YKJCQKClRoZSBzdmkgc3RhdHVzIGFuZCB0aGUgbG9nLXByb3N0YXRlZ2V3aWNodCAoJHhfdyQpIGRvIG5vdCBpbmZsdWVuY2UgdGhlIGNvbnRyaWJ1dGlvbiBvZiB0aGUgbG9nLXR1bW9yIHZvbHVtZSAoJHhfdiQpIHRvIHRoZSBhdmVyYWdlIGxvZy1QU0EgYW5kIHZpY2UgdmVyc2EuCgotLS0KCi0gSXQgaXMgaG93ZXZlciBwb3NzaWJsZSB0aGF0IHRoZSBhc3NvY2lhdGlvbiBvZiBscHNhIGFuZCBsY2F2b2wgZGVwZW5kcyBvbiB0aGUgcHJvc3RhdGUgd2VpZ2h0LgotIFRoZSBhdmVyYWdlIGRpZmZlcmVuY2UgaW4gbHBzYSBmb3IgcGF0aWVudHMgdGhhdCBkaWZmZXIgaW4gb25lIHVuaXQgb2YgdGhlIGxvZy10dW1vciB2b2x1bWUgY2FuIGZvciBpbnN0YW5jZSBjYW4gYmUgaGlnaGVyIGZvciBwYXRpZW50cyB3aWh0IGEgaGlnaCB0dW1vciB3ZWlnaHQgdGhlbiBmb3IgdGhvc2Ugd2l0aCBhIGxvdyB0dW1vciB3ZWlnaHQuCi0gVGhlIGVmZmVjdCBvZiB0aGUgdHVtb3Igdm9sdW1lIG9uIHRoZSBQU0EgZGVwZW5kcyBvbiB0aGUgcHJvc3RhdGUgd2VpZ2h0LgoKVG8gbW9kZWwgdGhpcyAqKmludGVyYWN0aWUqKiBvciAqKmVmZmVjdCBtb2RpZmljYXRpb24qKiB3ZSBjYW4gYWRkIGEgcHJvZHVjdCB0ZXJtIG9mIGJvdGggdmFyaWFibGVzIHRvIHRoZSBtb2RlbAoKJCQKWV9pID0gXGJldGFfMCArIFxiZXRhX3YgeF97aXZ9ICsgXGJldGFfdyB4X3tpd30gK1xiZXRhX3MgeF97aXN9ICsgXGJldGFfe3Z3fSB4X3tpdn14X3tpd30gK1xlcHNpbG9uX2kKJCQKClRoaXMgdGVybSBxdWFudGlmaWVzIHRoZSAqaW50ZXJhY3RpZS1lZmZlY3QqIG9mIHByZWRpY3RvcnMgJHhfdiQgZW4gJHhfdyQgb24gdGhlIG1lYW4gb3V0Y29tZS4KClRlcm1zICRcYmV0YV92eF97aXZ9JCBhbmQgJFxiZXRhX3d4X3tpd30kIGFyZSByZWZlcnJlZCB0byBhcyAqbWFpbiBlZmZlY3RzKiBvZiBwcmVkaWN0b3JzICR4X3YkIGFuZCAkeF93JC4KCi0tLQoKVGhlIGRpZmZlcmVuY2UgaW4gbHBzYSBmb3IgcGF0aWVudHMgdGhhdCBkaWZmZXIgMSB1bml0IGluICRYX3YkIGFuZCBoYXZlIGFuIGVxdWFsIGxvZyBwcm9zdGF0ZSB3ZWlnaHQgYW5kIHRoZSBzYW1lIHN2aSBzdGF0dXMgbm93IGJlY29tZXM6CgokJApcYmVnaW57YXJyYXl9e2x9CkUoWSB8IFhfdj14X3YgKzEsIFhfdz14X3csIFhfcz14X3MpIC0gRShZIHwgWF92PXhfdiwgWF93PXhfdywgWF9zPXhfcykgXFwKXHF1YWQgPSBcYmV0YV8wICsgXGJldGFfdiAoeF97dn0rMSkgKyBcYmV0YV93IHhfdyArXGJldGFfcyB4X3tzfSArIFxiZXRhX3t2d30gKHhfe3Z9KzEpIHhfdyAtIFxiZXRhXzAgLSBcYmV0YV92IHhfe3Z9IC0gXGJldGFfdyB4X3cgLVxiZXRhX3MgeF97c30gLSBcYmV0YV97dnd9ICh4X3t2fSkgeF93IFxcClxxdWFkID0gXGJldGFfdiArICBcYmV0YV97dnd9IHhfdwogXGVuZHthcnJheX0KICQkCgotLS0KCmBgYHtyfQpsbVZXU19JbnRWVyA8LSBsbShscHNhIH4gbGNhdm9sICsgbHdlaWdodCArIHN2aSArIGxjYXZvbDpsd2VpZ2h0LCBwcm9zdGF0ZSkKc3VtbWFyeShsbVZXU19JbnRWVykKYGBgCgotLS0KCgpgYGB7ciBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0KcGFyKG1mcm93ID0gYygxLCAyKSkKbGlicmFyeShwbG90M0QpCmdyaWQubGluZXMgPC0gMTAKeCA8LSBwcm9zdGF0ZSRsY2F2b2wKeSA8LSBwcm9zdGF0ZSRsd2VpZ2h0CnogPC0gcHJvc3RhdGUkbHBzYQpmaXQgPC0gbG0oeiB+IHggKyB5ICsgc3ZpLCBkYXRhID0gcHJvc3RhdGUpCngucHJlZCA8LSBzZXEobWluKHgpLCBtYXgoeCksIGxlbmd0aC5vdXQgPSBncmlkLmxpbmVzKQp5LnByZWQgPC0gc2VxKG1pbih5KSwgbWF4KHkpLCBsZW5ndGgub3V0ID0gZ3JpZC5saW5lcykKCiMgZml0dGVkIHBvaW50cyBmb3IgZHJvcGxpbmVzIHRvIHN1cmZhY2UKdGggPC0gLTI1CnBoIDwtIDUKc2NhdHRlcjNEKHgsIHksIHosCiAgcGNoID0gMTYsIGNvbCA9IGMoImRhcmtibHVlIiwgInJlZCIpW2FzLmRvdWJsZShwcm9zdGF0ZSRzdmkpXSwgY2V4ID0gLjc1LAogIHRoZXRhID0gdGgsIHBoaSA9IHBoLCB0aWNrdHlwZSA9ICJkZXRhaWxlZCIsCiAgeGxhYiA9ICJsY2F2b2wiLCB5bGFiID0gImx3ZWlnaHQiLCB6bGFiID0gImxwc2EiLAogIGNvbHZhciA9IEZBTFNFLCBidHkgPSAiZyIsIG1haW4gPSAiQWRkaXRpdmUgbW9kZWwiCikKCmZvciAoaSBpbiB3aGljaChwcm9zdGF0ZSRzdmkgPT0gImhlYWx0aHkiKSkgewogIGxpbmVzM0QoeCA9IHJlcChwcm9zdGF0ZSRsY2F2b2xbaV0sIDIpLCB5ID0gcmVwKHByb3N0YXRlJGx3ZWlnaHRbaV0sIDIpLCB6ID0gYyhwcm9zdGF0ZSRscHNhW2ldLCBsbVZXUyRmaXRbaV0pLCBjb2wgPSBjKCJkYXJrYmx1ZSIsICJyZWQiKVthcy5kb3VibGUocHJvc3RhdGUkc3ZpKVtpXV0sIGFkZCA9IFRSVUUsIGx0eSA9IDIpCn0KCnoucHJlZDNEIDwtIG91dGVyKHgucHJlZCwgeS5wcmVkLCBmdW5jdGlvbih4LCB5KSB7CiAgbG1WV1MkY29lZlsxXSArIGxtVldTJGNvZWZbMl0gKiB4ICsgbG1WV1MkY29lZlszXSAqIHkKfSkKeC5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLCB5LnByZWQsIGZ1bmN0aW9uKHgsIHkpIHgpCnkucHJlZDNEIDwtIG91dGVyKHgucHJlZCwgeS5wcmVkLCBmdW5jdGlvbih4LCB5KSB5KQpzdXJmM0QoeC5wcmVkM0QsIHkucHJlZDNELCB6LnByZWQzRCwgY29sID0gImJsdWUiLCBmYWNldHMgPSBOQSwgYWRkID0gVFJVRSkKCgpzY2F0dGVyM0QoeCwgeSwgeiwKICBwY2ggPSAxNiwgY29sID0gYygiZGFya2JsdWUiLCAicmVkIilbYXMuZG91YmxlKHByb3N0YXRlJHN2aSldLCBjZXggPSAuNzUsCiAgdGhldGEgPSB0aCwgcGhpID0gcGgsIHRpY2t0eXBlID0gImRldGFpbGVkIiwKICB4bGFiID0gImxjYXZvbCIsIHlsYWIgPSAibHdlaWdodCIsIHpsYWIgPSAibHBzYSIsCiAgY29sdmFyID0gRkFMU0UsIGJ0eSA9ICJnIiwgbWFpbiA9ICJNb2RlbCBtZXQgbGNhdm9sOmx3ZWlnaHQgaW50ZXJhY3RpZSIKKQoKZm9yIChpIGluIHdoaWNoKHByb3N0YXRlJHN2aSA9PSAiaGVhbHRoeSIpKSB7CiAgbGluZXMzRCh4ID0gcmVwKHByb3N0YXRlJGxjYXZvbFtpXSwgMiksIHkgPSByZXAocHJvc3RhdGUkbHdlaWdodFtpXSwgMiksIHogPSBjKHByb3N0YXRlJGxwc2FbaV0sIGxtVldTX0ludFZXJGZpdFtpXSksIGNvbCA9IGMoImRhcmtibHVlIiwgInJlZCIpW2FzLmRvdWJsZShwcm9zdGF0ZSRzdmkpW2ldXSwgYWRkID0gVFJVRSwgbHR5ID0gMikKfQoKei5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLCB5LnByZWQsIGZ1bmN0aW9uKHgsIHkpIHsKICBsbVZXU19JbnRWVyRjb2VmWzFdICsgbG1WV1NfSW50VlckY29lZlsyXSAqIHggKyBsbVZXU19JbnRWVyRjb2VmWzNdICogeSArIGxtVldTX0ludFZXJGNvZWZbNV0gKiB4ICogeQp9KQp4LnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCwgeSkgeCkKeS5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLCB5LnByZWQsIGZ1bmN0aW9uKHgsIHkpIHkpCnN1cmYzRCh4LnByZWQzRCwgeS5wcmVkM0QsIHoucHJlZDNELCBjb2wgPSAiYmx1ZSIsIGZhY2V0cyA9IE5BLCBhZGQgPSBUUlVFKQpgYGAKCi0tLQoKLSBOb3RlIHRoYXQgdGhlIGludGVyYWN0aW9uIGVmZmVjdCB0aGF0IGlzIG9ic2VydmVkIGlzIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IChwPWByIHJvdW5kKHN1bW1hcnkobG1WV1NfSW50VlcpJGNvZWZbNSw0XSwyKWApLgotIFRoZSBtYWluIGVmZmVjdHMgdGhhdCBhcmUgaW52b2x2ZWQgaW4gdGhlIGludGVyYWN0aW9uIGNhbm5vdCBiZSBpbnRlcnByZXRlZCBzZXBhcmF0ZWx5IGZyb20gb25lIGFub3RoZXIuCi0gV2Ugd2lsbCB0aGVyZWZvcmUgcmVtb3ZlIG5vbi1zaWduaWZpY2FudCBpbnRlcmFjdGlvbiB0ZXJtcyBmcm9tIHRoZSBtb2RlbC4KLSBVcG9uIHJlbW92YWwgb2Ygbm9uLXNpZ25pZmljYW50IGludGVyYWN0aW9uIHRlcm1zIHRoZSBtYWluIGVmZmVjdHMgY2FuIGJlIGludGVycHJldGVkLgoKLS0tCgojIyBJbnRlcmFjdGlvbiBiZXR3ZWVuIGEgY29udGludW91cyB2YXJpYWJsZSBhbmQgYSBmYWN0b3IgdmFyaWFibGUKCkludGVyYWN0aW9uIGJldHdlZW4gbGNhdm9sICRcbGVmdHJpZ2h0YXJyb3ckIHN2aSBhbmQgbHdlaWdodCAkXGxlZnRyaWdodGFycm93JCBzdmkuCgpUaGUgbW9kZWwgYmVjb21lcwoKJCRZPVxiZXRhXzArXGJldGFfdlhfditcYmV0YV93WF93K1xiZXRhX3NYX3MrXGJldGFfe3ZzfVhfdlhfcyArIFxiZXRhX3t3c31YX3dYX3MgK1xlcHNpbG9uJCQKCi0tLQoKYGBge3J9CmxtVldTX0ludFZTX1dTIDwtIGxtKGxwc2EgfiBsY2F2b2wgKyBsd2VpZ2h0ICsgc3ZpICsgc3ZpOmxjYXZvbCArIHN2aTpsd2VpZ2h0LCBkYXRhID0gcHJvc3RhdGUpCnN1bW1hcnkobG1WV1NfSW50VlNfV1MpCmBgYAoKLS0tCgpCZWNhdXNlICRYX1MkIGlzIGEgZHVtbXkgdmFyaWFiZWxlIHdlIG9idGFpbiB0byBkaXN0aW5jdCByZWdyZXNzaW9uIHBsYW5lczoKCjEuIE1vZGVsIGZvciAkWF9zPTAkOiAkJFk9XGJldGFfMCtcYmV0YV92WF92K1xiZXRhX3dYX3cgKyBcZXBzaWxvbiQkIHdoZXJlIHRoZSBtYWluIGVmZmVjdHMgYXJlIHRoZSBzbG9wZSBmb3IgbGNhdm9sIGFuZCBsd2VpZ2h0CjIuIGFuZCBtb2RlbCBmb3IgJFhfcz0xJDoKICAgJCRcYmVnaW57YXJyYXl9e2xjbH0KICAgWSY9JlxiZXRhXzArXGJldGFfdlhfditcYmV0YV9zK1xiZXRhX3dYX3crXGJldGFfe3ZzfVhfdiArIFxiZXRhX3t3c31YX3cgK1xlcHNpbG9uXFwKICAmPSYgKFxiZXRhXzArXGJldGFfcykrKFxiZXRhX3YrXGJldGFfe3ZzfSlYX3YrKFxiZXRhX3crXGJldGFfe3dzfSlYX3crXGVwc2lsb24KICBcZW5ke2FycmF5fSQkCndpdGggaW50ZXJjZXB0ICRcYmV0YV8wK1xiZXRhX3MkIGFuZCBzbG9wZXMgJFxiZXRhX3YrXGJldGFfe3ZzfSQgYW5kICRcYmV0YV93K1xiZXRhX3t3c30kCgotLS0KCmBgYHtyIG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQpwYXIobWZyb3cgPSBjKDEsIDIpKQpsaWJyYXJ5KHBsb3QzRCkKZ3JpZC5saW5lcyA8LSAxMAp4IDwtIHByb3N0YXRlJGxjYXZvbAp5IDwtIHByb3N0YXRlJGx3ZWlnaHQKeiA8LSBwcm9zdGF0ZSRscHNhCmZpdCA8LSBsbSh6IH4geCArIHkgKyBzdmksIGRhdGEgPSBwcm9zdGF0ZSkKeC5wcmVkIDwtIHNlcShtaW4oeCksIG1heCh4KSwgbGVuZ3RoLm91dCA9IGdyaWQubGluZXMpCnkucHJlZCA8LSBzZXEobWluKHkpLCBtYXgoeSksIGxlbmd0aC5vdXQgPSBncmlkLmxpbmVzKQoKIyBmaXR0ZWQgcG9pbnRzIGZvciBkcm9wbGluZXMgdG8gc3VyZmFjZQp0aCA8LSAtMjUKcGggPC0gNQpzY2F0dGVyM0QoeCwgeSwgeiwKICBwY2ggPSAxNiwgY29sID0gYygiZGFya2JsdWUiLCAicmVkIilbYXMuZG91YmxlKHByb3N0YXRlJHN2aSldLCBjZXggPSAuNzUsCiAgdGhldGEgPSB0aCwgcGhpID0gcGgsIHRpY2t0eXBlID0gImRldGFpbGVkIiwKICB4bGFiID0gImxjYXZvbCIsIHlsYWIgPSAibHdlaWdodCIsIHpsYWIgPSAibHBzYSIsCiAgY29sdmFyID0gRkFMU0UsIGJ0eSA9ICJnIiwgbWFpbiA9ICJBZGRpdGl2ZSBtb2RlbCIKKQoKZm9yIChpIGluIHdoaWNoKHByb3N0YXRlJHN2aSA9PSAiaGVhbHRoeSIpKSB7CiAgbGluZXMzRCh4ID0gcmVwKHByb3N0YXRlJGxjYXZvbFtpXSwgMiksIHkgPSByZXAocHJvc3RhdGUkbHdlaWdodFtpXSwgMiksIHogPSBjKHByb3N0YXRlJGxwc2FbaV0sIGxtVldTJGZpdFtpXSksIGNvbCA9IGMoImRhcmtibHVlIiwgInJlZCIpW2FzLmRvdWJsZShwcm9zdGF0ZSRzdmkpW2ldXSwgYWRkID0gVFJVRSwgbHR5ID0gMikKfQoKei5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLCB5LnByZWQsIGZ1bmN0aW9uKHgsIHkpIHsKICBsbVZXUyRjb2VmWzFdICsgbG1WV1MkY29lZlsyXSAqIHggKyBsbVZXUyRjb2VmWzNdICogeQp9KQp4LnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCwgeSkgeCkKeS5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLCB5LnByZWQsIGZ1bmN0aW9uKHgsIHkpIHkpCnN1cmYzRCh4LnByZWQzRCwgeS5wcmVkM0QsIHoucHJlZDNELCBjb2wgPSAiYmx1ZSIsIGZhY2V0cyA9IE5BLCBhZGQgPSBUUlVFKQp6Mi5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLCB5LnByZWQsIGZ1bmN0aW9uKHgsIHkpIHsKICBsbVZXUyRjb2VmWzFdICsgbG1WV1MkY29lZls0XSArIGxtVldTJGNvZWZbMl0gKiB4ICsgbG1WV1MkY29lZlszXSAqIHkKfSkKc3VyZjNEKHgucHJlZDNELCB5LnByZWQzRCwgejIucHJlZDNELCBjb2wgPSAib3JhbmdlIiwgZmFjZXRzID0gTkEsIGFkZCA9IFRSVUUpCgoKc2NhdHRlcjNEKHgsIHksIHosCiAgcGNoID0gMTYsIGNvbCA9IGMoImRhcmtibHVlIiwgInJlZCIpW2FzLmRvdWJsZShwcm9zdGF0ZSRzdmkpXSwgY2V4ID0gLjc1LAogIHRoZXRhID0gdGgsIHBoaSA9IHBoLCB0aWNrdHlwZSA9ICJkZXRhaWxlZCIsCiAgeGxhYiA9ICJsY2F2b2wiLCB5bGFiID0gImx3ZWlnaHQiLCB6bGFiID0gImxwc2EiLAogIGNvbHZhciA9IEZBTFNFLCBidHkgPSAiZyIsIG1haW4gPSAiTW9kZWwgbWV0IGxjYXZvbDpsd2VpZ2h0IGludGVyYWN0aWUiCikKCmZvciAoaSBpbiB3aGljaChwcm9zdGF0ZSRzdmkgPT0gImhlYWx0aHkiKSkgewogIGxpbmVzM0QoeCA9IHJlcChwcm9zdGF0ZSRsY2F2b2xbaV0sIDIpLCB5ID0gcmVwKHByb3N0YXRlJGx3ZWlnaHRbaV0sIDIpLCB6ID0gYyhwcm9zdGF0ZSRscHNhW2ldLCBsbVZXU19JbnRWU19XUyRmaXRbaV0pLCBjb2wgPSBjKCJkYXJrYmx1ZSIsICJyZWQiKVthcy5kb3VibGUocHJvc3RhdGUkc3ZpKVtpXV0sIGFkZCA9IFRSVUUsIGx0eSA9IDIpCn0KCnoucHJlZDNEIDwtIG91dGVyKHgucHJlZCwgeS5wcmVkLCBmdW5jdGlvbih4LCB5KSB7CiAgbG1WV1NfSW50VlNfV1MkY29lZlsxXSArIGxtVldTX0ludFZTX1dTJGNvZWZbMl0gKiB4ICsgbG1WV1NfSW50VlNfV1MkY29lZlszXSAqIHkKfSkKeC5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLCB5LnByZWQsIGZ1bmN0aW9uKHgsIHkpIHgpCnkucHJlZDNEIDwtIG91dGVyKHgucHJlZCwgeS5wcmVkLCBmdW5jdGlvbih4LCB5KSB5KQpzdXJmM0QoeC5wcmVkM0QsIHkucHJlZDNELCB6LnByZWQzRCwgY29sID0gImJsdWUiLCBmYWNldHMgPSBOQSwgYWRkID0gVFJVRSkKejIucHJlZDNEIDwtIG91dGVyKHgucHJlZCwgeS5wcmVkLCBmdW5jdGlvbih4LCB5KSB7CiAgbG1WV1NfSW50VlNfV1MkY29lZlsxXSArIGxtVldTX0ludFZTX1dTJGNvZWZbNF0gKyBsbVZXU19JbnRWU19XUyRjb2VmWzJdICogeCArIGxtVldTX0ludFZTX1dTJGNvZWZbM10gKiB5ICsgbG1WV1NfSW50VlNfV1MkY29lZls1XSAqIHggKyBsbVZXU19JbnRWU19XUyRjb2VmWzZdICogeQp9KQpzdXJmM0QoeC5wcmVkM0QsIHkucHJlZDNELCB6Mi5wcmVkM0QsIGNvbCA9ICJvcmFuZ2UiLCBmYWNldHMgPSBOQSwgYWRkID0gVFJVRSkKYGBgCgotLS0KCiMgQU5PVkEgdGFibGUKClRoZSB0b3RhbCBTU1RvdCBpcyBhZ2FpbgoKJCQKICBcdGV4dHtTU1RvdH0gPSBcc3VtX3tpPTF9Xm4gKFlfaSAtIFxiYXJ7WX0pXjIuCiQkCgpUaGUgcmVzaWR1YWwgc3VtIG9mIHNxdWFyZXMgcmVtYWlucyBzaW1pbGFyCiQkCiAgXHRleHR7U1NFfSA9IFxzdW1fe2k9MX1ebiAoWV9pLVxoYXR7WX1faSleMi4KJCQKCkFnYWluIHRoZSB0b3RhbCBzdW0gb2Ygc3F1YXJlcyBjYW4gYmUgZGVjb21wb3NlZCBpbiAsCiQkCiAgXHRleHR7U1NUb3R9ID0gXHRleHR7U1NSfSArIFx0ZXh0e1NTRX0gLAokJAp3aXRoCiQkCiAgXHRleHR7U1NSfSA9IFxzdW1fe2k9MX1ebiAoXGhhdHtZfV9pLVxiYXJ7WX0pXjIuCiQkCgotLS0KCldlIGhhdmUgZm9sbG93aW5nIGRlZ3JlZXMgb2YgZnJlZWRvbSBhbmQgbWVhbiBzdW0gb2Ygc3F1YXJlczoKCi0gU1NUb3QgaGFzICRuLTEkIGRlZ3JlZXMgb2YgZnJlZWRvbSBhbmQgJFx0ZXh0e1NTVG90fS8obi0xKSQgaXMgYW4gZXN0aW1hdG9yIGZvciB0aGUgdG90YWwgdmFyaWFuY2UgaW4gJFkkIChtYXJnaW5hbCBkaXN0cmlidXRpb24gb2YgJFkkKS4KLSBTU0UgaGFzICRuLXAkIGRlZ3JlZXMgb2YgZnJlZWRvbSBhbmQgJFx0ZXh0e01TRX09XHRleHR7U1NFfS8obi1wKSQgaXMgYW4gc2NoYXR0ZXIgZm9yIHRoZSByZXNpZHVhbCB2YXJpYW5jZSBvZiAkWSQgZ2l2ZW4gdGhlIHByZWRpY3RvcmVzIChpLmUuIGFuIGVzdGltYXRvciBmb3IgdGhlIHJlc2lkdWFsIHZhcmlhbmNlICRcc2lnbWFeMiQgb2YgdGhlIGVycm9yIHRlcm0gJFxlcHNpbG9uJCkuCi0gU1NSIGhhcyAkcC0xJCBkZWdyZWVzIG9mIGZyZWVkb20gICBhbmQgJFx0ZXh0e01TUn09XHRleHR7U1NSfS8ocC0xKSQgaXMgdGhlIG1lYW4gc3VtIG9mIHNxdWFyZXMgb2YgdGhlIHJlZ3Jlc3Npb24uCgpUaGUgZGV0ZXJtaW5hdGlvbiBjb2VmZmljaWVudHMgcmVtYWlucyBhcyBiZWZvcmUsICBpLmUuCiQkCiAgUl4yID0gMS1cZnJhY3tcdGV4dHtTU0V9fXtcdGV4dHtTU1RvdH19ID0gXGZyYWN7XHRleHR7U1NSfX17XHRleHR7U1NUb3R9fQokJAphbmQgaXMgdGhlIGZyYWN0aW9uIG9mIHRoZSB0b3RhbCB2YXJpYWJpbGl0eSB0aGF0IGNhbiBiZSBleHBsYWluZWQgYnkgdGhlIHJlZ3Jlc3Npb24gbW9kZWwuCgpUZXN0c3RhdGlzdGljICRGPVx0ZXh0e01TUn0vXHRleHR7TVNFfSQgaXMgdW5kZXIgJEhfMDpcYmV0YV8xPVxsZG90cz1cYmV0YV97cC0xfT0wJCBkaXN0cmlidXRlZCBieSBhbiBGIGRpc3RyaWJ1dGlvbjogJEZfe3AtMTtuLXB9JC4KCi0tLQoKYGBge3IsIGVjaG89RkFMU0V9CnN1bW1hcnkobG1WV1MpCmBgYAoKLS0tCgojIyBBZGRpdGlvbmFsIHN1bXMgb2Ygc3F1YXJlcwoKCkNvbnNpZGVyIDIgbW9kZWxzIGZvciB0aGUgcHJlZGljdG9ycyAkeF8xJCBlbiAkeF8yJDoKJCQKICBZX2kgPSBcYmV0YV8wK1xiZXRhXzEgeF97aTF9ICsgXGVwc2lsb25faSwKJCQKd2l0aCAkXGVwc2lsb25faVx0ZXh0eyBpaWQgfSBOKDAsXHNpZ21hXzFeezJ9KSQsIGFuZAokJApZX2kgPSBcYmV0YV8wK1xiZXRhXzEgeF97aTF9K1xiZXRhXzIgeF97aTJ9ICsgXGVwc2lsb25faSwKJCQKd2l0aCAkXGVwc2lsb25faVx0ZXh0eyBpaWQgfSBOKDAsXHNpZ21hXzJeezJ9KSQuCgpmb3IgdGhlIGZpcnN0IChnZXJlZHVjZWVyZGUpIG1vZGVsIHdlIGhhdmUgZGVjb21wb3NpdGlvbgpcWwogIFx0ZXh0e1NTVG90fSA9IFx0ZXh0e1NTUn1fMSArIFx0ZXh0e1NTRX1fMQpcXQplbiBmb3IgdGhlIHNlY29uZCBub24tcmVkdWNlZCBtb2RlbCB3ZSBoYXZlClxbCiAgXHRleHR7U1NUb3R9ID0gXHRleHR7U1NSfV8yICsgXHRleHR7U1NFfV8yClxdCihTU1RvdCBpcyBvZiBjb3Vyc2UgdGhlIHNhbWUgYmVjYXVzZSBpdCBvbmx5IGRlcGVuZHMgb24gdGhlIHJlc3BvbnNlIGFuZCBub3Qgb2YgdGhlIG1vZGVscykuCgotLS0KCioqRGVmaW5pdGlvbiBvZiBhZGRpdGlvbmFsIHN1bSBvZiBzcXVhcmVzKioKVGhlICphZGRpdGlvbmFsIHN1bSBvZiBzcXVhcmVzKiBvZiBwcmVkaWN0b3IgJHhfMiQgYXMgY29tcGFyZWQgdG8gdGhlIG1vZGVsIHdpdGggb25seSAkeF8xJCBhcyBwcmVkaWN0b3IgaXMgZ2l2ZW4gYnkKJCQKICBcdGV4dHtTU1J9X3syXG1pZCAxfSA9IFx0ZXh0e1NTRX1fMS1cdGV4dHtTU0V9XzI9XHRleHR7U1NSfV8yLVx0ZXh0e1NTUn1fMS4KJCQKCk5vdGUgdGhhdCwgICRcdGV4dHtTU0V9XzEtXHRleHR7U1NFfV8yPVx0ZXh0e1NTUn1fMi1cdGV4dHtTU1J9XzEkIGlzIHRyaXZpYWFsIGlzIGJlY2F1c2Ugb2YgdGhlIGRlY29tcG9zaXRpb24gb2YgdGhlIHRvdGFsIHN1bSBvZiBzcXVhcmVzLgoKVGhlIGFkZGl0aW9uYWwgc3VtIG9mIHNxdWFyZXMgJFx0ZXh0e1NTUn1fezJcbWlkIDF9JCBjYW4gc2ltcGx5IGJlIGludGVycHJldGVkIGFzIHRoZSBhZGRpdGlvbmFsIHZhcmlhYmlsaXR5IHRoYXQgY2FuIGJlIGV4cGxhaW5lZCBieSBhZGRpbmcgcHJlZGljdG9yICR4XzIkIHRvIHRoZSBtb2RlbCB3aXRoIHByZWRpY3RvciAkeF8xJC4KCldpdGggdGhpcyBzdW0gb2Ygc3F1YXJlcyB3ZSBjYW4gZnVydGhlciBkZWNvbXBvc2UgdGhlIHRvdGFsIHN1bSBvZiBzcXVhcmVzCiQkCiAgXHRleHR7U1NUb3R9ID0gXHRleHR7U1NSfV8xKyBcdGV4dHtTU1J9X3syXG1pZCAxfSArIFx0ZXh0e1NTRX0uCiQkCndoaWNoIGZvbGxvd3MgZGlyZWN0bHkgZnJvbSB0aGUgZGVmaW5pdGlvbiAkXHRleHR7U1NSfV97MlxtaWQgMX0kLgoKLS0tCgpFeHRlbnNpb246ICgkczxwLTEkKQokJApZX2kgPSBcYmV0YV8wICsgXGJldGFfMSB4X3tpMX0gKyBcY2RvdHMgKyBcYmV0YV97c30geF97aXN9ICsgXGVwc2lsb25faQokJAp3aXRoICRcZXBzaWxvbl9pXHRleHR7IGlpZCB9TigwLFxzaWdtYV8xXnsyfSkkLCBhbmQgKCRzPCBxXGxlcSBwLTEkKQokJApZX2kgPSBcYmV0YV8wICsgXGJldGFfMSB4X3tpMX0gKyBcY2RvdHMgKyBcYmV0YV97c30geF97aXN9ICsgXGJldGFfe3MrMX0geF97aXMrMX0gKyBcY2RvdHMgXGJldGFfe3F9eF97aXF9KyBcZXBzaWxvbl9pCiQkCndpdGggJFxlcHNpbG9uX2lcdGV4dHsgaWlkIH0gTigwLFxzaWdtYV8yXnsyfSkkLgoKClRoZSAqKmFkZGl0aW9uYWwgc3VtIG9mIHNxdWFyZXMqKiBvZiBwcmVkaWN0b3IgJHhfe3MrMX0sIFxsZG90cywgeF9xJCBjb21wYXJlZCB0byBhIG1vZGVsIHdpdGggb25seSBwcmVkaWN0b3JzICAkeF8xLFxsZG90cywgeF97c30kIGlzIGdpdmVuIGJ5CgokJAogIFx0ZXh0e1NTUn1fe3MrMSwgXGxkb3RzLCBxXG1pZCAxLFxsZG90cywgc30gPSBcdGV4dHtTU0V9XzEtXHRleHR7U1NFfV8yPVx0ZXh0e1NTUn1fMi1cdGV4dHtTU1J9XzEuCiQkCgotLS0KCiMjIyBUeXBlIEkgU3VtcyBvZiBTcXVhcmVzClN1cHBvc2UgdGhhdCAkcC0xJCBwcmVkaWN0b3JzIGFyZSBjb25zaWRlcmVkLCBhbmQgc3VwcG9zZSB0aGUgZm9sbG93aW5nIHNlcXVlbmNlIG9mIG1vZGVscyAoJHM9MixcbGRvdHMsIHAtMSQpCiQkCllfaSA9IFxiZXRhXzAgKyBcc3VtX3tqPTF9XntzfSBcYmV0YV9qIHhfe2lqfSArIFxlcHNpbG9uX2kKJCQKd3V0aCAkXGVwc2lsb25faVx0ZXh0eyBpaWQgfSBOKDAsXHNpZ21hXnsyfSkkLgoKLSBUaGUgY29ycmVzcG9uZGluZyBzdW0gb2Ygc3F1YXJlcyBhcmUgZGVub3RlZCBhcyAkXHRleHR7U1NSfV97c30kIGFuZCAkXHRleHR7U1NFfV97c30kLgotIFRoZSBzZXF1ZW5jZSBvZiBtb2RlbHMgZ2l2ZXMgcmlzZSB0byB0aGUgZm9sbG93aW5nIHN1bXMgb2Ygc3F1YXJlczogJFx0ZXh0e1NTUn1fe3NcbWlkIDEsXGxkb3RzLCBzLTF9JC4KLSBUaGUgbGF0dGVyIHN1bSBvZiBzcXVhcmVzIGlzIHJlZmVycmVkIHRvIGFzIHR5cGUgSSBzdW1zIG9mIHNxdWFyZXMuIE5vdGUgdGhhdCB0aGV5IGRlcGVuZCBvbiB0aGUgb3JkZXIgaW4gd2hpY2ggdGhlIG1vZGVscyB3ZXJlIGFkZGVkIHRvIHRoZSBtb2RlbC4KCi0tLQoKV2UgY2FuIHNob3cgZm9yIG1vZGVsIE1vZGVsIHdpdGggJHM9cC0xJCB0aGF0CiQkCiBcdGV4dHtTU1RvdH0gPSBcdGV4dHtTU1J9XzEgKyBcdGV4dHtTU1J9X3syXG1pZCAxfSArIFx0ZXh0e1NTUn1fezNcbWlkIDEsMn0gKyBcY2RvdHMgKyBcdGV4dHtTU1J9X3twLTFcbWlkIDEsXGxkb3RzLCBwLTJ9ICsgXHRleHR7U1NFfSwKJCQKd2l0aCAkXHRleHR7U1NFfSQgdGhlIHJlc2lkdWFsIHN1bSBvZiBzcXVhcmVzIG9mIHRoZSBtb2RlbCB3aXRoIGFsbCAkcC0xJCBwcmVkaWN0b3JzCiQkCiAgXHRleHR7U1NSfV8xICsgXHRleHR7U1NSfV97MlxtaWQgMX0gKyBcdGV4dHtTU1J9X3szXG1pZCAxLDJ9ICsgXGNkb3RzICsgXHRleHR7U1NSfV97cC0xXG1pZCAxLFxsZG90cywgcC0yfSA9IFx0ZXh0e1NTUn0KJCQKd2l0aCAkXHRleHR7U1NSfSQgdGhlIHN1bSBvZiBzcXVhcmVzIG9mIGFsbCAgJHAtMSQgcHJlZGljdG9ycy4KCi0gVGhlIGludGVycHJldGF0aW9uIG9mIGVhY2ggdGVybSBkZXBlbmRzIG9uIHRoZSBvcmRlciBvZiB0aGUgc2VxdWVuY2Ugb2YgdGhlIHJlZ3Jlc3Npb24gbW9kZWxzLgoKLS0tCgotIEVhY2ggdHlwZSBJIFNTUiBpbnZvbHZlcyAxIHByZWRpY3RvciBhbmQgaGFzIDEgZGVncmVlIG9mIGZyZWVkb20gKG5vdGUgdGhhdCBtdWx0aXBsZSBkdW1taWVzIGZvciBhIGZhY3RvciBhcmUgdHlwaWNhbGx5IHJlbW92ZWQgdG9nZXRoZXIpLgotIEZvciBlYWNoIHR5cGUgSSBTU1IgdGVybSB0aGUgbWVhbiBzdW0gb2Ygc3F1YXJlcyBpcyBkZWZpbmVkIGJ5ICAkXHRleHR7TVNSfV97alxtaWQgMSxcbGRvdHMsIGotMX09XHRleHR7U1NSfV97alxtaWQgMSxcbGRvdHMsIGotMX0vMSQuCi0gQW5kIHRlc3RzdGF0aXN0aWMgJEY9XHRleHR7TVNSfV97alxtaWQgMSxcbGRvdHMsIGotMX0vXHRleHR7TVNFfSQgZm9sbG93cyBhICRGX3sxO24tKGorMSl9JCBkaXN0cmlidXRpb24gdW5kZXIgICRIXzA6XGJldGFfaj0wJCB3aXRoICRzPWokLgotIFRoZXNlIHN1bXMgb2Ygc3F1YXJlcyBhcmUgdGhlIGRlZmF1bHQgc3VtIG9mIHNxdWFyZXMgaW4gdGhlIGFub3ZhIGZ1bmN0aW9uIG9mIFIuCgotLS0KCiMjIyBUeXBlIElJSSBTdW1zIG9mIHNxdWFyZXMKCiBUeXBlIElJSSBzdW0gb2Ygc3F1YXJlcyBmb3IgcHJlZGljdG9yICR4X2okIGFyZSBnaXZlbiBieSB0aGUgYWRkaXRpb25hbCBzdW0gb2Ygc3F1YXJlcwokJAogIFx0ZXh0e1NTUn1fe2ogXG1pZCAxLFxsZG90cywgai0xLGorMSxcbGRvdHMsIHAtMX0gPSBcdGV4dHtTU0V9XzEtXHRleHR7U1NFfV8yCiQkCgotICRcdGV4dHtTU0V9XzIkIHRoZSBzdW0gb2Ygc3F1YXJlcyBvZiB0aGUgcmVzaWR1YWxzIG9mIHRoZSBtb2RlbCB3aXRoIGFsbCAkcC0xJCBwcmVkaWN0b3JzLgotICRcdGV4dHtTU0V9XzEkIHN1bSBvZiBzcXVhcmVzIG9mIHRoZSByZXNpZHVhbHMgd2l0aCBhbGwgJHAtMSQgcHJlZGljdG9ycywgZXhjZXB0IGZvciBwcmVkaWN0b3IgJHhfaiQuCgpUaGUgdHlwZSBJSUkgc3VtIG9mIHNxdWFyZXMgJFx0ZXh0e1NTUn1fe2ogXG1pZCAxLFxsZG90cywgai0xLGorMSxcbGRvdHMsIHAtMX0kIHF1YW50aWZ5IHRoZSBjb250cmlidXRpb24gaW4gdGhlIHRvdGFsIHZhcmlhbmNlIG9mIHRoZSBvdXRjb21lIGV4cGxhaW5lZCBieSAkeF9qJCB0aGF0IGNhbm5vdCBiZSBleHBsYWluZWQgYnkgdGhlIHJlbWFpbmluZyAkcC0yJCBwcmVkaWN0b3JzLgoKLS0tCgpUaGUgdHlwZSBJSUkgc3VtIG9mIHNxdWFyZXMgaGFzIDEgZGVncmVlIG9mIGZyZWVkb20gYmVjYXVzZSBpdCBpbnZvbHZlcyAxICRcYmV0YSQtcGFyYW1ldGVyLgoKRm9yIGVhY2ggdHlwZSBJSUkgU1NSIHRlcm0gdGhlIG1lYW4gc3VtIG9mIHNxdWFyZXMgaXMgZGVmaW5lZCBieSAkXHRleHR7TVNSfV97aiBcbWlkIDEsXGxkb3RzLCBqLTEsaisxLFxsZG90cywgcC0xfT1cdGV4dHtTU1J9X3tqIFxtaWQgMSxcbGRvdHMsIGotMSxqKzEsXGxkb3RzLCBwLTF9LzEkLgoKVGVzdHN0YXRpc3RpZWsgJEY9XHRleHR7TVNSfV97aiBcbWlkIDEsXGxkb3RzLCBqLTEsaisxLFxsZG90cywgcC0xfS9cdGV4dHtNU0V9JCBpcyAkRl97MTtuLXB9JCBkaXN0cmlidXRlZCB1bmRlciAkSF8wOlxiZXRhX2o9MCQuCgpXZSBjYW4gb2J0YWluIHRoZXNlIHN1bXMgb2Ygc3F1YXJlcyB1c2luZyB0aGUgYEFub3ZhYCBmdW5jdGlvbiBmcm9tIHRoZSBgY2FyYCBwYWNrYWdlLgotLS0KCmBgYHtyfQpsaWJyYXJ5KGNhcikKQW5vdmEobG1WV1MsIHR5cGUgPSAzKQpgYGAKClRoZSBwLXZhbHVlcyBhcmUgaWRlbnRpY2FsIHRvIHRob3NlIG9mIHR3by1zaWRlZCB0LXRlc3RzCgpOb3RlLCBob3dldmVyLCB0aGF0IGFsbCBkdW1taWVzIGZvciBmYWN0b3JzIHdpdGggbXVsdGlwbGUgbGV2ZWxzIHdpbGwgYmUgdGFrZW4gb3V0IG9mIHRoZSBtb2RlbCBhdCBvbmNlLiBTbyB0aGVuIHRoZSB0eXBlIElJSSBzdW0gb2Ygc3F1YXJlcyB3aWxsIGhhdmUgYXMgbWFueSBkZWdyZWVzIG9mIGZyZWVkb20gYXMgdGhlIG51bWJlciBvZiBkdW1taWVzIGFuZCBhbiBvbW5pYnVzIHRlc3QgaXMgcGVyZm9ybWVkIGZvciB0aGUgZWZmZWN0IG9mIHRoZSBmYWN0b3IuCgotLS0KCiMgRGlhZ25vc3RpY3MKIyMgTXVsdGljb2xsaW5lYXJpdHkKCmBgYHtyIGVjaG89RkFMU0V9CnN1bW1hcnkobG1WV1MpCmBgYAoKLS0tCgpgYGB7ciBlY2hvPUZBTFNFfQpzdW1tYXJ5KGxtVldTX0ludFZXKQpgYGAKCi0tLQoKLSBFc3RpbWF0ZXMgYXJlIGRpZmZlcmVudCBmcm9tIHRob3NlIGluIHRoZSBhZGRpdGl2ZSBtb2RlbCBhbmQgdGhlIHN0YW5kYXJkIGVycm9ycyBhcmUgbXVjaCBoaWdoZXIhCgotIFRoaXMgaXMgY2F1c2VkIGJ5IHRoZSBtdWx0aWNvbGxpbmVhcml0eSBwcm9ibGVtLgoKLSBJZiAyIHByZWRpY3RvcnMgYXJlIHN0cm9uZ2x5IGNvcnJlbGF0ZWQgdGhhbiB0aGV5IHNoYXJlIGEgbG90IG9mIGluZm9ybWF0aW9uLgoKLSBJdCBpcyB0aGVyZWZvcmUgZGlmZmljdWx0IHRvIGVzdGltYXRlIHRoZSBpbmRpdmlkdWFsIGNvbnRyaWJ1dGlvbiBvZiBlYWNoIHByZWRpY3RvciBvbiB0aGUgb3V0Y29tZS4KCi0gTGVhc3Qgc3F1YXJlcyBlc3RpbWF0b3JzIGJlY29tZSBpbnN0YWJsZS4KCi0gU3RhbmRhcmQgZXJyb3JzIGJlY29tZSBpbmZsYXRlZC4KCi0gQXMgbG9uZyBhcyB3ZSBvbmx5IGRvIHByZWRpY3Rpb25zIG9uIHRoZSBiYXNpcyBvZiB0aGUgcmVncmVzc2lvbiBtb2RlbCB3aXRob3V0IGV4dHJhcG9sYXRpbmcgYmV5b25kIHRoZSByYW5nZSBvZiB0aGUgcHJlZGljdG9ycyBvYnNlcnZlZCBpbiB0aGUgc2FtcGxlIG11bHRpY29saW5lYXJpdHkgaXMgbm90IHByb2JsZW1hdGljLgoKLSBCdXQgZm9yIGluZmVyZW5jZSBpdCBpcyBwcm9ibGVtYXRpYy4KCi0tLQoKYGBge3J9CmNvcihjYmluZChwcm9zdGF0ZSRsY2F2b2wsIHByb3N0YXRlJGx3ZWlnaHQsIHByb3N0YXRlJGxjYXZvbCAqIHByb3N0YXRlJGx3ZWlnaHQpKQpgYGAKCi0gSGlnaCBjb3JyZWxhdGlvbiBiZXR3ZWVuIGxvZy10dW1vciB2b2x1bWUgYW5kIGludGVyYWN0aW9uLgotIEl0IGlzIGEga25vd24gcHJvYmxlbSBmb3IgaGlnaGVyIG9yZGVyIHRlcm1zIChpbnRlcmFjdGlvbnMgYW5kIHF1YWRyYXRpYyB0ZXJtcykKCi0tLQoKLSBEZXRlY3QgbXVsdGljb2xsaW5lYXJpdHkgYmFzZWQgb24gdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCBvciBzY2F0dGVycGxvdCBtYXRyaXggaXMgc3Vib3B0aW1hbC4KLSBJbiBtb2RlbHMgd2l0aCAzIG9yIG1vcmUgcHJlZGljdG9ycywgc2F5IFgxLCBYMiwgWDMgd2UgY2FuIGhhdmUgaGlnaCBtdWx0aWNvbGxpbmVhcml0eSB3aGlsZSBhbGxlIHBhaXJzd2lzZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0aGUgcHJlZGljdG9ycyBhcmUgbG93LgotIFdlIGFsc28gaGF2ZSBtdWx0aWNvbGxpbmVhcml0eSBpZiB0aGVyZSBpcyBhIGhpZ2ggY29ycmVsYXRpb24gYmV0d2VlbiBYMSBhbmQgYSBsaW5haXIgY29tYmluYXRpb24gb2YgWDIgYW5kIFgzLgoKLS0tCgojIyMgVmFyaWFuY2UgaW5mbGF0aW9uIGZhY3RvciAoVklGKQoKRm9yIHBhcmFtZXRlciAkaiQgaW4gZGUgcmVncmVzc2lvbiBtb2RlbApcW1x0ZXh0cm17VklGfV9qPVxsZWZ0KDEtUl9qXjJccmlnaHQpXnstMX1cXQoKLSBJbiB0aGlzIGV4cHJlc3Npb24gJFJfal4yJCBpcyB0aGUgbXVsdGlwbGUgZGV0ZXJtaW5hdGlvbiBjb2VmZmljaWVudCBvZiB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gb2YgcHJlZGljdG9yIGogb24gdGhlIHJlbWFpbmluZyBwcmVkaWN0b3JzIGluIHRoZSBtb2RlbC4KLSBWSUYgaXMgMSBpZiBwcmVkaWN0b3IgaiBpcyBub3QgbGluZWFyIGFzc29jaWF0ZWQgd2l0aCB0aGUgcmVtYWluaW5nIHByZWRpY3RvcnMgaW4gdGhlIG1vZGVsLgotIFZJRiBpcyBsYXJnZXIgdGhhbiAxIGluIGFsbCBhbmRlcmUgY2FzZXMuCi0gVklGIGlzIHRoZSBmYWN0b3Igd2l0aCB3aGljaCB0aGUgb2JzZXJ2ZWQgdmFyaWFuY2UgaW5mbGF0ZXMgYXMgY29tcGFyZWQgdG8gYSBtb2RlbCBmb3Igd2hpY2ggYWxsIHByZWRpY3RvcmVuIHdvdWxkIGJlIGluZGVwZW5kZW5kLgotIFZJRiA+IDEwICRccmlnaHRhcnJvdyQgc3Ryb25nIG11bHRpY29sbGluZWFyaXR5LgoKLS0tCgojIyMgQm9keSBmYXQgZXhhbXBsZQoKYGBge3Igb3V0LndpZHRoPSc5MCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0KYm9keWZhdCA8LSByZWFkX2RlbGltKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vR1RQQi9QU0xTMjAvbWFzdGVyL2RhdGEvYm9keWZhdC50eHQiLCBkZWxpbSA9ICIgIikKYm9keWZhdCAlPiUgZ2dwYWlycygpCmBgYAoKLS0tCgpgYGB7ciBlY2hvPUZBTFNFfQpsbUZhdCA8LSBsbShCb2R5X2ZhdCB+IFRyaWNlcHMgKyBUaGlnaCArIE1pZGFybSwgZGF0YSA9IGJvZHlmYXQpCnN1bW1hcnkobG1GYXQpCmBgYAoKLS0tCgpgYGB7cn0KdmlmKGxtRmF0KQpgYGAKCi0tLQoKYGBge3IgZWNobz1GQUxTRX0KbG1NaWRhcm0gPC0gbG0oTWlkYXJtIH4gVHJpY2VwcyArIFRoaWdoLCBkYXRhID0gYm9keWZhdCkKc3VtbWFyeShsbU1pZGFybSkKYGBgCgotLS0KCgpXZSBldmFsdWF0ZSB0aGUgVklGIGluIHRoZSBwcm9zdGF0ZSBjYW5jZXIgZXhhbXBsZSBmb3IgdGhlIGFkZGl0aXZlIG1vZGVsIGFuZCB0aGUgbW9kZWwgd2l0aCBpbnRlcmFjdGllLgoKYGBge3J9CnZpZihsbVZXUykKdmlmKGxtVldTX0ludFZXKQpgYGAKCi0gSW5mbGF0aW9uIGluIGludGVyYWN0aW9uIHRlcm1zIG9mdGVuIGNhdXNlZCBiZWNhdXNlIG1haW4gZWZmZWN0IGdldCBhbm90aGVyIGludGVycHJldGF0aW9uLgoKLS0tCgojIyBJbmZsdWVudGlhbCBvYnNlcnZhdGlvbnMKCgpgYGB7cn0Kc2V0LnNlZWQoMTEyMzU4KQpub2JzIDwtIDIwCnNkeSA8LSAxCnggPC0gc2VxKDAsIDEsIGxlbmd0aCA9IG5vYnMpCnkgPC0gMTAgKyA1ICogeCArIHJub3JtKG5vYnMsIHNkID0gc2R5KQp4MSA8LSBjKHgsIDAuNSkKeTEgPC0gYyh5LCAxMCArIDUgKiAxLjUgKyBybm9ybSgxLCBzZCA9IHNkeSkpCngyIDwtIGMoeCwgMS41KQp5MiA8LSBjKHksIHkxWzIxXSkKeDMgPC0gYyh4LCAxLjUpCnkzIDwtIGMoeSwgMTEpCnBsb3QoeCwgeSwgeGxpbSA9IHJhbmdlKGMoeDEsIHgyLCB4MykpLCB5bGltID0gcmFuZ2UoYyh5MSwgeTIsIHkzKSkpCnBvaW50cyhjKHgxWzIxXSwgeDJbMjFdLCB4M1syMV0pLCBjKHkxWzIxXSwgeTJbMjFdLCB5M1syMV0pLCBwY2ggPSBhcy5jaGFyYWN0ZXIoMTozKSwgY29sID0gMjo0KQphYmxpbmUobG0oeSB+IHgpLCBsd2QgPSAyKQphYmxpbmUobG0oeTEgfiB4MSksIGNvbCA9IDIsIGx0eSA9IDIsIGx3ZCA9IDIpCmFibGluZShsbSh5MiB+IHgyKSwgY29sID0gMywgbHR5ID0gMywgbHdkID0gMikKYWJsaW5lKGxtKHkzIH4geDMpLCBjb2wgPSA0LCBsdHkgPSA0LCBsd2QgPSAyKQpsZWdlbmQoInRvcGxlZnQiLCBjb2wgPSAxOjQsIGx0eSA9IDE6NCwgbGVnZW5kID0gcGFzdGUoImxtIiwgYygiIiwgYXMuY2hhcmFjdGVyKDE6MykpKSwgdGV4dC5jb2wgPSAxOjQpCmBgYAoKLS0tCgotIEl0IGlzIG5vdCBkZXNpcmFibGUgdGhhdCBhIHNpbmdsZSBvYnNlcnZhdGlvbiBsYXJnZWx5IGluZmx1ZW5jZXMgdGhlIHJlc3VsdCBvZiBhIGxpbmVhciByZWdyZXNzaW9uIGFuYWx5c2lzCgotIERpYWdub3N0aWNzIGFsbG93IHVzIHRvIGRldGVjdCBleHRyZW1lIG9ic2VydmF0aW9ucy4KLSAqU3R1ZGVudGl6ZWQgcmVzaWR1YWxzKiB0byBzcG90IG91dGxpZXJzCi0gKkxldmVyYWdlKiB0byBzcG90IG9ic2VydmF0aW9ucyB3aXRoIGV4dHJlZW0gY292YXJpYXRlIHBhdHRlcm4KCi0tLQoKIyMjIENvb2sncyBkaXN0YW5jZQoKLSBBIHN0YXRpc3RpY3MgdG8gYXNzZXNzIHRoZSBpbmZsdWVuY2UgdGhlIGVmZmVjdCBvZiBhIHNpbmdsZSBvYnNlcnZhdGlvbiBvbiB0aGUgcmVncmVzc2lvbiBhbmFseXNpcwotIENvb2sncyBkaXN0YW5jZSBmb3Igb2JzZXJ2YXRpb24gaSBpcyBkaWFnbm9zdGljIG1lYXN1cmUgZm9yIHRoaXMgcGFydGljdWxhciBvYnNlcnZhdGlvbiBvbiBhbGwgYWxsIHByZWRpY3Rpb25zIG9yIG9uICphbGwqIGVzdGltYXRlZCBwYXJhbWV0ZXJzLgpcW0RfaT1cZnJhY3tcc3VtX3tqPTF9Xm4oXGhhdHtZfV9qLVxoYXR7WX1fe2ooaSl9KV4yfXtwXHRleHRybXtNU0V9fVxdCgotIE9ic2VydmF0aW9uICRpJCBoYXMgYSBsYXJnZSBpbmZsdWVuY2Ugb24gdGhlIHJlZ3Jlc3Npb24gcGFyYW1ldGVycyBhbmQgcHJlZGljdGlvbnMgaWYgdGhlICBDb29rJ3MgZGlzdGFuY2UgJERfaSQgaXMgbGFyZ2UuCi0gRXh0cmVtZSBDb29rJ3MgZGlzdGFuY2UgaWYgaXQgaXMgbGFyZ2VyIHRoYW4gdGhlIDUwJSBxdWFudGlsZSBvZiBhbiAkRl97cCsxLG4tKHArMSl9JC1kaXN0cmlidXRpb24uCgotLS0KCgpgYGB7ciAgb3V0LndpZHRoPScxMDAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQpwYXIobWZyb3cgPSBjKDIsIDIpKQpwbG90KGxtVldTLCB3aGljaCA9IDUpCnBsb3QobG1WV1NfSW50VlcsIHdoaWNoID0gNSkKcGxvdChjb29rcy5kaXN0YW5jZShsbVZXUyksIHR5cGUgPSAiaCIsIHlsaW0gPSBjKDAsIDEpLCBtYWluID0gIkFkZGl0aXZlIG1vZGVsIikKYWJsaW5lKGggPSBxZigwLjUsIGxlbmd0aChsbVZXUyRjb2VmKSwgbnJvdyhwcm9zdGF0ZSkgLSBsZW5ndGgobG1WV1MkY29lZikpLCBsdHkgPSAyKQpwbG90KGNvb2tzLmRpc3RhbmNlKGxtVldTX0ludFZXKSwgdHlwZSA9ICJoIiwgeWxpbSA9IGMoMCwgMSksIG1haW4gPSAiTW9kZWwgd2l0aCBsY2F2b2w6bHdlaWdodCBpbnRlcmFjdGlvbiIpCmFibGluZShoID0gcWYoMC41LCBsZW5ndGgobG1WV1NfSW50VlckY29lZiksIG5yb3cocHJvc3RhdGUpIC0gbGVuZ3RoKGxtVldTX0ludFZXJGNvZWYpKSwgbHR5ID0gMikKYGBgCgotLS0KCi0gT25jZSB3ZSBlc3RhYmxpc2hlZCB0aGF0IGFuIG9ic2VydmF0aW9uIGlzIGluZmx1ZW50aWFsIHdlIGNhbiB1c2UgKkRGQkVUQVMqIHRvIGZpbmQgdGhlIHBhcmFtZXRlcnMgZm9yIHdoaWNoIHRoZSBlc3RpbWF0ZXMgYXJlIGxhcmdlbHkgYWZmZWN0ZWQgYnkgdGhlIG9ic2VydmF0aW9uCi0gIERGQkVUQVMgb2Ygb2JzZXJ2YXRpZSBpIGlzIGEgZGlhZ25vc3RpYyBtZWFzdXJlIGZvciAqZWFjaCBtb2RlbCBwYXJhbWV0ZXIgc2VwYXJhdGVseSouCiQkXHRleHRybXtERkJFVEFTfV97aihpKX09XGZyYWN7XGhhdHtcYmV0YX1fe2p9LVxoYXR7XGJldGF9X3tqKGkpfX17XHRleHRybXtTRH0oXGhhdHtcYmV0YX1fe2p9KX0kJAotICBERkJFVEFTIGlzIGV4dHJlbWUgd2hlbiBpdCBpcyBsYXJnZXIgdGhhbiAxIGluIHNtYWxsIHRvIG1vZGVyYXRlIGRhdGFzZXRzIG9yIGV4Y2VlZHMgJDIvXHNxcnR7bn0kIGluIGxhcmdlIGRhdGFzZXRzLgoKLS0tCgoKYGBge3Igb3V0LndpZHRoPSc5MCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9CnBhcihtZnJvdyA9IGMoMiwgMikpCmRmYmV0YXNQbG90cyhsbVZXUykKYGBgCgotLS0KCmBgYHtyIG91dC53aWR0aD0nOTAlJywgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQpwYXIobWZyb3cgPSBjKDIsIDIpKQpkZmJldGFzUGxvdHMobG1WV1NfSW50VlcpCmBgYAoKLS0tCgpgYGB7ciBvdXQud2lkdGg9JzEwMCUnLGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0KYm94cGxvdChleHAocHJvc3RhdGUkbHdlaWdodCksIHlsYWIgPSAiUHJvc3RhdGUgV2VpZ2h0IChnKSIpCmBgYAoKCiMgQ29uc3RyYXN0cwoKLSBJbiBtb3JlIGNvbXBsZXggZGVzaWducyB0aGF0IGFyZSBtb2RlbGxlZCB1c2luZyBnZW5lcmFsIGxpbmVhciBtb2RlbHMgb25lIG9mdGVuIGhhcyB0byBhc3Nlc3MgbXVsdGlwbGUgaHlwb3RoZXNlcy4KLSBNb3Jlb3ZlciB0aGVzZSBoeXBvdGhlc2VzIGNhbiB0eXBpY2FsbHkgbm90IGFsd2F5cyBiZSB0cmFuc2xhdGVkIGludG8gYSB0ZXN0IG9uIG9uZSBwYXJhbWV0ZXIsIGJ1dCBpbiBhIGxpbmVhciBjb21iaW5hdGlvbiBvZiBtb2RlbCBwYXJhbWV0ZXJzLgotIEEgbGluZWFyIGNvbWJpbmF0aW9uIG9mIG1vZGVsIHBhcmFtZXRlcnMgaXMgYWxzbyByZWZlcnJlZCB0byBhcyBhIGNvbnRyYXN0LgoKIyMgTkhBTkVTIGV4YW1wbGUKCi0gU3VwcG9zZSB0aGF0IHJlc2VhcmNoZXJzIHdhbnQgdG8gYXNzZXNzIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGFnZSBhbmQgYmxvb2RwcmVzc3VyZS4KCi0gUG9zc2libHkgdGhpcyBhc3NvY2lhdGlvbiB3aWxsIGRpZmZlciBmb3IgZmVtYWxlcyBhbmQgbWFsZXMuCgotIFRoZXkgd2FudCB0byBhc3Nlc3MgZm9sbG93aW5nIGh5cG90aGVzZXM6CgogICAgLSBJcyB0aGVyZSBhbiBhc3NvY2lhdGlvbiBiZXR3ZWVuIGFnZSBhbmQgYmxvb2QgcHJlc3N1cmUgZm9yIGZlbWFsZXM/CiAgICAtIElzIHRoZXJlIGFuIGFzc29jaWF0aW9uIGJldHdlZW4gYWdlIGFuZCBibG9vZCBwcmVzc3VyZSBmb3IgbWFsZXM/CiAgICAtIElzIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGFnZSBhbmQgYmxvb2QgcHJlc3N1cmUgZGlmZmVyZW50IGZvciBmZW1hbGVzIGFuZCAgbWFsZXM/CgojIyBNb2RlbAoKV2UgZml0IGEgbW9kZWwgZm9yIHRoZSBhdmVyYWdlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIChgQlBTeXNBdmVgKSB1c2luZyBhZ2UsIGdlbmRlciBhbmQgdGhlIGludGVyYWN0aW9uIGJldHdlZW4gYWdlIGFuZCBnZW5kZXIgZm9yIGFkdWx0IGNhdWNhc2lhbnMgZnJvbSB0aGUgTkhBTkVTIHN0dWR5LgoKYGBge3J9CmxpYnJhcnkoTkhBTkVTKQpicERhdGEgPC0gTkhBTkVTICU+JQogIGZpbHRlcigKICAgIFJhY2UxID09ICJXaGl0ZSIgJgogICAgICBBZ2UgPj0gMTggJgogICAgICAhaXMubmEoQlBTeXNBdmUpCiAgKQoKbUJwMSA8LSBsbShCUFN5c0F2ZSB+IEFnZSAqIEdlbmRlciwgYnBEYXRhKQpwYXIobWZyb3cgPSBjKDIsIDIpKQpwbG90KG1CcDEpCmBgYAoKLSBBc3N1bXB0aW9ucyBhcmUgbm90IGZ1bGxmaWxsZWQhCgogICAgLSBsaW5lYXJpdGVpdCBpcyBvawogICAgLSBoZXRlcm9zY2VkYXN0aWNpdHkKICAgIC0gTm8gbm9ybWFsaXR5OiBkaXN0cmlidXRpb24gaXMgc2tld2VkIHRvIHRoZSByaWdodCAuCiAgICAtIExhcmdlIGRhdGFzZXQgc28gd2UgY2FuIGFkb3B0IHRoZSBDTFQKCiMjIyBUcmFuc2Zvcm1hdGlvbgoKV2UgZml0IGEgbW9kZWwgdXNpbmcgbG9nMiB0cmFuc2Zvcm1lZCBhdmVyYWdlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIChgQlBTeXNBdmVgKS4KCmBgYHtyfQptQnAyIDwtIGxtKEJQU3lzQXZlICU+JSBsb2cyKCkgfiBBZ2UgKiBHZW5kZXIsIGJwRGF0YSkKcGFyKG1mcm93ID0gYygyLCAyKSkKcGxvdChtQnAyKQpgYGAKCi0gUmVzaWR1YWxzIGFyZSBzdGlsbCBoZXRlcm9zY2VkYXN0aWMuCgojIyMgUmVtZWRpYXRlIGZvciBoZXRlcm9zY2VkYXN0aWNpdHkKCi0gSWYgdGhlIHJlc2lkdWFsIHBsb3Qgc2hvd3MgYSBjb25lIHdlIGNhbiBnZXQgdG8gdmFsaWQgaW5mZXJlbmNlIGZvciBsYXJnZSBzYW1wbGVzIGJ5IG1vZGVsaW5nIHRoZSB2YXJpYW5jZSAgZXhwbGljaXRseSBpbiBmdW5jdGlvbiBvZiB0aGUgZml0dGVkIHJlc3BvbnNlLgoKLSBUaGUgaW52ZXJzZSB2YXJpYW5jZSBmb3IgZWFjaCBvYnNlcnZhdGlvbiBjYW4gdGhhbiBiZSB1c2VkIGFzIGEgd2VpZ2h0IGluIHRoZSBsbSBmdW5jdGlvbi4KCjEuIE1vZGVsIHN0YW5kYXJkIGRldmlhdGlvbiBpbiBmdW5jdGlvbiBvZiBtZWFuIHJlc3BvbnNlLgoyLiBEbyB0aGlzIGJ5IG1vZGVsaW5nIGFic29sdXRlIHZhbHVlcyBvZiByZXNpZHVhbHMgaW4gZnVuY3Rpb24gb2YgZml0dGVkIHZhbHVlcyBvZiBtb2RlbC4KMy4gV2UgY2FuIHRoYW4gZXN0aW1hdGUgdGhlIHZhcmlhbmNlIG9mIFkgZm9yIGVhY2ggb2JzZXJ2YXRpb24gYnkgc3F1YXJpbmcgdGhlIHByZWRpY3Rpb25zIGZvciBhbGwgb2JzZXJ2YXRpb25zIHVzaW5nIHRoZSBtb2RlbCBmb3IgdGhlIHN0YW5kYXJkIGRldmlhdGlvbi4KNC4gSW5mZXJlbmNlIHJlbWFpbnMgdmFsaWQgYXN5bXB0b3RpY2FsbHkuCgpgYGB7cn0KbVNkIDwtIGxtKG1CcDEkcmVzICU+JSBhYnMoKSB+IG1CcDIkZml0dGVkKQpgYGAKCldlIGVzdGltYXRlIHRoZSBtb2RlbCBhZ2FpbjoKCmBgYHtyfQptQnAzIDwtIGxtKEJQU3lzQXZlIH4gQWdlICogR2VuZGVyLCBicERhdGEsIHcgPSAxIC8gbVNkJGZpdHRlZF4yKQpgYGAKClJlc2lkdWFscyBhcmUgc3RpbGwgaGV0ZXJvc2NlZGFzdGljLgoKYGBge3J9CmRhdGEuZnJhbWUocmVzaWR1YWxzID0gbUJwMyRyZXNpZHVhbHMsIGZpdCA9IG1CcDMkZml0dGVkKSAlPiUKICBnZ3Bsb3QoYWVzKGZpdCwgcmVzaWR1YWxzKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCkJ1dCB3ZSBhY2NvdW50ZWQgZm9yIHRoYXQgdXNpbmcgd2VpZ2h0cyEKTm90ZSB0aGF0IGlmIHdlIHJlc2NhbGUgdGhlIHJlc2lkdWFscyB1c2luZyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIChtdWx0aXBseWluZyB0aGVtIHdpdGggdGhlIHNxdWFyZSByb290IG9mIHRoZSB3ZWlnaHQpIHdlIG9idGFpbiAgcmVzY2FsZWQgcmVzaWR1YWxzIHRoYXQgYXJlIGhvbW9zY2VkYXN0aWMuCgpUaGUgbW9kZWwgcGFyYW1ldGVycyBhcmUgZXN0aW1hdGVkIHVzaW5nIHdlaWdodGVkIGxlYXN0IHNxdWFyZXM6CgpcWyBTU0UgPSBcc3VtXGxpbWl0c197aT0xfV5uIHdfaSBlX2leMlxdCgp3aXRoICR3X2kgPSAxL1xoYXQgXHNpZ21hXjJfaSQuCgpXZWlnaHRlZCByZWdyZXNzaW9uIHdpbGwgY29ycmVjdCBmb3IgaGV0ZXJvc2NlZGFzdGljaXR5LgoKYGBge3J9CmRhdGEuZnJhbWUoc2NhbGVkX3Jlc2lkdWFscyA9IG1CcDMkcmVzaWR1YWxzIC8gbVNkJGZpdHRlZCwgZml0ID0gbUJwMyRmaXR0ZWQpICU+JQogIGdncGxvdChhZXMoZml0LCBzY2FsZWRfcmVzaWR1YWxzKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCiMjIyBJbmZlcmVuY2UKCmBgYHtyfQpzdW1tYXJ5KG1CcDMpCmBgYAoKVGhlIHJlc2VhcmNoIHF1ZXN0aW9ucyB0cmFuc2xhdGUgdG8gZm9sbG93aW5nIG51bGxoeXBvdGhlc2VzOgoKMS4gQXNzb2NpYXRpb24gYmV0d2VlbiBibG9vZCBwcmVzc3VyZSBhbmQgYWdlIGZvciBmZW1hbGVzPyBcW0hfMDogXGJldGFfXHRleHR7QWdlfSA9IDAgXHRleHR7IHZzIH0gSF8xOiBcYmV0YV9cdGV4dHtBZ2V9IFxuZXEgMCBcXQoKMi4gQXNzb2NpYXRpb24gYmV0d2VlbiBibG9vZCBwcmVzc3VyZSBhbmQgYWdlIGZvciBtYWxlcz8gXFtIXzA6IFxiZXRhX1x0ZXh0e0FnZX0gKyBcYmV0YV9cdGV4dHtBZ2U6R2VuZGVybWFsZX0gPSAwIFx0ZXh0eyB2cyB9IEhfMTogXGJldGFfXHRleHR7QWdlfSArIFxiZXRhX1x0ZXh0e0FnZTpHZW5kZXJtYWxlfSBcbmVxIDAgXF0KCjMuIElzIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGJsb29kIHByZXNzdXJlIGFuZCBhZ2UgZGlmZmVyZW50IGZvciBmZW1hbGVzIGFuZCBtYWxlcz8gIFxbSF8wOiBcYmV0YV9cdGV4dHtBZ2U6R2VuZGVybWFsZX0gPSAwIFx0ZXh0eyB2cyB9IEhfMTogXGJldGFfXHRleHR7QWdlOkdlbmRlcm1hbGV9IFxuZXEgMCBcXQoKCi0gV2UgY2FuIGFzc2VzcyBoeXBvdGhlc2VzIDEgYW5kIDMgaW1tZWRpYXRlbHkgdXNpbmcgdGhlIG91dHB1dCBvZiB0aGUgbW9kZWwuCi0gSHlwb3RoZXNlcyAyIGlzIGEgbGluZWFyIGNvbWJpbmF0aW9uIG9mIHR3byBwYXJhbWV0ZXJzLgotIFdlIGFsc28gbmVlZCBtdWx0aXBsZSB0ZXN0cyBmb3IgYXNzZXNzaW5nIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIHN5c0JwIGFuZCBBZ2UuCgpXZSBjYW4gYWdhaW4gdXNlIGFuIEFub3ZhIGFwcHJvYWNoLgoKMS4gIFdlIGZpcnN0IGFzc2VzcyB0aGUgb21uaWJ1cyBoeXBvdGhlc2lzIHRoYXQgdGhlcmUgaXMgbm8gYXNzb2NpYXRpb24gYmV0d2VlbiBhZ2UgYW5kIGJsb29kIHByZXNzdXJlLgpcWyBIXzA6IFxiZXRhX1x0ZXh0e0FnZX0gPSBcYmV0YV9cdGV4dHtBZ2V9ICsgXGJldGFfXHRleHR7QWdlOkdlbmRlcm1hbGV9ID0gXGJldGFfXHRleHR7QWdlOkdlbmRlcm1hbGV9ID0gMApcXQoKLSB3aGljaCBzaW1wbGlmaWVzIHRvIGFzc2Vzc2luZwoKXFsgSF8wOiBcYmV0YV9cdGV4dHtBZ2V9ID0gXGJldGFfXHRleHR7QWdlOkdlbmRlcm1hbGV9ID0gMApcXQoKLSBXZSBjYW4gZG8gdGhpcyBieSBjb21wYXJpbmcgdHdvIG1vZGVsczogdGhlIGZ1bGwgbW9kZWwgd2l0aCBhbiBlZmZlY3QgZm9yIEdlbmRlciwgQWdlIGFuZCBHZW5kZXIgeCBBZ2UgaW50ZXJhY3Rpb24gYWdhaW5zdCBhIHJlZHVjZWQgbW9kZWwgd2l0aCBvbmx5IEdlbmRlci4KCjIuIElmIHdlIGNhbiByZWplY3QgdGhpcyBoeXBvdGhlc2lzIHdlIGNhbiBhZ2FpbiBkbyBhIHBvc3Rob2MgYW5hbHlzaXMgZm9yIGVhY2ggb2YgdGhlIGNvbnRyYXN0cy4KCgojIyMjIE9tbmlidXMgdGVzdAoKYGBge3J9Cm1CcDAgPC0gbG0oQlBTeXNBdmUgfiBHZW5kZXIsIGJwRGF0YSwgdyA9IDEgLyBtU2QkZml0dGVkXjIpCmFub3ZhKG1CcDAsIG1CcDMpCmBgYAoKCiMjIyMgUG9zdGhvYyB0ZXN0cwoKRm9yIHRoZSBwb3N0aG9jIHRlc3RzIHdlIHdpbGwgYWdhaW4gYnVpbGQgdXBvbiB0aGUgYG11bHRjb21wYCBwYWNrYWdlLgoKYGBge3J9CmxpYnJhcnkobXVsdGNvbXApCmJwUG9zdGhvYyA8LSBnbGh0KG1CcDMsIGxpbmZjdCA9IGMoCiAgIkFnZSA9IDAiLAogICJBZ2UgKyBBZ2U6R2VuZGVybWFsZSA9IDAiLAogICJBZ2U6R2VuZGVybWFsZSA9IDAiCikpCmJwUG9zdGhvYyAlPiUgc3VtbWFyeSgpCgpicFBvc3Rob2NDSSA8LSBicFBvc3Rob2MgJT4lIGNvbmZpbnQoKQpicFBvc3Rob2NDSQpgYGAKCk5vdGUgdGhhdCB0aGUgZ2xodCBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gZGVmaW5lIHRoZSBjb250cmFzdHMgYnkgZXhwbGljaXRlbHkgZGVmaW5pbmcgdGhlIG51bGxoeXBvdGhlc2UgdXNpbmcgdGhlIG5hbWVzIG9mIHRoZSBtb2RlbCBwYXJhbWV0ZXJzLgoKIyMjIyBDb25jbHVzaW9uCgpXZSBjYW4gY29uY2x1ZGUgdGhhdCB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiBhZ2UgYW5kIGJsb29kIHByZXNzdXJlIGlzIGV4dHJlbWVseSBzaWduaWZpY2FudCAocCA8PCAwLjAwMSkuCgpUaGUgYmxvb2QgcHJlc3N1cmUgZm9yIGZlbWFsZXMgdGhhdCBkaWZmZXIgaW4gYWdlIGlzIG9uIGF2ZXJhZ2UgYHIgcm91bmQoYnBQb3N0aG9jQ0kkY29uZmludFsxLDFdLDIpYCBtbSBIZyBoaWdoZXIgcGVyIHllYXIgb2YgYWdlIGRpZmZlcmVuY2UgZm9yIHRoZSBlbGRlc3QgZmVtYWxlIGFuZCBpcyBleHRyZW1lbHkgc2lnbmlmaWNhbnQgKHAgPDwgMC4wMDEsIDk1JSBDSSBbYHIgcm91bmQoYnBQb3N0aG9jQ0kkY29uZmludFsxLC0xXSwyKWBdLgoKVGhlIGJsb29kIHByZXNzdXJlIGZvciBtYWxlcyB0aGF0IGRpZmZlciBpbiBhZ2UgaXMgb24gYXZlcmFnZSBgciByb3VuZChicFBvc3Rob2NDSSRjb25maW50WzIsMV0sMilgIG1tIEhnIGhpZ2hlciBwZXIgeWVhciBvZiBhZ2UgZGlmZmVyZW5jZSBmb3IgdGhlIGVsZGVzdCBtYWxlIGFuZCBpcyBleHRyZW1lbHkgc2lnbmlmaWNhbnQgKHAgPDwgMC4wMDEsIDk1JSBDSSBbYHIgcm91bmQoYnBQb3N0aG9jQ0kkY29uZmludFsyLC0xXSwyKWBdLgoKVGhlIGF2ZXJhZ2UgYmxvb2QgcHJlc3N1cmUgZGlmZmVyZW5jZSBiZXR3ZWVuIHN1YmplY3RzIHRoYXQgZGlmZmVyIGluIGFnZSBpcyBvbiBhdmVyYWdlICBgciByb3VuZChhYnMoYnBQb3N0aG9jQ0kkY29uZmludFszLDFdKSwyKWAgbW0gSGcvamFhciBoaWdoZXIgZm9yIGZlbWFsZXMgdGhhbiBmb3IgbWFsZXMgKHAgPDwgMC4wMDEsIDk1JSBDSSBbYHIgYnBQb3N0aG9jQ0kkY29uZmludFszLC0xXSAlPiUgYWJzICU+JSBzb3J0ICU+JXJvdW5kKC4sMilgXSkuCg==