Analýza meteorologických ukazovateľov
Úvod do problému a stanovenie hypotézy
Cieľom analýzy je modelovať strednú dennú teplotu v Bazileji
(BASEL_temp_mean) na základe viacerých meteorologických premenných:
oblačnosť (BASEL_cloud_cover),
vlhkosť (BASEL_humidity),
tlak vzduchu (BASEL_pressure),
globálne žiarenie (BASEL_global_radiation),
zrážky (BASEL_precipitation),
slnečný svit (BASEL_sunshine) a minimálnu a maximálnu teplotu
(BASEL_temp_min, BASEL_temp_max).
Pracovná hypotéza predpokladá, že tieto premenné významne ovplyvňujú
strednú teplotu – napríklad vyššie globálne žiarenie alebo slnečný svit
by mali viesť k vyšším teplotám, zatiaľ čo väčšia oblačnosť môže teplotu
znižovať. Cieľom analýzy je overiť túto hypotézu pomocou lineárneho
regresného modelu, posúdiť význam jednotlivých premenných a
skontrolovať, či model spĺňa predpoklady lineárnej regresie, ako sú
normalita rezíduí a konštantný rozptyl (homoskedasticita).
Na začiatku analýzy budeme najprv načítať potrebné knižnice,
vyčistíme pracovné prostredie, načítame súbor
weather_prediction_dataset.csv, vyberieme kľúčové stĺpce a doplníme
chýbajúce hodnoty mediánom, aby boli údaje pripravené na ďalšie
spracovanie.
Načítanie knižníc
library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)
library(ggplot2)
library(cowplot)
Vyčistenie pracovného prostredia
Načítanie údajov
udaje <- read.csv("weather_prediction_dataset.csv")
Výber potrebných stĺpcov
weather_data <- udaje[, c("BASEL_cloud_cover", "BASEL_humidity", "BASEL_pressure",
"BASEL_global_radiation", "BASEL_precipitation", "BASEL_sunshine",
"BASEL_temp_mean", "BASEL_temp_min", "BASEL_temp_max")]
Imputácia chýbajúcich hodnôt mediánom
median_hodnoty <- sapply(weather_data, median, na.rm = TRUE)
weather_data_imputed <- weather_data
for (col in names(weather_data)) {
weather_data_imputed[[col]][is.na(weather_data[[col]])] <- median_hodnoty[col]
}
weather_data <- weather_data_imputed
Boxploty pre vizuálnu kontrolu
Poskytnú nám rýchly prehľad o variabilite a rozsahu dát pred samotným
modelovaním.
num_plots <- length(names(weather_data))
par(mfrow = c(3, 3))
par(mar = c(4, 4, 2, 1))
for (col in names(weather_data)) {
boxplot(weather_data[[col]], main = col, xlab = "Hodnota", col = "lightblue")
}
par(mfrow = c(1, 1))

Lineárna regresia: závislá premenná BASEL_temp_mean
model <- lm(BASEL_temp_mean ~ BASEL_cloud_cover + BASEL_humidity + BASEL_pressure +
BASEL_global_radiation + BASEL_precipitation + BASEL_sunshine +
BASEL_temp_min + BASEL_temp_max, data = weather_data)
summary(model)
Call:
lm(formula = BASEL_temp_mean ~ BASEL_cloud_cover + BASEL_humidity +
BASEL_pressure + BASEL_global_radiation + BASEL_precipitation +
BASEL_sunshine + BASEL_temp_min + BASEL_temp_max, data = weather_data)
Residuals:
Min 1Q Median 3Q Max
-2.6986 -0.3519 0.0137 0.3576 2.6206
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.490728 1.310306 -1.138 0.255323
BASEL_cloud_cover 0.043206 0.007690 5.618 2.07e-08 ***
BASEL_humidity -1.508743 0.127840 -11.802 < 2e-16 ***
BASEL_pressure 2.345408 1.279865 1.833 0.066952 .
BASEL_global_radiation 0.090704 0.027478 3.301 0.000973 ***
BASEL_precipitation -0.028120 0.019019 -1.479 0.139343
BASEL_sunshine 0.007200 0.006625 1.087 0.277165
BASEL_temp_min 0.498117 0.004798 103.822 < 2e-16 ***
BASEL_temp_max 0.475467 0.004462 106.549 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.5475 on 3645 degrees of freedom
Multiple R-squared: 0.9946, Adjusted R-squared: 0.9945
F-statistic: 8.329e+04 on 8 and 3645 DF, p-value: < 2.2e-16
Pre lineárnu regresiu s BASEL_temp_mean ako závislou premennou model
ukazuje veľmi dobrú zhody s dátami. Koeficienty naznačujú, že niektoré
premenné majú silný vplyv na strednú teplotu.
Najdôležitejšie faktory sú:
Minimálna a maximálna teplota – hlavní prediktori s extrémne
vysokými t-hodnotami a p-hodnotami < 2e-16.
Vlhkosť – výrazne znižuje strednú teplotu (-1,51, t =
-11,8).
Oblačnosť a globálne žiarenie – mierny pozitívny efekt a
štatisticky významné.
Premenné ako tlak, zrážky alebo slnečný svit sa v tomto modeli
neprejavili ako významné.
Reziduá sú väčšinou malé (min = -2,6986, max = 2,6206, štandardná
chyba = 0,5475), čo naznačuje dobrú presnosť predikcie.
Hodnota R-squared = 0,9946 ukazuje, že model vysvetľuje takmer všetku
variabilitu strednej teploty, a vysoká F-statistika potvrdzuje celkovú
štatistickú významnosť modelu.
Celkovo model veľmi dobre zachytáva vzťahy medzi meteorologickými
premennými a strednou teplotou v Bazileji, pričom najdôležitejšie
faktory sú jasne identifikovateľné a zodpovedajú očakávanému fyzikálnemu
kontextu.
Diagnostické grafy
par(mfrow = c(2, 2))
plot(model)
par(mfrow = c(1, 1))

Residuals vs Fitted
Účel: Overiť, či má lineárny vzťah medzi premennými a či má
reziduá konštantný rozptyl.
Na tomto grafe je červená čiara ideálne rovná a body sú náhodne
rozmiestnené okolo nej. To znamená, že predpoklad linearity je splnený –
medzi premennými existuje vhodný lineárny vzťah a model je dobre
špecifikovaný.
Q-Q Residuals
Účel: Overiť, či sú reziduá normálne rozdelené.
Na tomto grafe body takmer dokonale sledujú diagonálnu čiaru. To
znamená, že reziduá sú normálne rozdelené. Tento dôležitý predpoklad pre
štatistické testovanie je splnený.
Scale-Location
Účel: Tiež overuje predpoklad homoskedasticity (konštantný
rozptyl reziduí). Je to podobné ako prvý graf, ale zobrazuje odmocninu
štandardizovaných reziduí.
Na tomto grafe sú body veľmi rozťahané a odchádzajú od čiary,
ktorá nie je dokonale rovná. To znamená, že dochádza k
heteroskedasticite – rozptyl reziduí nie je konštantný. To je hlavný
problém modelu, ktorý môže spôsobiť nespoľahlivosť štatistických
testov.
Residuals vs Leverage
Účel: Identifikovať vplyvné body (outliery), ktoré môžu neúmerne
ovplyvňovať výsledky regresie.
Na tomto grafe sú body sústredené v ľavej časti a červená čiara
sa mierne vlní. To znamená, že väčšina pozorovaní má nízku vplyvnosť, čo
je dobré, no niektoré body môžu mierne ovplyvňovať model. Nevidia sa
však extrémne vplyvné odľahlé hodnoty.
Jarque Bera test na normalitu rezíduí
residuals <- residuals(model)
jb_test <- jarque.bera.test(residuals)
jb_test
Jarque Bera Test
data: residuals
X-squared = 113.49, df = 2, p-value < 2.2e-16
Test Jarque-Bera sme použili na overenie, či sú reziduá modelu
normálne rozdelené. Tento test skúma rozdiel medzi tvarom rozdelenia
reziduí a teoretickým normálnym rozdelením pomocou dvoch ukazovateľov –
šikmosti (skewness) a špicatosti (kurtosis).
Výsledky:
X-squared = 113.49,
df = 2,
p-hodnota < 2.2e-16.
To znamená, že test zamieta nulovú hypotézu o normálnom rozdelení
reziduí. Napriek tomu, že Q-Q graf vizuálne naznačoval takmer normálne
rozdelenie, test ukazuje, že existujú drobné odchýlky — pravdepodobne
spôsobené veľkým počtom pozorovaní, kde aj malé rozdiely vedú k
štatistickej významnosti.
Reziduá nie sú úplne normálne rozdelené, hoci odchýlky nie sú výrazné
a model zostáva spoľahlivý na predikčné účely.
Test na odľahlé hodnoty
outlier_test <- outlierTest(model)
outlier_test
Pri teste na odľahlé hodnoty (outliery) sme použili štandardizované
reziduá (rstudent), aby sme identifikovali pozorovania s extrémnymi
hodnotami, ktoré môžu ovplyvniť stabilitu modelu.
Najvýraznejšie odľahlé hodnoty:
pozorovanie 1815 (rstudent = -4.96, Bonferroni p =
0.0027),
pozorovanie 713 (rstudent = 4.81, Bonferroni p =
0.0056),
pozorovanie 1273 (rstudent = -4.38, Bonferroni p =
0.0454).
Tieto hodnoty prekračujú bežný limit ±3, čo znamená, že ide o
potenciálne problematické pozorovania.
Záverom možno povedať, že niekoľko pozorovaní má vysoký vplyv a môžu
mierne skresľovať odhady parametrov
Grafy pre kontrolu heteroskedasticity
p1 <- ggplot(weather_data, aes(x = BASEL_pressure, y = resid(model)^2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "darkred") +
labs(x = "BASEL_pressure", y = "Štvorce rezíduí", title = "Rezíduá^2 vs Tlak") +
theme_minimal()
p2 <- ggplot(weather_data, aes(x = BASEL_humidity, y = resid(model)^2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "darkred") +
labs(x = "BASEL_humidity", y = "Štvorce rezíduí", title = "Rezíduá^2 vs Vlhkosť") +
theme_minimal()
plot_grid(p1, p2)

Tieto grafy zobrazujú vzťah medzi štvorcami rezíduí a vybranými
nezávislými premennými (tlakom a vlhkosťou). Ich cieľom je zistiť, či sa
rozptyl rezíduí mení v závislosti od hodnôt týchto premenných – teda či
sa v modeli prejavuje heteroskedasticita.
Rezíduá² vs Tlak
Väčšina bodov sa sústreďuje v spodnej časti grafu, prevažne medzi
hodnotami 0 až 2 na osi Y.
Červená čiara je len mierne zvlnená – na niektorých miestach sa
nepatrne dvíha a opäť klesá, no celkovo zostáva pomerne rovná.
Takýto priebeh naznačuje, že rozptyl rezíduí je relatívne
stabilný a výrazná heteroskedasticita sa neprejavuje.
Rezíduá² vs Vlhkosť
Body sú rozložené pomerne rovnomerne, väčšina z nich sa nachádza
v spodnej časti grafu.
Červená čiara je takmer rovná, bez výrazného zakrivenia, čo
svedčí o konštantnom rozptyle rezíduí.
Niekoľko bodov sa síce odchyľuje smerom nahor, ale tieto odchýlky
sú minimálne a nemajú zásadný vplyv na stabilitu rozptylu.
Na základe týchto grafov môžeme konštatovať, že model nevykazuje
výrazné známky heteroskedasticity – rozptyl chýb je relatívne konštantný
naprieč rôznymi hodnotami tlaku aj vlhkosti.
Breusch-Pagan test na heteroskedasticitu
Tento test sa používa na formálne overenie, či je rozptyl rezíduí
konštantný (homoskedasticita), alebo sa mení v závislosti od hodnôt
nezávislých premenných (heteroskedasticita).
studentized Breusch-Pagan test
data: model
BP = 248.6, df = 8, p-value < 2.2e-16
Keďže p-hodnota je výrazne menšia ako 0.05, zamietame nulovú hypotézu
o homoskedasticite. To znamená, že rozptyl rezíduí nie je konštantný a v
modeli sa vyskytuje heteroskedasticita.
Aj napriek tomu, že vizuálna kontrola grafov neukázala výrazné
porušenie predpokladov, štatistický test potvrdzuje, že variabilita
rezíduí sa mení v závislosti od niektorých premenných.
Model nespĺňa predpoklad konštantného rozptylu chýb. Tento problém
môžeme riešiť napríklad použitím robustných štandardných chýb, ktoré
korigujú dôsledky heteroskedasticity bez nutnosti meniť samotný
model.
library(lmtest)
library(sandwich)
Výpočet robustných štandardných chýb
robust_summary <- coeftest(model, vcov = vcovHC(model, type = "HC1"))
robust_summary
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.4907281 1.3517456 -1.1028 0.270179
BASEL_cloud_cover 0.0432057 0.0075177 5.7472 9.816e-09 ***
BASEL_humidity -1.5087434 0.1343456 -11.2303 < 2.2e-16 ***
BASEL_pressure 2.3454082 1.3187298 1.7785 0.075399 .
BASEL_global_radiation 0.0907036 0.0290459 3.1228 0.001806 **
BASEL_precipitation -0.0281202 0.0231747 -1.2134 0.225057
BASEL_sunshine 0.0072004 0.0065787 1.0945 0.273805
BASEL_temp_min 0.4981170 0.0055186 90.2609 < 2.2e-16 ***
BASEL_temp_max 0.4754666 0.0051496 92.3314 < 2.2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Z tabuľky výsledkov vyplýva:
Koeficienty odhadnuté pôvodným modelom sa nemenia, takže veľkosť
a smer vplyvu jednotlivých premenných zostávajú rovnaké,
Štandardné chyby sa mierne upravili, čo ovplyvnilo hodnoty t a
p-hodnoty.
Najsilnejšie a štatisticky významné premenné zostávajú:
Minimálna a maximálna teplota (p < 2.2e-16, extrémne vysoké
t-hodnoty),
Vlhkosť (p < 2.2e-16, negatívny efekt),
Oblačnosť a globálne žiarenie (p < 0.01).
Premenné ako tlak, zrážky a slnečný svit sa stále neprejavili ako
významné, hoci tlak je teraz mierne bližšie k hranici významnosti (p =
0.075).
Použitie robustných štandardných chýb zabezpečilo spoľahlivejšiu
interpretáciu modelu aj napriek prítomnosti heteroskedasticity. Model
naďalej vysvetľuje väčšinu variability strednej teploty a dôležité
vzťahy medzi premennými sú jasne identifikovateľné.
LS0tDQp0aXRsZTogIsOabG9oYV82Ig0KYXV0aG9yOiAiQmMuIEtyeXN0eW5hIFZhc3lseW5hIg0KZGF0ZTogIk5vdmVtYmVyIDIwMjUiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIGRmX3ByaW50OiBwYWdlZA0KZWRpdG9yX29wdGlvbnM6DQogIG1hcmtkb3duOg0KICAgIHdyYXA6IDcyDQotLS0NCg0KIyBBbmFsw716YSBtZXRlb3JvbG9naWNrw71jaCB1a2F6b3ZhdGXEvm92DQoNCiMjIMOadm9kIGRvIHByb2Jsw6ltdSBhIHN0YW5vdmVuaWUgaHlwb3TDqXp5DQoNCkNpZcS+b20gYW5hbMO9enkgamUgbW9kZWxvdmHFpSBzdHJlZG7DuiBkZW5uw7ogdGVwbG90dSB2IEJhemlsZWppIChCQVNFTF90ZW1wX21lYW4pIG5hIHrDoWtsYWRlIHZpYWNlcsO9Y2ggbWV0ZW9yb2xvZ2lja8O9Y2ggcHJlbWVubsO9Y2g6IA0KDQotIG9ibGHEjW5vc8WlIChCQVNFTF9jbG91ZF9jb3ZlciksIA0KDQotIHZsaGtvc8WlIChCQVNFTF9odW1pZGl0eSksIA0KDQotIHRsYWsgdnpkdWNodSAoQkFTRUxfcHJlc3N1cmUpLCANCg0KLSBnbG9iw6FsbmUgxb5pYXJlbmllIChCQVNFTF9nbG9iYWxfcmFkaWF0aW9uKSwgDQoNCi0genLDocW+a3kgKEJBU0VMX3ByZWNpcGl0YXRpb24pLCANCg0KLSBzbG5lxI1uw70gc3ZpdCAoQkFTRUxfc3Vuc2hpbmUpIGEgbWluaW3DoWxudSBhIG1heGltw6FsbnUgdGVwbG90dSAoQkFTRUxfdGVtcF9taW4sIEJBU0VMX3RlbXBfbWF4KS4NCg0KUHJhY292bsOhIGh5cG90w6l6YSBwcmVkcG9rbGFkw6EsIMW+ZSB0aWV0byBwcmVtZW5uw6kgdsO9em5hbW5lIG92cGx5dsWIdWrDuiBzdHJlZG7DuiB0ZXBsb3R1IOKAkyBuYXByw61rbGFkIHZ5xaHFoWllIGdsb2LDoWxuZSDFvmlhcmVuaWUgYWxlYm8gc2xuZcSNbsO9IHN2aXQgYnkgbWFsaSB2aWVzxaUgayB2ecWhxaHDrW0gdGVwbG90w6FtLCB6YXRpYcS+IMSNbyB2w6TEjcWhaWEgb2JsYcSNbm9zxaUgbcO0xb5lIHRlcGxvdHUgem5pxb5vdmHFpS4gQ2llxL5vbSBhbmFsw716eSBqZSBvdmVyacWlIHTDunRvIGh5cG90w6l6dSBwb21vY291IGxpbmXDoXJuZWhvIHJlZ3Jlc27DqWhvIG1vZGVsdSwgcG9zw7pkacWlIHbDvXpuYW0gamVkbm90bGl2w71jaCBwcmVtZW5uw71jaCBhIHNrb250cm9sb3ZhxaUsIMSNaSBtb2RlbCBzcMS6xYhhIHByZWRwb2tsYWR5IGxpbmXDoXJuZWogcmVncmVzaWUsIGFrbyBzw7ogbm9ybWFsaXRhIHJlesOtZHXDrSBhIGtvbsWhdGFudG7DvSByb3pwdHlsIChob21vc2tlZGFzdGljaXRhKS4NCg0KTmEgemHEjWlhdGt1IGFuYWzDvXp5IGJ1ZGVtZSBuYWpwcnYgbmHEjcOtdGHFpSBwb3RyZWJuw6kga25pxb5uaWNlLCB2ecSNaXN0w61tZSBwcmFjb3Zuw6kgcHJvc3RyZWRpZSwgbmHEjcOtdGFtZSBzw7pib3Igd2VhdGhlcl9wcmVkaWN0aW9uX2RhdGFzZXQuY3N2LCB2eWJlcmllbWUga8S+w7rEjW92w6kgc3TEunBjZSBhIGRvcGxuw61tZSBjaMO9YmFqw7pjZSBob2Rub3R5IG1lZGnDoW5vbSwgYWJ5IGJvbGkgw7pkYWplIHByaXByYXZlbsOpIG5hIMSPYWzFoWllIHNwcmFjb3ZhbmllLg0KDQojIyBOYcSNw610YW5pZSBrbmnFvm7DrWMNCg0KYGBge3J9DQpsaWJyYXJ5KHpvbykNCmxpYnJhcnkodHNlcmllcykNCmxpYnJhcnkobG10ZXN0KQ0KbGlicmFyeShzYW5kd2ljaCkNCmxpYnJhcnkoY2FyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShjb3dwbG90KQ0KYGBgDQoNCiMjIFZ5xI1pc3RlbmllIHByYWNvdm7DqWhvIHByb3N0cmVkaWENCg0KYGBge3J9DQpybShsaXN0PWxzKCkpDQpgYGANCg0KIyMgTmHEjcOtdGFuaWUgw7pkYWpvdg0KDQpgYGB7cn0NCnVkYWplIDwtIHJlYWQuY3N2KCJ3ZWF0aGVyX3ByZWRpY3Rpb25fZGF0YXNldC5jc3YiKQ0KYGBgDQoNCiMjIFbDvWJlciBwb3RyZWJuw71jaCBzdMS6cGNvdg0KDQpgYGB7cn0NCndlYXRoZXJfZGF0YSA8LSB1ZGFqZVssIGMoIkJBU0VMX2Nsb3VkX2NvdmVyIiwgIkJBU0VMX2h1bWlkaXR5IiwgIkJBU0VMX3ByZXNzdXJlIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJCQVNFTF9nbG9iYWxfcmFkaWF0aW9uIiwgIkJBU0VMX3ByZWNpcGl0YXRpb24iLCAiQkFTRUxfc3Vuc2hpbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiQkFTRUxfdGVtcF9tZWFuIiwgIkJBU0VMX3RlbXBfbWluIiwgIkJBU0VMX3RlbXBfbWF4IildDQpgYGANCg0KIyMgSW1wdXTDoWNpYSBjaMO9YmFqw7pjaWNoIGhvZG7DtHQgbWVkacOhbm9tDQoNCmBgYHtyfQ0KbWVkaWFuX2hvZG5vdHkgPC0gc2FwcGx5KHdlYXRoZXJfZGF0YSwgbWVkaWFuLCBuYS5ybSA9IFRSVUUpDQp3ZWF0aGVyX2RhdGFfaW1wdXRlZCA8LSB3ZWF0aGVyX2RhdGENCmZvciAoY29sIGluIG5hbWVzKHdlYXRoZXJfZGF0YSkpIHsNCiAgd2VhdGhlcl9kYXRhX2ltcHV0ZWRbW2NvbF1dW2lzLm5hKHdlYXRoZXJfZGF0YVtbY29sXV0pXSA8LSBtZWRpYW5faG9kbm90eVtjb2xdDQp9DQp3ZWF0aGVyX2RhdGEgPC0gd2VhdGhlcl9kYXRhX2ltcHV0ZWQNCmBgYA0KDQojIyBCb3hwbG90eSBwcmUgdml6dcOhbG51IGtvbnRyb2x1DQoNClBvc2t5dG7DuiBuw6FtIHLDvWNobHkgcHJlaMS+YWQgbyB2YXJpYWJpbGl0ZSBhIHJvenNhaHUgZMOhdCBwcmVkIHNhbW90bsO9bSBtb2RlbG92YW7DrW0uDQoNCg0KYGBge3J9DQpudW1fcGxvdHMgPC0gbGVuZ3RoKG5hbWVzKHdlYXRoZXJfZGF0YSkpDQpwYXIobWZyb3cgPSBjKDMsIDMpKQ0KcGFyKG1hciA9IGMoNCwgNCwgMiwgMSkpDQpmb3IgKGNvbCBpbiBuYW1lcyh3ZWF0aGVyX2RhdGEpKSB7DQogIGJveHBsb3Qod2VhdGhlcl9kYXRhW1tjb2xdXSwgbWFpbiA9IGNvbCwgeGxhYiA9ICJIb2Rub3RhIiwgY29sID0gImxpZ2h0Ymx1ZSIpDQp9DQpwYXIobWZyb3cgPSBjKDEsIDEpKQ0KYGBgDQoNCiMjIExpbmXDoXJuYSByZWdyZXNpYTogesOhdmlzbMOhIHByZW1lbm7DoSBCQVNFTF90ZW1wX21lYW4NCg0KYGBge3J9DQptb2RlbCA8LSBsbShCQVNFTF90ZW1wX21lYW4gfiBCQVNFTF9jbG91ZF9jb3ZlciArIEJBU0VMX2h1bWlkaXR5ICsgQkFTRUxfcHJlc3N1cmUgKw0KICAgICAgICAgICAgICBCQVNFTF9nbG9iYWxfcmFkaWF0aW9uICsgQkFTRUxfcHJlY2lwaXRhdGlvbiArIEJBU0VMX3N1bnNoaW5lICsNCiAgICAgICAgICAgICAgQkFTRUxfdGVtcF9taW4gKyBCQVNFTF90ZW1wX21heCwgZGF0YSA9IHdlYXRoZXJfZGF0YSkNCnN1bW1hcnkobW9kZWwpDQpgYGANClByZSBsaW5lw6FybnUgcmVncmVzaXUgcyBCQVNFTF90ZW1wX21lYW4gYWtvIHrDoXZpc2xvdSBwcmVtZW5ub3UgbW9kZWwgdWthenVqZSB2ZcS+bWkgZG9icsO6IHpob2R5IHMgZMOhdGFtaS4gS29lZmljaWVudHkgbmF6bmHEjXVqw7osIMW+ZSBuaWVrdG9yw6kgcHJlbWVubsOpIG1hasO6IHNpbG7DvSB2cGx5diBuYSBzdHJlZG7DuiB0ZXBsb3R1Lg0KDQpOYWpkw7RsZcW+aXRlasWhaWUgZmFrdG9yeSBzw7o6DQoNCi0gTWluaW3DoWxuYSBhIG1heGltw6FsbmEgdGVwbG90YSDigJMgaGxhdm7DrSBwcmVkaWt0b3JpIHMgZXh0csOpbW5lIHZ5c29rw71taSB0LWhvZG5vdGFtaSBhIHAtaG9kbm90YW1pIDwgMmUtMTYuDQoNCi0gVmxoa29zxaUg4oCTIHbDvXJhem5lIHpuacW+dWplIHN0cmVkbsO6IHRlcGxvdHUgKC0xLDUxLCB0ID0gLTExLDgpLg0KDQotIE9ibGHEjW5vc8WlIGEgZ2xvYsOhbG5lIMW+aWFyZW5pZSDigJMgbWllcm55IHBveml0w612bnkgZWZla3QgYSDFoXRhdGlzdGlja3kgdsO9em5hbW7DqS4NCg0KUHJlbWVubsOpIGFrbyB0bGFrLCB6csOhxb5reSBhbGVibyBzbG5lxI1uw70gc3ZpdCBzYSB2IHRvbXRvIG1vZGVsaSBuZXByZWphdmlsaSBha28gdsO9em5hbW7DqS4gDQoNClJlemlkdcOhIHPDuiB2w6TEjcWhaW5vdSBtYWzDqSAobWluID0gLTIsNjk4NiwgbWF4ID0gMiw2MjA2LCDFoXRhbmRhcmRuw6EgY2h5YmEgPSAwLDU0NzUpLCDEjW8gbmF6bmHEjXVqZSBkb2Jyw7ogcHJlc25vc8WlIHByZWRpa2NpZS4gDQoNCkhvZG5vdGEgUi1zcXVhcmVkID0gMCw5OTQ2IHVrYXp1amUsIMW+ZSBtb2RlbCB2eXN2ZXTEvnVqZSB0YWttZXIgdsWhZXRrdSB2YXJpYWJpbGl0dSBzdHJlZG5laiB0ZXBsb3R5LCBhIHZ5c29rw6EgRi1zdGF0aXN0aWthIHBvdHZyZHp1amUgY2Vsa292w7ogxaF0YXRpc3RpY2vDuiB2w716bmFtbm9zxaUgbW9kZWx1Lg0KDQpDZWxrb3ZvIG1vZGVsIHZlxL5taSBkb2JyZSB6YWNoeXTDoXZhIHZ6xaVhaHkgbWVkemkgbWV0ZW9yb2xvZ2lja8O9bWkgcHJlbWVubsO9bWkgYSBzdHJlZG5vdSB0ZXBsb3RvdSB2IEJhemlsZWppLCBwcmnEjW9tIG5hamTDtGxlxb5pdGVqxaFpZSBmYWt0b3J5IHPDuiBqYXNuZSBpZGVudGlmaWtvdmF0ZcS+bsOpIGEgem9kcG92ZWRhasO6IG/EjWFrw6F2YW7DqW11IGZ5emlrw6FsbmVtdSBrb250ZXh0dS4NCg0KIyMgRGlhZ25vc3RpY2vDqSBncmFmeQ0KDQpgYGB7cn0NCnBhcihtZnJvdyA9IGMoMiwgMikpDQpwbG90KG1vZGVsKQ0KcGFyKG1mcm93ID0gYygxLCAxKSkNCmBgYA0KIyMjIyBSZXNpZHVhbHMgdnMgRml0dGVkDQoNCi0gw5rEjWVsOiBPdmVyacWlLCDEjWkgbcOhIGxpbmXDoXJueSB2esWlYWggbWVkemkgcHJlbWVubsO9bWkgYSDEjWkgbcOhIHJlemlkdcOhIGtvbsWhdGFudG7DvSByb3pwdHlsLg0KDQotIE5hIHRvbXRvIGdyYWZlIGplIMSNZXJ2ZW7DoSDEjWlhcmEgaWRlw6FsbmUgcm92bsOhIGEgYm9keSBzw7ogbsOhaG9kbmUgcm96bWllc3RuZW7DqSBva29sbyBuZWouIFRvIHpuYW1lbsOhLCDFvmUgcHJlZHBva2xhZCBsaW5lYXJpdHkgamUgc3BsbmVuw70g4oCTIG1lZHppIHByZW1lbm7DvW1pIGV4aXN0dWplIHZob2Ruw70gbGluZcOhcm55IHZ6xaVhaCBhIG1vZGVsIGplIGRvYnJlIMWhcGVjaWZpa292YW7DvS4NCg0KIyMjIyBRLVEgUmVzaWR1YWxzDQoNCi0gw5rEjWVsOiBPdmVyacWlLCDEjWkgc8O6IHJlemlkdcOhIG5vcm3DoWxuZSByb3pkZWxlbsOpLg0KDQotIE5hIHRvbXRvIGdyYWZlIGJvZHkgdGFrbWVyIGRva29uYWxlIHNsZWR1asO6IGRpYWdvbsOhbG51IMSNaWFydS4gVG8gem5hbWVuw6EsIMW+ZSByZXppZHXDoSBzw7ogbm9ybcOhbG5lIHJvemRlbGVuw6kuIFRlbnRvIGTDtGxlxb5pdMO9IHByZWRwb2tsYWQgcHJlIMWhdGF0aXN0aWNrw6kgdGVzdG92YW5pZSBqZSBzcGxuZW7DvS4NCg0KIyMjIyBTY2FsZS1Mb2NhdGlvbg0KDQotIMOaxI1lbDogVGllxb4gb3ZlcnVqZSBwcmVkcG9rbGFkIGhvbW9za2VkYXN0aWNpdHkgKGtvbsWhdGFudG7DvSByb3pwdHlsIHJlemlkdcOtKS4gSmUgdG8gcG9kb2Juw6kgYWtvIHBydsO9IGdyYWYsIGFsZSB6b2JyYXp1amUgb2Rtb2NuaW51IMWhdGFuZGFyZGl6b3ZhbsO9Y2ggcmV6aWR1w60uDQoNCi0gTmEgdG9tdG8gZ3JhZmUgc8O6IGJvZHkgdmXEvm1pIHJvesWlYWhhbsOpIGEgb2RjaMOhZHphasO6IG9kIMSNaWFyeSwga3RvcsOhIG5pZSBqZSBkb2tvbmFsZSByb3Zuw6EuIFRvIHpuYW1lbsOhLCDFvmUgZG9jaMOhZHphIGsgaGV0ZXJvc2tlZGFzdGljaXRlIOKAkyByb3pwdHlsIHJlemlkdcOtIG5pZSBqZSBrb27FoXRhbnRuw70uIFRvIGplIGhsYXZuw70gcHJvYmzDqW0gbW9kZWx1LCBrdG9yw70gbcO0xb5lIHNww7Rzb2JpxaUgbmVzcG/EvmFobGl2b3PFpSDFoXRhdGlzdGlja8O9Y2ggdGVzdG92Lg0KDQojIyMjIFJlc2lkdWFscyB2cyBMZXZlcmFnZQ0KDQotIMOaxI1lbDogSWRlbnRpZmlrb3ZhxaUgdnBseXZuw6kgYm9keSAob3V0bGllcnkpLCBrdG9yw6kgbcO0xb51IG5lw7ptZXJuZSBvdnBseXbFiG92YcWlIHbDvXNsZWRreSByZWdyZXNpZS4NCg0KLSBOYSB0b210byBncmFmZSBzw7ogYm9keSBzw7pzdHJlZGVuw6kgdiDEvmF2ZWogxI1hc3RpIGEgxI1lcnZlbsOhIMSNaWFyYSBzYSBtaWVybmUgdmxuw60uIFRvIHpuYW1lbsOhLCDFvmUgdsOkxI3FoWluYSBwb3pvcm92YW7DrSBtw6EgbsOtemt1IHZwbHl2bm9zxaUsIMSNbyBqZSBkb2Jyw6ksIG5vIG5pZWt0b3LDqSBib2R5IG3DtMW+dSBtaWVybmUgb3ZwbHl2xYhvdmHFpSBtb2RlbC4gTmV2aWRpYSBzYSB2xaFhayBleHRyw6ltbmUgdnBseXZuw6kgb2TEvmFobMOpIGhvZG5vdHkuDQoNCiMjIEphcnF1ZSBCZXJhIHRlc3QgbmEgbm9ybWFsaXR1IHJlesOtZHXDrQ0KDQpgYGB7cn0NCnJlc2lkdWFscyA8LSByZXNpZHVhbHMobW9kZWwpDQpqYl90ZXN0IDwtIGphcnF1ZS5iZXJhLnRlc3QocmVzaWR1YWxzKQ0KamJfdGVzdA0KYGBgDQpUZXN0IEphcnF1ZS1CZXJhIHNtZSBwb3XFvmlsaSBuYSBvdmVyZW5pZSwgxI1pIHPDuiByZXppZHXDoSBtb2RlbHUgbm9ybcOhbG5lIHJvemRlbGVuw6kuIFRlbnRvIHRlc3Qgc2vDum1hIHJvemRpZWwgbWVkemkgdHZhcm9tIHJvemRlbGVuaWEgcmV6aWR1w60gYSB0ZW9yZXRpY2vDvW0gbm9ybcOhbG55bSByb3pkZWxlbsOtbSBwb21vY291IGR2b2NoIHVrYXpvdmF0ZcS+b3Yg4oCTIMWhaWttb3N0aSAoc2tld25lc3MpIGEgxaFwaWNhdG9zdGkgKGt1cnRvc2lzKS4NCg0KVsO9c2xlZGt5Og0KDQotIFgtc3F1YXJlZCA9IDExMy40OSwNCg0KLSBkZiA9IDIsDQoNCi0gcC1ob2Rub3RhIDwgMi4yZS0xNi4NCg0KVG8gem5hbWVuw6EsIMW+ZSB0ZXN0IHphbWlldGEgbnVsb3bDuiBoeXBvdMOpenUgbyBub3Jtw6Fsbm9tIHJvemRlbGVuw60gcmV6aWR1w60uIE5hcHJpZWsgdG9tdSwgxb5lIFEtUSBncmFmIHZpenXDoWxuZSBuYXpuYcSNb3ZhbCB0YWttZXIgbm9ybcOhbG5lIHJvemRlbGVuaWUsIHRlc3QgdWthenVqZSwgxb5lIGV4aXN0dWrDuiBkcm9ibsOpIG9kY2jDvWxreSDigJQgcHJhdmRlcG9kb2JuZSBzcMO0c29iZW7DqSB2ZcS+a8O9bSBwb8SNdG9tIHBvem9yb3ZhbsOtLCBrZGUgYWogbWFsw6kgcm96ZGllbHkgdmVkw7ogayDFoXRhdGlzdGlja2VqIHbDvXpuYW1ub3N0aS4NCg0KUmV6aWR1w6EgbmllIHPDuiDDunBsbmUgbm9ybcOhbG5lIHJvemRlbGVuw6ksIGhvY2kgb2RjaMO9bGt5IG5pZSBzw7ogdsO9cmF6bsOpIGEgbW9kZWwgem9zdMOhdmEgc3BvxL5haGxpdsO9IG5hIHByZWRpa8SNbsOpIMO6xI1lbHkuDQoNCiMjIFRlc3QgbmEgb2TEvmFobMOpIGhvZG5vdHkNCg0KYGBge3J9DQpvdXRsaWVyX3Rlc3QgPC0gb3V0bGllclRlc3QobW9kZWwpDQpvdXRsaWVyX3Rlc3QNCmBgYA0KUHJpIHRlc3RlIG5hIG9kxL5haGzDqSBob2Rub3R5IChvdXRsaWVyeSkgc21lIHBvdcW+aWxpIMWhdGFuZGFyZGl6b3ZhbsOpIHJlemlkdcOhIChyc3R1ZGVudCksIGFieSBzbWUgaWRlbnRpZmlrb3ZhbGkgcG96b3JvdmFuaWEgcyBleHRyw6ltbnltaSBob2Rub3RhbWksIGt0b3LDqSBtw7TFvnUgb3ZwbHl2bmnFpSBzdGFiaWxpdHUgbW9kZWx1Lg0KDQpOYWp2w71yYXpuZWrFoWllIG9kxL5haGzDqSBob2Rub3R5Og0KDQotIHBvem9yb3ZhbmllIDE4MTUgKHJzdHVkZW50ID0gLTQuOTYsIEJvbmZlcnJvbmkgcCA9IDAuMDAyNyksDQoNCi0gcG96b3JvdmFuaWUgNzEzIChyc3R1ZGVudCA9IDQuODEsIEJvbmZlcnJvbmkgcCA9IDAuMDA1NiksDQoNCi0gcG96b3JvdmFuaWUgMTI3MyAocnN0dWRlbnQgPSAtNC4zOCwgQm9uZmVycm9uaSBwID0gMC4wNDU0KS4NCg0KVGlldG8gaG9kbm90eSBwcmVrcmHEjXVqw7ogYmXFvm7DvSBsaW1pdCDCsTMsIMSNbyB6bmFtZW7DoSwgxb5lIGlkZSBvIHBvdGVuY2nDoWxuZSBwcm9ibGVtYXRpY2vDqSBwb3pvcm92YW5pYS4NCg0KWsOhdmVyb20gbW/Fvm5vIHBvdmVkYcWlLCDFvmUgbmlla2/EvmtvIHBvem9yb3ZhbsOtIG3DoSB2eXNva8O9IHZwbHl2IGEgbcO0xb51IG1pZXJuZSBza3Jlc8S+b3ZhxaUgb2RoYWR5IHBhcmFtZXRyb3YNCg0KIyMgR3JhZnkgcHJlIGtvbnRyb2x1IGhldGVyb3NrZWRhc3RpY2l0eQ0KDQpgYGB7cn0NCnAxIDwtIGdncGxvdCh3ZWF0aGVyX2RhdGEsIGFlcyh4ID0gQkFTRUxfcHJlc3N1cmUsIHkgPSByZXNpZChtb2RlbCleMikpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJkYXJrcmVkIikgKw0KICBsYWJzKHggPSAiQkFTRUxfcHJlc3N1cmUiLCB5ID0gIsWgdHZvcmNlIHJlesOtZHXDrSIsIHRpdGxlID0gIlJlesOtZHXDoV4yIHZzIFRsYWsiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpwMiA8LSBnZ3Bsb3Qod2VhdGhlcl9kYXRhLCBhZXMoeCA9IEJBU0VMX2h1bWlkaXR5LCB5ID0gcmVzaWQobW9kZWwpXjIpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiZGFya3JlZCIpICsNCiAgbGFicyh4ID0gIkJBU0VMX2h1bWlkaXR5IiwgeSA9ICLFoHR2b3JjZSByZXrDrWR1w60iLCB0aXRsZSA9ICJSZXrDrWR1w6FeMiB2cyBWbGhrb3PFpSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCnBsb3RfZ3JpZChwMSwgcDIpDQpgYGANClRpZXRvIGdyYWZ5IHpvYnJhenVqw7ogdnrFpWFoIG1lZHppIMWhdHZvcmNhbWkgcmV6w61kdcOtIGEgdnlicmFuw71taSBuZXrDoXZpc2zDvW1pIHByZW1lbm7DvW1pICh0bGFrb20gYSB2bGhrb3PFpW91KS4gSWNoIGNpZcS+b20gamUgemlzdGnFpSwgxI1pIHNhIHJvenB0eWwgcmV6w61kdcOtIG1lbsOtIHYgesOhdmlzbG9zdGkgb2QgaG9kbsO0dCB0w71jaHRvIHByZW1lbm7DvWNoIOKAkyB0ZWRhIMSNaSBzYSB2IG1vZGVsaSBwcmVqYXZ1amUgaGV0ZXJvc2tlZGFzdGljaXRhLg0KDQojIyMjIFJlesOtZHXDocKyIHZzIFRsYWsNCg0KLSBWw6TEjcWhaW5hIGJvZG92IHNhIHPDunN0cmXEj3VqZSB2IHNwb2RuZWogxI1hc3RpIGdyYWZ1LCBwcmV2YcW+bmUgbWVkemkgaG9kbm90YW1pIDAgYcW+IDIgbmEgb3NpIFkuDQoNCi0gxIxlcnZlbsOhIMSNaWFyYSBqZSBsZW4gbWllcm5lIHp2bG5lbsOhIOKAkyBuYSBuaWVrdG9yw71jaCBtaWVzdGFjaCBzYSBuZXBhdHJuZSBkdsOtaGEgYSBvcMOkxaUga2xlc8OhLCBubyBjZWxrb3ZvIHpvc3TDoXZhIHBvbWVybmUgcm92bsOhLg0KDQotIFRha8O9dG8gcHJpZWJlaCBuYXpuYcSNdWplLCDFvmUgcm96cHR5bCByZXrDrWR1w60gamUgcmVsYXTDrXZuZSBzdGFiaWxuw70gYSB2w71yYXpuw6EgaGV0ZXJvc2tlZGFzdGljaXRhIHNhIG5lcHJlamF2dWplLg0KDQojIyMjIFJlesOtZHXDocKyIHZzIFZsaGtvc8WlDQoNCi0gQm9keSBzw7ogcm96bG/FvmVuw6kgcG9tZXJuZSByb3Zub21lcm5lLCB2w6TEjcWhaW5hIHogbmljaCBzYSBuYWNow6FkemEgdiBzcG9kbmVqIMSNYXN0aSBncmFmdS4NCg0KLSDEjGVydmVuw6EgxI1pYXJhIGplIHRha21lciByb3Zuw6EsIGJleiB2w71yYXpuw6lobyB6YWtyaXZlbmlhLCDEjW8gc3ZlZMSNw60gbyBrb27FoXRhbnRub20gcm96cHR5bGUgcmV6w61kdcOtLg0KDQotIE5pZWtvxL5rbyBib2RvdiBzYSBzw61jZSBvZGNoecS+dWplIHNtZXJvbSBuYWhvciwgYWxlIHRpZXRvIG9kY2jDvWxreSBzw7ogbWluaW3DoWxuZSBhIG5lbWFqw7ogesOhc2FkbsO9IHZwbHl2IG5hIHN0YWJpbGl0dSByb3pwdHlsdS4NCg0KTmEgesOha2xhZGUgdMO9Y2h0byBncmFmb3YgbcO0xb5lbWUga29uxaF0YXRvdmHFpSwgxb5lIG1vZGVsIG5ldnlrYXp1amUgdsO9cmF6bsOpIHpuw6Fta3kgaGV0ZXJvc2tlZGFzdGljaXR5IOKAkyByb3pwdHlsIGNow71iIGplIHJlbGF0w612bmUga29uxaF0YW50bsO9IG5hcHJpZcSNIHLDtHpueW1pIGhvZG5vdGFtaSB0bGFrdSBhaiB2bGhrb3N0aS4NCg0KIyMgQnJldXNjaC1QYWdhbiB0ZXN0IG5hIGhldGVyb3NrZWRhc3RpY2l0dQ0KDQpUZW50byB0ZXN0IHNhIHBvdcW+w612YSBuYSBmb3Jtw6FsbmUgb3ZlcmVuaWUsIMSNaSBqZSByb3pwdHlsIHJlesOtZHXDrSBrb27FoXRhbnRuw70gKGhvbW9za2VkYXN0aWNpdGEpLCBhbGVibyBzYSBtZW7DrSB2IHrDoXZpc2xvc3RpIG9kIGhvZG7DtHQgbmV6w6F2aXNsw71jaCBwcmVtZW5uw71jaCAoaGV0ZXJvc2tlZGFzdGljaXRhKS4NCg0KYGBge3J9DQpicHRlc3QobW9kZWwpDQpgYGANCktlxI/FvmUgcC1ob2Rub3RhIGplIHbDvXJhem5lIG1lbsWhaWEgYWtvIDAuMDUsIHphbWlldGFtZSBudWxvdsO6IGh5cG90w6l6dSBvIGhvbW9za2VkYXN0aWNpdGUuIFRvIHpuYW1lbsOhLCDFvmUgcm96cHR5bCByZXrDrWR1w60gbmllIGplIGtvbsWhdGFudG7DvSBhIHYgbW9kZWxpIHNhIHZ5c2t5dHVqZSBoZXRlcm9za2VkYXN0aWNpdGEuDQoNCkFqIG5hcHJpZWsgdG9tdSwgxb5lIHZpenXDoWxuYSBrb250cm9sYSBncmFmb3YgbmV1a8OhemFsYSB2w71yYXpuw6kgcG9ydcWhZW5pZSBwcmVkcG9rbGFkb3YsIMWhdGF0aXN0aWNrw70gdGVzdCBwb3R2cmR6dWplLCDFvmUgdmFyaWFiaWxpdGEgcmV6w61kdcOtIHNhIG1lbsOtIHYgesOhdmlzbG9zdGkgb2Qgbmlla3RvcsO9Y2ggcHJlbWVubsO9Y2guDQoNCk1vZGVsIG5lc3DEusWIYSBwcmVkcG9rbGFkIGtvbsWhdGFudG7DqWhvIHJvenB0eWx1IGNow71iLiBUZW50byBwcm9ibMOpbSBtw7TFvmVtZSByaWXFoWnFpSBuYXByw61rbGFkIHBvdcW+aXTDrW0gcm9idXN0bsO9Y2ggxaF0YW5kYXJkbsO9Y2ggY2jDvWIsIGt0b3LDqSBrb3JpZ3Vqw7ogZMO0c2xlZGt5IGhldGVyb3NrZWRhc3RpY2l0eSBiZXogbnV0bm9zdGkgbWVuacWlIHNhbW90bsO9IG1vZGVsLg0KDQpgYGB7cn0NCmxpYnJhcnkobG10ZXN0KQ0KbGlicmFyeShzYW5kd2ljaCkNCmBgYA0KDQojIyBWw71wb8SNZXQgcm9idXN0bsO9Y2ggxaF0YW5kYXJkbsO9Y2ggY2jDvWINCg0KYGBge3J9DQpyb2J1c3Rfc3VtbWFyeSA8LSBjb2VmdGVzdChtb2RlbCwgdmNvdiA9IHZjb3ZIQyhtb2RlbCwgdHlwZSA9ICJIQzEiKSkNCnJvYnVzdF9zdW1tYXJ5DQpgYGANClogdGFidcS+a3kgdsO9c2xlZGtvdiB2eXBsw712YToNCg0KLSBLb2VmaWNpZW50eSBvZGhhZG51dMOpIHDDtHZvZG7DvW0gbW9kZWxvbSBzYSBuZW1lbmlhLCB0YWvFvmUgdmXEvmtvc8WlIGEgc21lciB2cGx5dnUgamVkbm90bGl2w71jaCBwcmVtZW5uw71jaCB6b3N0w6F2YWrDuiByb3ZuYWvDqSwNCg0KLSDFoHRhbmRhcmRuw6kgY2h5Ynkgc2EgbWllcm5lIHVwcmF2aWxpLCDEjW8gb3ZwbHl2bmlsbyBob2Rub3R5IHQgYSBwLWhvZG5vdHkuDQoNCk5hanNpbG5lasWhaWUgYSDFoXRhdGlzdGlja3kgdsO9em5hbW7DqSBwcmVtZW5uw6kgem9zdMOhdmFqw7o6DQoNCi0gTWluaW3DoWxuYSBhIG1heGltw6FsbmEgdGVwbG90YSAocCA8IDIuMmUtMTYsIGV4dHLDqW1uZSB2eXNva8OpIHQtaG9kbm90eSksDQoNCi0gVmxoa29zxaUgKHAgPCAyLjJlLTE2LCBuZWdhdMOtdm55IGVmZWt0KSwNCg0KLSBPYmxhxI1ub3PFpSBhIGdsb2LDoWxuZSDFvmlhcmVuaWUgKHAgPCAwLjAxKS4NCg0KUHJlbWVubsOpIGFrbyB0bGFrLCB6csOhxb5reSBhIHNsbmXEjW7DvSBzdml0IHNhIHN0w6FsZSBuZXByZWphdmlsaSBha28gdsO9em5hbW7DqSwgaG9jaSB0bGFrIGplIHRlcmF6IG1pZXJuZSBibGnFvsWhaWUgayBocmFuaWNpIHbDvXpuYW1ub3N0aSAocCA9IDAuMDc1KS4NCg0KUG91xb5pdGllIHJvYnVzdG7DvWNoIMWhdGFuZGFyZG7DvWNoIGNow71iIHphYmV6cGXEjWlsbyBzcG/EvmFobGl2ZWrFoWl1IGludGVycHJldMOhY2l1IG1vZGVsdSBhaiBuYXByaWVrIHByw610b21ub3N0aSBoZXRlcm9za2VkYXN0aWNpdHkuIE1vZGVsIG5hxI9hbGVqIHZ5c3ZldMS+dWplIHbDpMSNxaFpbnUgdmFyaWFiaWxpdHkgc3RyZWRuZWogdGVwbG90eSBhIGTDtGxlxb5pdMOpIHZ6xaVhaHkgbWVkemkgcHJlbWVubsO9bWkgc8O6IGphc25lIGlkZW50aWZpa292YXRlxL5uw6kuDQoNCiMgWsOhdmVyDQoNCk5hIHrDoWtsYWRlIHZ5a29uYW5laiBhbmFsw716eSBtw7TFvmVtZSBrb27FoXRhdG92YcWlLCDFvmUgbW9kZWwgc3RyZWRuZWogdGVwbG90eSB2IEJhemlsZWppIHZlxL5taSBkb2JyZSB2eXN2ZXTEvnVqZSB2w6TEjcWhaW51IHZhcmlhYmlsaXR5IGTDoXQuIFJvYnVzdG7DqSDFoXRhbmRhcmRuw6kgY2h5YnkgemFiZXpwZcSNaWxpIHNwb8S+YWhsaXZlasWhaXUgaW5mZXJlbmNpdSBhaiBuYXByaWVrIHByw610b21ub3N0aSBoZXRlcm9za2VkYXN0aWNpdHkuIEvEvsO6xI1vdsOpIHByZW1lbm7DqSwgYWtvIG1pbmltw6FsbmEgYSBtYXhpbcOhbG5hIHRlcGxvdGEsIHZsaGtvc8WlLCBvYmxhxI1ub3PFpSBhIGdsb2LDoWxuZSDFvmlhcmVuaWUsIG1hasO6IHbDvXJhem7DvSBhIMWhdGF0aXN0aWNreSB2w716bmFtbsO9IHZwbHl2IG5hIHN0cmVkbsO6IHRlcGxvdHUuIENlbGtvdm8gbW9kZWwgcG9za3l0dWplIHByZXNuw70gYSBpbnRlcnByZXRvdmF0ZcS+bsO9IHBvaMS+YWQgbmEgdnrFpWFoeSBtZWR6aSBtZXRlb3JvbG9naWNrw71taSBmYWt0b3JtaSBhIHRlcGxvdG91Lg0K