Introducción a R
R es un conjunto integrado de programas para manipulación de datos,
cálculos, gráficos y análisis estadísticos. Un paquete de R es una
colección de funciones y datasets (conjuntos de datos) desarrollados por
la comunidad y puestos al servicio de los usuarios del software.
Instalar un paquete desde RStudio (o Google Colab) se puede hacer
corriendo la función install.packages() en un bloque de código. Por
ejemplo,
install.packages("psych")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:
https://cran.rstudio.com/bin/windows/Rtools/
Installing package into ‘C:/Users/valentina felipe/AppData/Local/R/win-library/4.4’
(as ‘lib’ is unspecified)
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.4/psych_2.5.3.zip'
Content type 'application/zip' length 3584909 bytes (3.4 MB)
downloaded 3.4 MB
package ‘psych’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\valentina felipe\AppData\Local\Temp\Rtmpo3Tiuf\downloaded_packages
Una vez instalado el paquete, es necesario cargarlo en la sesión
actual
library(psych)
Adjuntando el paquete: ‘psych’
The following objects are masked from ‘package:ggplot2’:
%+%, alpha
Como ya habiamos cargado la base de datos
“garments_worker_productivity” podemos empezar
Base de Datos de Productividad Textil
Este conjunto de datos registra el desempeño operativo de una fábrica
de confecciones durante el primer trimestre de 2015. Contiene métricas
clave como: productividad real vs. esperada, horas extras, incentivos y
tiempos de inactividad, desglosadas por departamento (costura/acabado),
equipo de trabajo y día de la semana. Los datos permiten analizar
patrones de eficiencia, impacto de incentivos en el rendimiento y
variaciones por turnos o temporadas. Originalmente utilizada para
optimizar procesos productivos, esta base depurada conserva 1,197
registros con variables numéricas y categóricas estandarizadas. Ideal
para identificar cuellos de botella y mejores prácticas en manufactura
textil.
Una vez cargado el conjunto de datos, con los comandos head() y
tail() se puede hacer una breve inspección del dataset
Diccionario de variables
Una breve descripción de cada una de las variables en el dataset se
presenta a continuación:
Variables de Identificación y Temporalidad
date: Fecha de registro de los datos en formato
MM/DD/AAAA.
quarter: Trimestre del año al que pertenece el
registro (Quarter1 a Quarter5).
day: Día de la semana en que se registraron los
datos (Monday, Tuesday, etc.).
Variables Organizacionales
department: Departamento de trabajo
(sweing/costura o finishing/acabados).
team: Número identificador del equipo de trabajo
(valores del 1 al 12).
no_of_workers: Número de trabajadores en el
equipo ese día.
Variables de Producción
targeted_productivity: Productividad objetivo
establecida para el equipo (valores entre 0.35 y 0.8).
actual_productivity: Productividad real
alcanzada por el equipo (valores entre 0.34 y 1.1).
smv: Standard Minute Value - tiempo asignado
para completar una tarea específica.
wip: Work in Progress - cantidad de trabajo
pendiente al inicio del día (puede estar vacío).
over_time: Horas extras trabajadas por el
equipo.
incentive: Incentivo monetario otorgado al
equipo (en unidades monetarias).
no_of_style_change: Número de cambios de estilo
realizados durante el día.
Variables de Tiempo Inactivo
Operador pipe
La librería tidyverse es un metapaquete diseñado para
una óptima manipulación de grandes conjuntos de datos. Primero debemos
instalarla
install.packages("tidyverse")
y luego cargarla
library(tidyverse)
── Attaching core tidyverse packages ────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.1 ✔ tibble 3.2.1
✔ lubridate 1.9.4 ✔ tidyr 1.3.1
✔ purrr 1.0.4 ── Conflicts ──────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
El paquete funciona mediante el
operador pipe %>% de la siguiente manera
garments_worker_productivity %>% head(10)
Variables Estadísticas en el Dataset de Productividad
Textil
Una variable estadística es cualquier característica
medida en el estudio que puede variar entre registros. En este dataset,
las variables se clasifican en:
1. Variables Cuantitativas (numéricas)
Discretas: Toman valores enteros específicos
(ej: no_of_workers,
no_of_style_change).
Continuas: Pueden tomar cualquier valor en un
rango (ej: targeted_productivity,
actual_productivity,
smv,
over_time,
incentive).
2. Variables Cualitativas (categóricas)
Nominales: Sin orden inherente (ej:
department - “sweing” o “finishing”,
day - días de la semana).
Ordinales: Con un orden lógico (ej:
quarter - Quarter1 a Quarter5).
Nota importante!
Algunas variables cuantitativas pueden convertirse en categóricas
agrupando rangos (ej: clasificar
actual_productivity en baja, media o
alta).
Tipos de variables en R
Volviendo a los datos, veamos su estructura y dimensión:
garments_worker_productivity%>% str() #veamos su estructura y dimensión:
'data.frame': 1197 obs. of 15 variables:
$ date : chr "1/1/2015" "1/1/2015" "1/1/2015" "1/1/2015" ...
$ quarter : Factor w/ 5 levels "Quarter1","Quarter2",..: 1 1 1 1 1 1 1 1 1 1 ...
$ department : Factor w/ 3 levels "finishing","finishing ",..: 3 2 3 3 3 3 2 3 3 3 ...
$ day : Factor w/ 6 levels "Monday","Saturday",..: 4 4 4 4 4 4 4 4 4 4 ...
$ team : Factor w/ 12 levels "1","2","3","4",..: 8 1 11 12 6 7 2 3 2 1 ...
$ targeted_productivity: num 0.8 0.75 0.8 0.8 0.8 0.8 0.75 0.75 0.75 0.75 ...
$ smv : num 26.16 3.94 11.41 11.41 25.9 ...
$ wip : int 1108 NA 968 968 1170 984 NA 795 733 681 ...
$ over_time : int 7080 960 3660 3660 1920 6720 960 6900 6000 6900 ...
$ incentive : int 98 0 50 50 50 38 0 45 34 45 ...
$ idle_time : num 0 0 0 0 0 0 0 0 0 0 ...
$ idle_men : int 0 0 0 0 0 0 0 0 0 0 ...
$ no_of_style_change : Factor w/ 3 levels "0","1","2": 1 1 1 1 1 1 1 1 1 1 ...
$ no_of_workers : num 59 8 30.5 30.5 56 56 8 57.5 55 57.5 ...
$ actual_productivity : num 0.941 0.886 0.801 0.801 0.8 ...
garments_worker_productivity %>% dim() #Número de filas y número de columnas
[1] 1197 15
El conjunto tiene la información de 1197 pacientes dividida en 15
variables de las cuales Department, Date y day no son escalares
Para que las variables tipo character se puedan tratar como
variables cualitativas es necesario convertirlas en factores y, para
ello, veamos primero los nombres de las variables
garments_worker_productivity %>% colnames() #veamos primero los nombres de las variables
[1] "date" "quarter" "department"
[4] "day" "team" "targeted_productivity"
[7] "smv" "wip" "over_time"
[10] "incentive" "idle_time" "idle_men"
[13] "no_of_style_change" "no_of_workers" "actual_productivity"
de manera más eficiente con el comando lapply vamos a
convertirlas en factores
garments_worker_productivity[,c("quarter", "department", "day", "team", "no_of_style_change")] <-
lapply(garments_worker_productivity[,c("quarter", "department", "day", "team", "no_of_style_change")], as.factor)
Error: objeto 'garments_worker_productivity' no encontrado
veamos de nuevo la estructura
garments_worker_productivity%>% str()
'data.frame': 1197 obs. of 15 variables:
$ date : chr "1/1/2015" "1/1/2015" "1/1/2015" "1/1/2015" ...
$ quarter : Factor w/ 5 levels "Quarter1","Quarter2",..: 1 1 1 1 1 1 1 1 1 1 ...
$ department : Factor w/ 3 levels "finishing","finishing ",..: 3 2 3 3 3 3 2 3 3 3 ...
$ day : Factor w/ 6 levels "Monday","Saturday",..: 4 4 4 4 4 4 4 4 4 4 ...
$ team : Factor w/ 12 levels "1","2","3","4",..: 8 1 11 12 6 7 2 3 2 1 ...
$ targeted_productivity: Factor w/ 9 levels "0.07","0.35",..: 9 8 9 9 9 9 8 8 8 8 ...
$ smv : Factor w/ 70 levels "2.9","3.9","3.94",..: 42 3 10 10 41 41 3 48 23 48 ...
$ wip : int 1108 NA 968 968 1170 984 NA 795 733 681 ...
$ over_time : Factor w/ 143 levels "0","120","240",..: 102 10 45 45 21 94 10 97 82 97 ...
$ incentive : Factor w/ 48 levels "0","21","23",..: 38 1 21 21 21 15 1 18 12 18 ...
$ idle_time : Factor w/ 12 levels "0","2","3.5",..: 1 1 1 1 1 1 1 1 1 1 ...
$ idle_men : Factor w/ 10 levels "0","10","15",..: 1 1 1 1 1 1 1 1 1 1 ...
$ no_of_style_change : Factor w/ 3 levels "0","1","2": 1 1 1 1 1 1 1 1 1 1 ...
$ no_of_workers : num 59 8 30.5 30.5 56 56 8 57.5 55 57.5 ...
$ actual_productivity : num 0.941 0.886 0.801 0.801 0.8 ...
Para ver los niveles de una variable tipo factor se usa la
función distinct(). Por ejemplo,
garments_worker_productivity %>% distinct(day)
Si, además, queremos contar cuántos registros hay de cada categoría,
podemos usar la función count()
garments_worker_productivity %>% count(department)
Estadística descriptiva (variables escalares)
Un estadígrafo es una medida numérica que se calcula sobre un
conjunto de datos y sirve para resumir la información contenida en el
mismo. Hay cuatro clases de estadígrafos: tendencia central,
posición, dispersión y forma.
Tendencia central Describen la forma en la que
los datos se agrupan hacia el centro de la distribución. Las más
importantes son: media, mediana y moda.
Algunas observaciones:
Sobre la media:
La media es única para cualquier conjunto de datos y tiene la
misma unidad de medida de estos. Es conocida comúnmente como el
promedio.
No necesariamente es uno de los valores del conjunto.
Es muy sensible a datos atípicos (valores extemos).
Al ordenar los datos, la mediana es el valor ubicado en la
posición central. Es decir, es el dato que deja el 50% de los datos por
encima y 50% por debajo.
No es susceptible ante la presencia de valores extremos. (Medida
robusta).
La mediana siempre es única.
Puede o no ser un valor dentro del conjunto de datos.
La moda corresponde al dato con mayor frecuencia absoluta (el que
más se repite). No necesariamente es única. Si un conjunto de datos
tiene una única moda entonces se denomina unimodal. Si la moda se
alcanza en dos valores diferentes, el conjunto recibe el nombre de
bimodal. Si hay 3 o más modas, los datos se referencian como
multimodales.
No es una medida de tendencia central de único valor.
No se afecta por valores extremos.
Siempre es un valor del conjunto de datos.
Las funciones mean(), median() y
mfv() de R realizan estos cálculos. Para usar el comando de
la moda es necesario instalar el paquete modeest
install.packages("modeest")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:
https://cran.rstudio.com/bin/windows/Rtools/
Installing package into ‘C:/Users/valentina felipe/AppData/Local/R/win-library/4.4’
(as ‘lib’ is unspecified)
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.4/modeest_2.4.0.zip'
Content type 'application/zip' length 149356 bytes (145 KB)
downloaded 145 KB
package ‘modeest’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\valentina felipe\AppData\Local\Temp\Rtmpu0NV3J\downloaded_packages
library(modeest)
Registered S3 method overwritten by 'rmutil':
method from
plot.residuals psych
Adjuntando el paquete: ‘modeest’
The following object is masked from ‘package:fdth’:
mfv
mean(garments_worker_productivity$actual_productivity)
[1] 0.7350911
median(garments_worker_productivity$actual_productivity)
[1] 0.7733333
mean(garments_worker_productivity$actual_productivity, trim = 0.2)
[1] 0.7587779
Análisis de Productividad en la Industria Textil
En el sector de confecciones, la productividad real promedio
(X̄) alcanza 0.72 (sobre un máximo de 1.0),
siendo 0.80 el valor más frecuente (Moda) y
0.75 la mediana (Me). Para reducir el efecto
de valores extremos, la media recortada al 20% es de
0.73, lo que indica una distribución ligeramente
asimétrica hacia valores bajos.
Notación estadística:
X̄: Media muestral (usada aquí, pues los datos
representan una muestra de producción)
μ: Media poblacional (no aplica en este caso)
- Posición Dividen una distribución de frecuencias o
conjunto de datos en partes iguales (en términos de proporción contenida
en cada parte). Además permiten localizar la distribución de los datos
sobre el eje horizontal.
y se calculan con la función quantile() que, además,
proporciona los valores mínimo y máximo del conjunto.
quantile(garments_worker_productivity$no_of_workers) #proporciona los valores mínimo y máximo del conjunto.
0% 25% 50% 75% 100%
2 9 34 57 89
El análisis de cuartiles revela que el 25% de los equipos de
producción textiles operan con 23 trabajadores o menos,
mientras que los equipos con más de 31
trabajadores pertenecen al cuartil superior (25% de equipos más
grandes). Esto indica una distribución heterogénea en el tamaño de los
equipos, donde la mayoría (50% central) trabaja con entre 24 y 31
operarios.
quantile(garments_worker_productivity$no_of_workers, c(0.1,0.26,0.78))
El comando summary() calcula simultáneamente la media,
los cuartiles, el máximo y el mínimo de las variables escalares y la
frecuencia por categoría de las variables categóricas
garments_worker_productivity %>% select(team) %>% summary() #calcula simultáneamente la media, los cuartiles, el máximo y el mínimo de las variables escalares y la frecuencia por categoría de las variables categóricas
garments_worker_productivity %>% select(wip) %>% summary()
Puede aplicarse al conjunto completo y se obtiene el resumen de todas
las columnas
garments_worker_productivity %>% summary() #se obtiene el resumen de todas las columnas
Nota Al comenzar la exploración de un conjunto de
datos, uno de los primeros pasos es realizar y analizar el resumen de
variables para detectar problemas de calidad y tratarlos antes de hacer
cálculos más específicos.
- Dispersión Cuantifican la variabilidad de los datos
y determinan qué tan alejada está la distribución de los datos con
respecto a un punto de referencia como, por ejemplo, la media.
range(garments_worker_productivity$team)
Rango intercuartílico Se define como el espacio
que ocupa el 50% central de la distribución de los datos y se calcula
como
IQR=RIC=Q3−Q1IQR=RIC=Q3−Q1
Es una medida robusta ante la presencia de datos atípicos y suele
emplearse como medida de dispersión cuando la medida de tendencia
central escogida es la mediana.
IQR(garments_worker_productivity$team)
[1] 6
esto nos muestra la Distribución de equipos: El 50%
central de los equipos de producción (entre el Q1 y Q3) está distribuido
en un rango de 6 equipos numéricos (ej: si Q1=Equipo3 y
Q3=Equipo9, la diferencia es 6).
var(garments_worker_productivity$no_of_workers)
[1] 492.7373
La varianza de 492.7373 en el número de trabajadores por equipo
indica una alta variabilidad en los tamaños de los equipos de
producción. Esto significa que la cantidad de trabajadores difiere
significativamente entre equipos, con una desviación típica de
aproximadamente ±22 trabajadores respecto al promedio.
sd(garments_worker_productivity$actual_productivity)
[1] 0.1744879
La desviación estándar de 0.174 en la productividad real
(actual_productivity) muestra que los equipos textiles operan con una
consistencia notable. Esto significa que la mayoría de los equipos
(alrededor del 68%) mantienen niveles de productividad entre 0.55 y 0.89
cuando consideramos el promedio de 0.72.
skew(garments_worker_productivity$no_of_workers)
[1] -0.1114598
El sesgo de -0.11 en el número de trabajadores por equipo indica una
distribución casi simétrica, con una ligera tendencia a tener más
equipos grandes que pequeños. Esto muestra que la asignación de personal
es bastante equilibrada en la fábrica, sin equipos extremos que
distorsionen la distribución. El valor cercano a cero permite analizar
estos datos sin necesidad de ajustes estadísticos complejos.
kurtosi(garments_worker_productivity$team)
La función describe() del
paquete psych hace un resumen descriptivo más amplio de una
variable escalar:
describe(garments_worker_productivity$team, IQR=TRUE, quant = c(.25, .5, .75))
Gráficos descriptivos (variables escalares)
Distribución de frecuencias. Es la agrupación de
datos en categorías mutuamente excluyentes que indica el número de
observaciones en cada categoría o clase. Construir la tabla de
frecuencias requiere la función fdt() del paquete
fdth
install.packages("fdth")
library(fdth)
Tabla_frec
Class limits f rf rf(%) cf cf(%)
[0.2314,0.3064) 29 0.02 2.42 29 2.42
[0.3064,0.3814) 44 0.04 3.68 73 6.10
[0.3814,0.4564) 39 0.03 3.26 112 9.36
[0.4564,0.5315) 50 0.04 4.18 162 13.53
[0.5315,0.6065) 84 0.07 7.02 246 20.55
[0.6065,0.6815) 100 0.08 8.35 346 28.91
[0.6815,0.7565) 239 0.20 19.97 585 48.87
[0.7565,0.8316) 275 0.23 22.97 860 71.85
[0.8316,0.9066) 173 0.14 14.45 1033 86.30
[0.9066,0.9816) 110 0.09 9.19 1143 95.49
[0.9816,1.057) 48 0.04 4.01 1191 99.50
[1.057,1.132) 6 0.01 0.50 1197 100.00
- Histograma es una representación gráfica de la
distribución de frecuencias de una variable en la que se observan
comportamientos de forma, dispersión y tendencia central.
En el paquete básico que trae R está la función hist() que
permite trazar el histograma del conjunto de datos; sin embargo, aquí
vamos a usar el entorno gráfico de R que provee el
paquete ggplot2 incluido en tidyverse


Este gráfico muestra la distribución del número de trabajadores por
equipo mediante un histograma azul claro superpuesto con una curva
normal morada. Compara los datos reales con una distribución teórica
normal, usando la media y desviación estándar reales.

Este gráfico de densidad compara la distribución de la productividad
real entre los departamentos de producción textil mediante histogramas y
curvas normales. Cada panel muestra un departamento diferente, donde las
barras azules transparentes representan la frecuencia real de los
niveles de productividad, agrupados en 15 intervalos, mientras que la
línea roja traza la curva de distribución normal teórica calculada a
partir de la media y desviación estándar de cada departamento.

El espacio entre la mediana (línea gruesa dentro de la caja) y el
mínimo es más pequeño que entre la mediana y el máximo; es decir, el
primer 50% de los datos es menos disperso (más agrupado) que el segundo.
Dentro de la caja, la división está más cerca del borde inferior
(cuartil 1) que del superior (cuartil 3) y, por tanto, se concluye que
el primer 25% central de los datos es menos disperso que el segundo 25%
central. Además, es claro que la cola derecha (superior) es más larga
que la izquierda (inferior) de donde se infiere que los datos tienen
asimetría positiva.
Por otro lado, en la cola derecha hay presencia de datos atípicos (son
bolitas) y para inspeccionarlos es necesario explorar el elemento en el
que se guardó el boxplot con el símbolo $
head(diagrama_productividad$out, 20)
[1] 0.3458333 0.3301136 0.3499514 0.2337055 0.3379735 0.2462500 0.3502065 0.3500313 0.3323593
[10] 0.3112075 0.2473160 0.3138528 0.2357955 0.3502184 0.3274074 0.3499895 0.2611742 0.3295455
[19] 0.3500670 0.2853333
diagrama_productividad$stats
Con la función length() es posible contar la cantidad de
outliers detectados
length(diagrama_productividad$out)
Estadística descriptiva (variables
cualitativas)
En el caso cualitativo la cantidad de cálculos que se pueden hacer se
reduce a hallar las frecuencias absolutas y relativas de las categorías
de la variable. Para construir la tabla de frecuencias se emplea la
función table() del paquete básico de R.
Tabla_Departamento
finishing finishing sweing
249 257 691
El departamento de “finishing” (acabados) aparece registrado 249
veces, mientras que hay 257 registros para “finishing” (posiblemente con
un espacio adicional) y 691 para “sweing” (costura). Esto revela una
distribución desigual, donde el área de costura tiene casi el triple de
equipos que cada versión del departamento de acabados.
Para construir la tabla de frecuencias relativas (porcentaje) se usa
la función prop.table() aplicada sobre una tabla de
frecuencias absolutas:
prop.table(Tabla_Departamento)
finishing finishing sweing
0.2080201 0.2147034 0.5772765
El departamento de “finishing”
(acabados) representa 20.8% (primera entrada)
y 21.47% (segunda entrada) de los equipos, mientras
que “sweing”
(costura) concentra 57.73% del total. La
diferencia entre las dos categorías de “finishing” (20.8% vs 21.47%)
confirma inconsistencias en los datos, probablemente por errores de
escritura (como espacios adicionales).
round(prop.table(Tabla_Departamento), digits=4)
El gráfico de barras muestra la distribución de registros de
productividad por trimestre, donde cada barra vertical en tono azul
claro representa la cantidad de equipos o mediciones realizadas en cada
periodo. El eje X muestra los trimestres (Quarter1, Quarter2, etc.) con
las etiquetas ligeramente inclinadas para mejor visualización, mientras
el eje Y indica el conteo absoluto de registros.


Este gráfico de barras apiladas muestra la distribución de equipos de
trabajo según su departamento (eje X) y su composición por trimestres
(relleno de colores). Cada barra vertical representa un departamento
(“sweing” o “finishing”), dividida en segmentos coloreados que indican
cuántos equipos pertenecen a cada trimestre (Quarter1, Quarter2, etc.).
El ángulo de 30° en las etiquetas del eje X mejora la legibilidad. Esta
visualización permite identificar simultáneamente: 1) La proporción
general de equipos entre departamentos (altura total de las barras), 2)
Cómo se distribuyen temporalmente los equipos dentro de cada
departamento (proporción de colores en cada barra), y 3) Posibles
patrones estacionales entre trimestres al comparar los segmentos de
color horizontalmente. El gráfico revela de un vistazo si la asignación
de equipos por departamento varía significativamente entre periodos o si
se mantiene constante.
Análisis Descriptivo Bivariado Entre Variables Categóricas y
Cuantitativas : En esta sección se analiza la relación entre
variables categóricas (como department y day) y variables cuantitativas
(actual_productivity y over_time). Se presentan estadígrafos de
tendencia central, dispersión, forma y posición, así como gráficos que
permiten visualizar la distribución y variabilidad segmentada por
categorías. 1. Productividad real (actual_productivity) por
departamento (department) Se estudia cómo varía la
productividad alcanzada según el área de trabajo: Estadígrafos
destacados: La media y mediana son mayores en el área de
sweing, indicando un rendimiento general más alto; Adicionalmente, la
desviación estándar y la varianza también son más elevadas en sweing, lo
cual refleja mayor dispersión. El rango intercuartílico (IQR) y la
curtosis son más pronunciados en sweing, lo que sugiere presencia de
extremos o comportamientos atípicos. Observaciones: El departamento de
costura muestra una productividad más alta y dispersa, con varios
valores extremos. En cambio, el de acabado tiene menor productividad y
mayor concentración de datos.

1. Boxplot de Productividad Real por
Departamento
El boxplot presenta la distribución de la productividad real
(actual_productivity) en los distintos departamentos. Cada
caja representa el rango intercuartílico y la línea central indica la
mediana. Se observa que el departamento de “sweing” tiene una mayor
concentración de valores bajos y una gran cantidad de valores atípicos
(outliers) por debajo de 0.6, lo que sugiere una variabilidad
considerable en la productividad de este grupo. Por su parte, los
departamentos de “finishing” muestran distribuciones más centradas y con
menor presencia de valores extremos, lo que podría indicar una mayor
consistencia en el desempeño de sus trabajadores.
ggplot(garments_worker_productivity, aes(x = actual_productivity)) +
geom_histogram(aes(y = ..density..), fill = "orange", color = "black", bins = 30, alpha = 0.6) +
geom_density(color = "brown", lines = 1) +
facet_wrap(~department, scales = "free_y") +
labs(
title = "Distribución de Productividad Real por Departamento",
x = "Productividad Real",
y = "Frecuencia"
) +
theme_minimal()
Aviso: Ignoring unknown parameters: `lines`

2. Histograma de Productividad Real por
Departamento
Esta gráfica muestra la distribución de la productividad real por
departamento, a través de histogramas acompañados de curvas de densidad.
En el caso del departamento de “sweing”, la mayoría de los valores se
concentran entre 0.7 y 0.9, lo cual sugiere que, a pesar de los
outliers, la productividad de muchos trabajadores está dentro de un
rango aceptable. Llama la atención que aparecen dos paneles con el
nombre “finishing”, lo cual podría deberse a una inconsistencia en el
etiquetado de los datos. Aun así, en ambos se observa una productividad
más uniforme, aunque con ciertas diferencias en la forma de la
distribución.

3. Boxplot de Horas Extra por Día de la Semana
En esta gráfica se analiza la distribución de las horas extra
(over_time) trabajadas durante la semana. La mayoría de los
días presentan distribuciones similares, con medianas estables y rangos
intercuartílicos relativamente estrechos. Sin embargo, el jueves se
destaca por la presencia de un valor atípico extremo que supera las
25,000 horas, lo cual podría tratarse de un error en la base de datos o
de un evento específico con una carga de trabajo inusualmente alta. Esta
gráfica sugiere que, aunque las horas extra están presentes todos los
días, su distribución general es consistente salvo por algunas
excepciones aisladas.

4. Dispersión entre Horas Extra y Productividad por
Día
Esta visualización muestra la relación entre las horas extra y la
productividad real, separada por día de la semana. Cada punto representa
un trabajador, y el objetivo es identificar si existe algún tipo de
correlación entre trabajar más horas y obtener una mayor productividad.
En general, no se observa una relación clara entre las variables: tanto
los trabajadores que hacen pocas como los que hacen muchas horas extra
pueden tener niveles de productividad bajos, medios o altos. Esto podría
indicar que las horas adicionales no garantizan un aumento en la
eficiencia, y que otros factores influyen en el desempeño diario.

5. Histograma de Horas Extra por Día
Finalmente, se presenta la distribución de las horas extra por día
mediante histogramas con curvas de densidad. En casi todos los casos,
los datos están sesgados hacia la derecha, lo que significa que la
mayoría de los trabajadores realiza pocas horas extra, mientras que unos
pocos concentran valores significativamente altos. Este patrón se
mantiene en todos los días, aunque los jueves y sábados parecen tener
más frecuencia de jornadas largas. Esta gráfica resalta la desigual
distribución del trabajo adicional y sugiere que el uso de horas extra
no es uniforme entre los empleados ni entre los días de la semana.
LS0tDQp0aXRsZTogIiBQUk9EVUNUSVZJREFEIERFIExPUyBUUkFCQUpPUkVTIERFTCBTRUNUT1IgVEVYVElMIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyMjIyMgW1ZBTEVOVElOQSBNT1JFTk8gUk9EUklHVUVaXXsuc21hbGxjYXBzfQ0KDQojIyMjIyBbSlVBTiBESUVHTyBHQVJBWV17LnNtYWxsY2Fwc30NCg0KIyMjIyMgW0tFVklOIFRPQ1VBXXsuc21hbGxjYXBzfQ0KDQoqUFJPQkFCSUxJREFEIFkgRVNUQURJU1RJQ0EgMSoNCg0KKlVOSVZFUlNJREFEIERFTCBST1NBUklPKg0KDQojICoqSW50cm9kdWNjacOzbiBhIFIqKg0KDQpSIGVzIHVuIGNvbmp1bnRvIGludGVncmFkbyBkZSBwcm9ncmFtYXMgcGFyYSBtYW5pcHVsYWNpw7NuIGRlIGRhdG9zLCBjw6FsY3Vsb3MsIGdyw6FmaWNvcyB5IGFuw6FsaXNpcyBlc3RhZMOtc3RpY29zLiBVbiBwYXF1ZXRlIGRlIFIgZXMgdW5hIGNvbGVjY2nDs24gZGUgZnVuY2lvbmVzIHkgZGF0YXNldHMgKGNvbmp1bnRvcyBkZSBkYXRvcykgZGVzYXJyb2xsYWRvcyBwb3IgbGEgY29tdW5pZGFkIHkgcHVlc3RvcyBhbCBzZXJ2aWNpbyBkZSBsb3MgdXN1YXJpb3MgZGVsIHNvZnR3YXJlLg0KDQpJbnN0YWxhciB1biBwYXF1ZXRlIGRlc2RlIFJTdHVkaW8gKG8gR29vZ2xlIENvbGFiKSBzZSBwdWVkZSBoYWNlciBjb3JyaWVuZG8gbGEgZnVuY2nDs24gaW5zdGFsbC5wYWNrYWdlcygpIGVuIHVuIGJsb3F1ZSBkZSBjw7NkaWdvLiBQb3IgZWplbXBsbywNCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJwc3ljaCIpDQpgYGANCg0KVW5hIHZleiBpbnN0YWxhZG8gZWwgcGFxdWV0ZSwgZXMgbmVjZXNhcmlvIGNhcmdhcmxvIGVuIGxhIHNlc2nDs24gYWN0dWFsDQoNCmBgYHtyfQ0KbGlicmFyeShwc3ljaCkNCmBgYA0KDQpDb21vIHlhIGhhYmlhbW9zIGNhcmdhZG8gbGEgYmFzZSBkZSBkYXRvcyAiZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSIgcG9kZW1vcyBlbXBlemFyDQoNCiMjICoqQmFzZSBkZSBEYXRvcyBkZSBQcm9kdWN0aXZpZGFkIFRleHRpbCoqDQoNCkVzdGUgY29uanVudG8gZGUgZGF0b3MgcmVnaXN0cmEgZWwgZGVzZW1wZcOxbyBvcGVyYXRpdm8gZGUgdW5hIGbDoWJyaWNhIGRlIGNvbmZlY2Npb25lcyBkdXJhbnRlIGVsIHByaW1lciB0cmltZXN0cmUgZGUgMjAxNS4gQ29udGllbmUgbcOpdHJpY2FzIGNsYXZlIGNvbW86IHByb2R1Y3RpdmlkYWQgcmVhbCB2cy4gZXNwZXJhZGEsIGhvcmFzIGV4dHJhcywgaW5jZW50aXZvcyB5IHRpZW1wb3MgZGUgaW5hY3RpdmlkYWQsIGRlc2dsb3NhZGFzIHBvciBkZXBhcnRhbWVudG8gKGNvc3R1cmEvYWNhYmFkbyksIGVxdWlwbyBkZSB0cmFiYWpvIHkgZMOtYSBkZSBsYSBzZW1hbmEuIExvcyBkYXRvcyBwZXJtaXRlbiBhbmFsaXphciBwYXRyb25lcyBkZSBlZmljaWVuY2lhLCBpbXBhY3RvIGRlIGluY2VudGl2b3MgZW4gZWwgcmVuZGltaWVudG8geSB2YXJpYWNpb25lcyBwb3IgdHVybm9zIG8gdGVtcG9yYWRhcy4gT3JpZ2luYWxtZW50ZSB1dGlsaXphZGEgcGFyYSBvcHRpbWl6YXIgcHJvY2Vzb3MgcHJvZHVjdGl2b3MsIGVzdGEgYmFzZSBkZXB1cmFkYSBjb25zZXJ2YSAxLDE5NyByZWdpc3Ryb3MgY29uIHZhcmlhYmxlcyBudW3DqXJpY2FzIHkgY2F0ZWfDs3JpY2FzIGVzdGFuZGFyaXphZGFzLiBJZGVhbCBwYXJhIGlkZW50aWZpY2FyIGN1ZWxsb3MgZGUgYm90ZWxsYSB5IG1lam9yZXMgcHLDoWN0aWNhcyBlbiBtYW51ZmFjdHVyYSB0ZXh0aWwuDQoNClVuYSB2ZXogY2FyZ2FkbyBlbCBjb25qdW50byBkZSBkYXRvcywgY29uIGxvcyBjb21hbmRvcyBoZWFkKCkgeSB0YWlsKCkgc2UgcHVlZGUgaGFjZXIgdW5hIGJyZXZlIGluc3BlY2Npw7NuIGRlbCBkYXRhc2V0DQoNCmBgYHtyfQ0KaGVhZChnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5LDEwKSAjVmVtb3MgbGFzIHByaW1lcmFzIDEwIGZpbGFzDQpgYGANCg0KYGBge3J9DQp0YWlsKGdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHkpICNWZW1vcyBsYXMgw7psdGltYXMgNiBmaWxhcw0KYGBgDQoNCioqKkRpY2Npb25hcmlvIGRlIHZhcmlhYmxlcyoqKlwNClVuYSBicmV2ZSBkZXNjcmlwY2nDs24gZGUgY2FkYSB1bmEgZGUgbGFzIHZhcmlhYmxlcyBlbiBlbCBkYXRhc2V0IHNlIHByZXNlbnRhIGEgY29udGludWFjacOzbjoNCg0KIyMjIyAqKlZhcmlhYmxlcyBkZSBJZGVudGlmaWNhY2nDs24geSBUZW1wb3JhbGlkYWQqKg0KDQotICAgKipkYXRlKio6IEZlY2hhIGRlIHJlZ2lzdHJvIGRlIGxvcyBkYXRvcyBlbiBmb3JtYXRvIE1NL0REL0FBQUEuDQoNCi0gICAqKnF1YXJ0ZXIqKjogVHJpbWVzdHJlIGRlbCBhw7FvIGFsIHF1ZSBwZXJ0ZW5lY2UgZWwgcmVnaXN0cm8gKFF1YXJ0ZXIxIGEgUXVhcnRlcjUpLg0KDQotICAgKipkYXkqKjogRMOtYSBkZSBsYSBzZW1hbmEgZW4gcXVlIHNlIHJlZ2lzdHJhcm9uIGxvcyBkYXRvcyAoTW9uZGF5LCBUdWVzZGF5LCBldGMuKS4NCg0KIyMjIyAqKlZhcmlhYmxlcyBPcmdhbml6YWNpb25hbGVzKioNCg0KLSAgICoqZGVwYXJ0bWVudCoqOiBEZXBhcnRhbWVudG8gZGUgdHJhYmFqbyAoc3dlaW5nL2Nvc3R1cmEgbyBmaW5pc2hpbmcvYWNhYmFkb3MpLg0KDQotICAgKip0ZWFtKio6IE7Dum1lcm8gaWRlbnRpZmljYWRvciBkZWwgZXF1aXBvIGRlIHRyYWJham8gKHZhbG9yZXMgZGVsIDEgYWwgMTIpLg0KDQotICAgKipub19vZl93b3JrZXJzKio6IE7Dum1lcm8gZGUgdHJhYmFqYWRvcmVzIGVuIGVsIGVxdWlwbyBlc2UgZMOtYS4NCg0KIyMjIyAqKlZhcmlhYmxlcyBkZSBQcm9kdWNjacOzbioqDQoNCi0gICAqKnRhcmdldGVkX3Byb2R1Y3Rpdml0eSoqOiBQcm9kdWN0aXZpZGFkIG9iamV0aXZvIGVzdGFibGVjaWRhIHBhcmEgZWwgZXF1aXBvICh2YWxvcmVzIGVudHJlIDAuMzUgeSAwLjgpLg0KDQotICAgKiphY3R1YWxfcHJvZHVjdGl2aXR5Kio6IFByb2R1Y3RpdmlkYWQgcmVhbCBhbGNhbnphZGEgcG9yIGVsIGVxdWlwbyAodmFsb3JlcyBlbnRyZSAwLjM0IHkgMS4xKS4NCg0KLSAgICoqc212Kio6IFN0YW5kYXJkIE1pbnV0ZSBWYWx1ZSAtIHRpZW1wbyBhc2lnbmFkbyBwYXJhIGNvbXBsZXRhciB1bmEgdGFyZWEgZXNwZWPDrWZpY2EuDQoNCi0gICAqKndpcCoqOiBXb3JrIGluIFByb2dyZXNzIC0gY2FudGlkYWQgZGUgdHJhYmFqbyBwZW5kaWVudGUgYWwgaW5pY2lvIGRlbCBkw61hIChwdWVkZSBlc3RhciB2YWPDrW8pLg0KDQotICAgKipvdmVyX3RpbWUqKjogSG9yYXMgZXh0cmFzIHRyYWJhamFkYXMgcG9yIGVsIGVxdWlwby4NCg0KLSAgICoqaW5jZW50aXZlKio6IEluY2VudGl2byBtb25ldGFyaW8gb3RvcmdhZG8gYWwgZXF1aXBvIChlbiB1bmlkYWRlcyBtb25ldGFyaWFzKS4NCg0KLSAgICoqbm9fb2Zfc3R5bGVfY2hhbmdlKio6IE7Dum1lcm8gZGUgY2FtYmlvcyBkZSBlc3RpbG8gcmVhbGl6YWRvcyBkdXJhbnRlIGVsIGTDrWEuDQoNCiMjIyMgKipWYXJpYWJsZXMgZGUgVGllbXBvIEluYWN0aXZvKioNCg0KLSAgICoqaWRsZV90aW1lKio6IFRpZW1wbyBkZSBpbmFjdGl2aWRhZCByZWdpc3RyYWRvIChlbiBtaW51dG9zKS4NCg0KLSAgICoqaWRsZV9tZW4qKjogTsO6bWVybyBkZSB0cmFiYWphZG9yZXMgcXVlIGVzdHV2aWVyb24gaW5hY3Rpdm9zIGR1cmFudGUgZWwgZMOtYQ0KDQojIyMjICoqT3BlcmFkb3IgcGlwZSoqDQoNCkxhIGxpYnJlcsOtYSBgdGlkeXZlcnNlYCBlcyB1biBtZXRhcGFxdWV0ZSBkaXNlw7FhZG8gcGFyYSB1bmEgw7NwdGltYSBtYW5pcHVsYWNpw7NuIGRlIGdyYW5kZXMgY29uanVudG9zIGRlIGRhdG9zLiBQcmltZXJvIGRlYmVtb3MgaW5zdGFsYXJsYQ0KDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpgYGANCg0KeSBsdWVnbyBjYXJnYXJsYQ0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCkVsIHBhcXVldGUgZnVuY2lvbmEgbWVkaWFudGUgZWwgb3BlcmFkb3LCoCpwaXBlKsKgYCU+JWDCoGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmENCg0KYGBge3J9DQpnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5ICU+JSBoZWFkKDEwKQ0KYGBgDQoNCiMjIyAqKlZhcmlhYmxlcyBFc3RhZMOtc3RpY2FzIGVuIGVsIERhdGFzZXQgZGUgUHJvZHVjdGl2aWRhZCBUZXh0aWwqKg0KDQpVbmEgKip2YXJpYWJsZSBlc3RhZMOtc3RpY2EqKiBlcyBjdWFscXVpZXIgY2FyYWN0ZXLDrXN0aWNhIG1lZGlkYSBlbiBlbCBlc3R1ZGlvIHF1ZSBwdWVkZSB2YXJpYXIgZW50cmUgcmVnaXN0cm9zLiBFbiBlc3RlIGRhdGFzZXQsIGxhcyB2YXJpYWJsZXMgc2UgY2xhc2lmaWNhbiBlbjoNCg0KIyMjIyAqKjEuIFZhcmlhYmxlcyBDdWFudGl0YXRpdmFzIChudW3DqXJpY2FzKSoqDQoNCi0gICAqKkRpc2NyZXRhcyoqOiBUb21hbiB2YWxvcmVzIGVudGVyb3MgZXNwZWPDrWZpY29zIChlajogKipgbm9fb2Zfd29ya2Vyc2AqKiwgKipgbm9fb2Zfc3R5bGVfY2hhbmdlYCoqKS4NCg0KLSAgICoqQ29udGludWFzKio6IFB1ZWRlbiB0b21hciBjdWFscXVpZXIgdmFsb3IgZW4gdW4gcmFuZ28gKGVqOiAqKmB0YXJnZXRlZF9wcm9kdWN0aXZpdHlgKiosICoqYGFjdHVhbF9wcm9kdWN0aXZpdHlgKiosICoqYHNtdmAqKiwgKipgb3Zlcl90aW1lYCoqLCAqKmBpbmNlbnRpdmVgKiopLg0KDQojIyMjICoqMi4gVmFyaWFibGVzIEN1YWxpdGF0aXZhcyAoY2F0ZWfDs3JpY2FzKSoqDQoNCi0gICAqKk5vbWluYWxlcyoqOiBTaW4gb3JkZW4gaW5oZXJlbnRlIChlajogKipgZGVwYXJ0bWVudGAqKiAtICJzd2VpbmciIG8gImZpbmlzaGluZyIsICoqYGRheWAqKiAtIGTDrWFzIGRlIGxhIHNlbWFuYSkuDQoNCi0gICAqKk9yZGluYWxlcyoqOiBDb24gdW4gb3JkZW4gbMOzZ2ljbyAoZWo6ICoqYHF1YXJ0ZXJgKiogLSBRdWFydGVyMSBhIFF1YXJ0ZXI1KS4NCg0KIyMjIyAqKk5vdGEgaW1wb3J0YW50ZSEqKg0KDQpBbGd1bmFzIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzIHB1ZWRlbiBjb252ZXJ0aXJzZSBlbiBjYXRlZ8OzcmljYXMgYWdydXBhbmRvIHJhbmdvcyAoZWo6IGNsYXNpZmljYXIgKipgYWN0dWFsX3Byb2R1Y3Rpdml0eWAqKiBlbiBiYWphLCBtZWRpYSBvIGFsdGEpLg0KDQojIyAqKlRpcG9zIGRlIHZhcmlhYmxlcyBlbiBSKioNCg0KVm9sdmllbmRvIGEgbG9zIGRhdG9zLCB2ZWFtb3Mgc3UgZXN0cnVjdHVyYSB5IGRpbWVuc2nDs246DQoNCmBgYHtyfQ0KZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSU+JSBzdHIoKSAjdmVhbW9zIHN1IGVzdHJ1Y3R1cmEgeSBkaW1lbnNpw7NuOg0KYGBgDQoNCmBgYHtyfQ0KZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSAlPiUgZGltKCkgI07Dum1lcm8gZGUgZmlsYXMgeSBuw7ptZXJvIGRlIGNvbHVtbmFzDQpgYGANCg0KRWwgY29uanVudG8gdGllbmUgbGEgaW5mb3JtYWNpw7NuIGRlIDExOTcgcGFjaWVudGVzIGRpdmlkaWRhIGVuIDE1IHZhcmlhYmxlcyBkZSBsYXMgY3VhbGVzIERlcGFydG1lbnQsIERhdGUgeSBkYXkgbm8gc29uIGVzY2FsYXJlcw0KDQpQYXJhIHF1ZSBsYXMgdmFyaWFibGVzIHRpcG8gKmNoYXJhY3Rlciogc2UgcHVlZGFuIHRyYXRhciBjb21vIHZhcmlhYmxlcyBjdWFsaXRhdGl2YXMgZXMgbmVjZXNhcmlvIGNvbnZlcnRpcmxhcyBlbiBmYWN0b3JlcyB5LCBwYXJhIGVsbG8sIHZlYW1vcyBwcmltZXJvIGxvcyBub21icmVzIGRlIGxhcyB2YXJpYWJsZXMNCg0KYGBge3J9DQpnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5ICU+JSBjb2xuYW1lcygpICN2ZWFtb3MgcHJpbWVybyBsb3Mgbm9tYnJlcyBkZSBsYXMgdmFyaWFibGVzDQpgYGANCg0KZGUgbWFuZXJhIG3DoXMgZWZpY2llbnRlIGNvbiBlbCBjb21hbmRvwqBgbGFwcGx5YCB2YW1vcyBhIGNvbnZlcnRpcmxhcyBlbiBmYWN0b3Jlcw0KDQpgYGB7cn0NCiBnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5WyxjKCJxdWFydGVyIiwgImRlcGFydG1lbnQiLCAiZGF5IiwgInRlYW0iLCAibm9fb2Zfc3R5bGVfY2hhbmdlIildIDwtIA0KICBsYXBwbHkoZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eVssYygicXVhcnRlciIsICJkZXBhcnRtZW50IiwgImRheSIsICJ0ZWFtIiwgIm5vX29mX3N0eWxlX2NoYW5nZSIpXSwgYXMuZmFjdG9yKQ0KDQpgYGANCg0KdmVhbW9zIGRlIG51ZXZvIGxhIGVzdHJ1Y3R1cmENCg0KYGBge3J9DQpnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5JT4lIHN0cigpDQpgYGANCg0KUGFyYSB2ZXIgbG9zIG5pdmVsZXMgZGUgdW5hIHZhcmlhYmxlIHRpcG8gZmFjdG9yIHNlIHVzYSBsYSBmdW5jacOzbsKgYGRpc3RpbmN0KClgLiBQb3IgZWplbXBsbywNCg0KYGBge3J9DQpnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5ICU+JSBkaXN0aW5jdChkYXkpDQpgYGANCg0KU2ksIGFkZW3DoXMsIHF1ZXJlbW9zIGNvbnRhciBjdcOhbnRvcyByZWdpc3Ryb3MgaGF5IGRlIGNhZGEgY2F0ZWdvcsOtYSwgcG9kZW1vcyB1c2FyIGxhIGZ1bmNpw7NuwqBgY291bnQoKWANCg0KYGBge3J9DQpnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5ICU+JSBjb3VudChkZXBhcnRtZW50KQ0KYGBgDQoNCiMjICoqRXN0YWTDrXN0aWNhIGRlc2NyaXB0aXZhICh2YXJpYWJsZXMgZXNjYWxhcmVzKSoqDQoNClVuIGVzdGFkw61ncmFmbyBlcyB1bmEgbWVkaWRhIG51bcOpcmljYSBxdWUgc2UgY2FsY3VsYSBzb2JyZSB1biBjb25qdW50byBkZSBkYXRvcyB5IHNpcnZlIHBhcmEgcmVzdW1pciBsYSBpbmZvcm1hY2nDs24gY29udGVuaWRhIGVuIGVsIG1pc21vLiBIYXkgY3VhdHJvIGNsYXNlcyBkZSBlc3RhZMOtZ3JhZm9zOiAqdGVuZGVuY2lhIGNlbnRyYWwqLCAqcG9zaWNpw7NuKiwgKmRpc3BlcnNpw7NuKiB5ICpmb3JtYSouDQoNCjEuICAqKlRlbmRlbmNpYSBjZW50cmFsKiogRGVzY3JpYmVuIGxhIGZvcm1hIGVuIGxhIHF1ZSBsb3MgZGF0b3Mgc2UgYWdydXBhbiBoYWNpYSBlbCBjZW50cm8gZGUgbGEgZGlzdHJpYnVjacOzbi4gTGFzIG3DoXMgaW1wb3J0YW50ZXMgc29uOiBtZWRpYSwgbWVkaWFuYSB5IG1vZGEuXA0KICAgIEFsZ3VuYXMgb2JzZXJ2YWNpb25lczoNCg0KICAgIC0gICBTb2JyZSBsYSBtZWRpYToNCg0KICAgICAgICAtICAgTGEgbWVkaWEgZXMgw7puaWNhIHBhcmEgY3VhbHF1aWVyIGNvbmp1bnRvIGRlIGRhdG9zIHkgdGllbmUgbGEgbWlzbWEgdW5pZGFkIGRlIG1lZGlkYSBkZSBlc3Rvcy4gRXMgY29ub2NpZGEgY29tw7pubWVudGUgY29tbyBlbCBwcm9tZWRpby4NCg0KICAgICAgICAtICAgTm8gbmVjZXNhcmlhbWVudGUgZXMgdW5vIGRlIGxvcyB2YWxvcmVzIGRlbCBjb25qdW50by4NCg0KICAgICAgICAtICAgRXMgbXV5IHNlbnNpYmxlIGEgZGF0b3MgYXTDrXBpY29zICh2YWxvcmVzIGV4dGVtb3MpLg0KDQogICAgLSAgIEFsIG9yZGVuYXIgbG9zIGRhdG9zLCBsYSBtZWRpYW5hIGVzIGVsIHZhbG9yIHViaWNhZG8gZW4gbGEgcG9zaWNpw7NuIGNlbnRyYWwuIEVzIGRlY2lyLCBlcyBlbCBkYXRvIHF1ZSBkZWphIGVsIDUwJSBkZSBsb3MgZGF0b3MgcG9yIGVuY2ltYSB5IDUwJSBwb3IgZGViYWpvLg0KDQogICAgICAgIC0gICBObyBlcyBzdXNjZXB0aWJsZSBhbnRlIGxhIHByZXNlbmNpYSBkZSB2YWxvcmVzIGV4dHJlbW9zLiAoTWVkaWRhIHJvYnVzdGEpLg0KDQogICAgICAgIC0gICBMYSBtZWRpYW5hIHNpZW1wcmUgZXMgw7puaWNhLg0KDQogICAgICAgIC0gICBQdWVkZSBvIG5vIHNlciB1biB2YWxvciBkZW50cm8gZGVsIGNvbmp1bnRvIGRlIGRhdG9zLg0KDQogICAgLSAgIExhIG1vZGEgY29ycmVzcG9uZGUgYWwgZGF0byBjb24gbWF5b3IgZnJlY3VlbmNpYSBhYnNvbHV0YSAoZWwgcXVlIG3DoXMgc2UgcmVwaXRlKS4gTm8gbmVjZXNhcmlhbWVudGUgZXMgw7puaWNhLiBTaSB1biBjb25qdW50byBkZSBkYXRvcyB0aWVuZSB1bmEgw7puaWNhIG1vZGEgZW50b25jZXMgc2UgZGVub21pbmEgdW5pbW9kYWwuIFNpIGxhIG1vZGEgc2UgYWxjYW56YSBlbiBkb3MgdmFsb3JlcyBkaWZlcmVudGVzLCBlbCBjb25qdW50byByZWNpYmUgZWwgbm9tYnJlIGRlIGJpbW9kYWwuIFNpIGhheSAzIG8gbcOhcyBtb2RhcywgbG9zIGRhdG9zIHNlIHJlZmVyZW5jaWFuIGNvbW8gbXVsdGltb2RhbGVzLg0KDQogICAgICAgIC0gICBObyBlcyB1bmEgbWVkaWRhIGRlIHRlbmRlbmNpYSBjZW50cmFsIGRlIMO6bmljbyB2YWxvci4NCg0KICAgICAgICAtICAgTm8gc2UgYWZlY3RhIHBvciB2YWxvcmVzIGV4dHJlbW9zLg0KDQogICAgICAgIC0gICBTaWVtcHJlIGVzIHVuIHZhbG9yIGRlbCBjb25qdW50byBkZSBkYXRvcy4NCg0KICAgIExhcyBmdW5jaW9uZXMgYG1lYW4oKWAsIGBtZWRpYW4oKWAgeSBgbWZ2KClgIGRlIFIgcmVhbGl6YW4gZXN0b3MgY8OhbGN1bG9zLiBQYXJhIHVzYXIgZWwgY29tYW5kbyBkZSBsYSBtb2RhIGVzIG5lY2VzYXJpbyBpbnN0YWxhciBlbCBwYXF1ZXRlICptb2RlZXN0Kg0KDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoIm1vZGVlc3QiKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShtb2RlZXN0KQ0KYGBgDQoNCmBgYHtyfQ0KbWVhbihnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5JGFjdHVhbF9wcm9kdWN0aXZpdHkpDQpgYGANCg0KYGBge3J9DQptZWRpYW4oZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSRhY3R1YWxfcHJvZHVjdGl2aXR5KQ0KYGBgDQoNCmBgYHtyfQ0KbWVhbihnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5JGFjdHVhbF9wcm9kdWN0aXZpdHksIHRyaW0gPSAwLjIpDQpgYGANCg0KKipBbsOhbGlzaXMgZGUgUHJvZHVjdGl2aWRhZCBlbiBsYSBJbmR1c3RyaWEgVGV4dGlsKioNCg0KRW4gZWwgc2VjdG9yIGRlIGNvbmZlY2Npb25lcywgbGEgcHJvZHVjdGl2aWRhZCByZWFsIHByb21lZGlvICgqWMyEKikgYWxjYW56YSAqKjAuNzIqKiAoc29icmUgdW4gbcOheGltbyBkZSAxLjApLCBzaWVuZG8gKiowLjgwKiogZWwgdmFsb3IgbcOhcyBmcmVjdWVudGUgKE1vZGEpIHkgKiowLjc1KiogbGEgbWVkaWFuYSAoKk1lKikuIFBhcmEgcmVkdWNpciBlbCBlZmVjdG8gZGUgdmFsb3JlcyBleHRyZW1vcywgbGEgbWVkaWEgcmVjb3J0YWRhIGFsIDIwJSBlcyBkZSAqKjAuNzMqKiwgbG8gcXVlIGluZGljYSB1bmEgZGlzdHJpYnVjacOzbiBsaWdlcmFtZW50ZSBhc2ltw6l0cmljYSBoYWNpYSB2YWxvcmVzIGJham9zLg0KDQoqKk5vdGFjacOzbiBlc3RhZMOtc3RpY2E6KioNCg0KLSAgICpYzIQqOiBNZWRpYSBtdWVzdHJhbCAodXNhZGEgYXF1w60sIHB1ZXMgbG9zIGRhdG9zIHJlcHJlc2VudGFuIHVuYSBtdWVzdHJhIGRlIHByb2R1Y2Npw7NuKQ0KDQotICAgKs68KjogTWVkaWEgcG9ibGFjaW9uYWwgKG5vIGFwbGljYSBlbiBlc3RlIGNhc28pDQoNCjIuICAqKlBvc2ljacOzbioqwqBEaXZpZGVuIHVuYSBkaXN0cmlidWNpw7NuIGRlIGZyZWN1ZW5jaWFzIG8gY29uanVudG8gZGUgZGF0b3MgZW4gcGFydGVzIGlndWFsZXMgKGVuIHTDqXJtaW5vcyBkZSBwcm9wb3JjacOzbiBjb250ZW5pZGEgZW4gY2FkYSBwYXJ0ZSkuIEFkZW3DoXMgcGVybWl0ZW4gbG9jYWxpemFyIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zIHNvYnJlIGVsIGVqZSBob3Jpem9udGFsLg0KDQp5IHNlIGNhbGN1bGFuIGNvbiBsYSBmdW5jacOzbsKgYHF1YW50aWxlKClgwqBxdWUsIGFkZW3DoXMsIHByb3BvcmNpb25hIGxvcyB2YWxvcmVzIG3DrW5pbW8geSBtw6F4aW1vIGRlbCBjb25qdW50by4NCg0KYGBge3J9DQpxdWFudGlsZShnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5JG5vX29mX3dvcmtlcnMpICNwcm9wb3JjaW9uYSBsb3MgdmFsb3JlcyBtw61uaW1vIHkgbcOheGltbyBkZWwgY29uanVudG8uDQpgYGANCg0KRWwgYW7DoWxpc2lzIGRlIGN1YXJ0aWxlcyByZXZlbGEgcXVlIGVsIDI1JSBkZSBsb3MgZXF1aXBvcyBkZSBwcm9kdWNjacOzbiB0ZXh0aWxlcyBvcGVyYW4gY29uwqAqKjIzIHRyYWJhamFkb3JlcyBvIG1lbm9zKiosIG1pZW50cmFzIHF1ZSBsb3MgZXF1aXBvcyBjb27CoCoqbcOhcyBkZSAzMSB0cmFiYWphZG9yZXMqKsKgcGVydGVuZWNlbiBhbCBjdWFydGlsIHN1cGVyaW9yICgyNSUgZGUgZXF1aXBvcyBtw6FzIGdyYW5kZXMpLiBFc3RvIGluZGljYSB1bmEgZGlzdHJpYnVjacOzbiBoZXRlcm9nw6luZWEgZW4gZWwgdGFtYcOxbyBkZSBsb3MgZXF1aXBvcywgZG9uZGUgbGEgbWF5b3LDrWEgKDUwJSBjZW50cmFsKSB0cmFiYWphIGNvbiBlbnRyZSAyNCB5IDMxIG9wZXJhcmlvcy4NCg0KYGBge3J9DQpxdWFudGlsZShnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5JG5vX29mX3dvcmtlcnMsIGMoMC4xLDAuMjYsMC43OCkpDQpgYGANCg0KRWwgY29tYW5kb8KgYHN1bW1hcnkoKWDCoGNhbGN1bGEgc2ltdWx0w6FuZWFtZW50ZSBsYSBtZWRpYSwgbG9zIGN1YXJ0aWxlcywgZWwgbcOheGltbyB5IGVsIG3DrW5pbW8gZGUgbGFzIHZhcmlhYmxlcyBlc2NhbGFyZXMgeSBsYSBmcmVjdWVuY2lhIHBvciBjYXRlZ29yw61hIGRlIGxhcyB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzDQoNCmBgYHtyfQ0KZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSAlPiUgc2VsZWN0KHRlYW0pICU+JSBzdW1tYXJ5KCkgI2NhbGN1bGEgc2ltdWx0w6FuZWFtZW50ZSBsYSBtZWRpYSwgbG9zIGN1YXJ0aWxlcywgZWwgbcOheGltbyB5IGVsIG3DrW5pbW8gZGUgbGFzIHZhcmlhYmxlcyBlc2NhbGFyZXMgeSBsYSBmcmVjdWVuY2lhIHBvciBjYXRlZ29yw61hIGRlIGxhcyB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzDQpgYGANCg0KYGBge3J9DQpnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5ICU+JSBzZWxlY3Qod2lwKSAlPiUgc3VtbWFyeSgpDQpgYGANCg0KUHVlZGUgYXBsaWNhcnNlIGFsIGNvbmp1bnRvIGNvbXBsZXRvIHkgc2Ugb2J0aWVuZSBlbCByZXN1bWVuIGRlIHRvZGFzIGxhcyBjb2x1bW5hcw0KDQpgYGB7cn0NCmdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHkgJT4lIHN1bW1hcnkoKSAjc2Ugb2J0aWVuZSBlbCByZXN1bWVuIGRlIHRvZGFzIGxhcyBjb2x1bW5hcw0KYGBgDQoNCioqTm90YSoqwqBBbCBjb21lbnphciBsYSBleHBsb3JhY2nDs24gZGUgdW4gY29uanVudG8gZGUgZGF0b3MsIHVubyBkZSBsb3MgcHJpbWVyb3MgcGFzb3MgZXMgcmVhbGl6YXIgeSBhbmFsaXphciBlbCByZXN1bWVuIGRlIHZhcmlhYmxlcyBwYXJhIGRldGVjdGFyIHByb2JsZW1hcyBkZSBjYWxpZGFkIHkgdHJhdGFybG9zIGFudGVzIGRlIGhhY2VyIGPDoWxjdWxvcyBtw6FzIGVzcGVjw61maWNvcy4NCg0KMy4gICoqRGlzcGVyc2nDs24qKiBDdWFudGlmaWNhbiBsYSB2YXJpYWJpbGlkYWQgZGUgbG9zIGRhdG9zIHkgZGV0ZXJtaW5hbiBxdcOpIHRhbiBhbGVqYWRhIGVzdMOhIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zIGNvbiByZXNwZWN0byBhIHVuIHB1bnRvIGRlIHJlZmVyZW5jaWEgY29tbywgcG9yIGVqZW1wbG8sIGxhIG1lZGlhLg0KDQotICAgKipSYW5nbyoqIEVzIGxhIGRpZmVyZW5jaWEgZW50cmUgZWwgbcOheGltbyB5IGVsIG3DrW5pbW8gZGUgbG9zIGRhdG9zIHkgY3VhbnRpZmljYSBsYSBleHRlbnNpw7NuIHRvdGFsIGRlbCBjb25qdW50by4gRW4gUiwgbGEgZnVuY2nDs24gYHJhbmdlKClgIGRhIGxvcyB2YWxvcmVzIGRlbCBtw6F4aW1vIHkgZGVsIG3DrW5pbW8NCg0KICAgIFJhbmdvPW1heOKIkm1pbg0KDQpgYGB7cn0NCnJhbmdlKGdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHkkdGVhbSkNCmBgYA0KDQotICAgKipSYW5nbyBpbnRlcmN1YXJ0w61saWNvKiogU2UgZGVmaW5lIGNvbW8gZWwgZXNwYWNpbyBxdWUgb2N1cGEgZWwgNTAlIGNlbnRyYWwgZGUgbGEgZGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MgeSBzZSBjYWxjdWxhIGNvbW8NCg0KICAgIElRUj1SSUM9UTPiiJJRMUlRUj1SSUM9UTPiiJJRMQ0KDQogICAgRXMgdW5hIG1lZGlkYSByb2J1c3RhIGFudGUgbGEgcHJlc2VuY2lhIGRlIGRhdG9zIGF0w61waWNvcyB5IHN1ZWxlIGVtcGxlYXJzZSBjb21vIG1lZGlkYSBkZSBkaXNwZXJzacOzbiBjdWFuZG8gbGEgbWVkaWRhIGRlIHRlbmRlbmNpYSBjZW50cmFsIGVzY29naWRhIGVzIGxhIG1lZGlhbmEuDQoNCmBgYHtyfQ0KSVFSKGdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHkkdGVhbSkNCmBgYA0KDQplc3RvIG5vcyBtdWVzdHJhICoqbGEgRGlzdHJpYnVjacOzbiBkZSBlcXVpcG9zKio6IEVsIDUwJSBjZW50cmFsIGRlIGxvcyBlcXVpcG9zIGRlIHByb2R1Y2Npw7NuIChlbnRyZSBlbCBRMSB5IFEzKSBlc3TDoSBkaXN0cmlidWlkbyBlbiB1biByYW5nbyBkZSAqKjYgZXF1aXBvcyBudW3DqXJpY29zKiogKGVqOiBzaSBRMT1FcXVpcG8zIHkgUTM9RXF1aXBvOSwgbGEgZGlmZXJlbmNpYSBlcyA2KS4NCg0KYGBge3J9DQp2YXIoZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSRub19vZl93b3JrZXJzKQ0KYGBgDQoNCkxhIHZhcmlhbnphIGRlIDQ5Mi43MzczIGVuIGVsIG7Dum1lcm8gZGUgdHJhYmFqYWRvcmVzIHBvciBlcXVpcG8gaW5kaWNhIHVuYSBhbHRhIHZhcmlhYmlsaWRhZCBlbiBsb3MgdGFtYcOxb3MgZGUgbG9zIGVxdWlwb3MgZGUgcHJvZHVjY2nDs24uIEVzdG8gc2lnbmlmaWNhIHF1ZSBsYSBjYW50aWRhZCBkZSB0cmFiYWphZG9yZXMgZGlmaWVyZSBzaWduaWZpY2F0aXZhbWVudGUgZW50cmUgZXF1aXBvcywgY29uIHVuYSBkZXN2aWFjacOzbiB0w61waWNhIGRlIGFwcm94aW1hZGFtZW50ZSDCsTIyIHRyYWJhamFkb3JlcyByZXNwZWN0byBhbCBwcm9tZWRpby4NCg0KYGBge3J9DQpzZChnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5JGFjdHVhbF9wcm9kdWN0aXZpdHkpDQpgYGANCg0KTGEgZGVzdmlhY2nDs24gZXN0w6FuZGFyIGRlIDAuMTc0IGVuIGxhIHByb2R1Y3RpdmlkYWQgcmVhbCAoYWN0dWFsX3Byb2R1Y3Rpdml0eSkgbXVlc3RyYSBxdWUgbG9zIGVxdWlwb3MgdGV4dGlsZXMgb3BlcmFuIGNvbiB1bmEgY29uc2lzdGVuY2lhIG5vdGFibGUuIEVzdG8gc2lnbmlmaWNhIHF1ZSBsYSBtYXlvcsOtYSBkZSBsb3MgZXF1aXBvcyAoYWxyZWRlZG9yIGRlbCA2OCUpIG1hbnRpZW5lbiBuaXZlbGVzIGRlIHByb2R1Y3RpdmlkYWQgZW50cmUgMC41NSB5IDAuODkgY3VhbmRvIGNvbnNpZGVyYW1vcyBlbCBwcm9tZWRpbyBkZSAwLjcyLg0KDQpgYGB7cn0NCiBza2V3KGdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHkkbm9fb2Zfd29ya2VycykNCmBgYA0KDQpFbCBzZXNnbyBkZSAtMC4xMSBlbiBlbCBuw7ptZXJvIGRlIHRyYWJhamFkb3JlcyBwb3IgZXF1aXBvIGluZGljYSB1bmEgZGlzdHJpYnVjacOzbiBjYXNpIHNpbcOpdHJpY2EsIGNvbiB1bmEgbGlnZXJhIHRlbmRlbmNpYSBhIHRlbmVyIG3DoXMgZXF1aXBvcyBncmFuZGVzIHF1ZSBwZXF1ZcOxb3MuIEVzdG8gbXVlc3RyYSBxdWUgbGEgYXNpZ25hY2nDs24gZGUgcGVyc29uYWwgZXMgYmFzdGFudGUgZXF1aWxpYnJhZGEgZW4gbGEgZsOhYnJpY2EsIHNpbiBlcXVpcG9zIGV4dHJlbW9zIHF1ZSBkaXN0b3JzaW9uZW4gbGEgZGlzdHJpYnVjacOzbi4gRWwgdmFsb3IgY2VyY2FubyBhIGNlcm8gcGVybWl0ZSBhbmFsaXphciBlc3RvcyBkYXRvcyBzaW4gbmVjZXNpZGFkIGRlIGFqdXN0ZXMgZXN0YWTDrXN0aWNvcyBjb21wbGVqb3MuDQoNCmBgYHtyfQ0KIGt1cnRvc2koZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSR0ZWFtKQ0KYGBgDQoNCkxhIGZ1bmNpw7NuwqBgZGVzY3JpYmUoKWDCoGRlbCBwYXF1ZXRlwqBgcHN5Y2hgwqBoYWNlIHVuIHJlc3VtZW4gZGVzY3JpcHRpdm8gbcOhcyBhbXBsaW8gZGUgdW5hIHZhcmlhYmxlIGVzY2FsYXI6DQoNCmBgYHtyfQ0KZGVzY3JpYmUoZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSR0ZWFtLCBJUVI9VFJVRSwgcXVhbnQgPSBjKC4yNSwgLjUsIC43NSkpIA0KYGBgDQoNCiMjICoqR3LDoWZpY29zIGRlc2NyaXB0aXZvcyAodmFyaWFibGVzIGVzY2FsYXJlcykqKg0KDQoqKkRpc3RyaWJ1Y2nDs24gZGUgZnJlY3VlbmNpYXMuKiogRXMgbGEgYWdydXBhY2nDs24gZGUgZGF0b3MgZW4gY2F0ZWdvcsOtYXMgbXV0dWFtZW50ZSBleGNsdXllbnRlcyBxdWUgaW5kaWNhIGVsIG7Dum1lcm8gZGUgb2JzZXJ2YWNpb25lcyBlbiBjYWRhIGNhdGVnb3LDrWEgbyBjbGFzZS4gQ29uc3RydWlyIGxhIHRhYmxhIGRlIGZyZWN1ZW5jaWFzIHJlcXVpZXJlIGxhIGZ1bmNpw7NuIGBmZHQoKWAgZGVsIHBhcXVldGUgYGZkdGhgDQoNCmBgYHtyfQ0KIGluc3RhbGwucGFja2FnZXMoImZkdGgiKQ0KYGBgDQoNCmBgYHtyfQ0KIGxpYnJhcnkoZmR0aCkNCmBgYA0KDQpgYGB7cn0NClRhYmxhX2ZyZWMgPC0gZmR0KGdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHkkYWN0dWFsX3Byb2R1Y3Rpdml0eSwgYnJlYWtzID0gIlN0dXJnZXMiKSAjU2UgZW1wbGVhIGVsIG3DqXRvZG8gZGUgU3R1cmdlcyBwYXJhIGNhbGN1bGFyIGxhIGNhbnRpZGFkIGRlIGNsYXNlcyAoYmlucykNCiAgVGFibGFfZnJlYw0KYGBgDQoNCjEuICAqKkhpc3RvZ3JhbWEqKsKgZXMgdW5hIHJlcHJlc2VudGFjacOzbiBncsOhZmljYSBkZSBsYSBkaXN0cmlidWNpw7NuIGRlIGZyZWN1ZW5jaWFzIGRlIHVuYSB2YXJpYWJsZSBlbiBsYSBxdWUgc2Ugb2JzZXJ2YW4gY29tcG9ydGFtaWVudG9zIGRlIGZvcm1hLCBkaXNwZXJzacOzbiB5IHRlbmRlbmNpYSBjZW50cmFsLlwNCiAgICBFbiBlbCBwYXF1ZXRlIGLDoXNpY28gcXVlIHRyYWUgUiBlc3TDoSBsYSBmdW5jacOzbsKgYGhpc3QoKWDCoHF1ZSBwZXJtaXRlIHRyYXphciBlbCBoaXN0b2dyYW1hIGRlbCBjb25qdW50byBkZSBkYXRvczsgc2luIGVtYmFyZ28sIGFxdcOtIHZhbW9zIGEgdXNhciBlbCBlbnRvcm5vIGdyw6FmaWNvIGRlIFIgcXVlIHByb3ZlZSBlbCBwYXF1ZXRlwqBgZ2dwbG90MmDCoGluY2x1aWRvIGVuwqBgdGlkeXZlcnNlYA0KDQpgYGB7cn0NCmdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHkgICU+JSBnZ3Bsb3QoYWVzKHggPSBhY3R1YWxfcHJvZHVjdGl2aXR5KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiNGRjlBQTIiLCBjb2xvciA9ICIjRkZEQUMxIiwgYmlucyA9IDMwKSArDQogIGdndGl0bGUoIkhpc3RvZ3JhbWEgZGUgUHJvZHVjdGl2aWRhZCBSZWFsIikgKw0KICBsYWJzKHggPSAiUHJvZHVjdGl2aWRhZCBSZWFsIiwgeSA9ICJGcmVjdWVuY2lhIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHksIGFlcyh4ID0gbm9fb2Zfd29ya2VycywgeSA9IC4uZGVuc2l0eS4uKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiNCNUVBRDciLCAgIyBWZXJkZSBtZW50YQ0KICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgIGJpbnMgPSAxNSkgKw0KICBnZW9tX2xpbmUoYWVzKHggPSBub19vZl93b3JrZXJzLA0KICAgICAgICAgICAgICAgIHkgPSBkbm9ybShub19vZl93b3JrZXJzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbihub19vZl93b3JrZXJzLCBuYS5ybSA9IFRSVUUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2Qobm9fb2Zfd29ya2VycywgbmEucm0gPSBUUlVFKSkpLA0KICAgICAgICAgICAgY29sb3IgPSAiIzgzMzhFQyIsICAgICAgIyBQw7pycHVyYQ0KICAgICAgICAgICAgbGluZXdpZHRoID0gMS4yKSArDQogIGdndGl0bGUoIkRpc3RyaWJ1Y2nDs24gZGVsIE7Dum1lcm8gZGUgVHJhYmFqYWRvcmVzIikgKw0KICBsYWJzKHggPSAiTsO6bWVybyBkZSB0cmFiYWphZG9yZXMiLCB5ID0gIkRlbnNpZGFkIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpFc3RlIGdyw6FmaWNvIG11ZXN0cmEgbGEgZGlzdHJpYnVjacOzbiBkZWwgbsO6bWVybyBkZSB0cmFiYWphZG9yZXMgcG9yIGVxdWlwbyBtZWRpYW50ZSB1biBoaXN0b2dyYW1hIGF6dWwgY2xhcm8gc3VwZXJwdWVzdG8gY29uIHVuYSBjdXJ2YSBub3JtYWwgbW9yYWRhLiBDb21wYXJhIGxvcyBkYXRvcyByZWFsZXMgY29uIHVuYSBkaXN0cmlidWNpw7NuIHRlw7NyaWNhIG5vcm1hbCwgdXNhbmRvIGxhIG1lZGlhIHkgZGVzdmlhY2nDs24gZXN0w6FuZGFyIHJlYWxlcy4NCg0KYGBge3J9DQpnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5ICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBhY3R1YWxfcHJvZHVjdGl2aXR5LCB5ID0gLi5kZW5zaXR5Li4pKSArDQogIGdlb21faGlzdG9ncmFtKA0KICAgIGZpbGwgPSAiIzREQjhENSIsDQogICAgY29sb3IgPSAiYmxhY2siLA0KICAgIGJpbnMgPSAxNSwNCiAgICBhbHBoYSA9IDAuNw0KICApICsNCiAgZ2VvbV9saW5lKA0KICAgIGFlcygNCiAgICAgIHggPSBhY3R1YWxfcHJvZHVjdGl2aXR5LA0KICAgICAgeSA9IGRub3JtKGFjdHVhbF9wcm9kdWN0aXZpdHksDQogICAgICAgICAgICAgICAgbWVhbihhY3R1YWxfcHJvZHVjdGl2aXR5LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgIHNkKGFjdHVhbF9wcm9kdWN0aXZpdHksIG5hLnJtID0gVFJVRSkpDQogICAgKSwNCiAgICBjb2xvciA9ICIjRTc0QzNDIiwNCiAgICBsaW5ld2lkdGggPSAxLjINCiAgKSArDQogIGdndGl0bGUoIkRpc3RyaWJ1Y2nDs24gZGUgUHJvZHVjdGl2aWRhZCBwb3IgRGVwYXJ0YW1lbnRvIikgKw0KICBsYWJzKHggPSAiUHJvZHVjdGl2aWRhZCBSZWFsIiwgeSA9ICJEZW5zaWRhZCIpICsNCiAgZmFjZXRfd3JhcCh+ZGVwYXJ0bWVudCkgKyAgIyBkZXBhcnRtZW50IGVzIGNhdGVnw7NyaWNvLCBwZXJvIGVsIGVqZSBYIGVzIG51bcOpcmljbw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpFc3RlIGdyw6FmaWNvIGRlIGRlbnNpZGFkIGNvbXBhcmEgbGEgZGlzdHJpYnVjacOzbiBkZSBsYSBwcm9kdWN0aXZpZGFkIHJlYWwgZW50cmUgbG9zIGRlcGFydGFtZW50b3MgZGUgcHJvZHVjY2nDs24gdGV4dGlsIG1lZGlhbnRlIGhpc3RvZ3JhbWFzIHkgY3VydmFzIG5vcm1hbGVzLiBDYWRhIHBhbmVsIG11ZXN0cmEgdW4gZGVwYXJ0YW1lbnRvIGRpZmVyZW50ZSwgZG9uZGUgbGFzIGJhcnJhcyBhenVsZXMgdHJhbnNwYXJlbnRlcyByZXByZXNlbnRhbiBsYSBmcmVjdWVuY2lhIHJlYWwgZGUgbG9zIG5pdmVsZXMgZGUgcHJvZHVjdGl2aWRhZCwgYWdydXBhZG9zIGVuIDE1IGludGVydmFsb3MsIG1pZW50cmFzIHF1ZSBsYSBsw61uZWEgcm9qYSB0cmF6YSBsYSBjdXJ2YSBkZSBkaXN0cmlidWNpw7NuIG5vcm1hbCB0ZcOzcmljYSBjYWxjdWxhZGEgYSBwYXJ0aXIgZGUgbGEgbWVkaWEgeSBkZXN2aWFjacOzbiBlc3TDoW5kYXIgZGUgY2FkYSBkZXBhcnRhbWVudG8uwqANCg0KYGBge3J9DQpkaWFncmFtYV9wcm9kdWN0aXZpZGFkIDwtIGJveHBsb3QoZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSRhY3R1YWxfcHJvZHVjdGl2aXR5LCBob3Jpem9udGFsID0gVFJVRSkNCmBgYA0KDQpFbCBlc3BhY2lvIGVudHJlIGxhIG1lZGlhbmEgKGzDrW5lYSBncnVlc2EgZGVudHJvIGRlIGxhIGNhamEpIHkgZWwgbcOtbmltbyBlcyBtw6FzIHBlcXVlw7FvIHF1ZSBlbnRyZSBsYSBtZWRpYW5hIHkgZWwgbcOheGltbzsgZXMgZGVjaXIsIGVsIHByaW1lciA1MCUgZGUgbG9zIGRhdG9zIGVzIG1lbm9zIGRpc3BlcnNvIChtw6FzIGFncnVwYWRvKSBxdWUgZWwgc2VndW5kby4gRGVudHJvIGRlIGxhIGNhamEsIGxhIGRpdmlzacOzbiBlc3TDoSBtw6FzIGNlcmNhIGRlbCBib3JkZSBpbmZlcmlvciAoY3VhcnRpbCAxKSBxdWUgZGVsIHN1cGVyaW9yIChjdWFydGlsIDMpIHksIHBvciB0YW50bywgc2UgY29uY2x1eWUgcXVlIGVsIHByaW1lciAyNSUgY2VudHJhbCBkZSBsb3MgZGF0b3MgZXMgbWVub3MgZGlzcGVyc28gcXVlIGVsIHNlZ3VuZG8gMjUlIGNlbnRyYWwuIEFkZW3DoXMsIGVzIGNsYXJvIHF1ZSBsYSBjb2xhIGRlcmVjaGEgKHN1cGVyaW9yKSBlcyBtw6FzIGxhcmdhIHF1ZSBsYSBpenF1aWVyZGEgKGluZmVyaW9yKSBkZSBkb25kZSBzZSBpbmZpZXJlIHF1ZSBsb3MgZGF0b3MgdGllbmVuIGFzaW1ldHLDrWEgcG9zaXRpdmEuXA0KUG9yIG90cm8gbGFkbywgZW4gbGEgY29sYSBkZXJlY2hhIGhheSBwcmVzZW5jaWEgZGUgZGF0b3MgYXTDrXBpY29zIChzb24gYm9saXRhcykgeSBwYXJhIGluc3BlY2Npb25hcmxvcyBlcyBuZWNlc2FyaW8gZXhwbG9yYXIgZWwgZWxlbWVudG8gZW4gZWwgcXVlIHNlIGd1YXJkw7MgZWwgYm94cGxvdCBjb24gZWwgc8OtbWJvbG/CoGAkYA0KDQpgYGB7cn0NCmhlYWQoZGlhZ3JhbWFfcHJvZHVjdGl2aWRhZCRvdXQsIDIwKQ0KYGBgDQoNCmBgYHtyfQ0KZGlhZ3JhbWFfcHJvZHVjdGl2aWRhZCRzdGF0cw0KYGBgDQoNCkNvbiBsYSBmdW5jacOzbsKgYGxlbmd0aCgpYMKgZXMgcG9zaWJsZSBjb250YXIgbGEgY2FudGlkYWQgZGUgb3V0bGllcnMgZGV0ZWN0YWRvcw0KDQpgYGB7cn0NCmxlbmd0aChkaWFncmFtYV9wcm9kdWN0aXZpZGFkJG91dCkNCmBgYA0KDQojIyAqKkVzdGFkw61zdGljYSBkZXNjcmlwdGl2YSAodmFyaWFibGVzIGN1YWxpdGF0aXZhcykqKg0KDQpFbiBlbCBjYXNvIGN1YWxpdGF0aXZvIGxhIGNhbnRpZGFkIGRlIGPDoWxjdWxvcyBxdWUgc2UgcHVlZGVuIGhhY2VyIHNlIHJlZHVjZSBhIGhhbGxhciBsYXMgZnJlY3VlbmNpYXMgYWJzb2x1dGFzIHkgcmVsYXRpdmFzIGRlIGxhcyBjYXRlZ29yw61hcyBkZSBsYSB2YXJpYWJsZS4gUGFyYSBjb25zdHJ1aXIgbGEgdGFibGEgZGUgZnJlY3VlbmNpYXMgc2UgZW1wbGVhIGxhIGZ1bmNpw7NuIGB0YWJsZSgpYCBkZWwgcGFxdWV0ZSBiw6FzaWNvIGRlIFIuDQoNCmBgYHtyfQ0KVGFibGFfRGVwYXJ0YW1lbnRvIDwtIHRhYmxlKGdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHkkZGVwYXJ0bWVudCkNClRhYmxhX0RlcGFydGFtZW50bw0KYGBgDQoNCkVsIGRlcGFydGFtZW50byBkZSAiZmluaXNoaW5nIiAoYWNhYmFkb3MpIGFwYXJlY2UgcmVnaXN0cmFkbyAyNDkgdmVjZXMsIG1pZW50cmFzIHF1ZSBoYXkgMjU3IHJlZ2lzdHJvcyBwYXJhICJmaW5pc2hpbmciIChwb3NpYmxlbWVudGUgY29uIHVuIGVzcGFjaW8gYWRpY2lvbmFsKSB5IDY5MSBwYXJhICJzd2VpbmciIChjb3N0dXJhKS4gRXN0byByZXZlbGEgdW5hIGRpc3RyaWJ1Y2nDs24gZGVzaWd1YWwsIGRvbmRlIGVsIMOhcmVhIGRlIGNvc3R1cmEgdGllbmUgY2FzaSBlbCB0cmlwbGUgZGUgZXF1aXBvcyBxdWUgY2FkYSB2ZXJzacOzbiBkZWwgZGVwYXJ0YW1lbnRvIGRlIGFjYWJhZG9zLg0KDQpQYXJhIGNvbnN0cnVpciBsYSB0YWJsYSBkZSBmcmVjdWVuY2lhcyByZWxhdGl2YXMgKHBvcmNlbnRhamUpIHNlIHVzYSBsYSBmdW5jacOzbsKgYHByb3AudGFibGUoKWDCoGFwbGljYWRhIHNvYnJlIHVuYSB0YWJsYSBkZSBmcmVjdWVuY2lhcyBhYnNvbHV0YXM6DQoNCmBgYHtyfQ0KcHJvcC50YWJsZShUYWJsYV9EZXBhcnRhbWVudG8pDQpgYGANCg0KRWwgZGVwYXJ0YW1lbnRvIGRlwqAqKiJmaW5pc2hpbmciIChhY2FiYWRvcykqKsKgcmVwcmVzZW50YcKgKioyMC44JSoqwqAocHJpbWVyYSBlbnRyYWRhKSB5wqAqKjIxLjQ3JSoqwqAoc2VndW5kYSBlbnRyYWRhKSBkZSBsb3MgZXF1aXBvcywgbWllbnRyYXMgcXVlwqAqKiJzd2VpbmciIChjb3N0dXJhKSoqwqBjb25jZW50cmHCoCoqNTcuNzMlKirCoGRlbCB0b3RhbC4gTGEgZGlmZXJlbmNpYSBlbnRyZSBsYXMgZG9zIGNhdGVnb3LDrWFzIGRlICJmaW5pc2hpbmciICgyMC44JSB2cyAyMS40NyUpIGNvbmZpcm1hIGluY29uc2lzdGVuY2lhcyBlbiBsb3MgZGF0b3MsIHByb2JhYmxlbWVudGUgcG9yIGVycm9yZXMgZGUgZXNjcml0dXJhIChjb21vIGVzcGFjaW9zIGFkaWNpb25hbGVzKS4NCg0KYGBge3J9DQpyb3VuZChwcm9wLnRhYmxlKFRhYmxhX0RlcGFydGFtZW50byksIGRpZ2l0cz00KQ0KYGBgDQoNCkVsIGdyw6FmaWNvIGRlIGJhcnJhcyBtdWVzdHJhIGxhIGRpc3RyaWJ1Y2nDs24gZGUgcmVnaXN0cm9zIGRlIHByb2R1Y3RpdmlkYWQgcG9yIHRyaW1lc3RyZSwgZG9uZGUgY2FkYSBiYXJyYSB2ZXJ0aWNhbCBlbiB0b25vIGF6dWwgY2xhcm8gcmVwcmVzZW50YSBsYSBjYW50aWRhZCBkZSBlcXVpcG9zIG8gbWVkaWNpb25lcyByZWFsaXphZGFzIGVuIGNhZGEgcGVyaW9kby4gRWwgZWplIFggbXVlc3RyYSBsb3MgdHJpbWVzdHJlcyAoUXVhcnRlcjEsIFF1YXJ0ZXIyLCBldGMuKSBjb24gbGFzIGV0aXF1ZXRhcyBsaWdlcmFtZW50ZSBpbmNsaW5hZGFzIHBhcmEgbWVqb3IgdmlzdWFsaXphY2nDs24sIG1pZW50cmFzIGVsIGVqZSBZIGluZGljYSBlbCBjb250ZW8gYWJzb2x1dG8gZGUgcmVnaXN0cm9zLg0KDQpgYGB7cn0NCmdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBxdWFydGVyKSkgKw0KICBnZW9tX2Jhcihjb2xvciA9ICJibGFjayIsIGZpbGwgPSAibGlnaHRibHVlIikgKw0KICBnZ3RpdGxlKCJEaXN0cmlidWNpw7NuIHBvciBUcmltZXN0cmUiKSArDQogIGxhYnMoeCA9ICJUcmltZXN0cmUiLCB5ID0gIkNvbnRlbyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgc2l6ZSA9IDgpKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHksIGFlcyhkZXBhcnRtZW50LCBmaWxsPXF1YXJ0ZXIpKSArIGdlb21fYmFyKCkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0zMCkpDQpgYGANCg0KRXN0ZSBncsOhZmljbyBkZSBiYXJyYXMgYXBpbGFkYXMgbXVlc3RyYSBsYSBkaXN0cmlidWNpw7NuIGRlIGVxdWlwb3MgZGUgdHJhYmFqbyBzZWfDum4gc3UgZGVwYXJ0YW1lbnRvIChlamUgWCkgeSBzdSBjb21wb3NpY2nDs24gcG9yIHRyaW1lc3RyZXMgKHJlbGxlbm8gZGUgY29sb3JlcykuIENhZGEgYmFycmEgdmVydGljYWwgcmVwcmVzZW50YSB1biBkZXBhcnRhbWVudG8gKCJzd2VpbmciIG8gImZpbmlzaGluZyIpLCBkaXZpZGlkYSBlbiBzZWdtZW50b3MgY29sb3JlYWRvcyBxdWUgaW5kaWNhbiBjdcOhbnRvcyBlcXVpcG9zIHBlcnRlbmVjZW4gYSBjYWRhIHRyaW1lc3RyZSAoUXVhcnRlcjEsIFF1YXJ0ZXIyLCBldGMuKS4gRWwgw6FuZ3VsbyBkZSAzMMKwIGVuIGxhcyBldGlxdWV0YXMgZGVsIGVqZSBYIG1lam9yYSBsYSBsZWdpYmlsaWRhZC4gRXN0YSB2aXN1YWxpemFjacOzbiBwZXJtaXRlIGlkZW50aWZpY2FyIHNpbXVsdMOhbmVhbWVudGU6IDEpIExhIHByb3BvcmNpw7NuIGdlbmVyYWwgZGUgZXF1aXBvcyBlbnRyZSBkZXBhcnRhbWVudG9zIChhbHR1cmEgdG90YWwgZGUgbGFzIGJhcnJhcyksIDIpIEPDs21vIHNlIGRpc3RyaWJ1eWVuIHRlbXBvcmFsbWVudGUgbG9zIGVxdWlwb3MgZGVudHJvIGRlIGNhZGEgZGVwYXJ0YW1lbnRvIChwcm9wb3JjacOzbiBkZSBjb2xvcmVzIGVuIGNhZGEgYmFycmEpLCB5IDMpIFBvc2libGVzIHBhdHJvbmVzIGVzdGFjaW9uYWxlcyBlbnRyZSB0cmltZXN0cmVzIGFsIGNvbXBhcmFyIGxvcyBzZWdtZW50b3MgZGUgY29sb3IgaG9yaXpvbnRhbG1lbnRlLiBFbCBncsOhZmljbyByZXZlbGEgZGUgdW4gdmlzdGF6byBzaSBsYSBhc2lnbmFjacOzbiBkZSBlcXVpcG9zIHBvciBkZXBhcnRhbWVudG8gdmFyw61hIHNpZ25pZmljYXRpdmFtZW50ZSBlbnRyZSBwZXJpb2RvcyBvIHNpIHNlIG1hbnRpZW5lIGNvbnN0YW50ZS4NCg0KKipBbsOhbGlzaXMgRGVzY3JpcHRpdm8gQml2YXJpYWRvIEVudHJlIFZhcmlhYmxlcyBDYXRlZ8OzcmljYXMgeSBDdWFudGl0YXRpdmFzIDoqKg0KRW4gZXN0YSBzZWNjacOzbiBzZSBhbmFsaXphIGxhIHJlbGFjacOzbiBlbnRyZSB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzIChjb21vIGRlcGFydG1lbnQgeSBkYXkpIHkgdmFyaWFibGVzIGN1YW50aXRhdGl2YXMgKGFjdHVhbF9wcm9kdWN0aXZpdHkgeSBvdmVyX3RpbWUpLiBTZSBwcmVzZW50YW4gZXN0YWTDrWdyYWZvcyBkZSB0ZW5kZW5jaWEgY2VudHJhbCwgZGlzcGVyc2nDs24sIGZvcm1hIHkgcG9zaWNpw7NuLCBhc8OtIGNvbW8gZ3LDoWZpY29zIHF1ZSBwZXJtaXRlbiB2aXN1YWxpemFyIGxhIGRpc3RyaWJ1Y2nDs24geSB2YXJpYWJpbGlkYWQgc2VnbWVudGFkYSBwb3IgY2F0ZWdvcsOtYXMuDQoqKjEuIFByb2R1Y3RpdmlkYWQgcmVhbCAoYWN0dWFsX3Byb2R1Y3Rpdml0eSkgcG9yIGRlcGFydGFtZW50byAoZGVwYXJ0bWVudCkqKg0KU2UgZXN0dWRpYSBjw7NtbyB2YXLDrWEgbGEgcHJvZHVjdGl2aWRhZCBhbGNhbnphZGEgc2Vnw7puIGVsIMOhcmVhIGRlIHRyYWJham86DQoqKkVzdGFkw61ncmFmb3MgZGVzdGFjYWRvczoqKg0KTGEgbWVkaWEgeSBtZWRpYW5hIHNvbiBtYXlvcmVzIGVuIGVsIMOhcmVhIGRlIHN3ZWluZywgaW5kaWNhbmRvIHVuIHJlbmRpbWllbnRvIGdlbmVyYWwgbcOhcyBhbHRvOyBBZGljaW9uYWxtZW50ZSwgbGEgZGVzdmlhY2nDs24gZXN0w6FuZGFyIHkgbGEgdmFyaWFuemEgdGFtYmnDqW4gc29uIG3DoXMgZWxldmFkYXMgZW4gc3dlaW5nLCBsbyBjdWFsIHJlZmxlamEgbWF5b3IgZGlzcGVyc2nDs24uDQpFbCByYW5nbyBpbnRlcmN1YXJ0w61saWNvIChJUVIpIHkgbGEgY3VydG9zaXMgc29uIG3DoXMgcHJvbnVuY2lhZG9zIGVuIHN3ZWluZywgbG8gcXVlIHN1Z2llcmUgcHJlc2VuY2lhIGRlIGV4dHJlbW9zIG8gY29tcG9ydGFtaWVudG9zIGF0w61waWNvcy4NCk9ic2VydmFjaW9uZXM6IEVsIGRlcGFydGFtZW50byBkZSBjb3N0dXJhIG11ZXN0cmEgdW5hIHByb2R1Y3RpdmlkYWQgbcOhcyBhbHRhIHkgZGlzcGVyc2EsIGNvbiB2YXJpb3MgdmFsb3JlcyBleHRyZW1vcy4gRW4gY2FtYmlvLCBlbCBkZSBhY2FiYWRvIHRpZW5lIG1lbm9yIHByb2R1Y3RpdmlkYWQgeSBtYXlvciBjb25jZW50cmFjacOzbg0KZGUgZGF0b3MuDQoNCmBgYHtyfQ0KZ2dwbG90KGdhcm1lbnRzX3dvcmtlcl9wcm9kdWN0aXZpdHksIGFlcyh4ID0gYWN0dWFsX3Byb2R1Y3Rpdml0eSwgeSA9IGRlcGFydG1lbnQsIGZpbGwgPSBkZXBhcnRtZW50KSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnModGl0bGUgPSAiQm94cGxvdCBkZSBQcm9kdWN0aXZpZGFkIFJlYWwgcG9yIERlcGFydGFtZW50byIsDQogICAgICAgeCA9ICJQcm9kdWN0aXZpZGFkIFJlYWwiLA0KICAgICAgIHkgPSAiRGVwYXJ0YW1lbnRvIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoqKjEuIEJveHBsb3QgZGUgUHJvZHVjdGl2aWRhZCBSZWFsIHBvciBEZXBhcnRhbWVudG8qKlwNCg0KRWwgYm94cGxvdCBwcmVzZW50YSBsYSBkaXN0cmlidWNpw7NuIGRlIGxhIHByb2R1Y3RpdmlkYWQgcmVhbCAoYGFjdHVhbF9wcm9kdWN0aXZpdHlgKSBlbiBsb3MgZGlzdGludG9zIGRlcGFydGFtZW50b3MuIENhZGEgY2FqYSByZXByZXNlbnRhIGVsIHJhbmdvIGludGVyY3VhcnTDrWxpY28geSBsYSBsw61uZWEgY2VudHJhbCBpbmRpY2EgbGEgbWVkaWFuYS4gU2Ugb2JzZXJ2YSBxdWUgZWwgZGVwYXJ0YW1lbnRvIGRlICJzd2VpbmciIHRpZW5lIHVuYSBtYXlvciBjb25jZW50cmFjacOzbiBkZSB2YWxvcmVzIGJham9zIHkgdW5hIGdyYW4gY2FudGlkYWQgZGUgdmFsb3JlcyBhdMOtcGljb3MgKG91dGxpZXJzKSBwb3IgZGViYWpvIGRlIDAuNiwgbG8gcXVlIHN1Z2llcmUgdW5hIHZhcmlhYmlsaWRhZCBjb25zaWRlcmFibGUgZW4gbGEgcHJvZHVjdGl2aWRhZCBkZSBlc3RlIGdydXBvLiBQb3Igc3UgcGFydGUsIGxvcyBkZXBhcnRhbWVudG9zIGRlICJmaW5pc2hpbmciIG11ZXN0cmFuIGRpc3RyaWJ1Y2lvbmVzIG3DoXMgY2VudHJhZGFzIHkgY29uIG1lbm9yIHByZXNlbmNpYSBkZSB2YWxvcmVzIGV4dHJlbW9zLCBsbyBxdWUgcG9kcsOtYSBpbmRpY2FyIHVuYSBtYXlvciBjb25zaXN0ZW5jaWEgZW4gZWwgZGVzZW1wZcOxbyBkZSBzdXMgdHJhYmFqYWRvcmVzLg0KDQpgYGB7cn0NCmdncGxvdChnYXJtZW50c193b3JrZXJfcHJvZHVjdGl2aXR5LCBhZXMoeCA9IGFjdHVhbF9wcm9kdWN0aXZpdHkpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLCBmaWxsID0gIm9yYW5nZSIsIGNvbG9yID0gImJsYWNrIiwgYmlucyA9IDMwLCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX2RlbnNpdHkoY29sb3IgPSAiYnJvd24iLCBsaW5lcyA9IDEpICsNCiAgZmFjZXRfd3JhcCh+ZGVwYXJ0bWVudCwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIFByb2R1Y3RpdmlkYWQgUmVhbCBwb3IgRGVwYXJ0YW1lbnRvIiwNCiAgICB4ID0gIlByb2R1Y3RpdmlkYWQgUmVhbCIsDQogICAgeSA9ICJGcmVjdWVuY2lhIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KKioyLiBIaXN0b2dyYW1hIGRlIFByb2R1Y3RpdmlkYWQgUmVhbCBwb3IgRGVwYXJ0YW1lbnRvKipcDQoNCkVzdGEgZ3LDoWZpY2EgbXVlc3RyYSBsYSBkaXN0cmlidWNpw7NuIGRlIGxhIHByb2R1Y3RpdmlkYWQgcmVhbCBwb3IgZGVwYXJ0YW1lbnRvLCBhIHRyYXbDqXMgZGUgaGlzdG9ncmFtYXMgYWNvbXBhw7FhZG9zIGRlIGN1cnZhcyBkZSBkZW5zaWRhZC4gRW4gZWwgY2FzbyBkZWwgZGVwYXJ0YW1lbnRvIGRlICJzd2VpbmciLCBsYSBtYXlvcsOtYSBkZSBsb3MgdmFsb3JlcyBzZSBjb25jZW50cmFuIGVudHJlIDAuNyB5IDAuOSwgbG8gY3VhbCBzdWdpZXJlIHF1ZSwgYSBwZXNhciBkZSBsb3Mgb3V0bGllcnMsIGxhIHByb2R1Y3RpdmlkYWQgZGUgbXVjaG9zIHRyYWJhamFkb3JlcyBlc3TDoSBkZW50cm8gZGUgdW4gcmFuZ28gYWNlcHRhYmxlLiBMbGFtYSBsYSBhdGVuY2nDs24gcXVlIGFwYXJlY2VuIGRvcyBwYW5lbGVzIGNvbiBlbCBub21icmUgImZpbmlzaGluZyIsIGxvIGN1YWwgcG9kcsOtYSBkZWJlcnNlIGEgdW5hIGluY29uc2lzdGVuY2lhIGVuIGVsIGV0aXF1ZXRhZG8gZGUgbG9zIGRhdG9zLiBBdW4gYXPDrSwgZW4gYW1ib3Mgc2Ugb2JzZXJ2YSB1bmEgcHJvZHVjdGl2aWRhZCBtw6FzIHVuaWZvcm1lLCBhdW5xdWUgY29uIGNpZXJ0YXMgZGlmZXJlbmNpYXMgZW4gbGEgZm9ybWEgZGUgbGEgZGlzdHJpYnVjacOzbi4NCg0KYGBge3J9DQpnZ3Bsb3QoZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSwgYWVzKHggPSBkYXksIHkgPSBvdmVyX3RpbWUsIGZpbGwgPSBkYXkpKSArDQogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhc3RlbDEiKSArICAjIENvbG9yZXMgc3VhdmVzDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQm94cGxvdCBkZSBIb3JhcyBFeHRyYSBwb3IgRMOtYSBkZSBsYSBTZW1hbmEiLA0KICAgIHggPSAiIiwNCiAgICB5ID0gIkhvcmFzIGV4dHJhIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCmBgYA0KDQoqKjMuIEJveHBsb3QgZGUgSG9yYXMgRXh0cmEgcG9yIETDrWEgZGUgbGEgU2VtYW5hKipcDQoNCkVuIGVzdGEgZ3LDoWZpY2Egc2UgYW5hbGl6YSBsYSBkaXN0cmlidWNpw7NuIGRlIGxhcyBob3JhcyBleHRyYSAoYG92ZXJfdGltZWApIHRyYWJhamFkYXMgZHVyYW50ZSBsYSBzZW1hbmEuIExhIG1heW9yw61hIGRlIGxvcyBkw61hcyBwcmVzZW50YW4gZGlzdHJpYnVjaW9uZXMgc2ltaWxhcmVzLCBjb24gbWVkaWFuYXMgZXN0YWJsZXMgeSByYW5nb3MgaW50ZXJjdWFydMOtbGljb3MgcmVsYXRpdmFtZW50ZSBlc3RyZWNob3MuIFNpbiBlbWJhcmdvLCBlbCBqdWV2ZXMgc2UgZGVzdGFjYSBwb3IgbGEgcHJlc2VuY2lhIGRlIHVuIHZhbG9yIGF0w61waWNvIGV4dHJlbW8gcXVlIHN1cGVyYSBsYXMgMjUsMDAwIGhvcmFzLCBsbyBjdWFsIHBvZHLDrWEgdHJhdGFyc2UgZGUgdW4gZXJyb3IgZW4gbGEgYmFzZSBkZSBkYXRvcyBvIGRlIHVuIGV2ZW50byBlc3BlY8OtZmljbyBjb24gdW5hIGNhcmdhIGRlIHRyYWJham8gaW51c3VhbG1lbnRlIGFsdGEuIEVzdGEgZ3LDoWZpY2Egc3VnaWVyZSBxdWUsIGF1bnF1ZSBsYXMgaG9yYXMgZXh0cmEgZXN0w6FuIHByZXNlbnRlcyB0b2RvcyBsb3MgZMOtYXMsIHN1IGRpc3RyaWJ1Y2nDs24gZ2VuZXJhbCBlcyBjb25zaXN0ZW50ZSBzYWx2byBwb3IgYWxndW5hcyBleGNlcGNpb25lcyBhaXNsYWRhcy4NCg0KYGBge3J9DQpnZ3Bsb3QoZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSwgYWVzKHggPSBvdmVyX3RpbWUsIHkgPSBhY3R1YWxfcHJvZHVjdGl2aXR5KSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gIm9yYW5nZSIsIGFscGhhID0gMC41KSArDQogIGZhY2V0X3dyYXAofmRheSwgc2NhbGVzID0gImZyZWVfeCIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSZWxhY2nDs24gZW50cmUgSG9yYXMgRXh0cmEgeSBQcm9kdWN0aXZpZGFkIHBvciBEw61hIiwNCiAgICB4ID0gIkhvcmFzIGV4dHJhIiwNCiAgICB5ID0gIlByb2R1Y3RpdmlkYWQgUmVhbCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCioqNC4gRGlzcGVyc2nDs24gZW50cmUgSG9yYXMgRXh0cmEgeSBQcm9kdWN0aXZpZGFkIHBvciBEw61hKipcDQoNCkVzdGEgdmlzdWFsaXphY2nDs24gbXVlc3RyYSBsYSByZWxhY2nDs24gZW50cmUgbGFzIGhvcmFzIGV4dHJhIHkgbGEgcHJvZHVjdGl2aWRhZCByZWFsLCBzZXBhcmFkYSBwb3IgZMOtYSBkZSBsYSBzZW1hbmEuIENhZGEgcHVudG8gcmVwcmVzZW50YSB1biB0cmFiYWphZG9yLCB5IGVsIG9iamV0aXZvIGVzIGlkZW50aWZpY2FyIHNpIGV4aXN0ZSBhbGfDum4gdGlwbyBkZSBjb3JyZWxhY2nDs24gZW50cmUgdHJhYmFqYXIgbcOhcyBob3JhcyB5IG9idGVuZXIgdW5hIG1heW9yIHByb2R1Y3RpdmlkYWQuIEVuIGdlbmVyYWwsIG5vIHNlIG9ic2VydmEgdW5hIHJlbGFjacOzbiBjbGFyYSBlbnRyZSBsYXMgdmFyaWFibGVzOiB0YW50byBsb3MgdHJhYmFqYWRvcmVzIHF1ZSBoYWNlbiBwb2NhcyBjb21vIGxvcyBxdWUgaGFjZW4gbXVjaGFzIGhvcmFzIGV4dHJhIHB1ZWRlbiB0ZW5lciBuaXZlbGVzIGRlIHByb2R1Y3RpdmlkYWQgYmFqb3MsIG1lZGlvcyBvIGFsdG9zLiBFc3RvIHBvZHLDrWEgaW5kaWNhciBxdWUgbGFzIGhvcmFzIGFkaWNpb25hbGVzIG5vIGdhcmFudGl6YW4gdW4gYXVtZW50byBlbiBsYSBlZmljaWVuY2lhLCB5IHF1ZSBvdHJvcyBmYWN0b3JlcyBpbmZsdXllbiBlbiBlbCBkZXNlbXBlw7FvIGRpYXJpby4NCg0KYGBge3J9DQpnZ3Bsb3QoZ2FybWVudHNfd29ya2VyX3Byb2R1Y3Rpdml0eSwgYWVzKHggPSBvdmVyX3RpbWUpKSArDQogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5kZW5zaXR5Li4pLCBmaWxsID0gIm9saXZlZHJhYjMiLCBjb2xvciA9ICJibGFjayIsIGJpbnMgPSAzMCwgYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gImRhcmtncmVlbiIsIHNpemUgPSAxKSArDQogIGZhY2V0X3dyYXAofmRheSwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIEhvcmFzIEV4dHJhIHBvciBEw61hIiwNCiAgICB4ID0gIkhvcmFzIGV4dHJhIiwNCiAgICB5ID0gIkZyZWN1ZW5jaWEiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoqKjUuIEhpc3RvZ3JhbWEgZGUgSG9yYXMgRXh0cmEgcG9yIETDrWEqKlwNCg0KRmluYWxtZW50ZSwgc2UgcHJlc2VudGEgbGEgZGlzdHJpYnVjacOzbiBkZSBsYXMgaG9yYXMgZXh0cmEgcG9yIGTDrWEgbWVkaWFudGUgaGlzdG9ncmFtYXMgY29uIGN1cnZhcyBkZSBkZW5zaWRhZC4gRW4gY2FzaSB0b2RvcyBsb3MgY2Fzb3MsIGxvcyBkYXRvcyBlc3TDoW4gc2VzZ2Fkb3MgaGFjaWEgbGEgZGVyZWNoYSwgbG8gcXVlIHNpZ25pZmljYSBxdWUgbGEgbWF5b3LDrWEgZGUgbG9zIHRyYWJhamFkb3JlcyByZWFsaXphIHBvY2FzIGhvcmFzIGV4dHJhLCBtaWVudHJhcyBxdWUgdW5vcyBwb2NvcyBjb25jZW50cmFuIHZhbG9yZXMgc2lnbmlmaWNhdGl2YW1lbnRlIGFsdG9zLiBFc3RlIHBhdHLDs24gc2UgbWFudGllbmUgZW4gdG9kb3MgbG9zIGTDrWFzLCBhdW5xdWUgbG9zIGp1ZXZlcyB5IHPDoWJhZG9zIHBhcmVjZW4gdGVuZXIgbcOhcyBmcmVjdWVuY2lhIGRlIGpvcm5hZGFzIGxhcmdhcy4gRXN0YSBncsOhZmljYSByZXNhbHRhIGxhIGRlc2lndWFsIGRpc3RyaWJ1Y2nDs24gZGVsIHRyYWJham8gYWRpY2lvbmFsIHkgc3VnaWVyZSBxdWUgZWwgdXNvIGRlIGhvcmFzIGV4dHJhIG5vIGVzIHVuaWZvcm1lIGVudHJlIGxvcyBlbXBsZWFkb3MgbmkgZW50cmUgbG9zIGTDrWFzIGRlIGxhIHNlbWFuYS4NCg==