S využitím databázy WHO Life Expactancy Data database.

Pri ďalšej práci budeme používať knižnice

library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)
rm(list=ls())

V hlavnom menu som Session nastavil na Source File Location. Môžeme to urobiť aj interaktívnym spôsobom - napísať dole do Console (alebo to zahrnúť priamo do skriptu) ako

setwd(“/Cloud/project/tyzdne/tyzden5”)

Organizácia priečinkov a podpriečinkov sa však môže líšiť v závislosti od projektu, preto som ich nezaradil do Chunk-u.

Údaje o očakávanej dĺžke života sú usporiadané v súbore csv, stĺpce sú oddelené znakom “,” a používajú desatinnú čiarku. V pracovnom priečinku som vytvoril podpriečinok s názvom udaje, aby som oddelil údaje od zvyšku projektu. Môj priečinok sa tiež nazýva udaje.

Nie všetky údaje budú použité, preto som vybral len niektoré stĺpce pre neskoršie použitie.

Úvod do problému, stanovenie hypotéz

Rozhodol som sa modelovať strednú dĺžku života Life.expectancy v závislosti od troch vysvetľujúcich premenných a to BMI, HDP na obyvateľa GDP a stredný počet rokov štúdia Schooling.

Naša pracovná hypotéza hovorí o štatisticky významnom vplyve všetkých troch vysvetľujúcich premenných, pričom u premenných GDP a Schooling by malo ísť o pozitívny vplyv (očakávame kladné znamienko odhadovaného regresného koeficienta) a v prípade BMI by malo ísť of negatívny vplyv (so záporným znamienkom)

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

Keďže niektoré údaje chýbajú, doplnil som ich mediánovými hodnotami premennej, ktorú zvažujem. lm

udaje <- read.csv("udaje/Life_Expectancy_Data.csv",dec=".",sep=",",header = TRUE)
# select just the record from 2015
udaje.2015 <- udaje[udaje$Year==2015,c("Life.expectancy","BMI","GDP","Schooling")]

# data imputation

# Compute column medians
#column_medians <- sapply(udaje.2015, median, na.rm = TRUE)

# Impute missing values with column medians
# Compute column medians
column_medians <- sapply(udaje.2015, median, na.rm = TRUE)

# Impute missing values with column medians
udaje_imputed <- udaje.2015
for (col in names(udaje.2015)) {
  udaje_imputed[[col]][is.na(udaje_imputed[[col]])] <- column_medians[col]
}

udaje.2015 <- udaje_imputed

Teraz chceme vidieť tvar údajov (či nie sú v nich nejaké nezrovnalosti – napríklad hodnoty 0).

# Suppose udaje.2015 is your data frame

# Determine number of plots
num_plots <- length(names(udaje.2015))

# Set the layout: 2 rows × 2 columns
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1))  # Adjust margins (optional)

# Loop through columns and plot each boxplot
for (col in names(udaje.2015)) {
  boxplot(udaje.2015[[col]], main = "lmcol", xlab = "Value", col = "lightblue")
}

# Add a global caption / title
mtext("Boxploty jednotlivých premenných", outer = TRUE, cex = 1.4, font = 2)

# Reset layout to default (1 plot per figure)
par(mfrow = c(1, 1))

Lineárna regresia

Model odhadujeme príkazom lm()

model <- lm(Life.expectancy ~ +1 + BMI + GDP + Schooling,data=udaje.2015)

Objekt triedy lm() nám poskytuje niekoľko výsledkov:

  1. Vector odhadnutých koeficientov model$coefficients
  2. Vektor rezíduí model$ residuals
  3. Vektor vyrovnaných hodnôt vysvetľovanej veličiny model$fitted.values
  4. Maticu X model$x
#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 = Life.expectancy ~ +1 + BMI + GDP + Schooling, data = udaje.2015)

Residuals:
     Min       1Q   Median       3Q      Max 
-17.6471  -2.4024   0.4563   3.2355  12.8591 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 4.419e+01  1.839e+00  24.033   <2e-16 ***
BMI         4.948e-02  2.144e-02   2.308   0.0222 *  
GDP         6.972e-05  3.845e-05   1.813   0.0715 .  
Schooling   1.921e+00  1.645e-01  11.676   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.033 on 179 degrees of freedom
Multiple R-squared:  0.6224,    Adjusted R-squared:  0.6161 
F-statistic: 98.36 on 3 and 179 DF,  p-value: < 2.2e-16

Súhrn odhadovaného modelu nám poskytuje súbor odhadovaných regresných koeficientov, ktorých znamienka budú rozoberané neskôr. Ak hovoríme o vlastnostiach modelu ako celku, pozrime sa najskôr na nasledujúce obrázky. Na základe Q-Q grafu získavame dojem o možných problémoch porušenia normality rezíduí.

# 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))

Residuals vs. fitted

Interpretácia vášho konkrétneho grafu

  • Centrovanie okolo nuly

  • Reziduály kolíšu približne okolo 0 – to je dobré.

  • Naznačuje to, že model nemá výrazné skreslenie v predikciách.

  • Červená hladká čiara je mierne zakrivená (vpravo sa ohýba nadol a uprostred nahor), to naznačuje možnú miernu nelinearitu – modelu môže chýbať nelineárny tvar nejakej premennej.

  • Rozptyl rezíduí - Vertikálny rozptyl (variancia rezíduí) sa javí ako približne konštantný v rámci prispôsobených hodnôt čo je dobrý dôkaz homoscedasticity.

  • Ak by sa rezíduá rozprestierali (tvorili kónus), naznačovalo by to heteroskedasticitu.

  • Odľahlé hodnoty - Niekoľko bodov (napr. v blízkosti −20) leží ďaleko od ostatných – ide o potenciálne odľahlé hodnoty alebo vplyvné pozorovania.

Môžeme ich preskúmať pomocou outlierTest(model) (z balíka car).

Q-Q plot

Čo ukazuje

  • Os X: Teoretické kvantily – čo by sme očakávali, ak by rezíduá boli dokonale normálne rozložené.
  • Os Y: Štandardizované rezíduá – skutočné kvantily z vašej vzorky.
  • 45° prerušovaná čiara: Ideálny prípad – ak sú rezíduá normálne rozložené, body by mali ležať tesne pozdĺž tejto čiary.

Interpretácia vášho konkrétneho grafu

Celkový tvar

Väčšina bodov leží blízko priamky — to naznačuje, že rezíduá sú približne normálne.

To je dobré: predpoklad normality sa zdá byť vo veľkej miere splnený.

Krajné hodnoty (extrémy)

Body na oboch koncoch (vľavo dole a vpravo hore) sa mierne odchyľujú od priamky.

To naznačuje miernu nenormálnosť v koncoch – možno niekoľko odľahlých hodnôt alebo ťažšie konce, ako je normálne (trochu špicatosť).

Stredná oblasť

Stredná časť grafu (−1 až +1 kvantily) sa veľmi dobre zhoduje – čo znamená, že väčšina rezíduí pekne zapadá do normálneho rozdelenia.

Zároveň vykonávame následné testy, v ktorých zamietame hypotézu o normálnom rozložení modelových chýb, ako aj prítomnosť extrémnych hodnôt.

Scale location plot

Čo to znázorňuje

Os X: Vyrovnan0 hodnoty Os Y: Druhá odmocnina absolútnych štandardizovaných rezíduí Červená čiara: LOESS (vyhladený) trend cez body

Interpretácia nášho konkrétneho grafu

Horizontálne rozptýlenie

  • Body sú rovnomerne rozptýlené po osi x bez vytvorenia lievika alebo krivky. To naznačuje približne konštantnú varianciu – rezíduá sú homoscedastické.
  • Červená hladká čiara je takmer rovná – ďalší znak, že pri zvyšovaní vyrovnaných hodnôt nedochádza k žiadnej systematickej zmene variancie.
  • Odľahlé hodnoty - niekoľko bodov je mierne nad 1,5, ale žiadny z nich nie je extrémny – takže nedochádza k žiadnym závažným anomáliám variancie.

residuals vs leverage

Čo znázorňuje graf

Os X: Pákový efekt — meria, ako ďaleko je prediktorový vektor bodu od stredu všetkých 𝑥 x.

Os Y: Štandardizované rezíduá — ako ďaleko je pozorovaná hodnota od vyrovnanej hodnoty v jednotkách štandardnej odchýlky.

Bodkované krivky: Kontúry Cookovej vzdialenosti, ktoré udávajú, do akej miery pozorovanie ovplyvňuje regresnú priamku.

Červená čiara: Hladká LOESS čiara prechádzajúca rezíduami.lm

Interpretácia vášho konkrétneho grafu

Rozloženie vplyvu

Väčšina pozorovaní má nízky vplyv (pod 0,05) — typické pre veľké vzorky alebo dobre vyvážené údaje.

Jeden alebo dva body (napr. okolo 0,2) vynikajú – ide o pozorovania s vysokou pákou, čo znamená, že ich hodnoty sú ďaleko od väčšiny údajov.

Veľkosť rezíduí

Štandardizované rezíduá väčšinou medzi −2 a +2 – to je dobré (žiadne závažné výnimky v 𝑦 y).

Pozorovanie označené číslom 113 má zdanlivo stredný vplyv a relatívne veľkú rezíduálnu hodnotu – potenciálne vplyvný prípad.

Kontúry Cookovej vzdialenosti

Žiaden z bodov jasne neprekračuje vonkajšie línie Cookovej vzdialenosti (≈0,5 alebo 1,0).

Preto sa nezdá, že by niektoré pozorovanie neprimerane ovplyvňovalo regresné koeficienty.

{r}lm # normality tests residuals <- residuals(model) jb_test <- jarque.bera.test(residuals) jb_test # outlier test (see p-value for Bonferroni correction) outlier_test <- outlierTest(model) outlier_test

Keďže sa nepreukázala normalita rezíduí, pokúsme sa eliminovať odľahlé hodnoty v prípade GDP - dokážeme to logaritmickou transformáciou tejto premennej a vylúčením BMI, ktoré sa ukázalo ako neinterpretovateľné. Nová regresia bude mať tvar

model2 <- lm(Life.expectancy ~ +1 + I(log(GDP)) + Schooling,data=udaje.2015)
summary(model2)

Call:
lm(formula = Life.expectancy ~ +1 + I(log(GDP)) + Schooling, 
    data = udaje.2015)

Residuals:
     Min       1Q   Median       3Q      Max 
-18.7351  -2.4761   0.5209   3.4551  10.6277 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  40.0434     2.1992  18.208   <2e-16 ***
I(log(GDP))   0.6338     0.3002   2.112   0.0361 *  
Schooling     2.0561     0.1557  13.203   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.09 on 180 degrees of freedom
Multiple R-squared:  0.6118,    Adjusted R-squared:  0.6075 
F-statistic: 141.8 on 2 and 180 DF,  p-value: < 2.2e-16
# Nastaviť rozloženie 2 x 2
par(mfrow = c(2, 2))

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

# (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))

# normality tests
residuals <- residuals(model)
jb_test <- jarque.bera.test(residuals)
jb_test

    Jarque Bera Test

data:  residuals
X-squared = 21.391, df = 2, p-value = 2.265e-05
# outlier test (see p-value for Bonferroni correction)
outlier_test <- outlierTest(model)
outlier_test
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:

##Conclusion##

Premenné GDP, a Schooling predlžujú štatisicky významne strednú dĺžku života. Na druhej strane BMI nám dávalo neinterpretovateľné výsledky. Rezíduá nevykazujú normálne rozdelenie, keďže však máme veľké množstvo pozorovaní, aj naďalej budeme pracovať s týmito údajmi. V modeli sa nepreukazujú žiadne významné nelinearity.

LS0tCnRpdGxlOiAiRWNvbm9tZXRyaWNzIGluIFIgLSBjdmnEjWVuaWUgNSIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogVi4gR2F6ZGEKLS0tCgpTIHZ5dcW+aXTDrW0gZGF0YWLDoXp5IFtXSE8gTGlmZSBFeHBhY3RhbmN5IERhdGFdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMva3VtYXJhamFyc2hpL2xpZmUtZXhwZWN0YW5jeS13aG8pIGRhdGFiYXNlLgoKUHJpIMSPYWzFoWVqIHByw6FjaSBidWRlbWUgcG91xb7DrXZhxaUga25pxb5uaWNlCgpgYGB7cn0KbGlicmFyeSh6b28pCmxpYnJhcnkodHNlcmllcykKbGlicmFyeShsbXRlc3QpCmxpYnJhcnkoc2FuZHdpY2gpCmxpYnJhcnkoY2FyKQpybShsaXN0PWxzKCkpCmBgYAoKClYgKmhsYXZub20gbWVudSogc29tICpTZXNzaW9uKiBuYXN0YXZpbCBuYSAqU291cmNlIEZpbGUgTG9jYXRpb24qLiBNw7TFvmVtZSB0byB1cm9iacWlIGFqIGludGVyYWt0w612bnltIHNww7Rzb2JvbSAtIG5hcMOtc2HFpSBkb2xlIGRvIENvbnNvbGUgKGFsZWJvIHRvIHphaHJuw7rFpSBwcmlhbW8gZG8gc2tyaXB0dSkgYWtvIAoKICoqc2V0d2QoIi9DbG91ZC9wcm9qZWN0L3R5emRuZS90eXpkZW41IikqKgoKT3JnYW5pesOhY2lhIHByaWXEjWlua292IGEgcG9kcHJpZcSNaW5rb3Ygc2EgdsWhYWsgbcO0xb5lIGzDrcWhacWlIHYgesOhdmlzbG9zdGkgb2QgcHJvamVrdHUsIHByZXRvIHNvbSBpY2ggbmV6YXJhZGlsIGRvIENodW5rLXUuCgrDmmRhamUgbyBvxI1ha8OhdmFuZWogZMS6xb5rZSDFvml2b3RhIHPDuiB1c3BvcmlhZGFuw6kgdiBzw7pib3JlICpjc3YqLCBzdMS6cGNlIHPDuiBvZGRlbGVuw6kgem5ha29tICIsIiBhIHBvdcW+w612YWrDuiBkZXNhdGlubsO6IMSNaWFya3UuIFYgcHJhY292bm9tIHByaWXEjWlua3Ugc29tIHZ5dHZvcmlsIHBvZHByaWXEjWlub2sgcyBuw6F6dm9tICp1ZGFqZSosIGFieSBzb20gb2RkZWxpbCDDumRhamUgb2QgenZ5xaFrdSBwcm9qZWt0dS4gTcO0aiBwcmllxI1pbm9rIHNhIHRpZcW+IG5hesO9dmEgKnVkYWplKi4gCgpOaWUgdsWhZXRreSDDumRhamUgYnVkw7ogcG91xb5pdMOpLCBwcmV0byBzb20gdnlicmFsIGxlbiBuaWVrdG9yw6kgc3TEunBjZSBwcmUgbmVza29yxaFpZSBwb3XFvml0aWUuCgojIMOadm9kIGRvIHByb2Jsw6ltdSwgc3Rhbm92ZW5pZSBoeXBvdMOpeiAKClJvemhvZG9sIHNvbSBzYSBtb2RlbG92YcWlIHN0cmVkbsO6IGTEusW+a3Ugxb5pdm90YSAqTGlmZS5leHBlY3RhbmN5KiB2IHrDoXZpc2xvc3RpIG9kIHRyb2NoIHZ5c3ZldMS+dWrDumNpY2ggcHJlbWVubsO9Y2ggYSB0byAqQk1JKiwgSERQIG5hIG9ieXZhdGXEvmEgKkdEUCogYSBzdHJlZG7DvSBwb8SNZXQgcm9rb3YgxaF0w7pkaWEgICpTY2hvb2xpbmcqLgoKTmHFoWEgcHJhY292bsOhIGh5cG90w6l6YSBob3ZvcsOtIG8gxaF0YXRpc3RpY2t5IHbDvXpuYW1ub20gdnBseXZlIHbFoWV0a8O9Y2ggdHJvY2ggdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaCwgcHJpxI1vbSB1IHByZW1lbm7DvWNoICpHRFAqIGEgKlNjaG9vbGluZyogYnkgbWFsbyDDrXPFpSBvIHBveml0w612bnkgdnBseXYgKG/EjWFrw6F2YW1lIGtsYWRuw6kgem5hbWllbmtvIG9kaGFkb3ZhbsOpaG8gcmVncmVzbsOpaG8ga29lZmljaWVudGEpIGEgdiBwcsOtcGFkZSBCTUkgYnkgbWFsbyDDrXPFpSBvZiBuZWdhdMOtdm55IHZwbHl2IChzbyB6w6Fwb3Juw71tIHpuYW1pZW5rb20pCgoKCgojIFByw61wcmF2YSBkYXRhYsOhenksIMSNaXN0ZW5pZSBhIMO6cHJhdmEgw7pkYWpvdgoKS2XEj8W+ZSBuaWVrdG9yw6kgw7pkYWplIGNow71iYWrDuiwgZG9wbG5pbCBzb20gaWNoIG1lZGnDoW5vdsO9bWkgaG9kbm90YW1pIHByZW1lbm5laiwga3RvcsO6IHp2YcW+dWplbS4gbG0KCgpgYGB7cn0KdWRhamUgPC0gcmVhZC5jc3YoInVkYWplL0xpZmVfRXhwZWN0YW5jeV9EYXRhLmNzdiIsZGVjPSIuIixzZXA9IiwiLGhlYWRlciA9IFRSVUUpCiMgc2VsZWN0IGp1c3QgdGhlIHJlY29yZCBmcm9tIDIwMTUKdWRhamUuMjAxNSA8LSB1ZGFqZVt1ZGFqZSRZZWFyPT0yMDE1LGMoIkxpZmUuZXhwZWN0YW5jeSIsIkJNSSIsIkdEUCIsIlNjaG9vbGluZyIpXQoKIyBkYXRhIGltcHV0YXRpb24KCiMgQ29tcHV0ZSBjb2x1bW4gbWVkaWFucwojY29sdW1uX21lZGlhbnMgPC0gc2FwcGx5KHVkYWplLjIwMTUsIG1lZGlhbiwgbmEucm0gPSBUUlVFKQoKIyBJbXB1dGUgbWlzc2luZyB2YWx1ZXMgd2l0aCBjb2x1bW4gbWVkaWFucwojIENvbXB1dGUgY29sdW1uIG1lZGlhbnMKY29sdW1uX21lZGlhbnMgPC0gc2FwcGx5KHVkYWplLjIwMTUsIG1lZGlhbiwgbmEucm0gPSBUUlVFKQoKIyBJbXB1dGUgbWlzc2luZyB2YWx1ZXMgd2l0aCBjb2x1bW4gbWVkaWFucwp1ZGFqZV9pbXB1dGVkIDwtIHVkYWplLjIwMTUKZm9yIChjb2wgaW4gbmFtZXModWRhamUuMjAxNSkpIHsKICB1ZGFqZV9pbXB1dGVkW1tjb2xdXVtpcy5uYSh1ZGFqZV9pbXB1dGVkW1tjb2xdXSldIDwtIGNvbHVtbl9tZWRpYW5zW2NvbF0KfQoKdWRhamUuMjAxNSA8LSB1ZGFqZV9pbXB1dGVkCgpgYGAKCgoKVGVyYXogY2hjZW1lIHZpZGllxaUgdHZhciDDumRham92ICjEjWkgbmllIHPDuiB2IG5pY2ggbmVqYWvDqSBuZXpyb3ZuYWxvc3RpIOKAkyBuYXByw61rbGFkIGhvZG5vdHkgMCkuCgpgYGB7cn0KIyBTdXBwb3NlIHVkYWplLjIwMTUgaXMgeW91ciBkYXRhIGZyYW1lCgojIERldGVybWluZSBudW1iZXIgb2YgcGxvdHMKbnVtX3Bsb3RzIDwtIGxlbmd0aChuYW1lcyh1ZGFqZS4yMDE1KSkKCiMgU2V0IHRoZSBsYXlvdXQ6IDIgcm93cyDDlyAyIGNvbHVtbnMKcGFyKG1mcm93ID0gYygyLCAyKSkKcGFyKG1hciA9IGMoNCwgNCwgMiwgMSkpICAjIEFkanVzdCBtYXJnaW5zIChvcHRpb25hbCkKCiMgTG9vcCB0aHJvdWdoIGNvbHVtbnMgYW5kIHBsb3QgZWFjaCBib3hwbG90CmZvciAoY29sIGluIG5hbWVzKHVkYWplLjIwMTUpKSB7CiAgYm94cGxvdCh1ZGFqZS4yMDE1W1tjb2xdXSwgbWFpbiA9ICJsbWNvbCIsIHhsYWIgPSAiVmFsdWUiLCBjb2wgPSAibGlnaHRibHVlIikKfQoKIyBBZGQgYSBnbG9iYWwgY2FwdGlvbiAvIHRpdGxlCm10ZXh0KCJCb3hwbG90eSBqZWRub3RsaXbDvWNoIHByZW1lbm7DvWNoIiwgb3V0ZXIgPSBUUlVFLCBjZXggPSAxLjQsIGZvbnQgPSAyKQoKIyBSZXNldCBsYXlvdXQgdG8gZGVmYXVsdCAoMSBwbG90IHBlciBmaWd1cmUpCnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAoKCgoKIyMgTGluZcOhcm5hIHJlZ3Jlc2lhCgpNb2RlbCBvZGhhZHVqZW1lIHByw61rYXpvbSAqbG0oKSoKCmBgYHtyfQptb2RlbCA8LSBsbShMaWZlLmV4cGVjdGFuY3kgfiArMSArIEJNSSArIEdEUCArIFNjaG9vbGluZyxkYXRhPXVkYWplLjIwMTUpCmBgYAoKT2JqZWt0IHRyaWVkeSAqbG0oKSogbsOhbSBwb3NreXR1amUgbmlla2/EvmtvIHbDvXNsZWRrb3Y6CgoxLiBWZWN0b3Igb2RoYWRudXTDvWNoIGtvZWZpY2llbnRvdiAqbW9kZWwkY29lZmZpY2llbnRzKgoyLiBWZWt0b3IgcmV6w61kdcOtICptb2RlbCQgcmVzaWR1YWxzKgozLiBWZWt0b3Igdnlyb3ZuYW7DvWNoIGhvZG7DtHQgdnlzdmV0xL5vdmFuZWogdmVsacSNaW55ICptb2RlbCRmaXR0ZWQudmFsdWVzKgo0LiBNYXRpY3UgWCAqbW9kZWwkeCoKCmBgYHtyfQojcHJpbnQoIk9kaGFkbnV0w6kga29lZmljaWVudHkgc8O6OiAiKQojICAgICAgcHJpbnQobW9kZWwkY29lZmZpY2llbnRzKQojcHJpbnQoIk9kaGFkbnV0w6kgcmV6w61kdcOhOiAiKQojcHJpbnQobW9kZWwkcmVzaWR1YWxzKQojcHJpbnQoIlZ5cm92bmFuw6kgaG9kbm90eSB2eXN2ZXTEvm92YW5laiBwcmVtZW5uZWogc8O6OiAiKQojcHJpbnQobW9kZWwkZml0dGVkLnZhbHVlcykKI3ByaW50KCJtYXRpY2EgbW9kZWwkeGxldmVsczogIikKI3ByaW50KG1vZGVsLm1hdHJpeChtb2RlbCkpCiNYIDwtIG1vZGVsLm1hdHJpeChtb2RlbCkKI2RpYWcoWCAlKiUgc29sdmUodChYKSAlKiUgWCkgJSolIHQoWCkpCgpzdW1tYXJ5KG1vZGVsKQoKYGBgCgoKClPDumhybiBvZGhhZG92YW7DqWhvIG1vZGVsdSBuw6FtIHBvc2t5dHVqZSBzw7pib3Igb2RoYWRvdmFuw71jaCByZWdyZXNuw71jaCBrb2VmaWNpZW50b3YsIGt0b3LDvWNoIHpuYW1pZW5rYSBidWTDuiByb3pvYmVyYW7DqSBuZXNrw7RyLiBBayBob3ZvcsOtbWUgbyB2bGFzdG5vc3RpYWNoIG1vZGVsdSBha28gY2Vsa3UsIHBvenJpbWUgc2EgbmFqc2vDtHIgbmEgbmFzbGVkdWrDumNlIG9icsOhemt5LiBOYSB6w6FrbGFkZSBRLVEgZ3JhZnUgesOtc2thdmFtZSBkb2plbSBvIG1vxb5uw71jaCBwcm9ibMOpbW9jaCBwb3J1xaFlbmlhIG5vcm1hbGl0eSByZXrDrWR1w60uIAoKYGBge3IgZGlhZ3Bsb3RzLCBmaWcuY2FwPSJEaWFnbm9zdGlja8OpIGdyYWZ5IHJlZ3Jlc27DqWhvIG1vZGVsdSJ9CiMgTmFzdGF2acWlIHJvemxvxb5lbmllIDIgeCAyCnBhcihtZnJvdyA9IGMoMiwgMikpCgojIFZ5a3Jlc2xpxaUgdsWhZXRreSA0IGRpYWdub3N0aWNrw6kgZ3JhZnkgbW9kZWx1CnBsb3QobW9kZWwpCgojIChWb2xpdGXEvm7DqSkgcHJpZGHFpSBzcG9sb8SNbsO9IG5hZHBpcwojbXRleHQoIkRpYWdub3N0aWNrw6kgZ3JhZnkgcmVncmVzbsOpaG8gbW9kZWx1Iiwgb3V0ZXIgPSBUUlVFLCBjZXggPSAxLjIsIGZvbnQgPSAyKQoKIyBSZXNldG92YcWlIGxheW91dApwYXIobWZyb3cgPSBjKDEsIDEpKQpgYGAKCgojIyBSZXNpZHVhbHMgdnMuIGZpdHRlZAoKIyMjIEludGVycHJldMOhY2lhIHbDocWhaG8ga29ua3LDqXRuZWhvIGdyYWZ1CgotIENlbnRyb3ZhbmllIG9rb2xvIG51bHkKLSBSZXppZHXDoWx5IGtvbMOtxaF1IHByaWJsacW+bmUgb2tvbG8gMCDigJMgdG8gamUgZG9icsOpLgotIE5hem5hxI11amUgdG8sIMW+ZSBtb2RlbCBuZW3DoSB2w71yYXpuw6kgc2tyZXNsZW5pZSB2IHByZWRpa2Npw6FjaC4KLSDEjGVydmVuw6EgaGxhZGvDoSDEjWlhcmEgamUgbWllcm5lIHpha3JpdmVuw6EgKHZwcmF2byBzYSBvaMO9YmEgbmFkb2wgYSB1cHJvc3RyZWQgbmFob3IpLCB0byBuYXpuYcSNdWplIG1vxb5uw7ogbWllcm51IG5lbGluZWFyaXR1IOKAkyBtb2RlbHUgbcO0xb5lIGNow71iYcWlIG5lbGluZcOhcm55IHR2YXIgbmVqYWtlaiBwcmVtZW5uZWouCgotIFJvenB0eWwgcmV6w61kdcOtIC0gVmVydGlrw6Fsbnkgcm96cHR5bCAodmFyaWFuY2lhIHJlesOtZHXDrSkgc2EgamF2w60gYWtvIHByaWJsacW+bmUga29uxaF0YW50bsO9IHYgcsOhbWNpIHByaXNww7Rzb2JlbsO9Y2ggaG9kbsO0dCAgxI1vIGplIGRvYnLDvSBkw7RrYXogaG9tb3NjZWRhc3RpY2l0eS4KCi0gQWsgYnkgc2EgcmV6w61kdcOhIHJvenByZXN0aWVyYWxpICh0dm9yaWxpIGvDs251cyksIG5hem5hxI1vdmFsbyBieSB0byBoZXRlcm9za2VkYXN0aWNpdHUuCgotIE9kxL5haGzDqSBob2Rub3R5IC0gTmlla2/EvmtvIGJvZG92IChuYXByLiB2IGJsw616a29zdGkg4oiSMjApIGxlxb7DrSDEj2FsZWtvIG9kIG9zdGF0bsO9Y2gg4oCTIGlkZSBvIHBvdGVuY2nDoWxuZSBvZMS+YWhsw6kgaG9kbm90eSBhbGVibyB2cGx5dm7DqSBwb3pvcm92YW5pYS4KCk3DtMW+ZW1lIGljaCBwcmVza8O6bWHFpSBwb21vY291IG91dGxpZXJUZXN0KG1vZGVsKSAoeiBiYWzDrWthIGNhcikuCgojIyBRLVEgcGxvdAoKIyMjIMSMbyB1a2F6dWplCgoKLSBPcyBYOiBUZW9yZXRpY2vDqSBrdmFudGlseSDigJMgxI1vIGJ5IHNtZSBvxI1ha8OhdmFsaSwgYWsgYnkgcmV6w61kdcOhIGJvbGkgZG9rb25hbGUgbm9ybcOhbG5lIHJvemxvxb5lbsOpLgotIE9zIFk6IMWgdGFuZGFyZGl6b3ZhbsOpIHJlesOtZHXDoSDigJMgc2t1dG/EjW7DqSBrdmFudGlseSB6IHZhxaFlaiB2em9ya3kuCi0gNDXCsCBwcmVydcWhb3ZhbsOhIMSNaWFyYTogSWRlw6FsbnkgcHLDrXBhZCDigJMgYWsgc8O6IHJlesOtZHXDoSBub3Jtw6FsbmUgcm96bG/FvmVuw6ksIGJvZHkgYnkgbWFsaSBsZcW+YcWlIHRlc25lIHBvemTEusW+IHRlanRvIMSNaWFyeS4KCiMjIyBJbnRlcnByZXTDoWNpYSB2w6HFoWhvIGtvbmtyw6l0bmVobyBncmFmdQoKQ2Vsa292w70gdHZhcgoKVsOkxI3FoWluYSBib2RvdiBsZcW+w60gYmzDrXprbyBwcmlhbWt5IOKAlCB0byBuYXpuYcSNdWplLCDFvmUgcmV6w61kdcOhIHPDuiBwcmlibGnFvm5lIG5vcm3DoWxuZS4KClRvIGplIGRvYnLDqTogcHJlZHBva2xhZCBub3JtYWxpdHkgc2EgemTDoSBiecWlIHZvIHZlxL5rZWogbWllcmUgc3BsbmVuw70uCgpLcmFqbsOpIGhvZG5vdHkgKGV4dHLDqW15KQoKQm9keSBuYSBvYm9jaCBrb25jb2NoICh2xL5hdm8gZG9sZSBhIHZwcmF2byBob3JlKSBzYSBtaWVybmUgb2RjaHnEvnVqw7ogb2QgcHJpYW1reS4KClRvIG5hem5hxI11amUgbWllcm51IG5lbm9ybcOhbG5vc8WlIHYga29uY29jaCDigJMgbW/Fvm5vIG5pZWtvxL5rbyBvZMS+YWhsw71jaCBob2Ruw7R0IGFsZWJvIMWlYcW+xaFpZSBrb25jZSwgYWtvIGplIG5vcm3DoWxuZSAodHJvY2h1IMWhcGljYXRvc8WlKS4KClN0cmVkbsOhIG9ibGFzxaUKClN0cmVkbsOhIMSNYXPFpSBncmFmdSAo4oiSMSBhxb4gKzEga3ZhbnRpbHkpIHNhIHZlxL5taSBkb2JyZSB6aG9kdWplIOKAkyDEjW8gem5hbWVuw6EsIMW+ZSB2w6TEjcWhaW5hIHJlesOtZHXDrSBwZWtuZSB6YXBhZMOhIGRvIG5vcm3DoWxuZWhvIHJvemRlbGVuaWEuCgpaw6Fyb3ZlxYggdnlrb27DoXZhbWUgbsOhc2xlZG7DqSB0ZXN0eSwgdiBrdG9yw71jaCB6YW1pZXRhbWUgaHlwb3TDqXp1IG8gbm9ybcOhbG5vbSByb3psb8W+ZW7DrSBtb2RlbG92w71jaCBjaMO9YiwgYWtvIGFqIHByw610b21ub3PFpSBleHRyw6ltbnljaCBob2Ruw7R0LiAKCiMjIFNjYWxlIGxvY2F0aW9uIHBsb3QKCiMjIyDEjG8gdG8gem7DoXpvcsWIdWplCgpPcyBYOiBWeXJvdm5hbjAgaG9kbm90eSAKT3MgWTogRHJ1aMOhIG9kbW9jbmluYSBhYnNvbMO6dG55Y2ggxaF0YW5kYXJkaXpvdmFuw71jaCByZXrDrWR1w60gCsSMZXJ2ZW7DoSDEjWlhcmE6IExPRVNTICh2eWhsYWRlbsO9KSB0cmVuZCBjZXogYm9keQoKIyMjIEludGVycHJldMOhY2lhIG7DocWhaG8ga29ua3LDqXRuZWhvIGdyYWZ1CgpIb3Jpem9udMOhbG5lIHJvenB0w71sZW5pZQoKLSBCb2R5IHPDuiByb3Zub21lcm5lIHJvenB0w71sZW7DqSBwbyBvc2kgeCBiZXogdnl0dm9yZW5pYSBsaWV2aWthIGFsZWJvIGtyaXZreS4gVG8gbmF6bmHEjXVqZSBwcmlibGnFvm5lIGtvbsWhdGFudG7DuiB2YXJpYW5jaXUg4oCTIHJlesOtZHXDoSBzw7ogaG9tb3NjZWRhc3RpY2vDqS4KLSDEjGVydmVuw6EgaGxhZGvDoSDEjWlhcmEgamUgdGFrbWVyIHJvdm7DoSDigJMgxI9hbMWhw60gem5haywgxb5lIHByaSB6dnnFoW92YW7DrSB2eXJvdm5hbsO9Y2ggaG9kbsO0dCBuZWRvY2jDoWR6YSBrIMW+aWFkbmVqIHN5c3RlbWF0aWNrZWogem1lbmUgdmFyaWFuY2llLgotIE9kxL5haGzDqSBob2Rub3R5IC0gbmlla2/EvmtvIGJvZG92IGplIG1pZXJuZSBuYWQgMSw1LCBhbGUgxb5pYWRueSB6IG5pY2ggbmllIGplIGV4dHLDqW1ueSDigJMgdGFrxb5lIG5lZG9jaMOhZHphIGsgxb5pYWRueW0gesOhdmHFvm7DvW0gYW5vbcOhbGnDoW0gdmFyaWFuY2llLgoKIyMgcmVzaWR1YWxzIHZzIGxldmVyYWdlCgojIyMgxIxvIHpuw6F6b3LFiHVqZSBncmFmCgpPcyBYOiBQw6Frb3bDvSBlZmVrdCAg4oCUIG1lcmlhLCBha28gxI9hbGVrbyBqZSBwcmVkaWt0b3JvdsO9IHZla3RvciBib2R1ICBvZCBzdHJlZHUgdsWhZXRrw71jaCAK8J2RpQp4LgoKT3MgWTogxaB0YW5kYXJkaXpvdmFuw6kgcmV6w61kdcOhIOKAlCBha28gxI9hbGVrbyBqZSBwb3pvcm92YW7DoSBob2Rub3RhIAogb2Qgdnlyb3ZuYW5laiBob2Rub3R5IHYgamVkbm90a8OhY2ggxaF0YW5kYXJkbmVqIG9kY2jDvWxreS4KCkJvZGtvdmFuw6kga3Jpdmt5OiBLb250w7pyeSBDb29rb3ZlaiB2emRpYWxlbm9zdGksIGt0b3LDqSB1ZMOhdmFqw7osIGRvIGFrZWogbWllcnkgcG96b3JvdmFuaWUgb3ZwbHl2xYh1amUgcmVncmVzbsO6IHByaWFta3UuCgrEjGVydmVuw6EgxI1pYXJhOiBIbGFka8OhIExPRVNTIMSNaWFyYSBwcmVjaMOhZHphasO6Y2EgcmV6w61kdWFtaS5sbQoKIyMjIEludGVycHJldMOhY2lhIHbDocWhaG8ga29ua3LDqXRuZWhvIGdyYWZ1CgpSb3psb8W+ZW5pZSB2cGx5dnUKClbDpMSNxaFpbmEgcG96b3JvdmFuw60gbcOhIG7DrXpreSB2cGx5diAocG9kIDAsMDUpIOKAlCB0eXBpY2vDqSBwcmUgdmXEvmvDqSB2em9ya3kgYWxlYm8gZG9icmUgdnl2w6HFvmVuw6kgw7pkYWplLgoKSmVkZW4gYWxlYm8gZHZhIGJvZHkgKG5hcHIuIG9rb2xvIDAsMikgdnluaWthasO6IOKAkyBpZGUgbyBwb3pvcm92YW5pYSBzIHZ5c29rb3UgcMOha291LCDEjW8gem5hbWVuw6EsIMW+ZSBpY2ggaG9kbm90eSBzw7ogxI9hbGVrbyBvZCB2w6TEjcWhaW55IMO6ZGFqb3YuCgpWZcS+a29zxaUgcmV6w61kdcOtCgrFoHRhbmRhcmRpem92YW7DqSByZXrDrWR1w6EgdsOkxI3FoWlub3UgbWVkemkg4oiSMiBhICsyIOKAkyB0byBqZSBkb2Jyw6kgKMW+aWFkbmUgesOhdmHFvm7DqSB2w71uaW1reSB2IArwnZGmCnkpLgoKUG96b3JvdmFuaWUgb3puYcSNZW7DqSDEjcOtc2xvbSAxMTMgbcOhIHpkYW5saXZvIHN0cmVkbsO9IHZwbHl2IGEgcmVsYXTDrXZuZSB2ZcS+a8O6IHJlesOtZHXDoWxudSBob2Rub3R1IOKAkyBwb3RlbmNpw6FsbmUgdnBseXZuw70gcHLDrXBhZC4KCktvbnTDunJ5IENvb2tvdmVqIHZ6ZGlhbGVub3N0aQoKxb1pYWRlbiB6IGJvZG92IGphc25lIG5lcHJla3JhxI11amUgdm9ua2FqxaFpZSBsw61uaWUgQ29va292ZWogdnpkaWFsZW5vc3RpICjiiYgwLDUgYWxlYm8gMSwwKS4KClByZXRvIHNhIG5lemTDoSwgxb5lIGJ5IG5pZWt0b3LDqSBwb3pvcm92YW5pZSBuZXByaW1lcmFuZSBvdnBseXbFiG92YWxvIHJlZ3Jlc27DqSBrb2VmaWNpZW50eS4KCmBgYHtyfWxtCiMgbm9ybWFsaXR5IHRlc3RzCnJlc2lkdWFscyA8LSByZXNpZHVhbHMobW9kZWwpCmpiX3Rlc3QgPC0gamFycXVlLmJlcmEudGVzdChyZXNpZHVhbHMpCmpiX3Rlc3QKIyBvdXRsaWVyIHRlc3QgKHNlZSBwLXZhbHVlIGZvciBCb25mZXJyb25pIGNvcnJlY3Rpb24pCm91dGxpZXJfdGVzdCA8LSBvdXRsaWVyVGVzdChtb2RlbCkKb3V0bGllcl90ZXN0CmBgYAoKS2XEj8W+ZSBzYSBuZXByZXVrw6F6YWxhIG5vcm1hbGl0YSByZXrDrWR1w60sIHBva8O6c21lIHNhIGVsaW1pbm92YcWlIG9kxL5haGzDqSBob2Rub3R5IHYgcHLDrXBhZGUgR0RQIC0gZG9rw6HFvmVtZSB0byBsb2dhcml0bWlja291IHRyYW5zZm9ybcOhY2lvdSB0ZWp0byBwcmVtZW5uZWogYSB2eWzDusSNZW7DrW0gQk1JLCBrdG9yw6kgc2EgdWvDoXphbG8gYWtvIG5laW50ZXJwcmV0b3ZhdGXEvm7DqS4gTm92w6EgcmVncmVzaWEgYnVkZSBtYcWlIHR2YXIKCgpgYGB7cn0KbW9kZWwyIDwtIGxtKExpZmUuZXhwZWN0YW5jeSB+ICsxICsgSShsb2coR0RQKSkgKyBTY2hvb2xpbmcsZGF0YT11ZGFqZS4yMDE1KQpzdW1tYXJ5KG1vZGVsMikKYGBgCmBgYHtyIGRpYWdwbG90czIsIGZpZy5jYXA9IkRpYWdub3N0aWNrw6kgZ3JhZnkgcmVncmVzbsOpaG8gbW9kZWx1In0KIyBOYXN0YXZpxaUgcm96bG/FvmVuaWUgMiB4IDIKcGFyKG1mcm93ID0gYygyLCAyKSkKCiMgVnlrcmVzbGnFpSB2xaFldGt5IDQgZGlhZ25vc3RpY2vDqSBncmFmeSBtb2RlbHUKcGxvdChtb2RlbDIpCgojIChWb2xpdGXEvm7DqSkgcHJpZGHFpSBzcG9sb8SNbsO9IG5hZHBpcwojbXRleHQoIkRpYWdub3N0aWNrw6kgZ3JhZnkgcmVncmVzbsOpaG8gbW9kZWx1Iiwgb3V0ZXIgPSBUUlVFLCBjZXggPSAxLjIsIGZvbnQgPSAyKQoKIyBSZXNldG92YcWlIGxheW91dApwYXIobWZyb3cgPSBjKDEsIDEpKQpgYGAKCgoKCmBgYHtyfQojIG5vcm1hbGl0eSB0ZXN0cwpyZXNpZHVhbHMgPC0gcmVzaWR1YWxzKG1vZGVsKQpqYl90ZXN0IDwtIGphcnF1ZS5iZXJhLnRlc3QocmVzaWR1YWxzKQpqYl90ZXN0CiMgb3V0bGllciB0ZXN0IChzZWUgcC12YWx1ZSBmb3IgQm9uZmVycm9uaSBjb3JyZWN0aW9uKQpvdXRsaWVyX3Rlc3QgPC0gb3V0bGllclRlc3QobW9kZWwpCm91dGxpZXJfdGVzdApgYGAKCiMjQ29uY2x1c2lvbiMjCgpQcmVtZW5uw6kgKkdEUCosIGEgKlNjaG9vbGluZyogcHJlZGzFvnVqw7ogxaF0YXRpc2lja3kgdsO9em5hbW5lIHN0cmVkbsO6IGTEusW+a3Ugxb5pdm90YS4gTmEgZHJ1aGVqIHN0cmFuZSAqQk1JKiBuw6FtIGTDoXZhbG8gbmVpbnRlcnByZXRvdmF0ZcS+bsOpIHbDvXNsZWRreS4gUmV6w61kdcOhIG5ldnlrYXp1asO6IG5vcm3DoWxuZSByb3pkZWxlbmllLCBrZcSPxb5lIHbFoWFrIG3DoW1lIHZlxL5rw6kgbW5vxb5zdHZvIHBvem9yb3ZhbsOtLCBhaiBuYcSPYWxlaiBidWRlbWUgcHJhY292YcWlIHMgdMO9bWl0byDDumRham1pLiBWIG1vZGVsaSBzYSBuZXByZXVrYXp1asO6IMW+aWFkbmUgdsO9em5hbW7DqSBuZWxpbmVhcml0eS4KCg==