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.2     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.1
## ── 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("ggplot2")
library(ggplot2)
#install.packages("dplyr")
library(dplyr)

Importar la base de datos

#file.choose()
poblacion <- read.csv("C:\\Users\\Diego Pérez\\Downloads\\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 = 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=) #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
## 2020       29398472 29199487 29597457
## 2021       29806827 29463665 30149990
## 2022       30215183 29742956 30687410
## 2023       30623538 30024100 31222977
## 2024       31031894 30303359 31760429
## 2025       31440249 30579246 32301253
## 2026       31848605 30851090 32846119
## 2027       32256960 31118581 33395339
## 2028       32665316 31381587 33949044
## 2029       33073671 31640070 34507272
plot(pronostico_texas, main = "Población en Texas")

Ejercicio en clase Lunes 17: MAPA

## Intalar paquetes y llamar librerias

#install.packages("forecast")
library(forecast)
#install.packages("tidyverse")
library(tidyverse)
#install.packages("ggplot2")
library(ggplot2)
#install.packages("dplyr")
library(dplyr)
#install.packages("maps")
library(maps)
## Warning: package 'maps' was built under R version 4.3.3
## 
## Attaching package: 'maps'
## The following object is masked from 'package:purrr':
## 
##     map

Importar la base de datos

#file.choose()
poblacion <- read.csv("C:\\Users\\Diego Pérez\\Downloads\\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

map(database = "state")
map(database="state", regions = "Texas", col="red", fill = TRUE, add = TRUE) 
map(database="state", regions = "New York", col="green", fill = TRUE, add = TRUE)

Actividad Crear un Mapa

Crear un mapa de EUA por década, con un gradiente verde-rojo de la población por estado, desde 1950 hasta 2050

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)

Importar la base de datos de población

poblacion <- read.csv("C:\\Users\\Diego Pérez\\Downloads\\population.csv")

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)
  }
}

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")
    )
}

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")
## Warning: package 'forecast' is in use and will not be installed
library(forecast)
install.packages("tidyverse")
## Warning: package 'tidyverse' is in use and will not be installed
library(tidyverse)
install.packages("ggplot2")
## Warning: package 'ggplot2' is in use and will not be installed
library(ggplot2)

Importar la base de datos

#file.choose()
ventas <- read.csv("C:\\Users\\Diego Pérez\\Downloads\\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 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)
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 = "Pronostico de ventas 2020 de leche Sabpoorizada Hershey's", x="Tiempo", y="Miles de dolares")

2. Modelo 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        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 2020 de leche Saborizada Hershey's", xlab="Tiempo", ylab="Miles de dolares") +
abline(regresion_ventas, col="blue") +
points(siguiente_anio$mes, prediccion_Regresion, col="red")

## integer(0)
prediccion_reales <- predict(regresion_ventas, ventas)
MAPE <- mean(abs((ventas$Ventas - 
                   prediccion_reales)/ventas$Ventas))*100
MAPE
## [1] 2.011297

3. Conclusión

El mejor modelo que se adapta a la serie es el SARIMA con un MAPE de 0.70, comparado 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 Escenario 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\\Diego Pérez\\Downloads\\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's por Año", x = "Mes", y= "Miles de dolares")

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

LS0tDQp0aXRsZTogIkFjdGl2aWRhZCAyIg0KYXV0aG9yOiAiRGllZ28gQWxlamFuZHJvIFDDqXJleiBDaXNuZXJvcyAtIEEwMTI3NTU2MSINCmRhdGU6ICIyMDI1LTAyLTE3Ig0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IGNlcnVsZWFuDQotLS0NCg0KIVtdKEM6XFxVc2Vyc1xcRGllZ28gUMOpcmV6XFxEb3dubG9hZHNcXGlsdXN0cmFjaW9uLWNvbG9yLXBvYmxhY2lvbi1odW1hbmEtdGllcnJhLWRpYnVqby1saW5lYS1kaWEtbXVuZGlhbC1wb2JsYWNpb25fNzE4NTE4LTQ3MTQuYXZpZikNCg0KIyBFamVyY2ljaW8gZW4gQ2xhc2U6IFBvYmxhY2nDs24NCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxwb2JsYWNpw7NuLmpwZWcpDQoNCiMjIEluc3RhbGFyIHBhcXVldGVzIHkgbGxhbWFyIGxpYnJlcmlhcw0KYGBge3Igd2FybmluZz1GQUxTRX0NCiNpbnN0YWxsLnBhY2thZ2VzKCJmb3JlY2FzdCIpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KI2luc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCiNpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikNCmxpYnJhcnkoZ2dwbG90MikNCiNpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQojIyBJbXBvcnRhciBsYSBiYXNlIGRlIGRhdG9zDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0KI2ZpbGUuY2hvb3NlKCkNCnBvYmxhY2lvbiA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxEaWVnbyBQw6lyZXpcXERvd25sb2Fkc1xccG9wdWxhdGlvbi5jc3YiKQ0KYGBgDQoNCiMjIEVudGVuZGVyIGxhIGJhc2UgZGUgZGF0b3MNCmBgYHtyIHdhcm5pbmc9RkFMU0V9DQpzdW1tYXJ5KHBvYmxhY2lvbikNCnN0cihwb2JsYWNpb24pDQpoZWFkKHBvYmxhY2lvbikNCmBgYA0KDQojIyBTZXJpZSBkZSB0aWVtcG8gZW4gVGV4YXMNCmBgYHtyfQ0KcG9ibGFjaW9uX3RleGFzIDwtIHBvYmxhY2lvbiAlPiUgZmlsdGVyKHN0YXRlID09IlRYIikNCmdncGxvdChwb2JsYWNpb25fdGV4YXMsIGFlcyh4PXllYXIsIHk9cG9wdWxhdGlvbikpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHRpdGxlPSJQb2JsYWNpw7NuIGRlIFRleGFzIiwgeCA9IkHDsW8iLCB5PSJQb2JsYWNpw7NuIikNCnRzX3RleGFzIDwtIHRzKHBvYmxhY2lvbl90ZXhhcyRwb3B1bGF0aW9uLCBzdGFydCA9IDE5MDAsIGZyZXF1ZW5jeT0xKSAjU2VyaWUgZGUgdGllbXBvIGFudWFsDQojdHNfdGV4YXMgPC0gdHMocG9ibGFjaW9uX3RleGFzJHBvcHVsYXRpb24sIHN0YXJ0ID0gYygxOTAwLCA0KSwgZnJlcXVlbmN5PTQpICNTZXJpZSBkZSB0aWVtcG8gdHJpbWVzdHJhbA0KI3RzX3RleGFzIDwtIHRzKHBvYmxhY2lvbl90ZXhhcyRwb3B1bGF0aW9uLCBzdGFydCA9IGMoMTkwMCwgOCksIGZyZXF1ZW5jeT0pICNTZXJpZSBkZSB0aWVtcG8gbWVuc3VhbA0KYXJpbWFfdGV4YXMgPC0gYXV0by5hcmltYSh0c190ZXhhcykNCnN1bW1hcnkoYXJpbWFfdGV4YXMpDQpwcm9ub3N0aWNvX3RleGFzIDwtIGZvcmVjYXN0KGFyaW1hX3RleGFzLCBsZXZlbD05NSwgaD0xMCkNCnByb25vc3RpY29fdGV4YXMNCnBsb3QocHJvbm9zdGljb190ZXhhcywgbWFpbiA9ICJQb2JsYWNpw7NuIGVuIFRleGFzIikNCmBgYA0KDQojIEVqZXJjaWNpbyBlbiBjbGFzZSBMdW5lcyAxNzogTUFQQQ0KDQohW10oQzpcXFVzZXJzXFxEaWVnbyBQw6lyZXpcXERvd25sb2Fkc1xcbWFwYWEuanBnKQ0KIyMgSW50YWxhciBwYXF1ZXRlcyB5IGxsYW1hciBsaWJyZXJpYXMNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoImZvcmVjYXN0IikNCmxpYnJhcnkoZm9yZWNhc3QpDQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KI2luc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KI2luc3RhbGwucGFja2FnZXMoImRwbHlyIikNCmxpYnJhcnkoZHBseXIpDQojaW5zdGFsbC5wYWNrYWdlcygibWFwcyIpDQpsaWJyYXJ5KG1hcHMpDQpgYGANCg0KIyMgSW1wb3J0YXIgbGEgYmFzZSBkZSBkYXRvcw0KYGBge3Igd2FybmluZz1GQUxTRX0NCiNmaWxlLmNob29zZSgpDQpwb2JsYWNpb24gPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xcRGllZ28gUMOpcmV6XFxEb3dubG9hZHNcXHBvcHVsYXRpb24uY3N2IikNCmBgYA0KDQojIyBFbnRlbmRlciBsYSBiYXNlIGRlIGRhdG9zDQpgYGB7ciB3YXJuaW5nPUZBTFNFfQ0Kc3VtbWFyeShwb2JsYWNpb24pDQpzdHIocG9ibGFjaW9uKQ0KaGVhZChwb2JsYWNpb24pDQpgYGANCg0KIyMgU2VyaWUgZGUgdGllbXBvIGVuIFRleGFzDQpgYGB7cn0NCnBvYmxhY2lvbl90ZXhhcyA8LSBwb2JsYWNpb24gJT4lIGZpbHRlcihzdGF0ZSA9PSJUWCIpDQpnZ3Bsb3QocG9ibGFjaW9uX3RleGFzLCBhZXMoeD15ZWFyLCB5PXBvcHVsYXRpb24pKSArDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh0aXRsZT0iUG9ibGFjacOzbiBkZSBUZXhhcyIsIHggPSJBw7FvIiwgeT0iUG9ibGFjacOzbiIpDQp0c190ZXhhcyA8LSB0cyhwb2JsYWNpb25fdGV4YXMkcG9wdWxhdGlvbiwgc3RhcnQgPSAxOTUwLCBmcmVxdWVuY3k9MSkgI1NlcmllIGRlIHRpZW1wbyBhbnVhbA0KI3RzX3RleGFzIDwtIHRzKHBvYmxhY2lvbl90ZXhhcyRwb3B1bGF0aW9uLCBzdGFydCA9IGMoMTkwMCwgNCksIGZyZXF1ZW5jeT00KSAjU2VyaWUgZGUgdGllbXBvIHRyaW1lc3RyYWwNCiN0c190ZXhhcyA8LSB0cyhwb2JsYWNpb25fdGV4YXMkcG9wdWxhdGlvbiwgc3RhcnQgPSBjKDE5MDAsIDgpLCBmcmVxdWVuY3k9KSAjU2VyaWUgZGUgdGllbXBvIG1lbnN1YWwNCmFyaW1hX3RleGFzIDwtIGF1dG8uYXJpbWEodHNfdGV4YXMpDQpzdW1tYXJ5KGFyaW1hX3RleGFzKQ0KcHJvbm9zdGljb190ZXhhcyA8LSBmb3JlY2FzdChhcmltYV90ZXhhcywgbGV2ZWw9OTUsIGg9MTApDQpwcm9ub3N0aWNvX3RleGFzDQpwbG90KHByb25vc3RpY29fdGV4YXMsIG1haW4gPSAiUG9ibGFjacOzbiBlbiBUZXhhcyIpDQpgYGANCg0KIyMgQ3JlYXIgdW4gbWFwYQ0KYGBge3J9DQoNCm1hcChkYXRhYmFzZSA9ICJzdGF0ZSIpDQptYXAoZGF0YWJhc2U9InN0YXRlIiwgcmVnaW9ucyA9ICJUZXhhcyIsIGNvbD0icmVkIiwgZmlsbCA9IFRSVUUsIGFkZCA9IFRSVUUpIA0KbWFwKGRhdGFiYXNlPSJzdGF0ZSIsIHJlZ2lvbnMgPSAiTmV3IFlvcmsiLCBjb2w9ImdyZWVuIiwgZmlsbCA9IFRSVUUsIGFkZCA9IFRSVUUpDQpgYGANCg0KIyBBY3RpdmlkYWQgQ3JlYXIgdW4gTWFwYSANCiFbXShDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxtYXBhLmpwZykNCg0KQ3JlYXIgdW4gbWFwYSBkZSBFVUEgcG9yIGTDqWNhZGEsIGNvbiB1biBncmFkaWVudGUgdmVyZGUtcm9qbyBkZSBsYSBwb2JsYWNpw7NuIHBvciBlc3RhZG8sIGRlc2RlIDE5NTAgaGFzdGEgMjA1MA0KDQojIyBJbnN0YWxhciB5IGNhcmdhciBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzIHBhcmEgYW7DoWxpc2lzIHkgdmlzdWFsaXphY2nDs24NCmBgYHtyfQ0KIyBpbnN0YWxsLnBhY2thZ2VzKGMoImRwbHlyIiwgImdncGxvdDIiLCAiZm9yZWNhc3QiLCAibWFwcyIpKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZm9yZWNhc3QpDQpsaWJyYXJ5KG1hcHMpDQpgYGANCg0KIyMgSW1wb3J0YXIgbGEgYmFzZSBkZSBkYXRvcyBkZSBwb2JsYWNpw7NuIA0KYGBge3J9DQpwb2JsYWNpb24gPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xcRGllZ28gUMOpcmV6XFxEb3dubG9hZHNcXHBvcHVsYXRpb24uY3N2IikNCmBgYA0KDQojIyBQcm95ZWN0YXIgbGEgcG9ibGFjacOzbiBlc3RhdGFsIGhhc3RhIDIwNTAgeSBjb21iaW5hciBjb24gZGF0b3Mgb3JpZ2luYWxlcw0KYGBge3J9DQojIEludGVncmFjacOzbiBkZSBwcm9uw7NzdGljb3MgY29uIGxhIGJhc2UgZGUgZGF0b3MgaW5pY2lhbA0KIyBDcmVhciB1biBkYXRhc2V0IGFtcGxpYWRvIHF1ZSBwYXJ0ZSBkZSBsYSBiYXNlIGRlIGRhdG9zIG9yaWdpbmFsDQpwb2JsYWNpb25fZXh0ZW5kaWRhIDwtIHBvYmxhY2lvbg0KDQojIEV4dHJhZXIgbGEgbGlzdGEgZGUgZXN0YWRvcyDDum5pY29zIHByZXNlbnRlcyBlbiBsb3MgZGF0b3MNCmVzdGFkb3MgPC0gdW5pcXVlKHBvYmxhY2lvbiRzdGF0ZSkNCmBgYA0KDQoNCmBgYHtyfQ0KIyBNb2RlbGFyIHkgcHJvbm9zdGljYXIgbGEgcG9ibGFjacOzbiBkZSBjYWRhIGVzdGFkbyBoYXN0YSBlbCBhw7FvIDIwNTANCmZvcihzdCBpbiBlc3RhZG9zKXsNCiAgDQogICMgRmlsdHJhciB5IG9yZ2FuaXphciBsb3MgZGF0b3MgcG9yIGHDsW8gcGFyYSBjYWRhIGVzdGFkbw0KICBkYXRvc19zdCA8LSBwb2JsYWNpb24gJT4lDQogICAgZmlsdGVyKHN0YXRlID09IHN0KSAlPiUNCiAgICBhcnJhbmdlKHllYXIpDQogIA0KICAjIElkZW50aWZpY2FyIGVsIMO6bHRpbW8gYcOxbyBkaXNwb25pYmxlIGVuIGxhIHNlcmllIGhpc3TDs3JpY2ENCiAgdWx0aW1vX2FuaW8gPC0gbWF4KGRhdG9zX3N0JHllYXIpDQogIA0KICAjIEdlbmVyYXIgbGEgc2VyaWUgZGUgdGllbXBvIGFudWFsIHBhcmEgbGEgcG9ibGFjacOzbiBkZWwgZXN0YWRvDQogIHRzX3N0IDwtIHRzKGRhdG9zX3N0JHBvcHVsYXRpb24sDQogICAgICAgICAgICAgIHN0YXJ0ID0gbWluKGRhdG9zX3N0JHllYXIpLA0KICAgICAgICAgICAgICBlbmQgICA9IHVsdGltb19hbmlvLA0KICAgICAgICAgICAgICBmcmVxdWVuY3kgPSAxKSAgIyBEYXRvcyBhbnVhbGVzDQogIA0KICAjIEFqdXN0YXIgdW4gbW9kZWxvIEFSSU1BIGRlIG1hbmVyYSBhdXRvbcOhdGljYSBwYXJhIGVsIGVzdGFkbw0KICBtb2RlbG9fc3QgPC0gYXV0by5hcmltYSh0c19zdCkNCiAgDQogICMgQ2FsY3VsYXIgZWwgaG9yaXpvbnRlIGRlIHByb27Ds3N0aWNvIG5lY2VzYXJpbw0KICAjIChzZSBnZW5lcmEgZm9yZWNhc3Qgc29sbyBzaSBmYWx0YW4gYcOxb3MgcGFyYSBsbGVnYXIgYSAyMDUwKQ0KICBoX3llYXJzIDwtIDIwNTAgLSB1bHRpbW9fYW5pbw0KICANCiAgaWYoaF95ZWFycyA+IDApew0KICAgICMgR2VuZXJhciBlbCBwcm9uw7NzdGljbyBwYXJhIGVsIHBlcmlvZG8gZmFsdGFudGUNCiAgICBwcm9ub3N0aWNvIDwtIGZvcmVjYXN0KG1vZGVsb19zdCwgaCA9IGhfeWVhcnMpDQogICAgDQogICAgIyBDcmVhciB1biBkYXRhZnJhbWUgY29uIGxhcyBwcm95ZWNjaW9uZXMgZ2VuZXJhZGFzDQogICAgYW5pb3NfcHJvbm9zdGljbyA8LSAodWx0aW1vX2FuaW8gKyAxKToyMDUwDQogICAgcG9ibGFjaW9uX3Byb25vc3RpY2FkYSA8LSBhcy5udW1lcmljKHByb25vc3RpY28kbWVhbikNCiAgICANCiAgICBkZl9mb3JlY2FzdCA8LSBkYXRhLmZyYW1lKA0KICAgICAgc3RhdGUgPSBzdCwNCiAgICAgIHllYXIgID0gYW5pb3NfcHJvbm9zdGljbywNCiAgICAgIHBvcHVsYXRpb24gPSBwb2JsYWNpb25fcHJvbm9zdGljYWRhDQogICAgKQ0KICAgIA0KICAgICMgSW5jb3Jwb3JhciBsYXMgcHJveWVjY2lvbmVzIGFsIGRhdGFzZXQgZXh0ZW5kaWRvDQogICAgcG9ibGFjaW9uX2V4dGVuZGlkYSA8LSByYmluZChwb2JsYWNpb25fZXh0ZW5kaWRhLCBkZl9mb3JlY2FzdCkNCiAgfQ0KfQ0KYGBgDQoNCiMjIERlZmluaXIgdW5hIGZ1bmNpw7NuIHBhcmEgdmlzdWFsaXphciBlbCBtYXBhIGRlIHBvYmxhY2nDs24gcG9yIGHDsW8gDQpgYGB7cn0NCnBsb3RfbWFwIDwtIGZ1bmN0aW9uKHllYXIpIHsNCiAgDQogICMgRmlsdHJhciBlbCBkYXRhc2V0IHBhcmEgZWwgYcOxbyBlc3BlY2lmaWNhZG8NCiAgZGF0YV95ZWFyIDwtIHBvYmxhY2lvbl9leHRlbmRpZGEgJT4lDQogICAgZmlsdGVyKHllYXIgPT0gISF5ZWFyKQ0KICANCiAgIyBDYXJnYXIgbGEgaW5mb3JtYWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxvcyBlc3RhZG9zIGRlIEVFLlVVLg0KICBzdGF0ZXNfbWFwIDwtIG1hcF9kYXRhKCJzdGF0ZSIpDQogIA0KICAjIFJlbGFjaW9uYXIgbGFzIGFicmV2aWF0dXJhcyBlc3RhdGFsZXMgY29uIGxvcyBub21icmVzIGNvbXBsZXRvcyBlbiBtaW7DunNjdWxhcw0KICAjIFV0aWxpemFuZG8gbG9zIHZlY3RvcmVzIGF1eGlsaWFyZXMgc3RhdGUuYWJiIHkgc3RhdGUubmFtZQ0KICBkYXRhX3llYXIgPC0gZGF0YV95ZWFyICU+JQ0KICAgIG11dGF0ZShyZWdpb24gPSB0b2xvd2VyKHN0YXRlLm5hbWVbbWF0Y2goc3RhdGUsIHN0YXRlLmFiYildKSkgJT4lDQogICAgcmlnaHRfam9pbihzdGF0ZXNfbWFwLCBieSA9ICJyZWdpb24iKQ0KICANCiAgIyBHZW5lcmFyIGVsIG1hcGEgdGVtw6F0aWNvIHBvciBwb2JsYWNpw7NuDQogIGdncGxvdChkYXRhX3llYXIsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IHBvcHVsYXRpb24pKSArDQogICAgZ2VvbV9wb2x5Z29uKGNvbG9yID0gImJsYWNrIikgKw0KICAgICMgQXBsaWNhciB1biBncmFkaWVudGUgZGUgY29sb3IgdmVyZGUgKGJham8pIGEgcm9qbyAoYWx0bykNCiAgICBzY2FsZV9maWxsX2dyYWRpZW50KA0KICAgICAgbG93ID0gImdyZWVuIiwgICAjIFJlcHJlc2VudGEgbGEgbWVub3IgcG9ibGFjacOzbg0KICAgICAgaGlnaCA9ICJyZWQiLCAgICAjIEluZGljYSBsYSBtYXlvciBwb2JsYWNpw7NuDQogICAgICBuYW1lID0gIlBvYmxhY2nDs24iDQogICAgKSArDQogICAgbGFicygNCiAgICAgIHRpdGxlID0gcGFzdGUoIlBvYmxhY2nDs24gcG9yIEVzdGFkbyBlbiIsIHllYXIpDQogICAgKSArDQogICAgdGhlbWVfdm9pZCgpICsNCiAgICB0aGVtZSgNCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIikNCiAgICApDQp9DQpgYGANCg0KIyMgVmlzdWFsaXphciBsYSBldm9sdWNpw7NuIGRlbW9ncsOhZmljYSBjYWRhIGTDqWNhZGEgKDE5NTAgLSAyMDUwKSANCmBgYHtyfQ0KZm9yKHllYXIgaW4gc2VxKDE5NTAsIDIwNTAsIGJ5ID0gMTApKSB7DQogIHByaW50KHBsb3RfbWFwKHllYXIpKQ0KfQ0KDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6YnJvd247Ij4gQWN0aXZpZGFkIDIuIExlY2hlIFNhYm9yaXphZGEgSGVyc2hleSdzPC9zcGFuPg0KIVtdKEM6XFxVc2Vyc1xcRGllZ28gUMOpcmV6XFxEb3dubG9hZHNcXEhlcnNoZXktTG9nby5wbmcpDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpicm93bjsiPkluc3RhbGFyIHBhcXVldGVzIHkgbGxhbWFyIGxpYnJlcmlhczwvc3Bhbj4NCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJmb3JlY2FzdCIpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmJyb3duOyI+SW1wb3J0YXIgbGEgYmFzZSBkZSBkYXRvczwvc3Bhbj4NCg0KYGBge3J9DQojZmlsZS5jaG9vc2UoKQ0KdmVudGFzIDwtIHJlYWQuY3N2KCJDOlxcVXNlcnNcXERpZWdvIFDDqXJlelxcRG93bmxvYWRzXFxWZW50YXNfSGlzdMOzcmljYXNfTGVjaGl0YXMuY3N2IikNCmBgYA0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6YnJvd247Ij4xLiBNb2RlbG8gQVVUTy5BUklNQTwvc3Bhbj4NCmBgYHtyfQ0KdHNfdmVudGFzIDwtIHRzKHZlbnRhcyRWZW50YXMsIHN0YXJ0ID0gYygyMDE3LCAxKSwgZnJlcXVlbmN5ID0gMTIpDQphdXRvcGxvdCh0c192ZW50YXMpKyBsYWJzKHRpdGxlPSAiVmVudGFzIGRlIGxlY2hlIHNhYm9yaXphZGEgSGVyc2hleSdzIiwgeD0iVGllbXBvIiwgeT0iTWlsZXMgZGUgZG9sYXJlcyIpDQphcmltYV92ZW50YXMgPC0gYXV0by5hcmltYSh0c192ZW50YXMpDQpzdW1tYXJ5KGFyaW1hX3ZlbnRhcykNCnByb25vc3RpY29fdmVudGFzIDwtIGZvcmVjYXN0KGFyaW1hX3ZlbnRhcywgbGV2ZWw9OTUsIGg9MTIpDQpwcm9ub3N0aWNvX3ZlbnRhcw0KYXV0b3Bsb3QocHJvbm9zdGljb192ZW50YXMpKyBsYWJzKHRpdGxlID0gIlByb25vc3RpY28gZGUgdmVudGFzIDIwMjAgZGUgbGVjaGUgU2FicG9vcml6YWRhIEhlcnNoZXkncyIsIHg9IlRpZW1wbyIsIHk9Ik1pbGVzIGRlIGRvbGFyZXMiKQ0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpicm93bjsiPjIuIE1vZGVsbyBSZWdyZXNpw7NuIExpbmVhbDwvc3Bhbj4NCmBgYHtyfQ0KdmVudGFzJG1lcyA8LSAxOjM2DQpyZWdyZXNpb25fdmVudGFzIDwtIGxtKFZlbnRhc35tZXMsIGRhdGE9IHZlbnRhcykNCnN1bW1hcnkocmVncmVzaW9uX3ZlbnRhcykNCnNpZ3VpZW50ZV9hbmlvIDwtIGRhdGEuZnJhbWUobWVzPTM3OjQ4KQ0KcHJlZGljY2lvbl9SZWdyZXNpb24gPC0gcHJlZGljdChyZWdyZXNpb25fdmVudGFzLCBzaWd1aWVudGVfYW5pbykNCnByZWRpY2Npb25fUmVncmVzaW9uDQpwbG90KHZlbnRhcyRtZXMsIHZlbnRhcyRWZW50YXMsIG1haW49IlByb25vc3RpY28gZGUgdmVudGFzIDIwMjAgZGUgbGVjaGUgU2Fib3JpemFkYSBIZXJzaGV5J3MiLCB4bGFiPSJUaWVtcG8iLCB5bGFiPSJNaWxlcyBkZSBkb2xhcmVzIikgKw0KYWJsaW5lKHJlZ3Jlc2lvbl92ZW50YXMsIGNvbD0iYmx1ZSIpICsNCnBvaW50cyhzaWd1aWVudGVfYW5pbyRtZXMsIHByZWRpY2Npb25fUmVncmVzaW9uLCBjb2w9InJlZCIpDQpwcmVkaWNjaW9uX3JlYWxlcyA8LSBwcmVkaWN0KHJlZ3Jlc2lvbl92ZW50YXMsIHZlbnRhcykNCk1BUEUgPC0gbWVhbihhYnMoKHZlbnRhcyRWZW50YXMgLSANCiAgICAgICAgICAgICAgICAgICBwcmVkaWNjaW9uX3JlYWxlcykvdmVudGFzJFZlbnRhcykpKjEwMA0KTUFQRQ0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpicm93bjsiPjMuIENvbmNsdXNpw7NuPC9zcGFuPg0KRWwgbWVqb3IgbW9kZWxvIHF1ZSBzZSBhZGFwdGEgYSBsYSBzZXJpZSBlcyBlbCAqKlNBUklNQSoqIGNvbiB1biBNQVBFIGRlIDAuNzAsIGNvbXBhcmFkbyBjb24gbGEgUmVncmVzacOzbiBMaW5lYWwgcXVlIHN1IE1BUEUgZXMgZGUgMi4wMSUuDQoNClBhcmEgZWwgc2lndWllbnRlIGHDsW8sIGxhIHByb3llY2Npw7NuIGRlIHZlbnRhcyBlcyBsYSBzaWd1aWVudGU6ICANCg0KfCBNZXMgeSBBw7FvIHwgRXNjZW5hcmlvIEVzcGVyYWRvIHwgRXNjZW5hcmlvIFBlc2ltaXN0YSB8IEVzY2VuYXJpbyBPcHRpbWlzdGEgfCAgDQp8IC0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0tLS0tLSB8IC0tLS0tLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLS0tLS0tLS0tIHwgIA0KfCBKYW4gMjAyMCB8IDM1NDk4LjkwIHwgMzQ2MTYuNDggfCAzNjM4MS4zMiB8ICANCnwgRmViIDIwMjAgfCAzNDIwMi4xNyB8IDMzMTU1LjI4IHwgMzUyNDkuMDUgfCAgDQp8IE1hciAyMDIwIHwgMzY3MDMuMDEgfCAzNTU5Ni4xMCB8IDM3ODA5LjkyIHwgIA0KfCBBcHIgMjAyMCB8IDM2MjcxLjkwIHwgMzUxNDEuNDQgfCAzNzQwMi4zNgl8ICANCnwgTWF5IDIwMjAgfCAzNzEyMS45OCB8IDM1OTgyLjA3IHwgMzgyNjEuOTAJfCAgDQp8IEp1biAyMDIwIHwgMzcxMDIuNjUgfCAzNTk1OC45MCB8IDM4MjQ2LjQwCXwgIA0KfCBKdWwgMjAyMCB8IDM3MTUxLjA0IHwgMzYwMDUuNzMgfCAzODI5Ni4zNAl8ICANCnwgQXVnIDIwMjAgfCAzODU2NC42NCB8IDM3NDE4LjcwIHwgMzk3MTAuNTgJfCAgDQp8IFNlcCAyMDIwIHwgMzg3NTUuMjIgfCAzNzYwOS4wMyB8IDM5OTAxLjQyCXwgIA0KfCBPY3QgMjAyMCB8IDM5Nzc5LjAyIHwgMzg2MzIuNzIgfCA0MDkyNS4zMgl8ICANCnwgTm92IDIwMjAgfCAzODc0MS42MyB8IDM3NTk1LjI4IHwgMzk4ODcuOTcJfCAgDQp8IERlYyAyMDIwIHwgMzg2NDUuODYgfCAzNzQ5OS41MCB8IDM5NzkyLjIyCXwgIA0KDQpgYGB7cn0NCnZlbnRhc19wb3JfYW5pbyA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxEaWVnbyBQw6lyZXpcXERvd25sb2Fkc1xcdmVudGFzX3Bvcl9hbmlvLmNzdiIpDQpnZ3Bsb3QodmVudGFzX3Bvcl9hbmlvLCBhZXMoeD1tZXMsIHk9dmVudGFzLCANCiAgY29sPWFzLmZhY3RvcihhbmlvKSwgZ3JvdXAgPSBhbmlvKSkrDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh0aXRsZSA9ICIgVmVudGFzIGRlIExlY2hlIFNhYm9yaXphZGEgSGVyc2hleSdzIHBvciBBw7FvIiwgeCA9ICJNZXMiLCB5PSAiTWlsZXMgZGUgZG9sYXJlcyIpDQpgYGANCg0KTnVlc3RyYSByZWNvbWVuZGFjacOzbiBzZXLDrWEgcmVhbGl6YXIgY2FtcGHDsWFzIHB1YmxpY2l0YXJpYXMgcGFyYSBhdW1lbnRhciBlbCBjb25zdW1vIGRlIGxlY2hlIHNhYm9yaXphZGEgSGVyc2hleSdzIGVuIGVsIHByaW1lciBzZW1lc3RyZSBkZWwgYcOxbw==