Por: Lesly Darian Romero Vazquez - A01771127

Introducción

i) ¿Qué es un análisis exploratorio de los datos?

El análisis exploratorio de los datos (EDA, por sus siglas en inglés) es un enfoque en estadística que se enfoca en inspeccionar, limpiar y modelar conjuntos de datos con el objetivo de descubrir patrones, anomalías, tendencias y relaciones entre variables, que no se habrían identificado mediante métodos estadísticos formales. Este tipo de análisis es fundamental en la fase preliminar de cualquier proyecto de datos y se utiliza ampliamente antes de realizar inferencias estadísticas más complejas o construir modelos predictivos.

El EDA es fundamentalmente visual y descriptivo, empleando una variedad de técnicas gráficas y cuantitativas para analizar los datos. Entre las herramientas más comunes se encuentran los histogramas, diagramas de dispersión, gráficos de caja y bigotes (box plots), y mapas de calor, los cuales permiten a los analistas y científicos de datos observar las distribuciones y relaciones de las variables de manera intuitiva. Además, el EDA involucra el uso de estadísticas descriptivas, como la media, mediana, moda, varianza, y correlación para resumir las características principales de los conjuntos de datos.

Una parte crucial del EDA es la limpieza de datos, que incluye la identificación y manejo de valores atípicos, datos faltantes y errores de entrada, asegurando así la calidad y fiabilidad de los análisis posteriores. El EDA también puede implicar la transformación de datos, donde se modifican o se crean nuevas variables para facilitar el análisis.

ii) ¿Cómo contribuye el análisis exploratorio de los datos a mejorar el proceso y los resultados de analítica descriptiva?

El análisis exploratorio de los datos contribuye significativamente a mejorar tanto el proceso como los resultados de la analítica descriptiva de varias maneras:

  1. Identificación de características clave
  2. Mejora de la calidad de los datos
  3. Descubrimiento de patrones y relaciones
  4. Selección de variables relevantes
  5. Diseño de modelos más efectivos
  6. Facilitación de la comunicación

Antecedentes de la Empresa FORM

Visión

En 2033 seremos una de las cinco mejores compañías de México que generan valor dentro de la cadena de suministro de las industrias que más valoran la forma en la que se protegen y trasladan las cosas.

Misión

Transformar nuestro entorno y resolver retos industriales de nuestros clientes a través de la colaboración, provocando nuevas oportunidades que potencian nuestro modelo de negocio, para alcanzar nuestros ideales.

Contexto de la Industria

Industria de autopartes

** La producción de vehículos y autopartes en USA es muy centralizada, frente a un mercado mexicano que esta más diluido. ** Importante barrera de entrada para el resto de organizaciones que buscan competir en este mercado. ** Siguen distintas tendencias comerciales.

Industria de Cartón y Autos

** Industria de de productos de cartón y papel esta en una tendencia creciente. ** Exportaciones de Autos en México parece tener estacionalidad. ** Se espera que para el primer trimestre del 2024 haya un incremento en exportaciones.

FODA

Estrategias FODA Cruzado

PESTLE

Factores PESTLE

Situación Problema 1: Clima Laboral

Los principales factores del clima organizacional de FORM que propician la satisfacción y/o no satisfacción de trabajar en dicha empresa.

RH

Preguntas de Análisis del Clima Laboral

  • ¿Cuáles son las limitaciones, dolores, o impedimentos más comúnes dentro de los trabajadores de FORM?
  • ¿Cómo varían las opiniones sobre el trabajo según el género de los encuestados?
  • ¿Cuáles son los sentimientos y satisfacciones laborales que reportan los empleados?
  • ¿Cuál es el perfil del trabajador que sufre más acoso en el área de trabajo/empresa?

Librerías

library(syuzhet)
library(tm)
library(wordcloud)
library(ggplot2)
library(dplyr)
library(readr)
library(naniar)         
library(RColorBrewer)  
library(regclass)       
library(mctest)         
library(lmtest)         
library(caret)          
library(e1071)          
library(SparseM)        
library(Metrics)       
library(jtools)         
library(DiagrammeR)     
library(effects)        
library(scales)
library(DataExplorer)
library(corrr)
library(tidyverse)
library(readxl)
library(gmodels)
library(gridExtra)
library(readtext)
library(dlookr)

Limpieza y Organización de la base de datos

df <- read_xlsx("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\BD_FORM.xlsx")
df1 <- read.csv("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\Datos_FORM_RH.csv")
# Visualizar estructura interna del data frame
str(df)
## tibble [106 × 22] (S3: tbl_df/tbl/data.frame)
##  $ id                  : num [1:106] 1 2 3 4 5 6 7 8 9 10 ...
##  $ puesto_trabajo      : chr [1:106] "Administrativo" "Costurera" "Ayudante general" "Ayudante general" ...
##  $ antiguedad          : num [1:106] 9 36 4 2 1 36 36 36 36 1 ...
##  $ razon_trabajo       : chr [1:106] "Por el salario" "Otro" "Ubicación de la empresa" "Ubicación de la empresa" ...
##  $ salario             : chr [1:106] "Totalmente de acuerdo" "Medianamente de acuerdo" "Medianamente en desacuerdo" "Totalmente de acuerdo" ...
##  $ prestaciones        : chr [1:106] "Medianamente de acuerdo" "Medianamente de acuerdo" "Totalmente en desacuerdo" "Medianamente de acuerdo" ...
##  $ jornada_laboral     : chr [1:106] "Totalmente de acuerdo" "Totalmente de acuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ desemp_aprend       : chr [1:106] "Totalmente de acuerdo" "Medianamente de acuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ clima               : chr [1:106] "Medianamente en desacuerdo" "Ni de acuerdo ni en desacuerdo" "Ni de acuerdo ni en desacuerdo" "Medianamente de acuerdo" ...
##  $ estres              : chr [1:106] "Totalmente de acuerdo" "Medianamente en desacuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ transporte          : chr [1:106] "Medianamente de acuerdo" "Medianamente en desacuerdo" "Medianamente de acuerdo" "Totalmente de acuerdo" ...
##  $ zona_trabajo        : chr [1:106] "Totalmente de acuerdo" "Medianamente de acuerdo" "Medianamente de acuerdo" "Totalmente de acuerdo" ...
##  $ futuro_form         : chr [1:106] "Medianamente de acuerdo" "Totalmente de acuerdo" "Totalmente en desacuerdo" "Medianamente de acuerdo" ...
##  $ inseguridad         : chr [1:106] "No" "No" "Si" "No" ...
##  $ ins_puesto_actual   : chr [1:106] "Cotización ante IMSS, fecha de pago, comer a las 3pm" "NA" "Mucho trabajo, estrés" "NA" ...
##  $ op_form             : chr [1:106] "A gusto, feliz" "Bien" "Cómoda, no satisfecha" "Tranquila y contenta" ...
##  $ edad                : chr [1:106] "30" "54" "21" "20" ...
##  $ genero              : chr [1:106] "Femenino" "Femenino" "Femenino" "Femenino" ...
##  $ estado_civil        : chr [1:106] "Unión libre" "Casado" "Soltero" "Casado" ...
##  $ municipio_residencia: chr [1:106] "Apodaca" "Apodaca" "Apodaca" "Apodaca" ...
##  $ escolaridad         : chr [1:106] "Licenciatura" "Primaria" "Preparatoria" "Preparatoria" ...
##  $ dep_econ            : num [1:106] 0 0 0 0 0 2 1 0 0 2 ...
# Seleccionar información y datos relevantes para responder las preguntas de análisis

# Eliminar columna id
df <- subset(df, select = -id)
names(df)
##  [1] "puesto_trabajo"       "antiguedad"           "razon_trabajo"       
##  [4] "salario"              "prestaciones"         "jornada_laboral"     
##  [7] "desemp_aprend"        "clima"                "estres"              
## [10] "transporte"           "zona_trabajo"         "futuro_form"         
## [13] "inseguridad"          "ins_puesto_actual"    "op_form"             
## [16] "edad"                 "genero"               "estado_civil"        
## [19] "municipio_residencia" "escolaridad"          "dep_econ"
# Al visualizar la estructura interna del data frame, es poisble observar que algunos valores son representados por la palabra "NA", la cual está siendo identificada como un carácter. En este caso, sustituiremos la palabra "NA" por el tipo de dato NA.
df[df == "NA"] <- NA

# Contar la cantidad total de NA's en el data frame
sum(is.na(df))
## [1] 36
# Conocer cuántos datos faltantes hay por columna
colSums(is.na(df))
##       puesto_trabajo           antiguedad        razon_trabajo 
##                    0                    0                    0 
##              salario         prestaciones      jornada_laboral 
##                    0                    0                    0 
##        desemp_aprend                clima               estres 
##                    0                    0                    0 
##           transporte         zona_trabajo          futuro_form 
##                    0                    0                    0 
##          inseguridad    ins_puesto_actual              op_form 
##                    0                   36                    0 
##                 edad               genero         estado_civil 
##                    0                    0                    0 
## municipio_residencia          escolaridad             dep_econ 
##                    0                    0                    0
# Con esto podemos ver que los 36 datos faltantes se encuentran en la columna ins_puesto_actual. La columna contiene las respuestas de cada entrevistado para la pregunta ¿qué aspectos de tu puesto actual te resultan menos satisfactorios?. En este caso, los NA's son interpretados de la siguiente manera: el colaborador no califica ningún aspecto de su puesto actual como menos satisfactorio.

# Sustituir los valores NA por la palabra "Ninguno"
df$ins_puesto_actual[is.na(df$ins_puesto_actual)] <- "Ninguno"
# Al visualizar la estructura interna del data frame, es poisble observar que algunas columnas no corresponden al tipo de datos que deberían.

# Convertir las columnas seleccionadas a factores

categoricas <- c("puesto_trabajo","razon_trabajo","salario","prestaciones","jornada_laboral","desemp_aprend","clima","estres","transporte","zona_trabajo","futuro_form","inseguridad","genero","estado_civil","municipio_residencia","escolaridad")

# Usar lapply para aplicar la función as.factor a las columnas seleccionadas
df[categoricas] <- lapply(df[categoricas], as.factor)

# Convertir las columnas seleccionadas a enteros
df$antiguedad  <- as.integer(df$antiguedad)
df$edad        <- as.integer(df$edad)
df$dep_econ    <- as.integer(df$dep_econ)

# Revisar que las columnas tengan el tipo de dato correcto
str(df)
## tibble [106 × 21] (S3: tbl_df/tbl/data.frame)
##  $ puesto_trabajo      : Factor w/ 25 levels "Administrativo",..: 1 7 3 3 3 3 3 1 7 3 ...
##  $ antiguedad          : int [1:106] 9 36 4 2 1 36 36 36 36 1 ...
##  $ razon_trabajo       : Factor w/ 6 levels "Ambiente de trabajo",..: 3 2 6 6 6 5 6 5 3 3 ...
##  $ salario             : Factor w/ 5 levels "Medianamente de acuerdo",..: 4 1 2 4 3 1 2 4 1 4 ...
##  $ prestaciones        : Factor w/ 5 levels "Medianamente de acuerdo",..: 1 1 5 1 5 4 3 1 5 1 ...
##  $ jornada_laboral     : Factor w/ 5 levels "Medianamente de acuerdo",..: 4 4 5 4 4 4 1 4 1 4 ...
##  $ desemp_aprend       : Factor w/ 5 levels "Medianamente de acuerdo",..: 4 1 5 4 4 4 1 4 5 4 ...
##  $ clima               : Factor w/ 5 levels "Medianamente de acuerdo",..: 2 3 3 1 1 2 2 1 4 5 ...
##  $ estres              : Factor w/ 5 levels "Medianamente de acuerdo",..: 4 2 5 4 3 1 4 1 1 4 ...
##  $ transporte          : Factor w/ 5 levels "Medianamente de acuerdo",..: 1 2 1 4 5 4 5 4 4 2 ...
##  $ zona_trabajo        : Factor w/ 5 levels "Medianamente de acuerdo",..: 4 1 1 4 4 1 1 4 4 4 ...
##  $ futuro_form         : Factor w/ 5 levels "Medianamente de acuerdo",..: 1 4 5 1 3 4 3 4 4 4 ...
##  $ inseguridad         : Factor w/ 3 levels "No","Prefiero no decirlo",..: 1 1 3 1 1 1 3 1 3 1 ...
##  $ ins_puesto_actual   : chr [1:106] "Cotización ante IMSS, fecha de pago, comer a las 3pm" "Ninguno" "Mucho trabajo, estrés" "Ninguno" ...
##  $ op_form             : chr [1:106] "A gusto, feliz" "Bien" "Cómoda, no satisfecha" "Tranquila y contenta" ...
##  $ edad                : int [1:106] 30 54 21 20 43 61 55 29 56 36 ...
##  $ genero              : Factor w/ 2 levels "Femenino","Masculino": 1 1 1 1 1 1 1 2 1 1 ...
##  $ estado_civil        : Factor w/ 4 levels "Casado","Divorciado",..: 4 1 3 1 3 4 1 3 3 4 ...
##  $ municipio_residencia: Factor w/ 6 levels "Apodaca","Guadalupe",..: 1 1 1 1 3 1 1 1 1 1 ...
##  $ escolaridad         : Factor w/ 5 levels "Licenciatura",..: 1 4 3 3 5 5 5 1 5 5 ...
##  $ dep_econ            : int [1:106] 0 0 0 0 0 2 1 0 0 2 ...
# Confirmar ausencia de NA's en el data frame
any(is.na(df))
## [1] FALSE
# Visualizar los primeros 6 renglones de la nueva base de datos
head(df)
## # A tibble: 6 × 21
##   puesto_trabajo   antiguedad razon_trabajo salario prestaciones jornada_laboral
##   <fct>                 <int> <fct>         <fct>   <fct>        <fct>          
## 1 Administrativo            9 Por el salar… Totalm… Medianament… Totalmente de …
## 2 Costurera                36 Otro          Median… Medianament… Totalmente de …
## 3 Ayudante general          4 Ubicación de… Median… Totalmente … Totalmente en …
## 4 Ayudante general          2 Ubicación de… Totalm… Medianament… Totalmente de …
## 5 Ayudante general          1 Ubicación de… Ni de … Totalmente … Totalmente de …
## 6 Ayudante general         36 Razones pers… Median… Totalmente … Totalmente de …
## # ℹ 15 more variables: desemp_aprend <fct>, clima <fct>, estres <fct>,
## #   transporte <fct>, zona_trabajo <fct>, futuro_form <fct>, inseguridad <fct>,
## #   ins_puesto_actual <chr>, op_form <chr>, edad <int>, genero <fct>,
## #   estado_civil <fct>, municipio_residencia <fct>, escolaridad <fct>,
## #   dep_econ <int>

Glosario de la base de datos de Clima Laboral

Más información: Glosario de variables

str(df1)
## 'data.frame':    106 obs. of  23 variables:
##  $ ID              : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ Puesto_trabajo  : chr  "Administrativo" "Costurera" "Ayudante general" "Ayudante general" ...
##  $ Puesto_otro     : chr  "" "" "" "" ...
##  $ Antigüedad_meses: int  9 36 4 2 1 36 36 36 36 1 ...
##  $ p1              : chr  "Por el salario" "Otro" "Ubicación de la empresa" "Ubicación de la empresa" ...
##  $ p2              : chr  "Totalmente de acuerdo" "Medianamente de acuerdo" "Medianamente en desacuerdo" "Totalmente de acuerdo" ...
##  $ p3              : chr  "Medianamente de acuerdo" "Medianamente de acuerdo" "Totalmente en desacuerdo" "Medianamente de acuerdo" ...
##  $ p4              : chr  "Totalmente de acuerdo" "Totalmente de acuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ p5              : chr  "Totalmente de acuerdo" "Medianamente de acuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ p6              : chr  "Medianamente en desacuerdo" "Ni de acuerdo ni en desacuerdo" "Ni de acuerdo ni en desacuerdo" "Medianamente de acuerdo" ...
##  $ p7              : chr  "Totalmente de acuerdo" "Medianamente en desacuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ p8              : chr  "Medianamente de acuerdo" "Medianamente en desacuerdo" "Medianamente de acuerdo" "Totalmente de acuerdo" ...
##  $ p9              : chr  "Totalmente de acuerdo" "Medianamente de acuerdo" "Medianamente de acuerdo" "Totalmente de acuerdo" ...
##  $ p10             : chr  "Medianamente de acuerdo" "Totalmente de acuerdo" "Totalmente en desacuerdo" "Medianamente de acuerdo" ...
##  $ p11             : chr  "No" "No" "Si" "No" ...
##  $ p12             : chr  "cotización ante imss, fecha de pago, comer a las 3pm" "Ninguno" "mucho trabajo, estrés" "Todo bien " ...
##  $ p13             : chr  "agusto, feliz" "Bien" "cómoda, no satisfecha" "Tranquila y contenta " ...
##  $ Edad            : int  30 54 21 20 43 61 55 29 56 36 ...
##  $ Género          : chr  "Femenino" "Femenino" "Femenino" "Femenino" ...
##  $ Estado_civil    : chr  "Unión libre" "Casado" "Soltero" "Casado" ...
##  $ Residencia      : chr  "Apodaca" "Apodaca" "Apodaca" "Apodaca" ...
##  $ Escolaridad     : chr  "Licenciatura" "Primaria" "Preparatoria" "Preparatoria" ...
##  $ Dependientes    : int  0 0 0 0 0 2 1 0 0 2 ...
colnames(df1)
##  [1] "ID"               "Puesto_trabajo"   "Puesto_otro"      "Antigüedad_meses"
##  [5] "p1"               "p2"               "p3"               "p4"              
##  [9] "p5"               "p6"               "p7"               "p8"              
## [13] "p9"               "p10"              "p11"              "p12"             
## [17] "p13"              "Edad"             "Género"           "Estado_civil"    
## [21] "Residencia"       "Escolaridad"      "Dependientes"

Cambio de columnas para variables en base de datos “df1”

  • p1: ¿Cuál fue la principal razón por la que entraste a este trabajo?
  • p2: Considero que el salario que recibo es bueno para el trabajo que realizo
  • p3: Mis prestaciones son algo que hace que me quede en la empresa
  • p4: La jornada laboral no es excesiva
  • p5: FORM me ha ofrecido las herramientas necesarias para mi desempeño y aprendizaje
  • p6: Que haga mucho frío o calor en mi área de trabajo no es algo que me moleste
  • p7: Mi nivel de estrés durante la jornada laboral es bajo
  • p8: Me puedo transportar de forma segura de mi casa a mi trabajo y no me cuesta demasiado esfuerzo llegar
  • p9: Mi zona de trabajo es cómoda y segura para hacer mis actividades
  • p10: Es muy probable que siga trabajando en FORM en un futuro
  • p11: ¿Has experimentado situaciones de conflicto, acoso o que te hayan hecho sentir inseguro durante tu tiempo en la empresa?
  • p12: En 3 palabras o menos ¿Qué aspectos de tu puesto actual te resultan menos satisfactorios?
  • p13: ¿Cómo te sientes en FORM?

EDA del Clima Laboral

Estadísticos descriptivos

summary(df)
##           puesto_trabajo   antiguedad                    razon_trabajo
##  Ayudante general:46     Min.   : 1.00   Ambiente de trabajo    :13   
##  Administrativo  :17     1st Qu.: 1.00   Otro                   :21   
##  Costurera       : 7     Median : 9.00   Por el salario         :19   
##  Supervisor(a)   : 6     Mean   :14.08   Prestaciones           : 2   
##  Montacarguista  : 3     3rd Qu.:34.50   Razones personales     :19   
##  Operador        : 3     Max.   :36.00   Ubicación de la empresa:32   
##  (Other)         :24                                                  
##                            salario                           prestaciones
##  Medianamente de acuerdo       :35   Medianamente de acuerdo       :22   
##  Medianamente en desacuerdo    :11   Medianamente en desacuerdo    :19   
##  Ni de acuerdo ni en desacuerdo: 8   Ni de acuerdo ni en desacuerdo:10   
##  Totalmente de acuerdo         :41   Totalmente de acuerdo         :34   
##  Totalmente en desacuerdo      :11   Totalmente en desacuerdo      :21   
##                                                                          
##                                                                          
##                        jornada_laboral                        desemp_aprend
##  Medianamente de acuerdo       :19     Medianamente de acuerdo       :15   
##  Medianamente en desacuerdo    : 6     Medianamente en desacuerdo    : 2   
##  Ni de acuerdo ni en desacuerdo:10     Ni de acuerdo ni en desacuerdo: 9   
##  Totalmente de acuerdo         :63     Totalmente de acuerdo         :60   
##  Totalmente en desacuerdo      : 8     Totalmente en desacuerdo      :20   
##                                                                            
##                                                                            
##                             clima                               estres  
##  Medianamente de acuerdo       :14   Medianamente de acuerdo       :21  
##  Medianamente en desacuerdo    : 7   Medianamente en desacuerdo    : 9  
##  Ni de acuerdo ni en desacuerdo:12   Ni de acuerdo ni en desacuerdo:20  
##  Totalmente de acuerdo         :38   Totalmente de acuerdo         :43  
##  Totalmente en desacuerdo      :35   Totalmente en desacuerdo      :13  
##                                                                         
##                                                                         
##                           transporte                         zona_trabajo
##  Medianamente de acuerdo       :14   Medianamente de acuerdo       :18   
##  Medianamente en desacuerdo    : 9   Medianamente en desacuerdo    : 5   
##  Ni de acuerdo ni en desacuerdo: 2   Ni de acuerdo ni en desacuerdo: 4   
##  Totalmente de acuerdo         :66   Totalmente de acuerdo         :71   
##  Totalmente en desacuerdo      :15   Totalmente en desacuerdo      : 8   
##                                                                          
##                                                                          
##                          futuro_form              inseguridad
##  Medianamente de acuerdo       :21   No                 :89  
##  Medianamente en desacuerdo    : 5   Prefiero no decirlo: 1  
##  Ni de acuerdo ni en desacuerdo:15   Si                 :16  
##  Totalmente de acuerdo         :56                           
##  Totalmente en desacuerdo      : 9                           
##                                                              
##                                                              
##  ins_puesto_actual    op_form               edad             genero  
##  Length:106         Length:106         Min.   :18.00   Femenino :69  
##  Class :character   Class :character   1st Qu.:25.25   Masculino:37  
##  Mode  :character   Mode  :character   Median :33.50                 
##                                        Mean   :35.62                 
##                                        3rd Qu.:45.00                 
##                                        Max.   :68.00                 
##                                                                      
##       estado_civil municipio_residencia       escolaridad    dep_econ    
##  Casado     :38    Apodaca  :77         Licenciatura:24   Min.   :0.000  
##  Divorciado : 1    Guadalupe: 4         Otro        : 3   1st Qu.:0.000  
##  Soltero    :47    Juárez   :12         Preparatoria:27   Median :1.000  
##  Unión libre:20    Monterrey: 3         Primaria    : 9   Mean   :1.085  
##                    Otro     : 6         Secundaria  :43   3rd Qu.:2.000  
##                    Pesquería: 4                           Max.   :3.000  
## 

Medidas de dispersión

describe(df)
## # A tibble: 3 × 26
##   described_variables     n    na  mean    sd se_mean   IQR skewness kurtosis
##   <chr>               <int> <int> <dbl> <dbl>   <dbl> <dbl>    <dbl>    <dbl>
## 1 antiguedad            106     0 14.1  14.5    1.41   33.5    0.629   -1.33 
## 2 edad                  106     0 35.6  12.2    1.18   19.8    0.473   -0.853
## 3 dep_econ              106     0  1.08  1.10   0.106   2      0.492   -1.14 
## # ℹ 17 more variables: p00 <dbl>, p01 <dbl>, p05 <dbl>, p10 <dbl>, p20 <dbl>,
## #   p25 <dbl>, p30 <dbl>, p40 <dbl>, p50 <dbl>, p60 <dbl>, p70 <dbl>,
## #   p75 <dbl>, p80 <dbl>, p90 <dbl>, p95 <dbl>, p99 <dbl>, p100 <dbl>

Gráficos y tablas

# Seleccionar solo las columnas con tipo de dato factor para los gráficos de barras

# Seleccionar y graficar las variables demográficas
plot_bar(df %>% 
        select(genero,estado_civil,municipio_residencia,escolaridad))

# Graficar las variables en escala likert
plot_bar(df %>% 
         select(salario, prestaciones, jornada_laboral, desemp_aprend, clima, estres, transporte, zona_trabajo, futuro_form))

# Seleccionar y graficar el resto de las variables categóricas
plot_bar(df %>% 
        select(puesto_trabajo, razon_trabajo, inseguridad))

library(dplyr)
# Cambiamos las respuestas de la escala de Likert a números para clasificar las respuestas
df1 <- df1 %>%
  dplyr::mutate(p6_Escala = dplyr::recode(p6, 
                             "Totalmente en desacuerdo" = 1,
                             "Medianamente en desacuerdo" = 2,
                             "Ni de acuerdo ni en desacuerdo" = 3,
                             "Medianamente de acuerdo" = 4,
                             "Totalmente de acuerdo" = 5))      

frecuencias <- table(df1$Puesto_trabajo, df1$p6_Escala)

Graficamos las respuestas bajo la siguiente llave.

  • “Totalmente en desacuerdo” = 1
  • “Medianamente en desacuerdo” = 2
  • “Ni de acuerdo ni en desacuerdo” = 3
  • “Medianamente de acuerdo” = 4
  • “Totalmente de acuerdo” = 5
ggplot(data = as.data.frame.table(frecuencias), aes(x = Var1, y = Var2, fill = Freq)) +
  geom_tile() +
  scale_fill_gradient(low = "skyblue", high = "blue") +
  labs(x = "Puesto de Trabajo", y = "Totalmente en desacuerdo a totalmente de acuerdo", fill = "Frecuencia") +
  ggtitle("Que haga mucho frío o calor en mi área de trabajo no es algo que me moleste") +
  theme_minimal()

# En este caso se creará una copia del dataframe df
df_likert <- df 

# Las variables con respuestas en escala likert serán convertidas a enteros para facilitar su análisis en el EDA
df_likert <- df_likert %>%
  mutate(across(c("salario", "prestaciones", "jornada_laboral", "desemp_aprend", "clima", "estres", "transporte", "zona_trabajo", "futuro_form"), ~recode(., 
                                                                                  "Totalmente en desacuerdo" = 1, 
                                                                                  "Medianamente en desacuerdo" = 2, 
                                                                                  "Ni de acuerdo ni en desacuerdo" = 3, 
                                                                                  "Medianamente de acuerdo" = 4, 
                                                                                  "Totalmente de acuerdo" = 5)))

# Confirmar que la conversión no genere valores nulos
#any(is.na(df_likert))

Los siguientes gráficos representan únicamente la información obtenida de la encuesta.

# Histograma de edad
ggplot(df, aes(x = edad)) +
  geom_histogram(binwidth = 5, fill = "#FF8000", color = "black") +  # Puedes ajustar el ancho del bin según tus datos
  labs(title = "Histograma de Edad", subtitle = "Encuesta FORM, Otoño 2023", x = "Edad (años)", y = "Frecuencia")

# Porcentaje de respuestas por género
CrossTable(df_likert$genero, prop.c = FALSE, prop.t = FALSE, prop.chisq = FALSE)
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |-------------------------|
## 
##  
## Total Observations in Table:  106 
## 
##  
##           |  Femenino | Masculino | 
##           |-----------|-----------|
##           |        69 |        37 | 
##           |     0.651 |     0.349 | 
##           |-----------|-----------|
## 
## 
## 
## 
# Tabla cruzada municipio_residencia y transporte
CrossTable(df_likert$municipio_residencia, df_likert$transporte, prop.c = FALSE, prop.t = FALSE, prop.chisq = FALSE)
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  106 
## 
##  
##                                | df_likert$transporte 
## df_likert$municipio_residencia |         1 |         2 |         3 |         4 |         5 | Row Total | 
## -------------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                        Apodaca |        10 |         4 |         1 |         9 |        53 |        77 | 
##                                |     0.130 |     0.052 |     0.013 |     0.117 |     0.688 |     0.726 | 
## -------------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                      Guadalupe |         0 |         1 |         0 |         0 |         3 |         4 | 
##                                |     0.000 |     0.250 |     0.000 |     0.000 |     0.750 |     0.038 | 
## -------------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                         Juárez |         4 |         3 |         0 |         3 |         2 |        12 | 
##                                |     0.333 |     0.250 |     0.000 |     0.250 |     0.167 |     0.113 | 
## -------------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                      Monterrey |         0 |         0 |         0 |         0 |         3 |         3 | 
##                                |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.028 | 
## -------------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                           Otro |         1 |         1 |         0 |         1 |         3 |         6 | 
##                                |     0.167 |     0.167 |     0.000 |     0.167 |     0.500 |     0.057 | 
## -------------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                      Pesquería |         0 |         0 |         1 |         1 |         2 |         4 | 
##                                |     0.000 |     0.000 |     0.250 |     0.250 |     0.500 |     0.038 | 
## -------------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                   Column Total |        15 |         9 |         2 |        14 |        66 |       106 | 
## -------------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
## 
## 

Interpretación de los valores enteros (columnas de la tabla):

Totalmente en desacuerdo = 1
Medianamente en desacuerdo = 2
Ni de acuerdo ni en desacuerdo = 3
Medianamente de acuerdo = 4
Totalmente de acuerdo = 5

# Razón de trabajo por género

# Filtrar el DataFrame por género
df_femenino <- df_likert[df_likert$genero == 'Femenino', ]
df_masculino <- df_likert[df_likert$genero == 'Masculino', ]

# Calcular frecuencias de razon_trabajo
fem_razon_trabajo <- table(df_femenino$razon_trabajo)
masc_razon_trabajo <- table(df_masculino$razon_trabajo)

# Ordenar frecuencias
ord_fem <- names(sort(table(df_femenino$razon_trabajo), decreasing = TRUE))
ord_masc <- names(sort(table(df_masculino$razon_trabajo), decreasing = TRUE))

# Crear las gráficas de frecuencias
ggplot(data = as.data.frame(fem_razon_trabajo), aes(x = factor(Var1, levels = ord_fem), y = Freq)) +
  geom_bar(stat = "identity", fill = "#E7236F") +
  labs(title = "Razón de trabajo género femenino", subtitle = "Encuesta FORM, Otoño 2023",
       x = "Razón trabajo",
       y = "Frecuencia")

ggplot(data = as.data.frame(masc_razon_trabajo), aes(x = factor(Var1, levels = ord_masc), y = Freq)) +
  geom_bar(stat = "identity", fill = "#494D8A") +
  labs(title = "Razón de trabajo género masculino", subtitle = "Encuesta FORM, Otoño 2023",
       x = "Razón trabajo",
       y = "Frecuencia")

Análisis de sentimientos

A continuación, el análisis de sentimientos a la pregunta “¿Cómo te sientes en FORM?” En donde se resaltan los sentimiento de confianza y alegría como las principales vías que usaron los trabajadores para referirse a su estadía en FORM. Si bien también se registraron respuestas que hacen referencia a emociones negativas, la suma de todas ellas apenas es comparable con los sentimientos mencionados al inicio. A partir de este análisis es posible concluir que muy posiblemente el ambiente organizacional dentro de FORM y la relación que tienen los empleados con la empresa no son los problemas o principales causes que generan una alta rotación de personal.

Si bien también se mapeó la progresión emocional de las respuestas, al tratárse únicamente de encuestas individuales.

texto_palabras <- get_tokens(df1$p13)
emociones_df <- get_nrc_sentiment(texto_palabras, language = "spanish")
barras <- barplot(colSums(prop.table(emociones_df[, 1:8])))

respuestas <- get_tokens(df1$p13)
emociones_df_2 <- get_nrc_sentiment(respuestas, language = "spanish")
sentimientos <- (emociones_df_2$negative*-1) + emociones_df_2$positive
simple_plot(sentimientos)

Y ahora contrastando las opiniones por género

# Análisis de sentimientos de la columna op_form por género

opinion_fem <- get_tokens(df_femenino$op_form)
    emociones_df <- get_nrc_sentiment(opinion_fem, language = "spanish")
    barplot(colSums(prop.table(emociones_df[,1:8])),
        main = "F: ¿Cómo te sientes en FORM?",
        xlab = "Emociones",
        ylab = "Frecuencia")

opinion_masc <- get_tokens(df_masculino$op_form)
    emociones_df <- get_nrc_sentiment(opinion_masc, language = "spanish")
    barplot(colSums(prop.table(emociones_df[,1:8])),
        main = "M: ¿Cómo te sientes en FORM?",
        xlab = "Emociones",
        ylab = "Frecuencia")

Después nos enfocaremos en los principales dolores que tienen los trabajadores.

text <- read_lines("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\p12.txt")

corpus <- Corpus(VectorSource(text)) 

corpus <- tm_map(corpus, content_transformer(tolower))
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeNumbers)
corpus <- tm_map(corpus, removeWords, stopwords("spa"))

tdm <- TermDocumentMatrix(corpus)
m <- as.matrix(tdm)

frecuencia <- sort(rowSums(m), decreasing = TRUE)
frecuencia_df <- data.frame(word=names(frecuencia), freq = frecuencia)
# Análisis insatisfacción puesto actual
texto_ins <- read_lines("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\ins_puesto_actual.txt")

corpus_1 <- Corpus(VectorSource(texto_ins)) 

corpus_1 <- tm_map(corpus_1, content_transformer(tolower))
corpus_1 <- tm_map(corpus_1, removePunctuation)
corpus_1 <- tm_map(corpus_1, removeNumbers)
corpus_1 <- tm_map(corpus_1, removeWords, stopwords("spa"))
corpus_1 <- tm_map(corpus_1, removeWords, c("Ninguno"))

tdm_1 <- TermDocumentMatrix(corpus_1)
m_1 <- as.matrix(tdm_1)

frecuencia_1 <- sort(rowSums(m_1), decreasing = TRUE)
frecuencia_df_1 <- data.frame(word=names(frecuencia_1), freq = frecuencia_1)

Palabras Frecuentes y Wordclouds

ggplot(head(frecuencia_df, 10), aes(x = reorder(word, -freq), y = freq, fill = freq)) + 
  geom_col() +  
  geom_text(aes(label = freq), vjust = -0.3) +  
  scale_fill_gradient(low = "lightblue", high = "blue", limits = c(0, 20)) +  
  labs(title = "TOP 10 Palabras Más Frecuentes", 
       subtitle = "¿Qué aspectos de tu puesto actual te resultan menos satisfactorios?", 
       x = "Palabra", 
       y = "Frecuencia") +
  theme_minimal() 

wordcloud(words = frecuencia_df$word,
          freq = frecuencia_df$freq,
          min.freq = 2,
          random.order = FALSE,
          rot.per = 0.35, 
          colors = brewer.pal(8, "Dark2"),
          scale = c(4,0.5), 
          max.words = 100) 

ggplot(head(frecuencia_df_1, 10), aes(x = reorder(word, -freq), y = freq, fill = freq)) + 
  geom_col() +  
  geom_text(aes(label = freq), vjust = -0.3) +  
  scale_fill_gradient(low = "#FF8000", high = "blue", limits = c(0, 20)) +  
  labs(title = "TOP 10 Palabras Más Frecuentes", 
       subtitle = "¿Qué aspectos de tu puesto actual te resultan menos satisfactorios?", 
       x = "Palabra", 
       y = "Frecuencia") +
  theme_minimal() 

wordcloud(words = frecuencia_df_1$word,
          freq = frecuencia_df_1$freq,
          min.freq = 2,
          random.order = FALSE,
          rot.per = 0.35, 
          colors = brewer.pal(8, "RdGy"),
          scale = c(4,0.5), 
          max.words = 100) 

Tablas Cruzadas

# Tabla cruzada puesto_trabajo y clima
CrossTable(df_likert$puesto_trabajo, df_likert$clima, prop.c = FALSE, prop.t = FALSE, prop.chisq = FALSE)
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  106 
## 
##  
##                          | df_likert$clima 
## df_likert$puesto_trabajo |         1 |         2 |         3 |         4 |         5 | Row Total | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##           Administrativo |         3 |         1 |         5 |         3 |         5 |        17 | 
##                          |     0.176 |     0.059 |     0.294 |     0.176 |     0.294 |     0.160 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##  Asistente de producción |         1 |         0 |         0 |         0 |         0 |         1 | 
##                          |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##         Ayudante general |        18 |         5 |         3 |         7 |        13 |        46 | 
##                          |     0.391 |     0.109 |     0.065 |     0.152 |     0.283 |     0.434 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                  Calidad |         0 |         0 |         0 |         1 |         1 |         2 | 
##                          |     0.000 |     0.000 |     0.000 |     0.500 |     0.500 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                Comercial |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##           Coordinador(a) |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                Costurera |         3 |         0 |         1 |         0 |         3 |         7 | 
##                          |     0.429 |     0.000 |     0.143 |     0.000 |     0.429 |     0.066 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##              Desfajadora |         1 |         0 |         0 |         0 |         0 |         1 | 
##                          |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                  Desgajo |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##              Director(a) |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Embarque |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##             Enfermero(a) |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##               Ingeniería |         1 |         0 |         0 |         0 |         0 |         1 | 
##                          |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##       Intern/practicante |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##              Jefe de SGC |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Laminado |         1 |         0 |         0 |         1 |         0 |         2 | 
##                          |     0.500 |     0.000 |     0.000 |     0.500 |     0.000 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Limpieza |         1 |         1 |         0 |         0 |         0 |         2 | 
##                          |     0.500 |     0.500 |     0.000 |     0.000 |     0.000 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##            Mantenimiento |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##               Materiales |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##           Montacarguista |         2 |         0 |         0 |         0 |         1 |         3 | 
##                          |     0.667 |     0.000 |     0.000 |     0.000 |     0.333 |     0.028 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Operador |         0 |         0 |         1 |         0 |         2 |         3 | 
##                          |     0.000 |     0.000 |     0.333 |     0.000 |     0.667 |     0.028 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                     Otro |         1 |         0 |         0 |         0 |         1 |         2 | 
##                          |     0.500 |     0.000 |     0.000 |     0.000 |     0.500 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                  Pintura |         0 |         0 |         1 |         0 |         0 |         1 | 
##                          |     0.000 |     0.000 |     1.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Soldador |         1 |         0 |         0 |         0 |         1 |         2 | 
##                          |     0.500 |     0.000 |     0.000 |     0.000 |     0.500 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##            Supervisor(a) |         2 |         0 |         1 |         0 |         3 |         6 | 
##                          |     0.333 |     0.000 |     0.167 |     0.000 |     0.500 |     0.057 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##             Column Total |        35 |         7 |        12 |        14 |        38 |       106 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
## 
## 
# Tabla cruzada puesto_trabajo y salario
CrossTable(df_likert$puesto_trabajo, df_likert$salario, prop.c = FALSE, prop.t = FALSE, prop.chisq = FALSE)
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  106 
## 
##  
##                          | df_likert$salario 
## df_likert$puesto_trabajo |         1 |         2 |         3 |         4 |         5 | Row Total | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##           Administrativo |         0 |         3 |         2 |         6 |         6 |        17 | 
##                          |     0.000 |     0.176 |     0.118 |     0.353 |     0.353 |     0.160 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##  Asistente de producción |         0 |         1 |         0 |         0 |         0 |         1 | 
##                          |     0.000 |     1.000 |     0.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##         Ayudante general |         6 |         5 |         4 |        11 |        20 |        46 | 
##                          |     0.130 |     0.109 |     0.087 |     0.239 |     0.435 |     0.434 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                  Calidad |         0 |         0 |         1 |         1 |         0 |         2 | 
##                          |     0.000 |     0.000 |     0.500 |     0.500 |     0.000 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                Comercial |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##           Coordinador(a) |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                Costurera |         1 |         0 |         0 |         3 |         3 |         7 | 
##                          |     0.143 |     0.000 |     0.000 |     0.429 |     0.429 |     0.066 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##              Desfajadora |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                  Desgajo |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##              Director(a) |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Embarque |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##             Enfermero(a) |         0 |         0 |         1 |         0 |         0 |         1 | 
##                          |     0.000 |     0.000 |     1.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##               Ingeniería |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##       Intern/practicante |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##              Jefe de SGC |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Laminado |         0 |         0 |         0 |         2 |         0 |         2 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Limpieza |         0 |         0 |         0 |         0 |         2 |         2 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##            Mantenimiento |         1 |         0 |         0 |         0 |         0 |         1 | 
##                          |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##               Materiales |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##           Montacarguista |         0 |         0 |         0 |         3 |         0 |         3 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.028 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Operador |         1 |         0 |         0 |         0 |         2 |         3 | 
##                          |     0.333 |     0.000 |     0.000 |     0.000 |     0.667 |     0.028 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                     Otro |         0 |         1 |         0 |         1 |         0 |         2 | 
##                          |     0.000 |     0.500 |     0.000 |     0.500 |     0.000 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                  Pintura |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Soldador |         2 |         0 |         0 |         0 |         0 |         2 | 
##                          |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##            Supervisor(a) |         0 |         1 |         0 |         2 |         3 |         6 | 
##                          |     0.000 |     0.167 |     0.000 |     0.333 |     0.500 |     0.057 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##             Column Total |        11 |        11 |         8 |        35 |        41 |       106 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
## 
## 
# Tabla cruzada puesto_trabajo y prestaciones
CrossTable(df_likert$puesto_trabajo, df_likert$prestaciones, prop.c = FALSE, prop.t = FALSE, prop.chisq = FALSE)
## 
##  
##    Cell Contents
## |-------------------------|
## |                       N |
## |           N / Row Total |
## |-------------------------|
## 
##  
## Total Observations in Table:  106 
## 
##  
##                          | df_likert$prestaciones 
## df_likert$puesto_trabajo |         1 |         2 |         3 |         4 |         5 | Row Total | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##           Administrativo |         3 |         5 |         3 |         4 |         2 |        17 | 
##                          |     0.176 |     0.294 |     0.176 |     0.235 |     0.118 |     0.160 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##  Asistente de producción |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##         Ayudante general |         9 |         9 |         3 |        12 |        13 |        46 | 
##                          |     0.196 |     0.196 |     0.065 |     0.261 |     0.283 |     0.434 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                  Calidad |         0 |         1 |         0 |         0 |         1 |         2 | 
##                          |     0.000 |     0.500 |     0.000 |     0.000 |     0.500 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                Comercial |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##           Coordinador(a) |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                Costurera |         1 |         1 |         0 |         1 |         4 |         7 | 
##                          |     0.143 |     0.143 |     0.000 |     0.143 |     0.571 |     0.066 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##              Desfajadora |         1 |         0 |         0 |         0 |         0 |         1 | 
##                          |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                  Desgajo |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##              Director(a) |         0 |         0 |         0 |         1 |         0 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     1.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Embarque |         1 |         0 |         0 |         0 |         0 |         1 | 
##                          |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##             Enfermero(a) |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##               Ingeniería |         0 |         0 |         1 |         0 |         0 |         1 | 
##                          |     0.000 |     0.000 |     1.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##       Intern/practicante |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##              Jefe de SGC |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Laminado |         0 |         0 |         1 |         1 |         0 |         2 | 
##                          |     0.000 |     0.000 |     0.500 |     0.500 |     0.000 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Limpieza |         1 |         0 |         0 |         0 |         1 |         2 | 
##                          |     0.500 |     0.000 |     0.000 |     0.000 |     0.500 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##            Mantenimiento |         1 |         0 |         0 |         0 |         0 |         1 | 
##                          |     1.000 |     0.000 |     0.000 |     0.000 |     0.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##               Materiales |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##           Montacarguista |         0 |         2 |         0 |         0 |         1 |         3 | 
##                          |     0.000 |     0.667 |     0.000 |     0.000 |     0.333 |     0.028 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Operador |         1 |         0 |         0 |         1 |         1 |         3 | 
##                          |     0.333 |     0.000 |     0.000 |     0.333 |     0.333 |     0.028 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                     Otro |         1 |         1 |         0 |         0 |         0 |         2 | 
##                          |     0.500 |     0.500 |     0.000 |     0.000 |     0.000 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                  Pintura |         0 |         0 |         0 |         0 |         1 |         1 | 
##                          |     0.000 |     0.000 |     0.000 |     0.000 |     1.000 |     0.009 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##                 Soldador |         1 |         0 |         1 |         0 |         0 |         2 | 
##                          |     0.500 |     0.000 |     0.500 |     0.000 |     0.000 |     0.019 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##            Supervisor(a) |         1 |         0 |         1 |         0 |         4 |         6 | 
##                          |     0.167 |     0.000 |     0.167 |     0.000 |     0.667 |     0.057 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
##             Column Total |        21 |        19 |        10 |        22 |        34 |       106 | 
## -------------------------|-----------|-----------|-----------|-----------|-----------|-----------|
## 
## 

Gráfico de dispersión

ggplot(df_likert, aes(x=antiguedad, y=futuro_form)) + 
  geom_point(shape=19, size=3) +
  labs(title = "Relación entre antigüedad en la empresa y trabajar en un futuro en FORM",
       x="Antigüedad (meses)", y="Futuro FORM") +  
  theme_classic() 

Inseguridad por Género

# Tabla de frecuencias cruzadas entre género y opinión: femenino
Situaciones_inseguridad_fem <- table(df_femenino$inseguridad)

# Crear el gráfico de pastel

ggplot(data = NULL, aes(x = "", y = Situaciones_inseguridad_fem, fill = names(Situaciones_inseguridad_fem))) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  theme_void() +
  scale_fill_manual(values = c("#c6c6c6", "#FF7F50", "#FF4500")) + 
  labs(title = "¿Has experimentado situaciones de conflicto, acoso o que te hayan hecho sentir inseguro(a) durante tu tiempo en la empresa?") +
  geom_text(aes(label = paste0(round((..y..)/sum(..y..)*100), "%")), 
            position = position_stack(vjust = 0.5), 
            color = "black", size = 4)

# Tabla de frecuencias cruzadas entre género y opinión: masculino
Situaciones_inseguridad_masc <- table(df_masculino$inseguridad)

# Crear el gráfico de pastel
ggplot(data = NULL, aes(x = "", y = Situaciones_inseguridad_masc, fill = names(Situaciones_inseguridad_masc))) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) +
  theme_void() +
  scale_fill_manual(values = c("#c6c6c6", "#FF7F50", "#FF4500")) + 
  labs(title = "¿Has experimentado situaciones de conflicto, acoso o que te hayan hecho sentir inseguro(a) durante tu tiempo en la empresa?") +
  geom_text(aes(label = paste0(round((..y..)/sum(..y..)*100), "%")), 
            position = position_stack(vjust = 0.5), 
            color = "black", size = 4)

Acosos

# Estado Civil de los Trabajadores

# Calcular el total de observaciones
total <- nrow(df1)

# Calcular la frecuencia de cada categoría de estado civil
frecuencia_estado_civil <- table(df1$Estado_civil)

# Calcular los porcentajes
porcentajes <- (frecuencia_estado_civil / total) * 100

# Crear un DataFrame con los porcentajes
df_porcentajes <- data.frame(Estado_civil = names(porcentajes), Porcentaje = porcentajes)

# Graficar el gráfico de pastel con porcentajes
ggplot(df_porcentajes, aes(x = "", y = Porcentaje.Freq, fill = Estado_civil)) +
  geom_bar(width = 1, stat = "identity") +
  geom_text(aes(label = paste0(round(Porcentaje.Freq), "%")), 
            position = position_stack(vjust = 0.5), color = "black", size = 3) +
  coord_polar(theta = "y") +
  labs(title = "Estado Civil de los Trabajadores", y = "Porcentaje") +
  theme_void() +
  scale_fill_manual(values = rainbow(length(unique(df_porcentajes$Estado_civil))))

# Distribicion de Genero de los Trabajadores

# Calcular el total de observaciones
total <- nrow(df1)

# Calcular la frecuencia de cada género
frecuencia_genero <- table(df1$Género)

# Calcular los porcentajes
porcentajes <- (frecuencia_genero / total) * 100

# Crear un DataFrame con los porcentajes
df_porcentajes <- data.frame(Género = names(porcentajes), Porcentaje = porcentajes)

# Graficar el gráfico de pastel con porcentajes
ggplot(df_porcentajes, aes(x = "", y = Porcentaje.Freq, fill = Género)) +
  geom_bar(width = 1, stat = "identity") +
  geom_text(aes(label = paste0(round(Porcentaje.Freq), "%")), 
            position = position_stack(vjust = 0.5), color = "white", size = 3) +
  coord_polar(theta = "y") +
  labs(title = "Distribución de Género de los Trabajadores", y = "Porcentaje") +
  theme_void() +
  scale_fill_manual(values = c("blue", "pink"))  # Puedes cambiar los colores si lo deseas

# Estado civil de los Trabahadores por Género

# Filtrar datos por género femenino
df_femenino <- subset(df1, Género == "Femenino")

# Calcular el total de observaciones para el género femenino
total_femenino <- nrow(df_femenino)

# Calcular la frecuencia de cada categoría de estado civil para el género femenino
frecuencia_estado_civil_femenino <- table(df_femenino$Estado_civil)

# Calcular los porcentajes para el género femenino
porcentajes_femenino <- (frecuencia_estado_civil_femenino / total_femenino) * 100

# Crear un DataFrame con los porcentajes para el género femenino
df_porcentajes_femenino <- data.frame(Estado_civil = names(porcentajes_femenino), 
                                      Porcentaje = porcentajes_femenino, 
                                      Genero = "Femenino")

# Graficar el gráfico de pastel para el género femenino
ggplot(df_porcentajes_femenino, aes(x = "", y = Porcentaje.Freq, fill = Estado_civil)) +
  geom_bar(width = 1, stat = "identity") +
  geom_text(aes(label = paste0(round(Porcentaje.Freq), "%")), 
            position = position_stack(vjust = 0.5), color = "white", size = 3) +
  coord_polar(theta = "y") +
  labs(title = "Estado Civil de los Trabajadores - Género Femenino", y = "Porcentaje") +
  theme_void() +
  scale_fill_manual(values = rainbow(length(unique(df_porcentajes_femenino$Estado_civil)))) +
  theme(legend.position = "none")  # Para ocultar la leyenda

# Filtrar datos por género masculino
df_masculino <- subset(df1, Género == "Masculino")

# Calcular el total de observaciones para el género masculino
total_masculino <- nrow(df_masculino)

# Calcular la frecuencia de cada categoría de estado civil para el género masculino
frecuencia_estado_civil_masculino <- table(df_masculino$Estado_civil)

# Calcular los porcentajes para el género masculino
porcentajes_masculino <- (frecuencia_estado_civil_masculino / total_masculino) * 100

# Crear un DataFrame con los porcentajes para el género masculino
df_porcentajes_masculino <- data.frame(Estado_civil = names(porcentajes_masculino), 
                                       Porcentaje = porcentajes_masculino, 
                                       Genero = "Masculino")

# Graficar el gráfico de pastel para el género masculino
ggplot(df_porcentajes_masculino, aes(x = "", y = Porcentaje.Freq, fill = Estado_civil)) +
  geom_bar(width = 1, stat = "identity") +
  geom_text(aes(label = paste0(round(Porcentaje.Freq), "%")), 
            position = position_stack(vjust = 0.5), color = "white", size = 3) +
  coord_polar(theta = "y") +
  labs(title = "Estado Civil de los Trabajadores - Género Masculino", y = "Porcentaje") +
  theme_void() +
  scale_fill_manual(values = rainbow(length(unique(df_porcentajes_masculino$Estado_civil)))) +
  theme(legend.position = "none")  # Para ocultar la leyenda

#Experiencia de Acoso en el Trabajo por Género

# Contar la cantidad de hombres y mujeres que han experimentado o no acoso en el trabajo
acoso_por_genero <- table(df1$Género, df1$p11)

# Obtener las categorías únicas de género y acoso
categorias_genero <- unique(df1$Género)
categorias_acoso <- unique(df1$p11)

# Crear un data frame para almacenar los resultados
df_acoso_por_genero <- data.frame(Género = character(), Acoso = character(), Count = numeric(), stringsAsFactors = FALSE)

# Completar el data frame con todas las combinaciones posibles de género y acoso
for (gen in categorias_genero) {
  for (acos in categorias_acoso) {
    count <- acoso_por_genero[gen, acos]
    df_acoso_por_genero <- rbind(df_acoso_por_genero, data.frame(Género = gen, Acoso = acos, Count = count))
  }
}

# Reordenar los niveles de la variable "Acoso" para que coincidan con el orden de los datos reales
df_acoso_por_genero$Acoso <- factor(df_acoso_por_genero$Acoso, levels = c("Si", "No", "Prefiero no decirlo"))

# Graficar la gráfica de barras
ggplot(df_acoso_por_genero, aes(x = Género, y = Count, fill = Acoso)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Experiencia de Acoso en el Trabajo por Género",
       x = "Género",
       y = "Cantidad",
       fill = "Experiencia de Acoso") +
  scale_fill_manual(values = c("Si" = "salmon", "No" = "lightblue", "Prefiero no decirlo" = "yellow")) +
  theme_minimal()

#Experiencia de Acoso en el Trabajo por Estado Civil

# Contar la cantidad de hombres y mujeres que han experimentado o no acoso en el trabajo
acoso_por_genero <- table(df1$Estado_civil, df1$p11)

# Obtener las categorías únicas de género y acoso
categorias_genero <- unique(df1$Estado_civil)
categorias_acoso <- unique(df1$p11)

# Crear un data frame para almacenar los resultados
df_acoso_por_estado_civil <- data.frame(EstadoCivil = character(), Acoso = character(), Count = numeric(), stringsAsFactors = FALSE)

# Completar el data frame con todas las combinaciones posibles de género y acoso
for (gen in categorias_genero) {
  for (acos in categorias_acoso) {
    count <- acoso_por_genero[gen, acos]
    df_acoso_por_estado_civil <- rbind(df_acoso_por_estado_civil, data.frame(EstadoCivil = gen, Acoso = acos, Count = count))
  }
}

# Reordenar los niveles de la variable "Acoso" para que coincidan con el orden de los datos reales
df_acoso_por_estado_civil$Acoso <- factor(df_acoso_por_estado_civil$Acoso, levels = c("Si", "No", "Prefiero no decirlo"))

# Graficar la gráfica de barras
ggplot(df_acoso_por_estado_civil, aes(x = EstadoCivil, y = Count, fill = Acoso)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Experiencia de Acoso en el Trabajo por Género",
       x = "Estado Civil",
       y = "Cantidad",
       fill = "Experiencia de Acoso") +
  scale_fill_manual(values = c("Si" = "salmon", "No" = "lightblue", "Prefiero no decirlo" = "yellow")) +
  theme_minimal()

Hallazgos del Clima Laboral

  • La mayoría de los encuestados tienen entre 20 y 40 años de edad.

  • El 65% de las respuestas de esta encuesta corresponden al género femenino y el 35% restante al género masculino.

  • El 72% de los encuestados residen en el municipio de Apodaca.

  • A excepción del municipio de Juárez, la mayoría de los encuestados con residencia en municipios diferentes a Apodaca consideran que se puede transportar de forma segura de su casa al trabajo y no les cuesta demasiado esfuerzo llegar.

  • La ubicación de la empresa es la principal razón por la que la mayoría de hombres y mujeres entran a este trabajo.

  • Otro y el salario son dos de las top 3 razones por las que el género masculino entra a este trabajo.

  • Razones personales y otro son dos de las top 3 razones por las que el género femenino entra a este trabajo.

  • El calor, las prestaciones y el salario son los aspectos menos satisfactorios del puesto actual de la mayoría de los entrevistados (esto no considera a colaboradores con una opinión positiva sobre su puesto).

  • Los sentimiento con mayor frecuencia en los colaboradores de ambos géneros son alegría, confianza y anticipación. Además, el 34% (36/106) de los encuestados no califica alguno de los aspectos de su puesto actual como no satisfactorio, es decir, se sienten bien con su puesto de trabajo.

  • Ayudante general, administrativo, costurera, supervisor(a), operador y montacarguista son los puestos de trabajo para los cuales respondieron la encuesta un mayor número de personas (mínimo 3, máximo 46 personas).

  • A el 50% de los ayudantes generales, 43% de las costureras y 66% de los montacarguistas les molesta total o medianamente que haga mucho frío o calor en su área de trabajo.

Búsqueda de información y datos de RH

  • ¿Qué tipo de información / datos solicitarías al socio formador para mejorar EDA?

    • Una base de datos con los registros de todas las personas que hayan dejado la empresa con detalles demográficos, de opinión como la razón por la que optaron por tomar esa decisión, y características como el tiempo que llevaban en la organización o su puesto de trabajo.
    • Nombre de las áreas en las que se divide FORM. En este caso contamos con los puestos de trabajo, ¿a qué área corresponde cada puesto?
    • Sueldo por área, estrategias implementadas para contribuir al bienestar de sus colaboradores, perfil que buscan para contratar a alguien, estrategias de reclutamiento, información sobre el proceso de selección de aplicantes.
  • ¿Qué tipo de información / datos de fuentes secundarias buscarías para mejorar EDA?

    • Sería muy interesante buscar bases de datos que contengan registros de la rotación del personal de otras empresas para comparar el desempeño de FORM con sus competidores más immportantes del mercado, o incluso con otros negocios de la misma industria.
    • Para la situación problema de Recursos Humanos sería de gran utilidad obtener información más detallada en las encuestas así como también asegurar que la muestra sea representativa para realizar inferencias y generalizar la información obtenida para cada uno de los departamentos de la empresa.
    • Información más detallada en las encuestas como área o departamento del puesto de trabajo, evaluación del ambiente laboral, ventajas de trabajar en FORM, si los colaboradores recomendarían trabajar o no en FORM, factores más importante al elegir en qué empresa trabajar, etc.

Situación Problema 2: Nearshoring y Ventas FORM

La(s) posible(s) estrategia(s) de predicción de la demanda de producto fabricados por la empresa FORM.

Librerías

library(foreign)
library(dygraphs)
library(dplyr)        # data manipulation 
library(forcats)      # to work with categorical variables
library(ggplot2)      # data visualization 
library(readr)        # read specific csv files
library(janitor)      # data exploration and cleaning 
library(Hmisc)        # several useful functions for data analysis 
library(psych)        # functions for multivariate analysis 
library(naniar)       # summaries and visualization of missing values NA's
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(naniar)       # identifying missing values
library(stargazer)    # create publication quality tables
library(effects)      # displays for linear and other regression models
library(tidyverse)    # collection of R packages designed for data science
library(caret)        # Classification and Regression Training 
library(glmnet)       # methods for prediction and plotting, and functions for cross-validation
library(xts)
library(zoo)
library(tseries)
library(stats)
library(forecast)
library(astsa)
library(AER)
library(dynlm)
library(vars)
library(TSstudio)
library(sarima)
library(DataExplorer)
library(corrplot)     # correlation plots
library(readxl)

Nearshoring

Preguntas de Análisis de Nearshoring

  • ¿Qué se espera en la inversión directa extranjera en los proximos años?
  • ¿Cuál es la magnitud del impacto que puede llegar a tener el nearshoring
  • ¿Cuál es el desempeño de FORM actual y como se puede ver afectado por la situación problema
  • ¿Cómo se ve el desempeño de FORM en los proximos años?

Limpieza y Organización de Base de Datos Nearshoring

df <- read_excel("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\nearshoring_datos_series_de_tiempo_trimestral.xlsx")

Primeros renglones de Nearshoring

head(df)
## # A tibble: 6 × 7
##    Year Quarter New_FDI_Inflows Exchange_Rate new_fdi_inflows_mxn
##   <dbl> <chr>             <dbl>         <dbl>               <dbl>
## 1  2006 I                  897.          10.8              15471.
## 2  2006 II                2110.          10.9              36790.
## 3  2006 III               1284.          10.9              22338.
## 4  2006 IV                2678.          10.9              46617.
## 5  2007 I                 3108.          10.9              52252.
## 6  2007 II                2561.          10.9              42891.
## # ℹ 2 more variables: log_new_fdi_inflows_mxn <dbl>, INPC <dbl>
str(df)
## tibble [69 × 7] (S3: tbl_df/tbl/data.frame)
##  $ Year                   : num [1:69] 2006 2006 2006 2006 2007 ...
##  $ Quarter                : chr [1:69] "I" "II" "III" "IV" ...
##  $ New_FDI_Inflows        : num [1:69] 897 2110 1284 2678 3108 ...
##  $ Exchange_Rate          : num [1:69] 10.8 10.9 10.9 10.9 10.9 ...
##  $ new_fdi_inflows_mxn    : num [1:69] 15471 36790 22338 46617 52252 ...
##  $ log_new_fdi_inflows_mxn: num [1:69] 9.65 10.51 10.01 10.75 10.86 ...
##  $ INPC                   : num [1:69] 60.7 60.7 61.2 62.3 63.2 ...

Correción de tipo de variables en Nearshoring

df$Date <- ymd(paste0(df$Year, "-", 
                      ifelse(df$Quarter == "I", "01-01", 
                             ifelse(df$Quarter == "II", "04-01", 
                                    ifelse(df$Quarter == "III", "07-01", "10-01")))))

df$Year <- as.Date(df$Year)

df$Quarter <- ifelse(df$Quarter == "I", "A", df$Quarter)
df$Quarter <- ifelse(df$Quarter == "II","B", df$Quarter)
df$Quarter <- ifelse(df$Quarter == "III","C", df$Quarter)
df$Quarter <- ifelse(df$Quarter == "IV","D", df$Quarter)

df$Quarter <- ifelse(df$Quarter == "A", 1, df$Quarter)
df$Quarter <- ifelse(df$Quarter == "B", 2, df$Quarter)
df$Quarter <- ifelse(df$Quarter == "C", 3, df$Quarter)
df$Quarter <- ifelse(df$Quarter == "D", 4, df$Quarter)

df$Quarter <- as.numeric(df$Quarter)

# Revisar por NAs
sum(is.na(df))
## [1] 0

Glosariode la base de datos de Nearshoring

  • Year: Año
  • Quarter: Trimestre correpondiendo a su año.
  • New FDI Inflows: Inversión extranjera directa en millones de dolares.
  • Exchange Rate: Tipo de cambio de dolares estadunidenses a pesos mexicanos.
  • New FDI Inflows Mxn: Inversión extranjera directa en millones de pesos mexicanos.
  • Log New FDI Inflows Mxn: Inversión extranjera directa en millones de pesos mexicanos con transformación de logaritmos.
  • INPC: Indice Nacional de Precios al Consumidor en base al 2018

EDA de Nearshoring

Estadísticos Descriptivos

summary(df$new_fdi_inflows_mxn)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  -37081   33164   46617   51775   65069  237466
sd(df$new_fdi_inflows_mxn)
## [1] 37355.05

Medidas de Dispersión

summary(df)
##       Year               Quarter      New_FDI_Inflows Exchange_Rate  
##  Min.   :1975-06-30   Min.   :1.000   Min.   :-2433   Min.   :10.82  
##  1st Qu.:1975-07-04   1st Qu.:1.000   1st Qu.: 1934   1st Qu.:12.65  
##  Median :1975-07-08   Median :2.000   Median : 2605   Median :13.65  
##  Mean   :1975-07-08   Mean   :2.478   Mean   : 3001   Mean   :15.59  
##  3rd Qu.:1975-07-12   3rd Qu.:3.000   3rd Qu.: 3750   3rd Qu.:19.26  
##  Max.   :1975-07-17   Max.   :4.000   Max.   :15445   Max.   :21.60  
##  new_fdi_inflows_mxn log_new_fdi_inflows_mxn      INPC       
##  Min.   :-37081      Min.   :-10.52          Min.   : 60.69  
##  1st Qu.: 33164      1st Qu.: 10.41          1st Qu.: 73.00  
##  Median : 46617      Median : 10.75          Median : 85.24  
##  Mean   : 51775      Mean   : 10.10          Mean   : 87.59  
##  3rd Qu.: 65069      3rd Qu.: 11.08          3rd Qu.:102.25  
##  Max.   :237466      Max.   : 12.38          Max.   :127.92  
##       Date           
##  Min.   :2006-01-01  
##  1st Qu.:2010-04-01  
##  Median :2014-07-01  
##  Mean   :2014-07-01  
##  3rd Qu.:2018-10-01  
##  Max.   :2023-01-01
var(df$new_fdi_inflows_mxn)
## [1] 1395399560

Gráficos

plot_histogram(df)

plot_intro(df)

boxplot(df$new_fdi_inflows_mxn,
        main = "Box Plot of Flujos",
        ylab = "IED_Flujos")

plot(df$Date,df$new_fdi_inflows_mxn,col="skyblue", lwd=2, xlab ="Date",ylab ="Flujos IED", main = "FDI")

Pronóstico de ventas

Explorar los datos de series de tiempo

#Conversion de data a series de tiempo
FDIts <- ts(df$new_fdi_inflows_mxn,start=c(2006,1),end=c(2023,1),frequency=4)
FDI_ts_decompose<-decompose(FDIts)

#Descomposicion de datos
plot(FDI_ts_decompose) 

#Revisar Esacionaridad
adf.test(FDIts)  
## 
##  Augmented Dickey-Fuller Test
## 
## data:  FDIts
## Dickey-Fuller = -5.4066, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary
# En este caso si hay presencia de estacionariedad.

#Revisar Autocorrelacion Serial
acf(df$new_fdi_inflows_mxn,main="Serial Autocorrelations")

# Parece que si hay presencia de Autocorrelacion serial

Modelos de series de tiempo

Para esto se aplicara un modelo ARMA y ARIMA y se escogera el mejor adaptado a los datos para realizar el pronostico.

Modelo ARMA

summary(FDI_ARMA<-arma(df$new_fdi_inflows_mxn,order=c(1,1)))
## 
## Call:
## arma(x = df$new_fdi_inflows_mxn, order = c(1, 1))
## 
## Model:
## ARMA(1,1)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -94534 -20819   1758  17359 151397 
## 
## Coefficient(s):
##             Estimate  Std. Error  t value Pr(>|t|)    
## ar1           0.5954      0.1342    4.436 9.14e-06 ***
## ma1          -0.8173      0.1136   -7.193 6.35e-13 ***
## intercept 21448.9889   7147.7797    3.001  0.00269 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Fit:
## sigma^2 estimated as 1.311e+09,  Conditional Sum-of-Squares = 87863726846,  AIC = 1650.41
plot(FDI_ARMA)

FDI_estimated<-FDI_ARMA$fitted.values
plot(FDI_estimated)

# Autocorrelation
acf(na.omit(FDI_ARMA$residuals),main="ACF - ARMA (1,1)")

#Normality of residuals
hist(FDI_ARMA$residuals, main = "Histogram of Residuals", xlab = "Residuals", ylab = "Frequency")

#Check for Serial Autoorrelation
FDI_ARMA_residuals<-FDI_ARMA$residuals
Box.test(FDI_ARMA_residuals,lag=5,type="Ljung-Box") 
## 
##  Box-Ljung test
## 
## data:  FDI_ARMA_residuals
## X-squared = 4.1828, df = 5, p-value = 0.5234
#Chcek for Stationarity
adf.test(na.omit(FDI_estimated))
## 
##  Augmented Dickey-Fuller Test
## 
## data:  na.omit(FDI_estimated)
## Dickey-Fuller = -2.5562, Lag order = 4, p-value = 0.3492
## alternative hypothesis: stationary
  • Parece que el modelo ARMA no tiene autocorrelacion serial estadisticamente significativa.
  • Los residuales se ven normales a excpeción de un valor atípico.
  • El modelo ARMA no tiene estacionariedad en base a la prueba de Dicky Fuller Test.

Modelo ARIMA

FDI_ARIMA <- Arima(df$new_fdi_inflows_mxn,order=c(1,1,1))
print(FDI_ARIMA)
## Series: df$new_fdi_inflows_mxn 
## ARIMA(1,1,1) 
## 
## Coefficients:
##           ar1      ma1
##       -0.0389  -1.0000
## s.e.   0.1229   0.0406
## 
## sigma^2 = 1.434e+09:  log likelihood = -814.47
## AIC=1634.95   AICc=1635.32   BIC=1641.61
plot(FDI_ARIMA$residuals,main="ARIMA(1,1,1) - FDI")

#Normality of Residuals 
hist(FDI_ARIMA$residuals, main = "Histogram of Residuals", xlab = "Residuals", ylab = "Frequency")

#Check for  serial autocorrelation
acf(FDI_ARIMA$residuals,main="ACF - ARIMA (1,1,1)")

#Check for Serial Autocorrelation
Box.test(FDI_ARIMA$residuals,lag=1,type="Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  FDI_ARIMA$residuals
## X-squared = 0.016568, df = 1, p-value = 0.8976
#Check for Stationarity
adf.test(FDI_ARIMA$residuals)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  FDI_ARIMA$residuals
## Dickey-Fuller = -4.8918, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary
  • En base a las pruebas de diagnostico del modelo ARIMA, los residuales se ven normales a excepción de un valor atípico.
  • Parece que el modelo no tiene autocorrelacion serial, lo cual es una buena señal.
  • El modelo muestra que si hay presencia de estacionaridad, lo cual es una buena señal igualmente.

Despues de analizar los diagnosticos de los 2 modelos se concluyo que el modelo mejor adaptado a los datos seria el modelo de ARIMA. Esto se debe a que los 2 modelos no presentan autocorrelacion serial, pero solo el modelo de ARIMA presenta estacionaridad. Lo cual es mejor a la hora de realizar los pronosticos.

Pronostico de Flujos de Inversión Extranjera Directa (IED Flujos)

FDI_ARIMA_forecast<-forecast(FDI_ARIMA,h=5)
FDI_ARIMA_forecast
##    Point Forecast    Lo 80    Hi 80     Lo 95    Hi 95
## 70       53327.03 4447.107 102206.9 -21428.36 128082.4
## 71       51756.87 2867.109 100646.6 -23013.57 126527.3
## 72       51818.01 2927.175 100708.8 -22954.07 126590.1
## 73       51815.63 2924.834 100706.4 -22956.39 126587.6
## 74       51815.72 2924.925 100706.5 -22956.30 126587.7
plot(FDI_ARIMA_forecast)

autoplot(FDI_ARIMA_forecast)

Hallazgos de Nearshoring

  • Para los flujos de FDI, los datos son normales sin embargo existen dos valores atipicos, estos siendo el minimo y el maximo. Estos valores se ven reflejados a la hora de visualisalr los residuales de los modelos.

  • Hay una presnecia estadisiticamente significativa de estacionaridad, esto significa que los datos tienen propiedades estadisticas consistentes, lo cual facilita la aplicacion de los modelos de series de tiempo.

  • Los modelos ARMA y ARIMA no presentaron autocorrelacion serial, esto es un buen indicador para los modelos.

  • El modelo de ARMA no presento estacionaridad, pero el modelo de ARIMA si presento estacionaridad, esto es una buena señal para el modelo ARIMA y una mala señal para el modelo ARMA.

  • Los dos modelos ARMA y ARIMA presentaron normalidad en los residuales a esepcion de un valor atipico. Este valor probablemente es el valor atipico de los datos originales.

  • En base a el pronostico del modelo sleccionado, en este caso el modelo ARIMA, se espera que el valor de inversiones extranjeras directas incremente en los proximos 5 trimestres. Poniendo mas presión para FORM debido a que esto es una señal de que la competitividad en su industria estara incrementando por empresas extranjeras.

Ventas

Preguntas de Análisis de Ventas

  • ¿Cuál es el mes y el año en donde se tienen más ventas?
  • ¿Cuales la tendencia de las ventas de FORM?
  • ¿Cómo se vera el desempeño de FORM en las ventas de los proximos años?

Limpieza y Organización de Base de Datos Venta

ventas_meses <- read.csv("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\totales_mensualesFORM.csv")
ventas_anuales <- read.csv("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\ventasanualesFORM.csv")
ventas_anuales$año <- as.Date(paste0(ventas_anuales$año, "-12-31"))
ultima_fila <- nrow(ventas_anuales)
ventas_anuales$año[ultima_fila] <- as.Date("2022-09-30")
head(ventas_anuales)
##          año   ventas
## 1 2017-12-31 61993858
## 2 2018-12-31 86978635
## 3 2019-12-31 81443008
## 4 2020-12-31 85914707
## 5 2021-12-31 89938901
## 6 2022-09-30 82963816
meses_español <- c("Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre")
ventas_meses$año <- as.Date(paste0(ventas_meses$año, "-", match(ventas_meses$meses, meses_español), "-01")) + months(1) - days(1)
head(ventas_meses)
##          año   meses total_carton total_retornable total_servicios variacion
## 1 2020-01-31   Enero            0                0               0         0
## 2 2020-02-29 Febrero            0                0               0         0
## 3 2020-03-31   Marzo            0                0               0         0
## 4 2020-04-30   Abril            0                0               0         0
## 5 2020-05-31    Mayo            0                0               0         0
## 6 2020-06-30   Junio            0                0               0         0
##   total_mensual
## 1       6059791
## 2       6643181
## 3       8368674
## 4       4925778
## 5       2235669
## 6       7842003
ventas_meses$total_mensual <- as.numeric(ventas_meses$total_mensual)

ventas_meses <- ventas_meses[, c("año", "meses", "total_mensual")]
str(ventas_anuales)
## 'data.frame':    6 obs. of  2 variables:
##  $ año   : Date, format: "2017-12-31" "2018-12-31" ...
##  $ ventas: num  61993858 86978635 81443008 85914707 89938901 ...
str(ventas_meses)
## 'data.frame':    33 obs. of  3 variables:
##  $ año          : Date, format: "2020-01-31" "2020-02-29" ...
##  $ meses        : chr  "Enero" "Febrero" "Marzo" "Abril" ...
##  $ total_mensual: num  6059791 6643181 8368674 4925778 2235669 ...

Checar si hay NA’s

sum(is.na(ventas_anuales))
## [1] 0
sum(is.na(ventas_meses))
## [1] 0

Visualizar la nueva base de datos

head(ventas_anuales)
##          año   ventas
## 1 2017-12-31 61993858
## 2 2018-12-31 86978635
## 3 2019-12-31 81443008
## 4 2020-12-31 85914707
## 5 2021-12-31 89938901
## 6 2022-09-30 82963816
head(ventas_meses)
##          año   meses total_mensual
## 1 2020-01-31   Enero       6059791
## 2 2020-02-29 Febrero       6643181
## 3 2020-03-31   Marzo       8368674
## 4 2020-04-30   Abril       4925778
## 5 2020-05-31    Mayo       2235669
## 6 2020-06-30   Junio       7842003

Glosario de la base de datos de Ventas

Ventas Anuales:

  • año: El año al que corresponde el registro de ventas.
  • ventas: El total de ventas registrado para el año correspondiente.

Ventas Mensuales:

  • año: El año al que corresponde el registro de ventas mensuales.
  • meses: El mes al que corresponde el registro de ventas mensuales.
  • total_mensual: El total de ventas mensuales registrado para el mes correspondiente.

EDA de Ventas

str(ventas_meses)
## 'data.frame':    33 obs. of  3 variables:
##  $ año          : Date, format: "2020-01-31" "2020-02-29" ...
##  $ meses        : chr  "Enero" "Febrero" "Marzo" "Abril" ...
##  $ total_mensual: num  6059791 6643181 8368674 4925778 2235669 ...
str(ventas_anuales)
## 'data.frame':    6 obs. of  2 variables:
##  $ año   : Date, format: "2017-12-31" "2018-12-31" ...
##  $ ventas: num  61993858 86978635 81443008 85914707 89938901 ...

Estadistica Descriptiva y Medidas de Dispersión

summary(ventas_anuales)
##       año                 ventas        
##  Min.   :2017-12-31   Min.   :61993858  
##  1st Qu.:2019-04-01   1st Qu.:81823210  
##  Median :2020-07-01   Median :84439262  
##  Mean   :2020-06-15   Mean   :81538821  
##  3rd Qu.:2021-09-30   3rd Qu.:86712653  
##  Max.   :2022-09-30   Max.   :89938901
summary(ventas_meses)
##       año                meses           total_mensual     
##  Min.   :2020-01-31   Length:33          Min.   : 2235669  
##  1st Qu.:2020-09-30   Class :character   1st Qu.: 6358278  
##  Median :2021-05-31   Mode  :character   Median : 7872345  
##  Mean   :2021-05-31                      Mean   : 7841740  
##  3rd Qu.:2022-01-31                      3rd Qu.: 9219847  
##  Max.   :2022-09-30                      Max.   :12285123
print(ventas_meses$año)
##  [1] "2020-01-31" "2020-02-29" "2020-03-31" "2020-04-30" "2020-05-31"
##  [6] "2020-06-30" "2020-07-31" "2020-08-31" "2020-09-30" "2020-10-31"
## [11] "2020-11-30" "2020-12-31" "2021-01-31" "2021-02-28" "2021-03-31"
## [16] "2021-04-30" "2021-05-31" "2021-06-30" "2021-07-31" "2021-08-31"
## [21] "2021-09-30" "2021-10-31" "2021-11-30" "2021-12-31" "2022-01-31"
## [26] "2022-02-28" "2022-03-31" "2022-04-30" "2022-05-31" "2022-06-30"
## [31] "2022-07-31" "2022-08-31" "2022-09-30"
describe(ventas_anuales)
## Warning in FUN(newX[, i], ...): ningún argumento finito para min; retornando
## Inf
## Warning in FUN(newX[, i], ...): ningun argumento finito para max; retornando
## -Inf
##        vars n     mean       sd   median  trimmed     mad      min      max
## año       1 6      NaN       NA       NA      NaN      NA      Inf     -Inf
## ventas    2 6 81538821 10033411 84439262 81538821 4103560 61993858 89938901
##           range  skew kurtosis      se
## año        -Inf    NA       NA      NA
## ventas 27945043 -1.09     -0.5 4096123
describe(ventas_meses)
## Warning in FUN(newX[, i], ...): ningún argumento finito para min; retornando
## Inf

## Warning in FUN(newX[, i], ...): ningun argumento finito para max; retornando
## -Inf
##               vars  n       mean         sd  median    trimmed        mad
## año              1 33        NaN         NA      NA        NaN         NA
## meses*           2 33       6.36       3.46       6       6.33       4.45
## total_mensual    3 33 7841740.15 2227534.45 7872345 7845946.93 2108454.39
##                   min      max    range  skew kurtosis       se
## año               Inf     -Inf     -Inf    NA       NA       NA
## meses*              1       12       11  0.05    -1.23      0.6
## total_mensual 2235669 12285123 10049454 -0.10    -0.25 387764.0
var(ventas_anuales)
##        año       ventas
## año     NA           NA
## ventas  NA 1.006693e+14
var(ventas_meses)
##               año meses total_mensual
## año            NA    NA            NA
## meses          NA    NA            NA
## total_mensual  NA    NA   4.96191e+12

Visualizar las Ventas por Mes y Año

# Gráfico de ventas mensuales
ggplot(ventas_meses, aes(x = año, y = total_mensual)) +
  geom_col(fill = "lightblue", color = "blue") +
  labs(x = "Año", y = "Ventas", title = "Ventas Anuales")

ggplot(ventas_anuales, aes(x = año, y = ventas)) +
  geom_col(fill = "salmon", color = "red") +
  labs(x = "Año", y = "Ventas", title = "Ventas Anuales")

porcentaje_ventas <- ventas_anuales$ventas / sum(ventas_anuales$ventas) * 100
pie(ventas_anuales$ventas, labels = paste(ventas_anuales$año, ": ", round(porcentaje_ventas, 2), "%"), 
    main = "Distribución de Ventas Anuales")

Mejor Mes y Año de Ventas

ventas_mensuales_xts<-xts(ventas_meses$total_mensual,order.by=ventas_meses$año)
dygraph(ventas_mensuales_xts, main = "Ventas Mensuales") %>% 
  dyOptions(colors = RColorBrewer::brewer.pal(4, "Dark2")) %>%
  dyShading(from = "2020-12-01",
            to = "2020-12-31", 
            color = "#FFE6E6")
ventas_anuales_xts<-xts(ventas_anuales$ventas,order.by=ventas_anuales$año)
dygraph(ventas_anuales_xts, main = "Ventas Anuales") %>% 
  dyOptions(colors = RColorBrewer::brewer.pal(4, "Dark2")) %>%
  dyShading(from = "2021-04-09",
            to = "2021-12-31", 
            color = "#FFE6E6")

Este gráfico de líneas muestra los datos de ventas mensuales de la empresa desde enero de 2020 hasta Septiembre de 2022. El gráfico exhibe cuenta con picos y bajadas que ocurren en intervalos regulares, probablemente correspondientes a diferentes estaciones o períodos del año. Hay una tendencia general al alza en las ventas, con el pico más alto ocurriendo hacia el final del período de tiempo mostrado.

Podemos ver que las mejores ventas mensuales que ha tenido durante los años fueron las fechas de: * Diciembre del 2020 = $12,300,000 * Febrero del 2021 = $11,200,000 * Septiembre del 2022 = $11,600,000

Y de las mayores ventas anuales fue en el 2021. Exactamente en abril 10 de ese año, se cumple las ventas del 2018 que fueron 87,000,000, que para esos años era el año donde recibieron mayores ventas. Y acabando el año 2021 se llego a un nuevo record en ventas siendo mayores a $89,900,000, y fue tan solo hasta Septiembre de ese año, sin embargo FORM estimaba hasta 110 millones en ventas.

Prónosticos

Pronóstico de Promedios Móviles en R

# Agregar filas para los años 2023 y 2024
ventas_anuales_nuevas <- rbind(ventas_anuales,
                               data.frame(año = as.Date("2023-12-31"), ventas = NA),
                               data.frame(año = as.Date("2024-12-31"), ventas = NA))

print(ventas_anuales_nuevas)
##          año   ventas
## 1 2017-12-31 61993858
## 2 2018-12-31 86978635
## 3 2019-12-31 81443008
## 4 2020-12-31 85914707
## 5 2021-12-31 89938901
## 6 2022-09-30 82963816
## 7 2023-12-31       NA
## 8 2024-12-31       NA
# Crear un vector con las fechas de final de los meses de Octubre 2022 a Septiembre 2023
fechas_nuevas <- seq(as.Date("2022-10-31"), as.Date("2023-09-30"), by = "month")

# Crear un nuevo dataframe con las fechas y ventas a NA
nuevas_filas <- data.frame(año = fechas_nuevas, 
                           meses = format(fechas_nuevas, "%B"),
                           total_mensual = NA)

# Unir el nuevo dataframe con el original
ventas_meses_nuevas <- rbind(ventas_meses, nuevas_filas)

print(ventas_meses_nuevas)
##           año      meses total_mensual
## 1  2020-01-31      Enero       6059791
## 2  2020-02-29    Febrero       6643181
## 3  2020-03-31      Marzo       8368674
## 4  2020-04-30      Abril       4925778
## 5  2020-05-31       Mayo       2235669
## 6  2020-06-30      Junio       7842003
## 7  2020-07-31      Julio       5599913
## 8  2020-08-31     Agosto       8883507
## 9  2020-09-30 Septiembre       7452457
## 10 2020-10-31    Octubre       8078683
## 11 2020-11-30  Noviembre       7539929
## 12 2020-12-31  Diciembre      12285123
## 13 2021-01-31      Enero       9294478
## 14 2021-02-28    Febrero      11179236
## 15 2021-03-31      Marzo      10360017
## 16 2021-04-30      Abril       7872345
## 17 2021-05-31       Mayo       9219847
## 18 2021-06-30      Junio       5407600
## 19 2021-07-31      Julio       7936029
## 20 2021-08-31     Agosto       4733524
## 21 2021-09-30 Septiembre       6358278
## 22 2021-10-31    Octubre       5123874
## 23 2021-11-30  Noviembre       5913523
## 24 2021-12-31  Diciembre       6500150
## 25 2022-01-31      Enero       7534073
## 26 2022-02-28    Febrero       7898590
## 27 2022-03-31      Marzo      10597117
## 28 2022-04-30      Abril       8397928
## 29 2022-05-31       Mayo       7786912
## 30 2022-06-30      Junio       8623444
## 31 2022-07-31      Julio       9495207
## 32 2022-08-31     Agosto      11053017
## 33 2022-09-30 Septiembre      11577528
## 34 2022-10-31    octubre            NA
## 35 2022-12-01  diciembre            NA
## 36 2022-12-31  diciembre            NA
## 37 2023-01-31      enero            NA
## 38 2023-03-03      marzo            NA
## 39 2023-03-31      marzo            NA
## 40 2023-05-01       mayo            NA
## 41 2023-05-31       mayo            NA
## 42 2023-07-01      julio            NA
## 43 2023-07-31      julio            NA
## 44 2023-08-31     agosto            NA
pronostico_mensuales_xts<-xts(ventas_meses_nuevas$total_mensual,order.by=ventas_meses_nuevas$año)
pronostico_anuales_xts<-xts(ventas_anuales_nuevas$ventas,order.by=ventas_anuales_nuevas$año)

promedio_movil_mensual <- rollmean(pronostico_mensuales_xts, k = 12, align = "right", fill = NA)
promedio_movil_anual <- rollapply(pronostico_anuales_xts, width = 3, FUN = mean, by = 1, align = "right", fill = NA)

# Convertir promedios móviles a objetos de serie temporal
promedio_movil_mensual_ts <- ts(coredata(promedio_movil_mensual), start = start(pronostico_mensuales_xts), frequency = frequency(pronostico_mensuales_xts))
promedio_movil_anual_ts <- ts(coredata(promedio_movil_anual), start = start(pronostico_anuales_xts), frequency = frequency(pronostico_anuales_xts))

# Gráfico de pronóstico de promedio móvil mensual
autoplot(promedio_movil_mensual_ts) +
  labs(title = "Movimiento del Pronóstico de Promedio Móvil Mensual", x = "Fecha", y = "Ventas") +
  theme_minimal()

# Gráfico de pronóstico de promedio móvil anual
autoplot(promedio_movil_anual_ts) +
  labs(title = "Movimiento del Pronóstico de Promedio Móvil Anual", x = "Año", y = "Ventas") +
  theme_minimal()

# Extender el promedio móvil en el futuro para hacer pronósticos
# Supongamos que queremos pronosticar 12 meses hacia adelante
nuevas_fechas_mensuales <- seq(max(index(pronostico_mensuales_xts)) + 1, length.out = 12, by = "months")
pronostico_mensual <- zoo(NA, order.by = nuevas_fechas_mensuales)
for (i in seq_along(nuevas_fechas_mensuales)) {
  pronostico_mensual[i] <- mean(tail(pronostico_mensuales_xts, 12))
}

# Gráfico de pronóstico de ventas mensuales
plot(pronostico_mensuales_xts, main = "Pronóstico de Ventas Mensuales con Promedio Móvil", xlab = "Año", ylab = "Ventas")

lines(promedio_movil_mensual, col = "blue")
lines(pronostico_mensual, col = "red", lty = 2)
legend("topright", legend = c("Ventas Mensuales", "Promedio Móvil", "Pronóstico"), col = c("black", "blue", "red"), lty = c(1, 1, 2))

# Extender el promedio móvil en el futuro para hacer pronósticos
# Supongamos que queremos pronosticar 2 años hacia adelante
nuevas_fechas_anuales <- seq(max(index(pronostico_anuales_xts)) + 1, length.out = 2, by = "years")
pronostico_anual <- zoo(NA, order.by = nuevas_fechas_anuales)
for (i in seq_along(nuevas_fechas_anuales)) {
  pronostico_anual[i] <- mean(tail(pronostico_anuales_xts, 3))
}

# Gráfico de pronóstico de ventas anuales
plot(pronostico_anuales_xts, main = "Pronóstico de Ventas Anuales con Promedio Móvil", xlab = "Año", ylab = "Ventas")

lines(promedio_movil_anual, col = "blue")
lines(pronostico_anual, col = "red", lty = 2)
legend("topright", legend = c("Ventas Anuales", "Promedio Móvil", "Pronóstico"), col = c("black", "blue", "red"), lty = c(1, 1, 2))

Pronóstico de Promedios Móviles en Excel

Las ventas mensuales reflejan un patrón cíclico con meses de alta demanda, probablemente por factores estacionales o promocionales, donde el pronóstico captura adecuadamente las tendencias pero requiere ajustes para mayor precisión. A nivel anual, las ventas muestran un crecimiento sostenido, a pesar de un año con descenso significativo, y el pronóstico sigue de cerca la tendencia real, aunque también necesita mejoras para reducir las discrepancias observadas.

Hallazgos de Ventas

  1. Tenemos los datos de ventas mensuales desde enero de 2020 hasta septiembre de 2022, y los datos de ventas anuales del 2017 a Septiembre del 2022
  2. Se identifica un patrón estacional evidente, con picos y caídas recurrentes en las ventas mensuales
  3. La tendencia general de las ventas es ascendente, con el pico más alto hacia el final del período.
  4. Los mejores meses de ventas fueron diciembre de 2020, febrero de 2021 y septiembre de 2022.
  5. El año 2021 registró las mayores ventas anuales, alcanzando un récord de $89,900,000 y todavia faltando 3 meses para que acabe el año.
  6. En abril de 2021 se igualaron las ventas de 2018, que eran las más altas hasta ese momento. 7 Aunque hubo un descenso significativo en un año específico posiblemente por factores económicos o del mercado, teniendo una tendencia general que se mantiene positiva.
  7. A nivel mensual, las ventas siguen un patrón cíclico, mientras que a nivel anual muestran una tendencia general ascendente.
  8. Aunque los modelos de pronóstico capturan los patrones estacionales y las tendencias a largo plazo, todavía se puede mejorar su precisión. Ya que igualmente se observan discrepancias entre el pronóstico y las ventas reales, sugiriendo posibles mejoras en el modelo de pronóstico.

Búsqueda de información y datos de las Ventas

  • ¿Qué tipo de información / datos solicitarías al socio formador para mejorar EDA?.
    • Datos detallados de las ventas, integrando desgloses de cada producto, proyectos, regiones.
    • Datos sobre la competencia para hacer un contraste entre las empresas.
  • ¿Qué tipo de información / datos de fuentes secundarias buscarías para mejorar EDA?.
    • Datos sobre el mercado y la industria.
    • Informes de Investigacion del mercado/industria. Esto ayudaria para identificar tendencias en el mercado/industria, segmentaciones e informacion general la cual pueda apoyar los resultados encontrados en el analisis.

Analisis Exploratorio de las Bases de Datos Actualizadas

Ventas (Actualizado)

ventas_clientes2021 <- read_xlsx("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\BASES ACTUALIZADAS\\VentasClientes2021.xlsx")
ventas_clientes2022 <- read_xlsx("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\BASES ACTUALIZADAS\\VentasClientes2022.xlsx")
ventas_clientes2023 <- read_xlsx("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\BASES ACTUALIZADAS\\VentasClientes2023.xlsx")
# Crear el gráfico de barras VENTAS 2021
ggplot(ventas_clientes2021, aes(x = fecha, y = unidades)) +
  geom_bar(stat = "identity", fill = "blue") +
  labs(x = "Fecha", y = "Unidades", title = "Ventas por Fecha en 2021") +
  theme_minimal()

#TOP 5 CLIENTES 2021

# Agrupar por cliente y sumar las unidades
ventas_por_cliente <- ventas_clientes2021 %>%
  group_by(cliente) %>%
  summarise(total_unidades = sum(unidades))

# Ordenar por el total de unidades y seleccionar los 5 primeros
top_5_clientes <- ventas_por_cliente %>%
  arrange(desc(total_unidades)) %>%
  head(5)

# Mostrar el top 5 de clientes que más consumen
print(top_5_clientes)
## # A tibble: 5 × 2
##   cliente                                            total_unidades
##   <chr>                                                       <dbl>
## 1 Stabilus                                                  1001641
## 2 GRUPO ANTOLIN SALTILLO, S. de R.L de C.V.                  877550
## 3 YANFENG INTERNATIONAL AUTOMOTIVE TECHNOLOGY MEXICO          77682
## 4 PO LIGHTING MEXICO                                          59690
## 5 HELLA AUTOMOTIVE MEXICO                                     58948
# Graficar el top 5 de clientes que más consumen
ggplot(top_5_clientes, aes(x = cliente, y = total_unidades)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(title = "Top 5 de Clientes que más Consumen 2021",
       x = "Cliente",
       y = "Total de Unidades Vendidas") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))  # Rotar etiquetas del eje x para mejor legibilidad

# Crear el gráfico de barras VENTAS 2022
ggplot(ventas_clientes2022, aes(x = fecha, y = unidades)) +
  geom_bar(stat = "identity", fill = "blue") +
  labs(x = "Fecha", y = "Unidades", title = "Ventas por Fecha en 2022") +
  theme_minimal()

#TOP 5 CLIENTES 2022

# Agrupar por cliente y sumar las unidades
ventas_por_cliente <- ventas_clientes2022 %>%
  group_by(cliente) %>%
  summarise(total_unidades = sum(unidades))

# Ordenar por el total de unidades y seleccionar los 5 primeros
top_5_clientes <- ventas_por_cliente %>%
  arrange(desc(total_unidades)) %>%
  head(5)

# Mostrar el top 5 de clientes que más consumen
print(top_5_clientes)
## # A tibble: 5 × 2
##   cliente                 total_unidades
##   <chr>                            <dbl>
## 1 Stabilus                       1184928
## 2 HELLA AUTOMOTIVE MEXICO         315795
## 3 TOKAI RIKA MEXICO                86038
## 4 PO LIGHTING MEXICO               50697
## 5 DENSO MEXICO                     32930
# Graficar el top 5 de clientes que más consumen
ggplot(top_5_clientes, aes(x = cliente, y = total_unidades)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(title = "Top 5 de Clientes que más Consumen 2022",
       x = "Cliente",
       y = "Total de Unidades Vendidas") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))  # Rotar etiquetas del eje x para mejor legibilidad

# Crear el gráfico de barras VENTAS 2023
ggplot(ventas_clientes2023, aes(x = fecha, y = unidades)) +
  geom_bar(stat = "identity", fill = "blue") +
  labs(x = "Fecha", y = "Unidades", title = "Ventas por Fecha en 2023") +
  theme_minimal()

#TOP 5 CLIENTES 2023

# Agrupar por cliente y sumar las unidades
ventas_por_cliente <- ventas_clientes2023 %>%
  group_by(cliente) %>%
  summarise(total_unidades = sum(unidades))

# Ordenar por el total de unidades y seleccionar los 5 primeros
top_5_clientes <- ventas_por_cliente %>%
  arrange(desc(total_unidades)) %>%
  head(5)

# Mostrar el top 5 de clientes que más consumen
print(top_5_clientes)
## # A tibble: 5 × 2
##   cliente                 total_unidades
##   <chr>                            <dbl>
## 1 Stabilus                       1438773
## 2 Aptiv Services US, LLC          323696
## 3 HELLA AUTOMOTIVE MEXICO         199965
## 4 DENSO MEXICO                     76593
## 5 TOKAI RIKA MEXICO                75154
# Graficar el top 5 de clientes que más consumen
ggplot(top_5_clientes, aes(x = cliente, y = total_unidades)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(title = "Top 5 de Clientes que más Consumen 2023",
       x = "Cliente",
       y = "Total de Unidades Vendidas") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))  # Rotar etiquetas del eje x para mejor legibilidad

#Top 5 clientes Global

# Concatenar los datos de los tres años
ventas_totales <- rbind(ventas_clientes2021, ventas_clientes2022, ventas_clientes2023)

# Agrupar por cliente y sumar las unidades
ventas_por_cliente <- ventas_totales %>%
  group_by(cliente) %>%
  summarise(total_unidades = sum(unidades))

# Ordenar por el total de unidades y seleccionar los 5 primeros
top_5_clientes_general <- ventas_por_cliente %>%
  arrange(desc(total_unidades)) %>%
  head(5)

# Mostrar el top 5 de clientes que más consumen en general
print(top_5_clientes_general)
## # A tibble: 5 × 2
##   cliente                                   total_unidades
##   <chr>                                              <dbl>
## 1 Stabilus                                         3625342
## 2 GRUPO ANTOLIN SALTILLO, S. de R.L de C.V.         877550
## 3 HELLA AUTOMOTIVE MEXICO                           574708
## 4 Aptiv Services US, LLC                            323696
## 5 TOKAI RIKA MEXICO                                 203311
# Graficar el top 5 general de clientes que más consumen
ggplot(top_5_clientes_general, aes(x = cliente, y = total_unidades)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(title = "Top 5 de Clientes que más Consumen (2021-2023)",
       x = "Cliente",
       y = "Total de Unidades Vendidas") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))  # Rotar etiquetas del eje x para mejor legibilidad

RH (Actualizado)

operativa_FORM2024 <- readxl::read_excel("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\BASES ACTUALIZADAS\\Datos_FORM_RH_FJ2024.xlsx", sheet = "Operativa")
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
## • `` -> `...19`
## • `` -> `...20`
## • `` -> `...21`
## • `` -> `...22`
## • `` -> `...23`
## • `` -> `...24`
## • `` -> `...25`
## • `` -> `...26`
## • `` -> `...27`
## • `` -> `...28`
## • `` -> `...29`
## • `` -> `...30`
operativa_FORM2024
## # A tibble: 613 × 30
##    ...1  ...2    `BDD OPERATIVA` ...4  ...5  ...6  ...7  ...8  ...9  ...10 ...11
##    <chr> <chr>   <chr>           <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
##  1 <NA>  <NA>    <NA>            <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  2 <NA>  <NA>    <NA>            <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  3 <NA>  <NA>    <NA>            <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  4 <NA>  <NA>    <NA>            <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  5 <NA>  <NA>    <NA>            <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  6 <NA>  <NA>    <NA>            <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA>  <NA> 
##  7 No.   Apelli… Nombre          Fech… Géne… RFC   Fech… Prim… Cuar… Fech… Pues…
##  8 10    Luna L… Yolanda Judith  31277 Feme… LULY… 42786 42816 42906 45201 Cost…
##  9 12    Suarez… Julio Cesar     25381 Masc… SURJ… 43070 43100 43190 44931 Gest…
## 10 13    Cruz R… Victor Abel     32680 Masc… CURV… 43182 43212 43302 45230 Chof…
## # ℹ 603 more rows
## # ℹ 19 more variables: ...12 <chr>, ...13 <chr>, ...14 <chr>, ...15 <chr>,
## #   ...16 <chr>, ...17 <chr>, ...18 <chr>, ...19 <chr>, ...20 <chr>,
## #   ...21 <chr>, ...22 <chr>, ...23 <chr>, ...24 <chr>, ...25 <chr>,
## #   ...26 <chr>, ...27 <chr>, ...28 <chr>, ...29 <chr>, ...30 <chr>
# Eliminar las primeras 6 filas
operativa_FORM2024 <- operativa_FORM2024 %>%
  slice(-(1:6))
operativa_FORM2024
## # A tibble: 607 × 30
##    ...1    ...2  `BDD OPERATIVA` ...4  ...5  ...6  ...7  ...8  ...9  ...10 ...11
##    <chr>   <chr> <chr>           <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
##  1 No.     Apel… Nombre          Fech… Géne… RFC   Fech… Prim… Cuar… Fech… Pues…
##  2 10      Luna… Yolanda Judith  31277 Feme… LULY… 42786 42816 42906 45201 Cost…
##  3 12      Suar… Julio Cesar     25381 Masc… SURJ… 43070 43100 43190 44931 Gest…
##  4 13      Cruz… Victor Abel     32680 Masc… CURV… 43182 43212 43302 45230 Chof…
##  5 14      Espa… Lucero Shanyeza 35754 Feme… EAPL… 43349 43379 43469 <NA>  Lider
##  6 19      Garc… Yuliana Mireya  30913 Feme… GAPY… 43587 43617 43707 45342 Ayud…
##  7 20      Yabe… Mario Alberto   33048 Masc… YAAM… 43676 43706 43796 44944 Resi…
##  8 29      Lope… Martin          28548 Masc… LOTM… 44063 44093 44183 45004 Ayud…
##  9 32.501… Rodr… Nicolas De Jes… 33614 Masc… ROMN… 44138 44168 44258 <NA>  Ayud…
## 10 34.650… Cele… Jaime           30104 Masc… CEBJ… 44243 44273 44363 45044 Pint…
## # ℹ 597 more rows
## # ℹ 19 more variables: ...12 <chr>, ...13 <chr>, ...14 <chr>, ...15 <chr>,
## #   ...16 <chr>, ...17 <chr>, ...18 <chr>, ...19 <chr>, ...20 <chr>,
## #   ...21 <chr>, ...22 <chr>, ...23 <chr>, ...24 <chr>, ...25 <chr>,
## #   ...26 <chr>, ...27 <chr>, ...28 <chr>, ...29 <chr>, ...30 <chr>
# Tomar la primera fila como nombres de las columnas
nuevos_nombres <- as.character(unlist(operativa_FORM2024[1,]))
operativa_FORM2024 <- operativa_FORM2024[-1,]  # Eliminar la primera fila
colnames(operativa_FORM2024) <- nuevos_nombres
# Usando names()
columnas <- names(operativa_FORM2024)
print(columnas)
##  [1] "No."                         "Apellido"                   
##  [3] "Nombre"                      "Fecha de nacimiento"        
##  [5] "Género"                      "RFC"                        
##  [7] "Fecha de Alta"               "Primer Mes"                 
##  [9] "Cuarto Mes"                  "Fecha de Baja"              
## [11] "Puesto"                      "Dpto"                       
## [13] "Imss"                        "SD"                         
## [15] "Factor de Crédito Infonavit" "No. De Crédito Infonavit"   
## [17] "Lugar de Nacimiento"         "CURP"                       
## [19] "Calle"                       "Número"                     
## [21] "Colonia"                     "Municipio"                  
## [23] "Estado"                      "CP"                         
## [25] "Estado Civil"                "Número de Télefono"         
## [27] "Banco"                       "Correo Electronico"         
## [29] "Causa de Baja"               "Observaciones de baja"
# Reenombrar la columna Estado Civil a Estado_Civil
operativa_FORM2024 <- rename(operativa_FORM2024, Estado_Civil = `Estado Civil`)
columnas <- names(operativa_FORM2024)
print(columnas)
##  [1] "No."                         "Apellido"                   
##  [3] "Nombre"                      "Fecha de nacimiento"        
##  [5] "Género"                      "RFC"                        
##  [7] "Fecha de Alta"               "Primer Mes"                 
##  [9] "Cuarto Mes"                  "Fecha de Baja"              
## [11] "Puesto"                      "Dpto"                       
## [13] "Imss"                        "SD"                         
## [15] "Factor de Crédito Infonavit" "No. De Crédito Infonavit"   
## [17] "Lugar de Nacimiento"         "CURP"                       
## [19] "Calle"                       "Número"                     
## [21] "Colonia"                     "Municipio"                  
## [23] "Estado"                      "CP"                         
## [25] "Estado_Civil"                "Número de Télefono"         
## [27] "Banco"                       "Correo Electronico"         
## [29] "Causa de Baja"               "Observaciones de baja"
# Contar la cantidad de trabajadores por estado civil
conteo_estado_civil <- operativa_FORM2024 %>%
  group_by(Estado_Civil) %>%
  summarise(Cantidad_Trabajadores = n())

# Ordenar los estados civiles
conteo_estado_civil <- conteo_estado_civil %>%
  arrange(Estado_Civil)

# Crear el gráfico de barras
ggplot(conteo_estado_civil, aes(x = Estado_Civil, y = Cantidad_Trabajadores, fill = Estado_Civil)) +
  geom_bar(stat = "identity") +
  labs(x = "Estado Civil", y = "Cantidad de Trabajadores", title = "Distribución de Trabajadores por Estado Civil") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

library(readxl)
library(dplyr)
library(ggplot2)

# Registros por Genero

# Contar la cantidad de registros por género
conteo_genero <- operativa_FORM2024 %>%
  group_by(Género) %>%
  summarise(Cantidad = n())

# Calcular los porcentajes de género
conteo_genero <- conteo_genero %>%
  mutate(Porcentaje = (Cantidad / sum(Cantidad)) * 100)

# Crear el gráfico de barras
ggplot(conteo_genero, aes(x = Género, y = Cantidad, fill = Género)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = paste(round(Porcentaje, 1), "%"), y = Cantidad), vjust = -0.5, size = 3, color = "black") +
  labs(x = "Género", y = "Cantidad", title = "Distribución de Género") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

administrativa_FORM2024 <- readxl::read_excel("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\BASES ACTUALIZADAS\\Datos_FORM_RH_FJ2024.xlsx", sheet = "Administrativa")
administrativa_FORM2024
## # A tibble: 19 × 26
##      No. Apellidos Nombre `Fecha de Nacimiento` Género RFC   `Fecha de Alta`    
##    <dbl> <chr>     <chr>  <dttm>                <chr>  <chr> <dttm>             
##  1  17   Ramirez … Sandr… 1990-02-11 00:00:00   FEMEN… RARS… 2022-08-22 00:00:00
##  2  30   De Luna … Lluvia 2002-06-12 00:00:00   FEMEN… LURL… 2023-10-23 00:00:00
##  3  31   Contrera… Melin… 1985-10-12 00:00:00   FEMEN… COLM… 2023-12-01 00:00:00
##  4  32   Romero R… Nayda… 1993-10-29 00:00:00   FEMEN… RORN… 2023-12-04 00:00:00
##  5  28   Granados… Sonia… 1984-06-22 00:00:00   FEMEN… GASS… 2023-08-21 00:00:00
##  6  28   Sauri Vi… Said   2001-12-05 00:00:00   MASCU… SAVS… 2023-08-16 00:00:00
##  7  31   Garcia V… Deysy… 1997-07-05 00:00:00   FEMEN… GAVD… 2023-09-26 00:00:00
##  8  21   Ayala Za… Valer… 2001-09-12 00:00:00   FEMEN… AAZV… 2023-03-07 00:00:00
##  9  17   Hidalgo … Miguel 1995-03-07 00:00:00   MASCU… HIMM… 2022-06-13 00:00:00
## 10   1   Del Ange… Victo… 1990-12-23 00:00:00   FEMEN… AEAV… 2019-10-28 00:00:00
## 11  24   Sanchez … Lilia… 1988-08-16 00:00:00   FEMEN… SAML… 2023-04-03 00:00:00
## 12  26   Echavarr… Maria… 1998-12-30 00:00:00   FEMEN… EAGM… 2023-04-03 00:00:00
## 13  18   Gonzalez… Luis … 1999-06-24 00:00:00   MASCU… GOBL… 2022-06-08 00:00:00
## 14  23   Ibarra G… Janet… 1989-11-18 00:00:00   FEMEN… IAGJ… 2022-07-05 00:00:00
## 15  25.4 Lopez Ca… Yosse… 1994-10-25 00:00:00   FEMEN… LOCY… 2022-11-09 00:00:00
## 16   9   Jara Ast… Rober… 1994-01-07 00:00:00   MASCU… JAAR… 2019-10-31 00:00:00
## 17  15   Rodrigue… Laura… 1987-01-15 00:00:00   FEMEN… ROAL… 2021-05-17 00:00:00
## 18  20   Lezama R… Rocio  1991-05-10 00:00:00   FEMEN… LERR… 2022-03-24 00:00:00
## 19   3   Gonzalez… Elia … 1995-09-22 00:00:00   FEMEN… GOCE… 2020-04-16 00:00:00
## # ℹ 19 more variables: `Cuarto Mes` <dttm>, Baja <dttm>, Puesto <chr>,
## #   Dpto. <chr>, Imss <chr>, `Lugar de Nacimiento` <chr>, CURP <chr>,
## #   Calle <chr>, Número <chr>, Colonia <chr>, Municipio <chr>, Estado <chr>,
## #   CP <chr>, Estado_Civil <chr>, `Número de Télefono` <dbl>, Banco <chr>,
## #   Correo_Electronico <chr>, Causa_de_Baja <lgl>, Observaciones_de_baja <chr>
# Contar la cantidad de trabajadores por estado civil
conteo_estado_civil <- administrativa_FORM2024 %>%
  group_by(Estado_Civil) %>%
  summarise(Cantidad_Trabajadores = n())

# Ordenar los estados civiles
conteo_estado_civil <- conteo_estado_civil %>%
  arrange(Estado_Civil)

# Crear el gráfico de barras
ggplot(conteo_estado_civil, aes(x = Estado_Civil, y = Cantidad_Trabajadores, fill = Estado_Civil)) +
  geom_bar(stat = "identity") +
  labs(x = "Estado Civil", y = "Cantidad de Trabajadores", title = "Distribución de Trabajadores por Estado Civil") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

library(readxl)
library(dplyr)
library(ggplot2)

# Registros por Genero

# Contar la cantidad de registros por género
conteo_genero <- administrativa_FORM2024 %>%
  group_by(Género) %>%
  summarise(Cantidad = n())

# Calcular los porcentajes de género
conteo_genero <- conteo_genero %>%
  mutate(Porcentaje = (Cantidad / sum(Cantidad)) * 100)

# Crear el gráfico de barras
ggplot(conteo_genero, aes(x = Género, y = Cantidad, fill = Género)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = paste(round(Porcentaje, 1), "%"), y = Cantidad), vjust = -0.5, size = 3, color = "black") +
  labs(x = "Género", y = "Cantidad", title = "Distribución de Género") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Carton / Papel (Actualizado)

papelcarton <- read_xlsx("C:\\Users\\lesda_b5wfqqa\\Downloads\\ev1\\BASES ACTUALIZADAS\\ied_carton_papel_2023.xlsx")
papelcarton
## # A tibble: 99 × 5
##     Year Quarter IED_Fab_Carton_Papel Tipo_Cambio         INPC
##    <dbl> <chr>                  <dbl> <chr>              <dbl>
##  1  1999 I                     -61.3  9.5158000000000005  41.4
##  2  1999 II                      1.85 9.4875000000000007  42.3
##  3  1999 III                     6.79 9.3582000000000001  43.2
##  4  1999 IV                     25.7  9.5221999999999998  44.3
##  5  2000 I                      22.8  9.2331000000000003  45.6
##  6  2000 II                     22.2  9.9537999999999993  46.3
##  7  2000 III                     8.21 9.4290000000000003  47.1
##  8  2000 IV                     22.8  9.5997000000000003  48.3
##  9  2001 I                       3.04 9.5203000000000007  48.9
## 10  2001 II                     22.0  9.09                49.3
## # ℹ 89 more rows
# Seleccionar las columnas "Year" y "Tipo_Cambio"
# Crea una trendline entre el Year y el Tipo_Cambio
trendline1 <- ggplot(papelcarton, aes(x = Year, y = Tipo_Cambio)) +
  geom_smooth(method = "lm", se = FALSE) +
  geom_point() +
  labs(title = "Trendline de Tipo de Cambio por Año")

# Crea una gráfica por año y quarter
by_year_quarter <- ggplot(papelcarton, aes(x = Quarter, y = INPC, group = Year, color = factor(Year))) +
  geom_line() +
  geom_point() +
  labs(title = "INPC por Quarters (Color por Año)", x = "Quarter")

# Crea una gráfica por año de IED Fab Carton Papel e INPC
by_year <- ggplot(papelcarton, aes(x = Year)) +
  geom_line(aes(y = INPC, color = "INPC")) +
  labs(title = "INPC por Año", y = "Valor") +
  scale_color_manual(values = "red", labels = c( "INPC"))

# Mostrar las gráficas
print(trendline1)
## `geom_smooth()` using formula = 'y ~ x'

print(by_year_quarter)

print(by_year)

Principales Hallazgos

** Es necesario buscar una nueva alternativa para combatir el calor en las áreas de trabajo

** A nivel mensual, las ventas siguen un patrón cíclico, mientras que a nivel anual muestran una tendencia general ascendente.

** Aunque los valores reales de las ventas se ajustan a los patrones. Todavia se pueden hacer mejoras ya que se tienen discrepancias.

** Se tiene esperado un incremento significativo pero esperado en el nearshoring, incrementando la competitividad de la industria.

** Tomar medidas ante el acoso laboral hacia las trabajadoras y trabajadores solteros.

** Potenciar las fortalezas con menor enfoque que son de mayor importancia para evitar que el 65.1% de las trabajadoras decidan ya no continuar en la empresa.

** Con base al analisis de ventas definir metas a corto, mediano y largo plazo. Pues de esta manera lograremos observar a mayor medida el crecimiento de la empresa o las areas de mejora.

Referencias

or, R. (2021, August 23). The Form Way -. Form. https://form.com.mx/the-form-way/

for, R. (2021, September 27). Form right form of packing. Form. https://form.com.mx/

for, R. (2021, August 23). ¿Por qué Nosotros? -. Forma. https://form.com.mx/por-que-nosotros/ El Economista. (2022, August 29). Pase para gol en Norteamérica: la Ley de Reducción de Inflación. El Economista; El Economista. https://www.eleconomista.com.mx/opinion/Pase-para-gol-en-Norteamerica-la-Ley-de-Reduccion-de-Inflacion-20220829-0044.html

Adrián Duhalt. (2024, January 23). México y la Ley para la Reducción de la Inflación en EU. Expansión. https://expansion.mx/opinion/2024/01/23/mexico-y-la-ley-para-la-reduccion-de-la-inflacion-en-eu DW Español. (2023). México, EE. UU. y Canadá quieren liderar la producción mundial de vehículos eléctricos [YouTube Video]. En YouTube. https://www.youtube.com/watch?v=RHp_jSssWMg

Ricardo, D. (2023, February 6). Tendencias en packaging y sostenibilidad para el 2023. Plastico; Plastico. https://www.plastico.com/es/noticias/tendencias-en-packaging-y-sostenibilidad-para-el-2023

Contreras, J., & Contreras, J. (2024b, enero 24). Marcas más valiosas del mundo 2024: Empresas mexicanas destacan en el ranking. Líder Empresarial.https://www.liderempresarial.com/marcas-mas-valiosas-del-mundo-2024-empresas-mexicanas-destacan-en-el-ranking/

Human verification. (s. f.). https://www.eleconomista.com.mx/economia/Inflacion-inicia-el-2024-acelerandose-a-4.90-hila-5-quincenas-al-alza-20240124-0018.html

Importancia de las tendencias de mecado 2024 - Bing. (s. f.). Bing. https://www.bing.com/search?q=Importancia+de+las+Tendencias+de+Mecado+2024&qs=n&form=QBRE&sp=-1&ghc=1&lq=0&pq=importancia+de+las+tendencias+de+mecado+202&sc=11-43&sk=&cvid=D94910A78070405D8C72239C816AFAF0&ghsh=0&ghacc=0&ghpl=

Innovación en la empresa: concepto, importancia y tipologías. (s. f.). UNIR México. https://mexico.unir.net/economia/noticias/innovacion-en-una-empresa/#:~:text=La%20innovaci%C3%B3n%20empresarial%20se%20ha%20vuelto%20clave%20derivado,8%20A%C3%B1ade%20valor%20a%20los%20productos%20o%20servicios.

¿Qué es la automatización? | IBM. (s. f.). https://www.ibm.com/mx-es/topics/automation

Empaques sustentables - Bing. (s. f.). Bing. https://www.bing.com/search?pglt=41&q=Empaques+Sustentables&cvid=81e1393f3b7d42429057e254cb1321cb&gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIGCAEQABhAMgYIAhAAGEAyBggDEAAYQDIGCAQQABhA0gEHMzQyajBqMagCALACAA&FORM=ANNTA1&PC=LCTS

De las Mujeres, I. N. (s. f.). Las Madres en Cifras. gob.mx. https://www.gob.mx/inmujeres/articulos/las-madres-en-cifras

Alcaldes de México (2022, March 22). Nuevo León reduce presión del agua en área metropolitana por sequía. Alcaldes de México. [Imagen] https://www.alcaldesdemexico.com/notas-principales/nuevo-leon-reduce-presion-del-agua-en-area-metropolitana-por-sequia/

LS0tDQp0aXRsZTogIkV2aWRlbmNpYSAxIg0KYXV0aG9yOiAiTEVTTFkgUk9NRVJPIEEwMTc3MTEyNyINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUNCi0tLQ0KDQohW10oQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcTE9HTyBURUMucG5nKQ0KDQoNCioqUG9yOioqIExlc2x5IERhcmlhbiBSb21lcm8gVmF6cXVleiAtIEEwMTc3MTEyNw0KDQoNCg0KIyBJbnRyb2R1Y2Npw7NuDQoNCiMjIGkpIMK/UXXDqSBlcyB1biBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvIGRlIGxvcyBkYXRvcz8NCg0KRWwgYW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBkZSBsb3MgZGF0b3MgKEVEQSwgcG9yIHN1cyBzaWdsYXMgZW4gaW5nbMOpcykgZXMgdW4gZW5mb3F1ZSBlbiBlc3RhZMOtc3RpY2EgcXVlIHNlIGVuZm9jYSBlbiBpbnNwZWNjaW9uYXIsIGxpbXBpYXIgeSBtb2RlbGFyIGNvbmp1bnRvcyBkZSBkYXRvcyBjb24gZWwgb2JqZXRpdm8gZGUgZGVzY3VicmlyIHBhdHJvbmVzLCBhbm9tYWzDrWFzLCB0ZW5kZW5jaWFzIHkgcmVsYWNpb25lcyBlbnRyZSB2YXJpYWJsZXMsIHF1ZSBubyBzZSBoYWJyw61hbiBpZGVudGlmaWNhZG8gbWVkaWFudGUgbcOpdG9kb3MgZXN0YWTDrXN0aWNvcyBmb3JtYWxlcy4gRXN0ZSB0aXBvIGRlIGFuw6FsaXNpcyBlcyBmdW5kYW1lbnRhbCBlbiBsYSBmYXNlIHByZWxpbWluYXIgZGUgY3VhbHF1aWVyIHByb3llY3RvIGRlIGRhdG9zIHkgc2UgdXRpbGl6YSBhbXBsaWFtZW50ZSBhbnRlcyBkZSByZWFsaXphciBpbmZlcmVuY2lhcyBlc3RhZMOtc3RpY2FzIG3DoXMgY29tcGxlamFzIG8gY29uc3RydWlyIG1vZGVsb3MgcHJlZGljdGl2b3MuDQoNCkVsIEVEQSBlcyBmdW5kYW1lbnRhbG1lbnRlIHZpc3VhbCB5IGRlc2NyaXB0aXZvLCBlbXBsZWFuZG8gdW5hIHZhcmllZGFkIGRlIHTDqWNuaWNhcyBncsOhZmljYXMgeSBjdWFudGl0YXRpdmFzIHBhcmEgYW5hbGl6YXIgbG9zIGRhdG9zLiBFbnRyZSBsYXMgaGVycmFtaWVudGFzIG3DoXMgY29tdW5lcyBzZSBlbmN1ZW50cmFuIGxvcyBoaXN0b2dyYW1hcywgZGlhZ3JhbWFzIGRlIGRpc3BlcnNpw7NuLCBncsOhZmljb3MgZGUgY2FqYSB5IGJpZ290ZXMgKGJveCBwbG90cyksIHkgbWFwYXMgZGUgY2Fsb3IsIGxvcyBjdWFsZXMgcGVybWl0ZW4gYSBsb3MgYW5hbGlzdGFzIHkgY2llbnTDrWZpY29zIGRlIGRhdG9zIG9ic2VydmFyIGxhcyBkaXN0cmlidWNpb25lcyB5IHJlbGFjaW9uZXMgZGUgbGFzIHZhcmlhYmxlcyBkZSBtYW5lcmEgaW50dWl0aXZhLiBBZGVtw6FzLCBlbCBFREEgaW52b2x1Y3JhIGVsIHVzbyBkZSBlc3RhZMOtc3RpY2FzIGRlc2NyaXB0aXZhcywgY29tbyBsYSBtZWRpYSwgbWVkaWFuYSwgbW9kYSwgdmFyaWFuemEsIHkgY29ycmVsYWNpw7NuIHBhcmEgcmVzdW1pciBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBwcmluY2lwYWxlcyBkZSBsb3MgY29uanVudG9zIGRlIGRhdG9zLg0KDQpVbmEgcGFydGUgY3J1Y2lhbCBkZWwgRURBIGVzIGxhIGxpbXBpZXphIGRlIGRhdG9zLCBxdWUgaW5jbHV5ZSBsYSBpZGVudGlmaWNhY2nDs24geSBtYW5lam8gZGUgdmFsb3JlcyBhdMOtcGljb3MsIGRhdG9zIGZhbHRhbnRlcyB5IGVycm9yZXMgZGUgZW50cmFkYSwgYXNlZ3VyYW5kbyBhc8OtIGxhIGNhbGlkYWQgeSBmaWFiaWxpZGFkIGRlIGxvcyBhbsOhbGlzaXMgcG9zdGVyaW9yZXMuIEVsIEVEQSB0YW1iacOpbiBwdWVkZSBpbXBsaWNhciBsYSB0cmFuc2Zvcm1hY2nDs24gZGUgZGF0b3MsIGRvbmRlIHNlIG1vZGlmaWNhbiBvIHNlIGNyZWFuIG51ZXZhcyB2YXJpYWJsZXMgcGFyYSBmYWNpbGl0YXIgZWwgYW7DoWxpc2lzLg0KDQoNCg0KIyMgaWkpIMK/Q8OzbW8gY29udHJpYnV5ZSBlbCBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvIGRlIGxvcyBkYXRvcyBhIG1lam9yYXIgZWwgcHJvY2VzbyB5IGxvcyByZXN1bHRhZG9zIGRlIGFuYWzDrXRpY2EgZGVzY3JpcHRpdmE/DQoNCkVsIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgbG9zIGRhdG9zIGNvbnRyaWJ1eWUgc2lnbmlmaWNhdGl2YW1lbnRlIGEgbWVqb3JhciB0YW50byBlbCBwcm9jZXNvIGNvbW8gbG9zIHJlc3VsdGFkb3MgZGUgbGEgYW5hbMOtdGljYSBkZXNjcmlwdGl2YSBkZSB2YXJpYXMgbWFuZXJhczoNCg0KMS4gKklkZW50aWZpY2FjacOzbiBkZSBjYXJhY3RlcsOtc3RpY2FzIGNsYXZlKg0KMi4gKk1lam9yYSBkZSBsYSBjYWxpZGFkIGRlIGxvcyBkYXRvcyoNCjMuICpEZXNjdWJyaW1pZW50byBkZSBwYXRyb25lcyB5IHJlbGFjaW9uZXMqDQo0LiAqU2VsZWNjacOzbiBkZSB2YXJpYWJsZXMgcmVsZXZhbnRlcyoNCjUuICpEaXNlw7FvIGRlIG1vZGVsb3MgbcOhcyBlZmVjdGl2b3MqDQo2LiAqRmFjaWxpdGFjacOzbiBkZSBsYSBjb211bmljYWNpw7NuKg0KDQoNCg0KDQojIEFudGVjZWRlbnRlcyBkZSBsYSBFbXByZXNhIEZPUk0NCg0KIyMgVmlzacOzbg0KDQpFbiAyMDMzIHNlcmVtb3MgdW5hIGRlIGxhcyBjaW5jbyBtZWpvcmVzIGNvbXBhw7HDrWFzIGRlIE3DqXhpY28gcXVlIGdlbmVyYW4gdmFsb3IgZGVudHJvIGRlIGxhIGNhZGVuYSBkZSBzdW1pbmlzdHJvIGRlIGxhcyBpbmR1c3RyaWFzIHF1ZSBtw6FzIHZhbG9yYW4gbGEgZm9ybWEgZW4gbGEgcXVlIHNlIHByb3RlZ2VuIHkgdHJhc2xhZGFuIGxhcyBjb3Nhcy4NCg0KDQojIyBNaXNpw7NuDQoNClRyYW5zZm9ybWFyIG51ZXN0cm8gZW50b3JubyB5IHJlc29sdmVyIHJldG9zIGluZHVzdHJpYWxlcyBkZSBudWVzdHJvcyBjbGllbnRlcyBhIHRyYXbDqXMgZGUgbGEgY29sYWJvcmFjacOzbiwgcHJvdm9jYW5kbyBudWV2YXMgb3BvcnR1bmlkYWRlcyBxdWUgcG90ZW5jaWFuIG51ZXN0cm8gbW9kZWxvIGRlIG5lZ29jaW8sIHBhcmEgYWxjYW56YXIgbnVlc3Ryb3MgaWRlYWxlcy4NCg0KDQoNCiMgQ29udGV4dG8gZGUgbGEgSW5kdXN0cmlhDQoNCiMjIEluZHVzdHJpYSBkZSBhdXRvcGFydGVzDQoNCioqIExhIHByb2R1Y2Npw7NuIGRlIHZlaMOtY3Vsb3MgeSBhdXRvcGFydGVzIGVuIFVTQSBlcyBtdXkgY2VudHJhbGl6YWRhLCBmcmVudGUgYSB1biBtZXJjYWRvIG1leGljYW5vIHF1ZSBlc3RhIG3DoXMgZGlsdWlkby4NCioqIEltcG9ydGFudGUgYmFycmVyYSBkZSBlbnRyYWRhIHBhcmEgZWwgcmVzdG8gZGUgb3JnYW5pemFjaW9uZXMgcXVlIGJ1c2NhbiBjb21wZXRpciBlbiBlc3RlIG1lcmNhZG8uDQoqKiBTaWd1ZW4gZGlzdGludGFzIHRlbmRlbmNpYXMgY29tZXJjaWFsZXMuDQoNCiFbXShDOlxcVXNlcnNcXGxlc2RhX2I1d2ZxcWFcXERvd25sb2Fkc1xcZXYxXFwxLnBuZykNCg0KDQojIyBJbmR1c3RyaWEgZGUgQ2FydMOzbiB5IEF1dG9zDQoNCioqIEluZHVzdHJpYSBkZSBkZSBwcm9kdWN0b3MgZGUgY2FydMOzbiB5IHBhcGVsIGVzdGEgZW4gdW5hIHRlbmRlbmNpYSBjcmVjaWVudGUuDQoqKiBFeHBvcnRhY2lvbmVzIGRlIEF1dG9zIGVuIE3DqXhpY28gIHBhcmVjZSB0ZW5lciBlc3RhY2lvbmFsaWRhZC4NCioqIFNlIGVzcGVyYSBxdWUgcGFyYSBlbCBwcmltZXIgdHJpbWVzdHJlIGRlbCAyMDI0IGhheWEgdW4gaW5jcmVtZW50byBlbiBleHBvcnRhY2lvbmVzLg0KDQohW10oQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcMi5wbmcpDQoNCg0KDQoNCiMjIEZPREENCiFbXShDOlxcVXNlcnNcXGxlc2RhX2I1d2ZxcWFcXERvd25sb2Fkc1xcZXYxXFxGT0RBLnBuZykNCg0KIyMgRXN0cmF0ZWdpYXMgRk9EQSBDcnV6YWRvDQohW10oQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcRkMucG5nKQ0KDQoNCg0KDQohW10oQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcZm9kYSBjcnV6YWRvLnBuZykNCg0KDQojIyBQRVNUTEUNCiFbXShDOlxcVXNlcnNcXGxlc2RhX2I1d2ZxcWFcXERvd25sb2Fkc1xcZXYxXFxQRVNUTEUucG5nKQ0KDQoNCiMjIEZhY3RvcmVzIFBFU1RMRQ0KIVtdKEM6XFxVc2Vyc1xcbGVzZGFfYjV3ZnFxYVxcRG93bmxvYWRzXFxldjFcXEZQLnBuZykNCg0KDQoNCg0KDQoNCiMgU2l0dWFjacOzbiBQcm9ibGVtYSAxOiBDbGltYSBMYWJvcmFsDQoNCkxvcyBwcmluY2lwYWxlcyBmYWN0b3JlcyBkZWwgY2xpbWEgb3JnYW5pemFjaW9uYWwgZGUgRk9STSBxdWUgDQpwcm9waWNpYW4gbGEgc2F0aXNmYWNjaW/MgW4geS9vIG5vIHNhdGlzZmFjY2lvzIFuIGRlIHRyYWJhamFyIGVuIGRpY2hhIGVtcHJlc2EuDQoNCg0KIyBSSA0KDQojIyBQcmVndW50YXMgZGUgQW7DoWxpc2lzIGRlbCBDbGltYSBMYWJvcmFsDQoqIMK/Q3XDoWxlcyBzb24gbGFzIGxpbWl0YWNpb25lcywgZG9sb3JlcywgbyBpbXBlZGltZW50b3MgbcOhcyBjb23Dum5lcyBkZW50cm8gZGUgbG9zIHRyYWJhamFkb3JlcyBkZSBGT1JNPw0KKiDCv0PDs21vIHZhcsOtYW4gbGFzIG9waW5pb25lcyBzb2JyZSBlbCB0cmFiYWpvIHNlZ8O6biBlbCBnw6luZXJvIGRlIGxvcyBlbmN1ZXN0YWRvcz8NCiogwr9DdcOhbGVzIHNvbiBsb3Mgc2VudGltaWVudG9zIHkgc2F0aXNmYWNjaW9uZXMgbGFib3JhbGVzIHF1ZSByZXBvcnRhbiBsb3MgZW1wbGVhZG9zPw0KKiDCv0N1w6FsIGVzIGVsIHBlcmZpbCBkZWwgdHJhYmFqYWRvciBxdWUgc3VmcmUgbcOhcyBhY29zbyBlbiBlbCDDoXJlYSBkZSB0cmFiYWpvL2VtcHJlc2E/DQoNCioqTGlicmVyw61hcyoqDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShzeXV6aGV0KQ0KbGlicmFyeSh0bSkNCmxpYnJhcnkod29yZGNsb3VkKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KG5hbmlhcikgICAgICAgICANCmxpYnJhcnkoUkNvbG9yQnJld2VyKSAgDQpsaWJyYXJ5KHJlZ2NsYXNzKSAgICAgICANCmxpYnJhcnkobWN0ZXN0KSAgICAgICAgIA0KbGlicmFyeShsbXRlc3QpICAgICAgICAgDQpsaWJyYXJ5KGNhcmV0KSAgICAgICAgICANCmxpYnJhcnkoZTEwNzEpICAgICAgICAgIA0KbGlicmFyeShTcGFyc2VNKSAgICAgICAgDQpsaWJyYXJ5KE1ldHJpY3MpICAgICAgIA0KbGlicmFyeShqdG9vbHMpICAgICAgICAgDQpsaWJyYXJ5KERpYWdyYW1tZVIpICAgICANCmxpYnJhcnkoZWZmZWN0cykgICAgICAgIA0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KERhdGFFeHBsb3JlcikNCmxpYnJhcnkoY29ycnIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShnbW9kZWxzKQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KHJlYWR0ZXh0KQ0KbGlicmFyeShkbG9va3IpDQpgYGANCg0KIyMgTGltcGllemEgeSBPcmdhbml6YWNpw7NuIGRlIGxhIGJhc2UgZGUgZGF0b3MNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkZiA8LSByZWFkX3hsc3goIkM6XFxVc2Vyc1xcbGVzZGFfYjV3ZnFxYVxcRG93bmxvYWRzXFxldjFcXEJEX0ZPUk0ueGxzeCIpDQpkZjEgPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xcbGVzZGFfYjV3ZnFxYVxcRG93bmxvYWRzXFxldjFcXERhdG9zX0ZPUk1fUkguY3N2IikNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBWaXN1YWxpemFyIGVzdHJ1Y3R1cmEgaW50ZXJuYSBkZWwgZGF0YSBmcmFtZQ0Kc3RyKGRmKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFNlbGVjY2lvbmFyIGluZm9ybWFjaW/MgW4geSBkYXRvcyByZWxldmFudGVzIHBhcmEgcmVzcG9uZGVyIGxhcyBwcmVndW50YXMgZGUgYW5hzIFsaXNpcw0KDQojIEVsaW1pbmFyIGNvbHVtbmEgaWQNCmRmIDwtIHN1YnNldChkZiwgc2VsZWN0ID0gLWlkKQ0KbmFtZXMoZGYpDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQWwgdmlzdWFsaXphciBsYSBlc3RydWN0dXJhIGludGVybmEgZGVsIGRhdGEgZnJhbWUsIGVzIHBvaXNibGUgb2JzZXJ2YXIgcXVlIGFsZ3Vub3MgdmFsb3JlcyBzb24gcmVwcmVzZW50YWRvcyBwb3IgbGEgcGFsYWJyYSAiTkEiLCBsYSBjdWFsIGVzdMOhIHNpZW5kbyBpZGVudGlmaWNhZGEgY29tbyB1biBjYXLDoWN0ZXIuIEVuIGVzdGUgY2Fzbywgc3VzdGl0dWlyZW1vcyBsYSBwYWxhYnJhICJOQSIgcG9yIGVsIHRpcG8gZGUgZGF0byBOQS4NCmRmW2RmID09ICJOQSJdIDwtIE5BDQoNCiMgQ29udGFyIGxhIGNhbnRpZGFkIHRvdGFsIGRlIE5BJ3MgZW4gZWwgZGF0YSBmcmFtZQ0Kc3VtKGlzLm5hKGRmKSkNCg0KIyBDb25vY2VyIGN1w6FudG9zIGRhdG9zIGZhbHRhbnRlcyBoYXkgcG9yIGNvbHVtbmENCmNvbFN1bXMoaXMubmEoZGYpKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIENvbiBlc3RvIHBvZGVtb3MgdmVyIHF1ZSBsb3MgMzYgZGF0b3MgZmFsdGFudGVzIHNlIGVuY3VlbnRyYW4gZW4gbGEgY29sdW1uYSBpbnNfcHVlc3RvX2FjdHVhbC4gTGEgY29sdW1uYSBjb250aWVuZSBsYXMgcmVzcHVlc3RhcyBkZSBjYWRhIGVudHJldmlzdGFkbyBwYXJhIGxhIHByZWd1bnRhIMK/cXXDqSBhc3BlY3RvcyBkZSB0dSBwdWVzdG8gYWN0dWFsIHRlIHJlc3VsdGFuIG1lbm9zIHNhdGlzZmFjdG9yaW9zPy4gRW4gZXN0ZSBjYXNvLCBsb3MgTkEncyBzb24gaW50ZXJwcmV0YWRvcyBkZSBsYSBzaWd1aWVudGUgbWFuZXJhOiBlbCBjb2xhYm9yYWRvciBubyBjYWxpZmljYSBuaW5nw7puIGFzcGVjdG8gZGUgc3UgcHVlc3RvIGFjdHVhbCBjb21vIG1lbm9zIHNhdGlzZmFjdG9yaW8uDQoNCiMgU3VzdGl0dWlyIGxvcyB2YWxvcmVzIE5BIHBvciBsYSBwYWxhYnJhICJOaW5ndW5vIg0KZGYkaW5zX3B1ZXN0b19hY3R1YWxbaXMubmEoZGYkaW5zX3B1ZXN0b19hY3R1YWwpXSA8LSAiTmluZ3VubyINCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBBbCB2aXN1YWxpemFyIGxhIGVzdHJ1Y3R1cmEgaW50ZXJuYSBkZWwgZGF0YSBmcmFtZSwgZXMgcG9pc2JsZSBvYnNlcnZhciBxdWUgYWxndW5hcyBjb2x1bW5hcyBubyBjb3JyZXNwb25kZW4gYWwgdGlwbyBkZSBkYXRvcyBxdWUgZGViZXLDrWFuLg0KDQojIENvbnZlcnRpciBsYXMgY29sdW1uYXMgc2VsZWNjaW9uYWRhcyBhIGZhY3RvcmVzDQoNCmNhdGVnb3JpY2FzIDwtIGMoInB1ZXN0b190cmFiYWpvIiwicmF6b25fdHJhYmFqbyIsInNhbGFyaW8iLCJwcmVzdGFjaW9uZXMiLCJqb3JuYWRhX2xhYm9yYWwiLCJkZXNlbXBfYXByZW5kIiwiY2xpbWEiLCJlc3RyZXMiLCJ0cmFuc3BvcnRlIiwiem9uYV90cmFiYWpvIiwiZnV0dXJvX2Zvcm0iLCJpbnNlZ3VyaWRhZCIsImdlbmVybyIsImVzdGFkb19jaXZpbCIsIm11bmljaXBpb19yZXNpZGVuY2lhIiwiZXNjb2xhcmlkYWQiKQ0KDQojIFVzYXIgbGFwcGx5IHBhcmEgYXBsaWNhciBsYSBmdW5jacOzbiBhcy5mYWN0b3IgYSBsYXMgY29sdW1uYXMgc2VsZWNjaW9uYWRhcw0KZGZbY2F0ZWdvcmljYXNdIDwtIGxhcHBseShkZltjYXRlZ29yaWNhc10sIGFzLmZhY3RvcikNCg0KIyBDb252ZXJ0aXIgbGFzIGNvbHVtbmFzIHNlbGVjY2lvbmFkYXMgYSBlbnRlcm9zDQpkZiRhbnRpZ3VlZGFkICA8LSBhcy5pbnRlZ2VyKGRmJGFudGlndWVkYWQpDQpkZiRlZGFkICAgICAgICA8LSBhcy5pbnRlZ2VyKGRmJGVkYWQpDQpkZiRkZXBfZWNvbiAgICA8LSBhcy5pbnRlZ2VyKGRmJGRlcF9lY29uKQ0KDQojIFJldmlzYXIgcXVlIGxhcyBjb2x1bW5hcyB0ZW5nYW4gZWwgdGlwbyBkZSBkYXRvIGNvcnJlY3RvDQpzdHIoZGYpDQoNCiMgQ29uZmlybWFyIGF1c2VuY2lhIGRlIE5BJ3MgZW4gZWwgZGF0YSBmcmFtZQ0KYW55KGlzLm5hKGRmKSkNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBWaXN1YWxpemFyIGxvcyBwcmltZXJvcyA2IHJlbmdsb25lcyBkZSBsYSBudWV2YSBiYXNlIGRlIGRhdG9zDQpoZWFkKGRmKQ0KYGBgDQoNCg0KIyMjIEdsb3NhcmlvIGRlIGxhIGJhc2UgZGUgZGF0b3MgZGUgQ2xpbWEgTGFib3JhbA0KTcOhcyBpbmZvcm1hY2nDs246DQpbR2xvc2FyaW8gZGUgdmFyaWFibGVzXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xV2RIbC1lRmw0Tk84eWpWbzdCbjktMi1IQ19laEpLUVRETUl1M3BDTFBRVS9lZGl0P3VzcD1zaGFyaW5nKQ0KDQpgYGB7cn0NCnN0cihkZjEpDQpjb2xuYW1lcyhkZjEpDQpgYGANCg0KQ2FtYmlvIGRlIGNvbHVtbmFzIHBhcmEgdmFyaWFibGVzIGVuIGJhc2UgZGUgZGF0b3MgImRmMSINCg0KLSBwMTogwr9DdcOhbCBmdWUgbGEgcHJpbmNpcGFsIHJhesOzbiBwb3IgbGEgcXVlIGVudHJhc3RlIGEgZXN0ZSB0cmFiYWpvPw0KLSBwMjogQ29uc2lkZXJvIHF1ZSBlbCBzYWxhcmlvIHF1ZSByZWNpYm8gZXMgYnVlbm8gcGFyYSBlbCB0cmFiYWpvIHF1ZSByZWFsaXpvDQotIHAzOiBNaXMgcHJlc3RhY2lvbmVzIHNvbiBhbGdvIHF1ZSBoYWNlIHF1ZSBtZSBxdWVkZSBlbiBsYSBlbXByZXNhDQotIHA0OiBMYSBqb3JuYWRhIGxhYm9yYWwgbm8gZXMgZXhjZXNpdmENCi0gcDU6IEZPUk0gbWUgaGEgb2ZyZWNpZG8gbGFzIGhlcnJhbWllbnRhcyBuZWNlc2FyaWFzIHBhcmEgbWkgZGVzZW1wZcOxbyB5IGFwcmVuZGl6YWplDQotIHA2OiBRdWUgaGFnYSBtdWNobyBmcsOtbyBvIGNhbG9yIGVuIG1pIMOhcmVhIGRlIHRyYWJham8gbm8gZXMgYWxnbyBxdWUgbWUgbW9sZXN0ZQ0KLSBwNzogTWkgbml2ZWwgZGUgZXN0csOpcyBkdXJhbnRlIGxhIGpvcm5hZGEgbGFib3JhbCBlcyBiYWpvDQotIHA4OiBNZSBwdWVkbyB0cmFuc3BvcnRhciBkZSBmb3JtYSBzZWd1cmEgZGUgbWkgY2FzYSBhIG1pIHRyYWJham8geSBubyBtZSBjdWVzdGEgZGVtYXNpYWRvIGVzZnVlcnpvIGxsZWdhcg0KLSBwOTogTWkgem9uYSBkZSB0cmFiYWpvIGVzIGPDs21vZGEgeSBzZWd1cmEgcGFyYSBoYWNlciBtaXMgYWN0aXZpZGFkZXMNCi0gcDEwOiBFcyBtdXkgcHJvYmFibGUgcXVlIHNpZ2EgdHJhYmFqYW5kbyBlbiBGT1JNIGVuIHVuIGZ1dHVybw0KLSBwMTE6IMK/SGFzIGV4cGVyaW1lbnRhZG8gc2l0dWFjaW9uZXMgZGUgY29uZmxpY3RvLCBhY29zbyAgbyBxdWUgdGUgaGF5YW4gaGVjaG8gc2VudGlyIGluc2VndXJvIGR1cmFudGUgdHUgdGllbXBvIGVuIGxhIGVtcHJlc2E/DQotIHAxMjogRW4gMyBwYWxhYnJhcyBvIG1lbm9zIMK/UXXDqSBhc3BlY3RvcyBkZSB0dSBwdWVzdG8gYWN0dWFsIHRlIHJlc3VsdGFuIG1lbm9zIHNhdGlzZmFjdG9yaW9zPw0KLSBwMTM6IMK/Q8OzbW8gdGUgc2llbnRlcyBlbiBGT1JNPw0KDQojIyBFREEgZGVsIENsaW1hIExhYm9yYWwNCg0KIyMjIEVzdGFkw61zdGljb3MgZGVzY3JpcHRpdm9zDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc3VtbWFyeShkZikNCmBgYA0KDQojIyMgTWVkaWRhcyBkZSBkaXNwZXJzacOzbg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRlc2NyaWJlKGRmKQ0KYGBgDQoNCiMjIyBHcsOhZmljb3MgeSB0YWJsYXMNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgU2VsZWNjaW9uYXIgc29sbyBsYXMgY29sdW1uYXMgY29uIHRpcG8gZGUgZGF0byBmYWN0b3IgcGFyYSBsb3MgZ3LDoWZpY29zIGRlIGJhcnJhcw0KDQojIFNlbGVjY2lvbmFyIHkgZ3JhZmljYXIgbGFzIHZhcmlhYmxlcyBkZW1vZ3LDoWZpY2FzDQpwbG90X2JhcihkZiAlPiUgDQogICAgICAgIHNlbGVjdChnZW5lcm8sZXN0YWRvX2NpdmlsLG11bmljaXBpb19yZXNpZGVuY2lhLGVzY29sYXJpZGFkKSkNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBHcmFmaWNhciBsYXMgdmFyaWFibGVzIGVuIGVzY2FsYSBsaWtlcnQNCnBsb3RfYmFyKGRmICU+JSANCiAgICAgICAgIHNlbGVjdChzYWxhcmlvLCBwcmVzdGFjaW9uZXMsIGpvcm5hZGFfbGFib3JhbCwgZGVzZW1wX2FwcmVuZCwgY2xpbWEsIGVzdHJlcywgdHJhbnNwb3J0ZSwgem9uYV90cmFiYWpvLCBmdXR1cm9fZm9ybSkpDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgU2VsZWNjaW9uYXIgeSBncmFmaWNhciBlbCByZXN0byBkZSBsYXMgdmFyaWFibGVzIGNhdGVnw7NyaWNhcw0KcGxvdF9iYXIoZGYgJT4lIA0KICAgICAgICBzZWxlY3QocHVlc3RvX3RyYWJham8sIHJhem9uX3RyYWJham8sIGluc2VndXJpZGFkKSkNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShkcGx5cikNCiMgQ2FtYmlhbW9zIGxhcyByZXNwdWVzdGFzIGRlIGxhIGVzY2FsYSBkZSBMaWtlcnQgYSBuw7ptZXJvcyBwYXJhIGNsYXNpZmljYXIgbGFzIHJlc3B1ZXN0YXMNCmRmMSA8LSBkZjEgJT4lDQogIGRwbHlyOjptdXRhdGUocDZfRXNjYWxhID0gZHBseXI6OnJlY29kZShwNiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbG1lbnRlIGVuIGRlc2FjdWVyZG8iID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lZGlhbmFtZW50ZSBlbiBkZXNhY3VlcmRvIiA9IDIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOaSBkZSBhY3VlcmRvIG5pIGVuIGRlc2FjdWVyZG8iID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lZGlhbmFtZW50ZSBkZSBhY3VlcmRvIiA9IDQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbG1lbnRlIGRlIGFjdWVyZG8iID0gNSkpICAgICAgDQoNCmZyZWN1ZW5jaWFzIDwtIHRhYmxlKGRmMSRQdWVzdG9fdHJhYmFqbywgZGYxJHA2X0VzY2FsYSkNCmBgYA0KDQpHcmFmaWNhbW9zIGxhcyByZXNwdWVzdGFzIGJham8gbGEgc2lndWllbnRlIGxsYXZlLiANCg0KLSAiVG90YWxtZW50ZSBlbiBkZXNhY3VlcmRvIiA9IDENCi0gIk1lZGlhbmFtZW50ZSBlbiBkZXNhY3VlcmRvIiA9IDINCi0gIk5pIGRlIGFjdWVyZG8gbmkgZW4gZGVzYWN1ZXJkbyIgPSAzDQotICJNZWRpYW5hbWVudGUgZGUgYWN1ZXJkbyIgPSA0DQotICJUb3RhbG1lbnRlIGRlIGFjdWVyZG8iID0gNQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZ2dwbG90KGRhdGEgPSBhcy5kYXRhLmZyYW1lLnRhYmxlKGZyZWN1ZW5jaWFzKSwgYWVzKHggPSBWYXIxLCB5ID0gVmFyMiwgZmlsbCA9IEZyZXEpKSArDQogIGdlb21fdGlsZSgpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAic2t5Ymx1ZSIsIGhpZ2ggPSAiYmx1ZSIpICsNCiAgbGFicyh4ID0gIlB1ZXN0byBkZSBUcmFiYWpvIiwgeSA9ICJUb3RhbG1lbnRlIGVuIGRlc2FjdWVyZG8gYSB0b3RhbG1lbnRlIGRlIGFjdWVyZG8iLCBmaWxsID0gIkZyZWN1ZW5jaWEiKSArDQogIGdndGl0bGUoIlF1ZSBoYWdhIG11Y2hvIGZyw61vIG8gY2Fsb3IgZW4gbWkgw6FyZWEgZGUgdHJhYmFqbyBubyBlcyBhbGdvIHF1ZSBtZSBtb2xlc3RlIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEVuIGVzdGUgY2FzbyBzZSBjcmVhcsOhIHVuYSBjb3BpYSBkZWwgZGF0YWZyYW1lIGRmDQpkZl9saWtlcnQgPC0gZGYgDQoNCiMgTGFzIHZhcmlhYmxlcyBjb24gcmVzcHVlc3RhcyBlbiBlc2NhbGEgbGlrZXJ0IHNlcsOhbiBjb252ZXJ0aWRhcyBhIGVudGVyb3MgcGFyYSBmYWNpbGl0YXIgc3UgYW7DoWxpc2lzIGVuIGVsIEVEQQ0KZGZfbGlrZXJ0IDwtIGRmX2xpa2VydCAlPiUNCiAgbXV0YXRlKGFjcm9zcyhjKCJzYWxhcmlvIiwgInByZXN0YWNpb25lcyIsICJqb3JuYWRhX2xhYm9yYWwiLCAiZGVzZW1wX2FwcmVuZCIsICJjbGltYSIsICJlc3RyZXMiLCAidHJhbnNwb3J0ZSIsICJ6b25hX3RyYWJham8iLCAiZnV0dXJvX2Zvcm0iKSwgfnJlY29kZSguLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWxtZW50ZSBlbiBkZXNhY3VlcmRvIiA9IDEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZWRpYW5hbWVudGUgZW4gZGVzYWN1ZXJkbyIgPSAyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTmkgZGUgYWN1ZXJkbyBuaSBlbiBkZXNhY3VlcmRvIiA9IDMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZWRpYW5hbWVudGUgZGUgYWN1ZXJkbyIgPSA0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWxtZW50ZSBkZSBhY3VlcmRvIiA9IDUpKSkNCg0KIyBDb25maXJtYXIgcXVlIGxhIGNvbnZlcnNpw7NuIG5vIGdlbmVyZSB2YWxvcmVzIG51bG9zDQojYW55KGlzLm5hKGRmX2xpa2VydCkpDQpgYGANCg0KTG9zIHNpZ3VpZW50ZXMgZ3LDoWZpY29zIHJlcHJlc2VudGFuIMO6bmljYW1lbnRlIGxhIGluZm9ybWFjacOzbiBvYnRlbmlkYSBkZSBsYSBlbmN1ZXN0YS4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgSGlzdG9ncmFtYSBkZSBlZGFkDQpnZ3Bsb3QoZGYsIGFlcyh4ID0gZWRhZCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSA1LCBmaWxsID0gIiNGRjgwMDAiLCBjb2xvciA9ICJibGFjayIpICsgICMgUHVlZGVzIGFqdXN0YXIgZWwgYW5jaG8gZGVsIGJpbiBzZWfDum4gdHVzIGRhdG9zDQogIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtYSBkZSBFZGFkIiwgc3VidGl0bGUgPSAiRW5jdWVzdGEgRk9STSwgT3Rvw7FvIDIwMjMiLCB4ID0gIkVkYWQgKGHDsW9zKSIsIHkgPSAiRnJlY3VlbmNpYSIpDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgUG9yY2VudGFqZSBkZSByZXNwdWVzdGFzIHBvciBnw6luZXJvDQpDcm9zc1RhYmxlKGRmX2xpa2VydCRnZW5lcm8sIHByb3AuYyA9IEZBTFNFLCBwcm9wLnQgPSBGQUxTRSwgcHJvcC5jaGlzcSA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFRhYmxhIGNydXphZGEgbXVuaWNpcGlvX3Jlc2lkZW5jaWEgeSB0cmFuc3BvcnRlDQpDcm9zc1RhYmxlKGRmX2xpa2VydCRtdW5pY2lwaW9fcmVzaWRlbmNpYSwgZGZfbGlrZXJ0JHRyYW5zcG9ydGUsIHByb3AuYyA9IEZBTFNFLCBwcm9wLnQgPSBGQUxTRSwgcHJvcC5jaGlzcSA9IEZBTFNFKQ0KYGBgDQoNCioqSW50ZXJwcmV0YWNpw7NuIGRlIGxvcyB2YWxvcmVzIGVudGVyb3MgKGNvbHVtbmFzIGRlIGxhIHRhYmxhKToqKiAgDQoNCipUb3RhbG1lbnRlIGVuIGRlc2FjdWVyZG8gPSAxKiAgDQoqTWVkaWFuYW1lbnRlIGVuIGRlc2FjdWVyZG8gPSAyKiAgDQoqTmkgZGUgYWN1ZXJkbyBuaSBlbiBkZXNhY3VlcmRvID0gMyogIA0KKk1lZGlhbmFtZW50ZSBkZSBhY3VlcmRvID0gNCogICANCipUb3RhbG1lbnRlIGRlIGFjdWVyZG8gPSA1KiAgIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBSYXrDs24gZGUgdHJhYmFqbyBwb3IgZ8OpbmVybw0KDQojIEZpbHRyYXIgZWwgRGF0YUZyYW1lIHBvciBnw6luZXJvDQpkZl9mZW1lbmlubyA8LSBkZl9saWtlcnRbZGZfbGlrZXJ0JGdlbmVybyA9PSAnRmVtZW5pbm8nLCBdDQpkZl9tYXNjdWxpbm8gPC0gZGZfbGlrZXJ0W2RmX2xpa2VydCRnZW5lcm8gPT0gJ01hc2N1bGlubycsIF0NCg0KIyBDYWxjdWxhciBmcmVjdWVuY2lhcyBkZSByYXpvbl90cmFiYWpvDQpmZW1fcmF6b25fdHJhYmFqbyA8LSB0YWJsZShkZl9mZW1lbmlubyRyYXpvbl90cmFiYWpvKQ0KbWFzY19yYXpvbl90cmFiYWpvIDwtIHRhYmxlKGRmX21hc2N1bGlubyRyYXpvbl90cmFiYWpvKQ0KDQojIE9yZGVuYXIgZnJlY3VlbmNpYXMNCm9yZF9mZW0gPC0gbmFtZXMoc29ydCh0YWJsZShkZl9mZW1lbmlubyRyYXpvbl90cmFiYWpvKSwgZGVjcmVhc2luZyA9IFRSVUUpKQ0Kb3JkX21hc2MgPC0gbmFtZXMoc29ydCh0YWJsZShkZl9tYXNjdWxpbm8kcmF6b25fdHJhYmFqbyksIGRlY3JlYXNpbmcgPSBUUlVFKSkNCg0KIyBDcmVhciBsYXMgZ3LDoWZpY2FzIGRlIGZyZWN1ZW5jaWFzDQpnZ3Bsb3QoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZmVtX3Jhem9uX3RyYWJham8pLCBhZXMoeCA9IGZhY3RvcihWYXIxLCBsZXZlbHMgPSBvcmRfZmVtKSwgeSA9IEZyZXEpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNFNzIzNkYiKSArDQogIGxhYnModGl0bGUgPSAiUmF6w7NuIGRlIHRyYWJham8gZ8OpbmVybyBmZW1lbmlubyIsIHN1YnRpdGxlID0gIkVuY3Vlc3RhIEZPUk0sIE90b8OxbyAyMDIzIiwNCiAgICAgICB4ID0gIlJhesOzbiB0cmFiYWpvIiwNCiAgICAgICB5ID0gIkZyZWN1ZW5jaWEiKQ0KDQpnZ3Bsb3QoZGF0YSA9IGFzLmRhdGEuZnJhbWUobWFzY19yYXpvbl90cmFiYWpvKSwgYWVzKHggPSBmYWN0b3IoVmFyMSwgbGV2ZWxzID0gb3JkX21hc2MpLCB5ID0gRnJlcSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzQ5NEQ4QSIpICsNCiAgbGFicyh0aXRsZSA9ICJSYXrDs24gZGUgdHJhYmFqbyBnw6luZXJvIG1hc2N1bGlubyIsIHN1YnRpdGxlID0gIkVuY3Vlc3RhIEZPUk0sIE90b8OxbyAyMDIzIiwNCiAgICAgICB4ID0gIlJhesOzbiB0cmFiYWpvIiwNCiAgICAgICB5ID0gIkZyZWN1ZW5jaWEiKQ0KYGBgDQoNCiMjIEFuw6FsaXNpcyBkZSBzZW50aW1pZW50b3MNCg0KKipBIGNvbnRpbnVhY2nDs24sIGVsIGFuw6FsaXNpcyBkZSBzZW50aW1pZW50b3MgYSBsYSBwcmVndW50YSAiwr9Dw7NtbyB0ZSBzaWVudGVzIGVuIEZPUk0/IioqDQpFbiBkb25kZSBzZSByZXNhbHRhbiBsb3Mgc2VudGltaWVudG8gZGUgY29uZmlhbnphIHkgYWxlZ3LDrWEgY29tbyBsYXMgcHJpbmNpcGFsZXMgdsOtYXMgcXVlIHVzYXJvbiBsb3MgdHJhYmFqYWRvcmVzIHBhcmEgcmVmZXJpcnNlIGEgc3UgZXN0YWTDrWEgZW4gRk9STS4gU2kgYmllbiB0YW1iacOpbiBzZSByZWdpc3RyYXJvbiByZXNwdWVzdGFzIHF1ZSBoYWNlbiByZWZlcmVuY2lhIGEgZW1vY2lvbmVzIG5lZ2F0aXZhcywgbGEgc3VtYSBkZSB0b2RhcyBlbGxhcyBhcGVuYXMgZXMgY29tcGFyYWJsZSBjb24gbG9zIHNlbnRpbWllbnRvcyBtZW5jaW9uYWRvcyBhbCBpbmljaW8uIEEgcGFydGlyIGRlIGVzdGUgYW7DoWxpc2lzIGVzIHBvc2libGUgY29uY2x1aXIgcXVlIG11eSBwb3NpYmxlbWVudGUgZWwgYW1iaWVudGUgb3JnYW5pemFjaW9uYWwgZGVudHJvIGRlIEZPUk0geSBsYSByZWxhY2nDs24gcXVlIHRpZW5lbiBsb3MgZW1wbGVhZG9zIGNvbiBsYSBlbXByZXNhIG5vIHNvbiBsb3MgcHJvYmxlbWFzIG8gcHJpbmNpcGFsZXMgY2F1c2VzIHF1ZSBnZW5lcmFuIHVuYSBhbHRhIHJvdGFjacOzbiBkZSBwZXJzb25hbC4gDQoNClNpIGJpZW4gdGFtYmnDqW4gc2UgbWFwZcOzIGxhIHByb2dyZXNpw7NuIGVtb2Npb25hbCBkZSBsYXMgcmVzcHVlc3RhcywgYWwgdHJhdMOhcnNlIMO6bmljYW1lbnRlIGRlIGVuY3Vlc3RhcyBpbmRpdmlkdWFsZXMuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0ZXh0b19wYWxhYnJhcyA8LSBnZXRfdG9rZW5zKGRmMSRwMTMpDQplbW9jaW9uZXNfZGYgPC0gZ2V0X25yY19zZW50aW1lbnQodGV4dG9fcGFsYWJyYXMsIGxhbmd1YWdlID0gInNwYW5pc2giKQ0KYmFycmFzIDwtIGJhcnBsb3QoY29sU3Vtcyhwcm9wLnRhYmxlKGVtb2Npb25lc19kZlssIDE6OF0pKSkNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcmVzcHVlc3RhcyA8LSBnZXRfdG9rZW5zKGRmMSRwMTMpDQplbW9jaW9uZXNfZGZfMiA8LSBnZXRfbnJjX3NlbnRpbWVudChyZXNwdWVzdGFzLCBsYW5ndWFnZSA9ICJzcGFuaXNoIikNCnNlbnRpbWllbnRvcyA8LSAoZW1vY2lvbmVzX2RmXzIkbmVnYXRpdmUqLTEpICsgZW1vY2lvbmVzX2RmXzIkcG9zaXRpdmUNCnNpbXBsZV9wbG90KHNlbnRpbWllbnRvcykNCmBgYA0KKipZIGFob3JhIGNvbnRyYXN0YW5kbyBsYXMgb3BpbmlvbmVzIHBvciBnw6luZXJvKioNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgQW7DoWxpc2lzIGRlIHNlbnRpbWllbnRvcyBkZSBsYSBjb2x1bW5hIG9wX2Zvcm0gcG9yIGfDqW5lcm8NCg0Kb3Bpbmlvbl9mZW0gPC0gZ2V0X3Rva2VucyhkZl9mZW1lbmlubyRvcF9mb3JtKQ0KICAgIGVtb2Npb25lc19kZiA8LSBnZXRfbnJjX3NlbnRpbWVudChvcGluaW9uX2ZlbSwgbGFuZ3VhZ2UgPSAic3BhbmlzaCIpDQogICAgYmFycGxvdChjb2xTdW1zKHByb3AudGFibGUoZW1vY2lvbmVzX2RmWywxOjhdKSksDQogICAgICAgIG1haW4gPSAiRjogwr9Dw7NtbyB0ZSBzaWVudGVzIGVuIEZPUk0/IiwNCiAgICAgICAgeGxhYiA9ICJFbW9jaW9uZXMiLA0KICAgICAgICB5bGFiID0gIkZyZWN1ZW5jaWEiKQ0KICAgIA0Kb3Bpbmlvbl9tYXNjIDwtIGdldF90b2tlbnMoZGZfbWFzY3VsaW5vJG9wX2Zvcm0pDQogICAgZW1vY2lvbmVzX2RmIDwtIGdldF9ucmNfc2VudGltZW50KG9waW5pb25fbWFzYywgbGFuZ3VhZ2UgPSAic3BhbmlzaCIpDQogICAgYmFycGxvdChjb2xTdW1zKHByb3AudGFibGUoZW1vY2lvbmVzX2RmWywxOjhdKSksDQogICAgICAgIG1haW4gPSAiTTogwr9Dw7NtbyB0ZSBzaWVudGVzIGVuIEZPUk0/IiwNCiAgICAgICAgeGxhYiA9ICJFbW9jaW9uZXMiLA0KICAgICAgICB5bGFiID0gIkZyZWN1ZW5jaWEiKQ0KYGBgDQoNCkRlc3B1w6lzIG5vcyBlbmZvY2FyZW1vcyBlbiBsb3MgcHJpbmNpcGFsZXMgZG9sb3JlcyBxdWUgdGllbmVuIGxvcyB0cmFiYWphZG9yZXMuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0ZXh0IDwtIHJlYWRfbGluZXMoIkM6XFxVc2Vyc1xcbGVzZGFfYjV3ZnFxYVxcRG93bmxvYWRzXFxldjFcXHAxMi50eHQiKQ0KDQpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0KSkgDQoNCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBjb250ZW50X3RyYW5zZm9ybWVyKHRvbG93ZXIpKQ0KY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKQ0KY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZU51bWJlcnMpDQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIHN0b3B3b3Jkcygic3BhIikpDQoNCnRkbSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoY29ycHVzKQ0KbSA8LSBhcy5tYXRyaXgodGRtKQ0KDQpmcmVjdWVuY2lhIDwtIHNvcnQocm93U3VtcyhtKSwgZGVjcmVhc2luZyA9IFRSVUUpDQpmcmVjdWVuY2lhX2RmIDwtIGRhdGEuZnJhbWUod29yZD1uYW1lcyhmcmVjdWVuY2lhKSwgZnJlcSA9IGZyZWN1ZW5jaWEpDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQW7DoWxpc2lzIGluc2F0aXNmYWNjacOzbiBwdWVzdG8gYWN0dWFsDQp0ZXh0b19pbnMgPC0gcmVhZF9saW5lcygiQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcaW5zX3B1ZXN0b19hY3R1YWwudHh0IikNCg0KY29ycHVzXzEgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0b19pbnMpKSANCg0KY29ycHVzXzEgPC0gdG1fbWFwKGNvcnB1c18xLCBjb250ZW50X3RyYW5zZm9ybWVyKHRvbG93ZXIpKQ0KY29ycHVzXzEgPC0gdG1fbWFwKGNvcnB1c18xLCByZW1vdmVQdW5jdHVhdGlvbikNCmNvcnB1c18xIDwtIHRtX21hcChjb3JwdXNfMSwgcmVtb3ZlTnVtYmVycykNCmNvcnB1c18xIDwtIHRtX21hcChjb3JwdXNfMSwgcmVtb3ZlV29yZHMsIHN0b3B3b3Jkcygic3BhIikpDQpjb3JwdXNfMSA8LSB0bV9tYXAoY29ycHVzXzEsIHJlbW92ZVdvcmRzLCBjKCJOaW5ndW5vIikpDQoNCnRkbV8xIDwtIFRlcm1Eb2N1bWVudE1hdHJpeChjb3JwdXNfMSkNCm1fMSA8LSBhcy5tYXRyaXgodGRtXzEpDQoNCmZyZWN1ZW5jaWFfMSA8LSBzb3J0KHJvd1N1bXMobV8xKSwgZGVjcmVhc2luZyA9IFRSVUUpDQpmcmVjdWVuY2lhX2RmXzEgPC0gZGF0YS5mcmFtZSh3b3JkPW5hbWVzKGZyZWN1ZW5jaWFfMSksIGZyZXEgPSBmcmVjdWVuY2lhXzEpDQpgYGANCg0KIyMjIFBhbGFicmFzIEZyZWN1ZW50ZXMgeSBXb3JkY2xvdWRzDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZ2dwbG90KGhlYWQoZnJlY3VlbmNpYV9kZiwgMTApLCBhZXMoeCA9IHJlb3JkZXIod29yZCwgLWZyZXEpLCB5ID0gZnJlcSwgZmlsbCA9IGZyZXEpKSArIA0KICBnZW9tX2NvbCgpICsgIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gZnJlcSksIHZqdXN0ID0gLTAuMykgKyAgDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gImxpZ2h0Ymx1ZSIsIGhpZ2ggPSAiYmx1ZSIsIGxpbWl0cyA9IGMoMCwgMjApKSArICANCiAgbGFicyh0aXRsZSA9ICJUT1AgMTAgUGFsYWJyYXMgTcOhcyBGcmVjdWVudGVzIiwgDQogICAgICAgc3VidGl0bGUgPSAiwr9RdcOpIGFzcGVjdG9zIGRlIHR1IHB1ZXN0byBhY3R1YWwgdGUgcmVzdWx0YW4gbWVub3Mgc2F0aXNmYWN0b3Jpb3M/IiwgDQogICAgICAgeCA9ICJQYWxhYnJhIiwgDQogICAgICAgeSA9ICJGcmVjdWVuY2lhIikgKw0KICB0aGVtZV9taW5pbWFsKCkgDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCndvcmRjbG91ZCh3b3JkcyA9IGZyZWN1ZW5jaWFfZGYkd29yZCwNCiAgICAgICAgICBmcmVxID0gZnJlY3VlbmNpYV9kZiRmcmVxLA0KICAgICAgICAgIG1pbi5mcmVxID0gMiwNCiAgICAgICAgICByYW5kb20ub3JkZXIgPSBGQUxTRSwNCiAgICAgICAgICByb3QucGVyID0gMC4zNSwgDQogICAgICAgICAgY29sb3JzID0gYnJld2VyLnBhbCg4LCAiRGFyazIiKSwNCiAgICAgICAgICBzY2FsZSA9IGMoNCwwLjUpLCANCiAgICAgICAgICBtYXgud29yZHMgPSAxMDApIA0KDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmdncGxvdChoZWFkKGZyZWN1ZW5jaWFfZGZfMSwgMTApLCBhZXMoeCA9IHJlb3JkZXIod29yZCwgLWZyZXEpLCB5ID0gZnJlcSwgZmlsbCA9IGZyZXEpKSArIA0KICBnZW9tX2NvbCgpICsgIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gZnJlcSksIHZqdXN0ID0gLTAuMykgKyAgDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIiNGRjgwMDAiLCBoaWdoID0gImJsdWUiLCBsaW1pdHMgPSBjKDAsIDIwKSkgKyAgDQogIGxhYnModGl0bGUgPSAiVE9QIDEwIFBhbGFicmFzIE3DoXMgRnJlY3VlbnRlcyIsIA0KICAgICAgIHN1YnRpdGxlID0gIsK/UXXDqSBhc3BlY3RvcyBkZSB0dSBwdWVzdG8gYWN0dWFsIHRlIHJlc3VsdGFuIG1lbm9zIHNhdGlzZmFjdG9yaW9zPyIsIA0KICAgICAgIHggPSAiUGFsYWJyYSIsIA0KICAgICAgIHkgPSAiRnJlY3VlbmNpYSIpICsNCiAgdGhlbWVfbWluaW1hbCgpIA0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp3b3JkY2xvdWQod29yZHMgPSBmcmVjdWVuY2lhX2RmXzEkd29yZCwNCiAgICAgICAgICBmcmVxID0gZnJlY3VlbmNpYV9kZl8xJGZyZXEsDQogICAgICAgICAgbWluLmZyZXEgPSAyLA0KICAgICAgICAgIHJhbmRvbS5vcmRlciA9IEZBTFNFLA0KICAgICAgICAgIHJvdC5wZXIgPSAwLjM1LCANCiAgICAgICAgICBjb2xvcnMgPSBicmV3ZXIucGFsKDgsICJSZEd5IiksDQogICAgICAgICAgc2NhbGUgPSBjKDQsMC41KSwgDQogICAgICAgICAgbWF4LndvcmRzID0gMTAwKSANCmBgYA0KDQojIyMgVGFibGFzIENydXphZGFzDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBUYWJsYSBjcnV6YWRhIHB1ZXN0b190cmFiYWpvIHkgY2xpbWENCkNyb3NzVGFibGUoZGZfbGlrZXJ0JHB1ZXN0b190cmFiYWpvLCBkZl9saWtlcnQkY2xpbWEsIHByb3AuYyA9IEZBTFNFLCBwcm9wLnQgPSBGQUxTRSwgcHJvcC5jaGlzcSA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFRhYmxhIGNydXphZGEgcHVlc3RvX3RyYWJham8geSBzYWxhcmlvDQpDcm9zc1RhYmxlKGRmX2xpa2VydCRwdWVzdG9fdHJhYmFqbywgZGZfbGlrZXJ0JHNhbGFyaW8sIHByb3AuYyA9IEZBTFNFLCBwcm9wLnQgPSBGQUxTRSwgcHJvcC5jaGlzcSA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFRhYmxhIGNydXphZGEgcHVlc3RvX3RyYWJham8geSBwcmVzdGFjaW9uZXMNCkNyb3NzVGFibGUoZGZfbGlrZXJ0JHB1ZXN0b190cmFiYWpvLCBkZl9saWtlcnQkcHJlc3RhY2lvbmVzLCBwcm9wLmMgPSBGQUxTRSwgcHJvcC50ID0gRkFMU0UsIHByb3AuY2hpc3EgPSBGQUxTRSkNCmBgYA0KIyMjIEdyw6FmaWNvIGRlIGRpc3BlcnNpw7NuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZ2dwbG90KGRmX2xpa2VydCwgYWVzKHg9YW50aWd1ZWRhZCwgeT1mdXR1cm9fZm9ybSkpICsgDQogIGdlb21fcG9pbnQoc2hhcGU9MTksIHNpemU9MykgKw0KICBsYWJzKHRpdGxlID0gIlJlbGFjacOzbiBlbnRyZSBhbnRpZ8O8ZWRhZCBlbiBsYSBlbXByZXNhIHkgdHJhYmFqYXIgZW4gdW4gZnV0dXJvIGVuIEZPUk0iLA0KICAgICAgIHg9IkFudGlnw7xlZGFkIChtZXNlcykiLCB5PSJGdXR1cm8gRk9STSIpICsgIA0KICB0aGVtZV9jbGFzc2ljKCkgDQpgYGANCg0KIyMjIEluc2VndXJpZGFkIHBvciBHw6luZXJvDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBUYWJsYSBkZSBmcmVjdWVuY2lhcyBjcnV6YWRhcyBlbnRyZSBnw6luZXJvIHkgb3BpbmnDs246IGZlbWVuaW5vDQpTaXR1YWNpb25lc19pbnNlZ3VyaWRhZF9mZW0gPC0gdGFibGUoZGZfZmVtZW5pbm8kaW5zZWd1cmlkYWQpDQoNCiMgQ3JlYXIgZWwgZ3LDoWZpY28gZGUgcGFzdGVsDQoNCmdncGxvdChkYXRhID0gTlVMTCwgYWVzKHggPSAiIiwgeSA9IFNpdHVhY2lvbmVzX2luc2VndXJpZGFkX2ZlbSwgZmlsbCA9IG5hbWVzKFNpdHVhY2lvbmVzX2luc2VndXJpZGFkX2ZlbSkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsNCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2M2YzZjNiIsICIjRkY3RjUwIiwgIiNGRjQ1MDAiKSkgKyANCiAgbGFicyh0aXRsZSA9ICLCv0hhcyBleHBlcmltZW50YWRvIHNpdHVhY2lvbmVzIGRlIGNvbmZsaWN0bywgYWNvc28gbyBxdWUgdGUgaGF5YW4gaGVjaG8gc2VudGlyIGluc2VndXJvKGEpIGR1cmFudGUgdHUgdGllbXBvIGVuIGxhIGVtcHJlc2E/IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKCguLnkuLikvc3VtKC4ueS4uKSoxMDApLCAiJSIpKSwgDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwgDQogICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIHNpemUgPSA0KQ0KYGBgDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBUYWJsYSBkZSBmcmVjdWVuY2lhcyBjcnV6YWRhcyBlbnRyZSBnw6luZXJvIHkgb3BpbmnDs246IG1hc2N1bGlubw0KU2l0dWFjaW9uZXNfaW5zZWd1cmlkYWRfbWFzYyA8LSB0YWJsZShkZl9tYXNjdWxpbm8kaW5zZWd1cmlkYWQpDQoNCiMgQ3JlYXIgZWwgZ3LDoWZpY28gZGUgcGFzdGVsDQpnZ3Bsb3QoZGF0YSA9IE5VTEwsIGFlcyh4ID0gIiIsIHkgPSBTaXR1YWNpb25lc19pbnNlZ3VyaWRhZF9tYXNjLCBmaWxsID0gbmFtZXMoU2l0dWFjaW9uZXNfaW5zZWd1cmlkYWRfbWFzYykpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsNCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2M2YzZjNiIsICIjRkY3RjUwIiwgIiNGRjQ1MDAiKSkgKyANCiAgbGFicyh0aXRsZSA9ICLCv0hhcyBleHBlcmltZW50YWRvIHNpdHVhY2lvbmVzIGRlIGNvbmZsaWN0bywgYWNvc28gbyBxdWUgdGUgaGF5YW4gaGVjaG8gc2VudGlyIGluc2VndXJvKGEpIGR1cmFudGUgdHUgdGllbXBvIGVuIGxhIGVtcHJlc2E/IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKCguLnkuLikvc3VtKC4ueS4uKSoxMDApLCAiJSIpKSwgDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwgDQogICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIHNpemUgPSA0KQ0KYGBgDQoNCiMjIyBBY29zb3MNCg0KYGBge3J9DQojIEVzdGFkbyBDaXZpbCBkZSBsb3MgVHJhYmFqYWRvcmVzDQoNCiMgQ2FsY3VsYXIgZWwgdG90YWwgZGUgb2JzZXJ2YWNpb25lcw0KdG90YWwgPC0gbnJvdyhkZjEpDQoNCiMgQ2FsY3VsYXIgbGEgZnJlY3VlbmNpYSBkZSBjYWRhIGNhdGVnb3LDrWEgZGUgZXN0YWRvIGNpdmlsDQpmcmVjdWVuY2lhX2VzdGFkb19jaXZpbCA8LSB0YWJsZShkZjEkRXN0YWRvX2NpdmlsKQ0KDQojIENhbGN1bGFyIGxvcyBwb3JjZW50YWplcw0KcG9yY2VudGFqZXMgPC0gKGZyZWN1ZW5jaWFfZXN0YWRvX2NpdmlsIC8gdG90YWwpICogMTAwDQoNCiMgQ3JlYXIgdW4gRGF0YUZyYW1lIGNvbiBsb3MgcG9yY2VudGFqZXMNCmRmX3BvcmNlbnRhamVzIDwtIGRhdGEuZnJhbWUoRXN0YWRvX2NpdmlsID0gbmFtZXMocG9yY2VudGFqZXMpLCBQb3JjZW50YWplID0gcG9yY2VudGFqZXMpDQoNCiMgR3JhZmljYXIgZWwgZ3LDoWZpY28gZGUgcGFzdGVsIGNvbiBwb3JjZW50YWplcw0KZ2dwbG90KGRmX3BvcmNlbnRhamVzLCBhZXMoeCA9ICIiLCB5ID0gUG9yY2VudGFqZS5GcmVxLCBmaWxsID0gRXN0YWRvX2NpdmlsKSkgKw0KICBnZW9tX2Jhcih3aWR0aCA9IDEsIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQoUG9yY2VudGFqZS5GcmVxKSwgIiUiKSksIA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMpICsNCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpICsNCiAgbGFicyh0aXRsZSA9ICJFc3RhZG8gQ2l2aWwgZGUgbG9zIFRyYWJhamFkb3JlcyIsIHkgPSAiUG9yY2VudGFqZSIpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcmFpbmJvdyhsZW5ndGgodW5pcXVlKGRmX3BvcmNlbnRhamVzJEVzdGFkb19jaXZpbCkpKSkNCmBgYA0KDQpgYGB7cn0NCiMgRGlzdHJpYmljaW9uIGRlIEdlbmVybyBkZSBsb3MgVHJhYmFqYWRvcmVzDQoNCiMgQ2FsY3VsYXIgZWwgdG90YWwgZGUgb2JzZXJ2YWNpb25lcw0KdG90YWwgPC0gbnJvdyhkZjEpDQoNCiMgQ2FsY3VsYXIgbGEgZnJlY3VlbmNpYSBkZSBjYWRhIGfDqW5lcm8NCmZyZWN1ZW5jaWFfZ2VuZXJvIDwtIHRhYmxlKGRmMSRHw6luZXJvKQ0KDQojIENhbGN1bGFyIGxvcyBwb3JjZW50YWplcw0KcG9yY2VudGFqZXMgPC0gKGZyZWN1ZW5jaWFfZ2VuZXJvIC8gdG90YWwpICogMTAwDQoNCiMgQ3JlYXIgdW4gRGF0YUZyYW1lIGNvbiBsb3MgcG9yY2VudGFqZXMNCmRmX3BvcmNlbnRhamVzIDwtIGRhdGEuZnJhbWUoR8OpbmVybyA9IG5hbWVzKHBvcmNlbnRhamVzKSwgUG9yY2VudGFqZSA9IHBvcmNlbnRhamVzKQ0KDQojIEdyYWZpY2FyIGVsIGdyw6FmaWNvIGRlIHBhc3RlbCBjb24gcG9yY2VudGFqZXMNCmdncGxvdChkZl9wb3JjZW50YWplcywgYWVzKHggPSAiIiwgeSA9IFBvcmNlbnRhamUuRnJlcSwgZmlsbCA9IEfDqW5lcm8pKSArDQogIGdlb21fYmFyKHdpZHRoID0gMSwgc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChyb3VuZChQb3JjZW50YWplLkZyZXEpLCAiJSIpKSwgDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgR8OpbmVybyBkZSBsb3MgVHJhYmFqYWRvcmVzIiwgeSA9ICJQb3JjZW50YWplIikgKw0KICB0aGVtZV92b2lkKCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJibHVlIiwgInBpbmsiKSkgICMgUHVlZGVzIGNhbWJpYXIgbG9zIGNvbG9yZXMgc2kgbG8gZGVzZWFzDQoNCmBgYA0KDQpgYGB7cn0NCiMgRXN0YWRvIGNpdmlsIGRlIGxvcyBUcmFiYWhhZG9yZXMgcG9yIEfDqW5lcm8NCg0KIyBGaWx0cmFyIGRhdG9zIHBvciBnw6luZXJvIGZlbWVuaW5vDQpkZl9mZW1lbmlubyA8LSBzdWJzZXQoZGYxLCBHw6luZXJvID09ICJGZW1lbmlubyIpDQoNCiMgQ2FsY3VsYXIgZWwgdG90YWwgZGUgb2JzZXJ2YWNpb25lcyBwYXJhIGVsIGfDqW5lcm8gZmVtZW5pbm8NCnRvdGFsX2ZlbWVuaW5vIDwtIG5yb3coZGZfZmVtZW5pbm8pDQoNCiMgQ2FsY3VsYXIgbGEgZnJlY3VlbmNpYSBkZSBjYWRhIGNhdGVnb3LDrWEgZGUgZXN0YWRvIGNpdmlsIHBhcmEgZWwgZ8OpbmVybyBmZW1lbmlubw0KZnJlY3VlbmNpYV9lc3RhZG9fY2l2aWxfZmVtZW5pbm8gPC0gdGFibGUoZGZfZmVtZW5pbm8kRXN0YWRvX2NpdmlsKQ0KDQojIENhbGN1bGFyIGxvcyBwb3JjZW50YWplcyBwYXJhIGVsIGfDqW5lcm8gZmVtZW5pbm8NCnBvcmNlbnRhamVzX2ZlbWVuaW5vIDwtIChmcmVjdWVuY2lhX2VzdGFkb19jaXZpbF9mZW1lbmlubyAvIHRvdGFsX2ZlbWVuaW5vKSAqIDEwMA0KDQojIENyZWFyIHVuIERhdGFGcmFtZSBjb24gbG9zIHBvcmNlbnRhamVzIHBhcmEgZWwgZ8OpbmVybyBmZW1lbmlubw0KZGZfcG9yY2VudGFqZXNfZmVtZW5pbm8gPC0gZGF0YS5mcmFtZShFc3RhZG9fY2l2aWwgPSBuYW1lcyhwb3JjZW50YWplc19mZW1lbmlubyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQb3JjZW50YWplID0gcG9yY2VudGFqZXNfZmVtZW5pbm8sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBHZW5lcm8gPSAiRmVtZW5pbm8iKQ0KDQojIEdyYWZpY2FyIGVsIGdyw6FmaWNvIGRlIHBhc3RlbCBwYXJhIGVsIGfDqW5lcm8gZmVtZW5pbm8NCmdncGxvdChkZl9wb3JjZW50YWplc19mZW1lbmlubywgYWVzKHggPSAiIiwgeSA9IFBvcmNlbnRhamUuRnJlcSwgZmlsbCA9IEVzdGFkb19jaXZpbCkpICsNCiAgZ2VvbV9iYXIod2lkdGggPSAxLCBzdGF0ID0gImlkZW50aXR5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKFBvcmNlbnRhamUuRnJlcSksICIlIikpLCANCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiRXN0YWRvIENpdmlsIGRlIGxvcyBUcmFiYWphZG9yZXMgLSBHw6luZXJvIEZlbWVuaW5vIiwgeSA9ICJQb3JjZW50YWplIikgKw0KICB0aGVtZV92b2lkKCkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSByYWluYm93KGxlbmd0aCh1bmlxdWUoZGZfcG9yY2VudGFqZXNfZmVtZW5pbm8kRXN0YWRvX2NpdmlsKSkpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICMgUGFyYSBvY3VsdGFyIGxhIGxleWVuZGENCg0KIyBGaWx0cmFyIGRhdG9zIHBvciBnw6luZXJvIG1hc2N1bGlubw0KZGZfbWFzY3VsaW5vIDwtIHN1YnNldChkZjEsIEfDqW5lcm8gPT0gIk1hc2N1bGlubyIpDQoNCiMgQ2FsY3VsYXIgZWwgdG90YWwgZGUgb2JzZXJ2YWNpb25lcyBwYXJhIGVsIGfDqW5lcm8gbWFzY3VsaW5vDQp0b3RhbF9tYXNjdWxpbm8gPC0gbnJvdyhkZl9tYXNjdWxpbm8pDQoNCiMgQ2FsY3VsYXIgbGEgZnJlY3VlbmNpYSBkZSBjYWRhIGNhdGVnb3LDrWEgZGUgZXN0YWRvIGNpdmlsIHBhcmEgZWwgZ8OpbmVybyBtYXNjdWxpbm8NCmZyZWN1ZW5jaWFfZXN0YWRvX2NpdmlsX21hc2N1bGlubyA8LSB0YWJsZShkZl9tYXNjdWxpbm8kRXN0YWRvX2NpdmlsKQ0KDQojIENhbGN1bGFyIGxvcyBwb3JjZW50YWplcyBwYXJhIGVsIGfDqW5lcm8gbWFzY3VsaW5vDQpwb3JjZW50YWplc19tYXNjdWxpbm8gPC0gKGZyZWN1ZW5jaWFfZXN0YWRvX2NpdmlsX21hc2N1bGlubyAvIHRvdGFsX21hc2N1bGlubykgKiAxMDANCg0KIyBDcmVhciB1biBEYXRhRnJhbWUgY29uIGxvcyBwb3JjZW50YWplcyBwYXJhIGVsIGfDqW5lcm8gbWFzY3VsaW5vDQpkZl9wb3JjZW50YWplc19tYXNjdWxpbm8gPC0gZGF0YS5mcmFtZShFc3RhZG9fY2l2aWwgPSBuYW1lcyhwb3JjZW50YWplc19tYXNjdWxpbm8pLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBvcmNlbnRhamUgPSBwb3JjZW50YWplc19tYXNjdWxpbm8sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR2VuZXJvID0gIk1hc2N1bGlubyIpDQoNCiMgR3JhZmljYXIgZWwgZ3LDoWZpY28gZGUgcGFzdGVsIHBhcmEgZWwgZ8OpbmVybyBtYXNjdWxpbm8NCmdncGxvdChkZl9wb3JjZW50YWplc19tYXNjdWxpbm8sIGFlcyh4ID0gIiIsIHkgPSBQb3JjZW50YWplLkZyZXEsIGZpbGwgPSBFc3RhZG9fY2l2aWwpKSArDQogIGdlb21fYmFyKHdpZHRoID0gMSwgc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChyb3VuZChQb3JjZW50YWplLkZyZXEpLCAiJSIpKSwgDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKw0KICBsYWJzKHRpdGxlID0gIkVzdGFkbyBDaXZpbCBkZSBsb3MgVHJhYmFqYWRvcmVzIC0gR8OpbmVybyBNYXNjdWxpbm8iLCB5ID0gIlBvcmNlbnRhamUiKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHJhaW5ib3cobGVuZ3RoKHVuaXF1ZShkZl9wb3JjZW50YWplc19tYXNjdWxpbm8kRXN0YWRvX2NpdmlsKSkpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgICMgUGFyYSBvY3VsdGFyIGxhIGxleWVuZGENCg0KYGBgDQoNCg0KYGBge3J9DQojRXhwZXJpZW5jaWEgZGUgQWNvc28gZW4gZWwgVHJhYmFqbyBwb3IgR8OpbmVybw0KDQojIENvbnRhciBsYSBjYW50aWRhZCBkZSBob21icmVzIHkgbXVqZXJlcyBxdWUgaGFuIGV4cGVyaW1lbnRhZG8gbyBubyBhY29zbyBlbiBlbCB0cmFiYWpvDQphY29zb19wb3JfZ2VuZXJvIDwtIHRhYmxlKGRmMSRHw6luZXJvLCBkZjEkcDExKQ0KDQojIE9idGVuZXIgbGFzIGNhdGVnb3LDrWFzIMO6bmljYXMgZGUgZ8OpbmVybyB5IGFjb3NvDQpjYXRlZ29yaWFzX2dlbmVybyA8LSB1bmlxdWUoZGYxJEfDqW5lcm8pDQpjYXRlZ29yaWFzX2Fjb3NvIDwtIHVuaXF1ZShkZjEkcDExKQ0KDQojIENyZWFyIHVuIGRhdGEgZnJhbWUgcGFyYSBhbG1hY2VuYXIgbG9zIHJlc3VsdGFkb3MNCmRmX2Fjb3NvX3Bvcl9nZW5lcm8gPC0gZGF0YS5mcmFtZShHw6luZXJvID0gY2hhcmFjdGVyKCksIEFjb3NvID0gY2hhcmFjdGVyKCksIENvdW50ID0gbnVtZXJpYygpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCiMgQ29tcGxldGFyIGVsIGRhdGEgZnJhbWUgY29uIHRvZGFzIGxhcyBjb21iaW5hY2lvbmVzIHBvc2libGVzIGRlIGfDqW5lcm8geSBhY29zbw0KZm9yIChnZW4gaW4gY2F0ZWdvcmlhc19nZW5lcm8pIHsNCiAgZm9yIChhY29zIGluIGNhdGVnb3JpYXNfYWNvc28pIHsNCiAgICBjb3VudCA8LSBhY29zb19wb3JfZ2VuZXJvW2dlbiwgYWNvc10NCiAgICBkZl9hY29zb19wb3JfZ2VuZXJvIDwtIHJiaW5kKGRmX2Fjb3NvX3Bvcl9nZW5lcm8sIGRhdGEuZnJhbWUoR8OpbmVybyA9IGdlbiwgQWNvc28gPSBhY29zLCBDb3VudCA9IGNvdW50KSkNCiAgfQ0KfQ0KDQojIFJlb3JkZW5hciBsb3Mgbml2ZWxlcyBkZSBsYSB2YXJpYWJsZSAiQWNvc28iIHBhcmEgcXVlIGNvaW5jaWRhbiBjb24gZWwgb3JkZW4gZGUgbG9zIGRhdG9zIHJlYWxlcw0KZGZfYWNvc29fcG9yX2dlbmVybyRBY29zbyA8LSBmYWN0b3IoZGZfYWNvc29fcG9yX2dlbmVybyRBY29zbywgbGV2ZWxzID0gYygiU2kiLCAiTm8iLCAiUHJlZmllcm8gbm8gZGVjaXJsbyIpKQ0KDQojIEdyYWZpY2FyIGxhIGdyw6FmaWNhIGRlIGJhcnJhcw0KZ2dwbG90KGRmX2Fjb3NvX3Bvcl9nZW5lcm8sIGFlcyh4ID0gR8OpbmVybywgeSA9IENvdW50LCBmaWxsID0gQWNvc28pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgbGFicyh0aXRsZSA9ICJFeHBlcmllbmNpYSBkZSBBY29zbyBlbiBlbCBUcmFiYWpvIHBvciBHw6luZXJvIiwNCiAgICAgICB4ID0gIkfDqW5lcm8iLA0KICAgICAgIHkgPSAiQ2FudGlkYWQiLA0KICAgICAgIGZpbGwgPSAiRXhwZXJpZW5jaWEgZGUgQWNvc28iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIlNpIiA9ICJzYWxtb24iLCAiTm8iID0gImxpZ2h0Ymx1ZSIsICJQcmVmaWVybyBubyBkZWNpcmxvIiA9ICJ5ZWxsb3ciKSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCg0KYGBge3J9DQojRXhwZXJpZW5jaWEgZGUgQWNvc28gZW4gZWwgVHJhYmFqbyBwb3IgRXN0YWRvIENpdmlsDQoNCiMgQ29udGFyIGxhIGNhbnRpZGFkIGRlIGhvbWJyZXMgeSBtdWplcmVzIHF1ZSBoYW4gZXhwZXJpbWVudGFkbyBvIG5vIGFjb3NvIGVuIGVsIHRyYWJham8NCmFjb3NvX3Bvcl9nZW5lcm8gPC0gdGFibGUoZGYxJEVzdGFkb19jaXZpbCwgZGYxJHAxMSkNCg0KIyBPYnRlbmVyIGxhcyBjYXRlZ29yw61hcyDDum5pY2FzIGRlIGfDqW5lcm8geSBhY29zbw0KY2F0ZWdvcmlhc19nZW5lcm8gPC0gdW5pcXVlKGRmMSRFc3RhZG9fY2l2aWwpDQpjYXRlZ29yaWFzX2Fjb3NvIDwtIHVuaXF1ZShkZjEkcDExKQ0KDQojIENyZWFyIHVuIGRhdGEgZnJhbWUgcGFyYSBhbG1hY2VuYXIgbG9zIHJlc3VsdGFkb3MNCmRmX2Fjb3NvX3Bvcl9lc3RhZG9fY2l2aWwgPC0gZGF0YS5mcmFtZShFc3RhZG9DaXZpbCA9IGNoYXJhY3RlcigpLCBBY29zbyA9IGNoYXJhY3RlcigpLCBDb3VudCA9IG51bWVyaWMoKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIENvbXBsZXRhciBlbCBkYXRhIGZyYW1lIGNvbiB0b2RhcyBsYXMgY29tYmluYWNpb25lcyBwb3NpYmxlcyBkZSBnw6luZXJvIHkgYWNvc28NCmZvciAoZ2VuIGluIGNhdGVnb3JpYXNfZ2VuZXJvKSB7DQogIGZvciAoYWNvcyBpbiBjYXRlZ29yaWFzX2Fjb3NvKSB7DQogICAgY291bnQgPC0gYWNvc29fcG9yX2dlbmVyb1tnZW4sIGFjb3NdDQogICAgZGZfYWNvc29fcG9yX2VzdGFkb19jaXZpbCA8LSByYmluZChkZl9hY29zb19wb3JfZXN0YWRvX2NpdmlsLCBkYXRhLmZyYW1lKEVzdGFkb0NpdmlsID0gZ2VuLCBBY29zbyA9IGFjb3MsIENvdW50ID0gY291bnQpKQ0KICB9DQp9DQoNCiMgUmVvcmRlbmFyIGxvcyBuaXZlbGVzIGRlIGxhIHZhcmlhYmxlICJBY29zbyIgcGFyYSBxdWUgY29pbmNpZGFuIGNvbiBlbCBvcmRlbiBkZSBsb3MgZGF0b3MgcmVhbGVzDQpkZl9hY29zb19wb3JfZXN0YWRvX2NpdmlsJEFjb3NvIDwtIGZhY3RvcihkZl9hY29zb19wb3JfZXN0YWRvX2NpdmlsJEFjb3NvLCBsZXZlbHMgPSBjKCJTaSIsICJObyIsICJQcmVmaWVybyBubyBkZWNpcmxvIikpDQoNCiMgR3JhZmljYXIgbGEgZ3LDoWZpY2EgZGUgYmFycmFzDQpnZ3Bsb3QoZGZfYWNvc29fcG9yX2VzdGFkb19jaXZpbCwgYWVzKHggPSBFc3RhZG9DaXZpbCwgeSA9IENvdW50LCBmaWxsID0gQWNvc28pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgbGFicyh0aXRsZSA9ICJFeHBlcmllbmNpYSBkZSBBY29zbyBlbiBlbCBUcmFiYWpvIHBvciBHw6luZXJvIiwNCiAgICAgICB4ID0gIkVzdGFkbyBDaXZpbCIsDQogICAgICAgeSA9ICJDYW50aWRhZCIsDQogICAgICAgZmlsbCA9ICJFeHBlcmllbmNpYSBkZSBBY29zbyIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiU2kiID0gInNhbG1vbiIsICJObyIgPSAibGlnaHRibHVlIiwgIlByZWZpZXJvIG5vIGRlY2lybG8iID0gInllbGxvdyIpKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KIyMgSGFsbGF6Z29zIGRlbCBDbGltYSBMYWJvcmFsDQoqIExhIG1heW9yw61hIGRlIGxvcyBlbmN1ZXN0YWRvcyB0aWVuZW4gZW50cmUgMjAgeSA0MCBhw7FvcyBkZSBlZGFkLiANCiogRWwgNjUlIGRlIGxhcyByZXNwdWVzdGFzIGRlIGVzdGEgZW5jdWVzdGEgY29ycmVzcG9uZGVuIGFsIGfDqW5lcm8gZmVtZW5pbm8geSBlbCAzNSUgcmVzdGFudGUgYWwgZ8OpbmVybyBtYXNjdWxpbm8uICANCg0KKiBFbCA3MiUgZGUgbG9zIGVuY3Vlc3RhZG9zIHJlc2lkZW4gZW4gZWwgbXVuaWNpcGlvIGRlIEFwb2RhY2EuICANCiogQSBleGNlcGNpw7NuIGRlbCBtdW5pY2lwaW8gZGUgSnXDoXJleiwgbGEgbWF5b3LDrWEgZGUgbG9zIGVuY3Vlc3RhZG9zIGNvbiByZXNpZGVuY2lhIGVuIG11bmljaXBpb3MgZGlmZXJlbnRlcyBhIEFwb2RhY2EgY29uc2lkZXJhbiBxdWUgc2UgcHVlZGUgdHJhbnNwb3J0YXIgZGUgZm9ybWEgc2VndXJhIGRlIHN1IGNhc2EgYWwgdHJhYmFqbyB5IG5vIGxlcyBjdWVzdGEgZGVtYXNpYWRvIGVzZnVlcnpvIGxsZWdhci4gIA0KDQoqIExhIHViaWNhY2nDs24gZGUgbGEgZW1wcmVzYSBlcyBsYSBwcmluY2lwYWwgcmF6w7NuIHBvciBsYSBxdWUgbGEgbWF5b3LDrWEgZGUgaG9tYnJlcyB5IG11amVyZXMgZW50cmFuIGEgZXN0ZSB0cmFiYWpvLg0KKiBPdHJvIHkgZWwgc2FsYXJpbyBzb24gZG9zIGRlIGxhcyB0b3AgMyByYXpvbmVzIHBvciBsYXMgcXVlIGVsIGfDqW5lcm8gbWFzY3VsaW5vIGVudHJhIGEgZXN0ZSB0cmFiYWpvLg0KKiBSYXpvbmVzIHBlcnNvbmFsZXMgeSBvdHJvIHNvbiBkb3MgZGUgbGFzIHRvcCAzIHJhem9uZXMgcG9yIGxhcyBxdWUgZWwgZ8OpbmVybyBmZW1lbmlubyBlbnRyYSBhIGVzdGUgdHJhYmFqby4gIA0KDQoqIEVsIGNhbG9yLCBsYXMgcHJlc3RhY2lvbmVzIHkgZWwgc2FsYXJpbyBzb24gbG9zIGFzcGVjdG9zIG1lbm9zIHNhdGlzZmFjdG9yaW9zIGRlbCBwdWVzdG8gYWN0dWFsIGRlIGxhIG1heW9yw61hIGRlIGxvcyBlbnRyZXZpc3RhZG9zIChlc3RvIG5vIGNvbnNpZGVyYSBhIGNvbGFib3JhZG9yZXMgY29uIHVuYSBvcGluacOzbiBwb3NpdGl2YSBzb2JyZSBzdSBwdWVzdG8pLiAgDQoqIExvcyBzZW50aW1pZW50byBjb24gbWF5b3IgZnJlY3VlbmNpYSBlbiBsb3MgY29sYWJvcmFkb3JlcyBkZSBhbWJvcyBnw6luZXJvcyBzb24gYWxlZ3LDrWEsIGNvbmZpYW56YSB5IGFudGljaXBhY2nDs24uIEFkZW3DoXMsIGVsIDM0JSAoMzYvMTA2KSBkZSBsb3MgZW5jdWVzdGFkb3Mgbm8gY2FsaWZpY2EgYWxndW5vIGRlIGxvcyBhc3BlY3RvcyBkZSBzdSBwdWVzdG8gYWN0dWFsIGNvbW8gbm8gc2F0aXNmYWN0b3JpbywgZXMgZGVjaXIsIHNlIHNpZW50ZW4gYmllbiBjb24gc3UgcHVlc3RvIGRlIHRyYWJham8uDQoNCiogQXl1ZGFudGUgZ2VuZXJhbCwgYWRtaW5pc3RyYXRpdm8sIGNvc3R1cmVyYSwgc3VwZXJ2aXNvcihhKSwgb3BlcmFkb3IgeSBtb250YWNhcmd1aXN0YSBzb24gbG9zIHB1ZXN0b3MgZGUgdHJhYmFqbyBwYXJhIGxvcyBjdWFsZXMgcmVzcG9uZGllcm9uIGxhIGVuY3Vlc3RhIHVuIG1heW9yIG7Dum1lcm8gZGUgcGVyc29uYXMgKG3DrW5pbW8gMywgbcOheGltbyA0NiBwZXJzb25hcykuICANCg0KKiBBIGVsIDUwJSBkZSBsb3MgYXl1ZGFudGVzIGdlbmVyYWxlcywgNDMlIGRlIGxhcyBjb3N0dXJlcmFzIHkgNjYlIGRlIGxvcyBtb250YWNhcmd1aXN0YXMgbGVzIG1vbGVzdGEgdG90YWwgbyBtZWRpYW5hbWVudGUgcXVlIGhhZ2EgbXVjaG8gZnLDrW8gbyBjYWxvciBlbiBzdSDDoXJlYSBkZSB0cmFiYWpvLiAgDQoNCiMjIEJ1zIFzcXVlZGEgZGUgaW5mb3JtYWNpb8yBbiB5IGRhdG9zIGRlIFJIDQoNCiogKirCv1F1w6kgdGlwbyBkZSBpbmZvcm1hY2nDs24gLyBkYXRvcyBzb2xpY2l0YXLDrWFzIGFsIHNvY2lvIGZvcm1hZG9yIHBhcmEgbWVqb3JhciBFREE/KioNCg0KICArIFVuYSBiYXNlIGRlIGRhdG9zIGNvbiBsb3MgcmVnaXN0cm9zIGRlIHRvZGFzIGxhcyBwZXJzb25hcyBxdWUgaGF5YW4gZGVqYWRvIGxhIGVtcHJlc2EgY29uIGRldGFsbGVzIGRlbW9ncsOhZmljb3MsIGRlIG9waW5pw7NuIGNvbW8gbGEgcmF6w7NuIHBvciBsYSBxdWUgb3B0YXJvbiBwb3IgdG9tYXIgZXNhIGRlY2lzacOzbiwgeSBjYXJhY3RlcsOtc3RpY2FzIGNvbW8gZWwgdGllbXBvIHF1ZSBsbGV2YWJhbiBlbiBsYSBvcmdhbml6YWNpw7NuIG8gc3UgcHVlc3RvIGRlIHRyYWJham8uDQogICsgTm9tYnJlIGRlIGxhcyDDoXJlYXMgZW4gbGFzIHF1ZSBzZSBkaXZpZGUgRk9STS4gRW4gZXN0ZSBjYXNvIGNvbnRhbW9zIGNvbiBsb3MgcHVlc3RvcyBkZSB0cmFiYWpvLCDCv2EgcXXDqSDDoXJlYSBjb3JyZXNwb25kZSBjYWRhIHB1ZXN0bz8NCiAgKyBTdWVsZG8gcG9yIMOhcmVhLCBlc3RyYXRlZ2lhcyBpbXBsZW1lbnRhZGFzIHBhcmEgY29udHJpYnVpciBhbCBiaWVuZXN0YXIgZGUgc3VzIGNvbGFib3JhZG9yZXMsIHBlcmZpbCBxdWUgYnVzY2FuIHBhcmEgY29udHJhdGFyIGEgYWxndWllbiwgZXN0cmF0ZWdpYXMgZGUgcmVjbHV0YW1pZW50bywgaW5mb3JtYWNpw7NuIHNvYnJlIGVsIHByb2Nlc28gZGUgc2VsZWNjacOzbiBkZSBhcGxpY2FudGVzLiANCg0KDQoqICoqwr9RdcOpIHRpcG8gZGUgaW5mb3JtYWNpw7NuIC8gZGF0b3MgZGUgZnVlbnRlcyBzZWN1bmRhcmlhcyBidXNjYXLDrWFzIHBhcmEgbWVqb3JhciBFREE/KioNCg0KICArIFNlcsOtYSBtdXkgaW50ZXJlc2FudGUgYnVzY2FyIGJhc2VzIGRlIGRhdG9zIHF1ZSBjb250ZW5nYW4gcmVnaXN0cm9zIGRlIGxhIHJvdGFjacOzbiBkZWwgcGVyc29uYWwgZGUgb3RyYXMgZW1wcmVzYXMgcGFyYSBjb21wYXJhciBlbCBkZXNlbXBlw7FvIGRlIEZPUk0gY29uIHN1cyBjb21wZXRpZG9yZXMgbcOhcyBpbW1wb3J0YW50ZXMgZGVsIG1lcmNhZG8sIG8gaW5jbHVzbyBjb24gb3Ryb3MgbmVnb2Npb3MgZGUgbGEgbWlzbWEgaW5kdXN0cmlhLiANCiAgKyBQYXJhIGxhIHNpdHVhY2nDs24gcHJvYmxlbWEgZGUgUmVjdXJzb3MgSHVtYW5vcyBzZXLDrWEgZGUgZ3JhbiB1dGlsaWRhZCBvYnRlbmVyIGluZm9ybWFjacOzbiBtw6FzIGRldGFsbGFkYSBlbiBsYXMgZW5jdWVzdGFzIGFzw60gY29tbyB0YW1iacOpbiBhc2VndXJhciBxdWUgbGEgbXVlc3RyYSBzZWEgcmVwcmVzZW50YXRpdmEgcGFyYSByZWFsaXphciBpbmZlcmVuY2lhcyB5IGdlbmVyYWxpemFyIGxhIGluZm9ybWFjacOzbiBvYnRlbmlkYSBwYXJhIGNhZGEgdW5vIGRlIGxvcyBkZXBhcnRhbWVudG9zIGRlIGxhIGVtcHJlc2EuICANCiAgKyBJbmZvcm1hY2nDs24gbcOhcyBkZXRhbGxhZGEgZW4gbGFzIGVuY3Vlc3RhcyBjb21vIMOhcmVhIG8gZGVwYXJ0YW1lbnRvIGRlbCBwdWVzdG8gZGUgdHJhYmFqbywgZXZhbHVhY2nDs24gZGVsIGFtYmllbnRlIGxhYm9yYWwsIHZlbnRhamFzIGRlIHRyYWJhamFyIGVuIEZPUk0sIHNpIGxvcyBjb2xhYm9yYWRvcmVzIHJlY29tZW5kYXLDrWFuIHRyYWJhamFyIG8gbm8gZW4gRk9STSwgZmFjdG9yZXMgbcOhcyBpbXBvcnRhbnRlIGFsIGVsZWdpciBlbiBxdcOpIGVtcHJlc2EgdHJhYmFqYXIsIGV0Yy4gIA0KDQoNCg0KDQoNCiMgU2l0dWFjacOzbiBQcm9ibGVtYSAyOiBOZWFyc2hvcmluZyB5IFZlbnRhcyBGT1JNDQoNCkxhKHMpIHBvc2libGUocykgZXN0cmF0ZWdpYShzKSBkZSBwcmVkaWNjaW/MgW4gZGUgbGEgZGVtYW5kYSBkZSBwcm9kdWN0byBmYWJyaWNhZG9zIHBvciBsYSBlbXByZXNhIEZPUk0uDQoNCg0KDQoqKkxpYnJlcsOtYXMqKg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZm9yZWlnbikNCmxpYnJhcnkoZHlncmFwaHMpDQpsaWJyYXJ5KGRwbHlyKSAgICAgICAgIyBkYXRhIG1hbmlwdWxhdGlvbiANCmxpYnJhcnkoZm9yY2F0cykgICAgICAjIHRvIHdvcmsgd2l0aCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMNCmxpYnJhcnkoZ2dwbG90MikgICAgICAjIGRhdGEgdmlzdWFsaXphdGlvbiANCmxpYnJhcnkocmVhZHIpICAgICAgICAjIHJlYWQgc3BlY2lmaWMgY3N2IGZpbGVzDQpsaWJyYXJ5KGphbml0b3IpICAgICAgIyBkYXRhIGV4cGxvcmF0aW9uIGFuZCBjbGVhbmluZyANCmxpYnJhcnkoSG1pc2MpICAgICAgICAjIHNldmVyYWwgdXNlZnVsIGZ1bmN0aW9ucyBmb3IgZGF0YSBhbmFseXNpcyANCmxpYnJhcnkocHN5Y2gpICAgICAgICAjIGZ1bmN0aW9ucyBmb3IgbXVsdGl2YXJpYXRlIGFuYWx5c2lzIA0KbGlicmFyeShuYW5pYXIpICAgICAgICMgc3VtbWFyaWVzIGFuZCB2aXN1YWxpemF0aW9uIG9mIG1pc3NpbmcgdmFsdWVzIE5BJ3MNCmxpYnJhcnkoY29ycnBsb3QpICAgICAjIGNvcnJlbGF0aW9uIHBsb3RzDQpsaWJyYXJ5KGp0b29scykgICAgICAgIyBwcmVzZW50YXRpb24gb2YgcmVncmVzc2lvbiBhbmFseXNpcyANCmxpYnJhcnkobG10ZXN0KSAgICAgICAjIGRpYWdub3N0aWMgY2hlY2tzIC0gbGluZWFyIHJlZ3Jlc3Npb24gYW5hbHlzaXMgDQpsaWJyYXJ5KGNhcikgICAgICAgICAgIyBkaWFnbm9zdGljIGNoZWNrcyAtIGxpbmVhciByZWdyZXNzaW9uIGFuYWx5c2lzDQpsaWJyYXJ5KG9sc3JyKSAgICAgICAgIyBkaWFnbm9zdGljIGNoZWNrcyAtIGxpbmVhciByZWdyZXNzaW9uIGFuYWx5c2lzIA0KbGlicmFyeShuYW5pYXIpICAgICAgICMgaWRlbnRpZnlpbmcgbWlzc2luZyB2YWx1ZXMNCmxpYnJhcnkoc3RhcmdhemVyKSAgICAjIGNyZWF0ZSBwdWJsaWNhdGlvbiBxdWFsaXR5IHRhYmxlcw0KbGlicmFyeShlZmZlY3RzKSAgICAgICMgZGlzcGxheXMgZm9yIGxpbmVhciBhbmQgb3RoZXIgcmVncmVzc2lvbiBtb2RlbHMNCmxpYnJhcnkodGlkeXZlcnNlKSAgICAjIGNvbGxlY3Rpb24gb2YgUiBwYWNrYWdlcyBkZXNpZ25lZCBmb3IgZGF0YSBzY2llbmNlDQpsaWJyYXJ5KGNhcmV0KSAgICAgICAgIyBDbGFzc2lmaWNhdGlvbiBhbmQgUmVncmVzc2lvbiBUcmFpbmluZyANCmxpYnJhcnkoZ2xtbmV0KSAgICAgICAjIG1ldGhvZHMgZm9yIHByZWRpY3Rpb24gYW5kIHBsb3R0aW5nLCBhbmQgZnVuY3Rpb25zIGZvciBjcm9zcy12YWxpZGF0aW9uDQpsaWJyYXJ5KHh0cykNCmxpYnJhcnkoem9vKQ0KbGlicmFyeSh0c2VyaWVzKQ0KbGlicmFyeShzdGF0cykNCmxpYnJhcnkoZm9yZWNhc3QpDQpsaWJyYXJ5KGFzdHNhKQ0KbGlicmFyeShBRVIpDQpsaWJyYXJ5KGR5bmxtKQ0KbGlicmFyeSh2YXJzKQ0KbGlicmFyeShUU3N0dWRpbykNCmxpYnJhcnkoc2FyaW1hKQ0KbGlicmFyeShEYXRhRXhwbG9yZXIpDQpsaWJyYXJ5KGNvcnJwbG90KSAgICAgIyBjb3JyZWxhdGlvbiBwbG90cw0KbGlicmFyeShyZWFkeGwpDQpgYGANCg0KIyBOZWFyc2hvcmluZw0KDQojIyBQcmVndW50YXMgZGUgQW7DoWxpc2lzIGRlIE5lYXJzaG9yaW5nDQoqIMK/UXXDqSBzZSBlc3BlcmEgZW4gbGEgaW52ZXJzacOzbiBkaXJlY3RhIGV4dHJhbmplcmEgZW4gbG9zIHByb3hpbW9zIGHDsW9zPw0KKiDCv0N1w6FsIGVzIGxhIG1hZ25pdHVkIGRlbCBpbXBhY3RvIHF1ZSBwdWVkZSBsbGVnYXIgYSB0ZW5lciBlbCBuZWFyc2hvcmluZyANCiogwr9DdcOhbCBlcyBlbCBkZXNlbXBlw7FvIGRlIEZPUk0gYWN0dWFsIHkgY29tbyBzZSBwdWVkZSB2ZXIgYWZlY3RhZG8gcG9yIGxhIHNpdHVhY2nDs24gcHJvYmxlbWENCiogwr9Dw7NtbyBzZSB2ZSBlbCBkZXNlbXBlw7FvIGRlIEZPUk0gZW4gbG9zIHByb3hpbW9zIGHDsW9zPw0KDQojIyBMaW1waWV6YSB5IE9yZ2FuaXphY2nDs24gZGUgQmFzZSBkZSBEYXRvcyBOZWFyc2hvcmluZw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRmIDwtIHJlYWRfZXhjZWwoIkM6XFxVc2Vyc1xcbGVzZGFfYjV3ZnFxYVxcRG93bmxvYWRzXFxldjFcXG5lYXJzaG9yaW5nX2RhdG9zX3Nlcmllc19kZV90aWVtcG9fdHJpbWVzdHJhbC54bHN4IikNCg0KDQpgYGANCg0KIyMjIFByaW1lcm9zIHJlbmdsb25lcyBkZSBOZWFyc2hvcmluZw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmhlYWQoZGYpDQpzdHIoZGYpDQpgYGANCg0KIyMjIENvcnJlY2nDs24gZGUgdGlwbyBkZSB2YXJpYWJsZXMgZW4gTmVhcnNob3JpbmcNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkZiREYXRlIDwtIHltZChwYXN0ZTAoZGYkWWVhciwgIi0iLCANCiAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkUXVhcnRlciA9PSAiSSIsICIwMS0wMSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkUXVhcnRlciA9PSAiSUkiLCAiMDQtMDEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRRdWFydGVyID09ICJJSUkiLCAiMDctMDEiLCAiMTAtMDEiKSkpKSkNCg0KZGYkWWVhciA8LSBhcy5EYXRlKGRmJFllYXIpDQoNCmRmJFF1YXJ0ZXIgPC0gaWZlbHNlKGRmJFF1YXJ0ZXIgPT0gIkkiLCAiQSIsIGRmJFF1YXJ0ZXIpDQpkZiRRdWFydGVyIDwtIGlmZWxzZShkZiRRdWFydGVyID09ICJJSSIsIkIiLCBkZiRRdWFydGVyKQ0KZGYkUXVhcnRlciA8LSBpZmVsc2UoZGYkUXVhcnRlciA9PSAiSUlJIiwiQyIsIGRmJFF1YXJ0ZXIpDQpkZiRRdWFydGVyIDwtIGlmZWxzZShkZiRRdWFydGVyID09ICJJViIsIkQiLCBkZiRRdWFydGVyKQ0KDQpkZiRRdWFydGVyIDwtIGlmZWxzZShkZiRRdWFydGVyID09ICJBIiwgMSwgZGYkUXVhcnRlcikNCmRmJFF1YXJ0ZXIgPC0gaWZlbHNlKGRmJFF1YXJ0ZXIgPT0gIkIiLCAyLCBkZiRRdWFydGVyKQ0KZGYkUXVhcnRlciA8LSBpZmVsc2UoZGYkUXVhcnRlciA9PSAiQyIsIDMsIGRmJFF1YXJ0ZXIpDQpkZiRRdWFydGVyIDwtIGlmZWxzZShkZiRRdWFydGVyID09ICJEIiwgNCwgZGYkUXVhcnRlcikNCg0KZGYkUXVhcnRlciA8LSBhcy5udW1lcmljKGRmJFF1YXJ0ZXIpDQoNCiMgUmV2aXNhciBwb3IgTkFzDQpzdW0oaXMubmEoZGYpKQ0KYGBgDQoNCiMjIyBHbG9zYXJpb2RlIGxhIGJhc2UgZGUgZGF0b3MgZGUgTmVhcnNob3JpbmcNCg0KLSAqKlllYXI6KiogQcOxbyANCi0gKipRdWFydGVyOioqIFRyaW1lc3RyZSBjb3JyZXBvbmRpZW5kbyBhIHN1IGHDsW8uICANCi0gKipOZXcgRkRJIEluZmxvd3M6KiogSW52ZXJzacOzbiBleHRyYW5qZXJhIGRpcmVjdGEgZW4gbWlsbG9uZXMgZGUgZG9sYXJlcy4gIA0KLSAqKkV4Y2hhbmdlIFJhdGU6KiogVGlwbyBkZSBjYW1iaW8gZGUgZG9sYXJlcyBlc3RhZHVuaWRlbnNlcyBhIHBlc29zIG1leGljYW5vcy4gIA0KLSAqKk5ldyBGREkgSW5mbG93cyBNeG46KiogSW52ZXJzacOzbiBleHRyYW5qZXJhIGRpcmVjdGEgZW4gbWlsbG9uZXMgZGUgcGVzb3MgbWV4aWNhbm9zLiAgDQotICoqTG9nIE5ldyBGREkgSW5mbG93cyBNeG46KiogSW52ZXJzacOzbiBleHRyYW5qZXJhIGRpcmVjdGEgZW4gbWlsbG9uZXMgZGUgcGVzb3MgbWV4aWNhbm9zIGNvbiB0cmFuc2Zvcm1hY2nDs24gZGUgbG9nYXJpdG1vcy4gIA0KLSAqKklOUEM6KiogSW5kaWNlIE5hY2lvbmFsIGRlIFByZWNpb3MgYWwgQ29uc3VtaWRvciBlbiBiYXNlIGFsIDIwMTgNCg0KIyMgRURBIGRlIE5lYXJzaG9yaW5nDQoNCiMjIyBFc3RhZMOtc3RpY29zIERlc2NyaXB0aXZvcw0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc3VtbWFyeShkZiRuZXdfZmRpX2luZmxvd3NfbXhuKQ0Kc2QoZGYkbmV3X2ZkaV9pbmZsb3dzX214bikNCmBgYA0KDQojIyMgTWVkaWRhcyBkZSBEaXNwZXJzacOzbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc3VtbWFyeShkZikNCnZhcihkZiRuZXdfZmRpX2luZmxvd3NfbXhuKQ0KYGBgDQoNCg0KIyMjIEdyw6FmaWNvcyANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBsb3RfaGlzdG9ncmFtKGRmKQ0KDQpwbG90X2ludHJvKGRmKQ0KDQpib3hwbG90KGRmJG5ld19mZGlfaW5mbG93c19teG4sDQogICAgICAgIG1haW4gPSAiQm94IFBsb3Qgb2YgRmx1am9zIiwNCiAgICAgICAgeWxhYiA9ICJJRURfRmx1am9zIikNCg0KcGxvdChkZiREYXRlLGRmJG5ld19mZGlfaW5mbG93c19teG4sY29sPSJza3libHVlIiwgbHdkPTIsIHhsYWIgPSJEYXRlIix5bGFiID0iRmx1am9zIElFRCIsIG1haW4gPSAiRkRJIikNCmBgYA0KDQoNCiMjIyBQcm9uw7NzdGljbyBkZSB2ZW50YXMgDQoNCiMjIyMgRXhwbG9yYXIgbG9zIGRhdG9zIGRlIHNlcmllcyBkZSB0aWVtcG8gDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI0NvbnZlcnNpb24gZGUgZGF0YSBhIHNlcmllcyBkZSB0aWVtcG8NCkZESXRzIDwtIHRzKGRmJG5ld19mZGlfaW5mbG93c19teG4sc3RhcnQ9YygyMDA2LDEpLGVuZD1jKDIwMjMsMSksZnJlcXVlbmN5PTQpDQpGRElfdHNfZGVjb21wb3NlPC1kZWNvbXBvc2UoRkRJdHMpDQoNCiNEZXNjb21wb3NpY2lvbiBkZSBkYXRvcw0KcGxvdChGRElfdHNfZGVjb21wb3NlKSANCg0KI1JldmlzYXIgRXNhY2lvbmFyaWRhZA0KYWRmLnRlc3QoRkRJdHMpICANCiMgRW4gZXN0ZSBjYXNvIHNpIGhheSBwcmVzZW5jaWEgZGUgZXN0YWNpb25hcmllZGFkLg0KDQojUmV2aXNhciBBdXRvY29ycmVsYWNpb24gU2VyaWFsDQphY2YoZGYkbmV3X2ZkaV9pbmZsb3dzX214bixtYWluPSJTZXJpYWwgQXV0b2NvcnJlbGF0aW9ucyIpDQojIFBhcmVjZSBxdWUgc2kgaGF5IHByZXNlbmNpYSBkZSBBdXRvY29ycmVsYWNpb24gc2VyaWFsDQoNCg0KYGBgDQoNCiMjIyMgTW9kZWxvcyBkZSBzZXJpZXMgZGUgdGllbXBvDQpQYXJhIGVzdG8gc2UgYXBsaWNhcmEgdW4gbW9kZWxvIEFSTUEgeSBBUklNQSB5IHNlIGVzY29nZXJhIGVsIG1lam9yIGFkYXB0YWRvIGEgbG9zIGRhdG9zIHBhcmEgcmVhbGl6YXIgZWwgcHJvbm9zdGljby4gIA0KDQojIyMjIE1vZGVsbyBBUk1BIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc3VtbWFyeShGRElfQVJNQTwtYXJtYShkZiRuZXdfZmRpX2luZmxvd3NfbXhuLG9yZGVyPWMoMSwxKSkpDQpwbG90KEZESV9BUk1BKQ0KRkRJX2VzdGltYXRlZDwtRkRJX0FSTUEkZml0dGVkLnZhbHVlcw0KcGxvdChGRElfZXN0aW1hdGVkKQ0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQXV0b2NvcnJlbGF0aW9uDQphY2YobmEub21pdChGRElfQVJNQSRyZXNpZHVhbHMpLG1haW49IkFDRiAtIEFSTUEgKDEsMSkiKQ0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNOb3JtYWxpdHkgb2YgcmVzaWR1YWxzDQpoaXN0KEZESV9BUk1BJHJlc2lkdWFscywgbWFpbiA9ICJIaXN0b2dyYW0gb2YgUmVzaWR1YWxzIiwgeGxhYiA9ICJSZXNpZHVhbHMiLCB5bGFiID0gIkZyZXF1ZW5jeSIpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI0NoZWNrIGZvciBTZXJpYWwgQXV0b29ycmVsYXRpb24NCkZESV9BUk1BX3Jlc2lkdWFsczwtRkRJX0FSTUEkcmVzaWR1YWxzDQpCb3gudGVzdChGRElfQVJNQV9yZXNpZHVhbHMsbGFnPTUsdHlwZT0iTGp1bmctQm94IikgDQoNCiNDaGNlayBmb3IgU3RhdGlvbmFyaXR5DQphZGYudGVzdChuYS5vbWl0KEZESV9lc3RpbWF0ZWQpKQ0KDQpgYGANCiogUGFyZWNlIHF1ZSBlbCBtb2RlbG8gQVJNQSBubyB0aWVuZSBhdXRvY29ycmVsYWNpb24gc2VyaWFsIGVzdGFkaXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2YS4gIA0KKiBMb3MgcmVzaWR1YWxlcyBzZSB2ZW4gbm9ybWFsZXMgYSBleGNwZWNpw7NuIGRlIHVuIHZhbG9yIGF0w61waWNvLiAgDQoqIEVsIG1vZGVsbyBBUk1BIG5vIHRpZW5lIGVzdGFjaW9uYXJpZWRhZCBlbiBiYXNlIGEgbGEgcHJ1ZWJhIGRlIERpY2t5IEZ1bGxlciBUZXN0LiAgDQoNCiMjIyMgTW9kZWxvIEFSSU1BIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KRkRJX0FSSU1BIDwtIEFyaW1hKGRmJG5ld19mZGlfaW5mbG93c19teG4sb3JkZXI9YygxLDEsMSkpDQpwcmludChGRElfQVJJTUEpDQpwbG90KEZESV9BUklNQSRyZXNpZHVhbHMsbWFpbj0iQVJJTUEoMSwxLDEpIC0gRkRJIikNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojTm9ybWFsaXR5IG9mIFJlc2lkdWFscyANCmhpc3QoRkRJX0FSSU1BJHJlc2lkdWFscywgbWFpbiA9ICJIaXN0b2dyYW0gb2YgUmVzaWR1YWxzIiwgeGxhYiA9ICJSZXNpZHVhbHMiLCB5bGFiID0gIkZyZXF1ZW5jeSIpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI0NoZWNrIGZvciAgc2VyaWFsIGF1dG9jb3JyZWxhdGlvbg0KYWNmKEZESV9BUklNQSRyZXNpZHVhbHMsbWFpbj0iQUNGIC0gQVJJTUEgKDEsMSwxKSIpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI0NoZWNrIGZvciBTZXJpYWwgQXV0b2NvcnJlbGF0aW9uDQpCb3gudGVzdChGRElfQVJJTUEkcmVzaWR1YWxzLGxhZz0xLHR5cGU9IkxqdW5nLUJveCIpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI0NoZWNrIGZvciBTdGF0aW9uYXJpdHkNCmFkZi50ZXN0KEZESV9BUklNQSRyZXNpZHVhbHMpDQoNCg0KYGBgDQoNCiogRW4gYmFzZSBhIGxhcyBwcnVlYmFzIGRlIGRpYWdub3N0aWNvIGRlbCBtb2RlbG8gQVJJTUEsIGxvcyByZXNpZHVhbGVzIHNlIHZlbiBub3JtYWxlcyBhIGV4Y2VwY2nDs24gZGUgdW4gdmFsb3IgYXTDrXBpY28uICANCiogUGFyZWNlIHF1ZSBlbCBtb2RlbG8gbm8gdGllbmUgYXV0b2NvcnJlbGFjaW9uIHNlcmlhbCwgbG8gY3VhbCBlcyB1bmEgYnVlbmEgc2XDsWFsLiAgDQoqIEVsIG1vZGVsbyBtdWVzdHJhIHF1ZSBzaSBoYXkgcHJlc2VuY2lhIGRlIGVzdGFjaW9uYXJpZGFkLCBsbyBjdWFsIGVzIHVuYSBidWVuYSBzZcOxYWwgaWd1YWxtZW50ZS4gIA0KDQoNCkRlc3B1ZXMgZGUgYW5hbGl6YXIgbG9zIGRpYWdub3N0aWNvcyBkZSBsb3MgMiBtb2RlbG9zIHNlIGNvbmNsdXlvIHF1ZSBlbCBtb2RlbG8gbWVqb3IgYWRhcHRhZG8gYSBsb3MgZGF0b3Mgc2VyaWEgZWwgbW9kZWxvIGRlIEFSSU1BLiBFc3RvIHNlIGRlYmUgYSBxdWUgbG9zIDIgbW9kZWxvcyBubyBwcmVzZW50YW4gYXV0b2NvcnJlbGFjaW9uIHNlcmlhbCwgcGVybyBzb2xvIGVsIG1vZGVsbyBkZSBBUklNQSBwcmVzZW50YSBlc3RhY2lvbmFyaWRhZC4gTG8gY3VhbCBlcyBtZWpvciBhIGxhIGhvcmEgZGUgcmVhbGl6YXIgbG9zIHByb25vc3RpY29zLiAgDQoNCiMjIyMgUHJvbm9zdGljbyBkZSBGbHVqb3MgZGUgSW52ZXJzacOzbiBFeHRyYW5qZXJhIERpcmVjdGEgKElFRCBGbHVqb3MpDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpGRElfQVJJTUFfZm9yZWNhc3Q8LWZvcmVjYXN0KEZESV9BUklNQSxoPTUpDQpGRElfQVJJTUFfZm9yZWNhc3QNCnBsb3QoRkRJX0FSSU1BX2ZvcmVjYXN0KQ0KYXV0b3Bsb3QoRkRJX0FSSU1BX2ZvcmVjYXN0KQ0KYGBgDQoNCg0KIyMgSGFsbGF6Z29zIGRlIE5lYXJzaG9yaW5nDQoNCiogUGFyYSBsb3MgZmx1am9zIGRlIEZESSwgbG9zIGRhdG9zIHNvbiBub3JtYWxlcyBzaW4gZW1iYXJnbyBleGlzdGVuIGRvcyB2YWxvcmVzIGF0aXBpY29zLCBlc3RvcyBzaWVuZG8gZWwgbWluaW1vIHkgZWwgbWF4aW1vLiBFc3RvcyB2YWxvcmVzIHNlIHZlbiByZWZsZWphZG9zIGEgbGEgaG9yYSBkZSB2aXN1YWxpc2FsciBsb3MgcmVzaWR1YWxlcyBkZSBsb3MgbW9kZWxvcy4gIA0KDQoqIEhheSB1bmEgcHJlc25lY2lhIGVzdGFkaXNpdGljYW1lbnRlIHNpZ25pZmljYXRpdmEgZGUgZXN0YWNpb25hcmlkYWQsIGVzdG8gc2lnbmlmaWNhIHF1ZSBsb3MgZGF0b3MgdGllbmVuIHByb3BpZWRhZGVzIGVzdGFkaXN0aWNhcyBjb25zaXN0ZW50ZXMsIGxvIGN1YWwgZmFjaWxpdGEgbGEgYXBsaWNhY2lvbiBkZSBsb3MgbW9kZWxvcyBkZSBzZXJpZXMgZGUgdGllbXBvLiAgDQoNCiogTG9zIG1vZGVsb3MgQVJNQSB5IEFSSU1BIG5vIHByZXNlbnRhcm9uIGF1dG9jb3JyZWxhY2lvbiBzZXJpYWwsIGVzdG8gZXMgdW4gYnVlbiBpbmRpY2Fkb3IgcGFyYSBsb3MgbW9kZWxvcy4NCg0KKiBFbCBtb2RlbG8gZGUgQVJNQSBubyBwcmVzZW50byBlc3RhY2lvbmFyaWRhZCwgcGVybyBlbCBtb2RlbG8gZGUgQVJJTUEgc2kgcHJlc2VudG8gZXN0YWNpb25hcmlkYWQsIGVzdG8gZXMgdW5hIGJ1ZW5hIHNlw7FhbCBwYXJhIGVsIG1vZGVsbyBBUklNQSB5IHVuYSBtYWxhIHNlw7FhbCBwYXJhIGVsIG1vZGVsbyBBUk1BLiAgDQoNCiogTG9zIGRvcyBtb2RlbG9zIEFSTUEgeSBBUklNQSBwcmVzZW50YXJvbiBub3JtYWxpZGFkIGVuIGxvcyByZXNpZHVhbGVzIGEgZXNlcGNpb24gZGUgdW4gdmFsb3IgYXRpcGljby4gRXN0ZSB2YWxvciBwcm9iYWJsZW1lbnRlIGVzIGVsIHZhbG9yIGF0aXBpY28gZGUgbG9zIGRhdG9zIG9yaWdpbmFsZXMuICANCg0KKiBFbiBiYXNlIGEgZWwgcHJvbm9zdGljbyBkZWwgbW9kZWxvIHNsZWNjaW9uYWRvLCBlbiBlc3RlIGNhc28gZWwgbW9kZWxvIEFSSU1BLCBzZSBlc3BlcmEgcXVlIGVsIHZhbG9yIGRlIGludmVyc2lvbmVzIGV4dHJhbmplcmFzIGRpcmVjdGFzIGluY3JlbWVudGUgZW4gbG9zIHByb3hpbW9zIDUgdHJpbWVzdHJlcy4gUG9uaWVuZG8gbWFzIHByZXNpw7NuIHBhcmEgRk9STSBkZWJpZG8gYSBxdWUgZXN0byBlcyB1bmEgc2XDsWFsIGRlIHF1ZSBsYSBjb21wZXRpdGl2aWRhZCBlbiBzdSBpbmR1c3RyaWEgZXN0YXJhIGluY3JlbWVudGFuZG8gcG9yIGVtcHJlc2FzIGV4dHJhbmplcmFzLiAgDQoNCiMgVmVudGFzDQoNCiMjIFByZWd1bnRhcyBkZSBBbsOhbGlzaXMgZGUgVmVudGFzDQoqIMK/Q3XDoWwgZXMgZWwgbWVzIHkgZWwgYcOxbyBlbiBkb25kZSBzZSB0aWVuZW4gbcOhcyB2ZW50YXM/DQoqIMK/Q3VhbGVzIGxhIHRlbmRlbmNpYSBkZSBsYXMgdmVudGFzIGRlIEZPUk0/DQoqIMK/Q8OzbW8gc2UgdmVyYSBlbCBkZXNlbXBlw7FvIGRlIEZPUk0gZW4gbGFzIHZlbnRhcyBkZSBsb3MgcHJveGltb3MgYcOxb3M/DQoNCiMjIExpbXBpZXphIHkgT3JnYW5pemFjacOzbiBkZSBCYXNlIGRlIERhdG9zIFZlbnRhDQpgYGB7cn0NCnZlbnRhc19tZXNlcyA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcdG90YWxlc19tZW5zdWFsZXNGT1JNLmNzdiIpDQp2ZW50YXNfYW51YWxlcyA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcdmVudGFzYW51YWxlc0ZPUk0uY3N2IikNCmBgYA0KDQpgYGB7cn0NCnZlbnRhc19hbnVhbGVzJGHDsW8gPC0gYXMuRGF0ZShwYXN0ZTAodmVudGFzX2FudWFsZXMkYcOxbywgIi0xMi0zMSIpKQ0KdWx0aW1hX2ZpbGEgPC0gbnJvdyh2ZW50YXNfYW51YWxlcykNCnZlbnRhc19hbnVhbGVzJGHDsW9bdWx0aW1hX2ZpbGFdIDwtIGFzLkRhdGUoIjIwMjItMDktMzAiKQ0KaGVhZCh2ZW50YXNfYW51YWxlcykNCg0KbWVzZXNfZXNwYcOxb2wgPC0gYygiRW5lcm8iLCAiRmVicmVybyIsICJNYXJ6byIsICJBYnJpbCIsICJNYXlvIiwgIkp1bmlvIiwgIkp1bGlvIiwgIkFnb3N0byIsICJTZXB0aWVtYnJlIiwgIk9jdHVicmUiLCAiTm92aWVtYnJlIiwgIkRpY2llbWJyZSIpDQp2ZW50YXNfbWVzZXMkYcOxbyA8LSBhcy5EYXRlKHBhc3RlMCh2ZW50YXNfbWVzZXMkYcOxbywgIi0iLCBtYXRjaCh2ZW50YXNfbWVzZXMkbWVzZXMsIG1lc2VzX2VzcGHDsW9sKSwgIi0wMSIpKSArIG1vbnRocygxKSAtIGRheXMoMSkNCmhlYWQodmVudGFzX21lc2VzKQ0KDQp2ZW50YXNfbWVzZXMkdG90YWxfbWVuc3VhbCA8LSBhcy5udW1lcmljKHZlbnRhc19tZXNlcyR0b3RhbF9tZW5zdWFsKQ0KDQp2ZW50YXNfbWVzZXMgPC0gdmVudGFzX21lc2VzWywgYygiYcOxbyIsICJtZXNlcyIsICJ0b3RhbF9tZW5zdWFsIildDQpzdHIodmVudGFzX2FudWFsZXMpDQpzdHIodmVudGFzX21lc2VzKQ0KYGBgDQoNCiMjIyBDaGVjYXIgc2kgaGF5IE5BJ3MNCmBgYHtyfQ0Kc3VtKGlzLm5hKHZlbnRhc19hbnVhbGVzKSkNCnN1bShpcy5uYSh2ZW50YXNfbWVzZXMpKQ0KYGBgDQoNCiMjIyBWaXN1YWxpemFyIGxhIG51ZXZhIGJhc2UgZGUgZGF0b3MNCmBgYHtyfQ0KaGVhZCh2ZW50YXNfYW51YWxlcykNCmhlYWQodmVudGFzX21lc2VzKQ0KYGBgDQoNCiMjIyBHbG9zYXJpbyBkZSBsYSBiYXNlIGRlIGRhdG9zIGRlIFZlbnRhcw0KDQojIyMjIFZlbnRhcyBBbnVhbGVzOg0KDQotICoqYcOxbzoqKiBFbCBhw7FvIGFsIHF1ZSBjb3JyZXNwb25kZSBlbCByZWdpc3RybyBkZSB2ZW50YXMuDQotICoqdmVudGFzOioqIEVsIHRvdGFsIGRlIHZlbnRhcyByZWdpc3RyYWRvIHBhcmEgZWwgYcOxbyBjb3JyZXNwb25kaWVudGUuDQoNCiMjIyMgVmVudGFzIE1lbnN1YWxlczoNCg0KLSAqKmHDsW86KiogRWwgYcOxbyBhbCBxdWUgY29ycmVzcG9uZGUgZWwgcmVnaXN0cm8gZGUgdmVudGFzIG1lbnN1YWxlcy4NCi0gKiptZXNlczoqKiBFbCBtZXMgYWwgcXVlIGNvcnJlc3BvbmRlIGVsIHJlZ2lzdHJvIGRlIHZlbnRhcyBtZW5zdWFsZXMuDQotICoqdG90YWxfbWVuc3VhbDoqKiBFbCB0b3RhbCBkZSB2ZW50YXMgbWVuc3VhbGVzIHJlZ2lzdHJhZG8gcGFyYSBlbCBtZXMgY29ycmVzcG9uZGllbnRlLg0KDQojIyBFREEgZGUgVmVudGFzDQpgYGB7cn0NCnN0cih2ZW50YXNfbWVzZXMpDQpzdHIodmVudGFzX2FudWFsZXMpDQpgYGANCg0KIyMjIEVzdGFkaXN0aWNhIERlc2NyaXB0aXZhIHkgTWVkaWRhcyBkZSBEaXNwZXJzacOzbg0KYGBge3J9DQpzdW1tYXJ5KHZlbnRhc19hbnVhbGVzKQ0Kc3VtbWFyeSh2ZW50YXNfbWVzZXMpDQpgYGANCg0KYGBge3J9DQpwcmludCh2ZW50YXNfbWVzZXMkYcOxbykNCmBgYA0KDQpgYGB7cn0NCmRlc2NyaWJlKHZlbnRhc19hbnVhbGVzKQ0KZGVzY3JpYmUodmVudGFzX21lc2VzKQ0KYGBgDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KdmFyKHZlbnRhc19hbnVhbGVzKQ0KdmFyKHZlbnRhc19tZXNlcykNCmBgYA0KDQoNCiMjIyBWaXN1YWxpemFyIGxhcyBWZW50YXMgcG9yIE1lcyB5IEHDsW8NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEdyw6FmaWNvIGRlIHZlbnRhcyBtZW5zdWFsZXMNCmdncGxvdCh2ZW50YXNfbWVzZXMsIGFlcyh4ID0gYcOxbywgeSA9IHRvdGFsX21lbnN1YWwpKSArDQogIGdlb21fY29sKGZpbGwgPSAibGlnaHRibHVlIiwgY29sb3IgPSAiYmx1ZSIpICsNCiAgbGFicyh4ID0gIkHDsW8iLCB5ID0gIlZlbnRhcyIsIHRpdGxlID0gIlZlbnRhcyBBbnVhbGVzIikNCg0KZ2dwbG90KHZlbnRhc19hbnVhbGVzLCBhZXMoeCA9IGHDsW8sIHkgPSB2ZW50YXMpKSArDQogIGdlb21fY29sKGZpbGwgPSAic2FsbW9uIiwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHggPSAiQcOxbyIsIHkgPSAiVmVudGFzIiwgdGl0bGUgPSAiVmVudGFzIEFudWFsZXMiKQ0KDQpwb3JjZW50YWplX3ZlbnRhcyA8LSB2ZW50YXNfYW51YWxlcyR2ZW50YXMgLyBzdW0odmVudGFzX2FudWFsZXMkdmVudGFzKSAqIDEwMA0KcGllKHZlbnRhc19hbnVhbGVzJHZlbnRhcywgbGFiZWxzID0gcGFzdGUodmVudGFzX2FudWFsZXMkYcOxbywgIjogIiwgcm91bmQocG9yY2VudGFqZV92ZW50YXMsIDIpLCAiJSIpLCANCiAgICBtYWluID0gIkRpc3RyaWJ1Y2nDs24gZGUgVmVudGFzIEFudWFsZXMiKQ0KYGBgDQoNCiMjIyMgTWVqb3IgTWVzIHkgQcOxbyBkZSBWZW50YXMNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp2ZW50YXNfbWVuc3VhbGVzX3h0czwteHRzKHZlbnRhc19tZXNlcyR0b3RhbF9tZW5zdWFsLG9yZGVyLmJ5PXZlbnRhc19tZXNlcyRhw7FvKQ0KZHlncmFwaCh2ZW50YXNfbWVuc3VhbGVzX3h0cywgbWFpbiA9ICJWZW50YXMgTWVuc3VhbGVzIikgJT4lIA0KICBkeU9wdGlvbnMoY29sb3JzID0gUkNvbG9yQnJld2VyOjpicmV3ZXIucGFsKDQsICJEYXJrMiIpKSAlPiUNCiAgZHlTaGFkaW5nKGZyb20gPSAiMjAyMC0xMi0wMSIsDQogICAgICAgICAgICB0byA9ICIyMDIwLTEyLTMxIiwgDQogICAgICAgICAgICBjb2xvciA9ICIjRkZFNkU2IikNCg0KdmVudGFzX2FudWFsZXNfeHRzPC14dHModmVudGFzX2FudWFsZXMkdmVudGFzLG9yZGVyLmJ5PXZlbnRhc19hbnVhbGVzJGHDsW8pDQpkeWdyYXBoKHZlbnRhc19hbnVhbGVzX3h0cywgbWFpbiA9ICJWZW50YXMgQW51YWxlcyIpICU+JSANCiAgZHlPcHRpb25zKGNvbG9ycyA9IFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg0LCAiRGFyazIiKSkgJT4lDQogIGR5U2hhZGluZyhmcm9tID0gIjIwMjEtMDQtMDkiLA0KICAgICAgICAgICAgdG8gPSAiMjAyMS0xMi0zMSIsIA0KICAgICAgICAgICAgY29sb3IgPSAiI0ZGRTZFNiIpDQpgYGANCg0KRXN0ZSBncsOhZmljbyBkZSBsw61uZWFzIG11ZXN0cmEgbG9zIGRhdG9zIGRlIHZlbnRhcyBtZW5zdWFsZXMgZGUgbGEgZW1wcmVzYSBkZXNkZSBlbmVybyBkZSAyMDIwIGhhc3RhIFNlcHRpZW1icmUgZGUgMjAyMi4gRWwgZ3LDoWZpY28gZXhoaWJlIGN1ZW50YSBjb24gcGljb3MgeSBiYWphZGFzIHF1ZSBvY3VycmVuIGVuIGludGVydmFsb3MgcmVndWxhcmVzLCBwcm9iYWJsZW1lbnRlIGNvcnJlc3BvbmRpZW50ZXMgYSBkaWZlcmVudGVzIGVzdGFjaW9uZXMgbyBwZXLDrW9kb3MgZGVsIGHDsW8uIEhheSB1bmEgdGVuZGVuY2lhIGdlbmVyYWwgYWwgYWx6YSBlbiBsYXMgdmVudGFzLCBjb24gZWwgcGljbyBtw6FzIGFsdG8gb2N1cnJpZW5kbyBoYWNpYSBlbCBmaW5hbCBkZWwgcGVyw61vZG8gZGUgdGllbXBvIG1vc3RyYWRvLiANCg0KUG9kZW1vcyB2ZXIgcXVlIGxhcyBtZWpvcmVzIHZlbnRhcyBtZW5zdWFsZXMgcXVlIGhhIHRlbmlkbyBkdXJhbnRlIGxvcyBhw7FvcyBmdWVyb24gbGFzIGZlY2hhcyBkZToNCiogRGljaWVtYnJlIGRlbCAyMDIwID0gJDEyLDMwMCwwMDANCiogRmVicmVybyBkZWwgMjAyMSA9ICQxMSwyMDAsMDAwDQoqIFNlcHRpZW1icmUgZGVsIDIwMjIgPSAkMTEsNjAwLDAwMA0KDQpZIGRlIGxhcyBtYXlvcmVzIHZlbnRhcyBhbnVhbGVzIGZ1ZSBlbiBlbCAyMDIxLiBFeGFjdGFtZW50ZSBlbiBhYnJpbCAxMCBkZSBlc2UgYcOxbywgc2UgY3VtcGxlIGxhcyB2ZW50YXMgZGVsIDIwMTggcXVlIGZ1ZXJvbiA4NywwMDAsMDAwLCBxdWUgcGFyYSBlc29zIGHDsW9zIGVyYSBlbCBhw7FvIGRvbmRlIHJlY2liaWVyb24gbWF5b3JlcyB2ZW50YXMuIFkgYWNhYmFuZG8gZWwgYcOxbyAyMDIxIHNlIGxsZWdvIGEgdW4gbnVldm8gcmVjb3JkIGVuIHZlbnRhcyBzaWVuZG8gbWF5b3JlcyBhICQ4OSw5MDAsMDAwLCB5IGZ1ZSB0YW4gc29sbyBoYXN0YSBTZXB0aWVtYnJlIGRlIGVzZSBhw7FvLCBzaW4gZW1iYXJnbyBGT1JNIGVzdGltYWJhIGhhc3RhIDExMCBtaWxsb25lcyBlbiB2ZW50YXMuDQoNCiMjIFByw7Nub3N0aWNvcw0KDQojIyMgUHJvbsOzc3RpY28gZGUgUHJvbWVkaW9zIE3Ds3ZpbGVzIGVuIFINCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQWdyZWdhciBmaWxhcyBwYXJhIGxvcyBhw7FvcyAyMDIzIHkgMjAyNA0KdmVudGFzX2FudWFsZXNfbnVldmFzIDwtIHJiaW5kKHZlbnRhc19hbnVhbGVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoYcOxbyA9IGFzLkRhdGUoIjIwMjMtMTItMzEiKSwgdmVudGFzID0gTkEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoYcOxbyA9IGFzLkRhdGUoIjIwMjQtMTItMzEiKSwgdmVudGFzID0gTkEpKQ0KDQpwcmludCh2ZW50YXNfYW51YWxlc19udWV2YXMpDQoNCiMgQ3JlYXIgdW4gdmVjdG9yIGNvbiBsYXMgZmVjaGFzIGRlIGZpbmFsIGRlIGxvcyBtZXNlcyBkZSBPY3R1YnJlIDIwMjIgYSBTZXB0aWVtYnJlIDIwMjMNCmZlY2hhc19udWV2YXMgPC0gc2VxKGFzLkRhdGUoIjIwMjItMTAtMzEiKSwgYXMuRGF0ZSgiMjAyMy0wOS0zMCIpLCBieSA9ICJtb250aCIpDQoNCiMgQ3JlYXIgdW4gbnVldm8gZGF0YWZyYW1lIGNvbiBsYXMgZmVjaGFzIHkgdmVudGFzIGEgTkENCm51ZXZhc19maWxhcyA8LSBkYXRhLmZyYW1lKGHDsW8gPSBmZWNoYXNfbnVldmFzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lc2VzID0gZm9ybWF0KGZlY2hhc19udWV2YXMsICIlQiIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWxfbWVuc3VhbCA9IE5BKQ0KDQojIFVuaXIgZWwgbnVldm8gZGF0YWZyYW1lIGNvbiBlbCBvcmlnaW5hbA0KdmVudGFzX21lc2VzX251ZXZhcyA8LSByYmluZCh2ZW50YXNfbWVzZXMsIG51ZXZhc19maWxhcykNCg0KcHJpbnQodmVudGFzX21lc2VzX251ZXZhcykNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwcm9ub3N0aWNvX21lbnN1YWxlc194dHM8LXh0cyh2ZW50YXNfbWVzZXNfbnVldmFzJHRvdGFsX21lbnN1YWwsb3JkZXIuYnk9dmVudGFzX21lc2VzX251ZXZhcyRhw7FvKQ0KcHJvbm9zdGljb19hbnVhbGVzX3h0czwteHRzKHZlbnRhc19hbnVhbGVzX251ZXZhcyR2ZW50YXMsb3JkZXIuYnk9dmVudGFzX2FudWFsZXNfbnVldmFzJGHDsW8pDQoNCnByb21lZGlvX21vdmlsX21lbnN1YWwgPC0gcm9sbG1lYW4ocHJvbm9zdGljb19tZW5zdWFsZXNfeHRzLCBrID0gMTIsIGFsaWduID0gInJpZ2h0IiwgZmlsbCA9IE5BKQ0KcHJvbWVkaW9fbW92aWxfYW51YWwgPC0gcm9sbGFwcGx5KHByb25vc3RpY29fYW51YWxlc194dHMsIHdpZHRoID0gMywgRlVOID0gbWVhbiwgYnkgPSAxLCBhbGlnbiA9ICJyaWdodCIsIGZpbGwgPSBOQSkNCg0KIyBDb252ZXJ0aXIgcHJvbWVkaW9zIG3Ds3ZpbGVzIGEgb2JqZXRvcyBkZSBzZXJpZSB0ZW1wb3JhbA0KcHJvbWVkaW9fbW92aWxfbWVuc3VhbF90cyA8LSB0cyhjb3JlZGF0YShwcm9tZWRpb19tb3ZpbF9tZW5zdWFsKSwgc3RhcnQgPSBzdGFydChwcm9ub3N0aWNvX21lbnN1YWxlc194dHMpLCBmcmVxdWVuY3kgPSBmcmVxdWVuY3kocHJvbm9zdGljb19tZW5zdWFsZXNfeHRzKSkNCnByb21lZGlvX21vdmlsX2FudWFsX3RzIDwtIHRzKGNvcmVkYXRhKHByb21lZGlvX21vdmlsX2FudWFsKSwgc3RhcnQgPSBzdGFydChwcm9ub3N0aWNvX2FudWFsZXNfeHRzKSwgZnJlcXVlbmN5ID0gZnJlcXVlbmN5KHByb25vc3RpY29fYW51YWxlc194dHMpKQ0KDQojIEdyw6FmaWNvIGRlIHByb27Ds3N0aWNvIGRlIHByb21lZGlvIG3Ds3ZpbCBtZW5zdWFsDQphdXRvcGxvdChwcm9tZWRpb19tb3ZpbF9tZW5zdWFsX3RzKSArDQogIGxhYnModGl0bGUgPSAiTW92aW1pZW50byBkZWwgUHJvbsOzc3RpY28gZGUgUHJvbWVkaW8gTcOzdmlsIE1lbnN1YWwiLCB4ID0gIkZlY2hhIiwgeSA9ICJWZW50YXMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQojIEdyw6FmaWNvIGRlIHByb27Ds3N0aWNvIGRlIHByb21lZGlvIG3Ds3ZpbCBhbnVhbA0KYXV0b3Bsb3QocHJvbWVkaW9fbW92aWxfYW51YWxfdHMpICsNCiAgbGFicyh0aXRsZSA9ICJNb3ZpbWllbnRvIGRlbCBQcm9uw7NzdGljbyBkZSBQcm9tZWRpbyBNw7N2aWwgQW51YWwiLCB4ID0gIkHDsW8iLCB5ID0gIlZlbnRhcyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgRXh0ZW5kZXIgZWwgcHJvbWVkaW8gbcOzdmlsIGVuIGVsIGZ1dHVybyBwYXJhIGhhY2VyIHByb27Ds3N0aWNvcw0KIyBTdXBvbmdhbW9zIHF1ZSBxdWVyZW1vcyBwcm9ub3N0aWNhciAxMiBtZXNlcyBoYWNpYSBhZGVsYW50ZQ0KbnVldmFzX2ZlY2hhc19tZW5zdWFsZXMgPC0gc2VxKG1heChpbmRleChwcm9ub3N0aWNvX21lbnN1YWxlc194dHMpKSArIDEsIGxlbmd0aC5vdXQgPSAxMiwgYnkgPSAibW9udGhzIikNCnByb25vc3RpY29fbWVuc3VhbCA8LSB6b28oTkEsIG9yZGVyLmJ5ID0gbnVldmFzX2ZlY2hhc19tZW5zdWFsZXMpDQpmb3IgKGkgaW4gc2VxX2Fsb25nKG51ZXZhc19mZWNoYXNfbWVuc3VhbGVzKSkgew0KICBwcm9ub3N0aWNvX21lbnN1YWxbaV0gPC0gbWVhbih0YWlsKHByb25vc3RpY29fbWVuc3VhbGVzX3h0cywgMTIpKQ0KfQ0KDQojIEdyw6FmaWNvIGRlIHByb27Ds3N0aWNvIGRlIHZlbnRhcyBtZW5zdWFsZXMNCnBsb3QocHJvbm9zdGljb19tZW5zdWFsZXNfeHRzLCBtYWluID0gIlByb27Ds3N0aWNvIGRlIFZlbnRhcyBNZW5zdWFsZXMgY29uIFByb21lZGlvIE3Ds3ZpbCIsIHhsYWIgPSAiQcOxbyIsIHlsYWIgPSAiVmVudGFzIikNCmxpbmVzKHByb21lZGlvX21vdmlsX21lbnN1YWwsIGNvbCA9ICJibHVlIikNCmxpbmVzKHByb25vc3RpY29fbWVuc3VhbCwgY29sID0gInJlZCIsIGx0eSA9IDIpDQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiVmVudGFzIE1lbnN1YWxlcyIsICJQcm9tZWRpbyBNw7N2aWwiLCAiUHJvbsOzc3RpY28iKSwgY29sID0gYygiYmxhY2siLCAiYmx1ZSIsICJyZWQiKSwgbHR5ID0gYygxLCAxLCAyKSkNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBFeHRlbmRlciBlbCBwcm9tZWRpbyBtw7N2aWwgZW4gZWwgZnV0dXJvIHBhcmEgaGFjZXIgcHJvbsOzc3RpY29zDQojIFN1cG9uZ2Ftb3MgcXVlIHF1ZXJlbW9zIHByb25vc3RpY2FyIDIgYcOxb3MgaGFjaWEgYWRlbGFudGUNCm51ZXZhc19mZWNoYXNfYW51YWxlcyA8LSBzZXEobWF4KGluZGV4KHByb25vc3RpY29fYW51YWxlc194dHMpKSArIDEsIGxlbmd0aC5vdXQgPSAyLCBieSA9ICJ5ZWFycyIpDQpwcm9ub3N0aWNvX2FudWFsIDwtIHpvbyhOQSwgb3JkZXIuYnkgPSBudWV2YXNfZmVjaGFzX2FudWFsZXMpDQpmb3IgKGkgaW4gc2VxX2Fsb25nKG51ZXZhc19mZWNoYXNfYW51YWxlcykpIHsNCiAgcHJvbm9zdGljb19hbnVhbFtpXSA8LSBtZWFuKHRhaWwocHJvbm9zdGljb19hbnVhbGVzX3h0cywgMykpDQp9DQoNCiMgR3LDoWZpY28gZGUgcHJvbsOzc3RpY28gZGUgdmVudGFzIGFudWFsZXMNCnBsb3QocHJvbm9zdGljb19hbnVhbGVzX3h0cywgbWFpbiA9ICJQcm9uw7NzdGljbyBkZSBWZW50YXMgQW51YWxlcyBjb24gUHJvbWVkaW8gTcOzdmlsIiwgeGxhYiA9ICJBw7FvIiwgeWxhYiA9ICJWZW50YXMiKQ0KbGluZXMocHJvbWVkaW9fbW92aWxfYW51YWwsIGNvbCA9ICJibHVlIikNCmxpbmVzKHByb25vc3RpY29fYW51YWwsIGNvbCA9ICJyZWQiLCBsdHkgPSAyKQ0KbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9IGMoIlZlbnRhcyBBbnVhbGVzIiwgIlByb21lZGlvIE3Ds3ZpbCIsICJQcm9uw7NzdGljbyIpLCBjb2wgPSBjKCJibGFjayIsICJibHVlIiwgInJlZCIpLCBsdHkgPSBjKDEsIDEsIDIpKQ0KYGBgDQoNCiMjIyBQcm9uw7NzdGljbyBkZSBQcm9tZWRpb3MgTcOzdmlsZXMgZW4gRXhjZWwNCg0KIVtdKEM6XFxVc2Vyc1xcbGVzZGFfYjV3ZnFxYVxcRG93bmxvYWRzXFxldjFcXElNRyAxLnBuZykNCg0KIVtdKEM6XFxVc2Vyc1xcbGVzZGFfYjV3ZnFxYVxcRG93bmxvYWRzXFxldjFcXElNRyAyLnBuZykNCg0KDQpMYXMgdmVudGFzIG1lbnN1YWxlcyByZWZsZWphbiB1biBwYXRyw7NuIGPDrWNsaWNvIGNvbiBtZXNlcyBkZSBhbHRhIGRlbWFuZGEsIHByb2JhYmxlbWVudGUgcG9yIGZhY3RvcmVzIGVzdGFjaW9uYWxlcyBvIHByb21vY2lvbmFsZXMsIGRvbmRlIGVsIHByb27Ds3N0aWNvIGNhcHR1cmEgYWRlY3VhZGFtZW50ZSBsYXMgdGVuZGVuY2lhcyBwZXJvIHJlcXVpZXJlIGFqdXN0ZXMgcGFyYSBtYXlvciBwcmVjaXNpw7NuLiBBIG5pdmVsIGFudWFsLCBsYXMgdmVudGFzIG11ZXN0cmFuIHVuIGNyZWNpbWllbnRvIHNvc3RlbmlkbywgYSBwZXNhciBkZSB1biBhw7FvIGNvbiBkZXNjZW5zbyBzaWduaWZpY2F0aXZvLCB5IGVsIHByb27Ds3N0aWNvIHNpZ3VlIGRlIGNlcmNhIGxhIHRlbmRlbmNpYSByZWFsLCBhdW5xdWUgdGFtYmnDqW4gbmVjZXNpdGEgbWVqb3JhcyBwYXJhIHJlZHVjaXIgbGFzIGRpc2NyZXBhbmNpYXMgb2JzZXJ2YWRhcy4NCg0KIyMgSGFsbGF6Z29zIGRlIFZlbnRhcw0KMS4gVGVuZW1vcyBsb3MgZGF0b3MgZGUgdmVudGFzIG1lbnN1YWxlcyBkZXNkZSBlbmVybyBkZSAyMDIwIGhhc3RhIHNlcHRpZW1icmUgZGUgMjAyMiwgeSBsb3MgZGF0b3MgZGUgdmVudGFzIGFudWFsZXMgZGVsIDIwMTcgYSBTZXB0aWVtYnJlIGRlbCAyMDIyDQoyLiBTZSBpZGVudGlmaWNhIHVuIHBhdHLDs24gZXN0YWNpb25hbCBldmlkZW50ZSwgY29uIHBpY29zIHkgY2HDrWRhcyByZWN1cnJlbnRlcyBlbiBsYXMgdmVudGFzIG1lbnN1YWxlcw0KMy4gTGEgdGVuZGVuY2lhIGdlbmVyYWwgZGUgbGFzIHZlbnRhcyBlcyBhc2NlbmRlbnRlLCBjb24gZWwgcGljbyBtw6FzIGFsdG8gaGFjaWEgZWwgZmluYWwgZGVsIHBlcsOtb2RvLg0KNC4gTG9zIG1lam9yZXMgbWVzZXMgZGUgdmVudGFzIGZ1ZXJvbiBkaWNpZW1icmUgZGUgMjAyMCwgZmVicmVybyBkZSAyMDIxIHkgc2VwdGllbWJyZSBkZSAyMDIyLg0KNS4gRWwgYcOxbyAyMDIxIHJlZ2lzdHLDsyBsYXMgbWF5b3JlcyB2ZW50YXMgYW51YWxlcywgYWxjYW56YW5kbyB1biByw6ljb3JkIGRlICQ4OSw5MDAsMDAwIHkgdG9kYXZpYSBmYWx0YW5kbyAzIG1lc2VzIHBhcmEgcXVlIGFjYWJlIGVsIGHDsW8uDQo2LiBFbiBhYnJpbCBkZSAyMDIxIHNlIGlndWFsYXJvbiBsYXMgdmVudGFzIGRlIDIwMTgsIHF1ZSBlcmFuIGxhcyBtw6FzIGFsdGFzIGhhc3RhIGVzZSBtb21lbnRvLg0KNyBBdW5xdWUgaHVibyB1biBkZXNjZW5zbyBzaWduaWZpY2F0aXZvIGVuIHVuIGHDsW8gZXNwZWPDrWZpY28gcG9zaWJsZW1lbnRlIHBvciBmYWN0b3JlcyBlY29uw7NtaWNvcyBvIGRlbCBtZXJjYWRvLCB0ZW5pZW5kbyB1bmEgdGVuZGVuY2lhIGdlbmVyYWwgcXVlIHNlIG1hbnRpZW5lIHBvc2l0aXZhLg0KOC4gQSBuaXZlbCBtZW5zdWFsLCBsYXMgdmVudGFzIHNpZ3VlbiB1biBwYXRyw7NuIGPDrWNsaWNvLCBtaWVudHJhcyBxdWUgYSBuaXZlbCBhbnVhbCBtdWVzdHJhbiB1bmEgdGVuZGVuY2lhIGdlbmVyYWwgYXNjZW5kZW50ZS4NCjkuIEF1bnF1ZSBsb3MgbW9kZWxvcyBkZSBwcm9uw7NzdGljbyBjYXB0dXJhbiBsb3MgcGF0cm9uZXMgZXN0YWNpb25hbGVzIHkgbGFzIHRlbmRlbmNpYXMgYSBsYXJnbyBwbGF6bywgdG9kYXbDrWEgc2UgcHVlZGUgbWVqb3JhciBzdSBwcmVjaXNpw7NuLiBZYSBxdWUgaWd1YWxtZW50ZSBzZSBvYnNlcnZhbiBkaXNjcmVwYW5jaWFzIGVudHJlIGVsIHByb27Ds3N0aWNvIHkgbGFzIHZlbnRhcyByZWFsZXMsIHN1Z2lyaWVuZG8gcG9zaWJsZXMgbWVqb3JhcyBlbiBlbCBtb2RlbG8gZGUgcHJvbsOzc3RpY28uDQoNCiMjIEJ1zIFzcXVlZGEgZGUgaW5mb3JtYWNpb8yBbiB5IGRhdG9zIGRlIGxhcyBWZW50YXMNCiogKirCv1F1ZcyBIHRpcG8gZGUgaW5mb3JtYWNpb8yBbiAvIGRhdG9zIHNvbGljaXRhcmnMgWFzIGFsIHNvY2lvIGZvcm1hZG9yIHBhcmEgbWVqb3JhciBFREE/KiouICANCiAgKyBEYXRvcyBkZXRhbGxhZG9zIGRlIGxhcyB2ZW50YXMsIGludGVncmFuZG8gZGVzZ2xvc2VzIGRlIGNhZGENCnByb2R1Y3RvLCBwcm95ZWN0b3MsIHJlZ2lvbmVzLiAgDQogICsgRGF0b3Mgc29icmUgbGEgY29tcGV0ZW5jaWEgcGFyYSBoYWNlciB1biBjb250cmFzdGUgZW50cmUgbGFzIGVtcHJlc2FzLiAgDQoNCiogKirCv1F1ZcyBIHRpcG8gZGUgaW5mb3JtYWNpb8yBbiAvIGRhdG9zIGRlIGZ1ZW50ZXMgc2VjdW5kYXJpYXMgYnVzY2FyacyBYXMgcGFyYSBtZWpvcmFyIEVEQT8qKi4gIA0KICArIERhdG9zIHNvYnJlIGVsIG1lcmNhZG8geSBsYSBpbmR1c3RyaWEuICANCiAgKyBJbmZvcm1lcyBkZSBJbnZlc3RpZ2FjaW9uIGRlbCBtZXJjYWRvL2luZHVzdHJpYS4gRXN0byBheXVkYXJpYSBwYXJhIGlkZW50aWZpY2FyIHRlbmRlbmNpYXMgZW4gZWwgbWVyY2Fkby9pbmR1c3RyaWEsIHNlZ21lbnRhY2lvbmVzIGUgaW5mb3JtYWNpb24gZ2VuZXJhbCBsYSBjdWFsIHB1ZWRhIGFwb3lhciBsb3MgcmVzdWx0YWRvcyBlbmNvbnRyYWRvcyBlbiBlbCBhbmFsaXNpcy4gIA0KICANCiAgDQogIA0KDQoNCiMgQW5hbGlzaXMgRXhwbG9yYXRvcmlvIGRlIGxhcyBCYXNlcyBkZSBEYXRvcyBBY3R1YWxpemFkYXMNCg0KIyMgVmVudGFzIChBY3R1YWxpemFkbykNCg0KYGBge3J9DQp2ZW50YXNfY2xpZW50ZXMyMDIxIDwtIHJlYWRfeGxzeCgiQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcQkFTRVMgQUNUVUFMSVpBREFTXFxWZW50YXNDbGllbnRlczIwMjEueGxzeCIpDQp2ZW50YXNfY2xpZW50ZXMyMDIyIDwtIHJlYWRfeGxzeCgiQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcQkFTRVMgQUNUVUFMSVpBREFTXFxWZW50YXNDbGllbnRlczIwMjIueGxzeCIpDQp2ZW50YXNfY2xpZW50ZXMyMDIzIDwtIHJlYWRfeGxzeCgiQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcQkFTRVMgQUNUVUFMSVpBREFTXFxWZW50YXNDbGllbnRlczIwMjMueGxzeCIpDQpgYGANCg0KYGBge3J9DQojIENyZWFyIGVsIGdyw6FmaWNvIGRlIGJhcnJhcyBWRU5UQVMgMjAyMQ0KZ2dwbG90KHZlbnRhc19jbGllbnRlczIwMjEsIGFlcyh4ID0gZmVjaGEsIHkgPSB1bmlkYWRlcykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiYmx1ZSIpICsNCiAgbGFicyh4ID0gIkZlY2hhIiwgeSA9ICJVbmlkYWRlcyIsIHRpdGxlID0gIlZlbnRhcyBwb3IgRmVjaGEgZW4gMjAyMSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KDQpgYGB7cn0NCiNUT1AgNSBDTElFTlRFUyAyMDIxDQoNCiMgQWdydXBhciBwb3IgY2xpZW50ZSB5IHN1bWFyIGxhcyB1bmlkYWRlcw0KdmVudGFzX3Bvcl9jbGllbnRlIDwtIHZlbnRhc19jbGllbnRlczIwMjEgJT4lDQogIGdyb3VwX2J5KGNsaWVudGUpICU+JQ0KICBzdW1tYXJpc2UodG90YWxfdW5pZGFkZXMgPSBzdW0odW5pZGFkZXMpKQ0KDQojIE9yZGVuYXIgcG9yIGVsIHRvdGFsIGRlIHVuaWRhZGVzIHkgc2VsZWNjaW9uYXIgbG9zIDUgcHJpbWVyb3MNCnRvcF81X2NsaWVudGVzIDwtIHZlbnRhc19wb3JfY2xpZW50ZSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsX3VuaWRhZGVzKSkgJT4lDQogIGhlYWQoNSkNCg0KIyBNb3N0cmFyIGVsIHRvcCA1IGRlIGNsaWVudGVzIHF1ZSBtw6FzIGNvbnN1bWVuDQpwcmludCh0b3BfNV9jbGllbnRlcykNCmBgYA0KDQpgYGB7cn0NCiMgR3JhZmljYXIgZWwgdG9wIDUgZGUgY2xpZW50ZXMgcXVlIG3DoXMgY29uc3VtZW4NCmdncGxvdCh0b3BfNV9jbGllbnRlcywgYWVzKHggPSBjbGllbnRlLCB5ID0gdG90YWxfdW5pZGFkZXMpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArDQogIGxhYnModGl0bGUgPSAiVG9wIDUgZGUgQ2xpZW50ZXMgcXVlIG3DoXMgQ29uc3VtZW4gMjAyMSIsDQogICAgICAgeCA9ICJDbGllbnRlIiwNCiAgICAgICB5ID0gIlRvdGFsIGRlIFVuaWRhZGVzIFZlbmRpZGFzIikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSAgIyBSb3RhciBldGlxdWV0YXMgZGVsIGVqZSB4IHBhcmEgbWVqb3IgbGVnaWJpbGlkYWQNCmBgYA0KDQoNCmBgYHtyfQ0KIyBDcmVhciBlbCBncsOhZmljbyBkZSBiYXJyYXMgVkVOVEFTIDIwMjINCmdncGxvdCh2ZW50YXNfY2xpZW50ZXMyMDIyLCBhZXMoeCA9IGZlY2hhLCB5ID0gdW5pZGFkZXMpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImJsdWUiKSArDQogIGxhYnMoeCA9ICJGZWNoYSIsIHkgPSAiVW5pZGFkZXMiLCB0aXRsZSA9ICJWZW50YXMgcG9yIEZlY2hhIGVuIDIwMjIiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KI1RPUCA1IENMSUVOVEVTIDIwMjINCg0KIyBBZ3J1cGFyIHBvciBjbGllbnRlIHkgc3VtYXIgbGFzIHVuaWRhZGVzDQp2ZW50YXNfcG9yX2NsaWVudGUgPC0gdmVudGFzX2NsaWVudGVzMjAyMiAlPiUNCiAgZ3JvdXBfYnkoY2xpZW50ZSkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF91bmlkYWRlcyA9IHN1bSh1bmlkYWRlcykpDQoNCiMgT3JkZW5hciBwb3IgZWwgdG90YWwgZGUgdW5pZGFkZXMgeSBzZWxlY2Npb25hciBsb3MgNSBwcmltZXJvcw0KdG9wXzVfY2xpZW50ZXMgPC0gdmVudGFzX3Bvcl9jbGllbnRlICU+JQ0KICBhcnJhbmdlKGRlc2ModG90YWxfdW5pZGFkZXMpKSAlPiUNCiAgaGVhZCg1KQ0KDQojIE1vc3RyYXIgZWwgdG9wIDUgZGUgY2xpZW50ZXMgcXVlIG3DoXMgY29uc3VtZW4NCnByaW50KHRvcF81X2NsaWVudGVzKQ0KDQpgYGANCg0KYGBge3J9DQojIEdyYWZpY2FyIGVsIHRvcCA1IGRlIGNsaWVudGVzIHF1ZSBtw6FzIGNvbnN1bWVuDQpnZ3Bsb3QodG9wXzVfY2xpZW50ZXMsIGFlcyh4ID0gY2xpZW50ZSwgeSA9IHRvdGFsX3VuaWRhZGVzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKw0KICBsYWJzKHRpdGxlID0gIlRvcCA1IGRlIENsaWVudGVzIHF1ZSBtw6FzIENvbnN1bWVuIDIwMjIiLA0KICAgICAgIHggPSAiQ2xpZW50ZSIsDQogICAgICAgeSA9ICJUb3RhbCBkZSBVbmlkYWRlcyBWZW5kaWRhcyIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXIgZXRpcXVldGFzIGRlbCBlamUgeCBwYXJhIG1lam9yIGxlZ2liaWxpZGFkDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBDcmVhciBlbCBncsOhZmljbyBkZSBiYXJyYXMgVkVOVEFTIDIwMjMNCmdncGxvdCh2ZW50YXNfY2xpZW50ZXMyMDIzLCBhZXMoeCA9IGZlY2hhLCB5ID0gdW5pZGFkZXMpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImJsdWUiKSArDQogIGxhYnMoeCA9ICJGZWNoYSIsIHkgPSAiVW5pZGFkZXMiLCB0aXRsZSA9ICJWZW50YXMgcG9yIEZlY2hhIGVuIDIwMjMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCmBgYHtyfQ0KI1RPUCA1IENMSUVOVEVTIDIwMjMNCg0KIyBBZ3J1cGFyIHBvciBjbGllbnRlIHkgc3VtYXIgbGFzIHVuaWRhZGVzDQp2ZW50YXNfcG9yX2NsaWVudGUgPC0gdmVudGFzX2NsaWVudGVzMjAyMyAlPiUNCiAgZ3JvdXBfYnkoY2xpZW50ZSkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF91bmlkYWRlcyA9IHN1bSh1bmlkYWRlcykpDQoNCiMgT3JkZW5hciBwb3IgZWwgdG90YWwgZGUgdW5pZGFkZXMgeSBzZWxlY2Npb25hciBsb3MgNSBwcmltZXJvcw0KdG9wXzVfY2xpZW50ZXMgPC0gdmVudGFzX3Bvcl9jbGllbnRlICU+JQ0KICBhcnJhbmdlKGRlc2ModG90YWxfdW5pZGFkZXMpKSAlPiUNCiAgaGVhZCg1KQ0KDQojIE1vc3RyYXIgZWwgdG9wIDUgZGUgY2xpZW50ZXMgcXVlIG3DoXMgY29uc3VtZW4NCnByaW50KHRvcF81X2NsaWVudGVzKQ0KDQpgYGANCg0KYGBge3J9DQojIEdyYWZpY2FyIGVsIHRvcCA1IGRlIGNsaWVudGVzIHF1ZSBtw6FzIGNvbnN1bWVuDQpnZ3Bsb3QodG9wXzVfY2xpZW50ZXMsIGFlcyh4ID0gY2xpZW50ZSwgeSA9IHRvdGFsX3VuaWRhZGVzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKw0KICBsYWJzKHRpdGxlID0gIlRvcCA1IGRlIENsaWVudGVzIHF1ZSBtw6FzIENvbnN1bWVuIDIwMjMiLA0KICAgICAgIHggPSAiQ2xpZW50ZSIsDQogICAgICAgeSA9ICJUb3RhbCBkZSBVbmlkYWRlcyBWZW5kaWRhcyIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgICMgUm90YXIgZXRpcXVldGFzIGRlbCBlamUgeCBwYXJhIG1lam9yIGxlZ2liaWxpZGFkDQoNCmBgYA0KDQoNCmBgYHtyfQ0KI1RvcCA1IGNsaWVudGVzIEdsb2JhbA0KDQojIENvbmNhdGVuYXIgbG9zIGRhdG9zIGRlIGxvcyB0cmVzIGHDsW9zDQp2ZW50YXNfdG90YWxlcyA8LSByYmluZCh2ZW50YXNfY2xpZW50ZXMyMDIxLCB2ZW50YXNfY2xpZW50ZXMyMDIyLCB2ZW50YXNfY2xpZW50ZXMyMDIzKQ0KDQojIEFncnVwYXIgcG9yIGNsaWVudGUgeSBzdW1hciBsYXMgdW5pZGFkZXMNCnZlbnRhc19wb3JfY2xpZW50ZSA8LSB2ZW50YXNfdG90YWxlcyAlPiUNCiAgZ3JvdXBfYnkoY2xpZW50ZSkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF91bmlkYWRlcyA9IHN1bSh1bmlkYWRlcykpDQoNCiMgT3JkZW5hciBwb3IgZWwgdG90YWwgZGUgdW5pZGFkZXMgeSBzZWxlY2Npb25hciBsb3MgNSBwcmltZXJvcw0KdG9wXzVfY2xpZW50ZXNfZ2VuZXJhbCA8LSB2ZW50YXNfcG9yX2NsaWVudGUgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbF91bmlkYWRlcykpICU+JQ0KICBoZWFkKDUpDQoNCiMgTW9zdHJhciBlbCB0b3AgNSBkZSBjbGllbnRlcyBxdWUgbcOhcyBjb25zdW1lbiBlbiBnZW5lcmFsDQpwcmludCh0b3BfNV9jbGllbnRlc19nZW5lcmFsKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCiMgR3JhZmljYXIgZWwgdG9wIDUgZ2VuZXJhbCBkZSBjbGllbnRlcyBxdWUgbcOhcyBjb25zdW1lbg0KZ2dwbG90KHRvcF81X2NsaWVudGVzX2dlbmVyYWwsIGFlcyh4ID0gY2xpZW50ZSwgeSA9IHRvdGFsX3VuaWRhZGVzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKw0KICBsYWJzKHRpdGxlID0gIlRvcCA1IGRlIENsaWVudGVzIHF1ZSBtw6FzIENvbnN1bWVuICgyMDIxLTIwMjMpIiwNCiAgICAgICB4ID0gIkNsaWVudGUiLA0KICAgICAgIHkgPSAiVG90YWwgZGUgVW5pZGFkZXMgVmVuZGlkYXMiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICAjIFJvdGFyIGV0aXF1ZXRhcyBkZWwgZWplIHggcGFyYSBtZWpvciBsZWdpYmlsaWRhZA0KDQpgYGANCg0KDQojIyBSSCAoQWN0dWFsaXphZG8pDQoNCmBgYHtyfQ0Kb3BlcmF0aXZhX0ZPUk0yMDI0IDwtIHJlYWR4bDo6cmVhZF9leGNlbCgiQzpcXFVzZXJzXFxsZXNkYV9iNXdmcXFhXFxEb3dubG9hZHNcXGV2MVxcQkFTRVMgQUNUVUFMSVpBREFTXFxEYXRvc19GT1JNX1JIX0ZKMjAyNC54bHN4Iiwgc2hlZXQgPSAiT3BlcmF0aXZhIikNCmBgYA0KDQpgYGB7cn0NCm9wZXJhdGl2YV9GT1JNMjAyNA0KYGBgDQoNCg0KYGBge3J9DQojIEVsaW1pbmFyIGxhcyBwcmltZXJhcyA2IGZpbGFzDQpvcGVyYXRpdmFfRk9STTIwMjQgPC0gb3BlcmF0aXZhX0ZPUk0yMDI0ICU+JQ0KICBzbGljZSgtKDE6NikpDQpvcGVyYXRpdmFfRk9STTIwMjQNCmBgYA0KDQoNCmBgYHtyfQ0KIyBUb21hciBsYSBwcmltZXJhIGZpbGEgY29tbyBub21icmVzIGRlIGxhcyBjb2x1bW5hcw0KbnVldm9zX25vbWJyZXMgPC0gYXMuY2hhcmFjdGVyKHVubGlzdChvcGVyYXRpdmFfRk9STTIwMjRbMSxdKSkNCm9wZXJhdGl2YV9GT1JNMjAyNCA8LSBvcGVyYXRpdmFfRk9STTIwMjRbLTEsXSAgIyBFbGltaW5hciBsYSBwcmltZXJhIGZpbGENCmNvbG5hbWVzKG9wZXJhdGl2YV9GT1JNMjAyNCkgPC0gbnVldm9zX25vbWJyZXMNCg0KYGBgDQoNCg0KYGBge3J9DQojIFVzYW5kbyBuYW1lcygpDQpjb2x1bW5hcyA8LSBuYW1lcyhvcGVyYXRpdmFfRk9STTIwMjQpDQpwcmludChjb2x1bW5hcykNCmBgYA0KDQpgYGB7cn0NCiMgUmVlbm9tYnJhciBsYSBjb2x1bW5hIEVzdGFkbyBDaXZpbCBhIEVzdGFkb19DaXZpbA0Kb3BlcmF0aXZhX0ZPUk0yMDI0IDwtIHJlbmFtZShvcGVyYXRpdmFfRk9STTIwMjQsIEVzdGFkb19DaXZpbCA9IGBFc3RhZG8gQ2l2aWxgKQ0KYGBgDQoNCmBgYHtyfQ0KY29sdW1uYXMgPC0gbmFtZXMob3BlcmF0aXZhX0ZPUk0yMDI0KQ0KcHJpbnQoY29sdW1uYXMpDQpgYGANCg0KDQpgYGB7cn0NCiMgQ29udGFyIGxhIGNhbnRpZGFkIGRlIHRyYWJhamFkb3JlcyBwb3IgZXN0YWRvIGNpdmlsDQpjb250ZW9fZXN0YWRvX2NpdmlsIDwtIG9wZXJhdGl2YV9GT1JNMjAyNCAlPiUNCiAgZ3JvdXBfYnkoRXN0YWRvX0NpdmlsKSAlPiUNCiAgc3VtbWFyaXNlKENhbnRpZGFkX1RyYWJhamFkb3JlcyA9IG4oKSkNCg0KIyBPcmRlbmFyIGxvcyBlc3RhZG9zIGNpdmlsZXMNCmNvbnRlb19lc3RhZG9fY2l2aWwgPC0gY29udGVvX2VzdGFkb19jaXZpbCAlPiUNCiAgYXJyYW5nZShFc3RhZG9fQ2l2aWwpDQoNCiMgQ3JlYXIgZWwgZ3LDoWZpY28gZGUgYmFycmFzDQpnZ3Bsb3QoY29udGVvX2VzdGFkb19jaXZpbCwgYWVzKHggPSBFc3RhZG9fQ2l2aWwsIHkgPSBDYW50aWRhZF9UcmFiYWphZG9yZXMsIGZpbGwgPSBFc3RhZG9fQ2l2aWwpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnMoeCA9ICJFc3RhZG8gQ2l2aWwiLCB5ID0gIkNhbnRpZGFkIGRlIFRyYWJhamFkb3JlcyIsIHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgVHJhYmFqYWRvcmVzIHBvciBFc3RhZG8gQ2l2aWwiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQoNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBSZWdpc3Ryb3MgcG9yIEdlbmVybw0KDQojIENvbnRhciBsYSBjYW50aWRhZCBkZSByZWdpc3Ryb3MgcG9yIGfDqW5lcm8NCmNvbnRlb19nZW5lcm8gPC0gb3BlcmF0aXZhX0ZPUk0yMDI0ICU+JQ0KICBncm91cF9ieShHw6luZXJvKSAlPiUNCiAgc3VtbWFyaXNlKENhbnRpZGFkID0gbigpKQ0KDQojIENhbGN1bGFyIGxvcyBwb3JjZW50YWplcyBkZSBnw6luZXJvDQpjb250ZW9fZ2VuZXJvIDwtIGNvbnRlb19nZW5lcm8gJT4lDQogIG11dGF0ZShQb3JjZW50YWplID0gKENhbnRpZGFkIC8gc3VtKENhbnRpZGFkKSkgKiAxMDApDQoNCiMgQ3JlYXIgZWwgZ3LDoWZpY28gZGUgYmFycmFzDQpnZ3Bsb3QoY29udGVvX2dlbmVybywgYWVzKHggPSBHw6luZXJvLCB5ID0gQ2FudGlkYWQsIGZpbGwgPSBHw6luZXJvKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUocm91bmQoUG9yY2VudGFqZSwgMSksICIlIiksIHkgPSBDYW50aWRhZCksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDMsIGNvbG9yID0gImJsYWNrIikgKw0KICBsYWJzKHggPSAiR8OpbmVybyIsIHkgPSAiQ2FudGlkYWQiLCB0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIEfDqW5lcm8iKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQoNCmBgYA0KDQpgYGBge3J9DQphZG1pbmlzdHJhdGl2YV9GT1JNMjAyNCA8LSByZWFkeGw6OnJlYWRfZXhjZWwoIkM6XFxVc2Vyc1xcbGVzZGFfYjV3ZnFxYVxcRG93bmxvYWRzXFxldjFcXEJBU0VTIEFDVFVBTElaQURBU1xcRGF0b3NfRk9STV9SSF9GSjIwMjQueGxzeCIsIHNoZWV0ID0gIkFkbWluaXN0cmF0aXZhIikNCmBgYA0KDQpgYGB7cn0NCmFkbWluaXN0cmF0aXZhX0ZPUk0yMDI0DQpgYGANCg0KYGBge3J9DQojIENvbnRhciBsYSBjYW50aWRhZCBkZSB0cmFiYWphZG9yZXMgcG9yIGVzdGFkbyBjaXZpbA0KY29udGVvX2VzdGFkb19jaXZpbCA8LSBhZG1pbmlzdHJhdGl2YV9GT1JNMjAyNCAlPiUNCiAgZ3JvdXBfYnkoRXN0YWRvX0NpdmlsKSAlPiUNCiAgc3VtbWFyaXNlKENhbnRpZGFkX1RyYWJhamFkb3JlcyA9IG4oKSkNCg0KIyBPcmRlbmFyIGxvcyBlc3RhZG9zIGNpdmlsZXMNCmNvbnRlb19lc3RhZG9fY2l2aWwgPC0gY29udGVvX2VzdGFkb19jaXZpbCAlPiUNCiAgYXJyYW5nZShFc3RhZG9fQ2l2aWwpDQoNCiMgQ3JlYXIgZWwgZ3LDoWZpY28gZGUgYmFycmFzDQpnZ3Bsb3QoY29udGVvX2VzdGFkb19jaXZpbCwgYWVzKHggPSBFc3RhZG9fQ2l2aWwsIHkgPSBDYW50aWRhZF9UcmFiYWphZG9yZXMsIGZpbGwgPSBFc3RhZG9fQ2l2aWwpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnMoeCA9ICJFc3RhZG8gQ2l2aWwiLCB5ID0gIkNhbnRpZGFkIGRlIFRyYWJhamFkb3JlcyIsIHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgVHJhYmFqYWRvcmVzIHBvciBFc3RhZG8gQ2l2aWwiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBSZWdpc3Ryb3MgcG9yIEdlbmVybw0KDQojIENvbnRhciBsYSBjYW50aWRhZCBkZSByZWdpc3Ryb3MgcG9yIGfDqW5lcm8NCmNvbnRlb19nZW5lcm8gPC0gYWRtaW5pc3RyYXRpdmFfRk9STTIwMjQgJT4lDQogIGdyb3VwX2J5KEfDqW5lcm8pICU+JQ0KICBzdW1tYXJpc2UoQ2FudGlkYWQgPSBuKCkpDQoNCiMgQ2FsY3VsYXIgbG9zIHBvcmNlbnRhamVzIGRlIGfDqW5lcm8NCmNvbnRlb19nZW5lcm8gPC0gY29udGVvX2dlbmVybyAlPiUNCiAgbXV0YXRlKFBvcmNlbnRhamUgPSAoQ2FudGlkYWQgLyBzdW0oQ2FudGlkYWQpKSAqIDEwMCkNCg0KIyBDcmVhciBlbCBncsOhZmljbyBkZSBiYXJyYXMNCmdncGxvdChjb250ZW9fZ2VuZXJvLCBhZXMoeCA9IEfDqW5lcm8sIHkgPSBDYW50aWRhZCwgZmlsbCA9IEfDqW5lcm8pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZShyb3VuZChQb3JjZW50YWplLCAxKSwgIiUiKSwgeSA9IENhbnRpZGFkKSwgdmp1c3QgPSAtMC41LCBzaXplID0gMywgY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnMoeCA9ICJHw6luZXJvIiwgeSA9ICJDYW50aWRhZCIsIHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgR8OpbmVybyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCmBgYA0KDQoNCiMjIENhcnRvbiAvIFBhcGVsIChBY3R1YWxpemFkbykNCg0KYGBge3J9DQpwYXBlbGNhcnRvbiA8LSByZWFkX3hsc3goIkM6XFxVc2Vyc1xcbGVzZGFfYjV3ZnFxYVxcRG93bmxvYWRzXFxldjFcXEJBU0VTIEFDVFVBTElaQURBU1xcaWVkX2NhcnRvbl9wYXBlbF8yMDIzLnhsc3giKQ0KYGBgDQoNCmBgYHtyfQ0KcGFwZWxjYXJ0b24NCmBgYA0KDQpgYGB7cn0NCiMgU2VsZWNjaW9uYXIgbGFzIGNvbHVtbmFzICJZZWFyIiB5ICJUaXBvX0NhbWJpbyINCiMgQ3JlYSB1bmEgdHJlbmRsaW5lIGVudHJlIGVsIFllYXIgeSBlbCBUaXBvX0NhbWJpbw0KdHJlbmRsaW5lMSA8LSBnZ3Bsb3QocGFwZWxjYXJ0b24sIGFlcyh4ID0gWWVhciwgeSA9IFRpcG9fQ2FtYmlvKSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArDQogIGdlb21fcG9pbnQoKSArDQogIGxhYnModGl0bGUgPSAiVHJlbmRsaW5lIGRlIFRpcG8gZGUgQ2FtYmlvIHBvciBBw7FvIikNCg0KIyBDcmVhIHVuYSBncsOhZmljYSBwb3IgYcOxbyB5IHF1YXJ0ZXINCmJ5X3llYXJfcXVhcnRlciA8LSBnZ3Bsb3QocGFwZWxjYXJ0b24sIGFlcyh4ID0gUXVhcnRlciwgeSA9IElOUEMsIGdyb3VwID0gWWVhciwgY29sb3IgPSBmYWN0b3IoWWVhcikpKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgbGFicyh0aXRsZSA9ICJJTlBDIHBvciBRdWFydGVycyAoQ29sb3IgcG9yIEHDsW8pIiwgeCA9ICJRdWFydGVyIikNCg0KIyBDcmVhIHVuYSBncsOhZmljYSBwb3IgYcOxbyBkZSBJRUQgRmFiIENhcnRvbiBQYXBlbCBlIElOUEMNCmJ5X3llYXIgPC0gZ2dwbG90KHBhcGVsY2FydG9uLCBhZXMoeCA9IFllYXIpKSArDQogIGdlb21fbGluZShhZXMoeSA9IElOUEMsIGNvbG9yID0gIklOUEMiKSkgKw0KICBsYWJzKHRpdGxlID0gIklOUEMgcG9yIEHDsW8iLCB5ID0gIlZhbG9yIikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gInJlZCIsIGxhYmVscyA9IGMoICJJTlBDIikpDQoNCiMgTW9zdHJhciBsYXMgZ3LDoWZpY2FzDQpwcmludCh0cmVuZGxpbmUxKQ0KcHJpbnQoYnlfeWVhcl9xdWFydGVyKQ0KcHJpbnQoYnlfeWVhcikNCmBgYA0KDQojIFByaW5jaXBhbGVzIEhhbGxhemdvcw0KDQoqKiBFcyBuZWNlc2FyaW8gYnVzY2FyIHVuYSBudWV2YSBhbHRlcm5hdGl2YSBwYXJhIGNvbWJhdGlyIGVsIGNhbG9yIGVuIGxhcyDDoXJlYXMgZGUgdHJhYmFqbw0KDQoqKiBBIG5pdmVsIG1lbnN1YWwsIGxhcyB2ZW50YXMgc2lndWVuIHVuIHBhdHLDs24gY8OtY2xpY28sIG1pZW50cmFzIHF1ZSBhIG5pdmVsIGFudWFsIG11ZXN0cmFuIHVuYSB0ZW5kZW5jaWEgZ2VuZXJhbCBhc2NlbmRlbnRlLg0KDQoqKiBBdW5xdWUgbG9zIHZhbG9yZXMgcmVhbGVzIGRlIGxhcyB2ZW50YXMgc2UgYWp1c3RhbiBhIGxvcyBwYXRyb25lcy4gVG9kYXZpYSBzZSBwdWVkZW4gaGFjZXIgbWVqb3JhcyB5YSBxdWUgc2UgdGllbmVuIGRpc2NyZXBhbmNpYXMuDQoNCioqIFNlIHRpZW5lIGVzcGVyYWRvIHVuIGluY3JlbWVudG8gc2lnbmlmaWNhdGl2byBwZXJvIGVzcGVyYWRvIGVuIGVsIG5lYXJzaG9yaW5nLCBpbmNyZW1lbnRhbmRvIGxhIGNvbXBldGl0aXZpZGFkIGRlIGxhIGluZHVzdHJpYS4NCg0KKiogVG9tYXIgbWVkaWRhcyBhbnRlIGVsIGFjb3NvIGxhYm9yYWwgaGFjaWEgbGFzIHRyYWJhamFkb3JhcyB5IHRyYWJhamFkb3JlcyBzb2x0ZXJvcy4NCg0KKiogUG90ZW5jaWFyIGxhcyBmb3J0YWxlemFzIGNvbiBtZW5vciBlbmZvcXVlIHF1ZSBzb24gZGUgbWF5b3IgaW1wb3J0YW5jaWEgcGFyYSBldml0YXIgcXVlIGVsIDY1LjElIGRlIGxhcyB0cmFiYWphZG9yYXMgZGVjaWRhbiB5YSBubyBjb250aW51YXIgZW4gbGEgZW1wcmVzYS4NCg0KKiogQ29uIGJhc2UgYWwgYW5hbGlzaXMgZGUgdmVudGFzIGRlZmluaXIgbWV0YXMgYSBjb3J0bywgbWVkaWFubyB5IGxhcmdvIHBsYXpvLiBQdWVzIGRlIGVzdGEgbWFuZXJhIGxvZ3JhcmVtb3Mgb2JzZXJ2YXIgYSBtYXlvciBtZWRpZGEgZWwgY3JlY2ltaWVudG8gZGUgbGEgZW1wcmVzYSBvIGxhcyBhcmVhcyBkZSBtZWpvcmEuDQoNCg0KDQojIFJlZmVyZW5jaWFzDQoNCm9yLCBSLiAoMjAyMSwgQXVndXN0IDIzKS4gVGhlIEZvcm0gV2F5IC0uIEZvcm0uIGh0dHBzOi8vZm9ybS5jb20ubXgvdGhlLWZvcm0td2F5Lw0KDQpmb3IsIFIuICgyMDIxLCBTZXB0ZW1iZXIgMjcpLiBGb3JtIHJpZ2h0IGZvcm0gb2YgcGFja2luZy4gRm9ybS4gaHR0cHM6Ly9mb3JtLmNvbS5teC8NCg0KZm9yLCBSLiAoMjAyMSwgQXVndXN0IDIzKS4gwr9Qb3IgcXXDqSBOb3NvdHJvcz8gLS4gRm9ybWEuIGh0dHBzOi8vZm9ybS5jb20ubXgvcG9yLXF1ZS1ub3NvdHJvcy8NCkVsIEVjb25vbWlzdGEuICgyMDIyLCBBdWd1c3QgMjkpLiBQYXNlIHBhcmEgZ29sIGVuIE5vcnRlYW3DqXJpY2E6IGxhIExleSBkZSBSZWR1Y2Npw7NuIGRlIEluZmxhY2nDs24uIEVsIEVjb25vbWlzdGE7IEVsIEVjb25vbWlzdGEuIGh0dHBzOi8vd3d3LmVsZWNvbm9taXN0YS5jb20ubXgvb3Bpbmlvbi9QYXNlLXBhcmEtZ29sLWVuLU5vcnRlYW1lcmljYS1sYS1MZXktZGUtUmVkdWNjaW9uLWRlLUluZmxhY2lvbi0yMDIyMDgyOS0wMDQ0Lmh0bWwNCg0KQWRyacOhbiBEdWhhbHQuICgyMDI0LCBKYW51YXJ5IDIzKS4gTcOpeGljbyB5IGxhIExleSBwYXJhIGxhIFJlZHVjY2nDs24gZGUgbGEgSW5mbGFjacOzbiBlbiBFVS4gRXhwYW5zacOzbi4gaHR0cHM6Ly9leHBhbnNpb24ubXgvb3Bpbmlvbi8yMDI0LzAxLzIzL21leGljby15LWxhLWxleS1wYXJhLWxhLXJlZHVjY2lvbi1kZS1sYS1pbmZsYWNpb24tZW4tZXUNCkRXIEVzcGHDsW9sLiAoMjAyMykuIE3DqXhpY28sIEVFLiBVVS4geSBDYW5hZMOhIHF1aWVyZW4gbGlkZXJhciBsYSBwcm9kdWNjacOzbiBtdW5kaWFsIGRlIHZlaMOtY3Vsb3MgZWzDqWN0cmljb3MgW1lvdVR1YmUgVmlkZW9dLiBFbiBZb3VUdWJlLiBodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PVJIcF9qU3NzV01nDQoNClJpY2FyZG8sIEQuICgyMDIzLCBGZWJydWFyeSA2KS4gVGVuZGVuY2lhcyBlbiBwYWNrYWdpbmcgeSBzb3N0ZW5pYmlsaWRhZCBwYXJhIGVsIDIwMjMuIFBsYXN0aWNvOyBQbGFzdGljby4gaHR0cHM6Ly93d3cucGxhc3RpY28uY29tL2VzL25vdGljaWFzL3RlbmRlbmNpYXMtZW4tcGFja2FnaW5nLXktc29zdGVuaWJpbGlkYWQtcGFyYS1lbC0yMDIzDQoNCkNvbnRyZXJhcywgSi4sICYgQ29udHJlcmFzLCBKLiAoMjAyNGIsIGVuZXJvIDI0KS4gTWFyY2FzIG3DoXMgdmFsaW9zYXMgZGVsIG11bmRvIDIwMjQ6IEVtcHJlc2FzIG1leGljYW5hcyBkZXN0YWNhbiBlbiBlbCByYW5raW5nLiBMw61kZXIgRW1wcmVzYXJpYWwuaHR0cHM6Ly93d3cubGlkZXJlbXByZXNhcmlhbC5jb20vbWFyY2FzLW1hcy12YWxpb3Nhcy1kZWwtbXVuZG8tMjAyNC1lbXByZXNhcy1tZXhpY2FuYXMtZGVzdGFjYW4tZW4tZWwtcmFua2luZy8NCg0KSHVtYW4gdmVyaWZpY2F0aW9uLiAocy4gZi4pLiBodHRwczovL3d3dy5lbGVjb25vbWlzdGEuY29tLm14L2Vjb25vbWlhL0luZmxhY2lvbi1pbmljaWEtZWwtMjAyNC1hY2VsZXJhbmRvc2UtYS00LjkwLWhpbGEtNS1xdWluY2VuYXMtYWwtYWx6YS0yMDI0MDEyNC0wMDE4Lmh0bWwNCg0KSW1wb3J0YW5jaWEgZGUgbGFzIHRlbmRlbmNpYXMgZGUgbWVjYWRvIDIwMjQgLSBCaW5nLiAocy4gZi4pLiBCaW5nLiBodHRwczovL3d3dy5iaW5nLmNvbS9zZWFyY2g/cT1JbXBvcnRhbmNpYStkZStsYXMrVGVuZGVuY2lhcytkZStNZWNhZG8rMjAyNCZxcz1uJmZvcm09UUJSRSZzcD0tMSZnaGM9MSZscT0wJnBxPWltcG9ydGFuY2lhK2RlK2xhcyt0ZW5kZW5jaWFzK2RlK21lY2FkbysyMDImc2M9MTEtNDMmc2s9JmN2aWQ9RDk0OTEwQTc4MDcwNDA1RDhDNzIyMzlDODE2QUZBRjAmZ2hzaD0wJmdoYWNjPTAmZ2hwbD0NCg0KSW5ub3ZhY2nDs24gZW4gbGEgZW1wcmVzYTogY29uY2VwdG8sIGltcG9ydGFuY2lhIHkgdGlwb2xvZ8OtYXMuIChzLiBmLikuIFVOSVIgTcOpeGljby4gaHR0cHM6Ly9tZXhpY28udW5pci5uZXQvZWNvbm9taWEvbm90aWNpYXMvaW5ub3ZhY2lvbi1lbi11bmEtZW1wcmVzYS8jOn46dGV4dD1MYSUyMGlubm92YWNpJUMzJUIzbiUyMGVtcHJlc2FyaWFsJTIwc2UlMjBoYSUyMHZ1ZWx0byUyMGNsYXZlJTIwZGVyaXZhZG8sOCUyMEElQzMlQjFhZGUlMjB2YWxvciUyMGElMjBsb3MlMjBwcm9kdWN0b3MlMjBvJTIwc2VydmljaW9zLg0KDQrCv1F1w6kgZXMgbGEgYXV0b21hdGl6YWNpw7NuPyB8IElCTS4gKHMuIGYuKS4gaHR0cHM6Ly93d3cuaWJtLmNvbS9teC1lcy90b3BpY3MvYXV0b21hdGlvbg0KDQpFbXBhcXVlcyBzdXN0ZW50YWJsZXMgLSBCaW5nLiAocy4gZi4pLiBCaW5nLiBodHRwczovL3d3dy5iaW5nLmNvbS9zZWFyY2g/cGdsdD00MSZxPUVtcGFxdWVzK1N1c3RlbnRhYmxlcyZjdmlkPTgxZTEzOTNmM2I3ZDQyNDI5MDU3ZTI1NGNiMTMyMWNiJmdzX2xjcnA9RWdaamFISnZiV1V5QmdnQUVFVVlPVElHQ0FFUUFCaEFNZ1lJQWhBQUdFQXlCZ2dERUFBWVFESUdDQVFRQUJoQTBnRUhNelF5YWpCcU1hZ0NBTEFDQUEmRk9STT1BTk5UQTEmUEM9TENUUw0KDQpEZSBsYXMgTXVqZXJlcywgSS4gTi4gKHMuIGYuKS4gTGFzIE1hZHJlcyBlbiBDaWZyYXMuIGdvYi5teC4gaHR0cHM6Ly93d3cuZ29iLm14L2lubXVqZXJlcy9hcnRpY3Vsb3MvbGFzLW1hZHJlcy1lbi1jaWZyYXMNCg0KQWxjYWxkZXMgZGUgTcOpeGljbyAoMjAyMiwgTWFyY2ggMjIpLiBOdWV2byBMZcOzbiByZWR1Y2UgcHJlc2nDs24gZGVsIGFndWEgZW4gw6FyZWEgbWV0cm9wb2xpdGFuYSBwb3Igc2VxdcOtYS4gQWxjYWxkZXMgZGUgTcOpeGljby4gW0ltYWdlbl0gaHR0cHM6Ly93d3cuYWxjYWxkZXNkZW1leGljby5jb20vbm90YXMtcHJpbmNpcGFsZXMvbnVldm8tbGVvbi1yZWR1Y2UtcHJlc2lvbi1kZWwtYWd1YS1lbi1hcmVhLW1ldHJvcG9saXRhbmEtcG9yLXNlcXVpYS8NCg0KDQo=