Breast cancer dataset
brca <- read_csv("https://raw.githubusercontent.com/statOmics/sbc20/master/data/breastcancer.csv")
brca
# A tibble: 32 x 10
sample_name filename treatment er grade node size age ESR1 S100A8
<chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 OXFT_209 gsm65344.ce… tamoxifen 1 3 1 2.5 66 1939. 207.
2 OXFT_1769 gsm65345.ce… tamoxifen 1 1 1 3.5 86 2752. 37.0
3 OXFT_2093 gsm65347.ce… tamoxifen 1 1 1 2.2 74 379. 2364.
4 OXFT_1770 gsm65348.ce… tamoxifen 1 1 1 1.7 69 2532. 23.6
5 OXFT_1342 gsm65350.ce… tamoxifen 1 3 0 2.5 62 141. 3219.
6 OXFT_2338 gsm65352.ce… tamoxifen 1 3 1 1.4 63 1495. 108.
7 OXFT_2341 gsm65353.ce… tamoxifen 1 1 1 3.3 76 3406. 14.0
8 OXFT_1902 gsm65354.ce… tamoxifen 1 3 0 2.4 61 2813. 68.4
9 OXFT_1982 gsm65355.ce… tamoxifen 1 1 0 1.7 62 950. 74.2
10 OXFT_5210 gsm65356.ce… tamoxifen 1 3 0 3.5 65 1053. 182.
# … with 22 more rows
- Om didactische redenen verwijderen we eerst 3 outliers in de S100A8 expressie data.
- In deze studie kan dit echter niet worden verantwoord
- Later in de lessen laten we zien hoe je goed met alle data omgaat.
brca %>%
ggplot(aes(x="", y=S100A8)) +
geom_boxplot() +
xlab("") +
ylab("S100A8 expressie")

library(GGally)
brcaSubset <- brca %>%
filter(S100A8<2000)
brcaSubset[,-(1:4)] %>% ggpairs()

Associatie tussen ESR1 en S100A8 expressie
ESR1 in ± 75% van borstkankertumoren.
- Expressie van ER-gen positief voor behandeling: tumor reageert op hormoontherapie
- Tamoxifen interageert met ER en moduleert genexpressie.
Eiwitten van de S100-familie zijn vaak gedisreguleerd bij kanker
S100A8 expressie onderdrukt immuunsysteem in tumor en creëert inflamatoir milieu die kankergroei promoot.
Interesse in associatie tussen ESR1 en S100A8 expressie.
- pipe dataset naar ggplot
- selecteer data
ggplot(aes(x=ESR1,y=S100A8))
- voeg punten toe met
geom_point()
- voeg een “smooth line” toe
geom_smooth()
brcaSubset %>%
ggplot(aes(x=ESR1,y=S100A8)) +
geom_point() +
geom_smooth()

Lineaire Regressie
Statistische methode om relatie tussen 2 reeksen observaties (Xi,Yi), bekomen voor onafhankelijke subjecten i=1,...,n, te beschrijven.
Gen expressie voorbeeld
- Response Y : S100A8 expressie
- Predictor X: ESR1 expressie
- pipe dataset naar ggplot
- selecteer data
ggplot(aes(x=ESR1,y=S100A8))
- voeg punten toe met
geom_point()
- voeg een “smooth line” toe
geom_smooth()
- voeg een rechte toe
geom_smooth()
met method = "lm"
(linear model). (We zetten se = FALSE
om geen puntgewijze betrouwbaarheidsintervallen weer te geven)
brcaSubset %>%
ggplot(aes(x = ESR1,y = S100A8)) +
geom_point() +
geom_smooth(se = FALSE, col = "grey") +
geom_smooth(method = "lm", se = FALSE)

Model
- Voor vaste X, heeft Y niet noodzakelijke dezelfde waarde
observation = signal + noise
Yi=g(Xi)+ϵi
- We definiëren g(x) als het verwachte resultaat voor subjects met Xi=x
E[Yi|Xi=x]=g(x)
Daarom is ϵi gemiddeld 0 voor subjects met dezelfde Xi: E[ϵi|Xi]=0
Lineaire regressie
- Om accurate en interpreteerbare resultaten te bekomen, kiest men g(x) vaak als een lineaire functie met ongekende parameters.
E(Y|X=x)=β0+β1x
onbekend intercept β0 en helling β1.
Lineair model legt een assumptie op de verdeling van X en Y, die incorrect kan zijn.
Efficiënte data-analyse: benut alle observaties om iets te leren over verwachte uitkomst bij X=x.
Gebruik
Predictie: wanneer Y ongekend is, maar X wel, kunnen we Y voorspellen op basis van X E(Y|X=x)=β0+β1x
Associatie: biologische relatie tussen variabele X en continue meting Y beschrijven.
Intercept: E(Y|X=0)=β0
Slope: E(Y|X=x+δ)−E(Y|X=x)=β0+β1(x+δ)−β0−β1x=β1δ
β1: verschil in gemiddelde uitkomst voor subjecten die verschillen in één eenheid van de predictor X.
Parameterschatting
- Kleinste kwadraten techniek (Least squares)
brcaSubset %>%
ggplot(aes(x = ESR1, y = S100A8)) +
geom_point() +
geom_smooth(se = FALSE, col = "grey") +
geom_smooth(method = "lm", se = FALSE)

SSE=n∑i=1(yi−β0−β1xi)2=n∑i=1e2i
- Met ei de residuen: de verticale afstanden van de observaties tot de gefitte regressierechte
Schatters die SSE minimaliseren
^β1=n∑i=1(yi−ˉy)(xi−ˉx)n∑i=1(xi−ˉxi)2=cor(x,y)sysx
^β0=ˉy−ˆβ1ˉx
- Merk op dat de helling van de kleinste kwadratenlijn evenredig is met de correlatie tussen de uitkomst en de verklarende variabele.
Geschatte lineaire regressiemodel laat toe om:
verwachte uitkomst te voorspellen voor subjecten met een gegeven waarde x voor de predictor: E[Y|X=x]=ˆβ0+ˆβ1x
na te gaan hoeveel uitkomst gemiddeld verschilt tussen 2 groepen subjecten met een verschil van δ eenheden in de verklarende variabele:
E[Y|X=x+δ]−E[Y|X=x]=ˆβ1δ
Borstkanker voorbeeld
lm1 <- lm(S100A8 ~ ESR1, brcaSubset)
summary(lm1)
Call:
lm(formula = S100A8 ~ ESR1, data = brcaSubset)
Residuals:
Min 1Q Median 3Q Max
-95.43 -34.81 -6.79 34.23 145.21
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 208.47145 28.57207 7.296 7.56e-08 ***
ESR1 -0.05926 0.01212 -4.891 4.08e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 59.91 on 27 degrees of freedom
Multiple R-squared: 0.4698, Adjusted R-squared: 0.4502
F-statistic: 23.93 on 1 and 27 DF, p-value: 4.078e-05
E(Y|X=x)=208.47−0.059x
De verwachte S100A8-expressie is gemiddeld 59 eenheden lager voor patiënten met een ESR1-expressieniveau die 1000 eenheden hoger ligt.
Verwachte S100A8 expressieniveau voor patiënten met een ESR1 expressieniveau van 2000:
208.47−0.059×2000=89.94
Verwachte S100A8 expressieniveau voor patiënten met een ESR1 expressieniveau van 4000:
208.47−0.059×4000=−28.58
Let op voor extrapolatie! (Veronderstelling van lineariteit kan men enkel nagaan binnen het bereik van de data).
Statistische besluitvorming (statistische inferentie)
Om besluiten te kunnen trekken over lineaire regressiemodel E(Y|X)=β0+β1X
moeten we weten:
Hoe de least squares parameter schatters variëren van steekproef tot steekproef, en
En hoe is dit onder de nulhypothese dat er geen associatie is tussen predictor en response
Noodzaak aan statistisch model!
Modelleer de verdeling van Y gegeven X expliciet: fY|X(y)
Modelleer verdeling van Y?
- Naast lineariteit hebben we nog aannames nodig!
- Onafhankelijkheid: waarnemingen (X1,Y1),...,(Xn,Yn) zijn gemaakt voor n onafhankelijke subjecten (Is vereist om de variantie te schatten)
- Homoscedasticiteit of gelijke varianties: waarnemingen variëren met gelijk gemiddelde rond de regressielijn.
- Residuen ϵi hebben gelijke variantie voor elke Xi=x
- var(Y|X=x)=σ2 voor elke X=x
- σ wordt de residuele standaarddeviatie genoemd.
- Normaliteit: de residuen ϵi zijn normaal verdeeld

Uit 2, 3 en 4 volgt dat ϵi i.i.d.N(0,σ2).
Als we ook steunen op eerste veronderstelling van lineariteit: Yi|Xi∼N(β0+β1Xi,σ2),
Verder kan men aantonen dat onder deze aannames σ2ˆβ0=n∑i=1X2in∑i=1(Xi−ˉX)2×σ2n en σ2ˆβ1=σ2n∑i=1(Xi−ˉX)2
en dat de parameterschatters eveneens normaal verdeeld zijn ˆβ0∼N(β0,σ2ˆβ0) en ˆβ1∼N(β1,σ2ˆβ1)
Hoge spreiding op X verbetert de precisie
σ2ˆβ1=σ2n∑i=1(Xi−ˉX)2

- Conditionele variantie (σ2) is niet gekend
- Schatten d.m.v. gemiddelde van die kwadratische afwijkingen rond de regressierechte
- mean squared error (MSE)
ˆσ2=MSE=n∑i=1(yi−ˆβ0−ˆβ1×xi)2n−2=n∑i=1e2in−2. - Voor het bekomen van deze schatter steunen we op onafhankelijkheid (aanname 2) en homoscedasticiteit (aanname 3). - deel door n−2
Na schatting van σ2 bekomen we volgende standaard errors:
SEˆβ0=ˆσˆβ0=√n∑i=1X2in∑i=1(Xi−ˉX)2×MSEn en SEˆβ1=ˆσˆβ1=√MSEn∑i=1(Xi−ˉX)2
Opnieuw toetsen en betrouwbaarheidsintervallen o.b.v. T=ˆβk−βkSE(ˆβk) with k=1,2.
Als aan alle aannames is voldaan volgt T een t-verdeling met n-2 vrijheidsgraden.
Als geen normaliteit maar wel onafhankelijk, lineariteit en homoscedasticiteit en grote dataset →Centrale Limietstelling
Borstkanker voorbeeld
Negatieve associatie tussen S100A8 en ESR1 gen expressie.
Veralgemeen effect in steekproef naar populatie met behulp van het betrouwbaarheidsinterval op de helling: [ˆβ1−tn−2,α/2SEˆβ1,ˆβ1+tn−2,α/2SEˆβ1].
2.5 % 97.5 %
(Intercept) 149.84639096 267.09649989
ESR1 -0.08412397 -0.03440378
- Negatief verband is significant op het 5% significantieniveau.
Hypothese test
Vertaal de onderzoeksvraag “Is er een associatie tussen de S100A8- en ESR1-genexpressie?” naar de parameters in het model.
Onder nulhypothese geen associatie tussen expressie van beide genen: H0:β1=0
Onder alternatieve hypothese is er een associatie tussen beide genen: H1:β1≠0
Test statistiek T=ˆβ1−0SE(ˆβk)
Onder H0 volgt de statistiek een t-verdeling met n-2 vrijheidsgraden.
Brca dataset
Call:
lm(formula = S100A8 ~ ESR1, data = brcaSubset)
Residuals:
Min 1Q Median 3Q Max
-95.43 -34.81 -6.79 34.23 145.21
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 208.47145 28.57207 7.296 7.56e-08 ***
ESR1 -0.05926 0.01212 -4.891 4.08e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 59.91 on 27 degrees of freedom
Multiple R-squared: 0.4698, Adjusted R-squared: 0.4502
F-statistic: 23.93 on 1 and 27 DF, p-value: 4.078e-05
- Associatie tussen de S100A8 en ESR1 genexpressie extreem significant is (p<<0.001).
- Maar eerst moeten we alle assumpties controleren!
- Anders kunnen de conclusies o.b.v. de statistische test en het BI onjuist zijn.
Nagaan van modelveronderstellingen
- Onafhankelijkheid: design
- Lineariteit: besluitvorming geen zin als model niet lineair is
- Homoscedasticiteit: besluitvorming/p-waarde is niet betrouwbaar als de data niet homoscedastisch zijn
- Normaliteit: besluitvorming/p-waarde is niet betrouwbaar als de data niet normaal verdeeld zijn in kleine steekproeven
Lineariteit
brcaSubset %>%
ggplot(aes(x = ESR1, y = S100A8)) +
geom_point() +
geom_smooth(se = FALSE, col = "grey") +
geom_smooth(method = "lm", se = FALSE)

Residuplots
Afwijkingen van lineariteit echter makkelijker opgespoord d.m.v. een residuplot. (Zeker als er later meer variabelen zijn in het lineaire model)
verklarende variabele of predicties ˆβ0+ˆβ1x op de X-as
de residuen op de Y-as ei=yi−ˆg(xi)=yi−ˆβ0−ˆβ1×xi,




Homoscedasticiteit (gelijkheid van variantie)
Residuen en kwadratische residu’s dragen informatie over residuele variabiliteit.
Associatie met de verklarende variabelen → indicatie van heteroscedasticiteit.
Scatterplot van of ei versus xi of predicties ˆβ0+ˆβ1xi.
Scatterplot van gestandardiseerd residu versus xi of predicties.
Normaliteit
Indien voldoende gegevens, schatters normaal verdeeld zelfs wanneer observaties niet Normaal verdeeld zijn: centrale limiet stelling
Wat ‘voldoende observaties’ zijn, hangt af van hoe goed de verdeling op de Normale lijkt.
Aanname is dat uitkomsten Normaal verdeeld zijn bij vaste waarden van de verklarende variabelen. Yi|Xi∼N(β0+β1Xi,σ2)
QQ-plot van response Y is heel misleidend.
QQ-plot van de residuen ei


Afwijkingen van Modelveronderstellingen
Borstkanker voorbeeld
Problemen met
heteroscedasticiteit
mogelijkse afwijking van normaliteit (scheefheid naar rechts)
negatieve concentratievoorspellingen die theoretisch niet mogelijk zijn
niet-lineairiteit
treedt veelal op bij concentratie en intensiteitsmetingen
Deze zijn vaak log-normaal verdeeld (normale verdeling na log-transformatie)
In Figuur 6.3 eveneens een soort exponentiële trend
In de genexpressie literatuur wordt veelal gebruik gemaak van log2 transformatie
gen-expressie op log-schaal proportionele verschillen op de originele schaal
brca %>%
ggplot(aes(x = ESR1, y = S100A8)) +
geom_point() +
geom_smooth()

brca %>%
ggplot(aes(
x = ESR1 %>% log2,
y = S100A8 %>% log2)
) +
geom_point() +
geom_smooth()

lm2<-lm(S100A8 %>% log2 ~ ESR1 %>% log2, brca)
plot(lm2)




Call:
lm(formula = S100A8 %>% log2 ~ ESR1 %>% log2, data = brca)
Residuals:
Min 1Q Median 3Q Max
-1.94279 -0.66537 0.08124 0.68468 1.92714
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 23.401 1.603 14.60 3.57e-15 ***
ESR1 %>% log2 -1.615 0.150 -10.76 8.07e-12 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 1.026 on 30 degrees of freedom
Multiple R-squared: 0.7942, Adjusted R-squared: 0.7874
F-statistic: 115.8 on 1 and 30 DF, p-value: 8.07e-12
2.5 % 97.5 %
(Intercept) 20.128645 26.674023
ESR1 %>% log2 -1.921047 -1.308185
Interpretatie 1
Een patiënt met een ESR1 expressie die 1 eenheid op de log2 schaal hoger ligt dan dat van een andere patiënt heeft gemiddeld gezien een expressie-niveau van het S100A8 gen dat 1.61 eenheden lager ligt (95% BI [-1.92,-1.31]).
Crossectionele studie: enkel uitspraken over verschillen tussen patiënten!
log2ˆμ1=23.401−1.615×logESR1, log2ˆμ2=23.401−1.615×logESR2 log2ˆμ2−log2ˆμ1=−1.615(log2ESR2−log2ESR1)=−1.615×1=−1.615
Interpretatie 2
Model op log-schaal: bij terugtransformatie verkrijgen we het geometrische gemiddelde
n∑i=1logxin=logx1+…+logxnn(1)=log(x1×…×xn)n=log(n∏i=1xi)n(2)=log(n√n∏i=1xi)
- Populatiegemiddelden μ dus geschat a.d.h.v. geometrisch gemiddelden.
- Logaritmische transformatie is een monotoon: we kunnen betrouwbaarheidsintervallen berekend op log-schaal terugtransformeren!
ESR1 %>% log2
0.3265519
ESR1 %>% log2
3.0623
2.5 % 97.5 %
3.786977 2.476298
Een patiënt met een ESR1 expressie die 2 keer zo hoog is als die van een andere patiënt, zal gemiddeld een S100A8-expressie hebben die 3.06 keer lager is (95% BI [2.48,3.79]).
log2ˆμ1=23.401−1.615×logESR1, log2ˆμ2=23.401−1.615×logESR2 log2ˆμ2−log2ˆμ1=−1.615(log2ESR2−log2ESR1) log2[ˆμ2ˆμ1]=−1.615log2[ESR2ESR1] ˆμ2ˆμ1=[ESR2ESR1]−1.615=2−1.615=0.326 or ˆμ1ˆμ2=21.615=3.06
Interpratie 3
Een patiënt met een ESR1 expressie die 1% hoger is dan die van een andere patiënt zal gemiddeld een expressieniveau voor het S100A8 gen hebben dat ongeveer -1.61% lager is (95% BI [-1.92,-1.31])%.
log2ˆμ1=23.401−1.615×logESR1, log2ˆμ2=23.401−1.615×logESR2 log2ˆμ2−^log2μ1=−1.615(log2ESR2−log2ESR1) log2[ˆμ2ˆμ1]=−1.615log2[ESR2ESR1] ˆμ2ˆμ1=[ESR2ESR1]−1.615=1.01−1.615=0.984≈−1.6%
Dit geldt voor lage tot matige waarden van β1: −10<β1<10→1.01β1−1≈β1100.
Besluitvorming over gemiddelde uitkomst
Regressie model kan ook worden gebruikt voor predictie
Besluitvorming te doen over de gemiddelde uitkomst bij een gegeven waarde x, m.a.w. ˆg(x)=ˆβ0+ˆβ1x
ˆg(x) een schatter van het conditionele gemiddelde E[Y|X=x]
Parameterschatters Normale verdeeld en onvertekend → schatter ˆg(x) ook Normaal verdeeld en onvertekend.
SEˆg(x)=√MSE{1n+(x−ˉX)2n∑i=1(Xi−ˉX)2}.
T=ˆg(x)−g(x)SEˆg(x)∼tn−2
- Gemiddelde uitkomst en betrouwbaarheidsintervallen op de gemiddelde uitkomst in R via de
predict(.)
functie.
newdata
argument: predictorwaarden (x-waarden) voor het berekenen van gemiddelde uitkomsten
interval="confidence"
argument om betrouwbaarheidsintervallen te bekomen.
- Zonder
newdata
argument wordt de gemiddelde uitkomsten berekend voor alle predictorwaarden van de dataset.
grid <- 140:4000
g <- predict(
lm2,
newdata = data.frame(ESR1 = grid),
interval = "confidence")
head(g)
fit lwr upr
1 11.89028 10.76082 13.01974
2 11.87370 10.74721 13.00019
3 11.85724 10.73370 12.98078
4 11.84089 10.72028 12.96151
5 11.82466 10.70696 12.94237
6 11.80854 10.69372 12.92336
Merk op dat we de nieuwe data die we gespecificeerd hebben voor de ESR1 expressie niet moeten transformeren omdat we het model fitten met de lm
functie en de transformatie hebben gespecificeerd binnen die functie met behulp van het pipe commando!
brca %>% ggplot(
aes(
x = ESR1 %>% log2,
y = S100A8 %>% log2)
) +
geom_point() +
geom_smooth(method = "lm")

Predictie-intervallen
-We kunnen ook een voorspelling doen voor de locatie van een nieuwe waarneming die zou worden verzameld in een nieuw experiment voor een patiënt met een bepaalde waarde voor hun ESR1-expressie
Het is belangrijk op te merken dat dit experiment nog moet worden uitgevoerd. We willen dus de niet-waargenomen individuele expressiewaarde voor een nieuwe patiënt voorspellen.
Voor een nieuwe onafhankelijke waarneming Y∗ Y∗=g(x)+ϵ∗ met ϵ∗∼N(0,σ2) en ϵ∗ onafhankelijk van de waarnemingen in de steekproef Y1,…,Yn.
We voorspellen een nieuwe log-S100A8 voor een patiënt met een gekend log2-ESR1-expressieniveau x ˆy(x)=ˆβ0+ˆβ1×x
De geschatte gemiddelde uitkomst en voorspelling voor een nieuwe waarneming zijn gelijk.
Maar hun steekproef verdelingen zijn anders!
- Onzekerheid over de geschatte gemiddelde uitkomst ← onzekerheid over de geschatte modelparameters ˆβ0 en ˆβ1.
- Onzekerheid over nieuwe waarneming ← onzekerheid over geschat gemiddelde en extra onzekerheid omdat de nieuwe waarneming zal afwijken rond het gemiddelde!
SEˆY(x)=√ˆσ2+ˆσ2ˆg(x)=√MSE{1+1n+(x−ˉX)2n∑i=1(Xi−ˉX)2}.
ˆY(x)−YSEˆY(x)∼tn−2
- Merk op dat een predictie-interval (PI) een verbeterde versie is van een referentie-interval wanneer de modelparameters onbekend zijn: onzekerheid over modelparameters + t-verdeling.
p <- predict(
lm2,
newdata = data.frame(ESR1 = grid),
interval="prediction")
head(p)
fit lwr upr
1 11.89028 9.510524 14.27004
2 11.87370 9.495354 14.25205
3 11.85724 9.480288 14.23419
4 11.84089 9.465324 14.21646
5 11.82466 9.450461 14.19886
6 11.80854 9.435698 14.18138
preddata<-data.frame(
grid = grid%>%log2,
p)
brca %>% ggplot(aes(x=ESR1%>%log2,y=S100A8%>%log2)) +
geom_point() +
geom_smooth(method="lm") +
geom_line(aes(x=grid,y=lwr),preddata,color="blue") +
geom_line(aes(x=grid,y=upr),preddata,color="blue")

preddata<-data.frame(cbind(grid,2^p))
brca %>% ggplot(aes(x = ESR1, y = S100A8)) +
geom_point() +
geom_line(
aes(x = grid,y = fit),
newdata) +
geom_line(
aes(x = grid, y = lwr),
newdata,
color = "grey") +
geom_line(
aes(x = grid, y = upr),
newdata,
color = "grey") +
geom_line(
aes(x = grid, y = lwr),
preddata,
color = "blue") +
geom_line(
aes(x = grid,y = upr),
preddata,
color = "blue")

NHANES voorbeeld
library(NHANES)
fem <- NHANES %>%
filter(Gender=="female"&!is.na(DirectChol))
2^(
fem %>%
pull(DirectChol) %>%
log2 %>%
mean +
c(-1,1) *
qnorm(0.975) *
(fem %>%
pull(DirectChol) %>%
log2 %>%
sd)
)
[1] 0.8361311 2.4397130
lmChol <- lm(DirectChol %>% log2 ~ 1, data=fem)
predInt <- predict(
lmChol,
interval="prediction",
newdata=data.frame(noPred=1)
)
round(2^predInt,2)
fit lwr upr
1 1.43 0.84 2.44
Merk op dat het voorspellingsinterval bijna gelijk is aan het referentie-interval voor de grote steekproef. We konden de parameters inderdaad heel precies schatten.
We zullen hetzelfde doen voor een kleine steekproef van 10 patiënten.
set.seed(1)
fem10 <- NHANES %>%
filter(Gender=="female"&!is.na(DirectChol)) %>%
sample_n(size=10)
2^(
fem10 %>%
pull(DirectChol) %>%
log2 %>%
mean +
c(-1,1) *
qnorm(0.975) *
(fem10 %>%
pull(DirectChol) %>%
log2 %>%
sd)
)
[1] 0.8976012 2.2571645
Het referentie-interval is veel smaller dan in de grote steekproef.
lmChol10 <- lm(DirectChol %>% log2 ~ 1, data = fem10)
predInt10 <- predict(
lmChol10,
interval = "prediction",
newdata = data.frame(noPred=1)
)
round(2^predInt10, 2)
fit lwr upr
1 1.42 0.81 2.49
Merk op dat het PI nu onzekerheid meeneemt in parameterschatters (gemiddelde en standaard error). En dat het interval veel breder wordt! Dit is hier vooral belangrijk voor de bovengrens omdat we de gegevens terug hebben getransformeerd!
Het interval is bijna net zo breed als dat gebaseerd op de grote steekproef.
Bij kleine steekproeven is het erg belangrijk om met deze extra onzekerheid rekening te houden.
Kwadratensommen en Anova-tabel
Totale kwadratensom
SSTot=n∑i=1(Yi−ˉY)2.
SStot kan worden gebruikt om de variantie van de marginale verdeling van de respons te schatten.
In dit hoofdstuk hebben we ons gefocused op de conditionele verdeling f(Y|X=x).
We weten dat MSE een goede schatting is van de variantie van de conditionele verdeling van Y|X=x.

Kwadratensom van de regressie SSR
SSR=n∑i=1(ˆYi−ˉY)2=n∑i=1(ˆg(xi)−ˉY)2.
Maat voor de afwijking tussen de predicties op de geschatte regressierechte en het steekproefgemiddelde van de uitkomsten.
Een andere interpretatie: verschil tussen twee modellen
- Geschatte model ˆg(x)=ˆβ0+ˆβ1x
- Geschatte model zonder predictor (enkel intercept): g(x)=β0 → β0 zal gelijk zijn aan ˉY.
SSR meet de grootte van het effect van de predictor

Kwadratensom van de fouten
SSE=n∑i=1(Yi−ˆYi)2=n∑i=1{Yi−ˆg(xi)}2.

We kunnen aantonen dat SST kan worden ontbonden in SSTot=n∑i=1(Yi−ˉY)2=n∑i=1(Yi−ˆYi+ˆYi−ˉY)2=n∑i=1(Yi−ˆYi)2+n∑i=1(ˆYi−ˉY)2=SSE +SSR
- De totale variabiliteit in de gegevens (SSTot) wordt gedeeltelijk verklaard door het regressieverband (SSR).
- Variabiliteit die we niet kunnen verklaren met het regressiemodel is de residuele variabiliteit (SSE).
Determinatie-coëfficiënt
R2=1−SSESSTot=SSRSSTot.
Fractie van de totale variabiliteit in de steekproef-uitkomsten die verklaard wordt door het geschatte regressieverband.
Grote R2 indicatie dat model potentieel tot goede predicties kan leiden (kleine SSE)
Slechts in beperkte mate indicatief voor de p-waarde van de test H0:β1=0 vs H1:β1≠0.
- p-waarde sterk beïnvloed door SSE en steekproefgrootte n, maar niet door SSTot
- De determinatiecoëfficiënt R2 wordt door SSE en SSTot bepaald, maar niet door de steekproefgrootte n.
Model met lage R2 blijft wel nuttig om associatie te bestuderen, zolang het de associatie correct modelleert!
Borstkanker voorbeeld
Call:
lm(formula = S100A8 %>% log2 ~ ESR1 %>% log2, data = brca)
Residuals:
Min 1Q Median 3Q Max
-1.94279 -0.66537 0.08124 0.68468 1.92714
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 23.401 1.603 14.60 3.57e-15 ***
ESR1 %>% log2 -1.615 0.150 -10.76 8.07e-12 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 1.026 on 30 degrees of freedom
Multiple R-squared: 0.7942, Adjusted R-squared: 0.7874
F-statistic: 115.8 on 1 and 30 DF, p-value: 8.07e-12
F-Testen in het enkelvoudig lineair regressiemodel
- Kwadratensommen zijn basis voor F-tests F=MSRMSE
met MSR=SSR1 and MSE=SSEn−2.
MSR wordt de gemiddelde kwadratensom van de regressie genoemd.
noemers 1 en n−2 zijn de vrijheidsgraden van SSR en SSE.
onder H0:β1=0 volgt de teststatistiek H0:F=MSRMSE∼F1,n−2,
F-test is altijd twee-zijdig! H1:β1≠0 p=P0[F≥f]=1−FF(f;1,n−2)
Call:
lm(formula = S100A8 %>% log2 ~ ESR1 %>% log2, data = brca)
Residuals:
Min 1Q Median 3Q Max
-1.94279 -0.66537 0.08124 0.68468 1.92714
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 23.401 1.603 14.60 3.57e-15 ***
ESR1 %>% log2 -1.615 0.150 -10.76 8.07e-12 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 1.026 on 30 degrees of freedom
Multiple R-squared: 0.7942, Adjusted R-squared: 0.7874
F-statistic: 115.8 on 1 and 30 DF, p-value: 8.07e-12

Anova Tabel
Regressie |
vrijheidsgraden SSR |
SSR |
MSR |
f-statistiek |
p-waarde |
Error |
vrijheidsgraden SSE |
SSE |
MSE |
|
|
Analysis of Variance Table
Response: S100A8 %>% log2
Df Sum Sq Mean Sq F value Pr(>F)
ESR1 %>% log2 1 121.814 121.814 115.8 8.07e-12 ***
Residuals 30 31.559 1.052
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Dummy variabelen
Lineaire regressiemodel voor het vergelijken van twee gemiddelden.
Borstkanker: verschil is in gemiddelde leeftijd van de patiënten met onaangetaste lymfeknopen en patiënten waarvan lymfeknopen werden verwijderd.
Hiervoor definiëren we eerst een dummy variabele xi={1aangetaste lymfeknopen0onaangetaste lymfeknopen
groep met xi=0 wordt de referentiegroep genoemd.
Het regressiemodel blijft ongewijzigd, Yi=β0+β1xi+ϵi met ϵi iid N(0,σ2)
Gezien xi slechts twee waarden kan aannemen, is het eenvoudig om het regressiemodel voor beide waarden van xi afzonderlijk te bekijken: Yi=β0+ϵionaangetaste lymfeknopen(xi=0)Yi=β0+β1+ϵi aangetaste lymfeknopen(xi=1).
Dus E[Yi∣xi=0]=β0E[Yi∣xi=1]=β0+β1,
waaruit direct de interpretatie van β1 volgt: β1=E[Yi∣xi=1]−E[Yi∣xi=0]
β1 is dus het gemiddelde verschil in leeftijd tussen patiënten met aangetaste lymfeknopen en patiënten met onaangetaste lymfeknopen (referentiegroep).
Met de notatie μ0=E[Yi∣xi=0] en μ1=E[Yi∣xi=1] wordt dit β1=μ1−μ0.
Er kan aangetoond worden dat ˆβ0=ˉY1 (steekproefgemiddelde in referentiegroep)ˆβ1=ˉY2−ˉY1(schatter van effectgrootte)MSE=S2p.
De testen voor H0:β1=0 vs. H1:β1≠0 kunnen gebruikt worden voor het testen van de nulhypothese van de two-sample t-test, H0:μ1=μ2 t.o.v. H1:μ1≠μ2.
brca$node <- as.factor(brca$node)
t.test(age~node,brca,var.equal=TRUE)
Two Sample t-test
data: age by node
t = -2.7988, df = 30, p-value = 0.008879
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-15.791307 -2.467802
sample estimates:
mean in group 0 mean in group 1
59.94737 69.07692
lm3 <- lm(age~node, brca)
summary(lm3)
Call:
lm(formula = age ~ node, data = brca)
Residuals:
Min 1Q Median 3Q Max
-19.9474 -5.3269 0.0526 5.3026 18.0526
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 59.947 2.079 28.834 < 2e-16 ***
node1 9.130 3.262 2.799 0.00888 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 9.063 on 30 degrees of freedom
Multiple R-squared: 0.207, Adjusted R-squared: 0.1806
F-statistic: 7.833 on 1 and 30 DF, p-value: 0.008879




brca %>%
ggplot(
aes(
x = node %>%
as.factor,
y = age)
) +
geom_boxplot()

- Simulate 9 datasets with the same number of observations as the brca dataset from a normal distribution with the same standard deviation as in the original data. Store the data of all simulations in a data frame
- Plot the simulated data using the
ggplot
function
- Add a boxplot layer
- Use facet_wrap to make a separate plot for simulated dataset
- Change label of y-axis
set.seed(354)
sim_df <- data.frame(
node = rep(brca$node, 9),
iid = rnorm(9 * nrow(brca), sd = sigma(lm3)),
sim = rep(1:9, each = 32)
)
sim_df %>%
ggplot(aes(x = node, y=iid)) +
geom_boxplot() +
facet_wrap(.~sim) +
ylab(paste0("iid N(0,",round(sigma(lm3)^2,2),")"))

Observationele study
We kunnen echter niet besluiten dat oudere personen een hoger risico hebben op aantasting van de lymfeknopen ten gevolge van hun leeftijd.
Mogelijks confounding: geen randomisatie → groepen patiënten met aangetaste lymfeknopen en niet-aangetaste lymfeknopen kunnen nog in andere karateristieken van elkaar verschillen.
Enkel besluiten dat er een associatie is tussen de lymfeknoop status en de leeftijd.
Het is dus niet noodzakelijkerwijs een causaal verband!
Is ook zo voor lineair model voor de log2-S100A8-expressie.
Aangezien we de ESR1-expressie niet experimenteel vast hebben kunnen leggen, kunnen we niet besluiten dat een hogere ESR1-expressie de S100A8-expressie doet verlagen.
Enkel besluiten dat er een negatieve associatie is.
Om impact van gen te bestuderen op andere genen: knockout mutanten generenen in het labo
LS0tCnRpdGxlOiAiNi4gRW5rZWx2b3VkaWdlIGxpbmVhaXJlIHJlZ3Jlc3NpZSIgICAKYXV0aG9yOiAiTGlldmVuIENsZW1lbnQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCm91dHB1dDoKICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgICAgCiAgICAgIHRoZW1lOiBjb3NtbwogICAgICB0b2M6IHRydWUKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KFJtaXNjKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKIyBCcmVhc3QgY2FuY2VyIGRhdGFzZXQKCgotIHN1YnNldCB2YW4gc3R1ZGllIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDkzL2puY2kvZGpqMDUyCi0gMzIgYm9yc3RrYW5rZXIgcGF0acOrbnRlbiBtZXQgZWVuIGVzdHJvZ2VuIHJlY2VwdGVyIHBvc2l0aWV2ZSB0dW1vciBkaWUgdGFtb3hpZmVuIGNoZW1vdGhlcmFweSBiZWhhbmRlbGluZyBvbmRlcmdhYW4uIFZhcmlhYmVsZW46CgogICAgLSBncmFkZTogaGlzdG9sb2dpc2NoZSBncmFhZCB2YW4gdHVtb3IgKGdyYWFkIDEgdnMgMyksCiAgICAtIG5vZGU6IHN0YXR1cyB2YW4gZGUgbHltZmUga25vcGVuICgwOiBuaWV0IGFhbmdldGFzdCwgMTogYWFudGFzdGluZyBlbiB2ZXJ3aWpkZXJpbmcgdmFuIGRlIGx5bWZlIGtub3BlbiksCiAgICAtIHNpemU6IGdyb290dGUgdmFuIHR1bW9yIGluIGNtLAogICAgLSBFU1IxIGVuIFMxMDBBOCBnZW4gZXhwcmVzc2llIGluIHR1bW9yIGJpb3BzeSAodmlhIG1pY3JvYXJyYXkgdGVjaG5vbG9naWUpCgoKYGBge3J9CmJyY2EgPC0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3Mvc2JjMjAvbWFzdGVyL2RhdGEvYnJlYXN0Y2FuY2VyLmNzdiIpCmJyY2EKYGBgCgotIE9tIGRpZGFjdGlzY2hlIHJlZGVuZW4gdmVyd2lqZGVyZW4gd2UgZWVyc3QgMyBvdXRsaWVycyBpbiBkZSBTMTAwQTggZXhwcmVzc2llIGRhdGEuCi0gSW4gZGV6ZSBzdHVkaWUga2FuIGRpdCBlY2h0ZXIgbmlldCB3b3JkZW4gdmVyYW50d29vcmQKLSBMYXRlciBpbiBkZSBsZXNzZW4gbGF0ZW4gd2UgemllbiBob2UgamUgZ29lZCBtZXQgYWxsZSBkYXRhIG9tZ2FhdC4KCgpgYGB7ciBvdXQud2lkdGg9JzcwJScsIGZpZy5hbGlnbj0nY2VudGVyJyx3YXJuaW5ncz1GQUxTRX0KYnJjYSAlPiUKICBnZ3Bsb3QoYWVzKHg9IiIsIHk9UzEwMEE4KSkgKwogIGdlb21fYm94cGxvdCgpICsKICB4bGFiKCIiKSArCiAgeWxhYigiUzEwMEE4IGV4cHJlc3NpZSIpCmBgYAoKLS0tCgpgYGB7cn0KbGlicmFyeShHR2FsbHkpCmJyY2FTdWJzZXQgPC0gYnJjYSAlPiUKICBmaWx0ZXIoUzEwMEE4PDIwMDApCmJyY2FTdWJzZXRbLC0oMTo0KV0gJT4lIGdncGFpcnMoKQpgYGAKCiMjIEFzc29jaWF0aWUgdHVzc2VuIEVTUjEgZW4gUzEwMEE4IGV4cHJlc3NpZQoKLSBFU1IxIGluICRccG0kIDc1JSB2YW4gYm9yc3RrYW5rZXJ0dW1vcmVuLgoKICAgIC0gRXhwcmVzc2llIHZhbiBFUi1nZW4gcG9zaXRpZWYgdm9vciBiZWhhbmRlbGluZzogdHVtb3IgcmVhZ2VlcnQgb3AgaG9ybW9vbnRoZXJhcGllCiAgICAtIFRhbW94aWZlbiBpbnRlcmFnZWVydCBtZXQgRVIgZW4gbW9kdWxlZXJ0IGdlbmV4cHJlc3NpZS4KCi0gRWl3aXR0ZW4gdmFuIGRlIFMxMDAtZmFtaWxpZSB6aWpuIHZhYWsgZ2VkaXNyZWd1bGVlcmQgYmlqIGthbmtlcgoKLSBTMTAwQTggZXhwcmVzc2llIG9uZGVyZHJ1a3QgaW1tdXVuc3lzdGVlbSBpbiB0dW1vciBlbiBjcmXDq2VydCBpbmZsYW1hdG9pciBtaWxpZXUgZGllIGthbmtlcmdyb2VpIHByb21vb3QuCgotIEludGVyZXNzZSBpbiBhc3NvY2lhdGllIHR1c3NlbiBFU1IxIGVuIFMxMDBBOCBleHByZXNzaWUuCgoxLiBwaXBlIGRhdGFzZXQgbmFhciBnZ3Bsb3QKMi4gc2VsZWN0ZWVyIGRhdGEgYGdncGxvdChhZXMoeD1FU1IxLHk9UzEwMEE4KSlgCjMuIHZvZWcgcHVudGVuIHRvZSBtZXQgYGdlb21fcG9pbnQoKWAKNC4gdm9lZyBlZW4gInNtb290aCBsaW5lIiB0b2UgYGdlb21fc21vb3RoKClgCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcid9CmJyY2FTdWJzZXQgJT4lCiAgZ2dwbG90KGFlcyh4PUVTUjEseT1TMTAwQTgpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aCgpCmBgYAoKIyBMaW5lYWlyZSBSZWdyZXNzaWUKCi0gU3RhdGlzdGlzY2hlIG1ldGhvZGUgb20gcmVsYXRpZSB0dXNzZW4gMiByZWVrc2VuIG9ic2VydmF0aWVzICQoWF9pLCBZX2kpJCwgYmVrb21lbiB2b29yIG9uYWZoYW5rZWxpamtlIHN1YmplY3RlbiAkaSA9IDEsIC4uLiwgbiQsIHRlIGJlc2NocmlqdmVuLgoKLSBHZW4gZXhwcmVzc2llIHZvb3JiZWVsZAoKICAgIC0gUmVzcG9uc2UgWSA6IFMxMDBBOCBleHByZXNzaWUKICAgIC0gUHJlZGljdG9yIFg6IEVTUjEgZXhwcmVzc2llCgoxLiBwaXBlIGRhdGFzZXQgbmFhciBnZ3Bsb3QKMi4gc2VsZWN0ZWVyIGRhdGEgYGdncGxvdChhZXMoeD1FU1IxLHk9UzEwMEE4KSlgCjMuIHZvZWcgcHVudGVuIHRvZSBtZXQgYGdlb21fcG9pbnQoKWAKNC4gdm9lZyBlZW4gInNtb290aCBsaW5lIiB0b2UgYGdlb21fc21vb3RoKClgCjUuIHZvZWcgZWVuIHJlY2h0ZSB0b2UgYGdlb21fc21vb3RoKClgIG1ldCBgbWV0aG9kID0gImxtImAgKGxpbmVhciBtb2RlbCkuIChXZSB6ZXR0ZW4gYHNlID0gRkFMU0VgIG9tIGdlZW4gcHVudGdld2lqemUgYmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuIHdlZXIgdGUgZ2V2ZW4pCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcid9CmJyY2FTdWJzZXQgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRVNSMSx5ID0gUzEwMEE4KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSwgY29sID0gImdyZXkiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkKYGBgCgojIyBNb2RlbAoKLSBWb29yIHZhc3RlICRYJCwgaGVlZnQgJFkkIG5pZXQgbm9vZHpha2VsaWprZSBkZXplbGZkZSB3YWFyZGUKCiQkXHRleHR7b2JzZXJ2YXRpb24gPSBzaWduYWwgKyBub2lzZX0kJAoKJCRZX2k9ZyhYX2kpK1xlcHNpbG9uX2kkJAoKLSBXZSBkZWZpbmnDq3JlbiAkZyh4KSQgYWxzIGhldCB2ZXJ3YWNodGUgcmVzdWx0YWF0IHZvb3Igc3ViamVjdHMgbWV0ICRYX2k9eCQKCiQkRVtZX2l8WF9pPXhdPWcoeCkkJAoKRGFhcm9tIGlzICRcZXBzaWxvbl9pJCBnZW1pZGRlbGQgMCB2b29yIHN1YmplY3RzIG1ldCBkZXplbGZkZSAkWF9pJDoKJCRFW1xlcHNpbG9uX2l8WF9pXT0wJCQKCiMjIExpbmVhaXJlIHJlZ3Jlc3NpZQoKLSBPbSAqKmFjY3VyYXRlKiogZW4gKippbnRlcnByZXRlZXJiYXJlKiogcmVzdWx0YXRlbiB0ZSBiZWtvbWVuLCBraWVzdCBtZW4gJGcoeCkkIHZhYWsgYWxzIGVlbiBsaW5lYWlyZSBmdW5jdGllIG1ldCBvbmdla2VuZGUgcGFyYW1ldGVycy4KCiQkRShZfFg9eCk9XGJldGFfMCArIFxiZXRhXzEgeCQkCgpvbmJla2VuZCAgKippbnRlcmNlcHQqKiAkXGJldGFfMCQgZW4KKipoZWxsaW5nKiogJFxiZXRhXzEkLgoKLSBMaW5lYWlyIG1vZGVsIGxlZ3QgZWVuICphc3N1bXB0aWUqIG9wIGRlIHZlcmRlbGluZyB2YW4gJFgkIGVuICRZJCwgZGllIGluY29ycmVjdCBrYW4gemlqbi4KCi0gKkVmZmljacOrbnRlIGRhdGEtYW5hbHlzZSo6IGJlbnV0IGFsbGUgb2JzZXJ2YXRpZXMgb20gaWV0cyB0ZSBsZXJlbiBvdmVyIHZlcndhY2h0ZSB1aXRrb21zdCBiaWogJFg9eCQuCgoKIyMgR2VicnVpawoKLSAqUHJlZGljdGllKjogd2FubmVlciAkWSQgb25nZWtlbmQgaXMsIG1hYXIgJFgkIHdlbCwga3VubmVuIHdlICRZJCB2b29yc3BlbGxlbiBvcCBiYXNpcyB2YW4gJFgkClxbRShZfFg9eCk9XGJldGFfMCArIFxiZXRhXzEgeFxdCgotICpBc3NvY2lhdGllKjogYmlvbG9naXNjaGUgcmVsYXRpZSB0dXNzZW4gdmFyaWFiZWxlICRYJCBlbiBjb250aW51ZSBtZXRpbmcgJFkkIGJlc2NocmlqdmVuLgotICpJbnRlcmNlcHQ6KiAkRShZfFg9MCk9XGJldGFfMCQKCi0gKlNsb3BlKjoKXGJlZ2lue2VxbmFycmF5Kn0KRShZfFg9eCtcZGVsdGEpLUUoWXxYPXgpJj0mXGJldGFfMCArIFxiZXRhXzEgKHgrXGRlbHRhKSAtXGJldGFfMC1cYmV0YV8xIHhcXAomPSYgXGJldGFfMVxkZWx0YQpcZW5ke2VxbmFycmF5Kn0KCiRcYmV0YV8xOiQgdmVyc2NoaWwgaW4gZ2VtaWRkZWxkZSB1aXRrb21zdCB2b29yIHN1YmplY3RlbiBkaWUgdmVyc2NoaWxsZW4gaW4gw6nDqW4gZWVuaGVpZCB2YW4gZGUgcHJlZGljdG9yICRYJC4KCiMgUGFyYW1ldGVyc2NoYXR0aW5nCgotIC0gS2xlaW5zdGUga3dhZHJhdGVuIHRlY2huaWVrCihMZWFzdCBzcXVhcmVzKQoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInfQpicmNhU3Vic2V0ICU+JQogIGdncGxvdChhZXMoeCA9IEVTUjEsIHkgPSBTMTAwQTgpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBjb2wgPSAiZ3JleSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKQpgYGAKCi0gUGFyYW1ldGVycyAkXGJldGFfMCQgZW4gJFxiZXRhXzEkIHppam4gb25nZWtlbmQKCi0gUGFyYW1ldGVycyBzY2hhdHRlbiBvcCBiYXNpcyB2YW4gYmVwZXJrdGUgc3RlZWtwcm9lZgoKLSBCZXN0IHBhc3NlbmRlIGxpam4KCiAgICAtIFB1bnQgb3AgcmVncmVzc2llbGlqbiB2b29yIGVlbiBnZWdldmVuICR4X2kkOiAkKHhfaSwgXGJldGFfMCArIFxiZXRhXzEgeF9pKSQgIHpvIGRpY2h0IG1vZ2VsaWprIGJpaiAkKHhfaSwgeV9pKSQKICAgIC0gS2llcyAkXGJldGFfMCQgZW4gJFxiZXRhXzEkIHpvZGF0IGRlIHNvbSB0dXNzZW4gdm9vcnNwZWxkZSBlbiB3YWFyZ2Vub21lbiBwdW50ZW4gem8ga2xlaW4gbW9nZWxpamsgd29yZHQuCgokJFNTRT1cc3VtX3tpPTF9Xm4gKHlfaS1cYmV0YV8wLVxiZXRhXzEgeF9pKV4yPVxzdW1fe2k9MX1ebiBlX2leMiQkCgotIE1ldCAkZV9pJCBkZSByZXNpZHVlbjogZGUgdmVydGljYWxlIGFmc3RhbmRlbiB2YW4gZGUgb2JzZXJ2YXRpZXMgdG90IGRlIGdlZml0dGUgcmVncmVzc2llcmVjaHRlCgojIyBTY2hhdHRlcnMgZGllIFNTRSBtaW5pbWFsaXNlcmVuCgokJFxoYXR7XGJldGFfMX09IFxmcmFje1xzdW1cbGltaXRzX3tpPTF9Xm4gKHlfaS1cYmFyIHkpKHhfaS1cYmFyIHgpfXtcc3VtXGxpbWl0c197aT0xfV5uICh4X2ktXGJhciB4X2kpXjJ9PVxmcmFje1xtYm94e2Nvcn0oeCx5KXNfeX17c194fSAkJAoKJCRcaGF0e1xiZXRhXzB9PVxiYXIgeSAtIFxoYXR7XGJldGF9XzEgXGJhciB4ICQkCgotIE1lcmsgb3AgZGF0IGRlIGhlbGxpbmcgdmFuIGRlIGtsZWluc3RlIGt3YWRyYXRlbmxpam4gZXZlbnJlZGlnIGlzIG1ldCBkZSBjb3JyZWxhdGllIHR1c3NlbiBkZSB1aXRrb21zdCBlbiBkZSB2ZXJrbGFyZW5kZSB2YXJpYWJlbGUuCgpHZXNjaGF0dGUgbGluZWFpcmUgcmVncmVzc2llbW9kZWwgbGFhdCB0b2Ugb206CgotIHZlcndhY2h0ZSB1aXRrb21zdCB0ZSB2b29yc3BlbGxlbiB2b29yIHN1YmplY3RlbiBtZXQgZWVuIGdlZ2V2ZW4gd2FhcmRlICR4JCB2b29yIGRlIHByZWRpY3RvcjoKJCRcdGV4dHtFfSBbIFkgfCBYID0geF09XGhhdHtcYmV0YX1fMCtcaGF0e1xiZXRhfV8xeCQkCgotIG5hIHRlIGdhYW4gaG9ldmVlbCB1aXRrb21zdCBnZW1pZGRlbGQgdmVyc2NoaWx0IHR1c3NlbiAyIGdyb2VwZW4gc3ViamVjdGVuIG1ldCBlZW4gdmVyc2NoaWwgdmFuICRcZGVsdGEkIGVlbmhlZGVuIGluIGRlIHZlcmtsYXJlbmRlIHZhcmlhYmVsZToKCiQkXHRleHR7RX1cbGVmdFtZfFg9eCtcZGVsdGFccmlnaHRdLVx0ZXh0e0V9XGxlZnRbWXxYPXhccmlnaHRdPSBcaGF0e1xiZXRhfV8xXGRlbHRhJCQKCiMjIyBCb3JzdGthbmtlciB2b29yYmVlbGQKCmBgYHtyfQpsbTEgPC0gbG0oUzEwMEE4IH4gRVNSMSwgYnJjYVN1YnNldCkKc3VtbWFyeShsbTEpCmBgYAoKXFtFKFl8WD14KT1gciByb3VuZChsbTEkY29lZlsxXSwyKWAtYHIgYWJzKHJvdW5kKGxtMSRjb2VmWzJdLDMpKWAgeFxdCgotIERlIHZlcndhY2h0ZSBTMTAwQTgtZXhwcmVzc2llIGlzIGdlbWlkZGVsZCAgYHIgYWJzKHJvdW5kKGxtMSRjb2VmWzJdLDMpKjEwMDApYCBlZW5oZWRlbiBsYWdlciB2b29yIHBhdGnDq250ZW4gbWV0IGVlbiBFU1IxLWV4cHJlc3NpZW5pdmVhdSBkaWUgMTAwMCBlZW5oZWRlbiBob2dlciBsaWd0LgoKLSBWZXJ3YWNodGUgUzEwMEE4IGV4cHJlc3NpZW5pdmVhdSB2b29yIHBhdGnDq250ZW4gbWV0IGVlbiBFU1IxIGV4cHJlc3NpZW5pdmVhdSB2YW4gMjAwMDogIApcW2ByIHJvdW5kKGxtMSRjb2VmWzFdLDIpYC1gciBhYnMocm91bmQobG0xJGNvZWZbMl0sMykpYFx0aW1lcyAyMDAwPWByIHJvdW5kKGxtMSRjb2VmWzFdK2xtMSRjb2VmWzJdKjIwMDAsMilgXF0KCi0gVmVyd2FjaHRlIFMxMDBBOCBleHByZXNzaWVuaXZlYXUgdm9vciBwYXRpw6tudGVuIG1ldCBlZW4gRVNSMSBleHByZXNzaWVuaXZlYXUgdmFuIDQwMDA6ICAKXFtgciByb3VuZChsbTEkY29lZlsxXSwyKWAtYHIgYWJzKHJvdW5kKGxtMSRjb2VmWzJdLDMpKWBcdGltZXMgNDAwMD1gciByb3VuZChsbTEkY29lZlsxXStsbTEkY29lZlsyXSo0MDAwLDIpYFxdCi0gKipMZXQgb3Agdm9vciBleHRyYXBvbGF0aWUhKiogKFZlcm9uZGVyc3RlbGxpbmcgdmFuIGxpbmVhcml0ZWl0IGthbiBtZW4gZW5rZWwgbmFnYWFuIGJpbm5lbiBoZXQgYmVyZWlrIHZhbiBkZSBkYXRhKS4KCiMgU3RhdGlzdGlzY2hlIGJlc2x1aXR2b3JtaW5nIChzdGF0aXN0aXNjaGUgaW5mZXJlbnRpZSkKCk9tIGJlc2x1aXRlbiB0ZSBrdW5uZW4gdHJla2tlbiBvdmVyIGxpbmVhaXJlIHJlZ3Jlc3NpZW1vZGVsClxbRShZfFgpPVxiZXRhXzArXGJldGFfMSBYXF0KCm1vZXRlbiB3ZSB3ZXRlbjoKCi0gSG9lIGRlIGxlYXN0IHNxdWFyZXMgcGFyYW1ldGVyIHNjaGF0dGVycyB2YXJpw6tyZW4gdmFuIHN0ZWVrcHJvZWYgdG90IHN0ZWVrcHJvZWYsIGVuCi0gRW4gaG9lIGlzIGRpdCBvbmRlciBkZSBudWxoeXBvdGhlc2UgZGF0IGVyIGdlZW4gYXNzb2NpYXRpZSBpcyB0dXNzZW4gcHJlZGljdG9yIGVuIHJlc3BvbnNlCgotIE5vb2R6YWFrIGFhbiBzdGF0aXN0aXNjaCBtb2RlbCEKCi0gTW9kZWxsZWVyIGRlIHZlcmRlbGluZyB2YW4gJFkkIGdlZ2V2ZW4gJFgkIGV4cGxpY2lldDogJGZfe1l8WH0oeSkkCgojIyBNb2RlbGxlZXIgdmVyZGVsaW5nIHZhbiBZPwoKMS4gTmFhc3QgKmxpbmVhcml0ZWl0KiBoZWJiZW4gd2Ugbm9nIGFhbm5hbWVzIG5vZGlnIQoyLiAqT25hZmhhbmtlbGlqa2hlaWQqOiB3YWFybmVtaW5nZW4gJChYXzEsWV8xKSwgLi4uLCAgKFhfbixZX24pJCB6aWpuIGdlbWFha3Qgdm9vciBuIG9uYWZoYW5rZWxpamtlIHN1YmplY3RlbiAoSXMgdmVyZWlzdCBvbSBkZSB2YXJpYW50aWUgdGUgc2NoYXR0ZW4pCjMuICpIb21vc2NlZGFzdGljaXRlaXQgKiBvZiAqZ2VsaWprZSB2YXJpYW50aWVzKjogd2Fhcm5lbWluZ2VuIHZhcmnDq3JlbiBtZXQgZ2VsaWprIGdlbWlkZGVsZGUgcm9uZCBkZSByZWdyZXNzaWVsaWpuLgogICAgLSBSZXNpZHVlbiAkXGVwc2lsb25faSQgaGViYmVuIGdlbGlqa2UgdmFyaWFudGllIHZvb3IgZWxrZSAkWF9pPXgkCiAgICAtICRcdGV4dHt2YXJ9KFlcdmVydCBYPXgpID0gXHNpZ21hXjIkIHZvb3IgZWxrZSAkWD14JAogICAgLSAkXHNpZ21hJCB3b3JkdCBkZSAqcmVzaWR1ZWxlIHN0YW5kYWFyZGRldmlhdGllKiBnZW5vZW1kLgo0LiAqTm9ybWFsaXRlaXQqOiBkZSByZXNpZHVlbiAkXGVwc2lsb25faSQgemlqbiBub3JtYWFsIHZlcmRlZWxkCgohW10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRvbWljcy9zYmMyMC9tYXN0ZXIvZmlndXJlcy9SZWdNb2RlbDMucG5nKXt3aWR0aD0xMDAlfQoKCi0gVWl0IDIsIDMgZW4gNCB2b2xndCBkYXQKJCRcZXBzaWxvbl9pIFx0ZXh0eyBpLmkuZC59IE4oMCxcc2lnbWFeMikuJCQKLSBBbHMgd2Ugb29rIHN0ZXVuZW4gb3AgZWVyc3RlIHZlcm9uZGVyc3RlbGxpbmcgdmFuIGxpbmVhcml0ZWl0OgokJFlfaVx2ZXJ0IFhfaVxzaW0gTihcYmV0YV8wK1xiZXRhXzEgWF9pLFxzaWdtYV4yKSwkJAoKLSBWZXJkZXIga2FuIG1lbiBhYW50b25lbiBkYXQgb25kZXIgZGV6ZSBhYW5uYW1lcwokJFxzaWdtYV4yX3tcaGF0e1xiZXRhfV8wfT1cZnJhY3tcc3VtXGxpbWl0c197aT0xfV5uIFheMl9pfXtcc3VtXGxpbWl0c197aT0xfV5uIChYX2ktXGJhciBYKV4yfSBcdGltZXNcZnJhY3tcc2lnbWFeMn17bn0gXHRleHR7IGVuIH0gXHNpZ21hXjJfe1xoYXR7XGJldGF9XzF9PVxmcmFje1xzaWdtYV4yfXtcc3VtXGxpbWl0c197aT0xfV5uIChYX2ktXGJhciBYKV4yfSQkCi0gZW4gZGF0IGRlIHBhcmFtZXRlcnNjaGF0dGVycyBldmVuZWVucyBub3JtYWFsIHZlcmRlZWxkIHppam4KJCRcaGF0XGJldGFfMCBcc2ltIE5cbGVmdChcYmV0YV8wLFxzaWdtYV4yX3tcaGF0IFxiZXRhXzB9XHJpZ2h0KSBcdGV4dHsgZW4gfSBcaGF0XGJldGFfMSBcc2ltIE5cbGVmdChcYmV0YV8xLFxzaWdtYV4yX3tcaGF0IFxiZXRhXzF9XHJpZ2h0KSQkCgojIyBIb2dlIHNwcmVpZGluZyBvcCAkWCQgdmVyYmV0ZXJ0IGRlIHByZWNpc2llCgokJFxzaWdtYV4yX3tcaGF0e1xiZXRhfV8xfT1cZnJhY3tcc2lnbWFeMn17XHN1bVxsaW1pdHNfe2k9MX1ebiAoWF9pLVxiYXIgWCleMn0kJAoKIVtdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0b21pY3Mvc2JjMjAvbWFzdGVyL2ZpZ3VyZXMvc3ByZWFkLnBuZyl7IHdpZHRoPTEwMCUgfQoKLSBDb25kaXRpb25lbGUgdmFyaWFudGllICgkXHNpZ21hXjIkKSBpcyBuaWV0IGdla2VuZAotIFNjaGF0dGVuIGQubS52LiBnZW1pZGRlbGRlIHZhbiBkaWUga3dhZHJhdGlzY2hlIGFmd2lqa2luZ2VuIHJvbmQgZGUgcmVncmVzc2llcmVjaHRlCi0gKm1lYW4gc3F1YXJlZCBlcnJvciogKE1TRSkKCiQkXGhhdFxzaWdtYV4yPU1TRT1cZnJhY3tcc3VtXGxpbWl0c197aT0xfV5uIFxsZWZ0KHlfaS1caGF0XGJldGFfMC1caGF0XGJldGFfMVx0aW1lcyB4X2lccmlnaHQpXjJ9e24tMn09XGZyYWN7XHN1bVxsaW1pdHNfe2k9MX1ebiBlXjJfaX17bi0yfS4kJAotIFZvb3IgaGV0IGJla29tZW4gdmFuIGRlemUgc2NoYXR0ZXIgc3RldW5lbiB3ZSBvcCBvbmFmaGFua2VsaWpraGVpZCAoYWFubmFtZSAyKSBlbiBob21vc2NlZGFzdGljaXRlaXQgKGFhbm5hbWUgMykuCi0gZGVlbCBkb29yICRuLTIkCgpOYSBzY2hhdHRpbmcgdmFuICRcc2lnbWFeMiQgYmVrb21lbiB3ZSB2b2xnZW5kZSBzdGFuZGFhcmQgZXJyb3JzOgoKJCRcdGV4dHtTRX1fe1xoYXR7XGJldGF9XzB9PVxoYXRcc2lnbWFfe1xoYXR7XGJldGF9XzB9PVxzcXJ0e1xmcmFje1xzdW1cbGltaXRzX3tpPTF9Xm4gWF4yX2l9e1xzdW1cbGltaXRzX3tpPTF9Xm4gKFhfaS1cYmFyIFgpXjJ9IFx0aW1lc1xmcmFje1x0ZXh0e01TRX19e259fSBcdGV4dHsgZW4gfSBcdGV4dHtTRX1fe1xoYXR7XGJldGF9XzF9PVxoYXRcc2lnbWFfe1xoYXR7XGJldGF9XzF9PVxzcXJ0e1xmcmFje1x0ZXh0e01TRX19e1xzdW1cbGltaXRzX3tpPTF9Xm4gKFhfaS1cYmFyIFgpXjJ9fSQkCgotIE9wbmlldXcgdG9ldHNlbiBlbiBiZXRyb3V3YmFhcmhlaWRzaW50ZXJ2YWxsZW4gby5iLnYuCiQkVD1cZnJhY3tcaGF0e1xiZXRhfV9rLVxiZXRhX2t9e1NFKFxoYXR7XGJldGF9X2spfSBcdGV4dHsgd2l0aCB9IGs9MSwyLiQkCgotIEFscyBhYW4gYWxsZSBhYW5uYW1lcyBpcyB2b2xkYWFuIHZvbGd0ICRUJCBlZW4gdC12ZXJkZWxpbmcgbWV0IG4tMiB2cmlqaGVpZHNncmFkZW4uCgotIEFscyBnZWVuIG5vcm1hbGl0ZWl0IG1hYXIgd2VsIG9uYWZoYW5rZWxpamssIGxpbmVhcml0ZWl0IGVuIGhvbW9zY2VkYXN0aWNpdGVpdCBlbiBncm90ZSBkYXRhc2V0ClxbXHJpZ2h0YXJyb3cgXHRleHR7Q2VudHJhbGUgTGltaWV0c3RlbGxpbmd9XF0KCgojIyMgQm9yc3RrYW5rZXIgdm9vcmJlZWxkCgotIE5lZ2F0aWV2ZSBhc3NvY2lhdGllIHR1c3NlbiBTMTAwQTggZW4gRVNSMSBnZW4gZXhwcmVzc2llLgoKLSBWZXJhbGdlbWVlbiBlZmZlY3QgaW4gc3RlZWtwcm9lZiBuYWFyIHBvcHVsYXRpZSBtZXQgYmVodWxwIHZhbiBoZXQgYmV0cm91d2JhYXJoZWlkc2ludGVydmFsIG9wIGRlIGhlbGxpbmc6CiQkW1xoYXRcYmV0YV8xIC0gdF97bi0yLFxhbHBoYS8yfSBcdGV4dHtTRX1fe1xoYXRcYmV0YV8xfSxcaGF0XGJldGFfMSArIHRfe24tMixcYWxwaGEvMn0gXHRleHR7U0V9X3tcaGF0XGJldGFfMX1dJCQuCgpgYGB7cn0KY29uZmludChsbTEpCmBgYAoKLSBOZWdhdGllZiB2ZXJiYW5kIGlzIHNpZ25pZmljYW50IG9wIGhldCA1JSBzaWduaWZpY2FudGllbml2ZWF1LgoKCiMjIEh5cG90aGVzZSB0ZXN0CgotIFZlcnRhYWwgZGUgb25kZXJ6b2Vrc3ZyYWFnICJJcyBlciBlZW4gYXNzb2NpYXRpZSB0dXNzZW4gZGUgUzEwMEE4LSBlbiBFU1IxLWdlbmV4cHJlc3NpZT8iIG5hYXIgZGUgcGFyYW1ldGVycyBpbiBoZXQgbW9kZWwuCi0gT25kZXIgbnVsaHlwb3RoZXNlIGdlZW4gYXNzb2NpYXRpZSB0dXNzZW4gZXhwcmVzc2llIHZhbiBiZWlkZSBnZW5lbjoKJCRIXzA6IFxiZXRhXzE9MCQkCgotIE9uZGVyIGFsdGVybmF0aWV2ZSBoeXBvdGhlc2UgaXMgZXIgZWVuIGFzc29jaWF0aWUgdHVzc2VuIGJlaWRlIGdlbmVuOgokJEhfMTogXGJldGFfMVxuZXEwJCQKCi0gVGVzdCBzdGF0aXN0aWVrCiQkVD1cZnJhY3tcaGF0e1xiZXRhfV8xLTB9e1NFKFxoYXR7XGJldGF9X2spfSQkCgotIE9uZGVyICRIXzAkIHZvbGd0IGRlIHN0YXRpc3RpZWsgZWVuIHQtdmVyZGVsaW5nIG1ldCBuLTIgdnJpamhlaWRzZ3JhZGVuLgoKIyMjIEJyY2EgZGF0YXNldAoKYGBge3J9CnN1bW1hcnkobG0xKQpgYGAKCgotIEFzc29jaWF0aWUgdHVzc2VuIGRlIFMxMDBBOCBlbiBFU1IxIGdlbmV4cHJlc3NpZSBleHRyZWVtIHNpZ25pZmljYW50IGlzIChwPDwwLjAwMSkuCi0gTWFhciBlZXJzdCBtb2V0ZW4gd2UgYWxsZSBhc3N1bXB0aWVzIGNvbnRyb2xlcmVuIQotIEFuZGVycyBrdW5uZW4gZGUgY29uY2x1c2llcyBvLmIudi4gZGUgc3RhdGlzdGlzY2hlIHRlc3QgZW4gaGV0IEJJIG9uanVpc3Qgemlqbi4gIAoKIyBOYWdhYW4gdmFuIG1vZGVsdmVyb25kZXJzdGVsbGluZ2VuCgotIE9uYWZoYW5rZWxpamtoZWlkOiBkZXNpZ24KLSBMaW5lYXJpdGVpdDogYmVzbHVpdHZvcm1pbmcgZ2VlbiB6aW4gYWxzIG1vZGVsIG5pZXQgbGluZWFpciBpcwotIEhvbW9zY2VkYXN0aWNpdGVpdDogYmVzbHVpdHZvcm1pbmcvcC13YWFyZGUgaXMgbmlldCBiZXRyb3V3YmFhciBhbHMgZGUgZGF0YSBuaWV0IGhvbW9zY2VkYXN0aXNjaCB6aWpuCi0gTm9ybWFsaXRlaXQ6IGJlc2x1aXR2b3JtaW5nL3Atd2FhcmRlIGlzIG5pZXQgYmV0cm91d2JhYXIgYWxzIGRlIGRhdGEgbmlldCBub3JtYWFsIHZlcmRlZWxkIHppam4gaW4ga2xlaW5lIHN0ZWVrcHJvZXZlbgoKCiMjIExpbmVhcml0ZWl0CgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcid9CmJyY2FTdWJzZXQgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRVNSMSwgeSA9IFMxMDBBOCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKHNlID0gRkFMU0UsIGNvbCA9ICJncmV5IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpCmBgYAoKCiMjIFJlc2lkdXBsb3RzCgotIEFmd2lqa2luZ2VuIHZhbiBsaW5lYXJpdGVpdCBlY2h0ZXIgbWFra2VsaWprZXIgb3BnZXNwb29yZCBkLm0udi4gZWVuICpyZXNpZHVwbG90Ki4gKFpla2VyIGFscyBlciBsYXRlciBtZWVyIHZhcmlhYmVsZW4gemlqbiBpbiBoZXQgbGluZWFpcmUgbW9kZWwpCgotIHZlcmtsYXJlbmRlIHZhcmlhYmVsZSBvZiBwcmVkaWN0aWVzICRcaGF0XGJldGFfMCtcaGF0XGJldGFfMSB4JCBvcCBkZSAkWCQtYXMKCi0gZGUgKnJlc2lkdWVuKiBvcCBkZSAkWSQtYXMKJCRlX2k9eV9pLVxoYXR7Z30oeF9pKT15X2ktXGhhdFxiZXRhXzAtXGhhdFxiZXRhXzFcdGltZXMgeF9pLCQkCgpgYGB7cn0KcGxvdChsbTEpCmBgYAoKIyMgSG9tb3NjZWRhc3RpY2l0ZWl0IChnZWxpamtoZWlkIHZhbiB2YXJpYW50aWUpCgotIFJlc2lkdWVuIGVuIGt3YWRyYXRpc2NoZSByZXNpZHXigJlzIGRyYWdlbiBpbmZvcm1hdGllIG92ZXIgcmVzaWR1ZWxlIHZhcmlhYmlsaXRlaXQuCgotIEFzc29jaWF0aWUgbWV0IGRlIHZlcmtsYXJlbmRlIHZhcmlhYmVsZW4gJFxyaWdodGFycm93JCBpbmRpY2F0aWUgdmFuIGhldGVyb3NjZWRhc3RpY2l0ZWl0LgoKLSBTY2F0dGVycGxvdCB2YW4gb2YgJGVfaSQgdmVyc3VzICR4X2kkIG9mIHByZWRpY3RpZXMgJFxoYXQgXGJldGFfMCsgXGhhdCBcYmV0YV8xIHhfaSQuCgotIFNjYXR0ZXJwbG90IHZhbiBnZXN0YW5kYXJkaXNlZXJkIHJlc2lkdSB2ZXJzdXMgJHhfaSQgb2YgcHJlZGljdGllcy4KCgojIyBOb3JtYWxpdGVpdAoKLSBJbmRpZW4gdm9sZG9lbmRlIGdlZ2V2ZW5zLCBzY2hhdHRlcnMgbm9ybWFhbCB2ZXJkZWVsZCB6ZWxmcyB3YW5uZWVyIG9ic2VydmF0aWVzIG5pZXQgTm9ybWFhbCB2ZXJkZWVsZCB6aWpuOiBjZW50cmFsZSBsaW1pZXQgc3RlbGxpbmcKCi0gV2F0IOKAmHZvbGRvZW5kZSBvYnNlcnZhdGllc+KAmSB6aWpuLCBoYW5ndCBhZiB2YW4gaG9lIGdvZWQgZGUgdmVyZGVsaW5nIG9wIGRlIE5vcm1hbGUgbGlqa3QuCgotIEFhbm5hbWUgaXMgZGF0IHVpdGtvbXN0ZW4gTm9ybWFhbCB2ZXJkZWVsZCB6aWpuIGJpaiB2YXN0ZSB3YWFyZGVuIHZhbiBkZSB2ZXJrbGFyZW5kZSB2YXJpYWJlbGVuLgokJFlfaVx2ZXJ0IFhfaVxzaW0gTihcYmV0YV8wK1xiZXRhXzFYX2ksXHNpZ21hXjIpJCQKCi0gUVEtcGxvdCB2YW4gcmVzcG9uc2UgWSBpcyBoZWVsIG1pc2xlaWRlbmQuCgotIFFRLXBsb3QgdmFuIGRlIHJlc2lkdWVuICRlX2kkCgpgYGB7ciBlY2hvPUZBTFNFfQpzZXQuc2VlZCA8LSAyMDAKcGFyKG1mcm93PWMoMSwzKSkKeCA8LSByZXAoMToxMCxlYWNoPTIwKQp5IDwtIHgrcm5vcm0obGVuZ3RoKHgpKQpib3hwbG90KHl+eCkKcXFub3JtKHksIG1haW49Ik9yaWdpbmFsIG9ic2VydmF0aW9ucyIpCnFxbGluZSh5KQpsbUggPC0gbG0oeX54KQpwbG90KGxtSCwgd2hpY2g9MiwgbWFpbj0iUmVzaWR1YWxzIikKYGBgCgoKYGBge3J9CnBsb3QobG0xLCB3aGljaD0yKQpgYGAKCgojIEFmd2lqa2luZ2VuIHZhbiBNb2RlbHZlcm9uZGVyc3RlbGxpbmdlbgoKLSBUcmFuc2Zvcm1hdGllIHZhbiBvbmFmaGFua2VsaWprZSB2ZXJhbmRlcmxpamtlIHdpanppZ3QgZGUgdmVyZGVsaW5nIHZhbiBZIGJpaiBnZWdldmVuIFggbmlldDoKCiAgICAtIGhlbHB0IG5pZXQgb20gbm9ybWFsaXRlaXQgb2YgaG9tb3NjZWRhc3RpY2l0ZWl0IHRlIGJla29tZW4KICAgIC0gaGVscHQgd2VsIG9tIGxpbmVhcml0ZWl0IHRlIGJla29tZW4gd2FubmVlciBlciBub3JtYWxpdGVpdCBlbiBob21vc2NlZGFzdGljaXRlaXQgaXMKICAgIC0gVmFhayBvb2sgaG9nZXJlIG9yZGUgdGVybWVuOiAkWF4yJCwgJFheMyQsIC4uLgogICAgJCRZX2k9XGJldGFfMCtcYmV0YV8xWF9pK1xiZXRhXzJYX2leMisgLi4uICsgXGVwc2lsb25faSQkCgoKLSBUcmFuc2Zvcm1hdGllIHZhbiByZXNwb25zZSBZIGthbiBoZWxwZW4gb20gbm9ybWFsaXRlaXQgZW4gaG9tb3NjZWRhc3RpY2l0ZWl0IHRlIGJla29tZW4uCgogICAgLSAgJFxzcXJ0KFkpJCwgJFxsb2coWSkkLCAxL1ksIC4uLgoKCiMjIEJvcnN0a2Fua2VyIHZvb3JiZWVsZAoKUHJvYmxlbWVuIG1ldAoKLSAgaGV0ZXJvc2NlZGFzdGljaXRlaXQKLSBtb2dlbGlqa3NlIGFmd2lqa2luZyB2YW4gbm9ybWFsaXRlaXQgKHNjaGVlZmhlaWQgbmFhciByZWNodHMpCi0gbmVnYXRpZXZlIGNvbmNlbnRyYXRpZXZvb3JzcGVsbGluZ2VuIGRpZSB0aGVvcmV0aXNjaCBuaWV0IG1vZ2VsaWprIHppam4KLSBuaWV0LWxpbmVhaXJpdGVpdAoKLSB0cmVlZHQgdmVlbGFsIG9wIGJpaiBjb25jZW50cmF0aWUgZW4gaW50ZW5zaXRlaXRzbWV0aW5nZW4KLSBEZXplIHppam4gdmFhayBsb2ctbm9ybWFhbCB2ZXJkZWVsZCAobm9ybWFsZSB2ZXJkZWxpbmcgbmEgbG9nLXRyYW5zZm9ybWF0aWUpCi0gSW4gRmlndXVyIDYuMyBldmVuZWVucyBlZW4gc29vcnQgZXhwb25lbnRpw6tsZSB0cmVuZAotIEluIGRlIGdlbmV4cHJlc3NpZSBsaXRlcmF0dXVyIHdvcmR0IHZlZWxhbCBnZWJydWlrIGdlbWFhayB2YW4gJFxsb2dfMiQgdHJhbnNmb3JtYXRpZQotIGdlbi1leHByZXNzaWUgb3AgbG9nLXNjaGFhbCBwcm9wb3J0aW9uZWxlIHZlcnNjaGlsbGVuIG9wIGRlIG9yaWdpbmVsZSBzY2hhYWwKCgpgYGB7cn0KYnJjYSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBFU1IxLCB5ID0gUzEwMEE4KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoKQpgYGAKCmBgYHtyfQpicmNhICU+JQogIGdncGxvdChhZXMoCiAgICB4ID0gRVNSMSAlPiUgbG9nMiwKICAgIHkgPSBTMTAwQTggJT4lIGxvZzIpCiAgICApICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkKYGBgCgpgYGB7cn0KbG0yPC1sbShTMTAwQTggJT4lIGxvZzIgfiBFU1IxICU+JSBsb2cyLCBicmNhKQpwbG90KGxtMikKc3VtbWFyeShsbTIpCmBgYAoKCmBgYHtyfQpjb25maW50KGxtMikKYGBgCgoKIyMjIEludGVycHJldGF0aWUgMQoKRWVuIHBhdGnDq250IG1ldCBlZW4gRVNSMSBleHByZXNzaWUgZGllIDEgZWVuaGVpZCBvcCBkZSAkXGxvZ18yJCBzY2hhYWwgaG9nZXIgbGlndCBkYW4gZGF0IHZhbiBlZW4gYW5kZXJlIHBhdGnDq250IGhlZWZ0IGdlbWlkZGVsZCBnZXppZW4gZWVuIGV4cHJlc3NpZS1uaXZlYXUgdmFuIGhldCBTMTAwQTggZ2VuICBkYXQgYHIgYWJzKHJvdW5kKGxtMiRjb2VmWzJdLDIpKWAgZWVuaGVkZW4gbGFnZXIgbGlndCAoOTVcJSBCSSBbYHIgcGFzdGUocm91bmQoY29uZmludChsbTIpWzIsXSwyKSxjb2xsYXBzZT0iLCIpYF0pLgoKKipDcm9zc2VjdGlvbmVsZSBzdHVkaWU6IGVua2VsIHVpdHNwcmFrZW4gb3ZlciB2ZXJzY2hpbGxlbiB0dXNzZW4gcGF0acOrbnRlbiEqKgoKJCRcbG9nXzIgXGhhdFxtdV8xPTIzLjQwMSAgLTEuNjE1IFx0aW1lcyBcdGV4dHtsb2dFU1J9XzEsXHRleHR7IH0gXGxvZ18yIFxoYXRcbXVfMj0yMy40MDEgIC0xLjYxNSBcdGltZXMgXHRleHR7bG9nRVNSfV8yICQkCiQkXGxvZ18yIFxoYXRcbXVfMi1cbG9nXzIgXGhhdFxtdV8xPSAgLTEuNjE1IChcbG9nXzIgXHRleHR7RVNSfV8yLVxsb2dfMiBcdGV4dHtFU1J9XzEpID0gLTEuNjE1IFx0aW1lcyAxID0gLTEuNjE1JCQKCiMjIyBJbnRlcnByZXRhdGllIDIKCk1vZGVsIG9wIGxvZy1zY2hhYWw6IGJpaiB0ZXJ1Z3RyYW5zZm9ybWF0aWUgdmVya3JpamdlbiB3ZSBoZXQgZ2VvbWV0cmlzY2hlIGdlbWlkZGVsZGUKClxiZWdpbntlcW5hcnJheSp9ClxzdW1cbGltaXRzX3tpPTF9Xm4gXGZyYWN7XGxvZyB4X2l9e259Jj0mXGZyYWN7XGxvZyB4XzEgKyBcbGRvdHMgKyBcbG9nIHhfbn17bn1cXFxcCiZcc3RhY2tyZWx7KDEpfXs9fSZcZnJhY3tcbG9nKHhfMSBcdGltZXMgXGxkb3RzIFx0aW1lcyB4X24pfXtufT1cZnJhY3tcbG9nXGxlZnQoXHByb2RcbGltaXRzX3tpPTF9Xm4geF9pXHJpZ2h0KX17bn1cXFxcCiZcc3RhY2tyZWx7KDIpfXs9fSZcbG9nIFxsZWZ0KFxzcXJ0W1xsZWZ0cm9vdHstMX1cdXByb290ezJ9XHNjcmlwdHN0eWxlIG5de1xwcm9kXGxpbWl0c197aT0xfV5uIHhfaX1ccmlnaHQpClxlbmR7ZXFuYXJyYXkqfQoKLSBQb3B1bGF0aWVnZW1pZGRlbGRlbiAkXG11JCBkdXMgZ2VzY2hhdCBhLmQuaC52LiBnZW9tZXRyaXNjaCBnZW1pZGRlbGRlbi4KLSBMb2dhcml0bWlzY2hlIHRyYW5zZm9ybWF0aWUgaXMgZWVuIG1vbm90b29uOiB3ZSBrdW5uZW4gYmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuIGJlcmVrZW5kIG9wIGxvZy1zY2hhYWwgdGVydWd0cmFuc2Zvcm1lcmVuIQoKYGBge3J9CjJebG0yJGNvZWZbMl0KMl4tbG0yJGNvZWZbMl0KMl4tY29uZmludChsbTIpWzIsXQpgYGAKCkVlbiBwYXRpw6tudCBtZXQgZWVuIEVTUjEgZXhwcmVzc2llIGRpZSAyIGtlZXIgem8gaG9vZyBpcyBhbHMgZGllIHZhbiBlZW4gYW5kZXJlIHBhdGnDq250LCB6YWwgZ2VtaWRkZWxkIGVlbiBTMTAwQTgtZXhwcmVzc2llIGhlYmJlbiBkaWUgYHIgcm91bmQoMl4tbG0yJGNvZWZbMl0KLDIpYCBrZWVyIGxhZ2VyIGlzICg5NVwlIEJJIFtgciBwYXN0ZShzb3J0KHJvdW5kKDJeLWNvbmZpbnQobG0yKVsyLF0sMikpLGNvbGxhcHNlPSIsIilgXSkuCgoKJCRcbG9nXzIgXGhhdFxtdV8xPTIzLjQwMSAgLTEuNjE1IFx0aW1lcyBcdGV4dHtsb2dFU1J9XzEsXHRleHR7IH0gXGxvZ18yIFxoYXRcbXVfMj0yMy40MDEgIC0xLjYxNSBcdGltZXMgXHRleHR7bG9nRVNSfV8yICQkCiQkXGxvZ18yIFxoYXRcbXVfMi1cbG9nXzIgXGhhdFxtdV8xPSAgLTEuNjE1IChcbG9nXzIgXHRleHR7RVNSfV8yLVxsb2dfMiBcdGV4dHtFU1J9XzEpICQkCiQkXGxvZ18yIFxsZWZ0W1xmcmFje1xoYXRcbXVfMn17XGhhdFxtdV8xfVxyaWdodF09ICAtMS42MTUgXGxvZ18yXGxlZnRbXGZyYWN7IFx0ZXh0e0VTUn1fMn17XHRleHR7RVNSfV8xfVxyaWdodF0gJCQKJCRcZnJhY3tcaGF0XG11XzJ9e1xoYXRcbXVfMX09XGxlZnRbXGZyYWN7IFx0ZXh0e0VTUn1fMn17XHRleHR7RVNSfV8xfVxyaWdodF1eey0xLjYxNX09Ml4gey0xLjYxNX0gPTAuMzI2JCQKb3IKJCRcZnJhY3tcaGF0XG11XzF9e1xoYXRcbXVfMn09Ml57MS42MTV9ID0zLjA2JCQKCgojIyMgSW50ZXJwcmF0aWUgMwoKRWVuIHBhdGnDq250IG1ldCBlZW4gRVNSMSBleHByZXNzaWUgZGllIDFcJSBob2dlciBpcyBkYW4gZGllIHZhbiBlZW4gYW5kZXJlIHBhdGnDq250IHphbCBnZW1pZGRlbGQgZWVuIGV4cHJlc3NpZW5pdmVhdSB2b29yIGhldCBTMTAwQTggZ2VuICBoZWJiZW4gZGF0IG9uZ2V2ZWVyIGByIHJvdW5kKGxtMiRjb2VmWzJdLDIpYCUgbGFnZXIgaXMgKDk1XCUgQkkgW2ByIHBhc3RlKHJvdW5kKGNvbmZpbnQobG0yKVsyLF0sMiksY29sbGFwc2U9IiwiKWBdKSUuCgokJFxsb2dfMiBcaGF0XG11XzE9MjMuNDAxICAtMS42MTUgXHRpbWVzIFx0ZXh0e2xvZ0VTUn1fMSxcdGV4dHsgfSBcbG9nXzIgXGhhdFxtdV8yPTIzLjQwMSAgLTEuNjE1IFx0aW1lcyBcdGV4dHtsb2dFU1J9XzIgJCQKJCRcbG9nXzIgXGhhdFxtdV8yLVxoYXRcbG9nXzIgXG11XzE9ICAtMS42MTUgKFxsb2dfMiBcdGV4dHtFU1J9XzItXGxvZ18yIFx0ZXh0e0VTUn1fMSkgJCQKJCRcbG9nXzIgXGxlZnRbXGZyYWN7XGhhdFxtdV8yfXtcaGF0XG11XzF9XHJpZ2h0XT0gIC0xLjYxNSBcbG9nXzJcbGVmdFtcZnJhY3sgXHRleHR7RVNSfV8yfXtcdGV4dHtFU1J9XzF9XHJpZ2h0XSAkJAokJFxmcmFje1xoYXRcbXVfMn17XGhhdFxtdV8xfT1cbGVmdFtcZnJhY3sgXHRleHR7RVNSfV8yfXtcdGV4dHtFU1J9XzF9XHJpZ2h0XV57LTEuNjE1fT0xLjAxXiB7LTEuNjE1fSA9MC45ODQgXGFwcHJveCAtMS42XCUkJAoKRGl0IGdlbGR0IHZvb3IgbGFnZSB0b3QgbWF0aWdlIHdhYXJkZW4gdmFuICRcYmV0YV8xJDoKJCQtMTA8XGJldGFfMTwxMCBccmlnaHRhcnJvdyAxLjAxXntcYmV0YV8xfSAtMSBcYXBwcm94IFxmcmFje1xiZXRhXzF9ezEwMH0uJCQKCiMgQmVzbHVpdHZvcm1pbmcgb3ZlciBnZW1pZGRlbGRlIHVpdGtvbXN0CgotIFJlZ3Jlc3NpZSBtb2RlbCBrYW4gb29rIHdvcmRlbiBnZWJydWlrdCB2b29yIHByZWRpY3RpZQoKLSBCZXNsdWl0dm9ybWluZyB0ZSBkb2VuIG92ZXIgZGUgZ2VtaWRkZWxkZSB1aXRrb21zdCBiaWogZWVuIGdlZ2V2ZW4gd2FhcmRlICR4JCwgbS5hLncuCiQkXGhhdHtnfSh4KT0gXGhhdHtcYmV0YX1fMCArIFxoYXR7XGJldGF9XzEgeCQkCi0gJFxoYXR7Z30oeCkkIGVlbiBzY2hhdHRlciB2YW4gaGV0IGNvbmRpdGlvbmVsZSBnZW1pZGRlbGRlICRFW1lcdmVydCBYPXhdJAoKLSBQYXJhbWV0ZXJzY2hhdHRlcnMgTm9ybWFsZSB2ZXJkZWVsZCBlbiBvbnZlcnRla2VuZCAkXHJpZ2h0YXJyb3ckIHNjaGF0dGVyICRcaGF0e2d9KHgpJCBvb2sgTm9ybWFhbCB2ZXJkZWVsZCBlbiBvbnZlcnRla2VuZC4KCiQkXHRleHR7U0V9X3tcaGF0e2d9KHgpfT1cc3FydHtNU0VcbGVmdFx7XGZyYWN7MX17bn0rXGZyYWN7KHgtXGJhciBYKV4yfXtcc3VtXGxpbWl0c197aT0xfV5uIChYX2ktXGJhciBYKV4yfVxyaWdodFx9fS4kJAoKJCRUPVxmcmFje1xoYXR7Z30oeCktZyh4KX17U0Vfe1xoYXR7Z30oeCl9fVxzaW0gdF97bi0yfSQkCgotIEdlbWlkZGVsZGUgdWl0a29tc3QgZW4gYmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuIG9wIGRlIGdlbWlkZGVsZGUgdWl0a29tc3QgaW4gUiB2aWEgZGUgYHByZWRpY3QoLilgIGZ1bmN0aWUuCi0gYG5ld2RhdGFgIGFyZ3VtZW50OiBwcmVkaWN0b3J3YWFyZGVuICh4LXdhYXJkZW4pIHZvb3IgaGV0IGJlcmVrZW5lbiB2YW4gZ2VtaWRkZWxkZSB1aXRrb21zdGVuCi0gYGludGVydmFsPSJjb25maWRlbmNlImAgYXJndW1lbnQgb20gYmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuIHRlIGJla29tZW4uCi0gWm9uZGVyIGBuZXdkYXRhYCBhcmd1bWVudCB3b3JkdCBkZSBnZW1pZGRlbGRlIHVpdGtvbXN0ZW4gYmVyZWtlbmQgdm9vciBhbGxlIHByZWRpY3RvcndhYXJkZW4gdmFuIGRlIGRhdGFzZXQuCgoKYGBge3J9CmdyaWQgPC0gMTQwOjQwMDAKZyA8LSBwcmVkaWN0KAogIGxtMiwKICBuZXdkYXRhID0gZGF0YS5mcmFtZShFU1IxID0gZ3JpZCksCiAgaW50ZXJ2YWwgPSAiY29uZmlkZW5jZSIpCmhlYWQoZykKYGBgCgpNZXJrIG9wIGRhdCB3ZSBkZSBuaWV1d2UgZGF0YSBkaWUgd2UgZ2VzcGVjaWZpY2VlcmQgaGViYmVuIHZvb3IgZGUgRVNSMSBleHByZXNzaWUgbmlldCBtb2V0ZW4gdHJhbnNmb3JtZXJlbiBvbWRhdCB3ZSBoZXQgbW9kZWwgZml0dGVuIG1ldCBkZSBgbG1gZnVuY3RpZSBlbiBkZSB0cmFuc2Zvcm1hdGllIGhlYmJlbiBnZXNwZWNpZmljZWVyZCBiaW5uZW4gZGllIGZ1bmN0aWUgbWV0IGJlaHVscCB2YW4gaGV0IHBpcGUgY29tbWFuZG8hCgpgYGB7cn0KYnJjYSAlPiUgZ2dwbG90KAogIGFlcygKICAgIHggPSBFU1IxICU+JSBsb2cyLAogICAgeSA9IFMxMDBBOCAlPiUgbG9nMikKICApICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpCmBgYAoKIyMgVGVydWd0cmFuc2Zvcm1hdGllCmBgYHtyfQpuZXdkYXRhPC1kYXRhLmZyYW1lKGNiaW5kKGdyaWQsMl5nKSkKYnJjYSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBFU1IxLCB5ID0gUzEwMEE4KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9saW5lKGFlcyh4PWdyaWQseT1maXQpLG5ld2RhdGEpICsKICBnZW9tX2xpbmUoYWVzKHg9Z3JpZCx5PWx3ciksbmV3ZGF0YSxjb2xvcj0iZ3JleSIpICsKICBnZW9tX2xpbmUoYWVzKHg9Z3JpZCx5PXVwciksbmV3ZGF0YSxjb2xvcj0iZ3JleSIpCmBgYAoKIyBQcmVkaWN0aWUtaW50ZXJ2YWxsZW4KCi1XZSBrdW5uZW4gb29rIGVlbiB2b29yc3BlbGxpbmcgZG9lbiB2b29yIGRlIGxvY2F0aWUgdmFuIGVlbiBuaWV1d2Ugd2Fhcm5lbWluZyBkaWUgem91IHdvcmRlbiB2ZXJ6YW1lbGQgaW4gZWVuIG5pZXV3IGV4cGVyaW1lbnQgdm9vciBlZW4gcGF0acOrbnQgbWV0IGVlbiBiZXBhYWxkZSB3YWFyZGUgdm9vciBodW4gRVNSMS1leHByZXNzaWUKCi0gSGV0IGlzIGJlbGFuZ3Jpamsgb3AgdGUgbWVya2VuIGRhdCBkaXQgZXhwZXJpbWVudCBub2cgbW9ldCB3b3JkZW4gdWl0Z2V2b2VyZC4gV2Ugd2lsbGVuIGR1cyBkZSBuaWV0LXdhYXJnZW5vbWVuIGluZGl2aWR1ZWxlIGV4cHJlc3NpZXdhYXJkZSB2b29yIGVlbiBuaWV1d2UgcGF0acOrbnQgdm9vcnNwZWxsZW4uCgotIFZvb3IgZWVuIG5pZXV3ZSBvbmFmaGFua2VsaWprZSB3YWFybmVtaW5nICRZXiokCiQkCiAgWV4qID0gZyh4KSArIFxlcHNpbG9uXioKJCQKbWV0ICRcZXBzaWxvbl4qXHNpbSBOKDAsXHNpZ21hXjIpJCBlbiAkXGVwc2lsb25eKiQgb25hZmhhbmtlbGlqayB2YW4gZGUgd2Fhcm5lbWluZ2VuIGluIGRlIHN0ZWVrcHJvZWYgJFlfMSxcbGRvdHMsIFlfbiQuCgotIFdlIHZvb3JzcGVsbGVuIGVlbiBuaWV1d2UgbG9nLVMxMDBBOCB2b29yIGVlbiBwYXRpw6tudCBtZXQgZWVuIGdla2VuZCBsb2cyLUVTUjEtZXhwcmVzc2llbml2ZWF1IHgKXFsKICBcaGF0e3l9KHgpPVxoYXR7XGJldGF9XzArXGhhdHtcYmV0YX1fMSBcdGltZXMgeApcXQoKLSAgRGUgZ2VzY2hhdHRlIGdlbWlkZGVsZGUgdWl0a29tc3QgZW4gdm9vcnNwZWxsaW5nIHZvb3IgZWVuIG5pZXV3ZSB3YWFybmVtaW5nIHppam4gZ2VsaWprLgoKLSAgTWFhciBodW4gc3RlZWtwcm9lZiB2ZXJkZWxpbmdlbiB6aWpuIGFuZGVycyEKCiAgICAtIE9uemVrZXJoZWlkIG92ZXIgZGUgZ2VzY2hhdHRlIGdlbWlkZGVsZGUgdWl0a29tc3QgICAkXGxlZnRhcnJvdyQgb256ZWtlcmhlaWQgb3ZlciBkZSBnZXNjaGF0dGUgbW9kZWxwYXJhbWV0ZXJzICRcaGF0XGJldGFfMCQgZW4gJFxoYXRcYmV0YV8xJC4KICAgIC0gT256ZWtlcmhlaWQgb3ZlciBuaWV1d2Ugd2Fhcm5lbWluZyAkXGxlZnRhcnJvdyQgKm9uemVrZXJoZWlkIG92ZXIgZ2VzY2hhdCBnZW1pZGRlbGRlKiBlbiAgKmV4dHJhIG9uemVrZXJoZWlkKiAgb21kYXQgZGUgbmlldXdlIHdhYXJuZW1pbmcgemFsIGFmd2lqa2VuIHJvbmQgaGV0IGdlbWlkZGVsZGUhCgoKJCRcdGV4dHtTRX1fe1xoYXR7WX0oeCl9PVxzcXJ0e1xoYXRcc2lnbWFeMitcaGF0XHNpZ21hXjJfe1xoYXR7Z30oeCl9fT1cc3FydHtNU0VcbGVmdFx7MStcZnJhY3sxfXtufStcZnJhY3soeC1cYmFyIFgpXjJ9e1xzdW1cbGltaXRzX3tpPTF9Xm4gKFhfaS1cYmFyIFgpXjJ9XHJpZ2h0XH19LiQkCgokJFxmcmFje1xoYXR7WX0oeCktWX17XHRleHR7U0V9X3tcaGF0e1l9KHgpfX1cc2ltIHRfe24tMn0kJAoKLSBNZXJrIG9wIGRhdCBlZW4gKipwcmVkaWN0aWUtaW50ZXJ2YWwqKiAoUEkpIGVlbiB2ZXJiZXRlcmRlIHZlcnNpZSBpcyB2YW4gZWVuIHJlZmVyZW50aWUtaW50ZXJ2YWwgd2FubmVlciBkZSBtb2RlbHBhcmFtZXRlcnMgb25iZWtlbmQgemlqbjogb256ZWtlcmhlaWQgb3ZlciBtb2RlbHBhcmFtZXRlcnMgKyB0LXZlcmRlbGluZy4KCgpgYGB7cn0KcCA8LSBwcmVkaWN0KAogIGxtMiwKICBuZXdkYXRhID0gZGF0YS5mcmFtZShFU1IxID0gZ3JpZCksCiAgaW50ZXJ2YWw9InByZWRpY3Rpb24iKQoKaGVhZChwKQpgYGAKCmBgYHtyfQpwcmVkZGF0YTwtZGF0YS5mcmFtZSgKICBncmlkID0gZ3JpZCU+JWxvZzIsCiAgcCkKYnJjYSAlPiUgZ2dwbG90KGFlcyh4PUVTUjElPiVsb2cyLHk9UzEwMEE4JT4lbG9nMikpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArCiAgICAgZ2VvbV9saW5lKGFlcyh4PWdyaWQseT1sd3IpLHByZWRkYXRhLGNvbG9yPSJibHVlIikgKwogIGdlb21fbGluZShhZXMoeD1ncmlkLHk9dXByKSxwcmVkZGF0YSxjb2xvcj0iYmx1ZSIpCmBgYAoKYGBge3J9CnByZWRkYXRhPC1kYXRhLmZyYW1lKGNiaW5kKGdyaWQsMl5wKSkKYnJjYSAlPiUgZ2dwbG90KGFlcyh4ID0gRVNSMSwgeSA9IFMxMDBBOCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGluZSgKICAgIGFlcyh4ID0gZ3JpZCx5ID0gZml0KSwKICAgIG5ld2RhdGEpICsKICBnZW9tX2xpbmUoCiAgICBhZXMoeCA9IGdyaWQsIHkgPSBsd3IpLAogICAgbmV3ZGF0YSwKICAgIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9saW5lKAogICAgYWVzKHggPSBncmlkLCB5ID0gdXByKSwKICAgIG5ld2RhdGEsCiAgICBjb2xvciA9ICJncmV5IikgKwogIGdlb21fbGluZSgKICAgIGFlcyh4ID0gZ3JpZCwgeSA9IGx3ciksCiAgICBwcmVkZGF0YSwKICAgIGNvbG9yID0gImJsdWUiKSArCiAgZ2VvbV9saW5lKAogICAgYWVzKHggPSBncmlkLHkgPSB1cHIpLAogICAgcHJlZGRhdGEsCiAgICBjb2xvciA9ICJibHVlIikKYGBgCgoKIyMgTkhBTkVTIHZvb3JiZWVsZAoKCi0gVmVyZ2VsaWprIHJlZmVyZW50aWUtaW50ZXJ2YWwgdm9vciBjaG9sZXN0ZXJvbGdlaGFsdGUgbWV0IHByZWRpY3RpZSBpbnRlcnZhbC4KCi0gUmVmZXJlbnRpZS1pbnRlcnZhbAoKYGBge3J9CmxpYnJhcnkoTkhBTkVTKQpmZW0gPC0gTkhBTkVTICU+JQogIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiJiFpcy5uYShEaXJlY3RDaG9sKSkKCjJeKAogIGZlbSAlPiUKICBwdWxsKERpcmVjdENob2wpICU+JQogIGxvZzIgJT4lCiAgbWVhbiArCiAgICBjKC0xLDEpICoKICAgIHFub3JtKDAuOTc1KSAqCiAgICAoZmVtICU+JQogICAgICBwdWxsKERpcmVjdENob2wpICU+JQogICAgICBsb2cyICU+JQogICAgICBzZCkKICApCmBgYAoKLSBQcmVkaWN0aWUgaW50ZXJ2YWwKCmBgYHtyfQpsbUNob2wgPC0gbG0oRGlyZWN0Q2hvbCAlPiUgbG9nMiB+IDEsIGRhdGE9ZmVtKQpwcmVkSW50IDwtIHByZWRpY3QoCiAgbG1DaG9sLAogIGludGVydmFsPSJwcmVkaWN0aW9uIiwKICBuZXdkYXRhPWRhdGEuZnJhbWUobm9QcmVkPTEpCiAgKQpyb3VuZCgyXnByZWRJbnQsMikKYGBgCgpNZXJrIG9wIGRhdCBoZXQgdm9vcnNwZWxsaW5nc2ludGVydmFsIGJpam5hIGdlbGlqayBpcyBhYW4gaGV0IHJlZmVyZW50aWUtaW50ZXJ2YWwgdm9vciBkZSBncm90ZSBzdGVla3Byb2VmLiBXZSBrb25kZW4gZGUgcGFyYW1ldGVycyBpbmRlcmRhYWQgaGVlbCBwcmVjaWVzIHNjaGF0dGVuLgoKV2UgenVsbGVuIGhldHplbGZkZSBkb2VuIHZvb3IgZWVuIGtsZWluZSBzdGVla3Byb2VmIHZhbiAxMCBwYXRpw6tudGVuLgoKLSBSZWZlcmVudGllIGludGVydmFsCgpgYGB7cn0Kc2V0LnNlZWQoMSkKZmVtMTAgPC0gTkhBTkVTICU+JQogIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiJiFpcy5uYShEaXJlY3RDaG9sKSkgJT4lCiAgc2FtcGxlX24oc2l6ZT0xMCkKCjJeKAogIGZlbTEwICU+JQogICAgcHVsbChEaXJlY3RDaG9sKSAlPiUKICAgIGxvZzIgJT4lCiAgICBtZWFuICsKICAgICAgYygtMSwxKSAqCiAgICAgIHFub3JtKDAuOTc1KSAqCiAgICAgIChmZW0xMCAlPiUKICAgICAgICBwdWxsKERpcmVjdENob2wpICU+JQogICAgICAgIGxvZzIgJT4lCiAgICAgICAgc2QpCiAgKQpgYGAKCkhldCByZWZlcmVudGllLWludGVydmFsIGlzIHZlZWwgc21hbGxlciBkYW4gaW4gZGUgZ3JvdGUgc3RlZWtwcm9lZi4KCi0gUHJlZGljdGllIGludGVydmFsCgpgYGB7cn0KbG1DaG9sMTAgPC0gbG0oRGlyZWN0Q2hvbCAlPiUgbG9nMiB+IDEsIGRhdGEgPSBmZW0xMCkKcHJlZEludDEwIDwtIHByZWRpY3QoCiAgbG1DaG9sMTAsCiAgaW50ZXJ2YWwgPSAicHJlZGljdGlvbiIsCiAgbmV3ZGF0YSA9IGRhdGEuZnJhbWUobm9QcmVkPTEpCiAgKQpyb3VuZCgyXnByZWRJbnQxMCwgMikKYGBgCgotIE1lcmsgb3AgZGF0IGhldCBQSSBudSBvbnpla2VyaGVpZCBtZWVuZWVtdCBpbiBwYXJhbWV0ZXJzY2hhdHRlcnMgKGdlbWlkZGVsZGUgZW4gc3RhbmRhYXJkIGVycm9yKS4KRW4gZGF0IGhldCBpbnRlcnZhbCB2ZWVsIGJyZWRlciB3b3JkdCEgRGl0IGlzIGhpZXIgdm9vcmFsIGJlbGFuZ3Jpamsgdm9vciBkZSBib3ZlbmdyZW5zIG9tZGF0IHdlIGRlIGdlZ2V2ZW5zIHRlcnVnIGhlYmJlbiBnZXRyYW5zZm9ybWVlcmQhCgotIEhldCBpbnRlcnZhbCBpcyBiaWpuYSBuZXQgem8gYnJlZWQgYWxzIGRhdCBnZWJhc2VlcmQgb3AgZGUgZ3JvdGUgc3RlZWtwcm9lZi4KCi0gQmlqIGtsZWluZSBzdGVla3Byb2V2ZW4gaXMgaGV0IGVyZyBiZWxhbmdyaWprIG9tIG1ldCBkZXplIGV4dHJhIG9uemVrZXJoZWlkIHJla2VuaW5nIHRlIGhvdWRlbi4KCgojIEt3YWRyYXRlbnNvbW1lbiBlbiBBbm92YS10YWJlbAoKIyMgVG90YWxlIGt3YWRyYXRlbnNvbQoKJCRcdGV4dHtTU1RvdH0gPSBcc3VtX3tpPTF9Xm4gKFlfaS1cYmFye1l9KV4yLiQkCgotIFNTdG90IGthbiB3b3JkZW4gZ2VicnVpa3Qgb20gZGUgdmFyaWFudGllIHZhbiBkZSAqKm1hcmdpbmFsZSB2ZXJkZWxpbmcqKiB2YW4gZGUgcmVzcG9ucyB0ZSBzY2hhdHRlbi4KCi0gSW4gZGl0IGhvb2Zkc3R1ayBoZWJiZW4gd2Ugb25zIGdlZm9jdXNlZCBvcCBkZSAqKmNvbmRpdGlvbmVsZSB2ZXJkZWxpbmcqKiAkZihZXHZlcnQgWD14KSQuCgotIFdlIHdldGVuIGRhdCBNU0UgZWVuIGdvZWRlIHNjaGF0dGluZyBpcyB2YW4gZGUgdmFyaWFudGllIHZhbiBkZSBjb25kaXRpb25lbGUgdmVyZGVsaW5nIHZhbiAgJFlcdmVydCBYPXgkLgoKCmBgYHtyIG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJywgZWNobz1GQUxTRX0KYnJjYSRsb2cyRVNSMSA8LSBsb2cyKGJyY2EkRVNSMSkKYnJjYSRsb2cyUzEwMEE4IDwtIGxvZzIoYnJjYSRTMTAwQTgpCnBsb3QobG9nMlMxMDBBOCB+IGxvZzJFU1IxLAogIGRhdGEgPSBicmNhLAogIHhsYWIgPSAiRVNSMSBleHByZXNzaWUgKGxvZzIpIiwKICB5bGFiID0gIlMxMDBBOCBleHByZXNzaWUgKGxvZzIpIiwKICBjZXguYXhpcz0xLjUsCiAgY2V4Lm1haW49MS41LAogIGNleC5sYWI9MS41LGNvbD00KQphYmxpbmUoaCA9IG1lYW4oYnJjYSRsb2cyUzEwMEE4KSkKZm9yIChpIGluIDE6bGVuZ3RoKGJyY2EkbG9nMlMxMDBBOCkpIGxpbmVzKHJlcChicmNhJGxvZzJFU1IxW2ldLDIpLGMobWVhbihicmNhJGxvZzJTMTAwQTgpLGJyY2EkbG9nMlMxMDBBOFtpXSksbHR5PTIsY29sPTQpCmBgYAoKIyMgS3dhZHJhdGVuc29tIHZhbiBkZSByZWdyZXNzaWUgU1NSCgokJFx0ZXh0e1NTUn0gPSBcc3VtX3tpPTF9Xm4gKFxoYXR7WX1faSAtIFxiYXJ7WX0pXjIgPSBcc3VtX3tpPTF9Xm4gKFxoYXR7Z30oeF9pKSAtIFxiYXJ7WX0pXjIuJCQKCi0gTWFhdCB2b29yIGRlIGFmd2lqa2luZyB0dXNzZW4gZGUgcHJlZGljdGllcyBvcCBkZSBnZXNjaGF0dGUgcmVncmVzc2llcmVjaHRlIGVuIGhldCBzdGVla3Byb2VmZ2VtaWRkZWxkZSB2YW4gZGUgdWl0a29tc3Rlbi4KCi0gRWVuIGFuZGVyZSBpbnRlcnByZXRhdGllOiB2ZXJzY2hpbCB0dXNzZW4gdHdlZSBtb2RlbGxlbgoKICAgIC0gR2VzY2hhdHRlIG1vZGVsICRcaGF0e2d9KHgpPVxoYXRcYmV0YV8wK1xoYXRcYmV0YV8xeCQKICAgIC0gR2VzY2hhdHRlIG1vZGVsIHpvbmRlciBwcmVkaWN0b3IgKGVua2VsIGludGVyY2VwdCk6ICRnKHgpPVxiZXRhXzAkICRccmlnaHRhcnJvdyQgJFxiZXRhXzAkIHphbCBnZWxpamsgemlqbiBhYW4gJFxiYXJ7WX0kLgoKLSBTU1IgbWVldCBkZSBncm9vdHRlIHZhbiBoZXQgZWZmZWN0IHZhbiBkZSBwcmVkaWN0b3IKCmBgYHtyIG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpwbG90KGxvZzJTMTAwQTh+bG9nMkVTUjEsYnJjYSx4bGFiPSJFU1IxIGV4cHJlc3NpZSAobG9nMikiLHlsYWI9IlMxMDBBOCBleHByZXNzaWUgKGxvZzIpIixjZXguYXhpcz0xLjUsY2V4Lm1haW49MS41LGNleC5sYWI9MS41KQphYmxpbmUoaD1tZWFuKGJyY2EkbG9nMlMxMDBBOCkpCmFibGluZShsbTIsY29sPTIpCnBvaW50cyhicmNhJGxvZzJFU1IxLGxtMiRmaXR0ZWQscGNoPTIsY29sPTIpCmZvciAoaSBpbiAxOmxlbmd0aChicmNhJGxvZzJTMTAwQTgpKSBsaW5lcyhyZXAoYnJjYSRsb2cyRVNSMVtpXSwyKSxjKG1lYW4oYnJjYSRsb2cyUzEwMEE4KSxsbTIkZml0dGVkW2ldKSxsdHk9Mixjb2w9MikKYGBgCgoKIyMgS3dhZHJhdGVuc29tIHZhbiBkZSBmb3V0ZW4KCiQkIFx0ZXh0e1NTRX0gPSBcc3VtX3tpPTF9Xm4gKFlfaS1caGF0e1l9X2kgKV4yID0gXHN1bV97aT0xfV5uIFxsZWZ0XHtZX2ktXGhhdHtnfVxsZWZ0KHhfaVxyaWdodClccmlnaHRcfV4yLiQkCgotIEhvZSBrbGVpbmVyIGRlIFNTRSwgaG9lIGJldGVyIGhldCBtb2RlbCBmaXQuCgoKLSBLbGVpbnN0ZSBrd2FkcmF0ZW4gdGVjaG5pZWshCgotLS0KCmBgYHtyIG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpwbG90KGxvZzJTMTAwQTh+bG9nMkVTUjEsYnJjYSx4bGFiPSJFU1IxIGV4cHJlc3NpZSAobG9nMikiLHlsYWI9IlMxMDBBOCBleHByZXNzaWUgKGxvZzIpIixjZXguYXhpcz0xLjUsY2V4Lm1haW49MS41LGNleC5sYWI9MS41KQphYmxpbmUobG0yLGNvbD0yKQpwb2ludHMoYnJjYSRsb2cyRVNSMSxsbTIkZml0dGVkLHBjaD0yLGNvbD0yKQpmb3IgKGkgaW4gMTpsZW5ndGgoYnJjYSRsb2cyUzEwMEE4KSkgbGluZXMocmVwKGJyY2EkbG9nMkVTUjFbaV0sMiksYyhicmNhJGxvZzJTMTAwQThbaV0sbG0yJGZpdHRlZFtpXSksbHR5PTIpCmBgYAoKV2Uga3VubmVuIGFhbnRvbmVuIGRhdCBTU1Qga2FuIHdvcmRlbiBvbnRib25kZW4gaW4KXGJlZ2lue2VxbmFycmF5Kn0KICBcdGV4dHtTU1RvdH0KICAgICY9JiAgXHN1bV97aT0xfV5uIChZX2ktXGJhcntZfSleMiBcXAogICAgJj0mICBcc3VtX3tpPTF9Xm4gKFlfaS1caGF0e1l9X2krXGhhdHtZfV9pLVxiYXJ7WX0pXjIgXFwKICAgICY9JiAgXHN1bV97aT0xfV5uIChZX2ktXGhhdHtZfV9pKV4yK1xzdW1fe2k9MX1ebihcaGF0e1l9X2ktXGJhcntZfSleMiBcXAogICAgJj0mICBcdGV4dHtTU0UgfStcdGV4dHtTU1J9ICAKICBcZW5ke2VxbmFycmF5Kn0KCi0gIERlIHRvdGFsZSB2YXJpYWJpbGl0ZWl0IGluIGRlIGdlZ2V2ZW5zIChTU1RvdCkgd29yZHQgZ2VkZWVsdGVsaWprIHZlcmtsYWFyZCBkb29yIGhldCByZWdyZXNzaWV2ZXJiYW5kIChTU1IpLgotIFZhcmlhYmlsaXRlaXQgZGllIHdlIG5pZXQga3VubmVuIHZlcmtsYXJlbiBtZXQgaGV0IHJlZ3Jlc3NpZW1vZGVsIGlzIGRlIHJlc2lkdWVsZSB2YXJpYWJpbGl0ZWl0IChTU0UpLgoKCiMjICBEZXRlcm1pbmF0aWUtY2/Dq2ZmaWNpw6tudAoKJCQgUl4yID0gMS1cZnJhY3tcdGV4dHtTU0V9fXtcdGV4dHtTU1RvdH19PVxmcmFje1x0ZXh0e1NTUn19e1x0ZXh0e1NTVG90fX0uJCQKCi0gKkZyYWN0aWUgdmFuIGRlIHRvdGFsZSB2YXJpYWJpbGl0ZWl0IGluIGRlIHN0ZWVrcHJvZWYtdWl0a29tc3RlbiBkaWUgdmVya2xhYXJkIHdvcmR0IGRvb3IgaGV0IGdlc2NoYXR0ZSByZWdyZXNzaWV2ZXJiYW5kKi4KCi0gR3JvdGUgJFJeMiQgaW5kaWNhdGllIGRhdCBtb2RlbCBwb3RlbnRpZWVsIHRvdCBnb2VkZSBwcmVkaWN0aWVzIGthbiBsZWlkZW4gKGtsZWluZSBTU0UpCgotIFNsZWNodHMgaW4gYmVwZXJrdGUgbWF0ZSBpbmRpY2F0aWVmIHZvb3IgZGUgcC13YWFyZGUgdmFuIGRlIHRlc3QgJEhfMDpcYmV0YV8xPTAkIHZzICRIXzE6XGJldGFfMVxuZXEwJC4KCiAgICAtIHAtd2FhcmRlIHN0ZXJrIGJlw69udmxvZWQgZG9vciBTU0UgZW4gc3RlZWtwcm9lZmdyb290dGUgJG4kLCBtYWFyIG5pZXQgZG9vciBTU1RvdAogICAgLSBEZSBkZXRlcm1pbmF0aWVjb8OrZmZpY2nDq250ICRSXjIkIHdvcmR0IGRvb3IgU1NFIGVuIFNTVG90IGJlcGFhbGQsIG1hYXIgbmlldCBkb29yIGRlIHN0ZWVrcHJvZWZncm9vdHRlIG4uCgotIE1vZGVsIG1ldCBsYWdlICRSXjIkIGJsaWpmdCB3ZWwgbnV0dGlnIG9tIGFzc29jaWF0aWUgdGUgYmVzdHVkZXJlbiwgem9sYW5nIGhldCBkZSBhc3NvY2lhdGllIGNvcnJlY3QgbW9kZWxsZWVydCEKCiMjIyBCb3JzdGthbmtlciB2b29yYmVlbGQKCmBgYHtyfQpzdW1tYXJ5KGxtMikKYGBgCgojIyBGLVRlc3RlbiBpbiBoZXQgZW5rZWx2b3VkaWcgbGluZWFpciByZWdyZXNzaWVtb2RlbAoKLSBLd2FkcmF0ZW5zb21tZW4gIHppam4gYmFzaXMgdm9vciAkRiQtdGVzdHMKJCQgIEYgID0gXGZyYWN7XHRleHR7TVNSfX17XHRleHR7TVNFfX0kJAoKbWV0ICAkXHRleHR7TVNSfSA9IFxmcmFje1x0ZXh0e1NTUn19ezF9IFx0ZXh0eyBhbmQgfSBcdGV4dHtNU0V9ID0gXGZyYWN7XHRleHR7U1NFfX17bi0yfS4kCgotIE1TUiB3b3JkdCBkZSBnZW1pZGRlbGRlIGt3YWRyYXRlbnNvbSB2YW4gZGUgcmVncmVzc2llIGdlbm9lbWQuCgotIG5vZW1lcnMgMSBlbiAkbi0yJCB6aWpuIGRlIHZyaWpoZWlkc2dyYWRlbiB2YW4gU1NSIGVuIFNTRS4KCi0gb25kZXIgJEhfMDogXGJldGFfMT0wJCB2b2xndCBkZSB0ZXN0c3RhdGlzdGllawokJEhfMDpGID0gXGZyYWN7XHRleHR7TVNSfX17XHRleHR7TVNFfX0gXHNpbSBGX3sxLG4tMn0sJCQKLSBGLXRlc3QgaXMgYWx0aWpkIHR3ZWUtemlqZGlnISAkSF8xOlxiZXRhXzFcbmVxIDAkCiQkICBwID0gUF8wXGxlZnRbRlxnZXEgZlxyaWdodF09MS1GX0YoZjsxLG4tMikkJAoKCmBgYHtyfQpzdW1tYXJ5KGxtMikKYGBgCgoKYGBge3IsIGVjaG89RkFMU0V9CmdyaWQ8LXNlcSgwLDEwLC4xKQpwbG90KGdyaWQsZGYoZ3JpZCwxLDMwKSx0eXBlPSJsIix4bGFiPSJGIix5bGFiPSJEZW5zaXR5IixtYWluPSJGLWRpc3RyaWJ1dGllIDEgZGYgaW4gdGVsbGVuLCAzMCBpbiBub2VtZXIiLGNleC5tYWluPTEuNSxjZXguYXhpcz0xLjUsY2V4LmxhYj0xLjUpCmBgYAoKCiMjIEFub3ZhIFRhYmVsCgoKfCB8RGZ8U3VtIFNxfE1lYW4gU3F8RiB2YWx1ZXxQcig+Ril8CnwtLS18LS0tfC0tLXwtLS18LS0tfC0tLXwKfFJlZ3Jlc3NpZXx2cmlqaGVpZHNncmFkZW4gU1NSfFNTUnxNU1J8Zi1zdGF0aXN0aWVrfHAtd2FhcmRlfAp8RXJyb3J8dnJpamhlaWRzZ3JhZGVuIFNTRXxTU0V8TVNFfCB8IHwKCmBgYHtyfQphbm92YShsbTIpCmBgYAoKCiMgRHVtbXkgdmFyaWFiZWxlbgoKLSBMaW5lYWlyZSByZWdyZXNzaWVtb2RlbCB2b29yIGhldCB2ZXJnZWxpamtlbiB2YW4gdHdlZSBnZW1pZGRlbGRlbi4KLSBCb3JzdGthbmtlcjogdmVyc2NoaWwgaXMgaW4gZ2VtaWRkZWxkZSBsZWVmdGlqZCB2YW4gZGUgcGF0acOrbnRlbiBtZXQgb25hYW5nZXRhc3RlIGx5bWZla25vcGVuIGVuIHBhdGnDq250ZW4gd2FhcnZhbiBseW1mZWtub3BlbiB3ZXJkZW4gdmVyd2lqZGVyZC4KCi0gSGllcnZvb3IgZGVmaW5pw6tyZW4gd2UgZWVyc3QgZWVuICRkdW1teSQgdmFyaWFiZWxlCiQkeF9pID0gXGxlZnRceyBcYmVnaW57YXJyYXl9e2xsfQoxICYgXHRleHR7YWFuZ2V0YXN0ZSBseW1mZWtub3Blbn0gXFwKMCAmIFx0ZXh0e29uYWFuZ2V0YXN0ZSBseW1mZWtub3Blbn0gXGVuZHthcnJheX1ccmlnaHQuJCQKCi0gZ3JvZXAgbWV0ICR4X2k9MCQgd29yZHQgZGUgKipyZWZlcmVudGllZ3JvZXAqKiBnZW5vZW1kLgoKLSBIZXQgcmVncmVzc2llbW9kZWwgYmxpamZ0IG9uZ2V3aWp6aWdkLAokJFlfaSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfaSArXGVwc2lsb25faSQkCm1ldCAkXGVwc2lsb25faSBcdGV4dHsgaWlkIH0gTigwLFxzaWdtYV4yKSQKCgpHZXppZW4gJHhfaSQgc2xlY2h0cyB0d2VlIHdhYXJkZW4ga2FuIGFhbm5lbWVuLCBpcyBoZXQgZWVudm91ZGlnIG9tIGhldCByZWdyZXNzaWVtb2RlbCB2b29yIGJlaWRlIHdhYXJkZW4gdmFuICR4X2kkIGFmem9uZGVybGlqayB0ZSBiZWtpamtlbjoKJCQgXGJlZ2lue2FycmF5fXtsY2xsfQogICBZX2kgJj0mIFxiZXRhXzAgK1xlcHNpbG9uX2kgJlx0ZXh0e29uYWFuZ2V0YXN0ZSBseW1mZWtub3Blbn0gKHhfaT0wKSBcXAogICBZX2kgJj0mIFxiZXRhXzAgKyBcYmV0YV8xICtcZXBzaWxvbl9pICZcdGV4dHsgYWFuZ2V0YXN0ZSBseW1mZWtub3Blbn0gKHhfaT0xKSAuCiBcZW5ke2FycmF5fSQkCgpEdXMKIFxiZWdpbntlcW5hcnJheSp9CiAgIEVcbGVmdFtZX2lcbWlkIHhfaT0wXHJpZ2h0XSAmPSYgXGJldGFfMCBcXAogICBFXGxlZnRbWV9pXG1pZCB4X2k9MVxyaWdodF0gJj0mIFxiZXRhXzAgKyBcYmV0YV8xLApcZW5ke2VxbmFycmF5Kn0KCiB3YWFydWl0IGRpcmVjdCBkZSBpbnRlcnByZXRhdGllIHZhbiAkXGJldGFfMSQgdm9sZ3Q6CiQkICAgXGJldGFfMSA9IEVcbGVmdFtZX2lcbWlkIHhfaT0xXHJpZ2h0XS1FXGxlZnRbWV9pXG1pZCB4X2k9MFxyaWdodF0kJAoKJFxiZXRhXzEkIGlzIGR1cyBoZXQgZ2VtaWRkZWxkZSB2ZXJzY2hpbCBpbiBsZWVmdGlqZCB0dXNzZW4gcGF0acOrbnRlbiBtZXQgYWFuZ2V0YXN0ZSBseW1mZWtub3BlbiBlbiBwYXRpw6tudGVuIG1ldCBvbmFhbmdldGFzdGUgbHltZmVrbm9wZW4gKHJlZmVyZW50aWVncm9lcCkuCgpNZXQgZGUgbm90YXRpZSAkXG11XzA9IEVcbGVmdFtZX2lcbWlkIHhfaT0wXHJpZ2h0XSQgZW4gJFxtdV8xPSBFXGxlZnRbWV9pXG1pZCB4X2k9MVxyaWdodF0kIHdvcmR0IGRpdAokJFxiZXRhXzEgPSBcbXVfMS1cbXVfMC4kJAoKCkVyIGthbiBhYW5nZXRvb25kIHdvcmRlbiBkYXQKJCRcYmVnaW57YXJyYXl9e2NjbGx9CiBcaGF0XGJldGFfMAogICAmPSYgXGJhcntZfV8xJlx0ZXh0eyAoc3RlZWtwcm9lZmdlbWlkZGVsZGUgaW4gcmVmZXJlbnRpZWdyb2VwKX0gXFwKIFxoYXRcYmV0YV8xCiAgICY9JiBcYmFye1l9XzItXGJhcntZfV8xJlx0ZXh0eyhzY2hhdHRlciB2YW4gZWZmZWN0Z3Jvb3R0ZSl9IFxcCiBcdGV4dHtNU0V9CiAgICY9JiBTX3BeMiAuClxlbmR7YXJyYXl9JCQKCkRlIHRlc3RlbiB2b29yICRIXzA6XGJldGFfMT0wJCB2cy4gICRIXzE6XGJldGFfMVxuZXEwJCBrdW5uZW4gZ2VicnVpa3Qgd29yZGVuIHZvb3IgaGV0IHRlc3RlbiB2YW4gZGUgbnVsaHlwb3RoZXNlIHZhbiBkZSB0d28tc2FtcGxlICR0JC10ZXN0LCAkSF8wOlxtdV8xPVxtdV8yJCB0Lm8udi4gJEhfMTpcbXVfMVxuZXFcbXVfMiQuCgpgYGB7cn0KYnJjYSRub2RlIDwtIGFzLmZhY3RvcihicmNhJG5vZGUpCnQudGVzdChhZ2V+bm9kZSxicmNhLHZhci5lcXVhbD1UUlVFKQpgYGAKCmBgYHtyfQpsbTMgPC0gbG0oYWdlfm5vZGUsIGJyY2EpCnN1bW1hcnkobG0zKQpgYGAKCmBgYHtyfQpwbG90KGxtMykKYGBgCgoKCmBgYHtyfQpicmNhICU+JQogIGdncGxvdCgKICAgIGFlcygKICAgICAgeCA9IG5vZGUgJT4lCiAgICAgICAgYXMuZmFjdG9yLAogICAgICB5ID0gYWdlKQogICAgICApICsKICBnZW9tX2JveHBsb3QoKQpgYGAKCgoxLiBTaW11bGF0ZSA5IGRhdGFzZXRzIHdpdGggdGhlIHNhbWUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBhcyB0aGUgYnJjYSBkYXRhc2V0IGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggdGhlIHNhbWUgc3RhbmRhcmQgZGV2aWF0aW9uIGFzIGluIHRoZSBvcmlnaW5hbCBkYXRhLiBTdG9yZSB0aGUgZGF0YSBvZiBhbGwgc2ltdWxhdGlvbnMgaW4gYSBkYXRhIGZyYW1lCjIuIFBsb3QgdGhlIHNpbXVsYXRlZCBkYXRhIHVzaW5nIHRoZSBgZ2dwbG90YCBmdW5jdGlvbgozLiBBZGQgYSBib3hwbG90IGxheWVyCjQuIFVzZSBmYWNldF93cmFwIHRvIG1ha2UgYSBzZXBhcmF0ZSBwbG90IGZvciBzaW11bGF0ZWQgZGF0YXNldAo1LiBDaGFuZ2UgbGFiZWwgb2YgeS1heGlzCgpgYGB7ciBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcid9CnNldC5zZWVkKDM1NCkKc2ltX2RmIDwtIGRhdGEuZnJhbWUoCiAgbm9kZSA9IHJlcChicmNhJG5vZGUsIDkpLAogIGlpZCA9IHJub3JtKDkgKiBucm93KGJyY2EpLCBzZCA9IHNpZ21hKGxtMykpLAogIHNpbSA9IHJlcCgxOjksIGVhY2ggPSAzMikKICApCnNpbV9kZiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBub2RlLCB5PWlpZCkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZmFjZXRfd3JhcCgufnNpbSkgKwogIHlsYWIocGFzdGUwKCJpaWQgTigwLCIscm91bmQoc2lnbWEobG0zKV4yLDIpLCIpIikpCmBgYAoKCiMjIE9ic2VydmF0aW9uZWxlIHN0dWR5CgotIFdlIGt1bm5lbiBlY2h0ZXIgbmlldCBiZXNsdWl0ZW4gZGF0IG91ZGVyZSBwZXJzb25lbiBlZW4gaG9nZXIgcmlzaWNvIGhlYmJlbiBvcCBhYW50YXN0aW5nIHZhbiBkZSBseW1mZWtub3BlbiB0ZW4gZ2V2b2xnZSB2YW4gaHVuIGxlZWZ0aWpkLgoKLSBNb2dlbGlqa3MgKipjb25mb3VuZGluZyoqOiBnZWVuIHJhbmRvbWlzYXRpZSAkXHJpZ2h0YXJyb3ckIGdyb2VwZW4gcGF0acOrbnRlbiBtZXQgYWFuZ2V0YXN0ZSBseW1mZWtub3BlbiBlbiBuaWV0LWFhbmdldGFzdGUgbHltZmVrbm9wZW4ga3VubmVuIG5vZyBpbiBhbmRlcmUga2FyYXRlcmlzdGlla2VuIHZhbiBlbGthYXIgdmVyc2NoaWxsZW4uCgotIEVua2VsIGJlc2x1aXRlbiBkYXQgZXIgZWVuIGFzc29jaWF0aWUgaXMgdHVzc2VuIGRlIGx5bWZla25vb3Agc3RhdHVzIGVuIGRlIGxlZWZ0aWpkLgoKLSBIZXQgaXMgZHVzIG5pZXQgbm9vZHpha2VsaWprZXJ3aWpzIGVlbiBjYXVzYWFsIHZlcmJhbmQhCgotLS0KCi0gSXMgb29rIHpvIHZvb3IgbGluZWFpciBtb2RlbCB2b29yIGRlICRcbG9nXzIkLVMxMDBBOC1leHByZXNzaWUuCgotIEFhbmdlemllbiB3ZSBkZSBFU1IxLWV4cHJlc3NpZSBuaWV0IGV4cGVyaW1lbnRlZWwgdmFzdCBoZWJiZW4ga3VubmVuIGxlZ2dlbiwga3VubmVuIHdlIG5pZXQgYmVzbHVpdGVuIGRhdCBlZW4gaG9nZXJlIEVTUjEtZXhwcmVzc2llIGRlIFMxMDBBOC1leHByZXNzaWUgZG9ldCB2ZXJsYWdlbi4KCi0gRW5rZWwgYmVzbHVpdGVuIGRhdCBlciBlZW4gbmVnYXRpZXZlIGFzc29jaWF0aWUgaXMuCgotIE9tIGltcGFjdCB2YW4gZ2VuIHRlIGJlc3R1ZGVyZW4gb3AgYW5kZXJlIGdlbmVuOiBrbm9ja291dCBtdXRhbnRlbiBnZW5lcmVuZW4gaW4gaGV0IGxhYm8KCgotLS0KCiMgW0hvbWVdKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pby9zYmMyMC8pIHstfQo=