Ejemplo en clase: Población (17/02/2025)

1. Instalar paquetes y llamar librerias
library(forecast)
library(tidyverse)
library(ggplot2)
library(readxl)
2. Importar la base de datos
poblacion <- read.csv("/Users/hectordelagarzatrevino/Library/CloudStorage/GoogleDrive-a01177960@tec.mx/My Drive/LIT/8. Octavo semestre/Generación de escenarios futuros con analítica/Modulo 1/Actividades/Actividad 2/population.csv")
3. Entendiendo la base de datos
summary(poblacion)
## state year population
## Length:6020 Min. :1900 Min. : 43000
## Class :character 1st Qu.:1930 1st Qu.: 901483
## Mode :character Median :1960 Median : 2359000
## Mean :1960 Mean : 3726003
## 3rd Qu.:1990 3rd Qu.: 4541883
## Max. :2019 Max. :39512223
str(poblacion)
## 'data.frame': 6020 obs. of 3 variables:
## $ state : chr "AK" "AK" "AK" "AK" ...
## $ year : int 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 ...
## $ population: int 135000 158000 189000 205000 215000 222000 224000 231000 224000 224000 ...
head(poblacion)
## state year population
## 1 AK 1950 135000
## 2 AK 1951 158000
## 3 AK 1952 189000
## 4 AK 1953 205000
## 5 AK 1954 215000
## 6 AK 1955 222000
4. Serie de tiempo en Texas
poblacion_texas <- poblacion %>% filter(state=="TX")
ggplot(poblacion_texas, aes(x= year, y= population)) +
geom_line() +
labs(title = "Poblacion de Texas", x = "Año",
y = "Poblacion")

ts_texas <- ts(poblacion_texas$population, start = 1900, frequency = 1) # Serie de tiempo anual
# ts_texas <- ts(poblacion_texas$population, start = c(1900,4), frequency = 4) Serie de tiempo trimestral
# ts_texas <- ts(poblacion_texas$population, start = c(1900,8), frequency = 12) Serie de tiempo mensual
arima_texas <- auto.arima(ts_texas)
summary(arima_texas)
## Series: ts_texas
## ARIMA(0,2,2)
##
## Coefficients:
## ma1 ma2
## -0.5950 -0.1798
## s.e. 0.0913 0.0951
##
## sigma^2 = 1.031e+10: log likelihood = -1527.14
## AIC=3060.28 AICc=3060.5 BIC=3068.6
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set 12147.62 99818.31 59257.39 0.1046163 0.5686743 0.2672197
## ACF1
## Training set -0.02136734
pronostico_texas <- forecast(arima_texas, level = 95, h = 10) # h es el numero de predicciones
plot(pronostico_texas, main = "Pronostico de población de Texas")

Ejercicio en clase (17/02/2025): Mapa
1.1 Instalar paquetes y llamar librerias
library(forecast)
library(tidyverse)
library(ggplot2)
library(maps)
library(palette)
library(leaflet)
2.1Entendiendo la base de datos
summary(poblacion)
## state year population
## Length:6020 Min. :1900 Min. : 43000
## Class :character 1st Qu.:1930 1st Qu.: 901483
## Mode :character Median :1960 Median : 2359000
## Mean :1960 Mean : 3726003
## 3rd Qu.:1990 3rd Qu.: 4541883
## Max. :2019 Max. :39512223
str(poblacion)
## 'data.frame': 6020 obs. of 3 variables:
## $ state : chr "AK" "AK" "AK" "AK" ...
## $ year : int 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 ...
## $ population: int 135000 158000 189000 205000 215000 222000 224000 231000 224000 224000 ...
head(poblacion)
## state year population
## 1 AK 1950 135000
## 2 AK 1951 158000
## 3 AK 1952 189000
## 4 AK 1953 205000
## 5 AK 1954 215000
## 6 AK 1955 222000
3.1 Serie de tiempo en Texas
poblacion_texas <- poblacion %>% filter(state=="TX")
ggplot(poblacion_texas, aes(x= year, y= population)) +
geom_line() +
labs(title = "Poblacion de Texas", x = "Año",
y = "Poblacion")

ts_texas <- ts(poblacion_texas$population, start = 1900, frequency = 1) # Serie de tiempo anual
# ts_texas <- ts(poblacion_texas$population, start = c(1900,4), frequency = 4) Serie de tiempo trimestral
# ts_texas <- ts(poblacion_texas$population, start = c(1900,8), frequency = 12) Serie de tiempo mensual
arima_texas <- auto.arima(ts_texas)
summary(arima_texas)
## Series: ts_texas
## ARIMA(0,2,2)
##
## Coefficients:
## ma1 ma2
## -0.5950 -0.1798
## s.e. 0.0913 0.0951
##
## sigma^2 = 1.031e+10: log likelihood = -1527.14
## AIC=3060.28 AICc=3060.5 BIC=3068.6
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set 12147.62 99818.31 59257.39 0.1046163 0.5686743 0.2672197
## ACF1
## Training set -0.02136734
pronostico_texas <- forecast(arima_texas, level = 95, h = 10) # h es el numero de predicciones
plot(pronostico_texas, main = "Pronostico de población de Texas")

4.1 Crear un mapa
# Crear un mapa de EUA por decada, con un gradiente verde-rojo de la poblacion por estado, desde 1900 hasta 2050
map(database = "state")
map(database = "state", regions = "Texas", col = "red", fill = TRUE, add = TRUE)
map(database = "state", regions = "New York", col = "blue", fill = TRUE, add = TRUE)

5.1 Actividad de Mapa
# Generar pronósticos con ARIMA para cada estado
proyecciones <- poblacion %>%
group_by(state) %>%
summarise(
modelo = list(auto.arima(ts(population, start = 1950, frequency = 1))), # Modelo ARIMA
.groups = "drop"
) %>%
rowwise() %>%
mutate(
pronostico = list(forecast(modelo, h = 31)), # Pronóstico de 5 años
poblacion5 = tail(pronostico$mean, 1) # Obtener la población del último año pronosticado
) %>%
select(state, poblacion5)
# Unir proyecciones con el mapa
states <- map("state", plot = FALSE, fill = TRUE)
map_data <- merge(data.frame(state = tolower(state.name)), proyecciones, by = "state", all.x = TRUE)
# Asignar colores según la población (gradiente verde-rojo)
color_pal <- colorNumeric(palette = "RdYlGn", domain = proyecciones$poblacion5)
# Crear mapa interactivo con Leaflet
leaflet(data = states) %>%
addTiles() %>%
addPolygons(
fillColor = ~color_pal(proyecciones$poblacion5),
fillOpacity = 0.7,
color = "black",
weight = 1,
popup = ~paste("Estado:", proyecciones$state, "<br>",
"Población en 5 años:", format(proyecciones$poblacion5, big.mark = ","))
) %>%
addLegend(
"bottomright",
pal = color_pal,
values = proyecciones$poblacion5,
title = "Población pronosticada en 5 Años",
opacity = 1
)
Actividad 2. Leche
saborizada Hershey´s

1.2 Instalar paquetes y
llamar librerias
library(forecast)
library(tidyverse)
library(ggplot2)
library(readxl)
2.2 Importar la base de
datos
ventas <- read_excel("/Users/hectordelagarzatrevino/Library/CloudStorage/GoogleDrive-a01177960@tec.mx/My Drive/LIT/8. Octavo semestre/Generación de escenarios futuros con analítica/Modulo 1/Actividades/Actividad 2/Ventas_Históricas_lechitas.xlsx")
3.2 Modelo
AUTO.ARIMA
ts_ventas <- ts(ventas$Ventas, start = c(2017,1), frequency = 12)
autoplot(ts_ventas) + labs(title = "Ventas de leche saborizada Hersheys", x = "Tiempo", y = "Miles de dolares")

arima_ventas <- auto.arima(ts_ventas)
summary(arima_ventas)
## Series: ts_ventas
## 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
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 25.22158 343.864 227.17 0.08059932 0.7069542 0.06491044 0.2081026
pronostico_ventas <- forecast(arima_ventas, level = 95, h = 12)
autoplot(pronostico_ventas, main = "Pronostico de ventas de leche saborizada Hersheys")

4.2 Modelo Regresion
Lineal
ventas$mes <- 1:36
regresion_ventas <- lm(Ventas ~ mes, data = ventas)
summary(regresion_ventas)
##
## Call:
## lm(formula = Ventas ~ mes, data = ventas)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2075.79 -326.41 33.74 458.40 1537.04
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 24894.67 275.03 90.52 <2e-16 ***
## mes 298.37 12.96 23.02 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 808 on 34 degrees of freedom
## Multiple R-squared: 0.9397, Adjusted R-squared: 0.9379
## F-statistic: 529.8 on 1 and 34 DF, p-value: < 2.2e-16
siguiente_anio <- data.frame(mes=37:48)
prediccion_regresion <- predict(regresion_ventas, siguiente_anio)
prediccion_regresion
## 1 2 3 4 5 6 7 8
## 35934.49 36232.86 36531.23 36829.61 37127.98 37426.35 37724.73 38023.10
## 9 10 11 12
## 38321.47 38619.85 38918.22 39216.59
plot(ventas$mes, ventas$Ventas, main = "Pronostico de ventas de Hersheys", xlab = "Tiempo", ylab = "Miles de dolares")
abline(regresion_ventas, col = "blue")
points(siguiente_anio$mes, prediccion_regresion, col = "red")

predicciones_reales <- predict(regresion_ventas, ventas)
MAPE <- mean(abs((ventas$Ventas - predicciones_reales)/ventas$Ventas))*100
MAPE
## [1] 2.011297
5.2
Conclusiones
El mejor modelo que se adapta a la serie es el
SARIMA con un Mape de 0.71%, comparado con la Regresion
Lineal que su MAPE es de 2.01%
Para el siguiente año, la proyección de ventas es la siguiente:
| Jan 2020 |
35498.90 |
34616.48 |
36381.32 |
| Feb 2020 |
34202.17 |
33155.28 |
35249.05 |
| Mar 2020 |
36703.01 |
35596.10 |
37809.92 |
| Apr 2020 |
36271.90 |
35141.44 |
37402.36 |
| May 2020 |
37121.98 |
35982.07 |
38261.90 |
| Jun 2020 |
37102.65 |
35958.90 |
38246.40 |
| Jul 2020 |
37151.04 |
36005.73 |
38296.34 |
| Aug 2020 |
38564.64 |
37418.70 |
39710.58 |
| Sep 2020 |
38755.22 |
37609.03 |
39901.42 |
| Oct 2020 |
39779.02 |
38632.72 |
40925.32 |
| Nov 2020 |
38741.63 |
37595.28 |
39887.97 |
| Dec 2020 |
38645.86 |
37499.50 |
39792.22 |
ventasporanio <- read_excel("/Users/hectordelagarzatrevino/Library/CloudStorage/GoogleDrive-a01177960@tec.mx/My Drive/LIT/8. Octavo semestre/Generación de escenarios futuros con analítica/Modulo 1/Actividades/Actividad 2/Ventas2.xlsx")
ggplot(ventasporanio, aes(x = Mes,y= Ventas, col=as.factor(Anio), group=Anio))+
geom_line() + labs(title = "Ventas de Leche Saborizada Hershey's por Año", x="Mes", y= "Miles de Dólares")

Nuestra recomendación sería realizar campañas publicitarias para
aumentar el consumo de leche saborizada Hershey’s en el primer semestre
del año.
LS0tCnRpdGxlOiAiQWN0aXZpZGFkIDI6IEdlbmVyYWNpw7NuIGRlIGVzY2VuYXJpb3MgZnV0dXJvcyBjb24gbW9kZWxvcyBkZSBwcm9uw7NzdGljb3MgZW4gc2VyaWVzIGRlIHRpZW1wby4iCmF1dGhvcjogIkjDqWN0b3IgR3VhZGFsdXBlIGRlIGxhIEdhcnphIFRyZXZpw7FvIC0gQTAxMTc3OTYwIgpkYXRlOiAiMjAyNS0wMi0xNyIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKICAgIHRoZW1lOiBjZXJ1bGVhbgotLS0KCiMgKipFamVtcGxvIGVuIGNsYXNlOiBQb2JsYWNpw7NuICgxNy8wMi8yMDI1KSoqCgohW10oL1VzZXJzL2hlY3RvcmRlbGFnYXJ6YXRyZXZpbm8vTGlicmFyeS9DbG91ZFN0b3JhZ2UvR29vZ2xlRHJpdmUtYTAxMTc3OTYwQHRlYy5teC9NeSBEcml2ZS9MSVQvOC4gT2N0YXZvIHNlbWVzdHJlL0dlbmVyYWNpb8yBbiBkZSBlc2NlbmFyaW9zIGZ1dHVyb3MgY29uIGFuYWxpzIF0aWNhL01vZHVsbyAxL0FjdGl2aWRhZGVzL0FjdGl2aWRhZCAyL3BvYmxhY2lvbi5qcGcpCgojIyAqKjEuIEluc3RhbGFyIHBhcXVldGVzIHkgbGxhbWFyIGxpYnJlcmlhcyoqCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocmVhZHhsKQpgYGAKCiMjICoqMi4gSW1wb3J0YXIgbGEgYmFzZSBkZSBkYXRvcyoqCmBgYHtyfQpwb2JsYWNpb24gPC0gcmVhZC5jc3YoIi9Vc2Vycy9oZWN0b3JkZWxhZ2FyemF0cmV2aW5vL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0dvb2dsZURyaXZlLWEwMTE3Nzk2MEB0ZWMubXgvTXkgRHJpdmUvTElULzguIE9jdGF2byBzZW1lc3RyZS9HZW5lcmFjaW/MgW4gZGUgZXNjZW5hcmlvcyBmdXR1cm9zIGNvbiBhbmFsacyBdGljYS9Nb2R1bG8gMS9BY3RpdmlkYWRlcy9BY3RpdmlkYWQgMi9wb3B1bGF0aW9uLmNzdiIpCmBgYAoKIyMgKiozLiBFbnRlbmRpZW5kbyBsYSBiYXNlIGRlIGRhdG9zKioKYGBge3J9CnN1bW1hcnkocG9ibGFjaW9uKQpzdHIocG9ibGFjaW9uKQpoZWFkKHBvYmxhY2lvbikKYGBgCgojIyAqKjQuIFNlcmllIGRlIHRpZW1wbyBlbiBUZXhhcyoqCmBgYHtyfQpwb2JsYWNpb25fdGV4YXMgPC0gcG9ibGFjaW9uICU+JSBmaWx0ZXIoc3RhdGU9PSJUWCIpCmdncGxvdChwb2JsYWNpb25fdGV4YXMsIGFlcyh4PSB5ZWFyLCB5PSBwb3B1bGF0aW9uKSkgKyAKICBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJQb2JsYWNpb24gZGUgVGV4YXMiLCB4ID0gIkHDsW8iLAogICAgICAgeSA9ICJQb2JsYWNpb24iKQp0c190ZXhhcyA8LSB0cyhwb2JsYWNpb25fdGV4YXMkcG9wdWxhdGlvbiwgc3RhcnQgPSAxOTAwLCBmcmVxdWVuY3kgPSAxKSAjIFNlcmllIGRlIHRpZW1wbyBhbnVhbAojIHRzX3RleGFzIDwtIHRzKHBvYmxhY2lvbl90ZXhhcyRwb3B1bGF0aW9uLCBzdGFydCA9IGMoMTkwMCw0KSwgZnJlcXVlbmN5ID0gNCkgU2VyaWUgZGUgdGllbXBvIHRyaW1lc3RyYWwKIyB0c190ZXhhcyA8LSB0cyhwb2JsYWNpb25fdGV4YXMkcG9wdWxhdGlvbiwgc3RhcnQgPSBjKDE5MDAsOCksIGZyZXF1ZW5jeSA9IDEyKSBTZXJpZSBkZSB0aWVtcG8gbWVuc3VhbAphcmltYV90ZXhhcyA8LSBhdXRvLmFyaW1hKHRzX3RleGFzKQpzdW1tYXJ5KGFyaW1hX3RleGFzKQpwcm9ub3N0aWNvX3RleGFzIDwtIGZvcmVjYXN0KGFyaW1hX3RleGFzLCBsZXZlbCA9IDk1LCBoID0gMTApICMgaCBlcyBlbCBudW1lcm8gZGUgcHJlZGljY2lvbmVzCnBsb3QocHJvbm9zdGljb190ZXhhcywgbWFpbiA9ICJQcm9ub3N0aWNvIGRlIHBvYmxhY2nDs24gZGUgVGV4YXMiKQpgYGAKCiMgKipFamVyY2ljaW8gZW4gY2xhc2UgKDE3LzAyLzIwMjUpOiBNYXBhKioKCiMjICoqMS4xIEluc3RhbGFyIHBhcXVldGVzIHkgbGxhbWFyIGxpYnJlcmlhcyoqCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkobWFwcykKbGlicmFyeShwYWxldHRlKQpsaWJyYXJ5KGxlYWZsZXQpCmBgYAoKIyMgKioyLjFFbnRlbmRpZW5kbyBsYSBiYXNlIGRlIGRhdG9zKioKYGBge3J9CnN1bW1hcnkocG9ibGFjaW9uKQpzdHIocG9ibGFjaW9uKQpoZWFkKHBvYmxhY2lvbikKYGBgCgojIyAqKjMuMSBTZXJpZSBkZSB0aWVtcG8gZW4gVGV4YXMqKgpgYGB7cn0KcG9ibGFjaW9uX3RleGFzIDwtIHBvYmxhY2lvbiAlPiUgZmlsdGVyKHN0YXRlPT0iVFgiKQpnZ3Bsb3QocG9ibGFjaW9uX3RleGFzLCBhZXMoeD0geWVhciwgeT0gcG9wdWxhdGlvbikpICsgCiAgZ2VvbV9saW5lKCkgKwogIGxhYnModGl0bGUgPSAiUG9ibGFjaW9uIGRlIFRleGFzIiwgeCA9ICJBw7FvIiwKICAgICAgIHkgPSAiUG9ibGFjaW9uIikKdHNfdGV4YXMgPC0gdHMocG9ibGFjaW9uX3RleGFzJHBvcHVsYXRpb24sIHN0YXJ0ID0gMTkwMCwgZnJlcXVlbmN5ID0gMSkgIyBTZXJpZSBkZSB0aWVtcG8gYW51YWwKIyB0c190ZXhhcyA8LSB0cyhwb2JsYWNpb25fdGV4YXMkcG9wdWxhdGlvbiwgc3RhcnQgPSBjKDE5MDAsNCksIGZyZXF1ZW5jeSA9IDQpIFNlcmllIGRlIHRpZW1wbyB0cmltZXN0cmFsCiMgdHNfdGV4YXMgPC0gdHMocG9ibGFjaW9uX3RleGFzJHBvcHVsYXRpb24sIHN0YXJ0ID0gYygxOTAwLDgpLCBmcmVxdWVuY3kgPSAxMikgU2VyaWUgZGUgdGllbXBvIG1lbnN1YWwKYXJpbWFfdGV4YXMgPC0gYXV0by5hcmltYSh0c190ZXhhcykKc3VtbWFyeShhcmltYV90ZXhhcykKcHJvbm9zdGljb190ZXhhcyA8LSBmb3JlY2FzdChhcmltYV90ZXhhcywgbGV2ZWwgPSA5NSwgaCA9IDEwKSAjIGggZXMgZWwgbnVtZXJvIGRlIHByZWRpY2Npb25lcwpwbG90KHByb25vc3RpY29fdGV4YXMsIG1haW4gPSAiUHJvbm9zdGljbyBkZSBwb2JsYWNpw7NuIGRlIFRleGFzIikKYGBgCgojIyAqKjQuMSBDcmVhciB1biBtYXBhKioKYGBge3J9CiMgQ3JlYXIgdW4gbWFwYSBkZSBFVUEgcG9yIGRlY2FkYSwgY29uIHVuIGdyYWRpZW50ZSB2ZXJkZS1yb2pvIGRlIGxhIHBvYmxhY2lvbiBwb3IgZXN0YWRvLCBkZXNkZSAxOTAwIGhhc3RhIDIwNTAKbWFwKGRhdGFiYXNlID0gInN0YXRlIikKbWFwKGRhdGFiYXNlID0gInN0YXRlIiwgcmVnaW9ucyA9ICJUZXhhcyIsIGNvbCA9ICJyZWQiLCBmaWxsID0gVFJVRSwgYWRkID0gVFJVRSkKbWFwKGRhdGFiYXNlID0gInN0YXRlIiwgcmVnaW9ucyA9ICJOZXcgWW9yayIsIGNvbCA9ICJibHVlIiwgZmlsbCA9IFRSVUUsIGFkZCA9IFRSVUUpCmBgYAoKIyMgKio1LjEgQWN0aXZpZGFkIGRlIE1hcGEqKgoKYGBge3J9CiMgR2VuZXJhciBwcm9uw7NzdGljb3MgY29uIEFSSU1BIHBhcmEgY2FkYSBlc3RhZG8KcHJveWVjY2lvbmVzIDwtIHBvYmxhY2lvbiAlPiUKICBncm91cF9ieShzdGF0ZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgbW9kZWxvID0gbGlzdChhdXRvLmFyaW1hKHRzKHBvcHVsYXRpb24sIHN0YXJ0ID0gMTk1MCwgZnJlcXVlbmN5ID0gMSkpKSwgICMgTW9kZWxvIEFSSU1BCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKSAlPiUKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKAogICAgcHJvbm9zdGljbyA9IGxpc3QoZm9yZWNhc3QobW9kZWxvLCBoID0gMzEpKSwgICMgUHJvbsOzc3RpY28gZGUgNSBhw7FvcwogICAgcG9ibGFjaW9uNSA9IHRhaWwocHJvbm9zdGljbyRtZWFuLCAxKSAgIyBPYnRlbmVyIGxhIHBvYmxhY2nDs24gZGVsIMO6bHRpbW8gYcOxbyBwcm9ub3N0aWNhZG8KICApICU+JQogIHNlbGVjdChzdGF0ZSwgcG9ibGFjaW9uNSkKYGBgCgpgYGB7cn0KIyBVbmlyIHByb3llY2Npb25lcyBjb24gZWwgbWFwYQpzdGF0ZXMgPC0gbWFwKCJzdGF0ZSIsIHBsb3QgPSBGQUxTRSwgZmlsbCA9IFRSVUUpCm1hcF9kYXRhIDwtIG1lcmdlKGRhdGEuZnJhbWUoc3RhdGUgPSB0b2xvd2VyKHN0YXRlLm5hbWUpKSwgcHJveWVjY2lvbmVzLCBieSA9ICJzdGF0ZSIsIGFsbC54ID0gVFJVRSkKCgojIEFzaWduYXIgY29sb3JlcyBzZWfDum4gbGEgcG9ibGFjacOzbiAoZ3JhZGllbnRlIHZlcmRlLXJvam8pCmNvbG9yX3BhbCA8LSBjb2xvck51bWVyaWMocGFsZXR0ZSA9ICJSZFlsR24iLCBkb21haW4gPSBwcm95ZWNjaW9uZXMkcG9ibGFjaW9uNSkKCiMgQ3JlYXIgbWFwYSBpbnRlcmFjdGl2byBjb24gTGVhZmxldApsZWFmbGV0KGRhdGEgPSBzdGF0ZXMpICU+JQogIGFkZFRpbGVzKCkgJT4lCiAgYWRkUG9seWdvbnMoCiAgICBmaWxsQ29sb3IgPSB+Y29sb3JfcGFsKHByb3llY2Npb25lcyRwb2JsYWNpb241KSwKICAgIGZpbGxPcGFjaXR5ID0gMC43LAogICAgY29sb3IgPSAiYmxhY2siLAogICAgd2VpZ2h0ID0gMSwKICAgIHBvcHVwID0gfnBhc3RlKCJFc3RhZG86IiwgcHJveWVjY2lvbmVzJHN0YXRlLCAiPGJyPiIsCiAgICAgICAgICAgICAgICAgICAiUG9ibGFjacOzbiBlbiA1IGHDsW9zOiIsIGZvcm1hdChwcm95ZWNjaW9uZXMkcG9ibGFjaW9uNSwgYmlnLm1hcmsgPSAiLCIpKQogICkgJT4lCiAgYWRkTGVnZW5kKAogICAgImJvdHRvbXJpZ2h0IiwKICAgIHBhbCA9IGNvbG9yX3BhbCwKICAgIHZhbHVlcyA9IHByb3llY2Npb25lcyRwb2JsYWNpb241LAogICAgdGl0bGUgPSAiUG9ibGFjacOzbiBwcm9ub3N0aWNhZGEgZW4gNSBBw7FvcyIsCiAgICBvcGFjaXR5ID0gMQogICkKYGBgCgoKIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogIzgwNDAwMDsiPioqQWN0aXZpZGFkIDIuIExlY2hlIHNhYm9yaXphZGEgSGVyc2hlecK0cyoqPC9hcGFuPgoKIVtdKC9Vc2Vycy9oZWN0b3JkZWxhZ2FyemF0cmV2aW5vL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0dvb2dsZURyaXZlLWEwMTE3Nzk2MEB0ZWMubXgvTXkgRHJpdmUvTElULzguIE9jdGF2byBzZW1lc3RyZS9HZW5lcmFjaW/MgW4gZGUgZXNjZW5hcmlvcyBmdXR1cm9zIGNvbiBhbmFsacyBdGljYS9Nb2R1bG8gMS9BY3RpdmlkYWRlcy9BY3RpdmlkYWQgMi9oZXJzaGV5LnBuZykKCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjODA0MDAwOyI+KioxLjIgSW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyaWFzKio8L2FwYW4+CmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocmVhZHhsKQpgYGAKCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjODA0MDAwOyI+KioyLjIgSW1wb3J0YXIgbGEgYmFzZSBkZSBkYXRvcyoqPC9hcGFuPgpgYGB7cn0KdmVudGFzIDwtIHJlYWRfZXhjZWwoIi9Vc2Vycy9oZWN0b3JkZWxhZ2FyemF0cmV2aW5vL0xpYnJhcnkvQ2xvdWRTdG9yYWdlL0dvb2dsZURyaXZlLWEwMTE3Nzk2MEB0ZWMubXgvTXkgRHJpdmUvTElULzguIE9jdGF2byBzZW1lc3RyZS9HZW5lcmFjaW/MgW4gZGUgZXNjZW5hcmlvcyBmdXR1cm9zIGNvbiBhbmFsacyBdGljYS9Nb2R1bG8gMS9BY3RpdmlkYWRlcy9BY3RpdmlkYWQgMi9WZW50YXNfSGlzdMOzcmljYXNfbGVjaGl0YXMueGxzeCIpCmBgYAoKIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM4MDQwMDA7Ij4qKjMuMiBNb2RlbG8gQVVUTy5BUklNQSoqPC9hcGFuPgpgYGB7cn0KdHNfdmVudGFzIDwtIHRzKHZlbnRhcyRWZW50YXMsIHN0YXJ0ID0gYygyMDE3LDEpLCBmcmVxdWVuY3kgPSAxMikKYXV0b3Bsb3QodHNfdmVudGFzKSArIGxhYnModGl0bGUgPSAiVmVudGFzIGRlIGxlY2hlIHNhYm9yaXphZGEgSGVyc2hleXMiLCB4ID0gIlRpZW1wbyIsIHkgPSAiTWlsZXMgZGUgZG9sYXJlcyIpCmFyaW1hX3ZlbnRhcyA8LSBhdXRvLmFyaW1hKHRzX3ZlbnRhcykKc3VtbWFyeShhcmltYV92ZW50YXMpCnByb25vc3RpY29fdmVudGFzIDwtIGZvcmVjYXN0KGFyaW1hX3ZlbnRhcywgbGV2ZWwgPSA5NSwgaCA9IDEyKSAKYXV0b3Bsb3QocHJvbm9zdGljb192ZW50YXMsIG1haW4gPSAiUHJvbm9zdGljbyBkZSB2ZW50YXMgZGUgbGVjaGUgc2Fib3JpemFkYSBIZXJzaGV5cyIpCmBgYAoKIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6ICM4MDQwMDA7Ij4qKjQuMiBNb2RlbG8gUmVncmVzaW9uIExpbmVhbCoqPC9hcGFuPgpgYGB7cn0KdmVudGFzJG1lcyA8LSAxOjM2CnJlZ3Jlc2lvbl92ZW50YXMgPC0gbG0oVmVudGFzIH4gbWVzLCBkYXRhID0gdmVudGFzKQpzdW1tYXJ5KHJlZ3Jlc2lvbl92ZW50YXMpCnNpZ3VpZW50ZV9hbmlvIDwtIGRhdGEuZnJhbWUobWVzPTM3OjQ4KQpwcmVkaWNjaW9uX3JlZ3Jlc2lvbiA8LSBwcmVkaWN0KHJlZ3Jlc2lvbl92ZW50YXMsIHNpZ3VpZW50ZV9hbmlvKQpwcmVkaWNjaW9uX3JlZ3Jlc2lvbgpwbG90KHZlbnRhcyRtZXMsIHZlbnRhcyRWZW50YXMsIG1haW4gPSAiUHJvbm9zdGljbyBkZSB2ZW50YXMgZGUgSGVyc2hleXMiLCB4bGFiID0gIlRpZW1wbyIsIHlsYWIgPSAiTWlsZXMgZGUgZG9sYXJlcyIpCmFibGluZShyZWdyZXNpb25fdmVudGFzLCBjb2wgPSAiYmx1ZSIpCnBvaW50cyhzaWd1aWVudGVfYW5pbyRtZXMsIHByZWRpY2Npb25fcmVncmVzaW9uLCBjb2wgPSAicmVkIikKcHJlZGljY2lvbmVzX3JlYWxlcyA8LSBwcmVkaWN0KHJlZ3Jlc2lvbl92ZW50YXMsIHZlbnRhcykKTUFQRSA8LSBtZWFuKGFicygodmVudGFzJFZlbnRhcyAtIHByZWRpY2Npb25lc19yZWFsZXMpL3ZlbnRhcyRWZW50YXMpKSoxMDAKTUFQRQpgYGAKCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiAjODA0MDAwOyI+Kio1LjIgQ29uY2x1c2lvbmVzKio8L2FwYW4+CkVsIG1lam9yIG1vZGVsbyBxdWUgc2UgYWRhcHRhIGEgbGEgc2VyaWUgZXMgZWwgKipTQVJJTUEqKiBjb24gdW4gTWFwZSBkZSAwLjcxJSwgY29tcGFyYWRvIGNvbiBsYSBSZWdyZXNpb24gTGluZWFsIHF1ZSBzdSBNQVBFIGVzIGRlIDIuMDElCgoKUGFyYSBlbCBzaWd1aWVudGUgYcOxbywgbGEgcHJveWVjY2nDs24gZGUgdmVudGFzIGVzIGxhIHNpZ3VpZW50ZToKCnwgTWVzIHkgQcOxbyB8IEVzY2VuYXJpbyBPcHRpbWlzdGEgfCBFc2NlbmFyaW8gRXNwZXJhZG8gfCBFc2NlbmFyaW8gUGVzaW1pc3RhIHwKfC0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS18CnxKYW4gMjAyMAkgIHwgICAgICAgMzU0OTguOTAgICAgICB8CSAgICAgIDM0NjE2LjQ4ICAgICB8CSAgICAzNjM4MS4zMgkgICAgIHwKfEZlYiAyMDIwCSAgfCAgICAgICAzNDIwMi4xNyAgICAgIHwgCSAgICAzMzE1NS4yOCAgICAgfAkgICAgMzUyNDkuMDUgICAgICAgfAp8TWFyIDIwMjAJICB8ICAgICAgIDM2NzAzLjAxICAgICAgfCAgICAgCTM1NTk2LjEwICAgICB8CSAgICAzNzgwOS45MiAgICAJIHwKfEFwciAyMDIwCSAgfCAgICAgICAzNjI3MS45MCAgICAgIHwgICAgIAkzNTE0MS40NCAgICAgfAkgICAgMzc0MDIuMzYgICAgCSB8CnxNYXkgMjAyMAkgIHwgICAgICAgMzcxMjEuOTggICAgICB8ICAgICAgCTM1OTgyLjA3ICAgICB8CSAgICAzODI2MS45MCAgICAJIHwKfEp1biAyMDIwCSAgfCAgICAgICAzNzEwMi42NSAgICAgIHwgICAgIAkzNTk1OC45MCAgICAgfAkgICAgMzgyNDYuNDAgICAgCSB8CnxKdWwgMjAyMAkgIHwgICAgICAgMzcxNTEuMDQgICAgICB8ICAgICAJMzYwMDUuNzMgICAgIHwJICAgIDM4Mjk2LjM0CSAgICAgfAp8QXVnIDIwMjAJICB8ICAgICAgIDM4NTY0LjY0ICAgICAgfCAgICAgCTM3NDE4LjcwICAgICB8CSAgICAzOTcxMC41OCAgICAJIHwKfFNlcCAyMDIwCSAgfCAgICAgICAzODc1NS4yMiAgICAgIHwgICAgIAkzNzYwOS4wMyAgICAgfAkgICAgMzk5MDEuNDIgICAgCSB8CnxPY3QgMjAyMAkgIHwgICAgICAgMzk3NzkuMDIgICAgICB8ICAgICAJMzg2MzIuNzIgICAgIHwJICAgIDQwOTI1LjMyICAgICAgIHwKfE5vdiAyMDIwICAgfCAgIAkgIDM4NzQxLjYzCSAgICB8ICAgICAgIDM3NTk1LjI4ICAgICB8CSAgICAzOTg4Ny45NyAgICAgICB8CQp8RGVjIDIwMjAgICB8ICAgICAgIDM4NjQ1Ljg2CSAgICB8ICAgICAgIDM3NDk5LjUwICAgICB8CSAgICAzOTc5Mi4yMiAgICAgICB8CgpgYGB7cn0KdmVudGFzcG9yYW5pbyA8LSByZWFkX2V4Y2VsKCIvVXNlcnMvaGVjdG9yZGVsYWdhcnphdHJldmluby9MaWJyYXJ5L0Nsb3VkU3RvcmFnZS9Hb29nbGVEcml2ZS1hMDExNzc5NjBAdGVjLm14L015IERyaXZlL0xJVC84LiBPY3Rhdm8gc2VtZXN0cmUvR2VuZXJhY2lvzIFuIGRlIGVzY2VuYXJpb3MgZnV0dXJvcyBjb24gYW5hbGnMgXRpY2EvTW9kdWxvIDEvQWN0aXZpZGFkZXMvQWN0aXZpZGFkIDIvVmVudGFzMi54bHN4IikKZ2dwbG90KHZlbnRhc3BvcmFuaW8sIGFlcyh4ID0gTWVzLHk9IFZlbnRhcywgY29sPWFzLmZhY3RvcihBbmlvKSwgZ3JvdXA9QW5pbykpKwogIGdlb21fbGluZSgpICsgbGFicyh0aXRsZSA9ICJWZW50YXMgZGUgTGVjaGUgU2Fib3JpemFkYSBIZXJzaGV5J3MgcG9yIEHDsW8iLCB4PSJNZXMiLCB5PSAiTWlsZXMgZGUgRMOzbGFyZXMiKQpgYGAKCgpOdWVzdHJhIHJlY29tZW5kYWNpw7NuIHNlcsOtYSByZWFsaXphciBjYW1wYcOxYXMgcHVibGljaXRhcmlhcyBwYXJhIGF1bWVudGFyIGVsIGNvbnN1bW8gZGUgbGVjaGUgc2Fib3JpemFkYSBIZXJzaGV5J3MgZW4gZWwgcHJpbWVyIHNlbWVzdHJlIGRlbCBhw7FvLg==