Ú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.

install.packages("zoo")
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’
install.packages("car")
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)
colnames(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:
print(mapping)
                            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 ...
summary(udaje.y)
 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
car::outlierTest(model2)
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)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==