Špecifikácia modelu – pH a kvalita vody
data <- read.csv("Indian_water_data.csv")
# doplnenie NA mediánmi
column_medians <- sapply(data, median, na.rm = TRUE)
for (col in names(data)) {
if (is.numeric(data[[col]])) {
data[[col]][is.na(data[[col]])] <- column_medians[col]
}
}
data$Fecal.Coliform..MPN.100ml....Max[
data$Fecal.Coliform..MPN.100ml....Max %in% c("", "BDL", "NA")
] <- NA
data$Fecal.Coliform..MPN.100ml....Max <- as.numeric(data$Fecal.Coliform..MPN.100ml....Max)
Základná regresia
Tu dáme pH…Max ako závislú premennú a zopár kľúčových ukazovateľov
kvality vody ako vysvetľujúce:
library(lmtest)
library(car)
library(MASS)
model_pH <- lm(
pH...Max ~ Temperature..C....Max +
Dissolved...Max +
Conductivity...µmho.cm....Max +
BOD..mg.L....Max +
NitrateN..mg.L....Max,
data = data
)
summary(model_pH)
Call:
lm(formula = pH...Max ~ Temperature..C....Max + Dissolved...Max +
Conductivity...µmho.cm....Max + BOD..mg.L....Max + NitrateN..mg.L....Max,
data = data)
Residuals:
Min 1Q Median 3Q Max
-1.1756 -0.2354 -0.0322 0.1904 3.3086
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 7.828e+00 2.349e-01 33.323 < 2e-16 ***
Temperature..C....Max -1.311e-02 4.871e-03 -2.692 0.007748 **
Dissolved...Max 4.929e-02 1.979e-02 2.490 0.013641 *
Conductivity...µmho.cm....Max 5.200e-06 1.501e-06 3.465 0.000656 ***
BOD..mg.L....Max 9.465e-04 3.575e-03 0.265 0.791508
NitrateN..mg.L....Max 3.606e-02 1.155e-02 3.123 0.002073 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4217 on 188 degrees of freedom
Multiple R-squared: 0.1824, Adjusted R-squared: 0.1607
F-statistic: 8.388 on 5 and 188 DF, p-value: 3.51e-07
Základný lineárny model vysvetľuje maximálne pH vody pomocou teploty,
množstva rozpusteného kyslíka, vodivosti, BOD a obsahu dusičnanov.
Koeficienty interpretujeme ako zmenu pH pri jednotkovej zmene danej
premennej, za podmienky ceteris paribus.
2. Grafická analýza – Residuals vs Fitted + C+R grafy
2.1. Residuals vs Fitted
Ak rezíduá v grafe Residuals vs Fitted tvoria náhodný oblak okolo
nulovej osi, je lineárna špecifikácia v poriadku. Ak vidno zakrivenie
(napr. tvar U alebo S), naznačuje to potrebu nelineárnej transformácie
niektorej premennej (napr. kvadrát, logaritmus).
par(mfrow = c(2, 2))
plot(model_pH)
par(mfrow = c(1, 1))

Interpretácia diagnostických grafov regresného modelu (pH…Max)
1. Residuals vs Fitted
Rezíduá sú rozložené náhodne okolo nulovej osi, bez systematického
zakrivenia.
Červená LOESS krivka je takmer vodorovná, čo znamená, že model nemá
výrazný problém s nelinearitou.
Bod „191“ a „66“ sú mierne odľahlé, ale nie extrémne.
Nevzniká žiadny „lievikovitý“ tvar → predpoklad homoskedasticity je
vizuálne splnený.
Záver:
Lineárny tvar regresnej funkcie je vhodný, rezíduá neukazujú
systematické vzory.
2. Q–Q plot (normalita rezíduí)
Väčšina bodov leží na diagonále → rezíduá sú takmer normálne
rozložené.
Odchýlky sú viditeľné najmä na koncoch (napr. pri bode 191), čo
naznačuje mierne ťažšie chvosty.
Tieto odchýlky však nepredstavujú vážny problém pre OLS, keďže model má
nízky rozptyl rezíduí.
Záver:
Normalita rezíduí je dostatočne dobrá, s menšími odchýlkami v extrémoch,
čo je typické pre environmentálne dáta.
3. Scale–Location (homoskedasticita)
Body sú rozložené rovnomerne a LOESS krivka je takmer rovná.
Nevzniká viditeľný „lievikovitý“ tvar, takže variabilita rezíduí sa
nemení s veľkosťou predikcií.
Záver:
Predpoklad konštantného rozptylu chýb (homoskedasticity) je vizuálne
splnený.
Tento výsledok je v súlade aj s Ramseyho RESET testom, ktorý nepotvrdil
chybnú špecifikáciu.
4. Residuals vs Leverage (vplyvné pozorovania)
Väčšina pozorovaní má veľmi nízky „leverage“.
Body 191, 66 a 35 majú mierne zvýšené leverage, ale žiadny z nich:
- nepresahuje Cookovu vzdialenosť 0.5,
- nenachádza sa v oblasti, kde by výrazne ovplyvnil koeficienty.
Model teda neobsahuje extrémne vplyvné pozorovanie.
Záver:
Vplyvné body sú minimálne; model je stabilný a robustný voči jednotlivým
pozorovaniam.
2.2. Component + Residual (C+R) grafy
V C+R grafe sledujeme, či sa hladká krivka výrazne odchyľuje od
priamky. Ak áno pri niektorej premennej (napr. Conductivity…µmho.cm….Max
alebo Temperature..C….Max), je to kandidát na kvadratickú alebo
logaritmickú transformáciu.

Interpretácia Component + Residual (C+R) grafov
Prehľad
C+R grafy zobrazujú, či je vzťah medzi jednotlivými vysvetľujúcimi
premennými a závislou premennou (pH…Max) približne lineárny.
Ružová krivka predstavuje nelineárne vyhladenie (loess), zelená čiara je
lineárny vzťah predpokladaný modelom.
Ak sa ružová krivka výrazne odchyľuje od zelenej, znamená to, že
premenná by si mohla vyžadovať nelineárnu transformáciu (napr. log,
druhá mocnina).
1. Temperature..C….Max
Ružová LOESS krivka je takmer vodorovná a neukazuje žiadne ohyby či
zakrivenia.
Vzťah medzi teplotou a pH je teda bližší lineárnemu,
bez známok nelinearity.
Záver:
Teplota nevyžaduje transformáciu, lineárny vzťah je postačujúci.
2. Dissolved…Max (rozpustený kyslík)
Krivka LOESS je relatívne rovná, s minimálnymi odchýlkami od
lineárnej časti.
Nevyzerá to, že by existovala výrazná nelinearita.
Záver:
Vzťah medzi rozpusteným kyslíkom a pH je dobre aproximovaný
lineárne.
3. Conductivity…µmho.cm….Max (vodivosť)
Ružová krivka je opäť takmer identická s lineárnou časťou.
Aj keď existuje zopár extrémnych hodnôt vodivosti, krivka sa
nedeformuje.
Záver:
Žiadna viditeľná nelinearita; vodivosť nie je potrebné
transformovať.
4. BOD..mg.L….Max
Krivka LOESS je úplne rovná, čo naznačuje absenciu akejkoľvek
nelinearity.
Hodnoty BOD sú extrémne koncentrované pri nízkych hodnotách, ale to nie
je problém.
Záver:
Premenná BOD sa správa lineárne, transformácie nie sú potrebné.
5. NitrateN..mg.L….Max (dusičnany)
Ružová krivka je mierne zvlnená, ale celkový vzťah je stále veľmi
blízky priamke.
Malé lokálne odchýlky nie sú dostatočné na to, aby naznačili potrebu
transformácie.
Záver:
Vzťah medzi dusičnanmi a pH je takmer lineárny; transformácia nie je
potrebná.
3. Nelineárna špecifikácia – pridanie kvadrátov (analóg Schooling²,
BMI²)
Povedzme, že C+R grafy naznačia nelinearitu najmä pri teplote a
vodivosti. Pridáme teda ich kvadráty:
model_pH_poly <- lm(
pH...Max ~ Temperature..C....Max +
I(Temperature..C....Max^2) +
Dissolved...Max +
Conductivity...µmho.cm....Max +
I(Conductivity...µmho.cm....Max^2) +
BOD..mg.L....Max +
NitrateN..mg.L....Max,
data = data
)
summary(model_pH_poly)
Call:
lm(formula = pH...Max ~ Temperature..C....Max + I(Temperature..C....Max^2) +
Dissolved...Max + Conductivity...µmho.cm....Max + I(Conductivity...µmho.cm....Max^2) +
BOD..mg.L....Max + NitrateN..mg.L....Max, data = data)
Residuals:
Min 1Q Median 3Q Max
-1.1768 -0.2349 -0.0313 0.1903 3.3074
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 7.805e+00 4.287e-01 18.206 < 2e-16
Temperature..C....Max -1.097e-02 3.096e-02 -0.354 0.72360
I(Temperature..C....Max^2) -4.422e-05 6.171e-04 -0.072 0.94295
Dissolved...Max 4.945e-02 1.997e-02 2.476 0.01417
Conductivity...µmho.cm....Max 2.346e-06 1.464e-05 0.160 0.87281
I(Conductivity...µmho.cm....Max^2) 5.114e-11 2.629e-10 0.195 0.84597
BOD..mg.L....Max 1.023e-03 3.632e-03 0.282 0.77847
NitrateN..mg.L....Max 3.639e-02 1.173e-02 3.104 0.00221
(Intercept) ***
Temperature..C....Max
I(Temperature..C....Max^2)
Dissolved...Max *
Conductivity...µmho.cm....Max
I(Conductivity...µmho.cm....Max^2)
BOD..mg.L....Max
NitrateN..mg.L....Max **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4239 on 186 degrees of freedom
Multiple R-squared: 0.1826, Adjusted R-squared: 0.1518
F-statistic: 5.935 on 7 and 186 DF, p-value: 3.04e-06
V modifikovanom modeli pridávame kvadrát teploty a kvadrát vodivosti.
Ak sú tieto kvadratické koeficienty štatisticky významné (p < 0.05),
potvrdzuje to nelineárny vzťah pH s danými premennými.
Model je ako celok štatisticky významný
(F = 5.935, p-hodnota ≈ 3.04e-06), pričom vysvetľuje približne
18 % variability pH
( \(R^2 = 0.1826\), upravené \(R^2 = 0.1518\) ). Oproti základnému
lineárnemu modelu sa však hodnota
upravenej determinácie zlepšila len minimálne.
Z hľadiska jednotlivých koeficientov vidíme, že:
- kvadratický člen teploty
I(Temperature..C....Max^2) má p-hodnotu ≈ 0.943 →
nie je štatisticky významný;
- kvadratický člen vodivosti
I(Conductivity...µmho.cm....Max^2) má p-hodnotu ≈ 0.846 →
taktiež nie je významný;
- aj pôvodné lineárne členy teploty a
vodivosti v tomto rozšírenom modeli nie sú
významné
(p-hodnoty 0.724 a 0.873);
- významné zostávajú najmä premenné Dissolved…Max (p
≈ 0.014) a NitrateN..mg.L….Max (p ≈ 0.002).
Keďže ani kvadrát teploty, ani kvadrát vodivosti nie sú štatisticky
významné a nezlepšujú výraznejšie ani
upravované \(R^2\), nemáme dôkaz o tom,
že by vzťah pH s teplotou alebo vodivosťou bol v tomto modeli výrazne
nelineárny.
Záver:
Pridanie kvadratických členov teploty a vodivosti neprinieslo
podstatné zlepšenie modelu a ich koeficienty sú
nevýznamné. Z pohľadu špecifikácie teda postačuje jednoduchšia
lineárna verzia modelu bez kvadratických členov.
4. Porovnanie základného a kvadratického modelu (ANOVA + RESET)
4.1. ANOVA porovnanie
Porovnali sme základný lineárny model
model_pH a rozšírený polynomiálny model
model_pH_poly,
ktorý obsahuje aj kvadratické členy teploty a vodivosti.
anova(model_pH, model_pH_poly)
Analysis of Variance Table
Model 1: pH...Max ~ Temperature..C....Max + Dissolved...Max + Conductivity...µmho.cm....Max +
BOD..mg.L....Max + NitrateN..mg.L....Max
Model 2: pH...Max ~ Temperature..C....Max + I(Temperature..C....Max^2) +
Dissolved...Max + Conductivity...µmho.cm....Max + I(Conductivity...µmho.cm....Max^2) +
BOD..mg.L....Max + NitrateN..mg.L....Max
Res.Df RSS Df Sum of Sq F Pr(>F)
1 188 33.432
2 186 33.424 2 0.0074757 0.0208 0.9794
Výsledok ANOVA testu:
RSS (Residual Sum of Squares) je takmer rovnaké
v oboch modeloch:
- Model 1: RSS = 33.432
- Model 2: RSS = 33.424
Rozdiel RSS je zanedbateľný (≈ 0.0075), čo
znamená, že kvadratické členy
neprispeli k žiadnemu reálnemu zlepšeniu vysvetlenej
variability.
F-test má hodnotu ≈ 0.0208,
p-hodnota = 0.9794, čo je výrazne nad bežnou hladinou
významnosti (0.05).
Záver ANOVA:
Nemáme dôkaz, že polynomiálny model (s kvadrátmi) je
lepší než základný lineárny model.
Kvadratické členy neprinášajú štatisticky významné zlepšenie.
Odporúča sa ponechať jednoduchší lineárny model, ktorý
je rovnako dobrý, prehľadnejší a ľahšie interpretovateľný.
4.2. RESET na kvadratickom modeli
Ak RESET po úprave ukazuje vyššiu p-hodnotu (a ideálne ≥ 0.05),
špecifikácia sa zlepšila. Ak je p stále malá, model je aj naďalej
špecifikovaný nedostatočne – možno treba logaritmus alebo inú
transformáciu.
RESET test
data: model_pH_poly
RESET = 2.0457, df1 = 2, df2 = 184, p-value = 0.1322
Výsledok:
- RESET = 2.0457
- p-hodnota = 0.1322
Keďže p-hodnota je:
- vyššia ako 0.05,
- a výrazne vyššia než v pôvodnom lineárnom modeli,
znamená to, že po pridaní kvadratických členov sa parametre modelu
lepšie prispôsobili dátam a model už neprejavuje štatisticky
významnú chybu špecifikácie.
Záver RESET testu:
Nemáme dôvod odmietnuť nulovú hypotézu, že model je
správne špecifikovaný.
Kvadratický model teda prešiel RESET testom úspešne (p ≈ 0.13).
Napriek tomu však ANOVA ukázala, že kvadratické členy neprinášajú
zlepšenie v predikcii.
Preto: > Kvadratický model síce vykazuje lepšiu špecifikáciu podľa
RESET testu,
> ale jeho prediktívna sila sa nezlepšila – preto nemá zmysel
ho používať namiesto jednoduchšieho lineárneho modelu.
5. Dummy premenná a zlom v sklone – analóg s BMI a DUM
# Dummy premenná: vysoká vodivosť
data$DUM_cond <- ifelse(data$Conductivity...µmho.cm....Max > 1000, 1, 0)
5.1. Zlom v autonómnom člene (posun nadroviny)
Koeficient pri DUM_cond hovorí, či majú lokality s vysokou vodivosťou
inú priemernú úroveň pH (vertikálny posun).
modelD_auto <- lm(
pH...Max ~ DUM_cond +
Temperature..C....Max +
Dissolved...Max +
Conductivity...µmho.cm....Max +
BOD..mg.L....Max +
NitrateN..mg.L....Max,
data = data
)
summary(modelD_auto)
Call:
lm(formula = pH...Max ~ DUM_cond + Temperature..C....Max + Dissolved...Max +
Conductivity...µmho.cm....Max + BOD..mg.L....Max + NitrateN..mg.L....Max,
data = data)
Residuals:
Min 1Q Median 3Q Max
-1.13026 -0.22015 -0.06738 0.17508 3.10543
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 7.768e+00 2.310e-01 33.620 < 2e-16 ***
DUM_cond 2.680e-01 8.998e-02 2.979 0.00328 **
Temperature..C....Max -1.211e-02 4.784e-03 -2.530 0.01222 *
Dissolved...Max 5.089e-02 1.940e-02 2.623 0.00943 **
Conductivity...µmho.cm....Max 8.704e-07 2.067e-06 0.421 0.67419
BOD..mg.L....Max -2.141e-03 3.653e-03 -0.586 0.55848
NitrateN..mg.L....Max 3.030e-02 1.148e-02 2.640 0.00898 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4131 on 187 degrees of freedom
Multiple R-squared: 0.2194, Adjusted R-squared: 0.1944
F-statistic: 8.762 on 6 and 187 DF, p-value: 2.04e-08
Do modelu sme zaradili dummy premennú
DUM_cond, ktorá rozlišuje lokality:
DUM_cond = 0 – lokality s nižšou
vodivosťou,
DUM_cond = 1 – lokality s vysokou
vodivosťou.
Odhadnutý model má tvar:
\[
\text{pH...Max} = \beta_0 + \beta_1 DUM\_cond +
\beta_2 \text{Temperature..C....Max} +
\beta_3 \text{Dissolved...Max} +
\beta_4 \text{Conductivity...µmho.cm....Max} +
\beta_5 \text{BOD..mg.L....Max} +
\beta_6 \text{NitrateN..mg.L....Max} + u.
\]
Význam jednotlivých koeficientov
(Intercept) = 7.768, p < 2e-16
Odhadovaná priemerná hodnota pH v referenčnej skupine (nižšia vodivosť,
DUM_cond = 0), pri priemerných hodnotách ostatných
premenných.
DUM_cond = 0.268, p = 0.00328
(štatisticky významné)
Lokality s vysokou vodivosťou
(DUM_cond = 1) majú v priemere o približne 0.27
jednotky vyššie pH ako lokality s nízkou vodivosťou, za inak
rovnakých podmienok.
→ Potvrdzuje sa vertikálny posun regresnej nadroviny
podľa úrovne vodivosti.
Temperature..C....Max = −0.0121, p
= 0.01222
Pri zvýšení maximálnej teploty o 1 °C klesne pH v priemere o
0.012, pri nezmenených ostatných premenných.
Dissolved...Max = 0.0509, p =
0.00943
Vyšší obsah rozpusteného kyslíka je spojený s mierne vyšším
pH – pri náraste o 1 mg/l stúpne pH približne o 0.051.
Conductivity...µmho.cm....Max –
koeficient je malý a nevýznamný (p ≈ 0.67)
→ po zohľadnení dummy premennej DUM_cond už samotná
lineárna zmena vodivosti nemá na pH štatisticky významný vplyv.
BOD..mg.L....Max – koeficient je
nevýznamný (p ≈ 0.56)
→ BOD sa v tomto modeli neukazuje ako dôležitý determinant pH.
NitrateN..mg.L....Max = 0.0303, p =
0.00898
Vyšší obsah dusičnanov je spojený s rastom pH, pri
náraste o 1 mg/l vzrastie pH asi o 0.03.
Kvalita modelu
Residual standard error = 0.4131
Typická odchýlka pozorovaného pH od hodnoty predikovanej modelom je
približne 0.41 pH jednotky.
R² = 0.2194, upravené R² = 0.1944
Model vysvetľuje približne 19–22 % variability pH, čo
je mierne viac než základný model bez dummy premennej.
F-statistic = 8.762, p-value = 2.04e-08
Ako celok je model štatisticky významný – aspoň jedna z
premenných významne ovplyvňuje pH.
Záver
Zavedenie dummy premennej DUM_cond ukazuje, že:
- lokality s vysokou vodivosťou majú
systematicky vyššie pH (o približne 0.27),
- model sa mierne zlepšil (vyššie upravené \(R^2\)),
- hlavnými významnými faktormi sú teplota, rozpustený kyslík,
dusičnany a samotný posun podľa
DUM_cond.
Model so zlomom v autonómnom člene teda naznačuje, že úroveň
vodivosti ovplyvňuje priemernú úroveň pH prostredníctvom
vertikálneho posunu, aj keď lineárny efekt samotnej vodivosti zostáva
nevýznamný.
5.2. Zlom v sklone (interakcia DUM * Conductivity)
modelD_slope <- lm(
pH...Max ~
Temperature..C....Max +
Dissolved...Max +
Conductivity...µmho.cm....Max +
I(DUM_cond * Conductivity...µmho.cm....Max) +
BOD..mg.L....Max +
NitrateN..mg.L....Max,
data = data
)
summary(modelD_slope)
Call:
lm(formula = pH...Max ~ Temperature..C....Max + Dissolved...Max +
Conductivity...µmho.cm....Max + I(DUM_cond * Conductivity...µmho.cm....Max) +
BOD..mg.L....Max + NitrateN..mg.L....Max, data = data)
Residuals:
Min 1Q Median 3Q Max
-1.1863 -0.2367 -0.0270 0.1894 3.3178
Coefficients:
Estimate Std. Error t value
(Intercept) 7.817e+00 2.401e-01 32.554
Temperature..C....Max -1.307e-02 4.888e-03 -2.673
Dissolved...Max 4.942e-02 1.985e-02 2.489
Conductivity...µmho.cm....Max 3.439e-05 1.244e-04 0.276
I(DUM_cond * Conductivity...µmho.cm....Max) -2.903e-05 1.237e-04 -0.235
BOD..mg.L....Max 1.099e-03 3.643e-03 0.302
NitrateN..mg.L....Max 3.574e-02 1.166e-02 3.065
Pr(>|t|)
(Intercept) < 2e-16 ***
Temperature..C....Max 0.00817 **
Dissolved...Max 0.01367 *
Conductivity...µmho.cm....Max 0.78255
I(DUM_cond * Conductivity...µmho.cm....Max) 0.81476
BOD..mg.L....Max 0.76319
NitrateN..mg.L....Max 0.00250 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.4228 on 187 degrees of freedom
Multiple R-squared: 0.1826, Adjusted R-squared: 0.1564
F-statistic: 6.964 on 6 and 187 DF, p-value: 1.07e-06
V tomto modeli povoľujeme, aby sa sklon vzťahu medzi
vodivosťou a pH líšil podľa toho,
či má lokalita nízku alebo vysokú vodivosť. To zabezpečuje interakčný
člen
I(DUM_cond * Conductivity...µmho.cm....Max).
Model má tvar:
\[
\text{pH...Max} =
\beta_0 +
\beta_1 \text{Temperature} +
\beta_2 \text{Dissolved} +
\beta_3 \text{Conductivity} +
\beta_4 (DUM\_cond \times \text{Conductivity}) +
\beta_5 \text{BOD} +
\beta_6 \text{NitrateN} + u.
\]
- Pre lokality s nižšou vodivosťou
(
DUM_cond = 0) je sklon podľa vodivosti rovný \(\beta_3\).
- Pre lokality s vysokou vodivosťou
(
DUM_cond = 1) je sklon podľa vodivosti rovný \(\beta_3 + \beta_4\).
Hlavné výsledky
- Interakcia
I(DUM_cond * Conductivity...)
- odhad: −2.90e−05
- p-hodnota = 0.81476
→ interakčný efekt nie je štatisticky významný.
Nemáme dôkaz, že by sa sklon vzťahu vodivosti a pH
líšil medzi skupinami s nízkou a vysokou vodivosťou.
Conductivity...µmho.cm....Max
- p-hodnota = 0.78255
→ samotný lineárny efekt vodivosti je v prítomnosti interakcie taktiež
nevýznamný.
- Ostatné premenné sa správajú podobne ako v predchádzajúcich
modeloch:
- Temperature..C….Max – negatívny, významný vplyv
(vyššia teplota → nižšie pH),
- Dissolved…Max – pozitívny, významný vplyv,
- NitrateN..mg.L….Max – pozitívny, významný
vplyv,
- BOD..mg.L….Max – nevýznamný.
Kvalita modelu
- Residual standard error = 0.4228,
- R² = 0.1826, upravené R² = 0.1564,
- F-statistic = 6.964, p-value = 1.07e-06.
Model je ako celok síce štatisticky významný, ale vysvetlená
variabilita pH je podobná ako v základnom lineárnom modeli bez
interakcie.
Záver
Interakcia DUM_cond * Conductivity:
- nie je štatisticky významná,
- nezlepšuje vysvetľovaciu schopnosť modelu (R² zostáva prakticky
rovnaké),
- nenaznačuje existenciu zlomu v sklone regresnej
nadroviny podľa úrovne vodivosti.
Preto nemáme dôvod používať zložitejší model so zlomom v
sklone; na opis vzťahu medzi pH a vodivosťou postačuje
jednoduchší lineárny model bez interakcie.
5.3. Porovnanie modelu so zlomom v sklone s lineárnym modelom
# Porovnanie so základným modelom
anova(model_pH, modelD_slope)
Analysis of Variance Table
Model 1: pH...Max ~ Temperature..C....Max + Dissolved...Max + Conductivity...µmho.cm....Max +
BOD..mg.L....Max + NitrateN..mg.L....Max
Model 2: pH...Max ~ Temperature..C....Max + Dissolved...Max + Conductivity...µmho.cm....Max +
I(DUM_cond * Conductivity...µmho.cm....Max) + BOD..mg.L....Max +
NitrateN..mg.L....Max
Res.Df RSS Df Sum of Sq F Pr(>F)
1 188 33.432
2 187 33.422 1 0.0098388 0.055 0.8148
# RESET test pre model so zlomom v sklone
resettest(modelD_slope)
RESET test
data: modelD_slope
RESET = 1.6402, df1 = 2, df2 = 185, p-value = 0.1967
Najprv porovnávame základný lineárny model model_pH a
model so zlomom v sklone
(interakcia DUM_cond * Conductivity) pomocou ANOVA
testu.
ANOVA porovnanie modelov
Výsledky:
- RSS základného modelu: 33.432
- RSS modelu so zlomom v sklone: 33.422
Rozdiel RSS je iba 0.0098, čo je zanedbateľné.
- F = 0.055,
- p-hodnota = 0.8148
Keďže p-hodnota > 0.05, nemáme dôkaz, že model so
zlomom v sklone poskytuje lepšie vysvetlenie variability pH než pôvodný
lineárny model.
Záver ANOVA:
Interakcia DUM_cond * Conductivity nezlepšuje
model.
Neexistuje významný rozdiel medzi modelmi.
→ Lineárny model zostáva vhodnejšou a jednoduchšou
voľbou.
RESET test pre model so zlomom v sklone
RESET test hodnotí, či je model správne špecifikovaný.
Výsledok:
- RESET = 1.6402
- p-hodnota = 0.1967
Keďže p-hodnota > 0.05, neodmietame hypotézu správnej
špecifikácie.
Záver RESET:
Model so zlomom v sklone nie je zle
špecifikovaný.
Avšak podľa ANOVA neprináša žiadne zlepšenie oproti základnému
modelu.
Celkové zhrnutie
- Aj keď model so zlomom v sklone neporušuje predpoklady (RESET
OK),
neprináša žiadne zlepšenie vysvetlenej variability pH
(ANOVA p = 0.8148).
- Interakcia vodivosti s dummy premennou
DUM_cond
nie je významná.
- Najlepšou voľbou zostáva základný lineárny model bez
interakcie.
Model so zlomom v sklone je síce akceptovateľný, ale štatisticky
zbytočný.
6. Box-Cox test pre transformáciu závislej premennej pH…Max
Nakoniec analóg Box-Cox testu:

Na grafe sú zobrazené hodnoty log-likelihood pre
rôzne hodnoty parametra \(\lambda\).
Maximum krivky (a teda aj „najlepšia“ transformácia podľa Box–Cox) sa
nachádza približne pri
\[
\hat\lambda \approx -1.
\]
Zároveň 95 % interval spoľahlivosti (vyznačený vodorovnou bodkovanou
čiarou) nezahŕňa hodnoty \(\lambda = 1\) ani \(\lambda = 0\). To znamená:
- \(\lambda = 1\): bez
transformácie pH – nie je optimálne podľa Box–Cox;
- \(\lambda = 0\):
logaritmická transformácia \(\log(\text{pH...Max})\) – tiež nie je v
oblasti najvyššej vierohodnosti;
- \(\lambda \approx -1\): odporúčaná
je recipročná transformácia typu \(1/\text{pH...Max}\) (presnejšie
transformácia \((\text{pH...Max}^\lambda -
1)/\lambda\) s \(\lambda \approx
-1\)).
Inými slovami, Box–Cox test naznačuje, že pre lepšie splnenie
predpokladov lineárnej regresie by bolo vhodné transformovať
vysvetľovanú premennú približne ako
\[
Y^{(\lambda)} = \frac{\text{pH...Max}^{\,\lambda} - 1}{\lambda}, \quad
\lambda \approx -1,
\]
- pracovať skôr s inverznou hodnotou pH, než s
pôvodným pH alebo s log(pH).
Takto transformovaná premenná sa potom použije ako závislá premenná v
modeli:
lambda <- -1 # odporúčaná hodnota z Box–Cox grafu
# transformácia pH podľa Box–Cox vzorca
if (lambda == 0) {
pH_tr <- log(data$`pH...Max`)
} else {
pH_tr <- (data$`pH...Max`^lambda - 1) / lambda
}
# model s transformovanou premennou
model_boxcox <- lm(
pH_tr ~ Temperature..C....Max +
Dissolved...Max +
Conductivity...µmho.cm....Max +
BOD..mg.L....Max +
NitrateN..mg.L....Max,
data = data
)
summary(model_boxcox)
Call:
lm(formula = pH_tr ~ Temperature..C....Max + Dissolved...Max +
Conductivity...µmho.cm....Max + BOD..mg.L....Max + NitrateN..mg.L....Max,
data = data)
Residuals:
Min 1Q Median 3Q Max
-0.022259 -0.003402 -0.000185 0.002832 0.038082
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 8.712e-01 3.439e-03 253.350 < 2e-16 ***
Temperature..C....Max -2.117e-04 7.131e-05 -2.969 0.00338 **
Dissolved...Max 8.802e-04 2.897e-04 3.038 0.00272 **
Conductivity...µmho.cm....Max 8.820e-08 2.196e-08 4.016 8.56e-05 ***
BOD..mg.L....Max 2.934e-05 5.234e-05 0.561 0.57569
NitrateN..mg.L....Max 5.397e-04 1.690e-04 3.193 0.00165 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.006173 on 188 degrees of freedom
Multiple R-squared: 0.2174, Adjusted R-squared: 0.1966
F-statistic: 10.44 on 5 and 188 DF, p-value: 7.378e-09
# RESET test správnej špecifikácie
resettest(model_boxcox)
RESET test
data: model_boxcox
RESET = 1.9328, df1 = 2, df2 = 186, p-value = 0.1476
Na základe Box–Cox testu sme zvolili parameter \(\lambda = -1\) a pH transformovali podľa
vzorca
\[
pH^{(-1)} = \frac{\text{pH...Max}^{-1} - 1}{-1}.
\]
Transformovaná premenná pH_tr sa použila ako závislá
premenná v modeli:
\[
pH\_tr = \beta_0 + \beta_1 \text{Temperature} +
\beta_2 \text{Dissolved} +
\beta_3 \text{Conductivity} +
\beta_4 \text{BOD} +
\beta_5 \text{NitrateN} + u.
\]
Výsledky regresie
Intercept = 0.8712, p < 2e-16
→ pri priemerných hodnotách vysvetľujúcich premenných má transformované
pH hodnotu okolo 0.87.
Temperature..C….Max = −2.12e−04, p =
0.00338
→ vyššia teplota vedie k zníženiu transformovaného pH,
čo zodpovedá poklesu pôvodného pH.
Dissolved…Max = 8.80e−04, p = 0.00272
→ vyšší obsah rozpusteného kyslíka je spojený s vyšším
transformovaným pH, teda aj s vyšším pôvodným pH.
Conductivity…µmho.cm….Max = 8.82e−08, p =
8.56e−05
→ vodivosť má pozitívny a štatisticky veľmi významný
vplyv na transformované pH; pri veľkých zmenách vodivosti ide o
mierny, ale systematický efekt.
BOD..mg.L….Max – koeficient je nevýznamný (p ≈
0.576)
→ BOD stále nevykazuje štatisticky významný vplyv na pH.
NitrateN..mg.L….Max = 5.40e−04, p =
0.00165
→ vyšší obsah dusičnanov je spojený s vyšším transformovaným
pH, teda aj s vyšším pôvodným pH.
Kvalita modelu
Residual standard error = 0.00617
→ rezíduá sú veľmi malé, čo súvisí aj s mierkou transformovanej
premennej.
R² = 0.2174, upravené R² = 0.1966
→ model vysvetľuje približne 20–22 % variability
transformovaného pH, čo je mierne viac než pri pôvodnom
(netransformovanom) modeli.
F-statistic = 10.44, p-value ≈ 7.38e−09
→ model je ako celok štatisticky veľmi
významný.
RESET test pre Box–Cox model
Výsledok RESET testu:
- RESET = 1.9328,
- p-hodnota = 0.1476.
Keďže p-hodnota > 0.05, nezamietame nulovú hypotézu o
správnej špecifikácii modelu.
Záver
- Box–Cox transformácia (λ = −1) mierne zlepšila vysvetľovaciu
schopnosť modelu
a zároveň neodhalila chybnú špecifikáciu (RESET
OK).
- Na druhej strane interpretácia koeficientov je už menej intuitívna,
keďže sa vzťahujú k transformovanej veličine
pH_tr, nie k
pôvodnému pH.
Pre praktické závery je preto vhodné:
- používať Box–Cox model najmä ako diagnostickú / doplnkovú
kontrolu,
- ale pri slovnom popise výsledkov vysvetľovať vplyv premenných skôr v
kontexte pôvodného pH, nie transformovanej škály.
LS0tCnRpdGxlOiAiQ3ZpxI1lbmllIDYg4oCTIMWgcGVjaWZpa8OhY2lhIG1vZGVsdSIKYXV0aG9yOiAiU8OhcmEgTmlrb2wgU2Nob2x0em92w6EiCmRhdGU6ICJOb3ZlbWJlciAyMDI1IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgICBoaWdobGlnaHQ6IHRhbmdvCmVkaXRvcl9vcHRpb25zOgogIG1hcmtkb3duOgogICAgd3JhcDogNzIKLS0tCmBgYHtyfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgICBlY2hvID0gVFJVRSwKICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgIHdhcm5pbmcgPSBGQUxTRSkKYGBgCmBgYHtyfQpsaWJyYXJ5KHpvbykKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGxtdGVzdCkKbGlicmFyeShzYW5kd2ljaCkKbGlicmFyeShjYXIpCnJtKGxpc3Q9bHMoKSkKYGBgCiMgxaBwZWNpZmlrw6FjaWEgbW9kZWx1IOKAkyBwSCBhIGt2YWxpdGEgdm9keQpgYGB7cn0KZGF0YSA8LSByZWFkLmNzdigiSW5kaWFuX3dhdGVyX2RhdGEuY3N2IikKCiMgZG9wbG5lbmllIE5BIG1lZGnDoW5taSAKY29sdW1uX21lZGlhbnMgPC0gc2FwcGx5KGRhdGEsIG1lZGlhbiwgbmEucm0gPSBUUlVFKQpmb3IgKGNvbCBpbiBuYW1lcyhkYXRhKSkgewogIGlmIChpcy5udW1lcmljKGRhdGFbW2NvbF1dKSkgewogICAgZGF0YVtbY29sXV1baXMubmEoZGF0YVtbY29sXV0pXSA8LSBjb2x1bW5fbWVkaWFuc1tjb2xdCiAgfQp9CmRhdGEkRmVjYWwuQ29saWZvcm0uLk1QTi4xMDBtbC4uLi5NYXhbCiAgZGF0YSRGZWNhbC5Db2xpZm9ybS4uTVBOLjEwMG1sLi4uLk1heCAlaW4lIGMoIiIsICJCREwiLCAiTkEiKQpdIDwtIE5BCmRhdGEkRmVjYWwuQ29saWZvcm0uLk1QTi4xMDBtbC4uLi5NYXggPC0gYXMubnVtZXJpYyhkYXRhJEZlY2FsLkNvbGlmb3JtLi5NUE4uMTAwbWwuLi4uTWF4KQpgYGAKCiMjIFrDoWtsYWRuw6EgcmVncmVzaWEKVHUgZMOhbWUgcEguLi5NYXggYWtvIHrDoXZpc2zDuiBwcmVtZW5uw7ogYSB6b3DDoXIga8S+w7rEjW92w71jaCB1a2F6b3ZhdGXEvm92IGt2YWxpdHkgdm9keSBha28gdnlzdmV0xL51asO6Y2U6CgpgYGB7cn0KbGlicmFyeShsbXRlc3QpCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KE1BU1MpCgptb2RlbF9wSCA8LSBsbSgKICBwSC4uLk1heCB+IFRlbXBlcmF0dXJlLi5DLi4uLk1heCArCiAgICBEaXNzb2x2ZWQuLi5NYXggKwogICAgQ29uZHVjdGl2aXR5Li4uwrVtaG8uY20uLi4uTWF4ICsKICAgIEJPRC4ubWcuTC4uLi5NYXggKwogICAgTml0cmF0ZU4uLm1nLkwuLi4uTWF4LAogIGRhdGEgPSBkYXRhCikKCnN1bW1hcnkobW9kZWxfcEgpCmBgYApaw6FrbGFkbsO9IGxpbmXDoXJueSBtb2RlbCB2eXN2ZXTEvnVqZSBtYXhpbcOhbG5lIHBIIHZvZHkgcG9tb2NvdSB0ZXBsb3R5LCBtbm/FvnN0dmEgcm96cHVzdGVuw6lobyBreXNsw61rYSwgdm9kaXZvc3RpLCBCT0QgYSBvYnNhaHUgZHVzacSNbmFub3YuIEtvZWZpY2llbnR5IGludGVycHJldHVqZW1lIGFrbyB6bWVudSBwSCBwcmkgamVkbm90a292ZWogem1lbmUgZGFuZWogcHJlbWVubmVqLCB6YSBwb2RtaWVua3kgY2V0ZXJpcyBwYXJpYnVzLgoKIyMgMS4gUkVTRVQgdGVzdCDigJMgdGVzdCBzcHLDoXZuZWogZnVua8SNbmVqIGZvcm15CkFuYWzDs2cgUmFtc2V5aG8gUkVTRVQgdGVzdHU6CmBgYHtyfQpyZXNldHRlc3QobW9kZWxfcEgpCmBgYApSYW1zZXlobyBSRVNFVCB0ZXN0IChwID0gMC4xOTk0KSBuZW9kaGFsaWwgY2h5Ym7DuiDFoXBlY2lmaWvDoWNpdSBtb2RlbHUuCktlxI/FvmUgcC1ob2Rub3RhIGplIHbDvXJhem5lIHZ5xaHFoWlhIGFrbyA1ICUsIG5lemFtaWV0YW1lIG51bG92w7ogaHlwb3TDqXp1IG8gc3Byw6F2bmVqIGZ1bmvEjW5laiBmb3JtZS4KVG8gem5hbWVuw6EsIMW+ZSB2IG1vZGVsaSBwcmF2ZGVwb2RvYm5lIG5lY2jDvWJhasO6IMW+aWFkbmUgZMO0bGXFvml0w6kgbmVsaW5lw6FybmUgdHJhbnNmb3Jtw6FjaWUgYW5pIHphbmVkYmFuw6kgcHJlbWVubsOpIGEgbGluZcOhcm55IHR2YXIgcmVncmVzbmVqIGZ1bmtjaWUgamUgcG9zdGHEjXVqw7pjaS4KCiMjIDIuIEdyYWZpY2vDoSBhbmFsw716YSDigJMgUmVzaWR1YWxzIHZzIEZpdHRlZCArIEMrUiBncmFmeQojIyMgMi4xLiBSZXNpZHVhbHMgdnMgRml0dGVkCgpBayByZXrDrWR1w6EgdiBncmFmZSBSZXNpZHVhbHMgdnMgRml0dGVkIHR2b3JpYSBuw6Fob2Ruw70gb2JsYWsgb2tvbG8gbnVsb3ZlaiBvc2ksIGplIGxpbmXDoXJuYSDFoXBlY2lmaWvDoWNpYSB2IHBvcmlhZGt1LiBBayB2aWRubyB6YWtyaXZlbmllIChuYXByLiB0dmFyIFUgYWxlYm8gUyksIG5hem5hxI11amUgdG8gcG90cmVidSBuZWxpbmXDoXJuZWogdHJhbnNmb3Jtw6FjaWUgbmlla3RvcmVqIHByZW1lbm5laiAobmFwci4ga3ZhZHLDoXQsIGxvZ2FyaXRtdXMpLgpgYGB7cn0KcGFyKG1mcm93ID0gYygyLCAyKSkKcGxvdChtb2RlbF9wSCkKcGFyKG1mcm93ID0gYygxLCAxKSkKYGBgCiMjIEludGVycHJldMOhY2lhIGRpYWdub3N0aWNrw71jaCBncmFmb3YgcmVncmVzbsOpaG8gbW9kZWx1IChwSOKApk1heCkKCiMjIyAxLiBSZXNpZHVhbHMgdnMgRml0dGVkCgpSZXrDrWR1w6Egc8O6IHJvemxvxb5lbsOpIG7DoWhvZG5lIG9rb2xvIG51bG92ZWogb3NpLCBiZXogc3lzdGVtYXRpY2vDqWhvIHpha3JpdmVuaWEuICAKxIxlcnZlbsOhIExPRVNTIGtyaXZrYSBqZSB0YWttZXIgdm9kb3Jvdm7DoSwgxI1vIHpuYW1lbsOhLCDFvmUgbW9kZWwgbmVtw6EgdsO9cmF6bsO9IHByb2Jsw6ltIHMgbmVsaW5lYXJpdG91LiAgCkJvZCDigJ4xOTHigJwgYSDigJ42NuKAnCBzw7ogbWllcm5lIG9kxL5haGzDqSwgYWxlIG5pZSBleHRyw6ltbmUuICAKTmV2em5pa8OhIMW+aWFkbnkg4oCebGlldmlrb3ZpdMO94oCcIHR2YXIg4oaSIHByZWRwb2tsYWQgaG9tb3NrZWRhc3RpY2l0eSBqZSB2aXp1w6FsbmUgc3BsbmVuw70uCgoqKlrDoXZlcjoqKiAgCkxpbmXDoXJueSB0dmFyIHJlZ3Jlc25laiBmdW5rY2llIGplIHZob2Ruw70sIHJlesOtZHXDoSBuZXVrYXp1asO6IHN5c3RlbWF0aWNrw6kgdnpvcnkuCgotLS0KCiMjIyAyLiBR4oCTUSBwbG90IChub3JtYWxpdGEgcmV6w61kdcOtKQoKVsOkxI3FoWluYSBib2RvdiBsZcW+w60gbmEgZGlhZ29uw6FsZSDihpIgcmV6w61kdcOhIHPDuiB0YWttZXIgbm9ybcOhbG5lIHJvemxvxb5lbsOpLiAgCk9kY2jDvWxreSBzw7ogdmlkaXRlxL5uw6kgbmFqbcOkIG5hIGtvbmNvY2ggKG5hcHIuIHByaSBib2RlIDE5MSksIMSNbyBuYXpuYcSNdWplIG1pZXJuZSDFpWHFvsWhaWUgY2h2b3N0eS4gIApUaWV0byBvZGNow71sa3kgdsWhYWsgbmVwcmVkc3RhdnVqw7ogdsOhxb5ueSBwcm9ibMOpbSBwcmUgT0xTLCBrZcSPxb5lIG1vZGVsIG3DoSBuw616a3kgcm96cHR5bCByZXrDrWR1w60uCgoqKlrDoXZlcjoqKiAgCk5vcm1hbGl0YSByZXrDrWR1w60gamUgZG9zdGF0b8SNbmUgZG9icsOhLCBzIG1lbsWhw61taSBvZGNow71sa2FtaSB2IGV4dHLDqW1vY2gsIMSNbyBqZSB0eXBpY2vDqSBwcmUgZW52aXJvbm1lbnTDoWxuZSBkw6F0YS4KCi0tLQoKIyMjIDMuIFNjYWxl4oCTTG9jYXRpb24gKGhvbW9za2VkYXN0aWNpdGEpCgpCb2R5IHPDuiByb3psb8W+ZW7DqSByb3Zub21lcm5lIGEgTE9FU1Mga3JpdmthIGplIHRha21lciByb3Zuw6EuICAKTmV2em5pa8OhIHZpZGl0ZcS+bsO9IOKAnmxpZXZpa292aXTDveKAnCB0dmFyLCB0YWvFvmUgdmFyaWFiaWxpdGEgcmV6w61kdcOtIHNhIG5lbWVuw60gcyB2ZcS+a29zxaVvdSBwcmVkaWtjacOtLgoKKipaw6F2ZXI6KiogIApQcmVkcG9rbGFkIGtvbsWhdGFudG7DqWhvIHJvenB0eWx1IGNow71iIChob21vc2tlZGFzdGljaXR5KSBqZSB2aXp1w6FsbmUgc3BsbmVuw70uICAKVGVudG8gdsO9c2xlZG9rIGplIHYgc8O6bGFkZSBhaiBzIFJhbXNleWhvIFJFU0VUIHRlc3RvbSwga3RvcsO9IG5lcG90dnJkaWwgY2h5Ym7DuiDFoXBlY2lmaWvDoWNpdS4KCi0tLQoKIyMjIDQuIFJlc2lkdWFscyB2cyBMZXZlcmFnZSAodnBseXZuw6kgcG96b3JvdmFuaWEpCgpWw6TEjcWhaW5hIHBvem9yb3ZhbsOtIG3DoSB2ZcS+bWkgbsOtemt5IOKAnmxldmVyYWdl4oCcLiAgCkJvZHkgMTkxLCA2NiBhIDM1IG1hasO6IG1pZXJuZSB6dsO9xaFlbsOpIGxldmVyYWdlLCBhbGUgxb5pYWRueSB6IG5pY2g6CgotIG5lcHJlc2FodWplIENvb2tvdnUgdnpkaWFsZW5vc8WlIDAuNSwgIAotIG5lbmFjaMOhZHphIHNhIHYgb2JsYXN0aSwga2RlIGJ5IHbDvXJhem5lIG92cGx5dm5pbCBrb2VmaWNpZW50eS4KCk1vZGVsIHRlZGEgbmVvYnNhaHVqZSBleHRyw6ltbmUgdnBseXZuw6kgcG96b3JvdmFuaWUuCgoqKlrDoXZlcjoqKiAgClZwbHl2bsOpIGJvZHkgc8O6IG1pbmltw6FsbmU7IG1vZGVsIGplIHN0YWJpbG7DvSBhIHJvYnVzdG7DvSB2b8SNaSBqZWRub3RsaXbDvW0gcG96b3JvdmFuaWFtLgoKIyMjIDIuMi4gQ29tcG9uZW50ICsgUmVzaWR1YWwgKEMrUikgZ3JhZnkKViBDK1IgZ3JhZmUgc2xlZHVqZW1lLCDEjWkgc2EgaGxhZGvDoSBrcml2a2EgdsO9cmF6bmUgb2RjaHnEvnVqZSBvZCBwcmlhbWt5LgpBayDDoW5vIHByaSBuaWVrdG9yZWogcHJlbWVubmVqIChuYXByLiBDb25kdWN0aXZpdHkuLi7CtW1oby5jbS4uLi5NYXggYWxlYm8gVGVtcGVyYXR1cmUuLkMuLi4uTWF4KSwgamUgdG8ga2FuZGlkw6F0IG5hIGt2YWRyYXRpY2vDuiBhbGVibyBsb2dhcml0bWlja8O6IHRyYW5zZm9ybcOhY2l1LgpgYGB7cn0KY2FyOjpjclBsb3RzKG1vZGVsX3BIKQpgYGAKIyMgSW50ZXJwcmV0w6FjaWEgQ29tcG9uZW50ICsgUmVzaWR1YWwgKEMrUikgZ3JhZm92CgojIyMgUHJlaMS+YWQKQytSIGdyYWZ5IHpvYnJhenVqw7osIMSNaSBqZSB2esWlYWggbWVkemkgamVkbm90bGl2w71taSB2eXN2ZXTEvnVqw7pjaW1pIHByZW1lbm7DvW1pIGEgesOhdmlzbG91IHByZW1lbm5vdSAocEjigKZNYXgpIHByaWJsacW+bmUgbGluZcOhcm55LiAgClJ1xb5vdsOhIGtyaXZrYSBwcmVkc3RhdnVqZSBuZWxpbmXDoXJuZSB2eWhsYWRlbmllIChsb2VzcyksIHplbGVuw6EgxI1pYXJhIGplIGxpbmXDoXJueSB2esWlYWggcHJlZHBva2xhZGFuw70gbW9kZWxvbS4KCkFrIHNhIHJ1xb5vdsOhIGtyaXZrYSB2w71yYXpuZSBvZGNoecS+dWplIG9kIHplbGVuZWosIHpuYW1lbsOhIHRvLCDFvmUgcHJlbWVubsOhIGJ5IHNpIG1vaGxhIHZ5xb5hZG92YcWlIG5lbGluZcOhcm51IHRyYW5zZm9ybcOhY2l1IChuYXByLiBsb2csIGRydWjDoSBtb2NuaW5hKS4KCi0tLQoKIyMjIDEuICoqVGVtcGVyYXR1cmUuLkMuLi4uTWF4KioKUnXFvm92w6EgTE9FU1Mga3JpdmthIGplIHRha21lciB2b2Rvcm92bsOhIGEgbmV1a2F6dWplIMW+aWFkbmUgb2h5YnkgxI1pIHpha3JpdmVuaWEuICAKVnrFpWFoIG1lZHppIHRlcGxvdG91IGEgcEggamUgdGVkYSAqKmJsacW+xaHDrSBsaW5lw6FybmVtdSoqLCBiZXogem7DoW1vayBuZWxpbmVhcml0eS4KCioqWsOhdmVyOioqICAKVGVwbG90YSBuZXZ5xb5hZHVqZSB0cmFuc2Zvcm3DoWNpdSwgbGluZcOhcm55IHZ6xaVhaCBqZSBwb3N0YcSNdWrDumNpLgoKLS0tCgojIyMgMi4gKipEaXNzb2x2ZWQuLi5NYXgqKiAocm96cHVzdGVuw70ga3lzbMOtaykKS3JpdmthIExPRVNTIGplIHJlbGF0w612bmUgcm92bsOhLCBzIG1pbmltw6FsbnltaSBvZGNow71sa2FtaSBvZCBsaW5lw6FybmVqIMSNYXN0aS4gIApOZXZ5emVyw6EgdG8sIMW+ZSBieSBleGlzdG92YWxhIHbDvXJhem7DoSBuZWxpbmVhcml0YS4KCioqWsOhdmVyOioqICAKVnrFpWFoIG1lZHppIHJvenB1c3RlbsO9bSBreXNsw61rb20gYSBwSCBqZSBkb2JyZSBhcHJveGltb3ZhbsO9IGxpbmXDoXJuZS4KCi0tLQoKIyMjIDMuICoqQ29uZHVjdGl2aXR5Li4uwrVtaG8uY20uLi4uTWF4KiogKHZvZGl2b3PFpSkKUnXFvm92w6Ega3JpdmthIGplIG9ww6TFpSB0YWttZXIgaWRlbnRpY2vDoSBzIGxpbmXDoXJub3UgxI1hc8Wlb3UuICAKQWoga2XEjyBleGlzdHVqZSB6b3DDoXIgZXh0csOpbW55Y2ggaG9kbsO0dCB2b2Rpdm9zdGksIGtyaXZrYSBzYSBuZWRlZm9ybXVqZS4KCioqWsOhdmVyOioqICAKxb1pYWRuYSB2aWRpdGXEvm7DoSBuZWxpbmVhcml0YTsgdm9kaXZvc8WlIG5pZSBqZSBwb3RyZWJuw6kgdHJhbnNmb3Jtb3ZhxaUuCgotLS0KCiMjIyA0LiAqKkJPRC4ubWcuTC4uLi5NYXgqKgpLcml2a2EgTE9FU1MgamUgw7pwbG5lIHJvdm7DoSwgxI1vIG5hem5hxI11amUgYWJzZW5jaXUgYWtlamtvxL52ZWsgbmVsaW5lYXJpdHkuICAKSG9kbm90eSBCT0Qgc8O6IGV4dHLDqW1uZSBrb25jZW50cm92YW7DqSBwcmkgbsOtemt5Y2ggaG9kbm90w6FjaCwgYWxlIHRvIG5pZSBqZSBwcm9ibMOpbS4KCioqWsOhdmVyOioqICAKUHJlbWVubsOhIEJPRCBzYSBzcHLDoXZhIGxpbmXDoXJuZSwgdHJhbnNmb3Jtw6FjaWUgbmllIHPDuiBwb3RyZWJuw6kuCgotLS0KCiMjIyA1LiAqKk5pdHJhdGVOLi5tZy5MLi4uLk1heCoqIChkdXNpxI1uYW55KQpSdcW+b3bDoSBrcml2a2EgamUgbWllcm5lIHp2bG5lbsOhLCBhbGUgY2Vsa292w70gdnrFpWFoIGplIHN0w6FsZSB2ZcS+bWkgYmzDrXpreSBwcmlhbWtlLiAgCk1hbMOpIGxva8OhbG5lIG9kY2jDvWxreSBuaWUgc8O6IGRvc3RhdG/EjW7DqSBuYSB0bywgYWJ5IG5hem5hxI1pbGkgcG90cmVidSB0cmFuc2Zvcm3DoWNpZS4KCioqWsOhdmVyOioqICAKVnrFpWFoIG1lZHppIGR1c2nEjW5hbm1pIGEgcEggamUgdGFrbWVyIGxpbmXDoXJueTsgdHJhbnNmb3Jtw6FjaWEgbmllIGplIHBvdHJlYm7DoS4KCgojIyAzLiBOZWxpbmXDoXJuYSDFoXBlY2lmaWvDoWNpYSDigJMgcHJpZGFuaWUga3ZhZHLDoXRvdiAoYW5hbMOzZyBTY2hvb2xpbmfCsiwgQk1JwrIpClBvdmVkem1lLCDFvmUgQytSIGdyYWZ5IG5hem5hxI1pYSBuZWxpbmVhcml0dSBuYWptw6QgcHJpIHRlcGxvdGUgYSB2b2Rpdm9zdGkuClByaWTDoW1lIHRlZGEgaWNoIGt2YWRyw6F0eToKYGBge3J9Cm1vZGVsX3BIX3BvbHkgPC0gbG0oCiAgcEguLi5NYXggfiBUZW1wZXJhdHVyZS4uQy4uLi5NYXggKwogICAgSShUZW1wZXJhdHVyZS4uQy4uLi5NYXheMikgKwogICAgRGlzc29sdmVkLi4uTWF4ICsKICAgIENvbmR1Y3Rpdml0eS4uLsK1bWhvLmNtLi4uLk1heCArCiAgICBJKENvbmR1Y3Rpdml0eS4uLsK1bWhvLmNtLi4uLk1heF4yKSArCiAgICBCT0QuLm1nLkwuLi4uTWF4ICsKICAgIE5pdHJhdGVOLi5tZy5MLi4uLk1heCwKICBkYXRhID0gZGF0YQopCgpzdW1tYXJ5KG1vZGVsX3BIX3BvbHkpCmBgYApWIG1vZGlmaWtvdmFub20gbW9kZWxpIHByaWTDoXZhbWUga3ZhZHLDoXQgdGVwbG90eSBhIGt2YWRyw6F0IHZvZGl2b3N0aS4KQWsgc8O6IHRpZXRvIGt2YWRyYXRpY2vDqSBrb2VmaWNpZW50eSDFoXRhdGlzdGlja3kgdsO9em5hbW7DqSAocCA8IDAuMDUpLCBwb3R2cmR6dWplIHRvIG5lbGluZcOhcm55IHZ6xaVhaCBwSCBzIGRhbsO9bWkgcHJlbWVubsO9bWkuCgpNb2RlbCBqZSBha28gY2Vsb2sgKirFoXRhdGlzdGlja3kgdsO9em5hbW7DvSoqICAKKEYgPSA1LjkzNSwgcC1ob2Rub3RhIOKJiCAzLjA0ZS0wNiksIHByacSNb20gdnlzdmV0xL51amUgcHJpYmxpxb5uZSAqKjE4ICUgdmFyaWFiaWxpdHkgcEgqKiAgCiggXChSXjIgPSAwLjE4MjZcKSwgdXByYXZlbsOpIFwoUl4yID0gMC4xNTE4XCkgKS4gT3Byb3RpIHrDoWtsYWRuw6ltdSBsaW5lw6FybmVtdSBtb2RlbHUgc2EgdsWhYWsgaG9kbm90YSAgCnVwcmF2ZW5laiBkZXRlcm1pbsOhY2llIHpsZXDFoWlsYSBsZW4gbWluaW3DoWxuZS4KClogaMS+YWRpc2thIGplZG5vdGxpdsO9Y2gga29lZmljaWVudG92IHZpZMOtbWUsIMW+ZToKCi0gKiprdmFkcmF0aWNrw70gxI1sZW4gdGVwbG90eSoqIGBJKFRlbXBlcmF0dXJlLi5DLi4uLk1heF4yKWAgbcOhIHAtaG9kbm90dSDiiYggMC45NDMg4oaSICoqbmllIGplIMWhdGF0aXN0aWNreSB2w716bmFtbsO9Kio7ICAKLSAqKmt2YWRyYXRpY2vDvSDEjWxlbiB2b2Rpdm9zdGkqKiBgSShDb25kdWN0aXZpdHkuLi7CtW1oby5jbS4uLi5NYXheMilgIG3DoSBwLWhvZG5vdHUg4omIIDAuODQ2IOKGkiB0YWt0aWXFviAqKm5pZSBqZSB2w716bmFtbsO9Kio7ICAKLSBhaiBww7R2b2Ruw6kgbGluZcOhcm5lIMSNbGVueSAqKnRlcGxvdHkqKiBhICoqdm9kaXZvc3RpKiogdiB0b210byByb3rFocOtcmVub20gbW9kZWxpIG5pZSBzw7ogdsO9em5hbW7DqSAgCiAgKHAtaG9kbm90eSAwLjcyNCBhIDAuODczKTsgIAotIHbDvXpuYW1uw6kgem9zdMOhdmFqw7ogbmFqbcOkIHByZW1lbm7DqSAqKkRpc3NvbHZlZC4uLk1heCoqIChwIOKJiCAwLjAxNCkgYSAqKk5pdHJhdGVOLi5tZy5MLi4uLk1heCoqIChwIOKJiCAwLjAwMikuCgpLZcSPxb5lIGFuaSBrdmFkcsOhdCB0ZXBsb3R5LCBhbmkga3ZhZHLDoXQgdm9kaXZvc3RpIG5pZSBzw7ogxaF0YXRpc3RpY2t5IHbDvXpuYW1uw6kgYSBuZXpsZXDFoXVqw7ogdsO9cmF6bmVqxaFpZSBhbmkgIAp1cHJhdm92YW7DqSBcKFJeMlwpLCBuZW3DoW1lIGTDtGtheiBvIHRvbSwgxb5lIGJ5IHZ6xaVhaCBwSCBzIHRlcGxvdG91IGFsZWJvIHZvZGl2b3PFpW91IGJvbCB2IHRvbXRvIG1vZGVsaSB2w71yYXpuZSBuZWxpbmXDoXJueS4KCioqWsOhdmVyOioqICAKUHJpZGFuaWUga3ZhZHJhdGlja8O9Y2ggxI1sZW5vdiB0ZXBsb3R5IGEgdm9kaXZvc3RpICoqbmVwcmluaWVzbG8gcG9kc3RhdG7DqSB6bGVwxaFlbmllIG1vZGVsdSoqIGEgaWNoIGtvZWZpY2llbnR5IHPDuiAgCm5ldsO9em5hbW7DqS4gWiBwb2jEvmFkdSDFoXBlY2lmaWvDoWNpZSB0ZWRhIHBvc3RhxI11amUgKipqZWRub2R1Y2jFoWlhIGxpbmXDoXJuYSB2ZXJ6aWEgbW9kZWx1IGJleiBrdmFkcmF0aWNrw71jaCDEjWxlbm92KiouCgojIyA0LiBQb3Jvdm5hbmllIHrDoWtsYWRuw6lobyBhIGt2YWRyYXRpY2vDqWhvIG1vZGVsdSAoQU5PVkEgKyBSRVNFVCkKIyMjIDQuMS4gQU5PVkEgcG9yb3ZuYW5pZQpQb3Jvdm5hbGkgc21lICoqesOha2xhZG7DvSBsaW5lw6FybnkgbW9kZWwgYG1vZGVsX3BIYCoqIGEgKipyb3rFocOtcmVuw70gcG9seW5vbWnDoWxueSBtb2RlbCBgbW9kZWxfcEhfcG9seWAqKiwgIAprdG9yw70gb2JzYWh1amUgYWoga3ZhZHJhdGlja8OpIMSNbGVueSB0ZXBsb3R5IGEgdm9kaXZvc3RpLgpgYGB7cn0KYW5vdmEobW9kZWxfcEgsIG1vZGVsX3BIX3BvbHkpCmBgYApWw71zbGVkb2sgQU5PVkEgdGVzdHU6CgotICoqUlNTIChSZXNpZHVhbCBTdW0gb2YgU3F1YXJlcykqKiBqZSB0YWttZXIgcm92bmFrw6kgdiBvYm9jaCBtb2RlbG9jaDoKICAtIE1vZGVsIDE6IFJTUyA9IDMzLjQzMiAgCiAgLSBNb2RlbCAyOiBSU1MgPSAzMy40MjQgIAoKLSAqKlJvemRpZWwgUlNTIGplIHphbmVkYmF0ZcS+bsO9KiogKOKJiCAwLjAwNzUpLCDEjW8gem5hbWVuw6EsIMW+ZSBrdmFkcmF0aWNrw6kgxI1sZW55ICAKICBuZXByaXNwZWxpIGsgxb5pYWRuZW11IHJlw6FsbmVtdSB6bGVwxaFlbml1IHZ5c3ZldGxlbmVqIHZhcmlhYmlsaXR5LgoKLSAqKkYtdGVzdCoqIG3DoSBob2Rub3R1IOKJiCAwLjAyMDgsICAKICAqKnAtaG9kbm90YSA9IDAuOTc5NCoqLCDEjW8gamUgdsO9cmF6bmUgbmFkIGJlxb5ub3UgaGxhZGlub3UgdsO9em5hbW5vc3RpICgwLjA1KS4KCiMjIyMgWsOhdmVyIEFOT1ZBOgoqKk5lbcOhbWUgZMO0a2F6KiosIMW+ZSBwb2x5bm9tacOhbG55IG1vZGVsIChzIGt2YWRyw6F0bWkpIGplIGxlcMWhw60gbmXFviB6w6FrbGFkbsO9IGxpbmXDoXJueSBtb2RlbC4gIApLdmFkcmF0aWNrw6kgxI1sZW55IG5lcHJpbsOhxaFhasO6IMWhdGF0aXN0aWNreSB2w716bmFtbsOpIHpsZXDFoWVuaWUuICAKT2Rwb3LDusSNYSBzYSAqKnBvbmVjaGHFpSBqZWRub2R1Y2jFocOtIGxpbmXDoXJueSBtb2RlbCoqLCBrdG9yw70gamUgcm92bmFrbyBkb2Jyw70sIHByZWjEvmFkbmVqxaHDrSBhIMS+YWjFoWllIGludGVycHJldG92YXRlxL5uw70uCgojIyMgNC4yLiBSRVNFVCBuYSBrdmFkcmF0aWNrb20gbW9kZWxpCkFrIFJFU0VUIHBvIMO6cHJhdmUgdWthenVqZSB2ecWhxaFpdSBwLWhvZG5vdHUgKGEgaWRlw6FsbmUg4omlIDAuMDUpLCDFoXBlY2lmaWvDoWNpYSBzYSB6bGVwxaFpbGEuCkFrIGplIHAgc3TDoWxlIG1hbMOhLCBtb2RlbCBqZSBhaiBuYcSPYWxlaiDFoXBlY2lmaWtvdmFuw70gbmVkb3N0YXRvxI1uZSDigJMgbW/Fvm5vIHRyZWJhIGxvZ2FyaXRtdXMgYWxlYm8gaW7DuiB0cmFuc2Zvcm3DoWNpdS4KYGBge3J9CnJlc2V0dGVzdChtb2RlbF9wSF9wb2x5KQpgYGAKVsO9c2xlZG9rOgoKLSAqKlJFU0VUID0gMi4wNDU3KioKLSAqKnAtaG9kbm90YSA9IDAuMTMyMioqCgpLZcSPxb5lIHAtaG9kbm90YSBqZToKCi0gKip2ecWhxaFpYSBha28gMC4wNSoqLCAgCi0gYSB2w71yYXpuZSB2ecWhxaFpYSBuZcW+IHYgcMO0dm9kbm9tIGxpbmXDoXJub20gbW9kZWxpLAoKem5hbWVuw6EgdG8sIMW+ZSBwbyBwcmlkYW7DrSBrdmFkcmF0aWNrw71jaCDEjWxlbm92IHNhIHBhcmFtZXRyZSBtb2RlbHUgbGVwxaFpZSBwcmlzcMO0c29iaWxpIGTDoXRhbSBhIG1vZGVsICoqdcW+IG5lcHJlamF2dWplIMWhdGF0aXN0aWNreSB2w716bmFtbsO6IGNoeWJ1IMWhcGVjaWZpa8OhY2llKiouCgojIyMjIFrDoXZlciBSRVNFVCB0ZXN0dToKCioqTmVtw6FtZSBkw7R2b2Qgb2RtaWV0bnXFpSBudWxvdsO6IGh5cG90w6l6dSoqLCDFvmUgbW9kZWwgamUgc3Byw6F2bmUgxaFwZWNpZmlrb3ZhbsO9LiAgCkt2YWRyYXRpY2vDvSBtb2RlbCB0ZWRhIHByZcWhaWVsIFJFU0VUIHRlc3RvbSDDunNwZcWhbmUgKHAg4omIIDAuMTMpLiAgCk5hcHJpZWsgdG9tdSB2xaFhayBBTk9WQSB1a8OhemFsYSwgxb5lIGt2YWRyYXRpY2vDqSDEjWxlbnkgbmVwcmluw6HFoWFqw7ogemxlcMWhZW5pZSB2IHByZWRpa2NpaS4KClByZXRvOgo+IEt2YWRyYXRpY2vDvSBtb2RlbCBzw61jZSB2eWthenVqZSBsZXDFoWl1IMWhcGVjaWZpa8OhY2l1IHBvZMS+YSBSRVNFVCB0ZXN0dSwgIAo+IGFsZSBqZWhvIHByZWRpa3TDrXZuYSBzaWxhIHNhIG5lemxlcMWhaWxhIOKAkyBwcmV0byAqKm5lbcOhIHpteXNlbCBobyBwb3XFvsOtdmHFpSoqIG5hbWllc3RvIGplZG5vZHVjaMWhaWVobyBsaW5lw6FybmVobyBtb2RlbHUuCgojIyA1LiBEdW1teSBwcmVtZW5uw6EgYSB6bG9tIHYgc2tsb25lIOKAkyBhbmFsw7NnIHMgQk1JIGEgRFVNCmBgYHtyfQojIER1bW15IHByZW1lbm7DoTogdnlzb2vDoSB2b2Rpdm9zxaUKZGF0YSREVU1fY29uZCA8LSBpZmVsc2UoZGF0YSRDb25kdWN0aXZpdHkuLi7CtW1oby5jbS4uLi5NYXggPiAxMDAwLCAxLCAwKQpgYGAKIyMjIDUuMS4gWmxvbSB2IGF1dG9uw7Ntbm9tIMSNbGVuZSAocG9zdW4gbmFkcm92aW55KQpLb2VmaWNpZW50IHByaSBEVU1fY29uZCBob3ZvcsOtLCDEjWkgbWFqw7ogbG9rYWxpdHkgcyB2eXNva291IHZvZGl2b3PFpW91IGluw7ogcHJpZW1lcm7DuiDDunJvdmXFiCBwSCAodmVydGlrw6FsbnkgcG9zdW4pLgpgYGB7cn0KbW9kZWxEX2F1dG8gPC0gbG0oCiAgcEguLi5NYXggfiBEVU1fY29uZCArCiAgICBUZW1wZXJhdHVyZS4uQy4uLi5NYXggKwogICAgRGlzc29sdmVkLi4uTWF4ICsKICAgIENvbmR1Y3Rpdml0eS4uLsK1bWhvLmNtLi4uLk1heCArCiAgICBCT0QuLm1nLkwuLi4uTWF4ICsKICAgIE5pdHJhdGVOLi5tZy5MLi4uLk1heCwKICBkYXRhID0gZGF0YQopCgpzdW1tYXJ5KG1vZGVsRF9hdXRvKQpgYGAKRG8gbW9kZWx1IHNtZSB6YXJhZGlsaSAqKmR1bW15IHByZW1lbm7DuiBgRFVNX2NvbmRgKiosIGt0b3LDoSByb3psacWhdWplIGxva2FsaXR5OgoKLSBgRFVNX2NvbmQgPSAwYCDigJMgbG9rYWxpdHkgcyAqKm5pxb7FoW91IHZvZGl2b3PFpW91KiosCi0gYERVTV9jb25kID0gMWAg4oCTIGxva2FsaXR5IHMgKip2eXNva291IHZvZGl2b3PFpW91KiouCgpPZGhhZG51dMO9IG1vZGVsIG3DoSB0dmFyOgoKXFsKXHRleHR7cEguLi5NYXh9ID0gXGJldGFfMCArIFxiZXRhXzEgRFVNXF9jb25kICsKXGJldGFfMiBcdGV4dHtUZW1wZXJhdHVyZS4uQy4uLi5NYXh9ICsKXGJldGFfMyBcdGV4dHtEaXNzb2x2ZWQuLi5NYXh9ICsKXGJldGFfNCBcdGV4dHtDb25kdWN0aXZpdHkuLi7CtW1oby5jbS4uLi5NYXh9ICsKXGJldGFfNSBcdGV4dHtCT0QuLm1nLkwuLi4uTWF4fSArClxiZXRhXzYgXHRleHR7Tml0cmF0ZU4uLm1nLkwuLi4uTWF4fSArIHUuClxdCgotLS0KCiMjIyMgVsO9em5hbSBqZWRub3RsaXbDvWNoIGtvZWZpY2llbnRvdgoKLSAqKihJbnRlcmNlcHQpID0gNy43NjgqKiwgcCA8IDJlLTE2ICAKICBPZGhhZG92YW7DoSBwcmllbWVybsOhIGhvZG5vdGEgcEggdiByZWZlcmVuxI1uZWogc2t1cGluZSAobmnFvsWhaWEgdm9kaXZvc8WlLCBgRFVNX2NvbmQgPSAwYCksIHByaSBwcmllbWVybsO9Y2ggaG9kbm90w6FjaCBvc3RhdG7DvWNoIHByZW1lbm7DvWNoLgoKLSAqKmBEVU1fY29uZGAgPSAwLjI2OCoqLCBwID0gMC4wMDMyOCAqKijFoXRhdGlzdGlja3kgdsO9em5hbW7DqSkqKiAgCiAgTG9rYWxpdHkgcyAqKnZ5c29rb3Ugdm9kaXZvc8Wlb3UqKiAoYERVTV9jb25kID0gMWApIG1hasO6IHYgcHJpZW1lcmUgKipvIHByaWJsacW+bmUgMC4yNyBqZWRub3RreSB2ecWhxaFpZSBwSCoqIGFrbyBsb2thbGl0eSBzIG7DrXprb3Ugdm9kaXZvc8Wlb3UsIHphIGluYWsgcm92bmFrw71jaCBwb2RtaWVub2suICAKICDihpIgUG90dnJkenVqZSBzYSAqKnZlcnRpa8OhbG55IHBvc3VuIHJlZ3Jlc25laiBuYWRyb3ZpbnkqKiBwb2TEvmEgw7pyb3ZuZSB2b2Rpdm9zdGkuCgotICoqYFRlbXBlcmF0dXJlLi5DLi4uLk1heGAgPSDiiJIwLjAxMjEqKiwgcCA9IDAuMDEyMjIgIAogIFByaSB6dsO9xaFlbsOtIG1heGltw6FsbmVqIHRlcGxvdHkgbyAxIMKwQyAqKmtsZXNuZSBwSCB2IHByaWVtZXJlIG8gMC4wMTIqKiwgcHJpIG5lem1lbmVuw71jaCBvc3RhdG7DvWNoIHByZW1lbm7DvWNoLgoKLSAqKmBEaXNzb2x2ZWQuLi5NYXhgID0gMC4wNTA5KiosIHAgPSAwLjAwOTQzICAKICBWecWhxaHDrSBvYnNhaCByb3pwdXN0ZW7DqWhvIGt5c2zDrWthIGplIHNwb2plbsO9IHMgKiptaWVybmUgdnnFocWhw61tIHBIKiog4oCTIHByaSBuw6FyYXN0ZSBvIDEgbWcvbCBzdMO6cG5lIHBIIHByaWJsacW+bmUgbyAwLjA1MS4KCi0gKipgQ29uZHVjdGl2aXR5Li4uwrVtaG8uY20uLi4uTWF4YCoqIOKAkyBrb2VmaWNpZW50IGplIG1hbMO9IGEgKipuZXbDvXpuYW1uw70qKiAocCDiiYggMC42NykgIAogIOKGkiBwbyB6b2jEvmFkbmVuw60gZHVtbXkgcHJlbWVubmVqIGBEVU1fY29uZGAgdcW+IHNhbW90bsOhIGxpbmXDoXJuYSB6bWVuYSB2b2Rpdm9zdGkgbmVtw6EgbmEgcEggxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70gdnBseXYuCgotICoqYEJPRC4ubWcuTC4uLi5NYXhgKiog4oCTIGtvZWZpY2llbnQgamUgbmV2w716bmFtbsO9IChwIOKJiCAwLjU2KSAgCiAg4oaSIEJPRCBzYSB2IHRvbXRvIG1vZGVsaSBuZXVrYXp1amUgYWtvIGTDtGxlxb5pdMO9IGRldGVybWluYW50IHBILgoKLSAqKmBOaXRyYXRlTi4ubWcuTC4uLi5NYXhgID0gMC4wMzAzKiosIHAgPSAwLjAwODk4ICAKICBWecWhxaHDrSBvYnNhaCBkdXNpxI1uYW5vdiBqZSBzcG9qZW7DvSBzICoqcmFzdG9tIHBIKiosIHByaSBuw6FyYXN0ZSBvIDEgbWcvbCB2enJhc3RpZSBwSCBhc2kgbyAwLjAzLgoKLS0tCgojIyMjIEt2YWxpdGEgbW9kZWx1CgotICoqUmVzaWR1YWwgc3RhbmRhcmQgZXJyb3IgPSAwLjQxMzEqKiAgCiAgVHlwaWNrw6Egb2RjaMO9bGthIHBvem9yb3ZhbsOpaG8gcEggb2QgaG9kbm90eSBwcmVkaWtvdmFuZWogbW9kZWxvbSBqZSBwcmlibGnFvm5lIDAuNDEgcEggamVkbm90a3kuCgotICoqUsKyID0gMC4yMTk0LCB1cHJhdmVuw6kgUsKyID0gMC4xOTQ0KiogIAogIE1vZGVsIHZ5c3ZldMS+dWplIHByaWJsacW+bmUgKioxOeKAkzIyICUgdmFyaWFiaWxpdHkgcEgqKiwgxI1vIGplIG1pZXJuZSB2aWFjIG5lxb4gesOha2xhZG7DvSBtb2RlbCBiZXogZHVtbXkgcHJlbWVubmVqLgoKLSAqKkYtc3RhdGlzdGljID0gOC43NjIsIHAtdmFsdWUgPSAyLjA0ZS0wOCoqICAKICBBa28gY2Vsb2sgamUgbW9kZWwgKirFoXRhdGlzdGlja3kgdsO9em5hbW7DvSoqIOKAkyBhc3BvxYggamVkbmEgeiBwcmVtZW5uw71jaCB2w716bmFtbmUgb3ZwbHl2xYh1amUgcEguCgotLS0KCiMjIyMgWsOhdmVyCgpaYXZlZGVuaWUgZHVtbXkgcHJlbWVubmVqIGBEVU1fY29uZGAgdWthenVqZSwgxb5lOgoKLSBsb2thbGl0eSBzICoqdnlzb2tvdSB2b2Rpdm9zxaVvdSoqIG1hasO6ICoqc3lzdGVtYXRpY2t5IHZ5xaHFoWllIHBIKiogKG8gcHJpYmxpxb5uZSAwLjI3KSwgIAotIG1vZGVsIHNhIG1pZXJuZSB6bGVwxaFpbCAodnnFocWhaWUgdXByYXZlbsOpIFwoUl4yXCkpLCAgCi0gaGxhdm7DvW1pIHbDvXpuYW1uw71taSBmYWt0b3JtaSBzw7ogKip0ZXBsb3RhLCByb3pwdXN0ZW7DvSBreXNsw61rLCBkdXNpxI1uYW55KiogYSBzYW1vdG7DvSAqKnBvc3VuIHBvZMS+YSBgRFVNX2NvbmRgKiouCgpNb2RlbCBzbyB6bG9tb20gdiBhdXRvbsOzbW5vbSDEjWxlbmUgdGVkYSBuYXpuYcSNdWplLCDFvmUgKirDunJvdmXFiCB2b2Rpdm9zdGkgb3ZwbHl2xYh1amUgcHJpZW1lcm7DuiDDunJvdmXFiCBwSCoqIHByb3N0cmVkbsOtY3R2b20gdmVydGlrw6FsbmVobyBwb3N1bnUsIGFqIGtlxI8gbGluZcOhcm55IGVmZWt0IHNhbW90bmVqIHZvZGl2b3N0aSB6b3N0w6F2YSBuZXbDvXpuYW1uw70uCgojIyMgNS4yLiBabG9tIHYgc2tsb25lIChpbnRlcmFrY2lhIERVTSAqIENvbmR1Y3Rpdml0eSkKYGBge3J9Cm1vZGVsRF9zbG9wZSA8LSBsbSgKICBwSC4uLk1heCB+CiAgICBUZW1wZXJhdHVyZS4uQy4uLi5NYXggKwogICAgRGlzc29sdmVkLi4uTWF4ICsKICAgIENvbmR1Y3Rpdml0eS4uLsK1bWhvLmNtLi4uLk1heCArCiAgICBJKERVTV9jb25kICogQ29uZHVjdGl2aXR5Li4uwrVtaG8uY20uLi4uTWF4KSArCiAgICBCT0QuLm1nLkwuLi4uTWF4ICsKICAgIE5pdHJhdGVOLi5tZy5MLi4uLk1heCwKICBkYXRhID0gZGF0YQopCgpzdW1tYXJ5KG1vZGVsRF9zbG9wZSkKYGBgClYgdG9tdG8gbW9kZWxpIHBvdm/EvnVqZW1lLCBhYnkgc2EgKipza2xvbiB2esWlYWh1IG1lZHppIHZvZGl2b3PFpW91IGEgcEggbMOtxaFpbCoqIHBvZMS+YSB0b2hvLCAgCsSNaSBtw6EgbG9rYWxpdGEgbsOtemt1IGFsZWJvIHZ5c29rw7ogdm9kaXZvc8WlLiBUbyB6YWJlenBlxI11amUgaW50ZXJha8SNbsO9IMSNbGVuICAKYEkoRFVNX2NvbmQgKiBDb25kdWN0aXZpdHkuLi7CtW1oby5jbS4uLi5NYXgpYC4KCk1vZGVsIG3DoSB0dmFyOgoKXFsKXHRleHR7cEguLi5NYXh9ID0KXGJldGFfMCArClxiZXRhXzEgXHRleHR7VGVtcGVyYXR1cmV9ICsKXGJldGFfMiBcdGV4dHtEaXNzb2x2ZWR9ICsKXGJldGFfMyBcdGV4dHtDb25kdWN0aXZpdHl9ICsKXGJldGFfNCAoRFVNXF9jb25kIFx0aW1lcyBcdGV4dHtDb25kdWN0aXZpdHl9KSArClxiZXRhXzUgXHRleHR7Qk9EfSArClxiZXRhXzYgXHRleHR7Tml0cmF0ZU59ICsgdS4KXF0KCi0gUHJlICoqbG9rYWxpdHkgcyBuacW+xaFvdSB2b2Rpdm9zxaVvdSoqIChgRFVNX2NvbmQgPSAwYCkgamUgc2tsb24gcG9kxL5hIHZvZGl2b3N0aSByb3Zuw70gXChcYmV0YV8zXCkuCi0gUHJlICoqbG9rYWxpdHkgcyB2eXNva291IHZvZGl2b3PFpW91KiogKGBEVU1fY29uZCA9IDFgKSBqZSBza2xvbiBwb2TEvmEgdm9kaXZvc3RpIHJvdm7DvSBcKFxiZXRhXzMgKyBcYmV0YV80XCkuCgotLS0KCiMjIyMgSGxhdm7DqSB2w71zbGVka3kKCi0gKipJbnRlcmFrY2lhIGBJKERVTV9jb25kICogQ29uZHVjdGl2aXR5Li4uKWAqKiAgCiAgLSBvZGhhZDog4oiSMi45MGXiiJIwNSAgCiAgLSBwLWhvZG5vdGEgPSAwLjgxNDc2ICAKICDihpIgaW50ZXJha8SNbsO9IGVmZWt0ICoqbmllIGplIMWhdGF0aXN0aWNreSB2w716bmFtbsO9KiouICAKICBOZW3DoW1lIGTDtGtheiwgxb5lIGJ5IHNhICoqc2tsb24gdnrFpWFodSB2b2Rpdm9zdGkgYSBwSCBsw63FoWlsKiogbWVkemkgc2t1cGluYW1pIHMgbsOtemtvdSBhIHZ5c29rb3Ugdm9kaXZvc8Wlb3UuCgotICoqYENvbmR1Y3Rpdml0eS4uLsK1bWhvLmNtLi4uLk1heGAqKiAgCiAgLSBwLWhvZG5vdGEgPSAwLjc4MjU1ICAKICDihpIgc2Ftb3Ruw70gbGluZcOhcm55IGVmZWt0IHZvZGl2b3N0aSBqZSB2IHByw610b21ub3N0aSBpbnRlcmFrY2llIHRha3RpZcW+ICoqbmV2w716bmFtbsO9KiouCgotIE9zdGF0bsOpIHByZW1lbm7DqSBzYSBzcHLDoXZhasO6IHBvZG9ibmUgYWtvIHYgcHJlZGNow6FkemFqw7pjaWNoIG1vZGVsb2NoOgogIC0gKipUZW1wZXJhdHVyZS4uQy4uLi5NYXgqKiDigJMgbmVnYXTDrXZueSwgdsO9em5hbW7DvSB2cGx5diAodnnFocWhaWEgdGVwbG90YSDihpIgbmnFvsWhaWUgcEgpLCAgCiAgLSAqKkRpc3NvbHZlZC4uLk1heCoqIOKAkyBwb3ppdMOtdm55LCB2w716bmFtbsO9IHZwbHl2LCAgCiAgLSAqKk5pdHJhdGVOLi5tZy5MLi4uLk1heCoqIOKAkyBwb3ppdMOtdm55LCB2w716bmFtbsO9IHZwbHl2LCAgCiAgLSAqKkJPRC4ubWcuTC4uLi5NYXgqKiDigJMgbmV2w716bmFtbsO9LgoKLS0tCgojIyMjIEt2YWxpdGEgbW9kZWx1CgotICoqUmVzaWR1YWwgc3RhbmRhcmQgZXJyb3IgPSAwLjQyMjgqKiwgIAotICoqUsKyID0gMC4xODI2LCB1cHJhdmVuw6kgUsKyID0gMC4xNTY0KiosICAKLSAqKkYtc3RhdGlzdGljID0gNi45NjQsIHAtdmFsdWUgPSAxLjA3ZS0wNioqLgoKTW9kZWwgamUgYWtvIGNlbG9rIHPDrWNlIMWhdGF0aXN0aWNreSB2w716bmFtbsO9LCBhbGUgKip2eXN2ZXRsZW7DoSB2YXJpYWJpbGl0YSBwSCBqZSBwb2RvYm7DoSoqIGFrbyB2IHrDoWtsYWRub20gbGluZcOhcm5vbSBtb2RlbGkgYmV6IGludGVyYWtjaWUuCgotLS0KCiMjIyMgWsOhdmVyCgpJbnRlcmFrY2lhIGBEVU1fY29uZCAqIENvbmR1Y3Rpdml0eWA6CgotICoqbmllIGplIMWhdGF0aXN0aWNreSB2w716bmFtbsOhKiosICAKLSBuZXpsZXDFoXVqZSB2eXN2ZXTEvm92YWNpdSBzY2hvcG5vc8WlIG1vZGVsdSAoUsKyIHpvc3TDoXZhIHByYWt0aWNreSByb3ZuYWvDqSksICAKLSBuZW5hem5hxI11amUgZXhpc3RlbmNpdSAqKnpsb211IHYgc2tsb25lKiogcmVncmVzbmVqIG5hZHJvdmlueSBwb2TEvmEgw7pyb3ZuZSB2b2Rpdm9zdGkuCgpQcmV0byAqKm5lbcOhbWUgZMO0dm9kIHBvdcW+w612YcWlIHpsb8W+aXRlasWhw60gbW9kZWwgc28gemxvbW9tIHYgc2tsb25lKio7IG5hIG9waXMgdnrFpWFodSBtZWR6aSBwSCBhIHZvZGl2b3PFpW91IHBvc3RhxI11amUgamVkbm9kdWNoxaHDrSBsaW5lw6FybnkgbW9kZWwgYmV6IGludGVyYWtjaWUuCgojIyMgNS4zLiBQb3Jvdm5hbmllIG1vZGVsdSBzbyB6bG9tb20gdiBza2xvbmUgcyBsaW5lw6FybnltIG1vZGVsb20KYGBge3J9CiMgUG9yb3ZuYW5pZSBzbyB6w6FrbGFkbsO9bSBtb2RlbG9tCmFub3ZhKG1vZGVsX3BILCBtb2RlbERfc2xvcGUpCgojIFJFU0VUIHRlc3QgcHJlIG1vZGVsIHNvIHpsb21vbSB2IHNrbG9uZQpyZXNldHRlc3QobW9kZWxEX3Nsb3BlKQpgYGAKCk5hanBydiBwb3Jvdm7DoXZhbWUgesOha2xhZG7DvSBsaW5lw6FybnkgbW9kZWwgYG1vZGVsX3BIYCBhIG1vZGVsIHNvIHpsb21vbSB2IHNrbG9uZSAgCihpbnRlcmFrY2lhIGBEVU1fY29uZCAqIENvbmR1Y3Rpdml0eWApIHBvbW9jb3UgQU5PVkEgdGVzdHUuCgojIyMjIEFOT1ZBIHBvcm92bmFuaWUgbW9kZWxvdgoKVsO9c2xlZGt5OgoKLSAqKlJTUyB6w6FrbGFkbsOpaG8gbW9kZWx1OioqIDMzLjQzMiAgCi0gKipSU1MgbW9kZWx1IHNvIHpsb21vbSB2IHNrbG9uZToqKiAzMy40MjIgIAoKUm96ZGllbCBSU1MgamUgaWJhICoqMC4wMDk4KiosIMSNbyBqZSB6YW5lZGJhdGXEvm7DqS4KCi0gKipGID0gMC4wNTUqKiwgIAotICoqcC1ob2Rub3RhID0gMC44MTQ4KioKCktlxI/FvmUgcC1ob2Rub3RhID4gMC4wNSwgKipuZW3DoW1lIGTDtGtheioqLCDFvmUgbW9kZWwgc28gemxvbW9tIHYgc2tsb25lIHBvc2t5dHVqZSBsZXDFoWllIHZ5c3ZldGxlbmllIHZhcmlhYmlsaXR5IHBIIG5lxb4gcMO0dm9kbsO9IGxpbmXDoXJueSBtb2RlbC4KCiMjIyMgWsOhdmVyIEFOT1ZBOgoKSW50ZXJha2NpYSBgRFVNX2NvbmQgKiBDb25kdWN0aXZpdHlgICoqbmV6bGVwxaF1amUgbW9kZWwqKi4gIApOZWV4aXN0dWplIHbDvXpuYW1uw70gcm96ZGllbCBtZWR6aSBtb2RlbG1pLiAgCuKGkiAqKkxpbmXDoXJueSBtb2RlbCB6b3N0w6F2YSB2aG9kbmVqxaFvdSBhIGplZG5vZHVjaMWhb3Ugdm/EvmJvdS4qKgoKLS0tCgojIyMgUkVTRVQgdGVzdCBwcmUgbW9kZWwgc28gemxvbW9tIHYgc2tsb25lCgpSRVNFVCB0ZXN0IGhvZG5vdMOtLCDEjWkgamUgbW9kZWwgc3Byw6F2bmUgxaFwZWNpZmlrb3ZhbsO9LgoKVsO9c2xlZG9rOgoKLSAqKlJFU0VUID0gMS42NDAyKioKLSAqKnAtaG9kbm90YSA9IDAuMTk2NyoqCgpLZcSPxb5lIHAtaG9kbm90YSA+IDAuMDUsICoqbmVvZG1pZXRhbWUgaHlwb3TDqXp1IHNwcsOhdm5laiDFoXBlY2lmaWvDoWNpZSoqLgoKIyMjIyBaw6F2ZXIgUkVTRVQ6CgpNb2RlbCBzbyB6bG9tb20gdiBza2xvbmUgKipuaWUgamUgemxlIMWhcGVjaWZpa292YW7DvSoqLiAgCkF2xaFhayBwb2TEvmEgQU5PVkEgbmVwcmluw6HFoWEgxb5pYWRuZSB6bGVwxaFlbmllIG9wcm90aSB6w6FrbGFkbsOpbXUgbW9kZWx1LgoKLS0tCgojIyMgQ2Vsa292w6kgemhybnV0aWUKCi0gQWoga2XEjyBtb2RlbCBzbyB6bG9tb20gdiBza2xvbmUgbmVwb3J1xaF1amUgcHJlZHBva2xhZHkgKFJFU0VUIE9LKSwgIAogICoqbmVwcmluw6HFoWEgxb5pYWRuZSB6bGVwxaFlbmllIHZ5c3ZldGxlbmVqIHZhcmlhYmlsaXR5IHBIKiogKEFOT1ZBIHAgPSAwLjgxNDgpLgotIEludGVyYWtjaWEgdm9kaXZvc3RpIHMgZHVtbXkgcHJlbWVubm91IGBEVU1fY29uZGAgKipuaWUgamUgdsO9em5hbW7DoSoqLgotIE5hamxlcMWhb3Ugdm/EvmJvdSB6b3N0w6F2YSAqKnrDoWtsYWRuw70gbGluZcOhcm55IG1vZGVsIGJleiBpbnRlcmFrY2llKiouCgo+IE1vZGVsIHNvIHpsb21vbSB2IHNrbG9uZSBqZSBzw61jZSBha2NlcHRvdmF0ZcS+bsO9LCBhbGUgxaF0YXRpc3RpY2t5IHpieXRvxI1uw70uCgojIyA2LiBCb3gtQ294IHRlc3QgcHJlIHRyYW5zZm9ybcOhY2l1IHrDoXZpc2xlaiBwcmVtZW5uZWogcEguLi5NYXgKTmFrb25pZWMgYW5hbMOzZyBCb3gtQ294IHRlc3R1OgpgYGB7cn0KYm94Y294KG1vZGVsX3BIKQpgYGAKTmEgZ3JhZmUgc8O6IHpvYnJhemVuw6kgaG9kbm90eSAqKmxvZy1saWtlbGlob29kKiogcHJlIHLDtHpuZSBob2Rub3R5IHBhcmFtZXRyYSBcKFxsYW1iZGFcKS4gIApNYXhpbXVtIGtyaXZreSAoYSB0ZWRhIGFqIOKAnm5hamxlcMWhaWHigJwgdHJhbnNmb3Jtw6FjaWEgcG9kxL5hIEJveOKAk0NveCkgc2EgbmFjaMOhZHphIHByaWJsacW+bmUgcHJpCgpcWwpcaGF0XGxhbWJkYSBcYXBwcm94IC0xLgpcXQoKWsOhcm92ZcWIIDk1ICUgaW50ZXJ2YWwgc3BvxL5haGxpdm9zdGkgKHZ5em5hxI1lbsO9IHZvZG9yb3Zub3UgYm9ka292YW5vdSDEjWlhcm91KSAqKm5lemFoxZXFiGEgaG9kbm90eSoqClwoXGxhbWJkYSA9IDFcKSBhbmkgXChcbGFtYmRhID0gMFwpLiBUbyB6bmFtZW7DoToKCi0gXChcbGFtYmRhID0gMVwpOiAqKmJleiB0cmFuc2Zvcm3DoWNpZSBwSCoqIOKAkyBuaWUgamUgb3B0aW3DoWxuZSBwb2TEvmEgQm944oCTQ294OyAgCi0gXChcbGFtYmRhID0gMFwpOiAqKmxvZ2FyaXRtaWNrw6EgdHJhbnNmb3Jtw6FjaWEqKiBcKFxsb2coXHRleHR7cEguLi5NYXh9KVwpIOKAkyB0aWXFviBuaWUgamUgdiBvYmxhc3RpCiAgbmFqdnnFocWhZWogdmllcm9ob2Rub3N0aTsgIAotIFwoXGxhbWJkYSBcYXBwcm94IC0xXCk6IG9kcG9yw7rEjWFuw6EgamUgKipyZWNpcHJvxI1uw6EgdHJhbnNmb3Jtw6FjaWEgdHlwdSoqIFwoMS9cdGV4dHtwSC4uLk1heH1cKQogIChwcmVzbmVqxaFpZSB0cmFuc2Zvcm3DoWNpYSBcKChcdGV4dHtwSC4uLk1heH1eXGxhbWJkYSAtIDEpL1xsYW1iZGFcKSBzIFwoXGxhbWJkYSBcYXBwcm94IC0xXCkpLgoKSW7DvW1pIHNsb3ZhbWksIEJveOKAk0NveCB0ZXN0IG5hem5hxI11amUsIMW+ZSBwcmUgbGVwxaFpZSBzcGxuZW5pZSBwcmVkcG9rbGFkb3YgbGluZcOhcm5laiByZWdyZXNpZSBieSBib2xvIHZob2Ruw6kKdHJhbnNmb3Jtb3ZhxaUgdnlzdmV0xL5vdmFuw7ogcHJlbWVubsO6IHByaWJsacW+bmUgYWtvCgpcWwpZXnsoXGxhbWJkYSl9ID0gXGZyYWN7XHRleHR7cEguLi5NYXh9XntcLFxsYW1iZGF9IC0gMX17XGxhbWJkYX0sIFxxdWFkIFxsYW1iZGEgXGFwcHJveCAtMSwKXF0KCnQuIGouIHByYWNvdmHFpSBza8O0ciBzICoqaW52ZXJ6bm91IGhvZG5vdG91IHBIKiosIG5lxb4gcyBww7R2b2Ruw71tIHBIIGFsZWJvIHMgbG9nKHBIKS4KClRha3RvIHRyYW5zZm9ybW92YW7DoSBwcmVtZW5uw6Egc2EgcG90b20gcG91xb5pamUgYWtvIHrDoXZpc2zDoSBwcmVtZW5uw6EgdiBtb2RlbGk6CmBgYHtyfQpsYW1iZGEgPC0gLTEgICAjIG9kcG9yw7rEjWFuw6EgaG9kbm90YSB6IEJveOKAk0NveCBncmFmdQoKIyB0cmFuc2Zvcm3DoWNpYSBwSCBwb2TEvmEgQm944oCTQ294IHZ6b3JjYQppZiAobGFtYmRhID09IDApIHsKICBwSF90ciA8LSBsb2coZGF0YSRgcEguLi5NYXhgKQp9IGVsc2UgewogIHBIX3RyIDwtIChkYXRhJGBwSC4uLk1heGBebGFtYmRhIC0gMSkgLyBsYW1iZGEKfQoKIyBtb2RlbCBzIHRyYW5zZm9ybW92YW5vdSBwcmVtZW5ub3UKbW9kZWxfYm94Y294IDwtIGxtKAogIHBIX3RyIH4gVGVtcGVyYXR1cmUuLkMuLi4uTWF4ICsKICAgIERpc3NvbHZlZC4uLk1heCArCiAgICBDb25kdWN0aXZpdHkuLi7CtW1oby5jbS4uLi5NYXggKwogICAgQk9ELi5tZy5MLi4uLk1heCArCiAgICBOaXRyYXRlTi4ubWcuTC4uLi5NYXgsCiAgZGF0YSA9IGRhdGEKKQoKc3VtbWFyeShtb2RlbF9ib3hjb3gpCgojIFJFU0VUIHRlc3Qgc3Byw6F2bmVqIMWhcGVjaWZpa8OhY2llCnJlc2V0dGVzdChtb2RlbF9ib3hjb3gpCmBgYApOYSB6w6FrbGFkZSBCb3jigJNDb3ggdGVzdHUgc21lIHp2b2xpbGkgcGFyYW1ldGVyIFwoXGxhbWJkYSA9IC0xXCkgYSBwSCB0cmFuc2Zvcm1vdmFsaSBwb2TEvmEgdnpvcmNhCgpcWwpwSF57KC0xKX0gPSBcZnJhY3tcdGV4dHtwSC4uLk1heH1eey0xfSAtIDF9ey0xfS4KXF0KClRyYW5zZm9ybW92YW7DoSBwcmVtZW5uw6EgYHBIX3RyYCBzYSBwb3XFvmlsYSBha28gesOhdmlzbMOhIHByZW1lbm7DoSB2IG1vZGVsaToKClxbCnBIXF90ciA9IFxiZXRhXzAgKyBcYmV0YV8xIFx0ZXh0e1RlbXBlcmF0dXJlfSArCiAgICAgICAgIFxiZXRhXzIgXHRleHR7RGlzc29sdmVkfSArCiAgICAgICAgIFxiZXRhXzMgXHRleHR7Q29uZHVjdGl2aXR5fSArCiAgICAgICAgIFxiZXRhXzQgXHRleHR7Qk9EfSArCiAgICAgICAgIFxiZXRhXzUgXHRleHR7Tml0cmF0ZU59ICsgdS4KXF0KCiMjIyMgVsO9c2xlZGt5IHJlZ3Jlc2llCgotICoqSW50ZXJjZXB0ID0gMC44NzEyKiosIHAgPCAyZS0xNiAgCiAg4oaSIHByaSBwcmllbWVybsO9Y2ggaG9kbm90w6FjaCB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoIG3DoSB0cmFuc2Zvcm1vdmFuw6kgcEggaG9kbm90dSBva29sbyAwLjg3LgoKLSAqKlRlbXBlcmF0dXJlLi5DLi4uLk1heCA9IOKIkjIuMTJl4oiSMDQqKiwgcCA9IDAuMDAzMzggIAogIOKGkiB2ecWhxaFpYSB0ZXBsb3RhIHZlZGllIGsgKip6bsOtxb5lbml1IHRyYW5zZm9ybW92YW7DqWhvIHBIKiosIMSNbyB6b2Rwb3ZlZMOhIHBva2xlc3UgcMO0dm9kbsOpaG8gcEguCgotICoqRGlzc29sdmVkLi4uTWF4ID0gOC44MGXiiJIwNCoqLCBwID0gMC4wMDI3MiAgCiAg4oaSIHZ5xaHFocOtIG9ic2FoIHJvenB1c3RlbsOpaG8ga3lzbMOta2EgamUgc3BvamVuw70gcyAqKnZ5xaHFocOtbSB0cmFuc2Zvcm1vdmFuw71tIHBIKiosIHRlZGEgYWogcyB2ecWhxaHDrW0gcMO0dm9kbsO9bSBwSC4KCi0gKipDb25kdWN0aXZpdHkuLi7CtW1oby5jbS4uLi5NYXggPSA4LjgyZeKIkjA4KiosIHAgPSA4LjU2ZeKIkjA1ICAKICDihpIgdm9kaXZvc8WlIG3DoSAqKnBveml0w612bnkgYSDFoXRhdGlzdGlja3kgdmXEvm1pIHbDvXpuYW1uw70gdnBseXYqKiBuYSB0cmFuc2Zvcm1vdmFuw6kgcEg7IHByaSB2ZcS+a8O9Y2ggem1lbsOhY2ggdm9kaXZvc3RpIGlkZSBvIG1pZXJueSwgYWxlIHN5c3RlbWF0aWNrw70gZWZla3QuCgotICoqQk9ELi5tZy5MLi4uLk1heCoqIOKAkyBrb2VmaWNpZW50IGplIG5ldsO9em5hbW7DvSAocCDiiYggMC41NzYpICAKICDihpIgQk9EIHN0w6FsZSBuZXZ5a2F6dWplIMWhdGF0aXN0aWNreSB2w716bmFtbsO9IHZwbHl2IG5hIHBILgoKLSAqKk5pdHJhdGVOLi5tZy5MLi4uLk1heCA9IDUuNDBl4oiSMDQqKiwgcCA9IDAuMDAxNjUgIAogIOKGkiB2ecWhxaHDrSBvYnNhaCBkdXNpxI1uYW5vdiBqZSBzcG9qZW7DvSBzICoqdnnFocWhw61tIHRyYW5zZm9ybW92YW7DvW0gcEgqKiwgdGVkYSBhaiBzIHZ5xaHFocOtbSBww7R2b2Ruw71tIHBILgoKIyMjIyBLdmFsaXRhIG1vZGVsdQoKLSAqKlJlc2lkdWFsIHN0YW5kYXJkIGVycm9yID0gMC4wMDYxNyoqICAKICDihpIgcmV6w61kdcOhIHPDuiB2ZcS+bWkgbWFsw6ksIMSNbyBzw7p2aXPDrSBhaiBzIG1pZXJrb3UgdHJhbnNmb3Jtb3ZhbmVqIHByZW1lbm5lai4KCi0gKipSwrIgPSAwLjIxNzQsIHVwcmF2ZW7DqSBSwrIgPSAwLjE5NjYqKiAgCiAg4oaSIG1vZGVsIHZ5c3ZldMS+dWplIHByaWJsacW+bmUgKioyMOKAkzIyICUgdmFyaWFiaWxpdHkgdHJhbnNmb3Jtb3ZhbsOpaG8gcEgqKiwgxI1vIGplIG1pZXJuZSB2aWFjIG5lxb4gcHJpIHDDtHZvZG5vbSAobmV0cmFuc2Zvcm1vdmFub20pIG1vZGVsaS4KCi0gKipGLXN0YXRpc3RpYyA9IDEwLjQ0LCBwLXZhbHVlIOKJiCA3LjM4ZeKIkjA5KiogIAogIOKGkiBtb2RlbCBqZSBha28gY2Vsb2sgKirFoXRhdGlzdGlja3kgdmXEvm1pIHbDvXpuYW1uw70qKi4KCi0tLQoKIyMjIFJFU0VUIHRlc3QgcHJlIEJveOKAk0NveCBtb2RlbAoKVsO9c2xlZG9rIFJFU0VUIHRlc3R1OgoKLSAqKlJFU0VUID0gMS45MzI4KiosICAKLSAqKnAtaG9kbm90YSA9IDAuMTQ3NioqLgoKS2XEj8W+ZSBwLWhvZG5vdGEgPiAwLjA1LCAqKm5lemFtaWV0YW1lIG51bG92w7ogaHlwb3TDqXp1IG8gc3Byw6F2bmVqIMWhcGVjaWZpa8OhY2lpIG1vZGVsdSoqLgoKIyMjIyBaw6F2ZXIKCi0gQm944oCTQ294IHRyYW5zZm9ybcOhY2lhICjOuyA9IOKIkjEpIG1pZXJuZSAqKnpsZXDFoWlsYSB2eXN2ZXTEvm92YWNpdSBzY2hvcG5vc8WlIG1vZGVsdSoqICAKICBhIHrDoXJvdmXFiCAqKm5lb2RoYWxpbGEgY2h5Ym7DuiDFoXBlY2lmaWvDoWNpdSoqIChSRVNFVCBPSykuCi0gTmEgZHJ1aGVqIHN0cmFuZSBpbnRlcnByZXTDoWNpYSBrb2VmaWNpZW50b3YgamUgdcW+IG1lbmVqIGludHVpdMOtdm5hLCBrZcSPxb5lIHNhIHZ6xaVhaHVqw7ogayB0cmFuc2Zvcm1vdmFuZWogdmVsacSNaW5lIGBwSF90cmAsIG5pZSBrIHDDtHZvZG7DqW11IHBILgoKUHJlIHByYWt0aWNrw6kgesOhdmVyeSBqZSBwcmV0byB2aG9kbsOpOgoKLSBwb3XFvsOtdmHFpSBCb3jigJNDb3ggbW9kZWwgbmFqbcOkIGFrbyAqKmRpYWdub3N0aWNrw7ogLyBkb3BsbmtvdsO6IGtvbnRyb2x1KiosCi0gYWxlIHByaSBzbG92bm9tIHBvcGlzZSB2w71zbGVka292IHZ5c3ZldMS+b3ZhxaUgdnBseXYgcHJlbWVubsO9Y2ggc2vDtHIgdiBrb250ZXh0ZSAqKnDDtHZvZG7DqWhvIHBIKiosIG5pZSB0cmFuc2Zvcm1vdmFuZWogxaFrw6FseS4KCg==