Testovanie hypotéz

Ú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("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."                  
library(dplyr)

# 🧹 Vyčistenie a pretypovanie všetkých číselných stĺpcov
udaje <- udaje %>%
  mutate(across(
    c(GDP..in.USD., Unemployment.Rate,
      Employment.Sector..Agriculture,
      Employment.Sector..Industry,
      Employment.Sector..Services),
    ~ as.numeric(gsub(",", ".", gsub("\\s+", "", .x)))
  ))

Graf 1: Vzťah medzi HDP a mierou nezamestnanosti (2018)

Graf zobrazuje vzťah medzi hrubým domácim produktom (HDP) v USD a mierou nezamestnanosti pre jednotlivé krajiny v roku 2018. Každý bod predstavuje jednu krajinu. Osi X predstavuje HDP, ktoré vyjadruje veľkosť ekonomiky, a os Y mieru nezamestnanosti v %.

Z grafu môžeme vidieť, že krajiny s vyšším HDP majú nižšiu mieru nezamestnanosti, aj keď vzťah nie je veľmi silný. Body v pravej časti grafu predstavujú “bohatšie krajiny” sa nachádzajú nižšie na osi Y, čo znamená mierne negatívnu závislosť medzi ekonomickým výkonom a nezamestnanosťou. Tento vzťah zároveň potvrdzuje trendová čiara, ktorá mierne klesá, čo znamená, že s rastom HDP, nezamestnanosť klesá.

library(dplyr)

udaje.2018 <- udaje %>%
  filter(Year== 2018) %>%
  select(Country.Name, GDP..in.USD., Unemployment.Rate,
Employment.Sector..Agriculture, Employment.Sector..Industry, Employment.Sector..Services)
library(dplyr)

cols_to_num <- c(
  "GDP..in.USD.",
  "Unemployment.Rate",
  "Employment.Sector..Agriculture",
  "Employment.Sector..Industry",
  "Employment.Sector..Services"
)

udaje.2018 <- udaje.2018 %>%
  mutate(across(all_of(cols_to_num), ~ {
    x <- gsub("\\s+", "", .x)        # odstráni medzery
    x <- gsub(",", ".", x)           # nahradí európske desatinné čiarky
    as.numeric(x)                    # prevedie na číslo
  })) %>%
  filter(!is.na(GDP..in.USD.), !is.na(Unemployment.Rate))
library(ggplot2)
library(scales)

ggplot(udaje.2018, aes(x = GDP..in.USD., y = Unemployment.Rate)) +
  geom_point(color = "pink", size = 4, alpha = 0.9) +   # väčšie a jemne priesvitné body
  geom_smooth(method = "lm", se = TRUE, color = "darkblue") +      # regresná priamka
  scale_x_log10(
    labels = label_number(scale_cut = cut_si(""))                 # nové formátovanie čísel (tisíce, milióny, miliardy)
  ) +
  theme_minimal(base_size = 14) +
  labs(
    title = "Vzťah medzi HDP a mierou nezamestnanosti (2018)",
    
    x = "HDP (v USD, logaritmická os)",
    y = "Miera nezamestnanosti (%)"
  )

Graf 2: Vzťah medzi podielom poľnohospodárstva a priemyslu (2013)

Graf znázorňuje vzťah medzi podielom zamestnanosti v poľnohospodárstve a v priemysle v roku 2013. Každý bod predstavuje jednu krajinu. Na osi X je podiel pracovníkov v poľnohospodárstve (%) a na osi Y podiel pracovníkov v priemysle (%).

Z grafu možno vyčítať, že medzi oboma sektormi existuje mierne negatívna závislosť. Krajiny s vyšším podielom poľnohospodárstva majú nižší podiel priemyslu. To poukazuje na odlišnú ekonomickú štruktúru menej rozvinutých krajín, ktoré sú viac zamerané na agrárnu výrobu, zatiaľ čo rozvinutejšie štáty majú väčší podiel priemyselnej výroby.

Trendová čiara tento vzťah potvrdzuje.

ggplot(udaje.2013, aes(x = Employment.Sector..Agriculture, y = Employment.Sector..Industry)) +
  geom_point(color = "darkorange", size = 3, alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, color = "brown") +
  theme_minimal(base_size = 14) +
  labs(
    title = "Vzťah medzi podielom poľnohospodárstva a priemyslu (2013)",
    x = "Podiel poľnohospodárstva (%)",
    y = "Podiel priemyslu (%)"
  )

NA
NA

Graf 3: Vývoj miery nezamestnanosti podľa rokov (1991–2022)

Graf znázorňuje rozdelenie miery nezamestnanosti medzi krajinami v rokoch 1991- 2022. (roky sú označené poslednými 2 číslicami) Každý box predstavuje rozptyl hodnôt nezamestnanosti v danom roku, čiara v strede boxu znázorňuje medián, horný a dolný okraj ukazujú rozsah hodnôt a bodky predstavujú krajiny s extrémne vysokou nezamestnanosťou.

Z grafu vidíme, že v 90. rokoch boli medzi krajinami väčšie rozdiely. Po roku 2008, v období hospodárskej krízy, sa nezamestnanosť v niektorých krajinách výrazne zvýšila. Po roku 2010 sa situácia stabilizovala a nezamestnanosť v priemere klesala a rozdiely medzi krajinami sa zmenšovali, čiže sa jedná o zlepšenie situácie na trhu práce.

library(ggplot2)
library(dplyr)

# vyčistenie čísel 
udaje <- udaje %>%
  mutate(Unemployment.Rate = as.numeric(gsub(",", ".", Unemployment.Rate)))
rok_labels <- setNames(
  substr(unique(udaje$Year), 3, 4),   # vyber len 3. a 4. znak,
  unique(udaje$Year)
)

# GRAF
ggplot(udaje, aes(x = factor(Year), y = Unemployment.Rate)) +
  geom_boxplot(fill = "lightblue", color = "darkblue", alpha = 0.7, outlier.alpha = 0.25) +
  scale_x_discrete(labels = rok_labels) +

  theme_minimal(base_size = 14) +
  theme(axis.text.x = element_text(angle = 0, vjust = 0.5, hjust = 0.5)) +
  labs(
    title = "Rozdelenie miery nezamestnanosti podľa rokov",
    subtitle = "Roky sú označené poslednými dvoma číslicami ( 91 = 1991)",
    x = "Rok",
    y = "Miera nezamestnanosti (%)"
  )

NA
NA
NA
install.packages("kableExtra")
library(dplyr)
library(knitr)
library(kableExtra)

# Summarise basic statistics
GDP.stats <- udaje %>%
  filter(Year %in% 2013:2016) %>%
  group_by(Year) %>%
  summarise(
    n      = n(),
    mean   = mean(GDP..in.USD., na.rm = TRUE),
    sd     = sd(GDP..in.USD., na.rm = TRUE),
    min    = min(GDP..in.USD., na.rm = TRUE),
    q25    = quantile(GDP..in.USD., 0.25, na.rm = TRUE),
    median = median(GDP..in.USD., na.rm = TRUE),
    q75    = quantile(GDP..in.USD., 0.75, na.rm = TRUE),
    max    = max(GDP..in.USD., na.rm = TRUE),
    .groups = "drop"
  )
library(dplyr)
library(knitr)
library(kableExtra)

GDP.stats %>%
  mutate(across(-c(Year, n), ~ . / 1e9)) %>%                    # prepočet na miliardy
  kbl(
    digits = 1,
    caption = "Basic statistics of GDP (billion USD, 2013–2016)",
    col.names = c("Year","n","Mean","SD","Min","Q25","Median","Q75","Max")
  ) %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped","hover","condensed")) %>%
  column_spec(1, bold = TRUE) %>%
  row_spec(0, bold = TRUE, background = "#f2f2f2") %>%
  add_header_above(c(" " = 2, "GDP (billions USD)" = 7))
Basic statistics of GDP (billion USD, 2013–2016)
GDP (billions USD)
Year n Mean SD Min Q25 Median Q75 Max
2013 182 425.0 1565.3 0.3 12.0 41.6 236.1 16880.7
2014 182 436.8 1637.9 0.3 12.3 45.8 233.8 17608.1
2015 181 412.8 1677.1 0.3 11.4 41.3 195.1 18295.0
2016 180 421.9 1726.1 0.3 11.2 38.9 214.4 18804.9
NA
NA

Testovanie hypotéz

t-test: Porovnanie miery nezamestnanosti v rokoch 2010 a 2020

Výsledky t-testu ukazujú, že rozdiel medzi priemernou mierou nezamestnanosti v rokoch 2010 a 2020 nie je štatisticky významný (t = 0.08, p = 0.94).
Priemerná nezamestnanosť v roku 2010 bola 8.36 %, zatiaľ čo v roku 2020 8.31 %.

čo znamená, že nie je možné tvrdiť, že sa nezamestnanosť medzi rokmi 2010 a 2020 významne zmenila.

t.test.result <- t.test(
  udaje$Unemployment.Rate[udaje$Year == 2010],
  udaje$Unemployment.Rate[udaje$Year == 2020],
  alternative = "two.sided"
)

print(t.test.result)

    Welch Two Sample t-test

data:  udaje$Unemployment.Rate[udaje$Year == 2010] and udaje$Unemployment.Rate[udaje$Year == 2020]
t = 0.077014, df = 359.87, p-value = 0.9387
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -1.217566  1.316816
sample estimates:
mean of x mean of y 
 8.360536  8.310911 

ANOVA: Rozdiely medzi rokmi 2015–2021

Výsledky ANOVA testu (F = 0.78, p = 0.59) naznačujú, že rozdiely v priemernej nezamestnanosti medzi analyzovanými rokmi nie sú štatisticky významné. Z toho vyplýva, že v sledovanom období sa nezamestnanosť naprieč krajinami výrazne nemenila.

anova.result <- aov(Unemployment.Rate ~ factor(Year), data = udaje %>% filter(Year %in% 2015:2021))
summary(anova.result)
               Df Sum Sq Mean Sq F value Pr(>F)
factor(Year)    6    166   27.65   0.778  0.588
Residuals    1250  44444   35.56               

Lineárna regresia: Faktory ovplyvňujúce nezamestnanosť

Model lineárnej regresie skúmal, ako HDP a štruktúra zamestnanosti (poľnohospodárstvo, služby) ovplyvňujú mieru nezamestnanosti v roku 2018.

Výsledky ukazujú, že premenná HDP (v logaritmickej stupnici) má štatisticky významný negatívny vplyv na mieru nezamestnanosti. To znamená, že krajiny s vyšším HDP majú spravidla nižšiu nezamestnanosť.

Podiel poľnohospodárstva (-0.068) a služieb (0.014) neboli štatisticky významné.

Model ako celok je štatisticky významný (p < 0.001), avšak na nezamestnanosť vplývajú aj iné faktory, ktoré model nezahŕňa (napr. vzdelanosť, ekonomická politika, regionálne špecifiká).

model <- lm(Unemployment.Rate ~ log10(GDP..in.USD.) +
               Employment.Sector..Agriculture +
               Employment.Sector..Services,
             data = udaje %>% filter(Year == 2018))

summary(model)

Call:
lm(formula = Unemployment.Rate ~ log10(GDP..in.USD.) + Employment.Sector..Agriculture + 
    Employment.Sector..Services, data = udaje %>% filter(Year == 
    2018))

Residuals:
   Min     1Q Median     3Q    Max 
-8.346 -3.551 -1.740  2.472 20.495 

Coefficients:
                               Estimate Std. Error t value Pr(>|t|)    
(Intercept)                    27.99484    8.09908   3.457 0.000686 ***
log10(GDP..in.USD.)            -1.84597    0.49792  -3.707 0.000280 ***
Employment.Sector..Agriculture -0.06826    0.05732  -1.191 0.235343    
Employment.Sector..Services     0.01431    0.06662   0.215 0.830200    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.554 on 176 degrees of freedom
Multiple R-squared:  0.1059,    Adjusted R-squared:  0.09066 
F-statistic: 6.949 on 3 and 176 DF,  p-value: 0.0001906
install.packages("broom")
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/backports_1.5.0.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/purrr_1.1.0.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/tidyr_1.3.1.tar.gz'
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/broom_1.0.10.tar.gz'

The downloaded source packages are in
    ‘/tmp/RtmpSSBS6W/downloaded_packages’
library(broom)
library(stringr)

# 1️⃣ Tabuľka koeficientov
coef.tbl <- tidy(model, conf.int = TRUE) %>%
  mutate(
    term = recode(term,
      "(Intercept)" = "Intercept",
      "log10(GDP..in.USD.)" = "log10(HDP)",
      "Employment.Sector..Agriculture" = "Poľnohospodárstvo (%)",
      "Employment.Sector..Services" = "Služby (%)"
    ),
    stars = case_when(
      p.value < 0.001 ~ "***",
      p.value < 0.01  ~ "**",
      p.value < 0.05  ~ "*",
      p.value < 0.1   ~ "·",
      TRUE            ~ ""
    )
  ) %>%
  transmute(
    Premenná = term,
    Odhad = round(estimate, 3),
    `Štandardná chyba` = round(std.error, 3),
    `t-hodnota` = round(statistic, 3),
    `p-hodnota` = round(p.value, 4),
    `95% CI` = str_c("[", round(conf.low, 2), ", ", round(conf.high, 2), "]"),
    Významnosť = stars
  )

coef.tbl %>%
  kable(
    digits = 3,
    caption = "Odhady regresných koeficientov (model: nezamestnanosť ~ HDP + štruktúra sektora)"
  ) %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed")) %>%
  column_spec(1, bold = TRUE) %>%
  row_spec(0, bold = TRUE, background = "#f2f2f2") %>%
  footnote(
    general = "Signif. codes: *** p<0.001, ** p<0.01, * p<0.05, · p<0.1.",
    threeparttable = TRUE
  )
Odhady regresných koeficientov (model: nezamestnanosť ~ HDP + štruktúra sektora)
Premenná Odhad Štandardná chyba t-hodnota p-hodnota 95% CI Významnosť
Intercept 27.995 8.099 3.457 0.001 [12.01, 43.98] ***
log10(HDP) -1.846 0.498 -3.707 0.000 [-2.83, -0.86] ***
Poľnohospodárstvo (%) -0.068 0.057 -1.191 0.235 [-0.18, 0.04]
Služby (%) 0.014 0.067 0.215 0.830 [-0.12, 0.15]
Note:
Signif. codes: *** p<0.001, ** p<0.01, * p<0.05, · p<0.1.
NA
fit.tbl <- glance(model) %>%
  transmute(
    `R-squared` = round(r.squared, 3),
    `Adj. R-squared` = round(adj.r.squared, 3),
    `F-statistic` = round(statistic, 3),
    `F p-value` = round(p.value, 4),
    `AIC` = round(AIC, 1),
    `BIC` = round(BIC, 1),
    `Počet pozorovaní` = nobs
  )

fit.tbl %>%
  kable(
    digits = 3,
    caption = "Štatistiky prispôsobenia modelu"
  ) %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("condensed"))
Štatistiky prispôsobenia modelu
R-squared Adj. R-squared F-statistic F p-value AIC BIC Počet pozorovaní
0.106 0.091 6.949 0 1134 1149.9 180
NA

Bonus: Heatmap korelačnej matice

Na obrázku je zobrazená korelačná matica numerických premenných: HDP, miera nezamestnanosti a podiely jednotlivých sektorov hospodárstva. Z grafu vieme vyčítať, že HDP pozitívne koreluje s podielom sektora služieb a negatívne s poľnohospodárstvom. To znamená, že bohatšie krajiny majú väčší sektor služieb a menší agrárny sektor.

Miera nezamestnanosti má slabú až mierne negatívnu koreláciu s HDP, čo potvrdzuje trend pozorovaný v predchádzajúcich grafoch. vyšší ekonomický výkon krajiny súvisí s nižšou nezamestnanosťou.
Vzťahy medzi sektormi sú navzájom výrazne negatívne a nárast jedného sektora zvyčajne znamená pokles druhého.


library(ggplot2)
library(reshape2)
library(viridis)

# Vyberieme len numerické stĺpce
num_data <- udaje %>%
  select(GDP..in.USD., Unemployment.Rate,
         Employment.Sector..Agriculture,
         Employment.Sector..Industry,
         Employment.Sector..Services)

# Korelačná matica (Pearsonova korelácia)
corr <- cor(num_data, use = "complete.obs")

corr_melt <- melt(corr)

# Vykreslenie Heatmapy
ggplot(corr_melt, aes(x = Var1, y = Var2, fill = value)) +
  geom_tile(color = "white") +
  geom_text(aes(label = round(value, 2)), color = "white", size = 4) +
  scale_fill_viridis(option = "plasma", direction = -1, limits = c(-1, 1)) +
  theme_minimal(base_size = 14) +
  labs(
    title = "Heatmap korelačnej matice numerických veličín",
    subtitle = "Zobrazenie vzťahov medzi HDP, nezamestnanosťou a sektorovou štruktúrou",
    x = "",
    y = "",
    fill = "Korelácia"
  ) +
  theme(axis.text.x = element_text(angle = 30, vjust = 1, hjust = 1))

LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSAtIGltcG9ydCDDumRham92LCBncmFmeSwgxaF0YXRpc3Rpa3kiCmF1dGhvcjogIkzDrXZpYSBNZWxpY2hvdsOhIgpkYXRlOiAiT2N0b2JlciAyMDI1IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCjxzdHlsZT4KYm9keSB7CiAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDEyMGRlZywgI2ZmZTZmMCAwJSwgI2ZmZjhmYiAxMDAlKTsKICBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoJ2h0dHBzOi8vd3d3Lmdvb2dsZS5jb20vdXJsP3NhPWkmdXJsPWh0dHBzJTNBJTJGJTJGd3d3LmRvdmlkby5jeiUyRk1hcHktMjUyJTJGT2JyYXotYmFyZXZuYS1tYXBhLXN2ZXRhJnBzaWc9QU92VmF3MnJ4ZE1tSUtmaUhkTGlpWmlKSHpFViZ1c3Q9MTc2MDgyNzQxNzk1NTAwMCZzb3VyY2U9aW1hZ2VzJmNkPXZmZSZvcGk9ODk5Nzg0NDkmdmVkPTBDQklRalJ4cUZ3b1RDS2lzN3JpbnJKQURGUUFBQUFBZEFBQUFBQkFmJyk7CiAgYmFja2dyb3VuZC1yZXBlYXQ6IHJlcGVhdDsKICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiBjZW50ZXIgdG9wOwogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsKICBjb2xvcjogIzNjMmEzYTsKICBmb250LWZhbWlseTogIkNvbWljIFNhbnMgTVMiLCAiU2Vnb2UgVUkiLCBzYW5zLXNlcmlmOwp9Cjwvc3R5bGU+CjxzdHlsZT4KaDEsIGgyLCBoMywgaDQsIGg1LCBoNiB7CiAgY29sb3I6ICNlNzU0ODA7IC8qIHJ1xb5vdsOhICovCn0KPC9zdHlsZT4KCgojIFRlc3RvdmFuaWUgaHlwb3TDqXoKCiMjIMOadm9kIGEgcG9waXMgZGF0YWLDoXp5CgpWIHRlanRvIMSNYXN0aSBzYSB0ZXN0dWrDuiDFoXRhdGlzdGlja8OpIGh5cG90w6l6eSBwb21vY291IMO6ZGFqb3YgeiBkYXRhYsOhenksIGt0b3LDoSBvYnNhaHVqZSBla29ub21pY2vDqSB1a2F6b3ZhdGVsZSBrcmFqw61uIHYgcm9rb2NoIDE5OTEg4oCTIDIwMjIuIApQb3XFvml0w6kgcHJlbWVubsOpIHphaMWVxYhhasO6IGhydWLDvSBkb23DoWNpIHByb2R1a3QgKEhEUCkgdiBVU0QsIG1pZXJ1IG5lemFtZXN0bmFub3N0aSAoJSkgYSDFoXRydWt0w7pydSB6YW1lc3RuYW5vc3RpIHYgdHJvY2ggc2VrdG9yb2NoIOKAkyBwb8S+bm9ob3Nwb2TDoXJzdHZlLCBwcmllbXlzbGUgYSBzbHXFvmLDoWNoLgoKCgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoImtuaXRyIikKaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKYGBgCgpgYGB7cn0KIyBJbXBvcnQgdmxhc3Ruw6lobyBDU1Ygc8O6Ym9ydQoKdWRhamUgPC0gcmVhZC5jc3YoIkVtcGxveW1lbnRfVW5lbXBsb3ltZW50X0dEUF9kYXRhLmNzdiIsCmhlYWRlciA9IFRSVUUsCnNlcCA9ICIsIiwKZGVjID0gIiAiLApzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojIFpvYnJhemVuaWUgcHJ2w71jaCByaWFka292IGEgbsOhenZvdiBzdMS6cGNvdgoKaGVhZCh1ZGFqZSkKY29sbmFtZXModWRhamUpCgpgYGAKYGBge3J9CmxpYnJhcnkoZHBseXIpCgojIPCfp7kgVnnEjWlzdGVuaWUgYSBwcmV0eXBvdmFuaWUgdsWhZXRrw71jaCDEjcOtc2VsbsO9Y2ggc3TEunBjb3YKdWRhamUgPC0gdWRhamUgJT4lCiAgbXV0YXRlKGFjcm9zcygKICAgIGMoR0RQLi5pbi5VU0QuLCBVbmVtcGxveW1lbnQuUmF0ZSwKICAgICAgRW1wbG95bWVudC5TZWN0b3IuLkFncmljdWx0dXJlLAogICAgICBFbXBsb3ltZW50LlNlY3Rvci4uSW5kdXN0cnksCiAgICAgIEVtcGxveW1lbnQuU2VjdG9yLi5TZXJ2aWNlcyksCiAgICB+IGFzLm51bWVyaWMoZ3N1YigiLCIsICIuIiwgZ3N1YigiXFxzKyIsICIiLCAueCkpKQogICkpCgpgYGAKCgoKCgojIyBHcmFmIDE6IFZ6xaVhaCBtZWR6aSBIRFAgYSBtaWVyb3UgbmV6YW1lc3RuYW5vc3RpICgyMDE4KQoKR3JhZiB6b2JyYXp1amUgdnrFpWFoIG1lZHppIGhydWLDvW0gZG9tw6FjaW0gcHJvZHVrdG9tIChIRFApIHYgVVNEIGEgbWllcm91IG5lemFtZXN0bmFub3N0aSBwcmUgamVkbm90bGl2w6kga3JhamlueSB2IHJva3UgMjAxOC4gCkthxb5kw70gYm9kIHByZWRzdGF2dWplIGplZG51IGtyYWppbnUuIE9zaSBYIHByZWRzdGF2dWplIEhEUCwga3RvcsOpIHZ5amFkcnVqZSB2ZcS+a29zxaUgZWtvbm9taWt5LCBhIG9zIFkgbWllcnUgbmV6YW1lc3RuYW5vc3RpIHYgJS4gCgpaIGdyYWZ1IG3DtMW+ZW1lIHZpZGllxaUsIMW+ZSBrcmFqaW55IHMgdnnFocWhw61tIEhEUCBtYWrDuiBuacW+xaFpdSBtaWVydSBuZXphbWVzdG5hbm9zdGksIGFqIGtlxI8gdnrFpWFoIG5pZSBqZSB2ZcS+bWkgc2lsbsO9LiAKQm9keSB2IHByYXZlaiDEjWFzdGkgZ3JhZnUgcHJlZHN0YXZ1asO6ICJib2hhdMWhaWUga3JhamlueSIgc2EgbmFjaMOhZHphasO6IG5pxb7FoWllIG5hIG9zaSBZLCDEjW8gem5hbWVuw6EgbWllcm5lIG5lZ2F0w612bnUgesOhdmlzbG9zxaUgbWVkemkgZWtvbm9taWNrw71tIHbDvWtvbm9tIGEgbmV6YW1lc3RuYW5vc8Wlb3UuIApUZW50byB2esWlYWggesOhcm92ZcWIIHBvdHZyZHp1amUgdHJlbmRvdsOhIMSNaWFyYSwga3RvcsOhIG1pZXJuZSBrbGVzw6EsIMSNbyB6bmFtZW7DoSwgxb5lIHMgcmFzdG9tIEhEUCwgbmV6YW1lc3RuYW5vc8WlIGtsZXPDoS4KCgpgYGB7cn0KbGlicmFyeShkcGx5cikKCnVkYWplLjIwMTggPC0gdWRhamUgJT4lCiAgZmlsdGVyKFllYXI9PSAyMDE4KSAlPiUKICBzZWxlY3QoQ291bnRyeS5OYW1lLCBHRFAuLmluLlVTRC4sIFVuZW1wbG95bWVudC5SYXRlLApFbXBsb3ltZW50LlNlY3Rvci4uQWdyaWN1bHR1cmUsIEVtcGxveW1lbnQuU2VjdG9yLi5JbmR1c3RyeSwgRW1wbG95bWVudC5TZWN0b3IuLlNlcnZpY2VzKQpgYGAKCgpgYGB7cn0KbGlicmFyeShkcGx5cikKCmNvbHNfdG9fbnVtIDwtIGMoCiAgIkdEUC4uaW4uVVNELiIsCiAgIlVuZW1wbG95bWVudC5SYXRlIiwKICAiRW1wbG95bWVudC5TZWN0b3IuLkFncmljdWx0dXJlIiwKICAiRW1wbG95bWVudC5TZWN0b3IuLkluZHVzdHJ5IiwKICAiRW1wbG95bWVudC5TZWN0b3IuLlNlcnZpY2VzIgopCgp1ZGFqZS4yMDE4IDwtIHVkYWplLjIwMTggJT4lCiAgbXV0YXRlKGFjcm9zcyhhbGxfb2YoY29sc190b19udW0pLCB+IHsKICAgIHggPC0gZ3N1YigiXFxzKyIsICIiLCAueCkgICAgICAgICMgb2RzdHLDoW5pIG1lZHplcnkKICAgIHggPC0gZ3N1YigiLCIsICIuIiwgeCkgICAgICAgICAgICMgbmFocmFkw60gZXVyw7Nwc2tlIGRlc2F0aW5uw6kgxI1pYXJreQogICAgYXMubnVtZXJpYyh4KSAgICAgICAgICAgICAgICAgICAgIyBwcmV2ZWRpZSBuYSDEjcOtc2xvCiAgfSkpICU+JQogIGZpbHRlcighaXMubmEoR0RQLi5pbi5VU0QuKSwgIWlzLm5hKFVuZW1wbG95bWVudC5SYXRlKSkKCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc2NhbGVzKQoKZ2dwbG90KHVkYWplLjIwMTgsIGFlcyh4ID0gR0RQLi5pbi5VU0QuLCB5ID0gVW5lbXBsb3ltZW50LlJhdGUpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICJwaW5rIiwgc2l6ZSA9IDQsIGFscGhhID0gMC45KSArICAgIyB2w6TEjcWhaWUgYSBqZW1uZSBwcmllc3ZpdG7DqSBib2R5CiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBUUlVFLCBjb2xvciA9ICJkYXJrYmx1ZSIpICsgICAgICAjIHJlZ3Jlc27DoSBwcmlhbWthCiAgc2NhbGVfeF9sb2cxMCgKICAgIGxhYmVscyA9IGxhYmVsX251bWJlcihzY2FsZV9jdXQgPSBjdXRfc2koIiIpKSAgICAgICAgICAgICAgICAgCiAgKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJWesWlYWggbWVkemkgSERQIGEgbWllcm91IG5lemFtZXN0bmFub3N0aSAoMjAxOCkiLAogICAgCiAgICB4ID0gIkhEUCAodiBVU0QsIGxvZ2FyaXRtaWNrw6Egb3MpIiwKICAgIHkgPSAiTWllcmEgbmV6YW1lc3RuYW5vc3RpICglKSIKICApCmBgYAoKIyMgR3JhZiAyOiBWesWlYWggbWVkemkgcG9kaWVsb20gcG/Evm5vaG9zcG9kw6Fyc3R2YSBhIHByaWVteXNsdSAoMjAxMykKCkdyYWYgem7DoXpvcsWIdWplIHZ6xaVhaCBtZWR6aSBwb2RpZWxvbSB6YW1lc3RuYW5vc3RpIHYgcG/Evm5vaG9zcG9kw6Fyc3R2ZSBhIHYgcHJpZW15c2xlIHYgcm9rdSAyMDEzLiAKS2HFvmTDvSBib2QgcHJlZHN0YXZ1amUgamVkbnUga3JhamludS4gTmEgb3NpIFggamUgcG9kaWVsIHByYWNvdm7DrWtvdiB2IHBvxL5ub2hvc3BvZMOhcnN0dmUgKCUpIGEgbmEgb3NpIFkgcG9kaWVsIHByYWNvdm7DrWtvdiB2IHByaWVteXNsZSAoJSkuICAKClogZ3JhZnUgbW/Fvm5vIHZ5xI3DrXRhxaUsIMW+ZSBtZWR6aSBvYm9tYSBzZWt0b3JtaSBleGlzdHVqZSBtaWVybmUgbmVnYXTDrXZuYSB6w6F2aXNsb3PFpS4gS3JhamlueSBzIHZ5xaHFocOtbSBwb2RpZWxvbSBwb8S+bm9ob3Nwb2TDoXJzdHZhIG1hasO6IG5pxb7FocOtIHBvZGllbCBwcmllbXlzbHUuIApUbyBwb3VrYXp1amUgbmEgb2RsacWhbsO6IGVrb25vbWlja8O6IMWhdHJ1a3TDunJ1IG1lbmVqIHJvenZpbnV0w71jaCBrcmFqw61uLCAKa3RvcsOpIHPDuiB2aWFjIHphbWVyYW7DqSBuYSBhZ3LDoXJudSB2w71yb2J1LCB6YXRpYcS+IMSNbyByb3p2aW51dGVqxaFpZSDFoXTDoXR5IG1hasO6IHbDpMSNxaHDrSBwb2RpZWwgcHJpZW15c2VsbmVqIHbDvXJvYnkuICAKClRyZW5kb3bDoSDEjWlhcmEgdGVudG8gdnrFpWFoIHBvdHZyZHp1amUuCgoKCmBgYHtyfQpnZ3Bsb3QodWRhamUuMjAxMywgYWVzKHggPSBFbXBsb3ltZW50LlNlY3Rvci4uQWdyaWN1bHR1cmUsIHkgPSBFbXBsb3ltZW50LlNlY3Rvci4uSW5kdXN0cnkpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICJkYXJrb3JhbmdlIiwgc2l6ZSA9IDMsIGFscGhhID0gMC43KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYnJvd24iKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJWesWlYWggbWVkemkgcG9kaWVsb20gcG/Evm5vaG9zcG9kw6Fyc3R2YSBhIHByaWVteXNsdSAoMjAxMykiLAogICAgeCA9ICJQb2RpZWwgcG/Evm5vaG9zcG9kw6Fyc3R2YSAoJSkiLAogICAgeSA9ICJQb2RpZWwgcHJpZW15c2x1ICglKSIKICApCgoKYGBgCgoKCgojIyBHcmFmIDM6IFbDvXZvaiBtaWVyeSBuZXphbWVzdG5hbm9zdGkgcG9kxL5hIHJva292ICgxOTkx4oCTMjAyMikKCkdyYWYgem7DoXpvcsWIdWplIHJvemRlbGVuaWUgbWllcnkgbmV6YW1lc3RuYW5vc3RpIG1lZHppIGtyYWppbmFtaSB2IHJva29jaCAxOTkxLSAyMDIyLiAKKHJva3kgc8O6IG96bmHEjWVuw6kgcG9zbGVkbsO9bWkgMiDEjcOtc2xpY2FtaSkKS2HFvmTDvSBib3ggcHJlZHN0YXZ1amUgcm96cHR5bCBob2Ruw7R0IG5lemFtZXN0bmFub3N0aSB2IGRhbm9tIHJva3UsIMSNaWFyYSB2IHN0cmVkZSBib3h1IHpuw6F6b3LFiHVqZSBtZWRpw6FuLCAKaG9ybsO9IGEgZG9sbsO9IG9rcmFqIHVrYXp1asO6IHJvenNhaCBob2Ruw7R0IGEgYm9ka3kgcHJlZHN0YXZ1asO6IGtyYWppbnkgcyBleHRyw6ltbmUgdnlzb2tvdSBuZXphbWVzdG5hbm9zxaVvdS4gIAoKWiBncmFmdSB2aWTDrW1lLCDFvmUgdiA5MC4gcm9rb2NoIGJvbGkgbWVkemkga3JhamluYW1pIHbDpMSNxaFpZSByb3pkaWVseS4gUG8gcm9rdSAyMDA4LCB2IG9iZG9iw60gaG9zcG9kw6Fyc2tlaiBrcsOtenksIHNhIG5lemFtZXN0bmFub3PFpSB2IG5pZWt0b3LDvWNoIGtyYWppbsOhY2ggdsO9cmF6bmUgenbDvcWhaWxhLiAKUG8gcm9rdSAyMDEwIHNhIHNpdHXDoWNpYSBzdGFiaWxpem92YWxhIGEgbmV6YW1lc3RuYW5vc8WlIHYgcHJpZW1lcmUga2xlc2FsYSBhIHJvemRpZWx5IG1lZHppIGtyYWppbmFtaSBzYSB6bWVuxaFvdmFsaSwgCsSNacW+ZSBzYSBqZWRuw6EgbyB6bGVwxaFlbmllIHNpdHXDoWNpZSBuYSB0cmh1IHByw6FjZS4KCgoKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCgojIHZ5xI1pc3RlbmllIMSNw61zZWwgCnVkYWplIDwtIHVkYWplICU+JQogIG11dGF0ZShVbmVtcGxveW1lbnQuUmF0ZSA9IGFzLm51bWVyaWMoZ3N1YigiLCIsICIuIiwgVW5lbXBsb3ltZW50LlJhdGUpKSkKcm9rX2xhYmVscyA8LSBzZXROYW1lcygKICBzdWJzdHIodW5pcXVlKHVkYWplJFllYXIpLCAzLCA0KSwgICAjIHZ5YmVyIGxlbiAzLiBhIDQuIHpuYWssCiAgdW5pcXVlKHVkYWplJFllYXIpCikKCiMgR1JBRgpnZ3Bsb3QodWRhamUsIGFlcyh4ID0gZmFjdG9yKFllYXIpLCB5ID0gVW5lbXBsb3ltZW50LlJhdGUpKSArCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3IgPSAiZGFya2JsdWUiLCBhbHBoYSA9IDAuNywgb3V0bGllci5hbHBoYSA9IDAuMjUpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IHJva19sYWJlbHMpICsKCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMC41KSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJSb3pkZWxlbmllIG1pZXJ5IG5lemFtZXN0bmFub3N0aSBwb2TEvmEgcm9rb3YiLAogICAgeCA9ICJSb2siLAogICAgeSA9ICJNaWVyYSBuZXphbWVzdG5hbm9zdGkgKCUpIgogICkKCgoKYGBgCgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoImthYmxlRXh0cmEiKQpgYGAKCgpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShrbml0cikKbGlicmFyeShrYWJsZUV4dHJhKQoKIyBTdW1tYXJpc2UgYmFzaWMgc3RhdGlzdGljcwpHRFAuc3RhdHMgPC0gdWRhamUgJT4lCiAgZmlsdGVyKFllYXIgJWluJSAyMDEzOjIwMTYpICU+JQogIGdyb3VwX2J5KFllYXIpICU+JQogIHN1bW1hcmlzZSgKICAgIG4gICAgICA9IG4oKSwKICAgIG1lYW4gICA9IG1lYW4oR0RQLi5pbi5VU0QuLCBuYS5ybSA9IFRSVUUpLAogICAgc2QgICAgID0gc2QoR0RQLi5pbi5VU0QuLCBuYS5ybSA9IFRSVUUpLAogICAgbWluICAgID0gbWluKEdEUC4uaW4uVVNELiwgbmEucm0gPSBUUlVFKSwKICAgIHEyNSAgICA9IHF1YW50aWxlKEdEUC4uaW4uVVNELiwgMC4yNSwgbmEucm0gPSBUUlVFKSwKICAgIG1lZGlhbiA9IG1lZGlhbihHRFAuLmluLlVTRC4sIG5hLnJtID0gVFJVRSksCiAgICBxNzUgICAgPSBxdWFudGlsZShHRFAuLmluLlVTRC4sIDAuNzUsIG5hLnJtID0gVFJVRSksCiAgICBtYXggICAgPSBtYXgoR0RQLi5pbi5VU0QuLCBuYS5ybSA9IFRSVUUpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKYGBgCgoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoa2FibGVFeHRyYSkKCkdEUC5zdGF0cyAlPiUKICBtdXRhdGUoYWNyb3NzKC1jKFllYXIsIG4pLCB+IC4gLyAxZTkpKSAlPiUgICAgICAgICAgICAgICAgICAgICMgcHJlcG/EjWV0IG5hIG1pbGlhcmR5CiAga2JsKAogICAgZGlnaXRzID0gMSwKICAgIGNhcHRpb24gPSAiQmFzaWMgc3RhdGlzdGljcyBvZiBHRFAgKGJpbGxpb24gVVNELCAyMDEz4oCTMjAxNikiLAogICAgY29sLm5hbWVzID0gYygiWWVhciIsIm4iLCJNZWFuIiwiU0QiLCJNaW4iLCJRMjUiLCJNZWRpYW4iLCJRNzUiLCJNYXgiKQogICkgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsImhvdmVyIiwiY29uZGVuc2VkIikpICU+JQogIGNvbHVtbl9zcGVjKDEsIGJvbGQgPSBUUlVFKSAlPiUKICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgYmFja2dyb3VuZCA9ICIjZjJmMmYyIikgJT4lCiAgYWRkX2hlYWRlcl9hYm92ZShjKCIgIiA9IDIsICJHRFAgKGJpbGxpb25zIFVTRCkiID0gNykpCgoKYGBgCgoKIyBUZXN0b3ZhbmllIGh5cG90w6l6CgoKIyMgdC10ZXN0OiBQb3Jvdm5hbmllIG1pZXJ5IG5lemFtZXN0bmFub3N0aSB2IHJva29jaCAyMDEwIGEgMjAyMAoKVsO9c2xlZGt5IHQtdGVzdHUgdWthenVqw7osIMW+ZSByb3pkaWVsIG1lZHppIHByaWVtZXJub3UgbWllcm91IG5lemFtZXN0bmFub3N0aSB2IHJva29jaCAyMDEwIGEgMjAyMCBuaWUgamUgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70gKHQgPSAwLjA4LCBwID0gMC45NCkuICAKUHJpZW1lcm7DoSBuZXphbWVzdG5hbm9zxaUgdiByb2t1IDIwMTAgYm9sYSA4LjM2ICUsIHphdGlhxL4gxI1vIHYgcm9rdSAyMDIwIDguMzEgJS4gIAoKxI1vIHpuYW1lbsOhLCDFvmUgbmllIGplIG1vxb5uw6kgdHZyZGnFpSwgxb5lIHNhIG5lemFtZXN0bmFub3PFpSBtZWR6aSByb2ttaSAyMDEwIGEgMjAyMCB2w716bmFtbmUgem1lbmlsYS4gIAoKCmBgYHtyfQp0LnRlc3QucmVzdWx0IDwtIHQudGVzdCgKICB1ZGFqZSRVbmVtcGxveW1lbnQuUmF0ZVt1ZGFqZSRZZWFyID09IDIwMTBdLAogIHVkYWplJFVuZW1wbG95bWVudC5SYXRlW3VkYWplJFllYXIgPT0gMjAyMF0sCiAgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIgopCgpwcmludCh0LnRlc3QucmVzdWx0KQoKYGBgCgoKIyMgQU5PVkE6IFJvemRpZWx5IG1lZHppIHJva21pIDIwMTXigJMyMDIxCgpWw71zbGVka3kgQU5PVkEgdGVzdHUgKEYgPSAwLjc4LCBwID0gMC41OSkgbmF6bmHEjXVqw7osIMW+ZSByb3pkaWVseSB2IHByaWVtZXJuZWogbmV6YW1lc3RuYW5vc3RpIG1lZHppIGFuYWx5em92YW7DvW1pIHJva21pIApuaWUgc8O6IMWhdGF0aXN0aWNreSB2w716bmFtbsOpLgpaIHRvaG8gdnlwbMO9dmEsIMW+ZSB2IHNsZWRvdmFub20gb2Jkb2LDrSBzYSBuZXphbWVzdG5hbm9zxaUgbmFwcmllxI0ga3JhamluYW1pIHbDvXJhem5lIG5lbWVuaWxhLgoKCgoKYGBge3J9CmFub3ZhLnJlc3VsdCA8LSBhb3YoVW5lbXBsb3ltZW50LlJhdGUgfiBmYWN0b3IoWWVhciksIGRhdGEgPSB1ZGFqZSAlPiUgZmlsdGVyKFllYXIgJWluJSAyMDE1OjIwMjEpKQpzdW1tYXJ5KGFub3ZhLnJlc3VsdCkKCmBgYAoKCiMjIExpbmXDoXJuYSByZWdyZXNpYTogRmFrdG9yeSBvdnBseXbFiHVqw7pjZSBuZXphbWVzdG5hbm9zxaUKCk1vZGVsIGxpbmXDoXJuZWogcmVncmVzaWUgc2vDum1hbCwgYWtvIEhEUCBhIMWhdHJ1a3TDunJhIHphbWVzdG5hbm9zdGkgKHBvxL5ub2hvc3BvZMOhcnN0dm8sIHNsdcW+YnkpIG92cGx5dsWIdWrDuiBtaWVydSBuZXphbWVzdG5hbm9zdGkgdiByb2t1IDIwMTguCgpWw71zbGVka3kgdWthenVqw7osIMW+ZSBwcmVtZW5uw6EgSERQICh2IGxvZ2FyaXRtaWNrZWogc3R1cG5pY2kpIG3DoSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSBuZWdhdMOtdm55IHZwbHl2IG5hIG1pZXJ1IG5lemFtZXN0bmFub3N0aS4gClRvIHpuYW1lbsOhLCDFvmUga3JhamlueSBzIHZ5xaHFocOtbSBIRFAgbWFqw7ogc3ByYXZpZGxhIG5pxb7FoWl1IG5lemFtZXN0bmFub3PFpS4gIAoKUG9kaWVsIHBvxL5ub2hvc3BvZMOhcnN0dmEgKC0wLjA2OCkgYSBzbHXFvmllYiAoMC4wMTQpIG5lYm9saSDFoXRhdGlzdGlja3kgdsO9em5hbW7DqS4KCk1vZGVsIGFrbyBjZWxvayBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSAocCA8IDAuMDAxKSwgCmF2xaFhayBuYSBuZXphbWVzdG5hbm9zxaUgdnBsw712YWrDuiBhaiBpbsOpIGZha3RvcnksIGt0b3LDqSBtb2RlbCBuZXphaMWVxYhhIChuYXByLiB2emRlbGFub3PFpSwgZWtvbm9taWNrw6EgcG9saXRpa2EsIHJlZ2lvbsOhbG5lIMWhcGVjaWZpa8OhKS4KCmBgYHtyfQptb2RlbCA8LSBsbShVbmVtcGxveW1lbnQuUmF0ZSB+IGxvZzEwKEdEUC4uaW4uVVNELikgKwogICAgICAgICAgICAgICBFbXBsb3ltZW50LlNlY3Rvci4uQWdyaWN1bHR1cmUgKwogICAgICAgICAgICAgICBFbXBsb3ltZW50LlNlY3Rvci4uU2VydmljZXMsCiAgICAgICAgICAgICBkYXRhID0gdWRhamUgJT4lIGZpbHRlcihZZWFyID09IDIwMTgpKQoKc3VtbWFyeShtb2RlbCkKCmBgYAoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoImJyb29tIikKbGlicmFyeShicm9vbSkKbGlicmFyeShzdHJpbmdyKQoKIyAx77iP4oOjIFRhYnXEvmthIGtvZWZpY2llbnRvdgpjb2VmLnRibCA8LSB0aWR5KG1vZGVsLCBjb25mLmludCA9IFRSVUUpICU+JQogIG11dGF0ZSgKICAgIHRlcm0gPSByZWNvZGUodGVybSwKICAgICAgIihJbnRlcmNlcHQpIiA9ICJJbnRlcmNlcHQiLAogICAgICAibG9nMTAoR0RQLi5pbi5VU0QuKSIgPSAibG9nMTAoSERQKSIsCiAgICAgICJFbXBsb3ltZW50LlNlY3Rvci4uQWdyaWN1bHR1cmUiID0gIlBvxL5ub2hvc3BvZMOhcnN0dm8gKCUpIiwKICAgICAgIkVtcGxveW1lbnQuU2VjdG9yLi5TZXJ2aWNlcyIgPSAiU2x1xb5ieSAoJSkiCiAgICApLAogICAgc3RhcnMgPSBjYXNlX3doZW4oCiAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICBwLnZhbHVlIDwgMC4wMSAgfiAiKioiLAogICAgICBwLnZhbHVlIDwgMC4wNSAgfiAiKiIsCiAgICAgIHAudmFsdWUgPCAwLjEgICB+ICLCtyIsCiAgICAgIFRSVUUgICAgICAgICAgICB+ICIiCiAgICApCiAgKSAlPiUKICB0cmFuc211dGUoCiAgICBQcmVtZW5uw6EgPSB0ZXJtLAogICAgT2RoYWQgPSByb3VuZChlc3RpbWF0ZSwgMyksCiAgICBgxaB0YW5kYXJkbsOhIGNoeWJhYCA9IHJvdW5kKHN0ZC5lcnJvciwgMyksCiAgICBgdC1ob2Rub3RhYCA9IHJvdW5kKHN0YXRpc3RpYywgMyksCiAgICBgcC1ob2Rub3RhYCA9IHJvdW5kKHAudmFsdWUsIDQpLAogICAgYDk1JSBDSWAgPSBzdHJfYygiWyIsIHJvdW5kKGNvbmYubG93LCAyKSwgIiwgIiwgcm91bmQoY29uZi5oaWdoLCAyKSwgIl0iKSwKICAgIFbDvXpuYW1ub3PFpSA9IHN0YXJzCiAgKQoKY29lZi50YmwgJT4lCiAga2FibGUoCiAgICBkaWdpdHMgPSAzLAogICAgY2FwdGlvbiA9ICJPZGhhZHkgcmVncmVzbsO9Y2gga29lZmljaWVudG92IChtb2RlbDogbmV6YW1lc3RuYW5vc8WlIH4gSERQICsgxaF0cnVrdMO6cmEgc2VrdG9yYSkiCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKSAlPiUKICBjb2x1bW5fc3BlYygxLCBib2xkID0gVFJVRSkgJT4lCiAgcm93X3NwZWMoMCwgYm9sZCA9IFRSVUUsIGJhY2tncm91bmQgPSAiI2YyZjJmMiIpICU+JQogIGZvb3Rub3RlKAogICAgZ2VuZXJhbCA9ICJTaWduaWYuIGNvZGVzOiAqKiogcDwwLjAwMSwgKiogcDwwLjAxLCAqIHA8MC4wNSwgwrcgcDwwLjEuIiwKICAgIHRocmVlcGFydHRhYmxlID0gVFJVRQogICkKCmBgYAoKYGBge3J9CmZpdC50YmwgPC0gZ2xhbmNlKG1vZGVsKSAlPiUKICB0cmFuc211dGUoCiAgICBgUi1zcXVhcmVkYCA9IHJvdW5kKHIuc3F1YXJlZCwgMyksCiAgICBgQWRqLiBSLXNxdWFyZWRgID0gcm91bmQoYWRqLnIuc3F1YXJlZCwgMyksCiAgICBgRi1zdGF0aXN0aWNgID0gcm91bmQoc3RhdGlzdGljLCAzKSwKICAgIGBGIHAtdmFsdWVgID0gcm91bmQocC52YWx1ZSwgNCksCiAgICBgQUlDYCA9IHJvdW5kKEFJQywgMSksCiAgICBgQklDYCA9IHJvdW5kKEJJQywgMSksCiAgICBgUG/EjWV0IHBvem9yb3ZhbsOtYCA9IG5vYnMKICApCgpmaXQudGJsICU+JQogIGthYmxlKAogICAgZGlnaXRzID0gMywKICAgIGNhcHRpb24gPSAixaB0YXRpc3Rpa3kgcHJpc3DDtHNvYmVuaWEgbW9kZWx1IgogICkgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGJvb3RzdHJhcF9vcHRpb25zID0gYygiY29uZGVuc2VkIikpCgpgYGAKCiMjIyBCb251czogSGVhdG1hcCBrb3JlbGHEjW5laiBtYXRpY2UKCk5hIG9icsOhemt1IGplIHpvYnJhemVuw6Ega29yZWxhxI1uw6EgbWF0aWNhIG51bWVyaWNrw71jaCBwcmVtZW5uw71jaDogIEhEUCwgbWllcmEgbmV6YW1lc3RuYW5vc3RpIGEgcG9kaWVseSBqZWRub3RsaXbDvWNoIHNla3Rvcm92IGhvc3BvZMOhcnN0dmEuIApaIGdyYWZ1IHZpZW1lIHZ5xI3DrXRhxaUsIMW+ZSBIRFAgcG96aXTDrXZuZSBrb3JlbHVqZSBzIHBvZGllbG9tIHNla3RvcmEgc2x1xb5pZWIgYSBuZWdhdMOtdm5lIHMgcG/Evm5vaG9zcG9kw6Fyc3R2b20uIApUbyB6bmFtZW7DoSwgxb5lIGJvaGF0xaFpZSBrcmFqaW55IG1hasO6IHbDpMSNxaHDrSBzZWt0b3Igc2x1xb5pZWIgYSBtZW7FocOtIGFncsOhcm55IHNla3Rvci4gIAoKTWllcmEgbmV6YW1lc3RuYW5vc3RpIG3DoSBzbGFiw7ogYcW+IG1pZXJuZSBuZWdhdMOtdm51IGtvcmVsw6FjaXUgcyBIRFAsIArEjW8gcG90dnJkenVqZSB0cmVuZCBwb3pvcm92YW7DvSB2IHByZWRjaMOhZHphasO6Y2ljaCBncmFmb2NoLiAgdnnFocWhw60gZWtvbm9taWNrw70gdsO9a29uIGtyYWppbnkgc8O6dmlzw60gcyBuacW+xaFvdSBuZXphbWVzdG5hbm9zxaVvdS4gIApWesWlYWh5IG1lZHppIHNla3Rvcm1pIHPDuiBuYXZ6w6Fqb20gdsO9cmF6bmUgbmVnYXTDrXZuZSBhIG7DoXJhc3QgamVkbsOpaG8gc2VrdG9yYSB6dnnEjWFqbmUgem5hbWVuw6EgcG9rbGVzIGRydWjDqWhvLgoKCgpgYGB7cn0KCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeSh2aXJpZGlzKQoKIyBWeWJlcmllbWUgbGVuIG51bWVyaWNrw6kgc3TEunBjZQpudW1fZGF0YSA8LSB1ZGFqZSAlPiUKICBzZWxlY3QoR0RQLi5pbi5VU0QuLCBVbmVtcGxveW1lbnQuUmF0ZSwKICAgICAgICAgRW1wbG95bWVudC5TZWN0b3IuLkFncmljdWx0dXJlLAogICAgICAgICBFbXBsb3ltZW50LlNlY3Rvci4uSW5kdXN0cnksCiAgICAgICAgIEVtcGxveW1lbnQuU2VjdG9yLi5TZXJ2aWNlcykKCiMgS29yZWxhxI1uw6EgbWF0aWNhIChQZWFyc29ub3ZhIGtvcmVsw6FjaWEpCmNvcnIgPC0gY29yKG51bV9kYXRhLCB1c2UgPSAiY29tcGxldGUub2JzIikKCmNvcnJfbWVsdCA8LSBtZWx0KGNvcnIpCgojIFZ5a3Jlc2xlbmllIEhlYXRtYXB5CmdncGxvdChjb3JyX21lbHQsIGFlcyh4ID0gVmFyMSwgeSA9IFZhcjIsIGZpbGwgPSB2YWx1ZSkpICsKICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHZhbHVlLCAyKSksIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDQpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMob3B0aW9uID0gInBsYXNtYSIsIGRpcmVjdGlvbiA9IC0xLCBsaW1pdHMgPSBjKC0xLCAxKSkgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSGVhdG1hcCBrb3JlbGHEjW5laiBtYXRpY2UgbnVtZXJpY2vDvWNoIHZlbGnEjcOtbiIsCiAgICBzdWJ0aXRsZSA9ICJab2JyYXplbmllIHZ6xaVhaG92IG1lZHppIEhEUCwgbmV6YW1lc3RuYW5vc8Wlb3UgYSBzZWt0b3Jvdm91IMWhdHJ1a3TDunJvdSIsCiAgICB4ID0gIiIsCiAgICB5ID0gIiIsCiAgICBmaWxsID0gIktvcmVsw6FjaWEiCiAgKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgdmp1c3QgPSAxLCBoanVzdCA9IDEpKQoKYGBgCgo=