Limpieza, transformación y organización de Bases de Datos

Exportar bases de datos

Base de datos Recursos Humanos

blimpia<-read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/Base de datos FORM/Act 2.4 Equipo/bajas_limpia.csv")
climpia<-read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/Base de datos FORM/Act 2.4 Equipo/rlimpia.csv")
bajas_bd<-read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/BD_Form_Limpias/bajas_final.csv")
colab_bd<-read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/BD_Form_Limpias/colab_final.csv")
#file.choose()
bajas_bd<-read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/BD_Form_Limpias/bajas_final.csv")
colab_bd<-read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/BD_Form_Limpias/colab_final.csv")

Base de datos Delivery Plan

dp <- read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/Base de datos FORM/Act 2.4 Equipo/DELIVERY PLAN bdf_Prueba.csv")

Base de datos Delivery Performance

bd_delivery_perf <- read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/Base de datos FORM/Act 2.4 Equipo/FORM - Delivery Performance C.csv")

Base de datos Producción

data <- read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/Base de datos FORM/Act 2.4 Equipo/Producion Completa.csv")

Base de datos Merma

bd_merma <- read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/Base de datos FORM/FORM - Merma1.csv")

Base de datos Scrap

bd_scrap <- read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/Base de datos FORM/FORM - Scrap.csv")

Bases de datos externa: USA

bd_externa <- read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/Base de datos FORM/Act 2.4 Equipo/us_motor_production_and_domestic_sales.csv")
base <-read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/Base de datos FORM/Act 2.4 Equipo/us_motor_production_and_domestic_sales1.csv")

Bases de datos externa: México

bd_externaMX <- read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/industria_automotriz_mx.csv")

Librerias requeridas

library(foreign)
library(dplyr)        # data manipulation 
library(forcats)      # to work with categorical variables
library(ggplot2)      # data visualization 
library(janitor)      # data exploration and cleaning 
library(Hmisc)        # several useful functions for data analysis 
library(naniar) 
library(dlookr) 
library(pollster)
library(descr)
library(data.table)
library(epiDisplay)
library(tidyr)
library(tidyverse)
library(psych)        # functions for multivariate analysis 
library(corrplot)     # correlation plots
library(jtools)       # presentation of regression analysis 
library(lmtest)       # diagnostic checks - linear regression analysis 
library(car)          # diagnostic checks - linear regression analysis
library(olsrr)        # diagnostic checks - linear regression analysis 
library(kableExtra)   # HTML table attributes
library(tseries)   # time series analysis and computational finance 
library(forecast)  # provides methods and tools for displaying and analyzing univariate time series forecast
library(astsa)     # applied statistical time series analysis
library(plyr) 

a. FORM - Recursos Humanos

Limpieza

En la base de datos se trabajó previamente en excel, homogenizando las variables y después se trabajó en R distintas técnicas logrando eliminar las variables que no se consideren necesarias.

# Técnica. Remover valores irrelevantes
climpia2<-climpia
climpia2<-subset(climpia2,select=-c(Primer.mes,X4to.mes,Empleado,DEPARTAMENTO))
summary(climpia2)
##  ANO.DE.NACIMIENTO    GENERO          FECHA.DE.ALTA     PUESTO         
##  Min.   :1955      Length:104         Min.   :2010   Length:104        
##  1st Qu.:1978      Class :character   1st Qu.:2021   Class :character  
##  Median :1989      Mode  :character   Median :2022   Mode  :character  
##  Mean   :1987                         Mean   :2021                     
##  3rd Qu.:1996                         3rd Qu.:2022                     
##  Max.   :2003                         Max.   :2022                     
##  SALARIO.DIARIO.IMSS LUGAR.DE.NACIMIENTO  MUNICIPIO            ESTADO         
##  Min.   :144.4       Length:104          Length:104         Length:104        
##  1st Qu.:176.7       Class :character    Class :character   Class :character  
##  Median :180.7       Mode  :character    Mode  :character   Mode  :character  
##  Mean   :179.3                                                                
##  3rd Qu.:180.7                                                                
##  Max.   :337.1                                                                
##  ESTADO.CIVIL      
##  Length:104        
##  Class :character  
##  Mode  :character  
##                    
##                    
## 
# ¿Cuántos NA  tengo por variables? COLAB
sapply(climpia2,function(x) sum(is.na(x)))
##   ANO.DE.NACIMIENTO              GENERO       FECHA.DE.ALTA              PUESTO 
##                   0                   0                   0                   0 
## SALARIO.DIARIO.IMSS LUGAR.DE.NACIMIENTO           MUNICIPIO              ESTADO 
##                   0                   0                   0                   0 
##        ESTADO.CIVIL 
##                   0
# ¿Cuántos NA  tengo por variables? BAJAS
sapply(blimpia,function(x) sum(is.na(x)))
##     NOMBRE.COMPLETO                EDAD              GENERO       FECHA.DE.ALTA 
##                   0                   0                   0                   0 
##      MOTIVO.DE.BAJA            DURACION              PUESTO SALARIO.DIARIO.IMSS 
##                   0                   0                   0                   0 
##              ESTADO        ESTADO.CIVIL 
##                   0                   0
# No hay más valores faltantes.

# Técnica. Convertir tipos de datos

# Cambiar nombres de columnas.
# COLAB
str(climpia2)
## 'data.frame':    104 obs. of  9 variables:
##  $ ANO.DE.NACIMIENTO  : int  1990 1984 1984 1985 1984 1962 1966 1976 1963 1979 ...
##  $ GENERO             : chr  "FEMENINO" "MASCULINO" "FEMENINO" "MASCULINO" ...
##  $ FECHA.DE.ALTA      : int  2013 2018 2015 2016 2020 2020 2022 2022 2022 2022 ...
##  $ PUESTO             : chr  "SUPERVISORA" "MANTENIMIENTO" "COSTURERA" "AYUDANTE GENERAL" ...
##  $ SALARIO.DIARIO.IMSS: num  337 280 260 241 241 ...
##  $ LUGAR.DE.NACIMIENTO: chr  "" "" "" "" ...
##  $ MUNICIPIO          : chr  "APODACA" "APODACA" "APODACA" "APODACA" ...
##  $ ESTADO             : chr  "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" ...
##  $ ESTADO.CIVIL       : chr  "Casado" "Soltero" "Casado" "Casado" ...
names (climpia2) = c("edad", "genero", "alta", "puesto", "salario_diario", "lugar.nacim.","mpio","estado","civil")
names (climpia2)
## [1] "edad"           "genero"         "alta"           "puesto"        
## [5] "salario_diario" "lugar.nacim."   "mpio"           "estado"        
## [9] "civil"
str(climpia2)
## 'data.frame':    104 obs. of  9 variables:
##  $ edad          : int  1990 1984 1984 1985 1984 1962 1966 1976 1963 1979 ...
##  $ genero        : chr  "FEMENINO" "MASCULINO" "FEMENINO" "MASCULINO" ...
##  $ alta          : int  2013 2018 2015 2016 2020 2020 2022 2022 2022 2022 ...
##  $ puesto        : chr  "SUPERVISORA" "MANTENIMIENTO" "COSTURERA" "AYUDANTE GENERAL" ...
##  $ salario_diario: num  337 280 260 241 241 ...
##  $ lugar.nacim.  : chr  "" "" "" "" ...
##  $ mpio          : chr  "APODACA" "APODACA" "APODACA" "APODACA" ...
##  $ estado        : chr  "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" ...
##  $ civil         : chr  "Casado" "Soltero" "Casado" "Casado" ...
# BAJAS
str(blimpia)
## 'data.frame':    233 obs. of  10 variables:
##  $ NOMBRE.COMPLETO    : chr  "MARIO VALDEZ ORTIZ" "ISABEL BARRIOS MENDEZ" "MARIA ELIZABETH GOMEZ HERNANDEZ" "ALONDRA ABIGAIL ESCARCIA GOMEZ" ...
##  $ EDAD               : int  32 36 23 21 29 46 29 31 50 19 ...
##  $ GENERO             : chr  "MASCULINO" "FEMENINO" "FEMENINO" "FEMENINO" ...
##  $ FECHA.DE.ALTA      : chr  "09/03/20" "09/11/21" "10/11/21" "10/11/21" ...
##  $ MOTIVO.DE.BAJA     : chr  "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" ...
##  $ DURACION           : num  628 60 59 59 51 37 37 31 18 224 ...
##  $ PUESTO             : chr  "DISENO" "AYUDANTE GENERAL" "AYUDANTE GENERAL" "AYUDANTE GENERAL" ...
##  $ SALARIO.DIARIO.IMSS: num  500 152 152 152 152 ...
##  $ ESTADO             : chr  "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" ...
##  $ ESTADO.CIVIL       : chr  "Soltero" "Union libre" "Matrimonio" "Soltero" ...
names (blimpia) = c("nombre", "edad", "genero", "alta", "motivo_baja", "duracion", "puesto","salario_diario","estado","e.civil.")
names (blimpia)
##  [1] "nombre"         "edad"           "genero"         "alta"          
##  [5] "motivo_baja"    "duracion"       "puesto"         "salario_diario"
##  [9] "estado"         "e.civil."
str(blimpia)
## 'data.frame':    233 obs. of  10 variables:
##  $ nombre        : chr  "MARIO VALDEZ ORTIZ" "ISABEL BARRIOS MENDEZ" "MARIA ELIZABETH GOMEZ HERNANDEZ" "ALONDRA ABIGAIL ESCARCIA GOMEZ" ...
##  $ edad          : int  32 36 23 21 29 46 29 31 50 19 ...
##  $ genero        : chr  "MASCULINO" "FEMENINO" "FEMENINO" "FEMENINO" ...
##  $ alta          : chr  "09/03/20" "09/11/21" "10/11/21" "10/11/21" ...
##  $ motivo_baja   : chr  "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" ...
##  $ duracion      : num  628 60 59 59 51 37 37 31 18 224 ...
##  $ puesto        : chr  "DISENO" "AYUDANTE GENERAL" "AYUDANTE GENERAL" "AYUDANTE GENERAL" ...
##  $ salario_diario: num  500 152 152 152 152 ...
##  $ estado        : chr  "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" ...
##  $ e.civil.      : chr  "Soltero" "Union libre" "Matrimonio" "Soltero" ...
# Exportar bases de datos
colab_final<-climpia2
write.csv(colab_final, file ="colab_final.csv", row.names = FALSE)

bajas_final<-blimpia
write.csv(bajas_final, file ="bajas_final.csv", row.names = FALSE)
Cambiar a nombres de columna más cortos en base de datos colaboradores
colab_bd$genero[colab_bd$genero == "FEMENINO"] <- "F"
colab_bd$genero[colab_bd$genero == "MASCULINO"] <- "M"
str(colab_bd)
## 'data.frame':    104 obs. of  9 variables:
##  $ edad          : int  32 38 38 37 38 60 56 46 59 43 ...
##  $ genero        : chr  "F" "M" "F" "M" ...
##  $ alta          : int  2013 2018 2015 2016 2020 2020 2022 2022 2022 2022 ...
##  $ puesto        : chr  "SUPERVISORA" "MANTENIMIENTO" "COSTURERA" "AYUDANTE GENERAL" ...
##  $ salario_diario: num  337 280 260 241 241 ...
##  $ lugar.nacim.  : chr  "" "" "" "" ...
##  $ mpio          : chr  "APODACA" "APODACA" "APODACA" "APODACA" ...
##  $ estado        : chr  "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" ...
##  $ civil         : chr  "Casado" "Soltero" "Casado" "Casado" ...
Cambiar a nombres de columna más cortos en base de datos bajas
bajas_bd$genero[bajas_bd$genero == "FEMENINO"] <- "F"
bajas_bd$genero[bajas_bd$genero == "MASCULINO"] <- "M"
str(bajas_bd)
## 'data.frame':    233 obs. of  10 variables:
##  $ nombre        : chr  "MARIO VALDEZ ORTIZ" "ISABEL BARRIOS MENDEZ" "MARIA ELIZABETH GOMEZ HERNANDEZ" "ALONDRA ABIGAIL ESCARCIA GOMEZ" ...
##  $ edad          : int  32 36 23 21 29 46 29 31 50 19 ...
##  $ genero        : chr  "M" "F" "F" "F" ...
##  $ alta          : chr  "09/03/20" "09/11/21" "10/11/21" "10/11/21" ...
##  $ motivo_baja   : chr  "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" ...
##  $ duracion      : num  628 60 59 59 51 37 37 31 18 224 ...
##  $ puesto        : chr  "DISENO" "AYUDANTE GENERAL" "AYUDANTE GENERAL" "AYUDANTE GENERAL" ...
##  $ salario_diario: num  500 152 152 152 152 ...
##  $ estado        : chr  "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" ...
##  $ e.civil.      : chr  "Soltero" "Union libre" "Matrimonio" "Soltero" ...

¿Cuántas variables y cuantos registros tiene la base de datos?

Dentro de la base de datos de Colaboradores se cuenta con 9 variables y 104 registros y para la base de datos de Bajas se tiene 10 variables con 233 registros.

Clasificación y escala de medición

Clasificación Colaboradores

Variable Tipo
Año Nacimiento Cuantitativa (discreta)
Genero Cualitativa (nominal)
FechaAlta Cuantitativa (discreta)
PrimerMes Cuantitativa (discreta)
4toMes Cuantitativa (discreta)
Puesto Cualitativa (nominal)
Departamento Cualitativa (nominal)
SalarioDiario Cuantitativa (continuo)
LugarNacimiento Cualitativa (nominal)
Municipio Cualitativa (nominal)
Estado Cualitativa (nominal)
EstadoCivil Cualitativa (nominal)
Empleado Cualitativa (nominal)

Medición variables Colaboradores

Variable Medicion
Año Nacimiento Año
Genero No aplica
FechaAlta Año
PrimerMes Año
4toMes Año
Puesto No aplica
Departamento No aplica
SalarioDiario Pesos mexicanos
LugarNacimiento No aplica
Municipio No aplica
Estado No aplica
EstadoCivil No aplica
Empleado No aplica

Bajas

Variable Tipo
Nombre Completo Cualitativa (nominal)
Edad Cuantitativa (discreta)
Genero Cualitativa (nominal)
FechaAlta Cuantitativa (discreta)
Motivo de Baja Cuantitativa (discreta)
Duración Cuantitativa (discreta)
Puesto Cualitativa (nominal)
SalarioDiario Cuantitativa (continuo)
Estado Cualitativa (nominal)
EstadoCivil Cualitativa (nominal)

Medición variables Bajas

Variable Medicion
Nombre Completo No aplica
Edad Años
Genero No aplica
FechaAlta Año
Motivo de Baja No aplica
Duración Días
Puesto No aplica
SalarioDiario Pesos Mexicanos
Estado No aplica
EstadoCivil No aplica

b. Delivery plan

Limpieza

La limpieza y modificación de filas y columnas respecto a las variables se realizó directamente en Excel por cuestiones de facilidad ya que la base estaba ordenada de una manera en donde R resultaría mucho más complicado.

# Técnica 4. Convertir tipos de datos

# Convertir de caracter a fecha
dp1 <- dp
dp1$Fecha<-as.Date(dp1$Fecha,format="%m/%d/%Y") 

# Contabilizar si hay NA´S dentro de la base de datos actual para sustituirlos con la media, moda o mediana.

colSums(is.na(dp1))
## ID_Fecha    Fecha  CLIENTE  Pedidos 
##        0        0        0        0
# Vemos que en la base de datos no hay NA´S 

## Exportamos la base de datos limpia
write.csv(dp1, file ="DELIVERY_FINAL_LIMPIA.csv", row.names = FALSE)

¿Cuántas variables y cuantos registros tiene la base de datos?

Dentro de la base de datos se cuenta con 4 variables y 228 registros.

Clasificación y escala de medición

Clasificación

Variable<-c("`ID Fecha`","`Fecha`","`Clientes`","`Pedidos`")
Tipo<-c("Cualitativa (ordinal)", "Cuantitativa (discreta)","Cualitativa (nominal)","Cuantitativa(discreta)")
table<-data.frame(Variable,Tipo)
knitr::kable(table) 
Variable Tipo
ID Fecha Cualitativa (ordinal)
Fecha Cuantitativa (discreta)
Clientes Cualitativa (nominal)
Pedidos Cuantitativa(discreta)

Escala de medición

Variable<-c("`ID Fecha`","`Fecha`","`Clientes`","`Pedidos`")
Medicion<-c("Número", "Día, mes y año","Nombres","Núm. de ordenes")
table<-data.frame(Variable,Medicion)
knitr::kable(table) 
Variable Medicion
ID Fecha Número
Fecha Día, mes y año
Clientes Nombres
Pedidos Núm. de ordenes

c. Delivery Performance

Limpieza

Se realizó una limpia previa a la base de datos debido a que no se podía manejar en R, ya que el formato en que se encontraba no permitía que R pudiera entender cuales eran las variables de nuestra base de datos, por lo tanto las modificaciones y limpiezas que se realizaron fue la técnica de ‘Remover valores irrelevantes’ en este caso quitamos la conclusión porque no tendría valor en la base de datos, eliminamos target (horas) y tomamos el valor de cada inicio de mes para comparar principio de mes con mes, después en R se trabajo con la técnica de convertir tipos de datos en este caso de caracter a fecha y caracter a hora.

# Técnica 4. Convertir tipos de datos

# Convertir de caracter a fecha
bd_delivery_perf2 <- bd_delivery_perf
bd_delivery_perf2$fecha <- as.Date(bd_delivery_perf2$fecha, format ="%d/%m/%y")
library(tibble)
tibble(bd_delivery_perf2)  
## # A tibble: 52 × 3
##    fecha      cliente      dif
##    <date>     <chr>      <dbl>
##  1 2021-07-31 "PRINTEL "   4.9
##  2 2021-07-31 "MAHLE"     15.7
##  3 2021-07-31 "MAGNA"      0  
##  4 2021-07-31 "VARROC"     0  
##  5 2021-08-31 "PRINTEL "  27.7
##  6 2021-08-31 "MAHLE"     67.3
##  7 2021-08-31 "MAGNA"      0  
##  8 2021-08-31 "VARROC"     0  
##  9 2021-09-30 "PRINTEL "   8.6
## 10 2021-09-30 "MAHLE"     56.8
## # … with 42 more rows
# Cambiar los nombres de las variables más cortas y específicas

names(bd_delivery_perf2) [3] = "delay_performance"
names(bd_delivery_perf2)
## [1] "fecha"             "cliente"           "delay_performance"
# Exportar
bd_delivery_perf3 <- bd_delivery_perf2
write.csv(bd_delivery_perf3, file ="deliveryperformance_FORM_limpia.csv", row.names = FALSE)

¿Cuántas variables y cuantos registros tiene la base de datos?

Dentro de la base de datos se cuenta con 3 variables y 52 registros.

Clasificación y escala de medición

Clasificación

Variable <-c("Fecha", "Cliente", "Diferencia")
Tipo <-c("Cuantitativa (continua)","Cualitativa (nominal)","Cuantitativa (continua)")
table<-data.frame(Variable, Tipo)
knitr::kable(table)
Variable Tipo
Fecha Cuantitativa (continua)
Cliente Cualitativa (nominal)
Diferencia Cuantitativa (continua)

Escala de medición

Variable <-c("Fecha", "Cliente", "Diferencia")
Medición <-c("Dia, mes y año","Nombre","Minutos")
table<-data.frame(Variable, Medición)
knitr::kable(table)
Variable Medición
Fecha Dia, mes y año
Cliente Nombre
Diferencia Minutos

d. Producción

Limpieza

Se trabajo en la base de datos para primero eliminar columnas que no son relevantes para el analisis, después convertir de caracter a N/A para poder eliminar los espacios en blanco sin datos y por último se reemplazó los NA’s con el promedio para obtener un aproximando del tiempo de producion en los dias que esta en blanco o N/A.

#### Tecnica 1.  Remover valores irrelevantes

data1 <- data
data1<-subset(data1,select=-c(No.,ID.FORM,PRODUCTO,X,HR..FIN,ESTACION.ARRANQUE,INICIO.SEP.UP,FIN.INICIO.DE.SEP.UP,INICIO.de.PROCESO,FIN.de.PROCESO,TIEMPO.CALIDAD,TIEMPO.MATERIALES,MERMAS.Maquinas.))
str(data1)
## 'data.frame':    5300 obs. of  5 variables:
##  $ Fecha             : chr  "15/07/22" "15/07/22" "15/07/22" "15/07/22" ...
##  $ CLIENTE           : chr  "STABILUS 1" "STABILUS 1" "STABILUS 1" "STABILUS 1" ...
##  $ PIEZAS.PROG.      : int  20 15 20 10 10 20 10 10 10 60 ...
##  $ TMO..MIN.         : chr  "9:20" "9:35" "9:55" "10:05" ...
##  $ Laminas.procesadas: chr  "9:05" "10:05" "9:40" "11.2" ...
#### Tecnica 4. Convertir tipos de datos
data2 <- data1
data2$TMO..MIN. <- substr(data2$TMO..MIN., start = 1, stop = 2)
#tibble(data2)  
data2$TMO..MIN. <- as.integer(data2$TMO..MIN.)
str(data2)  
## 'data.frame':    5300 obs. of  5 variables:
##  $ Fecha             : chr  "15/07/22" "15/07/22" "15/07/22" "15/07/22" ...
##  $ CLIENTE           : chr  "STABILUS 1" "STABILUS 1" "STABILUS 1" "STABILUS 1" ...
##  $ PIEZAS.PROG.      : int  20 15 20 10 10 20 10 10 10 60 ...
##  $ TMO..MIN.         : int  NA NA NA 10 10 10 10 10 11 10 ...
##  $ Laminas.procesadas: chr  "9:05" "10:05" "9:40" "11.2" ...
data3 <- data2
data3$Laminas.procesadas <- substr(data3$Laminas.procesadas, start = 1, stop = 2)
#tibble(data3)  
data3$Laminas.procesadas <- as.integer(data3$Laminas.procesadas)
str(data3) 
## 'data.frame':    5300 obs. of  5 variables:
##  $ Fecha             : chr  "15/07/22" "15/07/22" "15/07/22" "15/07/22" ...
##  $ CLIENTE           : chr  "STABILUS 1" "STABILUS 1" "STABILUS 1" "STABILUS 1" ...
##  $ PIEZAS.PROG.      : int  20 15 20 10 10 20 10 10 10 60 ...
##  $ TMO..MIN.         : int  NA NA NA 10 10 10 10 10 11 10 ...
##  $ Laminas.procesadas: int  NA 10 NA 11 12 12 2 2 NA NA ...
data3$Fecha <- as.Date(data3$Fecha, format ="%d/%m/%y")

#### Tecnica 5. Valores faltantes
# Remplazar los valores por la media
data4 <- data3
data4$TMO..MIN.[is.na(data4$TMO..MIN.)]<-mean(data4$TMO..MIN., na.rm = TRUE)
summary (data4) 
##      Fecha              CLIENTE           PIEZAS.PROG.      TMO..MIN.   
##  Min.   :2022-01-08   Length:5300        Min.   :  0.00   Min.   : 0.0  
##  1st Qu.:2022-07-22   Class :character   1st Qu.: 15.00   1st Qu.:10.3  
##  Median :2022-08-19   Mode  :character   Median : 20.00   Median :10.3  
##  Mean   :2022-08-05                      Mean   : 28.18   Mean   :10.3  
##  3rd Qu.:2022-09-03                      3rd Qu.: 25.00   3rd Qu.:10.3  
##  Max.   :2022-12-09                      Max.   :800.00   Max.   :70.0  
##                                          NA's   :1496                   
##  Laminas.procesadas
##  Min.   : 0.000    
##  1st Qu.: 0.000    
##  Median : 0.000    
##  Mean   : 4.765    
##  3rd Qu.:10.000    
##  Max.   :97.000    
##  NA's   :2626
data5 <- data4
data5$PIEZAS.PROG.[is.na(data5$PIEZAS.PROG.)]<-mean(data5$PIEZAS.PROG., na.rm = TRUE)
summary (data5) 
##      Fecha              CLIENTE           PIEZAS.PROG.      TMO..MIN.   
##  Min.   :2022-01-08   Length:5300        Min.   :  0.00   Min.   : 0.0  
##  1st Qu.:2022-07-22   Class :character   1st Qu.: 15.00   1st Qu.:10.3  
##  Median :2022-08-19   Mode  :character   Median : 25.00   Median :10.3  
##  Mean   :2022-08-05                      Mean   : 28.18   Mean   :10.3  
##  3rd Qu.:2022-09-03                      3rd Qu.: 28.18   3rd Qu.:10.3  
##  Max.   :2022-12-09                      Max.   :800.00   Max.   :70.0  
##                                                                         
##  Laminas.procesadas
##  Min.   : 0.000    
##  1st Qu.: 0.000    
##  Median : 0.000    
##  Mean   : 4.765    
##  3rd Qu.:10.000    
##  Max.   :97.000    
##  NA's   :2626
data6 <- data5
data6$Laminas.procesadas[is.na(data6$Laminas.procesadas)]<-mean(data6$Laminas.procesadas, na.rm = TRUE)
summary (data6)
##      Fecha              CLIENTE           PIEZAS.PROG.      TMO..MIN.   
##  Min.   :2022-01-08   Length:5300        Min.   :  0.00   Min.   : 0.0  
##  1st Qu.:2022-07-22   Class :character   1st Qu.: 15.00   1st Qu.:10.3  
##  Median :2022-08-19   Mode  :character   Median : 25.00   Median :10.3  
##  Mean   :2022-08-05                      Mean   : 28.18   Mean   :10.3  
##  3rd Qu.:2022-09-03                      3rd Qu.: 28.18   3rd Qu.:10.3  
##  Max.   :2022-12-09                      Max.   :800.00   Max.   :70.0  
##  Laminas.procesadas
##  Min.   : 0.000    
##  1st Qu.: 0.000    
##  Median : 4.765    
##  Mean   : 4.765    
##  3rd Qu.: 4.765    
##  Max.   :97.000
#### Exportar base de datos
write.csv(data6, file ="producción_FORM_limpia.csv", row.names = FALSE)

¿Cuántas variables y cuantos registros tiene la base de datos?

Dentro de la base de datos se cuenta con 18 variables y 5300 registros.

Clasificación y escala de medición

Clasificación

Variable <-c("Fecha", "Cliente", "Piezas prog.", "Tiempo min.", "Láminas procesadas")
Tipo <-c("Cualitativa (nominal)","Cualitativa (nominal)", "Cuantitativa (discreta)", "Cuantitativa (discreta)", "Cuantitativa (discreta)")
table<-data.frame(Variable, Tipo)
knitr::kable(table)
Variable Tipo
Fecha Cualitativa (nominal)
Cliente Cualitativa (nominal)
Piezas prog. Cuantitativa (discreta)
Tiempo min. Cuantitativa (discreta)
Láminas procesadas Cuantitativa (discreta)

Escala de medición

Variable <-c("Fecha", "Cliente", "Piezas prog.", "Tiempo min.", "Láminas procesadas")
Medición <-c("Día, mes y año", "Nombre", "Cantidad de piezas", "Minutos", "Piezas finalizadas")
table<-data.frame(Variable, Medición)
knitr::kable(table)
Variable Medición
Fecha Día, mes y año
Cliente Nombre
Piezas prog. Cantidad de piezas
Tiempo min. Minutos
Láminas procesadas Piezas finalizadas

e. Merma

Limpieza

Se realizó una limpia previa a la base de datos debido a que no se podía manejar en R, ya que el formato en que se encontraba no permitía que R pudiera entender cuales eran las variables de nuestra base de datos y una vez teniendo la base de datos las técnicas que utilizamos en el programa fue Remover valores irrelevantes dejando las variables con mayor importancia como: Fecha, Cantidad y Ubicación de origen y la segunda técnica que utilizamos fue Convertir de caracter a fecha para tener la fecha en entero.

# Técnica. Remover valores irrelevantes

# Eliminar columnas
summary(bd_merma)
##     Fecha               Mes                Kilos       
##  Length:60          Length:60          Min.   :   790  
##  Class :character   Class :character   1st Qu.:  3545  
##  Mode  :character   Mode  :character   Median :  4025  
##                                        Mean   :  9271  
##                                        3rd Qu.:  4702  
##                                        Max.   :185426
bd_merma2 <- bd_merma
bd_merma2 <- subset (bd_merma2, select = -c (Mes))

# Eliminar renglones
bd_merma3 <- bd_merma2
bd_merma3 <- bd_merma3[bd_merma3$Fecha > 0, ]


# Técnica. Convertir tipos de datos

# Convertir de caracter a fecha
bd_merma4 <- bd_merma3
bd_merma4$Fecha <- as.Date(bd_merma4$Fecha, format ="%d/%m/%y")

# Exportar
bd_merma5 <- bd_merma4
write.csv(bd_merma5, file ="merma_FORM_limpia.csv", row.names = FALSE)

¿Cuántas variables y cuantos registros tiene la base de datos?

Dentro de la base de datos se cuenta con 3 variables y 60 registros.

Clasificación y escala de medición

Clasificación

Variable <-c("Fecha", "Merma")
Tipo <-c("Cualitativa (nominal)", "Cuantitativa (discreta)")
table<-data.frame(Variable, Tipo)
knitr::kable(table)
Variable Tipo
Fecha Cualitativa (nominal)
Merma Cuantitativa (discreta)

Escala de medición

Variable <-c("Fecha", "Merma")
Medición <-c("Día, mes y año", "Kilos")
table<-data.frame(Variable, Medición)
knitr::kable(table)
Variable Medición
Fecha Día, mes y año
Merma Kilos

f. Scrap

¿Cuántas variables y cuantos registros tiene la base de datos?

Dentro de la base de datos se cuenta con 9 variables y 250 registros.

Limpieza

Se realizó una limpia previa a la base de datos debido a que no se podía manejar en R, ya que el formato en que se encontraba no permitía que R pudiera entender cuales eran las variables de nuestra base de datos y una vez teniendo la base de datos las técnicas que utilizamos en el programa fue Remover valores irrelevantes dejando las variables con mayor importancia como: Fecha, Cantidad y Ubicación de origen y la segunda técnica que utilizamos fue Convertir de caracter a fecha para tener la fecha en entero.

#### Técnica. Remover valores irrelevantes

#### Eliminar columnas
summary(bd_scrap)
##   Referencia           Fecha               Hora             Producto        
##  Length:250         Length:250         Length:250         Length:250        
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##     Cantidad      Unidad.de.medida   Ubicación.de.origen Ubicación.de.desecho
##  Min.   : 0.000   Length:250         Length:250          Length:250          
##  1st Qu.: 1.000   Class :character   Class :character    Class :character    
##  Median : 2.000   Mode  :character   Mode  :character    Mode  :character    
##  Mean   : 6.696                                                              
##  3rd Qu.: 7.000                                                              
##  Max.   :96.000                                                              
##     Estado         
##  Length:250        
##  Class :character  
##  Mode  :character  
##                    
##                    
## 
bd_scrap2 <- bd_scrap
bd_scrap2 <- subset (bd_scrap2, select = -c (Referencia, Hora, Producto, Unidad.de.medida, Ubicación.de.desecho, Estado))

summary (bd_scrap2)
##     Fecha              Cantidad      Ubicación.de.origen
##  Length:250         Min.   : 0.000   Length:250         
##  Class :character   1st Qu.: 1.000   Class :character   
##  Mode  :character   Median : 2.000   Mode  :character   
##                     Mean   : 6.696                      
##                     3rd Qu.: 7.000                      
##                     Max.   :96.000
#### Técnica. Convertir tipos de datos

#### Convertir de caracter a fecha
bd_scrap3 <- bd_scrap2
bd_scrap3$Fecha <- as.Date(bd_scrap3$Fecha, format ="%d/%m/%y")
summary(bd_scrap3)
##      Fecha               Cantidad      Ubicación.de.origen
##  Min.   :2020-08-01   Min.   : 0.000   Length:250         
##  1st Qu.:2020-08-11   1st Qu.: 1.000   Class :character   
##  Median :2020-08-19   Median : 2.000   Mode  :character   
##  Mean   :2020-08-17   Mean   : 6.696                      
##  3rd Qu.:2020-08-25   3rd Qu.: 7.000                      
##  Max.   :2020-08-31   Max.   :96.000
# Cambiar los nombres de las variables más cortas y específicas

names(bd_scrap3) [3] = "Ubi_origen"
names(bd_scrap3)
## [1] "Fecha"      "Cantidad"   "Ubi_origen"
#### Exportar base de datos
bd_scrap4 <- bd_scrap3
write.csv(bd_scrap4, file ="scrap_FORM_limpia.csv", row.names = FALSE)

¿Cuántas variables y cuantos registros tiene la base de datos?

Dentro de la base de datos se cuenta con 9 variables y 250 registros.

Clasificación y escala de medición

Clasificación

Variable <-c("Fecha", "Cantidad", "Ubicación Origen")
Tipo <-c("Cualitativa (nominal)", "Cuantitativa (discreta)", "Cualitativa (nominal)")
table<-data.frame(Variable, Tipo)
knitr::kable(table)
Variable Tipo
Fecha Cualitativa (nominal)
Cantidad Cuantitativa (discreta)
Ubicación Origen Cualitativa (nominal)

Escala de medición

Variable <-c("Fecha", "Cantidad", "Ubicación Origen")
Medición <-c("Día, mes y año", "Kilos", "Nombre Area FORM")
table<-data.frame(Variable, Medición)
knitr::kable(table)
Variable Medición
Fecha Día, mes y año
Cantidad Kilos
Ubicación Origen Nombre Area FORM

Análisis estadístico descriptivo FORM

Tablas de frecuencia

BD Recursos humanos: Colaboradores
bd_colabf <- table(colab_final$genero)
knitr::kable(bd_colabf)
Var1 Freq
FEMENINO 59
MASCULINO 45
bd_colabf2 <- table(colab_final$civil)
knitr::kable(bd_colabf2)
Var1 Freq
Casado 39
Divorciado 3
Soltero 42
Union libre 20
bd_colabf3 <- table(colab_final$mpio)
knitr::kable(bd_colabf3)
Var1 Freq
APODACA 67
CANADA BLANCA 1
GUADALUPE 5
JUAREZ 9
MONTERREY 3
PESQUERIA 9
RAMOS ARIZPE 3
SALTILLO 5
SAN NICOLAS DE LOS G 2
bd_colabf4 <- table(colab_final$estado)
knitr::kable(bd_colabf4)
Var1 Freq
Coahuila 9
Nuevo Leon 95
bd_colabf5 <- table(colab_final$puesto)
knitr::kable(bd_colabf5)
Var1 Freq
AYUDANTE DE MANTENIMIENTO 1
Ayudante general 1
AYUDANTE GENERAL 61
CHOFER 3
CHOFER GESTOR 1
COSTURERA 10
CUSTOMER SERVICE INF 1
ENFERMERA 1
GESTOR 1
GUARDIA DE SEGURIDAD 1
INSPECTOR DE CALIDAD 2
LIDER 1
LIMPIEZA 1
MANTENIMIENTO 1
MONTACARGUISTA 1
MOZO 1
OP. FLEXO-RANURADORA-REFILADORA 1
OPERADOR SIERRA 1
PINTOR 1
RECIBO 1
RESIDENTE 4
SOLDADOR 5
Supervisor de M√°quin 1
Supervisor de pegado 1
SUPERVISORA 1
BD Recursos humanos: Bajas
bd_bajasf <- table(bajas_final$motivo_baja)
knitr::kable(bd_bajasf)
Var1 Freq
ABANDONO 1
BAJA POR FALTAS 139
JUBILACION 1
RENUNCIA VOLUNTARIA 84
TERMINO DE CONTRATO 8
bd_bajasf2 <- table(bajas_final$genero)
knitr::kable(bd_bajasf2)
Var1 Freq
FEMENINO 137
MASCULINO 96
bd_bajasf3 <- table(bajas_final$puesto)
knitr::kable(bd_bajasf3)
Var1 Freq
ANALISTA DE NOMINAS /AUX DE R.H. 1
AUXILIAR DE EMBARQUES 3
AYUD.EMBARQUES 1
AYUDANTE DE EMBARQUES 3
AYUDANTE DE MTTO 1
AYUDANTE DE SOLDADOR 1
AYUDANTE GENERAL 176
AYUDANTE GENERAL DE EMBARQUES 1
CHOFER 1
CORTADOR 1
COSTURERA 10
COSTURERO 1
DISENO 1
ENCARGADA DE CALIDAD 1
FACTURACION 1
GUARDIA DE SEGURIDAD 2
INSPECTOR CALIDAD 3
INSPECTORA DE CALIDAD 1
LIMPIEZA 1
MARCADORA 1
MATERIALISTA 2
MONTACARGUISTA 5
PRACTICANTE DE MTTO 1
RESIDENTE 2
Residente Yanfeng 1
SERVICIO AL CLIENTE 1
SOLDADOR 10
bd_bajasf4 <- table(bajas_final$e.civil)
knitr::kable(bd_bajasf4)
Var1 Freq
1
Divorcio 3
Matrimonio 63
Soltero 107
Union libre 59
Tablas cruzadas
Recursos humanos: Colaboradores
cruzada1<-table(colab_final$salario_diario,colab_final$genero)
knitr::kable(cruzada1)
FEMENINO MASCULINO
144.45 3 0
151.61 7 4
151.67 1 2
152.86 1 0
175.79 0 1
176.72 7 14
180.68 33 22
181.68 1 0
184.68 1 0
185.68 1 0
208.65 1 0
240.71 1 0
240.75 0 1
260.01 1 0
279.61 0 1
337.05 1 0
Recursos humanos: Bajas
cruzada1<-table(bajas_final$edad, bajas_final$salario_diario)
knitr::kable(cruzada1)
144.45 151.61 151.67 176.72 180.68 182.68 183.68 500
18 0 0 0 0 2 0 0 0
19 0 4 0 1 7 1 0 0
20 0 2 0 0 12 0 0 0
21 0 3 0 1 11 0 0 0
22 0 1 0 1 8 0 0 0
23 0 2 0 0 10 0 0 0
24 0 1 0 1 10 0 0 0
25 0 1 0 1 8 0 0 0
26 0 0 0 0 11 0 0 0
27 1 0 0 2 8 0 0 0
28 0 1 0 1 4 0 0 0
29 0 2 0 0 6 0 0 0
30 0 1 0 1 9 0 0 0
31 0 1 0 1 5 0 0 0
32 0 1 0 0 8 0 0 1
33 0 0 1 0 4 0 0 0
34 0 1 0 0 2 0 0 0
35 0 1 0 0 4 0 0 0
36 0 1 0 0 7 0 0 0
37 0 0 0 1 5 0 0 0
38 0 0 0 0 5 0 0 0
39 0 0 0 0 3 0 0 0
40 0 0 0 0 1 0 0 0
41 0 0 0 0 7 0 0 0
42 0 0 0 0 3 0 0 0
43 0 1 0 0 1 0 0 0
44 0 0 0 0 4 0 0 0
45 0 1 0 1 1 0 0 0
46 0 1 0 0 2 0 0 0
47 0 0 0 0 3 0 1 0
48 0 0 0 1 3 0 0 0
49 0 0 1 0 3 0 0 0
50 0 2 0 1 0 0 0 0
51 0 0 0 0 1 1 0 0
52 0 0 0 0 2 0 0 0
54 0 0 0 0 1 0 0 0
56 0 0 0 0 1 0 0 0
57 0 0 0 0 1 0 0 0
61 0 0 0 1 0 0 0 0
Producción
cruzada1<-table(data6$Fecha,data6$PIEZAS.PROG.)
knitr::kable(cruzada1)
0 5 10 12 15 20 25 26 28.1845425867508 30 35 40 41 45 50 56 57 60 62 68 69 70 75 80 90 99 100 104 110 120 130 150 160 192 199 200 208 216 240 300 320 400 483 600 800
2022-01-08 0 0 0 1 0 1 0 2 0 0 0 1 1 0 4 1 2 1 1 1 2 1 0 1 0 1 11 4 0 0 0 0 5 12 5 22 6 1 1 2 5 11 1 1 3
2022-02-08 1 0 22 0 15 18 15 0 37 2 0 6 0 0 1 0 0 1 0 0 0 2 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-03-08 0 0 18 0 20 9 18 0 28 1 2 6 0 0 3 0 0 3 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-04-08 0 1 7 0 14 11 15 0 20 1 3 3 0 2 3 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-05-08 4 0 18 0 9 11 9 0 25 4 0 1 0 1 2 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-05-09 0 0 27 0 13 17 24 0 26 2 3 3 0 0 4 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-06-08 0 0 7 0 6 4 13 0 22 0 2 4 0 2 0 0 0 2 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-06-09 0 0 18 0 19 13 18 0 32 0 6 5 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-09 0 0 7 0 8 13 12 0 21 1 1 1 0 0 5 0 0 0 0 0 0 0 1 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-15 0 0 8 0 1 11 13 0 15 1 1 1 0 0 4 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-16 0 0 13 0 4 8 6 0 14 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-18 0 0 9 0 9 4 13 0 17 1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-19 0 0 6 0 6 10 15 0 17 2 1 5 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-20 0 0 22 0 5 12 10 0 16 6 2 1 0 0 3 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-21 0 0 9 0 8 13 16 0 29 2 1 0 0 0 4 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-22 0 0 17 0 1 9 15 0 29 0 0 4 0 0 2 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-23 0 0 8 0 3 7 7 0 17 2 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-25 0 0 26 0 15 13 19 0 21 4 2 1 0 0 2 0 0 2 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-26 0 0 11 0 12 18 19 0 25 1 0 5 0 0 6 0 0 4 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-27 0 0 12 0 11 11 17 0 26 0 3 1 0 0 7 0 0 4 0 0 0 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-28 0 0 15 0 18 7 24 0 35 0 3 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-29 0 0 25 0 11 13 14 0 40 0 2 2 0 0 1 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-07-30 0 0 7 0 14 7 5 0 28 1 3 1 0 0 1 0 0 3 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-08 0 0 0 0 0 6 7 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-09 0 0 13 0 3 13 18 0 21 0 3 1 0 0 4 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-13 0 0 14 0 7 10 25 0 23 1 0 2 0 0 1 0 0 4 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-15 0 0 19 0 17 12 15 0 31 1 1 3 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-16 2 0 13 0 14 9 20 0 28 2 1 3 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-17 0 0 17 0 19 9 22 0 33 2 0 2 0 0 1 0 0 4 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-18 0 0 11 0 10 12 18 0 28 2 3 3 0 0 3 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-19 0 0 20 0 18 7 26 0 28 1 1 4 0 0 3 0 0 4 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-20 0 0 12 0 8 7 13 0 25 2 2 2 0 0 4 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-22 29 0 7 0 14 2 16 0 2 3 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-23 0 0 12 0 8 16 14 0 35 2 3 4 0 2 5 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-24 0 0 8 0 13 13 22 0 33 0 2 1 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-25 0 0 18 0 11 14 26 0 33 2 1 1 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-26 0 0 21 0 10 16 16 0 35 2 6 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-27 0 0 9 0 7 4 18 0 21 0 4 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-29 0 0 23 0 7 14 19 0 26 1 7 5 0 0 6 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-30 0 0 27 0 8 17 22 0 35 0 2 2 0 0 3 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-08-31 0 0 23 0 4 14 25 0 38 3 1 1 0 0 2 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-01 0 0 23 0 12 13 25 0 31 1 2 2 0 0 3 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-02 0 0 10 0 9 12 23 0 33 8 1 2 0 0 1 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-03 0 0 22 0 24 13 35 0 56 2 3 3 0 0 2 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-08 0 0 13 0 12 14 21 0 23 1 6 4 0 0 4 0 0 3 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-09 0 0 4 0 5 4 13 0 18 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-13 0 0 12 0 13 12 29 0 36 0 0 1 0 0 0 0 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-14 0 0 20 0 14 11 17 0 28 0 3 5 0 0 4 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-15 0 0 8 0 7 8 13 0 22 0 3 2 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-16 0 0 7 0 11 3 10 0 13 1 0 2 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-17 0 0 14 0 14 7 8 0 24 1 0 1 0 0 2 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-19 0 0 10 0 14 13 22 0 32 2 1 3 0 0 4 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-09-20 0 0 11 0 24 7 17 0 29 1 0 1 0 1 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-10-08 0 0 15 0 10 16 23 0 24 3 4 8 0 0 2 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-10-09 0 0 19 0 10 9 19 0 29 2 4 4 0 0 2 0 0 2 0 0 0 1 2 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-11-08 0 0 17 0 11 7 26 0 23 1 0 5 0 0 3 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-12-08 0 0 16 0 12 7 23 0 26 3 3 1 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2022-12-09 0 0 17 0 12 10 20 0 34 0 2 1 0 0 5 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
cruzada2<-table(data6$Laminas.procesadas,data6$TMO..MIN.)
knitr::kable(cruzada2)
0 2 4 9 10 10.3026178010471 11 12 15 20 25 30 35 40 45 50 60 65 70
0 128 0 0 0 100 1166 124 109 0 0 0 0 0 0 0 0 0 0 0
1 1 0 0 0 0 5 3 2 0 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 4 7 1 3 0 0 0 0 0 0 0 0 0 0 0
3 1 0 0 0 1 8 5 5 0 0 0 0 0 0 0 0 0 0 0
4 1 0 0 0 0 2 2 1 0 0 0 0 0 0 0 0 0 0 0
4.76477187733732 60 1 1 0 250 1947 175 186 4 0 1 0 0 0 0 1 0 0 0
8 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0
9 4 0 0 0 6 12 1 1 0 0 0 0 0 0 0 0 0 0 0
10 3 0 0 1 146 92 75 26 0 2 2 1 0 0 1 0 0 0 0
11 1 0 0 0 103 71 84 40 0 0 0 0 0 0 0 0 0 0 0
12 1 0 0 0 57 71 61 50 0 0 0 0 0 0 0 0 0 0 0
13 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
14 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0
16 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 1 0
17 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
19 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0
20 0 0 0 0 0 3 0 0 1 1 13 0 1 0 2 0 1 0 0
21 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0
22 0 0 0 0 0 0 0 0 1 0 2 0 0 0 0 0 0 0 0
23 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
25 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
27 0 0 0 0 1 0 0 0 2 0 0 0 0 0 0 0 0 0 0
32 0 0 0 0 0 1 1 0 0 0 0 0 2 0 0 0 0 0 0
33 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0
35 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
38 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0
40 0 0 0 0 0 1 1 0 0 0 1 0 0 2 0 0 0 0 0
41 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0
44 2 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
49 0 0 0 0 0 0 0 0 2 1 0 0 0 0 0 0 0 0 0
50 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
51 0 0 0 0 2 0 0 0 3 0 0 0 0 0 0 0 0 0 0
53 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0
55 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
65 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0
69 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
79 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
80 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0
97 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
Gráficos de datos cualitativos y cuantitativos
Colaboradores
Pie chart
proporciones <- c(59, 45) # creamos un vector con proporciones
etiquetas <- c("FEMENINO", "MASCULINO") # vector con etiquetas
pct <- round(proporciones/sum(proporciones)*100)
etiquetas <- paste(etiquetas,pct) # Añadimos porcentajes a etiquetas
etiquetas <- paste(etiquetas,"%",sep="") # Añadimos el símbolo de %

pie(proporciones,labels = etiquetas,
    col=rainbow(length(etiquetas)),
    main="Género")

Bar plot “Frecuencia de Estado Civil en la empresa”
df <- data.frame(Civil= c("Soltero","Casado", "Unión libre", "Divorciado"),
                 num= c(42, 39, 20, 3))

barplot(height = df$num, names = df$Civil,
        col = rainbow(4))

Histograma
hist(colab_bd$salario_diario, main = "Salario Diario", xlab = "Cantidad", ylab = "Frecuencia",col = "blue")

##### Bajas ###### Pie Chart sobre motivo de baja

proporciones <- c(139, 84, 8, 1, 1) # creamos un vector con proporciones
etiquetas <- c("BAJA POR FALTAS", "RENUNCIA VOLUNTARIA", "TERMINO DE CONTRATO","JUBILACIÓN", "ABANDONO") # vector con etiquetas
pct <- round(proporciones/sum(proporciones)*100)
etiquetas <- paste(etiquetas,pct) # Añadimos porcentajes a etiquetas
etiquetas <- paste(etiquetas,"%",sep="") # Añadimos el símbolo de %

pie(proporciones,labels = etiquetas,
    col=rainbow(length(etiquetas)),
    main="Género")

###### Bar plot “Bajas por estado civil”

df <- data.frame(Civil= c("Soltero","Matrimonio", "Unión libre", "Divorciado"),
                 num= c(107,63, 59, 3))

barplot(height = df$num, names = df$Civil,
        col = rainbow(4), legend.text = rownames(df))

Gráficos de dispersión
Producción
plot(x = data6$TMO..MIN., y = data6$Laminas.procesadas,  main = "Relación entre Laminas y Tiempo", xlab = "Tiempo", ylab = "Laminas procesadas")

Merma
plot(x = bd_merma5$Fecha, y = bd_merma5$Kilos,  main = "Relación entre Mes y Kilos", xlab = "Mes", ylab = "Kilos de merma")

Análisis estadístico descriptivo: Industria Automotriz

Tablas de frecuencia

bd_externa2 <- table(bd_externa$US_Min_Hour_Wage)
knitr::kable(bd_externa2)
Var1 Freq
5.5 1
6.2 1
6.9 1
7.25 11
Gráficos de datos cualitativos y cuantitativos
Industria Automotriz USA
ggplot(bd_externa, aes(x=reorder(Year,Total_Production), y=Domestic_Sales)) +
  geom_bar(stat="identity")+
  coord_flip()

Industria Automotriz México
Histograma
hist(bd_externaMX$unidades_exportacion, main = "Distribución de frecuencias Exportación", xlab = "Exportación", ylab = "Frecuencia",col = "red")

Gráficos de dispersión
Industria Automotriz USA
plot(x = bd_externa$Production_Commercial_Vehicles, y = bd_externa$Sales_Commercial_Vehicles,  main = "Vehículos Comerciales", xlab = "Producción", ylab = "Ventas")

Industria Automotriz México
plot(x = bd_externaMX$unidades_exportacion, y = bd_externaMX$unidades_produccion,  main = "Relación entre exportación y unidades de todo tipo vehículos", xlab = "Exportación", ylab = "Producción")

Análisis Exploratorio de las Bases de Datos

Estadísticos descriptivos Recursos humanos

# install.packages("psych")
library(psych)

describe(colab_final) # Función que nos da datos descriptivos
##                vars   n    mean    sd  median trimmed   mad     min     max
## edad              1 104 1986.52 12.20 1989.00 1987.32 13.34 1955.00 2003.00
## genero*           2 104    1.43  0.50    1.00    1.42  0.00    1.00    2.00
## alta              3 104 2020.69  2.34 2022.00 2021.25  0.00 2010.00 2022.00
## puesto*           4 104    7.01  6.75    3.00    5.69  0.00    1.00   25.00
## salario_diario    5 104  179.35 25.17  180.68  176.88  0.00  144.45  337.05
## lugar.nacim.*     6 104   15.38 13.49   14.50   14.46 20.02    1.00   42.00
## mpio*             7 104    2.58  2.41    1.00    2.13  0.00    1.00    9.00
## estado*           8 104    1.91  0.28    2.00    2.00  0.00    1.00    2.00
## civil*            9 104    2.41  1.18    3.00    2.39  1.48    1.00    4.00
##                range  skew kurtosis   se
## edad            48.0 -0.51    -0.80 1.20
## genero*          1.0  0.27    -1.95 0.05
## alta            12.0 -2.49     6.57 0.23
## puesto*         24.0  1.46     0.55 0.66
## salario_diario 192.6  3.31    16.26 2.47
## lugar.nacim.*   41.0  0.30    -1.38 1.32
## mpio*            8.0  1.21     0.05 0.24
## estado*          1.0 -2.90     6.47 0.03
## civil*           3.0 -0.13    -1.57 0.12
# Sacamos moda con otra función ya que en la función describe no nos la da
mode <- function (x) {
  ux <- unique(x)
  ux [which.max(tabulate(match(x,ux)))]
}

mode <- mode(colab_final$salario_diario)
mode
## [1] 180.68
Variables <-c("Salario diario" )
Media <-c("179.35" )
Mediana <-c("180.68" )
Moda <- c("180.68")
Desviacion_estandar <-c("25.17" )
tablecolab <- describe(data)
knitr::kable(tablecolab)
vars n mean sd median trimmed mad min max range skew kurtosis se
Fecha* 1 5300 29.284717 17.493629 29.0 29.264623 23.7216 1 58 57 0.0064672 -1.2818588 0.2402935
No.  2 5274 48.189041 29.437293 46.0 47.121090 35.5824 1 121 120 0.2499196 -0.9584016 0.4053478
CLIENTE* 3 5299 6.975090 2.617878 7.0 6.979014 1.4826 1 12 11 0.0736036 0.2211464 0.0359627
ID.FORM* 4 5299 143.393659 85.453129 152.0 142.013912 99.3342 1 311 310 0.0098375 -0.9025308 1.1738997
PRODUCTO* 5 5300 218.204528 123.083001 218.0 221.840094 149.7426 1 408 407 -0.1680240 -1.2048808 1.6906750
X* 6 5300 124.773962 99.349535 92.0 117.475000 130.4688 1 339 338 0.4240316 -0.9917658 1.3646708
PIEZAS.PROG. 7 3804 28.184543 42.610363 20.0 20.978975 7.4130 0 800 800 9.0626518 118.0020228 0.6908678
TMO..MIN.* 8 5300 118.286793 90.535906 131.0 114.214151 100.8168 1 274 273 0.0092239 -1.1219211 1.2436063
HR..FIN* 9 5300 84.927925 14.275750 87.0 86.411557 14.8260 1 99 98 -2.2309927 9.7820520 0.1960925
ESTACION.ARRANQUE* 10 5300 128.931509 151.437504 43.5 107.197170 63.0105 1 480 479 0.8514809 -0.6492739 2.0801541
Laminas.procesadas* 11 5300 177.477170 247.368831 3.0 134.551179 2.9652 1 754 753 1.0927667 -0.3197660 3.3978722
INICIO.SEP.UP* 12 5300 171.862830 241.797486 2.0 128.451887 1.4826 1 748 747 1.1205817 -0.2259700 3.3213439
FIN.INICIO.DE.SEP.UP* 13 5300 279.906604 301.987843 206.0 245.659670 303.9330 1 886 885 0.6272972 -1.0548002 4.1481220
INICIO.de.PROCESO* 14 5300 284.753585 303.733582 223.0 248.791745 329.1372 1 905 904 0.6060365 -1.0362020 4.1721016
FIN.de.PROCESO* 15 5300 10.405283 14.371053 12.0 7.844104 0.0000 1 109 108 3.7375855 16.1045786 0.1974016
TIEMPO.CALIDAD 16 676 3.106509 7.406737 0.0 1.265683 0.0000 0 60 60 3.7767077 17.6210730 0.2848745
TIEMPO.MATERIALES* 17 5300 1.102453 0.682923 1.0 1.000000 0.0000 1 13 12 9.0669699 97.0207719 0.0093807
MERMAS.Maquinas. 18 24 2.208333 1.102533 2.0 2.150000 1.4826 1 4 3 0.3515919 -1.3010627 0.2250537

Esta tabla de frecuencias nos dice que en FORM el salario promedio es de $179.

Estadísticos descriptivos Producción

# install.packages("psych")
library(psych)
describe(data6) # Función que nos da datos descriptivos
##                    vars    n  mean    sd median trimmed  mad min  max range
## Fecha                 1 5300   NaN    NA     NA     NaN   NA Inf -Inf  -Inf
## CLIENTE*              2 5299  6.98  2.62   7.00    6.98 1.48   1   12    11
## PIEZAS.PROG.          3 5300 28.18 36.10  25.00   23.20 7.41   0  800   800
## TMO..MIN.             4 5300 10.30  3.21  10.30   10.36 0.00   0   70    70
## Laminas.procesadas    5 5300  4.76  5.59   4.76    4.09 2.62   0   97    97
##                     skew kurtosis   se
## Fecha                 NA       NA   NA
## CLIENTE*            0.07     0.22 0.04
## PIEZAS.PROG.       10.70   165.61 0.50
## TMO..MIN.           5.01    82.01 0.04
## Laminas.procesadas  5.27    54.30 0.08
# Sacamos moda con otra función ya que en la función describe no nos la da
mode <- function (x) {
  ux <- unique(x)
  ux [which.max(tabulate(match(x,ux)))]
}

mode <- mode(data6$PIEZAS.PROG.)
mode
## [1] 28.18454
Variables <-c("Piezas programadas" )
Media <-c("28.18" )
Mediana <-c("25" )
Moda <- c("28.18")
Desviacion_estandar <-c("36.10" )
table1 <- describe(data)
knitr::kable(table1)
vars n mean sd median trimmed mad min max range skew kurtosis se
Fecha* 1 5300 29.284717 17.493629 29.0 29.264623 23.7216 1 58 57 0.0064672 -1.2818588 0.2402935
No.  2 5274 48.189041 29.437293 46.0 47.121090 35.5824 1 121 120 0.2499196 -0.9584016 0.4053478
CLIENTE* 3 5299 6.975090 2.617878 7.0 6.979014 1.4826 1 12 11 0.0736036 0.2211464 0.0359627
ID.FORM* 4 5299 143.393659 85.453129 152.0 142.013912 99.3342 1 311 310 0.0098375 -0.9025308 1.1738997
PRODUCTO* 5 5300 218.204528 123.083001 218.0 221.840094 149.7426 1 408 407 -0.1680240 -1.2048808 1.6906750
X* 6 5300 124.773962 99.349535 92.0 117.475000 130.4688 1 339 338 0.4240316 -0.9917658 1.3646708
PIEZAS.PROG. 7 3804 28.184543 42.610363 20.0 20.978975 7.4130 0 800 800 9.0626518 118.0020228 0.6908678
TMO..MIN.* 8 5300 118.286793 90.535906 131.0 114.214151 100.8168 1 274 273 0.0092239 -1.1219211 1.2436063
HR..FIN* 9 5300 84.927925 14.275750 87.0 86.411557 14.8260 1 99 98 -2.2309927 9.7820520 0.1960925
ESTACION.ARRANQUE* 10 5300 128.931509 151.437504 43.5 107.197170 63.0105 1 480 479 0.8514809 -0.6492739 2.0801541
Laminas.procesadas* 11 5300 177.477170 247.368831 3.0 134.551179 2.9652 1 754 753 1.0927667 -0.3197660 3.3978722
INICIO.SEP.UP* 12 5300 171.862830 241.797486 2.0 128.451887 1.4826 1 748 747 1.1205817 -0.2259700 3.3213439
FIN.INICIO.DE.SEP.UP* 13 5300 279.906604 301.987843 206.0 245.659670 303.9330 1 886 885 0.6272972 -1.0548002 4.1481220
INICIO.de.PROCESO* 14 5300 284.753585 303.733582 223.0 248.791745 329.1372 1 905 904 0.6060365 -1.0362020 4.1721016
FIN.de.PROCESO* 15 5300 10.405283 14.371053 12.0 7.844104 0.0000 1 109 108 3.7375855 16.1045786 0.1974016
TIEMPO.CALIDAD 16 676 3.106509 7.406737 0.0 1.265683 0.0000 0 60 60 3.7767077 17.6210730 0.2848745
TIEMPO.MATERIALES* 17 5300 1.102453 0.682923 1.0 1.000000 0.0000 1 13 12 9.0669699 97.0207719 0.0093807
MERMAS.Maquinas. 18 24 2.208333 1.102533 2.0 2.150000 1.4826 1 4 3 0.3515919 -1.3010627 0.2250537

Esta tabla de frecuencia nos dice que en FORM el tiempo promedio que se tarda producción es de 10 minutos, que se programan al rededor de 28 piezas y al final se procesan 4.

Estadísticos descriptivos Scrap

# install.packages("psych")
library(psych)
describe(bd_scrap4) # Función que nos da datos descriptivos
##             vars   n mean    sd median trimmed  mad min  max range  skew
## Fecha          1 250  NaN    NA     NA     NaN   NA Inf -Inf  -Inf    NA
## Cantidad       2 250 6.70 11.85      2    3.88 1.48   0   96    96  4.12
## Ubi_origen*    3 250 2.48  0.85      3    2.60 0.00   1    3     2 -1.10
##             kurtosis   se
## Fecha             NA   NA
## Cantidad       21.14 0.75
## Ubi_origen*    -0.70 0.05
# Sacamos moda con otra función ya que en la función describe no nos la da
mode <- function (x) {
  ux <- unique(x)
  ux [which.max(tabulate(match(x,ux)))]
}

mode <- mode(bd_scrap4$Cantidad)
mode
## [1] 1
Variables <-c("Cantidad" )
Media <-c("6.70" )
Mediana <-c("2" )
Moda <- c("1")
Desviacion_estandar <-c("11.85" )
table1 <-data.frame(Variables, Media , Mediana , Moda, Desviacion_estandar)
knitr::kable(table1)
Variables Media Mediana Moda Desviacion_estandar
Cantidad 6.70 2 1 11.85

Esta tabla de frecuencia nos dice que en FORM las unidades de Scrap promedio son de 6.

Estadísticos descriptivos Merma

# install.packages("psych")
library(psych)
describe(bd_merma5) # Función que nos da datos descriptivos
##       vars  n    mean      sd median trimmed    mad min  max range  skew
## Fecha    1 50     NaN      NA     NA     NaN     NA Inf -Inf  -Inf    NA
## Kilos    2 50 3708.52 1023.99   3925 3798.65 541.15 790 6140  5350 -0.94
##       kurtosis     se
## Fecha       NA     NA
## Kilos     1.65 144.81
# Sacamos moda con otra función ya que en la función describe no nos la da
mode <- function (x) {
  ux <- unique(x)
  ux [which.max(tabulate(match(x,ux)))]
}

mode <- mode(bd_merma5$Kilos)
mode
## [1] 3810
Variables <-c("Kilos")
Media <-c("3709.52")
Mediana <-c("3925")
Moda <-c("3810")
Desviacion_estandar <-c("1023.99")
table2 <-data.frame(Variables, Media, Mediana, Moda, Desviacion_estandar)
knitr::kable(table2)
Variables Media Mediana Moda Desviacion_estandar
Kilos 3709.52 3925 3810 1023.99

Esta tabla de frecuencia nos dice que en FORM en promedio se tienen 3,708 kilos de merma.

Estadísticos descriptivos Delivery Performance

# install.packages("psych")
library(psych)
describe(bd_delivery_perf3) # Función que nos da datos descriptivos
##                   vars  n  mean    sd median trimmed  mad min   max range skew
## fecha                1 52   NaN    NA     NA     NaN   NA Inf  -Inf  -Inf   NA
## cliente*             2 52  2.50  1.13    2.5    2.50 1.48   1  4.00  3.00 0.00
## delay_performance    3 52 16.07 24.63    0.0   11.88 0.00   0 71.25 71.25 1.15
##                   kurtosis   se
## fecha                   NA   NA
## cliente*             -1.42 0.16
## delay_performance    -0.33 3.42
# Sacamos moda con otra función ya que en la función describe no nos la da
mode <- function (x) {
  ux <- unique(x)
  ux [which.max(tabulate(match(x,ux)))]
}

mode <- mode(bd_delivery_perf3$delay_performance)
mode
## [1] 0
Variables <-c("Diferencia Delivery")
Media <-c("16.07")
Mediana <-c("0")
Moda <- c("0")
Desviacion_estandar <-c("24.63")
table3 <-data.frame(Variables, Media, Mediana, Moda, Desviacion_estandar)
knitr::kable(table3)
Variables Media Mediana Moda Desviacion_estandar
Diferencia Delivery 16.07 0 0 24.63

Estadísticos descriptivos Delivery Plan

# install.packages("psych")
library(psych)
describe(dp1) # Función que nos da datos descriptivos
## Warning in FUN(newX[, i], ...): no non-missing arguments to min; returning Inf
## Warning in FUN(newX[, i], ...): no non-missing arguments to max; returning -Inf
##          vars   n    mean      sd median trimmed  mad min   max range skew
## ID_Fecha    1 228    6.50    3.46    6.5    6.50 4.45   1    12    11 0.00
## Fecha       2 228     NaN      NA     NA     NaN   NA Inf  -Inf  -Inf   NA
## CLIENTE*    3 228   10.00    5.49   10.0   10.00 7.41   1    19    18 0.00
## Pedidos     4 228 1703.14 6164.04    0.0  251.26 0.00   0 52779 52779 5.69
##          kurtosis     se
## ID_Fecha    -1.23   0.23
## Fecha          NA     NA
## CLIENTE*    -1.22   0.36
## Pedidos     37.14 408.22
# Sacamos moda con otra función ya que en la función describe no nos la da
mode <- function (x) {
  ux <- unique(x)
  ux [which.max(tabulate(match(x,ux)))]
}

mode <- mode(dp1$Pedidos)
mode
## [1] 0
Variables <-c("Diferencia Delivery")
Media <-c("1,703")
Mediana <-c("0")
Moda <- c("0")
Desviacion_estandar <-c("6,164.04")
table4 <-data.frame(Variables, Media, Mediana, Moda, Desviacion_estandar)
knitr::kable(table4)
Variables Media Mediana Moda Desviacion_estandar
Diferencia Delivery 1,703 0 0 6,164.04

Esta tabla de frecuencia nos dice que en FORM los números de pedidos estan en promedio 1,703.

Estadísticos descriptivos Base externa: Industria Automotriz USA

# install.packages("psych")
library(psych)
describe(bd_externa) # Función que nos da datos descriptivos
##                                vars  n     mean      sd   median  trimmed
## Year                              1 14  2013.50    4.18  2013.50  2013.50
## Total_Production                  2 14 10077.11 1880.71 10822.59 10265.83
## Production_Passenger_Cars         3 14  3326.39  823.81  3382.30  3356.35
## Production_Commercial_Vehicles    4 14  6750.72 1521.04  6890.84  6873.69
## Domestic_Sales                    5 14 11995.81 2018.16 12583.17 12162.17
## Sales_Passenger_Cars              6 14  4490.79  918.19  4541.92  4558.45
## Sales_Commercial_Vehicles         7 14  7505.02 1788.05  7634.25  7552.32
## US_Unemployment                   8 14     6.43    2.09     5.98     6.39
## US_Consumer_Confidence            9 14    82.29   11.93    82.84    82.50
## US_Min_Hour_Wage                 10 14     7.03    0.52     7.25     7.13
##                                    mad     min      max   range  skew kurtosis
## Year                              5.19 2007.00  2020.00   13.00  0.00    -1.46
## Total_Production               1573.18 5710.29 12179.30 6469.01 -0.83    -0.42
## Production_Passenger_Cars      1020.96 1924.40  4368.84 2444.44 -0.22    -1.58
## Production_Commercial_Vehicles 1824.38 3513.84  8512.03 4998.19 -0.58    -0.88
## Domestic_Sales                 1646.83 7867.77 14127.53 6259.76 -0.66    -1.03
## Sales_Passenger_Cars           1042.10 2559.78  5609.88 3050.10 -0.45    -0.97
## Sales_Commercial_Vehicles      2071.49 4309.48 10132.95 5823.47 -0.22    -1.37
## US_Unemployment                   2.75    3.68     9.61    5.93  0.18    -1.65
## US_Consumer_Confidence           15.64   63.75    98.37   34.62 -0.14    -1.54
## US_Min_Hour_Wage                  0.00    5.50     7.25    1.75 -1.97     2.56
##                                    se
## Year                             1.12
## Total_Production               502.64
## Production_Passenger_Cars      220.17
## Production_Commercial_Vehicles 406.52
## Domestic_Sales                 539.38
## Sales_Passenger_Cars           245.40
## Sales_Commercial_Vehicles      477.88
## US_Unemployment                  0.56
## US_Consumer_Confidence           3.19
## US_Min_Hour_Wage                 0.14
# Sacamos moda con otra función ya que en la función describe no nos la da
mode <- function (x) {
  ux <- unique(x)
  ux [which.max(tabulate(match(x,ux)))]
}

mode <- mode(bd_externa$Total_Production)
mode
## [1] 10752.31
Variable <-c("Producción total" )
Media <-c("10077.11" )
Mediana <-c("10822.59" )
Moda <- c("10752.31")
Desviacion_estandar <-c("1880.71" )
table <-data.frame(Variable, Media, Mediana, Moda, Desviacion_estandar)
knitr::kable(table)
Variable Media Mediana Moda Desviacion_estandar
Producción total 10077.11 10822.59 10752.31 1880.71

Bar plots

PRODUCCIÓN

barplot(prop.table(table(data6$Laminas.procesadas)),col=c("orange"),main="Laminas procesadas",xlab = "Laminas", ylab ="Frecuencias",las=1)

SCRAP

library(plyr)
porcentajes <- as.numeric(round(((prop.table(table(bd_scrap4$Ubi_origen)))*100),2))
etiquetas <- c("Calidad/Entrega de PT","Post-Producción","Pre-Producción")
etiquetas <- paste(etiquetas, porcentajes)
etiquetas <- paste(etiquetas, "%", sep = "")


pie(porcentajes,etiquetas,col=c("Red","Blue","Orange"),main="Ubicación de origen: Scrap", ylab ="Frecuencias",las=1)

DELIVERY PLAN: PRINCIPALES CLIENTES

Con la siguiente función podremos identificar los principales clientes para generar un análisis con la información relevante, pues hay clientes con pocos o sin pedidos por lo que generar un diagnóstico respecto a delivery plan con esos datos no es necesario.

ggplot(dp1, aes(x=reorder(CLIENTE,Pedidos), y=Pedidos)) +
  geom_bar(stat="identity")+
  coord_flip()

DELIVERY PLAN: TOP 6 CLIENTES Y PROMEDIO

Como siguiente paso eliminaremos todos los clientes que no nos interesan para el análisis y dejaremos el top 6 de clientes para el ejercicio.

dp2 <- dp1
dp2<-dp2[dp2$CLIENTE!="ABC QUERETARO",]
dp2<-dp2[dp2$CLIENTE!="ANTOLIN ARTEAGA",]  
dp2<-dp2[dp2$CLIENTE!="ANTOLIN TOLUCA",] 
dp2<-dp2[dp2$CLIENTE!="ISRI",] 
dp2<-dp2[dp2$CLIENTE!="SEGROVE",] 
dp2<-dp2[dp2$CLIENTE!="STB 1",] 
dp2<-dp2[dp2$CLIENTE!="UFI",] 
dp2<-dp2[dp2$CLIENTE!="YF QRO",] 
dp2<-dp2[dp2$CLIENTE!="INOAC POLYTEC",] 
dp2<-dp2[dp2$CLIENTE!="HANON",] 
dp2<-dp2[dp2$CLIENTE!="MERIDIAN",] 
dp2<-dp2[dp2$CLIENTE!="YF RAMOS",] 
dp2<-dp2[dp2$CLIENTE!="YANFENG sm",] 
ggplot(dp2,aes(x=Fecha, y=Pedidos,fill=CLIENTE))+
  geom_bar(stat="identity")+
  geom_hline(yintercept=33,linetype="dashed",color="black")+
  labs(x="Fecha",y="Número de pedidos", color="Legend")+
  ggtitle("Pedidos por fecha")

RECURSOS HUMANOS: COLABORADORES ACTUALES

# as.data.frame(bajas_bd)
# as.data.frame(colab_bd)
colab_bd2<-colab_bd %>% dplyr::select(genero,edad,salario_diario) %>%  dplyr::group_by(genero) %>%
  dplyr::summarise(across(everything(),mean,na.rm=TRUE)) %>% arrange(desc(edad))
ggplot(colab_bd2, aes(x=reorder(genero,edad), y=edad, fill=(salario_diario))) +
  geom_bar(stat="identity",col=c("black"))+
  coord_flip()+
  guides(fill=guide_legend(reverse=FALSE))

La primera gráfica de barras nos da a conocer sobre el salario diario de las personas de Form, segmentado por edad y por género. Lo que nos da a conocer es que en la empresa existe un mayor rango de edad entre las mujeres de Form, llegando a ser casi 40 lo mayor; por otra parte, los hombres presentan un menor rango, con un máximo de (aprox) 33. Igualmente, vemos que en promedio las mujeres ganan 60 centavos más que los hombres.
ggplot(colab_bd, aes(x=genero, y=salario_diario, fill=genero)) + 
  geom_bar(stat="identity") + 
  facet_grid(~civil) + scale_fill_brewer(palette = "Set2")

Esta segunda gráfica descriptiva de los actuales colaboradores de Form, nos comunica, principalmente, el estado civil de los colaboradores por género, y su ganancia. Lo que podemos notar es que en general, las mujeres ganan más en cualquier estado civil en el que se encuentren, y en donde se puede ver una mayor variedad de la suma de los salarios es en las mujeres y los hombres que se encuentran en unión libre.

RECURSOS HUMANOS: BAJAS

bajas_bd2<-bajas_bd %>% dplyr::select(motivo_baja,edad,duracion) %>% group_by(motivo_baja) %>%
  dplyr::summarise(across(everything(),mean,na.rm=TRUE)) %>% arrange(desc(edad))
ggplot(bajas_bd2, aes(x=reorder(motivo_baja,edad), y=edad, fill=(duracion))) +
  geom_bar(stat="identity",col=c("black"))+
  coord_flip()+
  guides(fill=guide_legend(reverse=FALSE))

Viendo ahora los colaboradores que han sido dados de baja en la empresa, vemos que la gran parte de los que se han salido de Form tienen menos de 30 años. Pocos casos han sido de jubilación, llegando a más de 60 en rango. Igualmente, a partir de la gráfica vemos que las razones principales son por abandono y baja por faltas; durando menos de 500 días en su trabajo.
ggplot(bajas_bd, aes(x=genero, y=salario_diario, fill=genero)) + 
  geom_bar(stat="identity") + 
  facet_grid(~e.civil.) + scale_fill_brewer(palette = "Set2")

Finalmente, observamos la última gráfica descriptiva de los colaboradores que han sido dados de baja por Form. En un caso observamos que no se conoce su situación de estado civil. Igualmente, observamos que la mayor cantidad (se asume por la suma de salario diario) han sido solteros, y una gran cantidad de mujeres casadas. Por lo tanto, podemos asumir a partir de los datos que la mayoría de los que abandonan su trabajo en Form son personas solteras.

Dispersion plots

PRODUCCIÓN

plot(data6$TMO..MIN., xlab = "Proceso de lamina", ylab = "Tiempo", main = "Tiempo por Lamina" )

MERMA

ggplot(bd_merma5, aes(x= Fecha, y= Kilos)) + geom_bar(stat="identity", fill="red") + scale_fill_grey() + labs(title = "Kilos de merma", x = "Fecha")

Podemos ver como en inicios de Febrero a Abril tenemos la mayor cantidad de kilos de merma, que incluso pasa del promedio de los demas meses, por lo que es importante analizar que factor hizo que durante ese periodo hubiera más merma.
bd_merma5$Fecha <- as.Date(bd_merma5$Fecha, format = "%d/%m/%Y")
plot(bd_merma5$Fecha, bd_merma5$Kilos, main = "Kilos de merma",
     xlab = "Fecha", ylab = "Kilos",
     pch = 19, frame = FALSE)

Podemos ver como hay mas dispersión en septiembre, los demás meses ha tenido en promedio la misma cantidad de merma.

SCRAP

hist(bd_scrap4$Cantidad, main = "Cantidad de Material reciclado", xlab = "Cantidad", ylab = "Frecuencia",col = "blue")

Este histograma nos muestra que entre 0 a 10 Toneladas es lo que mas se frecuenta a reciclar el material.
plot(bd_scrap4$Fecha, bd_scrap4$Cantidad, main = "Cantidad de Scrap por fecha", xlab = "Fecha", ylab = "Cantidad")

Podemos ver que hay ciertos días que salen fuera del promedio (que es alrededor de 0-20Toneladas) que se tiene de la cantidad de Scrap.

DELIVERY PLAN

Pedidos

plot(dp2$Fecha, dp2$Pedidos, main = "Pedidos por fecha",
     xlab = "Fecha", ylab = "Pedidos",
     pch = 1, frame = FALSE)

boxplot(dp2$Pedidos, main = "Pedidos")

Como primer boxplot vimos los pedidos y la gran dispersión que hay entre pedidos, pues detectamos una frecuencia en donde hay clientes que generan pedidos obviamente diferentes como para tener una mediana o una dispersión positiva.

Clientes

Después de generar un boxplot de pedidos en general, realizamos un boxplot que nos muestra los pedidos por cliente

dp3 <- dp2
dp3$CLIENTE<-as.factor(dp3$CLIENTE)
ggplot(dp3, aes(x=CLIENTE, y=Pedidos)) + 
  geom_boxplot(color="red", fill="orange", alpha=0.2)

En el gráfico anterior podemos observar a los 6 clientes con mayor presencia en FORM en cuanto a Delivery Plan en donde el objetivo es ver la dispersión y la distribución entre cada uno y respecto a los pronósticos individuales.
El cliente HELLA es el cliente con una mayor distribución y dispersión y una mediana que genera una desviación estándar positiva. Varroc y TRMX tienen también una distribución mayor al tener la boxplot más grande, mientras que los demás; DENSO, STB3 y YFTO tienen la mayoría de sus pedidos en un mismo rango con pequeños datos fuera del boxplot presentando algunos warnings.
Se puede concluir, que HELLA es el cliente más fuerte en dicha base de datos para la empresa.

Time series plots

DISTRIBUCIÓN

ggplot(bd_delivery_perf3,aes(x=fecha, y=delay_performance,color=cliente))+
  geom_line()+
  labs(x="Fecha",y="Retraso en Minutos", color="Legend")+
  ggtitle("Retrasos en el desempeño por parte del cliente")

bd_delivery_perf3<-bd_delivery_perf3[bd_delivery_perf3$cliente!="Magna",]
bd_delivery_perf3<-bd_delivery_perf3[bd_delivery_perf3$cliente!="Varroc",]

ggplot(bd_delivery_perf3,aes(x=fecha, y=delay_performance,fill=cliente))+
  geom_bar(stat="identity")+
  geom_hline(yintercept=33,linetype="dashed",color="black")+
  labs(x="Fecha",y="Retraso en minutos", color="Legend")+
  ggtitle("Retrasos en el desempeño por parte del cliente")

A pesar de que esta diminutendo el retraso con el cliente Mahle seguimos viendo que se encuentra por arriba del promedio.

Hallazgos

  1. Nuestro top 3 clientes de producción son STABILUS 1, STABILUS 3 y TRMX.

  2. Traemos un retraso mayor en distribución con el cliente Mahle, arriba del promedio llegando incluso a tiempos de 1 hora con 40 minutos.

  3. Se tienen sobrepedidos (arriba del promedio) y esto puede afectar si no se tienen la capacidad para recibir pedidos de más.

  4. Dentro de RH tenemos más bajas por distintos motivos: en primer lugar esta por Jubilación, en segundo lugar Renuncia voluntaria y en tercer lugar Baja por Faltas.

Predicción del Desempeño de la Industria Automotriz

Industria Automotriz USA

Se cambian los nombres de las columnas.

names (base) = c("año", "prod_total", "prod_passenger", "prod_veh_comerciales", "ventas_domesticas", "ventas_passenger","ventas_comerciales","desempleo_usa","confianza_cons_usa","salario_hora_min_usa")
names (base)
##  [1] "año"                  "prod_total"           "prod_passenger"      
##  [4] "prod_veh_comerciales" "ventas_domesticas"    "ventas_passenger"    
##  [7] "ventas_comerciales"   "desempleo_usa"        "confianza_cons_usa"  
## [10] "salario_hora_min_usa"
str(base)
## 'data.frame':    14 obs. of  10 variables:
##  $ año                 : int  2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 ...
##  $ prod_total          : num  10752 8672 5710 7744 8662 ...
##  $ prod_passenger      : num  3867 3731 2196 2732 2978 ...
##  $ prod_veh_comerciales: num  6885 4941 3514 5012 5685 ...
##  $ ventas_domesticas   : num  12687 10108 7868 9020 10109 ...
##  $ ventas_passenger    : num  5197 4491 3558 3792 4146 ...
##  $ ventas_comerciales  : num  7490 5617 4309 5229 5963 ...
##  $ desempleo_usa       : num  4.62 5.8 9.28 9.61 8.93 8.08 7.36 6.16 5.28 4.88 ...
##  $ confianza_cons_usa  : num  85.6 63.8 66.3 71.8 67.3 ...
##  $ salario_hora_min_usa: num  5.5 6.2 6.9 7.25 7.25 7.25 7.25 7.25 7.25 7.25 ...

Primer modelo de regresión

En este caso, se escoge como variable dependiente las ventas de los carros passenger, por ello entiéndase los automóviles de uso cotidiano en Estados Unidos. Para esta variable dependiente, se han tomado las siguientes variables independientes, con el fin de notar su efecto en las ventas. Estas son:

  1. Desempleo USA: este índice es calculado anualmente con la formula. (Unemployed ÷ Labor Force) x 100. Entre menor mejor.

  2. Confianza del consumidor de USA: índice que mide, a partir de una encuesta que tan optimistas o pesimistas se encuentran los consumidores sobre su situación financiera. Entre mayor, mejor.

  3. Salario mínimo por hora: se mide en dólares. Está establecido a nivel federal.

  4. Año: los años que se tienen de los datos, 2007-2020.

regresion1 <- lm (ventas_passenger ~ desempleo_usa + confianza_cons_usa + salario_hora_min_usa + año, data=base)
summary (regresion1)
## 
## Call:
## lm(formula = ventas_passenger ~ desempleo_usa + confianza_cons_usa + 
##     salario_hora_min_usa + año, data = base)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -850.29 -560.86   88.28  446.55  847.47 
## 
## Coefficients:
##                       Estimate Std. Error t value Pr(>|t|)   
## (Intercept)          646180.04  197959.50   3.264  0.00977 **
## desempleo_usa          -255.04     217.62  -1.172  0.27129   
## confianza_cons_usa       46.68      41.57   1.123  0.29062   
## salario_hora_min_usa   1394.06     697.08   2.000  0.07657 . 
## año                    -324.65     100.49  -3.231  0.01031 * 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 712.5 on 9 degrees of freedom
## Multiple R-squared:  0.5831, Adjusted R-squared:  0.3978 
## F-statistic: 3.147 on 4 and 9 DF,  p-value: 0.0707

Para la tasa de desempleo y el índice de confianza del consumidor, se ha decidido tomar el promedio del 2007 al 2020, para poder predecir. Con el salario mínimo por hora, al ser establecido a nivel federal, se toma en cuenta la última cantidad: $7.25 dólares. Se quieren las predicciones para los siguientes cinco años, a partir del último año con datos (2020).

datos_nuevos1 <- data.frame(desempleo_usa=6.43,confianza_cons_usa=82.3,salario_hora_min_usa=7.25,año=2021:2025)
predict(regresion1,datos_nuevos1)
##        1        2        3        4        5 
## 2369.905 2045.254 1720.604 1395.954 1071.303

¿Qué observamos?

primer <- plot(predict(regresion1,datos_nuevos1), type = "l", xlab = "Año",  ylab ="Ventas Passenger",  main="Predicción de Ventas")

En esta predicción de ventas de automóviles passenger, observamos que es hacia abajo. Es decir, tomando en cuenta una tasa de desempleo de 6.43, un índice de confianza de 82.3 y el salario mínimo por hora de $7.25, se espera que las ventas de estos automóviles bajen en EUA del 2021 hasta 2025. Igualmente, resulta destacable mencionar que las variables que más impactan en las ventas de automóviles passenger son el año y el salario mínimo.

effect_plot(regresion1,pred=desempleo_usa,interval=TRUE)

Si tomamos en cuenta la tasa de desempleo de EUA, y su relación con las ventas de los automóviles passenger, observamos que esta es negativa. Debido a que al crecer la tasa de desempleo, bajan las ventas.

effect_plot(regresion1,pred=confianza_cons_usa,interval=TRUE)

Mientras que el índice de confianza del consumidor de EUA, y su relación con las ventas de los automóviles passenger, observamos que esta es positiva. Debido a que al crecer la confianza, incrementan las ventas.

effect_plot(regresion1,pred=salario_hora_min_usa,interval=TRUE)

Igualmente, al subir el salario mínimo por hora, las ventas de los automóviles passenger incrementan.

effect_plot(regresion1,pred=año,interval=TRUE)

Con el pasar de los años las ventas han decrecido.

Segundo modelo de regresión

En este caso, se escoge como variable dependiente las ventas de los carros comerciales, por ello entiéndase los cualquier tipo de vehículo de motor utilizado para transportar mercancías o pasajeros en Estados Unidos. Para esta variable dependiente, se han tomado las siguientes variables independientes, con el fin de notar su efecto en las ventas. Estas son:
1. Desempleo USA: este índice es calculado anualmente con la formula. (Unemployed ÷ Labor Force) x 100. Entre menor mejor.
2. Confianza del consumidor de USA: índice que mide, a partir de una encuesta que tan optimistas o pesimistas se encuentran los consumidores sobre su situación financiera. Entre mayor, mejor.
3. Salario mínimo por hora: se mide en dólares. Está establecido a nivel federal.
4. Año: los años que se tienen de los datos, 2007-2020.

regresion2 <- lm (ventas_comerciales ~ desempleo_usa + confianza_cons_usa + salario_hora_min_usa + año, data=base)
summary (regresion2)
## 
## Call:
## lm(formula = ventas_comerciales ~ desempleo_usa + confianza_cons_usa + 
##     salario_hora_min_usa + año, data = base)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -731.58  -87.12   57.56  160.03  513.82 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)    
## (Intercept)          -588817.41   97672.75  -6.028 0.000196 ***
## desempleo_usa           -147.24     107.37  -1.371 0.203504    
## confianza_cons_usa        50.55      20.51   2.464 0.035896 *  
## salario_hora_min_usa    -839.15     343.94  -2.440 0.037374 *  
## año                      297.49      49.58   6.000 0.000203 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 351.6 on 9 degrees of freedom
## Multiple R-squared:  0.9732, Adjusted R-squared:  0.9613 
## F-statistic: 81.82 on 4 and 9 DF,  p-value: 4.516e-07

Para la tasa de desempleo y el índice de confianza del consumidor, se ha decidido tomar el promedio del 2007 al 2020, para poder predecir. Con el salario mínimo por hora, al ser establecido a nivel federal, se toma en cuenta la última cantidad: $7.25 dólares. Se quieren las predicciones para los siguientes cinco años, a partir del último año con datos (2020).

datos_nuevos2 <- data.frame(desempleo_usa=6.43,confianza_cons_usa=82.3,salario_hora_min_usa=7.25,año=2021:2025)
predict(regresion2,datos_nuevos2)
##         1         2         3         4         5 
##  9547.780  9845.274 10142.768 10440.262 10737.756

¿Qué observamos?

segundo <- plot(predict(regresion2,datos_nuevos2), type = "l", xlab = "Año",  ylab ="Ventas Comerciales",  main="Predicción de Ventas")

En esta predicción de ventas de automóviles comerciales, observamos que es hacia arriba Es decir, tomando en cuenta una tasa de desempleo de 6.43, un índice de confianza de 82.3 y el salario mínimo por hora de $7.25, se espera que las ventas de estos automóviles suban en EUA del 2021 hasta 2025. En el caso de las ventas de automóviles comerciales, notamos que el pasar de los años es la variable que más impacta, siguiendo por el nivel de confianza del consumidor y el salario mínimo por hora; mientras que el que menos afecta es la tasa de desempleo.

effect_plot(regresion2,pred=desempleo_usa,interval=TRUE)

Si tomamos en cuenta la tasa de desempleo de EUA, y su relación con las ventas de los automóviles comerciales, observamos que esta es negativa. Debido a que al crecer la tasa de desempleo, bajan las ventas.

effect_plot(regresion2,pred=confianza_cons_usa,interval=TRUE)

Mientras que el índice de confianza del consumidor de EUA, y su relación con las ventas de los automóviles comerciales, observamos que esta es positiva. Debido a que al crecer la confianza, incrementan las ventas. A comparación de la gráfica de ventas passenger con el nivel de confianza, observamos que en este caso la pendiente es más pronunciada, por lo que vemos un mayor impacto.

effect_plot(regresion2,pred=salario_hora_min_usa,interval=TRUE)

Igualmente, al subir el salario mínimo por hora, las ventas de los automóviles comerciales disminuyen. Este podría ser un tema interesante a investigar.

effect_plot(regresion2,pred=año,interval=TRUE)

Con el pasar de los años las ventas han incrementado.

Industria Automotriz México

Primer modelo de regresión

Nuestra variable dependiente sera unidades de producción y las variables explanatorias en este caso serían unidades de exportacion y año.

mx_regresion1 <- lm (unidades_produccion ~ unidades_exportacion + año, data=bd_externaMX)
summary (mx_regresion1)
## 
## Call:
## lm(formula = unidades_produccion ~ unidades_exportacion + año, 
##     data = bd_externaMX)
## 
## Residuals:
##      1      2      3      4      5 
##  32786 -40083  15888 -42671  34080 
## 
## Coefficients:
##                        Estimate Std. Error t value Pr(>|t|)  
## (Intercept)           2.228e+08  5.666e+07   3.933   0.0590 .
## unidades_exportacion  8.527e-01  1.180e-01   7.223   0.0186 *
## año                  -1.099e+05  2.792e+04  -3.937   0.0589 .
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 54390 on 2 degrees of freedom
## Multiple R-squared:  0.9933, Adjusted R-squared:  0.9866 
## F-statistic: 148.2 on 2 and 2 DF,  p-value: 0.006703

Como resultado de la regresión podemos ver que existe una significancia de 0.05 con la variable de exportación en unidades vehiculares y lo que nos dice el modelo esque si aumenta la exportación aumenta la producción, pero después podemos ver que en año hay una tendencia negativa diciéndonos que decrecen las ventas con el año. El modelo tiene una R² de 0.98 teniendo un buen nivel de confianza.

Ahora graficaremos nuestra regresión, para las unidades de exportación se ha decidido tomar el media del 2017 al 2021 (3,096,421). Se quieren las predicciones para los siguientes cinco años, a partir del último año con datos (2021).

datos_nuevos1 <- data.frame(unidades_exportacion=3096421,año=2022:2026)
predict(mx_regresion1,datos_nuevos1)
##       1       2       3       4       5 
## 3216556 3106643 2996729 2886816 2776902

¿Qué observamos?

prediccionmx1 <- plot(predict(mx_regresion1,datos_nuevos1), type = "l", xlab = "Año",  ylab ="Exportaciones",  main="Predicción de Exportaciones")

En esta predicción exportaciones de automoviles, observamos que es hacia abajo. Es decir, se espera que las exportaciones de los automóviles bajen en México del 2022 hasta 2026.

Segundo modelo de regresión

mx_regresion2 <- lm (unidades_ventas ~ desempleo + año, data=bd_externaMX)
summary (mx_regresion2)
## 
## Call:
## lm(formula = unidades_ventas ~ desempleo + año, data = bd_externaMX)
## 
## Residuals:
##      1      2      3      4      5 
##  25338 -28279  -1471 -13570  17983 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)  
## (Intercept) 163028739   32739329   4.980   0.0380 *
## desempleo     -281802      50603  -5.569   0.0308 *
## año            -79602      16291  -4.886   0.0394 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 31240 on 2 degrees of freedom
## Multiple R-squared:  0.9926, Adjusted R-squared:  0.9851 
## F-statistic: 133.5 on 2 and 2 DF,  p-value: 0.007435

Como resultado de la regresión podemos ver que existe una significancia de 0.05 con la variable desempleo y año, teniendo una tendencia negativa en ambas, lo que quiere decir que si disminuye el desempleo aumentan las ventas y que con el paso de los años las ventas aumentan El modelo tiene una R² de 0.98 teniendo un buen nivel de confianza.

Ahora graficaremos nuestra regresión, para desempleo se ha decidido tomar la media del 2017 al 2021 (3.77). Se quieren las predicciones para los siguientes cinco años, a partir del último año con datos (2021).

datos_nuevos2 <- data.frame(desempleo=3.77, año=2022:2026)
predict(mx_regresion2,datos_nuevos2)
##         1         2         3         4         5 
## 1010144.2  930541.7  850939.2  771336.8  691734.3

¿Qué observamos?

prediccionmx2 <- plot(predict(mx_regresion2,datos_nuevos2), type = "l", xlab = "Año",  ylab ="Ventas",  main="Predicción de Ventas")

Con el modelo podemos ver como tenemos la tendencia negativa decreciendo las ventas.

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

Pronóstico Industria Automotriz USA

plot(bd_externa$Year,bd_externa$Production_Commercial_Vehicles, type="l",col="blue", lwd=1.5, xlab ="Year",ylab ="Thousands of Units", main = "Annual U.S. Motor Vehicle Sales")
lines(bd_externa$Year,bd_externa$Sales_Commercial_Vehicles,col="red",lty=3)
legend("topleft", legend=c("Domestic Commercial Sales", "Production Commercial Vehicles"),
       col=c("blue", "red"), lty = 1:2, cex=0.8)

Pronóstico Moving Average

summary(ma_model<-arma(bd_externa$Total_Production,order=c(0,1)))
## 
## Call:
## arma(x = bd_externa$Total_Production, order = c(0, 1))
## 
## Model:
## ARMA(0,1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3425.7 -1313.0   141.6  1100.1  1449.5 
## 
## Coefficient(s):
##            Estimate  Std. Error  t value Pr(>|t|)    
## ma1       6.756e-01   1.610e-01    4.195 2.73e-05 ***
## intercept 1.010e+04   6.096e+02   16.569  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Fit:
## sigma^2 estimated as 2094390,  Conditional Sum-of-Squares = 25229390,  AIC = 247.5
ma_model_forecast<-forecast(ma_model$fitted,h=3,level=c(95))
ma_model_forecast
##    Point Forecast    Lo 95    Hi 95
## 15       10455.67 8568.350 12342.99
## 16       10455.67 8438.084 12473.26
## 17       10455.67 8315.732 12595.61

Pronóstico Industria Automotriz México

plot(bd_externaMX$año,bd_externaMX$unidades_ventas, type="l",col="blue", lwd=1.5, xlab ="Año",ylab ="Millones de ventas", main = "Ventas anuales")
lines(bd_externaMX$año,bd_externaMX$unidades_ventas,col="red",lty=3)

ma_model<- bd_externaMX
ma_model_forecast<-forecast(ma_model$unidades_ventas,h=3,level=c(95))
ma_model_forecast
##   Point Forecast    Lo 95     Hi 95
## 6         887801 675739.5 1099862.5
## 7         779944 567882.5  992005.5
## 8         672087 460025.5  884148.5

Podemos ver que en la industria Automotriz de MX, específicamente en ventas de motores, tenemos una tendencia en decrecimieto y que nuestros intervalos de confianza van disminuyendo, pero las predicciones se encuentran entre 887801-672087 de ventas anuales de motores en MX para los próximos años.

Pronóstico Producción FORM

plot(data6$Fecha,data6$PIEZAS.PROG., type="l",col="blue", lwd=1.5, xlab ="Fecha",ylab ="Piezas programadas", main = "Piezas programadas por fecha")
lines(data6$Fecha,data6$Laminas.procesadas,col="red",lty=3)
legend("topleft", legend=c("Piezas programadas", "Laminas procesadas"),
       col=c("blue", "red"), lty = 1:2, cex=0.8)

(ma_model<-arma(data6$PIEZAS.PROG.,order=c(0,1)))
## 
## Call:
## arma(x = data6$PIEZAS.PROG., order = c(0, 1))
## 
## Coefficient(s):
##       ma1  intercept  
##     0.441     28.180
ma_model_forecast<-forecast(ma_model$fitted,h=3,level=c(95))
ma_model_forecast
##      Point Forecast    Lo 95    Hi 95
## 5301       25.55237 3.086481 48.01827
## 5302       25.41480 2.928867 47.90072
## 5303       25.30473 2.782038 47.82743

Pronóstico Delivery Plan FORM

plot(dp1$Fecha,dp1$Pedidos, type="l",col="blue", lwd=1.5, xlab ="Fecha",ylab ="Piezas programadas", main = "Piezas programadas por fecha")
lines(dp1$Fecha,dp1$CLIENTE,col="red",lty=3)
legend("topleft", legend=c("Piezas programadas", "Laminas procesadas"),
       col=c("blue", "red"), lty = 1:2, cex=0.8)

# Sumar el Total de PedidosxMes
pedidos <- c(18789,23932,52553,44100,37800,64279,42705,66060,11200)

pedidos_st <- ts(data = pedidos, start = c(2022,1), frequency = 12)
pedidos_st
##        Jan   Feb   Mar   Apr   May   Jun   Jul   Aug   Sep
## 2022 18789 23932 52553 44100 37800 64279 42705 66060 11200
modelo <- auto.arima(pedidos_st)
modelo
## Series: pedidos_st 
## ARIMA(0,0,0) with non-zero mean 
## 
## Coefficients:
##            mean
##       40157.556
## s.e.   6078.173
## 
## sigma^2 = 374055251:  log likelihood = -101.07
## AIC=206.14   AICc=208.14   BIC=206.53
pronostico <- forecast(modelo, level=c(95), h=3)
pronostico
##          Point Forecast    Lo 95    Hi 95
## Oct 2022       40157.56 2250.856 78064.25
## Nov 2022       40157.56 2250.856 78064.25
## Dec 2022       40157.56 2250.856 78064.25
plot(pronostico)

Pronóstico Merma FORM

# Sumar el Total de KilosxMes
merma <- c(14560,22830,22470,18820,23410,18280,19370,32100,13586)

merma_st <- ts(data = merma, start = c(2022,1), frequency = 12)
merma_st
##        Jan   Feb   Mar   Apr   May   Jun   Jul   Aug   Sep
## 2022 14560 22830 22470 18820 23410 18280 19370 32100 13586
modelo <- auto.arima(merma_st)
modelo
## Series: merma_st 
## ARIMA(0,0,0) with non-zero mean 
## 
## Coefficients:
##            mean
##       20602.889
## s.e.   1736.893
## 
## sigma^2 = 30544665:  log likelihood = -89.8
## AIC=183.59   AICc=185.59   BIC=183.99
pronostico <- forecast(modelo, level=c(95), h=3)
pronostico
##          Point Forecast    Lo 95    Hi 95
## Oct 2022       20602.89 9770.711 31435.07
## Nov 2022       20602.89 9770.711 31435.07
## Dec 2022       20602.89 9770.711 31435.07
plot(pronostico)

Resultados: ¿Cuál es la tendencia?

Podemos ver que en la industria Automotriz de USA, específicamente en ventas de motores, tenemos una tendencia continua y que nuestros intervalos de confianza ban disminuyendo, pero las predicciones se encuentran entre 8315.732-12595.61 de ventas anuales de motores en USA para los próximos años.

Para Form al desarrollar el pronóstico de Merma vemos que tenemos que para los próximos periodos de octubre, noviembre y diciembre tendremos una cantidad constante de 20602.89 kilos de merma y que nuestro intervalo de confianza cae entre 9770.711 a 31435.07.Interpretando la información vemos que a comparación del último mes de septiembre, los kilos crecerán.

Definición segmentos: K-Means Clustering

Definición de conceptos.

1. K - means Clustering
K-means es un método de agrupamiento, que tiene como objetivo la partición de un conjunto de observaciones en k grupos en el que cada observación pertenece al grupo cuyo valor medio es más cercano. De esta manera es que se puede analizar cada Cluster, obteniendo información importante de cada variable y las similitudes entre ellas. Un claro ejemplo de cómo funciona es usar clustering para comprimir imágenes con pérdida de información y/o comprender qué hace a los clientes diferentes para poder ofrecerles los productos y servicios que necesiten.

2. Unsupervised Learning
El “Unsupervised Learning” utiliza algoritmos de aprendizaje automático para analizar y agrupar conjuntos de datos sin etiquetar. Estos algoritmos descubren patrones ocultos o agrupaciones de datos sin necesidad de intervención humana. No se asignan etiquetas al algoritmo de aprendizaje, dejándolo solo para encontrar la estructura en su entrada. El Unsupervised Learning puede ser un objetivo en sí mismo (descubrir patrones ocultos en los datos) o un medio para lograr un fin (aprendizaje de funciones).

3. Distancia Euclidiana / Euclidean Distance
La distancia euclidiana se define como la distancia entre dos puntos. La distancia euclidiana entre dos puntos en el espacio euclidiano se define como la longitud del segmento de línea entre dos puntos. La herramienta Distancia euclidiana se utiliza con frecuencia como una herramienta independiente para aplicaciones, como encontrar el hospital más cercano para un vuelo de emergencia en helicóptero. Alternativamente, esta herramienta se puede usar al crear un mapa de idoneidad, cuando se necesitan datos que representan la distancia desde un objeto determinado.

Primer punto: Generar Clusters.

Descargar librerías

library(foreign)
library(dplyr)        # data manipulation 
library(ggplot2)      # data visualization 
#install.packages("psych")
library(psych)        # functions for multivariate analysis 
library(corrplot)     # correlation plots
library(jtools)       # presentation of regression analysis 
library(lmtest)       # diagnostic checks - linear regression analysis 
library(car)          # diagnostic checks - linear regression analysis
library(factoextra)   # provides functions to extract and visualize the output of exploratory multivariate data analyses
#install.packages("ggfortify")
library(ggfortify)    # data visualization tools for statistical analysis results
library(ggalluvial)

Se importa la base de datos de BAJAS ya limpia.

#file.choose()
bajas<-read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/ClustersBajasFORM.csv")
summary(bajas)
##     nombre               edad          duracion       salario_diario 
##  Length:233         Min.   :18.00   Min.   :   0.00   Min.   :144.4  
##  Class :character   1st Qu.:23.00   1st Qu.:   9.00   1st Qu.:180.7  
##  Mode  :character   Median :29.00   Median :  20.50   Median :180.7  
##                     Mean   :30.77   Mean   :  75.59   Mean   :177.9  
##                     3rd Qu.:37.00   3rd Qu.:  47.00   3rd Qu.:180.7  
##                     Max.   :61.00   Max.   :1966.00   Max.   :500.0  
##     estado            e.civil.            genero              alta          
##  Length:233         Length:233         Length:233         Length:233        
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##  motivo_baja           puesto         
##  Length:233         Length:233        
##  Class :character   Class :character  
##  Mode  :character   Mode  :character  
##                                       
##                                       
## 

¿Cuántos NA tengo por variables?

sapply(bajas,function(x) sum(is.na(x)))
##         nombre           edad       duracion salario_diario         estado 
##              0              0              0              0              0 
##       e.civil.         genero           alta    motivo_baja         puesto 
##              0              0              0              0              0

1. Edad y duración - 4 Clusters

bajas_new<-bajas
bajas_new<-subset(bajas_new,select = -c(alta,estado,nombre))
summary(bajas_new)
##       edad          duracion       salario_diario    e.civil.        
##  Min.   :18.00   Min.   :   0.00   Min.   :144.4   Length:233        
##  1st Qu.:23.00   1st Qu.:   9.00   1st Qu.:180.7   Class :character  
##  Median :29.00   Median :  20.50   Median :180.7   Mode  :character  
##  Mean   :30.77   Mean   :  75.59   Mean   :177.9                     
##  3rd Qu.:37.00   3rd Qu.:  47.00   3rd Qu.:180.7                     
##  Max.   :61.00   Max.   :1966.00   Max.   :500.0                     
##     genero          motivo_baja           puesto         
##  Length:233         Length:233         Length:233        
##  Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character  
##                                                          
##                                                          
## 

Se toman en cuenta la edad y la duración dentro de la empresa.

bajas_edaddur_norm<-scale(bajas_new[1:2]) 
fviz_nbclust(bajas_edaddur_norm, kmeans, method="wss")+ 
  geom_vline(xintercept=4, linetype=2)+         
  labs(subtitle = "Elbow method")  

Se toman en cuenta, primeramente, solo 4 clusters.

edad_cluster1<-kmeans(bajas_edaddur_norm,4)
edad_cluster1
## K-means clustering with 4 clusters of sizes 44, 4, 77, 108
## 
## Cluster means:
##         edad    duracion
## 1  1.6018961 -0.08724706
## 2  1.0813717  6.65505218
## 3  0.2101465 -0.10444505
## 4 -0.8425018 -0.13647287
## 
## Clustering vector:
##   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20 
##   3   3   4   4   3   1   3   3   1   4   4   3   4   3   3   4   4   4   4   4 
##  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40 
##   3   2   4   3   1   4   3   4   4   4   3   4   4   4   3   4   4   3   3   4 
##  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60 
##   4   3   4   4   4   4   4   4   1   1   1   2   4   1   4   4   1   4   4   4 
##  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80 
##   4   4   3   4   4   1   4   1   4   4   4   4   3   4   3   4   3   4   4   1 
##  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99 100 
##   2   3   1   4   4   4   1   4   4   4   3   1   1   4   4   3   1   3   4   3 
## 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 
##   4   4   1   3   4   4   3   2   3   4   3   3   4   3   3   3   1   1   1   4 
## 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 
##   4   4   4   4   3   4   3   1   4   3   4   1   4   3   4   3   1   3   1   3 
## 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 
##   3   1   1   1   4   3   3   3   4   4   4   3   1   1   4   3   4   3   1   1 
## 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 
##   1   1   3   1   4   4   3   4   4   1   3   1   4   1   3   3   1   3   3   4 
## 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 
##   4   4   3   1   3   3   4   4   3   3   3   3   3   3   4   3   3   3   3   4 
## 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 
##   3   1   3   4   4   4   1   4   4   4   3   3   4   4   3   3   3   1   4   4 
## 221 222 223 224 225 226 227 228 229 230 231 232 233 
##   3   4   4   4   3   1   3   1   4   4   4   4   4 
## 
## Within cluster sum of squares by cluster:
## [1] 20.68423 15.74846 31.40781 18.16981
##  (between_SS / total_SS =  81.5 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"
fviz_cluster(edad_cluster1,data=bajas_edaddur_norm)

Al observar vemos cuatro clusters que toman en cuenta la edad y la duración:
1. El rojo (será llamado “Senior”) es un cluster que observamos que son personas de edad mediana-alta y que durán relativamente poco tiempo, entran dentro del 25% con menor duración.
2. El verde (“Expert”) es el cluster que más se aparta de los demás; son personas con un mayor rango de edad pero que se alejan de los más jóvenes, y que han durado mucho má tiempo. Se encuentran en el 50% superior del tiempo de duración.
3. El azul (“junior”) resulta el cluster intermedio de los de menor duración. Son personas en un rango de edad medio que también son parte del 25% inferior que más han durado.
4. El morado (“beginner”) es el segmento más joven y que de las personas (en general) menos han durado. Se puede considerar que los jóvenes son los que menos duran en Form a partir de este cluster.

bajas_new2<-bajas_new
bajas_new2$Clusters<-edad_cluster1$cluster
bajas_new3<-bajas_new2 %>% group_by(Clusters) %>% dplyr:: summarise(edad=max(edad)) %>% arrange(desc(edad))
bajas_new2$Cluster_Names<-factor(bajas_new2$Clusters,levels = c(1,2,3,4), 
                              labels=c("Senior", "Expert", "Junior", "Beginner"))
bajas_new4 <- bajas_new2 %>% group_by(Cluster_Names) %>% dplyr::summarise(edad_años=max(edad), 
duracion=mean(duracion),
Count=n())
clusters<-as.data.frame(bajas_new4)
clusters
##   Cluster_Names edad_años   duracion Count
## 1        Senior        57   56.78409    44
## 2        Expert        61 1509.75000     4
## 3        Junior        39   53.07792    77
## 4      Beginner        27   46.17593   108

A partir de la tabla, observamos las edades máximas encontradas en cada clúster. Conocemos que la persona con mayor edad en los expert tiene 61, en senior tiene 57, en junior tiene 39 y en beginnner 27.

Igualmente, vemos la duración máxima que ha durado alguien de cada cluster, comparamos el máximo del mayor, expert, que han sido más de 1,500 días, con el máximo del menor, beginner, que han sido 46 días.

ggplot(bajas_new4,aes(x=reorder(Cluster_Names,Count),y=Count,fill=Cluster_Names)) +
  geom_bar(stat="identity")

Existe una mayor cantidad de “beginners”.

ggplot(bajas_new4, aes(x=Cluster_Names,y=edad_años,fill= Cluster_Names,label=round(edad_años,digits=2))) + 
  geom_col() + 
  geom_text()

Comparamos la edad máxima en cada clúster (descrito anteriormente).

ggplot(bajas_new4,aes(x=Cluster_Names,y=duracion,fill= Cluster_Names,label=round(duracion,digits=2))) + 
  geom_col() + 
  geom_text()

Comparamos los días máximos en cada clúster (descrito anteriormente).

2. Edad y duración - 5 Clusters

Debido a quee una gráfica anterior indicaba la posibilidad de tener otro clúster que describa a otro grupo, hacemos lo mismo con 5 segmentos, en vez de 4.

bajas_edaddur_norm2<-scale(bajas_new[1:2]) 
fviz_nbclust(bajas_edaddur_norm2, kmeans, method="wss")+ 
  geom_vline(xintercept=4, linetype=2)+         
  labs(subtitle = "Elbow method")  

edad_cluster2<-kmeans(bajas_edaddur_norm,5)
edad_cluster2
## K-means clustering with 5 clusters of sizes 42, 4, 71, 8, 108
## 
## Cluster means:
##         edad   duracion
## 1  1.5984349 -0.1859579
## 2  1.0813717  6.6550522
## 3  0.2360562 -0.2410113
## 4  0.2818274  1.9125942
## 5 -0.8377255 -0.1573975
## 
## Clustering vector:
##   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20 
##   4   3   5   5   3   1   3   3   1   5   5   3   5   3   4   5   5   5   5   5 
##  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40 
##   3   2   5   3   1   5   3   5   5   5   3   5   5   5   3   5   5   4   3   5 
##  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60 
##   4   4   5   5   5   5   5   5   1   1   1   2   5   1   5   5   1   5   5   5 
##  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80 
##   5   5   3   5   5   1   5   4   4   5   5   5   3   5   3   5   3   5   5   1 
##  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99 100 
##   2   5   1   5   5   5   1   5   5   5   3   1   1   5   5   3   1   3   5   3 
## 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 
##   5   5   1   3   5   5   3   2   3   5   3   3   5   3   3   3   1   1   1   5 
## 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 
##   5   5   5   5   3   5   3   1   5   3   5   4   5   5   5   3   1   3   1   3 
## 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 
##   3   1   1   1   5   3   3   3   5   5   5   3   1   1   5   3   5   3   1   1 
## 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 
##   1   1   3   1   5   5   3   5   5   1   3   1   5   1   3   3   1   3   3   5 
## 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 
##   5   5   3   1   3   3   5   5   3   3   3   3   3   3   5   3   3   3   3   5 
## 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 
##   3   1   3   5   5   5   1   5   5   5   3   3   5   5   3   3   3   1   5   5 
## 221 222 223 224 225 226 227 228 229 230 231 232 233 
##   3   5   5   5   3   1   3   1   5   5   5   5   5 
## 
## Within cluster sum of squares by cluster:
## [1] 10.710205 15.748462  8.791395  7.972209 13.731016
##  (between_SS / total_SS =  87.7 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"
fviz_cluster(edad_cluster2,data=bajas_edaddur_norm2)

Comparando esta gráfica de 5 segmentos contra la anteriormente vista de 4. En esta observamos que separa un segmento que deja un “espacio” que antes no existía; separa y crea un segmento que han durado aprox un 10% más de tieempo que las tres menores, y que se encuentra en rangos de edad parecidos. A continuación se comparan los clusters:
1. El rojo (llamado “Senior”): es el nuevo, el cual tiene de baja a mediana duración y un rango de edad mediana. Después de los que han durado mucho, ellos van después.

  1. El verde superior (llamado “Expert”): es el cluster que más se aparta de los demás; son personas con un mayor rango de edad pero que se alejan de los más jóvenes, y que han durado mucho má tiempo. Se encuentran en el 50% superior del tiempo de duración.

  2. El verde inferior (llamado “Junior”) son personas adultas que han durado poco tiempo en la empresa, parte del 17% inferior de duración.

  3. El morado (llamado “Middle”): al hacer el nuevo clúster nos damos cuenta de que existe un grupo de personas de mediana edad que duran muy poco, aún más poco que los jóvenes. Investigar estado civil.

  4. El azul (llamado “Beginner”): son las personas más jóvenes y que también han durado poco tiempo. Se quedan aproximadamente por el 10% inferior.

bajas_new6<-bajas_new
bajas_new6$Clusters<-edad_cluster2$cluster
bajas_new7<-bajas_new6 %>% group_by(Clusters) %>% summarise(edad=max(edad)) %>% arrange(desc(edad))
bajas_new6$Cluster_Names<-factor(bajas_new6$Clusters,levels = c(1,2,3,4,5), 
                              labels=c("Senior", "Expert", "Junior", "Middle","Beginner"))

Al analizar el estado civil de los 5 clústers, llegamos a las siguientes conclusiones:
1. Del segmento “Senior”, el 75% son solteros. Este es el nuevo clúster descubierto.
2. El 55% de las personas en el cluster “Middle” (menor duración) son solteras, el 26% viven en unión libre, y un 19% que viven en matrimonio.
3. De los expertos, el 75% son solteros.

3. Duración y salario

Importar base de datos

rh_bajas <-read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/ClustersBajasFORM.csv")

Base de datos con valores CUANTITATIVOS

rh_bajas2<-rh_bajas
rh_bajas2<-subset(rh_bajas2,select = -c(alta,estado,nombre))
summary(rh_bajas2)
##       edad          duracion       salario_diario    e.civil.        
##  Min.   :18.00   Min.   :   0.00   Min.   :144.4   Length:233        
##  1st Qu.:23.00   1st Qu.:   9.00   1st Qu.:180.7   Class :character  
##  Median :29.00   Median :  20.50   Median :180.7   Mode  :character  
##  Mean   :30.77   Mean   :  75.59   Mean   :177.9                     
##  3rd Qu.:37.00   3rd Qu.:  47.00   3rd Qu.:180.7                     
##  Max.   :61.00   Max.   :1966.00   Max.   :500.0                     
##     genero          motivo_baja           puesto         
##  Length:233         Length:233         Length:233        
##  Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character  
##                                                          
##                                                          
## 

Normalizando las variables

bajas_duracion_norm<-scale(rh_bajas2[2:3]) 

Elbow Plot

fviz_nbclust(bajas_duracion_norm, kmeans, method="wss")+ 
  geom_vline(xintercept=5, linetype=2)+         
  labs(subtitle = "Elbow method")  

Visualización información de clusters

duracion_cluster1<-kmeans(bajas_duracion_norm,5)
duracion_cluster1
## K-means clustering with 5 clusters of sizes 191, 10, 4, 27, 1
## 
## Cluster means:
##      duracion salario_diario
## 1 -0.23462767      0.1147221
## 2  1.49983327     -0.3729089
## 3  6.65505218     -0.3962566
## 4  0.02340506     -1.1243505
## 5  2.56340604     13.7596523
## 
## Clustering vector:
##   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20 
##   5   4   4   4   4   4   4   4   4   2   4   4   1   1   2   4   4   4   4   4 
##  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40 
##   4   3   4   4   1   1   1   1   1   1   1   1   1   1   1   1   4   2   1   1 
##  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60 
##   2   2   1   1   1   1   1   1   1   1   1   3   2   1   1   1   1   1   1   4 
##  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80 
##   1   1   1   1   1   1   1   2   2   4   1   1   1   1   1   1   1   1   1   1 
##  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99 100 
##   3   4   4   4   4   1   1   1   1   1   1   1   1   1   1   1   4   4   1   1 
## 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 
##   1   1   1   1   1   1   1   3   1   1   1   1   1   1   1   1   1   1   1   1 
## 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 
##   1   1   1   1   1   1   1   1   1   1   1   2   1   1   1   1   1   1   1   1 
## 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 
##   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1 
## 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 
##   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1 
## 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 
##   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1 
## 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 
##   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   2   1   1 
## 221 222 223 224 225 226 227 228 229 230 231 232 233 
##   1   1   1   1   1   1   1   1   1   1   1   1   1 
## 
## Within cluster sum of squares by cluster:
## [1] 3.281687 6.437305 7.884909 1.648877 0.000000
##  (between_SS / total_SS =  95.9 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

Visualización clustering resultados

fviz_cluster(duracion_cluster1,data=bajas_duracion_norm)

Al observar vemos 5 clusters que toman en cuenta la duración y el salario:

  1. Primero vemos nuestro cluster 1 (será llamado “Rehenes”) es un cluster que observamos que son personas que solo entran y salen muy pronto de la empresa (141 días) y tienen un salario diario que es arriba del promedio, alrededor de $180 pesos.

  2. El cluster 2 (“Duraderos”) son los colaboradores que tienen una duración regular, pero que aun así no se encuentran satisfechos por lo que se salen de la empresa al rededor después de 1 año y medio (646 días) y su salario es de $169.

  3. Como cluster 3 tenemos a los colaboradores que son leales a la empresa (“Resistentes”) es el segmento donde estuvo más de 4-5 años trabajando y cuentan con un salario de $168 pesos.

  4. El cluster 4 (“Costosos”) es el cluster que nos cuesta a la empresa porque se invierte en capacitaciones para ellos y terminan saliendo de la empresa; son personas con un poco mas de duración pero no la suficiente (197 días) y su salario es de $151 por debajo promedio.

  5. Por último tenemos el cluster 5 (“Extra”) que tuvo duración corto plazo con un salario muy alto ($500 pesos).

Nombrar a los clusters

rh_bajas3<-rh_bajas2
rh_bajas3$Clusters<-duracion_cluster1$cluster
rh_bajas4<-rh_bajas3 %>% group_by(Clusters) %>% dplyr::summarise(duracion=max(duracion)) %>% arrange(desc(duracion))
rh_bajas3$Cluster_Names<-factor(rh_bajas3$Clusters,levels = c(1,2,3,4,5), 
                              labels=c("Rehenes", "Duraderos","Resistentes", "Costosos","Extra"))

Engrupar los clusters por nombre de clusters y resumir columnas

rh_bajas5<- rh_bajas3 %>% group_by(Cluster_Names) %>% dplyr::summarise(duracion_dias=max(duracion), 
salario_diario=mean(salario_diario),
Count=n())

Formato tabla para información de los clusters

clusters<-as.data.frame(rh_bajas5)
clusters
##   Cluster_Names duracion_dias salario_diario Count
## 1       Rehenes           141       180.6130   191
## 2     Duraderos           646       169.1990    10
## 3   Resistentes          1966       168.6525     4
## 4      Costosos           197       151.6100    27
## 5         Extra           628       500.0000     1

Gráfica con el numero de observaciones por nombres de clusters

ggplot(rh_bajas5,aes(x=reorder(Cluster_Names,Count),y=Count,fill=Cluster_Names)) +
  geom_bar(stat="identity")

ggplot(rh_bajas5, aes(x=Cluster_Names,y=duracion_dias,fill= Cluster_Names,label=round(duracion_dias,digits=2))) + 
  geom_col() + 
  geom_text()

ggplot(rh_bajas5,aes(x=Cluster_Names,y=salario_diario,fill= Cluster_Names,label=round(salario_diario,digits=2))) + 
  geom_col() + 
  geom_text()

Estás ultimas gráficas nos muestran lo que se describió anteriorimente sobre que duración y salario tiene cada cluster y para concluir se mostrara cuantos colaboradores tiene cada cluster:

Total 233 * “Rehenes” tiene el segmento con más colaboradores y tiene un total de 191. En porcentaje se puede decir que es el 81.97% total de bajas.

  • “Costosos” esta en segundo lugar teniendo 27 colaboradores (11.57%).

  • “Duraderos” tercer lugar con un total de 10 colaboradores (4.29%).

  • “Resistentes” cuarto lugar con 4 colaboradores (1.71%).

  • Por último esta el “Extra” que fue solo un colaborador que se encuentra fuera de lo normal (0.43%).

4. Edad y salario

Importar base de datos

bdr <-read.csv("/Users/georginamartinez/Documents/Tec/Séptimo Semestre/Analítica para negocios, de los datos a decisiones/Clsuteredadysalario.csv")

Analizar la estructura de la base de datos

str(bdr) 
## 'data.frame':    233 obs. of  10 variables:
##  $ nombre        : chr  "MARIO VALDEZ ORTIZ" "ISABEL BARRIOS MENDEZ" "MARIA ELIZABETH GOMEZ HERNANDEZ" "ALONDRA ABIGAIL ESCARCIA GOMEZ" ...
##  $ edad          : int  32 36 23 21 29 46 29 31 50 19 ...
##  $ salario_diario: num  500 152 152 152 152 ...
##  $ duracion      : num  628 60 59 59 51 37 37 31 18 224 ...
##  $ estado        : chr  "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" "Nuevo Leon" ...
##  $ e.civil.      : chr  "Soltero" "Union libre" "Matrimonio" "Soltero" ...
##  $ genero        : chr  "MASCULINO" "FEMENINO" "FEMENINO" "FEMENINO" ...
##  $ alta          : chr  "09/03/20" "09/11/21" "10/11/21" "10/11/21" ...
##  $ motivo_baja   : chr  "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" "RENUNCIA VOLUNTARIA" ...
##  $ puesto        : chr  "DISENO" "AYUDANTE GENERAL" "AYUDANTE GENERAL" "AYUDANTE GENERAL" ...

Cuantos Na´s hay por variable

sapply(bdr,function(x) sum(is.na(x)))
##         nombre           edad salario_diario       duracion         estado 
##              0              0              0              0              0 
##       e.civil.         genero           alta    motivo_baja         puesto 
##              0              0              0              0              0

Dejamos únicamente las variables cuantitativas

bdr2 <- bdr
bdr2<-subset(bdr2,select = -c(alta,estado,nombre))
summary(bdr2)
##       edad       salario_diario     duracion         e.civil.        
##  Min.   :18.00   Min.   :144.4   Min.   :   0.00   Length:233        
##  1st Qu.:23.00   1st Qu.:180.7   1st Qu.:   9.00   Class :character  
##  Median :29.00   Median :180.7   Median :  20.50   Mode  :character  
##  Mean   :30.77   Mean   :177.9   Mean   :  75.59                     
##  3rd Qu.:37.00   3rd Qu.:180.7   3rd Qu.:  47.00                     
##  Max.   :61.00   Max.   :500.0   Max.   :1966.00                     
##     genero          motivo_baja           puesto         
##  Length:233         Length:233         Length:233        
##  Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character  
##                                                          
##                                                          
## 

Normalización de variables

bdr3 <- scale(bdr2[1:2]) 

Elbow plot

fviz_nbclust(bdr3, kmeans, method="wss")+ 
  geom_vline(xintercept=4, linetype=2)+         
  labs(subtitle = "Elbow method") 

Visualización de clusters

bdr4<-kmeans(bdr3,4)
bdr4
## K-means clustering with 4 clusters of sizes 1, 38, 76, 118
## 
## Cluster means:
##         edad salario_diario
## 1  0.1270769   13.759652253
## 2  1.7696042   -0.090629543
## 3  0.3483430   -0.003448058
## 4 -0.7953060   -0.085200655
## 
## Clustering vector:
##   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20 
##   1   3   4   4   4   2   4   3   2   4   4   3   4   3   3   4   4   4   4   4 
##  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40 
##   3   2   4   3   2   4   3   4   4   4   3   4   4   4   3   4   4   4   3   4 
##  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60 
##   4   3   4   4   4   4   4   4   2   2   3   2   4   2   4   4   2   4   4   4 
##  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80 
##   4   4   3   4   4   3   4   2   4   4   4   4   3   4   3   4   3   4   4   2 
##  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99 100 
##   4   4   2   4   4   4   3   4   4   4   3   3   2   4   4   4   2   3   4   3 
## 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 
##   4   4   3   3   4   4   3   4   3   4   3   3   4   3   3   3   2   2   2   4 
## 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 
##   4   4   4   4   3   4   3   2   4   3   4   2   4   4   4   3   2   3   2   3 
## 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 
##   3   3   2   2   4   3   3   3   4   4   4   3   2   2   4   3   4   3   3   3 
## 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 
##   2   2   3   2   4   4   3   4   4   2   3   2   4   2   3   3   2   3   3   4 
## 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 
##   4   4   3   2   3   3   4   4   3   3   3   3   3   3   4   3   4   3   3   4 
## 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 
##   3   2   3   4   4   4   2   4   4   4   3   3   4   4   3   3   3   2   4   4 
## 221 222 223 224 225 226 227 228 229 230 231 232 233 
##   3   4   4   4   4   2   3   2   4   4   4   4   4 
## 
## Within cluster sum of squares by cluster:
## [1]  0.00000 14.98451 20.97488 34.67145
##  (between_SS / total_SS =  84.8 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"
fviz_cluster(bdr4,data=bdr3)

Vemos que el número óptimo de klusters para las variables edad y salario diario son 4 según el método de Elbow.

Como dato disparado y posible warning vemos que hay un trabajador con un salario diario de 500 pesos lo que podría resultar como un error, sin embargo los otros 3 grupos varían bastante en edad más no en salario pues el rango es muy cercano.

  1. Cluster 1 El dato es único en el conteo con un trabajador de 32 años que tiene un salario diario de 500 pesos y es soltero. Su punto en el mapeo es único (color rojo).

  2. Clsuter 2 Es el cluster con el registro de personas con mayor edad y cuentan con el salario diario más alto 183.68.

  3. Cluster 3 Es el cluster con el registro de personas con edad promedio y salario de 180.68.

  4. Cluster 4 Es el cluster con mayor registro de personas con edad jóven y salario de 182.68.

Nombrar a los clusters

bdr5<-bdr2
bdr5$Cluster <- bdr4$cluster
bdr6<-bdr5 %>% group_by(Cluster) %>% dplyr::summarise(salario_diario=max(salario_diario)) %>% arrange(desc(salario_diario))
bdr5$Cluster_Names<-factor(bdr5$Cluster,levels = c(1,2,3,4), 
                                labels=c("Alto", "Medio","Bajo", "Regular"))

Agrupar clusters

bdr7<- bdr5 %>% group_by(Cluster_Names) %>% dplyr::summarise(salario_diario=max(salario_diario), 
edad=mean(edad),
Count=n())

Tabla

clusters<-as.data.frame(bdr7)
clusters
##   Cluster_Names salario_diario     edad Count
## 1          Alto         500.00 32.00000     1
## 2         Medio         183.68 47.92105    38
## 3          Bajo         180.68 34.14474    76
## 4       Regular         182.68 23.05932   118

Gráficas

ggplot(bdr7,aes(x= reorder(Cluster_Names,Count),y=Count,fill=Cluster_Names)) +
  geom_bar(stat="identity")

ggplot(bdr7, aes(x=Cluster_Names,y=edad,fill= Cluster_Names,label=round(edad,digits=2))) + 
  geom_col() + 
  geom_text()

ggplot(bdr7,aes(x=Cluster_Names,y=salario_diario,fill= Cluster_Names,label=round(salario_diario,digits=2))) + 
  geom_col() + 
  geom_text()

  1. En la segunda gráfica el clúster azul es el que tiene mayor frecuencia con un promedio de edad de 48 años.

  2. El cluster alto en la segunda grafica englobó en 22 años el count, sin embargo hay trabajadores con menor edad. Dicho cluster es el que tiene menos trabajadores dentro de Form.

  3. En cuanto al salario en la tercera gráfica, el dato más alto es el que anteriormente se había mencionado como un dato único ($500) y vemos el comportamiento que se generaba en el mapeo de clusters donde los demás tienen una diferencia mínima siendo los resultados 182.68, 180.68 y 183.68.

Segundo punto: Insights.

  • Con la base de datos de bajas se realizó el clúster de edad y duración, en la cual se tomaron en cuenta las variables de la edad de los colaboradores y la duración que han tenido en la empresa. Se buscó el número óptimo de clúster y se tomaron en cuenta los primeros 4. En este podemos observar que las personas con edad mediana-alta no tienen una duración de largo tiempo en la empresa ya que forman parte del 25% con menor duración; otro dato que observamos que las personas con mayor edad han durado más tiempo en Form y forman parte del superior 50%, y por último observamos que existe una mayor rotación de personal en los colaboradores jóvenes.
  • En el análisis que se realizó mediante gráficas, obtuvimos que en los clúster, que la persona con mayor edad en los expert tiene 61, en senior tiene 57, en junior tiene 39 y en beginnner 27, también que en la empresa la mayoría de los colaboradores corresponden al clúster de beginner.
  • En cuanto al análisis de la duración de los colaboradores en la empresa y su salario encontramos estos puntos mas importantes; a) la mayoría de los empleados ganan arriba del salario diario promedio establecido por el gobierno, este oscila entre $150-$2000 pesos diarios, b) los colaboradores que tienen un tiempo medio en la empresa aproximadamente de un año tiene un salario promedio de $169, mientras los que duran menos tiempo (alrededor de 141 días) tienen un salario promedio de alrededor de $180.
  • El clúster mas grande es el llamado “Rehenes” tiene un total de colaboradores de 191, y en porcentaje de bajas se puede decir que es el 81.97% total de bajas, estos tiene la característica de son las personas que entran y salen muy pronto y tienen un salario por arriba de todos los demás clúster de $180 pesos, por lo que, en este clúster se necesita aplicar una estrategia de fidelización de los colaboradores de otra forma que no sea con un aumento de salario, es decir, Form puede implementar estrategias con recompensas que sean a largo plazo.
  • Como se puede observar en el analisis que se realizó de edad y salario se pueden destacar los siguientes puntos:
  1. El cluster que tiene una mayor frecuencia es el de 48 años de edad,

  2. El cluster que mas chico es de 22 años o menos por lo que podemos decir que en Form, la mayoría son mayores de 23 años,

  3. En cuanto al salario tienen un promedio de 180.68, pero existe un dato único el cual ganaba 500.

Tercer punto: Relaciones entre variables cuantitativas y cualitativas.

Convertir las variables para crear analisis descriptivos

rh_bajas3$genero<-as.factor(rh_bajas3$genero)
rh_bajas3$puesto<-as.factor(rh_bajas3$puesto)
rh_bajas3$e.civil.<-as.factor(rh_bajas3$e.civil.)

Clusters Edad y duración (4 clusters)

Relación entre Salario, Género y Estado Civil

bajas_new8<-bajas_new2%>% filter(Clusters==1 | Clusters==4) %>% arrange(Clusters)
ggplot(as.data.frame(bajas_new8),
       aes(y=salario_diario, axis1=genero, axis2=e.civil.)) +
  geom_alluvium(aes(fill=Cluster_Names), width = 1/12) +
  geom_stratum(width = 1/12, fill = "black", color = "grey") +
  geom_label(stat = "stratum", aes(label = after_stat(stratum))) +
  scale_x_discrete(limits = c("Genero", "Estado Civil"), expand = c(.05, .05)) +
  scale_fill_brewer(type = "qual", palette = "Set1") +
  ggtitle("Salario Diario de Pasados Empleados de Form por Género y Estado Civil")

Clusters Edad y duración (5 clusters)

Relación entre Salario, Género y Estado Civil

bajas_new9<-bajas_new6%>% filter(Clusters==1 | Clusters==5) %>% arrange(Clusters)
ggplot(as.data.frame(bajas_new9),
       aes(y=salario_diario, axis1=genero, axis2=e.civil.)) +
  geom_alluvium(aes(fill=Cluster_Names), width = 1/12) +
  geom_stratum(width = 1/12, fill = "black", color = "grey") +
  geom_label(stat = "stratum", aes(label = after_stat(stratum))) +
  scale_x_discrete(limits = c("Genero", "Estado Civil"), expand = c(.05, .05)) +
  scale_fill_brewer(type = "qual", palette = "Set1") +
  ggtitle("Salario Diario de Pasados Empleados de Form por Género y Estado Civil")

Clusters Salario y edad

Relación entre Salario, Género y Estado Civil

bdr8<-bdr5%>% filter(Cluster==1 | Cluster==3) %>% arrange(Cluster)
ggplot(as.data.frame(bdr8),
       aes(y=salario_diario, axis1=genero, axis2=e.civil.)) +
  geom_alluvium(aes(fill=Cluster_Names), width = 1/12) +
  geom_stratum(width = 1/12, fill = "black", color = "grey") +
  geom_label(stat = "stratum", aes(label = after_stat(stratum))) +
  scale_x_discrete(limits = c("Genero", "Estado Civil"), expand = c(.05, .05)) +
  scale_fill_brewer(type = "qual", palette = "Set1") +
  ggtitle("Salario Diario de Pasados Empleados de Form por Género y Estado Civil")

#### Relación entre Salario, Género y Motivo de baja

bdr8<-bdr5%>% filter(Cluster==1 | Cluster==3) %>% arrange(Cluster)
ggplot(as.data.frame(bdr8),
       aes(y=salario_diario, axis1=genero, axis2=motivo_baja)) +
  geom_alluvium(aes(fill=Cluster_Names), width = 1/12) +
  geom_stratum(width = 1/12, fill = "black", color = "grey") +
  geom_label(stat = "stratum", aes(label = after_stat(stratum))) +
  scale_x_discrete(limits = c("Genero", "Estado Civil"), expand = c(.05, .05)) +
  scale_fill_brewer(type = "qual", palette = "Set1") +
  ggtitle("Salario Diario de Pasados Empleados de Form por Género y Motivo de baja")

Clusters Duración y salario

Asociaciones entre variables categóricas a través de nombres de grupos

Clusters Bajas con género y estado civil
rh_bajas6<-rh_bajas3 %>% filter(Clusters==4 | Clusters==3) %>% arrange(Clusters)
ggplot(as.data.frame(rh_bajas6),
       aes(y=salario_diario, axis1=genero, axis2=e.civil.)) +
  geom_alluvium(aes(fill=Cluster_Names), width = 1/12) +
  geom_stratum(width = 1/12, fill = "black", color = "grey") +
  geom_label(stat = "stratum", aes(label = after_stat(stratum))) +
  scale_x_discrete(limits = c("Genero", "Estado Civil"), expand = c(.05, .05)) +
  scale_fill_brewer(type = "qual", palette = "Set1") +
  ggtitle("Salario Diario de Pasados Empleados de Form por Género y Estado Civil")

##### Clusters Bajas con género y estado civil

ggplot(rh_bajas3, aes(Cluster_Names, fill=factor(genero,levels=rev(levels(genero))))) + 
  geom_bar(position="dodge")+
  scale_fill_discrete('Género')+
  ggtitle("Género de Colaboradores por Cluster")

ggplot(rh_bajas3, aes(Cluster_Names, fill=factor(e.civil.,levels=rev(levels(e.civil.)))))+
  geom_bar(position="dodge")+
  scale_fill_discrete('Estado Civil')+
  ggtitle("Estado Civil de Bajas por Cluster")

ggplot(rh_bajas3, mapping=aes(x=Cluster_Names, fill=puesto)) + 
  geom_bar(alpha = 1/5, position="identity")+
  ggtitle("Puestos de Colaboradores por Cluster")

En conclusión para Form podemos plantear una estrategia de estandarización de salarios de acuerdo al tiempo que llevan en la empresa y su edad, para poder así tener un mejor control de gastos de la empresa y aplicar nuevas a estrategias a cada uno de los cluster.

Identificación de Resultados Relevantes y Sugerencias

Meaningful insights

  1. Hablando del área de Recursos humanos podemos encontrar que es necesario recompensar la antigüedad y crear planes de crecimiento para la gente (sobre todo a los jóvenes) para reducir las bajas ya que al realizar los clusters nos muestran que los jóvenes son los que duran menos tiempo en la empresa.

  2. El tema por el que hay más bajas es por la razón de Faltas teniendo un 60% y en segundo lugar esta la Renuncia voluntaria con 36%. Se tiene que brindar atención porque capacitar a los empleados es algo costoso y se tiene una alta rotación.

  3. Dentro de Producción nuestro top 3 clientes de producción son STABILUS 1, STABILUS 3 y TRMX.

  4. En distrubución debemos prestar atención al cliente Mahle, su restraso es arriba del promedio llegando incluso a tiempos de 1 hora con 40 minutos y esto puede afectar la relación con el cliente y en la logística.

  5. En delivery Plan destaca el cliente HELLA haciendo pedidos que llegan hasta más de 200,000.

  6. En promedio se realizan entre 0 a 1000 pedidos, pero debemos de tener cuidado ya que también encontramos que se tienen sobrepedidos (arriba del promedio) llegando hasta 5,000 pedidos y esto puede afectar si no se tienen la capacidad para recibir pedidos de más.

Sugerencias para proceso de captura, organización, y analítica de datos

  1. Para captura de datos utilizar softwares que permitan el registro de datos de manera automatizada, ya que para la parte comercial se ve que las bases fueron hechas manuales y tienen datos faltantes o repetidos como el software MuleSoft.

  2. Al realizar bases de datos darle un mejor formato donde la primera fila sean las variables y abajo los registros para un eficaz y mejor proceso de limpieza.

  3. Agregar el tipo de producto a la base de datos de Scrap para encontrar cual es el que se tiene mayor cantidad y buscar una manera de disminuirlo.

  4. Contar con una área de Inteligencia de Negocios y Analítica de Negocios con datas engineer que logren recolectar información y procesarla para la toma de decisiones.

Conceptos y preguntas finales

Definiciones

Business Analytics

El concepto de Business Analytics se puede definir como el proceso de utilizar información con distintos métodos para tomar mejores decisiones, que sean informadas y correctas dentro del mundo de negocios gracias al análisis que se realiza (Gavin, M., 2019). Existen 4 tipos de métodos:

  • Descriptivo: Crear tendencias y patrones con datos históricos.

  • Diagnóstico: Explica el por que de los sucesos utilizando igualmente datos históricos.

  • Predictivo: Poder gráficar y encontrar tendencias a través de pronósticos mediante estadísticas.

  • Prescriptivo: Precisar resultados para escenarios con mejores resultados trabajando con aplicación de pruebas y otras técnicas.

El BA ayuda a reconocer patrones de consumo que permiten segmentar sobre los hábitos y preferencias de compra, también encontrar área de oportunidad que nos digan si podemos mejorar la productividad y rendimiento.

Business Intelligence

Podemos decir que hablamos de Business Intelligence cuando se tiene la visión estratégica para transformar los activos en datos que ayuden a generar decisiones basadas en datos (Shen, E., 2020). Y para esto es importante que la herramienta que permite cumplir con esta visión tome en cuenta las funcionalidades que se tienen:

  • Acceder a todos los datos de todas las áreas y niveles de gradulado.

  • Obtener datos de manera rápida.

  • Poder compartir la información con los responsables de decisiones en lenguajes comúnes.

Para aprovechar al máximo el utilizar Business Intelligence, es importante considerar los siguientes pasos:

  1. Conocer a los clientes y comprenderlos para poder desarrollar estrategias inteligentes que atiendan necesidades.

  2. Contar con un solo canal de datos que permita la eficiencia y limpieza.

  3. Modernizarse con las nuevas herramientas que tienen más capacidades de generar más inteligencia, como aprendizaje automático.

  4. Siempre estar en constante supervisión y mejoras.

Diferencias entre Business Analytics y Business Intelligence

  1. Business Intelligence lo que busca es comprender como se encuentra la empresa y como poder mejorar, utilizando datos históricos mediante un análisis descriptivo mientras que Business Analytics es explicar el porque de ciertos eventos, tendencias o patrones.

  2. La información se genera por Business Analyticis y después un experto de Business Intelligence transforma esa información en resultados y gráficos.

  3. Business Intelligence necesitan comprender lo que estan extrayendo y transformando, mientras que Business Analyticis tienen que tener capacidad para diseñar e implementar métodos que permitan la recolección de datos.

Key Performance Indicators (KPI)

Son indicadores claves para lograr medir el desempeño dentro de una empresa y llegar al resultado deseado. Ayudan a crear un enfoque de que se quiere hacer y que estrategias utilizar para cumplir con estos indicadores y al ver como se va progresando modificar la estrategia, también nos permiten tomar mejores decisiones. Se necesitan establecer objetivos para después ponerles estos indicadores clave.

KPI’s para la empresa FORM

  1. Rendimiento: Analizar la capacidad de producción que se tiene dentro de la empresa.

Fórmula= Cantidad de unidades producidas / Tiempo (horas o días)

  1. Rotación de empleados: Medir cual es la rotación que se tiene.

Fórmula= Número actual (del mes) de empleados que renunciaron o se fueron / ((empleados al inicio de mes+ empleados al final de mes)/2) x 100

  1. Entregas a tiempo: Estar analizando si nuestros pedidos llegan a tiempo con los clientes.

Fórmula= (Núm. de entregas a tiempo / Núm. total de entregas realizadas) x 100 # Referencias 1. Gavin, M. (2019, 16 julio). Business Analytics: What It Is & Why It’s Important | HBS Online. Business Insights Blog. Recuperado 21 de octubre de 2022, de https://online.hbs.edu/blog/post/importance-of-business-analytics

  1. Shen, S. (2021, 15 diciembre). 6 Key Areas of Business Intelligence in the New Era. Medium. Recuperado 21 de octubre de 2022, de https://towardsdatascience.com/6-key-areas-of-business-intelligence-in-the-new-era-105fdc6f9350

  2. Escobar, J. (2021, 26 octubre). Business Analytics vs Business Intelligence ¿cuál es la diferencia? Recuperado 21 de octubre de 2022, de https://blog.egade.tec.mx/business-analytics-vs-business-intelligence-diferencias

  3. What is a Key Performance Indicator (KPI)? (s. f.). Recuperado 21 de octubre de 2022, de https://kpi.org/KPI-Basics

LS0tCnRpdGxlOiAiRXZpZGVuY2lhIDIiCmF1dGhvcjogIkthcmxhIEdlb3JnaW5hIE1hcnTDrW5leiBHb256w6FsZXogQTAwODI3NTAwIgpkYXRlOiAiMjAyMi0xMC0xMiIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgo8aW1nIHNyYz0gIi9Vc2Vycy9nZW9yZ2luYW1hcnRpbmV6L0RvY3VtZW50cy9UZWMvU2XMgXB0aW1vIFNlbWVzdHJlL0FuYWxpzIF0aWNhIHBhcmEgbmVnb2Npb3MsIGRlIGxvcyBkYXRvcyBhIGRlY2lzaW9uZXMvRm9ybS5wbmciPgoKIyAqKkxpbXBpZXphLCB0cmFuc2Zvcm1hY2nDs24geSBvcmdhbml6YWNpw7NuIGRlIEJhc2VzIGRlIERhdG9zKioKCiMjIEV4cG9ydGFyIGJhc2VzIGRlIGRhdG9zICAKCkJhc2UgZGUgZGF0b3MgUmVjdXJzb3MgSHVtYW5vcwpgYGB7cn0KYmxpbXBpYTwtcmVhZC5jc3YoIi9Vc2Vycy9nZW9yZ2luYW1hcnRpbmV6L0RvY3VtZW50cy9UZWMvU2XMgXB0aW1vIFNlbWVzdHJlL0FuYWxpzIF0aWNhIHBhcmEgbmVnb2Npb3MsIGRlIGxvcyBkYXRvcyBhIGRlY2lzaW9uZXMvQmFzZSBkZSBkYXRvcyBGT1JNL0FjdCAyLjQgRXF1aXBvL2JhamFzX2xpbXBpYS5jc3YiKQpjbGltcGlhPC1yZWFkLmNzdigiL1VzZXJzL2dlb3JnaW5hbWFydGluZXovRG9jdW1lbnRzL1RlYy9TZcyBcHRpbW8gU2VtZXN0cmUvQW5hbGnMgXRpY2EgcGFyYSBuZWdvY2lvcywgZGUgbG9zIGRhdG9zIGEgZGVjaXNpb25lcy9CYXNlIGRlIGRhdG9zIEZPUk0vQWN0IDIuNCBFcXVpcG8vcmxpbXBpYS5jc3YiKQpiYWphc19iZDwtcmVhZC5jc3YoIi9Vc2Vycy9nZW9yZ2luYW1hcnRpbmV6L0RvY3VtZW50cy9UZWMvU2XMgXB0aW1vIFNlbWVzdHJlL0FuYWxpzIF0aWNhIHBhcmEgbmVnb2Npb3MsIGRlIGxvcyBkYXRvcyBhIGRlY2lzaW9uZXMvQkRfRm9ybV9MaW1waWFzL2JhamFzX2ZpbmFsLmNzdiIpCmNvbGFiX2JkPC1yZWFkLmNzdigiL1VzZXJzL2dlb3JnaW5hbWFydGluZXovRG9jdW1lbnRzL1RlYy9TZcyBcHRpbW8gU2VtZXN0cmUvQW5hbGnMgXRpY2EgcGFyYSBuZWdvY2lvcywgZGUgbG9zIGRhdG9zIGEgZGVjaXNpb25lcy9CRF9Gb3JtX0xpbXBpYXMvY29sYWJfZmluYWwuY3N2IikKYGBgCgpgYGB7cn0KI2ZpbGUuY2hvb3NlKCkKYmFqYXNfYmQ8LXJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0JEX0Zvcm1fTGltcGlhcy9iYWphc19maW5hbC5jc3YiKQpjb2xhYl9iZDwtcmVhZC5jc3YoIi9Vc2Vycy9nZW9yZ2luYW1hcnRpbmV6L0RvY3VtZW50cy9UZWMvU2XMgXB0aW1vIFNlbWVzdHJlL0FuYWxpzIF0aWNhIHBhcmEgbmVnb2Npb3MsIGRlIGxvcyBkYXRvcyBhIGRlY2lzaW9uZXMvQkRfRm9ybV9MaW1waWFzL2NvbGFiX2ZpbmFsLmNzdiIpCmBgYAoKQmFzZSBkZSBkYXRvcyBEZWxpdmVyeSBQbGFuCmBgYHtyfQpkcCA8LSByZWFkLmNzdigiL1VzZXJzL2dlb3JnaW5hbWFydGluZXovRG9jdW1lbnRzL1RlYy9TZcyBcHRpbW8gU2VtZXN0cmUvQW5hbGnMgXRpY2EgcGFyYSBuZWdvY2lvcywgZGUgbG9zIGRhdG9zIGEgZGVjaXNpb25lcy9CYXNlIGRlIGRhdG9zIEZPUk0vQWN0IDIuNCBFcXVpcG8vREVMSVZFUlkgUExBTiBiZGZfUHJ1ZWJhLmNzdiIpCmBgYAoKQmFzZSBkZSBkYXRvcyBEZWxpdmVyeSBQZXJmb3JtYW5jZQpgYGB7cn0KYmRfZGVsaXZlcnlfcGVyZiA8LSByZWFkLmNzdigiL1VzZXJzL2dlb3JnaW5hbWFydGluZXovRG9jdW1lbnRzL1RlYy9TZcyBcHRpbW8gU2VtZXN0cmUvQW5hbGnMgXRpY2EgcGFyYSBuZWdvY2lvcywgZGUgbG9zIGRhdG9zIGEgZGVjaXNpb25lcy9CYXNlIGRlIGRhdG9zIEZPUk0vQWN0IDIuNCBFcXVpcG8vRk9STSAtIERlbGl2ZXJ5IFBlcmZvcm1hbmNlIEMuY3N2IikKYGBgCgpCYXNlIGRlIGRhdG9zIFByb2R1Y2Npw7NuCmBgYHtyfQpkYXRhIDwtIHJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0Jhc2UgZGUgZGF0b3MgRk9STS9BY3QgMi40IEVxdWlwby9Qcm9kdWNpb24gQ29tcGxldGEuY3N2IikKYGBgCgpCYXNlIGRlIGRhdG9zIE1lcm1hCmBgYHtyfQpiZF9tZXJtYSA8LSByZWFkLmNzdigiL1VzZXJzL2dlb3JnaW5hbWFydGluZXovRG9jdW1lbnRzL1RlYy9TZcyBcHRpbW8gU2VtZXN0cmUvQW5hbGnMgXRpY2EgcGFyYSBuZWdvY2lvcywgZGUgbG9zIGRhdG9zIGEgZGVjaXNpb25lcy9CYXNlIGRlIGRhdG9zIEZPUk0vRk9STSAtIE1lcm1hMS5jc3YiKQpgYGAKCkJhc2UgZGUgZGF0b3MgU2NyYXAKYGBge3J9CmJkX3NjcmFwIDwtIHJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0Jhc2UgZGUgZGF0b3MgRk9STS9GT1JNIC0gU2NyYXAuY3N2IikKYGBgCgpCYXNlcyBkZSBkYXRvcyBleHRlcm5hOiBVU0EKYGBge3J9CmJkX2V4dGVybmEgPC0gcmVhZC5jc3YoIi9Vc2Vycy9nZW9yZ2luYW1hcnRpbmV6L0RvY3VtZW50cy9UZWMvU2XMgXB0aW1vIFNlbWVzdHJlL0FuYWxpzIF0aWNhIHBhcmEgbmVnb2Npb3MsIGRlIGxvcyBkYXRvcyBhIGRlY2lzaW9uZXMvQmFzZSBkZSBkYXRvcyBGT1JNL0FjdCAyLjQgRXF1aXBvL3VzX21vdG9yX3Byb2R1Y3Rpb25fYW5kX2RvbWVzdGljX3NhbGVzLmNzdiIpCmJhc2UgPC1yZWFkLmNzdigiL1VzZXJzL2dlb3JnaW5hbWFydGluZXovRG9jdW1lbnRzL1RlYy9TZcyBcHRpbW8gU2VtZXN0cmUvQW5hbGnMgXRpY2EgcGFyYSBuZWdvY2lvcywgZGUgbG9zIGRhdG9zIGEgZGVjaXNpb25lcy9CYXNlIGRlIGRhdG9zIEZPUk0vQWN0IDIuNCBFcXVpcG8vdXNfbW90b3JfcHJvZHVjdGlvbl9hbmRfZG9tZXN0aWNfc2FsZXMxLmNzdiIpCmBgYAoKQmFzZXMgZGUgZGF0b3MgZXh0ZXJuYTogTcOpeGljbwpgYGB7cn0KYmRfZXh0ZXJuYU1YIDwtIHJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL2luZHVzdHJpYV9hdXRvbW90cml6X214LmNzdiIpCmBgYAoKIyMgTGlicmVyaWFzIHJlcXVlcmlkYXMgIApgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGZvcmVpZ24pCmxpYnJhcnkoZHBseXIpICAgICAgICAjIGRhdGEgbWFuaXB1bGF0aW9uIApsaWJyYXJ5KGZvcmNhdHMpICAgICAgIyB0byB3b3JrIHdpdGggY2F0ZWdvcmljYWwgdmFyaWFibGVzCmxpYnJhcnkoZ2dwbG90MikgICAgICAjIGRhdGEgdmlzdWFsaXphdGlvbiAKbGlicmFyeShqYW5pdG9yKSAgICAgICMgZGF0YSBleHBsb3JhdGlvbiBhbmQgY2xlYW5pbmcgCmxpYnJhcnkoSG1pc2MpICAgICAgICAjIHNldmVyYWwgdXNlZnVsIGZ1bmN0aW9ucyBmb3IgZGF0YSBhbmFseXNpcyAKbGlicmFyeShuYW5pYXIpIApsaWJyYXJ5KGRsb29rcikgCmxpYnJhcnkocG9sbHN0ZXIpCmxpYnJhcnkoZGVzY3IpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShlcGlEaXNwbGF5KQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShwc3ljaCkgICAgICAgICMgZnVuY3Rpb25zIGZvciBtdWx0aXZhcmlhdGUgYW5hbHlzaXMgCmxpYnJhcnkoY29ycnBsb3QpICAgICAjIGNvcnJlbGF0aW9uIHBsb3RzCmxpYnJhcnkoanRvb2xzKSAgICAgICAjIHByZXNlbnRhdGlvbiBvZiByZWdyZXNzaW9uIGFuYWx5c2lzIApsaWJyYXJ5KGxtdGVzdCkgICAgICAgIyBkaWFnbm9zdGljIGNoZWNrcyAtIGxpbmVhciByZWdyZXNzaW9uIGFuYWx5c2lzIApsaWJyYXJ5KGNhcikgICAgICAgICAgIyBkaWFnbm9zdGljIGNoZWNrcyAtIGxpbmVhciByZWdyZXNzaW9uIGFuYWx5c2lzCmxpYnJhcnkob2xzcnIpICAgICAgICAjIGRpYWdub3N0aWMgY2hlY2tzIC0gbGluZWFyIHJlZ3Jlc3Npb24gYW5hbHlzaXMgCmxpYnJhcnkoa2FibGVFeHRyYSkgICAjIEhUTUwgdGFibGUgYXR0cmlidXRlcwpsaWJyYXJ5KHRzZXJpZXMpICAgIyB0aW1lIHNlcmllcyBhbmFseXNpcyBhbmQgY29tcHV0YXRpb25hbCBmaW5hbmNlIApsaWJyYXJ5KGZvcmVjYXN0KSAgIyBwcm92aWRlcyBtZXRob2RzIGFuZCB0b29scyBmb3IgZGlzcGxheWluZyBhbmQgYW5hbHl6aW5nIHVuaXZhcmlhdGUgdGltZSBzZXJpZXMgZm9yZWNhc3QKbGlicmFyeShhc3RzYSkgICAgICMgYXBwbGllZCBzdGF0aXN0aWNhbCB0aW1lIHNlcmllcyBhbmFseXNpcwpsaWJyYXJ5KHBseXIpIApgYGAKCiMjIGEuIEZPUk0gLSBSZWN1cnNvcyBIdW1hbm9zCgojIyMgTGltcGllemEKRW4gbGEgYmFzZSBkZSBkYXRvcyBzZSB0cmFiYWrDsyBwcmV2aWFtZW50ZSBlbiBleGNlbCwgaG9tb2dlbml6YW5kbyBsYXMgdmFyaWFibGVzIHkgZGVzcHXDqXMgc2UgdHJhYmFqw7MgZW4gUiBkaXN0aW50YXMgdMOpY25pY2FzIGxvZ3JhbmRvIGVsaW1pbmFyIGxhcyB2YXJpYWJsZXMgcXVlIG5vIHNlIGNvbnNpZGVyZW4gbmVjZXNhcmlhcy4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgVMOpY25pY2EuIFJlbW92ZXIgdmFsb3JlcyBpcnJlbGV2YW50ZXMKY2xpbXBpYTI8LWNsaW1waWEKY2xpbXBpYTI8LXN1YnNldChjbGltcGlhMixzZWxlY3Q9LWMoUHJpbWVyLm1lcyxYNHRvLm1lcyxFbXBsZWFkbyxERVBBUlRBTUVOVE8pKQpzdW1tYXJ5KGNsaW1waWEyKQoKIyDCv0N1w6FudG9zIE5BICB0ZW5nbyBwb3IgdmFyaWFibGVzPyBDT0xBQgpzYXBwbHkoY2xpbXBpYTIsZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkKCiMgwr9DdcOhbnRvcyBOQSAgdGVuZ28gcG9yIHZhcmlhYmxlcz8gQkFKQVMKc2FwcGx5KGJsaW1waWEsZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkKCiMgTm8gaGF5IG3DoXMgdmFsb3JlcyBmYWx0YW50ZXMuCgojIFTDqWNuaWNhLiBDb252ZXJ0aXIgdGlwb3MgZGUgZGF0b3MKCiMgQ2FtYmlhciBub21icmVzIGRlIGNvbHVtbmFzLgojIENPTEFCCnN0cihjbGltcGlhMikKbmFtZXMgKGNsaW1waWEyKSA9IGMoImVkYWQiLCAiZ2VuZXJvIiwgImFsdGEiLCAicHVlc3RvIiwgInNhbGFyaW9fZGlhcmlvIiwgImx1Z2FyLm5hY2ltLiIsIm1waW8iLCJlc3RhZG8iLCJjaXZpbCIpCm5hbWVzIChjbGltcGlhMikKc3RyKGNsaW1waWEyKQoKIyBCQUpBUwpzdHIoYmxpbXBpYSkKbmFtZXMgKGJsaW1waWEpID0gYygibm9tYnJlIiwgImVkYWQiLCAiZ2VuZXJvIiwgImFsdGEiLCAibW90aXZvX2JhamEiLCAiZHVyYWNpb24iLCAicHVlc3RvIiwic2FsYXJpb19kaWFyaW8iLCJlc3RhZG8iLCJlLmNpdmlsLiIpCm5hbWVzIChibGltcGlhKQpzdHIoYmxpbXBpYSkKCiMgRXhwb3J0YXIgYmFzZXMgZGUgZGF0b3MKY29sYWJfZmluYWw8LWNsaW1waWEyCndyaXRlLmNzdihjb2xhYl9maW5hbCwgZmlsZSA9ImNvbGFiX2ZpbmFsLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKYmFqYXNfZmluYWw8LWJsaW1waWEKd3JpdGUuY3N2KGJhamFzX2ZpbmFsLCBmaWxlID0iYmFqYXNfZmluYWwuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMjIyMgQ2FtYmlhciBhIG5vbWJyZXMgZGUgY29sdW1uYSBtw6FzIGNvcnRvcyBlbiBiYXNlIGRlIGRhdG9zIGNvbGFib3JhZG9yZXMKYGBge3J9CmNvbGFiX2JkJGdlbmVyb1tjb2xhYl9iZCRnZW5lcm8gPT0gIkZFTUVOSU5PIl0gPC0gIkYiCmNvbGFiX2JkJGdlbmVyb1tjb2xhYl9iZCRnZW5lcm8gPT0gIk1BU0NVTElOTyJdIDwtICJNIgpzdHIoY29sYWJfYmQpCmBgYAoKIyMjIyMgQ2FtYmlhciBhIG5vbWJyZXMgZGUgY29sdW1uYSBtw6FzIGNvcnRvcyBlbiBiYXNlIGRlIGRhdG9zIGJhamFzCmBgYHtyfQpiYWphc19iZCRnZW5lcm9bYmFqYXNfYmQkZ2VuZXJvID09ICJGRU1FTklOTyJdIDwtICJGIgpiYWphc19iZCRnZW5lcm9bYmFqYXNfYmQkZ2VuZXJvID09ICJNQVNDVUxJTk8iXSA8LSAiTSIKc3RyKGJhamFzX2JkKQpgYGAKCiMjIyDCv0N1w6FudGFzIHZhcmlhYmxlcyB5IGN1YW50b3MgcmVnaXN0cm9zIHRpZW5lIGxhIGJhc2UgZGUgZGF0b3M/CkRlbnRybyBkZSBsYSBiYXNlIGRlIGRhdG9zIGRlICpDb2xhYm9yYWRvcmVzKiBzZSBjdWVudGEgY29uIDkgdmFyaWFibGVzIHkgMTA0IHJlZ2lzdHJvcyB5IHBhcmEgbGEgYmFzZSBkZSBkYXRvcyBkZSAqQmFqYXMqIHNlIHRpZW5lIDEwIHZhcmlhYmxlcyBjb24gMjMzIHJlZ2lzdHJvcy4KCiMjIyBDbGFzaWZpY2FjacOzbiB5IGVzY2FsYSBkZSBtZWRpY2nDs24KCiMjIyMgQ2xhc2lmaWNhY2nDs24gQ29sYWJvcmFkb3JlcwpgYGB7ciBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSBUUlVFfQpWYXJpYWJsZTwtYygiYEHDsW8gTmFjaW1pZW50b2AiLCJgR2VuZXJvYCIsImBGZWNoYUFsdGFgIiwiYFByaW1lck1lc2AiLCJgNHRvTWVzYCIsImBQdWVzdG9gIiwiYERlcGFydGFtZW50b2AiLCJgU2FsYXJpb0RpYXJpb2AiLCJgTHVnYXJOYWNpbWllbnRvYCIsImBNdW5pY2lwaW9gIiwiYEVzdGFkb2AiLCJgRXN0YWRvQ2l2aWxgIiwiYEVtcGxlYWRvYCIpClRpcG88LWMoIkN1YW50aXRhdGl2YSAoZGlzY3JldGEpIiwiQ3VhbGl0YXRpdmEgKG5vbWluYWwpIiwgIkN1YW50aXRhdGl2YSAoZGlzY3JldGEpIiwgIkN1YW50aXRhdGl2YSAoZGlzY3JldGEpIiwiQ3VhbnRpdGF0aXZhIChkaXNjcmV0YSkiLCAiQ3VhbGl0YXRpdmEgKG5vbWluYWwpIiwgIkN1YWxpdGF0aXZhIChub21pbmFsKSIsICJDdWFudGl0YXRpdmEgKGNvbnRpbnVvKSIsIkN1YWxpdGF0aXZhIChub21pbmFsKSIsICJDdWFsaXRhdGl2YSAobm9taW5hbCkiLCJDdWFsaXRhdGl2YSAobm9taW5hbCkiLCJDdWFsaXRhdGl2YSAobm9taW5hbCkiLCAiQ3VhbGl0YXRpdmEgKG5vbWluYWwpIikKdGFibGU8LWRhdGEuZnJhbWUoVmFyaWFibGUsVGlwbykKa25pdHI6OmthYmxlKHRhYmxlKQpgYGAKCiMjIyMgTWVkaWNpw7NuIHZhcmlhYmxlcyBDb2xhYm9yYWRvcmVzCgpgYGB7ciBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSBUUlVFfQpWYXJpYWJsZTwtYygiYEHDsW8gTmFjaW1pZW50b2AiLCJgR2VuZXJvYCIsImBGZWNoYUFsdGFgIiwiYFByaW1lck1lc2AiLCJgNHRvTWVzYCIsImBQdWVzdG9gIiwiYERlcGFydGFtZW50b2AiLCJgU2FsYXJpb0RpYXJpb2AiLCJgTHVnYXJOYWNpbWllbnRvYCIsImBNdW5pY2lwaW9gIiwiYEVzdGFkb2AiLCJgRXN0YWRvQ2l2aWxgIiwiYEVtcGxlYWRvYCIpCk1lZGljaW9uPC1jKCJBw7FvIiwiTm8gYXBsaWNhIiwiQcOxbyIsICJBw7FvIiwiQcOxbyIsICJObyBhcGxpY2EiLCAiTm8gYXBsaWNhIiwgIlBlc29zIG1leGljYW5vcyIsIk5vIGFwbGljYSIsIk5vIGFwbGljYSIsIk5vIGFwbGljYSIsICJObyBhcGxpY2EiLCJObyBhcGxpY2EiKQoKdGFibGUyPC1kYXRhLmZyYW1lKFZhcmlhYmxlLE1lZGljaW9uKQprbml0cjo6a2FibGUodGFibGUyKQpgYGAKCiMjIyMgQmFqYXMKYGBge3IgZWNobyA9IEZBTFNFLCByZXN1bHRzID0gVFJVRX0KVmFyaWFibGU8LWMoImBOb21icmUgQ29tcGxldG9gIiwiYEVkYWRgIiwiYEdlbmVyb2AiLCJgRmVjaGFBbHRhYCIsImBNb3Rpdm8gZGUgQmFqYWAiLCJgRHVyYWNpw7NuYCIsICJgUHVlc3RvYCIsImBTYWxhcmlvRGlhcmlvYCIsImBFc3RhZG9gIiwiYEVzdGFkb0NpdmlsYCIpClRpcG88LWMoIkN1YWxpdGF0aXZhIChub21pbmFsKSIsICJDdWFudGl0YXRpdmEgKGRpc2NyZXRhKSIsIkN1YWxpdGF0aXZhIChub21pbmFsKSIsICJDdWFudGl0YXRpdmEgKGRpc2NyZXRhKSIsICJDdWFudGl0YXRpdmEgKGRpc2NyZXRhKSIsICJDdWFudGl0YXRpdmEgKGRpc2NyZXRhKSIsIkN1YWxpdGF0aXZhIChub21pbmFsKSIsICJDdWFudGl0YXRpdmEgKGNvbnRpbnVvKSIsIkN1YWxpdGF0aXZhIChub21pbmFsKSIsICJDdWFsaXRhdGl2YSAobm9taW5hbCkiKQp0YWJsZTwtZGF0YS5mcmFtZShWYXJpYWJsZSxUaXBvKQprbml0cjo6a2FibGUodGFibGUpCmBgYAoKIyMjIyBNZWRpY2nDs24gdmFyaWFibGVzIEJhamFzCgpgYGB7ciBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSBUUlVFfQpWYXJpYWJsZTwtYygiYE5vbWJyZSBDb21wbGV0b2AiLCJgRWRhZGAiLCJgR2VuZXJvYCIsImBGZWNoYUFsdGFgIiwiYE1vdGl2byBkZSBCYWphYCIsImBEdXJhY2nDs25gIiwgImBQdWVzdG9gIiwiYFNhbGFyaW9EaWFyaW9gIiwiYEVzdGFkb2AiLCJgRXN0YWRvQ2l2aWxgIikKCk1lZGljaW9uPC1jKCJObyBhcGxpY2EiLCJBw7FvcyIsICJObyBhcGxpY2EiLCAiQcOxbyIsICJObyBhcGxpY2EiLCJEw61hcyIsIk5vIGFwbGljYSIsICJQZXNvcyBNZXhpY2Fub3MiLCJObyBhcGxpY2EiLCAiTm8gYXBsaWNhIikKCnRhYmxlMjwtZGF0YS5mcmFtZShWYXJpYWJsZSxNZWRpY2lvbikKa25pdHI6OmthYmxlKHRhYmxlMikKYGBgCgojIyBiLiBEZWxpdmVyeSBwbGFuCgojIyMgTGltcGllemEKTGEgbGltcGllemEgeSBtb2RpZmljYWNpw7NuIGRlIGZpbGFzIHkgY29sdW1uYXMgcmVzcGVjdG8gYSBsYXMgdmFyaWFibGVzIHNlIHJlYWxpesOzIGRpcmVjdGFtZW50ZSBlbiBFeGNlbCBwb3IgY3Vlc3Rpb25lcyBkZSBmYWNpbGlkYWQgeWEgcXVlIGxhIGJhc2UgZXN0YWJhIG9yZGVuYWRhIGRlIHVuYSBtYW5lcmEgZW4gZG9uZGUgUiByZXN1bHRhcsOtYSBtdWNobyBtw6FzIGNvbXBsaWNhZG8uCgpgYGB7cn0KIyBUw6ljbmljYSA0LiBDb252ZXJ0aXIgdGlwb3MgZGUgZGF0b3MKCiMgQ29udmVydGlyIGRlIGNhcmFjdGVyIGEgZmVjaGEKZHAxIDwtIGRwCmRwMSRGZWNoYTwtYXMuRGF0ZShkcDEkRmVjaGEsZm9ybWF0PSIlbS8lZC8lWSIpIAoKIyBDb250YWJpbGl6YXIgc2kgaGF5IE5BwrRTIGRlbnRybyBkZSBsYSBiYXNlIGRlIGRhdG9zIGFjdHVhbCBwYXJhIHN1c3RpdHVpcmxvcyBjb24gbGEgbWVkaWEsIG1vZGEgbyBtZWRpYW5hLgoKY29sU3Vtcyhpcy5uYShkcDEpKQojIFZlbW9zIHF1ZSBlbiBsYSBiYXNlIGRlIGRhdG9zIG5vIGhheSBOQcK0UyAKCiMjIEV4cG9ydGFtb3MgbGEgYmFzZSBkZSBkYXRvcyBsaW1waWEKd3JpdGUuY3N2KGRwMSwgZmlsZSA9IkRFTElWRVJZX0ZJTkFMX0xJTVBJQS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIyMgwr9DdcOhbnRhcyB2YXJpYWJsZXMgeSBjdWFudG9zIHJlZ2lzdHJvcyB0aWVuZSBsYSBiYXNlIGRlIGRhdG9zPwpEZW50cm8gZGUgbGEgYmFzZSBkZSBkYXRvcyBzZSBjdWVudGEgY29uIDQgdmFyaWFibGVzIHkgMjI4IHJlZ2lzdHJvcy4KCiMjIyBDbGFzaWZpY2FjacOzbiB5IGVzY2FsYSBkZSBtZWRpY2nDs24KCiMjIyMgQ2xhc2lmaWNhY2nDs24KYGBge3J9ClZhcmlhYmxlPC1jKCJgSUQgRmVjaGFgIiwiYEZlY2hhYCIsImBDbGllbnRlc2AiLCJgUGVkaWRvc2AiKQpUaXBvPC1jKCJDdWFsaXRhdGl2YSAob3JkaW5hbCkiLCAiQ3VhbnRpdGF0aXZhIChkaXNjcmV0YSkiLCJDdWFsaXRhdGl2YSAobm9taW5hbCkiLCJDdWFudGl0YXRpdmEoZGlzY3JldGEpIikKdGFibGU8LWRhdGEuZnJhbWUoVmFyaWFibGUsVGlwbykKa25pdHI6OmthYmxlKHRhYmxlKSAKYGBgCgojIyMjIEVzY2FsYSBkZSBtZWRpY2nDs24KYGBge3J9ClZhcmlhYmxlPC1jKCJgSUQgRmVjaGFgIiwiYEZlY2hhYCIsImBDbGllbnRlc2AiLCJgUGVkaWRvc2AiKQpNZWRpY2lvbjwtYygiTsO6bWVybyIsICJEw61hLCBtZXMgeSBhw7FvIiwiTm9tYnJlcyIsIk7Dum0uIGRlIG9yZGVuZXMiKQp0YWJsZTwtZGF0YS5mcmFtZShWYXJpYWJsZSxNZWRpY2lvbikKa25pdHI6OmthYmxlKHRhYmxlKSAKYGBgCgojIyBjLiBEZWxpdmVyeSBQZXJmb3JtYW5jZSAgCgojIyMgTGltcGllemEKU2UgcmVhbGl6w7MgdW5hIGxpbXBpYSBwcmV2aWEgYSBsYSBiYXNlIGRlIGRhdG9zIGRlYmlkbyBhIHF1ZSBubyBzZSBwb2TDrWEgbWFuZWphciBlbiBSLCB5YSBxdWUgZWwgZm9ybWF0byBlbiBxdWUgc2UgZW5jb250cmFiYSAgbm8gcGVybWl0w61hIHF1ZSBSIHB1ZGllcmEgZW50ZW5kZXIgY3VhbGVzIGVyYW4gbGFzIHZhcmlhYmxlcyBkZSBudWVzdHJhIGJhc2UgZGUgZGF0b3MsIHBvciBsbyB0YW50byBsYXMgbW9kaWZpY2FjaW9uZXMgeSBsaW1waWV6YXMgcXVlIHNlIHJlYWxpemFyb24gZnVlIGxhIHTDqWNuaWNhIGRlICdSZW1vdmVyIHZhbG9yZXMgaXJyZWxldmFudGVzJyBlbiBlc3RlIGNhc28gcXVpdGFtb3MgbGEgY29uY2x1c2nDs24gcG9ycXVlIG5vIHRlbmRyw61hIHZhbG9yIGVuIGxhIGJhc2UgZGUgZGF0b3MsIGVsaW1pbmFtb3MgdGFyZ2V0IChob3JhcykgeSB0b21hbW9zIGVsIHZhbG9yIGRlIGNhZGEgaW5pY2lvIGRlIG1lcyBwYXJhIGNvbXBhcmFyIHByaW5jaXBpbyBkZSBtZXMgY29uIG1lcywgZGVzcHXDqXMgZW4gUiBzZSB0cmFiYWpvIGNvbiBsYSAqKnTDqWNuaWNhIGRlIGNvbnZlcnRpciB0aXBvcyBkZSBkYXRvcyoqIGVuIGVzdGUgY2FzbyBkZSBjYXJhY3RlciBhIGZlY2hhIHkgY2FyYWN0ZXIgYSBob3JhLiAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgVMOpY25pY2EgNC4gQ29udmVydGlyIHRpcG9zIGRlIGRhdG9zCgojIENvbnZlcnRpciBkZSBjYXJhY3RlciBhIGZlY2hhCmJkX2RlbGl2ZXJ5X3BlcmYyIDwtIGJkX2RlbGl2ZXJ5X3BlcmYKYmRfZGVsaXZlcnlfcGVyZjIkZmVjaGEgPC0gYXMuRGF0ZShiZF9kZWxpdmVyeV9wZXJmMiRmZWNoYSwgZm9ybWF0ID0iJWQvJW0vJXkiKQpsaWJyYXJ5KHRpYmJsZSkKdGliYmxlKGJkX2RlbGl2ZXJ5X3BlcmYyKSAgCgojIENhbWJpYXIgbG9zIG5vbWJyZXMgZGUgbGFzIHZhcmlhYmxlcyBtw6FzIGNvcnRhcyB5IGVzcGVjw61maWNhcwoKbmFtZXMoYmRfZGVsaXZlcnlfcGVyZjIpIFszXSA9ICJkZWxheV9wZXJmb3JtYW5jZSIKbmFtZXMoYmRfZGVsaXZlcnlfcGVyZjIpCgojIEV4cG9ydGFyCmJkX2RlbGl2ZXJ5X3BlcmYzIDwtIGJkX2RlbGl2ZXJ5X3BlcmYyCndyaXRlLmNzdihiZF9kZWxpdmVyeV9wZXJmMywgZmlsZSA9ImRlbGl2ZXJ5cGVyZm9ybWFuY2VfRk9STV9saW1waWEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMjIMK/Q3XDoW50YXMgdmFyaWFibGVzIHkgY3VhbnRvcyByZWdpc3Ryb3MgdGllbmUgbGEgYmFzZSBkZSBkYXRvcz8KRGVudHJvIGRlIGxhIGJhc2UgZGUgZGF0b3Mgc2UgY3VlbnRhIGNvbiAzIHZhcmlhYmxlcyB5IDUyIHJlZ2lzdHJvcy4KCiMjIyBDbGFzaWZpY2FjacOzbiB5IGVzY2FsYSBkZSBtZWRpY2nDs24KCiMjIyMgQ2xhc2lmaWNhY2nDs24KYGBge3J9ClZhcmlhYmxlIDwtYygiRmVjaGEiLCAiQ2xpZW50ZSIsICJEaWZlcmVuY2lhIikKVGlwbyA8LWMoIkN1YW50aXRhdGl2YSAoY29udGludWEpIiwiQ3VhbGl0YXRpdmEgKG5vbWluYWwpIiwiQ3VhbnRpdGF0aXZhIChjb250aW51YSkiKQp0YWJsZTwtZGF0YS5mcmFtZShWYXJpYWJsZSwgVGlwbykKa25pdHI6OmthYmxlKHRhYmxlKQpgYGAKCiMjIyMgRXNjYWxhIGRlIG1lZGljacOzbgpgYGB7cn0KVmFyaWFibGUgPC1jKCJGZWNoYSIsICJDbGllbnRlIiwgIkRpZmVyZW5jaWEiKQpNZWRpY2nDs24gPC1jKCJEaWEsIG1lcyB5IGHDsW8iLCJOb21icmUiLCJNaW51dG9zIikKdGFibGU8LWRhdGEuZnJhbWUoVmFyaWFibGUsIE1lZGljacOzbikKa25pdHI6OmthYmxlKHRhYmxlKQpgYGAKCiMjIGQuIFByb2R1Y2Npw7NuCgojIyMgTGltcGllemEKU2UgdHJhYmFqbyBlbiBsYSBiYXNlIGRlIGRhdG9zIHBhcmEgcHJpbWVybyBlbGltaW5hciBjb2x1bW5hcyBxdWUgbm8gc29uIHJlbGV2YW50ZXMgcGFyYSBlbCBhbmFsaXNpcywgZGVzcHXDqXMgY29udmVydGlyIGRlIGNhcmFjdGVyIGEgTi9BIHBhcmEgcG9kZXIgZWxpbWluYXIgbG9zIGVzcGFjaW9zIGVuIGJsYW5jbyBzaW4gZGF0b3MgeSBwb3Igw7psdGltbyBzZSByZWVtcGxhesOzIGxvcyBOQSdzIGNvbiBlbCBwcm9tZWRpbyBwYXJhIG9idGVuZXIgdW4gYXByb3hpbWFuZG8gZGVsIHRpZW1wbyBkZSBwcm9kdWNpb24gZW4gbG9zIGRpYXMgcXVlIGVzdGEgZW4gYmxhbmNvIG8gTi9BLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMjIyBUZWNuaWNhIDEuICBSZW1vdmVyIHZhbG9yZXMgaXJyZWxldmFudGVzCgpkYXRhMSA8LSBkYXRhCmRhdGExPC1zdWJzZXQoZGF0YTEsc2VsZWN0PS1jKE5vLixJRC5GT1JNLFBST0RVQ1RPLFgsSFIuLkZJTixFU1RBQ0lPTi5BUlJBTlFVRSxJTklDSU8uU0VQLlVQLEZJTi5JTklDSU8uREUuU0VQLlVQLElOSUNJTy5kZS5QUk9DRVNPLEZJTi5kZS5QUk9DRVNPLFRJRU1QTy5DQUxJREFELFRJRU1QTy5NQVRFUklBTEVTLE1FUk1BUy5NYXF1aW5hcy4pKQpzdHIoZGF0YTEpCgojIyMjIFRlY25pY2EgNC4gQ29udmVydGlyIHRpcG9zIGRlIGRhdG9zCmRhdGEyIDwtIGRhdGExCmRhdGEyJFRNTy4uTUlOLiA8LSBzdWJzdHIoZGF0YTIkVE1PLi5NSU4uLCBzdGFydCA9IDEsIHN0b3AgPSAyKQojdGliYmxlKGRhdGEyKSAgCmRhdGEyJFRNTy4uTUlOLiA8LSBhcy5pbnRlZ2VyKGRhdGEyJFRNTy4uTUlOLikKc3RyKGRhdGEyKSAgCgpkYXRhMyA8LSBkYXRhMgpkYXRhMyRMYW1pbmFzLnByb2Nlc2FkYXMgPC0gc3Vic3RyKGRhdGEzJExhbWluYXMucHJvY2VzYWRhcywgc3RhcnQgPSAxLCBzdG9wID0gMikKI3RpYmJsZShkYXRhMykgIApkYXRhMyRMYW1pbmFzLnByb2Nlc2FkYXMgPC0gYXMuaW50ZWdlcihkYXRhMyRMYW1pbmFzLnByb2Nlc2FkYXMpCnN0cihkYXRhMykgCgpkYXRhMyRGZWNoYSA8LSBhcy5EYXRlKGRhdGEzJEZlY2hhLCBmb3JtYXQgPSIlZC8lbS8leSIpCgojIyMjIFRlY25pY2EgNS4gVmFsb3JlcyBmYWx0YW50ZXMKIyBSZW1wbGF6YXIgbG9zIHZhbG9yZXMgcG9yIGxhIG1lZGlhCmRhdGE0IDwtIGRhdGEzCmRhdGE0JFRNTy4uTUlOLltpcy5uYShkYXRhNCRUTU8uLk1JTi4pXTwtbWVhbihkYXRhNCRUTU8uLk1JTi4sIG5hLnJtID0gVFJVRSkKc3VtbWFyeSAoZGF0YTQpIAoKZGF0YTUgPC0gZGF0YTQKZGF0YTUkUElFWkFTLlBST0cuW2lzLm5hKGRhdGE1JFBJRVpBUy5QUk9HLildPC1tZWFuKGRhdGE1JFBJRVpBUy5QUk9HLiwgbmEucm0gPSBUUlVFKQpzdW1tYXJ5IChkYXRhNSkgCgpkYXRhNiA8LSBkYXRhNQpkYXRhNiRMYW1pbmFzLnByb2Nlc2FkYXNbaXMubmEoZGF0YTYkTGFtaW5hcy5wcm9jZXNhZGFzKV08LW1lYW4oZGF0YTYkTGFtaW5hcy5wcm9jZXNhZGFzLCBuYS5ybSA9IFRSVUUpCnN1bW1hcnkgKGRhdGE2KQoKIyMjIyBFeHBvcnRhciBiYXNlIGRlIGRhdG9zCndyaXRlLmNzdihkYXRhNiwgZmlsZSA9InByb2R1Y2Npw7NuX0ZPUk1fbGltcGlhLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIyDCv0N1w6FudGFzIHZhcmlhYmxlcyB5IGN1YW50b3MgcmVnaXN0cm9zIHRpZW5lIGxhIGJhc2UgZGUgZGF0b3M/CkRlbnRybyBkZSBsYSBiYXNlIGRlIGRhdG9zIHNlIGN1ZW50YSBjb24gMTggdmFyaWFibGVzIHkgNTMwMCByZWdpc3Ryb3MuCgojIyMgQ2xhc2lmaWNhY2nDs24geSBlc2NhbGEgZGUgbWVkaWNpw7NuCgojIyMjIENsYXNpZmljYWNpw7NuCmBgYHtyfQpWYXJpYWJsZSA8LWMoIkZlY2hhIiwgIkNsaWVudGUiLCAiUGllemFzIHByb2cuIiwgIlRpZW1wbyBtaW4uIiwgIkzDoW1pbmFzIHByb2Nlc2FkYXMiKQpUaXBvIDwtYygiQ3VhbGl0YXRpdmEgKG5vbWluYWwpIiwiQ3VhbGl0YXRpdmEgKG5vbWluYWwpIiwgIkN1YW50aXRhdGl2YSAoZGlzY3JldGEpIiwgIkN1YW50aXRhdGl2YSAoZGlzY3JldGEpIiwgIkN1YW50aXRhdGl2YSAoZGlzY3JldGEpIikKdGFibGU8LWRhdGEuZnJhbWUoVmFyaWFibGUsIFRpcG8pCmtuaXRyOjprYWJsZSh0YWJsZSkKYGBgCgojIyMjIEVzY2FsYSBkZSBtZWRpY2nDs24KYGBge3J9ClZhcmlhYmxlIDwtYygiRmVjaGEiLCAiQ2xpZW50ZSIsICJQaWV6YXMgcHJvZy4iLCAiVGllbXBvIG1pbi4iLCAiTMOhbWluYXMgcHJvY2VzYWRhcyIpCk1lZGljacOzbiA8LWMoIkTDrWEsIG1lcyB5IGHDsW8iLCAiTm9tYnJlIiwgIkNhbnRpZGFkIGRlIHBpZXphcyIsICJNaW51dG9zIiwgIlBpZXphcyBmaW5hbGl6YWRhcyIpCnRhYmxlPC1kYXRhLmZyYW1lKFZhcmlhYmxlLCBNZWRpY2nDs24pCmtuaXRyOjprYWJsZSh0YWJsZSkKYGBgCgoKIyMgZS4gTWVybWEgIAoKIyMjIExpbXBpZXphClNlIHJlYWxpesOzIHVuYSBsaW1waWEgcHJldmlhIGEgbGEgYmFzZSBkZSBkYXRvcyBkZWJpZG8gYSBxdWUgbm8gc2UgcG9kw61hIG1hbmVqYXIgZW4gUiwgeWEgcXVlIGVsIGZvcm1hdG8gZW4gcXVlIHNlIGVuY29udHJhYmEgbm8gcGVybWl0w61hIHF1ZSBSIHB1ZGllcmEgZW50ZW5kZXIgY3VhbGVzIGVyYW4gbGFzIHZhcmlhYmxlcyBkZSBudWVzdHJhIGJhc2UgZGUgZGF0b3MgeSB1bmEgdmV6IHRlbmllbmRvIGxhIGJhc2UgZGUgZGF0b3MgbGFzIHTDqWNuaWNhcyBxdWUgdXRpbGl6YW1vcyBlbiBlbCBwcm9ncmFtYSBmdWUgKipSZW1vdmVyIHZhbG9yZXMgaXJyZWxldmFudGVzKiogZGVqYW5kbyBsYXMgdmFyaWFibGVzIGNvbiBtYXlvciBpbXBvcnRhbmNpYSBjb21vOiBGZWNoYSwgQ2FudGlkYWQgeSBVYmljYWNpw7NuIGRlIG9yaWdlbiB5IGxhIHNlZ3VuZGEgdMOpY25pY2EgcXVlIHV0aWxpemFtb3MgZnVlICoqQ29udmVydGlyIGRlIGNhcmFjdGVyIGEgZmVjaGEqKiBwYXJhIHRlbmVyIGxhIGZlY2hhIGVuIGVudGVyby4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgVMOpY25pY2EuIFJlbW92ZXIgdmFsb3JlcyBpcnJlbGV2YW50ZXMKCiMgRWxpbWluYXIgY29sdW1uYXMKc3VtbWFyeShiZF9tZXJtYSkKCmJkX21lcm1hMiA8LSBiZF9tZXJtYQpiZF9tZXJtYTIgPC0gc3Vic2V0IChiZF9tZXJtYTIsIHNlbGVjdCA9IC1jIChNZXMpKQoKIyBFbGltaW5hciByZW5nbG9uZXMKYmRfbWVybWEzIDwtIGJkX21lcm1hMgpiZF9tZXJtYTMgPC0gYmRfbWVybWEzW2JkX21lcm1hMyRGZWNoYSA+IDAsIF0KCgojIFTDqWNuaWNhLiBDb252ZXJ0aXIgdGlwb3MgZGUgZGF0b3MKCiMgQ29udmVydGlyIGRlIGNhcmFjdGVyIGEgZmVjaGEKYmRfbWVybWE0IDwtIGJkX21lcm1hMwpiZF9tZXJtYTQkRmVjaGEgPC0gYXMuRGF0ZShiZF9tZXJtYTQkRmVjaGEsIGZvcm1hdCA9IiVkLyVtLyV5IikKCiMgRXhwb3J0YXIKYmRfbWVybWE1IDwtIGJkX21lcm1hNAp3cml0ZS5jc3YoYmRfbWVybWE1LCBmaWxlID0ibWVybWFfRk9STV9saW1waWEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAojIyMgwr9DdcOhbnRhcyB2YXJpYWJsZXMgeSBjdWFudG9zIHJlZ2lzdHJvcyB0aWVuZSBsYSBiYXNlIGRlIGRhdG9zPwpEZW50cm8gZGUgbGEgYmFzZSBkZSBkYXRvcyBzZSBjdWVudGEgY29uIDMgdmFyaWFibGVzIHkgNjAgcmVnaXN0cm9zLgoKIyMjIENsYXNpZmljYWNpw7NuIHkgZXNjYWxhIGRlIG1lZGljacOzbgoKIyMjIyBDbGFzaWZpY2FjacOzbgpgYGB7cn0KVmFyaWFibGUgPC1jKCJGZWNoYSIsICJNZXJtYSIpClRpcG8gPC1jKCJDdWFsaXRhdGl2YSAobm9taW5hbCkiLCAiQ3VhbnRpdGF0aXZhIChkaXNjcmV0YSkiKQp0YWJsZTwtZGF0YS5mcmFtZShWYXJpYWJsZSwgVGlwbykKa25pdHI6OmthYmxlKHRhYmxlKQpgYGAKCiMjIyMgRXNjYWxhIGRlIG1lZGljacOzbgpgYGB7cn0KVmFyaWFibGUgPC1jKCJGZWNoYSIsICJNZXJtYSIpCk1lZGljacOzbiA8LWMoIkTDrWEsIG1lcyB5IGHDsW8iLCAiS2lsb3MiKQp0YWJsZTwtZGF0YS5mcmFtZShWYXJpYWJsZSwgTWVkaWNpw7NuKQprbml0cjo6a2FibGUodGFibGUpCmBgYAoKIyMgZi4gU2NyYXAKCiMjIyDCv0N1w6FudGFzIHZhcmlhYmxlcyB5IGN1YW50b3MgcmVnaXN0cm9zIHRpZW5lIGxhIGJhc2UgZGUgZGF0b3M/CkRlbnRybyBkZSBsYSBiYXNlIGRlIGRhdG9zIHNlIGN1ZW50YSBjb24gOSB2YXJpYWJsZXMgeSAyNTAgcmVnaXN0cm9zLgoKIyMjIExpbXBpZXphClNlIHJlYWxpesOzIHVuYSBsaW1waWEgcHJldmlhIGEgbGEgYmFzZSBkZSBkYXRvcyBkZWJpZG8gYSBxdWUgbm8gc2UgcG9kw61hIG1hbmVqYXIgZW4gUiwgeWEgcXVlIGVsIGZvcm1hdG8gZW4gcXVlIHNlIGVuY29udHJhYmEgbm8gcGVybWl0w61hIHF1ZSBSIHB1ZGllcmEgZW50ZW5kZXIgY3VhbGVzIGVyYW4gbGFzIHZhcmlhYmxlcyBkZSBudWVzdHJhIGJhc2UgZGUgZGF0b3MgeSB1bmEgdmV6IHRlbmllbmRvIGxhIGJhc2UgZGUgZGF0b3MgbGFzIHTDqWNuaWNhcyBxdWUgdXRpbGl6YW1vcyBlbiBlbCBwcm9ncmFtYSBmdWUgKipSZW1vdmVyIHZhbG9yZXMgaXJyZWxldmFudGVzKiogZGVqYW5kbyBsYXMgdmFyaWFibGVzIGNvbiBtYXlvciBpbXBvcnRhbmNpYSBjb21vOiBGZWNoYSwgQ2FudGlkYWQgeSBVYmljYWNpw7NuIGRlIG9yaWdlbiB5IGxhIHNlZ3VuZGEgdMOpY25pY2EgcXVlIHV0aWxpemFtb3MgZnVlICoqQ29udmVydGlyIGRlIGNhcmFjdGVyIGEgZmVjaGEqKiBwYXJhIHRlbmVyIGxhIGZlY2hhIGVuIGVudGVyby4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIyMgVMOpY25pY2EuIFJlbW92ZXIgdmFsb3JlcyBpcnJlbGV2YW50ZXMKCiMjIyMgRWxpbWluYXIgY29sdW1uYXMKc3VtbWFyeShiZF9zY3JhcCkKCmJkX3NjcmFwMiA8LSBiZF9zY3JhcApiZF9zY3JhcDIgPC0gc3Vic2V0IChiZF9zY3JhcDIsIHNlbGVjdCA9IC1jIChSZWZlcmVuY2lhLCBIb3JhLCBQcm9kdWN0bywgVW5pZGFkLmRlLm1lZGlkYSwgVWJpY2FjacOzbi5kZS5kZXNlY2hvLCBFc3RhZG8pKQoKc3VtbWFyeSAoYmRfc2NyYXAyKQoKIyMjIyBUw6ljbmljYS4gQ29udmVydGlyIHRpcG9zIGRlIGRhdG9zCgojIyMjIENvbnZlcnRpciBkZSBjYXJhY3RlciBhIGZlY2hhCmJkX3NjcmFwMyA8LSBiZF9zY3JhcDIKYmRfc2NyYXAzJEZlY2hhIDwtIGFzLkRhdGUoYmRfc2NyYXAzJEZlY2hhLCBmb3JtYXQgPSIlZC8lbS8leSIpCnN1bW1hcnkoYmRfc2NyYXAzKQoKIyBDYW1iaWFyIGxvcyBub21icmVzIGRlIGxhcyB2YXJpYWJsZXMgbcOhcyBjb3J0YXMgeSBlc3BlY8OtZmljYXMKCm5hbWVzKGJkX3NjcmFwMykgWzNdID0gIlViaV9vcmlnZW4iCm5hbWVzKGJkX3NjcmFwMykKCiMjIyMgRXhwb3J0YXIgYmFzZSBkZSBkYXRvcwpiZF9zY3JhcDQgPC0gYmRfc2NyYXAzCndyaXRlLmNzdihiZF9zY3JhcDQsIGZpbGUgPSJzY3JhcF9GT1JNX2xpbXBpYS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIyMgwr9DdcOhbnRhcyB2YXJpYWJsZXMgeSBjdWFudG9zIHJlZ2lzdHJvcyB0aWVuZSBsYSBiYXNlIGRlIGRhdG9zPwpEZW50cm8gZGUgbGEgYmFzZSBkZSBkYXRvcyBzZSBjdWVudGEgY29uIDkgdmFyaWFibGVzIHkgMjUwIHJlZ2lzdHJvcy4KCiMjIyBDbGFzaWZpY2FjacOzbiB5IGVzY2FsYSBkZSBtZWRpY2nDs24KCiMjIyMgQ2xhc2lmaWNhY2nDs24KYGBge3J9ClZhcmlhYmxlIDwtYygiRmVjaGEiLCAiQ2FudGlkYWQiLCAiVWJpY2FjacOzbiBPcmlnZW4iKQpUaXBvIDwtYygiQ3VhbGl0YXRpdmEgKG5vbWluYWwpIiwgIkN1YW50aXRhdGl2YSAoZGlzY3JldGEpIiwgIkN1YWxpdGF0aXZhIChub21pbmFsKSIpCnRhYmxlPC1kYXRhLmZyYW1lKFZhcmlhYmxlLCBUaXBvKQprbml0cjo6a2FibGUodGFibGUpCmBgYAoKIyMjIyBFc2NhbGEgZGUgbWVkaWNpw7NuCmBgYHtyfQpWYXJpYWJsZSA8LWMoIkZlY2hhIiwgIkNhbnRpZGFkIiwgIlViaWNhY2nDs24gT3JpZ2VuIikKTWVkaWNpw7NuIDwtYygiRMOtYSwgbWVzIHkgYcOxbyIsICJLaWxvcyIsICJOb21icmUgQXJlYSBGT1JNIikKdGFibGU8LWRhdGEuZnJhbWUoVmFyaWFibGUsIE1lZGljacOzbikKa25pdHI6OmthYmxlKHRhYmxlKQpgYGAKCiMjIyBBbsOhbGlzaXMgZXN0YWTDrXN0aWNvIGRlc2NyaXB0aXZvIEZPUk0KCiMjIyMgVGFibGFzIGRlIGZyZWN1ZW5jaWEKCiMjIyMjIEJEIFJlY3Vyc29zIGh1bWFub3M6IENvbGFib3JhZG9yZXMKYGBge3J9CmJkX2NvbGFiZiA8LSB0YWJsZShjb2xhYl9maW5hbCRnZW5lcm8pCmtuaXRyOjprYWJsZShiZF9jb2xhYmYpCmBgYAoKYGBge3J9CmJkX2NvbGFiZjIgPC0gdGFibGUoY29sYWJfZmluYWwkY2l2aWwpCmtuaXRyOjprYWJsZShiZF9jb2xhYmYyKQpgYGAKCmBgYHtyfQpiZF9jb2xhYmYzIDwtIHRhYmxlKGNvbGFiX2ZpbmFsJG1waW8pCmtuaXRyOjprYWJsZShiZF9jb2xhYmYzKQpgYGAKCmBgYHtyfQpiZF9jb2xhYmY0IDwtIHRhYmxlKGNvbGFiX2ZpbmFsJGVzdGFkbykKa25pdHI6OmthYmxlKGJkX2NvbGFiZjQpCmBgYAoKYGBge3J9CmJkX2NvbGFiZjUgPC0gdGFibGUoY29sYWJfZmluYWwkcHVlc3RvKQprbml0cjo6a2FibGUoYmRfY29sYWJmNSkKYGBgCgojIyMjIyBCRCBSZWN1cnNvcyBodW1hbm9zOiBCYWphcwpgYGB7cn0KYmRfYmFqYXNmIDwtIHRhYmxlKGJhamFzX2ZpbmFsJG1vdGl2b19iYWphKQprbml0cjo6a2FibGUoYmRfYmFqYXNmKQpgYGAKCmBgYHtyfQpiZF9iYWphc2YyIDwtIHRhYmxlKGJhamFzX2ZpbmFsJGdlbmVybykKa25pdHI6OmthYmxlKGJkX2JhamFzZjIpCmBgYAoKYGBge3J9CmJkX2JhamFzZjMgPC0gdGFibGUoYmFqYXNfZmluYWwkcHVlc3RvKQprbml0cjo6a2FibGUoYmRfYmFqYXNmMykKYGBgCgpgYGB7cn0KYmRfYmFqYXNmNCA8LSB0YWJsZShiYWphc19maW5hbCRlLmNpdmlsKQprbml0cjo6a2FibGUoYmRfYmFqYXNmNCkKYGBgCgojIyMjIyBUYWJsYXMgY3J1emFkYXMKCiMjIyMjIyBSZWN1cnNvcyBodW1hbm9zOiBDb2xhYm9yYWRvcmVzCmBgYHtyfQpjcnV6YWRhMTwtdGFibGUoY29sYWJfZmluYWwkc2FsYXJpb19kaWFyaW8sY29sYWJfZmluYWwkZ2VuZXJvKQprbml0cjo6a2FibGUoY3J1emFkYTEpCmBgYAoKIyMjIyMjIFJlY3Vyc29zIGh1bWFub3M6IEJhamFzCmBgYHtyfQpjcnV6YWRhMTwtdGFibGUoYmFqYXNfZmluYWwkZWRhZCwgYmFqYXNfZmluYWwkc2FsYXJpb19kaWFyaW8pCmtuaXRyOjprYWJsZShjcnV6YWRhMSkKYGBgCgojIyMjIyMgUHJvZHVjY2nDs24KYGBge3J9CmNydXphZGExPC10YWJsZShkYXRhNiRGZWNoYSxkYXRhNiRQSUVaQVMuUFJPRy4pCmtuaXRyOjprYWJsZShjcnV6YWRhMSkKYGBgCgpgYGB7cn0KY3J1emFkYTI8LXRhYmxlKGRhdGE2JExhbWluYXMucHJvY2VzYWRhcyxkYXRhNiRUTU8uLk1JTi4pCmtuaXRyOjprYWJsZShjcnV6YWRhMikKYGBgCgojIyMjIyBHcsOhZmljb3MgZGUgZGF0b3MgY3VhbGl0YXRpdm9zIHkgY3VhbnRpdGF0aXZvcwoKIyMjIyMgQ29sYWJvcmFkb3JlcwojIyMjIyMgUGllIGNoYXJ0CmBgYHtyfQpwcm9wb3JjaW9uZXMgPC0gYyg1OSwgNDUpICMgY3JlYW1vcyB1biB2ZWN0b3IgY29uIHByb3BvcmNpb25lcwpldGlxdWV0YXMgPC0gYygiRkVNRU5JTk8iLCAiTUFTQ1VMSU5PIikgIyB2ZWN0b3IgY29uIGV0aXF1ZXRhcwpwY3QgPC0gcm91bmQocHJvcG9yY2lvbmVzL3N1bShwcm9wb3JjaW9uZXMpKjEwMCkKZXRpcXVldGFzIDwtIHBhc3RlKGV0aXF1ZXRhcyxwY3QpICMgQcOxYWRpbW9zIHBvcmNlbnRhamVzIGEgZXRpcXVldGFzCmV0aXF1ZXRhcyA8LSBwYXN0ZShldGlxdWV0YXMsIiUiLHNlcD0iIikgIyBBw7FhZGltb3MgZWwgc8OtbWJvbG8gZGUgJQoKcGllKHByb3BvcmNpb25lcyxsYWJlbHMgPSBldGlxdWV0YXMsCiAgICBjb2w9cmFpbmJvdyhsZW5ndGgoZXRpcXVldGFzKSksCiAgICBtYWluPSJHw6luZXJvIikKYGBgCgojIyMjIyMgQmFyIHBsb3QgIkZyZWN1ZW5jaWEgZGUgRXN0YWRvIENpdmlsIGVuIGxhIGVtcHJlc2EiCmBgYHtyfQpkZiA8LSBkYXRhLmZyYW1lKENpdmlsPSBjKCJTb2x0ZXJvIiwiQ2FzYWRvIiwgIlVuacOzbiBsaWJyZSIsICJEaXZvcmNpYWRvIiksCiAgICAgICAgICAgICAgICAgbnVtPSBjKDQyLCAzOSwgMjAsIDMpKQoKYmFycGxvdChoZWlnaHQgPSBkZiRudW0sIG5hbWVzID0gZGYkQ2l2aWwsCiAgICAgICAgY29sID0gcmFpbmJvdyg0KSkKYGBgCgojIyMjIyMgSGlzdG9ncmFtYQoKYGBge3J9Cmhpc3QoY29sYWJfYmQkc2FsYXJpb19kaWFyaW8sIG1haW4gPSAiU2FsYXJpbyBEaWFyaW8iLCB4bGFiID0gIkNhbnRpZGFkIiwgeWxhYiA9ICJGcmVjdWVuY2lhIixjb2wgPSAiYmx1ZSIpCmBgYAojIyMjIyBCYWphcwojIyMjIyMgUGllIENoYXJ0IHNvYnJlIG1vdGl2byBkZSBiYWphCmBgYHtyfQpwcm9wb3JjaW9uZXMgPC0gYygxMzksIDg0LCA4LCAxLCAxKSAjIGNyZWFtb3MgdW4gdmVjdG9yIGNvbiBwcm9wb3JjaW9uZXMKZXRpcXVldGFzIDwtIGMoIkJBSkEgUE9SIEZBTFRBUyIsICJSRU5VTkNJQSBWT0xVTlRBUklBIiwgIlRFUk1JTk8gREUgQ09OVFJBVE8iLCJKVUJJTEFDScOTTiIsICJBQkFORE9OTyIpICMgdmVjdG9yIGNvbiBldGlxdWV0YXMKcGN0IDwtIHJvdW5kKHByb3BvcmNpb25lcy9zdW0ocHJvcG9yY2lvbmVzKSoxMDApCmV0aXF1ZXRhcyA8LSBwYXN0ZShldGlxdWV0YXMscGN0KSAjIEHDsWFkaW1vcyBwb3JjZW50YWplcyBhIGV0aXF1ZXRhcwpldGlxdWV0YXMgPC0gcGFzdGUoZXRpcXVldGFzLCIlIixzZXA9IiIpICMgQcOxYWRpbW9zIGVsIHPDrW1ib2xvIGRlICUKCnBpZShwcm9wb3JjaW9uZXMsbGFiZWxzID0gZXRpcXVldGFzLAogICAgY29sPXJhaW5ib3cobGVuZ3RoKGV0aXF1ZXRhcykpLAogICAgbWFpbj0iR8OpbmVybyIpCmBgYAojIyMjIyMgQmFyIHBsb3QgIkJhamFzIHBvciBlc3RhZG8gY2l2aWwiCmBgYHtyfQpkZiA8LSBkYXRhLmZyYW1lKENpdmlsPSBjKCJTb2x0ZXJvIiwiTWF0cmltb25pbyIsICJVbmnDs24gbGlicmUiLCAiRGl2b3JjaWFkbyIpLAogICAgICAgICAgICAgICAgIG51bT0gYygxMDcsNjMsIDU5LCAzKSkKCmJhcnBsb3QoaGVpZ2h0ID0gZGYkbnVtLCBuYW1lcyA9IGRmJENpdmlsLAogICAgICAgIGNvbCA9IHJhaW5ib3coNCksIGxlZ2VuZC50ZXh0ID0gcm93bmFtZXMoZGYpKQpgYGAKCiMjIyMjIEdyw6FmaWNvcyBkZSBkaXNwZXJzacOzbgojIyMjIyMgUHJvZHVjY2nDs24KYGBge3J9CnBsb3QoeCA9IGRhdGE2JFRNTy4uTUlOLiwgeSA9IGRhdGE2JExhbWluYXMucHJvY2VzYWRhcywgIG1haW4gPSAiUmVsYWNpw7NuIGVudHJlIExhbWluYXMgeSBUaWVtcG8iLCB4bGFiID0gIlRpZW1wbyIsIHlsYWIgPSAiTGFtaW5hcyBwcm9jZXNhZGFzIikKYGBgCgojIyMjIyMgTWVybWEKYGBge3J9CnBsb3QoeCA9IGJkX21lcm1hNSRGZWNoYSwgeSA9IGJkX21lcm1hNSRLaWxvcywgIG1haW4gPSAiUmVsYWNpw7NuIGVudHJlIE1lcyB5IEtpbG9zIiwgeGxhYiA9ICJNZXMiLCB5bGFiID0gIktpbG9zIGRlIG1lcm1hIikKYGBgCgojIyMgQW7DoWxpc2lzIGVzdGFkw61zdGljbyBkZXNjcmlwdGl2bzogSW5kdXN0cmlhIEF1dG9tb3RyaXoKCiMjIyMgVGFibGFzIGRlIGZyZWN1ZW5jaWEKCmBgYHtyfQpiZF9leHRlcm5hMiA8LSB0YWJsZShiZF9leHRlcm5hJFVTX01pbl9Ib3VyX1dhZ2UpCmtuaXRyOjprYWJsZShiZF9leHRlcm5hMikKYGBgCgojIyMjIyBHcsOhZmljb3MgZGUgZGF0b3MgY3VhbGl0YXRpdm9zIHkgY3VhbnRpdGF0aXZvcwojIyMjIyMgSW5kdXN0cmlhIEF1dG9tb3RyaXogVVNBCmBgYHtyfQpnZ3Bsb3QoYmRfZXh0ZXJuYSwgYWVzKHg9cmVvcmRlcihZZWFyLFRvdGFsX1Byb2R1Y3Rpb24pLCB5PURvbWVzdGljX1NhbGVzKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrCiAgY29vcmRfZmxpcCgpCmBgYAoKIyMjIyMjIEluZHVzdHJpYSBBdXRvbW90cml6IE3DqXhpY28KIyMjIyMjIEhpc3RvZ3JhbWEKYGBge3J9Cmhpc3QoYmRfZXh0ZXJuYU1YJHVuaWRhZGVzX2V4cG9ydGFjaW9uLCBtYWluID0gIkRpc3RyaWJ1Y2nDs24gZGUgZnJlY3VlbmNpYXMgRXhwb3J0YWNpw7NuIiwgeGxhYiA9ICJFeHBvcnRhY2nDs24iLCB5bGFiID0gIkZyZWN1ZW5jaWEiLGNvbCA9ICJyZWQiKQpgYGAKCiMjIyMjIEdyw6FmaWNvcyBkZSBkaXNwZXJzacOzbgojIyMjIyMgSW5kdXN0cmlhIEF1dG9tb3RyaXogVVNBCmBgYHtyfQpwbG90KHggPSBiZF9leHRlcm5hJFByb2R1Y3Rpb25fQ29tbWVyY2lhbF9WZWhpY2xlcywgeSA9IGJkX2V4dGVybmEkU2FsZXNfQ29tbWVyY2lhbF9WZWhpY2xlcywgIG1haW4gPSAiVmVow61jdWxvcyBDb21lcmNpYWxlcyIsIHhsYWIgPSAiUHJvZHVjY2nDs24iLCB5bGFiID0gIlZlbnRhcyIpCmBgYAoKIyMjIyMjIEluZHVzdHJpYSBBdXRvbW90cml6IE3DqXhpY28KYGBge3J9CnBsb3QoeCA9IGJkX2V4dGVybmFNWCR1bmlkYWRlc19leHBvcnRhY2lvbiwgeSA9IGJkX2V4dGVybmFNWCR1bmlkYWRlc19wcm9kdWNjaW9uLCAgbWFpbiA9ICJSZWxhY2nDs24gZW50cmUgZXhwb3J0YWNpw7NuIHkgdW5pZGFkZXMgZGUgdG9kbyB0aXBvIHZlaMOtY3Vsb3MiLCB4bGFiID0gIkV4cG9ydGFjacOzbiIsIHlsYWIgPSAiUHJvZHVjY2nDs24iKQpgYGAKCiMgKipBbsOhbGlzaXMgRXhwbG9yYXRvcmlvIGRlIGxhcyBCYXNlcyBkZSBEYXRvcyoqCgojIyMgRXN0YWTDrXN0aWNvcyBkZXNjcmlwdGl2b3MgUmVjdXJzb3MgaHVtYW5vcwpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIGluc3RhbGwucGFja2FnZXMoInBzeWNoIikKbGlicmFyeShwc3ljaCkKCmRlc2NyaWJlKGNvbGFiX2ZpbmFsKSAjIEZ1bmNpw7NuIHF1ZSBub3MgZGEgZGF0b3MgZGVzY3JpcHRpdm9zCgpgYGAKCmBgYHtyfQojIFNhY2Ftb3MgbW9kYSBjb24gb3RyYSBmdW5jacOzbiB5YSBxdWUgZW4gbGEgZnVuY2nDs24gZGVzY3JpYmUgbm8gbm9zIGxhIGRhCm1vZGUgPC0gZnVuY3Rpb24gKHgpIHsKICB1eCA8LSB1bmlxdWUoeCkKICB1eCBbd2hpY2gubWF4KHRhYnVsYXRlKG1hdGNoKHgsdXgpKSldCn0KCm1vZGUgPC0gbW9kZShjb2xhYl9maW5hbCRzYWxhcmlvX2RpYXJpbykKbW9kZQpgYGAKCgpgYGB7cn0KVmFyaWFibGVzIDwtYygiU2FsYXJpbyBkaWFyaW8iICkKTWVkaWEgPC1jKCIxNzkuMzUiICkKTWVkaWFuYSA8LWMoIjE4MC42OCIgKQpNb2RhIDwtIGMoIjE4MC42OCIpCkRlc3ZpYWNpb25fZXN0YW5kYXIgPC1jKCIyNS4xNyIgKQpgYGAKCmBgYHtyfQp0YWJsZWNvbGFiIDwtIGRlc2NyaWJlKGRhdGEpCmtuaXRyOjprYWJsZSh0YWJsZWNvbGFiKQpgYGAKCkVzdGEgdGFibGEgIGRlIGZyZWN1ZW5jaWFzIG5vcyBkaWNlIHF1ZSBlbiBGT1JNIGVsIHNhbGFyaW8gcHJvbWVkaW8gZXMgZGUgJDE3OS4KCiMjIyBFc3RhZMOtc3RpY29zIGRlc2NyaXB0aXZvcyBQcm9kdWNjacOzbgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIGluc3RhbGwucGFja2FnZXMoInBzeWNoIikKbGlicmFyeShwc3ljaCkKZGVzY3JpYmUoZGF0YTYpICMgRnVuY2nDs24gcXVlIG5vcyBkYSBkYXRvcyBkZXNjcmlwdGl2b3MKYGBgCgpgYGB7cn0KIyBTYWNhbW9zIG1vZGEgY29uIG90cmEgZnVuY2nDs24geWEgcXVlIGVuIGxhIGZ1bmNpw7NuIGRlc2NyaWJlIG5vIG5vcyBsYSBkYQptb2RlIDwtIGZ1bmN0aW9uICh4KSB7CiAgdXggPC0gdW5pcXVlKHgpCiAgdXggW3doaWNoLm1heCh0YWJ1bGF0ZShtYXRjaCh4LHV4KSkpXQp9Cgptb2RlIDwtIG1vZGUoZGF0YTYkUElFWkFTLlBST0cuKQptb2RlCmBgYAoKYGBge3J9ClZhcmlhYmxlcyA8LWMoIlBpZXphcyBwcm9ncmFtYWRhcyIgKQpNZWRpYSA8LWMoIjI4LjE4IiApCk1lZGlhbmEgPC1jKCIyNSIgKQpNb2RhIDwtIGMoIjI4LjE4IikKRGVzdmlhY2lvbl9lc3RhbmRhciA8LWMoIjM2LjEwIiApCmBgYAoKYGBge3J9CnRhYmxlMSA8LSBkZXNjcmliZShkYXRhKQprbml0cjo6a2FibGUodGFibGUxKQpgYGAKRXN0YSB0YWJsYSAgZGUgZnJlY3VlbmNpYSBub3MgZGljZSBxdWUgZW4gRk9STSBlbCB0aWVtcG8gcHJvbWVkaW8gcXVlIHNlIHRhcmRhIHByb2R1Y2Npw7NuIGVzIGRlIDEwIG1pbnV0b3MsIHF1ZSBzZSBwcm9ncmFtYW4gYWwgcmVkZWRvciBkZSAyOCBwaWV6YXMgeSBhbCBmaW5hbCBzZSBwcm9jZXNhbiA0LgoKIyMjIEVzdGFkw61zdGljb3MgZGVzY3JpcHRpdm9zIFNjcmFwCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQpsaWJyYXJ5KHBzeWNoKQpkZXNjcmliZShiZF9zY3JhcDQpICMgRnVuY2nDs24gcXVlIG5vcyBkYSBkYXRvcyBkZXNjcmlwdGl2b3MKYGBgCgpgYGB7cn0KIyBTYWNhbW9zIG1vZGEgY29uIG90cmEgZnVuY2nDs24geWEgcXVlIGVuIGxhIGZ1bmNpw7NuIGRlc2NyaWJlIG5vIG5vcyBsYSBkYQptb2RlIDwtIGZ1bmN0aW9uICh4KSB7CiAgdXggPC0gdW5pcXVlKHgpCiAgdXggW3doaWNoLm1heCh0YWJ1bGF0ZShtYXRjaCh4LHV4KSkpXQp9Cgptb2RlIDwtIG1vZGUoYmRfc2NyYXA0JENhbnRpZGFkKQptb2RlCmBgYAoKYGBge3J9ClZhcmlhYmxlcyA8LWMoIkNhbnRpZGFkIiApCk1lZGlhIDwtYygiNi43MCIgKQpNZWRpYW5hIDwtYygiMiIgKQpNb2RhIDwtIGMoIjEiKQpEZXN2aWFjaW9uX2VzdGFuZGFyIDwtYygiMTEuODUiICkKYGBgCgpgYGB7cn0KdGFibGUxIDwtZGF0YS5mcmFtZShWYXJpYWJsZXMsIE1lZGlhICwgTWVkaWFuYSAsIE1vZGEsIERlc3ZpYWNpb25fZXN0YW5kYXIpCmtuaXRyOjprYWJsZSh0YWJsZTEpCmBgYAoKRXN0YSB0YWJsYSAgZGUgZnJlY3VlbmNpYSBub3MgZGljZSBxdWUgZW4gRk9STSBsYXMgdW5pZGFkZXMgZGUgU2NyYXAgcHJvbWVkaW8gc29uIGRlIDYuCgojIyMgRXN0YWTDrXN0aWNvcyBkZXNjcmlwdGl2b3MgTWVybWEKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBpbnN0YWxsLnBhY2thZ2VzKCJwc3ljaCIpCmxpYnJhcnkocHN5Y2gpCmRlc2NyaWJlKGJkX21lcm1hNSkgIyBGdW5jacOzbiBxdWUgbm9zIGRhIGRhdG9zIGRlc2NyaXB0aXZvcwpgYGAKCmBgYHtyfQojIFNhY2Ftb3MgbW9kYSBjb24gb3RyYSBmdW5jacOzbiB5YSBxdWUgZW4gbGEgZnVuY2nDs24gZGVzY3JpYmUgbm8gbm9zIGxhIGRhCm1vZGUgPC0gZnVuY3Rpb24gKHgpIHsKICB1eCA8LSB1bmlxdWUoeCkKICB1eCBbd2hpY2gubWF4KHRhYnVsYXRlKG1hdGNoKHgsdXgpKSldCn0KCm1vZGUgPC0gbW9kZShiZF9tZXJtYTUkS2lsb3MpCm1vZGUKYGBgCgpgYGB7cn0KVmFyaWFibGVzIDwtYygiS2lsb3MiKQpNZWRpYSA8LWMoIjM3MDkuNTIiKQpNZWRpYW5hIDwtYygiMzkyNSIpCk1vZGEgPC1jKCIzODEwIikKRGVzdmlhY2lvbl9lc3RhbmRhciA8LWMoIjEwMjMuOTkiKQpgYGAKCmBgYHtyfQp0YWJsZTIgPC1kYXRhLmZyYW1lKFZhcmlhYmxlcywgTWVkaWEsIE1lZGlhbmEsIE1vZGEsIERlc3ZpYWNpb25fZXN0YW5kYXIpCmtuaXRyOjprYWJsZSh0YWJsZTIpCmBgYAoKRXN0YSB0YWJsYSAgZGUgZnJlY3VlbmNpYSBub3MgZGljZSBxdWUgZW4gRk9STSBlbiBwcm9tZWRpbyBzZSB0aWVuZW4gMyw3MDgga2lsb3MgZGUgbWVybWEuCgojIyMgRXN0YWTDrXN0aWNvcyBkZXNjcmlwdGl2b3MgRGVsaXZlcnkgUGVyZm9ybWFuY2UKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBpbnN0YWxsLnBhY2thZ2VzKCJwc3ljaCIpCmxpYnJhcnkocHN5Y2gpCmRlc2NyaWJlKGJkX2RlbGl2ZXJ5X3BlcmYzKSAjIEZ1bmNpw7NuIHF1ZSBub3MgZGEgZGF0b3MgZGVzY3JpcHRpdm9zCmBgYAoKYGBge3J9CiMgU2FjYW1vcyBtb2RhIGNvbiBvdHJhIGZ1bmNpw7NuIHlhIHF1ZSBlbiBsYSBmdW5jacOzbiBkZXNjcmliZSBubyBub3MgbGEgZGEKbW9kZSA8LSBmdW5jdGlvbiAoeCkgewogIHV4IDwtIHVuaXF1ZSh4KQogIHV4IFt3aGljaC5tYXgodGFidWxhdGUobWF0Y2goeCx1eCkpKV0KfQoKbW9kZSA8LSBtb2RlKGJkX2RlbGl2ZXJ5X3BlcmYzJGRlbGF5X3BlcmZvcm1hbmNlKQptb2RlCmBgYAoKYGBge3J9ClZhcmlhYmxlcyA8LWMoIkRpZmVyZW5jaWEgRGVsaXZlcnkiKQpNZWRpYSA8LWMoIjE2LjA3IikKTWVkaWFuYSA8LWMoIjAiKQpNb2RhIDwtIGMoIjAiKQpEZXN2aWFjaW9uX2VzdGFuZGFyIDwtYygiMjQuNjMiKQpgYGAKCmBgYHtyfQp0YWJsZTMgPC1kYXRhLmZyYW1lKFZhcmlhYmxlcywgTWVkaWEsIE1lZGlhbmEsIE1vZGEsIERlc3ZpYWNpb25fZXN0YW5kYXIpCmtuaXRyOjprYWJsZSh0YWJsZTMpCmBgYAoKIyMjIEVzdGFkw61zdGljb3MgZGVzY3JpcHRpdm9zIERlbGl2ZXJ5IFBsYW4KYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQpsaWJyYXJ5KHBzeWNoKQpkZXNjcmliZShkcDEpICMgRnVuY2nDs24gcXVlIG5vcyBkYSBkYXRvcyBkZXNjcmlwdGl2b3MKYGBgCmBgYHtyfQojIFNhY2Ftb3MgbW9kYSBjb24gb3RyYSBmdW5jacOzbiB5YSBxdWUgZW4gbGEgZnVuY2nDs24gZGVzY3JpYmUgbm8gbm9zIGxhIGRhCm1vZGUgPC0gZnVuY3Rpb24gKHgpIHsKICB1eCA8LSB1bmlxdWUoeCkKICB1eCBbd2hpY2gubWF4KHRhYnVsYXRlKG1hdGNoKHgsdXgpKSldCn0KCm1vZGUgPC0gbW9kZShkcDEkUGVkaWRvcykKbW9kZQpgYGAKCmBgYHtyfQpWYXJpYWJsZXMgPC1jKCJEaWZlcmVuY2lhIERlbGl2ZXJ5IikKTWVkaWEgPC1jKCIxLDcwMyIpCk1lZGlhbmEgPC1jKCIwIikKTW9kYSA8LSBjKCIwIikKRGVzdmlhY2lvbl9lc3RhbmRhciA8LWMoIjYsMTY0LjA0IikKYGBgCgpgYGB7cn0KdGFibGU0IDwtZGF0YS5mcmFtZShWYXJpYWJsZXMsIE1lZGlhLCBNZWRpYW5hLCBNb2RhLCBEZXN2aWFjaW9uX2VzdGFuZGFyKQprbml0cjo6a2FibGUodGFibGU0KQpgYGAKCkVzdGEgdGFibGEgIGRlIGZyZWN1ZW5jaWEgbm9zIGRpY2UgcXVlIGVuIEZPUk0gbG9zIG7Dum1lcm9zIGRlIHBlZGlkb3MgZXN0YW4gZW4gcHJvbWVkaW8gMSw3MDMuCgojIyMgRXN0YWTDrXN0aWNvcyBkZXNjcmlwdGl2b3MgQmFzZSBleHRlcm5hOiBJbmR1c3RyaWEgQXV0b21vdHJpeiBVU0EKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBpbnN0YWxsLnBhY2thZ2VzKCJwc3ljaCIpCmxpYnJhcnkocHN5Y2gpCmRlc2NyaWJlKGJkX2V4dGVybmEpICMgRnVuY2nDs24gcXVlIG5vcyBkYSBkYXRvcyBkZXNjcmlwdGl2b3MKYGBgCgpgYGB7cn0KIyBTYWNhbW9zIG1vZGEgY29uIG90cmEgZnVuY2nDs24geWEgcXVlIGVuIGxhIGZ1bmNpw7NuIGRlc2NyaWJlIG5vIG5vcyBsYSBkYQptb2RlIDwtIGZ1bmN0aW9uICh4KSB7CiAgdXggPC0gdW5pcXVlKHgpCiAgdXggW3doaWNoLm1heCh0YWJ1bGF0ZShtYXRjaCh4LHV4KSkpXQp9Cgptb2RlIDwtIG1vZGUoYmRfZXh0ZXJuYSRUb3RhbF9Qcm9kdWN0aW9uKQptb2RlCmBgYAoKYGBge3J9ClZhcmlhYmxlIDwtYygiUHJvZHVjY2nDs24gdG90YWwiICkKTWVkaWEgPC1jKCIxMDA3Ny4xMSIgKQpNZWRpYW5hIDwtYygiMTA4MjIuNTkiICkKTW9kYSA8LSBjKCIxMDc1Mi4zMSIpCkRlc3ZpYWNpb25fZXN0YW5kYXIgPC1jKCIxODgwLjcxIiApCmBgYAoKYGBge3J9CnRhYmxlIDwtZGF0YS5mcmFtZShWYXJpYWJsZSwgTWVkaWEsIE1lZGlhbmEsIE1vZGEsIERlc3ZpYWNpb25fZXN0YW5kYXIpCmtuaXRyOjprYWJsZSh0YWJsZSkKYGBgCgojIyMgQmFyIHBsb3RzCgojIyMjICoqUFJPRFVDQ0nDk04qKiAKYGBge3J9CmJhcnBsb3QocHJvcC50YWJsZSh0YWJsZShkYXRhNiRMYW1pbmFzLnByb2Nlc2FkYXMpKSxjb2w9Yygib3JhbmdlIiksbWFpbj0iTGFtaW5hcyBwcm9jZXNhZGFzIix4bGFiID0gIkxhbWluYXMiLCB5bGFiID0iRnJlY3VlbmNpYXMiLGxhcz0xKQpgYGAKCiMjIyMgKipTQ1JBUCoqIApgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHBseXIpCnBvcmNlbnRhamVzIDwtIGFzLm51bWVyaWMocm91bmQoKChwcm9wLnRhYmxlKHRhYmxlKGJkX3NjcmFwNCRVYmlfb3JpZ2VuKSkpKjEwMCksMikpCmV0aXF1ZXRhcyA8LSBjKCJDYWxpZGFkL0VudHJlZ2EgZGUgUFQiLCJQb3N0LVByb2R1Y2Npw7NuIiwiUHJlLVByb2R1Y2Npw7NuIikKZXRpcXVldGFzIDwtIHBhc3RlKGV0aXF1ZXRhcywgcG9yY2VudGFqZXMpCmV0aXF1ZXRhcyA8LSBwYXN0ZShldGlxdWV0YXMsICIlIiwgc2VwID0gIiIpCgoKcGllKHBvcmNlbnRhamVzLGV0aXF1ZXRhcyxjb2w9YygiUmVkIiwiQmx1ZSIsIk9yYW5nZSIpLG1haW49IlViaWNhY2nDs24gZGUgb3JpZ2VuOiBTY3JhcCIsIHlsYWIgPSJGcmVjdWVuY2lhcyIsbGFzPTEpCmBgYAoKIyMjIyAqKkRFTElWRVJZIFBMQU46IFBSSU5DSVBBTEVTIENMSUVOVEVTKioKQ29uIGxhIHNpZ3VpZW50ZSBmdW5jacOzbiBwb2RyZW1vcyBpZGVudGlmaWNhciBsb3MgcHJpbmNpcGFsZXMgY2xpZW50ZXMgcGFyYSBnZW5lcmFyIHVuIGFuw6FsaXNpcyBjb24gbGEgaW5mb3JtYWNpw7NuIHJlbGV2YW50ZSwgcHVlcyBoYXkgY2xpZW50ZXMgY29uIHBvY29zIG8gc2luIHBlZGlkb3MgcG9yIGxvIHF1ZSBnZW5lcmFyIHVuIGRpYWduw7NzdGljbyByZXNwZWN0byBhIGRlbGl2ZXJ5IHBsYW4gY29uIGVzb3MgZGF0b3Mgbm8gZXMgbmVjZXNhcmlvLiAKYGBge3J9CmdncGxvdChkcDEsIGFlcyh4PXJlb3JkZXIoQ0xJRU5URSxQZWRpZG9zKSwgeT1QZWRpZG9zKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrCiAgY29vcmRfZmxpcCgpCmBgYAoKIyMjIyAqKkRFTElWRVJZIFBMQU46IFRPUCA2IENMSUVOVEVTIFkgUFJPTUVESU8qKiAgCgpDb21vIHNpZ3VpZW50ZSBwYXNvIGVsaW1pbmFyZW1vcyB0b2RvcyBsb3MgY2xpZW50ZXMgcXVlIG5vIG5vcyBpbnRlcmVzYW4gcGFyYSBlbCBhbsOhbGlzaXMgeSBkZWphcmVtb3MgZWwgdG9wIDYgZGUgY2xpZW50ZXMgcGFyYSBlbCBlamVyY2ljaW8uCmBgYHtyfQoKZHAyIDwtIGRwMQpkcDI8LWRwMltkcDIkQ0xJRU5URSE9IkFCQyBRVUVSRVRBUk8iLF0KZHAyPC1kcDJbZHAyJENMSUVOVEUhPSJBTlRPTElOIEFSVEVBR0EiLF0gIApkcDI8LWRwMltkcDIkQ0xJRU5URSE9IkFOVE9MSU4gVE9MVUNBIixdIApkcDI8LWRwMltkcDIkQ0xJRU5URSE9IklTUkkiLF0gCmRwMjwtZHAyW2RwMiRDTElFTlRFIT0iU0VHUk9WRSIsXSAKZHAyPC1kcDJbZHAyJENMSUVOVEUhPSJTVEIgMSIsXSAKZHAyPC1kcDJbZHAyJENMSUVOVEUhPSJVRkkiLF0gCmRwMjwtZHAyW2RwMiRDTElFTlRFIT0iWUYgUVJPIixdIApkcDI8LWRwMltkcDIkQ0xJRU5URSE9IklOT0FDIFBPTFlURUMiLF0gCmRwMjwtZHAyW2RwMiRDTElFTlRFIT0iSEFOT04iLF0gCmRwMjwtZHAyW2RwMiRDTElFTlRFIT0iTUVSSURJQU4iLF0gCmRwMjwtZHAyW2RwMiRDTElFTlRFIT0iWUYgUkFNT1MiLF0gCmRwMjwtZHAyW2RwMiRDTElFTlRFIT0iWUFORkVORyBzbSIsXSAKYGBgCgpgYGB7cn0KZ2dwbG90KGRwMixhZXMoeD1GZWNoYSwgeT1QZWRpZG9zLGZpbGw9Q0xJRU5URSkpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTMzLGxpbmV0eXBlPSJkYXNoZWQiLGNvbG9yPSJibGFjayIpKwogIGxhYnMoeD0iRmVjaGEiLHk9Ik7Dum1lcm8gZGUgcGVkaWRvcyIsIGNvbG9yPSJMZWdlbmQiKSsKICBnZ3RpdGxlKCJQZWRpZG9zIHBvciBmZWNoYSIpCgpgYGAKCiMjIyMgKipSRUNVUlNPUyBIVU1BTk9TOiBDT0xBQk9SQURPUkVTIEFDVFVBTEVTKioKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgYXMuZGF0YS5mcmFtZShiYWphc19iZCkKIyBhcy5kYXRhLmZyYW1lKGNvbGFiX2JkKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cgpjb2xhYl9iZDI8LWNvbGFiX2JkICU+JSBkcGx5cjo6c2VsZWN0KGdlbmVybyxlZGFkLHNhbGFyaW9fZGlhcmlvKSAlPiUgIGRwbHlyOjpncm91cF9ieShnZW5lcm8pICU+JQogIGRwbHlyOjpzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSxtZWFuLG5hLnJtPVRSVUUpKSAlPiUgYXJyYW5nZShkZXNjKGVkYWQpKQpnZ3Bsb3QoY29sYWJfYmQyLCBhZXMoeD1yZW9yZGVyKGdlbmVybyxlZGFkKSwgeT1lZGFkLCBmaWxsPShzYWxhcmlvX2RpYXJpbykpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLGNvbD1jKCJibGFjayIpKSsKICBjb29yZF9mbGlwKCkrCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHJldmVyc2U9RkFMU0UpKQpgYGAKCiMjIyMjIExhIHByaW1lcmEgZ3LDoWZpY2EgZGUgYmFycmFzIG5vcyBkYSBhIGNvbm9jZXIgc29icmUgZWwgc2FsYXJpbyBkaWFyaW8gZGUgbGFzIHBlcnNvbmFzIGRlIEZvcm0sIHNlZ21lbnRhZG8gcG9yIGVkYWQgeSBwb3IgZ8OpbmVyby4gTG8gcXVlIG5vcyBkYSBhIGNvbm9jZXIgZXMgcXVlIGVuIGxhIGVtcHJlc2EgZXhpc3RlIHVuIG1heW9yIHJhbmdvIGRlIGVkYWQgZW50cmUgbGFzIG11amVyZXMgZGUgRm9ybSwgbGxlZ2FuZG8gYSBzZXIgY2FzaSA0MCBsbyBtYXlvcjsgcG9yIG90cmEgcGFydGUsIGxvcyAgaG9tYnJlcyBwcmVzZW50YW4gdW4gbWVub3IgcmFuZ28sIGNvbiB1biBtw6F4aW1vIGRlIChhcHJveCkgMzMuIElndWFsbWVudGUsIHZlbW9zIHF1ZSBlbiBwcm9tZWRpbyBsYXMgbXVqZXJlcyBnYW5hbiA2MCBjZW50YXZvcyBtw6FzIHF1ZSBsb3MgaG9tYnJlcy4gICAgICAKCmBgYHtyfQoKZ2dwbG90KGNvbGFiX2JkLCBhZXMoeD1nZW5lcm8sIHk9c2FsYXJpb19kaWFyaW8sIGZpbGw9Z2VuZXJvKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgCiAgZmFjZXRfZ3JpZCh+Y2l2aWwpICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKYGBgCgojIyMjIyBFc3RhIHNlZ3VuZGEgZ3LDoWZpY2EgZGVzY3JpcHRpdmEgZGUgbG9zIGFjdHVhbGVzIGNvbGFib3JhZG9yZXMgIGRlIEZvcm0sIG5vcyBjb211bmljYSwgcHJpbmNpcGFsbWVudGUsIGVsIGVzdGFkbyBjaXZpbCBkZSBsb3MgY29sYWJvcmFkb3JlcyAgcG9yIGfDqW5lcm8sIHkgc3UgZ2FuYW5jaWEuIExvIHF1ZSBwb2RlbW9zIG5vdGFyIGVzIHF1ZSBlbiBnZW5lcmFsLCBsYXMgbXVqZXJlcyBnYW5hbiBtw6FzIGVuIGN1YWxxdWllciBlc3RhZG8gY2l2aWwgZW4gZWwgcXVlIHNlIGVuY3VlbnRyZW4sIHkgZW4gZG9uZGUgc2UgcHVlZGUgdmVyIHVuYSBtYXlvciB2YXJpZWRhZCBkZSBsYSBzdW1hIGRlIGxvcyBzYWxhcmlvcyBlcyBlbiBsYXMgbXVqZXJlcyAgeSBsb3MgaG9tYnJlcyBxdWUgc2UgZW5jdWVudHJhbiBlbiB1bmnDs24gbGlicmUuIAoKIyMjIyAqKlJFQ1VSU09TIEhVTUFOT1M6IEJBSkFTKioKCmBgYHtyfQoKYmFqYXNfYmQyPC1iYWphc19iZCAlPiUgZHBseXI6OnNlbGVjdChtb3Rpdm9fYmFqYSxlZGFkLGR1cmFjaW9uKSAlPiUgZ3JvdXBfYnkobW90aXZvX2JhamEpICU+JQogIGRwbHlyOjpzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSxtZWFuLG5hLnJtPVRSVUUpKSAlPiUgYXJyYW5nZShkZXNjKGVkYWQpKQpnZ3Bsb3QoYmFqYXNfYmQyLCBhZXMoeD1yZW9yZGVyKG1vdGl2b19iYWphLGVkYWQpLCB5PWVkYWQsIGZpbGw9KGR1cmFjaW9uKSkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsY29sPWMoImJsYWNrIikpKwogIGNvb3JkX2ZsaXAoKSsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQocmV2ZXJzZT1GQUxTRSkpCmBgYAoKIyMjIyMgVmllbmRvIGFob3JhIGxvcyBjb2xhYm9yYWRvcmVzIHF1ZSBoYW4gc2lkbyBkYWRvcyBkZSBiYWphIGVuIGxhIGVtcHJlc2EsIHZlbW9zIHF1ZSBsYSBncmFuIHBhcnRlIGRlIGxvcyBxdWUgc2UgaGFuIHNhbGlkbyBkZSBGb3JtIHRpZW5lbiBtZW5vcyBkZSAzMCBhw7Fvcy4gUG9jb3MgY2Fzb3MgaGFuIHNpZG8gZGUganViaWxhY2nDs24sIGxsZWdhbmRvIGEgbcOhcyBkZSA2MCBlbiByYW5nby4gSWd1YWxtZW50ZSwgYSBwYXJ0aXIgZGUgbGEgZ3LDoWZpY2EgdmVtb3MgcXVlIGxhcyByYXpvbmVzIHByaW5jaXBhbGVzIHNvbiBwb3IgYWJhbmRvbm8geSAgYmFqYSBwb3IgZmFsdGFzOyBkdXJhbmRvIG1lbm9zIGRlIDUwMCBkw61hcyBlbiBzdSB0cmFiYWpvLiAKCmBgYHtyfQoKZ2dwbG90KGJhamFzX2JkLCBhZXMoeD1nZW5lcm8sIHk9c2FsYXJpb19kaWFyaW8sIGZpbGw9Z2VuZXJvKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgCiAgZmFjZXRfZ3JpZCh+ZS5jaXZpbC4pICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikKYGBgCgojIyMjIyBGaW5hbG1lbnRlLCBvYnNlcnZhbW9zIGxhIMO6bHRpbWEgZ3LDoWZpY2EgZGVzY3JpcHRpdmEgZGUgbG9zIGNvbGFib3JhZG9yZXMgcXVlIGhhbiBzaWRvIGRhZG9zIGRlIGJhamEgcG9yIEZvcm0uIEVuIHVuICBjYXNvIG9ic2VydmFtb3MgcXVlIG5vIHNlIGNvbm9jZSBzdSBzaXR1YWNpw7NuIGRlIGVzdGFkbyBjaXZpbC4gSWd1YWxtZW50ZSwgb2JzZXJ2YW1vcyBxdWUgbGEgbWF5b3IgY2FudGlkYWQgKHNlIGFzdW1lIHBvciBsYSBzdW1hIGRlIHNhbGFyaW8gIGRpYXJpbykgaGFuIHNpZG8gc29sdGVyb3MsIHkgIHVuYSBncmFuIGNhbnRpZGFkIGRlIG11amVyZXMgY2FzYWRhcy4gUG9yIGxvIHRhbnRvLCBwb2RlbW9zIGFzdW1pciBhIHBhcnRpciBkZSBsb3MgZGF0b3MgcXVlIGxhIG1heW9yw61hIGRlIGxvcyBxdWUgYWJhbmRvbmFuIHN1IHRyYWJham8gZW4gRm9ybSBzb24gcGVyc29uYXMgc29sdGVyYXMuICAKCiMjIyBEaXNwZXJzaW9uIHBsb3RzICAKCiMjIyMgKipQUk9EVUNDScOTTioqIApgYGB7cn0KcGxvdChkYXRhNiRUTU8uLk1JTi4sIHhsYWIgPSAiUHJvY2VzbyBkZSBsYW1pbmEiLCB5bGFiID0gIlRpZW1wbyIsIG1haW4gPSAiVGllbXBvIHBvciBMYW1pbmEiICkKYGBgCgojIyMjICoqTUVSTUEqKgpgYGB7cn0KZ2dwbG90KGJkX21lcm1hNSwgYWVzKHg9IEZlY2hhLCB5PSBLaWxvcykpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsPSJyZWQiKSArIHNjYWxlX2ZpbGxfZ3JleSgpICsgbGFicyh0aXRsZSA9ICJLaWxvcyBkZSBtZXJtYSIsIHggPSAiRmVjaGEiKQpgYGAKCiMjIyMjIFBvZGVtb3MgdmVyIGNvbW8gZW4gaW5pY2lvcyBkZSBGZWJyZXJvIGEgQWJyaWwgdGVuZW1vcyBsYSBtYXlvciBjYW50aWRhZCBkZSBraWxvcyBkZSBtZXJtYSwgcXVlIGluY2x1c28gcGFzYSBkZWwgcHJvbWVkaW8gZGUgbG9zIGRlbWFzIG1lc2VzLCBwb3IgbG8gcXVlIGVzIGltcG9ydGFudGUgYW5hbGl6YXIgcXVlIGZhY3RvciBoaXpvIHF1ZSBkdXJhbnRlIGVzZSBwZXJpb2RvIGh1YmllcmEgbcOhcyBtZXJtYS4gIAoKYGBge3J9CmJkX21lcm1hNSRGZWNoYSA8LSBhcy5EYXRlKGJkX21lcm1hNSRGZWNoYSwgZm9ybWF0ID0gIiVkLyVtLyVZIikKcGxvdChiZF9tZXJtYTUkRmVjaGEsIGJkX21lcm1hNSRLaWxvcywgbWFpbiA9ICJLaWxvcyBkZSBtZXJtYSIsCiAgICAgeGxhYiA9ICJGZWNoYSIsIHlsYWIgPSAiS2lsb3MiLAogICAgIHBjaCA9IDE5LCBmcmFtZSA9IEZBTFNFKQpgYGAKCiMjIyMjIFBvZGVtb3MgdmVyIGNvbW8gaGF5IG1hcyBkaXNwZXJzacOzbiBlbiBzZXB0aWVtYnJlLCBsb3MgZGVtw6FzIG1lc2VzIGhhIHRlbmlkbyBlbiBwcm9tZWRpbyBsYSBtaXNtYSBjYW50aWRhZCBkZSBtZXJtYS4gIAoKIyMjIyAqKlNDUkFQKiogCmBgYHtyfQpoaXN0KGJkX3NjcmFwNCRDYW50aWRhZCwgbWFpbiA9ICJDYW50aWRhZCBkZSBNYXRlcmlhbCByZWNpY2xhZG8iLCB4bGFiID0gIkNhbnRpZGFkIiwgeWxhYiA9ICJGcmVjdWVuY2lhIixjb2wgPSAiYmx1ZSIpCmBgYAoKIyMjIyMgRXN0ZSBoaXN0b2dyYW1hIG5vcyBtdWVzdHJhIHF1ZSBlbnRyZSAwIGEgMTAgVG9uZWxhZGFzIGVzIGxvIHF1ZSBtYXMgc2UgZnJlY3VlbnRhIGEgcmVjaWNsYXIgZWwgbWF0ZXJpYWwuICAKCmBgYHtyfQpwbG90KGJkX3NjcmFwNCRGZWNoYSwgYmRfc2NyYXA0JENhbnRpZGFkLCBtYWluID0gIkNhbnRpZGFkIGRlIFNjcmFwIHBvciBmZWNoYSIsIHhsYWIgPSAiRmVjaGEiLCB5bGFiID0gIkNhbnRpZGFkIikKYGBgCgojIyMjIyBQb2RlbW9zIHZlciBxdWUgaGF5IGNpZXJ0b3MgZMOtYXMgcXVlIHNhbGVuIGZ1ZXJhIGRlbCBwcm9tZWRpbyAocXVlIGVzIGFscmVkZWRvciBkZSAwLTIwVG9uZWxhZGFzKSBxdWUgc2UgdGllbmUgZGUgbGEgY2FudGlkYWQgZGUgU2NyYXAuICAgCgojIyMjICoqREVMSVZFUlkgUExBTioqCgojIyMjICpQZWRpZG9zKgpgYGB7cn0KcGxvdChkcDIkRmVjaGEsIGRwMiRQZWRpZG9zLCBtYWluID0gIlBlZGlkb3MgcG9yIGZlY2hhIiwKICAgICB4bGFiID0gIkZlY2hhIiwgeWxhYiA9ICJQZWRpZG9zIiwKICAgICBwY2ggPSAxLCBmcmFtZSA9IEZBTFNFKQpgYGAKCmBgYHtyfQpib3hwbG90KGRwMiRQZWRpZG9zLCBtYWluID0gIlBlZGlkb3MiKQpgYGAKCiMjIyMjIENvbW8gcHJpbWVyIGJveHBsb3Qgdmltb3MgbG9zIHBlZGlkb3MgeSBsYSBncmFuIGRpc3BlcnNpw7NuIHF1ZSBoYXkgZW50cmUgcGVkaWRvcywgcHVlcyBkZXRlY3RhbW9zIHVuYSBmcmVjdWVuY2lhIGVuIGRvbmRlIGhheSBjbGllbnRlcyBxdWUgZ2VuZXJhbiBwZWRpZG9zIG9idmlhbWVudGUgZGlmZXJlbnRlcyBjb21vIHBhcmEgdGVuZXIgdW5hIG1lZGlhbmEgbyB1bmEgZGlzcGVyc2nDs24gcG9zaXRpdmEuICAKCiMjIyMgKkNsaWVudGVzKgoKRGVzcHXDqXMgZGUgZ2VuZXJhciB1biBib3hwbG90IGRlIHBlZGlkb3MgZW4gZ2VuZXJhbCwgcmVhbGl6YW1vcyB1biBib3hwbG90IHF1ZSBub3MgbXVlc3RyYSBsb3MgcGVkaWRvcyBwb3IgY2xpZW50ZQpgYGB7cn0KCmRwMyA8LSBkcDIKZHAzJENMSUVOVEU8LWFzLmZhY3RvcihkcDMkQ0xJRU5URSkKZ2dwbG90KGRwMywgYWVzKHg9Q0xJRU5URSwgeT1QZWRpZG9zKSkgKyAKICBnZW9tX2JveHBsb3QoY29sb3I9InJlZCIsIGZpbGw9Im9yYW5nZSIsIGFscGhhPTAuMikKCmBgYAoKIyMjIyMgRW4gZWwgZ3LDoWZpY28gYW50ZXJpb3IgcG9kZW1vcyBvYnNlcnZhciBhIGxvcyA2IGNsaWVudGVzIGNvbiBtYXlvciBwcmVzZW5jaWEgZW4gRk9STSBlbiBjdWFudG8gYSBEZWxpdmVyeSBQbGFuIGVuIGRvbmRlIGVsIG9iamV0aXZvIGVzIHZlciBsYSBkaXNwZXJzacOzbiB5IGxhIGRpc3RyaWJ1Y2nDs24gZW50cmUgY2FkYSB1bm8geSByZXNwZWN0byBhIGxvcyBwcm9uw7NzdGljb3MgaW5kaXZpZHVhbGVzLiAgICAgIAoKIyMjIyMgRWwgY2xpZW50ZSBIRUxMQSBlcyBlbCBjbGllbnRlIGNvbiB1bmEgbWF5b3IgZGlzdHJpYnVjacOzbiB5IGRpc3BlcnNpw7NuIHkgdW5hIG1lZGlhbmEgcXVlIGdlbmVyYSB1bmEgZGVzdmlhY2nDs24gZXN0w6FuZGFyIHBvc2l0aXZhLiBWYXJyb2MgeSBUUk1YIHRpZW5lbiB0YW1iacOpbiB1bmEgZGlzdHJpYnVjacOzbiBtYXlvciBhbCB0ZW5lciBsYSBib3hwbG90IG3DoXMgZ3JhbmRlLCBtaWVudHJhcyBxdWUgbG9zIGRlbcOhczsgREVOU08sIFNUQjMgeSBZRlRPIHRpZW5lbiBsYSBtYXlvcsOtYSBkZSBzdXMgcGVkaWRvcyBlbiB1biBtaXNtbyByYW5nbyBjb24gcGVxdWXDsW9zIGRhdG9zIGZ1ZXJhIGRlbCBib3hwbG90IHByZXNlbnRhbmRvIGFsZ3Vub3Mgd2FybmluZ3MuICAgICAKCiMjIyMjIFNlIHB1ZWRlIGNvbmNsdWlyLCBxdWUgSEVMTEEgZXMgZWwgY2xpZW50ZSBtw6FzIGZ1ZXJ0ZSBlbiBkaWNoYSBiYXNlIGRlIGRhdG9zIHBhcmEgbGEgZW1wcmVzYS4gICAgIAoKIyMjIFRpbWUgc2VyaWVzIHBsb3RzIAoKIyMjIyAqKkRJU1RSSUJVQ0nDk04qKiAKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGJkX2RlbGl2ZXJ5X3BlcmYzLGFlcyh4PWZlY2hhLCB5PWRlbGF5X3BlcmZvcm1hbmNlLGNvbG9yPWNsaWVudGUpKSsKICBnZW9tX2xpbmUoKSsKICBsYWJzKHg9IkZlY2hhIix5PSJSZXRyYXNvIGVuIE1pbnV0b3MiLCBjb2xvcj0iTGVnZW5kIikrCiAgZ2d0aXRsZSgiUmV0cmFzb3MgZW4gZWwgZGVzZW1wZcOxbyBwb3IgcGFydGUgZGVsIGNsaWVudGUiKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmJkX2RlbGl2ZXJ5X3BlcmYzPC1iZF9kZWxpdmVyeV9wZXJmM1tiZF9kZWxpdmVyeV9wZXJmMyRjbGllbnRlIT0iTWFnbmEiLF0KYmRfZGVsaXZlcnlfcGVyZjM8LWJkX2RlbGl2ZXJ5X3BlcmYzW2JkX2RlbGl2ZXJ5X3BlcmYzJGNsaWVudGUhPSJWYXJyb2MiLF0KCmdncGxvdChiZF9kZWxpdmVyeV9wZXJmMyxhZXMoeD1mZWNoYSwgeT1kZWxheV9wZXJmb3JtYW5jZSxmaWxsPWNsaWVudGUpKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0zMyxsaW5ldHlwZT0iZGFzaGVkIixjb2xvcj0iYmxhY2siKSsKICBsYWJzKHg9IkZlY2hhIix5PSJSZXRyYXNvIGVuIG1pbnV0b3MiLCBjb2xvcj0iTGVnZW5kIikrCiAgZ2d0aXRsZSgiUmV0cmFzb3MgZW4gZWwgZGVzZW1wZcOxbyBwb3IgcGFydGUgZGVsIGNsaWVudGUiKQpgYGAKCiMjIyMjIEEgcGVzYXIgZGUgcXVlIGVzdGEgZGltaW51dGVuZG8gZWwgcmV0cmFzbyBjb24gZWwgY2xpZW50ZSBNYWhsZSBzZWd1aW1vcyB2aWVuZG8gcXVlIHNlIGVuY3VlbnRyYSBwb3IgYXJyaWJhIGRlbCBwcm9tZWRpby4gICAgCgojIyMgSGFsbGF6Z29zCgoxLiBOdWVzdHJvIHRvcCAzIGNsaWVudGVzIGRlIHByb2R1Y2Npw7NuIHNvbiBTVEFCSUxVUyAxLCBTVEFCSUxVUyAzIHkgVFJNWC4KCjIuIFRyYWVtb3MgdW4gcmV0cmFzbyBtYXlvciBlbiBkaXN0cmlidWNpw7NuIGNvbiBlbCBjbGllbnRlIE1haGxlLCBhcnJpYmEgZGVsIHByb21lZGlvIGxsZWdhbmRvIGluY2x1c28gYSB0aWVtcG9zIGRlIDEgaG9yYSBjb24gNDAgbWludXRvcy4KCjMuIFNlIHRpZW5lbiBzb2JyZXBlZGlkb3MgKGFycmliYSBkZWwgcHJvbWVkaW8pIHkgZXN0byBwdWVkZSBhZmVjdGFyIHNpIG5vIHNlIHRpZW5lbiBsYSBjYXBhY2lkYWQgcGFyYSByZWNpYmlyIHBlZGlkb3MgZGUgbcOhcy4gIAoKNC4gRGVudHJvIGRlIFJIIHRlbmVtb3MgbcOhcyBiYWphcyBwb3IgZGlzdGludG9zIG1vdGl2b3M6IGVuIHByaW1lciBsdWdhciBlc3RhIHBvciBKdWJpbGFjacOzbiwgZW4gc2VndW5kbyBsdWdhciBSZW51bmNpYSB2b2x1bnRhcmlhIHkgZW4gdGVyY2VyIGx1Z2FyIEJhamEgcG9yIEZhbHRhcy4KCgojICoqUHJlZGljY2nDs24gZGVsIERlc2VtcGXDsW8gZGUgbGEgSW5kdXN0cmlhIEF1dG9tb3RyaXoqKgojIyBJbmR1c3RyaWEgQXV0b21vdHJpeiBVU0EKU2UgY2FtYmlhbiBsb3Mgbm9tYnJlcyBkZSBsYXMgY29sdW1uYXMuIApgYGB7cn0KbmFtZXMgKGJhc2UpID0gYygiYcOxbyIsICJwcm9kX3RvdGFsIiwgInByb2RfcGFzc2VuZ2VyIiwgInByb2RfdmVoX2NvbWVyY2lhbGVzIiwgInZlbnRhc19kb21lc3RpY2FzIiwgInZlbnRhc19wYXNzZW5nZXIiLCJ2ZW50YXNfY29tZXJjaWFsZXMiLCJkZXNlbXBsZW9fdXNhIiwiY29uZmlhbnphX2NvbnNfdXNhIiwic2FsYXJpb19ob3JhX21pbl91c2EiKQpuYW1lcyAoYmFzZSkKc3RyKGJhc2UpCmBgYAoKIyMjICoqUHJpbWVyIG1vZGVsbyBkZSByZWdyZXNpw7NuKioKRW4gZXN0ZSBjYXNvLCBzZSBlc2NvZ2UgY29tbyB2YXJpYWJsZSBkZXBlbmRpZW50ZSBsYXMgdmVudGFzIGRlIGxvcyBjYXJyb3MgKnBhc3NlbmdlciosIHBvciBlbGxvIGVudGnDqW5kYXNlIGxvcyBhdXRvbcOzdmlsZXMgZGUgdXNvIGNvdGlkaWFubyBlbiBFc3RhZG9zIFVuaWRvcy4gUGFyYSBlc3RhIHZhcmlhYmxlIGRlcGVuZGllbnRlLCBzZSBoYW4gdG9tYWRvIGxhcyBzaWd1aWVudGVzIHZhcmlhYmxlcyBpbmRlcGVuZGllbnRlcywgY29uIGVsIGZpbiBkZSBub3RhciBzdSBlZmVjdG8gZW4gbGFzIHZlbnRhcy4gRXN0YXMgc29uOiAgCgoxLiBEZXNlbXBsZW8gVVNBOiBlc3RlIMOtbmRpY2UgZXMgY2FsY3VsYWRvIGFudWFsbWVudGUgY29uIGxhIGZvcm11bGEuIChVbmVtcGxveWVkIMO3IExhYm9yIEZvcmNlKSB4IDEwMC4gRW50cmUgbWVub3IgbWVqb3IuIAoKMi4gQ29uZmlhbnphIGRlbCBjb25zdW1pZG9yIGRlIFVTQTogw61uZGljZSBxdWUgbWlkZSwgYSBwYXJ0aXIgZGUgdW5hIGVuY3Vlc3RhIHF1ZSB0YW4gb3B0aW1pc3RhcyBvIHBlc2ltaXN0YXMgc2UgZW5jdWVudHJhbiBsb3MgY29uc3VtaWRvcmVzIHNvYnJlIHN1IHNpdHVhY2nDs24gZmluYW5jaWVyYS4gRW50cmUgbWF5b3IsIG1lam9yLiAKCjMuIFNhbGFyaW8gbcOtbmltbyBwb3IgaG9yYTogc2UgbWlkZSBlbiBkw7NsYXJlcy4gRXN0w6EgZXN0YWJsZWNpZG8gYSBuaXZlbCBmZWRlcmFsLiAKCjQuIEHDsW86IGxvcyBhw7FvcyBxdWUgc2UgdGllbmVuIGRlIGxvcyBkYXRvcywgMjAwNy0yMDIwLiAKCgpgYGB7cn0KcmVncmVzaW9uMSA8LSBsbSAodmVudGFzX3Bhc3NlbmdlciB+IGRlc2VtcGxlb191c2EgKyBjb25maWFuemFfY29uc191c2EgKyBzYWxhcmlvX2hvcmFfbWluX3VzYSArIGHDsW8sIGRhdGE9YmFzZSkKc3VtbWFyeSAocmVncmVzaW9uMSkKYGBgClBhcmEgbGEgdGFzYSBkZSBkZXNlbXBsZW8geSBlbCDDrW5kaWNlIGRlIGNvbmZpYW56YSBkZWwgY29uc3VtaWRvciwgc2UgaGEgZGVjaWRpZG8gdG9tYXIgZWwgKnByb21lZGlvKiBkZWwgMjAwNyBhbCAyMDIwLCBwYXJhIHBvZGVyIHByZWRlY2lyLiBDb24gZWwgc2FsYXJpbyBtw61uaW1vIHBvciBob3JhLCBhbCBzZXIgZXN0YWJsZWNpZG8gYSBuaXZlbCBmZWRlcmFsLCBzZSB0b21hIGVuIGN1ZW50YSBsYSDDumx0aW1hIGNhbnRpZGFkOiAkNy4yNSBkw7NsYXJlcy4gU2UgcXVpZXJlbiBsYXMgcHJlZGljY2lvbmVzIHBhcmEgbG9zIHNpZ3VpZW50ZXMgY2luY28gYcOxb3MsIGEgcGFydGlyIGRlbCDDumx0aW1vIGHDsW8gY29uIGRhdG9zICgyMDIwKS4KCmBgYHtyfQpkYXRvc19udWV2b3MxIDwtIGRhdGEuZnJhbWUoZGVzZW1wbGVvX3VzYT02LjQzLGNvbmZpYW56YV9jb25zX3VzYT04Mi4zLHNhbGFyaW9faG9yYV9taW5fdXNhPTcuMjUsYcOxbz0yMDIxOjIwMjUpCnByZWRpY3QocmVncmVzaW9uMSxkYXRvc19udWV2b3MxKQpgYGAKCioqwr9RdcOpIG9ic2VydmFtb3M/KioKCmBgYHtyfQpwcmltZXIgPC0gcGxvdChwcmVkaWN0KHJlZ3Jlc2lvbjEsZGF0b3NfbnVldm9zMSksIHR5cGUgPSAibCIsIHhsYWIgPSAiQcOxbyIsICB5bGFiID0iVmVudGFzIFBhc3NlbmdlciIsICBtYWluPSJQcmVkaWNjacOzbiBkZSBWZW50YXMiKQpgYGAKCkVuIGVzdGEgcHJlZGljY2nDs24gZGUgdmVudGFzIGRlIGF1dG9tw7N2aWxlcyAqcGFzc2VuZ2VyKiwgb2JzZXJ2YW1vcyBxdWUgZXMgaGFjaWEgYWJham8uIEVzIGRlY2lyLCB0b21hbmRvIGVuIGN1ZW50YSB1bmEgdGFzYSBkZSBkZXNlbXBsZW8gIGRlIDYuNDMsIHVuIMOtbmRpY2UgZGUgY29uZmlhbnphIGRlIDgyLjMgeSBlbCBzYWxhcmlvIG3DrW5pbW8gcG9yIGhvcmEgZGUgJDcuMjUsIHNlIGVzcGVyYSBxdWUgbGFzIHZlbnRhcyBkZSBlc3RvcyBhdXRvbcOzdmlsZXMgKipiYWplbioqIGVuIEVVQSBkZWwgMjAyMSBoYXN0YSAyMDI1LiBJZ3VhbG1lbnRlLCByZXN1bHRhIGRlc3RhY2FibGUgbWVuY2lvbmFyIHF1ZSBsYXMgIHZhcmlhYmxlcyBxdWUgbcOhcyBpbXBhY3RhbiBlbiBsYXMgdmVudGFzIGRlIGF1dG9tw7N2aWxlcyAqcGFzc2VuZ2VyKiBzb24gZWwgYcOxbyB5IGVsIHNhbGFyaW8gbcOtbmltby4KCmBgYHtyfQplZmZlY3RfcGxvdChyZWdyZXNpb24xLHByZWQ9ZGVzZW1wbGVvX3VzYSxpbnRlcnZhbD1UUlVFKQpgYGAKClNpIHRvbWFtb3MgZW4gY3VlbnRhIGxhIHRhc2EgZGUgZGVzZW1wbGVvIGRlIEVVQSwgeSBzdSByZWxhY2nDs24gY29uIGxhcyB2ZW50YXMgZGUgbG9zIGF1dG9tw7N2aWxlcyAqcGFzc2VuZ2VyKiwgb2JzZXJ2YW1vcyBxdWUgZXN0YSBlcyBuZWdhdGl2YS4gRGViaWRvIGEgcXVlIGFsIGNyZWNlciBsYSB0YXNhIGRlIGRlc2VtcGxlbywgYmFqYW4gbGFzIHZlbnRhcy4gCgoKYGBge3J9CmVmZmVjdF9wbG90KHJlZ3Jlc2lvbjEscHJlZD1jb25maWFuemFfY29uc191c2EsaW50ZXJ2YWw9VFJVRSkKYGBgCk1pZW50cmFzIHF1ZSBlbCDDrW5kaWNlIGRlIGNvbmZpYW56YSBkZWwgY29uc3VtaWRvciBkZSBFVUEsIHkgc3UgcmVsYWNpw7NuIGNvbiBsYXMgdmVudGFzIGRlIGxvcyBhdXRvbcOzdmlsZXMgKnBhc3NlbmdlciosIG9ic2VydmFtb3MgcXVlIGVzdGEgZXMgcG9zaXRpdmEuIERlYmlkbyBhIHF1ZSBhbCBjcmVjZXIgbGEgY29uZmlhbnphLCBpbmNyZW1lbnRhbiBsYXMgdmVudGFzLiAKCgpgYGB7cn0KZWZmZWN0X3Bsb3QocmVncmVzaW9uMSxwcmVkPXNhbGFyaW9faG9yYV9taW5fdXNhLGludGVydmFsPVRSVUUpCmBgYAoKSWd1YWxtZW50ZSwgYWwgc3ViaXIgZWwgc2FsYXJpbyBtw61uaW1vIHBvciBob3JhLCBsYXMgdmVudGFzIGRlIGxvcyBhdXRvbcOzdmlsZXMgKnBhc3NlbmdlciogaW5jcmVtZW50YW4uIAoKYGBge3J9CmVmZmVjdF9wbG90KHJlZ3Jlc2lvbjEscHJlZD1hw7FvLGludGVydmFsPVRSVUUpCmBgYAoKQ29uIGVsIHBhc2FyIGRlIGxvcyBhw7FvcyBsYXMgdmVudGFzIGhhbiBkZWNyZWNpZG8uIAoKIyMjICoqU2VndW5kbyBtb2RlbG8gZGUgcmVncmVzacOzbioqCkVuIGVzdGUgY2Fzbywgc2UgZXNjb2dlIGNvbW8gdmFyaWFibGUgZGVwZW5kaWVudGUgbGFzIHZlbnRhcyBkZSBsb3MgY2Fycm9zICpjb21lcmNpYWxlcyosIHBvciBlbGxvIGVudGnDqW5kYXNlIGxvcyBjdWFscXVpZXIgdGlwbyBkZSB2ZWjDrWN1bG8gZGUgbW90b3IgdXRpbGl6YWRvIHBhcmEgdHJhbnNwb3J0YXIgbWVyY2FuY8OtYXMgbyBwYXNhamVyb3MgZW4gRXN0YWRvcyBVbmlkb3MuIFBhcmEgZXN0YSB2YXJpYWJsZSBkZXBlbmRpZW50ZSwgc2UgaGFuIHRvbWFkbyBsYXMgc2lndWllbnRlcyB2YXJpYWJsZXMgaW5kZXBlbmRpZW50ZXMsIGNvbiBlbCBmaW4gZGUgbm90YXIgc3UgZWZlY3RvIGVuIGxhcyB2ZW50YXMuIEVzdGFzIHNvbjogIAoxLiBEZXNlbXBsZW8gVVNBOiBlc3RlIMOtbmRpY2UgZXMgY2FsY3VsYWRvIGFudWFsbWVudGUgY29uIGxhIGZvcm11bGEuIChVbmVtcGxveWVkIMO3IExhYm9yIEZvcmNlKSB4IDEwMC4gRW50cmUgbWVub3IgbWVqb3IuICAKMi4gQ29uZmlhbnphIGRlbCBjb25zdW1pZG9yIGRlIFVTQTogw61uZGljZSBxdWUgbWlkZSwgYSBwYXJ0aXIgZGUgdW5hIGVuY3Vlc3RhIHF1ZSB0YW4gb3B0aW1pc3RhcyBvIHBlc2ltaXN0YXMgc2UgZW5jdWVudHJhbiBsb3MgY29uc3VtaWRvcmVzIHNvYnJlIHN1IHNpdHVhY2nDs24gZmluYW5jaWVyYS4gRW50cmUgbWF5b3IsIG1lam9yLiAgCjMuIFNhbGFyaW8gbcOtbmltbyBwb3IgaG9yYTogc2UgbWlkZSBlbiBkw7NsYXJlcy4gRXN0w6EgZXN0YWJsZWNpZG8gYSBuaXZlbCBmZWRlcmFsLiAgCjQuIEHDsW86IGxvcyBhw7FvcyBxdWUgc2UgdGllbmVuIGRlIGxvcyBkYXRvcywgMjAwNy0yMDIwLgoKCmBgYHtyfQpyZWdyZXNpb24yIDwtIGxtICh2ZW50YXNfY29tZXJjaWFsZXMgfiBkZXNlbXBsZW9fdXNhICsgY29uZmlhbnphX2NvbnNfdXNhICsgc2FsYXJpb19ob3JhX21pbl91c2EgKyBhw7FvLCBkYXRhPWJhc2UpCnN1bW1hcnkgKHJlZ3Jlc2lvbjIpCmBgYApQYXJhIGxhIHRhc2EgZGUgZGVzZW1wbGVvIHkgZWwgw61uZGljZSBkZSBjb25maWFuemEgZGVsIGNvbnN1bWlkb3IsIHNlIGhhIGRlY2lkaWRvIHRvbWFyIGVsICpwcm9tZWRpbyogZGVsIDIwMDcgYWwgMjAyMCwgcGFyYSBwb2RlciBwcmVkZWNpci4gQ29uIGVsIHNhbGFyaW8gbcOtbmltbyBwb3IgaG9yYSwgYWwgc2VyIGVzdGFibGVjaWRvIGEgbml2ZWwgZmVkZXJhbCwgc2UgdG9tYSBlbiBjdWVudGEgbGEgw7psdGltYSBjYW50aWRhZDogJDcuMjUgZMOzbGFyZXMuIFNlIHF1aWVyZW4gbGFzIHByZWRpY2Npb25lcyBwYXJhIGxvcyBzaWd1aWVudGVzIGNpbmNvIGHDsW9zLCBhIHBhcnRpciBkZWwgw7psdGltbyBhw7FvIGNvbiBkYXRvcyAoMjAyMCkuCgoKYGBge3J9CmRhdG9zX251ZXZvczIgPC0gZGF0YS5mcmFtZShkZXNlbXBsZW9fdXNhPTYuNDMsY29uZmlhbnphX2NvbnNfdXNhPTgyLjMsc2FsYXJpb19ob3JhX21pbl91c2E9Ny4yNSxhw7FvPTIwMjE6MjAyNSkKcHJlZGljdChyZWdyZXNpb24yLGRhdG9zX251ZXZvczIpCmBgYAoKKirCv1F1w6kgb2JzZXJ2YW1vcz8qKgoKYGBge3J9CnNlZ3VuZG8gPC0gcGxvdChwcmVkaWN0KHJlZ3Jlc2lvbjIsZGF0b3NfbnVldm9zMiksIHR5cGUgPSAibCIsIHhsYWIgPSAiQcOxbyIsICB5bGFiID0iVmVudGFzIENvbWVyY2lhbGVzIiwgIG1haW49IlByZWRpY2Npw7NuIGRlIFZlbnRhcyIpCmBgYAoKRW4gZXN0YSBwcmVkaWNjacOzbiBkZSB2ZW50YXMgZGUgYXV0b23Ds3ZpbGVzICpjb21lcmNpYWxlcyosIG9ic2VydmFtb3MgcXVlIGVzIGhhY2lhIGFycmliYSBFcyBkZWNpciwgdG9tYW5kbyBlbiBjdWVudGEgdW5hIHRhc2EgZGUgZGVzZW1wbGVvICBkZSA2LjQzLCB1biDDrW5kaWNlIGRlIGNvbmZpYW56YSBkZSA4Mi4zIHkgZWwgc2FsYXJpbyBtw61uaW1vIHBvciBob3JhIGRlICQ3LjI1LCBzZSBlc3BlcmEgcXVlIGxhcyB2ZW50YXMgZGUgZXN0b3MgYXV0b23Ds3ZpbGVzICoqc3ViYW4qKiBlbiBFVUEgZGVsIDIwMjEgaGFzdGEgMjAyNS4gRW4gZWwgY2FzbyBkZSBsYXMgdmVudGFzIGRlIGF1dG9tw7N2aWxlcyAqY29tZXJjaWFsZXMqLCBub3RhbW9zIHF1ZSBlbCBwYXNhciBkZSBsb3MgYcOxb3MgZXMgbGEgdmFyaWFibGUgcXVlIG3DoXMgaW1wYWN0YSwgc2lndWllbmRvIHBvciBlbCBuaXZlbCBkZSBjb25maWFuemEgZGVsIGNvbnN1bWlkb3IgeSBlbCBzYWxhcmlvIG3DrW5pbW8gcG9yIGhvcmE7IG1pZW50cmFzIHF1ZSBlbCBxdWUgbWVub3MgYWZlY3RhIGVzIGxhIHRhc2EgZGUgZGVzZW1wbGVvLiAKCgpgYGB7cn0KZWZmZWN0X3Bsb3QocmVncmVzaW9uMixwcmVkPWRlc2VtcGxlb191c2EsaW50ZXJ2YWw9VFJVRSkKYGBgCgpTaSB0b21hbW9zIGVuIGN1ZW50YSBsYSB0YXNhIGRlIGRlc2VtcGxlbyBkZSBFVUEsIHkgc3UgcmVsYWNpw7NuIGNvbiBsYXMgdmVudGFzIGRlIGxvcyBhdXRvbcOzdmlsZXMgKmNvbWVyY2lhbGVzKiwgb2JzZXJ2YW1vcyBxdWUgZXN0YSBlcyBuZWdhdGl2YS4gRGViaWRvIGEgcXVlIGFsIGNyZWNlciBsYSB0YXNhIGRlIGRlc2VtcGxlbywgYmFqYW4gbGFzIHZlbnRhcy4gCgoKYGBge3J9CmVmZmVjdF9wbG90KHJlZ3Jlc2lvbjIscHJlZD1jb25maWFuemFfY29uc191c2EsaW50ZXJ2YWw9VFJVRSkKYGBgCgpNaWVudHJhcyBxdWUgZWwgw61uZGljZSBkZSBjb25maWFuemEgZGVsIGNvbnN1bWlkb3IgZGUgRVVBLCB5IHN1IHJlbGFjacOzbiBjb24gbGFzIHZlbnRhcyBkZSBsb3MgYXV0b23Ds3ZpbGVzICpjb21lcmNpYWxlcyosIG9ic2VydmFtb3MgcXVlIGVzdGEgZXMgcG9zaXRpdmEuIERlYmlkbyBhIHF1ZSBhbCBjcmVjZXIgbGEgY29uZmlhbnphLCBpbmNyZW1lbnRhbiBsYXMgdmVudGFzLiBBIGNvbXBhcmFjacOzbiBkZSBsYSBncsOhZmljYSBkZSB2ZW50YXMgKnBhc3NlbmdlciogY29uIGVsIG5pdmVsIGRlIGNvbmZpYW56YSwgb2JzZXJ2YW1vcyBxdWUgZW4gZXN0ZSBjYXNvIGxhIHBlbmRpZW50ZSBlcyBtw6FzIHByb251bmNpYWRhLCBwb3IgbG8gcXVlIHZlbW9zIHVuIG1heW9yIGltcGFjdG8uIAoKCmBgYHtyfQplZmZlY3RfcGxvdChyZWdyZXNpb24yLHByZWQ9c2FsYXJpb19ob3JhX21pbl91c2EsaW50ZXJ2YWw9VFJVRSkKYGBgCgpJZ3VhbG1lbnRlLCBhbCBzdWJpciBlbCBzYWxhcmlvIG3DrW5pbW8gcG9yIGhvcmEsIGxhcyB2ZW50YXMgZGUgbG9zIGF1dG9tw7N2aWxlcyAqY29tZXJjaWFsZXMqIGRpc21pbnV5ZW4uIEVzdGUgcG9kcsOtYSBzZXIgdW4gdGVtYSBpbnRlcmVzYW50ZSBhIGludmVzdGlnYXIuIAoKCmBgYHtyfQplZmZlY3RfcGxvdChyZWdyZXNpb24yLHByZWQ9YcOxbyxpbnRlcnZhbD1UUlVFKQpgYGAKCkNvbiBlbCBwYXNhciBkZSBsb3MgYcOxb3MgbGFzIHZlbnRhcyBoYW4gaW5jcmVtZW50YWRvLiAKCiMjIEluZHVzdHJpYSBBdXRvbW90cml6IE3DqXhpY28KCiMjIyAqKlByaW1lciBtb2RlbG8gZGUgcmVncmVzacOzbioqCgpOdWVzdHJhIHZhcmlhYmxlIGRlcGVuZGllbnRlIHNlcmEgdW5pZGFkZXMgZGUgcHJvZHVjY2nDs24geSBsYXMgdmFyaWFibGVzIGV4cGxhbmF0b3JpYXMgZW4gZXN0ZSBjYXNvIHNlcsOtYW4gdW5pZGFkZXMgZGUgZXhwb3J0YWNpb24geSBhw7FvLgpgYGB7cn0KbXhfcmVncmVzaW9uMSA8LSBsbSAodW5pZGFkZXNfcHJvZHVjY2lvbiB+IHVuaWRhZGVzX2V4cG9ydGFjaW9uICsgYcOxbywgZGF0YT1iZF9leHRlcm5hTVgpCnN1bW1hcnkgKG14X3JlZ3Jlc2lvbjEpCmBgYApDb21vIHJlc3VsdGFkbyBkZSBsYSByZWdyZXNpw7NuIHBvZGVtb3MgdmVyIHF1ZSBleGlzdGUgdW5hIHNpZ25pZmljYW5jaWEgZGUgMC4wNSBjb24gbGEgdmFyaWFibGUgZGUgZXhwb3J0YWNpw7NuIGVuIHVuaWRhZGVzIHZlaGljdWxhcmVzIHkgbG8gcXVlIG5vcyBkaWNlIGVsIG1vZGVsbyBlc3F1ZSBzaSBhdW1lbnRhIGxhIGV4cG9ydGFjacOzbiBhdW1lbnRhIGxhIHByb2R1Y2Npw7NuLCBwZXJvIGRlc3B1w6lzIHBvZGVtb3MgdmVyIHF1ZSBlbiBhw7FvIGhheSB1bmEgdGVuZGVuY2lhIG5lZ2F0aXZhIGRpY2nDqW5kb25vcyBxdWUgZGVjcmVjZW4gbGFzIHZlbnRhcyBjb24gZWwgYcOxby4gRWwgbW9kZWxvIHRpZW5lIHVuYSBSwrIgZGUgMC45OCB0ZW5pZW5kbyB1biBidWVuIG5pdmVsIGRlIGNvbmZpYW56YS4gIAoKCkFob3JhIGdyYWZpY2FyZW1vcyBudWVzdHJhIHJlZ3Jlc2nDs24sIHBhcmEgbGFzIHVuaWRhZGVzIGRlIGV4cG9ydGFjacOzbiBzZSBoYSBkZWNpZGlkbyB0b21hciBlbCAqbWVkaWEqIGRlbCAyMDE3IGFsIDIwMjEgKDMsMDk2LDQyMSkuIFNlIHF1aWVyZW4gbGFzIHByZWRpY2Npb25lcyBwYXJhIGxvcyBzaWd1aWVudGVzIGNpbmNvIGHDsW9zLCBhIHBhcnRpciBkZWwgw7psdGltbyBhw7FvIGNvbiBkYXRvcyAoMjAyMSkuCmBgYHtyfQpkYXRvc19udWV2b3MxIDwtIGRhdGEuZnJhbWUodW5pZGFkZXNfZXhwb3J0YWNpb249MzA5NjQyMSxhw7FvPTIwMjI6MjAyNikKcHJlZGljdChteF9yZWdyZXNpb24xLGRhdG9zX251ZXZvczEpCmBgYAoKKirCv1F1w6kgb2JzZXJ2YW1vcz8qKgoKYGBge3J9CnByZWRpY2Npb25teDEgPC0gcGxvdChwcmVkaWN0KG14X3JlZ3Jlc2lvbjEsZGF0b3NfbnVldm9zMSksIHR5cGUgPSAibCIsIHhsYWIgPSAiQcOxbyIsICB5bGFiID0iRXhwb3J0YWNpb25lcyIsICBtYWluPSJQcmVkaWNjacOzbiBkZSBFeHBvcnRhY2lvbmVzIikKYGBgCgpFbiBlc3RhIHByZWRpY2Npw7NuICpleHBvcnRhY2lvbmVzIGRlIGF1dG9tb3ZpbGVzKiwgb2JzZXJ2YW1vcyBxdWUgZXMgaGFjaWEgYWJham8uIEVzIGRlY2lyLCBzZSBlc3BlcmEgcXVlIGxhcyBleHBvcnRhY2lvbmVzIGRlIGxvcyBhdXRvbcOzdmlsZXMgKipiYWplbioqIGVuIE3DqXhpY28gZGVsIDIwMjIgaGFzdGEgMjAyNi4gCgojIyMgKipTZWd1bmRvIG1vZGVsbyBkZSByZWdyZXNpw7NuKioKYGBge3J9Cm14X3JlZ3Jlc2lvbjIgPC0gbG0gKHVuaWRhZGVzX3ZlbnRhcyB+IGRlc2VtcGxlbyArIGHDsW8sIGRhdGE9YmRfZXh0ZXJuYU1YKQpzdW1tYXJ5IChteF9yZWdyZXNpb24yKQpgYGAKCkNvbW8gcmVzdWx0YWRvIGRlIGxhIHJlZ3Jlc2nDs24gcG9kZW1vcyB2ZXIgcXVlIGV4aXN0ZSB1bmEgc2lnbmlmaWNhbmNpYSBkZSAwLjA1IGNvbiBsYSB2YXJpYWJsZSBkZXNlbXBsZW8geSBhw7FvLCB0ZW5pZW5kbyB1bmEgdGVuZGVuY2lhIG5lZ2F0aXZhIGVuIGFtYmFzLCBsbyBxdWUgcXVpZXJlIGRlY2lyIHF1ZSBzaSBkaXNtaW51eWUgZWwgZGVzZW1wbGVvIGF1bWVudGFuIGxhcyB2ZW50YXMgeSBxdWUgY29uIGVsIHBhc28gZGUgbG9zIGHDsW9zIGxhcyB2ZW50YXMgYXVtZW50YW4gRWwgbW9kZWxvIHRpZW5lIHVuYSBSwrIgZGUgMC45OCB0ZW5pZW5kbyB1biBidWVuIG5pdmVsIGRlIGNvbmZpYW56YS4gICAgCgpBaG9yYSBncmFmaWNhcmVtb3MgbnVlc3RyYSByZWdyZXNpw7NuLCBwYXJhIGRlc2VtcGxlbyBzZSBoYSBkZWNpZGlkbyB0b21hciBsYSAqbWVkaWEqIGRlbCAyMDE3IGFsIDIwMjEgKDMuNzcpLiBTZSBxdWllcmVuIGxhcyBwcmVkaWNjaW9uZXMgcGFyYSBsb3Mgc2lndWllbnRlcyBjaW5jbyBhw7FvcywgYSBwYXJ0aXIgZGVsIMO6bHRpbW8gYcOxbyBjb24gZGF0b3MgKDIwMjEpLgoKYGBge3J9CmRhdG9zX251ZXZvczIgPC0gZGF0YS5mcmFtZShkZXNlbXBsZW89My43NywgYcOxbz0yMDIyOjIwMjYpCnByZWRpY3QobXhfcmVncmVzaW9uMixkYXRvc19udWV2b3MyKQpgYGAKCioqwr9RdcOpIG9ic2VydmFtb3M/KioKCmBgYHtyfQpwcmVkaWNjaW9ubXgyIDwtIHBsb3QocHJlZGljdChteF9yZWdyZXNpb24yLGRhdG9zX251ZXZvczIpLCB0eXBlID0gImwiLCB4bGFiID0gIkHDsW8iLCAgeWxhYiA9IlZlbnRhcyIsICBtYWluPSJQcmVkaWNjacOzbiBkZSBWZW50YXMiKQpgYGAKCkNvbiBlbCBtb2RlbG8gcG9kZW1vcyB2ZXIgY29tbyB0ZW5lbW9zIGxhIHRlbmRlbmNpYSBuZWdhdGl2YSBkZWNyZWNpZW5kbyBsYXMgdmVudGFzLgoKIyMgUHJvbsOzc3RpY28gZGVsIERlc2VtcGXDsW8gZGUgbGEgSW5kdXN0cmlhIEF1dG9tb3RyaXogeSBsYSBFbXByZXNhIEZPUk0KIyMjICoqUHJvbsOzc3RpY28gSW5kdXN0cmlhIEF1dG9tb3RyaXogVVNBKioKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdChiZF9leHRlcm5hJFllYXIsYmRfZXh0ZXJuYSRQcm9kdWN0aW9uX0NvbW1lcmNpYWxfVmVoaWNsZXMsIHR5cGU9ImwiLGNvbD0iYmx1ZSIsIGx3ZD0xLjUsIHhsYWIgPSJZZWFyIix5bGFiID0iVGhvdXNhbmRzIG9mIFVuaXRzIiwgbWFpbiA9ICJBbm51YWwgVS5TLiBNb3RvciBWZWhpY2xlIFNhbGVzIikKbGluZXMoYmRfZXh0ZXJuYSRZZWFyLGJkX2V4dGVybmEkU2FsZXNfQ29tbWVyY2lhbF9WZWhpY2xlcyxjb2w9InJlZCIsbHR5PTMpCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZD1jKCJEb21lc3RpYyBDb21tZXJjaWFsIFNhbGVzIiwgIlByb2R1Y3Rpb24gQ29tbWVyY2lhbCBWZWhpY2xlcyIpLAogICAgICAgY29sPWMoImJsdWUiLCAicmVkIiksIGx0eSA9IDE6MiwgY2V4PTAuOCkKYGBgCgojIyMjIFByb27Ds3N0aWNvIE1vdmluZyBBdmVyYWdlIApgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzdW1tYXJ5KG1hX21vZGVsPC1hcm1hKGJkX2V4dGVybmEkVG90YWxfUHJvZHVjdGlvbixvcmRlcj1jKDAsMSkpKQptYV9tb2RlbF9mb3JlY2FzdDwtZm9yZWNhc3QobWFfbW9kZWwkZml0dGVkLGg9MyxsZXZlbD1jKDk1KSkKbWFfbW9kZWxfZm9yZWNhc3QKYGBgCgojIyMgKipQcm9uw7NzdGljbyBJbmR1c3RyaWEgQXV0b21vdHJpeiBNw6l4aWNvKioKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdChiZF9leHRlcm5hTVgkYcOxbyxiZF9leHRlcm5hTVgkdW5pZGFkZXNfdmVudGFzLCB0eXBlPSJsIixjb2w9ImJsdWUiLCBsd2Q9MS41LCB4bGFiID0iQcOxbyIseWxhYiA9Ik1pbGxvbmVzIGRlIHZlbnRhcyIsIG1haW4gPSAiVmVudGFzIGFudWFsZXMiKQpsaW5lcyhiZF9leHRlcm5hTVgkYcOxbyxiZF9leHRlcm5hTVgkdW5pZGFkZXNfdmVudGFzLGNvbD0icmVkIixsdHk9MykKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQptYV9tb2RlbDwtIGJkX2V4dGVybmFNWAptYV9tb2RlbF9mb3JlY2FzdDwtZm9yZWNhc3QobWFfbW9kZWwkdW5pZGFkZXNfdmVudGFzLGg9MyxsZXZlbD1jKDk1KSkKbWFfbW9kZWxfZm9yZWNhc3QKYGBgCgpQb2RlbW9zIHZlciBxdWUgZW4gbGEgaW5kdXN0cmlhIEF1dG9tb3RyaXogZGUgTVgsIGVzcGVjw61maWNhbWVudGUgZW4gdmVudGFzIGRlIG1vdG9yZXMsIHRlbmVtb3MgdW5hIHRlbmRlbmNpYSBlbiBkZWNyZWNpbWlldG8geSBxdWUgbnVlc3Ryb3MgaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgdmFuIGRpc21pbnV5ZW5kbywgcGVybyBsYXMgcHJlZGljY2lvbmVzIHNlIGVuY3VlbnRyYW4gZW50cmUgODg3ODAxLTY3MjA4NyBkZSB2ZW50YXMgYW51YWxlcyBkZSBtb3RvcmVzIGVuIE1YIHBhcmEgbG9zIHByw7N4aW1vcyBhw7Fvcy4KCiMjIyAqKlByb27Ds3N0aWNvIFByb2R1Y2Npw7NuIEZPUk0qKgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwbG90KGRhdGE2JEZlY2hhLGRhdGE2JFBJRVpBUy5QUk9HLiwgdHlwZT0ibCIsY29sPSJibHVlIiwgbHdkPTEuNSwgeGxhYiA9IkZlY2hhIix5bGFiID0iUGllemFzIHByb2dyYW1hZGFzIiwgbWFpbiA9ICJQaWV6YXMgcHJvZ3JhbWFkYXMgcG9yIGZlY2hhIikKbGluZXMoZGF0YTYkRmVjaGEsZGF0YTYkTGFtaW5hcy5wcm9jZXNhZGFzLGNvbD0icmVkIixsdHk9MykKbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kPWMoIlBpZXphcyBwcm9ncmFtYWRhcyIsICJMYW1pbmFzIHByb2Nlc2FkYXMiKSwKICAgICAgIGNvbD1jKCJibHVlIiwgInJlZCIpLCBsdHkgPSAxOjIsIGNleD0wLjgpCmBgYAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KKG1hX21vZGVsPC1hcm1hKGRhdGE2JFBJRVpBUy5QUk9HLixvcmRlcj1jKDAsMSkpKQptYV9tb2RlbF9mb3JlY2FzdDwtZm9yZWNhc3QobWFfbW9kZWwkZml0dGVkLGg9MyxsZXZlbD1jKDk1KSkKbWFfbW9kZWxfZm9yZWNhc3QKYGBgCgoKIyMjICoqUHJvbsOzc3RpY28gRGVsaXZlcnkgUGxhbiBGT1JNKioKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGxvdChkcDEkRmVjaGEsZHAxJFBlZGlkb3MsIHR5cGU9ImwiLGNvbD0iYmx1ZSIsIGx3ZD0xLjUsIHhsYWIgPSJGZWNoYSIseWxhYiA9IlBpZXphcyBwcm9ncmFtYWRhcyIsIG1haW4gPSAiUGllemFzIHByb2dyYW1hZGFzIHBvciBmZWNoYSIpCmxpbmVzKGRwMSRGZWNoYSxkcDEkQ0xJRU5URSxjb2w9InJlZCIsbHR5PTMpCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZD1jKCJQaWV6YXMgcHJvZ3JhbWFkYXMiLCAiTGFtaW5hcyBwcm9jZXNhZGFzIiksCiAgICAgICBjb2w9YygiYmx1ZSIsICJyZWQiKSwgbHR5ID0gMToyLCBjZXg9MC44KQpgYGAKCgpgYGB7cn0KIyBTdW1hciBlbCBUb3RhbCBkZSBQZWRpZG9zeE1lcwpwZWRpZG9zIDwtIGMoMTg3ODksMjM5MzIsNTI1NTMsNDQxMDAsMzc4MDAsNjQyNzksNDI3MDUsNjYwNjAsMTEyMDApCgpwZWRpZG9zX3N0IDwtIHRzKGRhdGEgPSBwZWRpZG9zLCBzdGFydCA9IGMoMjAyMiwxKSwgZnJlcXVlbmN5ID0gMTIpCnBlZGlkb3Nfc3QKYGBgCgpgYGB7cn0KbW9kZWxvIDwtIGF1dG8uYXJpbWEocGVkaWRvc19zdCkKbW9kZWxvCgpwcm9ub3N0aWNvIDwtIGZvcmVjYXN0KG1vZGVsbywgbGV2ZWw9Yyg5NSksIGg9MykKcHJvbm9zdGljbwpwbG90KHByb25vc3RpY28pCmBgYAoKIyMjICoqUHJvbsOzc3RpY28gTWVybWEgRk9STSoqCgpgYGB7cn0KIyBTdW1hciBlbCBUb3RhbCBkZSBLaWxvc3hNZXMKbWVybWEgPC0gYygxNDU2MCwyMjgzMCwyMjQ3MCwxODgyMCwyMzQxMCwxODI4MCwxOTM3MCwzMjEwMCwxMzU4NikKCm1lcm1hX3N0IDwtIHRzKGRhdGEgPSBtZXJtYSwgc3RhcnQgPSBjKDIwMjIsMSksIGZyZXF1ZW5jeSA9IDEyKQptZXJtYV9zdApgYGAKCmBgYHtyfQptb2RlbG8gPC0gYXV0by5hcmltYShtZXJtYV9zdCkKbW9kZWxvCgpwcm9ub3N0aWNvIDwtIGZvcmVjYXN0KG1vZGVsbywgbGV2ZWw9Yyg5NSksIGg9MykKcHJvbm9zdGljbwpwbG90KHByb25vc3RpY28pCmBgYAoKCiMjIyBSZXN1bHRhZG9zOiDCv0N1w6FsIGVzIGxhIHRlbmRlbmNpYT8KClBvZGVtb3MgdmVyIHF1ZSBlbiBsYSBpbmR1c3RyaWEgQXV0b21vdHJpeiBkZSBVU0EsIGVzcGVjw61maWNhbWVudGUgZW4gdmVudGFzIGRlIG1vdG9yZXMsIHRlbmVtb3MgdW5hIHRlbmRlbmNpYSBjb250aW51YSB5IHF1ZSBudWVzdHJvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSBiYW4gZGlzbWludXllbmRvLCBwZXJvIGxhcyBwcmVkaWNjaW9uZXMgc2UgZW5jdWVudHJhbiBlbnRyZSA4MzE1LjczMi0xMjU5NS42MSBkZSB2ZW50YXMgYW51YWxlcyBkZSBtb3RvcmVzIGVuIFVTQSBwYXJhIGxvcyBwcsOzeGltb3MgYcOxb3MuCgpQYXJhIEZvcm0gYWwgZGVzYXJyb2xsYXIgZWwgcHJvbsOzc3RpY28gZGUgTWVybWEgdmVtb3MgcXVlIHRlbmVtb3MgcXVlIHBhcmEgbG9zIHByw7N4aW1vcyBwZXJpb2RvcyBkZSBvY3R1YnJlLCBub3ZpZW1icmUgeSBkaWNpZW1icmUgdGVuZHJlbW9zIHVuYSBjYW50aWRhZCBjb25zdGFudGUgZGUgMjA2MDIuODkga2lsb3MgZGUgbWVybWEgeSBxdWUgbnVlc3RybyBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGNhZSBlbnRyZSA5NzcwLjcxMSBhIDMxNDM1LjA3LkludGVycHJldGFuZG8gbGEgaW5mb3JtYWNpw7NuIHZlbW9zIHF1ZSBhIGNvbXBhcmFjacOzbiBkZWwgw7psdGltbyBtZXMgZGUgc2VwdGllbWJyZSwgbG9zIGtpbG9zIGNyZWNlcsOhbi4KCgojICoqRGVmaW5pY2nDs24gc2VnbWVudG9zOiBLLU1lYW5zIENsdXN0ZXJpbmcqKgojIyMgRGVmaW5pY2nDs24gZGUgY29uY2VwdG9zLgoqKjEuIEsgLSBtZWFucyBDbHVzdGVyaW5nKiogIApLLW1lYW5zIGVzIHVuIG3DqXRvZG8gZGUgYWdydXBhbWllbnRvLCBxdWUgdGllbmUgY29tbyBvYmpldGl2byBsYSBwYXJ0aWNpw7NuIGRlIHVuIGNvbmp1bnRvIGRlIG9ic2VydmFjaW9uZXMgZW4gayBncnVwb3MgZW4gZWwgcXVlIGNhZGEgb2JzZXJ2YWNpw7NuIHBlcnRlbmVjZSBhbCBncnVwbyBjdXlvIHZhbG9yIG1lZGlvIGVzIG3DoXMgY2VyY2Fuby4gIERlIGVzdGEgbWFuZXJhIGVzIHF1ZSBzZSBwdWVkZSBhbmFsaXphciBjYWRhIENsdXN0ZXIsIG9idGVuaWVuZG8gaW5mb3JtYWNpw7NuIGltcG9ydGFudGUgZGUgY2FkYSB2YXJpYWJsZSB5IGxhcyBzaW1pbGl0dWRlcyBlbnRyZSBlbGxhcy4gVW4gY2xhcm8gZWplbXBsbyBkZSBjw7NtbyBmdW5jaW9uYSBlcyB1c2FyIGNsdXN0ZXJpbmcgcGFyYSBjb21wcmltaXIgaW3DoWdlbmVzIGNvbiBww6lyZGlkYSBkZSBpbmZvcm1hY2nDs24geS9vIGNvbXByZW5kZXIgcXXDqSBoYWNlIGEgbG9zIGNsaWVudGVzIGRpZmVyZW50ZXMgcGFyYSBwb2RlciBvZnJlY2VybGVzIGxvcyBwcm9kdWN0b3MgeSBzZXJ2aWNpb3MgcXVlIG5lY2VzaXRlbi4gIAogIAoKKioyLiBVbnN1cGVydmlzZWQgTGVhcm5pbmcqKiAgIApFbCDigJxVbnN1cGVydmlzZWQgTGVhcm5pbmfigJ0gdXRpbGl6YSBhbGdvcml0bW9zIGRlIGFwcmVuZGl6YWplIGF1dG9tw6F0aWNvIHBhcmEgYW5hbGl6YXIgeSBhZ3J1cGFyIGNvbmp1bnRvcyBkZSBkYXRvcyBzaW4gZXRpcXVldGFyLiBFc3RvcyBhbGdvcml0bW9zIGRlc2N1YnJlbiBwYXRyb25lcyBvY3VsdG9zIG8gYWdydXBhY2lvbmVzIGRlIGRhdG9zIHNpbiBuZWNlc2lkYWQgZGUgaW50ZXJ2ZW5jacOzbiBodW1hbmEuIE5vIHNlIGFzaWduYW4gZXRpcXVldGFzIGFsIGFsZ29yaXRtbyBkZSBhcHJlbmRpemFqZSwgZGVqw6FuZG9sbyBzb2xvIHBhcmEgZW5jb250cmFyIGxhIGVzdHJ1Y3R1cmEgZW4gc3UgZW50cmFkYS4gRWwgVW5zdXBlcnZpc2VkIExlYXJuaW5nIHB1ZWRlIHNlciB1biBvYmpldGl2byBlbiBzw60gbWlzbW8gKGRlc2N1YnJpciBwYXRyb25lcyBvY3VsdG9zIGVuIGxvcyBkYXRvcykgbyB1biBtZWRpbyBwYXJhIGxvZ3JhciB1biBmaW4gKGFwcmVuZGl6YWplIGRlIGZ1bmNpb25lcykuICAKICAKCioqMy4gRGlzdGFuY2lhIEV1Y2xpZGlhbmEgLyBFdWNsaWRlYW4gRGlzdGFuY2UqKiAgCkxhIGRpc3RhbmNpYSBldWNsaWRpYW5hIHNlIGRlZmluZSBjb21vIGxhIGRpc3RhbmNpYSBlbnRyZSBkb3MgcHVudG9zLiBMYSBkaXN0YW5jaWEgZXVjbGlkaWFuYSBlbnRyZSBkb3MgcHVudG9zIGVuIGVsIGVzcGFjaW8gZXVjbGlkaWFubyBzZSBkZWZpbmUgY29tbyBsYSBsb25naXR1ZCBkZWwgc2VnbWVudG8gZGUgbMOtbmVhIGVudHJlIGRvcyBwdW50b3MuIExhIGhlcnJhbWllbnRhIERpc3RhbmNpYSBldWNsaWRpYW5hIHNlIHV0aWxpemEgY29uIGZyZWN1ZW5jaWEgY29tbyB1bmEgaGVycmFtaWVudGEgaW5kZXBlbmRpZW50ZSBwYXJhIGFwbGljYWNpb25lcywgY29tbyBlbmNvbnRyYXIgZWwgaG9zcGl0YWwgbcOhcyBjZXJjYW5vIHBhcmEgdW4gdnVlbG8gZGUgZW1lcmdlbmNpYSBlbiBoZWxpY8OzcHRlcm8uIEFsdGVybmF0aXZhbWVudGUsIGVzdGEgaGVycmFtaWVudGEgc2UgcHVlZGUgdXNhciBhbCBjcmVhciB1biBtYXBhIGRlIGlkb25laWRhZCwgY3VhbmRvIHNlIG5lY2VzaXRhbiBkYXRvcyBxdWUgcmVwcmVzZW50YW4gbGEgZGlzdGFuY2lhIGRlc2RlIHVuIG9iamV0byBkZXRlcm1pbmFkby4gIAogIAogIAojIyMgUHJpbWVyIHB1bnRvOiBHZW5lcmFyICBDbHVzdGVycy4KICAKKkRlc2NhcmdhciBsaWJyZXLDrWFzKgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGZvcmVpZ24pCmxpYnJhcnkoZHBseXIpICAgICAgICAjIGRhdGEgbWFuaXB1bGF0aW9uIApsaWJyYXJ5KGdncGxvdDIpICAgICAgIyBkYXRhIHZpc3VhbGl6YXRpb24gCiNpbnN0YWxsLnBhY2thZ2VzKCJwc3ljaCIpCmxpYnJhcnkocHN5Y2gpICAgICAgICAjIGZ1bmN0aW9ucyBmb3IgbXVsdGl2YXJpYXRlIGFuYWx5c2lzIApsaWJyYXJ5KGNvcnJwbG90KSAgICAgIyBjb3JyZWxhdGlvbiBwbG90cwpsaWJyYXJ5KGp0b29scykgICAgICAgIyBwcmVzZW50YXRpb24gb2YgcmVncmVzc2lvbiBhbmFseXNpcyAKbGlicmFyeShsbXRlc3QpICAgICAgICMgZGlhZ25vc3RpYyBjaGVja3MgLSBsaW5lYXIgcmVncmVzc2lvbiBhbmFseXNpcyAKbGlicmFyeShjYXIpICAgICAgICAgICMgZGlhZ25vc3RpYyBjaGVja3MgLSBsaW5lYXIgcmVncmVzc2lvbiBhbmFseXNpcwpsaWJyYXJ5KGZhY3RvZXh0cmEpICAgIyBwcm92aWRlcyBmdW5jdGlvbnMgdG8gZXh0cmFjdCBhbmQgdmlzdWFsaXplIHRoZSBvdXRwdXQgb2YgZXhwbG9yYXRvcnkgbXVsdGl2YXJpYXRlIGRhdGEgYW5hbHlzZXMKI2luc3RhbGwucGFja2FnZXMoImdnZm9ydGlmeSIpCmxpYnJhcnkoZ2dmb3J0aWZ5KSAgICAjIGRhdGEgdmlzdWFsaXphdGlvbiB0b29scyBmb3Igc3RhdGlzdGljYWwgYW5hbHlzaXMgcmVzdWx0cwpsaWJyYXJ5KGdnYWxsdXZpYWwpCmBgYAoKKlNlIGltcG9ydGEgbGEgYmFzZSBkZSBkYXRvcyBkZSBCQUpBUyB5YSBsaW1waWEuKgpgYGB7cn0KI2ZpbGUuY2hvb3NlKCkKYmFqYXM8LXJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0NsdXN0ZXJzQmFqYXNGT1JNLmNzdiIpCnN1bW1hcnkoYmFqYXMpCmBgYAoKwr9DdcOhbnRvcyBOQSAgdGVuZ28gcG9yIHZhcmlhYmxlcz8KYGBge3J9CnNhcHBseShiYWphcyxmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQpgYGAKCiMjIyMgKioxLiBFZGFkIHkgIGR1cmFjacOzbiAtIDQgQ2x1c3RlcnMqKgpgYGB7cn0KYmFqYXNfbmV3PC1iYWphcwpiYWphc19uZXc8LXN1YnNldChiYWphc19uZXcsc2VsZWN0ID0gLWMoYWx0YSxlc3RhZG8sbm9tYnJlKSkKc3VtbWFyeShiYWphc19uZXcpCmBgYAoKU2UgdG9tYW4gZW4gY3VlbnRhIGxhIGVkYWQgeSBsYSBkdXJhY2nDs24gZGVudHJvIGRlIGxhIGVtcHJlc2EuIApgYGB7cn0KYmFqYXNfZWRhZGR1cl9ub3JtPC1zY2FsZShiYWphc19uZXdbMToyXSkgCmBgYAoKYGBge3J9CmZ2aXpfbmJjbHVzdChiYWphc19lZGFkZHVyX25vcm0sIGttZWFucywgbWV0aG9kPSJ3c3MiKSsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTQsIGxpbmV0eXBlPTIpKyAgICAgICAgIAogIGxhYnMoc3VidGl0bGUgPSAiRWxib3cgbWV0aG9kIikgIApgYGAKClNlIHRvbWFuIGVuIGN1ZW50YSwgcHJpbWVyYW1lbnRlLCBzb2xvIDQgY2x1c3RlcnMuCgpgYGB7cn0KZWRhZF9jbHVzdGVyMTwta21lYW5zKGJhamFzX2VkYWRkdXJfbm9ybSw0KQplZGFkX2NsdXN0ZXIxCmBgYAoKYGBge3J9CmZ2aXpfY2x1c3RlcihlZGFkX2NsdXN0ZXIxLGRhdGE9YmFqYXNfZWRhZGR1cl9ub3JtKQpgYGAKCkFsIG9ic2VydmFyIHZlbW9zIGN1YXRybyBjbHVzdGVycyBxdWUgdG9tYW4gZW4gY3VlbnRhIGxhIGVkYWQgeSBsYSBkdXJhY2nDs246ICAKMS4gRWwgcm9qbyAoc2Vyw6EgbGxhbWFkbyAiU2VuaW9yIikgZXMgdW4gY2x1c3RlciBxdWUgb2JzZXJ2YW1vcyBxdWUgc29uIHBlcnNvbmFzIGRlIGVkYWQgbWVkaWFuYS1hbHRhIHkgcXVlIGR1csOhbiByZWxhdGl2YW1lbnRlIHBvY28gdGllbXBvLCBlbnRyYW4gZGVudHJvIGRlbCAyNSUgY29uIG1lbm9yIGR1cmFjacOzbi4gICAKMi4gRWwgdmVyZGUgKCJFeHBlcnQiKSBlcyBlbCBjbHVzdGVyIHF1ZSBtw6FzIHNlIGFwYXJ0YSBkZSBsb3MgZGVtw6FzOyBzb24gcGVyc29uYXMgY29uIHVuIG1heW9yIHJhbmdvIGRlIGVkYWQgcGVybyBxdWUgc2UgYWxlamFuIGRlIGxvcyBtw6FzIGrDs3ZlbmVzLCB5ICBxdWUgaGFuIGR1cmFkbyBtdWNobyBtw6EgdGllbXBvLiBTZSBlbmN1ZW50cmFuIGVuIGVsIDUwJSBzdXBlcmlvciBkZWwgdGllbXBvIGRlIGR1cmFjacOzbi4gIAozLiBFbCBhenVsICgianVuaW9yIikgcmVzdWx0YSBlbCBjbHVzdGVyIGludGVybWVkaW8gZGUgbG9zIGRlIG1lbm9yIGR1cmFjacOzbi4gU29uIHBlcnNvbmFzIGVuICB1biByYW5nbyBkZSBlZGFkIG1lZGlvIHF1ZSB0YW1iacOpbiBzb24gcGFydGUgZGVsIDI1JSBpbmZlcmlvciBxdWUgbcOhcyBoYW4gZHVyYWRvLiAgCjQuIEVsIG1vcmFkbyAoImJlZ2lubmVyIikgZXMgZWwgc2VnbWVudG8gbcOhcyBqb3ZlbiB5IHF1ZSBkZSBsYXMgcGVyc29uYXMgKGVuIGdlbmVyYWwpIG1lbm9zIGhhbiBkdXJhZG8uIFNlIHB1ZWRlIGNvbnNpZGVyYXIgcXVlIGxvcyBqw7N2ZW5lcyBzb24gbG9zIHF1ZSBtZW5vcyBkdXJhbiBlbiBGb3JtIGEgcGFydGlyIGRlIGVzdGUgY2x1c3Rlci4gCgpgYGB7cn0KYmFqYXNfbmV3MjwtYmFqYXNfbmV3CmJhamFzX25ldzIkQ2x1c3RlcnM8LWVkYWRfY2x1c3RlcjEkY2x1c3RlcgpiYWphc19uZXczPC1iYWphc19uZXcyICU+JSBncm91cF9ieShDbHVzdGVycykgJT4lIGRwbHlyOjogc3VtbWFyaXNlKGVkYWQ9bWF4KGVkYWQpKSAlPiUgYXJyYW5nZShkZXNjKGVkYWQpKQpiYWphc19uZXcyJENsdXN0ZXJfTmFtZXM8LWZhY3RvcihiYWphc19uZXcyJENsdXN0ZXJzLGxldmVscyA9IGMoMSwyLDMsNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiU2VuaW9yIiwgIkV4cGVydCIsICJKdW5pb3IiLCAiQmVnaW5uZXIiKSkKYGBgCgpgYGB7cn0KYmFqYXNfbmV3NCA8LSBiYWphc19uZXcyICU+JSBncm91cF9ieShDbHVzdGVyX05hbWVzKSAlPiUgZHBseXI6OnN1bW1hcmlzZShlZGFkX2HDsW9zPW1heChlZGFkKSwgCmR1cmFjaW9uPW1lYW4oZHVyYWNpb24pLApDb3VudD1uKCkpCmBgYAoKCmBgYHtyfQpjbHVzdGVyczwtYXMuZGF0YS5mcmFtZShiYWphc19uZXc0KQpjbHVzdGVycwpgYGAKCkEgcGFydGlyIGRlIGxhIHRhYmxhLCBvYnNlcnZhbW9zIGxhcyBlZGFkZXMgbcOheGltYXMgZW5jb250cmFkYXMgZW4gY2FkYSBjbMO6c3Rlci4gQ29ub2NlbW9zIHF1ZSBsYSBwZXJzb25hIGNvbiBtYXlvciBlZGFkIGVuIGxvcyAqZXhwZXJ0KiB0aWVuZSA2MSwgZW4gKnNlbmlvciogdGllbmUgNTcsIGVuICpqdW5pb3IqIHRpZW5lIDM5IHkgZW4gKmJlZ2lubm5lciogMjcuICAgCgpJZ3VhbG1lbnRlLCB2ZW1vcyBsYSBkdXJhY2nDs24gbcOheGltYSBxdWUgaGEgZHVyYWRvIGFsZ3VpZW4gZGUgY2FkYSBjbHVzdGVyLCBjb21wYXJhbW9zIGVsIG3DoXhpbW8gZGVsIG1heW9yLCAqZXhwZXJ0KiwgcXVlIGhhbiBzaWRvIG3DoXMgZGUgMSw1MDAgZMOtYXMsIGNvbiBlbCBtw6F4aW1vIGRlbCBtZW5vciwgKmJlZ2lubmVyKiwgcXVlIGhhbiBzaWRvIDQ2IGTDrWFzLiAKCmBgYHtyfQpnZ3Bsb3QoYmFqYXNfbmV3NCxhZXMoeD1yZW9yZGVyKENsdXN0ZXJfTmFtZXMsQ291bnQpLHk9Q291bnQsZmlsbD1DbHVzdGVyX05hbWVzKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikKYGBgCgpFeGlzdGUgdW5hIG1heW9yIGNhbnRpZGFkIGRlICJiZWdpbm5lcnMiLgoKCmBgYHtyfQpnZ3Bsb3QoYmFqYXNfbmV3NCwgYWVzKHg9Q2x1c3Rlcl9OYW1lcyx5PWVkYWRfYcOxb3MsZmlsbD0gQ2x1c3Rlcl9OYW1lcyxsYWJlbD1yb3VuZChlZGFkX2HDsW9zLGRpZ2l0cz0yKSkpICsgCiAgZ2VvbV9jb2woKSArIAogIGdlb21fdGV4dCgpCmBgYAoKQ29tcGFyYW1vcyBsYSBlZGFkIG3DoXhpbWEgZW4gY2FkYSBjbMO6c3RlciAoZGVzY3JpdG8gYW50ZXJpb3JtZW50ZSkuCgpgYGB7cn0KZ2dwbG90KGJhamFzX25ldzQsYWVzKHg9Q2x1c3Rlcl9OYW1lcyx5PWR1cmFjaW9uLGZpbGw9IENsdXN0ZXJfTmFtZXMsbGFiZWw9cm91bmQoZHVyYWNpb24sZGlnaXRzPTIpKSkgKyAKICBnZW9tX2NvbCgpICsgCiAgZ2VvbV90ZXh0KCkKYGBgCgpDb21wYXJhbW9zIGxvcyBkw61hcyBtw6F4aW1vcyBlbiBjYWRhIGNsw7pzdGVyIChkZXNjcml0byBhbnRlcmlvcm1lbnRlKS4KCgojIyMjICoqMi4gRWRhZCB5ICBkdXJhY2nDs24gLSA1IENsdXN0ZXJzKioKCkRlYmlkbyBhIHF1ZWUgdW5hIGdyw6FmaWNhIGFudGVyaW9yIGluZGljYWJhIGxhIHBvc2liaWxpZGFkIGRlIHRlbmVyIG90cm8gY2zDunN0ZXIgcXVlIGRlc2NyaWJhIGEgb3RybyBncnVwbywgaGFjZW1vcyBsbyBtaXNtbyBjb24gNSBzZWdtZW50b3MsIGVuIHZleiBkZSA0LiAKCmBgYHtyfQpiYWphc19lZGFkZHVyX25vcm0yPC1zY2FsZShiYWphc19uZXdbMToyXSkgCmBgYAoKYGBge3J9CmZ2aXpfbmJjbHVzdChiYWphc19lZGFkZHVyX25vcm0yLCBrbWVhbnMsIG1ldGhvZD0id3NzIikrIAogIGdlb21fdmxpbmUoeGludGVyY2VwdD00LCBsaW5ldHlwZT0yKSsgICAgICAgICAKICBsYWJzKHN1YnRpdGxlID0gIkVsYm93IG1ldGhvZCIpICAKYGBgCgpgYGB7cn0KZWRhZF9jbHVzdGVyMjwta21lYW5zKGJhamFzX2VkYWRkdXJfbm9ybSw1KQplZGFkX2NsdXN0ZXIyCmBgYAoKYGBge3J9CmZ2aXpfY2x1c3RlcihlZGFkX2NsdXN0ZXIyLGRhdGE9YmFqYXNfZWRhZGR1cl9ub3JtMikKYGBgCgpDb21wYXJhbmRvIGVzdGEgIGdyw6FmaWNhIGRlIDUgc2VnbWVudG9zIGNvbnRyYSBsYSBhbnRlcmlvcm1lbnRlIHZpc3RhIGRlIDQuIEVuIGVzdGEgb2JzZXJ2YW1vcyBxdWUgc2VwYXJhIHVuIHNlZ21lbnRvIHF1ZSBkZWphIHVuICJlc3BhY2lvIiBxdWUgYW50ZXMgbm8gZXhpc3TDrWE7IHNlcGFyYSB5IGNyZWEgdW4gc2VnbWVudG8gcXVlIGhhbiBkdXJhZG8gYXByb3ggdW4gMTAlIG3DoXMgZGUgdGllZW1wbyBxdWUgbGFzIHRyZXMgbWVub3JlcywgeSBxdWUgc2UgZW5jdWVudHJhIGVuIHJhbmdvcyBkZSBlZGFkIHBhcmVjaWRvcy4gQSBjb250aW51YWNpw7NuIHNlIGNvbXBhcmFuIGxvcyBjbHVzdGVyczogIAoxLiBFbCByb2pvIChsbGFtYWRvICJTZW5pb3IiKTogZXMgZWwgbnVldm8sIGVsIGN1YWwgdGllbmUgZGUgYmFqYSBhIG1lZGlhbmEgZHVyYWNpw7NuIHkgdW4gcmFuZ28gZGUgZWRhZCBtZWRpYW5hLiBEZXNwdcOpcyBkZSBsb3MgcXVlIGhhbiBkdXJhZG8gbXVjaG8sIGVsbG9zIHZhbiBkZXNwdcOpcy4gIAogIAoyLiBFbCB2ZXJkZSBzdXBlcmlvciAobGxhbWFkbyAiRXhwZXJ0Iik6IGVzIGVsIGNsdXN0ZXIgcXVlIG3DoXMgc2UgYXBhcnRhIGRlIGxvcyBkZW3DoXM7IHNvbiBwZXJzb25hcyBjb24gdW4gbWF5b3IgcmFuZ28gZGUgZWRhZCBwZXJvIHF1ZSBzZSBhbGVqYW4gZGUgbG9zIG3DoXMgasOzdmVuZXMsIHkgIHF1ZSBoYW4gZHVyYWRvIG11Y2hvIG3DoSB0aWVtcG8uIFNlIGVuY3VlbnRyYW4gZW4gZWwgNTAlIHN1cGVyaW9yIGRlbCB0aWVtcG8gZGUgZHVyYWNpw7NuLiAgCiAgCjMuIEVsIHZlcmRlIGluZmVyaW9yIChsbGFtYWRvICJKdW5pb3IiKSBzb24gcGVyc29uYXMgYWR1bHRhcyBxdWUgaGFuIGR1cmFkbyBwb2NvIHRpZW1wbyBlbiBsYSBlbXByZXNhLCBwYXJ0ZSBkZWwgMTclIGluZmVyaW9yIGRlIGR1cmFjacOzbi4gICAKICAgIAo0LiBFbCBtb3JhZG8gKGxsYW1hZG8gIk1pZGRsZSIpOiBhbCBoYWNlciBlbCBudWV2byBjbMO6c3RlciBub3MgZGFtb3MgY3VlbnRhIGRlIHF1ZSBleGlzdGUgdW4gZ3J1cG8gZGUgcGVyc29uYXMgZGUgbWVkaWFuYSBlZGFkIHF1ZSBkdXJhbiAqKm11eSoqIHBvY28sIGHDum4gbcOhcyBwb2NvIHF1ZSBsb3MgasOzdmVuZXMuICpJbnZlc3RpZ2FyIGVzdGFkbyBjaXZpbCouICAKICAKNS4gRWwgYXp1bCAobGxhbWFkbyAiQmVnaW5uZXIiKTogc29uIGxhcyBwZXJzb25hcyBtw6FzIGrDs3ZlbmVzIHkgcXVlIHRhbWJpw6luIGhhbiBkdXJhZG8gcG9jbyB0aWVtcG8uIFNlIHF1ZWRhbiBhcHJveGltYWRhbWVudGUgcG9yIGVsIDEwJSBpbmZlcmlvci4gIAoKCmBgYHtyfQpiYWphc19uZXc2PC1iYWphc19uZXcKYmFqYXNfbmV3NiRDbHVzdGVyczwtZWRhZF9jbHVzdGVyMiRjbHVzdGVyCmJhamFzX25ldzc8LWJhamFzX25ldzYgJT4lIGdyb3VwX2J5KENsdXN0ZXJzKSAlPiUgc3VtbWFyaXNlKGVkYWQ9bWF4KGVkYWQpKSAlPiUgYXJyYW5nZShkZXNjKGVkYWQpKQpiYWphc19uZXc2JENsdXN0ZXJfTmFtZXM8LWZhY3RvcihiYWphc19uZXc2JENsdXN0ZXJzLGxldmVscyA9IGMoMSwyLDMsNCw1KSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJTZW5pb3IiLCAiRXhwZXJ0IiwgIkp1bmlvciIsICJNaWRkbGUiLCJCZWdpbm5lciIpKQpgYGAKCkFsIGFuYWxpemFyIGVsIGVzdGFkbyBjaXZpbCBkZSBsb3MgNSBjbMO6c3RlcnMsIGxsZWdhbW9zIGEgbGFzIHNpZ3VpZW50ZXMgY29uY2x1c2lvbmVzOiAgCjEuIERlbCBzZWdtZW50byAiU2VuaW9yIiwgZWwgNzUlIHNvbiBzb2x0ZXJvcy4gRXN0ZSBlcyBlbCBudWV2byBjbMO6c3RlciBkZXNjdWJpZXJ0by4gIAoyLiBFbCA1NSUgZGUgbGFzIHBlcnNvbmFzIGVuIGVsIGNsdXN0ZXIgIk1pZGRsZSIgKG1lbm9yIGR1cmFjacOzbikgc29uIHNvbHRlcmFzLCBlbCAyNiUgdml2ZW4gZW4gdW5pw7NuIGxpYnJlLCB5IHVuIDE5JSBxdWUgdml2ZW4gZW4gbWF0cmltb25pby4gIAozLiBEZSBsb3MgZXhwZXJ0b3MsIGVsIDc1JSBzb24gc29sdGVyb3MuICAgCgojIyMjICoqMy4gRHVyYWNpw7NuIHkgc2FsYXJpbyoqCgoqSW1wb3J0YXIgYmFzZSBkZSBkYXRvcyoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcmhfYmFqYXMgPC1yZWFkLmNzdigiL1VzZXJzL2dlb3JnaW5hbWFydGluZXovRG9jdW1lbnRzL1RlYy9TZcyBcHRpbW8gU2VtZXN0cmUvQW5hbGnMgXRpY2EgcGFyYSBuZWdvY2lvcywgZGUgbG9zIGRhdG9zIGEgZGVjaXNpb25lcy9DbHVzdGVyc0JhamFzRk9STS5jc3YiKQpgYGAKCgoKQmFzZSBkZSBkYXRvcyBjb24gdmFsb3JlcyBDVUFOVElUQVRJVk9TCmBgYHtyfQpyaF9iYWphczI8LXJoX2JhamFzCnJoX2JhamFzMjwtc3Vic2V0KHJoX2JhamFzMixzZWxlY3QgPSAtYyhhbHRhLGVzdGFkbyxub21icmUpKQpzdW1tYXJ5KHJoX2JhamFzMikKYGBgCgpOb3JtYWxpemFuZG8gbGFzIHZhcmlhYmxlcwpgYGB7cn0KYmFqYXNfZHVyYWNpb25fbm9ybTwtc2NhbGUocmhfYmFqYXMyWzI6M10pIApgYGAKCkVsYm93IFBsb3QKYGBge3J9CmZ2aXpfbmJjbHVzdChiYWphc19kdXJhY2lvbl9ub3JtLCBrbWVhbnMsIG1ldGhvZD0id3NzIikrIAogIGdlb21fdmxpbmUoeGludGVyY2VwdD01LCBsaW5ldHlwZT0yKSsgICAgICAgICAKICBsYWJzKHN1YnRpdGxlID0gIkVsYm93IG1ldGhvZCIpICAKYGBgCgpWaXN1YWxpemFjacOzbiBpbmZvcm1hY2nDs24gZGUgY2x1c3RlcnMKYGBge3J9CmR1cmFjaW9uX2NsdXN0ZXIxPC1rbWVhbnMoYmFqYXNfZHVyYWNpb25fbm9ybSw1KQpkdXJhY2lvbl9jbHVzdGVyMQpgYGAKClZpc3VhbGl6YWNpw7NuIGNsdXN0ZXJpbmcgcmVzdWx0YWRvcyAKYGBge3J9CmZ2aXpfY2x1c3RlcihkdXJhY2lvbl9jbHVzdGVyMSxkYXRhPWJhamFzX2R1cmFjaW9uX25vcm0pCmBgYAoKQWwgb2JzZXJ2YXIgdmVtb3MgNSBjbHVzdGVycyBxdWUgdG9tYW4gZW4gY3VlbnRhIGxhIGR1cmFjacOzbiB5IGVsIHNhbGFyaW86ICAKCjEuIFByaW1lcm8gdmVtb3MgbnVlc3RybyBjbHVzdGVyIDEgKHNlcsOhIGxsYW1hZG8gIlJlaGVuZXMiKSBlcyB1biBjbHVzdGVyIHF1ZSBvYnNlcnZhbW9zIHF1ZSBzb24gcGVyc29uYXMgcXVlIHNvbG8gZW50cmFuIHkgc2FsZW4gbXV5IHByb250byBkZSBsYSBlbXByZXNhICgxNDEgZMOtYXMpIHkgdGllbmVuIHVuIHNhbGFyaW8gZGlhcmlvIHF1ZSBlcyBhcnJpYmEgZGVsIHByb21lZGlvLCBhbHJlZGVkb3IgZGUgJDE4MCBwZXNvcy4gICAKCjIuIEVsIGNsdXN0ZXIgMiAoIkR1cmFkZXJvcyIpIHNvbiBsb3MgY29sYWJvcmFkb3JlcyBxdWUgdGllbmVuIHVuYSBkdXJhY2nDs24gcmVndWxhciwgcGVybyBxdWUgYXVuIGFzw60gbm8gc2UgZW5jdWVudHJhbiBzYXRpc2ZlY2hvcyBwb3IgbG8gcXVlIHNlIHNhbGVuIGRlIGxhIGVtcHJlc2EgYWwgcmVkZWRvciBkZXNwdcOpcyBkZSAxIGHDsW8geSBtZWRpbyAoNjQ2IGTDrWFzKSB5IHN1IHNhbGFyaW8gZXMgZGUgJDE2OS4gIAoKMy4gQ29tbyBjbHVzdGVyIDMgdGVuZW1vcyBhIGxvcyBjb2xhYm9yYWRvcmVzIHF1ZSBzb24gbGVhbGVzIGEgbGEgZW1wcmVzYSAoIlJlc2lzdGVudGVzIikgZXMgZWwgc2VnbWVudG8gZG9uZGUgZXN0dXZvIG3DoXMgZGUgNC01IGHDsW9zIHRyYWJhamFuZG8geSBjdWVudGFuIGNvbiB1biBzYWxhcmlvIGRlICQxNjggcGVzb3MuICAKCjQuIEVsIGNsdXN0ZXIgNCAoIkNvc3Rvc29zIikgZXMgZWwgY2x1c3RlciBxdWUgbm9zIGN1ZXN0YSBhIGxhIGVtcHJlc2EgcG9ycXVlIHNlIGludmllcnRlIGVuIGNhcGFjaXRhY2lvbmVzIHBhcmEgZWxsb3MgeSB0ZXJtaW5hbiBzYWxpZW5kbyBkZSBsYSBlbXByZXNhOyBzb24gcGVyc29uYXMgY29uIHVuIHBvY28gbWFzIGRlIGR1cmFjacOzbiBwZXJvIG5vIGxhIHN1ZmljaWVudGUgKDE5NyBkw61hcykgeSBzdSBzYWxhcmlvIGVzIGRlICQxNTEgcG9yIGRlYmFqbyBwcm9tZWRpby4gIAoKNS4gUG9yIMO6bHRpbW8gdGVuZW1vcyBlbCBjbHVzdGVyIDUgKCJFeHRyYSIpIHF1ZSB0dXZvIGR1cmFjacOzbiBjb3J0byBwbGF6byBjb24gdW4gc2FsYXJpbyBtdXkgYWx0byAoJDUwMCBwZXNvcykuICAKIAoKCk5vbWJyYXIgYSBsb3MgY2x1c3RlcnMgCmBgYHtyfQpyaF9iYWphczM8LXJoX2JhamFzMgpyaF9iYWphczMkQ2x1c3RlcnM8LWR1cmFjaW9uX2NsdXN0ZXIxJGNsdXN0ZXIKcmhfYmFqYXM0PC1yaF9iYWphczMgJT4lIGdyb3VwX2J5KENsdXN0ZXJzKSAlPiUgZHBseXI6OnN1bW1hcmlzZShkdXJhY2lvbj1tYXgoZHVyYWNpb24pKSAlPiUgYXJyYW5nZShkZXNjKGR1cmFjaW9uKSkKcmhfYmFqYXMzJENsdXN0ZXJfTmFtZXM8LWZhY3RvcihyaF9iYWphczMkQ2x1c3RlcnMsbGV2ZWxzID0gYygxLDIsMyw0LDUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIlJlaGVuZXMiLCAiRHVyYWRlcm9zIiwiUmVzaXN0ZW50ZXMiLCAiQ29zdG9zb3MiLCJFeHRyYSIpKQpgYGAKCkVuZ3J1cGFyIGxvcyBjbHVzdGVycyBwb3Igbm9tYnJlIGRlIGNsdXN0ZXJzIHkgcmVzdW1pciBjb2x1bW5hcwpgYGB7cn0KcmhfYmFqYXM1PC0gcmhfYmFqYXMzICU+JSBncm91cF9ieShDbHVzdGVyX05hbWVzKSAlPiUgZHBseXI6OnN1bW1hcmlzZShkdXJhY2lvbl9kaWFzPW1heChkdXJhY2lvbiksIApzYWxhcmlvX2RpYXJpbz1tZWFuKHNhbGFyaW9fZGlhcmlvKSwKQ291bnQ9bigpKQpgYGAKCgpGb3JtYXRvIHRhYmxhIHBhcmEgaW5mb3JtYWNpw7NuIGRlIGxvcyBjbHVzdGVycyAKYGBge3J9CmNsdXN0ZXJzPC1hcy5kYXRhLmZyYW1lKHJoX2JhamFzNSkKY2x1c3RlcnMKYGBgCgoKR3LDoWZpY2EgY29uIGVsIG51bWVybyBkZSBvYnNlcnZhY2lvbmVzIHBvciBub21icmVzIGRlIGNsdXN0ZXJzIApgYGB7cn0KZ2dwbG90KHJoX2JhamFzNSxhZXMoeD1yZW9yZGVyKENsdXN0ZXJfTmFtZXMsQ291bnQpLHk9Q291bnQsZmlsbD1DbHVzdGVyX05hbWVzKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikKYGBgCgpgYGB7cn0KZ2dwbG90KHJoX2JhamFzNSwgYWVzKHg9Q2x1c3Rlcl9OYW1lcyx5PWR1cmFjaW9uX2RpYXMsZmlsbD0gQ2x1c3Rlcl9OYW1lcyxsYWJlbD1yb3VuZChkdXJhY2lvbl9kaWFzLGRpZ2l0cz0yKSkpICsgCiAgZ2VvbV9jb2woKSArIAogIGdlb21fdGV4dCgpCmBgYAoKCmBgYHtyfQpnZ3Bsb3QocmhfYmFqYXM1LGFlcyh4PUNsdXN0ZXJfTmFtZXMseT1zYWxhcmlvX2RpYXJpbyxmaWxsPSBDbHVzdGVyX05hbWVzLGxhYmVsPXJvdW5kKHNhbGFyaW9fZGlhcmlvLGRpZ2l0cz0yKSkpICsgCiAgZ2VvbV9jb2woKSArIAogIGdlb21fdGV4dCgpCmBgYAoKRXN0w6FzIHVsdGltYXMgZ3LDoWZpY2FzIG5vcyBtdWVzdHJhbiBsbyBxdWUgc2UgZGVzY3JpYmnDsyBhbnRlcmlvcmltZW50ZSBzb2JyZSBxdWUgZHVyYWNpw7NuIHkgc2FsYXJpbyB0aWVuZSBjYWRhIGNsdXN0ZXIgeSBwYXJhIGNvbmNsdWlyIHNlIG1vc3RyYXJhIGN1YW50b3MgY29sYWJvcmFkb3JlcyB0aWVuZSBjYWRhIGNsdXN0ZXI6CgpUb3RhbCAyMzMgCiogKioiUmVoZW5lcyIqKiB0aWVuZSBlbCBzZWdtZW50byBjb24gbcOhcyBjb2xhYm9yYWRvcmVzIHkgdGllbmUgdW4gdG90YWwgZGUgMTkxLiBFbiBwb3JjZW50YWplIHNlIHB1ZWRlIGRlY2lyIHF1ZSBlcyBlbCA4MS45NyUgdG90YWwgZGUgYmFqYXMuICAKCiogKioiQ29zdG9zb3MiKiogZXN0YSBlbiBzZWd1bmRvIGx1Z2FyIHRlbmllbmRvIDI3IGNvbGFib3JhZG9yZXMgKDExLjU3JSkuICAgIAoKKiAqKiJEdXJhZGVyb3MiKiogdGVyY2VyIGx1Z2FyIGNvbiB1biB0b3RhbCBkZSAxMCBjb2xhYm9yYWRvcmVzICg0LjI5JSkuICAKCiogKioiUmVzaXN0ZW50ZXMiKiogY3VhcnRvIGx1Z2FyIGNvbiA0IGNvbGFib3JhZG9yZXMgKDEuNzElKS4gIAoKKiBQb3Igw7psdGltbyBlc3RhIGVsICoqIkV4dHJhIioqIHF1ZSBmdWUgc29sbyB1biBjb2xhYm9yYWRvciBxdWUgc2UgZW5jdWVudHJhIGZ1ZXJhIGRlIGxvIG5vcm1hbCAoMC40MyUpLiAgCgojIyMjICoqNC4gRWRhZCB5IHNhbGFyaW8qKgoKKkltcG9ydGFyIGJhc2UgZGUgZGF0b3MqCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmJkciA8LXJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0Nsc3V0ZXJlZGFkeXNhbGFyaW8uY3N2IikKYGBgCgoKQW5hbGl6YXIgbGEgZXN0cnVjdHVyYSBkZSBsYSBiYXNlIGRlIGRhdG9zCmBgYHtyfQpzdHIoYmRyKSAKYGBgCgpDdWFudG9zIE5hwrRzIGhheSBwb3IgdmFyaWFibGUKCmBgYHtyfQpzYXBwbHkoYmRyLGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpCmBgYAoKRGVqYW1vcyDDum5pY2FtZW50ZSBsYXMgdmFyaWFibGVzIGN1YW50aXRhdGl2YXMKCmBgYHtyfQpiZHIyIDwtIGJkcgpiZHIyPC1zdWJzZXQoYmRyMixzZWxlY3QgPSAtYyhhbHRhLGVzdGFkbyxub21icmUpKQpzdW1tYXJ5KGJkcjIpCmBgYAoKTm9ybWFsaXphY2nDs24gZGUgdmFyaWFibGVzCgpgYGB7cn0KYmRyMyA8LSBzY2FsZShiZHIyWzE6Ml0pIApgYGAKCkVsYm93IHBsb3QKCmBgYHtyfQpmdml6X25iY2x1c3QoYmRyMywga21lYW5zLCBtZXRob2Q9IndzcyIpKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9NCwgbGluZXR5cGU9MikrICAgICAgICAgCiAgbGFicyhzdWJ0aXRsZSA9ICJFbGJvdyBtZXRob2QiKSAKYGBgCgpWaXN1YWxpemFjacOzbiBkZSBjbHVzdGVycwoKYGBge3J9CmJkcjQ8LWttZWFucyhiZHIzLDQpCmJkcjQKCmZ2aXpfY2x1c3RlcihiZHI0LGRhdGE9YmRyMykKYGBgCgpWZW1vcyBxdWUgZWwgbsO6bWVybyDDs3B0aW1vIGRlIGtsdXN0ZXJzIHBhcmEgbGFzIHZhcmlhYmxlcyBlZGFkIHkgc2FsYXJpbyBkaWFyaW8gc29uIDQgc2Vnw7puIGVsIG3DqXRvZG8gZGUgRWxib3cuCgpDb21vIGRhdG8gZGlzcGFyYWRvIHkgcG9zaWJsZSB3YXJuaW5nIHZlbW9zIHF1ZSBoYXkgdW4gdHJhYmFqYWRvciBjb24gdW4gc2FsYXJpbyBkaWFyaW8gZGUgNTAwIHBlc29zIGxvIHF1ZSBwb2Ryw61hIHJlc3VsdGFyIGNvbW8gdW4gZXJyb3IsIHNpbiBlbWJhcmdvIGxvcyBvdHJvcyAzIGdydXBvcyB2YXLDrWFuIGJhc3RhbnRlIGVuIGVkYWQgbcOhcyBubyBlbiBzYWxhcmlvIHB1ZXMgZWwgcmFuZ28gZXMgbXV5IGNlcmNhbm8uCgoxLiAqKkNsdXN0ZXIgMSoqIEVsIGRhdG8gZXMgw7puaWNvIGVuIGVsIGNvbnRlbyBjb24gdW4gdHJhYmFqYWRvciBkZSAzMiBhw7FvcyBxdWUgdGllbmUgdW4gc2FsYXJpbyBkaWFyaW8gZGUgNTAwIHBlc29zIHkgZXMgc29sdGVyby4gU3UgcHVudG8gZW4gZWwgbWFwZW8gZXMgw7puaWNvIChjb2xvciByb2pvKS4gIAogIAoyLiAqKkNsc3V0ZXIgMioqIEVzIGVsIGNsdXN0ZXIgY29uIGVsIHJlZ2lzdHJvIGRlIHBlcnNvbmFzIGNvbiBtYXlvciBlZGFkIHkgY3VlbnRhbiBjb24gZWwgc2FsYXJpbyBkaWFyaW8gbcOhcyBhbHRvIDE4My42OC4gIAogIAozLiAqKkNsdXN0ZXIgMyoqIEVzIGVsIGNsdXN0ZXIgY29uIGVsIHJlZ2lzdHJvIGRlIHBlcnNvbmFzIGNvbiBlZGFkIHByb21lZGlvIHkgc2FsYXJpbyBkZSAxODAuNjguICAKICAKNC4gKipDbHVzdGVyIDQqKiBFcyBlbCBjbHVzdGVyIGNvbiBtYXlvciByZWdpc3RybyBkZSBwZXJzb25hcyBjb24gZWRhZCBqw7N2ZW4geSBzYWxhcmlvIGRlIDE4Mi42OC4gIAogIAoKTm9tYnJhciBhIGxvcyBjbHVzdGVycwoKYGBge3J9CmJkcjU8LWJkcjIKYmRyNSRDbHVzdGVyIDwtIGJkcjQkY2x1c3RlcgpiZHI2PC1iZHI1ICU+JSBncm91cF9ieShDbHVzdGVyKSAlPiUgZHBseXI6OnN1bW1hcmlzZShzYWxhcmlvX2RpYXJpbz1tYXgoc2FsYXJpb19kaWFyaW8pKSAlPiUgYXJyYW5nZShkZXNjKHNhbGFyaW9fZGlhcmlvKSkKYmRyNSRDbHVzdGVyX05hbWVzPC1mYWN0b3IoYmRyNSRDbHVzdGVyLGxldmVscyA9IGMoMSwyLDMsNCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJBbHRvIiwgIk1lZGlvIiwiQmFqbyIsICJSZWd1bGFyIikpCmBgYAoKQWdydXBhciBjbHVzdGVycwoKYGBge3J9CgpiZHI3PC0gYmRyNSAlPiUgZ3JvdXBfYnkoQ2x1c3Rlcl9OYW1lcykgJT4lIGRwbHlyOjpzdW1tYXJpc2Uoc2FsYXJpb19kaWFyaW89bWF4KHNhbGFyaW9fZGlhcmlvKSwgCmVkYWQ9bWVhbihlZGFkKSwKQ291bnQ9bigpKQoKYGBgCgpUYWJsYQpgYGB7cn0KY2x1c3RlcnM8LWFzLmRhdGEuZnJhbWUoYmRyNykKY2x1c3RlcnMKYGBgCgpHcsOhZmljYXMKCmBgYHtyfQpnZ3Bsb3QoYmRyNyxhZXMoeD0gcmVvcmRlcihDbHVzdGVyX05hbWVzLENvdW50KSx5PUNvdW50LGZpbGw9Q2x1c3Rlcl9OYW1lcykpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpCgpnZ3Bsb3QoYmRyNywgYWVzKHg9Q2x1c3Rlcl9OYW1lcyx5PWVkYWQsZmlsbD0gQ2x1c3Rlcl9OYW1lcyxsYWJlbD1yb3VuZChlZGFkLGRpZ2l0cz0yKSkpICsgCiAgZ2VvbV9jb2woKSArIAogIGdlb21fdGV4dCgpCgpnZ3Bsb3QoYmRyNyxhZXMoeD1DbHVzdGVyX05hbWVzLHk9c2FsYXJpb19kaWFyaW8sZmlsbD0gQ2x1c3Rlcl9OYW1lcyxsYWJlbD1yb3VuZChzYWxhcmlvX2RpYXJpbyxkaWdpdHM9MikpKSArIAogIGdlb21fY29sKCkgKyAKICBnZW9tX3RleHQoKQpgYGAKICAKMS4gRW4gbGEgc2VndW5kYSBncsOhZmljYSBlbCBjbMO6c3RlciBhenVsIGVzIGVsIHF1ZSB0aWVuZSBtYXlvciBmcmVjdWVuY2lhIGNvbiB1biBwcm9tZWRpbyBkZSBlZGFkIGRlIDQ4IGHDsW9zLiAgCiAgCjIuIEVsIGNsdXN0ZXIgYWx0byBlbiBsYSBzZWd1bmRhIGdyYWZpY2EgZW5nbG9iw7MgZW4gMjIgYcOxb3MgZWwgY291bnQsIHNpbiBlbWJhcmdvIGhheSB0cmFiYWphZG9yZXMgY29uIG1lbm9yIGVkYWQuIERpY2hvIGNsdXN0ZXIgZXMgZWwgcXVlIHRpZW5lIG1lbm9zIHRyYWJhamFkb3JlcyBkZW50cm8gZGUgRm9ybS4gIAogIAozLiBFbiBjdWFudG8gYWwgc2FsYXJpbyBlbiBsYSB0ZXJjZXJhIGdyw6FmaWNhLCBlbCBkYXRvIG3DoXMgYWx0byBlcyBlbCBxdWUgYW50ZXJpb3JtZW50ZSBzZSBoYWLDrWEgbWVuY2lvbmFkbyBjb21vIHVuIGRhdG8gw7puaWNvICgkNTAwKSB5IHZlbW9zIGVsIGNvbXBvcnRhbWllbnRvIHF1ZSBzZSBnZW5lcmFiYSBlbiBlbCBtYXBlbyBkZSBjbHVzdGVycyBkb25kZSBsb3MgZGVtw6FzIHRpZW5lbiB1bmEgZGlmZXJlbmNpYSBtw61uaW1hIHNpZW5kbyBsb3MgcmVzdWx0YWRvcyAxODIuNjgsIDE4MC42OCB5IDE4My42OC4gIAogIAoKIyMjIFNlZ3VuZG8gcHVudG86IEluc2lnaHRzLgoKKiBDb24gbGEgYmFzZSBkZSBkYXRvcyBkZSBiYWphcyBzZSByZWFsaXrDsyBlbCBjbMO6c3RlciBkZSBlZGFkIHkgZHVyYWNpw7NuLCBlbiBsYSBjdWFsIHNlIHRvbWFyb24gZW4gY3VlbnRhIGxhcyB2YXJpYWJsZXMgZGUgbGEgZWRhZCBkZSBsb3MgY29sYWJvcmFkb3JlcyB5IGxhIGR1cmFjacOzbiBxdWUgaGFuIHRlbmlkbyBlbiBsYSBlbXByZXNhLiBTZSBidXNjw7MgZWwgbsO6bWVybyDDs3B0aW1vIGRlIGNsw7pzdGVyIHkgc2UgdG9tYXJvbiBlbiBjdWVudGEgbG9zIHByaW1lcm9zIDQuIEVuIGVzdGUgcG9kZW1vcyBvYnNlcnZhciBxdWUgbGFzIHBlcnNvbmFzIGNvbiBlZGFkIG1lZGlhbmEtYWx0YSBubyB0aWVuZW4gdW5hIGR1cmFjacOzbiBkZSBsYXJnbyB0aWVtcG8gZW4gbGEgZW1wcmVzYSB5YSBxdWUgZm9ybWFuIHBhcnRlIGRlbCAyNSUgY29uIG1lbm9yIGR1cmFjacOzbjsgb3RybyBkYXRvIHF1ZSBvYnNlcnZhbW9zIHF1ZSBsYXMgcGVyc29uYXMgY29uIG1heW9yIGVkYWQgaGFuIGR1cmFkbyBtw6FzIHRpZW1wbyBlbiBGb3JtIHkgZm9ybWFuIHBhcnRlIGRlbCBzdXBlcmlvciA1MCUsIHkgcG9yIMO6bHRpbW8gb2JzZXJ2YW1vcyBxdWUgZXhpc3RlIHVuYSBtYXlvciByb3RhY2nDs24gZGUgcGVyc29uYWwgZW4gbG9zIGNvbGFib3JhZG9yZXMgasOzdmVuZXMuICAKKiBFbiBlbCBhbsOhbGlzaXMgcXVlIHNlIHJlYWxpesOzIG1lZGlhbnRlIGdyw6FmaWNhcywgb2J0dXZpbW9zIHF1ZSBlbiBsb3MgY2zDunN0ZXIsIHF1ZSBsYSBwZXJzb25hIGNvbiBtYXlvciBlZGFkIGVuIGxvcyBleHBlcnQgdGllbmUgNjEsIGVuIHNlbmlvciB0aWVuZSA1NywgZW4ganVuaW9yIHRpZW5lIDM5IHkgZW4gYmVnaW5ubmVyIDI3LCB0YW1iacOpbiBxdWUgZW4gbGEgZW1wcmVzYSBsYSBtYXlvcsOtYSBkZSBsb3MgY29sYWJvcmFkb3JlcyBjb3JyZXNwb25kZW4gYWwgY2zDunN0ZXIgZGUgYmVnaW5uZXIuICAgCiogRW4gY3VhbnRvIGFsIGFuw6FsaXNpcyBkZSBsYSBkdXJhY2nDs24gZGUgbG9zIGNvbGFib3JhZG9yZXMgZW4gbGEgZW1wcmVzYSB5IHN1IHNhbGFyaW8gZW5jb250cmFtb3MgZXN0b3MgcHVudG9zIG1hcyBpbXBvcnRhbnRlczsgYSkgbGEgbWF5b3LDrWEgZGUgbG9zIGVtcGxlYWRvcyBnYW5hbiBhcnJpYmEgZGVsIHNhbGFyaW8gZGlhcmlvIHByb21lZGlvIGVzdGFibGVjaWRvIHBvciBlbCBnb2JpZXJubywgZXN0ZSBvc2NpbGEgZW50cmUgJDE1MC0kMjAwMCBwZXNvcyBkaWFyaW9zLCBiKSBsb3MgY29sYWJvcmFkb3JlcyBxdWUgdGllbmVuIHVuIHRpZW1wbyBtZWRpbyBlbiBsYSBlbXByZXNhIGFwcm94aW1hZGFtZW50ZSBkZSB1biBhw7FvIHRpZW5lIHVuIHNhbGFyaW8gcHJvbWVkaW8gZGUgJDE2OSwgbWllbnRyYXMgbG9zIHF1ZSBkdXJhbiBtZW5vcyB0aWVtcG8gKGFscmVkZWRvciBkZSAxNDEgZMOtYXMpIHRpZW5lbiB1biBzYWxhcmlvIHByb21lZGlvIGRlIGFscmVkZWRvciBkZSAkMTgwLiAgCiogRWwgY2zDunN0ZXIgbWFzIGdyYW5kZSBlcyBlbCBsbGFtYWRvIOKAnFJlaGVuZXPigJ0gdGllbmUgdW4gdG90YWwgZGUgY29sYWJvcmFkb3JlcyBkZSAxOTEsIHkgZW4gcG9yY2VudGFqZSBkZSBiYWphcyBzZSBwdWVkZSBkZWNpciBxdWUgZXMgZWwgODEuOTclIHRvdGFsIGRlIGJhamFzLCBlc3RvcyB0aWVuZSBsYSBjYXJhY3RlcsOtc3RpY2EgZGUgc29uIGxhcyBwZXJzb25hcyBxdWUgZW50cmFuIHkgc2FsZW4gbXV5IHByb250byB5IHRpZW5lbiB1biBzYWxhcmlvIHBvciBhcnJpYmEgZGUgdG9kb3MgbG9zIGRlbcOhcyBjbMO6c3RlciBkZSAkMTgwIHBlc29zLCBwb3IgbG8gcXVlLCBlbiBlc3RlIGNsw7pzdGVyIHNlIG5lY2VzaXRhIGFwbGljYXIgdW5hIGVzdHJhdGVnaWEgZGUgZmlkZWxpemFjacOzbiBkZSBsb3MgY29sYWJvcmFkb3JlcyBkZSBvdHJhIGZvcm1hIHF1ZSBubyBzZWEgY29uIHVuIGF1bWVudG8gZGUgc2FsYXJpbywgZXMgZGVjaXIsIEZvcm0gcHVlZGUgaW1wbGVtZW50YXIgZXN0cmF0ZWdpYXMgY29uIHJlY29tcGVuc2FzIHF1ZSBzZWFuIGEgbGFyZ28gcGxhem8uICAKKiBDb21vIHNlIHB1ZWRlIG9ic2VydmFyIGVuIGVsIGFuYWxpc2lzIHF1ZSBzZSByZWFsaXrDsyBkZSBlZGFkIHkgc2FsYXJpbyBzZSBwdWVkZW4gZGVzdGFjYXIgbG9zIHNpZ3VpZW50ZXMgcHVudG9zOiAgCmEpIEVsIGNsdXN0ZXIgcXVlIHRpZW5lIHVuYSBtYXlvciBmcmVjdWVuY2lhIGVzIGVsIGRlIDQ4IGHDsW9zIGRlIGVkYWQsICAgIAoKYikgRWwgY2x1c3RlciBxdWUgbWFzIGNoaWNvIGVzIGRlIDIyIGHDsW9zIG8gbWVub3MgcG9yIGxvIHF1ZSBwb2RlbW9zIGRlY2lyIHF1ZSBlbiBGb3JtLCBsYSBtYXlvcsOtYSBzb24gbWF5b3JlcyBkZSAyMyBhw7FvcywgIAogCmMpIEVuIGN1YW50byBhbCBzYWxhcmlvIHRpZW5lbiB1biBwcm9tZWRpbyBkZSAxODAuNjgsIHBlcm8gZXhpc3RlIHVuIGRhdG8gw7puaWNvIGVsIGN1YWwgZ2FuYWJhIDUwMC4gIAogCiAKIyMjIFRlcmNlciBwdW50bzogUmVsYWNpb25lcyBlbnRyZSB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcyB5IGN1YWxpdGF0aXZhcy4gCgojIyMjIENvbnZlcnRpciBsYXMgdmFyaWFibGVzIHBhcmEgY3JlYXIgYW5hbGlzaXMgZGVzY3JpcHRpdm9zCmBgYHtyfQpyaF9iYWphczMkZ2VuZXJvPC1hcy5mYWN0b3IocmhfYmFqYXMzJGdlbmVybykKcmhfYmFqYXMzJHB1ZXN0bzwtYXMuZmFjdG9yKHJoX2JhamFzMyRwdWVzdG8pCnJoX2JhamFzMyRlLmNpdmlsLjwtYXMuZmFjdG9yKHJoX2JhamFzMyRlLmNpdmlsLikKYGBgCiMjIyBDbHVzdGVycyBFZGFkIHkgZHVyYWNpw7NuICg0IGNsdXN0ZXJzKQojIyMjIFJlbGFjacOzbiBlbnRyZSBTYWxhcmlvLCBHw6luZXJvIHkgRXN0YWRvIENpdmlsCmBgYHtyfQpiYWphc19uZXc4PC1iYWphc19uZXcyJT4lIGZpbHRlcihDbHVzdGVycz09MSB8IENsdXN0ZXJzPT00KSAlPiUgYXJyYW5nZShDbHVzdGVycykKZ2dwbG90KGFzLmRhdGEuZnJhbWUoYmFqYXNfbmV3OCksCiAgICAgICBhZXMoeT1zYWxhcmlvX2RpYXJpbywgYXhpczE9Z2VuZXJvLCBheGlzMj1lLmNpdmlsLikpICsKICBnZW9tX2FsbHV2aXVtKGFlcyhmaWxsPUNsdXN0ZXJfTmFtZXMpLCB3aWR0aCA9IDEvMTIpICsKICBnZW9tX3N0cmF0dW0od2lkdGggPSAxLzEyLCBmaWxsID0gImJsYWNrIiwgY29sb3IgPSAiZ3JleSIpICsKICBnZW9tX2xhYmVsKHN0YXQgPSAic3RyYXR1bSIsIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoc3RyYXR1bSkpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJHZW5lcm8iLCAiRXN0YWRvIENpdmlsIiksIGV4cGFuZCA9IGMoLjA1LCAuMDUpKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIodHlwZSA9ICJxdWFsIiwgcGFsZXR0ZSA9ICJTZXQxIikgKwogIGdndGl0bGUoIlNhbGFyaW8gRGlhcmlvIGRlIFBhc2Fkb3MgRW1wbGVhZG9zIGRlIEZvcm0gcG9yIEfDqW5lcm8geSBFc3RhZG8gQ2l2aWwiKQpgYGAKCiMjIyBDbHVzdGVycyBFZGFkIHkgZHVyYWNpw7NuICg1IGNsdXN0ZXJzKQoKIyMjIyBSZWxhY2nDs24gZW50cmUgU2FsYXJpbywgR8OpbmVybyB5IEVzdGFkbyBDaXZpbApgYGB7cn0KYmFqYXNfbmV3OTwtYmFqYXNfbmV3NiU+JSBmaWx0ZXIoQ2x1c3RlcnM9PTEgfCBDbHVzdGVycz09NSkgJT4lIGFycmFuZ2UoQ2x1c3RlcnMpCmdncGxvdChhcy5kYXRhLmZyYW1lKGJhamFzX25ldzkpLAogICAgICAgYWVzKHk9c2FsYXJpb19kaWFyaW8sIGF4aXMxPWdlbmVybywgYXhpczI9ZS5jaXZpbC4pKSArCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbD1DbHVzdGVyX05hbWVzKSwgd2lkdGggPSAxLzEyKSArCiAgZ2VvbV9zdHJhdHVtKHdpZHRoID0gMS8xMiwgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9sYWJlbChzdGF0ID0gInN0cmF0dW0iLCBhZXMobGFiZWwgPSBhZnRlcl9zdGF0KHN0cmF0dW0pKSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiR2VuZXJvIiwgIkVzdGFkbyBDaXZpbCIpLCBleHBhbmQgPSBjKC4wNSwgLjA1KSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAiU2V0MSIpICsKICBnZ3RpdGxlKCJTYWxhcmlvIERpYXJpbyBkZSBQYXNhZG9zIEVtcGxlYWRvcyBkZSBGb3JtIHBvciBHw6luZXJvIHkgRXN0YWRvIENpdmlsIikKYGBgCgojIyMgQ2x1c3RlcnMgU2FsYXJpbyB5IGVkYWQKIyMjIyBSZWxhY2nDs24gZW50cmUgU2FsYXJpbywgR8OpbmVybyB5IEVzdGFkbyBDaXZpbApgYGB7cn0KYmRyODwtYmRyNSU+JSBmaWx0ZXIoQ2x1c3Rlcj09MSB8IENsdXN0ZXI9PTMpICU+JSBhcnJhbmdlKENsdXN0ZXIpCmdncGxvdChhcy5kYXRhLmZyYW1lKGJkcjgpLAogICAgICAgYWVzKHk9c2FsYXJpb19kaWFyaW8sIGF4aXMxPWdlbmVybywgYXhpczI9ZS5jaXZpbC4pKSArCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbD1DbHVzdGVyX05hbWVzKSwgd2lkdGggPSAxLzEyKSArCiAgZ2VvbV9zdHJhdHVtKHdpZHRoID0gMS8xMiwgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9sYWJlbChzdGF0ID0gInN0cmF0dW0iLCBhZXMobGFiZWwgPSBhZnRlcl9zdGF0KHN0cmF0dW0pKSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiR2VuZXJvIiwgIkVzdGFkbyBDaXZpbCIpLCBleHBhbmQgPSBjKC4wNSwgLjA1KSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAiU2V0MSIpICsKICBnZ3RpdGxlKCJTYWxhcmlvIERpYXJpbyBkZSBQYXNhZG9zIEVtcGxlYWRvcyBkZSBGb3JtIHBvciBHw6luZXJvIHkgRXN0YWRvIENpdmlsIikKYGBgCiMjIyMgUmVsYWNpw7NuIGVudHJlIFNhbGFyaW8sIEfDqW5lcm8geSBNb3Rpdm8gZGUgYmFqYQpgYGB7cn0KYmRyODwtYmRyNSU+JSBmaWx0ZXIoQ2x1c3Rlcj09MSB8IENsdXN0ZXI9PTMpICU+JSBhcnJhbmdlKENsdXN0ZXIpCmdncGxvdChhcy5kYXRhLmZyYW1lKGJkcjgpLAogICAgICAgYWVzKHk9c2FsYXJpb19kaWFyaW8sIGF4aXMxPWdlbmVybywgYXhpczI9bW90aXZvX2JhamEpKSArCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbD1DbHVzdGVyX05hbWVzKSwgd2lkdGggPSAxLzEyKSArCiAgZ2VvbV9zdHJhdHVtKHdpZHRoID0gMS8xMiwgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9sYWJlbChzdGF0ID0gInN0cmF0dW0iLCBhZXMobGFiZWwgPSBhZnRlcl9zdGF0KHN0cmF0dW0pKSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiR2VuZXJvIiwgIkVzdGFkbyBDaXZpbCIpLCBleHBhbmQgPSBjKC4wNSwgLjA1KSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAiU2V0MSIpICsKICBnZ3RpdGxlKCJTYWxhcmlvIERpYXJpbyBkZSBQYXNhZG9zIEVtcGxlYWRvcyBkZSBGb3JtIHBvciBHw6luZXJvIHkgTW90aXZvIGRlIGJhamEiKQpgYGAKCiMjIyBDbHVzdGVycyBEdXJhY2nDs24geSBzYWxhcmlvCiMjIyMgQXNvY2lhY2lvbmVzIGVudHJlIHZhcmlhYmxlcyBjYXRlZ8OzcmljYXMgYSB0cmF2w6lzIGRlIG5vbWJyZXMgZGUgZ3J1cG9zCiMjIyMjIENsdXN0ZXJzIEJhamFzIGNvbiBnw6luZXJvIHkgZXN0YWRvIGNpdmlsCmBgYHtyfQpyaF9iYWphczY8LXJoX2JhamFzMyAlPiUgZmlsdGVyKENsdXN0ZXJzPT00IHwgQ2x1c3RlcnM9PTMpICU+JSBhcnJhbmdlKENsdXN0ZXJzKQpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShyaF9iYWphczYpLAogICAgICAgYWVzKHk9c2FsYXJpb19kaWFyaW8sIGF4aXMxPWdlbmVybywgYXhpczI9ZS5jaXZpbC4pKSArCiAgZ2VvbV9hbGx1dml1bShhZXMoZmlsbD1DbHVzdGVyX05hbWVzKSwgd2lkdGggPSAxLzEyKSArCiAgZ2VvbV9zdHJhdHVtKHdpZHRoID0gMS8xMiwgZmlsbCA9ICJibGFjayIsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9sYWJlbChzdGF0ID0gInN0cmF0dW0iLCBhZXMobGFiZWwgPSBhZnRlcl9zdGF0KHN0cmF0dW0pKSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiR2VuZXJvIiwgIkVzdGFkbyBDaXZpbCIpLCBleHBhbmQgPSBjKC4wNSwgLjA1KSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAiU2V0MSIpICsKICBnZ3RpdGxlKCJTYWxhcmlvIERpYXJpbyBkZSBQYXNhZG9zIEVtcGxlYWRvcyBkZSBGb3JtIHBvciBHw6luZXJvIHkgRXN0YWRvIENpdmlsIikKYGBgCiMjIyMjIENsdXN0ZXJzIEJhamFzIGNvbiBnw6luZXJvIHkgZXN0YWRvIGNpdmlsCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QocmhfYmFqYXMzLCBhZXMoQ2x1c3Rlcl9OYW1lcywgZmlsbD1mYWN0b3IoZ2VuZXJvLGxldmVscz1yZXYobGV2ZWxzKGdlbmVybykpKSkpICsgCiAgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIikrCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgnR8OpbmVybycpKwogIGdndGl0bGUoIkfDqW5lcm8gZGUgQ29sYWJvcmFkb3JlcyBwb3IgQ2x1c3RlciIpCmBgYAoKCgpgYGB7cn0KZ2dwbG90KHJoX2JhamFzMywgYWVzKENsdXN0ZXJfTmFtZXMsIGZpbGw9ZmFjdG9yKGUuY2l2aWwuLGxldmVscz1yZXYobGV2ZWxzKGUuY2l2aWwuKSkpKSkrCiAgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIikrCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgnRXN0YWRvIENpdmlsJykrCiAgZ2d0aXRsZSgiRXN0YWRvIENpdmlsIGRlIEJhamFzIHBvciBDbHVzdGVyIikKYGBgCgoKYGBge3J9CmdncGxvdChyaF9iYWphczMsIG1hcHBpbmc9YWVzKHg9Q2x1c3Rlcl9OYW1lcywgZmlsbD1wdWVzdG8pKSArIAogIGdlb21fYmFyKGFscGhhID0gMS81LCBwb3NpdGlvbj0iaWRlbnRpdHkiKSsKICBnZ3RpdGxlKCJQdWVzdG9zIGRlIENvbGFib3JhZG9yZXMgcG9yIENsdXN0ZXIiKQpgYGAKCiMjIyMjIyBFbiBjb25jbHVzacOzbiBwYXJhIEZvcm0gcG9kZW1vcyBwbGFudGVhciB1bmEgZXN0cmF0ZWdpYSBkZSBlc3RhbmRhcml6YWNpw7NuIGRlIHNhbGFyaW9zIGRlIGFjdWVyZG8gYWwgdGllbXBvIHF1ZSBsbGV2YW4gZW4gbGEgZW1wcmVzYSB5IHN1IGVkYWQsIHBhcmEgcG9kZXIgYXPDrSB0ZW5lciB1biBtZWpvciBjb250cm9sIGRlIGdhc3RvcyBkZSBsYSBlbXByZXNhIHkgYXBsaWNhciBudWV2YXMgYSBlc3RyYXRlZ2lhcyBhIGNhZGEgdW5vIGRlIGxvcyBjbHVzdGVyLgoKIyAqKklkZW50aWZpY2FjacOzbiBkZSBSZXN1bHRhZG9zIFJlbGV2YW50ZXMgeSBTdWdlcmVuY2lhcyoqCgojIyBNZWFuaW5nZnVsIGluc2lnaHRzCjEuIEhhYmxhbmRvIGRlbCDDoXJlYSBkZSBSZWN1cnNvcyBodW1hbm9zIHBvZGVtb3MgZW5jb250cmFyIHF1ZSBlcyBuZWNlc2FyaW8gcmVjb21wZW5zYXIgbGEgYW50aWfDvGVkYWQgeSBjcmVhciBwbGFuZXMgZGUgY3JlY2ltaWVudG8gcGFyYSBsYSBnZW50ZSAoc29icmUgdG9kbyBhIGxvcyBqw7N2ZW5lcykgcGFyYSByZWR1Y2lyIGxhcyBiYWphcyB5YSBxdWUgYWwgcmVhbGl6YXIgbG9zIGNsdXN0ZXJzIG5vcyBtdWVzdHJhbiBxdWUgbG9zIGrDs3ZlbmVzIHNvbiBsb3MgcXVlIGR1cmFuIG1lbm9zIHRpZW1wbyBlbiBsYSBlbXByZXNhLgoKMi4gRWwgdGVtYSBwb3IgZWwgcXVlIGhheSBtw6FzIGJhamFzIGVzIHBvciBsYSByYXrDs24gZGUgRmFsdGFzIHRlbmllbmRvIHVuIDYwJSB5IGVuIHNlZ3VuZG8gbHVnYXIgZXN0YSBsYSBSZW51bmNpYSB2b2x1bnRhcmlhIGNvbiAzNiUuIFNlIHRpZW5lIHF1ZSBicmluZGFyIGF0ZW5jacOzbiBwb3JxdWUgY2FwYWNpdGFyIGEgbG9zIGVtcGxlYWRvcyBlcyBhbGdvIGNvc3Rvc28geSBzZSB0aWVuZSB1bmEgYWx0YSByb3RhY2nDs24uCgozLiBEZW50cm8gZGUgUHJvZHVjY2nDs24gbnVlc3RybyB0b3AgMyBjbGllbnRlcyBkZSBwcm9kdWNjacOzbiBzb24gU1RBQklMVVMgMSwgU1RBQklMVVMgMyB5IFRSTVguCgo0LiBFbiBkaXN0cnVidWNpw7NuIGRlYmVtb3MgcHJlc3RhciBhdGVuY2nDs24gYWwgY2xpZW50ZSBNYWhsZSwgc3UgcmVzdHJhc28gZXMgYXJyaWJhIGRlbCBwcm9tZWRpbyBsbGVnYW5kbyBpbmNsdXNvIGEgdGllbXBvcyBkZSAxIGhvcmEgY29uIDQwIG1pbnV0b3MgeSBlc3RvIHB1ZWRlIGFmZWN0YXIgbGEgcmVsYWNpw7NuIGNvbiBlbCBjbGllbnRlIHkgZW4gbGEgbG9nw61zdGljYS4KCjUuIEVuIGRlbGl2ZXJ5IFBsYW4gZGVzdGFjYSBlbCBjbGllbnRlIEhFTExBIGhhY2llbmRvIHBlZGlkb3MgcXVlIGxsZWdhbiBoYXN0YSBtw6FzIGRlIDIwMCwwMDAuCgo2LiBFbiBwcm9tZWRpbyBzZSByZWFsaXphbiBlbnRyZSAwIGEgMTAwMCBwZWRpZG9zLCBwZXJvIGRlYmVtb3MgZGUgdGVuZXIgY3VpZGFkbyB5YSBxdWUgdGFtYmnDqW4gZW5jb250cmFtb3MgcXVlIHNlIHRpZW5lbiBzb2JyZXBlZGlkb3MgKGFycmliYSBkZWwgcHJvbWVkaW8pIGxsZWdhbmRvIGhhc3RhIDUsMDAwIHBlZGlkb3MgeSBlc3RvIHB1ZWRlIGFmZWN0YXIgc2kgbm8gc2UgdGllbmVuIGxhIGNhcGFjaWRhZCBwYXJhIHJlY2liaXIgcGVkaWRvcyBkZSBtw6FzLgoKCiMjIFN1Z2VyZW5jaWFzIHBhcmEgcHJvY2VzbyBkZSBjYXB0dXJhLCBvcmdhbml6YWNpw7NuLCB5IGFuYWzDrXRpY2EgZGUgZGF0b3MKMS4gUGFyYSBjYXB0dXJhIGRlIGRhdG9zIHV0aWxpemFyIHNvZnR3YXJlcyBxdWUgcGVybWl0YW4gZWwgcmVnaXN0cm8gZGUgZGF0b3MgZGUgbWFuZXJhIGF1dG9tYXRpemFkYSwgeWEgcXVlIHBhcmEgbGEgcGFydGUgY29tZXJjaWFsIHNlIHZlIHF1ZSBsYXMgYmFzZXMgZnVlcm9uIGhlY2hhcyBtYW51YWxlcyB5IHRpZW5lbiBkYXRvcyBmYWx0YW50ZXMgbyByZXBldGlkb3MgY29tbyBlbCBzb2Z0d2FyZSBNdWxlU29mdC4gIAoKMi4gQWwgcmVhbGl6YXIgYmFzZXMgZGUgZGF0b3MgZGFybGUgdW4gbWVqb3IgZm9ybWF0byBkb25kZSBsYSBwcmltZXJhIGZpbGEgc2VhbiBsYXMgdmFyaWFibGVzIHkgYWJham8gbG9zIHJlZ2lzdHJvcyBwYXJhIHVuIGVmaWNheiB5IG1lam9yIHByb2Nlc28gZGUgbGltcGllemEuCgozLiBBZ3JlZ2FyIGVsIHRpcG8gZGUgcHJvZHVjdG8gYSBsYSBiYXNlIGRlIGRhdG9zIGRlIFNjcmFwIHBhcmEgZW5jb250cmFyIGN1YWwgZXMgZWwgcXVlIHNlIHRpZW5lIG1heW9yIGNhbnRpZGFkIHkgYnVzY2FyIHVuYSBtYW5lcmEgZGUgZGlzbWludWlybG8uICAKCjQuIENvbnRhciBjb24gdW5hIMOhcmVhIGRlIEludGVsaWdlbmNpYSBkZSBOZWdvY2lvcyB5IEFuYWzDrXRpY2EgZGUgTmVnb2Npb3MgY29uIGRhdGFzIGVuZ2luZWVyIHF1ZSBsb2dyZW4gcmVjb2xlY3RhciBpbmZvcm1hY2nDs24geSBwcm9jZXNhcmxhIHBhcmEgbGEgdG9tYSBkZSBkZWNpc2lvbmVzLiAgICAKCiMgKipDb25jZXB0b3MgeSBwcmVndW50YXMgZmluYWxlcyoqCgojIyBEZWZpbmljaW9uZXMKCiMjIyBCdXNpbmVzcyBBbmFseXRpY3MKRWwgY29uY2VwdG8gZGUgQnVzaW5lc3MgQW5hbHl0aWNzIHNlIHB1ZWRlIGRlZmluaXIgY29tbyBlbCBwcm9jZXNvIGRlIHV0aWxpemFyIGluZm9ybWFjacOzbiBjb24gZGlzdGludG9zIG3DqXRvZG9zIHBhcmEgdG9tYXIgbWVqb3JlcyBkZWNpc2lvbmVzLCBxdWUgc2VhbiBpbmZvcm1hZGFzIHkgY29ycmVjdGFzIGRlbnRybyBkZWwgbXVuZG8gZGUgbmVnb2Npb3MgZ3JhY2lhcyBhbCBhbsOhbGlzaXMgcXVlIHNlIHJlYWxpemEgKEdhdmluLCBNLiwgMjAxOSkuIEV4aXN0ZW4gNCB0aXBvcyBkZSBtw6l0b2RvczogIAoKKiBEZXNjcmlwdGl2bzogQ3JlYXIgdGVuZGVuY2lhcyB5IHBhdHJvbmVzIGNvbiBkYXRvcyBoaXN0w7NyaWNvcy4gIAoKKiBEaWFnbsOzc3RpY286IEV4cGxpY2EgZWwgcG9yIHF1ZSBkZSBsb3Mgc3VjZXNvcyB1dGlsaXphbmRvIGlndWFsbWVudGUgZGF0b3MgaGlzdMOzcmljb3MuICAKCiogUHJlZGljdGl2bzogUG9kZXIgZ3LDoWZpY2FyIHkgZW5jb250cmFyIHRlbmRlbmNpYXMgYSB0cmF2w6lzIGRlIHByb27Ds3N0aWNvcyBtZWRpYW50ZSBlc3RhZMOtc3RpY2FzLiAgCgoqIFByZXNjcmlwdGl2bzogUHJlY2lzYXIgcmVzdWx0YWRvcyBwYXJhIGVzY2VuYXJpb3MgY29uIG1lam9yZXMgcmVzdWx0YWRvcyB0cmFiYWphbmRvIGNvbiBhcGxpY2FjacOzbiBkZSBwcnVlYmFzIHkgb3RyYXMgdMOpY25pY2FzLiAgICAKCkVsIEJBIGF5dWRhIGEgcmVjb25vY2VyIHBhdHJvbmVzIGRlIGNvbnN1bW8gcXVlIHBlcm1pdGVuIHNlZ21lbnRhciBzb2JyZSBsb3MgaMOhYml0b3MgeSBwcmVmZXJlbmNpYXMgZGUgY29tcHJhLCB0YW1iacOpbiBlbmNvbnRyYXIgw6FyZWEgZGUgb3BvcnR1bmlkYWQgcXVlIG5vcyBkaWdhbiBzaSBwb2RlbW9zIG1lam9yYXIgbGEgcHJvZHVjdGl2aWRhZCB5IHJlbmRpbWllbnRvLgoKIyMjIEJ1c2luZXNzIEludGVsbGlnZW5jZQpQb2RlbW9zIGRlY2lyIHF1ZSBoYWJsYW1vcyBkZSBCdXNpbmVzcyBJbnRlbGxpZ2VuY2UgY3VhbmRvIHNlIHRpZW5lIGxhIHZpc2nDs24gZXN0cmF0w6lnaWNhIHBhcmEgdHJhbnNmb3JtYXIgbG9zIGFjdGl2b3MgZW4gZGF0b3MgcXVlIGF5dWRlbiBhIGdlbmVyYXIgZGVjaXNpb25lcyBiYXNhZGFzIGVuIGRhdG9zIChTaGVuLCBFLiwgMjAyMCkuIFkgcGFyYSBlc3RvIGVzIGltcG9ydGFudGUgcXVlIGxhIGhlcnJhbWllbnRhIHF1ZSBwZXJtaXRlIGN1bXBsaXIgY29uIGVzdGEgdmlzacOzbiB0b21lIGVuIGN1ZW50YSBsYXMgZnVuY2lvbmFsaWRhZGVzIHF1ZSBzZSB0aWVuZW46ICAgIAoKKiBBY2NlZGVyIGEgdG9kb3MgbG9zIGRhdG9zIGRlIHRvZGFzIGxhcyDDoXJlYXMgeSBuaXZlbGVzIGRlIGdyYWR1bGFkby4gIAoKKiBPYnRlbmVyIGRhdG9zIGRlIG1hbmVyYSByw6FwaWRhLiAgCgoqIFBvZGVyIGNvbXBhcnRpciBsYSBpbmZvcm1hY2nDs24gY29uIGxvcyByZXNwb25zYWJsZXMgZGUgZGVjaXNpb25lcyBlbiBsZW5ndWFqZXMgY29tw7puZXMuICAKClBhcmEgYXByb3ZlY2hhciBhbCBtw6F4aW1vIGVsIHV0aWxpemFyIEJ1c2luZXNzIEludGVsbGlnZW5jZSwgZXMgaW1wb3J0YW50ZSBjb25zaWRlcmFyIGxvcyBzaWd1aWVudGVzIHBhc29zOgoKMS4gQ29ub2NlciBhIGxvcyBjbGllbnRlcyB5IGNvbXByZW5kZXJsb3MgcGFyYSBwb2RlciBkZXNhcnJvbGxhciBlc3RyYXRlZ2lhcyBpbnRlbGlnZW50ZXMgcXVlIGF0aWVuZGFuIG5lY2VzaWRhZGVzLiAgCgoyLiBDb250YXIgY29uIHVuIHNvbG8gY2FuYWwgZGUgZGF0b3MgcXVlIHBlcm1pdGEgbGEgZWZpY2llbmNpYSB5IGxpbXBpZXphLiAgCgozLiBNb2Rlcm5pemFyc2UgY29uIGxhcyBudWV2YXMgaGVycmFtaWVudGFzIHF1ZSB0aWVuZW4gbcOhcyBjYXBhY2lkYWRlcyBkZSBnZW5lcmFyIG3DoXMgaW50ZWxpZ2VuY2lhLCBjb21vIGFwcmVuZGl6YWplIGF1dG9tw6F0aWNvLiAgCgo0LiBTaWVtcHJlIGVzdGFyIGVuIGNvbnN0YW50ZSBzdXBlcnZpc2nDs24geSBtZWpvcmFzLgoKIyMjIERpZmVyZW5jaWFzIGVudHJlIEJ1c2luZXNzIEFuYWx5dGljcyB5IEJ1c2luZXNzIEludGVsbGlnZW5jZQoxLiBCdXNpbmVzcyBJbnRlbGxpZ2VuY2UgbG8gcXVlIGJ1c2NhIGVzIGNvbXByZW5kZXIgY29tbyBzZSBlbmN1ZW50cmEgbGEgZW1wcmVzYSB5IGNvbW8gcG9kZXIgbWVqb3JhciwgdXRpbGl6YW5kbyBkYXRvcyBoaXN0w7NyaWNvcyBtZWRpYW50ZSB1biBhbsOhbGlzaXMgZGVzY3JpcHRpdm8gbWllbnRyYXMgcXVlIEJ1c2luZXNzIEFuYWx5dGljcyBlcyBleHBsaWNhciBlbCBwb3JxdWUgZGUgY2llcnRvcyBldmVudG9zLCB0ZW5kZW5jaWFzIG8gcGF0cm9uZXMuICAKCjIuIExhIGluZm9ybWFjacOzbiBzZSBnZW5lcmEgcG9yIEJ1c2luZXNzIEFuYWx5dGljaXMgeSBkZXNwdcOpcyB1biBleHBlcnRvIGRlIEJ1c2luZXNzIEludGVsbGlnZW5jZSB0cmFuc2Zvcm1hIGVzYSBpbmZvcm1hY2nDs24gZW4gcmVzdWx0YWRvcyB5IGdyw6FmaWNvcy4gIAoKMy4gQnVzaW5lc3MgSW50ZWxsaWdlbmNlIG5lY2VzaXRhbiBjb21wcmVuZGVyIGxvIHF1ZSBlc3RhbiBleHRyYXllbmRvIHkgdHJhbnNmb3JtYW5kbywgbWllbnRyYXMgcXVlIEJ1c2luZXNzIEFuYWx5dGljaXMgdGllbmVuIHF1ZSB0ZW5lciBjYXBhY2lkYWQgcGFyYSBkaXNlw7FhciBlIGltcGxlbWVudGFyIG3DqXRvZG9zIHF1ZSBwZXJtaXRhbiBsYSByZWNvbGVjY2nDs24gZGUgZGF0b3MuCgoKIyMjIEtleSBQZXJmb3JtYW5jZSBJbmRpY2F0b3JzIChLUEkpClNvbiBpbmRpY2Fkb3JlcyBjbGF2ZXMgcGFyYSBsb2dyYXIgbWVkaXIgZWwgZGVzZW1wZcOxbyBkZW50cm8gZGUgdW5hIGVtcHJlc2EgeSBsbGVnYXIgYWwgcmVzdWx0YWRvIGRlc2VhZG8uIEF5dWRhbiBhIGNyZWFyIHVuIGVuZm9xdWUgZGUgcXVlIHNlIHF1aWVyZSBoYWNlciB5IHF1ZSBlc3RyYXRlZ2lhcyB1dGlsaXphciBwYXJhIGN1bXBsaXIgY29uIGVzdG9zIGluZGljYWRvcmVzIHkgYWwgdmVyIGNvbW8gc2UgdmEgcHJvZ3Jlc2FuZG8gbW9kaWZpY2FyIGxhIGVzdHJhdGVnaWEsIHRhbWJpw6luIG5vcyBwZXJtaXRlbiB0b21hciBtZWpvcmVzIGRlY2lzaW9uZXMuIFNlIG5lY2VzaXRhbiBlc3RhYmxlY2VyICoqb2JqZXRpdm9zKiogcGFyYSBkZXNwdcOpcyBwb25lcmxlcyBlc3RvcyBpbmRpY2Fkb3JlcyBjbGF2ZS4KCiMjIEtQSSdzIHBhcmEgbGEgZW1wcmVzYSBGT1JNCjEuIFJlbmRpbWllbnRvOiBBbmFsaXphciBsYSBjYXBhY2lkYWQgZGUgcHJvZHVjY2nDs24gcXVlIHNlIHRpZW5lIGRlbnRybyBkZSBsYSBlbXByZXNhLgoKRsOzcm11bGE9IENhbnRpZGFkIGRlIHVuaWRhZGVzIHByb2R1Y2lkYXMgLyBUaWVtcG8gKGhvcmFzIG8gZMOtYXMpCgoyLiBSb3RhY2nDs24gZGUgZW1wbGVhZG9zOiBNZWRpciBjdWFsIGVzIGxhIHJvdGFjacOzbiBxdWUgc2UgdGllbmUuCgpGw7NybXVsYT0gTsO6bWVybyBhY3R1YWwgKGRlbCBtZXMpIGRlIGVtcGxlYWRvcyBxdWUgcmVudW5jaWFyb24gbyBzZSBmdWVyb24gLyAoKGVtcGxlYWRvcyBhbCBpbmljaW8gZGUgbWVzKyBlbXBsZWFkb3MgYWwgZmluYWwgZGUgbWVzKS8yKSB4IDEwMAoKMy4gRW50cmVnYXMgYSB0aWVtcG86IEVzdGFyIGFuYWxpemFuZG8gc2kgbnVlc3Ryb3MgcGVkaWRvcyBsbGVnYW4gYSB0aWVtcG8gY29uIGxvcyBjbGllbnRlcy4KCkbDs3JtdWxhPSAoTsO6bS4gZGUgZW50cmVnYXMgYSB0aWVtcG8gLyBOw7ptLiB0b3RhbCBkZSBlbnRyZWdhcyByZWFsaXphZGFzKSB4IDEwMAojIFJlZmVyZW5jaWFzCjEuIEdhdmluLCBNLiAoMjAxOSwgMTYganVsaW8pLiAqQnVzaW5lc3MgQW5hbHl0aWNzOiBXaGF0IEl0IElzICYgV2h5IEl04oCZcyBJbXBvcnRhbnQgfCBIQlMgT25saW5lKi4gQnVzaW5lc3MgSW5zaWdodHMgQmxvZy4gUmVjdXBlcmFkbyAyMSBkZSBvY3R1YnJlIGRlIDIwMjIsIGRlIGh0dHBzOi8vb25saW5lLmhicy5lZHUvYmxvZy9wb3N0L2ltcG9ydGFuY2Utb2YtYnVzaW5lc3MtYW5hbHl0aWNzICAKCjIuIFNoZW4sIFMuICgyMDIxLCAxNSBkaWNpZW1icmUpLiAqNiBLZXkgQXJlYXMgb2YgQnVzaW5lc3MgSW50ZWxsaWdlbmNlIGluIHRoZSBOZXcgRXJhLiBNZWRpdW0qLiBSZWN1cGVyYWRvIDIxIGRlIG9jdHVicmUgZGUgMjAyMiwgZGUgaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tLzYta2V5LWFyZWFzLW9mLWJ1c2luZXNzLWludGVsbGlnZW5jZS1pbi10aGUtbmV3LWVyYS0xMDVmZGM2ZjkzNTAgIAoKMy4gRXNjb2JhciwgSi4gKDIwMjEsIDI2IG9jdHVicmUpLiAqQnVzaW5lc3MgQW5hbHl0aWNzIHZzIEJ1c2luZXNzIEludGVsbGlnZW5jZSDCv2N1w6FsIGVzIGxhIGRpZmVyZW5jaWE/KiBSZWN1cGVyYWRvIDIxIGRlIG9jdHVicmUgZGUgMjAyMiwgZGUgaHR0cHM6Ly9ibG9nLmVnYWRlLnRlYy5teC9idXNpbmVzcy1hbmFseXRpY3MtdnMtYnVzaW5lc3MtaW50ZWxsaWdlbmNlLWRpZmVyZW5jaWFzICAgCgo0LiAqV2hhdCBpcyBhIEtleSBQZXJmb3JtYW5jZSBJbmRpY2F0b3IgKEtQSSk/KiAocy4gZi4pLiBSZWN1cGVyYWRvIDIxIGRlIG9jdHVicmUgZGUgMjAyMiwgZGUgaHR0cHM6Ly9rcGkub3JnL0tQSS1CYXNpY3MgIAo=