EJERCICIO EN CLASE: Población

Instalar paquetes y llamar librerías

#install.packages("forecast")
library(forecast)
#install.packages("tidyverse")
library(tidyverse)
#install.packages("tidyverse")
library(ggplot2)
#install.packages("dplyr")
library(dplyr)

Importar la base de datos

poblacion <- read.csv("C:\\Users\\Cristina\\Desktop\\population.csv")

Entender 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

Serie de Tiempo en Texas

poblacion_texas <- poblacion %>% filter(state =="TX")
ggplot(poblacion_texas, aes(x=year, y=population)) +
  geom_line() +
  labs(title="Población de Texas", x ="Año", y="Población")

ts_texas <- ts(poblacion_texas$population, start = 1950, 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=) #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)
pronostico_texas
##      Point Forecast    Lo 95    Hi 95
## 2070       29398472 29199487 29597457
## 2071       29806827 29463665 30149990
## 2072       30215183 29742956 30687410
## 2073       30623538 30024100 31222977
## 2074       31031894 30303359 31760429
## 2075       31440249 30579246 32301253
## 2076       31848605 30851090 32846119
## 2077       32256960 31118581 33395339
## 2078       32665316 31381587 33949044
## 2079       33073671 31640070 34507272
plot(pronostico_texas, main = "Población en Texas")

Crear un Mapa

## Instalar y cargar las librerías necesarias para análisis y visualización
#install.packages(c("dplyr", "ggplot2", "forecast", "maps"))
library(dplyr)
library(ggplot2)
library(forecast)
library(maps)
## 1) Importar la base de datos de población 

poblacion <- read.csv("C:\\Users\\Cristina\\Desktop\\population.csv")

## 2) Proyectar la población estatal hasta 2050 y combinar con datos originales

# Integración de pronósticos con la base de datos inicial
# Crear un dataset ampliado que parte de la base de datos original
poblacion_extendida <- poblacion

# Extraer la lista de estados únicos presentes en los datos
estados <- unique(poblacion$state)

# Modelar y pronosticar la población de cada estado hasta el año 2050
for(st in estados){
  
  # Filtrar y organizar los datos por año para cada estado
  datos_st <- poblacion %>%
    filter(state == st) %>%
    arrange(year)
  
  # Identificar el último año disponible en la serie histórica
  ultimo_anio <- max(datos_st$year)
  
  # Generar la serie de tiempo anual para la población del estado
  ts_st <- ts(datos_st$population,
              start = min(datos_st$year),
              end   = ultimo_anio,
              frequency = 1)  # Datos anuales
  
  # Ajustar un modelo ARIMA de manera automática para el estado
  modelo_st <- auto.arima(ts_st)
  
  # Calcular el horizonte de pronóstico necesario
  # (se genera forecast solo si faltan años para llegar a 2050)
  h_years <- 2050 - ultimo_anio
  
  if(h_years > 0){
    # Generar el pronóstico para el periodo faltante
    pronostico <- forecast(modelo_st, h = h_years)
    
    # Crear un dataframe con las proyecciones generadas
    anios_pronostico <- (ultimo_anio + 1):2050
    poblacion_pronosticada <- as.numeric(pronostico$mean)
    
    df_forecast <- data.frame(
      state = st,
      year  = anios_pronostico,
      population = poblacion_pronosticada
    )
    
    # Incorporar las proyecciones al dataset extendido
    poblacion_extendida <- rbind(poblacion_extendida, df_forecast)
  }
}

## 3) Definir una función para visualizar el mapa de población por año 

plot_map <- function(year) {
  
  # Filtrar el dataset para el año especificado
  data_year <- poblacion_extendida %>%
    filter(year == !!year)
  
  # Cargar la información geográfica de los estados de EE.UU.
  states_map <- map_data("state")
  
  # Relacionar las abreviaturas estatales con los nombres completos en minúsculas
  # Utilizando los vectores auxiliares state.abb y state.name
  data_year <- data_year %>%
    mutate(region = tolower(state.name[match(state, state.abb)])) %>%
    right_join(states_map, by = "region")
  
  # Generar el mapa temático por población
  ggplot(data_year, aes(x = long, y = lat, group = group, fill = population)) +
    geom_polygon(color = "black") +
    # Aplicar un gradiente de color verde (bajo) a rojo (alto)
    scale_fill_gradient(
      low = "green",   # Representa la menor población
      high = "red",    # Indica la mayor población
      name = "Población"
    ) +
    labs(
      title = paste("Población por Estado en", year)
    ) +
    theme_void() +
    theme(
      legend.position = "right",
      plot.title = element_text(size = 16, face = "bold")
    )
}

## 4) Visualizar la evolución demográfica cada década (1950 - 2050) -----------

for(year in seq(1950, 2050, by = 10)) {
  print(plot_map(year))
}

Actividad 2. Leche saborizada Hershey’s

Intalar paquetes y llamar librerías

#install.packages("forecast")
library(forecast)
#install.packages("tidyverse")
library(tidyverse)
#install.packages("tidyverse")
library(ggplot2)
#install.packages("openxlsx")
library(openxlsx)
## Warning: package 'openxlsx' was built under R version 4.3.3

Importar la base de datos

ventas <- read.csv("C:\\Users\\Cristina\\Desktop\\hersheys.csv")

1. Modelo AUTO-ARIMA

ts_ventas <- ts(ventas$Ventas, start=c(2017,1), frequency=12)

autoplot (ts_ventas) + labs (title= "Ventas de Leche Saborizada Hershey's", x="Tiempo", y ="Miles de Dólares")

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)
pronostico_ventas
##          Point Forecast    Lo 95    Hi 95
## 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
autoplot (pronostico_ventas) + labs (title= "pronóstico de Ventas 2020 de Leche Saborizada Hershey's", x="Tiempo", y = "Miles de Dólares")

Modelo de Regresión 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 
## 36077.7
plot(ventas$mes, ventas$Ventas, main="Pronostico de ventas 2020 de leche saborizada Hershey", 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

Conclusiones

El mejor modelo que se adapta a la serie es el SARIMA con un MAPE de 0.71%, comparada con la regresión Lineal que su MAPE es de 2.01%.

Para el siguiente año, la proyección de ventas es la siguiente: | Mes y año | Esnearios Esperado | Escenario Pesimista | Escenario optimista |

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 |

ventas_por_anio <- read.csv("C:\\Users\\Cristina\\Desktop\\ventas_por_anio.csv")
ggplot(ventas_por_anio, aes(x=mes, y = ventas, col=as.factor(anio), 
group=anio)) + 
  geom_line() + 
  labs(title = "Ventas de Leche Saborizada Hershey por Año",
       x="Mes", y="Miles de dolares")

Nuestra recoemdación seria realizar campañas para aumentar el consumo de leche saborizada Hersheys en el primer semestre del año.

LS0tDQp0aXRsZTogIkFjdGl2aWRhZCAyIg0KYXV0aG9yOiAiQ3Jpc3RpbmEgRmxvcmVzIg0KZGF0ZTogIjIwMjUtMDItMTMiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IFRSVUUgDQogICAgdG9jX2Zsb2F0OiBUUlVFIA0KICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUgDQogICAgdGhlbWU6IGNlcnVsZWFuDQotLS0NCiFbXShDOlxcVXNlcnNcXENyaXN0aW5hXFxEZXNrdG9wXFxwb2JsYWNpb24tMDkucG5nKQ0KDQojIEVKRVJDSUNJTyBFTiBDTEFTRTogUG9ibGFjacOzbiANCg0KIyMgSW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hcyANCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojaW5zdGFsbC5wYWNrYWdlcygiZm9yZWNhc3QiKQ0KbGlicmFyeShmb3JlY2FzdCkNCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCmxpYnJhcnkoZ2dwbG90MikNCiNpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQoNCiMjIEltcG9ydGFyIGxhIGJhc2UgZGUgZGF0b3MgDQpgYGB7cn0NCnBvYmxhY2lvbiA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxDcmlzdGluYVxcRGVza3RvcFxccG9wdWxhdGlvbi5jc3YiKQ0KYGBgDQoNCiMjIEVudGVuZGVyIGxhIGJhc2UgZGUgZGF0b3MgDQpgYGB7cn0NCnN1bW1hcnkocG9ibGFjaW9uKQ0KYGBgDQpgYGB7cn0NCnN0cihwb2JsYWNpb24pDQpgYGANCmBgYHtyfQ0KaGVhZChwb2JsYWNpb24pDQpgYGANCg0KIyMgU2VyaWUgZGUgVGllbXBvIGVuIFRleGFzIA0KYGBge3J9DQpwb2JsYWNpb25fdGV4YXMgPC0gcG9ibGFjaW9uICU+JSBmaWx0ZXIoc3RhdGUgPT0iVFgiKQ0KZ2dwbG90KHBvYmxhY2lvbl90ZXhhcywgYWVzKHg9eWVhciwgeT1wb3B1bGF0aW9uKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGxhYnModGl0bGU9IlBvYmxhY2nDs24gZGUgVGV4YXMiLCB4ID0iQcOxbyIsIHk9IlBvYmxhY2nDs24iKQ0KYGBgDQpgYGB7cn0NCnRzX3RleGFzIDwtIHRzKHBvYmxhY2lvbl90ZXhhcyRwb3B1bGF0aW9uLCBzdGFydCA9IDE5NTAsIGZyZXF1ZW5jeT0xKSAjU2VyaWUgZGUgdGllbXBvIGFudWFsDQojdHNfdGV4YXMgPC0gdHMocG9ibGFjaW9uX3RleGFzJHBvcHVsYXRpb24sIHN0YXJ0ID0gYygxOTAwLCA0KSwgZnJlcXVlbmN5PTQpICNTZXJpZSBkZSB0aWVtcG8gdHJpbWVzdHJhbA0KI3RzX3RleGFzIDwtIHRzKHBvYmxhY2lvbl90ZXhhcyRwb3B1bGF0aW9uLCBzdGFydCA9IGMoMTkwMCwgOCksIGZyZXF1ZW5jeT0pICNTZXJpZSBkZSB0aWVtcG8gbWVuc3VhbA0KYXJpbWFfdGV4YXMgPC0gYXV0by5hcmltYSh0c190ZXhhcykNCnN1bW1hcnkoYXJpbWFfdGV4YXMpDQpgYGANCmBgYHtyfQ0KcHJvbm9zdGljb190ZXhhcyA8LSBmb3JlY2FzdChhcmltYV90ZXhhcywgbGV2ZWw9OTUsIGg9MTApDQpwcm9ub3N0aWNvX3RleGFzDQpgYGANCmBgYHtyfQ0KcGxvdChwcm9ub3N0aWNvX3RleGFzLCBtYWluID0gIlBvYmxhY2nDs24gZW4gVGV4YXMiKQ0KYGBgDQoNCiMjIENyZWFyIHVuIE1hcGEgDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMgSW5zdGFsYXIgeSBjYXJnYXIgbGFzIGxpYnJlcsOtYXMgbmVjZXNhcmlhcyBwYXJhIGFuw6FsaXNpcyB5IHZpc3VhbGl6YWNpw7NuDQojaW5zdGFsbC5wYWNrYWdlcyhjKCJkcGx5ciIsICJnZ3Bsb3QyIiwgImZvcmVjYXN0IiwgIm1hcHMiKSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KbGlicmFyeShtYXBzKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgMSkgSW1wb3J0YXIgbGEgYmFzZSBkZSBkYXRvcyBkZSBwb2JsYWNpw7NuIA0KDQpwb2JsYWNpb24gPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xcQ3Jpc3RpbmFcXERlc2t0b3BcXHBvcHVsYXRpb24uY3N2IikNCg0KIyMgMikgUHJveWVjdGFyIGxhIHBvYmxhY2nDs24gZXN0YXRhbCBoYXN0YSAyMDUwIHkgY29tYmluYXIgY29uIGRhdG9zIG9yaWdpbmFsZXMNCg0KIyBJbnRlZ3JhY2nDs24gZGUgcHJvbsOzc3RpY29zIGNvbiBsYSBiYXNlIGRlIGRhdG9zIGluaWNpYWwNCiMgQ3JlYXIgdW4gZGF0YXNldCBhbXBsaWFkbyBxdWUgcGFydGUgZGUgbGEgYmFzZSBkZSBkYXRvcyBvcmlnaW5hbA0KcG9ibGFjaW9uX2V4dGVuZGlkYSA8LSBwb2JsYWNpb24NCg0KIyBFeHRyYWVyIGxhIGxpc3RhIGRlIGVzdGFkb3Mgw7puaWNvcyBwcmVzZW50ZXMgZW4gbG9zIGRhdG9zDQplc3RhZG9zIDwtIHVuaXF1ZShwb2JsYWNpb24kc3RhdGUpDQoNCiMgTW9kZWxhciB5IHByb25vc3RpY2FyIGxhIHBvYmxhY2nDs24gZGUgY2FkYSBlc3RhZG8gaGFzdGEgZWwgYcOxbyAyMDUwDQpmb3Ioc3QgaW4gZXN0YWRvcyl7DQogIA0KICAjIEZpbHRyYXIgeSBvcmdhbml6YXIgbG9zIGRhdG9zIHBvciBhw7FvIHBhcmEgY2FkYSBlc3RhZG8NCiAgZGF0b3Nfc3QgPC0gcG9ibGFjaW9uICU+JQ0KICAgIGZpbHRlcihzdGF0ZSA9PSBzdCkgJT4lDQogICAgYXJyYW5nZSh5ZWFyKQ0KICANCiAgIyBJZGVudGlmaWNhciBlbCDDumx0aW1vIGHDsW8gZGlzcG9uaWJsZSBlbiBsYSBzZXJpZSBoaXN0w7NyaWNhDQogIHVsdGltb19hbmlvIDwtIG1heChkYXRvc19zdCR5ZWFyKQ0KICANCiAgIyBHZW5lcmFyIGxhIHNlcmllIGRlIHRpZW1wbyBhbnVhbCBwYXJhIGxhIHBvYmxhY2nDs24gZGVsIGVzdGFkbw0KICB0c19zdCA8LSB0cyhkYXRvc19zdCRwb3B1bGF0aW9uLA0KICAgICAgICAgICAgICBzdGFydCA9IG1pbihkYXRvc19zdCR5ZWFyKSwNCiAgICAgICAgICAgICAgZW5kICAgPSB1bHRpbW9fYW5pbywNCiAgICAgICAgICAgICAgZnJlcXVlbmN5ID0gMSkgICMgRGF0b3MgYW51YWxlcw0KICANCiAgIyBBanVzdGFyIHVuIG1vZGVsbyBBUklNQSBkZSBtYW5lcmEgYXV0b23DoXRpY2EgcGFyYSBlbCBlc3RhZG8NCiAgbW9kZWxvX3N0IDwtIGF1dG8uYXJpbWEodHNfc3QpDQogIA0KICAjIENhbGN1bGFyIGVsIGhvcml6b250ZSBkZSBwcm9uw7NzdGljbyBuZWNlc2FyaW8NCiAgIyAoc2UgZ2VuZXJhIGZvcmVjYXN0IHNvbG8gc2kgZmFsdGFuIGHDsW9zIHBhcmEgbGxlZ2FyIGEgMjA1MCkNCiAgaF95ZWFycyA8LSAyMDUwIC0gdWx0aW1vX2FuaW8NCiAgDQogIGlmKGhfeWVhcnMgPiAwKXsNCiAgICAjIEdlbmVyYXIgZWwgcHJvbsOzc3RpY28gcGFyYSBlbCBwZXJpb2RvIGZhbHRhbnRlDQogICAgcHJvbm9zdGljbyA8LSBmb3JlY2FzdChtb2RlbG9fc3QsIGggPSBoX3llYXJzKQ0KICAgIA0KICAgICMgQ3JlYXIgdW4gZGF0YWZyYW1lIGNvbiBsYXMgcHJveWVjY2lvbmVzIGdlbmVyYWRhcw0KICAgIGFuaW9zX3Byb25vc3RpY28gPC0gKHVsdGltb19hbmlvICsgMSk6MjA1MA0KICAgIHBvYmxhY2lvbl9wcm9ub3N0aWNhZGEgPC0gYXMubnVtZXJpYyhwcm9ub3N0aWNvJG1lYW4pDQogICAgDQogICAgZGZfZm9yZWNhc3QgPC0gZGF0YS5mcmFtZSgNCiAgICAgIHN0YXRlID0gc3QsDQogICAgICB5ZWFyICA9IGFuaW9zX3Byb25vc3RpY28sDQogICAgICBwb3B1bGF0aW9uID0gcG9ibGFjaW9uX3Byb25vc3RpY2FkYQ0KICAgICkNCiAgICANCiAgICAjIEluY29ycG9yYXIgbGFzIHByb3llY2Npb25lcyBhbCBkYXRhc2V0IGV4dGVuZGlkbw0KICAgIHBvYmxhY2lvbl9leHRlbmRpZGEgPC0gcmJpbmQocG9ibGFjaW9uX2V4dGVuZGlkYSwgZGZfZm9yZWNhc3QpDQogIH0NCn0NCg0KIyMgMykgRGVmaW5pciB1bmEgZnVuY2nDs24gcGFyYSB2aXN1YWxpemFyIGVsIG1hcGEgZGUgcG9ibGFjacOzbiBwb3IgYcOxbyANCg0KcGxvdF9tYXAgPC0gZnVuY3Rpb24oeWVhcikgew0KICANCiAgIyBGaWx0cmFyIGVsIGRhdGFzZXQgcGFyYSBlbCBhw7FvIGVzcGVjaWZpY2Fkbw0KICBkYXRhX3llYXIgPC0gcG9ibGFjaW9uX2V4dGVuZGlkYSAlPiUNCiAgICBmaWx0ZXIoeWVhciA9PSAhIXllYXIpDQogIA0KICAjIENhcmdhciBsYSBpbmZvcm1hY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbG9zIGVzdGFkb3MgZGUgRUUuVVUuDQogIHN0YXRlc19tYXAgPC0gbWFwX2RhdGEoInN0YXRlIikNCiAgDQogICMgUmVsYWNpb25hciBsYXMgYWJyZXZpYXR1cmFzIGVzdGF0YWxlcyBjb24gbG9zIG5vbWJyZXMgY29tcGxldG9zIGVuIG1pbsO6c2N1bGFzDQogICMgVXRpbGl6YW5kbyBsb3MgdmVjdG9yZXMgYXV4aWxpYXJlcyBzdGF0ZS5hYmIgeSBzdGF0ZS5uYW1lDQogIGRhdGFfeWVhciA8LSBkYXRhX3llYXIgJT4lDQogICAgbXV0YXRlKHJlZ2lvbiA9IHRvbG93ZXIoc3RhdGUubmFtZVttYXRjaChzdGF0ZSwgc3RhdGUuYWJiKV0pKSAlPiUNCiAgICByaWdodF9qb2luKHN0YXRlc19tYXAsIGJ5ID0gInJlZ2lvbiIpDQogIA0KICAjIEdlbmVyYXIgZWwgbWFwYSB0ZW3DoXRpY28gcG9yIHBvYmxhY2nDs24NCiAgZ2dwbG90KGRhdGFfeWVhciwgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gcG9wdWxhdGlvbikpICsNCiAgICBnZW9tX3BvbHlnb24oY29sb3IgPSAiYmxhY2siKSArDQogICAgIyBBcGxpY2FyIHVuIGdyYWRpZW50ZSBkZSBjb2xvciB2ZXJkZSAoYmFqbykgYSByb2pvIChhbHRvKQ0KICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQoDQogICAgICBsb3cgPSAiZ3JlZW4iLCAgICMgUmVwcmVzZW50YSBsYSBtZW5vciBwb2JsYWNpw7NuDQogICAgICBoaWdoID0gInJlZCIsICAgICMgSW5kaWNhIGxhIG1heW9yIHBvYmxhY2nDs24NCiAgICAgIG5hbWUgPSAiUG9ibGFjacOzbiINCiAgICApICsNCiAgICBsYWJzKA0KICAgICAgdGl0bGUgPSBwYXN0ZSgiUG9ibGFjacOzbiBwb3IgRXN0YWRvIGVuIiwgeWVhcikNCiAgICApICsNCiAgICB0aGVtZV92b2lkKCkgKw0KICAgIHRoZW1lKA0KICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKQ0KICAgICkNCn0NCg0KIyMgNCkgVmlzdWFsaXphciBsYSBldm9sdWNpw7NuIGRlbW9ncsOhZmljYSBjYWRhIGTDqWNhZGEgKDE5NTAgLSAyMDUwKSAtLS0tLS0tLS0tLQ0KDQpmb3IoeWVhciBpbiBzZXEoMTk1MCwgMjA1MCwgYnkgPSAxMCkpIHsNCiAgcHJpbnQocGxvdF9tYXAoeWVhcikpDQp9DQpgYGANCg0KIyBBY3RpdmlkYWQgMi4gTGVjaGUgc2Fib3JpemFkYSBIZXJzaGV5J3MNCiFbXShDOlxcVXNlcnNcXENyaXN0aW5hXFxEZXNrdG9wXFxDYXB0dXJhIGRlIHBhbnRhbGxhIDIwMjUtMDItMTkgMjEzNzExLnBuZykNCg0KIyMgSW50YWxhciBwYXF1ZXRlcyB5IGxsYW1hciBsaWJyZXLDrWFzIA0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygiZm9yZWNhc3QiKQ0KbGlicmFyeShmb3JlY2FzdCkNCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCmxpYnJhcnkoZ2dwbG90MikNCiNpbnN0YWxsLnBhY2thZ2VzKCJvcGVueGxzeCIpDQpsaWJyYXJ5KG9wZW54bHN4KQ0KYGBgDQoNCiMjIEltcG9ydGFyIGxhIGJhc2UgZGUgZGF0b3MgDQpgYGB7cn0NCnZlbnRhcyA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxDcmlzdGluYVxcRGVza3RvcFxcaGVyc2hleXMuY3N2IikNCmBgYA0KDQojIyAxLiBNb2RlbG8gQVVUTy1BUklNQQ0KYGBge3J9DQp0c192ZW50YXMgPC0gdHModmVudGFzJFZlbnRhcywgc3RhcnQ9YygyMDE3LDEpLCBmcmVxdWVuY3k9MTIpDQoNCmF1dG9wbG90ICh0c192ZW50YXMpICsgbGFicyAodGl0bGU9ICJWZW50YXMgZGUgTGVjaGUgU2Fib3JpemFkYSBIZXJzaGV5J3MiLCB4PSJUaWVtcG8iLCB5ID0iTWlsZXMgZGUgRMOzbGFyZXMiKQ0KYGBgDQpgYGB7cn0NCmFyaW1hX3ZlbnRhcyA8LSBhdXRvLmFyaW1hKHRzX3ZlbnRhcykNCnN1bW1hcnkgKGFyaW1hX3ZlbnRhcykNCmBgYA0KYGBge3J9DQpwcm9ub3N0aWNvX3ZlbnRhczwtIGZvcmVjYXN0IChhcmltYV92ZW50YXMsIGxldmVsPTk1LCBoPTEyKQ0KcHJvbm9zdGljb192ZW50YXMNCmBgYA0KYGBge3J9DQphdXRvcGxvdCAocHJvbm9zdGljb192ZW50YXMpICsgbGFicyAodGl0bGU9ICJwcm9uw7NzdGljbyBkZSBWZW50YXMgMjAyMCBkZSBMZWNoZSBTYWJvcml6YWRhIEhlcnNoZXkncyIsIHg9IlRpZW1wbyIsIHkgPSAiTWlsZXMgZGUgRMOzbGFyZXMiKQ0KYGBgDQoNCiMjIE1vZGVsbyBkZSBSZWdyZXNpw7NuIExpbmVhbCANCmBgYHtyfQ0KdmVudGFzJG1lcyA8LSAxOjM2DQpyZWdyZXNpb25fdmVudGFzIDwtIGxtKFZlbnRhcyB+IG1lcywgZGF0YT12ZW50YXMpDQpzdW1tYXJ5KHJlZ3Jlc2lvbl92ZW50YXMpDQpgYGANCmBgYHtyfQ0Kc2lndWllbnRlX2FuaW8gPC0gZGF0YS5mcmFtZShtZXM9MzcuNDgpDQpwcmVkaWNjaW9uX3JlZ3Jlc2lvbiA8LSBwcmVkaWN0KHJlZ3Jlc2lvbl92ZW50YXMsIHNpZ3VpZW50ZV9hbmlvKQ0KcHJlZGljY2lvbl9yZWdyZXNpb24NCmBgYA0KYGBge3J9DQpwbG90KHZlbnRhcyRtZXMsIHZlbnRhcyRWZW50YXMsIG1haW49IlByb25vc3RpY28gZGUgdmVudGFzIDIwMjAgZGUgbGVjaGUgc2Fib3JpemFkYSBIZXJzaGV5IiwgeGxhYj0gIlRpZW1wbyIsIHlsYWI9ICJNaWxlcyBkZSBEb2xhcmVzIikNCmFibGluZShyZWdyZXNpb25fdmVudGFzLCBjb2w9ImJsdWUiKQ0KcG9pbnRzKHNpZ3VpZW50ZV9hbmlvJG1lcywgIHByZWRpY2Npb25fcmVncmVzaW9uLCBjb2wgPSAicmVkIikNCmBgYA0KYGBge3J9DQpwcmVkaWNjaW9uZXNfcmVhbGVzIDwtIHByZWRpY3QocmVncmVzaW9uX3ZlbnRhcywgdmVudGFzKQ0KTUFQRSA8LSBtZWFuKGFicygodmVudGFzJFZlbnRhcyAtIA0KICAgICAgICAgICAgICAgICAgICBwcmVkaWNjaW9uZXNfcmVhbGVzKS92ZW50YXMkVmVudGFzKSkqMTAwDQpNQVBFDQpgYGANCg0KIyBDb25jbHVzaW9uZXMgDQpFbCBtZWpvciBtb2RlbG8gcXVlIHNlIGFkYXB0YSBhIGxhIHNlcmllIGVzIGVsIFNBUklNQSBjb24gdW4gTUFQRSBkZSAwLjcxJSwgY29tcGFyYWRhIGNvbiBsYSByZWdyZXNpw7NuIExpbmVhbCBxdWUgc3UgTUFQRSBlcyBkZSAyLjAxJS4NCg0KUGFyYSBlbCBzaWd1aWVudGUgYcOxbywgbGEgcHJveWVjY2nDs24gZGUgdmVudGFzIGVzIGxhIHNpZ3VpZW50ZTogfCBNZXMgeSBhw7FvIHwgRXNuZWFyaW9zIEVzcGVyYWRvIHwgRXNjZW5hcmlvIFBlc2ltaXN0YSB8IEVzY2VuYXJpbyBvcHRpbWlzdGEgfA0KDQogSmFuIDIwMjAgfCAzNTQ5OC45MCB8IDM0NjE2LjQ4IHwgMzYzODEuMzIgfCAgDQogRmViIDIwMjAgfCAzNDIwMi4xNyB8IDMzMTU1LjI4IHwgMzUyNDkuMDUgfCAgDQogTWFyIDIwMjAgfCAzNjcwMy4wMSB8IDM1NTk2LjEwIHwgMzc4MDkuOTIgfCAgDQogQXByIDIwMjAgfCAzNjI3MS45MCB8IDM1MTQxLjQ0IHwgMzc0MDIuMzYgfCAgDQogTWF5IDIwMjAgfCAzNzEyMS45OCB8IDM1OTgyLjA3IHwgMzgyNjEuOTAgfCAgIA0KIEp1biAyMDIwIHwgMzcxMDIuNjUgfCAzNTk1OC45MCB8IDM4MjQ2LjQwIHwgIA0KIEp1bCAyMDIwIHwgMzcxNTEuMDQgfCAzNjAwNS43MyB8IDM4Mjk2LjM0IHwgIA0KIEF1ZyAyMDIwIHwgMzg1NjQuNjQgfCAzNzQxOC43MCB8IDM5NzEwLjU4IHwgIA0KIFNlcCAyMDIwIHwgMzg3NTUuMjIgfCAzNzYwOS4wMyB8IDM5OTAxLjQyIHwgIA0KIE9jdCAyMDIwIHwgMzk3NzkuMDIgfCAzODYzMi43MiB8IDQwOTI1LjMyIHwgIA0KIE5vdiAyMDIwIHwgMzg3NDEuNjMgfCAzNzU5NS4yOCB8IDM5ODg3Ljk3IHwgIA0KIERlYyAyMDIwIHwgMzg2NDUuODYgfCAzNzQ5OS41MCB8IDM5NzkyLjIyIHwgIA0KIA0KYGBge3J9DQp2ZW50YXNfcG9yX2FuaW8gPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xcQ3Jpc3RpbmFcXERlc2t0b3BcXHZlbnRhc19wb3JfYW5pby5jc3YiKQ0KZ2dwbG90KHZlbnRhc19wb3JfYW5pbywgYWVzKHg9bWVzLCB5ID0gdmVudGFzLCBjb2w9YXMuZmFjdG9yKGFuaW8pLCANCmdyb3VwPWFuaW8pKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBsYWJzKHRpdGxlID0gIlZlbnRhcyBkZSBMZWNoZSBTYWJvcml6YWRhIEhlcnNoZXkgcG9yIEHDsW8iLA0KICAgICAgIHg9Ik1lcyIsIHk9Ik1pbGVzIGRlIGRvbGFyZXMiKQ0KYGBgDQoNCk51ZXN0cmEgcmVjb2VtZGFjacOzbiBzZXJpYSByZWFsaXphciBjYW1wYcOxYXMgcGFyYSBhdW1lbnRhciBlbCBjb25zdW1vIGRlIGxlY2hlIHNhYm9yaXphZGEgSGVyc2hleXMgZW4gZWwgcHJpbWVyIHNlbWVzdHJlIGRlbCBhw7FvLg0KDQo=