knitr::opts_chunk$set(
    echo = TRUE,
    message = FALSE,
    warning = FALSE
)

Ukážka databázy


head(world_population_data)              # pár prvých riadkov
colnames(world_population_data)          # názvy premenných
 [1] "rank"             "cca3"             "country"         
 [4] "continent"        "2023 population"  "2022 population" 
 [7] "2020 population"  "2015 population"  "2010 population" 
[10] "2000 population"  "1990 population"  "1980 population" 
[13] "1970 population"  "area (km²)"       "density (km²)"   
[16] "growth rate"      "world percentage"

Grafy

Výber a následné triedenie databázy, ktorú som obmedzila na dve premenné, a to krajiny Malta a Cyprus.

library(dplyr)

cyprus_malta_data <- world_population_data %>%
  filter(country == "Cyprus"| country == "Malta") %>%
  select(`cca3`, `2023 population`,`2022 population`, `2020 population`,`2015 population`, `2010 population`,`2000 population`,`1990 population`,`1980 population`,`1970 population`,`growth rate`,`world percentage`)
head(cyprus_malta_data)

Skontrolovanie štruktúry dát

colnames(cyprus_malta_data)
 [1] "cca3"             "2023 population"  "2022 population" 
 [4] "2020 population"  "2015 population"  "2010 population" 
 [7] "2000 population"  "1990 population"  "1980 population" 
[10] "1970 population"  "growth rate"      "world percentage"
head(cyprus_malta_data)

Scatter plot

# Basic scatter plot
library(dplyr)
library(tidyr)
library(ggplot2)

# 1. Vyberiem potrebné stĺpce a dáta len pre Cyprus a Maltu
cyprus_malta_sel <- cyprus_malta_data %>%
filter(cca3 %in% c("CYP", "MLT")) %>%  # Filtrovanie Cypru a Malty
select(cca3, `2023 population`, `2022 population`, `2020 population`, `2015 population`, `2010 population`,`2000 population`,`1990 population`,`1980 population`,`1970 population`) 

# 2. Premením dáta do dlhého formátu (pre graf)
cyprus_malta_long <- cyprus_malta_sel %>%
pivot_longer(cols = c(`2023 population`, `2022 population`, `2020 population`,`2015 population`,`2010 population`,`2000 population`,`1990 population`,`1980 population`,`1970 population`), names_to = "year",         
values_to = "population")  

# 3. Vytvorím graf - Zobrazím populáciu Cypru a Malty v rokoch 1970 - 2023
ggplot(cyprus_malta_long, aes(x = year, y = population, color = cca3, group = cca3)) +
  geom_line(size = 1) +    
  geom_point(size = 3) +   
  theme_minimal() +        
  labs(title = "Populácia Cypru a Malty v rokoch 1970 až 2023",
       x = "Rok",
       y = "Populácia",
       color = "Krajina") + theme(axis.text.x = element_text(angle = 45, hjust = 1))

scale_color_manual(values = c("CYP" = "lightpink", "MLT" = "skyblue"))  
<ggproto object: Class ScaleDiscrete, Scale, gg>
    aesthetics: colour
    axis_order: function
    break_info: function
    break_positions: function
    breaks: waiver
    call: call
    clone: function
    dimension: function
    drop: TRUE
    expand: waiver
    get_breaks: function
    get_breaks_minor: function
    get_labels: function
    get_limits: function
    get_transformation: function
    guide: legend
    is_discrete: function
    is_empty: function
    labels: waiver
    limits: function
    make_sec_title: function
    make_title: function
    map: function
    map_df: function
    minor_breaks: waiver
    n.breaks.cache: NULL
    na.translate: TRUE
    na.value: grey50
    name: waiver
    palette: function
    palette.cache: NULL
    position: left
    range: environment
    rescale: function
    reset: function
    train: function
    train_df: function
    transform: function
    transform_df: function
    super:  <ggproto object: Class ScaleDiscrete, Scale, gg>

Boxplot

Z dôvodu, že premenné populácie majú v konkrétnom roku iba jednu hodnotu je vyhotovenie boxplotu bezpredmetné, avšak nižšie uvádzam názornú ukážku.

library(ggplot2)
library(dplyr)
library(scales)  

# Filtrovanie len pre Cyprus a Maltu
cyprus_malta_long %>%
filter(cca3 %in% c("CYP", "MLT")) %>%
ggplot(aes(x = year, y = population, fill = cca3, color = cca3)) + geom_boxplot(alpha = 0.5, outlier.shape = 16, outlier.size = 2) +  
scale_fill_manual(values = c("CYP" = "lightpink", "MLT" = "lightblue")) + scale_color_manual(values = c("CYP" = "pink", "MLT" = "darkblue")) +  labs( title = "Populácia Cypru a Malty podľa rokov",
      x = "Rok",
      y = "Populácia",
      fill = "Krajina",
      color = "Krajina") + theme_minimal() + scale_y_continuous(labels = label_comma()) +  theme(axis.text.x = element_text(angle = 45, hjust = 1),  
      legend.position = "top",  
      plot.title = element_text(hjust = 0.5),  
      strip.text = element_text(size = 14), 
      axis.text = element_text(size = 12),  
      axis.title = element_text(size = 14)) +
    facet_wrap(~ cca3)

Základné štatistiky.

V nasledujúcej tabuľke zobrazujem výpočet základných štatistík Cypru a Malty. Je vypočítaný priemer populácie v rámci týchto dvoch krajín, minimálna a maximálna hodnota populácie, medián, smerodajná odchýlka či kvartily. Od roku 2010 do 2023 priemerná hodnota populácie stúpla z 774 220 na 897 601, čo je nárast asi o 16 %. Smerodajná odchýlka sa pohybuje okolo 500 000 vo všetkých rokoch, čo znamená, že variabilita hodnôt je pomerne veľká, ale relatívne stabilná v čase. Minimálne hodnoty stúpajú z 418 755 na 535 064, a maximá z 1 129 686 na 1 260 138. Celý rozsah hodnôt sa teda posúva smerom nahor, čo potvrdzuje všeobecný rast populácie daných krajín. Kvartily (Q25, Median, Q75) sa tiež postupne zvyšujú, čo znamená, že celé rozdelenie hodnôt sa posúva vyššie, nielen priemer.

library(dplyr)
library(tidyr)
library(knitr)

# Vyberiem Cyprus a Maltu a potrebné stĺpce
cyprus_malta_data <- world_population_data %>%
filter(country %in% c("Cyprus", "Malta")) %>%
select(cca3, `2023 population`, `2022 population`, `2020 population`, `2015 population`, `2010 population`, `2000 population`, `1990 population`, `1980 population`, `1970 population`, `growth rate`, `world percentage`)

# Premením do dlhého formátu, aby sme mali rok a populáciu v samostatných stĺpcoch
cyprus_malta_long <- cyprus_malta_data %>%
  pivot_longer(cols = ends_with("population"),
               names_to = "year",
               values_to = "population") %>%
  mutate(year = gsub(" population", "", year)) 

# Vyberiem len konkrétne roky na sumarizáciu (napr. 2010 až 2023)
selected_years <- c("2023", "2022", "2020", "2015", "2010")

# Vypočítam základné štatistiky pre každý rok (z oboch krajín)
pop_stats <- cyprus_malta_long %>%
  filter(year %in% selected_years) %>%
  group_by(year) %>%
  summarise(
    n      = n(),
    mean   = mean(population, na.rm = TRUE),
    sd     = sd(population, na.rm = TRUE),
    min    = min(population, na.rm = TRUE),
    q25    = quantile(population, 0.25, na.rm = TRUE),
    median = median(population, na.rm = TRUE),
    q75    = quantile(population, 0.75, na.rm = TRUE),
    max    = max(population, na.rm = TRUE),
    .groups = "drop")

# Vytvorenie peknej tabuľky
kable(pop_stats, digits = 0, caption = "**Základné štatistiky populácie pre Cyprus a Maltu** *(vybrané roky)*")
Základné štatistiky populácie pre Cyprus a Maltu (vybrané roky)
year n mean sd min q25 median q75 max
2010 2 774220 502704 418755 596488 774220 951953 1129686
2015 2 821930 516684 456579 639254 821930 1004605 1187280
2020 2 876447 510658 515357 695902 876447 1056992 1237537
2022 2 892387 507846 533286 712836 892387 1071938 1251488
2023 2 897601 512705 535064 716332 897601 1078870 1260138

tabuľku vieme vytvoriť i krajšiu s pomocou “kableExtra”:

library(dplyr)
library(knitr)
library(kableExtra)

# Vyberiem Cyprus a Maltu a potrebné stĺpce
cyprus_malta_data <- world_population_data %>%
filter(country %in% c("Cyprus", "Malta")) %>%
select(cca3, `2023 population`, `2022 population`, `2020 population`, `2015 population`, `2010 population`, `2000 population`, `1990 population`, `1980 population`, `1970 population`, `growth rate`, `world percentage`)

# Premením do dlhého formátu, aby sme mali rok a populáciu v samostatných stĺpcoch
cyprus_malta_long <- cyprus_malta_data %>%
 pivot_longer(cols = ends_with("population"),names_to = "year", values_to = "population") %>% mutate(year = gsub(" population", "", year)) 

# Vyberiem len konkrétne roky na sumarizáciu (napr. 2010 až 2023)
selected_years <- c("2023", "2022", "2020", "2015", "2010")

# Vypočítam základné štatistiky pre každý rok (z oboch krajín)
pop_stats <- cyprus_malta_long %>%
  filter(year %in% selected_years) %>%
  group_by(year) %>%
  summarise(
    n      = n(),
    mean   = mean(population, na.rm = TRUE),
    sd     = sd(population, na.rm = TRUE),
    min    = min(population, na.rm = TRUE),
    q25    = quantile(population, 0.25, na.rm = TRUE),
    median = median(population, na.rm = TRUE),
    q75    = quantile(population, 0.75, na.rm = TRUE),
    max    = max(population, na.rm = TRUE),
    .groups = "drop")

# Vytvorenie štýlovanej tabuľky s kableExtra
pop_stats %>%
  kable(digits = 0, caption = "Základné štatistiky populácie pre Cyprus a Maltu (vybrané roky)") %>%
  kable_styling(
    full_width = FALSE,
    bootstrap_options = c("striped", "hover", "condensed", "responsive"),
    position = "center",
    font_size = 13) %>%
  column_spec(1, bold = TRUE) %>%  # Tučný text pre rok
  row_spec(0, bold = TRUE, color = "purple", background = "pink") %>%
  add_header_above(c(" " = 2, "Štatistiky populácie" = 7), bold = TRUE, background = "pink", color = "black") %>%
  kable_paper("hover", full_width = FALSE) %>%
  kable_material(c("hover"))  
Základné štatistiky populácie pre Cyprus a Maltu (vybrané roky)
Štatistiky populácie
year n mean sd min q25 median q75 max
2010 2 774220 502704 418755 596488 774220 951953 1129686
2015 2 821930 516684 456579 639254 821930 1004605 1187280
2020 2 876447 510658 515357 695902 876447 1056992 1237537
2022 2 892387 507846 533286 712836 892387 1071938 1251488
2023 2 897601 512705 535064 716332 897601 1078870 1260138

Testovanie hypotéz

Nasledujúcimi príkazmi zisťujem, či sa priemerná populácia krajín na svete významne zmenila medzi rokmi 1970 a 2023. Na lepšiu vizualizáciu uvádzam boxplot, ktorý vizuálne ukazuje rozloženie populácie jednotlivých krajín v období medzi týmito dvoma rokmi – napríklad, že v roku 2023 majú krajiny všeobecne vyšší počet obyvateľov a väčšie rozdiely medzi nimi ako v roku 1970. Na uvedenom boxplote je taktiež možné sledovať extrémne hodnoty.

t-test: Porovnanie populácie krajín v rokoch 1970 a 2020

library(dplyr)
library(tidyr)
library(ggplot2)
library(scales)

# Prevedenie do long formátu
world_population_long <- world_population_data %>%
  pivot_longer(cols = ends_with("population"), names_to = "year", values_to = "population", names_pattern = "(\\d{4}) population") %>%
  mutate(year = as.numeric(year))

# t-test – porovnanie priemernej populácie krajín medzi rokmi 1970 a 2020
t.test.result <- t.test(world_population_long$population[world_population_long$year == 1970], world_population_long$population[world_population_long$year == 2023], paired = FALSE)

print(t.test.result)

    Welch Two Sample t-test

data:  world_population_long$population[world_population_long$year == 1970] and world_population_long$population[world_population_long$year == 2023]
t = -1.8559, df = 340.12, p-value = 0.06433
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -38287050   1112018
sample estimates:
mean of x mean of y 
 15786909  34374425 
# Boxplot – vizualizácia rozdielu medzi rokmi
world_population_long %>%
  filter(year %in% c(1970, 2023)) %>%
  ggplot(aes(x = factor(year), y = population, fill = factor(year))) +
  geom_boxplot(alpha = 0.7, outlier.shape = 16, outlier.size = 1.5) +
  scale_y_continuous(labels = label_comma()) +
  scale_fill_manual(values = c("1970" = "lightgreen", "2023" = "yellow")) +
  labs(
    title = "Porovnanie populácie krajín v rokoch 1970 a 2023",
    x = "Rok",
    y = "Populácia krajín") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, size = 16),
    axis.title = element_text(size = 13),
    axis.text = element_text(size = 11),
    legend.position = "none")

ANOVA

H0: Priemerná populácia krajín sa medzi rokmi nelíši.

H1: Aspoň v jednom roku sa priemerná populácia krajín líši od ostatných rokov.

# ANOVA – testovanie rozdielov priemernej populácie medzi rokmi
anova.result <- aov(population ~ factor(year), data = world_population_long)
summary(anova.result)
               Df    Sum Sq   Mean Sq F value Pr(>F)
factor(year)    8 8.987e+16 1.123e+16   0.831  0.576
Residuals    2097 2.836e+19 1.353e+16               

Výsledky ANOVY (F(8, 2097) = 0.831, p = 0.576) ukazujú, že medzi rokmi neexistujú štatisticky významné rozdiely. To znamená, že vývoj populácie podľa týchto údajov nepreukazuje systematický nárast alebo pokles v jednotlivých rokoch – zmeny možno považovať za náhodné, čím sa nulová hypotéza nezamieta, pretože nie je štatisticky významný dôkaz, že by sa priemerná populácia krajín medzi rokmi líšila.

Linear Regression

Lineárnou regresiou som skúmala vplyv roku, hustoty obyvateľstva a rozlohy krajiny na populáciu krajiny. Výsledky ukazujú, že model je štatisticky významný (F(3, 2102) = 188.3, p < 2.2e-16), čo znamená, že aspoň jedna z premenných má vplyv na populáciu.

Rok je významným prediktorom populácie, pričom každý ďalší rok je spojený s nárastom populácie približne o 355 500 obyvateľov.

Rozloha krajiny je najsilnejším faktorom; väčšie krajiny majú výrazne vyššiu populáciu (každý km² prispieva v priemere o 30 obyvateľov, p < 2e-16).

Hustota obyvateľstva nebola štatisticky významná (p = 0.814), teda podľa tohto modelu nemá významný vplyv na celkovú populáciu.

Model vysvetľuje približne 21 % variability v populácii krajín (R² = 0.2119), čo naznačuje, že existujú aj ďalšie faktory, ktoré ovplyvňujú veľkosť populácie, a ktoré nie sú zahrnuté v tomto modeli.

# Linearna regresia pre populáciu krajiny
model <- lm(population ~ year + `density (km²)` + `area (km²)`, data = world_population_long)

summary(model)

Call:
lm(formula = population ~ year + `density (km²)` + `area (km²)`, 
    data = world_population_long)

Residuals:
       Min         1Q     Median         3Q        Max 
-389069080  -15682655   -8548796     505115 1312368897 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)     -7.024e+08  2.454e+08  -2.862  0.00425 ** 
year             3.555e+05  1.225e+05   2.902  0.00375 ** 
`density (km²)`  2.680e+02  1.142e+03   0.235  0.81447    
`area (km²)`     3.022e+01  1.283e+00  23.556  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 103300000 on 2102 degrees of freedom
Multiple R-squared:  0.2119,    Adjusted R-squared:  0.2107 
F-statistic: 188.3 on 3 and 2102 DF,  p-value: < 2.2e-16
library(broom)
library(dplyr)
library(kableExtra)
library(stringr)
library(scales)  

model <- lm(population ~ year + `density (km²)` + `area (km²)`, data = world_population_long)

# Úprava výstupu a formátovanie
coef.tbl <- tidy(model, conf.int = TRUE) %>%
  mutate(
    term = recode(term,
      "(Intercept)" = "Intercept",
      "year" = "Rok",
      "`density (km²)`" = "Hustota obyvateľstva",
      "`area (km²)`" = "Rozloha"),
    stars = case_when(
      p.value < 0.001 ~ "***",
      p.value < 0.01  ~ "**",
      p.value < 0.05  ~ "*",
      p.value < 0.1   ~ "·",
      TRUE            ~ "." ),
    Estimate = label_comma()(estimate),
    `Std. Error` = label_comma()(std.error),
    `t value` = round(statistic, 2),
    `p value` = round(p.value, 4),
    `95% CI` = str_c("[", label_comma()(round(conf.low, 2)), ", ", label_comma()(round(conf.high, 2)), "]")
  ) %>%
  transmute(
    Premenná = term,
    Odhad = Estimate,
    `Štandardná chyba` = `Std. Error`,
    `t-hodnota` = `t value`,
    `p-hodnota` = `p value`,
    `95% Interval spoľahlivosti` = `95% CI`,
    `Významnosť` = stars
  )

# Pekná tabuľka s hover efektom a bez „e“ zápisu
coef.tbl %>%
  kable(caption = "Regresný model populácie krajín podľa roku, hustoty a rozlohy") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed")) %>%
  column_spec(1, bold = TRUE) %>%
  row_spec(0, bold = TRUE, background = "pink") %>%
  footnote(
    general = "Signif. codes: *** p<0.001, ** p<0.01, * p<0.05, · p<0.1.",
    threeparttable = TRUE)
Regresný model populácie krajín podľa roku, hustoty a rozlohy
Premenná Odhad Štandardná chyba t-hodnota p-hodnota 95% Interval spoľahlivosti Významnosť
Intercept -702,407,686 245,431,087 -2.86 0.0043 [-1,183,720,923, -221,094,449] **
Rok 355,502 122,505 2.90 0.0037 [115,258, 595,747] **
Hustota obyvateľstva 268 1,142 0.23 0.8145 [-1,971, 2,507] .
Rozloha 30 1 23.56 0.0000 [28, 33] ***
Note:
Signif. codes: *** p<0.001, ** p<0.01, * p<0.05, · p<0.1.
fit.tbl <- glance(model) %>%
  transmute(
    `R-squared` = round(r.squared, 3),
    `Adj. R-squared` = round(adj.r.squared, 3),
    `F-statistic` = round(statistic, 2),
    `F p-value` = format.pval(p.value, digits = 3, eps = 0.001),
    `AIC` = round(AIC, 2),
    `BIC` = round(BIC, 2),
    `Počet pozorovaní` = nobs)

fit.tbl %>%
  kable(
    caption = "Ukazovatele kvality regresného modelu populácie krajín") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed"))
Ukazovatele kvality regresného modelu populácie krajín
R-squared Adj. R-squared F-statistic F p-value AIC BIC Počet pozorovaní
0.212 0.211 188.34 <0.001 83706.8 83735.06 2106
library(dplyr)
library(ggplot2)
library(tidyr)

num_df <- world_population_data %>% select(where(is.numeric))
print(colnames(num_df))
 [1] "rank"            "2023 population" "2022 population"
 [4] "2020 population" "2015 population" "2010 population"
 [7] "2000 population" "1990 population" "1980 population"
[10] "1970 population" "area (km²)"      "density (km²)"  
cor_mat <- cor(num_df, use = "pairwise.complete.obs")
cor_long <- as.data.frame(as.table(cor_mat))
colnames(cor_long) <- c("Var1", "Var2", "Corr")
ord <- order(colSums(abs(cor_mat)), decreasing = TRUE)
vars_ordered <- colnames(cor_mat)[ord]
cor_long$Var1 <- factor(cor_long$Var1, levels = vars_ordered)
cor_long$Var2 <- factor(cor_long$Var2, levels = rev(vars_ordered)) 

# Vykreslenie heatmapy s hodnotami
ggplot(cor_long, aes(x = Var1, y = Var2, fill = Corr)) +
  geom_tile(color = "white") +
  geom_text(aes(label = round(Corr, 2)), size = 3) +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", midpoint = 0,
                       limits = c(-1, 1), name = "Pearson r") +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    axis.title = element_blank(),
    panel.grid = element_blank()) +
  labs(title = "Heatmap korelačnej matice (numerické premenné)")

Analýza korelačnej matice ukazuje, že populácia krajín je silne konzistentná medzi jednotlivými rokmi. Rozloha krajiny je stredne pozitívne korelovaná s populáciou, zatiaľ čo hustota obyvateľstva nemá výrazný lineárny vzťah s veľkosťou populácie.

LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSAtIGltcG9ydCDDumRham92LCBncmFmeSwgxaF0YXRpc3Rpa3kiCmF1dGhvcjogIkJhcnTDoWtvdsOhIFRlcsOpemlhICA8YnI+IChzIHZ5dcW+aXTDrW0gdmVyZWpuZSBkb3N0dXBuw71jaCBrw7Nkb3YgYSBDaGF0R1BUKSIKZGF0ZTogIk9rdMOzYmVyIDIwMjUiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRoZW1lOiB1bml0ZWQKICAgIGhpZ2hsaWdodDogdGFuZ28KICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBkZl9wcmludDogcGFnZWQKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKZWRpdG9yX29wdGlvbnM6CiAgbWFya2Rvd246CiAgICB3cmFwOiA3MgotLS0KCmBgYHtyfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgICBlY2hvID0gVFJVRSwKICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgIHdhcm5pbmcgPSBGQUxTRQopCmBgYAoKIyBVa8Ohxb5rYSBkYXRhYsOhenkgCgpgYGB7cn0KCmhlYWQod29ybGRfcG9wdWxhdGlvbl9kYXRhKSAgICAgICAgICAgICAgIyBww6FyIHBydsO9Y2ggcmlhZGtvdgpjb2xuYW1lcyh3b3JsZF9wb3B1bGF0aW9uX2RhdGEpICAgICAgICAgICMgbsOhenZ5IHByZW1lbm7DvWNoCmBgYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAoKIyBHcmFmeQoKVsO9YmVyIGEgbsOhc2xlZG7DqSB0cmllZGVuaWUgZGF0YWLDoXp5LCBrdG9yw7ogc29tIG9ibWVkemlsYSBuYSBkdmUgcHJlbWVubsOpLCBhIHRvIGtyYWppbnkgTWFsdGEgYSBDeXBydXMuIAoKYGBge3J9CmxpYnJhcnkoZHBseXIpCgpjeXBydXNfbWFsdGFfZGF0YSA8LSB3b3JsZF9wb3B1bGF0aW9uX2RhdGEgJT4lCiAgZmlsdGVyKGNvdW50cnkgPT0gIkN5cHJ1cyJ8IGNvdW50cnkgPT0gIk1hbHRhIikgJT4lCiAgc2VsZWN0KGBjY2EzYCwgYDIwMjMgcG9wdWxhdGlvbmAsYDIwMjIgcG9wdWxhdGlvbmAsIGAyMDIwIHBvcHVsYXRpb25gLGAyMDE1IHBvcHVsYXRpb25gLCBgMjAxMCBwb3B1bGF0aW9uYCxgMjAwMCBwb3B1bGF0aW9uYCxgMTk5MCBwb3B1bGF0aW9uYCxgMTk4MCBwb3B1bGF0aW9uYCxgMTk3MCBwb3B1bGF0aW9uYCxgZ3Jvd3RoIHJhdGVgLGB3b3JsZCBwZXJjZW50YWdlYCkKaGVhZChjeXBydXNfbWFsdGFfZGF0YSkKYGBgCgojIFNrb250cm9sb3ZhbmllIMWhdHJ1a3TDunJ5IGTDoXQgCmBgYHtyfQpjb2xuYW1lcyhjeXBydXNfbWFsdGFfZGF0YSkKaGVhZChjeXBydXNfbWFsdGFfZGF0YSkKYGBgCgoKIyMjIyBTY2F0dGVyIHBsb3QKCmBgYHtyfQojIEJhc2ljIHNjYXR0ZXIgcGxvdApsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncGxvdDIpCgojIDEuIFZ5YmVyaWVtIHBvdHJlYm7DqSBzdMS6cGNlIGEgZMOhdGEgbGVuIHByZSBDeXBydXMgYSBNYWx0dQpjeXBydXNfbWFsdGFfc2VsIDwtIGN5cHJ1c19tYWx0YV9kYXRhICU+JQpmaWx0ZXIoY2NhMyAlaW4lIGMoIkNZUCIsICJNTFQiKSkgJT4lICAjIEZpbHRyb3ZhbmllIEN5cHJ1IGEgTWFsdHkKc2VsZWN0KGNjYTMsIGAyMDIzIHBvcHVsYXRpb25gLCBgMjAyMiBwb3B1bGF0aW9uYCwgYDIwMjAgcG9wdWxhdGlvbmAsIGAyMDE1IHBvcHVsYXRpb25gLCBgMjAxMCBwb3B1bGF0aW9uYCxgMjAwMCBwb3B1bGF0aW9uYCxgMTk5MCBwb3B1bGF0aW9uYCxgMTk4MCBwb3B1bGF0aW9uYCxgMTk3MCBwb3B1bGF0aW9uYCkgCgojIDIuIFByZW1lbsOtbSBkw6F0YSBkbyBkbGjDqWhvIGZvcm3DoXR1IChwcmUgZ3JhZikKY3lwcnVzX21hbHRhX2xvbmcgPC0gY3lwcnVzX21hbHRhX3NlbCAlPiUKcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGAyMDIzIHBvcHVsYXRpb25gLCBgMjAyMiBwb3B1bGF0aW9uYCwgYDIwMjAgcG9wdWxhdGlvbmAsYDIwMTUgcG9wdWxhdGlvbmAsYDIwMTAgcG9wdWxhdGlvbmAsYDIwMDAgcG9wdWxhdGlvbmAsYDE5OTAgcG9wdWxhdGlvbmAsYDE5ODAgcG9wdWxhdGlvbmAsYDE5NzAgcG9wdWxhdGlvbmApLCBuYW1lc190byA9ICJ5ZWFyIiwgICAgICAgICAKdmFsdWVzX3RvID0gInBvcHVsYXRpb24iKSAgCgojIDMuIFZ5dHZvcsOtbSBncmFmIC0gWm9icmF6w61tIHBvcHVsw6FjaXUgQ3lwcnUgYSBNYWx0eSB2IHJva29jaCAxOTcwIC0gMjAyMwpnZ3Bsb3QoY3lwcnVzX21hbHRhX2xvbmcsIGFlcyh4ID0geWVhciwgeSA9IHBvcHVsYXRpb24sIGNvbG9yID0gY2NhMywgZ3JvdXAgPSBjY2EzKSkgKwogIGdlb21fbGluZShzaXplID0gMSkgKyAgICAKICBnZW9tX3BvaW50KHNpemUgPSAzKSArICAgCiAgdGhlbWVfbWluaW1hbCgpICsgICAgICAgIAogIGxhYnModGl0bGUgPSAiUG9wdWzDoWNpYSBDeXBydSBhIE1hbHR5IHYgcm9rb2NoIDE5NzAgYcW+IDIwMjMiLAogICAgICAgeCA9ICJSb2siLAogICAgICAgeSA9ICJQb3B1bMOhY2lhIiwKICAgICAgIGNvbG9yID0gIktyYWppbmEiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJDWVAiID0gImxpZ2h0cGluayIsICJNTFQiID0gInNreWJsdWUiKSkgIApgYGAKCiMjIyMgQm94cGxvdApaIGTDtHZvZHUsIMW+ZSBwcmVtZW5uw6kgcG9wdWzDoWNpZSBtYWrDuiB2IGtvbmtyw6l0bm9tIHJva3UgaWJhIGplZG51IGhvZG5vdHUgamUgdnlob3RvdmVuaWUgYm94cGxvdHUgYmV6cHJlZG1ldG7DqSwgYXbFoWFrIG5pxb7FoWllIHV2w6FkemFtIG7DoXpvcm7DuiB1a8Ohxb5rdS4gCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHNjYWxlcykgIAoKIyBGaWx0cm92YW5pZSBsZW4gcHJlIEN5cHJ1cyBhIE1hbHR1CmN5cHJ1c19tYWx0YV9sb25nICU+JQpmaWx0ZXIoY2NhMyAlaW4lIGMoIkNZUCIsICJNTFQiKSkgJT4lCmdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBwb3B1bGF0aW9uLCBmaWxsID0gY2NhMywgY29sb3IgPSBjY2EzKSkgKyBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjUsIG91dGxpZXIuc2hhcGUgPSAxNiwgb3V0bGllci5zaXplID0gMikgKyAgCnNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkNZUCIgPSAibGlnaHRwaW5rIiwgIk1MVCIgPSAibGlnaHRibHVlIikpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIkNZUCIgPSAicGluayIsICJNTFQiID0gImRhcmtibHVlIikpICsgIGxhYnMoIHRpdGxlID0gIlBvcHVsw6FjaWEgQ3lwcnUgYSBNYWx0eSBwb2TEvmEgcm9rb3YiLAogICAgICB4ID0gIlJvayIsCiAgICAgIHkgPSAiUG9wdWzDoWNpYSIsCiAgICAgIGZpbGwgPSAiS3JhamluYSIsCiAgICAgIGNvbG9yID0gIktyYWppbmEiKSArIHRoZW1lX21pbmltYWwoKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9jb21tYSgpKSArICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLCAgCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCAgCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCAgCiAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgCiAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLCAgCiAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSkgKwogICAgZmFjZXRfd3JhcCh+IGNjYTMpCmBgYAoKCiMgWsOha2xhZG7DqSDFoXRhdGlzdGlreS4gClYgbmFzbGVkdWrDumNlaiB0YWJ1xL5rZSB6b2JyYXp1amVtIHbDvXBvxI1ldCB6w6FrbGFkbsO9Y2ggxaF0YXRpc3TDrWsgQ3lwcnUgYSBNYWx0eS4gSmUgdnlwb8SNw610YW7DvSBwcmllbWVyIHBvcHVsw6FjaWUgdiByw6FtY2kgdMO9Y2h0byBkdm9jaCBrcmFqw61uLCBtaW5pbcOhbG5hIGEgbWF4aW3DoWxuYSBob2Rub3RhIHBvcHVsw6FjaWUsIG1lZGnDoW4sIHNtZXJvZGFqbsOhIG9kY2jDvWxrYSDEjWkga3ZhcnRpbHkuIApPZCByb2t1IDIwMTAgZG8gMjAyMyBwcmllbWVybsOhIGhvZG5vdGEgcG9wdWzDoWNpZSBzdMO6cGxhIHogNzc0IDIyMCBuYSA4OTcgNjAxLCDEjW8gamUgbsOhcmFzdCBhc2kgbyAxNiAlLiBTbWVyb2Rham7DoSBvZGNow71sa2Egc2EgcG9oeWJ1amUgb2tvbG8gNTAwIDAwMCB2byB2xaFldGvDvWNoIHJva29jaCwgxI1vIHpuYW1lbsOhLCDFvmUgdmFyaWFiaWxpdGEgaG9kbsO0dCBqZSBwb21lcm5lIHZlxL5rw6EsIGFsZSByZWxhdMOtdm5lIHN0YWJpbG7DoSB2IMSNYXNlLiBNaW5pbcOhbG5lIGhvZG5vdHkgc3TDunBhasO6IHogNDE4IDc1NSBuYSA1MzUgMDY0LAphIG1heGltw6EgeiAxIDEyOSA2ODYgbmEgMSAyNjAgMTM4LiBDZWzDvSByb3pzYWggaG9kbsO0dCBzYSB0ZWRhIHBvc8O6dmEgc21lcm9tIG5haG9yLCDEjW8gcG90dnJkenVqZSB2xaFlb2JlY27DvSByYXN0IHBvcHVsw6FjaWUgZGFuw71jaCBrcmFqw61uLiBLdmFydGlseSAoUTI1LCBNZWRpYW4sIFE3NSkgc2EgdGllxb4gcG9zdHVwbmUgenZ5xaF1asO6LCDEjW8gem5hbWVuw6EsIMW+ZSBjZWzDqSByb3pkZWxlbmllIGhvZG7DtHQgc2EgcG9zw7p2YSB2ecWhxaFpZSwgbmllbGVuIHByaWVtZXIuCgoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoa25pdHIpCgojIFZ5YmVyaWVtIEN5cHJ1cyBhIE1hbHR1IGEgcG90cmVibsOpIHN0xLpwY2UKY3lwcnVzX21hbHRhX2RhdGEgPC0gd29ybGRfcG9wdWxhdGlvbl9kYXRhICU+JQpmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkN5cHJ1cyIsICJNYWx0YSIpKSAlPiUKc2VsZWN0KGNjYTMsIGAyMDIzIHBvcHVsYXRpb25gLCBgMjAyMiBwb3B1bGF0aW9uYCwgYDIwMjAgcG9wdWxhdGlvbmAsIGAyMDE1IHBvcHVsYXRpb25gLCBgMjAxMCBwb3B1bGF0aW9uYCwgYDIwMDAgcG9wdWxhdGlvbmAsIGAxOTkwIHBvcHVsYXRpb25gLCBgMTk4MCBwb3B1bGF0aW9uYCwgYDE5NzAgcG9wdWxhdGlvbmAsIGBncm93dGggcmF0ZWAsIGB3b3JsZCBwZXJjZW50YWdlYCkKCiMgUHJlbWVuw61tIGRvIGRsaMOpaG8gZm9ybcOhdHUsIGFieSBzbWUgbWFsaSByb2sgYSBwb3B1bMOhY2l1IHYgc2Ftb3N0YXRuw71jaCBzdMS6cGNvY2gKY3lwcnVzX21hbHRhX2xvbmcgPC0gY3lwcnVzX21hbHRhX2RhdGEgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBlbmRzX3dpdGgoInBvcHVsYXRpb24iKSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAieWVhciIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJwb3B1bGF0aW9uIikgJT4lCiAgbXV0YXRlKHllYXIgPSBnc3ViKCIgcG9wdWxhdGlvbiIsICIiLCB5ZWFyKSkgCgojIFZ5YmVyaWVtIGxlbiBrb25rcsOpdG5lIHJva3kgbmEgc3VtYXJpesOhY2l1IChuYXByLiAyMDEwIGHFviAyMDIzKQpzZWxlY3RlZF95ZWFycyA8LSBjKCIyMDIzIiwgIjIwMjIiLCAiMjAyMCIsICIyMDE1IiwgIjIwMTAiKQoKIyBWeXBvxI3DrXRhbSB6w6FrbGFkbsOpIMWhdGF0aXN0aWt5IHByZSBrYcW+ZMO9IHJvayAoeiBvYm9jaCBrcmFqw61uKQpwb3Bfc3RhdHMgPC0gY3lwcnVzX21hbHRhX2xvbmcgJT4lCiAgZmlsdGVyKHllYXIgJWluJSBzZWxlY3RlZF95ZWFycykgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgc3VtbWFyaXNlKAogICAgbiAgICAgID0gbigpLAogICAgbWVhbiAgID0gbWVhbihwb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpLAogICAgc2QgICAgID0gc2QocG9wdWxhdGlvbiwgbmEucm0gPSBUUlVFKSwKICAgIG1pbiAgICA9IG1pbihwb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpLAogICAgcTI1ICAgID0gcXVhbnRpbGUocG9wdWxhdGlvbiwgMC4yNSwgbmEucm0gPSBUUlVFKSwKICAgIG1lZGlhbiA9IG1lZGlhbihwb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpLAogICAgcTc1ICAgID0gcXVhbnRpbGUocG9wdWxhdGlvbiwgMC43NSwgbmEucm0gPSBUUlVFKSwKICAgIG1heCAgICA9IG1heChwb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpLAogICAgLmdyb3VwcyA9ICJkcm9wIikKCiMgVnl0dm9yZW5pZSBwZWtuZWogdGFidcS+a3kKa2FibGUocG9wX3N0YXRzLCBkaWdpdHMgPSAwLCBjYXB0aW9uID0gIioqWsOha2xhZG7DqSDFoXRhdGlzdGlreSBwb3B1bMOhY2llIHByZSBDeXBydXMgYSBNYWx0dSoqICoodnlicmFuw6kgcm9reSkqIikKYGBgCgoKdGFidcS+a3UgdmllbWUgdnl0dm9yacWlIGkga3JhasWhaXUgcyBwb21vY291ICJrYWJsZUV4dHJhIjoKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgojIFZ5YmVyaWVtIEN5cHJ1cyBhIE1hbHR1IGEgcG90cmVibsOpIHN0xLpwY2UKY3lwcnVzX21hbHRhX2RhdGEgPC0gd29ybGRfcG9wdWxhdGlvbl9kYXRhICU+JQpmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkN5cHJ1cyIsICJNYWx0YSIpKSAlPiUKc2VsZWN0KGNjYTMsIGAyMDIzIHBvcHVsYXRpb25gLCBgMjAyMiBwb3B1bGF0aW9uYCwgYDIwMjAgcG9wdWxhdGlvbmAsIGAyMDE1IHBvcHVsYXRpb25gLCBgMjAxMCBwb3B1bGF0aW9uYCwgYDIwMDAgcG9wdWxhdGlvbmAsIGAxOTkwIHBvcHVsYXRpb25gLCBgMTk4MCBwb3B1bGF0aW9uYCwgYDE5NzAgcG9wdWxhdGlvbmAsIGBncm93dGggcmF0ZWAsIGB3b3JsZCBwZXJjZW50YWdlYCkKCiMgUHJlbWVuw61tIGRvIGRsaMOpaG8gZm9ybcOhdHUsIGFieSBzbWUgbWFsaSByb2sgYSBwb3B1bMOhY2l1IHYgc2Ftb3N0YXRuw71jaCBzdMS6cGNvY2gKY3lwcnVzX21hbHRhX2xvbmcgPC0gY3lwcnVzX21hbHRhX2RhdGEgJT4lCiBwaXZvdF9sb25nZXIoY29scyA9IGVuZHNfd2l0aCgicG9wdWxhdGlvbiIpLG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAicG9wdWxhdGlvbiIpICU+JSBtdXRhdGUoeWVhciA9IGdzdWIoIiBwb3B1bGF0aW9uIiwgIiIsIHllYXIpKSAKCiMgVnliZXJpZW0gbGVuIGtvbmtyw6l0bmUgcm9reSBuYSBzdW1hcml6w6FjaXUgKG5hcHIuIDIwMTAgYcW+IDIwMjMpCnNlbGVjdGVkX3llYXJzIDwtIGMoIjIwMjMiLCAiMjAyMiIsICIyMDIwIiwgIjIwMTUiLCAiMjAxMCIpCgojIFZ5cG/EjcOtdGFtIHrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kgcHJlIGthxb5kw70gcm9rICh6IG9ib2NoIGtyYWrDrW4pCnBvcF9zdGF0cyA8LSBjeXBydXNfbWFsdGFfbG9uZyAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIHNlbGVjdGVkX3llYXJzKSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2UoCiAgICBuICAgICAgPSBuKCksCiAgICBtZWFuICAgPSBtZWFuKHBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICBzZCAgICAgPSBzZChwb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpLAogICAgbWluICAgID0gbWluKHBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICBxMjUgICAgPSBxdWFudGlsZShwb3B1bGF0aW9uLCAwLjI1LCBuYS5ybSA9IFRSVUUpLAogICAgbWVkaWFuID0gbWVkaWFuKHBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICBxNzUgICAgPSBxdWFudGlsZShwb3B1bGF0aW9uLCAwLjc1LCBuYS5ybSA9IFRSVUUpLAogICAgbWF4ICAgID0gbWF4KHBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICAuZ3JvdXBzID0gImRyb3AiKQoKIyBWeXR2b3JlbmllIMWhdMO9bG92YW5laiB0YWJ1xL5reSBzIGthYmxlRXh0cmEKcG9wX3N0YXRzICU+JQogIGthYmxlKGRpZ2l0cyA9IDAsIGNhcHRpb24gPSAiWsOha2xhZG7DqSDFoXRhdGlzdGlreSBwb3B1bMOhY2llIHByZSBDeXBydXMgYSBNYWx0dSAodnlicmFuw6kgcm9reSkiKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIiksCiAgICBwb3NpdGlvbiA9ICJjZW50ZXIiLAogICAgZm9udF9zaXplID0gMTMpICU+JQogIGNvbHVtbl9zcGVjKDEsIGJvbGQgPSBUUlVFKSAlPiUgICMgVHXEjW7DvSB0ZXh0IHByZSByb2sKICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgY29sb3IgPSAicHVycGxlIiwgYmFja2dyb3VuZCA9ICJwaW5rIikgJT4lCiAgYWRkX2hlYWRlcl9hYm92ZShjKCIgIiA9IDIsICLFoHRhdGlzdGlreSBwb3B1bMOhY2llIiA9IDcpLCBib2xkID0gVFJVRSwgYmFja2dyb3VuZCA9ICJwaW5rIiwgY29sb3IgPSAiYmxhY2siKSAlPiUKICBrYWJsZV9wYXBlcigiaG92ZXIiLCBmdWxsX3dpZHRoID0gRkFMU0UpICU+JQogIGthYmxlX21hdGVyaWFsKGMoImhvdmVyIikpICAKYGBgCgoKIyBUZXN0b3ZhbmllIGh5cG90w6l6Ck5hc2xlZHVqw7pjaW1pIHByw61rYXptaSB6aXPFpXVqZW0sIMSNaSBzYSBwcmllbWVybsOhIHBvcHVsw6FjaWEga3JhasOtbiBuYSBzdmV0ZSB2w716bmFtbmUgem1lbmlsYSBtZWR6aSByb2ttaSAxOTcwIGEgMjAyMy4KTmEgbGVwxaFpdSB2aXp1YWxpesOhY2l1IHV2w6FkemFtIGJveHBsb3QsIGt0b3LDvSB2aXp1w6FsbmUgdWthenVqZSByb3psb8W+ZW5pZSBwb3B1bMOhY2llIGplZG5vdGxpdsO9Y2gga3JhasOtbiB2IG9iZG9iw60gbWVkemkgdMO9bWl0byBkdm9tYSByb2ttaSDigJMgbmFwcsOta2xhZCwgxb5lIHYgcm9rdSAyMDIzIG1hasO6IGtyYWppbnkgdsWhZW9iZWNuZSB2ecWhxaHDrSBwb8SNZXQgb2J5dmF0ZcS+b3YgYSB2w6TEjcWhaWUgcm96ZGllbHkgbWVkemkgbmltaSBha28gdiByb2t1IDE5NzAuIE5hIHV2ZWRlbm9tIGJveHBsb3RlIGplIHRha3RpZcW+IG1vxb5uw6kgc2xlZG92YcWlIGV4dHLDqW1uZSBob2Rub3R5LgoKIyMjIyB0LXRlc3Q6ICoqUG9yb3ZuYW5pZSBwb3B1bMOhY2llIGtyYWrDrW4gdiByb2tvY2ggMTk3MCBhIDIwMjAqKgoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShzY2FsZXMpCgojIFByZXZlZGVuaWUgZG8gbG9uZyBmb3Jtw6F0dQp3b3JsZF9wb3B1bGF0aW9uX2xvbmcgPC0gd29ybGRfcG9wdWxhdGlvbl9kYXRhICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gZW5kc193aXRoKCJwb3B1bGF0aW9uIiksIG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAicG9wdWxhdGlvbiIsIG5hbWVzX3BhdHRlcm4gPSAiKFxcZHs0fSkgcG9wdWxhdGlvbiIpICU+JQogIG11dGF0ZSh5ZWFyID0gYXMubnVtZXJpYyh5ZWFyKSkKCiMgdC10ZXN0IOKAkyBwb3Jvdm5hbmllIHByaWVtZXJuZWogcG9wdWzDoWNpZSBrcmFqw61uIG1lZHppIHJva21pIDE5NzAgYSAyMDIwCnQudGVzdC5yZXN1bHQgPC0gdC50ZXN0KHdvcmxkX3BvcHVsYXRpb25fbG9uZyRwb3B1bGF0aW9uW3dvcmxkX3BvcHVsYXRpb25fbG9uZyR5ZWFyID09IDE5NzBdLCB3b3JsZF9wb3B1bGF0aW9uX2xvbmckcG9wdWxhdGlvblt3b3JsZF9wb3B1bGF0aW9uX2xvbmckeWVhciA9PSAyMDIzXSwgcGFpcmVkID0gRkFMU0UpCgpwcmludCh0LnRlc3QucmVzdWx0KQoKIyBCb3hwbG90IOKAkyB2aXp1YWxpesOhY2lhIHJvemRpZWx1IG1lZHppIHJva21pCndvcmxkX3BvcHVsYXRpb25fbG9uZyAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk3MCwgMjAyMykpICU+JQogIGdncGxvdChhZXMoeCA9IGZhY3Rvcih5ZWFyKSwgeSA9IHBvcHVsYXRpb24sIGZpbGwgPSBmYWN0b3IoeWVhcikpKSArCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43LCBvdXRsaWVyLnNoYXBlID0gMTYsIG91dGxpZXIuc2l6ZSA9IDEuNSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9jb21tYSgpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiMTk3MCIgPSAibGlnaHRncmVlbiIsICIyMDIzIiA9ICJ5ZWxsb3ciKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJQb3Jvdm5hbmllIHBvcHVsw6FjaWUga3JhasOtbiB2IHJva29jaCAxOTcwIGEgMjAyMyIsCiAgICB4ID0gIlJvayIsCiAgICB5ID0gIlBvcHVsw6FjaWEga3JhasOtbiIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMyksCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgoKIyMjIyBBTk9WQQpIMDogUHJpZW1lcm7DoSBwb3B1bMOhY2lhIGtyYWrDrW4gc2EgbWVkemkgcm9rbWkgbmVsw63FoWkuCgpIMTogQXNwb8WIIHYgamVkbm9tIHJva3Ugc2EgcHJpZW1lcm7DoSBwb3B1bMOhY2lhIGtyYWrDrW4gbMOtxaFpIG9kIG9zdGF0bsO9Y2ggcm9rb3YuCmBgYHtyfQojIEFOT1ZBIOKAkyB0ZXN0b3ZhbmllIHJvemRpZWxvdiBwcmllbWVybmVqIHBvcHVsw6FjaWUgbWVkemkgcm9rbWkKYW5vdmEucmVzdWx0IDwtIGFvdihwb3B1bGF0aW9uIH4gZmFjdG9yKHllYXIpLCBkYXRhID0gd29ybGRfcG9wdWxhdGlvbl9sb25nKQpzdW1tYXJ5KGFub3ZhLnJlc3VsdCkKYGBgCgpWw71zbGVka3kgQU5PVlkgKEYoOCwgMjA5NykgPSAwLjgzMSwgcCA9IDAuNTc2KSB1a2F6dWrDuiwgxb5lIG1lZHppIHJva21pIG5lZXhpc3R1asO6IMWhdGF0aXN0aWNreSB2w716bmFtbsOpIHJvemRpZWx5LiBUbyB6bmFtZW7DoSwgxb5lIHbDvXZvaiBwb3B1bMOhY2llIHBvZMS+YSB0w71jaHRvIMO6ZGFqb3YgbmVwcmV1a2F6dWplIHN5c3RlbWF0aWNrw70gbsOhcmFzdCBhbGVibyBwb2tsZXMgdiBqZWRub3RsaXbDvWNoIHJva29jaCDigJMgem1lbnkgbW/Fvm5vIHBvdmHFvm92YcWlIHphIG7DoWhvZG7DqSwgxI3DrW0gc2EgbnVsb3bDoSBoeXBvdMOpemEgbmV6YW1pZXRhLCBwcmV0b8W+ZSBuaWUgamUgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70gZMO0a2F6LCDFvmUgYnkgc2EgcHJpZW1lcm7DoSBwb3B1bMOhY2lhIGtyYWrDrW4gbWVkemkgcm9rbWkgbMOtxaFpbGEuCgojIyMjIExpbmVhciBSZWdyZXNzaW9uCkxpbmXDoXJub3UgcmVncmVzaW91IHNvbSBza8O6bWFsYSB2cGx5diByb2t1LCBodXN0b3R5IG9ieXZhdGXEvnN0dmEgYSByb3psb2h5IGtyYWppbnkgbmEgcG9wdWzDoWNpdSBrcmFqaW55LiBWw71zbGVka3kgdWthenVqw7osIMW+ZSBtb2RlbCBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSAoRigzLCAyMTAyKSA9IDE4OC4zLCBwIDwgMi4yZS0xNiksIMSNbyB6bmFtZW7DoSwgxb5lIGFzcG/FiCBqZWRuYSB6IHByZW1lbm7DvWNoIG3DoSB2cGx5diBuYSBwb3B1bMOhY2l1LgoKUm9rIGplIHbDvXpuYW1uw71tIHByZWRpa3Rvcm9tIHBvcHVsw6FjaWUsIHByacSNb20ga2HFvmTDvSDEj2FsxaHDrSByb2sgamUgc3BvamVuw70gcyBuw6FyYXN0b20gcG9wdWzDoWNpZSBwcmlibGnFvm5lIG8gMzU1IDUwMCBvYnl2YXRlxL5vdi4KClJvemxvaGEga3JhamlueSBqZSAqKm5hanNpbG5lasWhw61tIGZha3Rvcm9tKio7IHbDpMSNxaFpZSBrcmFqaW55IG1hasO6IHbDvXJhem5lIHZ5xaHFoWl1IHBvcHVsw6FjaXUgKGthxb5kw70ga23CsiBwcmlzcGlldmEgdiBwcmllbWVyZSBvIDMwIG9ieXZhdGXEvm92LCBwIDwgMmUtMTYpLgoKSHVzdG90YSBvYnl2YXRlxL5zdHZhIG5lYm9sYSDFoXRhdGlzdGlja3kgdsO9em5hbW7DoSAocCA9IDAuODE0KSwgdGVkYSBwb2TEvmEgdG9odG8gbW9kZWx1IG5lbcOhIHbDvXpuYW1uw70gdnBseXYgbmEgY2Vsa292w7ogcG9wdWzDoWNpdS4KCk1vZGVsIHZ5c3ZldMS+dWplIHByaWJsacW+bmUgMjEgJSB2YXJpYWJpbGl0eSB2IHBvcHVsw6FjaWkga3JhasOtbiAoUsKyID0gMC4yMTE5KSwgxI1vIG5hem5hxI11amUsIMW+ZSBleGlzdHVqw7ogYWogxI9hbMWhaWUgZmFrdG9yeSwga3RvcsOpIG92cGx5dsWIdWrDuiB2ZcS+a29zxaUgcG9wdWzDoWNpZSwgYSBrdG9yw6kgbmllIHPDuiB6YWhybnV0w6kgdiB0b210byBtb2RlbGkuCgpgYGB7cn0KIyBMaW5lYXJuYSByZWdyZXNpYSBwcmUgcG9wdWzDoWNpdSBrcmFqaW55Cm1vZGVsIDwtIGxtKHBvcHVsYXRpb24gfiB5ZWFyICsgYGRlbnNpdHkgKGttwrIpYCArIGBhcmVhIChrbcKyKWAsIGRhdGEgPSB3b3JsZF9wb3B1bGF0aW9uX2xvbmcpCgpzdW1tYXJ5KG1vZGVsKQpgYGAKCgoKYGBge3J9CmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHNjYWxlcykgIAoKbW9kZWwgPC0gbG0ocG9wdWxhdGlvbiB+IHllYXIgKyBgZGVuc2l0eSAoa23CsilgICsgYGFyZWEgKGttwrIpYCwgZGF0YSA9IHdvcmxkX3BvcHVsYXRpb25fbG9uZykKCiMgw5pwcmF2YSB2w71zdHVwdSBhIGZvcm3DoXRvdmFuaWUKY29lZi50YmwgPC0gdGlkeShtb2RlbCwgY29uZi5pbnQgPSBUUlVFKSAlPiUKICBtdXRhdGUoCiAgICB0ZXJtID0gcmVjb2RlKHRlcm0sCiAgICAgICIoSW50ZXJjZXB0KSIgPSAiSW50ZXJjZXB0IiwKICAgICAgInllYXIiID0gIlJvayIsCiAgICAgICJgZGVuc2l0eSAoa23CsilgIiA9ICJIdXN0b3RhIG9ieXZhdGXEvnN0dmEiLAogICAgICAiYGFyZWEgKGttwrIpYCIgPSAiUm96bG9oYSIpLAogICAgc3RhcnMgPSBjYXNlX3doZW4oCiAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICBwLnZhbHVlIDwgMC4wMSAgfiAiKioiLAogICAgICBwLnZhbHVlIDwgMC4wNSAgfiAiKiIsCiAgICAgIHAudmFsdWUgPCAwLjEgICB+ICLCtyIsCiAgICAgIFRSVUUgICAgICAgICAgICB+ICIuIiApLAogICAgRXN0aW1hdGUgPSBsYWJlbF9jb21tYSgpKGVzdGltYXRlKSwKICAgIGBTdGQuIEVycm9yYCA9IGxhYmVsX2NvbW1hKCkoc3RkLmVycm9yKSwKICAgIGB0IHZhbHVlYCA9IHJvdW5kKHN0YXRpc3RpYywgMiksCiAgICBgcCB2YWx1ZWAgPSByb3VuZChwLnZhbHVlLCA0KSwKICAgIGA5NSUgQ0lgID0gc3RyX2MoIlsiLCBsYWJlbF9jb21tYSgpKHJvdW5kKGNvbmYubG93LCAyKSksICIsICIsIGxhYmVsX2NvbW1hKCkocm91bmQoY29uZi5oaWdoLCAyKSksICJdIikKICApICU+JQogIHRyYW5zbXV0ZSgKICAgIFByZW1lbm7DoSA9IHRlcm0sCiAgICBPZGhhZCA9IEVzdGltYXRlLAogICAgYMWgdGFuZGFyZG7DoSBjaHliYWAgPSBgU3RkLiBFcnJvcmAsCiAgICBgdC1ob2Rub3RhYCA9IGB0IHZhbHVlYCwKICAgIGBwLWhvZG5vdGFgID0gYHAgdmFsdWVgLAogICAgYDk1JSBJbnRlcnZhbCBzcG/EvmFobGl2b3N0aWAgPSBgOTUlIENJYCwKICAgIGBWw716bmFtbm9zxaVgID0gc3RhcnMKICApCgojIFBla27DoSB0YWJ1xL5rYSBzIGhvdmVyIGVmZWt0b20gYSBiZXog4oCeZeKAnCB6w6FwaXN1CmNvZWYudGJsICU+JQogIGthYmxlKGNhcHRpb24gPSAiUmVncmVzbsO9IG1vZGVsIHBvcHVsw6FjaWUga3JhasOtbiBwb2TEvmEgcm9rdSwgaHVzdG90eSBhIHJvemxvaHkiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKSAlPiUKICBjb2x1bW5fc3BlYygxLCBib2xkID0gVFJVRSkgJT4lCiAgcm93X3NwZWMoMCwgYm9sZCA9IFRSVUUsIGJhY2tncm91bmQgPSAicGluayIpICU+JQogIGZvb3Rub3RlKAogICAgZ2VuZXJhbCA9ICJTaWduaWYuIGNvZGVzOiAqKiogcDwwLjAwMSwgKiogcDwwLjAxLCAqIHA8MC4wNSwgwrcgcDwwLjEuIiwKICAgIHRocmVlcGFydHRhYmxlID0gVFJVRSkKYGBgCgpgYGB7cn0KZml0LnRibCA8LSBnbGFuY2UobW9kZWwpICU+JQogIHRyYW5zbXV0ZSgKICAgIGBSLXNxdWFyZWRgID0gcm91bmQoci5zcXVhcmVkLCAzKSwKICAgIGBBZGouIFItc3F1YXJlZGAgPSByb3VuZChhZGouci5zcXVhcmVkLCAzKSwKICAgIGBGLXN0YXRpc3RpY2AgPSByb3VuZChzdGF0aXN0aWMsIDIpLAogICAgYEYgcC12YWx1ZWAgPSBmb3JtYXQucHZhbChwLnZhbHVlLCBkaWdpdHMgPSAzLCBlcHMgPSAwLjAwMSksCiAgICBgQUlDYCA9IHJvdW5kKEFJQywgMiksCiAgICBgQklDYCA9IHJvdW5kKEJJQywgMiksCiAgICBgUG/EjWV0IHBvem9yb3ZhbsOtYCA9IG5vYnMpCgpmaXQudGJsICU+JQogIGthYmxlKAogICAgY2FwdGlvbiA9ICJVa2F6b3ZhdGVsZSBrdmFsaXR5IHJlZ3Jlc27DqWhvIG1vZGVsdSBwb3B1bMOhY2llIGtyYWrDrW4iKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKQpgYGAKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh0aWR5cikKCm51bV9kZiA8LSB3b3JsZF9wb3B1bGF0aW9uX2RhdGEgJT4lIHNlbGVjdCh3aGVyZShpcy5udW1lcmljKSkKcHJpbnQoY29sbmFtZXMobnVtX2RmKSkKY29yX21hdCA8LSBjb3IobnVtX2RmLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIikKY29yX2xvbmcgPC0gYXMuZGF0YS5mcmFtZShhcy50YWJsZShjb3JfbWF0KSkKY29sbmFtZXMoY29yX2xvbmcpIDwtIGMoIlZhcjEiLCAiVmFyMiIsICJDb3JyIikKb3JkIDwtIG9yZGVyKGNvbFN1bXMoYWJzKGNvcl9tYXQpKSwgZGVjcmVhc2luZyA9IFRSVUUpCnZhcnNfb3JkZXJlZCA8LSBjb2xuYW1lcyhjb3JfbWF0KVtvcmRdCmNvcl9sb25nJFZhcjEgPC0gZmFjdG9yKGNvcl9sb25nJFZhcjEsIGxldmVscyA9IHZhcnNfb3JkZXJlZCkKY29yX2xvbmckVmFyMiA8LSBmYWN0b3IoY29yX2xvbmckVmFyMiwgbGV2ZWxzID0gcmV2KHZhcnNfb3JkZXJlZCkpIAoKIyBWeWtyZXNsZW5pZSBoZWF0bWFweSBzIGhvZG5vdGFtaQpnZ3Bsb3QoY29yX2xvbmcsIGFlcyh4ID0gVmFyMSwgeSA9IFZhcjIsIGZpbGwgPSBDb3JyKSkgKwogIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoQ29yciwgMikpLCBzaXplID0gMykgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgbWlkID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtMSwgMSksIG5hbWUgPSAiUGVhcnNvbiByIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpICsKICBsYWJzKHRpdGxlID0gIkhlYXRtYXAga29yZWxhxI1uZWogbWF0aWNlIChudW1lcmlja8OpIHByZW1lbm7DqSkiKQpgYGAKQW5hbMO9emEga29yZWxhxI1uZWogbWF0aWNlIHVrYXp1amUsIMW+ZSBwb3B1bMOhY2lhIGtyYWrDrW4gamUgc2lsbmUga29uemlzdGVudG7DoSBtZWR6aSBqZWRub3RsaXbDvW1pIHJva21pLiBSb3psb2hhIGtyYWppbnkgamUgc3RyZWRuZSBwb3ppdMOtdm5lIGtvcmVsb3ZhbsOhIHMgcG9wdWzDoWNpb3UsIHphdGlhxL4gxI1vIGh1c3RvdGEgb2J5dmF0ZcS+c3R2YSBuZW3DoSB2w71yYXpuw70gbGluZcOhcm55IHZ6xaVhaCBzIHZlxL5rb3PFpW91IHBvcHVsw6FjaWUuCgoKCgoK