knitr::opts_chunk$set(
    echo = TRUE,
    message = FALSE,
    warning = FALSE)
library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)
rm(list=ls())

Š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.

1. RESET test – test správnej funkčnej formy

Analóg Ramseyho RESET testu:

resettest(model_pH)

    RESET test

data:  model_pH
RESET = 1.6264, df1 = 2, df2 = 186, p-value = 0.1994

Ramseyho RESET test (p = 0.1994) neodhalil chybnú špecifikáciu modelu. Keďže p-hodnota je výrazne vyššia ako 5 %, nezamietame nulovú hypotézu o správnej funkčnej forme. To znamená, že v modeli pravdepodobne nechýbajú žiadne dôležité nelineárne transformácie ani zanedbané premenné a lineárny tvar regresnej funkcie je postačujúci.

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.

car::crPlots(model_pH)

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.

resettest(model_pH_poly)

    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:

boxcox(model_pH)

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, \]

    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==