title: “Actividad 2” author: “Gerardo Cedillo Corona A01704232” date: “2025-02-13” output: html_document: toc: TRUE toc_float: TRUE code_download: TRUE theme: cerulean —

Ejercicio en clase: Población

Instalar paquetes y llamar librerias

#install.packages("forecast")
library(forecast)
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
#install.packages("tidyverse")
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.4
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
#install.packages("tidyverse")
library(ggplot2)
#install.packages("dplyr")
library(dplyr)

Importar la base de datos

#file.choose()
poblacion <- read.csv("C:\\Users\\rodri\\Desktop\\Octavo\\Analitica\\Modulo 1\\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)
## 
## Adjuntando el paquete: 'maps'
## The following object is masked from 'package:purrr':
## 
##     map
## 1) Importar la base de datos de población 

poblacion <- read.csv("C:\\Users\\rodri\\Desktop\\Octavo\\Analitica\\Modulo 1\\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

##Instalar paquetes y llamar librerias

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

##Importar base de datos

ventas <- read.csv("C:\\Users\\rodri\\Desktop\\Octavo\\Analitica\\Modulo 1\\Ventas_Históricas_Lechitas.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")

##2. 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\\rodri\\Desktop\\Octavo\\Analitica\\Modulo 1\\ventas_por_anio (2).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.

LS0tDQoNCg0KdGl0bGU6ICJBY3RpdmlkYWQgMiINCmF1dGhvcjogIkdlcmFyZG8gQ2VkaWxsbyBDb3JvbmEgQTAxNzA0MjMyIg0KZGF0ZTogIjIwMjUtMDItMTMiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUgDQogICAgdGhlbWU6IGNlcnVsZWFuIA0KLS0tDQohW10oQzpcXFVzZXJzXFxyb2RyaVxcRGVza3RvcFxcT2N0YXZvXFxBbmFsaXRpY2FcXE1vZHVsbyAxXFxwb2JsYWNpb24tZTE1NTExMjQwMzE2OTguanBnKSANCg0KIyBFamVyY2ljaW8gZW4gY2xhc2U6IFBvYmxhY2nDs24NCg0KIyMgSW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyaWFzIA0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygiZm9yZWNhc3QiKQ0KbGlicmFyeShmb3JlY2FzdCkNCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCmxpYnJhcnkoZ2dwbG90MikNCiNpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQpsaWJyYXJ5KGRwbHlyKQ0KDQpgYGANCg0KIyMgSW1wb3J0YXIgbGEgYmFzZSBkZSBkYXRvcw0KYGBge3J9DQojZmlsZS5jaG9vc2UoKQ0KcG9ibGFjaW9uIDwtIHJlYWQuY3N2KCJDOlxcVXNlcnNcXHJvZHJpXFxEZXNrdG9wXFxPY3Rhdm9cXEFuYWxpdGljYVxcTW9kdWxvIDFcXHBvcHVsYXRpb24uY3N2IikNCmBgYA0KDQojIyBFbnRlbmRlciBsYSBiYXNlIGRlIGRhdG9zIA0KDQpgYGB7cn0NCnN1bW1hcnkocG9ibGFjaW9uKQ0Kc3RyKHBvYmxhY2lvbikNCmhlYWQocG9ibGFjaW9uKQ0KYGBgDQoNCiMjIFNlcmllIGRlIHRpZW1wbyBlbiBUZXhhcyANCmBgYHtyfQ0KcG9ibGFjaW9uX3RleGFzIDwtIHBvYmxhY2lvbiAlPiUgZmlsdGVyKHN0YXRlID09IlRYIikNCmdncGxvdChwb2JsYWNpb25fdGV4YXMsIGFlcyh4PXllYXIsIHk9cG9wdWxhdGlvbikpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHRpdGxlPSJQb2JsYWNpw7NuIGRlIFRleGFzIiwgeCA9IkHDsW8iLCB5PSJQb2JsYWNpw7NuIikNCnRzX3RleGFzIDwtIHRzKHBvYmxhY2lvbl90ZXhhcyRwb3B1bGF0aW9uLCBzdGFydCA9IDE5NTAsIGZyZXF1ZW5jeT0xKSAjU2VyaWUgZGUgdGllbXBvIGFudWFsDQojdHNfdGV4YXMgPC0gdHMocG9ibGFjaW9uX3RleGFzJHBvcHVsYXRpb24sIHN0YXJ0ID0gYygxOTAwLCA0KSwgZnJlcXVlbmN5PTQpICNTZXJpZSBkZSB0aWVtcG8gdHJpbWVzdHJhbA0KI3RzX3RleGFzIDwtIHRzKHBvYmxhY2lvbl90ZXhhcyRwb3B1bGF0aW9uLCBzdGFydCA9IGMoMTkwMCwgOCksIGZyZXF1ZW5jeT0pICNTZXJpZSBkZSB0aWVtcG8gbWVuc3VhbA0KYXJpbWFfdGV4YXMgPC0gYXV0by5hcmltYSh0c190ZXhhcykNCnN1bW1hcnkoYXJpbWFfdGV4YXMpDQpwcm9ub3N0aWNvX3RleGFzIDwtIGZvcmVjYXN0KGFyaW1hX3RleGFzLCBsZXZlbD05NSwgaD0xMCkNCnByb25vc3RpY29fdGV4YXMNCnBsb3QocHJvbm9zdGljb190ZXhhcywgbWFpbiA9ICJQb2JsYWNpw7NuIGVuIFRleGFzIikNCg0KYGBgDQoNCiMjIENyZWFyIHVuIE1hcGEgDQpgYGB7cn0NCiMjIEluc3RhbGFyIHkgY2FyZ2FyIGxhcyBsaWJyZXLDrWFzIG5lY2VzYXJpYXMgcGFyYSBhbsOhbGlzaXMgeSB2aXN1YWxpemFjacOzbg0KDQoNCiNpbnN0YWxsLnBhY2thZ2VzKGMoImRwbHlyIiwgImdncGxvdDIiLCAiZm9yZWNhc3QiLCAibWFwcyIpKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZm9yZWNhc3QpDQpsaWJyYXJ5KG1hcHMpDQoNCg0KDQojIyAxKSBJbXBvcnRhciBsYSBiYXNlIGRlIGRhdG9zIGRlIHBvYmxhY2nDs24gDQoNCnBvYmxhY2lvbiA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxyb2RyaVxcRGVza3RvcFxcT2N0YXZvXFxBbmFsaXRpY2FcXE1vZHVsbyAxXFxwb3B1bGF0aW9uLmNzdiIpDQoNCiMjIDIpIFByb3llY3RhciBsYSBwb2JsYWNpw7NuIGVzdGF0YWwgaGFzdGEgMjA1MCB5IGNvbWJpbmFyIGNvbiBkYXRvcyBvcmlnaW5hbGVzDQoNCiMgSW50ZWdyYWNpw7NuIGRlIHByb27Ds3N0aWNvcyBjb24gbGEgYmFzZSBkZSBkYXRvcyBpbmljaWFsDQojIENyZWFyIHVuIGRhdGFzZXQgYW1wbGlhZG8gcXVlIHBhcnRlIGRlIGxhIGJhc2UgZGUgZGF0b3Mgb3JpZ2luYWwNCnBvYmxhY2lvbl9leHRlbmRpZGEgPC0gcG9ibGFjaW9uDQoNCiMgRXh0cmFlciBsYSBsaXN0YSBkZSBlc3RhZG9zIMO6bmljb3MgcHJlc2VudGVzIGVuIGxvcyBkYXRvcw0KZXN0YWRvcyA8LSB1bmlxdWUocG9ibGFjaW9uJHN0YXRlKQ0KDQojIE1vZGVsYXIgeSBwcm9ub3N0aWNhciBsYSBwb2JsYWNpw7NuIGRlIGNhZGEgZXN0YWRvIGhhc3RhIGVsIGHDsW8gMjA1MA0KZm9yKHN0IGluIGVzdGFkb3Mpew0KICANCiAgIyBGaWx0cmFyIHkgb3JnYW5pemFyIGxvcyBkYXRvcyBwb3IgYcOxbyBwYXJhIGNhZGEgZXN0YWRvDQogIGRhdG9zX3N0IDwtIHBvYmxhY2lvbiAlPiUNCiAgICBmaWx0ZXIoc3RhdGUgPT0gc3QpICU+JQ0KICAgIGFycmFuZ2UoeWVhcikNCiAgDQogICMgSWRlbnRpZmljYXIgZWwgw7psdGltbyBhw7FvIGRpc3BvbmlibGUgZW4gbGEgc2VyaWUgaGlzdMOzcmljYQ0KICB1bHRpbW9fYW5pbyA8LSBtYXgoZGF0b3Nfc3QkeWVhcikNCiAgDQogICMgR2VuZXJhciBsYSBzZXJpZSBkZSB0aWVtcG8gYW51YWwgcGFyYSBsYSBwb2JsYWNpw7NuIGRlbCBlc3RhZG8NCiAgdHNfc3QgPC0gdHMoZGF0b3Nfc3QkcG9wdWxhdGlvbiwNCiAgICAgICAgICAgICAgc3RhcnQgPSBtaW4oZGF0b3Nfc3QkeWVhciksDQogICAgICAgICAgICAgIGVuZCAgID0gdWx0aW1vX2FuaW8sDQogICAgICAgICAgICAgIGZyZXF1ZW5jeSA9IDEpICAjIERhdG9zIGFudWFsZXMNCiAgDQogICMgQWp1c3RhciB1biBtb2RlbG8gQVJJTUEgZGUgbWFuZXJhIGF1dG9tw6F0aWNhIHBhcmEgZWwgZXN0YWRvDQogIG1vZGVsb19zdCA8LSBhdXRvLmFyaW1hKHRzX3N0KQ0KICANCiAgIyBDYWxjdWxhciBlbCBob3Jpem9udGUgZGUgcHJvbsOzc3RpY28gbmVjZXNhcmlvDQogICMgKHNlIGdlbmVyYSBmb3JlY2FzdCBzb2xvIHNpIGZhbHRhbiBhw7FvcyBwYXJhIGxsZWdhciBhIDIwNTApDQogIGhfeWVhcnMgPC0gMjA1MCAtIHVsdGltb19hbmlvDQogIA0KICBpZihoX3llYXJzID4gMCl7DQogICAgIyBHZW5lcmFyIGVsIHByb27Ds3N0aWNvIHBhcmEgZWwgcGVyaW9kbyBmYWx0YW50ZQ0KICAgIHByb25vc3RpY28gPC0gZm9yZWNhc3QobW9kZWxvX3N0LCBoID0gaF95ZWFycykNCiAgICANCiAgICAjIENyZWFyIHVuIGRhdGFmcmFtZSBjb24gbGFzIHByb3llY2Npb25lcyBnZW5lcmFkYXMNCiAgICBhbmlvc19wcm9ub3N0aWNvIDwtICh1bHRpbW9fYW5pbyArIDEpOjIwNTANCiAgICBwb2JsYWNpb25fcHJvbm9zdGljYWRhIDwtIGFzLm51bWVyaWMocHJvbm9zdGljbyRtZWFuKQ0KICAgIA0KICAgIGRmX2ZvcmVjYXN0IDwtIGRhdGEuZnJhbWUoDQogICAgICBzdGF0ZSA9IHN0LA0KICAgICAgeWVhciAgPSBhbmlvc19wcm9ub3N0aWNvLA0KICAgICAgcG9wdWxhdGlvbiA9IHBvYmxhY2lvbl9wcm9ub3N0aWNhZGENCiAgICApDQogICAgDQogICAgIyBJbmNvcnBvcmFyIGxhcyBwcm95ZWNjaW9uZXMgYWwgZGF0YXNldCBleHRlbmRpZG8NCiAgICBwb2JsYWNpb25fZXh0ZW5kaWRhIDwtIHJiaW5kKHBvYmxhY2lvbl9leHRlbmRpZGEsIGRmX2ZvcmVjYXN0KQ0KICB9DQp9DQoNCiMjIDMpIERlZmluaXIgdW5hIGZ1bmNpw7NuIHBhcmEgdmlzdWFsaXphciBlbCBtYXBhIGRlIHBvYmxhY2nDs24gcG9yIGHDsW8gDQoNCnBsb3RfbWFwIDwtIGZ1bmN0aW9uKHllYXIpIHsNCiAgDQogICMgRmlsdHJhciBlbCBkYXRhc2V0IHBhcmEgZWwgYcOxbyBlc3BlY2lmaWNhZG8NCiAgZGF0YV95ZWFyIDwtIHBvYmxhY2lvbl9leHRlbmRpZGEgJT4lDQogICAgZmlsdGVyKHllYXIgPT0gISF5ZWFyKQ0KICANCiAgIyBDYXJnYXIgbGEgaW5mb3JtYWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxvcyBlc3RhZG9zIGRlIEVFLlVVLg0KICBzdGF0ZXNfbWFwIDwtIG1hcF9kYXRhKCJzdGF0ZSIpDQogIA0KICAjIFJlbGFjaW9uYXIgbGFzIGFicmV2aWF0dXJhcyBlc3RhdGFsZXMgY29uIGxvcyBub21icmVzIGNvbXBsZXRvcyBlbiBtaW7DunNjdWxhcw0KICAjIFV0aWxpemFuZG8gbG9zIHZlY3RvcmVzIGF1eGlsaWFyZXMgc3RhdGUuYWJiIHkgc3RhdGUubmFtZQ0KICBkYXRhX3llYXIgPC0gZGF0YV95ZWFyICU+JQ0KICAgIG11dGF0ZShyZWdpb24gPSB0b2xvd2VyKHN0YXRlLm5hbWVbbWF0Y2goc3RhdGUsIHN0YXRlLmFiYildKSkgJT4lDQogICAgcmlnaHRfam9pbihzdGF0ZXNfbWFwLCBieSA9ICJyZWdpb24iKQ0KICANCiAgIyBHZW5lcmFyIGVsIG1hcGEgdGVtw6F0aWNvIHBvciBwb2JsYWNpw7NuDQogIGdncGxvdChkYXRhX3llYXIsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IHBvcHVsYXRpb24pKSArDQogICAgZ2VvbV9wb2x5Z29uKGNvbG9yID0gImJsYWNrIikgKw0KICAgICMgQXBsaWNhciB1biBncmFkaWVudGUgZGUgY29sb3IgdmVyZGUgKGJham8pIGEgcm9qbyAoYWx0bykNCiAgICBzY2FsZV9maWxsX2dyYWRpZW50KA0KICAgICAgbG93ID0gImdyZWVuIiwgICAjIFJlcHJlc2VudGEgbGEgbWVub3IgcG9ibGFjacOzbg0KICAgICAgaGlnaCA9ICJyZWQiLCAgICAjIEluZGljYSBsYSBtYXlvciBwb2JsYWNpw7NuDQogICAgICBuYW1lID0gIlBvYmxhY2nDs24iDQogICAgKSArDQogICAgbGFicygNCiAgICAgIHRpdGxlID0gcGFzdGUoIlBvYmxhY2nDs24gcG9yIEVzdGFkbyBlbiIsIHllYXIpDQogICAgKSArDQogICAgdGhlbWVfdm9pZCgpICsNCiAgICB0aGVtZSgNCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIikNCiAgICApDQp9DQoNCiMjIDQpIFZpc3VhbGl6YXIgbGEgZXZvbHVjacOzbiBkZW1vZ3LDoWZpY2EgY2FkYSBkw6ljYWRhICgxOTUwIC0gMjA1MCkgLS0tLS0tLS0tLS0NCg0KZm9yKHllYXIgaW4gc2VxKDE5NTAsIDIwNTAsIGJ5ID0gMTApKSB7DQogIHByaW50KHBsb3RfbWFwKHllYXIpKQ0KfQ0KDQpgYGANCg0KDQojIEFjdGl2aWRhZCAyLiBMZWNoZSBzYWJvcml6YWRhIEhlcnNoZXkncyANCg0KIVtdKEM6XFxVc2Vyc1xccm9kcmlcXERlc2t0b3BcXE9jdGF2b1xcQW5hbGl0aWNhXFxNb2R1bG8gMVxcODAwcHgtSGVyc2hleS1iYXItb3Blbi5qcGcpIA0KDQojI0luc3RhbGFyIHBhcXVldGVzIHkgbGxhbWFyIGxpYnJlcmlhcyANCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoImZvcmVjYXN0IikNCmxpYnJhcnkoZm9yZWNhc3QpDQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KI2luc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCmBgYA0KDQoNCiMjSW1wb3J0YXIgYmFzZSBkZSBkYXRvcw0KYGBge3J9DQp2ZW50YXMgPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xccm9kcmlcXERlc2t0b3BcXE9jdGF2b1xcQW5hbGl0aWNhXFxNb2R1bG8gMVxcVmVudGFzX0hpc3TDs3JpY2FzX0xlY2hpdGFzLmNzdiIpDQpgYGANCg0KDQojIzEuIE1vZGVsbyBBVVRPLkFSSU1BDQpgYGB7cn0NCnRzX3ZlbnRhcyA8LSB0cyh2ZW50YXMkVmVudGFzLCBzdGFydD1jKDIwMTcsMSksIGZyZXF1ZW5jeT0xMikNCg0KYXV0b3Bsb3QgKHRzX3ZlbnRhcykgKyBsYWJzICh0aXRsZT0gInZlbnRhcyBkZSBMZWNoZSBTYWJvcml6YWRhDQpIZXJzaGV5J3MiLCB4PSJUaWVtcG8iLCB5ID0iTWlsZXMgZGUgRMOzbGFyZXMiKQ0KYXJpbWFfdmVudGFzIDwtIGF1dG8uYXJpbWEodHNfdmVudGFzKQ0Kc3VtbWFyeSAoYXJpbWFfdmVudGFzKQ0KcHJvbm9zdGljb192ZW50YXM8LSBmb3JlY2FzdCAoYXJpbWFfdmVudGFzLCBsZXZlbD05NSwgaD0xMikNCnByb25vc3RpY29fdmVudGFzDQphdXRvcGxvdCAocHJvbm9zdGljb192ZW50YXMpICsgbGFicyAodGl0bGU9ICJwcm9uw7NzdGljbyBkZSBWZW50YXMgMjAyMCBkZSBMZWNoZSBTYWJvcml6YWRhIEhlcnNoZXkncyIsIHg9IlRpZW1wbyIsIHkgPSAiTWlsZXMgZGUgRMOzbGFyZXMiKQ0KYGBgDQoNCiMjMi4gTW9kZWxvIGRlIHJlZ3Jlc2nDs24gTGluZWFsIA0KYGBge3J9DQp2ZW50YXMkbWVzIDwtIDE6MzYNCnJlZ3Jlc2lvbl92ZW50YXMgPC0gbG0oVmVudGFzIH4gbWVzLCBkYXRhPXZlbnRhcykNCnN1bW1hcnkocmVncmVzaW9uX3ZlbnRhcykNCnNpZ3VpZW50ZV9hbmlvIDwtIGRhdGEuZnJhbWUobWVzPTM3LjQ4KQ0KcHJlZGljY2lvbl9yZWdyZXNpb24gPC0gcHJlZGljdChyZWdyZXNpb25fdmVudGFzLCBzaWd1aWVudGVfYW5pbykNCnByZWRpY2Npb25fcmVncmVzaW9uDQpwbG90KHZlbnRhcyRtZXMsIHZlbnRhcyRWZW50YXMsIG1haW49IlByb25vc3RpY28gZGUgdmVudGFzIDIwMjAgZGUgbGVjaGUgc2Fib3JpemFkYSBIZXJzaGV5IiwgeGxhYj0gIlRpZW1wbyIsIHlsYWI9ICJNaWxlcyBkZSBEb2xhcmVzIikNCmFibGluZShyZWdyZXNpb25fdmVudGFzLCBjb2w9ImJsdWUiKQ0KcG9pbnRzKHNpZ3VpZW50ZV9hbmlvJG1lcywgIHByZWRpY2Npb25fcmVncmVzaW9uLCBjb2wgPSAicmVkIikNCnByZWRpY2Npb25lc19yZWFsZXMgPC0gcHJlZGljdChyZWdyZXNpb25fdmVudGFzLCB2ZW50YXMpDQpNQVBFIDwtIG1lYW4oYWJzKCh2ZW50YXMkVmVudGFzIC0gDQogICAgICAgICAgICAgICAgICAgIHByZWRpY2Npb25lc19yZWFsZXMpL3ZlbnRhcyRWZW50YXMpKSoxMDANCk1BUEUNCmBgYA0KDQojIyBDb25jbHVzaW9uZXMgDQpFbCBtZWpvciBtb2RlbG8gcXVlIHNlIGFkYXB0YSBhIGxhIHNlcmllIGVzIGVsICoqU0FSSU1BKiogY29uIHVuIE1BUEUgZGUgMC43MSUsIGNvbXBhcmFkYSBjb24gbGEgcmVncmVzacOzbiBMaW5lYWwgcXVlIHN1IE1BUEUgZXMgZGUgMi4wMSUuDQoNClBhcmEgZWwgc2lndWllbnRlIGHDsW8sIGxhIHByb3llY2Npw7NuIGRlIHZlbnRhcyBlcyBsYSBzaWd1aWVudGU6IA0KfCAgTWVzIHkgYcOxbyAgfCAgRXNuZWFyaW9zIEVzcGVyYWRvICB8IEVzY2VuYXJpbyBQZXNpbWlzdGEgIHwgIEVzY2VuYXJpbyBvcHRpbWlzdGEgIHwNCg0KfCAgSmFuIDIwMjAgICB8CSAzNTQ5OC45MCAgfAkgMzQ2MTYuNDggICB8CSAzNjM4MS4zMiAgfAkNCnwgIEZlYiAyMDIwICAgfAkgMzQyMDIuMTcgIHwJIDMzMTU1LjI4ICAgfAkgMzUyNDkuMDUgIHwJDQp8ICBNYXIgMjAyMCAgIHwJIDM2NzAzLjAxICB8CSAzNTU5Ni4xMCAgIHwJIDM3ODA5LjkyICB8CQ0KfCAgQXByIDIwMjAgICB8CSAzNjI3MS45MCAgfAkgMzUxNDEuNDQgICB8CSAzNzQwMi4zNiAgfAkNCnwgIE1heSAyMDIwICAgfCAgMzcxMjEuOTggIHwJIDM1OTgyLjA3ICAgfAkgMzgyNjEuOTAgIHwJDQp8ICBKdW4gMjAyMCAgIHwJIDM3MTAyLjY1ICB8CSAzNTk1OC45MCAgIHwJIDM4MjQ2LjQwICB8CQ0KfCAgSnVsIDIwMjAgICB8CSAzNzE1MS4wNCAgfAkgMzYwMDUuNzMgICB8CSAzODI5Ni4zNCAgfAkNCnwgIEF1ZyAyMDIwICAgfAkgMzg1NjQuNjQgIHwJIDM3NDE4LjcwICAgfAkgMzk3MTAuNTggIHwJDQp8ICBTZXAgMjAyMCAgIHwJIDM4NzU1LjIyICB8CSAzNzYwOS4wMyAgIHwJIDM5OTAxLjQyICB8CQ0KfCAgT2N0IDIwMjAgICB8CSAzOTc3OS4wMiAgfAkgMzg2MzIuNzIgICB8CSA0MDkyNS4zMiAgfAkNCnwgIE5vdiAyMDIwICAgfAkgMzg3NDEuNjMgIHwJIDM3NTk1LjI4ICAgfAkgMzk4ODcuOTcgIHwJDQp8ICBEZWMgMjAyMCAgIHwJIDM4NjQ1Ljg2ICB8CSAzNzQ5OS41MCAgIHwJIDM5NzkyLjIyICB8CQ0KDQpgYGB7cn0NCnZlbnRhc19wb3JfYW5pbyA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxyb2RyaVxcRGVza3RvcFxcT2N0YXZvXFxBbmFsaXRpY2FcXE1vZHVsbyAxXFx2ZW50YXNfcG9yX2FuaW8gKDIpLmNzdiIpDQpnZ3Bsb3QodmVudGFzX3Bvcl9hbmlvLCBhZXMoeD1tZXMsIHkgPSB2ZW50YXMsIGNvbD1hcy5mYWN0b3IoYW5pbyksIA0KZ3JvdXA9YW5pbykpICsgDQogIGdlb21fbGluZSgpICsgDQogIGxhYnModGl0bGUgPSAiVmVudGFzIGRlIExlY2hlIFNhYm9yaXphZGEgSGVyc2hleSBwb3IgQcOxbyIsDQogICAgICAgeD0iTWVzIiwgeT0iTWlsZXMgZGUgZG9sYXJlcyIpDQoNCmBgYA0KDQpOdWVzdHJhIHJlY29lbWRhY2nDs24gc2VyaWEgcmVhbGl6YXIgY2FtcGHDsWFzIHBhcmEgYXVtZW50YXIgZWwgY29uc3VtbyBkZSBsZWNoZSBzYWJvcml6YWRhIEhlcnNoZXlzIGVuIGVsIHByaW1lciBzZW1lc3RyZSBkZWwgYcOxby4g