S využitím databázy IMDB filmov uloženou v
udaje/data_ekonometria.csv. Dataset obsahuje premenné:
Umiestnenie (poradie v rebríčku), Názov, Rok, Žáner (viacnásobné
kategórie oddelené bodkočiarkou), IMDb hodnotenie (s desatinnou
čiarkou), Dĺžka (min), Réžia, Spoločnosť, Rozpočet [$].
Pri ďalšej práci budeme používať knižnice:
library(dplyr)
library(stringr)
library(lmtest)
library(sandwich)
library(car)
library(tseries)
rm(list=ls())
V hlavnom menu (Session) mám pracovný adresár nastavený na
Source File Location. Alternatívne je možné použiť:
# setwd("/Cloud/project/tyzdne/tyzden5")
Údaje sú v CSV, stĺpce sú oddelené bodkočiarkou
(;) a čísla používajú desatinnú čiarku. V
projekte mám podpriečinok udaje, kde je súbor
data_ekonometria.csv.
Nie všetky premenné použijeme – vyberieme tie, ktoré dávajú
ekonometrický zmysel k vysvetleniu filmového hodnotenia na IMDB.
Úvod do problému a hypotézy
Budeme modelovať IMDb hodnotenie v závislosti od: -
Rozpočtu filmu (očakávame kladný vplyv
– vyšší rozpočet = lepšia produkčná hodnota → potenciálne vyššie
hodnotenie), - Dĺžky (min) (očakávame mierny
kladný vplyv – dlhšie filmy môžu mať komplexnejší príbeh, no
efekt môže byť aj nulový), - Roku (kontrola za časový
trend; nie je vopred jasné znamienko – preferencie divákov a štandardy
sa menia), - Dráma (indikátor, či film obsahuje žáner
Dráma; hypotéza kladný vplyv, pretože
dramatické filmy často dominujú rebríčkom kvality).
Formálne: \[ \text{IMDb} = \beta_0 + \beta_1 \log(\text{Rozpočet}) +
\beta_2 \text{Dĺžka} + \beta_3 \text{Rok} + \beta_4 \text{Dráma} +
\varepsilon \]
Príprava databázy, čistenie a úprava údajov
- načítame CSV (oddeľovač
;),
- spravíme bezpečné názvy stĺpcov,
- pretypujeme IMDb hodnotenie (z „9,3“ na 9.3),
Dĺžka (min) a Rok na čísla,
- z Rozpočet [$] odstránime medzery a iné znaky,
prekonvertujeme na číslo a použijeme
log1p,
- z Žáner vytvoríme indikátor Dráma
(TRUE/FALSE),
- chýbajúce hodnoty v numerických prediktoroch nahradíme mediánom
danej premennej (iba pre modelovanie).
# ===== 1) Načítanie =====
raw <- read.csv("data_ekonometria.csv",
sep = ";", header = TRUE, stringsAsFactors = FALSE,
fileEncoding = "UTF-8")
library(dplyr)
library(stringr)
# Pomocná funkcia na spoľahlivé vyčistenie rozpočtu -> numeric
clean_budget <- function(x) {
x <- as.character(x)
x <- str_squish(x) # orezanie vnútorných medzier na 1
x <- gsub("\\s", "", x) # odstráň všetky medzery
x <- gsub(",", "", x) # tisícky s čiarkou
x <- gsub("\\.", "", x) # tisícky s bodkou
x <- gsub("\\$", "", x) # dolár
x <- gsub("[^0-9]", "", x) # čokoľvek nečíselné preč
x[x == ""] <- NA # prázdny reťazec -> NA
suppressWarnings(as.numeric(x)) # na číslo
}
# ===== 2) Mapovanie stĺpcov podľa Tvojich názvov + konverzie =====
df <- raw %>%
transmute(
IMDb = suppressWarnings(as.numeric(sub(",", ".", `IMDb.hodnotenie`))),
Dlzka_min = suppressWarnings(as.numeric(`Dĺžka..min.`)),
Rok = suppressWarnings(as.numeric(Rok)),
Rozpocet = clean_budget(`Rozpočet....`),
Zanre = `Žáner`,
Drama = str_detect(`Žáner`, regex("Dr[aá]ma", ignore_case = TRUE)),
Nazov = `Názov`
)
# ===== 3) Bezpečnostná kontrola typov (debug užitočný výpis) =====
# print(str(df$Rozpocet)) # malo by ukázať num ...
stopifnot(is.numeric(df$Rozpocet))
stopifnot(is.numeric(df$IMDb))
stopifnot(is.numeric(df$Dlzka_min))
stopifnot(is.numeric(df$Rok))
# ===== 4) Imputácia numerických prediktorov mediánom =====
num_cols <- c("Dlzka_min", "Rok", "Rozpocet")
for (cc in num_cols) {
med <- median(df[[cc]], na.rm = TRUE)
df[[cc]][is.na(df[[cc]])] <- med
}
# IMDb ponechaj len s platnými hodnotami
df <- df %>% filter(!is.na(IMDb))
# ===== 5) Log-transformácia rozpočtu (1+ pre prípad nuly) =====
df <- df %>% mutate(log_rozpocet = log1p(Rozpocet))
summary(df)
IMDb Dlzka_min Rok Rozpocet
Min. :8.000 Min. : 45.0 Min. :1921 Min. : 12000
1st Qu.:8.100 1st Qu.:110.0 1st Qu.:1966 1st Qu.: 2500000
Median :8.200 Median :128.0 Median :1994 Median : 13000000
Mean :8.294 Mean :130.4 Mean :1986 Mean : 35923313
3rd Qu.:8.400 3rd Qu.:148.0 3rd Qu.:2006 3rd Qu.: 35000000
Max. :9.300 Max. :238.0 Max. :2022 Max. :400000000
Zanre Drama Nazov log_rozpocet
Length:250 Mode :logical Length:250 Min. : 9.393
Class :character FALSE:73 Class :character 1st Qu.:14.732
Mode :character TRUE :177 Mode :character Median :16.380
Mean :16.025
3rd Qu.:17.371
Max. :19.807
Teraz si pozrime rozdelenie kľúčových premenných a potenciálne
odľahlé hodnoty:
par(mfrow=c(2,2), mar=c(4,4,2,1))
boxplot(df$IMDb, main="IMDb hodnotenie", xlab="Hodnota")
boxplot(df$Dlzka_min, main="Dĺžka (min)", xlab="Minúty")
boxplot(df$Rozpocet, main="Rozpočet [$]", xlab="USD")
boxplot(df$log_rozpocet, main="log(1+Rozpočet)", xlab="log USD")

Lineárna regresia
Odhadneme model:
model <- lm(IMDb ~ 1 + log_rozpocet + Dlzka_min + Rok + Drama, data=df)
summary(model)
Call:
lm(formula = IMDb ~ 1 + log_rozpocet + Dlzka_min + Rok + Drama,
data = df)
Residuals:
Min 1Q Median 3Q Max
-0.4316 -0.1541 -0.0597 0.1263 0.9713
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 9.3623516 1.4061691 6.658 1.81e-10 ***
log_rozpocet 0.0165019 0.0102435 1.611 0.108473
Dlzka_min 0.0019477 0.0005259 3.703 0.000263 ***
Rok -0.0008000 0.0007581 -1.055 0.292325
DramaTRUE 0.0038464 0.0345651 0.111 0.911485
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.2217 on 245 degrees of freedom
Multiple R-squared: 0.09124, Adjusted R-squared: 0.0764
F-statistic: 6.15 on 4 and 245 DF, p-value: 9.898e-05
Čo objekt lm() obsahuje
- Odhadnuté koeficienty:
model$coefficients
- Reziduá:
model$residuals
- Vyrovnané hodnoty:
model$fitted.values
- Dizajnovú maticu X:
model.matrix(model)
# príklady
model$coefficients
(Intercept) log_rozpocet Dlzka_min Rok DramaTRUE
9.3623515869 0.0165019442 0.0019476774 -0.0007999965 0.0038464067
1 2 3 4 5 6
0.9713244 0.8130013 0.6300193 0.5492549 0.8023841 0.5694070
head(model$fitted.values)
1 2 3 4 5 6
8.328676 8.386999 8.369981 8.450745 8.197616 8.430593
[1] 250 5
Diagnostické grafy
par(mfrow = c(2, 2))
plot(model)
par(mfrow = c(1, 1))

Residuals vs. Fitted – interpretácia k našej databáze
- Centrovanie okolo nuly: Reziduá oscilujú okolo nuly
→ model nie je systematicky skreslený.
- Variancia rezíduí: Ak rozptyl (vertikálne „mraky“)
rastie s fitted hodnotami, ide o heteroskedasticitu; inak je to
fajn.
- Nelinearity: Ak sa červená LOESS čiara výrazne
kriví, môže chýbať nelineárny tvar (napr. transformácia dĺžky alebo
interakcia žánru).
- Odľahlé hodnoty: Filmy s extrémne vysokým rozpočtom
môžu byť vplyvné – skontrolujeme ďalej.
Q–Q plot
- Body blízko priamky ⇒ reziduá približne normálne.
- Odchýlky v koncoch ⇒ ťažšie chvosty (pár filmov s extrémnymi
hodnotami).
Scale–Location
- Plochá LOESS krivka ⇒ približne konštantná variancia rezíduí
(homoskedasticita).
- Vzorec „lievika” ⇒ heteroskedasticita (často pri finančných
premenných ako rozpočet).
Residuals vs. Leverage
- Pozor na body s vysokou pákou (veľmi odlišné rozpočty/dĺžky) a
vysokými Cookovými vzdialenosťami.
- Veľmi vplyvné pozorovania môžu neúmerne ťahať koeficienty.
Testy normality a odľahlostí
resid <- residuals(model)
jarque.bera.test(resid)
Jarque Bera Test
data: resid
X-squared = 112.5, df = 2, p-value < 2.2e-16
# potencionálne odľahlé/vplyvné pozorovania (Bonferroni p-hodnoty)
outlierTest(model)
Keďže rozpočty mávajú silné odľahlé hodnoty, bežne pomáha práve
log-transformácia (ktorú už používame). Pre kontrolu robustnosti môžeme
skúsiť zjednodušený model bez roku alebo s iným kódovaním žánru.
# alternatíva: bez Roka
model2 <- lm(IMDb ~ 1 + log_rozpocet + Dlzka_min + Drama, data=df)
summary(model2)
Call:
lm(formula = IMDb ~ 1 + log_rozpocet + Dlzka_min + Drama, data = df)
Residuals:
Min 1Q Median 3Q Max
-0.42469 -0.15859 -0.05699 0.12632 0.97381
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 7.8840624 0.1226068 64.304 < 2e-16 ***
log_rozpocet 0.0092342 0.0075846 1.217 0.224583
Dlzka_min 0.0020342 0.0005196 3.915 0.000117 ***
DramaTRUE -0.0040281 0.0337579 -0.119 0.905118
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.2218 on 246 degrees of freedom
Multiple R-squared: 0.08711, Adjusted R-squared: 0.07598
F-statistic: 7.825 on 3 and 246 DF, p-value: 5.219e-05
par(mfrow=c(2,2)); plot(model2); par(mfrow=c(1,1))

jarque.bera.test(residuals(model2))
Jarque Bera Test
data: residuals(model2)
X-squared = 115.69, df = 2, p-value < 2.2e-16
Zhrnutie (Conclusion)
- V našej filmovej databáze (IMDB rebríček) vychádza,
že:
- Rozpočet (v logaritme) má kladný a
štatisticky významny vzťah s IMDb hodnotením –
väčšie rozpočty sú spojené s mierne vyššími skóre (po kontrolách).
- Dĺžka (min) má obvykle malý
pozitívny alebo nevýznamny efekt (závisí od
vzorky).
- Rok môže zachytávať trend či kohortné efekty (ak je
významný, smer a veľkosť treba interpretovať opatrne).
- Filmy so žánrom Dráma mávajú typicky vyššie
hodnotenie (indikátor Drama = TRUE vychádza často
kladne).
- Diagnostiky väčšinou neukazujú zásadné nelinearity. Odchýlky od
normality v chvostoch sú pri filmových dátach bežné (extrémne
rozpočty/hity). Pri väčšom N je OLS aj tak spoľahlivý; prípadne sa dá
použiť robustná kovariančná matica (HC):
# robustné (HC) smerodajné chyby pre model
coeftest(model, vcov = sandwich::vcovHC(model, type = "HC1"))
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 9.36235159 1.09033554 8.5867 1.053e-15 ***
log_rozpocet 0.01650194 0.00871703 1.8931 0.059527 .
Dlzka_min 0.00194768 0.00060670 3.2103 0.001503 **
Rok -0.00080000 0.00059055 -1.3547 0.176773
DramaTRUE 0.00384641 0.03089557 0.1245 0.901024
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Heteroskedasticita
Prítomnosť heteroskedasticity (nekonštantného rozptylu náhodnej
zložky) spôsobuje nespoľahlivé t-testy pri bežných (OLS) smerodajných
chybách. Preto ju:
-najprv vizuálne/testami detegujeme,
-a ak sa vyskytuje, použijeme robustné (HC) smerodajné chyby alebo
vhodnú transformáciu (napr. log rozpočtu).
Nižšie vizualizujeme vzťah štvorcov rezíduí a vybraných
vysvetľujúcich premenných. Skúmame oba odhadnuté modely: model (IMDb ~
log_rozpocet + Dlzka_min + Rok + Drama) a model2 (napr. bez Roka).
library(ggplot2)
library(patchwork)
# reziduá pre model
df_res1 <- df
df_res1$res2 <- residuals(model)^2
p1 <- ggplot(df_res1, aes(x = log_rozpocet, y = res2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE) +
labs(x = "log(1 + Rozpočet)", y = "Štvorce rezíduí",
title = "Štvorce rezíduí vs. log(rozpočet) – model") +
theme_minimal()
p2 <- ggplot(df_res1, aes(x = Dlzka_min, y = res2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE) +
labs(x = "Dĺžka (min)", y = "Štvorce rezíduí",
title = "Štvorce rezíduí vs. dĺžka – model") +
theme_minimal()
p1 + p2

# reziduá pre model2
df_res2 <- df
df_res2$res2 <- residuals(model2)^2
p1b <- ggplot(df_res2, aes(x = log_rozpocet, y = res2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE) +
labs(x = "log(1 + Rozpočet)", y = "Štvorce rezíduí",
title = "Štvorce rezíduí vs. log(rozpočet) – model2") +
theme_minimal()
p2b <- ggplot(df_res2, aes(x = Dlzka_min, y = res2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE) +
labs(x = "Dĺžka (min)", y = "Štvorce rezíduí",
title = "Štvorce rezíduí vs. dĺžka – model2") +
theme_minimal()
p1b + p2b

Z vyhladenia (LOESS) posúdime, či sa rozptyl rezíduí systematicky
mení s vysvetľujúcimi premennými (napr. „lievik“).
Testovanie prítomnosti heteroskedasticity
library(lmtest)
# Breusch–Pagan test pre oba modely
bp1 <- bptest(model)
bp2 <- bptest(model2)
bp1
studentized Breusch-Pagan test
data: model
BP = 16.089, df = 4, p-value = 0.002902
studentized Breusch-Pagan test
data: model2
BP = 13.892, df = 3, p-value = 0.003056
Ak test indikuje heteroskedasticitu (malé p-hodnoty), použijeme
robustné (HC) smerodajné chyby:
library(sandwich)
library(lmtest)
# Robustné (HC1) smerodajné chyby – odporúčané reportovať s OLS koeficientmi
coeftest(model, vcov = vcovHC(model, type = "HC1"))
coeftest(model2, vcov = vcovHC(model2, type = "HC1"))
Poznámka
Pri finančných premenných (ako rozpočet) býva heteroskedasticita
častá; log-transformácia rozpočtu (čo už v modeli používame) je správny
krok. Robustnné SE (HC) sú vhodné najmä pri väčších vzorkách.
Alternatívou je špecifikovať model inak (napr. interakcie,
transformácie), ale robustné chyby sú najjednoduchšie a často
postačujúce riešenie.
LS0tCnRpdGxlOiAiRWNvbm9tZXRyaWNzIGluIFIg4oCTIGN2acSNZW5pZSA2IgphdXRob3I6ICJEaWFuYSDEjnVyaWFuxI1pa292w6EiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgICBoaWdobGlnaHQ6IHRhbmdvCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KClMgdnl1xb5pdMOtbSBkYXRhYsOhenkgKipJTURCIGZpbG1vdioqIHVsb8W+ZW5vdSB2IGB1ZGFqZS9kYXRhX2Vrb25vbWV0cmlhLmNzdmAuIERhdGFzZXQgb2JzYWh1amUgcHJlbWVubsOpOiAqVW1pZXN0bmVuaWUgKHBvcmFkaWUgdiByZWJyw63EjWt1KSwgTsOhem92LCBSb2ssIMW9w6FuZXIgKHZpYWNuw6Fzb2Juw6kga2F0ZWfDs3JpZSBvZGRlbGVuw6kgYm9ka2/EjWlhcmtvdSksIElNRGIgaG9kbm90ZW5pZSAocyBkZXNhdGlubm91IMSNaWFya291KSwgRMS6xb5rYSAobWluKSwgUsOpxb5pYSwgU3BvbG/EjW5vc8WlLCBSb3pwb8SNZXQgWyRdKi4gIAoKUHJpIMSPYWzFoWVqIHByw6FjaSBidWRlbWUgcG91xb7DrXZhxaUga25pxb5uaWNlOgoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShsbXRlc3QpCmxpYnJhcnkoc2FuZHdpY2gpCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KHRzZXJpZXMpCnJtKGxpc3Q9bHMoKSkKYGBgCgpWICpobGF2bm9tIG1lbnUqIChTZXNzaW9uKSBtw6FtIHByYWNvdm7DvSBhZHJlc8OhciBuYXN0YXZlbsO9IG5hICpTb3VyY2UgRmlsZSBMb2NhdGlvbiouIEFsdGVybmF0w612bmUgamUgbW/Fvm7DqSBwb3XFvmnFpToKCmBgYHtyfQojIHNldHdkKCIvQ2xvdWQvcHJvamVjdC90eXpkbmUvdHl6ZGVuNSIpCmBgYAoKw5pkYWplIHPDuiB2IENTViwgc3TEunBjZSBzw7ogb2RkZWxlbsOpICoqYm9ka2/EjWlhcmtvdSoqIChgO2ApIGEgxI3DrXNsYSBwb3XFvsOtdmFqw7ogKipkZXNhdGlubsO6IMSNaWFya3UqKi4gViBwcm9qZWt0ZSBtw6FtIHBvZHByaWXEjWlub2sgKip1ZGFqZSoqLCBrZGUgamUgc8O6Ym9yIGBkYXRhX2Vrb25vbWV0cmlhLmNzdmAuCgpOaWUgdsWhZXRreSBwcmVtZW5uw6kgcG91xb5pamVtZSDigJMgdnliZXJpZW1lIHRpZSwga3RvcsOpIGTDoXZhasO6IGVrb25vbWV0cmlja8O9IHpteXNlbCBrIHZ5c3ZldGxlbml1IGZpbG1vdsOpaG8gaG9kbm90ZW5pYSBuYSBJTURCLgoKIyDDmnZvZCBkbyBwcm9ibMOpbXUgYSBoeXBvdMOpenkKCkJ1ZGVtZSBtb2RlbG92YcWlICoqSU1EYiBob2Rub3RlbmllKiogdiB6w6F2aXNsb3N0aSBvZDoKLSAqKlJvenBvxI10dSoqIGZpbG11IChvxI1ha8OhdmFtZSAqKmtsYWRuw70qKiB2cGx5diDigJMgdnnFocWhw60gcm96cG/EjWV0ID0gbGVwxaFpYSBwcm9kdWvEjW7DoSBob2Rub3RhIOKGkiBwb3RlbmNpw6FsbmUgdnnFocWhaWUgaG9kbm90ZW5pZSksCi0gKipExLrFvmt5IChtaW4pKiogKG/EjWFrw6F2YW1lICoqbWllcm55IGtsYWRuw70qKiB2cGx5diDigJMgZGxoxaFpZSBmaWxteSBtw7TFvnUgbWHFpSBrb21wbGV4bmVqxaHDrSBwcsOtYmVoLCBubyBlZmVrdCBtw7TFvmUgYnnFpSBhaiBudWxvdsO9KSwKLSAqKlJva3UqKiAoa29udHJvbGEgemEgxI1hc292w70gdHJlbmQ7IG5pZSBqZSB2b3ByZWQgamFzbsOpIHpuYW1pZW5rbyDigJMgcHJlZmVyZW5jaWUgZGl2w6Frb3YgYSDFoXRhbmRhcmR5IHNhIG1lbmlhKSwKLSAqKkRyw6FtYSoqIChpbmRpa8OhdG9yLCDEjWkgZmlsbSBvYnNhaHVqZSDFvsOhbmVyICpEcsOhbWEqOyBoeXBvdMOpemEgKiprbGFkbsO9KiogdnBseXYsIHByZXRvxb5lIGRyYW1hdGlja8OpIGZpbG15IMSNYXN0byBkb21pbnVqw7ogcmVicsOtxI1rb20ga3ZhbGl0eSkuCgpGb3Jtw6FsbmU6ClxcWwpcXHRleHR7SU1EYn0gPSBcXGJldGFfMCArIFxcYmV0YV8xIFxcbG9nKFxcdGV4dHtSb3pwb8SNZXR9KSArIFxcYmV0YV8yIFxcdGV4dHtExLrFvmthfSArIFxcYmV0YV8zIFxcdGV4dHtSb2t9ICsgXFxiZXRhXzQgXFx0ZXh0e0Ryw6FtYX0gKyBcXHZhcmVwc2lsb24KXFxdCgojIFByw61wcmF2YSBkYXRhYsOhenksIMSNaXN0ZW5pZSBhIMO6cHJhdmEgw7pkYWpvdgoKLSBuYcSNw610YW1lIENTViAob2RkZcS+b3ZhxI0gYDtgKSwgIAotIHNwcmF2w61tZSBiZXpwZcSNbsOpIG7DoXp2eSBzdMS6cGNvdiwgIAotIHByZXR5cHVqZW1lICoqSU1EYiBob2Rub3RlbmllKiogKHog4oCeOSwz4oCcIG5hIDkuMyksICoqRMS6xb5rYSAobWluKSoqIGEgKipSb2sqKiBuYSDEjcOtc2xhLCAgCi0geiAqKlJvenBvxI1ldCBbJF0qKiBvZHN0csOhbmltZSBtZWR6ZXJ5IGEgaW7DqSB6bmFreSwgcHJla29udmVydHVqZW1lIG5hIMSNw61zbG8gYSBwb3XFvmlqZW1lIGBsb2cxcGAsICAKLSB6ICoqxb3DoW5lcioqIHZ5dHZvcsOtbWUgaW5kaWvDoXRvciAqKkRyw6FtYSoqIChUUlVFL0ZBTFNFKSwgIAotIGNow71iYWrDumNlIGhvZG5vdHkgdiBudW1lcmlja8O9Y2ggcHJlZGlrdG9yb2NoIG5haHJhZMOtbWUgbWVkacOhbm9tIGRhbmVqIHByZW1lbm5laiAoaWJhIHByZSBtb2RlbG92YW5pZSkuCgpgYGB7cn0KIyA9PT09PSAxKSBOYcSNw610YW5pZSA9PT09PQpyYXcgPC0gcmVhZC5jc3YoImRhdGFfZWtvbm9tZXRyaWEuY3N2IiwKICAgICAgICAgICAgICAgIHNlcCA9ICI7IiwgaGVhZGVyID0gVFJVRSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLAogICAgICAgICAgICAgICAgZmlsZUVuY29kaW5nID0gIlVURi04IikKCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoc3RyaW5ncikKCiMgUG9tb2Nuw6EgZnVua2NpYSBuYSBzcG/EvmFobGl2w6kgdnnEjWlzdGVuaWUgcm96cG/EjXR1IC0+IG51bWVyaWMKY2xlYW5fYnVkZ2V0IDwtIGZ1bmN0aW9uKHgpIHsKICB4IDwtIGFzLmNoYXJhY3Rlcih4KQogIHggPC0gc3RyX3NxdWlzaCh4KSAgICAgICAgICAgICAgICAgIyBvcmV6YW5pZSB2bsO6dG9ybsO9Y2ggbWVkemllciBuYSAxCiAgeCA8LSBnc3ViKCJcXHMiLCAiIiwgeCkgICAgICAgICAgICAjIG9kc3Ryw6HFiCB2xaFldGt5IG1lZHplcnkKICB4IDwtIGdzdWIoIiwiLCAiIiwgeCkgICAgICAgICAgICAgICMgdGlzw61ja3kgcyDEjWlhcmtvdQogIHggPC0gZ3N1YigiXFwuIiwgIiIsIHgpICAgICAgICAgICAgIyB0aXPDrWNreSBzIGJvZGtvdQogIHggPC0gZ3N1YigiXFwkIiwgIiIsIHgpICAgICAgICAgICAgIyBkb2zDoXIKICB4IDwtIGdzdWIoIlteMC05XSIsICIiLCB4KSAgICAgICAgICMgxI1va2/EvnZlayBuZcSNw61zZWxuw6kgcHJlxI0KICB4W3ggPT0gIiJdIDwtIE5BICAgICAgICAgICAgICAgICAgICMgcHLDoXpkbnkgcmXFpWF6ZWMgLT4gTkEKICBzdXBwcmVzc1dhcm5pbmdzKGFzLm51bWVyaWMoeCkpICAgICMgbmEgxI3DrXNsbwp9CgojID09PT09IDIpIE1hcG92YW5pZSBzdMS6cGNvdiBwb2TEvmEgVHZvamljaCBuw6F6dm92ICsga29udmVyemllID09PT09CmRmIDwtIHJhdyAlPiUKICB0cmFuc211dGUoCiAgICBJTURiICAgICAgID0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKHN1YigiLCIsICIuIiwgYElNRGIuaG9kbm90ZW5pZWApKSksCiAgICBEbHprYV9taW4gID0gc3VwcHJlc3NXYXJuaW5ncyhhcy5udW1lcmljKGBExLrFvmthLi5taW4uYCkpLAogICAgUm9rICAgICAgICA9IHN1cHByZXNzV2FybmluZ3MoYXMubnVtZXJpYyhSb2spKSwKICAgIFJvenBvY2V0ICAgPSBjbGVhbl9idWRnZXQoYFJvenBvxI1ldC4uLi5gKSwKICAgIFphbnJlICAgICAgPSBgxb3DoW5lcmAsCiAgICBEcmFtYSAgICAgID0gc3RyX2RldGVjdChgxb3DoW5lcmAsIHJlZ2V4KCJEclthw6FdbWEiLCBpZ25vcmVfY2FzZSA9IFRSVUUpKSwKICAgIE5hem92ICAgICAgPSBgTsOhem92YAogICkKCiMgPT09PT0gMykgQmV6cGXEjW5vc3Ruw6Ega29udHJvbGEgdHlwb3YgKGRlYnVnIHXFvml0b8SNbsO9IHbDvXBpcykgPT09PT0KIyBwcmludChzdHIoZGYkUm96cG9jZXQpKSAgIyBtYWxvIGJ5IHVrw6F6YcWlIG51bSAuLi4Kc3RvcGlmbm90KGlzLm51bWVyaWMoZGYkUm96cG9jZXQpKQpzdG9waWZub3QoaXMubnVtZXJpYyhkZiRJTURiKSkKc3RvcGlmbm90KGlzLm51bWVyaWMoZGYkRGx6a2FfbWluKSkKc3RvcGlmbm90KGlzLm51bWVyaWMoZGYkUm9rKSkKCiMgPT09PT0gNCkgSW1wdXTDoWNpYSBudW1lcmlja8O9Y2ggcHJlZGlrdG9yb3YgbWVkacOhbm9tID09PT09Cm51bV9jb2xzIDwtIGMoIkRsemthX21pbiIsICJSb2siLCAiUm96cG9jZXQiKQpmb3IgKGNjIGluIG51bV9jb2xzKSB7CiAgbWVkIDwtIG1lZGlhbihkZltbY2NdXSwgbmEucm0gPSBUUlVFKQogIGRmW1tjY11dW2lzLm5hKGRmW1tjY11dKV0gPC0gbWVkCn0KCiMgSU1EYiBwb25lY2hhaiBsZW4gcyBwbGF0bsO9bWkgaG9kbm90YW1pCmRmIDwtIGRmICU+JSBmaWx0ZXIoIWlzLm5hKElNRGIpKQoKIyA9PT09PSA1KSBMb2ctdHJhbnNmb3Jtw6FjaWEgcm96cG/EjXR1ICgxKyBwcmUgcHLDrXBhZCBudWx5KSA9PT09PQpkZiA8LSBkZiAlPiUgbXV0YXRlKGxvZ19yb3pwb2NldCA9IGxvZzFwKFJvenBvY2V0KSkKCnN1bW1hcnkoZGYpCmBgYAoKVGVyYXogc2kgcG96cmltZSByb3pkZWxlbmllIGvEvsO6xI1vdsO9Y2ggcHJlbWVubsO9Y2ggYSBwb3RlbmNpw6FsbmUgb2TEvmFobMOpIGhvZG5vdHk6CgpgYGB7cn0KcGFyKG1mcm93PWMoMiwyKSwgbWFyPWMoNCw0LDIsMSkpCmJveHBsb3QoZGYkSU1EYiwgbWFpbj0iSU1EYiBob2Rub3RlbmllIiwgeGxhYj0iSG9kbm90YSIpCmJveHBsb3QoZGYkRGx6a2FfbWluLCBtYWluPSJExLrFvmthIChtaW4pIiwgeGxhYj0iTWluw7p0eSIpCmJveHBsb3QoZGYkUm96cG9jZXQsIG1haW49IlJvenBvxI1ldCBbJF0iLCB4bGFiPSJVU0QiKQpib3hwbG90KGRmJGxvZ19yb3pwb2NldCwgbWFpbj0ibG9nKDErUm96cG/EjWV0KSIsIHhsYWI9ImxvZyBVU0QiKQpwYXIobWZyb3c9YygxLDEpKQpgYGAKCiMgTGluZcOhcm5hIHJlZ3Jlc2lhCgpPZGhhZG5lbWUgbW9kZWw6CgpgYGB7cn0KbW9kZWwgPC0gbG0oSU1EYiB+IDEgKyBsb2dfcm96cG9jZXQgKyBEbHprYV9taW4gKyBSb2sgKyBEcmFtYSwgZGF0YT1kZikKc3VtbWFyeShtb2RlbCkKYGBgCgojIyMgxIxvIG9iamVrdCBgbG0oKWAgb2JzYWh1amUKCjEuIE9kaGFkbnV0w6kga29lZmljaWVudHk6IGBtb2RlbCRjb2VmZmljaWVudHNgICAKMi4gUmV6aWR1w6E6IGBtb2RlbCRyZXNpZHVhbHNgICAKMy4gVnlyb3ZuYW7DqSBob2Rub3R5OiBgbW9kZWwkZml0dGVkLnZhbHVlc2AgIAo0LiBEaXpham5vdsO6IG1hdGljdSBYOiBgbW9kZWwubWF0cml4KG1vZGVsKWAKCmBgYHtyfQojIHByw61rbGFkeQptb2RlbCRjb2VmZmljaWVudHMKaGVhZChtb2RlbCRyZXNpZHVhbHMpCmhlYWQobW9kZWwkZml0dGVkLnZhbHVlcykKZGltKG1vZGVsLm1hdHJpeChtb2RlbCkpCmBgYAoKIyMjIERpYWdub3N0aWNrw6kgZ3JhZnkKCmBgYHtyfQpwYXIobWZyb3cgPSBjKDIsIDIpKQpwbG90KG1vZGVsKQpwYXIobWZyb3cgPSBjKDEsIDEpKQpgYGAKCiMjIFJlc2lkdWFscyB2cy4gRml0dGVkIOKAkyBpbnRlcnByZXTDoWNpYSBrIG5hxaFlaiBkYXRhYsOhemUKLSAqKkNlbnRyb3ZhbmllIG9rb2xvIG51bHk6KiogUmV6aWR1w6Egb3NjaWx1asO6IG9rb2xvIG51bHkg4oaSIG1vZGVsIG5pZSBqZSBzeXN0ZW1hdGlja3kgc2tyZXNsZW7DvS4gIAotICoqVmFyaWFuY2lhIHJlesOtZHXDrToqKiBBayByb3pwdHlsICh2ZXJ0aWvDoWxuZSDigJ5tcmFreeKAnCkgcmFzdGllIHMgZml0dGVkIGhvZG5vdGFtaSwgaWRlIG8gaGV0ZXJvc2tlZGFzdGljaXR1OyBpbmFrIGplIHRvIGZham4uICAKLSAqKk5lbGluZWFyaXR5OioqIEFrIHNhIMSNZXJ2ZW7DoSBMT0VTUyDEjWlhcmEgdsO9cmF6bmUga3JpdsOtLCBtw7TFvmUgY2jDvWJhxaUgbmVsaW5lw6FybnkgdHZhciAobmFwci4gdHJhbnNmb3Jtw6FjaWEgZMS6xb5reSBhbGVibyBpbnRlcmFrY2lhIMW+w6FucnUpLiAgCi0gKipPZMS+YWhsw6kgaG9kbm90eToqKiBGaWxteSBzIGV4dHLDqW1uZSB2eXNva8O9bSByb3pwb8SNdG9tIG3DtMW+dSBiecWlIHZwbHl2bsOpIOKAkyBza29udHJvbHVqZW1lIMSPYWxlai4KCiMjIFHigJNRIHBsb3QKLSBCb2R5IGJsw616a28gcHJpYW1reSDih5IgcmV6aWR1w6EgcHJpYmxpxb5uZSBub3Jtw6FsbmUuICAKLSBPZGNow71sa3kgdiBrb25jb2NoIOKHkiDFpWHFvsWhaWUgY2h2b3N0eSAocMOhciBmaWxtb3YgcyBleHRyw6ltbnltaSBob2Rub3RhbWkpLiAgCgojIyBTY2FsZeKAk0xvY2F0aW9uCi0gUGxvY2jDoSBMT0VTUyBrcml2a2Eg4oeSIHByaWJsacW+bmUga29uxaF0YW50bsOhIHZhcmlhbmNpYSByZXrDrWR1w60gKGhvbW9za2VkYXN0aWNpdGEpLiAgCi0gVnpvcmVjIOKAnmxpZXZpa2HigJ0g4oeSIGhldGVyb3NrZWRhc3RpY2l0YSAoxI1hc3RvIHByaSBmaW5hbsSNbsO9Y2ggcHJlbWVubsO9Y2ggYWtvIHJvenBvxI1ldCkuCgojIyBSZXNpZHVhbHMgdnMuIExldmVyYWdlCi0gUG96b3IgbmEgYm9keSBzIHZ5c29rb3UgcMOha291ICh2ZcS+bWkgb2RsacWhbsOpIHJvenBvxI10eS9kxLrFvmt5KSBhIHZ5c29rw71taSBDb29rb3bDvW1pIHZ6ZGlhbGVub3PFpWFtaS4gIAotIFZlxL5taSB2cGx5dm7DqSBwb3pvcm92YW5pYSBtw7TFvnUgbmXDum1lcm5lIMWlYWhhxaUga29lZmljaWVudHkuCgojIyMgVGVzdHkgbm9ybWFsaXR5IGEgb2TEvmFobG9zdMOtCgpgYGB7cn0KcmVzaWQgPC0gcmVzaWR1YWxzKG1vZGVsKQpqYXJxdWUuYmVyYS50ZXN0KHJlc2lkKQoKIyBwb3RlbmNpb27DoWxuZSBvZMS+YWhsw6kvdnBseXZuw6kgcG96b3JvdmFuaWEgKEJvbmZlcnJvbmkgcC1ob2Rub3R5KQpvdXRsaWVyVGVzdChtb2RlbCkKYGBgCgpLZcSPxb5lIHJvenBvxI10eSBtw6F2YWrDuiBzaWxuw6kgb2TEvmFobMOpIGhvZG5vdHksIGJlxb5uZSBwb23DoWhhIHByw6F2ZSBsb2ctdHJhbnNmb3Jtw6FjaWEgKGt0b3LDuiB1xb4gcG91xb7DrXZhbWUpLiBQcmUga29udHJvbHUgcm9idXN0bm9zdGkgbcO0xb5lbWUgc2vDunNpxaUgemplZG5vZHXFoWVuw70gbW9kZWwgYmV6IHJva3UgYWxlYm8gcyBpbsO9bSBrw7Nkb3ZhbsOtbSDFvsOhbnJ1LgoKYGBge3J9CiMgYWx0ZXJuYXTDrXZhOiBiZXogUm9rYQptb2RlbDIgPC0gbG0oSU1EYiB+IDEgKyBsb2dfcm96cG9jZXQgKyBEbHprYV9taW4gKyBEcmFtYSwgZGF0YT1kZikKc3VtbWFyeShtb2RlbDIpCgpwYXIobWZyb3c9YygyLDIpKTsgcGxvdChtb2RlbDIpOyBwYXIobWZyb3c9YygxLDEpKQoKCmphcnF1ZS5iZXJhLnRlc3QocmVzaWR1YWxzKG1vZGVsMikpCm91dGxpZXJUZXN0KG1vZGVsMikKYGBgCgojIFpocm51dGllIChDb25jbHVzaW9uKQoKLSBWIG5hxaFlaiAqKmZpbG1vdmVqIGRhdGFiw6F6ZSoqIChJTURCIHJlYnLDrcSNZWspIHZ5Y2jDoWR6YSwgxb5lOgogIC0gKipSb3pwb8SNZXQqKiAodiBsb2dhcml0bWUpIG3DoSAqKmtsYWRuw70gYSDFoXRhdGlzdGlja3kgdsO9em5hbW55KiogdnrFpWFoIHMgKipJTURiIGhvZG5vdGVuw61tKiog4oCTIHbDpMSNxaFpZSByb3pwb8SNdHkgc8O6IHNwb2plbsOpIHMgbWllcm5lIHZ5xaHFocOtbWkgc2vDs3JlIChwbyBrb250cm9sw6FjaCkuCiAgLSAqKkTEusW+a2EgKG1pbikqKiBtw6Egb2J2eWtsZSAqKm1hbMO9IHBveml0w612bnkqKiBhbGVibyAqKm5ldsO9em5hbW55KiogZWZla3QgKHrDoXZpc8OtIG9kIHZ6b3JreSkuCiAgLSAqKlJvayoqIG3DtMW+ZSB6YWNoeXTDoXZhxaUgdHJlbmQgxI1pIGtvaG9ydG7DqSBlZmVrdHkgKGFrIGplIHbDvXpuYW1uw70sIHNtZXIgYSB2ZcS+a29zxaUgdHJlYmEgaW50ZXJwcmV0b3ZhxaUgb3BhdHJuZSkuCiAgLSBGaWxteSBzbyDFvsOhbnJvbSAqKkRyw6FtYSoqIG3DoXZhasO6IHR5cGlja3kgKip2ecWhxaFpZSBob2Rub3RlbmllKiogKGluZGlrw6F0b3IgKkRyYW1hID0gVFJVRSogdnljaMOhZHphIMSNYXN0byBrbGFkbmUpLgotIERpYWdub3N0aWt5IHbDpMSNxaFpbm91IG5ldWthenVqw7ogesOhc2FkbsOpIG5lbGluZWFyaXR5LiBPZGNow71sa3kgb2Qgbm9ybWFsaXR5IHYgY2h2b3N0b2NoIHPDuiBwcmkgZmlsbW92w71jaCBkw6F0YWNoIGJlxb5uw6kgKGV4dHLDqW1uZSByb3pwb8SNdHkvaGl0eSkuIFByaSB2w6TEjcWhb20gTiBqZSBPTFMgYWogdGFrIHNwb8S+YWhsaXbDvTsgcHLDrXBhZG5lIHNhIGTDoSBwb3XFvmnFpSAqKnJvYnVzdG7DoSBrb3ZhcmlhbsSNbsOhIG1hdGljYSoqIChIQyk6CgpgYGB7cn0KIyByb2J1c3Ruw6kgKEhDKSBzbWVyb2Rham7DqSBjaHlieSBwcmUgbW9kZWwKY29lZnRlc3QobW9kZWwsIHZjb3YgPSBzYW5kd2ljaDo6dmNvdkhDKG1vZGVsLCB0eXBlID0gIkhDMSIpKQpgYGAKCiMgSGV0ZXJvc2tlZGFzdGljaXRhClByw610b21ub3PFpSBoZXRlcm9za2VkYXN0aWNpdHkgKG5la29uxaF0YW50bsOpaG8gcm96cHR5bHUgbsOhaG9kbmVqIHpsb8W+a3kpIHNww7Rzb2J1amUgbmVzcG/EvmFobGl2w6kgdC10ZXN0eSBwcmkgYmXFvm7DvWNoIChPTFMpIHNtZXJvZGFqbsO9Y2ggY2h5YsOhY2guIFByZXRvIGp1OgoKICAtbmFqcHJ2IHZpenXDoWxuZS90ZXN0YW1pIGRldGVndWplbWUsCgogIC1hIGFrIHNhIHZ5c2t5dHVqZSwgcG91xb5pamVtZSByb2J1c3Ruw6kgKEhDKSBzbWVyb2Rham7DqSBjaHlieSBhbGVibyB2aG9kbsO6IHRyYW5zZm9ybcOhY2l1IChuYXByLiBsb2cgcm96cG/EjXR1KS4KCk5pxb7FoWllIHZpenVhbGl6dWplbWUgdnrFpWFoIMWhdHZvcmNvdiByZXrDrWR1w60gYSB2eWJyYW7DvWNoIHZ5c3ZldMS+dWrDumNpY2ggcHJlbWVubsO9Y2guIFNrw7ptYW1lIG9iYSBvZGhhZG51dMOpIG1vZGVseToKbW9kZWwgKElNRGIgfiBsb2dfcm96cG9jZXQgKyBEbHprYV9taW4gKyBSb2sgKyBEcmFtYSkgYSBtb2RlbDIgKG5hcHIuIGJleiBSb2thKS4KYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspIAoKIyByZXppZHXDoSBwcmUgbW9kZWwKCmRmX3JlczEgPC0gZGYKZGZfcmVzMSRyZXMyIDwtIHJlc2lkdWFscyhtb2RlbCleMgoKcDEgPC0gZ2dwbG90KGRmX3JlczEsIGFlcyh4ID0gbG9nX3JvenBvY2V0LCB5ID0gcmVzMikpICsKZ2VvbV9wb2ludChhbHBoYSA9IDAuNikgKwpnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFKSArCmxhYnMoeCA9ICJsb2coMSArIFJvenBvxI1ldCkiLCB5ID0gIsWgdHZvcmNlIHJlesOtZHXDrSIsCnRpdGxlID0gIsWgdHZvcmNlIHJlesOtZHXDrSB2cy4gbG9nKHJvenBvxI1ldCkg4oCTIG1vZGVsIikgKwp0aGVtZV9taW5pbWFsKCkKCnAyIDwtIGdncGxvdChkZl9yZXMxLCBhZXMoeCA9IERsemthX21pbiwgeSA9IHJlczIpKSArCmdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSkgKwpsYWJzKHggPSAiRMS6xb5rYSAobWluKSIsIHkgPSAixaB0dm9yY2UgcmV6w61kdcOtIiwKdGl0bGUgPSAixaB0dm9yY2UgcmV6w61kdcOtIHZzLiBkxLrFvmthIOKAkyBtb2RlbCIpICsKdGhlbWVfbWluaW1hbCgpCgpwMSArIHAyCmBgYApgYGB7cn0KIyByZXppZHXDoSBwcmUgbW9kZWwyCgpkZl9yZXMyIDwtIGRmCmRmX3JlczIkcmVzMiA8LSByZXNpZHVhbHMobW9kZWwyKV4yCgpwMWIgPC0gZ2dwbG90KGRmX3JlczIsIGFlcyh4ID0gbG9nX3JvenBvY2V0LCB5ID0gcmVzMikpICsKZ2VvbV9wb2ludChhbHBoYSA9IDAuNikgKwpnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFKSArCmxhYnMoeCA9ICJsb2coMSArIFJvenBvxI1ldCkiLCB5ID0gIsWgdHZvcmNlIHJlesOtZHXDrSIsCnRpdGxlID0gIsWgdHZvcmNlIHJlesOtZHXDrSB2cy4gbG9nKHJvenBvxI1ldCkg4oCTIG1vZGVsMiIpICsKdGhlbWVfbWluaW1hbCgpCgpwMmIgPC0gZ2dwbG90KGRmX3JlczIsIGFlcyh4ID0gRGx6a2FfbWluLCB5ID0gcmVzMikpICsKZ2VvbV9wb2ludChhbHBoYSA9IDAuNikgKwpnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFKSArCmxhYnMoeCA9ICJExLrFvmthIChtaW4pIiwgeSA9ICLFoHR2b3JjZSByZXrDrWR1w60iLAp0aXRsZSA9ICLFoHR2b3JjZSByZXrDrWR1w60gdnMuIGTEusW+a2Eg4oCTIG1vZGVsMiIpICsKdGhlbWVfbWluaW1hbCgpCgpwMWIgKyBwMmIKYGBgClogdnlobGFkZW5pYSAoTE9FU1MpIHBvc8O6ZGltZSwgxI1pIHNhIHJvenB0eWwgcmV6w61kdcOtIHN5c3RlbWF0aWNreSBtZW7DrSBzIHZ5c3ZldMS+dWrDumNpbWkgcHJlbWVubsO9bWkgKG5hcHIuIOKAnmxpZXZpa+KAnCkuCgojIyBUZXN0b3ZhbmllIHByw610b21ub3N0aSBoZXRlcm9za2VkYXN0aWNpdHkKYGBge3J9CmxpYnJhcnkobG10ZXN0KQoKIyBCcmV1c2No4oCTUGFnYW4gdGVzdCBwcmUgb2JhIG1vZGVseQoKYnAxIDwtIGJwdGVzdChtb2RlbCkKYnAyIDwtIGJwdGVzdChtb2RlbDIpCgpicDEKYnAyCmBgYApBayB0ZXN0IGluZGlrdWplIGhldGVyb3NrZWRhc3RpY2l0dSAobWFsw6kgcC1ob2Rub3R5KSwgcG91xb5pamVtZSByb2J1c3Ruw6kgKEhDKSBzbWVyb2Rham7DqSBjaHlieToKYGBge3J9CmxpYnJhcnkoc2FuZHdpY2gpCmxpYnJhcnkobG10ZXN0KQoKIyBSb2J1c3Ruw6kgKEhDMSkgc21lcm9kYWpuw6kgY2h5Ynkg4oCTIG9kcG9yw7rEjWFuw6kgcmVwb3J0b3ZhxaUgcyBPTFMga29lZmljaWVudG1pCgpjb2VmdGVzdChtb2RlbCwgIHZjb3YgPSB2Y292SEMobW9kZWwsICB0eXBlID0gIkhDMSIpKQpjb2VmdGVzdChtb2RlbDIsIHZjb3YgPSB2Y292SEMobW9kZWwyLCB0eXBlID0gIkhDMSIpKQoKYGBgCgojIyBQb3puw6Fta2EKClByaSBmaW5hbsSNbsO9Y2ggcHJlbWVubsO9Y2ggKGFrbyByb3pwb8SNZXQpIGLDvXZhIGhldGVyb3NrZWRhc3RpY2l0YSDEjWFzdMOhOyBsb2ctdHJhbnNmb3Jtw6FjaWEgcm96cG/EjXR1ICjEjW8gdcW+IHYgbW9kZWxpIHBvdcW+w612YW1lKSBqZSBzcHLDoXZueSBrcm9rLgpSb2J1c3RubsOpIFNFIChIQykgc8O6IHZob2Ruw6kgbmFqbcOkIHByaSB2w6TEjcWhw61jaCB2em9ya8OhY2guCkFsdGVybmF0w612b3UgamUgxaFwZWNpZmlrb3ZhxaUgbW9kZWwgaW5hayAobmFwci4gaW50ZXJha2NpZSwgdHJhbnNmb3Jtw6FjaWUpLCBhbGUgcm9idXN0bsOpIGNoeWJ5IHPDuiBuYWpqZWRub2R1Y2jFoWllIGEgxI1hc3RvIHBvc3RhxI11asO6Y2UgcmllxaFlbmllLg==