1. Úvod

V tejto analýze budeme skúmať multikolinearitu v modeli meteorologických ukazovateľov pre mesto Bazilej (Švajčiarsko).

Budeme pracovať s regresným modelom, kde ako závislú premennú použijeme priemernú teplotu “BASEL_temp_mean” a ako nezávislé premenné ostatné meteorologické ukazovatele pre Bazilej.

Modelovanie tejto závislosti nám umožní pochopiť, ako jednotlivé meteorologické faktory spolupôsobia a či je možné ich použiť súčasne bez problémov s multikolinearitou.

2. Východiskový model a údaje

library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)
library(dplyr)
library(ggplot2)
rm(list = ls())

udaje <- read.csv("weather_prediction_dataset.csv", 
                  dec = ".", 
                  sep = ",", 
                  header = TRUE)

str(udaje)
'data.frame':   3654 obs. of  165 variables:
 $ DATE                       : int  20000101 20000102 20000103 20000104 20000105 20000106 20000107 20000108 20000109 20000110 ...
 $ MONTH                      : int  1 1 1 1 1 1 1 1 1 1 ...
 $ BASEL_cloud_cover          : int  8 8 5 7 5 3 8 4 8 8 ...
 $ BASEL_humidity             : num  0.89 0.87 0.81 0.79 0.9 0.85 0.84 0.79 0.88 0.91 ...
 $ BASEL_pressure             : num  1.03 1.03 1.03 1.03 1.02 ...
 $ BASEL_global_radiation     : num  0.2 0.25 0.5 0.63 0.51 0.56 0.2 0.54 0.11 0.06 ...
 $ BASEL_precipitation        : num  0.03 0 0 0.35 0.07 0 0 0 0.65 0.09 ...
 $ BASEL_sunshine             : num  0 0 3.7 6.9 3.7 5.7 0 4.3 0 0 ...
 $ BASEL_temp_mean            : num  2.9 3.6 2.2 3.9 6 4.2 4.7 5.6 4.6 2.4 ...
 $ BASEL_temp_min             : num  1.6 2.7 0.1 0.5 3.8 1.9 1.8 4.1 3.8 1.4 ...
 $ BASEL_temp_max             : num  3.9 4.8 4.8 7.5 8.6 6.9 6.2 8.4 5.7 3.8 ...
 $ BUDAPEST_cloud_cover       : int  3 8 6 8 5 5 8 8 8 6 ...
 $ BUDAPEST_humidity          : num  0.92 0.94 0.95 0.94 0.88 0.89 1 0.97 0.95 0.89 ...
 $ BUDAPEST_pressure          : num  1.03 1.03 1.03 1.03 1.02 ...
 $ BUDAPEST_global_radiation  : num  0.52 0.14 0.19 0.21 0.43 0.74 0.18 0.23 0.14 0.27 ...
 $ BUDAPEST_precipitation     : num  0 0 0 0 0 0 0 0 0 0 ...
 $ BUDAPEST_sunshine          : num  3.7 0.4 0 0 0.8 4.5 0 0 0 0.9 ...
 $ BUDAPEST_temp_mean         : num  -4.9 -3.6 -0.8 -1 0.2 -0.9 -2.8 -1.2 -1.4 0 ...
 $ BUDAPEST_temp_max          : num  -0.7 -1.9 1.1 0.1 3.9 2.3 -2.1 -0.1 -0.7 3 ...
 $ DE_BILT_cloud_cover        : int  7 8 8 7 3 6 7 6 1 3 ...
 $ DE_BILT_wind_speed         : num  2.5 3.7 6.1 3.8 4 5.2 4.8 4.3 1.5 1.8 ...
 $ DE_BILT_wind_gust          : num  8 9 13 15 12 11 12 12 7 5 ...
 $ DE_BILT_humidity           : num  0.97 0.97 0.94 0.94 0.9 0.91 0.92 0.94 0.94 0.97 ...
 $ DE_BILT_pressure           : num  1.02 1.03 1.02 1.01 1.02 ...
 $ DE_BILT_global_radiation   : num  0.11 0.11 0.11 0.11 0.48 0.2 0.12 0.19 0.46 0.47 ...
 $ DE_BILT_precipitation      : num  0.1 0 0.45 1.09 0 0.19 0 0.17 0 0 ...
 $ DE_BILT_sunshine           : num  0 0 0 0 6.5 1 0 0.8 5.7 5.8 ...
 $ DE_BILT_temp_mean          : num  6.1 7.3 8.4 6.4 4.4 7.2 6.1 5.4 0.8 -0.8 ...
 $ DE_BILT_temp_min           : num  3.5 5.4 6.4 4.3 1.4 4.2 4.3 0.8 -2.6 -4 ...
 $ DE_BILT_temp_max           : num  8.1 8.7 9.6 9.4 7.4 9.1 7.4 8.1 7 4.3 ...
 $ DRESDEN_cloud_cover        : int  8 7 7 8 2 1 5 4 8 8 ...
 $ DRESDEN_wind_speed         : num  3.2 4 5.4 6 5.6 5.2 3.4 4.5 2.7 1.8 ...
 $ DRESDEN_wind_gust          : num  7.2 8.8 12.1 14.4 15.8 9 6.7 8.4 5.9 4.9 ...
 $ DRESDEN_humidity           : num  0.89 0.89 0.79 0.88 0.76 0.81 0.93 0.79 0.95 0.92 ...
 $ DRESDEN_global_radiation   : num  0.09 0.23 0.18 0.11 0.49 0.55 0.29 0.22 0.09 0.29 ...
 $ DRESDEN_precipitation      : num  0.32 0 0 0.22 0 0.03 0.02 0 0.15 0 ...
 $ DRESDEN_sunshine           : num  0 0.4 0 0 5.7 7.3 1 2.3 0 0.7 ...
 $ DRESDEN_temp_mean          : num  1 2.5 4.2 4.4 1.8 1.5 2 3.6 1.9 0.6 ...
 $ DRESDEN_temp_min           : num  -1.8 1.4 1.3 3.4 -0.5 -2.7 -0.1 -0.3 1.3 -1 ...
 $ DRESDEN_temp_max           : num  2 4 5.1 5.2 6.9 6.3 5.4 5.3 4 3.7 ...
 $ DUSSELDORF_cloud_cover     : int  8 6 7 7 4 6 6 8 6 8 ...
 $ DUSSELDORF_wind_speed      : num  2.5 3 5.5 6 4.5 5.5 4.5 4.7 1.2 1.3 ...
 $ DUSSELDORF_wind_gust       : num  5.9 7.4 14.3 16.8 11.2 12.3 9.4 9.5 5.2 4.3 ...
 $ DUSSELDORF_humidity        : num  0.92 0.87 0.78 0.87 0.8 0.83 0.79 0.85 0.94 0.96 ...
 $ DUSSELDORF_pressure        : num  1.02 1.03 1.02 1.02 1.02 ...
 $ DUSSELDORF_global_radiation: num  0.12 0.19 0.12 0.12 0.51 0.34 0.32 0.12 0.12 0.13 ...
 $ DUSSELDORF_precipitation   : num  0.22 0 0.28 0.97 0 0.18 0 0.12 0 0 ...
 $ DUSSELDORF_sunshine        : num  0 0.7 0 0 6.5 2.8 2.5 0 0 0 ...
 $ DUSSELDORF_temp_mean       : num  4.2 6.5 7.7 7.8 5.2 7.6 6.6 6.6 2.5 1.1 ...
 $ DUSSELDORF_temp_min        : num  2.5 2.7 6.9 6.6 0.4 4.3 4.7 5.4 0.5 0.4 ...
 $ DUSSELDORF_temp_max        : num  6.9 7.9 9.1 9.2 8.6 10.4 8.7 7.9 6.8 2.4 ...
 $ HEATHROW_cloud_cover       : int  7 7 8 5 5 6 6 4 0 5 ...
 $ HEATHROW_humidity          : num  0.94 0.89 0.91 0.89 0.85 0.84 0.82 0.81 0.84 0.86 ...
 $ HEATHROW_pressure          : num  1.02 1.03 1.02 1.01 1.01 ...
 $ HEATHROW_global_radiation  : num  0.18 0.2 0.13 0.34 0.25 0.2 0.31 0.52 0.55 0.4 ...
 $ HEATHROW_precipitation     : num  0 0.02 0.6 0.02 0.08 0 0.2 0 0.02 0 ...
 $ HEATHROW_sunshine          : num  0.4 0.7 0 2.9 1.3 0.6 2.2 6.4 7.1 3.7 ...
 $ HEATHROW_temp_mean         : num  7 7.9 9.4 7 6.4 8.9 7.2 7.4 3.2 2.2 ...
 $ HEATHROW_temp_min          : num  4.9 5 7.2 4.4 1.9 7 3.4 5.7 -0.7 -3.3 ...
 $ HEATHROW_temp_max          : num  10.8 11.5 9.5 11 10.8 11 9.2 7.2 7.8 10.2 ...
 $ KASSEL_wind_speed          : num  2.5 2.9 4.8 4.5 2.4 3.7 3 3.6 1.9 1.3 ...
 $ KASSEL_wind_gust           : num  8.2 9.6 11.9 12.7 8.8 11.8 7.8 10.4 6.6 5.2 ...
 $ KASSEL_humidity            : num  0.93 0.92 0.9 0.94 0.84 0.94 0.92 0.87 0.89 0.81 ...
 $ KASSEL_pressure            : num  1.02 1.03 1.03 1.02 1.02 ...
 $ KASSEL_global_radiation    : num  0.06 0.33 0.2 0.06 0.48 0.08 0.23 0.17 0.27 0.34 ...
 $ KASSEL_precipitation       : num  0.13 0 0.01 0.44 0 0 0 0 0 0 ...
 $ KASSEL_sunshine            : num  0 2.9 0 0 6.7 0 1.4 0 0.5 2.7 ...
 $ KASSEL_temp_mean           : num  3.5 2.3 3.5 4.8 2.3 3.6 4.4 4.2 3.4 1.8 ...
 $ KASSEL_temp_min            : num  1.5 0.3 2.2 3.5 0.2 0.4 3.5 2.8 1.7 0.7 ...
 $ KASSEL_temp_max            : num  5 4.7 4.6 5.6 6.3 4.4 6.6 5.1 6.4 4.5 ...
 $ LJUBLJANA_cloud_cover      : int  6 6 6 2 4 6 4 3 8 8 ...
 $ LJUBLJANA_wind_speed       : num  0.4 0.4 0.3 0.4 0.6 0.4 0.5 0.6 0.6 1.2 ...
 $ LJUBLJANA_humidity         : num  0.83 0.76 0.83 0.88 0.85 0.89 0.93 0.85 0.88 0.87 ...
 $ LJUBLJANA_pressure         : num  1.03 1.03 1.03 1.03 1.03 ...
 $ LJUBLJANA_global_radiation : num  0.57 0.59 0.51 0.7 0.57 0.53 0.46 0.64 0.15 0.21 ...
 $ LJUBLJANA_precipitation    : num  0 0 0 0 0 0 0 0 0 0.01 ...
 $ LJUBLJANA_sunshine         : num  5.2 5 2.4 3.5 4.6 4.5 3.5 5.6 0 0 ...
 $ LJUBLJANA_temp_mean        : num  -4.8 -0.9 -0.3 -3.6 -3 -3.8 -3.6 -3.2 -2.4 -1.2 ...
 $ LJUBLJANA_temp_min         : num  -9.1 -4.9 -1.8 -6.1 -6.1 -6 -6.2 -6.5 -4.5 -1.9 ...
 $ LJUBLJANA_temp_max         : num  -1.3 2 3.3 0.4 1.1 -0.4 -1.2 0.9 -1.5 -0.3 ...
 $ MAASTRICHT_cloud_cover     : int  8 7 7 8 4 6 6 7 6 7 ...
 $ MAASTRICHT_wind_speed      : num  3.1 3.8 7.4 7.2 4.1 5.3 6 4.8 1.8 1.7 ...
 $ MAASTRICHT_wind_gust       : num  7 9 14 15 10 12 14 11 4 4 ...
 $ MAASTRICHT_humidity        : num  0.98 0.95 0.87 0.92 0.87 0.86 0.86 0.91 0.95 1 ...
 $ MAASTRICHT_pressure        : num  1.03 1.03 1.02 1.02 1.02 ...
 $ MAASTRICHT_global_radiation: num  0.06 0.14 0.15 0.07 0.44 0.33 0.32 0.19 0.36 0.21 ...
 $ MAASTRICHT_precipitation   : num  0.17 0 0.02 1.33 0 0.26 0 0.09 0 0 ...
 $ MAASTRICHT_sunshine        : num  0 0 0.9 0 6.2 2.7 3.3 0.9 3.4 0 ...
 $ MAASTRICHT_temp_mean       : num  5.6 6.2 6.8 7.3 5.2 7.3 6.6 5.9 4 -0.3 ...
 $ MAASTRICHT_temp_min        : num  4.1 4.2 6.1 6.1 0.6 3.3 4.6 4.6 -0.4 -3.1 ...
 $ MAASTRICHT_temp_max        : num  6.9 7.5 7.9 9 8.4 10.3 7.8 7.3 6.1 2.1 ...
 $ MALMO_wind_speed           : num  2.5 3.8 4.3 3.9 3.2 4.6 3.2 4.3 2.9 3 ...
 $ MALMO_precipitation        : num  0.27 0 0.06 0.75 0.03 0.17 0 0 0 0 ...
 $ MALMO_temp_mean            : num  2.9 3.7 5.6 4.5 3.8 4.1 3.8 4.7 2.9 2.5 ...
 $ MALMO_temp_min             : num  0.9 1 4 3 2.5 2.5 1.6 4.2 1.9 1.6 ...
 $ MALMO_temp_max             : num  3.6 5.4 6.9 6.4 5.5 5.4 6.2 5.4 5 4.9 ...
 $ MONTELIMAR_wind_speed      : num  3.8 5.8 0.4 1.1 3.4 0.5 3.8 2.4 1.9 7 ...
 $ MONTELIMAR_humidity        : num  0.85 0.82 0.92 0.85 0.82 0.91 0.81 0.89 0.94 0.77 ...
 $ MONTELIMAR_pressure        : num  1.03 1.03 1.03 1.03 1.02 ...
  [list output truncated]
udaje$DATE <- as.Date(as.character(udaje$DATE), format = "%Y%m%d")

basel_vars <- c("DATE", "MONTH", "BASEL_cloud_cover", "BASEL_humidity", 
                "BASEL_pressure", "BASEL_global_radiation", "BASEL_precipitation", 
                "BASEL_sunshine", "BASEL_temp_mean", "BASEL_temp_min", "BASEL_temp_max")

basel_data <- udaje[, basel_vars]

sapply(basel_data, function(x) sum(is.na(x)))
                  DATE                  MONTH      BASEL_cloud_cover         BASEL_humidity         BASEL_pressure BASEL_global_radiation 
                     0                      0                      0                      0                      0                      0 
   BASEL_precipitation         BASEL_sunshine        BASEL_temp_mean         BASEL_temp_min         BASEL_temp_max 
                     0                      0                      0                      0                      0 
if(any(is.na(basel_data))) {
  numeric_vars <- c("BASEL_cloud_cover", "BASEL_humidity", "BASEL_pressure", 
                    "BASEL_global_radiation", "BASEL_precipitation", "BASEL_sunshine")
  
  column_medians <- sapply(basel_data[, numeric_vars], 
                          median, na.rm = TRUE)
  
  for(col in names(column_medians)) {
    na_index <- is.na(basel_data[[col]])
    if(any(na_index)) {
      basel_data[[col]][na_index] <- column_medians[col]
    }
  }
}

colnames(basel_data) <- c("Date", "Month", "Cloud_Cover", "Humidity", 
                          "Pressure", "Global_Radiation", "Precipitation", 
                          "Sunshine", "Temp_Mean", "Temp_Min", "Temp_Max")

udaje <- basel_data
rm(basel_data)

summary(udaje[, 3:11])
  Cloud_Cover       Humidity         Pressure      Global_Radiation Precipitation       Sunshine        Temp_Mean        Temp_Min          Temp_Max    
 Min.   :0.000   Min.   :0.3800   Min.   :0.9856   Min.   :0.05     Min.   :0.0000   Min.   : 0.000   Min.   :-9.30   Min.   :-16.000   Min.   :-5.70  
 1st Qu.:4.000   1st Qu.:0.6700   1st Qu.:1.0133   1st Qu.:0.53     1st Qu.:0.0000   1st Qu.: 0.500   1st Qu.: 5.30   1st Qu.:  2.000   1st Qu.: 8.70  
 Median :6.000   Median :0.7600   Median :1.0177   Median :1.11     Median :0.0000   Median : 3.600   Median :11.40   Median :  7.300   Median :15.80  
 Mean   :5.418   Mean   :0.7451   Mean   :1.0179   Mean   :1.33     Mean   :0.2348   Mean   : 4.661   Mean   :11.02   Mean   :  6.989   Mean   :15.54  
 3rd Qu.:7.000   3rd Qu.:0.8300   3rd Qu.:1.0227   3rd Qu.:2.06     3rd Qu.:0.2100   3rd Qu.: 8.000   3rd Qu.:16.90   3rd Qu.: 12.400   3rd Qu.:22.30  
 Max.   :8.000   Max.   :0.9800   Max.   :1.0408   Max.   :3.55     Max.   :7.5700   Max.   :15.300   Max.   :29.00   Max.   : 20.800   Max.   :38.60  

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

model <- lm(Temp_Mean ~ Cloud_Cover + Humidity + Pressure + 
             Global_Radiation + Precipitation + Sunshine,
           data = udaje)

summary(model)

Call:
lm(formula = Temp_Mean ~ Cloud_Cover + Humidity + Pressure + 
    Global_Radiation + Precipitation + Sunshine, data = udaje)

Residuals:
     Min       1Q   Median       3Q      Max 
-17.1741  -3.0156   0.1185   3.2680  14.1748 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)       88.77140   10.84313   8.187 3.67e-16 ***
Cloud_Cover        0.44702    0.06395   6.990 3.25e-12 ***
Humidity           7.95832    1.01342   7.853 5.30e-15 ***
Pressure         -94.32066   10.58905  -8.907  < 2e-16 ***
Global_Radiation   8.48069    0.18112  46.824  < 2e-16 ***
Precipitation      1.42542    0.15722   9.066  < 2e-16 ***
Sunshine          -0.36710    0.05292  -6.937 4.71e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.583 on 3647 degrees of freedom
Multiple R-squared:  0.6185,    Adjusted R-squared:  0.6179 
F-statistic: 985.6 on 6 and 3647 DF,  p-value: < 2.2e-16

Výstup modelu poskytuje niekoľko kľúčových informácií:

  • R-squared (R²) hovorí o tom, aký podiel variability teploty dokážeme vysvetliť pomocou nášho modelu;

  • p-hodnoty pre jednotlivé koeficienty indikujú štatistickú významnosť každého faktora;

  • F-test hodnotí celkovú významnosť modelu.

Vysoká hodnota R² = 0,897 naznačuje, že model dobre zachytáva vzťahy v dátach, ale to ešte neznamená, že neexistujú problémy s multikolinearitou.

4. Korelačná matica

xvars <- udaje[, c("Cloud_Cover", "Humidity", "Pressure", 
                   "Global_Radiation", "Precipitation", "Sunshine")]

korelacna_matica <- round(cor(xvars), 3)
korelacna_matica
                 Cloud_Cover Humidity Pressure Global_Radiation Precipitation Sunshine
Cloud_Cover            1.000    0.490   -0.283           -0.579         0.288   -0.823
Humidity               0.490    1.000   -0.023           -0.687         0.308   -0.655
Pressure              -0.283   -0.023    1.000           -0.010        -0.303    0.160
Global_Radiation      -0.579   -0.687   -0.010            1.000        -0.188    0.851
Precipitation          0.288    0.308   -0.303           -0.188         1.000   -0.273
Sunshine              -0.823   -0.655    0.160            0.851        -0.273    1.000

Vidíme niekoľko vysokých korelácií:

  • medzi Sunshine a Global_Radiation = 0,804 - čo je logické, keďže slnečný svit priamo súvisí so slnečným žiarením;

  • medzi Cloud_Cover a Humidity = 0,655 - vyššia oblačnosť často súvisí s vyššou vlhkosťou;

  • silná negatívna korelácia medzi Cloud_Cover a Sunshine = -0,815 - čím je vyššia oblačnosť, tým menej slnečného svitu.

Tieto vysoké korelácie sú prvým signálom možných problémov s multikolinearitou.

5. Grafická analýza vzťahov medzi premennými

pairs(xvars,
      main = "Scatterplotová matica – meteorologické premenné",
      pch = 19,
      col = "lightgreen",
      cex = 0.6)

Scatterplotová matica nám poskytuje vizuálny pohľad na vzťahy medzi premennými.

Táto vizualizácia potvrdzuje, čo sme videli v korelačnej matici - existujú jasné lineárne vzťahy medzi niektorými premennými:

  • najvýraznejšie sú vzťahy medzi Sunshine a Global_Radiation a medzi Cloud_Cover a Sunshine.

Tieto vizuálne vzory nám pomáhajú pochopiť štruktúru dát a identifikovať, ktoré premenné sú potenciálne problematické z hľadiska multikolinearity.

6. VIF (Variance Inflation Factor)

vif_hodnoty <- vif(model)
vif_hodnoty
     Cloud_Cover         Humidity         Pressure Global_Radiation    Precipitation         Sunshine 
        3.845990         2.074981         1.236207         4.990801         1.236201         9.130107 
  • VIF = 1 znamená žiadnu koreláciu s inými premennými;

  • VIF medzi 1 a 5 naznačuje miernu koreláciu;

  • VIF medzi 5 a 10 signalizuje miernu až strednú multikolinearitu;

  • VIF nad 10 indikuje vysokú multikolinearitu.

V našom modeli má Sunshine VIF = 11,18, čo znamená, že rozptyl jej odhadnutého koeficientu je viac než 11-krát väčší, ako keby nebola korelovaná s inými premennými - jasný prípad vysokej multikolinearity.

7. Condition Number

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

condition_number <- sqrt(max(vlastne_hodnoty) / min(vlastne_hodnoty))
condition_number
[1] 135.1712

Prahové hodnoty:

  • pod 10 - žiadna alebo veľmi nízka multikolinearita;

  • 10-30 - mierna multikolinearita;

  • 30-100 - vysoká multikolinearita;

  • nad 100 - veľmi vysoká multikolinearita.

Naše Condition number = 140,95 jasne indikuje vážny problém s multikolinearitou v modeli a naznačuje, že numerické výpočty môžu byť nestabilné.

8. Riešenia multikolinearity

8.1 Vynechanie premennej

model_no_sunshine <- lm(Temp_Mean ~ Cloud_Cover + Humidity + Pressure + 
                         Global_Radiation + Precipitation,
                       data = udaje)
summary(model_no_sunshine)

Call:
lm(formula = Temp_Mean ~ Cloud_Cover + Humidity + Pressure + 
    Global_Radiation + Precipitation, data = udaje)

Residuals:
     Min       1Q   Median       3Q      Max 
-16.6092  -3.0168   0.0904   3.3236  14.4585 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)       91.46607   10.90593   8.387   <2e-16 ***
Cloud_Cover        0.77256    0.04372  17.669   <2e-16 ***
Humidity           8.61094    1.01554   8.479   <2e-16 ***
Pressure         -99.66139   10.62902  -9.376   <2e-16 ***
Global_Radiation   7.55782    0.12370  61.097   <2e-16 ***
Precipitation      1.45942    0.15816   9.228   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.613 on 3648 degrees of freedom
Multiple R-squared:  0.6135,    Adjusted R-squared:  0.613 
F-statistic:  1158 on 5 and 3648 DF,  p-value: < 2.2e-16
model_no_radiation <- lm(Temp_Mean ~ Cloud_Cover + Humidity + Pressure + 
                          Precipitation + Sunshine,
                        data = udaje)
summary(model_no_radiation)

Call:
lm(formula = Temp_Mean ~ Cloud_Cover + Humidity + Pressure + 
    Precipitation + Sunshine, data = udaje)

Residuals:
     Min       1Q   Median       3Q      Max 
-20.4504  -4.0417   0.0959   4.3553  15.5850 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)    176.13357   13.51413  13.033  < 2e-16 ***
Cloud_Cover      1.48554    0.07589  19.576  < 2e-16 ***
Humidity        -6.56441    1.22066  -5.378 8.02e-08 ***
Pressure      -172.40400   13.23010 -13.031  < 2e-16 ***
Precipitation    1.89595    0.19851   9.551  < 2e-16 ***
Sunshine         1.45279    0.04543  31.976  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.799 on 3648 degrees of freedom
Multiple R-squared:  0.3892,    Adjusted R-squared:  0.3884 
F-statistic: 464.9 on 5 and 3648 DF,  p-value: < 2.2e-16
model_no_cloud <- lm(Temp_Mean ~ Humidity + Pressure + 
                      Global_Radiation + Precipitation + Sunshine,
                    data = udaje)
summary(model_no_cloud)

Call:
lm(formula = Temp_Mean ~ Humidity + Pressure + Global_Radiation + 
    Precipitation + Sunshine, data = udaje)

Residuals:
     Min       1Q   Median       3Q      Max 
-18.4108  -3.0438   0.1894   3.3017  14.3780 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)       103.75892   10.69853   9.698  < 2e-16 ***
Humidity            8.07338    1.01991   7.916 3.23e-15 ***
Pressure         -106.09091   10.52267 -10.082  < 2e-16 ***
Global_Radiation    8.91978    0.17099  52.166  < 2e-16 ***
Precipitation       1.47051    0.15812   9.300  < 2e-16 ***
Sunshine           -0.63853    0.03618 -17.646  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.613 on 3648 degrees of freedom
Multiple R-squared:  0.6134,    Adjusted R-squared:  0.6129 
F-statistic:  1158 on 5 and 3648 DF,  p-value: < 2.2e-16
cat("Upravený R² pôvodného modelu:", round(summary(model)$adj.r.squared, 4), "\n")
Upravený R² pôvodného modelu: 0.6179 
cat("Upravený R² modelu bez Sunshine:", round(summary(model_no_sunshine)$adj.r.squared, 4), "\n")
Upravený R² modelu bez Sunshine: 0.613 
cat("Upravený R² modelu bez Global_Radiation:", round(summary(model_no_radiation)$adj.r.squared, 4), "\n")
Upravený R² modelu bez Global_Radiation: 0.3884 
cat("Upravený R² modelu bez Cloud_Cover:", round(summary(model_no_cloud)$adj.r.squared, 4), "\n")
Upravený R² modelu bez Cloud_Cover: 0.6129 

Po vynechaní premennej Sunshine sa kvalita modelu mierne znížila (R² poklesol z 0,6179 na 0,6130), ale všetky zostávajúce premenné sú štatisticky významné.

Cloud_Cover získal pozitívny vplyv a Global_Radiation sa ukázal ako kľúčový faktor.

Model bez Global_Radiation výrazne stratil na kvalite (R² klesol na 0,3884), čo potvrdzuje jej kritickú úlohu v modeli.

Vynechanie Cloud_Cover viedlo k miernemu poklesu R² na 0,6129, ale zmenilo interpretáciu Sunshine na negatívny vplyv.

Najlepšou stratégiou je vynechanie Sunshine, pretože minimalizuje stratu kvality pri odstránení hlavného zdroja multikolinearity.

8.2 VIF nových modelov

cat("VIF modelu bez Sunshine:\n")
VIF modelu bez Sunshine:
print(vif(model_no_sunshine))
     Cloud_Cover         Humidity         Pressure Global_Radiation    Precipitation 
        1.775061         2.057101         1.229672         2.298374         1.235000 
cat("\nVIF modelu bez Global_Radiation:\n")

VIF modelu bez Global_Radiation:
print(vif(model_no_radiation))
  Cloud_Cover      Humidity      Pressure Precipitation      Sunshine 
     3.383370      1.880627      1.205548      1.231151      4.204617 
cat("\nVIF modelu bez Cloud_Cover:\n")

VIF modelu bez Cloud_Cover:
print(vif(model_no_cloud))
        Humidity         Pressure Global_Radiation    Precipitation         Sunshine 
        2.074434         1.204948         4.390475         1.234120         4.213869 

Po vynechaní Sunshine sa VIF všetkých premenných dostal pod kritickú hranicu 5, čo značne redukovalo multikolinearitu. Najvyššiu hodnotu má Global_Radiation - 2,30, čo stále predstavuje len miernu multikolinearitu.

Model bez Global_Radiation má najvyšší VIF pre Sunshine = 4,20, čo je stále prijateľné.

Vynechanie Cloud_Cover viedlo k zvýšeniu VIF pre Global_Radiation a Sunshine na úroveň miernej multikolinearity - 4,2.

Najefektívnejšie riešenie multikolinearity poskytuje vynechanie premennej Sunshine, kedy všetky VIF hodnoty klesli pod 2,3, čo zaručuje stabilné odhady regresných koeficientov.

8.3 Škálovanie premenných

udaje$Cloud_scaled <- scale(udaje$Cloud_Cover, center = TRUE, scale = TRUE)
udaje$Humidity_scaled <- scale(udaje$Humidity, center = TRUE, scale = TRUE)
udaje$Pressure_scaled <- scale(udaje$Pressure, center = TRUE, scale = TRUE)
udaje$Radiation_scaled <- scale(udaje$Global_Radiation, center = TRUE, scale = TRUE)
udaje$Precipitation_scaled <- scale(udaje$Precipitation, center = TRUE, scale = TRUE)
udaje$Sunshine_scaled <- scale(udaje$Sunshine, center = TRUE, scale = TRUE)

model_scaled <- lm(Temp_Mean ~ Cloud_scaled + Humidity_scaled + Pressure_scaled + 
                    Radiation_scaled + Precipitation_scaled + Sunshine_scaled,
                  data = udaje)

summary(model_scaled)

Call:
lm(formula = Temp_Mean ~ Cloud_scaled + Humidity_scaled + Pressure_scaled + 
    Radiation_scaled + Precipitation_scaled + Sunshine_scaled, 
    data = udaje)

Residuals:
     Min       1Q   Median       3Q      Max 
-17.1741  -3.0156   0.1185   3.2680  14.1748 

Coefficients:
                     Estimate Std. Error t value Pr(>|t|)    
(Intercept)          11.02280    0.07582 145.378  < 2e-16 ***
Cloud_scaled          1.03954    0.14872   6.990 3.25e-12 ***
Humidity_scaled       0.85781    0.10923   7.853 5.30e-15 ***
Pressure_scaled      -0.75101    0.08431  -8.907  < 2e-16 ***
Radiation_scaled      7.93240    0.16941  46.824  < 2e-16 ***
Precipitation_scaled  0.76441    0.08431   9.066  < 2e-16 ***
Sunshine_scaled      -1.58957    0.22913  -6.937 4.71e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.583 on 3647 degrees of freedom
Multiple R-squared:  0.6185,    Adjusted R-squared:  0.6179 
F-statistic: 985.6 on 6 and 3647 DF,  p-value: < 2.2e-16
vif_scaled <- vif(model_scaled)
vif_scaled
        Cloud_scaled      Humidity_scaled      Pressure_scaled     Radiation_scaled Precipitation_scaled      Sunshine_scaled 
            3.845990             2.074981             1.236207             4.990801             1.236201             9.130107 

Škálovanie premenných nezmenilo základné štatistické vlastnosti modelu - R² zostáva na úrovni 0,6179 a všetky premenné sú štatisticky významné.

Avšak VIF hodnoty ukazujú, že multikolinearita pretrváva, najmä pre Sunshine_scaled (VIF = 9,13) a Radiation_scaled (VIF = 4,99).

Škálovanie len transformuje premenné na porovnateľné mierky, ale nerieši ich vnútorné korelácie. Sunshine_scaled má negatívny koeficient (-1,59), čo je v rozpore s očakávaniami, a naznačuje problémy s interpretáciou v dôsledku multikolinearity.

Tento prístup je užitočný pre numerickú stabilitu, ale sám o sebe neodstraňuje korelácie medzi premennými.

8.4 Condition Number po škálovaní

X_scaled <- model.matrix(model_scaled)[, -1]
XtX_scaled <- t(X_scaled) %*% X_scaled
vlastne_hodnoty_scaled <- eigen(XtX_scaled)$values

condition_number_scaled <- sqrt(max(vlastne_hodnoty_scaled) / min(vlastne_hodnoty_scaled))
condition_number_scaled
[1] 6.80095

Po škálovaní premenných sa condition number výrazne znížil z pôvodných 140,95 na 6,80, čo predstavuje výrazné zlepšenie numerickej stability modelu.

Hodnota 6,80 sa nachádza v pásme nízkej multikolinearity (pod 10), čo naznačuje, že škálovanie úspešne redukovalo numerickú citlivosť výpočtov.

To znamená, že matica dizajnu je teraz lepšie podmienená a odhady regresných koeficientov sú stabilnejšie. Avšak toto zlepšenie sa týka len numerickej stability, nie však základných štatistických vzťahov medzi premennými, ako ukazujú stále vysoké VIF hodnoty.

8.5 Transformácia premenných

model_interaction <- lm(Temp_Mean ~ Cloud_Cover * Sunshine + Humidity + Pressure + 
                         Global_Radiation + Precipitation,
                       data = udaje)
summary(model_interaction)

Call:
lm(formula = Temp_Mean ~ Cloud_Cover * Sunshine + Humidity + 
    Pressure + Global_Radiation + Precipitation, data = udaje)

Residuals:
     Min       1Q   Median       3Q      Max 
-17.0302  -3.0474   0.1323   3.2992  14.1350 

Coefficients:
                       Estimate Std. Error t value Pr(>|t|)    
(Intercept)           82.792714  10.876314   7.612 3.41e-14 ***
Cloud_Cover            0.734451   0.086358   8.505  < 2e-16 ***
Sunshine              -0.145544   0.069274  -2.101   0.0357 *  
Humidity               8.111203   1.010669   8.026 1.35e-15 ***
Pressure             -90.407315  10.585083  -8.541  < 2e-16 ***
Global_Radiation       8.525535   0.180770  47.162  < 2e-16 ***
Precipitation          1.341558   0.157641   8.510  < 2e-16 ***
Cloud_Cover:Sunshine  -0.044112   0.008941  -4.934 8.43e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.569 on 3646 degrees of freedom
Multiple R-squared:  0.6211,    Adjusted R-squared:  0.6203 
F-statistic: 853.7 on 7 and 3646 DF,  p-value: < 2.2e-16
model_quadratic <- lm(Temp_Mean ~ Cloud_Cover + I(Cloud_Cover^2) + Humidity + 
                       Pressure + Global_Radiation + Precipitation + Sunshine,
                     data = udaje)
summary(model_quadratic)

Call:
lm(formula = Temp_Mean ~ Cloud_Cover + I(Cloud_Cover^2) + Humidity + 
    Pressure + Global_Radiation + Precipitation + Sunshine, data = udaje)

Residuals:
     Min       1Q   Median       3Q      Max 
-17.2237  -3.0225   0.1187   3.2645  14.2011 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)       88.858262  10.844918   8.194 3.47e-16 ***
Cloud_Cover        0.361908   0.150229   2.409    0.016 *  
I(Cloud_Cover^2)   0.009893   0.015800   0.626    0.531    
Humidity           7.969555   1.013664   7.862 4.93e-15 ***
Pressure         -94.321589  10.589929  -8.907  < 2e-16 ***
Global_Radiation   8.500078   0.183762  46.256  < 2e-16 ***
Precipitation      1.413180   0.158446   8.919  < 2e-16 ***
Sunshine          -0.367090   0.052921  -6.937 4.73e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 4.584 on 3646 degrees of freedom
Multiple R-squared:  0.6186,    Adjusted R-squared:  0.6179 
F-statistic: 844.7 on 7 and 3646 DF,  p-value: < 2.2e-16

Model s interakciou medzi Cloud_Cover a Sunshine dosiahol najvyšší upravený R² = 0,6203 a ukázal štatisticky významný interakčný člen (p = 8,43e-07).

To naznačuje, že vplyv slnečného svitu na teplotu závisí od úrovne oblačnosti – komplexný vzťah, ktorý jednoduchý lineárny model nezachytáva.

Naproti tomu kvadratický model s Cloud_Cover² nepriniesol zlepšenie – kvadratický člen nie je štatisticky významný (p = 0,531) a R² je nižší.

Model s interakciou tak ponúka najlepšie riešenie, ktoré zachováva vysokú prediktívnu silu a zároveň adekvátne modeluje komplexné vzťahy medzi meteorologickými premennými.

9. Porovnanie modelov

models <- list("Pôvodný model" = model,
               "Bez Sunshine" = model_no_sunshine,
               "Bez Global_Radiation" = model_no_radiation,
               "Bez Cloud_Cover" = model_no_cloud,
               "S interakciou" = model_interaction,
               "Škálovaný model" = model_scaled)

comparison <- data.frame(
  Model = names(models),
  R2 = sapply(models, function(m) round(summary(m)$r.squared, 4)),
  Adj_R2 = sapply(models, function(m) round(summary(m)$adj.r.squared, 4)),
  AIC = round(sapply(models, AIC), 2),
  BIC = round(sapply(models, BIC), 2)
)

print(comparison)

Model s interakciou medzi Cloud_Cover a Sunshine je najlepší podľa všetkých kritérií – má najvyšší upravený R² = 0,6203, najnižšie AIC = 21482,09 a BIC = 21537,92.

Model bez Global_Radiation výrazne zaostáva s R² = 0,3884.

Pôvodný a škálovaný model sú štatisticky ekvivalentné.

Najlepšou stratégiou na riešenie multikolinearity je pridanie interakčného člena medzi Cloud_Cover a Sunshine, čo zlepšuje prediktívnu silu a adekvátne zachytáva komplexné meteorologické vzťahy.

10. Zhrnutie

Analýza multikolinearity v meteorologickom modeli pre mesto Bazilej potvrdila prítomnosť výraznej multikolinearity medzi kľúčovými premennými, najmä medzi Sunshine, Global_Radiation a Cloud_Cover. Tento jav je spôsobený prirodzenými fyzikálnymi vzťahmi v atmosfére – vyššia oblačnosť prirodzene redukuje slnečný svit a globálne žiarenie.

Diagnostické nástroje konzistentne identifikovali problém:

  • VIF pre Sunshine dosahoval 11,18 (vysoká multikolinearita) a condition number pôvodného modelu bol 140,95 (veľmi vysoká multikolinearita). Napriek tejto multikolinearite si model zachoval vysokú prediktívnu silu s R² = 0,6179, čo naznačuje dobré zachytenie vzťahov v dátach.

Testované riešenia multikolinearity ukázali, že najefektívnejšou stratégiou je pridanie interakčného členu medzi Cloud_Cover a Sunshine. Tento model dosiahol najvyššiu explanačnú silu (R² = 0,6203) a najnižšie informačné kritériá (AIC = 21482,09), pričom adekvátne zachytil komplexný vzťah medzi týmito premennými. Interakčný člen bol štatisticky významný (p = 8,43e-07), čo potvrdzuje, že vplyv slnečného svitu na teplotu závisí od úrovne oblačnosti.

Alternatívne riešenie – vynechanie premennej Sunshine – síce redukovalo multikolinearitu (VIF všetkých premenných pod 2,3), ale viedlo k miernemu poklesu prediktívnej sily. Vynechanie Global_Radiation sa ukázalo ako neprijateľné, keďže spôsobilo výraznú stratu kvality modelu (R² poklesol na 0,3884).

LS0tDQp0aXRsZTogIsOabG9oYV8xMCINCmF1dGhvcjogIkJjLiBLcnlzdHluYSBWYXN5bHluYSINCmRhdGU6ICJEZWNlbWJlciAyMDI1Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIHRoZW1lOiB1bml0ZWQNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICBkZl9wcmludDogcGFnZWQNCmVkaXRvcl9vcHRpb25zOg0KICBtYXJrZG93bjoNCiAgICB3cmFwOiA3Mg0KLS0tDQoNCiMjIDEuIMOadm9kDQoNClYgdGVqdG8gYW5hbMO9emUgYnVkZW1lIHNrw7ptYcWlIG11bHRpa29saW5lYXJpdHUgdiBtb2RlbGkgbWV0ZW9yb2xvZ2lja8O9Y2ggdWthem92YXRlxL5vdiBwcmUgbWVzdG8gKipCYXppbGVqICjFoHZhasSNaWFyc2tvKSoqLg0KDQpCdWRlbWUgcHJhY292YcWlIHMgcmVncmVzbsO9bSBtb2RlbG9tLCBrZGUgYWtvIHrDoXZpc2zDuiBwcmVtZW5uw7ogcG91xb5pamVtZSAqKnByaWVtZXJuw7ogdGVwbG90dSAiQkFTRUxfdGVtcF9tZWFuIioqIGEgYWtvIG5lesOhdmlzbMOpIHByZW1lbm7DqSBvc3RhdG7DqSBtZXRlb3JvbG9naWNrw6kgdWthem92YXRlbGUgcHJlIEJhemlsZWouDQoNCk1vZGVsb3ZhbmllIHRlanRvIHrDoXZpc2xvc3RpIG7DoW0gdW1vxb5uw60gcG9jaG9wacWlLCBha28gamVkbm90bGl2w6kgbWV0ZW9yb2xvZ2lja8OpIGZha3Rvcnkgc3BvbHVww7Rzb2JpYSBhIMSNaSBqZSBtb8W+bsOpIGljaCBwb3XFvmnFpSBzw7rEjWFzbmUgYmV6IHByb2Jsw6ltb3YgcyBtdWx0aWtvbGluZWFyaXRvdS4NCg0KIyMgMi4gVsO9Y2hvZGlza292w70gbW9kZWwgYSDDumRhamUNCg0KYGBge3J9DQpsaWJyYXJ5KHpvbykNCmxpYnJhcnkodHNlcmllcykNCmxpYnJhcnkobG10ZXN0KQ0KbGlicmFyeShzYW5kd2ljaCkNCmxpYnJhcnkoY2FyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCnJtKGxpc3QgPSBscygpKQ0KDQp1ZGFqZSA8LSByZWFkLmNzdigid2VhdGhlcl9wcmVkaWN0aW9uX2RhdGFzZXQuY3N2IiwgDQogICAgICAgICAgICAgICAgICBkZWMgPSAiLiIsIA0KICAgICAgICAgICAgICAgICAgc2VwID0gIiwiLCANCiAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFRSVUUpDQoNCnN0cih1ZGFqZSkNCg0KdWRhamUkREFURSA8LSBhcy5EYXRlKGFzLmNoYXJhY3Rlcih1ZGFqZSREQVRFKSwgZm9ybWF0ID0gIiVZJW0lZCIpDQoNCmJhc2VsX3ZhcnMgPC0gYygiREFURSIsICJNT05USCIsICJCQVNFTF9jbG91ZF9jb3ZlciIsICJCQVNFTF9odW1pZGl0eSIsIA0KICAgICAgICAgICAgICAgICJCQVNFTF9wcmVzc3VyZSIsICJCQVNFTF9nbG9iYWxfcmFkaWF0aW9uIiwgIkJBU0VMX3ByZWNpcGl0YXRpb24iLCANCiAgICAgICAgICAgICAgICAiQkFTRUxfc3Vuc2hpbmUiLCAiQkFTRUxfdGVtcF9tZWFuIiwgIkJBU0VMX3RlbXBfbWluIiwgIkJBU0VMX3RlbXBfbWF4IikNCg0KYmFzZWxfZGF0YSA8LSB1ZGFqZVssIGJhc2VsX3ZhcnNdDQoNCnNhcHBseShiYXNlbF9kYXRhLCBmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQ0KDQppZihhbnkoaXMubmEoYmFzZWxfZGF0YSkpKSB7DQogIG51bWVyaWNfdmFycyA8LSBjKCJCQVNFTF9jbG91ZF9jb3ZlciIsICJCQVNFTF9odW1pZGl0eSIsICJCQVNFTF9wcmVzc3VyZSIsIA0KICAgICAgICAgICAgICAgICAgICAiQkFTRUxfZ2xvYmFsX3JhZGlhdGlvbiIsICJCQVNFTF9wcmVjaXBpdGF0aW9uIiwgIkJBU0VMX3N1bnNoaW5lIikNCiAgDQogIGNvbHVtbl9tZWRpYW5zIDwtIHNhcHBseShiYXNlbF9kYXRhWywgbnVtZXJpY192YXJzXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhbiwgbmEucm0gPSBUUlVFKQ0KICANCiAgZm9yKGNvbCBpbiBuYW1lcyhjb2x1bW5fbWVkaWFucykpIHsNCiAgICBuYV9pbmRleCA8LSBpcy5uYShiYXNlbF9kYXRhW1tjb2xdXSkNCiAgICBpZihhbnkobmFfaW5kZXgpKSB7DQogICAgICBiYXNlbF9kYXRhW1tjb2xdXVtuYV9pbmRleF0gPC0gY29sdW1uX21lZGlhbnNbY29sXQ0KICAgIH0NCiAgfQ0KfQ0KDQpjb2xuYW1lcyhiYXNlbF9kYXRhKSA8LSBjKCJEYXRlIiwgIk1vbnRoIiwgIkNsb3VkX0NvdmVyIiwgIkh1bWlkaXR5IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJQcmVzc3VyZSIsICJHbG9iYWxfUmFkaWF0aW9uIiwgIlByZWNpcGl0YXRpb24iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlN1bnNoaW5lIiwgIlRlbXBfTWVhbiIsICJUZW1wX01pbiIsICJUZW1wX01heCIpDQoNCnVkYWplIDwtIGJhc2VsX2RhdGENCnJtKGJhc2VsX2RhdGEpDQoNCnN1bW1hcnkodWRhamVbLCAzOjExXSkNCmBgYA0KDQojIyAzLiBPZGhhZCB6w6FrbGFkbsOpaG8gcmVncmVzbsOpaG8gbW9kZWx1DQoNCmBgYHtyfQ0KbW9kZWwgPC0gbG0oVGVtcF9NZWFuIH4gQ2xvdWRfQ292ZXIgKyBIdW1pZGl0eSArIFByZXNzdXJlICsgDQogICAgICAgICAgICAgR2xvYmFsX1JhZGlhdGlvbiArIFByZWNpcGl0YXRpb24gKyBTdW5zaGluZSwNCiAgICAgICAgICAgZGF0YSA9IHVkYWplKQ0KDQpzdW1tYXJ5KG1vZGVsKQ0KYGBgDQpWw71zdHVwIG1vZGVsdSBwb3NreXR1amUgbmlla2/EvmtvIGvEvsO6xI1vdsO9Y2ggaW5mb3Jtw6FjacOtOiANCg0KLSBSLXNxdWFyZWQgKFLCsikgaG92b3LDrSBvIHRvbSwgYWvDvSBwb2RpZWwgdmFyaWFiaWxpdHkgdGVwbG90eSBkb2vDocW+ZW1lIHZ5c3ZldGxpxaUgcG9tb2NvdSBuw6HFoWhvIG1vZGVsdTsgDQoNCi0gcC1ob2Rub3R5IHByZSBqZWRub3RsaXbDqSBrb2VmaWNpZW50eSBpbmRpa3Vqw7ogxaF0YXRpc3RpY2vDuiB2w716bmFtbm9zxaUga2HFvmTDqWhvIGZha3RvcmE7IA0KDQotIEYtdGVzdCBob2Rub3TDrSBjZWxrb3bDuiB2w716bmFtbm9zxaUgbW9kZWx1LiANCg0KVnlzb2vDoSBob2Rub3RhICoqUsKyID0gMCw4OTcqKiBuYXpuYcSNdWplLCDFvmUgbW9kZWwgZG9icmUgemFjaHl0w6F2YSB2esWlYWh5IHYgZMOhdGFjaCwgYWxlIHRvIGXFoXRlIG5lem5hbWVuw6EsIMW+ZSBuZWV4aXN0dWrDuiBwcm9ibMOpbXkgcyBtdWx0aWtvbGluZWFyaXRvdS4NCg0KIyMgNC4gS29yZWxhxI1uw6EgbWF0aWNhDQoNCmBgYHtyfQ0KeHZhcnMgPC0gdWRhamVbLCBjKCJDbG91ZF9Db3ZlciIsICJIdW1pZGl0eSIsICJQcmVzc3VyZSIsIA0KICAgICAgICAgICAgICAgICAgICJHbG9iYWxfUmFkaWF0aW9uIiwgIlByZWNpcGl0YXRpb24iLCAiU3Vuc2hpbmUiKV0NCg0Ka29yZWxhY25hX21hdGljYSA8LSByb3VuZChjb3IoeHZhcnMpLCAzKQ0Ka29yZWxhY25hX21hdGljYQ0KYGBgDQpWaWTDrW1lIG5pZWtvxL5rbyB2eXNva8O9Y2gga29yZWzDoWNpw606IA0KDQotIG1lZHppICoqU3Vuc2hpbmUgYSBHbG9iYWxfUmFkaWF0aW9uID0gMCw4MDQqKiAtIMSNbyBqZSBsb2dpY2vDqSwga2XEj8W+ZSBzbG5lxI1uw70gc3ZpdCBwcmlhbW8gc8O6dmlzw60gc28gc2xuZcSNbsO9bSDFvmlhcmVuw61tOyANCg0KLSBtZWR6aSAqKkNsb3VkX0NvdmVyIGEgSHVtaWRpdHkgPSAwLDY1NSoqIC0gdnnFocWhaWEgb2JsYcSNbm9zxaUgxI1hc3RvIHPDunZpc8OtIHMgdnnFocWhb3Ugdmxoa29zxaVvdTsgDQoNCi0gc2lsbsOhIG5lZ2F0w612bmEga29yZWzDoWNpYSBtZWR6aSAqKkNsb3VkX0NvdmVyIGEgU3Vuc2hpbmUgPSAtMCw4MTUqKiAtIMSNw61tIGplIHZ5xaHFoWlhIG9ibGHEjW5vc8WlLCB0w71tIG1lbmVqIHNsbmXEjW7DqWhvIHN2aXR1LiANCg0KVGlldG8gdnlzb2vDqSBrb3JlbMOhY2llIHPDuiBwcnbDvW0gc2lnbsOhbG9tIG1vxb5uw71jaCBwcm9ibMOpbW92IHMgbXVsdGlrb2xpbmVhcml0b3UuDQoNCiMjIDUuIEdyYWZpY2vDoSBhbmFsw716YSB2esWlYWhvdiBtZWR6aSBwcmVtZW5uw71taQ0KDQpgYGB7cn0NCnBhaXJzKHh2YXJzLA0KICAgICAgbWFpbiA9ICJTY2F0dGVycGxvdG92w6EgbWF0aWNhIOKAkyBtZXRlb3JvbG9naWNrw6kgcHJlbWVubsOpIiwNCiAgICAgIHBjaCA9IDE5LA0KICAgICAgY29sID0gImxpZ2h0Z3JlZW4iLA0KICAgICAgY2V4ID0gMC42KQ0KYGBgDQpTY2F0dGVycGxvdG92w6EgbWF0aWNhIG7DoW0gcG9za3l0dWplIHZpenXDoWxueSBwb2jEvmFkIG5hIHZ6xaVhaHkgbWVkemkgcHJlbWVubsO9bWkuIA0KDQpUw6F0byB2aXp1YWxpesOhY2lhIHBvdHZyZHp1amUsIMSNbyBzbWUgdmlkZWxpIHYga29yZWxhxI1uZWogbWF0aWNpIC0gZXhpc3R1asO6IGphc27DqSBsaW5lw6FybmUgdnrFpWFoeSBtZWR6aSBuaWVrdG9yw71taSBwcmVtZW5uw71taTogDQoNCi0gbmFqdsO9cmF6bmVqxaFpZSBzw7ogdnrFpWFoeSBtZWR6aSAqKlN1bnNoaW5lIGEgR2xvYmFsX1JhZGlhdGlvbioqIGEgbWVkemkgKipDbG91ZF9Db3ZlciBhIFN1bnNoaW5lKiouIA0KDQpUaWV0byB2aXp1w6FsbmUgdnpvcnkgbsOhbSBwb23DoWhhasO6IHBvY2hvcGnFpSDFoXRydWt0w7pydSBkw6F0IGEgaWRlbnRpZmlrb3ZhxaUsIGt0b3LDqSBwcmVtZW5uw6kgc8O6IHBvdGVuY2nDoWxuZSBwcm9ibGVtYXRpY2vDqSB6IGjEvmFkaXNrYSBtdWx0aWtvbGluZWFyaXR5Lg0KDQojIyA2LiBWSUYgKFZhcmlhbmNlIEluZmxhdGlvbiBGYWN0b3IpDQoNCmBgYHtyfQ0KdmlmX2hvZG5vdHkgPC0gdmlmKG1vZGVsKQ0KdmlmX2hvZG5vdHkNCmBgYA0KLSBWSUYgPSAxIHpuYW1lbsOhIMW+aWFkbnUga29yZWzDoWNpdSBzIGluw71taSBwcmVtZW5uw71taTsgDQoNCi0gVklGIG1lZHppIDEgYSA1IG5hem5hxI11amUgbWllcm51IGtvcmVsw6FjaXU7IA0KDQotIFZJRiBtZWR6aSA1IGEgMTAgc2lnbmFsaXp1amUgbWllcm51IGHFviBzdHJlZG7DuiBtdWx0aWtvbGluZWFyaXR1OyANCg0KLSBWSUYgbmFkIDEwIGluZGlrdWplIHZ5c29rw7ogbXVsdGlrb2xpbmVhcml0dS4gDQoNClYgbmHFoW9tIG1vZGVsaSBtw6EgU3Vuc2hpbmUgKipWSUYgPSAxMSwxOCoqLCDEjW8gem5hbWVuw6EsIMW+ZSByb3pwdHlsIGplaiBvZGhhZG51dMOpaG8ga29lZmljaWVudHUgamUgdmlhYyBuZcW+IDExLWtyw6F0IHbDpMSNxaHDrSwgYWtvIGtlYnkgbmVib2xhIGtvcmVsb3ZhbsOhIHMgaW7DvW1pIHByZW1lbm7DvW1pIC0gamFzbsO9IHByw61wYWQgdnlzb2tlaiBtdWx0aWtvbGluZWFyaXR5Lg0KDQojIyA3LiBDb25kaXRpb24gTnVtYmVyIA0KDQpgYGB7cn0NClggPC0gbW9kZWwubWF0cml4KG1vZGVsKVssIC0xXQ0KWHRYIDwtIHQoWCkgJSolIFgNCnZsYXN0bmVfaG9kbm90eSA8LSBlaWdlbihYdFgpJHZhbHVlcw0KDQpjb25kaXRpb25fbnVtYmVyIDwtIHNxcnQobWF4KHZsYXN0bmVfaG9kbm90eSkgLyBtaW4odmxhc3RuZV9ob2Rub3R5KSkNCmNvbmRpdGlvbl9udW1iZXINCmBgYA0KUHJhaG92w6kgaG9kbm90eTogDQoNCi0gcG9kIDEwIC0gxb5pYWRuYSBhbGVibyB2ZcS+bWkgbsOtemthIG11bHRpa29saW5lYXJpdGE7IA0KDQotIDEwLTMwIC0gbWllcm5hIG11bHRpa29saW5lYXJpdGE7IA0KDQotIDMwLTEwMCAtIHZ5c29rw6EgbXVsdGlrb2xpbmVhcml0YTsgDQoNCi0gbmFkIDEwMCAtIHZlxL5taSB2eXNva8OhIG11bHRpa29saW5lYXJpdGEuIA0KDQpOYcWhZSAqKkNvbmRpdGlvbiBudW1iZXIgPSAxNDAsOTUqKiBqYXNuZSBpbmRpa3VqZSB2w6HFvm55IHByb2Jsw6ltIHMgbXVsdGlrb2xpbmVhcml0b3UgdiBtb2RlbGkgYSBuYXpuYcSNdWplLCDFvmUgbnVtZXJpY2vDqSB2w71wb8SNdHkgbcO0xb51IGJ5xaUgbmVzdGFiaWxuw6kuDQoNCiMjIDguIFJpZcWhZW5pYSBtdWx0aWtvbGluZWFyaXR5DQoNCiMjIyA4LjEgVnluZWNoYW5pZSBwcmVtZW5uZWoNCg0KYGBge3J9DQptb2RlbF9ub19zdW5zaGluZSA8LSBsbShUZW1wX01lYW4gfiBDbG91ZF9Db3ZlciArIEh1bWlkaXR5ICsgUHJlc3N1cmUgKyANCiAgICAgICAgICAgICAgICAgICAgICAgICBHbG9iYWxfUmFkaWF0aW9uICsgUHJlY2lwaXRhdGlvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHVkYWplKQ0Kc3VtbWFyeShtb2RlbF9ub19zdW5zaGluZSkNCg0KbW9kZWxfbm9fcmFkaWF0aW9uIDwtIGxtKFRlbXBfTWVhbiB+IENsb3VkX0NvdmVyICsgSHVtaWRpdHkgKyBQcmVzc3VyZSArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBQcmVjaXBpdGF0aW9uICsgU3Vuc2hpbmUsDQogICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gdWRhamUpDQpzdW1tYXJ5KG1vZGVsX25vX3JhZGlhdGlvbikNCg0KbW9kZWxfbm9fY2xvdWQgPC0gbG0oVGVtcF9NZWFuIH4gSHVtaWRpdHkgKyBQcmVzc3VyZSArIA0KICAgICAgICAgICAgICAgICAgICAgIEdsb2JhbF9SYWRpYXRpb24gKyBQcmVjaXBpdGF0aW9uICsgU3Vuc2hpbmUsDQogICAgICAgICAgICAgICAgICAgIGRhdGEgPSB1ZGFqZSkNCnN1bW1hcnkobW9kZWxfbm9fY2xvdWQpDQoNCmNhdCgiVXByYXZlbsO9IFLCsiBww7R2b2Ruw6lobyBtb2RlbHU6Iiwgcm91bmQoc3VtbWFyeShtb2RlbCkkYWRqLnIuc3F1YXJlZCwgNCksICJcbiIpDQpjYXQoIlVwcmF2ZW7DvSBSwrIgbW9kZWx1IGJleiBTdW5zaGluZToiLCByb3VuZChzdW1tYXJ5KG1vZGVsX25vX3N1bnNoaW5lKSRhZGouci5zcXVhcmVkLCA0KSwgIlxuIikNCmNhdCgiVXByYXZlbsO9IFLCsiBtb2RlbHUgYmV6IEdsb2JhbF9SYWRpYXRpb246Iiwgcm91bmQoc3VtbWFyeShtb2RlbF9ub19yYWRpYXRpb24pJGFkai5yLnNxdWFyZWQsIDQpLCAiXG4iKQ0KY2F0KCJVcHJhdmVuw70gUsKyIG1vZGVsdSBiZXogQ2xvdWRfQ292ZXI6Iiwgcm91bmQoc3VtbWFyeShtb2RlbF9ub19jbG91ZCkkYWRqLnIuc3F1YXJlZCwgNCksICJcbiIpDQpgYGANClBvIHZ5bmVjaGFuw60gcHJlbWVubmVqIFN1bnNoaW5lIHNhIGt2YWxpdGEgbW9kZWx1IG1pZXJuZSB6bsOtxb5pbGEgKCoqUsKyIHBva2xlc29sIHogMCw2MTc5IG5hIDAsNjEzMCoqKSwgYWxlIHbFoWV0a3kgem9zdMOhdmFqw7pjZSBwcmVtZW5uw6kgc8O6IMWhdGF0aXN0aWNreSB2w716bmFtbsOpLiANCg0KQ2xvdWRfQ292ZXIgesOtc2thbCBwb3ppdMOtdm55IHZwbHl2IGEgR2xvYmFsX1JhZGlhdGlvbiBzYSB1a8OhemFsIGFrbyBrxL7DusSNb3bDvSBmYWt0b3IuIA0KDQpNb2RlbCBiZXogR2xvYmFsX1JhZGlhdGlvbiB2w71yYXpuZSBzdHJhdGlsIG5hIGt2YWxpdGUgKCoqUsKyIGtsZXNvbCBuYSAwLDM4ODQqKiksIMSNbyBwb3R2cmR6dWplIGplaiBrcml0aWNrw7ogw7psb2h1IHYgbW9kZWxpLiANCg0KVnluZWNoYW5pZSBDbG91ZF9Db3ZlciB2aWVkbG8gayBtaWVybmVtdSAqKnBva2xlc3UgUsKyIG5hIDAsNjEyOSoqLCBhbGUgem1lbmlsbyBpbnRlcnByZXTDoWNpdSBTdW5zaGluZSBuYSBuZWdhdMOtdm55IHZwbHl2LiANCg0KTmFqbGVwxaFvdSBzdHJhdMOpZ2lvdSBqZSB2eW5lY2hhbmllIFN1bnNoaW5lLCBwcmV0b8W+ZSBtaW5pbWFsaXp1amUgc3RyYXR1IGt2YWxpdHkgcHJpIG9kc3Ryw6FuZW7DrSBobGF2bsOpaG8gemRyb2phIG11bHRpa29saW5lYXJpdHkuDQoNCiMjIyA4LjIgVklGIG5vdsO9Y2ggbW9kZWxvdg0KDQpgYGB7cn0NCmNhdCgiVklGIG1vZGVsdSBiZXogU3Vuc2hpbmU6XG4iKQ0KcHJpbnQodmlmKG1vZGVsX25vX3N1bnNoaW5lKSkNCg0KY2F0KCJcblZJRiBtb2RlbHUgYmV6IEdsb2JhbF9SYWRpYXRpb246XG4iKQ0KcHJpbnQodmlmKG1vZGVsX25vX3JhZGlhdGlvbikpDQoNCmNhdCgiXG5WSUYgbW9kZWx1IGJleiBDbG91ZF9Db3ZlcjpcbiIpDQpwcmludCh2aWYobW9kZWxfbm9fY2xvdWQpKQ0KYGBgDQpQbyB2eW5lY2hhbsOtIFN1bnNoaW5lIHNhIFZJRiB2xaFldGvDvWNoIHByZW1lbm7DvWNoIGRvc3RhbCBwb2Qga3JpdGlja8O6IGhyYW5pY3UgNSwgxI1vIHpuYcSNbmUgcmVkdWtvdmFsbyBtdWx0aWtvbGluZWFyaXR1LiBOYWp2ecWhxaFpdSBob2Rub3R1IG3DoSBHbG9iYWxfUmFkaWF0aW9uIC0gKioyLDMwKiosIMSNbyBzdMOhbGUgcHJlZHN0YXZ1amUgbGVuIG1pZXJudSBtdWx0aWtvbGluZWFyaXR1LiANCg0KTW9kZWwgYmV6IEdsb2JhbF9SYWRpYXRpb24gbcOhIG5hanZ5xaHFocOtICoqVklGIHByZSBTdW5zaGluZSA9IDQsMjAqKiwgxI1vIGplIHN0w6FsZSBwcmlqYXRlxL5uw6kuIA0KDQpWeW5lY2hhbmllIENsb3VkX0NvdmVyIHZpZWRsbyBrIHp2w73FoWVuaXUgVklGIHByZSBHbG9iYWxfUmFkaWF0aW9uIGEgU3Vuc2hpbmUgbmEgw7pyb3ZlxYggbWllcm5laiBtdWx0aWtvbGluZWFyaXR5IC0gKio0LDIqKi4gDQoNCk5hamVmZWt0w612bmVqxaFpZSByaWXFoWVuaWUgbXVsdGlrb2xpbmVhcml0eSBwb3NreXR1amUgdnluZWNoYW5pZSBwcmVtZW5uZWogU3Vuc2hpbmUsIGtlZHkgdsWhZXRreSBWSUYgaG9kbm90eSBrbGVzbGkgcG9kICoqMiwzKiosIMSNbyB6YXJ1xI11amUgc3RhYmlsbsOpIG9kaGFkeSByZWdyZXNuw71jaCBrb2VmaWNpZW50b3YuDQoNCiMjIyA4LjMgxaBrw6Fsb3ZhbmllIHByZW1lbm7DvWNoDQoNCmBgYHtyfQ0KdWRhamUkQ2xvdWRfc2NhbGVkIDwtIHNjYWxlKHVkYWplJENsb3VkX0NvdmVyLCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IFRSVUUpDQp1ZGFqZSRIdW1pZGl0eV9zY2FsZWQgPC0gc2NhbGUodWRhamUkSHVtaWRpdHksIGNlbnRlciA9IFRSVUUsIHNjYWxlID0gVFJVRSkNCnVkYWplJFByZXNzdXJlX3NjYWxlZCA8LSBzY2FsZSh1ZGFqZSRQcmVzc3VyZSwgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBUUlVFKQ0KdWRhamUkUmFkaWF0aW9uX3NjYWxlZCA8LSBzY2FsZSh1ZGFqZSRHbG9iYWxfUmFkaWF0aW9uLCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IFRSVUUpDQp1ZGFqZSRQcmVjaXBpdGF0aW9uX3NjYWxlZCA8LSBzY2FsZSh1ZGFqZSRQcmVjaXBpdGF0aW9uLCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IFRSVUUpDQp1ZGFqZSRTdW5zaGluZV9zY2FsZWQgPC0gc2NhbGUodWRhamUkU3Vuc2hpbmUsIGNlbnRlciA9IFRSVUUsIHNjYWxlID0gVFJVRSkNCg0KbW9kZWxfc2NhbGVkIDwtIGxtKFRlbXBfTWVhbiB+IENsb3VkX3NjYWxlZCArIEh1bWlkaXR5X3NjYWxlZCArIFByZXNzdXJlX3NjYWxlZCArIA0KICAgICAgICAgICAgICAgICAgICBSYWRpYXRpb25fc2NhbGVkICsgUHJlY2lwaXRhdGlvbl9zY2FsZWQgKyBTdW5zaGluZV9zY2FsZWQsDQogICAgICAgICAgICAgICAgICBkYXRhID0gdWRhamUpDQoNCnN1bW1hcnkobW9kZWxfc2NhbGVkKQ0KDQp2aWZfc2NhbGVkIDwtIHZpZihtb2RlbF9zY2FsZWQpDQp2aWZfc2NhbGVkDQpgYGANCsWga8OhbG92YW5pZSBwcmVtZW5uw71jaCBuZXptZW5pbG8gesOha2xhZG7DqSDFoXRhdGlzdGlja8OpIHZsYXN0bm9zdGkgbW9kZWx1IC0gUsKyIHpvc3TDoXZhIG5hIMO6cm92bmkgKiowLDYxNzkqKiBhIHbFoWV0a3kgcHJlbWVubsOpIHPDuiDFoXRhdGlzdGlja3kgdsO9em5hbW7DqS4gDQoNCkF2xaFhayBWSUYgaG9kbm90eSB1a2F6dWrDuiwgxb5lIG11bHRpa29saW5lYXJpdGEgcHJldHJ2w6F2YSwgbmFqbcOkIHByZSBTdW5zaGluZV9zY2FsZWQgKCoqVklGID0gOSwxMyoqKSBhIFJhZGlhdGlvbl9zY2FsZWQgKCoqVklGID0gNCw5OSoqKS4gDQoNCsWga8OhbG92YW5pZSBsZW4gdHJhbnNmb3JtdWplIHByZW1lbm7DqSBuYSBwb3Jvdm5hdGXEvm7DqSBtaWVya3ksIGFsZSBuZXJpZcWhaSBpY2ggdm7DunRvcm7DqSBrb3JlbMOhY2llLiBTdW5zaGluZV9zY2FsZWQgbcOhIG5lZ2F0w612bnkga29lZmljaWVudCAoKiotMSw1OSoqKSwgxI1vIGplIHYgcm96cG9yZSBzIG/EjWFrw6F2YW5pYW1pLCBhIG5hem5hxI11amUgcHJvYmzDqW15IHMgaW50ZXJwcmV0w6FjaW91IHYgZMO0c2xlZGt1IG11bHRpa29saW5lYXJpdHkuIA0KDQpUZW50byBwcsOtc3R1cCBqZSB1xb5pdG/EjW7DvSBwcmUgbnVtZXJpY2vDuiBzdGFiaWxpdHUsIGFsZSBzw6FtIG8gc2ViZSBuZW9kc3RyYcWIdWplIGtvcmVsw6FjaWUgbWVkemkgcHJlbWVubsO9bWkuDQoNCiMjIyA4LjQgQ29uZGl0aW9uIE51bWJlciBwbyDFoWvDoWxvdmFuw60NCg0KYGBge3J9DQpYX3NjYWxlZCA8LSBtb2RlbC5tYXRyaXgobW9kZWxfc2NhbGVkKVssIC0xXQ0KWHRYX3NjYWxlZCA8LSB0KFhfc2NhbGVkKSAlKiUgWF9zY2FsZWQNCnZsYXN0bmVfaG9kbm90eV9zY2FsZWQgPC0gZWlnZW4oWHRYX3NjYWxlZCkkdmFsdWVzDQoNCmNvbmRpdGlvbl9udW1iZXJfc2NhbGVkIDwtIHNxcnQobWF4KHZsYXN0bmVfaG9kbm90eV9zY2FsZWQpIC8gbWluKHZsYXN0bmVfaG9kbm90eV9zY2FsZWQpKQ0KY29uZGl0aW9uX251bWJlcl9zY2FsZWQNCmBgYA0KUG8gxaFrw6Fsb3ZhbsOtIHByZW1lbm7DvWNoIHNhIGNvbmRpdGlvbiBudW1iZXIgdsO9cmF6bmUgem7DrcW+aWwgeiBww7R2b2Ruw71jaCAqKjE0MCw5NSBuYSA2LDgwKiosIMSNbyBwcmVkc3RhdnVqZSB2w71yYXpuw6kgemxlcMWhZW5pZSBudW1lcmlja2VqIHN0YWJpbGl0eSBtb2RlbHUuDQoNCkhvZG5vdGEgNiw4MCBzYSBuYWNow6FkemEgdiBww6FzbWUgbsOtemtlaiBtdWx0aWtvbGluZWFyaXR5ICgqKnBvZCAxMCoqKSwgxI1vIG5hem5hxI11amUsIMW+ZSDFoWvDoWxvdmFuaWUgw7pzcGXFoW5lIHJlZHVrb3ZhbG8gbnVtZXJpY2vDuiBjaXRsaXZvc8WlIHbDvXBvxI10b3YuIA0KDQpUbyB6bmFtZW7DoSwgxb5lIG1hdGljYSBkaXpham51IGplIHRlcmF6IGxlcMWhaWUgcG9kbWllbmVuw6EgYSBvZGhhZHkgcmVncmVzbsO9Y2gga29lZmljaWVudG92IHPDuiBzdGFiaWxuZWrFoWllLiBBdsWhYWsgdG90byB6bGVwxaFlbmllIHNhIHTDvWthIGxlbiBudW1lcmlja2VqIHN0YWJpbGl0eSwgbmllIHbFoWFrIHrDoWtsYWRuw71jaCDFoXRhdGlzdGlja8O9Y2ggdnrFpWFob3YgbWVkemkgcHJlbWVubsO9bWksIGFrbyB1a2F6dWrDuiBzdMOhbGUgdnlzb2vDqSBWSUYgaG9kbm90eS4NCg0KIyMjIDguNSBUcmFuc2Zvcm3DoWNpYSBwcmVtZW5uw71jaA0KDQpgYGB7cn0NCm1vZGVsX2ludGVyYWN0aW9uIDwtIGxtKFRlbXBfTWVhbiB+IENsb3VkX0NvdmVyICogU3Vuc2hpbmUgKyBIdW1pZGl0eSArIFByZXNzdXJlICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgR2xvYmFsX1JhZGlhdGlvbiArIFByZWNpcGl0YXRpb24sDQogICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSB1ZGFqZSkNCnN1bW1hcnkobW9kZWxfaW50ZXJhY3Rpb24pDQoNCm1vZGVsX3F1YWRyYXRpYyA8LSBsbShUZW1wX01lYW4gfiBDbG91ZF9Db3ZlciArIEkoQ2xvdWRfQ292ZXJeMikgKyBIdW1pZGl0eSArIA0KICAgICAgICAgICAgICAgICAgICAgICBQcmVzc3VyZSArIEdsb2JhbF9SYWRpYXRpb24gKyBQcmVjaXBpdGF0aW9uICsgU3Vuc2hpbmUsDQogICAgICAgICAgICAgICAgICAgICBkYXRhID0gdWRhamUpDQpzdW1tYXJ5KG1vZGVsX3F1YWRyYXRpYykNCmBgYA0KTW9kZWwgcyBpbnRlcmFrY2lvdSBtZWR6aSBDbG91ZF9Db3ZlciBhIFN1bnNoaW5lIGRvc2lhaG9sIG5hanZ5xaHFocOtIHVwcmF2ZW7DvSAqKlLCsiA9IDAsNjIwMyoqIGEgdWvDoXphbCDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSBpbnRlcmFrxI1uw70gxI1sZW4gKCoqcCA9IDgsNDNlLTA3KiopLiANCg0KVG8gbmF6bmHEjXVqZSwgxb5lIHZwbHl2IHNsbmXEjW7DqWhvIHN2aXR1IG5hIHRlcGxvdHUgesOhdmlzw60gb2Qgw7pyb3ZuZSBvYmxhxI1ub3N0aSDigJMga29tcGxleG7DvSB2esWlYWgsIGt0b3LDvSBqZWRub2R1Y2jDvSBsaW5lw6FybnkgbW9kZWwgbmV6YWNoeXTDoXZhLiANCg0KTmFwcm90aSB0b211IGt2YWRyYXRpY2vDvSBtb2RlbCBzIENsb3VkX0NvdmVywrIgbmVwcmluaWVzb2wgemxlcMWhZW5pZSDigJMga3ZhZHJhdGlja8O9IMSNbGVuIG5pZSBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSAoKipwID0gMCw1MzEqKikgYSBSwrIgamUgbmnFvsWhw60uIA0KDQpNb2RlbCBzIGludGVyYWtjaW91IHRhayBwb27DumthIG5hamxlcMWhaWUgcmllxaFlbmllLCBrdG9yw6kgemFjaG92w6F2YSB2eXNva8O6IHByZWRpa3TDrXZudSBzaWx1IGEgesOhcm92ZcWIIGFkZWt2w6F0bmUgbW9kZWx1amUga29tcGxleG7DqSB2esWlYWh5IG1lZHppIG1ldGVvcm9sb2dpY2vDvW1pIHByZW1lbm7DvW1pLg0KDQojIyA5LiBQb3Jvdm5hbmllIG1vZGVsb3YNCg0KYGBge3J9DQptb2RlbHMgPC0gbGlzdCgiUMO0dm9kbsO9IG1vZGVsIiA9IG1vZGVsLA0KICAgICAgICAgICAgICAgIkJleiBTdW5zaGluZSIgPSBtb2RlbF9ub19zdW5zaGluZSwNCiAgICAgICAgICAgICAgICJCZXogR2xvYmFsX1JhZGlhdGlvbiIgPSBtb2RlbF9ub19yYWRpYXRpb24sDQogICAgICAgICAgICAgICAiQmV6IENsb3VkX0NvdmVyIiA9IG1vZGVsX25vX2Nsb3VkLA0KICAgICAgICAgICAgICAgIlMgaW50ZXJha2Npb3UiID0gbW9kZWxfaW50ZXJhY3Rpb24sDQogICAgICAgICAgICAgICAixaBrw6Fsb3ZhbsO9IG1vZGVsIiA9IG1vZGVsX3NjYWxlZCkNCg0KY29tcGFyaXNvbiA8LSBkYXRhLmZyYW1lKA0KICBNb2RlbCA9IG5hbWVzKG1vZGVscyksDQogIFIyID0gc2FwcGx5KG1vZGVscywgZnVuY3Rpb24obSkgcm91bmQoc3VtbWFyeShtKSRyLnNxdWFyZWQsIDQpKSwNCiAgQWRqX1IyID0gc2FwcGx5KG1vZGVscywgZnVuY3Rpb24obSkgcm91bmQoc3VtbWFyeShtKSRhZGouci5zcXVhcmVkLCA0KSksDQogIEFJQyA9IHJvdW5kKHNhcHBseShtb2RlbHMsIEFJQyksIDIpLA0KICBCSUMgPSByb3VuZChzYXBwbHkobW9kZWxzLCBCSUMpLCAyKQ0KKQ0KDQpwcmludChjb21wYXJpc29uKQ0KYGBgDQpNb2RlbCBzIGludGVyYWtjaW91IG1lZHppIENsb3VkX0NvdmVyIGEgU3Vuc2hpbmUgamUgbmFqbGVwxaHDrSBwb2TEvmEgdsWhZXRrw71jaCBrcml0w6lyacOtIOKAkyBtw6EgbmFqdnnFocWhw60gdXByYXZlbsO9ICoqUsKyID0gMCw2MjAzKiosIG5ham5pxb7FoWllICoqQUlDID0gMjE0ODIsMDkqKiBhICoqQklDID0gMjE1MzcsOTIqKi4gDQoNCk1vZGVsIGJleiBHbG9iYWxfUmFkaWF0aW9uIHbDvXJhem5lIHphb3N0w6F2YSBzICoqUsKyID0gMCwzODg0KiouIA0KDQpQw7R2b2Ruw70gYSDFoWvDoWxvdmFuw70gbW9kZWwgc8O6IMWhdGF0aXN0aWNreSBla3ZpdmFsZW50bsOpLiANCg0KTmFqbGVwxaFvdSBzdHJhdMOpZ2lvdSBuYSByaWXFoWVuaWUgbXVsdGlrb2xpbmVhcml0eSBqZSBwcmlkYW5pZSBpbnRlcmFrxI1uw6lobyDEjWxlbmEgbWVkemkgQ2xvdWRfQ292ZXIgYSBTdW5zaGluZSwgxI1vIHpsZXDFoXVqZSBwcmVkaWt0w612bnUgc2lsdSBhIGFkZWt2w6F0bmUgemFjaHl0w6F2YSBrb21wbGV4bsOpIG1ldGVvcm9sb2dpY2vDqSB2esWlYWh5Lg0KDQojIyAxMC4gWmhybnV0aWUNCg0KQW5hbMO9emEgbXVsdGlrb2xpbmVhcml0eSB2IG1ldGVvcm9sb2dpY2tvbSBtb2RlbGkgcHJlIG1lc3RvIEJhemlsZWogcG90dnJkaWxhIHByw610b21ub3PFpSB2w71yYXpuZWogbXVsdGlrb2xpbmVhcml0eSBtZWR6aSBrxL7DusSNb3bDvW1pIHByZW1lbm7DvW1pLCBuYWptw6QgbWVkemkgU3Vuc2hpbmUsIEdsb2JhbF9SYWRpYXRpb24gYSBDbG91ZF9Db3Zlci4gVGVudG8gamF2IGplIHNww7Rzb2JlbsO9IHByaXJvZHplbsO9bWkgZnl6aWvDoWxueW1pIHZ6xaVhaG1pIHYgYXRtb3Nmw6lyZSDigJMgdnnFocWhaWEgb2JsYcSNbm9zxaUgcHJpcm9kemVuZSByZWR1a3VqZSBzbG5lxI1uw70gc3ZpdCBhIGdsb2LDoWxuZSDFvmlhcmVuaWUuDQoNCkRpYWdub3N0aWNrw6kgbsOhc3Ryb2plIGtvbnppc3RlbnRuZSBpZGVudGlmaWtvdmFsaSBwcm9ibMOpbTogDQoNCi0gVklGIHByZSBTdW5zaGluZSBkb3NhaG92YWwgKioxMSwxOCoqICh2eXNva8OhIG11bHRpa29saW5lYXJpdGEpIGEgY29uZGl0aW9uIG51bWJlciBww7R2b2Ruw6lobyBtb2RlbHUgYm9sICoqMTQwLDk1KiogKHZlxL5taSB2eXNva8OhIG11bHRpa29saW5lYXJpdGEpLiBOYXByaWVrIHRlanRvIG11bHRpa29saW5lYXJpdGUgc2kgbW9kZWwgemFjaG92YWwgdnlzb2vDuiBwcmVkaWt0w612bnUgc2lsdSBzICoqUsKyID0gMCw2MTc5KiosIMSNbyBuYXpuYcSNdWplIGRvYnLDqSB6YWNoeXRlbmllIHZ6xaVhaG92IHYgZMOhdGFjaC4NCg0KVGVzdG92YW7DqSByaWXFoWVuaWEgbXVsdGlrb2xpbmVhcml0eSB1a8OhemFsaSwgxb5lIG5hamVmZWt0w612bmVqxaFvdSBzdHJhdMOpZ2lvdSBqZSBwcmlkYW5pZSBpbnRlcmFrxI1uw6lobyDEjWxlbnUgbWVkemkgQ2xvdWRfQ292ZXIgYSBTdW5zaGluZS4gVGVudG8gbW9kZWwgZG9zaWFob2wgbmFqdnnFocWhaXUgZXhwbGFuYcSNbsO6IHNpbHUgKCoqUsKyID0gMCw2MjAzKiopIGEgbmFqbmnFvsWhaWUgaW5mb3JtYcSNbsOpIGtyaXTDqXJpw6EgKCoqQUlDID0gMjE0ODIsMDkqKiksIHByacSNb20gYWRla3bDoXRuZSB6YWNoeXRpbCBrb21wbGV4bsO9IHZ6xaVhaCBtZWR6aSB0w71taXRvIHByZW1lbm7DvW1pLiBJbnRlcmFrxI1uw70gxI1sZW4gYm9sIMWhdGF0aXN0aWNreSB2w716bmFtbsO9ICgqKnAgPSA4LDQzZS0wNyoqKSwgxI1vIHBvdHZyZHp1amUsIMW+ZSB2cGx5diBzbG5lxI1uw6lobyBzdml0dSBuYSB0ZXBsb3R1IHrDoXZpc8OtIG9kIMO6cm92bmUgb2JsYcSNbm9zdGkuDQoNCkFsdGVybmF0w612bmUgcmllxaFlbmllIOKAkyB2eW5lY2hhbmllIHByZW1lbm5laiBTdW5zaGluZSDigJMgc8OtY2UgcmVkdWtvdmFsbyBtdWx0aWtvbGluZWFyaXR1ICgqKlZJRiB2xaFldGvDvWNoIHByZW1lbm7DvWNoIHBvZCAyLDMqKiksIGFsZSB2aWVkbG8gayBtaWVybmVtdSBwb2tsZXN1IHByZWRpa3TDrXZuZWogc2lseS4gVnluZWNoYW5pZSBHbG9iYWxfUmFkaWF0aW9uIHNhIHVrw6F6YWxvIGFrbyBuZXByaWphdGXEvm7DqSwga2XEj8W+ZSBzcMO0c29iaWxvIHbDvXJhem7DuiBzdHJhdHUga3ZhbGl0eSBtb2RlbHUgKCoqUsKyIHBva2xlc29sIG5hIDAsMzg4NCoqKS4NCg0KDQoNCg0KDQoNCg0K