Contexto

Para Arca Continental su principal canal de distribuciĂ³n es el canal tradicional, es decir, las tienditas de la esquina. Esto permite que la familia de productos de la compañía Coca Cola estĂ©n siempre cerca de sus consumidores a travĂ©s de estas pequeñas empresas familiares que forman parte de su propia comunidad.

InstalaciĂ³n y llamar librerĂ­as

# install.packages("readxl") # Importar archivo de Excel
library(readxl)
# install.packages("DataExplorer") # Para realizar AnĂ¡lisis Descriptivo
library(DataExplorer)
# install.packages("dplyr")
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
# install.packages("forecast")
library(forecast)
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
# install.packages("ggplot2")
library(ggplot2)
# install.packages("tidyverse")
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ lubridate 1.9.3     ✔ tibble    3.2.1
## ✔ purrr     1.0.2     ✔ tidyr     1.3.1
## ✔ readr     2.1.5
## ── 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

Importar la base de datos

# file.choose()
df <- read_excel("/Users/estebanloyo/Desktop/Codes/RStudio/Bootcamp/Datos Arca Continental Original.xlsx")
colnames(df) <- make.names(colnames(df))

AnĂ¡lisis Descriptivo

summary(df)
##        ID              Año        Territorio        Sub.Territorio    
##  Min.   :     1   Min.   :2016   Length:466509      Length:466509     
##  1st Qu.:116628   1st Qu.:2017   Class :character   Class :character  
##  Median :233255   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:466509      Length:466509      Length:466509      Length:466509       
##  Class :character   Class :character   Class :character   Class :character    
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character    
##                                                                               
##                                                                               
##                                                                               
##                                                                               
##  Segmento.Det          Marca           Presentacion          Tamaño         
##  Length:466509      Length:466509      Length:466509      Length:466509     
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##  Retornable_NR          Enero            Febrero             Marzo         
##  Length:466509      Min.   :  -19.0   Min.   :  -11.00   Min.   :  -32.00  
##  Class :character   1st Qu.:    1.0   1st Qu.:    1.00   1st Qu.:    1.00  
##  Mode  :character   Median :    2.0   Median :    2.00   Median :    3.00  
##                     Mean   :   10.1   Mean   :    9.76   Mean   :   11.36  
##                     3rd Qu.:    6.0   3rd Qu.:    6.00   3rd Qu.:    6.00  
##                     Max.   :42736.0   Max.   :42767.00   Max.   :42795.00  
##                     NA's   :233480    NA's   :231213     NA's   :227420    
##      Abril               Mayo              Junio             Julio         
##  Min.   :  -70.00   Min.   : -106.00   Min.   : -211.0   Min.   :  -60.00  
##  1st Qu.:    1.00   1st Qu.:    1.00   1st Qu.:    1.0   1st Qu.:    1.00  
##  Median :    3.00   Median :    3.00   Median :    3.0   Median :    2.00  
##  Mean   :   11.71   Mean   :   12.75   Mean   :   12.2   Mean   :   11.75  
##  3rd Qu.:    6.00   3rd Qu.:    7.00   3rd Qu.:    6.0   3rd Qu.:    6.00  
##  Max.   :42826.00   Max.   :42856.00   Max.   :42887.0   Max.   :42917.00  
##  NA's   :224057     NA's   :216910     NA's   :215753    NA's   :223411    
##      Agosto           Septiembre         Octubre          Noviembre      
##  Min.   : -211.00   Min.   : -527.0   Min.   :  -38.0   Min.   :  -25.0  
##  1st Qu.:    1.00   1st Qu.:    1.0   1st Qu.:    1.0   1st Qu.:    1.0  
##  Median :    3.00   Median :    3.0   Median :    3.0   Median :    3.0  
##  Mean   :   11.98   Mean   :   13.4   Mean   :   13.7   Mean   :   13.3  
##  3rd Qu.:    6.00   3rd Qu.:    7.0   3rd Qu.:    7.0   3rd Qu.:    6.0  
##  Max.   :42948.00   Max.   :42979.0   Max.   :43009.0   Max.   :43040.0  
##  NA's   :220242     NA's   :337314    NA's   :338386    NA's   :338460   
##    Diciembre      
##  Min.   :  -28.0  
##  1st Qu.:    1.0  
##  Median :    3.0  
##  Mean   :   14.8  
##  3rd Qu.:    7.0  
##  Max.   :43070.0  
##  NA's   :341855
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 ...
# create_report(df)
introduce(df)
## # A tibble: 1 Ă— 9
##     rows columns discrete_columns continuous_columns all_missing_columns
##    <int>   <int>            <int>              <int>               <int>
## 1 466509      25               11                 14                   0
## # ℹ 4 more variables: total_missing_values <int>, complete_rows <int>,
## #   total_observations <int>, memory_usage <dbl>
plot_intro(df)

plot_missing(df)

plot_histogram(df)

plot_bar(df)
## 4 columns ignored with more than 50 categories.
## Cliente: 5249 categories
## Nombre: 1090 categories
## Marca: 56 categories
## Presentacion: 57 categories

plot_correlation(df)
## 5 features with more than 20 categories ignored!
## Cliente: 5249 categories
## Nombre: 1090 categories
## Segmento.Det: 21 categories
## Marca: 56 categories
## Presentacion: 57 categories

count(df, Territorio, sort = T)
## # A tibble: 2 Ă— 2
##   Territorio       n
##   <chr>        <int>
## 1 Guadalajara 466508
## 2 Territorio       1
count(df, Sub.Territorio, sort = T)
## # A tibble: 4 Ă— 2
##   Sub.Territorio      n
##   <chr>           <int>
## 1 Belenes        208982
## 2 HuentitĂ¡n      144196
## 3 Toluquilla     113330
## 4 Sub Territorio      1
count(df, CEDI , sort = T)
## # A tibble: 4 Ă— 2
##   CEDI                 n
##   <chr>            <int>
## 1 Suc. Belenes    208982
## 2 Suc. HuentitĂ¡n  144196
## 3 Suc. Toluquilla 113330
## 4 CEDI                 1
count(df, Cliente, sort = T)
## # A tibble: 5,249 Ă— 2
##    Cliente     n
##    <chr>   <int>
##  1 0286      647
##  2 2912      586
##  3 2661      537
##  4 7821      531
##  5 1859      525
##  6 5583      516
##  7 9998      508
##  8 3601      506
##  9 5879      499
## 10 0335      496
## # ℹ 5,239 more rows
count(df, Nombre, sort = T)
## # A tibble: 1,090 Ă— 2
##    Nombre     n
##    <chr>  <int>
##  1 ABARR  71186
##  2 MARIA  39816
##  3 JOSE   17479
##  4 JUAN    7580
##  5 MARTH   5759
##  6 MISCE   5700
##  7 LUIS    5585
##  8 SUPER   4565
##  9 CARLO   3991
## 10 ROSA    3890
## # ℹ 1,080 more rows
count(df, Tamaño.Cte.Industria, sort = T)
## # A tibble: 5 Ă— 2
##   Tamaño.Cte.Industria      n
##   <chr>                 <int>
## 1 Extra Grande         230190
## 2 Micro                117110
## 3 Pequeño               77875
## 4 Grande                41333
## 5 Tamaño Cte Industria      1
count(df, Segmento.Det, sort = T)
## # A tibble: 21 Ă— 2
##    Segmento.Det            n
##    <chr>               <int>
##  1 Sabores Regular    156242
##  2 Colas Regular       95720
##  3 Colas Light         43807
##  4 Jugos y Néctares    33362
##  5 Bebidas de Fruta    30641
##  6 Agua Purificada     20766
##  7 Agua Mineral        12590
##  8 IsotĂ³nicos Regular  11905
##  9 TĂ© Regular          10062
## 10 Agua Saborizada     10056
## # ℹ 11 more rows
count(df, Marca, sort = T)
## # A tibble: 56 Ă— 2
##    Marca                    n
##    <chr>                <int>
##  1 Coca-Cola            95720
##  2 Sprite               37925
##  3 Fanta                35728
##  4 Fresca               26435
##  5 Manzana Lift         25598
##  6 Coca-Cola Light      21926
##  7 Del Valle            21325
##  8 Ciel Agua Purificada 20766
##  9 Sidral Mundet        17150
## 10 Valle Frut           15808
## # ℹ 46 more rows
count(df, Presentacion, sort = T)
## # A tibble: 57 Ă— 2
##    Presentacion         n
##    <chr>            <int>
##  1 600 ml NR        74008
##  2 1 Ltro. N.R.     36930
##  3 2 Lts. NR        36415
##  4 500 ml Ret       35165
##  5 1.5 Lts. NR      30637
##  6 Lata 235 ml      24551
##  7 400 ml NR        22877
##  8 250 ml. NR PET   21735
##  9 500 ml NR Vidrio 18758
## 10 2.5 Lts. NR      13235
## # ℹ 47 more rows
count(df, Tamaño, sort = T)
## # A tibble: 3 Ă— 2
##   Tamaño          n
##   <chr>       <int>
## 1 Individual 328513
## 2 Familiar   137995
## 3 Tamaño          1
count(df, Retornable_NR, sort = T)
## # A tibble: 3 Ă— 2
##   Retornable_NR      n
##   <chr>          <int>
## 1 No Retornable 403226
## 2 Retornable     63282
## 3 Retornable_NR      1

Limpieza de la Base de Datos

# Revisar NAs en la base de datos
# CuĂ¡ntos NAs tengo en la base de datos?

sum(is.na(df))
## [1] 3148501
# CuĂ¡ntas 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
# Reemplazar NAs con CEROS
df[is.na(df)] <- 0
sum(is.na(df))
## [1] 0
## Detectar valores atĂ­picos
boxplot(df$Enero)

# Eliminar renglĂ³n de los totales
df <- df[df$Enero <6000, ]
boxplot(df$Enero)

AnĂ¡lisis de Ventas (Tarea Colaborativa 1)

df1 <- df

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

RegresiĂ³n lineal

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

Series de Tiempo

ventas_mensuales_4567 <- df7 %>%
  filter(Cliente == "4567") %>%
  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_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 2019, las ventas en general mostraron un crecimiento, aunque cada segmento tuvo un comportamiento distinto. Este incremento en las ventas pudo lograrse mediante campañas de mercadotecnia mĂ¡s efectivas y la introducciĂ³n de nuevos productos. En 2018, las ventas de Coca-Cola entre febrero y diciembre crecieron en 100,000 unidades, mientras que las ventas de aguas isotĂ³nicas permanecieron estables durante el mismo perĂ­odo.

  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 aumento en las ventas fue consistente sin importar el tamaño de los clientes, ya que todos los negocios operan los mismos dĂ­as y se encuentran en la misma ciudad (Guadalajara), lo que hace que los factores externos afecten de manera similar a todos. El mes de mayo de 2019 registrĂ³ el mayor volumen de ventas para todos los tamaños de clientes, mientras que el primer bimestre del año tuvo el nivel de ventas mĂ¡s bajo, tambiĂ©n de manera uniforme para todos los segmentos de clientes.

  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 muestra una tendencia similar entre las diferentes marcas a lo largo de los meses; sin embargo, algunas marcas registran ventas significativamente mayores que otras. Los periodos de mayor venta de bebidas coinciden con los meses de temperaturas mĂ¡s elevadas, y las marcas mĂ¡s reconocidas son las que los consumidores tienden a preferir. En mayo de 2019, todas las marcas experimentaron su pico mĂ¡s alto de ventas, siendo Coca-Cola la marca con el volumen de ventas mĂ¡s elevado.

  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: Las ventas de productos en envases retornables han aumentado en los Ăºltimos dos años, impulsadas por campañas de conciencia ambiental que han popularizado las opciones mĂ¡s ecolĂ³gicas. De 2017 a 2018, se observĂ³ un leve incremento en las ventas de envases retornables, mientras que entre 2018 y 2019 este crecimiento fue mucho mĂ¡s significativo.

Notas: Existen otros factores que tambiĂ©n deben tenerse en cuenta, como el hecho de que en 2019 hay mĂ¡s tiendas participando en el proyecto Siglo XXI, lo que podrĂ­a haber contribuido al aumento en ventas. AdemĂ¡s, en general, las tiendas han experimentado un incremento en la venta de productos, tanto en envases retornables como no retornables, lo que refleja un crecimiento en la demanda y posiblemente un mayor enfoque en las estrategias comerciales.

  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 han mostrado el mismo crecimiento en comparaciĂ³n con Refrescos o Bebidas IsotĂ³nicas. Esto se debe a la percepciĂ³n de que el agua no ofrece un valor agregado en su preparaciĂ³n y a que el azĂºcar presente en los refrescos los convierte en la opciĂ³n preferida de los consumidores mexicanos. En 2018, las ventas totales de Agua Purificada no superaron las 50,000 unidades, mientras que Coca-Cola alcanzĂ³ su pico de ventas con 450,000 unidades en su mes mĂ¡s alto, vendiendo ocho 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: Las ventas de agua y refrescos muestran un aumento durante los mismos meses y a lo largo de los años; sin embargo, no es posible concluir que el incremento en la venta de uno cause el incremento en el otro. Este aumento en ventas coincide con los meses mĂ¡s calurosos y con el crecimiento de la poblaciĂ³n, lo que impulsa una mayor demanda de bebidas, ya sea agua o refrescos. La grĂ¡fica obtenida refleja un incremento constante año tras año en las ventas tanto de agua como 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.7436
## s.e.  0.1328  299.8430
## 
## sigma^2 = 41602809:  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.7436
## s.e.  0.1328  299.8430
## 
## sigma^2 = 41602809:  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.66702 5325.932 3245.859 -1.373606 8.085645 0.3668337 -0.1551565
# Generar el pronĂ³stico de ventas
pronostico <- forecast(arima, level=95, h=16)
pronostico
##          Point Forecast    Lo 95    Hi 95
## Sep 2019       57009.58 44367.77 69651.40
## Oct 2019       47611.62 32113.16 63110.08
## Nov 2019       43891.25 27139.04 60643.45
## Dec 2019       49988.01 32639.38 67336.63
## Jan 2020       52649.69 35008.69 70290.69
## Feb 2020       59116.66 41330.41 76902.91
## Mar 2020       63214.67 45355.81 81073.53
## Apr 2020       45929.93 28034.66 63825.21
## May 2020       77894.00 59980.44 95807.57
## Jun 2020       66917.27 48994.51 84840.02
## Jul 2020       65104.33 47176.96 83031.71
## Aug 2020       66475.77 48546.08 84405.47
## Sep 2020       65846.40 43789.47 87903.33
## Oct 2020       56390.31 32525.70 80254.93
## Nov 2020       52628.72 27904.75 77352.68
## Dec 2020       58696.24 33551.13 83841.36
plot(pronostico, main="Ventas Mensuales y PronĂ³stico para 2020 de Coca-Cola 500 ml NR Vidrio", xlab="Año",  ylab="Ventas (Qty)")

Respuesta: Para 2020, las ventas proyectadas de Coca-Cola de 500 ml en envase de vidrio no retornable se esperan que varĂ­en mensualmente entre 45,000 y 65,000 unidades, con un nivel de confianza del 95%.

LS0tCnRpdGxlOiAiRXZpZGVuY2lhIgphdXRob3I6ICJFc3RlYmFuIExveW8gLSBBMDA4Mzc3MjUiCmRhdGU6ICIyMDI0LTA5LTExIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQogICAgY29kZV9kb3dubG9hZDogVFJVRQogICAgdGhlbWU6IHVuaXRlZAplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKLS0tCiFbXSgvVXNlcnMvZXN0ZWJhbmxveW8vRGVza3RvcC9Db2Rlcy9SU3R1ZGlvL0Jvb3RjYW1wL0FyY2FfQ29udGluZW50YWxfY29tcGxldGFfZW1pc2luX2V4aXRvc2FfZGVfYm9ub3NfZW5fTXhpY28uanBnKQoKIyA8c3BhbiBzdHlsZT0gImNvbG9yOiByZWQ7Ij5Db250ZXh0bzwvc3Bhbj4KUGFyYSBBcmNhIENvbnRpbmVudGFsIHN1IHByaW5jaXBhbCBjYW5hbCBkZSBkaXN0cmlidWNpw7NuIGVzIGVsIGNhbmFsIHRyYWRpY2lvbmFsLCBlcyBkZWNpciwgbGFzIHRpZW5kaXRhcyBkZSBsYSBlc3F1aW5hLiBFc3RvIHBlcm1pdGUgcXVlIGxhIGZhbWlsaWEgZGUgcHJvZHVjdG9zIGRlIGxhIGNvbXBhw7HDrWEgQ29jYSBDb2xhIGVzdMOpbiBzaWVtcHJlIGNlcmNhIGRlIHN1cyBjb25zdW1pZG9yZXMgYSB0cmF2w6lzIGRlIGVzdGFzIHBlcXVlw7FhcyBlbXByZXNhcyBmYW1pbGlhcmVzIHF1ZSBmb3JtYW4gcGFydGUgZGUgc3UgcHJvcGlhIGNvbXVuaWRhZC4KCiMgPHNwYW4gc3R5bGU9ICJjb2xvcjogcmVkOyI+SW5zdGFsYWNpw7NuIHkgbGxhbWFyIGxpYnJlcsOtYXM8L3NwYW4+CmBgYHtyIHdhcm5pbmc9RkFMU0V9CiMgaW5zdGFsbC5wYWNrYWdlcygicmVhZHhsIikgIyBJbXBvcnRhciBhcmNoaXZvIGRlIEV4Y2VsCmxpYnJhcnkocmVhZHhsKQojIGluc3RhbGwucGFja2FnZXMoIkRhdGFFeHBsb3JlciIpICMgUGFyYSByZWFsaXphciBBbsOhbGlzaXMgRGVzY3JpcHRpdm8KbGlicmFyeShEYXRhRXhwbG9yZXIpCiMgaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQpsaWJyYXJ5KGRwbHlyKQojIGluc3RhbGwucGFja2FnZXMoImZvcmVjYXN0IikKbGlicmFyeShmb3JlY2FzdCkKIyBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKbGlicmFyeShnZ3Bsb3QyKQojIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCiMgPHNwYW4gc3R5bGU9ICJjb2xvcjogcmVkOyI+SW1wb3J0YXIgbGEgYmFzZSBkZSBkYXRvczwvc3Bhbj4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CiMgZmlsZS5jaG9vc2UoKQpkZiA8LSByZWFkX2V4Y2VsKCIvVXNlcnMvZXN0ZWJhbmxveW8vRGVza3RvcC9Db2Rlcy9SU3R1ZGlvL0Jvb3RjYW1wL0RhdG9zIEFyY2EgQ29udGluZW50YWwgT3JpZ2luYWwueGxzeCIpCmNvbG5hbWVzKGRmKSA8LSBtYWtlLm5hbWVzKGNvbG5hbWVzKGRmKSkKYGBgCgojIDxzcGFuIHN0eWxlPSAiY29sb3I6IHJlZDsiPkFuw6FsaXNpcyBEZXNjcmlwdGl2bzwvc3Bhbj4KYGBge3J9CnN1bW1hcnkoZGYpCnN0cihkZikKIyBjcmVhdGVfcmVwb3J0KGRmKQppbnRyb2R1Y2UoZGYpCnBsb3RfaW50cm8oZGYpCnBsb3RfbWlzc2luZyhkZikKcGxvdF9oaXN0b2dyYW0oZGYpCnBsb3RfYmFyKGRmKQpwbG90X2NvcnJlbGF0aW9uKGRmKQoKY291bnQoZGYsIFRlcnJpdG9yaW8sIHNvcnQgPSBUKQpjb3VudChkZiwgU3ViLlRlcnJpdG9yaW8sIHNvcnQgPSBUKQpjb3VudChkZiwgQ0VESSAsIHNvcnQgPSBUKQpjb3VudChkZiwgQ2xpZW50ZSwgc29ydCA9IFQpCmNvdW50KGRmLCBOb21icmUsIHNvcnQgPSBUKQpjb3VudChkZiwgVGFtYcOxby5DdGUuSW5kdXN0cmlhLCBzb3J0ID0gVCkKY291bnQoZGYsIFNlZ21lbnRvLkRldCwgc29ydCA9IFQpCmNvdW50KGRmLCBNYXJjYSwgc29ydCA9IFQpCmNvdW50KGRmLCBQcmVzZW50YWNpb24sIHNvcnQgPSBUKQpjb3VudChkZiwgVGFtYcOxbywgc29ydCA9IFQpCmNvdW50KGRmLCBSZXRvcm5hYmxlX05SLCBzb3J0ID0gVCkKYGBgCgojIDxzcGFuIHN0eWxlPSAiY29sb3I6IHJlZDsiPkxpbXBpZXphIGRlIGxhIEJhc2UgZGUgRGF0b3M8L3NwYW4+CmBgYHtyfQojIFJldmlzYXIgTkFzIGVuIGxhIGJhc2UgZGUgZGF0b3MKIyBDdcOhbnRvcyBOQXMgdGVuZ28gZW4gbGEgYmFzZSBkZSBkYXRvcz8KCnN1bShpcy5uYShkZikpCgojIEN1w6FudGFzIE5BcyB0ZW5nbyBwb3IgdmFyaWFibGUKc2FwcGx5KGRmLCBmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQoKIyBSZWVtcGxhemFyIE5BcyBjb24gQ0VST1MKZGZbaXMubmEoZGYpXSA8LSAwCnN1bShpcy5uYShkZikpCgojIyBEZXRlY3RhciB2YWxvcmVzIGF0w61waWNvcwpib3hwbG90KGRmJEVuZXJvKQoKIyBFbGltaW5hciByZW5nbMOzbiBkZSBsb3MgdG90YWxlcwpkZiA8LSBkZltkZiRFbmVybyA8NjAwMCwgXQpib3hwbG90KGRmJEVuZXJvKQpgYGAKCiMgPHNwYW4gc3R5bGU9ICJjb2xvcjogcmVkOyI+QW7DoWxpc2lzIGRlIFZlbnRhcyAoVGFyZWEgQ29sYWJvcmF0aXZhIDEpPC9zcGFuPgpgYGB7cn0KZGYxIDwtIGRmCgojIE11ZXN0cmEgbGFzIHZlbnRhcyBkZSBFbmVybyBhIEp1bmlvIHBvciBDRURJOgpkZjIgPC0gc2VsZWN0KGRmMSxjKENFREksRW5lcm86SnVuaW8pKQoKIyBNdWVzdHJhIGxvcyBtb3ZpbWllbnRvcyBwb3IgQ2VkaSB5IHRhbWHDsW8gZGUgdGllbmRhIGdyYW5kZToKZGYzIDwtIGRmMSAlPiUgZmlsdGVyKFRhbWHDsW8uQ3RlLkluZHVzdHJpYSA9PSAiR3JhbmRlIikKCiMgT3JkZW5hIGxhIGJhc2UgZGUgZGF0b3MgcG9yIENlZGksIHBvciBtYXJjYSB5IHBvciBwcmVzZW50YWNpw7NuOgpkZjQgPC0gZGYxICU+JSBhcnJhbmdlKENFREksIE1hcmNhLCBQcmVzZW50YWNpb24pCgojIEFncmVnYSB1biBjYW1wbyBjYWxjdWxhZG8gY29uIGxhcyB2ZW50YXMgZGVsIHByaW1lciBzZW1lc3RyZSB5IG11ZXN0cmEgbGFzIHZlbnRhcyBkZWwgcHJpbWVyIHNlbWVzdHJlIHBvciBtYXJjYToKZGY1IDwtIGRmMSAlPiUgCiAgbXV0YXRlKFZlbnRhc19TZW0xID0gRW5lcm8gKyBGZWJyZXJvICsgTWFyem8gKyBBYnJpbCArIE1heW8gKyBKdW5pbykKCnZlbnRhc19zZW0xX3Bvcl9tYXJjYSA8LSBkZjUgJT4lIAogIGdyb3VwX2J5KE1hcmNhKSAlPiUgCiAgc3VtbWFyaXNlKFZlbnRhc19TZW0xPXN1bShWZW50YXNfU2VtMSkpCgojIE9idMOpbiBsYSBtZWRpYSBkZSBsYXMgdmVudGFzIGRlbCBwcmltZXIgc2VtZXN0cmUgYWdydXBhZG8gcG9yIG1hcmNhLCBwcmVzZW50YWNpw7NuIHkgdGFtYcOxby4KZGY2IDwtIGRmNSAlPiUKICBncm91cF9ieShNYXJjYSwgUHJlc2VudGFjaW9uLCBUYW1hw7FvKSAlPiUKICBzdW1tYXJpc2UoVmVudGFzX1NlbTE9bWVhbihWZW50YXNfU2VtMSkpCgojIENhbGN1bGFyIG1lZGlkYXMgZGUgdGVuZGVuY2lhIGNlbnRyYWwKc3VtbWFyeShkZjEpCgojIENvbGFwc2FyIG1lc2VzIGVuIHVuYSBjb2x1bW5hCmRmNyA8LSBnYXRoZXIoZGYxLCBNZXMsIFZlbnRhcywgRW5lcm86RGljaWVtYnJlKQpkZjcKCiMgQWdyZWdhciB1bmEgY29sdW1uYSBjb24gZWwgTsO6bWVybyBkZSBNZXMKbWVzZXMgPC0gYygiRW5lcm8iPSIwMSIsICJGZWJyZXJvIj0iMDIiLCJNYXJ6byI9IjAzIiwgIkFicmlsIj0iMDQiLCAiTWF5byI9IjA1IiwgIkp1bmlvIj0iMDYiLCAiSnVsaW8iPSIwNyIsICJBZ29zdG8iPSIwOCIsICJTZXB0aWVtYnJlIj0iMDkiLCAiT2N0dWJyZSI9IjEwIiwgIk5vdmllbWJyZSI9IjExIiwgIkRpY2llbWJyZSI9IjEyIikKCmRmNyROw7ptZXJvX2RlX01lcyA8LSBtZXNlc1tkZjckTWVzXQoKIyBHcmFmaWNhciBlbCB0b3RhbCBkZSB2ZW50YXMgcG9yIG1lcyB5IGHDsW8KCnZlbnRhc190b3RhbGVzIDwtIGRmNyAlPiUKICBncm91cF9ieShBw7FvLCBOw7ptZXJvX2RlX01lcykgJT4lCiAgc3VtbWFyaXNlKFZlbnRhc19Ub3RhbGVzID0gc3VtKFZlbnRhcykpICU+JQogIGFycmFuZ2UoTsO6bWVyb19kZV9NZXMpCgpnZ3Bsb3QodmVudGFzX3RvdGFsZXMsIGFlcyh4PU7Dum1lcm9fZGVfTWVzLCB5PVZlbnRhc19Ub3RhbGVzLGdyb3VwPUHDsW8sIGNvbG9yPSBhcy5mYWN0b3IoQcOxbykpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh4PSJNZXMiLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCBjb2xvciA9ICJBw7FvIikKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+UmVncmVzacOzbiBsaW5lYWw8L3NwYW4+CmBgYHtyfQojIEVsYWJvcmFyIFJlZ3Jlc2nDs24gTGluZWFsCgp2ZW50YXNfNDU2NyA8LSBkZjcgJT4lCiAgZmlsdGVyKENsaWVudGUgPT0gIjQ1NjciKSAlPiUKICBncm91cF9ieShBw7FvKSAlPiUKICBzdW1tYXJpc2UoVmVudGFzX1RvdGFsZXMgPSBzdW0oVmVudGFzKSkgJT4lCiAgZmlsdGVyKFZlbnRhc19Ub3RhbGVzICE9IDApCgojIHZlbnRhc180NTY3JFNlY3VlbmNpYSA8LSAxOm5yb3codmVudGFzXzQ1NjcpCgpnZ3Bsb3QodmVudGFzXzQ1NjcsIGFlcyh4PUHDsW8sIHk9VmVudGFzX1RvdGFsZXMpKSArCiAgZ2VvbV9wb2ludCgpICsKICBsYWJzKHg9IkHDsW8iLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCB0aXRsZT0gIlZlbnRhcyBUb3RhbGVzIGRlbCBDbGllbnRlIDQ1NjciKQoKcmVncmVzaW9uIDwtIGxtKFZlbnRhc19Ub3RhbGVzIH4gQcOxbywgZGF0YT12ZW50YXNfNDU2NykKc3VtbWFyeShyZWdyZXNpb24pCgojIEVjdWFjacOzbgojIHkgPSA0ODkxODY3NyAtIDI0MTc0ICogQcOxbyAKCiMgUiBjdWFkcmFkYSBhanVzdGFkYQojIDc3JQoKZGF0b3MgPC0gZGF0YS5mcmFtZShBw7FvPTIwMjA6MjAyNSkKcHJlZGljY2lvbiA8LSBwcmVkaWN0KHJlZ3Jlc2lvbixkYXRvcykKcHJlZGljY2lvbgoKdmVudGFzXzQ1NjckVGlwb19kZV9EYXRvIDwtICJEYXRvcyBSZWFsZXMiCmRhdG9zJFZlbnRhc19Ub3RhbGVzIDwtIHByZWRpY2Npb24KZGF0b3MkVGlwb19kZV9EYXRvIDwtICJQcmVkaWNjacOzbiIKCmRhdG9zX2NvbWJpbmFkb3MgPC0gcmJpbmQodmVudGFzXzQ1NjcsZGF0b3MpCgpnZ3Bsb3QoZGF0b3NfY29tYmluYWRvcywgYWVzKHg9QcOxbywgeT1WZW50YXNfVG90YWxlcywgY29sb3I9VGlwb19kZV9EYXRvKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh4PSJBw7FvIix5PSJWZW50YXMgVG90YWxlcyhRdHkpIiwgdGl0bGU9ICJQcm9uw7NzdGljbyBhIDUgYcOxb3MgZGUgVmVudGFzIGRlbCBDbGllbnRlIDQ1NjciKQpgYGAKCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+U2VyaWVzIGRlIFRpZW1wbzwvc3Bhbj4KYGBge3J9CnZlbnRhc19tZW5zdWFsZXNfNDU2NyA8LSBkZjcgJT4lCiAgZmlsdGVyKENsaWVudGUgPT0gIjQ1NjciKSAlPiUKICBncm91cF9ieShBw7FvLCBOw7ptZXJvX2RlX01lcykgJT4lCiAgc3VtbWFyaXNlKFZlbnRhc19Ub3RhbGVzID0gc3VtKFZlbnRhcykpICU+JQogIGZpbHRlcihWZW50YXNfVG90YWxlcyAhPSAwKQoKIyBDb25maXJtYXIgcXVlIGxvcyBkYXRvcyBxdWUgcXVlcmVtb3MgbW9kZWxhciBlc3RlbiBvcmRlbmFkb3MgY3Jvbm9sw7NnaWNhbWVudGUuCgojIEZ1bmNpw7NuIGRlIFNlcmllIGRlIFRpZW1wbyBNRU5TVUFMLCBxdWUgaW5pY2lhIGVuIEVuZXJvIDIwMTcKdHMgPC0gdHMoZGF0YT12ZW50YXNfbWVuc3VhbGVzXzQ1NjckVmVudGFzX1RvdGFsZXMsIHN0YXJ0ID0gYygyMDE3LDEpLCBmcmVxdWVuY3kgPSAxMikKCiMgRnVuY2nDs24gZGUgU2VyaWUgZGUgVGllbXBvIE1FTlNVQUwsIHF1ZSBpbmljaWEgZW4gQWJyaWwgMjAxNwojIHRzIDwtIHRzKGRhdGE9dmVudGFzX21lbnN1YWxlc180NTY3JFZlbnRhc19Ub3RhbGVzLCBzdGFydCA9IGMoMjAxNyw0KSwgZnJlcXVlbmN5ID0gMTIpCgojIEZ1bmNpw7NuIGRlIFNlcmllIGRlIFRpZW1wbyBUUklNRVNUUkFMLCBxdWUgaW5pY2lhIGVuIEVuZXJvIDIwMTcKIyB0cyA8LSB0cyhkYXRhPXZlbnRhc19tZW5zdWFsZXNfNDU2NyRWZW50YXNfVG90YWxlcywgc3RhcnQgPSBjKDIwMTcsMSksIGZyZXF1ZW5jeSA9IDQpCgojIEZ1bmNpw7NuIGRlIFNlcmllIGRlIFRpZW1wbyBUUklNRVNUUkFMLCBxdWUgaW5pY2lhIGVuIE9jdHVicmUgMjAxNyAoUTQpCiMgdHMgPC0gdHMoZGF0YT12ZW50YXNfbWVuc3VhbGVzXzQ1NjckVmVudGFzX1RvdGFsZXMsIHN0YXJ0ID0gYygyMDE3LDQpLCBmcmVxdWVuY3kgPSA0KQoKIyBGdW5jacOzbiBkZSBTZXJpZSBkZSBUaWVtcG8gQU5VQUwsIHF1ZSBpbmljaWEgZW4gMjAxNwojIHRzIDwtIHRzKGRhdGE9dmVudGFzX21lbnN1YWxlc180NTY3JFZlbnRhc19Ub3RhbGVzLCBzdGFydCA9IDIwMTcsIGZyZXF1ZW5jeSA9IDEpCgojIENyZWFyIE1vZGVsbyBBUklNQQojIE1vZGVsbyBBdXRvcnJlZ3Jlc2l2byBJbnRlZ3JhZG8gZGUgUHJvbWVkaW8gTW92aWwuCmFyaW1hIDwtIGF1dG8uYXJpbWEodHMsIEQ9MSkgIyBEPTEgcG9yIGxhIHRlbXBvcmFsaWRhZAphcmltYQpzdW1tYXJ5KGFyaW1hKQoKIyBHZW5lcmFyIGVsIHByb27Ds3N0aWNvIGRlIHZlbnRhcwpwcm9ub3N0aWNvIDwtIGZvcmVjYXN0KGFyaW1hLCBsZXZlbD05NSwgaD0zNikKcHJvbm9zdGljbwpwbG90KHByb25vc3RpY28sIG1haW49IlZlbnRhcyBNZW5zdWFsZXMgeSBQcm9uw7NzdGljbyBhIDMgQcOxb3MgZGVsIENsaWVudGUgNDU2NyIsIHhsYWI9IkHDsW8iLCB5bGFiPSJWZW50YXMgKFF0eSkiKQpgYGAKCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+RXZpZGVuY2lhPC9zcGFuPgoKIyMgUHJlZ3VudGFzIERldG9uYW50ZXMKCjEuIMK/UHVlZGUgb2JzZXJ2YXJzZSB1biBjcmVjaW1pZW50byBlbiBsYXMgdmVudGFzIGRlIGFsZ3Vub3MgZGUgbG9zIHNlZ21lbnRvcyBkZSBwcm9kdWN0b3MgZGUgbGEgZmFtaWxpYSBDb2NhIENvbGEgZW4gbGFzIHRpZW5kYXMgZW4gbGFzIHF1ZSBzZSBpbXBsZW1lbnTDsyBlbCBQcm95ZWN0byBTaWdsbyBYWEkgZGUgQXJjYSBDb250aW5lbnRhbD8KCmBgYHtyfQp2ZW50YXNfdG90YWxlc19zZWcgPC0gZGY3ICU+JQogIGZpbHRlcihTZWdtZW50by5EZXQgPT0gIkFndWEgUHVyaWZpY2FkYSIgfCBTZWdtZW50by5EZXQgPT0gIklzb3TDs25pY29zIFJlZ3VsYXIiIHwgU2VnbWVudG8uRGV0ID09ICJDb2xhcyBSZWd1bGFyIiApICU+JQogIGZpbHRlcihBw7FvID09IDIwMTgpICU+JQogIGdyb3VwX2J5KFNlZ21lbnRvLkRldCwgTsO6bWVyb19kZV9NZXMpICU+JQogIHN1bW1hcmlzZShWZW50YXMuVG90YWxlcyA9IHN1bShWZW50YXMpKSAlPiUKICBhcnJhbmdlKE7Dum1lcm9fZGVfTWVzKQoKZ2dwbG90KHZlbnRhc190b3RhbGVzX3NlZywgYWVzKHg9TsO6bWVyb19kZV9NZXMsIHk9VmVudGFzLlRvdGFsZXMsZ3JvdXA9U2VnbWVudG8uRGV0LCBjb2xvcj0gYXMuZmFjdG9yKFNlZ21lbnRvLkRldCkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh4PSJNZXMiLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCB0aXRsZT0gIlZlbnRhcyBUb3RhbGVzIHBvciBTZWdtZW50byIsIGNvbG9yID0gIlNlZ21lbnRvIikKYGBgCgoqKlJlc3B1ZXN0YTogRW4gMjAxOSwgbGFzIHZlbnRhcyBlbiBnZW5lcmFsIG1vc3RyYXJvbiB1biBjcmVjaW1pZW50bywgYXVucXVlIGNhZGEgc2VnbWVudG8gdHV2byB1biBjb21wb3J0YW1pZW50byBkaXN0aW50by4gRXN0ZSBpbmNyZW1lbnRvIGVuIGxhcyB2ZW50YXMgcHVkbyBsb2dyYXJzZSBtZWRpYW50ZSBjYW1wYcOxYXMgZGUgbWVyY2Fkb3RlY25pYSBtw6FzIGVmZWN0aXZhcyB5IGxhIGludHJvZHVjY2nDs24gZGUgbnVldm9zIHByb2R1Y3Rvcy4gRW4gMjAxOCwgbGFzIHZlbnRhcyBkZSBDb2NhLUNvbGEgZW50cmUgZmVicmVybyB5IGRpY2llbWJyZSBjcmVjaWVyb24gZW4gMTAwLDAwMCB1bmlkYWRlcywgbWllbnRyYXMgcXVlIGxhcyB2ZW50YXMgZGUgYWd1YXMgaXNvdMOzbmljYXMgcGVybWFuZWNpZXJvbiBlc3RhYmxlcyBkdXJhbnRlIGVsIG1pc21vIHBlcsOtb2RvLioqCgoyLiDCv0VsIGluY3JlbWVudG8gZW4gbGFzIHZlbnRhcyBlcyBzaW1pbGFyIGVudHJlIGxvcyBkaWZlcmVudGVzIHRhbWHDsW9zIGRlIGNsaWVudGVzPwpgYGB7cn0KdmVudGFzX3RvdGFsZXNfdGFtX2NsaWVudGUgPC0gZGY3ICU+JQogIGZpbHRlcihBw7FvID09IDIwMTkpICU+JQogIGdyb3VwX2J5KFRhbWHDsW8uQ3RlLkluZHVzdHJpYSwgTsO6bWVyb19kZV9NZXMpICU+JQogIHN1bW1hcmlzZShWZW50YXMuVG90YWxlcyA9IHN1bShWZW50YXMpKSAlPiUKICBhcnJhbmdlKE7Dum1lcm9fZGVfTWVzKSAlPiUKICBmaWx0ZXIoVmVudGFzLlRvdGFsZXMgIT0gMCkKCmdncGxvdCh2ZW50YXNfdG90YWxlc190YW1fY2xpZW50ZSwgYWVzKHg9TsO6bWVyb19kZV9NZXMsIHk9VmVudGFzLlRvdGFsZXMsZ3JvdXA9VGFtYcOxby5DdGUuSW5kdXN0cmlhLCBjb2xvcj0gYXMuZmFjdG9yKFRhbWHDsW8uQ3RlLkluZHVzdHJpYSkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh4PSJNZXMiLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCB0aXRsZT0gIlZlbnRhcyBUb3RhbGVzIHBvciBUYW1hw7FvIGRlIENsaWVudGUiLCBjb2xvciA9ICJUYW1hw7FvIGRlIENsaWVudGUiKQpgYGAKCioqUmVzcHVlc3RhOiBFbCBhdW1lbnRvIGVuIGxhcyB2ZW50YXMgZnVlIGNvbnNpc3RlbnRlIHNpbiBpbXBvcnRhciBlbCB0YW1hw7FvIGRlIGxvcyBjbGllbnRlcywgeWEgcXVlIHRvZG9zIGxvcyBuZWdvY2lvcyBvcGVyYW4gbG9zIG1pc21vcyBkw61hcyB5IHNlIGVuY3VlbnRyYW4gZW4gbGEgbWlzbWEgY2l1ZGFkIChHdWFkYWxhamFyYSksIGxvIHF1ZSBoYWNlIHF1ZSBsb3MgZmFjdG9yZXMgZXh0ZXJub3MgYWZlY3RlbiBkZSBtYW5lcmEgc2ltaWxhciBhIHRvZG9zLiBFbCBtZXMgZGUgbWF5byBkZSAyMDE5IHJlZ2lzdHLDsyBlbCBtYXlvciB2b2x1bWVuIGRlIHZlbnRhcyBwYXJhIHRvZG9zIGxvcyB0YW1hw7FvcyBkZSBjbGllbnRlcywgbWllbnRyYXMgcXVlIGVsIHByaW1lciBiaW1lc3RyZSBkZWwgYcOxbyB0dXZvIGVsIG5pdmVsIGRlIHZlbnRhcyBtw6FzIGJham8sIHRhbWJpw6luIGRlIG1hbmVyYSB1bmlmb3JtZSBwYXJhIHRvZG9zIGxvcyBzZWdtZW50b3MgZGUgY2xpZW50ZXMuKioKCjMuIMK/Q3XDoWwgZXMgZWwgY29tcG9ydGFtaWVudG8gb2JzZXJ2YWRvIGRlIGxhcyB1bmlkYWRlcyB2ZW5kaWRhcyBwb3IgbWVzIGRlIGNhZGEgdW5hIGRlIGxhcyBtYXJjYXMsIGluZGVwZW5kaWVudGVtZW50ZSBkZSBzdXMgcmVzcGVjdGl2YXMgcHJlc2VudGFjaW9uZXM/CmBgYHtyfQp2ZW50YXNfdG90YWxlc19tYXJjYSA8LSBkZjcgJT4lCiAgZmlsdGVyKEHDsW8gPT0gMjAxOSkgJT4lCiAgZmlsdGVyKE1hcmNhID09IGMoIkNvY2EtQ29sYSIsICJWYWxsZSBGcnV0IiwgIkNpZWwgQWd1YSBQdXJpZmljYWRhIiwiQ29jYS1Db2xhIExpZ2h0IikpICU+JQogIGdyb3VwX2J5KE1hcmNhLCBOw7ptZXJvX2RlX01lcykgJT4lCiAgc3VtbWFyaXNlKFZlbnRhcy5Ub3RhbGVzID0gc3VtKFZlbnRhcykpICU+JQogIGFycmFuZ2UoTsO6bWVyb19kZV9NZXMpICU+JQogIGZpbHRlcihWZW50YXMuVG90YWxlcyAhPSAwKQoKZ2dwbG90KHZlbnRhc190b3RhbGVzX21hcmNhLCBhZXMoeD1Ow7ptZXJvX2RlX01lcywgeT1WZW50YXMuVG90YWxlcyxncm91cD1NYXJjYSwgY29sb3I9IGFzLmZhY3RvcihNYXJjYSkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh4PSJNZXMiLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCB0aXRsZT0gIlZlbnRhcyBUb3RhbGVzIHBvciBNYXJjYSIsIGNvbG9yID0gIk1hcmNhIikKYGBgCgoqKlJlc3B1ZXN0YTogRWwgY29tcG9ydGFtaWVudG8gZGUgdmVudGFzIG11ZXN0cmEgdW5hIHRlbmRlbmNpYSBzaW1pbGFyIGVudHJlIGxhcyBkaWZlcmVudGVzIG1hcmNhcyBhIGxvIGxhcmdvIGRlIGxvcyBtZXNlczsgc2luIGVtYmFyZ28sIGFsZ3VuYXMgbWFyY2FzIHJlZ2lzdHJhbiB2ZW50YXMgc2lnbmlmaWNhdGl2YW1lbnRlIG1heW9yZXMgcXVlIG90cmFzLiBMb3MgcGVyaW9kb3MgZGUgbWF5b3IgdmVudGEgZGUgYmViaWRhcyBjb2luY2lkZW4gY29uIGxvcyBtZXNlcyBkZSB0ZW1wZXJhdHVyYXMgbcOhcyBlbGV2YWRhcywgeSBsYXMgbWFyY2FzIG3DoXMgcmVjb25vY2lkYXMgc29uIGxhcyBxdWUgbG9zIGNvbnN1bWlkb3JlcyB0aWVuZGVuIGEgcHJlZmVyaXIuIEVuIG1heW8gZGUgMjAxOSwgdG9kYXMgbGFzIG1hcmNhcyBleHBlcmltZW50YXJvbiBzdSBwaWNvIG3DoXMgYWx0byBkZSB2ZW50YXMsIHNpZW5kbyBDb2NhLUNvbGEgbGEgbWFyY2EgY29uIGVsIHZvbHVtZW4gZGUgdmVudGFzIG3DoXMgZWxldmFkby4qKgoKNC4gwr9TZSBoYSBpbmNyZW1lbnRhZG8gbGEgdmVudGEgZGUgcHJvZHVjdG9zIGVuIGVudmFzZXMgcmV0b3JuYWJsZXMgZW4gbG9zIMO6bHRpbW9zIGRvcyBhw7Fvcz8KYGBge3J9CnZlbnRhc190b3RhbGVzX2VudmFzZSA8LSBkZjcgJT4lCiAgZmlsdGVyKFJldG9ybmFibGVfTlI9PSJSZXRvcm5hYmxlIikgJT4lCiAgZmlsdGVyKEHDsW8gPT0gYygyMDE3LDIwMTgsMjAxOSkpICU+JQogIGdyb3VwX2J5KEHDsW8sIE7Dum1lcm9fZGVfTWVzKSAlPiUKICBzdW1tYXJpc2UoVmVudGFzLlRvdGFsZXMgPSBzdW0oVmVudGFzKSkgJT4lCiAgYXJyYW5nZShOw7ptZXJvX2RlX01lcykgJT4lCiAgZmlsdGVyKFZlbnRhcy5Ub3RhbGVzICE9IDApCgpnZ3Bsb3QodmVudGFzX3RvdGFsZXNfZW52YXNlLCBhZXMoeD1Ow7ptZXJvX2RlX01lcywgeT1WZW50YXMuVG90YWxlcyxncm91cD1Bw7FvLCBjb2xvcj0gYXMuZmFjdG9yKEHDsW8pKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGxhYnMoeD0iTWVzIix5PSJWZW50YXMgVG90YWxlcyhRdHkpIiwgdGl0bGU9ICJWZW50YXMgVG90YWxlcyBkZSBFbnZhc2VzIFJldG9ybmFibGVzIiwgY29sb3IgPSAiQcOxbyIpCmBgYAoKKipSZXNwdWVzdGE6IExhcyB2ZW50YXMgZGUgcHJvZHVjdG9zIGVuIGVudmFzZXMgcmV0b3JuYWJsZXMgaGFuIGF1bWVudGFkbyBlbiBsb3Mgw7psdGltb3MgZG9zIGHDsW9zLCBpbXB1bHNhZGFzIHBvciBjYW1wYcOxYXMgZGUgY29uY2llbmNpYSBhbWJpZW50YWwgcXVlIGhhbiBwb3B1bGFyaXphZG8gbGFzIG9wY2lvbmVzIG3DoXMgZWNvbMOzZ2ljYXMuIERlIDIwMTcgYSAyMDE4LCBzZSBvYnNlcnbDsyB1biBsZXZlIGluY3JlbWVudG8gZW4gbGFzIHZlbnRhcyBkZSBlbnZhc2VzIHJldG9ybmFibGVzLCBtaWVudHJhcyBxdWUgZW50cmUgMjAxOCB5IDIwMTkgZXN0ZSBjcmVjaW1pZW50byBmdWUgbXVjaG8gbcOhcyBzaWduaWZpY2F0aXZvLioqICAKCioqTm90YXM6IEV4aXN0ZW4gb3Ryb3MgZmFjdG9yZXMgcXVlIHRhbWJpw6luIGRlYmVuIHRlbmVyc2UgZW4gY3VlbnRhLCBjb21vIGVsIGhlY2hvIGRlIHF1ZSBlbiAyMDE5IGhheSBtw6FzIHRpZW5kYXMgcGFydGljaXBhbmRvIGVuIGVsIHByb3llY3RvIFNpZ2xvIFhYSSwgbG8gcXVlIHBvZHLDrWEgaGFiZXIgY29udHJpYnVpZG8gYWwgYXVtZW50byBlbiB2ZW50YXMuIEFkZW3DoXMsIGVuIGdlbmVyYWwsIGxhcyB0aWVuZGFzIGhhbiBleHBlcmltZW50YWRvIHVuIGluY3JlbWVudG8gZW4gbGEgdmVudGEgZGUgcHJvZHVjdG9zLCB0YW50byBlbiBlbnZhc2VzIHJldG9ybmFibGVzIGNvbW8gbm8gcmV0b3JuYWJsZXMsIGxvIHF1ZSByZWZsZWphIHVuIGNyZWNpbWllbnRvIGVuIGxhIGRlbWFuZGEgeSBwb3NpYmxlbWVudGUgdW4gbWF5b3IgZW5mb3F1ZSBlbiBsYXMgZXN0cmF0ZWdpYXMgY29tZXJjaWFsZXMuKioKCjUuIMK/RWwgY29tcG9ydGFtaWVudG8gZGUgbGEgdmVudGEgZGUgYWd1YSBoYSBpbmNyZW1lbnRhZG8gZW4gcmVsYWNpw7NuIGFsIGRlIGxvcyByZWZyZXNjb3MgbyBsYXMgYmViaWRhcyBpc290w7NuaWNhcz8KYGBge3J9CnZlbnRhc190b3RhbGVzX3NlZyA8LSBkZjcgJT4lCiAgIGZpbHRlcihTZWdtZW50by5EZXQgPT0gIkFndWEgUHVyaWZpY2FkYSIgfCBTZWdtZW50by5EZXQgPT0gIklzb3TDs25pY29zIFJlZ3VsYXIiIHwgU2VnbWVudG8uRGV0ID09ICJDb2xhcyBSZWd1bGFyIiApICU+JQogIGZpbHRlcihBw7FvID09IDIwMTgpICU+JQogIGdyb3VwX2J5KFNlZ21lbnRvLkRldCwgTsO6bWVyb19kZV9NZXMpICU+JQogIHN1bW1hcmlzZShWZW50YXMuVG90YWxlcyA9IHN1bShWZW50YXMpKSAlPiUKICBhcnJhbmdlKE7Dum1lcm9fZGVfTWVzKQoKZ2dwbG90KHZlbnRhc190b3RhbGVzX3NlZywgYWVzKHg9TsO6bWVyb19kZV9NZXMsIHk9VmVudGFzLlRvdGFsZXMsZ3JvdXA9U2VnbWVudG8uRGV0LCBjb2xvcj0gYXMuZmFjdG9yKFNlZ21lbnRvLkRldCkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh4PSJNZXMiLHk9IlZlbnRhcyBUb3RhbGVzKFF0eSkiLCB0aXRsZT0gIlZlbnRhcyBUb3RhbGVzIHBvciBTZWdtZW50byIsIGNvbG9yID0gIlNlZ21lbnRvIikKYGBgCgoqKlJlc3B1ZXN0YTogTGFzIHZlbnRhcyBkZSBBZ3VhIFB1cmlmaWNhZGEgbm8gaGFuIG1vc3RyYWRvIGVsIG1pc21vIGNyZWNpbWllbnRvIGVuIGNvbXBhcmFjacOzbiBjb24gUmVmcmVzY29zIG8gQmViaWRhcyBJc290w7NuaWNhcy4gRXN0byBzZSBkZWJlIGEgbGEgcGVyY2VwY2nDs24gZGUgcXVlIGVsIGFndWEgbm8gb2ZyZWNlIHVuIHZhbG9yIGFncmVnYWRvIGVuIHN1IHByZXBhcmFjacOzbiB5IGEgcXVlIGVsIGF6w7pjYXIgcHJlc2VudGUgZW4gbG9zIHJlZnJlc2NvcyBsb3MgY29udmllcnRlIGVuIGxhIG9wY2nDs24gcHJlZmVyaWRhIGRlIGxvcyBjb25zdW1pZG9yZXMgbWV4aWNhbm9zLiBFbiAyMDE4LCBsYXMgdmVudGFzIHRvdGFsZXMgZGUgQWd1YSBQdXJpZmljYWRhIG5vIHN1cGVyYXJvbiBsYXMgNTAsMDAwIHVuaWRhZGVzLCBtaWVudHJhcyBxdWUgQ29jYS1Db2xhIGFsY2FuesOzIHN1IHBpY28gZGUgdmVudGFzIGNvbiA0NTAsMDAwIHVuaWRhZGVzIGVuIHN1IG1lcyBtw6FzIGFsdG8sIHZlbmRpZW5kbyBvY2hvIHZlY2VzIG3DoXMgcXVlIGVsIGFndWEuKioKCjYuIMK/UHVlZGUgZGVjaXJzZSBxdWUgbGEgdmVudGEgbWVuc3VhbCBkZSBhZ3VhIGVzdMOhIHJlbGFjaW9uYWRhIGNvbiBsYSB2ZW50YSBtZW5zdWFsIGRlIHJlZnJlc2NvcyBlbiBsb3Mgw7psdGltb3MgNCBhw7Fvcz8KYGBge3J9CnZlbnRhc190b3RhbGVzX2F5ciA8LSBkZjcgJT4lCiAgIGZpbHRlcihTZWdtZW50by5EZXQgPT0gYygiQWd1YSBQdXJpZmljYWRhIiwgIkNvbGFzIFJlZ3VsYXIiKSkgJT4lCiAgZ3JvdXBfYnkoU2VnbWVudG8uRGV0LCBBw7FvKSAlPiUKICBzdW1tYXJpc2UoVmVudGFzLlRvdGFsZXMgPSBzdW0oVmVudGFzKSkgCiAgCmdncGxvdCh2ZW50YXNfdG90YWxlc19heXIsIGFlcyh4PUHDsW8sIHk9VmVudGFzLlRvdGFsZXMsZ3JvdXA9U2VnbWVudG8uRGV0LCBjb2xvcj0gYXMuZmFjdG9yKFNlZ21lbnRvLkRldCkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh4PSJBw7FvIix5PSJWZW50YXMgVG90YWxlcyhRdHkpIiwgdGl0bGU9ICJWZW50YXMgVG90YWxlcyBwb3IgU2VnbWVudG8iLCBjb2xvciA9ICJTZWdtZW50byIpCmBgYAoKKipSZXNwdWVzdGE6IExhcyB2ZW50YXMgZGUgYWd1YSB5IHJlZnJlc2NvcyBtdWVzdHJhbiB1biBhdW1lbnRvIGR1cmFudGUgbG9zIG1pc21vcyBtZXNlcyB5IGEgbG8gbGFyZ28gZGUgbG9zIGHDsW9zOyBzaW4gZW1iYXJnbywgbm8gZXMgcG9zaWJsZSBjb25jbHVpciBxdWUgZWwgaW5jcmVtZW50byBlbiBsYSB2ZW50YSBkZSB1bm8gY2F1c2UgZWwgaW5jcmVtZW50byBlbiBlbCBvdHJvLiBFc3RlIGF1bWVudG8gZW4gdmVudGFzIGNvaW5jaWRlIGNvbiBsb3MgbWVzZXMgbcOhcyBjYWx1cm9zb3MgeSBjb24gZWwgY3JlY2ltaWVudG8gZGUgbGEgcG9ibGFjacOzbiwgbG8gcXVlIGltcHVsc2EgdW5hIG1heW9yIGRlbWFuZGEgZGUgYmViaWRhcywgeWEgc2VhIGFndWEgbyByZWZyZXNjb3MuIExhIGdyw6FmaWNhIG9idGVuaWRhIHJlZmxlamEgdW4gaW5jcmVtZW50byBjb25zdGFudGUgYcOxbyB0cmFzIGHDsW8gZW4gbGFzIHZlbnRhcyB0YW50byBkZSBhZ3VhIGNvbW8gZGUgcmVmcmVzY29zLiAqKgoKCjcuIMK/QSBjdcOhbnRvIGFzY2llbmRlbiBsYXMgdmVudGFzIGVzcGVyYWRhcyBwYXJhIGVsIDIwMjAgZW4gbGEgQ29jYSBDb2xhIGRlIDUwMCBtbCBOUiBWaWRyaW8/CmBgYHtyfQp2ZW50YXNfY29jYV92aWRyaW8gPC0gZGY3ICU+JQogIGZpbHRlcihNYXJjYSA9PSAiQ29jYS1Db2xhIiAmIFByZXNlbnRhY2lvbiA9PSAiNTAwIG1sIE5SIFZpZHJpbyIpICU+JQogIGdyb3VwX2J5KEHDsW8sIE7Dum1lcm9fZGVfTWVzKSAlPiUKICBzdW1tYXJpc2UoVmVudGFzLlRvdGFsZXMgPSBzdW0oVmVudGFzKSkgJT4lCiAgZmlsdGVyKFZlbnRhcy5Ub3RhbGVzICE9IDApCgojIENvbmZpcm1hciBxdWUgbG9zIGRhdG9zIHF1ZSBxdWVyZW1vcyBtb2RlbGFyIGVzdGVuIG9yZGVuYWRvcyBjcm9ub2zDs2dpY2FtZW50ZS4KCiMgRnVuY2nDs24gZGUgU2VyaWUgZGUgVGllbXBvIE1FTlNVQUwsIHF1ZSBpbmljaWEgZW4gRW5lcm8gMjAxNwp0cyA8LSB0cyhkYXRhPXZlbnRhc19jb2NhX3ZpZHJpbyRWZW50YXMuVG90YWxlcywgc3RhcnQgPSBjKDIwMTYsMSksIGZyZXF1ZW5jeSA9IDEyKQoKIyBDcmVhciBNb2RlbG8gQVJJTUEKIyBNb2RlbG8gQXV0b3JyZWdyZXNpdm8gSW50ZWdyYWRvIGRlIFByb21lZGlvIE1vdmlsLgphcmltYSA8LSBhdXRvLmFyaW1hKHRzLCBEPTEpICMgRD0xIHBvciBsYSB0ZW1wb3JhbGlkYWQKYXJpbWEKc3VtbWFyeShhcmltYSkKCiMgR2VuZXJhciBlbCBwcm9uw7NzdGljbyBkZSB2ZW50YXMKcHJvbm9zdGljbyA8LSBmb3JlY2FzdChhcmltYSwgbGV2ZWw9OTUsIGg9MTYpCnByb25vc3RpY28KcGxvdChwcm9ub3N0aWNvLCBtYWluPSJWZW50YXMgTWVuc3VhbGVzIHkgUHJvbsOzc3RpY28gcGFyYSAyMDIwIGRlIENvY2EtQ29sYSA1MDAgbWwgTlIgVmlkcmlvIiwgeGxhYj0iQcOxbyIsICB5bGFiPSJWZW50YXMgKFF0eSkiKQpgYGAKCioqUmVzcHVlc3RhOiBQYXJhIDIwMjAsIGxhcyB2ZW50YXMgcHJveWVjdGFkYXMgZGUgQ29jYS1Db2xhIGRlIDUwMCBtbCBlbiBlbnZhc2UgZGUgdmlkcmlvIG5vIHJldG9ybmFibGUgc2UgZXNwZXJhbiBxdWUgdmFyw61lbiBtZW5zdWFsbWVudGUgZW50cmUgNDUsMDAwIHkgNjUsMDAwIHVuaWRhZGVzLCBjb24gdW4gbml2ZWwgZGUgY29uZmlhbnphIGRlbCA5NSUuKioK