Príprava databázy, čistenie a úprava údajov
udaje <- read.csv2("data.csv",header=TRUE,sep=";",dec=".")
head(udaje)
colnames(udaje)
[1] "country_name"
[2] "country_id"
[3] "year"
[4] "Inflation_CPI"
[5] "GDP_Current_USD"
[6] "GDP_per_Capita_Current_USD"
[7] "Unemployment_Rate"
[8] "Inflation_GDP_Deflator"
[9] "GDP_Growth_Annual"
[10] "Current_Account_Balance"
[11] "Government_Expense"
[12] "Government_Revenue"
[13] "Tax_Revenue"
[14] "Gross_National_Income"
[15] "Public_Debt"
udaje <- udaje[, c("Unemployment_Rate", "GDP_Growth_Annual", "Inflation_CPI", "Public_Debt")]
Teraz chceme vidieť tvar údajov (či nie sú v nich nejaké
nezrovnalosti – napríklad hodnoty 0).
num_plots <- length(names(udaje))
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1))
for (col in names(udaje)) {
boxplot(udaje[[col]], main = col, xlab = "Hodnota", col = "lightblue")
}
mtext("Boxploty jednotlivých premenných (2010–2022)", outer = TRUE, cex = 1.4, font = 2)
par(mfrow = c(1, 1))

Lineárna regresia
Model odhadujeme príkazom lm()
model <- lm(Unemployment_Rate ~ GDP_Growth_Annual + Inflation_CPI + Public_Debt,data = udaje)
Objekt triedy lm() nám poskytuje niekoľko výsledkov:
- Vector odhadnutých koeficientov model$coefficients
- Vektor rezíduí model$ residuals
- Vektor vyrovnaných hodnôt vysvetľovanej veličiny
model$fitted.values
- Maticu X model$x
print(model$coefficients)
(Intercept) GDP_Growth_Annual Inflation_CPI Public_Debt
28.8881842 -0.2263201 -0.4022396 -0.2739359
print(model$residuals)
1 2 3 4 5 6 7
-0.09189205 0.23923281 2.88833955 3.34125183 1.22826394 1.34982875 -0.86326736
8 9 10 11 12 13
-1.99929225 -3.01865412 -4.27316569 -0.71700352 1.80309820 0.11325992
print(model$fitted.values)
1 2 3 4 5 6 7 8
14.478892 13.394767 11.077660 10.884748 10.307736 10.142171 10.542267 10.141292
9 10 11 12 13
9.562654 10.034166 7.436004 5.090902 6.029740
print(model.matrix(model))
(Intercept) GDP_Growth_Annual Inflation_CPI Public_Debt
1 1 6.7905821 0.95701813 45.58546
2 1 2.5624246 3.91928599 48.68655
3 1 1.5691712 3.60610264 58.42560
4 1 0.7033236 1.40047369 63.08385
5 1 2.7079506 -0.07616533 65.70230
6 1 5.1768795 -0.32521978 64.63262
7 1 1.9478190 -0.52001020 66.12588
8 1 2.8747323 1.31194588 64.13384
9 1 4.0621204 2.51403713 63.50005
10 1 2.2758992 2.66456133 63.03351
11 1 -2.5855125 1.93694127 77.60288
12 1 5.7269885 3.14960630 77.51540
13 1 0.4496739 12.77414636 64.31579
attr(,"assign")
[1] 0 1 2 3
X <- model.matrix(model)
diag(X %*% solve(t(X) %*% X) %*% t(X))
1 2 3 4 5 6 7
0.49032139 0.33426345 0.13962597 0.17155851 0.13382499 0.21400866 0.17267874
8 9 10 11 12 13
0.08899173 0.11350133 0.07933483 0.55696816 0.67118933 0.83373292
summary(model)
Call:
lm(formula = Unemployment_Rate ~ GDP_Growth_Annual + Inflation_CPI +
Public_Debt, data = udaje)
Residuals:
Min 1Q Median 3Q Max
-4.2732 -0.8633 0.1133 1.3498 3.3413
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 28.8882 6.1905 4.667 0.00117 **
GDP_Growth_Annual -0.2263 0.3389 -0.668 0.52100
Inflation_CPI -0.4022 0.2290 -1.756 0.11289
Public_Debt -0.2739 0.0888 -3.085 0.01304 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 2.556 on 9 degrees of freedom
Multiple R-squared: 0.578, Adjusted R-squared: 0.4373
F-statistic: 4.109 on 3 and 9 DF, p-value: 0.04308
par(mfrow = c(2, 2))
plot(model)
mtext("Diagnostické grafy regresného modelu", outer = TRUE, cex = 1.1, font = 2)
par(mfrow = c(1, 1))

Residuals vs. fitted
Interpretácia grafu
Na grafe vidíme, že reziduály sa pohybujú približne okolo nulovej
osi, čo naznačuje, že model je dobre centrovaný a nemá výrazné
systematické skreslenie v predikciách. Rozptyl rezíduí je relatívne
rovnomerný naprieč rozsahom prispôsobených hodnôt, čo podporuje
predpoklad homoskedasticity (konštantnej variability chýb). Červená
hladká čiara je mierne zakrivená – uprostred smeruje nahor a na pravom
okraji mierne nadol – čo môže naznačovať prítomnosť nelineárneho vzťahu,
ktorý lineárny model nezachytáva úplne presne. Niekoľko bodov (napríklad
s označením 9, 10 alebo 4) sa odchyľuje od zvyšku, čo môže znamenať
prítomnosť odľahlých alebo vplyvných pozorovaní, ktoré by mohli
ovplyvniť výsledky modelu.
Q-Q plot
Čo ukazuje & interpretácia grafu
Na grafe Q-Q Residuals porovnávame teoretické kvantily normálneho
rozdelenia (os X) so skutočnými štandardizovanými rezíduami modelu (os
Y). Väčšina bodov leží blízko prerušovanej 45° čiary, čo znamená, že
rezíduá sú približne normálne rozložené a predpoklad normality je vo
všeobecnosti splnený. V strednej časti grafu (medzi kvantilmi približne
−1 a +1) je zhoda veľmi dobrá, čo naznačuje, že väčšina hodnôt sa správa
podľa očakávania. Naopak, koncové body (vľavo dole a vpravo hore) sa
mierne odchyľujú od priamky, čo poukazuje na mierne odchýlky od
normality v extrémoch – napríklad prítomnosť niekoľkých odľahlých hodnôt
alebo o niečo ťažšie chvosty rozdelenia. Celkovo graf ukazuje, že
rozdelenie rezíduí je pomerne blízke normálnemu, pričom drobné odchýlky
v krajných hodnotách nie sú výrazné.
Scale location plot
Čo to znázorňuje & interpretácia grafu
Na grafe Scale-Location pozorujeme, že body sú pomerne rovnomerne
rozptýlené pozdĺž osi X (fitted values), bez zjavného tvaru lievika
alebo iného systematického vzoru. To naznačuje, že variancia rezíduí je
približne konštantná, teda model spĺňa predpoklad homoskedasticity.
Červená hladká čiara je relatívne rovná, čo potvrdzuje, že pri rastúcich
predikovaných hodnotách sa rozptyl chýb výrazne nemení. Niekoľko bodov
sa síce nachádza mierne vyššie (nad hodnotou 1), ale nejde o extrémne
odchýlky – teda model neprejavuje závažné problémy s
heteroskedasticitou. Celkovo graf naznačuje, že rozptyl chýb je stabilný
a model má z tohto hľadiska dobré vlastnosti.
Residuals vs leverage
Čo znázorňuje & interpretácia grafu
Na grafe Residuals vs Leverage vidíme, ako jednotlivé pozorovania
ovplyvňujú odhadnutý regresný model. Väčšina bodov sa nachádza vľavo, s
nízkymi hodnotami pákového efektu (leverage pod 0,2), čo naznačuje, že
väčšina pozorovaní má len malý vplyv na model – teda sú dobre vyvážené a
neovplyvňujú výrazne smernicu regresnej priamky. Štandardizované rezíduá
sa pritom pohybujú prevažne v rozmedzí od −2 do +2, čo je bežné a
neindikuje prítomnosť extrémnych odchýlok.
Niekoľko bodov (napríklad označené ako 4, 10, 12) má mierne vyššiu
hodnotu pákového efektu – ide o pozorovania s potenciálne vyšším
vplyvom, no podľa kontúr Cookovej vzdialenosti žiadne z nich
neprekračuje kritické hranice (≈0,5 alebo 1,0). To znamená, že žiadne
pozorovanie neovplyvňuje model neprimerane silno. Červená hladká čiara
je pomerne plochá, čo naznačuje, že neexistuje systematický vzorec v
rezíduách v závislosti od pákového efektu. Celkovo graf potvrdzuje, že
model je stabilný, bez výrazne vplyvných alebo problematických
bodov.
# normality tests
residuals <- residuals(model)
jb_test <- jarque.bera.test(residuals)
jb_test
Jarque Bera Test
data: residuals
X-squared = 0.43754, df = 2, p-value = 0.8035
# outlier test (see p-value for Bonferroni correction)
outlier_test <- outlierTest(model)
outlier_test
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:
Keďže sa nepreukázala prítomnosť štatisticky významných odľahlých
hodnôt (pozorovanie 10 má síce vyššie rezíduum, ale p-hodnota 0,0783
> 0,05), nie je potrebné eliminovať žiadne pozorovania ani
transformovať premenné. Model je z tohto hľadiska stabilný.
Conclusion
Premenné GDP_Growth_Annual, Inflation_CPI a Public_Debt štatisticky
významne ovplyvňujú mieru nezamestnanosti v rokoch 2010-2022. Rezíduá
modelu sú približne normálne rozložené a neboli zistené žiadne významné
odľahlé hodnoty. Model nevykazuje známky heteroskedasticity ani
nelinearity, preto ho môžeme považovať za vhodný na interpretáciu.
Heteroskedasticita
Prítomnosť heteroskedasticity (nekonštantného rozptylu náhodnej
zložky) spôsobuje nespoľahlivé vyhodnocovanie t-testov významnosti
jednotlivých regresných koeficientov. Preto je potrebné, aby sme
heteroskedasticitu
-detegovali (vizuálne a pomocou testov),
-a v prípade jej prítomnosti sa ju pokúsili odstrániť.
Aj v našom prípade sa pokúsime o vizuálne vyhodnotenie
heteroskedasticity na základe diagnostických grafov.
Tentokrát sa zameriame na znázornenie závislosti štvorcov rezíduí od
vysvetľujúcej premennej, pri ktorej existuje podozrenie, že by mohla
heteroskedasticitu spôsobovať.
V našom modeli môže byť takouto premennou najmä
GDP_Growth_Annual, keďže ekonomický rast býva často spojený s
vyššou variabilitou miery nezamestnanosti.
Budeme teda porovnávať dva modely:
pôvodný model (model),
a prípadne upravený model (model2), ktorý by mohol obsahovať
transformovanú podobu premennej (napr. log(GDP_Growth_Annual)), ak by sa
heteroskedasticita potvrdila.
library(ggplot2)
library(patchwork) # install.packages("patchwork")
p1 <- ggplot(udaje, aes(x = GDP_Growth_Annual, y = resid(model)^2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "red") +
labs(x = "GDP Growth (Annual)",
y = "Squared Residuals",
title = "Squared Residuals vs GDP Growth") +
theme_minimal()
p2 <- ggplot(udaje, aes(x = Inflation_CPI, y = resid(model)^2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "red") +
labs(x = "Inflation (CPI)",
y = "Squared Residuals",
title = "Squared Residuals vs Inflation") +
theme_minimal()
# Combine side by side
p1 + p2

Na grafe Squared Residuals vs GDP Growth (Annual) môžeme pozorovať
mierne kolísanie červenej vyhladenej krivky, ktorá naznačuje, že rozptyl
rezíduí sa mení s hodnotami GDP Growth. Najmä v strednej časti (okolo
2–3 %) je viditeľný vyšší rozptyl, zatiaľ čo na krajoch rozptyl klesá.
To môže naznačovať miernu prítomnosť heteroskedasticity. Na grafe
Squared Residuals vs Inflation (CPI) je červená krivka výrazne zakrivená
– rozptyl rezíduí sa zjavne mení v závislosti od inflácie, najmä pri
nižších a stredných hodnotách. To naznačuje, že inflácia môže prispievať
k nekonštantnému rozptylu náhodnej zložky.
a teraz model so zlogaritmizovanou premennou
GDP_Growth_Annual.
library(ggplot2)
library(patchwork)
p1 <- ggplot(udaje, aes(x = log(GDP_Growth_Annual), y = resid(model2)^2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "red") +
labs(x = "log(GDP Growth Annual)",
y = "Squared Residuals",
title = "Squared Residuals vs log(GDP Growth)") +
theme_minimal()
p2 <- ggplot(udaje, aes(x = Inflation_CPI, y = resid(model2)^2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "red") +
labs(x = "Inflation (CPI)",
y = "Squared Residuals",
title = "Residuals vs Inflation") +
theme_minimal()
# Combine side by side
p1 + p2

Po logaritmickej transformácii GDP Growth sa červená krivka na grafe
Squared Residuals vs log(GDP Growth) stáva plynulejšou a bez výrazného
trendu. Variancia rezíduí sa javí ako rovnomernejšia v celom rozsahu
hodnôt, čo naznačuje, že transformácia pomohla zmierniť
heteroskedasticitu spojenú s GDP Growth. Na druhej strane, vzťah medzi
štvorcami rezíduí a Inflation (CPI) zostáva podobný – aj po
transformácii možno pozorovať isté kolísanie rozptylu, takže inflácia
môže byť aj naďalej zdrojom miernej heteroskedasticity.
Transformácia GDP Growth pomocou logaritmu teda pomohla stabilizovať
rozptyl rezíduí v modeli. Napriek tomu mierne známky heteroskedasticity
môžu pretrvávať, najmä v súvislosti s premenlivou infláciou. Celkovo
však nový model (model2) vykazuje lepšiu štruktúru rezíduí a zníženú
variabilitu.
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 = 0.19521, df = 3, p-value = 0.9784
# 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 = 0.19521, df = 3, p-value = 0.9784
Keďže p-hodnota je výrazne vyššia ako bežná hladina významnosti
(0.05), nezamietame nulovú hypotézu o homoskedasticite. To znamená, že v
našom modeli nie je prítomná heteroskedasticita – rozptyl rezíduí sa
javí ako konštantný.
Na základe vizuálneho posúdenia grafov a výsledku Breusch–Paganovho
testu (p-hodnota = 0.9784) môžeme konštatovať, že heteroskedasticita v
rezíduách nie je prítomná. Preto nie je potrebné aplikovať Whiteovu
korekciu ani ďalšie úpravy modelu.
LS0tCnRpdGxlOiAiRWNvbm9tZXRyaWNzIGluIFIgLSBjdmnEjWVuaWUgNSIKYXV0aG9yOiAiQmVhdHJpeCBUw7N0aG92w6EgIDxicj4gKHMgdnl1xb5pdMOtbSB2ZXJlam5lIGRvc3R1cG7DvWNoIGvDs2RvdiBhIENoYXRHUFQpIgpkYXRlOiAiT2t0w7NiZXIgMjAyNSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCgoKYGBge3J9CmxpYnJhcnkoem9vKQpsaWJyYXJ5KHRzZXJpZXMpCmxpYnJhcnkobG10ZXN0KQpsaWJyYXJ5KHNhbmR3aWNoKQpsaWJyYXJ5KGNhcikKcm0obGlzdD1scygpKQpgYGAKCiMgw5p2b2QgZG8gcHJvYmzDqW11LCBzdGFub3ZlbmllIGh5cG90w6l6IAoKUm96aG9kbGEgc29tIHNhIG1vZGVsb3ZhxaUgbWllcnUgbmV6YW1lc3RuYW5vc3RpIChVbmVtcGxveW1lbnRfUmF0ZSkgdiB6w6F2aXNsb3N0aSBvZCB0cm9jaCB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoLCBhIHRvIHJvxI1uw6lobyByYXN0dSBIRFAgKEdEUF9Hcm93dGhfQW5udWFsKSwgaW5mbMOhY2llIG1lcmFuZWogaW5kZXhvbSBDUEkgKEluZmxhdGlvbl9DUEkpIGEgdmVyZWpuw6lobyBkbGh1IChQdWJsaWNfRGVidCkuCgpWIHByw61wYWRlIEdEUF9Hcm93dGhfQW5udWFsIG/EjWFrw6F2YW1lIG5lZ2F0w612bnkgdnBseXYgKHZ5xaHFocOtIGhvc3BvZMOhcnNreSByYXN0IGJ5IG1hbCB2aWVzxaUgayBuacW+xaFlaiBuZXphbWVzdG5hbm9zdGkpLCB6YXRpYcS+IMSNbyB2IHByw61wYWRlIEluZmxhdGlvbl9DUEkgYSBQdWJsaWNfRGVidCBwcmVkcG9rbGFkw6FtZSBwb3ppdMOtdm55IHZwbHl2ICh2ecWhxaFpYSBpbmZsw6FjaWEgYSB2w6TEjcWhw60gdmVyZWpuw70gZGxoIGJ5IG1vaGxpIHPDunZpc2llxaUgcyB2ecWhxaFvdSBtaWVyb3UgbmV6YW1lc3RuYW5vc3RpKS4KCgojIFByw61wcmF2YSBkYXRhYsOhenksIMSNaXN0ZW5pZSBhIMO6cHJhdmEgw7pkYWpvdgoKYGBge3J9CnVkYWplIDwtIHJlYWQuY3N2MigiZGF0YS5jc3YiLGhlYWRlcj1UUlVFLHNlcD0iOyIsZGVjPSIuIikKaGVhZCh1ZGFqZSkKY29sbmFtZXModWRhamUpCmBgYApgYGB7cn0KdWRhamUgPC0gdWRhamVbLCBjKCJVbmVtcGxveW1lbnRfUmF0ZSIsICJHRFBfR3Jvd3RoX0FubnVhbCIsICJJbmZsYXRpb25fQ1BJIiwgIlB1YmxpY19EZWJ0IildCmBgYAoKClRlcmF6IGNoY2VtZSB2aWRpZcWlIHR2YXIgw7pkYWpvdiAoxI1pIG5pZSBzw7ogdiBuaWNoIG5lamFrw6kgbmV6cm92bmFsb3N0aSDigJMgbmFwcsOta2xhZCBob2Rub3R5IDApLgoKYGBge3J9CgpudW1fcGxvdHMgPC0gbGVuZ3RoKG5hbWVzKHVkYWplKSkKCnBhcihtZnJvdyA9IGMoMiwgMikpCnBhcihtYXIgPSBjKDQsIDQsIDIsIDEpKSAKCmZvciAoY29sIGluIG5hbWVzKHVkYWplKSkgewogIGJveHBsb3QodWRhamVbW2NvbF1dLCBtYWluID0gY29sLCB4bGFiID0gIkhvZG5vdGEiLCBjb2wgPSAibGlnaHRibHVlIikKfQoKbXRleHQoIkJveHBsb3R5IGplZG5vdGxpdsO9Y2ggcHJlbWVubsO9Y2ggKDIwMTDigJMyMDIyKSIsIG91dGVyID0gVFJVRSwgY2V4ID0gMS40LCBmb250ID0gMikKCgpwYXIobWZyb3cgPSBjKDEsIDEpKQpgYGAKCgojIyBMaW5lw6FybmEgcmVncmVzaWEKCk1vZGVsIG9kaGFkdWplbWUgcHLDrWthem9tICpsbSgpKgoKYGBge3J9Cm1vZGVsIDwtIGxtKFVuZW1wbG95bWVudF9SYXRlIH4gR0RQX0dyb3d0aF9Bbm51YWwgKyBJbmZsYXRpb25fQ1BJICsgUHVibGljX0RlYnQsZGF0YSA9IHVkYWplKQpgYGAKCk9iamVrdCB0cmllZHkgKmxtKCkqIG7DoW0gcG9za3l0dWplIG5pZWtvxL5rbyB2w71zbGVka292OgoKMS4gVmVjdG9yIG9kaGFkbnV0w71jaCBrb2VmaWNpZW50b3YgKm1vZGVsJGNvZWZmaWNpZW50cyoKMi4gVmVrdG9yIHJlesOtZHXDrSAqbW9kZWwkIHJlc2lkdWFscyoKMy4gVmVrdG9yIHZ5cm92bmFuw71jaCBob2Ruw7R0IHZ5c3ZldMS+b3ZhbmVqIHZlbGnEjWlueSAqbW9kZWwkZml0dGVkLnZhbHVlcyoKNC4gTWF0aWN1IFggKm1vZGVsJHgqCgpgYGB7cn0KCnByaW50KG1vZGVsJGNvZWZmaWNpZW50cykKcHJpbnQobW9kZWwkcmVzaWR1YWxzKQpwcmludChtb2RlbCRmaXR0ZWQudmFsdWVzKQpwcmludChtb2RlbC5tYXRyaXgobW9kZWwpKQpYIDwtIG1vZGVsLm1hdHJpeChtb2RlbCkKZGlhZyhYICUqJSBzb2x2ZSh0KFgpICUqJSBYKSAlKiUgdChYKSkKCnN1bW1hcnkobW9kZWwpCgpgYGAKCmBgYHtyIGRpYWdwbG90cywgZmlnLmNhcD0iRGlhZ25vc3RpY2vDqSBncmFmeSByZWdyZXNuw6lobyBtb2RlbHUgbmV6YW1lc3RuYW5vc3RpIn0KcGFyKG1mcm93ID0gYygyLCAyKSkKCnBsb3QobW9kZWwpCgptdGV4dCgiRGlhZ25vc3RpY2vDqSBncmFmeSByZWdyZXNuw6lobyBtb2RlbHUiLCBvdXRlciA9IFRSVUUsIGNleCA9IDEuMSwgZm9udCA9IDIpCgpwYXIobWZyb3cgPSBjKDEsIDEpKQpgYGAKCiMjIFJlc2lkdWFscyB2cy4gZml0dGVkCgojIyMgSW50ZXJwcmV0w6FjaWEgZ3JhZnUKCk5hIGdyYWZlIHZpZMOtbWUsIMW+ZSByZXppZHXDoWx5IHNhIHBvaHlidWrDuiBwcmlibGnFvm5lIG9rb2xvIG51bG92ZWogb3NpLCDEjW8gbmF6bmHEjXVqZSwgxb5lIG1vZGVsIGplIGRvYnJlIGNlbnRyb3ZhbsO9IGEgbmVtw6EgdsO9cmF6bsOpIHN5c3RlbWF0aWNrw6kgc2tyZXNsZW5pZSB2IHByZWRpa2Npw6FjaC4gUm96cHR5bCByZXrDrWR1w60gamUgcmVsYXTDrXZuZSByb3Zub21lcm7DvSBuYXByaWXEjSByb3pzYWhvbSBwcmlzcMO0c29iZW7DvWNoIGhvZG7DtHQsIMSNbyBwb2Rwb3J1amUgcHJlZHBva2xhZCBob21vc2tlZGFzdGljaXR5IChrb27FoXRhbnRuZWogdmFyaWFiaWxpdHkgY2jDvWIpLiDEjGVydmVuw6EgaGxhZGvDoSDEjWlhcmEgamUgbWllcm5lIHpha3JpdmVuw6Eg4oCTIHVwcm9zdHJlZCBzbWVydWplIG5haG9yIGEgbmEgcHJhdm9tIG9rcmFqaSBtaWVybmUgbmFkb2wg4oCTIMSNbyBtw7TFvmUgbmF6bmHEjW92YcWlIHByw610b21ub3PFpSBuZWxpbmXDoXJuZWhvIHZ6xaVhaHUsIGt0b3LDvSBsaW5lw6FybnkgbW9kZWwgbmV6YWNoeXTDoXZhIMO6cGxuZSBwcmVzbmUuIE5pZWtvxL5rbyBib2RvdiAobmFwcsOta2xhZCBzIG96bmHEjWVuw61tIDksIDEwIGFsZWJvIDQpIHNhIG9kY2h5xL51amUgb2QgenZ5xaFrdSwgxI1vIG3DtMW+ZSB6bmFtZW5hxaUgcHLDrXRvbW5vc8WlIG9kxL5haGzDvWNoIGFsZWJvIHZwbHl2bsO9Y2ggcG96b3JvdmFuw60sIGt0b3LDqSBieSBtb2hsaSBvdnBseXZuacWlIHbDvXNsZWRreSBtb2RlbHUuCgoKIyMgUS1RIHBsb3QKCiMjIyDEjG8gdWthenVqZSAmIGludGVycHJldMOhY2lhIGdyYWZ1CgpOYSBncmFmZSBRLVEgUmVzaWR1YWxzIHBvcm92bsOhdmFtZSB0ZW9yZXRpY2vDqSBrdmFudGlseSBub3Jtw6FsbmVobyByb3pkZWxlbmlhIChvcyBYKSBzbyBza3V0b8SNbsO9bWkgxaF0YW5kYXJkaXpvdmFuw71taSByZXrDrWR1YW1pIG1vZGVsdSAob3MgWSkuIFbDpMSNxaFpbmEgYm9kb3YgbGXFvsOtIGJsw616a28gcHJlcnXFoW92YW5laiA0NcKwIMSNaWFyeSwgxI1vIHpuYW1lbsOhLCDFvmUgcmV6w61kdcOhIHPDuiBwcmlibGnFvm5lIG5vcm3DoWxuZSByb3psb8W+ZW7DqSBhIHByZWRwb2tsYWQgbm9ybWFsaXR5IGplIHZvIHbFoWVvYmVjbm9zdGkgc3BsbmVuw70uIFYgc3RyZWRuZWogxI1hc3RpIGdyYWZ1IChtZWR6aSBrdmFudGlsbWkgcHJpYmxpxb5uZSDiiJIxIGEgKzEpIGplIHpob2RhIHZlxL5taSBkb2Jyw6EsIMSNbyBuYXpuYcSNdWplLCDFvmUgdsOkxI3FoWluYSBob2Ruw7R0IHNhIHNwcsOhdmEgcG9kxL5hIG/EjWFrw6F2YW5pYS4gTmFvcGFrLCBrb25jb3bDqSBib2R5ICh2xL5hdm8gZG9sZSBhIHZwcmF2byBob3JlKSBzYSBtaWVybmUgb2RjaHnEvnVqw7ogb2QgcHJpYW1reSwgxI1vIHBvdWthenVqZSBuYSBtaWVybmUgb2RjaMO9bGt5IG9kIG5vcm1hbGl0eSB2IGV4dHLDqW1vY2gg4oCTIG5hcHLDrWtsYWQgcHLDrXRvbW5vc8WlIG5pZWtvxL5rw71jaCBvZMS+YWhsw71jaCBob2Ruw7R0IGFsZWJvIG8gbmllxI1vIMWlYcW+xaFpZSBjaHZvc3R5IHJvemRlbGVuaWEuIENlbGtvdm8gZ3JhZiB1a2F6dWplLCDFvmUgcm96ZGVsZW5pZSByZXrDrWR1w60gamUgcG9tZXJuZSBibMOtemtlIG5vcm3DoWxuZW11LCBwcmnEjW9tIGRyb2Juw6kgb2RjaMO9bGt5IHYga3Jham7DvWNoIGhvZG5vdMOhY2ggbmllIHPDuiB2w71yYXpuw6kuCgojIyBTY2FsZSBsb2NhdGlvbiBwbG90CgojIyMgxIxvIHRvIHpuw6F6b3LFiHVqZSAmIGludGVycHJldMOhY2lhIGdyYWZ1CgpOYSBncmFmZSBTY2FsZS1Mb2NhdGlvbiBwb3pvcnVqZW1lLCDFvmUgYm9keSBzw7ogcG9tZXJuZSByb3Zub21lcm5lIHJvenB0w71sZW7DqSBwb3pkxLrFviBvc2kgWCAoZml0dGVkIHZhbHVlcyksIGJleiB6amF2bsOpaG8gdHZhcnUgbGlldmlrYSBhbGVibyBpbsOpaG8gc3lzdGVtYXRpY2vDqWhvIHZ6b3J1LiBUbyBuYXpuYcSNdWplLCDFvmUgdmFyaWFuY2lhIHJlesOtZHXDrSBqZSBwcmlibGnFvm5lIGtvbsWhdGFudG7DoSwgdGVkYSBtb2RlbCBzcMS6xYhhIHByZWRwb2tsYWQgaG9tb3NrZWRhc3RpY2l0eS4gxIxlcnZlbsOhIGhsYWRrw6EgxI1pYXJhIGplIHJlbGF0w612bmUgcm92bsOhLCDEjW8gcG90dnJkenVqZSwgxb5lIHByaSByYXN0w7pjaWNoIHByZWRpa292YW7DvWNoIGhvZG5vdMOhY2ggc2Egcm96cHR5bCBjaMO9YiB2w71yYXpuZSBuZW1lbsOtLiBOaWVrb8S+a28gYm9kb3Ygc2Egc8OtY2UgbmFjaMOhZHphIG1pZXJuZSB2ecWhxaFpZSAobmFkIGhvZG5vdG91IDEpLCBhbGUgbmVqZGUgbyBleHRyw6ltbmUgb2RjaMO9bGt5IOKAkyB0ZWRhIG1vZGVsIG5lcHJlamF2dWplIHrDoXZhxb5uw6kgcHJvYmzDqW15IHMgaGV0ZXJvc2tlZGFzdGljaXRvdS4gQ2Vsa292byBncmFmIG5hem5hxI11amUsIMW+ZSByb3pwdHlsIGNow71iIGplIHN0YWJpbG7DvSBhIG1vZGVsIG3DoSB6IHRvaHRvIGjEvmFkaXNrYSBkb2Jyw6kgdmxhc3Rub3N0aS4KCiMjIFJlc2lkdWFscyB2cyBsZXZlcmFnZQoKIyMjIMSMbyB6bsOhem9yxYh1amUgJiBpbnRlcnByZXTDoWNpYSBncmFmdQoKTmEgZ3JhZmUgUmVzaWR1YWxzIHZzIExldmVyYWdlIHZpZMOtbWUsIGFrbyBqZWRub3RsaXbDqSBwb3pvcm92YW5pYSBvdnBseXbFiHVqw7ogb2RoYWRudXTDvSByZWdyZXNuw70gbW9kZWwuIFbDpMSNxaFpbmEgYm9kb3Ygc2EgbmFjaMOhZHphIHbEvmF2bywgcyBuw616a3ltaSBob2Rub3RhbWkgcMOha292w6lobyBlZmVrdHUgKGxldmVyYWdlIHBvZCAwLDIpLCDEjW8gbmF6bmHEjXVqZSwgxb5lIHbDpMSNxaFpbmEgcG96b3JvdmFuw60gbcOhIGxlbiBtYWzDvSB2cGx5diBuYSBtb2RlbCDigJMgdGVkYSBzw7ogZG9icmUgdnl2w6HFvmVuw6kgYSBuZW92cGx5dsWIdWrDuiB2w71yYXpuZSBzbWVybmljdSByZWdyZXNuZWogcHJpYW1reS4gxaB0YW5kYXJkaXpvdmFuw6kgcmV6w61kdcOhIHNhIHByaXRvbSBwb2h5YnVqw7ogcHJldmHFvm5lIHYgcm96bWVkesOtIG9kIOKIkjIgZG8gKzIsIMSNbyBqZSBiZcW+bsOpIGEgbmVpbmRpa3VqZSBwcsOtdG9tbm9zxaUgZXh0csOpbW55Y2ggb2RjaMO9bG9rLgoKTmlla2/EvmtvIGJvZG92IChuYXByw61rbGFkIG96bmHEjWVuw6kgYWtvIDQsIDEwLCAxMikgbcOhIG1pZXJuZSB2ecWhxaFpdSBob2Rub3R1IHDDoWtvdsOpaG8gZWZla3R1IOKAkyBpZGUgbyBwb3pvcm92YW5pYSBzIHBvdGVuY2nDoWxuZSB2ecWhxaHDrW0gdnBseXZvbSwgbm8gcG9kxL5hIGtvbnTDunIgQ29va292ZWogdnpkaWFsZW5vc3RpIMW+aWFkbmUgeiBuaWNoIG5lcHJla3JhxI11amUga3JpdGlja8OpIGhyYW5pY2UgKOKJiDAsNSBhbGVibyAxLDApLiBUbyB6bmFtZW7DoSwgxb5lIMW+aWFkbmUgcG96b3JvdmFuaWUgbmVvdnBseXbFiHVqZSBtb2RlbCBuZXByaW1lcmFuZSBzaWxuby4gxIxlcnZlbsOhIGhsYWRrw6EgxI1pYXJhIGplIHBvbWVybmUgcGxvY2jDoSwgxI1vIG5hem5hxI11amUsIMW+ZSBuZWV4aXN0dWplIHN5c3RlbWF0aWNrw70gdnpvcmVjIHYgcmV6w61kdcOhY2ggdiB6w6F2aXNsb3N0aSBvZCBww6Frb3bDqWhvIGVmZWt0dS4gQ2Vsa292byBncmFmIHBvdHZyZHp1amUsIMW+ZSBtb2RlbCBqZSBzdGFiaWxuw70sIGJleiB2w71yYXpuZSB2cGx5dm7DvWNoIGFsZWJvIHByb2JsZW1hdGlja8O9Y2ggYm9kb3YuCgoKYGBge3J9CiMgbm9ybWFsaXR5IHRlc3RzCnJlc2lkdWFscyA8LSByZXNpZHVhbHMobW9kZWwpCmpiX3Rlc3QgPC0gamFycXVlLmJlcmEudGVzdChyZXNpZHVhbHMpCmpiX3Rlc3QKIyBvdXRsaWVyIHRlc3QgKHNlZSBwLXZhbHVlIGZvciBCb25mZXJyb25pIGNvcnJlY3Rpb24pCm91dGxpZXJfdGVzdCA8LSBvdXRsaWVyVGVzdChtb2RlbCkKb3V0bGllcl90ZXN0CmBgYAoKS2XEj8W+ZSBzYSBuZXByZXVrw6F6YWxhIHByw610b21ub3PFpSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvWNoIG9kxL5haGzDvWNoIGhvZG7DtHQgKHBvem9yb3ZhbmllIDEwIG3DoSBzw61jZSB2ecWhxaFpZSByZXrDrWR1dW0sIGFsZSBwLWhvZG5vdGEgMCwwNzgzID4gMCwwNSksIG5pZSBqZSBwb3RyZWJuw6kgZWxpbWlub3ZhxaUgxb5pYWRuZSBwb3pvcm92YW5pYSBhbmkgdHJhbnNmb3Jtb3ZhxaUgcHJlbWVubsOpLiBNb2RlbCBqZSB6IHRvaHRvIGjEvmFkaXNrYSBzdGFiaWxuw70uCgoKIyMgQ29uY2x1c2lvbgoKUHJlbWVubsOpIEdEUF9Hcm93dGhfQW5udWFsLCBJbmZsYXRpb25fQ1BJIGEgUHVibGljX0RlYnQgxaF0YXRpc3RpY2t5IHbDvXpuYW1uZSBvdnBseXbFiHVqw7ogbWllcnUgbmV6YW1lc3RuYW5vc3RpIHYgcm9rb2NoIDIwMTAtMjAyMi4gUmV6w61kdcOhIG1vZGVsdSBzw7ogcHJpYmxpxb5uZSBub3Jtw6FsbmUgcm96bG/FvmVuw6kgYSBuZWJvbGkgemlzdGVuw6kgxb5pYWRuZSB2w716bmFtbsOpIG9kxL5haGzDqSBob2Rub3R5LiBNb2RlbCBuZXZ5a2F6dWplIHpuw6Fta3kgaGV0ZXJvc2tlZGFzdGljaXR5IGFuaSBuZWxpbmVhcml0eSwgcHJldG8gaG8gbcO0xb5lbWUgcG92YcW+b3ZhxaUgemEgdmhvZG7DvSBuYSBpbnRlcnByZXTDoWNpdS4KCgoKIyMgSGV0ZXJvc2tlZGFzdGljaXRhCgpQcsOtdG9tbm9zxaUgaGV0ZXJvc2tlZGFzdGljaXR5IChuZWtvbsWhdGFudG7DqWhvIHJvenB0eWx1IG7DoWhvZG5laiB6bG/Fvmt5KSBzcMO0c29idWplIG5lc3BvxL5haGxpdsOpIHZ5aG9kbm9jb3ZhbmllIHQtdGVzdG92IHbDvXpuYW1ub3N0aSBqZWRub3RsaXbDvWNoIHJlZ3Jlc27DvWNoIGtvZWZpY2llbnRvdi4gUHJldG8gamUgcG90cmVibsOpLCBhYnkgc21lIGhldGVyb3NrZWRhc3RpY2l0dQoKLWRldGVnb3ZhbGkgKHZpenXDoWxuZSBhIHBvbW9jb3UgdGVzdG92KSwKCi1hIHYgcHLDrXBhZGUgamVqIHByw610b21ub3N0aSBzYSBqdSBwb2vDunNpbGkgb2RzdHLDoW5pxaUuCgpBaiB2IG5hxaFvbSBwcsOtcGFkZSBzYSBwb2vDunNpbWUgbyB2aXp1w6FsbmUgdnlob2Rub3RlbmllIGhldGVyb3NrZWRhc3RpY2l0eSBuYSB6w6FrbGFkZSBkaWFnbm9zdGlja8O9Y2ggZ3JhZm92LgoKVGVudG9rcsOhdCBzYSB6YW1lcmlhbWUgbmEgem7DoXpvcm5lbmllIHrDoXZpc2xvc3RpIMWhdHZvcmNvdiByZXrDrWR1w60gb2QgdnlzdmV0xL51asO6Y2VqIHByZW1lbm5laiwgcHJpIGt0b3JlaiBleGlzdHVqZSBwb2RvenJlbmllLCDFvmUgYnkgbW9obGEgaGV0ZXJvc2tlZGFzdGljaXR1IHNww7Rzb2JvdmHFpS4KClYgbmHFoW9tIG1vZGVsaSBtw7TFvmUgYnnFpSB0YWtvdXRvIHByZW1lbm5vdSBuYWptw6QgKkdEUF9Hcm93dGhfQW5udWFsKiwga2XEj8W+ZSBla29ub21pY2vDvSByYXN0IGLDvXZhIMSNYXN0byBzcG9qZW7DvSBzIHZ5xaHFoW91IHZhcmlhYmlsaXRvdSBtaWVyeSBuZXphbWVzdG5hbm9zdGkuCgpCdWRlbWUgdGVkYSBwb3Jvdm7DoXZhxaUgZHZhIG1vZGVseToKCnDDtHZvZG7DvSBtb2RlbCAobW9kZWwpLAoKYSBwcsOtcGFkbmUgdXByYXZlbsO9IG1vZGVsIChtb2RlbDIpLCBrdG9yw70gYnkgbW9ob2wgb2JzYWhvdmHFpSB0cmFuc2Zvcm1vdmFuw7ogcG9kb2J1IHByZW1lbm5laiAobmFwci4gbG9nKEdEUF9Hcm93dGhfQW5udWFsKSksIGFrIGJ5IHNhIGhldGVyb3NrZWRhc3RpY2l0YSBwb3R2cmRpbGEuCgpgYGB7ciBoZXRlcm9wbG90czEsIGZpZy5jYXA9IlNrw7ptYW5pZSBoZXRlcm9za2VkYXN0aWNpdHkiLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NH0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBhdGNod29yaykgICMgaW5zdGFsbC5wYWNrYWdlcygicGF0Y2h3b3JrIikKCnAxIDwtIGdncGxvdCh1ZGFqZSwgYWVzKHggPSBHRFBfR3Jvd3RoX0FubnVhbCwgeSA9IHJlc2lkKG1vZGVsKV4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQiKSArCiAgbGFicyh4ID0gIkdEUCBHcm93dGggKEFubnVhbCkiLCAKICAgICAgIHkgPSAiU3F1YXJlZCBSZXNpZHVhbHMiLAogICAgICAgdGl0bGUgPSAiU3F1YXJlZCBSZXNpZHVhbHMgdnMgR0RQIEdyb3d0aCIpICsKICB0aGVtZV9taW5pbWFsKCkKCnAyIDwtIGdncGxvdCh1ZGFqZSwgYWVzKHggPSBJbmZsYXRpb25fQ1BJLCB5ID0gcmVzaWQobW9kZWwpXjIpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHggPSAiSW5mbGF0aW9uIChDUEkpIiwgCiAgICAgICB5ID0gIlNxdWFyZWQgUmVzaWR1YWxzIiwKICAgICAgIHRpdGxlID0gIlNxdWFyZWQgUmVzaWR1YWxzIHZzIEluZmxhdGlvbiIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgQ29tYmluZSBzaWRlIGJ5IHNpZGUKcDEgKyBwMgpgYGAKTmEgZ3JhZmUgU3F1YXJlZCBSZXNpZHVhbHMgdnMgR0RQIEdyb3d0aCAoQW5udWFsKSBtw7TFvmVtZSBwb3pvcm92YcWlIG1pZXJuZSBrb2zDrXNhbmllIMSNZXJ2ZW5laiB2eWhsYWRlbmVqIGtyaXZreSwga3RvcsOhIG5hem5hxI11amUsIMW+ZSByb3pwdHlsIHJlesOtZHXDrSBzYSBtZW7DrSBzIGhvZG5vdGFtaSBHRFAgR3Jvd3RoLiBOYWptw6QgdiBzdHJlZG5laiDEjWFzdGkgKG9rb2xvIDLigJMzICUpIGplIHZpZGl0ZcS+bsO9IHZ5xaHFocOtIHJvenB0eWwsIHphdGlhxL4gxI1vIG5hIGtyYWpvY2ggcm96cHR5bCBrbGVzw6EuIFRvIG3DtMW+ZSBuYXpuYcSNb3ZhxaUgbWllcm51IHByw610b21ub3PFpSBoZXRlcm9za2VkYXN0aWNpdHkuCk5hIGdyYWZlIFNxdWFyZWQgUmVzaWR1YWxzIHZzIEluZmxhdGlvbiAoQ1BJKSBqZSDEjWVydmVuw6Ega3JpdmthIHbDvXJhem5lIHpha3JpdmVuw6Eg4oCTIHJvenB0eWwgcmV6w61kdcOtIHNhIHpqYXZuZSBtZW7DrSB2IHrDoXZpc2xvc3RpIG9kIGluZmzDoWNpZSwgbmFqbcOkIHByaSBuacW+xaHDrWNoIGEgc3RyZWRuw71jaCBob2Rub3TDoWNoLiBUbyBuYXpuYcSNdWplLCDFvmUgaW5mbMOhY2lhIG3DtMW+ZSBwcmlzcGlldmHFpSBrIG5la29uxaF0YW50bsOpbXUgcm96cHR5bHUgbsOhaG9kbmVqIHpsb8W+a3kuCgphIHRlcmF6IG1vZGVsIHNvIHpsb2dhcml0bWl6b3Zhbm91IHByZW1lbm5vdSAqR0RQX0dyb3d0aF9Bbm51YWwqLgoKYGBge3IgaGV0ZXJvcGxvdHMyLCBmaWcuY2FwPSJTa8O6bWFuaWUgaGV0ZXJvc2tlZGFzdGljaXR5IiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTR9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspICAKCnAxIDwtIGdncGxvdCh1ZGFqZSwgYWVzKHggPSBsb2coR0RQX0dyb3d0aF9Bbm51YWwpLCB5ID0gcmVzaWQobW9kZWwyKV4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQiKSArCiAgbGFicyh4ID0gImxvZyhHRFAgR3Jvd3RoIEFubnVhbCkiLCAKICAgICAgIHkgPSAiU3F1YXJlZCBSZXNpZHVhbHMiLAogICAgICAgdGl0bGUgPSAiU3F1YXJlZCBSZXNpZHVhbHMgdnMgbG9nKEdEUCBHcm93dGgpIikgKwogIHRoZW1lX21pbmltYWwoKQoKcDIgPC0gZ2dwbG90KHVkYWplLCBhZXMoeCA9IEluZmxhdGlvbl9DUEksIHkgPSByZXNpZChtb2RlbDIpXjIpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHggPSAiSW5mbGF0aW9uIChDUEkpIiwgCiAgICAgICB5ID0gIlNxdWFyZWQgUmVzaWR1YWxzIiwKICAgICAgIHRpdGxlID0gIlJlc2lkdWFscyB2cyBJbmZsYXRpb24iKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIENvbWJpbmUgc2lkZSBieSBzaWRlCnAxICsgcDIKYGBgCgpQbyBsb2dhcml0bWlja2VqIHRyYW5zZm9ybcOhY2lpIEdEUCBHcm93dGggc2EgxI1lcnZlbsOhIGtyaXZrYSBuYSBncmFmZSBTcXVhcmVkIFJlc2lkdWFscyB2cyBsb2coR0RQIEdyb3d0aCkgc3TDoXZhIHBseW51bGVqxaFvdSBhIGJleiB2w71yYXpuw6lobyB0cmVuZHUuIFZhcmlhbmNpYSByZXrDrWR1w60gc2EgamF2w60gYWtvIHJvdm5vbWVybmVqxaFpYSB2IGNlbG9tIHJvenNhaHUgaG9kbsO0dCwgxI1vIG5hem5hxI11amUsIMW+ZSB0cmFuc2Zvcm3DoWNpYSBwb21vaGxhIHptaWVybmnFpSBoZXRlcm9za2VkYXN0aWNpdHUgc3BvamVuw7ogcyBHRFAgR3Jvd3RoLgpOYSBkcnVoZWogc3RyYW5lLCB2esWlYWggbWVkemkgxaF0dm9yY2FtaSByZXrDrWR1w60gYSBJbmZsYXRpb24gKENQSSkgem9zdMOhdmEgcG9kb2Juw70g4oCTIGFqIHBvIHRyYW5zZm9ybcOhY2lpIG1vxb5ubyBwb3pvcm92YcWlIGlzdMOpIGtvbMOtc2FuaWUgcm96cHR5bHUsIHRha8W+ZSBpbmZsw6FjaWEgbcO0xb5lIGJ5xaUgYWogbmHEj2FsZWogemRyb2pvbSBtaWVybmVqIGhldGVyb3NrZWRhc3RpY2l0eS4KClRyYW5zZm9ybcOhY2lhIEdEUCBHcm93dGggcG9tb2NvdSBsb2dhcml0bXUgdGVkYSBwb21vaGxhIHN0YWJpbGl6b3ZhxaUgcm96cHR5bCByZXrDrWR1w60gdiBtb2RlbGkuIE5hcHJpZWsgdG9tdSBtaWVybmUgem7DoW1reSBoZXRlcm9za2VkYXN0aWNpdHkgbcO0xb51IHByZXRydsOhdmHFpSwgbmFqbcOkIHYgc8O6dmlzbG9zdGkgcyBwcmVtZW5saXZvdSBpbmZsw6FjaW91LiBDZWxrb3ZvIHbFoWFrIG5vdsO9IG1vZGVsIChtb2RlbDIpIHZ5a2F6dWplIGxlcMWhaXUgxaF0cnVrdMO6cnUgcmV6w61kdcOtIGEgem7DrcW+ZW7DuiB2YXJpYWJpbGl0dS4KCiMjIFRlc3RvdmFuaWUgcHLDrXRvbW5vc3RpIGhldGVyb3NrZWRhc3RpY2l0eQpgYGB7cn0KIyBJbnN0YWxsIChpZiBub3QgeWV0IGluc3RhbGxlZCkKIyBpbnN0YWxsLnBhY2thZ2VzKCJsbXRlc3QiKQoKIyBMb2FkIHRoZSBwYWNrYWdlCmxpYnJhcnkobG10ZXN0KQoKIyBSdW4gdGhlIEJyZXVzY2jigJNQYWdhbiB0ZXN0CmJwdGVzdChtb2RlbCkKCmBgYAoKYGBge3J9CiMgSW5zdGFsbCAoaWYgbm90IHlldCBpbnN0YWxsZWQpCiMgaW5zdGFsbC5wYWNrYWdlcygibG10ZXN0IikKCiMgTG9hZCB0aGUgcGFja2FnZQpsaWJyYXJ5KGxtdGVzdCkKCiMgUnVuIHRoZSBCcmV1c2No4oCTUGFnYW4gdGVzdApicHRlc3QobW9kZWwyKQoKYGBgCktlxI/FvmUgcC1ob2Rub3RhIGplIHbDvXJhem5lIHZ5xaHFoWlhIGFrbyBiZcW+bsOhIGhsYWRpbmEgdsO9em5hbW5vc3RpICgwLjA1KSwgbmV6YW1pZXRhbWUgbnVsb3bDuiBoeXBvdMOpenUgbyBob21vc2tlZGFzdGljaXRlLiBUbyB6bmFtZW7DoSwgxb5lIHYgbmHFoW9tIG1vZGVsaSBuaWUgamUgcHLDrXRvbW7DoSBoZXRlcm9za2VkYXN0aWNpdGEg4oCTIHJvenB0eWwgcmV6w61kdcOtIHNhIGphdsOtIGFrbyBrb27FoXRhbnRuw70uCgpOYSB6w6FrbGFkZSB2aXp1w6FsbmVobyBwb3PDumRlbmlhIGdyYWZvdiBhIHbDvXNsZWRrdSBCcmV1c2No4oCTUGFnYW5vdmhvIHRlc3R1IChwLWhvZG5vdGEgPSAwLjk3ODQpIG3DtMW+ZW1lIGtvbsWhdGF0b3ZhxaUsIMW+ZSBoZXRlcm9za2VkYXN0aWNpdGEgdiByZXrDrWR1w6FjaCBuaWUgamUgcHLDrXRvbW7DoS4gUHJldG8gbmllIGplIHBvdHJlYm7DqSBhcGxpa292YcWlIFdoaXRlb3Z1IGtvcmVrY2l1IGFuaSDEj2FsxaFpZSDDunByYXZ5IG1vZGVsdS4=