library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)
rm(list=ls())
Moja databáza obsahuje záznamy o dopravných nehodách v Barcelone za
rok 2017. Ide o kombináciu premenných týkajúcich sa miesta nehody
(mestská štvrť, ulica), času (deň v týždni, hodina, časť dňa) a
závažnosti nehody (počet zranených, počet obetí, počet zapojených
vozidiel). Cieľom analýzy je pomocou viacnásobnej lineárnej regresie
preskúmať, do akej miery sú počty obetí dopravných nehôd ovplyvnené
vybranými časovými a kontextovými faktormi, konkrétne hodinou nehody
(Hour.1), časťou dňa (Part.of.the.day) a počtom zapojených vozidiel
(Vehicles.involved). Výsledkom je identifikácia premenných, ktoré
štatisticky významne prispievajú k vysvetleniu závažnosti nehôd.
barc_data <- read.csv("barc_data.csv", sep=";", dec=",", header = TRUE)
head(udaje)
udaje <- udaje[-27,]
udaje <- udaje[-2,]
udaje <- barc_data[, c("Victims", "Hour.1", "Part.of.the.day", "Vehicles.involved")]
udaje$Part.of.the.day <- as.factor(udaje$Part.of.the.day)
# Data imputation
# Compute column medians for numeric variables
column_medians <- sapply(udaje[, c("Victims", "Hour.1", "Vehicles.involved")], median, na.rm = TRUE)
# Impute missing values with column medians
udaje_imputed <- udaje
for (col in names(column_medians)) {
udaje_imputed[[col]][is.na(udaje_imputed[[col]])] <- column_medians[col]
}
# Replace original data with imputed version
udaje <- udaje_imputed
# ZAKLADNA REGRESIA
attach(udaje)
model <- lm(Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved, data = udaje)
summary(model)
Call:
lm(formula = Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved,
data = udaje)
Residuals:
Min 1Q Median 3Q Max
-1.6389 -0.5528 -0.2234 0.3994 3.9091
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.56205 0.78521 0.716 0.477
Hour.1 0.01195 0.03267 0.366 0.716
Part.of.the.dayMorning -0.22459 0.35783 -0.628 0.533
Part.of.the.dayNight 0.66066 0.50874 1.299 0.199
Vehicles.involved 0.40421 0.24294 1.664 0.102
Residual standard error: 0.9391 on 55 degrees of freedom
Multiple R-squared: 0.1156, Adjusted R-squared: 0.05129
F-statistic: 1.797 on 4 and 55 DF, p-value: 0.1425
Testovať, či je model v správnej funkčnej forme (t. j. či je lineárna
špecifikácia vhodná, alebo či by ste mali transformovať premenné,
napríklad pomocou logaritmov alebo mocninami), možno vykonať viacerými
spôsobmi.
1. Test RESET (test chyby špecifikácie Ramseyho regresnej rovnice -
Ramsey Reset Test)
Ide o najštandardnejší formálny test nesprávnej špecifikácie funkčnej
formy ale dá sa použiť aj pre prípady, ak sme nešpecifikovali všetky
vysvetľujúce premenné.
Myšlienka: Nech pôvodný model má tvar \[y_t = \beta_0 + \beta_1 x_{t10} + \dots +\beta_k
x_{tk} + u_t\] Ak je váš model správne špecifikovaný, potom
pridaním mocnín vyrovnaných hodnôt (napr. \(\hat y_t^2\), \(\hat{y}_t^3\)) by sa pôvodný model nemal
podstatne zlepšiť, teda budeme testovať pôvodný model uvedený vyššie a
model
\[y_t = \beta_0 + \beta_1 x_{t10} + \dots
+\beta_k x_{tk} + \gamma_2\hat y_t^2 + \gamma_3\hat{y}_t^3 +
u_t\]
Budeme testovať hypotézu
\(H_0:\) model je správne
špecifikovaný (\(\gamma_2 = \gamma_3 =
0\))
oproti
\(H_1:\) model je nesprávne
špecifikovaný (\(\gamma_2 \ne 0 \quad
\text{alebo} \quad \gamma_3 \ne 0\))
# Suppose your model is:
model <- lm(Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved, data = udaje)
# RESET test from 'lmtest' package:
library(lmtest)
resettest(model)
RESET test
data: model
RESET = 0.11629, df1 = 2, df2 = 53, p-value = 0.8904
Na základe výsledkov RESET testu (p-hodnota: 0.8904 > 0.05)
nezamietame nulovú hypotézu o správnej špecifikácii modelu. To
naznačuje, že model pravdepodobne neobsahuje štrukturálnu chybu a
zvolená lineárna forma je vhodná na vysvetlenie počtu obetí dopravných
nehôd.
2. Grafická analýza
Graf Residuals vs. Fitted
Grafická analýza vzťahu medzi vyrovnanými hodnotami náhodnej
premennej a rezíduami:
plot(model, which = 1)

Graf rezíduí voči vyrovnaným hodnotám naznačuje jemné zakrivenie, čo
môže signalizovať, že model nezachytáva všetky vzťahy úplne presne.
Mierna odchýlka od náhodnosti rezíduí môže poukazovať na nelineárny
efekt alebo na chýbajúcu relevantnú premennú.
Grafy C+R **
Táto analýza nám môže pomôcť pri hľadaní odpovede na otázku, ktorú
premennú by sme mali transfomovať pomocou nejakej známej funkcie.
Vychádzajme z pôvodnej rovnice
\[y_t = \beta_0 + \beta_1 x_{t1} + \dots
+\beta_k x_{tk} + u_t\] Túto rovnicu najprv odhadneme a potom
vykresľujeme grafy, kde výraz component+residual (C+R) plot vykresľuje
na zvislej osi \(\hat{\beta}_ix_{ti}+e_t\) a na vodorovnej
osi vykresľuje hodnoty \(x_{ti}\)
Tieto grafy pomáhajú identifikovať nelineárne vzťahy pre každý
regresor:
car::crPlots(model)

Component + Residual grafy ukazujú, že vzťah medzi počtom obetí a
niektorými premennými nemusí byť úplne lineárny. Najväčší odklon od
priamky vidno pri premenných Hour.1 a Vehicles.involved, čo naznačuje,
že by mohlo byť vhodné zvážiť ich kvadratickú alebo inú funkčnú
transformáciu.
3. Nelineárna špecifikácia
Častokrát môžeme aj zložitejšie nelineárne vzťahy modelovať s pomocou
ich aproximácie s polynómom, teda v prípade kvadratických členov
\[y_t = \beta_0 + \beta_1 x_{t10} + \dots
+\beta_k x_{tk} + \dots + \gamma_i\hat x_{ik}^2 + \dots + \gamma_j\hat
x_{jk}^2 + \dots + u_t\] Príklad na túto modifikáciu uvidíme
nižšie.
3. Porovnanie základného a modifikovaného modelu
Predpokladajme, že pri nelineárnych úpravách pôvodného modelu
dopravných nehôd zavedieme kvadratické členy pre premenné Hour.1 a
Vehicles.involved. K tomuto kroku nás motivuje Component + Residual
graf, kde sa vyrovnaná krivka najviac odchyľuje od priamky práve pri
týchto premenných.
Ak má transformovaný model vyšší upravený koefcient determinácie
\(R^2_{adj}\) a pri RESET test prijmeme
alternatívnu hypotézu, odporúčame si výsledky potvrdiť s pomocou Anova
testu oboch modelov a prípadne opakovaného Reset Testu uplatneneného na
nelineárne transformovaný model
model <- lm(Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved)
model_kvadr <- lm(Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved + I(Hour.1^2) + I(Vehicles.involved^2), data = udaje)
summary(model_kvadr)
Call:
lm(formula = Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved +
I(Hour.1^2) + I(Vehicles.involved^2), data = udaje)
Residuals:
Min 1Q Median 3Q Max
-1.5810 -0.4786 -0.1790 0.4468 3.1569
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.991820 1.349285 -1.476 0.1458
Hour.1 0.316196 0.160864 1.966 0.0546 .
Part.of.the.dayMorning -0.493600 0.365117 -1.352 0.1821
Part.of.the.dayNight 1.640067 0.726676 2.257 0.0282 *
Vehicles.involved 1.797412 1.098365 1.636 0.1077
I(Hour.1^2) -0.012282 0.006349 -1.934 0.0584 .
I(Vehicles.involved^2) -0.418467 0.301140 -1.390 0.1705
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.91 on 53 degrees of freedom
Multiple R-squared: 0.1998, Adjusted R-squared: 0.1092
F-statistic: 2.206 on 6 and 53 DF, p-value: 0.05666
anova(model, model_kvadr)
Analysis of Variance Table
Model 1: Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved
Model 2: Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved +
I(Hour.1^2) + I(Vehicles.involved^2)
Res.Df RSS Df Sum of Sq F Pr(>F)
1 55 48.509
2 53 43.889 2 4.6199 2.7894 0.0705 .
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
library(lmtest)
resettest(model_kvadr)
RESET test
data: model_kvadr
RESET = 5.9336, df1 = 2, df2 = 51, p-value = 0.004822
Rozšírený model, ktorý zahŕňa kvadratické členy premenných Hour.1 a
Vehicles.involved, nepreukázal výrazné zlepšenie oproti pôvodnému
lineárnemu modelu. Hoci niektoré koeficienty sa približujú k hranici
štatistickej významnosti, väčšina z nich – vrátane novopridaných
kvadratických členov – ostáva nevýznamná. Upravený koeficient
determinácie (R²adj) sa síce mierne zvýšil, ale stále zostáva nízky, čo
naznačuje, že model len slabo vysvetľuje variabilitu počtu obetí.
Porovnanie modelov pomocou ANOVA testu ukazuje, že rozdiel medzi
základným a rozšíreným modelom nie je štatisticky významný (p ≈ 0.0705),
teda pridanie kvadratických členov neviedlo k výrazne lepšiemu opisu
dát. Naopak, RESET test aplikovaný na rozšírený model ukazuje p-hodnotu
≈ 0.0048, čo naznačuje, že aj tento model môže trpieť špecifikačnou
chybou – napriek tomu, že som už zaviedla nelineárne prvky.
V tomto prípade teda kvadratické členy síce mierne upravili model,
ale neodstránili podozrenie na nesprávnu špecifikáciu. To naznačuje, že
problém nemusí byť len v linearite, ale možno chýba aj ďalšia relevantná
premenná. Preto by bolo vhodné zvážiť doplnenie nových vysvetľujúcich
premenných alebo iný typ transformácie. Samotné kvadratické rozšírenie
však v tomto prípade neprinieslo jednoznačné zlepšenie.
6. Transformácia pomocou dummy premennej a lineárnej lomenej
funkcie
Predpokladajme, že máme dummy premennú DUM, ktorá nadobúda hodnotu 0
alebo 1 podľa počtu zapojených vozidiel. Takáto premenná sa dá využiť
modelovanie zlomov,, a to napr.
- zlom v autonómnom člene \(\beta_0\)
a to nasledovnou špecifikáciou \[y_t =
\beta_0 + \beta_D D+ \beta_1 x_{t1} + \dots +\beta_k x_{tk} +
u_t\] čo interpretujeme ako posun regresnej priamky (regresnej
nadroviny) o \(\beta_D\) jednotiek
pozdĺž zvislej osi a to len v pozorovaniach, ak je splnená podmienka
\(D_t = 1\)
- zlom v sklone regresnej priamky (nadroviny) a to len v
pozorovaniach, ak je splnená podmienka \(D_t =
1\), čo dosiahneme nasledovnou špecifikáciou \[y_t = \beta_0 + \beta_1 x_{t1} + \dots +
\beta_{i}x_{ti} + \beta_{Di}D_tx_{ti}+ \dots + \beta_k x_{tk} +
u_t\] kde teda sklon priamky pozdĺž premenne \(x_{ti}\) je \(\beta_i\) ale len v prípade \(D_t=0\), inak je ten sklon rovný \(\beta_i+\beta_{D_i}\).
V našom prípade sa z grafov Component + Residual ukazuje, že vzťah
medzi počtom obetí a premennou Vehicles.involved nemusí byť úplne
lineárny. Krivka naznačuje zmenu smerovania približne pri hodnote 2
zapojených vozidiel.
Preto zavedieme dummy premennú DUM, ktorá vyjadruje, či sa nehody
týkajú dvoch a viacerých vozidiel:
# Vytvorenie dummy premennej: 0 ak počet vozidiel < 2, inak 1
udaje$DUM <- ifelse(udaje$Vehicles.involved < 2, 0, 1)
# Regresný model s dummy premennou
modelD_auto <- lm(Victims ~ +1 + DUM + Hour.1 + Part.of.the.day + Vehicles.involved, data = udaje)
summary(modelD_auto)
Call:
lm(formula = Victims ~ +1 + DUM + Hour.1 + Part.of.the.day +
Vehicles.involved, data = udaje)
Residuals:
Min 1Q Median 3Q Max
-1.4926 -0.6605 -0.2038 0.3398 3.8296
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.05441 0.86426 1.220 0.228
DUM 0.81615 0.61728 1.322 0.192
Hour.1 0.01110 0.03245 0.342 0.734
Part.of.the.dayMorning -0.30113 0.36011 -0.836 0.407
Part.of.the.dayNight 0.60983 0.50678 1.203 0.234
Vehicles.involved -0.18274 0.50527 -0.362 0.719
Residual standard error: 0.9328 on 54 degrees of freedom
Multiple R-squared: 0.1433, Adjusted R-squared: 0.06402
F-statistic: 1.807 on 5 and 54 DF, p-value: 0.127
Na základe výsledkov regresného modelu, ktorý zahŕňa dummy premennú
DUM rozlišujúcu nehody s jedným vozidlom od tých s dvoma a viacerými, sa
nepreukázal žiadny štatisticky významný efekt. Koeficient pri DUM je
síce kladný (0.81615), no jeho p-hodnota (0.192) je výrazne nad bežnou
hladinou významnosti, čo znamená, že rozdiel v autonómnom člene medzi
skupinami nie je preukázateľný. Rovnako ani ostatné premenné ako Hour.1,
Part.of.the.dayMorning, Part.of.the.dayNight a Vehicles.involved
nevykazujú štatistickú významnosť.
Celková vysvetľovacia schopnosť modelu je slabá – R² dosahuje hodnotu
0.1433 a upravené R² len 0.06402. Tieto výsledky naznačujú, že zavedenie
dummy premennej nezlepšilo kvalitu modelu a neodhalilo žiadne výrazné
rozdiely v počte obetí medzi nehodami s rôznym počtom zapojených
vozidiel. Model teda neodporúča rozlišovať tieto skupiny pomocou
DUM.
modelD_sklon <- lm(Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved + I(DUM * Vehicles.involved),data=udaje )
summary(modelD_sklon)
Call:
lm(formula = Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved +
I(DUM * Vehicles.involved), data = udaje)
Residuals:
Min 1Q Median 3Q Max
-1.4926 -0.6605 -0.2038 0.3398 3.8296
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.87056 1.26005 1.485 0.143
Hour.1 0.01110 0.03245 0.342 0.734
Part.of.the.dayMorning -0.30113 0.36011 -0.836 0.407
Part.of.the.dayNight 0.60983 0.50678 1.203 0.234
Vehicles.involved -0.99889 1.08830 -0.918 0.363
I(DUM * Vehicles.involved) 0.81615 0.61728 1.322 0.192
Residual standard error: 0.9328 on 54 degrees of freedom
Multiple R-squared: 0.1433, Adjusted R-squared: 0.06402
F-statistic: 1.807 on 5 and 54 DF, p-value: 0.127
V tomto modeli som pridala interakčný člen I(DUM *
Vehicles.involved), aby som zistila, či sa vplyv počtu vozidiel na počet
obetí líši medzi nehodami s jedným vozidlom a tými, kde bolo zapojených
viac vozidiel.
Výsledky však ukazujú, že ani samotný počet vozidiel (p = 0.363), ani
interakcia s dummy premennou (p = 0.192) nie sú štatisticky významné. To
znamená, že sklon regresnej priamky sa medzi týmito skupinami nehôd
výrazne nelíši.
Upravené R² má hodnotu len 0.06402, takže model má slabú
vysvetľovaciu schopnosť. Intercept je jediný parameter, ktorý sa
približuje k významnosti, ale ani ten nie je jednoznačne preukázateľný
(p = 0.143). Celkový F-test (p = 0.127) naznačuje, že model ako celok
nie je štatisticky významný.
Zavedenie interakčného člena teda neprinieslo zlepšenie a neviedlo k
identifikácii rozdielneho vplyvu počtu vozidiel na počet obetí. Model
ostáva slabý a interakcia sa neukázala ako užitočná.
Porovnanie pôvodného modelu a modelu s premenlivým sklonom nadroviny
vykonáme s pomocou anova testu:
anova(model, modelD_sklon)
Analysis of Variance Table
Model 1: Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved
Model 2: Victims ~ +1 + Hour.1 + Part.of.the.day + Vehicles.involved +
I(DUM * Vehicles.involved)
Res.Df RSS Df Sum of Sq F Pr(>F)
1 55 48.509
2 54 46.988 1 1.5211 1.7481 0.1917
resettest(modelD_sklon)
RESET test
data: modelD_sklon
RESET = 0.21684, df1 = 2, df2 = 52, p-value = 0.8058
Porovnanie modelov pomocou ANOVA testu ukázalo, že pridanie
interakčného členu I(DUM * Vehicles.involved) nezlepšilo výkonnosť
modelu – p-hodnota 0.1917 naznačuje, že rozdiel medzi pôvodným a
rozšíreným modelom nie je štatisticky významný.
RESET test s p-hodnotou 0.8058 takisto neukazuje žiadnu výraznú chybu
v špecifikácii modelu. To znamená, že aktuálna forma modelu je z
hľadiska funkčnej štruktúry postačujúca.
Celkovo sa interakčný člen neukázal ako prínosný a jeho zahrnutie do
modelu nevedie k lepšiemu vysvetleniu počtu obetí. Model sa po tejto
úprave nezlepšil.
LS0tCnRpdGxlOiAixaBwZWNpZmlrw6FjaWEgbW9kZWx1IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiBNb25pa2EgU3rFsWNzb3bDoQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKYGBge3J9CmxpYnJhcnkoem9vKQpsaWJyYXJ5KHRzZXJpZXMpCmxpYnJhcnkobG10ZXN0KQpsaWJyYXJ5KHNhbmR3aWNoKQpsaWJyYXJ5KGNhcikKcm0obGlzdD1scygpKQpgYGAKCk1vamEgZGF0YWLDoXphIG9ic2FodWplIHrDoXpuYW15IG8gZG9wcmF2bsO9Y2ggbmVob2TDoWNoIHYgQmFyY2Vsb25lIHphIHJvayAyMDE3LiBJZGUgbyBrb21iaW7DoWNpdSBwcmVtZW5uw71jaCB0w71rYWrDumNpY2ggc2EgbWllc3RhIG5laG9keSAobWVzdHNrw6EgxaF0dnLFpSwgdWxpY2EpLCDEjWFzdSAoZGXFiCB2IHTDvcW+ZG5pLCBob2RpbmEsIMSNYXPFpSBkxYhhKSBhIHrDoXZhxb5ub3N0aSBuZWhvZHkgKHBvxI1ldCB6cmFuZW7DvWNoLCBwb8SNZXQgb2JldMOtLCBwb8SNZXQgemFwb2plbsO9Y2ggdm96aWRpZWwpLiBDaWXEvm9tIGFuYWzDvXp5IGplIHBvbW9jb3UgdmlhY27DoXNvYm5laiBsaW5lw6FybmVqIHJlZ3Jlc2llIHByZXNrw7ptYcWlLCBkbyBha2VqIG1pZXJ5IHPDuiBwb8SNdHkgb2JldMOtIGRvcHJhdm7DvWNoIG5laMO0ZCBvdnBseXZuZW7DqSB2eWJyYW7DvW1pIMSNYXNvdsO9bWkgYSBrb250ZXh0b3bDvW1pIGZha3Rvcm1pLCBrb25rcsOpdG5lIGhvZGlub3UgbmVob2R5IChIb3VyLjEpLCDEjWFzxaVvdSBkxYhhIChQYXJ0Lm9mLnRoZS5kYXkpIGEgcG/EjXRvbSB6YXBvamVuw71jaCB2b3ppZGllbCAoVmVoaWNsZXMuaW52b2x2ZWQpLiBWw71zbGVka29tIGplIGlkZW50aWZpa8OhY2lhIHByZW1lbm7DvWNoLCBrdG9yw6kgxaF0YXRpc3RpY2t5IHbDvXpuYW1uZSBwcmlzcGlldmFqw7ogayB2eXN2ZXRsZW5pdSB6w6F2YcW+bm9zdGkgbmVow7RkLgoKYGBge3J9CmJhcmNfZGF0YSA8LSByZWFkLmNzdigiYmFyY19kYXRhLmNzdiIsIHNlcD0iOyIsIGRlYz0iLCIsIGhlYWRlciA9IFRSVUUpCmhlYWQodWRhamUpIAp1ZGFqZSA8LSB1ZGFqZVstMjcsXQp1ZGFqZSA8LSB1ZGFqZVstMixdCgp1ZGFqZSA8LSBiYXJjX2RhdGFbLCBjKCJWaWN0aW1zIiwgIkhvdXIuMSIsICJQYXJ0Lm9mLnRoZS5kYXkiLCAiVmVoaWNsZXMuaW52b2x2ZWQiKV0KCnVkYWplJFBhcnQub2YudGhlLmRheSA8LSBhcy5mYWN0b3IodWRhamUkUGFydC5vZi50aGUuZGF5KQoKIyBEYXRhIGltcHV0YXRpb24KIyBDb21wdXRlIGNvbHVtbiBtZWRpYW5zIGZvciBudW1lcmljIHZhcmlhYmxlcwpjb2x1bW5fbWVkaWFucyA8LSBzYXBwbHkodWRhamVbLCBjKCJWaWN0aW1zIiwgIkhvdXIuMSIsICJWZWhpY2xlcy5pbnZvbHZlZCIpXSwgbWVkaWFuLCBuYS5ybSA9IFRSVUUpCgojIEltcHV0ZSBtaXNzaW5nIHZhbHVlcyB3aXRoIGNvbHVtbiBtZWRpYW5zCnVkYWplX2ltcHV0ZWQgPC0gdWRhamUKZm9yIChjb2wgaW4gbmFtZXMoY29sdW1uX21lZGlhbnMpKSB7CiAgdWRhamVfaW1wdXRlZFtbY29sXV1baXMubmEodWRhamVfaW1wdXRlZFtbY29sXV0pXSA8LSBjb2x1bW5fbWVkaWFuc1tjb2xdCn0KCiMgUmVwbGFjZSBvcmlnaW5hbCBkYXRhIHdpdGggaW1wdXRlZCB2ZXJzaW9uCnVkYWplIDwtIHVkYWplX2ltcHV0ZWQKCiMgWkFLTEFETkEgUkVHUkVTSUEKYXR0YWNoKHVkYWplKQptb2RlbCA8LSBsbShWaWN0aW1zIH4gKzEgKyBIb3VyLjEgKyBQYXJ0Lm9mLnRoZS5kYXkgKyBWZWhpY2xlcy5pbnZvbHZlZCwgZGF0YSA9IHVkYWplKQpzdW1tYXJ5KG1vZGVsKQpgYGAKClRlc3RvdmHFpSwgxI1pIGplIG1vZGVsIHYgc3Byw6F2bmVqIGZ1bmvEjW5laiBmb3JtZSAodC4gai4gxI1pIGplIGxpbmXDoXJuYSDFoXBlY2lmaWvDoWNpYSB2aG9kbsOhLCBhbGVibyDEjWkgYnkgc3RlIG1hbGkgdHJhbnNmb3Jtb3ZhxaUgcHJlbWVubsOpLCBuYXByw61rbGFkIHBvbW9jb3UgbG9nYXJpdG1vdiBhbGVibyBtb2NuaW5hbWkpLCBtb8W+bm8gdnlrb25hxaUgdmlhY2Vyw71taSBzcMO0c29ibWkuCgojIyMgMS4gVGVzdCBSRVNFVCAodGVzdCBjaHlieSDFoXBlY2lmaWvDoWNpZSBSYW1zZXlobyByZWdyZXNuZWogcm92bmljZSAtIFJhbXNleSBSZXNldCBUZXN0KQoKSWRlIG8gbmFqxaF0YW5kYXJkbmVqxaHDrSBmb3Jtw6FsbnkgdGVzdCBuZXNwcsOhdm5laiDFoXBlY2lmaWvDoWNpZSBmdW5rxI1uZWogZm9ybXkgYWxlIGTDoSBzYSBwb3XFvmnFpSBhaiBwcmUgcHLDrXBhZHksIGFrIHNtZSBuZcWhcGVjaWZpa292YWxpIHbFoWV0a3kgdnlzdmV0xL51asO6Y2UgcHJlbWVubsOpLgoKTXnFoWxpZW5rYTogTmVjaCBww7R2b2Ruw70gbW9kZWwgbcOhIHR2YXIKJCR5X3QgPSBcYmV0YV8wICsgXGJldGFfMSB4X3t0MTB9ICsgXGRvdHMgK1xiZXRhX2sgeF97dGt9ICsgdV90JCQKQWsgamUgdsOhxaEgbW9kZWwgc3Byw6F2bmUgxaFwZWNpZmlrb3ZhbsO9LCBwb3RvbSBwcmlkYW7DrW0gbW9jbsOtbiB2eXJvdm5hbsO9Y2ggaG9kbsO0dCAobmFwci4gJFxoYXQgeV90XjIkLCAkXGhhdHt5fV90XjMkKSBieSBzYSBww7R2b2Ruw70gbW9kZWwgbmVtYWwgcG9kc3RhdG5lIHpsZXDFoWnFpSwgdGVkYSBidWRlbWUgdGVzdG92YcWlIHDDtHZvZG7DvSBtb2RlbCB1dmVkZW7DvSB2ecWhxaFpZSBhIG1vZGVsCgokJHlfdCA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfe3QxMH0gKyBcZG90cyArXGJldGFfayB4X3t0a30gKyBcZ2FtbWFfMlxoYXQgeV90XjIgKyBcZ2FtbWFfM1xoYXR7eX1fdF4zICsgdV90JCQKCkJ1ZGVtZSB0ZXN0b3ZhxaUgaHlwb3TDqXp1IAoKJEhfMDokIG1vZGVsIGplIHNwcsOhdm5lIMWhcGVjaWZpa292YW7DvSAoJFxnYW1tYV8yID0gXGdhbW1hXzMgPSAwJCkKCm9wcm90aQoKJEhfMTokIG1vZGVsIGplIG5lc3Byw6F2bmUgxaFwZWNpZmlrb3ZhbsO9ICgkXGdhbW1hXzIgXG5lIDAgIFxxdWFkIFx0ZXh0e2FsZWJvfSAgXHF1YWQgXGdhbW1hXzMgXG5lIDAkKQoKYGBge3J9CiMgU3VwcG9zZSB5b3VyIG1vZGVsIGlzOgptb2RlbCA8LSBsbShWaWN0aW1zIH4gKzEgKyBIb3VyLjEgKyBQYXJ0Lm9mLnRoZS5kYXkgKyBWZWhpY2xlcy5pbnZvbHZlZCwgZGF0YSA9IHVkYWplKQoKIyBSRVNFVCB0ZXN0IGZyb20gJ2xtdGVzdCcgcGFja2FnZToKbGlicmFyeShsbXRlc3QpCnJlc2V0dGVzdChtb2RlbCkKCmBgYAoKTmEgesOha2xhZGUgdsO9c2xlZGtvdiBSRVNFVCB0ZXN0dSAocC1ob2Rub3RhOiAwLjg5MDQgPiAwLjA1KSBuZXphbWlldGFtZSBudWxvdsO6IGh5cG90w6l6dSBvIHNwcsOhdm5laiDFoXBlY2lmaWvDoWNpaSBtb2RlbHUuIFRvIG5hem5hxI11amUsIMW+ZSBtb2RlbCBwcmF2ZGVwb2RvYm5lIG5lb2JzYWh1amUgxaF0cnVrdHVyw6FsbnUgY2h5YnUgYSB6dm9sZW7DoSBsaW5lw6FybmEgZm9ybWEgamUgdmhvZG7DoSBuYSB2eXN2ZXRsZW5pZSBwb8SNdHUgb2JldMOtIGRvcHJhdm7DvWNoIG5laMO0ZC4KCiMjIyAyLiBHcmFmaWNrw6EgYW5hbMO9emEKCiMjIyMgR3JhZiAqUmVzaWR1YWxzIHZzLiBGaXR0ZWQqCgpHcmFmaWNrw6EgYW5hbMO9emEgdnrFpWFodSBtZWR6aSB2eXJvdm5hbsO9bWkgaG9kbm90YW1pIG7DoWhvZG5laiBwcmVtZW5uZWogYSByZXrDrWR1YW1pOgoKYGBge3J9CnBsb3QobW9kZWwsIHdoaWNoID0gMSkKYGBgCgpHcmFmIHJlesOtZHXDrSB2b8SNaSB2eXJvdm5hbsO9bSBob2Rub3TDoW0gbmF6bmHEjXVqZSBqZW1uw6kgemFrcml2ZW5pZSwgxI1vIG3DtMW+ZSBzaWduYWxpem92YcWlLCDFvmUgbW9kZWwgbmV6YWNoeXTDoXZhIHbFoWV0a3kgdnrFpWFoeSDDunBsbmUgcHJlc25lLiBNaWVybmEgb2RjaMO9bGthIG9kIG7DoWhvZG5vc3RpIHJlesOtZHXDrSBtw7TFvmUgcG91a2F6b3ZhxaUgbmEgbmVsaW5lw6FybnkgZWZla3QgYWxlYm8gbmEgY2jDvWJhasO6Y3UgcmVsZXZhbnRuw7ogcHJlbWVubsO6LgoKIyMjIyBHcmFmeSBDK1IgKioKClTDoXRvIGFuYWzDvXphIG7DoW0gbcO0xb5lIHBvbcO0Y8WlIHByaSBoxL5hZGFuw60gb2Rwb3ZlZGUgbmEgb3TDoXprdSwga3RvcsO6IHByZW1lbm7DuiBieSBzbWUgbWFsaSB0cmFuc2ZvbW92YcWlIHBvbW9jb3UgbmVqYWtlaiB6bsOhbWVqIGZ1bmtjaWUuIFZ5Y2jDoWR6YWptZSB6IHDDtHZvZG5laiByb3ZuaWNlCgokJHlfdCA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfe3QxfSArIFxkb3RzICtcYmV0YV9rIHhfe3RrfSArIHVfdCQkClTDunRvIHJvdm5pY3UgbmFqcHJ2IG9kaGFkbmVtZSBhIHBvdG9tIHZ5a3Jlc8S+dWplbWUgZ3JhZnksIGtkZSB2w71yYXogY29tcG9uZW50K3Jlc2lkdWFsIChDK1IpIHBsb3QgdnlrcmVzxL51amUgbmEgenZpc2xlaiBvc2kgJFxoYXR7XGJldGF9X2l4X3t0aX0rZV90JCBhIG5hIHZvZG9yb3ZuZWogb3NpIHZ5a3Jlc8S+dWplIGhvZG5vdHkgJHhfe3RpfSQKClRpZXRvIGdyYWZ5IHBvbcOhaGFqw7ogaWRlbnRpZmlrb3ZhxaUgbmVsaW5lw6FybmUgdnrFpWFoeSBwcmUga2HFvmTDvSByZWdyZXNvcjoKCmBgYHtyfQpjYXI6OmNyUGxvdHMobW9kZWwpCgpgYGAKQ29tcG9uZW50ICsgUmVzaWR1YWwgZ3JhZnkgdWthenVqw7osIMW+ZSB2esWlYWggbWVkemkgcG/EjXRvbSBvYmV0w60gYSBuaWVrdG9yw71taSBwcmVtZW5uw71taSBuZW11c8OtIGJ5xaUgw7pwbG5lIGxpbmXDoXJueS4gTmFqdsOkxI3FocOtIG9ka2xvbiBvZCBwcmlhbWt5IHZpZG5vIHByaSBwcmVtZW5uw71jaCBIb3VyLjEgYSBWZWhpY2xlcy5pbnZvbHZlZCwgxI1vIG5hem5hxI11amUsIMW+ZSBieSBtb2hsbyBiecWlIHZob2Ruw6kgenbDocW+acWlIGljaCBrdmFkcmF0aWNrw7ogYWxlYm8gaW7DuiBmdW5rxI1uw7ogdHJhbnNmb3Jtw6FjaXUuCgojIyAzLiBOZWxpbmXDoXJuYSDFoXBlY2lmaWvDoWNpYQoKxIxhc3Rva3LDoXQgbcO0xb5lbWUgYWogemxvxb5pdGVqxaFpZSBuZWxpbmXDoXJuZSB2esWlYWh5IG1vZGVsb3ZhxaUgcyBwb21vY291IGljaCBhcHJveGltw6FjaWUgcyBwb2x5bsOzbW9tLCB0ZWRhIHYgcHLDrXBhZGUga3ZhZHJhdGlja8O9Y2ggxI1sZW5vdgoKJCR5X3QgPSBcYmV0YV8wICsgXGJldGFfMSB4X3t0MTB9ICsgXGRvdHMgK1xiZXRhX2sgeF97dGt9ICsgXGRvdHMgKyBcZ2FtbWFfaVxoYXQgeF97aWt9XjIgKyBcZG90cyArIFxnYW1tYV9qXGhhdCB4X3tqa31eMiArIFxkb3RzICsgdV90JCQKUHLDrWtsYWQgbmEgdMO6dG8gbW9kaWZpa8OhY2l1IHV2aWTDrW1lIG5pxb7FoWllLgoKIyMgMy4gUG9yb3ZuYW5pZSB6w6FrbGFkbsOpaG8gYSBtb2RpZmlrb3ZhbsOpaG8gbW9kZWx1CgpQcmVkcG9rbGFkYWptZSwgxb5lIHByaSBuZWxpbmXDoXJueWNoIMO6cHJhdsOhY2ggcMO0dm9kbsOpaG8gbW9kZWx1IGRvcHJhdm7DvWNoIG5laMO0ZCB6YXZlZGllbWUga3ZhZHJhdGlja8OpIMSNbGVueSBwcmUgcHJlbWVubsOpIEhvdXIuMSBhIFZlaGljbGVzLmludm9sdmVkLiBLIHRvbXV0byBrcm9rdSBuw6FzIG1vdGl2dWplIENvbXBvbmVudCArIFJlc2lkdWFsIGdyYWYsIGtkZSBzYSB2eXJvdm5hbsOhIGtyaXZrYSBuYWp2aWFjIG9kY2h5xL51amUgb2QgcHJpYW1reSBwcsOhdmUgcHJpIHTDvWNodG8gcHJlbWVubsO9Y2guCgpBayBtw6EgdHJhbnNmb3Jtb3ZhbsO9IG1vZGVsIHZ5xaHFocOtIHVwcmF2ZW7DvSBrb2VmY2llbnQgZGV0ZXJtaW7DoWNpZSAkUl4yX3thZGp9JCBhIHByaSBSRVNFVCB0ZXN0IHByaWptZW1lIGFsdGVybmF0w612bnUgaHlwb3TDqXp1LCBvZHBvcsO6xI1hbWUgc2kgdsO9c2xlZGt5IHBvdHZyZGnFpSBzIHBvbW9jb3UgQW5vdmEgdGVzdHUgb2JvY2ggbW9kZWxvdiBhIHByw61wYWRuZSBvcGFrb3ZhbsOpaG8gUmVzZXQgVGVzdHUgdXBsYXRuZW5lbsOpaG8gbmEgbmVsaW5lw6FybmUgdHJhbnNmb3Jtb3ZhbsO9IG1vZGVsCgoKYGBge3J9Cm1vZGVsIDwtIGxtKFZpY3RpbXMgfiArMSArIEhvdXIuMSArIFBhcnQub2YudGhlLmRheSArIFZlaGljbGVzLmludm9sdmVkKQptb2RlbF9rdmFkciA8LSBsbShWaWN0aW1zIH4gKzEgKyBIb3VyLjEgKyBQYXJ0Lm9mLnRoZS5kYXkgKyBWZWhpY2xlcy5pbnZvbHZlZCArIEkoSG91ci4xXjIpICsgSShWZWhpY2xlcy5pbnZvbHZlZF4yKSwgZGF0YSA9IHVkYWplKQpzdW1tYXJ5KG1vZGVsX2t2YWRyKQphbm92YShtb2RlbCwgbW9kZWxfa3ZhZHIpCmxpYnJhcnkobG10ZXN0KQpyZXNldHRlc3QobW9kZWxfa3ZhZHIpCmBgYAoKUm96xaHDrXJlbsO9IG1vZGVsLCBrdG9yw70gemFoxZXFiGEga3ZhZHJhdGlja8OpIMSNbGVueSBwcmVtZW5uw71jaCBIb3VyLjEgYSBWZWhpY2xlcy5pbnZvbHZlZCwgbmVwcmV1a8OhemFsIHbDvXJhem7DqSB6bGVwxaFlbmllIG9wcm90aSBww7R2b2Ruw6ltdSBsaW5lw6FybmVtdSBtb2RlbHUuIEhvY2kgbmlla3RvcsOpIGtvZWZpY2llbnR5IHNhIHByaWJsacW+dWrDuiBrIGhyYW5pY2kgxaF0YXRpc3RpY2tlaiB2w716bmFtbm9zdGksIHbDpMSNxaFpbmEgeiBuaWNoIOKAkyB2csOhdGFuZSBub3ZvcHJpZGFuw71jaCBrdmFkcmF0aWNrw71jaCDEjWxlbm92IOKAkyBvc3TDoXZhIG5ldsO9em5hbW7DoS4gVXByYXZlbsO9IGtvZWZpY2llbnQgZGV0ZXJtaW7DoWNpZSAoUsKyYWRqKSBzYSBzw61jZSBtaWVybmUgenbDvcWhaWwsIGFsZSBzdMOhbGUgem9zdMOhdmEgbsOtemt5LCDEjW8gbmF6bmHEjXVqZSwgxb5lIG1vZGVsIGxlbiBzbGFibyB2eXN2ZXTEvnVqZSB2YXJpYWJpbGl0dSBwb8SNdHUgb2JldMOtLgoKUG9yb3ZuYW5pZSBtb2RlbG92IHBvbW9jb3UgQU5PVkEgdGVzdHUgdWthenVqZSwgxb5lIHJvemRpZWwgbWVkemkgesOha2xhZG7DvW0gYSByb3rFocOtcmVuw71tIG1vZGVsb20gbmllIGplIMWhdGF0aXN0aWNreSB2w716bmFtbsO9IChwIOKJiCAwLjA3MDUpLCB0ZWRhIHByaWRhbmllIGt2YWRyYXRpY2vDvWNoIMSNbGVub3YgbmV2aWVkbG8gayB2w71yYXpuZSBsZXDFoWllbXUgb3Bpc3UgZMOhdC4gTmFvcGFrLCBSRVNFVCB0ZXN0IGFwbGlrb3ZhbsO9IG5hIHJvesWhw61yZW7DvSBtb2RlbCB1a2F6dWplIHAtaG9kbm90dSDiiYggMC4wMDQ4LCDEjW8gbmF6bmHEjXVqZSwgxb5lIGFqIHRlbnRvIG1vZGVsIG3DtMW+ZSB0cnBpZcWlIMWhcGVjaWZpa2HEjW5vdSBjaHlib3Ug4oCTIG5hcHJpZWsgdG9tdSwgxb5lIHNvbSB1xb4gemF2aWVkbGEgbmVsaW5lw6FybmUgcHJ2a3kuCgpWIHRvbXRvIHByw61wYWRlIHRlZGEga3ZhZHJhdGlja8OpIMSNbGVueSBzw61jZSBtaWVybmUgdXByYXZpbGkgbW9kZWwsIGFsZSBuZW9kc3Ryw6FuaWxpIHBvZG96cmVuaWUgbmEgbmVzcHLDoXZudSDFoXBlY2lmaWvDoWNpdS4gVG8gbmF6bmHEjXVqZSwgxb5lIHByb2Jsw6ltIG5lbXVzw60gYnnFpSBsZW4gdiBsaW5lYXJpdGUsIGFsZSBtb8W+bm8gY2jDvWJhIGFqIMSPYWzFoWlhIHJlbGV2YW50bsOhIHByZW1lbm7DoS4gUHJldG8gYnkgYm9sbyB2aG9kbsOpIHp2w6HFvmnFpSBkb3BsbmVuaWUgbm92w71jaCB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoIGFsZWJvIGluw70gdHlwIHRyYW5zZm9ybcOhY2llLiBTYW1vdG7DqSBrdmFkcmF0aWNrw6kgcm96xaHDrXJlbmllIHbFoWFrIHYgdG9tdG8gcHLDrXBhZGUgbmVwcmluaWVzbG8gamVkbm96bmHEjW7DqSB6bGVwxaFlbmllLgoKIyMjIDYuIFRyYW5zZm9ybcOhY2lhIHBvbW9jb3UgZHVtbXkgcHJlbWVubmVqIGEgbGluZcOhcm5laiBsb21lbmVqIGZ1bmtjaWUKClByZWRwb2tsYWRham1lLCDFvmUgbcOhbWUgZHVtbXkgcHJlbWVubsO6IERVTSwga3RvcsOhIG5hZG9iw7pkYSBob2Rub3R1IDAgYWxlYm8gMSBwb2TEvmEgcG/EjXR1IHphcG9qZW7DvWNoIHZvemlkaWVsLiBUYWvDoXRvIHByZW1lbm7DoSBzYSBkw6Egdnl1xb5pxaUgbW9kZWxvdmFuaWUgemxvbW92LCwgYSB0byBuYXByLgoKMS4gemxvbSB2IGF1dG9uw7Ntbm9tIMSNbGVuZSAkXGJldGFfMCQgYSB0byBuYXNsZWRvdm5vdSDFoXBlY2lmaWvDoWNpb3UKJCR5X3QgPSBcYmV0YV8wICsgXGJldGFfRCBEKyBcYmV0YV8xIHhfe3QxfSArIFxkb3RzICtcYmV0YV9rIHhfe3RrfSArIHVfdCQkCsSNbyBpbnRlcnByZXR1amVtZSBha28gcG9zdW4gcmVncmVzbmVqIHByaWFta3kgKHJlZ3Jlc25laiBuYWRyb3ZpbnkpIG8gJFxiZXRhX0QkIGplZG5vdGllayBwb3pkxLrFviB6dmlzbGVqIG9zaSBhIHRvIGxlbiB2IHBvem9yb3ZhbmlhY2gsIGFrIGplIHNwbG5lbsOhIHBvZG1pZW5rYSAkRF90ID0gMSQKMi4gemxvbSB2IHNrbG9uZSByZWdyZXNuZWogcHJpYW1reSAobmFkcm92aW55KSBhIHRvIGxlbiB2IHBvem9yb3ZhbmlhY2gsIGFrIGplIHNwbG5lbsOhIHBvZG1pZW5rYSAkRF90ID0gMSQsIMSNbyBkb3NpYWhuZW1lIG5hc2xlZG92bm91IMWhcGVjaWZpa8OhY2lvdQokJHlfdCA9IFxiZXRhXzAgKyAgXGJldGFfMSB4X3t0MX0gKyBcZG90cyArIFxiZXRhX3tpfXhfe3RpfSArIFxiZXRhX3tEaX1EX3R4X3t0aX0rIFxkb3RzICsgXGJldGFfayB4X3t0a30gKyB1X3QkJAprZGUgdGVkYSBza2xvbiBwcmlhbWt5IHBvemTEusW+IHByZW1lbm5lICR4X3t0aX0kIGplICRcYmV0YV9pJCBhbGUgbGVuIHYgcHLDrXBhZGUgJERfdD0wJCwgaW5hayBqZSB0ZW4gc2tsb24gcm92bsO9ICRcYmV0YV9pK1xiZXRhX3tEX2l9JC4KClYgbmHFoW9tIHByw61wYWRlIHNhIHogZ3JhZm92IENvbXBvbmVudCArIFJlc2lkdWFsIHVrYXp1amUsIMW+ZSB2esWlYWggbWVkemkgcG/EjXRvbSBvYmV0w60gYSBwcmVtZW5ub3UgVmVoaWNsZXMuaW52b2x2ZWQgbmVtdXPDrSBiecWlIMO6cGxuZSBsaW5lw6FybnkuIEtyaXZrYSBuYXpuYcSNdWplIHptZW51IHNtZXJvdmFuaWEgcHJpYmxpxb5uZSBwcmkgaG9kbm90ZSAyIHphcG9qZW7DvWNoIHZvemlkaWVsLgoKUHJldG8gemF2ZWRpZW1lIGR1bW15IHByZW1lbm7DuiBEVU0sIGt0b3LDoSB2eWphZHJ1amUsIMSNaSBzYSBuZWhvZHkgdMO9a2Fqw7ogZHZvY2ggYSB2aWFjZXLDvWNoIHZvemlkaWVsOgoKLSBhayBWZWhpY2xlcy5pbnZvbHZlZCA8IDIg4oaSIERVTSA9IDAKCi0gYWsgVmVoaWNsZXMuaW52b2x2ZWQg4omlIDIg4oaSIERVTSA9IDEKCgpgYGB7cn0KIyBWeXR2b3JlbmllIGR1bW15IHByZW1lbm5lajogMCBhayBwb8SNZXQgdm96aWRpZWwgPCAyLCBpbmFrIDEKdWRhamUkRFVNIDwtIGlmZWxzZSh1ZGFqZSRWZWhpY2xlcy5pbnZvbHZlZCA8IDIsIDAsIDEpCgojIFJlZ3Jlc27DvSBtb2RlbCBzIGR1bW15IHByZW1lbm5vdQptb2RlbERfYXV0byA8LSBsbShWaWN0aW1zIH4gKzEgKyBEVU0gKyBIb3VyLjEgKyBQYXJ0Lm9mLnRoZS5kYXkgKyBWZWhpY2xlcy5pbnZvbHZlZCwgZGF0YSA9IHVkYWplKQpzdW1tYXJ5KG1vZGVsRF9hdXRvKQpgYGAKCk5hIHrDoWtsYWRlIHbDvXNsZWRrb3YgcmVncmVzbsOpaG8gbW9kZWx1LCBrdG9yw70gemFoxZXFiGEgZHVtbXkgcHJlbWVubsO6IERVTSByb3psacWhdWrDumN1IG5laG9keSBzIGplZG7DvW0gdm96aWRsb20gb2QgdMO9Y2ggcyBkdm9tYSBhIHZpYWNlcsO9bWksIHNhIG5lcHJldWvDoXphbCDFvmlhZG55IMWhdGF0aXN0aWNreSB2w716bmFtbsO9IGVmZWt0LiBLb2VmaWNpZW50IHByaSBEVU0gamUgc8OtY2Uga2xhZG7DvSAoMC44MTYxNSksIG5vIGplaG8gcC1ob2Rub3RhICgwLjE5MikgamUgdsO9cmF6bmUgbmFkIGJlxb5ub3UgaGxhZGlub3UgdsO9em5hbW5vc3RpLCDEjW8gem5hbWVuw6EsIMW+ZSByb3pkaWVsIHYgYXV0b27Ds21ub20gxI1sZW5lIG1lZHppIHNrdXBpbmFtaSBuaWUgamUgcHJldWvDoXphdGXEvm7DvS4gUm92bmFrbyBhbmkgb3N0YXRuw6kgcHJlbWVubsOpIGFrbyBIb3VyLjEsIFBhcnQub2YudGhlLmRheU1vcm5pbmcsIFBhcnQub2YudGhlLmRheU5pZ2h0IGEgVmVoaWNsZXMuaW52b2x2ZWQgbmV2eWthenVqw7ogxaF0YXRpc3RpY2vDuiB2w716bmFtbm9zxaUuIAoKQ2Vsa292w6EgdnlzdmV0xL5vdmFjaWEgc2Nob3Bub3PFpSBtb2RlbHUgamUgc2xhYsOhIOKAkyBSwrIgZG9zYWh1amUgaG9kbm90dSAwLjE0MzMgYSB1cHJhdmVuw6kgUsKyIGxlbiAwLjA2NDAyLiBUaWV0byB2w71zbGVka3kgbmF6bmHEjXVqw7osIMW+ZSB6YXZlZGVuaWUgZHVtbXkgcHJlbWVubmVqIG5lemxlcMWhaWxvIGt2YWxpdHUgbW9kZWx1IGEgbmVvZGhhbGlsbyDFvmlhZG5lIHbDvXJhem7DqSByb3pkaWVseSB2IHBvxI10ZSBvYmV0w60gbWVkemkgbmVob2RhbWkgcyByw7R6bnltIHBvxI10b20gemFwb2plbsO9Y2ggdm96aWRpZWwuIE1vZGVsIHRlZGEgbmVvZHBvcsO6xI1hIHJvemxpxaFvdmHFpSB0aWV0byBza3VwaW55IHBvbW9jb3UgRFVNLgoKCmBgYHtyfQoKbW9kZWxEX3NrbG9uIDwtIGxtKFZpY3RpbXMgfiArMSArIEhvdXIuMSArIFBhcnQub2YudGhlLmRheSArIFZlaGljbGVzLmludm9sdmVkICsgSShEVU0gKiBWZWhpY2xlcy5pbnZvbHZlZCksZGF0YT11ZGFqZSApIApzdW1tYXJ5KG1vZGVsRF9za2xvbikKYGBgCgpWIHRvbXRvIG1vZGVsaSBzb20gcHJpZGFsYSBpbnRlcmFrxI1uw70gxI1sZW4gSShEVU0gKiBWZWhpY2xlcy5pbnZvbHZlZCksIGFieSBzb20gemlzdGlsYSwgxI1pIHNhIHZwbHl2IHBvxI10dSB2b3ppZGllbCBuYSBwb8SNZXQgb2JldMOtIGzDrcWhaSBtZWR6aSBuZWhvZGFtaSBzIGplZG7DvW0gdm96aWRsb20gYSB0w71taSwga2RlIGJvbG8gemFwb2plbsO9Y2ggdmlhYyB2b3ppZGllbC4KClbDvXNsZWRreSB2xaFhayB1a2F6dWrDuiwgxb5lIGFuaSBzYW1vdG7DvSBwb8SNZXQgdm96aWRpZWwgKHAgPSAwLjM2MyksIGFuaSBpbnRlcmFrY2lhIHMgZHVtbXkgcHJlbWVubm91IChwID0gMC4xOTIpIG5pZSBzw7ogxaF0YXRpc3RpY2t5IHbDvXpuYW1uw6kuIFRvIHpuYW1lbsOhLCDFvmUgc2tsb24gcmVncmVzbmVqIHByaWFta3kgc2EgbWVkemkgdMO9bWl0byBza3VwaW5hbWkgbmVow7RkIHbDvXJhem5lIG5lbMOtxaFpLgoKVXByYXZlbsOpIFLCsiBtw6EgaG9kbm90dSBsZW4gMC4wNjQwMiwgdGFrxb5lIG1vZGVsIG3DoSBzbGFiw7ogdnlzdmV0xL5vdmFjaXUgc2Nob3Bub3PFpS4gSW50ZXJjZXB0IGplIGplZGluw70gcGFyYW1ldGVyLCBrdG9yw70gc2EgcHJpYmxpxb51amUgayB2w716bmFtbm9zdGksIGFsZSBhbmkgdGVuIG5pZSBqZSBqZWRub3puYcSNbmUgcHJldWvDoXphdGXEvm7DvSAocCA9IDAuMTQzKS4gQ2Vsa292w70gRi10ZXN0IChwID0gMC4xMjcpIG5hem5hxI11amUsIMW+ZSBtb2RlbCBha28gY2Vsb2sgbmllIGplIMWhdGF0aXN0aWNreSB2w716bmFtbsO9LgoKWmF2ZWRlbmllIGludGVyYWvEjW7DqWhvIMSNbGVuYSB0ZWRhIG5lcHJpbmllc2xvIHpsZXDFoWVuaWUgYSBuZXZpZWRsbyBrIGlkZW50aWZpa8OhY2lpIHJvemRpZWxuZWhvIHZwbHl2dSBwb8SNdHUgdm96aWRpZWwgbmEgcG/EjWV0IG9iZXTDrS4gTW9kZWwgb3N0w6F2YSBzbGFiw70gYSBpbnRlcmFrY2lhIHNhIG5ldWvDoXphbGEgYWtvIHXFvml0b8SNbsOhLgoKClBvcm92bmFuaWUgcMO0dm9kbsOpaG8gbW9kZWx1IGEgbW9kZWx1IHMgcHJlbWVubGl2w71tIHNrbG9ub20gbmFkcm92aW55IHZ5a29uw6FtZSBzIHBvbW9jb3UgYW5vdmEgdGVzdHU6CgpgYGB7cn0KYW5vdmEobW9kZWwsIG1vZGVsRF9za2xvbikKcmVzZXR0ZXN0KG1vZGVsRF9za2xvbikKYGBgClBvcm92bmFuaWUgbW9kZWxvdiBwb21vY291IEFOT1ZBIHRlc3R1IHVrw6F6YWxvLCDFvmUgcHJpZGFuaWUgaW50ZXJha8SNbsOpaG8gxI1sZW51IEkoRFVNICogVmVoaWNsZXMuaW52b2x2ZWQpIG5lemxlcMWhaWxvIHbDvWtvbm5vc8WlIG1vZGVsdSDigJMgcC1ob2Rub3RhIDAuMTkxNyBuYXpuYcSNdWplLCDFvmUgcm96ZGllbCBtZWR6aSBww7R2b2Ruw71tIGEgcm96xaHDrXJlbsO9bSBtb2RlbG9tIG5pZSBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvS4KClJFU0VUIHRlc3QgcyBwLWhvZG5vdG91IDAuODA1OCB0YWtpc3RvIG5ldWthenVqZSDFvmlhZG51IHbDvXJhem7DuiBjaHlidSB2IMWhcGVjaWZpa8OhY2lpIG1vZGVsdS4gVG8gem5hbWVuw6EsIMW+ZSBha3R1w6FsbmEgZm9ybWEgbW9kZWx1IGplIHogaMS+YWRpc2thIGZ1bmvEjW5laiDFoXRydWt0w7pyeSBwb3N0YcSNdWrDumNhLgoKQ2Vsa292byBzYSBpbnRlcmFrxI1uw70gxI1sZW4gbmV1a8OhemFsIGFrbyBwcsOtbm9zbsO9IGEgamVobyB6YWhybnV0aWUgZG8gbW9kZWx1IG5ldmVkaWUgayBsZXDFoWllbXUgdnlzdmV0bGVuaXUgcG/EjXR1IG9iZXTDrS4gTW9kZWwgc2EgcG8gdGVqdG8gw7pwcmF2ZSBuZXpsZXDFoWlsLgoK