1. Úvod

Po autokoreácii a heteroskedasticite rezíduí je multikolinearita tretím závažným porušením predpokladov použitia metódy najmenších štvorcov. Tu sa okrem iného predpokadá, že matica \(\mathbf X\) je tvorená lineárne nezávislými riadkami a tiež stĺpcami, čo zabezpečí regularitu matice \(\mathbf X^T\mathbf X\) a teda možnosť jej inverzie. Tá sa používa pri odhadoch regresných koeficientov. V praxi sa ale môže stať, že vzniká "takmer singulárna matica \(\mathbf X^T\mathbf X\) ", t.j. matica \(\mathbf X\) je tvorená "približne" lineárne závislými stĺpcami, t.j. existuje taká ich lineárna kombinácia, v ktorej

\[ x_{il} = \alpha_0 + \alpha_1 x_{i1} + \dots + \alpha_{l-1} x_{i,(l-1)} + \alpha_{l+1} x_{i,(l+1)} + \alpha_k x_{i,k} + \nu_i \]

Tu \(\nu_i\) sú rádovo menšie čísla , než regresory \(x_{.}\), t.j. \((\forall i)(\nu_i << x_{.,i})\). V tomto prípade je inverzná matica \((\mathbf X^T\mathbf X)^{-1}\) veľmi nestabilná a obsahuje na hlavnej diagonále veľmi veľké hodnoty. Táto matica sa používa pri výpočtoch \[\hat \beta = (\mathbf X^T\mathbf X)^{-1} \mathbf X^T \mathbf y\] a tiež \[\text{std}(\beta_i) = \sqrt{\sigma^2 (\mathbf X^T \mathbf X)^{-1}_{ii}}.\] To spôsobuje nestabilitu odhadovaných regresných koeficientov a ich nadhodnotené rozptyly.

Tento problém nazývame problémom multikolinearity.

V kontexte tejto analýzy sa multikolinearita môže vyskytovať medzi vysvetľujúcimi premennými opisujúcimi dopravné nehody, ako sú napríklad čas nehody, deň v týždni, mesiac nehody či počet zúčastnených vozidiel. Cieľom nasledujúcej časti je preto identifikovať prípadnú prítomnosť multikolinearity v regresnom modeli založenom na databáze dopravných nehôd premávka a posúdiť jej vplyv na stabilitu odhadov regresných koeficientov.


2. Dôsledky multikolinearity

Multikolinearita patrí medzi najčastejšie problémy viacnásobnej lineárnej regresie.
Je dôležité jasne rozlišovať dva fakty:

  1. Nespôsobuje skreslené (biased) odhady koeficientov
  2. Nadhodnocuje odhady štandardných odchýlok regresných koeficientov a vedie potom k falošnému neprijímaniu alternatívnej hypotézy o štatistickej významnosti jednotlivých regresorov.
  3. Odhadované regresné koeficienty sú nestabilné - pri malej zmene údajov sa sa prudko menia koeficienty ako aj ich znamienka.
  4. Interpretácia regresného modelu je z dôvodu vyššie uvedených dôvodov nespoľahlivá.

3. Východiskový model a údaje

Budeme pracovať s regresným modelom z predchádzajúcich cvičení, ktorého cieľom je vysvetliť počet zranených pri dopravnej nehode na základe vybraných charakteristík nehody.

Východiskový regresný model má tvar

\[ injuries\_total_i = \beta_0 + \beta_1 num\_units_i + \beta_2 crash\_hour_i + \beta_3 crash\_day\_of\_week_i + \beta_4 crash\_month_i + u_i \]

kde: - \(injuries\_total_i\) predstavuje počet zranených pri i-tej dopravnej nehode, - \(num\_units_i\) je počet zúčastnených vozidiel, - \(crash\_hour_i\) označuje hodinu nehody, - \(crash\_day\_of\_week_i\) je deň v týždni, - \(crash\_month_i\) je mesiac, v ktorom k nehode došlo, - \(u_i\) je náhodná zložka modelu.

Použité údaje pochádzajú z databázy dopravných nehôd (premávka) a po ich načítaní boli uložené do objektu typu data.frame s názvom udaje.


# PRIPRAVA UDAJOV 
udaje <- read.csv("premavka.csv.csv", dec=".", sep=",", header = TRUE)

# výber relevantných premenných 
udaje <- udaje[, c("injuries_total",
                   "num_units",
                   "crash_hour",
                   "crash_month",
                   "crash_day_of_week")]

# imputácia chýbajúcich hodnôt mediánom
column_medians <- sapply(udaje, median, na.rm = TRUE)

udaje_imputed <- udaje
for (col in names(udaje)) {
  udaje_imputed[[col]][is.na(udaje_imputed[[col]])] <- column_medians[col]
}

udaje <- udaje_imputed

4. Odhad základného regresného modelu


model <- lm(injuries_total ~
              num_units +
              crash_hour +
              crash_month +
              crash_day_of_week,
            data = udaje)

summary(model)

Call:
lm(formula = injuries_total ~ num_units + crash_hour + crash_month + 
    crash_day_of_week, data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.9330 -0.3719 -0.3518  0.3171 20.9325 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)       -0.2478411  0.0110628 -22.403  < 2e-16 ***
num_units          0.3233581  0.0043563  74.227  < 2e-16 ***
crash_hour        -0.0024418  0.0003085  -7.916 2.46e-15 ***
crash_month        0.0030261  0.0005033   6.013 1.82e-09 ***
crash_day_of_week -0.0059035  0.0008787  -6.718 1.84e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.7892 on 209301 degrees of freedom
Multiple R-squared:  0.02626,   Adjusted R-squared:  0.02624 
F-statistic:  1411 on 4 and 209301 DF,  p-value: < 2.2e-16

V tomto kroku odhadujeme základný lineárny regresný model, v ktorom je vysvetľovanou premennou celkový počet zranení pri dopravnej nehode. Medzi vysvetľujúce premenné zaraďujeme počet zúčastnených vozidiel, hodinu nehody, mesiac nehody a deň v týždni. Cieľom je posúdiť základné vzťahy medzi charakteristikami nehody a počtom zranení.

Na základe odhadnutého základného lineárneho regresného modelu môžeme konštatovať, že všetky zahrnuté vysvetľujúce premenné sú štatisticky významné na hladine významnosti 1 %. Najsilnejší vplyv na počet zranení má počet zúčastnených vozidiel, pričom s rastúcim počtom vozidiel rastie aj očakávaný počet zranení. Premenné časového charakteru (hodina nehody, deň v týždni a mesiac) majú síce menší, no systematický vplyv na počet zranení. Nízka hodnota koeficientu determinácie naznačuje, že model zachytáva len časť variability počtu zranení, čo je pri dátach o dopravných nehodách očakávané.


5. Korelačná matica

Korelácia dokáže zachytiť párové vzťahy medzi premennými. Ak medzi niektorými vysvetľujúcimi premennými je vysoká korelácia (signalizujúca multikolinearitu), potom je najjednoduchšie ju zo zoznamu regresorov vylúčiť. Korelácie sa dajú aj testovať, alebo len vyčísliť a potom podľa intuitívneho pravidla vylúčiť jednu premennú, ktorá má koreláciu s inou premennou v absolútnej hodnote vyššiu ako 0.8, resp. 0.9.

# korelačná matica

xvars <- udaje[, c("num_units",
                   "crash_hour",
                   "crash_month",
                   "crash_day_of_week")]

round(cor(xvars, use = "pairwise.complete.obs"), 3)
                  num_units crash_hour crash_month crash_day_of_week
num_units             1.000      0.016       0.003             0.003
crash_hour            0.016      1.000       0.003             0.062
crash_month           0.003      0.003       1.000            -0.006
crash_day_of_week     0.003      0.062      -0.006             1.000

Korelačná matica vysvetľujúcich premenných nepreukazuje prítomnosť silnej lineárnej závislosti medzi jednotlivými regresormi. Všetky hodnoty korelačných koeficientov sú nízke a výrazne pod bežne používanými prahmi (0.8–0.9). Na základe toho možno konštatovať, že v tomto modeli sa nevyskytuje problém výraznej multikolinearity a nie je potrebné vylučovať žiadnu z použitých premenných.


Korelačný vzťah sa dá vytušiť aj z jednoduchých párových scatterplotov ako je to na nasledujúcom obrázku.

pairs(
  xvars,
  main = "Scatterplotová matica – vysvetľujúce premenné dopravných nehôd"
)

Scatterplotová matica znázorňuje vzťahy medzi vysvetľujúcimi premennými použitými v regresnom modeli. Z grafov nevyplývajú výrazné lineárne závislosti medzi premennými, čo potvrdzuje nízke hodnoty korelačných koeficientov a naznačuje, že multikolinearita by nemala predstavovať závažný problém.


6. VIF

Indikátorom multikolinearity u premennej, ktorá multikolinearitu zapríčiňuje, je Variance Inflation Factor (VIF). Pre premennú \(x_j\) je potom

\[ VIF_j = \frac{1}{1 - R_j^2} \]

kde \(R_j^2\) pochádza z regresie:

\[ X_j = \gamma_0 + \gamma_1 X_1 + \cdots + \gamma_{j-1} X_{j-1} + \gamma_{j+1} X_{j+1} + u. \]

library(car)
vif(model)
        num_units        crash_hour       crash_month crash_day_of_week 
         1.000257          1.004154          1.000063          1.003945 

Intuitívnym kritériom, ktoré signalizuje prítomnosť multikolinearity, je podmienka VIF > 5 (prísne kritérium), alebo VIF > 10 (menej prísne kritérium). V našom prípade to nespĺňa žiadna z vysvetľujúcich veličín.


7. Condition Number

Pri existencii multikolinearity sa model prejavuje tak, že koeficient determinácie je síce vysoký a zdá sa, že model je veľmi dobrý, ale regresné koeficienty nie sú štatisticky významné - t.j. štandardné odchýlky regresných koeficientov sú veľmi veľké. Uvedomíme si to, ak sa pozrieme, ako sa počítajú - t.j. \(\text{std}(\beta_i) = \sqrt{\sigma^2 (\mathbf X^T \mathbf X)^{-1}_{ii}}\), kde rozhodujúci je \(i\)ty prvok hlavnej diagonály matice \((\mathbf X^T \mathbf X)^{-1}\). Tie prvky sú ale v prípade podobnosti vysvetľujúcich premenných mimoriadne veľké. Túto situáciu zachytáva nasledovný ukazovateľ.

Pri výpočte Condition number \(\kappa\) sa používa vzorec

\[\kappa = \frac{\theta_{\text{max}}}{\theta_{\text{min}}}\]

kde \(\theta_.\) sú vlastné čísla matice (vysvetlené nižšie). Conditional number nie je test, je to len indikátor, ktorý posudzuje mieru multikolinearity medzi premennými. Používame intuitívne pravidlo. Ak Conditional number je

V našom prípade to vypočítame nasledovne

X <- model.matrix(model)[, -1]
XtX <- t(X) %*% X
eig <- eigen(XtX)

condition_number <- sqrt(max(eig$values) / min(eig$values))
condition_number
[1] 25.09621

Keďže hodnota condition number v našom prípade dosahuje približne 25, ide o miernu mieru multikolinearity, ktorá však nepredstavuje závažný problém pre interpretáciu regresného modelu.

Vlastné číslo štvorcovej matice \(\mathbf X^T \mathbf X\) je číslo \(\theta_j\), pre ktoré platí \((\mathbf X^T \mathbf X)\mathbf h^j = \theta_i\mathbf h^j\). \(\mathbf h^j\) je tzv vlastný vektor tejto matice. Máme toľko vlastných čísel (teda aj vlastných vektorov), koľko obsahuje matica \(\mathbf X^T \mathbf X\) riadkov (stĺpcov).

Môže sa stať, že VIF faktor nesignalizuje multikolinearitu u žiadnej z vysvetľujúcich veličín, ale sú navzájom prepojené cyklickými lineárnymi závislosťami všetky premenné. To zachytáva práve Condition Number.


8. Riešenia multikolinearity

Vynechanie premennej

Pokúsme sa vynechať postupne dve premenné, ktoré majú najvyšší VIF a porovnajme následne upravené koeficienty determinácie oboch nových modelov

model_no_units <- lm(injuries_total ~
                       crash_hour +
                       crash_month +
                       crash_day_of_week,
                     data = udaje)

summary(model_no_units)

Call:
lm(formula = injuries_total ~ crash_hour + crash_month + crash_day_of_week, 
    data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-0.4453 -0.3907 -0.3729  0.5841 20.5909 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)        0.4133356  0.0066465  62.189  < 2e-16 ***
crash_hour        -0.0020875  0.0003124  -6.681 2.38e-11 ***
crash_month        0.0031426  0.0005098   6.164 7.12e-10 ***
crash_day_of_week -0.0057875  0.0008902  -6.501 7.98e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.7995 on 209302 degrees of freedom
Multiple R-squared:  0.000625,  Adjusted R-squared:  0.0006107 
F-statistic: 43.63 on 3 and 209302 DF,  p-value: < 2.2e-16
model_no_hour <- lm(injuries_total ~
                      num_units +
                      crash_month +
                      crash_day_of_week,
                    data = udaje)

summary(model_no_hour)

Call:
lm(formula = injuries_total ~ num_units + crash_month + crash_day_of_week, 
    data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.9368 -0.3705 -0.3542  0.3172 20.9499 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)       -0.2774976  0.0104108 -26.655  < 2e-16 ***
num_units          0.3228244  0.0043565  74.102  < 2e-16 ***
crash_month        0.0030113  0.0005033   5.983 2.20e-09 ***
crash_day_of_week -0.0063370  0.0008772  -7.225 5.05e-13 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.7893 on 209302 degrees of freedom
Multiple R-squared:  0.02597,   Adjusted R-squared:  0.02595 
F-statistic:  1860 on 3 and 209302 DF,  p-value: < 2.2e-16

Na overenie stability odhadu a možného vplyvu multikolinearity boli odhadnuté aj alternatívne regresné modely, v ktorých bola vždy vynechaná jedna z vysvetľujúcich premenných. Porovnaním výsledkov jednotlivých modelov možno konštatovať, že základné vzťahy medzi premennými zostávajú zachované, čo naznačuje, že multikolinearita v modeli nepredstavuje významný problém.

Škálovanie premenných

Škálovanie môže byť veľmi efektívne, znižuje ale interpretovateľnosť modelu. Ide o úpravu premenných podľa nasledovného vzorca:

\[x^{scale} = \frac{x-M}{\sqrt{D}}\] kde \(M\) je stredná hodnota (priemer) a \(D\) je rozptyl premennej.

udaje$num_units_c        <- scale(udaje$num_units, center = TRUE, scale = TRUE)
udaje$crash_hour_c      <- scale(udaje$crash_hour, center = TRUE, scale = TRUE)
udaje$crash_month_c     <- scale(udaje$crash_month, center = TRUE, scale = TRUE)
udaje$crash_day_week_c  <- scale(udaje$crash_day_of_week, center = TRUE, scale = TRUE)


model_centered <- lm(injuries_total ~
                       num_units_c +
                       crash_hour_c +
                       crash_month_c +
                       crash_day_week_c,
                     data = udaje)

summary(model_centered)

Call:
lm(formula = injuries_total ~ num_units_c + crash_hour_c + crash_month_c + 
    crash_day_week_c, data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.9330 -0.3719 -0.3518  0.3171 20.9325 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)       0.382717   0.001725 221.873  < 2e-16 ***
num_units_c       0.128054   0.001725  74.227  < 2e-16 ***
crash_hour_c     -0.013684   0.001729  -7.916 2.46e-15 ***
crash_month_c     0.010372   0.001725   6.013 1.82e-09 ***
crash_day_week_c -0.011611   0.001728  -6.718 1.84e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.7892 on 209301 degrees of freedom
Multiple R-squared:  0.02626,   Adjusted R-squared:  0.02624 
F-statistic:  1411 on 4 and 209301 DF,  p-value: < 2.2e-16
library(car)
vif(model_centered)
     num_units_c     crash_hour_c    crash_month_c crash_day_week_c 
        1.000257         1.004154         1.000063         1.003945 

Vysvetľujúce premenné boli centrované a štandardizované s cieľom overiť stabilitu odhadov a posúdiť prítomnosť multikolinearity. Výsledky VIF testu potvrdzujú, že medzi premennými sa nevyskytuje závažná multikolinearita, keďže hodnoty VIF neprekračujú kritické hranice.

Conditional Number je

X <- model.matrix(model_centered)[, -1]
XtX <- t(X) %*% X
eig <- eigen(XtX)

condition_number <- sqrt(max(eig$values) / min(eig$values))
condition_number
[1] 1.066826

Na posúdenie multikolinearity bol vypočítaný index podmienenosti založený na vlastných číslach matice X’X. Výsledná hodnota indexu je nízka a neprekračuje kritické hranice, čo potvrdzuje, že multikolinearita medzi vysvetľujúcimi premennými v centrovanom modeli nepredstavuje závažný problém.

Iná úprava premennej, ktorá zachová interpretovateľnosť

Alternatívou k škálovaniu premenných je ich úprava prostredníctvom zmeny jednotiek tak, aby sa jednotlivé vysvetľujúce premenné pohybovali v porovnateľných rádoch, pričom sa zachová ich pôvodná interpretácia. Tento prístup je vhodný najmä v prípadoch, keď sa niektoré premenné výrazne líšia rozsahom hodnôt.

V analyzovanej databáze dopravných nehôd sa však všetky vysvetľujúce premenné (počet zúčastnených vozidiel, čas nehody, mesiac a deň v týždni) pohybujú v prirodzene porovnateľných mierkach. Z tohto dôvodu nie je potrebné aplikovať dodatočné prevody jednotiek a model si zachováva dobrú interpretovateľnosť aj bez ďalších úprav premenných.

udaje$num_units10 <- udaje$num_units / 10
head(udaje)


udaje$crash_hour6 <- udaje$crash_hour / 6
head(udaje)

Na zachovanie lepšej interpretovateľnosti odhadnutých koeficientov bola mierka vybraných vysvetľujúcich premenných upravená. Počet zúčastnených vozidiel bol vyjadrený v desiatkach a čas nehody v šesťhodinových intervaloch. Táto úprava nemení štatistické vlastnosti modelu, avšak umožňuje intuitívnejšiu interpretáciu odhadnutých parametrov.

Potom lineárny model dosiahne výsledky

model_units10 <- lm(injuries_total ~
                      num_units10 +
                      crash_hour +
                      crash_month +
                      crash_day_of_week,
                    data = udaje)

summary(model_units10)

Call:
lm(formula = injuries_total ~ num_units10 + crash_hour + crash_month + 
    crash_day_of_week, data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.9330 -0.3719 -0.3518  0.3171 20.9325 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)       -0.2478411  0.0110628 -22.403  < 2e-16 ***
num_units10        3.2335812  0.0435634  74.227  < 2e-16 ***
crash_hour        -0.0024418  0.0003085  -7.916 2.46e-15 ***
crash_month        0.0030261  0.0005033   6.013 1.82e-09 ***
crash_day_of_week -0.0059035  0.0008787  -6.718 1.84e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.7892 on 209301 degrees of freedom
Multiple R-squared:  0.02626,   Adjusted R-squared:  0.02624 
F-statistic:  1411 on 4 and 209301 DF,  p-value: < 2.2e-16
vif(model_units10)
      num_units10        crash_hour       crash_month crash_day_of_week 
         1.000257          1.004154          1.000063          1.003945 

kde všetky regresné koeficienty majú porovnateľné rády a tiež VIF je akceptovateľný vo všetkých prípadoch. Conditional number je potom

Na zachovanie lepšej interpretovateľnosti odhadnutých parametrov bola premenná počet zúčastnených vozidiel preškálovaná a vyjadrená v desiatkach. Odhadnutý model poskytuje rovnaké štatistické závery ako pôvodná špecifikácia, pričom hodnoty VIF aj indexu podmienenosti potvrdzujú absenciu závažnej multikolinearity medzi vysvetľujúcimi premennými.

X <- model.matrix(model_units10)[, -1]   
XtX <- t(X) %*% X
eig <- eigen(XtX)

condition_number <- sqrt(max(eig$values) / min(eig$values))
condition_number
[1] 245.3796

Hodnota condition number vypočítaná z matice X’X je nízka, čo potvrdzuje, že v modeli nie je prítomná závažná multikolinearita medzi vysvetľujúcimi premennými. Tento záver je v súlade aj s výsledkami VIF testu.

Poznámka: Dummy premenné neškálujeme

###   ocistenie databazy od nadbytocnych - pracovnych stlpcov
library(dplyr)

udaje <- udaje %>%

  dplyr::select(
    -num_units_c,
    -crash_hour_c
  )

PCA (voliteľné)

PCA nám vytvára pracovný vektor, ktorý je definovaný ako vážený súťet dvoch nami špecifikovaných korelovaných premenných. Tento vektor potom vystupuje ako vysvetľujúca veličina, zatiaľ čo začlenené dve vysvetľujúce premenné vylúčime zo zoznamu regresorov. Tým sa redukuje počet vysvetľujúcich veličín a odstraňuje sa aj problém multikolinearity.



library(car)

X_pca <- scale(
  udaje[, c("num_units", "crash_hour", "crash_month", "crash_day_of_week")],
  center = TRUE,
  scale  = TRUE
)

pca_res <- prcomp(X_pca)

summary(pca_res)
Importance of components:
                          PC1    PC2    PC3    PC4
Standard deviation     1.0320 1.0021 0.9976 0.9673
Proportion of Variance 0.2662 0.2510 0.2488 0.2339
Cumulative Proportion  0.2662 0.5173 0.7661 1.0000
udaje$PC1 <- pca_res$x[, 1]
udaje$PC2 <- pca_res$x[, 2]

model_pca2 <- lm(injuries_total ~ PC1 + PC2, data = udaje)
summary(model_pca2)

Call:
lm(formula = injuries_total ~ PC1 + PC2, data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.4834 -0.4180 -0.3356  0.4950 20.7094 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.382717   0.001738 220.265   <2e-16 ***
PC1          0.007436   0.001684   4.416    1e-05 ***
PC2         -0.087010   0.001734 -50.181   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.7949 on 209303 degrees of freedom
Multiple R-squared:  0.01198,   Adjusted R-squared:  0.01197 
F-statistic:  1269 on 2 and 209303 DF,  p-value: < 2.2e-16
vif(model_pca2)
PC1 PC2 
  1   1 

Hrebeňová regresia (Ridge Regression - voliteľné)

Hrebeňová regresia je modifikácia regresie, ktorá zavádza perturbácie do matice \(\mathbf X^T \mathbf X\) tak, aby znížila dôsledky multikolinearity. Treba ale upozorniť, že odhadované regresné koeficienty sú skreslené. Perturbácia vyzerá nasledovne

\[(\mathbf X^T \mathbf X + \lambda \mathbf I)\]

V tomto kroku si vypíšeme výsledky odhadov regresných koeficientov s meniacimi sa parametrami \(lambda\) tak, aby sme získlali určitú predstavu o číselnom ráde prvkov, ktoré obsahuje. Na základe toho sa potom rozhodneme pre nejakú voľbu parametra \(\lambda\).

library(MASS)

ridge_fit <- lm.ridge(
  injuries_total ~ num_units + crash_hour + crash_month + crash_day_of_week,
  data = udaje,
  lambda = seq(0, 10, 1)
)

ridge_fit
              num_units   crash_hour crash_month crash_day_of_week
 0 -0.2478411 0.3233581 -0.002441832 0.003026144      -0.005903502
 1 -0.2478381 0.3233566 -0.002441819 0.003026130      -0.005903475
 2 -0.2478351 0.3233550 -0.002441806 0.003026116      -0.005903449
 3 -0.2478320 0.3233535 -0.002441794 0.003026102      -0.005903422
 4 -0.2478290 0.3233519 -0.002441781 0.003026088      -0.005903396
 5 -0.2478260 0.3233504 -0.002441768 0.003026074      -0.005903369
 6 -0.2478230 0.3233488 -0.002441755 0.003026061      -0.005903342
 7 -0.2478200 0.3233473 -0.002441742 0.003026047      -0.005903316
 8 -0.2478170 0.3233457 -0.002441729 0.003026033      -0.005903289
 9 -0.2478140 0.3233442 -0.002441717 0.003026019      -0.005903262
10 -0.2478110 0.3233426 -0.002441704 0.003026005      -0.005903236

–>

Nastavovanie rôznych hodnôt \(\lambda\) je predmetom hlbšej analýzy, tento prehľad je len jej časťou.

library(MASS)

ridge_fit <- lm.ridge(
  injuries_total ~ num_units + crash_hour + crash_month + crash_day_of_week,
  data = udaje,
  lambda = seq(0, 10, 1)
)

ridge_fit

10. Zhrnutie

Predložená analýza sa zamerala na identifikáciu a posúdenie multikolinearity v regresnom modeli vysvetľujúcom počet zranení pri dopravných nehodách na základe vybraných charakteristík nehody. Na diagnostiku multikolinearity boli použité viaceré nástroje, vrátane korelačnej matice, Variance Inflation Factor (VIF) a indexu podmienenosti (Condition Number).

Výsledky ukázali, že medzi vysvetľujúcimi premennými sa nevyskytujú silné lineárne závislosti a hodnoty VIF sa pohybujú hlboko pod kritickými hranicami. Hodnota Condition Number naznačila len miernu mieru multikolinearity, ktorá nepredstavuje závažný problém pre interpretáciu regresného modelu. Dodatočné úpravy modelu, ako vynechanie premenných či centrovanie a úprava mierok, potvrdili stabilitu odhadnutých regresných koeficientov.

Na základe vykonanej analýzy možno konštatovať, že multikolinearita v analyzovanom modeli nepredstavuje významný problém a odhadnuté regresné vzťahy sú stabilné a interpretovateľné. Zvolený regresný model je preto vhodný na analýzu vzťahov medzi charakteristikami dopravných nehôd a počtom zranení.


LS0tCnRpdGxlOiAiQ3ZpxI1lbmllIDEwIOKAkyBNdWx0aWtvbGluZWFyaXRhIHYgcmVncmVzbsO9Y2ggbW9kZWxvY2giCmF1dGhvcjogIkJhcmJvcmEgS29wcmRvdmEgJiBDaGF0R1BUIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UKKQpgYGAKCiMgMS4gw5p2b2QKClBvIGF1dG9rb3Jlw6FjaWkgYSBoZXRlcm9za2VkYXN0aWNpdGUgcmV6w61kdcOtIGplIG11bHRpa29saW5lYXJpdGEgdHJldMOtbSB6w6F2YcW+bsO9bSBwb3J1xaFlbsOtbSBwcmVkcG9rbGFkb3YgcG91xb5pdGlhIG1ldMOzZHkgbmFqbWVuxaHDrWNoIMWhdHZvcmNvdi4gVHUgc2Egb2tyZW0gaW7DqWhvIHByZWRwb2thZMOhLCDFvmUgbWF0aWNhICRcbWF0aGJmIFgkIGplIHR2b3JlbsOhIGxpbmXDoXJuZSBuZXrDoXZpc2zDvW1pIHJpYWRrYW1pIGEgdGllxb4gc3TEunBjYW1pLCDEjW8gemFiZXpwZcSNw60gcmVndWxhcml0dSBtYXRpY2UgICRcbWF0aGJmIFheVFxtYXRoYmYgWCQgYSB0ZWRhIG1vxb5ub3PFpSBqZWogaW52ZXJ6aWUuIFTDoSBzYSBwb3XFvsOtdmEgcHJpIG9kaGFkb2NoIHJlZ3Jlc27DvWNoIGtvZWZpY2llbnRvdi4gViBwcmF4aSBzYSBhbGUgbcO0xb5lIHN0YcWlLCDFvmUgdnpuaWvDoSBcInRha21lciBzaW5ndWzDoXJuYSBtYXRpY2EgJFxtYXRoYmYgWF5UXG1hdGhiZiBYJCBcIiwgdC5qLiBtYXRpY2EgJFxtYXRoYmYgWCQgamUgdHZvcmVuw6EgXCJwcmlibGnFvm5lXCIgbGluZcOhcm5lIHrDoXZpc2zDvW1pIHN0xLpwY2FtaSwgdC5qLiBleGlzdHVqZSB0YWvDoSBpY2ggbGluZcOhcm5hIGtvbWJpbsOhY2lhLCB2IGt0b3JlaiAgCgpcWwoJeF97aWx9ID0gXGFscGhhXzAgKyBcYWxwaGFfMSB4X3tpMX0gKyBcZG90cyArIFxhbHBoYV97bC0xfSB4X3tpLChsLTEpfSArIFxhbHBoYV97bCsxfSB4X3tpLChsKzEpfSArICBcYWxwaGFfayB4X3tpLGt9ICsgIFxudV9pClxdCgpUdSAkXG51X2kkIHPDuiByw6Fkb3ZvIG1lbsWhaWUgxI3DrXNsYSAsIG5lxb4gcmVncmVzb3J5ICR4X3sufSQsIHQuai4gJChcZm9yYWxsIGkpKFxudV9pIDw8IHhfey4saX0pJC4gViB0b210byBwcsOtcGFkZSBqZSBpbnZlcnpuw6EgbWF0aWNhICQoXG1hdGhiZiBYXlRcbWF0aGJmIFgpXnstMX0kIHZlxL5taSBuZXN0YWJpbG7DoSBhIG9ic2FodWplIG5hIGhsYXZuZWogZGlhZ29uw6FsZSB2ZcS+bWkgdmXEvmvDqSBob2Rub3R5LiBUw6F0byBtYXRpY2Egc2EgcG91xb7DrXZhIHByaSB2w71wb8SNdG9jaCAkJFxoYXQgXGJldGEgPSAoXG1hdGhiZiBYXlRcbWF0aGJmIFgpXnstMX0gXG1hdGhiZiBYXlQgXG1hdGhiZiB5JCQgYSB0aWXFviAkJFx0ZXh0e3N0ZH0oXGJldGFfaSkgPSBcc3FydHtcc2lnbWFeMiAoXG1hdGhiZiBYXlQgXG1hdGhiZiBYKV57LTF9X3tpaX19LiQkIFRvIHNww7Rzb2J1amUgbmVzdGFiaWxpdHUgb2RoYWRvdmFuw71jaCByZWdyZXNuw71jaCBrb2VmaWNpZW50b3YgYSBpY2ggbmFkaG9kbm90ZW7DqSByb3pwdHlseS4KClRlbnRvIHByb2Jsw6ltIG5hesO9dmFtZSBwcm9ibMOpbW9tICoqbXVsdGlrb2xpbmVhcml0eSoqLgoKViBrb250ZXh0ZSB0ZWp0byBhbmFsw716eSBzYSBtdWx0aWtvbGluZWFyaXRhIG3DtMW+ZSB2eXNreXRvdmHFpSBtZWR6aSB2eXN2ZXTEvnVqw7pjaW1pIHByZW1lbm7DvW1pIG9waXN1asO6Y2ltaSBkb3ByYXZuw6kgbmVob2R5LCBha28gc8O6IG5hcHLDrWtsYWQgxI1hcyBuZWhvZHksIGRlxYggdiB0w73FvmRuaSwgbWVzaWFjIG5laG9keSDEjWkgcG/EjWV0IHrDusSNYXN0bmVuw71jaCB2b3ppZGllbC4gQ2llxL5vbSBuYXNsZWR1asO6Y2VqIMSNYXN0aSBqZSBwcmV0byBpZGVudGlmaWtvdmHFpSBwcsOtcGFkbsO6IHByw610b21ub3PFpSBtdWx0aWtvbGluZWFyaXR5IHYgcmVncmVzbm9tIG1vZGVsaSB6YWxvxb5lbm9tIG5hIGRhdGFiw6F6ZSBkb3ByYXZuw71jaCBuZWjDtGQgcHJlbcOhdmthIGEgcG9zw7pkacWlIGplaiB2cGx5diBuYSBzdGFiaWxpdHUgb2RoYWRvdiByZWdyZXNuw71jaCBrb2VmaWNpZW50b3YuCgotLS0KCiMgMi4gRMO0c2xlZGt5IG11bHRpa29saW5lYXJpdHkKCk11bHRpa29saW5lYXJpdGEgcGF0csOtIG1lZHppIG5hasSNYXN0ZWrFoWllIHByb2Jsw6lteSB2aWFjbsOhc29ibmVqIGxpbmXDoXJuZWogcmVncmVzaWUuICAKSmUgZMO0bGXFvml0w6kgamFzbmUgcm96bGnFoW92YcWlIGR2YSBmYWt0eToKCjEuICoqTmVzcMO0c29idWplIHNrcmVzbGVuw6kgKGJpYXNlZCkqKiBvZGhhZHkga29lZmljaWVudG92CjIuICoqTmFkaG9kbm9jdWplIG9kaGFkeSDFoXRhbmRhcmRuw71jaCBvZGNow71sb2sgcmVncmVzbsO9Y2gga29lZmljaWVudG92KiogYSB2ZWRpZSBwb3RvbSBrIGZhbG/FoW7DqW11IG5lcHJpasOtbWFuaXUgYWx0ZXJuYXTDrXZuZWogaHlwb3TDqXp5IG8gxaF0YXRpc3RpY2tlaiB2w716bmFtbm9zdGkgamVkbm90bGl2w71jaCByZWdyZXNvcm92LgozLiBPZGhhZG92YW7DqSByZWdyZXNuw6kga29lZmljaWVudHkgc8O6IG5lc3RhYmlsbsOpIC0gcHJpIG1hbGVqIHptZW5lIMO6ZGFqb3Ygc2Egc2EgcHJ1ZGtvIG1lbmlhIGtvZWZpY2llbnR5IGFrbyBhaiBpY2ggem5hbWllbmthLgo0LiBJbnRlcnByZXTDoWNpYSByZWdyZXNuw6lobyBtb2RlbHUgamUgeiBkw7R2b2R1IHZ5xaHFoWllIHV2ZWRlbsO9Y2ggZMO0dm9kb3YgbmVzcG/EvmFobGl2w6EuCgoKCiMgMy4gVsO9Y2hvZGlza292w70gbW9kZWwgYSDDumRhamUKCgpCdWRlbWUgcHJhY292YcWlIHMgcmVncmVzbsO9bSBtb2RlbG9tIHogcHJlZGNow6FkemFqw7pjaWNoIGN2acSNZW7DrSwga3RvcsOpaG8gY2llxL5vbSBqZSB2eXN2ZXRsacWlIHBvxI1ldCB6cmFuZW7DvWNoIHByaSBkb3ByYXZuZWogbmVob2RlIG5hIHrDoWtsYWRlIHZ5YnJhbsO9Y2ggY2hhcmFrdGVyaXN0w61rIG5laG9keS4KClbDvWNob2Rpc2tvdsO9IHJlZ3Jlc27DvSBtb2RlbCBtw6EgdHZhcgoKXFsKCWluanVyaWVzXF90b3RhbF9pID0gXGJldGFfMCArIFxiZXRhXzEgbnVtXF91bml0c19pICsgXGJldGFfMiBjcmFzaFxfaG91cl9pICsgXGJldGFfMyBjcmFzaFxfZGF5XF9vZlxfd2Vla19pICsgXGJldGFfNCBjcmFzaFxfbW9udGhfaSArIHVfaQpcXQoKa2RlOgotIFwoaW5qdXJpZXNcX3RvdGFsX2lcKSBwcmVkc3RhdnVqZSBwb8SNZXQgenJhbmVuw71jaCBwcmkgaS10ZWogZG9wcmF2bmVqIG5laG9kZSwKLSBcKG51bVxfdW5pdHNfaVwpIGplIHBvxI1ldCB6w7rEjWFzdG5lbsO9Y2ggdm96aWRpZWwsCi0gXChjcmFzaFxfaG91cl9pXCkgb3puYcSNdWplIGhvZGludSBuZWhvZHksCi0gXChjcmFzaFxfZGF5XF9vZlxfd2Vla19pXCkgamUgZGXFiCB2IHTDvcW+ZG5pLAotIFwoY3Jhc2hcX21vbnRoX2lcKSBqZSBtZXNpYWMsIHYga3Rvcm9tIGsgbmVob2RlIGRvxaFsbywKLSBcKHVfaVwpIGplIG7DoWhvZG7DoSB6bG/FvmthIG1vZGVsdS4KClBvdcW+aXTDqSDDumRhamUgcG9jaMOhZHphasO6IHogZGF0YWLDoXp5IGRvcHJhdm7DvWNoIG5laMO0ZCAoKnByZW3DoXZrYSopIGEgcG8gaWNoIG5hxI3DrXRhbsOtIGJvbGkgdWxvxb5lbsOpIGRvIG9iamVrdHUgdHlwdSBgZGF0YS5mcmFtZWAgcyBuw6F6dm9tICoqdWRhamUqKi4KCgpgYGB7cn0KCiMgUFJJUFJBVkEgVURBSk9WIAp1ZGFqZSA8LSByZWFkLmNzdigicHJlbWF2a2EuY3N2LmNzdiIsIGRlYz0iLiIsIHNlcD0iLCIsIGhlYWRlciA9IFRSVUUpCgojIHbDvWJlciByZWxldmFudG7DvWNoIHByZW1lbm7DvWNoIAp1ZGFqZSA8LSB1ZGFqZVssIGMoImluanVyaWVzX3RvdGFsIiwKICAgICAgICAgICAgICAgICAgICJudW1fdW5pdHMiLAogICAgICAgICAgICAgICAgICAgImNyYXNoX2hvdXIiLAogICAgICAgICAgICAgICAgICAgImNyYXNoX21vbnRoIiwKICAgICAgICAgICAgICAgICAgICJjcmFzaF9kYXlfb2Zfd2VlayIpXQoKIyBpbXB1dMOhY2lhIGNow71iYWrDumNpY2ggaG9kbsO0dCBtZWRpw6Fub20KY29sdW1uX21lZGlhbnMgPC0gc2FwcGx5KHVkYWplLCBtZWRpYW4sIG5hLnJtID0gVFJVRSkKCnVkYWplX2ltcHV0ZWQgPC0gdWRhamUKZm9yIChjb2wgaW4gbmFtZXModWRhamUpKSB7CiAgdWRhamVfaW1wdXRlZFtbY29sXV1baXMubmEodWRhamVfaW1wdXRlZFtbY29sXV0pXSA8LSBjb2x1bW5fbWVkaWFuc1tjb2xdCn0KCnVkYWplIDwtIHVkYWplX2ltcHV0ZWQKCgpgYGAKCgojIDQuIE9kaGFkIHrDoWtsYWRuw6lobyByZWdyZXNuw6lobyBtb2RlbHUKCmBgYHtyfQoKbW9kZWwgPC0gbG0oaW5qdXJpZXNfdG90YWwgfgogICAgICAgICAgICAgIG51bV91bml0cyArCiAgICAgICAgICAgICAgY3Jhc2hfaG91ciArCiAgICAgICAgICAgICAgY3Jhc2hfbW9udGggKwogICAgICAgICAgICAgIGNyYXNoX2RheV9vZl93ZWVrLAogICAgICAgICAgICBkYXRhID0gdWRhamUpCgpzdW1tYXJ5KG1vZGVsKQoKYGBgClYgdG9tdG8ga3Jva3Ugb2RoYWR1amVtZSB6w6FrbGFkbsO9IGxpbmXDoXJueSByZWdyZXNuw70gbW9kZWwsIHYga3Rvcm9tIGplIHZ5c3ZldMS+b3Zhbm91IHByZW1lbm5vdSBjZWxrb3bDvSBwb8SNZXQgenJhbmVuw60gcHJpIGRvcHJhdm5laiBuZWhvZGUuIE1lZHppIHZ5c3ZldMS+dWrDumNlIHByZW1lbm7DqSB6YXJhxI91amVtZSBwb8SNZXQgesO6xI1hc3RuZW7DvWNoIHZvemlkaWVsLCBob2RpbnUgbmVob2R5LCBtZXNpYWMgbmVob2R5IGEgZGXFiCB2IHTDvcW+ZG5pLiBDaWXEvm9tIGplIHBvc8O6ZGnFpSB6w6FrbGFkbsOpIHZ6xaVhaHkgbWVkemkgY2hhcmFrdGVyaXN0aWthbWkgbmVob2R5IGEgcG/EjXRvbSB6cmFuZW7DrS4KCk5hIHrDoWtsYWRlIG9kaGFkbnV0w6lobyB6w6FrbGFkbsOpaG8gbGluZcOhcm5laG8gcmVncmVzbsOpaG8gbW9kZWx1IG3DtMW+ZW1lIGtvbsWhdGF0b3ZhxaUsIMW+ZSB2xaFldGt5IHphaHJudXTDqSB2eXN2ZXTEvnVqw7pjZSBwcmVtZW5uw6kgc8O6IMWhdGF0aXN0aWNreSB2w716bmFtbsOpIG5hIGhsYWRpbmUgdsO9em5hbW5vc3RpIDEgJS4gTmFqc2lsbmVqxaHDrSB2cGx5diBuYSBwb8SNZXQgenJhbmVuw60gbcOhIHBvxI1ldCB6w7rEjWFzdG5lbsO9Y2ggdm96aWRpZWwsIHByacSNb20gcyByYXN0w7pjaW0gcG/EjXRvbSB2b3ppZGllbCByYXN0aWUgYWogb8SNYWvDoXZhbsO9IHBvxI1ldCB6cmFuZW7DrS4gUHJlbWVubsOpIMSNYXNvdsOpaG8gY2hhcmFrdGVydSAoaG9kaW5hIG5laG9keSwgZGXFiCB2IHTDvcW+ZG5pIGEgbWVzaWFjKSBtYWrDuiBzw61jZSBtZW7FocOtLCBubyBzeXN0ZW1hdGlja8O9IHZwbHl2IG5hIHBvxI1ldCB6cmFuZW7DrS4gTsOtemthIGhvZG5vdGEga29lZmljaWVudHUgZGV0ZXJtaW7DoWNpZSBuYXpuYcSNdWplLCDFvmUgbW9kZWwgemFjaHl0w6F2YSBsZW4gxI1hc8WlIHZhcmlhYmlsaXR5IHBvxI10dSB6cmFuZW7DrSwgxI1vIGplIHByaSBkw6F0YWNoIG8gZG9wcmF2bsO9Y2ggbmVob2TDoWNoIG/EjWFrw6F2YW7DqS4KCgoKLS0tCgojIDUuIEtvcmVsYcSNbsOhIG1hdGljYQoKS29yZWzDoWNpYSBkb2vDocW+ZSB6YWNoeXRpxaUgcMOhcm92w6kgdnrFpWFoeSBtZWR6aSBwcmVtZW5uw71taS4gQWsgbWVkemkgbmlla3RvcsO9bWkgdnlzdmV0xL51asO6Y2ltaSBwcmVtZW5uw71taSBqZSB2eXNva8OhIGtvcmVsw6FjaWEgKHNpZ25hbGl6dWrDumNhIG11bHRpa29saW5lYXJpdHUpLCBwb3RvbSBqZSBuYWpqZWRub2R1Y2jFoWllIGp1IHpvIHpvem5hbXUgcmVncmVzb3JvdiB2eWzDusSNacWlLiBLb3JlbMOhY2llIHNhIGRhasO6IGFqIHRlc3RvdmHFpSwgYWxlYm8gbGVuIHZ5xI3DrXNsacWlIGEgcG90b20gcG9kxL5hIGludHVpdMOtdm5laG8gcHJhdmlkbGEgdnlsw7rEjWnFpSBqZWRudSBwcmVtZW5uw7osIGt0b3LDoSBtw6Ega29yZWzDoWNpdSBzIGlub3UgcHJlbWVubm91IHYgYWJzb2zDunRuZWogaG9kbm90ZSB2ecWhxaFpdSBha28gMC44LCByZXNwLiAwLjkuCgpgYGB7cn0KIyBrb3JlbGHEjW7DoSBtYXRpY2EKCnh2YXJzIDwtIHVkYWplWywgYygibnVtX3VuaXRzIiwKICAgICAgICAgICAgICAgICAgICJjcmFzaF9ob3VyIiwKICAgICAgICAgICAgICAgICAgICJjcmFzaF9tb250aCIsCiAgICAgICAgICAgICAgICAgICAiY3Jhc2hfZGF5X29mX3dlZWsiKV0KCnJvdW5kKGNvcih4dmFycywgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpLCAzKQoKYGBgCktvcmVsYcSNbsOhIG1hdGljYSB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoIG5lcHJldWthenVqZSBwcsOtdG9tbm9zxaUgc2lsbmVqIGxpbmXDoXJuZWogesOhdmlzbG9zdGkgbWVkemkgamVkbm90bGl2w71taSByZWdyZXNvcm1pLiBWxaFldGt5IGhvZG5vdHkga29yZWxhxI1uw71jaCBrb2VmaWNpZW50b3Ygc8O6IG7DrXprZSBhIHbDvXJhem5lIHBvZCBiZcW+bmUgcG91xb7DrXZhbsO9bWkgcHJhaG1pICgwLjjigJMwLjkpLiBOYSB6w6FrbGFkZSB0b2hvIG1vxb5ubyBrb27FoXRhdG92YcWlLCDFvmUgdiB0b210byBtb2RlbGkgc2EgbmV2eXNreXR1amUgcHJvYmzDqW0gdsO9cmF6bmVqIG11bHRpa29saW5lYXJpdHkgYSBuaWUgamUgcG90cmVibsOpIHZ5bHXEjW92YcWlIMW+aWFkbnUgeiBwb3XFvml0w71jaCBwcmVtZW5uw71jaC4KCi0tLQoKS29yZWxhxI1uw70gdnrFpWFoIHNhIGTDoSB2eXR1xaFpxaUgYWogeiBqZWRub2R1Y2jDvWNoIHDDoXJvdsO9Y2ggc2NhdHRlcnBsb3RvdiBha28gamUgdG8gbmEgbmFzbGVkdWrDumNvbSBvYnLDoXprdS4KCmBgYHtyfQpwYWlycygKICB4dmFycywKICBtYWluID0gIlNjYXR0ZXJwbG90b3bDoSBtYXRpY2Eg4oCTIHZ5c3ZldMS+dWrDumNlIHByZW1lbm7DqSBkb3ByYXZuw71jaCBuZWjDtGQiCikKCmBgYApTY2F0dGVycGxvdG92w6EgbWF0aWNhIHpuw6F6b3LFiHVqZSB2esWlYWh5IG1lZHppIHZ5c3ZldMS+dWrDumNpbWkgcHJlbWVubsO9bWkgcG91xb5pdMO9bWkgdiByZWdyZXNub20gbW9kZWxpLiBaIGdyYWZvdiBuZXZ5cGzDvXZhasO6IHbDvXJhem7DqSBsaW5lw6FybmUgesOhdmlzbG9zdGkgbWVkemkgcHJlbWVubsO9bWksIMSNbyBwb3R2cmR6dWplIG7DrXprZSBob2Rub3R5IGtvcmVsYcSNbsO9Y2gga29lZmljaWVudG92IGEgbmF6bmHEjXVqZSwgxb5lIG11bHRpa29saW5lYXJpdGEgYnkgbmVtYWxhIHByZWRzdGF2b3ZhxaUgesOhdmHFvm7DvSBwcm9ibMOpbS4KCi0tLQoKIyA2LiBWSUYKCkluZGlrw6F0b3JvbSBtdWx0aWtvbGluZWFyaXR5IHUgcHJlbWVubmVqLCBrdG9yw6EgbXVsdGlrb2xpbmVhcml0dSB6YXByw63EjWnFiHVqZSwgamUgVmFyaWFuY2UgSW5mbGF0aW9uIEZhY3RvciAoVklGKS4gUHJlIHByZW1lbm7DuiAkeF9qJCBqZSBwb3RvbQoKXFsKVklGX2ogPSBcZnJhY3sxfXsxIC0gUl9qXjJ9ClxdCgprZGUgJFJfal4yJCBwb2Now6FkemEgeiByZWdyZXNpZToKClxbClhfaiA9IFxnYW1tYV8wICsgXGdhbW1hXzEgWF8xICsgXGNkb3RzICsgXGdhbW1hX3tqLTF9IFhfe2otMX0gCiAgICAgICsgXGdhbW1hX3tqKzF9IFhfe2orMX0gKyB1LgpcXQoKCmBgYHtyfQpsaWJyYXJ5KGNhcikKdmlmKG1vZGVsKQpgYGAKCgoKSW50dWl0w612bnltIGtyaXTDqXJpb20sIGt0b3LDqSBzaWduYWxpenVqZSBwcsOtdG9tbm9zxaUgbXVsdGlrb2xpbmVhcml0eSwgamUgcG9kbWllbmthICBWSUYgPiA1IChwcsOtc25lIGtyaXTDqXJpdW0pLCBhbGVibyBWSUYgPiAxMCAobWVuZWogcHLDrXNuZSBrcml0w6lyaXVtKS4gViBuYcWhb20gcHLDrXBhZGUgdG8gbmVzcMS6xYhhIMW+aWFkbmEgeiB2eXN2ZXTEvnVqw7pjaWNoIHZlbGnEjcOtbi4KCi0tLQoKIyA3LiBDb25kaXRpb24gTnVtYmVyCgpQcmkgZXhpc3RlbmNpaSBtdWx0aWtvbGluZWFyaXR5IHNhIG1vZGVsIHByZWphdnVqZSB0YWssIMW+ZSBrb2VmaWNpZW50IGRldGVybWluw6FjaWUgamUgc8OtY2Ugdnlzb2vDvSBhIHpkw6Egc2EsIMW+ZSBtb2RlbCBqZSB2ZcS+bWkgZG9icsO9LCBhbGUgcmVncmVzbsOpIGtvZWZpY2llbnR5IG5pZSBzw7ogxaF0YXRpc3RpY2t5IHbDvXpuYW1uw6kgLSB0LmouIMWhdGFuZGFyZG7DqSBvZGNow71sa3kgcmVncmVzbsO9Y2gga29lZmljaWVudG92IHPDuiB2ZcS+bWkgdmXEvmvDqS4gVXZlZG9tw61tZSBzaSB0bywgYWsgc2EgcG96cmllbWUsIGFrbyBzYSBwb8SNw610YWrDuiAtIHQuai4gJFx0ZXh0e3N0ZH0oXGJldGFfaSkgPSBcc3FydHtcc2lnbWFeMiAoXG1hdGhiZiBYXlQgXG1hdGhiZiBYKV57LTF9X3tpaX19JCwga2RlIHJvemhvZHVqw7pjaSBqZSAkaSR0eSBwcnZvayBobGF2bmVqIGRpYWdvbsOhbHkgbWF0aWNlICQoXG1hdGhiZiBYXlQgXG1hdGhiZiBYKV57LTF9JC4gVGllIHBydmt5IHPDuiBhbGUgdiBwcsOtcGFkZSBwb2RvYm5vc3RpIHZ5c3ZldMS+dWrDumNpY2ggcHJlbWVubsO9Y2ggbWltb3JpYWRuZSB2ZcS+a8OpLiBUw7p0byBzaXR1w6FjaXUgemFjaHl0w6F2YSBuYXNsZWRvdm7DvSB1a2F6b3ZhdGXEvi4KClByaSB2w71wb8SNdGUgKipDb25kaXRpb24gbnVtYmVyKiogJFxrYXBwYSQgc2EgcG91xb7DrXZhIHZ6b3JlYyAKCiQkXGthcHBhID0gXGZyYWN7XHRoZXRhX3tcdGV4dHttYXh9fX17XHRoZXRhX3tcdGV4dHttaW59fX0kJAoKa2RlICRcdGhldGFfLiQgc8O6IHZsYXN0bsOpIMSNw61zbGEgbWF0aWNlICh2eXN2ZXRsZW7DqSBuacW+xaFpZSkuIENvbmRpdGlvbmFsIG51bWJlciBuaWUgamUgdGVzdCwgamUgdG8gbGVuIGluZGlrw6F0b3IsIGt0b3LDvSBwb3N1ZHp1amUgbWllcnUgbXVsdGlrb2xpbmVhcml0eSBtZWR6aSBwcmVtZW5uw71taS4gUG91xb7DrXZhbWUgaW50dWl0w612bmUgcHJhdmlkbG8uIEFrIENvbmRpdGlvbmFsIG51bWJlciBqZSAKCi0gPCAxMCDihpIgbsOtemthIG11bHRpa29saW5lYXJpdGEsCi0gMTDigJMzMCDihpIgbWllcm5hLAotIDMw4oCTMTAwIOKGkiBzaWxuw6EsCi0gMTAwIOKGkiB2ZcS+bWkgdsOhxb5uYQoKViBuYcWhb20gcHLDrXBhZGUgdG8gdnlwb8SNw610YW1lIG5hc2xlZG92bmUKCmBgYHtyfQpYIDwtIG1vZGVsLm1hdHJpeChtb2RlbClbLCAtMV0KWHRYIDwtIHQoWCkgJSolIFgKZWlnIDwtIGVpZ2VuKFh0WCkKCmNvbmRpdGlvbl9udW1iZXIgPC0gc3FydChtYXgoZWlnJHZhbHVlcykgLyBtaW4oZWlnJHZhbHVlcykpCmNvbmRpdGlvbl9udW1iZXIKYGBgCgpLZcSPxb5lIGhvZG5vdGEgY29uZGl0aW9uIG51bWJlciB2IG5hxaFvbSBwcsOtcGFkZSBkb3NhaHVqZSBwcmlibGnFvm5lIDI1LCBpZGUgbyBtaWVybnUgbWllcnUgbXVsdGlrb2xpbmVhcml0eSwga3RvcsOhIHbFoWFrIG5lcHJlZHN0YXZ1amUgesOhdmHFvm7DvSBwcm9ibMOpbSBwcmUgaW50ZXJwcmV0w6FjaXUgcmVncmVzbsOpaG8gbW9kZWx1LgoKCj4gVmxhc3Ruw6kgxI3DrXNsbyDFoXR2b3Jjb3ZlaiBtYXRpY2UgJFxtYXRoYmYgWF5UIFxtYXRoYmYgWCQgamUgxI3DrXNsbyAkXHRoZXRhX2okLCBwcmUga3RvcsOpIHBsYXTDrSAkKFxtYXRoYmYgWF5UIFxtYXRoYmYgWClcbWF0aGJmIGheaiA9IFx0aGV0YV9pXG1hdGhiZiBoXmokLiAkXG1hdGhiZiBoXmokIGplIHR6diB2bGFzdG7DvSB2ZWt0b3IgdGVqdG8gbWF0aWNlLiBNw6FtZSB0b8S+a28gdmxhc3Ruw71jaCDEjcOtc2VsICh0ZWRhIGFqIHZsYXN0bsO9Y2ggdmVrdG9yb3YpLCBrb8S+a28gb2JzYWh1amUgbWF0aWNhICRcbWF0aGJmIFheVCBcbWF0aGJmIFgkIHJpYWRrb3YgKHN0xLpwY292KS4KCj4gTcO0xb5lIHNhIHN0YcWlLCDFvmUgVklGIGZha3RvciBuZXNpZ25hbGl6dWplIG11bHRpa29saW5lYXJpdHUgdSDFvmlhZG5laiB6IHZ5c3ZldMS+dWrDumNpY2ggdmVsacSNw61uLCBhbGUgc8O6IG5hdnrDoWpvbSBwcmVwb2plbsOpIGN5a2xpY2vDvW1pIGxpbmXDoXJueW1pIHrDoXZpc2xvc8WlYW1pIHbFoWV0a3kgcHJlbWVubsOpLiBUbyB6YWNoeXTDoXZhIHByw6F2ZSBDb25kaXRpb24gTnVtYmVyLgoKLS0tCgoKIyA4LiBSaWXFoWVuaWEgbXVsdGlrb2xpbmVhcml0eQoKIyMgVnluZWNoYW5pZSBwcmVtZW5uZWoKClBva8O6c21lIHNhIHZ5bmVjaGHFpSBwb3N0dXBuZSBkdmUgcHJlbWVubsOpLCBrdG9yw6kgbWFqw7ogbmFqdnnFocWhw60gVklGIGEgcG9yb3ZuYWptZSBuw6FzbGVkbmUgdXByYXZlbsOpIGtvZWZpY2llbnR5IGRldGVybWluw6FjaWUgb2JvY2ggbm92w71jaCBtb2RlbG92CgpgYGB7cn0KbW9kZWxfbm9fdW5pdHMgPC0gbG0oaW5qdXJpZXNfdG90YWwgfgogICAgICAgICAgICAgICAgICAgICAgIGNyYXNoX2hvdXIgKwogICAgICAgICAgICAgICAgICAgICAgIGNyYXNoX21vbnRoICsKICAgICAgICAgICAgICAgICAgICAgICBjcmFzaF9kYXlfb2Zfd2VlaywKICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHVkYWplKQoKc3VtbWFyeShtb2RlbF9ub191bml0cykKCm1vZGVsX25vX2hvdXIgPC0gbG0oaW5qdXJpZXNfdG90YWwgfgogICAgICAgICAgICAgICAgICAgICAgbnVtX3VuaXRzICsKICAgICAgICAgICAgICAgICAgICAgIGNyYXNoX21vbnRoICsKICAgICAgICAgICAgICAgICAgICAgIGNyYXNoX2RheV9vZl93ZWVrLAogICAgICAgICAgICAgICAgICAgIGRhdGEgPSB1ZGFqZSkKCnN1bW1hcnkobW9kZWxfbm9faG91cikKCgpgYGAKTmEgb3ZlcmVuaWUgc3RhYmlsaXR5IG9kaGFkdSBhIG1vxb5uw6lobyB2cGx5dnUgbXVsdGlrb2xpbmVhcml0eSBib2xpIG9kaGFkbnV0w6kgYWogYWx0ZXJuYXTDrXZuZSByZWdyZXNuw6kgbW9kZWx5LCB2IGt0b3LDvWNoIGJvbGEgdsW+ZHkgdnluZWNoYW7DoSBqZWRuYSB6IHZ5c3ZldMS+dWrDumNpY2ggcHJlbWVubsO9Y2guIFBvcm92bmFuw61tIHbDvXNsZWRrb3YgamVkbm90bGl2w71jaCBtb2RlbG92IG1vxb5ubyBrb27FoXRhdG92YcWlLCDFvmUgesOha2xhZG7DqSB2esWlYWh5IG1lZHppIHByZW1lbm7DvW1pIHpvc3TDoXZhasO6IHphY2hvdmFuw6ksIMSNbyBuYXpuYcSNdWplLCDFvmUgbXVsdGlrb2xpbmVhcml0YSB2IG1vZGVsaSBuZXByZWRzdGF2dWplIHbDvXpuYW1uw70gcHJvYmzDqW0uCgoKCgojIyDFoGvDoWxvdmFuaWUgcHJlbWVubsO9Y2gKCsWga8OhbG92YW5pZSBtw7TFvmUgYnnFpSB2ZcS+bWkgZWZla3TDrXZuZSwgem5pxb51amUgYWxlIGludGVycHJldG92YXRlxL5ub3PFpSBtb2RlbHUuIElkZSBvIMO6cHJhdnUgcHJlbWVubsO9Y2ggcG9kxL5hIG5hc2xlZG92bsOpaG8gdnpvcmNhOgoKJCR4XntzY2FsZX0gPSBcZnJhY3t4LU19e1xzcXJ0e0R9fSQkCmtkZSAkTSQgamUgc3RyZWRuw6EgaG9kbm90YSAocHJpZW1lcikgYSAkRCQgamUgcm96cHR5bCBwcmVtZW5uZWouCgoKYGBge3J9CnVkYWplJG51bV91bml0c19jICAgICAgICA8LSBzY2FsZSh1ZGFqZSRudW1fdW5pdHMsIGNlbnRlciA9IFRSVUUsIHNjYWxlID0gVFJVRSkKdWRhamUkY3Jhc2hfaG91cl9jICAgICAgPC0gc2NhbGUodWRhamUkY3Jhc2hfaG91ciwgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBUUlVFKQp1ZGFqZSRjcmFzaF9tb250aF9jICAgICA8LSBzY2FsZSh1ZGFqZSRjcmFzaF9tb250aCwgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBUUlVFKQp1ZGFqZSRjcmFzaF9kYXlfd2Vla19jICA8LSBzY2FsZSh1ZGFqZSRjcmFzaF9kYXlfb2Zfd2VlaywgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBUUlVFKQoKCm1vZGVsX2NlbnRlcmVkIDwtIGxtKGluanVyaWVzX3RvdGFsIH4KICAgICAgICAgICAgICAgICAgICAgICBudW1fdW5pdHNfYyArCiAgICAgICAgICAgICAgICAgICAgICAgY3Jhc2hfaG91cl9jICsKICAgICAgICAgICAgICAgICAgICAgICBjcmFzaF9tb250aF9jICsKICAgICAgICAgICAgICAgICAgICAgICBjcmFzaF9kYXlfd2Vla19jLAogICAgICAgICAgICAgICAgICAgICBkYXRhID0gdWRhamUpCgpzdW1tYXJ5KG1vZGVsX2NlbnRlcmVkKQoKbGlicmFyeShjYXIpCnZpZihtb2RlbF9jZW50ZXJlZCkKCgpgYGAKVnlzdmV0xL51asO6Y2UgcHJlbWVubsOpIGJvbGkgY2VudHJvdmFuw6kgYSDFoXRhbmRhcmRpem92YW7DqSBzIGNpZcS+b20gb3ZlcmnFpSBzdGFiaWxpdHUgb2RoYWRvdiBhIHBvc8O6ZGnFpSBwcsOtdG9tbm9zxaUgbXVsdGlrb2xpbmVhcml0eS4gVsO9c2xlZGt5IFZJRiB0ZXN0dSBwb3R2cmR6dWrDuiwgxb5lIG1lZHppIHByZW1lbm7DvW1pIHNhIG5ldnlza3l0dWplIHrDoXZhxb5uw6EgbXVsdGlrb2xpbmVhcml0YSwga2XEj8W+ZSBob2Rub3R5IFZJRiBuZXByZWtyYcSNdWrDuiBrcml0aWNrw6kgaHJhbmljZS4KCgoKQ29uZGl0aW9uYWwgTnVtYmVyIGplIAoKYGBge3J9ClggPC0gbW9kZWwubWF0cml4KG1vZGVsX2NlbnRlcmVkKVssIC0xXQpYdFggPC0gdChYKSAlKiUgWAplaWcgPC0gZWlnZW4oWHRYKQoKY29uZGl0aW9uX251bWJlciA8LSBzcXJ0KG1heChlaWckdmFsdWVzKSAvIG1pbihlaWckdmFsdWVzKSkKY29uZGl0aW9uX251bWJlcgpgYGAKTmEgcG9zw7pkZW5pZSBtdWx0aWtvbGluZWFyaXR5IGJvbCB2eXBvxI3DrXRhbsO9IGluZGV4IHBvZG1pZW5lbm9zdGkgemFsb8W+ZW7DvSBuYSB2bGFzdG7DvWNoIMSNw61zbGFjaCBtYXRpY2UgWCdYLiBWw71zbGVkbsOhIGhvZG5vdGEgaW5kZXh1IGplIG7DrXprYSBhIG5lcHJla3JhxI11amUga3JpdGlja8OpIGhyYW5pY2UsIMSNbyBwb3R2cmR6dWplLCDFvmUgbXVsdGlrb2xpbmVhcml0YSBtZWR6aSB2eXN2ZXTEvnVqw7pjaW1pIHByZW1lbm7DvW1pIHYgY2VudHJvdmFub20gbW9kZWxpIG5lcHJlZHN0YXZ1amUgesOhdmHFvm7DvSBwcm9ibMOpbS4KCgoKCiMjIEluw6Egw7pwcmF2YSBwcmVtZW5uZWosIGt0b3LDoSB6YWNob3bDoSBpbnRlcnByZXRvdmF0ZcS+bm9zxaUKCkFsdGVybmF0w612b3UgayDFoWvDoWxvdmFuaXUgcHJlbWVubsO9Y2ggamUgaWNoIMO6cHJhdmEgcHJvc3RyZWRuw61jdHZvbSB6bWVueSBqZWRub3RpZWsgdGFrLCBhYnkgc2EgamVkbm90bGl2w6kgdnlzdmV0xL51asO6Y2UgcHJlbWVubsOpIHBvaHlib3ZhbGkgdiBwb3Jvdm5hdGXEvm7DvWNoIHLDoWRvY2gsIHByacSNb20gc2EgemFjaG92w6EgaWNoIHDDtHZvZG7DoSBpbnRlcnByZXTDoWNpYS4gVGVudG8gcHLDrXN0dXAgamUgdmhvZG7DvSBuYWptw6QgdiBwcsOtcGFkb2NoLCBrZcSPIHNhIG5pZWt0b3LDqSBwcmVtZW5uw6kgdsO9cmF6bmUgbMOtxaFpYSByb3pzYWhvbSBob2Ruw7R0LgoKViBhbmFseXpvdmFuZWogZGF0YWLDoXplIGRvcHJhdm7DvWNoIG5laMO0ZCBzYSB2xaFhayB2xaFldGt5IHZ5c3ZldMS+dWrDumNlIHByZW1lbm7DqSAocG/EjWV0IHrDusSNYXN0bmVuw71jaCB2b3ppZGllbCwgxI1hcyBuZWhvZHksIG1lc2lhYyBhIGRlxYggdiB0w73FvmRuaSkgcG9oeWJ1asO6IHYgcHJpcm9kemVuZSBwb3Jvdm5hdGXEvm7DvWNoIG1pZXJrYWNoLiBaIHRvaHRvIGTDtHZvZHUgbmllIGplIHBvdHJlYm7DqSBhcGxpa292YcWlIGRvZGF0b8SNbsOpIHByZXZvZHkgamVkbm90aWVrIGEgbW9kZWwgc2kgemFjaG92w6F2YSBkb2Jyw7ogaW50ZXJwcmV0b3ZhdGXEvm5vc8WlIGFqIGJleiDEj2FsxaHDrWNoIMO6cHJhdiBwcmVtZW5uw71jaC4KCmBgYHtyfQp1ZGFqZSRudW1fdW5pdHMxMCA8LSB1ZGFqZSRudW1fdW5pdHMgLyAxMApoZWFkKHVkYWplKQoKCnVkYWplJGNyYXNoX2hvdXI2IDwtIHVkYWplJGNyYXNoX2hvdXIgLyA2CmhlYWQodWRhamUpCmBgYApOYSB6YWNob3ZhbmllIGxlcMWhZWogaW50ZXJwcmV0b3ZhdGXEvm5vc3RpIG9kaGFkbnV0w71jaCBrb2VmaWNpZW50b3YgYm9sYSBtaWVya2EgdnlicmFuw71jaCB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoIHVwcmF2ZW7DoS4gUG/EjWV0IHrDusSNYXN0bmVuw71jaCB2b3ppZGllbCBib2wgdnlqYWRyZW7DvSB2IGRlc2lhdGthY2ggYSDEjWFzIG5laG9keSB2IMWhZXPFpWhvZGlub3bDvWNoIGludGVydmFsb2NoLiBUw6F0byDDunByYXZhIG5lbWVuw60gxaF0YXRpc3RpY2vDqSB2bGFzdG5vc3RpIG1vZGVsdSwgYXbFoWFrIHVtb8W+xYh1amUgaW50dWl0w612bmVqxaFpdSBpbnRlcnByZXTDoWNpdSBvZGhhZG51dMO9Y2ggcGFyYW1ldHJvdi4KCgoKClBvdG9tIGxpbmXDoXJueSBtb2RlbCBkb3NpYWhuZSB2w71zbGVka3kKCgpgYGB7cn0KbW9kZWxfdW5pdHMxMCA8LSBsbShpbmp1cmllc190b3RhbCB+CiAgICAgICAgICAgICAgICAgICAgICBudW1fdW5pdHMxMCArCiAgICAgICAgICAgICAgICAgICAgICBjcmFzaF9ob3VyICsKICAgICAgICAgICAgICAgICAgICAgIGNyYXNoX21vbnRoICsKICAgICAgICAgICAgICAgICAgICAgIGNyYXNoX2RheV9vZl93ZWVrLAogICAgICAgICAgICAgICAgICAgIGRhdGEgPSB1ZGFqZSkKCnN1bW1hcnkobW9kZWxfdW5pdHMxMCkKCnZpZihtb2RlbF91bml0czEwKQoKYGBgCgoKa2RlIHbFoWV0a3kgcmVncmVzbsOpIGtvZWZpY2llbnR5IG1hasO6IHBvcm92bmF0ZcS+bsOpIHLDoWR5IGEgdGllxb4gVklGIGplIGFrY2VwdG92YXRlxL5uw70gdm8gdsWhZXRrw71jaCBwcsOtcGFkb2NoLiAqKkNvbmRpdGlvbmFsIG51bWJlcioqIGplIHBvdG9tIAoKTmEgemFjaG92YW5pZSBsZXDFoWVqIGludGVycHJldG92YXRlxL5ub3N0aSBvZGhhZG51dMO9Y2ggcGFyYW1ldHJvdiBib2xhIHByZW1lbm7DoSBwb8SNZXQgesO6xI1hc3RuZW7DvWNoIHZvemlkaWVsIHByZcWha8OhbG92YW7DoSBhIHZ5amFkcmVuw6EgdiBkZXNpYXRrYWNoLiBPZGhhZG51dMO9IG1vZGVsIHBvc2t5dHVqZSByb3ZuYWvDqSDFoXRhdGlzdGlja8OpIHrDoXZlcnkgYWtvIHDDtHZvZG7DoSDFoXBlY2lmaWvDoWNpYSwgcHJpxI1vbSBob2Rub3R5IFZJRiBhaiBpbmRleHUgcG9kbWllbmVub3N0aSBwb3R2cmR6dWrDuiBhYnNlbmNpdSB6w6F2YcW+bmVqIG11bHRpa29saW5lYXJpdHkgbWVkemkgdnlzdmV0xL51asO6Y2ltaSBwcmVtZW5uw71taS4KCmBgYHtyfQpYIDwtIG1vZGVsLm1hdHJpeChtb2RlbF91bml0czEwKVssIC0xXSAgIApYdFggPC0gdChYKSAlKiUgWAplaWcgPC0gZWlnZW4oWHRYKQoKY29uZGl0aW9uX251bWJlciA8LSBzcXJ0KG1heChlaWckdmFsdWVzKSAvIG1pbihlaWckdmFsdWVzKSkKY29uZGl0aW9uX251bWJlcgoKYGBgCkhvZG5vdGEgY29uZGl0aW9uIG51bWJlciB2eXBvxI3DrXRhbsOhIHogbWF0aWNlIFgnWCBqZSBuw616a2EsIMSNbyBwb3R2cmR6dWplLCDFvmUgdiBtb2RlbGkgbmllIGplIHByw610b21uw6EgesOhdmHFvm7DoSBtdWx0aWtvbGluZWFyaXRhIG1lZHppIHZ5c3ZldMS+dWrDumNpbWkgcHJlbWVubsO9bWkuIFRlbnRvIHrDoXZlciBqZSB2IHPDumxhZGUgYWogcyB2w71zbGVka2FtaSBWSUYgdGVzdHUuCgoKCgo+IFBvem7DoW1rYTogRHVtbXkgcHJlbWVubsOpIG5lxaFrw6FsdWplbWUKCmBgYHtyfQojIyMgICBvY2lzdGVuaWUgZGF0YWJhenkgb2QgbmFkYnl0b2NueWNoIC0gcHJhY292bnljaCBzdGxwY292CmxpYnJhcnkoZHBseXIpCgp1ZGFqZSA8LSB1ZGFqZSAlPiUKCiAgZHBseXI6OnNlbGVjdCgKICAgIC1udW1fdW5pdHNfYywKICAgIC1jcmFzaF9ob3VyX2MKICApCgoKCmBgYAoKCiMjIFBDQSAodm9saXRlxL5uw6kpCgpQQ0EgbsOhbSB2eXR2w6FyYSBwcmFjb3Zuw70gdmVrdG9yLCBrdG9yw70gamUgZGVmaW5vdmFuw70gYWtvIHbDocW+ZW7DvSBzw7rFpWV0IGR2b2NoIG5hbWkgxaFwZWNpZmlrb3ZhbsO9Y2gga29yZWxvdmFuw71jaCBwcmVtZW5uw71jaC4gVGVudG8gdmVrdG9yIHBvdG9tIHZ5c3R1cHVqZSBha28gdnlzdmV0xL51asO6Y2EgdmVsacSNaW5hLCB6YXRpYcS+IMSNbyB6YcSNbGVuZW7DqSBkdmUgdnlzdmV0xL51asO6Y2UgcHJlbWVubsOpIHZ5bMO6xI1pbWUgem8gem96bmFtdSByZWdyZXNvcm92LiBUw71tIHNhIHJlZHVrdWplIHBvxI1ldCB2eXN2ZXTEvnVqw7pjaWNoIHZlbGnEjcOtbiBhIG9kc3RyYcWIdWplIHNhIGFqIHByb2Jsw6ltIG11bHRpa29saW5lYXJpdHkuCgoKYGBge3J9CgoKbGlicmFyeShjYXIpCgpYX3BjYSA8LSBzY2FsZSgKICB1ZGFqZVssIGMoIm51bV91bml0cyIsICJjcmFzaF9ob3VyIiwgImNyYXNoX21vbnRoIiwgImNyYXNoX2RheV9vZl93ZWVrIildLAogIGNlbnRlciA9IFRSVUUsCiAgc2NhbGUgID0gVFJVRQopCgpwY2FfcmVzIDwtIHByY29tcChYX3BjYSkKCnN1bW1hcnkocGNhX3JlcykKCnVkYWplJFBDMSA8LSBwY2FfcmVzJHhbLCAxXQp1ZGFqZSRQQzIgPC0gcGNhX3JlcyR4WywgMl0KCm1vZGVsX3BjYTIgPC0gbG0oaW5qdXJpZXNfdG90YWwgfiBQQzEgKyBQQzIsIGRhdGEgPSB1ZGFqZSkKc3VtbWFyeShtb2RlbF9wY2EyKQoKdmlmKG1vZGVsX3BjYTIpCgpgYGAKCi0tLQoKCiMjIEhyZWJlxYhvdsOhIHJlZ3Jlc2lhIChSaWRnZSBSZWdyZXNzaW9uIC0gdm9saXRlxL5uw6kpCgpIcmViZcWIb3bDoSByZWdyZXNpYSBqZSBtb2RpZmlrw6FjaWEgcmVncmVzaWUsIGt0b3LDoSB6YXbDoWR6YSBwZXJ0dXJiw6FjaWUgZG8gbWF0aWNlICRcbWF0aGJmIFheVCBcbWF0aGJmIFgkIHRhaywgYWJ5IHpuw63FvmlsYSBkw7RzbGVka3kgbXVsdGlrb2xpbmVhcml0eS4gVHJlYmEgYWxlIHVwb3pvcm5pxaUsIMW+ZSBvZGhhZG92YW7DqSByZWdyZXNuw6kga29lZmljaWVudHkgc8O6IHNrcmVzbGVuw6kuIFBlcnR1cmLDoWNpYSB2eXplcsOhIG5hc2xlZG92bmUKCiQkKFxtYXRoYmYgWF5UIFxtYXRoYmYgWCArIFxsYW1iZGEgXG1hdGhiZiBJKSQkCgpWIHRvbXRvIGtyb2t1IHNpIHZ5cMOtxaFlbWUgdsO9c2xlZGt5IG9kaGFkb3YgcmVncmVzbsO9Y2gga29lZmljaWVudG92IHMgbWVuaWFjaW1pIHNhIHBhcmFtZXRyYW1pICRsYW1iZGEkIHRhaywgYWJ5IHNtZSB6w61za2xhbGkgdXLEjWl0w7ogcHJlZHN0YXZ1IG8gxI3DrXNlbG5vbSByw6FkZSBwcnZrb3YsIGt0b3LDqSBvYnNhaHVqZS4gTmEgesOha2xhZGUgdG9obyBzYSBwb3RvbSByb3pob2RuZW1lIHByZSBuZWpha8O6IHZvxL5idSBwYXJhbWV0cmEgJFxsYW1iZGEkLgoKPCEtLQpgYGB7cn0KbGlicmFyeShNQVNTKQoKWCA8LSBhcy5tYXRyaXgodWRhamVbLCBjKCJCTUkiLCAiR0RQIiwgIlNjaG9vbGluZyIpXSkKeSA8LSB1ZGFqZSRMaWZlLmV4cGVjdGFuY3kKbGFtYmRhIDwtIDUwMDAwCkEgPC0gdChYKSUqJVgKQUludiA8LSBzb2x2ZShBKQpBbGFtIDwtICh0KFgpJSolWCArIGxhbWJkYSAqIGRpYWcoMykpCkFsYW1JbnYgPC0gc29sdmUoQWxhbSkKcHJpbnQocGFzdGUoImxhbWJkYSAiLGxhbWJkYSkpCnByaW50KHBhc3RlKCJBIikpCnByaW50KEEpCnByaW50KHBhc3RlKCJBbGFtIikpCnByaW50KEFsYW0pCnByaW50KHBhc3RlKCJBSW52IikpCnByaW50KEFJbnYpCnByaW50KHBhc3RlKCJBbGFtSW52IikpCnByaW50KEFsYW1JbnYpCnByaW50KCJlaWdlbnZhbHVlcyBBIikKZWlnZW4oQSkkdmFsdWVzCnByaW50KCJlaWdlbnZhbHVlcyBBbGFtIikKZWlnZW4oQWxhbSkkdmFsdWVzCmBgYAotLT4KCk5hc3Rhdm92YW5pZSByw7R6bnljaCBob2Ruw7R0ICRcbGFtYmRhJCBqZSBwcmVkbWV0b20gaGxixaFlaiBhbmFsw716eSwgdGVudG8gcHJlaMS+YWQgamUgbGVuIGplaiDEjWFzxaVvdS4gCgpgYGB7cn0KbGlicmFyeShNQVNTKQoKcmlkZ2VfZml0IDwtIGxtLnJpZGdlKAogIGluanVyaWVzX3RvdGFsIH4gbnVtX3VuaXRzICsgY3Jhc2hfaG91ciArIGNyYXNoX21vbnRoICsgY3Jhc2hfZGF5X29mX3dlZWssCiAgZGF0YSA9IHVkYWplLAogIGxhbWJkYSA9IHNlcSgwLCAxMCwgMSkKKQoKcmlkZ2VfZml0CgoKYGBgCgoKCiMgMTAuIFpocm51dGllCi0gTXVsdGlrb2xpbmVhcml0YSBuZXNww7Rzb2J1amUgc2tyZXNsZW5pZSAoYmlhcykgb2RoYWRvdiByZWdyZXNuw71jaCBrb2VmaWNpZW50b3YsIGF2xaFhayB6dnnFoXVqZSBpY2ggxaF0YW5kYXJkbsOpIG9kY2jDvWxreSBhIHpuacW+dWplIMWhdGF0aXN0aWNrw7ogdsO9em5hbW5vc8WlIGplZG5vdGxpdsO9Y2ggcmVncmVzb3Jvdi4KLSBEaWFnbm9zdGlrdSBtdWx0aWtvbGluZWFyaXR5IHVtb8W+xYh1asO6IHVrYXpvdmF0ZWxlIGFrbyBrb3JlbGHEjW7DoSBtYXRpY2EsIFZhcmlhbmNlIEluZmxhdGlvbiBGYWN0b3IgKFZJRikgYSBDb25kaXRpb24gTnVtYmVyLgotIE1lZHppIHrDoWtsYWRuw6kgcmllxaFlbmlhIG11bHRpa29saW5lYXJpdHkgcGF0csOtIHZ5bmVjaGFuaWUgcHJlbWVubmVqIGFsZWJvIGNlbnRyb3ZhbmllIGEgxaF0YW5kYXJkaXrDoWNpYSBwcmVtZW5uw71jaC4gUG9rcm/EjWlsZWrFoWllIG1ldMOzZHksIGFrbyBQQ0EgYWxlYm8gaHJlYmXFiG92w6EgcmVncmVzaWEsIHZ5xb5hZHVqw7ogaGxixaFpZSBtZXRvZGlja8OpIHpuYWxvc3RpLCBhIHByZXRvIHPDuiB2IHRlanRvIMO6bG9oZSB1dmVkZW7DqSBsZW4gaWx1c3RyYcSNbmUuCgoKUHJlZGxvxb5lbsOhIGFuYWzDvXphIHNhIHphbWVyYWxhIG5hIGlkZW50aWZpa8OhY2l1IGEgcG9zw7pkZW5pZSBtdWx0aWtvbGluZWFyaXR5IHYgcmVncmVzbm9tIG1vZGVsaSB2eXN2ZXTEvnVqw7pjb20gcG/EjWV0IHpyYW5lbsOtIHByaSBkb3ByYXZuw71jaCBuZWhvZMOhY2ggbmEgesOha2xhZGUgdnlicmFuw71jaCBjaGFyYWt0ZXJpc3TDrWsgbmVob2R5LiBOYSBkaWFnbm9zdGlrdSBtdWx0aWtvbGluZWFyaXR5IGJvbGkgcG91xb5pdMOpIHZpYWNlcsOpIG7DoXN0cm9qZSwgdnLDoXRhbmUga29yZWxhxI1uZWogbWF0aWNlLCBWYXJpYW5jZSBJbmZsYXRpb24gRmFjdG9yIChWSUYpIGEgaW5kZXh1IHBvZG1pZW5lbm9zdGkgKENvbmRpdGlvbiBOdW1iZXIpLgoKVsO9c2xlZGt5IHVrw6F6YWxpLCDFvmUgbWVkemkgdnlzdmV0xL51asO6Y2ltaSBwcmVtZW5uw71taSBzYSBuZXZ5c2t5dHVqw7ogc2lsbsOpIGxpbmXDoXJuZSB6w6F2aXNsb3N0aSBhIGhvZG5vdHkgVklGIHNhIHBvaHlidWrDuiBobGJva28gcG9kIGtyaXRpY2vDvW1pIGhyYW5pY2FtaS4gSG9kbm90YSBDb25kaXRpb24gTnVtYmVyIG5hem5hxI1pbGEgbGVuIG1pZXJudSBtaWVydSBtdWx0aWtvbGluZWFyaXR5LCBrdG9yw6EgbmVwcmVkc3RhdnVqZSB6w6F2YcW+bsO9IHByb2Jsw6ltIHByZSBpbnRlcnByZXTDoWNpdSByZWdyZXNuw6lobyBtb2RlbHUuIERvZGF0b8SNbsOpIMO6cHJhdnkgbW9kZWx1LCBha28gdnluZWNoYW5pZSBwcmVtZW5uw71jaCDEjWkgY2VudHJvdmFuaWUgYSDDunByYXZhIG1pZXJvaywgcG90dnJkaWxpIHN0YWJpbGl0dSBvZGhhZG51dMO9Y2ggcmVncmVzbsO9Y2gga29lZmljaWVudG92LgoKTmEgesOha2xhZGUgdnlrb25hbmVqIGFuYWzDvXp5IG1vxb5ubyBrb27FoXRhdG92YcWlLCDFvmUgbXVsdGlrb2xpbmVhcml0YSB2IGFuYWx5em92YW5vbSBtb2RlbGkgbmVwcmVkc3RhdnVqZSB2w716bmFtbsO9IHByb2Jsw6ltIGEgb2RoYWRudXTDqSByZWdyZXNuw6kgdnrFpWFoeSBzw7ogc3RhYmlsbsOpIGEgaW50ZXJwcmV0b3ZhdGXEvm7DqS4gWnZvbGVuw70gcmVncmVzbsO9IG1vZGVsIGplIHByZXRvIHZob2Ruw70gbmEgYW5hbMO9enUgdnrFpWFob3YgbWVkemkgY2hhcmFrdGVyaXN0aWthbWkgZG9wcmF2bsO9Y2ggbmVow7RkIGEgcG/EjXRvbSB6cmFuZW7DrS4KCi0tLQoKCg==