Instalar paquetes y llamar librerías

# install.packages("readxl") # Leer documentos de excel
library(readxl)
# install.packages("tidyverse") # Manipulación de datos
library(tidyverse)
# install.packages("ggplot2") # Generar gráficos presentables
library(ggplot2)
# install.packages("forecast") # Generar series de tiempo y pronósticos
library(forecast)

Actividad Individual 2

Importar la base de datos

# file.choose()
df <- read_excel("C:\\Users\\spacanino\\Downloads\\R\\Datos Arca Continental Original.xlsx")

Revisar la estructura de los datos

str(df)
## tibble [466,509 × 25] (S3: tbl_df/tbl/data.frame)
##  $ ID                  : num [1:466509] 1 2 3 4 5 6 7 8 9 10 ...
##  $ Año                 : num [1:466509] 2016 2016 2016 2016 2016 ...
##  $ Territorio          : chr [1:466509] "Guadalajara" "Guadalajara" "Guadalajara" "Guadalajara" ...
##  $ Sub Territorio      : chr [1:466509] "Belenes" "Belenes" "Belenes" "Belenes" ...
##  $ CEDI                : chr [1:466509] "Suc. Belenes" "Suc. Belenes" "Suc. Belenes" "Suc. Belenes" ...
##  $ Cliente             : chr [1:466509] "77737" "77737" "77737" "77737" ...
##  $ Nombre              : chr [1:466509] "ABARR" "ABARR" "ABARR" "ABARR" ...
##  $ Tamaño Cte Industria: chr [1:466509] "Extra Grande" "Extra Grande" "Extra Grande" "Extra Grande" ...
##  $ Segmento Det        : chr [1:466509] "Agua Mineral" "Agua Purificada" "Agua Purificada" "Agua Saborizada" ...
##  $ Marca               : chr [1:466509] "Topo Chico A.M." "Ciel Agua Purificada" "Ciel Agua Purificada" "Ciel Exprim" ...
##  $ Presentacion        : chr [1:466509] "600 ml NR" "1 Ltro. N.R." "1.5 Lts. NR" "600 ml NR" ...
##  $ Tamaño              : chr [1:466509] "Individual" "Individual" "Individual" "Individual" ...
##  $ Retornable_NR       : chr [1:466509] "No Retornable" "No Retornable" "No Retornable" "No Retornable" ...
##  $ Enero               : num [1:466509] NA NA NA NA NA NA 1 NA 3 NA ...
##  $ Febrero             : num [1:466509] NA 2 NA NA NA NA NA 1 3 NA ...
##  $ Marzo               : num [1:466509] NA 8 3 NA NA 1 NA NA 4 NA ...
##  $ Abril               : num [1:466509] NA 4 6 NA NA NA NA 1 4 NA ...
##  $ Mayo                : num [1:466509] NA 4 3 NA NA NA 0 NA 4 NA ...
##  $ Junio               : num [1:466509] NA 2 3 NA NA NA NA 1 4 0 ...
##  $ Julio               : num [1:466509] NA 2 3 NA NA NA 0 NA 4 NA ...
##  $ Agosto              : num [1:466509] NA 2 3 NA NA NA NA 1 7 NA ...
##  $ Septiembre          : num [1:466509] NA 2 3 NA NA NA NA 1 4 NA ...
##  $ Octubre             : num [1:466509] NA 2 3 NA NA NA 0 NA 3 NA ...
##  $ Noviembre           : num [1:466509] NA 4 3 NA 0 NA NA NA 1 NA ...
##  $ Diciembre           : num [1:466509] 1 2 3 1 NA NA NA NA 3 NA ...

Revisar NAs en la base de datos

# ¿Cuántos NAs tengo en la base de datos?
sum(is.na(df))
## [1] 3148501
# ¿Cuántos NAs tengo por variable?
sapply(df, function(x) sum(is.na(x)))
##                   ID                  Año           Territorio 
##                    0                    0                    0 
##       Sub Territorio                 CEDI              Cliente 
##                    0                    0                    0 
##               Nombre Tamaño Cte Industria         Segmento Det 
##                    0                    0                    0 
##                Marca         Presentacion               Tamaño 
##                    0                    0                    0 
##        Retornable_NR                Enero              Febrero 
##                    0               233480               231213 
##                Marzo                Abril                 Mayo 
##               227420               224057               216910 
##                Junio                Julio               Agosto 
##               215753               223411               220242 
##           Septiembre              Octubre            Noviembre 
##               337314               338386               338460 
##            Diciembre 
##               341855
# Opción 1. Eliminar NAs
# df1 <- na.omit(df)

# Opción 2. Reemplazar NAs con CEROS
df1 <- df
df1[is.na(df1)] <- 0
sum(is.na(df1))
## [1] 0
# Opción 3. Reemplazar NAs con PROMEDIO
# df1 <- df
# df1$Enero[is.na(df1$Enero)] <- mean(df1$Enero, na.rm=TRUE)

Detectar valores atípicos

boxplot(df1$Enero)

# Eliminar renglón de los totales
df1 <- df1[df1$Enero <6000, ]
boxplot(df1$Enero)

Funciones del paquete dplyr

# Adecuar nombres con gsub
names(df1) <- gsub(" ", "_", names(df1))

# Muestra las ventas de Enero a Junio por CEDI:
df2 <- select(df1,c(CEDI,Enero:Junio))

# Muestra los movimientos por Cedi y tamaño de tienda grande:
df3 <- df1 %>% filter(Tamaño_Cte_Industria == "Grande")

# Ordena la base de datos por Cedi, por marca y por presentación:
df4 <- df1 %>% arrange(CEDI, Marca, Presentacion)

# Agrega un campo calculado con las ventas del primer semestre y muestra las ventas del primer semestre por marca:
df5 <- df1 %>% 
  mutate(Ventas_Sem1 = Enero + Febrero + Marzo + Abril + Mayo + Junio)

ventas_sem1_por_marca <- df5 %>% 
  group_by(Marca) %>% 
  summarise(Ventas_Sem1=sum(Ventas_Sem1))

# Obtén la media de las ventas del primer semestre agrupado por marca, presentación y tamaño.
df6 <- df5 %>%
  group_by(Marca, Presentacion, Tamaño) %>%
  summarise(Ventas_Sem1=mean(Ventas_Sem1))
## `summarise()` has grouped output by 'Marca', 'Presentacion'. You can override
## using the `.groups` argument.
# Calcular medidas de tendencia central
summary(df1)
##        ID              Año        Territorio        Sub_Territorio    
##  Min.   :     1   Min.   :2016   Length:466508      Length:466508     
##  1st Qu.:116628   1st Qu.:2017   Class :character   Class :character  
##  Median :233256   Median :2018   Mode  :character   Mode  :character  
##  Mean   :233255   Mean   :2018                                        
##  3rd Qu.:349882   3rd Qu.:2019                                        
##  Max.   :466509   Max.   :2019                                        
##      CEDI             Cliente             Nombre          Tamaño_Cte_Industria
##  Length:466508      Length:466508      Length:466508      Length:466508       
##  Class :character   Class :character   Class :character   Class :character    
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character    
##                                                                               
##                                                                               
##                                                                               
##  Segmento_Det          Marca           Presentacion          Tamaño         
##  Length:466508      Length:466508      Length:466508      Length:466508     
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##  Retornable_NR          Enero             Febrero             Marzo         
##  Length:466508      Min.   : -19.000   Min.   : -11.000   Min.   : -32.000  
##  Class :character   1st Qu.:   0.000   1st Qu.:   0.000   1st Qu.:   0.000  
##  Mode  :character   Median :   0.000   Median :   0.000   Median :   0.000  
##                     Mean   :   4.951   Mean   :   4.829   Mean   :   5.729  
##                     3rd Qu.:   2.000   3rd Qu.:   2.000   3rd Qu.:   3.000  
##                     Max.   :5333.000   Max.   :4995.000   Max.   :5636.000  
##      Abril               Mayo             Junio              Julio         
##  Min.   : -70.000   Min.   :-106.00   Min.   :-211.000   Min.   : -60.000  
##  1st Qu.:   0.000   1st Qu.:   0.00   1st Qu.:   0.000   1st Qu.:   0.000  
##  Median :   0.000   Median :   0.00   Median :   0.000   Median :   0.000  
##  Mean   :   5.992   Mean   :   6.73   Mean   :   6.464   Mean   :   6.033  
##  3rd Qu.:   3.000   3rd Qu.:   3.00   3rd Qu.:   3.000   3rd Qu.:   3.000  
##  Max.   :6164.000   Max.   :6759.00   Max.   :6033.000   Max.   :6735.000  
##      Agosto           Septiembre          Octubre           Noviembre      
##  Min.   :-211.000   Min.   :-527.000   Min.   : -38.000   Min.   : -25.00  
##  1st Qu.:   0.000   1st Qu.:   0.000   1st Qu.:   0.000   1st Qu.:   0.00  
##  Median :   0.000   Median :   0.000   Median :   0.000   Median :   0.00  
##  Mean   :   6.235   Mean   :   3.625   Mean   :   3.674   Mean   :   3.57  
##  3rd Qu.:   3.000   3rd Qu.:   1.000   3rd Qu.:   1.000   3rd Qu.:   1.00  
##  Max.   :6065.000   Max.   :6509.000   Max.   :6326.000   Max.   :5319.00  
##    Diciembre       
##  Min.   : -28.000  
##  1st Qu.:   0.000  
##  Median :   0.000  
##  Mean   :   3.858  
##  3rd Qu.:   0.000  
##  Max.   :6182.000
# Colapsar meses en una columna
df7 <- gather(df1, Mes, Ventas, Enero:Diciembre)
df7
## # A tibble: 5,598,096 × 15
##       ID   Año Territorio  Sub_Territorio CEDI         Cliente Nombre
##    <dbl> <dbl> <chr>       <chr>          <chr>        <chr>   <chr> 
##  1     1  2016 Guadalajara Belenes        Suc. Belenes 77737   ABARR 
##  2     2  2016 Guadalajara Belenes        Suc. Belenes 77737   ABARR 
##  3     3  2016 Guadalajara Belenes        Suc. Belenes 77737   ABARR 
##  4     4  2016 Guadalajara Belenes        Suc. Belenes 77737   ABARR 
##  5     5  2016 Guadalajara Belenes        Suc. Belenes 77737   ABARR 
##  6     6  2016 Guadalajara Belenes        Suc. Belenes 77737   ABARR 
##  7     7  2016 Guadalajara Belenes        Suc. Belenes 77737   ABARR 
##  8     8  2016 Guadalajara Belenes        Suc. Belenes 77737   ABARR 
##  9     9  2016 Guadalajara Belenes        Suc. Belenes 77737   ABARR 
## 10    10  2016 Guadalajara Belenes        Suc. Belenes 77737   ABARR 
## # ℹ 5,598,086 more rows
## # ℹ 8 more variables: Tamaño_Cte_Industria <chr>, Segmento_Det <chr>,
## #   Marca <chr>, Presentacion <chr>, Tamaño <chr>, Retornable_NR <chr>,
## #   Mes <chr>, Ventas <dbl>

Tarea Colaborativa 2

Actividad Individual 3

# Agregar una columna con el Número de Mes
meses <- c("Enero"="01", "Febrero"="02","Marzo"="03", "Abril"="04", "Mayo"="05", "Junio"="06", "Julio"="07", "Agosto"="08", "Septiembre"="09", "Octubre"="10", "Noviembre"="11", "Diciembre"="12")

df7$Número_de_Mes <- meses[df7$Mes]

# Graficar el total de ventas por mes y año

ventas_totales <- df7 %>%
  group_by(Año, Número_de_Mes) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  arrange(Número_de_Mes)
## `summarise()` has grouped output by 'Año'. You can override using the `.groups`
## argument.
ggplot(ventas_totales, aes(x=Número_de_Mes, y=Ventas_Totales,group=Año, color= as.factor(Año))) +
  geom_line() +
  geom_point() +
  labs(x="Mes",y="Ventas Totales(Qty)", color = "Año")

Tarea Colaborativa 3

# Pregunta Detonante 4. ¿Se ha incrementado la venta de productos en envases retornables en los últimos dos años?
ventas_totales_er <- df7 %>%
   filter(Retornable_NR == "Retornable") %>%
  group_by(Año, Número_de_Mes) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  arrange(Número_de_Mes)
## `summarise()` has grouped output by 'Año'. You can override using the `.groups`
## argument.
ggplot(ventas_totales_er, aes(x=Número_de_Mes, y=Ventas_Totales,group=Año, color= as.factor(Año))) +
  geom_line() +
  geom_point() +
  labs(x="Mes",y="Ventas Totales(Qty)", title= "Ventas Totales de Productos en Envases Retornables", color = "Año")

# Pregunta Detonante 
ventas_totales_seg <- df7 %>%
   filter(Segmento_Det == "Agua Purificada" | Segmento_Det == "Isotónicos Regular" | Segmento_Det == "Colas Regular" ) %>%
  filter(Año == 2018) %>%
  group_by(Segmento_Det, Número_de_Mes) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  arrange(Número_de_Mes)
## `summarise()` has grouped output by 'Segmento_Det'. You can override using the
## `.groups` argument.
ggplot(ventas_totales_seg, aes(x=Número_de_Mes, y=Ventas_Totales,group=Segmento_Det, color= as.factor(Segmento_Det))) +
  geom_line() +
  geom_point() +
  labs(x="Mes",y="Ventas Totales(Qty)", title= "Ventas Totales por Segmento", color = "Segmento")

Actividad Individual 4

# Elaborar Regresión Lineal

ventas_4567 <- df7 %>%
  filter(Cliente == "4567") %>%
  group_by(Año) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  filter(Ventas_Totales != 0)

# ventas_4567$Secuencia <- 1:nrow(ventas_4567)

ggplot(ventas_4567, aes(x=Año, y=Ventas_Totales)) +
  geom_point() +
  labs(x="Año",y="Ventas Totales(Qty)", title= "Ventas Totales del Cliente 4567")

regresion <- lm(Ventas_Totales ~ Año, data=ventas_4567)
summary(regresion)
## 
## Call:
## lm(formula = Ventas_Totales ~ Año, data = ventas_4567)
## 
## Residuals:
##     1     2     3 
## -5092 10185 -5092 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)
## (Intercept) 48918677   17799125   2.748    0.222
## Año           -24174       8820  -2.741    0.223
## 
## Residual standard error: 12470 on 1 degrees of freedom
## Multiple R-squared:  0.8825, Adjusted R-squared:  0.765 
## F-statistic: 7.512 on 1 and 1 DF,  p-value: 0.2227
# Ecuación
# y = 48918677 - 24174 * Año 

# R cuadrada ajustada
# 77%

datos <- data.frame(Año=2020:2025)
prediccion <- predict(regresion,datos)
prediccion
##          1          2          3          4          5          6 
##  87197.333  63023.333  38849.333  14675.333  -9498.667 -33672.667
ventas_4567$Tipo_de_Dato <- "Datos Reales"
datos$Ventas_Totales <- prediccion
datos$Tipo_de_Dato <- "Predicción"

datos_combinados <- rbind(ventas_4567,datos)

ggplot(datos_combinados, aes(x=Año, y=Ventas_Totales, color=Tipo_de_Dato)) +
  geom_point() +
  labs(x="Año",y="Ventas Totales(Qty)", title= "Pronóstico a 5 años de Ventas del Cliente 4567")

Tarea Colaborativa 4

Actividad Individual 5

ventas_mensuales_4567 <- df7 %>%
  filter(Cliente == "4567") %>%
  group_by(Año, Número_de_Mes) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  filter(Ventas_Totales != 0)

# Confirmar que los datos que queremos modelar esten ordenados cronológicamente.

# Función de Serie de Tiempo MENSUAL, que inicia en Enero 2017
ts <- ts(data=ventas_mensuales_4567$Ventas_Totales, start = c(2017,1), frequency = 12)

# Función de Serie de Tiempo MENSUAL, que inicia en Abril 2017
# ts <- ts(data=ventas_mensuales_4567$Ventas_Totales, start = c(2017,4), frequency = 12)

# Función de Serie de Tiempo TRIMESTRAL, que inicia en Enero 2017
# ts <- ts(data=ventas_mensuales_4567$Ventas_Totales, start = c(2017,1), frequency = 4)

# Función de Serie de Tiempo TRIMESTRAL, que inicia en Octubre 2017 (Q4)
# ts <- ts(data=ventas_mensuales_4567$Ventas_Totales, start = c(2017,4), frequency = 4)

# Función de Serie de Tiempo ANUAL, que inicia en 2017
# ts <- ts(data=ventas_mensuales_4567$Ventas_Totales, start = 2017, frequency = 1)

# Crear Modelo ARIMA
# Modelo Autorregresivo Integrado de Promedio Movil.
arima <- auto.arima(ts, D=1) # D=1 por la temporalidad
arima
## Series: ts 
## ARIMA(0,0,0)(0,1,0)[12] 
## 
## sigma^2 = 10383172:  log likelihood = -189.94
## AIC=381.87   AICc=382.09   BIC=382.87
summary(arima)
## Series: ts 
## ARIMA(0,0,0)(0,1,0)[12] 
## 
## sigma^2 = 10383172:  log likelihood = -189.94
## AIC=381.87   AICc=382.09   BIC=382.87
## 
## Training set error measures:
##                     ME     RMSE     MAE       MPE     MAPE      MASE      ACF1
## Training set -36.98041 2547.446 1572.02 -1.811657 13.08459 0.6269271 0.2519497
# Generar el pronóstico de ventas
pronostico <- forecast(arima, level=95, h=36)
pronostico
##          Point Forecast      Lo 95    Hi 95
## Sep 2019          12086  5770.4219 18401.58
## Oct 2019          11427  5111.4219 17742.58
## Nov 2019          11270  4954.4219 17585.58
## Dec 2019          12227  5911.4219 18542.58
## Jan 2020           9430  3114.4219 15745.58
## Feb 2020          11312  4996.4219 17627.58
## Mar 2020          12515  6199.4219 18830.58
## Apr 2020          13334  7018.4219 19649.58
## May 2020          16286  9970.4219 22601.58
## Jun 2020          15347  9031.4219 21662.58
## Jul 2020          14005  7689.4219 20320.58
## Aug 2020          14050  7734.4219 20365.58
## Sep 2020          12086  3154.4238 21017.58
## Oct 2020          11427  2495.4238 20358.58
## Nov 2020          11270  2338.4238 20201.58
## Dec 2020          12227  3295.4238 21158.58
## Jan 2021           9430   498.4238 18361.58
## Feb 2021          11312  2380.4238 20243.58
## Mar 2021          12515  3583.4238 21446.58
## Apr 2021          13334  4402.4238 22265.58
## May 2021          16286  7354.4238 25217.58
## Jun 2021          15347  6415.4238 24278.58
## Jul 2021          14005  5073.4238 22936.58
## Aug 2021          14050  5118.4238 22981.58
## Sep 2021          12086  1147.0979 23024.90
## Oct 2021          11427   488.0979 22365.90
## Nov 2021          11270   331.0979 22208.90
## Dec 2021          12227  1288.0979 23165.90
## Jan 2022           9430 -1508.9021 20368.90
## Feb 2022          11312   373.0979 22250.90
## Mar 2022          12515  1576.0979 23453.90
## Apr 2022          13334  2395.0979 24272.90
## May 2022          16286  5347.0979 27224.90
## Jun 2022          15347  4408.0979 26285.90
## Jul 2022          14005  3066.0979 24943.90
## Aug 2022          14050  3111.0979 24988.90
plot(pronostico, main="Ventas Mensuales y Pronóstico a 3 Años del Cliente 4567", xlab="Año", ylab="Ventas (Qty)")

Evidencia

Preguntas Detonantes

  1. ¿Puede observarse un crecimiento en las ventas de algunos de los segmentos de productos de la familia Coca Cola en las tiendas en las que se implementó el Proyecto Siglo XXI de Arca Continental?
ventas_totales_seg <- df7 %>%
   filter(Segmento_Det == "Agua Purificada" | Segmento_Det == "Isotónicos Regular" | Segmento_Det == "Colas Regular" ) %>%
  filter(Año == 2018) %>%
  group_by(Segmento_Det, Número_de_Mes) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  arrange(Número_de_Mes)
## `summarise()` has grouped output by 'Segmento_Det'. You can override using the
## `.groups` argument.
ggplot(ventas_totales_seg, aes(x=Número_de_Mes, y=Ventas_Totales,group=Segmento_Det, color= as.factor(Segmento_Det))) +
  geom_line() +
  geom_point() +
  labs(x="Mes",y="Ventas Totales(Qty)", title= "Ventas Totales por Segmento", color = "Segmento")

Respuesta: En general las ventas aumentaron en 2019, pero cada segmento se comportó diferente. El incremento de ventas se puede lograr gracias a mejores campañas de mercadotecnia y lanzamiento de nuevos productos.En 2018 la venta de Coca-Cola entre Febrero y Diciembre aumentó en 100,000 unidades, mientras que las aguas isotónicas no tuvieron cambios.

  1. ¿El incremento en las ventas es similar entre los diferentes tamaños de clientes?
ventas_totales_tam_cliente <- df7 %>%
  filter(Año == 2019) %>%
  group_by(Tamaño_Cte_Industria, Número_de_Mes) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  arrange(Número_de_Mes) %>%
  filter(Ventas_Totales != 0)
## `summarise()` has grouped output by 'Tamaño_Cte_Industria'. You can override
## using the `.groups` argument.
ggplot(ventas_totales_tam_cliente, aes(x=Número_de_Mes, y=Ventas_Totales,group=Tamaño_Cte_Industria, color= as.factor(Tamaño_Cte_Industria))) +
  geom_line() +
  geom_point() +
  labs(x="Mes",y="Ventas Totales(Qty)", title= "Ventas Totales por Tamaño de Cliente", color = "Tamaño de Cliente")

Respuesta: El incremento de ventas es similar independientemente de los tamaños de los clientes. Como todos los negocios están abiertos los mismos días, y están ubicados en la misma ciudad (Guadalajara), los factores externos de las ventas efectan casi igual a todos. El mes de mayo de 2019 fue el de mayor ventas en todos los tamaños de cliente, y el primer bimestre fue el más bajo también para todos los tamaños de cliente.

  1. ¿Cuál es el comportamiento observado de las unidades vendidas por mes de cada una de las marcas, independientemente de sus respectivas presentaciones?
ventas_totales_marca <- df7 %>%
  filter(Año == 2019) %>%
  filter(Marca == c("Coca-Cola", "Valle Frut", "Ciel Agua Purificada","Coca-Cola Light")) %>%
  group_by(Marca, Número_de_Mes) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  arrange(Número_de_Mes) %>%
  filter(Ventas_Totales != 0)
## `summarise()` has grouped output by 'Marca'. You can override using the
## `.groups` argument.
ggplot(ventas_totales_marca, aes(x=Número_de_Mes, y=Ventas_Totales,group=Marca, color= as.factor(Marca))) +
  geom_line() +
  geom_point() +
  labs(x="Mes",y="Ventas Totales(Qty)", title= "Ventas Totales por Marca", color = "Marca")

Respuesta: El comportamiento de ventas es similar entre las marcas a través de los meses, pero hay marcas que venden mucho más que otras. Los meses de más ventas de bebidas son los meses en que la temperatura es mayor, y las marcas más conocidas son las que tiene en mente el consumidor. El mes de mayo 2019 es para todas las marcas el de mayores ventas, pero la marca Coca-Cola es la que vende más que todas.

  1. ¿Se ha incrementado la venta de productos en envases retornables en los últimos dos años?
ventas_totales_envase <- df7 %>%
  filter(Retornable_NR=="Retornable") %>%
  filter(Año == c(2017,2018,2019)) %>%
  group_by(Año, Número_de_Mes) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  arrange(Número_de_Mes) %>%
  filter(Ventas_Totales != 0)
## `summarise()` has grouped output by 'Año'. You can override using the `.groups`
## argument.
ggplot(ventas_totales_envase, aes(x=Número_de_Mes, y=Ventas_Totales,group=Año, color= as.factor(Año))) +
  geom_line() +
  geom_point() +
  labs(x="Mes",y="Ventas Totales(Qty)", title= "Ventas Totales de Envases Retornables", color = "Año")

Respuesta: La venta de productos en envase retornable aumentó en los últimos dos años. Las campañas de conciencia ambiental han vuelto populares las opciones menos dañinas al ecosistema. De 2017 a 2018 hubo un ligero incremento en las ventas de envase retornable, y entre 2018 y 2019 el aumento fue muy notorio.

Notas: Hay otros factores a considerar como que en 2019 hay más tiendas con el proyecto Siglo XXI, o que las tiendas en general venden más productos (tanto retornables como no retornables).

  1. ¿El comportamiento de la venta de agua ha incrementado en relación al de los refrescos o las bebidas isotónicas?
ventas_totales_seg <- df7 %>%
   filter(Segmento_Det == "Agua Purificada" | Segmento_Det == "Isotónicos Regular" | Segmento_Det == "Colas Regular" ) %>%
  filter(Año == 2018) %>%
  group_by(Segmento_Det, Número_de_Mes) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  arrange(Número_de_Mes)
## `summarise()` has grouped output by 'Segmento_Det'. You can override using the
## `.groups` argument.
ggplot(ventas_totales_seg, aes(x=Número_de_Mes, y=Ventas_Totales,group=Segmento_Det, color= as.factor(Segmento_Det))) +
  geom_line() +
  geom_point() +
  labs(x="Mes",y="Ventas Totales(Qty)", title= "Ventas Totales por Segmento", color = "Segmento")

Respuesta: Las ventas de Agua Purificada no ha aumentado en relación a Refrescos o Bebidas Isotónicas. La persepción que el agua no tiene valor agregado en la preparación y el azúcar en la receta hacen de los refrescos la opción preferida de los consumidores mexicanos. En 2018 las ventas totales de Agua Purificada no superaron las 50,000 unidades, mientras que la Coca-Cola vendió en su mes más alto 450,000 (8 veces más que el agua).

  1. ¿Puede decirse que la venta mensual de agua está relacionada con la venta mensual de refrescos en los últimos 4 años?
ventas_totales_ayr <- df7 %>%
   filter(Segmento_Det == c("Agua Purificada", "Colas Regular")) %>%
  group_by(Segmento_Det, Año) %>%
  summarise(Ventas_Totales = sum(Ventas)) 
## `summarise()` has grouped output by 'Segmento_Det'. You can override using the
## `.groups` argument.
ggplot(ventas_totales_ayr, aes(x=Año, y=Ventas_Totales,group=Segmento_Det, color= as.factor(Segmento_Det))) +
  geom_line() +
  geom_point() +
  labs(x="Año",y="Ventas Totales(Qty)", title= "Ventas Totales por Segmento", color = "Segmento")

Respuesta: La venta de agua y refrescos se incrementa en los mismos meses, y a través de los años, pero no se puede concluir que un incremento cause el otro. Los meses calurosos y el crecimiento de la población hace que las ventas se incrementen en las bebidas, sean agua o refresco. En la gráfica obtenida se observa un incremento año con año en la venta de agua y también de refrescos.

  1. ¿A cuánto ascienden las ventas esperadas para el 2020 en la Coca Cola de 500 ml NR Vidrio?
ventas_coca_vidrio <- df7 %>%
  filter(Marca == "Coca-Cola" & Presentacion == "500 ml NR Vidrio") %>%
  group_by(Año, Número_de_Mes) %>%
  summarise(Ventas_Totales = sum(Ventas)) %>%
  filter(Ventas_Totales != 0)
## `summarise()` has grouped output by 'Año'. You can override using the `.groups`
## argument.
# Confirmar que los datos que queremos modelar esten ordenados cronológicamente.

# Función de Serie de Tiempo MENSUAL, que inicia en Enero 2017
ts <- ts(data=ventas_coca_vidrio$Ventas_Totales, start = c(2016,1), frequency = 12)

# Crear Modelo ARIMA
# Modelo Autorregresivo Integrado de Promedio Movil.
arima <- auto.arima(ts, D=1) # D=1 por la temporalidad
arima
## Series: ts 
## ARIMA(1,0,0)(0,1,0)[12] with drift 
## 
## Coefficients:
##          ar1     drift
##       0.7092  719.6837
## s.e.  0.1328  299.8533
## 
## sigma^2 = 41602728:  log likelihood = -325.42
## AIC=656.84   AICc=657.7   BIC=661.24
summary(arima)
## Series: ts 
## ARIMA(1,0,0)(0,1,0)[12] with drift 
## 
## Coefficients:
##          ar1     drift
##       0.7092  719.6837
## s.e.  0.1328  299.8533
## 
## sigma^2 = 41602728:  log likelihood = -325.42
## AIC=656.84   AICc=657.7   BIC=661.24
## 
## Training set error measures:
##                    ME     RMSE      MAE      MPE     MAPE      MASE       ACF1
## Training set 48.85447 5325.927 3245.824 -1.37305 8.085494 0.3668297 -0.1551829
# Generar el pronóstico de ventas
pronostico <- forecast(arima, level=95, h=16)
pronostico
##          Point Forecast    Lo 95    Hi 95
## Sep 2019       57009.75 44367.95 69651.56
## Oct 2019       47611.80 32113.20 63110.40
## Nov 2019       43891.36 27138.87 60643.85
## Dec 2019       49988.01 32639.01 67337.02
## Jan 2020       52649.58 35008.14 70291.03
## Feb 2020       59116.44 41329.71 76903.18
## Mar 2020       63214.35 45354.98 81073.72
## Apr 2020       45929.53 28033.74 63825.33
## May 2020       77893.53 59979.44 95807.63
## Jun 2020       66916.74 48993.45 84840.03
## Jul 2020       65103.76 47175.85 83031.68
## Aug 2020       66475.17 48544.93 84405.41
## Sep 2020       65845.94 43788.54 87903.34
## Oct 2020       56389.84 32524.67 80255.02
## Nov 2020       52628.16 27903.54 77352.78
## Dec 2020       58695.56 33549.72 83841.40
plot(pronostico, main="Ventas Mensuales y Pronóstico para 2020 de Coca-Cola 500 ml NR Vidrio", xlab="Año",  ylab="Ventas (Qty)")

Respuesta: Las ventas esperadas de Coca-Cola de 500 ml NR Vidrio para 2020 oscilan mensualmente entre 45,000 y 65,000 unidades, con una confiabilidad del 95%.

Conclusiones

El ver los resultados de la actividades realmente muestra la util que puede llegar a ser R para el analisis de datos, el poder ser capaz no solo de limpiar las bases de datos, sino el realmente ser capaz de crear graficas personalizadas a las necesidades que se ocupan, el utilizar R brinda una nueva oportunidad para poder ser capaz de entender la informacion en un nuevo nivel, la ser capaz de encontrar cosas que uno no seria capaz de hacer de manera tradicional, asi mismo fue sumamente interesanre el ver como es que R tiene tambien sus errores por lo cual considero que aprender R mas a detalle es una gran opcion y algo muy interesante pero tambien pude ber que puede llegar a ser un poco mas complicado.

LS0tDQp0aXRsZTogIkFyY2EgY29udGluZW50YWwgMiINCmF1dGhvcjogIkplc8O6cyBHYXhpb2xhIEEwMDIyNzI2NiINCmRhdGU6ICIyMDI1LTAzLTIxIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IGNvc21vDQotLS0NCg0KIVtdKGh0dHBzOi8vc2NvbnRlbnQtbXR5Mi0xLnh4LmZiY2RuLm5ldC92L3QzOS4zMDgwOC02LzQ2NTExNjEwMF84ODMwNzY1MDA2OTc5Nzc0XzU3NDQ2MTU2NjkzNTY2MTI0MDRfbi5qcGc/X25jX2NhdD0xMDYmY2NiPTEtNyZfbmNfc2lkPTZlZTExYSZfbmNfb2hjPTdpd01Ha0NtazVFUTdrTnZnSHNxeVJxJl9uY19vYz1BZG52ZjM5SzYwYnRkQ2hxM29VVkNRWGthZk1JNlltTUl6LUtxS2NTWTk4cTNYaGMwRHlHUHBDVDZhLXVHTHJSU2xZJl9uY196dD0yMyZfbmNfaHQ9c2NvbnRlbnQtbXR5Mi0xLnh4Jl9uY19naWQ9cFdJemx5eGNseVFhc2ptVjhzb2k0USZvaD0wMF9BWUg0QUFjUkhJRTVOQkFaUkozVk5kWlg3UU85R1AxMGk1ZHdSRHAzWHVDeFBBJm9lPTY3RTM4QzI1KQ0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+SW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hczwvc3Bhbj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIGluc3RhbGwucGFja2FnZXMoInJlYWR4bCIpICMgTGVlciBkb2N1bWVudG9zIGRlIGV4Y2VsDQpsaWJyYXJ5KHJlYWR4bCkNCiMgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikgIyBNYW5pcHVsYWNpw7NuIGRlIGRhdG9zDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCiMgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpICMgR2VuZXJhciBncsOhZmljb3MgcHJlc2VudGFibGVzDQpsaWJyYXJ5KGdncGxvdDIpDQojIGluc3RhbGwucGFja2FnZXMoImZvcmVjYXN0IikgIyBHZW5lcmFyIHNlcmllcyBkZSB0aWVtcG8geSBwcm9uw7NzdGljb3MNCmxpYnJhcnkoZm9yZWNhc3QpDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZDsiPkFjdGl2aWRhZCBJbmRpdmlkdWFsIDI8L3NwYW4+DQoNCiMjIEltcG9ydGFyIGxhIGJhc2UgZGUgZGF0b3MNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIGZpbGUuY2hvb3NlKCkNCmRmIDwtIHJlYWRfZXhjZWwoIkM6XFxVc2Vyc1xcc3BhY2FuaW5vXFxEb3dubG9hZHNcXFJcXERhdG9zIEFyY2EgQ29udGluZW50YWwgT3JpZ2luYWwueGxzeCIpDQpgYGANCg0KIyMgUmV2aXNhciBsYSBlc3RydWN0dXJhIGRlIGxvcyBkYXRvcw0KYGBge3J9DQpzdHIoZGYpDQpgYGANCg0KIyMgUmV2aXNhciBOQXMgZW4gbGEgYmFzZSBkZSBkYXRvcw0KYGBge3J9DQojIMK/Q3XDoW50b3MgTkFzIHRlbmdvIGVuIGxhIGJhc2UgZGUgZGF0b3M/DQpzdW0oaXMubmEoZGYpKQ0KDQojIMK/Q3XDoW50b3MgTkFzIHRlbmdvIHBvciB2YXJpYWJsZT8NCnNhcHBseShkZiwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkNCg0KIyBPcGNpw7NuIDEuIEVsaW1pbmFyIE5Bcw0KIyBkZjEgPC0gbmEub21pdChkZikNCg0KIyBPcGNpw7NuIDIuIFJlZW1wbGF6YXIgTkFzIGNvbiBDRVJPUw0KZGYxIDwtIGRmDQpkZjFbaXMubmEoZGYxKV0gPC0gMA0Kc3VtKGlzLm5hKGRmMSkpDQoNCiMgT3BjacOzbiAzLiBSZWVtcGxhemFyIE5BcyBjb24gUFJPTUVESU8NCiMgZGYxIDwtIGRmDQojIGRmMSRFbmVyb1tpcy5uYShkZjEkRW5lcm8pXSA8LSBtZWFuKGRmMSRFbmVybywgbmEucm09VFJVRSkNCmBgYA0KDQojIyBEZXRlY3RhciB2YWxvcmVzIGF0w61waWNvcw0KYGBge3J9DQpib3hwbG90KGRmMSRFbmVybykNCg0KIyBFbGltaW5hciByZW5nbMOzbiBkZSBsb3MgdG90YWxlcw0KZGYxIDwtIGRmMVtkZjEkRW5lcm8gPDYwMDAsIF0NCmJveHBsb3QoZGYxJEVuZXJvKQ0KYGBgDQoNCiMjIEZ1bmNpb25lcyBkZWwgcGFxdWV0ZSBkcGx5cg0KYGBge3J9DQojIEFkZWN1YXIgbm9tYnJlcyBjb24gZ3N1Yg0KbmFtZXMoZGYxKSA8LSBnc3ViKCIgIiwgIl8iLCBuYW1lcyhkZjEpKQ0KDQojIE11ZXN0cmEgbGFzIHZlbnRhcyBkZSBFbmVybyBhIEp1bmlvIHBvciBDRURJOg0KZGYyIDwtIHNlbGVjdChkZjEsYyhDRURJLEVuZXJvOkp1bmlvKSkNCg0KIyBNdWVzdHJhIGxvcyBtb3ZpbWllbnRvcyBwb3IgQ2VkaSB5IHRhbWHDsW8gZGUgdGllbmRhIGdyYW5kZToNCmRmMyA8LSBkZjEgJT4lIGZpbHRlcihUYW1hw7FvX0N0ZV9JbmR1c3RyaWEgPT0gIkdyYW5kZSIpDQoNCiMgT3JkZW5hIGxhIGJhc2UgZGUgZGF0b3MgcG9yIENlZGksIHBvciBtYXJjYSB5IHBvciBwcmVzZW50YWNpw7NuOg0KZGY0IDwtIGRmMSAlPiUgYXJyYW5nZShDRURJLCBNYXJjYSwgUHJlc2VudGFjaW9uKQ0KDQojIEFncmVnYSB1biBjYW1wbyBjYWxjdWxhZG8gY29uIGxhcyB2ZW50YXMgZGVsIHByaW1lciBzZW1lc3RyZSB5IG11ZXN0cmEgbGFzIHZlbnRhcyBkZWwgcHJpbWVyIHNlbWVzdHJlIHBvciBtYXJjYToNCmRmNSA8LSBkZjEgJT4lIA0KICBtdXRhdGUoVmVudGFzX1NlbTEgPSBFbmVybyArIEZlYnJlcm8gKyBNYXJ6byArIEFicmlsICsgTWF5byArIEp1bmlvKQ0KDQp2ZW50YXNfc2VtMV9wb3JfbWFyY2EgPC0gZGY1ICU+JSANCiAgZ3JvdXBfYnkoTWFyY2EpICU+JSANCiAgc3VtbWFyaXNlKFZlbnRhc19TZW0xPXN1bShWZW50YXNfU2VtMSkpDQoNCiMgT2J0w6luIGxhIG1lZGlhIGRlIGxhcyB2ZW50YXMgZGVsIHByaW1lciBzZW1lc3RyZSBhZ3J1cGFkbyBwb3IgbWFyY2EsIHByZXNlbnRhY2nDs24geSB0YW1hw7FvLg0KZGY2IDwtIGRmNSAlPiUNCiAgZ3JvdXBfYnkoTWFyY2EsIFByZXNlbnRhY2lvbiwgVGFtYcOxbykgJT4lDQogIHN1bW1hcmlzZShWZW50YXNfU2VtMT1tZWFuKFZlbnRhc19TZW0xKSkNCg0KIyBDYWxjdWxhciBtZWRpZGFzIGRlIHRlbmRlbmNpYSBjZW50cmFsDQpzdW1tYXJ5KGRmMSkNCg0KIyBDb2xhcHNhciBtZXNlcyBlbiB1bmEgY29sdW1uYQ0KZGY3IDwtIGdhdGhlcihkZjEsIE1lcywgVmVudGFzLCBFbmVybzpEaWNpZW1icmUpDQpkZjcNCg0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiByZWQ7Ij5UYXJlYSBDb2xhYm9yYXRpdmEgMjwvc3Bhbj4NCmBgYHtyfQ0KDQpgYGANCg0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+QWN0aXZpZGFkIEluZGl2aWR1YWwgMzwvc3Bhbj4NCmBgYHtyfQ0KIyBBZ3JlZ2FyIHVuYSBjb2x1bW5hIGNvbiBlbCBOw7ptZXJvIGRlIE1lcw0KbWVzZXMgPC0gYygiRW5lcm8iPSIwMSIsICJGZWJyZXJvIj0iMDIiLCJNYXJ6byI9IjAzIiwgIkFicmlsIj0iMDQiLCAiTWF5byI9IjA1IiwgIkp1bmlvIj0iMDYiLCAiSnVsaW8iPSIwNyIsICJBZ29zdG8iPSIwOCIsICJTZXB0aWVtYnJlIj0iMDkiLCAiT2N0dWJyZSI9IjEwIiwgIk5vdmllbWJyZSI9IjExIiwgIkRpY2llbWJyZSI9IjEyIikNCg0KZGY3JE7Dum1lcm9fZGVfTWVzIDwtIG1lc2VzW2RmNyRNZXNdDQoNCiMgR3JhZmljYXIgZWwgdG90YWwgZGUgdmVudGFzIHBvciBtZXMgeSBhw7FvDQoNCnZlbnRhc190b3RhbGVzIDwtIGRmNyAlPiUNCiAgZ3JvdXBfYnkoQcOxbywgTsO6bWVyb19kZV9NZXMpICU+JQ0KICBzdW1tYXJpc2UoVmVudGFzX1RvdGFsZXMgPSBzdW0oVmVudGFzKSkgJT4lDQogIGFycmFuZ2UoTsO6bWVyb19kZV9NZXMpDQoNCmdncGxvdCh2ZW50YXNfdG90YWxlcywgYWVzKHg9TsO6bWVyb19kZV9NZXMsIHk9VmVudGFzX1RvdGFsZXMsZ3JvdXA9QcOxbywgY29sb3I9IGFzLmZhY3RvcihBw7FvKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHg9Ik1lcyIseT0iVmVudGFzIFRvdGFsZXMoUXR5KSIsIGNvbG9yID0gIkHDsW8iKQ0KYGBgDQoNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZDsiPlRhcmVhIENvbGFib3JhdGl2YSAzPC9zcGFuPg0KYGBge3J9DQojIFByZWd1bnRhIERldG9uYW50ZSA0LiDCv1NlIGhhIGluY3JlbWVudGFkbyBsYSB2ZW50YSBkZSBwcm9kdWN0b3MgZW4gZW52YXNlcyByZXRvcm5hYmxlcyBlbiBsb3Mgw7psdGltb3MgZG9zIGHDsW9zPw0KdmVudGFzX3RvdGFsZXNfZXIgPC0gZGY3ICU+JQ0KICAgZmlsdGVyKFJldG9ybmFibGVfTlIgPT0gIlJldG9ybmFibGUiKSAlPiUNCiAgZ3JvdXBfYnkoQcOxbywgTsO6bWVyb19kZV9NZXMpICU+JQ0KICBzdW1tYXJpc2UoVmVudGFzX1RvdGFsZXMgPSBzdW0oVmVudGFzKSkgJT4lDQogIGFycmFuZ2UoTsO6bWVyb19kZV9NZXMpDQoNCmdncGxvdCh2ZW50YXNfdG90YWxlc19lciwgYWVzKHg9TsO6bWVyb19kZV9NZXMsIHk9VmVudGFzX1RvdGFsZXMsZ3JvdXA9QcOxbywgY29sb3I9IGFzLmZhY3RvcihBw7FvKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHg9Ik1lcyIseT0iVmVudGFzIFRvdGFsZXMoUXR5KSIsIHRpdGxlPSAiVmVudGFzIFRvdGFsZXMgZGUgUHJvZHVjdG9zIGVuIEVudmFzZXMgUmV0b3JuYWJsZXMiLCBjb2xvciA9ICJBw7FvIikNCg0KDQojIFByZWd1bnRhIERldG9uYW50ZSANCnZlbnRhc190b3RhbGVzX3NlZyA8LSBkZjcgJT4lDQogICBmaWx0ZXIoU2VnbWVudG9fRGV0ID09ICJBZ3VhIFB1cmlmaWNhZGEiIHwgU2VnbWVudG9fRGV0ID09ICJJc290w7NuaWNvcyBSZWd1bGFyIiB8IFNlZ21lbnRvX0RldCA9PSAiQ29sYXMgUmVndWxhciIgKSAlPiUNCiAgZmlsdGVyKEHDsW8gPT0gMjAxOCkgJT4lDQogIGdyb3VwX2J5KFNlZ21lbnRvX0RldCwgTsO6bWVyb19kZV9NZXMpICU+JQ0KICBzdW1tYXJpc2UoVmVudGFzX1RvdGFsZXMgPSBzdW0oVmVudGFzKSkgJT4lDQogIGFycmFuZ2UoTsO6bWVyb19kZV9NZXMpDQoNCmdncGxvdCh2ZW50YXNfdG90YWxlc19zZWcsIGFlcyh4PU7Dum1lcm9fZGVfTWVzLCB5PVZlbnRhc19Ub3RhbGVzLGdyb3VwPVNlZ21lbnRvX0RldCwgY29sb3I9IGFzLmZhY3RvcihTZWdtZW50b19EZXQpKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoKSArDQogIGxhYnMoeD0iTWVzIix5PSJWZW50YXMgVG90YWxlcyhRdHkpIiwgdGl0bGU9ICJWZW50YXMgVG90YWxlcyBwb3IgU2VnbWVudG8iLCBjb2xvciA9ICJTZWdtZW50byIpDQoNCiANCg0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiByZWQ7Ij5BY3RpdmlkYWQgSW5kaXZpZHVhbCA0PC9zcGFuPg0KYGBge3J9DQojIEVsYWJvcmFyIFJlZ3Jlc2nDs24gTGluZWFsDQoNCnZlbnRhc180NTY3IDwtIGRmNyAlPiUNCiAgZmlsdGVyKENsaWVudGUgPT0gIjQ1NjciKSAlPiUNCiAgZ3JvdXBfYnkoQcOxbykgJT4lDQogIHN1bW1hcmlzZShWZW50YXNfVG90YWxlcyA9IHN1bShWZW50YXMpKSAlPiUNCiAgZmlsdGVyKFZlbnRhc19Ub3RhbGVzICE9IDApDQoNCiMgdmVudGFzXzQ1NjckU2VjdWVuY2lhIDwtIDE6bnJvdyh2ZW50YXNfNDU2NykNCg0KZ2dwbG90KHZlbnRhc180NTY3LCBhZXMoeD1Bw7FvLCB5PVZlbnRhc19Ub3RhbGVzKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHg9IkHDsW8iLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCB0aXRsZT0gIlZlbnRhcyBUb3RhbGVzIGRlbCBDbGllbnRlIDQ1NjciKQ0KDQpyZWdyZXNpb24gPC0gbG0oVmVudGFzX1RvdGFsZXMgfiBBw7FvLCBkYXRhPXZlbnRhc180NTY3KQ0Kc3VtbWFyeShyZWdyZXNpb24pDQoNCiMgRWN1YWNpw7NuDQojIHkgPSA0ODkxODY3NyAtIDI0MTc0ICogQcOxbyANCg0KIyBSIGN1YWRyYWRhIGFqdXN0YWRhDQojIDc3JQ0KDQpkYXRvcyA8LSBkYXRhLmZyYW1lKEHDsW89MjAyMDoyMDI1KQ0KcHJlZGljY2lvbiA8LSBwcmVkaWN0KHJlZ3Jlc2lvbixkYXRvcykNCnByZWRpY2Npb24NCg0KdmVudGFzXzQ1NjckVGlwb19kZV9EYXRvIDwtICJEYXRvcyBSZWFsZXMiDQpkYXRvcyRWZW50YXNfVG90YWxlcyA8LSBwcmVkaWNjaW9uDQpkYXRvcyRUaXBvX2RlX0RhdG8gPC0gIlByZWRpY2Npw7NuIg0KDQpkYXRvc19jb21iaW5hZG9zIDwtIHJiaW5kKHZlbnRhc180NTY3LGRhdG9zKQ0KDQpnZ3Bsb3QoZGF0b3NfY29tYmluYWRvcywgYWVzKHg9QcOxbywgeT1WZW50YXNfVG90YWxlcywgY29sb3I9VGlwb19kZV9EYXRvKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHg9IkHDsW8iLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCB0aXRsZT0gIlByb27Ds3N0aWNvIGEgNSBhw7FvcyBkZSBWZW50YXMgZGVsIENsaWVudGUgNDU2NyIpDQpgYGANCg0KIA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+VGFyZWEgQ29sYWJvcmF0aXZhIDQ8L3NwYW4+DQoNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZDsiPkFjdGl2aWRhZCBJbmRpdmlkdWFsIDU8L3NwYW4+DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQp2ZW50YXNfbWVuc3VhbGVzXzQ1NjcgPC0gZGY3ICU+JQ0KICBmaWx0ZXIoQ2xpZW50ZSA9PSAiNDU2NyIpICU+JQ0KICBncm91cF9ieShBw7FvLCBOw7ptZXJvX2RlX01lcykgJT4lDQogIHN1bW1hcmlzZShWZW50YXNfVG90YWxlcyA9IHN1bShWZW50YXMpKSAlPiUNCiAgZmlsdGVyKFZlbnRhc19Ub3RhbGVzICE9IDApDQoNCiMgQ29uZmlybWFyIHF1ZSBsb3MgZGF0b3MgcXVlIHF1ZXJlbW9zIG1vZGVsYXIgZXN0ZW4gb3JkZW5hZG9zIGNyb25vbMOzZ2ljYW1lbnRlLg0KDQojIEZ1bmNpw7NuIGRlIFNlcmllIGRlIFRpZW1wbyBNRU5TVUFMLCBxdWUgaW5pY2lhIGVuIEVuZXJvIDIwMTcNCnRzIDwtIHRzKGRhdGE9dmVudGFzX21lbnN1YWxlc180NTY3JFZlbnRhc19Ub3RhbGVzLCBzdGFydCA9IGMoMjAxNywxKSwgZnJlcXVlbmN5ID0gMTIpDQoNCiMgRnVuY2nDs24gZGUgU2VyaWUgZGUgVGllbXBvIE1FTlNVQUwsIHF1ZSBpbmljaWEgZW4gQWJyaWwgMjAxNw0KIyB0cyA8LSB0cyhkYXRhPXZlbnRhc19tZW5zdWFsZXNfNDU2NyRWZW50YXNfVG90YWxlcywgc3RhcnQgPSBjKDIwMTcsNCksIGZyZXF1ZW5jeSA9IDEyKQ0KDQojIEZ1bmNpw7NuIGRlIFNlcmllIGRlIFRpZW1wbyBUUklNRVNUUkFMLCBxdWUgaW5pY2lhIGVuIEVuZXJvIDIwMTcNCiMgdHMgPC0gdHMoZGF0YT12ZW50YXNfbWVuc3VhbGVzXzQ1NjckVmVudGFzX1RvdGFsZXMsIHN0YXJ0ID0gYygyMDE3LDEpLCBmcmVxdWVuY3kgPSA0KQ0KDQojIEZ1bmNpw7NuIGRlIFNlcmllIGRlIFRpZW1wbyBUUklNRVNUUkFMLCBxdWUgaW5pY2lhIGVuIE9jdHVicmUgMjAxNyAoUTQpDQojIHRzIDwtIHRzKGRhdGE9dmVudGFzX21lbnN1YWxlc180NTY3JFZlbnRhc19Ub3RhbGVzLCBzdGFydCA9IGMoMjAxNyw0KSwgZnJlcXVlbmN5ID0gNCkNCg0KIyBGdW5jacOzbiBkZSBTZXJpZSBkZSBUaWVtcG8gQU5VQUwsIHF1ZSBpbmljaWEgZW4gMjAxNw0KIyB0cyA8LSB0cyhkYXRhPXZlbnRhc19tZW5zdWFsZXNfNDU2NyRWZW50YXNfVG90YWxlcywgc3RhcnQgPSAyMDE3LCBmcmVxdWVuY3kgPSAxKQ0KDQojIENyZWFyIE1vZGVsbyBBUklNQQ0KIyBNb2RlbG8gQXV0b3JyZWdyZXNpdm8gSW50ZWdyYWRvIGRlIFByb21lZGlvIE1vdmlsLg0KYXJpbWEgPC0gYXV0by5hcmltYSh0cywgRD0xKSAjIEQ9MSBwb3IgbGEgdGVtcG9yYWxpZGFkDQphcmltYQ0Kc3VtbWFyeShhcmltYSkNCg0KIyBHZW5lcmFyIGVsIHByb27Ds3N0aWNvIGRlIHZlbnRhcw0KcHJvbm9zdGljbyA8LSBmb3JlY2FzdChhcmltYSwgbGV2ZWw9OTUsIGg9MzYpDQpwcm9ub3N0aWNvDQpwbG90KHByb25vc3RpY28sIG1haW49IlZlbnRhcyBNZW5zdWFsZXMgeSBQcm9uw7NzdGljbyBhIDMgQcOxb3MgZGVsIENsaWVudGUgNDU2NyIsIHhsYWI9IkHDsW8iLCB5bGFiPSJWZW50YXMgKFF0eSkiKQ0KYGBgDQoNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZDsiPkV2aWRlbmNpYTwvc3Bhbj4NCg0KIyMgUHJlZ3VudGFzIERldG9uYW50ZXMNCg0KMS4gwr9QdWVkZSBvYnNlcnZhcnNlIHVuIGNyZWNpbWllbnRvIGVuIGxhcyB2ZW50YXMgZGUgYWxndW5vcyBkZSBsb3Mgc2VnbWVudG9zIGRlIHByb2R1Y3RvcyBkZSBsYSBmYW1pbGlhIENvY2EgQ29sYSBlbiBsYXMgdGllbmRhcyBlbiBsYXMgcXVlIHNlIGltcGxlbWVudMOzIGVsIFByb3llY3RvIFNpZ2xvIFhYSSBkZSBBcmNhIENvbnRpbmVudGFsPw0KYGBge3J9DQp2ZW50YXNfdG90YWxlc19zZWcgPC0gZGY3ICU+JQ0KICAgZmlsdGVyKFNlZ21lbnRvX0RldCA9PSAiQWd1YSBQdXJpZmljYWRhIiB8IFNlZ21lbnRvX0RldCA9PSAiSXNvdMOzbmljb3MgUmVndWxhciIgfCBTZWdtZW50b19EZXQgPT0gIkNvbGFzIFJlZ3VsYXIiICkgJT4lDQogIGZpbHRlcihBw7FvID09IDIwMTgpICU+JQ0KICBncm91cF9ieShTZWdtZW50b19EZXQsIE7Dum1lcm9fZGVfTWVzKSAlPiUNCiAgc3VtbWFyaXNlKFZlbnRhc19Ub3RhbGVzID0gc3VtKFZlbnRhcykpICU+JQ0KICBhcnJhbmdlKE7Dum1lcm9fZGVfTWVzKQ0KDQpnZ3Bsb3QodmVudGFzX3RvdGFsZXNfc2VnLCBhZXMoeD1Ow7ptZXJvX2RlX01lcywgeT1WZW50YXNfVG90YWxlcyxncm91cD1TZWdtZW50b19EZXQsIGNvbG9yPSBhcy5mYWN0b3IoU2VnbWVudG9fRGV0KSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHg9Ik1lcyIseT0iVmVudGFzIFRvdGFsZXMoUXR5KSIsIHRpdGxlPSAiVmVudGFzIFRvdGFsZXMgcG9yIFNlZ21lbnRvIiwgY29sb3IgPSAiU2VnbWVudG8iKQ0KYGBgDQoNCioqUmVzcHVlc3RhOiBFbiBnZW5lcmFsIGxhcyB2ZW50YXMgYXVtZW50YXJvbiBlbiAyMDE5LCBwZXJvIGNhZGEgc2VnbWVudG8gc2UgY29tcG9ydMOzIGRpZmVyZW50ZS4gRWwgaW5jcmVtZW50byBkZSB2ZW50YXMgc2UgcHVlZGUgbG9ncmFyIGdyYWNpYXMgYSBtZWpvcmVzIGNhbXBhw7FhcyBkZSBtZXJjYWRvdGVjbmlhIHkgbGFuemFtaWVudG8gZGUgbnVldm9zIHByb2R1Y3Rvcy5FbiAyMDE4IGxhIHZlbnRhIGRlIENvY2EtQ29sYSBlbnRyZSBGZWJyZXJvIHkgRGljaWVtYnJlIGF1bWVudMOzIGVuIDEwMCwwMDAgdW5pZGFkZXMsIG1pZW50cmFzIHF1ZSBsYXMgYWd1YXMgaXNvdMOzbmljYXMgbm8gdHV2aWVyb24gY2FtYmlvcy4qKg0KDQoyLiDCv0VsIGluY3JlbWVudG8gZW4gbGFzIHZlbnRhcyBlcyBzaW1pbGFyIGVudHJlIGxvcyBkaWZlcmVudGVzIHRhbWHDsW9zIGRlIGNsaWVudGVzPw0KYGBge3J9DQp2ZW50YXNfdG90YWxlc190YW1fY2xpZW50ZSA8LSBkZjcgJT4lDQogIGZpbHRlcihBw7FvID09IDIwMTkpICU+JQ0KICBncm91cF9ieShUYW1hw7FvX0N0ZV9JbmR1c3RyaWEsIE7Dum1lcm9fZGVfTWVzKSAlPiUNCiAgc3VtbWFyaXNlKFZlbnRhc19Ub3RhbGVzID0gc3VtKFZlbnRhcykpICU+JQ0KICBhcnJhbmdlKE7Dum1lcm9fZGVfTWVzKSAlPiUNCiAgZmlsdGVyKFZlbnRhc19Ub3RhbGVzICE9IDApDQoNCmdncGxvdCh2ZW50YXNfdG90YWxlc190YW1fY2xpZW50ZSwgYWVzKHg9TsO6bWVyb19kZV9NZXMsIHk9VmVudGFzX1RvdGFsZXMsZ3JvdXA9VGFtYcOxb19DdGVfSW5kdXN0cmlhLCBjb2xvcj0gYXMuZmFjdG9yKFRhbWHDsW9fQ3RlX0luZHVzdHJpYSkpKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgbGFicyh4PSJNZXMiLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCB0aXRsZT0gIlZlbnRhcyBUb3RhbGVzIHBvciBUYW1hw7FvIGRlIENsaWVudGUiLCBjb2xvciA9ICJUYW1hw7FvIGRlIENsaWVudGUiKQ0KYGBgDQoNCioqUmVzcHVlc3RhOiBFbCBpbmNyZW1lbnRvIGRlIHZlbnRhcyBlcyBzaW1pbGFyIGluZGVwZW5kaWVudGVtZW50ZSBkZSBsb3MgdGFtYcOxb3MgZGUgbG9zIGNsaWVudGVzLiBDb21vIHRvZG9zIGxvcyBuZWdvY2lvcyBlc3TDoW4gYWJpZXJ0b3MgbG9zIG1pc21vcyBkw61hcywgeSBlc3TDoW4gdWJpY2Fkb3MgZW4gbGEgbWlzbWEgY2l1ZGFkIChHdWFkYWxhamFyYSksIGxvcyBmYWN0b3JlcyBleHRlcm5vcyBkZSBsYXMgdmVudGFzIGVmZWN0YW4gY2FzaSBpZ3VhbCBhIHRvZG9zLiBFbCBtZXMgZGUgbWF5byBkZSAyMDE5IGZ1ZSBlbCBkZSBtYXlvciB2ZW50YXMgZW4gdG9kb3MgbG9zIHRhbWHDsW9zIGRlIGNsaWVudGUsIHkgZWwgcHJpbWVyIGJpbWVzdHJlIGZ1ZSBlbCBtw6FzIGJham8gdGFtYmnDqW4gcGFyYSB0b2RvcyBsb3MgdGFtYcOxb3MgZGUgY2xpZW50ZS4qKg0KDQozLiDCv0N1w6FsIGVzIGVsIGNvbXBvcnRhbWllbnRvIG9ic2VydmFkbyBkZSBsYXMgdW5pZGFkZXMgdmVuZGlkYXMgcG9yIG1lcyBkZSBjYWRhIHVuYSBkZSBsYXMgbWFyY2FzLCBpbmRlcGVuZGllbnRlbWVudGUgZGUgc3VzIHJlc3BlY3RpdmFzIHByZXNlbnRhY2lvbmVzPw0KYGBge3J9DQp2ZW50YXNfdG90YWxlc19tYXJjYSA8LSBkZjcgJT4lDQogIGZpbHRlcihBw7FvID09IDIwMTkpICU+JQ0KICBmaWx0ZXIoTWFyY2EgPT0gYygiQ29jYS1Db2xhIiwgIlZhbGxlIEZydXQiLCAiQ2llbCBBZ3VhIFB1cmlmaWNhZGEiLCJDb2NhLUNvbGEgTGlnaHQiKSkgJT4lDQogIGdyb3VwX2J5KE1hcmNhLCBOw7ptZXJvX2RlX01lcykgJT4lDQogIHN1bW1hcmlzZShWZW50YXNfVG90YWxlcyA9IHN1bShWZW50YXMpKSAlPiUNCiAgYXJyYW5nZShOw7ptZXJvX2RlX01lcykgJT4lDQogIGZpbHRlcihWZW50YXNfVG90YWxlcyAhPSAwKQ0KDQpnZ3Bsb3QodmVudGFzX3RvdGFsZXNfbWFyY2EsIGFlcyh4PU7Dum1lcm9fZGVfTWVzLCB5PVZlbnRhc19Ub3RhbGVzLGdyb3VwPU1hcmNhLCBjb2xvcj0gYXMuZmFjdG9yKE1hcmNhKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHg9Ik1lcyIseT0iVmVudGFzIFRvdGFsZXMoUXR5KSIsIHRpdGxlPSAiVmVudGFzIFRvdGFsZXMgcG9yIE1hcmNhIiwgY29sb3IgPSAiTWFyY2EiKQ0KYGBgDQoNCioqUmVzcHVlc3RhOiBFbCBjb21wb3J0YW1pZW50byBkZSB2ZW50YXMgZXMgc2ltaWxhciBlbnRyZSBsYXMgbWFyY2FzIGEgdHJhdsOpcyBkZSBsb3MgbWVzZXMsIHBlcm8gaGF5IG1hcmNhcyBxdWUgdmVuZGVuIG11Y2hvIG3DoXMgcXVlIG90cmFzLiBMb3MgbWVzZXMgZGUgbcOhcyB2ZW50YXMgZGUgYmViaWRhcyBzb24gbG9zIG1lc2VzIGVuIHF1ZSBsYSB0ZW1wZXJhdHVyYSBlcyBtYXlvciwgeSBsYXMgbWFyY2FzIG3DoXMgY29ub2NpZGFzIHNvbiBsYXMgcXVlIHRpZW5lIGVuIG1lbnRlIGVsIGNvbnN1bWlkb3IuIEVsIG1lcyBkZSBtYXlvIDIwMTkgZXMgcGFyYSB0b2RhcyBsYXMgbWFyY2FzIGVsIGRlIG1heW9yZXMgdmVudGFzLCBwZXJvIGxhIG1hcmNhIENvY2EtQ29sYSBlcyBsYSBxdWUgdmVuZGUgbcOhcyBxdWUgdG9kYXMuKioNCg0KNC4gwr9TZSBoYSBpbmNyZW1lbnRhZG8gbGEgdmVudGEgZGUgcHJvZHVjdG9zIGVuIGVudmFzZXMgcmV0b3JuYWJsZXMgZW4gbG9zIMO6bHRpbW9zIGRvcyBhw7Fvcz8NCmBgYHtyfQ0KdmVudGFzX3RvdGFsZXNfZW52YXNlIDwtIGRmNyAlPiUNCiAgZmlsdGVyKFJldG9ybmFibGVfTlI9PSJSZXRvcm5hYmxlIikgJT4lDQogIGZpbHRlcihBw7FvID09IGMoMjAxNywyMDE4LDIwMTkpKSAlPiUNCiAgZ3JvdXBfYnkoQcOxbywgTsO6bWVyb19kZV9NZXMpICU+JQ0KICBzdW1tYXJpc2UoVmVudGFzX1RvdGFsZXMgPSBzdW0oVmVudGFzKSkgJT4lDQogIGFycmFuZ2UoTsO6bWVyb19kZV9NZXMpICU+JQ0KICBmaWx0ZXIoVmVudGFzX1RvdGFsZXMgIT0gMCkNCg0KZ2dwbG90KHZlbnRhc190b3RhbGVzX2VudmFzZSwgYWVzKHg9TsO6bWVyb19kZV9NZXMsIHk9VmVudGFzX1RvdGFsZXMsZ3JvdXA9QcOxbywgY29sb3I9IGFzLmZhY3RvcihBw7FvKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHg9Ik1lcyIseT0iVmVudGFzIFRvdGFsZXMoUXR5KSIsIHRpdGxlPSAiVmVudGFzIFRvdGFsZXMgZGUgRW52YXNlcyBSZXRvcm5hYmxlcyIsIGNvbG9yID0gIkHDsW8iKQ0KYGBgDQoNCioqUmVzcHVlc3RhOiBMYSB2ZW50YSBkZSBwcm9kdWN0b3MgZW4gZW52YXNlIHJldG9ybmFibGUgYXVtZW50w7MgZW4gbG9zIMO6bHRpbW9zIGRvcyBhw7Fvcy4gTGFzIGNhbXBhw7FhcyBkZSBjb25jaWVuY2lhIGFtYmllbnRhbCBoYW4gdnVlbHRvIHBvcHVsYXJlcyBsYXMgb3BjaW9uZXMgbWVub3MgZGHDsWluYXMgYWwgZWNvc2lzdGVtYS4gRGUgMjAxNyBhIDIwMTggaHVibyB1biBsaWdlcm8gaW5jcmVtZW50byBlbiBsYXMgdmVudGFzIGRlIGVudmFzZSByZXRvcm5hYmxlLCB5IGVudHJlIDIwMTggeSAyMDE5IGVsIGF1bWVudG8gZnVlIG11eSBub3RvcmlvLioqICANCg0KKipOb3RhczogSGF5IG90cm9zIGZhY3RvcmVzIGEgY29uc2lkZXJhciBjb21vIHF1ZSBlbiAyMDE5IGhheSBtw6FzIHRpZW5kYXMgY29uIGVsIHByb3llY3RvIFNpZ2xvIFhYSSwgbyBxdWUgbGFzIHRpZW5kYXMgZW4gZ2VuZXJhbCB2ZW5kZW4gbcOhcyBwcm9kdWN0b3MgKHRhbnRvIHJldG9ybmFibGVzIGNvbW8gbm8gcmV0b3JuYWJsZXMpLioqDQoNCjUuIMK/RWwgY29tcG9ydGFtaWVudG8gZGUgbGEgdmVudGEgZGUgYWd1YSBoYSBpbmNyZW1lbnRhZG8gZW4gcmVsYWNpw7NuIGFsIGRlIGxvcyByZWZyZXNjb3MgbyBsYXMgYmViaWRhcyBpc290w7NuaWNhcz8NCmBgYHtyfQ0KdmVudGFzX3RvdGFsZXNfc2VnIDwtIGRmNyAlPiUNCiAgIGZpbHRlcihTZWdtZW50b19EZXQgPT0gIkFndWEgUHVyaWZpY2FkYSIgfCBTZWdtZW50b19EZXQgPT0gIklzb3TDs25pY29zIFJlZ3VsYXIiIHwgU2VnbWVudG9fRGV0ID09ICJDb2xhcyBSZWd1bGFyIiApICU+JQ0KICBmaWx0ZXIoQcOxbyA9PSAyMDE4KSAlPiUNCiAgZ3JvdXBfYnkoU2VnbWVudG9fRGV0LCBOw7ptZXJvX2RlX01lcykgJT4lDQogIHN1bW1hcmlzZShWZW50YXNfVG90YWxlcyA9IHN1bShWZW50YXMpKSAlPiUNCiAgYXJyYW5nZShOw7ptZXJvX2RlX01lcykNCg0KZ2dwbG90KHZlbnRhc190b3RhbGVzX3NlZywgYWVzKHg9TsO6bWVyb19kZV9NZXMsIHk9VmVudGFzX1RvdGFsZXMsZ3JvdXA9U2VnbWVudG9fRGV0LCBjb2xvcj0gYXMuZmFjdG9yKFNlZ21lbnRvX0RldCkpKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgbGFicyh4PSJNZXMiLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCB0aXRsZT0gIlZlbnRhcyBUb3RhbGVzIHBvciBTZWdtZW50byIsIGNvbG9yID0gIlNlZ21lbnRvIikNCmBgYA0KDQoqKlJlc3B1ZXN0YTogTGFzIHZlbnRhcyBkZSBBZ3VhIFB1cmlmaWNhZGEgbm8gaGEgYXVtZW50YWRvIGVuIHJlbGFjacOzbiBhIFJlZnJlc2NvcyBvIEJlYmlkYXMgSXNvdMOzbmljYXMuIExhIHBlcnNlcGNpw7NuIHF1ZSBlbCBhZ3VhIG5vIHRpZW5lIHZhbG9yIGFncmVnYWRvIGVuIGxhIHByZXBhcmFjacOzbiB5IGVsIGF6w7pjYXIgZW4gbGEgcmVjZXRhIGhhY2VuIGRlIGxvcyByZWZyZXNjb3MgbGEgb3BjacOzbiBwcmVmZXJpZGEgZGUgbG9zIGNvbnN1bWlkb3JlcyBtZXhpY2Fub3MuIEVuIDIwMTggbGFzIHZlbnRhcyB0b3RhbGVzIGRlIEFndWEgUHVyaWZpY2FkYSBubyBzdXBlcmFyb24gbGFzIDUwLDAwMCB1bmlkYWRlcywgbWllbnRyYXMgcXVlIGxhIENvY2EtQ29sYSB2ZW5kacOzIGVuIHN1IG1lcyBtw6FzIGFsdG8gNDUwLDAwMCAoOCB2ZWNlcyBtw6FzIHF1ZSBlbCBhZ3VhKS4qKg0KDQo2LiDCv1B1ZWRlIGRlY2lyc2UgcXVlIGxhIHZlbnRhIG1lbnN1YWwgZGUgYWd1YSBlc3TDoSByZWxhY2lvbmFkYSBjb24gbGEgdmVudGEgbWVuc3VhbCBkZSByZWZyZXNjb3MgZW4gbG9zIMO6bHRpbW9zIDQgYcOxb3M/DQpgYGB7cn0NCnZlbnRhc190b3RhbGVzX2F5ciA8LSBkZjcgJT4lDQogICBmaWx0ZXIoU2VnbWVudG9fRGV0ID09IGMoIkFndWEgUHVyaWZpY2FkYSIsICJDb2xhcyBSZWd1bGFyIikpICU+JQ0KICBncm91cF9ieShTZWdtZW50b19EZXQsIEHDsW8pICU+JQ0KICBzdW1tYXJpc2UoVmVudGFzX1RvdGFsZXMgPSBzdW0oVmVudGFzKSkgDQogIA0KZ2dwbG90KHZlbnRhc190b3RhbGVzX2F5ciwgYWVzKHg9QcOxbywgeT1WZW50YXNfVG90YWxlcyxncm91cD1TZWdtZW50b19EZXQsIGNvbG9yPSBhcy5mYWN0b3IoU2VnbWVudG9fRGV0KSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHg9IkHDsW8iLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCB0aXRsZT0gIlZlbnRhcyBUb3RhbGVzIHBvciBTZWdtZW50byIsIGNvbG9yID0gIlNlZ21lbnRvIikNCmBgYA0KDQoqKlJlc3B1ZXN0YTogTGEgdmVudGEgZGUgYWd1YSB5IHJlZnJlc2NvcyBzZSBpbmNyZW1lbnRhIGVuIGxvcyBtaXNtb3MgbWVzZXMsIHkgYSB0cmF2w6lzIGRlIGxvcyBhw7FvcywgcGVybyBubyBzZSBwdWVkZSBjb25jbHVpciBxdWUgdW4gaW5jcmVtZW50byBjYXVzZSBlbCBvdHJvLiBMb3MgbWVzZXMgY2FsdXJvc29zIHkgZWwgY3JlY2ltaWVudG8gZGUgbGEgcG9ibGFjacOzbiBoYWNlIHF1ZSBsYXMgdmVudGFzIHNlIGluY3JlbWVudGVuIGVuIGxhcyBiZWJpZGFzLCBzZWFuIGFndWEgbyByZWZyZXNjby4gRW4gbGEgZ3LDoWZpY2Egb2J0ZW5pZGEgc2Ugb2JzZXJ2YSB1biBpbmNyZW1lbnRvIGHDsW8gY29uIGHDsW8gZW4gbGEgdmVudGEgZGUgYWd1YSB5IHRhbWJpw6luIGRlIHJlZnJlc2Nvcy4gKioNCg0KNy4gwr9BIGN1w6FudG8gYXNjaWVuZGVuIGxhcyB2ZW50YXMgZXNwZXJhZGFzIHBhcmEgZWwgMjAyMCBlbiBsYSBDb2NhIENvbGEgZGUgNTAwIG1sIE5SIFZpZHJpbz8NCmBgYHtyfQ0KdmVudGFzX2NvY2FfdmlkcmlvIDwtIGRmNyAlPiUNCiAgZmlsdGVyKE1hcmNhID09ICJDb2NhLUNvbGEiICYgUHJlc2VudGFjaW9uID09ICI1MDAgbWwgTlIgVmlkcmlvIikgJT4lDQogIGdyb3VwX2J5KEHDsW8sIE7Dum1lcm9fZGVfTWVzKSAlPiUNCiAgc3VtbWFyaXNlKFZlbnRhc19Ub3RhbGVzID0gc3VtKFZlbnRhcykpICU+JQ0KICBmaWx0ZXIoVmVudGFzX1RvdGFsZXMgIT0gMCkNCg0KIyBDb25maXJtYXIgcXVlIGxvcyBkYXRvcyBxdWUgcXVlcmVtb3MgbW9kZWxhciBlc3RlbiBvcmRlbmFkb3MgY3Jvbm9sw7NnaWNhbWVudGUuDQoNCiMgRnVuY2nDs24gZGUgU2VyaWUgZGUgVGllbXBvIE1FTlNVQUwsIHF1ZSBpbmljaWEgZW4gRW5lcm8gMjAxNw0KdHMgPC0gdHMoZGF0YT12ZW50YXNfY29jYV92aWRyaW8kVmVudGFzX1RvdGFsZXMsIHN0YXJ0ID0gYygyMDE2LDEpLCBmcmVxdWVuY3kgPSAxMikNCg0KIyBDcmVhciBNb2RlbG8gQVJJTUENCiMgTW9kZWxvIEF1dG9ycmVncmVzaXZvIEludGVncmFkbyBkZSBQcm9tZWRpbyBNb3ZpbC4NCmFyaW1hIDwtIGF1dG8uYXJpbWEodHMsIEQ9MSkgIyBEPTEgcG9yIGxhIHRlbXBvcmFsaWRhZA0KYXJpbWENCnN1bW1hcnkoYXJpbWEpDQoNCiMgR2VuZXJhciBlbCBwcm9uw7NzdGljbyBkZSB2ZW50YXMNCnByb25vc3RpY28gPC0gZm9yZWNhc3QoYXJpbWEsIGxldmVsPTk1LCBoPTE2KQ0KcHJvbm9zdGljbw0KcGxvdChwcm9ub3N0aWNvLCBtYWluPSJWZW50YXMgTWVuc3VhbGVzIHkgUHJvbsOzc3RpY28gcGFyYSAyMDIwIGRlIENvY2EtQ29sYSA1MDAgbWwgTlIgVmlkcmlvIiwgeGxhYj0iQcOxbyIsICB5bGFiPSJWZW50YXMgKFF0eSkiKQ0KYGBgDQoNCioqUmVzcHVlc3RhOiBMYXMgdmVudGFzIGVzcGVyYWRhcyBkZSBDb2NhLUNvbGEgZGUgNTAwIG1sIE5SIFZpZHJpbyBwYXJhIDIwMjAgb3NjaWxhbiBtZW5zdWFsbWVudGUgZW50cmUgNDUsMDAwIHkgNjUsMDAwIHVuaWRhZGVzLCBjb24gdW5hIGNvbmZpYWJpbGlkYWQgZGVsIDk1JS4qKg0KDQojIyBDb25jbHVzaW9uZXMgDQpFbCB2ZXIgbG9zIHJlc3VsdGFkb3MgZGUgbGEgYWN0aXZpZGFkZXMgcmVhbG1lbnRlIG11ZXN0cmEgbGEgdXRpbCBxdWUgcHVlZGUgbGxlZ2FyIGEgc2VyIFIgcGFyYSBlbCBhbmFsaXNpcyBkZSBkYXRvcywgZWwgcG9kZXIgc2VyIGNhcGF6IG5vIHNvbG8gZGUgbGltcGlhciBsYXMgYmFzZXMgZGUgZGF0b3MsIHNpbm8gZWwgcmVhbG1lbnRlIHNlciBjYXBheiBkZSBjcmVhciBncmFmaWNhcyBwZXJzb25hbGl6YWRhcyBhIGxhcyBuZWNlc2lkYWRlcyBxdWUgc2Ugb2N1cGFuLCBlbCB1dGlsaXphciBSIGJyaW5kYSB1bmEgbnVldmEgb3BvcnR1bmlkYWQgcGFyYSBwb2RlciBzZXIgY2FwYXogZGUgZW50ZW5kZXIgbGEgaW5mb3JtYWNpb24gZW4gdW4gbnVldm8gbml2ZWwsIGxhIHNlciBjYXBheiBkZSBlbmNvbnRyYXIgY29zYXMgcXVlIHVubyBubyBzZXJpYSBjYXBheiBkZSBoYWNlciBkZSBtYW5lcmEgdHJhZGljaW9uYWwsIGFzaSBtaXNtbyBmdWUgc3VtYW1lbnRlIGludGVyZXNhbnJlIGVsIHZlciBjb21vIGVzIHF1ZSBSIHRpZW5lIHRhbWJpZW4gc3VzIGVycm9yZXMgcG9yIGxvIGN1YWwgY29uc2lkZXJvIHF1ZSBhcHJlbmRlciBSIG1hcyBhIGRldGFsbGUgZXMgdW5hIGdyYW4gb3BjaW9uIHkgYWxnbyBtdXkgaW50ZXJlc2FudGUgcGVybyB0YW1iaWVuIHB1ZGUgYmVyIHF1ZSBwdWVkZSBsbGVnYXIgYSBzZXIgdW4gcG9jbyBtYXMgY29tcGxpY2Fkby4NCg==