library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)

rm(list = ls())

Pokračujeme v predchádzajúcich úlohách, kde s pomocou regresie skúmame, nakoľko je počet obyvateľov v obci na konci roka 2024 (stav v decembri 2024) ovplyvnený počtom obyvateľov:

Pracujeme teda s prierezovými dátami za obce Slovenska, pričom za každú obec máme stav obyvateľov v jednotlivých mesiacoch roka 2024. Výsledok základnej regresie je uvedený nižšie.


#######################################################################
# PRÍPRAVA ÚDAJOV
#######################################################################

# načítame databázu (tvoj súbor Databaza.csv)
# check.names = FALSE zabezpečí, že stĺpce zostanú pomenované 2024M12, 2024M01 atď.
udaje_raw <- read.csv("Databaza.csv", dec = ".", sep = ";", header = TRUE,
                      check.names = FALSE)

# skontrolujeme štruktúru
str(udaje_raw)
'data.frame':   200 obs. of  14 variables:
 $ Okres  : chr  "Okres Bratislava I" "Okres Bratislava II" "Okres Bratislava II" "Okres Bratislava II" ...
 $ Obec   : chr  "Bratislava - mestská časť Staré Mesto" "Bratislava - m. č. Podunajské Biskupice" "Bratislava - mestská časť Ružinov" "Bratislava - mestská časť Vrakuňa" ...
 $ 2024M12: int  47634 23095 83365 20172 45539 26481 6050 17065 35538 34815 ...
 $ 2024M11: int  47632 23110 83251 20161 45480 26466 6052 17071 35575 34831 ...
 $ 2024M10: int  47565 23130 83192 20159 45444 26429 6045 17040 35579 34816 ...
 $ 2024M09: int  47564 23132 83163 20162 45455 26432 6049 17036 35636 34788 ...
 $ 2024M08: int  47525 23137 83137 20161 45442 26430 6040 17027 35649 34748 ...
 $ 2024M07: int  47488 23147 83056 20190 45442 26394 6036 17021 35627 34782 ...
 $ 2024M06: int  47503 23162 82867 20216 45411 26376 6030 16999 35633 34812 ...
 $ 2024M05: int  47484 23178 82789 20211 45376 26346 6024 17005 35624 34843 ...
 $ 2024M04: int  47411 23179 82641 20227 45414 26291 6031 17027 35600 34854 ...
 $ 2024M03: int  47408 23201 82612 20209 45439 26245 6034 17007 35575 34899 ...
 $ 2024M02: int  47391 23226 82553 20196 45410 26231 6037 17030 35570 34924 ...
 $ 2024M01: int  47375 23276 82483 20221 45342 26214 6038 17067 35572 34942 ...
head(udaje_raw)

# Vytvoríme si premenné pre jednotlivé mesiace, s ktorými budeme pracovať v modeli:
# obyv_12 – počet obyvateľov v decembri 2024 (vysvetľovaná premenná)
# obyv_01 – počet obyvateľov v januári 2024
# obyv_06 – počet obyvateľov v júni 2024
# obyv_09 – počet obyvateľov v septembri 2024

udaje <- within(udaje_raw, {
  obyv_12 <- `2024M12`
  obyv_01 <- `2024M01`
  obyv_06 <- `2024M06`
  obyv_09 <- `2024M09`
})

# vyberieme len premenné, ktoré idú do modelu
udaje_model <- udaje[, c("obyv_12", "obyv_01", "obyv_06", "obyv_09")]

# (prípadná) imputácia chýbajúcich hodnôt – v našej databáze zrejme chýbajúce údaje nie sú,
# ale pre ukážku ponecháme postup s doplnením mediánov
column_medians <- sapply(udaje_model, median, na.rm = TRUE)

udaje_imputed <- udaje_model
for (col in names(udaje_model)) {
  udaje_imputed[[col]][is.na(udaje_imputed[[col]])] <- column_medians[col]
}

udaje <- udaje_imputed
str(udaje)
'data.frame':   200 obs. of  4 variables:
 $ obyv_12: num  47634 23095 83365 20172 45539 ...
 $ obyv_01: num  47375 23276 82483 20221 45342 ...
 $ obyv_06: num  47503 23162 82867 20216 45411 ...
 $ obyv_09: num  47564 23132 83163 20162 45455 ...

Základná regresia

V základnom modeli predpokladáme, že počet obyvateľov v obci v decembri 2024 je lineárne vysvetlený počtom obyvateľov v januári, júni a septembri:

\[ \text{obyv\_12}_i = \beta_0 + \beta_1 \text{obyv\_01}_i + \beta_2 \text{obyv\_06}_i + \beta_3 \text{obyv\_09}_i + u_i \]

kde index \(i\) označuje obec.

#######################################################################
# ZÁKLADNÁ REGRESIA
#######################################################################
attach(udaje)

model <- lm(obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09, data = udaje)
summary(model)

Call:
lm(formula = obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09, data = udaje)

Residuals:
     Min       1Q   Median       3Q      Max 
-118.937   -4.211    0.368    5.820   41.782 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.34570    1.10739  -0.312 0.755242    
obyv_01     -0.11970    0.03708  -3.228 0.001459 ** 
obyv_06     -0.34533    0.09994  -3.455 0.000673 ***
obyv_09      1.46539    0.06681  21.934  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 14.26 on 196 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 4.588e+07 on 3 and 196 DF,  p-value: < 2.2e-16

Interpretácia: koeficienty pri premenných obyv_01, obyv_06 a obyv_09 hovoria, o koľko sa v priemere zmení počet obyvateľov v decembri, ak sa daná vysvetľujúca premenná zvýši o jednu osobu (pri ostatných premenných nezmenených).


1. Test RESET (test špecifikácie funkčnej formy)

Chceme otestovať, či je lineárna špecifikácia vhodná, t. j. či medzi premennými nie je výraznejší nelineárny vzťah, ktorý by sme mali zachytiť pomocou transformácií (napr. kvadratické členy, logaritmy).

Základný model:

\[ y_i = \beta_0 + \beta_1 x_{1i} + \dots + \beta_k x_{ki} + u_i \]

Ak je model správne špecifikovaný, pridaním mocnín vyrovnaných hodnôt (napr. \(\hat{y}_i^2\), \(\hat{y}_i^3\)) by sa model nemal štatisticky významne zlepšiť. RESET test formálne testuje:

#######################################################################
# RESET TEST
#######################################################################
library(lmtest)
resettest(model)

    RESET test

data:  model
RESET = 8.0852, df1 = 2, df2 = 194, p-value = 0.000424

Interpretácia:
Ak p-hodnota < 0,05, zamietame \(H_0\) a usudzujeme, že lineárny model môže byť nesprávne špecifikovaný – buď chýbajú niektoré vysvetľujúce premenné, alebo je potrebná nelineárna transformácia premenných.
Ak p-hodnota ≥ 0,05, nemáme dôvod tvrdiť, že je špecifikácia modelu nevhodná.


2. Grafická analýza

Graf Residuals vs. Fitted

Graf rezíduí voči vyrovnaným hodnotám nám pomáha odhaliť nelinearity, heteroskedasticitu či iné systematické vzory v rezíduách.

plot(model, which = 1)

Ak rezíduá vykazujú nenáhodný vzor (napr. zakrivenie), lineárna špecifikácia môže byť nevhodná a má zmysel uvažovať o transformácii niektorej premennej alebo o zaradení ďalšej premennej.

Grafy C+R (Component + Residual Plots)

Tieto grafy nám pomáhajú odhadnúť, pri ktorej vysvetľujúcej premennej by mohol byť vzťah s vysvetľovanou premennou nelineárny.

car::crPlots(model)

Vertikálna os zobrazuje hodnoty typu \(\hat{\beta}_i x_{i} + e_i\), horizontálna os zobrazuje hodnotu príslušnej vysvetľujúcej premennej.

Ak sa hladká krivka (lokálna aproximácia) výrazne odchyľuje od priamky, zvážime transformáciu danej premennej (napr. kvadratický člen, logaritmus a pod.). V našom prípade nás môžu zaujímať najmä premené obyv_06 (počet obyvateľov v júni) a obyv_09 (počet obyvateľov v septembri), ak sa pri nich objavuje výraznejšie zakrivenie.


3. Nelineárna špecifikácia

Často môžeme nelineárne vzťahy približovať pomocou polynómov. V prípade kvadratických členov má model tvar:

\[ y_i = \beta_0 + \beta_1 x_{1i} + \dots + \beta_k x_{ki} + \gamma_i x_{ki}^2 + u_i \]

V našom príklade môžeme zaradiť kvadrát niektorých mesačných stavov obyvateľov, napríklad obyv_06 (jún) a obyv_09 (september).


4. Porovnanie základného a modifikovaného modelu

Predpokladajme, že podľa C+R grafov sa rozhodneme pridať kvadrát premenných obyv_06 a obyv_09. Náš rozšírený model bude:

#######################################################################
# MODELY S KVADRATICKÝMI ČLENMI
#######################################################################
model_linear <- lm(obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09)

model_kvadr <- lm(obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09 +
                    I(obyv_06^2) + I(obyv_09^2))

summary(model_kvadr)

Call:
lm(formula = obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09 + I(obyv_06^2) + 
    I(obyv_09^2))

Residuals:
     Min       1Q   Median       3Q      Max 
-108.896   -4.359   -0.382    5.112   57.656 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   1.075e+00  1.189e+00   0.904 0.366992    
obyv_01      -1.471e-01  3.627e-02  -4.056 7.21e-05 ***
obyv_06      -4.099e-01  1.127e-01  -3.637 0.000353 ***
obyv_09       1.557e+00  8.553e-02  18.201  < 2e-16 ***
I(obyv_06^2)  9.685e-07  4.695e-07   2.063 0.040454 *  
I(obyv_09^2) -9.601e-07  4.699e-07  -2.043 0.042392 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 13.62 on 194 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 3.017e+07 on 5 and 194 DF,  p-value: < 2.2e-16
anova(model_linear, model_kvadr)
Analysis of Variance Table

Model 1: obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09
Model 2: obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09 + I(obyv_06^2) + I(obyv_09^2)
  Res.Df   RSS Df Sum of Sq      F    Pr(>F)    
1    196 39873                                  
2    194 36013  2    3859.6 10.396 5.142e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
resettest(model_kvadr)

    RESET test

data:  model_kvadr
RESET = 12.357, df1 = 2, df2 = 192, p-value = 8.949e-06

Porovnávame:

Ak rozšírený model vykazuje vyšší \(R^2_{adj}\), ANOVA test je významný a RESET test poukazuje na lepšiu špecifikáciu, môžeme kvadratické členy považovať za vhodné.

Ak by napríklad kvadrát jednej premennej vyšiel štatisticky nevýznamný, môžeme model zjednodušiť a ponechať len tie kvadratické členy, ktoré zlepšujú štatistické vlastnosti modelu.

# Príklad zjednodušenia – ponechajme len kvadrát obyv_06
model_kvadr_simple <- lm(obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09 +
                           I(obyv_06^2))
summary(model_kvadr_simple)

Call:
lm(formula = obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09 + I(obyv_06^2))

Residuals:
     Min       1Q   Median       3Q      Max 
-108.106   -4.552   -0.013    5.115   57.819 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   1.604e+00  1.170e+00   1.370  0.17217    
obyv_01      -1.508e-01  3.652e-02  -4.128 5.42e-05 ***
obyv_06      -2.906e-01  9.719e-02  -2.990  0.00315 ** 
obyv_09       1.441e+00  6.462e-02  22.300  < 2e-16 ***
I(obyv_06^2)  9.292e-09  2.298e-09   4.044 7.58e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 13.74 on 195 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 3.711e+07 on 4 and 195 DF,  p-value: < 2.2e-16

5. Rozšírený model s kvadratickými členmi

Môžeme ešte skúsiť systematickejšiu rozšírenú špecifikáciu, kde pridáme kvadratické členy ku všetkým vysvetľujúcim premenným:

#######################################################################
# ROZŠÍRENÝ MODEL S VIACERÝMI KVADRATICKÝMI ČLENMI
#######################################################################
model_rozsireny <- lm(obyv_12 ~ obyv_01 + obyv_06 + obyv_09 +
                        I(obyv_01^2) + I(obyv_06^2) + I(obyv_09^2))

summary(model_rozsireny)

Call:
lm(formula = obyv_12 ~ obyv_01 + obyv_06 + obyv_09 + I(obyv_01^2) + 
    I(obyv_06^2) + I(obyv_09^2))

Residuals:
    Min      1Q  Median      3Q     Max 
-93.720  -4.850   0.383   5.847  56.068 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   1.625e-02  1.183e+00   0.014 0.989049    
obyv_01      -3.015e-01  5.350e-02  -5.636 6.09e-08 ***
obyv_06      -3.479e-02  1.466e-01  -0.237 0.812710    
obyv_09       1.336e+00  1.008e-01  13.258  < 2e-16 ***
I(obyv_01^2)  5.639e-06  1.476e-06   3.821 0.000179 ***
I(obyv_06^2) -1.306e-05  3.699e-06  -3.530 0.000519 ***
I(obyv_09^2)  7.418e-06  2.239e-06   3.313 0.001102 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 13.17 on 193 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 2.69e+07 on 6 and 193 DF,  p-value: < 2.2e-16
anova(model_linear, model_rozsireny)
Analysis of Variance Table

Model 1: obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09
Model 2: obyv_12 ~ obyv_01 + obyv_06 + obyv_09 + I(obyv_01^2) + I(obyv_06^2) + 
    I(obyv_09^2)
  Res.Df   RSS Df Sum of Sq      F    Pr(>F)    
1    196 39873                                  
2    193 33480  3    6392.6 12.284 2.172e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
resettest(model_rozsireny)

    RESET test

data:  model_rozsireny
RESET = 15.208, df1 = 2, df2 = 191, p-value = 7.436e-07

Tu sledujeme, či kvadratické členy vychádzajú štatisticky významné a či ANOVA test ukáže štatisticky významné zlepšenie oproti pôvodnému lineárnemu modelu. Výsledok RESET testu nám zároveň napovie, či aj po týchto úpravách zostáva problém nesprávnej špecifikácie.


6. Transformácia pomocou dummy premennej a lineárnej lomenej funkcie

Predpokladajme, že podľa C+R grafu pri premennej obyv_06 (počet obyvateľov v júni) vidíme, že pre menšie obce a väčšie obce môže byť vzťah odlišný – teda pre určité „kritické“ veľkosti obcí sa mení sklon.

Zaveďme dummy premennú:

\[ DUM_i = \begin{cases} 1, & \text{ak obec má v júni viac ako 10\,000 obyvateľov}, \\ 0, & \text{inak}. \end{cases} \]

Pomocou tejto premennej môžeme modelovať:

  1. Zlom v autonómnom člene – posun regresnej nadroviny medzi menšími a väčšími obcami.
  2. Zlom v sklone – odlišný vplyv júnového počtu obyvateľov na december podľa veľkosti obce.
#######################################################################
# DUMMY PREMENNÁ A LOMENÁ FUNKCIA
#######################################################################

# definujeme dummy podľa júnového stavu – hranica 10 000 obyvateľov je ilustračná
DUM <- ifelse(obyv_06 > 10000, 1, 0)
udaje$DUM <- DUM

# Model so zlomom v autonómnom člene
modelD_auto <- lm(obyv_12 ~ 1 + DUM + obyv_01 + obyv_06 + obyv_09, data = udaje)
summary(modelD_auto)

Call:
lm(formula = obyv_12 ~ 1 + DUM + obyv_01 + obyv_06 + obyv_09, 
    data = udaje)

Residuals:
     Min       1Q   Median       3Q      Max 
-115.108   -4.408    0.171    5.410   46.743 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -0.24123    1.08877  -0.222 0.824885    
DUM         -13.85798    4.90100  -2.828 0.005180 ** 
obyv_01      -0.12770    0.03654  -3.495 0.000588 ***
obyv_06      -0.31432    0.09881  -3.181 0.001708 ** 
obyv_09       1.44264    0.06614  21.812  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 14.02 on 195 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 3.564e+07 on 4 and 195 DF,  p-value: < 2.2e-16
# Model so zlomom v sklone (interakcia DUM * obyv_06)
modelD_sklon <- lm(obyv_12 ~ 1 + obyv_01 + obyv_06 + I(DUM * obyv_06) + obyv_09,
                   data = udaje)
summary(modelD_sklon)

Call:
lm(formula = obyv_12 ~ 1 + obyv_01 + obyv_06 + I(DUM * obyv_06) + 
    obyv_09, data = udaje)

Residuals:
     Min       1Q   Median       3Q      Max 
-119.941   -3.962    0.428    5.884   41.831 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)       0.6221606  1.5304139   0.407 0.684798    
obyv_01          -0.1257484  0.0376748  -3.338 0.001012 ** 
obyv_06          -0.3363435  0.1004595  -3.348 0.000977 ***
I(DUM * obyv_06)  0.0005266  0.0005745   0.917 0.360462    
obyv_09           1.4619095  0.0669453  21.837  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 14.27 on 195 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 3.438e+07 on 4 and 195 DF,  p-value: < 2.2e-16
anova(model_linear, modelD_sklon)
Analysis of Variance Table

Model 1: obyv_12 ~ 1 + obyv_01 + obyv_06 + obyv_09
Model 2: obyv_12 ~ 1 + obyv_01 + obyv_06 + I(DUM * obyv_06) + obyv_09
  Res.Df   RSS Df Sum of Sq      F Pr(>F)
1    196 39873                           
2    195 39702  1    171.07 0.8402 0.3605
resettest(modelD_sklon)

    RESET test

data:  modelD_sklon
RESET = 7.9324, df1 = 2, df2 = 193, p-value = 0.000489

Interpretácia:

Ak ANOVA test medzi model_linear a modelD_sklon vyjde štatisticky významný a interakčný člen je významný, môžeme usúdiť, že zavedenie zlomu v sklone zlepšilo model.


7. Box–Coxov transformačný test

Box–Coxov test nám pomáha rozhodnúť, či je vhodné transformovať vysvetľovanú premennú (u nás obyv_12), napríklad pomocou logaritmu, odmocniny alebo reciproka.

#######################################################################
# BOX–COXOVA TRANSFORMÁCIA
#######################################################################
library(MASS)
boxcox(model_linear)

Interpretácia:

Predpokladajme, že Box–Coxov test naznačí nejakú hodnotu \(\lambda\); ilustračné nastavenie:

# Ilustračná transformácia s lambda = 0.5 (odmocnina), ak by nám to Box–Cox odporučil
model_lambda <- lm(I((obyv_12^0.5 - 1) / 0.5) ~ 1 + obyv_01 + obyv_06 + obyv_09,
                   data = udaje)
summary(model_lambda)

Call:
lm(formula = I((obyv_12^0.5 - 1)/0.5) ~ 1 + obyv_01 + obyv_06 + 
    obyv_09, data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-175.16  -21.13   -4.00   16.55   98.26 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 69.71777    2.51086  27.766  < 2e-16 ***
obyv_01     -0.26908    0.08407  -3.201  0.00160 ** 
obyv_06      0.60113    0.22660   2.653  0.00864 ** 
obyv_09     -0.32490    0.15148  -2.145  0.03320 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 32.34 on 196 degrees of freedom
Multiple R-squared:  0.8732,    Adjusted R-squared:  0.8712 
F-statistic: 449.7 on 3 and 196 DF,  p-value: < 2.2e-16
resettest(model_lambda)

    RESET test

data:  model_lambda
RESET = 857.29, df1 = 2, df2 = 194, p-value < 2.2e-16

Pri porovnávaní s pôvodným modelom sledujeme zmenu \(R^2_{adj}\) a výsledok RESET testu. Ak síce dôjde k malej zmene \(R^2_{adj}\), ale výrazne sa skomplikuje interpretácia (už nepracujeme priamo s počtom obyvateľov, ale s transformáciou), v praktických aplikáciách sa často preferuje jednoduchší model, pokiaľ štatisticky „stačí“.

LS0tCnRpdGxlOiAixaBwZWNpZmlrw6FjaWEgbW9kZWx1IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiAiRmlsaXAgSnVya8OhxI1layIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHpvbykKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGxtdGVzdCkKbGlicmFyeShzYW5kd2ljaCkKbGlicmFyeShjYXIpCgpybShsaXN0ID0gbHMoKSkKYGBgCgpQb2tyYcSNdWplbWUgdiBwcmVkY2jDoWR6YWrDumNpY2ggw7psb2jDoWNoLCBrZGUgcyBwb21vY291IHJlZ3Jlc2llIHNrw7ptYW1lLCBuYWtvxL5rbyBqZSAqKnBvxI1ldCBvYnl2YXRlxL5vdiB2IG9iY2kgbmEga29uY2kgcm9rYSAyMDI0KiogKHN0YXYgdiBkZWNlbWJyaSAyMDI0KSBvdnBseXZuZW7DvSBwb8SNdG9tIG9ieXZhdGXEvm92OgoKLSBuYSB6YcSNaWF0a3Ugcm9rYSAoamFudcOhciAyMDI0KSwKLSB2IHBvbG92aWNpIHJva2EgKGrDum4gMjAyNCksCi0gbmEgemHEjWlhdGt1IGplc2VuZSAoc2VwdGVtYmVyIDIwMjQpLgoKUHJhY3VqZW1lIHRlZGEgcyAqKnByaWVyZXpvdsO9bWkgZMOhdGFtaSB6YSBvYmNlIFNsb3ZlbnNrYSoqLCBwcmnEjW9tIHphIGthxb5kw7ogb2JlYyBtw6FtZSBzdGF2IG9ieXZhdGXEvm92IHYgamVkbm90bGl2w71jaCBtZXNpYWNvY2ggcm9rYSAyMDI0LiBWw71zbGVkb2sgesOha2xhZG5laiByZWdyZXNpZSBqZSB1dmVkZW7DvSBuacW+xaFpZS4KCi0tLQoKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgUFLDjVBSQVZBIMOaREFKT1YKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgbmHEjcOtdGFtZSBkYXRhYsOhenUgKHR2b2ogc8O6Ym9yIERhdGFiYXphLmNzdikKIyBjaGVjay5uYW1lcyA9IEZBTFNFIHphYmV6cGXEjcOtLCDFvmUgc3TEunBjZSB6b3N0YW7DuiBwb21lbm92YW7DqSAyMDI0TTEyLCAyMDI0TTAxIGF0xI8uCnVkYWplX3JhdyA8LSByZWFkLmNzdigiRGF0YWJhemEuY3N2IiwgZGVjID0gIi4iLCBzZXAgPSAiOyIsIGhlYWRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBjaGVjay5uYW1lcyA9IEZBTFNFKQoKIyBza29udHJvbHVqZW1lIMWhdHJ1a3TDunJ1CnN0cih1ZGFqZV9yYXcpCmhlYWQodWRhamVfcmF3KQoKIyBWeXR2b3LDrW1lIHNpIHByZW1lbm7DqSBwcmUgamVkbm90bGl2w6kgbWVzaWFjZSwgcyBrdG9yw71taSBidWRlbWUgcHJhY292YcWlIHYgbW9kZWxpOgojIG9ieXZfMTIg4oCTIHBvxI1ldCBvYnl2YXRlxL5vdiB2IGRlY2VtYnJpIDIwMjQgKHZ5c3ZldMS+b3ZhbsOhIHByZW1lbm7DoSkKIyBvYnl2XzAxIOKAkyBwb8SNZXQgb2J5dmF0ZcS+b3YgdiBqYW51w6FyaSAyMDI0CiMgb2J5dl8wNiDigJMgcG/EjWV0IG9ieXZhdGXEvm92IHYgasO6bmkgMjAyNAojIG9ieXZfMDkg4oCTIHBvxI1ldCBvYnl2YXRlxL5vdiB2IHNlcHRlbWJyaSAyMDI0Cgp1ZGFqZSA8LSB3aXRoaW4odWRhamVfcmF3LCB7CiAgb2J5dl8xMiA8LSBgMjAyNE0xMmAKICBvYnl2XzAxIDwtIGAyMDI0TTAxYAogIG9ieXZfMDYgPC0gYDIwMjRNMDZgCiAgb2J5dl8wOSA8LSBgMjAyNE0wOWAKfSkKCiMgdnliZXJpZW1lIGxlbiBwcmVtZW5uw6ksIGt0b3LDqSBpZMO6IGRvIG1vZGVsdQp1ZGFqZV9tb2RlbCA8LSB1ZGFqZVssIGMoIm9ieXZfMTIiLCAib2J5dl8wMSIsICJvYnl2XzA2IiwgIm9ieXZfMDkiKV0KCiMgKHByw61wYWRuw6EpIGltcHV0w6FjaWEgY2jDvWJhasO6Y2ljaCBob2Ruw7R0IOKAkyB2IG5hxaFlaiBkYXRhYsOhemUgenJlam1lIGNow71iYWrDumNlIMO6ZGFqZSBuaWUgc8O6LAojIGFsZSBwcmUgdWvDocW+a3UgcG9uZWNow6FtZSBwb3N0dXAgcyBkb3BsbmVuw61tIG1lZGnDoW5vdgpjb2x1bW5fbWVkaWFucyA8LSBzYXBwbHkodWRhamVfbW9kZWwsIG1lZGlhbiwgbmEucm0gPSBUUlVFKQoKdWRhamVfaW1wdXRlZCA8LSB1ZGFqZV9tb2RlbApmb3IgKGNvbCBpbiBuYW1lcyh1ZGFqZV9tb2RlbCkpIHsKICB1ZGFqZV9pbXB1dGVkW1tjb2xdXVtpcy5uYSh1ZGFqZV9pbXB1dGVkW1tjb2xdXSldIDwtIGNvbHVtbl9tZWRpYW5zW2NvbF0KfQoKdWRhamUgPC0gdWRhamVfaW1wdXRlZApzdHIodWRhamUpCmBgYAoKLS0tCgojIyMgWsOha2xhZG7DoSByZWdyZXNpYQoKViB6w6FrbGFkbm9tIG1vZGVsaSBwcmVkcG9rbGFkw6FtZSwgxb5lIHBvxI1ldCBvYnl2YXRlxL5vdiB2IG9iY2kgdiBkZWNlbWJyaSAyMDI0IGplIGxpbmXDoXJuZSB2eXN2ZXRsZW7DvSBwb8SNdG9tIG9ieXZhdGXEvm92IHYgamFudcOhcmksIGrDum5pIGEgc2VwdGVtYnJpOgoKXFsKXHRleHR7b2J5dlxfMTJ9X2kgPSBcYmV0YV8wICsgXGJldGFfMSBcdGV4dHtvYnl2XF8wMX1faSArIFxiZXRhXzIgXHRleHR7b2J5dlxfMDZ9X2kgKyBcYmV0YV8zIFx0ZXh0e29ieXZcXzA5fV9pICsgdV9pClxdCgprZGUgaW5kZXggXChpXCkgb3puYcSNdWplIG9iZWMuCgpgYGB7cn0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBaw4FLTEFETsOBIFJFR1JFU0lBCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmF0dGFjaCh1ZGFqZSkKCm1vZGVsIDwtIGxtKG9ieXZfMTIgfiAxICsgb2J5dl8wMSArIG9ieXZfMDYgKyBvYnl2XzA5LCBkYXRhID0gdWRhamUpCnN1bW1hcnkobW9kZWwpCmBgYAoKSW50ZXJwcmV0w6FjaWE6IGtvZWZpY2llbnR5IHByaSBwcmVtZW5uw71jaCBgb2J5dl8wMWAsIGBvYnl2XzA2YCBhIGBvYnl2XzA5YCBob3ZvcmlhLCBvIGtvxL5rbyBzYSB2IHByaWVtZXJlIHptZW7DrSBwb8SNZXQgb2J5dmF0ZcS+b3YgdiBkZWNlbWJyaSwgYWsgc2EgZGFuw6EgdnlzdmV0xL51asO6Y2EgcHJlbWVubsOhIHp2w73FoWkgbyBqZWRudSBvc29idSAocHJpIG9zdGF0bsO9Y2ggcHJlbWVubsO9Y2ggbmV6bWVuZW7DvWNoKS4KCi0tLQoKIyMgMS4gVGVzdCBSRVNFVCAodGVzdCDFoXBlY2lmaWvDoWNpZSBmdW5rxI1uZWogZm9ybXkpCgpDaGNlbWUgb3Rlc3RvdmHFpSwgxI1pIGplIGxpbmXDoXJuYSDFoXBlY2lmaWvDoWNpYSB2aG9kbsOhLCB0LiBqLiDEjWkgbWVkemkgcHJlbWVubsO9bWkgbmllIGplIHbDvXJhem5lasWhw60gbmVsaW5lw6FybnkgdnrFpWFoLCBrdG9yw70gYnkgc21lIG1hbGkgemFjaHl0acWlIHBvbW9jb3UgdHJhbnNmb3Jtw6FjacOtIChuYXByLiBrdmFkcmF0aWNrw6kgxI1sZW55LCBsb2dhcml0bXkpLgoKWsOha2xhZG7DvSBtb2RlbDoKClxbCnlfaSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfezFpfSArIFxkb3RzICsgXGJldGFfayB4X3traX0gKyB1X2kKXF0KCkFrIGplIG1vZGVsIHNwcsOhdm5lIMWhcGVjaWZpa292YW7DvSwgcHJpZGFuw61tIG1vY27DrW4gdnlyb3ZuYW7DvWNoIGhvZG7DtHQgKG5hcHIuIFwoXGhhdHt5fV9pXjJcKSwgXChcaGF0e3l9X2leM1wpKSBieSBzYSBtb2RlbCBuZW1hbCDFoXRhdGlzdGlja3kgdsO9em5hbW5lIHpsZXDFoWnFpS4gUkVTRVQgdGVzdCBmb3Jtw6FsbmUgdGVzdHVqZToKCi0gXChIXzBcKTogbW9kZWwgamUgc3Byw6F2bmUgxaFwZWNpZmlrb3ZhbsO9LAotIFwoSF8xXCk6IG1vZGVsIGplIG5lc3Byw6F2bmUgxaFwZWNpZmlrb3ZhbsO9IChjaHliw60gbmVsaW5lYXJpdGEgYWxlYm8gxI9hbMWhaWUgcHJlbWVubsOpKS4KCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFJFU0VUIFRFU1QKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKbGlicmFyeShsbXRlc3QpCnJlc2V0dGVzdChtb2RlbCkKYGBgCgoqKkludGVycHJldMOhY2lhOioqICAKQWsgcC1ob2Rub3RhIFw8IDAsMDUsIHphbWlldGFtZSBcKEhfMFwpIGEgdXN1ZHp1amVtZSwgxb5lIGxpbmXDoXJueSBtb2RlbCBtw7TFvmUgYnnFpSBuZXNwcsOhdm5lIMWhcGVjaWZpa292YW7DvSDigJMgYnXEjyBjaMO9YmFqw7ogbmlla3RvcsOpIHZ5c3ZldMS+dWrDumNlIHByZW1lbm7DqSwgYWxlYm8gamUgcG90cmVibsOhIG5lbGluZcOhcm5hIHRyYW5zZm9ybcOhY2lhIHByZW1lbm7DvWNoLiAgCkFrIHAtaG9kbm90YSDiiaUgMCwwNSwgbmVtw6FtZSBkw7R2b2QgdHZyZGnFpSwgxb5lIGplIMWhcGVjaWZpa8OhY2lhIG1vZGVsdSBuZXZob2Ruw6EuCgotLS0KCiMjIDIuIEdyYWZpY2vDoSBhbmFsw716YQoKIyMjIEdyYWYgKlJlc2lkdWFscyB2cy4gRml0dGVkKgoKR3JhZiByZXrDrWR1w60gdm/EjWkgdnlyb3ZuYW7DvW0gaG9kbm90w6FtIG7DoW0gcG9tw6FoYSBvZGhhbGnFpSBuZWxpbmVhcml0eSwgaGV0ZXJvc2tlZGFzdGljaXR1IMSNaSBpbsOpIHN5c3RlbWF0aWNrw6kgdnpvcnkgdiByZXrDrWR1w6FjaC4KCmBgYHtyfQpwbG90KG1vZGVsLCB3aGljaCA9IDEpCmBgYAoKQWsgcmV6w61kdcOhIHZ5a2F6dWrDuiBuZW7DoWhvZG7DvSB2em9yIChuYXByLiB6YWtyaXZlbmllKSwgbGluZcOhcm5hIMWhcGVjaWZpa8OhY2lhIG3DtMW+ZSBiecWlIG5ldmhvZG7DoSBhIG3DoSB6bXlzZWwgdXZhxb5vdmHFpSBvIHRyYW5zZm9ybcOhY2lpIG5pZWt0b3JlaiBwcmVtZW5uZWogYWxlYm8gbyB6YXJhZGVuw60gxI9hbMWhZWogcHJlbWVubmVqLgoKIyMjIEdyYWZ5IEMrUiAoQ29tcG9uZW50ICsgUmVzaWR1YWwgUGxvdHMpCgpUaWV0byBncmFmeSBuw6FtIHBvbcOhaGFqw7ogb2RoYWRuw7rFpSwgcHJpIGt0b3JlaiB2eXN2ZXTEvnVqw7pjZWogcHJlbWVubmVqIGJ5IG1vaG9sIGJ5xaUgdnrFpWFoIHMgdnlzdmV0xL5vdmFub3UgcHJlbWVubm91IG5lbGluZcOhcm55LgoKYGBge3J9CmNhcjo6Y3JQbG90cyhtb2RlbCkKYGBgCgpWZXJ0aWvDoWxuYSBvcyB6b2JyYXp1amUgaG9kbm90eSB0eXB1IFwoXGhhdHtcYmV0YX1faSB4X3tpfSArIGVfaVwpLCBob3Jpem9udMOhbG5hIG9zIHpvYnJhenVqZSBob2Rub3R1IHByw61zbHXFoW5laiB2eXN2ZXTEvnVqw7pjZWogcHJlbWVubmVqLiAgCgpBayBzYSBobGFka8OhIGtyaXZrYSAobG9rw6FsbmEgYXByb3hpbcOhY2lhKSB2w71yYXpuZSBvZGNoecS+dWplIG9kIHByaWFta3ksIHp2w6HFvmltZSB0cmFuc2Zvcm3DoWNpdSBkYW5laiBwcmVtZW5uZWogKG5hcHIuIGt2YWRyYXRpY2vDvSDEjWxlbiwgbG9nYXJpdG11cyBhIHBvZC4pLiBWIG5hxaFvbSBwcsOtcGFkZSBuw6FzIG3DtMW+dSB6YXVqw61tYcWlIG5ham3DpCBwcmVtZW7DqSBgb2J5dl8wNmAgKHBvxI1ldCBvYnl2YXRlxL5vdiB2IGrDum5pKSBhIGBvYnl2XzA5YCAocG/EjWV0IG9ieXZhdGXEvm92IHYgc2VwdGVtYnJpKSwgYWsgc2EgcHJpIG5pY2ggb2JqYXZ1amUgdsO9cmF6bmVqxaFpZSB6YWtyaXZlbmllLgoKLS0tCgojIyAzLiBOZWxpbmXDoXJuYSDFoXBlY2lmaWvDoWNpYQoKxIxhc3RvIG3DtMW+ZW1lIG5lbGluZcOhcm5lIHZ6xaVhaHkgcHJpYmxpxb5vdmHFpSBwb21vY291IHBvbHluw7Ntb3YuIFYgcHLDrXBhZGUga3ZhZHJhdGlja8O9Y2ggxI1sZW5vdiBtw6EgbW9kZWwgdHZhcjoKClxbCnlfaSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfezFpfSArIFxkb3RzICsgXGJldGFfayB4X3traX0gKyBcZ2FtbWFfaSB4X3traX1eMiArIHVfaQpcXQoKViBuYcWhb20gcHLDrWtsYWRlIG3DtMW+ZW1lIHphcmFkacWlIGt2YWRyw6F0IG5pZWt0b3LDvWNoIG1lc2HEjW7DvWNoIHN0YXZvdiBvYnl2YXRlxL5vdiwgbmFwcsOta2xhZCBgb2J5dl8wNmAgKGrDum4pIGEgYG9ieXZfMDlgIChzZXB0ZW1iZXIpLgoKLS0tCgojIyA0LiBQb3Jvdm5hbmllIHrDoWtsYWRuw6lobyBhIG1vZGlmaWtvdmFuw6lobyBtb2RlbHUKClByZWRwb2tsYWRham1lLCDFvmUgcG9kxL5hIEMrUiBncmFmb3Ygc2Egcm96aG9kbmVtZSBwcmlkYcWlIGt2YWRyw6F0IHByZW1lbm7DvWNoIGBvYnl2XzA2YCBhIGBvYnl2XzA5YC4gTsOhxaEgcm96xaHDrXJlbsO9IG1vZGVsIGJ1ZGU6CgpgYGB7cn0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBNT0RFTFkgUyBLVkFEUkFUSUNLw51NSSDEjExFTk1JCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm1vZGVsX2xpbmVhciA8LSBsbShvYnl2XzEyIH4gMSArIG9ieXZfMDEgKyBvYnl2XzA2ICsgb2J5dl8wOSkKCm1vZGVsX2t2YWRyIDwtIGxtKG9ieXZfMTIgfiAxICsgb2J5dl8wMSArIG9ieXZfMDYgKyBvYnl2XzA5ICsKICAgICAgICAgICAgICAgICAgICBJKG9ieXZfMDZeMikgKyBJKG9ieXZfMDleMikpCgpzdW1tYXJ5KG1vZGVsX2t2YWRyKQoKYW5vdmEobW9kZWxfbGluZWFyLCBtb2RlbF9rdmFkcikKcmVzZXR0ZXN0KG1vZGVsX2t2YWRyKQpgYGAKClBvcm92bsOhdmFtZToKCi0gKip1cHJhdmVuw70ga29lZmljaWVudCBkZXRlcm1pbsOhY2llKiogXChSXjJfe2Fkan1cKSwKLSAqKkFOT1ZBIHRlc3QgZHZvY2ggdm5vcmVuZcO9Y2ggbW9kZWxvdioqIChsaW5lw6FybnkgdnMuIHMga3ZhZHLDoXRtaSksCi0gdsO9c2xlZG9rICoqUkVTRVQgdGVzdHUqKiBwcmUgcm96xaHDrXJlbsO9IG1vZGVsLgoKQWsgcm96xaHDrXJlbsO9IG1vZGVsIHZ5a2F6dWplIHZ5xaHFocOtIFwoUl4yX3thZGp9XCksIEFOT1ZBIHRlc3QgamUgdsO9em5hbW7DvSBhIFJFU0VUIHRlc3QgcG91a2F6dWplIG5hIGxlcMWhaXUgxaFwZWNpZmlrw6FjaXUsIG3DtMW+ZW1lIGt2YWRyYXRpY2vDqSDEjWxlbnkgcG92YcW+b3ZhxaUgemEgdmhvZG7DqS4KCkFrIGJ5IG5hcHLDrWtsYWQga3ZhZHLDoXQgamVkbmVqIHByZW1lbm5laiB2ecWhaWVsIMWhdGF0aXN0aWNreSBuZXbDvXpuYW1uw70sIG3DtMW+ZW1lIG1vZGVsIHpqZWRub2R1xaFpxaUgYSBwb25lY2hhxaUgbGVuIHRpZSBrdmFkcmF0aWNrw6kgxI1sZW55LCBrdG9yw6kgemxlcMWhdWrDuiDFoXRhdGlzdGlja8OpIHZsYXN0bm9zdGkgbW9kZWx1LgoKYGBge3J9CiMgUHLDrWtsYWQgemplZG5vZHXFoWVuaWEg4oCTIHBvbmVjaGFqbWUgbGVuIGt2YWRyw6F0IG9ieXZfMDYKbW9kZWxfa3ZhZHJfc2ltcGxlIDwtIGxtKG9ieXZfMTIgfiAxICsgb2J5dl8wMSArIG9ieXZfMDYgKyBvYnl2XzA5ICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgSShvYnl2XzA2XjIpKQpzdW1tYXJ5KG1vZGVsX2t2YWRyX3NpbXBsZSkKYGBgCgotLS0KCiMjIDUuIFJvesWhw61yZW7DvSBtb2RlbCBzIGt2YWRyYXRpY2vDvW1pIMSNbGVubWkKCk3DtMW+ZW1lIGXFoXRlIHNrw7pzacWlIHN5c3RlbWF0aWNrZWrFoWl1IHJvesWhw61yZW7DuiDFoXBlY2lmaWvDoWNpdSwga2RlIHByaWTDoW1lIGt2YWRyYXRpY2vDqSDEjWxlbnkga3UgdsWhZXRrw71tIHZ5c3ZldMS+dWrDumNpbSBwcmVtZW5uw71tOgoKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgUk9axaDDjVJFTsOdIE1PREVMIFMgVklBQ0VSw51NSSBLVkFEUkFUSUNLw51NSSDEjExFTk1JCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCm1vZGVsX3JvenNpcmVueSA8LSBsbShvYnl2XzEyIH4gb2J5dl8wMSArIG9ieXZfMDYgKyBvYnl2XzA5ICsKICAgICAgICAgICAgICAgICAgICAgICAgSShvYnl2XzAxXjIpICsgSShvYnl2XzA2XjIpICsgSShvYnl2XzA5XjIpKQoKc3VtbWFyeShtb2RlbF9yb3pzaXJlbnkpCgphbm92YShtb2RlbF9saW5lYXIsIG1vZGVsX3JvenNpcmVueSkKcmVzZXR0ZXN0KG1vZGVsX3JvenNpcmVueSkKYGBgCgpUdSBzbGVkdWplbWUsIMSNaSBrdmFkcmF0aWNrw6kgxI1sZW55IHZ5Y2jDoWR6YWrDuiDFoXRhdGlzdGlja3kgdsO9em5hbW7DqSBhIMSNaSBBTk9WQSB0ZXN0IHVrw6HFvmUgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw6kgemxlcMWhZW5pZSBvcHJvdGkgcMO0dm9kbsOpbXUgbGluZcOhcm5lbXUgbW9kZWx1LiBWw71zbGVkb2sgUkVTRVQgdGVzdHUgbsOhbSB6w6Fyb3ZlxYggbmFwb3ZpZSwgxI1pIGFqIHBvIHTDvWNodG8gw7pwcmF2w6FjaCB6b3N0w6F2YSBwcm9ibMOpbSBuZXNwcsOhdm5laiDFoXBlY2lmaWvDoWNpZS4KCi0tLQoKIyMgNi4gVHJhbnNmb3Jtw6FjaWEgcG9tb2NvdSBkdW1teSBwcmVtZW5uZWogYSBsaW5lw6FybmVqIGxvbWVuZWogZnVua2NpZQoKUHJlZHBva2xhZGFqbWUsIMW+ZSBwb2TEvmEgQytSIGdyYWZ1IHByaSBwcmVtZW5uZWogYG9ieXZfMDZgIChwb8SNZXQgb2J5dmF0ZcS+b3YgdiBqw7puaSkgdmlkw61tZSwgxb5lIHByZSAqKm1lbsWhaWUqKiBvYmNlIGEgKip2w6TEjcWhaWUqKiBvYmNlIG3DtMW+ZSBiecWlIHZ6xaVhaCBvZGxpxaFuw70g4oCTIHRlZGEgcHJlIHVyxI1pdMOpIOKAnmtyaXRpY2vDqeKAnCB2ZcS+a29zdGkgb2Jjw60gc2EgbWVuw60gc2tsb24uCgpaYXZlxI9tZSBkdW1teSBwcmVtZW5uw7o6CgpcWwpEVU1faSA9ClxiZWdpbntjYXNlc30KMSwgJiBcdGV4dHthayBvYmVjIG3DoSB2IGrDum5pIHZpYWMgYWtvIDEwXCwwMDAgb2J5dmF0ZcS+b3Z9LCBcXAowLCAmIFx0ZXh0e2luYWt9LgpcZW5ke2Nhc2VzfQpcXQoKUG9tb2NvdSB0ZWp0byBwcmVtZW5uZWogbcO0xb5lbWUgbW9kZWxvdmHFpToKCjEuICoqWmxvbSB2IGF1dG9uw7Ntbm9tIMSNbGVuZSoqIOKAkyBwb3N1biByZWdyZXNuZWogbmFkcm92aW55IG1lZHppIG1lbsWhw61taSBhIHbDpMSNxaHDrW1pIG9iY2FtaS4KMi4gKipabG9tIHYgc2tsb25lKiog4oCTIG9kbGnFoW7DvSB2cGx5diBqw7pub3bDqWhvIHBvxI10dSBvYnl2YXRlxL5vdiBuYSBkZWNlbWJlciBwb2TEvmEgdmXEvmtvc3RpIG9iY2UuCgpgYGB7cn0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBEVU1NWSBQUkVNRU5Ow4EgQSBMT01FTsOBIEZVTktDSUEKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgZGVmaW51amVtZSBkdW1teSBwb2TEvmEgasO6bm92w6lobyBzdGF2dSDigJMgaHJhbmljYSAxMCAwMDAgb2J5dmF0ZcS+b3YgamUgaWx1c3RyYcSNbsOhCkRVTSA8LSBpZmVsc2Uob2J5dl8wNiA+IDEwMDAwLCAxLCAwKQp1ZGFqZSREVU0gPC0gRFVNCgojIE1vZGVsIHNvIHpsb21vbSB2IGF1dG9uw7Ntbm9tIMSNbGVuZQptb2RlbERfYXV0byA8LSBsbShvYnl2XzEyIH4gMSArIERVTSArIG9ieXZfMDEgKyBvYnl2XzA2ICsgb2J5dl8wOSwgZGF0YSA9IHVkYWplKQpzdW1tYXJ5KG1vZGVsRF9hdXRvKQoKIyBNb2RlbCBzbyB6bG9tb20gdiBza2xvbmUgKGludGVyYWtjaWEgRFVNICogb2J5dl8wNikKbW9kZWxEX3NrbG9uIDwtIGxtKG9ieXZfMTIgfiAxICsgb2J5dl8wMSArIG9ieXZfMDYgKyBJKERVTSAqIG9ieXZfMDYpICsgb2J5dl8wOSwKICAgICAgICAgICAgICAgICAgIGRhdGEgPSB1ZGFqZSkKc3VtbWFyeShtb2RlbERfc2tsb24pCgphbm92YShtb2RlbF9saW5lYXIsIG1vZGVsRF9za2xvbikKcmVzZXR0ZXN0KG1vZGVsRF9za2xvbikKYGBgCgpJbnRlcnByZXTDoWNpYToKCi0gdiBtb2RlbGkgYG1vZGVsRF9hdXRvYCBza8O6bWFtZSwgxI1pIHNhIGzDrcWhaSAqKsO6cm92ZcWIKiogcG/EjXR1IG9ieXZhdGXEvm92IHYgZGVjZW1icmkgKGF1dG9uw7NtbnkgxI1sZW4pIG1lZHppIG1lbsWhw61taSBhIHbDpMSNxaHDrW1pIG9iY2FtaSwKLSB2IG1vZGVsaSBgbW9kZWxEX3NrbG9uYCBza8O6bWFtZSwgxI1pIHNhIGzDrcWhaSAqKnNrbG9uKiogcHJpIHByZW1lbm5laiBgb2J5dl8wNmAgKHQuIGouIMSNaSBuw6FyYXN0IHBvxI10dSBvYnl2YXRlxL5vdiB2IGrDum5pIG8gamVkbnUgb3NvYnUgenZ5xaF1amUgcG/EjWV0IG9ieXZhdGXEvm92IHYgZGVjZW1icmkgcm92bmFrw71tIHNww7Rzb2JvbSB2IG1hbMO9Y2ggYWogdmXEvmvDvWNoIG9iY2lhY2gpLgoKQWsgQU5PVkEgdGVzdCBtZWR6aSBgbW9kZWxfbGluZWFyYCBhIGBtb2RlbERfc2tsb25gIHZ5amRlIMWhdGF0aXN0aWNreSB2w716bmFtbsO9IGEgaW50ZXJha8SNbsO9IMSNbGVuIGplIHbDvXpuYW1uw70sIG3DtMW+ZW1lIHVzw7pkacWlLCDFvmUgemF2ZWRlbmllIHpsb211IHYgc2tsb25lIHpsZXDFoWlsbyBtb2RlbC4KCi0tLQoKIyMgNy4gQm944oCTQ294b3YgdHJhbnNmb3JtYcSNbsO9IHRlc3QKCkJveOKAk0NveG92IHRlc3QgbsOhbSBwb23DoWhhIHJvemhvZG7DusWlLCDEjWkgamUgdmhvZG7DqSB0cmFuc2Zvcm1vdmHFpSAqKnZ5c3ZldMS+b3ZhbsO6IHByZW1lbm7DuioqICh1IG7DoXMgYG9ieXZfMTJgKSwgbmFwcsOta2xhZCBwb21vY291IGxvZ2FyaXRtdSwgb2Rtb2NuaW55IGFsZWJvIHJlY2lwcm9rYS4KCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIEJPWOKAk0NPWE9WQSBUUkFOU0ZPUk3DgUNJQQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpsaWJyYXJ5KE1BU1MpCmJveGNveChtb2RlbF9saW5lYXIpCmBgYAoKSW50ZXJwcmV0w6FjaWE6CgotIGFrIFwoXGxhbWJkYSBcYXBwcm94IDFcKSDigJMgdHJhbnNmb3Jtw6FjaWEgbmllIGplIHBvdHJlYm7DoSwKLSBhayBcKFxsYW1iZGEgXGFwcHJveCAwXCkg4oCTIHZob2Ruw6EgamUgbG9nYXJpdG1pY2vDoSB0cmFuc2Zvcm3DoWNpYSBcKFxsb2coeSlcKSwKLSBhayBcKFxsYW1iZGEgXGFwcHJveCAweyx9NVwpIOKAkyB2aG9kbsOhIGplIG9kbW9jbmluYSBcKFxzcXJ0e3l9XCksCi0gYWsgXChcbGFtYmRhIFxhcHByb3ggLTFcKSDigJMgdmhvZG7DoSBqZSByZWNpcHJvxI1uw6EgdHJhbnNmb3Jtw6FjaWEgXCgxL3lcKS4KClByZWRwb2tsYWRham1lLCDFvmUgQm944oCTQ294b3YgdGVzdCBuYXpuYcSNw60gbmVqYWvDuiBob2Rub3R1IFwoXGxhbWJkYVwpOyBpbHVzdHJhxI1uw6kgbmFzdGF2ZW5pZToKCmBgYHtyfQojIElsdXN0cmHEjW7DoSB0cmFuc2Zvcm3DoWNpYSBzIGxhbWJkYSA9IDAuNSAob2Rtb2NuaW5hKSwgYWsgYnkgbsOhbSB0byBCb3jigJNDb3ggb2Rwb3J1xI1pbAptb2RlbF9sYW1iZGEgPC0gbG0oSSgob2J5dl8xMl4wLjUgLSAxKSAvIDAuNSkgfiAxICsgb2J5dl8wMSArIG9ieXZfMDYgKyBvYnl2XzA5LAogICAgICAgICAgICAgICAgICAgZGF0YSA9IHVkYWplKQpzdW1tYXJ5KG1vZGVsX2xhbWJkYSkKcmVzZXR0ZXN0KG1vZGVsX2xhbWJkYSkKYGBgCgpQcmkgcG9yb3Zuw6F2YW7DrSBzIHDDtHZvZG7DvW0gbW9kZWxvbSBzbGVkdWplbWUgem1lbnUgXChSXjJfe2Fkan1cKSBhIHbDvXNsZWRvayBSRVNFVCB0ZXN0dS4gQWsgc8OtY2UgZMO0amRlIGsgbWFsZWogem1lbmUgXChSXjJfe2Fkan1cKSwgYWxlIHbDvXJhem5lIHNhIHNrb21wbGlrdWplIGludGVycHJldMOhY2lhICh1xb4gbmVwcmFjdWplbWUgcHJpYW1vIHMgcG/EjXRvbSBvYnl2YXRlxL5vdiwgYWxlIHMgdHJhbnNmb3Jtw6FjaW91KSwgdiBwcmFrdGlja8O9Y2ggYXBsaWvDoWNpw6FjaCBzYSDEjWFzdG8gcHJlZmVydWplIGplZG5vZHVjaMWhw60gbW9kZWwsIHBva2lhxL4gxaF0YXRpc3RpY2t5IOKAnnN0YcSNw63igJwuCg==