Limpieza, Transformación, y Organización

Exportar bases de datos

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

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(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 - Producción

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
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

b. FORM – Scrap

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

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

c. FORM – Merma

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)

d. Delivery Performance

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)

e. Delivery plan

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)

f. Recursos humanos

En la base de datos s e trabajó previamente en excel, homogenizando las variables y después se trabajo 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
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)
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" ...
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" ...

Análisis Exploratorio de las Bases de Datos

Tabla con los principales estadísticos descrptivos

Estadísticos descriptivos Producción

# install.packages("psych")
library(psych)
describe(data)
##                       vars    n   mean     sd median trimmed    mad min max
## Fecha*                   1 5300  29.28  17.49   29.0   29.26  23.72   1  58
## No.                      2 5274  48.19  29.44   46.0   47.12  35.58   1 121
## CLIENTE*                 3 5299   6.98   2.62    7.0    6.98   1.48   1  12
## ID.FORM*                 4 5299 143.39  85.45  152.0  142.01  99.33   1 311
## PRODUCTO*                5 5300 218.20 123.08  218.0  221.84 149.74   1 408
## X*                       6 5300 124.77  99.35   92.0  117.47 130.47   1 339
## PIEZAS.PROG.             7 3804  28.18  42.61   20.0   20.98   7.41   0 800
## TMO..MIN.*               8 5300 118.29  90.54  131.0  114.21 100.82   1 274
## HR..FIN*                 9 5300  84.93  14.28   87.0   86.41  14.83   1  99
## ESTACION.ARRANQUE*      10 5300 128.93 151.44   43.5  107.20  63.01   1 480
## Laminas.procesadas*     11 5300 177.48 247.37    3.0  134.55   2.97   1 754
## INICIO.SEP.UP*          12 5300 171.86 241.80    2.0  128.45   1.48   1 748
## FIN.INICIO.DE.SEP.UP*   13 5300 279.91 301.99  206.0  245.66 303.93   1 886
## INICIO.de.PROCESO*      14 5300 284.75 303.73  223.0  248.79 329.14   1 905
## FIN.de.PROCESO*         15 5300  10.41  14.37   12.0    7.84   0.00   1 109
## TIEMPO.CALIDAD          16  676   3.11   7.41    0.0    1.27   0.00   0  60
## TIEMPO.MATERIALES*      17 5300   1.10   0.68    1.0    1.00   0.00   1  13
## MERMAS.Maquinas.        18   24   2.21   1.10    2.0    2.15   1.48   1   4
##                       range  skew kurtosis   se
## Fecha*                   57  0.01    -1.28 0.24
## No.                     120  0.25    -0.96 0.41
## CLIENTE*                 11  0.07     0.22 0.04
## ID.FORM*                310  0.01    -0.90 1.17
## PRODUCTO*               407 -0.17    -1.20 1.69
## X*                      338  0.42    -0.99 1.36
## PIEZAS.PROG.            800  9.06   118.00 0.69
## TMO..MIN.*              273  0.01    -1.12 1.24
## HR..FIN*                 98 -2.23     9.78 0.20
## ESTACION.ARRANQUE*      479  0.85    -0.65 2.08
## Laminas.procesadas*     753  1.09    -0.32 3.40
## INICIO.SEP.UP*          747  1.12    -0.23 3.32
## FIN.INICIO.DE.SEP.UP*   885  0.63    -1.05 4.15
## INICIO.de.PROCESO*      904  0.61    -1.04 4.17
## FIN.de.PROCESO*         108  3.74    16.10 0.20
## TIEMPO.CALIDAD           60  3.78    17.62 0.28
## TIEMPO.MATERIALES*       12  9.07    97.02 0.01
## MERMAS.Maquinas.          3  0.35    -1.30 0.23
Variables <-c("Cantidad" )
Media <-c("6.70" )
Mediana <-c("2" )
Desviacion_estandar <-c("11.85" )

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

Estadísticos descriptivos Scrap

# install.packages("psych")
library(psych)
describe(bd_scrap4)
##             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
Variables <-c("Cantidad" )
Media <-c("6.70" )
Mediana <-c("2" )
Desviacion_estandar <-c("11.85" )

table1 <-data.frame(Variables, Media , Mediana , Desviacion_estandar)
knitr::kable(table1)
Variables Media Mediana Desviacion_estandar
Cantidad 6.70 2 11.85

Estadísticos descriptivos Merma

# install.packages("psych")
library(psych)
describe(bd_merma5)
##       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
Variables <-c("Kilos")
Media <-c("3709.52")
Mediana <-c("3925")
Desviacion_estandar <-c("1023.99")
table2 <-data.frame(Variables, Media, Mediana, Desviacion_estandar)
knitr::kable(table2)
Variables Media Mediana Desviacion_estandar
Kilos 3709.52 3925 1023.99

Estadísticos descriptivos Delivery Performance

# install.packages("psych")
library(psych)
describe(bd_delivery_perf3)
##                   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
Variables <-c("Diferencia Delivery")
Media <-c("16.07")
Mediana <-c("0")
Desviacion_estandar <-c("24.63")
table3 <-data.frame(Variables, Media, Mediana, Desviacion_estandar)
knitr::kable(table3)
Variables Media Mediana Desviacion_estandar
Diferencia Delivery 16.07 0 24.63

Estadísticos descriptivos Delivery Plan

mediana <- median(dp1$Pedidos, na.rm = TRUE)
mediana
## [1] 0
describe(dp1)
## 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
Para conocer estas funciones estadísticas realizamos una descripción de la base de datos, donde podemos ver que la mediana es 0. Hay un total de 228 registros y utilizamos 4 variables para acomodo de las gráficas en donde contabilizamos el número de pedidos por mes y cliente.

Histograma general

hist(dp1$Pedidos) 

Bar plots

PRODUCCIÓN

barplot(prop.table(table(data6$Laminas.procesadas)),col=c("orange","blue","red","green"),main="Fabricante por estado", ylab ="Frecuencias",las=1)

pie(prop.table(table(data6$CLIENTE)),col=c("pink","blue","yellow","orange","red","grey","green","black","white"),main="Empresa", ylab ="Frecuencias",las=1)

SCRAP

library(plyr)
pie(prop.table(table(bd_scrap4$Ubi_origen)),col=c("lightgreen","blue","red"),main="Ubicación de origen",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 kg 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-20kg) 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

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.

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

Pronóstico Industria Automotriz

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 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 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.

Identificación y descripción de Principales Resultados Relevantes (Insights)

  • Como podemos observar en la base de datos de Producción, el mayor cliente de Form, en cuestión de laminas procesadas, es Stabilus 1, así se muestra en la grafica de pastel de empresa, mientras que también cuenta con algunos clientes con muy poca producción como es el caso de VL-017-14989.

  • En la base de datos Scrap, con las graficas que elaboramos, podemos observar que el mayor numero de desecho se origina en el área de la empresa de Pre-Producción, por lo que podemos enforcarnos en proponer estrategias que reduzcan el numero de desecho significativamente en esta área, así como también en el área donde menos hay desecho es en Post-producción.

  • En el área de recursos humanos podemos interpretar con las graficas que en Form, hay un mayor rango de edad entre las mujeres, así como también podemos observar que las mujeres en promedio ganan más que los hombres.

  • En cuestión a las bajas, el análisis de la base de datos nos arroja que existe una gran rotación de personal, y la mayoría de ellos no han alcanzado el grado de jubilación, las razones principales de este son abandono y baja por faltas. En base a la grafica de barras explicada en la parte de bajas, se menciona que la mayoría de las personas que abandonan su trabajo son solteras, así como también algunas de ellas no se conoce su estado civil.

  • En las predicciones de desempeño de la industria automotriz se pudo observar que el automóvil de modelo Passenger se encuentra en decremento, tomando como base los datos de la tasa de desempleo de 6.43 y un índice de confianza de 82.3, se espera que siga el decremento de estos automóviles en EUA del 2021 al 2025. Mientras que en el segundo modelo de regresión con la misma base de datos se espera una predicción de ventas positiva en los automóviles comerciales, tomando en cuenta datos como tasa de desempleo de 6.43, un índice de confianza de 82.3, es incremento se espera del 2021 al 2025.

Reflexión Final

Business Analytics es un enfoque de análisis de datos dentro de alguna empresa, consiste en llevar a cabo soluciones para satisfacer las necesidades de un negocio, lograr metas y alcanzar los objetivos planteados. BA se compone de obtener datos, analizar y mostrar datos de manera visual, ayuda en tomar decisiones basado en tendencias y lo que está pasando en el mercado en general.

  • Business Analytics ayuda a alcanzar los objetivos empresariales a partir de un análisis de grandes volúmenes de datos mediante herramientas como los es RStudio, Phyton, entre otros.

  • BA detecta tendencias conforme al tiempo y puede realizar pronósticos a partir de modelos predictivos.

  • BA utiliza modelos predictivos para optimizar los procesos de una empresa en cualquier área como producción, logística, recursos humanos entre otros.

Business Intelligence se utiliza para evaluar, optimizar y coordinar las operaciones internas de una empresa, mientras que Business Analytics es obtener datos, analizarlos y mostrarlos. Existe diferencias entres estos dos, la mayor diferencia es en la poractica de utilizar los datos de una empresa para anticipar tendencias y resultados. Business Analytics ayuda en tomar decisiones basado en tendencias y lo que está pasando en el mercado en general.

LS0tCnRpdGxlOiAiRW50cmVnYWJsZSAyLjQgRGVzYXJyb2xsYXIgcHJvbsOzc3RpY29zIChzZXJpZXMgZGUgdGllbXBvLCBwcm9tZWRpb3MgbcOzdmlsZXMKICB5IHJlZ3Jlc2nDs24pIgphdXRob3I6ICJLYXJsYSBHZW9yZ2luYSBNYXJ0w61uZXogR29uesOhbGV6IEEwMDgyNzUwMCIKZGF0ZTogIjIwMjItMDktMzAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQoKPGltZyBzcmM9ICIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0Zvcm0ucG5nIj4KCiMgTGltcGllemEsIFRyYW5zZm9ybWFjacOzbiwgeSBPcmdhbml6YWNpw7NuCgojIyMjIEV4cG9ydGFyIGJhc2VzIGRlIGRhdG9zCmBgYHtyfQpkYXRhIDwtIHJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0Jhc2UgZGUgZGF0b3MgRk9STS9BY3QgMi40IEVxdWlwby9Qcm9kdWNpb24gQ29tcGxldGEuY3N2IikKYmRfbWVybWEgPC0gcmVhZC5jc3YoIi9Vc2Vycy9nZW9yZ2luYW1hcnRpbmV6L0RvY3VtZW50cy9UZWMvU2XMgXB0aW1vIFNlbWVzdHJlL0FuYWxpzIF0aWNhIHBhcmEgbmVnb2Npb3MsIGRlIGxvcyBkYXRvcyBhIGRlY2lzaW9uZXMvQmFzZSBkZSBkYXRvcyBGT1JNL0ZPUk0gLSBNZXJtYTEuY3N2IikKYmRfc2NyYXAgPC0gcmVhZC5jc3YoIi9Vc2Vycy9nZW9yZ2luYW1hcnRpbmV6L0RvY3VtZW50cy9UZWMvU2XMgXB0aW1vIFNlbWVzdHJlL0FuYWxpzIF0aWNhIHBhcmEgbmVnb2Npb3MsIGRlIGxvcyBkYXRvcyBhIGRlY2lzaW9uZXMvQmFzZSBkZSBkYXRvcyBGT1JNL0ZPUk0gLSBTY3JhcC5jc3YiKQpiZF9kZWxpdmVyeV9wZXJmIDwtIHJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0Jhc2UgZGUgZGF0b3MgRk9STS9BY3QgMi40IEVxdWlwby9GT1JNIC0gRGVsaXZlcnkgUGVyZm9ybWFuY2UgQy5jc3YiKQpiZF9leHRlcm5hIDwtIHJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0Jhc2UgZGUgZGF0b3MgRk9STS9BY3QgMi40IEVxdWlwby91c19tb3Rvcl9wcm9kdWN0aW9uX2FuZF9kb21lc3RpY19zYWxlcy5jc3YiKQpibGltcGlhPC1yZWFkLmNzdigiL1VzZXJzL2dlb3JnaW5hbWFydGluZXovRG9jdW1lbnRzL1RlYy9TZcyBcHRpbW8gU2VtZXN0cmUvQW5hbGnMgXRpY2EgcGFyYSBuZWdvY2lvcywgZGUgbG9zIGRhdG9zIGEgZGVjaXNpb25lcy9CYXNlIGRlIGRhdG9zIEZPUk0vQWN0IDIuNCBFcXVpcG8vYmFqYXNfbGltcGlhLmNzdiIpCmNsaW1waWE8LXJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0Jhc2UgZGUgZGF0b3MgRk9STS9BY3QgMi40IEVxdWlwby9ybGltcGlhLmNzdiIpCmJhc2UgPC1yZWFkLmNzdigiL1VzZXJzL2dlb3JnaW5hbWFydGluZXovRG9jdW1lbnRzL1RlYy9TZcyBcHRpbW8gU2VtZXN0cmUvQW5hbGnMgXRpY2EgcGFyYSBuZWdvY2lvcywgZGUgbG9zIGRhdG9zIGEgZGVjaXNpb25lcy9CYXNlIGRlIGRhdG9zIEZPUk0vQWN0IDIuNCBFcXVpcG8vdXNfbW90b3JfcHJvZHVjdGlvbl9hbmRfZG9tZXN0aWNfc2FsZXMxLmNzdiIpCmRwIDwtIHJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0Jhc2UgZGUgZGF0b3MgRk9STS9BY3QgMi40IEVxdWlwby9ERUxJVkVSWSBQTEFOIGJkZl9QcnVlYmEuY3N2IikKYGBgCgpgYGB7cn0KYmFqYXNfYmQ8LXJlYWQuY3N2KCIvVXNlcnMvZ2VvcmdpbmFtYXJ0aW5lei9Eb2N1bWVudHMvVGVjL1NlzIFwdGltbyBTZW1lc3RyZS9BbmFsacyBdGljYSBwYXJhIG5lZ29jaW9zLCBkZSBsb3MgZGF0b3MgYSBkZWNpc2lvbmVzL0JEX0Zvcm1fTGltcGlhcy9iYWphc19maW5hbC5jc3YiKQpjb2xhYl9iZDwtcmVhZC5jc3YoIi9Vc2Vycy9nZW9yZ2luYW1hcnRpbmV6L0RvY3VtZW50cy9UZWMvU2XMgXB0aW1vIFNlbWVzdHJlL0FuYWxpzIF0aWNhIHBhcmEgbmVnb2Npb3MsIGRlIGxvcyBkYXRvcyBhIGRlY2lzaW9uZXMvQkRfRm9ybV9MaW1waWFzL2NvbGFiX2ZpbmFsLmNzdiIpCmBgYAoKIyMjIyBMaWJyZXJpYXMgcmVxdWVyaWRhcyAgCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoZm9yZWlnbikKbGlicmFyeShkcGx5cikgICAgICAgICMgZGF0YSBtYW5pcHVsYXRpb24gCmxpYnJhcnkoZm9yY2F0cykgICAgICAjIHRvIHdvcmsgd2l0aCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKbGlicmFyeShnZ3Bsb3QyKSAgICAgICMgZGF0YSB2aXN1YWxpemF0aW9uIApsaWJyYXJ5KGphbml0b3IpICAgICAgIyBkYXRhIGV4cGxvcmF0aW9uIGFuZCBjbGVhbmluZyAKbGlicmFyeShIbWlzYykgICAgICAgICMgc2V2ZXJhbCB1c2VmdWwgZnVuY3Rpb25zIGZvciBkYXRhIGFuYWx5c2lzIApsaWJyYXJ5KG5hbmlhcikgCmxpYnJhcnkoZGxvb2tyKSAKbGlicmFyeShwb2xsc3RlcikKbGlicmFyeShkZXNjcikKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGVwaURpc3BsYXkpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkocHN5Y2gpICAgICAgICAjIGZ1bmN0aW9ucyBmb3IgbXVsdGl2YXJpYXRlIGFuYWx5c2lzIApsaWJyYXJ5KGNvcnJwbG90KSAgICAgIyBjb3JyZWxhdGlvbiBwbG90cwpsaWJyYXJ5KGp0b29scykgICAgICAgIyBwcmVzZW50YXRpb24gb2YgcmVncmVzc2lvbiBhbmFseXNpcyAKbGlicmFyeShsbXRlc3QpICAgICAgICMgZGlhZ25vc3RpYyBjaGVja3MgLSBsaW5lYXIgcmVncmVzc2lvbiBhbmFseXNpcyAKbGlicmFyeShjYXIpICAgICAgICAgICMgZGlhZ25vc3RpYyBjaGVja3MgLSBsaW5lYXIgcmVncmVzc2lvbiBhbmFseXNpcwpsaWJyYXJ5KG9sc3JyKSAgICAgICAgIyBkaWFnbm9zdGljIGNoZWNrcyAtIGxpbmVhciByZWdyZXNzaW9uIGFuYWx5c2lzIApsaWJyYXJ5KGthYmxlRXh0cmEpICAgIyBIVE1MIHRhYmxlIGF0dHJpYnV0ZXMKbGlicmFyeSh0c2VyaWVzKSAgICMgdGltZSBzZXJpZXMgYW5hbHlzaXMgYW5kIGNvbXB1dGF0aW9uYWwgZmluYW5jZSAKbGlicmFyeShmb3JlY2FzdCkgICMgcHJvdmlkZXMgbWV0aG9kcyBhbmQgdG9vbHMgZm9yIGRpc3BsYXlpbmcgYW5kIGFuYWx5emluZyB1bml2YXJpYXRlIHRpbWUgc2VyaWVzIGZvcmVjYXN0CmxpYnJhcnkoYXN0c2EpICAgICAjIGFwcGxpZWQgc3RhdGlzdGljYWwgdGltZSBzZXJpZXMgYW5hbHlzaXMKbGlicmFyeShwbHlyKSAKYGBgCgojIyBhLiBGT1JNIC0gUHJvZHVjY2nDs24KClNlIHRyYWJham8gZW4gbGEgYmFzZSBkZSBkYXRvcyBwYXJhIHByaW1lcm8gZWxpbWluYXIgY29sdW1uYXMgcXVlIG5vIHNvbiByZWxldmFudGVzIHBhcmEgZWwgYW5hbGlzaXMsIGRlc3B1w6lzIGNvbnZlcnRpciBkZSBjYXJhY3RlciBhIE4vQSBwYXJhIHBvZGVyIGVsaW1pbmFyIGxvcyBlc3BhY2lvcyBlbiBibGFuY28gc2luIGRhdG9zIHkgcG9yIMO6bHRpbW8gc2UgcmVlbXBsYXrDsyBsb3MgTkEncyBjb24gZWwgcHJvbWVkaW8gcGFyYSBvYnRlbmVyIHVuIGFwcm94aW1hbmRvIGRlbCB0aWVtcG8gZGUgcHJvZHVjaW9uIGVuIGxvcyBkaWFzIHF1ZSBlc3RhIGVuIGJsYW5jbyBvIE4vQS4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIyMgVGVjbmljYSAxLiAgUmVtb3ZlciB2YWxvcmVzIGlycmVsZXZhbnRlcwoKZGF0YTEgPC0gZGF0YQpkYXRhMTwtc3Vic2V0KGRhdGExLHNlbGVjdD0tYyhOby4sSUQuRk9STSxQUk9EVUNUTyxYLEhSLi5GSU4sRVNUQUNJT04uQVJSQU5RVUUsSU5JQ0lPLlNFUC5VUCxGSU4uSU5JQ0lPLkRFLlNFUC5VUCxJTklDSU8uZGUuUFJPQ0VTTyxGSU4uZGUuUFJPQ0VTTyxUSUVNUE8uQ0FMSURBRCxUSUVNUE8uTUFURVJJQUxFUyxNRVJNQVMuTWFxdWluYXMuKSkKc3RyKGRhdGExKQoKIyMjIyBUZWNuaWNhIDQuIENvbnZlcnRpciB0aXBvcyBkZSBkYXRvcwpkYXRhMiA8LSBkYXRhMQpkYXRhMiRUTU8uLk1JTi4gPC0gc3Vic3RyKGRhdGEyJFRNTy4uTUlOLiwgc3RhcnQgPSAxLCBzdG9wID0gMikKI3RpYmJsZShkYXRhMikgIApkYXRhMiRUTU8uLk1JTi4gPC0gYXMuaW50ZWdlcihkYXRhMiRUTU8uLk1JTi4pCnN0cihkYXRhMikgIAoKZGF0YTMgPC0gZGF0YTIKZGF0YTMkTGFtaW5hcy5wcm9jZXNhZGFzIDwtIHN1YnN0cihkYXRhMyRMYW1pbmFzLnByb2Nlc2FkYXMsIHN0YXJ0ID0gMSwgc3RvcCA9IDIpCiN0aWJibGUoZGF0YTMpICAKZGF0YTMkTGFtaW5hcy5wcm9jZXNhZGFzIDwtIGFzLmludGVnZXIoZGF0YTMkTGFtaW5hcy5wcm9jZXNhZGFzKQpzdHIoZGF0YTMpIAoKZGF0YTMkRmVjaGEgPC0gYXMuRGF0ZShkYXRhMyRGZWNoYSwgZm9ybWF0ID0iJWQvJW0vJXkiKQoKIyMjIyBUZWNuaWNhIDUuIFZhbG9yZXMgZmFsdGFudGVzCmRhdGE0IDwtIGRhdGEzCmRhdGE0JFRNTy4uTUlOLltpcy5uYShkYXRhNCRUTU8uLk1JTi4pXTwtbWVhbihkYXRhNCRUTU8uLk1JTi4sIG5hLnJtID0gVFJVRSkKc3VtbWFyeSAoZGF0YTQpIAoKZGF0YTUgPC0gZGF0YTQKZGF0YTUkUElFWkFTLlBST0cuW2lzLm5hKGRhdGE1JFBJRVpBUy5QUk9HLildPC1tZWFuKGRhdGE1JFBJRVpBUy5QUk9HLiwgbmEucm0gPSBUUlVFKQpzdW1tYXJ5IChkYXRhNSkgCgpkYXRhNiA8LSBkYXRhNQpkYXRhNiRMYW1pbmFzLnByb2Nlc2FkYXNbaXMubmEoZGF0YTYkTGFtaW5hcy5wcm9jZXNhZGFzKV08LW1lYW4oZGF0YTYkTGFtaW5hcy5wcm9jZXNhZGFzLCBuYS5ybSA9IFRSVUUpCnN1bW1hcnkgKGRhdGE2KQpgYGAKCiMjIGIuIEZPUk0g4oCTIFNjcmFwCgpTZSByZWFsaXrDsyB1bmEgbGltcGlhIHByZXZpYSBhIGxhIGJhc2UgZGUgZGF0b3MgZGViaWRvIGEgcXVlIG5vIHNlIHBvZMOtYSBtYW5lamFyIGVuIFIsIHlhIHF1ZSBlbCBmb3JtYXRvIGVuIHF1ZSBzZSBlbmNvbnRyYWJhIG5vIHBlcm1pdMOtYSBxdWUgUiBwdWRpZXJhIGVudGVuZGVyIGN1YWxlcyBlcmFuIGxhcyB2YXJpYWJsZXMgZGUgbnVlc3RyYSBiYXNlIGRlIGRhdG9zIHkgdW5hIHZleiB0ZW5pZW5kbyBsYSBiYXNlIGRlIGRhdG9zIGxhcyB0w6ljbmljYXMgcXVlIHV0aWxpemFtb3MgZW4gZWwgcHJvZ3JhbWEgZnVlICoqUmVtb3ZlciB2YWxvcmVzIGlycmVsZXZhbnRlcyoqIGRlamFuZG8gbGFzIHZhcmlhYmxlcyBjb24gbWF5b3IgaW1wb3J0YW5jaWEgY29tbzogRmVjaGEsIENhbnRpZGFkIHkgVWJpY2FjacOzbiBkZSBvcmlnZW4geSBsYSBzZWd1bmRhIHTDqWNuaWNhIHF1ZSB1dGlsaXphbW9zIGZ1ZSAqKkNvbnZlcnRpciBkZSBjYXJhY3RlciBhIGZlY2hhKiogcGFyYSB0ZW5lciBsYSBmZWNoYSBlbiBlbnRlcm8uCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMjIyBUw6ljbmljYS4gUmVtb3ZlciB2YWxvcmVzIGlycmVsZXZhbnRlcwoKIyMjIyBFbGltaW5hciBjb2x1bW5hcwpzdW1tYXJ5KGJkX3NjcmFwKQoKYmRfc2NyYXAyIDwtIGJkX3NjcmFwCmJkX3NjcmFwMiA8LSBzdWJzZXQgKGJkX3NjcmFwMiwgc2VsZWN0ID0gLWMgKFJlZmVyZW5jaWEsIEhvcmEsIFByb2R1Y3RvLCBVbmlkYWQuZGUubWVkaWRhLCBVYmljYWNpw7NuLmRlLmRlc2VjaG8sIEVzdGFkbykpCgpzdW1tYXJ5IChiZF9zY3JhcDIpCgojIyMjIFTDqWNuaWNhLiBDb252ZXJ0aXIgdGlwb3MgZGUgZGF0b3MKCiMjIyMgQ29udmVydGlyIGRlIGNhcmFjdGVyIGEgZmVjaGEKYmRfc2NyYXAzIDwtIGJkX3NjcmFwMgpiZF9zY3JhcDMkRmVjaGEgPC0gYXMuRGF0ZShiZF9zY3JhcDMkRmVjaGEsIGZvcm1hdCA9IiVkLyVtLyV5IikKCiMgQ2FtYmlhciBsb3Mgbm9tYnJlcyBkZSBsYXMgdmFyaWFibGVzIG3DoXMgY29ydGFzIHkgZXNwZWPDrWZpY2FzCgpuYW1lcyhiZF9zY3JhcDMpIFszXSA9ICJVYmlfb3JpZ2VuIgpuYW1lcyhiZF9zY3JhcDMpCgojIyMjIEV4cG9ydGFyIGJhc2UgZGUgZGF0b3MKYmRfc2NyYXA0IDwtIGJkX3NjcmFwMwp3cml0ZS5jc3YoYmRfc2NyYXA0LCBmaWxlID0ic2NyYXBfRk9STV9saW1waWEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyMgYy4gRk9STSDigJMgTWVybWEgIAoKU2UgcmVhbGl6w7MgdW5hIGxpbXBpYSBwcmV2aWEgYSBsYSBiYXNlIGRlIGRhdG9zIGRlYmlkbyBhIHF1ZSBubyBzZSBwb2TDrWEgbWFuZWphciBlbiBSLCB5YSBxdWUgZWwgZm9ybWF0byBlbiBxdWUgc2UgZW5jb250cmFiYSBubyBwZXJtaXTDrWEgcXVlIFIgcHVkaWVyYSBlbnRlbmRlciBjdWFsZXMgZXJhbiBsYXMgdmFyaWFibGVzIGRlIG51ZXN0cmEgYmFzZSBkZSBkYXRvcyB5IHVuYSB2ZXogdGVuaWVuZG8gbGEgYmFzZSBkZSBkYXRvcyBsYXMgdMOpY25pY2FzIHF1ZSB1dGlsaXphbW9zIGVuIGVsIHByb2dyYW1hIGZ1ZSAqKlJlbW92ZXIgdmFsb3JlcyBpcnJlbGV2YW50ZXMqKiBkZWphbmRvIGxhcyB2YXJpYWJsZXMgY29uIG1heW9yIGltcG9ydGFuY2lhIGNvbW86IEZlY2hhLCBDYW50aWRhZCB5IFViaWNhY2nDs24gZGUgb3JpZ2VuIHkgbGEgc2VndW5kYSB0w6ljbmljYSBxdWUgdXRpbGl6YW1vcyBmdWUgKipDb252ZXJ0aXIgZGUgY2FyYWN0ZXIgYSBmZWNoYSoqIHBhcmEgdGVuZXIgbGEgZmVjaGEgZW4gZW50ZXJvLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBUw6ljbmljYS4gUmVtb3ZlciB2YWxvcmVzIGlycmVsZXZhbnRlcwoKIyBFbGltaW5hciBjb2x1bW5hcwpzdW1tYXJ5KGJkX21lcm1hKQoKYmRfbWVybWEyIDwtIGJkX21lcm1hCmJkX21lcm1hMiA8LSBzdWJzZXQgKGJkX21lcm1hMiwgc2VsZWN0ID0gLWMgKE1lcykpCgojIEVsaW1pbmFyIHJlbmdsb25lcwpiZF9tZXJtYTMgPC0gYmRfbWVybWEyCmJkX21lcm1hMyA8LSBiZF9tZXJtYTNbYmRfbWVybWEzJEZlY2hhID4gMCwgXQoKCiMgVMOpY25pY2EuIENvbnZlcnRpciB0aXBvcyBkZSBkYXRvcwoKIyBDb252ZXJ0aXIgZGUgY2FyYWN0ZXIgYSBmZWNoYQpiZF9tZXJtYTQgPC0gYmRfbWVybWEzCmJkX21lcm1hNCRGZWNoYSA8LSBhcy5EYXRlKGJkX21lcm1hNCRGZWNoYSwgZm9ybWF0ID0iJWQvJW0vJXkiKQoKIyBFeHBvcnRhcgpiZF9tZXJtYTUgPC0gYmRfbWVybWE0CndyaXRlLmNzdihiZF9tZXJtYTUsIGZpbGUgPSJtZXJtYV9GT1JNX2xpbXBpYS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIyBkLiBEZWxpdmVyeSBQZXJmb3JtYW5jZSAgCgpTZSByZWFsaXrDsyB1bmEgbGltcGlhIHByZXZpYSBhIGxhIGJhc2UgZGUgZGF0b3MgZGViaWRvIGEgcXVlIG5vIHNlIHBvZMOtYSBtYW5lamFyIGVuIFIsIHlhIHF1ZSBlbCBmb3JtYXRvIGVuIHF1ZSBzZSBlbmNvbnRyYWJhICBubyBwZXJtaXTDrWEgcXVlIFIgcHVkaWVyYSBlbnRlbmRlciBjdWFsZXMgZXJhbiBsYXMgdmFyaWFibGVzIGRlIG51ZXN0cmEgYmFzZSBkZSBkYXRvcywgcG9yIGxvIHRhbnRvIGxhcyBtb2RpZmljYWNpb25lcyB5IGxpbXBpZXphcyBxdWUgc2UgcmVhbGl6YXJvbiBmdWUgbGEgdMOpY25pY2EgZGUgJ1JlbW92ZXIgdmFsb3JlcyBpcnJlbGV2YW50ZXMnIGVuIGVzdGUgY2FzbyBxdWl0YW1vcyBsYSBjb25jbHVzacOzbiBwb3JxdWUgbm8gdGVuZHLDrWEgdmFsb3IgZW4gbGEgYmFzZSBkZSBkYXRvcywgZWxpbWluYW1vcyB0YXJnZXQgKGhvcmFzKSB5IHRvbWFtb3MgZWwgdmFsb3IgZGUgY2FkYSBpbmljaW8gZGUgbWVzIHBhcmEgY29tcGFyYXIgcHJpbmNpcGlvIGRlIG1lcyBjb24gbWVzLCBkZXNwdcOpcyBlbiBSIHNlIHRyYWJham8gY29uIGxhICoqdMOpY25pY2EgZGUgY29udmVydGlyIHRpcG9zIGRlIGRhdG9zKiogZW4gZXN0ZSBjYXNvIGRlIGNhcmFjdGVyIGEgZmVjaGEgeSBjYXJhY3RlciBhIGhvcmEuIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBUw6ljbmljYSA0LiBDb252ZXJ0aXIgdGlwb3MgZGUgZGF0b3MKCiMgQ29udmVydGlyIGRlIGNhcmFjdGVyIGEgZmVjaGEKYmRfZGVsaXZlcnlfcGVyZjIgPC0gYmRfZGVsaXZlcnlfcGVyZgpiZF9kZWxpdmVyeV9wZXJmMiRmZWNoYSA8LSBhcy5EYXRlKGJkX2RlbGl2ZXJ5X3BlcmYyJGZlY2hhLCBmb3JtYXQgPSIlZC8lbS8leSIpCmxpYnJhcnkodGliYmxlKQp0aWJibGUoYmRfZGVsaXZlcnlfcGVyZjIpICAKCiMgQ2FtYmlhciBsb3Mgbm9tYnJlcyBkZSBsYXMgdmFyaWFibGVzIG3DoXMgY29ydGFzIHkgZXNwZWPDrWZpY2FzCgpuYW1lcyhiZF9kZWxpdmVyeV9wZXJmMikgWzNdID0gImRlbGF5X3BlcmZvcm1hbmNlIgpuYW1lcyhiZF9kZWxpdmVyeV9wZXJmMikKCiMgRXhwb3J0YXIKYmRfZGVsaXZlcnlfcGVyZjMgPC0gYmRfZGVsaXZlcnlfcGVyZjIKd3JpdGUuY3N2KGJkX2RlbGl2ZXJ5X3BlcmYzLCBmaWxlID0iZGVsaXZlcnlwZXJmb3JtYW5jZV9GT1JNX2xpbXBpYS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIyBlLiBEZWxpdmVyeSBwbGFuCgpMYSBsaW1waWV6YSB5IG1vZGlmaWNhY2nDs24gZGUgZmlsYXMgeSBjb2x1bW5hcyByZXNwZWN0byBhIGxhcyB2YXJpYWJsZXMgc2UgcmVhbGl6w7MgZGlyZWN0YW1lbnRlIGVuIEV4Y2VsIHBvciBjdWVzdGlvbmVzIGRlIGZhY2lsaWRhZCB5YSBxdWUgbGEgYmFzZSBlc3RhYmEgb3JkZW5hZGEgZGUgdW5hIG1hbmVyYSBlbiBkb25kZSBSIHJlc3VsdGFyw61hIG11Y2hvIG3DoXMgY29tcGxpY2Fkby4KCmBgYHtyfQojIFTDqWNuaWNhIDQuIENvbnZlcnRpciB0aXBvcyBkZSBkYXRvcwoKIyBDb252ZXJ0aXIgZGUgY2FyYWN0ZXIgYSBmZWNoYQpkcDEgPC0gZHAKZHAxJEZlY2hhPC1hcy5EYXRlKGRwMSRGZWNoYSxmb3JtYXQ9IiVtLyVkLyVZIikgCgojIENvbnRhYmlsaXphciBzaSBoYXkgTkHCtFMgZGVudHJvIGRlIGxhIGJhc2UgZGUgZGF0b3MgYWN0dWFsIHBhcmEgc3VzdGl0dWlybG9zIGNvbiBsYSBtZWRpYSwgbW9kYSBvIG1lZGlhbmEuCgpjb2xTdW1zKGlzLm5hKGRwMSkpCiMgVmVtb3MgcXVlIGVuIGxhIGJhc2UgZGUgZGF0b3Mgbm8gaGF5IE5BwrRTIAoKIyMgRXhwb3J0YW1vcyBsYSBiYXNlIGRlIGRhdG9zIGxpbXBpYQp3cml0ZS5jc3YoZHAxLCBmaWxlID0iREVMSVZFUllfRklOQUxfTElNUElBLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQpgYGAKCiMjIGYuIFJlY3Vyc29zIGh1bWFub3MKCkVuIGxhIGJhc2UgZGUgZGF0b3MgcyBlIHRyYWJhasOzIHByZXZpYW1lbnRlIGVuIGV4Y2VsLCBob21vZ2VuaXphbmRvIGxhcyB2YXJpYWJsZXMgeSBkZXNwdcOpcyBzZSB0cmFiYWpvIGVuIFIgZGlzdGludGFzIHTDqWNuaWNhcyBsb2dyYW5kbyBlbGltaW5hciBsYXMgdmFyaWFibGVzIHF1ZSBubyBzZSBjb25zaWRlcmVuIG5lY2VzYXJpYXMuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFTDqWNuaWNhLiBSZW1vdmVyIHZhbG9yZXMgaXJyZWxldmFudGVzCmNsaW1waWEyPC1jbGltcGlhCmNsaW1waWEyPC1zdWJzZXQoY2xpbXBpYTIsc2VsZWN0PS1jKFByaW1lci5tZXMsWDR0by5tZXMsRW1wbGVhZG8sREVQQVJUQU1FTlRPKSkKc3VtbWFyeShjbGltcGlhMikKCiMgwr9DdcOhbnRvcyBOQSAgdGVuZ28gcG9yIHZhcmlhYmxlcz8gQ09MQUIKCnNhcHBseShjbGltcGlhMixmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQoKIyDCv0N1w6FudG9zIE5BICB0ZW5nbyBwb3IgdmFyaWFibGVzPyBCQUpBUwpzYXBwbHkoYmxpbXBpYSxmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQoKIyBObyBoYXkgbcOhcyB2YWxvcmVzIGZhbHRhbnRlcy4KCiMgVMOpY25pY2EuIENvbnZlcnRpciB0aXBvcyBkZSBkYXRvcwoKIyBDYW1iaWFyIG5vbWJyZXMgZGUgY29sdW1uYXMuCiMgQ09MQUIKc3RyKGNsaW1waWEyKQpuYW1lcyAoY2xpbXBpYTIpID0gYygiZWRhZCIsICJnZW5lcm8iLCAiYWx0YSIsICJwdWVzdG8iLCAic2FsYXJpb19kaWFyaW8iLCAibHVnYXIubmFjaW0uIiwibXBpbyIsImVzdGFkbyIsImNpdmlsIikKbmFtZXMgKGNsaW1waWEyKQpzdHIoY2xpbXBpYTIpCgojIEJBSkFTCnN0cihibGltcGlhKQpuYW1lcyAoYmxpbXBpYSkgPSBjKCJub21icmUiLCAiZWRhZCIsICJnZW5lcm8iLCAiYWx0YSIsICJtb3Rpdm9fYmFqYSIsICJkdXJhY2lvbiIsICJwdWVzdG8iLCJzYWxhcmlvX2RpYXJpbyIsImVzdGFkbyIsImUuY2l2aWwuIikKbmFtZXMgKGJsaW1waWEpCnN0cihibGltcGlhKQoKIyBFeHBvcnRhcgpjb2xhYl9maW5hbDwtY2xpbXBpYTIKd3JpdGUuY3N2KGNvbGFiX2ZpbmFsLCBmaWxlID0iY29sYWJfZmluYWwuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgpiYWphc19maW5hbDwtYmxpbXBpYQp3cml0ZS5jc3YoYmFqYXNfZmluYWwsIGZpbGUgPSJiYWphc19maW5hbC5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgpgYGB7cn0KY29sYWJfYmQkZ2VuZXJvW2NvbGFiX2JkJGdlbmVybyA9PSAiRkVNRU5JTk8iXSA8LSAiRiIKY29sYWJfYmQkZ2VuZXJvW2NvbGFiX2JkJGdlbmVybyA9PSAiTUFTQ1VMSU5PIl0gPC0gIk0iCnN0cihjb2xhYl9iZCkKYGBgCgpgYGB7cn0KYmFqYXNfYmQkZ2VuZXJvW2JhamFzX2JkJGdlbmVybyA9PSAiRkVNRU5JTk8iXSA8LSAiRiIKYmFqYXNfYmQkZ2VuZXJvW2JhamFzX2JkJGdlbmVybyA9PSAiTUFTQ1VMSU5PIl0gPC0gIk0iCnN0cihiYWphc19iZCkKYGBgCgojIEFuw6FsaXNpcyBFeHBsb3JhdG9yaW8gZGUgbGFzIEJhc2VzIGRlIERhdG9zCiMjIyBUYWJsYSBjb24gbG9zIHByaW5jaXBhbGVzIGVzdGFkw61zdGljb3MgZGVzY3JwdGl2b3MKCiMjIyMgKipFc3RhZMOtc3RpY29zIGRlc2NyaXB0aXZvcyBQcm9kdWNjacOzbioqCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQpsaWJyYXJ5KHBzeWNoKQpkZXNjcmliZShkYXRhKQoKVmFyaWFibGVzIDwtYygiQ2FudGlkYWQiICkKTWVkaWEgPC1jKCI2LjcwIiApCk1lZGlhbmEgPC1jKCIyIiApCkRlc3ZpYWNpb25fZXN0YW5kYXIgPC1jKCIxMS44NSIgKQoKdGFibGUxIDwtIGRlc2NyaWJlKGRhdGEpCmtuaXRyOjprYWJsZSh0YWJsZTEpCmBgYAoKIyMjIyAqKkVzdGFkw61zdGljb3MgZGVzY3JpcHRpdm9zIFNjcmFwKioKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBpbnN0YWxsLnBhY2thZ2VzKCJwc3ljaCIpCmxpYnJhcnkocHN5Y2gpCmRlc2NyaWJlKGJkX3NjcmFwNCkKClZhcmlhYmxlcyA8LWMoIkNhbnRpZGFkIiApCk1lZGlhIDwtYygiNi43MCIgKQpNZWRpYW5hIDwtYygiMiIgKQpEZXN2aWFjaW9uX2VzdGFuZGFyIDwtYygiMTEuODUiICkKCnRhYmxlMSA8LWRhdGEuZnJhbWUoVmFyaWFibGVzLCBNZWRpYSAsIE1lZGlhbmEgLCBEZXN2aWFjaW9uX2VzdGFuZGFyKQprbml0cjo6a2FibGUodGFibGUxKQpgYGAKCiMjIyMgKipFc3RhZMOtc3RpY29zIGRlc2NyaXB0aXZvcyBNZXJtYSoqCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQpsaWJyYXJ5KHBzeWNoKQpkZXNjcmliZShiZF9tZXJtYTUpCgpWYXJpYWJsZXMgPC1jKCJLaWxvcyIpCk1lZGlhIDwtYygiMzcwOS41MiIpCk1lZGlhbmEgPC1jKCIzOTI1IikKRGVzdmlhY2lvbl9lc3RhbmRhciA8LWMoIjEwMjMuOTkiKQpgYGAKCmBgYHtyfQp0YWJsZTIgPC1kYXRhLmZyYW1lKFZhcmlhYmxlcywgTWVkaWEsIE1lZGlhbmEsIERlc3ZpYWNpb25fZXN0YW5kYXIpCmtuaXRyOjprYWJsZSh0YWJsZTIpCmBgYAoKIyMjIyAqKkVzdGFkw61zdGljb3MgZGVzY3JpcHRpdm9zIERlbGl2ZXJ5IFBlcmZvcm1hbmNlKioKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBpbnN0YWxsLnBhY2thZ2VzKCJwc3ljaCIpCmxpYnJhcnkocHN5Y2gpCmRlc2NyaWJlKGJkX2RlbGl2ZXJ5X3BlcmYzKQoKVmFyaWFibGVzIDwtYygiRGlmZXJlbmNpYSBEZWxpdmVyeSIpCk1lZGlhIDwtYygiMTYuMDciKQpNZWRpYW5hIDwtYygiMCIpCkRlc3ZpYWNpb25fZXN0YW5kYXIgPC1jKCIyNC42MyIpCmBgYAoKYGBge3J9CnRhYmxlMyA8LWRhdGEuZnJhbWUoVmFyaWFibGVzLCBNZWRpYSwgTWVkaWFuYSwgRGVzdmlhY2lvbl9lc3RhbmRhcikKa25pdHI6OmthYmxlKHRhYmxlMykKYGBgCgojIyMjICoqRXN0YWTDrXN0aWNvcyBkZXNjcmlwdGl2b3MgRGVsaXZlcnkgUGxhbioqCmBgYHtyfQptZWRpYW5hIDwtIG1lZGlhbihkcDEkUGVkaWRvcywgbmEucm0gPSBUUlVFKQptZWRpYW5hCgpkZXNjcmliZShkcDEpCmBgYAojIyMjIyBQYXJhIGNvbm9jZXIgZXN0YXMgZnVuY2lvbmVzIGVzdGFkw61zdGljYXMgcmVhbGl6YW1vcyB1bmEgZGVzY3JpcGNpw7NuIGRlIGxhIGJhc2UgZGUgZGF0b3MsIGRvbmRlIHBvZGVtb3MgdmVyIHF1ZSBsYSBtZWRpYW5hIGVzIDAuIEhheSB1biB0b3RhbCBkZSAyMjggcmVnaXN0cm9zIHkgdXRpbGl6YW1vcyA0IHZhcmlhYmxlcyBwYXJhIGFjb21vZG8gZGUgbGFzIGdyw6FmaWNhcyBlbiBkb25kZSBjb250YWJpbGl6YW1vcyBlbCBuw7ptZXJvIGRlIHBlZGlkb3MgcG9yIG1lcyB5IGNsaWVudGUuICAgIAoKIyMjIyBIaXN0b2dyYW1hIGdlbmVyYWwgCmBgYHtyfQpoaXN0KGRwMSRQZWRpZG9zKSAKYGBgCgojIyMgQmFyIHBsb3RzCgojIyMjICoqUFJPRFVDQ0nDk04qKiAKYGBge3J9CmJhcnBsb3QocHJvcC50YWJsZSh0YWJsZShkYXRhNiRMYW1pbmFzLnByb2Nlc2FkYXMpKSxjb2w9Yygib3JhbmdlIiwiYmx1ZSIsInJlZCIsImdyZWVuIiksbWFpbj0iRmFicmljYW50ZSBwb3IgZXN0YWRvIiwgeWxhYiA9IkZyZWN1ZW5jaWFzIixsYXM9MSkKcGllKHByb3AudGFibGUodGFibGUoZGF0YTYkQ0xJRU5URSkpLGNvbD1jKCJwaW5rIiwiYmx1ZSIsInllbGxvdyIsIm9yYW5nZSIsInJlZCIsImdyZXkiLCJncmVlbiIsImJsYWNrIiwid2hpdGUiKSxtYWluPSJFbXByZXNhIiwgeWxhYiA9IkZyZWN1ZW5jaWFzIixsYXM9MSkKYGBgCgojIyMjICoqU0NSQVAqKiAKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShwbHlyKQpwaWUocHJvcC50YWJsZSh0YWJsZShiZF9zY3JhcDQkVWJpX29yaWdlbikpLGNvbD1jKCJsaWdodGdyZWVuIiwiYmx1ZSIsInJlZCIpLG1haW49IlViaWNhY2nDs24gZGUgb3JpZ2VuIixsYXM9MSkKYGBgCgojIyMjICoqREVMSVZFUlkgUExBTjogUFJJTkNJUEFMRVMgQ0xJRU5URVMqKgpDb24gbGEgc2lndWllbnRlIGZ1bmNpw7NuIHBvZHJlbW9zIGlkZW50aWZpY2FyIGxvcyBwcmluY2lwYWxlcyBjbGllbnRlcyBwYXJhIGdlbmVyYXIgdW4gYW7DoWxpc2lzIGNvbiBsYSBpbmZvcm1hY2nDs24gcmVsZXZhbnRlLCBwdWVzIGhheSBjbGllbnRlcyBjb24gcG9jb3MgbyBzaW4gcGVkaWRvcyBwb3IgbG8gcXVlIGdlbmVyYXIgdW4gZGlhZ27Ds3N0aWNvIHJlc3BlY3RvIGEgZGVsaXZlcnkgcGxhbiBjb24gZXNvcyBkYXRvcyBubyBlcyBuZWNlc2FyaW8uIApgYGB7cn0KZ2dwbG90KGRwMSwgYWVzKHg9cmVvcmRlcihDTElFTlRFLFBlZGlkb3MpLCB5PVBlZGlkb3MpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsKICBjb29yZF9mbGlwKCkKYGBgCgojIyMjICoqREVMSVZFUlkgUExBTjogVE9QIDYgQ0xJRU5URVMgWSBQUk9NRURJTyoqICAKCkNvbW8gc2lndWllbnRlIHBhc28gZWxpbWluYXJlbW9zIHRvZG9zIGxvcyBjbGllbnRlcyBxdWUgbm8gbm9zIGludGVyZXNhbiBwYXJhIGVsIGFuw6FsaXNpcyB5IGRlamFyZW1vcyBlbCB0b3AgNiBkZSBjbGllbnRlcyBwYXJhIGVsIGVqZXJjaWNpby4KYGBge3J9CgpkcDIgPC0gZHAxCmRwMjwtZHAyW2RwMiRDTElFTlRFIT0iQUJDIFFVRVJFVEFSTyIsXQpkcDI8LWRwMltkcDIkQ0xJRU5URSE9IkFOVE9MSU4gQVJURUFHQSIsXSAgCmRwMjwtZHAyW2RwMiRDTElFTlRFIT0iQU5UT0xJTiBUT0xVQ0EiLF0gCmRwMjwtZHAyW2RwMiRDTElFTlRFIT0iSVNSSSIsXSAKZHAyPC1kcDJbZHAyJENMSUVOVEUhPSJTRUdST1ZFIixdIApkcDI8LWRwMltkcDIkQ0xJRU5URSE9IlNUQiAxIixdIApkcDI8LWRwMltkcDIkQ0xJRU5URSE9IlVGSSIsXSAKZHAyPC1kcDJbZHAyJENMSUVOVEUhPSJZRiBRUk8iLF0gCmRwMjwtZHAyW2RwMiRDTElFTlRFIT0iSU5PQUMgUE9MWVRFQyIsXSAKZHAyPC1kcDJbZHAyJENMSUVOVEUhPSJIQU5PTiIsXSAKZHAyPC1kcDJbZHAyJENMSUVOVEUhPSJNRVJJRElBTiIsXSAKZHAyPC1kcDJbZHAyJENMSUVOVEUhPSJZRiBSQU1PUyIsXSAKZHAyPC1kcDJbZHAyJENMSUVOVEUhPSJZQU5GRU5HIHNtIixdIApgYGAKCmBgYHtyfQpnZ3Bsb3QoZHAyLGFlcyh4PUZlY2hhLCB5PVBlZGlkb3MsZmlsbD1DTElFTlRFKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MzMsbGluZXR5cGU9ImRhc2hlZCIsY29sb3I9ImJsYWNrIikrCiAgbGFicyh4PSJGZWNoYSIseT0iTsO6bWVybyBkZSBwZWRpZG9zIiwgY29sb3I9IkxlZ2VuZCIpKwogIGdndGl0bGUoIlBlZGlkb3MgcG9yIGZlY2hhIikKCmBgYAoKIyMjIyAqKlJFQ1VSU09TIEhVTUFOT1M6IENPTEFCT1JBRE9SRVMgQUNUVUFMRVMqKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBhcy5kYXRhLmZyYW1lKGJhamFzX2JkKQojIGFzLmRhdGEuZnJhbWUoY29sYWJfYmQpCmBgYAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmNvbGFiX2JkMjwtY29sYWJfYmQgJT4lIGRwbHlyOjpzZWxlY3QoZ2VuZXJvLGVkYWQsc2FsYXJpb19kaWFyaW8pICU+JSAgZHBseXI6Omdyb3VwX2J5KGdlbmVybykgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLG1lYW4sbmEucm09VFJVRSkpICU+JSBhcnJhbmdlKGRlc2MoZWRhZCkpCmdncGxvdChjb2xhYl9iZDIsIGFlcyh4PXJlb3JkZXIoZ2VuZXJvLGVkYWQpLCB5PWVkYWQsIGZpbGw9KHNhbGFyaW9fZGlhcmlvKSkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsY29sPWMoImJsYWNrIikpKwogIGNvb3JkX2ZsaXAoKSsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQocmV2ZXJzZT1GQUxTRSkpCmBgYAoKIyMjIyMgTGEgcHJpbWVyYSBncsOhZmljYSBkZSBiYXJyYXMgbm9zIGRhIGEgY29ub2NlciBzb2JyZSBlbCBzYWxhcmlvIGRpYXJpbyBkZSBsYXMgcGVyc29uYXMgZGUgRm9ybSwgc2VnbWVudGFkbyBwb3IgZWRhZCB5IHBvciBnw6luZXJvLiBMbyBxdWUgbm9zIGRhIGEgY29ub2NlciBlcyBxdWUgZW4gbGEgZW1wcmVzYSBleGlzdGUgdW4gbWF5b3IgcmFuZ28gZGUgZWRhZCBlbnRyZSBsYXMgbXVqZXJlcyBkZSBGb3JtLCBsbGVnYW5kbyBhIHNlciBjYXNpIDQwIGxvIG1heW9yOyBwb3Igb3RyYSBwYXJ0ZSwgbG9zICBob21icmVzIHByZXNlbnRhbiB1biBtZW5vciByYW5nbywgY29uIHVuIG3DoXhpbW8gZGUgKGFwcm94KSAzMy4gSWd1YWxtZW50ZSwgdmVtb3MgcXVlIGVuIHByb21lZGlvIGxhcyBtdWplcmVzIGdhbmFuIDYwIGNlbnRhdm9zIG3DoXMgcXVlIGxvcyBob21icmVzLiAgICAgIAoKYGBge3J9CgpnZ3Bsb3QoY29sYWJfYmQsIGFlcyh4PWdlbmVybywgeT1zYWxhcmlvX2RpYXJpbywgZmlsbD1nZW5lcm8pKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKyAKICBmYWNldF9ncmlkKH5jaXZpbCkgKyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKQpgYGAKCiMjIyMjIEVzdGEgc2VndW5kYSBncsOhZmljYSBkZXNjcmlwdGl2YSBkZSBsb3MgYWN0dWFsZXMgY29sYWJvcmFkb3JlcyAgZGUgRm9ybSwgbm9zIGNvbXVuaWNhLCBwcmluY2lwYWxtZW50ZSwgZWwgZXN0YWRvIGNpdmlsIGRlIGxvcyBjb2xhYm9yYWRvcmVzICBwb3IgZ8OpbmVybywgeSBzdSBnYW5hbmNpYS4gTG8gcXVlIHBvZGVtb3Mgbm90YXIgZXMgcXVlIGVuIGdlbmVyYWwsIGxhcyBtdWplcmVzIGdhbmFuIG3DoXMgZW4gY3VhbHF1aWVyIGVzdGFkbyBjaXZpbCBlbiBlbCBxdWUgc2UgZW5jdWVudHJlbiwgeSBlbiBkb25kZSBzZSBwdWVkZSB2ZXIgdW5hIG1heW9yIHZhcmllZGFkIGRlIGxhIHN1bWEgZGUgbG9zIHNhbGFyaW9zIGVzIGVuIGxhcyBtdWplcmVzICB5IGxvcyBob21icmVzIHF1ZSBzZSBlbmN1ZW50cmFuIGVuIHVuacOzbiBsaWJyZS4gCgojIyMjICoqUkVDVVJTT1MgSFVNQU5PUzogQkFKQVMqKgoKYGBge3J9CgpiYWphc19iZDI8LWJhamFzX2JkICU+JSBkcGx5cjo6c2VsZWN0KG1vdGl2b19iYWphLGVkYWQsZHVyYWNpb24pICU+JSBncm91cF9ieShtb3Rpdm9fYmFqYSkgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLG1lYW4sbmEucm09VFJVRSkpICU+JSBhcnJhbmdlKGRlc2MoZWRhZCkpCmdncGxvdChiYWphc19iZDIsIGFlcyh4PXJlb3JkZXIobW90aXZvX2JhamEsZWRhZCksIHk9ZWRhZCwgZmlsbD0oZHVyYWNpb24pKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iixjb2w9YygiYmxhY2siKSkrCiAgY29vcmRfZmxpcCgpKwogIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZChyZXZlcnNlPUZBTFNFKSkKYGBgCgojIyMjIyBWaWVuZG8gYWhvcmEgbG9zIGNvbGFib3JhZG9yZXMgcXVlIGhhbiBzaWRvIGRhZG9zIGRlIGJhamEgZW4gbGEgZW1wcmVzYSwgdmVtb3MgcXVlIGxhIGdyYW4gcGFydGUgZGUgbG9zIHF1ZSBzZSBoYW4gc2FsaWRvIGRlIEZvcm0gdGllbmVuIG1lbm9zIGRlIDMwIGHDsW9zLiBQb2NvcyBjYXNvcyBoYW4gc2lkbyBkZSBqdWJpbGFjacOzbiwgbGxlZ2FuZG8gYSBtw6FzIGRlIDYwIGVuIHJhbmdvLiBJZ3VhbG1lbnRlLCBhIHBhcnRpciBkZSBsYSBncsOhZmljYSB2ZW1vcyBxdWUgbGFzIHJhem9uZXMgcHJpbmNpcGFsZXMgc29uIHBvciBhYmFuZG9ubyB5ICBiYWphIHBvciBmYWx0YXM7IGR1cmFuZG8gbWVub3MgZGUgNTAwIGTDrWFzIGVuIHN1IHRyYWJham8uIAoKYGBge3J9CgpnZ3Bsb3QoYmFqYXNfYmQsIGFlcyh4PWdlbmVybywgeT1zYWxhcmlvX2RpYXJpbywgZmlsbD1nZW5lcm8pKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKyAKICBmYWNldF9ncmlkKH5lLmNpdmlsLikgKyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKQpgYGAKCiMjIyMjIEZpbmFsbWVudGUsIG9ic2VydmFtb3MgbGEgw7psdGltYSBncsOhZmljYSBkZXNjcmlwdGl2YSBkZSBsb3MgY29sYWJvcmFkb3JlcyBxdWUgaGFuIHNpZG8gZGFkb3MgZGUgYmFqYSBwb3IgRm9ybS4gRW4gdW4gIGNhc28gb2JzZXJ2YW1vcyBxdWUgbm8gc2UgY29ub2NlIHN1IHNpdHVhY2nDs24gZGUgZXN0YWRvIGNpdmlsLiBJZ3VhbG1lbnRlLCBvYnNlcnZhbW9zIHF1ZSBsYSBtYXlvciBjYW50aWRhZCAoc2UgYXN1bWUgcG9yIGxhIHN1bWEgZGUgc2FsYXJpbyAgZGlhcmlvKSBoYW4gc2lkbyBzb2x0ZXJvcywgeSAgdW5hIGdyYW4gY2FudGlkYWQgZGUgbXVqZXJlcyBjYXNhZGFzLiBQb3IgbG8gdGFudG8sIHBvZGVtb3MgYXN1bWlyIGEgcGFydGlyIGRlIGxvcyBkYXRvcyBxdWUgbGEgbWF5b3LDrWEgZGUgbG9zIHF1ZSBhYmFuZG9uYW4gc3UgdHJhYmFqbyBlbiBGb3JtIHNvbiBwZXJzb25hcyBzb2x0ZXJhcy4gIAoKIyMjIERpc3BlcnNpb24gcGxvdHMgIAoKIyMjIyAqKlBST0RVQ0NJw5NOKiogCmBgYHtyfQpwbG90KGRhdGE2JFRNTy4uTUlOLiwgeGxhYiA9ICJQcm9jZXNvIGRlIGxhbWluYSIsIHlsYWIgPSAiVGllbXBvIiwgbWFpbiA9ICJUaWVtcG8gcG9yIExhbWluYSIgKQpgYGAKCiMjIyMgKipNRVJNQSoqCmBgYHtyfQpnZ3Bsb3QoYmRfbWVybWE1LCBhZXMoeD0gRmVjaGEsIHk9IEtpbG9zKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9InJlZCIpICsgc2NhbGVfZmlsbF9ncmV5KCkgKyBsYWJzKHRpdGxlID0gIktpbG9zIGRlIG1lcm1hIiwgeCA9ICJGZWNoYSIpCmBgYAoKIyMjIyMgUG9kZW1vcyB2ZXIgY29tbyBlbiBpbmljaW9zIGRlIEZlYnJlcm8gYSBBYnJpbCB0ZW5lbW9zIGxhIG1heW9yIGNhbnRpZGFkIGRlIGtpbG9zIGRlIG1lcm1hLCBxdWUgaW5jbHVzbyBwYXNhIGRlbCBwcm9tZWRpbyBkZSBsb3MgZGVtYXMgbWVzZXMsIHBvciBsbyBxdWUgZXMgaW1wb3J0YW50ZSBhbmFsaXphciBxdWUgZmFjdG9yIGhpem8gcXVlIGR1cmFudGUgZXNlIHBlcmlvZG8gaHViaWVyYSBtw6FzIG1lcm1hLiAgCgpgYGB7cn0KYmRfbWVybWE1JEZlY2hhIDwtIGFzLkRhdGUoYmRfbWVybWE1JEZlY2hhLCBmb3JtYXQgPSAiJWQvJW0vJVkiKQpwbG90KGJkX21lcm1hNSRGZWNoYSwgYmRfbWVybWE1JEtpbG9zLCBtYWluID0gIktpbG9zIGRlIG1lcm1hIiwKICAgICB4bGFiID0gIkZlY2hhIiwgeWxhYiA9ICJLaWxvcyIsCiAgICAgcGNoID0gMTksIGZyYW1lID0gRkFMU0UpCmBgYAoKIyMjIyMgUG9kZW1vcyB2ZXIgY29tbyBoYXkgbWFzIGRpc3BlcnNpw7NuIGVuIHNlcHRpZW1icmUsIGxvcyBkZW3DoXMgbWVzZXMgaGEgdGVuaWRvIGVuIHByb21lZGlvIGxhIG1pc21hIGNhbnRpZGFkIGRlIG1lcm1hLiAgCgojIyMjICoqU0NSQVAqKiAKYGBge3J9Cmhpc3QoYmRfc2NyYXA0JENhbnRpZGFkLCBtYWluID0gIkNhbnRpZGFkIGRlIE1hdGVyaWFsIHJlY2ljbGFkbyIsIHhsYWIgPSAiQ2FudGlkYWQiLCB5bGFiID0gIkZyZWN1ZW5jaWEiLGNvbCA9ICJibHVlIikKYGBgCgojIyMjIyBFc3RlIGhpc3RvZ3JhbWEgbm9zIG11ZXN0cmEgcXVlIGVudHJlIDAgYSAxMCBrZyBlcyBsbyBxdWUgbWFzIHNlIGZyZWN1ZW50YSBhIHJlY2ljbGFyIGVsIG1hdGVyaWFsLiAgCgpgYGB7cn0KcGxvdChiZF9zY3JhcDQkRmVjaGEsIGJkX3NjcmFwNCRDYW50aWRhZCwgbWFpbiA9ICJDYW50aWRhZCBkZSBTY3JhcCBwb3IgZmVjaGEiLCB4bGFiID0gIkZlY2hhIiwgeWxhYiA9ICJDYW50aWRhZCIpCmBgYAoKIyMjIyMgUG9kZW1vcyB2ZXIgcXVlIGhheSBjaWVydG9zIGTDrWFzIHF1ZSBzYWxlbiBmdWVyYSBkZWwgcHJvbWVkaW8gKHF1ZSBlcyBhbHJlZGVkb3IgZGUgMC0yMGtnKSBxdWUgc2UgdGllbmUgZGUgbGEgY2FudGlkYWQgZGUgU2NyYXAuICAgCgojIyMjICoqREVMSVZFUlkgUExBTioqCgojIyMjICpQZWRpZG9zKgpgYGB7cn0KcGxvdChkcDIkRmVjaGEsIGRwMiRQZWRpZG9zLCBtYWluID0gIlBlZGlkb3MgcG9yIGZlY2hhIiwKICAgICB4bGFiID0gIkZlY2hhIiwgeWxhYiA9ICJQZWRpZG9zIiwKICAgICBwY2ggPSAxLCBmcmFtZSA9IEZBTFNFKQpgYGAKCmBgYHtyfQpib3hwbG90KGRwMiRQZWRpZG9zLCBtYWluID0gIlBlZGlkb3MiKQpgYGAKCiMjIyMjIENvbW8gcHJpbWVyIGJveHBsb3Qgdmltb3MgbG9zIHBlZGlkb3MgeSBsYSBncmFuIGRpc3BlcnNpw7NuIHF1ZSBoYXkgZW50cmUgcGVkaWRvcywgcHVlcyBkZXRlY3RhbW9zIHVuYSBmcmVjdWVuY2lhIGVuIGRvbmRlIGhheSBjbGllbnRlcyBxdWUgZ2VuZXJhbiBwZWRpZG9zIG9idmlhbWVudGUgZGlmZXJlbnRlcyBjb21vIHBhcmEgdGVuZXIgdW5hIG1lZGlhbmEgbyB1bmEgZGlzcGVyc2nDs24gcG9zaXRpdmEuICAKCiMjIyMgKkNsaWVudGVzKgoKRGVzcHXDqXMgZGUgZ2VuZXJhciB1biBib3hwbG90IGRlIHBlZGlkb3MgZW4gZ2VuZXJhbCwgcmVhbGl6YW1vcyB1biBib3hwbG90IHF1ZSBub3MgbXVlc3RyYSBsb3MgcGVkaWRvcyBwb3IgY2xpZW50ZQpgYGB7cn0KCmRwMyA8LSBkcDIKZHAzJENMSUVOVEU8LWFzLmZhY3RvcihkcDMkQ0xJRU5URSkKZ2dwbG90KGRwMywgYWVzKHg9Q0xJRU5URSwgeT1QZWRpZG9zKSkgKyAKICBnZW9tX2JveHBsb3QoY29sb3I9InJlZCIsIGZpbGw9Im9yYW5nZSIsIGFscGhhPTAuMikKCmBgYAoKIyMjIyMgRW4gZWwgZ3LDoWZpY28gYW50ZXJpb3IgcG9kZW1vcyBvYnNlcnZhciBhIGxvcyA2IGNsaWVudGVzIGNvbiBtYXlvciBwcmVzZW5jaWEgZW4gRk9STSBlbiBjdWFudG8gYSBEZWxpdmVyeSBQbGFuIGVuIGRvbmRlIGVsIG9iamV0aXZvIGVzIHZlciBsYSBkaXNwZXJzacOzbiB5IGxhIGRpc3RyaWJ1Y2nDs24gZW50cmUgY2FkYSB1bm8geSByZXNwZWN0byBhIGxvcyBwcm9uw7NzdGljb3MgaW5kaXZpZHVhbGVzLiAgICAgIAoKIyMjIyMgRWwgY2xpZW50ZSBIRUxMQSBlcyBlbCBjbGllbnRlIGNvbiB1bmEgbWF5b3IgZGlzdHJpYnVjacOzbiB5IGRpc3BlcnNpw7NuIHkgdW5hIG1lZGlhbmEgcXVlIGdlbmVyYSB1bmEgZGVzdmlhY2nDs24gZXN0w6FuZGFyIHBvc2l0aXZhLiBWYXJyb2MgeSBUUk1YIHRpZW5lbiB0YW1iacOpbiB1bmEgZGlzdHJpYnVjacOzbiBtYXlvciBhbCB0ZW5lciBsYSBib3hwbG90IG3DoXMgZ3JhbmRlLCBtaWVudHJhcyBxdWUgbG9zIGRlbcOhczsgREVOU08sIFNUQjMgeSBZRlRPIHRpZW5lbiBsYSBtYXlvcsOtYSBkZSBzdXMgcGVkaWRvcyBlbiB1biBtaXNtbyByYW5nbyBjb24gcGVxdWXDsW9zIGRhdG9zIGZ1ZXJhIGRlbCBib3hwbG90IHByZXNlbnRhbmRvIGFsZ3Vub3Mgd2FybmluZ3MuICAgICAKCiMjIyMjIFNlIHB1ZWRlIGNvbmNsdWlyLCBxdWUgSEVMTEEgZXMgZWwgY2xpZW50ZSBtw6FzIGZ1ZXJ0ZSBlbiBkaWNoYSBiYXNlIGRlIGRhdG9zIHBhcmEgbGEgZW1wcmVzYS4gICAgIAoKIyMjIFRpbWUgc2VyaWVzIHBsb3RzIAoKIyMjIyAqKkRJU1RSSUJVQ0nDk04qKiAKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGJkX2RlbGl2ZXJ5X3BlcmYzLGFlcyh4PWZlY2hhLCB5PWRlbGF5X3BlcmZvcm1hbmNlLGNvbG9yPWNsaWVudGUpKSsKICBnZW9tX2xpbmUoKSsKICBsYWJzKHg9IkZlY2hhIix5PSJSZXRyYXNvIGVuIE1pbnV0b3MiLCBjb2xvcj0iTGVnZW5kIikrCiAgZ2d0aXRsZSgiUmV0cmFzb3MgZW4gZWwgZGVzZW1wZcOxbyBwb3IgcGFydGUgZGVsIGNsaWVudGUiKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmJkX2RlbGl2ZXJ5X3BlcmYzPC1iZF9kZWxpdmVyeV9wZXJmM1tiZF9kZWxpdmVyeV9wZXJmMyRjbGllbnRlIT0iTWFnbmEiLF0KYmRfZGVsaXZlcnlfcGVyZjM8LWJkX2RlbGl2ZXJ5X3BlcmYzW2JkX2RlbGl2ZXJ5X3BlcmYzJGNsaWVudGUhPSJWYXJyb2MiLF0KCmdncGxvdChiZF9kZWxpdmVyeV9wZXJmMyxhZXMoeD1mZWNoYSwgeT1kZWxheV9wZXJmb3JtYW5jZSxmaWxsPWNsaWVudGUpKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0zMyxsaW5ldHlwZT0iZGFzaGVkIixjb2xvcj0iYmxhY2siKSsKICBsYWJzKHg9IkZlY2hhIix5PSJSZXRyYXNvIGVuIG1pbnV0b3MiLCBjb2xvcj0iTGVnZW5kIikrCiAgZ2d0aXRsZSgiUmV0cmFzb3MgZW4gZWwgZGVzZW1wZcOxbyBwb3IgcGFydGUgZGVsIGNsaWVudGUiKQpgYGAKCiMjIyMjIEEgcGVzYXIgZGUgcXVlIGVzdGEgZGltaW51dGVuZG8gZWwgcmV0cmFzbyBjb24gZWwgY2xpZW50ZSBNYWhsZSBzZWd1aW1vcyB2aWVuZG8gcXVlIHNlIGVuY3VlbnRyYSBwb3IgYXJyaWJhIGRlbCBwcm9tZWRpby4gICAgCgojIyMgSGFsbGF6Z29zCgoxLiBOdWVzdHJvIHRvcCAzIGNsaWVudGVzIGRlIHByb2R1Y2Npw7NuIHNvbiBTVEFCSUxVUyAxLCBTVEFCSUxVUyAzIHkgVFJNWC4KCjIuIFRyYWVtb3MgdW4gcmV0cmFzbyBtYXlvciBlbiBkaXN0cmlidWNpw7NuIGNvbiBlbCBjbGllbnRlIE1haGxlLCBhcnJpYmEgZGVsIHByb21lZGlvIGxsZWdhbmRvIGluY2x1c28gYSB0aWVtcG9zIGRlIDEgaG9yYSBjb24gNDAgbWludXRvcy4KCjMuIFNlIHRpZW5lbiBzb2JyZXBlZGlkb3MgKGFycmliYSBkZWwgcHJvbWVkaW8pIHkgZXN0byBwdWVkZSBhZmVjdGFyIHNpIG5vIHNlIHRpZW5lbiBsYSBjYXBhY2lkYWQgcGFyYSByZWNpYmlyIHBlZGlkb3MgZGUgbcOhcy4gIAoKNC4gRGVudHJvIGRlIFJIIHRlbmVtb3MgbcOhcyBiYWphcyBwb3IgZGlzdGludG9zIG1vdGl2b3M6IGVuIHByaW1lciBsdWdhciBlc3RhIHBvciBKdWJpbGFjacOzbiwgZW4gc2VndW5kbyBsdWdhciBSZW51bmNpYSB2b2x1bnRhcmlhIHkgZW4gdGVyY2VyIGx1Z2FyIEJhamEgcG9yIEZhbHRhcy4KCgojIFByZWRpY2Npw7NuIGRlbCBEZXNlbXBlw7FvIGRlIGxhIEluZHVzdHJpYSBBdXRvbW90cml6ICAKClNlIGNhbWJpYW4gbG9zIG5vbWJyZXMgZGUgbGFzIGNvbHVtbmFzLiAKYGBge3J9Cm5hbWVzIChiYXNlKSA9IGMoImHDsW8iLCAicHJvZF90b3RhbCIsICJwcm9kX3Bhc3NlbmdlciIsICJwcm9kX3ZlaF9jb21lcmNpYWxlcyIsICJ2ZW50YXNfZG9tZXN0aWNhcyIsICJ2ZW50YXNfcGFzc2VuZ2VyIiwidmVudGFzX2NvbWVyY2lhbGVzIiwiZGVzZW1wbGVvX3VzYSIsImNvbmZpYW56YV9jb25zX3VzYSIsInNhbGFyaW9faG9yYV9taW5fdXNhIikKbmFtZXMgKGJhc2UpCnN0cihiYXNlKQpgYGAKCiMjIyAqKlByaW1lciBtb2RlbG8gZGUgcmVncmVzacOzbioqCkVuIGVzdGUgY2Fzbywgc2UgZXNjb2dlIGNvbW8gdmFyaWFibGUgZGVwZW5kaWVudGUgbGFzIHZlbnRhcyBkZSBsb3MgY2Fycm9zICpwYXNzZW5nZXIqLCBwb3IgZWxsbyBlbnRpw6luZGFzZSBsb3MgYXV0b23Ds3ZpbGVzIGRlIHVzbyBjb3RpZGlhbm8gZW4gRXN0YWRvcyBVbmlkb3MuIFBhcmEgZXN0YSB2YXJpYWJsZSBkZXBlbmRpZW50ZSwgc2UgaGFuIHRvbWFkbyBsYXMgc2lndWllbnRlcyB2YXJpYWJsZXMgaW5kZXBlbmRpZW50ZXMsIGNvbiBlbCBmaW4gZGUgbm90YXIgc3UgZWZlY3RvIGVuIGxhcyB2ZW50YXMuIEVzdGFzIHNvbjogIAoKMS4gRGVzZW1wbGVvIFVTQTogZXN0ZSDDrW5kaWNlIGVzIGNhbGN1bGFkbyBhbnVhbG1lbnRlIGNvbiBsYSBmb3JtdWxhLiAoVW5lbXBsb3llZCDDtyBMYWJvciBGb3JjZSkgeCAxMDAuIEVudHJlIG1lbm9yIG1lam9yLiAKCjIuIENvbmZpYW56YSBkZWwgY29uc3VtaWRvciBkZSBVU0E6IMOtbmRpY2UgcXVlIG1pZGUsIGEgcGFydGlyIGRlIHVuYSBlbmN1ZXN0YSBxdWUgdGFuIG9wdGltaXN0YXMgbyBwZXNpbWlzdGFzIHNlIGVuY3VlbnRyYW4gbG9zIGNvbnN1bWlkb3JlcyBzb2JyZSBzdSBzaXR1YWNpw7NuIGZpbmFuY2llcmEuIEVudHJlIG1heW9yLCBtZWpvci4gCgozLiBTYWxhcmlvIG3DrW5pbW8gcG9yIGhvcmE6IHNlIG1pZGUgZW4gZMOzbGFyZXMuIEVzdMOhIGVzdGFibGVjaWRvIGEgbml2ZWwgZmVkZXJhbC4gCgo0LiBBw7FvOiBsb3MgYcOxb3MgcXVlIHNlIHRpZW5lbiBkZSBsb3MgZGF0b3MsIDIwMDctMjAyMC4gCgoKYGBge3J9CnJlZ3Jlc2lvbjEgPC0gbG0gKHZlbnRhc19wYXNzZW5nZXIgfiBkZXNlbXBsZW9fdXNhICsgY29uZmlhbnphX2NvbnNfdXNhICsgc2FsYXJpb19ob3JhX21pbl91c2EgKyBhw7FvLCBkYXRhPWJhc2UpCnN1bW1hcnkgKHJlZ3Jlc2lvbjEpCmBgYApQYXJhIGxhIHRhc2EgZGUgZGVzZW1wbGVvIHkgZWwgw61uZGljZSBkZSBjb25maWFuemEgZGVsIGNvbnN1bWlkb3IsIHNlIGhhIGRlY2lkaWRvIHRvbWFyIGVsICpwcm9tZWRpbyogZGVsIDIwMDcgYWwgMjAyMCwgcGFyYSBwb2RlciBwcmVkZWNpci4gQ29uIGVsIHNhbGFyaW8gbcOtbmltbyBwb3IgaG9yYSwgYWwgc2VyIGVzdGFibGVjaWRvIGEgbml2ZWwgZmVkZXJhbCwgc2UgdG9tYSBlbiBjdWVudGEgbGEgw7psdGltYSBjYW50aWRhZDogJDcuMjUgZMOzbGFyZXMuIFNlIHF1aWVyZW4gbGFzIHByZWRpY2Npb25lcyBwYXJhIGxvcyBzaWd1aWVudGVzIGNpbmNvIGHDsW9zLCBhIHBhcnRpciBkZWwgw7psdGltbyBhw7FvIGNvbiBkYXRvcyAoMjAyMCkuCgpgYGB7cn0KZGF0b3NfbnVldm9zMSA8LSBkYXRhLmZyYW1lKGRlc2VtcGxlb191c2E9Ni40Myxjb25maWFuemFfY29uc191c2E9ODIuMyxzYWxhcmlvX2hvcmFfbWluX3VzYT03LjI1LGHDsW89MjAyMToyMDI1KQpwcmVkaWN0KHJlZ3Jlc2lvbjEsZGF0b3NfbnVldm9zMSkKYGBgCgoqKsK/UXXDqSBvYnNlcnZhbW9zPyoqCgpgYGB7cn0KcHJpbWVyIDwtIHBsb3QocHJlZGljdChyZWdyZXNpb24xLGRhdG9zX251ZXZvczEpLCB0eXBlID0gImwiLCB4bGFiID0gIkHDsW8iLCAgeWxhYiA9IlZlbnRhcyBQYXNzZW5nZXIiLCAgbWFpbj0iUHJlZGljY2nDs24gZGUgVmVudGFzIikKYGBgCgpFbiBlc3RhIHByZWRpY2Npw7NuIGRlIHZlbnRhcyBkZSBhdXRvbcOzdmlsZXMgKnBhc3NlbmdlciosIG9ic2VydmFtb3MgcXVlIGVzIGhhY2lhIGFiYWpvLiBFcyBkZWNpciwgdG9tYW5kbyBlbiBjdWVudGEgdW5hIHRhc2EgZGUgZGVzZW1wbGVvICBkZSA2LjQzLCB1biDDrW5kaWNlIGRlIGNvbmZpYW56YSBkZSA4Mi4zIHkgZWwgc2FsYXJpbyBtw61uaW1vIHBvciBob3JhIGRlICQ3LjI1LCBzZSBlc3BlcmEgcXVlIGxhcyB2ZW50YXMgZGUgZXN0b3MgYXV0b23Ds3ZpbGVzICoqYmFqZW4qKiBlbiBFVUEgZGVsIDIwMjEgaGFzdGEgMjAyNS4gSWd1YWxtZW50ZSwgcmVzdWx0YSBkZXN0YWNhYmxlIG1lbmNpb25hciBxdWUgbGFzICB2YXJpYWJsZXMgcXVlIG3DoXMgaW1wYWN0YW4gZW4gbGFzIHZlbnRhcyBkZSBhdXRvbcOzdmlsZXMgKnBhc3Nlbmdlciogc29uIGVsIGHDsW8geSBlbCBzYWxhcmlvIG3DrW5pbW8uCgpgYGB7cn0KZWZmZWN0X3Bsb3QocmVncmVzaW9uMSxwcmVkPWRlc2VtcGxlb191c2EsaW50ZXJ2YWw9VFJVRSkKYGBgCgpTaSB0b21hbW9zIGVuIGN1ZW50YSBsYSB0YXNhIGRlIGRlc2VtcGxlbyBkZSBFVUEsIHkgc3UgcmVsYWNpw7NuIGNvbiBsYXMgdmVudGFzIGRlIGxvcyBhdXRvbcOzdmlsZXMgKnBhc3NlbmdlciosIG9ic2VydmFtb3MgcXVlIGVzdGEgZXMgbmVnYXRpdmEuIERlYmlkbyBhIHF1ZSBhbCBjcmVjZXIgbGEgdGFzYSBkZSBkZXNlbXBsZW8sIGJhamFuIGxhcyB2ZW50YXMuIAoKCmBgYHtyfQplZmZlY3RfcGxvdChyZWdyZXNpb24xLHByZWQ9Y29uZmlhbnphX2NvbnNfdXNhLGludGVydmFsPVRSVUUpCmBgYApNaWVudHJhcyBxdWUgZWwgw61uZGljZSBkZSBjb25maWFuemEgZGVsIGNvbnN1bWlkb3IgZGUgRVVBLCB5IHN1IHJlbGFjacOzbiBjb24gbGFzIHZlbnRhcyBkZSBsb3MgYXV0b23Ds3ZpbGVzICpwYXNzZW5nZXIqLCBvYnNlcnZhbW9zIHF1ZSBlc3RhIGVzIHBvc2l0aXZhLiBEZWJpZG8gYSBxdWUgYWwgY3JlY2VyIGxhIGNvbmZpYW56YSwgaW5jcmVtZW50YW4gbGFzIHZlbnRhcy4gCgoKYGBge3J9CmVmZmVjdF9wbG90KHJlZ3Jlc2lvbjEscHJlZD1zYWxhcmlvX2hvcmFfbWluX3VzYSxpbnRlcnZhbD1UUlVFKQpgYGAKCklndWFsbWVudGUsIGFsIHN1YmlyIGVsIHNhbGFyaW8gbcOtbmltbyBwb3IgaG9yYSwgbGFzIHZlbnRhcyBkZSBsb3MgYXV0b23Ds3ZpbGVzICpwYXNzZW5nZXIqIGluY3JlbWVudGFuLiAKCmBgYHtyfQplZmZlY3RfcGxvdChyZWdyZXNpb24xLHByZWQ9YcOxbyxpbnRlcnZhbD1UUlVFKQpgYGAKCkNvbiBlbCBwYXNhciBkZSBsb3MgYcOxb3MgbGFzIHZlbnRhcyBoYW4gZGVjcmVjaWRvLiAKCiMjIyAqKlNlZ3VuZG8gbW9kZWxvIGRlIHJlZ3Jlc2nDs24qKgpFbiBlc3RlIGNhc28sIHNlIGVzY29nZSBjb21vIHZhcmlhYmxlIGRlcGVuZGllbnRlIGxhcyB2ZW50YXMgZGUgbG9zIGNhcnJvcyAqY29tZXJjaWFsZXMqLCBwb3IgZWxsbyBlbnRpw6luZGFzZSBsb3MgY3VhbHF1aWVyIHRpcG8gZGUgdmVow61jdWxvIGRlIG1vdG9yIHV0aWxpemFkbyBwYXJhIHRyYW5zcG9ydGFyIG1lcmNhbmPDrWFzIG8gcGFzYWplcm9zIGVuIEVzdGFkb3MgVW5pZG9zLiBQYXJhIGVzdGEgdmFyaWFibGUgZGVwZW5kaWVudGUsIHNlIGhhbiB0b21hZG8gbGFzIHNpZ3VpZW50ZXMgdmFyaWFibGVzIGluZGVwZW5kaWVudGVzLCBjb24gZWwgZmluIGRlIG5vdGFyIHN1IGVmZWN0byBlbiBsYXMgdmVudGFzLiBFc3RhcyBzb246ICAKMS4gRGVzZW1wbGVvIFVTQTogZXN0ZSDDrW5kaWNlIGVzIGNhbGN1bGFkbyBhbnVhbG1lbnRlIGNvbiBsYSBmb3JtdWxhLiAoVW5lbXBsb3llZCDDtyBMYWJvciBGb3JjZSkgeCAxMDAuIEVudHJlIG1lbm9yIG1lam9yLiAgCjIuIENvbmZpYW56YSBkZWwgY29uc3VtaWRvciBkZSBVU0E6IMOtbmRpY2UgcXVlIG1pZGUsIGEgcGFydGlyIGRlIHVuYSBlbmN1ZXN0YSBxdWUgdGFuIG9wdGltaXN0YXMgbyBwZXNpbWlzdGFzIHNlIGVuY3VlbnRyYW4gbG9zIGNvbnN1bWlkb3JlcyBzb2JyZSBzdSBzaXR1YWNpw7NuIGZpbmFuY2llcmEuIEVudHJlIG1heW9yLCBtZWpvci4gIAozLiBTYWxhcmlvIG3DrW5pbW8gcG9yIGhvcmE6IHNlIG1pZGUgZW4gZMOzbGFyZXMuIEVzdMOhIGVzdGFibGVjaWRvIGEgbml2ZWwgZmVkZXJhbC4gIAo0LiBBw7FvOiBsb3MgYcOxb3MgcXVlIHNlIHRpZW5lbiBkZSBsb3MgZGF0b3MsIDIwMDctMjAyMC4KCgpgYGB7cn0KcmVncmVzaW9uMiA8LSBsbSAodmVudGFzX2NvbWVyY2lhbGVzIH4gZGVzZW1wbGVvX3VzYSArIGNvbmZpYW56YV9jb25zX3VzYSArIHNhbGFyaW9faG9yYV9taW5fdXNhICsgYcOxbywgZGF0YT1iYXNlKQpzdW1tYXJ5IChyZWdyZXNpb24yKQpgYGAKUGFyYSBsYSB0YXNhIGRlIGRlc2VtcGxlbyB5IGVsIMOtbmRpY2UgZGUgY29uZmlhbnphIGRlbCBjb25zdW1pZG9yLCBzZSBoYSBkZWNpZGlkbyB0b21hciBlbCAqcHJvbWVkaW8qIGRlbCAyMDA3IGFsIDIwMjAsIHBhcmEgcG9kZXIgcHJlZGVjaXIuIENvbiBlbCBzYWxhcmlvIG3DrW5pbW8gcG9yIGhvcmEsIGFsIHNlciBlc3RhYmxlY2lkbyBhIG5pdmVsIGZlZGVyYWwsIHNlIHRvbWEgZW4gY3VlbnRhIGxhIMO6bHRpbWEgY2FudGlkYWQ6ICQ3LjI1IGTDs2xhcmVzLiBTZSBxdWllcmVuIGxhcyBwcmVkaWNjaW9uZXMgcGFyYSBsb3Mgc2lndWllbnRlcyBjaW5jbyBhw7FvcywgYSBwYXJ0aXIgZGVsIMO6bHRpbW8gYcOxbyBjb24gZGF0b3MgKDIwMjApLgoKCmBgYHtyfQpkYXRvc19udWV2b3MyIDwtIGRhdGEuZnJhbWUoZGVzZW1wbGVvX3VzYT02LjQzLGNvbmZpYW56YV9jb25zX3VzYT04Mi4zLHNhbGFyaW9faG9yYV9taW5fdXNhPTcuMjUsYcOxbz0yMDIxOjIwMjUpCnByZWRpY3QocmVncmVzaW9uMixkYXRvc19udWV2b3MyKQpgYGAKCioqwr9RdcOpIG9ic2VydmFtb3M/KioKCmBgYHtyfQpzZWd1bmRvIDwtIHBsb3QocHJlZGljdChyZWdyZXNpb24yLGRhdG9zX251ZXZvczIpLCB0eXBlID0gImwiLCB4bGFiID0gIkHDsW8iLCAgeWxhYiA9IlZlbnRhcyBDb21lcmNpYWxlcyIsICBtYWluPSJQcmVkaWNjacOzbiBkZSBWZW50YXMiKQpgYGAKCkVuIGVzdGEgcHJlZGljY2nDs24gZGUgdmVudGFzIGRlIGF1dG9tw7N2aWxlcyAqY29tZXJjaWFsZXMqLCBvYnNlcnZhbW9zIHF1ZSBlcyBoYWNpYSBhcnJpYmEgRXMgZGVjaXIsIHRvbWFuZG8gZW4gY3VlbnRhIHVuYSB0YXNhIGRlIGRlc2VtcGxlbyAgZGUgNi40MywgdW4gw61uZGljZSBkZSBjb25maWFuemEgZGUgODIuMyB5IGVsIHNhbGFyaW8gbcOtbmltbyBwb3IgaG9yYSBkZSAkNy4yNSwgc2UgZXNwZXJhIHF1ZSBsYXMgdmVudGFzIGRlIGVzdG9zIGF1dG9tw7N2aWxlcyAqKnN1YmFuKiogZW4gRVVBIGRlbCAyMDIxIGhhc3RhIDIwMjUuIEVuIGVsIGNhc28gZGUgbGFzIHZlbnRhcyBkZSBhdXRvbcOzdmlsZXMgKmNvbWVyY2lhbGVzKiwgbm90YW1vcyBxdWUgZWwgcGFzYXIgZGUgbG9zIGHDsW9zIGVzIGxhIHZhcmlhYmxlIHF1ZSBtw6FzIGltcGFjdGEsIHNpZ3VpZW5kbyBwb3IgZWwgbml2ZWwgZGUgY29uZmlhbnphIGRlbCBjb25zdW1pZG9yIHkgZWwgc2FsYXJpbyBtw61uaW1vIHBvciBob3JhOyBtaWVudHJhcyBxdWUgZWwgcXVlIG1lbm9zIGFmZWN0YSBlcyBsYSB0YXNhIGRlIGRlc2VtcGxlby4gCgoKYGBge3J9CmVmZmVjdF9wbG90KHJlZ3Jlc2lvbjIscHJlZD1kZXNlbXBsZW9fdXNhLGludGVydmFsPVRSVUUpCmBgYAoKU2kgdG9tYW1vcyBlbiBjdWVudGEgbGEgdGFzYSBkZSBkZXNlbXBsZW8gZGUgRVVBLCB5IHN1IHJlbGFjacOzbiBjb24gbGFzIHZlbnRhcyBkZSBsb3MgYXV0b23Ds3ZpbGVzICpjb21lcmNpYWxlcyosIG9ic2VydmFtb3MgcXVlIGVzdGEgZXMgbmVnYXRpdmEuIERlYmlkbyBhIHF1ZSBhbCBjcmVjZXIgbGEgdGFzYSBkZSBkZXNlbXBsZW8sIGJhamFuIGxhcyB2ZW50YXMuIAoKCmBgYHtyfQplZmZlY3RfcGxvdChyZWdyZXNpb24yLHByZWQ9Y29uZmlhbnphX2NvbnNfdXNhLGludGVydmFsPVRSVUUpCmBgYAoKTWllbnRyYXMgcXVlIGVsIMOtbmRpY2UgZGUgY29uZmlhbnphIGRlbCBjb25zdW1pZG9yIGRlIEVVQSwgeSBzdSByZWxhY2nDs24gY29uIGxhcyB2ZW50YXMgZGUgbG9zIGF1dG9tw7N2aWxlcyAqY29tZXJjaWFsZXMqLCBvYnNlcnZhbW9zIHF1ZSBlc3RhIGVzIHBvc2l0aXZhLiBEZWJpZG8gYSBxdWUgYWwgY3JlY2VyIGxhIGNvbmZpYW56YSwgaW5jcmVtZW50YW4gbGFzIHZlbnRhcy4gQSBjb21wYXJhY2nDs24gZGUgbGEgZ3LDoWZpY2EgZGUgdmVudGFzICpwYXNzZW5nZXIqIGNvbiBlbCBuaXZlbCBkZSBjb25maWFuemEsIG9ic2VydmFtb3MgcXVlIGVuIGVzdGUgY2FzbyBsYSBwZW5kaWVudGUgZXMgbcOhcyBwcm9udW5jaWFkYSwgcG9yIGxvIHF1ZSB2ZW1vcyB1biBtYXlvciBpbXBhY3RvLiAKCgpgYGB7cn0KZWZmZWN0X3Bsb3QocmVncmVzaW9uMixwcmVkPXNhbGFyaW9faG9yYV9taW5fdXNhLGludGVydmFsPVRSVUUpCmBgYAoKSWd1YWxtZW50ZSwgYWwgc3ViaXIgZWwgc2FsYXJpbyBtw61uaW1vIHBvciBob3JhLCBsYXMgdmVudGFzIGRlIGxvcyBhdXRvbcOzdmlsZXMgKmNvbWVyY2lhbGVzKiBkaXNtaW51eWVuLiBFc3RlIHBvZHLDrWEgc2VyIHVuIHRlbWEgaW50ZXJlc2FudGUgYSBpbnZlc3RpZ2FyLiAKCgpgYGB7cn0KZWZmZWN0X3Bsb3QocmVncmVzaW9uMixwcmVkPWHDsW8saW50ZXJ2YWw9VFJVRSkKYGBgCgpDb24gZWwgcGFzYXIgZGUgbG9zIGHDsW9zIGxhcyB2ZW50YXMgaGFuIGluY3JlbWVudGFkby4gCgoKIyBQcm9uw7NzdGljbyBkZWwgRGVzZW1wZcOxbyBkZSBsYSBJbmR1c3RyaWEgQXV0b21vdHJpeiB5IGxhIGVtcHJlc2EgRk9STSAgCgojIyMgKipQcm9uw7NzdGljbyBJbmR1c3RyaWEgQXV0b21vdHJpeioqCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3QoYmRfZXh0ZXJuYSRZZWFyLGJkX2V4dGVybmEkUHJvZHVjdGlvbl9Db21tZXJjaWFsX1ZlaGljbGVzLCB0eXBlPSJsIixjb2w9ImJsdWUiLCBsd2Q9MS41LCB4bGFiID0iWWVhciIseWxhYiA9IlRob3VzYW5kcyBvZiBVbml0cyIsIG1haW4gPSAiQW5udWFsIFUuUy4gTW90b3IgVmVoaWNsZSBTYWxlcyIpCmxpbmVzKGJkX2V4dGVybmEkWWVhcixiZF9leHRlcm5hJFNhbGVzX0NvbW1lcmNpYWxfVmVoaWNsZXMsY29sPSJyZWQiLGx0eT0zKQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQ9YygiRG9tZXN0aWMgQ29tbWVyY2lhbCBTYWxlcyIsICJQcm9kdWN0aW9uIENvbW1lcmNpYWwgVmVoaWNsZXMiKSwKICAgICAgIGNvbD1jKCJibHVlIiwgInJlZCIpLCBsdHkgPSAxOjIsIGNleD0wLjgpCmBgYAoKIyMjIyBQcm9uw7NzdGljbyBNb3ZpbmcgQXZlcmFnZSAKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc3VtbWFyeShtYV9tb2RlbDwtYXJtYShiZF9leHRlcm5hJFRvdGFsX1Byb2R1Y3Rpb24sb3JkZXI9YygwLDEpKSkKbWFfbW9kZWxfZm9yZWNhc3Q8LWZvcmVjYXN0KG1hX21vZGVsJGZpdHRlZCxoPTMsbGV2ZWw9Yyg5NSkpCm1hX21vZGVsX2ZvcmVjYXN0CmBgYAoKIyMjICoqUHJvbsOzc3RpY28gUHJvZHVjY2nDs24gRk9STSoqCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3QoZGF0YTYkRmVjaGEsZGF0YTYkUElFWkFTLlBST0cuLCB0eXBlPSJsIixjb2w9ImJsdWUiLCBsd2Q9MS41LCB4bGFiID0iRmVjaGEiLHlsYWIgPSJQaWV6YXMgcHJvZ3JhbWFkYXMiLCBtYWluID0gIlBpZXphcyBwcm9ncmFtYWRhcyBwb3IgZmVjaGEiKQpsaW5lcyhkYXRhNiRGZWNoYSxkYXRhNiRMYW1pbmFzLnByb2Nlc2FkYXMsY29sPSJyZWQiLGx0eT0zKQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQ9YygiUGllemFzIHByb2dyYW1hZGFzIiwgIkxhbWluYXMgcHJvY2VzYWRhcyIpLAogICAgICAgY29sPWMoImJsdWUiLCAicmVkIiksIGx0eSA9IDE6MiwgY2V4PTAuOCkKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoobWFfbW9kZWw8LWFybWEoZGF0YTYkUElFWkFTLlBST0cuLG9yZGVyPWMoMCwxKSkpCm1hX21vZGVsX2ZvcmVjYXN0PC1mb3JlY2FzdChtYV9tb2RlbCRmaXR0ZWQsaD0zLGxldmVsPWMoOTUpKQptYV9tb2RlbF9mb3JlY2FzdApgYGAKCiMjIyAqKlByb27Ds3N0aWNvIE1lcm1hIEZPUk0qKgoKYGBge3J9CiMgU3VtYXIgZWwgVG90YWwgZGUgS2lsb3N4TWVzCm1lcm1hIDwtIGMoMTQ1NjAsMjI4MzAsMjI0NzAsMTg4MjAsMjM0MTAsMTgyODAsMTkzNzAsMzIxMDAsMTM1ODYpCgptZXJtYV9zdCA8LSB0cyhkYXRhID0gbWVybWEsIHN0YXJ0ID0gYygyMDIyLDEpLCBmcmVxdWVuY3kgPSAxMikKbWVybWFfc3QKYGBgCgpgYGB7cn0KbW9kZWxvIDwtIGF1dG8uYXJpbWEobWVybWFfc3QpCm1vZGVsbwoKcHJvbm9zdGljbyA8LSBmb3JlY2FzdChtb2RlbG8sIGxldmVsPWMoOTUpLCBoPTMpCnByb25vc3RpY28KcGxvdChwcm9ub3N0aWNvKQpgYGAKCgojIyMgUmVzdWx0YWRvczogwr9DdcOhbCBlcyBsYSB0ZW5kZW5jaWE/CgpQb2RlbW9zIHZlciBxdWUgZW4gbGEgaW5kdXN0cmlhIEF1dG9tb3RyaXogZGUgVVNBLCBlc3BlY8OtZmljYW1lbnRlIGVuIHZlbnRhcyBkZSBtb3RvcmVzLCB0ZW5lbW9zIHVuYSB0ZW5kZW5jaWEgY29udGludWEgeSBxdWUgbnVlc3Ryb3MgaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgYmFuIGRpc21pbnV5ZW5kbywgcGVybyBsYXMgcHJlZGljY2lvbmVzIHNlIGVuY3VlbnRyYW4gZW50cmUgODMxNS43MzItMTI1OTUuNjEgZGUgdmVudGFzIGFudWFsZXMgZGUgbW90b3JlcyBlbiBVU0EgcGFyYSBsb3MgcHLDs3hpbW9zIGHDsW9zLgoKUGFyYSBGb3JtIGFsIGRlc2Fycm9sbGFyIGVsIHByb27Ds3N0aWNvIGRlIE1lcm1hIHZlbW9zIHF1ZSB0ZW5lbW9zIHF1ZSBwYXJhIGxvcyBwcsOzeGltb3MgcGVyaW9kb3MgZGUgb2N0dWJyZSwgbm92aWVtYnJlIHkgZGljaWVtYnJlIHRlbmRyZW1vcyB1bmEgY2FudGlkYWQgY29uc3RhbnRlIGRlIDIwNjAyLjg5IGtpbG9zIGRlIG1lcm1hIHkgcXVlIG51ZXN0cm8gaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBjYWUgZW50cmUgOTc3MC43MTEgYSAzMTQzNS4wNy5JbnRlcnByZXRhbmRvIGxhIGluZm9ybWFjacOzbiB2ZW1vcyBxdWUgYSBjb21wYXJhY2nDs24gZGVsIMO6bHRpbW8gbWVzIGRlIHNlcHRpZW1icmUsIGxvcyBraWxvcyBjcmVjZXLDoW4uCgojIElkZW50aWZpY2FjacOzbiB5IGRlc2NyaXBjacOzbiBkZSBQcmluY2lwYWxlcyBSZXN1bHRhZG9zIFJlbGV2YW50ZXMgKEluc2lnaHRzKSAKCioJQ29tbyBwb2RlbW9zIG9ic2VydmFyIGVuIGxhIGJhc2UgZGUgZGF0b3MgZGUgUHJvZHVjY2nDs24sIGVsIG1heW9yIGNsaWVudGUgZGUgRm9ybSwgZW4gY3Vlc3Rpw7NuIGRlIGxhbWluYXMgcHJvY2VzYWRhcywgZXMgU3RhYmlsdXMgMSwgYXPDrSBzZSBtdWVzdHJhIGVuIGxhIGdyYWZpY2EgZGUgcGFzdGVsIGRlIGVtcHJlc2EsIG1pZW50cmFzIHF1ZSB0YW1iacOpbiBjdWVudGEgY29uIGFsZ3Vub3MgY2xpZW50ZXMgY29uIG11eSBwb2NhIHByb2R1Y2Npw7NuIGNvbW8gZXMgZWwgY2FzbyBkZSBWTC0wMTctMTQ5ODkuIAoKKglFbiBsYSBiYXNlIGRlIGRhdG9zIFNjcmFwLCBjb24gbGFzIGdyYWZpY2FzIHF1ZSBlbGFib3JhbW9zLCBwb2RlbW9zIG9ic2VydmFyIHF1ZSBlbCBtYXlvciBudW1lcm8gZGUgZGVzZWNobyBzZSBvcmlnaW5hIGVuIGVsIMOhcmVhIGRlIGxhIGVtcHJlc2EgZGUgUHJlLVByb2R1Y2Npw7NuLCBwb3IgbG8gcXVlIHBvZGVtb3MgZW5mb3JjYXJub3MgZW4gcHJvcG9uZXIgZXN0cmF0ZWdpYXMgcXVlIHJlZHV6Y2FuIGVsIG51bWVybyBkZSBkZXNlY2hvIHNpZ25pZmljYXRpdmFtZW50ZSBlbiBlc3RhIMOhcmVhLCBhc8OtIGNvbW8gdGFtYmnDqW4gZW4gZWwgw6FyZWEgZG9uZGUgbWVub3MgaGF5IGRlc2VjaG8gZXMgZW4gUG9zdC1wcm9kdWNjacOzbi4gCgoqCUVuIGVsIMOhcmVhIGRlIHJlY3Vyc29zIGh1bWFub3MgcG9kZW1vcyBpbnRlcnByZXRhciBjb24gbGFzIGdyYWZpY2FzIHF1ZSBlbiBGb3JtLCBoYXkgdW4gbWF5b3IgcmFuZ28gZGUgZWRhZCBlbnRyZSBsYXMgbXVqZXJlcywgYXPDrSBjb21vIHRhbWJpw6luIHBvZGVtb3Mgb2JzZXJ2YXIgcXVlIGxhcyBtdWplcmVzIGVuIHByb21lZGlvIGdhbmFuIG3DoXMgcXVlIGxvcyBob21icmVzLiAgCgoqCUVuIGN1ZXN0acOzbiBhIGxhcyBiYWphcywgZWwgYW7DoWxpc2lzIGRlIGxhIGJhc2UgZGUgZGF0b3Mgbm9zIGFycm9qYSBxdWUgZXhpc3RlIHVuYSBncmFuIHJvdGFjacOzbiBkZSBwZXJzb25hbCwgeSBsYSBtYXlvcsOtYSBkZSBlbGxvcyBubyBoYW4gYWxjYW56YWRvIGVsIGdyYWRvIGRlIGp1YmlsYWNpw7NuLCBsYXMgcmF6b25lcyBwcmluY2lwYWxlcyBkZSBlc3RlIHNvbiBhYmFuZG9ubyB5IGJhamEgcG9yIGZhbHRhcy4gRW4gYmFzZSBhIGxhIGdyYWZpY2EgZGUgYmFycmFzIGV4cGxpY2FkYSBlbiBsYSBwYXJ0ZSBkZSBiYWphcywgc2UgbWVuY2lvbmEgcXVlIGxhIG1heW9yw61hIGRlIGxhcyBwZXJzb25hcyBxdWUgYWJhbmRvbmFuIHN1IHRyYWJham8gc29uIHNvbHRlcmFzLCBhc8OtIGNvbW8gdGFtYmnDqW4gYWxndW5hcyBkZSBlbGxhcyBubyBzZSBjb25vY2Ugc3UgZXN0YWRvIGNpdmlsLiAgCgoqCUVuIGxhcyBwcmVkaWNjaW9uZXMgZGUgZGVzZW1wZcOxbyBkZSBsYSBpbmR1c3RyaWEgYXV0b21vdHJpeiBzZSBwdWRvIG9ic2VydmFyIHF1ZSBlbCBhdXRvbcOzdmlsIGRlIG1vZGVsbyBQYXNzZW5nZXIgc2UgZW5jdWVudHJhIGVuIGRlY3JlbWVudG8sIHRvbWFuZG8gY29tbyBiYXNlIGxvcyBkYXRvcyBkZSBsYSB0YXNhIGRlIGRlc2VtcGxlbyBkZSA2LjQzIHkgdW4gw61uZGljZSBkZSBjb25maWFuemEgZGUgODIuMywgc2UgZXNwZXJhIHF1ZSBzaWdhIGVsIGRlY3JlbWVudG8gZGUgZXN0b3MgYXV0b23Ds3ZpbGVzIGVuIEVVQSBkZWwgMjAyMSBhbCAyMDI1LiBNaWVudHJhcyBxdWUgZW4gZWwgc2VndW5kbyBtb2RlbG8gZGUgcmVncmVzacOzbiBjb24gbGEgbWlzbWEgYmFzZSBkZSBkYXRvcyBzZSBlc3BlcmEgdW5hIHByZWRpY2Npw7NuIGRlIHZlbnRhcyBwb3NpdGl2YSBlbiBsb3MgYXV0b23Ds3ZpbGVzIGNvbWVyY2lhbGVzLCB0b21hbmRvIGVuIGN1ZW50YSBkYXRvcyBjb21vIHRhc2EgZGUgZGVzZW1wbGVvIGRlIDYuNDMsIHVuIMOtbmRpY2UgZGUgY29uZmlhbnphIGRlIDgyLjMsIGVzIGluY3JlbWVudG8gc2UgZXNwZXJhIGRlbCAyMDIxIGFsIDIwMjUuICAKCiMgUmVmbGV4acOzbiBGaW5hbApCdXNpbmVzcyBBbmFseXRpY3MgZXMgdW4gZW5mb3F1ZSBkZSBhbsOhbGlzaXMgZGUgZGF0b3MgZGVudHJvIGRlIGFsZ3VuYSBlbXByZXNhLCBjb25zaXN0ZSBlbiBsbGV2YXIgYSBjYWJvIHNvbHVjaW9uZXMgcGFyYSBzYXRpc2ZhY2VyIGxhcyBuZWNlc2lkYWRlcyBkZSB1biBuZWdvY2lvLCBsb2dyYXIgbWV0YXMgeSBhbGNhbnphciBsb3Mgb2JqZXRpdm9zIHBsYW50ZWFkb3MuIEJBIHNlIGNvbXBvbmUgZGUgb2J0ZW5lciBkYXRvcywgYW5hbGl6YXIgeSBtb3N0cmFyIGRhdG9zIGRlIG1hbmVyYSB2aXN1YWwsIGF5dWRhIGVuIHRvbWFyIGRlY2lzaW9uZXMgYmFzYWRvIGVuIHRlbmRlbmNpYXMgeSBsbyBxdWUgZXN0w6EgcGFzYW5kbyBlbiBlbCBtZXJjYWRvIGVuIGdlbmVyYWwuICAKCioJQnVzaW5lc3MgQW5hbHl0aWNzIGF5dWRhIGEgYWxjYW56YXIgbG9zIG9iamV0aXZvcyBlbXByZXNhcmlhbGVzIGEgcGFydGlyIGRlIHVuIGFuw6FsaXNpcyBkZSBncmFuZGVzIHZvbMO6bWVuZXMgZGUgZGF0b3MgbWVkaWFudGUgaGVycmFtaWVudGFzIGNvbW8gbG9zIGVzIFJTdHVkaW8sIFBoeXRvbiwgZW50cmUgb3Ryb3MuICAKCioJQkEgZGV0ZWN0YSB0ZW5kZW5jaWFzIGNvbmZvcm1lIGFsIHRpZW1wbyB5IHB1ZWRlIHJlYWxpemFyIHByb27Ds3N0aWNvcyBhIHBhcnRpciBkZSBtb2RlbG9zIHByZWRpY3Rpdm9zLiAgCgoqCUJBIHV0aWxpemEgbW9kZWxvcyBwcmVkaWN0aXZvcyBwYXJhIG9wdGltaXphciBsb3MgcHJvY2Vzb3MgZGUgdW5hIGVtcHJlc2EgZW4gY3VhbHF1aWVyIMOhcmVhIGNvbW8gcHJvZHVjY2nDs24sIGxvZ8Otc3RpY2EsIHJlY3Vyc29zIGh1bWFub3MgZW50cmUgb3Ryb3MuICAKCkJ1c2luZXNzIEludGVsbGlnZW5jZSBzZSB1dGlsaXphIHBhcmEgZXZhbHVhciwgb3B0aW1pemFyIHkgY29vcmRpbmFyIGxhcyBvcGVyYWNpb25lcyBpbnRlcm5hcyBkZSB1bmEgZW1wcmVzYSwgbWllbnRyYXMgcXVlIEJ1c2luZXNzIEFuYWx5dGljcyBlcyBvYnRlbmVyIGRhdG9zLCBhbmFsaXphcmxvcyB5IG1vc3RyYXJsb3MuIEV4aXN0ZSBkaWZlcmVuY2lhcyBlbnRyZXMgZXN0b3MgZG9zLCBsYSBtYXlvciBkaWZlcmVuY2lhIGVzIGVuIGxhIHBvcmFjdGljYSBkZSB1dGlsaXphciBsb3MgZGF0b3MgZGUgdW5hIGVtcHJlc2EgcGFyYSBhbnRpY2lwYXIgdGVuZGVuY2lhcyB5IHJlc3VsdGFkb3MuIEJ1c2luZXNzIEFuYWx5dGljcyBheXVkYSBlbiB0b21hciBkZWNpc2lvbmVzIGJhc2FkbyBlbiB0ZW5kZW5jaWFzIHkgbG8gcXVlIGVzdMOhIHBhc2FuZG8gZW4gZWwgbWVyY2FkbyBlbiBnZW5lcmFsLiAgCg==