Úvod
Cieľom analýzy je preskúmať, či rozšírenie elektromobility v
krajinách V4 súvisí s kvalitou životného prostredia meranou indexom
environmentálnej výkonnosti (EPI). Pracujem s prečisteným
panelovým datasetom z mojej bakalárskej práce (krajiny V4 × roky).
Charakteristika dát
- Zdroj a pokrytie: Vlastný dataset zostavený pre BP
(krajiny V4 × roky).
- Hlavné premenné:
EPI (zložený index
kvality životného prostredia), BEV (počet batériových EV),
BEV_PHEV (BEV + plug‑in hybridy), HDP na
obyvateľa.
- Stav dát: Dáta boli prečistené
pred týmto cvičením; v tomto dokumente už neriešime imputačné či
čistiace kroky.
Premenné
Závislá premenná: EPI – zložený index
environmentálnej výkonnosti krajín.
Kľúčové vysvetľujúce premenné: BEV – počet
batériových elektromobilov; BEV_PHEV – súčet BEV a plug-in
hybridov (PHEV).
Kontrolné premenné: HDP na obyvateľa
(ekonomická úroveň); podľa dostupnosti aj ďalšie sprievodné ukazovatele
(CO₂, investičné/rozvojové indikátory).
Výskumná otázka a hypotézy
Súvisí vyšší počet (P)HEV s vyšším EPI, po zohľadnení ekonomickej
úrovne krajín?
- H0: Počet BEV/BEV_PHEV nemá
významný vplyv na EPI.
- H1: Vyšší BEV/BEV_PHEV je spojený s
vyšším EPI.
Metodika v skratke
Používam lineárne modely OLS s log‑transformáciou
počtových premenných (log1p), aby sa stabilizovala
variancia a tlmili sa extrémy. Aby som sa vyhla kolinearite, odhadujem
model s BEV a model s BEV_PHEV
oddelene; HDP figuruje ako kontrola úrovne
rozvoja. Diagnostiku robím cez štandardné grafy (Q–Q, Scale–Location,
Leverage) a formálne testy (Breusch–Pagan). Inferenciu reportujem s
robustnými SE (HC1), prípadne klastrovanými podľa
krajiny pri panelových špecifikáciách.
Import údajov
z mojej bakalárskej práce
Načítam csv súbor s dátami o elektromobilite vo V4 (počet
BEV, BEV_PHEV, EPI, HDP, emisie CO₂, investičné ukazovatele…). Dáta sú
už prečistené.
Interaktívna tabuľka s dátami
Prieskumné grafy - BOXPLOT
Prečo: pred modelovaním overujem, či mierky a
rozdelenia dávajú zmysel a či nie sú viditeľné extrémy. Počtové premenné
(BEV, BEV_PHEV) vizualizujem v log‑mierke
(log1p).
par(mfrow = c(2, 2))
boxplot(udaje$EPI, main = "EPI (bez log)", col = "darkgreen", horizontal = TRUE)
boxplot(log1p(udaje$BEV), main = "log1p(BEV)", col = "lightblue", horizontal = TRUE)
boxplot(log1p(udaje$BEV_PHEV), main = "log1p(BEV_PHEV)", col = "darkgreen", horizontal = TRUE)
boxplot(log1p(udaje$HDP), main = "log1p(HDP)", col = "lightblue", horizontal = TRUE)
par(mfrow = c(1, 1))

Boxplot zobrazuje rozdelenie premennej – hrubá čiara v strede je
medián, „krabička“ (box) je IQR (od 1. po 3. kvartil), „fúzy“ ukazujú
typický rozsah a bodky mimo sú odľahlé hodnoty. V našich grafoch je EPI
sústredené okolo ~70 s jedným nižším outlierom; po log-transformácii sú
log1p(BEV) a log1p(BEV_PHEV) pekne stabilné a symetrické (bez dlhých
chvostov) a log1p(HDP) má veľmi úzky rozsah – bude slúžiť najmä ako
kontrola úrovne rozvoja.
Lineárna regresia (dve alternatívy)
Motivácia výberu špecifikácie: EPI je
zložený index a elektromobilita môže byť korelovaná s celkovou
vyspelosťou krajiny. Preto zahrniem HDP ako kontrolu. Keďže
BEV a BEV_PHEV spolu silno súvisia, odhadujem
ich oddelené modely, aby som predišla kolinearite.
Koeficienty interpretujem ako semi‑elasticity: zmena v
log1p(x) približne zodpovedá percentuálnej zmene počtu
vozidiel.
Metóda A (Model A: EPI ~ log1p(BEV) + log1p(HDP))
Overuje, či samotné batériové elektromobily (BEV) súvisia s EPI po
zohľadnení ekonomickej úrovne (HDP). Teda: keď dve krajiny majú rovnaký
HDP, má vyšší počet BEV (v % zmenách – vďaka log1p) spojený vyšší/nižší
EPI?
Metóda B (Model B: EPI ~ log1p(BEV_PHEV) +
log1p(HDP)) Overuje vzťah medzi EPI a celkovým rozšírením
(P)HEV (BEV + plug-in hybridy), opäť pri rovnakej úrovni HDP. Tento
model hovorí, čo spraví spoločný“ (P)HEV indikátor s EPI.
Aby som sa vyhla kolinearite, odhadujem dve špecifikácie zvlášť:
# Model A: EPI ~ log1p(BEV) + log1p(HDP)
m_bev <- lm(EPI ~ log1p(BEV) + log1p(HDP), data = udaje)
# Model B: EPI ~ log1p(BEV_PHEV) + log1p(HDP)
m_phev <- lm(EPI ~ log1p(BEV_PHEV) + log1p(HDP), data = udaje)
summary(m_bev)
Call:
lm(formula = EPI ~ log1p(BEV) + log1p(HDP), data = udaje)
Residuals:
Min 1Q Median 3Q Max
-15.1351 -4.4467 -0.8368 4.9316 15.2734
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -16.7362 36.6646 -0.456 0.65016
log1p(BEV) -3.6278 0.6707 -5.409 2.09e-06 ***
log1p(HDP) 11.6591 4.0185 2.901 0.00564 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 7.358 on 47 degrees of freedom
Multiple R-squared: 0.3839, Adjusted R-squared: 0.3577
F-statistic: 14.64 on 2 and 47 DF, p-value: 1.14e-05
summary(m_phev)
Call:
lm(formula = EPI ~ log1p(BEV_PHEV) + log1p(HDP), data = udaje)
Residuals:
Min 1Q Median 3Q Max
-15.005 -4.389 -1.012 4.244 14.395
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -24.7863 35.9496 -0.689 0.49392
log1p(BEV_PHEV) -3.8147 0.6564 -5.811 5.19e-07 ***
log1p(HDP) 12.8282 3.9667 3.234 0.00224 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 7.149 on 47 degrees of freedom
Multiple R-squared: 0.4184, Adjusted R-squared: 0.3936
F-statistic: 16.9 on 2 and 47 DF, p-value: 2.947e-06
# Robustné SE (HC1)
coeftest(m_bev, vcov = vcovHC(m_bev, type = "HC1"))
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -16.73620 37.34531 -0.4481 0.656106
log1p(BEV) -3.62776 0.76151 -4.7639 1.86e-05 ***
log1p(HDP) 11.65906 4.11228 2.8352 0.006733 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
coeftest(m_phev, vcov = vcovHC(m_phev, type = "HC1"))
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -24.78627 37.46093 -0.6617 0.511422
log1p(BEV_PHEV) -3.81473 0.77914 -4.8961 1.194e-05 ***
log1p(HDP) 12.82820 4.15931 3.0842 0.003413 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Porovnanie kvality
aic_tbl <- AIC(m_bev, m_phev)
aic_tbl
# Zvolený model na diagnostiku
model <- m_phev
Z lineárnych regresií vychádza, že HDP na obyvateľa má na EPI
pozitívny a štatisticky významný vplyv, kým počet (P)HEV (a podobne aj
samotných BEV) je záporný a významný po zohľadnení HDP; model s BEV_PHEV
sedí mierne lepšie (nižšie AIC) a závery sa nemenia ani pri robustných
smerodajných chybách. Modely vysvetľujú zhruba 38–42 % variability
EPI.
# ak m_lin ešte neexistuje, použijem lineárny model s (P)HEV
if (!exists("m_lin")) m_lin <- m_phev
# 1) Skontrolujeme a prípadne opravíme názov stĺpca EPI
if (!"EPI" %in% names(udaje)) {
col_epi <- grep("^EPI\\b", names(udaje), value = TRUE)[1]
if (!is.na(col_epi)) names(udaje)[names(udaje) == col_epi] <- "EPI"
}
# 2) Vyberieme model, z ktorého chceme predikovať
mod <- m_lin # <- prípadne zmeň na: m_phev, m_slope, m_quad, ...
# 3) Predikčná krivka: EPI ~ BEV_PHEV pri mediáne HDP
pdat <- data.frame(
BEV_PHEV = seq(min(udaje$BEV_PHEV, na.rm = TRUE),
max(udaje$BEV_PHEV, na.rm = TRUE),
length.out = 200),
HDP = median(udaje$HDP, na.rm = TRUE)
)
pr <- predict(mod, newdata = pdat, se.fit = TRUE)
pdat$yhat <- pr$fit
pdat$lo <- pr$fit - 1.96 * pr$se.fit
pdat$hi <- pr$fit + 1.96 * pr$se.fit
library(ggplot2)
ggplot(pdat, aes(x = BEV_PHEV, y = yhat)) +
geom_ribbon(aes(ymin = lo, ymax = hi), alpha = 0.2) +
geom_line() +
labs(x = "BEV_PHEV", y = "Predikované EPI",
title = "EPI vs. (P)HEV (pri mediáne HDP)") +
theme_minimal()

Graf ukazuje predikovaný EPI v závislosti od počtu (P)HEV pri
fixovanom (mediánovom) HDP z nášho semi-log modelu. Krivka má zreteľne
klesajúci a splošťujúci sa tvar: pri nízkych hodnotách (P)HEV je pokles
EPI strmší, no s rastúcim (P)HEV sa účinok zmierňuje (diminishing
returns), čo je typické pre špecifikáciu s log(1+(P)HEV. Šedé pásmo
vyznačuje 95 % interval predikcie a smerom k vyšším hodnotám sa
rozširuje, teda neistota rastie (v tých oblastiach máme menej pozorovaní
alebo väčší rozptyl). Celkovo graf vizuálne potvrdzuje negatívnu
asociáciu medzi rozšírením (P)HEV a EPI v našich dátach po zohľadnení
HDP; ide o asociáciu, nie dôkaz kauzality.
Diagnostika (krajšie grafy)
Residuals vs Fitted
– ukazuje, či model nechýba tvar (nelinearita) a či sú chyby
rovnomerne okolo nuly. Hľadáme „náhodný mrak“ bez vzoru.
Normal Q–Q
– porovnáva rozdelenie rezíduí s ideálnou normálnou krivkou; body pri
priamke = približná normalita, odchýlky v chvostoch signalizujú
extrémy.
Scale–Location (√|štandardizované rezíduá| vs. fitted)
– test rovnakého rozptylu chýb (homoskedasticita). Rovná LOESS krivka
≈ konštantný rozptyl; stúpajúci/lievik = heteroskedasticita.
Residuals vs Leverage
– identifikuje vplyvné pozorovania: kombinácia veľkého „leverage“
(hat hodnoty) a veľkých rezíduí. Pomáha rozhodnúť, či niekoľko bodov
neťahá regresnú priamku (podľa Cookovej vzdialenosti).
clr <- "#0E6B4D"
# diagnostický dataframe
diag_df <- augment(model) %>% mutate(id = dplyr::row_number())
cook_cut <- 4 / nrow(diag_df)
lab_df <- dplyr::filter(diag_df, .cooksd > cook_cut)
p1 <- ggplot(diag_df, aes(.fitted, .resid)) +
geom_hline(yintercept = 0, linetype = "dashed", color = "grey60") +
geom_point(alpha = .75, color = clr) +
geom_smooth(method = "loess", se = FALSE, color = clr) +
labs(title = "Residuals vs Fitted", x = "Fitted values", y = "Residuals") +
theme_minimal(base_size = 12) + theme(plot.title = element_text(face = "bold"))
p2 <- ggplot(diag_df, aes(sample = .std.resid)) +
stat_qq(color = clr, alpha = .9) +
stat_qq_line(color = "grey45") +
labs(title = "Normal Q–Q", x = "Theoretical Quantiles", y = "Standardized residuals") +
theme_minimal(base_size = 12) + theme(plot.title = element_text(face = "bold"))
p3 <- ggplot(diag_df, aes(.fitted, sqrt(abs(.std.resid)))) +
geom_point(alpha = .75, color = clr) +
geom_smooth(method = "loess", se = FALSE, color = clr) +
labs(title = "Scale–Location", x = "Fitted values",
y = expression(sqrt("|Standardized residuals|"))) +
theme_minimal(base_size = 12) + theme(plot.title = element_text(face = "bold"))
p4 <- ggplot(diag_df, aes(.hat, .std.resid)) +
geom_hline(yintercept = 0, linetype = "dashed", color = "grey60") +
geom_point(alpha = .75, color = clr) +
geom_smooth(method = "loess", se = FALSE, color = clr) +
geom_text(data = lab_df, aes(label = id), vjust = -0.5, size = 3) +
labs(title = "Residuals vs Leverage", x = "Hat values", y = "Standardized residuals") +
theme_minimal(base_size = 12) + theme(plot.title = element_text(face = "bold"))
(p1 + p2) / (p3 + p4)

Diagnostika – čítanie grafov:
- Residuals vs Fitted: jemná nelinearita a mierne kolísanie
rozptylu.
- Q–Q: drobné odchýlky v chvostoch → približná
normalita.
- Scale–Location: slabá heteroskedasticita → použijem
robustné SE.
- Residuals vs Leverage: zopár vplyvných bodov (označené ID),
ale bez extrémov.
Keď zohľadníme HDP, viac (P)HEV sa v našich dátach spája s nižším
EPI. Kontrolné grafy neukázali vážne problémy a drobné odchýlky sme
pokryli robustnými chybami, takže výsledok berieme ako spoľahlivý.
Vplyvné pozorovania
influencePlot(model, main = "Influence plot")

outlierTest(model) # Bonferroni p-value
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:
Krátke čítanie grafu a tabuľky:
Influence plot (bubble chart)
-X-os (Hat-values) = „páka“ (leverage): ak je bod viac vpravo, má
neštandardnú kombináciu vysvetľujúcich premenných a vie viac strhnúť
priamku.
-Y-os (Studentized residuals) = veľkosť chyby: nad +2 alebo pod −2 je
podozrivé.
-Veľkosť/odtieň bubliny = Cookovo D: čím väčšia a tmavšia bublina,
tým väčší vplyv jednotky na odhad celého modelu.
Graf vplyvu ukazuje niekoľko pozorovaní s vyššou „pákou“ a vplyvom
(najmä body 31, 41 a 20), no zostávajú v rozumných medziach; Cookovo D
nie je extrémne a hodnoty študentizovaných rezíduí sa pohybujú okolo
hraníc ±2. Formálny outlierTest pritom nenašiel žiadny štatisticky
významný odľahlý bod po Bonferroni korekcii (najväčší |rstudent| má bod
20 ≈ −2.30, neopravené p ~ 0.026, po korekcii nevýznamné). Inými
slovami: v dátach sú jednotky, ktoré majú citeľnejší vplyv na odhad, ale
nemáme dôkaz o skutočných outlieroch # Dodatočné porovnanie modelov
# Model A: EPI ~ log1p(BEV) + HDP (bez log na HDP – ako kontrola úrovne)
m_bev2 <- lm(EPI ~ log1p(BEV) + HDP, data = udaje)
# Model B: EPI ~ log1p(BEV_PHEV) + HDP
m_phev2 <- lm(EPI ~ log1p(BEV_PHEV) + HDP, data = udaje)
summary(m_bev2); coeftest(m_bev2, vcov = vcovHC(m_bev2, type = "HC1"))
Call:
lm(formula = EPI ~ log1p(BEV) + HDP, data = udaje)
Residuals:
Min 1Q Median 3Q Max
-15.0909 -4.1711 -0.7445 5.2535 14.7114
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 86.8956784 4.7398188 18.333 < 2e-16 ***
log1p(BEV) -3.5939951 0.6665698 -5.392 2.21e-06 ***
HDP 0.0005466 0.0001900 2.877 0.00603 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 7.367 on 47 degrees of freedom
Multiple R-squared: 0.3823, Adjusted R-squared: 0.356
F-statistic: 14.54 on 2 and 47 DF, p-value: 1.211e-05
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 86.89567837 5.43343513 15.9928 < 2.2e-16 ***
log1p(BEV) -3.59399513 0.75667089 -4.7497 1.95e-05 ***
HDP 0.00054656 0.00019420 2.8144 0.007115 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
summary(m_phev2); coeftest(m_phev2, vcov = vcovHC(m_phev2, type = "HC1"))
Call:
lm(formula = EPI ~ log1p(BEV_PHEV) + HDP, data = udaje)
Residuals:
Min 1Q Median 3Q Max
-14.8667 -4.2839 -0.6805 4.3720 13.7936
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 89.2739287 4.7887883 18.642 < 2e-16 ***
log1p(BEV_PHEV) -3.8005552 0.6530506 -5.820 5.04e-07 ***
HDP 0.0006089 0.0001877 3.243 0.00218 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 7.145 on 47 degrees of freedom
Multiple R-squared: 0.419, Adjusted R-squared: 0.3942
F-statistic: 16.94 on 2 and 47 DF, p-value: 2.877e-06
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 89.27392868 5.80102043 15.3893 < 2.2e-16 ***
log1p(BEV_PHEV) -3.80055516 0.78549751 -4.8384 1.45e-05 ***
HDP 0.00060888 0.00019776 3.0789 0.003464 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
AIC(m_bev2, m_phev2)
Po zohľadnení HDP vychádza negatívna asociácia EPI s (P)HEV aj s BEV;
mierne lepšie sedí špecifikácia s BEV_PHEV.
Oneskorený vplyv (lag 1 rok) s fixnými efektmi
Prečo lag: zmeny v zložení vozového parku a budovaní
infraštruktúry sa nemusia okamžite premietnuť do EPI. Jednoročný lag
BEV_PHEV s fixnými efektmi krajín a rokov
zachytáva nepozorovanú heterogenitu a spoločné šoky.
udaje_lag <- udaje %>%
arrange(Krajina, Rok) %>%
group_by(Krajina) %>%
mutate(lag_BEV_PHEV = dplyr::lag(BEV_PHEV, 1)) %>%
ungroup()
m_lag <- lm(EPI ~ log1p(lag_BEV_PHEV) + HDP + factor(Krajina) + factor(Rok), data = udaje_lag)
coeftest(m_lag, vcov = vcovCL(m_lag, cluster = ~ Krajina, type = "HC1"))
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 50.8959137 65.0340670 0.7826 0.4399939
log1p(lag_BEV_PHEV) -2.0425584 1.5285689 -1.3363 0.1915136
HDP 0.0020646 0.0038335 0.5386 0.5941504
factor(Krajina)EU-avrg -20.6979705 37.5633150 -0.5510 0.5857037
factor(Krajina)MR 9.5261676 25.1708980 0.3785 0.7077543
factor(Krajina)PL 7.3166762 26.7654445 0.2734 0.7864475
factor(Krajina)SK 4.1908401 12.0927337 0.3466 0.7313421
factor(Rok)2016 9.5399727 2.4016859 3.9722 0.0004121 ***
factor(Rok)2017 -1.4413973 3.0279243 -0.4760 0.6374981
factor(Rok)2018 -8.1105733 5.3325433 -1.5210 0.1387416
factor(Rok)2019 -10.1512429 6.6783228 -1.5200 0.1389742
factor(Rok)2020 -7.7457174 3.0950422 -2.5026 0.0180056 *
factor(Rok)2021 -15.1063011 6.3794152 -2.3680 0.0245284 *
factor(Rok)2022 -18.9950331 7.2001178 -2.6382 0.0130861 *
factor(Rok)2023 -6.9375471 8.2719932 -0.8387 0.4082826
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Aj keď sa pozrieme na oneskorený (1-ročný) efekt a zafixujeme
rozdiely medzi krajinami a rokmi, nevidíme štatistický dôkaz, že viac
(P)HEV zlepší EPI—koeficient je síce negatívny, ale nevýznamný. Pre našu
prácu to znamená, že hlavný záver zostáva rovnaký: po zohľadnení HDP (a
pri FE) sa v dostupných dátach V4 nepotvrdzuje krátkodobý pozitívny
vplyv rozšírenia (P)HEV na EPI. Model teda skôr hovorí, že EPI formujú
aj iné, širšie faktory než samotná elektromobilita
Štandardizované koeficienty
Zmysel: po štandardizácii viem porovnať
veľkosť efektov naprieč rozdielnymi mierkami (SD jednotky).
m_std <- lm(scale(EPI) ~ scale(log1p(BEV_PHEV)) + scale(HDP), data = udaje)
summary(m_std)
Call:
lm(formula = scale(EPI) ~ scale(log1p(BEV_PHEV)) + scale(HDP),
data = udaje)
Residuals:
Min 1Q Median 3Q Max
-1.61936 -0.46663 -0.07412 0.47622 1.50247
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.914e-16 1.101e-01 0.000 1.00000
scale(log1p(BEV_PHEV)) -7.921e-01 1.361e-01 -5.820 5.04e-07 ***
scale(HDP) 4.414e-01 1.361e-01 3.243 0.00218 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.7783 on 47 degrees of freedom
Multiple R-squared: 0.419, Adjusted R-squared: 0.3942
F-statistic: 16.94 on 2 and 47 DF, p-value: 2.877e-06
Po štandardizácii vychádza, že log1p(BEV_PHEV) má silnejší vplyv na
EPI a je negatívny (~−0.79 SD za +1 SD v (P)HEV), kým HDP je pozitívne
(~+0.44 SD za +1 SD v HDP); oba efekty sú štatisticky významné.
Intercept je ~0 (lebo premenné sú centrované) a model vysvetľuje ~42 %
variability EPI. Inými slovami: v našich dátach sa zmeny v (P)HEV
spájajú s väčším (negatívnym) posunom EPI než rovnako veľké zmeny v HDP
s pozitívnym smerom.
Heteroskedasticita – testy a grafy
Heteroskedasticita = rozptyl chýb nie je všade rovnaký. Ak by bola
výrazná, bežné p-hodnoty môžu byť skreslené. Nižšie ju rýchlo overím
(grafy + testy) a zohľadním cez robustné štandardné chyby (HC1).
Vizuálna diagnostika
library(broom); library(ggplot2); library(patchwork); clr <- "#0E6B4D"
h <- augment(model, data = udaje) |>
dplyr::mutate(
absres = sqrt(abs(.std.resid)),
res2 = .resid^2,
x_bev = log1p(.data$BEV_PHEV), # ak používame BEV: log1p(.data$BEV)
x_hdp = .data$HDP
)
p_SL <- ggplot(h, aes(.fitted, absres)) +
geom_point(alpha=.65) +
geom_smooth(method="loess", se=FALSE, linewidth=1, color=clr) +
labs(x="Predikované hodnoty", y=expression(sqrt("|rezíduá|")), title="Scale–Location") +
theme_minimal()
p_bev <- ggplot(h, aes(x_bev, res2)) +
geom_point(alpha=.65) +
geom_smooth(method="loess", se=FALSE, linewidth=1, color=clr) +
labs(x="log1p(BEV_PHEV)", y="rezíduá^2", title="Rezíduá^2 vs. log1p(BEV_PHEV)") +
theme_minimal()
p_hdp <- ggplot(h, aes(x_hdp, res2)) +
geom_point(alpha=.65) +
geom_smooth(method="loess", se=FALSE, linewidth=1, color=clr) +
labs(x="HDP", y="rezíduá^2", title="Rezíduá^2 vs. HDP") +
theme_minimal()
p_SL / (p_bev | p_hdp)

LOESS krivka v Scale–Location má jemné „U“ – rozptyl rezíduí je
najmenší pri stredných predikciách a väčší na okrajoch, takže ide o
miernu heteroskedasticitu. Vo vzťahu rezíduá² vs. log1p(BEV_PHEV) je
U-tvar len plytký, čiže s (P)HEV súvisí rozptyl skôr slabo. Naopak, graf
rezíduá² vs. HDP ukazuje výraznejší U-tvar: variancia je najnižšia pri
stredných hodnotách HDP a rastie pri nízkych aj vysokých, čo naznačuje,
že prípadná heteroskedasticita je viazaná najmä na HDP. Celkovo nejde o
silné porušenie, ale je rozumné používať robustné štandardné chyby
(HC1); nižšie to ešte overíme formálnymi testami.
library(ggplot2)
library(patchwork)
# model, ktorý chceme diagnostikovať
mod <- m_phev # EPI ~ log1p(BEV_PHEV) + log1p(HDP)
dta <- udaje
# vypočítam rezíduá a pripravím log premennú pre BEV_PHEV (aby sedela s modelom)
dta$resid2 <- resid(mod)^2
dta$logBEVP <- log1p(dta$BEV_PHEV)
# 1) Rezíduá^2 vs. log1p(BEV_PHEV)
p_bev <- ggplot(dta, aes(x = logBEVP, y = resid2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "firebrick") +
labs(x = "log1p(BEV_PHEV)", y = "Štvorce rezíduí",
title = "Rezíduá^2 vs. log1p(BEV_PHEV)") +
theme_minimal()
# 2) Rezíduá^2 vs. HDP (pozor: v modeli je log(HDP) – tu úmyselne dávame aj „raw“ HDP,
# aby bolo jasne vidno, či problém súvisí s úrovňou bohatstva)
p_hdp <- ggplot(dta, aes(x = HDP, y = resid2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "firebrick") +
labs(x = "HDP na obyvateľa", y = "Štvorce rezíduí",
title = "Rezíduá^2 vs. HDP") +
theme_minimal()
p_bev | p_hdp

Z týchto dvoch grafov vidno, že veľkosť chýb (štvorce rezíduí) nie je
všade rovnaká. Červená LOESS krivka má v oboch prípadoch tvar jemného
„U“ – rozptyl rezíduí je najmenší v strede a väčší pri veľmi nízkych aj
veľmi vysokých hodnotách. Efekt je zreteľnejší pri HDP, čo naznačuje, že
nerovnaký rozptyl chýb súvisí skôr s úrovňou bohatstva krajín než s
počtom (P)HEV. Nie je to extrémny „lievik“, ale ide o miernu
heteroskedasticitu.
Heteroskedasticita - prehľad testov
library(lmtest); library(car); library(dplyr); library(knitr)
bp_fitted <- bptest(model)
bp_white <- bptest(model, ~ fitted(model) + I(fitted(model)^2))
ncv <- ncvTest(model)
tribble(
~Test, ~Statistic, ~p_value,
"Breusch–Pagan", unname(bp_fitted$statistic), bp_fitted$p.value,
"BP (White štýl)", unname(bp_white$statistic), bp_white$p.value,
"NCV (car)", unname(ncv$ChiSquare), ncv$p
) |>
mutate(across(c(Statistic, p_value), ~round(.x, 4))) |>
kable(caption = "Heteroskedasticita – prehľad testov")
Heteroskedasticita – prehľad testov
| Test |
Statistic |
p_value |
| Breusch–Pagan |
0.4876 |
0.7836 |
| BP (White štýl) |
5.6585 |
0.0591 |
| NCV (car) |
0.0032 |
0.9545 |
Nelineárne špecifikácie a testy funkčnej formy
Prečo toto robíme? Doteraz sme predpokladali, že vzťah medzi EPI a
vysvetľujúcimi premennými (log1p(BEV_PHEV), log1p(HDP)) je lineárny.
Nižšie skontrolujeme, či obyčajná „priamka“ naozaj stačí – a ak nie,
pridáme jemné zakrivenie (kvadráty) alebo zlom v sklone (iný efekt pri
vyšších hodnotách (P)HEV).
Zjednodušene: RESET test: rýchla kontrola,
či priamka stačí. Malá p-hodnota ⇒ pridať nelineárne prvky. C+R
grafy: ukážu, kde sa krivka ohýba – ktorú premennú
transformovať. Kvadráty log-premenných: dovolia jemné
zakrivenie. Zlom v sklone: dovolí iný vplyv (P)HEV pri
nižších vs. vyšších hodnotách. Výber modelu: porovnáme
AIC a (ak sú modely v tej istej mierke) aj ANOVA; koeficienty vždy s
robustnými SE (HC1).
1) Ramsey RESET – kontrola špecifikácie
library(lmtest)
# Základný (lineárny) model – používame ten, s ktorým pracuješ v práci:
m_lin <- lm(EPI ~ log1p(BEV_PHEV) + log1p(HDP), data = udaje)
# Ramsey RESET test
resettest(m_lin)
RESET test
data: m_lin
RESET = 4.9787, df1 = 2, df2 = 45, p-value = 0.01114
RESET vyšiel p = 0.011 → základná lineárna špecifikácia pravdepodobne
chýba (nelinearita/nezahrnutý tvar). Preto ďalej cielene hľadáme kde by
sa mohla krivka ohýbať a či sa oplatí pridať kvadráty alebo zlom.
2) Component + Residual (C+R) grafy – kde sa krivka ohýba
library(car)
car::crPlots(m_lin) # pozrieme zakrivenie pri log1p(BEV_PHEV) a log1p(HDP)

C+R pre log1p(BEV_PHEV) ukazuje citeľné prehnutie okolo ~7–9 →
kandidát na nelineárny tvar. C+R pre log1p(HDP) je prakticky priamka
(len jemná krivka), takže výraznu nelinearitu pri HDP nečakáme. Z toho
dôvodu testujeme hlavne úpravy pri (P)HEV.
3) Kvadratické členy – jemné zakrivenie
library(sandwich)
library(lmtest)
m_quad <- lm(EPI ~ log1p(BEV_PHEV) + I(log1p(BEV_PHEV)^2) +
log1p(HDP) + I(log1p(HDP)^2),
data = udaje)
# Porovnanie kvality (nižší AIC je lepší)
AIC(m_lin, m_quad)
# ANOVA:
anova(m_lin, m_quad)
Analysis of Variance Table
Model 1: EPI ~ log1p(BEV_PHEV) + log1p(HDP)
Model 2: EPI ~ log1p(BEV_PHEV) + I(log1p(BEV_PHEV)^2) + log1p(HDP) + I(log1p(HDP)^2)
Res.Df RSS Df Sum of Sq F Pr(>F)
1 47 2402.1
2 45 2286.6 2 115.48 1.1363 0.3301
# Koeficienty s robustnými SE (HC1)
coeftest(m_lin, vcov = vcovHC(m_lin, type = "HC1"))
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -24.78627 37.46093 -0.6617 0.511422
log1p(BEV_PHEV) -3.81473 0.77914 -4.8961 1.194e-05 ***
log1p(HDP) 12.82820 4.15931 3.0842 0.003413 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
coeftest(m_quad, vcov = vcovHC(m_quad, type = "HC1"))
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1175.79233 1220.85177 0.9631 0.3406
log1p(BEV_PHEV) 3.88313 6.57887 0.5902 0.5580
I(log1p(BEV_PHEV)^2) -0.44168 0.38178 -1.1569 0.2534
log1p(HDP) -236.25676 249.85488 -0.9456 0.3494
I(log1p(HDP)^2) 12.57104 12.62555 0.9957 0.3247
AIC sa zhoršil (345.0 vs. 343.5).
ANOVA: p = 0.33 → kvadráty nezlepšujú model.
Robustné SE (HC1): kvadratické koeficienty
nevýznamné.
Záver: kvadráty nepriniesli prínos – nelinearitu
takto nepotvrdzujeme.
4) Zlom v sklone – iný efekt (P)HEV pri vyšších hodnotách
# Prah: medián log1p(BEV_PHEV)
cut_bev <- median(log1p(udaje$BEV_PHEV), na.rm = TRUE)
udaje$D_highBEV <- as.integer(log1p(udaje$BEV_PHEV) >= cut_bev)
# (a) len posun (intercept shift)
m_shift <- lm(EPI ~ D_highBEV + log1p(BEV_PHEV) + log1p(HDP), data = udaje)
# (b) zlom v sklone (interakcia premenná × dummy)
m_slope <- lm(EPI ~ log1p(BEV_PHEV)*D_highBEV + log1p(HDP), data = udaje)
# Porovnanie AIC
AIC(m_lin, m_shift, m_slope)
# ANOVA (rovnaká vysvetľovaná premenná)
anova(m_lin, m_shift)
Analysis of Variance Table
Model 1: EPI ~ log1p(BEV_PHEV) + log1p(HDP)
Model 2: EPI ~ D_highBEV + log1p(BEV_PHEV) + log1p(HDP)
Res.Df RSS Df Sum of Sq F Pr(>F)
1 47 2402.1
2 46 2366.4 1 35.666 0.6933 0.4093
anova(m_lin, m_slope)
Analysis of Variance Table
Model 1: EPI ~ log1p(BEV_PHEV) + log1p(HDP)
Model 2: EPI ~ log1p(BEV_PHEV) * D_highBEV + log1p(HDP)
Res.Df RSS Df Sum of Sq F Pr(>F)
1 47 2402.1
2 45 2348.1 2 53.993 0.5174 0.5996
# Robustné SE
coeftest(m_slope, vcov = vcovHC(m_slope, type = "HC1"))
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -29.6808 39.5065 -0.7513 0.456389
log1p(BEV_PHEV) -2.5330 1.5078 -1.6798 0.099918 .
D_highBEV 7.4189 20.1690 0.3678 0.714720
log1p(HDP) 12.4336 4.3666 2.8474 0.006619 **
log1p(BEV_PHEV):D_highBEV -1.1895 2.1857 -0.5442 0.588969
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Prah = medián log1p(BEV_PHEV). Skúsili sme (a) posun priamky a (b)
zmenu sklonu (interakcia s dummy):
AIC je vyšší než v lineárnom modeli (horšie).
ANOVA: posun p = 0.41, zmena sklonu p = 0.52.
Robustné SE: interakcia nevýznamná.
Záver: dôkaz pre odlišný efekt (P)HEV pri „vyšších“
úrovniach sme nenašli.
5) Výber pracovného modelu a krátke zhrnutie
Keďže (i) RESET síce naznačil nesprávnu špecifikáciu, ale (ii) C+R
ukázal len jemné ohyby a (iii) ani kvadráty, ani zlom štatisticky
nezlepšili model, ako pracovný model ponechávame základnú lineárnu
špecifikáciu s robustnými chybami (HC1). V nej vychádza log1p(BEV_PHEV)
negatívne a významne, kým log1p(HDP) pozitívne a významne. Prakticky: v
tomto súbore dát V4 nevychádza, že by mierne zakrivenia alebo prahové
efekty menili hlavné závery; ak je nelinearita prítomná, je skôr slabá a
naše testy ju nevedia presvedčivo uchopiť (limit vzorky).
Porovnávacia tabuľka modelov
# istota, že máme základný lineárny model
if (!exists("m_lin")) {
m_lin <- lm(EPI ~ log1p(BEV_PHEV) + log1p(HDP), data = udaje)
}
mods <- list("Lineárny" = m_lin)
if (exists("m_quad")) mods[["Kvadratický"]] <- m_quad
if (exists("m_slope")) mods[["Zlom v sklone"]] <- m_slope
if (exists("m_shift")) mods[["Posun úrovne"]] <- m_shift
library(purrr); library(lmtest); library(dplyr); library(kableExtra)
reset_p <- function(m) tryCatch(resettest(m)$p.value, error = function(e) NA_real_)
anova_vs_base <- function(m, base) {
if (identical(formula(base)[[2]], formula(m)[[2]])) as.numeric(anova(base, m)$`Pr(>F)`[2]) else NA_real_
}
base_model <- mods[["Lineárny"]]
cmp_tbl <- tibble(
model = names(mods),
AIC = map_dbl(mods, AIC),
adjR2 = map_dbl(mods, ~ summary(.x)$adj.r.squared),
RESET_p = map_dbl(mods, reset_p),
ANOVA_vs_lin_p = map_dbl(mods, ~ anova_vs_base(.x, base_model))
) %>% arrange(AIC)
kbl(cmp_tbl, digits = 3, caption = "Porovnanie špecifikácií (nižšie AIC je lepšie)") %>%
kable_classic(full_width = FALSE)
Porovnanie špecifikácií (nižšie AIC je lepšie)
| model |
AIC |
adjR2 |
RESET_p |
ANOVA_vs_lin_p |
| Lineárny |
343.498 |
0.394 |
0.011 |
NA |
| Posun úrovne |
344.750 |
0.390 |
0.025 |
0.409 |
| Kvadratický |
345.035 |
0.397 |
0.007 |
0.330 |
| Zlom v sklone |
346.361 |
0.381 |
0.032 |
0.600 |
NA
Graf predikčných kriviek (Lineárny vs. Kvadratický vs. Zlom)
# Predikcie pri mediáne HDP
x_grid <- tibble(
BEV_PHEV = seq(min(udaje$BEV_PHEV, na.rm = TRUE),
max(udaje$BEV_PHEV, na.rm = TRUE),
length.out = 200),
HDP = median(udaje$HDP, na.rm = TRUE)
)
pred_one <- function(m, name) {
# (ak model potrebuje dummy D_highBEV, dopočítame ju podľa prahu, ktorý používame v práci)
newdat <- x_grid
if ("D_highBEV" %in% names(model.frame(m))) {
cut_bev <- median(log1p(udaje$BEV_PHEV), na.rm = TRUE)
newdat$D_highBEV <- as.integer(log1p(newdat$BEV_PHEV) >= cut_bev)
}
pr <- predict(m, newdata = newdat, se.fit = TRUE)
tibble(model = name,
BEV_PHEV = newdat$BEV_PHEV,
fit = pr$fit,
lo = pr$fit - 1.96*pr$se.fit,
hi = pr$fit + 1.96*pr$se.fit)
}
pred_all <- bind_rows(
pred_one(m_lin, "Lineárny"),
pred_one(m_quad, "Kvadratický"),
pred_one(m_slope,"Zlom v sklone")
)
ggplot(pred_all, aes(BEV_PHEV, fit, color = model, fill = model)) +
geom_ribbon(aes(ymin = lo, ymax = hi), alpha = 0.10, color = NA) +
geom_line(size = 1) +
labs(x = "(P)HEV (počet)", y = "Predikované EPI",
title = "Predikčné krivky: EPI vs. (P)HEV pri mediáne HDP",
subtitle = "Porovnanie špecifikácií (lineárny, kvadratický, zlom v sklone)") +
theme_minimal() +
theme(legend.position = "bottom")

Graf porovnáva predikčné krivky EPI vs. (P)HEV pri mediánovom HDP pre
tri špecifikácie (lineárna v loge, kvadratická, a „zlom v sklone“).
Všetky tri modely ukazujú rovnaký príbeh: s rastúcim (P)HEV EPI klesá a
efekt sa postupne splošťuje (najmä pri nízkych hodnotách je pokles
strmší). Rozdiely medzi krivkami sú malé – kvadratická verzia je o niečo
prudšia v chvoste, zatiaľ čo „zlom v sklone“ sa prakticky prekrýva s
lineárnym modelom. Intervaly neistoty (priesvitné pásma) sa rozširujú v
extrémoch, kde je menej dát. Spolu s výsledkami AIC/ANOVA vyššie to
naznačuje, že jednoduchý lineárny model v loge postačuje; prípadné
nelinearity nijako nemenia kvalitatívny záver o negatívnej asociácii
(P)HEV a EPI po zohľadnení HDP.
Stručná tabuľka výsledkov a záver
library(tibble)
library(kableExtra)
## 1) stručná diagnostika
sum_tbl <- tibble::tibble(
`Q–Q plot` = "Väčšina bodov na priamke; len mierne odchýlky v chvostoch.",
`Scale–Location` = "Jemný U-tvar → slabá heteroskedasticita (riešime robustnými SE).",
`Residuals vs Leverage` = "Pár vplyvných bodov, bez extrémov.",
`Heteroskedasticita – testy`= "Breusch–Pagan a NCV nevýznamné; White štýl hraničný → skôr slabý náznak.",
`RESET (špecifikácia)` = "p ≈ 0.011 ⇒ lineárna špecifikácia má známky nesprávnej formy (skúšali sme jemné nelinearity)."
)
emerald_light <- "#ECFDF5"; emerald_head <- "#D1FAE5"; emerald_text <- "#065F46"
kbl(
sum_tbl,
caption = "Diagnostika – stručné zhrnutie",
booktabs = TRUE
) |>
kable_classic(full_width = TRUE, html_font = "Helvetica") |>
row_spec(0, background = emerald_head, color = emerald_text, bold = TRUE) |>
column_spec(1:ncol(sum_tbl), background = emerald_light, color = emerald_text, border_left = TRUE, border_right = TRUE)
Diagnostika – stručné zhrnutie
| Q–Q plot |
Scale–Location |
Residuals vs Leverage |
Heteroskedasticita – testy |
RESET (špecifikácia) |
| Väčšina bodov na priamke; len mierne odchýlky v chvostoch. |
Jemný U-tvar → slabá heteroskedasticita (riešime robustnými SE). |
Pár vplyvných bodov, bez extrémov. |
Breusch–Pagan a NCV nevýznamné; White štýl hraničný → skôr slabý náznak. |
p ≈ 0.011 ⇒ lineárna špecifikácia má známky nesprávnej formy (skúšali sme jemné nelinearity). |
## 2) porovnanie špecifikácií (AIC)
# predpoklad: objekty m_lin, m_quad, m_slope sú už odhadnuté v dokumente
aic_tbl <- tryCatch(
{
aa <- AIC(m_lin, m_quad, m_slope)
dplyr::rename(aa, Model = df, AIC = AIC) |>
dplyr::mutate(Model = rownames(aa))
},
error = function(e) tibble::tibble(
Model = c("Lineárny", "Kvadratický", "Zlom v sklone"),
AIC = c(343.50, 345.03, 346.36) # hodnoty z tvojich výstupov
)
)
kbl(aic_tbl, caption = "Porovnanie kvality modelov (nižší AIC = lepší)", booktabs = TRUE) |>
kable_classic(full_width = FALSE, html_font = "Helvetica") |>
row_spec(0, background = emerald_head, color = emerald_text, bold = TRUE) |>
column_spec(1:ncol(aic_tbl), background = emerald_light, color = emerald_text)
Porovnanie kvality modelov (nižší AIC = lepší)
| |
Model |
AIC |
| m_lin |
m_lin |
343.4979 |
| m_quad |
m_quad |
345.0346 |
| m_slope |
m_slope |
346.3613 |
## 3) hypotézy
hyp_tbl <- tibble::tribble(
~Premenná, ~`H1 (očakávanie)`, ~`Rozhodnutie o H0`, ~`Rozhodnutie o H1`, ~Poznámka,
"BEV", "β > 0", "NEZAMIETAM / neisté", "NEPODPORUJEME", "Efekt nevýznamný alebo záporný.",
"BEV_PHEV", "β > 0", "ZAMIETAM (významné, záporné)", "ZAMIETAM (pozitívny sa nepotvrdil)","log1p(BEV_PHEV) stabilne negatívny s HC1.",
"HDP", "β > 0", "ZAMIETAM (významné, pozitívne)", "PODPORUJEME", "HDP vychádza kladne a významne."
)
kbl(hyp_tbl, caption = "Hypotézy a rozhodnutia (robustné SE)", booktabs = TRUE) |>
kable_classic(full_width = FALSE, html_font = "Helvetica") |>
row_spec(0, background = emerald_head, color = emerald_text, bold = TRUE) |>
column_spec(1:ncol(hyp_tbl), background = emerald_light, color = emerald_text)
Hypotézy a rozhodnutia (robustné SE)
| Premenná |
H1 (očakávanie) |
Rozhodnutie o H0 |
Rozhodnutie o H1 |
Poznámka |
| BEV |
β > 0 |
NEZAMIETAM / neisté |
NEPODPORUJEME |
Efekt nevýznamný alebo záporný. |
| BEV_PHEV |
β > 0 |
ZAMIETAM (významné, záporné) |
ZAMIETAM (pozitívny sa nepotvrdil) |
log1p(BEV_PHEV) stabilne negatívny s HC1. |
| HDP |
β > 0 |
ZAMIETAM (významné, pozitívne) |
PODPORUJEME |
HDP vychádza kladne a významne. |
NA
Diskusia, limity a záver
Čo ukázala diagnostika a testy: Rozptyl chýb je
najmä slabo nehomogénny, preto v celej práci reportujeme
robustné smerodajné chyby (HC1). RESET test (p ≈
0.011) signalizoval, že samotná priamka môže byť pre jednoduchý
lineárny model tesná, preto sme skúsili jemné nelinearity (kvadrát
log1p(BEV_PHEV), kvadrát log1p(HDP)) a aj zlom v sklone podľa úrovne
(P)HEV.
Porovnanie špecifikácií: Napriek signálu z RESET-u
sa kvalita modelov nezlepšila – AIC je najnižší pri lineárnom modeli a
ANOVA porovnania kvadratickej/zlomovej špecifikácie voči lineárnej
nevyšli významne. Predikčné krivky pre všetky tri verzie sú tvarovo
podobné (mierne klesajúce), rozdiely sú malé a v rámci intervalov
spoľahlivosti.
Interpretácia účinkov (robustné SE):
log1p(BEV_PHEV) je negatívny a štatisticky významný – v našom
súbore sa s vyšším rozšírením (P)HEV spája nižší EPI.
HDP je pozitívny a významný – krajiny/roky s vyšším HDP dosahujú
vyšší EPI.
Samotné BEV nevyšlo robustne pozitívne.
Zjednodušene: viac (P)HEV ≠ vyšší EPI v krátkom
horizonte; EPI zrejme ovplyvňujú širšie faktory (ekonomická úroveň,
štruktúra energií, zloženie dopravy atď.).
Limity: malá vzorka (V4 × roky), agregačná úroveň,
možná meracia chyba v registroch vozidiel, chýbajúce kontroly
(energetický mix, dopravné výkony, priemysel). Krátke obdobie môže
skrývať oneskorené účinky.
LS0tCnRpdGxlOiAiQW5hbMO9emEgZMOhdCBvIGVsZWt0cm9tb2JpbGl0ZSIKYXV0aG9yOiAiU2ltb25hIFZhbsSNb3bDoSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBjc3M6IFN0eWxlc0dyZWVuLmNzcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIGNzczogU3R5bGVzR3JlZW4uY3NzCi0tLQoKCmBgYHs9aHRtbH0KPHN0eWxlPgovKiBzbWFyYWdkb3ZvIHplbGVuw6EgKi8KaDEsIGgxLnRpdGxlLCAudGl0bGUgeyBjb2xvcjogIzA3NUU1NCAhaW1wb3J0YW50OyB9CmVtLCBpIHsgY29sb3I6ICMwNzVFNTQgIWltcG9ydGFudDsgfQo8L3N0eWxlPgpgYGAKCiMgw5p2b2QKCiAgQ2llxL5vbSBhbmFsw716eSBqZSBwcmVza8O6bWHFpSwgxI1pIHJvesWhw61yZW5pZSAqKmVsZWt0cm9tb2JpbGl0eSB2IGtyYWppbsOhY2ggVjQgc8O6dmlzw60gcyBrdmFsaXRvdSDFvml2b3Ruw6lobyBwcm9zdHJlZGlhIG1lcmFub3UgaW5kZXhvbSBlbnZpcm9ubWVudMOhbG5laiB2w71rb25ub3N0aSAoRVBJKSoqLiBQcmFjdWplbSBzIHByZcSNaXN0ZW7DvW0gcGFuZWxvdsO9bSBkYXRhc2V0b20geiBtb2plaiBiYWthbMOhcnNrZWogcHLDoWNlIChrcmFqaW55IFY0IMOXIHJva3kpLgoKIyMgQ2hhcmFrdGVyaXN0aWthIGTDoXQKCi0gICAqKlpkcm9qIGEgcG9rcnl0aWU6KiogVmxhc3Ruw70gZGF0YXNldCB6b3N0YXZlbsO9IHByZSBCUCAoa3JhamlueSBWNCDDlyByb2t5KS4KLSAgICoqSGxhdm7DqSBwcmVtZW5uw6k6KiogYEVQSWAgKHpsb8W+ZW7DvSBpbmRleCBrdmFsaXR5IMW+aXZvdG7DqWhvIHByb3N0cmVkaWEpLCBgQkVWYCAocG/EjWV0IGJhdMOpcmlvdsO9Y2ggRVYpLCBgQkVWX1BIRVZgIChCRVYgKyBwbHVn4oCRaW4gaHlicmlkeSksIGBIRFBgIG5hIG9ieXZhdGXEvmEuCi0gICAqKlN0YXYgZMOhdDoqKiBEw6F0YSBib2xpICoqcHJlxI1pc3RlbsOpKiogcHJlZCB0w71tdG8gY3ZpxI1lbsOtbTsgdiB0b210byBkb2t1bWVudGUgdcW+IG5lcmllxaFpbWUgaW1wdXRhxI1uw6kgxI1pIMSNaXN0aWFjZSBrcm9reS4KCiMjIFByZW1lbm7DqQoqKlrDoXZpc2zDoSBwcmVtZW5uw6E6KioKKkVQSSog4oCTIHpsb8W+ZW7DvSBpbmRleCBlbnZpcm9ubWVudMOhbG5laiB2w71rb25ub3N0aSBrcmFqw61uLgoKKipLxL7DusSNb3bDqSB2eXN2ZXTEvnVqw7pjZSBwcmVtZW5uw6k6KioKKkJFViog4oCTIHBvxI1ldCBiYXTDqXJpb3bDvWNoIGVsZWt0cm9tb2JpbG92OwoqQkVWX1BIRVYqIOKAkyBzw7rEjWV0IEJFViBhIHBsdWctaW4gaHlicmlkb3YgKFBIRVYpLgoKKipLb250cm9sbsOpIHByZW1lbm7DqToqKgoqSERQIG5hIG9ieXZhdGXEvmEqIChla29ub21pY2vDoSDDunJvdmXFiCk7IHBvZMS+YSBkb3N0dXBub3N0aSBhaiDEj2FsxaFpZSBzcHJpZXZvZG7DqSB1a2F6b3ZhdGVsZSAoQ0/igoIsIGludmVzdGnEjW7DqS9yb3p2b2pvdsOpIGluZGlrw6F0b3J5KS4KCiMjIFbDvXNrdW1uw6Egb3TDoXprYSBhIGh5cG90w6l6eQoKU8O6dmlzw60gdnnFocWhw60gcG/EjWV0IChQKUhFViBzIHZ5xaHFocOtbSBFUEksIHBvIHpvaMS+YWRuZW7DrSBla29ub21pY2tlaiDDunJvdm5lIGtyYWrDrW4/CgotICAgKipIMDoqKiBQb8SNZXQgQkVWL0JFVl9QSEVWICoqbmVtw6EqKiB2w716bmFtbsO9IHZwbHl2IG5hIEVQSS4KLSAgICoqSDE6KiogVnnFocWhw60gQkVWL0JFVl9QSEVWIGplIHNwb2plbsO9IHMgKip2ecWhxaHDrW0qKiBFUEkuCgojIyBNZXRvZGlrYSB2IHNrcmF0a2UKClBvdcW+w612YW0gKipsaW5lw6FybmUgbW9kZWx5IE9MUyoqIHMgbG9n4oCRdHJhbnNmb3Jtw6FjaW91IHBvxI10b3bDvWNoIHByZW1lbm7DvWNoIChgbG9nMXBgKSwgYWJ5IHNhIHN0YWJpbGl6b3ZhbGEgdmFyaWFuY2lhIGEgdGxtaWxpIHNhIGV4dHLDqW15LiBBYnkgc29tIHNhIHZ5aGxhIGtvbGluZWFyaXRlLCBvZGhhZHVqZW0gbW9kZWwgcyBgQkVWYCBhIG1vZGVsIHMgYEJFVl9QSEVWYCAqKm9kZGVsZW5lKio7IGBIRFBgIGZpZ3VydWplIGFrbyBrb250cm9sYSDDunJvdm5lIHJvenZvamEuIERpYWdub3N0aWt1IHJvYsOtbSBjZXogxaF0YW5kYXJkbsOpIGdyYWZ5IChR4oCTUSwgU2NhbGXigJNMb2NhdGlvbiwgTGV2ZXJhZ2UpIGEgZm9ybcOhbG5lIHRlc3R5IChCcmV1c2No4oCTUGFnYW4pLiBJbmZlcmVuY2l1IHJlcG9ydHVqZW0gcyAqKnJvYnVzdG7DvW1pIFNFIChIQzEpKiosIHByw61wYWRuZSBrbGFzdHJvdmFuw71taSBwb2TEvmEga3JhamlueSBwcmkgcGFuZWxvdsO9Y2ggxaFwZWNpZmlrw6FjacOhY2guCgojIFsqKkltcG9ydCDDumRham92IHogbW9qZWogYmFrYWzDoXJza2VqIHByw6FjZSoqXXtzdHlsZT0iY29sb3I6IzA3NUU1NDsgZm9udC13ZWlnaHQ6NzAwOyJ9CgpOYcSNw610YW0gY3N2IHPDumJvciBzICpkw6F0YW1pIG8gZWxla3Ryb21vYmlsaXRlIHZvIFY0KiAocG/EjWV0IEJFViwgQkVWX1BIRVYsIEVQSSwgSERQLCBlbWlzaWUgQ0/igoIsIGludmVzdGnEjW7DqSB1a2F6b3ZhdGVsZeKApikuIETDoXRhIHPDuiB1xb4gcHJlxI1pc3RlbsOpLgoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyA9IFRSVUUsCiAgbWVzc2FnZSA9IEZBTFNFLCAgIyB2eXBuZSAidXNpbmcgZm9ybXVsYSA9IHkgfiB4IiBhIGluw6kgaGzDocWha3kKICB3YXJuaW5nID0gRkFMU0UsICAjIHBvdGxhxI3DrSB2YXJvdmFuaWEKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwKICBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNQopCgoKIyBCYWzDrcSNa3kgYSBkw6F0YSAocG91xb5pdMOpIMSPYWxlaiB2IHByw6FjaSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkobG10ZXN0KQpsaWJyYXJ5KHNhbmR3aWNoKQpsaWJyYXJ5KGNhcikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoa2FibGVFeHRyYSkKCnVkYWplIDwtIHJlYWQuY3N2KCJkYXRhX3JfY29tbWFfdXRmOC5jc3YiLCBoZWFkZXIgPSBUUlVFLCBjaGVjay5uYW1lcyA9IEZBTFNFKQpgYGAKIAojIEludGVyYWt0w612bmEgdGFidcS+a2EgcyBkw6F0YW1pCmBgYHtyIGVjaG89RkFMU0V9CmxpYnJhcnkoRFQpCgpEVDo6ZGF0YXRhYmxlKAogIHVkYWplIHw+IGRwbHlyOjpzbGljZV9oZWFkKG4gPSAxMCksCiAgcm93bmFtZXMgPSBGQUxTRSwKICBvcHRpb25zID0gbGlzdChkb20gPSAndGlwJywgcGFnZUxlbmd0aCA9IDEwKSwKICBjYXB0aW9uID0gIk7DoWjEvmFkIGTDoXQg4oCTIHBydsO9Y2ggMTAgcmlhZGtvdiIKKSB8PgogIGZvcm1hdFN0eWxlKGNvbHVtbnMgPSBuYW1lcyh1ZGFqZSksIGBmb250LXNpemVgID0gJzkwJScpCmBgYAojIFByaWVza3VtbsOpIGdyYWZ5IC0gQk9YUExPVAoKKipQcmXEjW86KiogcHJlZCBtb2RlbG92YW7DrW0gb3ZlcnVqZW0sIMSNaSBtaWVya3kgYSByb3pkZWxlbmlhIGTDoXZhasO6IHpteXNlbCBhIMSNaSBuaWUgc8O6IHZpZGl0ZcS+bsOpIGV4dHLDqW15LiBQb8SNdG92w6kgcHJlbWVubsOpIChgQkVWYCwgYEJFVl9QSEVWYCkgdml6dWFsaXp1amVtIHYgbG9n4oCRbWllcmtlIChgbG9nMXBgKS4KCmBgYHtyIGJveHBsb3RzfQpwYXIobWZyb3cgPSBjKDIsIDIpKQpib3hwbG90KHVkYWplJEVQSSwgICAgICAgICAgICAgICAgbWFpbiA9ICJFUEkgKGJleiBsb2cpIiwgICAgY29sID0gImRhcmtncmVlbiIsICBob3Jpem9udGFsID0gVFJVRSkKYm94cGxvdChsb2cxcCh1ZGFqZSRCRVYpLCAgICAgICAgIG1haW4gPSAibG9nMXAoQkVWKSIsICAgICAgIGNvbCA9ICJsaWdodGJsdWUiLCBob3Jpem9udGFsID0gVFJVRSkKYm94cGxvdChsb2cxcCh1ZGFqZSRCRVZfUEhFViksICAgIG1haW4gPSAibG9nMXAoQkVWX1BIRVYpIiwgIGNvbCA9ICJkYXJrZ3JlZW4iLCAgaG9yaXpvbnRhbCA9IFRSVUUpCmJveHBsb3QobG9nMXAodWRhamUkSERQKSwgICAgICAgICBtYWluID0gImxvZzFwKEhEUCkiLCAgICAgICBjb2wgPSAibGlnaHRibHVlIiwgaG9yaXpvbnRhbCA9IFRSVUUpCnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAoKQm94cGxvdCB6b2JyYXp1amUgcm96ZGVsZW5pZSBwcmVtZW5uZWog4oCTIGhydWLDoSDEjWlhcmEgdiBzdHJlZGUgamUgbWVkacOhbiwg4oCea3JhYmnEjWth4oCcIChib3gpIGplIElRUiAob2QgMS4gcG8gMy4ga3ZhcnRpbCksIOKAnmbDunp54oCcIHVrYXp1asO6IHR5cGlja8O9IHJvenNhaCBhIGJvZGt5IG1pbW8gc8O6IG9kxL5haGzDqSBob2Rub3R5LiBWIG5hxaFpY2ggZ3JhZm9jaCBqZSBFUEkgc8O6c3RyZWRlbsOpIG9rb2xvIFx+NzAgcyBqZWRuw71tIG5pxb7FocOtbSBvdXRsaWVyb207IHBvIGxvZy10cmFuc2Zvcm3DoWNpaSBzw7ogbG9nMXAoQkVWKSBhIGxvZzFwKEJFVl9QSEVWKSBwZWtuZSBzdGFiaWxuw6kgYSBzeW1ldHJpY2vDqSAoYmV6IGRsaMO9Y2ggY2h2b3N0b3YpIGEgbG9nMXAoSERQKSBtw6EgdmXEvm1pIMO6emt5IHJvenNhaCDigJMgYnVkZSBzbMO6xb5pxaUgbmFqbcOkIGFrbyBrb250cm9sYSDDunJvdm5lIHJvenZvamEuCgoKIyBMaW5lw6FybmEgcmVncmVzaWEgKGR2ZSBhbHRlcm5hdMOtdnkpCgoqKk1vdGl2w6FjaWEgdsO9YmVydSDFoXBlY2lmaWvDoWNpZToqKiBgRVBJYCBqZSB6bG/FvmVuw70gaW5kZXggYSBlbGVrdHJvbW9iaWxpdGEgbcO0xb5lIGJ5xaUga29yZWxvdmFuw6EgcyBjZWxrb3ZvdSB2eXNwZWxvc8Wlb3Uga3JhamlueS4gUHJldG8gemFocm5pZW0gYEhEUGAgYWtvIGtvbnRyb2x1LiBLZcSPxb5lIGBCRVZgIGEgYEJFVl9QSEVWYCBzcG9sdSBzaWxubyBzw7p2aXNpYSwgb2RoYWR1amVtIGljaCAqKm9kZGVsZW7DqSoqIG1vZGVseSwgYWJ5IHNvbSBwcmVkacWhbGEga29saW5lYXJpdGUuIEtvZWZpY2llbnR5IGludGVycHJldHVqZW0gYWtvICpzZW1p4oCRZWxhc3RpY2l0eSo6IHptZW5hIHYgYGxvZzFwKHgpYCBwcmlibGnFvm5lIHpvZHBvdmVkw6EgcGVyY2VudHXDoWxuZWogem1lbmUgcG/EjXR1IHZvemlkaWVsLgoKKipNZXTDs2RhIEEgKE1vZGVsIEE6IEVQSSB+IGxvZzFwKEJFVikgKyBsb2cxcChIRFApKSoqCk92ZXJ1amUsIMSNaSBzYW1vdG7DqSBiYXTDqXJpb3bDqSBlbGVrdHJvbW9iaWx5IChCRVYpIHPDunZpc2lhIHMgRVBJIHBvIHpvaMS+YWRuZW7DrSBla29ub21pY2tlaiDDunJvdm5lIChIRFApLiBUZWRhOiBrZcSPIGR2ZSBrcmFqaW55IG1hasO6IHJvdm5ha8O9IEhEUCwgbcOhIHZ5xaHFocOtIHBvxI1ldCBCRVYgKHYgJSB6bWVuw6FjaCDigJMgdsSPYWthIGxvZzFwKSBzcG9qZW7DvSB2ecWhxaHDrS9uacW+xaHDrSBFUEk/CgoqKk1ldMOzZGEgQiAoTW9kZWwgQjogRVBJIH4gbG9nMXAoQkVWX1BIRVYpICsgbG9nMXAoSERQKSkqKgpPdmVydWplIHZ6xaVhaCBtZWR6aSBFUEkgYSBjZWxrb3bDvW0gcm96xaHDrXJlbsOtbSAoUClIRVYgKEJFViArIHBsdWctaW4gaHlicmlkeSksIG9ww6TFpSBwcmkgcm92bmFrZWogw7pyb3ZuaSBIRFAuIFRlbnRvIG1vZGVsIGhvdm9yw60sIMSNbyBzcHJhdsOtIHNwb2xvxI1uw73igJwgKFApSEVWIGluZGlrw6F0b3IgcyBFUEkuCgpBYnkgc29tIHNhIHZ5aGxhIGtvbGluZWFyaXRlLCBvZGhhZHVqZW0gZHZlIMWhcGVjaWZpa8OhY2llIHp2bMOhxaHFpToKCmBgYHtyIG1vZGVsc30KIyBNb2RlbCBBOiBFUEkgfiBsb2cxcChCRVYpICsgbG9nMXAoSERQKQptX2JldiAgPC0gbG0oRVBJIH4gbG9nMXAoQkVWKSAgICAgICsgbG9nMXAoSERQKSwgZGF0YSA9IHVkYWplKQoKIyBNb2RlbCBCOiBFUEkgfiBsb2cxcChCRVZfUEhFVikgKyBsb2cxcChIRFApCm1fcGhldiA8LSBsbShFUEkgfiBsb2cxcChCRVZfUEhFVikgKyBsb2cxcChIRFApLCBkYXRhID0gdWRhamUpCgpzdW1tYXJ5KG1fYmV2KQpzdW1tYXJ5KG1fcGhldikKCiMgUm9idXN0bsOpIFNFIChIQzEpCmNvZWZ0ZXN0KG1fYmV2LCAgdmNvdiA9IHZjb3ZIQyhtX2JldiwgIHR5cGUgPSAiSEMxIikpCmNvZWZ0ZXN0KG1fcGhldiwgdmNvdiA9IHZjb3ZIQyhtX3BoZXYsIHR5cGUgPSAiSEMxIikpCgojIFBvcm92bmFuaWUga3ZhbGl0eQphaWNfdGJsIDwtIEFJQyhtX2JldiwgbV9waGV2KQphaWNfdGJsCgojIFp2b2xlbsO9IG1vZGVsIG5hIGRpYWdub3N0aWt1Cm1vZGVsIDwtIG1fcGhldgpgYGAKClogbGluZcOhcm55Y2ggcmVncmVzacOtIHZ5Y2jDoWR6YSwgxb5lIEhEUCBuYSBvYnl2YXRlxL5hIG3DoSBuYSBFUEkgcG96aXTDrXZueSBhIMWhdGF0aXN0aWNreSB2w716bmFtbsO9IHZwbHl2LCBrw71tIHBvxI1ldCAoUClIRVYgKGEgcG9kb2JuZSBhaiBzYW1vdG7DvWNoIEJFVikgamUgesOhcG9ybsO9IGEgdsO9em5hbW7DvSBwbyB6b2jEvmFkbmVuw60gSERQOyBtb2RlbCBzIEJFVl9QSEVWIHNlZMOtIG1pZXJuZSBsZXDFoWllIChuacW+xaFpZSBBSUMpIGEgesOhdmVyeSBzYSBuZW1lbmlhIGFuaSBwcmkgcm9idXN0bsO9Y2ggc21lcm9kYWpuw71jaCBjaHliw6FjaC4gTW9kZWx5IHZ5c3ZldMS+dWrDuiB6aHJ1YmEgMzjigJM0MiAlIHZhcmlhYmlsaXR5IEVQSS4KCgpgYGB7cn0KIyBhayBtX2xpbiBlxaF0ZSBuZWV4aXN0dWplLCBwb3XFvmlqZW0gbGluZcOhcm55IG1vZGVsIHMgKFApSEVWCmlmICghZXhpc3RzKCJtX2xpbiIpKSBtX2xpbiA8LSBtX3BoZXYKIyAxKSBTa29udHJvbHVqZW1lIGEgcHLDrXBhZG5lIG9wcmF2w61tZSBuw6F6b3Ygc3TEunBjYSBFUEkKaWYgKCEiRVBJIiAlaW4lIG5hbWVzKHVkYWplKSkgewogIGNvbF9lcGkgPC0gZ3JlcCgiXkVQSVxcYiIsIG5hbWVzKHVkYWplKSwgdmFsdWUgPSBUUlVFKVsxXQogIGlmICghaXMubmEoY29sX2VwaSkpIG5hbWVzKHVkYWplKVtuYW1lcyh1ZGFqZSkgPT0gY29sX2VwaV0gPC0gIkVQSSIKfQoKIyAyKSBWeWJlcmllbWUgbW9kZWwsIHoga3RvcsOpaG8gY2hjZW1lIHByZWRpa292YcWlCm1vZCA8LSBtX2xpbiAgICMgPC0gcHLDrXBhZG5lIHptZcWIIG5hOiBtX3BoZXYsIG1fc2xvcGUsIG1fcXVhZCwgLi4uCgojIDMpIFByZWRpa8SNbsOhIGtyaXZrYTogRVBJIH4gQkVWX1BIRVYgcHJpIG1lZGnDoW5lIEhEUApwZGF0IDwtIGRhdGEuZnJhbWUoCiAgQkVWX1BIRVYgPSBzZXEobWluKHVkYWplJEJFVl9QSEVWLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgIG1heCh1ZGFqZSRCRVZfUEhFViwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gMjAwKSwKICBIRFAgPSBtZWRpYW4odWRhamUkSERQLCBuYS5ybSA9IFRSVUUpCikKCnByIDwtIHByZWRpY3QobW9kLCBuZXdkYXRhID0gcGRhdCwgc2UuZml0ID0gVFJVRSkKcGRhdCR5aGF0IDwtIHByJGZpdApwZGF0JGxvICAgPC0gcHIkZml0IC0gMS45NiAqIHByJHNlLmZpdApwZGF0JGhpICAgPC0gcHIkZml0ICsgMS45NiAqIHByJHNlLmZpdAoKbGlicmFyeShnZ3Bsb3QyKQpnZ3Bsb3QocGRhdCwgYWVzKHggPSBCRVZfUEhFViwgeSA9IHloYXQpKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBsbywgeW1heCA9IGhpKSwgYWxwaGEgPSAwLjIpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh4ID0gIkJFVl9QSEVWIiwgeSA9ICJQcmVkaWtvdmFuw6kgRVBJIiwKICAgICAgIHRpdGxlID0gIkVQSSB2cy4gKFApSEVWIChwcmkgbWVkacOhbmUgSERQKSIpICsKICB0aGVtZV9taW5pbWFsKCkKCmBgYApHcmFmIHVrYXp1amUgcHJlZGlrb3ZhbsO9IEVQSSB2IHrDoXZpc2xvc3RpIG9kIHBvxI10dSAoUClIRVYgcHJpIGZpeG92YW5vbSAobWVkacOhbm92b20pIEhEUCB6IG7DocWhaG8gc2VtaS1sb2cgbW9kZWx1LiBLcml2a2EgbcOhIHpyZXRlxL5uZSBrbGVzYWrDumNpIGEgc3Bsb8WhxaV1asO6Y2kgc2EgdHZhcjogcHJpIG7DrXpreWNoIGhvZG5vdMOhY2ggKFApSEVWIGplIHBva2xlcyBFUEkgc3RybcWhw60sIG5vIHMgcmFzdMO6Y2ltIChQKUhFViBzYSDDusSNaW5vayB6bWllcsWIdWplIChkaW1pbmlzaGluZyByZXR1cm5zKSwgxI1vIGplIHR5cGlja8OpIHByZSDFoXBlY2lmaWvDoWNpdSBzIGxvZ+KBoSgxKyhQKUhFVi4gxaBlZMOpIHDDoXNtbyB2eXpuYcSNdWplIDk1ICUgaW50ZXJ2YWwgcHJlZGlrY2llIGEgc21lcm9tIGsgdnnFocWhw61tIGhvZG5vdMOhbSBzYSByb3rFoWlydWplLCB0ZWRhIG5laXN0b3RhIHJhc3RpZSAodiB0w71jaCBvYmxhc3RpYWNoIG3DoW1lIG1lbmVqIHBvem9yb3ZhbsOtIGFsZWJvIHbDpMSNxaHDrSByb3pwdHlsKS4gQ2Vsa292byBncmFmIHZpenXDoWxuZSBwb3R2cmR6dWplIG5lZ2F0w612bnUgYXNvY2nDoWNpdSBtZWR6aSByb3rFocOtcmVuw61tIChQKUhFViBhIEVQSSB2IG5hxaFpY2ggZMOhdGFjaCBwbyB6b2jEvmFkbmVuw60gSERQOyBpZGUgbyBhc29jacOhY2l1LCBuaWUgZMO0a2F6IGthdXphbGl0eS4KCgojIyBEaWFnbm9zdGlrYSAoa3JhasWhaWUgZ3JhZnkpCgojIyMgUmVzaWR1YWxzIHZzIEZpdHRlZAoK4oCTIHVrYXp1amUsIMSNaSBtb2RlbCBuZWNow71iYSB0dmFyIChuZWxpbmVhcml0YSkgYSDEjWkgc8O6IGNoeWJ5IHJvdm5vbWVybmUgb2tvbG8gbnVseS4gSMS+YWTDoW1lIOKAnm7DoWhvZG7DvSBtcmFr4oCcIGJleiB2em9ydS4KCiMjIyBOb3JtYWwgUeKAk1EKCuKAkyBwb3Jvdm7DoXZhIHJvemRlbGVuaWUgcmV6w61kdcOtIHMgaWRlw6Fsbm91IG5vcm3DoWxub3Uga3JpdmtvdTsgYm9keSBwcmkgcHJpYW1rZSA9IHByaWJsacW+bsOhIG5vcm1hbGl0YSwgb2RjaMO9bGt5IHYgY2h2b3N0b2NoIHNpZ25hbGl6dWrDuiBleHRyw6lteS4KCiMjIyBTY2FsZeKAk0xvY2F0aW9uICjiiJpcfMWhdGFuZGFyZGl6b3ZhbsOpIHJlesOtZHXDoVx8IHZzLiBmaXR0ZWQpCgrigJMgdGVzdCByb3ZuYWvDqWhvIHJvenB0eWx1IGNow71iIChob21vc2tlZGFzdGljaXRhKS4gUm92bsOhIExPRVNTIGtyaXZrYSDiiYgga29uxaF0YW50bsO9IHJvenB0eWw7IHN0w7pwYWrDumNpL2xpZXZpayA9IGhldGVyb3NrZWRhc3RpY2l0YS4KCiMjIyBSZXNpZHVhbHMgdnMgTGV2ZXJhZ2UKCuKAkyBpZGVudGlmaWt1amUgdnBseXZuw6kgcG96b3JvdmFuaWE6IGtvbWJpbsOhY2lhIHZlxL5rw6lobyDigJ5sZXZlcmFnZeKAnCAoaGF0IGhvZG5vdHkpIGEgdmXEvmvDvWNoIHJlesOtZHXDrS4gUG9tw6FoYSByb3pob2Ruw7rFpSwgxI1pIG5pZWtvxL5rbyBib2RvdiBuZcWlYWjDoSByZWdyZXNuw7ogcHJpYW1rdSAocG9kxL5hIENvb2tvdmVqIHZ6ZGlhbGVub3N0aSkuCgpgYGB7ciBkaWFnLWdncGxvdH0KY2xyIDwtICIjMEU2QjREIgoKIyBkaWFnbm9zdGlja8O9IGRhdGFmcmFtZSAKZGlhZ19kZiA8LSBhdWdtZW50KG1vZGVsKSAlPiUgbXV0YXRlKGlkID0gZHBseXI6OnJvd19udW1iZXIoKSkKCmNvb2tfY3V0IDwtIDQgLyBucm93KGRpYWdfZGYpCmxhYl9kZiAgIDwtIGRwbHlyOjpmaWx0ZXIoZGlhZ19kZiwgLmNvb2tzZCA+IGNvb2tfY3V0KQoKcDEgPC0gZ2dwbG90KGRpYWdfZGYsIGFlcyguZml0dGVkLCAucmVzaWQpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JleTYwIikgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAuNzUsIGNvbG9yID0gY2xyKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSwgY29sb3IgPSBjbHIpICsKICBsYWJzKHRpdGxlID0gIlJlc2lkdWFscyB2cyBGaXR0ZWQiLCB4ID0gIkZpdHRlZCB2YWx1ZXMiLCB5ID0gIlJlc2lkdWFscyIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikpCgpwMiA8LSBnZ3Bsb3QoZGlhZ19kZiwgYWVzKHNhbXBsZSA9IC5zdGQucmVzaWQpKSArCiAgc3RhdF9xcShjb2xvciA9IGNsciwgYWxwaGEgPSAuOSkgKwogIHN0YXRfcXFfbGluZShjb2xvciA9ICJncmV5NDUiKSArCiAgbGFicyh0aXRsZSA9ICJOb3JtYWwgUeKAk1EiLCB4ID0gIlRoZW9yZXRpY2FsIFF1YW50aWxlcyIsIHkgPSAiU3RhbmRhcmRpemVkIHJlc2lkdWFscyIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikpCgpwMyA8LSBnZ3Bsb3QoZGlhZ19kZiwgYWVzKC5maXR0ZWQsIHNxcnQoYWJzKC5zdGQucmVzaWQpKSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gLjc1LCBjb2xvciA9IGNscikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gY2xyKSArCiAgbGFicyh0aXRsZSA9ICJTY2FsZeKAk0xvY2F0aW9uIiwgeCA9ICJGaXR0ZWQgdmFsdWVzIiwKICAgICAgIHkgPSBleHByZXNzaW9uKHNxcnQoInxTdGFuZGFyZGl6ZWQgcmVzaWR1YWxzfCIpKSkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSkKCnA0IDwtIGdncGxvdChkaWFnX2RmLCBhZXMoLmhhdCwgLnN0ZC5yZXNpZCkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmV5NjAiKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IC43NSwgY29sb3IgPSBjbHIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9IGNscikgKwogIGdlb21fdGV4dChkYXRhID0gbGFiX2RmLCBhZXMobGFiZWwgPSBpZCksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDMpICsKICBsYWJzKHRpdGxlID0gIlJlc2lkdWFscyB2cyBMZXZlcmFnZSIsIHggPSAiSGF0IHZhbHVlcyIsIHkgPSAiU3RhbmRhcmRpemVkIHJlc2lkdWFscyIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikpCgoocDEgKyBwMikgLyAocDMgKyBwNCkKYGBgCgoqKkRpYWdub3N0aWthIOKAkyDEjcOtdGFuaWUgZ3JhZm92OioqCgotICAgKlJlc2lkdWFscyB2cyBGaXR0ZWQqOiBqZW1uw6EgbmVsaW5lYXJpdGEgYSBtaWVybmUga29sw61zYW5pZSByb3pwdHlsdS4KLSAgICpR4oCTUSo6IGRyb2Juw6kgb2RjaMO9bGt5IHYgY2h2b3N0b2NoIOKGkiBwcmlibGnFvm7DoSBub3JtYWxpdGEuCi0gICAqU2NhbGXigJNMb2NhdGlvbio6IHNsYWLDoSBoZXRlcm9za2VkYXN0aWNpdGEg4oaSIHBvdcW+aWplbSByb2J1c3Ruw6kgU0UuCi0gICAqUmVzaWR1YWxzIHZzIExldmVyYWdlKjogem9ww6FyIHZwbHl2bsO9Y2ggYm9kb3YgKG96bmHEjWVuw6kgSUQpLCBhbGUgYmV6IGV4dHLDqW1vdi4KCktlxI8gem9oxL5hZG7DrW1lIEhEUCwgdmlhYyAoUClIRVYgc2EgdiBuYcWhaWNoIGTDoXRhY2ggc3DDoWphIHMgbmnFvsWhw61tIEVQSS4gS29udHJvbG7DqSBncmFmeSBuZXVrw6F6YWxpIHbDocW+bmUgcHJvYmzDqW15IGEgZHJvYm7DqSBvZGNow71sa3kgc21lIHBva3J5bGkgcm9idXN0bsO9bWkgY2h5YmFtaSwgdGFrxb5lIHbDvXNsZWRvayBiZXJpZW1lIGFrbyBzcG/EvmFobGl2w70uCgojIFZwbHl2bsOpIHBvem9yb3ZhbmlhCgpgYGB7ciBpbmZsdWVuY2V9CmluZmx1ZW5jZVBsb3QobW9kZWwsIG1haW4gPSAiSW5mbHVlbmNlIHBsb3QiKQpvdXRsaWVyVGVzdChtb2RlbCkgICMgQm9uZmVycm9uaSBwLXZhbHVlCmBgYAoqKktyw6F0a2UgxI3DrXRhbmllIGdyYWZ1IGEgdGFidcS+a3k6KioKCipJbmZsdWVuY2UgcGxvdCAoYnViYmxlIGNoYXJ0KSoKCi1YLW9zIChIYXQtdmFsdWVzKSA9IOKAnnDDoWth4oCcIChsZXZlcmFnZSk6IGFrIGplIGJvZCB2aWFjIHZwcmF2bywgbcOhIG5lxaF0YW5kYXJkbsO6IGtvbWJpbsOhY2l1IHZ5c3ZldMS+dWrDumNpY2ggcHJlbWVubsO9Y2ggYSB2aWUgdmlhYyBzdHJobsO6xaUgcHJpYW1rdS4KCi1ZLW9zIChTdHVkZW50aXplZCByZXNpZHVhbHMpID0gdmXEvmtvc8WlIGNoeWJ5OiBuYWQgKzIgYWxlYm8gcG9kIOKIkjIgamUgcG9kb3pyaXbDqS4KCi1WZcS+a29zxaUvb2R0aWXFiCBidWJsaW55ID0gQ29va292byBEOiDEjcOtbSB2w6TEjcWhaWEgYSB0bWF2xaFpYSBidWJsaW5hLCB0w71tIHbDpMSNxaHDrSB2cGx5diBqZWRub3RreSBuYSBvZGhhZCBjZWzDqWhvIG1vZGVsdS4KCkdyYWYgdnBseXZ1IHVrYXp1amUgbmlla2/EvmtvIHBvem9yb3ZhbsOtIHMgdnnFocWhb3Ug4oCecMOha2914oCcIGEgdnBseXZvbSAobmFqbcOkIGJvZHkgMzEsIDQxIGEgMjApLCBubyB6b3N0w6F2YWrDuiB2IHJvenVtbsO9Y2ggbWVkemlhY2g7IENvb2tvdm8gRCBuaWUgamUgZXh0csOpbW5lIGEgaG9kbm90eSDFoXR1ZGVudGl6b3ZhbsO9Y2ggcmV6w61kdcOtIHNhIHBvaHlidWrDuiBva29sbyBocmFuw61jIMKxMi4gRm9ybcOhbG55IG91dGxpZXJUZXN0IHByaXRvbSBuZW5hxaFpZWwgxb5pYWRueSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSBvZMS+YWhsw70gYm9kIHBvIEJvbmZlcnJvbmkga29yZWtjaWkgKG5hanbDpMSNxaHDrSB8cnN0dWRlbnR8IG3DoSBib2QgMjAg4omIIOKIkjIuMzAsIG5lb3ByYXZlbsOpIHAgfiAwLjAyNiwgcG8ga29yZWtjaWkgbmV2w716bmFtbsOpKS4gSW7DvW1pIHNsb3ZhbWk6IHYgZMOhdGFjaCBzw7ogamVkbm90a3ksIGt0b3LDqSBtYWrDuiBjaXRlxL5uZWrFocOtIHZwbHl2IG5hIG9kaGFkLCBhbGUgbmVtw6FtZSBkw7RrYXogbyBza3V0b8SNbsO9Y2ggb3V0bGllcm9jaAojIERvZGF0b8SNbsOpIHBvcm92bmFuaWUgbW9kZWxvdgoKYGBge3IgY29tcGFyZX0KIyBNb2RlbCBBOiBFUEkgfiBsb2cxcChCRVYpICsgSERQIChiZXogbG9nIG5hIEhEUCDigJMgYWtvIGtvbnRyb2xhIMO6cm92bmUpCm1fYmV2MiAgPC0gbG0oRVBJIH4gbG9nMXAoQkVWKSAgICAgICsgSERQLCBkYXRhID0gdWRhamUpCiMgTW9kZWwgQjogRVBJIH4gbG9nMXAoQkVWX1BIRVYpICsgSERQCm1fcGhldjIgPC0gbG0oRVBJIH4gbG9nMXAoQkVWX1BIRVYpICsgSERQLCBkYXRhID0gdWRhamUpCnN1bW1hcnkobV9iZXYyKTsgY29lZnRlc3QobV9iZXYyLCB2Y292ID0gdmNvdkhDKG1fYmV2MiwgdHlwZSA9ICJIQzEiKSkKc3VtbWFyeShtX3BoZXYyKTsgY29lZnRlc3QobV9waGV2MiwgdmNvdiA9IHZjb3ZIQyhtX3BoZXYyLCB0eXBlID0gIkhDMSIpKQpBSUMobV9iZXYyLCBtX3BoZXYyKQpgYGAKClBvIHpvaMS+YWRuZW7DrSBIRFAgdnljaMOhZHphIG5lZ2F0w612bmEgYXNvY2nDoWNpYSBFUEkgcyAoUClIRVYgYWogcyBCRVY7IG1pZXJuZSBsZXDFoWllIHNlZMOtIMWhcGVjaWZpa8OhY2lhIHMgQkVWX1BIRVYuCgojIE9uZXNrb3JlbsO9IHZwbHl2IChsYWcgMSByb2spIHMgZml4bsO9bWkgZWZla3RtaQoKKipQcmXEjW8gbGFnOioqIHptZW55IHYgemxvxb5lbsOtIHZvem92w6lobyBwYXJrdSBhIGJ1ZG92YW7DrSBpbmZyYcWhdHJ1a3TDunJ5IHNhIG5lbXVzaWEgb2thbcW+aXRlIHByZW1pZXRudcWlIGRvIEVQSS4gSmVkbm9yb8SNbsO9IGxhZyBgQkVWX1BIRVZgIHMgKipmaXhuw71taSBlZmVrdG1pIGtyYWrDrW4gYSByb2tvdioqIHphY2h5dMOhdmEgbmVwb3pvcm92YW7DuiBoZXRlcm9nZW5pdHUgYSBzcG9sb8SNbsOpIMWhb2t5LgoKYGBge3IgbGFnfQp1ZGFqZV9sYWcgPC0gdWRhamUgJT4lCiAgYXJyYW5nZShLcmFqaW5hLCBSb2spICU+JQogIGdyb3VwX2J5KEtyYWppbmEpICU+JQogIG11dGF0ZShsYWdfQkVWX1BIRVYgPSBkcGx5cjo6bGFnKEJFVl9QSEVWLCAxKSkgJT4lCiAgdW5ncm91cCgpCgptX2xhZyA8LSBsbShFUEkgfiBsb2cxcChsYWdfQkVWX1BIRVYpICsgSERQICsgZmFjdG9yKEtyYWppbmEpICsgZmFjdG9yKFJvayksIGRhdGEgPSB1ZGFqZV9sYWcpCmNvZWZ0ZXN0KG1fbGFnLCB2Y292ID0gdmNvdkNMKG1fbGFnLCBjbHVzdGVyID0gfiBLcmFqaW5hLCB0eXBlID0gIkhDMSIpKQpgYGAKCkFqIGtlxI8gc2EgcG96cmllbWUgbmEgb25lc2tvcmVuw70gKDEtcm/EjW7DvSkgZWZla3QgYSB6YWZpeHVqZW1lIHJvemRpZWx5IG1lZHppIGtyYWppbmFtaSBhIHJva21pLCBuZXZpZMOtbWUgxaF0YXRpc3RpY2vDvSBkw7RrYXosIMW+ZSB2aWFjIChQKUhFViB6bGVwxaHDrSBFUEnigJRrb2VmaWNpZW50IGplIHPDrWNlIG5lZ2F0w612bnksIGFsZSBuZXbDvXpuYW1uw70uIFByZSBuYcWhdSBwcsOhY3UgdG8gem5hbWVuw6EsIMW+ZSBobGF2bsO9IHrDoXZlciB6b3N0w6F2YSByb3ZuYWvDvTogcG8gem9oxL5hZG5lbsOtIEhEUCAoYSBwcmkgRkUpIHNhIHYgZG9zdHVwbsO9Y2ggZMOhdGFjaCBWNCBuZXBvdHZyZHp1amUga3LDoXRrb2RvYsO9IHBveml0w612bnkgdnBseXYgcm96xaHDrXJlbmlhIChQKUhFViBuYSBFUEkuIE1vZGVsIHRlZGEgc2vDtHIgaG92b3LDrSwgxb5lIEVQSSBmb3JtdWrDuiBhaiBpbsOpLCDFoWlyxaFpZSBmYWt0b3J5IG5lxb4gc2Ftb3Ruw6EgZWxla3Ryb21vYmlsaXRhCgojIMWgdGFuZGFyZGl6b3ZhbsOpIGtvZWZpY2llbnR5CgoqKlpteXNlbDoqKiBwbyDFoXRhbmRhcmRpesOhY2lpIHZpZW0gcG9yb3ZuYcWlICp2ZcS+a29zxaUqIGVmZWt0b3YgbmFwcmllxI0gcm96ZGllbG55bWkgbWllcmthbWkgKFNEIGplZG5vdGt5KS4KCmBgYHtyIHN0ZH0KbV9zdGQgPC0gbG0oc2NhbGUoRVBJKSB+IHNjYWxlKGxvZzFwKEJFVl9QSEVWKSkgKyBzY2FsZShIRFApLCBkYXRhID0gdWRhamUpCnN1bW1hcnkobV9zdGQpCmBgYAoKUG8gxaF0YW5kYXJkaXrDoWNpaSB2eWNow6FkemEsIMW+ZSBsb2cxcChCRVZfUEhFVikgbcOhIHNpbG5lasWhw60gdnBseXYgbmEgRVBJIGEgamUgbmVnYXTDrXZueSAoXH7iiJIwLjc5IFNEIHphICsxIFNEIHYgKFApSEVWKSwga8O9bSBIRFAgamUgcG96aXTDrXZuZSAoXH4rMC40NCBTRCB6YSArMSBTRCB2IEhEUCk7IG9iYSBlZmVrdHkgc8O6IMWhdGF0aXN0aWNreSB2w716bmFtbsOpLiBJbnRlcmNlcHQgamUgXH4wIChsZWJvIHByZW1lbm7DqSBzw7ogY2VudHJvdmFuw6kpIGEgbW9kZWwgdnlzdmV0xL51amUgXH40MiAlIHZhcmlhYmlsaXR5IEVQSS4gSW7DvW1pIHNsb3ZhbWk6IHYgbmHFoWljaCBkw6F0YWNoIHNhIHptZW55IHYgKFApSEVWIHNww6FqYWrDuiBzIHbDpMSNxaHDrW0gKG5lZ2F0w612bnltKSBwb3N1bm9tIEVQSSBuZcW+IHJvdm5ha28gdmXEvmvDqSB6bWVueSB2IEhEUCBzIHBveml0w612bnltIHNtZXJvbS4KCiMgSGV0ZXJvc2tlZGFzdGljaXRhIOKAkyB0ZXN0eSBhIGdyYWZ5CgpIZXRlcm9za2VkYXN0aWNpdGEgPSByb3pwdHlsIGNow71iIG5pZSBqZSB2xaFhZGUgcm92bmFrw70uIEFrIGJ5IGJvbGEgdsO9cmF6bsOhLCBiZcW+bsOpIHAtaG9kbm90eSBtw7TFvnUgYnnFpSBza3Jlc2xlbsOpLiBOacW+xaFpZSBqdSByw71jaGxvIG92ZXLDrW0gKGdyYWZ5ICsgdGVzdHkpIGEgem9oxL5hZG7DrW0gY2V6IHJvYnVzdG7DqSDFoXRhbmRhcmRuw6kgY2h5YnkgKEhDMSkuCgojIyBWaXp1w6FsbmEgZGlhZ25vc3Rpa2EKCmBgYHtyIGhldGVyby1wbG90eSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShicm9vbSk7IGxpYnJhcnkoZ2dwbG90Mik7IGxpYnJhcnkocGF0Y2h3b3JrKTsgY2xyIDwtICIjMEU2QjREIgoKaCA8LSBhdWdtZW50KG1vZGVsLCBkYXRhID0gdWRhamUpIHw+CiAgZHBseXI6Om11dGF0ZSgKICAgIGFic3JlcyA9IHNxcnQoYWJzKC5zdGQucmVzaWQpKSwKICAgIHJlczIgICA9IC5yZXNpZF4yLAogICAgeF9iZXYgID0gbG9nMXAoLmRhdGEkQkVWX1BIRVYpLCAgIyBhayBwb3XFvsOtdmFtZSBCRVY6IGxvZzFwKC5kYXRhJEJFVikKICAgIHhfaGRwICA9IC5kYXRhJEhEUAogICkKCnBfU0wgPC0gZ2dwbG90KGgsIGFlcyguZml0dGVkLCBhYnNyZXMpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0uNjUpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgc2U9RkFMU0UsIGxpbmV3aWR0aD0xLCBjb2xvcj1jbHIpICsKICBsYWJzKHg9IlByZWRpa292YW7DqSBob2Rub3R5IiwgeT1leHByZXNzaW9uKHNxcnQoInxyZXrDrWR1w6F8IikpLCB0aXRsZT0iU2NhbGXigJNMb2NhdGlvbiIpICsKICB0aGVtZV9taW5pbWFsKCkKCnBfYmV2IDwtIGdncGxvdChoLCBhZXMoeF9iZXYsIHJlczIpKSArCiAgZ2VvbV9wb2ludChhbHBoYT0uNjUpICsKICBnZW9tX3Ntb290aChtZXRob2Q9ImxvZXNzIiwgc2U9RkFMU0UsIGxpbmV3aWR0aD0xLCBjb2xvcj1jbHIpICsKICBsYWJzKHg9ImxvZzFwKEJFVl9QSEVWKSIsIHk9InJlesOtZHXDoV4yIiwgdGl0bGU9IlJlesOtZHXDoV4yIHZzLiBsb2cxcChCRVZfUEhFVikiKSArCiAgdGhlbWVfbWluaW1hbCgpCgpwX2hkcCA8LSBnZ3Bsb3QoaCwgYWVzKHhfaGRwLCByZXMyKSkgKwogIGdlb21fcG9pbnQoYWxwaGE9LjY1KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsb2VzcyIsIHNlPUZBTFNFLCBsaW5ld2lkdGg9MSwgY29sb3I9Y2xyKSArCiAgbGFicyh4PSJIRFAiLCB5PSJyZXrDrWR1w6FeMiIsIHRpdGxlPSJSZXrDrWR1w6FeMiB2cy4gSERQIikgKwogIHRoZW1lX21pbmltYWwoKQoKcF9TTCAvIChwX2JldiB8IHBfaGRwKQpgYGAKTE9FU1Mga3JpdmthIHYgU2NhbGXigJNMb2NhdGlvbiBtw6EgamVtbsOpIOKAnlXigJwg4oCTIHJvenB0eWwgcmV6w61kdcOtIGplIG5ham1lbsWhw60gcHJpIHN0cmVkbsO9Y2ggcHJlZGlrY2nDoWNoIGEgdsOkxI3FocOtIG5hIG9rcmFqb2NoLCB0YWvFvmUgaWRlIG8gbWllcm51IGhldGVyb3NrZWRhc3RpY2l0dS4gVm8gdnrFpWFodSByZXrDrWR1w6HCsiB2cy4gbG9nMXAoQkVWX1BIRVYpIGplIFUtdHZhciBsZW4gcGx5dGvDvSwgxI1pxb5lIHMgKFApSEVWIHPDunZpc8OtIHJvenB0eWwgc2vDtHIgc2xhYm8uIE5hb3BhaywgZ3JhZiByZXrDrWR1w6HCsiB2cy4gSERQIHVrYXp1amUgdsO9cmF6bmVqxaHDrSBVLXR2YXI6IHZhcmlhbmNpYSBqZSBuYWpuacW+xaFpYSBwcmkgc3RyZWRuw71jaCBob2Rub3TDoWNoIEhEUCBhIHJhc3RpZSBwcmkgbsOtemt5Y2ggYWogdnlzb2vDvWNoLCDEjW8gbmF6bmHEjXVqZSwgxb5lIHByw61wYWRuw6EgaGV0ZXJvc2tlZGFzdGljaXRhIGplIHZpYXphbsOhIG5ham3DpCBuYSBIRFAuIENlbGtvdm8gbmVqZGUgbyBzaWxuw6kgcG9ydcWhZW5pZSwgYWxlIGplIHJvenVtbsOpIHBvdcW+w612YcWlIHJvYnVzdG7DqSDFoXRhbmRhcmRuw6kgY2h5YnkgKEhDMSk7IG5pxb7FoWllIHRvIGXFoXRlIG92ZXLDrW1lIGZvcm3DoWxueW1pIHRlc3RhbWkuCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBhdGNod29yaykgICAKCiMgbW9kZWwsIGt0b3LDvSBjaGNlbWUgZGlhZ25vc3Rpa292YcWlCgptb2QgICA8LSBtX3BoZXYgICAgICMgRVBJIH4gbG9nMXAoQkVWX1BIRVYpICsgbG9nMXAoSERQKQpkdGEgICA8LSB1ZGFqZQoKIyB2eXBvxI3DrXRhbSByZXrDrWR1w6EgYSBwcmlwcmF2w61tIGxvZyBwcmVtZW5uw7ogcHJlIEJFVl9QSEVWIChhYnkgc2VkZWxhIHMgbW9kZWxvbSkKCmR0YSRyZXNpZDIgICA8LSByZXNpZChtb2QpXjIKZHRhJGxvZ0JFVlAgIDwtIGxvZzFwKGR0YSRCRVZfUEhFVikKCiMgMSkgUmV6w61kdcOhXjIgdnMuIGxvZzFwKEJFVl9QSEVWKQoKcF9iZXYgPC0gZ2dwbG90KGR0YSwgYWVzKHggPSBsb2dCRVZQLCB5ID0gcmVzaWQyKSkgKwpnZW9tX3BvaW50KGFscGhhID0gMC42KSArCmdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gImZpcmVicmljayIpICsKbGFicyh4ID0gImxvZzFwKEJFVl9QSEVWKSIsIHkgPSAixaB0dm9yY2UgcmV6w61kdcOtIiwKdGl0bGUgPSAiUmV6w61kdcOhXjIgdnMuIGxvZzFwKEJFVl9QSEVWKSIpICsKdGhlbWVfbWluaW1hbCgpCgojIDIpIFJlesOtZHXDoV4yIHZzLiBIRFAgIChwb3pvcjogdiBtb2RlbGkgamUgbG9nKEhEUCkg4oCTIHR1IMO6bXlzZWxuZSBkw6F2YW1lIGFqIOKAnnJhd+KAnCBIRFAsCgojIGFieSBib2xvIGphc25lIHZpZG5vLCDEjWkgcHJvYmzDqW0gc8O6dmlzw60gcyDDunJvdsWIb3UgYm9oYXRzdHZhKQoKcF9oZHAgPC0gZ2dwbG90KGR0YSwgYWVzKHggPSBIRFAsIHkgPSByZXNpZDIpKSArCmdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiZmlyZWJyaWNrIikgKwpsYWJzKHggPSAiSERQIG5hIG9ieXZhdGXEvmEiLCB5ID0gIsWgdHZvcmNlIHJlesOtZHXDrSIsCnRpdGxlID0gIlJlesOtZHXDoV4yIHZzLiBIRFAiKSArCnRoZW1lX21pbmltYWwoKQoKcF9iZXYgfCBwX2hkcAoKYGBgCgpaIHTDvWNodG8gZHZvY2ggZ3JhZm92IHZpZG5vLCDFvmUgdmXEvmtvc8WlIGNow71iICjFoXR2b3JjZSByZXrDrWR1w60pIG5pZSBqZSB2xaFhZGUgcm92bmFrw6EuIMSMZXJ2ZW7DoSBMT0VTUyBrcml2a2EgbcOhIHYgb2JvY2ggcHLDrXBhZG9jaCB0dmFyIGplbW7DqWhvIOKAnlXigJwg4oCTIHJvenB0eWwgcmV6w61kdcOtIGplIG5ham1lbsWhw60gdiBzdHJlZGUgYSB2w6TEjcWhw60gcHJpIHZlxL5taSBuw616a3ljaCBhaiB2ZcS+bWkgdnlzb2vDvWNoIGhvZG5vdMOhY2guIEVmZWt0IGplIHpyZXRlxL5uZWrFocOtIHByaSBIRFAsIMSNbyBuYXpuYcSNdWplLCDFvmUgbmVyb3ZuYWvDvSByb3pwdHlsIGNow71iIHPDunZpc8OtIHNrw7RyIHMgw7pyb3bFiG91IGJvaGF0c3R2YSBrcmFqw61uIG5lxb4gcyBwb8SNdG9tIChQKUhFVi4gTmllIGplIHRvIGV4dHLDqW1ueSDigJ5saWV2aWvigJwsIGFsZSBpZGUgbyBtaWVybnUgaGV0ZXJvc2tlZGFzdGljaXR1LgoKIyMgSGV0ZXJvc2tlZGFzdGljaXRhIC0gcHJlaMS+YWQgdGVzdG92CgpgYGB7cn0KbGlicmFyeShsbXRlc3QpOyBsaWJyYXJ5KGNhcik7IGxpYnJhcnkoZHBseXIpOyBsaWJyYXJ5KGtuaXRyKQoKYnBfZml0dGVkIDwtIGJwdGVzdChtb2RlbCkKYnBfd2hpdGUgIDwtIGJwdGVzdChtb2RlbCwgfiBmaXR0ZWQobW9kZWwpICsgSShmaXR0ZWQobW9kZWwpXjIpKQpuY3YgICAgICAgPC0gbmN2VGVzdChtb2RlbCkKCnRyaWJibGUoCiAgflRlc3QsICAgICAgICAgICAgICAgflN0YXRpc3RpYywgICAgICAgICAgICAgICAgICAgfnBfdmFsdWUsCiAgIkJyZXVzY2jigJNQYWdhbiIsICAgICB1bm5hbWUoYnBfZml0dGVkJHN0YXRpc3RpYyksICBicF9maXR0ZWQkcC52YWx1ZSwKICAiQlAgKFdoaXRlIMWhdMO9bCkiLCAgIHVubmFtZShicF93aGl0ZSRzdGF0aXN0aWMpLCAgIGJwX3doaXRlJHAudmFsdWUsCiAgIk5DViAoY2FyKSIsICAgICAgICAgdW5uYW1lKG5jdiRDaGlTcXVhcmUpLCAgICAgICAgbmN2JHAKKSB8PgogIG11dGF0ZShhY3Jvc3MoYyhTdGF0aXN0aWMsIHBfdmFsdWUpLCB+cm91bmQoLngsIDQpKSkgfD4KICBrYWJsZShjYXB0aW9uID0gIkhldGVyb3NrZWRhc3RpY2l0YSDigJMgcHJlaMS+YWQgdGVzdG92IikKYGBgCiMjIyBGb3Jtw6FsbmUgdGVzdHkKLSAqQnJldXNjaOKAk1BhZ2FuOiogcCA9IDAsNzg0IChuZXbDvXpuYW1uw6kpLiAKCi0gKldoaXRlLcWhdMO9bDoqIHAgPSAwLDA1OSAoaHJhbmnEjW7DvSBuw6F6bmFrIFUtdHZhcnUgdm8gdmFyaWFuY2lpKS4gCgotICpOQ1YgKGNhcik6KiBwID0gMCw5NTUgKG5ldsO9em5hbW7DqSkuCgoqKlJvemhvZG51dGllOioqIFRlc3R5IG5lZMOhdmFqw7ogc2lsbsO9IGTDtGtheiBoZXRlcm9za2VkYXN0aWNpdHk7IHZ6aMS+YWRvbSBuYSBqZW1uw70gdnpvciB2IGdyYWZvY2ggamUgcHJpbWVyYW7DqSByZXBvcnRvdmHFpSByb2J1c3Ruw6kgxaF0YW5kYXJkbsOpIGNoeWJ5IChIQzEpLiBLdmFsaXRhdMOtdm5lIHrDoXZlcnkgbW9kZWx1IHNhIHTDvW0gbmVtZW5pYS4KCiMgTmVsaW5lw6FybmUgxaFwZWNpZmlrw6FjaWUgYSB0ZXN0eSBmdW5rxI1uZWogZm9ybXkKUHJlxI1vIHRvdG8gcm9iw61tZT8gRG90ZXJheiBzbWUgcHJlZHBva2xhZGFsaSwgxb5lIHZ6xaVhaCBtZWR6aSBFUEkgYSB2eXN2ZXTEvnVqw7pjaW1pIHByZW1lbm7DvW1pIChsb2cxcChCRVZfUEhFViksIGxvZzFwKEhEUCkpIGplIGxpbmXDoXJueS4gTmnFvsWhaWUgc2tvbnRyb2x1amVtZSwgxI1pIG9iecSNYWpuw6Eg4oCecHJpYW1rYeKAnCBuYW96YWogc3RhxI3DrSDigJMgYSBhayBuaWUsIHByaWTDoW1lIGplbW7DqSB6YWtyaXZlbmllIChrdmFkcsOhdHkpIGFsZWJvIHpsb20gdiBza2xvbmUgKGluw70gZWZla3QgcHJpIHZ5xaHFocOtY2ggaG9kbm90w6FjaCAoUClIRVYpLgoKKlpqZWRub2R1xaFlbmU6KgoqKlJFU0VUIHRlc3Q6KiogcsO9Y2hsYSBrb250cm9sYSwgxI1pIHByaWFta2Egc3RhxI3DrS4gTWFsw6EgcC1ob2Rub3RhIOKHkiBwcmlkYcWlIG5lbGluZcOhcm5lIHBydmt5LgoqKkMrUiBncmFmeToqKiB1a8Ohxb51LCBrZGUgc2Ega3JpdmthIG9ow71iYSDigJMga3RvcsO6IHByZW1lbm7DuiB0cmFuc2Zvcm1vdmHFpS4KKipLdmFkcsOhdHkgbG9nLXByZW1lbm7DvWNoOioqIGRvdm9saWEgamVtbsOpIHpha3JpdmVuaWUuCioqWmxvbSB2IHNrbG9uZToqKiBkb3ZvbMOtIGluw70gdnBseXYgKFApSEVWIHByaSBuacW+xaHDrWNoIHZzLiB2ecWhxaHDrWNoIGhvZG5vdMOhY2guCioqVsO9YmVyIG1vZGVsdToqKiBwb3Jvdm7DoW1lIEFJQyBhIChhayBzw7ogbW9kZWx5IHYgdGVqIGlzdGVqIG1pZXJrZSkgYWogQU5PVkE7IGtvZWZpY2llbnR5IHbFvmR5IHMgcm9idXN0bsO9bWkgU0UgKEhDMSkuCgojIyAxKSBSYW1zZXkgUkVTRVQg4oCTIGtvbnRyb2xhIMWhcGVjaWZpa8OhY2llCmBgYHtyfQpsaWJyYXJ5KGxtdGVzdCkKCiMgWsOha2xhZG7DvSAobGluZcOhcm55KSBtb2RlbCDigJMgcG91xb7DrXZhbWUgdGVuLCBzIGt0b3LDvW0gcHJhY3VqZcWhIHYgcHLDoWNpOgoKbV9saW4gPC0gbG0oRVBJIH4gbG9nMXAoQkVWX1BIRVYpICsgbG9nMXAoSERQKSwgZGF0YSA9IHVkYWplKQoKIyBSYW1zZXkgUkVTRVQgdGVzdAoKcmVzZXR0ZXN0KG1fbGluKQoKYGBgClJFU0VUIHZ5xaFpZWwgcCA9IDAuMDExIOKGkiB6w6FrbGFkbsOhIGxpbmXDoXJuYSDFoXBlY2lmaWvDoWNpYSBwcmF2ZGVwb2RvYm5lIGNow71iYSAobmVsaW5lYXJpdGEvbmV6YWhybnV0w70gdHZhcikuIFByZXRvIMSPYWxlaiBjaWVsZW5lIGjEvmFkw6FtZSBrZGUgYnkgc2EgbW9obGEga3JpdmthIG9ow71iYcWlIGEgxI1pIHNhIG9wbGF0w60gcHJpZGHFpSBrdmFkcsOhdHkgYWxlYm8gemxvbS4KCiMjIDIpIENvbXBvbmVudCArIFJlc2lkdWFsIChDK1IpIGdyYWZ5IOKAkyBrZGUgc2Ega3JpdmthIG9ow71iYQpgYGB7cn0KbGlicmFyeShjYXIpCmNhcjo6Y3JQbG90cyhtX2xpbikgICAjIHBvenJpZW1lIHpha3JpdmVuaWUgcHJpIGxvZzFwKEJFVl9QSEVWKSBhIGxvZzFwKEhEUCkKCmBgYApDK1IgcHJlIGxvZzFwKEJFVl9QSEVWKSB1a2F6dWplIGNpdGXEvm7DqSBwcmVobnV0aWUgb2tvbG8gfjfigJM5IOKGkiBrYW5kaWTDoXQgbmEgbmVsaW5lw6FybnkgdHZhci4gQytSIHByZSBsb2cxcChIRFApIGplIHByYWt0aWNreSBwcmlhbWthIChsZW4gamVtbsOhIGtyaXZrYSksIHRha8W+ZSB2w71yYXpudSBuZWxpbmVhcml0dSBwcmkgSERQIG5lxI1ha8OhbWUuIFogdG9obyBkw7R2b2R1IHRlc3R1amVtZSBobGF2bmUgw7pwcmF2eSBwcmkgKFApSEVWLgoKIyMgMykgS3ZhZHJhdGlja8OpIMSNbGVueSDigJMgamVtbsOpIHpha3JpdmVuaWUKYGBge3J9CmxpYnJhcnkoc2FuZHdpY2gpCmxpYnJhcnkobG10ZXN0KQoKbV9xdWFkIDwtIGxtKEVQSSB+IGxvZzFwKEJFVl9QSEVWKSArIEkobG9nMXAoQkVWX1BIRVYpXjIpICsKbG9nMXAoSERQKSAgICAgICsgSShsb2cxcChIRFApXjIpLApkYXRhID0gdWRhamUpCgojIFBvcm92bmFuaWUga3ZhbGl0eSAobmnFvsWhw60gQUlDIGplIGxlcMWhw60pCgpBSUMobV9saW4sIG1fcXVhZCkKCiMgQU5PVkE6Cgphbm92YShtX2xpbiwgbV9xdWFkKQoKIyBLb2VmaWNpZW50eSBzIHJvYnVzdG7DvW1pIFNFIChIQzEpCgpjb2VmdGVzdChtX2xpbiwgIHZjb3YgPSB2Y292SEMobV9saW4sICB0eXBlID0gIkhDMSIpKQpjb2VmdGVzdChtX3F1YWQsIHZjb3YgPSB2Y292SEMobV9xdWFkLCB0eXBlID0gIkhDMSIpKQoKYGBgCi0gKkFJQyogc2EgemhvcsWhaWwgKDM0NS4wIHZzLiAzNDMuNSkuCgotICpBTk9WQToqIHAgPSAwLjMzIOKGkiBrdmFkcsOhdHkgbmV6bGVwxaF1asO6IG1vZGVsLgoKLSAqUm9idXN0bsOpIFNFIChIQzEpOioga3ZhZHJhdGlja8OpIGtvZWZpY2llbnR5IG5ldsO9em5hbW7DqS4KCioqWsOhdmVyOioqIGt2YWRyw6F0eSBuZXByaW5pZXNsaSBwcsOtbm9zIOKAkyBuZWxpbmVhcml0dSB0YWt0byBuZXBvdHZyZHp1amVtZS4KCiMjIDQpIFpsb20gdiBza2xvbmUg4oCTIGluw70gZWZla3QgKFApSEVWIHByaSB2ecWhxaHDrWNoIGhvZG5vdMOhY2gKYGBge3J9CiMgUHJhaDogbWVkacOhbiBsb2cxcChCRVZfUEhFVikKCmN1dF9iZXYgPC0gbWVkaWFuKGxvZzFwKHVkYWplJEJFVl9QSEVWKSwgbmEucm0gPSBUUlVFKQp1ZGFqZSREX2hpZ2hCRVYgPC0gYXMuaW50ZWdlcihsb2cxcCh1ZGFqZSRCRVZfUEhFVikgPj0gY3V0X2JldikKCiMgKGEpIGxlbiBwb3N1biAoaW50ZXJjZXB0IHNoaWZ0KQoKbV9zaGlmdCA8LSBsbShFUEkgfiBEX2hpZ2hCRVYgKyBsb2cxcChCRVZfUEhFVikgKyBsb2cxcChIRFApLCBkYXRhID0gdWRhamUpCgojIChiKSB6bG9tIHYgc2tsb25lIChpbnRlcmFrY2lhIHByZW1lbm7DoSDDlyBkdW1teSkKCm1fc2xvcGUgPC0gbG0oRVBJIH4gbG9nMXAoQkVWX1BIRVYpKkRfaGlnaEJFViArIGxvZzFwKEhEUCksIGRhdGEgPSB1ZGFqZSkKCiMgUG9yb3ZuYW5pZSBBSUMKCkFJQyhtX2xpbiwgbV9zaGlmdCwgbV9zbG9wZSkKCiMgQU5PVkEgKHJvdm5ha8OhIHZ5c3ZldMS+b3ZhbsOhIHByZW1lbm7DoSkKCmFub3ZhKG1fbGluLCBtX3NoaWZ0KQphbm92YShtX2xpbiwgbV9zbG9wZSkKCiMgUm9idXN0bsOpIFNFCgpjb2VmdGVzdChtX3Nsb3BlLCB2Y292ID0gdmNvdkhDKG1fc2xvcGUsIHR5cGUgPSAiSEMxIikpCgpgYGAKUHJhaCA9IG1lZGnDoW4gbG9nMXAoQkVWX1BIRVYpLiBTa8O6c2lsaSBzbWUgKGEpIHBvc3VuIHByaWFta3kgYSAoYikgem1lbnUgc2tsb251IChpbnRlcmFrY2lhIHMgZHVtbXkpOgoKQUlDIGplIHZ5xaHFocOtIG5lxb4gdiBsaW5lw6Fybm9tIG1vZGVsaSAoaG9yxaFpZSkuCgpBTk9WQTogcG9zdW4gcCA9IDAuNDEsIHptZW5hIHNrbG9udSBwID0gMC41Mi4KClJvYnVzdG7DqSBTRTogaW50ZXJha2NpYSBuZXbDvXpuYW1uw6EuCgoqKlrDoXZlcjoqKiBkw7RrYXogcHJlIG9kbGnFoW7DvSBlZmVrdCAoUClIRVYgcHJpIOKAnnZ5xaHFocOtY2jigJwgw7pyb3ZuaWFjaCBzbWUgbmVuYcWhbGkuCgojIyA1KSBWw71iZXIgcHJhY292bsOpaG8gbW9kZWx1IGEga3LDoXRrZSB6aHJudXRpZQoKS2XEj8W+ZSAoaSkgUkVTRVQgc8OtY2UgbmF6bmHEjWlsIG5lc3Byw6F2bnUgxaFwZWNpZmlrw6FjaXUsIGFsZSAoaWkpIEMrUiB1a8OhemFsIGxlbiBqZW1uw6kgb2h5YnkgYSAoaWlpKSBhbmkga3ZhZHLDoXR5LCBhbmkgemxvbSDFoXRhdGlzdGlja3kgbmV6bGVwxaFpbGkgbW9kZWwsIGFrbyBwcmFjb3Zuw70gbW9kZWwgcG9uZWNow6F2YW1lIHrDoWtsYWRuw7ogbGluZcOhcm51IMWhcGVjaWZpa8OhY2l1IHMgcm9idXN0bsO9bWkgY2h5YmFtaSAoSEMxKS4gViBuZWogdnljaMOhZHphIGxvZzFwKEJFVl9QSEVWKSBuZWdhdMOtdm5lIGEgdsO9em5hbW5lLCBrw71tIGxvZzFwKEhEUCkgcG96aXTDrXZuZSBhIHbDvXpuYW1uZS4gUHJha3RpY2t5OiB2IHRvbXRvIHPDumJvcmUgZMOhdCBWNCBuZXZ5Y2jDoWR6YSwgxb5lIGJ5IG1pZXJuZSB6YWtyaXZlbmlhIGFsZWJvIHByYWhvdsOpIGVmZWt0eSBtZW5pbGkgaGxhdm7DqSB6w6F2ZXJ5OyBhayBqZSBuZWxpbmVhcml0YSBwcsOtdG9tbsOhLCBqZSBza8O0ciBzbGFiw6EgYSBuYcWhZSB0ZXN0eSBqdSBuZXZlZGlhIHByZXN2ZWTEjWl2byB1Y2hvcGnFpSAobGltaXQgdnpvcmt5KS4KCiMjIyBQb3Jvdm7DoXZhY2lhIHRhYnXEvmthIG1vZGVsb3YKYGBge3J9CiMgaXN0b3RhLCDFvmUgbcOhbWUgesOha2xhZG7DvSBsaW5lw6FybnkgbW9kZWwKaWYgKCFleGlzdHMoIm1fbGluIikpIHsKICBtX2xpbiA8LSBsbShFUEkgfiBsb2cxcChCRVZfUEhFVikgKyBsb2cxcChIRFApLCBkYXRhID0gdWRhamUpCn0KCm1vZHMgPC0gbGlzdCgiTGluZcOhcm55IiA9IG1fbGluKQppZiAoZXhpc3RzKCJtX3F1YWQiKSkgICBtb2RzW1siS3ZhZHJhdGlja8O9Il1dICAgPC0gbV9xdWFkCmlmIChleGlzdHMoIm1fc2xvcGUiKSkgIG1vZHNbWyJabG9tIHYgc2tsb25lIl1dIDwtIG1fc2xvcGUKaWYgKGV4aXN0cygibV9zaGlmdCIpKSAgbW9kc1tbIlBvc3VuIMO6cm92bmUiXV0gIDwtIG1fc2hpZnQKCmxpYnJhcnkocHVycnIpOyBsaWJyYXJ5KGxtdGVzdCk7IGxpYnJhcnkoZHBseXIpOyBsaWJyYXJ5KGthYmxlRXh0cmEpCgpyZXNldF9wIDwtIGZ1bmN0aW9uKG0pIHRyeUNhdGNoKHJlc2V0dGVzdChtKSRwLnZhbHVlLCBlcnJvciA9IGZ1bmN0aW9uKGUpIE5BX3JlYWxfKQphbm92YV92c19iYXNlIDwtIGZ1bmN0aW9uKG0sIGJhc2UpIHsKICBpZiAoaWRlbnRpY2FsKGZvcm11bGEoYmFzZSlbWzJdXSwgZm9ybXVsYShtKVtbMl1dKSkgYXMubnVtZXJpYyhhbm92YShiYXNlLCBtKSRgUHIoPkYpYFsyXSkgZWxzZSBOQV9yZWFsXwp9CgpiYXNlX21vZGVsIDwtIG1vZHNbWyJMaW5lw6FybnkiXV0KY21wX3RibCA8LSB0aWJibGUoCiAgbW9kZWwgPSBuYW1lcyhtb2RzKSwKICBBSUMgICA9IG1hcF9kYmwobW9kcywgQUlDKSwKICBhZGpSMiA9IG1hcF9kYmwobW9kcywgfiBzdW1tYXJ5KC54KSRhZGouci5zcXVhcmVkKSwKICBSRVNFVF9wID0gbWFwX2RibChtb2RzLCByZXNldF9wKSwKICBBTk9WQV92c19saW5fcCA9IG1hcF9kYmwobW9kcywgfiBhbm92YV92c19iYXNlKC54LCBiYXNlX21vZGVsKSkKKSAlPiUgYXJyYW5nZShBSUMpCgprYmwoY21wX3RibCwgZGlnaXRzID0gMywgY2FwdGlvbiA9ICJQb3Jvdm5hbmllIMWhcGVjaWZpa8OhY2nDrSAobmnFvsWhaWUgQUlDIGplIGxlcMWhaWUpIikgJT4lCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRkFMU0UpCgpgYGAKCgojIyMgR3JhZiBwcmVkaWvEjW7DvWNoIGtyaXZpZWsgKExpbmXDoXJueSB2cy4gS3ZhZHJhdGlja8O9IHZzLiBabG9tKQpgYGB7cn0KCiMgUHJlZGlrY2llIHByaSBtZWRpw6FuZSBIRFAKeF9ncmlkIDwtIHRpYmJsZSgKICBCRVZfUEhFViA9IHNlcShtaW4odWRhamUkQkVWX1BIRVYsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgICAgICAgbWF4KHVkYWplJEJFVl9QSEVWLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSAyMDApLAogIEhEUCA9IG1lZGlhbih1ZGFqZSRIRFAsIG5hLnJtID0gVFJVRSkKKQoKcHJlZF9vbmUgPC0gZnVuY3Rpb24obSwgbmFtZSkgewogICMgKGFrIG1vZGVsIHBvdHJlYnVqZSBkdW1teSBEX2hpZ2hCRVYsIGRvcG/EjcOtdGFtZSBqdSBwb2TEvmEgcHJhaHUsIGt0b3LDvSBwb3XFvsOtdmFtZSB2IHByw6FjaSkKICBuZXdkYXQgPC0geF9ncmlkCiAgaWYgKCJEX2hpZ2hCRVYiICVpbiUgbmFtZXMobW9kZWwuZnJhbWUobSkpKSB7CiAgICBjdXRfYmV2IDwtIG1lZGlhbihsb2cxcCh1ZGFqZSRCRVZfUEhFViksIG5hLnJtID0gVFJVRSkKICAgIG5ld2RhdCREX2hpZ2hCRVYgPC0gYXMuaW50ZWdlcihsb2cxcChuZXdkYXQkQkVWX1BIRVYpID49IGN1dF9iZXYpCiAgfQogIHByIDwtIHByZWRpY3QobSwgbmV3ZGF0YSA9IG5ld2RhdCwgc2UuZml0ID0gVFJVRSkKICB0aWJibGUobW9kZWwgPSBuYW1lLAogICAgICAgICBCRVZfUEhFViA9IG5ld2RhdCRCRVZfUEhFViwKICAgICAgICAgZml0ID0gcHIkZml0LAogICAgICAgICBsbyAgPSBwciRmaXQgLSAxLjk2KnByJHNlLmZpdCwKICAgICAgICAgaGkgID0gcHIkZml0ICsgMS45NipwciRzZS5maXQpCn0KCnByZWRfYWxsIDwtIGJpbmRfcm93cygKICBwcmVkX29uZShtX2xpbiwgICJMaW5lw6FybnkiKSwKICBwcmVkX29uZShtX3F1YWQsICJLdmFkcmF0aWNrw70iKSwKICBwcmVkX29uZShtX3Nsb3BlLCJabG9tIHYgc2tsb25lIikKKQoKZ2dwbG90KHByZWRfYWxsLCBhZXMoQkVWX1BIRVYsIGZpdCwgY29sb3IgPSBtb2RlbCwgZmlsbCA9IG1vZGVsKSkgKwogIGdlb21fcmliYm9uKGFlcyh5bWluID0gbG8sIHltYXggPSBoaSksIGFscGhhID0gMC4xMCwgY29sb3IgPSBOQSkgKwogIGdlb21fbGluZShzaXplID0gMSkgKwogIGxhYnMoeCA9ICIoUClIRVYgKHBvxI1ldCkiLCB5ID0gIlByZWRpa292YW7DqSBFUEkiLAogICAgICAgdGl0bGUgPSAiUHJlZGlrxI1uw6kga3Jpdmt5OiBFUEkgdnMuIChQKUhFViBwcmkgbWVkacOhbmUgSERQIiwKICAgICAgIHN1YnRpdGxlID0gIlBvcm92bmFuaWUgxaFwZWNpZmlrw6FjacOtIChsaW5lw6FybnksIGt2YWRyYXRpY2vDvSwgemxvbSB2IHNrbG9uZSkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmBgYApHcmFmIHBvcm92bsOhdmEgcHJlZGlrxI1uw6kga3Jpdmt5IEVQSSB2cy4gKFApSEVWIHByaSBtZWRpw6Fub3ZvbSBIRFAgcHJlIHRyaSDFoXBlY2lmaWvDoWNpZSAobGluZcOhcm5hIHYgbG9nZSwga3ZhZHJhdGlja8OhLCBhIOKAnnpsb20gdiBza2xvbmXigJwpLiBWxaFldGt5IHRyaSBtb2RlbHkgdWthenVqw7ogcm92bmFrw70gcHLDrWJlaDogcyByYXN0w7pjaW0gKFApSEVWIEVQSSBrbGVzw6EgYSBlZmVrdCBzYSBwb3N0dXBuZSBzcGxvxaHFpXVqZSAobmFqbcOkIHByaSBuw616a3ljaCBob2Rub3TDoWNoIGplIHBva2xlcyBzdHJtxaHDrSkuIFJvemRpZWx5IG1lZHppIGtyaXZrYW1pIHPDuiBtYWzDqSDigJMga3ZhZHJhdGlja8OhIHZlcnppYSBqZSBvIG5pZcSNbyBwcnVkxaFpYSB2IGNodm9zdGUsIHphdGlhxL4gxI1vIOKAnnpsb20gdiBza2xvbmXigJwgc2EgcHJha3RpY2t5IHByZWtyw712YSBzIGxpbmXDoXJueW0gbW9kZWxvbS4gSW50ZXJ2YWx5IG5laXN0b3R5IChwcmllc3ZpdG7DqSBww6FzbWEpIHNhIHJvesWhaXJ1asO6IHYgZXh0csOpbW9jaCwga2RlIGplIG1lbmVqIGTDoXQuIFNwb2x1IHMgdsO9c2xlZGthbWkgQUlDL0FOT1ZBIHZ5xaHFoWllIHRvIG5hem5hxI11amUsIMW+ZSBqZWRub2R1Y2jDvSBsaW5lw6FybnkgbW9kZWwgdiBsb2dlIHBvc3RhxI11amU7IHByw61wYWRuw6kgbmVsaW5lYXJpdHkgbmlqYWtvIG5lbWVuaWEga3ZhbGl0YXTDrXZueSB6w6F2ZXIgbyBuZWdhdMOtdm5laiBhc29jacOhY2lpIChQKUhFViBhIEVQSSBwbyB6b2jEvmFkbmVuw60gSERQLgoKCiMgU3RydcSNbsOhIHRhYnXEvmthIHbDvXNsZWRrb3YgYSB6w6F2ZXIKYGBge3J9CmxpYnJhcnkodGliYmxlKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgojIyAxKSBzdHJ1xI1uw6EgZGlhZ25vc3Rpa2EKCnN1bV90YmwgPC0gdGliYmxlOjp0aWJibGUoCmBR4oCTUSBwbG90YCAgICAgICAgICAgICAgICAgID0gIlbDpMSNxaFpbmEgYm9kb3YgbmEgcHJpYW1rZTsgbGVuIG1pZXJuZSBvZGNow71sa3kgdiBjaHZvc3RvY2guIiwKYFNjYWxl4oCTTG9jYXRpb25gICAgICAgICAgICAgPSAiSmVtbsO9IFUtdHZhciDihpIgc2xhYsOhIGhldGVyb3NrZWRhc3RpY2l0YSAocmllxaFpbWUgcm9idXN0bsO9bWkgU0UpLiIsCmBSZXNpZHVhbHMgdnMgTGV2ZXJhZ2VgICAgICA9ICJQw6FyIHZwbHl2bsO9Y2ggYm9kb3YsIGJleiBleHRyw6ltb3YuIiwKYEhldGVyb3NrZWRhc3RpY2l0YSDigJMgdGVzdHlgPSAiQnJldXNjaOKAk1BhZ2FuIGEgTkNWIG5ldsO9em5hbW7DqTsgV2hpdGUgxaF0w71sIGhyYW5pxI1uw70g4oaSIHNrw7RyIHNsYWLDvSBuw6F6bmFrLiIsCmBSRVNFVCAoxaFwZWNpZmlrw6FjaWEpYCAgICAgID0gInAg4omIIDAuMDExIOKHkiBsaW5lw6FybmEgxaFwZWNpZmlrw6FjaWEgbcOhIHpuw6Fta3kgbmVzcHLDoXZuZWogZm9ybXkgKHNrw7rFoWFsaSBzbWUgamVtbsOpIG5lbGluZWFyaXR5KS4iCikKCmVtZXJhbGRfbGlnaHQgPC0gIiNFQ0ZERjUiOyBlbWVyYWxkX2hlYWQgPC0gIiNEMUZBRTUiOyBlbWVyYWxkX3RleHQgPC0gIiMwNjVGNDYiCgprYmwoCnN1bV90YmwsCmNhcHRpb24gPSAiRGlhZ25vc3Rpa2Eg4oCTIHN0cnXEjW7DqSB6aHJudXRpZSIsCmJvb2t0YWJzID0gVFJVRQopIHw+CmthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IFRSVUUsIGh0bWxfZm9udCA9ICJIZWx2ZXRpY2EiKSB8Pgpyb3dfc3BlYygwLCBiYWNrZ3JvdW5kID0gZW1lcmFsZF9oZWFkLCBjb2xvciA9IGVtZXJhbGRfdGV4dCwgYm9sZCA9IFRSVUUpIHw+CmNvbHVtbl9zcGVjKDE6bmNvbChzdW1fdGJsKSwgYmFja2dyb3VuZCA9IGVtZXJhbGRfbGlnaHQsIGNvbG9yID0gZW1lcmFsZF90ZXh0LCBib3JkZXJfbGVmdCA9IFRSVUUsIGJvcmRlcl9yaWdodCA9IFRSVUUpCgojIyAyKSBwb3Jvdm5hbmllIMWhcGVjaWZpa8OhY2nDrSAoQUlDKQoKIyBwcmVkcG9rbGFkOiBvYmpla3R5IG1fbGluLCBtX3F1YWQsIG1fc2xvcGUgc8O6IHXFviBvZGhhZG51dMOpIHYgZG9rdW1lbnRlCgphaWNfdGJsIDwtIHRyeUNhdGNoKAp7CmFhIDwtIEFJQyhtX2xpbiwgbV9xdWFkLCBtX3Nsb3BlKQpkcGx5cjo6cmVuYW1lKGFhLCBNb2RlbCA9IGRmLCBBSUMgPSBBSUMpIHw+CmRwbHlyOjptdXRhdGUoTW9kZWwgPSByb3duYW1lcyhhYSkpCn0sCmVycm9yID0gZnVuY3Rpb24oZSkgdGliYmxlOjp0aWJibGUoCk1vZGVsID0gYygiTGluZcOhcm55IiwgIkt2YWRyYXRpY2vDvSIsICJabG9tIHYgc2tsb25lIiksCkFJQyAgID0gYygzNDMuNTAsIDM0NS4wMywgMzQ2LjM2KSAgICMgaG9kbm90eSB6IHR2b2ppY2ggdsO9c3R1cG92CikKKQoKa2JsKGFpY190YmwsIGNhcHRpb24gPSAiUG9yb3ZuYW5pZSBrdmFsaXR5IG1vZGVsb3YgKG5pxb7FocOtIEFJQyA9IGxlcMWhw60pIiwgYm9va3RhYnMgPSBUUlVFKSB8PgprYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGQUxTRSwgaHRtbF9mb250ID0gIkhlbHZldGljYSIpIHw+CnJvd19zcGVjKDAsIGJhY2tncm91bmQgPSBlbWVyYWxkX2hlYWQsIGNvbG9yID0gZW1lcmFsZF90ZXh0LCBib2xkID0gVFJVRSkgfD4KY29sdW1uX3NwZWMoMTpuY29sKGFpY190YmwpLCBiYWNrZ3JvdW5kID0gZW1lcmFsZF9saWdodCwgY29sb3IgPSBlbWVyYWxkX3RleHQpCgojIyAzKSBoeXBvdMOpenkKCmh5cF90YmwgPC0gdGliYmxlOjp0cmliYmxlKAp+UHJlbWVubsOhLCAgfmBIMSAob8SNYWvDoXZhbmllKWAsICAgfmBSb3pob2RudXRpZSBvIEgwYCwgICAgICAgICAgICAgICB+YFJvemhvZG51dGllIG8gSDFgLCAgICAgICAgICAgICAgflBvem7DoW1rYSwKIkJFViIsICAgICAgIs6yID4gMCIsICAgICAgICAgICAgICAiTkVaQU1JRVRBTSAvIG5laXN0w6kiLCAgICAgICAgICAgICJORVBPRFBPUlVKRU1FIiwgICAgICAgICAgICAgICAgICAiRWZla3QgbmV2w716bmFtbsO9IGFsZWJvIHrDoXBvcm7DvS4iLAoiQkVWX1BIRVYiLCAizrIgPiAwIiwgICAgICAgICAgICAgICJaQU1JRVRBTSAodsO9em5hbW7DqSwgesOhcG9ybsOpKSIsICAgIlpBTUlFVEFNIChwb3ppdMOtdm55IHNhIG5lcG90dnJkaWwpIiwibG9nMXAoQkVWX1BIRVYpIHN0YWJpbG5lIG5lZ2F0w612bnkgcyBIQzEuIiwKIkhEUCIsICAgICAgIs6yID4gMCIsICAgICAgICAgICAgICAiWkFNSUVUQU0gKHbDvXpuYW1uw6ksIHBveml0w612bmUpIiwgIlBPRFBPUlVKRU1FIiwgICAgICAgICAgICAgICAgICAgICJIRFAgdnljaMOhZHphIGtsYWRuZSBhIHbDvXpuYW1uZS4iCikKCmtibChoeXBfdGJsLCBjYXB0aW9uID0gIkh5cG90w6l6eSBhIHJvemhvZG51dGlhIChyb2J1c3Ruw6kgU0UpIiwgYm9va3RhYnMgPSBUUlVFKSB8PgprYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGQUxTRSwgaHRtbF9mb250ID0gIkhlbHZldGljYSIpIHw+CnJvd19zcGVjKDAsIGJhY2tncm91bmQgPSBlbWVyYWxkX2hlYWQsIGNvbG9yID0gZW1lcmFsZF90ZXh0LCBib2xkID0gVFJVRSkgfD4KY29sdW1uX3NwZWMoMTpuY29sKGh5cF90YmwpLCBiYWNrZ3JvdW5kID0gZW1lcmFsZF9saWdodCwgY29sb3IgPSBlbWVyYWxkX3RleHQpCmBgYAojIyBEaXNrdXNpYSwgbGltaXR5IGEgesOhdmVyCgoqKsSMbyB1a8OhemFsYSBkaWFnbm9zdGlrYSBhIHRlc3R5OioqClJvenB0eWwgY2jDvWIgamUgbmFqbcOkICpzbGFibyBuZWhvbW9nw6lubnkqLCBwcmV0byB2IGNlbGVqIHByw6FjaSByZXBvcnR1amVtZSAqcm9idXN0bsOpIHNtZXJvZGFqbsOpIGNoeWJ5IChIQzEpKi4gCipSRVNFVCB0ZXN0IChwIOKJiCAwLjAxMSkqIHNpZ25hbGl6b3ZhbCwgxb5lIHNhbW90bsOhIHByaWFta2EgbcO0xb5lIGJ5xaUgcHJlIGplZG5vZHVjaMO9IGxpbmXDoXJueSBtb2RlbCB0ZXNuw6EsIHByZXRvIHNtZSBza8O6c2lsaSBqZW1uw6kgbmVsaW5lYXJpdHkgKGt2YWRyw6F0IGxvZzFwKEJFVl9QSEVWKSwga3ZhZHLDoXQgbG9nMXAoSERQKSkgYSBhaiB6bG9tIHYgc2tsb25lIHBvZMS+YSDDunJvdm5lIChQKUhFVi4KCioqUG9yb3ZuYW5pZSDFoXBlY2lmaWvDoWNpw606KioKTmFwcmllayBzaWduw6FsdSB6IFJFU0VULXUgc2Ega3ZhbGl0YSBtb2RlbG92IG5lemxlcMWhaWxhIOKAkyBBSUMgamUgbmFqbmnFvsWhw60gcHJpIGxpbmXDoXJub20gbW9kZWxpIGEgQU5PVkEgcG9yb3ZuYW5pYSBrdmFkcmF0aWNrZWovemxvbW92ZWogxaFwZWNpZmlrw6FjaWUgdm/EjWkgbGluZcOhcm5laiBuZXZ5xaFsaSB2w716bmFtbmUuIFByZWRpa8SNbsOpIGtyaXZreSBwcmUgdsWhZXRreSB0cmkgdmVyemllIHPDuiB0dmFyb3ZvIHBvZG9ibsOpIChtaWVybmUga2xlc2Fqw7pjZSksIHJvemRpZWx5IHPDuiBtYWzDqSBhIHYgcsOhbWNpIGludGVydmFsb3Ygc3BvxL5haGxpdm9zdGkuCgoqKkludGVycHJldMOhY2lhIMO6xI1pbmtvdiAocm9idXN0bsOpIFNFKToqKgoKLSBsb2cxcChCRVZfUEhFVikgamUgbmVnYXTDrXZueSBhIMWhdGF0aXN0aWNreSB2w716bmFtbsO9IOKAkyB2IG5hxaFvbSBzw7pib3JlIHNhIHMgdnnFocWhw61tIHJvesWhw61yZW7DrW0gKFApSEVWIHNww6FqYSBuacW+xaHDrSBFUEkuCgotIEhEUCBqZSBwb3ppdMOtdm55IGEgdsO9em5hbW7DvSDigJMga3JhamlueS9yb2t5IHMgdnnFocWhw61tIEhEUCBkb3NhaHVqw7ogdnnFocWhw60gRVBJLgoKLSBTYW1vdG7DqSBCRVYgbmV2ecWhbG8gcm9idXN0bmUgcG96aXTDrXZuZS4KCioqWmplZG5vZHXFoWVuZToqKiB2aWFjIChQKUhFViDiiaAgdnnFocWhw60gRVBJIHYga3LDoXRrb20gaG9yaXpvbnRlOyBFUEkgenJlam1lIG92cGx5dsWIdWrDuiDFoWlyxaFpZSBmYWt0b3J5IChla29ub21pY2vDoSDDunJvdmXFiCwgxaF0cnVrdMO6cmEgZW5lcmdpw60sIHpsb8W+ZW5pZSBkb3ByYXZ5IGF0xI8uKS4KCioqTGltaXR5OioqIG1hbMOhIHZ6b3JrYSAoVjQgw5cgcm9reSksIGFncmVnYcSNbsOhIMO6cm92ZcWILCBtb8W+bsOhIG1lcmFjaWEgY2h5YmEgdiByZWdpc3Ryb2NoIHZvemlkaWVsLCBjaMO9YmFqw7pjZSBrb250cm9seSAoZW5lcmdldGlja8O9IG1peCwgZG9wcmF2bsOpIHbDvWtvbnksIHByaWVteXNlbCkuIEtyw6F0a2Ugb2Jkb2JpZSBtw7TFvmUgc2tyw712YcWlIG9uZXNrb3JlbsOpIMO6xI1pbmt5Lgo=