# Load data
udaje <- read.csv("world_population.csv", dec=".", sep=",", header = TRUE)

# Select relevant variables for prediction
udaje_pred <- udaje[, c("Country.Territory","X2020.Population", "X2015.Population",
                        "Growth.Rate", "Continent")]

# Median imputation for numeric variables
numeric_cols <- c("X2020.Population", "X2015.Population", "Growth.Rate")
column_medians <- sapply(udaje_pred[, numeric_cols], median, na.rm = TRUE)
for (col in numeric_cols) {
  udaje_pred[[col]][is.na(udaje_pred[[col]])] <- column_medians[col]
}

# Log-transform for modeling
udaje_pred$log_pop <- log(udaje_pred$X2020.Population)
udaje_pred$log_pop15 <- log(udaje_pred$X2015.Population)

# Dataset ready for predictive modeling
udaje <- udaje_pred

Čo skúmame:

  • Pripravujeme dáta na predikciu budúcej populácie.

  • Chýbajúce hodnoty dopĺňame mediánom, aby model fungoval správne.

  • Log-transformácia populácie stabilizuje extrémne rozdiely medzi malými a veľkými krajinami.

# Pre budúcu populáciu nás najviac zaujíma historická populácia a rast
xvars <- udaje[, c("X2015.Population", "Growth.Rate")]
round(cor(xvars), 3)
                 X2015.Population Growth.Rate
X2015.Population            1.000      -0.032
Growth.Rate                -0.032       1.000

Teraz zisťujeme, ako sú medzi sebou prepojené historická populácia a ročný rast. Väčšinou historická populácia a Growth.Rate nie sú silne korelované → obe môžu byť použité ako prediktory pre budúcu populáciu.

pairs(xvars,
      main = "Scatterplotová matica – historická populácia a Growth Rate")

Vizualizujeme vzťah medzi historickou populáciou a rastom a pozrieme sa, či existujú extrémne hodnoty alebo netypické krajiny.

Ako môžme vidieť, väčšina krajín sa nachádza v stabilnom pásme rastu, niektoré majú extrémne hodnoty, ktoré môžu ovplyvniť predikciu.

library(car)
vif(model)
       Area..km.. Density..per.km..       Growth.Rate 
         1.004343          1.009057          1.005232 
X <- model.matrix(model)[, -1]
XtX <- t(X) %*% X
eig <- eigen(XtX)

condition_number <- sqrt(max(eig$values) / min(eig$values))
condition_number
[1] 1980890

Chceme zistiť, ako historická populácia, rast a kontinent vplývajú na populáciu 2020. Model nám zároveň slúži na overenie predikčnej schopnosti.

# Model predikcie populácie 2020
model_pred <- lm(log_pop ~ log_pop15 + Growth.Rate + Continent, data = udaje)
summary(model_pred)

Call:
lm(formula = log_pop ~ log_pop15 + Growth.Rate + Continent, data = udaje)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.228477 -0.018980  0.001669  0.020626  0.181035 

Coefficients:
                        Estimate Std. Error t value Pr(>|t|)    
(Intercept)            -2.274370   0.267180  -8.513 2.39e-15 ***
log_pop15               0.999371   0.001313 761.114  < 2e-16 ***
Growth.Rate             2.347058   0.262618   8.937  < 2e-16 ***
ContinentAsia          -0.021732   0.009384  -2.316 0.021465 *  
ContinentEurope        -0.057497   0.010139  -5.671 4.32e-08 ***
ContinentNorth America -0.041139   0.010860  -3.788 0.000195 ***
ContinentOceania       -0.048714   0.012870  -3.785 0.000197 ***
ContinentSouth America -0.024168   0.013950  -1.732 0.084559 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.04529 on 226 degrees of freedom
Multiple R-squared:  0.9997,    Adjusted R-squared:  0.9997 
F-statistic: 1.25e+05 on 7 and 226 DF,  p-value: < 2.2e-16

Historická populácia je najsilnejší prediktor.

Growth.Rate má pozitívny vplyv – krajiny s vyšším rastom budú väčšie.

Kontinent zachytáva regionálne rozdiely (napr. Európa má priemerne menšiu populáciu pri rovnakej historickej veľkosti).

# Spätná transformácia na počet obyvateľov
udaje$pred_pop2020 <- exp(predict(model_pred, newdata = udaje))

# Predikcia podľa Growth.Rate
udaje$pred_pop2025 <- udaje$X2020.Population * (1 + udaje$Growth.Rate)^5
udaje$pred_pop2030 <- udaje$X2020.Population * (1 + udaje$Growth.Rate)^10


# --- Výber konkrétnych krajín ---
vybrane_krajiny <- c("Slovakia", 
                     "Czech Republic", 
                     "Hungary", 
                     "Austria", 
                     "Ukraine", 
                     "Poland")

# Filtrovanie podľa názvu krajiny
udaje_vybrane <- udaje[udaje$Country.Territory %in% vybrane_krajiny, ]


# --- Zobrazenie výsledku ---
udaje_vybrane[, c("Country.Territory", 
                  "X2020.Population", 
                  "pred_pop2020", 
                  "pred_pop2025", 
                  "pred_pop2030")]

Predikujeme populáciu do budúcnosti (2025 a 2030) pomocou Growth.Rate. Umožňuje nám odhadnúť rast a porovnať ho medzi krajinami.

Keď sa pozrieme na naše výsledky, vidíme, že východiskové hodnoty populácie v roku 2020 zodpovedajú reálnym počtom obyvateľov v jednotlivých krajinách. Model však pri dlhodobej predikcii (najmä smerom k roku 2030) generuje extrémne vysoké čísla. Toto sa deje preto, že sme použili jednoduchý výpočet založený na exponenciálnom raste, ktorý pri dlhšom období veľmi preháňa výsledky.

V krátkodobom horizonte (do roku 2025) sú predpovede ešte relatívne podobné realite – populácia sa mení len mierne. V dlhodobom horizonte (rok 2030) už model predpovedá nereálne vysoký nárast, takže tieto čísla nevnímame ako skutočnú predpoveď, ale skôr ako ukážku toho, ako rýchlo vie populácia narásť, keď necháme v modeli pôsobiť rastovú mieru bez obmedzenia.

Krajinám môžeme pripísať tieto trendy:

Slovensko, Česko, Rakúsko, Maďarsko a Poľsko – krátkodobo stabilné, bez veľkých zmien.

Ukrajina – krátkodobo skôr pokles, čo zodpovedá realite.

Dlhodobé výsledky – sú enormné vo všetkých krajinách, čo znamená, že exponenciálny model nie je vhodný na dlhé časové obdobie.

X <- model.matrix(model_centered)[, -1]
XtX <- t(X) %*% X
eig <- eigen(XtX)

condition_number <- sqrt(max(eig$values) / min(eig$values))
condition_number
[1] 1.09998
udaje$GrowthRate_c <- scale(udaje$Growth.Rate, center=TRUE, scale=TRUE)
model_centered <- lm(log_pop ~ log_pop15 + GrowthRate_c + Continent, data = udaje)
summary(model_centered)

Call:
lm(formula = log_pop ~ log_pop15 + GrowthRate_c + Continent, 
    data = udaje)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.228477 -0.018980  0.001669  0.020626  0.181035 

Coefficients:
                        Estimate Std. Error t value Pr(>|t|)    
(Intercept)             0.095167   0.021598   4.406 1.62e-05 ***
log_pop15               0.999371   0.001313 761.114  < 2e-16 ***
GrowthRate_c            0.031415   0.003515   8.937  < 2e-16 ***
ContinentAsia          -0.021732   0.009384  -2.316 0.021465 *  
ContinentEurope        -0.057497   0.010139  -5.671 4.32e-08 ***
ContinentNorth America -0.041139   0.010860  -3.788 0.000195 ***
ContinentOceania       -0.048714   0.012870  -3.785 0.000197 ***
ContinentSouth America -0.024168   0.013950  -1.732 0.084559 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.04529 on 226 degrees of freedom
Multiple R-squared:  0.9997,    Adjusted R-squared:  0.9997 
F-statistic: 1.25e+05 on 7 and 226 DF,  p-value: < 2.2e-16
library(MASS)

# Matrix-based analysis for predictive variables
X <- as.matrix(udaje[, c("log_pop15", "Growth.Rate")])  # historická populácia a rast
y <- udaje$log_pop  # log-populácia 2020

lambda <- 0.01  # regularizačný parameter pre Ridge (môžeš upraviť)
A <- t(X) %*% X
AInv <- solve(A)
Alam <- t(X) %*% X + lambda * diag(ncol(X))
AlamInv <- solve(Alam)

cat("lambda =", lambda, "\n")
lambda = 0.01 
cat("Matrix A:\n"); print(A)
Matrix A:
            log_pop15 Growth.Rate
log_pop15   53207.913   3504.1094
Growth.Rate  3504.109    238.5454
cat("Matrix Alam (regularized):\n"); print(Alam)
Matrix Alam (regularized):
            log_pop15 Growth.Rate
log_pop15   53207.923   3504.1094
Growth.Rate  3504.109    238.5554
cat("Inverse of A:\n"); print(AInv)
Inverse of A:
                log_pop15 Growth.Rate
log_pop15    0.0005765852 -0.00846974
Growth.Rate -0.0084697403  0.12860820
cat("Inverse of Alam:\n"); print(AlamInv)
Inverse of Alam:
                log_pop15  Growth.Rate
log_pop15    0.0005758655 -0.008458813
Growth.Rate -0.0084588128  0.128442299
cat("Eigenvalues of A:\n"); print(eigen(A)$values)
Eigenvalues of A:
[1] 53438.716800     7.741971
cat("Eigenvalues of Alam:\n"); print(eigen(Alam)$values)
Eigenvalues of Alam:
[1] 53438.726800     7.751971

Celkové zistenie:

Historická populácia je najsilnejším prediktorom budúcej populácie.

Growth.Rate umožňuje predikciu rastu do budúcnosti (2025, 2030).

Kontinent zachytáva regionálne rozdiely.

Model umožňuje praktickú predikciu budúcej populácie pre všetky krajiny a jej porovnanie medzi regiónmi.

Na základe našej analýzy môžeme povedať, že model funguje dobre na krátkodobú projekciu, ale pri dlhšom časovom horizonte dochádza k výraznému nadhodnocovaniu populácie. Preto tieto výsledky skôr ukazujú, ako veľmi dokáže model reagovať na rastovú mieru, než to, ako bude populácia v skutočnosti vyzerať.

LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSAtIFdvcmxkIHBvcHVsYXRpb24iCmF1dGhvcjogIkJhcmJvcmEgS3VjaMOhcmlrb3bDoSAgPGJyPiIKZGF0ZTogIk5vdmVtYmVyIDIwMjUiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRoZW1lOiB1bml0ZWQKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGNzczogY3VzdG9tLmNzcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQplZGl0b3Jfb3B0aW9uczoKICBtYXJrZG93bjoKICAgIHdyYXA6IDcyCi0tLQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UKKQpgYGAKCmBgYHtyfQojIExvYWQgZGF0YQp1ZGFqZSA8LSByZWFkLmNzdigid29ybGRfcG9wdWxhdGlvbi5jc3YiLCBkZWM9Ii4iLCBzZXA9IiwiLCBoZWFkZXIgPSBUUlVFKQoKIyBTZWxlY3QgcmVsZXZhbnQgdmFyaWFibGVzIGZvciBwcmVkaWN0aW9uCnVkYWplX3ByZWQgPC0gdWRhamVbLCBjKCJDb3VudHJ5LlRlcnJpdG9yeSIsIlgyMDIwLlBvcHVsYXRpb24iLCAiWDIwMTUuUG9wdWxhdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICJHcm93dGguUmF0ZSIsICJDb250aW5lbnQiKV0KCiMgTWVkaWFuIGltcHV0YXRpb24gZm9yIG51bWVyaWMgdmFyaWFibGVzCm51bWVyaWNfY29scyA8LSBjKCJYMjAyMC5Qb3B1bGF0aW9uIiwgIlgyMDE1LlBvcHVsYXRpb24iLCAiR3Jvd3RoLlJhdGUiKQpjb2x1bW5fbWVkaWFucyA8LSBzYXBwbHkodWRhamVfcHJlZFssIG51bWVyaWNfY29sc10sIG1lZGlhbiwgbmEucm0gPSBUUlVFKQpmb3IgKGNvbCBpbiBudW1lcmljX2NvbHMpIHsKICB1ZGFqZV9wcmVkW1tjb2xdXVtpcy5uYSh1ZGFqZV9wcmVkW1tjb2xdXSldIDwtIGNvbHVtbl9tZWRpYW5zW2NvbF0KfQoKIyBMb2ctdHJhbnNmb3JtIGZvciBtb2RlbGluZwp1ZGFqZV9wcmVkJGxvZ19wb3AgPC0gbG9nKHVkYWplX3ByZWQkWDIwMjAuUG9wdWxhdGlvbikKdWRhamVfcHJlZCRsb2dfcG9wMTUgPC0gbG9nKHVkYWplX3ByZWQkWDIwMTUuUG9wdWxhdGlvbikKCiMgRGF0YXNldCByZWFkeSBmb3IgcHJlZGljdGl2ZSBtb2RlbGluZwp1ZGFqZSA8LSB1ZGFqZV9wcmVkCmBgYAoqKsSMbyBza8O6bWFtZToqKgoKLSBQcmlwcmF2dWplbWUgZMOhdGEgbmEgcHJlZGlrY2l1IGJ1ZMO6Y2VqIHBvcHVsw6FjaWUuCgotIENow71iYWrDumNlIGhvZG5vdHkgZG9wxLrFiGFtZSBtZWRpw6Fub20sIGFieSBtb2RlbCBmdW5nb3ZhbCBzcHLDoXZuZS4KCi0gTG9nLXRyYW5zZm9ybcOhY2lhIHBvcHVsw6FjaWUgc3RhYmlsaXp1amUgZXh0csOpbW5lIHJvemRpZWx5IG1lZHppIG1hbMO9bWkgYSB2ZcS+a8O9bWkga3JhamluYW1pLgoKYGBge3J9CiMgUHJlIGJ1ZMO6Y3UgcG9wdWzDoWNpdSBuw6FzIG5hanZpYWMgemF1asOtbWEgaGlzdG9yaWNrw6EgcG9wdWzDoWNpYSBhIHJhc3QKeHZhcnMgPC0gdWRhamVbLCBjKCJYMjAxNS5Qb3B1bGF0aW9uIiwgIkdyb3d0aC5SYXRlIildCnJvdW5kKGNvcih4dmFycyksIDMpCmBgYAoqVGVyYXogemlzxaV1amVtZSwgYWtvIHPDuiBtZWR6aSBzZWJvdSBwcmVwb2plbsOpIGhpc3Rvcmlja8OhIHBvcHVsw6FjaWEgYSByb8SNbsO9IHJhc3QuIFbDpMSNxaFpbm91IGhpc3Rvcmlja8OhIHBvcHVsw6FjaWEgYSBHcm93dGguUmF0ZSBuaWUgc8O6IHNpbG5lIGtvcmVsb3ZhbsOpIOKGkiBvYmUgbcO0xb51IGJ5xaUgcG91xb5pdMOpIGFrbyBwcmVkaWt0b3J5IHByZSBidWTDumN1IHBvcHVsw6FjaXUuKgoKYGBge3J9CnBhaXJzKHh2YXJzLAogICAgICBtYWluID0gIlNjYXR0ZXJwbG90b3bDoSBtYXRpY2Eg4oCTIGhpc3Rvcmlja8OhIHBvcHVsw6FjaWEgYSBHcm93dGggUmF0ZSIpCmBgYAoqVml6dWFsaXp1amVtZSB2esWlYWggbWVkemkgaGlzdG9yaWNrb3UgcG9wdWzDoWNpb3UgYSByYXN0b20gYSBwb3pyaWVtZSBzYSwgxI1pIGV4aXN0dWrDuiBleHRyw6ltbmUgaG9kbm90eSBhbGVibyBuZXR5cGlja8OpIGtyYWppbnkuKgoKQWtvIG3DtMW+bWUgdmlkaWXFpSwgdsOkxI3FoWluYSBrcmFqw61uIHNhIG5hY2jDoWR6YSB2IHN0YWJpbG5vbSBww6FzbWUgcmFzdHUsIG5pZWt0b3LDqSBtYWrDuiBleHRyw6ltbmUgaG9kbm90eSwga3RvcsOpIG3DtMW+dSBvdnBseXZuacWlIHByZWRpa2NpdS4KCmBgYHtyfQpsaWJyYXJ5KGNhcikKdmlmKG1vZGVsKQpgYGAKCmBgYHtyfQpYIDwtIG1vZGVsLm1hdHJpeChtb2RlbClbLCAtMV0KWHRYIDwtIHQoWCkgJSolIFgKZWlnIDwtIGVpZ2VuKFh0WCkKCmNvbmRpdGlvbl9udW1iZXIgPC0gc3FydChtYXgoZWlnJHZhbHVlcykgLyBtaW4oZWlnJHZhbHVlcykpCmNvbmRpdGlvbl9udW1iZXIKYGBgCgoqQ2hjZW1lIHppc3RpxaUsIGFrbyBoaXN0b3JpY2vDoSBwb3B1bMOhY2lhLCByYXN0IGEga29udGluZW50IHZwbMO9dmFqw7ogbmEgcG9wdWzDoWNpdSAyMDIwLiBNb2RlbCBuw6FtIHrDoXJvdmXFiCBzbMO6xb5pIG5hIG92ZXJlbmllIHByZWRpa8SNbmVqIHNjaG9wbm9zdGkuKgpgYGB7cn0KIyBNb2RlbCBwcmVkaWtjaWUgcG9wdWzDoWNpZSAyMDIwCm1vZGVsX3ByZWQgPC0gbG0obG9nX3BvcCB+IGxvZ19wb3AxNSArIEdyb3d0aC5SYXRlICsgQ29udGluZW50LCBkYXRhID0gdWRhamUpCnN1bW1hcnkobW9kZWxfcHJlZCkKYGBgCkhpc3Rvcmlja8OhIHBvcHVsw6FjaWEgamUgbmFqc2lsbmVqxaHDrSBwcmVkaWt0b3IuCgpHcm93dGguUmF0ZSBtw6EgcG96aXTDrXZueSB2cGx5diDigJMga3JhamlueSBzIHZ5xaHFocOtbSByYXN0b20gYnVkw7ogdsOkxI3FoWllLgoKS29udGluZW50IHphY2h5dMOhdmEgcmVnaW9uw6FsbmUgcm96ZGllbHkgKG5hcHIuIEV1csOzcGEgbcOhIHByaWVtZXJuZSBtZW7FoWl1IHBvcHVsw6FjaXUgcHJpIHJvdm5ha2VqIGhpc3Rvcmlja2VqIHZlxL5rb3N0aSkuCgpgYGB7cn0KIyBTcMOkdG7DoSB0cmFuc2Zvcm3DoWNpYSBuYSBwb8SNZXQgb2J5dmF0ZcS+b3YKdWRhamUkcHJlZF9wb3AyMDIwIDwtIGV4cChwcmVkaWN0KG1vZGVsX3ByZWQsIG5ld2RhdGEgPSB1ZGFqZSkpCgojIFByZWRpa2NpYSBwb2TEvmEgR3Jvd3RoLlJhdGUKdWRhamUkcHJlZF9wb3AyMDI1IDwtIHVkYWplJFgyMDIwLlBvcHVsYXRpb24gKiAoMSArIHVkYWplJEdyb3d0aC5SYXRlKV41CnVkYWplJHByZWRfcG9wMjAzMCA8LSB1ZGFqZSRYMjAyMC5Qb3B1bGF0aW9uICogKDEgKyB1ZGFqZSRHcm93dGguUmF0ZSleMTAKCgojIC0tLSBWw71iZXIga29ua3LDqXRueWNoIGtyYWrDrW4gLS0tCnZ5YnJhbmVfa3JhamlueSA8LSBjKCJTbG92YWtpYSIsIAogICAgICAgICAgICAgICAgICAgICAiQ3plY2ggUmVwdWJsaWMiLCAKICAgICAgICAgICAgICAgICAgICAgIkh1bmdhcnkiLCAKICAgICAgICAgICAgICAgICAgICAgIkF1c3RyaWEiLCAKICAgICAgICAgICAgICAgICAgICAgIlVrcmFpbmUiLCAKICAgICAgICAgICAgICAgICAgICAgIlBvbGFuZCIpCgojIEZpbHRyb3ZhbmllIHBvZMS+YSBuw6F6dnUga3JhamlueQp1ZGFqZV92eWJyYW5lIDwtIHVkYWplW3VkYWplJENvdW50cnkuVGVycml0b3J5ICVpbiUgdnlicmFuZV9rcmFqaW55LCBdCgoKIyAtLS0gWm9icmF6ZW5pZSB2w71zbGVka3UgLS0tCnVkYWplX3Z5YnJhbmVbLCBjKCJDb3VudHJ5LlRlcnJpdG9yeSIsIAogICAgICAgICAgICAgICAgICAiWDIwMjAuUG9wdWxhdGlvbiIsIAogICAgICAgICAgICAgICAgICAicHJlZF9wb3AyMDIwIiwgCiAgICAgICAgICAgICAgICAgICJwcmVkX3BvcDIwMjUiLCAKICAgICAgICAgICAgICAgICAgInByZWRfcG9wMjAzMCIpXQpgYGAKKlByZWRpa3VqZW1lIHBvcHVsw6FjaXUgZG8gYnVkw7pjbm9zdGkgKDIwMjUgYSAyMDMwKSBwb21vY291IEdyb3d0aC5SYXRlLiBVbW/FvsWIdWplIG7DoW0gb2RoYWRuw7rFpSByYXN0IGEgcG9yb3ZuYcWlIGhvIG1lZHppIGtyYWppbmFtaS4qCgpLZcSPIHNhIHBvenJpZW1lIG5hIG5hxaFlIHbDvXNsZWRreSwgdmlkw61tZSwgxb5lIHbDvWNob2Rpc2tvdsOpIGhvZG5vdHkgcG9wdWzDoWNpZSB2IHJva3UgMjAyMCB6b2Rwb3ZlZGFqw7ogcmXDoWxueW0gcG/EjXRvbSBvYnl2YXRlxL5vdiB2IGplZG5vdGxpdsO9Y2gga3Jhamluw6FjaC4gTW9kZWwgdsWhYWsgcHJpIGRsaG9kb2JlaiBwcmVkaWtjaWkgKG5ham3DpCBzbWVyb20gayByb2t1IDIwMzApIGdlbmVydWplIGV4dHLDqW1uZSB2eXNva8OpIMSNw61zbGEuIFRvdG8gc2EgZGVqZSBwcmV0bywgxb5lIHNtZSBwb3XFvmlsaSBqZWRub2R1Y2jDvSB2w71wb8SNZXQgemFsb8W+ZW7DvSBuYSBleHBvbmVuY2nDoWxub20gcmFzdGUsIGt0b3LDvSBwcmkgZGxoxaFvbSBvYmRvYsOtIHZlxL5taSBwcmVow6HFiGEgdsO9c2xlZGt5LgoKViBrcsOhdGtvZG9ib20gaG9yaXpvbnRlIChkbyByb2t1IDIwMjUpIHPDuiBwcmVkcG92ZWRlIGXFoXRlIHJlbGF0w612bmUgcG9kb2Juw6kgcmVhbGl0ZSDigJMgcG9wdWzDoWNpYSBzYSBtZW7DrSBsZW4gbWllcm5lLgpWIGRsaG9kb2JvbSBob3Jpem9udGUgKHJvayAyMDMwKSB1xb4gbW9kZWwgcHJlZHBvdmVkw6EgbmVyZcOhbG5lIHZ5c29rw70gbsOhcmFzdCwgdGFrxb5lIHRpZXRvIMSNw61zbGEgbmV2bsOtbWFtZSBha28gc2t1dG/EjW7DuiBwcmVkcG92ZcSPLCBhbGUgc2vDtHIgYWtvIHVrw6HFvmt1IHRvaG8sIGFrbyByw71jaGxvIHZpZSBwb3B1bMOhY2lhIG5hcsOhc8WlLCBrZcSPIG5lY2jDoW1lIHYgbW9kZWxpIHDDtHNvYmnFpSByYXN0b3bDuiBtaWVydSBiZXogb2JtZWR6ZW5pYS4KCioqS3Jhamluw6FtIG3DtMW+ZW1lIHByaXDDrXNhxaUgdGlldG8gdHJlbmR5OioqCgoqU2xvdmVuc2tvLCDEjGVza28sIFJha8O6c2tvLCBNYcSPYXJza28gYSBQb8S+c2tvKiDigJMga3LDoXRrb2RvYm8gc3RhYmlsbsOpLCBiZXogdmXEvmvDvWNoIHptaWVuLgoKKlVrcmFqaW5hKiDigJMga3LDoXRrb2RvYm8gc2vDtHIgcG9rbGVzLCDEjW8gem9kcG92ZWTDoSByZWFsaXRlLgoKKkRsaG9kb2LDqSB2w71zbGVka3kqIOKAkyBzw7ogZW5vcm1uw6kgdm8gdsWhZXRrw71jaCBrcmFqaW7DoWNoLCDEjW8gem5hbWVuw6EsIMW+ZSBleHBvbmVuY2nDoWxueSBtb2RlbCBuaWUgamUgdmhvZG7DvSBuYSBkbGjDqSDEjWFzb3bDqSBvYmRvYmllLgoKCmBgYHtyfQpYIDwtIG1vZGVsLm1hdHJpeChtb2RlbF9jZW50ZXJlZClbLCAtMV0KWHRYIDwtIHQoWCkgJSolIFgKZWlnIDwtIGVpZ2VuKFh0WCkKCmNvbmRpdGlvbl9udW1iZXIgPC0gc3FydChtYXgoZWlnJHZhbHVlcykgLyBtaW4oZWlnJHZhbHVlcykpCmNvbmRpdGlvbl9udW1iZXIKYGBgCmBgYHtyfQp1ZGFqZSRHcm93dGhSYXRlX2MgPC0gc2NhbGUodWRhamUkR3Jvd3RoLlJhdGUsIGNlbnRlcj1UUlVFLCBzY2FsZT1UUlVFKQptb2RlbF9jZW50ZXJlZCA8LSBsbShsb2dfcG9wIH4gbG9nX3BvcDE1ICsgR3Jvd3RoUmF0ZV9jICsgQ29udGluZW50LCBkYXRhID0gdWRhamUpCnN1bW1hcnkobW9kZWxfY2VudGVyZWQpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KE1BU1MpCgojIE1hdHJpeC1iYXNlZCBhbmFseXNpcyBmb3IgcHJlZGljdGl2ZSB2YXJpYWJsZXMKWCA8LSBhcy5tYXRyaXgodWRhamVbLCBjKCJsb2dfcG9wMTUiLCAiR3Jvd3RoLlJhdGUiKV0pICAjIGhpc3Rvcmlja8OhIHBvcHVsw6FjaWEgYSByYXN0CnkgPC0gdWRhamUkbG9nX3BvcCAgIyBsb2ctcG9wdWzDoWNpYSAyMDIwCgpsYW1iZGEgPC0gMC4wMSAgCkEgPC0gdChYKSAlKiUgWApBSW52IDwtIHNvbHZlKEEpCkFsYW0gPC0gdChYKSAlKiUgWCArIGxhbWJkYSAqIGRpYWcobmNvbChYKSkKQWxhbUludiA8LSBzb2x2ZShBbGFtKQoKY2F0KCJsYW1iZGEgPSIsIGxhbWJkYSwgIlxuIikKY2F0KCJNYXRyaXggQTpcbiIpOyBwcmludChBKQpjYXQoIk1hdHJpeCBBbGFtIChyZWd1bGFyaXplZCk6XG4iKTsgcHJpbnQoQWxhbSkKY2F0KCJJbnZlcnNlIG9mIEE6XG4iKTsgcHJpbnQoQUludikKY2F0KCJJbnZlcnNlIG9mIEFsYW06XG4iKTsgcHJpbnQoQWxhbUludikKY2F0KCJFaWdlbnZhbHVlcyBvZiBBOlxuIik7IHByaW50KGVpZ2VuKEEpJHZhbHVlcykKY2F0KCJFaWdlbnZhbHVlcyBvZiBBbGFtOlxuIik7IHByaW50KGVpZ2VuKEFsYW0pJHZhbHVlcykKYGBgCiMjICoqKkNlbGtvdsOpIHppc3RlbmllOioqKgoKSGlzdG9yaWNrw6EgcG9wdWzDoWNpYSBqZSBuYWpzaWxuZWrFocOtbSBwcmVkaWt0b3JvbSBidWTDumNlaiBwb3B1bMOhY2llLgoKR3Jvd3RoLlJhdGUgdW1vxb7FiHVqZSBwcmVkaWtjaXUgcmFzdHUgZG8gYnVkw7pjbm9zdGkgKDIwMjUsIDIwMzApLgoKS29udGluZW50IHphY2h5dMOhdmEgcmVnaW9uw6FsbmUgcm96ZGllbHkuCgpNb2RlbCB1bW/FvsWIdWplIHByYWt0aWNrw7ogcHJlZGlrY2l1IGJ1ZMO6Y2VqIHBvcHVsw6FjaWUgcHJlIHbFoWV0a3kga3JhamlueSBhIGplaiBwb3Jvdm5hbmllIG1lZHppIHJlZ2nDs25taS4KCipOYSB6w6FrbGFkZSBuYcWhZWogYW5hbMO9enkgbcO0xb5lbWUgcG92ZWRhxaUsIMW+ZSBtb2RlbCBmdW5ndWplIGRvYnJlIG5hIGtyw6F0a29kb2LDuiBwcm9qZWtjaXUsIGFsZSBwcmkgZGxoxaFvbSDEjWFzb3ZvbSBob3Jpem9udGUgZG9jaMOhZHphIGsgdsO9cmF6bsOpbXUgbmFkaG9kbm9jb3Zhbml1IHBvcHVsw6FjaWUuIFByZXRvIHRpZXRvIHbDvXNsZWRreSBza8O0ciB1a2F6dWrDuiwgYWtvIHZlxL5taSBkb2vDocW+ZSBtb2RlbCByZWFnb3ZhxaUgbmEgcmFzdG92w7ogbWllcnUsIG5lxb4gdG8sIGFrbyBidWRlIHBvcHVsw6FjaWEgdiBza3V0b8SNbm9zdGkgdnl6ZXJhxaUuKgoKCgoKCgoK