S využitím databázy Databaza.csv, ktorá obsahuje počty obyvateľov slovenských obcí podľa okresu a mesiaca v roku 2024.

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

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

1. Úvod a údaje

Údaje o počte obyvateľov sú uložené v súbore Databaza.csv.
Každý riadok predstavuje jednu obec, stĺpce:

  • Okres – názov okresu,
  • Obec – názov obce,
  • 2024M012024M12 – počet obyvateľov v danom mesiaci roku 2024.

Súbor predpokladáme uložený v podpriečinku udaje v pracovnom priečinku (aby boli údaje oddelené od zvyšku projektu).

1.1 Úvod do problému, stanovenie hypotéz

Rozhodli sme sa sledovať vývoj počtu obyvateľov v čase vo vybranej obci.
Konkrétne budeme modelovať mesačný počet obyvateľov v obci
„Bratislava - mestská časť Staré Mesto“ v závislosti od času (index mesiaca).

Označme:

  • \(Y_t\): počet obyvateľov v mesiaci \(t\),
  • \(t\): časový index (1 = január 2024, 2 = február 2024, …, 12 = december 2024).

Naša pracovná hypotéza:

  • predpokladáme, že počet obyvateľov sa v priebehu roka mierne mení (napr. vplyvom migrácie),
  • očakávame hladký vývoj v čase, teda silnú autokoreláciu, t. j. počet obyvateľov v mesiaci \(t\) je veľmi podobný počtu v mesiaci \(t-1\),
  • očakávame kladný trendový koeficient (\(\beta_1 > 0\)), ak počet obyvateľov má mierne rastúcu tendenciu.

1.2 Príprava databázy, úprava údajov

Databáza je v tzv. „wide“ tvare (mesiace v stĺpcoch). Pre časovú analýzu jednej obce je výhodnejšie mať údaje v „long“ tvare: každý riadok = jedna obec v jednom mesiaci.

Najskôr načítame údaje, potom vyberieme jednu obec a preklopíme mesačné stĺpce do časového radu.

# načítanie databázy
udaje <- read.csv("Databaza.csv",
                  sep = ";",
                  dec = ",",
                  header = TRUE,
                  check.names = FALSE)

# vyberieme jednu konkrétnu obec (možeš zmeniť na inú)
udajeMesto <- udaje[udaje$Obec == "Bratislava - mestská časť Staré Mesto", ]

# preklopenie z wide na long (mesiace do riadkov)
udajeMesto_long <- udajeMesto %>%
  pivot_longer(
    cols = dplyr::starts_with("2024M"),
    names_to = "RokMesiac",
    values_to = "Pocet_obyvatelov"
  ) %>%
  arrange(RokMesiac) %>% 
  mutate(
    Rok = as.numeric(substr(RokMesiac, 1, 4)),
    Mes = as.numeric(substr(RokMesiac, 6, 7)),
    Time = dplyr::row_number()  # 1 = január, 12 = december
  )

udajeMesto_long

2. Lineárna regresia v základnom tvare

Ide o odhad rovnice

\[ \text{Pocet\_obyvatelov}_t = \beta_0 + \beta_1 \text{Time}_t + e_t, \]

kde:

  • \(\text{Pocet\_obyvatelov}_t\) – počet obyvateľov vo vybranom mesiaci,
  • \(\text{Time}_t\) – index mesiaca (1–12),
  • \(e_t\) – náhodná zložka (rezíduum).
library(ggplot2)

# lineárny trendový model
model <- lm(Pocet_obyvatelov ~ Time, data = udajeMesto_long)
summary(model)

Call:
lm(formula = Pocet_obyvatelov ~ Time, data = udajeMesto_long)

Residuals:
    Min      1Q  Median      3Q     Max 
-26.232 -12.214   1.946  12.539  23.684 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 47339.47      10.96 4318.14  < 2e-16 ***
Time           24.44       1.49   16.41 1.47e-08 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 17.81 on 10 degrees of freedom
Multiple R-squared:  0.9642,    Adjusted R-squared:  0.9606 
F-statistic: 269.2 on 1 and 10 DF,  p-value: 1.472e-08

3. Autokorelácia rezíduí

V tejto časti sa pozrieme na ďalší dôležitý predpoklad klasického lineárneho regresného modelu – nezávislosť rezíduí. V časových radoch (ako je náš mesačný počet obyvateľov) sa často stáva, že chyba v čase \(t\) je systematicky spätá s chybou v čase \(t-1\), čo nazývame autokoreláciou rezíduí.

3.1 Čo je autokorelácia rezíduí?

Autokorelácia rezíduí je situácia, keď platí:

\[ \operatorname{Corr}(e_t, e_{t-k}) \neq 0 \quad \text{pre niektoré } k \neq 0. \]

Najčastejšie sa skúma autokorelácia prvého rádu:

\[ e_t = \rho e_{t-1} + \nu_t,\quad |\rho| < 1. \]

3.2 Dôsledky autokorelácie rezíduí

  • odhady koeficientov \(\hat{\beta}\) sú nestranné,
  • ale neefektívne,
  • štandardné chyby sú skreslené (často podhodnotené), teda p-hodnoty sa javia menšie,
  • t- a F-testy sú potom skreslené.

3.3 Detekcia autokorelácie

Grafická informácia

# pridáme do dát fitted values z modelu
udajeMesto_long$fitted <- fitted(model)

# scatterplot + vyrovnaná trendová čiara
ggplot(udajeMesto_long, aes(x = Time, y = Pocet_obyvatelov)) +
  geom_point(color = "steelblue", size = 2) +
  geom_line(aes(y = fitted), color = "red", size = 1) +
  labs(
    title = "Počet obyvateľov: empirické údaje (modrá) vs. odhadnutý trend (červená)",
    x = "Mesiac (2024)",
    y = "Počet obyvateľov"
  ) +
  theme_minimal()

Analýzou obrázka vidíme, že mesačné hodnoty počtu obyvateľov na seba plynulo nadväzujú – v susedných mesiacoch sú si veľmi podobné. Ak by sme si zobrazili rezíduá (rozdiel medzi empirickými a vyrovnanými hodnotami), je prirodzené očakávať, že počas niekoľkých po sebe idúcich mesiacov budú mať podobné znamienko. To je typický vizuálny signál možnej autokorelácie.

# uložíme si reziduá z pôvodného modelu
res <- residuals(model)

ACF graf (Autocorrelation Function)

Táto funkcia priraďuje odhad korelácie, ktorá je medzi jednotlivými rezíduami v aktuálnom období a období posunutom (Lag) o \(k\) období späť.

acf(res, lag.max = 4, main = "Autokorelačná funkcia rezíduí")

Na tomto grafe je modrou prerušovanou čiarou vyjadrený aj 95 % interval spoľahlivosti pre hodnotu autokorelačného koeficientu s príslušným posunom. Ak sa niektorý stĺpec nachádza mimo tohto pásma, naznačuje to štatisticky významnú autokoreláciu pri danom posune.


Durbin–Watsonov test

Durbin–Watsonov koeficient (DW) je vypočítaný z rezíduí podľa vzorca

\[ DW = \frac{\sum_{t=2}^{n} (e_t - e_{t-1})^{2}}{\sum_{t=1}^{n} e_t^{2}} \]

kde \(n\) je počet pozorovaní. Medzi koeficientom autokorelácie dvoch susedných rezíduí a DW platí približný vzťah

\[ \hat{\rho} \approx 1 - \frac{DW}{2}. \]

Hodnoty:

  • blízke nule → silná pozitívna autokorelácia,
  • blízke 4 → silná negatívna autokorelácia,
  • okolo 2 → žiadny výrazný problém s autokoreláciou.

V praxi sa často používa intuitívne pravidlo: ak sa DW nachádza v intervale približne 1,8 až 2,2, problém autokorelácie väčšinou nepovažujeme za vážny.

library(lmtest)
dwtest(model)

    Durbin-Watson test

data:  model
DW = 2.4468, p-value = 0.6766
alternative hypothesis: true autocorrelation is greater than 0

DW test má isté obmedzenia – regresory nesmú byť časovo posunuté a nesmú obsahovať oneskorené pozorovania vysvetľovanej veličiny ako regresory. Tieto obmedzenia neplatia pre Breusch–Godfreyov test.


Breusch–Godfreyov test (BG test)

Čo test testuje

BG test je formálnym testom autokorelácie (sériovej korelácie) rezíduí:

\[ u_t = \rho_1 u_{t-1} + \rho_2 u_{t-2} + \cdots + \rho_p u_{t-p} + \varepsilon_t. \]

Testuje, či sú rezíduá korelované v čase až do rádu \(p\), čo je typické pre časové rady.

Na rozdiel od DW testu:

  • testuje autokoreláciu s vyšším posunom (lag 1, 2, 3, …),
  • funguje aj pri modeloch s oneskorenou vysvetľovanou premennou ako regresorom,
  • pracuje s nekonštantnými regresormi (trend, dummy premenné atď.).

Hypotézy

Pre test autokorelácie až do rádu \(p\):

  • Nulová hypotéza \(H_0\): žiadna sériová korelácia
    \[ \rho_1 = \rho_2 = \cdots = \rho_p = 0 \]

  • Alternatívna hypotéza \(H_1\): séria je autokorelovaná
    Aspoň jedna z \(\rho_j\) je odlišná od nuly.


Ako funguje BG test
  1. Odhadneme pôvodnú regresiu (u nás trendový model) a získame rezíduá \(e_t\).
  2. Spustíme pomocnú regresiu: \[ e_t = \alpha_0 + \alpha_1 x_{1t} + \cdots + \alpha_k x_{kt} + \rho_1 e_{t-1} + \cdots + \rho_p e_{t-p} + v_t, \] kde \(x_{jt}\) sú pôvodné regresory.
  3. Z tejto regresie vypočítame: \[ \text{BG} = (n - p) R^2_{\text{aux}} \]
  4. Pod \(H_0\) platí približne: \[ \text{BG} \sim \chi^2_p. \]

Interpretácia
  • Veľká hodnota testovej štatistiky BG (malá p-hodnota) → zamietame \(H_0\)autokorelácia prítomná.
  • Malá hodnota BG (veľká p-hodnota) → nezamietneme \(H_0\)nie je dôkaz autokorelácie.

Praktický výpočet v R
bgtest(model, order = 1)

    Breusch-Godfrey test for serial correlation of order up to 1

data:  model
LM test = 0.70926, df = 1, p-value = 0.3997

V našich údajoch (mesačný počet obyvateľov vo vybranej obci v roku 2024) sa ukáže, či BG test potvrdí alebo vyvráti prítomnosť autokorelácie prvého rádu. Aj keď pri krátkom časovom rade (len 12 mesiacov) nebýva test príliš silný, pre demonštračné účely použijeme aj postup odstránenia dôsledkov autokorelácie pomocou dynamizácie modelu.


Ako riešiť autokoreláciu

Koyckova transformácia a Koyckova rovnica

V predchádzajúcej časti sme sa venovali autokorelácii rezíduí. Teraz rozšírime model o dynamickú štruktúru založenú na tzv. geometricky klesajúcom rozložení oneskorených efektov. Takýto model sa nazýva Koyckov model a jeho ústredným prvkom je Koyckova transformácia.


Východiskový model s distribuovaným oneskorením

Uvažujme model:

\[ y_t = \alpha + \beta_0 x_t + \beta_1 x_{t-1} + \beta_2 x_{t-2} + \cdots + u_t. \]


Koyckova štruktúra koeficientov

Koyck navrhol, že oneskorené efekty majú geometricky klesajúcu podobu:

\[ \beta_k = \lambda^k \beta_0, \qquad 0 < \lambda < 1. \]

Tým sa distribučné oneskorenie zjednoduší tak, že namiesto nekonečného počtu parametrov odhadujeme len:

  • \(\beta_0\) – okamžitý efekt,
  • \(\lambda\) – rýchlosť tlmenia efektov oneskorenia.

Koyckova transformácia

Pôvodný model:

\[ y_t = \alpha + \beta_0 x_t + \lambda \beta_0 x_{t-1} + \lambda^2 \beta_0 x_{t-2} + \cdots + u_t. \]

Vynásobíme model konštantou \(\lambda\) a posunieme časový index o 1 dozadu:

\[ \lambda y_{t-1} = \lambda\alpha + \beta_0 x_{t-1} + \lambda \beta_0 x_{t-2} + \cdots + \lambda u_{t-1}. \]

Odčítaním oboch výrazov dostaneme:

\[ y_t - \lambda y_{t-1} = \alpha(1-\lambda) + \beta_0 (x_t - \lambda x_{t-1}) + (u_t - \lambda u_{t-1}). \]

To je Koyckova transformácia.


Koyckova rovnica (autoregresívny model)

Po algebraickej úprave:

\[ y_t = \alpha(1-\lambda) + \beta_0 x_t + \lambda y_{t-1} + v_t, \]

kde:

\[ v_t = u_t - \lambda u_{t-1}. \]

Toto je Koyckova rovnica – dynamický autoregresívny model so závislosťou na minulosti.

V našom kontexte:

  • \(y_t\) = počet obyvateľov v mesiaci \(t\),
  • \(x_t\) – napríklad časový trend (Time),
  • \(y_{t-1}\) – počet obyvateľov v predchádzajúcom mesiaci.

Odstraňovanie problému autokorelácie rezíduí

Odhad Koyckovho modelu v R

Najjednoduchšia implementácia pre naše údaje:

udajeMesto_long <- udajeMesto_long %>%
  arrange(Time) %>%
  mutate(
    Pocet_obyvatelov_lag1 = dplyr::lag(Pocet_obyvatelov)
  )

model_koyck <- lm(Pocet_obyvatelov ~ Time + Pocet_obyvatelov_lag1, 
                  data = udajeMesto_long)

summary(model_koyck)

Call:
lm(formula = Pocet_obyvatelov ~ Time + Pocet_obyvatelov_lag1, 
    data = udajeMesto_long)

Residuals:
    Min      1Q  Median      3Q     Max 
-24.591 -16.219   2.003  13.554  23.918 

Coefficients:
                        Estimate Std. Error t value Pr(>|t|)   
(Intercept)           58792.7569 15755.3637   3.732  0.00577 **
Time                     30.9479     8.3103   3.724  0.00584 **
Pocet_obyvatelov_lag1    -0.2422     0.3330  -0.727  0.48779   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 18.75 on 8 degrees of freedom
  (1 observation deleted due to missingness)
Multiple R-squared:  0.9609,    Adjusted R-squared:  0.9512 
F-statistic:  98.4 on 2 and 8 DF,  p-value: 2.329e-06
dwtest(model_koyck)

    Durbin-Watson test

data:  model_koyck
DW = 2.2885, p-value = 0.5587
alternative hypothesis: true autocorrelation is greater than 0

V dynamizovanom modeli vystupuje aj oneskorená hodnota vysvetľovanej premennej (Pocet_obyvatelov_lag1). Ak je jej koeficient kladný a menší ako 1, interpretujeme to tak, že časť úrovne z minulého mesiaca sa prenáša do aktuálneho mesiaca (zotrvačnosť). Pri hodnotení kvality modelu je vhodné porovnať napríklad Adjusted R-squared pôvodného a dynamického modelu, prípadne znova overiť autokoreláciu rezíduí (DW, BG test).


Newey–West robustné štandardné chyby

Ešte jednou možnosťou, ako reagovať na prítomnosť autokorelácie (a heteroskedasticity), je použiť robustné štandardné chyby podľa Newey–Westa. Tie nemenia samotné odhady koeficientov, ale korigujú odhady smerodajných odchýlok.

library(sandwich)
library(lmtest)

coeftest(model, vcov = NeweyWest(model))

t test of coefficients:

              Estimate Std. Error  t value  Pr(>|t|)    
(Intercept) 4.7339e+04 6.5101e+00 7271.681 < 2.2e-16 ***
Time        2.4441e+01 7.7275e-01   31.628 2.347e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

4. Záver

Na jednoduchom príklade mesačného počtu obyvateľov vo vybranej slovenskej obci v roku 2024 sme ukázali:

  • ako odhadnúť trendový model v čase,
  • ako graficky a štatisticky testovať autokoreláciu rezíduí (ACF, Durbin–Watson, BG test),
  • ako možno model dynamizovať pomocou Koyckovej rovnice,
  • a ako využiť Newey–Westove robustné štandardné chyby.

Autokorelácia rezíduí a z nej vyplývajúca potreba dynamizácie modelov má v ekonometrii veľký význam. Tu sme uviedli len základné prístupy – k zložitejším patrí napríklad Almonov model distribuovaného oneskorenia, metóda Cochran–Orcutt alebo všeobecnejšie ARIMA modely, ktoré sa používajú pri dlhších časových radoch.

LS0tCnRpdGxlOiAiRWNvbm9tZXRyaWNzIGluIFIgLSBjdmnEjWVuaWUgOSIKYXV0aG9yOiAiRmlsaXAgSnVya8OhxI1layAoemEgcG9tb2NpIENoYXRHUFQpIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgpTIHZ5dcW+aXTDrW0gZGF0YWLDoXp5ICoqRGF0YWJhemEuY3N2KiosIGt0b3LDoSBvYnNhaHVqZSAqKnBvxI10eSBvYnl2YXRlxL5vdiBzbG92ZW5za8O9Y2ggb2Jjw60gcG9kxL5hIG9rcmVzdSBhIG1lc2lhY2EgdiByb2t1IDIwMjQqKi4KClByaSDEj2FsxaFlaiBwcsOhY2kgYnVkZW1lIHBvdcW+w612YcWlIGtuacW+bmljZQoKYGBge3J9CmxpYnJhcnkoem9vKQpsaWJyYXJ5KHRzZXJpZXMpCmxpYnJhcnkobG10ZXN0KQpsaWJyYXJ5KHNhbmR3aWNoKQpsaWJyYXJ5KGNhcikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKcm0obGlzdCA9IGxzKCkpCmBgYAoKLS0tCgojIyAxLiDDmnZvZCBhIMO6ZGFqZQoKw5pkYWplIG8gcG/EjXRlIG9ieXZhdGXEvm92IHPDuiB1bG/FvmVuw6kgdiBzw7pib3JlIGBEYXRhYmF6YS5jc3ZgLiAgCkthxb5kw70gcmlhZG9rIHByZWRzdGF2dWplIGplZG51ICoqb2JlYyoqLCBzdMS6cGNlOgoKLSBgT2tyZXNgIOKAkyBuw6F6b3Ygb2tyZXN1LAotIGBPYmVjYCDigJMgbsOhem92IG9iY2UsCi0gYDIwMjRNMDFgIOKApiBgMjAyNE0xMmAg4oCTIHBvxI1ldCBvYnl2YXRlxL5vdiB2IGRhbm9tIG1lc2lhY2kgcm9rdSAyMDI0LgoKU8O6Ym9yIHByZWRwb2tsYWTDoW1lIHVsb8W+ZW7DvSB2IHBvZHByaWXEjWlua3UgKipgdWRhamVgKiogdiBwcmFjb3Zub20gcHJpZcSNaW5rdSAoYWJ5IGJvbGkgw7pkYWplIG9kZGVsZW7DqSBvZCB6dnnFoWt1IHByb2pla3R1KS4KCiMjIyAxLjEgw5p2b2QgZG8gcHJvYmzDqW11LCBzdGFub3ZlbmllIGh5cG90w6l6CgpSb3pob2RsaSBzbWUgc2Egc2xlZG92YcWlICoqdsO9dm9qIHBvxI10dSBvYnl2YXRlxL5vdiB2IMSNYXNlKiogdm8gdnlicmFuZWogb2JjaS4gIApLb25rcsOpdG5lIGJ1ZGVtZSBtb2RlbG92YcWlICoqbWVzYcSNbsO9IHBvxI1ldCBvYnl2YXRlxL5vdioqIHYgb2JjaSAgCioq4oCeQnJhdGlzbGF2YSAtIG1lc3Rza8OhIMSNYXPFpSBTdGFyw6kgTWVzdG/igJwqKiB2IHrDoXZpc2xvc3RpIG9kIMSNYXN1IChpbmRleCBtZXNpYWNhKS4KCk96bmHEjW1lOgoKLSBcKFlfdFwpOiBwb8SNZXQgb2J5dmF0ZcS+b3YgdiBtZXNpYWNpIFwodFwpLAotIFwodFwpOiDEjWFzb3bDvSBpbmRleCAoMSA9IGphbnXDoXIgMjAyNCwgMiA9IGZlYnJ1w6FyIDIwMjQsIOKApiwgMTIgPSBkZWNlbWJlciAyMDI0KS4KCk5hxaFhIHByYWNvdm7DoSBoeXBvdMOpemE6CgotIHByZWRwb2tsYWTDoW1lLCDFvmUgKipwb8SNZXQgb2J5dmF0ZcS+b3Ygc2EgdiBwcmllYmVodSByb2thIG1pZXJuZSBtZW7DrSoqIChuYXByLiB2cGx5dm9tIG1pZ3LDoWNpZSksCi0gb8SNYWvDoXZhbWUgKipobGFka8O9IHbDvXZvaiB2IMSNYXNlKiosIHRlZGEgc2lsbsO6ICoqYXV0b2tvcmVsw6FjaXUqKiwgdC4gai4gcG/EjWV0IG9ieXZhdGXEvm92IHYgbWVzaWFjaSBcKHRcKSBqZSB2ZcS+bWkgcG9kb2Juw70gcG/EjXR1IHYgbWVzaWFjaSBcKHQtMVwpLAotIG/EjWFrw6F2YW1lICoqa2xhZG7DvSB0cmVuZG92w70ga29lZmljaWVudCoqIChcKFxiZXRhXzEgPiAwXCkpLCBhayBwb8SNZXQgb2J5dmF0ZcS+b3YgbcOhIG1pZXJuZSByYXN0w7pjdSB0ZW5kZW5jaXUuCgojIyMgMS4yIFByw61wcmF2YSBkYXRhYsOhenksIMO6cHJhdmEgw7pkYWpvdgoKRGF0YWLDoXphIGplIHYgdHp2LiDigJ53aWRl4oCcIHR2YXJlIChtZXNpYWNlIHYgc3TEunBjb2NoKS4gUHJlIMSNYXNvdsO6IGFuYWzDvXp1IGplZG5laiBvYmNlIGplIHbDvWhvZG5lasWhaWUgbWHFpSDDumRhamUgdiDigJ5sb25n4oCcIHR2YXJlOiBrYcW+ZMO9IHJpYWRvayA9IGplZG5hIG9iZWMgdiBqZWRub20gbWVzaWFjaS4KCk5hanNrw7RyIG5hxI3DrXRhbWUgw7pkYWplLCBwb3RvbSB2eWJlcmllbWUgamVkbnUgb2JlYyBhIHByZWtsb3DDrW1lIG1lc2HEjW7DqSBzdMS6cGNlIGRvIMSNYXNvdsOpaG8gcmFkdS4KCmBgYHtyfQojIG5hxI3DrXRhbmllIGRhdGFiw6F6eQp1ZGFqZSA8LSByZWFkLmNzdigiRGF0YWJhemEuY3N2IiwKICAgICAgICAgICAgICAgICAgc2VwID0gIjsiLAogICAgICAgICAgICAgICAgICBkZWMgPSAiLCIsCiAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUsCiAgICAgICAgICAgICAgICAgIGNoZWNrLm5hbWVzID0gRkFMU0UpCgojIHZ5YmVyaWVtZSBqZWRudSBrb25rcsOpdG51IG9iZWMgKG1vxb5lxaEgem1lbmnFpSBuYSBpbsO6KQp1ZGFqZU1lc3RvIDwtIHVkYWplW3VkYWplJE9iZWMgPT0gIkJyYXRpc2xhdmEgLSBtZXN0c2vDoSDEjWFzxaUgU3RhcsOpIE1lc3RvIiwgXQoKIyBwcmVrbG9wZW5pZSB6IHdpZGUgbmEgbG9uZyAobWVzaWFjZSBkbyByaWFka292KQp1ZGFqZU1lc3RvX2xvbmcgPC0gdWRhamVNZXN0byAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gZHBseXI6OnN0YXJ0c193aXRoKCIyMDI0TSIpLAogICAgbmFtZXNfdG8gPSAiUm9rTWVzaWFjIiwKICAgIHZhbHVlc190byA9ICJQb2NldF9vYnl2YXRlbG92IgogICkgJT4lCiAgYXJyYW5nZShSb2tNZXNpYWMpICU+JSAKICBtdXRhdGUoCiAgICBSb2sgPSBhcy5udW1lcmljKHN1YnN0cihSb2tNZXNpYWMsIDEsIDQpKSwKICAgIE1lcyA9IGFzLm51bWVyaWMoc3Vic3RyKFJva01lc2lhYywgNiwgNykpLAogICAgVGltZSA9IGRwbHlyOjpyb3dfbnVtYmVyKCkgICMgMSA9IGphbnXDoXIsIDEyID0gZGVjZW1iZXIKICApCgp1ZGFqZU1lc3RvX2xvbmcKYGBgCgotLS0KCiMjIDIuIExpbmXDoXJuYSByZWdyZXNpYSB2IHrDoWtsYWRub20gdHZhcmUKCklkZSBvIG9kaGFkIHJvdm5pY2UKClxbClx0ZXh0e1BvY2V0XF9vYnl2YXRlbG92fV90ID0gXGJldGFfMCArIFxiZXRhXzEgXHRleHR7VGltZX1fdCArIGVfdCwKXF0KCmtkZToKCi0gXChcdGV4dHtQb2NldFxfb2J5dmF0ZWxvdn1fdFwpIOKAkyBwb8SNZXQgb2J5dmF0ZcS+b3Ygdm8gdnlicmFub20gbWVzaWFjaSwKLSBcKFx0ZXh0e1RpbWV9X3RcKSDigJMgaW5kZXggbWVzaWFjYSAoMeKAkzEyKSwKLSBcKGVfdFwpIOKAkyBuw6Fob2Ruw6Egemxvxb5rYSAocmV6w61kdXVtKS4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgojIGxpbmXDoXJueSB0cmVuZG92w70gbW9kZWwKbW9kZWwgPC0gbG0oUG9jZXRfb2J5dmF0ZWxvdiB+IFRpbWUsIGRhdGEgPSB1ZGFqZU1lc3RvX2xvbmcpCnN1bW1hcnkobW9kZWwpCmBgYAoKLS0tCgojIyAzLiBBdXRva29yZWzDoWNpYSByZXrDrWR1w60KClYgdGVqdG8gxI1hc3RpIHNhIHBvenJpZW1lIG5hIMSPYWzFocOtIGTDtGxlxb5pdMO9IHByZWRwb2tsYWQga2xhc2lja8OpaG8gbGluZcOhcm5laG8KcmVncmVzbsOpaG8gbW9kZWx1IOKAkyAqKm5lesOhdmlzbG9zxaUgcmV6w61kdcOtKiouIFYgxI1hc292w71jaCByYWRvY2ggKGFrbyBqZSBuw6HFoSBtZXNhxI1uw70KcG/EjWV0IG9ieXZhdGXEvm92KSBzYSDEjWFzdG8gc3TDoXZhLCDFvmUgY2h5YmEgdiDEjWFzZSBcKHRcKSBqZSBzeXN0ZW1hdGlja3kgc3DDpHTDoQpzIGNoeWJvdSB2IMSNYXNlIFwodC0xXCksIMSNbyBuYXrDvXZhbWUgKiphdXRva29yZWzDoWNpb3UgcmV6w61kdcOtKiouCgojIyMgMy4xIMSMbyBqZSBhdXRva29yZWzDoWNpYSByZXrDrWR1w60/CgpBdXRva29yZWzDoWNpYSByZXrDrWR1w60gamUgc2l0dcOhY2lhLCBrZcSPIHBsYXTDrToKClxbClxvcGVyYXRvcm5hbWV7Q29ycn0oZV90LCBlX3t0LWt9KSBcbmVxIDAgXHF1YWQgXHRleHR7cHJlIG5pZWt0b3LDqSB9IGsgXG5lcSAwLgpcXQoKTmFqxI1hc3RlasWhaWUgc2Egc2vDum1hIGF1dG9rb3JlbMOhY2lhIHBydsOpaG8gcsOhZHU6CgpcWwplX3QgPSBccmhvIGVfe3QtMX0gKyBcbnVfdCxccXVhZCB8XHJob3wgPCAxLgpcXQoKIyMjIDMuMiBEw7RzbGVka3kgYXV0b2tvcmVsw6FjaWUgcmV6w61kdcOtCgotIG9kaGFkeSBrb2VmaWNpZW50b3YgXChcaGF0e1xiZXRhfVwpIHPDuiBuZXN0cmFubsOpLAotIGFsZSBuZWVmZWt0w612bmUsCi0gxaF0YW5kYXJkbsOpIGNoeWJ5IHPDuiBza3Jlc2xlbsOpICjEjWFzdG8gcG9kaG9kbm90ZW7DqSksIHRlZGEgcC1ob2Rub3R5IHNhIGphdmlhIG1lbsWhaWUsCi0gdC0gYSBGLXRlc3R5IHPDuiBwb3RvbSBza3Jlc2xlbsOpLgoKLS0tCgojIyMgMy4zIERldGVrY2lhIGF1dG9rb3JlbMOhY2llIAoKIyMjIyBHcmFmaWNrw6EgaW5mb3Jtw6FjaWEKCmBgYHtyfQojIHByaWTDoW1lIGRvIGTDoXQgZml0dGVkIHZhbHVlcyB6IG1vZGVsdQp1ZGFqZU1lc3RvX2xvbmckZml0dGVkIDwtIGZpdHRlZChtb2RlbCkKCiMgc2NhdHRlcnBsb3QgKyB2eXJvdm5hbsOhIHRyZW5kb3bDoSDEjWlhcmEKZ2dwbG90KHVkYWplTWVzdG9fbG9uZywgYWVzKHggPSBUaW1lLCB5ID0gUG9jZXRfb2J5dmF0ZWxvdikpICsKICBnZW9tX3BvaW50KGNvbG9yID0gInN0ZWVsYmx1ZSIsIHNpemUgPSAyKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gZml0dGVkKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDEpICsKICBsYWJzKAogICAgdGl0bGUgPSAiUG/EjWV0IG9ieXZhdGXEvm92OiBlbXBpcmlja8OpIMO6ZGFqZSAobW9kcsOhKSB2cy4gb2RoYWRudXTDvSB0cmVuZCAoxI1lcnZlbsOhKSIsCiAgICB4ID0gIk1lc2lhYyAoMjAyNCkiLAogICAgeSA9ICJQb8SNZXQgb2J5dmF0ZcS+b3YiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKQW5hbMO9em91IG9icsOhemthIHZpZMOtbWUsIMW+ZSAqKm1lc2HEjW7DqSBob2Rub3R5IHBvxI10dSBvYnl2YXRlxL5vdiBuYSBzZWJhIHBseW51bG8gbmFkdsOkenVqw7oqKiDigJMgdiBzdXNlZG7DvWNoIG1lc2lhY29jaCBzw7ogc2kgdmXEvm1pIHBvZG9ibsOpLiBBayBieSBzbWUgc2kgem9icmF6aWxpIHJlesOtZHXDoSAocm96ZGllbCBtZWR6aSBlbXBpcmlja8O9bWkgYSB2eXJvdm5hbsO9bWkgaG9kbm90YW1pKSwgamUgcHJpcm9kemVuw6kgb8SNYWvDoXZhxaUsIMW+ZSBwb8SNYXMgbmlla2/EvmvDvWNoIHBvIHNlYmUgaWTDumNpY2ggbWVzaWFjb3YgYnVkw7ogbWHFpSBwb2RvYm7DqSB6bmFtaWVua28uIFRvIGplIHR5cGlja8O9IHZpenXDoWxueSBzaWduw6FsIG1vxb5uZWogYXV0b2tvcmVsw6FjaWUuCgpgYGB7cn0KIyB1bG/FvsOtbWUgc2kgcmV6aWR1w6EgeiBww7R2b2Ruw6lobyBtb2RlbHUKcmVzIDwtIHJlc2lkdWFscyhtb2RlbCkKYGBgCgotLS0KCiMjIyMgQUNGIGdyYWYgKEF1dG9jb3JyZWxhdGlvbiBGdW5jdGlvbikKClTDoXRvIGZ1bmtjaWEgcHJpcmHEj3VqZSBvZGhhZCBrb3JlbMOhY2llLCBrdG9yw6EgamUgbWVkemkgamVkbm90bGl2w71taSByZXrDrWR1YW1pCnYgYWt0dcOhbG5vbSBvYmRvYsOtIGEgb2Jkb2LDrSBwb3N1bnV0b20gKExhZykgbyBcKGtcKSBvYmRvYsOtIHNww6TFpS4KCmBgYHtyfQphY2YocmVzLCBsYWcubWF4ID0gNCwgbWFpbiA9ICJBdXRva29yZWxhxI1uw6EgZnVua2NpYSByZXrDrWR1w60iKQpgYGAKCk5hIHRvbXRvIGdyYWZlIGplIG1vZHJvdSBwcmVydcWhb3Zhbm91IMSNaWFyb3UgdnlqYWRyZW7DvSBhaiA5NSAlIGludGVydmFsCnNwb8S+YWhsaXZvc3RpIHByZSBob2Rub3R1IGF1dG9rb3JlbGHEjW7DqWhvIGtvZWZpY2llbnR1IHMgcHLDrXNsdcWhbsO9bSBwb3N1bm9tLgpBayBzYSBuaWVrdG9yw70gc3TEunBlYyBuYWNow6FkemEgbWltbyB0b2h0byBww6FzbWEsIG5hem5hxI11amUgdG8gKirFoXRhdGlzdGlja3kKdsO9em5hbW7DuiBhdXRva29yZWzDoWNpdSoqIHByaSBkYW5vbSBwb3N1bmUuCgotLS0KCiMjIyMgRHVyYmlu4oCTV2F0c29ub3YgdGVzdAoKRHVyYmlu4oCTV2F0c29ub3Yga29lZmljaWVudCAoRFcpIGplIHZ5cG/EjcOtdGFuw70geiByZXrDrWR1w60gcG9kxL5hIHZ6b3JjYQoKXFsKRFcgPSBcZnJhY3tcc3VtX3t0PTJ9XntufSAoZV90IC0gZV97dC0xfSleezJ9fXtcc3VtX3t0PTF9XntufSBlX3ReezJ9fQpcXQoKa2RlIFwoblwpIGplIHBvxI1ldCBwb3pvcm92YW7DrS4gTWVkemkga29lZmljaWVudG9tIGF1dG9rb3JlbMOhY2llIGR2b2NoIHN1c2VkbsO9Y2ggcmV6w61kdcOtIGEgRFcgcGxhdMOtIHByaWJsacW+bsO9IHZ6xaVhaAoKXFsKXGhhdHtccmhvfSBcYXBwcm94IDEgLSBcZnJhY3tEV317Mn0uClxdCgpIb2Rub3R5OgoKLSAqKmJsw616a2UgbnVsZSoqIOKGkiBzaWxuw6EgKipwb3ppdMOtdm5hIGF1dG9rb3JlbMOhY2lhKiosCi0gKipibMOtemtlIDQqKiDihpIgc2lsbsOhICoqbmVnYXTDrXZuYSBhdXRva29yZWzDoWNpYSoqLAotICoqb2tvbG8gMioqIOKGkiDFvmlhZG55IHbDvXJhem7DvSBwcm9ibMOpbSBzIGF1dG9rb3JlbMOhY2lvdS4KClYgcHJheGkgc2EgxI1hc3RvIHBvdcW+w612YSBpbnR1aXTDrXZuZSBwcmF2aWRsbzogYWsgc2EgRFcgbmFjaMOhZHphIHYgaW50ZXJ2YWxlCnByaWJsacW+bmUgKioxLDggYcW+IDIsMioqLCBwcm9ibMOpbSBhdXRva29yZWzDoWNpZSB2w6TEjcWhaW5vdSBuZXBvdmHFvnVqZW1lIHphIHbDocW+bnkuCgpgYGB7cn0KbGlicmFyeShsbXRlc3QpCmR3dGVzdChtb2RlbCkKYGBgCgpEVyB0ZXN0IG3DoSBpc3TDqSBvYm1lZHplbmlhIOKAkyByZWdyZXNvcnkgbmVzbcO6IGJ5xaUgxI1hc292byBwb3N1bnV0w6kgYSBuZXNtw7oKb2JzYWhvdmHFpSBvbmVza29yZW7DqSBwb3pvcm92YW5pYSB2eXN2ZXTEvm92YW5laiB2ZWxpxI1pbnkgYWtvIHJlZ3Jlc29yeS4KVGlldG8gb2JtZWR6ZW5pYSBuZXBsYXRpYSBwcmUgQnJldXNjaOKAk0dvZGZyZXlvdiB0ZXN0LgoKLS0tCgojIyMjIEJyZXVzY2jigJNHb2RmcmV5b3YgdGVzdCAoQkcgdGVzdCkKCiMjIyMjIMSMbyB0ZXN0IHRlc3R1amUKCkJHIHRlc3QgamUgZm9ybcOhbG55bSB0ZXN0b20gKiphdXRva29yZWzDoWNpZSAoc8OpcmlvdmVqIGtvcmVsw6FjaWUpKiogcmV6w61kdcOtOgoKXFsKdV90ID0gXHJob18xIHVfe3QtMX0gKyBccmhvXzIgdV97dC0yfSArIFxjZG90cyArIFxyaG9fcCB1X3t0LXB9ICsgXHZhcmVwc2lsb25fdC4KXF0KClRlc3R1amUsIMSNaSBzw7ogcmV6w61kdcOhIGtvcmVsb3ZhbsOpIHYgxI1hc2UgYcW+IGRvIHLDoWR1IFwocFwpLCDEjW8gamUgdHlwaWNrw6kgcHJlIMSNYXNvdsOpIHJhZHkuCgpOYSByb3pkaWVsIG9kIERXIHRlc3R1OgoKLSB0ZXN0dWplICoqYXV0b2tvcmVsw6FjaXUgcyB2ecWhxaHDrW0gcG9zdW5vbSoqIChsYWcgMSwgMiwgMywg4oCmKSwKLSBmdW5ndWplIGFqIHByaSBtb2RlbG9jaCBzICoqb25lc2tvcmVub3UgdnlzdmV0xL5vdmFub3UgcHJlbWVubm91KiogYWtvIHJlZ3Jlc29yb20sCi0gcHJhY3VqZSBzIG5la29uxaF0YW50bsO9bWkgcmVncmVzb3JtaSAodHJlbmQsIGR1bW15IHByZW1lbm7DqSBhdMSPLikuCgotLS0KCiMjIyMjIEh5cG90w6l6eQoKUHJlIHRlc3QgYXV0b2tvcmVsw6FjaWUgYcW+IGRvIHLDoWR1IFwocFwpOgoKLSAqKk51bG92w6EgaHlwb3TDqXphIFwoSF8wXCkqKjogxb5pYWRuYSBzw6lyaW92w6Ega29yZWzDoWNpYSAgCiAgXFsKICBccmhvXzEgPSBccmhvXzIgPSBcY2RvdHMgPSBccmhvX3AgPSAwCiAgXF0KCi0gKipBbHRlcm5hdMOtdm5hIGh5cG90w6l6YSBcKEhfMVwpKio6IHPDqXJpYSBqZSBhdXRva29yZWxvdmFuw6EgIAogIEFzcG/FiCBqZWRuYSB6IFwoXHJob19qXCkgamUgb2RsacWhbsOhIG9kIG51bHkuCgotLS0KCiMjIyMjIEFrbyBmdW5ndWplIEJHIHRlc3QKCjEuIE9kaGFkbmVtZSBww7R2b2Ruw7ogcmVncmVzaXUgKHUgbsOhcyB0cmVuZG92w70gbW9kZWwpIGEgesOtc2thbWUgcmV6w61kdcOhIFwoZV90XCkuCjIuIFNwdXN0w61tZSBwb21vY27DuiByZWdyZXNpdToKICAgXFsKICAgZV90CiAgID0gXGFscGhhXzAgKyBcYWxwaGFfMSB4X3sxdH0gKyBcY2RvdHMgKyBcYWxwaGFfayB4X3trdH0KICAgKyBccmhvXzEgZV97dC0xfSArIFxjZG90cyArIFxyaG9fcCBlX3t0LXB9ICsgdl90LAogICBcXQogICBrZGUgXCh4X3tqdH1cKSBzw7ogcMO0dm9kbsOpIHJlZ3Jlc29yeS4KMy4gWiB0ZWp0byByZWdyZXNpZSB2eXBvxI3DrXRhbWU6CiAgIFxbCiAgIFx0ZXh0e0JHfSA9IChuIC0gcCkgUl4yX3tcdGV4dHthdXh9fQogICBcXQo0LiBQb2QgXChIXzBcKSBwbGF0w60gcHJpYmxpxb5uZToKICAgXFsKICAgXHRleHR7Qkd9IFxzaW0gXGNoaV4yX3AuCiAgIFxdCgotLS0KCiMjIyMjIEludGVycHJldMOhY2lhCgotICoqVmXEvmvDoSBob2Rub3RhIHRlc3RvdmVqIMWhdGF0aXN0aWt5IEJHIChtYWzDoSBwLWhvZG5vdGEpKiog4oaSIHphbWlldGFtZSBcKEhfMFwpIOKGkiAqKmF1dG9rb3JlbMOhY2lhIHByw610b21uw6EqKi4KLSAqKk1hbMOhIGhvZG5vdGEgQkcgKHZlxL5rw6EgcC1ob2Rub3RhKSoqIOKGkiBuZXphbWlldG5lbWUgXChIXzBcKSDihpIgKipuaWUgamUgZMO0a2F6IGF1dG9rb3JlbMOhY2llKiouCgotLS0KCiMjIyMjICBQcmFrdGlja8O9IHbDvXBvxI1ldCB2IFIKCmBgYHtyfQpiZ3Rlc3QobW9kZWwsIG9yZGVyID0gMSkKYGBgCgpWIG5hxaFpY2ggw7pkYWpvY2ggKG1lc2HEjW7DvSBwb8SNZXQgb2J5dmF0ZcS+b3Ygdm8gdnlicmFuZWogb2JjaSB2IHJva3UgMjAyNCkKc2EgdWvDocW+ZSwgxI1pIEJHIHRlc3QgcG90dnJkw60gYWxlYm8gdnl2csOhdGkgcHLDrXRvbW5vc8WlIGF1dG9rb3JlbMOhY2llIHBydsOpaG8KcsOhZHUuIEFqIGtlxI8gcHJpIGtyw6F0a29tIMSNYXNvdm9tIHJhZGUgKGxlbiAxMiBtZXNpYWNvdikgbmViw712YSB0ZXN0IHByw61sacWhCnNpbG7DvSwgcHJlICoqZGVtb27FoXRyYcSNbsOpIMO6xI1lbHkqKiBwb3XFvmlqZW1lIGFqIHBvc3R1cCBvZHN0csOhbmVuaWEKZMO0c2xlZGtvdiBhdXRva29yZWzDoWNpZSBwb21vY291IGR5bmFtaXrDoWNpZSBtb2RlbHUuCgotLS0KCiMjIEFrbyByaWXFoWnFpSBhdXRva29yZWzDoWNpdQoKIyMjIEtveWNrb3ZhIHRyYW5zZm9ybcOhY2lhIGEgS295Y2tvdmEgcm92bmljYQoKViBwcmVkY2jDoWR6YWrDumNlaiDEjWFzdGkgc21lIHNhIHZlbm92YWxpIGF1dG9rb3JlbMOhY2lpIHJlesOtZHXDrS4gVGVyYXoKcm96xaHDrXJpbWUgbW9kZWwgbyBkeW5hbWlja8O6IMWhdHJ1a3TDunJ1IHphbG/FvmVuw7ogbmEgdHp2LiAqKmdlb21ldHJpY2t5CmtsZXNhasO6Y29tIHJvemxvxb5lbsOtIG9uZXNrb3JlbsO9Y2ggZWZla3RvdioqLiBUYWvDvXRvIG1vZGVsIHNhIG5hesO9dmEKKipLb3lja292IG1vZGVsKiogYSBqZWhvIMO6c3RyZWRuw71tIHBydmtvbSBqZSAqKktveWNrb3ZhIHRyYW5zZm9ybcOhY2lhKiouCgotLS0KCiMjIyMjIFbDvWNob2Rpc2tvdsO9IG1vZGVsIHMgZGlzdHJpYnVvdmFuw71tIG9uZXNrb3JlbsOtbQoKVXZhxb51am1lIG1vZGVsOgoKXFsKeV90ID0gXGFscGhhICsgXGJldGFfMCB4X3QgKyBcYmV0YV8xIHhfe3QtMX0gKyBcYmV0YV8yIHhfe3QtMn0gKyBcY2RvdHMgKyB1X3QuClxdCgotLS0KCiMjIyMjICBLb3lja292YSDFoXRydWt0w7pyYSBrb2VmaWNpZW50b3YKCktveWNrIG5hdnJob2wsIMW+ZSBvbmVza29yZW7DqSBlZmVrdHkgbWFqw7ogKipnZW9tZXRyaWNreSBrbGVzYWrDumN1IHBvZG9idSoqOgoKXFsKXGJldGFfayA9IFxsYW1iZGFeayBcYmV0YV8wLCBccXF1YWQgMCA8IFxsYW1iZGEgPCAxLgpcXQoKVMO9bSBzYSBkaXN0cmlidcSNbsOpIG9uZXNrb3JlbmllIHpqZWRub2R1xaHDrSB0YWssIMW+ZSBuYW1pZXN0byBuZWtvbmXEjW7DqWhvCnBvxI10dSBwYXJhbWV0cm92IG9kaGFkdWplbWUgbGVuOgoKLSBcKFxiZXRhXzBcKSDigJMgb2thbcW+aXTDvSBlZmVrdCwKLSBcKFxsYW1iZGFcKSDigJMgcsO9Y2hsb3PFpSB0bG1lbmlhIGVmZWt0b3Ygb25lc2tvcmVuaWEuCgotLS0KCiMjIyMjIEtveWNrb3ZhIHRyYW5zZm9ybcOhY2lhCgpQw7R2b2Ruw70gbW9kZWw6CgpcWwp5X3QgPSBcYWxwaGEgKyBcYmV0YV8wIHhfdCArIFxsYW1iZGEgXGJldGFfMCB4X3t0LTF9CiAgICAgICsgXGxhbWJkYV4yIFxiZXRhXzAgeF97dC0yfSArIFxjZG90cyArIHVfdC4KXF0KClZ5bsOhc29iw61tZSBtb2RlbCBrb27FoXRhbnRvdSBcKFxsYW1iZGFcKSBhIHBvc3VuaWVtZSDEjWFzb3bDvSBpbmRleCBvIDEgZG96YWR1OgoKXFsKXGxhbWJkYSB5X3t0LTF9ID0gXGxhbWJkYVxhbHBoYSArIFxiZXRhXzAgeF97dC0xfQogICAgICArIFxsYW1iZGEgXGJldGFfMCB4X3t0LTJ9ICsgXGNkb3RzICsgXGxhbWJkYSB1X3t0LTF9LgpcXQoKT2TEjcOtdGFuw61tIG9ib2NoIHbDvXJhem92IGRvc3RhbmVtZToKClxbCnlfdCAtIFxsYW1iZGEgeV97dC0xfQo9IFxhbHBoYSgxLVxsYW1iZGEpICsgXGJldGFfMCAoeF90IC0gXGxhbWJkYSB4X3t0LTF9KQogICsgKHVfdCAtIFxsYW1iZGEgdV97dC0xfSkuClxdCgpUbyBqZSAqKktveWNrb3ZhIHRyYW5zZm9ybcOhY2lhKiouCgotLS0KCiMjIyMjIEtveWNrb3ZhIHJvdm5pY2EgKGF1dG9yZWdyZXPDrXZueSBtb2RlbCkKClBvIGFsZ2VicmFpY2tlaiDDunByYXZlOgoKXFsKeV90ID0gXGFscGhhKDEtXGxhbWJkYSkgKyBcYmV0YV8wIHhfdCArIFxsYW1iZGEgeV97dC0xfSArIHZfdCwKXF0KCmtkZToKClxbCnZfdCA9IHVfdCAtIFxsYW1iZGEgdV97dC0xfS4KXF0KClRvdG8gamUgKipLb3lja292YSByb3ZuaWNhKiog4oCTIGR5bmFtaWNrw70gYXV0b3JlZ3Jlc8Otdm55IG1vZGVsIHNvCnrDoXZpc2xvc8Wlb3UgbmEgbWludWxvc3RpLgoKViBuYcWhb20ga29udGV4dGU6CgotIFwoeV90XCkgPSBwb8SNZXQgb2J5dmF0ZcS+b3YgdiBtZXNpYWNpIFwodFwpLAotIFwoeF90XCkg4oCTIG5hcHLDrWtsYWQgxI1hc292w70gdHJlbmQgKFRpbWUpLAotIFwoeV97dC0xfVwpIOKAkyBwb8SNZXQgb2J5dmF0ZcS+b3YgdiBwcmVkY2jDoWR6YWrDumNvbSBtZXNpYWNpLgoKLS0tCgojIyMgT2RzdHJhxYhvdmFuaWUgcHJvYmzDqW11IGF1dG9rb3JlbMOhY2llIHJlesOtZHXDrQoKIyMjIyBPZGhhZCBLb3lja292aG8gbW9kZWx1IHYgUgoKTmFqamVkbm9kdWNoxaFpYSBpbXBsZW1lbnTDoWNpYSBwcmUgbmHFoWUgw7pkYWplOgoKYGBge3J9CnVkYWplTWVzdG9fbG9uZyA8LSB1ZGFqZU1lc3RvX2xvbmcgJT4lCiAgYXJyYW5nZShUaW1lKSAlPiUKICBtdXRhdGUoCiAgICBQb2NldF9vYnl2YXRlbG92X2xhZzEgPSBkcGx5cjo6bGFnKFBvY2V0X29ieXZhdGVsb3YpCiAgKQoKbW9kZWxfa295Y2sgPC0gbG0oUG9jZXRfb2J5dmF0ZWxvdiB+IFRpbWUgKyBQb2NldF9vYnl2YXRlbG92X2xhZzEsIAogICAgICAgICAgICAgICAgICBkYXRhID0gdWRhamVNZXN0b19sb25nKQoKc3VtbWFyeShtb2RlbF9rb3ljaykKYGBgCgpgYGB7cn0KZHd0ZXN0KG1vZGVsX2tveWNrKQpgYGAKClYgZHluYW1pem92YW5vbSBtb2RlbGkgdnlzdHVwdWplIGFqIG9uZXNrb3JlbsOhIGhvZG5vdGEgdnlzdmV0xL5vdmFuZWogcHJlbWVubmVqCihgUG9jZXRfb2J5dmF0ZWxvdl9sYWcxYCkuIEFrIGplIGplaiBrb2VmaWNpZW50ICoqa2xhZG7DvSBhIG1lbsWhw60gYWtvIDEqKiwgaW50ZXJwcmV0dWplbWUgdG8gdGFrLCDFvmUgKirEjWFzxaUgw7pyb3ZuZSB6IG1pbnVsw6lobyBtZXNpYWNhIHNhIHByZW7DocWhYSBkbyBha3R1w6FsbmVobyBtZXNpYWNhKiogKHpvdHJ2YcSNbm9zxaUpLiBQcmkgaG9kbm90ZW7DrSBrdmFsaXR5IG1vZGVsdSBqZSB2aG9kbsOpIHBvcm92bmHFpSBuYXByw61rbGFkICoqQWRqdXN0ZWQgUi1zcXVhcmVkKiogcMO0dm9kbsOpaG8gYSBkeW5hbWlja8OpaG8gbW9kZWx1LCBwcsOtcGFkbmUgem5vdmEgb3ZlcmnFpSBhdXRva29yZWzDoWNpdSByZXrDrWR1w60gKERXLCBCRyB0ZXN0KS4KCi0tLQoKIyMjIyBOZXdleeKAk1dlc3Qgcm9idXN0bsOpIMWhdGFuZGFyZG7DqSBjaHlieQoKRcWhdGUgamVkbm91IG1vxb5ub3PFpW91LCBha28gcmVhZ292YcWlIG5hIHByw610b21ub3PFpSBhdXRva29yZWzDoWNpZSAoYSBoZXRlcm9za2VkYXN0aWNpdHkpLApqZSBwb3XFvmnFpSAqKnJvYnVzdG7DqSDFoXRhbmRhcmRuw6kgY2h5YnkqKiBwb2TEvmEgTmV3ZXnigJNXZXN0YS4gVGllIG5lbWVuaWEgc2Ftb3Ruw6kKb2RoYWR5IGtvZWZpY2llbnRvdiwgYWxlIGtvcmlndWrDuiBvZGhhZHkgc21lcm9kYWpuw71jaCBvZGNow71sb2suCgpgYGB7cn0KbGlicmFyeShzYW5kd2ljaCkKbGlicmFyeShsbXRlc3QpCgpjb2VmdGVzdChtb2RlbCwgdmNvdiA9IE5ld2V5V2VzdChtb2RlbCkpCmBgYAoKLS0tCgojIyA0LiBaw6F2ZXIKCk5hIGplZG5vZHVjaG9tIHByw61rbGFkZSBtZXNhxI1uw6lobyBwb8SNdHUgb2J5dmF0ZcS+b3Ygdm8gdnlicmFuZWogc2xvdmVuc2tlaiBvYmNpCnYgcm9rdSAyMDI0IHNtZSB1a8OhemFsaToKCi0gYWtvIG9kaGFkbsO6xaUgKip0cmVuZG92w70gbW9kZWwqKiB2IMSNYXNlLAotIGFrbyBncmFmaWNreSBhIMWhdGF0aXN0aWNreSB0ZXN0b3ZhxaUgKiphdXRva29yZWzDoWNpdSByZXrDrWR1w60qKiAoQUNGLCBEdXJiaW7igJNXYXRzb24sIEJHIHRlc3QpLAotIGFrbyBtb8W+bm8gbW9kZWwgKipkeW5hbWl6b3ZhxaUqKiBwb21vY291ICoqS295Y2tvdmVqIHJvdm5pY2UqKiwKLSBhIGFrbyB2eXXFvmnFpSAqKk5ld2V54oCTV2VzdG92ZSByb2J1c3Ruw6kgxaF0YW5kYXJkbsOpIGNoeWJ5KiouCgpBdXRva29yZWzDoWNpYSByZXrDrWR1w60gYSB6IG5laiB2eXBsw712YWrDumNhIHBvdHJlYmEgZHluYW1pesOhY2llIG1vZGVsb3YgbcOhCnYgZWtvbm9tZXRyaWkgdmXEvmvDvSB2w716bmFtLiBUdSBzbWUgdXZpZWRsaSBsZW4gesOha2xhZG7DqSBwcsOtc3R1cHkg4oCTIGsgemxvxb5pdGVqxaHDrW0KcGF0csOtIG5hcHLDrWtsYWQgQWxtb25vdiBtb2RlbCBkaXN0cmlidW92YW7DqWhvIG9uZXNrb3JlbmlhLCBtZXTDs2RhIENvY2hyYW7igJNPcmN1dHQKYWxlYm8gdsWhZW9iZWNuZWrFoWllICoqQVJJTUEgbW9kZWx5KiosIGt0b3LDqSBzYSBwb3XFvsOtdmFqw7ogcHJpIGRsaMWhw61jaCDEjWFzb3bDvWNoIHJhZG9jaC4K