Contexto

La base de datos es de la universidad de Nueva York y contiene 90 observaciones que incluyen los costos de 6 aerolíneas estadounidenses durante 15 años, desde 1970 a 1984.

Las variables que incluye son:

  • I = Aerolinea
  • T = Año
  • Q = Output
  • C = Costo Total en $1,000 USD
  • PF = Precio del combustible
  • LF = Factor de Carga (Utilización promedio de la capacidad de la flota)

Fuente: Tabla F7.1

Instalar Paqueterias y Librerias

#install.packages("plm")
#install.packages("tidyverse")
#install.packages("forecast")
#install.packages("lavaan")
#install.packages("lavaanPlot")
#install.packages(DataExplorer)
#install.packages("ggplot2")
#install.packages("gplots")
library(plm)
library(tidyverse)
library(forecast)
library(lavaan)
library(lavaanPlot)
library(DataExplorer)
library(ggplot2)
library(gplots)

Importar Base de Datos

df <- read.csv("costos.csv")

Análisis Descriptivo

summary(df)
##        I             T            C                 Q          
##  Min.   :1.0   Min.   : 1   Min.   :  68978   Min.   :0.03768  
##  1st Qu.:2.0   1st Qu.: 4   1st Qu.: 292046   1st Qu.:0.14213  
##  Median :3.5   Median : 8   Median : 637001   Median :0.30503  
##  Mean   :3.5   Mean   : 8   Mean   :1122524   Mean   :0.54499  
##  3rd Qu.:5.0   3rd Qu.:12   3rd Qu.:1345968   3rd Qu.:0.94528  
##  Max.   :6.0   Max.   :15   Max.   :4748320   Max.   :1.93646  
##        PF                LF        
##  Min.   : 103795   Min.   :0.4321  
##  1st Qu.: 129848   1st Qu.:0.5288  
##  Median : 357434   Median :0.5661  
##  Mean   : 471683   Mean   :0.5605  
##  3rd Qu.: 849840   3rd Qu.:0.5947  
##  Max.   :1015610   Max.   :0.6763
str(df)
## 'data.frame':    90 obs. of  6 variables:
##  $ I : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ T : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ C : int  1140640 1215690 1309570 1511530 1676730 1823740 2022890 2314760 2639160 3247620 ...
##  $ Q : num  0.953 0.987 1.092 1.176 1.16 ...
##  $ PF: int  106650 110307 110574 121974 196606 265609 263451 316411 384110 569251 ...
##  $ LF: num  0.534 0.532 0.548 0.541 0.591 ...
#Convertir Tipo de Variables

## Transformar Aerolinea a Factor
df$I <- as.factor(df$I)
## Agregar columna de año (1970 - 1984)
df$Y <- df$T + 1969

#Revisar Cambios
summary(df)
##  I            T            C                 Q                 PF         
##  1:15   Min.   : 1   Min.   :  68978   Min.   :0.03768   Min.   : 103795  
##  2:15   1st Qu.: 4   1st Qu.: 292046   1st Qu.:0.14213   1st Qu.: 129848  
##  3:15   Median : 8   Median : 637001   Median :0.30503   Median : 357434  
##  4:15   Mean   : 8   Mean   :1122524   Mean   :0.54499   Mean   : 471683  
##  5:15   3rd Qu.:12   3rd Qu.:1345968   3rd Qu.:0.94528   3rd Qu.: 849840  
##  6:15   Max.   :15   Max.   :4748320   Max.   :1.93646   Max.   :1015610  
##        LF               Y       
##  Min.   :0.4321   Min.   :1970  
##  1st Qu.:0.5288   1st Qu.:1973  
##  Median :0.5661   Median :1977  
##  Mean   :0.5605   Mean   :1977  
##  3rd Qu.:0.5947   3rd Qu.:1981  
##  Max.   :0.6763   Max.   :1984
str(df)
## 'data.frame':    90 obs. of  7 variables:
##  $ I : Factor w/ 6 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ T : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ C : int  1140640 1215690 1309570 1511530 1676730 1823740 2022890 2314760 2639160 3247620 ...
##  $ Q : num  0.953 0.987 1.092 1.176 1.16 ...
##  $ PF: int  106650 110307 110574 121974 196606 265609 263451 316411 384110 569251 ...
##  $ LF: num  0.534 0.532 0.548 0.541 0.591 ...
##  $ Y : num  1970 1971 1972 1973 1974 ...
# Obtener analisis exploratorio mediante DataExplorer
# create_report(df)
plot_missing(df)

plot_histogram(df)

plot_correlation(df)

# Graficar con ggplot2
ggplot(df, aes(x = Y, y = C, color = I, group = I)) +
  geom_line() +
  labs(title = "Costo por Aerolinea 1970 - 1984", x = "Año",
       y = "Costo (miles de USD)", color = "Aerolinea") +
  theme_minimal()

ggplot(df, aes(x = Y, y = Q, color = I, group = I)) +
  geom_line() +
  labs(title = "Millas Voladas por Aerolinea 1970 - 1984", x = "Año",
       y = "Indice Normalizado", color = "Aerolinea") +
  theme_minimal()

ggplot(df, aes(x = Y, y = PF, color = I, group = I)) +
  geom_line() +
  labs(title = "Precio Combustible por Aerolinea 1970 - 1984", x = "Año",
       y = "Precio (USD)", color = "Aerolinea") +
  theme_minimal()

ggplot(df, aes(x = Y, y = LF, color = I, group = I)) +
  geom_line() +
  labs(title = "Factor de carga por Aerolinea 1970 - 1984", x = "Año",
       y = "Porcentaje", color = "Aerolinea") +
  theme_minimal()

Tema 1: Datos de Panel

Heterogeniedad

plotmeans(C ~ I, main = "Heterogeniedad entre aerolineas", xlab = "Aerolineas", ylab = "Costo (miles de USD)", data = df)

Como el valor promedio (círculo) y el rango intercuartil (lineas azules) varian entre individuos, se identifica presencia de heterogeniedad.

Creación de Datos de Panel

df_panel <- pdata.frame(df, index = c("I","Y"))
df_panel <- df_panel %>%
  select(-c("I","T","Y"))

Generacion de Modelos

Modelo 1: Regresion Agrupada (Pooled)

El Modelo de Regresión Agrupada (Pooled) es una técnica de estimación en datos de panel donde se asume que no hay efectos individuales específicos para cada unidad, ni variaciones en el tiempo.
¡Ignora Heterogeniedades!

pooled <- plm(C ~ Q + PF + LF, data = df_panel, model = "pooling")
summary(pooled)
## Pooling Model
## 
## Call:
## plm(formula = C ~ Q + PF + LF, data = df_panel, model = "pooling")
## 
## Balanced Panel: n = 6, T = 15, N = 90
## 
## Residuals:
##    Min. 1st Qu.  Median 3rd Qu.    Max. 
## -520654 -250270   37333  208690  849700 
## 
## Coefficients:
##                Estimate  Std. Error t-value  Pr(>|t|)    
## (Intercept)  1.1586e+06  3.6059e+05  3.2129   0.00185 ** 
## Q            2.0261e+06  6.1807e+04 32.7813 < 2.2e-16 ***
## PF           1.2253e+00  1.0372e-01 11.8138 < 2.2e-16 ***
## LF          -3.0658e+06  6.9633e+05 -4.4027 3.058e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Total Sum of Squares:    1.2647e+14
## Residual Sum of Squares: 6.8177e+12
## R-Squared:      0.94609
## Adj. R-Squared: 0.94421
## F-statistic: 503.118 on 3 and 86 DF, p-value: < 2.22e-16
#Prueba Breusch-Pagan:
plmtest(pooled, type = "bp")
## 
##  Lagrange Multiplier Test - (Breusch-Pagan)
## 
## data:  C ~ Q + PF + LF
## chisq = 0.61309, df = 1, p-value = 0.4336
## alternative hypothesis: significant effects

Como el p-value es mayor a 0.05, podemos utilizar el Modelo Pooled

Modelo 2: Efectos Fijos (Within)

within <- plm(C ~ Q + PF + LF, data = df_panel, model = "within")
summary(within)
## Oneway (individual) effect Within Model
## 
## Call:
## plm(formula = C ~ Q + PF + LF, data = df_panel, model = "within")
## 
## Balanced Panel: n = 6, T = 15, N = 90
## 
## Residuals:
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
## -551783 -159259    1796       0  137226  499296 
## 
## Coefficients:
##       Estimate  Std. Error t-value  Pr(>|t|)    
## Q   3.3190e+06  1.7135e+05 19.3694 < 2.2e-16 ***
## PF  7.7307e-01  9.7319e-02  7.9437 9.698e-12 ***
## LF -3.7974e+06  6.1377e+05 -6.1869 2.375e-08 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Total Sum of Squares:    5.0776e+13
## Residual Sum of Squares: 3.5865e+12
## R-Squared:      0.92937
## Adj. R-Squared: 0.92239
## F-statistic: 355.254 on 3 and 81 DF, p-value: < 2.22e-16

Modelo 3: Efectos Aleatorios (Random) - Walhus

walhus <- plm(C ~ Q + PF + LF, data = df_panel, model = "random", random.method = "walhus")
summary(walhus)
## Oneway (individual) effect Random Effect Model 
##    (Wallace-Hussain's transformation)
## 
## Call:
## plm(formula = C ~ Q + PF + LF, data = df_panel, model = "random", 
##     random.method = "walhus")
## 
## Balanced Panel: n = 6, T = 15, N = 90
## 
## Effects:
##                     var   std.dev share
## idiosyncratic 7.339e+10 2.709e+05 0.969
## individual    2.363e+09 4.861e+04 0.031
## theta: 0.1788
## 
## Residuals:
##    Min. 1st Qu.  Median 3rd Qu.    Max. 
## -524180 -243611   39332  199517  824905 
## 
## Coefficients:
##                Estimate  Std. Error z-value  Pr(>|z|)    
## (Intercept)  1.1267e+06  3.6994e+05  3.0455  0.002323 ** 
## Q            2.0647e+06  7.1927e+04 28.7051 < 2.2e-16 ***
## PF           1.2075e+00  1.0358e-01 11.6578 < 2.2e-16 ***
## LF          -3.0314e+06  7.1431e+05 -4.2438 2.198e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Total Sum of Squares:    1.0182e+14
## Residual Sum of Squares: 6.5784e+12
## R-Squared:      0.93539
## Adj. R-Squared: 0.93314
## Chisq: 1245.09 on 3 DF, p-value: < 2.22e-16

Modelo 4: Efectos Aleatorios (Random) - Amemiya

amemiya <- plm(C ~ Q + PF + LF, data = df_panel, model = "random", random.method = "amemiya")
summary(amemiya)
## Oneway (individual) effect Random Effect Model 
##    (Amemiya's transformation)
## 
## Call:
## plm(formula = C ~ Q + PF + LF, data = df_panel, model = "random", 
##     random.method = "amemiya")
## 
## Balanced Panel: n = 6, T = 15, N = 90
## 
## Effects:
##                     var   std.dev share
## idiosyncratic 4.270e+10 2.066e+05 0.084
## individual    4.640e+11 6.812e+05 0.916
## theta: 0.9219
## 
## Residuals:
##    Min. 1st Qu.  Median 3rd Qu.    Max. 
## -603585 -144415   22641  158005  485417 
## 
## Coefficients:
##                Estimate  Std. Error z-value  Pr(>|z|)    
## (Intercept)  1.0746e+06  4.2105e+05  2.5522    0.0107 *  
## Q            3.2090e+06  1.6482e+05 19.4695 < 2.2e-16 ***
## PF           8.1014e-01  9.6147e-02  8.4260 < 2.2e-16 ***
## LF          -3.7168e+06  6.1330e+05 -6.0603 1.359e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Total Sum of Squares:    5.1238e+13
## Residual Sum of Squares: 3.8227e+12
## R-Squared:      0.92539
## Adj. R-Squared: 0.92279
## Chisq: 1066.71 on 3 DF, p-value: < 2.22e-16

Modelo 5: Efectos Aleatorios (Random) - Nerlove

nerlove <- plm(C ~ Q + PF + LF, data = df_panel, model = "random", random.method = "nerlove")
summary(nerlove)
## Oneway (individual) effect Random Effect Model 
##    (Nerlove's transformation)
## 
## Call:
## plm(formula = C ~ Q + PF + LF, data = df_panel, model = "random", 
##     random.method = "nerlove")
## 
## Balanced Panel: n = 6, T = 15, N = 90
## 
## Effects:
##                     var   std.dev share
## idiosyncratic 3.985e+10 1.996e+05 0.066
## individual    5.602e+11 7.485e+05 0.934
## theta: 0.9313
## 
## Residuals:
##    Min. 1st Qu.  Median 3rd Qu.    Max. 
## -601947 -145039   18713  154903  483623 
## 
## Coefficients:
##                Estimate  Std. Error z-value  Pr(>|z|)    
## (Intercept)  1.0752e+06  4.4535e+05  2.4142   0.01577 *  
## Q            3.2323e+06  1.6521e+05 19.5652 < 2.2e-16 ***
## PF           8.0229e-01  9.5804e-02  8.3743 < 2.2e-16 ***
## LF          -3.7338e+06  6.0963e+05 -6.1247 9.084e-10 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Total Sum of Squares:    5.1133e+13
## Residual Sum of Squares: 3.7726e+12
## R-Squared:      0.92622
## Adj. R-Squared: 0.92365
## Chisq: 1079.63 on 3 DF, p-value: < 2.22e-16

Comparando las R2 ajustadas de los Modelos Aleatorios, el mejor método obtenido es el de Walhus.

Efectos Fijos Vs Efectos Aleatorios

phtest(within,walhus)
## 
##  Hausman Test
## 
## data:  C ~ Q + PF + LF
## chisq = 65.039, df = 3, p-value = 4.919e-14
## alternative hypothesis: one model is inconsistent

En caso de elegir algun modelo de Efectos Fijos o Aleatorios, el mejor en esta situación es el de Efectos Fijos ya que el valor de p-value es menor que 0.05.

Tema 2: Series de Tiempo

Generar Serie de Tiempo

# Filtrar la Aerolinea 1 (ejemplo)
df_a1 <- df[df$I == 1,]
# Convertir a Series de Tiempo
ts_a1 <- ts(df_a1$C, start = 1970, frequency = 1)

# Filtrar la Aerolinea 2 (ejemplo)
df_a2 <- df[df$I == 2,]
# Convertir a Series de Tiempo
ts_a2 <- ts(df_a2$C, start = 1970, frequency = 1)

# Filtrar la Aerolinea 3 (ejemplo)
df_a3 <- df[df$I == 3,]
# Convertir a Series de Tiempo
ts_a3 <- ts(df_a3$C, start = 1970, frequency = 1)

# Filtrar la Aerolinea 4 (ejemplo)
df_a4 <- df[df$I == 4,]
# Convertir a Series de Tiempo
ts_a4 <- ts(df_a4$C, start = 1970, frequency = 1)

# Filtrar la Aerolinea 5 (ejemplo)
df_a5 <- df[df$I == 5,]
# Convertir a Series de Tiempo
ts_a5 <- ts(df_a5$C, start = 1970, frequency = 1)

# Filtrar la Aerolinea 6 (ejemplo)
df_a6 <- df[df$I == 6,]
# Convertir a Series de Tiempo
ts_a6 <- ts(df_a6$C, start = 1970, frequency = 1)

Generacion de Modelos

arima_a1 <- auto.arima(ts_a1)
summary(arima_a1)
## Series: ts_a1 
## ARIMA(0,1,0) with drift 
## 
## Coefficients:
##           drift
##       257691.43
## s.e.   44508.78
## 
## sigma^2 = 2.987e+10:  log likelihood = -188.19
## AIC=380.37   AICc=381.46   BIC=381.65
## 
## Training set error measures:
##                    ME   RMSE      MAE       MPE     MAPE     MASE      ACF1
## Training set 58.86321 160892 129527.1 -1.742419 5.395122 0.502644 0.4084903
arima_a2 <- auto.arima(ts_a2)
summary(arima_a2)
## Series: ts_a2 
## ARIMA(0,2,0) 
## 
## sigma^2 = 1.392e+10:  log likelihood = -170.26
## AIC=342.53   AICc=342.89   BIC=343.09
## 
## Training set error measures:
##                    ME     RMSE      MAE      MPE     MAPE      MASE      ACF1
## Training set 11689.89 109830.2 79466.33 1.387268 3.747652 0.3056315 0.3172172
arima_a3 <- auto.arima(ts_a3)
summary(arima_a3)
## Series: ts_a3 
## ARIMA(0,1,0) with drift 
## 
## Coefficients:
##          drift
##       63155.14
## s.e.  13344.11
## 
## sigma^2 = 2.685e+09:  log likelihood = -171.32
## AIC=346.64   AICc=347.74   BIC=347.92
## 
## Training set error measures:
##                    ME     RMSE      MAE        MPE     MAPE     MASE       ACF1
## Training set 14.87618 48235.79 38474.72 -0.9277567 5.324145 0.538349 0.09130379
arima_a4 <- auto.arima(ts_a4)
summary(arima_a4)
## Series: ts_a4 
## ARIMA(0,2,0) 
## 
## sigma^2 = 1.469e+09:  log likelihood = -155.65
## AIC=313.3   AICc=313.66   BIC=313.86
## 
## Training set error measures:
##                    ME    RMSE      MAE      MPE     MAPE      MASE      ACF1
## Training set 7232.074 35684.5 27472.98 1.761789 5.046326 0.2977402 0.1925091
arima_a5 <- auto.arima(ts_a5)
summary(arima_a5)
## Series: ts_a5 
## ARIMA(1,2,0) 
## 
## Coefficients:
##           ar1
##       -0.4543
## s.e.   0.2354
## 
## sigma^2 = 775697764:  log likelihood = -151.09
## AIC=306.18   AICc=307.38   BIC=307.31
## 
## Training set error measures:
##                   ME     RMSE      MAE      MPE     MAPE      MASE        ACF1
## Training set 3061.06 24911.01 14171.99 2.393894 4.771228 0.3823654 0.008627682
arima_a6 <- auto.arima(ts_a6)
summary(arima_a6)
## Series: ts_a6 
## ARIMA(1,2,0) 
## 
## Coefficients:
##          ar1
##       0.5824
## s.e.  0.2281
## 
## sigma^2 = 386182350:  log likelihood = -146.65
## AIC=297.3   AICc=298.5   BIC=298.43
## 
## Training set error measures:
##                    ME     RMSE      MAE      MPE     MAPE      MASE       ACF1
## Training set 6829.403 17576.86 10190.16 2.076518 3.550582 0.1516841 -0.2989742

La serie de tiempo ARIMA con menor MAPE fue el de la Aerolina 6 por lo que se estara trabajando con esta.

Generar Pronosticos

pronostico_a6 <- forecast(arima_a6, level = 95, h = 5)
pronostico_a6
##      Point Forecast   Lo 95   Hi 95
## 1985        1234478 1195962 1272994
## 1986        1471026 1364365 1577687
## 1987        1714311 1510670 1917953
## 1988        1961521 1635113 2287929
## 1989        2211016 1738872 2683160
plot(pronostico_a6, main = "Pronóstico de Costo Total Aerolinea 6",
     xlab = "Año", ylab = "Miles de USD")

Tema 3: Modelo de Ecuaciones Estructurales (SEM)

Estructurar el Modelo

modelo <- '
          # Variables Latentes
          #Regresiones
          C ~ Q + PF + LF + I + Y
          Q ~ PF + I
          PF ~ Y
          LF ~ I
          #Varianzas y Covarianzas
          C ~~ C
          Q ~~ Q
          PF ~~ PF
          LF ~~ LF
          #Interceptos
          '

Generar el Analisis Factorial Confirmatorio

# Escalar la base de datos
df_escalada <- df
df_escalada$I <- as.numeric(df_escalada$I)
df_escalada <- scale(df_escalada)

#Analisis Factorial
cfa <- cfa(modelo, df_escalada)
summary(cfa)
## lavaan 0.6-19 ended normally after 3 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        13
## 
##   Number of observations                            90
## 
## Model Test User Model:
##                                                       
##   Test statistic                                63.804
##   Degrees of freedom                                 5
##   P-value (Chi-square)                           0.000
## 
## Parameter Estimates:
## 
##   Standard errors                             Standard
##   Information                                 Expected
##   Information saturated (h1) model          Structured
## 
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   C ~                                                 
##     Q                 1.000    0.053   18.826    0.000
##     PF                0.194    0.065    3.000    0.003
##     LF               -0.154    0.025   -6.248    0.000
##     I                 0.105    0.052    1.999    0.046
##     Y                 0.140    0.063    2.211    0.027
##   Q ~                                                 
##     PF                0.239    0.046    5.213    0.000
##     I                -0.871    0.046  -18.985    0.000
##   PF ~                                                
##     Y                 0.931    0.038   24.233    0.000
##   LF ~                                                
##     I                -0.340    0.099   -3.429    0.001
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##    .C                 0.048    0.007    6.708    0.000
##    .Q                 0.187    0.028    6.708    0.000
##    .PF                0.131    0.020    6.708    0.000
##    .LF                0.875    0.130    6.708    0.000

Generar el Modelo de Ecuaciones Estructurales

lavaanPlot(cfa)

Aplicacion de Shiny (SEM)

Link de la Aplicación

LS0tDQp0aXRsZTogIkNOMSAtIGNvc3RvcyBlbiBBZXJvbGluZWFzIg0KYXV0aG9yOiAiUm9kcmlnbyBBcnJveW8gLSBBMDE3NDczODAiDQpkYXRlOiAiMjAyNS0wMi0yNCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIHRoZW1lOiBkYXJrbHkNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQotLS0NCg0KIVtdKGF2aW9uLmdpZikNCg0KIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICoqQ29udGV4dG8qKiA8L3NwYW4+DQpMYSBiYXNlIGRlIGRhdG9zIGVzIGRlIGxhIHVuaXZlcnNpZGFkIGRlIE51ZXZhIFlvcmsgeSBjb250aWVuZSA5MCBvYnNlcnZhY2lvbmVzIHF1ZSBpbmNsdXllbiBsb3MgY29zdG9zIGRlIDYgYWVyb2zDrW5lYXMgZXN0YWRvdW5pZGVuc2VzIGR1cmFudGUgMTUgYcOxb3MsIGRlc2RlIDE5NzAgYSAxOTg0LiAgDQoNCkxhcyAqKnZhcmlhYmxlcyoqIHF1ZSBpbmNsdXllIHNvbjogIA0KDQoqICoqSSoqID0gQWVyb2xpbmVhDQoqICoqVCoqID0gQcOxbw0KKiAqKlEqKiA9IE91dHB1dA0KKiAqKkMqKiA9IENvc3RvIFRvdGFsIGVuICQxLDAwMCBVU0QNCiogKipQRioqID0gUHJlY2lvIGRlbCBjb21idXN0aWJsZQ0KKiAqKkxGKiogPSBGYWN0b3IgZGUgQ2FyZ2EgKFV0aWxpemFjacOzbiBwcm9tZWRpbyBkZSBsYSBjYXBhY2lkYWQgZGUgbGEgZmxvdGEpICANCg0KRnVlbnRlOg0KW1RhYmxhIEY3LjFdKGh0dHBzOi8vcGFnZXMuc3Rlcm4ubnl1LmVkdS9+d2dyZWVuZS9UZXh0L3RhYmxlcy90YWJsZWxpc3Q1Lmh0bSkNCg0KDQojIDxzcGFuIHN0eWxlID0gImNvbG9yOiBvcmFuZ2U7Ij4gKipJbnN0YWxhciBQYXF1ZXRlcmlhcyB5IExpYnJlcmlhcyoqIDwvc3Bhbj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojaW5zdGFsbC5wYWNrYWdlcygicGxtIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KI2luc3RhbGwucGFja2FnZXMoImZvcmVjYXN0IikNCiNpbnN0YWxsLnBhY2thZ2VzKCJsYXZhYW4iKQ0KI2luc3RhbGwucGFja2FnZXMoImxhdmFhblBsb3QiKQ0KI2luc3RhbGwucGFja2FnZXMoRGF0YUV4cGxvcmVyKQ0KI2luc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KI2luc3RhbGwucGFja2FnZXMoImdwbG90cyIpDQoNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShwbG0pDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZm9yZWNhc3QpDQpsaWJyYXJ5KGxhdmFhbikNCmxpYnJhcnkobGF2YWFuUGxvdCkNCmxpYnJhcnkoRGF0YUV4cGxvcmVyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShncGxvdHMpDQpgYGANCg0KIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICoqSW1wb3J0YXIgQmFzZSBkZSBEYXRvcyoqIDwvc3Bhbj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkZiA8LSByZWFkLmNzdigiY29zdG9zLmNzdiIpDQpgYGANCg0KIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICoqQW7DoWxpc2lzIERlc2NyaXB0aXZvKiogPC9zcGFuPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnN1bW1hcnkoZGYpDQpzdHIoZGYpDQoNCiNDb252ZXJ0aXIgVGlwbyBkZSBWYXJpYWJsZXMNCg0KIyMgVHJhbnNmb3JtYXIgQWVyb2xpbmVhIGEgRmFjdG9yDQpkZiRJIDwtIGFzLmZhY3RvcihkZiRJKQ0KIyMgQWdyZWdhciBjb2x1bW5hIGRlIGHDsW8gKDE5NzAgLSAxOTg0KQ0KZGYkWSA8LSBkZiRUICsgMTk2OQ0KDQojUmV2aXNhciBDYW1iaW9zDQpzdW1tYXJ5KGRmKQ0Kc3RyKGRmKQ0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgT2J0ZW5lciBhbmFsaXNpcyBleHBsb3JhdG9yaW8gbWVkaWFudGUgRGF0YUV4cGxvcmVyDQojIGNyZWF0ZV9yZXBvcnQoZGYpDQpwbG90X21pc3NpbmcoZGYpDQpwbG90X2hpc3RvZ3JhbShkZikNCnBsb3RfY29ycmVsYXRpb24oZGYpDQoNCiMgR3JhZmljYXIgY29uIGdncGxvdDINCmdncGxvdChkZiwgYWVzKHggPSBZLCB5ID0gQywgY29sb3IgPSBJLCBncm91cCA9IEkpKSArDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh0aXRsZSA9ICJDb3N0byBwb3IgQWVyb2xpbmVhIDE5NzAgLSAxOTg0IiwgeCA9ICJBw7FvIiwNCiAgICAgICB5ID0gIkNvc3RvIChtaWxlcyBkZSBVU0QpIiwgY29sb3IgPSAiQWVyb2xpbmVhIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KZ2dwbG90KGRmLCBhZXMoeCA9IFksIHkgPSBRLCBjb2xvciA9IEksIGdyb3VwID0gSSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHRpdGxlID0gIk1pbGxhcyBWb2xhZGFzIHBvciBBZXJvbGluZWEgMTk3MCAtIDE5ODQiLCB4ID0gIkHDsW8iLA0KICAgICAgIHkgPSAiSW5kaWNlIE5vcm1hbGl6YWRvIiwgY29sb3IgPSAiQWVyb2xpbmVhIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KZ2dwbG90KGRmLCBhZXMoeCA9IFksIHkgPSBQRiwgY29sb3IgPSBJLCBncm91cCA9IEkpKSArDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gQ29tYnVzdGlibGUgcG9yIEFlcm9saW5lYSAxOTcwIC0gMTk4NCIsIHggPSAiQcOxbyIsDQogICAgICAgeSA9ICJQcmVjaW8gKFVTRCkiLCBjb2xvciA9ICJBZXJvbGluZWEiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpnZ3Bsb3QoZGYsIGFlcyh4ID0gWSwgeSA9IExGLCBjb2xvciA9IEksIGdyb3VwID0gSSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHRpdGxlID0gIkZhY3RvciBkZSBjYXJnYSBwb3IgQWVyb2xpbmVhIDE5NzAgLSAxOTg0IiwgeCA9ICJBw7FvIiwNCiAgICAgICB5ID0gIlBvcmNlbnRhamUiLCBjb2xvciA9ICJBZXJvbGluZWEiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IG9yYW5nZTsiPiAqKlRlbWEgMTogRGF0b3MgZGUgUGFuZWwqKiA8L3NwYW4+DQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICpIZXRlcm9nZW5pZWRhZCogPC9zcGFuPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBsb3RtZWFucyhDIH4gSSwgbWFpbiA9ICJIZXRlcm9nZW5pZWRhZCBlbnRyZSBhZXJvbGluZWFzIiwgeGxhYiA9ICJBZXJvbGluZWFzIiwgeWxhYiA9ICJDb3N0byAobWlsZXMgZGUgVVNEKSIsIGRhdGEgPSBkZikNCmBgYA0KDQpDb21vIGVsIHZhbG9yIHByb21lZGlvIChjw61yY3VsbykgeSBlbCByYW5nbyBpbnRlcmN1YXJ0aWwgKGxpbmVhcyBhenVsZXMpIHZhcmlhbiBlbnRyZSBpbmRpdmlkdW9zLCBzZSBpZGVudGlmaWNhIHByZXNlbmNpYSBkZSAqKmhldGVyb2dlbmllZGFkKiouICANCg0KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IG9yYW5nZTsiPiAqQ3JlYWNpw7NuIGRlIERhdG9zIGRlIFBhbmVsKiA8L3NwYW4+DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGZfcGFuZWwgPC0gcGRhdGEuZnJhbWUoZGYsIGluZGV4ID0gYygiSSIsIlkiKSkNCmRmX3BhbmVsIDwtIGRmX3BhbmVsICU+JQ0KICBzZWxlY3QoLWMoIkkiLCJUIiwiWSIpKQ0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiBvcmFuZ2U7Ij4gKkdlbmVyYWNpb24gZGUgTW9kZWxvcyogPC9zcGFuPg0KDQojIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IG9yYW5nZTsiPiAqKk1vZGVsbyAxOiBSZWdyZXNpb24gQWdydXBhZGEgKFBvb2xlZCkqKiA8L3NwYW4+DQoNCkVsIE1vZGVsbyBkZSBSZWdyZXNpw7NuIEFncnVwYWRhIChQb29sZWQpIGVzIHVuYSB0w6ljbmljYSBkZSBlc3RpbWFjacOzbiBlbiBkYXRvcyBkZSBwYW5lbCBkb25kZSBzZSBhc3VtZSBxdWUgbm8gaGF5IGVmZWN0b3MgaW5kaXZpZHVhbGVzIGVzcGVjw61maWNvcyBwYXJhIGNhZGEgdW5pZGFkLCBuaSB2YXJpYWNpb25lcyBlbiBlbCB0aWVtcG8uICANCioqwqFJZ25vcmEgSGV0ZXJvZ2VuaWVkYWRlcyEqKiAgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwb29sZWQgPC0gcGxtKEMgfiBRICsgUEYgKyBMRiwgZGF0YSA9IGRmX3BhbmVsLCBtb2RlbCA9ICJwb29saW5nIikNCnN1bW1hcnkocG9vbGVkKQ0KDQojUHJ1ZWJhIEJyZXVzY2gtUGFnYW46DQpwbG10ZXN0KHBvb2xlZCwgdHlwZSA9ICJicCIpDQpgYGANCg0KQ29tbyBlbCBwLXZhbHVlIGVzIG1heW9yIGEgMC4wNSwgcG9kZW1vcyB1dGlsaXphciBlbCAqTW9kZWxvIFBvb2xlZCoNCg0KIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiBvcmFuZ2U7Ij4gKipNb2RlbG8gMjogRWZlY3RvcyBGaWpvcyAoV2l0aGluKSoqIDwvc3Bhbj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp3aXRoaW4gPC0gcGxtKEMgfiBRICsgUEYgKyBMRiwgZGF0YSA9IGRmX3BhbmVsLCBtb2RlbCA9ICJ3aXRoaW4iKQ0Kc3VtbWFyeSh3aXRoaW4pDQpgYGANCg0KDQojIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IG9yYW5nZTsiPiAqKk1vZGVsbyAzOiBFZmVjdG9zIEFsZWF0b3Jpb3MgKFJhbmRvbSkgLSBXYWxodXMqKiA8L3NwYW4+DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kd2FsaHVzIDwtIHBsbShDIH4gUSArIFBGICsgTEYsIGRhdGEgPSBkZl9wYW5lbCwgbW9kZWwgPSAicmFuZG9tIiwgcmFuZG9tLm1ldGhvZCA9ICJ3YWxodXMiKQ0Kc3VtbWFyeSh3YWxodXMpDQpgYGANCg0KDQojIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IG9yYW5nZTsiPiAqKk1vZGVsbyA0OiBFZmVjdG9zIEFsZWF0b3Jpb3MgKFJhbmRvbSkgLSBBbWVtaXlhKiogPC9zcGFuPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmFtZW1peWEgPC0gcGxtKEMgfiBRICsgUEYgKyBMRiwgZGF0YSA9IGRmX3BhbmVsLCBtb2RlbCA9ICJyYW5kb20iLCByYW5kb20ubWV0aG9kID0gImFtZW1peWEiKQ0Kc3VtbWFyeShhbWVtaXlhKQ0KYGBgDQoNCg0KIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiBvcmFuZ2U7Ij4gKipNb2RlbG8gNTogRWZlY3RvcyBBbGVhdG9yaW9zIChSYW5kb20pIC0gTmVybG92ZSoqIDwvc3Bhbj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpuZXJsb3ZlIDwtIHBsbShDIH4gUSArIFBGICsgTEYsIGRhdGEgPSBkZl9wYW5lbCwgbW9kZWwgPSAicmFuZG9tIiwgcmFuZG9tLm1ldGhvZCA9ICJuZXJsb3ZlIikNCnN1bW1hcnkobmVybG92ZSkNCmBgYA0KDQpDb21wYXJhbmRvIGxhcyBSMiBhanVzdGFkYXMgZGUgbG9zIE1vZGVsb3MgQWxlYXRvcmlvcywgZWwgbWVqb3IgbcOpdG9kbyBvYnRlbmlkbyBlcyBlbCBkZSAqKldhbGh1cyoqLiAgDQoNCiMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICoqRWZlY3RvcyBGaWpvcyBWcyBFZmVjdG9zIEFsZWF0b3Jpb3MqKiA8L3NwYW4+DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGh0ZXN0KHdpdGhpbix3YWxodXMpDQpgYGANCg0KRW4gY2FzbyBkZSBlbGVnaXIgYWxndW4gbW9kZWxvIGRlIEVmZWN0b3MgRmlqb3MgbyBBbGVhdG9yaW9zLCBlbCBtZWpvciBlbiBlc3RhIHNpdHVhY2nDs24gZXMgZWwgZGUgKipFZmVjdG9zIEZpam9zKiogeWEgcXVlIGVsIHZhbG9yIGRlIHAtdmFsdWUgZXMgbWVub3IgcXVlIDAuMDUuICANCg0KIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICoqVGVtYSAyOiBTZXJpZXMgZGUgVGllbXBvKiogPC9zcGFuPg0KDQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICpHZW5lcmFyIFNlcmllIGRlIFRpZW1wbyogPC9zcGFuPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgRmlsdHJhciBsYSBBZXJvbGluZWEgMSAoZWplbXBsbykNCmRmX2ExIDwtIGRmW2RmJEkgPT0gMSxdDQojIENvbnZlcnRpciBhIFNlcmllcyBkZSBUaWVtcG8NCnRzX2ExIDwtIHRzKGRmX2ExJEMsIHN0YXJ0ID0gMTk3MCwgZnJlcXVlbmN5ID0gMSkNCg0KIyBGaWx0cmFyIGxhIEFlcm9saW5lYSAyIChlamVtcGxvKQ0KZGZfYTIgPC0gZGZbZGYkSSA9PSAyLF0NCiMgQ29udmVydGlyIGEgU2VyaWVzIGRlIFRpZW1wbw0KdHNfYTIgPC0gdHMoZGZfYTIkQywgc3RhcnQgPSAxOTcwLCBmcmVxdWVuY3kgPSAxKQ0KDQojIEZpbHRyYXIgbGEgQWVyb2xpbmVhIDMgKGVqZW1wbG8pDQpkZl9hMyA8LSBkZltkZiRJID09IDMsXQ0KIyBDb252ZXJ0aXIgYSBTZXJpZXMgZGUgVGllbXBvDQp0c19hMyA8LSB0cyhkZl9hMyRDLCBzdGFydCA9IDE5NzAsIGZyZXF1ZW5jeSA9IDEpDQoNCiMgRmlsdHJhciBsYSBBZXJvbGluZWEgNCAoZWplbXBsbykNCmRmX2E0IDwtIGRmW2RmJEkgPT0gNCxdDQojIENvbnZlcnRpciBhIFNlcmllcyBkZSBUaWVtcG8NCnRzX2E0IDwtIHRzKGRmX2E0JEMsIHN0YXJ0ID0gMTk3MCwgZnJlcXVlbmN5ID0gMSkNCg0KIyBGaWx0cmFyIGxhIEFlcm9saW5lYSA1IChlamVtcGxvKQ0KZGZfYTUgPC0gZGZbZGYkSSA9PSA1LF0NCiMgQ29udmVydGlyIGEgU2VyaWVzIGRlIFRpZW1wbw0KdHNfYTUgPC0gdHMoZGZfYTUkQywgc3RhcnQgPSAxOTcwLCBmcmVxdWVuY3kgPSAxKQ0KDQojIEZpbHRyYXIgbGEgQWVyb2xpbmVhIDYgKGVqZW1wbG8pDQpkZl9hNiA8LSBkZltkZiRJID09IDYsXQ0KIyBDb252ZXJ0aXIgYSBTZXJpZXMgZGUgVGllbXBvDQp0c19hNiA8LSB0cyhkZl9hNiRDLCBzdGFydCA9IDE5NzAsIGZyZXF1ZW5jeSA9IDEpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IG9yYW5nZTsiPiAqR2VuZXJhY2lvbiBkZSBNb2RlbG9zKiA8L3NwYW4+DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQphcmltYV9hMSA8LSBhdXRvLmFyaW1hKHRzX2ExKQ0Kc3VtbWFyeShhcmltYV9hMSkNCg0KYXJpbWFfYTIgPC0gYXV0by5hcmltYSh0c19hMikNCnN1bW1hcnkoYXJpbWFfYTIpDQoNCmFyaW1hX2EzIDwtIGF1dG8uYXJpbWEodHNfYTMpDQpzdW1tYXJ5KGFyaW1hX2EzKQ0KDQphcmltYV9hNCA8LSBhdXRvLmFyaW1hKHRzX2E0KQ0Kc3VtbWFyeShhcmltYV9hNCkNCg0KYXJpbWFfYTUgPC0gYXV0by5hcmltYSh0c19hNSkNCnN1bW1hcnkoYXJpbWFfYTUpDQoNCmFyaW1hX2E2IDwtIGF1dG8uYXJpbWEodHNfYTYpDQpzdW1tYXJ5KGFyaW1hX2E2KQ0KYGBgDQoNCkxhIHNlcmllIGRlIHRpZW1wbyBBUklNQSBjb24gbWVub3IgTUFQRSBmdWUgZWwgZGUgbGEgKipBZXJvbGluYSA2KiogcG9yIGxvIHF1ZSBzZSBlc3RhcmEgdHJhYmFqYW5kbyBjb24gZXN0YS4NCg0KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IG9yYW5nZTsiPiAqR2VuZXJhciBQcm9ub3N0aWNvcyogPC9zcGFuPg0KYGBge3J9DQpwcm9ub3N0aWNvX2E2IDwtIGZvcmVjYXN0KGFyaW1hX2E2LCBsZXZlbCA9IDk1LCBoID0gNSkNCnByb25vc3RpY29fYTYNCg0KcGxvdChwcm9ub3N0aWNvX2E2LCBtYWluID0gIlByb27Ds3N0aWNvIGRlIENvc3RvIFRvdGFsIEFlcm9saW5lYSA2IiwNCiAgICAgeGxhYiA9ICJBw7FvIiwgeWxhYiA9ICJNaWxlcyBkZSBVU0QiKQ0KYGBgDQoNCg0KIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICoqVGVtYSAzOiBNb2RlbG8gZGUgRWN1YWNpb25lcyBFc3RydWN0dXJhbGVzIChTRU0pKiogPC9zcGFuPg0KDQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICpFc3RydWN0dXJhciBlbCBNb2RlbG8qIDwvc3Bhbj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQptb2RlbG8gPC0gJw0KICAgICAgICAgICMgVmFyaWFibGVzIExhdGVudGVzDQogICAgICAgICAgI1JlZ3Jlc2lvbmVzDQogICAgICAgICAgQyB+IFEgKyBQRiArIExGICsgSSArIFkNCiAgICAgICAgICBRIH4gUEYgKyBJDQogICAgICAgICAgUEYgfiBZDQogICAgICAgICAgTEYgfiBJDQogICAgICAgICAgI1ZhcmlhbnphcyB5IENvdmFyaWFuemFzDQogICAgICAgICAgQyB+fiBDDQogICAgICAgICAgUSB+fiBRDQogICAgICAgICAgUEYgfn4gUEYNCiAgICAgICAgICBMRiB+fiBMRg0KICAgICAgICAgICNJbnRlcmNlcHRvcw0KICAgICAgICAgICcNCmBgYA0KDQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICpHZW5lcmFyIGVsIEFuYWxpc2lzIEZhY3RvcmlhbCBDb25maXJtYXRvcmlvKiA8L3NwYW4+DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBFc2NhbGFyIGxhIGJhc2UgZGUgZGF0b3MNCmRmX2VzY2FsYWRhIDwtIGRmDQpkZl9lc2NhbGFkYSRJIDwtIGFzLm51bWVyaWMoZGZfZXNjYWxhZGEkSSkNCmRmX2VzY2FsYWRhIDwtIHNjYWxlKGRmX2VzY2FsYWRhKQ0KDQojQW5hbGlzaXMgRmFjdG9yaWFsDQpjZmEgPC0gY2ZhKG1vZGVsbywgZGZfZXNjYWxhZGEpDQpzdW1tYXJ5KGNmYSkNCmBgYA0KDQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogb3JhbmdlOyI+ICpHZW5lcmFyIGVsIE1vZGVsbyBkZSBFY3VhY2lvbmVzIEVzdHJ1Y3R1cmFsZXMqIDwvc3Bhbj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsYXZhYW5QbG90KGNmYSkNCmBgYA0KDQoNCiMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IG9yYW5nZTsiPiAqKkFwbGljYWNpb24gZGUgU2hpbnkgKFNFTSkqKiA8L3NwYW4+DQpbTGluayBkZSBsYSBBcGxpY2FjacOzbl0oaHR0cHM6Ly9yYW82Nzguc2hpbnlhcHBzLmlvL0FjdGl2aWRhZENhc29GaW5hbFB1bnRvcy8pDQoNCg==