Instalar paquetes y llamar libreria

library(forecast)
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.0     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ 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
#file.choose()
poblacion <- read.csv("/Users/jenaromtzg/Desktop/Generación de Escenarios Futuros/R/Semana 2/population.csv")
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
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) - TRIMESTRAL
## ts_texas <- ts(poblacion_texas$population start = c(1900, 8), frequency=12) - 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=50)
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
## 2030       33482027 31894047 35070007
## 2031       33890382 32143561 35637204
## 2032       34298738 32388674 36208801
## 2033       34707093 32629456 36784730
## 2034       35115449 32865983 37364914
## 2035       35523804 33098330 37949278
## 2036       35932160 33326573 38537746
## 2037       36340515 33550788 39130242
## 2038       36748871 33771046 39726695
## 2039       37157226 33987418 40327034
## 2040       37565581 34199972 40931191
## 2041       37973937 34408774 41539100
## 2042       38382292 34613887 42150698
## 2043       38790648 34815371 42765925
## 2044       39199003 35013284 43384723
## 2045       39607359 35207682 44007036
## 2046       40015714 35398618 44632810
## 2047       40424070 35586145 45261995
## 2048       40832425 35770311 45894540
## 2049       41240781 35951163 46530399
## 2050       41649136 36128748 47169524
## 2051       42057492 36303110 47811874
## 2052       42465847 36474290 48457405
## 2053       42874203 36642330 49106076
## 2054       43282558 36807269 49757848
## 2055       43690914 36969145 50412683
## 2056       44099269 37127994 51070544
## 2057       44507625 37283853 51731396
## 2058       44915980 37436755 52395205
## 2059       45324336 37586734 53061937
## 2060       45732691 37733822 53731560
## 2061       46141047 37878050 54404044
## 2062       46549402 38019447 55079357
## 2063       46957758 38158044 55757471
## 2064       47366113 38293868 56438358
## 2065       47774469 38426948 57121989
## 2066       48182824 38557310 57808338
## 2067       48591180 38684979 58497380
## 2068       48999535 38809982 59189088
## 2069       49407891 38932343 59883438
plot(pronostico_texas, main="Poblacion en Texas")

Ejercicio en Clase Lunes 17: Mapa

library(forecast)
library(tidyverse)
library(ggplot2)
library(maps)
## 
## Attaching package: 'maps'
## The following object is masked from 'package:purrr':
## 
##     map
#file.choose()
poblacion <- read.csv("/Users/jenaromtzg/Desktop/Generación de Escenarios Futuros/R/Semana 2/population.csv")
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
# Crear un mapa de EUA por década, con un gradiente verde-rojo de la poblacion por estado, desde 1900, hasta el 2100
map(database="state")
map(database="state", regions = "New York", col = "green", fill = TRUE, add = TRUE)
map(database="state", regions = "Texas", col = "red", fill = TRUE, add = TRUE)
title(main = "Pronóstico de Población en EE.UU.")

Generar Pronostico por Cada Estado

# Suponiendo que en 'poblacion' tienes columnas:
# state (abreviatura, ej. "TX"), year (año), population (valor)
poblacion_extended <- poblacion %>%
  group_by(state) %>%
  arrange(year) %>%
  # Para cada estado, creamos un df con valores observados + pronóstico
  do({
    df <- .
    # Años mínimos y máximos en tus datos
    min_year <- min(df$year)
    max_year <- max(df$year)
    
    # Creamos la serie de tiempo anual
    ts_pop <- ts(df$population, start = min_year, frequency = 1)
    
    # Determinamos cuántos años faltan para llegar a 2050
    horizon <- 2050 - max_year
    
    # Si el dataset llega hasta antes de 2050, hacemos forecast
    if(horizon > 0){
      fit <- auto.arima(ts_pop)
      fc <- forecast(fit, h = horizon)
      
      # Data frame con los datos pronosticados
      years_forecast <- (max_year + 1):2050
      df_forecast <- data.frame(
        state      = unique(df$state),
        year       = years_forecast,
        population = as.numeric(fc$mean)
      )
      
      # Unimos histórico + forecast
      df_all <- bind_rows(
        # Histórico (columnas relevantes)
        df %>% select(state, year, population),
        # Futuro
        df_forecast
      )
    } else {
      # Si ya tenemos datos hasta 2050 o más, no pronosticamos
      df_all <- df
    }
    
    df_all
  }) %>%
  ungroup()

Convertir abreviaturas de estado (p.ej., “TX”) a nombres completos

df_state_names <- data.frame(
  state_abb  = state.abb,
  state_name = tolower(state.name),
  stringsAsFactors = FALSE
)

poblacion_full <- poblacion_extended %>%
  left_join(df_state_names, by = c("state" = "state_abb"))

Unir la geometría de los estados con los datos de población

# 4.1) Obtenemos las coordenadas de polígonos con 'map_data("state")'
states_map <- map_data("state")

# 4.2) Hacemos left_join para heredar la columna 'population' (por estado y año)
map_data_joined <- states_map %>%
  left_join(poblacion_full, by = c("region" = "state_name"))
## Warning in left_join(., poblacion_full, by = c(region = "state_name")): Each row in `x` is expected to match at most 1 row in `y`.
## ℹ Row 1 of `x` matches multiple rows.
## ℹ If multiple matches are expected, set `multiple = "all"` to silence this
##   warning.

Filtrar décadas entre 1950 y 2050

map_data_decadas <- map_data_joined %>%
  mutate(year = as.numeric(year)) %>%
  filter(year >= 1950, year <= 2050, year %% 10 == 0)

Graficar con ggplot2 (rojo = población baja, verde = población alta)Filtrar décadas entre 1950 y 2050

ggplot(map_data_decadas, aes(x = long, 
                             y = lat, 
                             group = group, 
                             fill = population)) +
  geom_polygon(color = "black", size = 0.1) +
  # Gradiente de rojo (baja) a verde (alta)
  scale_fill_gradient(low = "red", high = "green", 
                      na.value = "grey90") +
  facet_wrap(~ year) +
  coord_fixed(1.3) +
  labs(title = "Población de EUA por Estado (1950 - 2050, por década)",
       fill = "Población estimada") +
  theme_void() +
  theme(legend.position = "right",
        strip.text = element_text(face = "bold"))
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Actividad 2. Leche saborizada Hershey’s

library(knitr)
library(kableExtra)
## 
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows
library(forecast)
library(tidyverse)
library(ggplot2)
#file.choose()
ventas <- read.csv("/Users/jenaromtzg/Desktop/Generación de Escenarios Futuros/R/Semana 2/Ventas_Históricas_Lechitas.csv")

Modelo 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.8980
## s.e.  0.1551   0.2047   14.5026
## 
## sigma^2 = 202700:  log likelihood = -181.5
## AIC=371   AICc=373.11   BIC=375.72
## 
## Training set error measures:
##                    ME    RMSE      MAE        MPE      MAPE       MASE
## Training set 25.22163 343.863 227.1699 0.08059942 0.7069541 0.06491041
##                   ACF1
## Training set 0.2081043
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.29 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.91 38246.40
## Jul 2020       37151.04 36005.74 38296.35
## Aug 2020       38564.65 37418.71 39710.59
## Sep 2020       38755.23 37609.03 39901.42
## Oct 2020       39779.03 38632.73 40925.33
## Nov 2020       38741.63 37595.29 39887.97
## Dec 2020       38645.86 37499.50 39792.22
autoplot(pronostico_ventas) + labs(title = "Pronostico de ventas 2020 de lecehe 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.41  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 20220 de leche saborizadas Hershey's", xlab = "Tiempo", ylab = "Miles de Dólares")
abline(regresion_ventas, col = "blue")
points(siguiente_anio$mes, prediccion_regresion, col = "red")

prediccion_reales <- predict(regresion_ventas, ventas)

MAPE <- mean(abs((ventas$Ventas - prediccion_reales)/ventas$Ventas))*100
MAPE
## [1] 2.011298
## El mejor modelo que se adapta a la serie es el SARIMA con un MAPE DE 0.71%, comparado con la de regresion lineal que su MAPE es de 2.01%. Para el siguiente año, la proyección de ventas es la siguiente:

tabla <- data.frame(
  `Mes y Año` = c("Jan 2020", "Feb 2020", "Mar 2020", "Apr 2020", "May 2020",
                  "Jun 2020", "Jul 2020", "Aug 2020", "Sep 2020", "Oct 2020"),
  Esperado = c(35498.90, 34202.17, 36703.01, 36271.90, 37121.98, 
               37102.65, 37151.04, 38564.64, 38755.22, 39779.02),
  Pesimista = c(34616.48, 33155.28, 35596.10, 35141.44, 35982.07, 
                35958.90, 36005.73, 37418.70, 37609.03, 38632.72),
  Optimista = c(36381.32, 35249.05, 37809.92, 37402.36, 38261.90, 
                38246.40, 38296.34, 39710.58, 39901.42, 40925.32)
)

# Generar tabla con kable
tabla %>%
  kable("html", caption = "Proyección Financiera 2020") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
Proyección Financiera 2020
Mes.y.Año Esperado Pesimista 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
#file.choose()
ventas_por_anio <- read.csv("/Users/jenaromtzg/Desktop/Generación de Escenarios Futuros/R/Semana 2/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="Ventas",y="Miles de Dólares")

## Nuestra recomendación seria realizar campañas publicitarias para aumentar el consumo de leches saborizadas Hershey’s en el primer semestre del año.
LS0tCnRpdGxlOiAiQWN0IDIgLSBHRUZBIgphdXRob3I6ICJKZW5hcm8gTWFydMOtbmV6IEEwMTcyMTk1MSIKZGF0ZTogIjIwMjUtMDItMTciCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogVFJVRQogICAgdG9jX2Zsb2F0OiBUUlVFCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFCiAgICB0aGVtZTogY2VydWxlYW4KLS0tCgoKIyMgSW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyaWEKYGBge3J9CmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCmBgYHtyfQojZmlsZS5jaG9vc2UoKQpwb2JsYWNpb24gPC0gcmVhZC5jc3YoIi9Vc2Vycy9qZW5hcm9tdHpnL0Rlc2t0b3AvR2VuZXJhY2lvzIFuIGRlIEVzY2VuYXJpb3MgRnV0dXJvcy9SL1NlbWFuYSAyL3BvcHVsYXRpb24uY3N2IikKCmBgYAoKYGBge3J9CnN1bW1hcnkocG9ibGFjaW9uKQpzdHIocG9ibGFjaW9uKQpoZWFkKHBvYmxhY2lvbikKYGBgCgpgYGB7cn0KcG9ibGFjaW9uX3RleGFzIDwtIHBvYmxhY2lvbiAlPiUgZmlsdGVyKHN0YXRlPT0iVFgiKQpnZ3Bsb3QocG9ibGFjaW9uX3RleGFzLCBhZXMoeD15ZWFyLCB5PXBvcHVsYXRpb24pKSArIGdlb21fbGluZSgpICsKICBsYWJzKHRpdGxlPSJQb2JsYWNpw7NuIGRlIFRleGFzIiwgeCA9ICJBw7FvIiwgCiAgICAgICB5ID0iUG9ibGFjacOzbiIpCgp0c190ZXhhcyA8LSB0cyhwb2JsYWNpb25fdGV4YXMkcG9wdWxhdGlvbiwgc3RhcnQgPSAxOTAwLCBmcmVxdWVuY3k9MSkKCiMgU2VyaWUgZGUgdGllbXBvIGFudWFsCiMjIHRzX3RleGFzIDwtIHRzKHBvYmxhY2lvbl90ZXhhcyRwb3B1bGF0aW9uIHN0YXJ0ID0gYygxOTAwLCA0KSwgZnJlcXVlbmN5PTQpIC0gVFJJTUVTVFJBTAojIyB0c190ZXhhcyA8LSB0cyhwb2JsYWNpb25fdGV4YXMkcG9wdWxhdGlvbiBzdGFydCA9IGMoMTkwMCwgOCksIGZyZXF1ZW5jeT0xMikgLSBNRU5TVUFMCgoKYXJpbWFfdGV4YXMgPC0gYXV0by5hcmltYSh0c190ZXhhcykKc3VtbWFyeShhcmltYV90ZXhhcykKCnByb25vc3RpY29fdGV4YXMgPC0gZm9yZWNhc3QoYXJpbWFfdGV4YXMsIGxldmVsPTk1LCBoPTUwKQpwcm9ub3N0aWNvX3RleGFzCnBsb3QocHJvbm9zdGljb190ZXhhcywgbWFpbj0iUG9ibGFjaW9uIGVuIFRleGFzIikKYGBgCgojIEVqZXJjaWNpbyBlbiBDbGFzZSBMdW5lcyAxNzogTWFwYQoKYGBge3J9CmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkobWFwcykKYGBgCgpgYGB7cn0KI2ZpbGUuY2hvb3NlKCkKcG9ibGFjaW9uIDwtIHJlYWQuY3N2KCIvVXNlcnMvamVuYXJvbXR6Zy9EZXNrdG9wL0dlbmVyYWNpb8yBbiBkZSBFc2NlbmFyaW9zIEZ1dHVyb3MvUi9TZW1hbmEgMi9wb3B1bGF0aW9uLmNzdiIpCmBgYAoKYGBge3J9CnN1bW1hcnkocG9ibGFjaW9uKQpzdHIocG9ibGFjaW9uKQpoZWFkKHBvYmxhY2lvbikKYGBgCgpgYGB7cn0KIyBDcmVhciB1biBtYXBhIGRlIEVVQSBwb3IgZMOpY2FkYSwgY29uIHVuIGdyYWRpZW50ZSB2ZXJkZS1yb2pvIGRlIGxhIHBvYmxhY2lvbiBwb3IgZXN0YWRvLCBkZXNkZSAxOTAwLCBoYXN0YSBlbCAyMTAwCm1hcChkYXRhYmFzZT0ic3RhdGUiKQptYXAoZGF0YWJhc2U9InN0YXRlIiwgcmVnaW9ucyA9ICJOZXcgWW9yayIsIGNvbCA9ICJncmVlbiIsIGZpbGwgPSBUUlVFLCBhZGQgPSBUUlVFKQptYXAoZGF0YWJhc2U9InN0YXRlIiwgcmVnaW9ucyA9ICJUZXhhcyIsIGNvbCA9ICJyZWQiLCBmaWxsID0gVFJVRSwgYWRkID0gVFJVRSkKdGl0bGUobWFpbiA9ICJQcm9uw7NzdGljbyBkZSBQb2JsYWNpw7NuIGVuIEVFLlVVLiIpCmBgYAoKCiMjIEdlbmVyYXIgUHJvbm9zdGljbyBwb3IgQ2FkYSBFc3RhZG8KYGBge3J9CgojIFN1cG9uaWVuZG8gcXVlIGVuICdwb2JsYWNpb24nIHRpZW5lcyBjb2x1bW5hczoKIyBzdGF0ZSAoYWJyZXZpYXR1cmEsIGVqLiAiVFgiKSwgeWVhciAoYcOxbyksIHBvcHVsYXRpb24gKHZhbG9yKQpwb2JsYWNpb25fZXh0ZW5kZWQgPC0gcG9ibGFjaW9uICU+JQogIGdyb3VwX2J5KHN0YXRlKSAlPiUKICBhcnJhbmdlKHllYXIpICU+JQogICMgUGFyYSBjYWRhIGVzdGFkbywgY3JlYW1vcyB1biBkZiBjb24gdmFsb3JlcyBvYnNlcnZhZG9zICsgcHJvbsOzc3RpY28KICBkbyh7CiAgICBkZiA8LSAuCiAgICAjIEHDsW9zIG3DrW5pbW9zIHkgbcOheGltb3MgZW4gdHVzIGRhdG9zCiAgICBtaW5feWVhciA8LSBtaW4oZGYkeWVhcikKICAgIG1heF95ZWFyIDwtIG1heChkZiR5ZWFyKQogICAgCiAgICAjIENyZWFtb3MgbGEgc2VyaWUgZGUgdGllbXBvIGFudWFsCiAgICB0c19wb3AgPC0gdHMoZGYkcG9wdWxhdGlvbiwgc3RhcnQgPSBtaW5feWVhciwgZnJlcXVlbmN5ID0gMSkKICAgIAogICAgIyBEZXRlcm1pbmFtb3MgY3XDoW50b3MgYcOxb3MgZmFsdGFuIHBhcmEgbGxlZ2FyIGEgMjA1MAogICAgaG9yaXpvbiA8LSAyMDUwIC0gbWF4X3llYXIKICAgIAogICAgIyBTaSBlbCBkYXRhc2V0IGxsZWdhIGhhc3RhIGFudGVzIGRlIDIwNTAsIGhhY2Vtb3MgZm9yZWNhc3QKICAgIGlmKGhvcml6b24gPiAwKXsKICAgICAgZml0IDwtIGF1dG8uYXJpbWEodHNfcG9wKQogICAgICBmYyA8LSBmb3JlY2FzdChmaXQsIGggPSBob3Jpem9uKQogICAgICAKICAgICAgIyBEYXRhIGZyYW1lIGNvbiBsb3MgZGF0b3MgcHJvbm9zdGljYWRvcwogICAgICB5ZWFyc19mb3JlY2FzdCA8LSAobWF4X3llYXIgKyAxKToyMDUwCiAgICAgIGRmX2ZvcmVjYXN0IDwtIGRhdGEuZnJhbWUoCiAgICAgICAgc3RhdGUgICAgICA9IHVuaXF1ZShkZiRzdGF0ZSksCiAgICAgICAgeWVhciAgICAgICA9IHllYXJzX2ZvcmVjYXN0LAogICAgICAgIHBvcHVsYXRpb24gPSBhcy5udW1lcmljKGZjJG1lYW4pCiAgICAgICkKICAgICAgCiAgICAgICMgVW5pbW9zIGhpc3TDs3JpY28gKyBmb3JlY2FzdAogICAgICBkZl9hbGwgPC0gYmluZF9yb3dzKAogICAgICAgICMgSGlzdMOzcmljbyAoY29sdW1uYXMgcmVsZXZhbnRlcykKICAgICAgICBkZiAlPiUgc2VsZWN0KHN0YXRlLCB5ZWFyLCBwb3B1bGF0aW9uKSwKICAgICAgICAjIEZ1dHVybwogICAgICAgIGRmX2ZvcmVjYXN0CiAgICAgICkKICAgIH0gZWxzZSB7CiAgICAgICMgU2kgeWEgdGVuZW1vcyBkYXRvcyBoYXN0YSAyMDUwIG8gbcOhcywgbm8gcHJvbm9zdGljYW1vcwogICAgICBkZl9hbGwgPC0gZGYKICAgIH0KICAgIAogICAgZGZfYWxsCiAgfSkgJT4lCiAgdW5ncm91cCgpCgpgYGAKCiMjIENvbnZlcnRpciBhYnJldmlhdHVyYXMgZGUgZXN0YWRvIChwLmVqLiwgIlRYIikgYSBub21icmVzIGNvbXBsZXRvcwpgYGB7cn0KZGZfc3RhdGVfbmFtZXMgPC0gZGF0YS5mcmFtZSgKICBzdGF0ZV9hYmIgID0gc3RhdGUuYWJiLAogIHN0YXRlX25hbWUgPSB0b2xvd2VyKHN0YXRlLm5hbWUpLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQopCgpwb2JsYWNpb25fZnVsbCA8LSBwb2JsYWNpb25fZXh0ZW5kZWQgJT4lCiAgbGVmdF9qb2luKGRmX3N0YXRlX25hbWVzLCBieSA9IGMoInN0YXRlIiA9ICJzdGF0ZV9hYmIiKSkKCmBgYAoKIyMgVW5pciBsYSBnZW9tZXRyw61hIGRlIGxvcyBlc3RhZG9zIGNvbiBsb3MgZGF0b3MgZGUgcG9ibGFjacOzbgpgYGB7cn0KIyA0LjEpIE9idGVuZW1vcyBsYXMgY29vcmRlbmFkYXMgZGUgcG9sw61nb25vcyBjb24gJ21hcF9kYXRhKCJzdGF0ZSIpJwpzdGF0ZXNfbWFwIDwtIG1hcF9kYXRhKCJzdGF0ZSIpCgojIDQuMikgSGFjZW1vcyBsZWZ0X2pvaW4gcGFyYSBoZXJlZGFyIGxhIGNvbHVtbmEgJ3BvcHVsYXRpb24nIChwb3IgZXN0YWRvIHkgYcOxbykKbWFwX2RhdGFfam9pbmVkIDwtIHN0YXRlc19tYXAgJT4lCiAgbGVmdF9qb2luKHBvYmxhY2lvbl9mdWxsLCBieSA9IGMoInJlZ2lvbiIgPSAic3RhdGVfbmFtZSIpKQoKYGBgCiMjIEZpbHRyYXIgZMOpY2FkYXMgZW50cmUgMTk1MCB5IDIwNTAKYGBge3J9Cm1hcF9kYXRhX2RlY2FkYXMgPC0gbWFwX2RhdGFfam9pbmVkICU+JQogIG11dGF0ZSh5ZWFyID0gYXMubnVtZXJpYyh5ZWFyKSkgJT4lCiAgZmlsdGVyKHllYXIgPj0gMTk1MCwgeWVhciA8PSAyMDUwLCB5ZWFyICUlIDEwID09IDApCgpgYGAKCiMjIEdyYWZpY2FyIGNvbiBnZ3Bsb3QyIChyb2pvID0gcG9ibGFjacOzbiBiYWphLCB2ZXJkZSA9IHBvYmxhY2nDs24gYWx0YSlGaWx0cmFyIGTDqWNhZGFzIGVudHJlIDE5NTAgeSAyMDUwCmBgYHtyfQpnZ3Bsb3QobWFwX2RhdGFfZGVjYWRhcywgYWVzKHggPSBsb25nLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbGF0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGdyb3VwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gcG9wdWxhdGlvbikpICsKICBnZW9tX3BvbHlnb24oY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4xKSArCiAgIyBHcmFkaWVudGUgZGUgcm9qbyAoYmFqYSkgYSB2ZXJkZSAoYWx0YSkKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJyZWQiLCBoaWdoID0gImdyZWVuIiwgCiAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICJncmV5OTAiKSArCiAgZmFjZXRfd3JhcCh+IHllYXIpICsKICBjb29yZF9maXhlZCgxLjMpICsKICBsYWJzKHRpdGxlID0gIlBvYmxhY2nDs24gZGUgRVVBIHBvciBFc3RhZG8gKDE5NTAgLSAyMDUwLCBwb3IgZMOpY2FkYSkiLAogICAgICAgZmlsbCA9ICJQb2JsYWNpw7NuIGVzdGltYWRhIikgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKQoKYGBgCgoKIyMgQWN0aXZpZGFkIDIuIExlY2hlIHNhYm9yaXphZGEgSGVyc2hleeKAmXMKCmBgYHtyfQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoZm9yZWNhc3QpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKYGBge3J9CiNmaWxlLmNob29zZSgpCnZlbnRhcyA8LSByZWFkLmNzdigiL1VzZXJzL2plbmFyb210emcvRGVza3RvcC9HZW5lcmFjaW/MgW4gZGUgRXNjZW5hcmlvcyBGdXR1cm9zL1IvU2VtYW5hIDIvVmVudGFzX0hpc3RvzIFyaWNhc19MZWNoaXRhcy5jc3YiKQoKYGBgCgojIyBNb2RlbG8gQXJpbWEKYGBge3J9CnRzX3ZlbnRhcyA8LSB0cyh2ZW50YXMkVmVudGFzLHN0YXJ0PWMoMjAxNywxKSwgZnJlcXVlbmN5ID0gMTIpCmF1dG9wbG90KHRzX3ZlbnRhcykgKyBsYWJzKHRpdGxlID0gIlZlbnRhcyBkZSBsZWNoZSBzYWJvcml6YWRhIEhlcnNoZXkncyIsIHggPSAiVGllbXBvIiAsIHkgPSAiTWlsZXMgZGUgRMOzbGFyZXMiKQpgYGAKCmBgYHtyfQphcmltYV92ZW50YXMgPC0gYXV0by5hcmltYSh0c192ZW50YXMpCnN1bW1hcnkoYXJpbWFfdmVudGFzKQpgYGAKCmBgYHtyfQpwcm9ub3N0aWNvX3ZlbnRhcyA8LSBmb3JlY2FzdChhcmltYV92ZW50YXMsIGxldmVsPTk1LCBoID0gMTIpCnByb25vc3RpY29fdmVudGFzCmBgYApgYGB7cn0KYXV0b3Bsb3QocHJvbm9zdGljb192ZW50YXMpICsgbGFicyh0aXRsZSA9ICJQcm9ub3N0aWNvIGRlIHZlbnRhcyAyMDIwIGRlIGxlY2VoZSBzYWJvcml6YWRhIEhlcnNoZXkncyIsIHg9IlRpZW1wbyIsIHkgPSAiTWlsZXMgZGUgRMOzbGFyZXMiKQpgYGAKCiMjIE1vZGVsbyBkZSByZWdyZXNpw7NuIExpbmVhbApgYGB7cn0KdmVudGFzJG1lcyA8LSAxOjM2CnJlZ3Jlc2lvbl92ZW50YXMgPC0gbG0oVmVudGFzIH4gbWVzLCBkYXRhID0gdmVudGFzKQpzdW1tYXJ5KHJlZ3Jlc2lvbl92ZW50YXMpCgpzaWd1aWVudGVfYW5pbyA8LSBkYXRhLmZyYW1lKG1lcz0zNzo0OCkKcHJlZGljY2lvbl9yZWdyZXNpb24gPC0gcHJlZGljdChyZWdyZXNpb25fdmVudGFzLCBzaWd1aWVudGVfYW5pbykKcHJlZGljY2lvbl9yZWdyZXNpb24KYGBgCgpgYGB7cn0KcGxvdCh2ZW50YXMkbWVzLCB2ZW50YXMkVmVudGFzLCBtYWluID0gIlByb25vc3RpY28gZGUgVmVudGFzIDIwMjIwIGRlIGxlY2hlIHNhYm9yaXphZGFzIEhlcnNoZXkncyIsIHhsYWIgPSAiVGllbXBvIiwgeWxhYiA9ICJNaWxlcyBkZSBEw7NsYXJlcyIpCmFibGluZShyZWdyZXNpb25fdmVudGFzLCBjb2wgPSAiYmx1ZSIpCnBvaW50cyhzaWd1aWVudGVfYW5pbyRtZXMsIHByZWRpY2Npb25fcmVncmVzaW9uLCBjb2wgPSAicmVkIikKYGBgCgpgYGB7cn0KcHJlZGljY2lvbl9yZWFsZXMgPC0gcHJlZGljdChyZWdyZXNpb25fdmVudGFzLCB2ZW50YXMpCgpNQVBFIDwtIG1lYW4oYWJzKCh2ZW50YXMkVmVudGFzIC0gcHJlZGljY2lvbl9yZWFsZXMpL3ZlbnRhcyRWZW50YXMpKSoxMDAKTUFQRQpgYGAKCmBgYHtyfQojIyBFbCBtZWpvciBtb2RlbG8gcXVlIHNlIGFkYXB0YSBhIGxhIHNlcmllIGVzIGVsIFNBUklNQSBjb24gdW4gTUFQRSBERSAwLjcxJSwgY29tcGFyYWRvIGNvbiBsYSBkZSByZWdyZXNpb24gbGluZWFsIHF1ZSBzdSBNQVBFIGVzIGRlIDIuMDElLiBQYXJhIGVsIHNpZ3VpZW50ZSBhw7FvLCBsYSBwcm95ZWNjacOzbiBkZSB2ZW50YXMgZXMgbGEgc2lndWllbnRlOgoKdGFibGEgPC0gZGF0YS5mcmFtZSgKICBgTWVzIHkgQcOxb2AgPSBjKCJKYW4gMjAyMCIsICJGZWIgMjAyMCIsICJNYXIgMjAyMCIsICJBcHIgMjAyMCIsICJNYXkgMjAyMCIsCiAgICAgICAgICAgICAgICAgICJKdW4gMjAyMCIsICJKdWwgMjAyMCIsICJBdWcgMjAyMCIsICJTZXAgMjAyMCIsICJPY3QgMjAyMCIpLAogIEVzcGVyYWRvID0gYygzNTQ5OC45MCwgMzQyMDIuMTcsIDM2NzAzLjAxLCAzNjI3MS45MCwgMzcxMjEuOTgsIAogICAgICAgICAgICAgICAzNzEwMi42NSwgMzcxNTEuMDQsIDM4NTY0LjY0LCAzODc1NS4yMiwgMzk3NzkuMDIpLAogIFBlc2ltaXN0YSA9IGMoMzQ2MTYuNDgsIDMzMTU1LjI4LCAzNTU5Ni4xMCwgMzUxNDEuNDQsIDM1OTgyLjA3LCAKICAgICAgICAgICAgICAgIDM1OTU4LjkwLCAzNjAwNS43MywgMzc0MTguNzAsIDM3NjA5LjAzLCAzODYzMi43MiksCiAgT3B0aW1pc3RhID0gYygzNjM4MS4zMiwgMzUyNDkuMDUsIDM3ODA5LjkyLCAzNzQwMi4zNiwgMzgyNjEuOTAsIAogICAgICAgICAgICAgICAgMzgyNDYuNDAsIDM4Mjk2LjM0LCAzOTcxMC41OCwgMzk5MDEuNDIsIDQwOTI1LjMyKQopCgojIEdlbmVyYXIgdGFibGEgY29uIGthYmxlCnRhYmxhICU+JQogIGthYmxlKCJodG1sIiwgY2FwdGlvbiA9ICJQcm95ZWNjacOzbiBGaW5hbmNpZXJhIDIwMjAiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpCgpgYGAKCgoKCgoKYGBge3J9CiNmaWxlLmNob29zZSgpCnZlbnRhc19wb3JfYW5pbyA8LSByZWFkLmNzdigiL1VzZXJzL2plbmFyb210emcvRGVza3RvcC9HZW5lcmFjaW/MgW4gZGUgRXNjZW5hcmlvcyBGdXR1cm9zL1IvU2VtYW5hIDIvdmVudGFzX3Bvcl9hbmlvLmNzdiIpCgpnZ3Bsb3QodmVudGFzX3Bvcl9hbmlvLCBhZXMoeD1tZXMsIHk9dmVudGFzLCBjb2w9YXMuZmFjdG9yKGFuaW8pLGdyb3VwPWFuaW8pKSArIGdlb21fbGluZSgpICsgCiAgbGFicyh0aXRsZSA9ICJWZW50YXMgZGUgbGVjaGUgc2Fib3JpemFkYSBIZXJzaGV5J3MgcG9yIGHDsW8iLCB4PSJWZW50YXMiLHk9Ik1pbGVzIGRlIETDs2xhcmVzIikKCiMjIE51ZXN0cmEgcmVjb21lbmRhY2nDs24gc2VyaWEgcmVhbGl6YXIgY2FtcGHDsWFzIHB1YmxpY2l0YXJpYXMgcGFyYSBhdW1lbnRhciBlbCBjb25zdW1vIGRlIGxlY2hlcyBzYWJvcml6YWRhcyBIZXJzaGV54oCZcyBlbiBlbCBwcmltZXIgc2VtZXN0cmUgZGVsIGHDsW8uCgpgYGAKCgoKCgoKCgo=