Análisis Exploratorio de las Bases de Datos

Librerias Utilizadas

library(data.table)
library(dplyr)
library(plyr)
library(ggplot2)
library(naniar)
library(Hmisc)         
library(psych)
library(tidyverse)
library(janitor)
library(knitr)
library(pollster)
library(epiDisplay)
library(descr)
library(tidyr)
library(textclean)
library(lubridate)
library(foreign)
library(corrplot)    
library(jtools)       
library(lmtest)       
library(car)          
library(factoextra)  
library(ggfortify)    
library(ggalluvial) 

Importar Bases de Datos

merma <- read.csv("/Users/anita3/Downloads/merma_limpia.csv")
scrap <- read.csv("/Users/anita3/Downloads/scrap_limpia.csv")
carton <- read.csv("/Users/anita3/Downloads/carton_limpia.csv")
perf <- read.csv("/Users/anita3/Downloads/del_perf_limpia.csv")
plan <- read.csv("/Users/anita3/Downloads/plan_limpia.csv")
bajas <- read.csv("/Users/anita3/Downloads/bajas_limpia.csv")
colaboradores <- read.csv("/Users/anita3/Downloads/colaboradores_limpia.csv")

Análisis Exploratorio de las Bases de Datos

Tabla de los principales estadísticos descrptivos

Merma En merma como fecha y mes son datos cualitativos no contienen información descriptiva, sin embargo la variable de kilos si. A continuación podemos identificar que tiene skewness negativo, cercano a -1.

ed_merma <- describe(merma)
ed_merma
##        vars  n    mean      sd median trimmed    mad min  max range  skew
## fecha*    1 50   19.84   13.31   19.5   19.58  18.53   1   42    41  0.08
## mes*      2 50    4.60    2.60    4.0    4.53   2.97   1    9     8  0.21
## kilos     3 50 3708.52 1023.99 3925.0 3798.65 541.15 790 6140  5350 -0.94
##        kurtosis     se
## fecha*    -1.43   1.88
## mes*      -1.35   0.37
## kilos      1.65 144.81
hist(merma$kilos, main= "Merma por kilos", col = c("orange"))

Scrap En Scrap referencia, fecha producto y ubicación de origen son más que nada cualitativas por lo que no tenemos sus datos descriptivos, sin embargo en cantidad sí, a continuación pdoemos encontrar su media, mediana, desviación, estandar y también su distribución, pues tiene skewness positiva alta, indicandonos que en caso de datos faltantes seria mejor remplazar con la mediana que con la media.

ed_scrap <- describe(scrap)
ed_scrap
##             vars   n   mean    sd median trimmed   mad min max range  skew
## referencia*    1 250 125.50 72.31  125.5  125.50 92.66   1 250   249  0.00
## fecha*         2 250  15.27  7.06   16.0   15.56  7.41   1  26    25 -0.29
## producto*      3 250  44.38 24.72   45.0   44.12 25.95   1  95    94  0.01
## cantidad       4 250   6.69 11.85    2.0    3.88  1.48   0  96    96  4.12
## ubi_origen*    5 250   2.48  0.85    3.0    2.60  0.00   1   3     2 -1.10
##             kurtosis   se
## referencia*    -1.21 4.57
## fecha*         -1.00 0.45
## producto*      -0.79 1.56
## cantidad       21.13 0.75
## ubi_origen*    -0.70 0.05
hist(scrap$cantidad, main= "Cantidad de scap", col = c("orange"))

Producción de Carton En producción de carton tenemos los datos descriptivos principalmente de pizas programas, laminas procesadas, tiempo de calidad y tmo_min. EN todas estas ademas de encontrar su media, mediana y desviación estandar podemos identificar su skewness positiva de nuevo indicando su distribución y como en caso de valores faltantes es mejor remplazar con la mediana.

ed_carton <- describe(carton)
ed_carton
##                 vars    n   mean     sd median trimmed    mad min  max range
## fecha*             1 1486 743.50 429.12  743.5  743.50 550.79   1 1486  1485
## cliente*           2 1486   6.03   2.39    6.0    5.95   1.48   1   11    10
## piezas_prog        3 1486 169.96 127.90  184.0  153.67 124.54   1 1500  1499
## tmo_min            4 1477  22.39  13.78   20.0   20.03   7.41  10  120   110
## hr_fin*            5 1469  57.28  43.46   39.0   54.58  34.10   1  130   129
## lam_procesadas     6 1486 153.70 141.65  105.5  131.81 130.47   1 1262  1261
## inicio_sep_up*     7 1486 234.99 137.67  223.5  236.10 193.48   1  447   446
## fin_sep_up*        8 1486 248.71 146.57  234.5  249.26 198.67   1  476   475
## inicio_proceso*    9 1486 247.78 147.46  227.5  247.57 194.96   1  480   479
## fin_proceso*      10 1486 238.86 146.07  214.0  236.76 180.88   1  481   480
## tiempo_calidad    11 1431   1.29   1.50    1.0    1.00   0.00   0   25    25
##                 skew kurtosis    se
## fecha*          0.00    -1.20 11.13
## cliente*        0.34     0.48  0.06
## piezas_prog     1.97     9.97  3.32
## tmo_min         2.68    11.01  0.36
## hr_fin*         0.59    -1.26  1.13
## lam_procesadas  2.24     9.66  3.67
## inicio_sep_up*  0.02    -1.41  3.57
## fin_sep_up*     0.06    -1.37  3.80
## inicio_proceso* 0.10    -1.35  3.83
## fin_proceso*    0.18    -1.26  3.79
## tiempo_calidad  9.21   107.84  0.04
hist(carton$piezas_prog, main= "Piezas programadas", col = c("orange"))

hist(carton$lam_procesadas, main= "Laminas procesadas", col = c("orange"))

hist(carton$tiempo_calidad, main= "Tiempo de calidad", col = c("orange"))

hist(carton$tmo_min, main= "Tiempo (minutos)", col = c("orange"))

Delivery Performance Para Delivery performance podemos encontrar a continuación sus datos descriptivos, sin embargo hay algunos que no tomamos mucho en consideración por ejemplo, la fecha, vuelta o cliente, y por otro lado tenemos plan arrival, real arrival y real departure que son horas en teoria y difference que es la diferencia en minutos.

ed_perf <- describe(perf)
ed_perf
##                vars   n   mean    sd median trimmed   mad    min   max  range
## cliente*          1 800   1.12  0.32      1    1.02  0.00   1.00   2.0   1.00
## vueltas           2 800   1.91  0.83      2    1.89  1.48   1.00   3.0   2.00
## fecha*            3 800 116.21 69.82    115  114.85 86.73   1.00 250.0 249.00
## plan_arrival      4 800  18.10  5.18     20   19.62  0.00   4.00  20.0  16.00
## real_arrival      5 800   7.82  1.65      8    8.12  0.30   1.00  11.5  10.50
## real_departure    6 800   8.85  1.63      9    9.11  0.84   0.05  12.5  12.45
## diference         7 800   1.02  0.84      1    1.02  0.04 -14.35   4.4  18.75
##                  skew kurtosis   se
## cliente*         2.35     3.54 0.01
## vueltas          0.16    -1.53 0.03
## fecha*           0.11    -1.09 2.47
## plan_arrival    -2.35     3.54 0.18
## real_arrival    -1.63     2.48 0.06
## real_departure  -1.72     3.89 0.06
## diference      -12.19   214.85 0.03

Delivery Plan Con delivery plan muchas de las variables son horas o cualitativas, sin embargo tenemos la variable de unidades, la cual, al igual que en bases anteriores tiene una distribución con skew positiva y alta, por lo que en caso de valores faltantes nos convendría mas remplazar con la mediana que con la media.

ed_plan <- describe(plan)
ed_plan
##           vars   n   mean      sd median trimmed    mad min   max range  skew
## cliente*     1 972  17.71    6.87   21.0   18.52   2.97   1    26    25 -1.15
## proyecto*    2 972  46.04   26.24   58.0   46.51  14.83   1   103   102 -0.47
## item*        3 972 100.68   54.76  108.0  101.17  59.30   1   201   200 -0.20
## mes*         4 972  10.05    5.66   10.0   10.01   5.93   1    20    19 -0.03
## unidades     5 972 548.07 2016.47   90.5  176.34 116.38   1 29379 29378  8.56
##           kurtosis    se
## cliente*     -0.19  0.22
## proyecto*    -0.49  0.84
## item*        -1.12  1.76
## mes*         -1.10  0.18
## unidades     89.82 64.68
hist(plan$unidades, main= "Unidades", col = c("orange"))

Bajas En bajas muchas de las variables son cualitativas por lo que carecen de estadisticos descriptivos, sin embargo, tenemos otra como el salario diario, el cual tiene una distribución con skewness positivo también.

ed_bajas <- describe(bajas)
ed_bajas
##                  vars   n     mean       sd   median  trimmed   mad    min
## nombre_completo*    1 238   117.54    67.76   116.50   117.43 86.73   1.00
## fecha_nac*          2 238   119.50    68.85   119.50   119.50 88.21   1.00
## genero*             3 238     1.41     0.49     1.00     1.39  0.00   1.00
## fecha_alta*         4 238   119.50    68.85   119.50   119.50 88.21   1.00
## mot_baja*           5 213     2.50     1.28     2.00     2.46  1.48   1.00
## permanencia         6 213    79.71   224.98    19.00    31.18 19.27   0.00
## baja*               7 238    98.41    62.82    99.50    98.22 79.32   1.00
## puesto*             8 238     6.03     4.93     4.00     4.66  0.00   1.00
## departamento*       9 238    10.11     8.11     9.00     9.97 11.86   1.00
## sal_diario_imss    10 238   177.99    23.16   180.68   179.16  0.00 144.45
## colonia*           11 238    58.43    27.09    73.00    60.30 25.20   1.00
## CP                 12 235 64816.15 10387.65 66646.00 66657.98  2.97   0.00
## municipio*         13 238     3.82     2.74     2.00     3.41  0.00   1.00
## estado*            14 238     3.00     0.27     3.00     3.00  0.00   1.00
## estado_civil*      15 238     3.67     1.17     4.00     3.72  1.48   1.00
##                    max    range  skew kurtosis     se
## nombre_completo*   235   234.00  0.01    -1.21   4.39
## fecha_nac*         238   237.00  0.00    -1.22   4.46
## genero*              2     1.00  0.36    -1.88   0.03
## fecha_alta*        238   237.00  0.00    -1.22   4.46
## mot_baja*            5     4.00  0.33    -1.39   0.09
## permanencia       1966  1966.00  5.65    35.86  15.42
## baja*              206   205.00 -0.02    -1.26   4.07
## puesto*             22    21.00  2.33     4.09   0.32
## departamento*       21    20.00  0.08    -1.72   0.53
## sal_diario_imss    500   355.55 11.09   154.20   1.50
## colonia*            99    98.00 -0.63    -0.88   1.76
## CP               99999 99999.00 -3.74    18.53 677.62
## municipio*          12    11.00  1.06    -0.37   0.18
## estado*              4     3.00 -2.45    30.65   0.02
## estado_civil*        6     5.00 -0.53    -1.04   0.08
hist(bajas$sal_diario_imss, main= "Bajas x salario IMSS", col = c("orange"))

Colaboradores El caso de la base de datos de colaboradores es muy similar al de bajas.

ed_colaboradores <- describe(colaboradores)
ed_colaboradores
##                  vars   n     mean       sd   median  trimmed   mad      min
## nombre_completo*    1 113    57.00    32.76    57.00    57.00 41.51     1.00
## fecha_nac*          2 113    57.00    32.76    57.00    57.00 41.51     1.00
## genero*             3 113     1.46     0.50     1.00     1.45  0.00     1.00
## fecha_alta*         4 113    57.00    32.76    57.00    57.00 41.51     1.00
## puesto*             5 113     4.88     6.71     1.00     3.46  0.00     1.00
## departamento*       6 113     7.73     6.53     7.00     7.25  8.90     1.00
## sal_diario_imss     7 113   180.25    28.60   180.68   176.77  0.00   144.45
## colonia*            8 113    39.42    19.75    47.00    40.07 19.27     1.00
## municipio*          9 113     2.58     2.39     1.00     2.14  0.00     1.00
## estado*            10 113     2.17     0.55     2.00     2.19  0.00     1.00
## CP                 11 113 63364.74 11201.89 66646.00 66622.84  4.45 25016.00
## estado_civil*      12 113     2.38     1.19     3.00     2.34  1.48     1.00
##                       max   range  skew kurtosis      se
## nombre_completo*   113.00   112.0  0.00    -1.23    3.08
## fecha_nac*         113.00   112.0  0.00    -1.23    3.08
## genero*              2.00     1.0  0.16    -1.99    0.05
## fecha_alta*        113.00   112.0  0.00    -1.23    3.08
## puesto*             22.00    21.0  1.53     0.74    0.63
## departamento*       19.00    18.0  0.36    -1.47    0.61
## sal_diario_imss    337.05   192.6  3.45    15.39    2.69
## colonia*            73.00    72.0 -0.38    -0.99    1.86
## municipio*           9.00     8.0  1.19     0.02    0.22
## estado*              3.00     2.0  0.08    -0.06    0.05
## CP               67493.00 42477.0 -3.06     7.42 1053.79
## estado_civil*        5.00     4.0 -0.03    -1.48    0.11
hist(colaboradores$sal_diario_imss, main= "Slario IMSS por colaboradores", col = c("orange"))

“Bar Plots” de Desempeño

Merma
Para merma, nos interesa saber el total de kilos que se producen por mes. Para gráficar el total de kilos de merma por mes primero es necesario obtener la cantidad total de kilos por mes, eso lo hacemos de la siguiente manera.

merma_mes<-aggregate(kilos ~ mes, data = merma, sum) %>% arrange(desc(kilos))
merma_mes
##          mes kilos
## 1     AGOSTO 32100
## 2       MAYO 23410
## 3    FEBRERO 22830
## 4      MARZO 22470
## 5      JULIO 19370
## 6      ABRIL 18820
## 7      JUNIO 18280
## 8      ENERO 14560
## 9 SEPTIEMBRE 13586

Una vez que ya tenemos el total por mes podemos graficarlo.

ggplot(merma_mes,aes(x= reorder(mes, -kilos),y=kilos, fill=mes))+
  geom_bar(stat="identity")+labs(x="Mes", y="Kilos")+
  theme_minimal()+
  labs(title="Kilos de merma por mes")+theme(axis.text.x = element_text(angle=65, hjust=1))

Scrap
Para Scrap hemos optado por visualizar un gráfico de barras de la cantidad y la ubicación de origen.

ggplot(scrap,aes(x= reorder(ubi_origen, -cantidad),y=cantidad, fill=ubi_origen))+
  geom_bar(stat="identity")+labs(x="Ubicación de origen", y="Cantidad")+
  theme_minimal()+
  labs(title="Cantidad por ubicación de origen")+theme(axis.text.x = element_text(angle=65, hjust=1))

Producción de Cartón
La base de datos de producción de cartón solo abarca de los meses de julio a septiembre del 2022, la base de datos de merma incluye más meses pero del mismo año. Hemos graficado la cantidad de piezas programadas por mes en producción de cartón para confirmar si el mes con mayor cantidad de piezas programadas también es el mes con mayor cantidad de kilos de merma.

carton$fecha <- as.Date(carton$fecha, format ="%d/%m/%y")
str(carton$fecha)
##  Date[1:1486], format: "2020-07-15" "2020-07-16" "2020-07-17" "2020-07-18" "2020-07-19" ...
unique(carton$fecha)
##   [1] "2020-07-15" "2020-07-16" "2020-07-17" "2020-07-18" "2020-07-19"
##   [6] "2020-07-20" "2020-07-21" "2020-07-22" "2020-07-23" "2020-07-24"
##  [11] "2020-07-25" "2020-07-26" "2020-07-27" "2020-07-28" "2020-07-29"
##  [16] "2020-07-30" "2020-07-31" "2020-08-01" "2020-08-02" "2020-08-03"
##  [21] "2020-08-04" "2020-08-05" "2020-08-06" "2020-08-07" "2020-08-08"
##  [26] "2020-08-09" "2020-08-10" "2020-08-11" "2020-08-12" "2020-08-13"
##  [31] "2020-08-14" "2020-08-15" "2020-08-16" "2020-08-17" "2020-08-18"
##  [36] "2020-08-19" "2020-08-20" "2020-08-21" "2020-08-22" "2020-08-23"
##  [41] "2020-08-24" "2020-08-25" "2020-08-26" "2020-08-27" "2020-08-28"
##  [46] "2020-08-29" "2020-08-30" "2020-08-31" "2020-09-01" "2020-09-02"
##  [51] "2020-09-03" "2020-09-04" "2020-09-05" "2020-09-06" "2020-09-07"
##  [56] "2020-09-08" "2020-09-09" "2020-09-10" "2020-09-11" "2020-09-12"
##  [61] "2020-09-13" "2020-09-14" "2020-09-15" "2020-09-16" "2020-09-17"
##  [66] "2020-09-18" "2020-09-19" "2020-09-20" "2020-09-21" "2020-09-22"
##  [71] "2020-09-23" "2020-09-24" "2020-09-25" "2020-09-26" "2020-09-27"
##  [76] "2020-09-28" "2020-09-29" "2020-09-30" "2020-10-01" "2020-10-02"
##  [81] "2020-10-03" "2020-10-04" "2020-10-05" "2020-10-06" "2020-10-07"
##  [86] "2020-10-08" "2020-10-09" "2020-10-10" "2020-10-11" "2020-10-12"
##  [91] "2020-10-13" "2020-10-14" "2020-10-15" "2020-10-16" "2020-10-17"
##  [96] "2020-10-18" "2020-10-19" "2020-10-20" "2020-10-21" "2020-10-22"
## [101] "2020-10-23" "2020-10-24" "2020-10-25" "2020-10-26" "2020-10-27"
## [106] "2020-10-28" "2020-10-29" "2020-10-30" "2020-10-31" "2020-11-01"
## [111] "2020-11-02" "2020-11-03" "2020-11-04" "2020-11-05" "2020-11-06"
## [116] "2020-11-07" "2020-11-08" "2020-11-09" "2020-11-10" "2020-11-11"
## [121] "2020-11-12" "2020-11-13" "2020-11-14" "2020-11-15" "2020-11-16"
## [126] "2020-11-17" "2020-11-18" "2020-11-19" "2020-11-20" "2020-11-21"
## [131] "2020-11-22" "2020-11-23" "2020-11-24" "2020-11-25" "2020-11-26"
## [136] "2020-11-27" "2020-11-28" "2020-11-29" "2020-11-30" "2020-12-01"
## [141] "2020-12-02" "2020-12-03" "2020-12-04" "2020-12-05" "2020-12-06"
## [146] "2020-12-07" "2020-12-08" "2020-12-09" "2020-12-10" "2020-12-11"
## [151] "2020-12-12" "2020-12-13" "2020-12-14" "2020-12-15" "2020-12-16"
## [156] "2020-12-17" "2020-12-18" "2020-12-19" "2020-12-20" "2020-12-21"
## [161] "2020-12-22" "2020-12-23" "2020-12-24" "2020-12-25" "2020-12-26"
## [166] "2020-12-27" "2020-12-28" "2020-12-29" "2020-12-30" "2020-12-31"
## [171] "2020-01-01" "2020-01-02" "2020-01-03" "2020-01-04" "2020-01-05"
## [176] "2020-01-06" "2020-01-07" "2020-01-08" "2020-01-09" "2020-01-10"
## [181] "2020-01-11" "2020-01-12" "2020-01-13" "2020-01-14" "2020-01-15"
## [186] "2020-01-16" "2020-01-17" "2020-01-18" "2020-01-19" "2020-01-20"
## [191] "2020-01-21" "2020-01-22" "2020-01-23" "2020-01-24" "2020-01-25"
## [196] "2020-01-26" "2020-01-27" "2020-01-28" "2020-01-29" "2020-01-30"
## [201] "2020-01-31" "2020-02-01" "2020-02-02" "2020-02-03" "2020-02-04"
## [206] "2020-02-05" "2020-02-06" "2020-02-07" "2020-02-08" "2020-02-09"
## [211] "2020-02-10" "2020-02-11" "2020-02-12" "2020-02-13" "2020-02-14"
## [216] "2020-02-15" "2020-02-16" "2020-02-17" "2020-02-18" "2020-02-19"
## [221] "2020-02-20" "2020-02-21" "2020-02-22" "2020-02-23" "2020-02-24"
## [226] "2020-02-25" "2020-02-26" "2020-02-27" "2020-02-28" "2020-03-01"
## [231] "2020-03-02" "2020-03-03" "2020-03-04" "2020-03-05" "2020-03-06"
## [236] "2020-03-07" "2020-03-08" "2020-03-09" "2020-03-10" "2020-03-11"
## [241] "2020-03-12" "2020-03-13" "2020-03-14" "2020-03-15" "2020-03-16"
## [246] "2020-03-17" "2020-03-18" "2020-03-19" "2020-03-20" "2020-03-21"
## [251] "2020-03-22" "2020-03-23" "2020-03-24" "2020-03-25" "2020-03-26"
## [256] "2020-03-27" "2020-03-28" "2020-03-29" "2020-03-30" "2020-03-31"
## [261] "2020-04-01" "2020-04-02" "2020-04-03" "2020-04-04" "2020-04-05"
## [266] "2020-04-06" "2020-04-07" "2020-04-08" "2020-04-09" "2020-04-10"
## [271] "2020-04-11" "2020-04-12" "2020-04-13" "2020-04-14" "2020-04-15"
## [276] "2020-04-16" "2020-04-17" "2020-04-18" "2020-04-19" "2020-04-20"
## [281] "2020-04-21" "2020-04-22" "2020-04-23" "2020-04-24" "2020-04-25"
## [286] "2020-04-26" "2020-04-27" "2020-04-28" "2020-04-29" "2020-04-30"
## [291] "2020-05-01" "2020-05-02" "2020-05-03" "2020-05-04" "2020-05-05"
## [296] "2020-05-06" "2020-05-07" "2020-05-08" "2020-05-09" "2020-05-10"
## [301] "2020-05-11" "2020-05-12" "2020-05-13" "2020-05-14" "2020-05-15"
## [306] "2020-05-16" "2020-05-17" "2020-05-18" "2020-05-19" "2020-05-20"
## [311] "2020-05-21" "2020-05-22" "2020-05-23" "2020-05-24" "2020-05-25"
## [316] "2020-05-26" "2020-05-27" "2020-05-28" "2020-05-29" "2020-05-30"
## [321] "2020-05-31" "2020-06-01" "2020-06-02" "2020-06-03" "2020-06-04"
## [326] "2020-06-05" "2020-06-06" "2020-06-07" "2020-06-08" "2020-06-09"
## [331] "2020-06-10" "2020-06-11" "2020-06-12" "2020-06-13" "2020-06-14"
## [336] "2020-06-15" "2020-06-16" "2020-06-17" "2020-06-18" "2020-06-19"
## [341] "2020-06-20" "2020-06-21" "2020-06-22" "2020-06-23" "2020-06-24"
## [346] "2020-06-25" "2020-06-26" "2020-06-27" "2020-06-28" "2020-06-29"
## [351] "2020-06-30" "2020-07-01" "2020-07-02" "2020-07-03" "2020-07-04"
## [356] "2020-07-05" "2020-07-06" "2020-07-07" "2020-07-08" "2020-07-09"
## [361] "2020-07-10" "2020-07-11" "2020-07-12" "2020-07-13" "2020-07-14"
## [366] "2020-02-29"
carton_mes <- carton %>% mutate(mes=format(fecha, "%M"))

carton_mes2<-aggregate(piezas_prog ~ mes, data = carton_mes, sum) %>% arrange(desc(piezas_prog))

ggplot(carton_mes2,aes(x= reorder(mes, -piezas_prog),y=piezas_prog, fill=mes))+
  geom_bar(stat="identity")+labs(x="Mes", y="Piezas programadas")+
  theme_minimal()+
  labs(title="Piezas programadas por mes")+theme(axis.text.x = element_text(angle=65, hjust=1))

Al observar el gráfico de barras podemos confirmar que efectivamente el mes de agosto, el mes donde más piezas programadas para producción hubo también fue el mes con mayor cantidad de merma.

Delivery Performance
Para delivery performance optamos por graficar el retraso que hubo entre el tiempo planeado de llegada con el cliente y el tiempo real. Nos dimos cuenta que el formato de hora variaba de 24 horas a 12 horas por lo que hicimos el cambio para que este correcto. Como podemos ver MAHLE tiene un delay mayor al de PRINTEL.

class(perf$real_arrival)
perf2 <- perf
perf3 <-  perf2 %>% mutate(plan_arrival=ifelse(cliente == "MAHLE"| plan_arrival ==  20 | real_arrival < 15, 8, plan_arrival))

perf3 <- mutate(perf3, delay=real_arrival-plan_arrival) 
perf3 <- aggregate(delay~cliente, data=perf3, mean)
ggplot(perf3,aes(x= cliente,y=delay, fill=cliente))+
  geom_bar(stat="identity")+labs(x="Clientes", y="Delay en min")+
  theme_minimal()+
  labs(title="Delay por cliente")+theme(axis.text.x = element_text(angle=65, hjust=1))

Delivery Plan
Con Delivery Plan queremos evaluar si el mes donde mayor cantidad de piezas programadas había también era el mes donde mayor producción hubo.

plan_mes<-aggregate(unidades ~ mes, data = plan, sum) %>% arrange(desc(unidades))

ggplot(plan_mes,aes(x= reorder(mes, -unidades),y=unidades, fill=mes))+
  geom_bar(stat="identity")+labs(x="Mes", y="Unidades programadas")+
  theme_minimal()+
  labs(title="Unidades programadas por mes")+theme(axis.text.x = element_text(angle=65, hjust=1))

Al observar el gráfico de barras podemos identificar que el mes en el que más piezas programadas hubo no fue el mes con mayor producción y merma.

Bajas
En esta gráfica de barras se pude observar que el principal motivo de las bajas son las faltas seguidamente de renuncias voluntarias. Es importante mencionar que las personas fueron dadas de bajas a pesar de tener solo una falta, por lo que no se puede realizar un buen diagnóstico sobre las bajas por faltas.

mot_baja <- bajas %>% group_by(mot_baja, genero) %>% tally()
mot_baja
## # A tibble: 11 × 3
## # Groups:   mot_baja [6]
##    mot_baja            genero        n
##    <chr>               <chr>     <int>
##  1 ABANDONO            FEMENINO     30
##  2 ABANDONO            MASCULINO    25
##  3 BAJA POR FALTAS     FEMENINO     56
##  4 BAJA POR FALTAS     MASCULINO    24
##  5 JUBILACION          MASCULINO     1
##  6 RENUNCIA VOLUNTARIA FEMENINO     37
##  7 RENUNCIA VOLUNTARIA MASCULINO    33
##  8 TERMINO DE CONTRATO FEMENINO      6
##  9 TERMINO DE CONTRATO MASCULINO     1
## 10 <NA>                FEMENINO     11
## 11 <NA>                MASCULINO    14
ggplot(data=mot_baja, aes(x=mot_baja, y=n, fill=genero)) +
geom_bar(stat="identity", position=position_dodge())+theme(axis.text.x = element_text(angle=65, hjust=1))

Colaboradores
En esta gráfica de barras podemos observar el sueldo promedio por puesto y género. Una observación importante es en el puesto de supervisor/supervisora, ya que las mujeres tienen mayor salario que los hombres a pesar de realizar el mismo trabajo. Otro puesto en donde la situación es similar pero el salario no es de mucha diferencia es en el puesto de costurera/costurero.
Al observar esta gráfica podemos decir que las mujeres ganan más, ya que a pesar de que realicen el mismo trabajo las mujeres reciben un mayor sueldo que los hombres.

sueldo_genero_puesto<-aggregate(sal_diario_imss ~ puesto+genero, data = colaboradores, mean) 

ggplot(data=sueldo_genero_puesto, aes(x=puesto, y=sal_diario_imss, fill=genero)) +
geom_bar(stat="identity", position=position_dodge())+theme(axis.text.x = element_text(angle=65, hjust=1))

“Dispersion Plots”

Merma
En esta gráfica de boxplot podemos observar la dispersión de kilos de merma por mes. Agosto es el mes con mayor dispersión,por lo que podemos inferir que en este mes es donde hay mayor producción.

ggplot(merma, aes(x=mes, y=kilos)) + 
  geom_boxplot(color="red", fill="orange", alpha=0.2)

Scrap
En esta gráfica de boxplot podemos observar la desperation de cantidad de scrap por ubicación de origen. Como se puede observar dónde hay mayor dispersión de scrap es en pre-producción y esto se puede deber a que la empresa utiliza más materiales en esta área de trabajo.

ggplot(scrap, aes(x=ubi_origen, y=cantidad)) + 
  geom_boxplot(color="red", fill="orange", alpha=0.2)

Producción de Cartón
En esta gráfica podemos observar la dispersión de tiempo de calidad por cliente de producción de cartón. Existen diferentes motivos por lo cual se tome mayor tiempo de calidad a ciertos clientes esto puede ser por:
- cantidad de piezas
- cliente frecuente
- empaque complicado

ggplot(carton, aes(x=cliente, y=tiempo_calidad)) + 
  geom_boxplot(color="red", fill="orange", alpha=0.2)+theme(axis.text.x = element_text(angle=65, hjust=1))
## Warning: Removed 55 rows containing non-finite values (stat_boxplot).

Delivery Performance
Al graficar la dispersión de la diferencia entre real arrival y departure arrival vemos que hay mayor variacion en el cliente MAHLE que en PRINTEL.

ggplot(perf, aes(x=cliente, y=diference)) + 
  geom_boxplot(color="red", fill="orange", alpha=0.2)+theme(axis.text.x = element_text(angle=65, hjust=1))

Delivery Plan
El boxplot a continuación muestra la dispersión de las unidades programadas por cliente, como podemos ver Hella y TRMX tienen mayor cantidad de unidades programadas y es más dispersa su distribución.

ggplot(plan, aes(x=cliente, y=unidades)) + 
  geom_boxplot(color="red", fill="orange", alpha=0.2)+theme(axis.text.x = element_text(angle=65, hjust=1))

Bajas
El siguiente es un boxplot de la permanencia en la empresa en las bajas por genero, por lo general las mujeres duran más en la empresa.

ggplot(bajas, aes(x=genero, y=permanencia)) + 
  geom_boxplot(color="red", fill="orange", alpha=0.2)+theme(axis.text.x = element_text(angle=65, hjust=1))
## Warning: Removed 25 rows containing non-finite values (stat_boxplot).

Colaboradores
Este boxplot muestra la dispersión que hay en el salario diario que reciben los colaboradores por género, la dispersión en mayor en el género femenino, hay mujeres que ganan considerablemente más que los hombres.

ggplot(colaboradores, aes(x=genero, y=sal_diario_imss)) + 
  geom_boxplot(color="red", fill="orange", alpha=0.2)+theme(axis.text.x = element_text(angle=65, hjust=1))

“Time Series Plots”

Merma
En el siguiente plot podemos identificar la fecha en la que hubo mayor kilos de merma. A mediados de febrero hubo una gran cantidad de merma, específicamente el 18 de febrero. Podemos observar también que después de cada pico de merma, hay una corrección y la merma disminuye. Esto podría ser por diversos factores como ajustes en la producción, en los cortes, entre otros.

merma_fecha<-aggregate(kilos ~ fecha, data = merma, sum) 
class(merma_fecha$kilos)
## [1] "integer"
ggplot(merma_fecha,aes(x=fecha,y=kilos))+
  geom_point()+
  labs(title="Kilos por fecha")+ theme(axis.text.x = element_text(angle=65, hjust=1))

Producción de Cartón
Para la producción de cartón vamos a graficar el tiempo en minutos que tomó el proceso. Para esto necesitamos restar el tiempo de inicio de proceso al de fin de proceso.

carton$inicio_proceso<-as.POSIXct(carton$inicio_proceso,format="%H:%M")
carton$inicio_proceso <- as.ITime(carton$inicio_proceso)

carton$fin_proceso<-as.POSIXct(carton$fin_proceso,format="%H:%M")
carton$fin_proceso <- as.ITime(carton$fin_proceso)

carton2<-mutate(carton, tiempo_proceso = fin_proceso - inicio_proceso)
carton2 <- filter(carton2, !tiempo_proceso < 0)

Asi mismo, vamos a sacar el promedio de tiempo que toma el proceso por cliente. De esta forma podremos saber cual cliente consume mas tiempo de produccion de Form en el mes de agosto.

prod_cliente<-aggregate(tiempo_proceso ~ cliente, data=carton2, mean)
prod_cliente
##                 cliente tiempo_proceso
## 1                 DENSO       00:20:08
## 2         HANON SYSTEMS       01:23:30
## 3                 HELLA       00:12:00
## 4  MERIDIAN LIGHTWEIGHT       00:18:56
## 5            STABILUS 1       00:20:34
## 6            STABILUS 3       00:19:00
## 7                  TRMX       00:17:11
## 8                VARROC       00:28:45
## 9          VL-017-13939       00:27:40
## 10         VL-017-14086       00:27:00
## 11              YANFENG       00:32:25
ggplot(prod_cliente,aes(x=cliente,y=tiempo_proceso))+
  geom_point()+
  labs(title="Tiempo promedio por cliente")+ theme(axis.text.x = element_text(angle=90, hjust=1))
## Don't know how to automatically pick scale for object of type ITime. Defaulting to continuous.

Como podemos ver Hanon Systems, Yen Fang y Varroc son los clientes que mayor tiempo toma su proceso de producción. Esto puede ser debido a la complejidad de sus productos o material, sin embargo, hay que prestar especial atención a la gran diferencia que hay entre Hanon Systems y el resto de clientes.

Delivery Plan
En Delivery Plan podemos observar la cantidad de unidades por mes por cliente. Podemos identificar que HELLA en la gran mayoría de las fechas es el cliente con mayor cantidad de unidades planeadas, rara vez es superado por TRMX.

plan_mesycliente <- aggregate(unidades ~ cliente+mes, data=plan, sum)

plan_mesycliente <- plan_mesycliente %>%  pivot_wider(names_from = cliente, values_from = unidades)

plan_mesycliente <- dplyr::select(plan_mesycliente, c(mes,"HELLA", "TRMX", "VARROC", "DENSO"))


ggplot(plan_mesycliente, aes(x=mes)) + 
  geom_point(aes(y = HELLA), color = "darkred") + 
  geom_point(aes(y = TRMX), color="steelblue", linetype="twodash")+
  geom_point(aes(y = VARROC), color = "darkgreen") + 
  geom_point(aes(y = DENSO), color="darkorange", linetype="twodash")+ theme(axis.text.x = element_text(angle=90, hjust=1))

Bajas
En estos gráficos de barras podemos identificar los meses donde más bajas hay y donde más ingresos hay, identificando patrones. En las bajas, la mayor cantidad ocurren al inicio del año y posteriormente a mediados pero casi nunca a finales de año. Esto podría deberse a que los colaboradores no quieren estar sin trabajo en fechas donde sus gastos pueden ser mayores como navidad, año nuevo, cierre e inicio de ciclos escolares, entre otros.

En el caso de los ingresos o altas, estas se dan más a mediados de año, muy probablemente FORM haga esto para cubrir las bajas que ocurrieron a inicios y mediados de año. De igual forma, las altas son muy bajas a finales de año, quizás podría deberse a que en estas fechas FORM está cerrando el año, preparando aguinaldos, entre otros costos que tiene por lo que prefiere no contratar nuevos empleados.

bajas$baja <- as.Date(bajas$baja, format ="%d/%m/%Y")
bajas$fecha_alta <- as.Date(bajas$fecha_alta, format ="%d/%m/%Y")

bajas_mes <- bajas %>% mutate(mes_baja=format(baja, "%m"))
bajas_mes <- bajas_mes %>% mutate(mes_alta=format(fecha_alta,"%m"))

bajas_por_mes <- bajas_mes %>% group_by(mes_baja) %>% tally()
altas_por_mes <- bajas_mes %>% group_by(mes_alta) %>% tally()

ggplot(bajas_por_mes,aes(x= reorder(mes_baja,-n),y=n, fill=mes_baja))+
  geom_bar(stat="identity")+labs(x="Mes", y="Bajas")+
  theme_minimal()+
  labs(title="Bajas por mes")+theme(axis.text.x = element_text(angle=65, hjust=1))

ggplot(altas_por_mes,aes(x= reorder(mes_alta,-n),y=n, fill=mes_alta))+
  geom_bar(stat="identity")+labs(x="Mes", y="Altas")+
  theme_minimal()+
  labs(title="Altas por mes")+theme(axis.text.x = element_text(angle=65, hjust=1))

Colaboradores
Graficamos antiguedad por puesto y podemos identificar que los hombres tienen mayor antiguedad en form que las mujeres, además que los unicos puestos donde hay hombres y mujeres son en supervisor(a) y costurera(o). Así mismo que los puestos hay más para hombres que para muejeres.

colaboradores$fecha_alta <- as.Date(colaboradores$fecha_alta, format ="%d/%m/%Y")
colaboradores <- mutate(colaboradores, antiguedad=today()-fecha_alta)

antiguedad_puesto <- aggregate(antiguedad ~ puesto+genero, data=colaboradores, mean)

ggplot(data=antiguedad_puesto, aes(x=puesto, y=antiguedad, fill=genero)) +
geom_bar(stat="identity", position=position_dodge())+theme(axis.text.x = element_text(angle=65, hjust=1))
## Don't know how to automatically pick scale for object of type difftime. Defaulting to continuous.

Principales hallazgos

Merma Realizando un análisis de la base de datos merma nos dimos cuenta que los meses con mayor producción de merma son los meses de agosto con 32,500 kilos de merma y mayo con 22,700 kilos de merma, en base a esto podemos inferir que en estos meses es donde la empresa FORM tiene mayor producción. De igual manera se identificaron los meses donde la empresa producía menos merma, los cuales fueron los meses de enero con 14,800 kilos de merma y septiembre con 12,400 kilos de merma, por lo que también podemos inferir que en estos meses FORM no tiene mucha producción.

Scrap Analizando los resultados de la base de datos Scrap, el cual se refiere a todos los desechos y/o residuos derivados del proceso industrial, se observa que SAB/Pre-Production es el lugar donde más cantidad existe con un valor total de 1500 toneladas.

Producción de cartón Las gráficas de dispersión nos indican que con el cliente YANFENG es la vez que más se ha llevado más tiempo de calidad, podemos analizar el tiempo que se llevó a cabo con un empaque y si la producción del mismo ¿es rentable para la empresa? o si lo mejor es no aceptar producir este tipo de producto.

Por otro lado con las series de tiempo, observamos que con Hanon Systems es con quien más se ha tomado tiempo en el proceso. Podemos preguntarnos si es conveniente llevar procesos de producción tan largos con un cliente y evaluar su rentabilidad.

Delivery Performance En Delivery Performance hemos podido identificar que MAHLE tiene mayor delay que PRINTEL, por lo que podría decirnos que algo sucede con MAHLE que ocasiona que se retrase más que otros clientes. Habría que tomar medidas correctivas.

Delivery Plan Al analizar los resultados, se obtuvo que el mes con más piezas programadas fue Julio de 2022, seguido de Septiembre y Mayo. Además se puede observar una caída significativa de piezas programadas entre el mes de julio a septiembre, ya que en julio hay más de 72,000 piezas programadas y para septiembre ese valor decreció con 10 mil unidades menos.

Bajas El principal motivo de las bajas fue por renuncias, este es un dato muy interesante sin embargo no se puede llegar a hacer una buena interpretación ya que muchos de los ex empleados fueron dados de baja solo por faltar un día. El segundo motivo de las bajas fue por renuncia voluntaria y muchas de estas personas no renunciaron sin complir el año en la empresa. Es importante que la empresa recuerde bien la información sobre las bajas y sus motivos para de esta manera generar una buena estrategia en disminuir la rotación de empleados, ya que, la mayoría de los empleados solo dura un año o menos en la empresa.

Colaboradores La persona que más salario tienen son la supervisora mujeres y los de mantenimiento, si FORM necesita un recorte en gastos se fijaría primeramente en estas personas.

Predicción del Desempeño de la Industria Automotriz

Importar Bases de Datos (México)

ventasi_autopartes <- read.csv("/Users/anita3/Desktop/FORM/VentasAP.csv")

Importar Bases de Datos (EUA)

eua <- read.csv("/Users/anita3/Downloads/car_production.csv")

Librerias a Utilizar

library(tseries)   
library(forecast)  
library(astsa)    

Modelo de regresión lineal múltiple México

Tenemos las ventas internacionales de autopartes por estado de la república mexicana. Nuestro proosito es encontrar el estado con mayor futuro y volumen de ventas internacionales de autopartes.

summary(ventasi_autopartes)
##       year       id_trimestre     trimestre       id_estado    
##  Min.   :2014   Min.   :20141   Min.   :1.000   Min.   : 1.00  
##  1st Qu.:2016   1st Qu.:20161   1st Qu.:1.000   1st Qu.:10.00  
##  Median :2018   Median :20181   Median :2.000   Median :17.00  
##  Mean   :2018   Mean   :20180   Mean   :2.399   Mean   :17.37  
##  3rd Qu.:2020   3rd Qu.:20201   3rd Qu.:3.000   3rd Qu.:26.00  
##  Max.   :2022   Max.   :20222   Max.   :4.000   Max.   :32.00  
##     estado          id_estado_and_id_trimestre   idnueva         
##  Length:690         Min.   : 120141            Length:690        
##  Class :character   1st Qu.:1020152            Class :character  
##  Mode  :character   Median :1720178            Mode  :character  
##                     Mean   :1756991                              
##                     3rd Qu.:2620172                              
##                     Max.   :3220222                              
##  ventas_autopartes_trimestre ventas_autopartes_anual      eci         
##  Min.   :1.084e+04           Min.   :4.382e+03       Min.   :-0.9374  
##  1st Qu.:8.805e+07           1st Qu.:2.256e+07       1st Qu.:-0.4630  
##  Median :8.976e+08           Median :2.316e+08       Median : 0.7088  
##  Mean   :1.238e+09           Mean   :3.307e+08       Mean   : 0.4391  
##  3rd Qu.:2.151e+09           3rd Qu.:5.759e+08       3rd Qu.: 0.9138  
##  Max.   :4.206e+09           Max.   :1.467e+09       Max.   : 1.7810  
##  poblacion_ocupada_ensambladora_year exportaciones_anual
##  Length:690                          Length:690         
##  Class :character                    Class :character   
##  Mode  :character                    Mode  :character   
##                                                         
##                                                         
##                                                         
##  exportaciones_trimestrales iedanual_porestado
##  Length:690                 Length:690        
##  Class :character           Class :character  
##  Mode  :character           Mode  :character  
##                                               
##                                               
## 
Limpieza

¿Que modificaciones le haremos a la base de datos?
En excel realizamos limpieza de datos con: nombres_de_variables, añadir cifrias anuales y unir bases de datos. Esto con la finalidad de realizar una predicción sobre los Estados de la República con el mayor número de ventas internacionales de autopartes en México.

En R, la limpieza que realizaremos será: eliminar registros de los trimestres 2, 3 y 4. Usamos como base el trimestre 1 para juntar las cifras anuales y no repetir registros.

Eliminamos las columnas que no necesitaremos y Cambiamos los tipos de variable.

Filtrar por Trismestre

vap_1 <- ventasi_autopartes
vap_1 <- filter(vap_1, trimestre == 1)

Eliminar Columnas

vap_2 <- vap_1
vap_2 <- subset(vap_2,select = -c(id_trimestre, trimestre, id_estado, id_estado_and_id_trimestre, idnueva, ventas_autopartes_trimestre, exportaciones_trimestrales))
summary(vap_2)
##       year         estado          ventas_autopartes_anual      eci         
##  Min.   :2014   Length:186         Min.   :7.241e+03       Min.   :-0.9374  
##  1st Qu.:2016   Class :character   1st Qu.:2.344e+07       1st Qu.:-0.4143  
##  Median :2018   Mode  :character   Median :2.314e+08       Median : 0.7088  
##  Mean   :2018                      Mean   :3.302e+08       Mean   : 0.4587  
##  3rd Qu.:2020                      3rd Qu.:5.574e+08       3rd Qu.: 0.9138  
##  Max.   :2022                      Max.   :1.300e+09       Max.   : 1.7810  
##  poblacion_ocupada_ensambladora_year exportaciones_anual iedanual_porestado
##  Length:186                          Length:186          Length:186        
##  Class :character                    Class :character    Class :character  
##  Mode  :character                    Mode  :character    Mode  :character  
##                                                                            
##                                                                            
## 

Cambiar tipos de variable

vap_3 <- vap_2
vap_3$ventas_autopartes_anual <- as.numeric(vap_3$ventas_autopartes_anual)
vap_3$eci <- as.numeric(vap_3$eci)
vap_3$poblacion_ocupada_ensambladora_year <- as.numeric(vap_3$poblacion_ocupada_ensambladora_year)
## Warning: NAs introduced by coercion
vap_3$exportaciones_anual <- as.numeric(vap_3$exportaciones_anual)
## Warning: NAs introduced by coercion
vap_3$iedanual_porestado <- as.numeric(vap_3$iedanual_porestado)
## Warning: NAs introduced by coercion
vap_3$year <- as.numeric(vap_3$year)
vap_3$estado <- as.character(vap_3$estado)
vap_3
vap_4 <- vap_3
vap_4 <- vap_4 %>%
  group_by(estado) %>%
  summarise(ventas = sum(ventas_autopartes_anual))
vap_4
vap_7 <- vap_3
top_5 <- vap_4 %>%
  filter(rank(desc(ventas))<=5)
top_5
Encontrar el top 5 de los estados con mayor numero de ventas internacionales de autopartes y enfocarnos en ellos.

Eliminar registros de estados no relevantes

nueva <- vap_3
nueva <- filter(nueva, !estado=="Durango")
nueva <- filter(nueva, !estado=="Hidalgo")
nueva <- filter(nueva, !estado=="Jalisco")
nueva <- filter(nueva, !estado=="Estado de Mexico")
nueva <- filter(nueva, !estado=="Morelos")
nueva <- filter(nueva, !estado=="Hidalgo")
nueva <- filter(nueva, !estado=="Quintana Roo")
nueva <- filter(nueva, !estado=="Sonora")
nueva <- filter(nueva, !estado=="Zacatecas")
nueva <- filter(nueva, !estado=="Yucatan")
nueva <- filter(nueva, !estado=="Tlaxcala")
nueva <- filter(nueva, !estado=="Veracruz de Ignacio de la Llave")
nueva <- filter(nueva, !estado=="Colima")
nueva <- filter(nueva, !estado=="Baja California")
nueva <- filter(nueva, !estado=="Chihuaua")
nueva <- filter(nueva, !estado=="Puebla")
nueva <- filter(nueva, !estado=="Aguascalientes")
nueva <- filter(nueva, !estado=="San Luis Potosi")
nueva <- filter(nueva, !estado=="Tamaulipas")
nueva <- filter(nueva, !estado=="Chihuahua")
nueva <- filter(nueva, !estado=="Ciudad de Mexico")

unique(nueva$estado)

Eliminamos tambien a Ciudad de Mexico debido a que es un mercado fuera del que busca FORM

top_4 <- nueva
top_4
Podemos identificar las variables a utilizar dentro del modelo.

ventas_autopartes_anual
Es la variable dependiente que nos ayudará a responder la pregunta principal sobre las ventas por estado.

eci
Variable exploratoria para comparar los estados con mayores niveles de ingresos, potencial de crecimiento económico, menor desigualdad de ingresos y menores emisiones.

poblacion_ocupada_ensambladora_year
Variable exploratoria que se refiere a las personas dentro del estado que trabajan dierectamente dentro de la industria de autopartes en el respecivo año.

exportaciones_anual
Variable exploratoria que se refiere a el número de exportaciones anuales del estado en todas las industrias.

iedanual_porestadol
Variable explanatoria que se refiere a la inversion extranjera directa anual del estado, no necesariamente enfocada en la industria automotriz.

Realizaremos un modelo de regresion lineal para los estados de Coahuila, Guanajuato, Nuevo Leon y Queretaro. Esto nos permitirá evaluar el rumbo de los estados con más ventas internacionales de autopartes.

Modelo de Regresion Lineal por Estado
model1coahuila<-lm(ventas_autopartes_anual~eci+poblacion_ocupada_ensambladora_year+exportaciones_anual+iedanual_porestado,data=coahuila) 
summary(model1coahuila)
## 
## Call:
## lm(formula = ventas_autopartes_anual ~ eci + poblacion_ocupada_ensambladora_year + 
##     exportaciones_anual + iedanual_porestado, data = coahuila)
## 
## Residuals:
##          1          2          3          4          5          6          7 
## -112098108  -21573011   68781706   17705699   66916376  -25757932  -54147456 
##          8 
##   60172727 
## 
## Coefficients: (1 not defined because of singularities)
##                                       Estimate Std. Error t value Pr(>|t|)
## (Intercept)                          4.803e+08  4.315e+08   1.113    0.328
## eci                                         NA         NA      NA       NA
## poblacion_ocupada_ensambladora_year  8.151e+03  5.473e+03   1.489    0.211
## exportaciones_anual                  8.748e-03  1.100e-02   0.796    0.471
## iedanual_porestado                  -1.232e-01  9.976e-02  -1.235    0.284
## 
## Residual standard error: 86270000 on 4 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.7555, Adjusted R-squared:  0.5722 
## F-statistic:  4.12 on 3 and 4 DF,  p-value: 0.1025

Coahuila: Adjusted R-squared: 0.5317

model1nuevoleon<-lm(ventas_autopartes_anual~eci+poblacion_ocupada_ensambladora_year+exportaciones_anual+iedanual_porestado,data=nuevoleon) 
summary(model1nuevoleon)
## 
## Call:
## lm(formula = ventas_autopartes_anual ~ eci + poblacion_ocupada_ensambladora_year + 
##     exportaciones_anual + iedanual_porestado, data = nuevoleon)
## 
## Residuals:
##         1         2         3         4         5         6         7         8 
## -27425247  45082342  13143113  34080604 -16783601 -23023827   1501825 -26575210 
## 
## Coefficients: (1 not defined because of singularities)
##                                       Estimate Std. Error t value Pr(>|t|)   
## (Intercept)                          9.950e+08  1.572e+08   6.329  0.00319 **
## eci                                         NA         NA      NA       NA   
## poblacion_ocupada_ensambladora_year  6.950e+03  3.018e+03   2.303  0.08270 . 
## exportaciones_anual                 -1.530e-02  4.382e-03  -3.492  0.02508 * 
## iedanual_porestado                  -4.235e-02  2.339e-02  -1.810  0.14447   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 37550000 on 4 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.7897, Adjusted R-squared:  0.6321 
## F-statistic: 5.008 on 3 and 4 DF,  p-value: 0.07683

Nuevo Leon: Adjusted R-squared: 0.8242

model1guanajuato<-lm(ventas_autopartes_anual~eci+poblacion_ocupada_ensambladora_year+exportaciones_anual+iedanual_porestado,data=guanajuato) 
summary(model1guanajuato)
## 
## Call:
## lm(formula = ventas_autopartes_anual ~ eci + poblacion_ocupada_ensambladora_year + 
##     exportaciones_anual + iedanual_porestado, data = guanajuato)
## 
## Residuals:
##         1         2         3         4         5         6         7         8 
## -41107653  16667588   6583736  55782925 -20566009 -50526839   9687603  23478649 
## 
## Coefficients: (1 not defined because of singularities)
##                                      Estimate Std. Error t value Pr(>|t|)  
## (Intercept)                         3.208e+08  1.443e+08   2.223   0.0903 .
## eci                                        NA         NA      NA       NA  
## poblacion_ocupada_ensambladora_year 3.954e+03  2.548e+03   1.551   0.1958  
## exportaciones_anual                 1.347e-02  6.916e-03   1.948   0.1233  
## iedanual_porestado                  4.981e-02  3.681e-02   1.353   0.2474  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 46750000 on 4 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.7318, Adjusted R-squared:  0.5307 
## F-statistic: 3.639 on 3 and 4 DF,  p-value: 0.1221

Guanajuato: Adjusted R-squared: 0.5904

model1queretaro<-lm(ventas_autopartes_anual~eci+poblacion_ocupada_ensambladora_year+exportaciones_anual+iedanual_porestado,data=queretaro) 
summary(model1queretaro)
## 
## Call:
## lm(formula = ventas_autopartes_anual ~ eci + poblacion_ocupada_ensambladora_year + 
##     exportaciones_anual + iedanual_porestado, data = queretaro)
## 
## Residuals:
##         1         2         3         4         5         6         7         8 
## -29436644   9131024  37147064 -44654010  -2383969 -15201637  -4223647  49621818 
## 
## Coefficients: (1 not defined because of singularities)
##                                       Estimate Std. Error t value Pr(>|t|)  
## (Intercept)                          4.902e+08  2.016e+08   2.431   0.0719 .
## eci                                         NA         NA      NA       NA  
## poblacion_ocupada_ensambladora_year  2.845e+04  1.877e+04   1.516   0.2042  
## exportaciones_anual                  1.420e-02  1.763e-02   0.805   0.4659  
## iedanual_porestado                  -6.691e-02  1.292e-01  -0.518   0.6319  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 41950000 on 4 degrees of freedom
##   (1 observation deleted due to missingness)
## Multiple R-squared:  0.7624, Adjusted R-squared:  0.5842 
## F-statistic: 4.279 on 3 and 4 DF,  p-value: 0.09704

Queretaro: Adjusted R-squared: 0.686

options(scipen =999)
plot(nuevoleon$year,nuevoleon$ventas_autopartes_anual, type="l",col="orange", lwd=1.5, xlab ="año",ylab ="Ventas en dolares", main = "Ventas Internacionales de Nuevo Leon en Autopartes ")
lines(nuevoleon$ventas_autopartes_anual,coahuila$ventas_autopartes_anual, col="green",lty=3)
legend("topleft", legend=c("Nuevo Leon", "Coahuila"),
       col=c("orange", "green"), lty = 1:2, cex=0.8) 

options(scipen =999)
colors <- c("coahuila"="green", "nuevoleon"="orange", "queretaro"="blue", "guanajuato"="red")
ggplot(data=coahuila, aes(x=year, y=ventas_autopartes_anual), color='green') + 
geom_line() + 
geom_line(data=nuevoleon, aes(x=year, y=ventas_autopartes_anual), color='orange') + 
geom_line() + 
geom_line(data=queretaro, aes(x=year, y=ventas_autopartes_anual), color='blue')+
geom_line() + 
geom_line(data=guanajuato, aes(x=year, y=ventas_autopartes_anual), color='red')+
  scale_colour_manual("", 
                      breaks = c("Coahuila", "Nuevo Leon", "Queretaro", "Guanajuato"),
                      values = c("green", "orange", "blue", "red"))+
  labs(x="Year", y="Total Ventas Dolares")

Modelo de regresión lineal múltiple EUA

names (eua)[3] = "poblacion_desocupada"
str(eua)
## 'data.frame':    28 obs. of  5 variables:
##  $ year                 : int  1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 ...
##  $ us_car_production    : num  6601200 6326100 6035200 5878300 5492300 ...
##  $ poblacion_desocupada : num  8000000 7400000 7240000 6740000 6210000 5880000 5690000 6800000 8380000 8770000 ...
##  $ imports_value        : num  663250000000000 743540000000000 795290000000000 869700000000000 911900000000000 ...
##  $ retail_price_gasoline: num  1.08 1.11 1.2 1.2 1.03 1.14 1.48 1.42 1.35 1.56 ...
corrplot(cor(eua),type='upper',order='hclust',addCoef.col='black') 

model1<-lm(us_car_production~poblacion_desocupada+retail_price_gasoline+imports_value,data=eua)     
summary(model1)
## 
## Call:
## lm(formula = us_car_production ~ poblacion_desocupada + retail_price_gasoline + 
##     imports_value, data = eua)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1359520  -352691  -111282   344515  1063427 
## 
## Coefficients:
##                                    Estimate            Std. Error t value
## (Intercept)           8275412.3037308147177  445399.4491195540177  18.580
## poblacion_desocupada       -0.2131769451487       0.0530583892962  -4.018
## retail_price_gasoline 1029583.7625037067337  320655.8808632462169   3.211
## imports_value              -0.0000000026274       0.0000000003765  -6.978
##                                   Pr(>|t|)    
## (Intercept)           0.000000000000000946 ***
## poblacion_desocupada              0.000504 ***
## retail_price_gasoline             0.003741 ** 
## imports_value         0.000000324193824012 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 595000 on 24 degrees of freedom
## Multiple R-squared:  0.827,  Adjusted R-squared:  0.8053 
## F-statistic: 38.23 on 3 and 24 DF,  p-value: 0.00000000266
model2<-lm(retail_price_gasoline~poblacion_desocupada+us_car_production+imports_value,data=eua)     
summary(model2)
## 
## Call:
## lm(formula = retail_price_gasoline ~ poblacion_desocupada + us_car_production + 
##     imports_value, data = eua)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.8133 -0.1041  0.0030  0.1254  0.5793 
## 
## Coefficients:
##                                    Estimate             Std. Error t value
## (Intercept)          -2.6282922583622485568  0.7597789559560633732  -3.459
## poblacion_desocupada  0.0000001231329615166  0.0000000265147666152   4.644
## us_car_production     0.0000002918546849205  0.0000000908958789809   3.211
## imports_value         0.0000000000000014792  0.0000000000000001748   8.463
##                          Pr(>|t|)    
## (Intercept)              0.002037 ** 
## poblacion_desocupada     0.000103 ***
## us_car_production        0.003741 ** 
## imports_value        0.0000000115 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.3168 on 24 degrees of freedom
## Multiple R-squared:  0.8751, Adjusted R-squared:  0.8595 
## F-statistic: 56.07 on 3 and 24 DF,  p-value: 0.00000000005445

Intepretación de los resultados

¿Cuáles son las variables explanatorias que muestran un impacto significativo en la variable dependiente?
¿Cómo es el impacto de dichas variables explanatorias sobre la variable dependiente?

Pronóstico del Desempeño de la Industria Automotriz y la Empresa FORM

Pronóstico México

Moving Average
summary(model1nuevoleon<-arma(nuevoleon$ventas_autopartes_anual,order=c(0,1)))
## 
## Call:
## arma(x = nuevoleon$ventas_autopartes_anual, order = c(0, 1))
## 
## Model:
## ARMA(0,1)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -155651952  -37299724   19338817   44510100   79154505 
## 
## Coefficient(s):
##                 Estimate     Std. Error   t value            Pr(>|t|)    
## ma1               0.7301         0.3604     2.026              0.0428 *  
## intercept 600553057.7170     37703.4591 15928.328 <0.0000000000000002 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Fit:
## sigma^2 estimated as 5473146058018973,  Conditional Sum-of-Squares = 38381860832053096,  AIC = 355.69
nuevoleon_forecast<-forecast(model1nuevoleon$fitted,h=5,level=c(95))
## Warning in ets(object, lambda = lambda, biasadj = biasadj,
## allow.multiplicative.trend = allow.multiplicative.trend, : Missing values
## encountered. Using longest contiguous portion of time series
nuevoleon_forecast
##    Point Forecast     Lo 95     Hi 95
## 10      591345747 488822579 693868916
## 11      591345747 488822579 693868916
## 12      591345747 488822578 693868917
## 13      591345747 488822578 693868917
## 14      591345747 488822577 693868918

Pronóstico EUA

colSums(is.na(eua))
##                  year     us_car_production  poblacion_desocupada 
##                     0                     0                     0 
##         imports_value retail_price_gasoline 
##                     0                     0
summary(ma_model<-arma(eua$us_car_production/1000,order=c(0,1)))
## 
## Call:
## arma(x = eua$us_car_production/1000, order = c(0, 1))
## 
## Model:
## ARMA(0,1)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1829.05  -510.98   -93.95   407.41  2190.13 
## 
## Coefficient(s):
##            Estimate  Std. Error  t value             Pr(>|t|)    
## ma1           0.670       0.106    6.319       0.000000000263 ***
## intercept  4135.974     280.249   14.758 < 0.0000000000000002 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Fit:
## sigma^2 estimated as 848999,  Conditional Sum-of-Squares = 22184465,  AIC = 465.71
ma_model_forecast
##    Point Forecast    Lo 95   Hi 95
## 29       3395.174 2685.108 4105.24
## 30       3340.308 2641.717 4038.90
## 31       3285.443 2598.325 3972.56

Pronóstico del desempeño de 2 de las áreas de la empresa FORM

** Producción de Carton**

Modelo 1

carton2 <- carton
str(carton2)
## 'data.frame':    1486 obs. of  11 variables:
##  $ fecha         : Date, format: "2020-07-15" "2020-07-16" ...
##  $ cliente       : chr  "YANFENG" "TRMX" "YANFENG" "STABILUS 1" ...
##  $ piezas_prog   : int  20 200 500 300 5 200 200 100 200 100 ...
##  $ tmo_min       : int  10 20 60 20 10 25 25 20 25 20 ...
##  $ hr_fin        : chr  "10:15:00" "10:35:00" "10:00:00" "10:20:00" ...
##  $ lam_procesadas: int  51 402 501 152 3 202 202 216 407 212 ...
##  $ inicio_sep_up : chr  "12:00:00" "12:32:00" "9:00:00" "9:22:00" ...
##  $ fin_sep_up    : chr  "12:05:00" "12:34:00" "9:11:00" "9:24:00" ...
##  $ inicio_proceso: 'ITime' int  12:15:00 12:47:00 09:13:00 09:27:00 11:36:00 09:06:00 09:43:00 11:47:00 10:00:00 12:53:00 ...
##  $ fin_proceso   : 'ITime' int  12:31:00 02:00:00 10:59:00 09:41:00 11:40:00 09:13:00 09:49:00 11:58:00 11:16:00 01:02:00 ...
##  $ tiempo_calidad: int  1 1 2 3 3 1 1 1 1 1 ...
carton_model<-dplyr::select(carton2,-c(fecha, cliente, hr_fin, inicio_sep_up,inicio_proceso,fin_proceso, fin_sep_up ))
colnames(carton_model)
## [1] "piezas_prog"    "tmo_min"        "lam_procesadas" "tiempo_calidad"
carton_model <- drop_na(carton_model)
corrplot(cor(carton_model),type='upper',order='hclust',addCoef.col='black') 

modelcarton<-lm(lam_procesadas~piezas_prog+tmo_min,data=carton_model)     
summary(modelcarton)
## 
## Call:
## lm(formula = lam_procesadas ~ piezas_prog + tmo_min, data = carton_model)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -909.09  -37.62   -1.45   23.22  858.05 
## 
## Coefficients:
##             Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)  5.37368    5.16877   1.040                0.299    
## piezas_prog  0.67417    0.02924  23.056 < 0.0000000000000002 ***
## tmo_min      1.58286    0.27617   5.731         0.0000000121 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 99.78 on 1419 degrees of freedom
## Multiple R-squared:  0.5119, Adjusted R-squared:  0.5112 
## F-statistic: 744.2 on 2 and 1419 DF,  p-value: < 0.00000000000000022
summary(modelcarton<-arma(carton2$lam_procesadas,order=c(0,1)))
## 
## Call:
## arma(x = carton2$lam_procesadas, order = c(0, 1))
## 
## Model:
## ARMA(0,1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -329.02  -93.83  -33.33   47.86 1114.20 
## 
## Coefficient(s):
##            Estimate  Std. Error  t value            Pr(>|t|)    
## ma1         0.25224     0.02221    11.36 <0.0000000000000002 ***
## intercept 153.83179     4.41920    34.81 <0.0000000000000002 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Fit:
## sigma^2 estimated as 18525,  Conditional Sum-of-Squares = 27491243,  AIC = 18823.83
modelcarton_forecast<-forecast(modelcarton$fitted,h=3,level=c(95))
## Warning in ets(object, lambda = lambda, biasadj = biasadj,
## allow.multiplicative.trend = allow.multiplicative.trend, : Missing values
## encountered. Using longest contiguous portion of time series
modelcarton_forecast
##      Point Forecast    Lo 95    Hi 95
## 1487       148.6078 84.09279 213.1227
## 1488       148.6078 84.01919 213.1963
## 1489       148.6078 83.94566 213.2699

Modelo 2

str(carton2)
## 'data.frame':    1486 obs. of  11 variables:
##  $ fecha         : Date, format: "2020-07-15" "2020-07-16" ...
##  $ cliente       : chr  "YANFENG" "TRMX" "YANFENG" "STABILUS 1" ...
##  $ piezas_prog   : int  20 200 500 300 5 200 200 100 200 100 ...
##  $ tmo_min       : int  10 20 60 20 10 25 25 20 25 20 ...
##  $ hr_fin        : chr  "10:15:00" "10:35:00" "10:00:00" "10:20:00" ...
##  $ lam_procesadas: int  51 402 501 152 3 202 202 216 407 212 ...
##  $ inicio_sep_up : chr  "12:00:00" "12:32:00" "9:00:00" "9:22:00" ...
##  $ fin_sep_up    : chr  "12:05:00" "12:34:00" "9:11:00" "9:24:00" ...
##  $ inicio_proceso: 'ITime' int  12:15:00 12:47:00 09:13:00 09:27:00 11:36:00 09:06:00 09:43:00 11:47:00 10:00:00 12:53:00 ...
##  $ fin_proceso   : 'ITime' int  12:31:00 02:00:00 10:59:00 09:41:00 11:40:00 09:13:00 09:49:00 11:58:00 11:16:00 01:02:00 ...
##  $ tiempo_calidad: int  1 1 2 3 3 1 1 1 1 1 ...
cartonp_dia <- dplyr::select(carton2, fecha, piezas_prog, tmo_min, lam_procesadas, tiempo_calidad)
cartonp_dia <- cartonp_dia %>%
  dplyr::group_by(fecha) %>%
  dplyr::summarize(piezas_dia = sum(piezas_prog), tminimo_dia = sum(tmo_min), laminas_dia =sum(lam_procesadas), tcalidad_dia = sum(tiempo_calidad))
model1form<-lm(laminas_dia~piezas_dia+tminimo_dia,data=cartonp_dia)     
summary(model1form)
## 
## Call:
## lm(formula = laminas_dia ~ piezas_dia + tminimo_dia, data = cartonp_dia)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -536.06 -107.38   -7.30   81.39  817.50 
## 
## Coefficients:
##             Estimate Std. Error t value             Pr(>|t|)    
## (Intercept) -7.96655   33.00223  -0.241              0.80939    
## piezas_dia   0.70685    0.05847  12.089 < 0.0000000000000002 ***
## tminimo_dia  1.60012    0.51714   3.094              0.00213 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 194 on 354 degrees of freedom
##   (9 observations deleted due to missingness)
## Multiple R-squared:  0.5823, Adjusted R-squared:   0.58 
## F-statistic: 246.8 on 2 and 354 DF,  p-value: < 0.00000000000000022
summary(model1form<-arma(cartonp_dia$laminas_dia,order=c(1,1)))
## 
## Call:
## arma(x = cartonp_dia$laminas_dia, order = c(1, 1))
## 
## Model:
## ARMA(1,1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -544.82 -185.68  -57.15  142.86  959.65 
## 
## Coefficient(s):
##            Estimate  Std. Error  t value             Pr(>|t|)    
## ar1         0.78167     0.06910   11.312 < 0.0000000000000002 ***
## ma1        -0.51356     0.09324   -5.508         0.0000000363 ***
## intercept 136.14853    43.62697    3.121               0.0018 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Fit:
## sigma^2 estimated as 75988,  Conditional Sum-of-Squares = 27659544,  AIC = 5157.89
model1form_forecast<-forecast(model1form$fitted,h=3,level=c(95))
## Warning in ets(object, lambda = lambda, biasadj = biasadj,
## allow.multiplicative.trend = allow.multiplicative.trend, : Missing values
## encountered. Using longest contiguous portion of time series
model1form_forecast
##     Point Forecast    Lo 95    Hi 95
## 367        676.879 524.0736 829.6844
## 368        676.879 474.8881 878.8699
## 369        676.879 435.5262 918.2317

K-means

Importar base de datos

mex2 <- read.csv("/Users/anita3/Downloads/tradevaluenuevo2.csv")
mex_alt<-mex2 %>% dplyr::select(State, concentracionmercado_hierroyacero, exportaciones_por_estado, venta_autopartes_por_estado, cajas_de.papel_o_carton )

Eliminar registros con NA´S y Convertir Variables a Numerico

mex_alt$concentracionmercado_hierroyacero<- as.numeric(mex_alt$concentracionmercado_hierroyacero)
mex_alt$exportaciones_por_estado<- as.numeric(mex_alt$exportaciones_por_estado)
## Warning: NAs introduced by coercion
mex_alt$venta_autopartes_por_estado<- as.numeric(mex_alt$venta_autopartes_por_estado)
## Warning: NAs introduced by coercion
mex_alt$cajas_de.papel_o_carton<- as.numeric(mex_alt$cajas_de.papel_o_carton)
## Warning: NAs introduced by coercion
mex_alt <- filter(mex_alt, !is.na(mex_alt$exportaciones_por_estado))
mex_alt <- filter(mex_alt, !is.na(mex_alt$venta_autopartes_por_estado))
mex_alt <- filter(mex_alt, !is.na(mex_alt$cajas_de.papel_o_carton))
mex_alt_norm<-scale(mex_alt[3:4]) 
fviz_nbclust(mex_alt_norm, kmeans, method="wss")+ # wss method considers total within sum of square
  geom_vline(xintercept=4, linetype=2)+           # optimal number of clusters is computed with the default method = "euclidean"
  labs(subtitle = "Elbow method")  

mex_cluster1<-kmeans(mex_alt_norm,4)
mex_cluster1
## K-means clustering with 4 clusters of sizes 397, 334, 122, 182
## 
## Cluster means:
##   exportaciones_por_estado venta_autopartes_por_estado
## 1               -0.8551414                  -0.8058148
## 2                0.2258218                  -0.2171287
## 3               -0.3005659                   1.5189365
## 4                1.6523940                   1.1380176
## 
## Clustering vector:
##    [1] 1 2 2 2 1 1 1 1 2 1 1 2 1 1 1 1 2 1 1 1 2 2 2 1 1 1 2 2 2 1 1 1 1 2 1 1 1
##   [38] 2 2 2 1 1 1 2 1 2 1 1 1 1 2 1 1 1 1 2 2 2 1 1 1 2 1 2 1 1 1 1 2 1 1 2 2 2
##   [75] 1 1 1 1 2 1 2 1 1 1 1 2 1 1 1 2 1 2 1 1 2 1 2 1 1 1 1 2 1 2 2 2 1 1 1 2 1
##  [112] 2 1 1 1 1 2 1 1 2 2 2 1 1 2 1 2 1 1 1 1 2 1 1 2 2 2 1 2 2 1 2 1 3 1 1 2 1
##  [149] 1 1 2 2 4 1 1 2 2 1 1 2 1 3 1 1 2 1 1 1 2 2 4 1 1 2 2 1 2 1 3 1 1 2 1 1 1
##  [186] 2 2 4 1 1 2 2 1 2 1 3 1 2 2 1 1 1 2 2 2 1 1 2 2 2 3 1 3 1 2 2 1 1 1 1 2 4
##  [223] 4 1 1 3 2 2 4 1 3 1 2 2 1 2 4 4 1 3 2 2 4 2 3 1 2 2 1 1 2 4 4 1 1 3 1 2 2
##  [260] 1 4 1 3 1 2 2 1 1 1 1 2 4 4 1 1 3 2 2 1 1 4 1 3 1 2 2 1 1 1 2 4 4 1 1 3 2
##  [297] 2 1 4 2 3 1 2 2 1 1 1 1 2 4 4 1 1 3 1 2 2 1 4 2 3 1 1 2 1 1 1 2 4 4 1 1 3
##  [334] 2 2 1 4 2 3 1 2 2 1 1 1 2 4 4 1 1 3 2 2 1 3 2 3 1 2 2 1 1 1 1 1 2 4 4 1 1
##  [371] 3 2 2 1 4 2 3 1 2 2 1 1 1 2 4 4 1 1 3 2 2 1 4 2 3 1 2 2 1 1 2 1 4 4 1 1 3
##  [408] 2 2 1 4 1 3 1 2 4 1 1 1 2 2 4 4 3 1 3 2 2 1 4 2 3 1 2 2 1 2 2 4 4 1 1 3 2
##  [445] 2 1 4 2 3 1 2 4 1 1 1 2 2 4 4 3 1 3 2 2 1 4 2 3 1 2 4 1 1 1 2 4 4 4 3 1 3
##  [482] 2 2 1 4 2 3 1 2 4 1 1 1 2 2 4 4 1 1 3 2 2 1 4 2 3 1 2 4 1 1 2 2 4 4 1 1 3
##  [519] 2 2 1 4 2 3 2 2 4 1 1 1 1 2 4 4 4 3 1 3 1 2 2 1 4 2 3 2 2 4 1 1 1 1 2 4 4
##  [556] 4 3 1 3 1 2 2 1 4 2 3 2 2 4 1 1 1 2 2 4 4 3 1 3 2 2 1 4 1 3 1 2 3 1 1 1 1
##  [593] 2 2 4 4 3 1 3 2 2 1 4 2 3 2 2 4 1 1 1 2 2 4 4 3 1 3 2 2 4 2 3 1 2 4 1 1 1
##  [630] 2 4 4 4 3 1 3 1 2 2 1 4 2 3 2 2 4 1 1 2 2 4 4 3 1 3 2 2 1 4 2 3 2 2 3 1 1
##  [667] 1 2 2 4 4 3 1 3 1 2 2 1 4 2 3 2 2 4 1 1 1 1 2 2 4 4 3 1 3 2 2 1 4 2 3 2 2
##  [704] 4 1 1 1 2 4 4 4 3 1 3 2 2 1 4 2 3 2 2 4 1 1 1 1 2 2 4 4 3 1 3 1 2 2 4 2 3
##  [741] 2 2 4 1 1 1 2 4 4 4 3 1 3 2 2 1 4 2 3 2 2 4 1 1 1 2 4 4 4 3 1 3 2 2 1 4 2
##  [778] 3 2 2 4 1 1 2 4 4 4 3 1 3 2 2 1 4 2 3 2 2 4 1 1 1 2 2 4 4 3 1 3 1 2 2 1 4
##  [815] 2 3 2 2 4 1 1 1 1 2 4 4 4 3 1 3 2 2 1 4 2 3 2 2 4 1 1 1 1 2 4 4 4 3 1 3 1
##  [852] 2 2 1 4 2 3 2 2 4 1 1 1 1 2 4 4 4 3 1 3 1 2 2 1 4 2 3 2 2 4 1 1 1 2 4 4 4
##  [889] 3 1 4 1 2 2 4 3 3 2 2 4 1 1 1 1 1 2 2 4 1 1 2 2 1 2 1 1 1 2 2 1 1 1 2 4 4
##  [926] 4 3 1 4 2 2 4 3 3 2 2 4 1 1 1 2 4 4 4 3 1 4 1 2 2 1 4 3 3 2 2 4 1 1 1 2 4
##  [963] 4 4 3 1 3 1 2 2 4 3 3 2 2 4 1 1 1 1 2 4 4 4 3 1 4 2 2 4 3 3 2 2 4 1 1 1 2
## [1000] 4 4 4 3 1 4 2 2 1 4 3 3 2 2 4 1 1 1 2 4 4 4 3 1 4 2 2 4 3 3 2 2 4 1 1 1
## 
## Within cluster sum of squares by cluster:
## [1]  66.65946 119.08099  75.22244 201.02322
##  (between_SS / total_SS =  77.7 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"
fviz_cluster(mex_cluster1,data=mex_alt_norm)

Intepretación de los resultados

¿cuál es la tendencia del desempeño durante el período de análisis y los siguientes 3 períodos de tiempo?

LS0tCnRpdGxlOiAiU0VDQ0nDk04gMiIKYXV0aG9yOiAiQW5hIFBhdHJpY2lhIEFwb250ZSAtIEEwMTI4MzkyOCIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQoKIyA8c3BhbiBzdHlsZT0iY29sb3I6ICNGRjdGMjQiPiAqKkFuw6FsaXNpcyBFeHBsb3JhdG9yaW8gZGUgbGFzIEJhc2VzIGRlIERhdG9zKiogPC9zcGFuPgoKKipMaWJyZXJpYXMgVXRpbGl6YWRhcyoqCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkobmFuaWFyKQpsaWJyYXJ5KEhtaXNjKSAgICAgICAgIApsaWJyYXJ5KHBzeWNoKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHBvbGxzdGVyKQpsaWJyYXJ5KGVwaURpc3BsYXkpCmxpYnJhcnkoZGVzY3IpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkodGV4dGNsZWFuKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShmb3JlaWduKQpsaWJyYXJ5KGNvcnJwbG90KSAgICAKbGlicmFyeShqdG9vbHMpICAgICAgIApsaWJyYXJ5KGxtdGVzdCkgICAgICAgCmxpYnJhcnkoY2FyKSAgICAgICAgICAKbGlicmFyeShmYWN0b2V4dHJhKSAgCmxpYnJhcnkoZ2dmb3J0aWZ5KSAgICAKbGlicmFyeShnZ2FsbHV2aWFsKSAKYGBgCgoqKkltcG9ydGFyIEJhc2VzIGRlIERhdG9zKioKYGBge3J9Cm1lcm1hIDwtIHJlYWQuY3N2KCIvVXNlcnMvYW5pdGEzL0Rvd25sb2Fkcy9tZXJtYV9saW1waWEuY3N2IikKc2NyYXAgPC0gcmVhZC5jc3YoIi9Vc2Vycy9hbml0YTMvRG93bmxvYWRzL3NjcmFwX2xpbXBpYS5jc3YiKQpjYXJ0b24gPC0gcmVhZC5jc3YoIi9Vc2Vycy9hbml0YTMvRG93bmxvYWRzL2NhcnRvbl9saW1waWEuY3N2IikKcGVyZiA8LSByZWFkLmNzdigiL1VzZXJzL2FuaXRhMy9Eb3dubG9hZHMvZGVsX3BlcmZfbGltcGlhLmNzdiIpCnBsYW4gPC0gcmVhZC5jc3YoIi9Vc2Vycy9hbml0YTMvRG93bmxvYWRzL3BsYW5fbGltcGlhLmNzdiIpCmJhamFzIDwtIHJlYWQuY3N2KCIvVXNlcnMvYW5pdGEzL0Rvd25sb2Fkcy9iYWphc19saW1waWEuY3N2IikKY29sYWJvcmFkb3JlcyA8LSByZWFkLmNzdigiL1VzZXJzL2FuaXRhMy9Eb3dubG9hZHMvY29sYWJvcmFkb3Jlc19saW1waWEuY3N2IikKYGBgCgojIyBBbsOhbGlzaXMgRXhwbG9yYXRvcmlvIGRlIGxhcyBCYXNlcyBkZSBEYXRvcwoKIyMjIFRhYmxhIGRlIGxvcyBwcmluY2lwYWxlcyBlc3RhZMOtc3RpY29zIGRlc2NycHRpdm9zCgoqKk1lcm1hKioKRW4gbWVybWEgY29tbyBmZWNoYSB5IG1lcyBzb24gZGF0b3MgY3VhbGl0YXRpdm9zIG5vIGNvbnRpZW5lbiBpbmZvcm1hY2nDs24gZGVzY3JpcHRpdmEsIHNpbiBlbWJhcmdvIGxhIHZhcmlhYmxlIGRlIGtpbG9zIHNpLiBBIGNvbnRpbnVhY2nDs24gcG9kZW1vcyBpZGVudGlmaWNhciBxdWUgdGllbmUgc2tld25lc3MgbmVnYXRpdm8sIGNlcmNhbm8gYSAtMS4gCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmVkX21lcm1hIDwtIGRlc2NyaWJlKG1lcm1hKQplZF9tZXJtYQpoaXN0KG1lcm1hJGtpbG9zLCBtYWluPSAiTWVybWEgcG9yIGtpbG9zIiwgY29sID0gYygib3JhbmdlIikpCmBgYAoKKipTY3JhcCoqCkVuIFNjcmFwIHJlZmVyZW5jaWEsIGZlY2hhIHByb2R1Y3RvIHkgdWJpY2FjacOzbiBkZSBvcmlnZW4gc29uIG3DoXMgcXVlIG5hZGEgY3VhbGl0YXRpdmFzIHBvciBsbyBxdWUgbm8gdGVuZW1vcyBzdXMgZGF0b3MgZGVzY3JpcHRpdm9zLCBzaW4gZW1iYXJnbyBlbiBjYW50aWRhZCBzw60sIGEgY29udGludWFjacOzbiBwZG9lbW9zIGVuY29udHJhciBzdSBtZWRpYSwgbWVkaWFuYSwgZGVzdmlhY2nDs24sIGVzdGFuZGFyIHkgdGFtYmnDqW4gc3UgZGlzdHJpYnVjacOzbiwgcHVlcyB0aWVuZSBza2V3bmVzcyBwb3NpdGl2YSBhbHRhLCBpbmRpY2FuZG9ub3MgcXVlIGVuIGNhc28gZGUgZGF0b3MgZmFsdGFudGVzIHNlcmlhIG1lam9yIHJlbXBsYXphciBjb24gbGEgbWVkaWFuYSBxdWUgY29uIGxhIG1lZGlhLgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQplZF9zY3JhcCA8LSBkZXNjcmliZShzY3JhcCkKZWRfc2NyYXAKaGlzdChzY3JhcCRjYW50aWRhZCwgbWFpbj0gIkNhbnRpZGFkIGRlIHNjYXAiLCBjb2wgPSBjKCJvcmFuZ2UiKSkKYGBgCgoqKlByb2R1Y2Npw7NuIGRlIENhcnRvbioqCkVuIHByb2R1Y2Npw7NuIGRlIGNhcnRvbiB0ZW5lbW9zIGxvcyBkYXRvcyBkZXNjcmlwdGl2b3MgcHJpbmNpcGFsbWVudGUgZGUgcGl6YXMgcHJvZ3JhbWFzLCBsYW1pbmFzIHByb2Nlc2FkYXMsIHRpZW1wbyBkZSBjYWxpZGFkIHkgdG1vX21pbi4gRU4gdG9kYXMgZXN0YXMgYWRlbWFzIGRlIGVuY29udHJhciBzdSBtZWRpYSwgbWVkaWFuYSB5IGRlc3ZpYWNpw7NuIGVzdGFuZGFyIHBvZGVtb3MgaWRlbnRpZmljYXIgc3Ugc2tld25lc3MgcG9zaXRpdmEgZGUgbnVldm8gaW5kaWNhbmRvIHN1IGRpc3RyaWJ1Y2nDs24geSBjb21vIGVuIGNhc28gZGUgdmFsb3JlcyBmYWx0YW50ZXMgZXMgbWVqb3IgcmVtcGxhemFyIGNvbiBsYSBtZWRpYW5hLgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQplZF9jYXJ0b24gPC0gZGVzY3JpYmUoY2FydG9uKQplZF9jYXJ0b24KaGlzdChjYXJ0b24kcGllemFzX3Byb2csIG1haW49ICJQaWV6YXMgcHJvZ3JhbWFkYXMiLCBjb2wgPSBjKCJvcmFuZ2UiKSkKaGlzdChjYXJ0b24kbGFtX3Byb2Nlc2FkYXMsIG1haW49ICJMYW1pbmFzIHByb2Nlc2FkYXMiLCBjb2wgPSBjKCJvcmFuZ2UiKSkKaGlzdChjYXJ0b24kdGllbXBvX2NhbGlkYWQsIG1haW49ICJUaWVtcG8gZGUgY2FsaWRhZCIsIGNvbCA9IGMoIm9yYW5nZSIpKQpoaXN0KGNhcnRvbiR0bW9fbWluLCBtYWluPSAiVGllbXBvIChtaW51dG9zKSIsIGNvbCA9IGMoIm9yYW5nZSIpKQpgYGAKCioqRGVsaXZlcnkgUGVyZm9ybWFuY2UqKgpQYXJhIERlbGl2ZXJ5IHBlcmZvcm1hbmNlIHBvZGVtb3MgZW5jb250cmFyIGEgY29udGludWFjacOzbiBzdXMgZGF0b3MgZGVzY3JpcHRpdm9zLCBzaW4gZW1iYXJnbyBoYXkgYWxndW5vcyBxdWUgbm8gdG9tYW1vcyBtdWNobyBlbiBjb25zaWRlcmFjacOzbiBwb3IgZWplbXBsbywgbGEgZmVjaGEsIHZ1ZWx0YSBvIGNsaWVudGUsIHkgcG9yIG90cm8gbGFkbyB0ZW5lbW9zIHBsYW4gYXJyaXZhbCwgcmVhbCBhcnJpdmFsIHkgcmVhbCBkZXBhcnR1cmUgcXVlIHNvbiBob3JhcyBlbiB0ZW9yaWEgeSBkaWZmZXJlbmNlIHF1ZSBlcyBsYSBkaWZlcmVuY2lhIGVuIG1pbnV0b3MuCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmVkX3BlcmYgPC0gZGVzY3JpYmUocGVyZikKZWRfcGVyZgpgYGAKCioqRGVsaXZlcnkgUGxhbioqCkNvbiBkZWxpdmVyeSBwbGFuIG11Y2hhcyBkZSBsYXMgdmFyaWFibGVzIHNvbiBob3JhcyBvIGN1YWxpdGF0aXZhcywgc2luIGVtYmFyZ28gdGVuZW1vcyBsYSB2YXJpYWJsZSBkZSB1bmlkYWRlcywgbGEgY3VhbCwgYWwgaWd1YWwgcXVlIGVuIGJhc2VzIGFudGVyaW9yZXMgdGllbmUgdW5hIGRpc3RyaWJ1Y2nDs24gY29uIHNrZXcgcG9zaXRpdmEgeSBhbHRhLCBwb3IgbG8gcXVlIGVuIGNhc28gZGUgdmFsb3JlcyBmYWx0YW50ZXMgbm9zIGNvbnZlbmRyw61hIG1hcyByZW1wbGF6YXIgY29uIGxhIG1lZGlhbmEgcXVlIGNvbiBsYSBtZWRpYS4KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZWRfcGxhbiA8LSBkZXNjcmliZShwbGFuKQplZF9wbGFuCmhpc3QocGxhbiR1bmlkYWRlcywgbWFpbj0gIlVuaWRhZGVzIiwgY29sID0gYygib3JhbmdlIikpCmBgYAoKKipCYWphcyoqCkVuIGJhamFzIG11Y2hhcyBkZSBsYXMgdmFyaWFibGVzIHNvbiBjdWFsaXRhdGl2YXMgcG9yIGxvIHF1ZSBjYXJlY2VuIGRlIGVzdGFkaXN0aWNvcyBkZXNjcmlwdGl2b3MsIHNpbiBlbWJhcmdvLCB0ZW5lbW9zIG90cmEgY29tbyBlbCBzYWxhcmlvIGRpYXJpbywgZWwgY3VhbCB0aWVuZSB1bmEgZGlzdHJpYnVjacOzbiBjb24gc2tld25lc3MgcG9zaXRpdm8gdGFtYmnDqW4uCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmVkX2JhamFzIDwtIGRlc2NyaWJlKGJhamFzKQplZF9iYWphcwpoaXN0KGJhamFzJHNhbF9kaWFyaW9faW1zcywgbWFpbj0gIkJhamFzIHggc2FsYXJpbyBJTVNTIiwgY29sID0gYygib3JhbmdlIikpCmBgYAoKKipDb2xhYm9yYWRvcmVzKioKRWwgY2FzbyBkZSBsYSBiYXNlIGRlIGRhdG9zIGRlIGNvbGFib3JhZG9yZXMgZXMgbXV5IHNpbWlsYXIgYWwgZGUgYmFqYXMuCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmVkX2NvbGFib3JhZG9yZXMgPC0gZGVzY3JpYmUoY29sYWJvcmFkb3JlcykKZWRfY29sYWJvcmFkb3JlcwpoaXN0KGNvbGFib3JhZG9yZXMkc2FsX2RpYXJpb19pbXNzLCBtYWluPSAiU2xhcmlvIElNU1MgcG9yIGNvbGFib3JhZG9yZXMiLCBjb2wgPSBjKCJvcmFuZ2UiKSkKYGBgCgojIyMg4oCcQmFyIFBsb3Rz4oCdIGRlIERlc2VtcGXDsW8KCioqTWVybWEqKiAgClBhcmEgbWVybWEsIG5vcyBpbnRlcmVzYSBzYWJlciBlbCB0b3RhbCBkZSBraWxvcyBxdWUgc2UgcHJvZHVjZW4gcG9yIG1lcy4gClBhcmEgZ3LDoWZpY2FyIGVsIHRvdGFsIGRlIGtpbG9zIGRlIG1lcm1hIHBvciBtZXMgcHJpbWVybyBlcyBuZWNlc2FyaW8gb2J0ZW5lciBsYSBjYW50aWRhZCB0b3RhbCBkZSBraWxvcyBwb3IgbWVzLCBlc28gbG8gaGFjZW1vcyBkZSBsYSBzaWd1aWVudGUgbWFuZXJhLgpgYGB7cn0KbWVybWFfbWVzPC1hZ2dyZWdhdGUoa2lsb3MgfiBtZXMsIGRhdGEgPSBtZXJtYSwgc3VtKSAlPiUgYXJyYW5nZShkZXNjKGtpbG9zKSkKbWVybWFfbWVzCmBgYAoKVW5hIHZleiBxdWUgeWEgdGVuZW1vcyBlbCB0b3RhbCBwb3IgbWVzIHBvZGVtb3MgZ3JhZmljYXJsby4KYGBge3J9CmdncGxvdChtZXJtYV9tZXMsYWVzKHg9IHJlb3JkZXIobWVzLCAta2lsb3MpLHk9a2lsb3MsIGZpbGw9bWVzKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKStsYWJzKHg9Ik1lcyIsIHk9IktpbG9zIikrCiAgdGhlbWVfbWluaW1hbCgpKwogIGxhYnModGl0bGU9IktpbG9zIGRlIG1lcm1hIHBvciBtZXMiKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02NSwgaGp1c3Q9MSkpCmBgYAoKKipTY3JhcCoqICAKUGFyYSBTY3JhcCBoZW1vcyBvcHRhZG8gcG9yIHZpc3VhbGl6YXIgdW4gZ3LDoWZpY28gZGUgYmFycmFzIGRlIGxhIGNhbnRpZGFkIHkgbGEgdWJpY2FjacOzbiBkZSBvcmlnZW4uCmBgYHtyfQpnZ3Bsb3Qoc2NyYXAsYWVzKHg9IHJlb3JkZXIodWJpX29yaWdlbiwgLWNhbnRpZGFkKSx5PWNhbnRpZGFkLCBmaWxsPXViaV9vcmlnZW4pKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpK2xhYnMoeD0iVWJpY2FjacOzbiBkZSBvcmlnZW4iLCB5PSJDYW50aWRhZCIpKwogIHRoZW1lX21pbmltYWwoKSsKICBsYWJzKHRpdGxlPSJDYW50aWRhZCBwb3IgdWJpY2FjacOzbiBkZSBvcmlnZW4iKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02NSwgaGp1c3Q9MSkpCmBgYAoKKipQcm9kdWNjacOzbiBkZSBDYXJ0w7NuKiogIApMYSBiYXNlIGRlIGRhdG9zIGRlIHByb2R1Y2Npw7NuIGRlIGNhcnTDs24gc29sbyBhYmFyY2EgZGUgbG9zIG1lc2VzIGRlIGp1bGlvIGEgc2VwdGllbWJyZSBkZWwgMjAyMiwgbGEgYmFzZSBkZSBkYXRvcyBkZSBtZXJtYSBpbmNsdXllIG3DoXMgbWVzZXMgcGVybyBkZWwgbWlzbW8gYcOxby4gSGVtb3MgZ3JhZmljYWRvIGxhIGNhbnRpZGFkIGRlIHBpZXphcyBwcm9ncmFtYWRhcyBwb3IgbWVzIGVuIHByb2R1Y2Npw7NuIGRlIGNhcnTDs24gcGFyYSBjb25maXJtYXIgc2kgZWwgbWVzIGNvbiBtYXlvciBjYW50aWRhZCBkZSBwaWV6YXMgcHJvZ3JhbWFkYXMgdGFtYmnDqW4gZXMgZWwgbWVzIGNvbiBtYXlvciBjYW50aWRhZCBkZSBraWxvcyBkZSBtZXJtYS4KYGBge3J9CmNhcnRvbiRmZWNoYSA8LSBhcy5EYXRlKGNhcnRvbiRmZWNoYSwgZm9ybWF0ID0iJWQvJW0vJXkiKQpzdHIoY2FydG9uJGZlY2hhKQp1bmlxdWUoY2FydG9uJGZlY2hhKQoKY2FydG9uX21lcyA8LSBjYXJ0b24gJT4lIG11dGF0ZShtZXM9Zm9ybWF0KGZlY2hhLCAiJU0iKSkKCmNhcnRvbl9tZXMyPC1hZ2dyZWdhdGUocGllemFzX3Byb2cgfiBtZXMsIGRhdGEgPSBjYXJ0b25fbWVzLCBzdW0pICU+JSBhcnJhbmdlKGRlc2MocGllemFzX3Byb2cpKQoKZ2dwbG90KGNhcnRvbl9tZXMyLGFlcyh4PSByZW9yZGVyKG1lcywgLXBpZXphc19wcm9nKSx5PXBpZXphc19wcm9nLCBmaWxsPW1lcykpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrbGFicyh4PSJNZXMiLCB5PSJQaWV6YXMgcHJvZ3JhbWFkYXMiKSsKICB0aGVtZV9taW5pbWFsKCkrCiAgbGFicyh0aXRsZT0iUGllemFzIHByb2dyYW1hZGFzIHBvciBtZXMiKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02NSwgaGp1c3Q9MSkpCgpgYGAKCkFsIG9ic2VydmFyIGVsIGdyw6FmaWNvIGRlIGJhcnJhcyBwb2RlbW9zIGNvbmZpcm1hciBxdWUgZWZlY3RpdmFtZW50ZSBlbCBtZXMgZGUgYWdvc3RvLCBlbCBtZXMgZG9uZGUgbcOhcyBwaWV6YXMgcHJvZ3JhbWFkYXMgcGFyYSBwcm9kdWNjacOzbiBodWJvIHRhbWJpw6luIGZ1ZSBlbCBtZXMgY29uIG1heW9yIGNhbnRpZGFkIGRlIG1lcm1hLgoKKipEZWxpdmVyeSBQZXJmb3JtYW5jZSoqICAKUGFyYSBkZWxpdmVyeSBwZXJmb3JtYW5jZSBvcHRhbW9zIHBvciBncmFmaWNhciBlbCByZXRyYXNvIHF1ZSBodWJvIGVudHJlIGVsIHRpZW1wbyBwbGFuZWFkbyBkZSBsbGVnYWRhIGNvbiBlbCBjbGllbnRlIHkgZWwgdGllbXBvIHJlYWwuIE5vcyBkaW1vcyBjdWVudGEgcXVlIGVsIGZvcm1hdG8gZGUgaG9yYSB2YXJpYWJhIGRlIDI0IGhvcmFzIGEgMTIgaG9yYXMgcG9yIGxvIHF1ZSBoaWNpbW9zIGVsIGNhbWJpbyBwYXJhIHF1ZSBlc3RlIGNvcnJlY3RvLiBDb21vIHBvZGVtb3MgdmVyIE1BSExFIHRpZW5lIHVuIGRlbGF5IG1heW9yIGFsIGRlIFBSSU5URUwuCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KY2xhc3MocGVyZiRyZWFsX2Fycml2YWwpCnBlcmYyIDwtIHBlcmYKcGVyZjMgPC0gIHBlcmYyICU+JSBtdXRhdGUocGxhbl9hcnJpdmFsPWlmZWxzZShjbGllbnRlID09ICJNQUhMRSJ8IHBsYW5fYXJyaXZhbCA9PSAgMjAgfCByZWFsX2Fycml2YWwgPCAxNSwgOCwgcGxhbl9hcnJpdmFsKSkKCnBlcmYzIDwtIG11dGF0ZShwZXJmMywgZGVsYXk9cmVhbF9hcnJpdmFsLXBsYW5fYXJyaXZhbCkgCnBlcmYzIDwtIGFnZ3JlZ2F0ZShkZWxheX5jbGllbnRlLCBkYXRhPXBlcmYzLCBtZWFuKQpnZ3Bsb3QocGVyZjMsYWVzKHg9IGNsaWVudGUseT1kZWxheSwgZmlsbD1jbGllbnRlKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKStsYWJzKHg9IkNsaWVudGVzIiwgeT0iRGVsYXkgZW4gbWluIikrCiAgdGhlbWVfbWluaW1hbCgpKwogIGxhYnModGl0bGU9IkRlbGF5IHBvciBjbGllbnRlIikrdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NjUsIGhqdXN0PTEpKQpgYGAKCioqRGVsaXZlcnkgUGxhbioqICAgIApDb24gRGVsaXZlcnkgUGxhbiBxdWVyZW1vcyBldmFsdWFyIHNpIGVsIG1lcyBkb25kZSBtYXlvciBjYW50aWRhZCBkZSBwaWV6YXMgcHJvZ3JhbWFkYXMgaGFiw61hIHRhbWJpw6luIGVyYSBlbCBtZXMgZG9uZGUgbWF5b3IgcHJvZHVjY2nDs24gaHViby4KYGBge3J9CnBsYW5fbWVzPC1hZ2dyZWdhdGUodW5pZGFkZXMgfiBtZXMsIGRhdGEgPSBwbGFuLCBzdW0pICU+JSBhcnJhbmdlKGRlc2ModW5pZGFkZXMpKQoKZ2dwbG90KHBsYW5fbWVzLGFlcyh4PSByZW9yZGVyKG1lcywgLXVuaWRhZGVzKSx5PXVuaWRhZGVzLCBmaWxsPW1lcykpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrbGFicyh4PSJNZXMiLCB5PSJVbmlkYWRlcyBwcm9ncmFtYWRhcyIpKwogIHRoZW1lX21pbmltYWwoKSsKICBsYWJzKHRpdGxlPSJVbmlkYWRlcyBwcm9ncmFtYWRhcyBwb3IgbWVzIikrdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NjUsIGhqdXN0PTEpKQpgYGAKCkFsIG9ic2VydmFyIGVsIGdyw6FmaWNvIGRlIGJhcnJhcyBwb2RlbW9zIGlkZW50aWZpY2FyIHF1ZSBlbCBtZXMgZW4gZWwgcXVlIG3DoXMgcGllemFzIHByb2dyYW1hZGFzIGh1Ym8gbm8gZnVlIGVsIG1lcyBjb24gbWF5b3IgcHJvZHVjY2nDs24geSBtZXJtYS4KCioqQmFqYXMqKiAgCkVuIGVzdGEgZ3LDoWZpY2EgZGUgYmFycmFzIHNlIHB1ZGUgb2JzZXJ2YXIgcXVlIGVsIHByaW5jaXBhbCBtb3Rpdm8gZGUgbGFzIGJhamFzIHNvbiBsYXMgZmFsdGFzIHNlZ3VpZGFtZW50ZSBkZSByZW51bmNpYXMgdm9sdW50YXJpYXMuIEVzIGltcG9ydGFudGUgbWVuY2lvbmFyIHF1ZSBsYXMgcGVyc29uYXMgZnVlcm9uIGRhZGFzIGRlIGJhamFzIGEgcGVzYXIgZGUgdGVuZXIgc29sbyB1bmEgZmFsdGEsIHBvciBsbyBxdWUgbm8gc2UgcHVlZGUgcmVhbGl6YXIgdW4gYnVlbiBkaWFnbsOzc3RpY28gc29icmUgbGFzIGJhamFzIHBvciBmYWx0YXMuCmBgYHtyfQptb3RfYmFqYSA8LSBiYWphcyAlPiUgZ3JvdXBfYnkobW90X2JhamEsIGdlbmVybykgJT4lIHRhbGx5KCkKbW90X2JhamEKCmdncGxvdChkYXRhPW1vdF9iYWphLCBhZXMoeD1tb3RfYmFqYSwgeT1uLCBmaWxsPWdlbmVybykpICsKZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSgpKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02NSwgaGp1c3Q9MSkpCmBgYAoKKipDb2xhYm9yYWRvcmVzKiogICAgCkVuIGVzdGEgZ3LDoWZpY2EgZGUgYmFycmFzIHBvZGVtb3Mgb2JzZXJ2YXIgZWwgc3VlbGRvIHByb21lZGlvIHBvciBwdWVzdG8geSBnw6luZXJvLiBVbmEgb2JzZXJ2YWNpw7NuIGltcG9ydGFudGUgZXMgZW4gZWwgcHVlc3RvIGRlIHN1cGVydmlzb3Ivc3VwZXJ2aXNvcmEsIHlhIHF1ZSBsYXMgbXVqZXJlcyB0aWVuZW4gbWF5b3Igc2FsYXJpbyBxdWUgbG9zIGhvbWJyZXMgYSBwZXNhciBkZSByZWFsaXphciBlbCBtaXNtbyB0cmFiYWpvLiBPdHJvIHB1ZXN0byBlbiBkb25kZSBsYSBzaXR1YWNpw7NuIGVzIHNpbWlsYXIgcGVybyBlbCBzYWxhcmlvIG5vIGVzIGRlIG11Y2hhIGRpZmVyZW5jaWEgZXMgZW4gZWwgcHVlc3RvIGRlIGNvc3R1cmVyYS9jb3N0dXJlcm8uICAgCkFsIG9ic2VydmFyIGVzdGEgZ3LDoWZpY2EgcG9kZW1vcyBkZWNpciBxdWUgbGFzIG11amVyZXMgZ2FuYW4gbcOhcywgeWEgcXVlIGEgcGVzYXIgZGUgcXVlIHJlYWxpY2VuIGVsIG1pc21vIHRyYWJham8gbGFzIG11amVyZXMgcmVjaWJlbiB1biBtYXlvciBzdWVsZG8gcXVlIGxvcyBob21icmVzLgpgYGB7cn0Kc3VlbGRvX2dlbmVyb19wdWVzdG88LWFnZ3JlZ2F0ZShzYWxfZGlhcmlvX2ltc3MgfiBwdWVzdG8rZ2VuZXJvLCBkYXRhID0gY29sYWJvcmFkb3JlcywgbWVhbikgCgpnZ3Bsb3QoZGF0YT1zdWVsZG9fZ2VuZXJvX3B1ZXN0bywgYWVzKHg9cHVlc3RvLCB5PXNhbF9kaWFyaW9faW1zcywgZmlsbD1nZW5lcm8pKSArCmdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoKSkrdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NjUsIGhqdXN0PTEpKQpgYGAKCiMjIyDigJxEaXNwZXJzaW9uIFBsb3Rz4oCdCgoqKk1lcm1hKiogICAKRW4gZXN0YSBncsOhZmljYSBkZSBib3hwbG90IHBvZGVtb3Mgb2JzZXJ2YXIgbGEgZGlzcGVyc2nDs24gZGUga2lsb3MgZGUgbWVybWEgcG9yIG1lcy4gQWdvc3RvIGVzIGVsIG1lcyBjb24gbWF5b3IgZGlzcGVyc2nDs24scG9yIGxvIHF1ZSBwb2RlbW9zIGluZmVyaXIgcXVlIGVuIGVzdGUgbWVzIGVzIGRvbmRlIGhheSBtYXlvciBwcm9kdWNjacOzbi4KYGBge3J9CmdncGxvdChtZXJtYSwgYWVzKHg9bWVzLCB5PWtpbG9zKSkgKyAKICBnZW9tX2JveHBsb3QoY29sb3I9InJlZCIsIGZpbGw9Im9yYW5nZSIsIGFscGhhPTAuMikKYGBgCgoqKlNjcmFwKiogIApFbiBlc3RhIGdyw6FmaWNhIGRlIGJveHBsb3QgcG9kZW1vcyBvYnNlcnZhciBsYSBkZXNwZXJhdGlvbiBkZSBjYW50aWRhZCBkZSBzY3JhcCBwb3IgdWJpY2FjacOzbiBkZSBvcmlnZW4uIENvbW8gc2UgcHVlZGUgb2JzZXJ2YXIgZMOzbmRlIGhheSBtYXlvciBkaXNwZXJzacOzbiBkZSBzY3JhcCBlcyBlbiBwcmUtcHJvZHVjY2nDs24geSBlc3RvIHNlIHB1ZWRlIGRlYmVyIGEgcXVlIGxhIGVtcHJlc2EgdXRpbGl6YSBtw6FzIG1hdGVyaWFsZXMgZW4gZXN0YSDDoXJlYSBkZSB0cmFiYWpvLgpgYGB7cn0KZ2dwbG90KHNjcmFwLCBhZXMoeD11Ymlfb3JpZ2VuLCB5PWNhbnRpZGFkKSkgKyAKICBnZW9tX2JveHBsb3QoY29sb3I9InJlZCIsIGZpbGw9Im9yYW5nZSIsIGFscGhhPTAuMikKYGBgCgoqKlByb2R1Y2Npw7NuIGRlIENhcnTDs24qKiAgCkVuIGVzdGEgZ3LDoWZpY2EgcG9kZW1vcyBvYnNlcnZhciBsYSBkaXNwZXJzacOzbiBkZSB0aWVtcG8gZGUgY2FsaWRhZCBwb3IgY2xpZW50ZSBkZSBwcm9kdWNjacOzbiBkZSBjYXJ0w7NuLiBFeGlzdGVuIGRpZmVyZW50ZXMgbW90aXZvcyBwb3IgbG8gY3VhbCBzZSB0b21lIG1heW9yIHRpZW1wbyBkZSBjYWxpZGFkIGEgY2llcnRvcyBjbGllbnRlcyBlc3RvIHB1ZWRlIHNlciBwb3I6ICAgCi0gY2FudGlkYWQgZGUgcGllemFzICAgCi0gY2xpZW50ZSBmcmVjdWVudGUgICAKLSBlbXBhcXVlIGNvbXBsaWNhZG8gIApgYGB7cn0KZ2dwbG90KGNhcnRvbiwgYWVzKHg9Y2xpZW50ZSwgeT10aWVtcG9fY2FsaWRhZCkpICsgCiAgZ2VvbV9ib3hwbG90KGNvbG9yPSJyZWQiLCBmaWxsPSJvcmFuZ2UiLCBhbHBoYT0wLjIpK3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTY1LCBoanVzdD0xKSkKYGBgCgoqKkRlbGl2ZXJ5IFBlcmZvcm1hbmNlKiogIApBbCBncmFmaWNhciBsYSBkaXNwZXJzacOzbiBkZSBsYSBkaWZlcmVuY2lhIGVudHJlIHJlYWwgYXJyaXZhbCB5IGRlcGFydHVyZSBhcnJpdmFsIHZlbW9zIHF1ZSBoYXkgbWF5b3IgdmFyaWFjaW9uIGVuIGVsIGNsaWVudGUgTUFITEUgcXVlIGVuIFBSSU5URUwuCmBgYHtyfQpnZ3Bsb3QocGVyZiwgYWVzKHg9Y2xpZW50ZSwgeT1kaWZlcmVuY2UpKSArIAogIGdlb21fYm94cGxvdChjb2xvcj0icmVkIiwgZmlsbD0ib3JhbmdlIiwgYWxwaGE9MC4yKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02NSwgaGp1c3Q9MSkpCmBgYAoKKipEZWxpdmVyeSBQbGFuKiogIApFbCBib3hwbG90IGEgY29udGludWFjacOzbiBtdWVzdHJhIGxhIGRpc3BlcnNpw7NuIGRlIGxhcyB1bmlkYWRlcyBwcm9ncmFtYWRhcyBwb3IgY2xpZW50ZSwgY29tbyBwb2RlbW9zIHZlciBIZWxsYSB5IFRSTVggdGllbmVuIG1heW9yIGNhbnRpZGFkIGRlIHVuaWRhZGVzIHByb2dyYW1hZGFzIHkgZXMgbcOhcyBkaXNwZXJzYSBzdSBkaXN0cmlidWNpw7NuLgpgYGB7cn0KZ2dwbG90KHBsYW4sIGFlcyh4PWNsaWVudGUsIHk9dW5pZGFkZXMpKSArIAogIGdlb21fYm94cGxvdChjb2xvcj0icmVkIiwgZmlsbD0ib3JhbmdlIiwgYWxwaGE9MC4yKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02NSwgaGp1c3Q9MSkpCmBgYAoKKipCYWphcyoqICAgIApFbCBzaWd1aWVudGUgZXMgdW4gYm94cGxvdCBkZSBsYSBwZXJtYW5lbmNpYSBlbiBsYSBlbXByZXNhIGVuIGxhcyBiYWphcyBwb3IgZ2VuZXJvLCBwb3IgbG8gZ2VuZXJhbCBsYXMgbXVqZXJlcyBkdXJhbiBtw6FzIGVuIGxhIGVtcHJlc2EuCmBgYHtyfQpnZ3Bsb3QoYmFqYXMsIGFlcyh4PWdlbmVybywgeT1wZXJtYW5lbmNpYSkpICsgCiAgZ2VvbV9ib3hwbG90KGNvbG9yPSJyZWQiLCBmaWxsPSJvcmFuZ2UiLCBhbHBoYT0wLjIpK3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTY1LCBoanVzdD0xKSkKYGBgCgoqKkNvbGFib3JhZG9yZXMqKiAgCkVzdGUgYm94cGxvdCBtdWVzdHJhIGxhIGRpc3BlcnNpw7NuIHF1ZSBoYXkgZW4gZWwgc2FsYXJpbyBkaWFyaW8gcXVlIHJlY2liZW4gbG9zIGNvbGFib3JhZG9yZXMgcG9yIGfDqW5lcm8sIGxhIGRpc3BlcnNpw7NuIGVuIG1heW9yIGVuIGVsIGfDqW5lcm8gZmVtZW5pbm8sIGhheSBtdWplcmVzIHF1ZSBnYW5hbiBjb25zaWRlcmFibGVtZW50ZSBtw6FzIHF1ZSBsb3MgaG9tYnJlcy4KYGBge3J9CmdncGxvdChjb2xhYm9yYWRvcmVzLCBhZXMoeD1nZW5lcm8sIHk9c2FsX2RpYXJpb19pbXNzKSkgKyAKICBnZW9tX2JveHBsb3QoY29sb3I9InJlZCIsIGZpbGw9Im9yYW5nZSIsIGFscGhhPTAuMikrdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NjUsIGhqdXN0PTEpKQpgYGAKCgojIyMg4oCcVGltZSBTZXJpZXMgUGxvdHPigJ0KCioqTWVybWEqKiAgCkVuIGVsIHNpZ3VpZW50ZSBwbG90IHBvZGVtb3MgaWRlbnRpZmljYXIgbGEgZmVjaGEgZW4gbGEgcXVlIGh1Ym8gbWF5b3Iga2lsb3MgZGUgbWVybWEuIEEgbWVkaWFkb3MgZGUgZmVicmVybyBodWJvIHVuYSBncmFuIGNhbnRpZGFkIGRlIG1lcm1hLCBlc3BlY8OtZmljYW1lbnRlIGVsIDE4IGRlIGZlYnJlcm8uIFBvZGVtb3Mgb2JzZXJ2YXIgdGFtYmnDqW4gcXVlIGRlc3B1w6lzIGRlIGNhZGEgcGljbyBkZSBtZXJtYSwgaGF5IHVuYSBjb3JyZWNjacOzbiB5IGxhIG1lcm1hIGRpc21pbnV5ZS4gRXN0byBwb2Ryw61hIHNlciBwb3IgZGl2ZXJzb3MgZmFjdG9yZXMgY29tbyBhanVzdGVzIGVuIGxhIHByb2R1Y2Npw7NuLCBlbiBsb3MgY29ydGVzLCBlbnRyZSBvdHJvcy4KYGBge3J9Cm1lcm1hX2ZlY2hhPC1hZ2dyZWdhdGUoa2lsb3MgfiBmZWNoYSwgZGF0YSA9IG1lcm1hLCBzdW0pIApjbGFzcyhtZXJtYV9mZWNoYSRraWxvcykKZ2dwbG90KG1lcm1hX2ZlY2hhLGFlcyh4PWZlY2hhLHk9a2lsb3MpKSsKICBnZW9tX3BvaW50KCkrCiAgbGFicyh0aXRsZT0iS2lsb3MgcG9yIGZlY2hhIikrIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTY1LCBoanVzdD0xKSkKYGBgCgoqKlByb2R1Y2Npw7NuIGRlIENhcnTDs24qKiAgClBhcmEgbGEgcHJvZHVjY2nDs24gZGUgY2FydMOzbiB2YW1vcyBhIGdyYWZpY2FyIGVsIHRpZW1wbyBlbiBtaW51dG9zIHF1ZSB0b23DsyBlbCBwcm9jZXNvLiBQYXJhIGVzdG8gbmVjZXNpdGFtb3MgcmVzdGFyIGVsIHRpZW1wbyBkZSBpbmljaW8gZGUgcHJvY2VzbyBhbCBkZSBmaW4gZGUgcHJvY2Vzby4KYGBge3J9CmNhcnRvbiRpbmljaW9fcHJvY2VzbzwtYXMuUE9TSVhjdChjYXJ0b24kaW5pY2lvX3Byb2Nlc28sZm9ybWF0PSIlSDolTSIpCmNhcnRvbiRpbmljaW9fcHJvY2VzbyA8LSBhcy5JVGltZShjYXJ0b24kaW5pY2lvX3Byb2Nlc28pCgpjYXJ0b24kZmluX3Byb2Nlc288LWFzLlBPU0lYY3QoY2FydG9uJGZpbl9wcm9jZXNvLGZvcm1hdD0iJUg6JU0iKQpjYXJ0b24kZmluX3Byb2Nlc28gPC0gYXMuSVRpbWUoY2FydG9uJGZpbl9wcm9jZXNvKQoKY2FydG9uMjwtbXV0YXRlKGNhcnRvbiwgdGllbXBvX3Byb2Nlc28gPSBmaW5fcHJvY2VzbyAtIGluaWNpb19wcm9jZXNvKQpjYXJ0b24yIDwtIGZpbHRlcihjYXJ0b24yLCAhdGllbXBvX3Byb2Nlc28gPCAwKQpgYGAKCkFzaSBtaXNtbywgdmFtb3MgYSBzYWNhciBlbCBwcm9tZWRpbyBkZSB0aWVtcG8gcXVlIHRvbWEgZWwgcHJvY2VzbyBwb3IgY2xpZW50ZS4gRGUgZXN0YSBmb3JtYSBwb2RyZW1vcyBzYWJlciBjdWFsIGNsaWVudGUgY29uc3VtZSBtYXMgdGllbXBvIGRlIHByb2R1Y2Npb24gZGUgRm9ybSBlbiBlbCBtZXMgZGUgYWdvc3RvLgpgYGB7cn0KcHJvZF9jbGllbnRlPC1hZ2dyZWdhdGUodGllbXBvX3Byb2Nlc28gfiBjbGllbnRlLCBkYXRhPWNhcnRvbjIsIG1lYW4pCnByb2RfY2xpZW50ZQpgYGAKCmBgYHtyfQpnZ3Bsb3QocHJvZF9jbGllbnRlLGFlcyh4PWNsaWVudGUseT10aWVtcG9fcHJvY2VzbykpKwogIGdlb21fcG9pbnQoKSsKICBsYWJzKHRpdGxlPSJUaWVtcG8gcHJvbWVkaW8gcG9yIGNsaWVudGUiKSsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0PTEpKQpgYGAKQ29tbyBwb2RlbW9zIHZlciBIYW5vbiBTeXN0ZW1zLCBZZW4gRmFuZyB5IFZhcnJvYyBzb24gbG9zIGNsaWVudGVzIHF1ZSBtYXlvciB0aWVtcG8gdG9tYSBzdSBwcm9jZXNvIGRlIHByb2R1Y2Npw7NuLiBFc3RvIHB1ZWRlIHNlciBkZWJpZG8gYSBsYSBjb21wbGVqaWRhZCBkZSBzdXMgcHJvZHVjdG9zIG8gbWF0ZXJpYWwsIHNpbiBlbWJhcmdvLCBoYXkgcXVlIHByZXN0YXIgZXNwZWNpYWwgYXRlbmNpw7NuIGEgbGEgZ3JhbiBkaWZlcmVuY2lhIHF1ZSBoYXkgZW50cmUgSGFub24gU3lzdGVtcyB5IGVsIHJlc3RvIGRlIGNsaWVudGVzLgoKKipEZWxpdmVyeSBQbGFuKiogIApFbiBEZWxpdmVyeSBQbGFuIHBvZGVtb3Mgb2JzZXJ2YXIgbGEgY2FudGlkYWQgZGUgdW5pZGFkZXMgcG9yIG1lcyBwb3IgY2xpZW50ZS4gUG9kZW1vcyBpZGVudGlmaWNhciBxdWUgSEVMTEEgZW4gbGEgZ3JhbiBtYXlvcsOtYSBkZSBsYXMgZmVjaGFzIGVzIGVsIGNsaWVudGUgY29uIG1heW9yIGNhbnRpZGFkIGRlIHVuaWRhZGVzIHBsYW5lYWRhcywgcmFyYSB2ZXogZXMgc3VwZXJhZG8gcG9yIFRSTVguCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsYW5fbWVzeWNsaWVudGUgPC0gYWdncmVnYXRlKHVuaWRhZGVzIH4gY2xpZW50ZSttZXMsIGRhdGE9cGxhbiwgc3VtKQoKcGxhbl9tZXN5Y2xpZW50ZSA8LSBwbGFuX21lc3ljbGllbnRlICU+JSAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGNsaWVudGUsIHZhbHVlc19mcm9tID0gdW5pZGFkZXMpCgpwbGFuX21lc3ljbGllbnRlIDwtIGRwbHlyOjpzZWxlY3QocGxhbl9tZXN5Y2xpZW50ZSwgYyhtZXMsIkhFTExBIiwgIlRSTVgiLCAiVkFSUk9DIiwgIkRFTlNPIikpCgoKZ2dwbG90KHBsYW5fbWVzeWNsaWVudGUsIGFlcyh4PW1lcykpICsgCiAgZ2VvbV9wb2ludChhZXMoeSA9IEhFTExBKSwgY29sb3IgPSAiZGFya3JlZCIpICsgCiAgZ2VvbV9wb2ludChhZXMoeSA9IFRSTVgpLCBjb2xvcj0ic3RlZWxibHVlIiwgbGluZXR5cGU9InR3b2Rhc2giKSsKICBnZW9tX3BvaW50KGFlcyh5ID0gVkFSUk9DKSwgY29sb3IgPSAiZGFya2dyZWVuIikgKyAKICBnZW9tX3BvaW50KGFlcyh5ID0gREVOU08pLCBjb2xvcj0iZGFya29yYW5nZSIsIGxpbmV0eXBlPSJ0d29kYXNoIikrIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLCBoanVzdD0xKSkKCmBgYAoKKipCYWphcyoqICAKRW4gZXN0b3MgZ3LDoWZpY29zIGRlIGJhcnJhcyBwb2RlbW9zIGlkZW50aWZpY2FyIGxvcyBtZXNlcyBkb25kZSBtw6FzIGJhamFzIGhheSB5IGRvbmRlIG3DoXMgaW5ncmVzb3MgaGF5LCBpZGVudGlmaWNhbmRvIHBhdHJvbmVzLiBFbiBsYXMgYmFqYXMsIGxhIG1heW9yIGNhbnRpZGFkIG9jdXJyZW4gYWwgaW5pY2lvIGRlbCBhw7FvIHkgcG9zdGVyaW9ybWVudGUgYSBtZWRpYWRvcyBwZXJvIGNhc2kgbnVuY2EgYSBmaW5hbGVzIGRlIGHDsW8uIEVzdG8gcG9kcsOtYSBkZWJlcnNlIGEgcXVlIGxvcyBjb2xhYm9yYWRvcmVzIG5vIHF1aWVyZW4gZXN0YXIgc2luIHRyYWJham8gZW4gZmVjaGFzIGRvbmRlIHN1cyBnYXN0b3MgcHVlZGVuIHNlciBtYXlvcmVzIGNvbW8gbmF2aWRhZCwgYcOxbyBudWV2bywgY2llcnJlIGUgaW5pY2lvIGRlIGNpY2xvcyBlc2NvbGFyZXMsIGVudHJlIG90cm9zLiAgCgpFbiBlbCBjYXNvIGRlIGxvcyBpbmdyZXNvcyBvIGFsdGFzLCBlc3RhcyBzZSBkYW4gbcOhcyBhIG1lZGlhZG9zIGRlIGHDsW8sIG11eSBwcm9iYWJsZW1lbnRlIEZPUk0gaGFnYSBlc3RvIHBhcmEgY3VicmlyIGxhcyBiYWphcyBxdWUgb2N1cnJpZXJvbiBhIGluaWNpb3MgeSBtZWRpYWRvcyBkZSBhw7FvLiBEZSBpZ3VhbCBmb3JtYSwgbGFzIGFsdGFzIHNvbiBtdXkgYmFqYXMgYSBmaW5hbGVzIGRlIGHDsW8sIHF1aXrDoXMgcG9kcsOtYSBkZWJlcnNlIGEgcXVlIGVuIGVzdGFzIGZlY2hhcyBGT1JNIGVzdMOhIGNlcnJhbmRvIGVsIGHDsW8sIHByZXBhcmFuZG8gYWd1aW5hbGRvcywgZW50cmUgb3Ryb3MgY29zdG9zIHF1ZSB0aWVuZSBwb3IgbG8gcXVlIHByZWZpZXJlIG5vIGNvbnRyYXRhciBudWV2b3MgZW1wbGVhZG9zLgpgYGB7cn0KYmFqYXMkYmFqYSA8LSBhcy5EYXRlKGJhamFzJGJhamEsIGZvcm1hdCA9IiVkLyVtLyVZIikKYmFqYXMkZmVjaGFfYWx0YSA8LSBhcy5EYXRlKGJhamFzJGZlY2hhX2FsdGEsIGZvcm1hdCA9IiVkLyVtLyVZIikKCmJhamFzX21lcyA8LSBiYWphcyAlPiUgbXV0YXRlKG1lc19iYWphPWZvcm1hdChiYWphLCAiJW0iKSkKYmFqYXNfbWVzIDwtIGJhamFzX21lcyAlPiUgbXV0YXRlKG1lc19hbHRhPWZvcm1hdChmZWNoYV9hbHRhLCIlbSIpKQoKYmFqYXNfcG9yX21lcyA8LSBiYWphc19tZXMgJT4lIGdyb3VwX2J5KG1lc19iYWphKSAlPiUgdGFsbHkoKQphbHRhc19wb3JfbWVzIDwtIGJhamFzX21lcyAlPiUgZ3JvdXBfYnkobWVzX2FsdGEpICU+JSB0YWxseSgpCgpnZ3Bsb3QoYmFqYXNfcG9yX21lcyxhZXMoeD0gcmVvcmRlcihtZXNfYmFqYSwtbikseT1uLCBmaWxsPW1lc19iYWphKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKStsYWJzKHg9Ik1lcyIsIHk9IkJhamFzIikrCiAgdGhlbWVfbWluaW1hbCgpKwogIGxhYnModGl0bGU9IkJhamFzIHBvciBtZXMiKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02NSwgaGp1c3Q9MSkpCgpnZ3Bsb3QoYWx0YXNfcG9yX21lcyxhZXMoeD0gcmVvcmRlcihtZXNfYWx0YSwtbikseT1uLCBmaWxsPW1lc19hbHRhKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKStsYWJzKHg9Ik1lcyIsIHk9IkFsdGFzIikrCiAgdGhlbWVfbWluaW1hbCgpKwogIGxhYnModGl0bGU9IkFsdGFzIHBvciBtZXMiKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02NSwgaGp1c3Q9MSkpCmBgYAoKCioqQ29sYWJvcmFkb3JlcyoqICAKR3JhZmljYW1vcyBhbnRpZ3VlZGFkIHBvciBwdWVzdG8geSBwb2RlbW9zIGlkZW50aWZpY2FyIHF1ZSBsb3MgaG9tYnJlcyB0aWVuZW4gbWF5b3IgYW50aWd1ZWRhZCBlbiBmb3JtIHF1ZSBsYXMgbXVqZXJlcywgYWRlbcOhcyBxdWUgbG9zIHVuaWNvcyBwdWVzdG9zIGRvbmRlIGhheSBob21icmVzIHkgbXVqZXJlcyBzb24gZW4gc3VwZXJ2aXNvcihhKSB5IGNvc3R1cmVyYShvKS4gQXPDrSBtaXNtbyBxdWUgbG9zIHB1ZXN0b3MgaGF5IG3DoXMgcGFyYSBob21icmVzIHF1ZSBwYXJhIG11ZWplcmVzLgpgYGB7cn0KY29sYWJvcmFkb3JlcyRmZWNoYV9hbHRhIDwtIGFzLkRhdGUoY29sYWJvcmFkb3JlcyRmZWNoYV9hbHRhLCBmb3JtYXQgPSIlZC8lbS8lWSIpCmNvbGFib3JhZG9yZXMgPC0gbXV0YXRlKGNvbGFib3JhZG9yZXMsIGFudGlndWVkYWQ9dG9kYXkoKS1mZWNoYV9hbHRhKQoKYW50aWd1ZWRhZF9wdWVzdG8gPC0gYWdncmVnYXRlKGFudGlndWVkYWQgfiBwdWVzdG8rZ2VuZXJvLCBkYXRhPWNvbGFib3JhZG9yZXMsIG1lYW4pCgpnZ3Bsb3QoZGF0YT1hbnRpZ3VlZGFkX3B1ZXN0bywgYWVzKHg9cHVlc3RvLCB5PWFudGlndWVkYWQsIGZpbGw9Z2VuZXJvKSkgKwpnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKCkpK3RoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTY1LCBoanVzdD0xKSkKYGBgCgojIyMgUHJpbmNpcGFsZXMgaGFsbGF6Z29zCgoqKk1lcm1hKioKUmVhbGl6YW5kbyB1biBhbsOhbGlzaXMgZGUgbGEgYmFzZSBkZSBkYXRvcyBtZXJtYSBub3MgZGltb3MgY3VlbnRhIHF1ZSBsb3MgbWVzZXMgY29uIG1heW9yIHByb2R1Y2Npw7NuIGRlIG1lcm1hIHNvbiBsb3MgbWVzZXMgZGUgYWdvc3RvIGNvbiAzMiw1MDAga2lsb3MgZGUgbWVybWEgeSBtYXlvIGNvbiAyMiw3MDAga2lsb3MgZGUgbWVybWEsIGVuIGJhc2UgYSBlc3RvIHBvZGVtb3MgaW5mZXJpciBxdWUgZW4gZXN0b3MgbWVzZXMgZXMgZG9uZGUgbGEgZW1wcmVzYSBGT1JNIHRpZW5lIG1heW9yIHByb2R1Y2Npw7NuLiBEZSBpZ3VhbCBtYW5lcmEgc2UgaWRlbnRpZmljYXJvbiBsb3MgbWVzZXMgZG9uZGUgbGEgZW1wcmVzYSBwcm9kdWPDrWEgbWVub3MgbWVybWEsIGxvcyBjdWFsZXMgZnVlcm9uIGxvcyBtZXNlcyBkZSBlbmVybyBjb24gMTQsODAwIGtpbG9zIGRlIG1lcm1hIHkgc2VwdGllbWJyZSBjb24gMTIsNDAwIGtpbG9zIGRlIG1lcm1hLCBwb3IgbG8gcXVlIHRhbWJpw6luIHBvZGVtb3MgaW5mZXJpciBxdWUgZW4gZXN0b3MgbWVzZXMgRk9STSBubyB0aWVuZSBtdWNoYSBwcm9kdWNjacOzbi4KCioqU2NyYXAqKgpBbmFsaXphbmRvIGxvcyByZXN1bHRhZG9zIGRlIGxhIGJhc2UgZGUgZGF0b3MgU2NyYXAsIGVsIGN1YWwgc2UgcmVmaWVyZSBhIHRvZG9zIGxvcyBkZXNlY2hvcyB5L28gcmVzaWR1b3MgZGVyaXZhZG9zIGRlbCBwcm9jZXNvIGluZHVzdHJpYWwsIHNlIG9ic2VydmEgcXVlIFNBQi9QcmUtUHJvZHVjdGlvbiBlcyBlbCBsdWdhciBkb25kZSBtw6FzIGNhbnRpZGFkIGV4aXN0ZSBjb24gdW4gdmFsb3IgdG90YWwgZGUgMTUwMCB0b25lbGFkYXMuIAoKKipQcm9kdWNjacOzbiBkZSBjYXJ0w7NuKioKTGFzIGdyw6FmaWNhcyBkZSBkaXNwZXJzacOzbiBub3MgaW5kaWNhbiBxdWUgY29uIGVsIGNsaWVudGUgWUFORkVORyBlcyBsYSB2ZXogcXVlIG3DoXMgc2UgaGEgbGxldmFkbyBtw6FzIHRpZW1wbyBkZSBjYWxpZGFkLCBwb2RlbW9zIGFuYWxpemFyIGVsIHRpZW1wbyBxdWUgc2UgbGxldsOzIGEgY2FibyBjb24gdW4gZW1wYXF1ZSB5IHNpIGxhIHByb2R1Y2Npw7NuIGRlbCBtaXNtbyDCv2VzIHJlbnRhYmxlIHBhcmEgbGEgZW1wcmVzYT8gbyBzaSBsbyBtZWpvciBlcyBubyBhY2VwdGFyIHByb2R1Y2lyIGVzdGUgdGlwbyBkZSBwcm9kdWN0by4gCgpQb3Igb3RybyBsYWRvIGNvbiBsYXMgc2VyaWVzIGRlIHRpZW1wbywgb2JzZXJ2YW1vcyBxdWUgY29uIEhhbm9uIFN5c3RlbXMgZXMgY29uIHF1aWVuIG3DoXMgc2UgaGEgdG9tYWRvIHRpZW1wbyBlbiBlbCBwcm9jZXNvLiBQb2RlbW9zIHByZWd1bnRhcm5vcyBzaSBlcyBjb252ZW5pZW50ZSBsbGV2YXIgcHJvY2Vzb3MgZGUgcHJvZHVjY2nDs24gdGFuIGxhcmdvcyBjb24gdW4gY2xpZW50ZSB5IGV2YWx1YXIgc3UgcmVudGFiaWxpZGFkLiAKCioqRGVsaXZlcnkgUGVyZm9ybWFuY2UqKgpFbiBEZWxpdmVyeSBQZXJmb3JtYW5jZSBoZW1vcyBwb2RpZG8gaWRlbnRpZmljYXIgcXVlIE1BSExFIHRpZW5lIG1heW9yIGRlbGF5IHF1ZSBQUklOVEVMLCBwb3IgbG8gcXVlIHBvZHLDrWEgZGVjaXJub3MgcXVlIGFsZ28gc3VjZWRlIGNvbiBNQUhMRSBxdWUgb2Nhc2lvbmEgcXVlIHNlIHJldHJhc2UgbcOhcyBxdWUgb3Ryb3MgY2xpZW50ZXMuIEhhYnLDrWEgcXVlIHRvbWFyIG1lZGlkYXMgY29ycmVjdGl2YXMuCgoqKkRlbGl2ZXJ5IFBsYW4qKgpBbCBhbmFsaXphciBsb3MgcmVzdWx0YWRvcywgc2Ugb2J0dXZvIHF1ZSBlbCBtZXMgY29uIG3DoXMgcGllemFzIHByb2dyYW1hZGFzIGZ1ZSBKdWxpbyBkZSAyMDIyLCBzZWd1aWRvIGRlIFNlcHRpZW1icmUgeSBNYXlvLiBBZGVtw6FzIHNlIHB1ZWRlIG9ic2VydmFyIHVuYSBjYcOtZGEgc2lnbmlmaWNhdGl2YSBkZSBwaWV6YXMgcHJvZ3JhbWFkYXMgZW50cmUgZWwgbWVzIGRlIGp1bGlvIGEgc2VwdGllbWJyZSwgeWEgcXVlIGVuIGp1bGlvIGhheSBtw6FzIGRlIDcyLDAwMCBwaWV6YXMgcHJvZ3JhbWFkYXMgeSBwYXJhIHNlcHRpZW1icmUgZXNlIHZhbG9yIGRlY3JlY2nDsyBjb24gMTAgbWlsIHVuaWRhZGVzIG1lbm9zLiAKCioqQmFqYXMqKgpFbCBwcmluY2lwYWwgbW90aXZvIGRlIGxhcyBiYWphcyBmdWUgcG9yIHJlbnVuY2lhcywgZXN0ZSBlcyB1biBkYXRvIG11eSBpbnRlcmVzYW50ZSBzaW4gZW1iYXJnbyBubyBzZSBwdWVkZSBsbGVnYXIgYSBoYWNlciB1bmEgYnVlbmEgaW50ZXJwcmV0YWNpw7NuIHlhIHF1ZSBtdWNob3MgZGUgbG9zIGV4IGVtcGxlYWRvcyBmdWVyb24gZGFkb3MgZGUgYmFqYSBzb2xvIHBvciBmYWx0YXIgdW4gZMOtYS4gIEVsIHNlZ3VuZG8gbW90aXZvIGRlIGxhcyBiYWphcyBmdWUgcG9yIHJlbnVuY2lhIHZvbHVudGFyaWEgeSBtdWNoYXMgZGUgZXN0YXMgcGVyc29uYXMgbm8gcmVudW5jaWFyb24gc2luIGNvbXBsaXIgZWwgYcOxbyBlbiBsYSBlbXByZXNhLgpFcyBpbXBvcnRhbnRlIHF1ZSBsYSBlbXByZXNhIHJlY3VlcmRlIGJpZW4gbGEgaW5mb3JtYWNpw7NuIHNvYnJlIGxhcyBiYWphcyB5IHN1cyBtb3Rpdm9zIHBhcmEgZGUgZXN0YSBtYW5lcmEgZ2VuZXJhciB1bmEgYnVlbmEgZXN0cmF0ZWdpYSBlbiBkaXNtaW51aXIgbGEgcm90YWNpw7NuIGRlIGVtcGxlYWRvcywgeWEgcXVlLCBsYSBtYXlvcsOtYSBkZSBsb3MgZW1wbGVhZG9zIHNvbG8gZHVyYSB1biBhw7FvIG8gbWVub3MgZW4gbGEgZW1wcmVzYS4KCioqQ29sYWJvcmFkb3JlcyoqCkxhIHBlcnNvbmEgcXVlIG3DoXMgc2FsYXJpbyB0aWVuZW4gc29uIGxhIHN1cGVydmlzb3JhIG11amVyZXMgeSBsb3MgZGUgbWFudGVuaW1pZW50bywgc2kgRk9STSBuZWNlc2l0YSB1biByZWNvcnRlIGVuIGdhc3RvcyBzZSBmaWphcsOtYSBwcmltZXJhbWVudGUgZW4gZXN0YXMgcGVyc29uYXMuIAoKIyMgUHJlZGljY2nDs24gZGVsIERlc2VtcGXDsW8gZGUgbGEgSW5kdXN0cmlhIEF1dG9tb3RyaXoKCioqSW1wb3J0YXIgQmFzZXMgZGUgRGF0b3MgKE3DqXhpY28pKioKYGBge3J9CnZlbnRhc2lfYXV0b3BhcnRlcyA8LSByZWFkLmNzdigiL1VzZXJzL2FuaXRhMy9EZXNrdG9wL0ZPUk0vVmVudGFzQVAuY3N2IikKYGBgCgoqKkltcG9ydGFyIEJhc2VzIGRlIERhdG9zIChFVUEpKioKYGBge3J9CmV1YSA8LSByZWFkLmNzdigiL1VzZXJzL2FuaXRhMy9Eb3dubG9hZHMvY2FyX3Byb2R1Y3Rpb24uY3N2IikKYGBgCgoqKkxpYnJlcmlhcyBhIFV0aWxpemFyKioKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSh0c2VyaWVzKSAgIApsaWJyYXJ5KGZvcmVjYXN0KSAgCmxpYnJhcnkoYXN0c2EpICAgIApgYGAKCiMjIyBNb2RlbG8gZGUgcmVncmVzacOzbiBsaW5lYWwgbcO6bHRpcGxlICoqTcOpeGljbyoqCgpUZW5lbW9zIGxhcyB2ZW50YXMgaW50ZXJuYWNpb25hbGVzIGRlIGF1dG9wYXJ0ZXMgcG9yIGVzdGFkbyBkZSBsYSByZXDDumJsaWNhIG1leGljYW5hLiBOdWVzdHJvIHByb29zaXRvIGVzIGVuY29udHJhciBlbCBlc3RhZG8gY29uIG1heW9yIGZ1dHVybyB5IHZvbHVtZW4gZGUgdmVudGFzIGludGVybmFjaW9uYWxlcyBkZSBhdXRvcGFydGVzLgoKYGBge3J9CnN1bW1hcnkodmVudGFzaV9hdXRvcGFydGVzKQpgYGAKCjxjZW50ZXI+IAo8c3BhbiBzdHlsZT0iY29sb3I6ICNGRkE1NEYiPiAqKkxpbXBpZXphKiogPC9zcGFuPgo8L2NlbnRlcj4gCgoqKsK/UXVlIG1vZGlmaWNhY2lvbmVzIGxlIGhhcmVtb3MgYSBsYSBiYXNlIGRlIGRhdG9zPyoqICAKRW4gZXhjZWwgcmVhbGl6YW1vcyBsaW1waWV6YSBkZSBkYXRvcyBjb246IG5vbWJyZXNfZGVfdmFyaWFibGVzLCBhw7FhZGlyIGNpZnJpYXMgYW51YWxlcyB5IHVuaXIgYmFzZXMgZGUgZGF0b3MuIEVzdG8gY29uIGxhIGZpbmFsaWRhZCBkZSByZWFsaXphciB1bmEgcHJlZGljY2nDs24gc29icmUgbG9zICoqRXN0YWRvcyBkZSBsYSBSZXDDumJsaWNhIGNvbiBlbCBtYXlvciBuw7ptZXJvIGRlIHZlbnRhcyBpbnRlcm5hY2lvbmFsZXMgZGUgYXV0b3BhcnRlcyBlbiBNw6l4aWNvKiouICAgICAKCkVuIFIsIGxhIGxpbXBpZXphIHF1ZSByZWFsaXphcmVtb3Mgc2Vyw6E6IGVsaW1pbmFyIHJlZ2lzdHJvcyBkZSBsb3MgdHJpbWVzdHJlcyAyLCAzIHkgNC4gVXNhbW9zIGNvbW8gYmFzZSBlbCB0cmltZXN0cmUgMSBwYXJhIGp1bnRhciBsYXMgY2lmcmFzIGFudWFsZXMgeSBubyByZXBldGlyIHJlZ2lzdHJvcy4gICAKCioqRWxpbWluYW1vcyBsYXMgY29sdW1uYXMgcXVlIG5vIG5lY2VzaXRhcmVtb3MgeSBDYW1iaWFtb3MgbG9zIHRpcG9zIGRlIHZhcmlhYmxlLioqICAKCioqRmlsdHJhciBwb3IgVHJpc21lc3RyZSoqICAKYGBge3J9CnZhcF8xIDwtIHZlbnRhc2lfYXV0b3BhcnRlcwp2YXBfMSA8LSBmaWx0ZXIodmFwXzEsIHRyaW1lc3RyZSA9PSAxKQpgYGAKCioqRWxpbWluYXIgQ29sdW1uYXMqKgpgYGB7cn0KdmFwXzIgPC0gdmFwXzEKdmFwXzIgPC0gc3Vic2V0KHZhcF8yLHNlbGVjdCA9IC1jKGlkX3RyaW1lc3RyZSwgdHJpbWVzdHJlLCBpZF9lc3RhZG8sIGlkX2VzdGFkb19hbmRfaWRfdHJpbWVzdHJlLCBpZG51ZXZhLCB2ZW50YXNfYXV0b3BhcnRlc190cmltZXN0cmUsIGV4cG9ydGFjaW9uZXNfdHJpbWVzdHJhbGVzKSkKc3VtbWFyeSh2YXBfMikKYGBgCgoqKkNhbWJpYXIgdGlwb3MgZGUgdmFyaWFibGUqKgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CnZhcF8zIDwtIHZhcF8yCnZhcF8zJHZlbnRhc19hdXRvcGFydGVzX2FudWFsIDwtIGFzLm51bWVyaWModmFwXzMkdmVudGFzX2F1dG9wYXJ0ZXNfYW51YWwpCnZhcF8zJGVjaSA8LSBhcy5udW1lcmljKHZhcF8zJGVjaSkKdmFwXzMkcG9ibGFjaW9uX29jdXBhZGFfZW5zYW1ibGFkb3JhX3llYXIgPC0gYXMubnVtZXJpYyh2YXBfMyRwb2JsYWNpb25fb2N1cGFkYV9lbnNhbWJsYWRvcmFfeWVhcikKdmFwXzMkZXhwb3J0YWNpb25lc19hbnVhbCA8LSBhcy5udW1lcmljKHZhcF8zJGV4cG9ydGFjaW9uZXNfYW51YWwpCnZhcF8zJGllZGFudWFsX3BvcmVzdGFkbyA8LSBhcy5udW1lcmljKHZhcF8zJGllZGFudWFsX3BvcmVzdGFkbykKdmFwXzMkeWVhciA8LSBhcy5udW1lcmljKHZhcF8zJHllYXIpCnZhcF8zJGVzdGFkbyA8LSBhcy5jaGFyYWN0ZXIodmFwXzMkZXN0YWRvKQp2YXBfMwpgYGAKCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KdmFwXzQgPC0gdmFwXzMKdmFwXzQgPC0gdmFwXzQgJT4lCiAgZ3JvdXBfYnkoZXN0YWRvKSAlPiUKICBzdW1tYXJpc2UodmVudGFzID0gc3VtKHZlbnRhc19hdXRvcGFydGVzX2FudWFsKSkKdmFwXzQKYGBgCgpgYGB7cn0KdmFwXzcgPC0gdmFwXzMKYGBgCgpgYGB7ciwgcmVzdWx0cz0naGlkZSd9CnRvcF81IDwtIHZhcF80ICU+JQogIGZpbHRlcihyYW5rKGRlc2ModmVudGFzKSk8PTUpCnRvcF81CmBgYAoKPGNlbnRlcj4gCjxzcGFuIHN0eWxlPSJjb2xvcjogI0ZGQTU0RiI+ICoqRW5jb250cmFyIGVsIHRvcCA1IGRlIGxvcyBlc3RhZG9zIGNvbiBtYXlvciBudW1lcm8gZGUgdmVudGFzIGludGVybmFjaW9uYWxlcyBkZSBhdXRvcGFydGVzIHkgZW5mb2Nhcm5vcyBlbiBlbGxvcy4qKiA8L3NwYW4+CjwvY2VudGVyPiAKCioqRWxpbWluYXIgcmVnaXN0cm9zIGRlIGVzdGFkb3Mgbm8gcmVsZXZhbnRlcyoqCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30KbnVldmEgPC0gdmFwXzMKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iRHVyYW5nbyIpCm51ZXZhIDwtIGZpbHRlcihudWV2YSwgIWVzdGFkbz09IkhpZGFsZ28iKQpudWV2YSA8LSBmaWx0ZXIobnVldmEsICFlc3RhZG89PSJKYWxpc2NvIikKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iRXN0YWRvIGRlIE1leGljbyIpCm51ZXZhIDwtIGZpbHRlcihudWV2YSwgIWVzdGFkbz09Ik1vcmVsb3MiKQpudWV2YSA8LSBmaWx0ZXIobnVldmEsICFlc3RhZG89PSJIaWRhbGdvIikKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iUXVpbnRhbmEgUm9vIikKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iU29ub3JhIikKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iWmFjYXRlY2FzIikKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iWXVjYXRhbiIpCm51ZXZhIDwtIGZpbHRlcihudWV2YSwgIWVzdGFkbz09IlRsYXhjYWxhIikKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iVmVyYWNydXogZGUgSWduYWNpbyBkZSBsYSBMbGF2ZSIpCm51ZXZhIDwtIGZpbHRlcihudWV2YSwgIWVzdGFkbz09IkNvbGltYSIpCm51ZXZhIDwtIGZpbHRlcihudWV2YSwgIWVzdGFkbz09IkJhamEgQ2FsaWZvcm5pYSIpCm51ZXZhIDwtIGZpbHRlcihudWV2YSwgIWVzdGFkbz09IkNoaWh1YXVhIikKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iUHVlYmxhIikKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iQWd1YXNjYWxpZW50ZXMiKQpudWV2YSA8LSBmaWx0ZXIobnVldmEsICFlc3RhZG89PSJTYW4gTHVpcyBQb3Rvc2kiKQpudWV2YSA8LSBmaWx0ZXIobnVldmEsICFlc3RhZG89PSJUYW1hdWxpcGFzIikKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iQ2hpaHVhaHVhIikKbnVldmEgPC0gZmlsdGVyKG51ZXZhLCAhZXN0YWRvPT0iQ2l1ZGFkIGRlIE1leGljbyIpCgp1bmlxdWUobnVldmEkZXN0YWRvKQpgYGAKCioqRWxpbWluYW1vcyB0YW1iaWVuIGEgQ2l1ZGFkIGRlIE1leGljbyBkZWJpZG8gYSBxdWUgZXMgdW4gbWVyY2FkbyBmdWVyYSBkZWwgcXVlIGJ1c2NhIEZPUk0qKgoKYGBge3IsIHJlc3VsdHM9J2hpZGUnfQp0b3BfNCA8LSBudWV2YQp0b3BfNApgYGAKCjxjZW50ZXI+IAo8c3BhbiBzdHlsZT0iY29sb3I6ICNGRkE1NEYiPiAqKlBvZGVtb3MgaWRlbnRpZmljYXIgbGFzIHZhcmlhYmxlcyBhIHV0aWxpemFyIGRlbnRybyBkZWwgbW9kZWxvLiAqKiA8L3NwYW4+CjwvY2VudGVyPiAKCioqdmVudGFzX2F1dG9wYXJ0ZXNfYW51YWwqKiAgIApFcyBsYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSBxdWUgbm9zIGF5dWRhcsOhIGEgcmVzcG9uZGVyIGxhIHByZWd1bnRhIHByaW5jaXBhbCBzb2JyZSBsYXMgdmVudGFzIHBvciBlc3RhZG8uICAgCgoqKmVjaSoqICAKVmFyaWFibGUgZXhwbG9yYXRvcmlhIHBhcmEgY29tcGFyYXIgbG9zIGVzdGFkb3MgY29uIG1heW9yZXMgbml2ZWxlcyBkZSBpbmdyZXNvcywgcG90ZW5jaWFsIGRlIGNyZWNpbWllbnRvIGVjb27Ds21pY28sIG1lbm9yIGRlc2lndWFsZGFkIGRlIGluZ3Jlc29zIHkgbWVub3JlcyBlbWlzaW9uZXMuICAKCioqcG9ibGFjaW9uX29jdXBhZGFfZW5zYW1ibGFkb3JhX3llYXIqKiAgClZhcmlhYmxlIGV4cGxvcmF0b3JpYSBxdWUgc2UgcmVmaWVyZSBhIGxhcyBwZXJzb25hcyBkZW50cm8gZGVsIGVzdGFkbyBxdWUgdHJhYmFqYW4gZGllcmVjdGFtZW50ZSBkZW50cm8gZGUgbGEgaW5kdXN0cmlhIGRlIGF1dG9wYXJ0ZXMgZW4gZWwgcmVzcGVjaXZvIGHDsW8uICAgCgoqKmV4cG9ydGFjaW9uZXNfYW51YWwqKiAgClZhcmlhYmxlIGV4cGxvcmF0b3JpYSBxdWUgc2UgcmVmaWVyZSBhIGVsIG7Dum1lcm8gZGUgZXhwb3J0YWNpb25lcyBhbnVhbGVzIGRlbCBlc3RhZG8gZW4gdG9kYXMgbGFzIGluZHVzdHJpYXMuICAgCgoqKmllZGFudWFsX3BvcmVzdGFkb2wqKiAgClZhcmlhYmxlIGV4cGxhbmF0b3JpYSBxdWUgc2UgcmVmaWVyZSBhIGxhIGludmVyc2lvbiBleHRyYW5qZXJhIGRpcmVjdGEgYW51YWwgZGVsIGVzdGFkbywgbm8gbmVjZXNhcmlhbWVudGUgZW5mb2NhZGEgZW4gbGEgaW5kdXN0cmlhIGF1dG9tb3RyaXouIAoKUmVhbGl6YXJlbW9zIHVuIG1vZGVsbyBkZSByZWdyZXNpb24gbGluZWFsIHBhcmEgbG9zIGVzdGFkb3MgZGUgKipDb2FodWlsYSoqLCAqKkd1YW5hanVhdG8qKiwgKipOdWV2byBMZW9uKiogeSAqKlF1ZXJldGFybyoqLiBFc3RvIG5vcyBwZXJtaXRpcsOhIGV2YWx1YXIgZWwgcnVtYm8gZGUgbG9zIGVzdGFkb3MgY29uIG3DoXMgdmVudGFzIGludGVybmFjaW9uYWxlcyBkZSBhdXRvcGFydGVzLgoKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmNvYWh1aWxhIDwtIGZpbHRlcih0b3BfNCwgZXN0YWRvID09ICJDb2FodWlsYSBkZSBaYXJhZ296YSIpCmNvYWh1aWxhIDwtIHN1YnNldChjb2FodWlsYSwgc2VsZWN0ID0gLWMoZXN0YWRvKSkKY29haHVpbGEKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpudWV2b2xlb24gPC0gZmlsdGVyKHRvcF80LCBlc3RhZG8gPT0gIk51ZXZvIExlb24iKQpudWV2b2xlb248LSBzdWJzZXQobnVldm9sZW9uLCBzZWxlY3QgPSAtYyhlc3RhZG8pKQpudWV2b2xlb24KYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpndWFuYWp1YXRvIDwtIGZpbHRlcih0b3BfNCwgZXN0YWRvID09ICJHdWFuYWp1YXRvIikKZ3VhbmFqdWF0bzwtIHN1YnNldChndWFuYWp1YXRvLCBzZWxlY3QgPSAtYyhlc3RhZG8pKQpndWFuYWp1YXRvCmBgYAoKYGBge3IgaW5jbHVkZT1GQUxTRX0KcXVlcmV0YXJvIDwtIGZpbHRlcih0b3BfNCwgZXN0YWRvID09ICJRdWVyZXRhcm8iKQpxdWVyZXRhcm88LSBzdWJzZXQocXVlcmV0YXJvLCBzZWxlY3QgPSAtYyhlc3RhZG8pKQpxdWVyZXRhcm8KYGBgCgo8Y2VudGVyPiAKPHNwYW4gc3R5bGU9ImNvbG9yOiAjRkZBNTRGIj4gKipNb2RlbG8gZGUgUmVncmVzaW9uIExpbmVhbCBwb3IgRXN0YWRvKiogPC9zcGFuPgo8L2NlbnRlcj4gCgpgYGB7cn0KbW9kZWwxY29haHVpbGE8LWxtKHZlbnRhc19hdXRvcGFydGVzX2FudWFsfmVjaStwb2JsYWNpb25fb2N1cGFkYV9lbnNhbWJsYWRvcmFfeWVhcitleHBvcnRhY2lvbmVzX2FudWFsK2llZGFudWFsX3BvcmVzdGFkbyxkYXRhPWNvYWh1aWxhKSAKc3VtbWFyeShtb2RlbDFjb2FodWlsYSkKYGBgCioqQ29haHVpbGE6IEFkanVzdGVkIFItc3F1YXJlZDogIDAuNTMxNyoqCgpgYGB7cn0KbW9kZWwxbnVldm9sZW9uPC1sbSh2ZW50YXNfYXV0b3BhcnRlc19hbnVhbH5lY2krcG9ibGFjaW9uX29jdXBhZGFfZW5zYW1ibGFkb3JhX3llYXIrZXhwb3J0YWNpb25lc19hbnVhbCtpZWRhbnVhbF9wb3Jlc3RhZG8sZGF0YT1udWV2b2xlb24pIApzdW1tYXJ5KG1vZGVsMW51ZXZvbGVvbikKYGBgCioqTnVldm8gTGVvbjogQWRqdXN0ZWQgUi1zcXVhcmVkOiAgMC44MjQyKiogCgpgYGB7cn0KbW9kZWwxZ3VhbmFqdWF0bzwtbG0odmVudGFzX2F1dG9wYXJ0ZXNfYW51YWx+ZWNpK3BvYmxhY2lvbl9vY3VwYWRhX2Vuc2FtYmxhZG9yYV95ZWFyK2V4cG9ydGFjaW9uZXNfYW51YWwraWVkYW51YWxfcG9yZXN0YWRvLGRhdGE9Z3VhbmFqdWF0bykgCnN1bW1hcnkobW9kZWwxZ3VhbmFqdWF0bykKYGBgCioqR3VhbmFqdWF0bzogQWRqdXN0ZWQgUi1zcXVhcmVkOiAgMC41OTA0KioKCmBgYHtyfQptb2RlbDFxdWVyZXRhcm88LWxtKHZlbnRhc19hdXRvcGFydGVzX2FudWFsfmVjaStwb2JsYWNpb25fb2N1cGFkYV9lbnNhbWJsYWRvcmFfeWVhcitleHBvcnRhY2lvbmVzX2FudWFsK2llZGFudWFsX3BvcmVzdGFkbyxkYXRhPXF1ZXJldGFybykgCnN1bW1hcnkobW9kZWwxcXVlcmV0YXJvKQpgYGAKKipRdWVyZXRhcm86IEFkanVzdGVkIFItc3F1YXJlZDogIDAuNjg2KioKCmBgYHtyfQpvcHRpb25zKHNjaXBlbiA9OTk5KQpwbG90KG51ZXZvbGVvbiR5ZWFyLG51ZXZvbGVvbiR2ZW50YXNfYXV0b3BhcnRlc19hbnVhbCwgdHlwZT0ibCIsY29sPSJvcmFuZ2UiLCBsd2Q9MS41LCB4bGFiID0iYcOxbyIseWxhYiA9IlZlbnRhcyBlbiBkb2xhcmVzIiwgbWFpbiA9ICJWZW50YXMgSW50ZXJuYWNpb25hbGVzIGRlIE51ZXZvIExlb24gZW4gQXV0b3BhcnRlcyAiKQpsaW5lcyhudWV2b2xlb24kdmVudGFzX2F1dG9wYXJ0ZXNfYW51YWwsY29haHVpbGEkdmVudGFzX2F1dG9wYXJ0ZXNfYW51YWwsIGNvbD0iZ3JlZW4iLGx0eT0zKQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQ9YygiTnVldm8gTGVvbiIsICJDb2FodWlsYSIpLAogICAgICAgY29sPWMoIm9yYW5nZSIsICJncmVlbiIpLCBsdHkgPSAxOjIsIGNleD0wLjgpIApgYGAKCmBgYHtyfQpvcHRpb25zKHNjaXBlbiA9OTk5KQpjb2xvcnMgPC0gYygiY29haHVpbGEiPSJncmVlbiIsICJudWV2b2xlb24iPSJvcmFuZ2UiLCAicXVlcmV0YXJvIj0iYmx1ZSIsICJndWFuYWp1YXRvIj0icmVkIikKZ2dwbG90KGRhdGE9Y29haHVpbGEsIGFlcyh4PXllYXIsIHk9dmVudGFzX2F1dG9wYXJ0ZXNfYW51YWwpLCBjb2xvcj0nZ3JlZW4nKSArIApnZW9tX2xpbmUoKSArIApnZW9tX2xpbmUoZGF0YT1udWV2b2xlb24sIGFlcyh4PXllYXIsIHk9dmVudGFzX2F1dG9wYXJ0ZXNfYW51YWwpLCBjb2xvcj0nb3JhbmdlJykgKyAKZ2VvbV9saW5lKCkgKyAKZ2VvbV9saW5lKGRhdGE9cXVlcmV0YXJvLCBhZXMoeD15ZWFyLCB5PXZlbnRhc19hdXRvcGFydGVzX2FudWFsKSwgY29sb3I9J2JsdWUnKSsKZ2VvbV9saW5lKCkgKyAKZ2VvbV9saW5lKGRhdGE9Z3VhbmFqdWF0bywgYWVzKHg9eWVhciwgeT12ZW50YXNfYXV0b3BhcnRlc19hbnVhbCksIGNvbG9yPSdyZWQnKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKCIiLCAKICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIkNvYWh1aWxhIiwgIk51ZXZvIExlb24iLCAiUXVlcmV0YXJvIiwgIkd1YW5hanVhdG8iKSwKICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoImdyZWVuIiwgIm9yYW5nZSIsICJibHVlIiwgInJlZCIpKSsKICBsYWJzKHg9IlllYXIiLCB5PSJUb3RhbCBWZW50YXMgRG9sYXJlcyIpCmBgYAoKIyMjIE1vZGVsbyBkZSByZWdyZXNpw7NuIGxpbmVhbCBtw7psdGlwbGUgKipFVUEqKgoKYGBge3J9Cm5hbWVzIChldWEpWzNdID0gInBvYmxhY2lvbl9kZXNvY3VwYWRhIgpgYGAKCmBgYHtyfQpzdHIoZXVhKQpgYGAKCmBgYHtyfQpjb3JycGxvdChjb3IoZXVhKSx0eXBlPSd1cHBlcicsb3JkZXI9J2hjbHVzdCcsYWRkQ29lZi5jb2w9J2JsYWNrJykgCmBgYAoKYGBge3J9Cm1vZGVsMTwtbG0odXNfY2FyX3Byb2R1Y3Rpb25+cG9ibGFjaW9uX2Rlc29jdXBhZGErcmV0YWlsX3ByaWNlX2dhc29saW5lK2ltcG9ydHNfdmFsdWUsZGF0YT1ldWEpICAgICAKc3VtbWFyeShtb2RlbDEpCmBgYAoKYGBge3J9Cm1vZGVsMjwtbG0ocmV0YWlsX3ByaWNlX2dhc29saW5lfnBvYmxhY2lvbl9kZXNvY3VwYWRhK3VzX2Nhcl9wcm9kdWN0aW9uK2ltcG9ydHNfdmFsdWUsZGF0YT1ldWEpICAgICAKc3VtbWFyeShtb2RlbDIpCmBgYAoKIyMjIEludGVwcmV0YWNpw7NuIGRlIGxvcyByZXN1bHRhZG9zCgoqKsK/Q3XDoWxlcyBzb24gbGFzIHZhcmlhYmxlcyBleHBsYW5hdG9yaWFzIHF1ZSBtdWVzdHJhbiB1biBpbXBhY3RvIHNpZ25pZmljYXRpdm8gZW4gbGEgdmFyaWFibGUgZGVwZW5kaWVudGU/KiogICAKKirCv0PDs21vIGVzIGVsIGltcGFjdG8gZGUgZGljaGFzIHZhcmlhYmxlcyBleHBsYW5hdG9yaWFzIHNvYnJlIGxhIHZhcmlhYmxlIGRlcGVuZGllbnRlPyoqCgojIyBQcm9uw7NzdGljbyBkZWwgRGVzZW1wZcOxbyBkZSBsYSBJbmR1c3RyaWEgQXV0b21vdHJpeiB5IGxhIEVtcHJlc2EgRk9STQoKIyMjIFByb27Ds3N0aWNvICoqTcOpeGljbyoqCiAgCjxjZW50ZXI+IAoqKk1vdmluZyBBdmVyYWdlKioKPC9jZW50ZXI+IApgYGB7cn0KCnN1bW1hcnkobW9kZWwxbnVldm9sZW9uPC1hcm1hKG51ZXZvbGVvbiR2ZW50YXNfYXV0b3BhcnRlc19hbnVhbCxvcmRlcj1jKDAsMSkpKQpudWV2b2xlb25fZm9yZWNhc3Q8LWZvcmVjYXN0KG1vZGVsMW51ZXZvbGVvbiRmaXR0ZWQsaD01LGxldmVsPWMoOTUpKQpudWV2b2xlb25fZm9yZWNhc3QKYGBgCgojIyMgUHJvbsOzc3RpY28gKipFVUEqKgoKYGBge3J9CmNvbFN1bXMoaXMubmEoZXVhKSkKc3VtbWFyeShtYV9tb2RlbDwtYXJtYShldWEkdXNfY2FyX3Byb2R1Y3Rpb24vMTAwMCxvcmRlcj1jKDAsMSkpKQpgYGAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9Cm1hX21vZGVsX2ZvcmVjYXN0PC1mb3JlY2FzdChtYV9tb2RlbCRmaXR0ZWQsaD0zLGxldmVsPWMoOTUpKQpgYGAKCmBgYHtyfQptYV9tb2RlbF9mb3JlY2FzdApgYGAKCiMjIyBQcm9uw7NzdGljbyBkZWwgZGVzZW1wZcOxbyBkZSAyIGRlIGxhcyDDoXJlYXMgZGUgbGEgZW1wcmVzYSBGT1JNCgoqKiBQcm9kdWNjacOzbiBkZSBDYXJ0b24qKgoKKipNb2RlbG8gMSoqCgpgYGB7cn0KY2FydG9uMiA8LSBjYXJ0b24KYGBgCgpgYGB7cn0Kc3RyKGNhcnRvbjIpCmBgYAoKYGBge3J9CmNhcnRvbl9tb2RlbDwtZHBseXI6OnNlbGVjdChjYXJ0b24yLC1jKGZlY2hhLCBjbGllbnRlLCBocl9maW4sIGluaWNpb19zZXBfdXAsaW5pY2lvX3Byb2Nlc28sZmluX3Byb2Nlc28sIGZpbl9zZXBfdXAgKSkKY29sbmFtZXMoY2FydG9uX21vZGVsKQpgYGAKCmBgYHtyfQpjYXJ0b25fbW9kZWwgPC0gZHJvcF9uYShjYXJ0b25fbW9kZWwpCmBgYAoKYGBge3J9CmNvcnJwbG90KGNvcihjYXJ0b25fbW9kZWwpLHR5cGU9J3VwcGVyJyxvcmRlcj0naGNsdXN0JyxhZGRDb2VmLmNvbD0nYmxhY2snKSAKYGBgCgpgYGB7cn0KbW9kZWxjYXJ0b248LWxtKGxhbV9wcm9jZXNhZGFzfnBpZXphc19wcm9nK3Rtb19taW4sZGF0YT1jYXJ0b25fbW9kZWwpICAgICAKc3VtbWFyeShtb2RlbGNhcnRvbikKYGBgCgpgYGB7cn0Kc3VtbWFyeShtb2RlbGNhcnRvbjwtYXJtYShjYXJ0b24yJGxhbV9wcm9jZXNhZGFzLG9yZGVyPWMoMCwxKSkpCmBgYAoKYGBge3J9Cm1vZGVsY2FydG9uX2ZvcmVjYXN0PC1mb3JlY2FzdChtb2RlbGNhcnRvbiRmaXR0ZWQsaD0zLGxldmVsPWMoOTUpKQpgYGAKCmBgYHtyfQptb2RlbGNhcnRvbl9mb3JlY2FzdApgYGAKCioqTW9kZWxvIDIqKgoKYGBge3J9CnN0cihjYXJ0b24yKQpgYGAKCmBgYHtyfQpjYXJ0b25wX2RpYSA8LSBkcGx5cjo6c2VsZWN0KGNhcnRvbjIsIGZlY2hhLCBwaWV6YXNfcHJvZywgdG1vX21pbiwgbGFtX3Byb2Nlc2FkYXMsIHRpZW1wb19jYWxpZGFkKQpgYGAKCmBgYHtyfQpjYXJ0b25wX2RpYSA8LSBjYXJ0b25wX2RpYSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoZmVjaGEpICU+JQogIGRwbHlyOjpzdW1tYXJpemUocGllemFzX2RpYSA9IHN1bShwaWV6YXNfcHJvZyksIHRtaW5pbW9fZGlhID0gc3VtKHRtb19taW4pLCBsYW1pbmFzX2RpYSA9c3VtKGxhbV9wcm9jZXNhZGFzKSwgdGNhbGlkYWRfZGlhID0gc3VtKHRpZW1wb19jYWxpZGFkKSkKYGBgCgpgYGB7cn0KbW9kZWwxZm9ybTwtbG0obGFtaW5hc19kaWF+cGllemFzX2RpYSt0bWluaW1vX2RpYSxkYXRhPWNhcnRvbnBfZGlhKSAgICAgCnN1bW1hcnkobW9kZWwxZm9ybSkKYGBgCgpgYGB7cn0Kc3VtbWFyeShtb2RlbDFmb3JtPC1hcm1hKGNhcnRvbnBfZGlhJGxhbWluYXNfZGlhLG9yZGVyPWMoMSwxKSkpCmBgYAoKYGBge3J9Cm1vZGVsMWZvcm1fZm9yZWNhc3Q8LWZvcmVjYXN0KG1vZGVsMWZvcm0kZml0dGVkLGg9MyxsZXZlbD1jKDk1KSkKYGBgCgpgYGB7cn0KbW9kZWwxZm9ybV9mb3JlY2FzdApgYGAKCioqSy1tZWFucyoqCgoqKkltcG9ydGFyIGJhc2UgZGUgZGF0b3MqKgpgYGB7cn0KbWV4MiA8LSByZWFkLmNzdigiL1VzZXJzL2FuaXRhMy9Eb3dubG9hZHMvdHJhZGV2YWx1ZW51ZXZvMi5jc3YiKQpgYGAKCmBgYHtyfQptZXhfYWx0PC1tZXgyICU+JSBkcGx5cjo6c2VsZWN0KFN0YXRlLCBjb25jZW50cmFjaW9ubWVyY2Fkb19oaWVycm95YWNlcm8sIGV4cG9ydGFjaW9uZXNfcG9yX2VzdGFkbywgdmVudGFfYXV0b3BhcnRlc19wb3JfZXN0YWRvLCBjYWphc19kZS5wYXBlbF9vX2NhcnRvbiApCmBgYAoKKipFbGltaW5hciByZWdpc3Ryb3MgY29uIE5BwrRTIHkgQ29udmVydGlyIFZhcmlhYmxlcyBhIE51bWVyaWNvKioKYGBge3J9CgptZXhfYWx0JGNvbmNlbnRyYWNpb25tZXJjYWRvX2hpZXJyb3lhY2VybzwtIGFzLm51bWVyaWMobWV4X2FsdCRjb25jZW50cmFjaW9ubWVyY2Fkb19oaWVycm95YWNlcm8pCm1leF9hbHQkZXhwb3J0YWNpb25lc19wb3JfZXN0YWRvPC0gYXMubnVtZXJpYyhtZXhfYWx0JGV4cG9ydGFjaW9uZXNfcG9yX2VzdGFkbykKbWV4X2FsdCR2ZW50YV9hdXRvcGFydGVzX3Bvcl9lc3RhZG88LSBhcy5udW1lcmljKG1leF9hbHQkdmVudGFfYXV0b3BhcnRlc19wb3JfZXN0YWRvKQptZXhfYWx0JGNhamFzX2RlLnBhcGVsX29fY2FydG9uPC0gYXMubnVtZXJpYyhtZXhfYWx0JGNhamFzX2RlLnBhcGVsX29fY2FydG9uKQoKbWV4X2FsdCA8LSBmaWx0ZXIobWV4X2FsdCwgIWlzLm5hKG1leF9hbHQkZXhwb3J0YWNpb25lc19wb3JfZXN0YWRvKSkKbWV4X2FsdCA8LSBmaWx0ZXIobWV4X2FsdCwgIWlzLm5hKG1leF9hbHQkdmVudGFfYXV0b3BhcnRlc19wb3JfZXN0YWRvKSkKbWV4X2FsdCA8LSBmaWx0ZXIobWV4X2FsdCwgIWlzLm5hKG1leF9hbHQkY2FqYXNfZGUucGFwZWxfb19jYXJ0b24pKQpgYGAKCmBgYHtyfQptZXhfYWx0X25vcm08LXNjYWxlKG1leF9hbHRbMzo0XSkgCmBgYAoKYGBge3J9CmZ2aXpfbmJjbHVzdChtZXhfYWx0X25vcm0sIGttZWFucywgbWV0aG9kPSJ3c3MiKSsgIyB3c3MgbWV0aG9kIGNvbnNpZGVycyB0b3RhbCB3aXRoaW4gc3VtIG9mIHNxdWFyZQogIGdlb21fdmxpbmUoeGludGVyY2VwdD00LCBsaW5ldHlwZT0yKSsgICAgICAgICAgICMgb3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlcnMgaXMgY29tcHV0ZWQgd2l0aCB0aGUgZGVmYXVsdCBtZXRob2QgPSAiZXVjbGlkZWFuIgogIGxhYnMoc3VidGl0bGUgPSAiRWxib3cgbWV0aG9kIikgIApgYGAKCmBgYHtyfQptZXhfY2x1c3RlcjE8LWttZWFucyhtZXhfYWx0X25vcm0sNCkKbWV4X2NsdXN0ZXIxCmBgYAoKYGBge3J9CmZ2aXpfY2x1c3RlcihtZXhfY2x1c3RlcjEsZGF0YT1tZXhfYWx0X25vcm0pCmBgYAoKCiMjIyBJbnRlcHJldGFjacOzbiBkZSBsb3MgcmVzdWx0YWRvcwoKKirCv2N1w6FsIGVzIGxhIHRlbmRlbmNpYSBkZWwgZGVzZW1wZcOxbyBkdXJhbnRlIGVsIHBlcsOtb2RvIGRlIGFuw6FsaXNpcyB5IGxvcyBzaWd1aWVudGVzIDMgcGVyw61vZG9zIGRlIHRpZW1wbz8qKgo=