Instalar paquetes y llamar librerías

#install.packages("forecast")
#install.packages("readxl")
library(forecast)
library(readxl)

Ejercicio 1. Ventas Semanales

INSTRUCCIONES: Modela la sigueinte Serie de Tiempo y elige la mejor opción. Pronostica las sigueintes 6 semanas.

semana <- c(1:12)
valor <- c(17,21,19,23,18,16,20,18,22,20,15,22)
df1 <- data.frame(semana,valor)

ts1 <- ts(valor, c(2025,1), frequency = 52)

# Modelo 1. Naive
naive1 <- naive(ts1, h=6)
summary(naive1)
## 
## Forecast method: Naive method
## 
## Model Information:
## Call: naive(y = ts1, h = 6) 
## 
## Residual sd: 4.0339 
## 
## Error measures:
##                     ME     RMSE      MAE       MPE     MAPE MASE       ACF1
## Training set 0.4545455 4.033947 3.727273 0.1082169 19.24431  NaN -0.4553872
## 
## Forecasts:
##          Point Forecast     Lo 80    Hi 80     Lo 95    Hi 95
## 2025.231             22 16.830289 27.16971 14.093609 29.90639
## 2025.250             22 14.688925 29.31108 10.818675 33.18132
## 2025.269             22 13.045798 30.95420  8.305730 35.69427
## 2025.288             22 11.660578 32.33942  6.187219 37.81278
## 2025.308             22 10.440175 33.55983  4.320773 39.67923
## 2025.327             22  9.336846 34.66315  2.633377 41.36662
mape_naive1 <- accuracy(naive1)[1,"MAPE"]
# Modelo con menor MAPE es el mas adecuado.

# Función genérica de Promedio Móvil: promedia los últimos k valores para
# obtener el ajuste dentro de la muestra, y de forma recursiva usa los
# pronósticos ya calculados para proyectar h periodos hacia adelante.
ma_forecast <- function(serie, k, h){
  n <- length(serie)
  fitted <- rep(NA, n)
  for (i in (k+1):n) fitted[i] <- mean(serie[(i-k):(i-1)])
  mape <- mean(abs((serie[(k+1):n] - fitted[(k+1):n]) / serie[(k+1):n])) * 100
  ext <- c(serie, rep(NA, h))
  for (i in (n+1):(n+h)) ext[i] <- mean(ext[(i-k):(i-1)])
  list(fitted = fitted, mape = mape, forecast = ext[(n+1):(n+h)])
}

# Modelo 2. Promedio Móvil (k = 3)
ma1 <- ma_forecast(valor, k = 3, h = 6)
ma1$mape       # MAPE del modelo
## [1] 14.35661
ma1$forecast   # Pronóstico de las siguientes 6 semanas
## [1] 19.00000 18.66667 19.88889 19.18519 19.24691 19.44033
# Función genérica de Promedio Móvil Ponderado: los pesos se aplican del más
# antiguo al más reciente, por lo que el valor más reciente pesa más (3/6).
wma_forecast <- function(serie, pesos, h){
  k <- length(pesos)
  n <- length(serie)
  fitted <- rep(NA, n)
  for (i in (k+1):n) fitted[i] <- sum(serie[(i-k):(i-1)] * pesos)
  mape <- mean(abs((serie[(k+1):n] - fitted[(k+1):n]) / serie[(k+1):n])) * 100
  ext <- c(serie, rep(NA, h))
  for (i in (n+1):(n+h)) ext[i] <- sum(ext[(i-k):(i-1)] * pesos)
  list(fitted = fitted, mape = mape, forecast = ext[(n+1):(n+h)])
}

pesos <- c(1,2,3)/6  # 1/6 al más antiguo, 2/6 al intermedio, 3/6 al más reciente

# Modelo 3. Promedio Móvil Ponderado (k =3 Pesos: 3/6, 2/6, y 1/6)
wma1 <- wma_forecast(valor, pesos, h = 6)
wma1$mape
## [1] 15.99248
wma1$forecast
## [1] 19.33333 19.50000 19.86111 19.65278 19.69676 19.70949
# Modelo 4. Suavizador Exponencial (alfa = 0.2). Menor alfa = mejor modelo
ses1 <- ses(ts1, alpha = 0.2, h = 6)
summary(ses1)
## 
## Forecast method: Simple exponential smoothing
## 
## Model Information:
## Simple exponential smoothing 
## 
## Call:
## ses(y = ts1, h = 6, alpha = 0.2)
## 
##   Smoothing parameters:
##     alpha = 0.2 
## 
##   Initial states:
##     l = 19.1774 
## 
##   sigma:  2.9273
## 
##      AIC     AICc      BIC 
## 57.40932 58.74266 58.37914 
## 
## Error measures:
##                      ME     RMSE      MAE       MPE     MAPE MASE       ACF1
## Training set 0.06549665 2.672288 2.312859 -1.479963 12.37329  NaN -0.3669082
## 
## Forecasts:
##          Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## 2025.231       19.33458 15.58304 23.08613 13.59709 25.07208
## 2025.250       19.33458 15.50875 23.16042 13.48347 25.18570
## 2025.269       19.33458 15.43587 23.23330 13.37201 25.29716
## 2025.288       19.33458 15.36432 23.30485 13.26259 25.40657
## 2025.308       19.33458 15.29405 23.37512 13.15512 25.51405
## 2025.327       19.33458 15.22497 23.44419 13.04948 25.61969
mape_ses1 <- accuracy(ses1)[1,"MAPE"]

# Modelo 5. ARIMA
arima1 <- auto.arima(ts1)
arima1
## Series: ts1 
## ARIMA(0,0,0) with non-zero mean 
## 
## Coefficients:
##          mean
##       19.2500
## s.e.   0.6985
## 
## sigma^2 = 6.386:  log likelihood = -27.63
## AIC=59.26   AICc=60.59   BIC=60.23
pronostico1 <- forecast(arima1, level = c(95), h = 6)
plot(pronostico1)

mape_arima1 <- accuracy(arima1)[1,"MAPE"]

# Tabla con el Resumen de los Resultados.
resumen1 <- data.frame(
  Modelo = c("Naive", "Promedio Móvil (k=3)", "Promedio Móvil Ponderado",
             "Suavizador Exponencial (alfa=0.2)", "ARIMA"),
  MAPE = round(c(mape_naive1, ma1$mape, wma1$mape, mape_ses1, mape_arima1), 2)
)
resumen1 <- resumen1[order(resumen1$MAPE), ]
resumen1
##                              Modelo  MAPE
## 5                             ARIMA 11.19
## 4 Suavizador Exponencial (alfa=0.2) 12.37
## 2              Promedio Móvil (k=3) 14.36
## 3          Promedio Móvil Ponderado 15.99
## 1                             Naive 19.24
pronostico_final1 <- data.frame(
  Semana = 13:18,
  Naive = as.numeric(naive1$mean),
  Prom_Movil = ma1$forecast,
  Prom_Movil_Pond = wma1$forecast,
  Suavizador_Exp = as.numeric(ses1$mean),
  ARIMA = as.numeric(pronostico1$mean)
)
pronostico_final1
##   Semana Naive Prom_Movil Prom_Movil_Pond Suavizador_Exp ARIMA
## 1     13    22   19.00000        19.33333       19.33458 19.25
## 2     14    22   18.66667        19.50000       19.33458 19.25
## 3     15    22   19.88889        19.86111       19.33458 19.25
## 4     16    22   19.18519        19.65278       19.33458 19.25
## 5     17    22   19.24691        19.69676       19.33458 19.25
## 6     18    22   19.44033        19.70949       19.33458 19.25
# Conclusión Método ARE.
mejor1 <- resumen1$Modelo[1]
cat("El modelo con el MAPE más bajo (", round(resumen1$MAPE[1],2),
    "%) es:", mejor1,
    ". Por lo tanto es el modelo más adecuado para pronosticar las siguientes 6 semanas.\n")
## El modelo con el MAPE más bajo ( 11.19 %) es: ARIMA . Por lo tanto es el modelo más adecuado para pronosticar las siguientes 6 semanas.

Ejercicio 2. Hershey’s

INSTRUCCIONES: Modela la sigueinte Serie de Tiempo y elige la mejor opción. Pronostica las sigueintes 6 semanas.

ruta <- "/Users/adriana/Downloads/Ventas_Históricas_Lechitas.xlsx"

datos <- read_excel(ruta, sheet = 1, skip = 2)
## New names:
## • `Mes` -> `Mes...1`
## • `Ventas` -> `Ventas...2`
## • `Mes` -> `Mes...3`
## • `Ventas` -> `Ventas...4`
## • `Mes` -> `Mes...5`
## • `Ventas` -> `Ventas...6`
ventas <- as.numeric(c(datos[[2]], datos[[4]], datos[[6]]))  # concatena 2017-2018-2019
mes <- 1:length(ventas)
df2 <- data.frame(mes, ventas)

ts2 <- ts(ventas, start = c(2017,1), frequency = 12)
plot(ts2, main = "Ventas históricas de leche saborizada Hershey (Lechitas)",
     ylab = "Ventas (miles de dólares)", xlab = "Año")

# Modelo 1. Naive
naive2 <- naive(ts2, h = 6)
summary(naive2)
## 
## Forecast method: Naive method
## 
## Model Information:
## Call: naive(y = ts2, h = 6) 
## 
## Residual sd: 1112.6435 
## 
## Error measures:
##                    ME     RMSE      MAE       MPE     MAPE      MASE       ACF1
## Training set 266.4474 1112.644 902.8514 0.8162353 3.013136 0.2579763 -0.5648044
## 
## Forecasts:
##          Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## Jan 2020       34846.17 33420.26 36272.08 32665.43 37026.91
## Feb 2020       34846.17 32829.63 36862.71 31762.14 37930.20
## Mar 2020       34846.17 32376.42 37315.92 31069.02 38623.32
## Apr 2020       34846.17 31994.35 37697.99 30484.69 39207.65
## May 2020       34846.17 31657.74 38034.60 29969.88 39722.46
## Jun 2020       34846.17 31353.42 38338.92 29504.47 40187.87
mape_naive2 <- accuracy(naive2)[1,"MAPE"]
# Modelo con menor MAPE es el mas adecuado.

# Modelo 2. Promedio Móvil (k = 3)
ma2 <- ma_forecast(ventas, k = 3, h = 6)
ma2$mape
## [1] 2.811654
ma2$forecast
## [1] 35259.72 34968.60 35024.83 35084.38 35025.94 35045.05
# Modelo 3. Promedio Móvil Ponderado (k =3 Pesos: 3/6, 2/6, y 1/6)
wma2 <- wma_forecast(ventas, pesos, h = 6)
wma2$mape
## [1] 2.624516
wma2$forecast
## [1] 35045.23 34937.99 34958.44 34966.09 34958.85 34961.20
# Modelo 4. Suavizador Exponencial (alfa = 0.2). Menor alfa = mejor modelo
ses2 <- ses(ts2, alpha = 0.2, h = 6)
summary(ses2)
## 
## Forecast method: Simple exponential smoothing
## 
## Model Information:
## Simple exponential smoothing 
## 
## Call:
## ses(y = ts2, h = 6, alpha = 0.2)
## 
##   Smoothing parameters:
##     alpha = 0.2 
## 
##   Initial states:
##     l = 26303.9678 
## 
##   sigma:  1574.86
## 
##      AIC     AICc      BIC 
## 661.0074 661.3710 664.1744 
## 
## Error measures:
##                    ME     RMSE      MAE      MPE     MAPE      MASE      ACF1
## Training set 1111.747 1530.489 1335.458 3.458378 4.357771 0.3815873 0.3247295
## 
## Forecasts:
##          Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## Jan 2020       34308.55 32290.28 36326.81 31221.88 37395.22
## Feb 2020       34308.55 32250.31 36366.78 31160.75 37456.34
## Mar 2020       34308.55 32211.10 36405.99 31100.78 37516.31
## Apr 2020       34308.55 32172.61 36444.48 31041.92 37575.17
## May 2020       34308.55 32134.81 36482.28 30984.10 37632.99
## Jun 2020       34308.55 32097.65 36519.44 30927.27 37689.82
mape_ses2 <- accuracy(ses2)[1,"MAPE"]

# Modelo 5. ARIMA
arima2 <- auto.arima(ts2)
arima2
## Series: ts2 
## ARIMA(1,0,0)(1,1,0)[12] with drift 
## 
## Coefficients:
##          ar1     sar1     drift
##       0.6383  -0.5517  288.8979
## s.e.  0.1551   0.2047   14.5026
## 
## sigma^2 = 202701:  log likelihood = -181.5
## AIC=371   AICc=373.11   BIC=375.72
pronostico2 <- forecast(arima2, level = c(95), h = 6)
plot(pronostico2)

mape_arima2 <- accuracy(arima2)[1,"MAPE"]

# Tabla con el Resumen de los Resultados.
resumen2 <- data.frame(
  Modelo = c("Naive", "Promedio Móvil (k=3)", "Promedio Móvil Ponderado",
             "Suavizador Exponencial (alfa=0.2)", "ARIMA"),
  MAPE = round(c(mape_naive2, ma2$mape, wma2$mape, mape_ses2, mape_arima2), 2)
)
resumen2 <- resumen2[order(resumen2$MAPE), ]
resumen2
##                              Modelo MAPE
## 5                             ARIMA 0.71
## 3          Promedio Móvil Ponderado 2.62
## 2              Promedio Móvil (k=3) 2.81
## 1                             Naive 3.01
## 4 Suavizador Exponencial (alfa=0.2) 4.36
pronostico_final2 <- data.frame(
  Mes = 37:42,
  Naive = as.numeric(naive2$mean),
  Prom_Movil = ma2$forecast,
  Prom_Movil_Pond = wma2$forecast,
  Suavizador_Exp = as.numeric(ses2$mean),
  ARIMA = as.numeric(pronostico2$mean)
)
pronostico_final2
##   Mes    Naive Prom_Movil Prom_Movil_Pond Suavizador_Exp    ARIMA
## 1  37 34846.17   35259.72        35045.23       34308.55 35498.90
## 2  38 34846.17   34968.60        34937.99       34308.55 34202.17
## 3  39 34846.17   35024.83        34958.44       34308.55 36703.01
## 4  40 34846.17   35084.38        34966.09       34308.55 36271.90
## 5  41 34846.17   35025.94        34958.85       34308.55 37121.98
## 6  42 34846.17   35045.05        34961.20       34308.55 37102.65
# Conclusión Método ARE.
mejor2 <- resumen2$Modelo[1]
cat("El modelo con el MAPE más bajo (", round(resumen2$MAPE[1],2),
    "%) es:", mejor2,
    ". Por lo tanto es el modelo más adecuado para pronosticar las ventas de los próximos 6 meses de Lechitas.\n")
## El modelo con el MAPE más bajo ( 0.71 %) es: ARIMA . Por lo tanto es el modelo más adecuado para pronosticar las ventas de los próximos 6 meses de Lechitas.

Ejercicio 3. Vintage Restaurant

INSTRUCCIONES: Analiza las ventas de alimentos y bebidas del Vintage Restaurant (Tabla 18.26) e incluye: gráfica de la serie, índices estacionales, serie desestacionalizada, pronóstico por descomposición y por regresión con variables ficticias para el año 4, tablas resumen y conclusiones.

# Ventas de alimentos y bebidas del restaurante Vintage ($ miles)
vintage <- c(242,235,232,178,184,140,145,152,110,130,152,206,   # Año 1
             263,238,247,193,193,149,157,161,122,130,167,230,   # Año 2
             282,255,265,205,210,160,166,174,126,148,173,235)   # Año 3

ts_vintage <- ts(vintage, start = c(1,1), frequency = 12)

# 1. Gráfica de la serie de tiempo
plot(ts_vintage, main = "Ventas de alimentos y bebidas - Vintage Restaurant",
     ylab = "Ventas ($ miles)", xlab = "Año", type = "o")

Patrón principal: se observa un componente estacional muy marcado que se repite cada 12 meses (ventas altas en la temporada de invierno: dic-ene-feb-mar, y bajas en el verano/otoño, con el mínimo en septiembre), junto con una tendencia creciente de un año a otro conforme crece la reputación del restaurante.

# 2. Descomposición multiplicativa e índices estacionales
decomp_vintage <- decompose(ts_vintage, type = "multiplicative")
plot(decomp_vintage)

indices_estacionales <- data.frame(
  Mes = month.name,
  Indice = round(as.numeric(decomp_vintage$figure), 3)
)
indices_estacionales
##          Mes Indice
## 1    January  1.444
## 2   February  1.300
## 3      March  1.344
## 4      April  1.041
## 5        May  1.049
## 6       June  0.800
## 7       July  0.828
## 8     August  0.853
## 9  September  0.628
## 10   October  0.700
## 11  November  0.853
## 12  December  1.159

Los índices estacionales muestran temporada alta en enero-marzo y diciembre (índices arriba de 1, ventas por encima del promedio) y temporada baja en septiembre y octubre (índices muy por debajo de 1). Esto tiene sentido intuitivo: Captiva Island es un destino turístico de invierno (temporada de “snowbirds”), mientras que septiembre-octubre coincide con la temporada baja de turismo y de huracanes en Florida.

# 3. Serie desestacionalizada y análisis de tendencia
deseasonalized <- ts_vintage / decomp_vintage$seasonal
plot(deseasonalized, main = "Serie desestacionalizada - Vintage Restaurant",
     ylab = "Ventas ($ miles)", xlab = "Año", type = "o")

t <- 1:36
modelo_tendencia <- lm(as.numeric(deseasonalized) ~ t)
summary(modelo_tendencia)
## 
## Call:
## lm(formula = as.numeric(deseasonalized) ~ t)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -6.1892 -2.2527 -0.4848  0.8131  9.4189 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 169.3494     1.0926  155.00   <2e-16 ***
## t             1.0213     0.0515   19.83   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3.21 on 34 degrees of freedom
## Multiple R-squared:  0.9204, Adjusted R-squared:  0.9181 
## F-statistic: 393.3 on 1 and 34 DF,  p-value: < 2.2e-16

La serie desestacionalizada sí muestra una tendencia lineal creciente: la pendiente estimada es positiva y estadísticamente significativa, lo que confirma que, quitando el efecto estacional, las ventas del restaurante crecen mes con mes.

# 4. Pronóstico por el método de descomposición para el año 4
pred_tendencia_a4 <- predict(modelo_tendencia, newdata = data.frame(t = 37:48))
estacional_a4 <- as.numeric(decomp_vintage$figure)  # 12 índices, Ene-Dic
pronostico_descomp <- pred_tendencia_a4 * estacional_a4

pronostico_descomp_tabla <- data.frame(
  Mes = month.name,
  Pronostico_Descomposicion = round(pronostico_descomp, 1)
)
pronostico_descomp_tabla
##          Mes Pronostico_Descomposicion
## 1    January                     299.0
## 2   February                     270.5
## 3      March                     281.2
## 4      April                     218.9
## 5        May                     221.7
## 6       June                     169.9
## 7       July                     176.6
## 8     August                     182.8
## 9  September                     135.2
## 10   October                     151.5
## 11  November                     185.3
## 12  December                     253.2
# 5. Pronóstico por regresión con variables ficticias (dummy variables)
mes_factor <- factor(rep(1:12, 3))
modelo_dummy <- lm(vintage ~ t + mes_factor)
summary(modelo_dummy)
## 
## Call:
## lm(formula = vintage ~ t + mes_factor)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -8.1250 -1.9583  0.1667  2.2292  7.4583 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   249.10764    2.74567  90.727  < 2e-16 ***
## t               1.01736    0.07554  13.467 2.14e-12 ***
## mes_factor2   -20.68403    3.62688  -5.703 8.30e-06 ***
## mes_factor3   -16.36806    3.62924  -4.510 0.000158 ***
## mes_factor4   -73.38542    3.63317 -20.199 3.90e-16 ***
## mes_factor5   -70.73611    3.63866 -19.440 8.97e-16 ***
## mes_factor6  -117.75347    3.64571 -32.299  < 2e-16 ***
## mes_factor7  -112.43750    3.65431 -30.768  < 2e-16 ***
## mes_factor8  -107.12153    3.66445 -29.233  < 2e-16 ***
## mes_factor9  -151.13889    3.67611 -41.114  < 2e-16 ***
## mes_factor10 -135.48958    3.68928 -36.725  < 2e-16 ***
## mes_factor11 -108.50694    3.70395 -29.295  < 2e-16 ***
## mes_factor12  -49.85764    3.72009 -13.402 2.36e-12 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 4.441 on 23 degrees of freedom
## Multiple R-squared:  0.9942, Adjusted R-squared:  0.9911 
## F-statistic:   327 on 12 and 23 DF,  p-value: < 2.2e-16
pronostico_regresion <- predict(
  modelo_dummy,
  newdata = data.frame(t = 37:48, mes_factor = factor(1:12, levels = levels(mes_factor)))
)

pronostico_regresion_tabla <- data.frame(
  Mes = month.name,
  Pronostico_Regresion = round(as.numeric(pronostico_regresion), 1)
)
pronostico_regresion_tabla
##          Mes Pronostico_Regresion
## 1    January                286.8
## 2   February                267.1
## 3      March                272.4
## 4      April                216.4
## 5        May                220.1
## 6       June                174.1
## 7       July                180.4
## 8     August                186.8
## 9  September                143.8
## 10   October                160.4
## 11  November                188.4
## 12  December                248.1
# 6. Tabla resumen con ambos métodos y gráfica comparativa
resumen_vintage <- data.frame(
  Mes = month.name,
  Descomposicion = round(pronostico_descomp, 1),
  Regresion_Dummy = round(as.numeric(pronostico_regresion), 1)
)
resumen_vintage
##          Mes Descomposicion Regresion_Dummy
## 1    January          299.0           286.8
## 2   February          270.5           267.1
## 3      March          281.2           272.4
## 4      April          218.9           216.4
## 5        May          221.7           220.1
## 6       June          169.9           174.1
## 7       July          176.6           180.4
## 8     August          182.8           186.8
## 9  September          135.2           143.8
## 10   October          151.5           160.4
## 11  November          185.3           188.4
## 12  December          253.2           248.1
matplot(1:12, resumen_vintage[, c("Descomposicion","Regresion_Dummy")], type = "o", pch = 16,
        col = c("blue","red"), xaxt = "n",
        main = "Pronóstico Año 4 - Vintage Restaurant",
        xlab = "Mes", ylab = "Ventas ($ miles)")
axis(1, at = 1:12, labels = month.abb)
legend("topright", legend = c("Descomposición","Regresión Dummy"), col = c("blue","red"), lty = 1, pch = 16)

# Error de pronóstico de enero del año 4 (venta real reportada = $295 miles)
venta_real_enero_a4 <- 295
error_descomp_ene <- venta_real_enero_a4 - resumen_vintage$Descomposicion[1]
error_regresion_ene <- venta_real_enero_a4 - resumen_vintage$Regresion_Dummy[1]

cat("Error de pronóstico (Descomposición) para enero del año 4:", round(error_descomp_ene,1), "\n")
## Error de pronóstico (Descomposición) para enero del año 4: -4
cat("Error de pronóstico (Regresión con dummies) para enero del año 4:", round(error_regresion_ene,1), "\n")
## Error de pronóstico (Regresión con dummies) para enero del año 4: 8.2

Conclusiones Ejercicio 3: ambos métodos arrojan pronósticos similares para enero del año 4, y el error frente a la venta real ($295 mil) es relativamente pequeño en comparación con el nivel de ventas, lo que indica que los modelos capturan bien el patrón estacional y la tendencia. Si a Karen le preocupa esa diferencia, puede reducir la incertidumbre generando un intervalo de pronóstico (en vez de un solo número), actualizando el modelo cada mes con los datos reales más recientes (pronóstico móvil / recalibración continua), y monitoreando si el error se mantiene dentro de un rango razonable o si crece de forma sistemática, lo cual señalaría que el patrón de la serie está cambiando.

Ejercicio 4. Carlson Department Store

INSTRUCCIONES: Estima las ventas que Carlson y el condado habrían tenido de septiembre a diciembre del año 5 si no hubiera ocurrido el huracán, estima la pérdida de ventas de Carlson, y evalúa si hay evidencia de un exceso de ventas en el condado relacionado con el huracán.

# Ventas de Carlson Department Store ($ millones)
# 48 meses: de septiembre del Año 1 a agosto del Año 5 (mes previo al huracán)
carlson <- c(1.71,1.90,2.74,4.20,                                          # Sep-Dic Año 1
             1.45,1.80,2.03,1.99,2.32,2.20,2.13,2.43,1.90,2.13,2.56,4.16,  # Año 2 completo
             2.31,1.89,2.02,2.23,2.39,2.14,2.27,2.21,1.89,2.29,2.83,4.04,  # Año 3 completo
             2.31,1.99,2.42,2.45,2.57,2.42,2.40,2.50,2.09,2.54,2.97,4.35,  # Año 4 completo
             2.56,2.28,2.69,2.48,2.73,2.37,2.31,2.23)                     # Ene-Ago Año 5

# Ventas de las tiendas departamentales del condado ($ millones)
# Mismos 48 meses que la serie de Carlson
condado <- c(55.80,56.40,71.40,117.60,
             46.80,48.00,60.00,57.60,61.80,58.20,56.40,63.00,57.60,53.40,71.40,114.00,
             46.80,48.60,59.40,58.20,60.60,55.20,51.00,58.80,49.80,54.60,65.40,102.00,
             43.80,45.60,57.60,53.40,56.40,52.80,54.00,60.60,47.40,54.60,67.80,100.20,
             48.00,51.60,57.60,58.20,60.00,57.00,57.60,61.80)

# Ventas reales del condado durante los 4 meses en que Carlson permaneció cerrada
# (Sep-Dic Año 5, después del huracán)
condado_real_cierre <- c(69.00, 75.00, 85.20, 121.80)

length(carlson)  # debe ser 48
## [1] 48
length(condado)  # debe ser 48
## [1] 48
# Secuencia de mes calendario (1=Ene ... 12=Dic) para los 48 meses, empezando en septiembre
meses_seq <- c(9,10,11,12, rep(1:12, 3), 1,2,3,4,5,6,7,8)
factor_meses <- factor(meses_seq)
t48 <- 1:48
# 1. Estimación de las ventas que Carlson habría tenido de Sep a Dic del Año 5
modelo_carlson <- lm(carlson ~ t48 + factor_meses)
summary(modelo_carlson)
## 
## Call:
## lm(formula = carlson ~ t48 + factor_meses)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.50750 -0.06604  0.00875  0.07458  0.28750 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     1.901944   0.090906  20.922  < 2e-16 ***
## t48             0.011111   0.001753   6.338 2.78e-07 ***
## factor_meses2  -0.178611   0.115236  -1.550   0.1301    
## factor_meses3   0.110278   0.115276   0.957   0.3453    
## factor_meses4   0.096667   0.115342   0.838   0.4077    
## factor_meses5   0.300556   0.115436   2.604   0.0134 *  
## factor_meses6   0.069444   0.115555   0.601   0.5517    
## factor_meses7   0.053333   0.115701   0.461   0.6477    
## factor_meses8   0.107222   0.115874   0.925   0.3611    
## factor_meses9  -0.215556   0.115436  -1.867   0.0702 .  
## factor_meses10  0.090833   0.115342   0.788   0.4363    
## factor_meses11  0.639722   0.115276   5.549 3.03e-06 ***
## factor_meses12  2.041111   0.115236  17.712  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.1629 on 35 degrees of freedom
## Multiple R-squared:  0.9472, Adjusted R-squared:  0.9291 
## F-statistic: 52.35 on 12 and 35 DF,  p-value: < 2.2e-16
pronostico_carlson_cierre <- predict(
  modelo_carlson,
  newdata = data.frame(t48 = 49:52, factor_meses = factor(c(9,10,11,12), levels = levels(factor_meses)))
)
pronostico_carlson_cierre
##        1        2        3        4 
## 2.230833 2.548333 3.108333 4.520833
# 2. Estimación de las ventas que el condado habría tenido de Sep a Dic del Año 5
modelo_condado <- lm(condado ~ t48 + factor_meses)
summary(modelo_condado)
## 
## Call:
## lm(formula = condado ~ t48 + factor_meses)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -6.5925 -2.0250  0.0475  1.4963  7.4925 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)    48.46792    1.80898  26.793  < 2e-16 ***
## t48            -0.09208    0.03488  -2.640 0.012311 *  
## factor_meses2   2.19208    2.29314   0.956 0.345663    
## factor_meses3  12.48417    2.29393   5.442 4.20e-06 ***
## factor_meses4  10.77625    2.29526   4.695 4.02e-05 ***
## factor_meses5  13.71833    2.29711   5.972 8.41e-07 ***
## factor_meses6   9.91042    2.29950   4.310 0.000126 ***
## factor_meses7   8.95250    2.30241   3.888 0.000431 ***
## factor_meses8  15.34458    2.30584   6.655 1.07e-07 ***
## factor_meses9   5.93167    2.29711   2.582 0.014160 *  
## factor_meses10  8.12375    2.29526   3.539 0.001155 ** 
## factor_meses11 22.46583    2.29393   9.794 1.46e-11 ***
## factor_meses12 62.00792    2.29314  27.041  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 3.243 on 35 degrees of freedom
## Multiple R-squared:  0.9693, Adjusted R-squared:  0.9587 
## F-statistic: 92.02 on 12 and 35 DF,  p-value: < 2.2e-16
pronostico_condado_cierre <- predict(
  modelo_condado,
  newdata = data.frame(t48 = 49:52, factor_meses = factor(c(9,10,11,12), levels = levels(factor_meses)))
)
pronostico_condado_cierre
##        1        2        3        4 
##  49.8875  51.9875  66.2375 105.6875
# 3. Estimación de la pérdida de ventas de Carlson (Sep-Dic Año 5)
resumen_carlson <- data.frame(
  Mes = c("Septiembre","Octubre","Noviembre","Diciembre"),
  Ventas_Estimadas = round(as.numeric(pronostico_carlson_cierre), 3),
  Ventas_Reales = c(0, 0, 0, 0)  # la tienda estuvo cerrada, ventas reales = 0
)
resumen_carlson$Perdida <- resumen_carlson$Ventas_Estimadas - resumen_carlson$Ventas_Reales
resumen_carlson
##          Mes Ventas_Estimadas Ventas_Reales Perdida
## 1 Septiembre            2.231             0   2.231
## 2    Octubre            2.548             0   2.548
## 3  Noviembre            3.108             0   3.108
## 4  Diciembre            4.521             0   4.521
perdida_total_carlson <- sum(resumen_carlson$Perdida)
cat("Pérdida total estimada de ventas de Carlson (Sep-Dic Año 5): $",
    round(perdida_total_carlson,2), "millones\n")
## Pérdida total estimada de ventas de Carlson (Sep-Dic Año 5): $ 12.41 millones
# 4. Comparación de ventas reales del condado vs. estimadas 
resumen_condado <- data.frame(
  Mes = c("Septiembre","Octubre","Noviembre","Diciembre"),
  Ventas_Estimadas = round(as.numeric(pronostico_condado_cierre), 2),
  Ventas_Reales = condado_real_cierre
)
resumen_condado$Exceso <- resumen_condado$Ventas_Reales - resumen_condado$Ventas_Estimadas
resumen_condado
##          Mes Ventas_Estimadas Ventas_Reales Exceso
## 1 Septiembre            49.89          69.0  19.11
## 2    Octubre            51.99          75.0  23.01
## 3  Noviembre            66.24          85.2  18.96
## 4  Diciembre           105.69         121.8  16.11
exceso_total_condado <- sum(resumen_condado$Exceso)
cat("Exceso total de ventas reales del condado vs. lo estimado (Sep-Dic Año 5): $",
    round(exceso_total_condado,2), "millones\n")
## Exceso total de ventas reales del condado vs. lo estimado (Sep-Dic Año 5): $ 77.19 millones

Conclusiones Ejercicio 4:

  1. Se estima que, de no haber ocurrido el huracán, Carlson habría vendido aproximadamente 12.41 millones de dólares entre septiembre y diciembre del año 5; como la tienda permaneció cerrada (ventas reales = 0), esa cifra representa la pérdida de ventas atribuible al huracán.
  2. Las ventas reales del condado en esos mismos 4 meses superaron en 77.19 millones de dólares lo que el modelo estimaba que habrían sido sin el huracán.
  3. Ese exceso de ventas en el condado (probablemente impulsado por los más de $8,000 millones en ayuda federal y pagos de seguros que se inyectaron a la zona) es evidencia a favor del argumento de Carlson de que hubo un incremento en la actividad comercial de la zona tras el huracán — lo cual respalda que, de haber permanecido abierta, la tienda muy probablemente también se habría beneficiado de ese repunte y no solo habría perdido sus ventas “normales”, sino también una parte de ese exceso de demanda.
LS0tCnRpdGxlOiAiU2VyaWVzIGRlIFRpZW1wbyIKYXV0aG9yOiAiQWRyaWFuYSBNYWRyaWdhbCAtIEEwMDgzNDg0NiIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRydWUKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKZGF0ZTogIjIwMjYtMDgtMjIiCi0tLQoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZCI+IEluc3RhbGFyIHBhcXVldGVzIHkgbGxhbWFyIGxpYnJlcsOtYXM8L3NwYW4+CmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNpbnN0YWxsLnBhY2thZ2VzKCJmb3JlY2FzdCIpCiNpbnN0YWxsLnBhY2thZ2VzKCJyZWFkeGwiKQpsaWJyYXJ5KGZvcmVjYXN0KQpsaWJyYXJ5KHJlYWR4bCkKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkIj5FamVyY2ljaW8gMS4gVmVudGFzIFNlbWFuYWxlczwvc3Bhbj4KSU5TVFJVQ0NJT05FUzogTW9kZWxhIGxhIHNpZ3VlaW50ZSBTZXJpZSBkZSBUaWVtcG8geSBlbGlnZSBsYSBtZWpvciBvcGNpw7NuLgpQcm9ub3N0aWNhIGxhcyBzaWd1ZWludGVzIDYgc2VtYW5hcy4KCmBgYHtyfQpzZW1hbmEgPC0gYygxOjEyKQp2YWxvciA8LSBjKDE3LDIxLDE5LDIzLDE4LDE2LDIwLDE4LDIyLDIwLDE1LDIyKQpkZjEgPC0gZGF0YS5mcmFtZShzZW1hbmEsdmFsb3IpCgp0czEgPC0gdHModmFsb3IsIGMoMjAyNSwxKSwgZnJlcXVlbmN5ID0gNTIpCgojIE1vZGVsbyAxLiBOYWl2ZQpuYWl2ZTEgPC0gbmFpdmUodHMxLCBoPTYpCnN1bW1hcnkobmFpdmUxKQptYXBlX25haXZlMSA8LSBhY2N1cmFjeShuYWl2ZTEpWzEsIk1BUEUiXQojIE1vZGVsbyBjb24gbWVub3IgTUFQRSBlcyBlbCBtYXMgYWRlY3VhZG8uCgojIEZ1bmNpw7NuIGdlbsOpcmljYSBkZSBQcm9tZWRpbyBNw7N2aWw6IHByb21lZGlhIGxvcyDDumx0aW1vcyBrIHZhbG9yZXMgcGFyYQojIG9idGVuZXIgZWwgYWp1c3RlIGRlbnRybyBkZSBsYSBtdWVzdHJhLCB5IGRlIGZvcm1hIHJlY3Vyc2l2YSB1c2EgbG9zCiMgcHJvbsOzc3RpY29zIHlhIGNhbGN1bGFkb3MgcGFyYSBwcm95ZWN0YXIgaCBwZXJpb2RvcyBoYWNpYSBhZGVsYW50ZS4KbWFfZm9yZWNhc3QgPC0gZnVuY3Rpb24oc2VyaWUsIGssIGgpewogIG4gPC0gbGVuZ3RoKHNlcmllKQogIGZpdHRlZCA8LSByZXAoTkEsIG4pCiAgZm9yIChpIGluIChrKzEpOm4pIGZpdHRlZFtpXSA8LSBtZWFuKHNlcmllWyhpLWspOihpLTEpXSkKICBtYXBlIDwtIG1lYW4oYWJzKChzZXJpZVsoaysxKTpuXSAtIGZpdHRlZFsoaysxKTpuXSkgLyBzZXJpZVsoaysxKTpuXSkpICogMTAwCiAgZXh0IDwtIGMoc2VyaWUsIHJlcChOQSwgaCkpCiAgZm9yIChpIGluIChuKzEpOihuK2gpKSBleHRbaV0gPC0gbWVhbihleHRbKGktayk6KGktMSldKQogIGxpc3QoZml0dGVkID0gZml0dGVkLCBtYXBlID0gbWFwZSwgZm9yZWNhc3QgPSBleHRbKG4rMSk6KG4raCldKQp9CgojIE1vZGVsbyAyLiBQcm9tZWRpbyBNw7N2aWwgKGsgPSAzKQptYTEgPC0gbWFfZm9yZWNhc3QodmFsb3IsIGsgPSAzLCBoID0gNikKbWExJG1hcGUgICAgICAgIyBNQVBFIGRlbCBtb2RlbG8KbWExJGZvcmVjYXN0ICAgIyBQcm9uw7NzdGljbyBkZSBsYXMgc2lndWllbnRlcyA2IHNlbWFuYXMKCiMgRnVuY2nDs24gZ2Vuw6lyaWNhIGRlIFByb21lZGlvIE3Ds3ZpbCBQb25kZXJhZG86IGxvcyBwZXNvcyBzZSBhcGxpY2FuIGRlbCBtw6FzCiMgYW50aWd1byBhbCBtw6FzIHJlY2llbnRlLCBwb3IgbG8gcXVlIGVsIHZhbG9yIG3DoXMgcmVjaWVudGUgcGVzYSBtw6FzICgzLzYpLgp3bWFfZm9yZWNhc3QgPC0gZnVuY3Rpb24oc2VyaWUsIHBlc29zLCBoKXsKICBrIDwtIGxlbmd0aChwZXNvcykKICBuIDwtIGxlbmd0aChzZXJpZSkKICBmaXR0ZWQgPC0gcmVwKE5BLCBuKQogIGZvciAoaSBpbiAoaysxKTpuKSBmaXR0ZWRbaV0gPC0gc3VtKHNlcmllWyhpLWspOihpLTEpXSAqIHBlc29zKQogIG1hcGUgPC0gbWVhbihhYnMoKHNlcmllWyhrKzEpOm5dIC0gZml0dGVkWyhrKzEpOm5dKSAvIHNlcmllWyhrKzEpOm5dKSkgKiAxMDAKICBleHQgPC0gYyhzZXJpZSwgcmVwKE5BLCBoKSkKICBmb3IgKGkgaW4gKG4rMSk6KG4raCkpIGV4dFtpXSA8LSBzdW0oZXh0WyhpLWspOihpLTEpXSAqIHBlc29zKQogIGxpc3QoZml0dGVkID0gZml0dGVkLCBtYXBlID0gbWFwZSwgZm9yZWNhc3QgPSBleHRbKG4rMSk6KG4raCldKQp9CgpwZXNvcyA8LSBjKDEsMiwzKS82ICAjIDEvNiBhbCBtw6FzIGFudGlndW8sIDIvNiBhbCBpbnRlcm1lZGlvLCAzLzYgYWwgbcOhcyByZWNpZW50ZQoKIyBNb2RlbG8gMy4gUHJvbWVkaW8gTcOzdmlsIFBvbmRlcmFkbyAoayA9MyBQZXNvczogMy82LCAyLzYsIHkgMS82KQp3bWExIDwtIHdtYV9mb3JlY2FzdCh2YWxvciwgcGVzb3MsIGggPSA2KQp3bWExJG1hcGUKd21hMSRmb3JlY2FzdAoKIyBNb2RlbG8gNC4gU3Vhdml6YWRvciBFeHBvbmVuY2lhbCAoYWxmYSA9IDAuMikuIE1lbm9yIGFsZmEgPSBtZWpvciBtb2RlbG8Kc2VzMSA8LSBzZXModHMxLCBhbHBoYSA9IDAuMiwgaCA9IDYpCnN1bW1hcnkoc2VzMSkKbWFwZV9zZXMxIDwtIGFjY3VyYWN5KHNlczEpWzEsIk1BUEUiXQoKIyBNb2RlbG8gNS4gQVJJTUEKYXJpbWExIDwtIGF1dG8uYXJpbWEodHMxKQphcmltYTEKcHJvbm9zdGljbzEgPC0gZm9yZWNhc3QoYXJpbWExLCBsZXZlbCA9IGMoOTUpLCBoID0gNikKcGxvdChwcm9ub3N0aWNvMSkKbWFwZV9hcmltYTEgPC0gYWNjdXJhY3koYXJpbWExKVsxLCJNQVBFIl0KCiMgVGFibGEgY29uIGVsIFJlc3VtZW4gZGUgbG9zIFJlc3VsdGFkb3MuCnJlc3VtZW4xIDwtIGRhdGEuZnJhbWUoCiAgTW9kZWxvID0gYygiTmFpdmUiLCAiUHJvbWVkaW8gTcOzdmlsIChrPTMpIiwgIlByb21lZGlvIE3Ds3ZpbCBQb25kZXJhZG8iLAogICAgICAgICAgICAgIlN1YXZpemFkb3IgRXhwb25lbmNpYWwgKGFsZmE9MC4yKSIsICJBUklNQSIpLAogIE1BUEUgPSByb3VuZChjKG1hcGVfbmFpdmUxLCBtYTEkbWFwZSwgd21hMSRtYXBlLCBtYXBlX3NlczEsIG1hcGVfYXJpbWExKSwgMikKKQpyZXN1bWVuMSA8LSByZXN1bWVuMVtvcmRlcihyZXN1bWVuMSRNQVBFKSwgXQpyZXN1bWVuMQoKcHJvbm9zdGljb19maW5hbDEgPC0gZGF0YS5mcmFtZSgKICBTZW1hbmEgPSAxMzoxOCwKICBOYWl2ZSA9IGFzLm51bWVyaWMobmFpdmUxJG1lYW4pLAogIFByb21fTW92aWwgPSBtYTEkZm9yZWNhc3QsCiAgUHJvbV9Nb3ZpbF9Qb25kID0gd21hMSRmb3JlY2FzdCwKICBTdWF2aXphZG9yX0V4cCA9IGFzLm51bWVyaWMoc2VzMSRtZWFuKSwKICBBUklNQSA9IGFzLm51bWVyaWMocHJvbm9zdGljbzEkbWVhbikKKQpwcm9ub3N0aWNvX2ZpbmFsMQoKIyBDb25jbHVzacOzbiBNw6l0b2RvIEFSRS4KbWVqb3IxIDwtIHJlc3VtZW4xJE1vZGVsb1sxXQpjYXQoIkVsIG1vZGVsbyBjb24gZWwgTUFQRSBtw6FzIGJham8gKCIsIHJvdW5kKHJlc3VtZW4xJE1BUEVbMV0sMiksCiAgICAiJSkgZXM6IiwgbWVqb3IxLAogICAgIi4gUG9yIGxvIHRhbnRvIGVzIGVsIG1vZGVsbyBtw6FzIGFkZWN1YWRvIHBhcmEgcHJvbm9zdGljYXIgbGFzIHNpZ3VpZW50ZXMgNiBzZW1hbmFzLlxuIikKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkIj5FamVyY2ljaW8gMi4gSGVyc2hleSdzPC9zcGFuPgpJTlNUUlVDQ0lPTkVTOiBNb2RlbGEgbGEgc2lndWVpbnRlIFNlcmllIGRlIFRpZW1wbyB5IGVsaWdlIGxhIG1lam9yIG9wY2nDs24uClByb25vc3RpY2EgbGFzIHNpZ3VlaW50ZXMgNiBzZW1hbmFzLgoKYGBge3J9CnJ1dGEgPC0gIi9Vc2Vycy9hZHJpYW5hL0Rvd25sb2Fkcy9WZW50YXNfSGlzdMOzcmljYXNfTGVjaGl0YXMueGxzeCIKCmRhdG9zIDwtIHJlYWRfZXhjZWwocnV0YSwgc2hlZXQgPSAxLCBza2lwID0gMikKCnZlbnRhcyA8LSBhcy5udW1lcmljKGMoZGF0b3NbWzJdXSwgZGF0b3NbWzRdXSwgZGF0b3NbWzZdXSkpICAjIGNvbmNhdGVuYSAyMDE3LTIwMTgtMjAxOQptZXMgPC0gMTpsZW5ndGgodmVudGFzKQpkZjIgPC0gZGF0YS5mcmFtZShtZXMsIHZlbnRhcykKCnRzMiA8LSB0cyh2ZW50YXMsIHN0YXJ0ID0gYygyMDE3LDEpLCBmcmVxdWVuY3kgPSAxMikKcGxvdCh0czIsIG1haW4gPSAiVmVudGFzIGhpc3TDs3JpY2FzIGRlIGxlY2hlIHNhYm9yaXphZGEgSGVyc2hleSAoTGVjaGl0YXMpIiwKICAgICB5bGFiID0gIlZlbnRhcyAobWlsZXMgZGUgZMOzbGFyZXMpIiwgeGxhYiA9ICJBw7FvIikKCiMgTW9kZWxvIDEuIE5haXZlCm5haXZlMiA8LSBuYWl2ZSh0czIsIGggPSA2KQpzdW1tYXJ5KG5haXZlMikKbWFwZV9uYWl2ZTIgPC0gYWNjdXJhY3kobmFpdmUyKVsxLCJNQVBFIl0KIyBNb2RlbG8gY29uIG1lbm9yIE1BUEUgZXMgZWwgbWFzIGFkZWN1YWRvLgoKIyBNb2RlbG8gMi4gUHJvbWVkaW8gTcOzdmlsIChrID0gMykKbWEyIDwtIG1hX2ZvcmVjYXN0KHZlbnRhcywgayA9IDMsIGggPSA2KQptYTIkbWFwZQptYTIkZm9yZWNhc3QKCiMgTW9kZWxvIDMuIFByb21lZGlvIE3Ds3ZpbCBQb25kZXJhZG8gKGsgPTMgUGVzb3M6IDMvNiwgMi82LCB5IDEvNikKd21hMiA8LSB3bWFfZm9yZWNhc3QodmVudGFzLCBwZXNvcywgaCA9IDYpCndtYTIkbWFwZQp3bWEyJGZvcmVjYXN0CgojIE1vZGVsbyA0LiBTdWF2aXphZG9yIEV4cG9uZW5jaWFsIChhbGZhID0gMC4yKS4gTWVub3IgYWxmYSA9IG1lam9yIG1vZGVsbwpzZXMyIDwtIHNlcyh0czIsIGFscGhhID0gMC4yLCBoID0gNikKc3VtbWFyeShzZXMyKQptYXBlX3NlczIgPC0gYWNjdXJhY3koc2VzMilbMSwiTUFQRSJdCgojIE1vZGVsbyA1LiBBUklNQQphcmltYTIgPC0gYXV0by5hcmltYSh0czIpCmFyaW1hMgpwcm9ub3N0aWNvMiA8LSBmb3JlY2FzdChhcmltYTIsIGxldmVsID0gYyg5NSksIGggPSA2KQpwbG90KHByb25vc3RpY28yKQptYXBlX2FyaW1hMiA8LSBhY2N1cmFjeShhcmltYTIpWzEsIk1BUEUiXQoKIyBUYWJsYSBjb24gZWwgUmVzdW1lbiBkZSBsb3MgUmVzdWx0YWRvcy4KcmVzdW1lbjIgPC0gZGF0YS5mcmFtZSgKICBNb2RlbG8gPSBjKCJOYWl2ZSIsICJQcm9tZWRpbyBNw7N2aWwgKGs9MykiLCAiUHJvbWVkaW8gTcOzdmlsIFBvbmRlcmFkbyIsCiAgICAgICAgICAgICAiU3Vhdml6YWRvciBFeHBvbmVuY2lhbCAoYWxmYT0wLjIpIiwgIkFSSU1BIiksCiAgTUFQRSA9IHJvdW5kKGMobWFwZV9uYWl2ZTIsIG1hMiRtYXBlLCB3bWEyJG1hcGUsIG1hcGVfc2VzMiwgbWFwZV9hcmltYTIpLCAyKQopCnJlc3VtZW4yIDwtIHJlc3VtZW4yW29yZGVyKHJlc3VtZW4yJE1BUEUpLCBdCnJlc3VtZW4yCgpwcm9ub3N0aWNvX2ZpbmFsMiA8LSBkYXRhLmZyYW1lKAogIE1lcyA9IDM3OjQyLAogIE5haXZlID0gYXMubnVtZXJpYyhuYWl2ZTIkbWVhbiksCiAgUHJvbV9Nb3ZpbCA9IG1hMiRmb3JlY2FzdCwKICBQcm9tX01vdmlsX1BvbmQgPSB3bWEyJGZvcmVjYXN0LAogIFN1YXZpemFkb3JfRXhwID0gYXMubnVtZXJpYyhzZXMyJG1lYW4pLAogIEFSSU1BID0gYXMubnVtZXJpYyhwcm9ub3N0aWNvMiRtZWFuKQopCnByb25vc3RpY29fZmluYWwyCgojIENvbmNsdXNpw7NuIE3DqXRvZG8gQVJFLgptZWpvcjIgPC0gcmVzdW1lbjIkTW9kZWxvWzFdCmNhdCgiRWwgbW9kZWxvIGNvbiBlbCBNQVBFIG3DoXMgYmFqbyAoIiwgcm91bmQocmVzdW1lbjIkTUFQRVsxXSwyKSwKICAgICIlKSBlczoiLCBtZWpvcjIsCiAgICAiLiBQb3IgbG8gdGFudG8gZXMgZWwgbW9kZWxvIG3DoXMgYWRlY3VhZG8gcGFyYSBwcm9ub3N0aWNhciBsYXMgdmVudGFzIGRlIGxvcyBwcsOzeGltb3MgNiBtZXNlcyBkZSBMZWNoaXRhcy5cbiIpCmBgYAoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZCI+RWplcmNpY2lvIDMuIFZpbnRhZ2UgUmVzdGF1cmFudDwvc3Bhbj4KSU5TVFJVQ0NJT05FUzogQW5hbGl6YSBsYXMgdmVudGFzIGRlIGFsaW1lbnRvcyB5IGJlYmlkYXMgZGVsIFZpbnRhZ2UgUmVzdGF1cmFudAooVGFibGEgMTguMjYpIGUgaW5jbHV5ZTogZ3LDoWZpY2EgZGUgbGEgc2VyaWUsIMOtbmRpY2VzIGVzdGFjaW9uYWxlcywgc2VyaWUKZGVzZXN0YWNpb25hbGl6YWRhLCBwcm9uw7NzdGljbyBwb3IgZGVzY29tcG9zaWNpw7NuIHkgcG9yIHJlZ3Jlc2nDs24gY29uCnZhcmlhYmxlcyBmaWN0aWNpYXMgcGFyYSBlbCBhw7FvIDQsIHRhYmxhcyByZXN1bWVuIHkgY29uY2x1c2lvbmVzLgoKYGBge3J9CiMgVmVudGFzIGRlIGFsaW1lbnRvcyB5IGJlYmlkYXMgZGVsIHJlc3RhdXJhbnRlIFZpbnRhZ2UgKCQgbWlsZXMpCnZpbnRhZ2UgPC0gYygyNDIsMjM1LDIzMiwxNzgsMTg0LDE0MCwxNDUsMTUyLDExMCwxMzAsMTUyLDIwNiwgICAjIEHDsW8gMQogICAgICAgICAgICAgMjYzLDIzOCwyNDcsMTkzLDE5MywxNDksMTU3LDE2MSwxMjIsMTMwLDE2NywyMzAsICAgIyBBw7FvIDIKICAgICAgICAgICAgIDI4MiwyNTUsMjY1LDIwNSwyMTAsMTYwLDE2NiwxNzQsMTI2LDE0OCwxNzMsMjM1KSAgICMgQcOxbyAzCgp0c192aW50YWdlIDwtIHRzKHZpbnRhZ2UsIHN0YXJ0ID0gYygxLDEpLCBmcmVxdWVuY3kgPSAxMikKCiMgMS4gR3LDoWZpY2EgZGUgbGEgc2VyaWUgZGUgdGllbXBvCnBsb3QodHNfdmludGFnZSwgbWFpbiA9ICJWZW50YXMgZGUgYWxpbWVudG9zIHkgYmViaWRhcyAtIFZpbnRhZ2UgUmVzdGF1cmFudCIsCiAgICAgeWxhYiA9ICJWZW50YXMgKCQgbWlsZXMpIiwgeGxhYiA9ICJBw7FvIiwgdHlwZSA9ICJvIikKYGBgClBhdHLDs24gcHJpbmNpcGFsOiBzZSBvYnNlcnZhIHVuIGNvbXBvbmVudGUgZXN0YWNpb25hbCBtdXkgbWFyY2FkbyBxdWUgc2UKcmVwaXRlIGNhZGEgMTIgbWVzZXMgKHZlbnRhcyBhbHRhcyBlbiBsYSB0ZW1wb3JhZGEgZGUgaW52aWVybm86IGRpYy1lbmUtZmViLW1hciwKeSBiYWphcyBlbiBlbCB2ZXJhbm8vb3Rvw7FvLCBjb24gZWwgbcOtbmltbyBlbiBzZXB0aWVtYnJlKSwganVudG8gY29uIHVuYQp0ZW5kZW5jaWEgY3JlY2llbnRlIGRlIHVuIGHDsW8gYSBvdHJvIGNvbmZvcm1lIGNyZWNlIGxhIHJlcHV0YWNpw7NuIGRlbApyZXN0YXVyYW50ZS4KCmBgYHtyfQojIDIuIERlc2NvbXBvc2ljacOzbiBtdWx0aXBsaWNhdGl2YSBlIMOtbmRpY2VzIGVzdGFjaW9uYWxlcwpkZWNvbXBfdmludGFnZSA8LSBkZWNvbXBvc2UodHNfdmludGFnZSwgdHlwZSA9ICJtdWx0aXBsaWNhdGl2ZSIpCnBsb3QoZGVjb21wX3ZpbnRhZ2UpCgppbmRpY2VzX2VzdGFjaW9uYWxlcyA8LSBkYXRhLmZyYW1lKAogIE1lcyA9IG1vbnRoLm5hbWUsCiAgSW5kaWNlID0gcm91bmQoYXMubnVtZXJpYyhkZWNvbXBfdmludGFnZSRmaWd1cmUpLCAzKQopCmluZGljZXNfZXN0YWNpb25hbGVzCmBgYApMb3Mgw61uZGljZXMgZXN0YWNpb25hbGVzIG11ZXN0cmFuIHRlbXBvcmFkYSBhbHRhIGVuIGVuZXJvLW1hcnpvIHkgZGljaWVtYnJlCijDrW5kaWNlcyBhcnJpYmEgZGUgMSwgdmVudGFzIHBvciBlbmNpbWEgZGVsIHByb21lZGlvKSB5IHRlbXBvcmFkYSBiYWphIGVuCnNlcHRpZW1icmUgeSBvY3R1YnJlICjDrW5kaWNlcyBtdXkgcG9yIGRlYmFqbyBkZSAxKS4gRXN0byB0aWVuZSBzZW50aWRvCmludHVpdGl2bzogQ2FwdGl2YSBJc2xhbmQgZXMgdW4gZGVzdGlubyB0dXLDrXN0aWNvIGRlIGludmllcm5vICh0ZW1wb3JhZGEgZGUKInNub3diaXJkcyIpLCBtaWVudHJhcyBxdWUgc2VwdGllbWJyZS1vY3R1YnJlIGNvaW5jaWRlIGNvbiBsYSB0ZW1wb3JhZGEgYmFqYQpkZSB0dXJpc21vIHkgZGUgaHVyYWNhbmVzIGVuIEZsb3JpZGEuCgpgYGB7cn0KIyAzLiBTZXJpZSBkZXNlc3RhY2lvbmFsaXphZGEgeSBhbsOhbGlzaXMgZGUgdGVuZGVuY2lhCmRlc2Vhc29uYWxpemVkIDwtIHRzX3ZpbnRhZ2UgLyBkZWNvbXBfdmludGFnZSRzZWFzb25hbApwbG90KGRlc2Vhc29uYWxpemVkLCBtYWluID0gIlNlcmllIGRlc2VzdGFjaW9uYWxpemFkYSAtIFZpbnRhZ2UgUmVzdGF1cmFudCIsCiAgICAgeWxhYiA9ICJWZW50YXMgKCQgbWlsZXMpIiwgeGxhYiA9ICJBw7FvIiwgdHlwZSA9ICJvIikKCnQgPC0gMTozNgptb2RlbG9fdGVuZGVuY2lhIDwtIGxtKGFzLm51bWVyaWMoZGVzZWFzb25hbGl6ZWQpIH4gdCkKc3VtbWFyeShtb2RlbG9fdGVuZGVuY2lhKQpgYGAKTGEgc2VyaWUgZGVzZXN0YWNpb25hbGl6YWRhIHPDrSBtdWVzdHJhIHVuYSB0ZW5kZW5jaWEgbGluZWFsIGNyZWNpZW50ZTogbGEKcGVuZGllbnRlIGVzdGltYWRhIGVzIHBvc2l0aXZhIHkgZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2YSwgbG8gcXVlCmNvbmZpcm1hIHF1ZSwgcXVpdGFuZG8gZWwgZWZlY3RvIGVzdGFjaW9uYWwsIGxhcyB2ZW50YXMgZGVsIHJlc3RhdXJhbnRlCmNyZWNlbiBtZXMgY29uIG1lcy4KCmBgYHtyfQojIDQuIFByb27Ds3N0aWNvIHBvciBlbCBtw6l0b2RvIGRlIGRlc2NvbXBvc2ljacOzbiBwYXJhIGVsIGHDsW8gNApwcmVkX3RlbmRlbmNpYV9hNCA8LSBwcmVkaWN0KG1vZGVsb190ZW5kZW5jaWEsIG5ld2RhdGEgPSBkYXRhLmZyYW1lKHQgPSAzNzo0OCkpCmVzdGFjaW9uYWxfYTQgPC0gYXMubnVtZXJpYyhkZWNvbXBfdmludGFnZSRmaWd1cmUpICAjIDEyIMOtbmRpY2VzLCBFbmUtRGljCnByb25vc3RpY29fZGVzY29tcCA8LSBwcmVkX3RlbmRlbmNpYV9hNCAqIGVzdGFjaW9uYWxfYTQKCnByb25vc3RpY29fZGVzY29tcF90YWJsYSA8LSBkYXRhLmZyYW1lKAogIE1lcyA9IG1vbnRoLm5hbWUsCiAgUHJvbm9zdGljb19EZXNjb21wb3NpY2lvbiA9IHJvdW5kKHByb25vc3RpY29fZGVzY29tcCwgMSkKKQpwcm9ub3N0aWNvX2Rlc2NvbXBfdGFibGEKYGBgCgpgYGB7cn0KIyA1LiBQcm9uw7NzdGljbyBwb3IgcmVncmVzacOzbiBjb24gdmFyaWFibGVzIGZpY3RpY2lhcyAoZHVtbXkgdmFyaWFibGVzKQptZXNfZmFjdG9yIDwtIGZhY3RvcihyZXAoMToxMiwgMykpCm1vZGVsb19kdW1teSA8LSBsbSh2aW50YWdlIH4gdCArIG1lc19mYWN0b3IpCnN1bW1hcnkobW9kZWxvX2R1bW15KQoKcHJvbm9zdGljb19yZWdyZXNpb24gPC0gcHJlZGljdCgKICBtb2RlbG9fZHVtbXksCiAgbmV3ZGF0YSA9IGRhdGEuZnJhbWUodCA9IDM3OjQ4LCBtZXNfZmFjdG9yID0gZmFjdG9yKDE6MTIsIGxldmVscyA9IGxldmVscyhtZXNfZmFjdG9yKSkpCikKCnByb25vc3RpY29fcmVncmVzaW9uX3RhYmxhIDwtIGRhdGEuZnJhbWUoCiAgTWVzID0gbW9udGgubmFtZSwKICBQcm9ub3N0aWNvX1JlZ3Jlc2lvbiA9IHJvdW5kKGFzLm51bWVyaWMocHJvbm9zdGljb19yZWdyZXNpb24pLCAxKQopCnByb25vc3RpY29fcmVncmVzaW9uX3RhYmxhCmBgYAoKYGBge3J9CiMgNi4gVGFibGEgcmVzdW1lbiBjb24gYW1ib3MgbcOpdG9kb3MgeSBncsOhZmljYSBjb21wYXJhdGl2YQpyZXN1bWVuX3ZpbnRhZ2UgPC0gZGF0YS5mcmFtZSgKICBNZXMgPSBtb250aC5uYW1lLAogIERlc2NvbXBvc2ljaW9uID0gcm91bmQocHJvbm9zdGljb19kZXNjb21wLCAxKSwKICBSZWdyZXNpb25fRHVtbXkgPSByb3VuZChhcy5udW1lcmljKHByb25vc3RpY29fcmVncmVzaW9uKSwgMSkKKQpyZXN1bWVuX3ZpbnRhZ2UKCm1hdHBsb3QoMToxMiwgcmVzdW1lbl92aW50YWdlWywgYygiRGVzY29tcG9zaWNpb24iLCJSZWdyZXNpb25fRHVtbXkiKV0sIHR5cGUgPSAibyIsIHBjaCA9IDE2LAogICAgICAgIGNvbCA9IGMoImJsdWUiLCJyZWQiKSwgeGF4dCA9ICJuIiwKICAgICAgICBtYWluID0gIlByb27Ds3N0aWNvIEHDsW8gNCAtIFZpbnRhZ2UgUmVzdGF1cmFudCIsCiAgICAgICAgeGxhYiA9ICJNZXMiLCB5bGFiID0gIlZlbnRhcyAoJCBtaWxlcykiKQpheGlzKDEsIGF0ID0gMToxMiwgbGFiZWxzID0gbW9udGguYWJiKQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiRGVzY29tcG9zaWNpw7NuIiwiUmVncmVzacOzbiBEdW1teSIpLCBjb2wgPSBjKCJibHVlIiwicmVkIiksIGx0eSA9IDEsIHBjaCA9IDE2KQoKIyBFcnJvciBkZSBwcm9uw7NzdGljbyBkZSBlbmVybyBkZWwgYcOxbyA0ICh2ZW50YSByZWFsIHJlcG9ydGFkYSA9ICQyOTUgbWlsZXMpCnZlbnRhX3JlYWxfZW5lcm9fYTQgPC0gMjk1CmVycm9yX2Rlc2NvbXBfZW5lIDwtIHZlbnRhX3JlYWxfZW5lcm9fYTQgLSByZXN1bWVuX3ZpbnRhZ2UkRGVzY29tcG9zaWNpb25bMV0KZXJyb3JfcmVncmVzaW9uX2VuZSA8LSB2ZW50YV9yZWFsX2VuZXJvX2E0IC0gcmVzdW1lbl92aW50YWdlJFJlZ3Jlc2lvbl9EdW1teVsxXQoKY2F0KCJFcnJvciBkZSBwcm9uw7NzdGljbyAoRGVzY29tcG9zaWNpw7NuKSBwYXJhIGVuZXJvIGRlbCBhw7FvIDQ6Iiwgcm91bmQoZXJyb3JfZGVzY29tcF9lbmUsMSksICJcbiIpCmNhdCgiRXJyb3IgZGUgcHJvbsOzc3RpY28gKFJlZ3Jlc2nDs24gY29uIGR1bW1pZXMpIHBhcmEgZW5lcm8gZGVsIGHDsW8gNDoiLCByb3VuZChlcnJvcl9yZWdyZXNpb25fZW5lLDEpLCAiXG4iKQpgYGAKCioqQ29uY2x1c2lvbmVzIEVqZXJjaWNpbyAzOioqIGFtYm9zIG3DqXRvZG9zIGFycm9qYW4gcHJvbsOzc3RpY29zIHNpbWlsYXJlcwpwYXJhIGVuZXJvIGRlbCBhw7FvIDQsIHkgZWwgZXJyb3IgZnJlbnRlIGEgbGEgdmVudGEgcmVhbCAoJDI5NSBtaWwpIGVzCnJlbGF0aXZhbWVudGUgcGVxdWXDsW8gZW4gY29tcGFyYWNpw7NuIGNvbiBlbCBuaXZlbCBkZSB2ZW50YXMsIGxvIHF1ZSBpbmRpY2EKcXVlIGxvcyBtb2RlbG9zIGNhcHR1cmFuIGJpZW4gZWwgcGF0csOzbiBlc3RhY2lvbmFsIHkgbGEgdGVuZGVuY2lhLiBTaSBhIEthcmVuCmxlIHByZW9jdXBhIGVzYSBkaWZlcmVuY2lhLCBwdWVkZSByZWR1Y2lyIGxhIGluY2VydGlkdW1icmUgZ2VuZXJhbmRvIHVuCmludGVydmFsbyBkZSBwcm9uw7NzdGljbyAoZW4gdmV6IGRlIHVuIHNvbG8gbsO6bWVybyksIGFjdHVhbGl6YW5kbyBlbCBtb2RlbG8KY2FkYSBtZXMgY29uIGxvcyBkYXRvcyByZWFsZXMgbcOhcyByZWNpZW50ZXMgKHByb27Ds3N0aWNvIG3Ds3ZpbCAvIHJlY2FsaWJyYWNpw7NuCmNvbnRpbnVhKSwgeSBtb25pdG9yZWFuZG8gc2kgZWwgZXJyb3Igc2UgbWFudGllbmUgZGVudHJvIGRlIHVuIHJhbmdvCnJhem9uYWJsZSBvIHNpIGNyZWNlIGRlIGZvcm1hIHNpc3RlbcOhdGljYSwgbG8gY3VhbCBzZcOxYWxhcsOtYSBxdWUgZWwgcGF0csOzbgpkZSBsYSBzZXJpZSBlc3TDoSBjYW1iaWFuZG8uCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkIj5FamVyY2ljaW8gNC4gQ2FybHNvbiBEZXBhcnRtZW50IFN0b3JlPC9zcGFuPgpJTlNUUlVDQ0lPTkVTOiBFc3RpbWEgbGFzIHZlbnRhcyBxdWUgQ2FybHNvbiB5IGVsIGNvbmRhZG8gaGFicsOtYW4gdGVuaWRvIGRlCnNlcHRpZW1icmUgYSBkaWNpZW1icmUgZGVsIGHDsW8gNSBzaSBubyBodWJpZXJhIG9jdXJyaWRvIGVsIGh1cmFjw6FuLCBlc3RpbWEgbGEKcMOpcmRpZGEgZGUgdmVudGFzIGRlIENhcmxzb24sIHkgZXZhbMO6YSBzaSBoYXkgZXZpZGVuY2lhIGRlIHVuIGV4Y2VzbyBkZQp2ZW50YXMgZW4gZWwgY29uZGFkbyByZWxhY2lvbmFkbyBjb24gZWwgaHVyYWPDoW4uCgpgYGB7cn0KIyBWZW50YXMgZGUgQ2FybHNvbiBEZXBhcnRtZW50IFN0b3JlICgkIG1pbGxvbmVzKQojIDQ4IG1lc2VzOiBkZSBzZXB0aWVtYnJlIGRlbCBBw7FvIDEgYSBhZ29zdG8gZGVsIEHDsW8gNSAobWVzIHByZXZpbyBhbCBodXJhY8OhbikKY2FybHNvbiA8LSBjKDEuNzEsMS45MCwyLjc0LDQuMjAsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBTZXAtRGljIEHDsW8gMQogICAgICAgICAgICAgMS40NSwxLjgwLDIuMDMsMS45OSwyLjMyLDIuMjAsMi4xMywyLjQzLDEuOTAsMi4xMywyLjU2LDQuMTYsICAjIEHDsW8gMiBjb21wbGV0bwogICAgICAgICAgICAgMi4zMSwxLjg5LDIuMDIsMi4yMywyLjM5LDIuMTQsMi4yNywyLjIxLDEuODksMi4yOSwyLjgzLDQuMDQsICAjIEHDsW8gMyBjb21wbGV0bwogICAgICAgICAgICAgMi4zMSwxLjk5LDIuNDIsMi40NSwyLjU3LDIuNDIsMi40MCwyLjUwLDIuMDksMi41NCwyLjk3LDQuMzUsICAjIEHDsW8gNCBjb21wbGV0bwogICAgICAgICAgICAgMi41NiwyLjI4LDIuNjksMi40OCwyLjczLDIuMzcsMi4zMSwyLjIzKSAgICAgICAgICAgICAgICAgICAgICMgRW5lLUFnbyBBw7FvIDUKCiMgVmVudGFzIGRlIGxhcyB0aWVuZGFzIGRlcGFydGFtZW50YWxlcyBkZWwgY29uZGFkbyAoJCBtaWxsb25lcykKIyBNaXNtb3MgNDggbWVzZXMgcXVlIGxhIHNlcmllIGRlIENhcmxzb24KY29uZGFkbyA8LSBjKDU1LjgwLDU2LjQwLDcxLjQwLDExNy42MCwKICAgICAgICAgICAgIDQ2LjgwLDQ4LjAwLDYwLjAwLDU3LjYwLDYxLjgwLDU4LjIwLDU2LjQwLDYzLjAwLDU3LjYwLDUzLjQwLDcxLjQwLDExNC4wMCwKICAgICAgICAgICAgIDQ2LjgwLDQ4LjYwLDU5LjQwLDU4LjIwLDYwLjYwLDU1LjIwLDUxLjAwLDU4LjgwLDQ5LjgwLDU0LjYwLDY1LjQwLDEwMi4wMCwKICAgICAgICAgICAgIDQzLjgwLDQ1LjYwLDU3LjYwLDUzLjQwLDU2LjQwLDUyLjgwLDU0LjAwLDYwLjYwLDQ3LjQwLDU0LjYwLDY3LjgwLDEwMC4yMCwKICAgICAgICAgICAgIDQ4LjAwLDUxLjYwLDU3LjYwLDU4LjIwLDYwLjAwLDU3LjAwLDU3LjYwLDYxLjgwKQoKIyBWZW50YXMgcmVhbGVzIGRlbCBjb25kYWRvIGR1cmFudGUgbG9zIDQgbWVzZXMgZW4gcXVlIENhcmxzb24gcGVybWFuZWNpw7MgY2VycmFkYQojIChTZXAtRGljIEHDsW8gNSwgZGVzcHXDqXMgZGVsIGh1cmFjw6FuKQpjb25kYWRvX3JlYWxfY2llcnJlIDwtIGMoNjkuMDAsIDc1LjAwLCA4NS4yMCwgMTIxLjgwKQoKbGVuZ3RoKGNhcmxzb24pICAjIGRlYmUgc2VyIDQ4Cmxlbmd0aChjb25kYWRvKSAgIyBkZWJlIHNlciA0OAoKIyBTZWN1ZW5jaWEgZGUgbWVzIGNhbGVuZGFyaW8gKDE9RW5lIC4uLiAxMj1EaWMpIHBhcmEgbG9zIDQ4IG1lc2VzLCBlbXBlemFuZG8gZW4gc2VwdGllbWJyZQptZXNlc19zZXEgPC0gYyg5LDEwLDExLDEyLCByZXAoMToxMiwgMyksIDEsMiwzLDQsNSw2LDcsOCkKZmFjdG9yX21lc2VzIDwtIGZhY3RvcihtZXNlc19zZXEpCnQ0OCA8LSAxOjQ4CmBgYAoKYGBge3J9CiMgMS4gRXN0aW1hY2nDs24gZGUgbGFzIHZlbnRhcyBxdWUgQ2FybHNvbiBoYWJyw61hIHRlbmlkbyBkZSBTZXAgYSBEaWMgZGVsIEHDsW8gNQptb2RlbG9fY2FybHNvbiA8LSBsbShjYXJsc29uIH4gdDQ4ICsgZmFjdG9yX21lc2VzKQpzdW1tYXJ5KG1vZGVsb19jYXJsc29uKQoKcHJvbm9zdGljb19jYXJsc29uX2NpZXJyZSA8LSBwcmVkaWN0KAogIG1vZGVsb19jYXJsc29uLAogIG5ld2RhdGEgPSBkYXRhLmZyYW1lKHQ0OCA9IDQ5OjUyLCBmYWN0b3JfbWVzZXMgPSBmYWN0b3IoYyg5LDEwLDExLDEyKSwgbGV2ZWxzID0gbGV2ZWxzKGZhY3Rvcl9tZXNlcykpKQopCnByb25vc3RpY29fY2FybHNvbl9jaWVycmUKYGBgCgpgYGB7cn0KIyAyLiBFc3RpbWFjacOzbiBkZSBsYXMgdmVudGFzIHF1ZSBlbCBjb25kYWRvIGhhYnLDrWEgdGVuaWRvIGRlIFNlcCBhIERpYyBkZWwgQcOxbyA1Cm1vZGVsb19jb25kYWRvIDwtIGxtKGNvbmRhZG8gfiB0NDggKyBmYWN0b3JfbWVzZXMpCnN1bW1hcnkobW9kZWxvX2NvbmRhZG8pCgpwcm9ub3N0aWNvX2NvbmRhZG9fY2llcnJlIDwtIHByZWRpY3QoCiAgbW9kZWxvX2NvbmRhZG8sCiAgbmV3ZGF0YSA9IGRhdGEuZnJhbWUodDQ4ID0gNDk6NTIsIGZhY3Rvcl9tZXNlcyA9IGZhY3RvcihjKDksMTAsMTEsMTIpLCBsZXZlbHMgPSBsZXZlbHMoZmFjdG9yX21lc2VzKSkpCikKcHJvbm9zdGljb19jb25kYWRvX2NpZXJyZQpgYGAKCmBgYHtyfQojIDMuIEVzdGltYWNpw7NuIGRlIGxhIHDDqXJkaWRhIGRlIHZlbnRhcyBkZSBDYXJsc29uIChTZXAtRGljIEHDsW8gNSkKcmVzdW1lbl9jYXJsc29uIDwtIGRhdGEuZnJhbWUoCiAgTWVzID0gYygiU2VwdGllbWJyZSIsIk9jdHVicmUiLCJOb3ZpZW1icmUiLCJEaWNpZW1icmUiKSwKICBWZW50YXNfRXN0aW1hZGFzID0gcm91bmQoYXMubnVtZXJpYyhwcm9ub3N0aWNvX2Nhcmxzb25fY2llcnJlKSwgMyksCiAgVmVudGFzX1JlYWxlcyA9IGMoMCwgMCwgMCwgMCkgICMgbGEgdGllbmRhIGVzdHV2byBjZXJyYWRhLCB2ZW50YXMgcmVhbGVzID0gMAopCnJlc3VtZW5fY2FybHNvbiRQZXJkaWRhIDwtIHJlc3VtZW5fY2FybHNvbiRWZW50YXNfRXN0aW1hZGFzIC0gcmVzdW1lbl9jYXJsc29uJFZlbnRhc19SZWFsZXMKcmVzdW1lbl9jYXJsc29uCgpwZXJkaWRhX3RvdGFsX2Nhcmxzb24gPC0gc3VtKHJlc3VtZW5fY2FybHNvbiRQZXJkaWRhKQpjYXQoIlDDqXJkaWRhIHRvdGFsIGVzdGltYWRhIGRlIHZlbnRhcyBkZSBDYXJsc29uIChTZXAtRGljIEHDsW8gNSk6ICQiLAogICAgcm91bmQocGVyZGlkYV90b3RhbF9jYXJsc29uLDIpLCAibWlsbG9uZXNcbiIpCmBgYAoKYGBge3J9CiMgNC4gQ29tcGFyYWNpw7NuIGRlIHZlbnRhcyByZWFsZXMgZGVsIGNvbmRhZG8gdnMuIGVzdGltYWRhcyAKcmVzdW1lbl9jb25kYWRvIDwtIGRhdGEuZnJhbWUoCiAgTWVzID0gYygiU2VwdGllbWJyZSIsIk9jdHVicmUiLCJOb3ZpZW1icmUiLCJEaWNpZW1icmUiKSwKICBWZW50YXNfRXN0aW1hZGFzID0gcm91bmQoYXMubnVtZXJpYyhwcm9ub3N0aWNvX2NvbmRhZG9fY2llcnJlKSwgMiksCiAgVmVudGFzX1JlYWxlcyA9IGNvbmRhZG9fcmVhbF9jaWVycmUKKQpyZXN1bWVuX2NvbmRhZG8kRXhjZXNvIDwtIHJlc3VtZW5fY29uZGFkbyRWZW50YXNfUmVhbGVzIC0gcmVzdW1lbl9jb25kYWRvJFZlbnRhc19Fc3RpbWFkYXMKcmVzdW1lbl9jb25kYWRvCgpleGNlc29fdG90YWxfY29uZGFkbyA8LSBzdW0ocmVzdW1lbl9jb25kYWRvJEV4Y2VzbykKY2F0KCJFeGNlc28gdG90YWwgZGUgdmVudGFzIHJlYWxlcyBkZWwgY29uZGFkbyB2cy4gbG8gZXN0aW1hZG8gKFNlcC1EaWMgQcOxbyA1KTogJCIsCiAgICByb3VuZChleGNlc29fdG90YWxfY29uZGFkbywyKSwgIm1pbGxvbmVzXG4iKQpgYGAKCioqQ29uY2x1c2lvbmVzIEVqZXJjaWNpbyA0OioqCgoxLiBTZSBlc3RpbWEgcXVlLCBkZSBubyBoYWJlciBvY3VycmlkbyBlbCBodXJhY8OhbiwgQ2FybHNvbiBoYWJyw61hIHZlbmRpZG8KICAgYXByb3hpbWFkYW1lbnRlIGByIHJvdW5kKHBlcmRpZGFfdG90YWxfY2FybHNvbiwyKWAgbWlsbG9uZXMgZGUgZMOzbGFyZXMKICAgZW50cmUgc2VwdGllbWJyZSB5IGRpY2llbWJyZSBkZWwgYcOxbyA1OyBjb21vIGxhIHRpZW5kYSBwZXJtYW5lY2nDsyBjZXJyYWRhCiAgICh2ZW50YXMgcmVhbGVzID0gMCksIGVzYSBjaWZyYSByZXByZXNlbnRhIGxhIHDDqXJkaWRhIGRlIHZlbnRhcyBhdHJpYnVpYmxlCiAgIGFsIGh1cmFjw6FuLgoyLiBMYXMgdmVudGFzIHJlYWxlcyBkZWwgY29uZGFkbyBlbiBlc29zIG1pc21vcyA0IG1lc2VzIHN1cGVyYXJvbiBlbgogICBgciByb3VuZChleGNlc29fdG90YWxfY29uZGFkbywyKWAgbWlsbG9uZXMgZGUgZMOzbGFyZXMgbG8gcXVlIGVsIG1vZGVsbwogICBlc3RpbWFiYSBxdWUgaGFicsOtYW4gc2lkbyBzaW4gZWwgaHVyYWPDoW4uCjMuIEVzZSBleGNlc28gZGUgdmVudGFzIGVuIGVsIGNvbmRhZG8gKHByb2JhYmxlbWVudGUgaW1wdWxzYWRvIHBvciBsb3MgbcOhcyBkZQogICAkOCwwMDAgbWlsbG9uZXMgZW4gYXl1ZGEgZmVkZXJhbCB5IHBhZ29zIGRlIHNlZ3Vyb3MgcXVlIHNlIGlueWVjdGFyb24gYSBsYQogICB6b25hKSBlcyBldmlkZW5jaWEgYSBmYXZvciBkZWwgYXJndW1lbnRvIGRlIENhcmxzb24gZGUgcXVlIGh1Ym8gdW4KICAgaW5jcmVtZW50byBlbiBsYSBhY3RpdmlkYWQgY29tZXJjaWFsIGRlIGxhIHpvbmEgdHJhcyBlbCBodXJhY8OhbiDigJQgbG8gY3VhbAogICByZXNwYWxkYSBxdWUsIGRlIGhhYmVyIHBlcm1hbmVjaWRvIGFiaWVydGEsIGxhIHRpZW5kYSBtdXkgcHJvYmFibGVtZW50ZQogICB0YW1iacOpbiBzZSBoYWJyw61hIGJlbmVmaWNpYWRvIGRlIGVzZSByZXB1bnRlIHkgbm8gc29sbyBoYWJyw61hIHBlcmRpZG8gc3VzCiAgIHZlbnRhcyDigJxub3JtYWxlc+KAnSwgc2lubyB0YW1iacOpbiB1bmEgcGFydGUgZGUgZXNlIGV4Y2VzbyBkZSBkZW1hbmRhLgo=