Úvod a popis databázy
V tejto časti sa testujú štatistické hypotézy pomocou údajov z
databázy, ktorá obsahuje ekonomické ukazovatele krajín v rokoch 1991 –
2022. Použité premenné zahŕňajú hrubý domáci produkt (HDP) v USD, mieru
nezamestnanosti (%) a štruktúru zamestnanosti v troch sektoroch –
poľnohospodárstve, priemysle a službách.
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/zoo_1.8-14.tar.gz'
Content type 'application/x-gzip' length 1018553 bytes (994 KB)
==================================================
downloaded 994 KB
The downloaded source packages are in
‘/tmp/RtmpwcuBmf/downloaded_packages’
install.packages("tseries")
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/xts_0.14.1.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/TTR_0.24.4.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/quadprog_1.5-8.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/quantmod_0.4.28.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/tseries_0.10-58.tar.gz'
The downloaded source packages are in
‘/tmp/RtmpwcuBmf/downloaded_packages’
install.packages("lmtest")
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/lmtest_0.9-40.tar.gz'
Content type 'application/x-gzip' length 399624 bytes (390 KB)
==================================================
downloaded 390 KB
The downloaded source packages are in
‘/tmp/RtmpwcuBmf/downloaded_packages’
install.packages("sandwich")
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/sandwich_3.1-1.tar.gz'
Content type 'application/x-gzip' length 1505348 bytes (1.4 MB)
==================================================
downloaded 1.4 MB
The downloaded source packages are in
‘/tmp/RtmpwcuBmf/downloaded_packages’
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/rbibutils_2.3.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/cowplot_1.2.0.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/Deriv_4.2.0.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/modelr_0.1.11.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/microbenchmark_1.5.0.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/Rdpack_2.6.4.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/numDeriv_2016.8-1.1.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/doBy_4.7.0.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/SparseM_1.84-2.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/MatrixModels_0.5-4.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/minqa_1.2.8.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/nloptr_2.2.1.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/reformulas_0.4.2.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/RcppEigen_0.3.4.0.2.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/carData_3.0-5.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/abind_1.4-8.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/Formula_1.2-5.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/pbkrtest_0.5.5.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/quantreg_6.1.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/lme4_1.1-37.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/car_3.1-3.tar.gz'
The downloaded source packages are in
‘/tmp/RtmpwcuBmf/downloaded_packages’
library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)
rm(list=ls())
install.packages("knitr")
install.packages("dplyr")
install.packages("ggplot2")
# Import vlastného CSV súboru
udaje <- read.csv("Employment_Unemployment_GDP_data.csv",
header = TRUE,
sep = ",",
dec = " ",
stringsAsFactors = FALSE)
# Zobrazenie prvých riadkov a názvov stĺpcov
head(udaje)
[1] "Country.Name" "Year"
[3] "Employment.Sector..Agriculture" "Employment.Sector..Industry"
[5] "Employment.Sector..Services" "Unemployment.Rate"
[7] "GDP..in.USD."
Úvod do problému, stanovenie hypotéz
Rozhodla som sa modelovať mieru nezamestnanosti
(Unemployment.Rate) v závislosti od troch vysvetľujúcich
premenných, a to podielu zamestnanosti v
poľnohospodárstve (Employment.Sector..Agriculture),
podielu zamestnanosti v priemysle
(Employment.Sector..Industry) a hrubého domáceho
produktu na obyvateľa (GDP..in.USD.).
Naša pracovná hypotéza hovorí o štatisticky významnom
vplyve všetkých troch vysvetľujúcich premenných, pričom:
- u premennej Industry predpokladáme
negatívny vplyv, to znamená čím väčší podiel
pracujúcich v priemysle, tým nižšia nezamestnanosť,
- u premennej GDP očakávame negatívny
vplyv, vyšší HDP na obyvateľa je spojený s lepšou ekonomickou
výkonnosťou a teda nižšou nezamestnanosťou,
- u premennej Agriculture predpokladáme
pozitívny alebo nejednoznačný vplyv, vo vyspelých
ekonomikách nižší podiel poľnohospodárstva súvisí s nižšou
nezamestnanosťou, zatiaľ čo vo vyvíjajúcich sa krajinách môže byť efekt
opačný.
Príprava databázy, čistenie a úprava údajov
Budeme pracovať s vlastným súborom
Employment_Unemployment_GDP_data.csv. Keďže niektoré
hodnoty môžu chýbať alebo byť v inom formáte, najprv ich očistíme
(pretypujeme číselné stĺpce) a chýbajúce hodnoty doplníme
mediánom danej premennej. Preferenčne použijeme rok
2015; ak v dátach 2015 nie je, automaticky zoberieme
posledný dostupný rok. Na ďalšie kroky si ponecháme
kľúčové premenné: Unemployment.Rate,
Employment.Sector..Agriculture,
Employment.Sector..Industry,
Employment.Sector..Services a GDP..in.USD..
# Robustná príprava: automatické namapovanie názvov stĺpcov + imputácia mediánom
# 0) Načítanie (ponechaj check.names = FALSE, aby sa nemenili mená)
udaje <- read.csv(
"Employment_Unemployment_GDP_data.csv",
header = TRUE, sep = ",", dec = ".",
stringsAsFactors = FALSE, check.names = FALSE
)
# 1) Pomocné funkcie
find_col <- function(candidates, cols) {
# skúsi presnú zhodu (case-insensitive), potom 'obsahuje'
lc <- tolower(cols)
# presná zhoda
for (p in candidates) {
idx <- which(lc == tolower(p))
if (length(idx) == 1) return(cols[idx])
}
# obsahuje (regex/substring, case-insensitive)
for (p in candidates) {
idx <- grep(tolower(p), lc, fixed = TRUE)
if (length(idx) >= 1) return(cols[idx][1])
}
return(NA_character_)
}
num_clean <- function(x) {
if (is.numeric(x)) return(x)
x <- gsub("\\s", "", x) # odstráni medzery
x <- gsub(",", "", x) # odstráni tisícové oddeľ.
suppressWarnings(as.numeric(x))
}
# 2) Nájdeme požadované stĺpce (tolerantne na názvy)
cols <- colnames(udaje)
col_year <- find_col(c("Year","Rok"), cols)
col_unemp <- find_col(c("Unemployment.Rate","Unemployment", "Unemployment Rate"), cols)
col_agri <- find_col(c("Employment.Sector..Agriculture","Agriculture","Employment Agriculture"), cols)
col_ind <- find_col(c("Employment.Sector..Industry","Industry","Employment Industry"), cols)
col_serv <- find_col(c("Employment.Sector..Services","Services","Employment Services"), cols)
col_gdp <- find_col(c("GDP..in.USD.","GDP..in.USD","GDP per capita","GDP","gdp"), cols)
mapping <- c(
Year = col_year,
Unemployment.Rate = col_unemp,
Agriculture = col_agri,
Industry = col_ind,
Services = col_serv,
GDP_in_USD = col_gdp
)
cat("Mapovanie stĺpcov:\n")
Mapovanie stĺpcov:
Year Unemployment.Rate
"Year" "Unemployment Rate"
Agriculture Industry
"Employment Sector: Agriculture" "Employment Sector: Industry"
Services GDP_in_USD
"Employment Sector: Services" "GDP (in USD)"
# 3) Ošetri, ak sa niečo nenašlo
if (any(is.na(mapping))) {
stop("Niektoré stĺpce sa nenašli. Skontroluj mapovanie vyššie a prípadne uprav kandidátov.")
}
# 4) Pretypuj na numerické (kde treba)
for (cn in unique(c(col_year,col_unemp,col_agri,col_ind,col_serv,col_gdp))) {
if (cn %in% c(col_year,col_unemp,col_agri,col_ind,col_serv,col_gdp)) {
udaje[[cn]] <- num_clean(udaje[[cn]])
}
}
# 5) Vyber rok: 2015, inak posledný dostupný
target_year <- if (any(udaje[[col_year]] == 2015, na.rm = TRUE)) 2015 else max(udaje[[col_year]], na.rm = TRUE)
cat("Použitý rok:", target_year, "\n")
Použitý rok: 2015
# 6) Vyber kľúčové premenné pre daný rok
udaje.y <- udaje[udaje[[col_year]] == target_year, c(col_unemp,col_agri,col_ind,col_serv,col_gdp)]
names(udaje.y) <- c("Unemployment.Rate","Agriculture","Industry","Services","GDP_USD")
# 7) Imputácia mediánom
column_medians <- sapply(udaje.y, median, na.rm = TRUE)
for (col in names(udaje.y)) {
idx <- is.na(udaje.y[[col]])
if (any(idx)) udaje.y[[col]][idx] <- column_medians[col]
}
# 8) Hotovo – dataset pripravený na modelovanie
str(udaje.y)
'data.frame': 181 obs. of 5 variables:
$ Unemployment.Rate: num 9.05 17.19 11.21 16.49 7.58 ...
$ Agriculture : num 44.59 41.28 8.83 56.85 7.84 ...
$ Industry : num 20.7 18.7 31.2 7.8 22.3 ...
$ Services : num 34.7 40 59.9 35.4 69.8 ...
$ GDP_USD : num 1.91e+10 1.15e+10 1.87e+11 9.05e+10 5.95e+11 ...
Unemployment.Rate Agriculture Industry Services
Min. : 0.170 Min. : 0.2338 Min. : 3.465 Min. :10.22
1st Qu.: 3.678 1st Qu.: 5.3210 1st Qu.:14.514 1st Qu.:42.40
Median : 6.313 Median :18.1105 Median :19.555 Median :58.51
Mean : 8.127 Mean :25.0850 Mean :19.612 Mean :55.30
3rd Qu.:10.842 3rd Qu.:40.3543 3rd Qu.:24.458 3rd Qu.:69.15
Max. :27.695 Max. :86.3175 Max. :54.141 Max. :93.17
GDP_USD
Min. :2.600e+08
1st Qu.:1.139e+10
Median :4.130e+10
Mean :4.128e+11
3rd Qu.:1.951e+11
Max. :1.830e+13
Vizualizácia dát – kontrola nezrovnalostí
V tejto časti sa pozrieme na rozloženie jednotlivých premenných
pomocou boxplotov.
Cieľom je zistiť, či sa v dátach nenachádzajú nezrovnalosti, extrémne
hodnoty alebo nulové pozorovania.
Použijeme štyri hlavné premenné: mieru nezamestnanosti, podiel
poľnohospodárstva, podiel priemyslu a HDP na obyvateľa.
# Boxploty premenných – kontrola rozloženia a odľahlých hodnôt
# Zvolíme len relevantné premenné
vars_to_plot <- c("Unemployment.Rate","Agriculture","Industry","GDP_USD")
# Nastavenie grafického layoutu: 2 × 2
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1))
# Pre každý vybraný stĺpec nakreslíme boxplot
for (col in vars_to_plot) {
boxplot(
udaje.y[[col]],
main = col,
xlab = "Hodnota",
col = "lightblue",
border = "darkblue"
)
}
# Nadpis pre celú sadu grafov
mtext("Boxploty jednotlivých premenných (rok vybraný pre analýzu)",
outer = TRUE, cex = 1.2, font = 2)
# Reset layoutu na 1 graf
par(mfrow = c(1, 1))

Na základe boxplotov môžeme pozorovať nasledovné skutočnosti:
- Unemployment.Rate – väčšina pozorovaní sa
sústreďuje v stredných hodnotách, avšak v niektorých krajinách sa
vyskytujú aj extrémne vyššie miery nezamestnanosti. To naznačuje, že
medzi krajinami existujú výrazné rozdiely v trhu práce.
- Agriculture – hodnoty sa pohybujú v širokom
intervale. Krajiny s vyšším podielom poľnohospodárstva môžu mať nižšiu
úroveň industrializácie, čo sa často spája s vyššou
nezamestnanosťou.
- Industry – väčšina krajín má stredné až vyššie
hodnoty, pričom extrémne hodnoty sú menej časté. Vyšší podiel priemyslu
naznačuje rozvinutejšiu ekonomiku.
- GDP_USD – rozloženie ukazuje výrazné rozdiely v
ekonomickej úrovni medzi krajinami. Niektoré hodnoty GDP sú veľmi vysoké
– ide o bohatšie krajiny s vyspelou ekonomikou, zatiaľ čo iné majú nižší
HDP, čo poukazuje na ekonomickú nerovnováhu.
Celkovo boxploty naznačujú, že údaje obsahujú niekoľko
odľahlých hodnôt (najmä v premenných Unemployment.Rate
a GDP_USD), čo je však pri medzinárodných dátach prirodzené.
Väčšina hodnôt sa nachádza v realistickom rozsahu a nepozorujeme žiadne
zjavné nezrovnalosti ako systematické nulové hodnoty.
Tieto výsledky potvrdzujú, že údaje sú vhodné na ďalšie modelovanie.
Lineárna regresia
Model odhadujeme príkazom lm().
V našom prípade modelujeme mieru nezamestnanosti
(Unemployment.Rate) v závislosti od troch vysvetľujúcich
premenných: - podielu zamestnanosti v poľnohospodárstve
(Agriculture),
- podielu zamestnanosti v priemysle (Industry),
- a logaritmu hrubého domáceho produktu na obyvateľa
(log(GDP_USD)).
Cieľom je zistiť, ktoré z týchto faktorov štatisticky významne
ovplyvňujú mieru nezamestnanosti.
# Pridáme logaritmickú transformáciu HDP
udaje.y$logGDP <- ifelse(udaje.y$GDP_USD > 0, log(udaje.y$GDP_USD), NA_real_)
# Základný lineárny model
model <- lm(Unemployment.Rate ~ Agriculture + Industry + logGDP, data = udaje.y)
# Súhrn výsledkov
summary(model)
Call:
lm(formula = Unemployment.Rate ~ Agriculture + Industry + logGDP,
data = udaje.y)
Residuals:
Min 1Q Median 3Q Max
-9.314 -3.847 -1.469 2.371 18.219
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 30.08415 5.72158 5.258 4.16e-07 ***
Agriculture -0.09546 0.02569 -3.716 0.000272 ***
Industry -0.01164 0.07216 -0.161 0.872028
logGDP -0.78903 0.22480 -3.510 0.000569 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 5.775 on 177 degrees of freedom
Multiple R-squared: 0.1173, Adjusted R-squared: 0.1023
F-statistic: 7.839 on 3 and 177 DF, p-value: 6.094e-05
Diagnostické grafy regresného modelu
Súhrn odhadovaného modelu nám poskytuje súbor odhadnutých regresných
koeficientov, ktorých znamienka budú rozoberané neskôr.
Ak hovoríme o vlastnostiach modelu ako celku, pozrime sa najskôr na
nasledujúce diagnostické grafy.
Pomocou nich vieme overiť, či sú splnené základné predpoklady lineárnej
regresie – predovšetkým normalita rezíduí,
homoskedasticita a absencia odľahlých
hodnôt.
# Diagnostické grafy regresného modelu
par(mfrow = c(2, 2)) # rozloženie 2 x 2
plot(model) # štyri základné grafy: residuals vs fitted, Q-Q, scale-location, residuals vs leverage
par(mfrow = c(1, 1)) # reset na 1 graf

Interpretácia diagnostických grafov
1. Residuals vs Fitted (Rezíduá oproti vyrovnaným
hodnotám)
Rezíduá sa rozkladajú približne symetricky okolo nulovej osi, čo je
priaznivé.
Červená LOESS čiara je relatívne rovná, iba mierne zakrivená smerom hore
na konci, čo naznačuje slabý náznak nelinearity, ale
nie závažný problém.
Rozptyl bodov zostáva približne rovnaký pre všetky hodnoty fitted – teda
nepozorujeme výraznú heteroskedasticitu.
2. Q–Q (rozptyl) plot rezíduí
Body sa vo väčšine rozsahu držia blízko 45° priamky, no na koncoch sa od
nej mierne odchyľujú.
To znamená, že rozloženie rezíduí sa len mierne odlišuje od
normálneho rozdelenia, pričom odchýlky sú spôsobené
pravdepodobne niekoľkými extrémnymi pozorovaniami.
Celkovo však predpoklad normality nie je vážne porušený.
3. Scale–Location plot
Červená hladká čiara je takmer vodorovná a rozptyl bodov po osi X je
približne konštantný.
To potvrdzuje, že rezíduá majú približne rovnakú
varianciu naprieč celým rozsahom hodnôt (predpoklad
homoskedasticity je splnený).
4. Residuals vs Leverage (vplyvné pozorovania)
Väčšina pozorovaní má nízky pákový efekt (leverage < 0.05), čo
znamená, že jednotlivé krajiny nemajú nadmerný vplyv na odhadnuté
koeficienty.
Niekoľko bodov (napr. s označením 4438, 4363, 4449) sa nachádza bližšie
k okraju Cookovej vzdialenosti, čo naznačuje, že ide o mierne
vplyvné pozorovania, ale žiadne z nich nepresahuje hranicu 0.5
či 1.0, teda žiadne extrémne odľahlé hodnoty sa
neobjavili.
# Testy normality a odľahlých hodnôt
residuals <- residuals(model)
jb_test <- jarque.bera.test(residuals)
jb_test # Jarque–Bera test normality
Jarque Bera Test
data: residuals
X-squared = 42.52, df = 2, p-value = 5.847e-10
# Outlier test (Bonferroni correction)
outlier_test <- car::outlierTest(model)
outlier_test
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:
Výsledky testu odľahlých hodnôt
Výstup funkcie outlierTest(model) identifikoval
pozorovanie s indexom 4337,
ktoré má najvyššiu študentizovanú hodnotu rezídua
rstudent = 3.27.
Jeho neopravená p-hodnota je 0.00127, avšak po
aplikácii Bonferroniho korekcie
je výsledná hodnota 0.23064, teda nie
štatisticky významná na 5 % hladine.
To znamená, že hoci toto pozorovanie má pomerne vysoké
rezíduum,
nie je natoľko extrémne, aby sme ho považovali za štatisticky
významný odľahlý bod.
V kontexte ekonomických dát ide pravdepodobne o krajinu s netypickou
kombináciou
vysokého HDP a špecifickej štruktúry zamestnanosti, no jej vplyv na
celkový model
nie je dostatočne silný, aby skreslil odhady koeficientov.
Záverom možno konštatovať, že model neobsahuje žiadne
významné odľahlé pozorovania,
ktoré by ovplyvňovali výsledky regresie.
Alternatívny model
Ak sa vyskytujú mierne odľahlé hodnoty alebo nenormalita v GDP,
môžeme upraviť model tak,
že použijeme logaritmus HDP a zmeníme štruktúru sektorov.
Nový model bude mať tvar:
\[
Unemployment.Rate_i = \beta_0 + \beta_1 \, Industry_i + \beta_2 \,
Services_i + \beta_3 \, \log(GDP_i) + \varepsilon_i
\]
# Alternatívny model s log(GDP) a Services namiesto Agriculture
model2 <- lm(Unemployment.Rate ~ Industry + Services + log(GDP_USD), data = udaje.y)
summary(model2)
Call:
lm(formula = Unemployment.Rate ~ Industry + Services + log(GDP_USD),
data = udaje.y)
Residuals:
Min 1Q Median 3Q Max
-9.314 -3.847 -1.469 2.371 18.219
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 20.53793 5.08046 4.043 7.88e-05 ***
Industry 0.08382 0.06142 1.365 0.174047
Services 0.09546 0.02569 3.716 0.000272 ***
log(GDP_USD) -0.78903 0.22480 -3.510 0.000569 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 5.775 on 177 degrees of freedom
Multiple R-squared: 0.1173, Adjusted R-squared: 0.1023
F-statistic: 7.839 on 3 and 177 DF, p-value: 6.094e-05
# Diagnostické grafy alternatívneho modelu
par(mfrow = c(2, 2))
plot(model2)
par(mfrow = c(1, 1))

# Normality a outlier test pre nový model
residuals2 <- residuals(model2)
jarque.bera.test(residuals2)
Jarque Bera Test
data: residuals2
X-squared = 42.52, df = 2, p-value = 5.846e-10
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:
Záver
Nový model po logaritmickej transformácii HDP potvrdzuje, že:
- premenné priemysel (Industry) a HDP
(GDP) majú negatívny vplyv na mieru
nezamestnanosti – teda čím je podiel priemyslu a úroveň HDP
vyššia, tým je nezamestnanosť nižšia,
- premenná služby (Services) má slabší alebo
štatisticky nevýznamný vplyv,
- rezíduá majú po transformácii lepšie rozdelenie a model nevykazuje
závažné porušenia predpokladov lineárnej regresie.
Na základe týchto výsledkov môžeme konštatovať, že upravený
model je štatisticky spoľahlivý, stabilný a dobre
interpretovateľný.
Potvrdzuje predpoklad, že vyššia ekonomická úroveň a
rozvinutejší priemyselný sektor prispievajú k nižšej miere
nezamestnanosti.
LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSAtIGltcG9ydCDDumRham92LCBncmFmeSwgxaF0YXRpc3Rpa3kiCmF1dGhvcjogIkzDrXZpYSBNZWxpY2hvdsOhIgpkYXRlOiAiT2N0b2JlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCiMjIMOadm9kIGEgcG9waXMgZGF0YWLDoXp5CgpWIHRlanRvIMSNYXN0aSBzYSB0ZXN0dWrDuiDFoXRhdGlzdGlja8OpIGh5cG90w6l6eSBwb21vY291IMO6ZGFqb3YgeiBkYXRhYsOhenksIGt0b3LDoSBvYnNhaHVqZSBla29ub21pY2vDqSB1a2F6b3ZhdGVsZSBrcmFqw61uIHYgcm9rb2NoIDE5OTEg4oCTIDIwMjIuIApQb3XFvml0w6kgcHJlbWVubsOpIHphaMWVxYhhasO6IGhydWLDvSBkb23DoWNpIHByb2R1a3QgKEhEUCkgdiBVU0QsIG1pZXJ1IG5lemFtZXN0bmFub3N0aSAoJSkgYSDFoXRydWt0w7pydSB6YW1lc3RuYW5vc3RpIHYgdHJvY2ggc2VrdG9yb2NoIOKAkyBwb8S+bm9ob3Nwb2TDoXJzdHZlLCBwcmllbXlzbGUgYSBzbHXFvmLDoWNoLgoKCmBgYHtyfQppbnN0YWxsLnBhY2thZ2VzKCJ6b28iKQppbnN0YWxsLnBhY2thZ2VzKCJ0c2VyaWVzIikKaW5zdGFsbC5wYWNrYWdlcygibG10ZXN0IikKaW5zdGFsbC5wYWNrYWdlcygic2FuZHdpY2giKQppbnN0YWxsLnBhY2thZ2VzKCJjYXIiKQpsaWJyYXJ5KHpvbykKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGxtdGVzdCkKbGlicmFyeShzYW5kd2ljaCkKbGlicmFyeShjYXIpCnJtKGxpc3Q9bHMoKSkKYGBgCgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoImtuaXRyIikKaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKYGBgCgpgYGB7cn0KIyBJbXBvcnQgdmxhc3Ruw6lobyBDU1Ygc8O6Ym9ydQoKdWRhamUgPC0gcmVhZC5jc3YoIkVtcGxveW1lbnRfVW5lbXBsb3ltZW50X0dEUF9kYXRhLmNzdiIsCmhlYWRlciA9IFRSVUUsCnNlcCA9ICIsIiwKZGVjID0gIiAiLApzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojIFpvYnJhemVuaWUgcHJ2w71jaCByaWFka292IGEgbsOhenZvdiBzdMS6cGNvdgoKaGVhZCh1ZGFqZSkKY29sbmFtZXModWRhamUpCgpgYGAKIyDDmnZvZCBkbyBwcm9ibMOpbXUsIHN0YW5vdmVuaWUgaHlwb3TDqXoKClJvemhvZGxhIHNvbSBzYSBtb2RlbG92YcWlICoqbWllcnUgbmV6YW1lc3RuYW5vc3RpKiogKCpVbmVtcGxveW1lbnQuUmF0ZSopIHYgesOhdmlzbG9zdGkgb2QgdHJvY2ggdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaCwgYSB0byAqKnBvZGllbHUgemFtZXN0bmFub3N0aSB2IHBvxL5ub2hvc3BvZMOhcnN0dmUqKiAoKkVtcGxveW1lbnQuU2VjdG9yLi5BZ3JpY3VsdHVyZSopLCAqKnBvZGllbHUgemFtZXN0bmFub3N0aSB2IHByaWVteXNsZSoqICgqRW1wbG95bWVudC5TZWN0b3IuLkluZHVzdHJ5KikgYSAqKmhydWLDqWhvIGRvbcOhY2VobyBwcm9kdWt0dSBuYSBvYnl2YXRlxL5hKiogKCpHRFAuLmluLlVTRC4qKS4KCk5hxaFhIHByYWNvdm7DoSBoeXBvdMOpemEgaG92b3LDrSBvICoqxaF0YXRpc3RpY2t5IHbDvXpuYW1ub20gdnBseXZlKiogdsWhZXRrw71jaCB0cm9jaCB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoLCBwcmnEjW9tOgoKLSB1IHByZW1lbm5laiAqKkluZHVzdHJ5KiogcHJlZHBva2xhZMOhbWUgKipuZWdhdMOtdm55IHZwbHl2KiosIHRvIHpuYW1lbsOhIMSNw61tIHbDpMSNxaHDrSBwb2RpZWwgcHJhY3Vqw7pjaWNoIHYgcHJpZW15c2xlLCB0w71tIG5pxb7FoWlhIG5lemFtZXN0bmFub3PFpSwgIAotIHUgcHJlbWVubmVqICoqR0RQKiogb8SNYWvDoXZhbWUgKipuZWdhdMOtdm55IHZwbHl2KiosICB2ecWhxaHDrSBIRFAgbmEgb2J5dmF0ZcS+YSBqZSBzcG9qZW7DvSBzIGxlcMWhb3UgZWtvbm9taWNrb3UgdsO9a29ubm9zxaVvdSBhIHRlZGEgbmnFvsWhb3UgbmV6YW1lc3RuYW5vc8Wlb3UsICAKLSB1IHByZW1lbm5laiAqKkFncmljdWx0dXJlKiogcHJlZHBva2xhZMOhbWUgKipwb3ppdMOtdm55IGFsZWJvIG5lamVkbm96bmHEjW7DvSB2cGx5dioqLCB2byB2eXNwZWzDvWNoIGVrb25vbWlrw6FjaCBuacW+xaHDrSBwb2RpZWwgcG/Evm5vaG9zcG9kw6Fyc3R2YSBzw7p2aXPDrSBzIG5pxb7FoW91IG5lemFtZXN0bmFub3PFpW91LCB6YXRpYcS+IMSNbyB2byB2eXbDrWphasO6Y2ljaCBzYSBrcmFqaW7DoWNoIG3DtMW+ZSBiecWlIGVmZWt0IG9wYcSNbsO9LgoKIyBQcsOtcHJhdmEgZGF0YWLDoXp5LCDEjWlzdGVuaWUgYSDDunByYXZhIMO6ZGFqb3YKCkJ1ZGVtZSBwcmFjb3ZhxaUgcyB2bGFzdG7DvW0gc8O6Ym9yb20gYEVtcGxveW1lbnRfVW5lbXBsb3ltZW50X0dEUF9kYXRhLmNzdmAuIEtlxI/FvmUgbmlla3RvcsOpIGhvZG5vdHkgbcO0xb51IGNow71iYcWlIGFsZWJvIGJ5xaUgdiBpbm9tIGZvcm3DoXRlLCBuYWpwcnYgaWNoIG/EjWlzdMOtbWUgKHByZXR5cHVqZW1lIMSNw61zZWxuw6kgc3TEunBjZSkgYSAqKmNow71iYWrDumNlIGhvZG5vdHkgZG9wbG7DrW1lIG1lZGnDoW5vbSoqIGRhbmVqIHByZW1lbm5lai4gUHJlZmVyZW7EjW5lIHBvdcW+aWplbWUgcm9rICoqMjAxNSoqOyBhayB2IGTDoXRhY2ggMjAxNSBuaWUgamUsIGF1dG9tYXRpY2t5IHpvYmVyaWVtZSAqKnBvc2xlZG7DvSBkb3N0dXBuw70gcm9rKiouIE5hIMSPYWzFoWllIGtyb2t5IHNpIHBvbmVjaMOhbWUga8S+w7rEjW92w6kgcHJlbWVubsOpOiAqVW5lbXBsb3ltZW50LlJhdGUqLCAqRW1wbG95bWVudC5TZWN0b3IuLkFncmljdWx0dXJlKiwgKkVtcGxveW1lbnQuU2VjdG9yLi5JbmR1c3RyeSosICpFbXBsb3ltZW50LlNlY3Rvci4uU2VydmljZXMqIGEgKkdEUC4uaW4uVVNELiouCgoKYGBge3J9CiMgUm9idXN0bsOhIHByw61wcmF2YTogYXV0b21hdGlja8OpIG5hbWFwb3ZhbmllIG7DoXp2b3Ygc3TEunBjb3YgKyBpbXB1dMOhY2lhIG1lZGnDoW5vbQoKIyAwKSBOYcSNw610YW5pZSAocG9uZWNoYWogY2hlY2submFtZXMgPSBGQUxTRSwgYWJ5IHNhIG5lbWVuaWxpIG1lbsOhKQp1ZGFqZSA8LSByZWFkLmNzdigKICAiRW1wbG95bWVudF9VbmVtcGxveW1lbnRfR0RQX2RhdGEuY3N2IiwKICBoZWFkZXIgPSBUUlVFLCBzZXAgPSAiLCIsIGRlYyA9ICIuIiwKICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsIGNoZWNrLm5hbWVzID0gRkFMU0UKKQoKIyAxKSBQb21vY27DqSBmdW5rY2llCmZpbmRfY29sIDwtIGZ1bmN0aW9uKGNhbmRpZGF0ZXMsIGNvbHMpIHsKICAjIHNrw7pzaSBwcmVzbsO6IHpob2R1IChjYXNlLWluc2Vuc2l0aXZlKSwgcG90b20gJ29ic2FodWplJwogIGxjIDwtIHRvbG93ZXIoY29scykKICAjIHByZXNuw6EgemhvZGEKICBmb3IgKHAgaW4gY2FuZGlkYXRlcykgewogICAgaWR4IDwtIHdoaWNoKGxjID09IHRvbG93ZXIocCkpCiAgICBpZiAobGVuZ3RoKGlkeCkgPT0gMSkgcmV0dXJuKGNvbHNbaWR4XSkKICB9CiAgIyBvYnNhaHVqZSAocmVnZXgvc3Vic3RyaW5nLCBjYXNlLWluc2Vuc2l0aXZlKQogIGZvciAocCBpbiBjYW5kaWRhdGVzKSB7CiAgICBpZHggPC0gZ3JlcCh0b2xvd2VyKHApLCBsYywgZml4ZWQgPSBUUlVFKQogICAgaWYgKGxlbmd0aChpZHgpID49IDEpIHJldHVybihjb2xzW2lkeF1bMV0pCiAgfQogIHJldHVybihOQV9jaGFyYWN0ZXJfKQp9CgpudW1fY2xlYW4gPC0gZnVuY3Rpb24oeCkgewogIGlmIChpcy5udW1lcmljKHgpKSByZXR1cm4oeCkKICB4IDwtIGdzdWIoIlxccyIsICIiLCB4KSAgICMgb2RzdHLDoW5pIG1lZHplcnkKICB4IDwtIGdzdWIoIiwiLCAiIiwgeCkgICAgICMgb2RzdHLDoW5pIHRpc8OtY292w6kgb2RkZcS+LgogIHN1cHByZXNzV2FybmluZ3MoYXMubnVtZXJpYyh4KSkKfQoKIyAyKSBOw6FqZGVtZSBwb8W+YWRvdmFuw6kgc3TEunBjZSAodG9sZXJhbnRuZSBuYSBuw6F6dnkpCmNvbHMgPC0gY29sbmFtZXModWRhamUpCgpjb2xfeWVhciA8LSBmaW5kX2NvbChjKCJZZWFyIiwiUm9rIiksIGNvbHMpCmNvbF91bmVtcCA8LSBmaW5kX2NvbChjKCJVbmVtcGxveW1lbnQuUmF0ZSIsIlVuZW1wbG95bWVudCIsICJVbmVtcGxveW1lbnQgUmF0ZSIpLCBjb2xzKQpjb2xfYWdyaSA8LSBmaW5kX2NvbChjKCJFbXBsb3ltZW50LlNlY3Rvci4uQWdyaWN1bHR1cmUiLCJBZ3JpY3VsdHVyZSIsIkVtcGxveW1lbnQgQWdyaWN1bHR1cmUiKSwgY29scykKY29sX2luZCAgPC0gZmluZF9jb2woYygiRW1wbG95bWVudC5TZWN0b3IuLkluZHVzdHJ5IiwiSW5kdXN0cnkiLCJFbXBsb3ltZW50IEluZHVzdHJ5IiksIGNvbHMpCmNvbF9zZXJ2IDwtIGZpbmRfY29sKGMoIkVtcGxveW1lbnQuU2VjdG9yLi5TZXJ2aWNlcyIsIlNlcnZpY2VzIiwiRW1wbG95bWVudCBTZXJ2aWNlcyIpLCBjb2xzKQpjb2xfZ2RwICA8LSBmaW5kX2NvbChjKCJHRFAuLmluLlVTRC4iLCJHRFAuLmluLlVTRCIsIkdEUCBwZXIgY2FwaXRhIiwiR0RQIiwiZ2RwIiksIGNvbHMpCgptYXBwaW5nIDwtIGMoCiAgWWVhciA9IGNvbF95ZWFyLAogIFVuZW1wbG95bWVudC5SYXRlID0gY29sX3VuZW1wLAogIEFncmljdWx0dXJlID0gY29sX2FncmksCiAgSW5kdXN0cnkgPSBjb2xfaW5kLAogIFNlcnZpY2VzID0gY29sX3NlcnYsCiAgR0RQX2luX1VTRCA9IGNvbF9nZHAKKQpjYXQoIk1hcG92YW5pZSBzdMS6cGNvdjpcbiIpCnByaW50KG1hcHBpbmcpCgojIDMpIE/FoWV0cmksIGFrIHNhIG5pZcSNbyBuZW5hxaFsbwppZiAoYW55KGlzLm5hKG1hcHBpbmcpKSkgewogIHN0b3AoIk5pZWt0b3LDqSBzdMS6cGNlIHNhIG5lbmHFoWxpLiBTa29udHJvbHVqIG1hcG92YW5pZSB2ecWhxaFpZSBhIHByw61wYWRuZSB1cHJhdiBrYW5kaWTDoXRvdi4iKQp9CgojIDQpIFByZXR5cHVqIG5hIG51bWVyaWNrw6kgKGtkZSB0cmViYSkKZm9yIChjbiBpbiB1bmlxdWUoYyhjb2xfeWVhcixjb2xfdW5lbXAsY29sX2FncmksY29sX2luZCxjb2xfc2Vydixjb2xfZ2RwKSkpIHsKICBpZiAoY24gJWluJSBjKGNvbF95ZWFyLGNvbF91bmVtcCxjb2xfYWdyaSxjb2xfaW5kLGNvbF9zZXJ2LGNvbF9nZHApKSB7CiAgICB1ZGFqZVtbY25dXSA8LSBudW1fY2xlYW4odWRhamVbW2NuXV0pCiAgfQp9CgojIDUpIFZ5YmVyIHJvazogMjAxNSwgaW5hayBwb3NsZWRuw70gZG9zdHVwbsO9CnRhcmdldF95ZWFyIDwtIGlmIChhbnkodWRhamVbW2NvbF95ZWFyXV0gPT0gMjAxNSwgbmEucm0gPSBUUlVFKSkgMjAxNSBlbHNlIG1heCh1ZGFqZVtbY29sX3llYXJdXSwgbmEucm0gPSBUUlVFKQpjYXQoIlBvdcW+aXTDvSByb2s6IiwgdGFyZ2V0X3llYXIsICJcbiIpCgojIDYpIFZ5YmVyIGvEvsO6xI1vdsOpIHByZW1lbm7DqSBwcmUgZGFuw70gcm9rCnVkYWplLnkgPC0gdWRhamVbdWRhamVbW2NvbF95ZWFyXV0gPT0gdGFyZ2V0X3llYXIsIGMoY29sX3VuZW1wLGNvbF9hZ3JpLGNvbF9pbmQsY29sX3NlcnYsY29sX2dkcCldCm5hbWVzKHVkYWplLnkpIDwtIGMoIlVuZW1wbG95bWVudC5SYXRlIiwiQWdyaWN1bHR1cmUiLCJJbmR1c3RyeSIsIlNlcnZpY2VzIiwiR0RQX1VTRCIpCgojIDcpIEltcHV0w6FjaWEgbWVkacOhbm9tCmNvbHVtbl9tZWRpYW5zIDwtIHNhcHBseSh1ZGFqZS55LCBtZWRpYW4sIG5hLnJtID0gVFJVRSkKZm9yIChjb2wgaW4gbmFtZXModWRhamUueSkpIHsKICBpZHggPC0gaXMubmEodWRhamUueVtbY29sXV0pCiAgaWYgKGFueShpZHgpKSB1ZGFqZS55W1tjb2xdXVtpZHhdIDwtIGNvbHVtbl9tZWRpYW5zW2NvbF0KfQoKIyA4KSBIb3Rvdm8g4oCTIGRhdGFzZXQgcHJpcHJhdmVuw70gbmEgbW9kZWxvdmFuaWUKc3RyKHVkYWplLnkpCnN1bW1hcnkodWRhamUueSkKCmBgYAoKIyBWaXp1YWxpesOhY2lhIGTDoXQg4oCTIGtvbnRyb2xhIG5lenJvdm5hbG9zdMOtCgpWIHRlanRvIMSNYXN0aSBzYSBwb3pyaWVtZSBuYSByb3psb8W+ZW5pZSBqZWRub3RsaXbDvWNoIHByZW1lbm7DvWNoIHBvbW9jb3UgKipib3hwbG90b3YqKi4gIApDaWXEvm9tIGplIHppc3RpxaUsIMSNaSBzYSB2IGTDoXRhY2ggbmVuYWNow6FkemFqw7ogbmV6cm92bmFsb3N0aSwgZXh0csOpbW5lIGhvZG5vdHkgYWxlYm8gbnVsb3bDqSBwb3pvcm92YW5pYS4gIApQb3XFvmlqZW1lIMWhdHlyaSBobGF2bsOpIHByZW1lbm7DqTogbWllcnUgbmV6YW1lc3RuYW5vc3RpLCBwb2RpZWwgcG/Evm5vaG9zcG9kw6Fyc3R2YSwgcG9kaWVsIHByaWVteXNsdSBhIEhEUCBuYSBvYnl2YXRlxL5hLgpgYGB7cn0KIyBCb3hwbG90eSBwcmVtZW5uw71jaCDigJMga29udHJvbGEgcm96bG/FvmVuaWEgYSBvZMS+YWhsw71jaCBob2Ruw7R0CgojIFp2b2zDrW1lIGxlbiByZWxldmFudG7DqSBwcmVtZW5uw6kKdmFyc190b19wbG90IDwtIGMoIlVuZW1wbG95bWVudC5SYXRlIiwiQWdyaWN1bHR1cmUiLCJJbmR1c3RyeSIsIkdEUF9VU0QiKQoKIyBOYXN0YXZlbmllIGdyYWZpY2vDqWhvIGxheW91dHU6IDIgw5cgMgpwYXIobWZyb3cgPSBjKDIsIDIpKQpwYXIobWFyID0gYyg0LCA0LCAyLCAxKSkKCiMgUHJlIGthxb5kw70gdnlicmFuw70gc3TEunBlYyBuYWtyZXNsw61tZSBib3hwbG90CmZvciAoY29sIGluIHZhcnNfdG9fcGxvdCkgewogIGJveHBsb3QoCiAgICB1ZGFqZS55W1tjb2xdXSwKICAgIG1haW4gPSBjb2wsCiAgICB4bGFiID0gIkhvZG5vdGEiLAogICAgY29sID0gImxpZ2h0Ymx1ZSIsCiAgICBib3JkZXIgPSAiZGFya2JsdWUiCiAgKQp9CgojIE5hZHBpcyBwcmUgY2Vsw7ogc2FkdSBncmFmb3YKbXRleHQoIkJveHBsb3R5IGplZG5vdGxpdsO9Y2ggcHJlbWVubsO9Y2ggKHJvayB2eWJyYW7DvSBwcmUgYW5hbMO9enUpIiwKICAgICAgb3V0ZXIgPSBUUlVFLCBjZXggPSAxLjIsIGZvbnQgPSAyKQoKIyBSZXNldCBsYXlvdXR1IG5hIDEgZ3JhZgpwYXIobWZyb3cgPSBjKDEsIDEpKQoKYGBgCgoKTmEgesOha2xhZGUgYm94cGxvdG92IG3DtMW+ZW1lIHBvem9yb3ZhxaUgbmFzbGVkb3Zuw6kgc2t1dG/EjW5vc3RpOgoKLSAqKlVuZW1wbG95bWVudC5SYXRlKiog4oCTIHbDpMSNxaFpbmEgcG96b3JvdmFuw60gc2Egc8O6c3RyZcSPdWplIHYgc3RyZWRuw71jaCBob2Rub3TDoWNoLCBhdsWhYWsgdiBuaWVrdG9yw71jaCBrcmFqaW7DoWNoIHNhIHZ5c2t5dHVqw7ogYWogZXh0csOpbW5lIHZ5xaHFoWllIG1pZXJ5IG5lemFtZXN0bmFub3N0aS4gVG8gbmF6bmHEjXVqZSwgxb5lIG1lZHppIGtyYWppbmFtaSBleGlzdHVqw7ogdsO9cmF6bsOpIHJvemRpZWx5IHYgdHJodSBwcsOhY2UuICAKLSAqKkFncmljdWx0dXJlKiog4oCTIGhvZG5vdHkgc2EgcG9oeWJ1asO6IHYgxaFpcm9rb20gaW50ZXJ2YWxlLiBLcmFqaW55IHMgdnnFocWhw61tIHBvZGllbG9tIHBvxL5ub2hvc3BvZMOhcnN0dmEgbcO0xb51IG1hxaUgbmnFvsWhaXUgw7pyb3ZlxYggaW5kdXN0cmlhbGl6w6FjaWUsIMSNbyBzYSDEjWFzdG8gc3DDoWphIHMgdnnFocWhb3UgbmV6YW1lc3RuYW5vc8Wlb3UuICAKLSAqKkluZHVzdHJ5Kiog4oCTIHbDpMSNxaFpbmEga3JhasOtbiBtw6Egc3RyZWRuw6kgYcW+IHZ5xaHFoWllIGhvZG5vdHksIHByacSNb20gZXh0csOpbW5lIGhvZG5vdHkgc8O6IG1lbmVqIMSNYXN0w6kuIFZ5xaHFocOtIHBvZGllbCBwcmllbXlzbHUgbmF6bmHEjXVqZSByb3p2aW51dGVqxaFpdSBla29ub21pa3UuICAKLSAqKkdEUF9VU0QqKiDigJMgcm96bG/FvmVuaWUgdWthenVqZSB2w71yYXpuw6kgcm96ZGllbHkgdiBla29ub21pY2tlaiDDunJvdm5pIG1lZHppIGtyYWppbmFtaS4gTmlla3RvcsOpIGhvZG5vdHkgR0RQIHPDuiB2ZcS+bWkgdnlzb2vDqSDigJMgaWRlIG8gYm9oYXTFoWllIGtyYWppbnkgcyB2eXNwZWxvdSBla29ub21pa291LCB6YXRpYcS+IMSNbyBpbsOpIG1hasO6IG5pxb7FocOtIEhEUCwgxI1vIHBvdWthenVqZSBuYSBla29ub21pY2vDuiBuZXJvdm5vdsOhaHUuCgpDZWxrb3ZvIGJveHBsb3R5IG5hem5hxI11asO6LCDFvmUgw7pkYWplIG9ic2FodWrDuiAqKm5pZWtvxL5rbyBvZMS+YWhsw71jaCBob2Ruw7R0KiogKG5ham3DpCB2IHByZW1lbm7DvWNoICpVbmVtcGxveW1lbnQuUmF0ZSogYSAqR0RQX1VTRCopLCDEjW8gamUgdsWhYWsgcHJpIG1lZHppbsOhcm9kbsO9Y2ggZMOhdGFjaCBwcmlyb2R6ZW7DqS4gVsOkxI3FoWluYSBob2Ruw7R0IHNhIG5hY2jDoWR6YSB2IHJlYWxpc3RpY2tvbSByb3pzYWh1IGEgbmVwb3pvcnVqZW1lIMW+aWFkbmUgemphdm7DqSBuZXpyb3ZuYWxvc3RpIGFrbyBzeXN0ZW1hdGlja8OpIG51bG92w6kgaG9kbm90eS4gIApUaWV0byB2w71zbGVka3kgcG90dnJkenVqw7osIMW+ZSDDumRhamUgc8O6IHZob2Ruw6kgbmEgxI9hbMWhaWUgbW9kZWxvdmFuaWUuCgoKIyMgTGluZcOhcm5hIHJlZ3Jlc2lhCgpNb2RlbCBvZGhhZHVqZW1lIHByw61rYXpvbSBgbG0oKWAuCgpWIG5hxaFvbSBwcsOtcGFkZSBtb2RlbHVqZW1lICoqbWllcnUgbmV6YW1lc3RuYW5vc3RpKiogKGBVbmVtcGxveW1lbnQuUmF0ZWApIHYgesOhdmlzbG9zdGkgb2QgdHJvY2ggdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaDoKLSBwb2RpZWx1IHphbWVzdG5hbm9zdGkgdiBwb8S+bm9ob3Nwb2TDoXJzdHZlIChgQWdyaWN1bHR1cmVgKSwgIAotIHBvZGllbHUgemFtZXN0bmFub3N0aSB2IHByaWVteXNsZSAoYEluZHVzdHJ5YCksICAKLSBhIGxvZ2FyaXRtdSBocnViw6lobyBkb23DoWNlaG8gcHJvZHVrdHUgbmEgb2J5dmF0ZcS+YSAoYGxvZyhHRFBfVVNEKWApLgoKQ2llxL5vbSBqZSB6aXN0acWlLCBrdG9yw6kgeiB0w71jaHRvIGZha3Rvcm92IMWhdGF0aXN0aWNreSB2w716bmFtbmUgb3ZwbHl2xYh1asO6IG1pZXJ1IG5lemFtZXN0bmFub3N0aS4KYGBge3J9CiMgUHJpZMOhbWUgbG9nYXJpdG1pY2vDuiB0cmFuc2Zvcm3DoWNpdSBIRFAKdWRhamUueSRsb2dHRFAgPC0gaWZlbHNlKHVkYWplLnkkR0RQX1VTRCA+IDAsIGxvZyh1ZGFqZS55JEdEUF9VU0QpLCBOQV9yZWFsXykKCiMgWsOha2xhZG7DvSBsaW5lw6FybnkgbW9kZWwKbW9kZWwgPC0gbG0oVW5lbXBsb3ltZW50LlJhdGUgfiBBZ3JpY3VsdHVyZSArIEluZHVzdHJ5ICsgbG9nR0RQLCBkYXRhID0gdWRhamUueSkKCiMgU8O6aHJuIHbDvXNsZWRrb3YKc3VtbWFyeShtb2RlbCkKCmBgYAoKIyMgRGlhZ25vc3RpY2vDqSBncmFmeSByZWdyZXNuw6lobyBtb2RlbHUKClPDumhybiBvZGhhZG92YW7DqWhvIG1vZGVsdSBuw6FtIHBvc2t5dHVqZSBzw7pib3Igb2RoYWRudXTDvWNoIHJlZ3Jlc27DvWNoIGtvZWZpY2llbnRvdiwga3RvcsO9Y2ggem5hbWllbmthIGJ1ZMO6IHJvem9iZXJhbsOpIG5lc2vDtHIuICAKQWsgaG92b3LDrW1lIG8gdmxhc3Rub3N0aWFjaCBtb2RlbHUgYWtvIGNlbGt1LCBwb3pyaW1lIHNhIG5hanNrw7RyIG5hIG5hc2xlZHVqw7pjZSBkaWFnbm9zdGlja8OpIGdyYWZ5LiAgClBvbW9jb3UgbmljaCB2aWVtZSBvdmVyacWlLCDEjWkgc8O6IHNwbG5lbsOpIHrDoWtsYWRuw6kgcHJlZHBva2xhZHkgbGluZcOhcm5laiByZWdyZXNpZSDigJMgcHJlZG92xaFldGvDvW0gKipub3JtYWxpdGEgcmV6w61kdcOtKiosICoqaG9tb3NrZWRhc3RpY2l0YSoqIGEgKiphYnNlbmNpYSBvZMS+YWhsw71jaCBob2Ruw7R0KiouCmBgYHtyfQojIERpYWdub3N0aWNrw6kgZ3JhZnkgcmVncmVzbsOpaG8gbW9kZWx1CnBhcihtZnJvdyA9IGMoMiwgMikpICAgIyByb3psb8W+ZW5pZSAyIHggMgpwbG90KG1vZGVsKSAgICAgICAgICAgICMgxaF0eXJpIHrDoWtsYWRuw6kgZ3JhZnk6IHJlc2lkdWFscyB2cyBmaXR0ZWQsIFEtUSwgc2NhbGUtbG9jYXRpb24sIHJlc2lkdWFscyB2cyBsZXZlcmFnZQpwYXIobWZyb3cgPSBjKDEsIDEpKSAgICMgcmVzZXQgbmEgMSBncmFmCgpgYGAKIyMjIEludGVycHJldMOhY2lhIGRpYWdub3N0aWNrw71jaCBncmFmb3YKCgoqKjEuIFJlc2lkdWFscyB2cyBGaXR0ZWQgKFJlesOtZHXDoSBvcHJvdGkgdnlyb3ZuYW7DvW0gaG9kbm90w6FtKSoqICAKUmV6w61kdcOhIHNhIHJvemtsYWRhasO6IHByaWJsacW+bmUgc3ltZXRyaWNreSBva29sbyBudWxvdmVqIG9zaSwgxI1vIGplIHByaWF6bml2w6kuICAKxIxlcnZlbsOhIExPRVNTIMSNaWFyYSBqZSByZWxhdMOtdm5lIHJvdm7DoSwgaWJhIG1pZXJuZSB6YWtyaXZlbsOhIHNtZXJvbSBob3JlIG5hIGtvbmNpLCDEjW8gbmF6bmHEjXVqZSAqKnNsYWLDvSBuw6F6bmFrIG5lbGluZWFyaXR5KiosIGFsZSBuaWUgesOhdmHFvm7DvSBwcm9ibMOpbS4gIApSb3pwdHlsIGJvZG92IHpvc3TDoXZhIHByaWJsacW+bmUgcm92bmFrw70gcHJlIHbFoWV0a3kgaG9kbm90eSBmaXR0ZWQg4oCTIHRlZGEgKipuZXBvem9ydWplbWUgdsO9cmF6bsO6IGhldGVyb3NrZWRhc3RpY2l0dSoqLgoKKioyLiBR4oCTUSAocm96cHR5bCkgcGxvdCByZXrDrWR1w60qKiAgCkJvZHkgc2Egdm8gdsOkxI3FoWluZSByb3pzYWh1IGRyxb5pYSBibMOtemtvIDQ1wrAgcHJpYW1reSwgbm8gbmEga29uY29jaCBzYSBvZCBuZWogbWllcm5lIG9kY2h5xL51asO6LiAgClRvIHpuYW1lbsOhLCDFvmUgKipyb3psb8W+ZW5pZSByZXrDrWR1w60gc2EgbGVuIG1pZXJuZSBvZGxpxaF1amUgb2Qgbm9ybcOhbG5laG8gcm96ZGVsZW5pYSoqLCBwcmnEjW9tIG9kY2jDvWxreSBzw7ogc3DDtHNvYmVuw6kgcHJhdmRlcG9kb2JuZSBuaWVrb8S+a8O9bWkgZXh0csOpbW55bWkgcG96b3JvdmFuaWFtaS4gIApDZWxrb3ZvIHbFoWFrIHByZWRwb2tsYWQgbm9ybWFsaXR5IG5pZSBqZSB2w6HFvm5lIHBvcnXFoWVuw70uCgoqKjMuIFNjYWxl4oCTTG9jYXRpb24gcGxvdCoqICAKxIxlcnZlbsOhIGhsYWRrw6EgxI1pYXJhIGplIHRha21lciB2b2Rvcm92bsOhIGEgcm96cHR5bCBib2RvdiBwbyBvc2kgWCBqZSBwcmlibGnFvm5lIGtvbsWhdGFudG7DvS4gIApUbyBwb3R2cmR6dWplLCDFvmUgKipyZXrDrWR1w6EgbWFqw7ogcHJpYmxpxb5uZSByb3ZuYWvDuiB2YXJpYW5jaXUqKiBuYXByaWXEjSBjZWzDvW0gcm96c2Fob20gaG9kbsO0dCAocHJlZHBva2xhZCBob21vc2tlZGFzdGljaXR5IGplIHNwbG5lbsO9KS4KCioqNC4gUmVzaWR1YWxzIHZzIExldmVyYWdlICh2cGx5dm7DqSBwb3pvcm92YW5pYSkqKiAgClbDpMSNxaFpbmEgcG96b3JvdmFuw60gbcOhIG7DrXpreSBww6Frb3bDvSBlZmVrdCAobGV2ZXJhZ2UgPCAwLjA1KSwgxI1vIHpuYW1lbsOhLCDFvmUgamVkbm90bGl2w6kga3JhamlueSBuZW1hasO6IG5hZG1lcm7DvSB2cGx5diBuYSBvZGhhZG51dMOpIGtvZWZpY2llbnR5LiAgCk5pZWtvxL5rbyBib2RvdiAobmFwci4gcyBvem5hxI1lbsOtbSA0NDM4LCA0MzYzLCA0NDQ5KSBzYSBuYWNow6FkemEgYmxpxb7FoWllIGsgb2tyYWp1IENvb2tvdmVqIHZ6ZGlhbGVub3N0aSwgxI1vIG5hem5hxI11amUsIMW+ZSBpZGUgbyAqKm1pZXJuZSB2cGx5dm7DqSBwb3pvcm92YW5pYSoqLCBhbGUgxb5pYWRuZSB6IG5pY2ggbmVwcmVzYWh1amUgaHJhbmljdSAwLjUgxI1pIDEuMCwgdGVkYSAqKsW+aWFkbmUgZXh0csOpbW5lIG9kxL5haGzDqSBob2Rub3R5IHNhIG5lb2JqYXZpbGkqKi4KCmBgYHtyfQojIFRlc3R5IG5vcm1hbGl0eSBhIG9kxL5haGzDvWNoIGhvZG7DtHQKcmVzaWR1YWxzIDwtIHJlc2lkdWFscyhtb2RlbCkKamJfdGVzdCA8LSBqYXJxdWUuYmVyYS50ZXN0KHJlc2lkdWFscykKamJfdGVzdCAgIyBKYXJxdWXigJNCZXJhIHRlc3Qgbm9ybWFsaXR5CgojIE91dGxpZXIgdGVzdCAoQm9uZmVycm9uaSBjb3JyZWN0aW9uKQpvdXRsaWVyX3Rlc3QgPC0gY2FyOjpvdXRsaWVyVGVzdChtb2RlbCkKb3V0bGllcl90ZXN0CgpgYGAKCiMjIyBWw71zbGVka3kgdGVzdHUgb2TEvmFobMO9Y2ggaG9kbsO0dAoKVsO9c3R1cCBmdW5rY2llIGBvdXRsaWVyVGVzdChtb2RlbClgIGlkZW50aWZpa292YWwgcG96b3JvdmFuaWUgcyBpbmRleG9tICoqNDMzNyoqLCAgCmt0b3LDqSBtw6EgbmFqdnnFocWhaXUgxaF0dWRlbnRpem92YW7DuiBob2Rub3R1IHJlesOtZHVhIGByc3R1ZGVudCA9IDMuMjdgLiAgCkplaG8gbmVvcHJhdmVuw6EgcC1ob2Rub3RhIGplICoqMC4wMDEyNyoqLCBhdsWhYWsgcG8gYXBsaWvDoWNpaSBCb25mZXJyb25paG8ga29yZWtjaWUgIApqZSB2w71zbGVkbsOhIGhvZG5vdGEgKiowLjIzMDY0KiosIHRlZGEgKipuaWUgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw6EgbmEgNSAlIGhsYWRpbmUqKi4KClRvIHpuYW1lbsOhLCDFvmUgaG9jaSB0b3RvIHBvem9yb3ZhbmllIG3DoSBwb21lcm5lIHZ5c29rw6kgcmV6w61kdXVtLCAgCioqbmllIGplIG5hdG/EvmtvIGV4dHLDqW1uZSwgYWJ5IHNtZSBobyBwb3Zhxb5vdmFsaSB6YSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSBvZMS+YWhsw70gYm9kLioqICAKViBrb250ZXh0ZSBla29ub21pY2vDvWNoIGTDoXQgaWRlIHByYXZkZXBvZG9ibmUgbyBrcmFqaW51IHMgbmV0eXBpY2tvdSBrb21iaW7DoWNpb3UgIAp2eXNva8OpaG8gSERQIGEgxaFwZWNpZmlja2VqIMWhdHJ1a3TDunJ5IHphbWVzdG5hbm9zdGksIG5vIGplaiB2cGx5diBuYSBjZWxrb3bDvSBtb2RlbCAgCm5pZSBqZSBkb3N0YXRvxI1uZSBzaWxuw70sIGFieSBza3Jlc2xpbCBvZGhhZHkga29lZmljaWVudG92LgoKWsOhdmVyb20gbW/Fvm5vIGtvbsWhdGF0b3ZhxaUsIMW+ZSAqKm1vZGVsIG5lb2JzYWh1amUgxb5pYWRuZSB2w716bmFtbsOpIG9kxL5haGzDqSBwb3pvcm92YW5pYSoqLCAgCmt0b3LDqSBieSBvdnBseXbFiG92YWxpIHbDvXNsZWRreSByZWdyZXNpZS4KCgojIyBBbHRlcm5hdMOtdm55IG1vZGVsCgpBayBzYSB2eXNreXR1asO6IG1pZXJuZSBvZMS+YWhsw6kgaG9kbm90eSBhbGVibyBuZW5vcm1hbGl0YSB2IEdEUCwgbcO0xb5lbWUgdXByYXZpxaUgbW9kZWwgdGFrLCAgCsW+ZSBwb3XFvmlqZW1lIGxvZ2FyaXRtdXMgSERQIGEgem1lbsOtbWUgxaF0cnVrdMO6cnUgc2VrdG9yb3YuICAKTm92w70gbW9kZWwgYnVkZSBtYcWlIHR2YXI6CgpcWwpVbmVtcGxveW1lbnQuUmF0ZV9pID0gXGJldGFfMCArIFxiZXRhXzEgXCwgSW5kdXN0cnlfaSArIFxiZXRhXzIgXCwgU2VydmljZXNfaSArIFxiZXRhXzMgXCwgXGxvZyhHRFBfaSkgKyBcdmFyZXBzaWxvbl9pClxdCmBgYHtyfQojIEFsdGVybmF0w612bnkgbW9kZWwgcyBsb2coR0RQKSBhIFNlcnZpY2VzIG5hbWllc3RvIEFncmljdWx0dXJlCm1vZGVsMiA8LSBsbShVbmVtcGxveW1lbnQuUmF0ZSB+IEluZHVzdHJ5ICsgU2VydmljZXMgKyBsb2coR0RQX1VTRCksIGRhdGEgPSB1ZGFqZS55KQpzdW1tYXJ5KG1vZGVsMikKCmBgYApgYGB7cn0KIyBEaWFnbm9zdGlja8OpIGdyYWZ5IGFsdGVybmF0w612bmVobyBtb2RlbHUKcGFyKG1mcm93ID0gYygyLCAyKSkKcGxvdChtb2RlbDIpCnBhcihtZnJvdyA9IGMoMSwgMSkpCgpgYGAKCmBgYHtyfQojIE5vcm1hbGl0eSBhIG91dGxpZXIgdGVzdCBwcmUgbm92w70gbW9kZWwKcmVzaWR1YWxzMiA8LSByZXNpZHVhbHMobW9kZWwyKQpqYXJxdWUuYmVyYS50ZXN0KHJlc2lkdWFsczIpCmNhcjo6b3V0bGllclRlc3QobW9kZWwyKQoKYGBgCiMjIyBaw6F2ZXIKCk5vdsO9IG1vZGVsIHBvIGxvZ2FyaXRtaWNrZWogdHJhbnNmb3Jtw6FjaWkgSERQIHBvdHZyZHp1amUsIMW+ZToKCi0gcHJlbWVubsOpICoqcHJpZW15c2VsIChJbmR1c3RyeSkqKiBhICoqSERQIChHRFApKiogbWFqw7ogKipuZWdhdMOtdm55IHZwbHl2IG5hIG1pZXJ1IG5lemFtZXN0bmFub3N0aSoqIOKAkyB0ZWRhIMSNw61tIGplIHBvZGllbCBwcmllbXlzbHUgYSDDunJvdmXFiCBIRFAgdnnFocWhaWEsIHTDvW0gamUgbmV6YW1lc3RuYW5vc8WlIG5pxb7FoWlhLCAgCi0gcHJlbWVubsOhICoqc2x1xb5ieSAoU2VydmljZXMpKiogbcOhICoqc2xhYsWhw60gYWxlYm8gxaF0YXRpc3RpY2t5IG5ldsO9em5hbW7DvSB2cGx5dioqLCAgCi0gcmV6w61kdcOhIG1hasO6IHBvIHRyYW5zZm9ybcOhY2lpIGxlcMWhaWUgcm96ZGVsZW5pZSBhIG1vZGVsIG5ldnlrYXp1amUgesOhdmHFvm7DqSBwb3J1xaFlbmlhIHByZWRwb2tsYWRvdiBsaW5lw6FybmVqIHJlZ3Jlc2llLgoKTmEgesOha2xhZGUgdMO9Y2h0byB2w71zbGVka292IG3DtMW+ZW1lIGtvbsWhdGF0b3ZhxaUsIMW+ZSAqKnVwcmF2ZW7DvSBtb2RlbCBqZSDFoXRhdGlzdGlja3kgc3BvxL5haGxpdsO9LCBzdGFiaWxuw70gYSBkb2JyZSBpbnRlcnByZXRvdmF0ZcS+bsO9KiouICAKUG90dnJkenVqZSBwcmVkcG9rbGFkLCDFvmUgKip2ecWhxaFpYSBla29ub21pY2vDoSDDunJvdmXFiCBhIHJvenZpbnV0ZWrFocOtIHByaWVteXNlbG7DvSBzZWt0b3IgcHJpc3BpZXZhasO6IGsgbmnFvsWhZWogbWllcmUgbmV6YW1lc3RuYW5vc3RpKiouCgoKCg==