Introducción
Esta presentación se centra en algunos microaprendizajes de un proyecto de análisis de resultados de una encuesta de diversidad e inclusión.
Lo razón por la que lo llamo “microaprendizajes” es porque no tuve que aprender muchas cosas desde cero, pero si aprendí varios truquitos que me sirvieron mucho.
Voy a usar una encuesta simulada para no violar la confidencialidad de los datos, pero va a ser algo análogo a lo que estuve usando en el proyecto.
Para explotar al máximo esta sesión conviene saber un poco de hacer informes con RMarkdown. Si necesitás un tutorial sobre ese tema te comparto el video que hicimos el año pasado.
Este material se puede utilizar y compartir sin fines comerciales y citando la fuente.
Aprendizajes
El chunk de ‘setup’
El bloque de código de setup es muy útil para controlar cómo se van a comportar todos los bloques de código.
Mi archivo original tiene +150 bloques de código, imaginen si modificara uno por uno las características de cada bloque.
knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE, fig.retina = 3,
out.width = "80%")
Ordenar el código
Tener un orden en el código es muy importante para poder ir y venir rápido y encontrar rápidamente las cosas, modificar algo, y demás.
Dentro de los bloques de código también es importante poner títulos o marcadores que nos ayuden a encontrar rápido las cosas. El orden que definí fue:
- Librerías.
- Configuraciones generales
- Carga de datos
- Preprocesamiento y limpieza de datos
- Funciones
# Librerías -----
library(tidyverse)
library(gt)
library(scales)
library(extrafont)
library(readxl)
# Configuraciones generales ----------
# Colores
verde <- "#01B3B6"
negro <- "#333132"
gris <- "#AEB6BF"
color3 <- c(verde, gris, negro)
color2 <- c(verde, negro)
# Opciones de visualización --------
options(scipen = 999) # Modifica la visualización de los ejes numérico a valores nominales
loadfonts(quiet = TRUE) # Permite cargar en R otros tipos de fuentes.
# Estilo limpio sin líneas de fondo
estilo <- theme(panel.grid = element_blank(),
plot.background = element_rect(fill = "#FBFCFC"),
panel.background = element_blank(),
text = element_text(family = "Ubuntu Mono"))
# Estilo limpio con líneas de referencia verticales en gris claro
estilov <- theme(panel.grid = element_blank(),
plot.background = element_rect(fill = "#FBFCFC"),
panel.background = element_blank(),
panel.grid.major.x = element_line(color = "#ecf0f1"),
text = element_text(family = "Ubuntu Mono"))
# Estilo limpio con líneas de referencia horizontales en gris claro
estiloh <- theme(panel.grid = element_blank(),
plot.background = element_rect(fill = "#FBFCFC"),
panel.background = element_blank(),
panel.grid.major.y = element_line(color = "#ecf0f1"),
text = element_text(family = "Ubuntu Mono"))
# Creo un objeto con un texto que se va a repetir mucho a lo largo del análisis
fuente <- "Club de R para RRHH\nDatos Ficticios"
# Creo objetos para formatear las etiquetas numéricas de los ejes x e y
eje_x_per <- scale_x_continuous(labels = scales::percent_format(accuracy = 1))
eje_y_per <- scale_y_continuous(labels = scales::percent_format(accuracy = 1))
# Carga de Datos -----
encuesta <- read_excel("data/encuesta.xlsx")
plantel <- read_excel("data/plantel.xlsx")
# Preparación de datos -----------
# Pivotea el dataset a un formato largo
enc <- encuesta %>%
pivot_longer(cols = c(7:11),
names_to = "pregunta",
values_to = "valor")
# Cambia nombres y Organiza variables ordinales
enc <- enc %>%
rename(id = "ID",
genero = `¿Cómo definirías tu identidad de género?`,
unidad = "Unidad de Negocio",
pais = "País",
sector = "Sector",
cargo = "Tu cargo/nivel:") %>%
mutate(cargo = factor(cargo,
levels = c("Management", "Líder", "Contribuidor individual")))
# Crea categorías de resultados
enc <- enc %>%
mutate(resultado = if_else(valor == "Totalmente de acuerdo", "Positivo",
if_else(valor == "De acuerdo", "Positivo",
if_else(valor == "Ni de acuerdo ni en desacuerdo",
"Neutral", "Negativo"
)
)
),
resultado = factor(resultado,
levels = c("Positivo", "Neutral", "Negativo")))
Y comenten el código por amor a Jebús!

Poner el nombre a los bloques de código
Algo muy útil es ponerle nombre a los bloques de código. Por un lado porque es fácil para navegar entre bloques buscándolos en RStudio.
Por ejemplo, probemos un gráfico simple:
ggplot(enc, aes(x = pais, fill = resultado)) +
geom_bar(position = "fill") +
scale_fill_manual(values = c(color3)) +
estiloh +
eje_y_per +
labs(title = "Resultados por país",
fill = "Resultado",
x = "", y = "",
caption = fuente)

Puede ocurrir que necesitemos reutilizar el gráfico. Hacer la gran stackoverflow (copiar y pegar el código) es una opción, pero puede generar errores y por otro lado implica tiempo de procesamiento.
En cambio, con la opción ref.label podemos reutilizar lo que hicimos antes, de una forma más prolija y cómoda pasando el nombre del bloque anterior.
Internamente, lo que hace R es reutilizar el código creado anteriormente.
Voilá!
ggplot(enc, aes(x = pais, fill = resultado)) +
geom_bar(position = "fill") +
scale_fill_manual(values = c(color3)) +
estiloh +
eje_y_per +
labs(title = "Resultados por país",
fill = "Resultado",
x = "", y = "",
caption = fuente)

Etiquetas largas
A veces necesitamos presentar en un gráfico o en una tabla la pregunta original de la encuesta. Por ejemplo, una de las “preguntas” de la encuesta dice:
Otra pregunta que tiene muchísimo texto escrito en la encuesta y quedó tan larga que no entra en un solo renglón y que me hace preguntarme cómo la voy a poner en un gráfico
Ahora veamos cómo se ven las preguntas en un gráfico si intentamos hacer un ranking.
enc %>%
group_by(pregunta, resultado) %>%
summarise(cant = n()) %>%
mutate(prop = cant/sum(cant)) %>%
filter(resultado == "Positivo") %>%
ggplot(aes(x = prop, y = pregunta)) +
geom_col(fill = verde) +
estilov +
eje_x_per +
labs(title = "Ranking de Respuestas Positivas",
x = "", y = "",
caption = fuente)

Queda hermoso, no? 😱
Para sortear este problema podemos crear una columna nueva, y usar la función str_wrap() del paquete stringr.
Lo que hace esto es agregar el símbolo \n que divide el texto en renglones. Con el parámetro width le indicamos la cantidad de caracteres de largo que tendrá cada renglón.
# Divide el largo de 'función' en varias líneas
enc$preg2 <- str_wrap(enc$pregunta, width = 40)
# Veamos como queda esto en el df
head(enc$preg2,5)
## [1] "Una pregunta con un texto muy pero muy\npero muy largo, de verdad que es muy muy\nmuy largo"
## [2] "Otra pregunta que tiene muchísimo texto\nescrito en la encuesta y quedó tan larga\nque no entra en un solo renglón y que me\nhace preguntarme cómo la voy a poner en\nun gráfico"
## [3] "Los líderes son unos capos"
## [4] "Que grosso es trabajar acá"
## [5] "Esta encuesta es genial"
Y ahora podemos hacer un gráfico que se vea bien:
enc %>%
group_by(preg2, resultado) %>%
summarise(cant = n()) %>%
mutate(prop = cant/sum(cant)) %>%
filter(resultado == "Positivo") %>%
ggplot(aes(x = prop, y = reorder(preg2, prop))) +
geom_col(fill = verde) +
estilov +
eje_x_per +
labs(title = "Ranking de Respuestas Positivas",
x = "", y = "",
caption = fuente)

Ahora queda mucho mejor 👍
También se puede jugar con la altura del gráfico usando la opción fig.height en las opciones del bloque para que haya más espacio entre las barras.
{r fig.height=8} # El tamaño es exagerado en este caso
ranking <- enc %>%
group_by(preg2, resultado) %>%
summarise(cant = n()) %>%
mutate(prop = cant/sum(cant)) %>%
filter(resultado == "Positivo") %>%
ggplot(aes(x = prop, y = reorder(preg2, prop))) +
geom_col(fill = verde) +
estilov +
eje_x_per +
labs(title = "Ranking de Respuestas Positivas",
x = "", y = "",
caption = fuente)
ranking

Texto en los gráficos
Es simple agregar las etiquetas de datos a un gráfico:
ranking +
geom_text(aes(label = percent(prop, # Muestra los resultados como porcentaje
accuracy = 1)), # Indica la cantidad de decimales
size = 3, # Cambia el tamaño de la letra
hjust = 1.2, # Mueve la etiqueta para la izquierda
family = "Ubuntu Mono")

Miremos lo que pasa cuando queremos agregar más información al gráfico, por ejemplo, con los resultados por país.
ranking <- enc %>%
group_by(pais, preg2, resultado) %>%
summarise(cant = n()) %>%
mutate(prop = cant/sum(cant)) %>%
filter(resultado == "Positivo") %>%
ggplot(aes(x = prop, y = reorder(preg2, prop), fill = pais)) +
geom_col(position = "dodge") +
estilov +
eje_x_per +
labs(title = "Ranking de Respuestas Positivas",
x = "", y = "",
fill = "País",
caption = fuente) +
scale_fill_brewer(palette = 2)
ranking +
geom_text(aes(label = percent(prop, # Muestra los resultados como porcentaje
accuracy = 1)), # Indica la cantidad de decimales
size = 3, # Cambia el tamaño de la letra
hjust = 1.2, # Mueve la etiqueta para la izquierda
family = "Ubuntu Mono") # Modifica la fuente

El problema es que todas las etiquetas de cada barra están centradas con la etiqueta del eje y. En la guía de geom_text en la documentación de ggplot2 encontramos como solucionar el problema usando el parámetro position_dodge().
ranking <- ranking +
geom_text(aes(label = percent(prop, # Muestra los resultados como porcentaje
accuracy = 1)), # Indica la cantidad de decimales
position = position_dodge(0.9), # Acomoda cada etiqueta con las barras
size = 3, # Cambia el tamaño de la letra
hjust = 1.2, # Mueve la etiqueta para la izquierda
family = "Ubuntu Mono") # Modifica la fuente
ranking

Otra mejora que podemos hacer al gráfico es acomodar los colores en la leyenda (la referencia de los colores) para que tengan la misma secuencia que tiene en el gráfico, es decir que el verde oscuro aparezca primero al igual que la barra con el verde más oscuro en el gráfico.
En esta página hay muchas variantes para trabajar con las etiquetas y leyendas.
ranking +
guides(fill = guide_legend(reverse=TRUE)) + # Invierte el orden de los colores en la leyenda
theme(axis.text.x = element_blank())

Cuando estamos mapeando una variable categórica en el eje y, R lo ordena alfabéticamente desde abajo hacia arriba.
enc %>%
group_by(sector, resultado) %>%
summarise(cant = n()) %>%
mutate(prop = cant/sum(cant)) %>%
filter(resultado == "Positivo") %>%
ggplot(aes(x = prop, y = sector)) +
geom_col(fill = verde) +
estilov +
eje_x_per +
labs(title = "Resultado Positivos por Sector",
x = "", y = "",
caption = fuente)

Podemos usar la función fct_rev del paquete forcats para poner al revés las etiquetas del eje y cuando estamos mapeando las variables dentro de ggplot
enc %>%
group_by(sector, resultado) %>%
summarise(cant = n()) %>%
mutate(prop = cant/sum(cant)) %>%
filter(resultado == "Positivo") %>%
ggplot(aes(x = prop, y = fct_rev(sector))) + # Invertimos el orden del eje y
geom_col(fill = verde) +
estilov +
eje_x_per +
labs(title = "Resultado Positivos por Sector",
x = "", y = "",
caption = fuente)

Por último, una mejora adicional que podemos hacer a los gráficos anteriores es alinear el título a la izquierda del gráfico agregando el parámetro plot.title.position = "plot" dentro de theme.
enc %>%
group_by(sector, resultado) %>%
summarise(cant = n()) %>%
mutate(prop = cant/sum(cant)) %>%
filter(resultado == "Positivo") %>%
ggplot(aes(x = prop, y = fct_rev(sector))) + # Invertimos el orden del eje y
geom_col(fill = verde) +
estilov +
eje_x_per +
labs(title = "Resultado Positivos por Sector",
x = "", y = "",
caption = fuente) +
theme(plot.title.position = "plot")

Funciones
Esto es un work-in-progress y tengo que agradecer a Mónica Alonso de RLadies Buenos Aires por la ayuda.
El problema es que me encontré muchas veces escribiendo esta secuencia de código muchas veces:
# Calcular pocertajes de respuestas
enc %>%
group_by(genero, resultado) %>%
summarise(cant = n()) %>%
mutate(prop = cant / sum(cant))
## # A tibble: 6 x 4
## # Groups: genero [2]
## genero resultado cant prop
## <chr> <fct> <int> <dbl>
## 1 Femenino Positivo 1127 0.764
## 2 Femenino Neutral 244 0.165
## 3 Femenino Negativo 104 0.0705
## 4 Masculino Positivo 1477 0.823
## 5 Masculino Neutral 222 0.124
## 6 Masculino Negativo 96 0.0535
Muchas veces resolví copiando y pegando el código, pero se hace tedioso controlar cada uno de los bloques de código y gráficos. Así que para eso, podemos crear nuestras propias funciones.
cant_prop_gen <- function(df){
df %>%
group_by(genero,resultado) %>%
summarise(cant = n()) %>%
mutate(prop = cant / sum(cant))
}
Y ahora lo podemos incorporar en nuestro flujo de trabajo como cualquier función.
enc %>%
cant_prop_gen() %>%
ggplot(aes(x = genero, y = prop, fill = resultado)) +
geom_col(position = "dodge") +
eje_y_per +
estiloh +
scale_fill_manual(values = color3) +
labs(title = "Resultados por Género",
x = "", y = "",
fill = "Resultado",
caption = fuente)

Todavía estoy resolviendo como crear funciones usando cualquier tipo de variable en la función. Por ahora, lo estoy resolviendo creando una función para cada combinación de variables que agrupo. No es lo ideal, pero es lo que hay. 🤷
Capaz encuentre lo que necesito en estos libros:
Ya les contaré… stay tuned 📺
Código Inline
Como sabemos, algo interesante de RMarkdown es la posibilidad de utilizar el código de los bloques dentro del texto.
Así que creemos un pequeño objeto primero para almacenar los resultados positivos y negativos por género.
result_genero <- enc %>%
cant_prop_gen()
result_genero
## # A tibble: 6 x 4
## # Groups: genero [2]
## genero resultado cant prop
## <chr> <fct> <int> <dbl>
## 1 Femenino Positivo 1127 0.764
## 2 Femenino Neutral 244 0.165
## 3 Femenino Negativo 104 0.0705
## 4 Masculino Positivo 1477 0.823
## 5 Masculino Neutral 222 0.124
## 6 Masculino Negativo 96 0.0535
Usando la llamada de datos de un dataframe con nombre_df[fila,columna] puedo usar los resultados almacenados para incluirlos dentro del texto por ejemplo para decir:
Los resultados positivos para las personas de género femenino es 0.7640678.
Lo ideal es poder ver ese resultado como un porcentaje, así que intuitivamente podemos usar la función percent para lograr eso…
…y no va a funcionar. Obtenemos el siguiente mensaje de error:
# Intento de código inline
`r percent(result_genero[1,4])`
# Quitting from lines 425-441 (r4hr_microaprendizajes.Rmd)
# Error in is.finite(x) : default method not implemented for type 'list'
Para que la función percent funcione la tenemos que combinar con la función pull . Y ahora así sí funciona:
Los resultados positivos para las personas de género femenino es 76% .
Trust the Tidyverse
Lo barato sale caro
Dicho popular

La encuesta que estábamos analizando era anónima, lo cual hacía imposible poder cruzar datos contra el listado de empleados.
Pero, sí podíamos calcular los resultados según la composición del liderazgo. Para eso teníamos que calcular el porcentaje de líderes hombres y mujeres por sector.
# Cuento la cantidad de líderes por sector y géenero
plantel <- plantel %>%
rename(division = `Unidad de Negocio`,
lider = Líder,
sexo = Género,
sector = Sector,
pais = País) %>%
filter(lider == "true") %>%
group_by(pais, division, sector, lider, sexo) %>%
tally() %>%
ungroup()
plantel
## # A tibble: 106 x 6
## pais division sector lider sexo n
## <chr> <chr> <chr> <chr> <chr> <int>
## 1 Chad Unidad 1 Comercial true Femenino 4
## 2 Chad Unidad 1 Comercial true Masculino 3
## 3 Chad Unidad 1 R&D true Femenino 5
## 4 Chad Unidad 1 R&D true Masculino 1
## 5 Chad Unidad 2 Administración true Femenino 3
## 6 Chad Unidad 2 Administración true Masculino 6
## 7 Chad Unidad 2 Calidad true Femenino 1
## 8 Chad Unidad 2 Comercial true Femenino 5
## 9 Chad Unidad 2 Comercial true Masculino 1
## 10 Chad Unidad 2 Recursos Humanos true Femenino 3
## # ... with 96 more rows
# Pivoteo el dataset a un dataset ancho
(plantel <- plantel %>%
pivot_wider(.,
names_from = sexo,
values_from = n))
## # A tibble: 60 x 6
## pais division sector lider Femenino Masculino
## <chr> <chr> <chr> <chr> <int> <int>
## 1 Chad Unidad 1 Comercial true 4 3
## 2 Chad Unidad 1 R&D true 5 1
## 3 Chad Unidad 2 Administración true 3 6
## 4 Chad Unidad 2 Calidad true 1 NA
## 5 Chad Unidad 2 Comercial true 5 1
## 6 Chad Unidad 2 Recursos Humanos true 3 NA
## 7 Chad Unidad 3 Administración true 2 2
## 8 Chad Unidad 3 Calidad true 2 2
## 9 Chad Unidad 3 Comercial true 5 20
## 10 Chad Unidad 3 HSE true 1 NA
## # ... with 50 more rows
# Reemplaza los NA con un 0
plantel[is.na(plantel)] <- 0
plantel
## # A tibble: 60 x 6
## pais division sector lider Femenino Masculino
## <chr> <chr> <chr> <chr> <int> <int>
## 1 Chad Unidad 1 Comercial true 4 3
## 2 Chad Unidad 1 R&D true 5 1
## 3 Chad Unidad 2 Administración true 3 6
## 4 Chad Unidad 2 Calidad true 1 0
## 5 Chad Unidad 2 Comercial true 5 1
## 6 Chad Unidad 2 Recursos Humanos true 3 0
## 7 Chad Unidad 3 Administración true 2 2
## 8 Chad Unidad 3 Calidad true 2 2
## 9 Chad Unidad 3 Comercial true 5 20
## 10 Chad Unidad 3 HSE true 1 0
## # ... with 50 more rows
Terminados esos pasos puedo calcular el porcentaje de líderes hombres por país, unidad de negocio y sector para incorporarlo en el análisis.
# Calculo porcentaje de líderes hombres
plantel %>%
mutate(prop_lider_hombre = if_else(Femenino == 0, # Condición
1, # Valor si cumple condición
Masculino / (Masculino +Femenino))) %>% # Valor si no cumple
select(-lider) # Elimina columna 'líder'
## # A tibble: 60 x 6
## pais division sector Femenino Masculino prop_lider_hombre
## <chr> <chr> <chr> <int> <int> <dbl>
## 1 Chad Unidad 1 Comercial 4 3 0.429
## 2 Chad Unidad 1 R&D 5 1 0.167
## 3 Chad Unidad 2 Administración 3 6 0.667
## 4 Chad Unidad 2 Calidad 1 0 0
## 5 Chad Unidad 2 Comercial 5 1 0.167
## 6 Chad Unidad 2 Recursos Humanos 3 0 0
## 7 Chad Unidad 3 Administración 2 2 0.5
## 8 Chad Unidad 3 Calidad 2 2 0.5
## 9 Chad Unidad 3 Comercial 5 20 0.8
## 10 Chad Unidad 3 HSE 1 0 0
## # ... with 50 more rows
LS0tDQp0aXRsZTogIk1pY3JvYXByZW5kaXphamVzIGRlIHVuIFByb3llY3RvIg0KYXV0aG9yOiAiU2VyZ2lvIEdhcmNpYSBNb3JhIHwgQ2x1YiBkZSBSIHBhcmEgUlJISCINCmRhdGU6ICIyMi8wNS8yMDIxIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiBzcGFjZWxhYg0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkOiBoaWRlDQotLS0NCg0KIyBJbnRyb2R1Y2Npw7NuDQoNCkVzdGEgcHJlc2VudGFjacOzbiBzZSBjZW50cmEgZW4gYWxndW5vcyAqbWljcm9hcHJlbmRpemFqZXMqIGRlIHVuIHByb3llY3RvIGRlIGFuw6FsaXNpcyBkZSByZXN1bHRhZG9zIGRlIHVuYSBlbmN1ZXN0YSBkZSBkaXZlcnNpZGFkIGUgaW5jbHVzacOzbi4NCg0KTG8gcmF6w7NuIHBvciBsYSBxdWUgbG8gbGxhbW8gKiJtaWNyb2FwcmVuZGl6YWplcyIqIGVzIHBvcnF1ZSBubyB0dXZlIHF1ZSBhcHJlbmRlciBtdWNoYXMgY29zYXMgZGVzZGUgY2VybywgcGVybyBzaSBhcHJlbmTDrSB2YXJpb3MgdHJ1cXVpdG9zIHF1ZSBtZSBzaXJ2aWVyb24gbXVjaG8uDQoNClZveSBhIHVzYXIgdW5hIGVuY3Vlc3RhIHNpbXVsYWRhIHBhcmEgbm8gdmlvbGFyIGxhIGNvbmZpZGVuY2lhbGlkYWQgZGUgbG9zIGRhdG9zLCBwZXJvIHZhIGEgc2VyIGFsZ28gYW7DoWxvZ28gYSBsbyBxdWUgZXN0dXZlIHVzYW5kbyBlbiBlbCBwcm95ZWN0by4NCg0KUGFyYSBleHBsb3RhciBhbCBtw6F4aW1vIGVzdGEgc2VzacOzbiBjb252aWVuZSBzYWJlciB1biBwb2NvIGRlIGhhY2VyIGluZm9ybWVzIGNvbiBSTWFya2Rvd24uIFNpIG5lY2VzaXTDoXMgdW4gdHV0b3JpYWwgc29icmUgZXNlIHRlbWEgdGUgY29tcGFydG8gZWwgW3ZpZGVvIHF1ZSBoaWNpbW9zIGVsIGHDsW8gcGFzYWRvXShodHRwczovL3lvdXR1LmJlL0tUNFVmVHFBWW9VKS4NCg0KIyMjIGByIGZvbnRhd2Vzb21lOjpmYSgiZ2l0aHViIiwgZmlsbCA9ICJzdGVlbGJsdWUiKWAgW1JlcG9dKGh0dHBzOi8vZ2l0aHViLmNvbS9yNGhyL3I0aHJfbWljcm9hcHJlbmRpemFqZXMpDQoNCkVzdGUgbWF0ZXJpYWwgc2UgcHVlZGUgdXRpbGl6YXIgeSBjb21wYXJ0aXIgc2luIGZpbmVzIGNvbWVyY2lhbGVzIHkgY2l0YW5kbyBsYSBmdWVudGUuDQoNCiFbTGljZW5jaWFdKGh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvdGh1bWIvOS85OS9DYy1ieS1uY19pY29uLnN2Zy8xMjAwcHgtQ2MtYnktbmNfaWNvbi5zdmcucG5nKXt3aWR0aD0iMTUwIn0NCg0KIyBBcHJlbmRpemFqZXMNCg0KIyMgRWwgKmNodW5rKiBkZSAnc2V0dXAnDQoNCkVsIGJsb3F1ZSBkZSBjw7NkaWdvIGRlIGBzZXR1cGAgZXMgbXV5IMO6dGlsIHBhcmEgY29udHJvbGFyIGPDs21vIHNlIHZhbiBhIGNvbXBvcnRhciB0b2RvcyBsb3MgYmxvcXVlcyBkZSBjw7NkaWdvLg0KDQpNaSBhcmNoaXZvIG9yaWdpbmFsIHRpZW5lICsxNTAgYmxvcXVlcyBkZSBjw7NkaWdvLCBpbWFnaW5lbiBzaSBtb2RpZmljYXJhIHVubyBwb3IgdW5vIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGRlIGNhZGEgYmxvcXVlLg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLnJldGluYSA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgb3V0LndpZHRoID0gIjgwJSIpDQpgYGANCg0KIyMgT3JkZW5hciBlbCBjw7NkaWdvDQoNClRlbmVyIHVuIG9yZGVuIGVuIGVsIGPDs2RpZ28gZXMgbXV5IGltcG9ydGFudGUgcGFyYSBwb2RlciBpciB5IHZlbmlyIHLDoXBpZG8geSBlbmNvbnRyYXIgcsOhcGlkYW1lbnRlIGxhcyBjb3NhcywgbW9kaWZpY2FyIGFsZ28sIHkgZGVtw6FzLg0KDQpEZW50cm8gZGUgbG9zIGJsb3F1ZXMgZGUgY8OzZGlnbyB0YW1iacOpbiBlcyBpbXBvcnRhbnRlIHBvbmVyIHTDrXR1bG9zIG8gbWFyY2Fkb3JlcyBxdWUgbm9zIGF5dWRlbiBhIGVuY29udHJhciByw6FwaWRvIGxhcyBjb3Nhcy4gRWwgb3JkZW4gcXVlIGRlZmluw60gZnVlOg0KDQoxLiAgTGlicmVyw61hcy4NCjIuICBDb25maWd1cmFjaW9uZXMgZ2VuZXJhbGVzDQozLiAgQ2FyZ2EgZGUgZGF0b3MNCjQuICBQcmVwcm9jZXNhbWllbnRvIHkgbGltcGllemEgZGUgZGF0b3MNCjUuICBGdW5jaW9uZXMNCg0KYGBge3IgaW5pY2lvfQ0KIyBMaWJyZXLDrWFzIC0tLS0tDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ3QpDQpsaWJyYXJ5KHNjYWxlcykNCmxpYnJhcnkoZXh0cmFmb250KQ0KbGlicmFyeShyZWFkeGwpDQoNCg0KIyBDb25maWd1cmFjaW9uZXMgZ2VuZXJhbGVzIC0tLS0tLS0tLS0NCg0KIyBDb2xvcmVzDQp2ZXJkZSA8LSAiIzAxQjNCNiINCm5lZ3JvIDwtICIjMzMzMTMyIg0KZ3JpcyA8LSAiI0FFQjZCRiINCg0KY29sb3IzIDwtIGModmVyZGUsIGdyaXMsIG5lZ3JvKQ0KY29sb3IyIDwtIGModmVyZGUsIG5lZ3JvKQ0KDQojIE9wY2lvbmVzIGRlIHZpc3VhbGl6YWNpw7NuIC0tLS0tLS0tDQpvcHRpb25zKHNjaXBlbiA9IDk5OSkgICAjIE1vZGlmaWNhIGxhIHZpc3VhbGl6YWNpw7NuIGRlIGxvcyBlamVzIG51bcOpcmljbyBhIHZhbG9yZXMgbm9taW5hbGVzDQoNCmxvYWRmb250cyhxdWlldCA9IFRSVUUpICMgUGVybWl0ZSBjYXJnYXIgZW4gUiBvdHJvcyB0aXBvcyBkZSBmdWVudGVzLg0KDQojIEVzdGlsbyBsaW1waW8gc2luIGzDrW5lYXMgZGUgZm9uZG8NCmVzdGlsbyA8LSB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGQkZDRkMiKSwNCiAgICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIlVidW50dSBNb25vIikpDQoNCiMgRXN0aWxvIGxpbXBpbyBjb24gbMOtbmVhcyBkZSByZWZlcmVuY2lhIHZlcnRpY2FsZXMgZW4gZ3JpcyBjbGFybw0KZXN0aWxvdiA8LSB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkJGQ0ZDIiksDQogICAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZShjb2xvciA9ICIjZWNmMGYxIiksDQogICAgICAgICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIlVidW50dSBNb25vIikpDQoNCiMgRXN0aWxvIGxpbXBpbyBjb24gbMOtbmVhcyBkZSByZWZlcmVuY2lhIGhvcml6b250YWxlcyBlbiBncmlzIGNsYXJvDQplc3RpbG9oIDwtIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGQkZDRkMiKSwNCiAgICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gIiNlY2YwZjEiKSwNCiAgICAgICAgICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiVWJ1bnR1IE1vbm8iKSkNCg0KDQojIENyZW8gdW4gb2JqZXRvIGNvbiB1biB0ZXh0byBxdWUgc2UgdmEgYSByZXBldGlyIG11Y2hvIGEgbG8gbGFyZ28gZGVsIGFuw6FsaXNpcw0KZnVlbnRlIDwtICJDbHViIGRlIFIgcGFyYSBSUkhIXG5EYXRvcyBGaWN0aWNpb3MiDQoNCiMgQ3JlbyBvYmpldG9zIHBhcmEgZm9ybWF0ZWFyIGxhcyBldGlxdWV0YXMgbnVtw6lyaWNhcyBkZSBsb3MgZWplcyB4IGUgeQ0KZWplX3hfcGVyIDwtIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpDQoNCmVqZV95X3BlciA8LSBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKQ0KDQojIENhcmdhIGRlIERhdG9zIC0tLS0tDQplbmN1ZXN0YSA8LSByZWFkX2V4Y2VsKCJkYXRhL2VuY3Vlc3RhLnhsc3giKQ0KcGxhbnRlbCAgPC0gcmVhZF9leGNlbCgiZGF0YS9wbGFudGVsLnhsc3giKQ0KDQojIFByZXBhcmFjacOzbiBkZSBkYXRvcyAtLS0tLS0tLS0tLQ0KDQojIFBpdm90ZWEgZWwgZGF0YXNldCBhIHVuIGZvcm1hdG8gbGFyZ28NCmVuYyA8LSBlbmN1ZXN0YSAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gYyg3OjExKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInByZWd1bnRhIiwgDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsb3IiKQ0KDQojIENhbWJpYSBub21icmVzIHkgT3JnYW5pemEgdmFyaWFibGVzIG9yZGluYWxlcyANCg0KZW5jIDwtIGVuYyAlPiUgDQogIHJlbmFtZShpZCA9ICJJRCIsDQogICAgICAgICBnZW5lcm8gPSBgwr9Dw7NtbyBkZWZpbmlyw61hcyB0dSBpZGVudGlkYWQgZGUgZ8OpbmVybz9gLA0KICAgICAgICAgdW5pZGFkID0gIlVuaWRhZCBkZSBOZWdvY2lvIiwNCiAgICAgICAgIHBhaXMgPSAiUGHDrXMiLA0KICAgICAgICAgc2VjdG9yID0gIlNlY3RvciIsDQogICAgICAgICBjYXJnbyA9ICJUdSBjYXJnby9uaXZlbDoiKSAlPiUgDQogIG11dGF0ZShjYXJnbyA9IGZhY3RvcihjYXJnbywNCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIk1hbmFnZW1lbnQiLCAiTMOtZGVyIiwgIkNvbnRyaWJ1aWRvciBpbmRpdmlkdWFsIikpKQ0KDQojIENyZWEgY2F0ZWdvcsOtYXMgZGUgcmVzdWx0YWRvcw0KDQplbmMgPC0gZW5jICU+JSANCiAgbXV0YXRlKHJlc3VsdGFkbyA9IGlmX2Vsc2UodmFsb3IgPT0gIlRvdGFsbWVudGUgZGUgYWN1ZXJkbyIsICJQb3NpdGl2byIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZl9lbHNlKHZhbG9yID09ICJEZSBhY3VlcmRvIiwgIlBvc2l0aXZvIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZSh2YWxvciA9PSAiTmkgZGUgYWN1ZXJkbyBuaSBlbiBkZXNhY3VlcmRvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOZXV0cmFsIiwgIk5lZ2F0aXZvIg0KICAgICAgKQ0KICAgICkNCiAgKSwNCiAgICAgICAgIHJlc3VsdGFkbyA9IGZhY3RvcihyZXN1bHRhZG8sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlBvc2l0aXZvIiwgIk5ldXRyYWwiLCAiTmVnYXRpdm8iKSkpDQoNCmBgYA0KDQo+IFkgY29tZW50ZW4gZWwgY8OzZGlnbyBwb3IgYW1vciBhIEplYsO6cyENCg0KIVtdKGZpbGVzL2NvbWVudGVuLnBuZyl7d2lkdGg9IjMwMCJ9DQoNCiMjIFBvbmVyIGVsIG5vbWJyZSBhIGxvcyBibG9xdWVzIGRlIGPDs2RpZ28NCg0KQWxnbyBtdXkgw7p0aWwgZXMgcG9uZXJsZSBub21icmUgYSBsb3MgYmxvcXVlcyBkZSBjw7NkaWdvLiBQb3IgdW4gbGFkbyBwb3JxdWUgZXMgZsOhY2lsIHBhcmEgbmF2ZWdhciBlbnRyZSBibG9xdWVzIGJ1c2PDoW5kb2xvcyBlbiBSU3R1ZGlvLg0KDQpQb3IgZWplbXBsbywgcHJvYmVtb3MgdW4gZ3LDoWZpY28gc2ltcGxlOg0KDQpgYGB7ciBncmFmaWNvMX0NCmdncGxvdChlbmMsIGFlcyh4ID0gcGFpcywgZmlsbCA9IHJlc3VsdGFkbykpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyhjb2xvcjMpKSArDQogIGVzdGlsb2ggKw0KICBlamVfeV9wZXIgKw0KICBsYWJzKHRpdGxlID0gIlJlc3VsdGFkb3MgcG9yIHBhw61zIiwNCiAgICAgICBmaWxsID0gIlJlc3VsdGFkbyIsDQogICAgICAgeCA9ICIiLCB5ID0gIiIsDQogICAgICAgY2FwdGlvbiA9IGZ1ZW50ZSkNCmBgYA0KDQpQdWVkZSBvY3VycmlyIHF1ZSBuZWNlc2l0ZW1vcyByZXV0aWxpemFyIGVsIGdyw6FmaWNvLiBIYWNlciBsYSBncmFuICpzdGFja292ZXJmbG93KiAoY29waWFyIHkgcGVnYXIgZWwgY8OzZGlnbykgZXMgdW5hIG9wY2nDs24sIHBlcm8gcHVlZGUgZ2VuZXJhciBlcnJvcmVzIHkgcG9yIG90cm8gbGFkbyBpbXBsaWNhIHRpZW1wbyBkZSBwcm9jZXNhbWllbnRvLg0KDQpFbiBjYW1iaW8sIGNvbiBsYSBvcGNpw7NuIGByZWYubGFiZWxgIHBvZGVtb3MgcmV1dGlsaXphciBsbyBxdWUgaGljaW1vcyBhbnRlcywgZGUgdW5hIGZvcm1hIG3DoXMgcHJvbGlqYSB5IGPDs21vZGEgcGFzYW5kbyBlbCBub21icmUgZGVsIGJsb3F1ZSBhbnRlcmlvci4NCg0KSW50ZXJuYW1lbnRlLCBsbyBxdWUgaGFjZSBSIGVzIHJldXRpbGl6YXIgZWwgY8OzZGlnbyBjcmVhZG8gYW50ZXJpb3JtZW50ZS4NCg0KYGBge3IgZWplbXBsbzEsIGV2YWw9RkFMU0V9DQp7ciByZWYubGFiZWw9ImdyYWZpY28xIn0NCmBgYA0KDQpWb2lsw6EhDQoNCmBgYHtyIHJlZi5sYWJlbD0iZ3JhZmljbzEifQ0KDQpgYGANCg0KIyMgRXRpcXVldGFzIGxhcmdhcw0KDQpBIHZlY2VzIG5lY2VzaXRhbW9zIHByZXNlbnRhciBlbiB1biBncsOhZmljbyBvIGVuIHVuYSB0YWJsYSBsYSBwcmVndW50YSBvcmlnaW5hbCBkZSBsYSBlbmN1ZXN0YS4gUG9yIGVqZW1wbG8sIHVuYSBkZSBsYXMgInByZWd1bnRhcyIgZGUgbGEgZW5jdWVzdGEgZGljZToNCg0KPiAqYHIgZW5jWzIsN11gKg0KDQpBaG9yYSB2ZWFtb3MgY8OzbW8gc2UgdmVuIGxhcyBwcmVndW50YXMgZW4gdW4gZ3LDoWZpY28gc2kgaW50ZW50YW1vcyBoYWNlciB1biByYW5raW5nLg0KDQpgYGB7ciBldGlxLWxhcmdhc30NCmVuYyAlPiUgDQogIGdyb3VwX2J5KHByZWd1bnRhLCByZXN1bHRhZG8pICU+JSANCiAgc3VtbWFyaXNlKGNhbnQgPSBuKCkpICU+JSANCiAgbXV0YXRlKHByb3AgPSBjYW50L3N1bShjYW50KSkgJT4lIA0KICBmaWx0ZXIocmVzdWx0YWRvID09ICJQb3NpdGl2byIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gcHJvcCwgeSA9IHByZWd1bnRhKSkgKw0KICBnZW9tX2NvbChmaWxsID0gdmVyZGUpICsNCiAgZXN0aWxvdiArDQogIGVqZV94X3BlciArDQogIGxhYnModGl0bGUgPSAiUmFua2luZyBkZSBSZXNwdWVzdGFzIFBvc2l0aXZhcyIsDQogICAgICAgeCA9ICIiLCB5ID0gIiIsDQogICAgICAgY2FwdGlvbiA9IGZ1ZW50ZSkNCmBgYA0KDQpRdWVkYSBoZXJtb3NvLCBubz8g8J+YsQ0KDQpQYXJhIHNvcnRlYXIgZXN0ZSBwcm9ibGVtYSBwb2RlbW9zIGNyZWFyIHVuYSBjb2x1bW5hIG51ZXZhLCB5IHVzYXIgbGEgZnVuY2nDs24gYHN0cl93cmFwKClgIGRlbCBwYXF1ZXRlICpzdHJpbmdyKi4NCg0KTG8gcXVlIGhhY2UgZXN0byBlcyBhZ3JlZ2FyIGVsIHPDrW1ib2xvIGBcbmAgcXVlIGRpdmlkZSBlbCB0ZXh0byBlbiByZW5nbG9uZXMuIENvbiBlbCBwYXLDoW1ldHJvIGB3aWR0aGAgbGUgaW5kaWNhbW9zIGxhIGNhbnRpZGFkIGRlIGNhcmFjdGVyZXMgZGUgbGFyZ28gcXVlIHRlbmRyw6EgY2FkYSByZW5nbMOzbi4NCg0KYGBge3IgZXRpcS1sYXJnYXMxfQ0KIyBEaXZpZGUgZWwgbGFyZ28gZGUgJ2Z1bmNpw7NuJyBlbiB2YXJpYXMgbMOtbmVhcw0KZW5jJHByZWcyIDwtIHN0cl93cmFwKGVuYyRwcmVndW50YSwgd2lkdGggPSA0MCkNCg0KIyBWZWFtb3MgY29tbyBxdWVkYSBlc3RvIGVuIGVsIGRmDQpoZWFkKGVuYyRwcmVnMiw1KQ0KDQpgYGANCg0KWSBhaG9yYSBwb2RlbW9zIGhhY2VyIHVuIGdyw6FmaWNvIHF1ZSBzZSB2ZWEgYmllbjoNCg0KYGBge3IgZXRpcS1sYXJnYXMyfQ0KZW5jICU+JSANCiAgZ3JvdXBfYnkocHJlZzIsIHJlc3VsdGFkbykgJT4lIA0KICBzdW1tYXJpc2UoY2FudCA9IG4oKSkgJT4lIA0KICBtdXRhdGUocHJvcCA9IGNhbnQvc3VtKGNhbnQpKSAlPiUgDQogIGZpbHRlcihyZXN1bHRhZG8gPT0gIlBvc2l0aXZvIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBwcm9wLCB5ID0gcmVvcmRlcihwcmVnMiwgcHJvcCkpKSArDQogIGdlb21fY29sKGZpbGwgPSB2ZXJkZSkgKw0KICBlc3RpbG92ICsNCiAgZWplX3hfcGVyICsNCiAgbGFicyh0aXRsZSA9ICJSYW5raW5nIGRlIFJlc3B1ZXN0YXMgUG9zaXRpdmFzIiwNCiAgICAgICB4ID0gIiIsIHkgPSAiIiwNCiAgICAgICBjYXB0aW9uID0gZnVlbnRlKQ0KYGBgDQoNCkFob3JhIHF1ZWRhIG11Y2hvIG1lam9yIGByIGVtbzo6amkoIisxIilgDQoNClRhbWJpw6luIHNlIHB1ZWRlIGp1Z2FyIGNvbiBsYSBhbHR1cmEgZGVsIGdyw6FmaWNvIHVzYW5kbyBsYSBvcGNpw7NuIGBmaWcuaGVpZ2h0YCBlbiBsYXMgb3BjaW9uZXMgZGVsIGJsb3F1ZSBwYXJhIHF1ZSBoYXlhIG3DoXMgZXNwYWNpbyBlbnRyZSBsYXMgYmFycmFzLg0KDQpgYGB7ciBlajIsIGV2YWw9RkFMU0V9DQp7ciBmaWcuaGVpZ2h0PTh9ICMgRWwgdGFtYcOxbyBlcyBleGFnZXJhZG8gZW4gZXN0ZSBjYXNvDQpgYGANCg0KYGBge3IgZXRpcS1sYXJnYXMzLCBmaWcuaGVpZ2h0PTh9DQpyYW5raW5nIDwtIGVuYyAlPiUgDQogIGdyb3VwX2J5KHByZWcyLCByZXN1bHRhZG8pICU+JSANCiAgc3VtbWFyaXNlKGNhbnQgPSBuKCkpICU+JSANCiAgbXV0YXRlKHByb3AgPSBjYW50L3N1bShjYW50KSkgJT4lIA0KICBmaWx0ZXIocmVzdWx0YWRvID09ICJQb3NpdGl2byIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gcHJvcCwgeSA9IHJlb3JkZXIocHJlZzIsIHByb3ApKSkgKw0KICBnZW9tX2NvbChmaWxsID0gdmVyZGUpICsNCiAgZXN0aWxvdiArDQogIGVqZV94X3BlciArDQogIGxhYnModGl0bGUgPSAiUmFua2luZyBkZSBSZXNwdWVzdGFzIFBvc2l0aXZhcyIsDQogICAgICAgeCA9ICIiLCB5ID0gIiIsDQogICAgICAgY2FwdGlvbiA9IGZ1ZW50ZSkNCg0KcmFua2luZw0KYGBgDQoNCiMjIFRleHRvIGVuIGxvcyBncsOhZmljb3MNCg0KRXMgc2ltcGxlIGFncmVnYXIgbGFzIGV0aXF1ZXRhcyBkZSBkYXRvcyBhIHVuIGdyw6FmaWNvOg0KDQpgYGB7ciB0ZXh0bzF9DQpyYW5raW5nICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnQocHJvcCwgIyBNdWVzdHJhIGxvcyByZXN1bHRhZG9zIGNvbW8gcG9yY2VudGFqZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2N1cmFjeSA9IDEpKSwgIyBJbmRpY2EgbGEgY2FudGlkYWQgZGUgZGVjaW1hbGVzDQogICAgICAgICAgICBzaXplID0gMywgICAgICAgICAgICAgICAgICAgICAgICAgICAjIENhbWJpYSBlbCB0YW1hw7FvIGRlIGxhIGxldHJhDQogICAgICAgICAgICBoanVzdCA9IDEuMiwgICAgICAgICAgICAgICAgICAgICAgICAjIE11ZXZlIGxhIGV0aXF1ZXRhIHBhcmEgbGEgaXpxdWllcmRhDQogICAgICAgICAgICBmYW1pbHkgPSAiVWJ1bnR1IE1vbm8iKSANCmBgYA0KDQpNaXJlbW9zIGxvIHF1ZSBwYXNhIGN1YW5kbyBxdWVyZW1vcyBhZ3JlZ2FyIG3DoXMgaW5mb3JtYWNpw7NuIGFsIGdyw6FmaWNvLCBwb3IgZWplbXBsbywgY29uIGxvcyByZXN1bHRhZG9zIHBvciBwYcOtcy4NCg0KYGBge3IgdGV4dG8yfQ0KcmFua2luZyA8LSBlbmMgJT4lIA0KICBncm91cF9ieShwYWlzLCBwcmVnMiwgcmVzdWx0YWRvKSAlPiUgDQogIHN1bW1hcmlzZShjYW50ID0gbigpKSAlPiUgDQogIG11dGF0ZShwcm9wID0gY2FudC9zdW0oY2FudCkpICU+JSANCiAgZmlsdGVyKHJlc3VsdGFkbyA9PSAiUG9zaXRpdm8iKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHByb3AsIHkgPSByZW9yZGVyKHByZWcyLCBwcm9wKSwgZmlsbCA9IHBhaXMpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBlc3RpbG92ICsNCiAgZWplX3hfcGVyICsNCiAgbGFicyh0aXRsZSA9ICJSYW5raW5nIGRlIFJlc3B1ZXN0YXMgUG9zaXRpdmFzIiwNCiAgICAgICB4ID0gIiIsIHkgPSAiIiwNCiAgICAgICBmaWxsID0gIlBhw61zIiwNCiAgICAgICBjYXB0aW9uID0gZnVlbnRlKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAyKQ0KDQpyYW5raW5nICsNCiAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50KHByb3AsICMgTXVlc3RyYSBsb3MgcmVzdWx0YWRvcyBjb21vIHBvcmNlbnRhamUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNjdXJhY3kgPSAxKSksICMgSW5kaWNhIGxhIGNhbnRpZGFkIGRlIGRlY2ltYWxlcw0KICAgICAgICAgICAgc2l6ZSA9IDMsICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBDYW1iaWEgZWwgdGFtYcOxbyBkZSBsYSBsZXRyYQ0KICAgICAgICAgICAgaGp1c3QgPSAxLjIsICAgICAgICAgICAgICAgICAgICAgICAgIyBNdWV2ZSBsYSBldGlxdWV0YSBwYXJhIGxhIGl6cXVpZXJkYQ0KICAgICAgICAgICAgZmFtaWx5ID0gIlVidW50dSBNb25vIikgICAgICAgICAgICAgIyBNb2RpZmljYSBsYSBmdWVudGUNCmBgYA0KDQpFbCBwcm9ibGVtYSBlcyBxdWUgdG9kYXMgbGFzIGV0aXF1ZXRhcyBkZSBjYWRhIGJhcnJhIGVzdMOhbiBjZW50cmFkYXMgY29uIGxhIGV0aXF1ZXRhIGRlbCBlamUgKnkqLiBFbiBsYSBndcOtYSBkZSBgZ2VvbV90ZXh0YCBlbiBsYSBkb2N1bWVudGFjacOzbiBkZSBgZ2dwbG90MmAgW2VuY29udHJhbW9zIGNvbW8gc29sdWNpb25hciBlbCBwcm9ibGVtYV0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2dlb21fdGV4dC5odG1sKSB1c2FuZG8gZWwgcGFyw6FtZXRybyBgcG9zaXRpb25fZG9kZ2UoKWAuDQoNCmBgYHtyIHRleHQzfQ0KcmFua2luZyA8LSByYW5raW5nICsNCiAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50KHByb3AsICMgTXVlc3RyYSBsb3MgcmVzdWx0YWRvcyBjb21vIHBvcmNlbnRhamUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNjdXJhY3kgPSAxKSksICMgSW5kaWNhIGxhIGNhbnRpZGFkIGRlIGRlY2ltYWxlcw0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpLCAgICAgIyBBY29tb2RhIGNhZGEgZXRpcXVldGEgY29uIGxhcyBiYXJyYXMNCiAgICAgICAgICAgIHNpemUgPSAzLCAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQ2FtYmlhIGVsIHRhbWHDsW8gZGUgbGEgbGV0cmENCiAgICAgICAgICAgIGhqdXN0ID0gMS4yLCAgICAgICAgICAgICAgICAgICAgICAgICMgTXVldmUgbGEgZXRpcXVldGEgcGFyYSBsYSBpenF1aWVyZGENCiAgICAgICAgICAgIGZhbWlseSA9ICJVYnVudHUgTW9ubyIpICAgICAgICAgICAgICMgTW9kaWZpY2EgbGEgZnVlbnRlDQoNCnJhbmtpbmcNCmBgYA0KDQpPdHJhIG1lam9yYSBxdWUgcG9kZW1vcyBoYWNlciBhbCBncsOhZmljbyBlcyBhY29tb2RhciBsb3MgY29sb3JlcyBlbiBsYSBsZXllbmRhIChsYSByZWZlcmVuY2lhIGRlIGxvcyBjb2xvcmVzKSBwYXJhIHF1ZSB0ZW5nYW4gbGEgbWlzbWEgc2VjdWVuY2lhIHF1ZSB0aWVuZSBlbiBlbCBncsOhZmljbywgZXMgZGVjaXIgcXVlIGVsIHZlcmRlIG9zY3VybyBhcGFyZXpjYSBwcmltZXJvIGFsIGlndWFsIHF1ZSBsYSBiYXJyYSBjb24gZWwgdmVyZGUgbcOhcyBvc2N1cm8gZW4gZWwgZ3LDoWZpY28uDQoNCkVuIFtlc3RhIHDDoWdpbmFdKGh0dHBzOi8vd3d3LmRhdGFub3ZpYS5jb20vZW4vYmxvZy9nZ3Bsb3QtbGVnZW5kLXRpdGxlLXBvc2l0aW9uLWFuZC1sYWJlbHMvKSBoYXkgbXVjaGFzIHZhcmlhbnRlcyBwYXJhIHRyYWJhamFyIGNvbiBsYXMgZXRpcXVldGFzIHkgbGV5ZW5kYXMuDQoNCmBgYHtyIHRleHRvNH0NCnJhbmtpbmcgKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlPVRSVUUpKSArICMgSW52aWVydGUgZWwgb3JkZW4gZGUgbG9zIGNvbG9yZXMgZW4gbGEgbGV5ZW5kYQ0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQpDdWFuZG8gZXN0YW1vcyBtYXBlYW5kbyB1bmEgdmFyaWFibGUgY2F0ZWfDs3JpY2EgZW4gZWwgZWplICp5KiwgUiBsbyBvcmRlbmEgYWxmYWLDqXRpY2FtZW50ZSBkZXNkZSAqYWJham8qICoqaGFjaWEqKiAqYXJyaWJhKi4NCg0KYGBge3IgdGV4dG95fQ0KZW5jICU+JSANCiAgZ3JvdXBfYnkoc2VjdG9yLCByZXN1bHRhZG8pICU+JSANCiAgc3VtbWFyaXNlKGNhbnQgPSBuKCkpICU+JSANCiAgbXV0YXRlKHByb3AgPSBjYW50L3N1bShjYW50KSkgJT4lIA0KICBmaWx0ZXIocmVzdWx0YWRvID09ICJQb3NpdGl2byIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gcHJvcCwgeSA9IHNlY3RvcikpICsNCiAgZ2VvbV9jb2woZmlsbCA9IHZlcmRlKSArDQogIGVzdGlsb3YgKw0KICBlamVfeF9wZXIgKw0KICBsYWJzKHRpdGxlID0gIlJlc3VsdGFkbyBQb3NpdGl2b3MgcG9yIFNlY3RvciIsDQogICAgICAgeCA9ICIiLCB5ID0gIiIsDQogICAgICAgY2FwdGlvbiA9IGZ1ZW50ZSkNCmBgYA0KDQpQb2RlbW9zIHVzYXIgbGEgZnVuY2nDs24gYGZjdF9yZXZgIGRlbCBwYXF1ZXRlICpmb3JjYXRzKiBwYXJhIHBvbmVyIGFsIHJldsOpcyBsYXMgZXRpcXVldGFzIGRlbCBlamUgKnkqIGN1YW5kbyBlc3RhbW9zIG1hcGVhbmRvIGxhcyB2YXJpYWJsZXMgZGVudHJvIGRlIGBnZ3Bsb3RgDQoNCmBgYHtyIHRleHRveTJ9DQplbmMgJT4lIA0KICBncm91cF9ieShzZWN0b3IsIHJlc3VsdGFkbykgJT4lIA0KICBzdW1tYXJpc2UoY2FudCA9IG4oKSkgJT4lIA0KICBtdXRhdGUocHJvcCA9IGNhbnQvc3VtKGNhbnQpKSAlPiUgDQogIGZpbHRlcihyZXN1bHRhZG8gPT0gIlBvc2l0aXZvIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBwcm9wLCB5ID0gZmN0X3JldihzZWN0b3IpKSkgKyAjIEludmVydGltb3MgZWwgb3JkZW4gZGVsIGVqZSB5DQogIGdlb21fY29sKGZpbGwgPSB2ZXJkZSkgKw0KICBlc3RpbG92ICsNCiAgZWplX3hfcGVyICsNCiAgbGFicyh0aXRsZSA9ICJSZXN1bHRhZG8gUG9zaXRpdm9zIHBvciBTZWN0b3IiLA0KICAgICAgIHggPSAiIiwgeSA9ICIiLA0KICAgICAgIGNhcHRpb24gPSBmdWVudGUpDQpgYGANCg0KUG9yIMO6bHRpbW8sIHVuYSBtZWpvcmEgYWRpY2lvbmFsIHF1ZSBwb2RlbW9zIGhhY2VyIGEgbG9zIGdyw6FmaWNvcyBhbnRlcmlvcmVzIGVzIGFsaW5lYXIgZWwgKip0w610dWxvKiogYSBsYSBpenF1aWVyZGEgZGVsIGdyw6FmaWNvIGFncmVnYW5kbyBlbCBwYXLDoW1ldHJvIGBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiYCBkZW50cm8gZGUgYHRoZW1lYC4NCg0KYGBge3IgdGV4dG95M30NCmVuYyAlPiUgDQogIGdyb3VwX2J5KHNlY3RvciwgcmVzdWx0YWRvKSAlPiUgDQogIHN1bW1hcmlzZShjYW50ID0gbigpKSAlPiUgDQogIG11dGF0ZShwcm9wID0gY2FudC9zdW0oY2FudCkpICU+JSANCiAgZmlsdGVyKHJlc3VsdGFkbyA9PSAiUG9zaXRpdm8iKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHByb3AsIHkgPSBmY3RfcmV2KHNlY3RvcikpKSArICMgSW52ZXJ0aW1vcyBlbCBvcmRlbiBkZWwgZWplIHkNCiAgZ2VvbV9jb2woZmlsbCA9IHZlcmRlKSArDQogIGVzdGlsb3YgKw0KICBlamVfeF9wZXIgKw0KICBsYWJzKHRpdGxlID0gIlJlc3VsdGFkbyBQb3NpdGl2b3MgcG9yIFNlY3RvciIsDQogICAgICAgeCA9ICIiLCB5ID0gIiIsDQogICAgICAgY2FwdGlvbiA9IGZ1ZW50ZSkgKw0KICB0aGVtZShwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiKQ0KYGBgDQoNCiMjIEZ1bmNpb25lcw0KDQpFc3RvIGVzIHVuICp3b3JrLWluLXByb2dyZXNzKiB5IHRlbmdvIHF1ZSBhZ3JhZGVjZXIgYSBbTcOzbmljYSBBbG9uc29dKGh0dHBzOi8vdHdpdHRlci5jb20vTW9uaWNhTEEyMDAwKSBkZSBSTGFkaWVzIEJ1ZW5vcyBBaXJlcyBwb3IgbGEgYXl1ZGEuDQoNCkVsIHByb2JsZW1hIGVzIHF1ZSBtZSBlbmNvbnRyw6kgbXVjaGFzIHZlY2VzIGVzY3JpYmllbmRvIGVzdGEgc2VjdWVuY2lhIGRlIGPDs2RpZ28gbXVjaGFzIHZlY2VzOg0KDQpgYGB7ciBmdW4xfQ0KIyBDYWxjdWxhciBwb2NlcnRhamVzIGRlIHJlc3B1ZXN0YXMNCmVuYyAlPiUgDQogIGdyb3VwX2J5KGdlbmVybywgcmVzdWx0YWRvKSAlPiUgDQogIHN1bW1hcmlzZShjYW50ID0gbigpKSAlPiUgDQogIG11dGF0ZShwcm9wID0gY2FudCAvIHN1bShjYW50KSkNCmBgYA0KDQpNdWNoYXMgdmVjZXMgcmVzb2x2w60gY29waWFuZG8geSBwZWdhbmRvIGVsIGPDs2RpZ28sIHBlcm8gc2UgaGFjZSB0ZWRpb3NvIGNvbnRyb2xhciBjYWRhIHVubyBkZSBsb3MgYmxvcXVlcyBkZSBjw7NkaWdvIHkgZ3LDoWZpY29zLiBBc8OtIHF1ZSBwYXJhIGVzbywgcG9kZW1vcyBjcmVhciBudWVzdHJhcyBwcm9waWFzIGZ1bmNpb25lcy4NCg0KYGBge3IgZnVuMn0NCmNhbnRfcHJvcF9nZW4gPC0gZnVuY3Rpb24oZGYpew0KICBkZiAlPiUgDQogICAgZ3JvdXBfYnkoZ2VuZXJvLHJlc3VsdGFkbykgJT4lIA0KICAgIHN1bW1hcmlzZShjYW50ID0gbigpKSAlPiUgDQogICAgbXV0YXRlKHByb3AgPSBjYW50IC8gc3VtKGNhbnQpKSANCn0NCmBgYA0KDQpZIGFob3JhIGxvIHBvZGVtb3MgaW5jb3Jwb3JhciBlbiBudWVzdHJvIGZsdWpvIGRlIHRyYWJham8gY29tbyBjdWFscXVpZXIgZnVuY2nDs24uDQoNCmBgYHtyIGZ1bjN9DQplbmMgJT4lIA0KICBjYW50X3Byb3BfZ2VuKCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBnZW5lcm8sIHkgPSBwcm9wLCBmaWxsID0gcmVzdWx0YWRvKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgZWplX3lfcGVyICsNCiAgZXN0aWxvaCArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yMykgKw0KICBsYWJzKHRpdGxlID0gIlJlc3VsdGFkb3MgcG9yIEfDqW5lcm8iLA0KICAgICAgIHggPSAiIiwgeSA9ICIiLA0KICAgICAgIGZpbGwgPSAiUmVzdWx0YWRvIiwNCiAgICAgICBjYXB0aW9uID0gZnVlbnRlKQ0KYGBgDQoNClRvZGF2w61hIGVzdG95IHJlc29sdmllbmRvIGNvbW8gY3JlYXIgZnVuY2lvbmVzIHVzYW5kbyBjdWFscXVpZXIgdGlwbyBkZSB2YXJpYWJsZSBlbiBsYSBmdW5jacOzbi4gUG9yIGFob3JhLCBsbyBlc3RveSByZXNvbHZpZW5kbyBjcmVhbmRvIHVuYSBmdW5jacOzbiBwYXJhIGNhZGEgY29tYmluYWNpw7NuIGRlIHZhcmlhYmxlcyBxdWUgYWdydXBvLiBObyBlcyBsbyBpZGVhbCwgcGVybyBlcyBsbyBxdWUgaGF5LiDwn6S3DQoNCkNhcGF6IGVuY3VlbnRyZSBsbyBxdWUgbmVjZXNpdG8gZW4gZXN0b3MgbGlicm9zOg0KDQotICAgW1IgcGFyYSBDaWVuY2lhIGRlIERhdG9zXShodHRwczovL2VzLnI0ZHMuaGFkbGV5Lm56LykNCi0gICBbSGFuZHMtT24gUHJvZ3JhbW1pbmcgd2l0aCBSXShodHRwczovL3JzdHVkaW8tZWR1Y2F0aW9uLmdpdGh1Yi5pby9ob3ByLykNCi0gICBbQWR2YW5jZWQgUl0oaHR0cHM6Ly9hZHYtci5oYWRsZXkubnovaW5kZXguaHRtbCkNCg0KWWEgbGVzIGNvbnRhcsOpLi4uIHN0YXkgdHVuZWQg8J+Tug0KDQojIyBDw7NkaWdvIElubGluZQ0KDQpDb21vIHNhYmVtb3MsIGFsZ28gaW50ZXJlc2FudGUgZGUgUk1hcmtkb3duIGVzIGxhIHBvc2liaWxpZGFkIGRlIHV0aWxpemFyIGVsIGPDs2RpZ28gZGUgbG9zIGJsb3F1ZXMgZGVudHJvIGRlbCB0ZXh0by4NCg0KQXPDrSBxdWUgY3JlZW1vcyB1biBwZXF1ZcOxbyBvYmpldG8gcHJpbWVybyBwYXJhIGFsbWFjZW5hciBsb3MgcmVzdWx0YWRvcyBwb3NpdGl2b3MgeSBuZWdhdGl2b3MgcG9yIGfDqW5lcm8uDQoNCmBgYHtyIGNvZC1pbmx9DQpyZXN1bHRfZ2VuZXJvIDwtIGVuYyAlPiUgDQogIGNhbnRfcHJvcF9nZW4oKQ0KDQpyZXN1bHRfZ2VuZXJvDQpgYGANCg0KVXNhbmRvIGxhIGxsYW1hZGEgZGUgZGF0b3MgZGUgdW4gZGF0YWZyYW1lIGNvbiBgbm9tYnJlX2RmW2ZpbGEsY29sdW1uYV1gIHB1ZWRvIHVzYXIgbG9zIHJlc3VsdGFkb3MgYWxtYWNlbmFkb3MgcGFyYSBpbmNsdWlybG9zIGRlbnRybyBkZWwgdGV4dG8gcG9yIGVqZW1wbG8gcGFyYSBkZWNpcjoNCg0KKkxvcyByZXN1bHRhZG9zIHBvc2l0aXZvcyBwYXJhIGxhcyBwZXJzb25hcyBkZSBnw6luZXJvIGZlbWVuaW5vIGVzIGByIHJlc3VsdF9nZW5lcm9bMSw0XWAqLg0KDQpMbyBpZGVhbCBlcyBwb2RlciB2ZXIgZXNlIHJlc3VsdGFkbyBjb21vIHVuIHBvcmNlbnRhamUsIGFzw60gcXVlIGludHVpdGl2YW1lbnRlIHBvZGVtb3MgdXNhciBsYSBmdW5jacOzbiBgcGVyY2VudGAgcGFyYSBsb2dyYXIgZXNvLi4uDQoNCi4uLnkgbm8gdmEgYSBmdW5jaW9uYXIuIE9idGVuZW1vcyBlbCBzaWd1aWVudGUgbWVuc2FqZSBkZSBlcnJvcjoNCg0KYGBge3IgZXZhbD1GQUxTRX0NCiMgSW50ZW50byBkZSBjw7NkaWdvIGlubGluZQ0KYHIgcGVyY2VudChyZXN1bHRfZ2VuZXJvWzEsNF0pYA0KDQojIFF1aXR0aW5nIGZyb20gbGluZXMgNDI1LTQ0MSAocjRocl9taWNyb2FwcmVuZGl6YWplcy5SbWQpIA0KIyBFcnJvciBpbiBpcy5maW5pdGUoeCkgOiBkZWZhdWx0IG1ldGhvZCBub3QgaW1wbGVtZW50ZWQgZm9yIHR5cGUgJ2xpc3QnDQpgYGANCg0KUGFyYSBxdWUgbGEgZnVuY2nDs24gYHBlcmNlbnRgIGZ1bmNpb25lIGxhIHRlbmVtb3MgcXVlIGNvbWJpbmFyIGNvbiBsYSBmdW5jacOzbiBgcHVsbGAgLiBZIGFob3JhIGFzw60gc8OtIGZ1bmNpb25hOg0KDQoqTG9zIHJlc3VsdGFkb3MgcG9zaXRpdm9zIHBhcmEgbGFzIHBlcnNvbmFzIGRlIGfDqW5lcm8gZmVtZW5pbm8gZXMgYHIgcGVyY2VudChwdWxsKHJlc3VsdF9nZW5lcm9bMSw0XSkpYCogLg0KDQojIyAqVHJ1c3QgdGhlIFRpZHl2ZXJzZSoNCg0KPiAqTG8gYmFyYXRvIHNhbGUgY2FybyoNCj4NCj4gRGljaG8gcG9wdWxhcg0KDQohW10oaHR0cHM6Ly9saW50ZXJuYXN5Ym9zcXVlcy5maWxlcy53b3JkcHJlc3MuY29tLzIwMTgvMTAvbWVtZS1uby1jcmVhcy5wbmcpe3dpZHRoPSIzMDAifQ0KDQpMYSBlbmN1ZXN0YSBxdWUgZXN0w6FiYW1vcyBhbmFsaXphbmRvIGVyYSBhbsOzbmltYSwgbG8gY3VhbCBoYWPDrWEgaW1wb3NpYmxlIHBvZGVyIGNydXphciBkYXRvcyBjb250cmEgZWwgbGlzdGFkbyBkZSBlbXBsZWFkb3MuDQoNClBlcm8sIHPDrSBwb2TDrWFtb3MgY2FsY3VsYXIgbG9zIHJlc3VsdGFkb3Mgc2Vnw7puIGxhIGNvbXBvc2ljacOzbiBkZWwgbGlkZXJhemdvLiBQYXJhIGVzbyB0ZW7DrWFtb3MgcXVlIGNhbGN1bGFyIGVsIHBvcmNlbnRhamUgZGUgbMOtZGVyZXMgaG9tYnJlcyB5IG11amVyZXMgcG9yIHNlY3Rvci4NCg0KYGBge3IgdHJ1c3QxfQ0KDQojIEN1ZW50byBsYSBjYW50aWRhZCBkZSBsw61kZXJlcyBwb3Igc2VjdG9yIHkgZ8OpZW5lcm8NCnBsYW50ZWwgPC0gcGxhbnRlbCAlPiUgDQogIHJlbmFtZShkaXZpc2lvbiA9IGBVbmlkYWQgZGUgTmVnb2Npb2AsIA0KICAgICAgICAgbGlkZXIgPSBMw61kZXIsIA0KICAgICAgICAgc2V4byA9IEfDqW5lcm8sIA0KICAgICAgICAgc2VjdG9yID0gU2VjdG9yLCANCiAgICAgICAgIHBhaXMgPSBQYcOtcykgJT4lIA0KICBmaWx0ZXIobGlkZXIgPT0gInRydWUiKSAlPiUgDQogIGdyb3VwX2J5KHBhaXMsIGRpdmlzaW9uLCBzZWN0b3IsIGxpZGVyLCBzZXhvKSAlPiUgDQogIHRhbGx5KCkgJT4lIA0KICB1bmdyb3VwKCkNCg0KcGxhbnRlbA0KDQpgYGANCg0KYGBge3IgdHJ1c3QyfQ0KIyBQaXZvdGVvIGVsIGRhdGFzZXQgYSB1biBkYXRhc2V0IGFuY2hvDQoocGxhbnRlbCA8LSBwbGFudGVsICU+JSANCiAgcGl2b3Rfd2lkZXIoLiwNCiAgICAgICAgICAgICAgbmFtZXNfZnJvbSA9IHNleG8sDQogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gbikpDQoNCg0KDQpgYGANCg0KYGBge3IgdHJ1c3QzfQ0KIyBSZWVtcGxhemEgbG9zIE5BIGNvbiB1biAwDQpwbGFudGVsW2lzLm5hKHBsYW50ZWwpXSA8LSAwDQoNCnBsYW50ZWwNCg0KDQpgYGANCg0KVGVybWluYWRvcyBlc29zIHBhc29zIHB1ZWRvIGNhbGN1bGFyIGVsIHBvcmNlbnRhamUgZGUgbMOtZGVyZXMgaG9tYnJlcyBwb3IgcGHDrXMsIHVuaWRhZCBkZSBuZWdvY2lvIHkgc2VjdG9yIHBhcmEgaW5jb3Jwb3JhcmxvIGVuIGVsIGFuw6FsaXNpcy4NCg0KYGBge3IgdHJ1c3Q0fQ0KIyBDYWxjdWxvIHBvcmNlbnRhamUgZGUgbMOtZGVyZXMgaG9tYnJlcw0KcGxhbnRlbCAlPiUgDQogIG11dGF0ZShwcm9wX2xpZGVyX2hvbWJyZSA9IGlmX2Vsc2UoRmVtZW5pbm8gPT0gMCwgICAgICAgICAjIENvbmRpY2nDs24NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAgICAgICAgICAgICAgICAgICAgICMgVmFsb3Igc2kgY3VtcGxlIGNvbmRpY2nDs24NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNYXNjdWxpbm8gLyAoTWFzY3VsaW5vICtGZW1lbmlubykpKSAlPiUgIyBWYWxvciBzaSBubyBjdW1wbGUNCiAgc2VsZWN0KC1saWRlcikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgRWxpbWluYSBjb2x1bW5hICdsw61kZXInDQpgYGANCg==