
Presentación
En el marco del cálculo del costo de menstruar en Argentina, llevado a cabo desde la campaña #MenstruAcción y EcoFeminitas, en el presente documento de trabajo se encuentra la exploración, organización y limpieza de los datos obtenidos mediante el #MenstruScrapper, desarrollado por Nayla Portas de [LAS] de sistemas. El #MenstruScrapper fue ejecutado el día 17 de Septiembre de 2021 sobre la página Precios Claros, sumándose esta información a la obtenida anteriormente en Septiembre y Marzo de 2019, Marzo y Septiembre de 2020, y Marzo de 2021. En esta instancia, se obtuvieron 83.317 observaciones en total.
- Respecto de los tampones: Se obtuvieron 17.799 precios.
- Respecto de las toallitas: Se obtuvieron 65.518 precios.
En nuestro repositorio se encuentran aclaradas todas las fuentes adicionales a las que se recurrió para realizar el cálculo y los archivos correspondientes. En otro paso se encuentra el cálculo propiamente dicho del costo anual de menstruar.
Preparando el entorno de trabajo
Comenzamos levantando las librerías necesarias, cargando los datos srappeados desde el archivo .csv, y un diccionario que indica a qué región pertenece cada provincia del país.
library(EnvStats)
library(tidyverse)
library(ggridges)
library(openxlsx)
library(viridis)
library(readxl)
library(magrittr)
library(scales)
library(kableExtra)
datos <- read.csv("Fuentes/precios-gestion-menstrual-2021-09-17.csv",
header = TRUE, sep = ",", dec = ".",
fill = TRUE, encoding = "UTF-8")
regiones <- openxlsx::read.xlsx("Fuentes/provincias_regiones.xlsx")
Vista previa del dataset:
| | | | |
---|
1 | tampones | EQUATE | Tampon Higienico Mujer Equate Super 20 Un | |
2 | tampones | FARMACITY | Tampon Medio Farmacity Enjoy 8 Un | |
3 | tampones | FARMACITY | Tampon Medio Farmacity Enjoy 8 Un | |
4 | tampones | FARMACITY | Tampon Medio Farmacity Enjoy 8 Un | |
5 | tampones | FARMACITY | Tampon Medio Farmacity Enjoy 8 Un | |
6 | tampones | FARMACITY | Tampon Mini Farmacity Enjoy 8 Un | |
Vista previa del diccionario de regiones:
| | | | |
---|
1 | Buenos Aires | GBA | | |
2 | CABA | GBA | | |
3 | Mendoza | CUY | | |
4 | Córdoba | PAM | | |
5 | Río Negro | PAT | | |
6 | Neuquén | PAT | | |
Definimos una pequeña función: cant
nos va a devolver un número en formato character (texto), con cero dígitos, con un punto para separar los miles, y una coma para separar los decimales.
cant <- function(x){
format(x, digits = 0, big.mark = ".", decimal.mark = ",")}
Guardamos el valor de la fecha a la que corresponde el ejercicio.
date <- "Septiembre 2021"
Exploración de los datos
Al dataframe datos
le pegamos los valores de las regiones, usando como variable de identificación a la Provincia
. A continuación podemos borrar de nuestro entorno de trabajo el elemento regiones
.
datos <- left_join(datos, regiones, by = "Provincia")
rm(regiones)
datos
cuenta con 83.013 observaciones. A su vez, podemos ver con qué variables contamos en el dataset:
[1] "Categoría" "Marca" "Nombre" "Presentación" "Comercio" "Sucursal" "Dirección"
[8] "Localidad" "Provincia" "Precio.de.lista" "Region"
A continuación, exploraremos el comportamiento de las diferentes variables. Con count()
pedimos un conteo de observaciones para cada valor que toma la variable aclarada, con arrange()
ordenamos los datos de forma decreciente según el conteo anterior, y en mutate()
se definen nuevas variables para nuestro cuadro. Por ejemplo, el porcentaje es la cantidad de cada categoría sobre la suma de las mismas, expresada en formato de porcentaje.
Categorías
datos %>%
count(Categoría) %>%
arrange(-n) %>%
mutate(porcentaje = percent(n/sum(n)))
| | | | |
---|
toallitas | 65518 | 79% | | |
tampones | 17799 | 21% | | |
Cabe destacar que esta composición corresponde a la disponibilidad de precios, no refleja la estructura del consumo. O sea, no podemos decir que se consumen en un 80% toallitas y en 20% tampones. Lo que sí sabemos es que tenemos una muestra muy grande de precios para ambas categorías, aunque debemos tener en cuenta que la página de Precios Claros puede tener un sesgo por no incluir los comercios tradicionales sino únicamente grandes cadenas.
Marcas
datos %>%
count(Marca) %>%
arrange(-n) %>%
mutate(porcentaje = n/sum(n),
acumulado = cumsum(porcentaje),
porcentaje = percent(porcentaje),
acumulado = percent(acumulado))
| | | | |
---|
SIEMPRE LIBRE | 23249 | 27.9043% | 27.9043% | |
ALWAYS | 12032 | 14.4412% | 42.3455% | |
KOTEX | 7850 | 9.4218% | 51.7673% | |
O.B. | 7417 | 8.9021% | 60.6695% | |
BONTÉ | 7170 | 8.6057% | 69.2752% | |
LADYSOFT | 5625 | 6.7513% | 76.0265% | |
NOSOTRAS | 3743 | 4.4925% | 80.5190% | |
CARREFOUR | 3361 | 4.0340% | 84.5530% | |
FARMACITY | 2555 | 3.0666% | 87.6196% | |
LINA | 2548 | 3.0582% | 90.6778% | |
Contamos con 28 marcas de productos, aunque con 10 de ellas se completa el 90% del total de productos. Las primeras 3 marcas concentran casi la mitad de las observaciones. Nuevamente aquí hay que tener en cuenta que no se trata exactamente de una “concentración de mercado”.
Presentación
datos %>%
count(Presentación) %>%
arrange(-n) %>%
mutate(porcentaje = n/sum(n),
acumulado = cumsum(porcentaje),
porcentaje = percent(porcentaje),
acumulado = percent(acumulado))
| | | | |
---|
8.0 un | 45043 | 54.0622% | 54.0622% | |
16.0 un | 30897 | 37.0837% | 91.1459% | |
20.0 un | 2480 | 2.9766% | 94.1224% | |
10.0 un | 1308 | 1.5699% | 95.6924% | |
32.0 un | 1160 | 1.3923% | 97.0846% | |
24.0 un | 806 | 0.9674% | 98.0520% | |
14.0 un | 583 | 0.6997% | 98.7518% | |
30.0 un | 461 | 0.5533% | 99.3051% | |
15.0 un | 241 | 0.2893% | 99.5943% | |
7.0 un | 147 | 0.1764% | 99.7708% | |
Casi el 90% de los productos vienen en paquetes de 8 o 16 unidades. Luego seguiremos analizando esta variable en particular, porque nos interesa para calcular los precios unitarios de los productos, y hay valores (como “1.0 un”) que son raros y, en caso de tratarse de errores, podrían arrastrar problemas hacia el cálculo de esos precios.
Provincias
datos %>%
count(Provincia) %>%
arrange(-n) %>%
mutate(porcentaje = n/sum(n),
acumulado = cumsum(porcentaje),
porcentaje = percent(porcentaje),
acumulado = percent(acumulado))
| | | | |
---|
Buenos Aires | 27342 | 32.8168% | 32.82% | |
CABA | 27089 | 32.5132% | 65.33% | |
Córdoba | 4582 | 5.4995% | 70.83% | |
Río Negro | 3224 | 3.8696% | 74.70% | |
Neuquén | 2954 | 3.5455% | 78.24% | |
Entre Ríos | 2328 | 2.7941% | 81.04% | |
Chubut | 2233 | 2.6801% | 83.72% | |
Santa Cruz | 2009 | 2.4113% | 86.13% | |
Santa Fe | 1860 | 2.2324% | 88.36% | |
Salta | 1269 | 1.5231% | 89.89% | |
Si bien más de la mitad de las observaciones se concentran en Buenos Aires y CABA, es importante saber que se cuenta con información de todas las provincias del país, y que incluso en el peor de los casos (por ejemplo, 165 observaciones en Catamarca) se trata de una cantidad pasible de proveernos estimaciones útiles.
Regiones
datos %>%
count(Region) %>%
arrange(-n) %>%
mutate(porcentaje = n/sum(n),
acumulado = cumsum(porcentaje),
porcentaje = percent(porcentaje),
acumulado = percent(acumulado))
| | | | |
---|
GBA | 54431 | 65.3% | 65.3% | |
PAT | 11306 | 13.6% | 78.9% | |
PAM | 9796 | 11.8% | 90.7% | |
NOA | 3757 | 4.5% | 95.2% | |
NEA | 2554 | 3.1% | 98.2% | |
CUY | 1473 | 1.8% | 100.0% | |
En términos regionales seguimos viendo esa asimetría en la disponibilidad de datos, pero hay que tener en cuenta que efectivamente hay diferencias de escala de mercados en términos regionales.
Precio de lista
Ahora graficamos la distribución de los precios de lista (o sea, sin tener en cuenta las unidades por paquete) según cada categoría. Para ello utilizamos ggplot2
.
En la primer línea de código referida a ggplot
, tomamos como fuente el dataset que venimos utilizando (a eso refiere el punto), en el eje x
queremos los precios, en el eje y
queremos cada categoría, y el relleno de cada parte del gráfico también según las categorías de productos. En la segunda línea aclaramos que queremos un gráfico de densidad (que es como un histograma pero en versión continua), la escala hace a la superposición de los graficos y el bandwidth
o “ancho de banda” indica la extensión del intervalo de valores con los que se va a realizar la estimación del gráfico (o sea, si el gráfico va a ser más detallista y por ende más “ruidoso”, o más suave y “redondeado”). Se puede jugar con ambos valores para ver sus efectos. En la tercer línea aclaramos que queremos un tema minimalista, en la cuarta que la paleta de colores la vamos a asigna de manera manual, en la quinta que no queremos una leyenda aclarando los colores de cada categoría porque ya están aclaradas en el eje y. Y por último aclaramos las etiquetas necesarias.
datos %>%
ggplot(., aes(x = Precio.de.lista, y = Categoría, fill = Categoría)) +
geom_density_ridges(scale = 3, bandwidth = 20) +
theme_minimal() +
scale_fill_manual(values = c("red", "violetred")) +
theme(legend.position = "none") +
labs(title = "Precio de lista de productos de gestión menstrual según categoría",
subtitle = date,
x = "Precio de lista",
y = "",
caption = "Fuente: #MenstruAcción")

Por esta vez, filtramos de los datos los precios mayores a 1.000 pesos, basicamente porque hay casos (outliers que de hecho vamos a tener que corregir) que superan ese monto y “rompen” la escala del gráfico. Para una comprensión más acabada de este efecto, veamos qué sucede si quitamos estos valores que hasta superan los 15.000 pesos:
datos <- datos %>%
filter(Precio.de.lista < 1000)
datos %>%
ggplot(., aes(x = Precio.de.lista, y = Categoría, fill = Categoría)) +
geom_density_ridges(scale = 3, bandwidth = 20) +
theme_minimal() +
scale_fill_manual(values = c("red", "violetred")) +
theme(legend.position = "none") +
labs(title = "Precio de lista de productos de gestión menstrual según categoría",
subtitle = date,
x = "Precio de lista",
y = "",
caption = "Fuente: #MenstruAcción")

A primera vista, los niveles de precios de toallitas y tampones se distribuyen en una misma escala. En el caso de los tampones hay una distribución bimodal, que puede deberse a la amplia cantidad de presentaciones de 8 y 16 unidades.
También podemos graficar los precios de cada categoría por regiones:
datos %>%
ggplot(., aes(x = Precio.de.lista, y = Region, fill = Categoría, alpha = Region)) +
geom_density_ridges(scale = 2, bandwidth = 20) +
theme_minimal() +
scale_fill_manual(values = c("red", "violetred"))+
facet_wrap(. ~ Categoría) +
theme(legend.position = "none") +
labs(title = "Precio de lista de productos de gestión menstrual según categoría y región",
subtitle = date,
x = "Precio de lista",
y = "",
caption = "Fuente: #MenstruAcción")

En este caso se encuentran diferencias más que nada entre los tampones, no así en el caso de las toallitas. Dado el peso de GBA entre las observaciones, tiene sentido que la distribución general se asemeje a la de dicha región.
Limpieza de la cantidad de unidades (Presentación)
Como mencionábamos anteriormente, es necesario prestarle particular atención a la variable de Presentación
, que indica la cantidad de unidades por cada paquete. En primer lugar, teniendo en cuenta que está expresada como “X un.”, modificamos la variable para quedarnos únicamente con las unidades en formato numérico. Esto lo hacemos convirtiendo la variable al tipo character, y luego quedándonos con aquellos caracteres entre la primer posición y aquella que se encuentra 4 posiciones por detrás de la última (omitiendo así “.0 un”). En la tabla presentacion_nros
resumimos el comportamiento de esta nueva variable unidades
.
datos <- datos %>%
mutate(Presentación = as.character(Presentación),
unidades = as.numeric(substr(Presentación, 1, nchar(Presentación)-4)))
presentacion_nros <- datos %>%
count(unidades) %>%
arrange(-n) %>%
mutate(porcentaje = n/sum(n),
acumulado = cumsum(porcentaje),
porcentaje = percent(porcentaje),
acumulado = percent(acumulado))
presentacion_nros
| | | | |
---|
8 | 45041 | 54.1118% | 54.1118% | |
16 | 30851 | 37.0640% | 91.1758% | |
20 | 2480 | 2.9794% | 94.1552% | |
10 | 1308 | 1.5714% | 95.7267% | |
32 | 1160 | 1.3936% | 97.1203% | |
24 | 806 | 0.9683% | 98.0886% | |
14 | 583 | 0.7004% | 98.7890% | |
30 | 429 | 0.5154% | 99.3044% | |
15 | 241 | 0.2895% | 99.5939% | |
7 | 147 | 0.1766% | 99.7705% | |
Sin embargo, en la base puede verse que hay casos que, de acuerdo a la descripción en Nombre
, tienen mal la cantidad de unidades en Presentacion
(y por ende en unidades), afectando el calculo de precios unitarios.
Utilizando expresiones regulares podemos quedarnos con los dígitos, sean uno o más, que están seguidos de “Un” o “un” en la variable Nombre
. Nos quedamos con esta información en la variable unidades_regex
y resumimos su comportamiento.
datos <- datos %>%
mutate(unidades_regex = as.numeric(str_extract(Nombre, '\\d+(?=\\s*[Uu]n?)')))
presentacion_regex <- datos %>%
count(unidades_regex) %>%
arrange(-n) %>%
mutate(porcentaje = n/sum(n),
acumulado = cumsum(porcentaje),
porcentaje = percent(porcentaje),
acumulado = percent(acumulado))
presentacion_regex
| | | | |
---|
8 | 45169 | 54.2655% | 54.2655% | |
16 | 30862 | 37.0773% | 91.3428% | |
20 | 2480 | 2.9794% | 94.3222% | |
10 | 1308 | 1.5714% | 95.8937% | |
32 | 1160 | 1.3936% | 97.2873% | |
24 | 806 | 0.9683% | 98.2556% | |
14 | 583 | 0.7004% | 98.9560% | |
30 | 459 | 0.5514% | 99.5074% | |
15 | 241 | 0.2895% | 99.7970% | |
7 | 147 | 0.1766% | 99.9736% | |
Nótese que hay pequeñas diferencias respecto del cuadro anterior (en las 30 unidades por ejemplo). En este caso, las unidades se encuentran más concentradas en valores populares. Podemos identificar cuándo ambas informaciones (la contenida en unidades
y en unidades_regex
) coinciden y cuándo no. Creamos la variable igual
que toma valor TRUE cuando son iguales, y FALSE cuando no. A continuación, en la tabla comparo_unidades
se realiza un conteo de observaciones para ambas variables, se identifican las situaciones de coincidencia y diferencia y se ordenan los datos para ver primero las diferencias, según la magnitud.
datos <- datos %>%
mutate(igual = case_when(unidades == unidades_regex ~ T,
unidades != unidades_regex ~ F))
comparo_unidades <- datos %>%
count(unidades, unidades_regex) %>%
mutate(igual = case_when(unidades == unidades_regex ~ T,
unidades != unidades_regex ~ F)) %>%
arrange(igual, -n)
comparo_unidades
| | | | |
---|
1 | 8 | 77 | FALSE | |
16 | 8 | 49 | FALSE | |
27 | 16 | 40 | FALSE | |
1 | 30 | 30 | FALSE | |
1 | 16 | 20 | FALSE | |
50 | 8 | 2 | FALSE | |
8 | 8 | 45041 | TRUE | |
16 | 16 | 30802 | TRUE | |
20 | 20 | 2480 | TRUE | |
10 | 10 | 1308 | TRUE | |
En particular, hay casos que fueron informados como de 1 o 16 unidades y en realidad eran de 8 (tiene sentido que este último sea el verdadero valor), casos que fueron informados como de 1 o 27 unidades y en realidad eran de 16, o casos que fueron informados como de 1 unidad y en realidad eran de 30, etc. Como puede verse a continuación, hay en total 218 casos en que la información no coincide, lo que representa el 0.26% de la información (mejoró muchísimo en comparación a relevamientos anteriores), y sólo 6 casos en que no había información sobre la cantidad de unidades en la descripción del artículo.
datos %>%
group_by(igual) %>%
summarise(n = n()) %>%
mutate(porc = percent(n/sum(n)))
| | | | |
---|
FALSE | 218 | 0.26% | | |
TRUE | 83013 | 99.73% | | |
NA | 6 | 0.01% | | |
Vale la pena destacar que estos errores corresponden a todas las regiones, mayormente concentrados en GBA, y en 5 marcas diferentes.
datos %>%
filter(igual == FALSE) %>%
count(Region)
| | | | |
---|
CUY | 2 | | | |
GBA | 100 | | | |
NEA | 7 | | | |
NOA | 35 | | | |
PAM | 44 | | | |
PAT | 30 | | | |
datos %>%
filter(igual == FALSE) %>%
count(Marca)
| | | | |
---|
CALIPSO | 2 | | | |
KOTEX | 52 | | | |
LADYSOFT | 109 | | | |
NOSOTRAS | 30 | | | |
SIEMPRE LIBRE | 25 | | | |
Aclaración
En un ejercicio anterior (septiembre 2019), prescindimos de los valores faltantes en unidades_regex
(por más que tengan valor en unidades
, aquella que surge de la variable Presentación
). Verificamos aquellos casos en que unidades_regex
(que surge del texto en Nombre
) no coincide con la variable unidades
, y establecimos que las cantidades referidas a las unidades por paquete parecen ser mejor captadas con el método de regex sobre el texto del Nombre
del producto, respecto de lo surgido de la información de la página como Presentación
. Nos quedamos con unidades_regex
para calcular el precio por unidad de los productos.
Esta vez, dado que el porcentaje de aquellos casos en que no coinciden unidades
y unidades_regex
, junto a los casos en que unidades_regex
figura como NA
, alcanzan solamente un 0.27%, se prescindirá de ellos.
datos <- datos %>%
filter(igual == TRUE)
Se descartan 224 casos y ahora contamos con 83.013 observaciones. También podemos deshacernos de variables que no vamos a utilizar en el ejercicio de estimación.
datos <- datos %>%
select(-Presentación, -unidades_regex, -igual)
Cálculo del precio por unidad
Creo la variable precio_unidad
, dividiendo el Precio.de.lista
por las unidades
.
datos <- datos %>%
mutate(precio_unidad = round(Precio.de.lista/unidades, 2))
Gráficos del precio por unidad
Ahora podemos observar la distribución de esta nueva variable con los mismos gráficos que utilizamos antes.
ggplot(datos, aes(x = precio_unidad, y = Categoría, fill = Categoría)) +
geom_density_ridges(scale = 2, bandwidth = 1.25) +
theme_minimal() +
scale_x_continuous(limits = c(0, 30)) +
scale_fill_manual(values = c("red", "violetred")) +
theme(legend.position = "none") +
labs(title = "Precio por unidad de productos de gestión menstrual según categoría",
subtitle = date,
x = "Precio por unidad",
y = "",
caption = "Fuente: #MenstruAcción")

Esta vez, para realizar el gráfico por categorías y regiones, podemos ordenar a estas últimas según su precio promedio en el gráfico. Para ello construimos un vector que las aloje en orden, llamado reg_ordenadas
. Luego, pisamos la variable Region
en los datos para que sea de tipo factor, y el orden de la misma esté determinado según el vector previamente definido.
reg_ordenadas <- datos %>%
group_by(Region) %>%
summarise(promedio = mean(precio_unidad)) %>%
arrange(promedio) %$% Region
datos <- datos %>%
mutate(Region = factor(Region, levels = reg_ordenadas))
ggplot(datos, aes(x = precio_unidad, y = Region, fill = Categoría, alpha = Region)) +
geom_density_ridges(scale = 2, bandwidth = 1.25) +
theme_minimal() +
scale_fill_manual(values = c("red", "violetred"))+
facet_wrap(. ~ Categoría) +
theme(legend.position = "none") +
scale_x_continuous(limits = c(0, 30)) +
labs(title = "Precio por unidad de productos de gestión menstrual según categoría y región",
subtitle = date,
x = "Precio por unidad",
y = "",
caption = "Fuente: #MenstruAcción")

2,5 % de los extremos de la distribución
Adicionalmente, como el cálculo lo realizaremos agregando los precios de acuerdo a una media alpha podada con alpha = 2,5% (o sea, ignorando los valores superiores e inferiores para evitar la intrusión de outliers a pesar de la limpieza), presentamos gráficos que justamente muestran las “colas” de la distribución que se estarían obviando.
ggplot(datos, aes(x = precio_unidad, y = Categoría, fill = factor(..quantile..))) +
stat_density_ridges(geom = "density_ridges_gradient",
calc_ecdf = TRUE, quantiles = c(0.025, 0.975),
bandwidth = 1.25, scale = 1.5) +
scale_fill_manual(name = "Probabilidad",
values = c("violetred1", "red2", "violetred1"),
labels = c("2,5 %", "95,0 %", "2,5 %")) +
scale_x_continuous(limits = c(0, 30)) +
theme_minimal() +
theme(legend.position = "bottom") +
labs(title = "Precio por unidad de productos de gestión menstrual según categoría",
subtitle = paste(date),
x = "Precio por unidad",
y = "",
caption = "Fuente: #MenstruAcción")

Realizamos el mismo gráfico por cada provincia, ya que esa será la primer unidad de agregación para el cálculo total a nivel nacional.
prov_ordenadas <- datos %>%
group_by(Provincia) %>%
summarise(promedio = mean(precio_unidad)) %>%
arrange(promedio) %$%
Provincia
datos <- datos %>%
mutate(Provincia = factor(Provincia, levels = prov_ordenadas))
ggplot(datos, aes(x = precio_unidad, y = Provincia,
fill = factor(..quantile..))) +
stat_density_ridges(geom = "density_ridges_gradient",
calc_ecdf = TRUE, quantiles = c(0.025, 0.975),
bandwidth = 1.25, scale = 2) +
scale_fill_manual(name = "Probabilidad",
values = c("violetred1", "red2", "violetred1"),
labels = c("2,5 %", "95,0 %", "2,5 %")) +
scale_x_continuous(limits = c(0, 30)) +
facet_wrap(. ~ Categoría) +
theme_minimal() +
theme(legend.position = "bottom") +
labs(title = "Precio por unidad de productos de gestión menstrual según categoría y provincia",
subtitle = paste(date, ". "),
x = "Precio por unidad",
y = "",
caption = "Fuente: #MenstruAcción")

Apéndice: Precios iguales a cero
En esta ocasión, no hay precios iguales a cero, con lo que se prescinde de dicho análisis.
Finalmente, guardamos esta nueva versión del dataset en formato .RDS para continuar en el siguiente script con el cálculo de cuánto cuesta menstruar.
LS0tCnRpdGxlOiAiTGltcGllemEgeSBvcmdhbml6YWNpw7NuIGRlIGxvcyBkYXRvcyBkZWwgI01lbnN0cnVTY3JhcHBlciIKc3VidGl0bGU6ICJEYXRvcyBkZSBTZXB0aWVtYnJlIDIwMjEiCmF1dGhvcjogIkVjb2ZlbWluaXRhIC8gI01lbnN0cnVBY2Npw7NuIC8gRWNvZmVtaWRhdGEiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiBmYWxzZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDUKLS0tCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgogIGJvZHl7CiAgZm9udC1zaXplOiAxNHB0Owp9Cjwvc3R5bGU+CgohW10oaW1nL0xvZ29zIEVjb0ZlbWluaXRhLTAzLnBuZyl7d2lkdGg9MTMwcHh9ICFbXShpbWcvTUVOU1RSVUFDQ0lPTi5wbmcpe3dpZHRoPTExMHB4fSAhW10oaW1nL0Vjb2ZlbWlkYXRhLnBuZyl7d2lkdGg9MTAwcHh9CgojIyBQcmVzZW50YWNpw7NuCgpFbiBlbCBtYXJjbyBkZWwgY8OhbGN1bG8gZGVsIGNvc3RvIGRlIG1lbnN0cnVhciBlbiBBcmdlbnRpbmEsIGxsZXZhZG8gYSBjYWJvIGRlc2RlIGxhIGNhbXBhw7FhICNNZW5zdHJ1QWNjacOzbiB5IEVjb0ZlbWluaXRhcywgZW4gZWwgcHJlc2VudGUgZG9jdW1lbnRvIGRlIHRyYWJham8gc2UgZW5jdWVudHJhIGxhIGV4cGxvcmFjacOzbiwgb3JnYW5pemFjacOzbiB5IGxpbXBpZXphIGRlIGxvcyBkYXRvcyBvYnRlbmlkb3MgbWVkaWFudGUgZWwgWyNNZW5zdHJ1U2NyYXBwZXJdKGh0dHBzOi8vZ2l0aHViLmNvbS9ucG9ydGFzL21lbnN0cnVzY3JhcHBlciksIGRlc2Fycm9sbGFkbyBwb3IgTmF5bGEgUG9ydGFzIGRlIFtMQVNdIGRlIHNpc3RlbWFzLiBFbCAjTWVuc3RydVNjcmFwcGVyIGZ1ZSBlamVjdXRhZG8gZWwgZMOtYSAxNyBkZSBTZXB0aWVtYnJlIGRlIDIwMjEgc29icmUgbGEgcMOhZ2luYSBQcmVjaW9zIENsYXJvcywgc3Vtw6FuZG9zZSBlc3RhIGluZm9ybWFjacOzbiBhIGxhIG9idGVuaWRhIGFudGVyaW9ybWVudGUgZW4gU2VwdGllbWJyZSB5IE1hcnpvIGRlIDIwMTksIE1hcnpvIHkgU2VwdGllbWJyZSBkZSAyMDIwLCB5IE1hcnpvIGRlIDIwMjEuIEVuIGVzdGEgaW5zdGFuY2lhLCBzZSBvYnR1dmllcm9uIDgzLjMxNyBvYnNlcnZhY2lvbmVzIGVuIHRvdGFsLgoKKyBSZXNwZWN0byBkZSBsb3MgdGFtcG9uZXM6IFNlIG9idHV2aWVyb24gMTcuNzk5IHByZWNpb3MuCisgUmVzcGVjdG8gZGUgbGFzIHRvYWxsaXRhczogU2Ugb2J0dXZpZXJvbiA2NS41MTggcHJlY2lvcy4KCkVuIFtudWVzdHJvIHJlcG9zaXRvcmlvXShodHRwczovL2dpdGh1Yi5jb20vRWNvZmVtaW5pdGEvRWNvRmVtaURhdGEvdHJlZS9tYXN0ZXIvTWVuc3RydUFjY2lvbi9jdWFudG9fY3Vlc3RhX21lbnN0cnVhcikgc2UgZW5jdWVudHJhbiBhY2xhcmFkYXMgdG9kYXMgbGFzIGZ1ZW50ZXMgYWRpY2lvbmFsZXMgYSBsYXMgcXVlIHNlIHJlY3VycmnDsyBwYXJhIHJlYWxpemFyIGVsIGPDoWxjdWxvIHkgbG9zIGFyY2hpdm9zIGNvcnJlc3BvbmRpZW50ZXMuIEVuIG90cm8gcGFzbyBzZSBlbmN1ZW50cmEgZWwgY8OhbGN1bG8gcHJvcGlhbWVudGUgZGljaG8gZGVsIGNvc3RvIGFudWFsIGRlIG1lbnN0cnVhci4gCgojIyBQcmVwYXJhbmRvIGVsIGVudG9ybm8gZGUgdHJhYmFqbwoKQ29tZW56YW1vcyBsZXZhbnRhbmRvIGxhcyBsaWJyZXLDrWFzIG5lY2VzYXJpYXMsIGNhcmdhbmRvIGxvcyBkYXRvcyBzcmFwcGVhZG9zIGRlc2RlIGVsIGFyY2hpdm8gLmNzdiwgeSB1biBkaWNjaW9uYXJpbyBxdWUgaW5kaWNhIGEgcXXDqSByZWdpw7NuIHBlcnRlbmVjZSBjYWRhIHByb3ZpbmNpYSBkZWwgcGHDrXMuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KEVudlN0YXRzKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3JpZGdlcykKbGlicmFyeShvcGVueGxzeCkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoa2FibGVFeHRyYSkKCmRhdG9zIDwtIHJlYWQuY3N2KCJGdWVudGVzL3ByZWNpb3MtZ2VzdGlvbi1tZW5zdHJ1YWwtMjAyMS0wOS0xNy5jc3YiLCAKICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwgc2VwID0gIiwiLCBkZWMgPSAiLiIsIAogICAgICAgICAgICAgICAgICBmaWxsID0gVFJVRSwgZW5jb2RpbmcgPSAiVVRGLTgiKQoKcmVnaW9uZXMgPC0gb3Blbnhsc3g6OnJlYWQueGxzeCgiRnVlbnRlcy9wcm92aW5jaWFzX3JlZ2lvbmVzLnhsc3giKQpgYGAKClZpc3RhIHByZXZpYSBkZWwgZGF0YXNldDoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmhlYWQoZGF0b3MpCmBgYAoKVmlzdGEgcHJldmlhIGRlbCBkaWNjaW9uYXJpbyBkZSByZWdpb25lczoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmhlYWQocmVnaW9uZXMpCmBgYAoKRGVmaW5pbW9zIHVuYSBwZXF1ZcOxYSBmdW5jacOzbjogYGNhbnRgIG5vcyB2YSBhIGRldm9sdmVyIHVuIG7Dum1lcm8gZW4gZm9ybWF0byBjaGFyYWN0ZXIgKHRleHRvKSwgY29uIGNlcm8gZMOtZ2l0b3MsIGNvbiB1biBwdW50byBwYXJhIHNlcGFyYXIgbG9zIG1pbGVzLCB5IHVuYSBjb21hIHBhcmEgc2VwYXJhciBsb3MgZGVjaW1hbGVzLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY2FudCA8LSBmdW5jdGlvbih4KXsKICBmb3JtYXQoeCwgZGlnaXRzID0gMCwgYmlnLm1hcmsgPSAiLiIsIGRlY2ltYWwubWFyayA9ICIsIil9CmBgYAoKR3VhcmRhbW9zIGVsIHZhbG9yIGRlIGxhIGZlY2hhIGEgbGEgcXVlIGNvcnJlc3BvbmRlIGVsIGVqZXJjaWNpby4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdGUgPC0gIlNlcHRpZW1icmUgMjAyMSIKYGBgCgojIyBFeHBsb3JhY2nDs24gZGUgbG9zIGRhdG9zCgpBbCBkYXRhZnJhbWUgYGRhdG9zYCBsZSBwZWdhbW9zIGxvcyB2YWxvcmVzIGRlIGxhcyByZWdpb25lcywgdXNhbmRvIGNvbW8gdmFyaWFibGUgZGUgaWRlbnRpZmljYWNpw7NuIGEgbGEgYFByb3ZpbmNpYWAuIEEgY29udGludWFjacOzbiBwb2RlbW9zIGJvcnJhciBkZSBudWVzdHJvIGVudG9ybm8gZGUgdHJhYmFqbyBlbCBlbGVtZW50byBgcmVnaW9uZXNgLiAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zIDwtIGxlZnRfam9pbihkYXRvcywgcmVnaW9uZXMsIGJ5ID0gIlByb3ZpbmNpYSIpCnJtKHJlZ2lvbmVzKQpgYGAKCmBkYXRvc2AgY3VlbnRhIGNvbiBgciBjYW50KG5yb3coZGF0b3MpKWAgb2JzZXJ2YWNpb25lcy4gQSBzdSB2ZXosIHBvZGVtb3MgdmVyIGNvbiBxdcOpIHZhcmlhYmxlcyBjb250YW1vcyBlbiBlbCBkYXRhc2V0OgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbmFtZXMoZGF0b3MpCmBgYAoKQSBjb250aW51YWNpw7NuLCBleHBsb3JhcmVtb3MgZWwgY29tcG9ydGFtaWVudG8gZGUgbGFzIGRpZmVyZW50ZXMgdmFyaWFibGVzLiBDb24gYGNvdW50KClgIHBlZGltb3MgdW4gY29udGVvIGRlIG9ic2VydmFjaW9uZXMgcGFyYSBjYWRhIHZhbG9yIHF1ZSB0b21hIGxhIHZhcmlhYmxlIGFjbGFyYWRhLCBjb24gYGFycmFuZ2UoKWAgb3JkZW5hbW9zIGxvcyBkYXRvcyBkZSBmb3JtYSBkZWNyZWNpZW50ZSBzZWfDum4gZWwgY29udGVvIGFudGVyaW9yLCB5IGVuIGBtdXRhdGUoKWAgc2UgZGVmaW5lbiBudWV2YXMgdmFyaWFibGVzIHBhcmEgbnVlc3RybyBjdWFkcm8uIFBvciBlamVtcGxvLCBlbCBwb3JjZW50YWplIGVzIGxhIGNhbnRpZGFkIGRlIGNhZGEgY2F0ZWdvcsOtYSBzb2JyZSBsYSBzdW1hIGRlIGxhcyBtaXNtYXMsIGV4cHJlc2FkYSBlbiBmb3JtYXRvIGRlIHBvcmNlbnRhamUuCgojIyMgQ2F0ZWdvcsOtYXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zICU+JSAKICBjb3VudChDYXRlZ29yw61hKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIG11dGF0ZShwb3JjZW50YWplID0gcGVyY2VudChuL3N1bShuKSkpIApgYGAKCkNhYmUgZGVzdGFjYXIgcXVlIGVzdGEgY29tcG9zaWNpw7NuIGNvcnJlc3BvbmRlIGEgbGEgZGlzcG9uaWJpbGlkYWQgZGUgcHJlY2lvcywgbm8gcmVmbGVqYSBsYSBlc3RydWN0dXJhIGRlbCBjb25zdW1vLiBPIHNlYSwgbm8gcG9kZW1vcyBkZWNpciBxdWUgc2UgY29uc3VtZW4gZW4gdW4gODAlIHRvYWxsaXRhcyB5IGVuIDIwJSB0YW1wb25lcy4gTG8gcXVlIHPDrSBzYWJlbW9zIGVzIHF1ZSB0ZW5lbW9zIHVuYSBtdWVzdHJhIG11eSBncmFuZGUgZGUgcHJlY2lvcyBwYXJhIGFtYmFzIGNhdGVnb3LDrWFzLCBhdW5xdWUgZGViZW1vcyB0ZW5lciBlbiBjdWVudGEgcXVlIGxhIHDDoWdpbmEgZGUgUHJlY2lvcyBDbGFyb3MgcHVlZGUgdGVuZXIgdW4gc2VzZ28gcG9yIG5vIGluY2x1aXIgbG9zIGNvbWVyY2lvcyB0cmFkaWNpb25hbGVzIHNpbm8gw7puaWNhbWVudGUgZ3JhbmRlcyBjYWRlbmFzLgoKIyMjIE1hcmNhcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lIAogIGNvdW50KE1hcmNhKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIG11dGF0ZShwb3JjZW50YWplID0gbi9zdW0obiksCiAgICAgICAgIGFjdW11bGFkbyA9IGN1bXN1bShwb3JjZW50YWplKSwKICAgICAgICAgcG9yY2VudGFqZSA9IHBlcmNlbnQocG9yY2VudGFqZSksCiAgICAgICAgIGFjdW11bGFkbyA9IHBlcmNlbnQoYWN1bXVsYWRvKSkKYGBgCgpDb250YW1vcyBjb24gMjggbWFyY2FzIGRlIHByb2R1Y3RvcywgYXVucXVlIGNvbiAxMCBkZSBlbGxhcyBzZSBjb21wbGV0YSBlbCA5MCUgZGVsIHRvdGFsIGRlIHByb2R1Y3Rvcy4gTGFzIHByaW1lcmFzIDMgbWFyY2FzIGNvbmNlbnRyYW4gY2FzaSBsYSBtaXRhZCBkZSBsYXMgb2JzZXJ2YWNpb25lcy4gTnVldmFtZW50ZSBhcXXDrSBoYXkgcXVlIHRlbmVyIGVuIGN1ZW50YSBxdWUgbm8gc2UgdHJhdGEgZXhhY3RhbWVudGUgZGUgdW5hICJjb25jZW50cmFjacOzbiBkZSBtZXJjYWRvIi4KCiMjIyBQcmVzZW50YWNpw7NuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyAlPiUgCiAgY291bnQoUHJlc2VudGFjacOzbikgJT4lIAogIGFycmFuZ2UoLW4pICU+JSAKICBtdXRhdGUocG9yY2VudGFqZSA9IG4vc3VtKG4pLAogICAgICAgICBhY3VtdWxhZG8gPSBjdW1zdW0ocG9yY2VudGFqZSksCiAgICAgICAgIHBvcmNlbnRhamUgPSBwZXJjZW50KHBvcmNlbnRhamUpLAogICAgICAgICBhY3VtdWxhZG8gPSBwZXJjZW50KGFjdW11bGFkbykpCmBgYAoKQ2FzaSBlbCA5MCUgZGUgbG9zIHByb2R1Y3RvcyB2aWVuZW4gZW4gcGFxdWV0ZXMgZGUgOCBvIDE2IHVuaWRhZGVzLiBMdWVnbyBzZWd1aXJlbW9zIGFuYWxpemFuZG8gZXN0YSB2YXJpYWJsZSBlbiBwYXJ0aWN1bGFyLCBwb3JxdWUgbm9zIGludGVyZXNhIHBhcmEgY2FsY3VsYXIgbG9zIHByZWNpb3MgdW5pdGFyaW9zIGRlIGxvcyBwcm9kdWN0b3MsIHkgaGF5IHZhbG9yZXMgKGNvbW8gIjEuMCB1biIpIHF1ZSBzb24gcmFyb3MgeSwgZW4gY2FzbyBkZSB0cmF0YXJzZSBkZSBlcnJvcmVzLCBwb2Ryw61hbiBhcnJhc3RyYXIgcHJvYmxlbWFzIGhhY2lhIGVsIGPDoWxjdWxvIGRlIGVzb3MgcHJlY2lvcy4KCiMjIyBQcm92aW5jaWFzCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyAlPiUgCiAgY291bnQoUHJvdmluY2lhKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIG11dGF0ZShwb3JjZW50YWplID0gbi9zdW0obiksCiAgICAgICAgIGFjdW11bGFkbyA9IGN1bXN1bShwb3JjZW50YWplKSwKICAgICAgICAgcG9yY2VudGFqZSA9IHBlcmNlbnQocG9yY2VudGFqZSksCiAgICAgICAgIGFjdW11bGFkbyA9IHBlcmNlbnQoYWN1bXVsYWRvKSkKYGBgCgpTaSBiaWVuIG3DoXMgZGUgbGEgbWl0YWQgZGUgbGFzIG9ic2VydmFjaW9uZXMgc2UgY29uY2VudHJhbiBlbiBCdWVub3MgQWlyZXMgeSBDQUJBLCBlcyBpbXBvcnRhbnRlIHNhYmVyIHF1ZSBzZSBjdWVudGEgY29uIGluZm9ybWFjacOzbiBkZSB0b2RhcyBsYXMgcHJvdmluY2lhcyBkZWwgcGHDrXMsIHkgcXVlIGluY2x1c28gZW4gZWwgcGVvciBkZSBsb3MgY2Fzb3MgKHBvciBlamVtcGxvLCAxNjUgb2JzZXJ2YWNpb25lcyBlbiBDYXRhbWFyY2EpIHNlIHRyYXRhIGRlIHVuYSBjYW50aWRhZCBwYXNpYmxlIGRlIHByb3ZlZXJub3MgZXN0aW1hY2lvbmVzIMO6dGlsZXMuCgojIyMgUmVnaW9uZXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zICU+JSAKICBjb3VudChSZWdpb24pICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgCiAgbXV0YXRlKHBvcmNlbnRhamUgPSBuL3N1bShuKSwKICAgICAgICAgYWN1bXVsYWRvID0gY3Vtc3VtKHBvcmNlbnRhamUpLAogICAgICAgICBwb3JjZW50YWplID0gcGVyY2VudChwb3JjZW50YWplKSwKICAgICAgICAgYWN1bXVsYWRvID0gcGVyY2VudChhY3VtdWxhZG8pKQpgYGAKCkVuIHTDqXJtaW5vcyByZWdpb25hbGVzIHNlZ3VpbW9zIHZpZW5kbyBlc2EgYXNpbWV0csOtYSBlbiBsYSBkaXNwb25pYmlsaWRhZCBkZSBkYXRvcywgcGVybyBoYXkgcXVlIHRlbmVyIGVuIGN1ZW50YSBxdWUgZWZlY3RpdmFtZW50ZSBoYXkgZGlmZXJlbmNpYXMgZGUgZXNjYWxhIGRlIG1lcmNhZG9zIGVuIHTDqXJtaW5vcyByZWdpb25hbGVzLgoKIyMjIFByZWNpbyBkZSBsaXN0YQoKQWhvcmEgZ3JhZmljYW1vcyBsYSBkaXN0cmlidWNpw7NuIGRlIGxvcyBwcmVjaW9zIGRlIGxpc3RhIChvIHNlYSwgc2luIHRlbmVyIGVuIGN1ZW50YSBsYXMgdW5pZGFkZXMgcG9yIHBhcXVldGUpIHNlZ8O6biBjYWRhIGNhdGVnb3LDrWEuIFBhcmEgZWxsbyB1dGlsaXphbW9zIGBnZ3Bsb3QyYC4gCgpFbiBsYSBwcmltZXIgbMOtbmVhIGRlIGPDs2RpZ28gcmVmZXJpZGEgYSBgZ2dwbG90YCwgdG9tYW1vcyBjb21vIGZ1ZW50ZSBlbCBkYXRhc2V0IHF1ZSB2ZW5pbW9zIHV0aWxpemFuZG8gKGEgZXNvIHJlZmllcmUgZWwgcHVudG8pLCBlbiBlbCBgZWplIHhgIHF1ZXJlbW9zIGxvcyBwcmVjaW9zLCBlbiBlbCBgZWplIHlgIHF1ZXJlbW9zIGNhZGEgY2F0ZWdvcsOtYSwgeSBlbCByZWxsZW5vIGRlIGNhZGEgcGFydGUgZGVsIGdyw6FmaWNvIHRhbWJpw6luIHNlZ8O6biBsYXMgY2F0ZWdvcsOtYXMgZGUgcHJvZHVjdG9zLiBFbiBsYSBzZWd1bmRhIGzDrW5lYSBhY2xhcmFtb3MgcXVlIHF1ZXJlbW9zIHVuIGdyw6FmaWNvIGRlIGRlbnNpZGFkIChxdWUgZXMgY29tbyB1biBoaXN0b2dyYW1hIHBlcm8gZW4gdmVyc2nDs24gY29udGludWEpLCBsYSBlc2NhbGEgaGFjZSBhIGxhIHN1cGVycG9zaWNpw7NuIGRlIGxvcyBncmFmaWNvcyB5IGVsIGBiYW5kd2lkdGhgIG8gImFuY2hvIGRlIGJhbmRhIiBpbmRpY2EgbGEgZXh0ZW5zacOzbiBkZWwgaW50ZXJ2YWxvIGRlIHZhbG9yZXMgY29uIGxvcyBxdWUgc2UgdmEgYSByZWFsaXphciBsYSBlc3RpbWFjacOzbiBkZWwgZ3LDoWZpY28gKG8gc2VhLCBzaSBlbCBncsOhZmljbyB2YSBhIHNlciBtw6FzIGRldGFsbGlzdGEgeSBwb3IgZW5kZSBtw6FzICJydWlkb3NvIiwgbyBtw6FzIHN1YXZlIHkgInJlZG9uZGVhZG8iKS4gU2UgcHVlZGUganVnYXIgY29uIGFtYm9zIHZhbG9yZXMgcGFyYSB2ZXIgc3VzIGVmZWN0b3MuIEVuIGxhIHRlcmNlciBsw61uZWEgYWNsYXJhbW9zIHF1ZSBxdWVyZW1vcyB1biB0ZW1hIG1pbmltYWxpc3RhLCBlbiBsYSBjdWFydGEgcXVlIGxhIHBhbGV0YSBkZSBjb2xvcmVzIGxhIHZhbW9zIGEgYXNpZ25hIGRlIG1hbmVyYSBtYW51YWwsIGVuIGxhIHF1aW50YSBxdWUgbm8gcXVlcmVtb3MgdW5hIGxleWVuZGEgYWNsYXJhbmRvIGxvcyBjb2xvcmVzIGRlIGNhZGEgY2F0ZWdvcsOtYSBwb3JxdWUgeWEgZXN0w6FuIGFjbGFyYWRhcyBlbiBlbCBlamUgeS4gWSBwb3Igw7psdGltbyBhY2xhcmFtb3MgbGFzIGV0aXF1ZXRhcyBuZWNlc2FyaWFzLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lIAogIGdncGxvdCguLCBhZXMoeCA9IFByZWNpby5kZS5saXN0YSwgeSA9IENhdGVnb3LDrWEsIGZpbGwgPSBDYXRlZ29yw61hKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2NhbGUgPSAzLCBiYW5kd2lkdGggPSAyMCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygicmVkIiwgInZpb2xldHJlZCIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gZGUgbGlzdGEgZGUgcHJvZHVjdG9zIGRlIGdlc3Rpw7NuIG1lbnN0cnVhbCBzZWfDum4gY2F0ZWdvcsOtYSIsCiAgICAgICBzdWJ0aXRsZSA9IGRhdGUsCiAgICAgICB4ID0gIlByZWNpbyBkZSBsaXN0YSIsCiAgICAgICB5ID0gIiIsCiAgICAgICBjYXB0aW9uID0gIkZ1ZW50ZTogI01lbnN0cnVBY2Npw7NuIikKYGBgClBvciBlc3RhIHZleiwgZmlsdHJhbW9zIGRlIGxvcyBkYXRvcyBsb3MgcHJlY2lvcyBtYXlvcmVzIGEgMS4wMDAgcGVzb3MsIGJhc2ljYW1lbnRlIHBvcnF1ZSBoYXkgY2Fzb3MgKG91dGxpZXJzIHF1ZSBkZSBoZWNobyB2YW1vcyBhIHRlbmVyIHF1ZSBjb3JyZWdpcikgcXVlIHN1cGVyYW4gZXNlIG1vbnRvIHkgInJvbXBlbiIgbGEgZXNjYWxhIGRlbCBncsOhZmljby4gUGFyYSB1bmEgY29tcHJlbnNpw7NuIG3DoXMgYWNhYmFkYSBkZSBlc3RlIGVmZWN0bywgdmVhbW9zIHF1w6kgc3VjZWRlIHNpIHF1aXRhbW9zIGVzdG9zIHZhbG9yZXMgcXVlIGhhc3RhIHN1cGVyYW4gbG9zIDE1LjAwMCBwZXNvczoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgU29sbyBlbiBlc3RhIG9jYXNpw7NuIHBvciBsb3Mgb3V0bGllcnMgcHJlc2VudGVzOgoKZGF0b3MgPC0gZGF0b3MgJT4lIAogIGZpbHRlcihQcmVjaW8uZGUubGlzdGEgPCAxMDAwKSAjc2FjbyBsb3Mgb3V0bGllcnMgbWF5b3JlcyBhIDEwMDAgcG9ycXVlIHNvbiBkZW1hc2lhZG8gYWx0b3MuIAojIEVsIHJlc3RvIHZhIGEgc2VyIGNvbnRyb2xhZG8gYSBsYSBob3JhIGRlIGNhbGN1bGFyIGxhIG1lZGlhIGRlIHByZWNpb3MgZGUgZm9ybWEgInBvZGFkYSIKCmRhdG9zICU+JSAKICBnZ3Bsb3QoLiwgYWVzKHggPSBQcmVjaW8uZGUubGlzdGEsIHkgPSBDYXRlZ29yw61hLCBmaWxsID0gQ2F0ZWdvcsOtYSkpICsKICBnZW9tX2RlbnNpdHlfcmlkZ2VzKHNjYWxlID0gMywgYmFuZHdpZHRoID0gMjApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInJlZCIsICJ2aW9sZXRyZWQiKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnModGl0bGUgPSAiUHJlY2lvIGRlIGxpc3RhIGRlIHByb2R1Y3RvcyBkZSBnZXN0acOzbiBtZW5zdHJ1YWwgc2Vnw7puIGNhdGVnb3LDrWEiLAogICAgICAgc3VidGl0bGUgPSBkYXRlLAogICAgICAgeCA9ICJQcmVjaW8gZGUgbGlzdGEiLAogICAgICAgeSA9ICIiLAogICAgICAgY2FwdGlvbiA9ICJGdWVudGU6ICNNZW5zdHJ1QWNjacOzbiIpCmBgYAoKQSBwcmltZXJhIHZpc3RhLCBsb3Mgbml2ZWxlcyBkZSBwcmVjaW9zIGRlIHRvYWxsaXRhcyB5IHRhbXBvbmVzIHNlIGRpc3RyaWJ1eWVuIGVuIHVuYSBtaXNtYSBlc2NhbGEuIEVuIGVsIGNhc28gZGUgbG9zIHRhbXBvbmVzIGhheSB1bmEgZGlzdHJpYnVjacOzbiBiaW1vZGFsLCBxdWUgcHVlZGUgZGViZXJzZSBhIGxhIGFtcGxpYSBjYW50aWRhZCBkZSBwcmVzZW50YWNpb25lcyBkZSA4IHkgMTYgdW5pZGFkZXMuCgo8YnI+PGJyPgoKVGFtYmnDqW4gcG9kZW1vcyBncmFmaWNhciBsb3MgcHJlY2lvcyBkZSBjYWRhIGNhdGVnb3LDrWEgcG9yIHJlZ2lvbmVzOgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lIAogIGdncGxvdCguLCBhZXMoeCA9IFByZWNpby5kZS5saXN0YSwgeSA9IFJlZ2lvbiwgZmlsbCA9IENhdGVnb3LDrWEsIGFscGhhID0gUmVnaW9uKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2NhbGUgPSAyLCBiYW5kd2lkdGggPSAyMCkgKyAjIGVsIGJhbmR3aWR0aCBhbnRlcmlvciBlc3RhYmEgZW4gMTAKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInJlZCIsICJ2aW9sZXRyZWQiKSkrCiAgZmFjZXRfd3JhcCguIH4gQ2F0ZWdvcsOtYSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnModGl0bGUgPSAiUHJlY2lvIGRlIGxpc3RhIGRlIHByb2R1Y3RvcyBkZSBnZXN0acOzbiBtZW5zdHJ1YWwgc2Vnw7puIGNhdGVnb3LDrWEgeSByZWdpw7NuIiwKICAgICAgIHN1YnRpdGxlID0gZGF0ZSwKICAgICAgIHggPSAiUHJlY2lvIGRlIGxpc3RhIiwKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiAjTWVuc3RydUFjY2nDs24iKQpgYGAKCkVuIGVzdGUgY2FzbyBzZSBlbmN1ZW50cmFuIGRpZmVyZW5jaWFzIG3DoXMgcXVlIG5hZGEgZW50cmUgbG9zIHRhbXBvbmVzLCBubyBhc8OtIGVuIGVsIGNhc28gZGUgbGFzIHRvYWxsaXRhcy4gRGFkbyBlbCBwZXNvIGRlIEdCQSBlbnRyZSBsYXMgb2JzZXJ2YWNpb25lcywgdGllbmUgc2VudGlkbyBxdWUgbGEgZGlzdHJpYnVjacOzbiBnZW5lcmFsIHNlIGFzZW1lamUgYSBsYSBkZSBkaWNoYSByZWdpw7NuLgoKIyMgTGltcGllemEgZGUgbGEgY2FudGlkYWQgZGUgdW5pZGFkZXMgKFByZXNlbnRhY2nDs24pCgpDb21vIG1lbmNpb27DoWJhbW9zIGFudGVyaW9ybWVudGUsIGVzIG5lY2VzYXJpbyBwcmVzdGFybGUgcGFydGljdWxhciBhdGVuY2nDs24gYSBsYSB2YXJpYWJsZSBkZSBgUHJlc2VudGFjacOzbmAsIHF1ZSBpbmRpY2EgbGEgY2FudGlkYWQgZGUgdW5pZGFkZXMgcG9yIGNhZGEgcGFxdWV0ZS4gRW4gcHJpbWVyIGx1Z2FyLCB0ZW5pZW5kbyBlbiBjdWVudGEgcXVlIGVzdMOhIGV4cHJlc2FkYSBjb21vICJYIHVuLiIsIG1vZGlmaWNhbW9zIGxhIHZhcmlhYmxlIHBhcmEgcXVlZGFybm9zIMO6bmljYW1lbnRlIGNvbiBsYXMgdW5pZGFkZXMgZW4gZm9ybWF0byBudW3DqXJpY28uIEVzdG8gbG8gaGFjZW1vcyBjb252aXJ0aWVuZG8gbGEgdmFyaWFibGUgYWwgdGlwbyBjaGFyYWN0ZXIsIHkgbHVlZ28gcXVlZMOhbmRvbm9zIGNvbiBhcXVlbGxvcyBjYXJhY3RlcmVzIGVudHJlIGxhIHByaW1lciBwb3NpY2nDs24geSBhcXVlbGxhIHF1ZSBzZSBlbmN1ZW50cmEgNCBwb3NpY2lvbmVzIHBvciBkZXRyw6FzIGRlIGxhIMO6bHRpbWEgKG9taXRpZW5kbyBhc8OtICIuMCB1biIpLiBFbiBsYSB0YWJsYSBgcHJlc2VudGFjaW9uX25yb3NgIHJlc3VtaW1vcyBlbCBjb21wb3J0YW1pZW50byBkZSBlc3RhIG51ZXZhIHZhcmlhYmxlIGB1bmlkYWRlc2AuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyA8LSBkYXRvcyAlPiUgCiAgbXV0YXRlKFByZXNlbnRhY2nDs24gPSBhcy5jaGFyYWN0ZXIoUHJlc2VudGFjacOzbiksCiAgICAgICAgIHVuaWRhZGVzID0gYXMubnVtZXJpYyhzdWJzdHIoUHJlc2VudGFjacOzbiwgMSwgbmNoYXIoUHJlc2VudGFjacOzbiktNCkpKQoKcHJlc2VudGFjaW9uX25yb3MgPC0gZGF0b3MgJT4lIAogIGNvdW50KHVuaWRhZGVzKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIG11dGF0ZShwb3JjZW50YWplID0gbi9zdW0obiksCiAgICAgICAgIGFjdW11bGFkbyA9IGN1bXN1bShwb3JjZW50YWplKSwKICAgICAgICAgcG9yY2VudGFqZSA9IHBlcmNlbnQocG9yY2VudGFqZSksCiAgICAgICAgIGFjdW11bGFkbyA9IHBlcmNlbnQoYWN1bXVsYWRvKSkKcHJlc2VudGFjaW9uX25yb3MKYGBgCgpTaW4gZW1iYXJnbywgZW4gbGEgYmFzZSBwdWVkZSB2ZXJzZSBxdWUgaGF5IGNhc29zIHF1ZSwgZGUgYWN1ZXJkbyBhIGxhIGRlc2NyaXBjacOzbiBlbiBgTm9tYnJlYCwgdGllbmVuIG1hbCBsYSBjYW50aWRhZCBkZSB1bmlkYWRlcyBlbiBgUHJlc2VudGFjaW9uYCAoeSBwb3IgZW5kZSBlbiB1bmlkYWRlcyksIGFmZWN0YW5kbyBlbCBjYWxjdWxvIGRlIHByZWNpb3MgdW5pdGFyaW9zLgo8YnI+PGJyPgpVdGlsaXphbmRvIGV4cHJlc2lvbmVzIHJlZ3VsYXJlcyBwb2RlbW9zIHF1ZWRhcm5vcyBjb24gbG9zIGTDrWdpdG9zLCBzZWFuIHVubyBvIG3DoXMsIHF1ZSBlc3TDoW4gc2VndWlkb3MgZGUgIlVuIiBvICJ1biIgZW4gbGEgdmFyaWFibGUgYE5vbWJyZWAuIE5vcyBxdWVkYW1vcyBjb24gZXN0YSBpbmZvcm1hY2nDs24gZW4gbGEgdmFyaWFibGUgYHVuaWRhZGVzX3JlZ2V4YCB5IHJlc3VtaW1vcyBzdSBjb21wb3J0YW1pZW50by4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUodW5pZGFkZXNfcmVnZXggPSBhcy5udW1lcmljKHN0cl9leHRyYWN0KE5vbWJyZSwgJ1xcZCsoPz1cXHMqW1V1XW4/KScpKSkKCnByZXNlbnRhY2lvbl9yZWdleCA8LSBkYXRvcyAlPiUgCiAgY291bnQodW5pZGFkZXNfcmVnZXgpICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgCiAgbXV0YXRlKHBvcmNlbnRhamUgPSBuL3N1bShuKSwKICAgICAgICAgYWN1bXVsYWRvID0gY3Vtc3VtKHBvcmNlbnRhamUpLAogICAgICAgICBwb3JjZW50YWplID0gcGVyY2VudChwb3JjZW50YWplKSwKICAgICAgICAgYWN1bXVsYWRvID0gcGVyY2VudChhY3VtdWxhZG8pKQpwcmVzZW50YWNpb25fcmVnZXgKYGBgCgpOw7N0ZXNlIHF1ZSBoYXkgcGVxdWXDsWFzIGRpZmVyZW5jaWFzIHJlc3BlY3RvIGRlbCBjdWFkcm8gYW50ZXJpb3IgKGVuIGxhcyAzMCB1bmlkYWRlcyBwb3IgZWplbXBsbykuIEVuIGVzdGUgY2FzbywgbGFzIHVuaWRhZGVzIHNlIGVuY3VlbnRyYW4gbcOhcyBjb25jZW50cmFkYXMgZW4gdmFsb3JlcyBwb3B1bGFyZXMuIFBvZGVtb3MgaWRlbnRpZmljYXIgY3XDoW5kbyBhbWJhcyBpbmZvcm1hY2lvbmVzIChsYSBjb250ZW5pZGEgZW4gYHVuaWRhZGVzYCB5IGVuIGB1bmlkYWRlc19yZWdleGApIGNvaW5jaWRlbiB5IGN1w6FuZG8gbm8uIENyZWFtb3MgbGEgdmFyaWFibGUgYGlndWFsYCBxdWUgdG9tYSB2YWxvciBUUlVFIGN1YW5kbyBzb24gaWd1YWxlcywgeSBGQUxTRSBjdWFuZG8gbm8uIEEgY29udGludWFjacOzbiwgZW4gbGEgdGFibGEgYGNvbXBhcm9fdW5pZGFkZXNgIHNlIHJlYWxpemEgdW4gY29udGVvIGRlIG9ic2VydmFjaW9uZXMgcGFyYSBhbWJhcyB2YXJpYWJsZXMsIHNlIGlkZW50aWZpY2FuIGxhcyBzaXR1YWNpb25lcyBkZSBjb2luY2lkZW5jaWEgeSBkaWZlcmVuY2lhIHkgc2Ugb3JkZW5hbiBsb3MgZGF0b3MgcGFyYSB2ZXIgcHJpbWVybyBsYXMgZGlmZXJlbmNpYXMsIHNlZ8O6biBsYSBtYWduaXR1ZC4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUoaWd1YWwgPSBjYXNlX3doZW4odW5pZGFkZXMgPT0gdW5pZGFkZXNfcmVnZXggfiBULAogICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlkYWRlcyAhPSB1bmlkYWRlc19yZWdleCB+IEYpKQoKY29tcGFyb191bmlkYWRlcyA8LSBkYXRvcyAlPiUgCiAgY291bnQodW5pZGFkZXMsIHVuaWRhZGVzX3JlZ2V4KSAlPiUgCiAgbXV0YXRlKGlndWFsID0gY2FzZV93aGVuKHVuaWRhZGVzID09IHVuaWRhZGVzX3JlZ2V4IH4gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pZGFkZXMgIT0gdW5pZGFkZXNfcmVnZXggfiBGKSkgJT4lIAogIGFycmFuZ2UoaWd1YWwsIC1uKQoKY29tcGFyb191bmlkYWRlcwpgYGAKRW4gcGFydGljdWxhciwgaGF5IGNhc29zIHF1ZSBmdWVyb24gaW5mb3JtYWRvcyBjb21vIGRlIDEgbyAxNiB1bmlkYWRlcyB5IGVuIHJlYWxpZGFkIGVyYW4gZGUgOCAodGllbmUgc2VudGlkbyBxdWUgZXN0ZSDDumx0aW1vIHNlYSBlbCB2ZXJkYWRlcm8gdmFsb3IpLCBjYXNvcyBxdWUgZnVlcm9uIGluZm9ybWFkb3MgY29tbyBkZSAxIG8gMjcgdW5pZGFkZXMgeSBlbiByZWFsaWRhZCBlcmFuIGRlIDE2LCBvIGNhc29zIHF1ZSBmdWVyb24gaW5mb3JtYWRvcyBjb21vIGRlIDEgdW5pZGFkIHkgZW4gcmVhbGlkYWQgZXJhbiBkZSAzMCwgZXRjLiBDb21vIHB1ZWRlIHZlcnNlIGEgY29udGludWFjacOzbiwgaGF5IGVuIHRvdGFsIDIxOCBjYXNvcyBlbiBxdWUgbGEgaW5mb3JtYWNpw7NuIG5vIGNvaW5jaWRlLCBsbyBxdWUgcmVwcmVzZW50YSBlbCAwLjI2JSBkZSBsYSBpbmZvcm1hY2nDs24gKG1lam9yw7MgbXVjaMOtc2ltbyBlbiBjb21wYXJhY2nDs24gYSByZWxldmFtaWVudG9zIGFudGVyaW9yZXMpLCB5IHPDs2xvIDYgY2Fzb3MgZW4gcXVlIG5vIGhhYsOtYSBpbmZvcm1hY2nDs24gc29icmUgbGEgY2FudGlkYWQgZGUgdW5pZGFkZXMgZW4gbGEgZGVzY3JpcGNpw7NuIGRlbCBhcnTDrWN1bG8uCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyAlPiUgCiAgZ3JvdXBfYnkoaWd1YWwpICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIAogIG11dGF0ZShwb3JjID0gcGVyY2VudChuL3N1bShuKSkpCmBgYAoKVmFsZSBsYSBwZW5hIGRlc3RhY2FyIHF1ZSBlc3RvcyBlcnJvcmVzIGNvcnJlc3BvbmRlbiBhIHRvZGFzIGxhcyByZWdpb25lcywgbWF5b3JtZW50ZSBjb25jZW50cmFkb3MgZW4gR0JBLCB5IGVuIDUgbWFyY2FzIGRpZmVyZW50ZXMuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIERpc3RyaWJ1Y2lvbiBkZSBsb3MgZGF0b3MgcXVlIHF1ZXJlbW9zIHNhY2FyIGVudHJlIGxhcyByZWdpb25lcwpkYXRvcyAlPiUgCiAgZmlsdGVyKGlndWFsID09IEZBTFNFKSAlPiUgCiAgY291bnQoUmVnaW9uKQoKIyBEaXN0cmlidWNpb24gZGUgbG9zIGRhdG9zIHF1ZSBxdWVyZW1vcyBzYWNhciBlbnRyZSBsYXMgbWFyY2FzCmRhdG9zICU+JSAKICBmaWx0ZXIoaWd1YWwgPT0gRkFMU0UpICU+JSAKICBjb3VudChNYXJjYSkKYGBgCgojIyMgQWNsYXJhY2nDs24KCkVuIHVuIGVqZXJjaWNpbyBhbnRlcmlvciAoc2VwdGllbWJyZSAyMDE5KSwgcHJlc2NpbmRpbW9zIGRlIGxvcyB2YWxvcmVzIGZhbHRhbnRlcyBlbiBgdW5pZGFkZXNfcmVnZXhgIChwb3IgbcOhcyBxdWUgdGVuZ2FuIHZhbG9yIGVuIGB1bmlkYWRlc2AsIGFxdWVsbGEgcXVlIHN1cmdlIGRlIGxhIHZhcmlhYmxlIGBQcmVzZW50YWNpw7NuYCkuIFZlcmlmaWNhbW9zIGFxdWVsbG9zIGNhc29zIGVuIHF1ZSBgdW5pZGFkZXNfcmVnZXhgIChxdWUgc3VyZ2UgZGVsIHRleHRvIGVuIGBOb21icmVgKSBubyBjb2luY2lkZSBjb24gbGEgdmFyaWFibGUgYHVuaWRhZGVzYCwgeSBlc3RhYmxlY2ltb3MgcXVlIGxhcyBjYW50aWRhZGVzIHJlZmVyaWRhcyBhIGxhcyB1bmlkYWRlcyBwb3IgcGFxdWV0ZSBwYXJlY2VuIHNlciBtZWpvciBjYXB0YWRhcyBjb24gZWwgbcOpdG9kbyBkZSByZWdleCBzb2JyZSBlbCB0ZXh0byBkZWwgYE5vbWJyZWAgZGVsIHByb2R1Y3RvLCByZXNwZWN0byBkZSBsbyBzdXJnaWRvIGRlIGxhIGluZm9ybWFjacOzbiBkZSBsYSBww6FnaW5hIGNvbW8gYFByZXNlbnRhY2nDs25gLiBOb3MgcXVlZGFtb3MgY29uIGB1bmlkYWRlc19yZWdleGAgcGFyYSBjYWxjdWxhciBlbCBwcmVjaW8gcG9yIHVuaWRhZCBkZSBsb3MgcHJvZHVjdG9zLgoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyBFc3RlIGNvZGlnbyBlc3RhIGFudWxhZG8uIEVzIGxvIHF1ZSBlc3RhYmEgZW4gZWwgZWplcmNpY2lvIGFudGVyaW9yCnVuaWRhZGVzLmZhbHRhbnRlcyA8LSBkYXRvcyAlPiUgCiAgZmlsdGVyKGlzLm5hKHVuaWRhZGVzLnJlZ2V4KSkgJT4lIAogIHNlbGVjdChOb21icmUsIHVuaWRhZGVzLnJlZ2V4LCBQcmVzZW50YWNpw7NuLCB1bmlkYWRlcykgJT4lIAogIGdyb3VwX2J5KE5vbWJyZSwgdW5pZGFkZXMucmVnZXgsIFByZXNlbnRhY2nDs24sIHVuaWRhZGVzKSAlPiUgCiAgc3VtbWFyaXNlKG4oKSkKCmRhdG9zIDwtIGRhdG9zICU+JSAKICBmaWx0ZXIoIWlzLm5hKHVuaWRhZGVzLnJlZ2V4KSkKCmthYmxlKHVuaWRhZGVzLmZhbHRhbnRlcykgJT4lIAogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRikKCnZlcmlmIDwtIGRhdG9zICU+JSAKICBmaWx0ZXIodW5pZGFkZXMucmVnZXggIT0gdW5pZGFkZXMpICU+JSAKICBncm91cF9ieShOb21icmUsIHVuaWRhZGVzLCB1bmlkYWRlcy5yZWdleCkgJT4lIAogIHN1bW1hcmlzZShuPW4oKSkgJT4lIAogIGFycmFuZ2UoLW4pCgprYWJsZSh2ZXJpZikgJT4lIAogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRikKYGBgCgpFc3RhIHZleiwgZGFkbyBxdWUgZWwgcG9yY2VudGFqZSBkZSBhcXVlbGxvcyBjYXNvcyBlbiBxdWUgbm8gY29pbmNpZGVuIGB1bmlkYWRlc2AgeSBgdW5pZGFkZXNfcmVnZXhgLCBqdW50byBhIGxvcyBjYXNvcyBlbiBxdWUgYHVuaWRhZGVzX3JlZ2V4YCBmaWd1cmEgY29tbyBgTkFgLCBhbGNhbnphbiBzb2xhbWVudGUgdW4gMC4yNyUsIHNlIHByZXNjaW5kaXLDoSBkZSBlbGxvcy4gCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyA8LSBkYXRvcyAlPiUgCiAgZmlsdGVyKGlndWFsID09IFRSVUUpCmBgYAoKX19TZSBkZXNjYXJ0YW4gMjI0IGNhc29zX18geSBhaG9yYSBjb250YW1vcyBjb24gYHIgY2FudChucm93KGRhdG9zKSlgIG9ic2VydmFjaW9uZXMuIFRhbWJpw6luIHBvZGVtb3MgZGVzaGFjZXJub3MgZGUgdmFyaWFibGVzIHF1ZSBubyB2YW1vcyBhIHV0aWxpemFyIGVuIGVsIGVqZXJjaWNpbyBkZSBlc3RpbWFjacOzbi4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgRGVzY2FydG8gbGFzIHZhcmlhYmxlcyBxdWUgbm8gdm95IGEgdXNhcgpkYXRvcyA8LSBkYXRvcyAlPiUgCiAgc2VsZWN0KC1QcmVzZW50YWNpw7NuLCAtdW5pZGFkZXNfcmVnZXgsIC1pZ3VhbCkKYGBgCiAgICAgICAgCiMjIEPDoWxjdWxvIGRlbCBwcmVjaW8gcG9yIHVuaWRhZAoKQ3JlbyBsYSB2YXJpYWJsZSBgcHJlY2lvX3VuaWRhZGAsIGRpdmlkaWVuZG8gZWwgYFByZWNpby5kZS5saXN0YWAgcG9yIGxhcyBgdW5pZGFkZXNgLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgPC0gZGF0b3MgJT4lIAogIG11dGF0ZShwcmVjaW9fdW5pZGFkID0gcm91bmQoUHJlY2lvLmRlLmxpc3RhL3VuaWRhZGVzLCAyKSkKYGBgCgojIyBHcsOhZmljb3MgZGVsIHByZWNpbyBwb3IgdW5pZGFkCgpBaG9yYSBwb2RlbW9zIG9ic2VydmFyIGxhIGRpc3RyaWJ1Y2nDs24gZGUgZXN0YSBudWV2YSB2YXJpYWJsZSBjb24gbG9zIG1pc21vcyBncsOhZmljb3MgcXVlIHV0aWxpemFtb3MgYW50ZXMuCgpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTcsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRvcywgYWVzKHggPSBwcmVjaW9fdW5pZGFkLCB5ID0gQ2F0ZWdvcsOtYSwgZmlsbCA9IENhdGVnb3LDrWEpKSArCiAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhzY2FsZSA9IDIsIGJhbmR3aWR0aCA9IDEuMjUpICsgIyBlbCBiYW5kd2lkdGggYW50ZXJpb3IgZXN0YWJhIGVuIDEwCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAzMCkpICsgIyBFbiBlbCBhbnRlcmlvciBlbCBsaW1pdGUgZXN0YWJhIGVuIDIwCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygicmVkIiwgInZpb2xldHJlZCIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gcG9yIHVuaWRhZCBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIiwKICAgICAgIHN1YnRpdGxlID0gZGF0ZSwKICAgICAgIHggPSAiUHJlY2lvIHBvciB1bmlkYWQiLAogICAgICAgeSA9ICIiLAogICAgICAgY2FwdGlvbiA9ICJGdWVudGU6ICNNZW5zdHJ1QWNjacOzbiIpCmBgYAoKRXN0YSB2ZXosIHBhcmEgcmVhbGl6YXIgZWwgZ3LDoWZpY28gcG9yIGNhdGVnb3LDrWFzIHkgcmVnaW9uZXMsIHBvZGVtb3Mgb3JkZW5hciBhIGVzdGFzIMO6bHRpbWFzIHNlZ8O6biBzdSBwcmVjaW8gcHJvbWVkaW8gZW4gZWwgZ3LDoWZpY28uIFBhcmEgZWxsbyBjb25zdHJ1aW1vcyB1biB2ZWN0b3IgcXVlIGxhcyBhbG9qZSBlbiBvcmRlbiwgbGxhbWFkbyBgcmVnX29yZGVuYWRhc2AuIEx1ZWdvLCBwaXNhbW9zIGxhIHZhcmlhYmxlIGBSZWdpb25gIGVuIGxvcyBkYXRvcyBwYXJhIHF1ZSBzZWEgZGUgdGlwbyBmYWN0b3IsIHkgZWwgb3JkZW4gZGUgbGEgbWlzbWEgZXN0w6kgZGV0ZXJtaW5hZG8gc2Vnw7puIGVsIHZlY3RvciBwcmV2aWFtZW50ZSBkZWZpbmlkby4KCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcmVnX29yZGVuYWRhcyA8LSBkYXRvcyAlPiUgCiAgZ3JvdXBfYnkoUmVnaW9uKSAlPiUgCiAgc3VtbWFyaXNlKHByb21lZGlvID0gbWVhbihwcmVjaW9fdW5pZGFkKSkgJT4lIAogIGFycmFuZ2UocHJvbWVkaW8pICUkJSBSZWdpb24KCmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUoUmVnaW9uID0gZmFjdG9yKFJlZ2lvbiwgbGV2ZWxzID0gcmVnX29yZGVuYWRhcykpCmBgYAoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZGF0b3MsIGFlcyh4ID0gcHJlY2lvX3VuaWRhZCwgeSA9IFJlZ2lvbiwgZmlsbCA9IENhdGVnb3LDrWEsIGFscGhhID0gUmVnaW9uKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2NhbGUgPSAyLCBiYW5kd2lkdGggPSAxLjI1KSArICMgZWwgYmFuZHdpZHRoIGFudGVyaW9yIGVzdGFiYSBlbiAxCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQiLCAidmlvbGV0cmVkIikpKwogIGZhY2V0X3dyYXAoLiB+IENhdGVnb3LDrWEpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAzMCkpICsgIyBFc3RlIHZhbG9yIHNlIGFjdHVhbGl6YSBzZWd1biBpbmZsYWNpb24sIGEgb2pvCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gcG9yIHVuaWRhZCBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIHkgcmVnacOzbiIsCiAgICAgICBzdWJ0aXRsZSA9IGRhdGUsCiAgICAgICB4ID0gIlByZWNpbyBwb3IgdW5pZGFkIiwKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiAjTWVuc3RydUFjY2nDs24iKQpgYGAKCiMjIDIsNSAlIGRlIGxvcyBleHRyZW1vcyBkZSBsYSBkaXN0cmlidWNpw7NuCgpBZGljaW9uYWxtZW50ZSwgY29tbyBlbCBjw6FsY3VsbyBsbyByZWFsaXphcmVtb3MgYWdyZWdhbmRvIGxvcyBwcmVjaW9zIGRlIGFjdWVyZG8gYSB1bmEgbWVkaWEgYWxwaGEgcG9kYWRhIGNvbiBhbHBoYSA9IDIsNSUgKG8gc2VhLCBpZ25vcmFuZG8gbG9zIHZhbG9yZXMgc3VwZXJpb3JlcyBlIGluZmVyaW9yZXMgcGFyYSBldml0YXIgbGEgaW50cnVzacOzbiBkZSBvdXRsaWVycyBhIHBlc2FyIGRlIGxhIGxpbXBpZXphKSwgcHJlc2VudGFtb3MgZ3LDoWZpY29zIHF1ZSBqdXN0YW1lbnRlIG11ZXN0cmFuIGxhcyAiY29sYXMiIGRlIGxhIGRpc3RyaWJ1Y2nDs24gcXVlIHNlIGVzdGFyw61hbiBvYnZpYW5kby4KCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGRhdG9zLCBhZXMoeCA9IHByZWNpb191bmlkYWQsIHkgPSBDYXRlZ29yw61hLCBmaWxsID0gZmFjdG9yKC4ucXVhbnRpbGUuLikpKSArCiAgc3RhdF9kZW5zaXR5X3JpZGdlcyhnZW9tID0gImRlbnNpdHlfcmlkZ2VzX2dyYWRpZW50IiwgCiAgICAgICAgICAgICAgICAgICAgICBjYWxjX2VjZGYgPSBUUlVFLCBxdWFudGlsZXMgPSBjKDAuMDI1LCAwLjk3NSksCiAgICAgICAgICAgICAgICAgICAgICBiYW5kd2lkdGggPSAxLjI1LCBzY2FsZSA9IDEuNSkgKyAjIEVsIGJhbmR3aWR0aCBhbnRlcmlvciBlc3RhYmEgZW4gMC43NQogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiUHJvYmFiaWxpZGFkIiwgCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygidmlvbGV0cmVkMSIsICJyZWQyIiwgInZpb2xldHJlZDEiKSwKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIyLDUgJSIsICI5NSwwICUiLCAiMiw1ICUiKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDMwKSkgKyAjIEVsIGxpbWl0ZSBhbnRlcmlvciBlc3RhYmEgZW4gMjAKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gcG9yIHVuaWRhZCBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIiwKICAgICAgIHN1YnRpdGxlID0gcGFzdGUoZGF0ZSksCiAgICAgICB4ID0gIlByZWNpbyBwb3IgdW5pZGFkIiwKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiAjTWVuc3RydUFjY2nDs24iKQpgYGAKClJlYWxpemFtb3MgZWwgbWlzbW8gZ3LDoWZpY28gcG9yIGNhZGEgcHJvdmluY2lhLCB5YSBxdWUgZXNhIHNlcsOhIGxhIHByaW1lciB1bmlkYWQgZGUgYWdyZWdhY2nDs24gcGFyYSBlbCBjw6FsY3VsbyB0b3RhbCBhIG5pdmVsIG5hY2lvbmFsLgoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwcm92X29yZGVuYWRhcyA8LSBkYXRvcyAlPiUgCiAgZ3JvdXBfYnkoUHJvdmluY2lhKSAlPiUgCiAgc3VtbWFyaXNlKHByb21lZGlvID0gbWVhbihwcmVjaW9fdW5pZGFkKSkgJT4lIAogIGFycmFuZ2UocHJvbWVkaW8pICUkJSAKICBQcm92aW5jaWEKCmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUoUHJvdmluY2lhID0gZmFjdG9yKFByb3ZpbmNpYSwgbGV2ZWxzID0gcHJvdl9vcmRlbmFkYXMpKQpgYGAKCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTksIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRvcywgYWVzKHggPSBwcmVjaW9fdW5pZGFkLCB5ID0gUHJvdmluY2lhLCAKICAgICAgICAgICAgICAgICAgZmlsbCA9IGZhY3RvciguLnF1YW50aWxlLi4pKSkgKwogIHN0YXRfZGVuc2l0eV9yaWRnZXMoZ2VvbSA9ICJkZW5zaXR5X3JpZGdlc19ncmFkaWVudCIsIAogICAgICAgICAgICAgICAgICAgICAgY2FsY19lY2RmID0gVFJVRSwgcXVhbnRpbGVzID0gYygwLjAyNSwgMC45NzUpLAogICAgICAgICAgICAgICAgICAgICAgYmFuZHdpZHRoID0gMS4yNSwgc2NhbGUgPSAyKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJQcm9iYWJpbGlkYWQiLCAKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ2aW9sZXRyZWQxIiwgInJlZDIiLCAidmlvbGV0cmVkMSIpLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjIsNSAlIiwgIjk1LDAgJSIsICIyLDUgJSIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMzApKSArICMgRWwgbGltaXRlIGFudGVyaW9yIGVzdGFiYSBlbiAyMAogIGZhY2V0X3dyYXAoLiB+IENhdGVnb3LDrWEpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gcG9yIHVuaWRhZCBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIHkgcHJvdmluY2lhIiwKICAgICAgIHN1YnRpdGxlID0gcGFzdGUoZGF0ZSwgIi4gIiksCiAgICAgICB4ID0gIlByZWNpbyBwb3IgdW5pZGFkIiwKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiAjTWVuc3RydUFjY2nDs24iKQpgYGAKCiMjIEFww6luZGljZTogUHJlY2lvcyBpZ3VhbGVzIGEgY2VybwoKRW4gZXN0YSBvY2FzacOzbiwgbm8gaGF5IHByZWNpb3MgaWd1YWxlcyBhIGNlcm8sIGNvbiBsbyBxdWUgc2UgcHJlc2NpbmRlIGRlIGRpY2hvIGFuw6FsaXNpcy4KICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIAoKRmluYWxtZW50ZSwgZ3VhcmRhbW9zIGVzdGEgbnVldmEgdmVyc2nDs24gZGVsIGRhdGFzZXQgZW4gZm9ybWF0byAuUkRTIHBhcmEgY29udGludWFyIGVuIGVsIHNpZ3VpZW50ZSBzY3JpcHQgY29uIGVsIGPDoWxjdWxvIGRlIGN1w6FudG8gY3Vlc3RhIG1lbnN0cnVhci4KCmBgYHtyIGVjaG89VFJVRX0KI3NhdmVSRFMoZGF0b3MsIGZpbGUgPSAiRnVlbnRlcy9wcmVjaW9zLWdlc3Rpb24tbWVuc3RydWFsLTIwMjEtMDktMTctbGltcGlvLlJEUyIpCmBgYAo=