S využitím databázy Databaza.csv (so štruktúrou zhodnou s hárokom v_om7101mr_00_00_00_sk) s mesačnými údajmi za rok 2024 na úrovni obcí a okresov na Slovensku. Stĺpce 2024M012024M12 obsahujú mesačné hodnoty miery nezamestnanosti (%). V analýze pracujeme s rokom 2024, pričom pozorovaním je kombinácia obec × mesiac.

Pri práci používame knižnice:

library(readr)
library(dplyr)
library(tidyr)
library(stringr)
library(ggplot2)
library(lmtest)
library(sandwich)
library(car)
library(tseries)
rm(list = ls())

V hlavnom menu mám Session nastavené na Source File Location. Alternatívne možno použiť v Console príkaz, napr.:

setwd("/Cloud/project/tyzdne/tyzden5")

Údaje sú v súbore udaje/Databaza.csv (odporúčam mať súbor v podpriečinku udaje).

Úvod do problému a hypotézy

Chceme skúmať, ako sa mesačná miera nezamestnanosti v roku 2024 líši naprieč mesiacmi a okresmi/obcami.

  • Budeme modelovať Mieru nezamestnanosti (v %) v závislosti od:
    • časového trendu v rámci roka (index mesiaca 1–12),
    • fixných efektov okresov (zachytia priestorové rozdiely),
    • a alternatívne aj sezónnych efektov mesiacov (faktor mesiaca).

Hypotézy: 1. Existujú významné rozdiely medzi okresmi (fixné efekty budú štatisticky významné). 2. V priebehu roka pozorujeme mierny trend/sezónnosť (v niektorých mesiacoch je nezamestnanosť vyššia/nižšia). 3. Diagnostika môže ukázať heteroskedasticitu (rozptyl rezíduí sa líši medzi obcami/okresmi), preto overíme aj robustné (HC) smerodajné chyby a transformáciu.

Načítanie, čistenie a príprava údajov

# ===== Načítanie, čistenie a príprava údajov (robustná verzia) =====

library(readr)
library(dplyr)
library(tidyr)
library(stringr)

# zvoľ cestu: ak existuje udaje/Databaza.csv, použi ju; inak hľadaj v koreňovom priečinku
FILE <- if (file.exists("udaje/Databaza.csv")) "udaje/Databaza.csv" else "Databaza.csv"

# 1) načítanie CSV; ak by bolo ; a desatinná čiarka, prepneme na read_csv2
raw <- suppressMessages(readr::read_csv(FILE, show_col_types = FALSE, locale = locale(encoding = "UTF-8")))
if (ncol(raw) == 1) {
  # pravdepodobne ; ako oddeľovač
  raw <- suppressMessages(readr::read_csv2(FILE, show_col_types = FALSE,
                                           locale = locale(encoding = "UTF-8", decimal_mark = ",", grouping_mark = " ")))
}

# 2) očistenie názvov stĺpcov (trim, na malé, nahradiť medzery podčiarkovníkom)
names(raw) <- gsub("\\s+", "_", tolower(trimws(names(raw))), perl = TRUE)

# 3) nájdi stĺpce s mesiacmi 2024: akceptuj 2024M01, 2024-01, 202401, 2024_01, 2024 01
month_cols <- names(raw)[grepl(
  "^2024(m)?(0[1-9]|1[0-2])$|^2024[-_ ]?(0[1-9]|1[0-2])$|^2024(0[1-9]|1[0-2])$",
  names(raw), perl = TRUE
)]

stopifnot(length(month_cols) > 0)

# 4) nájdi stĺpce okres/obec podľa názvov (fallback: prvé dva nemesačné stĺpce)
cand_okres <- names(raw)[grepl("^(okres|district)", names(raw), perl = TRUE)]
cand_obec  <- names(raw)[grepl("^(obec|municip|nazov_obce|nazov_obce|obec_nazov)", names(raw), perl = TRUE)]

non_month <- setdiff(names(raw), month_cols)

if (length(cand_okres) == 0) cand_okres <- non_month[1]
if (length(cand_obec)  == 0) cand_obec  <- non_month[2]

stopifnot(!is.na(cand_okres), !is.na(cand_obec))

# 5) premenuj na štandardné mená Okres/Obec
raw <- raw |>
  rename(Okres = all_of(cand_okres),
         Obec  = all_of(cand_obec))

# 6) wide -> long
df_long <- raw |>
  tidyr::pivot_longer(all_of(month_cols), names_to = "Mesacnik", values_to = "Miera") |>
  mutate(
    # Mesacnik ako "2024M01" / "2024-01" / "202401" -> vyťaž mesiac
    Year  = 2024L,
    Month = as.integer(str_extract(Mesacnik, "(0[1-9]|1[0-2])")),
    MonthIndex = Month
  ) |>
  select(Okres, Obec, Year, Month, MonthIndex, Miera)

# 7) typy a chýbajúce hodnoty
df_long <- df_long |>
  mutate(
    Okres = as.factor(Okres),
    Obec  = as.factor(Obec),
    Miera = suppressWarnings(as.numeric(Miera))
  )

# 8) imputácia chýbajúcich – medián obce; ak obec celý rok chýba, medián okresu; ak aj to chýba, celkový medián
overall_med <- median(df_long$Miera, na.rm = TRUE)
df_long <- df_long |>
  group_by(Okres) |>
  mutate(okres_med = median(Miera, na.rm = TRUE)) |>
  ungroup() |>
  group_by(Obec) |>
  mutate(obec_med = median(Miera, na.rm = TRUE)) |>
  ungroup() |>
  mutate(
    Miera = ifelse(is.na(Miera),
                   ifelse(!is.na(obec_med), obec_med,
                          ifelse(!is.na(okres_med), okres_med, overall_med)),
                   Miera)
  ) |>
  select(-okres_med, -obec_med)

# 9) rýchla kontrola
summary(df_long$Miera)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    100     883    1716    4922    3264  112794 

Teraz si vizualizujeme rozloženie a extrémy:

# krabicové grafy pre maticu (vybrané premenné)
par(mfrow=c(1,3), mar=c(4,4,2,1))
boxplot(df_long$Miera, main="Miera nezamestnanosti (%)", xlab="", col="lightblue")
boxplot(df_long$MonthIndex, main="Index mesiaca (1–12)", xlab="", col="lightblue")
boxplot(tapply(df_long$Miera, df_long$Okres, median), main="Medián podľa okresu", col="lightblue")
mtext("Boxploty vybraných premenných", outer = TRUE, cex = 1.2, font = 2)
par(mfrow=c(1,1))

Lineárna regresia (panel 2024)

Zvolíme dva prirodzené modely:

  • Model A (trend + okresy):
    Miera ~ 1 + MonthIndex + Okres
    — meria priemerný trend v roku 2024 s rozdielmi medzi okresmi.

  • Model B (sezónnosť + okresy):
    Miera ~ 1 + factor(Month) + Okres
    — namiesto lineárneho trendu zachytí plnú sezónnosť mesiacov.

# robustne nájdi mesačné stĺpce (2024 + mesiac v rôznych formátoch)
month_cols <- names(raw)[grepl(
  "(^|[^0-9])2024\\D*(0[1-9]|1[0-2])($|\\D)", 
  names(raw), perl = TRUE
)]

if (length(month_cols) < 2) {
  message("Pozor: našiel som iba ", length(month_cols), " mesačných stĺpcov.")
  message("Hlavička dát:"); print(names(raw))
  stop("Potrebujem aspoň 2 mesačné stĺpce (napr. 2024M01, 2024M02, ...).")
}

library(stringr)

df_long <- raw |>
  tidyr::pivot_longer(all_of(month_cols), names_to = "Mesacnik", values_to = "Miera") |>
  mutate(
    Year  = 2024L,
    Month = as.integer(str_match(Mesacnik, "(0[1-9]|1[0-2])")[,1]),
    MonthIndex = Month
  ) |>
  select(Okres, Obec, Year, Month, MonthIndex, Miera)

df_long <- droplevels(df_long)

if (dplyr::n_distinct(df_long$Okres) < 2) {
  message("Pozor: Okres má len jednu úroveň. Model s Okres ako faktor nedáva zmysel.")
}

if (dplyr::n_distinct(df_long$Month) < 2) {
  message("Pozor: Month má len jednu úroveň – Model B (sezónnosť) sa preskočí.")
}

# Model A
modelA <- lm(Miera ~ 1 + MonthIndex + Okres, data = df_long)
summary(modelA)

Call:
lm(formula = Miera ~ 1 + MonthIndex + Okres, data = df_long)

Residuals:
   Min     1Q Median     3Q    Max 
-28712  -1740  -1034    135  82312 

Coefficients: (1 not defined because of singularities)
                           Estimate Std. Error t value Pr(>|t|)    
(Intercept)                   47498       2599  18.276  < 2e-16 ***
MonthIndex                       NA         NA      NA       NA    
OkresOkres Bratislava II      -5405       3001  -1.801   0.0718 .  
OkresOkres Bratislava III    -21554       3001  -7.182 9.12e-13 ***
OkresOkres Bratislava IV     -29986       2807 -10.682  < 2e-16 ***
OkresOkres Bratislava V      -17016       2906  -5.856 5.39e-09 ***
OkresOkres Dunajská Streda   -45596       2618 -17.415  < 2e-16 ***
OkresOkres Galanta           -44850       2635 -17.022  < 2e-16 ***
OkresOkres Hlohovec          -44118       2757 -16.004  < 2e-16 ***
OkresOkres Malacky           -44427       2648 -16.774  < 2e-16 ***
OkresOkres Pezinok           -43380       2674 -16.221  < 2e-16 ***
OkresOkres Senec             -43841       2643 -16.585  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 9003 on 2389 degrees of freedom
Multiple R-squared:  0.4226,    Adjusted R-squared:  0.4202 
F-statistic: 174.9 on 10 and 2389 DF,  p-value: < 2.2e-16
# Model B – iba ak je aspoň 2+ mesiacov
if (dplyr::n_distinct(df_long$Month) >= 2) {
  modelB <- lm(Miera ~ 1 + factor(Month) + Okres, data = df_long)
  summary(modelB)
} else {
  message("Model B (factor(Month)) preskakujem: v dátach je len jeden mesiac.")
}

names(raw) <- gsub("\\s+", "_", tolower(trimws(names(raw))), perl = TRUE)

Interpretácia:

  • Koeficient MonthIndex (Model A) ukazuje, či má nezamestnanosť v roku 2024 rastúci/klesajúci trend.
  • Faktor Month (Model B) umožní porovnať každý mesiac so základným (január), a tým zmerať sezónnosť.
  • Koeficienty Okres zachytávajú trvalé rozdiely medzi okresmi (napr. štruktúra ekonomiky, veľkosť trhu práce a pod.).

Diagnostické grafy

par(mfrow=c(2,2))
plot(modelA)
par(mfrow=c(1,1))

Residuals vs Fitted

  • Ak reziduá kmitajú okolo nuly bez kónusu, je rozptyl približne konštantný (homoskedasticita). Kónus –> heteroskedasticita.

Q–Q plot

  • Odchýlky na koncoch znamenajú nenormalitu rezíduí (ťažšie chvosty).

Scale-Location

  • Rovnomerná výška/šírka naznačuje konštantný rozptyl.

Residuals vs Leverage

  • Sledujeme vplyvné pozorovania (Cookove vzdialenosti).

Formálne testy normality a odľahlostí

resA <- residuals(modelA)

# Jarque–Bera test normality
jb_A <- jarque.bera.test(resA)
jb_A

    Jarque Bera Test

data:  resA
X-squared = 139874, df = 2, p-value < 2.2e-16
# Outlier test (Bonferroni)
out_A <- outlierTest(modelA)
out_A

Ak normalita nevychádza (pri väčšom n je to bežné), môžeme skúsiť miernu transformáciu (napr. log(…)), ale pri percentách hrozí nula. Použijeme log(Miera + c), kde c je malé kladné číslo.

c_eps <- max(1e-3, 0.01*median(df_long$Miera, na.rm=TRUE))
df_long <- df_long |> mutate(Miera_log = log(Miera + c_eps))

modelA_log <- lm(Miera_log ~ 1 + MonthIndex + Okres, data = df_long)
summary(modelA_log)

Call:
lm(formula = Miera_log ~ 1 + MonthIndex + Okres, data = df_long)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.91782 -0.66110 -0.03617  0.52232  2.99933 

Coefficients: (1 not defined because of singularities)
                           Estimate Std. Error t value Pr(>|t|)    
(Intercept)                 10.7688     0.2766  38.940  < 2e-16 ***
MonthIndex                       NA         NA      NA       NA    
OkresOkres Bratislava II    -0.3385     0.3193  -1.060  0.28919    
OkresOkres Bratislava III   -0.8977     0.3193  -2.811  0.00498 ** 
OkresOkres Bratislava IV    -1.3931     0.2987  -4.664 3.28e-06 ***
OkresOkres Bratislava V     -1.8724     0.3092  -6.056 1.62e-09 ***
OkresOkres Dunajská Streda  -3.7277     0.2786 -13.380  < 2e-16 ***
OkresOkres Galanta          -3.3050     0.2804 -11.788  < 2e-16 ***
OkresOkres Hlohovec         -3.5681     0.2933 -12.164  < 2e-16 ***
OkresOkres Malacky          -3.1714     0.2818 -11.254  < 2e-16 ***
OkresOkres Pezinok          -3.0171     0.2846 -10.602  < 2e-16 ***
OkresOkres Senec            -3.0874     0.2813 -10.976  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.958 on 2389 degrees of freedom
Multiple R-squared:  0.3501,    Adjusted R-squared:  0.3474 
F-statistic: 128.7 on 10 and 2389 DF,  p-value: < 2.2e-16
par(mfrow=c(2,2)); plot(modelA_log); par(mfrow=c(1,1))


# normalita a odľahlé po transformácii
jarque.bera.test(residuals(modelA_log))

    Jarque Bera Test

data:  residuals(modelA_log)
X-squared = 146.11, df = 2, p-value < 2.2e-16
outlierTest(modelA_log)
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:

Heteroskedasticita

Otestujeme prítomnosť heteroskedasticity Breusch–Paganovým testom pre Model A aj transformovaný model:

bptest(modelA)

    studentized Breusch-Pagan test

data:  modelA
BP = 1025, df = 10, p-value < 2.2e-16
bptest(modelA_log)

    studentized Breusch-Pagan test

data:  modelA_log
BP = 100.3, df = 10, p-value < 2.2e-16

Ak je heteroskedasticita prítomná, použijeme White-HC robustné smerodajné chyby:

coeftest(modelA, vcov = vcovHC(modelA))      # robustné SE pre model A

t test of coefficients:

                             Estimate Std. Error   t value  Pr(>|t|)    
(Intercept)                 47498.333     27.059 1755.3841 < 2.2e-16 ***
OkresOkres Bratislava II    -5404.806   4954.148   -1.0910   0.27540    
OkresOkres Bratislava III  -21554.028   2757.620   -7.8162 8.096e-15 ***
OkresOkres Bratislava IV   -29986.347   1585.497  -18.9129 < 2.2e-16 ***
OkresOkres Bratislava V    -17016.271   6987.021   -2.4354   0.01495 *  
OkresOkres Dunajská Streda -45596.346    117.882 -386.7974 < 2.2e-16 ***
OkresOkres Galanta         -44850.377    161.300 -278.0559 < 2.2e-16 ***
OkresOkres Hlohovec        -44118.031    636.330  -69.3320 < 2.2e-16 ***
OkresOkres Malacky         -44426.676    223.010 -199.2142 < 2.2e-16 ***
OkresOkres Pezinok         -43379.926    394.388 -109.9930 < 2.2e-16 ***
OkresOkres Senec           -43841.109    221.210 -198.1875 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
coeftest(modelA_log, vcov = vcovHC(modelA_log))

t test of coefficients:

                              Estimate  Std. Error    t value  Pr(>|t|)    
(Intercept)                10.76880958  0.00056941 18912.3506 < 2.2e-16 ***
OkresOkres Bratislava II   -0.33853454  0.10899306    -3.1060  0.001919 ** 
OkresOkres Bratislava III  -0.89765407  0.14595436    -6.1502 9.042e-10 ***
OkresOkres Bratislava IV   -1.39311045  0.11792566   -11.8135 < 2.2e-16 ***
OkresOkres Bratislava V    -1.87238053  0.23760590    -7.8802 4.922e-15 ***
OkresOkres Dunajská Streda -3.72771556  0.03097039  -120.3639 < 2.2e-16 ***
OkresOkres Galanta         -3.30503736  0.04134388   -79.9402 < 2.2e-16 ***
OkresOkres Hlohovec        -3.56808417  0.11902083   -29.9787 < 2.2e-16 ***
OkresOkres Malacky         -3.17144336  0.05190112   -61.1055 < 2.2e-16 ***
OkresOkres Pezinok         -3.01705929  0.07296094   -41.3517 < 2.2e-16 ***
OkresOkres Senec           -3.08741108  0.05861326   -52.6743 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Vizualizácia heteroskedasticity (príklad)

# Reziduá^2 vs. fitted (Model A)
df_long$fitA <- fitted(modelA)
df_long$res2A <- residuals(modelA)^2

ggplot(df_long, aes(x = fitA, y = res2A)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "loess", se = FALSE) +
  labs(x = "Fitted values", y = "Squared residuals",
       title = "Heteroskedasticita: reziduá^2 vs. fitted (Model A)") +
  theme_minimal()

Zhrnutie výsledkov

  • Okresy: Fixné efekty okresov sú spravidla štatisticky významné – regionálne rozdiely v miere nezamestnanosti v roku 2024 existujú.
  • Čas:
    • V Modeli A koeficient MonthIndex ukáže, či v roku 2024 existuje trend (rast/klesanie).
    • V Modeli B porovnanie factor(Month) odhalí sezónny profil.
  • Diagnostika: Normalita rezíduí sa pri veľkom n často formálne zamieta; dôležitejšia je robustnosť odhadov. BP test prípadnú heteroskedasticitu odhalí a v týchto prípadoch používame HC robustné chyby.
  • Interpretácia je teraz priamo viazaná na tvoju databázu 2024M01–2024M12 na úrovni obec/okres, nie na WHO life expectancy.

Poznámky k rozšíreniam

  • Vieme pridať efekty obcí, náhodné efekty (balík lme4), mapové vizualizácie podľa okresov, alebo porovnať prvú vs. druhú polovicu roka 2024.
LS0tCnRpdGxlOiAiRWNvbm9tZXRyaWNzIGluIFIgLSBjdmnEjWVuaWUgNSIKYXV0aG9yOiAiRmlsaXAgSnVya8OhxI1layIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRoZW1lOiB1bml0ZWQKICAgIGhpZ2hsaWdodDogdGFuZ28KZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IDcyCi0tLQoKUyB2eXXFvml0w61tIGRhdGFiw6F6eSAqKkRhdGFiYXphLmNzdioqIChzbyDFoXRydWt0w7pyb3UgemhvZG5vdSBzIGjDoXJva29tIGB2X29tNzEwMW1yXzAwXzAwXzAwX3NrYCkKcyBtZXNhxI1uw71taSDDumRham1pIHphIHJvayAyMDI0IG5hIMO6cm92bmkgb2Jjw60gYSBva3Jlc292IG5hIFNsb3ZlbnNrdS4KU3TEunBjZSBgMjAyNE0wMWAgYcW+IGAyMDI0TTEyYCBvYnNhaHVqw7ogKiptZXNhxI1uw6kgaG9kbm90eSBtaWVyeSBuZXphbWVzdG5hbm9zdGkgKCUpKiouClYgYW5hbMO9emUgcHJhY3VqZW1lIHMgcm9rb20gMjAyNCwgcHJpxI1vbSBwb3pvcm92YW7DrW0gamUga29tYmluw6FjaWEgKm9iZWMgw5cgbWVzaWFjKi4KClByaSBwcsOhY2kgcG91xb7DrXZhbWUga25pxb5uaWNlOgoKYGBge3J9CmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGxtdGVzdCkKbGlicmFyeShzYW5kd2ljaCkKbGlicmFyeShjYXIpCmxpYnJhcnkodHNlcmllcykKcm0obGlzdCA9IGxzKCkpCmBgYAoKViAqaGxhdm5vbSBtZW51KiBtw6FtICoqU2Vzc2lvbioqIG5hc3RhdmVuw6kgbmEgKipTb3VyY2UgRmlsZSBMb2NhdGlvbioqLgpBbHRlcm5hdMOtdm5lIG1vxb5ubyBwb3XFvmnFpSB2IENvbnNvbGUgcHLDrWtheiwgbmFwci46Cgpgc2V0d2QoIi9DbG91ZC9wcm9qZWN0L3R5emRuZS90eXpkZW41IilgCgrDmmRhamUgc8O6IHYgc8O6Ym9yZSBgdWRhamUvRGF0YWJhemEuY3N2YCAob2Rwb3LDusSNYW0gbWHFpSBzw7pib3IgdiBwb2RwcmllxI1pbmt1ICoqdWRhamUqKikuCgojIMOadm9kIGRvIHByb2Jsw6ltdSBhIGh5cG90w6l6eQoKQ2hjZW1lIHNrw7ptYcWlLCBha28gc2EgKiptZXNhxI1uw6EgbWllcmEgbmV6YW1lc3RuYW5vc3RpKiogdiByb2t1IDIwMjQgbMOtxaFpIG5hcHJpZcSNIG1lc2lhY21pIGEgb2tyZXNtaS9vYmNhbWkuCgotIEJ1ZGVtZSBtb2RlbG92YcWlICpNaWVydSBuZXphbWVzdG5hbm9zdGkqICh2ICUpIHYgesOhdmlzbG9zdGkgb2Q6CiAgLSAqKsSNYXNvdsOpaG8gdHJlbmR1KiogdiByw6FtY2kgcm9rYSAoaW5kZXggbWVzaWFjYSAx4oCTMTIpLAogIC0gKipmaXhuw71jaCBlZmVrdG92IG9rcmVzb3YqKiAoemFjaHl0aWEgcHJpZXN0b3JvdsOpIHJvemRpZWx5KSwKICAtIGEgYWx0ZXJuYXTDrXZuZSBhaiAqKnNlesOzbm55Y2ggZWZla3RvdiBtZXNpYWNvdioqIChmYWt0b3IgbWVzaWFjYSkuCgoqKkh5cG90w6l6eToqKgoxLiBFeGlzdHVqw7ogKip2w716bmFtbsOpIHJvemRpZWx5IG1lZHppIG9rcmVzbWkqKiAoZml4bsOpIGVmZWt0eSBidWTDuiDFoXRhdGlzdGlja3kgdsO9em5hbW7DqSkuCjIuIFYgcHJpZWJlaHUgcm9rYSBwb3pvcnVqZW1lICoqbWllcm55IHRyZW5kL3NlesOzbm5vc8WlKiogKHYgbmlla3RvcsO9Y2ggbWVzaWFjb2NoIGplIG5lemFtZXN0bmFub3PFpSB2ecWhxaFpYS9uacW+xaFpYSkuCjMuIERpYWdub3N0aWthIG3DtMW+ZSB1a8OhemHFpSAqKmhldGVyb3NrZWRhc3RpY2l0dSoqIChyb3pwdHlsIHJlesOtZHXDrSBzYSBsw63FoWkgbWVkemkgb2JjYW1pL29rcmVzbWkpLCBwcmV0byBvdmVyw61tZSBhaiByb2J1c3Ruw6kgKEhDKSBzbWVyb2Rham7DqSBjaHlieSBhIHRyYW5zZm9ybcOhY2l1LgoKIyBOYcSNw610YW5pZSwgxI1pc3RlbmllIGEgcHLDrXByYXZhIMO6ZGFqb3YKCmBgYHtyfQojID09PT09IE5hxI3DrXRhbmllLCDEjWlzdGVuaWUgYSBwcsOtcHJhdmEgw7pkYWpvdiAocm9idXN0bsOhIHZlcnppYSkgPT09PT0KCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoc3RyaW5ncikKCiMgenZvxL4gY2VzdHU6IGFrIGV4aXN0dWplIHVkYWplL0RhdGFiYXphLmNzdiwgcG91xb5pIGp1OyBpbmFrIGjEvmFkYWogdiBrb3JlxYhvdm9tIHByaWXEjWlua3UKRklMRSA8LSBpZiAoZmlsZS5leGlzdHMoInVkYWplL0RhdGFiYXphLmNzdiIpKSAidWRhamUvRGF0YWJhemEuY3N2IiBlbHNlICJEYXRhYmF6YS5jc3YiCgojIDEpIG5hxI3DrXRhbmllIENTVjsgYWsgYnkgYm9sbyA7IGEgZGVzYXRpbm7DoSDEjWlhcmthLCBwcmVwbmVtZSBuYSByZWFkX2NzdjIKcmF3IDwtIHN1cHByZXNzTWVzc2FnZXMocmVhZHI6OnJlYWRfY3N2KEZJTEUsIHNob3dfY29sX3R5cGVzID0gRkFMU0UsIGxvY2FsZSA9IGxvY2FsZShlbmNvZGluZyA9ICJVVEYtOCIpKSkKaWYgKG5jb2wocmF3KSA9PSAxKSB7CiAgIyBwcmF2ZGVwb2RvYm5lIDsgYWtvIG9kZGXEvm92YcSNCiAgcmF3IDwtIHN1cHByZXNzTWVzc2FnZXMocmVhZHI6OnJlYWRfY3N2MihGSUxFLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9jYWxlID0gbG9jYWxlKGVuY29kaW5nID0gIlVURi04IiwgZGVjaW1hbF9tYXJrID0gIiwiLCBncm91cGluZ19tYXJrID0gIiAiKSkpCn0KCiMgMikgb8SNaXN0ZW5pZSBuw6F6dm92IHN0xLpwY292ICh0cmltLCBuYSBtYWzDqSwgbmFocmFkacWlIG1lZHplcnkgcG9kxI1pYXJrb3Zuw61rb20pCm5hbWVzKHJhdykgPC0gZ3N1YigiXFxzKyIsICJfIiwgdG9sb3dlcih0cmltd3MobmFtZXMocmF3KSkpLCBwZXJsID0gVFJVRSkKCiMgMykgbsOhamRpIHN0xLpwY2UgcyBtZXNpYWNtaSAyMDI0OiBha2NlcHR1aiAyMDI0TTAxLCAyMDI0LTAxLCAyMDI0MDEsIDIwMjRfMDEsIDIwMjQgMDEKbW9udGhfY29scyA8LSBuYW1lcyhyYXcpW2dyZXBsKAogICJeMjAyNChtKT8oMFsxLTldfDFbMC0yXSkkfF4yMDI0Wy1fIF0/KDBbMS05XXwxWzAtMl0pJHxeMjAyNCgwWzEtOV18MVswLTJdKSQiLAogIG5hbWVzKHJhdyksIHBlcmwgPSBUUlVFCildCgpzdG9waWZub3QobGVuZ3RoKG1vbnRoX2NvbHMpID4gMCkKCiMgNCkgbsOhamRpIHN0xLpwY2Ugb2tyZXMvb2JlYyBwb2TEvmEgbsOhenZvdiAoZmFsbGJhY2s6IHBydsOpIGR2YSBuZW1lc2HEjW7DqSBzdMS6cGNlKQpjYW5kX29rcmVzIDwtIG5hbWVzKHJhdylbZ3JlcGwoIl4ob2tyZXN8ZGlzdHJpY3QpIiwgbmFtZXMocmF3KSwgcGVybCA9IFRSVUUpXQpjYW5kX29iZWMgIDwtIG5hbWVzKHJhdylbZ3JlcGwoIl4ob2JlY3xtdW5pY2lwfG5hem92X29iY2V8bmF6b3Zfb2JjZXxvYmVjX25hem92KSIsIG5hbWVzKHJhdyksIHBlcmwgPSBUUlVFKV0KCm5vbl9tb250aCA8LSBzZXRkaWZmKG5hbWVzKHJhdyksIG1vbnRoX2NvbHMpCgppZiAobGVuZ3RoKGNhbmRfb2tyZXMpID09IDApIGNhbmRfb2tyZXMgPC0gbm9uX21vbnRoWzFdCmlmIChsZW5ndGgoY2FuZF9vYmVjKSAgPT0gMCkgY2FuZF9vYmVjICA8LSBub25fbW9udGhbMl0KCnN0b3BpZm5vdCghaXMubmEoY2FuZF9va3JlcyksICFpcy5uYShjYW5kX29iZWMpKQoKIyA1KSBwcmVtZW51aiBuYSDFoXRhbmRhcmRuw6kgbWVuw6EgT2tyZXMvT2JlYwpyYXcgPC0gcmF3IHw+CiAgcmVuYW1lKE9rcmVzID0gYWxsX29mKGNhbmRfb2tyZXMpLAogICAgICAgICBPYmVjICA9IGFsbF9vZihjYW5kX29iZWMpKQoKIyA2KSB3aWRlIC0+IGxvbmcKZGZfbG9uZyA8LSByYXcgfD4KICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGFsbF9vZihtb250aF9jb2xzKSwgbmFtZXNfdG8gPSAiTWVzYWNuaWsiLCB2YWx1ZXNfdG8gPSAiTWllcmEiKSB8PgogIG11dGF0ZSgKICAgICMgTWVzYWNuaWsgYWtvICIyMDI0TTAxIiAvICIyMDI0LTAxIiAvICIyMDI0MDEiIC0+IHZ5xaVhxb4gbWVzaWFjCiAgICBZZWFyICA9IDIwMjRMLAogICAgTW9udGggPSBhcy5pbnRlZ2VyKHN0cl9leHRyYWN0KE1lc2FjbmlrLCAiKDBbMS05XXwxWzAtMl0pIikpLAogICAgTW9udGhJbmRleCA9IE1vbnRoCiAgKSB8PgogIHNlbGVjdChPa3JlcywgT2JlYywgWWVhciwgTW9udGgsIE1vbnRoSW5kZXgsIE1pZXJhKQoKIyA3KSB0eXB5IGEgY2jDvWJhasO6Y2UgaG9kbm90eQpkZl9sb25nIDwtIGRmX2xvbmcgfD4KICBtdXRhdGUoCiAgICBPa3JlcyA9IGFzLmZhY3RvcihPa3JlcyksCiAgICBPYmVjICA9IGFzLmZhY3RvcihPYmVjKSwKICAgIE1pZXJhID0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKE1pZXJhKSkKICApCgojIDgpIGltcHV0w6FjaWEgY2jDvWJhasO6Y2ljaCDigJMgbWVkacOhbiBvYmNlOyBhayBvYmVjIGNlbMO9IHJvayBjaMO9YmEsIG1lZGnDoW4gb2tyZXN1OyBhayBhaiB0byBjaMO9YmEsIGNlbGtvdsO9IG1lZGnDoW4Kb3ZlcmFsbF9tZWQgPC0gbWVkaWFuKGRmX2xvbmckTWllcmEsIG5hLnJtID0gVFJVRSkKZGZfbG9uZyA8LSBkZl9sb25nIHw+CiAgZ3JvdXBfYnkoT2tyZXMpIHw+CiAgbXV0YXRlKG9rcmVzX21lZCA9IG1lZGlhbihNaWVyYSwgbmEucm0gPSBUUlVFKSkgfD4KICB1bmdyb3VwKCkgfD4KICBncm91cF9ieShPYmVjKSB8PgogIG11dGF0ZShvYmVjX21lZCA9IG1lZGlhbihNaWVyYSwgbmEucm0gPSBUUlVFKSkgfD4KICB1bmdyb3VwKCkgfD4KICBtdXRhdGUoCiAgICBNaWVyYSA9IGlmZWxzZShpcy5uYShNaWVyYSksCiAgICAgICAgICAgICAgICAgICBpZmVsc2UoIWlzLm5hKG9iZWNfbWVkKSwgb2JlY19tZWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKCFpcy5uYShva3Jlc19tZWQpLCBva3Jlc19tZWQsIG92ZXJhbGxfbWVkKSksCiAgICAgICAgICAgICAgICAgICBNaWVyYSkKICApIHw+CiAgc2VsZWN0KC1va3Jlc19tZWQsIC1vYmVjX21lZCkKCiMgOSkgcsO9Y2hsYSBrb250cm9sYQpzdW1tYXJ5KGRmX2xvbmckTWllcmEpCmBgYAoKVGVyYXogc2kgdml6dWFsaXp1amVtZSByb3psb8W+ZW5pZSBhIGV4dHLDqW15OgoKYGBge3J9CiMga3JhYmljb3bDqSBncmFmeSBwcmUgbWF0aWN1ICh2eWJyYW7DqSBwcmVtZW5uw6kpCnBhcihtZnJvdz1jKDEsMyksIG1hcj1jKDQsNCwyLDEpKQpib3hwbG90KGRmX2xvbmckTWllcmEsIG1haW49Ik1pZXJhIG5lemFtZXN0bmFub3N0aSAoJSkiLCB4bGFiPSIiLCBjb2w9ImxpZ2h0Ymx1ZSIpCmJveHBsb3QoZGZfbG9uZyRNb250aEluZGV4LCBtYWluPSJJbmRleCBtZXNpYWNhICgx4oCTMTIpIiwgeGxhYj0iIiwgY29sPSJsaWdodGJsdWUiKQpib3hwbG90KHRhcHBseShkZl9sb25nJE1pZXJhLCBkZl9sb25nJE9rcmVzLCBtZWRpYW4pLCBtYWluPSJNZWRpw6FuIHBvZMS+YSBva3Jlc3UiLCBjb2w9ImxpZ2h0Ymx1ZSIpCm10ZXh0KCJCb3hwbG90eSB2eWJyYW7DvWNoIHByZW1lbm7DvWNoIiwgb3V0ZXIgPSBUUlVFLCBjZXggPSAxLjIsIGZvbnQgPSAyKQpwYXIobWZyb3c9YygxLDEpKQpgYGAKCiMgTGluZcOhcm5hIHJlZ3Jlc2lhIChwYW5lbCAyMDI0KQoKWnZvbMOtbWUgZHZhIHByaXJvZHplbsOpIG1vZGVseToKCi0gKipNb2RlbCBBICh0cmVuZCArIG9rcmVzeSkqKjogIAogIGBNaWVyYSB+IDEgKyBNb250aEluZGV4ICsgT2tyZXNgICAKICDigJQgbWVyaWEgcHJpZW1lcm7DvSB0cmVuZCB2IHJva3UgMjAyNCBzIHJvemRpZWxtaSBtZWR6aSBva3Jlc21pLgoKLSAqKk1vZGVsIEIgKHNlesOzbm5vc8WlICsgb2tyZXN5KSoqOiAgCiAgYE1pZXJhIH4gMSArIGZhY3RvcihNb250aCkgKyBPa3Jlc2AgIAogIOKAlCBuYW1pZXN0byBsaW5lw6FybmVobyB0cmVuZHUgemFjaHl0w60gcGxuw7ogc2V6w7Nubm9zxaUgbWVzaWFjb3YuCgpgYGB7cn0KIyByb2J1c3RuZSBuw6FqZGkgbWVzYcSNbsOpIHN0xLpwY2UgKDIwMjQgKyBtZXNpYWMgdiByw7R6bnljaCBmb3Jtw6F0b2NoKQptb250aF9jb2xzIDwtIG5hbWVzKHJhdylbZ3JlcGwoCiAgIihefFteMC05XSkyMDI0XFxEKigwWzEtOV18MVswLTJdKSgkfFxcRCkiLCAKICBuYW1lcyhyYXcpLCBwZXJsID0gVFJVRQopXQoKaWYgKGxlbmd0aChtb250aF9jb2xzKSA8IDIpIHsKICBtZXNzYWdlKCJQb3pvcjogbmHFoWllbCBzb20gaWJhICIsIGxlbmd0aChtb250aF9jb2xzKSwgIiBtZXNhxI1uw71jaCBzdMS6cGNvdi4iKQogIG1lc3NhZ2UoIkhsYXZpxI1rYSBkw6F0OiIpOyBwcmludChuYW1lcyhyYXcpKQogIHN0b3AoIlBvdHJlYnVqZW0gYXNwb8WIIDIgbWVzYcSNbsOpIHN0xLpwY2UgKG5hcHIuIDIwMjRNMDEsIDIwMjRNMDIsIC4uLikuIikKfQoKbGlicmFyeShzdHJpbmdyKQoKZGZfbG9uZyA8LSByYXcgfD4KICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGFsbF9vZihtb250aF9jb2xzKSwgbmFtZXNfdG8gPSAiTWVzYWNuaWsiLCB2YWx1ZXNfdG8gPSAiTWllcmEiKSB8PgogIG11dGF0ZSgKICAgIFllYXIgID0gMjAyNEwsCiAgICBNb250aCA9IGFzLmludGVnZXIoc3RyX21hdGNoKE1lc2FjbmlrLCAiKDBbMS05XXwxWzAtMl0pIilbLDFdKSwKICAgIE1vbnRoSW5kZXggPSBNb250aAogICkgfD4KICBzZWxlY3QoT2tyZXMsIE9iZWMsIFllYXIsIE1vbnRoLCBNb250aEluZGV4LCBNaWVyYSkKCmRmX2xvbmcgPC0gZHJvcGxldmVscyhkZl9sb25nKQoKaWYgKGRwbHlyOjpuX2Rpc3RpbmN0KGRmX2xvbmckT2tyZXMpIDwgMikgewogIG1lc3NhZ2UoIlBvem9yOiBPa3JlcyBtw6EgbGVuIGplZG51IMO6cm92ZcWILiBNb2RlbCBzIE9rcmVzIGFrbyBmYWt0b3IgbmVkw6F2YSB6bXlzZWwuIikKfQoKaWYgKGRwbHlyOjpuX2Rpc3RpbmN0KGRmX2xvbmckTW9udGgpIDwgMikgewogIG1lc3NhZ2UoIlBvem9yOiBNb250aCBtw6EgbGVuIGplZG51IMO6cm92ZcWIIOKAkyBNb2RlbCBCIChzZXrDs25ub3PFpSkgc2EgcHJlc2tvxI3DrS4iKQp9CgojIE1vZGVsIEEKbW9kZWxBIDwtIGxtKE1pZXJhIH4gMSArIE1vbnRoSW5kZXggKyBPa3JlcywgZGF0YSA9IGRmX2xvbmcpCnN1bW1hcnkobW9kZWxBKQoKIyBNb2RlbCBCIOKAkyBpYmEgYWsgamUgYXNwb8WIIDIrIG1lc2lhY292CmlmIChkcGx5cjo6bl9kaXN0aW5jdChkZl9sb25nJE1vbnRoKSA+PSAyKSB7CiAgbW9kZWxCIDwtIGxtKE1pZXJhIH4gMSArIGZhY3RvcihNb250aCkgKyBPa3JlcywgZGF0YSA9IGRmX2xvbmcpCiAgc3VtbWFyeShtb2RlbEIpCn0gZWxzZSB7CiAgbWVzc2FnZSgiTW9kZWwgQiAoZmFjdG9yKE1vbnRoKSkgcHJlc2tha3VqZW06IHYgZMOhdGFjaCBqZSBsZW4gamVkZW4gbWVzaWFjLiIpCn0KCm5hbWVzKHJhdykgPC0gZ3N1YigiXFxzKyIsICJfIiwgdG9sb3dlcih0cmltd3MobmFtZXMocmF3KSkpLCBwZXJsID0gVFJVRSkKCmBgYAoKKipJbnRlcnByZXTDoWNpYToqKgoKLSBLb2VmaWNpZW50IGBNb250aEluZGV4YCAoTW9kZWwgQSkgdWthenVqZSwgxI1pIG3DoSBuZXphbWVzdG5hbm9zxaUgdiByb2t1IDIwMjQgKipyYXN0w7pjaS9rbGVzYWrDumNpIHRyZW5kKiouCi0gRmFrdG9yIGBNb250aGAgKE1vZGVsIEIpIHVtb8W+bsOtIHBvcm92bmHFpSAqKmthxb5kw70gbWVzaWFjKiogc28gesOha2xhZG7DvW0gKGphbnXDoXIpLCBhIHTDvW0gem1lcmHFpSAqKnNlesOzbm5vc8WlKiouCi0gS29lZmljaWVudHkgYE9rcmVzYCB6YWNoeXTDoXZhasO6ICoqdHJ2YWzDqSByb3pkaWVseSoqIG1lZHppIG9rcmVzbWkgKG5hcHIuIMWhdHJ1a3TDunJhIGVrb25vbWlreSwgdmXEvmtvc8WlIHRyaHUgcHLDoWNlIGEgcG9kLikuCgojIyBEaWFnbm9zdGlja8OpIGdyYWZ5CgpgYGB7cn0KcGFyKG1mcm93PWMoMiwyKSkKcGxvdChtb2RlbEEpCnBhcihtZnJvdz1jKDEsMSkpCmBgYAoKIyMjIFJlc2lkdWFscyB2cyBGaXR0ZWQKLSBBayByZXppZHXDoSBrbWl0YWrDuiBva29sbyBudWx5IGJleiBrw7NudXN1LCBqZSByb3pwdHlsIHByaWJsacW+bmUga29uxaF0YW50bsO9IChob21vc2tlZGFzdGljaXRhKS4gS8OzbnVzIOKAkz4gaGV0ZXJvc2tlZGFzdGljaXRhLgoKIyMjIFHigJNRIHBsb3QKLSBPZGNow71sa3kgbmEga29uY29jaCB6bmFtZW5hasO6IG5lbm9ybWFsaXR1IHJlesOtZHXDrSAoxaVhxb7FoWllIGNodm9zdHkpLgoKIyMjIFNjYWxlLUxvY2F0aW9uCi0gUm92bm9tZXJuw6EgdsO9xaFrYS/FocOtcmthIG5hem5hxI11amUga29uxaF0YW50bsO9IHJvenB0eWwuCgojIyMgUmVzaWR1YWxzIHZzIExldmVyYWdlCi0gU2xlZHVqZW1lIHZwbHl2bsOpIHBvem9yb3ZhbmlhIChDb29rb3ZlIHZ6ZGlhbGVub3N0aSkuCgojIyBGb3Jtw6FsbmUgdGVzdHkgbm9ybWFsaXR5IGEgb2TEvmFobG9zdMOtCgpgYGB7cn0KcmVzQSA8LSByZXNpZHVhbHMobW9kZWxBKQoKIyBKYXJxdWXigJNCZXJhIHRlc3Qgbm9ybWFsaXR5CmpiX0EgPC0gamFycXVlLmJlcmEudGVzdChyZXNBKQpqYl9BCgojIE91dGxpZXIgdGVzdCAoQm9uZmVycm9uaSkKb3V0X0EgPC0gb3V0bGllclRlc3QobW9kZWxBKQpvdXRfQQpgYGAKCkFrIG5vcm1hbGl0YSBuZXZ5Y2jDoWR6YSAocHJpIHbDpMSNxaFvbSBuIGplIHRvIGJlxb5uw6kpLCBtw7TFvmVtZSBza8O6c2nFpSBtaWVybnUgdHJhbnNmb3Jtw6FjaXUgKG5hcHIuIGxvZyjigKYpKSwgYWxlIHByaSBwZXJjZW50w6FjaCBocm96w60gbnVsYS4KUG91xb5pamVtZSBgbG9nKE1pZXJhICsgYylgLCBrZGUgYGNgIGplIG1hbMOpIGtsYWRuw6kgxI3DrXNsby4KCmBgYHtyfQpjX2VwcyA8LSBtYXgoMWUtMywgMC4wMSptZWRpYW4oZGZfbG9uZyRNaWVyYSwgbmEucm09VFJVRSkpCmRmX2xvbmcgPC0gZGZfbG9uZyB8PiBtdXRhdGUoTWllcmFfbG9nID0gbG9nKE1pZXJhICsgY19lcHMpKQoKbW9kZWxBX2xvZyA8LSBsbShNaWVyYV9sb2cgfiAxICsgTW9udGhJbmRleCArIE9rcmVzLCBkYXRhID0gZGZfbG9uZykKc3VtbWFyeShtb2RlbEFfbG9nKQoKcGFyKG1mcm93PWMoMiwyKSk7IHBsb3QobW9kZWxBX2xvZyk7IHBhcihtZnJvdz1jKDEsMSkpCgojIG5vcm1hbGl0YSBhIG9kxL5haGzDqSBwbyB0cmFuc2Zvcm3DoWNpaQpqYXJxdWUuYmVyYS50ZXN0KHJlc2lkdWFscyhtb2RlbEFfbG9nKSkKb3V0bGllclRlc3QobW9kZWxBX2xvZykKYGBgCgojIyBIZXRlcm9za2VkYXN0aWNpdGEKCk90ZXN0dWplbWUgcHLDrXRvbW5vc8WlIGhldGVyb3NrZWRhc3RpY2l0eSBCcmV1c2No4oCTUGFnYW5vdsO9bSB0ZXN0b20gcHJlIE1vZGVsIEEgYWogdHJhbnNmb3Jtb3ZhbsO9IG1vZGVsOgoKYGBge3J9CmJwdGVzdChtb2RlbEEpCmJwdGVzdChtb2RlbEFfbG9nKQpgYGAKCkFrIGplIGhldGVyb3NrZWRhc3RpY2l0YSBwcsOtdG9tbsOhLCBwb3XFvmlqZW1lICoqV2hpdGUtSEMqKiByb2J1c3Ruw6kgc21lcm9kYWpuw6kgY2h5Ynk6CgpgYGB7cn0KY29lZnRlc3QobW9kZWxBLCB2Y292ID0gdmNvdkhDKG1vZGVsQSkpICAgICAgIyByb2J1c3Ruw6kgU0UgcHJlIG1vZGVsIEEKY29lZnRlc3QobW9kZWxBX2xvZywgdmNvdiA9IHZjb3ZIQyhtb2RlbEFfbG9nKSkKYGBgCgojIyBWaXp1YWxpesOhY2lhIGhldGVyb3NrZWRhc3RpY2l0eSAocHLDrWtsYWQpCgpgYGB7cn0KIyBSZXppZHXDoV4yIHZzLiBmaXR0ZWQgKE1vZGVsIEEpCmRmX2xvbmckZml0QSA8LSBmaXR0ZWQobW9kZWxBKQpkZl9sb25nJHJlczJBIDwtIHJlc2lkdWFscyhtb2RlbEEpXjIKCmdncGxvdChkZl9sb25nLCBhZXMoeCA9IGZpdEEsIHkgPSByZXMyQSkpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC41KSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSkgKwogIGxhYnMoeCA9ICJGaXR0ZWQgdmFsdWVzIiwgeSA9ICJTcXVhcmVkIHJlc2lkdWFscyIsCiAgICAgICB0aXRsZSA9ICJIZXRlcm9za2VkYXN0aWNpdGE6IHJlemlkdcOhXjIgdnMuIGZpdHRlZCAoTW9kZWwgQSkiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyBaaHJudXRpZSB2w71zbGVka292CgotICoqT2tyZXN5Kio6IEZpeG7DqSBlZmVrdHkgb2tyZXNvdiBzw7ogc3ByYXZpZGxhIMWhdGF0aXN0aWNreSB2w716bmFtbsOpIOKAkyByZWdpb27DoWxuZSByb3pkaWVseSB2IG1pZXJlIG5lemFtZXN0bmFub3N0aSB2IHJva3UgMjAyNCBleGlzdHVqw7ouCi0gKirEjGFzKio6ICAKICAtIFYgKipNb2RlbGkgQSoqIGtvZWZpY2llbnQgYE1vbnRoSW5kZXhgIHVrw6HFvmUsIMSNaSB2IHJva3UgMjAyNCBleGlzdHVqZSAqKnRyZW5kKiogKHJhc3Qva2xlc2FuaWUpLiAgCiAgLSBWICoqTW9kZWxpIEIqKiBwb3Jvdm5hbmllIGBmYWN0b3IoTW9udGgpYCBvZGhhbMOtICoqc2V6w7NubnkgcHJvZmlsKiouCi0gKipEaWFnbm9zdGlrYSoqOiBOb3JtYWxpdGEgcmV6w61kdcOtIHNhIHByaSB2ZcS+a29tIG4gxI1hc3RvIGZvcm3DoWxuZSB6YW1pZXRhOyBkw7RsZcW+aXRlasWhaWEgamUgcm9idXN0bm9zxaUgb2RoYWRvdi4gKipCUCB0ZXN0KiogcHLDrXBhZG7DuiBoZXRlcm9za2VkYXN0aWNpdHUgb2RoYWzDrSBhIHYgdMO9Y2h0byBwcsOtcGFkb2NoIHBvdcW+w612YW1lICoqSEMgcm9idXN0bsOpIGNoeWJ5KiouCi0gKipJbnRlcnByZXTDoWNpYSoqIGplIHRlcmF6IHByaWFtbyB2aWF6YW7DoSBuYSB0dm9qdSAqKmRhdGFiw6F6dSAyMDI0TTAx4oCTMjAyNE0xMioqIG5hIMO6cm92bmkgKipvYmVjL29rcmVzKiosIG5pZSBuYSBXSE8gbGlmZSBleHBlY3RhbmN5LgoKIyMgUG96bsOhbWt5IGsgcm96xaHDrXJlbmlhbQoKLSBWaWVtZSBwcmlkYcWlIGVmZWt0eSBvYmPDrSwgbsOhaG9kbsOpIGVmZWt0eSAoYmFsw61rIGBsbWU0YCksIG1hcG92w6kgdml6dWFsaXrDoWNpZSBwb2TEvmEgb2tyZXNvdiwgYWxlYm8gcG9yb3ZuYcWlIHBydsO6IHZzLiBkcnVow7ogcG9sb3ZpY3Ugcm9rYSAyMDI0Lgo=