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:
- Nespôsobuje skreslené (biased) odhady
koeficientov
- 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.
- Odhadované regresné koeficienty sú nestabilné - pri malej zmene
údajov sa sa prudko menia koeficienty ako aj ich znamienka.
- 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
- < 10 → nízka multikolinearita,
- 10–30 → mierna,
- 30–100 → silná,
- 100 → veľmi vážna
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
- Multikolinearita nespôsobuje skreslenie (bias) odhadov regresných
koeficientov, avšak zvyšuje ich štandardné odchýlky a znižuje
štatistickú významnosť jednotlivých regresorov.
- Diagnostiku multikolinearity umožňujú ukazovatele ako korelačná
matica, Variance Inflation Factor (VIF) a Condition Number.
- Medzi základné riešenia multikolinearity patrí vynechanie premennej
alebo centrovanie a štandardizácia premenných. Pokročilejšie metódy, ako
PCA alebo hrebeňová regresia, vyžadujú hlbšie metodické znalosti, a
preto sú v tejto úlohe uvedené len ilustračne.
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==