S využitím databázy dopravných nehôd budem analyzovať faktory, ktoré
súvisia s počtom zranených pri nehode.
Organizácia priečinkov a podpriečinkov sa však môže líšiť v
závislosti od projektu, preto cestu nezaraďujem do Chunk-u.
Nie všetky údaje budú použité, preto som vybrala len niektoré stĺpce
pre neskoršie použitie.
Príprava databázy, čistenie a úprava údajov
Keďže niektoré údaje chýbajú, doplnila som ich mediánovými hodnotami
premennej, ktorú zvažujem.
# Načítanie údajov o dopravných nehodách
udaje <- read.csv("premavka.csv.csv", dec=".", sep=",", header = TRUE)
# Vyberiem len premenné, ktoré budem používať v analýze
udaje.sub <- udaje[, c("injuries_total",
"num_units",
"crash_hour",
"crash_day_of_week",
"crash_month")]
# Doplnenie chýbajúcich hodnôt mediánom (imputácia)
column_medians <- sapply(udaje.sub, median, na.rm = TRUE)
udaje_imputed <- udaje.sub
for (col in names(udaje.sub)) {
udaje_imputed[[col]][is.na(udaje_imputed[[col]])] <- column_medians[col]
}
udaje.sub <- udaje_imputed
Teraz chcem vizuálne preskúmať tvar jednotlivých premenných a overiť,
či sa v údajoch nenachádzajú nezrovnalosti, napríklad extrémne alebo
nulové hodnoty. Na tento účel využívam boxploty, ktoré umožňujú rýchlu
identifikáciu odľahlých pozorovaní a základných charakteristík
rozdelenia dát.
# Predpokladáme, že udaje.sub je dátový rámec s vybranými premennými
# Počet premenných
num_plots <- length(names(udaje.sub))
# Nastavenie rozloženia grafov: 2 x 2
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1)) # úprava okrajov
# Vykreslenie boxplotov pre každú premennú
for (col in names(udaje.sub)) {
boxplot(udaje.sub[[col]],
main = col,
xlab = "Hodnota",
col = "lightblue")
}

# Spoločný nadpis
mtext("Boxploty jednotlivých premenných", outer = TRUE, cex = 1.4, font = 2)

NA
NA
Lineárna regresia
Model odhadujem príkazom lm(). Vysvetľovanou premennou je
počet zranených pri dopravnej nehode
(injuries_total). Ako vysvetľujúce premenné som zvolila
počet zapojených vozidiel (num_units) a
časové charakteristiky nehody, konkrétne hodinu nehody
(crash_hour), deň v týždni (crash_day_of_week) a
mesiac nehody (crash_month).
model <- lm(
injuries_total ~ +1 + num_units + crash_hour + crash_day_of_week + crash_month,
data = udaje.sub
)
summary(model)
Call:
lm(formula = injuries_total ~ +1 + num_units + crash_hour + crash_day_of_week +
crash_month, data = udaje.sub)
Residuals:
Min 1Q Median 3Q Max
-2.9330 -0.3719 -0.3518 0.3171 20.9325
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.2478411 0.0110628 -22.403 < 2e-16 ***
num_units 0.3233581 0.0043563 74.227 < 2e-16 ***
crash_hour -0.0024418 0.0003085 -7.916 2.46e-15 ***
crash_day_of_week -0.0059035 0.0008787 -6.718 1.84e-11 ***
crash_month 0.0030261 0.0005033 6.013 1.82e-09 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.7892 on 209301 degrees of freedom
Multiple R-squared: 0.02626, Adjusted R-squared: 0.02624
F-statistic: 1411 on 4 and 209301 DF, p-value: < 2.2e-16
Objekt triedy lm() mi po odhadnutí modelu poskytuje viacero
užitočných výstupov, ktoré môžem využiť pri interpretácii a diagnostike
regresie:
- Vektor odhadnutých koeficientov model$coefficients –
ukazuje odhadovaný vplyv premenných (num_units,
crash_hour, crash_day_of_week, crash_month)
na vysvetľovanú premennú injuries_total.
- Vektor rezíduí model$residuals – rozdiely medzi skutočnými
hodnotami injuries_total a hodnotami predikovanými
modelom.
- Vektor vyrovnaných hodnôt vysvetľovanej premennej
model$fitted.values – modelom vypočítané (predikované) hodnoty
počtu zranených pri nehode.
- Matica vysvetľujúcich premenných X model.matrix(model) –
numerická matica premenných zahrnutých v modeli, ktorú regresia používa
pri výpočtoch.
Prehľad základných výsledkov a štatistickej významnosti získam
pomocou príkazu summary(model).
Keďže všetky potrebné informácie viem získať priamo z objektu
model, môžem si ich v prípade potreby vypísať aj jednotlivo.
Pre prehľadnosť však budem ďalej pracovať najmä so súhrnom modelu
pomocou príkazu summary(model), ktorý obsahuje koeficienty, ich
štatistickú významnosť, informácie o rezíduách aj celkové vlastnosti
modelu.
#print("Odhadnuté regresné koeficienty sú: ")
#print(model$coefficients)
#print("Odhadnuté rezíduá sú: ")
#print(model$residuals)
#print("Vyrovnané (predikované) hodnoty vysvetľovanej premennej sú: ")
#print(model$fitted.values)
#print("Matica vysvetľujúcich premenných X (model.matrix) je: ")
#print(model.matrix(model))
# (voliteľné) diagnostika vplyvu pozorovaní – diagonála hat-matrix:
#X <- model.matrix(model)
#diag(X %*% solve(t(X) %*% X) %*% t(X))
summary(model)
Call:
lm(formula = injuries_total ~ +1 + num_units + crash_hour + crash_day_of_week +
crash_month, data = udaje.sub)
Residuals:
Min 1Q Median 3Q Max
-2.9330 -0.3719 -0.3518 0.3171 20.9325
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.2478411 0.0110628 -22.403 < 2e-16 ***
num_units 0.3233581 0.0043563 74.227 < 2e-16 ***
crash_hour -0.0024418 0.0003085 -7.916 2.46e-15 ***
crash_day_of_week -0.0059035 0.0008787 -6.718 1.84e-11 ***
crash_month 0.0030261 0.0005033 6.013 1.82e-09 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.7892 on 209301 degrees of freedom
Multiple R-squared: 0.02626, Adjusted R-squared: 0.02624
F-statistic: 1411 on 4 and 209301 DF, p-value: < 2.2e-16
Súhrn odhadovaného regresného modelu poskytuje súbor odhadnutých
regresných koeficientov, ktorých znamienka a štatistická významnosť budú
podrobnejšie interpretované v ďalšej časti analýzy. Ak sa však zameriame
na vlastnosti modelu ako celku, je potrebné najskôr overiť, či sú
splnené základné predpoklady lineárnej regresie.
Na tento účel využívam diagnostické grafy regresného modelu.
Prostredníctvom Q–Q grafu posudzujem predpoklad
normality rezíduí, zatiaľ čo ostatné diagnostické grafy mi umožňujú
identifikovať prípadné problémy s heteroskedasticitou, nelinearitou
alebo prítomnosťou vplyvných pozorovaní. Na základe týchto grafov si
viem vytvoriť prvotný dojem o vhodnosti zvoleného modelu a o tom, či je
možné jeho výsledky považovať za spoľahlivé.
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1))
# Vykresliť všetky 4 diagnostické grafy modelu
plot(model)
# Resetovať layout
par(mfrow = c(1, 1))

Residuals vs. Fitted
Interpretácia konkrétneho grafu
Centrovanie okolo nuly
Rezíduá kolíšu približne okolo hodnoty 0, čo je žiaduci stav. Naznačuje
to, že model nemá systematickú tendenciu nadhodnocovať alebo
podhodnocovať počet zranených pri dopravných nehodách.
Tvar vzťahu
Červená vyhladzovacia čiara (LOESS) vykazuje mierne zakrivenie, čo môže
naznačovať slabú nelinearitu medzi vysvetľujúcimi premennými (najmä
časovými charakteristikami nehody) a počtom zranených. Tento efekt však
nie je výrazný a nepredstavuje zásadný problém pre interpretáciu
modelu.
Rozptyl rezíduí
Vertikálny rozptyl rezíduí sa javí ako približne konštantný v celom
rozsahu vyrovnaných hodnôt, čo naznačuje splnenie predpokladu
homoskedasticity.
Odľahlé pozorovania
Niekoľko bodov sa nachádza ďalej od ostatných, čo môže predstavovať
nehody s mimoriadne vysokým alebo nízkym počtom zranených. Tieto
pozorovania je možné ďalej preskúmať pomocou testu
outlierTest(model) z balíka car.
Q–Q Plot
Čo graf znázorňuje
- Os X predstavuje teoretické kvantily normálneho rozdelenia.
- Os Y zobrazuje štandardizované rezíduá modelu.
- Prerušovaná diagonála predstavuje ideálny prípad, v ktorom by
rezíduá mali normálne rozdelenie.
Interpretácia konkrétneho grafu
Celkový tvar rozdelenia
Väčšina bodov sa nachádza blízko referenčnej priamky, čo naznačuje, že
rezíduá sú približne normálne rozložené.
Krajné hodnoty
Na oboch koncoch grafu dochádza k miernym odchýlkam od priamky, čo môže
signalizovať prítomnosť extrémnych hodnôt – napríklad nehôd s
neštandardným počtom zranených.
Stredná časť rozdelenia
V centrálnej oblasti grafu (okolo mediánu) rezíduá veľmi dobre kopírujú
teoretickú priamku, čo znamená, že väčšina pozorovaní spĺňa predpoklad
normality.
Na základe Q–Q grafu možno konštatovať, že predpoklad normality
rezíduí je v prijateľnej miere splnený, aj keď s miernymi odchýlkami v
extrémoch.
Scale–Location Plot
Čo graf znázorňuje
- Os X predstavuje vyrovnané hodnoty závislej premennej (predikovaný
počet zranených).
- Os Y zobrazuje druhú odmocninu absolútnych štandardizovaných
rezíduí.
- Červená čiara predstavuje vyhladený trend (LOESS).
Interpretácia konkrétneho grafu
Homoskedasticita
Body sú rovnomerne rozptýlené pozdĺž osi X a nevytvárajú lievikovitý
tvar. To naznačuje, že variancia rezíduí je približne konštantná.
Trend vyhladzovacej krivky
Červená LOESS krivka je takmer horizontálna, čo podporuje predpoklad, že
rozptyl rezíduí sa nemení s rastúcimi vyrovnanými hodnotami.
Odľahlé hodnoty
Niekoľko bodov sa nachádza mierne vyššie, avšak nejde o extrémne
pozorovania, ktoré by výrazne narušovali stabilitu modelu.
Residuals vs. Leverage
Čo graf znázorňuje
- Os X predstavuje pákový efekt pozorovaní, ktorý vyjadruje, ako veľmi
sa dané pozorovanie líši od ostatných z hľadiska vysvetľujúcich
premenných.
- Os Y zobrazuje štandardizované rezíduá.
- Bodkované krivky znázorňujú kontúry Cookovej vzdialenosti, ktoré
identifikujú potenciálne vplyvné pozorovania.
Interpretácia konkrétneho grafu
Rozloženie vplyvu
Väčšina pozorovaní má nízky pákový efekt, čo je typické pre dobre
štruktúrované dáta o dopravných nehodách.
Veľkosť rezíduí
Štandardizované rezíduá sa prevažne pohybujú v intervale ⟨−2, 2⟩, čo
naznačuje absenciu extrémnych chýb modelu.
Vplyvné pozorovania
Niektoré pozorovania sa nachádzajú bližšie ku kontúram Cookovej
vzdialenosti, avšak žiadne z nich neprekračuje kritické hranice. Z toho
vyplýva, že žiadna nehoda neovplyvňuje regresné koeficienty
neprimerane.
# Test normality rezíduí
residuals <- residuals(model)
jb_test <- jarque.bera.test(residuals)
jb_test
Jarque Bera Test
data: residuals
X-squared = 4841155, df = 2, p-value < 2.2e-16
# Test odľahlých pozorovaní (Bonferroni)
outlier_test <- outlierTest(model)
outlier_test
NA
Na overenie predpokladu normality rezíduí som použila Jarque–Bera
test. Nulová hypotéza testu predpokladá, že rezíduá majú normálne
rozdelenie. Výsledky testu naznačujú, že rezíduá sa môžu odchyľovať od
normálneho rozdelenia, čo je pri dátach o dopravných nehodách pomerne
časté, keďže počet zranených môže nadobúdať extrémne hodnoty pri
závažných nehodách.
Zároveň som pomocou funkcie outlierTest() identifikovala potenciálne
odľahlé a vplyvné pozorovania. Výsledky testu poukazujú na existenciu
niekoľkých pozorovaní, ktoré môžu mať neprimerane veľký vplyv na odhad
regresných koeficientov. Ide najmä o nehody s mimoriadne vysokým počtom
zranených, ktoré môžu narúšať splnenie predpokladov lineárnej
regresie.
Na základe výsledkov týchto testov sa rozhodnem upraviť pôvodný model
transformáciou vysvetľovanej premennej injuries_total, aby som
znížila vplyv extrémnych hodnôt a zlepšila vlastnosti modelu.
udaje.sub$log_injuries <- log(udaje.sub$injuries_total + 1)
model2 <- lm(
log_injuries ~ num_units + crash_hour + crash_day_of_week + crash_month,
data = udaje.sub
)
summary(model2)
Call:
lm(formula = log_injuries ~ num_units + crash_hour + crash_day_of_week +
crash_month, data = udaje.sub)
Residuals:
Min 1Q Median 3Q Max
-1.3932 -0.2191 -0.2080 0.3322 3.0102
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.0647948 0.0055820 -11.608 < 2e-16 ***
num_units 0.1484818 0.0021981 67.551 < 2e-16 ***
crash_hour -0.0012759 0.0001556 -8.198 2.46e-16 ***
crash_day_of_week -0.0032113 0.0004434 -7.243 4.41e-13 ***
crash_month 0.0017661 0.0002539 6.955 3.53e-12 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.3982 on 209301 degrees of freedom
Multiple R-squared: 0.02207, Adjusted R-squared: 0.02205
F-statistic: 1181 on 4 and 209301 DF, p-value: < 2.2e-16
# Nastaviť rozloženie 2 x 2
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1)) # ZMENŠÍ OKRAJE
# Vykresliť všetky 4 diagnostické grafy modelu
plot(model2)
# (Voliteľné) pridať spoločný nadpis
#mtext("Diagnostické grafy regresného modelu", outer = TRUE, cex = 1.2, font = 2)
# Resetovať layout
par(mfrow = c(1, 1))

# Test normality rezíduí (model2)
residuals <- residuals(model2)
jb_test <- jarque.bera.test(residuals)
jb_test
Jarque Bera Test
data: residuals
X-squared = 115371, df = 2, p-value < 2.2e-16
# Test odľahlých pozorovaní (Bonferroni korekcia)
outlier_test <- outlierTest(model2)
outlier_test
Záver o analýze odľahlých hodnôt
Na základe vykonanej analýzy môžem konštatovať, že vybrané
vysvetľujúce premenné majú štatisticky významný vplyv na vysvetľovanú
premennú súvisiacu s dopravnými nehodami. Niektoré premenné sa v
pôvodnom modeli ukázali ako menej vhodné alebo ťažko interpretovateľné,
a preto bol model v ďalšom kroku upravený.
Testy normality a diagnostické grafy naznačili prítomnosť odľahlých
pozorovaní, ktoré sú typické pre dáta z oblasti dopravy, kde sa
vyskytujú extrémne situácie (napr. nehody s vysokým počtom zranených). Z
tohto dôvodu bola použitá logaritmická transformácia vysvetľovanej
premenne,ktorá prispela k zmierneniu vplyvu extrémnych hodnôt.
V upravenom modeli sa nepreukázali výrazné vplyvné pozorovania ani
závažné nelinearity. Na základe toho možno výsledky regresnej analýzy
považovať za primerané a model za vhodný na ďalšiu interpretáciu.
Heteroskedasticita
Prítomnosť heteroskedasticity (nekonštantného rozptylu náhodnej
zložky) môže viesť k nesprávnemu vyhodnocovaniu t-testov
významnosti jednotlivých regresných koeficientov. Z tohto dôvodu je
nevyhnutné heteroskedasticitu
- detekovať (vizuálne aj pomocou štatistických testov),
- a v prípade jej prítomnosti ju vhodným spôsobom
eliminovať.
V prípade databázy dopravných nehôd je možné heteroskedasticitu
očakávať, keďže počet nehôd a ich následky sa môžu výrazne líšiť v
závislosti od času, dňa alebo iných charakteristík premávky. Aj preto
som sa zamerala na jej posúdenie prostredníctvom diagnostických
grafov.
Na tento účel budem porovnávať dva regresné modely – pôvodný model
označený ako model a upravený model model2, v ktorom
bola použitá logaritmická transformácia vysvetľovanej premennej. Cieľom
tejto úpravy bolo zníženie vplyvu extrémnych hodnôt a stabilizácia
rozptylu rezíduí.
library(ggplot2)
library(patchwork)
df_res <- model.frame(model2)
df_res$res2 <- resid(model2)^2
set.seed(123)
df_plot <- df_res[sample(nrow(df_res), min(3000, nrow(df_res))), ]
p1 <- ggplot(df_plot, aes(x = num_units, y = res2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE) +
labs(
x = "Počet zúčastnených vozidiel",
y = "Štvorce rezíduí",
title = "Štvorce rezíduí vs. počet vozidiel"
) +
theme_minimal()
p2 <- ggplot(df_plot, aes(x = crash_hour, y = res2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE) +
labs(
x = "Hodina nehody",
y = "Štvorce rezíduí",
title = "Štvorce rezíduí vs. hodina nehody"
) +
theme_minimal()
print(p1 + p2)

NA
NA
a teraz model so zlogaritmizovanou premennou num_units.
library(ggplot2)
library(patchwork)
df_res <- model.frame(model2)
df_res$res2 <- resid(model2)^2
df_res <- df_res[
is.finite(df_res$res2) &
!is.na(df_res$num_units) &
!is.na(df_res$crash_hour),
]
set.seed(123)
df_plot <- df_res[sample(nrow(df_res), min(3000, nrow(df_res))), ]
p1 <- ggplot(df_plot, aes(x = log(num_units + 1), y = res2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE) +
labs(x = "log(num_units + 1)",
y = "Squared Residuals",
title = "Residuals vs log(num_units + 1)") +
theme_minimal()
p2 <- ggplot(df_plot, aes(x = crash_hour, y = res2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE) +
labs(x = "crash_hour",
y = "Squared Residuals",
title = "Residuals vs crash_hour") +
theme_minimal()
p1 + p2

NA
NA
Na tomto obrázku podľa vyhladených hodnôt štvorcov rezíduí (vyhladená
krivka v grafe) môžem konštatovať, že nevidím výrazný rast ani pokles
rozptylu rezíduí v závislosti od vysvetľujúcich premenných.
V grafe Residuals vs log(num_units + 1) je väčšina bodov
sústredená pri nižších hodnotách počtu zúčastnených vozidiel a vyhladená
krivka nevykazuje jasný trend, ktorý by naznačoval systematické
zvyšovanie variability.
V grafe Residuals vs crash_hour sa takisto neukazuje
jednoznačný vývoj rozptylu rezíduí v priebehu dňa – vyhladená krivka je
len mierne rastúca, čo môže naznačovať slabý efekt, ale nie výraznú
heteroskedasticitu.
Preto na základe vizuálneho posúdenia nevidím silný dôkaz
heteroskedasticity. Tento záver však následne overím formálnym testom
(napr. Breusch–Pagan testom).
Testovanie prítomnosti heteroskedasticity
# Install (if not yet installed)
# install.packages("lmtest")
# Load the package
library(lmtest)
# Run the Breusch–Pagan test
bptest(model)
studentized Breusch-Pagan test
data: model
BP = 1823, df = 4, p-value < 2.2e-16
# Install (if not yet installed)
# install.packages("lmtest")
# Load the package
library(lmtest)
# Run the Breusch–Pagan test
bptest(model2)
studentized Breusch-Pagan test
data: model2
BP = 2957.9, df = 4, p-value < 2.2e-16
Na základe Breusch–Paganovho testu môžeme konštatovať, že
heteroskedasticita rezíduí je prítomná v pôvodnom modeli
(model) aj v upravenom modeli (model2), keďže
v oboch prípadoch bola nulová hypotéza o konštantnom rozptyle zamietnutá
(p-hodnota < 0,05).
Logaritmická transformácia vysvetľovanej premennej síce zlepšila tvar
rezíduí a ich vizuálne správanie, avšak heteroskedasticitu sa
tým nepodarilo úplne odstrániť. V ďalšej analýze je preto
vhodné pracovať s robustnými (heteroskedasticity-consistent) odhadmi
rozptylov regresných koeficientov, aby boli výsledky testov štatistickej
významnosti spoľahlivé.
#install.packages("sandwich")
#install.packages("lmtest")
library(sandwich)
library(lmtest)
coeftest(model, vcov = vcovHC(model))
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.24784106 0.01823464 -13.5918 < 2.2e-16 ***
num_units 0.32335812 0.00826524 39.1226 < 2.2e-16 ***
crash_hour -0.00244183 0.00034277 -7.1238 1.053e-12 ***
crash_day_of_week -0.00590350 0.00091434 -6.4565 1.074e-10 ***
crash_month 0.00302614 0.00048532 6.2353 4.517e-10 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Všimnime si, že po použití heteroskedasticity-robustných (White)
odhadov rozptylov zostávajú všetky vysvetľujúce premenné
štatisticky významné. To znamená, že aj po korekcii na
heteroskedasticitu sú vzťahy zachytené modelom stabilné a výsledky
testov štatistickej významnosti možno považovať za spoľahlivé.
Použitie tejto metódy je vhodné najmä pri väčšom počte
pozorovaní, čo je v prípade databázy dopravných nehôd splnené.
Alternatívnym riešením heteroskedasticity by bola transformácia alebo
škálovanie niektorých premenných (napr. prepočet na mieru na jednotku
času alebo vozidlo), avšak takéto úpravy by mohli znížiť interpretačnú
prehľadnosť modelu. Z tohto dôvodu považujem použitie robustných odhadov
za primerané riešenie v rámci tejto analýzy.
LS0tCnRpdGxlOiAiRWNvbm9tZXRyaWNzIGluIFIgLSBjdmnEjWVuaWUgNiIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogQmFyYm9yYSBLb3ByZG92YQotLS0KClMgdnl1xb5pdMOtbSBkYXRhYsOhenkgZG9wcmF2bsO9Y2ggbmVow7RkIGJ1ZGVtIGFuYWx5em92YcWlIGZha3RvcnksIGt0b3LDqSBzw7p2aXNpYSBzIHBvxI10b20genJhbmVuw71jaCBwcmkgbmVob2RlLgoKUHJpIMSPYWzFoWVqIHByw6FjaSBidWRlbWUgcG91xb7DrXZhxaUga25pxb5uaWNlCgpgYGB7cn0KbGlicmFyeSh6b28pCmxpYnJhcnkodHNlcmllcykKbGlicmFyeShsbXRlc3QpCmxpYnJhcnkoc2FuZHdpY2gpCmxpYnJhcnkoY2FyKQpybShsaXN0PWxzKCkpCmBgYAoKCgpWICpobGF2bm9tIG1lbnUqIHNvbSAqU2Vzc2lvbiogbmFzdGF2aWxhIG5hICpTb3VyY2UgRmlsZSBMb2NhdGlvbiouIE3DtMW+ZW0gdG8gdXJvYmnFpSBhaiBpbnRlcmFrdMOtdm55bSBzcMO0c29ib20gLSBuYXDDrXNhxaUgZG9sZSBkbyBDb25zb2xlIChhbGVibyB0byB6YWhybsO6xaUgcHJpYW1vIGRvIHNrcmlwdHUpIGFrbyAKCiAqKnNldHdkKCIuLi4iKSoqCgpPcmdhbml6w6FjaWEgcHJpZcSNaW5rb3YgYSBwb2RwcmllxI1pbmtvdiBzYSB2xaFhayBtw7TFvmUgbMOtxaFpxaUgdiB6w6F2aXNsb3N0aSBvZCBwcm9qZWt0dSwgcHJldG8gY2VzdHUgbmV6YXJhxI91amVtIGRvIENodW5rLXUuCgrDmmRhamUgbyBkb3ByYXZuw71jaCBuZWhvZMOhY2ggc8O6IHVzcG9yaWFkYW7DqSB2IHPDumJvcmUgKmNzdiosIHN0xLpwY2Ugc8O6IG9kZGVsZW7DqSB6bmFrb20gIiwiIGEgcG91xb7DrXZhasO6IGRlc2F0aW5uw7ogYm9ka3UuIFYgcHJhY292bm9tIHByaWXEjWlua3UgbcOhbSB1bG/FvmVuw70gc8O6Ym9yIHMgbsOhenZvbSAqcHJlbWF2a2EuY3N2LmNzdiouCgpOaWUgdsWhZXRreSDDumRhamUgYnVkw7ogcG91xb5pdMOpLCBwcmV0byBzb20gdnlicmFsYSBsZW4gbmlla3RvcsOpIHN0xLpwY2UgcHJlIG5lc2tvcsWhaWUgcG91xb5pdGllLgoKIyDDmnZvZCBkbyBwcm9ibMOpbXUsIHN0YW5vdmVuaWUgaHlwb3TDqXogCgpSb3pob2RsYSBzb20gc2EgbW9kZWxvdmHFpSBwb8SNZXQgenJhbmVuw71jaCBwcmkgbmVob2RlICppbmp1cmllc190b3RhbCogdiB6w6F2aXNsb3N0aSBvZCB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoOgoKLSBwb8SNZXQgdm96aWRpZWwgemFwb2plbsO9Y2ggZG8gbmVob2R5ICpudW1fdW5pdHMqLAotIGhvZGluYSBuZWhvZHkgKmNyYXNoX2hvdXIqLAotIGRlxYggdiB0w73FvmRuaSAqY3Jhc2hfZGF5X29mX3dlZWsqLAotIG1lc2lhYyBuZWhvZHkgKmNyYXNoX21vbnRoKi4KCk5hxaFhIHByYWNvdm7DoSBoeXBvdMOpemEgaG92b3LDrSBvIMWhdGF0aXN0aWNreSB2w716bmFtbm9tIHZwbHl2ZSB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoIG5hIHBvxI1ldCB6cmFuZW7DvWNoLCBwcmnEjW9tIG/EjWFrw6F2YW0sIMW+ZToKCi0gdnnFocWhw60gcG/EjWV0IHZvemlkaWVsICgqbnVtX3VuaXRzKikgYnVkZSBzw7p2aXNpZcWlIHMgdnnFocWhw61tIHBvxI10b20genJhbmVuw71jaCAoKmluanVyaWVzX3RvdGFsKiksCi0gxI1hc292w6kgcHJlbWVubsOpICgqY3Jhc2hfaG91ciosICpjcmFzaF9kYXlfb2Zfd2VlayosICpjcmFzaF9tb250aCopIG3DtMW+dSB6YWNoeXTDoXZhxaUgcm96ZGllbHkgdiB6w6F2YcW+bm9zdGkgbmVow7RkIHBvxI1hcyBkxYhhLCB0w73FvmTFiGEgYSByb2thLgoKIyBQcsOtcHJhdmEgZGF0YWLDoXp5LCDEjWlzdGVuaWUgYSDDunByYXZhIMO6ZGFqb3YKCktlxI/FvmUgbmlla3RvcsOpIMO6ZGFqZSBjaMO9YmFqw7osIGRvcGxuaWxhIHNvbSBpY2ggbWVkacOhbm92w71taSBob2Rub3RhbWkgcHJlbWVubmVqLCBrdG9yw7ogenZhxb51amVtLgoKCgoKYGBge3J9CgojIE5hxI3DrXRhbmllIMO6ZGFqb3YgbyBkb3ByYXZuw71jaCBuZWhvZMOhY2gKdWRhamUgPC0gcmVhZC5jc3YoInByZW1hdmthLmNzdi5jc3YiLCBkZWM9Ii4iLCBzZXA9IiwiLCBoZWFkZXIgPSBUUlVFKQoKIyBWeWJlcmllbSBsZW4gcHJlbWVubsOpLCBrdG9yw6kgYnVkZW0gcG91xb7DrXZhxaUgdiBhbmFsw716ZQp1ZGFqZS5zdWIgPC0gdWRhamVbLCBjKCJpbmp1cmllc190b3RhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgIm51bV91bml0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgImNyYXNoX2hvdXIiLAogICAgICAgICAgICAgICAgICAgICAgICJjcmFzaF9kYXlfb2Zfd2VlayIsCiAgICAgICAgICAgICAgICAgICAgICAgImNyYXNoX21vbnRoIildCgojIERvcGxuZW5pZSBjaMO9YmFqw7pjaWNoIGhvZG7DtHQgbWVkacOhbm9tIChpbXB1dMOhY2lhKQpjb2x1bW5fbWVkaWFucyA8LSBzYXBwbHkodWRhamUuc3ViLCBtZWRpYW4sIG5hLnJtID0gVFJVRSkKCnVkYWplX2ltcHV0ZWQgPC0gdWRhamUuc3ViCmZvciAoY29sIGluIG5hbWVzKHVkYWplLnN1YikpIHsKICB1ZGFqZV9pbXB1dGVkW1tjb2xdXVtpcy5uYSh1ZGFqZV9pbXB1dGVkW1tjb2xdXSldIDwtIGNvbHVtbl9tZWRpYW5zW2NvbF0KfQoKdWRhamUuc3ViIDwtIHVkYWplX2ltcHV0ZWQKCgpgYGAKCgpUZXJheiBjaGNlbSB2aXp1w6FsbmUgcHJlc2vDum1hxaUgdHZhciBqZWRub3RsaXbDvWNoIHByZW1lbm7DvWNoIGEgb3ZlcmnFpSwgxI1pIHNhIHYgw7pkYWpvY2ggbmVuYWNow6FkemFqw7ogbmV6cm92bmFsb3N0aSwgbmFwcsOta2xhZCBleHRyw6ltbmUgYWxlYm8gbnVsb3bDqSBob2Rub3R5LgpOYSB0ZW50byDDusSNZWwgdnl1xb7DrXZhbSBib3hwbG90eSwga3RvcsOpIHVtb8W+xYh1asO6IHLDvWNobHUgaWRlbnRpZmlrw6FjaXUgb2TEvmFobMO9Y2ggcG96b3JvdmFuw60gYSB6w6FrbGFkbsO9Y2ggY2hhcmFrdGVyaXN0w61rIHJvemRlbGVuaWEgZMOhdC4KCmBgYHtyfQoKIyBQcmVkcG9rbGFkw6FtZSwgxb5lIHVkYWplLnN1YiBqZSBkw6F0b3bDvSByw6FtZWMgcyB2eWJyYW7DvW1pIHByZW1lbm7DvW1pCgojIFBvxI1ldCBwcmVtZW5uw71jaApudW1fcGxvdHMgPC0gbGVuZ3RoKG5hbWVzKHVkYWplLnN1YikpCgojIE5hc3RhdmVuaWUgcm96bG/FvmVuaWEgZ3JhZm92OiAyIHggMgpwYXIobWZyb3cgPSBjKDIsIDIpKQpwYXIobWFyID0gYyg0LCA0LCAyLCAxKSkgICMgw7pwcmF2YSBva3Jham92CgojIFZ5a3Jlc2xlbmllIGJveHBsb3RvdiBwcmUga2HFvmTDuiBwcmVtZW5uw7oKZm9yIChjb2wgaW4gbmFtZXModWRhamUuc3ViKSkgewogIGJveHBsb3QodWRhamUuc3ViW1tjb2xdXSwKICAgICAgICAgIG1haW4gPSBjb2wsCiAgICAgICAgICB4bGFiID0gIkhvZG5vdGEiLAogICAgICAgICAgY29sID0gImxpZ2h0Ymx1ZSIpCn0KCiMgU3BvbG/EjW7DvSBuYWRwaXMKbXRleHQoIkJveHBsb3R5IGplZG5vdGxpdsO9Y2ggcHJlbWVubsO9Y2giLCBvdXRlciA9IFRSVUUsIGNleCA9IDEuNCwgZm9udCA9IDIpCgoKYGBgCgojIyBMaW5lw6FybmEgcmVncmVzaWEKCgpNb2RlbCBvZGhhZHVqZW0gcHLDrWthem9tICpsbSgpKi4gVnlzdmV0xL5vdmFub3UgcHJlbWVubm91IGplICoqcG/EjWV0IHpyYW5lbsO9Y2ggcHJpIGRvcHJhdm5laiBuZWhvZGUqKiAoKmluanVyaWVzX3RvdGFsKikuIEFrbyB2eXN2ZXTEvnVqw7pjZSBwcmVtZW5uw6kgc29tIHp2b2xpbGEgKipwb8SNZXQgemFwb2plbsO9Y2ggdm96aWRpZWwqKiAoKm51bV91bml0cyopIGEgKirEjWFzb3bDqSBjaGFyYWt0ZXJpc3Rpa3kgbmVob2R5KiosIGtvbmtyw6l0bmUgaG9kaW51IG5laG9keSAoKmNyYXNoX2hvdXIqKSwgZGXFiCB2IHTDvcW+ZG5pICgqY3Jhc2hfZGF5X29mX3dlZWsqKSBhIG1lc2lhYyBuZWhvZHkgKCpjcmFzaF9tb250aCopLgoKYGBge3J9Cm1vZGVsIDwtIGxtKAogIGluanVyaWVzX3RvdGFsIH4gKzEgKyBudW1fdW5pdHMgKyBjcmFzaF9ob3VyICsgY3Jhc2hfZGF5X29mX3dlZWsgKyBjcmFzaF9tb250aCwKICBkYXRhID0gdWRhamUuc3ViCikKc3VtbWFyeShtb2RlbCkKYGBgCk9iamVrdCB0cmllZHkgKmxtKCkqIG1pIHBvIG9kaGFkbnV0w60gbW9kZWx1IHBvc2t5dHVqZSB2aWFjZXJvIHXFvml0b8SNbsO9Y2ggdsO9c3R1cG92LCBrdG9yw6kgbcO0xb5lbSB2eXXFvmnFpSBwcmkgaW50ZXJwcmV0w6FjaWkgYSBkaWFnbm9zdGlrZSByZWdyZXNpZToKCjEuIFZla3RvciBvZGhhZG51dMO9Y2gga29lZmljaWVudG92ICptb2RlbCRjb2VmZmljaWVudHMqIOKAkyB1a2F6dWplIG9kaGFkb3ZhbsO9IHZwbHl2IHByZW1lbm7DvWNoICgqbnVtX3VuaXRzKiwgKmNyYXNoX2hvdXIqLCAqY3Jhc2hfZGF5X29mX3dlZWsqLCAqY3Jhc2hfbW9udGgqKSBuYSB2eXN2ZXTEvm92YW7DuiBwcmVtZW5uw7ogKmluanVyaWVzX3RvdGFsKi4KMi4gVmVrdG9yIHJlesOtZHXDrSAqbW9kZWwkcmVzaWR1YWxzKiDigJMgcm96ZGllbHkgbWVkemkgc2t1dG/EjW7DvW1pIGhvZG5vdGFtaSAqaW5qdXJpZXNfdG90YWwqIGEgaG9kbm90YW1pIHByZWRpa292YW7DvW1pIG1vZGVsb20uCjMuIFZla3RvciB2eXJvdm5hbsO9Y2ggaG9kbsO0dCB2eXN2ZXTEvm92YW5laiBwcmVtZW5uZWogKm1vZGVsJGZpdHRlZC52YWx1ZXMqIOKAkyBtb2RlbG9tIHZ5cG/EjcOtdGFuw6kgKHByZWRpa292YW7DqSkgaG9kbm90eSBwb8SNdHUgenJhbmVuw71jaCBwcmkgbmVob2RlLgo0LiBNYXRpY2EgdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaCBYICptb2RlbC5tYXRyaXgobW9kZWwpKiDigJMgbnVtZXJpY2vDoSBtYXRpY2EgcHJlbWVubsO9Y2ggemFocm51dMO9Y2ggdiBtb2RlbGksIGt0b3LDuiByZWdyZXNpYSBwb3XFvsOtdmEgcHJpIHbDvXBvxI10b2NoLgoKUHJlaMS+YWQgesOha2xhZG7DvWNoIHbDvXNsZWRrb3YgYSDFoXRhdGlzdGlja2VqIHbDvXpuYW1ub3N0aSB6w61za2FtIHBvbW9jb3UgcHLDrWthenUgKnN1bW1hcnkobW9kZWwpKi4KCgpLZcSPxb5lIHbFoWV0a3kgcG90cmVibsOpIGluZm9ybcOhY2llIHZpZW0gesOtc2thxaUgcHJpYW1vIHogb2JqZWt0dSAqbW9kZWwqLCBtw7TFvmVtIHNpIGljaCB2IHByw61wYWRlIHBvdHJlYnkgdnlww61zYcWlIGFqIGplZG5vdGxpdm8uIFByZSBwcmVoxL5hZG5vc8WlIHbFoWFrIGJ1ZGVtIMSPYWxlaiBwcmFjb3ZhxaUgbmFqbcOkIHNvIHPDumhybm9tIG1vZGVsdSBwb21vY291IHByw61rYXp1ICpzdW1tYXJ5KG1vZGVsKSosIGt0b3LDvSBvYnNhaHVqZSBrb2VmaWNpZW50eSwgaWNoIMWhdGF0aXN0aWNrw7ogdsO9em5hbW5vc8WlLCBpbmZvcm3DoWNpZSBvIHJlesOtZHXDoWNoIGFqIGNlbGtvdsOpIHZsYXN0bm9zdGkgbW9kZWx1LgoKYGBge3J9CiNwcmludCgiT2RoYWRudXTDqSByZWdyZXNuw6kga29lZmljaWVudHkgc8O6OiAiKQojcHJpbnQobW9kZWwkY29lZmZpY2llbnRzKQoKI3ByaW50KCJPZGhhZG51dMOpIHJlesOtZHXDoSBzw7o6ICIpCiNwcmludChtb2RlbCRyZXNpZHVhbHMpCgojcHJpbnQoIlZ5cm92bmFuw6kgKHByZWRpa292YW7DqSkgaG9kbm90eSB2eXN2ZXTEvm92YW5laiBwcmVtZW5uZWogc8O6OiAiKQojcHJpbnQobW9kZWwkZml0dGVkLnZhbHVlcykKCiNwcmludCgiTWF0aWNhIHZ5c3ZldMS+dWrDumNpY2ggcHJlbWVubsO9Y2ggWCAobW9kZWwubWF0cml4KSBqZTogIikKI3ByaW50KG1vZGVsLm1hdHJpeChtb2RlbCkpCgojICh2b2xpdGXEvm7DqSkgZGlhZ25vc3Rpa2EgdnBseXZ1IHBvem9yb3ZhbsOtIOKAkyBkaWFnb27DoWxhIGhhdC1tYXRyaXg6CiNYIDwtIG1vZGVsLm1hdHJpeChtb2RlbCkKI2RpYWcoWCAlKiUgc29sdmUodChYKSAlKiUgWCkgJSolIHQoWCkpCgpzdW1tYXJ5KG1vZGVsKQoKYGBgCgoKU8O6aHJuIG9kaGFkb3ZhbsOpaG8gcmVncmVzbsOpaG8gbW9kZWx1IHBvc2t5dHVqZSBzw7pib3Igb2RoYWRudXTDvWNoIHJlZ3Jlc27DvWNoIGtvZWZpY2llbnRvdiwga3RvcsO9Y2ggem5hbWllbmthIGEgxaF0YXRpc3RpY2vDoSB2w716bmFtbm9zxaUgYnVkw7ogcG9kcm9ibmVqxaFpZSBpbnRlcnByZXRvdmFuw6kgdiDEj2FsxaFlaiDEjWFzdGkgYW5hbMO9enkuIEFrIHNhIHbFoWFrIHphbWVyaWFtZSBuYSB2bGFzdG5vc3RpIG1vZGVsdSBha28gY2Vsa3UsIGplIHBvdHJlYm7DqSBuYWpza8O0ciBvdmVyacWlLCDEjWkgc8O6IHNwbG5lbsOpIHrDoWtsYWRuw6kgcHJlZHBva2xhZHkgbGluZcOhcm5laiByZWdyZXNpZS4KCk5hIHRlbnRvIMO6xI1lbCB2eXXFvsOtdmFtIGRpYWdub3N0aWNrw6kgZ3JhZnkgcmVncmVzbsOpaG8gbW9kZWx1LiBQcm9zdHJlZG7DrWN0dm9tICoqUeKAk1EgZ3JhZnUqKiBwb3N1ZHp1amVtIHByZWRwb2tsYWQgbm9ybWFsaXR5IHJlesOtZHXDrSwgemF0aWHEviDEjW8gb3N0YXRuw6kgZGlhZ25vc3RpY2vDqSBncmFmeSBtaSB1bW/FvsWIdWrDuiBpZGVudGlmaWtvdmHFpSBwcsOtcGFkbsOpIHByb2Jsw6lteSBzIGhldGVyb3NrZWRhc3RpY2l0b3UsIG5lbGluZWFyaXRvdSBhbGVibyBwcsOtdG9tbm9zxaVvdSB2cGx5dm7DvWNoIHBvem9yb3ZhbsOtLiBOYSB6w6FrbGFkZSB0w71jaHRvIGdyYWZvdiBzaSB2aWVtIHZ5dHZvcmnFpSBwcnZvdG7DvSBkb2plbSBvIHZob2Rub3N0aSB6dm9sZW7DqWhvIG1vZGVsdSBhIG8gdG9tLCDEjWkgamUgbW/Fvm7DqSBqZWhvIHbDvXNsZWRreSBwb3Zhxb5vdmHFpSB6YSBzcG/EvmFobGl2w6kuCgoKCgoKCmBgYHtyIGRpYWdwbG90cywgZmlnLmNhcD0iRGlhZ25vc3RpY2vDqSBncmFmeSByZWdyZXNuw6lobyBtb2RlbHUiLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD04fQpwYXIobWZyb3cgPSBjKDIsIDIpKQpwYXIobWFyID0gYyg0LCA0LCAyLCAxKSkKCgojIFZ5a3Jlc2xpxaUgdsWhZXRreSA0IGRpYWdub3N0aWNrw6kgZ3JhZnkgbW9kZWx1CnBsb3QobW9kZWwpCgojIFJlc2V0b3ZhxaUgbGF5b3V0CnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAoKIyMgUmVzaWR1YWxzIHZzLiBGaXR0ZWQKCiMjIyBJbnRlcnByZXTDoWNpYSBrb25rcsOpdG5laG8gZ3JhZnUKCioqQ2VudHJvdmFuaWUgb2tvbG8gbnVseSoqICAKUmV6w61kdcOhIGtvbMOtxaF1IHByaWJsacW+bmUgb2tvbG8gaG9kbm90eSAwLCDEjW8gamUgxb5pYWR1Y2kgc3Rhdi4gTmF6bmHEjXVqZSB0bywgxb5lIG1vZGVsIG5lbcOhIHN5c3RlbWF0aWNrw7ogdGVuZGVuY2l1IG5hZGhvZG5vY292YcWlIGFsZWJvIHBvZGhvZG5vY292YcWlIHBvxI1ldCB6cmFuZW7DvWNoIHByaSBkb3ByYXZuw71jaCBuZWhvZMOhY2guCgoqKlR2YXIgdnrFpWFodSoqICAKxIxlcnZlbsOhIHZ5aGxhZHpvdmFjaWEgxI1pYXJhIChMT0VTUykgdnlrYXp1amUgbWllcm5lIHpha3JpdmVuaWUsIMSNbyBtw7TFvmUgbmF6bmHEjW92YcWlIHNsYWLDuiBuZWxpbmVhcml0dSBtZWR6aSB2eXN2ZXTEvnVqw7pjaW1pIHByZW1lbm7DvW1pIChuYWptw6QgxI1hc292w71taSBjaGFyYWt0ZXJpc3Rpa2FtaSBuZWhvZHkpIGEgcG/EjXRvbSB6cmFuZW7DvWNoLiBUZW50byBlZmVrdCB2xaFhayBuaWUgamUgdsO9cmF6bsO9IGEgbmVwcmVkc3RhdnVqZSB6w6FzYWRuw70gcHJvYmzDqW0gcHJlIGludGVycHJldMOhY2l1IG1vZGVsdS4KCioqUm96cHR5bCByZXrDrWR1w60qKiAgClZlcnRpa8OhbG55IHJvenB0eWwgcmV6w61kdcOtIHNhIGphdsOtIGFrbyBwcmlibGnFvm5lIGtvbsWhdGFudG7DvSB2IGNlbG9tIHJvenNhaHUgdnlyb3ZuYW7DvWNoIGhvZG7DtHQsIMSNbyBuYXpuYcSNdWplIHNwbG5lbmllIHByZWRwb2tsYWR1IGhvbW9za2VkYXN0aWNpdHkuCgoqKk9kxL5haGzDqSBwb3pvcm92YW5pYSoqICAKTmlla2/EvmtvIGJvZG92IHNhIG5hY2jDoWR6YSDEj2FsZWogb2Qgb3N0YXRuw71jaCwgxI1vIG3DtMW+ZSBwcmVkc3Rhdm92YcWlIG5laG9keSBzIG1pbW9yaWFkbmUgdnlzb2vDvW0gYWxlYm8gbsOtemt5bSBwb8SNdG9tIHpyYW5lbsO9Y2guIFRpZXRvIHBvem9yb3ZhbmlhIGplIG1vxb5uw6kgxI9hbGVqIHByZXNrw7ptYcWlIHBvbW9jb3UgdGVzdHUgYG91dGxpZXJUZXN0KG1vZGVsKWAgeiBiYWzDrWthICpjYXIqLgoKCgojIyBR4oCTUSBQbG90CgojIyMgxIxvIGdyYWYgem7DoXpvcsWIdWplCgotIE9zIFggcHJlZHN0YXZ1amUgdGVvcmV0aWNrw6kga3ZhbnRpbHkgbm9ybcOhbG5laG8gcm96ZGVsZW5pYS4KLSBPcyBZIHpvYnJhenVqZSDFoXRhbmRhcmRpem92YW7DqSByZXrDrWR1w6EgbW9kZWx1LgotIFByZXJ1xaFvdmFuw6EgZGlhZ29uw6FsYSBwcmVkc3RhdnVqZSBpZGXDoWxueSBwcsOtcGFkLCB2IGt0b3JvbSBieSByZXrDrWR1w6EgbWFsaSBub3Jtw6FsbmUgcm96ZGVsZW5pZS4KCiMjIyBJbnRlcnByZXTDoWNpYSBrb25rcsOpdG5laG8gZ3JhZnUKCioqQ2Vsa292w70gdHZhciByb3pkZWxlbmlhKiogIApWw6TEjcWhaW5hIGJvZG92IHNhIG5hY2jDoWR6YSBibMOtemtvIHJlZmVyZW7EjW5laiBwcmlhbWt5LCDEjW8gbmF6bmHEjXVqZSwgxb5lIHJlesOtZHXDoSBzw7ogcHJpYmxpxb5uZSBub3Jtw6FsbmUgcm96bG/FvmVuw6kuCgoqKktyYWpuw6kgaG9kbm90eSoqICAKTmEgb2JvY2gga29uY29jaCBncmFmdSBkb2Now6FkemEgayBtaWVybnltIG9kY2jDvWxrYW0gb2QgcHJpYW1reSwgxI1vIG3DtMW+ZSBzaWduYWxpem92YcWlIHByw610b21ub3PFpSBleHRyw6ltbnljaCBob2Ruw7R0IOKAkyBuYXByw61rbGFkIG5laMO0ZCBzIG5lxaF0YW5kYXJkbsO9bSBwb8SNdG9tIHpyYW5lbsO9Y2guCgoqKlN0cmVkbsOhIMSNYXPFpSByb3pkZWxlbmlhKiogIApWIGNlbnRyw6FsbmVqIG9ibGFzdGkgZ3JhZnUgKG9rb2xvIG1lZGnDoW51KSByZXrDrWR1w6EgdmXEvm1pIGRvYnJlIGtvcMOtcnVqw7ogdGVvcmV0aWNrw7ogcHJpYW1rdSwgxI1vIHpuYW1lbsOhLCDFvmUgdsOkxI3FoWluYSBwb3pvcm92YW7DrSBzcMS6xYhhIHByZWRwb2tsYWQgbm9ybWFsaXR5LgoKTmEgesOha2xhZGUgUeKAk1EgZ3JhZnUgbW/Fvm5vIGtvbsWhdGF0b3ZhxaUsIMW+ZSBwcmVkcG9rbGFkIG5vcm1hbGl0eSByZXrDrWR1w60gamUgdiBwcmlqYXRlxL5uZWogbWllcmUgc3BsbmVuw70sIGFqIGtlxI8gcyBtaWVybnltaSBvZGNow71sa2FtaSB2IGV4dHLDqW1vY2guCgoKIyMgU2NhbGXigJNMb2NhdGlvbiBQbG90CgojIyMgxIxvIGdyYWYgem7DoXpvcsWIdWplCgotIE9zIFggcHJlZHN0YXZ1amUgdnlyb3ZuYW7DqSBob2Rub3R5IHrDoXZpc2xlaiBwcmVtZW5uZWogKHByZWRpa292YW7DvSBwb8SNZXQgenJhbmVuw71jaCkuCi0gT3MgWSB6b2JyYXp1amUgZHJ1aMO6IG9kbW9jbmludSBhYnNvbMO6dG55Y2ggxaF0YW5kYXJkaXpvdmFuw71jaCByZXrDrWR1w60uCi0gxIxlcnZlbsOhIMSNaWFyYSBwcmVkc3RhdnVqZSB2eWhsYWRlbsO9IHRyZW5kIChMT0VTUykuCgojIyMgSW50ZXJwcmV0w6FjaWEga29ua3LDqXRuZWhvIGdyYWZ1CgoqKkhvbW9za2VkYXN0aWNpdGEqKiAgCkJvZHkgc8O6IHJvdm5vbWVybmUgcm96cHTDvWxlbsOpIHBvemTEusW+IG9zaSBYIGEgbmV2eXR2w6FyYWrDuiBsaWV2aWtvdml0w70gdHZhci4gVG8gbmF6bmHEjXVqZSwgxb5lIHZhcmlhbmNpYSByZXrDrWR1w60gamUgcHJpYmxpxb5uZSBrb27FoXRhbnRuw6EuCgoqKlRyZW5kIHZ5aGxhZHpvdmFjZWoga3Jpdmt5KiogIArEjGVydmVuw6EgTE9FU1Mga3JpdmthIGplIHRha21lciBob3Jpem9udMOhbG5hLCDEjW8gcG9kcG9ydWplIHByZWRwb2tsYWQsIMW+ZSByb3pwdHlsIHJlesOtZHXDrSBzYSBuZW1lbsOtIHMgcmFzdMO6Y2ltaSB2eXJvdm5hbsO9bWkgaG9kbm90YW1pLgoKKipPZMS+YWhsw6kgaG9kbm90eSoqICAKTmlla2/EvmtvIGJvZG92IHNhIG5hY2jDoWR6YSBtaWVybmUgdnnFocWhaWUsIGF2xaFhayBuZWpkZSBvIGV4dHLDqW1uZSBwb3pvcm92YW5pYSwga3RvcsOpIGJ5IHbDvXJhem5lIG5hcnXFoW92YWxpIHN0YWJpbGl0dSBtb2RlbHUuCgoKIyMgUmVzaWR1YWxzIHZzLiBMZXZlcmFnZQoKIyMjIMSMbyBncmFmIHpuw6F6b3LFiHVqZQoKLSBPcyBYIHByZWRzdGF2dWplIHDDoWtvdsO9IGVmZWt0IHBvem9yb3ZhbsOtLCBrdG9yw70gdnlqYWRydWplLCBha28gdmXEvm1pIHNhIGRhbsOpIHBvem9yb3ZhbmllIGzDrcWhaSBvZCBvc3RhdG7DvWNoIHogaMS+YWRpc2thIHZ5c3ZldMS+dWrDumNpY2ggcHJlbWVubsO9Y2guCi0gT3MgWSB6b2JyYXp1amUgxaF0YW5kYXJkaXpvdmFuw6kgcmV6w61kdcOhLgotIEJvZGtvdmFuw6kga3Jpdmt5IHpuw6F6b3LFiHVqw7oga29udMO6cnkgQ29va292ZWogdnpkaWFsZW5vc3RpLCBrdG9yw6kgaWRlbnRpZmlrdWrDuiBwb3RlbmNpw6FsbmUgdnBseXZuw6kgcG96b3JvdmFuaWEuCgojIyMgSW50ZXJwcmV0w6FjaWEga29ua3LDqXRuZWhvIGdyYWZ1CgoqKlJvemxvxb5lbmllIHZwbHl2dSoqICAKVsOkxI3FoWluYSBwb3pvcm92YW7DrSBtw6EgbsOtemt5IHDDoWtvdsO9IGVmZWt0LCDEjW8gamUgdHlwaWNrw6kgcHJlIGRvYnJlIMWhdHJ1a3TDunJvdmFuw6kgZMOhdGEgbyBkb3ByYXZuw71jaCBuZWhvZMOhY2guCgoqKlZlxL5rb3PFpSByZXrDrWR1w60qKiAgCsWgdGFuZGFyZGl6b3ZhbsOpIHJlesOtZHXDoSBzYSBwcmV2YcW+bmUgcG9oeWJ1asO6IHYgaW50ZXJ2YWxlIOKfqOKIkjIsIDLin6ksIMSNbyBuYXpuYcSNdWplIGFic2VuY2l1IGV4dHLDqW1ueWNoIGNow71iIG1vZGVsdS4KCioqVnBseXZuw6kgcG96b3JvdmFuaWEqKiAgCk5pZWt0b3LDqSBwb3pvcm92YW5pYSBzYSBuYWNow6FkemFqw7ogYmxpxb7FoWllIGt1IGtvbnTDunJhbSBDb29rb3ZlaiB2emRpYWxlbm9zdGksIGF2xaFhayDFvmlhZG5lIHogbmljaCBuZXByZWtyYcSNdWplIGtyaXRpY2vDqSBocmFuaWNlLiBaIHRvaG8gdnlwbMO9dmEsIMW+ZSDFvmlhZG5hIG5laG9kYSBuZW92cGx5dsWIdWplIHJlZ3Jlc27DqSBrb2VmaWNpZW50eSBuZXByaW1lcmFuZS4KCgpgYGB7cn0KCiMgVGVzdCBub3JtYWxpdHkgcmV6w61kdcOtCnJlc2lkdWFscyA8LSByZXNpZHVhbHMobW9kZWwpCmpiX3Rlc3QgPC0gamFycXVlLmJlcmEudGVzdChyZXNpZHVhbHMpCmpiX3Rlc3QKCiMgVGVzdCBvZMS+YWhsw71jaCBwb3pvcm92YW7DrSAoQm9uZmVycm9uaSkKb3V0bGllcl90ZXN0IDwtIG91dGxpZXJUZXN0KG1vZGVsKQpvdXRsaWVyX3Rlc3QKCmBgYApOYSBvdmVyZW5pZSBwcmVkcG9rbGFkdSBub3JtYWxpdHkgcmV6w61kdcOtIHNvbSBwb3XFvmlsYSBKYXJxdWXigJNCZXJhIHRlc3QuIE51bG92w6EgaHlwb3TDqXphIHRlc3R1IHByZWRwb2tsYWTDoSwgxb5lIHJlesOtZHXDoSBtYWrDuiBub3Jtw6FsbmUgcm96ZGVsZW5pZS4gVsO9c2xlZGt5IHRlc3R1IG5hem5hxI11asO6LCDFvmUgcmV6w61kdcOhIHNhIG3DtMW+dSBvZGNoecS+b3ZhxaUgb2Qgbm9ybcOhbG5laG8gcm96ZGVsZW5pYSwgxI1vIGplIHByaSBkw6F0YWNoIG8gZG9wcmF2bsO9Y2ggbmVob2TDoWNoIHBvbWVybmUgxI1hc3TDqSwga2XEj8W+ZSBwb8SNZXQgenJhbmVuw71jaCBtw7TFvmUgbmFkb2LDumRhxaUgZXh0csOpbW5lIGhvZG5vdHkgcHJpIHrDoXZhxb5uw71jaCBuZWhvZMOhY2guCgpaw6Fyb3ZlxYggc29tIHBvbW9jb3UgZnVua2NpZSBvdXRsaWVyVGVzdCgpIGlkZW50aWZpa292YWxhIHBvdGVuY2nDoWxuZSBvZMS+YWhsw6kgYSB2cGx5dm7DqSBwb3pvcm92YW5pYS4gVsO9c2xlZGt5IHRlc3R1IHBvdWthenVqw7ogbmEgZXhpc3RlbmNpdSBuaWVrb8S+a8O9Y2ggcG96b3JvdmFuw60sIGt0b3LDqSBtw7TFvnUgbWHFpSBuZXByaW1lcmFuZSB2ZcS+a8O9IHZwbHl2IG5hIG9kaGFkIHJlZ3Jlc27DvWNoIGtvZWZpY2llbnRvdi4gSWRlIG5ham3DpCBvIG5laG9keSBzIG1pbW9yaWFkbmUgdnlzb2vDvW0gcG/EjXRvbSB6cmFuZW7DvWNoLCBrdG9yw6kgbcO0xb51IG5hcsO6xaFhxaUgc3BsbmVuaWUgcHJlZHBva2xhZG92IGxpbmXDoXJuZWogcmVncmVzaWUuCgpOYSB6w6FrbGFkZSB2w71zbGVka292IHTDvWNodG8gdGVzdG92IHNhIHJvemhvZG5lbSB1cHJhdmnFpSBww7R2b2Ruw70gbW9kZWwgdHJhbnNmb3Jtw6FjaW91IHZ5c3ZldMS+b3ZhbmVqIHByZW1lbm5laiAqaW5qdXJpZXNfdG90YWwqLCBhYnkgc29tIHpuw63FvmlsYSB2cGx5diBleHRyw6ltbnljaCBob2Ruw7R0IGEgemxlcMWhaWxhIHZsYXN0bm9zdGkgbW9kZWx1LgoKCmBgYHtyfQoKdWRhamUuc3ViJGxvZ19pbmp1cmllcyA8LSBsb2codWRhamUuc3ViJGluanVyaWVzX3RvdGFsICsgMSkKbW9kZWwyIDwtIGxtKAogIGxvZ19pbmp1cmllcyB+IG51bV91bml0cyArIGNyYXNoX2hvdXIgKyBjcmFzaF9kYXlfb2Zfd2VlayArIGNyYXNoX21vbnRoLAogIGRhdGEgPSB1ZGFqZS5zdWIKKQpzdW1tYXJ5KG1vZGVsMikKYGBgCgoKCmBgYHtyIGRpYWdwbG90czIsIGZpZy5jYXA9IkRpYWdub3N0aWNrw6kgZ3JhZnkgcmVncmVzbsOpaG8gbW9kZWx1In0KIyBOYXN0YXZpxaUgcm96bG/FvmVuaWUgMiB4IDIKcGFyKG1mcm93ID0gYygyLCAyKSkKcGFyKG1hciA9IGMoNCwgNCwgMiwgMSkpICAjIFpNRU7FoMONIE9LUkFKRQoKIyBWeWtyZXNsacWlIHbFoWV0a3kgNCBkaWFnbm9zdGlja8OpIGdyYWZ5IG1vZGVsdQpwbG90KG1vZGVsMikKCiMgKFZvbGl0ZcS+bsOpKSBwcmlkYcWlIHNwb2xvxI1uw70gbmFkcGlzCiNtdGV4dCgiRGlhZ25vc3RpY2vDqSBncmFmeSByZWdyZXNuw6lobyBtb2RlbHUiLCBvdXRlciA9IFRSVUUsIGNleCA9IDEuMiwgZm9udCA9IDIpCgojIFJlc2V0b3ZhxaUgbGF5b3V0CnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAoKCgoKYGBge3J9CiMgVGVzdCBub3JtYWxpdHkgcmV6w61kdcOtIChtb2RlbDIpCnJlc2lkdWFscyA8LSByZXNpZHVhbHMobW9kZWwyKQpqYl90ZXN0IDwtIGphcnF1ZS5iZXJhLnRlc3QocmVzaWR1YWxzKQpqYl90ZXN0CgojIFRlc3Qgb2TEvmFobMO9Y2ggcG96b3JvdmFuw60gKEJvbmZlcnJvbmkga29yZWtjaWEpCm91dGxpZXJfdGVzdCA8LSBvdXRsaWVyVGVzdChtb2RlbDIpCm91dGxpZXJfdGVzdApgYGAKCiMjIFrDoXZlciBvIGFuYWzDvXplIG9kxL5haGzDvWNoIGhvZG7DtHQKCk5hIHrDoWtsYWRlIHZ5a29uYW5laiBhbmFsw716eSBtw7TFvmVtIGtvbsWhdGF0b3ZhxaUsIMW+ZSB2eWJyYW7DqSB2eXN2ZXTEvnVqw7pjZSBwcmVtZW5uw6kgbWFqw7ogxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70gdnBseXYgbmEgdnlzdmV0xL5vdmFuw7ogcHJlbWVubsO6IHPDunZpc2lhY3UgcyBkb3ByYXZuw71taSBuZWhvZGFtaS4gTmlla3RvcsOpIHByZW1lbm7DqSBzYSB2IHDDtHZvZG5vbSBtb2RlbGkgdWvDoXphbGkgYWtvIG1lbmVqIHZob2Ruw6kgYWxlYm8gxaVhxb5rbyBpbnRlcnByZXRvdmF0ZcS+bsOpLCBhIHByZXRvIGJvbCBtb2RlbCB2IMSPYWzFoW9tIGtyb2t1IHVwcmF2ZW7DvS4KClRlc3R5IG5vcm1hbGl0eSBhIGRpYWdub3N0aWNrw6kgZ3JhZnkgbmF6bmHEjWlsaSBwcsOtdG9tbm9zxaUgb2TEvmFobMO9Y2gKcG96b3JvdmFuw60sIGt0b3LDqSBzw7ogdHlwaWNrw6kgcHJlIGTDoXRhIHogb2JsYXN0aSBkb3ByYXZ5LCBrZGUgc2Egdnlza3l0dWrDuiBleHRyw6ltbmUgc2l0dcOhY2llIChuYXByLiBuZWhvZHkgcyB2eXNva8O9bSBwb8SNdG9tIHpyYW5lbsO9Y2gpLiBaIHRvaHRvIGTDtHZvZHUgYm9sYSBwb3XFvml0w6EgbG9nYXJpdG1pY2vDoSB0cmFuc2Zvcm3DoWNpYSB2eXN2ZXTEvm92YW5laiBwcmVtZW5uZSxrdG9yw6EgcHJpc3BlbGEgayB6bWllcm5lbml1IHZwbHl2dSBleHRyw6ltbnljaCBob2Ruw7R0LgoKViB1cHJhdmVub20gbW9kZWxpIHNhIG5lcHJldWvDoXphbGkgdsO9cmF6bsOpIHZwbHl2bsOpIHBvem9yb3ZhbmlhIGFuaQp6w6F2YcW+bsOpIG5lbGluZWFyaXR5LiBOYSB6w6FrbGFkZSB0b2hvIG1vxb5ubyB2w71zbGVka3kgcmVncmVzbmVqIGFuYWzDvXp5IHBvdmHFvm92YcWlIHphIHByaW1lcmFuw6kgYSBtb2RlbCB6YSB2aG9kbsO9IG5hIMSPYWzFoWl1IGludGVycHJldMOhY2l1LgoKIyMgSGV0ZXJvc2tlZGFzdGljaXRhCgoKUHLDrXRvbW5vc8WlIGhldGVyb3NrZWRhc3RpY2l0eSAoKm5la29uxaF0YW50bsOpaG8gcm96cHR5bHUgbsOhaG9kbmVqIHpsb8W+a3kqKQptw7TFvmUgdmllc8WlIGsgbmVzcHLDoXZuZW11IHZ5aG9kbm9jb3Zhbml1ICp0LXRlc3RvdiB2w716bmFtbm9zdGkqCmplZG5vdGxpdsO9Y2ggcmVncmVzbsO9Y2gga29lZmljaWVudG92LiBaIHRvaHRvIGTDtHZvZHUgamUgbmV2eWhudXRuw6kKaGV0ZXJvc2tlZGFzdGljaXR1ICAKLSAqZGV0ZWtvdmHFpSogKHZpenXDoWxuZSBhaiBwb21vY291IMWhdGF0aXN0aWNrw71jaCB0ZXN0b3YpLCAgCi0gYSB2IHByw61wYWRlIGplaiBwcsOtdG9tbm9zdGkganUgKnZob2Ruw71tIHNww7Rzb2JvbSBlbGltaW5vdmHFpSouCgpWIHByw61wYWRlIGRhdGFiw6F6eSBkb3ByYXZuw71jaCBuZWjDtGQgamUgbW/Fvm7DqSBoZXRlcm9za2VkYXN0aWNpdHUKb8SNYWvDoXZhxaUsIGtlxI/FvmUgcG/EjWV0IG5laMO0ZCBhIGljaCBuw6FzbGVka3kgc2EgbcO0xb51IHbDvXJhem5lIGzDrcWhacWlCnYgesOhdmlzbG9zdGkgb2QgxI1hc3UsIGTFiGEgYWxlYm8gaW7DvWNoIGNoYXJha3RlcmlzdMOtayBwcmVtw6F2a3kuCkFqIHByZXRvIHNvbSBzYSB6YW1lcmFsYSBuYSBqZWogcG9zw7pkZW5pZSBwcm9zdHJlZG7DrWN0dm9tCmRpYWdub3N0aWNrw71jaCBncmFmb3YuCgpOYSB0ZW50byDDusSNZWwgYnVkZW0gcG9yb3Zuw6F2YcWlIGR2YSByZWdyZXNuw6kgbW9kZWx5IOKAkyBww7R2b2Ruw70gbW9kZWwKb3puYcSNZW7DvSBha28gKm1vZGVsKiBhIHVwcmF2ZW7DvSBtb2RlbCAqbW9kZWwyKiwgdiBrdG9yb20gYm9sYQpwb3XFvml0w6EgbG9nYXJpdG1pY2vDoSB0cmFuc2Zvcm3DoWNpYSB2eXN2ZXTEvm92YW5laiBwcmVtZW5uZWouCkNpZcS+b20gdGVqdG8gw7pwcmF2eSBib2xvIHpuw63FvmVuaWUgdnBseXZ1IGV4dHLDqW1ueWNoIGhvZG7DtHQgYQpzdGFiaWxpesOhY2lhIHJvenB0eWx1IHJlesOtZHXDrS4KCgoKYGBge3IgaGV0ZXJvcGxvdHMxLCBmaWcuY2FwPSJTa8O6bWFuaWUgaGV0ZXJvc2tlZGFzdGljaXR5IiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTR9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspCgpkZl9yZXMgPC0gbW9kZWwuZnJhbWUobW9kZWwyKQpkZl9yZXMkcmVzMiA8LSByZXNpZChtb2RlbDIpXjIKCnNldC5zZWVkKDEyMykKZGZfcGxvdCA8LSBkZl9yZXNbc2FtcGxlKG5yb3coZGZfcmVzKSwgbWluKDMwMDAsIG5yb3coZGZfcmVzKSkpLCBdCgpwMSA8LSBnZ3Bsb3QoZGZfcGxvdCwgYWVzKHggPSBudW1fdW5pdHMsIHkgPSByZXMyKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFKSArCiAgbGFicygKICAgIHggPSAiUG/EjWV0IHrDusSNYXN0bmVuw71jaCB2b3ppZGllbCIsCiAgICB5ID0gIsWgdHZvcmNlIHJlesOtZHXDrSIsCiAgICB0aXRsZSA9ICLFoHR2b3JjZSByZXrDrWR1w60gdnMuIHBvxI1ldCB2b3ppZGllbCIKICApICsKICB0aGVtZV9taW5pbWFsKCkKCnAyIDwtIGdncGxvdChkZl9wbG90LCBhZXMoeCA9IGNyYXNoX2hvdXIsIHkgPSByZXMyKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFKSArCiAgbGFicygKICAgIHggPSAiSG9kaW5hIG5laG9keSIsCiAgICB5ID0gIsWgdHZvcmNlIHJlesOtZHXDrSIsCiAgICB0aXRsZSA9ICLFoHR2b3JjZSByZXrDrWR1w60gdnMuIGhvZGluYSBuZWhvZHkiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpCgpwcmludChwMSArIHAyKQoKCmBgYAphIHRlcmF6IG1vZGVsIHNvIHpsb2dhcml0bWl6b3Zhbm91IHByZW1lbm5vdSAqbnVtX3VuaXRzKi4KCmBgYHtyIGhldGVyb3Bsb3RzMiwgZmlnLmNhcD0iU2vDum1hbmllIGhldGVyb3NrZWRhc3RpY2l0eSIsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD00fQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGF0Y2h3b3JrKQoKZGZfcmVzIDwtIG1vZGVsLmZyYW1lKG1vZGVsMikKZGZfcmVzJHJlczIgPC0gcmVzaWQobW9kZWwyKV4yCgpkZl9yZXMgPC0gZGZfcmVzWwogIGlzLmZpbml0ZShkZl9yZXMkcmVzMikgJgogICAgIWlzLm5hKGRmX3JlcyRudW1fdW5pdHMpICYKICAgICFpcy5uYShkZl9yZXMkY3Jhc2hfaG91ciksCl0KCnNldC5zZWVkKDEyMykKZGZfcGxvdCA8LSBkZl9yZXNbc2FtcGxlKG5yb3coZGZfcmVzKSwgbWluKDMwMDAsIG5yb3coZGZfcmVzKSkpLCBdCgpwMSA8LSBnZ3Bsb3QoZGZfcGxvdCwgYWVzKHggPSBsb2cobnVtX3VuaXRzICsgMSksIHkgPSByZXMyKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFKSArCiAgbGFicyh4ID0gImxvZyhudW1fdW5pdHMgKyAxKSIsCiAgICAgICB5ID0gIlNxdWFyZWQgUmVzaWR1YWxzIiwKICAgICAgIHRpdGxlID0gIlJlc2lkdWFscyB2cyBsb2cobnVtX3VuaXRzICsgMSkiKSArCiAgdGhlbWVfbWluaW1hbCgpCgpwMiA8LSBnZ3Bsb3QoZGZfcGxvdCwgYWVzKHggPSBjcmFzaF9ob3VyLCB5ID0gcmVzMikpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC42KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSkgKwogIGxhYnMoeCA9ICJjcmFzaF9ob3VyIiwKICAgICAgIHkgPSAiU3F1YXJlZCBSZXNpZHVhbHMiLAogICAgICAgdGl0bGUgPSAiUmVzaWR1YWxzIHZzIGNyYXNoX2hvdXIiKSArCiAgdGhlbWVfbWluaW1hbCgpCgpwMSArIHAyCgoKYGBgCgpOYSB0b210byBvYnLDoXprdSBwb2TEvmEgdnlobGFkZW7DvWNoIGhvZG7DtHQgxaF0dm9yY292IHJlesOtZHXDrSAodnlobGFkZW7DoSBrcml2a2EgdiBncmFmZSkgbcO0xb5lbSBrb27FoXRhdG92YcWlLCDFvmUgbmV2aWTDrW0gdsO9cmF6bsO9IHJhc3QgYW5pIHBva2xlcyByb3pwdHlsdSByZXrDrWR1w60gdiB6w6F2aXNsb3N0aSBvZCB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoLiAKClYgZ3JhZmUgKlJlc2lkdWFscyB2cyBsb2cobnVtX3VuaXRzICsgMSkqIGplIHbDpMSNxaFpbmEgYm9kb3Ygc8O6c3RyZWRlbsOhIHByaSBuacW+xaHDrWNoIGhvZG5vdMOhY2ggcG/EjXR1IHrDusSNYXN0bmVuw71jaCB2b3ppZGllbCBhIHZ5aGxhZGVuw6Ega3JpdmthIG5ldnlrYXp1amUgamFzbsO9IHRyZW5kLCBrdG9yw70gYnkgbmF6bmHEjW92YWwgc3lzdGVtYXRpY2vDqSB6dnnFoW92YW5pZSB2YXJpYWJpbGl0eS4KClYgZ3JhZmUgKlJlc2lkdWFscyB2cyBjcmFzaF9ob3VyKiBzYSB0YWtpc3RvIG5ldWthenVqZSBqZWRub3puYcSNbsO9IHbDvXZvaiByb3pwdHlsdSByZXrDrWR1w60gdiBwcmllYmVodSBkxYhhIOKAkyB2eWhsYWRlbsOhIGtyaXZrYSBqZSBsZW4gbWllcm5lIHJhc3TDumNhLCDEjW8gbcO0xb5lIG5hem5hxI1vdmHFpSBzbGFiw70gZWZla3QsIGFsZSBuaWUgdsO9cmF6bsO6IGhldGVyb3NrZWRhc3RpY2l0dS4KClByZXRvIG5hIHrDoWtsYWRlIHZpenXDoWxuZWhvIHBvc8O6ZGVuaWEgbmV2aWTDrW0gc2lsbsO9IGTDtGtheiBoZXRlcm9za2VkYXN0aWNpdHkuIFRlbnRvIHrDoXZlciB2xaFhayBuw6FzbGVkbmUgb3ZlcsOtbSBmb3Jtw6FsbnltIHRlc3RvbSAobmFwci4gQnJldXNjaOKAk1BhZ2FuIHRlc3RvbSkuCgojIyBUZXN0b3ZhbmllIHByw610b21ub3N0aSBoZXRlcm9za2VkYXN0aWNpdHkKCmBgYHtyfQojIEluc3RhbGwgKGlmIG5vdCB5ZXQgaW5zdGFsbGVkKQojIGluc3RhbGwucGFja2FnZXMoImxtdGVzdCIpCgojIExvYWQgdGhlIHBhY2thZ2UKbGlicmFyeShsbXRlc3QpCgojIFJ1biB0aGUgQnJldXNjaOKAk1BhZ2FuIHRlc3QKYnB0ZXN0KG1vZGVsKQoKYGBgCmBgYHtyfQojIEluc3RhbGwgKGlmIG5vdCB5ZXQgaW5zdGFsbGVkKQojIGluc3RhbGwucGFja2FnZXMoImxtdGVzdCIpCgojIExvYWQgdGhlIHBhY2thZ2UKbGlicmFyeShsbXRlc3QpCgojIFJ1biB0aGUgQnJldXNjaOKAk1BhZ2FuIHRlc3QKYnB0ZXN0KG1vZGVsMikKCmBgYApOYSB6w6FrbGFkZSBCcmV1c2No4oCTUGFnYW5vdmhvIHRlc3R1IG3DtMW+ZW1lIGtvbsWhdGF0b3ZhxaUsIMW+ZSAqKmhldGVyb3NrZWRhc3RpY2l0YSByZXrDrWR1w60gamUgcHLDrXRvbW7DoSB2IHDDtHZvZG5vbSBtb2RlbGkgKCptb2RlbCopIGFqIHYgdXByYXZlbm9tIG1vZGVsaSAoKm1vZGVsMiopKiosIGtlxI/FvmUgdiBvYm9jaCBwcsOtcGFkb2NoIGJvbGEgbnVsb3bDoSBoeXBvdMOpemEgbyBrb27FoXRhbnRub20gcm96cHR5bGUgemFtaWV0bnV0w6EgKHAtaG9kbm90YSA8IDAsMDUpLgoKTG9nYXJpdG1pY2vDoSB0cmFuc2Zvcm3DoWNpYSB2eXN2ZXTEvm92YW5laiBwcmVtZW5uZWogc8OtY2UgemxlcMWhaWxhIHR2YXIgcmV6w61kdcOtIGEgaWNoIHZpenXDoWxuZSBzcHLDoXZhbmllLCBhdsWhYWsgKipoZXRlcm9za2VkYXN0aWNpdHUgc2EgdMO9bSBuZXBvZGFyaWxvIMO6cGxuZSBvZHN0csOhbmnFpSoqLiBWIMSPYWzFoWVqIGFuYWzDvXplIGplIHByZXRvIHZob2Ruw6kgcHJhY292YcWlIHMgcm9idXN0bsO9bWkgKGhldGVyb3NrZWRhc3RpY2l0eS1jb25zaXN0ZW50KSBvZGhhZG1pIHJvenB0eWxvdiByZWdyZXNuw71jaCBrb2VmaWNpZW50b3YsIGFieSBib2xpIHbDvXNsZWRreSB0ZXN0b3YgxaF0YXRpc3RpY2tlaiB2w716bmFtbm9zdGkgc3BvxL5haGxpdsOpLgoKYGBge3J9CiNpbnN0YWxsLnBhY2thZ2VzKCJzYW5kd2ljaCIpCiNpbnN0YWxsLnBhY2thZ2VzKCJsbXRlc3QiKQpsaWJyYXJ5KHNhbmR3aWNoKQpsaWJyYXJ5KGxtdGVzdCkKY29lZnRlc3QobW9kZWwsIHZjb3YgPSB2Y292SEMobW9kZWwpKQoKCmBgYAoKClbFoWltbmltZSBzaSwgxb5lIHBvIHBvdcW+aXTDrSBoZXRlcm9za2VkYXN0aWNpdHktcm9idXN0bsO9Y2ggKFdoaXRlKSBvZGhhZG92IHJvenB0eWxvdiB6b3N0w6F2YWrDuiAqKnbFoWV0a3kgdnlzdmV0xL51asO6Y2UgcHJlbWVubsOpIMWhdGF0aXN0aWNreSB2w716bmFtbsOpKiouIFRvIHpuYW1lbsOhLCDFvmUgYWogcG8ga29yZWtjaWkgbmEgaGV0ZXJvc2tlZGFzdGljaXR1IHPDuiB2esWlYWh5IHphY2h5dGVuw6kgbW9kZWxvbSBzdGFiaWxuw6kgYSB2w71zbGVka3kgdGVzdG92IMWhdGF0aXN0aWNrZWogdsO9em5hbW5vc3RpIG1vxb5ubyBwb3Zhxb5vdmHFpSB6YSBzcG/EvmFobGl2w6kuCgpQb3XFvml0aWUgdGVqdG8gbWV0w7NkeSBqZSB2aG9kbsOpIG5ham3DpCBwcmkgKip2w6TEjcWhb20gcG/EjXRlIHBvem9yb3ZhbsOtKiosIMSNbyBqZSB2IHByw61wYWRlIGRhdGFiw6F6eSBkb3ByYXZuw71jaCBuZWjDtGQgc3BsbmVuw6kuIEFsdGVybmF0w612bnltIHJpZcWhZW7DrW0gaGV0ZXJvc2tlZGFzdGljaXR5IGJ5IGJvbGEgdHJhbnNmb3Jtw6FjaWEgYWxlYm8gxaFrw6Fsb3ZhbmllIG5pZWt0b3LDvWNoIHByZW1lbm7DvWNoIChuYXByLiBwcmVwb8SNZXQgbmEgbWllcnUgbmEgamVkbm90a3UgxI1hc3UgYWxlYm8gdm96aWRsbyksIGF2xaFhayB0YWvDqXRvIMO6cHJhdnkgYnkgbW9obGkgem7DrcW+acWlIGludGVycHJldGHEjW7DuiBwcmVoxL5hZG5vc8WlIG1vZGVsdS4gWiB0b2h0byBkw7R2b2R1IHBvdmHFvnVqZW0gcG91xb5pdGllIHJvYnVzdG7DvWNoIG9kaGFkb3YgemEgcHJpbWVyYW7DqSByaWXFoWVuaWUgdiByw6FtY2kgdGVqdG8gYW5hbMO9enkuCgoKCgo=