Processing math: 100%
  • 1 Intro
    • 1.1 Prostate cancer example
  • 2 Additive multiple linair model
    • 2.1 Statistical model
      • 2.1.1 Prostate example
  • 3 Inference in multiple linear models
    • 3.1 Assess the model assumptions
    • 3.2 The non additive multiple linear model
      • 3.2.1 Interaction between two continuous variables
    • 3.3 Interaction between a continuous variable and a factor variable
  • 4 ANOVA Tabel
    • 4.1 Additional sums of squares
      • 4.1.1 Type I Sums of Squares
      • 4.1.2 Type III Sums of squares
    • 4.2 We can obtain these sums of squares using the Anova function from the car package.
  • 5 Diagnostics
    • 5.1 Multicollineariteit
      • 5.1.1 Variance inflation factor (VIF)
      • 5.1.2 Body fat example
    • 5.2 Influencial Observaties
      • 5.2.1 Cook’s distance
  • 6 Constrasts
    • 6.1 NHANES example
    • 6.2 Model
      • 6.2.1 Transformation
      • 6.2.2 Remediate for heteroscedasticity
      • 6.2.3 Inference

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 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.

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
ABCDEFGHIJ0123456789
lcavol
<dbl>
lweight
<dbl>
age
<dbl>
lbph
<dbl>
svi
<chr>
lcp
<dbl>
gleason
<dbl>
pgg45
<chr>
lpsa
<dbl>
-0.5798184952.76945950-1.38629436healthy-1.386294366healthy-0.4307829
-0.9942522733.31962658-1.38629436healthy-1.386294366healthy-0.1625189
-0.5108256242.69124374-1.38629436healthy-1.38629436720-0.1625189
-1.2039728043.28278958-1.38629436healthy-1.386294366healthy-0.1625189
0.7514160893.43237362-1.38629436healthy-1.386294366healthy0.3715636
-1.0498221243.22882650-1.38629436healthy-1.386294366healthy0.7654678
0.7371640663.473518640.61518564healthy-1.386294366healthy0.7654678
0.6931471813.539509581.53686722healthy-1.386294366healthy0.8544153
-0.7765287893.53950947-1.38629436healthy-1.386294366healthy1.0473190
0.2231435513.24454463-1.38629436healthy-1.386294366healthy1.0473190
prostate$svi<-as.factor(prostate$svi)


2 Additive multiple linair model

Separate simple linair models, like

E(Y|Xv)=α+βvXv

  • Association between lpsa en 1 variabele e.g lcavol.
  • More accurate predictions by simultaneously accounting for multiple predictors
  • Estimate for parameter βv does not only capture the effect of tumor volume.
  • β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). confounding.
  • Compare patients with same svi status
  • Is posible in multiple linear model

2.1 Statistical model

  • p1 predictors X1,...,Xp1 and outcome Y for n subjecten.

Yi=β0+β1Xi1+...+βp1Xip1+ϵi

  • β0,β1,...,βp1 unknown parameters
  • ϵ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 x1,...,xp1 for the predictor variables. E[Y|X1=x1,Xp1=xp1]=ˆβ0+ˆβ1x1+...+ˆβp1xp1.
  2. Does the average outcome differ between two groups of patients that differ by δ units in predictor Xj but have the same value for the remaining variables {Xk,k=1,...,p,kj}. E(Y|X1=x1,...,Xj=xj+δ,...,Xp1=xp1)E(Y|X1=x1,...,Xj=xj,...,Xp1=xp1)=β0+β1x1+...+βj(xj+δ)+...+βp1xp1β0β1x1...βjxj...βp1xp1=βjδ

Interpretation βj:

  • difference in mean outcome between subjects that differ in one unit of Xj, 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[ˆβj]=βj,j=0,,p1.

  • 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 ϵi are normally distributed.

Under these assumptions: ϵiN(0,σ2). en YiN(β0+β1Xi1++βp1Xip1,σ2)


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

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

ˆσ2=MSE=ni=1(yiˆβ0ˆβ1Xi1ˆβp1Xip1)2np=ni=1e2inp.

Again hypothesis tests and confidence intervals by Tk=ˆβkβkSE(ˆβk) met k=0,,p1.

If all assumptions are satisfied than the statistics Tk t-distributed with np 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 Tk is approximately normally distributed in large samples.


We can build confidence intervals on the slopes by: [ˆβjtnp,α/2SEˆβj,ˆβj+tnp,α/2SEˆβ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: H0:βj=0 H1:βj0

With test statistic T=ˆβj0SE(ˆβj) which follows a t-distribution with np degrees of freedom under H0


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.

β0+βv(xv+δv)+βwxw+βsxsβ0βvxvβwxwβsxs=βvδv

The svi status and the log-prostategewicht (xw) do not influence the contribution of the log-tumor volume (xv) 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

Yi=β0+βvxiv+βwxiw+βsxis+βvwxivxiw+ϵi

This term quantifies the interactie-effect of predictors xv en xw on the mean outcome.

Terms βvxiv and βwxiw are referred to as main effects of predictors xv and xw.


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

E(Y|Xv=xv+1,Xw=xw,Xs=xs)E(Y|Xv=xv,Xw=xw,Xs=xs)=β0+βv(xv+1)+βwxw+βsxs+βvw(xv+1)xwβ0βvxvβwxwβsxsβvw(xv)xw=βv+βvwxw


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 svi and lweight svi.

The model becomes

Y=β0+βvXv+βwXw+βsXs+βvsXvXs+βwsXwXs+ϵ


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 XS is a dummy variabele we obtain to distinct regression planes:

  1. Model for Xs=0: Y=β0+βvXv+βwXw+ϵ where the main effects are the slope for lcavol and lweight
  2. and model for Xs=1: Y=β0+βvXv+βs+βwXw+βvsXv+βwsXw+ϵ=(β0+βs)+(βv+βvs)Xv+(βw+βws)Xw+ϵ with intercept β0+βs and slopes βv+βvs and βw+βws


4 ANOVA Tabel

The total SSTot is again

SSTot=ni=1(YiˉY)2.

The residual sum of squares remains similar SSE=ni=1(YiˆYi)2.

Again the total sum of squares can be decomposed in , SSTot=SSR+SSE, with SSR=ni=1(ˆYiˉY)2.


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

  • SSTot has n1 degrees of freedom and SSTot/(n1) is an estimator for the total variance in Y (marginal distribution of Y).
  • SSE has np degrees of freedom and MSE=SSE/(np) is an schatter for the residual variance of Y given the predictores (i.e. an estimator for the residual variance σ2 of the error term ϵ).
  • SSR has p1 degrees of freedom and MSR=SSR/(p1) is the mean sum of squares of the regression.

The determination coefficients remains as before, i.e. R2=1SSESSTot=SSRSSTot and is the fraction of the total variability that can be explained by the regression model.

Teststatistic F=MSR/MSE is under H0:β1==βp1=0 distributed by an F distribution: Fp1;np.



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 x1 en x2: Yi=β0+β1xi1+ϵi, with ϵi iid N(0,σ21), and Yi=β0+β1xi1+β2xi2+ϵi, with ϵi iid N(0,σ22).

for the first (gereduceerde) model we have decomposition SSTot=SSR1+SSE1 en for the second non-reduced model we have SSTot=SSR2+SSE2 (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 x2 as compared to the model with only x1 as predictor is given by SSR21=SSE1SSE2=SSR2SSR1.

Note that, SSE1SSE2=SSR2SSR1 is triviaal is because of the decomposition of the total sum of squares.

The additional sum of squares SSR21 can simply be interpreted as the additional variability that can be explained by adding predictor x2 to the model with predictor x1.

With this sum of squares we can further decompose the total sum of squares SSTot=SSR1+SSR21+SSE. which follows directly from the definition SSR21.


Extension: (s<p1) Yi=β0+β1xi1++βsxis+ϵi with ϵi iid N(0,σ21), and (s<qp1) Yi=β0+β1xi1++βsxis+βs+1xis+1+βqxiq+ϵi with ϵi iid N(0,σ22).

The additional sum of squares of predictor xs+1,,xq compared to a model with only predictors x1,,xs is given by

SSRs+1,,q1,,s=SSE1SSE2=SSR2SSR1.


4.1.1 Type I Sums of Squares

Suppose that p1 predictors are considered, and suppose the following sequence of models (s=2,,p1) Yi=β0+sj=1βjxij+ϵi wuth ϵi iid N(0,σ2).

  • The corresponding sum of squares are denoted as SSRs and SSEs.
  • The sequence of models gives rise to the following sums of squares: SSRs1,,s1.
  • 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=p1 that SSTot=SSR1+SSR21+SSR31,2++SSRp11,,p2+SSE, with SSE the residual sum of squares of the model with all p1 predictors SSR1+SSR21+SSR31,2++SSRp11,,p2=SSR with SSR the sum of squares of all p1 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 MSRj1,,j1=SSRj1,,j1/1.
  • And teststatistic F=MSRj1,,j1/MSE follows a F1;n(j+1) distribution under H0:β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 xj are given by the additional sum of squares SSRj1,,j1,j+1,,p1=SSE1SSE2

  • SSE2 the sum of squares of the residuals of the model with all p1 predictors.
  • SSE1 sum of squares of the residuals with all p1 predictors, except for predictor xj.

The type III sum of squares SSRj1,,j1,j+1,,p1 quantify the contribution in the total variance of the outcome explained by xj that cannot be explained by the remaining p2 predictors.


The type III sum of squares has 1 degree of freedom because it involves 1 β-parameter.

For each type III SSR term the mean sum of squares is defined by MSRj1,,j1,j+1,,p1=SSRj1,,j1,j+1,,p1/1.

Teststatistiek F=MSRj1,,j1,j+1,,p1/MSE is F1;np distributed under H0:β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)
ABCDEFGHIJ0123456789
 
 
Sum Sq
<dbl>
Df
<dbl>
F value
<dbl>
Pr(>F)
<dbl>
(Intercept)0.125002110.24328156.230088e-01
lcavol28.0445759154.58088646.303883e-11
lweight5.8923334111.46777111.039115e-03
svi5.1813959110.08413122.029035e-03
Residuals47.784961693NANA

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 Multicollineariteit


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 multicollineariteit 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 VIFj=(1R2j)1

  • In this expression R2j 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 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 Influencial Observaties

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. Di=nj=1(ˆYjˆYj(i))2pMSE

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

  • Extreme Cook’s distance if it is larger than the 50% quantile of an Fp+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. DFBETASj(i)=ˆβjˆβj(i)SD(ˆβj)
  • DFBETAS is extreme when it is larger than 1 in small to moderate datasets or exceeds 2/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=ni=1wie2i

with wi=1/ˆσ2i.

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? H0:βAge=0 vs H1:βAge0

  2. Association between blood pressure and age for males? H0:βAge+βAge:Gendermale=0 vs H1:βAge+βAge:Gendermale0

  3. Is the association between blood pressure and age different for females and males? H0:βAge:Gendermale=0 vs H1:βAge:Gendermale0

  • 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. H0:βAge=βAge+βAge:Gendermale=βAge:Gendermale=0
  • which simplifies to assessing

H0:βAge=β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)
ABCDEFGHIJ0123456789
 
 
Res.Df
<dbl>
RSS
<dbl>
Df
<dbl>
Sum of Sq
<dbl>
F
<dbl>
Pr(>F)
<dbl>
1483010200.529NANANANA
248288404.52921796515.8589.123215e-204

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]).

LS0tCnRpdGxlOiAiOC4gTXVsdGlwbGUgcmVncmVzc2lvbiIgCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50IgpkYXRlOiAic3RhdE9taWNzLCBHaGVudCBVbml2ZXJzaXR5IChodHRwczovL3N0YXRvbWljcy5naXRodWIuaW8pIgpvdXRwdXQ6CiAgICBodG1sX2RvY3VtZW50OgogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAgIAogICAgICB0aGVtZTogY29zbW8KICAgICAgdG9jOiB0cnVlCiAgICAgIHRvY19mbG9hdDogdHJ1ZQogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQotLS0KCgo8YSByZWw9ImxpY2Vuc2UiIGhyZWY9Imh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy1zYS80LjAiPjxpbWcgYWx0PSJDcmVhdGl2ZSBDb21tb25zIExpY2Vuc2UiIHN0eWxlPSJib3JkZXItd2lkdGg6MCIgc3JjPSJodHRwczovL2kuY3JlYXRpdmVjb21tb25zLm9yZy9sL2J5LW5jLXNhLzQuMC84OHgzMS5wbmciIC8+PC9hPgoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSkKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKCiMgSW50cm8KCi0gVW50aWwgbm93OiBvbmUgb3V0Y29tZSAkWSQgYW5kIGEgc2luZ2xlICBwcmVkaWN0b3IgJFgkLgotIE9mdGVuIHVzZWZ1bCB0byB1c2UgbXVsdGlwbGUgcHJlZGljdG9ycyB0byBtb2RlbCB0aGUgcmVzcG9uc2UuIGUuZwoKMS4gQXNzb2NpYXRpb24gYmV0d2VlbiBYIGFuZCBZIGlzIGFmZmVjdGVkIGJ5IGNvbmZvdW5kZXI6IFNtb2tpbmcgYW5kIGFnZSBieSB5b3VuZ3N0ZXJzIGFyZSBjb25mb3VuZGVkIGFuZCB0aGV5IGJvdGggYWZmZWN0IHRoZSBsdW5nIGNhcGFjaXR5CjIuIFdoaWNoIGdyb3VwIG9mIHZhcmlhYmxlcyBpcyBhc3NvY2lhdGVkIHdpdGggYSBnaXZlbiBvdXRjb21lLiBFLmcgSGFiaXRhdCBhbmQgaHVtYW4gYWN0aXZpdHkgb24gdGhlIGJpb2RpdmVyc2l0eSBvZiB0aGUgcmFpbiBmb3Jlc3QuIChTaXplLCBhZ2UsIGhlaWdodCBvZiB0aGUgd29vZCAkXHJpZ2h0YXJyb3ckIGFzc2VzcyBhbGwgZWZmZWN0cyBzaW11bHRhbmVvdXNseS4KMy4gUHJlZGljdGlvbiBvZiBvdXRjb21lIGZvciBpbmRpdmlkdWFsczogdXNlIGFzIG1hbnkgcHJlZGljdGl2ZSBpbmZvcm1hdGlvbiBzaW11bHRhbmVvdXNseS4gRS5nIHByZWRpY3Rpb24gb2YgcmlzayBvbiBtb3J0YWxpdHkgaXMgdXNlZCBvbiBhIGRhaWx5IGJhc2lzIGluIGludGVuc2l2ZSBjYXJlIHVuaXRzIHRvIHByaW9yaXRpc2UgcGF0aWVudCBjYXJlLiAKCiRccmlnaHRhcnJvdyQgRXh0ZW5kIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiB0byBtdWx0aXBsZSBwcmVkaWN0b3JzLiAKCi0tLQoKIyMgUHJvc3RhdGUgY2FuY2VyIGV4YW1wbGUKCi0gUHJvc3RhdGUgc3BlY2lmaWMgYW50aWdlbiAoUFNBKSBhbmQgYSBudW1iZXIgb2YgY2xpbmljYWwgdmFyaWFibGVzIGZvciA5NyBtYWxlcyB3aXRoIHJhZGljYWwgcHJvc3RhdGVjdG9teS4gCi0gQXNzb2NpYXRpb24gb2YgUFNBIGJ5IAoKICAgIC0gdHVtb3Igdm9sdW1lIChsY2F2b2wpCiAgICAtIHByb3N0YXRlIHdlaWdodCAobHdlaWdodCkKICAgIC0gYWdlCiAgICAtIGJlbmlnbiBwcm9zdGF0ZSBoeXBlcnRyb3BoeSAgKGxicGgpCiAgICAtIHNlbWluYWwgdmVzaWNsZSBpbnZhc2lvbiAoc3ZpKQogICAgLSBjYXBzdWxhciBwZW5ldHJhdGlvbiAobGNwKQogICAgLSBHbGVhc29uIHNjb3JlIChnbGVhc29uKSAKICAgIC0gcHJlY2VudGFnZSBnbGVhc29uIHNjb3JlIDQvNSAocGdnNDUpCiAKLS0tCgpgYGB7cn0KcHJvc3RhdGU8LXJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vR1RQQi9QU0xTMjAvbWFzdGVyL2RhdGEvcHJvc3RhdGUuY3N2IikKcHJvc3RhdGUKcHJvc3RhdGUkc3ZpPC1hcy5mYWN0b3IocHJvc3RhdGUkc3ZpKQpgYGAKCi0tLQoKYGBge3IgLCBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KbGlicmFyeShHR2FsbHkpCnByb3N0YXRlICU+JSBzZWxlY3QoLXBnZzQ1KSAgJT4lIGdncGFpcnMoKQpgYGAKCi0tLQoKIyBBZGRpdGl2ZSAgbXVsdGlwbGUgbGluYWlyIG1vZGVsCgpTZXBhcmF0ZSBzaW1wbGUgbGluYWlyIG1vZGVscywgbGlrZSAKCiQkRShZfFhfdik9XGFscGhhK1xiZXRhX3YgWF92JCQKCi0gQXNzb2NpYXRpb24gYmV0d2VlbiBscHNhIGVuIDEgdmFyaWFiZWxlIGUuZyBsY2F2b2wuCi0gTW9yZSBhY2N1cmF0ZSBwcmVkaWN0aW9ucyBieSBzaW11bHRhbmVvdXNseSBhY2NvdW50aW5nIGZvciBtdWx0aXBsZSBwcmVkaWN0b3JzCi0gRXN0aW1hdGUgZm9yIHBhcmFtZXRlciAkXGJldGFfdiQgZG9lcyBub3Qgb25seSBjYXB0dXJlIHRoZSBlZmZlY3Qgb2YgdHVtb3Igdm9sdW1lLgotICRcYmV0YV92JCBhdmVyYWdlIGRpZmZlcmVuY2UgZm9yIGxvZy1wc2EgZm9yIHBhdGllbnRzIHRoYXQgZGlmZmVyIGluIDEgdW5pdCBvZiB0aGUgbG9nIHR1bW9yIHZvbHVtZS4gCi0gRXZlbiBpZiBsY2F2b2wgaXMgbm90IGFzc29jaWF0ZWQgd2l0aCBscHNhIHRoZW4gcGF0aWVudHMgd2l0aCBhIGhpZ2hlciB0dW1vciB2b2x1bWUgY2FuIGhhdmUgYSBoaWdoZXIgbHBzYSBiZWNhdXNlIHRoZWlyIHNlbWVuIHZlc2ljbGVzIGFyZSBhZmZlY3RlZCAoc3ZpIHN0YXR1cyAxKS4KJFxyaWdodGFycm93JCBjb25mb3VuZGluZy4KLSBDb21wYXJlIHBhdGllbnRzIHdpdGggc2FtZSBzdmkgc3RhdHVzCi0gSXMgcG9zaWJsZSBpbiBtdWx0aXBsZSBsaW5lYXIgbW9kZWwKCi0tLQoKIyMgU3RhdGlzdGljYWwgbW9kZWwKCi0gJHAtMSQgcHJlZGljdG9ycyAkWF8xLC4uLixYX3twLTF9JCBhbmQgb3V0Y29tZSAkWSQgZm9yICRuJCBzdWJqZWN0ZW4uIAoKXGJlZ2lue2VxdWF0aW9ufSAgCllfaSA9XGJldGFfMCArIFxiZXRhXzEgWF97aTF9ICsgLi4uICtcYmV0YV97cC0xfSBYX3tpcC0xfSArIFxlcHNpbG9uX2kKXGVuZHtlcXVhdGlvbn0KCi0gJFxiZXRhXzAsXGJldGFfMSwuLi4sXGJldGFfe3AtMX0kIHVua25vd24gcGFyYW1ldGVycwotICRcZXBzaWxvbl9pJCByZXNpZHVhbHMgdGhhdCBjYW5ub3QgYmUgZXhwbGFpbmVkIGJ5IHByZWRpY3RvcnMKLSBFc3RpbWF0aW9uIGJ5ICpsZWFzdCBzcXVhcmVzIG1ldGhvZCogCgotLS0KCk1vZGVsIGFsbG93cyB0bwoKMS4gcHJlZGljdCB0aGUgZXhwZWN0ZWQgb3V0Y29tZSBmb3Igc3ViamVjdHMgZ2l2ZW4gdGhlaXIgdmFsdWVzICR4XzEsLi4uLHhfe3AtMX0kIGZvciB0aGUgcHJlZGljdG9yIHZhcmlhYmxlcy4gCiRFW1lcdmVydCBYXzE9eF8xLCBcbGRvdHMgWF97cC0xfT14X3twLTF9XT1caGF0e1xiZXRhfV8wK1xoYXR7XGJldGF9XzF4XzErLi4uK1xoYXR7XGJldGF9X3twLTF9eF97cC0xfSQuCjIuIERvZXMgdGhlIGF2ZXJhZ2Ugb3V0Y29tZSBkaWZmZXIgYmV0d2VlbiB0d28gZ3JvdXBzIG9mIHBhdGllbnRzIHRoYXQgZGlmZmVyIGJ5ICRcZGVsdGEkIHVuaXRzIGluIHByZWRpY3RvciAkWF9qJCBidXQgaGF2ZSB0aGUgc2FtZSB2YWx1ZSBmb3IgdGhlIHJlbWFpbmluZyB2YXJpYWJsZXMgJFx7WF9rLGs9MSwuLi4scCxrXG5lIGpcfSQuIAokJApcYmVnaW57YXJyYXl9e2x9CkUoWXxYXzE9eF8xLC4uLixYX2o9eF9qK1xkZWx0YSwuLi4sWF97cC0xfT14X3twLTF9KSBcXApccXVhZFxxdWFkIC0gRShZfFhfMT14XzEsLi4uLFhfaj14X2osLi4uLFhfe3AtMX09eF97cC0xfSkgXFxcXApccXVhZCA9XGJldGFfMCArIFxiZXRhXzEgeF8xICsgLi4uICsgXGJldGFfaih4X2orXGRlbHRhKSsuLi4rXGJldGFfe3AtMX0geF97cC0xfVxcIApccXVhZFxxdWFkLSBcYmV0YV8wIC0gXGJldGFfMSB4XzEgLSAuLi4gLSBcYmV0YV9qeF9qLS4uLi1cYmV0YV97cC0xfSB4X3twLTF9IFxcXFwKXHF1YWQ9IFxiZXRhX2pcZGVsdGEKXGVuZHthcnJheX0KJCQKCkludGVycHJldGF0aW9uICRcYmV0YV9qJDogCgotIGRpZmZlcmVuY2UgaW4gbWVhbiBvdXRjb21lIGJldHdlZW4gc3ViamVjdHMgdGhhdCBkaWZmZXIgaW4gb25lIHVuaXQgb2YgJFhfaiQsIGJ1dCBoYXZlIHRoZSBzYW1lIHZhbHVlIGZvciB0aGUgcmVtYWluaW5nIHByZWRpY3RvcnMgaW4gdGhlIG1vZGVsLiAgCgpvciAKCi0gRWZmZWN0IG9mIHByZWRpY3RvciBqIGNvcnJlY3RlZCBmb3IgdGhlIHJlbWFpbmluZyBwcmVkaWN0b3JzLiAgZS5nLiBlZmZlY3Qgb2YgY2FuY2VyIHZvbHVtZSBjb3JyZWN0IGZvciBwcm9zdGF0ZSB3ZWlnaHQgYW5kIHRoZSBzdmkgc3RhdHVzLiAKCi0tLQoKIyMjIFByb3N0YXRlIGV4YW1wbGUKCmBgYHtyfQpsbVYgPC0gbG0obHBzYX5sY2F2b2wscHJvc3RhdGUpCnN1bW1hcnkobG1WKQpgYGAKCi0tLQoKYGBge3J9CmxtVldTIDwtIGxtKGxwc2F+bGNhdm9sICsgbHdlaWdodCArIHN2aSAscHJvc3RhdGUpCnN1bW1hcnkobG1WV1MpCmBgYAoKLS0tCgpgYGB7ciBvdXQud2lkdGg9JzgwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQpsaWJyYXJ5KHBsb3QzRCkKZ3JpZC5saW5lcyA9IDEwCng8LXByb3N0YXRlJGxjYXZvbAp5PC1wcm9zdGF0ZSRsd2VpZ2h0Cno8LXByb3N0YXRlJGxwc2EKZml0PC1sbSh6fngreStzdmksZGF0YT1wcm9zdGF0ZSkKeC5wcmVkIDwtIHNlcShtaW4oeCksIG1heCh4KSwgbGVuZ3RoLm91dCA9IGdyaWQubGluZXMpCnkucHJlZCA8LSBzZXEobWluKHkpLCBtYXgoeSksIGxlbmd0aC5vdXQgPSBncmlkLmxpbmVzKQoKIyBmaXR0ZWQgcG9pbnRzIGZvciBkcm9wbGluZXMgdG8gc3VyZmFjZQp0aD0yMApwaD01IApzY2F0dGVyM0QoeCwgeSwgeiwgcGNoID0gMTYsY29sPWMoImRhcmtibHVlIiwicmVkIilbYXMuZG91YmxlKHByb3N0YXRlJHN2aSldLCBjZXggPSAuNzUsIAogICAgdGhldGEgPSB0aCwgcGhpID0gcGgsIHRpY2t0eXBlID0gImRldGFpbGVkIiwKICAgIHhsYWIgPSAibGNhdm9sIiwgeWxhYiA9ICJsd2VpZ2h0IiwgemxhYiA9ICJscHNhIiwgIAogICBjb2x2YXI9RkFMU0UsYnR5ID0gImciKQoKZm9yIChpIGluIDE6bnJvdyhwcm9zdGF0ZSkpCmxpbmVzM0QoeD1yZXAocHJvc3RhdGUkbGNhdm9sW2ldLDIpLHk9cmVwKHByb3N0YXRlJGx3ZWlnaHRbaV0sMiksej1jKHByb3N0YXRlJGxwc2FbaV0sbG1WV1MkZml0W2ldKSxjb2w9YygiZGFya2JsdWUiLCJyZWQiKVthcy5kb3VibGUocHJvc3RhdGUkc3ZpKVtpXV0sYWRkPVRSVUUsbHR5PTIpCgp6LnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCx5KSB7bG1WV1MkY29lZlsxXStsbVZXUyRjb2VmWzJdKngrbG1WV1MkY29lZlszXSp5fSkKeC5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLHkucHJlZCxmdW5jdGlvbih4LHkpIHgpCnkucHJlZDNEIDwtIG91dGVyKHgucHJlZCx5LnByZWQsZnVuY3Rpb24oeCx5KSB5KQpzdXJmM0QoeC5wcmVkM0QseS5wcmVkM0Qsei5wcmVkM0QsY29sPSJibHVlIixmYWNldHM9TkEsYWRkPVRSVUUpCnoyLnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCx5KSB7bG1WV1MkY29lZlsxXStsbVZXUyRjb2VmWzRdK2xtVldTJGNvZWZbMl0qeCtsbVZXUyRjb2VmWzNdKnl9KQpzdXJmM0QoeC5wcmVkM0QseS5wcmVkM0QsejIucHJlZDNELGNvbD0icmVkIixmYWNldHM9TkEsYWRkPVRSVUUpCmBgYAoKLS0tCgojIEluZmVyZW5jZSBpbiBtdWx0aXBsZSBsaW5lYXIgbW9kZWxzCgpJZiBkYXRhIGFyZSByZXByZXNlbnRhdGl2ZSB0aGFuIHRoZSBsZWFzdCBzcXVhcmVzIGVzdGltYXRvcnMgZm9yIHRoZSBpbnRlcmNlcHQgYW5kIHNsb3BlcyBhcmUgdW5iaWFzZWQuCiQkRVtcaGF0IFxiZXRhX2pdPVxiZXRhX2osXHF1YWQgaj0wLFxsZG90cyxwLTEuJCQKCi0gR2FpbiBpbnNpZ2h0IGluIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHBhcmFtZXRlciBlc3RpbWF0b3JzIHNvIGFzIHRvIGdlbmVyYWxpemUgdGhlIGVmZmVjdCBpbiB0aGUgc2FtcGxlIHRvIHRoZSBwb3B1bGF0aW9uLiAKCi0gQWRkaXRpb25hbCBhc3N1bXB0aW9ucyBhcmUgbmVlZGVkIGZvciBpbmZlcmVuY2UuICAKCjEuICpMaW5lYXJpdHkqCgoyLiAqSW5kZXBlbmRlbmNlKgoKMy4gKkhvbW9zY2VkYXN0aWNpdHkqIG9mICplcXVhbCB2YXJpYW5jZSoKNC4gKk5vcm1hbGl0eSo6IHJlc2lkdWFscyAkXGVwc2lsb25faSQgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKVW5kZXIgdGhlc2UgYXNzdW1wdGlvbnM6CiQkXGVwc2lsb25faSBcc2ltIE4oMCxcc2lnbWFeMikuJCQgCmVuCiQkWV9pXHNpbSBOKFxiZXRhXzArXGJldGFfMSBYX3tpMX0rXGxkb3RzK1xiZXRhX3twLTF9IFhfe2lwLTF9LFxzaWdtYV4yKSQkCgotLS0KCi0gU2xvcGVzIGFyZSBhZ2FpbiBtb3JlIHByZWNpc2UgaWYgdGhlIHByZWRpY3RvciB2YWx1ZXMgaGF2ZSBhIGxhcmdlciByYW5nZS4gCgotIENvbmRpdGlvbmFsIHZhcmlhbmNlICgkXHNpZ21hXjIkKSBjYW4gYWdhaW4gYmUgZXN0aW1hdGVkIGJhc2VkIG9uIHRoZSAqbWVhbiBzcXVhcmVkIGVycm9yKiAoTVNFKTogCgokJFxoYXRcc2lnbWFeMj1NU0U9XGZyYWN7XHN1bVxsaW1pdHNfe2k9MX1ebiBcbGVmdCh5X2ktXGhhdFxiZXRhXzAtXGhhdFxiZXRhXzEgWF97aTF9LVxsZG90cy1caGF0XGJldGFfe3AtMX0gWF97aXAtMX1ccmlnaHQpXjJ9e24tcH09XGZyYWN7XHN1bVxsaW1pdHNfe2k9MX1ebiBlXjJfaX17bi1wfS4kJAoKQWdhaW4gaHlwb3RoZXNpcyB0ZXN0cyBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMgYnkgCiQkVF9rPVxmcmFje1xoYXR7XGJldGF9X2stXGJldGFfa317U0UoXGhhdHtcYmV0YX1fayl9IFx0ZXh0eyBtZXQgfSBrPTAsIFxsZG90cywgcC0xLiQkCgpJZiBhbGwgYXNzdW1wdGlvbnMgYXJlIHNhdGlzZmllZCB0aGFuIHRoZSBzdGF0aXN0aWNzICRUX2skIHQtZGlzdHJpYnV0ZWQgd2l0aCAkbi1wJCBkZWdyZWVzIG9mIGZyZWVkb20uIAoKLS0tCgpXaGVuIG5vcm1hbGl0eSB0aHVzIG5vdCBob2xkLCBidXQgbGluZWFyaXRlaXQsIGluZGVwZW5kZW5jZSBhbmQgaG9tb3NjZWRhc3RpY2l0eSBhcmUgdmFsaWQgd2UgY2FuIGFnYWluIGFkb3B0IHRoZSBDTFQgdGhhdCBzdGF0ZXMgdGhhdCBzdGF0aXN0aWMgJFRfayQgaXMgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZCBpbiBsYXJnZSBzYW1wbGVzLgoKLS0tCgpXZSBjYW4gYnVpbGQgY29uZmlkZW5jZSBpbnRlcnZhbHMgb24gdGhlIHNsb3BlcyBieToKJCRbXGhhdFxiZXRhX2ogLSB0X3tuLXAsXGFscGhhLzJ9IFx0ZXh0e1NFfV97XGhhdFxiZXRhX2p9LFxoYXRcYmV0YV9qICsgdF97bi1wLFxhbHBoYS8yfSBcdGV4dHtTRX1fe1xoYXRcYmV0YV9qfV0kJC4KCmBgYHtyfQpjb25maW50KGxtVldTKQpgYGAKCi0tLQoKRm9ybWFsIGh5cG90aGVzaXMgdGVzdHM6IAokJEhfMDogXGJldGFfaj0wJCQKJCRIXzE6IFxiZXRhX2pcbmVxMCQkCgpXaXRoIHRlc3Qgc3RhdGlzdGljCiQkVD1cZnJhY3tcaGF0e1xiZXRhfV9qLTB9e1NFKFxoYXR7XGJldGF9X2opfSQkIAp3aGljaCBmb2xsb3dzIGEgdC1kaXN0cmlidXRpb24gd2l0aCAkbi1wJCBkZWdyZWVzIG9mIGZyZWVkb20gdW5kZXIgJEhfMCQKCi0tLQoKYGBge3J9CnN1bW1hcnkobG1WV1MpCmBgYAoKLS0tCgojIyBBc3Nlc3MgdGhlIG1vZGVsIGFzc3VtcHRpb25zCgpgYGB7cn0KcGxvdChsbVZXUykKYGBgCgotLS0KCiMjIFRoZSBub24gYWRkaXRpdmUgbXVsdGlwbGUgbGluZWFyIG1vZGVsIAojIyMgSW50ZXJhY3Rpb24gYmV0d2VlbiB0d28gY29udGludW91cyB2YXJpYWJsZXMgCgpUaGUgcHJldmlvdXMgbW9kZWwgaXMgYWRkaXRpdmUgYmVjYXVzZSB0aGUgY29udHJpYnV0aW9uIG9mIHRoZSBjYW5jZXIgdm9sdW1lIG9uIGxwc2EgZG9lcyBub3QgZGVwZW5kIG9uIHRoZSBoZWlnaHQgb2YgdGhlIHByb3N0YXRlIHdlaWdodCBhbmQgdGhlIHN2aSBzdGF0dXMuCgpUaGUgc2xvcGUgZm9yIGxjYXZvbCBkb2VzIG5vdCBkZXBlbmQgb24gbG9nIHByb3N0YXRlIHdlaWdodCBhbmQgc3ZpLiAKCiQkClxiZXRhXzAgKyBcYmV0YV92ICh4X3t2fStcZGVsdGFfdikgKyBcYmV0YV93IHhfe3d9ICtcYmV0YV9zIHhfe3N9IC0gXGJldGFfMCAtIFxiZXRhX3YgeF97dn0gLSBcYmV0YV93IHhfe3d9IC1cYmV0YV9zIHhfcyA9IFxiZXRhX3YgXGRlbHRhX3YKJCQKClRoZSBzdmkgc3RhdHVzIGFuZCB0aGUgbG9nLXByb3N0YXRlZ2V3aWNodCAoJHhfdyQpIGRvIG5vdCBpbmZsdWVuY2UgdGhlIGNvbnRyaWJ1dGlvbiBvZiB0aGUgbG9nLXR1bW9yIHZvbHVtZSAoJHhfdiQpIHRvIHRoZSBhdmVyYWdlIGxvZy1QU0EgYW5kIHZpY2UgdmVyc2EuIAoKLS0tCgotIEl0IGlzIGhvd2V2ZXIgcG9zc2libGUgdGhhdCB0aGUgYXNzb2NpYXRpb24gb2YgbHBzYSBhbmQgbGNhdm9sIGRlcGVuZHMgb24gdGhlIHByb3N0YXRlIHdlaWdodC4gCi0gVGhlIGF2ZXJhZ2UgZGlmZmVyZW5jZSBpbiBscHNhIGZvciBwYXRpZW50cyB0aGF0IGRpZmZlciBpbiBvbmUgdW5pdCBvZiB0aGUgbG9nLXR1bW9yIHZvbHVtZSBjYW4gZm9yIGluc3RhbmNlIGNhbiBiZSBoaWdoZXIgZm9yIHBhdGllbnRzIHdpaHQgYSBoaWdoIHR1bW9yIHdlaWdodCB0aGVuIGZvciB0aG9zZSB3aXRoIGEgbG93IHR1bW9yIHdlaWdodC4gCi0gVGhlIGVmZmVjdCBvZiB0aGUgdHVtb3Igdm9sdW1lIG9uIHRoZSBQU0EgZGVwZW5kcyBvbiB0aGUgcHJvc3RhdGUgd2VpZ2h0LiAgCgpUbyBtb2RlbCB0aGlzICoqaW50ZXJhY3RpZSoqIG9yICoqZWZmZWN0IG1vZGlmaWNhdGlvbioqIHdlIGNhbiBhZGQgYSBwcm9kdWN0IHRlcm0gb2YgYm90aCB2YXJpYWJsZXMgdG8gdGhlIG1vZGVsCgokJApZX2kgPSBcYmV0YV8wICsgXGJldGFfdiB4X3tpdn0gKyBcYmV0YV93IHhfe2l3fSArXGJldGFfcyB4X3tpc30gKyBcYmV0YV97dnd9IHhfe2l2fXhfe2l3fSArXGVwc2lsb25faQokJAoKVGhpcyB0ZXJtIHF1YW50aWZpZXMgdGhlICppbnRlcmFjdGllLWVmZmVjdCogb2YgcHJlZGljdG9ycyAkeF92JCBlbiAkeF93JCBvbiB0aGUgbWVhbiBvdXRjb21lLiAKClRlcm1zICRcYmV0YV92eF97aXZ9JCBhbmQgJFxiZXRhX3d4X3tpd30kIGFyZSByZWZlcnJlZCB0byBhcyAqbWFpbiBlZmZlY3RzKiBvZiBwcmVkaWN0b3JzICR4X3YkIGFuZCAkeF93JC4KCi0tLQoKVGhlIGRpZmZlcmVuY2UgaW4gbHBzYSBmb3IgcGF0aWVudHMgdGhhdCBkaWZmZXIgMSB1bml0IGluICRYX3YkIGFuZCBoYXZlIGFuIGVxdWFsIGxvZyBwcm9zdGF0ZSB3ZWlnaHQgYW5kIHRoZSBzYW1lIHN2aSBzdGF0dXMgbm93IGJlY29tZXM6IAoKJCQKXGJlZ2lue2FycmF5fXtsfQpFKFkgfCBYX3Y9eF92ICsxLCBYX3c9eF93LCBYX3M9eF9zKSAtIEUoWSB8IFhfdj14X3YsIFhfdz14X3csIFhfcz14X3MpIFxcClxxdWFkID0gXGJldGFfMCArIFxiZXRhX3YgKHhfe3Z9KzEpICsgXGJldGFfdyB4X3cgK1xiZXRhX3MgeF97c30gKyBcYmV0YV97dnd9ICh4X3t2fSsxKSB4X3cgLSBcYmV0YV8wIC0gXGJldGFfdiB4X3t2fSAtIFxiZXRhX3cgeF93IC1cYmV0YV9zIHhfe3N9IC0gXGJldGFfe3Z3fSAoeF97dn0pIHhfdyBcXApccXVhZCA9IFxiZXRhX3YgKyAgXGJldGFfe3Z3fSB4X3cKIFxlbmR7YXJyYXl9IAogJCQKCi0tLQoKYGBge3J9CmxtVldTX0ludFZXIDwtIGxtKGxwc2F+bGNhdm9sICsgbHdlaWdodCArIHN2aSArIGxjYXZvbDpsd2VpZ2h0ICxwcm9zdGF0ZSkKc3VtbWFyeShsbVZXU19JbnRWVykKYGBgCgotLS0KCgpgYGB7ciBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0KcGFyKG1mcm93PWMoMSwyKSkKbGlicmFyeShwbG90M0QpCmdyaWQubGluZXMgPSAxMAp4PC1wcm9zdGF0ZSRsY2F2b2wKeTwtcHJvc3RhdGUkbHdlaWdodAp6PC1wcm9zdGF0ZSRscHNhCmZpdDwtbG0oen54K3krc3ZpLGRhdGE9cHJvc3RhdGUpCngucHJlZCA8LSBzZXEobWluKHgpLCBtYXgoeCksIGxlbmd0aC5vdXQgPSBncmlkLmxpbmVzKQp5LnByZWQgPC0gc2VxKG1pbih5KSwgbWF4KHkpLCBsZW5ndGgub3V0ID0gZ3JpZC5saW5lcykKCiMgZml0dGVkIHBvaW50cyBmb3IgZHJvcGxpbmVzIHRvIHN1cmZhY2UKdGg9LTI1CnBoPTUgCnNjYXR0ZXIzRCh4LCB5LCB6LCBwY2ggPSAxNixjb2w9YygiZGFya2JsdWUiLCJyZWQiKVthcy5kb3VibGUocHJvc3RhdGUkc3ZpKV0sIGNleCA9IC43NSwgCiAgICB0aGV0YSA9IHRoLCBwaGkgPSBwaCwgdGlja3R5cGUgPSAiZGV0YWlsZWQiLAogICAgeGxhYiA9ICJsY2F2b2wiLCB5bGFiID0gImx3ZWlnaHQiLCB6bGFiID0gImxwc2EiLCAgCiAgIGNvbHZhcj1GQUxTRSxidHkgPSAiZyIsbWFpbj0iQWRkaXRpdmUgbW9kZWwiKQoKZm9yIChpIGluIHdoaWNoKHByb3N0YXRlJHN2aT09ImhlYWx0aHkiKSkKbGluZXMzRCh4PXJlcChwcm9zdGF0ZSRsY2F2b2xbaV0sMikseT1yZXAocHJvc3RhdGUkbHdlaWdodFtpXSwyKSx6PWMocHJvc3RhdGUkbHBzYVtpXSxsbVZXUyRmaXRbaV0pLGNvbD1jKCJkYXJrYmx1ZSIsInJlZCIpW2FzLmRvdWJsZShwcm9zdGF0ZSRzdmkpW2ldXSxhZGQ9VFJVRSxsdHk9MikKCnoucHJlZDNEIDwtIG91dGVyKHgucHJlZCwgeS5wcmVkLCBmdW5jdGlvbih4LHkpIHtsbVZXUyRjb2VmWzFdK2xtVldTJGNvZWZbMl0qeCtsbVZXUyRjb2VmWzNdKnl9KQp4LnByZWQzRCA8LSBvdXRlcih4LnByZWQseS5wcmVkLGZ1bmN0aW9uKHgseSkgeCkKeS5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLHkucHJlZCxmdW5jdGlvbih4LHkpIHkpCnN1cmYzRCh4LnByZWQzRCx5LnByZWQzRCx6LnByZWQzRCxjb2w9ImJsdWUiLGZhY2V0cz1OQSxhZGQ9VFJVRSkKCgpzY2F0dGVyM0QoeCwgeSwgeiwgcGNoID0gMTYsY29sPWMoImRhcmtibHVlIiwicmVkIilbYXMuZG91YmxlKHByb3N0YXRlJHN2aSldLCBjZXggPSAuNzUsIAogICAgdGhldGEgPSB0aCwgcGhpID0gcGgsIHRpY2t0eXBlID0gImRldGFpbGVkIiwKICAgIHhsYWIgPSAibGNhdm9sIiwgeWxhYiA9ICJsd2VpZ2h0IiwgemxhYiA9ICJscHNhIiwgIAogICBjb2x2YXI9RkFMU0UsYnR5ID0gImciLG1haW49Ik1vZGVsIG1ldCBsY2F2b2w6bHdlaWdodCBpbnRlcmFjdGllIikKCmZvciAoaSBpbiB3aGljaChwcm9zdGF0ZSRzdmk9PSJoZWFsdGh5IikpCmxpbmVzM0QoeD1yZXAocHJvc3RhdGUkbGNhdm9sW2ldLDIpLHk9cmVwKHByb3N0YXRlJGx3ZWlnaHRbaV0sMiksej1jKHByb3N0YXRlJGxwc2FbaV0sbG1WV1NfSW50VlckZml0W2ldKSxjb2w9YygiZGFya2JsdWUiLCJyZWQiKVthcy5kb3VibGUocHJvc3RhdGUkc3ZpKVtpXV0sYWRkPVRSVUUsbHR5PTIpCgp6LnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCx5KSB7bG1WV1NfSW50VlckY29lZlsxXStsbVZXU19JbnRWVyRjb2VmWzJdKngrbG1WV1NfSW50VlckY29lZlszXSp5K2xtVldTX0ludFZXJGNvZWZbNV0qeCp5fSkKeC5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLHkucHJlZCxmdW5jdGlvbih4LHkpIHgpCnkucHJlZDNEIDwtIG91dGVyKHgucHJlZCx5LnByZWQsZnVuY3Rpb24oeCx5KSB5KQpzdXJmM0QoeC5wcmVkM0QseS5wcmVkM0Qsei5wcmVkM0QsY29sPSJibHVlIixmYWNldHM9TkEsYWRkPVRSVUUpCmBgYAoKLS0tCgotIE5vdGUgdGhhdCB0aGUgaW50ZXJhY3Rpb24gZWZmZWN0IHRoYXQgaXMgb2JzZXJ2ZWQgaXMgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKHA9YHIgcm91bmQoc3VtbWFyeShsbVZXU19JbnRWVykkY29lZls1LDRdLDIpYCkuIAotIFRoZSBtYWluIGVmZmVjdHMgdGhhdCBhcmUgaW52b2x2ZWQgaW4gdGhlIGludGVyYWN0aW9uIGNhbm5vdCBiZSBpbnRlcnByZXRlZCBzZXBhcmF0ZWx5IGZyb20gb25lIGFub3RoZXIuIAotIFdlIHdpbGwgdGhlcmVmb3JlIHJlbW92ZSBub24tc2lnbmlmaWNhbnQgaW50ZXJhY3Rpb24gdGVybXMgZnJvbSB0aGUgbW9kZWwuCi0gVXBvbiByZW1vdmFsIG9mIG5vbi1zaWduaWZpY2FudCBpbnRlcmFjdGlvbiB0ZXJtcyB0aGUgbWFpbiBlZmZlY3RzIGNhbiBiZSBpbnRlcnByZXRlZC4gCgotLS0KCiMjIEludGVyYWN0aW9uIGJldHdlZW4gYSBjb250aW51b3VzIHZhcmlhYmxlIGFuZCBhIGZhY3RvciB2YXJpYWJsZSAKCkludGVyYWN0aW9uIGJldHdlZW4gbGNhdm9sICRcbGVmdHJpZ2h0YXJyb3ckIHN2aSBhbmQgbHdlaWdodCAkXGxlZnRyaWdodGFycm93JCBzdmkuIAoKVGhlIG1vZGVsIGJlY29tZXMgCgokJFk9XGJldGFfMCtcYmV0YV92WF92K1xiZXRhX3dYX3crXGJldGFfc1hfcytcYmV0YV97dnN9WF92WF9zICsgXGJldGFfe3dzfVhfd1hfcyArXGVwc2lsb24kJAoKLS0tCgpgYGB7cn0KbG1WV1NfSW50VlNfV1MgPC0gbG0obHBzYSB+IGxjYXZvbCArIGx3ZWlnaHQgKyBzdmkgKyBzdmk6bGNhdm9sICsgc3ZpOmx3ZWlnaHQsZGF0YT1wcm9zdGF0ZSkgCnN1bW1hcnkobG1WV1NfSW50VlNfV1MpCmBgYAoKLS0tCgpCZWNhdXNlICRYX1MkIGlzIGEgZHVtbXkgdmFyaWFiZWxlIHdlIG9idGFpbiB0byBkaXN0aW5jdCByZWdyZXNzaW9uIHBsYW5lczoKCjEuIE1vZGVsIGZvciAkWF9zPTAkOiAkJFk9XGJldGFfMCtcYmV0YV92WF92K1xiZXRhX3dYX3cgKyBcZXBzaWxvbiQkIHdoZXJlIHRoZSBtYWluIGVmZmVjdHMgYXJlIHRoZSBzbG9wZSBmb3IgbGNhdm9sIGFuZCBsd2VpZ2h0CjIuIGFuZCBtb2RlbCBmb3IgJFhfcz0xJDogCiAgICQkXGJlZ2lue2FycmF5fXtsY2x9CiAgIFkmPSZcYmV0YV8wK1xiZXRhX3ZYX3YrXGJldGFfcytcYmV0YV93WF93K1xiZXRhX3t2c31YX3YgKyBcYmV0YV97d3N9WF93ICtcZXBzaWxvblxcCiAgJj0mIChcYmV0YV8wK1xiZXRhX3MpKyhcYmV0YV92K1xiZXRhX3t2c30pWF92KyhcYmV0YV93K1xiZXRhX3t3c30pWF93K1xlcHNpbG9uCiAgXGVuZHthcnJheX0kJCAKd2l0aCBpbnRlcmNlcHQgJFxiZXRhXzArXGJldGFfcyQgYW5kIHNsb3BlcyAkXGJldGFfditcYmV0YV97dnN9JCBhbmQgJFxiZXRhX3crXGJldGFfe3dzfSQKCi0tLQoKYGBge3Igb3V0LndpZHRoPScxMDAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CnBhcihtZnJvdz1jKDEsMikpCmxpYnJhcnkocGxvdDNEKQpncmlkLmxpbmVzID0gMTAKeDwtcHJvc3RhdGUkbGNhdm9sCnk8LXByb3N0YXRlJGx3ZWlnaHQKejwtcHJvc3RhdGUkbHBzYQpmaXQ8LWxtKHp+eCt5K3N2aSxkYXRhPXByb3N0YXRlKQp4LnByZWQgPC0gc2VxKG1pbih4KSwgbWF4KHgpLCBsZW5ndGgub3V0ID0gZ3JpZC5saW5lcykKeS5wcmVkIDwtIHNlcShtaW4oeSksIG1heCh5KSwgbGVuZ3RoLm91dCA9IGdyaWQubGluZXMpCgojIGZpdHRlZCBwb2ludHMgZm9yIGRyb3BsaW5lcyB0byBzdXJmYWNlCnRoPS0yNQpwaD01IApzY2F0dGVyM0QoeCwgeSwgeiwgcGNoID0gMTYsY29sPWMoImRhcmtibHVlIiwicmVkIilbYXMuZG91YmxlKHByb3N0YXRlJHN2aSldLCBjZXggPSAuNzUsIAogICAgdGhldGEgPSB0aCwgcGhpID0gcGgsIHRpY2t0eXBlID0gImRldGFpbGVkIiwKICAgIHhsYWIgPSAibGNhdm9sIiwgeWxhYiA9ICJsd2VpZ2h0IiwgemxhYiA9ICJscHNhIiwgIAogICBjb2x2YXI9RkFMU0UsYnR5ID0gImciLG1haW49IkFkZGl0aXZlIG1vZGVsIikKCmZvciAoaSBpbiB3aGljaChwcm9zdGF0ZSRzdmk9PSJoZWFsdGh5IikpCmxpbmVzM0QoeD1yZXAocHJvc3RhdGUkbGNhdm9sW2ldLDIpLHk9cmVwKHByb3N0YXRlJGx3ZWlnaHRbaV0sMiksej1jKHByb3N0YXRlJGxwc2FbaV0sbG1WV1MkZml0W2ldKSxjb2w9YygiZGFya2JsdWUiLCJyZWQiKVthcy5kb3VibGUocHJvc3RhdGUkc3ZpKVtpXV0sYWRkPVRSVUUsbHR5PTIpCgp6LnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCx5KSB7bG1WV1MkY29lZlsxXStsbVZXUyRjb2VmWzJdKngrbG1WV1MkY29lZlszXSp5fSkKeC5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLHkucHJlZCxmdW5jdGlvbih4LHkpIHgpCnkucHJlZDNEIDwtIG91dGVyKHgucHJlZCx5LnByZWQsZnVuY3Rpb24oeCx5KSB5KQpzdXJmM0QoeC5wcmVkM0QseS5wcmVkM0Qsei5wcmVkM0QsY29sPSJibHVlIixmYWNldHM9TkEsYWRkPVRSVUUpCnoyLnByZWQzRCA8LSBvdXRlcih4LnByZWQsIHkucHJlZCwgZnVuY3Rpb24oeCx5KSB7bG1WV1MkY29lZlsxXStsbVZXUyRjb2VmWzRdK2xtVldTJGNvZWZbMl0qeCtsbVZXUyRjb2VmWzNdKnl9KQpzdXJmM0QoeC5wcmVkM0QseS5wcmVkM0QsejIucHJlZDNELGNvbD0ib3JhbmdlIixmYWNldHM9TkEsYWRkPVRSVUUpCgoKc2NhdHRlcjNEKHgsIHksIHosIHBjaCA9IDE2LGNvbD1jKCJkYXJrYmx1ZSIsInJlZCIpW2FzLmRvdWJsZShwcm9zdGF0ZSRzdmkpXSwgY2V4ID0gLjc1LCAKICAgIHRoZXRhID0gdGgsIHBoaSA9IHBoLCB0aWNrdHlwZSA9ICJkZXRhaWxlZCIsCiAgICB4bGFiID0gImxjYXZvbCIsIHlsYWIgPSAibHdlaWdodCIsIHpsYWIgPSAibHBzYSIsICAKICAgY29sdmFyPUZBTFNFLGJ0eSA9ICJnIixtYWluPSJNb2RlbCBtZXQgbGNhdm9sOmx3ZWlnaHQgaW50ZXJhY3RpZSIpCgpmb3IgKGkgaW4gd2hpY2gocHJvc3RhdGUkc3ZpPT0iaGVhbHRoeSIpKQpsaW5lczNEKHg9cmVwKHByb3N0YXRlJGxjYXZvbFtpXSwyKSx5PXJlcChwcm9zdGF0ZSRsd2VpZ2h0W2ldLDIpLHo9Yyhwcm9zdGF0ZSRscHNhW2ldLGxtVldTX0ludFZTX1dTJGZpdFtpXSksY29sPWMoImRhcmtibHVlIiwicmVkIilbYXMuZG91YmxlKHByb3N0YXRlJHN2aSlbaV1dLGFkZD1UUlVFLGx0eT0yKQoKei5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLCB5LnByZWQsIGZ1bmN0aW9uKHgseSkge2xtVldTX0ludFZTX1dTJGNvZWZbMV0rbG1WV1NfSW50VlNfV1MkY29lZlsyXSp4K2xtVldTX0ludFZTX1dTJGNvZWZbM10qeX0pCngucHJlZDNEIDwtIG91dGVyKHgucHJlZCx5LnByZWQsZnVuY3Rpb24oeCx5KSB4KQp5LnByZWQzRCA8LSBvdXRlcih4LnByZWQseS5wcmVkLGZ1bmN0aW9uKHgseSkgeSkKc3VyZjNEKHgucHJlZDNELHkucHJlZDNELHoucHJlZDNELGNvbD0iYmx1ZSIsZmFjZXRzPU5BLGFkZD1UUlVFKQp6Mi5wcmVkM0QgPC0gb3V0ZXIoeC5wcmVkLCB5LnByZWQsIGZ1bmN0aW9uKHgseSkge2xtVldTX0ludFZTX1dTJGNvZWZbMV0rbG1WV1NfSW50VlNfV1MkY29lZls0XStsbVZXU19JbnRWU19XUyRjb2VmWzJdKngrbG1WV1NfSW50VlNfV1MkY29lZlszXSp5K2xtVldTX0ludFZTX1dTJGNvZWZbNV0qeCtsbVZXU19JbnRWU19XUyRjb2VmWzZdKnl9KQpzdXJmM0QoeC5wcmVkM0QseS5wcmVkM0QsejIucHJlZDNELGNvbD0ib3JhbmdlIixmYWNldHM9TkEsYWRkPVRSVUUpCmBgYAoKLS0tCgojIEFOT1ZBIFRhYmVsCgpUaGUgdG90YWwgU1NUb3QgaXMgYWdhaW4KCiQkCiAgXHRleHR7U1NUb3R9ID0gXHN1bV97aT0xfV5uIChZX2kgLSBcYmFye1l9KV4yLgokJAoKVGhlIHJlc2lkdWFsIHN1bSBvZiBzcXVhcmVzIHJlbWFpbnMgc2ltaWxhcgokJAogIFx0ZXh0e1NTRX0gPSBcc3VtX3tpPTF9Xm4gKFlfaS1caGF0e1l9X2kpXjIuCiQkCgpBZ2FpbiB0aGUgdG90YWwgc3VtIG9mIHNxdWFyZXMgY2FuIGJlIGRlY29tcG9zZWQgaW4gLAokJAogIFx0ZXh0e1NTVG90fSA9IFx0ZXh0e1NTUn0gKyBcdGV4dHtTU0V9ICwKJCQKd2l0aAokJAogIFx0ZXh0e1NTUn0gPSBcc3VtX3tpPTF9Xm4gKFxoYXR7WX1faS1cYmFye1l9KV4yLgokJAoKLS0tCgpXZSBoYXZlIGZvbGxvd2luZyBkZWdyZWVzIG9mIGZyZWVkb20gYW5kIG1lYW4gc3VtIG9mIHNxdWFyZXM6IAoKLSBTU1RvdCBoYXMgJG4tMSQgZGVncmVlcyBvZiBmcmVlZG9tIGFuZCAkXHRleHR7U1NUb3R9LyhuLTEpJCBpcyBhbiBlc3RpbWF0b3IgZm9yIHRoZSB0b3RhbCB2YXJpYW5jZSBpbiAkWSQgKG1hcmdpbmFsIGRpc3RyaWJ1dGlvbiBvZiAkWSQpLiAKLSBTU0UgaGFzICRuLXAkIGRlZ3JlZXMgb2YgZnJlZWRvbSBhbmQgJFx0ZXh0e01TRX09XHRleHR7U1NFfS8obi1wKSQgaXMgYW4gc2NoYXR0ZXIgZm9yIHRoZSByZXNpZHVhbCB2YXJpYW5jZSBvZiAkWSQgZ2l2ZW4gdGhlIHByZWRpY3RvcmVzIChpLmUuIGFuIGVzdGltYXRvciBmb3IgdGhlIHJlc2lkdWFsIHZhcmlhbmNlICRcc2lnbWFeMiQgb2YgdGhlIGVycm9yIHRlcm0gJFxlcHNpbG9uJCkuCi0gU1NSIGhhcyAkcC0xJCBkZWdyZWVzIG9mIGZyZWVkb20gICBhbmQgJFx0ZXh0e01TUn09XHRleHR7U1NSfS8ocC0xKSQgaXMgdGhlIG1lYW4gc3VtIG9mIHNxdWFyZXMgb2YgdGhlIHJlZ3Jlc3Npb24uIAoKVGhlIGRldGVybWluYXRpb24gY29lZmZpY2llbnRzIHJlbWFpbnMgYXMgYmVmb3JlLCAgaS5lLgokJAogIFJeMiA9IDEtXGZyYWN7XHRleHR7U1NFfX17XHRleHR7U1NUb3R9fSA9IFxmcmFje1x0ZXh0e1NTUn19e1x0ZXh0e1NTVG90fX0KJCQKYW5kIGlzIHRoZSBmcmFjdGlvbiBvZiB0aGUgdG90YWwgdmFyaWFiaWxpdHkgdGhhdCBjYW4gYmUgZXhwbGFpbmVkIGJ5IHRoZSByZWdyZXNzaW9uIG1vZGVsLiAKClRlc3RzdGF0aXN0aWMgJEY9XHRleHR7TVNSfS9cdGV4dHtNU0V9JCBpcyB1bmRlciAkSF8wOlxiZXRhXzE9XGxkb3RzPVxiZXRhX3twLTF9PTAkIGRpc3RyaWJ1dGVkIGJ5IGFuIEYgZGlzdHJpYnV0aW9uOiAkRl97cC0xO24tcH0kLgoKLS0tCgpgYGB7ciwgZWNobz1GQUxTRX0Kc3VtbWFyeShsbVZXUykKYGBgCgotLS0KCiMjIEFkZGl0aW9uYWwgc3VtcyBvZiBzcXVhcmVzCgoKQ29uc2lkZXIgMiBtb2RlbHMgZm9yIHRoZSBwcmVkaWN0b3JzICR4XzEkIGVuICR4XzIkOgokJAogIFlfaSA9IFxiZXRhXzArXGJldGFfMSB4X3tpMX0gKyBcZXBzaWxvbl9pLAokJAp3aXRoICRcZXBzaWxvbl9pXHRleHR7IGlpZCB9IE4oMCxcc2lnbWFfMV57Mn0pJCwgYW5kIAokJApZX2kgPSBcYmV0YV8wK1xiZXRhXzEgeF97aTF9K1xiZXRhXzIgeF97aTJ9ICsgXGVwc2lsb25faSwKJCQKd2l0aCAkXGVwc2lsb25faVx0ZXh0eyBpaWQgfSBOKDAsXHNpZ21hXzJeezJ9KSQuCgpmb3IgdGhlIGZpcnN0IChnZXJlZHVjZWVyZGUpIG1vZGVsIHdlIGhhdmUgZGVjb21wb3NpdGlvbgpcWwogIFx0ZXh0e1NTVG90fSA9IFx0ZXh0e1NTUn1fMSArIFx0ZXh0e1NTRX1fMQpcXQplbiBmb3IgdGhlIHNlY29uZCBub24tcmVkdWNlZCBtb2RlbCB3ZSBoYXZlIApcWwogIFx0ZXh0e1NTVG90fSA9IFx0ZXh0e1NTUn1fMiArIFx0ZXh0e1NTRX1fMgpcXQooU1NUb3QgaXMgb2YgY291cnNlIHRoZSBzYW1lIGJlY2F1c2UgaXQgb25seSBkZXBlbmRzIG9uIHRoZSByZXNwb25zZSBhbmQgbm90IG9mIHRoZSBtb2RlbHMpLiAKCi0tLQoKKipEZWZpbml0aW9uIG9mIGFkZGl0aW9uYWwgc3VtIG9mIHNxdWFyZXMqKgpUaGUgKmFkZGl0aW9uYWwgc3VtIG9mIHNxdWFyZXMqIG9mIHByZWRpY3RvciAkeF8yJCBhcyBjb21wYXJlZCB0byB0aGUgbW9kZWwgd2l0aCBvbmx5ICR4XzEkIGFzIHByZWRpY3RvciBpcyBnaXZlbiBieQokJAogIFx0ZXh0e1NTUn1fezJcbWlkIDF9ID0gXHRleHR7U1NFfV8xLVx0ZXh0e1NTRX1fMj1cdGV4dHtTU1J9XzItXHRleHR7U1NSfV8xLgokJCAgCgpOb3RlIHRoYXQsICAkXHRleHR7U1NFfV8xLVx0ZXh0e1NTRX1fMj1cdGV4dHtTU1J9XzItXHRleHR7U1NSfV8xJCBpcyB0cml2aWFhbCBpcyBiZWNhdXNlIG9mIHRoZSBkZWNvbXBvc2l0aW9uIG9mIHRoZSB0b3RhbCBzdW0gb2Ygc3F1YXJlcy4gCgpUaGUgYWRkaXRpb25hbCBzdW0gb2Ygc3F1YXJlcyAkXHRleHR7U1NSfV97MlxtaWQgMX0kIGNhbiBzaW1wbHkgYmUgaW50ZXJwcmV0ZWQgYXMgdGhlIGFkZGl0aW9uYWwgdmFyaWFiaWxpdHkgdGhhdCBjYW4gYmUgZXhwbGFpbmVkIGJ5IGFkZGluZyBwcmVkaWN0b3IgJHhfMiQgdG8gdGhlIG1vZGVsIHdpdGggcHJlZGljdG9yICR4XzEkLiAKCldpdGggdGhpcyBzdW0gb2Ygc3F1YXJlcyB3ZSBjYW4gZnVydGhlciBkZWNvbXBvc2UgdGhlIHRvdGFsIHN1bSBvZiBzcXVhcmVzCiQkCiAgXHRleHR7U1NUb3R9ID0gXHRleHR7U1NSfV8xKyBcdGV4dHtTU1J9X3syXG1pZCAxfSArIFx0ZXh0e1NTRX0uCiQkCndoaWNoIGZvbGxvd3MgZGlyZWN0bHkgZnJvbSB0aGUgZGVmaW5pdGlvbiAkXHRleHR7U1NSfV97MlxtaWQgMX0kLiAKCi0tLQoKRXh0ZW5zaW9uOiAoJHM8cC0xJCkKJCQKWV9pID0gXGJldGFfMCArIFxiZXRhXzEgeF97aTF9ICsgXGNkb3RzICsgXGJldGFfe3N9IHhfe2lzfSArIFxlcHNpbG9uX2kgCiQkCndpdGggJFxlcHNpbG9uX2lcdGV4dHsgaWlkIH1OKDAsXHNpZ21hXzFeezJ9KSQsIGFuZCAoJHM8IHFcbGVxIHAtMSQpCiQkCllfaSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfe2kxfSArIFxjZG90cyArIFxiZXRhX3tzfSB4X3tpc30gKyBcYmV0YV97cysxfSB4X3tpcysxfSArIFxjZG90cyBcYmV0YV97cX14X3tpcX0rIFxlcHNpbG9uX2kgCiQkCndpdGggJFxlcHNpbG9uX2lcdGV4dHsgaWlkIH0gTigwLFxzaWdtYV8yXnsyfSkkLgoKClRoZSAqKmFkZGl0aW9uYWwgc3VtIG9mIHNxdWFyZXMqKiBvZiBwcmVkaWN0b3IgJHhfe3MrMX0sIFxsZG90cywgeF9xJCBjb21wYXJlZCB0byBhIG1vZGVsIHdpdGggb25seSBwcmVkaWN0b3JzICAkeF8xLFxsZG90cywgeF97c30kIGlzIGdpdmVuIGJ5IAoKJCQKICBcdGV4dHtTU1J9X3tzKzEsIFxsZG90cywgcVxtaWQgMSxcbGRvdHMsIHN9ID0gXHRleHR7U1NFfV8xLVx0ZXh0e1NTRX1fMj1cdGV4dHtTU1J9XzItXHRleHR7U1NSfV8xLgokJCAgCgotLS0KCiMjIyBUeXBlIEkgU3VtcyBvZiBTcXVhcmVzClN1cHBvc2UgdGhhdCAkcC0xJCBwcmVkaWN0b3JzIGFyZSBjb25zaWRlcmVkLCBhbmQgc3VwcG9zZSB0aGUgZm9sbG93aW5nIHNlcXVlbmNlIG9mIG1vZGVscyAoJHM9MixcbGRvdHMsIHAtMSQpCiQkCllfaSA9IFxiZXRhXzAgKyBcc3VtX3tqPTF9XntzfSBcYmV0YV9qIHhfe2lqfSArIFxlcHNpbG9uX2kKJCQKd3V0aCAkXGVwc2lsb25faVx0ZXh0eyBpaWQgfSBOKDAsXHNpZ21hXnsyfSkkLgoKLSBUaGUgY29ycmVzcG9uZGluZyBzdW0gb2Ygc3F1YXJlcyBhcmUgZGVub3RlZCBhcyAkXHRleHR7U1NSfV97c30kIGFuZCAkXHRleHR7U1NFfV97c30kLiAKLSBUaGUgc2VxdWVuY2Ugb2YgbW9kZWxzIGdpdmVzIHJpc2UgdG8gdGhlIGZvbGxvd2luZyBzdW1zIG9mIHNxdWFyZXM6ICRcdGV4dHtTU1J9X3tzXG1pZCAxLFxsZG90cywgcy0xfSQuIAotIFRoZSBsYXR0ZXIgc3VtIG9mIHNxdWFyZXMgaXMgcmVmZXJyZWQgdG8gYXMgdHlwZSBJIHN1bXMgb2Ygc3F1YXJlcy4gTm90ZSB0aGF0IHRoZXkgZGVwZW5kIG9uIHRoZSBvcmRlciBpbiB3aGljaCB0aGUgbW9kZWxzIHdlcmUgYWRkZWQgdG8gdGhlIG1vZGVsLiAKCi0tLQoKV2UgY2FuIHNob3cgZm9yIG1vZGVsIE1vZGVsIHdpdGggJHM9cC0xJCB0aGF0CiQkCiBcdGV4dHtTU1RvdH0gPSBcdGV4dHtTU1J9XzEgKyBcdGV4dHtTU1J9X3syXG1pZCAxfSArIFx0ZXh0e1NTUn1fezNcbWlkIDEsMn0gKyBcY2RvdHMgKyBcdGV4dHtTU1J9X3twLTFcbWlkIDEsXGxkb3RzLCBwLTJ9ICsgXHRleHR7U1NFfSwKJCQKd2l0aCAkXHRleHR7U1NFfSQgdGhlIHJlc2lkdWFsIHN1bSBvZiBzcXVhcmVzIG9mIHRoZSBtb2RlbCB3aXRoIGFsbCAkcC0xJCBwcmVkaWN0b3JzIAokJAogIFx0ZXh0e1NTUn1fMSArIFx0ZXh0e1NTUn1fezJcbWlkIDF9ICsgXHRleHR7U1NSfV97M1xtaWQgMSwyfSArIFxjZG90cyArIFx0ZXh0e1NTUn1fe3AtMVxtaWQgMSxcbGRvdHMsIHAtMn0gPSBcdGV4dHtTU1J9CiQkCndpdGggJFx0ZXh0e1NTUn0kIHRoZSBzdW0gb2Ygc3F1YXJlcyBvZiBhbGwgICRwLTEkIHByZWRpY3RvcnMuCgotIFRoZSBpbnRlcnByZXRhdGlvbiBvZiBlYWNoIHRlcm0gZGVwZW5kcyBvbiB0aGUgb3JkZXIgb2YgdGhlIHNlcXVlbmNlIG9mIHRoZSByZWdyZXNzaW9uIG1vZGVscy4gCgotLS0KCi0gRWFjaCB0eXBlIEkgU1NSIGludm9sdmVzIDEgcHJlZGljdG9yIGFuZCBoYXMgMSBkZWdyZWUgb2YgZnJlZWRvbSAobm90ZSB0aGF0IG11bHRpcGxlIGR1bW1pZXMgZm9yIGEgZmFjdG9yIGFyZSB0eXBpY2FsbHkgcmVtb3ZlZCB0b2dldGhlcikuIAotIEZvciBlYWNoIHR5cGUgSSBTU1IgdGVybSB0aGUgbWVhbiBzdW0gb2Ygc3F1YXJlcyBpcyBkZWZpbmVkIGJ5ICAkXHRleHR7TVNSfV97alxtaWQgMSxcbGRvdHMsIGotMX09XHRleHR7U1NSfV97alxtaWQgMSxcbGRvdHMsIGotMX0vMSQuCi0gQW5kIHRlc3RzdGF0aXN0aWMgJEY9XHRleHR7TVNSfV97alxtaWQgMSxcbGRvdHMsIGotMX0vXHRleHR7TVNFfSQgZm9sbG93cyBhICRGX3sxO24tKGorMSl9JCBkaXN0cmlidXRpb24gdW5kZXIgICRIXzA6XGJldGFfaj0wJCB3aXRoICRzPWokLgotIFRoZXNlIHN1bXMgb2Ygc3F1YXJlcyBhcmUgdGhlIGRlZmF1bHQgc3VtIG9mIHNxdWFyZXMgaW4gdGhlIGFub3ZhIGZ1bmN0aW9uIG9mIFIuIAoKLS0tCgojIyMgVHlwZSBJSUkgU3VtcyBvZiBzcXVhcmVzCgogVHlwZSBJSUkgc3VtIG9mIHNxdWFyZXMgZm9yIHByZWRpY3RvciAkeF9qJCBhcmUgZ2l2ZW4gYnkgdGhlIGFkZGl0aW9uYWwgc3VtIG9mIHNxdWFyZXMKJCQKICBcdGV4dHtTU1J9X3tqIFxtaWQgMSxcbGRvdHMsIGotMSxqKzEsXGxkb3RzLCBwLTF9ID0gXHRleHR7U1NFfV8xLVx0ZXh0e1NTRX1fMgokJAoKLSAkXHRleHR7U1NFfV8yJCB0aGUgc3VtIG9mIHNxdWFyZXMgb2YgdGhlIHJlc2lkdWFscyBvZiB0aGUgbW9kZWwgd2l0aCBhbGwgJHAtMSQgcHJlZGljdG9ycy4KLSAkXHRleHR7U1NFfV8xJCBzdW0gb2Ygc3F1YXJlcyBvZiB0aGUgcmVzaWR1YWxzIHdpdGggYWxsICRwLTEkIHByZWRpY3RvcnMsIGV4Y2VwdCBmb3IgcHJlZGljdG9yICR4X2okLiAKClRoZSB0eXBlIElJSSBzdW0gb2Ygc3F1YXJlcyAkXHRleHR7U1NSfV97aiBcbWlkIDEsXGxkb3RzLCBqLTEsaisxLFxsZG90cywgcC0xfSQgcXVhbnRpZnkgdGhlIGNvbnRyaWJ1dGlvbiBpbiB0aGUgdG90YWwgdmFyaWFuY2Ugb2YgdGhlIG91dGNvbWUgZXhwbGFpbmVkIGJ5ICR4X2okIHRoYXQgY2Fubm90IGJlIGV4cGxhaW5lZCBieSB0aGUgcmVtYWluaW5nICRwLTIkIHByZWRpY3RvcnMuIAoKLS0tCgpUaGUgdHlwZSBJSUkgc3VtIG9mIHNxdWFyZXMgaGFzIDEgZGVncmVlIG9mIGZyZWVkb20gYmVjYXVzZSBpdCBpbnZvbHZlcyAxICRcYmV0YSQtcGFyYW1ldGVyLiAKCkZvciBlYWNoIHR5cGUgSUlJIFNTUiB0ZXJtIHRoZSBtZWFuIHN1bSBvZiBzcXVhcmVzIGlzIGRlZmluZWQgYnkgJFx0ZXh0e01TUn1fe2ogXG1pZCAxLFxsZG90cywgai0xLGorMSxcbGRvdHMsIHAtMX09XHRleHR7U1NSfV97aiBcbWlkIDEsXGxkb3RzLCBqLTEsaisxLFxsZG90cywgcC0xfS8xJC4KClRlc3RzdGF0aXN0aWVrICRGPVx0ZXh0e01TUn1fe2ogXG1pZCAxLFxsZG90cywgai0xLGorMSxcbGRvdHMsIHAtMX0vXHRleHR7TVNFfSQgaXMgJEZfezE7bi1wfSQgZGlzdHJpYnV0ZWQgdW5kZXIgJEhfMDpcYmV0YV9qPTAkLgoKV2UgY2FuIG9idGFpbiB0aGVzZSBzdW1zIG9mIHNxdWFyZXMgdXNpbmcgdGhlIGBBbm92YWAgZnVuY3Rpb24gZnJvbSB0aGUgYGNhcmAgcGFja2FnZS4gCi0tLQoKYGBge3J9CmxpYnJhcnkoY2FyKQpBbm92YShsbVZXUyx0eXBlPTMpCmBgYAoKVGhlIHAtdmFsdWVzIGFyZSBpZGVudGljYWwgdG8gdGhvc2Ugb2YgdHdvLXNpZGVkIHQtdGVzdHMKCk5vdGUsIGhvd2V2ZXIsIHRoYXQgYWxsIGR1bW1pZXMgZm9yIGZhY3RvcnMgd2l0aCBtdWx0aXBsZSBsZXZlbHMgd2lsbCBiZSB0YWtlbiBvdXQgb2YgdGhlIG1vZGVsIGF0IG9uY2UuIFNvIHRoZW4gdGhlIHR5cGUgSUlJIHN1bSBvZiBzcXVhcmVzIHdpbGwgaGF2ZSBhcyBtYW55IGRlZ3JlZXMgb2YgZnJlZWRvbSBhcyB0aGUgbnVtYmVyIG9mIGR1bW1pZXMgYW5kIGFuIG9tbmlidXMgdGVzdCBpcyBwZXJmb3JtZWQgZm9yIHRoZSBlZmZlY3Qgb2YgdGhlIGZhY3Rvci4gCgotLS0KCiMgRGlhZ25vc3RpY3MKIyMgTXVsdGljb2xsaW5lYXJpdGVpdAoKYGBge3IgZWNobz1GQUxTRX0Kc3VtbWFyeShsbVZXUykKYGBgCgotLS0KCmBgYHtyIGVjaG89RkFMU0V9CnN1bW1hcnkobG1WV1NfSW50VlcpCmBgYAoKLS0tCgotIEVzdGltYXRlcyBhcmUgZGlmZmVyZW50IGZyb20gdGhvc2UgaW4gdGhlIGFkZGl0aXZlIG1vZGVsIGFuZCB0aGUgc3RhbmRhcmQgZXJyb3JzIGFyZSBtdWNoIGhpZ2hlciEgCgotIFRoaXMgaXMgY2F1c2VkIGJ5IHRoZSBtdWx0aWNvbGxpbmVhcml0eSBwcm9ibGVtLiAKCi0gSWYgMiBwcmVkaWN0b3JzIGFyZSBzdHJvbmdseSBjb3JyZWxhdGVkIHRoYW4gdGhleSBzaGFyZSBhIGxvdCBvZiBpbmZvcm1hdGlvbi4gCgotIEl0IGlzIHRoZXJlZm9yZSBkaWZmaWN1bHQgdG8gZXN0aW1hdGUgdGhlIGluZGl2aWR1YWwgY29udHJpYnV0aW9uIG9mIGVhY2ggcHJlZGljdG9yIG9uIHRoZSBvdXRjb21lLiAKCi0gTGVhc3Qgc3F1YXJlcyBlc3RpbWF0b3JzIGJlY29tZSBpbnN0YWJsZS4KCi0gU3RhbmRhcmQgZXJyb3JzIGJlY29tZSBpbmZsYXRlZC4KCi0gQXMgbG9uZyBhcyB3ZSBvbmx5IGRvIHByZWRpY3Rpb25zIG9uIHRoZSBiYXNpcyBvZiB0aGUgcmVncmVzc2lvbiBtb2RlbCB3aXRob3V0IGV4dHJhcG9sYXRpbmcgYmV5b25kIHRoZSByYW5nZSBvZiB0aGUgcHJlZGljdG9ycyBvYnNlcnZlZCBpbiB0aGUgc2FtcGxlIG11bHRpY29saW5lYXJpdHkgaXMgbm90IHByb2JsZW1hdGljLgoKLSBCdXQgZm9yIGluZmVyZW5jZSBpdCBpcyBwcm9ibGVtYXRpYy4KCi0tLQoKYGBge3J9CmNvcihjYmluZChwcm9zdGF0ZSRsY2F2b2wscHJvc3RhdGUkbHdlaWdodCxwcm9zdGF0ZSRsY2F2b2wqcHJvc3RhdGUkbHdlaWdodCkpCmBgYAoKLSBIaWdoIGNvcnJlbGF0aW9uIGJldHdlZW4gbG9nLXR1bW9yIHZvbHVtZSBhbmQgaW50ZXJhY3Rpb24uIAotIEl0IGlzIGEga25vd24gcHJvYmxlbSBmb3IgaGlnaGVyIG9yZGVyIHRlcm1zIChpbnRlcmFjdGlvbnMgYW5kIHF1YWRyYXRpYyB0ZXJtcykgCgotLS0gCgotIERldGVjdCBtdWx0aWNvbGxpbmVhcml0ZWl0IGJhc2VkIG9uIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggb3Igc2NhdHRlcnBsb3QgbWF0cml4IGlzIHN1Ym9wdGltYWwuIAotIEluIG1vZGVscyB3aXRoIDMgb3IgbW9yZSBwcmVkaWN0b3JzLCBzYXkgWDEsIFgyLCBYMyB3ZSBjYW4gaGF2ZSBoaWdoIG11bHRpY29sbGluZWFyaXR5IHdoaWxlIGFsbGUgcGFpcnN3aXNlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHRoZSBwcmVkaWN0b3JzIGFyZSBsb3cuIAotIFdlIGFsc28gaGF2ZSBtdWx0aWNvbGxpbmVhcml0eSBpZiB0aGVyZSBpcyBhIGhpZ2ggY29ycmVsYXRpb24gYmV0d2VlbiBYMSBhbmQgYSBsaW5haXIgY29tYmluYXRpb24gb2YgWDIgYW5kIFgzLgoKLS0tCgojIyMgVmFyaWFuY2UgaW5mbGF0aW9uIGZhY3RvciAoVklGKQoKRm9yIHBhcmFtZXRlciAkaiQgaW4gZGUgcmVncmVzc2lvbiBtb2RlbCAKXFtcdGV4dHJte1ZJRn1faj1cbGVmdCgxLVJfal4yXHJpZ2h0KV57LTF9XF0KCi0gSW4gdGhpcyBleHByZXNzaW9uICRSX2peMiQgaXMgdGhlIG11bHRpcGxlIGRldGVybWluYXRpb24gY29lZmZpY2llbnQgb2YgdGhlIGxpbmVhciByZWdyZXNzaW9uIG9mIHByZWRpY3RvciBqIG9uIHRoZSByZW1haW5pbmcgcHJlZGljdG9ycyBpbiB0aGUgbW9kZWwuIAotIFZJRiBpcyAxIGlmIHByZWRpY3RvciBqIGlzIG5vdCBsaW5lYXIgYXNzb2NpYXRlZCB3aXRoIHRoZSByZW1haW5pbmcgcHJlZGljdG9ycyBpbiB0aGUgbW9kZWwuIAotIFZJRiBpcyBsYXJnZXIgdGhhbiAxIGluIGFsbCBhbmRlcmUgY2FzZXMuIAotIFZJRiBpcyB0aGUgZmFjdG9yIHdpdGggd2hpY2ggdGhlIG9ic2VydmVkIHZhcmlhbmNlIGluZmxhdGVzIGFzIGNvbXBhcmVkIHRvIGEgbW9kZWwgZm9yIHdoaWNoIGFsbCBwcmVkaWN0b3JlbiB3b3VsZCBiZSBpbmRlcGVuZGVuZC4gCi0gVklGID4gMTAgJFxyaWdodGFycm93JCBzdHJvbmcgbXVsdGljb2xsaW5lYXJpdHkuIAoKLS0tCgojIyMgQm9keSBmYXQgZXhhbXBsZQoKYGBge3Igb3V0LndpZHRoPSc5MCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0KYm9keWZhdCA8LSByZWFkX2RlbGltKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vR1RQQi9QU0xTMjAvbWFzdGVyL2RhdGEvYm9keWZhdC50eHQiLGRlbGltPSIgIikKYm9keWZhdCAlPiUgZ2dwYWlycygpCmBgYAoKLS0tCgpgYGB7ciBlY2hvPUZBTFNFfQpsbUZhdCA8LSBsbShCb2R5X2ZhdH5UcmljZXBzK1RoaWdoK01pZGFybSAsZGF0YT1ib2R5ZmF0KQpzdW1tYXJ5KGxtRmF0KQpgYGAKCi0tLQoKYGBge3J9CnZpZihsbUZhdCkKYGBgCgotLS0KCmBgYHtyIGVjaG89RkFMU0V9CmxtTWlkYXJtIDwtIGxtKE1pZGFybSB+IFRyaWNlcHMrVGhpZ2gsZGF0YT1ib2R5ZmF0KQpzdW1tYXJ5KGxtTWlkYXJtKQpgYGAKCi0tLQoKCldlIGV2YWx1YXRlIHRoZSBWSUYgaW4gdGhlIHByb3N0YXRlIGNhbmNlciBleGFtcGxlIGZvciB0aGUgYWRkaXRpdmUgbW9kZWwgYW5kIHRoZSBtb2RlbCB3aXRoIGludGVyYWN0aWUuCgpgYGB7cn0KdmlmKGxtVldTKQp2aWYobG1WV1NfSW50VlcpCmBgYAoKLSBJbmZsYXRpb24gaW4gaW50ZXJhY3Rpb24gdGVybXMgb2Z0ZW4gY2F1c2VkIGJlY2F1c2UgbWFpbiBlZmZlY3QgZ2V0IGFub3RoZXIgaW50ZXJwcmV0YXRpb24uIAoKLS0tCgojIyBJbmZsdWVuY2lhbCBPYnNlcnZhdGllcwoKCmBgYHtyfQpzZXQuc2VlZCgxMTIzNTgpCm5vYnM8LTIwCnNkeTwtMQp4PC1zZXEoMCwxLGxlbmd0aD1ub2JzKQp5PC0xMCs1Kngrcm5vcm0obm9icyxzZD1zZHkpCngxPC1jKHgsMC41KQp5MSA8LSBjKHksMTArNSoxLjUrcm5vcm0oMSxzZD1zZHkpKQp4MiA8LSBjKHgsMS41KQp5MiA8LSBjKHkseTFbMjFdKQp4MyA8LSBjKHgsMS41KQp5MyA8LSBjKHksMTEpCnBsb3QoeCx5LHhsaW09cmFuZ2UoYyh4MSx4Mix4MykpLHlsaW09cmFuZ2UoYyh5MSx5Mix5MykpKQpwb2ludHMoYyh4MVsyMV0seDJbMjFdLHgzWzIxXSksYyh5MVsyMV0seTJbMjFdLHkzWzIxXSkscGNoPWFzLmNoYXJhY3RlcigxOjMpLGNvbD0yOjQpIAphYmxpbmUobG0oeX54KSxsd2Q9MikKYWJsaW5lKGxtKHkxfngxKSxjb2w9MixsdHk9Mixsd2Q9MikKYWJsaW5lKGxtKHkyfngyKSxjb2w9MyxsdHk9Myxsd2Q9MikKYWJsaW5lKGxtKHkzfngzKSxjb2w9NCxsdHk9NCxsd2Q9MikKbGVnZW5kKCJ0b3BsZWZ0Iixjb2w9MTo0LGx0eT0xOjQsbGVnZW5kPXBhc3RlKCJsbSIsYygiIixhcy5jaGFyYWN0ZXIoMTozKSkpLHRleHQuY29sPTE6NCkKYGBgCgotLS0KCi0gSXQgaXMgbm90IGRlc2lyYWJsZSB0aGF0IGEgc2luZ2xlIG9ic2VydmF0aW9uIGxhcmdlbHkgaW5mbHVlbmNlcyB0aGUgcmVzdWx0IG9mIGEgbGluZWFyIHJlZ3Jlc3Npb24gYW5hbHlzaXMKCi0gRGlhZ25vc3RpY3MgYWxsb3cgdXMgdG8gZGV0ZWN0IGV4dHJlbWUgb2JzZXJ2YXRpb25zLiAKLSAqU3R1ZGVudGl6ZWQgcmVzaWR1YWxzKiB0byBzcG90IG91dGxpZXJzIAotICpMZXZlcmFnZSogdG8gc3BvdCBvYnNlcnZhdGlvbnMgd2l0aCBleHRyZWVtIGNvdmFyaWF0ZSBwYXR0ZXJuCgotLS0KCiMjIyBDb29rJ3MgZGlzdGFuY2UKCi0gQSBzdGF0aXN0aWNzIHRvIGFzc2VzcyB0aGUgaW5mbHVlbmNlIHRoZSBlZmZlY3Qgb2YgYSBzaW5nbGUgb2JzZXJ2YXRpb24gb24gdGhlIHJlZ3Jlc3Npb24gYW5hbHlzaXMgIAotIENvb2sncyBkaXN0YW5jZSBmb3Igb2JzZXJ2YXRpb24gaSBpcyBkaWFnbm9zdGljIG1lYXN1cmUgZm9yIHRoaXMgcGFydGljdWxhciBvYnNlcnZhdGlvbiBvbiBhbGwgYWxsIHByZWRpY3Rpb25zIG9yIG9uICphbGwqIGVzdGltYXRlZCBwYXJhbWV0ZXJzLiAKXFtEX2k9XGZyYWN7XHN1bV97aj0xfV5uKFxoYXR7WX1fai1caGF0e1l9X3tqKGkpfSleMn17cFx0ZXh0cm17TVNFfX1cXSAKCi0gT2JzZXJ2YXRpb24gJGkkIGhhcyBhIGxhcmdlIGluZmx1ZW5jZSBvbiB0aGUgcmVncmVzc2lvbiBwYXJhbWV0ZXJzIGFuZCBwcmVkaWN0aW9ucyBpZiB0aGUgIENvb2sncyBkaXN0YW5jZSAkRF9pJCBpcyBsYXJnZS4gCi0gRXh0cmVtZSBDb29rJ3MgZGlzdGFuY2UgaWYgaXQgaXMgbGFyZ2VyIHRoYW4gdGhlIDUwJSBxdWFudGlsZSBvZiBhbiAkRl97cCsxLG4tKHArMSl9JC1kaXN0cmlidXRpb24uCgotLS0KCgpgYGB7ciAgb3V0LndpZHRoPScxMDAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQpwYXIobWZyb3c9YygyLDIpKQpwbG90KGxtVldTLHdoaWNoPTUpCnBsb3QobG1WV1NfSW50Vlcsd2hpY2g9NSkKcGxvdChjb29rcy5kaXN0YW5jZShsbVZXUyksdHlwZT0iaCIseWxpbT1jKDAsMSksbWFpbj0iQWRkaXRpdmUgbW9kZWwiKQphYmxpbmUoaD1xZigwLjUsbGVuZ3RoKGxtVldTJGNvZWYpLG5yb3cocHJvc3RhdGUpLWxlbmd0aChsbVZXUyRjb2VmKSksbHR5PTIpCnBsb3QoY29va3MuZGlzdGFuY2UobG1WV1NfSW50VlcpLHR5cGU9ImgiLHlsaW09YygwLDEpLCBtYWluPSJNb2RlbCB3aXRoIGxjYXZvbDpsd2VpZ2h0IGludGVyYWN0aW9uIikKYWJsaW5lKGg9cWYoMC41LGxlbmd0aChsbVZXU19JbnRWVyRjb2VmKSxucm93KHByb3N0YXRlKS1sZW5ndGgobG1WV1NfSW50VlckY29lZikpLGx0eT0yKQpgYGAKCi0tLQoKLSBPbmNlIHdlIGVzdGFibGlzaGVkIHRoYXQgYW4gb2JzZXJ2YXRpb24gaXMgaW5mbHVlbnRpYWwgd2UgY2FuIHVzZSAqREZCRVRBUyogdG8gZmluZCB0aGUgcGFyYW1ldGVycyBmb3Igd2hpY2ggdGhlIGVzdGltYXRlcyBhcmUgbGFyZ2VseSBhZmZlY3RlZCBieSB0aGUgb2JzZXJ2YXRpb24KLSAgREZCRVRBUyBvZiBvYnNlcnZhdGllIGkgaXMgYSBkaWFnbm9zdGljIG1lYXN1cmUgZm9yICplYWNoIG1vZGVsIHBhcmFtZXRlciBzZXBhcmF0ZWx5Ki4gCiQkXHRleHRybXtERkJFVEFTfV97aihpKX09XGZyYWN7XGhhdHtcYmV0YX1fe2p9LVxoYXR7XGJldGF9X3tqKGkpfX17XHRleHRybXtTRH0oXGhhdHtcYmV0YX1fe2p9KX0kJCAKLSAgREZCRVRBUyBpcyBleHRyZW1lIHdoZW4gaXQgaXMgbGFyZ2VyIHRoYW4gMSBpbiBzbWFsbCB0byBtb2RlcmF0ZSBkYXRhc2V0cyBvciBleGNlZWRzICQyL1xzcXJ0e259JCBpbiBsYXJnZSBkYXRhc2V0cy4KCi0tLQoKCmBgYHtyIG91dC53aWR0aD0nOTAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQpwYXIobWZyb3c9YygyLDIpKQpkZmJldGFzUGxvdHMobG1WV1MpCmBgYAoKLS0tCgpgYGB7ciBvdXQud2lkdGg9JzkwJScsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0KcGFyKG1mcm93PWMoMiwyKSkKZGZiZXRhc1Bsb3RzKGxtVldTX0ludFZXKQpgYGAKCi0tLQoKYGBge3Igb3V0LndpZHRoPScxMDAlJyxmaWcuYWxpZ249J2NlbnRlcicsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0V9CmJveHBsb3QoZXhwKHByb3N0YXRlJGx3ZWlnaHQpLHlsYWI9IlByb3N0YXRlIFdlaWdodCAoZykiKQpgYGAKCgojIENvbnN0cmFzdHMKCi0gSW4gbW9yZSBjb21wbGV4IGRlc2lnbnMgdGhhdCBhcmUgbW9kZWxsZWQgdXNpbmcgZ2VuZXJhbCBsaW5lYXIgbW9kZWxzIG9uZSBvZnRlbiBoYXMgdG8gYXNzZXNzIG11bHRpcGxlIGh5cG90aGVzZXMuIAotIE1vcmVvdmVyIHRoZXNlIGh5cG90aGVzZXMgY2FuIHR5cGljYWxseSBub3QgYWx3YXlzIGJlIHRyYW5zbGF0ZWQgaW50byBhIHRlc3Qgb24gb25lIHBhcmFtZXRlciwgYnV0IGluIGEgbGluZWFyIGNvbWJpbmF0aW9uIG9mIG1vZGVsIHBhcmFtZXRlcnMuIAotIEEgbGluZWFyIGNvbWJpbmF0aW9uIG9mIG1vZGVsIHBhcmFtZXRlcnMgaXMgYWxzbyByZWZlcnJlZCB0byBhcyBhIGNvbnRyYXN0LgoKIyMgTkhBTkVTIGV4YW1wbGUKCi0gU3VwcG9zZSB0aGF0IHJlc2VhcmNoZXJzIHdhbnQgdG8gYXNzZXNzIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGFnZSBhbmQgYmxvb2RwcmVzc3VyZS4gCgotIFBvc3NpYmx5IHRoaXMgYXNzb2NpYXRpb24gd2lsbCBkaWZmZXIgZm9yIGZlbWFsZXMgYW5kIG1hbGVzLiAKCi0gVGhleSB3YW50IHRvIGFzc2VzcyBmb2xsb3dpbmcgaHlwb3RoZXNlczogCgogICAgLSBJcyB0aGVyZSBhbiBhc3NvY2lhdGlvbiBiZXR3ZWVuIGFnZSBhbmQgYmxvb2QgcHJlc3N1cmUgZm9yIGZlbWFsZXM/IAogICAgLSBJcyB0aGVyZSBhbiBhc3NvY2lhdGlvbiBiZXR3ZWVuIGFnZSBhbmQgYmxvb2QgcHJlc3N1cmUgZm9yIG1hbGVzPyAKICAgIC0gSXMgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gYWdlIGFuZCBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbnQgZm9yIGZlbWFsZXMgYW5kICBtYWxlcz8gCgojIyBNb2RlbAoKV2UgZml0IGEgbW9kZWwgZm9yIHRoZSBhdmVyYWdlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIChgQlBTeXNBdmVgKSB1c2luZyBhZ2UsIGdlbmRlciBhbmQgdGhlIGludGVyYWN0aW9uIGJldHdlZW4gYWdlIGFuZCBnZW5kZXIgZm9yIGFkdWx0IGNhdWNhc2lhbnMgZnJvbSB0aGUgTkhBTkVTIHN0dWR5LgoKYGBge3J9CmxpYnJhcnkoTkhBTkVTKQpicERhdGEgPC0gTkhBTkVTICU+JQpmaWx0ZXIoCiAgUmFjZTEgPT0iV2hpdGUiICYKICAgIEFnZSA+PSAxOCAmCiAgICAhaXMubmEoQlBTeXNBdmUpCiAgICApCgptQnAxIDwtIGxtKEJQU3lzQXZlIH4gQWdlKkdlbmRlciwgYnBEYXRhKQpwYXIobWZyb3cgPSBjKDIsMikpCnBsb3QobUJwMSkKYGBgCgotIEFzc3VtcHRpb25zIGFyZSBub3QgZnVsbGZpbGxlZCEKCiAgICAtIGxpbmVhcml0ZWl0IGlzIG9rCiAgICAtIGhldGVyb3NjZWRhc3RpY2l0eQogICAgLSBObyBub3JtYWxpdHk6IGRpc3RyaWJ1dGlvbiBpcyBza2V3ZWQgdG8gdGhlIHJpZ2h0IC4KICAgIC0gTGFyZ2UgZGF0YXNldCBzbyB3ZSBjYW4gYWRvcHQgdGhlIENMVAoKIyMjIFRyYW5zZm9ybWF0aW9uCgpXZSBmaXQgYSBtb2RlbCB1c2luZyBsb2cyIHRyYW5zZm9ybWVkIGF2ZXJhZ2Ugc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUgKGBCUFN5c0F2ZWApLgoKYGBge3J9Cm1CcDIgPC0gbG0oQlBTeXNBdmUgJT4lIGxvZzIgfiBBZ2UqR2VuZGVyLCBicERhdGEpCnBhcihtZnJvdyA9IGMoMiwyKSkKcGxvdChtQnAyKQpgYGAKCi0gUmVzaWR1YWxzIGFyZSBzdGlsbCBoZXRlcm9zY2VkYXN0aWMuCgojIyMgUmVtZWRpYXRlIGZvciBoZXRlcm9zY2VkYXN0aWNpdHkKCi0gSWYgdGhlIHJlc2lkdWFsIHBsb3Qgc2hvd3MgYSBjb25lIHdlIGNhbiBnZXQgdG8gdmFsaWQgaW5mZXJlbmNlIGZvciBsYXJnZSBzYW1wbGVzIGJ5IG1vZGVsaW5nIHRoZSB2YXJpYW5jZSAgZXhwbGljaXRseSBpbiBmdW5jdGlvbiBvZiB0aGUgZml0dGVkIHJlc3BvbnNlLiAKCi0gVGhlIGludmVyc2UgdmFyaWFuY2UgZm9yIGVhY2ggb2JzZXJ2YXRpb24gY2FuIHRoYW4gYmUgdXNlZCBhcyBhIHdlaWdodCBpbiB0aGUgbG0gZnVuY3Rpb24uIAoKMS4gTW9kZWwgc3RhbmRhcmQgZGV2aWF0aW9uIGluIGZ1bmN0aW9uIG9mIG1lYW4gcmVzcG9uc2UuCjIuIERvIHRoaXMgYnkgbW9kZWxpbmcgYWJzb2x1dGUgdmFsdWVzIG9mIHJlc2lkdWFscyBpbiBmdW5jdGlvbiBvZiBmaXR0ZWQgdmFsdWVzIG9mIG1vZGVsLiAKMy4gV2UgY2FuIHRoYW4gZXN0aW1hdGUgdGhlIHZhcmlhbmNlIG9mIFkgZm9yIGVhY2ggb2JzZXJ2YXRpb24gYnkgc3F1YXJpbmcgdGhlIHByZWRpY3Rpb25zIGZvciBhbGwgb2JzZXJ2YXRpb25zIHVzaW5nIHRoZSBtb2RlbCBmb3IgdGhlIHN0YW5kYXJkIGRldmlhdGlvbi4gCjQuIEluZmVyZW5jZSByZW1haW5zIHZhbGlkIGFzeW1wdG90aWNhbGx5LiAKCmBgYHtyfQptU2QgPC0gbG0obUJwMSRyZXMgJT4lIGFicyB+IG1CcDIkZml0dGVkKQpgYGAKCldlIGVzdGltYXRlIHRoZSBtb2RlbCBhZ2FpbjoKCmBgYHtyfQptQnAzIDwtIGxtKEJQU3lzQXZlIH4gQWdlKkdlbmRlciwgYnBEYXRhLCB3ID0gMS9tU2QkZml0dGVkXjIpCmBgYAoKUmVzaWR1YWxzIGFyZSBzdGlsbCBoZXRlcm9zY2VkYXN0aWMuCgpgYGB7cn0KZGF0YS5mcmFtZShyZXNpZHVhbHMgPSBtQnAzJHJlc2lkdWFscywgZml0ID0gbUJwMyRmaXR0ZWQpICU+JQogIGdncGxvdChhZXMoZml0LHJlc2lkdWFscykpICsKICBnZW9tX3BvaW50KCkKYGBgCgpCdXQgd2UgYWNjb3VudGVkIGZvciB0aGF0IHVzaW5nIHdlaWdodHMhIApOb3RlIHRoYXQgaWYgd2UgcmVzY2FsZSB0aGUgcmVzaWR1YWxzIHVzaW5nIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gKG11bHRpcGx5aW5nIHRoZW0gd2l0aCB0aGUgc3F1YXJlIHJvb3Qgb2YgdGhlIHdlaWdodCkgd2Ugb2J0YWluICByZXNjYWxlZCByZXNpZHVhbHMgdGhhdCBhcmUgaG9tb3NjZWRhc3RpYy4KClRoZSBtb2RlbCBwYXJhbWV0ZXJzIGFyZSBlc3RpbWF0ZWQgdXNpbmcgd2VpZ2h0ZWQgbGVhc3Qgc3F1YXJlczoKClxbIFNTRSA9IFxzdW1cbGltaXRzX3tpPTF9Xm4gd19pIGVfaV4yXF0KCndpdGggJHdfaSA9IDEvXGhhdCBcc2lnbWFeMl9pJC4KCldlaWdodGVkIHJlZ3Jlc3Npb24gd2lsbCBjb3JyZWN0IGZvciBoZXRlcm9zY2VkYXN0aWNpdHkuCgpgYGB7cn0KZGF0YS5mcmFtZShzY2FsZWRfcmVzaWR1YWxzID0gbUJwMyRyZXNpZHVhbHMvbVNkJGZpdHRlZCwgZml0ID0gbUJwMyRmaXR0ZWQpICU+JQogIGdncGxvdChhZXMoZml0LHNjYWxlZF9yZXNpZHVhbHMpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKIyMjIEluZmVyZW5jZQoKYGBge3J9CnN1bW1hcnkobUJwMykKYGBgCgpUaGUgcmVzZWFyY2ggcXVlc3Rpb25zIHRyYW5zbGF0ZSB0byBmb2xsb3dpbmcgbnVsbGh5cG90aGVzZXM6CgoxLiBBc3NvY2lhdGlvbiBiZXR3ZWVuIGJsb29kIHByZXNzdXJlIGFuZCBhZ2UgZm9yIGZlbWFsZXM/IFxbSF8wOiBcYmV0YV9cdGV4dHtBZ2V9ID0gMCBcdGV4dHsgdnMgfSBIXzE6IFxiZXRhX1x0ZXh0e0FnZX0gXG5lcSAwIFxdCgoyLiBBc3NvY2lhdGlvbiBiZXR3ZWVuIGJsb29kIHByZXNzdXJlIGFuZCBhZ2UgZm9yIG1hbGVzPyBcW0hfMDogXGJldGFfXHRleHR7QWdlfSArIFxiZXRhX1x0ZXh0e0FnZTpHZW5kZXJtYWxlfSA9IDAgXHRleHR7IHZzIH0gSF8xOiBcYmV0YV9cdGV4dHtBZ2V9ICsgXGJldGFfXHRleHR7QWdlOkdlbmRlcm1hbGV9IFxuZXEgMCBcXQoKMy4gSXMgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gYmxvb2QgcHJlc3N1cmUgYW5kIGFnZSBkaWZmZXJlbnQgZm9yIGZlbWFsZXMgYW5kIG1hbGVzPyAgXFtIXzA6IFxiZXRhX1x0ZXh0e0FnZTpHZW5kZXJtYWxlfSA9IDAgXHRleHR7IHZzIH0gSF8xOiBcYmV0YV9cdGV4dHtBZ2U6R2VuZGVybWFsZX0gXG5lcSAwIFxdCgoKLSBXZSBjYW4gYXNzZXNzIGh5cG90aGVzZXMgMSBhbmQgMyBpbW1lZGlhdGVseSB1c2luZyB0aGUgb3V0cHV0IG9mIHRoZSBtb2RlbC4gCi0gSHlwb3RoZXNlcyAyIGlzIGEgbGluZWFyIGNvbWJpbmF0aW9uIG9mIHR3byBwYXJhbWV0ZXJzLiAKLSBXZSBhbHNvIG5lZWQgbXVsdGlwbGUgdGVzdHMgZm9yIGFzc2Vzc2luZyB0aGUgYXNzb2NpYXRpb24gYmV0d2VlbiBzeXNCcCBhbmQgQWdlLiAKCldlIGNhbiBhZ2FpbiB1c2UgYW4gQW5vdmEgYXBwcm9hY2guCgoxLiAgV2UgZmlyc3QgYXNzZXNzIHRoZSBvbW5pYnVzIGh5cG90aGVzaXMgdGhhdCB0aGVyZSBpcyBubyBhc3NvY2lhdGlvbiBiZXR3ZWVuIGFnZSBhbmQgYmxvb2QgcHJlc3N1cmUuIApcWyBIXzA6IFxiZXRhX1x0ZXh0e0FnZX0gPSBcYmV0YV9cdGV4dHtBZ2V9ICsgXGJldGFfXHRleHR7QWdlOkdlbmRlcm1hbGV9ID0gXGJldGFfXHRleHR7QWdlOkdlbmRlcm1hbGV9ID0gMApcXQoKLSB3aGljaCBzaW1wbGlmaWVzIHRvIGFzc2Vzc2luZyAKClxbIEhfMDogXGJldGFfXHRleHR7QWdlfSA9IFxiZXRhX1x0ZXh0e0FnZTpHZW5kZXJtYWxlfSA9IDAKXF0KCi0gV2UgY2FuIGRvIHRoaXMgYnkgY29tcGFyaW5nIHR3byBtb2RlbHM6IHRoZSBmdWxsIG1vZGVsIHdpdGggYW4gZWZmZWN0IGZvciBHZW5kZXIsIEFnZSBhbmQgR2VuZGVyIHggQWdlIGludGVyYWN0aW9uIGFnYWluc3QgYSByZWR1Y2VkIG1vZGVsIHdpdGggb25seSBHZW5kZXIuCgoyLiBJZiB3ZSBjYW4gcmVqZWN0IHRoaXMgaHlwb3RoZXNpcyB3ZSBjYW4gYWdhaW4gZG8gYSBwb3N0aG9jIGFuYWx5c2lzIGZvciBlYWNoIG9mIHRoZSBjb250cmFzdHMuIAoKCiMjIyMgT21uaWJ1cyB0ZXN0CgpgYGB7cn0KbUJwMCA8LSBsbShCUFN5c0F2ZSB+IEdlbmRlciwgYnBEYXRhLCB3ID0gMS9tU2QkZml0dGVkXjIpCmFub3ZhKG1CcDAsIG1CcDMpCmBgYCAgCgoKIyMjIyBQb3N0aG9jIHRlc3RzCgpGb3IgdGhlIHBvc3Rob2MgdGVzdHMgd2Ugd2lsbCBhZ2FpbiBidWlsZCB1cG9uIHRoZSBgbXVsdGNvbXBgIHBhY2thZ2UuCgpgYGB7cn0KbGlicmFyeShtdWx0Y29tcCkKYnBQb3N0aG9jIDwtIGdsaHQobUJwMywgbGluZmN0PWMoCiAgIkFnZSA9IDAiLAogICJBZ2UgKyBBZ2U6R2VuZGVybWFsZSA9IDAiLAogICJBZ2U6R2VuZGVybWFsZSA9IDAiKQogICkKYnBQb3N0aG9jICU+JSBzdW1tYXJ5CgpicFBvc3Rob2NDSSA8LSBicFBvc3Rob2MgJT4lIGNvbmZpbnQKYnBQb3N0aG9jQ0kKYGBgCgpOb3RlIHRoYXQgdGhlIGdsaHQgZnVuY3Rpb24gYWxsb3dzIHVzIHRvIGRlZmluZSB0aGUgY29udHJhc3RzIGJ5IGV4cGxpY2l0ZWx5IGRlZmluaW5nIHRoZSBudWxsaHlwb3RoZXNlIHVzaW5nIHRoZSBuYW1lcyBvZiB0aGUgbW9kZWwgcGFyYW1ldGVycy4gCgojIyMjIENvbmNsdXNpb24KCldlIGNhbiBjb25jbHVkZSB0aGF0IHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGFnZSBhbmQgYmxvb2QgcHJlc3N1cmUgaXMgZXh0cmVtZWx5IHNpZ25pZmljYW50IChwIDw8IDAuMDAxKS4KClRoZSBibG9vZCBwcmVzc3VyZSBmb3IgZmVtYWxlcyB0aGF0IGRpZmZlciBpbiBhZ2UgaXMgb24gYXZlcmFnZSBgciByb3VuZChicFBvc3Rob2NDSSRjb25maW50WzEsMV0sMilgIG1tIEhnIGhpZ2hlciBwZXIgeWVhciBvZiBhZ2UgZGlmZmVyZW5jZSBmb3IgdGhlIGVsZGVzdCBmZW1hbGUgYW5kIGlzIGV4dHJlbWVseSBzaWduaWZpY2FudCAocCA8PCAwLjAwMSwgOTUlIENJIFtgciByb3VuZChicFBvc3Rob2NDSSRjb25maW50WzEsLTFdLDIpYF0uCgpUaGUgYmxvb2QgcHJlc3N1cmUgZm9yIG1hbGVzIHRoYXQgZGlmZmVyIGluIGFnZSBpcyBvbiBhdmVyYWdlIGByIHJvdW5kKGJwUG9zdGhvY0NJJGNvbmZpbnRbMiwxXSwyKWAgbW0gSGcgaGlnaGVyIHBlciB5ZWFyIG9mIGFnZSBkaWZmZXJlbmNlIGZvciB0aGUgZWxkZXN0IG1hbGUgYW5kIGlzIGV4dHJlbWVseSBzaWduaWZpY2FudCAocCA8PCAwLjAwMSwgOTUlIENJIFtgciByb3VuZChicFBvc3Rob2NDSSRjb25maW50WzIsLTFdLDIpYF0uCgpUaGUgYXZlcmFnZSBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlIGJldHdlZW4gc3ViamVjdHMgdGhhdCBkaWZmZXIgaW4gYWdlIGlzIG9uIGF2ZXJhZ2UgIGByIHJvdW5kKGFicyhicFBvc3Rob2NDSSRjb25maW50WzMsMV0pLDIpYCBtbSBIZy9qYWFyIGhpZ2hlciBmb3IgZmVtYWxlcyB0aGFuIGZvciBtYWxlcyAocCA8PCAwLjAwMSwgOTUlIENJIFtgciBicFBvc3Rob2NDSSRjb25maW50WzMsLTFdICU+JSBhYnMgJT4lIHNvcnQgJT4lcm91bmQoLiwyKWBdKS4gIAoK