Importovanie vlastnej databázy

head(world_population)                            # niekolko prvych riadkov
colnames(world_population)
 [1] "Rank"                        "CCA3"                       
 [3] "Country.Territory"           "Capital"                    
 [5] "Continent"                   "X2022.Population"           
 [7] "X2020.Population"            "X2015.Population"           
 [9] "X2010.Population"            "X2000.Population"           
[11] "X1990.Population"            "X1980.Population"           
[13] "X1970.Population"            "Area..km.."                 
[15] "Density..per.km.."           "Growth.Rate"                
[17] "World.Population.Percentage"

Grafy

ggplot2 - knižnica pre grafy

Výber a následné triedenie

library(ggplot2)
SVK_CZE_data <- world_population %>%
  filter(CCA3 %in% c("SVK", "CZE")) %>%  # Filtrovanie na Slovensko a Česko
  select(CCA3, `2020 Population`, `2010 Population`, `2000 Population`, `1990 Population`, `1980 Population`) # Vyberáme len relevantné stĺpce
Error in world_population %>% filter(CCA3 %in% c("SVK", "CZE")) %>% select(CCA3,  : 
  could not find function "%>%"

Scatter plot

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

# Predpokladám, že dataset je uložený v premennej `SVK_CZE_data`

# 1. Vyberieme potrebné stĺpce a dáta len pre Slovensko a Česko
SVK_CZE_sel <- SVK_CZE_data %>%
  filter(CCA3 %in% c("SVK", "CZE")) %>%  # Filtrovanie na Slovensko a Česko
  select(CCA3, `2020 Population`, `2010 Population`, `2000 Population`, `1990 Population`, `1980 Population`)  # Vyberáme len relevantné stĺpce

# 2. Premeníme dáta do dlhého formátu (pre graf)
SVK_CZE_long <- SVK_CZE_sel %>%
  pivot_longer(cols = c(`2020 Population`, `2010 Population`, `2000 Population`, `1990 Population`, `1980 Population`),
               names_to = "year",     # Stĺpec s rokmi
               values_to = "population")  # Stĺpec s populáciou

# 3. Vytvoríme stĺpcový graf - Zobrazíme populáciu Slovenska a Česka v rokoch 1980, 1990, 2000, 2010 a 2020
ggplot(SVK_CZE_long, aes(x = year,y = population, fill = CCA3, group = CCA3)) + geom_bar(stat = "identity", position = "dodge", width = 0.8) + # Stĺpcový graf s oddelenými stĺpcami pre každú krajinu 
  geom_text(aes(label = population), position = position_dodge(width = 0.3), vjust = -0.1) + # Pridanie označení hodnôt 
  theme_minimal() + # Minimalistický dizajn grafu 
  labs(title = "Vývoj populácie Slovenska a Česka", # Upravený nadpis 
       x = "Rok", 
       y = "Populácia", 
       fill = "Krajina") + # Popis farieb podľa krajiny 
  theme(axis.text.x = element_text(angle = 30, hjust = 1)) # Rotácia textu na osi X

Boxplot

# Bar plot with grouping
library(ggplot2)

ggplot(SVK_CZE_long, aes(x = year, y = population, color = CCA3, group = CCA3)) +
  geom_line(linewidth = 1.2) +                 # Čiary pre každú krajinu
  geom_point(size = 3) +                       # Bodky na čiarach
  geom_text(aes(label = population),           # Hodnoty nad bodkami
            vjust = -0.5, size = 2,            # Malé písmo, posunuté mierne nahor
            show.legend = FALSE) +             # Bez legendy pre text
  theme_minimal() +
  labs(
    title = "Vývoj populácie Slovenska a Česka",
    x = "Rok",
    y = "Populácia",
    color = "Krajina"
  ) +
  theme(axis.text.x = element_text(angle = 30, hjust = 1))

Základné štatistiky

knitr - tabuľka

library(dplyr)
library(knitr)

# 1. Vyberieme potrebné stĺpce a dáta len pre Slovensko a Česko
SVK_CZE_sel <- SVK_CZE_data %>%
  filter(CCA3 %in% c("SVK", "CZE")) %>%  # Filtrovanie na Slovensko a Česko
  select(CCA3, `2020 Population`, `2010 Population`, `2000 Population`, `1990 Population`, `1980 Population`)  # Relevantné stĺpce

# 2. Premeníme dáta do dlhého formátu
SVK_CZE_long <- SVK_CZE_sel %>%
  pivot_longer(cols = c(`2020 Population`, `2010 Population`, `2000 Population`, `1990 Population`, `1980 Population`),
               names_to = "year",
               values_to = "population")
# 3. Vypočítame základné štatistiky populácie podľa krajiny a roku
SVK_CZE_stats <- SVK_CZE_long %>%
  group_by(CCA3, 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"
  )

# 4. Vytvoríme tabuľku pomocou knitr
kable(SVK_CZE_stats, digits = 0, caption = "Základné štatistiky populácie Slovenska a Česka (1980–2020)")
Základné štatistiky populácie Slovenska a Česka (1980–2020)
CCA3 year n mean sd min q25 median q75 max
CZE 1980 Population 1 10270060 NA 10270060 10270060 10270060 10270060 10270060
CZE 1990 Population 1 10301192 NA 10301192 10301192 10301192 10301192 10301192
CZE 2000 Population 1 10234710 NA 10234710 10234710 10234710 10234710 10234710
CZE 2010 Population 1 10464749 NA 10464749 10464749 10464749 10464749 10464749
CZE 2020 Population 1 10530953 NA 10530953 10530953 10530953 10530953 10530953
SVK 1980 Population 1 4973883 NA 4973883 4973883 4973883 4973883 4973883
SVK 1990 Population 1 5261305 NA 5261305 5261305 5261305 5261305 5261305
SVK 2000 Population 1 5376690 NA 5376690 5376690 5376690 5376690 5376690
SVK 2010 Population 1 5396424 NA 5396424 5396424 5396424 5396424 5396424
SVK 2020 Population 1 5456681 NA 5456681 5456681 5456681 5456681 5456681

Testovanie hypotéz

t-test: Porovnanie populácie Slovenska a Česka v rokoch 2020

# 1. Vyberieme populáciu Slovenska a Česka v roku 2020
SVK_CZE_2020 <- SVK_CZE_data %>%
  filter(CCA3 %in% c("SVK", "CZE")) %>%
  select(CCA3, `2020 Population`)

# 2. Vykonáme t-test na porovnanie populácie medzi SVK a CZE v roku 2020
SVK_pop <- SVK_CZE_long %>% filter(CCA3 == "SVK") %>% pull(population)
CZE_pop <- SVK_CZE_long %>% filter(CCA3 == "CZE") %>% pull(population)

# 3. Výpis výsledku testu
t_test_result <- t.test(SVK_pop, CZE_pop)
print(t_test_result)

    Welch Two Sample t-test

data:  SVK_pop and CZE_pop
t = -48.899, df = 7.0276, p-value = 3.655e-10
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -5312182 -4822491
sample estimates:
mean of x mean of y 
  5292997  10360333 

ANOVA: Comparing Reading Scores Across Programs

anova_result <- aov(population ~ year, data = SVK_CZE_long)
summary(anova_result)
            Df    Sum Sq   Mean Sq F value Pr(>F)
year         4 1.663e+11 4.157e+10   0.003      1
Residuals    5 6.424e+13 1.285e+13               

Linear Regression: Predicting Math Scores



# 3. Vytvoríme lineárny model populácie podľa roku a krajiny
model <- lm(population ~ year + CCA3, data = SVK_CZE_long)
summary(model)

Call:
lm(formula = population ~ year + CCA3, data = SVK_CZE_long)

Residuals:
        1         2         3         4         5         6         7 
   3467.9     494.4 -104658.1  -13724.6  114420.4   -3467.9    -494.4 
        8         9        10 
 104658.1   13724.6 -114420.4 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)         10155640      85286 119.077 2.98e-08 ***
year1990 Population   159277     110104   1.447   0.2216    
year2000 Population   183728     110104   1.669   0.1705    
year2010 Population   308615     110104   2.803   0.0487 *  
year2020 Population   371846     110104   3.377   0.0279 *  
CCA3SVK             -5067336      69636 -72.769 2.14e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 110100 on 4 degrees of freedom
Multiple R-squared:  0.9992,    Adjusted R-squared:  0.9983 
F-statistic:  1062 on 5 and 4 DF,  p-value: 2.478e-06
# install.packages(c("broom", "kableExtra", "dplyr", "stringr"))
library(broom)
library(dplyr)
library(kableExtra)
library(stringr)

# Your model (already fitted)
# model <- lm(ESG.INDEX ~ RETURN.ON.ASSETS + FIRM.SIZE + DEBT.TO.ASSET, data = udaje.2013)

coef.tbl <- tidy(model, conf.int = TRUE) %>%
  mutate(
    term = recode(term,
      "(Intercept)" = "Intercept",
      "year1990 Population" = "Rok 1990",
      "year2000 Population" = "Rok 2000",
      "year2010 Population" = "Rok 2010",
      "year2020 Population" = "Rok 2020",
      "CCA3SVK" = "Slovensko"
    ),
    stars = case_when(
      p.value < 0.001 ~ "***",
      p.value < 0.01  ~ "**",
      p.value < 0.05  ~ "*",
      p.value < 0.1   ~ "·",
      TRUE            ~ ""
    )
  ) %>%
  transmute(
    Term = term,
    Estimate = estimate,
    `Std. Error` = std.error,
    `t value` = statistic,
    `p value` = p.value,
    `95% CI` = str_c("[", round(conf.low, 0), ", ", round(conf.high, 0), "]"),
    Sig = stars
  )

coef.tbl %>%
  kable(
    digits = 0,
    caption = "OLS regresné koeficienty (population ~ year + CCA3)"
  ) %>%
  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)
OLS regresné koeficienty (population ~ year + CCA3)
Term Estimate Std. Error t value p value 95% CI Sig
Intercept 10155640 85287 119 0 [9918846, 10392433] ***
Rok 1990 159277 110104 1 0 [-146422, 464976]
Rok 2000 183728 110104 2 0 [-121970, 489427]
Rok 2010 308615 110104 3 0 [2916, 614314] *
Rok 2020 371845 110104 3 0 [66147, 677544] *
Slovensko -5067336 69636 -73 0 [-5260677, -4873995] ***
Note:
Signif. codes: *** p<0.001, ** p<0.01, * p<0.05, · p<0.1.
NA

Príprava databázy, čistenie a úprava údajov

# Načítanie dát
udaje <- read.csv("world_population.csv", dec=".", sep=",", header = TRUE)

# Kontrola názvov stĺpcov
names(udaje)
 [1] "Rank"                        "CCA3"                       
 [3] "Country.Territory"           "Capital"                    
 [5] "Continent"                   "X2022.Population"           
 [7] "X2020.Population"            "X2015.Population"           
 [9] "X2010.Population"            "X2000.Population"           
[11] "X1990.Population"            "X1980.Population"           
[13] "X1970.Population"            "Area..km.."                 
[15] "Density..per.km.."           "Growth.Rate"                
[17] "World.Population.Percentage"
# Výber len číselných údajov (uprav podľa presných názvov stĺpcov)
udaje.2020 <- udaje[, c("X2020.Population", "Area..km..", "Density..per.km..")]

# Konverzia na numeric
udaje.2020 <- as.data.frame(lapply(udaje.2020, as.numeric))

# Nahradenie NA mediánmi
column_medians <- sapply(udaje.2020, median, na.rm = TRUE)
for (col in names(udaje.2020)) {
  udaje.2020[[col]][is.na(udaje.2020[[col]])] <- column_medians[col]
}

# Vykreslenie boxplotov
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1))
for (col in names(udaje.2020)) {
  boxplot(udaje.2020[[col]], main = col, xlab = "Hodnoty", col = "lightpink", border = "orange")
}

Boxploty – Populácia, Rozloha a Hustota obyvateľstva

Interpretácia grafov

1. X2020.Population

Väčšina hodnôt sa koncentruje pri veľmi nízkych hodnotách populácie.

Viditeľných je niekoľko výrazných odľahlých hodnôt (outliers) – niektoré krajiny/územia majú populáciu výrazne vyššiu než ostatné.

Rozdelenie je silne pravostranné (pozitívne zošikmené) – väčšina pozorovaní má malé hodnoty, zatiaľ čo niekoľko extrémnych pozorovaní ťahá medián smerom nadol.

2. Area..km..

Väčšina krajín má pomerne malú rozlohu, pričom zopár veľmi veľkých území spôsobuje silnú pravostrannú šikmosť.

Viaceré body ďaleko od hlavného poľa dát naznačujú odľahlé pozorovania (veľké krajiny).

Podobne ako pri populácii, dáta sú veľmi nesymetrické – odporúča sa zvážiť transformáciu (napr. log(area)).

3. Density..per.km..

Hustota obyvateľstva má väčšinu hodnôt sústredených pri nízkych číslach, no niekoľko oblastí má extrémne vysokú hustotu.

To sa prejavuje odľahlými bodmi nad horným fúzom boxplotu.

Rozdelenie je pravostranné, teda existujú niektoré extrémne husto obývané regióny.

Transformácia (napr. log) by mohla pomôcť zlepšiť symetriu rozdelenia.

Lineárna regresia

#print("Odhadnuté koeficienty sú: ")
#      print(model$coefficients)
#print("Odhadnuté rezíduá: ")
#print(model$residuals)
#print("Vyrovnané hodnoty vysvetľovanej premennej sú: ")
#print(model$fitted.values)
#print("matica model$xlevels: ")
#print(model.matrix(model))
#X <- model.matrix(model)
#diag(X %*% solve(t(X) %*% X) %*% t(X))

summary(model)

Call:
lm(formula = population ~ year + CCA3, data = SVK_CZE_long)

Residuals:
        1         2         3         4         5         6         7         8         9        10 
   3467.9     494.4 -104658.1  -13724.6  114420.4   -3467.9    -494.4  104658.1   13724.6 -114420.4 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)         10155640      85286 119.077 2.98e-08 ***
year1990 Population   159277     110104   1.447   0.2216    
year2000 Population   183728     110104   1.669   0.1705    
year2010 Population   308615     110104   2.803   0.0487 *  
year2020 Population   371846     110104   3.377   0.0279 *  
CCA3SVK             -5067336      69636 -72.769 2.14e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 110100 on 4 degrees of freedom
Multiple R-squared:  0.9992,    Adjusted R-squared:  0.9983 
F-statistic:  1062 on 5 and 4 DF,  p-value: 2.478e-06
# Nastaviť rozloženie 2 x 2
par(mfrow = c(2, 2))

# Vykresliť všetky 4 diagnostické grafy modelu
plot(model)

# (Voliteľné) pridať spoločný nadpis
mtext("Diagnostické grafy regresného modelu", outer = TRUE, cex = 1.2, font = 2)

# Resetovať layout
par(mfrow = c(1, 1))

Interpretácia grafov

Residuals vs Fitted

Reziduály sú rozložené okolo nuly bez výrazného trendu, čo naznačuje dobré prispôsobenie modelu. Mierne zakrivenie čiary poukazuje na možnú nelinearitu alebo vplyv niekoľkých odľahlých pozorovaní.

Normal Q–Q plot

Väčšina bodov leží blízko diagonály, takže rozdelenie rezíduí je približne normálne. Menšie odchýlky na okrajoch naznačujú len mierne porušenie normality.

Scale–Location

Rozptyl rezíduí sa javí ako približne konštantný, čo podporuje predpoklad homoskedasticity. Mierne výkyvy na začiatku môžu byť spôsobené niekoľkými extrémnymi bodmi.

Residuals vs Factor Levels

Reziduály sa v jednotlivých faktorových úrovniach pohybujú okolo nuly, bez systematického trendu. Body 5 a 10 pôsobia ako možné vplyvné pozorovania, ktoré môžu ovplyvňovať model.

install.packages("tseries")  # len raz
library(tseries)   
# normality tests
residuals <- residuals(model)
jarque.bera.test(residuals)

    Jarque Bera Test

data:  residuals
X-squared = 0.1133, df = 2, p-value = 0.9449
# outlier test (see p-value for Bonferroni correction)
install.packages("car")  
Error in install.packages : Updating loaded packages
library(car)  
outlierTest(model)
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:
model2 <- lm(Density..per.km.. ~ X2020.Population + Area..km.., data = udaje.2020)
summary(model2)

Call:
lm(formula = Density..per.km.. ~ X2020.Population + Area..km.., 
    data = udaje.2020)

Residuals:
    Min      1Q  Median      3Q     Max 
 -493.6  -417.8  -361.8  -217.8 22677.4 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)       4.948e+02  1.434e+02   3.452 0.000662 ***
X2020.Population  2.622e-08  1.124e-06   0.023 0.981404    
Area..km..       -7.495e-05  8.647e-05  -0.867 0.386995    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2071 on 231 degrees of freedom
Multiple R-squared:  0.003987,  Adjusted R-squared:  -0.004636 
F-statistic: 0.4624 on 2 and 231 DF,  p-value: 0.6304
# Diagnostické grafy
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1))
plot(model2)
par(mfrow = c(1, 1))

Interpretácia grafov

Residuals vs Fitted

Reziduály sa väčšinou pohybujú okolo nuly, čo naznačuje, že model nemá výrazné systematické chyby v predikciách. Niekoľko bodov s veľkými reziduálmi (napr. 120, 135, 188) predstavuje možné odľahlé pozorovania.

Normal Q–Q plot

Väčšina bodov sleduje diagonálu, no koniec grafu sa výrazne odchyľuje smerom nahor. To znamená, že reziduály nie sú dokonale normálne rozdelené a existujú extrémne hodnoty v pravej časti rozdelenia.

Scale–Location

Rozptyl rezíduí sa javí ako relatívne konštantný, bez výrazného rozširovania alebo zužovania. Len niekoľko bodov s vysokými štandardizovanými reziduálmi môže naznačovať miernu heteroskedasticitu.

Residuals vs Leverage

Väčšina bodov má nízke hodnoty leverage, čo je dobré, no niekoľko pozorovaní (napr. 120, 135, 172) má väčší vplyv podľa Cookovej vzdialenosti. Tieto pozorovania môžu výraznejšie ovplyvňovať odhad parametrov a je vhodné ich skontrolovať.

residuals <- residuals(model)
jarque.bera.test(residuals)
outlierTest(model)

Zadanie 6 - Heteroskedasticita

library(dplyr)
library(tidyr)
library(ggplot2)
library(patchwork)

# 1️⃣ Preformátovanie dát do dlhého formátu
world_population_long <- world_population %>%
  select(Continent, Country.Territory, 
         X2022.Population, X2020.Population, X2015.Population, 
         X2010.Population, X2000.Population, X1990.Population, X1980.Population, X1970.Population) %>%
  pivot_longer(cols = starts_with("X"), 
               names_to = "Year", 
               values_to = "Population") %>%
  mutate(Year = as.numeric(gsub("X|\\.Population", "", Year))) %>%  # odstráni "X" a ".Population", zostáva rok
  group_by(Country.Territory) %>%
  arrange(Year) %>%
  mutate(GrowthRate = (Population / lag(Population) - 1) * 100) %>%
  ungroup() %>%
  filter(!is.na(GrowthRate))

# 2️⃣ Lineárny model
model <- lm(GrowthRate ~ Year, data = world_population_long)

# 3️⃣ Predikcie a reziduá
world_population_long$pred_model <- predict(model)
world_population_long$resid_model <- resid(model)

# 4️⃣ Grafy heteroskedasticity
p1 <- ggplot(world_population_long, aes(x = Year, y = resid_model^2)) +
  geom_point(alpha = 1, color = "steelblue") +
  geom_smooth(method = "loess", se = FALSE, color = "brown") +
  labs(x = "Rok", y = "Štvorce rezíduí", title = "Residuals² vs Rok") +
  theme_minimal()

p2 <- ggplot(world_population_long, aes(x = GrowthRate, y = resid_model^2)) +
  geom_point(alpha = 0.6, color = "lightgreen") +
  geom_smooth(method = "loess", se = FALSE, color = "pink") +
  labs(x = "Tempo rastu populácie (%)", y = "Štvorce rezíduí", title = "Residuals² vs Growth Rate") +
  theme_minimal()

# 5️⃣ Zobrazenie oboch grafov vedľa seba
p1 + p2

library(ggplot2)
library(patchwork)

model <- lm(GrowthRate ~ Continent, data = world_population_long)
world_population_long$resid_model <- resid(model)

p1 <- ggplot(world_population_long, aes(x = Year, y = resid_model^2)) +
  geom_point(alpha = 0.6, color = "grey") +
  geom_smooth(method = "loess", se = FALSE, color = "purple") +
  labs(x = "Rok", y = "Štvorce rezíduí", title = "Residuals² vs Rok") +
  theme_minimal() +
  theme(
  plot.background = element_rect(fill = "#f5f5dc", color = NA),  # béžová
  panel.background = element_rect(fill = "#f5f5dc", color = NA)
) 

p2 <- ggplot(world_population_long, aes(x = GrowthRate, y = resid_model^2)) +
  geom_point(alpha = 0.6, color = "darkgreen") +
  geom_smooth(method = "loess", se = FALSE, color = "red") +
  labs(x = "Tempo rastu populácie (%)", y = "Štvorce rezíduí", title = "Residuals² vs Growth Rate") +
  theme_minimal() +
  theme(
  plot.background = element_rect(fill = "#f5f5dc", color = NA),  # béžová
  panel.background = element_rect(fill = "#f5f5dc", color = NA)
) 
  

p1 + p2

Graf: Štvorce rezíduí vs Rok

V tomto grafe sledujeme, či sa veľkosť chýb modelu mení v čase. Fialová vyhladená krivka je takmer rovná, čo naznačuje, že rozptyl rezíduí je stabilný naprieč rokmi. To znamená, že premenná „rok“ pravdepodobne nespôsobuje heteroskedasticitu. Model teda v tomto smere neukazuje žiadny systematický problém.

Graf: Štvorce rezíduí vs Tempo rastu populácie

Tu skúmame, či veľkosť chýb závisí od tempa rastu populácie. Červená krivka má výrazný oblúkovitý tvar, čo naznačuje, že model robí väčšie chyby pri extrémnych hodnotách rastu. To je vizuálny náznak heteroskedasticity teda toho, že rozptyl rezíduí nie je konštantný. Tento problém potvrdzuje aj výsledok Breusch–Paganovho testu.

# 📦 Načítanie knižníc
library(dplyr)
library(tidyr)
library(ggplot2)
library(lmtest)
library(patchwork)

# 1️⃣ Preformátovanie dát do dlhého formátu
world_population_long <- world_population %>%
  select(Continent, Country.Territory, 
         X2022.Population, X2020.Population, X2015.Population, 
         X2010.Population, X2000.Population, X1990.Population, X1980.Population, X1970.Population) %>%
  pivot_longer(cols = starts_with("X"), 
               names_to = "Year", 
               values_to = "Population") %>%
  mutate(Year = as.numeric(gsub("X|\\.Population", "", Year))) %>%  # z názvu stĺpca vyber rok
  group_by(Country.Territory) %>%
  arrange(Year) %>%
  mutate(GrowthRate = (Population / lag(Population) - 1) * 100) %>%
  ungroup() %>%
  filter(!is.na(GrowthRate))

# 2️⃣ Vytvorenie lineárneho modelu
model <- lm(GrowthRate ~ Year, data = world_population_long)
summary(model)

Call:
lm(formula = GrowthRate ~ Year, data = world_population_long)

Residuals:
    Min      1Q  Median      3Q     Max 
-69.121  -7.491  -2.093   5.668 239.690 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) 1087.20768   59.39472   18.30   <2e-16 ***
Year          -0.53527    0.02962  -18.07   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 17.63 on 1636 degrees of freedom
Multiple R-squared:  0.1664,    Adjusted R-squared:  0.1659 
F-statistic: 326.6 on 1 and 1636 DF,  p-value: < 2.2e-16
# 3️⃣ Breusch-Pagan test na heteroskedasticitu
bptest(model)

    studentized Breusch-Pagan test

data:  model
BP = 19.018, df = 1, p-value = 1.295e-05

Breusch–Paganov test overuje, či sa veľkosť chýb modelu mení v závislosti od vysvetľujúcich premenných – teda či je prítomná heteroskedasticita. Výsledok testu (BP = 19.018, p-hodnota < 0.001) naznačuje, že rozptyl rezíduí nie je konštantný. To znamená, že model robí systematicky väčšie chyby pri určitých hodnotách vstupných premenných. Takýto problém môže ovplyvniť spoľahlivosť odhadov a vyžaduje úpravu modelu.

# Install (if not yet installed)
# install.packages("lmtest")

# Load the package
library(lmtest)

model2 <- lm(GrowthRate ~ +1 + I(log(Year)),data=world_population_long)
summary(model2)

Call:
lm(formula = GrowthRate ~ +1 + I(log(Year)), data = world_population_long)

Residuals:
    Min      1Q  Median      3Q     Max 
-69.089  -7.493  -2.125   5.670 239.708 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   8153.92     450.83   18.09   <2e-16 ***
I(log(Year)) -1070.57      59.29  -18.06   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 17.63 on 1636 degrees of freedom
Multiple R-squared:  0.1662,    Adjusted R-squared:  0.1657 
F-statistic:   326 on 1 and 1636 DF,  p-value: < 2.2e-16
# Run the Breusch–Pagan test
bptest(model2)

    studentized Breusch-Pagan test

data:  model2
BP = 18.994, df = 1, p-value = 1.311e-05

Tento model skúma vzťah medzi rastom populácie a logaritmicky transformovaným rokom. Výsledky ukazujú, že log(Year) má silne negatívny a štatisticky významný vplyv na rast populácie. Napriek transformácii však Breusch–Paganov test (BP = 18.994, p < 0.001) stále naznačuje prítomnosť heteroskedasticity. To znamená, že rozptyl chýb sa mení a model by mohol byť ďalej upravený, napríklad použitím robustných metód.

#install.packages("sandwich")
#install.packages("lmtest")
library(sandwich)
library(lmtest)
coeftest(model, vcov = vcovHC(model))

t test of coefficients:

               Estimate  Std. Error t value  Pr(>|t|)    
(Intercept) 1087.207679   66.659480  16.310 < 2.2e-16 ***
Year          -0.535267    0.033097 -16.173 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSAtIGltcG9ydCDDumRham92LCBncmFmeSwgxaF0YXRpc3Rpa3kiCmF1dGhvcjogIkJhcmJvcmEgS3VjaMOhcmlrb3bDoSAgPGJyPiIKZGF0ZTogIk9rdMOzYmVyIDIwMjUiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRoZW1lOiB1bml0ZWQKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGNzczogY3VzdG9tLmNzcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQplZGl0b3Jfb3B0aW9uczoKICBtYXJrZG93bjoKICAgIHdyYXA6IDcyCi0tLQoKCiMgKkltcG9ydG92YW5pZSB2bGFzdG5laiBkYXRhYsOhenkqCgpgYGB7cn0KaGVhZCh3b3JsZF9wb3B1bGF0aW9uKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG5pZWtvbGtvIHBydnljaCByaWFka292CmNvbG5hbWVzKHdvcmxkX3BvcHVsYXRpb24pCgpgYGAKCiMgR3JhZnkKCgojIyMgKioqZ2dwbG90MiAtIGtuacW+bmljYSBwcmUgZ3JhZnkqKioKClbDvWJlciBhIG7DoXNsZWRuw6kgdHJpZWRlbmllCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpClNWS19DWkVfZGF0YSA8LSB3b3JsZF9wb3B1bGF0aW9uICU+JQogIGZpbHRlcihDQ0EzICVpbiUgYygiU1ZLIiwgIkNaRSIpKSAlPiUgICMgRmlsdHJvdmFuaWUgbmEgU2xvdmVuc2tvIGEgxIxlc2tvCiAgc2VsZWN0KENDQTMsIGAyMDIwIFBvcHVsYXRpb25gLCBgMjAxMCBQb3B1bGF0aW9uYCwgYDIwMDAgUG9wdWxhdGlvbmAsIGAxOTkwIFBvcHVsYXRpb25gLCBgMTk4MCBQb3B1bGF0aW9uYCkgIyBWeWJlcsOhbWUgbGVuIHJlbGV2YW50bsOpIHN0xLpwY2UKaGVhZChTVktfQ1pFX2RhdGEpCmBgYAoKIyMjIyAqKlNjYXR0ZXIgcGxvdCoqCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncGxvdDIpCgojIFByZWRwb2tsYWTDoW0sIMW+ZSBkYXRhc2V0IGplIHVsb8W+ZW7DvSB2IHByZW1lbm5laiBgU1ZLX0NaRV9kYXRhYAoKIyAxLiBWeWJlcmllbWUgcG90cmVibsOpIHN0xLpwY2UgYSBkw6F0YSBsZW4gcHJlIFNsb3ZlbnNrbyBhIMSMZXNrbwpTVktfQ1pFX3NlbCA8LSBTVktfQ1pFX2RhdGEgJT4lCiAgZmlsdGVyKENDQTMgJWluJSBjKCJTVksiLCAiQ1pFIikpICU+JSAgIyBGaWx0cm92YW5pZSBuYSBTbG92ZW5za28gYSDEjGVza28KICBzZWxlY3QoQ0NBMywgYDIwMjAgUG9wdWxhdGlvbmAsIGAyMDEwIFBvcHVsYXRpb25gLCBgMjAwMCBQb3B1bGF0aW9uYCwgYDE5OTAgUG9wdWxhdGlvbmAsIGAxOTgwIFBvcHVsYXRpb25gKSAgIyBWeWJlcsOhbWUgbGVuIHJlbGV2YW50bsOpIHN0xLpwY2UKCiMgMi4gUHJlbWVuw61tZSBkw6F0YSBkbyBkbGjDqWhvIGZvcm3DoXR1IChwcmUgZ3JhZikKU1ZLX0NaRV9sb25nIDwtIFNWS19DWkVfc2VsICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhgMjAyMCBQb3B1bGF0aW9uYCwgYDIwMTAgUG9wdWxhdGlvbmAsIGAyMDAwIFBvcHVsYXRpb25gLCBgMTk5MCBQb3B1bGF0aW9uYCwgYDE5ODAgUG9wdWxhdGlvbmApLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJ5ZWFyIiwgICAgICMgU3TEunBlYyBzIHJva21pCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJwb3B1bGF0aW9uIikgICMgU3TEunBlYyBzIHBvcHVsw6FjaW91CgojIDMuIFZ5dHZvcsOtbWUgc3TEunBjb3bDvSBncmFmIC0gWm9icmF6w61tZSBwb3B1bMOhY2l1IFNsb3ZlbnNrYSBhIMSMZXNrYSB2IHJva29jaCAxOTgwLCAxOTkwLCAyMDAwLCAyMDEwIGEgMjAyMApnZ3Bsb3QoU1ZLX0NaRV9sb25nLCBhZXMoeCA9IHllYXIseSA9IHBvcHVsYXRpb24sIGZpbGwgPSBDQ0EzLCBncm91cCA9IENDQTMpKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHdpZHRoID0gMC44KSArICMgU3TEunBjb3bDvSBncmFmIHMgb2RkZWxlbsO9bWkgc3TEunBjYW1pIHByZSBrYcW+ZMO6IGtyYWppbnUgCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBvcHVsYXRpb24pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4zKSwgdmp1c3QgPSAtMC4xKSArICMgUHJpZGFuaWUgb3puYcSNZW7DrSBob2Ruw7R0IAogIHRoZW1lX21pbmltYWwoKSArICMgTWluaW1hbGlzdGlja8O9IGRpemFqbiBncmFmdSAKICBsYWJzKHRpdGxlID0gIlbDvXZvaiBwb3B1bMOhY2llIFNsb3ZlbnNrYSBhIMSMZXNrYSIsICMgVXByYXZlbsO9IG5hZHBpcyAKICAgICAgIHggPSAiUm9rIiwgCiAgICAgICB5ID0gIlBvcHVsw6FjaWEiLCAKICAgICAgIGZpbGwgPSAiS3JhamluYSIpICsgIyBQb3BpcyBmYXJpZWIgcG9kxL5hIGtyYWppbnkgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkgIyBSb3TDoWNpYSB0ZXh0dSBuYSBvc2kgWApgYGAKCgoKIyMjIyAqQm94cGxvdCoKCmBgYHtyfQojIEJhciBwbG90IHdpdGggZ3JvdXBpbmcKbGlicmFyeShnZ3Bsb3QyKQoKZ2dwbG90KFNWS19DWkVfbG9uZywgYWVzKHggPSB5ZWFyLCB5ID0gcG9wdWxhdGlvbiwgY29sb3IgPSBDQ0EzLCBncm91cCA9IENDQTMpKSArCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEuMikgKyAgICAgICAgICAgICAgICAgIyDEjGlhcnkgcHJlIGthxb5kw7oga3JhamludQogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgICAgICAgICAgICAgICAgICAgICAgICMgQm9ka3kgbmEgxI1pYXJhY2gKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcG9wdWxhdGlvbiksICAgICAgICAgICAjIEhvZG5vdHkgbmFkIGJvZGthbWkKICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBzaXplID0gMiwgICAgICAgICAgICAjIE1hbMOpIHDDrXNtbywgcG9zdW51dMOpIG1pZXJuZSBuYWhvcgogICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArICAgICAgICAgICAgICMgQmV6IGxlZ2VuZHkgcHJlIHRleHQKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJWw712b2ogcG9wdWzDoWNpZSBTbG92ZW5za2EgYSDEjGVza2EiLAogICAgeCA9ICJSb2siLAogICAgeSA9ICJQb3B1bMOhY2lhIiwKICAgIGNvbG9yID0gIktyYWppbmEiCiAgKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkKYGBgCgojICoqKlrDoWtsYWRuw6kgxaF0YXRpc3Rpa3kqKioKCgojIyAqKmtuaXRyIC0gdGFidcS+a2EqKgoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoa25pdHIpCgojIDEuIFZ5YmVyaWVtZSBwb3RyZWJuw6kgc3TEunBjZSBhIGTDoXRhIGxlbiBwcmUgU2xvdmVuc2tvIGEgxIxlc2tvClNWS19DWkVfc2VsIDwtIFNWS19DWkVfZGF0YSAlPiUKICBmaWx0ZXIoQ0NBMyAlaW4lIGMoIlNWSyIsICJDWkUiKSkgJT4lICAjIEZpbHRyb3ZhbmllIG5hIFNsb3ZlbnNrbyBhIMSMZXNrbwogIHNlbGVjdChDQ0EzLCBgMjAyMCBQb3B1bGF0aW9uYCwgYDIwMTAgUG9wdWxhdGlvbmAsIGAyMDAwIFBvcHVsYXRpb25gLCBgMTk5MCBQb3B1bGF0aW9uYCwgYDE5ODAgUG9wdWxhdGlvbmApICAjIFJlbGV2YW50bsOpIHN0xLpwY2UKCiMgMi4gUHJlbWVuw61tZSBkw6F0YSBkbyBkbGjDqWhvIGZvcm3DoXR1ClNWS19DWkVfbG9uZyA8LSBTVktfQ1pFX3NlbCAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoYDIwMjAgUG9wdWxhdGlvbmAsIGAyMDEwIFBvcHVsYXRpb25gLCBgMjAwMCBQb3B1bGF0aW9uYCwgYDE5OTAgUG9wdWxhdGlvbmAsIGAxOTgwIFBvcHVsYXRpb25gKSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAieWVhciIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJwb3B1bGF0aW9uIikKIyAzLiBWeXBvxI3DrXRhbWUgesOha2xhZG7DqSDFoXRhdGlzdGlreSBwb3B1bMOhY2llIHBvZMS+YSBrcmFqaW55IGEgcm9rdQpTVktfQ1pFX3N0YXRzIDwtIFNWS19DWkVfbG9uZyAlPiUKICBncm91cF9ieShDQ0EzLCB5ZWFyKSAlPiUKICBzdW1tYXJpc2UoCiAgICBuICAgICAgPSBuKCksCiAgICBtZWFuICAgPSBtZWFuKHBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICBzZCAgICAgPSBzZChwb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpLAogICAgbWluICAgID0gbWluKHBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICBxMjUgICAgPSBxdWFudGlsZShwb3B1bGF0aW9uLCAwLjI1LCBuYS5ybSA9IFRSVUUpLAogICAgbWVkaWFuID0gbWVkaWFuKHBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICBxNzUgICAgPSBxdWFudGlsZShwb3B1bGF0aW9uLCAwLjc1LCBuYS5ybSA9IFRSVUUpLAogICAgbWF4ICAgID0gbWF4KHBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKQoKIyA0LiBWeXR2b3LDrW1lIHRhYnXEvmt1IHBvbW9jb3Uga25pdHIKa2FibGUoU1ZLX0NaRV9zdGF0cywgZGlnaXRzID0gMCwgY2FwdGlvbiA9ICJaw6FrbGFkbsOpIMWhdGF0aXN0aWt5IHBvcHVsw6FjaWUgU2xvdmVuc2thIGEgxIxlc2thICgxOTgw4oCTMjAyMCkiKQpgYGAKCgojICpUZXN0b3ZhbmllIGh5cG90w6l6KgoKIyMjIyAqKnQtdGVzdDogUG9yb3ZuYW5pZSBwb3B1bMOhY2llIFNsb3ZlbnNrYSBhIMSMZXNrYSB2IHJva29jaCAyMDIwKioKCmBgYHtyfQojIDEuIFZ5YmVyaWVtZSBwb3B1bMOhY2l1IFNsb3ZlbnNrYSBhIMSMZXNrYSB2IHJva3UgMjAyMApTVktfQ1pFXzIwMjAgPC0gU1ZLX0NaRV9kYXRhICU+JQogIGZpbHRlcihDQ0EzICVpbiUgYygiU1ZLIiwgIkNaRSIpKSAlPiUKICBzZWxlY3QoQ0NBMywgYDIwMjAgUG9wdWxhdGlvbmApCgojIDIuIFZ5a29uw6FtZSB0LXRlc3QgbmEgcG9yb3ZuYW5pZSBwb3B1bMOhY2llIG1lZHppIFNWSyBhIENaRSB2IHJva3UgMjAyMApTVktfcG9wIDwtIFNWS19DWkVfbG9uZyAlPiUgZmlsdGVyKENDQTMgPT0gIlNWSyIpICU+JSBwdWxsKHBvcHVsYXRpb24pCkNaRV9wb3AgPC0gU1ZLX0NaRV9sb25nICU+JSBmaWx0ZXIoQ0NBMyA9PSAiQ1pFIikgJT4lIHB1bGwocG9wdWxhdGlvbikKCiMgMy4gVsO9cGlzIHbDvXNsZWRrdSB0ZXN0dQp0X3Rlc3RfcmVzdWx0IDwtIHQudGVzdChTVktfcG9wLCBDWkVfcG9wKQpwcmludCh0X3Rlc3RfcmVzdWx0KQpgYGAKCgojIyMjICoqKkFOT1ZBOiBDb21wYXJpbmcgUmVhZGluZyBTY29yZXMgQWNyb3NzIFByb2dyYW1zKioqCgpgYGB7cn0KYW5vdmFfcmVzdWx0IDwtIGFvdihwb3B1bGF0aW9uIH4geWVhciwgZGF0YSA9IFNWS19DWkVfbG9uZykKc3VtbWFyeShhbm92YV9yZXN1bHQpCmBgYAoKIyMjIyAqKkxpbmVhciBSZWdyZXNzaW9uOiBQcmVkaWN0aW5nIE1hdGggU2NvcmVzKioKCmBgYHtyfQojVnl0dm9yw61tZSBsaW5lw6FybnkgbW9kZWwgcG9wdWzDoWNpZSBwb2TEvmEgcm9rdSBhIGtyYWppbnkKbW9kZWwgPC0gbG0ocG9wdWxhdGlvbiB+IHllYXIgKyBDQ0EzLCBkYXRhID0gU1ZLX0NaRV9sb25nKQpzdW1tYXJ5KG1vZGVsKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoc3RyaW5ncikKCmNvZWYudGJsIDwtIHRpZHkobW9kZWwsIGNvbmYuaW50ID0gVFJVRSkgJT4lCiAgbXV0YXRlKAogICAgdGVybSA9IHJlY29kZSh0ZXJtLAogICAgICAiKEludGVyY2VwdCkiID0gIkludGVyY2VwdCIsCiAgICAgICJ5ZWFyMTk5MCBQb3B1bGF0aW9uIiA9ICJSb2sgMTk5MCIsCiAgICAgICJ5ZWFyMjAwMCBQb3B1bGF0aW9uIiA9ICJSb2sgMjAwMCIsCiAgICAgICJ5ZWFyMjAxMCBQb3B1bGF0aW9uIiA9ICJSb2sgMjAxMCIsCiAgICAgICJ5ZWFyMjAyMCBQb3B1bGF0aW9uIiA9ICJSb2sgMjAyMCIsCiAgICAgICJDQ0EzU1ZLIiA9ICJTbG92ZW5za28iCiAgICApLAogICAgc3RhcnMgPSBjYXNlX3doZW4oCiAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICBwLnZhbHVlIDwgMC4wMSAgfiAiKioiLAogICAgICBwLnZhbHVlIDwgMC4wNSAgfiAiKiIsCiAgICAgIHAudmFsdWUgPCAwLjEgICB+ICLCtyIsCiAgICAgIFRSVUUgICAgICAgICAgICB+ICIiCiAgICApCiAgKSAlPiUKICB0cmFuc211dGUoCiAgICBUZXJtID0gdGVybSwKICAgIEVzdGltYXRlID0gZXN0aW1hdGUsCiAgICBgU3RkLiBFcnJvcmAgPSBzdGQuZXJyb3IsCiAgICBgdCB2YWx1ZWAgPSBzdGF0aXN0aWMsCiAgICBgcCB2YWx1ZWAgPSBwLnZhbHVlLAogICAgYDk1JSBDSWAgPSBzdHJfYygiWyIsIHJvdW5kKGNvbmYubG93LCAwKSwgIiwgIiwgcm91bmQoY29uZi5oaWdoLCAwKSwgIl0iKSwKICAgIFNpZyA9IHN0YXJzCiAgKQoKY29lZi50YmwgJT4lCiAga2FibGUoCiAgICBkaWdpdHMgPSAwLAogICAgY2FwdGlvbiA9ICJPTFMgcmVncmVzbsOpIGtvZWZpY2llbnR5IChwb3B1bGF0aW9uIH4geWVhciArIENDQTMpIgogICkgJT4lCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSkgJT4lCiAgY29sdW1uX3NwZWMoMSwgYm9sZCA9IFRSVUUpICU+JQogIHJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBiYWNrZ3JvdW5kID0gIiNmMmYyZjIiKSAlPiUKICBmb290bm90ZSgKICAgIGdlbmVyYWwgPSAiU2lnbmlmLiBjb2RlczogKioqIHA8MC4wMDEsICoqIHA8MC4wMSwgKiBwPDAuMDUsIMK3IHA8MC4xLiIsCiAgICB0aHJlZXBhcnR0YWJsZSA9IFRSVUUpCgpgYGAKIyBQcsOtcHJhdmEgZGF0YWLDoXp5LCDEjWlzdGVuaWUgYSDDunByYXZhIMO6ZGFqb3YKCmBgYHtyfQojIE5hxI3DrXRhbmllIGTDoXQKdWRhamUgPC0gcmVhZC5jc3YoIndvcmxkX3BvcHVsYXRpb24uY3N2IiwgZGVjPSIuIiwgc2VwPSIsIiwgaGVhZGVyID0gVFJVRSkKCiMgS29udHJvbGEgbsOhenZvdiBzdMS6cGNvdgpuYW1lcyh1ZGFqZSkKCiMgVsO9YmVyIGxlbiDEjcOtc2VsbsO9Y2ggw7pkYWpvdiAodXByYXYgcG9kxL5hIHByZXNuw71jaCBuw6F6dm92IHN0xLpwY292KQp1ZGFqZS4yMDIwIDwtIHVkYWplWywgYygiWDIwMjAuUG9wdWxhdGlvbiIsICJBcmVhLi5rbS4uIiwgIkRlbnNpdHkuLnBlci5rbS4uIildCgojIEtvbnZlcnppYSBuYSBudW1lcmljCnVkYWplLjIwMjAgPC0gYXMuZGF0YS5mcmFtZShsYXBwbHkodWRhamUuMjAyMCwgYXMubnVtZXJpYykpCgojIE5haHJhZGVuaWUgTkEgbWVkacOhbm1pCmNvbHVtbl9tZWRpYW5zIDwtIHNhcHBseSh1ZGFqZS4yMDIwLCBtZWRpYW4sIG5hLnJtID0gVFJVRSkKZm9yIChjb2wgaW4gbmFtZXModWRhamUuMjAyMCkpIHsKICB1ZGFqZS4yMDIwW1tjb2xdXVtpcy5uYSh1ZGFqZS4yMDIwW1tjb2xdXSldIDwtIGNvbHVtbl9tZWRpYW5zW2NvbF0KfQoKIyBWeWtyZXNsZW5pZSBib3hwbG90b3YKcGFyKG1mcm93ID0gYygyLCAyKSkKcGFyKG1hciA9IGMoNCwgNCwgMiwgMSkpCmZvciAoY29sIGluIG5hbWVzKHVkYWplLjIwMjApKSB7CiAgYm94cGxvdCh1ZGFqZS4yMDIwW1tjb2xdXSwgbWFpbiA9IGNvbCwgeGxhYiA9ICJIb2Rub3R5IiwgY29sID0gImxpZ2h0cGluayIsIGJvcmRlciA9ICJvcmFuZ2UiKQp9CgpgYGAKIyBCb3hwbG90eSDigJMgUG9wdWzDoWNpYSwgUm96bG9oYSBhIEh1c3RvdGEgb2J5dmF0ZcS+c3R2YQojIyBJbnRlcnByZXTDoWNpYSBncmFmb3YKIyMjICoxLiBYMjAyMC5Qb3B1bGF0aW9uKgoKVsOkxI3FoWluYSBob2Ruw7R0IHNhIGtvbmNlbnRydWplIHByaSB2ZcS+bWkgbsOtemt5Y2ggaG9kbm90w6FjaCBwb3B1bMOhY2llLgoKVmlkaXRlxL5uw71jaCBqZSBuaWVrb8S+a28gdsO9cmF6bsO9Y2ggb2TEvmFobMO9Y2ggaG9kbsO0dCAob3V0bGllcnMpIOKAkyBuaWVrdG9yw6kga3JhamlueS/DunplbWlhIG1hasO6IHBvcHVsw6FjaXUgdsO9cmF6bmUgdnnFocWhaXUgbmXFviBvc3RhdG7DqS4KClJvemRlbGVuaWUgamUgc2lsbmUgcHJhdm9zdHJhbm7DqSAocG96aXTDrXZuZSB6b8WhaWttZW7DqSkg4oCTIHbDpMSNxaFpbmEgcG96b3JvdmFuw60gbcOhIG1hbMOpIGhvZG5vdHksIHphdGlhxL4gxI1vIG5pZWtvxL5rbyBleHRyw6ltbnljaCBwb3pvcm92YW7DrSDFpWFow6EgbWVkacOhbiBzbWVyb20gbmFkb2wuCgoKIyMjICoyLiBBcmVhLi5rbS4uKgoKVsOkxI3FoWluYSBrcmFqw61uIG3DoSBwb21lcm5lIG1hbMO6IHJvemxvaHUsIHByacSNb20gem9ww6FyIHZlxL5taSB2ZcS+a8O9Y2ggw7p6ZW3DrSBzcMO0c29idWplIHNpbG7DuiBwcmF2b3N0cmFubsO6IMWhaWttb3PFpS4KClZpYWNlcsOpIGJvZHkgxI9hbGVrbyBvZCBobGF2bsOpaG8gcG/EvmEgZMOhdCBuYXpuYcSNdWrDuiBvZMS+YWhsw6kgcG96b3JvdmFuaWEgKHZlxL5rw6kga3JhamlueSkuCgpQb2RvYm5lIGFrbyBwcmkgcG9wdWzDoWNpaSwgZMOhdGEgc8O6IHZlxL5taSBuZXN5bWV0cmlja8OpIOKAkyBvZHBvcsO6xI1hIHNhIHp2w6HFvmnFpSB0cmFuc2Zvcm3DoWNpdSAobmFwci4gbG9nKGFyZWEpKS4KCiMjIyAqMy4gRGVuc2l0eS4ucGVyLmttLi4qCgpIdXN0b3RhIG9ieXZhdGXEvnN0dmEgbcOhIHbDpMSNxaFpbnUgaG9kbsO0dCBzw7pzdHJlZGVuw71jaCBwcmkgbsOtemt5Y2ggxI3DrXNsYWNoLCBubyBuaWVrb8S+a28gb2JsYXN0w60gbcOhIGV4dHLDqW1uZSB2eXNva8O6IGh1c3RvdHUuCgpUbyBzYSBwcmVqYXZ1amUgb2TEvmFobMO9bWkgYm9kbWkgbmFkIGhvcm7DvW0gZsO6em9tIGJveHBsb3R1LgoKUm96ZGVsZW5pZSBqZSBwcmF2b3N0cmFubsOpLCB0ZWRhIGV4aXN0dWrDuiBuaWVrdG9yw6kgZXh0csOpbW5lIGh1c3RvIG9iw712YW7DqSByZWdpw7NueS4KClRyYW5zZm9ybcOhY2lhIChuYXByLiBsb2cpIGJ5IG1vaGxhIHBvbcO0Y8WlIHpsZXDFoWnFpSBzeW1ldHJpdSByb3pkZWxlbmlhLgoKCiMjIExpbmXDoXJuYSByZWdyZXNpYQoKYGBge3J9CiNwcmludCgiT2RoYWRudXTDqSBrb2VmaWNpZW50eSBzw7o6ICIpCiMgICAgICBwcmludChtb2RlbCRjb2VmZmljaWVudHMpCiNwcmludCgiT2RoYWRudXTDqSByZXrDrWR1w6E6ICIpCiNwcmludChtb2RlbCRyZXNpZHVhbHMpCiNwcmludCgiVnlyb3ZuYW7DqSBob2Rub3R5IHZ5c3ZldMS+b3ZhbmVqIHByZW1lbm5laiBzw7o6ICIpCiNwcmludChtb2RlbCRmaXR0ZWQudmFsdWVzKQojcHJpbnQoIm1hdGljYSBtb2RlbCR4bGV2ZWxzOiAiKQojcHJpbnQobW9kZWwubWF0cml4KG1vZGVsKSkKI1ggPC0gbW9kZWwubWF0cml4KG1vZGVsKQojZGlhZyhYICUqJSBzb2x2ZSh0KFgpICUqJSBYKSAlKiUgdChYKSkKCnN1bW1hcnkobW9kZWwpCgpgYGAKYGBge3IgZGlhZ3Bsb3RzLCBmaWcuY2FwPSJEaWFnbm9zdGlja8OpIGdyYWZ5IHJlZ3Jlc27DqWhvIG1vZGVsdSJ9CiMgTmFzdGF2acWlIHJvemxvxb5lbmllIDIgeCAyCnBhcihtZnJvdyA9IGMoMiwgMikpCgojIFZ5a3Jlc2xpxaUgdsWhZXRreSA0IGRpYWdub3N0aWNrw6kgZ3JhZnkgbW9kZWx1CnBsb3QobW9kZWwpCgojIChWb2xpdGXEvm7DqSkgcHJpZGHFpSBzcG9sb8SNbsO9IG5hZHBpcwptdGV4dCgiRGlhZ25vc3RpY2vDqSBncmFmeSByZWdyZXNuw6lobyBtb2RlbHUiLCBvdXRlciA9IFRSVUUsIGNleCA9IDEuMiwgZm9udCA9IDIpCgojIFJlc2V0b3ZhxaUgbGF5b3V0CnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAojIyBJbnRlcnByZXTDoWNpYSBncmFmb3YKCiMjIyAqUmVzaWR1YWxzIHZzIEZpdHRlZCoKUmV6aWR1w6FseSBzw7ogcm96bG/FvmVuw6kgb2tvbG8gbnVseSBiZXogdsO9cmF6bsOpaG8gdHJlbmR1LCDEjW8gbmF6bmHEjXVqZSBkb2Jyw6kgcHJpc3DDtHNvYmVuaWUgbW9kZWx1LgpNaWVybmUgemFrcml2ZW5pZSDEjWlhcnkgcG91a2F6dWplIG5hIG1vxb5uw7ogbmVsaW5lYXJpdHUgYWxlYm8gdnBseXYgbmlla2/EvmvDvWNoIG9kxL5haGzDvWNoIHBvem9yb3ZhbsOtLgoKIyMjICpOb3JtYWwgUeKAk1EgcGxvdCoKVsOkxI3FoWluYSBib2RvdiBsZcW+w60gYmzDrXprbyBkaWFnb27DoWx5LCB0YWvFvmUgcm96ZGVsZW5pZSByZXrDrWR1w60gamUgcHJpYmxpxb5uZSBub3Jtw6FsbmUuCk1lbsWhaWUgb2RjaMO9bGt5IG5hIG9rcmFqb2NoIG5hem5hxI11asO6IGxlbiBtaWVybmUgcG9ydcWhZW5pZSBub3JtYWxpdHkuCgojIyMgKlNjYWxl4oCTTG9jYXRpb24qClJvenB0eWwgcmV6w61kdcOtIHNhIGphdsOtIGFrbyBwcmlibGnFvm5lIGtvbsWhdGFudG7DvSwgxI1vIHBvZHBvcnVqZSBwcmVkcG9rbGFkIGhvbW9za2VkYXN0aWNpdHkuCk1pZXJuZSB2w71reXZ5IG5hIHphxI1pYXRrdSBtw7TFvnUgYnnFpSBzcMO0c29iZW7DqSBuaWVrb8S+a8O9bWkgZXh0csOpbW55bWkgYm9kbWkuCgojIyMgKlJlc2lkdWFscyB2cyBGYWN0b3IgTGV2ZWxzKgpSZXppZHXDoWx5IHNhIHYgamVkbm90bGl2w71jaCBmYWt0b3JvdsO9Y2ggw7pyb3ZuaWFjaCBwb2h5YnVqw7ogb2tvbG8gbnVseSwgYmV6IHN5c3RlbWF0aWNrw6lobyB0cmVuZHUuCkJvZHkgNSBhIDEwIHDDtHNvYmlhIGFrbyBtb8W+bsOpIHZwbHl2bsOpIHBvem9yb3ZhbmlhLCBrdG9yw6kgbcO0xb51IG92cGx5dsWIb3ZhxaUgbW9kZWwuCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygidHNlcmllcyIpICAjIGxlbiByYXoKbGlicmFyeSh0c2VyaWVzKSAgIApgYGAKCmBgYHtyfQojIG5vcm1hbGl0eSB0ZXN0cwpyZXNpZHVhbHMgPC0gcmVzaWR1YWxzKG1vZGVsKQpqYXJxdWUuYmVyYS50ZXN0KHJlc2lkdWFscykKCiMgb3V0bGllciB0ZXN0IChzZWUgcC12YWx1ZSBmb3IgQm9uZmVycm9uaSBjb3JyZWN0aW9uKQppbnN0YWxsLnBhY2thZ2VzKCJjYXIiKSAgCmxpYnJhcnkoY2FyKSAgCm91dGxpZXJUZXN0KG1vZGVsKQpgYGAKCmBgYHtyfQptb2RlbDIgPC0gbG0oRGVuc2l0eS4ucGVyLmttLi4gfiBYMjAyMC5Qb3B1bGF0aW9uICsgQXJlYS4ua20uLiwgZGF0YSA9IHVkYWplLjIwMjApCnN1bW1hcnkobW9kZWwyKQoKIyBEaWFnbm9zdGlja8OpIGdyYWZ5CnBhcihtZnJvdyA9IGMoMiwgMikpCnBhcihtYXIgPSBjKDQsIDQsIDIsIDEpKQpwbG90KG1vZGVsMikKcGFyKG1mcm93ID0gYygxLCAxKSkKCmBgYAojIyBJbnRlcnByZXTDoWNpYSBncmFmb3YKCiMjIyAqUmVzaWR1YWxzIHZzIEZpdHRlZCoKUmV6aWR1w6FseSBzYSB2w6TEjcWhaW5vdSBwb2h5YnVqw7ogb2tvbG8gbnVseSwgxI1vIG5hem5hxI11amUsIMW+ZSBtb2RlbCBuZW3DoSB2w71yYXpuw6kgc3lzdGVtYXRpY2vDqSBjaHlieSB2IHByZWRpa2Npw6FjaC4KTmlla2/EvmtvIGJvZG92IHMgdmXEvmvDvW1pIHJlemlkdcOhbG1pIChuYXByLiAxMjAsIDEzNSwgMTg4KSBwcmVkc3RhdnVqZSBtb8W+bsOpIG9kxL5haGzDqSBwb3pvcm92YW5pYS4KCiMjIyAqTm9ybWFsIFHigJNRIHBsb3QqClbDpMSNxaFpbmEgYm9kb3Ygc2xlZHVqZSBkaWFnb27DoWx1LCBubyBrb25pZWMgZ3JhZnUgc2EgdsO9cmF6bmUgb2RjaHnEvnVqZSBzbWVyb20gbmFob3IuClRvIHpuYW1lbsOhLCDFvmUgcmV6aWR1w6FseSBuaWUgc8O6IGRva29uYWxlIG5vcm3DoWxuZSByb3pkZWxlbsOpIGEgZXhpc3R1asO6IGV4dHLDqW1uZSBob2Rub3R5IHYgcHJhdmVqIMSNYXN0aSByb3pkZWxlbmlhLgoKIyMjICpTY2FsZeKAk0xvY2F0aW9uKgpSb3pwdHlsIHJlesOtZHXDrSBzYSBqYXbDrSBha28gcmVsYXTDrXZuZSBrb27FoXRhbnRuw70sIGJleiB2w71yYXpuw6lobyByb3rFoWlyb3ZhbmlhIGFsZWJvIHp1xb5vdmFuaWEuCkxlbiBuaWVrb8S+a28gYm9kb3YgcyB2eXNva8O9bWkgxaF0YW5kYXJkaXpvdmFuw71taSByZXppZHXDoWxtaSBtw7TFvmUgbmF6bmHEjW92YcWlIG1pZXJudSBoZXRlcm9za2VkYXN0aWNpdHUuCgojIyMgKlJlc2lkdWFscyB2cyBMZXZlcmFnZSoKVsOkxI3FoWluYSBib2RvdiBtw6EgbsOtemtlIGhvZG5vdHkgbGV2ZXJhZ2UsIMSNbyBqZSBkb2Jyw6ksIG5vIG5pZWtvxL5rbyBwb3pvcm92YW7DrSAobmFwci4gMTIwLCAxMzUsIDE3MikgbcOhIHbDpMSNxaHDrSB2cGx5diBwb2TEvmEgQ29va292ZWogdnpkaWFsZW5vc3RpLgpUaWV0byBwb3pvcm92YW5pYSBtw7TFvnUgdsO9cmF6bmVqxaFpZSBvdnBseXbFiG92YcWlIG9kaGFkIHBhcmFtZXRyb3YgYSBqZSB2aG9kbsOpIGljaCBza29udHJvbG92YcWlLgoKCmBgYHtyfQpyZXNpZHVhbHMgPC0gcmVzaWR1YWxzKG1vZGVsKQpqYXJxdWUuYmVyYS50ZXN0KHJlc2lkdWFscykKb3V0bGllclRlc3QobW9kZWwpCmBgYAoKIyAqKlphZGFuaWUgNiAtIEhldGVyb3NrZWRhc3RpY2l0YSoqCgpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBhdGNod29yaykKCiMgMe+4j+KDoyBQcmVmb3Jtw6F0b3ZhbmllIGTDoXQgZG8gZGxow6lobyBmb3Jtw6F0dQp3b3JsZF9wb3B1bGF0aW9uX2xvbmcgPC0gd29ybGRfcG9wdWxhdGlvbiAlPiUKICBzZWxlY3QoQ29udGluZW50LCBDb3VudHJ5LlRlcnJpdG9yeSwgCiAgICAgICAgIFgyMDIyLlBvcHVsYXRpb24sIFgyMDIwLlBvcHVsYXRpb24sIFgyMDE1LlBvcHVsYXRpb24sIAogICAgICAgICBYMjAxMC5Qb3B1bGF0aW9uLCBYMjAwMC5Qb3B1bGF0aW9uLCBYMTk5MC5Qb3B1bGF0aW9uLCBYMTk4MC5Qb3B1bGF0aW9uLCBYMTk3MC5Qb3B1bGF0aW9uKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IHN0YXJ0c193aXRoKCJYIiksIAogICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwgCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQb3B1bGF0aW9uIikgJT4lCiAgbXV0YXRlKFllYXIgPSBhcy5udW1lcmljKGdzdWIoIlh8XFwuUG9wdWxhdGlvbiIsICIiLCBZZWFyKSkpICU+JSAgIyBvZHN0csOhbmkgIlgiIGEgIi5Qb3B1bGF0aW9uIiwgem9zdMOhdmEgcm9rCiAgZ3JvdXBfYnkoQ291bnRyeS5UZXJyaXRvcnkpICU+JQogIGFycmFuZ2UoWWVhcikgJT4lCiAgbXV0YXRlKEdyb3d0aFJhdGUgPSAoUG9wdWxhdGlvbiAvIGxhZyhQb3B1bGF0aW9uKSAtIDEpICogMTAwKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKCFpcy5uYShHcm93dGhSYXRlKSkKCiMgMu+4j+KDoyBMaW5lw6FybnkgbW9kZWwKbW9kZWwgPC0gbG0oR3Jvd3RoUmF0ZSB+IFllYXIsIGRhdGEgPSB3b3JsZF9wb3B1bGF0aW9uX2xvbmcpCgojIDPvuI/ig6MgUHJlZGlrY2llIGEgcmV6aWR1w6EKd29ybGRfcG9wdWxhdGlvbl9sb25nJHByZWRfbW9kZWwgPC0gcHJlZGljdChtb2RlbCkKd29ybGRfcG9wdWxhdGlvbl9sb25nJHJlc2lkX21vZGVsIDwtIHJlc2lkKG1vZGVsKQoKIyA077iP4oOjIEdyYWZ5IGhldGVyb3NrZWRhc3RpY2l0eQpwMSA8LSBnZ3Bsb3Qod29ybGRfcG9wdWxhdGlvbl9sb25nLCBhZXMoeCA9IFllYXIsIHkgPSByZXNpZF9tb2RlbF4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAxLCBjb2xvciA9ICJzdGVlbGJsdWUiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYnJvd24iKSArCiAgbGFicyh4ID0gIlJvayIsIHkgPSAixaB0dm9yY2UgcmV6w61kdcOtIiwgdGl0bGUgPSAiUmVzaWR1YWxzwrIgdnMgUm9rIikgKwogIHRoZW1lX21pbmltYWwoKQoKcDIgPC0gZ2dwbG90KHdvcmxkX3BvcHVsYXRpb25fbG9uZywgYWVzKHggPSBHcm93dGhSYXRlLCB5ID0gcmVzaWRfbW9kZWxeMikpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC42LCBjb2xvciA9ICJsaWdodGdyZWVuIikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gInBpbmsiKSArCiAgbGFicyh4ID0gIlRlbXBvIHJhc3R1IHBvcHVsw6FjaWUgKCUpIiwgeSA9ICLFoHR2b3JjZSByZXrDrWR1w60iLCB0aXRsZSA9ICJSZXNpZHVhbHPCsiB2cyBHcm93dGggUmF0ZSIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgNe+4j+KDoyBab2JyYXplbmllIG9ib2NoIGdyYWZvdiB2ZWTEvmEgc2ViYQpwMSArIHAyCmBgYApgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBhdGNod29yaykKCm1vZGVsIDwtIGxtKEdyb3d0aFJhdGUgfiBDb250aW5lbnQsIGRhdGEgPSB3b3JsZF9wb3B1bGF0aW9uX2xvbmcpCndvcmxkX3BvcHVsYXRpb25fbG9uZyRyZXNpZF9tb2RlbCA8LSByZXNpZChtb2RlbCkKCnAxIDwtIGdncGxvdCh3b3JsZF9wb3B1bGF0aW9uX2xvbmcsIGFlcyh4ID0gWWVhciwgeSA9IHJlc2lkX21vZGVsXjIpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNiwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJwdXJwbGUiKSArCiAgbGFicyh4ID0gIlJvayIsIHkgPSAixaB0dm9yY2UgcmV6w61kdcOtIiwgdGl0bGUgPSAiUmVzaWR1YWxzwrIgdnMgUm9rIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI2Y1ZjVkYyIsIGNvbG9yID0gTkEpLCAgIyBiw6nFvm92w6EKICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI2Y1ZjVkYyIsIGNvbG9yID0gTkEpCikgCgpwMiA8LSBnZ3Bsb3Qod29ybGRfcG9wdWxhdGlvbl9sb25nLCBhZXMoeCA9IEdyb3d0aFJhdGUsIHkgPSByZXNpZF9tb2RlbF4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYsIGNvbG9yID0gImRhcmtncmVlbiIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQiKSArCiAgbGFicyh4ID0gIlRlbXBvIHJhc3R1IHBvcHVsw6FjaWUgKCUpIiwgeSA9ICLFoHR2b3JjZSByZXrDrWR1w60iLCB0aXRsZSA9ICJSZXNpZHVhbHPCsiB2cyBHcm93dGggUmF0ZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNmNWY1ZGMiLCBjb2xvciA9IE5BKSwgICMgYsOpxb5vdsOhCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNmNWY1ZGMiLCBjb2xvciA9IE5BKQopIAogIAoKcDEgKyBwMgpgYGAKIyMgKipHcmFmOiDFoHR2b3JjZSByZXrDrWR1w60gdnMgUm9rKioKKlYgdG9tdG8gZ3JhZmUgc2xlZHVqZW1lLCDEjWkgc2EgdmXEvmtvc8WlIGNow71iIG1vZGVsdSBtZW7DrSB2IMSNYXNlLiBGaWFsb3bDoSB2eWhsYWRlbsOhIGtyaXZrYSBqZSB0YWttZXIgcm92bsOhLCDEjW8gbmF6bmHEjXVqZSwgxb5lIHJvenB0eWwgcmV6w61kdcOtIGplIHN0YWJpbG7DvSBuYXByaWXEjSByb2ttaS4gVG8gem5hbWVuw6EsIMW+ZSBwcmVtZW5uw6Eg4oCecm9r4oCcIHByYXZkZXBvZG9ibmUgKipuZXNww7Rzb2J1amUgaGV0ZXJvc2tlZGFzdGljaXR1KiouIE1vZGVsIHRlZGEgdiB0b210byBzbWVyZSBuZXVrYXp1amUgxb5pYWRueSBzeXN0ZW1hdGlja8O9IHByb2Jsw6ltLioKCiMjICoqR3JhZjogxaB0dm9yY2UgcmV6w61kdcOtIHZzIFRlbXBvIHJhc3R1IHBvcHVsw6FjaWUqKgoqVHUgc2vDum1hbWUsIMSNaSB2ZcS+a29zxaUgY2jDvWIgesOhdmlzw60gb2QgdGVtcGEgcmFzdHUgcG9wdWzDoWNpZS4gxIxlcnZlbsOhIGtyaXZrYSBtw6EgdsO9cmF6bsO9IG9ibMO6a292aXTDvSB0dmFyLCDEjW8gbmF6bmHEjXVqZSwgxb5lIG1vZGVsIHJvYsOtIHbDpMSNxaFpZSBjaHlieSBwcmkgZXh0csOpbW55Y2ggaG9kbm90w6FjaCByYXN0dS4gVG8gamUgdml6dcOhbG55KiAqKm7DoXpuYWsgaGV0ZXJvc2tlZGFzdGljaXR5ICoqIOKAkyAqdGVkYSB0b2hvLCDFvmUgcm96cHR5bCByZXrDrWR1w60gbmllIGplIGtvbsWhdGFudG7DvS4gVGVudG8gcHJvYmzDqW0gcG90dnJkenVqZSBhaiB2w71zbGVkb2sgQnJldXNjaOKAk1BhZ2Fub3ZobyB0ZXN0dS4qCgpgYGB7cn0KIyDwn5OmIE5hxI3DrXRhbmllIGtuacW+bsOtYwpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkobG10ZXN0KQpsaWJyYXJ5KHBhdGNod29yaykKCiMgMe+4j+KDoyBQcmVmb3Jtw6F0b3ZhbmllIGTDoXQgZG8gZGxow6lobyBmb3Jtw6F0dQp3b3JsZF9wb3B1bGF0aW9uX2xvbmcgPC0gd29ybGRfcG9wdWxhdGlvbiAlPiUKICBzZWxlY3QoQ29udGluZW50LCBDb3VudHJ5LlRlcnJpdG9yeSwgCiAgICAgICAgIFgyMDIyLlBvcHVsYXRpb24sIFgyMDIwLlBvcHVsYXRpb24sIFgyMDE1LlBvcHVsYXRpb24sIAogICAgICAgICBYMjAxMC5Qb3B1bGF0aW9uLCBYMjAwMC5Qb3B1bGF0aW9uLCBYMTk5MC5Qb3B1bGF0aW9uLCBYMTk4MC5Qb3B1bGF0aW9uLCBYMTk3MC5Qb3B1bGF0aW9uKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IHN0YXJ0c193aXRoKCJYIiksIAogICAgICAgICAgICAgICBuYW1lc190byA9ICJZZWFyIiwgCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQb3B1bGF0aW9uIikgJT4lCiAgbXV0YXRlKFllYXIgPSBhcy5udW1lcmljKGdzdWIoIlh8XFwuUG9wdWxhdGlvbiIsICIiLCBZZWFyKSkpICU+JSAgIyB6IG7DoXp2dSBzdMS6cGNhIHZ5YmVyIHJvawogIGdyb3VwX2J5KENvdW50cnkuVGVycml0b3J5KSAlPiUKICBhcnJhbmdlKFllYXIpICU+JQogIG11dGF0ZShHcm93dGhSYXRlID0gKFBvcHVsYXRpb24gLyBsYWcoUG9wdWxhdGlvbikgLSAxKSAqIDEwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcighaXMubmEoR3Jvd3RoUmF0ZSkpCgojIDLvuI/ig6MgVnl0dm9yZW5pZSBsaW5lw6FybmVobyBtb2RlbHUKbW9kZWwgPC0gbG0oR3Jvd3RoUmF0ZSB+IFllYXIsIGRhdGEgPSB3b3JsZF9wb3B1bGF0aW9uX2xvbmcpCnN1bW1hcnkobW9kZWwpCiMgM++4j+KDoyBCcmV1c2NoLVBhZ2FuIHRlc3QgbmEgaGV0ZXJvc2tlZGFzdGljaXR1CmJwdGVzdChtb2RlbCkKYGBgCipCcmV1c2No4oCTUGFnYW5vdiB0ZXN0IG92ZXJ1amUsIMSNaSBzYSB2ZcS+a29zxaUgY2jDvWIgbW9kZWx1IG1lbsOtIHYgesOhdmlzbG9zdGkgb2QgdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaCDigJMgdGVkYSDEjWkgamUgcHLDrXRvbW7DoSBoZXRlcm9za2VkYXN0aWNpdGEuIFbDvXNsZWRvayB0ZXN0dSAoQlAgPSAxOS4wMTgsIHAtaG9kbm90YSA8IDAuMDAxKSBuYXpuYcSNdWplLCDFvmUgcm96cHR5bCByZXrDrWR1w60gbmllIGplIGtvbsWhdGFudG7DvS4gVG8gem5hbWVuw6EsIMW+ZSBtb2RlbCByb2LDrSBzeXN0ZW1hdGlja3kgdsOkxI3FoWllIGNoeWJ5IHByaSB1csSNaXTDvWNoIGhvZG5vdMOhY2ggdnN0dXBuw71jaCBwcmVtZW5uw71jaC4gVGFrw710byBwcm9ibMOpbSBtw7TFvmUgb3ZwbHl2bmnFpSBzcG/EvmFobGl2b3PFpSBvZGhhZG92IGEgdnnFvmFkdWplIMO6cHJhdnUgbW9kZWx1LioKCmBgYHtyfQojIEluc3RhbGwgKGlmIG5vdCB5ZXQgaW5zdGFsbGVkKQojIGluc3RhbGwucGFja2FnZXMoImxtdGVzdCIpCgojIExvYWQgdGhlIHBhY2thZ2UKbGlicmFyeShsbXRlc3QpCgptb2RlbDIgPC0gbG0oR3Jvd3RoUmF0ZSB+ICsxICsgSShsb2coWWVhcikpLGRhdGE9d29ybGRfcG9wdWxhdGlvbl9sb25nKQpzdW1tYXJ5KG1vZGVsMikKCiMgUnVuIHRoZSBCcmV1c2No4oCTUGFnYW4gdGVzdApicHRlc3QobW9kZWwyKQpgYGAKKlRlbnRvIG1vZGVsIHNrw7ptYSB2esWlYWggbWVkemkgcmFzdG9tIHBvcHVsw6FjaWUgYSBsb2dhcml0bWlja3kgdHJhbnNmb3Jtb3ZhbsO9bSByb2tvbS4gVsO9c2xlZGt5IHVrYXp1asO6LCDFvmUgbG9nKFllYXIpIG3DoSBzaWxuZSBuZWdhdMOtdm55IGEgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70gdnBseXYgbmEgcmFzdCBwb3B1bMOhY2llLiBOYXByaWVrIHRyYW5zZm9ybcOhY2lpIHbFoWFrIEJyZXVzY2jigJNQYWdhbm92IHRlc3QgKEJQID0gMTguOTk0LCBwIDwgMC4wMDEpIHN0w6FsZSBuYXpuYcSNdWplIHByw610b21ub3PFpSBoZXRlcm9za2VkYXN0aWNpdHkuIFRvIHpuYW1lbsOhLCDFvmUgcm96cHR5bCBjaMO9YiBzYSBtZW7DrSBhIG1vZGVsIGJ5IG1vaG9sIGJ5xaUgxI9hbGVqIHVwcmF2ZW7DvSwgbmFwcsOta2xhZCBwb3XFvml0w61tIHJvYnVzdG7DvWNoIG1ldMOzZC4qCgpgYGB7cn0KI2luc3RhbGwucGFja2FnZXMoInNhbmR3aWNoIikKI2luc3RhbGwucGFja2FnZXMoImxtdGVzdCIpCmxpYnJhcnkoc2FuZHdpY2gpCmxpYnJhcnkobG10ZXN0KQpjb2VmdGVzdChtb2RlbCwgdmNvdiA9IHZjb3ZIQyhtb2RlbCkpCmBgYAo=