S využitím databázy [student_exam_scores] database.

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

library(tidyverse)
library(GGally)    # pairs
library(broom)     # tidy model outputs
library(car)       # VIF
library(caret)     # RMSE, trainControl 
library(report)    # pre pekné reporty 

Úvod do problému, stanovenie hypotéz

Rozhodla som sa modelovať výsledné skúškové skóre študentov (exam_score) v závislosti od troch vysvetľujúcich premenných:

Cieľom analýzy je overiť, ktoré z týchto faktorov majú štatisticky významný vplyv na dosiahnutý výsledok skúšky a ako silný tento vzťah je. Modelovanie prebehne pomocou viacnásobnej lineárnej regresie, pričom budeme skúmať, či sa zmeny v týchto premenných prejavia v zmene skúškového skóre.

Naša pracovná hypotéza predpokladá štatisticky významný vplyv všetkých troch vysvetľujúcich premenných. Zároveň sa očakáva nasledovný smer účinku jednotlivých faktorov:

Formálne teda stanovujeme nasledovné hypotézy:

H₁: Premenné hours_studied, sleep_hours a attendance_percent majú štatisticky významný vplyv na exam_score.

H₀: Medzi exam_score a uvedenými vysvetľujúcimi premennými neexistuje štatisticky významný vzťah.


# Načítanie dát ----------------------------------------------------------
df <- read_csv("student_exam_scores.csv")

# Rýchly prehľad
glimpse(df)
Rows: 200
Columns: 6
$ student_id         <chr> "S001", "S002", "S003", "S004", "S005", "S006", "S007", "S008", "S009", "S010", "S011", "…
$ hours_studied      <dbl> 8.0, 1.3, 4.0, 3.5, 9.1, 8.4, 10.8, 2.0, 5.6, 1.3, 3.4, 6.6, 1.3, 3.2, 8.1, 7.0, 3.4, 7.5…
$ sleep_hours        <dbl> 8.8, 8.6, 8.2, 4.8, 6.4, 5.1, 6.0, 4.3, 5.9, 8.9, 5.3, 7.9, 6.3, 6.1, 8.8, 9.0, 6.8, 7.6,…
$ attendance_percent <dbl> 72.1, 60.7, 73.7, 95.1, 89.8, 58.5, 54.2, 75.8, 81.6, 66.8, 90.9, 87.6, 83.6, 61.2, 60.0,…
$ previous_scores    <dbl> 45, 55, 86, 66, 71, 75, 88, 55, 84, 70, 81, 85, 71, 68, 90, 41, 45, 58, 54, 65, 84, 55, 5…
$ exam_score         <dbl> 30.2, 25.0, 35.8, 34.0, 40.3, 35.7, 37.9, 18.3, 34.7, 24.7, 29.3, 35.1, 31.2, 30.2, 41.1,…
summary(df)
  student_id        hours_studied     sleep_hours    attendance_percent previous_scores   exam_score   
 Length:200         Min.   : 1.000   Min.   :4.000   Min.   : 50.30     Min.   :40.0    Min.   :17.10  
 Class :character   1st Qu.: 3.500   1st Qu.:5.300   1st Qu.: 62.20     1st Qu.:54.0    1st Qu.:29.50  
 Mode  :character   Median : 6.150   Median :6.700   Median : 75.25     Median :67.5    Median :34.05  
                    Mean   : 6.325   Mean   :6.622   Mean   : 74.83     Mean   :66.8    Mean   :33.95  
                    3rd Qu.: 9.000   3rd Qu.:8.025   3rd Qu.: 87.42     3rd Qu.:80.0    3rd Qu.:38.75  
                    Max.   :12.000   Max.   :9.000   Max.   :100.00     Max.   :95.0    Max.   :51.30  
# ukáž prvých 10 riadkov
print(head(df, 10))

# Čistenie a kontrola ---------------------------------------------------
# Skontrolujeme chýbajúce hodnoty
map_dfr(df, ~sum(is.na(.x))) %>% gather(var, missing) %>% print()

# Ak sú chýbajúce hodnoty a chceš ich odstrániť:
df <- df %>% drop_na()

df <- df %>% mutate(student_id = as.character(student_id))

# Prieskumná analýza (EDA) -----------------------------------------------
# Popisné štatistiky pre numerické premenné
num_vars <- df %>% select_if(is.numeric)
summary(num_vars)
 hours_studied     sleep_hours    attendance_percent previous_scores   exam_score   
 Min.   : 1.000   Min.   :4.000   Min.   : 50.30     Min.   :40.0    Min.   :17.10  
 1st Qu.: 3.500   1st Qu.:5.300   1st Qu.: 62.20     1st Qu.:54.0    1st Qu.:29.50  
 Median : 6.150   Median :6.700   Median : 75.25     Median :67.5    Median :34.05  
 Mean   : 6.325   Mean   :6.622   Mean   : 74.83     Mean   :66.8    Mean   :33.95  
 3rd Qu.: 9.000   3rd Qu.:8.025   3rd Qu.: 87.42     3rd Qu.:80.0    3rd Qu.:38.75  
 Max.   :12.000   Max.   :9.000   Max.   :100.00     Max.   :95.0    Max.   :51.30  
# Histogramy (všetky numerické)
num_vars %>% gather(variable, value) %>%
  ggplot(aes(x = value)) +
  geom_histogram(bins = 30) +
  facet_wrap(~variable, scales = "free") +
  labs(title = "Histogramy numerických premenných")


# Boxploty proti exam_score pre vybrané prediktory
ggplot(df, aes(x = 1, y = exam_score)) +
  geom_boxplot() +
  labs(title = "Boxplot exam_score (všetky hodnoty)")


# Párové grafy / korelácie
GGally::ggpairs(df %>% select(-student_id))


# Korelačná matica
cor_mat <- cor(df %>% select_if(is.numeric))
print(round(cor_mat, 3))
                   hours_studied sleep_hours attendance_percent previous_scores exam_score
hours_studied              1.000       0.078             -0.031           0.069      0.777
sleep_hours                0.078       1.000              0.001          -0.194      0.188
attendance_percent        -0.031       0.001              1.000           0.052      0.226
previous_scores            0.069      -0.194              0.052           1.000      0.431
exam_score                 0.777       0.188              0.226           0.431      1.000
# Vytvorenie lineárneho modelu -------------------------------------------
# Predpokladáme, že cieľová premenná je exam_score a ostatné sú prediktory
model <- lm(exam_score ~ hours_studied + sleep_hours + attendance_percent + previous_scores,
            data = df)

# Rýchle zhrnutie modelu
summary(model)

Call:
lm(formula = exam_score ~ hours_studied + sleep_hours + attendance_percent + 
    previous_scores, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-5.5455 -2.1818 -0.0847  2.3436  4.8390 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)        -2.14209    1.67079  -1.282    0.201    
hours_studied       1.55526    0.06044  25.732  < 2e-16 ***
sleep_hours         0.95226    0.13243   7.191 1.34e-11 ***
attendance_percent  0.10839    0.01362   7.961 1.38e-13 ***
previous_scores     0.17728    0.01267  13.995  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.731 on 195 degrees of freedom
Multiple R-squared:  0.8414,    Adjusted R-squared:  0.8382 
F-statistic: 258.7 on 4 and 195 DF,  p-value: < 2.2e-16
# Upratané výsledky cez broom
tidy(model)        # koeficienty s p-hodnotami
glance(model)      # R^2, AIC, BIC, RMSE (residual sd), atď.
augment(model) %>% head()

# Diagnostika modelu -----------------------------------------------------
# Reziduá vs fitted
plot(model, which = 1)  # residuals vs fitted


# QQ plot - normálne rozdelenie reziduí
plot(model, which = 2)  # QQ


# Cook's distance (influential points)
plot(model, which = 4)


# Multikolinearita (VIF)
car::vif(model)  # >5 alebo >10 varovať
     hours_studied        sleep_hours attendance_percent    previous_scores 
          1.014944           1.048547           1.004142           1.050271 
# Výpočet RMSE a ďalších metrík -----------------------------------------
preds <- predict(model, newdata = df)
rmse_val <- sqrt(mean((df$exam_score - preds)^2))
mae_val <- mean(abs(df$exam_score - preds))
r2 <- summary(model)$r.squared

cat("RMSE:", round(rmse_val,3), "MAE:", round(mae_val,3), "R2:", round(r2,3), "\n")
RMSE: 2.697 MAE: 2.287 R2: 0.841 
# Alternatívne: cross-validated RMSE cez caret (10-fold CV)
set.seed(123)
train_control <- trainControl(method = "cv", number = 10)
cv_model <- train(exam_score ~ hours_studied + sleep_hours + attendance_percent + previous_scores,
                  data = df,
                  method = "lm",
                  trControl = train_control)

print(cv_model)
Linear Regression 

200 samples
  4 predictor

No pre-processing
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 180, 180, 180, 180, 180, 179, ... 
Resampling results:

  RMSE      Rsquared  MAE   
  2.771046  0.850901  2.3605

Tuning parameter 'intercept' was held constant at a value of TRUE
cv_model$results

# Graf predikcie vs skutočnosť ------------------------------------------
df_plot <- df %>% mutate(predicted = preds)

ggplot(df_plot, aes(x = predicted, y = exam_score)) +
  geom_point() +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed") +
  labs(title = "Predikované vs Skutočné exam_score",
       x = "Predikované hodnoty",
       y = "Skutočné hodnoty")


# Scatter s lineárnym fitom medzi konkrétnym prediktorom a exam_score
ggplot(df, aes(x = hours_studied, y = exam_score)) +
  geom_point() +
  geom_smooth(method = "lm", se = TRUE) +
  labs(title = "Exam score vs Hours studied")

NA
NA

Interpretácia konkrétneho grafu

Na grafe nižšie je znázornený vzťah medzi počtom hodín, ktoré študent venoval štúdiu (hours_studied), a jeho výsledným skóre na skúške (exam_score). Každý bod predstavuje jedného študenta, pričom na osi X je zobrazený počet hodín štúdia a na osi Y výsledné skóre. Do grafu bola pridaná aj regresná priamka, ktorá znázorňuje trend medzi oboma premennými.

Z grafu môžeme pozorovať, že so zvyšujúcim sa počtom hodín štúdia má exam_score tendenciu rásť. To znamená, že medzi týmito dvoma premennými existuje pozitívna lineárna závislosť – čím viac času študent venoval príprave, tým lepšie výsledky na skúške dosiahol. Regresná priamka má kladný smerový koeficient, čo potvrdzuje očakávanie z pracovnej hypotézy (H₁), že počet hodín štúdia má pozitívny vplyv na skúškové skóre.

Zároveň môžeme vidieť mierny rozptyl hodnôt okolo regresnej priamky, čo naznačuje, že aj keď štúdium významne ovplyvňuje výsledok, na výkone študenta sa môžu podieľať aj iné faktory – napríklad kvalita spánku, účinnosť učenia alebo priebežná aktivita počas semestra.

Q-Q plot

Čo ukazuje

  • Os X: Teoretické kvantily – hodnoty, ktoré by sme očakávali, ak by rezíduá boli dokonale normálne rozložené.
  • Os Y: Štandardizované rezíduá – skutočné kvantily vypočítané z dát nášho modelu.
  • 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 konkrétneho grafu

Celkový tvar:
Väčšina bodov leží blízko priamky, čo naznačuje, že rezíduá sú približne normálne rozložené. Predpoklad normality modelových chýb sa teda javí ako vo veľkej miere splnený.

Krajné hodnoty (extrémy):
Na oboch koncoch grafu (vľavo dole a vpravo hore) možno pozorovať mierne odchýlky od 45° čiary. To poukazuje na menšie odchýlky od normality v chvostoch rozdelenia – teda niekoľko odľahlých hodnôt alebo mierne ťažšie konce, než by mal ideálny normálny tvar.

Stredná oblasť:
V strednej časti grafu (približne v intervale −1 až +1 kvantily) sa body veľmi dobre zhodujú s teoretickou priamkou, čo znamená, že väčšina rezíduí zodpovedá normálnemu rozdeleniu.

Na záver možno konštatovať, že model v zásade spĺňa predpoklad normality rezíduí.
Mierne odchýlky v koncoch však naznačujú, že by sa mohol vyskytovať menší počet odľahlých pozorovaní, čo si vyžaduje dodatočnú kontrolu pomocou doplnkových testov (napr. Shapiro–Wilk test, analýza Cookovej vzdialenosti).

Scale location plot

Interpretácia vášho konkrétneho grafu

Body sú rovnomerne rozptýlené pozdĺž osi X bez zreteľného vzoru, čo naznačuje, že rozptyl rezíduí je približne konštantný. Tento jav sa označuje ako homoskedasticita, teda predpoklad rovnakého rozptylu chýb pre všetky úrovne predikovaných hodnôt je vo všeobecnosti splnený.

Červená vyhladzovacia (LOESS) čiara je relatívne rovná a bez výraznej krivky,
čo podporuje záver, že so zvyšujúcimi sa vyrovnanými hodnotami sa variancia rezíduí systematicky nemení.

Niekoľko bodov je síce mierne vzdialených od hlavného zhluku (hodnoty nad 1,5 na osi Y), avšak nejde o extrémne odľahlé pozorovania.
Celkovo teda môžeme konštatovať, že predpoklad konštantnej variability (homoskedasticity) je splnený a model neprejavuje žiadne závažné známky heteroskedasticity.

Interpretácia vášho konkrétneho grafu

Väčšina pozorovaní má nízky pákový efekt (hodnoty pod 0,05), čo naznačuje, že jednotlivé body nemajú výrazný vplyv na tvar regresnej priamky.
To je typické pre dobre rozložené údaje, kde žiadny študent nevyčnieva extrémnymi hodnotami v premenných ako hours_studied, sleep_hours alebo attendance_percent.

Jeden až dva body sa však mierne oddeľujú od ostatných (napr. v oblasti pákového efektu okolo 0,2).
Ide o pozorovania so zvýšenou pákou, teda ich hodnoty prediktorov sú ďalej od väčšiny údajov — napríklad študent s extrémne nízkym počtom hodín spánku alebo veľmi vysokým počtom hodín štúdia.

Väčšina štandardizovaných rezíduí sa nachádza medzi hodnotami −2 a +2, čo znamená, že neexistujú žiadne závažné odľahlé hodnoty v závislej premennej (exam_score).

Kontúry Cookovej vzdialenosti ukazujú, že žiaden z bodov neprekračuje hranice 0,5 či 1,0,
preto žiadne pozorovanie nemá výrazne neprimeraný vplyv na odhady regresných koeficientov.

Celkovo možno konštatovať, že model nie je citlivý na jednotlivé pozorovania a nie sú prítomné extrémne vplyvné body, ktoré by mohli skresľovať výsledky regresie.

Conclusion

Premenné hours_studied a attendance_percent majú štatisticky významný pozitívny vplyv na výsledné skúškové skóre študentov – teda čím viac času študent venuje štúdiu a čím pravidelnejšie sa zúčastňuje vyučovania, tým vyššie skóre dosahuje.

Premenná sleep_hours sa ukázala ako menej významná, pričom jej vplyv na výsledok skúšky nebol jednoznačný – v modeli sa prejavuje s malým alebo neinterpretovateľným účinkom.

Rezíduá nevykazujú úplne dokonalé normálne rozdelenie, avšak vzhľadom na dostatočne veľký počet pozorovaní môžeme model považovať za spoľahlivý a vhodný na interpretáciu.

Z diagnostických grafov taktiež vyplýva, že v modeli sa nepreukazujú žiadne výrazné nelinearity, heteroskedasticita ani vplyvné pozorovania.
Model teda pomerne dobre vystihuje vzťah medzi študijnými návykmi a výsledným skúškovým skóre.

LS0tCnRpdGxlOiAiRWNvbm9tZXRyaWNzIGluIFIgLSBjdmnEjWVuaWUgNSIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogRGlhbmEgSHJ1xaFvdnNrw6EKZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IDcyCi0tLQoKUyB2eXXFvml0w61tIGRhdGFiw6F6eSBbc3R1ZGVudF9leGFtX3Njb3Jlc10gZGF0YWJhc2UuCgpQcmkgxI9hbMWhZWogcHLDoWNpIGJ1ZGVtZSBwb3XFvsOtdmHFpSBrbmnFvm5pY2UKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShHR2FsbHkpICAgICMgcGFpcnMKbGlicmFyeShicm9vbSkgICAgICMgdGlkeSBtb2RlbCBvdXRwdXRzCmxpYnJhcnkoY2FyKSAgICAgICAjIFZJRgpsaWJyYXJ5KGNhcmV0KSAgICAgIyBSTVNFLCB0cmFpbkNvbnRyb2wgCmxpYnJhcnkocmVwb3J0KSAgICAjIHByZSBwZWtuw6kgcmVwb3J0eSAKYGBgCgojIMOadm9kIGRvIHByb2Jsw6ltdSwgc3Rhbm92ZW5pZSBoeXBvdMOpegoKUm96aG9kbGEgc29tIHNhIG1vZGVsb3ZhxaUgKip2w71zbGVkbsOpIHNrw7rFoWtvdsOpIHNrw7NyZSDFoXR1ZGVudG92CigqZXhhbV9zY29yZSopKiogdiB6w6F2aXNsb3N0aSBvZCB0cm9jaCB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoOgoKLSAgIHBvxI10dSBob2TDrW4gxaF0w7pkaWEgKCpob3Vyc19zdHVkaWVkKiksCi0gICBwcmllbWVybsOpaG8gcG/EjXR1IGhvZMOtbiBzcMOhbmt1ICgqc2xlZXBfaG91cnMqKSwKLSAgIGEgcGVyY2VudHXDoWxuZWogw7rEjWFzdGkgbmEgdnl1xI1vdmFuw60gKCphdHRlbmRhbmNlX3BlcmNlbnQqKS4KCkNpZcS+b20gYW5hbMO9enkgamUgb3ZlcmnFpSwga3RvcsOpIHogdMO9Y2h0byBmYWt0b3JvdiBtYWrDuiAqKsWhdGF0aXN0aWNreQp2w716bmFtbsO9IHZwbHl2KiogbmEgZG9zaWFobnV0w70gdsO9c2xlZG9rIHNrw7rFoWt5IGEgYWtvIHNpbG7DvSB0ZW50byB2esWlYWgKamUuIE1vZGVsb3ZhbmllIHByZWJlaG5lIHBvbW9jb3UgKip2aWFjbsOhc29ibmVqIGxpbmXDoXJuZWogcmVncmVzaWUqKiwKcHJpxI1vbSBidWRlbWUgc2vDum1hxaUsIMSNaSBzYSB6bWVueSB2IHTDvWNodG8gcHJlbWVubsO9Y2ggcHJlamF2aWEgdiB6bWVuZQpza8O6xaFrb3bDqWhvIHNrw7NyZS4KCk5hxaFhICoqcHJhY292bsOhIGh5cG90w6l6YSoqIHByZWRwb2tsYWTDoSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSB2cGx5dgp2xaFldGvDvWNoIHRyb2NoIHZ5c3ZldMS+dWrDumNpY2ggcHJlbWVubsO9Y2guIFrDoXJvdmXFiCBzYSBvxI1ha8OhdmEgbmFzbGVkb3Zuw70Kc21lciDDusSNaW5rdSBqZWRub3RsaXbDvWNoIGZha3Rvcm92OgoKLSAgICoqUG/EjWV0IGhvZMOtbiDFoXTDumRpYSAoKmhvdXJzX3N0dWRpZWQqKSoqOiBvxI1ha8OhdmFtZSAqKnBveml0w612bnkKICAgIHZwbHl2Kiog4oCTIMWhdHVkZW50aSwga3RvcsOtIHZlbnVqw7ogdmlhYyDEjWFzdSBwcsOtcHJhdmUsIGRvc2FodWrDuiBsZXDFoWllCiAgICB2w71zbGVka3kuIChrbGFkbsOpIHpuYW1pZW5rbyBvZGhhZG92YW7DqWhvIHJlZ3Jlc27DqWhvIGtvZWZpY2llbnRhKQoKLSAgICoqUG/EjWV0IGhvZMOtbiBzcMOhbmt1ICgqc2xlZXBfaG91cnMqKSoqOiBwcmVkcG9rbGFkw6FtZSAqKnBveml0w612bnkKICAgIHZwbHl2KiosIGtlxI/FvmUgZG9zdGF0b2sgc3DDoW5rdSB6bGVwxaF1amUga29uY2VudHLDoWNpdSBhIHbDvWtvbi4KICAgIChrbGFkbsOpIHpuYW1pZW5rbyBrb2VmaWNpZW50YSkKCi0gICAqKsOaxI1hc8WlIG5hIHZ5dcSNb3ZhbsOtICgqYXR0ZW5kYW5jZV9wZXJjZW50KikqKjogb8SNYWvDoXZhbWUgKipwb3ppdMOtdm55CiAgICB2cGx5dioqLCBwcmV0b8W+ZSBwcmF2aWRlbG7DoSDDusSNYXPFpSBuYSBob2RpbsOhY2ggenZ5xaF1amUgcG9jaG9wZW5pZQogICAgbMOhdGt5IGEgdGVkYSBhaiDDunNwZcWhbm9zxaUuIChrbGFkbsOpIHpuYW1pZW5rbyBrb2VmaWNpZW50YSkKCkZvcm3DoWxuZSB0ZWRhIHN0YW5vdnVqZW1lIG5hc2xlZG92bsOpIGh5cG90w6l6eToKCj4gKipI4oKBOioqIFByZW1lbm7DqSAqaG91cnNfc3R1ZGllZCosICpzbGVlcF9ob3VycyogYSAqYXR0ZW5kYW5jZV9wZXJjZW50Kgo+IG1hasO6IMWhdGF0aXN0aWNreSB2w716bmFtbsO9IHZwbHl2IG5hICpleGFtX3Njb3JlKi4KCj4gKipI4oKAOioqIE1lZHppICpleGFtX3Njb3JlKiBhIHV2ZWRlbsO9bWkgdnlzdmV0xL51asO6Y2ltaSBwcmVtZW5uw71taQo+IG5lZXhpc3R1amUgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70gdnrFpWFoLgoKYGBge3J9CgojIE5hxI3DrXRhbmllIGTDoXQgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpkZiA8LSByZWFkX2Nzdigic3R1ZGVudF9leGFtX3Njb3Jlcy5jc3YiKQoKIyBSw71jaGx5IHByZWjEvmFkCmdsaW1wc2UoZGYpCnN1bW1hcnkoZGYpCiMgdWvDocW+IHBydsO9Y2ggMTAgcmlhZGtvdgpwcmludChoZWFkKGRmLCAxMCkpCgojIMSMaXN0ZW5pZSBhIGtvbnRyb2xhIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFNrb250cm9sdWplbWUgY2jDvWJhasO6Y2UgaG9kbm90eQptYXBfZGZyKGRmLCB+c3VtKGlzLm5hKC54KSkpICU+JSBnYXRoZXIodmFyLCBtaXNzaW5nKSAlPiUgcHJpbnQoKQoKIyBBayBzw7ogY2jDvWJhasO6Y2UgaG9kbm90eSBhIGNoY2XFoSBpY2ggb2RzdHLDoW5pxaU6CmRmIDwtIGRmICU+JSBkcm9wX25hKCkKCmRmIDwtIGRmICU+JSBtdXRhdGUoc3R1ZGVudF9pZCA9IGFzLmNoYXJhY3RlcihzdHVkZW50X2lkKSkKCiMgUHJpZXNrdW1uw6EgYW5hbMO9emEgKEVEQSkgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBQb3Bpc27DqSDFoXRhdGlzdGlreSBwcmUgbnVtZXJpY2vDqSBwcmVtZW5uw6kKbnVtX3ZhcnMgPC0gZGYgJT4lIHNlbGVjdF9pZihpcy5udW1lcmljKQpzdW1tYXJ5KG51bV92YXJzKQoKIyBIaXN0b2dyYW15ICh2xaFldGt5IG51bWVyaWNrw6kpCm51bV92YXJzICU+JSBnYXRoZXIodmFyaWFibGUsIHZhbHVlKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB2YWx1ZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzApICsKICBmYWNldF93cmFwKH52YXJpYWJsZSwgc2NhbGVzID0gImZyZWUiKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW15IG51bWVyaWNrw71jaCBwcmVtZW5uw71jaCIpCgojIEJveHBsb3R5IHByb3RpIGV4YW1fc2NvcmUgcHJlIHZ5YnJhbsOpIHByZWRpa3RvcnkKZ2dwbG90KGRmLCBhZXMoeCA9IDEsIHkgPSBleGFtX3Njb3JlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBsYWJzKHRpdGxlID0gIkJveHBsb3QgZXhhbV9zY29yZSAodsWhZXRreSBob2Rub3R5KSIpCgojIFDDoXJvdsOpIGdyYWZ5IC8ga29yZWzDoWNpZQpHR2FsbHk6OmdncGFpcnMoZGYgJT4lIHNlbGVjdCgtc3R1ZGVudF9pZCkpCgojIEtvcmVsYcSNbsOhIG1hdGljYQpjb3JfbWF0IDwtIGNvcihkZiAlPiUgc2VsZWN0X2lmKGlzLm51bWVyaWMpKQpwcmludChyb3VuZChjb3JfbWF0LCAzKSkKCiMgVnl0dm9yZW5pZSBsaW5lw6FybmVobyBtb2RlbHUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIFByZWRwb2tsYWTDoW1lLCDFvmUgY2llxL5vdsOhIHByZW1lbm7DoSBqZSBleGFtX3Njb3JlIGEgb3N0YXRuw6kgc8O6IHByZWRpa3RvcnkKbW9kZWwgPC0gbG0oZXhhbV9zY29yZSB+IGhvdXJzX3N0dWRpZWQgKyBzbGVlcF9ob3VycyArIGF0dGVuZGFuY2VfcGVyY2VudCArIHByZXZpb3VzX3Njb3JlcywKICAgICAgICAgICAgZGF0YSA9IGRmKQoKIyBSw71jaGxlIHpocm51dGllIG1vZGVsdQpzdW1tYXJ5KG1vZGVsKQoKIyBVcHJhdGFuw6kgdsO9c2xlZGt5IGNleiBicm9vbQp0aWR5KG1vZGVsKSAgICAgICAgIyBrb2VmaWNpZW50eSBzIHAtaG9kbm90YW1pCmdsYW5jZShtb2RlbCkgICAgICAjIFJeMiwgQUlDLCBCSUMsIFJNU0UgKHJlc2lkdWFsIHNkKSwgYXTEjy4KYXVnbWVudChtb2RlbCkgJT4lIGhlYWQoKQoKIyBEaWFnbm9zdGlrYSBtb2RlbHUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBSZXppZHXDoSB2cyBmaXR0ZWQKcGxvdChtb2RlbCwgd2hpY2ggPSAxKSAgIyByZXNpZHVhbHMgdnMgZml0dGVkCgojIFFRIHBsb3QgLSBub3Jtw6FsbmUgcm96ZGVsZW5pZSByZXppZHXDrQpwbG90KG1vZGVsLCB3aGljaCA9IDIpICAjIFFRCgojIENvb2sncyBkaXN0YW5jZSAoaW5mbHVlbnRpYWwgcG9pbnRzKQpwbG90KG1vZGVsLCB3aGljaCA9IDQpCgojIE11bHRpa29saW5lYXJpdGEgKFZJRikKY2FyOjp2aWYobW9kZWwpICAjID41IGFsZWJvID4xMCB2YXJvdmHFpQoKIyBWw71wb8SNZXQgUk1TRSBhIMSPYWzFocOtY2ggbWV0csOtayAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpwcmVkcyA8LSBwcmVkaWN0KG1vZGVsLCBuZXdkYXRhID0gZGYpCnJtc2VfdmFsIDwtIHNxcnQobWVhbigoZGYkZXhhbV9zY29yZSAtIHByZWRzKV4yKSkKbWFlX3ZhbCA8LSBtZWFuKGFicyhkZiRleGFtX3Njb3JlIC0gcHJlZHMpKQpyMiA8LSBzdW1tYXJ5KG1vZGVsKSRyLnNxdWFyZWQKCmNhdCgiUk1TRToiLCByb3VuZChybXNlX3ZhbCwzKSwgIk1BRToiLCByb3VuZChtYWVfdmFsLDMpLCAiUjI6Iiwgcm91bmQocjIsMyksICJcbiIpCgojIEFsdGVybmF0w612bmU6IGNyb3NzLXZhbGlkYXRlZCBSTVNFIGNleiBjYXJldCAoMTAtZm9sZCBDVikKc2V0LnNlZWQoMTIzKQp0cmFpbl9jb250cm9sIDwtIHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXIgPSAxMCkKY3ZfbW9kZWwgPC0gdHJhaW4oZXhhbV9zY29yZSB+IGhvdXJzX3N0dWRpZWQgKyBzbGVlcF9ob3VycyArIGF0dGVuZGFuY2VfcGVyY2VudCArIHByZXZpb3VzX3Njb3JlcywKICAgICAgICAgICAgICAgICAgZGF0YSA9IGRmLAogICAgICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLAogICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbl9jb250cm9sKQoKcHJpbnQoY3ZfbW9kZWwpCmN2X21vZGVsJHJlc3VsdHMKCiMgR3JhZiBwcmVkaWtjaWUgdnMgc2t1dG/EjW5vc8WlIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQpkZl9wbG90IDwtIGRmICU+JSBtdXRhdGUocHJlZGljdGVkID0gcHJlZHMpCgpnZ3Bsb3QoZGZfcGxvdCwgYWVzKHggPSBwcmVkaWN0ZWQsIHkgPSBleGFtX3Njb3JlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgbGFicyh0aXRsZSA9ICJQcmVkaWtvdmFuw6kgdnMgU2t1dG/EjW7DqSBleGFtX3Njb3JlIiwKICAgICAgIHggPSAiUHJlZGlrb3ZhbsOpIGhvZG5vdHkiLAogICAgICAgeSA9ICJTa3V0b8SNbsOpIGhvZG5vdHkiKQoKIyBTY2F0dGVyIHMgbGluZcOhcm55bSBmaXRvbSBtZWR6aSBrb25rcsOpdG55bSBwcmVkaWt0b3JvbSBhIGV4YW1fc2NvcmUKZ2dwbG90KGRmLCBhZXMoeCA9IGhvdXJzX3N0dWRpZWQsIHkgPSBleGFtX3Njb3JlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBUUlVFKSArCiAgbGFicyh0aXRsZSA9ICJFeGFtIHNjb3JlIHZzIEhvdXJzIHN0dWRpZWQiKQoKCmBgYAoKIyMjIEludGVycHJldMOhY2lhIGtvbmtyw6l0bmVobyBncmFmdQoKTmEgZ3JhZmUgbmnFvsWhaWUgamUgem7DoXpvcm5lbsO9IHZ6xaVhaCBtZWR6aSBwb8SNdG9tIGhvZMOtbiwga3RvcsOpIMWhdHVkZW50CnZlbm92YWwgxaF0w7pkaXUgKCpob3Vyc19zdHVkaWVkKiksIGEgamVobyB2w71zbGVkbsO9bSBza8OzcmUgbmEgc2vDusWha2UKKCpleGFtX3Njb3JlKikuIEthxb5kw70gYm9kIHByZWRzdGF2dWplIGplZG7DqWhvIMWhdHVkZW50YSwgcHJpxI1vbSBuYSBvc2kgWApqZSB6b2JyYXplbsO9IHBvxI1ldCBob2TDrW4gxaF0w7pkaWEgYSBuYSBvc2kgWSB2w71zbGVkbsOpIHNrw7NyZS4gRG8gZ3JhZnUgYm9sYQpwcmlkYW7DoSBhaiByZWdyZXNuw6EgcHJpYW1rYSwga3RvcsOhIHpuw6F6b3LFiHVqZSB0cmVuZCBtZWR6aSBvYm9tYQpwcmVtZW5uw71taS4KClogZ3JhZnUgbcO0xb5lbWUgcG96b3JvdmHFpSwgxb5lIHNvIHp2ecWhdWrDumNpbSBzYSBwb8SNdG9tIGhvZMOtbiDFoXTDumRpYSBtw6EKKmV4YW1fc2NvcmUqIHRlbmRlbmNpdSByw6FzxaUuIFRvIHpuYW1lbsOhLCDFvmUgbWVkemkgdMO9bWl0byBkdm9tYQpwcmVtZW5uw71taSBleGlzdHVqZSAqKnBveml0w612bmEgbGluZcOhcm5hIHrDoXZpc2xvc8WlKiog4oCTIMSNw61tIHZpYWMgxI1hc3UKxaF0dWRlbnQgdmVub3ZhbCBwcsOtcHJhdmUsIHTDvW0gbGVwxaFpZSB2w71zbGVka3kgbmEgc2vDusWha2UgZG9zaWFob2wuClJlZ3Jlc27DoSBwcmlhbWthIG3DoSAqKmtsYWRuw70gc21lcm92w70ga29lZmljaWVudCoqLCDEjW8gcG90dnJkenVqZQpvxI1ha8OhdmFuaWUgeiBwcmFjb3ZuZWogaHlwb3TDqXp5ICgqSOKCgSopLCDFvmUgcG/EjWV0IGhvZMOtbiDFoXTDumRpYSBtw6EKcG96aXTDrXZueSB2cGx5diBuYSBza8O6xaFrb3bDqSBza8OzcmUuCgpaw6Fyb3ZlxYggbcO0xb5lbWUgdmlkaWXFpSBtaWVybnkgcm96cHR5bCBob2Ruw7R0IG9rb2xvIHJlZ3Jlc25laiBwcmlhbWt5LCDEjW8KbmF6bmHEjXVqZSwgxb5lIGFqIGtlxI8gxaF0w7pkaXVtIHbDvXpuYW1uZSBvdnBseXbFiHVqZSB2w71zbGVkb2ssIG5hIHbDvWtvbmUKxaF0dWRlbnRhIHNhIG3DtMW+dSBwb2RpZcS+YcWlIGFqIGluw6kgZmFrdG9yeSDigJMgbmFwcsOta2xhZCBrdmFsaXRhIHNww6Fua3UsCsO6xI1pbm5vc8WlIHXEjWVuaWEgYWxlYm8gcHJpZWJlxb5uw6EgYWt0aXZpdGEgcG/EjWFzIHNlbWVzdHJhLgoKIyMgUS1RIHBsb3QKCiMjIyDEjG8gdWthenVqZQoKLSAgICoqT3MgWDoqKiBUZW9yZXRpY2vDqSBrdmFudGlseSDigJMgaG9kbm90eSwga3RvcsOpIGJ5IHNtZSBvxI1ha8OhdmFsaSwgYWsKICAgIGJ5IHJlesOtZHXDoSBib2xpIGRva29uYWxlIG5vcm3DoWxuZSByb3psb8W+ZW7DqS5cCi0gICAqKk9zIFk6KiogxaB0YW5kYXJkaXpvdmFuw6kgcmV6w61kdcOhIOKAkyBza3V0b8SNbsOpIGt2YW50aWx5IHZ5cG/EjcOtdGFuw6kgegogICAgZMOhdCBuw6HFoWhvIG1vZGVsdS5cCi0gICAqKjQ1wrAgcHJlcnXFoW92YW7DoSDEjWlhcmE6KiogSWRlw6FsbnkgcHLDrXBhZCDigJMgYWsgc8O6IHJlesOtZHXDoSBub3Jtw6FsbmUKICAgIHJvemxvxb5lbsOpLCBib2R5IGJ5IG1hbGkgbGXFvmHFpSB0ZXNuZSBwb3pkxLrFviB0ZWp0byDEjWlhcnkuCgojIyMgSW50ZXJwcmV0w6FjaWEga29ua3LDqXRuZWhvIGdyYWZ1CgoqKkNlbGtvdsO9IHR2YXI6KipcClbDpMSNxaFpbmEgYm9kb3YgbGXFvsOtIGJsw616a28gcHJpYW1reSwgxI1vIG5hem5hxI11amUsIMW+ZSByZXrDrWR1w6Egc8O6CioqcHJpYmxpxb5uZSBub3Jtw6FsbmUgcm96bG/FvmVuw6kqKi4gUHJlZHBva2xhZCBub3JtYWxpdHkgbW9kZWxvdsO9Y2ggY2jDvWIKc2EgdGVkYSBqYXbDrSBha28gdm8gdmXEvmtlaiBtaWVyZSBzcGxuZW7DvS4KCioqS3Jham7DqSBob2Rub3R5IChleHRyw6lteSk6KipcCk5hIG9ib2NoIGtvbmNvY2ggZ3JhZnUgKHbEvmF2byBkb2xlIGEgdnByYXZvIGhvcmUpIG1vxb5ubyBwb3pvcm92YcWlIG1pZXJuZQpvZGNow71sa3kgb2QgNDXCsCDEjWlhcnkuIFRvIHBvdWthenVqZSBuYSAqKm1lbsWhaWUgb2RjaMO9bGt5IG9kIG5vcm1hbGl0eSB2CmNodm9zdG9jaCByb3pkZWxlbmlhKiog4oCTIHRlZGEgbmlla2/EvmtvIG9kxL5haGzDvWNoIGhvZG7DtHQgYWxlYm8gbWllcm5lCsWlYcW+xaFpZSBrb25jZSwgbmXFviBieSBtYWwgaWRlw6Fsbnkgbm9ybcOhbG55IHR2YXIuCgoqKlN0cmVkbsOhIG9ibGFzxaU6KipcClYgc3RyZWRuZWogxI1hc3RpIGdyYWZ1IChwcmlibGnFvm5lIHYgaW50ZXJ2YWxlIOKIkjEgYcW+ICsxIGt2YW50aWx5KSBzYSBib2R5CnZlxL5taSBkb2JyZSB6aG9kdWrDuiBzIHRlb3JldGlja291IHByaWFta291LCDEjW8gem5hbWVuw6EsIMW+ZSB2w6TEjcWhaW5hCnJlesOtZHXDrSB6b2Rwb3ZlZMOhIG5vcm3DoWxuZW11IHJvemRlbGVuaXUuCgpOYSB6w6F2ZXIgbW/Fvm5vIGtvbsWhdGF0b3ZhxaUsIMW+ZSAqKm1vZGVsIHYgesOhc2FkZSBzcMS6xYhhIHByZWRwb2tsYWQKbm9ybWFsaXR5IHJlesOtZHXDrSoqLlwKTWllcm5lIG9kY2jDvWxreSB2IGtvbmNvY2ggdsWhYWsgbmF6bmHEjXVqw7osIMW+ZSBieSBzYSBtb2hvbCB2eXNreXRvdmHFpQptZW7FocOtIHBvxI1ldCBvZMS+YWhsw71jaCBwb3pvcm92YW7DrSwgxI1vIHNpIHZ5xb5hZHVqZSBkb2RhdG/EjW7DuiBrb250cm9sdQpwb21vY291IGRvcGxua292w71jaCB0ZXN0b3YgKG5hcHIuIFNoYXBpcm/igJNXaWxrIHRlc3QsIGFuYWzDvXphIENvb2tvdmVqCnZ6ZGlhbGVub3N0aSkuCgojIyBTY2FsZSBsb2NhdGlvbiBwbG90CgojIyMgSW50ZXJwcmV0w6FjaWEgdsOhxaFobyBrb25rcsOpdG5laG8gZ3JhZnUKCkJvZHkgc8O6IHJvdm5vbWVybmUgcm96cHTDvWxlbsOpIHBvemTEusW+IG9zaSBYIGJleiB6cmV0ZcS+bsOpaG8gdnpvcnUsIMSNbwpuYXpuYcSNdWplLCDFvmUgcm96cHR5bCByZXrDrWR1w60gamUgKipwcmlibGnFvm5lIGtvbsWhdGFudG7DvSoqLiBUZW50byBqYXYgc2EKb3puYcSNdWplIGFrbyAqKmhvbW9za2VkYXN0aWNpdGEqKiwgdGVkYSBwcmVkcG9rbGFkIHJvdm5ha8OpaG8gcm96cHR5bHUKY2jDvWIgcHJlIHbFoWV0a3kgw7pyb3ZuZSBwcmVkaWtvdmFuw71jaCBob2Ruw7R0IGplIHZvIHbFoWVvYmVjbm9zdGkgc3BsbmVuw70uCgrEjGVydmVuw6EgdnlobGFkem92YWNpYSAoTE9FU1MpIMSNaWFyYSBqZSByZWxhdMOtdm5lICoqcm92bsOhIGEgYmV6IHbDvXJhem5lagprcml2a3kqKixcCsSNbyBwb2Rwb3J1amUgesOhdmVyLCDFvmUgc28genZ5xaF1asO6Y2ltaSBzYSB2eXJvdm5hbsO9bWkgaG9kbm90YW1pIHNhCnZhcmlhbmNpYSByZXrDrWR1w60gc3lzdGVtYXRpY2t5IG5lbWVuw60uCgpOaWVrb8S+a28gYm9kb3YgamUgc8OtY2UgbWllcm5lIHZ6ZGlhbGVuw71jaCBvZCBobGF2bsOpaG8gemhsdWt1IChob2Rub3R5Cm5hZCAxLDUgbmEgb3NpIFkpLCBhdsWhYWsgbmVqZGUgbyBleHRyw6ltbmUgb2TEvmFobMOpIHBvem9yb3ZhbmlhLlwKQ2Vsa292byB0ZWRhIG3DtMW+ZW1lIGtvbsWhdGF0b3ZhxaUsIMW+ZSAqKnByZWRwb2tsYWQga29uxaF0YW50bmVqIHZhcmlhYmlsaXR5Cihob21vc2tlZGFzdGljaXR5KSBqZSBzcGxuZW7DvSoqIGEgbW9kZWwgbmVwcmVqYXZ1amUgxb5pYWRuZSB6w6F2YcW+bsOpCnpuw6Fta3kgaGV0ZXJvc2tlZGFzdGljaXR5LgoKIyMjIEludGVycHJldMOhY2lhIHbDocWhaG8ga29ua3LDqXRuZWhvIGdyYWZ1CgpWw6TEjcWhaW5hIHBvem9yb3ZhbsOtIG3DoSBuw616a3kgcMOha292w70gZWZla3QgKGhvZG5vdHkgcG9kIDAsMDUpLCDEjW8KbmF6bmHEjXVqZSwgxb5lIGplZG5vdGxpdsOpIGJvZHkgbmVtYWrDuiB2w71yYXpuw70gdnBseXYgbmEgdHZhciByZWdyZXNuZWoKcHJpYW1reS5cClRvIGplIHR5cGlja8OpIHByZSBkb2JyZSByb3psb8W+ZW7DqSDDumRhamUsIGtkZSDFvmlhZG55IMWhdHVkZW50IG5ldnnEjW5pZXZhCmV4dHLDqW1ueW1pIGhvZG5vdGFtaSB2IHByZW1lbm7DvWNoIGFrbyAqaG91cnNfc3R1ZGllZCosICpzbGVlcF9ob3VycyoKYWxlYm8gKmF0dGVuZGFuY2VfcGVyY2VudCouCgpKZWRlbiBhxb4gZHZhIGJvZHkgc2EgdsWhYWsgbWllcm5lIG9kZGXEvnVqw7ogb2Qgb3N0YXRuw71jaCAobmFwci4gdiBvYmxhc3RpCnDDoWtvdsOpaG8gZWZla3R1IG9rb2xvIDAsMikuXApJZGUgbyBwb3pvcm92YW5pYSBzbyAqKnp2w73FoWVub3UgcMOha291KiosIHRlZGEgaWNoIGhvZG5vdHkgcHJlZGlrdG9yb3Ygc8O6CsSPYWxlaiBvZCB2w6TEjcWhaW55IMO6ZGFqb3Yg4oCUIG5hcHLDrWtsYWQgxaF0dWRlbnQgcyBleHRyw6ltbmUgbsOtemt5bSBwb8SNdG9tCmhvZMOtbiBzcMOhbmt1IGFsZWJvIHZlxL5taSB2eXNva8O9bSBwb8SNdG9tIGhvZMOtbiDFoXTDumRpYS4KClbDpMSNxaFpbmEgxaF0YW5kYXJkaXpvdmFuw71jaCByZXrDrWR1w60gc2EgbmFjaMOhZHphIG1lZHppIGhvZG5vdGFtaSAqKuKIkjIgYQorMioqLCDEjW8gem5hbWVuw6EsIMW+ZSBuZWV4aXN0dWrDuiDFvmlhZG5lIHrDoXZhxb5uw6kgb2TEvmFobMOpIGhvZG5vdHkgdgp6w6F2aXNsZWogcHJlbWVubmVqICgqZXhhbV9zY29yZSopLgoKS29udMO6cnkgQ29va292ZWogdnpkaWFsZW5vc3RpIHVrYXp1asO6LCDFvmUgxb5pYWRlbiB6IGJvZG92ICoqbmVwcmVrcmHEjXVqZQpocmFuaWNlIDAsNSDEjWkgMSwwKiosXApwcmV0byAqKsW+aWFkbmUgcG96b3JvdmFuaWUgbmVtw6EgdsO9cmF6bmUgbmVwcmltZXJhbsO9IHZwbHl2KiogbmEgb2RoYWR5CnJlZ3Jlc27DvWNoIGtvZWZpY2llbnRvdi4KCkNlbGtvdm8gbW/Fvm5vIGtvbsWhdGF0b3ZhxaUsIMW+ZSBtb2RlbCBuaWUgamUgY2l0bGl2w70gbmEgamVkbm90bGl2w6kKcG96b3JvdmFuaWEgYSBuaWUgc8O6IHByw610b21uw6kgZXh0csOpbW5lIHZwbHl2bsOpIGJvZHksIGt0b3LDqSBieSBtb2hsaQpza3Jlc8S+b3ZhxaUgdsO9c2xlZGt5IHJlZ3Jlc2llLgoKIyMgQ29uY2x1c2lvbgoKUHJlbWVubsOpICpob3Vyc19zdHVkaWVkKiBhICphdHRlbmRhbmNlX3BlcmNlbnQqIG1hasO6ICoqxaF0YXRpc3RpY2t5CnbDvXpuYW1uw70gcG96aXTDrXZueSB2cGx5dioqIG5hIHbDvXNsZWRuw6kgc2vDusWha292w6kgc2vDs3JlIMWhdHVkZW50b3Yg4oCTIHRlZGEKxI3DrW0gdmlhYyDEjWFzdSDFoXR1ZGVudCB2ZW51amUgxaF0w7pkaXUgYSDEjcOtbSBwcmF2aWRlbG5lasWhaWUgc2EgesO6xI1hc3TFiHVqZQp2eXXEjW92YW5pYSwgdMO9bSB2ecWhxaFpZSBza8OzcmUgZG9zYWh1amUuCgpQcmVtZW5uw6EgKnNsZWVwX2hvdXJzKiBzYSB1a8OhemFsYSBha28gKiptZW5laiB2w716bmFtbsOhKiosIHByacSNb20gamVqCnZwbHl2IG5hIHbDvXNsZWRvayBza8O6xaFreSBuZWJvbCBqZWRub3puYcSNbsO9IOKAkyB2IG1vZGVsaSBzYSBwcmVqYXZ1amUgcwptYWzDvW0gYWxlYm8gbmVpbnRlcnByZXRvdmF0ZcS+bsO9bSDDusSNaW5rb20uCgpSZXrDrWR1w6EgbmV2eWthenVqw7ogw7pwbG5lIGRva29uYWzDqSBub3Jtw6FsbmUgcm96ZGVsZW5pZSwgYXbFoWFrIHZ6aMS+YWRvbSBuYQpkb3N0YXRvxI1uZSB2ZcS+a8O9IHBvxI1ldCBwb3pvcm92YW7DrSBtw7TFvmVtZSBtb2RlbCBwb3Zhxb5vdmHFpSB6YSBzcG/EvmFobGl2w70gYQp2aG9kbsO9IG5hIGludGVycHJldMOhY2l1LgoKWiBkaWFnbm9zdGlja8O9Y2ggZ3JhZm92IHRha3RpZcW+IHZ5cGzDvXZhLCDFvmUgKip2IG1vZGVsaSBzYSBuZXByZXVrYXp1asO6CsW+aWFkbmUgdsO9cmF6bsOpIG5lbGluZWFyaXR5LCBoZXRlcm9za2VkYXN0aWNpdGEgYW5pIHZwbHl2bsOpCnBvem9yb3ZhbmlhKiouXApNb2RlbCB0ZWRhIHBvbWVybmUgZG9icmUgdnlzdGlodWplIHZ6xaVhaCBtZWR6aSDFoXR1ZGlqbsO9bWkgbsOhdnlrbWkgYQp2w71zbGVkbsO9bSBza8O6xaFrb3bDvW0gc2vDs3JlLgo=