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.

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:

head(datos)

Vista previa del diccionario de regiones:

head(regiones)

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:

names(datos)
 [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))) 

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

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

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

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

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:

# Solo en esta ocasión por los outliers presentes:

datos <- datos %>% 
  filter(Precio.de.lista < 1000) #saco los outliers mayores a 1000 porque son demasiado altos. 
# El resto va a ser controlado a la hora de calcular la media de precios de forma "podada"

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) + # el bandwidth anterior estaba en 10
  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

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

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

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

Vale la pena destacar que estos errores corresponden a todas las regiones, mayormente concentrados en GBA, y en 5 marcas diferentes.

# Distribucion de los datos que queremos sacar entre las regiones
datos %>% 
  filter(igual == FALSE) %>% 
  count(Region)

# Distribucion de los datos que queremos sacar entre las marcas
datos %>% 
  filter(igual == FALSE) %>% 
  count(Marca)

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.

# Descarto las variables que no voy a usar
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) + # el bandwidth anterior estaba en 10
  theme_minimal() +
  scale_x_continuous(limits = c(0, 30)) + # En el anterior el limite estaba en 20
  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) + # el bandwidth anterior estaba en 1
  theme_minimal() +
  scale_fill_manual(values = c("red", "violetred"))+
  facet_wrap(. ~ Categoría) +
  theme(legend.position = "none") +
  scale_x_continuous(limits = c(0, 30)) + # Este valor se actualiza segun inflacion, a ojo
  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) + # El bandwidth anterior estaba en 0.75
  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)) + # El limite anterior estaba en 20
  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)) + # El limite anterior estaba en 20
  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.

#saveRDS(datos, file = "Fuentes/precios-gestion-menstrual-2021-09-17-limpio.RDS")
LS0tCnRpdGxlOiAiTGltcGllemEgeSBvcmdhbml6YWNpw7NuIGRlIGxvcyBkYXRvcyBkZWwgI01lbnN0cnVTY3JhcHBlciIKc3VidGl0bGU6ICJEYXRvcyBkZSBTZXB0aWVtYnJlIDIwMjEiCmF1dGhvcjogIkVjb2ZlbWluaXRhIC8gI01lbnN0cnVBY2Npw7NuIC8gRWNvZmVtaWRhdGEiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiBmYWxzZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDUKLS0tCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgogIGJvZHl7CiAgZm9udC1zaXplOiAxNHB0Owp9Cjwvc3R5bGU+CgohW10oaW1nL0xvZ29zIEVjb0ZlbWluaXRhLTAzLnBuZyl7d2lkdGg9MTMwcHh9ICFbXShpbWcvTUVOU1RSVUFDQ0lPTi5wbmcpe3dpZHRoPTExMHB4fSAhW10oaW1nL0Vjb2ZlbWlkYXRhLnBuZyl7d2lkdGg9MTAwcHh9CgojIyBQcmVzZW50YWNpw7NuCgpFbiBlbCBtYXJjbyBkZWwgY8OhbGN1bG8gZGVsIGNvc3RvIGRlIG1lbnN0cnVhciBlbiBBcmdlbnRpbmEsIGxsZXZhZG8gYSBjYWJvIGRlc2RlIGxhIGNhbXBhw7FhICNNZW5zdHJ1QWNjacOzbiB5IEVjb0ZlbWluaXRhcywgZW4gZWwgcHJlc2VudGUgZG9jdW1lbnRvIGRlIHRyYWJham8gc2UgZW5jdWVudHJhIGxhIGV4cGxvcmFjacOzbiwgb3JnYW5pemFjacOzbiB5IGxpbXBpZXphIGRlIGxvcyBkYXRvcyBvYnRlbmlkb3MgbWVkaWFudGUgZWwgWyNNZW5zdHJ1U2NyYXBwZXJdKGh0dHBzOi8vZ2l0aHViLmNvbS9ucG9ydGFzL21lbnN0cnVzY3JhcHBlciksIGRlc2Fycm9sbGFkbyBwb3IgTmF5bGEgUG9ydGFzIGRlIFtMQVNdIGRlIHNpc3RlbWFzLiBFbCAjTWVuc3RydVNjcmFwcGVyIGZ1ZSBlamVjdXRhZG8gZWwgZMOtYSAxNyBkZSBTZXB0aWVtYnJlIGRlIDIwMjEgc29icmUgbGEgcMOhZ2luYSBQcmVjaW9zIENsYXJvcywgc3Vtw6FuZG9zZSBlc3RhIGluZm9ybWFjacOzbiBhIGxhIG9idGVuaWRhIGFudGVyaW9ybWVudGUgZW4gU2VwdGllbWJyZSB5IE1hcnpvIGRlIDIwMTksIE1hcnpvIHkgU2VwdGllbWJyZSBkZSAyMDIwLCB5IE1hcnpvIGRlIDIwMjEuIEVuIGVzdGEgaW5zdGFuY2lhLCBzZSBvYnR1dmllcm9uIDgzLjMxNyBvYnNlcnZhY2lvbmVzIGVuIHRvdGFsLgoKKyBSZXNwZWN0byBkZSBsb3MgdGFtcG9uZXM6IFNlIG9idHV2aWVyb24gMTcuNzk5IHByZWNpb3MuCisgUmVzcGVjdG8gZGUgbGFzIHRvYWxsaXRhczogU2Ugb2J0dXZpZXJvbiA2NS41MTggcHJlY2lvcy4KCkVuIFtudWVzdHJvIHJlcG9zaXRvcmlvXShodHRwczovL2dpdGh1Yi5jb20vRWNvZmVtaW5pdGEvRWNvRmVtaURhdGEvdHJlZS9tYXN0ZXIvTWVuc3RydUFjY2lvbi9jdWFudG9fY3Vlc3RhX21lbnN0cnVhcikgc2UgZW5jdWVudHJhbiBhY2xhcmFkYXMgdG9kYXMgbGFzIGZ1ZW50ZXMgYWRpY2lvbmFsZXMgYSBsYXMgcXVlIHNlIHJlY3VycmnDsyBwYXJhIHJlYWxpemFyIGVsIGPDoWxjdWxvIHkgbG9zIGFyY2hpdm9zIGNvcnJlc3BvbmRpZW50ZXMuIEVuIG90cm8gcGFzbyBzZSBlbmN1ZW50cmEgZWwgY8OhbGN1bG8gcHJvcGlhbWVudGUgZGljaG8gZGVsIGNvc3RvIGFudWFsIGRlIG1lbnN0cnVhci4gCgojIyBQcmVwYXJhbmRvIGVsIGVudG9ybm8gZGUgdHJhYmFqbwoKQ29tZW56YW1vcyBsZXZhbnRhbmRvIGxhcyBsaWJyZXLDrWFzIG5lY2VzYXJpYXMsIGNhcmdhbmRvIGxvcyBkYXRvcyBzcmFwcGVhZG9zIGRlc2RlIGVsIGFyY2hpdm8gLmNzdiwgeSB1biBkaWNjaW9uYXJpbyBxdWUgaW5kaWNhIGEgcXXDqSByZWdpw7NuIHBlcnRlbmVjZSBjYWRhIHByb3ZpbmNpYSBkZWwgcGHDrXMuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KEVudlN0YXRzKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3JpZGdlcykKbGlicmFyeShvcGVueGxzeCkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoa2FibGVFeHRyYSkKCmRhdG9zIDwtIHJlYWQuY3N2KCJGdWVudGVzL3ByZWNpb3MtZ2VzdGlvbi1tZW5zdHJ1YWwtMjAyMS0wOS0xNy5jc3YiLCAKICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwgc2VwID0gIiwiLCBkZWMgPSAiLiIsIAogICAgICAgICAgICAgICAgICBmaWxsID0gVFJVRSwgZW5jb2RpbmcgPSAiVVRGLTgiKQoKcmVnaW9uZXMgPC0gb3Blbnhsc3g6OnJlYWQueGxzeCgiRnVlbnRlcy9wcm92aW5jaWFzX3JlZ2lvbmVzLnhsc3giKQpgYGAKClZpc3RhIHByZXZpYSBkZWwgZGF0YXNldDoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmhlYWQoZGF0b3MpCmBgYAoKVmlzdGEgcHJldmlhIGRlbCBkaWNjaW9uYXJpbyBkZSByZWdpb25lczoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmhlYWQocmVnaW9uZXMpCmBgYAoKRGVmaW5pbW9zIHVuYSBwZXF1ZcOxYSBmdW5jacOzbjogYGNhbnRgIG5vcyB2YSBhIGRldm9sdmVyIHVuIG7Dum1lcm8gZW4gZm9ybWF0byBjaGFyYWN0ZXIgKHRleHRvKSwgY29uIGNlcm8gZMOtZ2l0b3MsIGNvbiB1biBwdW50byBwYXJhIHNlcGFyYXIgbG9zIG1pbGVzLCB5IHVuYSBjb21hIHBhcmEgc2VwYXJhciBsb3MgZGVjaW1hbGVzLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY2FudCA8LSBmdW5jdGlvbih4KXsKICBmb3JtYXQoeCwgZGlnaXRzID0gMCwgYmlnLm1hcmsgPSAiLiIsIGRlY2ltYWwubWFyayA9ICIsIil9CmBgYAoKR3VhcmRhbW9zIGVsIHZhbG9yIGRlIGxhIGZlY2hhIGEgbGEgcXVlIGNvcnJlc3BvbmRlIGVsIGVqZXJjaWNpby4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdGUgPC0gIlNlcHRpZW1icmUgMjAyMSIKYGBgCgojIyBFeHBsb3JhY2nDs24gZGUgbG9zIGRhdG9zCgpBbCBkYXRhZnJhbWUgYGRhdG9zYCBsZSBwZWdhbW9zIGxvcyB2YWxvcmVzIGRlIGxhcyByZWdpb25lcywgdXNhbmRvIGNvbW8gdmFyaWFibGUgZGUgaWRlbnRpZmljYWNpw7NuIGEgbGEgYFByb3ZpbmNpYWAuIEEgY29udGludWFjacOzbiBwb2RlbW9zIGJvcnJhciBkZSBudWVzdHJvIGVudG9ybm8gZGUgdHJhYmFqbyBlbCBlbGVtZW50byBgcmVnaW9uZXNgLiAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zIDwtIGxlZnRfam9pbihkYXRvcywgcmVnaW9uZXMsIGJ5ID0gIlByb3ZpbmNpYSIpCnJtKHJlZ2lvbmVzKQpgYGAKCmBkYXRvc2AgY3VlbnRhIGNvbiBgciBjYW50KG5yb3coZGF0b3MpKWAgb2JzZXJ2YWNpb25lcy4gQSBzdSB2ZXosIHBvZGVtb3MgdmVyIGNvbiBxdcOpIHZhcmlhYmxlcyBjb250YW1vcyBlbiBlbCBkYXRhc2V0OgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbmFtZXMoZGF0b3MpCmBgYAoKQSBjb250aW51YWNpw7NuLCBleHBsb3JhcmVtb3MgZWwgY29tcG9ydGFtaWVudG8gZGUgbGFzIGRpZmVyZW50ZXMgdmFyaWFibGVzLiBDb24gYGNvdW50KClgIHBlZGltb3MgdW4gY29udGVvIGRlIG9ic2VydmFjaW9uZXMgcGFyYSBjYWRhIHZhbG9yIHF1ZSB0b21hIGxhIHZhcmlhYmxlIGFjbGFyYWRhLCBjb24gYGFycmFuZ2UoKWAgb3JkZW5hbW9zIGxvcyBkYXRvcyBkZSBmb3JtYSBkZWNyZWNpZW50ZSBzZWfDum4gZWwgY29udGVvIGFudGVyaW9yLCB5IGVuIGBtdXRhdGUoKWAgc2UgZGVmaW5lbiBudWV2YXMgdmFyaWFibGVzIHBhcmEgbnVlc3RybyBjdWFkcm8uIFBvciBlamVtcGxvLCBlbCBwb3JjZW50YWplIGVzIGxhIGNhbnRpZGFkIGRlIGNhZGEgY2F0ZWdvcsOtYSBzb2JyZSBsYSBzdW1hIGRlIGxhcyBtaXNtYXMsIGV4cHJlc2FkYSBlbiBmb3JtYXRvIGRlIHBvcmNlbnRhamUuCgojIyMgQ2F0ZWdvcsOtYXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zICU+JSAKICBjb3VudChDYXRlZ29yw61hKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIG11dGF0ZShwb3JjZW50YWplID0gcGVyY2VudChuL3N1bShuKSkpIApgYGAKCkNhYmUgZGVzdGFjYXIgcXVlIGVzdGEgY29tcG9zaWNpw7NuIGNvcnJlc3BvbmRlIGEgbGEgZGlzcG9uaWJpbGlkYWQgZGUgcHJlY2lvcywgbm8gcmVmbGVqYSBsYSBlc3RydWN0dXJhIGRlbCBjb25zdW1vLiBPIHNlYSwgbm8gcG9kZW1vcyBkZWNpciBxdWUgc2UgY29uc3VtZW4gZW4gdW4gODAlIHRvYWxsaXRhcyB5IGVuIDIwJSB0YW1wb25lcy4gTG8gcXVlIHPDrSBzYWJlbW9zIGVzIHF1ZSB0ZW5lbW9zIHVuYSBtdWVzdHJhIG11eSBncmFuZGUgZGUgcHJlY2lvcyBwYXJhIGFtYmFzIGNhdGVnb3LDrWFzLCBhdW5xdWUgZGViZW1vcyB0ZW5lciBlbiBjdWVudGEgcXVlIGxhIHDDoWdpbmEgZGUgUHJlY2lvcyBDbGFyb3MgcHVlZGUgdGVuZXIgdW4gc2VzZ28gcG9yIG5vIGluY2x1aXIgbG9zIGNvbWVyY2lvcyB0cmFkaWNpb25hbGVzIHNpbm8gw7puaWNhbWVudGUgZ3JhbmRlcyBjYWRlbmFzLgoKIyMjIE1hcmNhcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lIAogIGNvdW50KE1hcmNhKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIG11dGF0ZShwb3JjZW50YWplID0gbi9zdW0obiksCiAgICAgICAgIGFjdW11bGFkbyA9IGN1bXN1bShwb3JjZW50YWplKSwKICAgICAgICAgcG9yY2VudGFqZSA9IHBlcmNlbnQocG9yY2VudGFqZSksCiAgICAgICAgIGFjdW11bGFkbyA9IHBlcmNlbnQoYWN1bXVsYWRvKSkKYGBgCgpDb250YW1vcyBjb24gMjggbWFyY2FzIGRlIHByb2R1Y3RvcywgYXVucXVlIGNvbiAxMCBkZSBlbGxhcyBzZSBjb21wbGV0YSBlbCA5MCUgZGVsIHRvdGFsIGRlIHByb2R1Y3Rvcy4gTGFzIHByaW1lcmFzIDMgbWFyY2FzIGNvbmNlbnRyYW4gY2FzaSBsYSBtaXRhZCBkZSBsYXMgb2JzZXJ2YWNpb25lcy4gTnVldmFtZW50ZSBhcXXDrSBoYXkgcXVlIHRlbmVyIGVuIGN1ZW50YSBxdWUgbm8gc2UgdHJhdGEgZXhhY3RhbWVudGUgZGUgdW5hICJjb25jZW50cmFjacOzbiBkZSBtZXJjYWRvIi4KCiMjIyBQcmVzZW50YWNpw7NuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyAlPiUgCiAgY291bnQoUHJlc2VudGFjacOzbikgJT4lIAogIGFycmFuZ2UoLW4pICU+JSAKICBtdXRhdGUocG9yY2VudGFqZSA9IG4vc3VtKG4pLAogICAgICAgICBhY3VtdWxhZG8gPSBjdW1zdW0ocG9yY2VudGFqZSksCiAgICAgICAgIHBvcmNlbnRhamUgPSBwZXJjZW50KHBvcmNlbnRhamUpLAogICAgICAgICBhY3VtdWxhZG8gPSBwZXJjZW50KGFjdW11bGFkbykpCmBgYAoKQ2FzaSBlbCA5MCUgZGUgbG9zIHByb2R1Y3RvcyB2aWVuZW4gZW4gcGFxdWV0ZXMgZGUgOCBvIDE2IHVuaWRhZGVzLiBMdWVnbyBzZWd1aXJlbW9zIGFuYWxpemFuZG8gZXN0YSB2YXJpYWJsZSBlbiBwYXJ0aWN1bGFyLCBwb3JxdWUgbm9zIGludGVyZXNhIHBhcmEgY2FsY3VsYXIgbG9zIHByZWNpb3MgdW5pdGFyaW9zIGRlIGxvcyBwcm9kdWN0b3MsIHkgaGF5IHZhbG9yZXMgKGNvbW8gIjEuMCB1biIpIHF1ZSBzb24gcmFyb3MgeSwgZW4gY2FzbyBkZSB0cmF0YXJzZSBkZSBlcnJvcmVzLCBwb2Ryw61hbiBhcnJhc3RyYXIgcHJvYmxlbWFzIGhhY2lhIGVsIGPDoWxjdWxvIGRlIGVzb3MgcHJlY2lvcy4KCiMjIyBQcm92aW5jaWFzCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyAlPiUgCiAgY291bnQoUHJvdmluY2lhKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIG11dGF0ZShwb3JjZW50YWplID0gbi9zdW0obiksCiAgICAgICAgIGFjdW11bGFkbyA9IGN1bXN1bShwb3JjZW50YWplKSwKICAgICAgICAgcG9yY2VudGFqZSA9IHBlcmNlbnQocG9yY2VudGFqZSksCiAgICAgICAgIGFjdW11bGFkbyA9IHBlcmNlbnQoYWN1bXVsYWRvKSkKYGBgCgpTaSBiaWVuIG3DoXMgZGUgbGEgbWl0YWQgZGUgbGFzIG9ic2VydmFjaW9uZXMgc2UgY29uY2VudHJhbiBlbiBCdWVub3MgQWlyZXMgeSBDQUJBLCBlcyBpbXBvcnRhbnRlIHNhYmVyIHF1ZSBzZSBjdWVudGEgY29uIGluZm9ybWFjacOzbiBkZSB0b2RhcyBsYXMgcHJvdmluY2lhcyBkZWwgcGHDrXMsIHkgcXVlIGluY2x1c28gZW4gZWwgcGVvciBkZSBsb3MgY2Fzb3MgKHBvciBlamVtcGxvLCAxNjUgb2JzZXJ2YWNpb25lcyBlbiBDYXRhbWFyY2EpIHNlIHRyYXRhIGRlIHVuYSBjYW50aWRhZCBwYXNpYmxlIGRlIHByb3ZlZXJub3MgZXN0aW1hY2lvbmVzIMO6dGlsZXMuCgojIyMgUmVnaW9uZXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zICU+JSAKICBjb3VudChSZWdpb24pICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgCiAgbXV0YXRlKHBvcmNlbnRhamUgPSBuL3N1bShuKSwKICAgICAgICAgYWN1bXVsYWRvID0gY3Vtc3VtKHBvcmNlbnRhamUpLAogICAgICAgICBwb3JjZW50YWplID0gcGVyY2VudChwb3JjZW50YWplKSwKICAgICAgICAgYWN1bXVsYWRvID0gcGVyY2VudChhY3VtdWxhZG8pKQpgYGAKCkVuIHTDqXJtaW5vcyByZWdpb25hbGVzIHNlZ3VpbW9zIHZpZW5kbyBlc2EgYXNpbWV0csOtYSBlbiBsYSBkaXNwb25pYmlsaWRhZCBkZSBkYXRvcywgcGVybyBoYXkgcXVlIHRlbmVyIGVuIGN1ZW50YSBxdWUgZWZlY3RpdmFtZW50ZSBoYXkgZGlmZXJlbmNpYXMgZGUgZXNjYWxhIGRlIG1lcmNhZG9zIGVuIHTDqXJtaW5vcyByZWdpb25hbGVzLgoKIyMjIFByZWNpbyBkZSBsaXN0YQoKQWhvcmEgZ3JhZmljYW1vcyBsYSBkaXN0cmlidWNpw7NuIGRlIGxvcyBwcmVjaW9zIGRlIGxpc3RhIChvIHNlYSwgc2luIHRlbmVyIGVuIGN1ZW50YSBsYXMgdW5pZGFkZXMgcG9yIHBhcXVldGUpIHNlZ8O6biBjYWRhIGNhdGVnb3LDrWEuIFBhcmEgZWxsbyB1dGlsaXphbW9zIGBnZ3Bsb3QyYC4gCgpFbiBsYSBwcmltZXIgbMOtbmVhIGRlIGPDs2RpZ28gcmVmZXJpZGEgYSBgZ2dwbG90YCwgdG9tYW1vcyBjb21vIGZ1ZW50ZSBlbCBkYXRhc2V0IHF1ZSB2ZW5pbW9zIHV0aWxpemFuZG8gKGEgZXNvIHJlZmllcmUgZWwgcHVudG8pLCBlbiBlbCBgZWplIHhgIHF1ZXJlbW9zIGxvcyBwcmVjaW9zLCBlbiBlbCBgZWplIHlgIHF1ZXJlbW9zIGNhZGEgY2F0ZWdvcsOtYSwgeSBlbCByZWxsZW5vIGRlIGNhZGEgcGFydGUgZGVsIGdyw6FmaWNvIHRhbWJpw6luIHNlZ8O6biBsYXMgY2F0ZWdvcsOtYXMgZGUgcHJvZHVjdG9zLiBFbiBsYSBzZWd1bmRhIGzDrW5lYSBhY2xhcmFtb3MgcXVlIHF1ZXJlbW9zIHVuIGdyw6FmaWNvIGRlIGRlbnNpZGFkIChxdWUgZXMgY29tbyB1biBoaXN0b2dyYW1hIHBlcm8gZW4gdmVyc2nDs24gY29udGludWEpLCBsYSBlc2NhbGEgaGFjZSBhIGxhIHN1cGVycG9zaWNpw7NuIGRlIGxvcyBncmFmaWNvcyB5IGVsIGBiYW5kd2lkdGhgIG8gImFuY2hvIGRlIGJhbmRhIiBpbmRpY2EgbGEgZXh0ZW5zacOzbiBkZWwgaW50ZXJ2YWxvIGRlIHZhbG9yZXMgY29uIGxvcyBxdWUgc2UgdmEgYSByZWFsaXphciBsYSBlc3RpbWFjacOzbiBkZWwgZ3LDoWZpY28gKG8gc2VhLCBzaSBlbCBncsOhZmljbyB2YSBhIHNlciBtw6FzIGRldGFsbGlzdGEgeSBwb3IgZW5kZSBtw6FzICJydWlkb3NvIiwgbyBtw6FzIHN1YXZlIHkgInJlZG9uZGVhZG8iKS4gU2UgcHVlZGUganVnYXIgY29uIGFtYm9zIHZhbG9yZXMgcGFyYSB2ZXIgc3VzIGVmZWN0b3MuIEVuIGxhIHRlcmNlciBsw61uZWEgYWNsYXJhbW9zIHF1ZSBxdWVyZW1vcyB1biB0ZW1hIG1pbmltYWxpc3RhLCBlbiBsYSBjdWFydGEgcXVlIGxhIHBhbGV0YSBkZSBjb2xvcmVzIGxhIHZhbW9zIGEgYXNpZ25hIGRlIG1hbmVyYSBtYW51YWwsIGVuIGxhIHF1aW50YSBxdWUgbm8gcXVlcmVtb3MgdW5hIGxleWVuZGEgYWNsYXJhbmRvIGxvcyBjb2xvcmVzIGRlIGNhZGEgY2F0ZWdvcsOtYSBwb3JxdWUgeWEgZXN0w6FuIGFjbGFyYWRhcyBlbiBlbCBlamUgeS4gWSBwb3Igw7psdGltbyBhY2xhcmFtb3MgbGFzIGV0aXF1ZXRhcyBuZWNlc2FyaWFzLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lIAogIGdncGxvdCguLCBhZXMoeCA9IFByZWNpby5kZS5saXN0YSwgeSA9IENhdGVnb3LDrWEsIGZpbGwgPSBDYXRlZ29yw61hKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2NhbGUgPSAzLCBiYW5kd2lkdGggPSAyMCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygicmVkIiwgInZpb2xldHJlZCIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gZGUgbGlzdGEgZGUgcHJvZHVjdG9zIGRlIGdlc3Rpw7NuIG1lbnN0cnVhbCBzZWfDum4gY2F0ZWdvcsOtYSIsCiAgICAgICBzdWJ0aXRsZSA9IGRhdGUsCiAgICAgICB4ID0gIlByZWNpbyBkZSBsaXN0YSIsCiAgICAgICB5ID0gIiIsCiAgICAgICBjYXB0aW9uID0gIkZ1ZW50ZTogI01lbnN0cnVBY2Npw7NuIikKYGBgClBvciBlc3RhIHZleiwgZmlsdHJhbW9zIGRlIGxvcyBkYXRvcyBsb3MgcHJlY2lvcyBtYXlvcmVzIGEgMS4wMDAgcGVzb3MsIGJhc2ljYW1lbnRlIHBvcnF1ZSBoYXkgY2Fzb3MgKG91dGxpZXJzIHF1ZSBkZSBoZWNobyB2YW1vcyBhIHRlbmVyIHF1ZSBjb3JyZWdpcikgcXVlIHN1cGVyYW4gZXNlIG1vbnRvIHkgInJvbXBlbiIgbGEgZXNjYWxhIGRlbCBncsOhZmljby4gUGFyYSB1bmEgY29tcHJlbnNpw7NuIG3DoXMgYWNhYmFkYSBkZSBlc3RlIGVmZWN0bywgdmVhbW9zIHF1w6kgc3VjZWRlIHNpIHF1aXRhbW9zIGVzdG9zIHZhbG9yZXMgcXVlIGhhc3RhIHN1cGVyYW4gbG9zIDE1LjAwMCBwZXNvczoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgU29sbyBlbiBlc3RhIG9jYXNpw7NuIHBvciBsb3Mgb3V0bGllcnMgcHJlc2VudGVzOgoKZGF0b3MgPC0gZGF0b3MgJT4lIAogIGZpbHRlcihQcmVjaW8uZGUubGlzdGEgPCAxMDAwKSAjc2FjbyBsb3Mgb3V0bGllcnMgbWF5b3JlcyBhIDEwMDAgcG9ycXVlIHNvbiBkZW1hc2lhZG8gYWx0b3MuIAojIEVsIHJlc3RvIHZhIGEgc2VyIGNvbnRyb2xhZG8gYSBsYSBob3JhIGRlIGNhbGN1bGFyIGxhIG1lZGlhIGRlIHByZWNpb3MgZGUgZm9ybWEgInBvZGFkYSIKCmRhdG9zICU+JSAKICBnZ3Bsb3QoLiwgYWVzKHggPSBQcmVjaW8uZGUubGlzdGEsIHkgPSBDYXRlZ29yw61hLCBmaWxsID0gQ2F0ZWdvcsOtYSkpICsKICBnZW9tX2RlbnNpdHlfcmlkZ2VzKHNjYWxlID0gMywgYmFuZHdpZHRoID0gMjApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInJlZCIsICJ2aW9sZXRyZWQiKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnModGl0bGUgPSAiUHJlY2lvIGRlIGxpc3RhIGRlIHByb2R1Y3RvcyBkZSBnZXN0acOzbiBtZW5zdHJ1YWwgc2Vnw7puIGNhdGVnb3LDrWEiLAogICAgICAgc3VidGl0bGUgPSBkYXRlLAogICAgICAgeCA9ICJQcmVjaW8gZGUgbGlzdGEiLAogICAgICAgeSA9ICIiLAogICAgICAgY2FwdGlvbiA9ICJGdWVudGU6ICNNZW5zdHJ1QWNjacOzbiIpCmBgYAoKQSBwcmltZXJhIHZpc3RhLCBsb3Mgbml2ZWxlcyBkZSBwcmVjaW9zIGRlIHRvYWxsaXRhcyB5IHRhbXBvbmVzIHNlIGRpc3RyaWJ1eWVuIGVuIHVuYSBtaXNtYSBlc2NhbGEuIEVuIGVsIGNhc28gZGUgbG9zIHRhbXBvbmVzIGhheSB1bmEgZGlzdHJpYnVjacOzbiBiaW1vZGFsLCBxdWUgcHVlZGUgZGViZXJzZSBhIGxhIGFtcGxpYSBjYW50aWRhZCBkZSBwcmVzZW50YWNpb25lcyBkZSA4IHkgMTYgdW5pZGFkZXMuCgo8YnI+PGJyPgoKVGFtYmnDqW4gcG9kZW1vcyBncmFmaWNhciBsb3MgcHJlY2lvcyBkZSBjYWRhIGNhdGVnb3LDrWEgcG9yIHJlZ2lvbmVzOgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lIAogIGdncGxvdCguLCBhZXMoeCA9IFByZWNpby5kZS5saXN0YSwgeSA9IFJlZ2lvbiwgZmlsbCA9IENhdGVnb3LDrWEsIGFscGhhID0gUmVnaW9uKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2NhbGUgPSAyLCBiYW5kd2lkdGggPSAyMCkgKyAjIGVsIGJhbmR3aWR0aCBhbnRlcmlvciBlc3RhYmEgZW4gMTAKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInJlZCIsICJ2aW9sZXRyZWQiKSkrCiAgZmFjZXRfd3JhcCguIH4gQ2F0ZWdvcsOtYSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnModGl0bGUgPSAiUHJlY2lvIGRlIGxpc3RhIGRlIHByb2R1Y3RvcyBkZSBnZXN0acOzbiBtZW5zdHJ1YWwgc2Vnw7puIGNhdGVnb3LDrWEgeSByZWdpw7NuIiwKICAgICAgIHN1YnRpdGxlID0gZGF0ZSwKICAgICAgIHggPSAiUHJlY2lvIGRlIGxpc3RhIiwKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiAjTWVuc3RydUFjY2nDs24iKQpgYGAKCkVuIGVzdGUgY2FzbyBzZSBlbmN1ZW50cmFuIGRpZmVyZW5jaWFzIG3DoXMgcXVlIG5hZGEgZW50cmUgbG9zIHRhbXBvbmVzLCBubyBhc8OtIGVuIGVsIGNhc28gZGUgbGFzIHRvYWxsaXRhcy4gRGFkbyBlbCBwZXNvIGRlIEdCQSBlbnRyZSBsYXMgb2JzZXJ2YWNpb25lcywgdGllbmUgc2VudGlkbyBxdWUgbGEgZGlzdHJpYnVjacOzbiBnZW5lcmFsIHNlIGFzZW1lamUgYSBsYSBkZSBkaWNoYSByZWdpw7NuLgoKIyMgTGltcGllemEgZGUgbGEgY2FudGlkYWQgZGUgdW5pZGFkZXMgKFByZXNlbnRhY2nDs24pCgpDb21vIG1lbmNpb27DoWJhbW9zIGFudGVyaW9ybWVudGUsIGVzIG5lY2VzYXJpbyBwcmVzdGFybGUgcGFydGljdWxhciBhdGVuY2nDs24gYSBsYSB2YXJpYWJsZSBkZSBgUHJlc2VudGFjacOzbmAsIHF1ZSBpbmRpY2EgbGEgY2FudGlkYWQgZGUgdW5pZGFkZXMgcG9yIGNhZGEgcGFxdWV0ZS4gRW4gcHJpbWVyIGx1Z2FyLCB0ZW5pZW5kbyBlbiBjdWVudGEgcXVlIGVzdMOhIGV4cHJlc2FkYSBjb21vICJYIHVuLiIsIG1vZGlmaWNhbW9zIGxhIHZhcmlhYmxlIHBhcmEgcXVlZGFybm9zIMO6bmljYW1lbnRlIGNvbiBsYXMgdW5pZGFkZXMgZW4gZm9ybWF0byBudW3DqXJpY28uIEVzdG8gbG8gaGFjZW1vcyBjb252aXJ0aWVuZG8gbGEgdmFyaWFibGUgYWwgdGlwbyBjaGFyYWN0ZXIsIHkgbHVlZ28gcXVlZMOhbmRvbm9zIGNvbiBhcXVlbGxvcyBjYXJhY3RlcmVzIGVudHJlIGxhIHByaW1lciBwb3NpY2nDs24geSBhcXVlbGxhIHF1ZSBzZSBlbmN1ZW50cmEgNCBwb3NpY2lvbmVzIHBvciBkZXRyw6FzIGRlIGxhIMO6bHRpbWEgKG9taXRpZW5kbyBhc8OtICIuMCB1biIpLiBFbiBsYSB0YWJsYSBgcHJlc2VudGFjaW9uX25yb3NgIHJlc3VtaW1vcyBlbCBjb21wb3J0YW1pZW50byBkZSBlc3RhIG51ZXZhIHZhcmlhYmxlIGB1bmlkYWRlc2AuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyA8LSBkYXRvcyAlPiUgCiAgbXV0YXRlKFByZXNlbnRhY2nDs24gPSBhcy5jaGFyYWN0ZXIoUHJlc2VudGFjacOzbiksCiAgICAgICAgIHVuaWRhZGVzID0gYXMubnVtZXJpYyhzdWJzdHIoUHJlc2VudGFjacOzbiwgMSwgbmNoYXIoUHJlc2VudGFjacOzbiktNCkpKQoKcHJlc2VudGFjaW9uX25yb3MgPC0gZGF0b3MgJT4lIAogIGNvdW50KHVuaWRhZGVzKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIG11dGF0ZShwb3JjZW50YWplID0gbi9zdW0obiksCiAgICAgICAgIGFjdW11bGFkbyA9IGN1bXN1bShwb3JjZW50YWplKSwKICAgICAgICAgcG9yY2VudGFqZSA9IHBlcmNlbnQocG9yY2VudGFqZSksCiAgICAgICAgIGFjdW11bGFkbyA9IHBlcmNlbnQoYWN1bXVsYWRvKSkKcHJlc2VudGFjaW9uX25yb3MKYGBgCgpTaW4gZW1iYXJnbywgZW4gbGEgYmFzZSBwdWVkZSB2ZXJzZSBxdWUgaGF5IGNhc29zIHF1ZSwgZGUgYWN1ZXJkbyBhIGxhIGRlc2NyaXBjacOzbiBlbiBgTm9tYnJlYCwgdGllbmVuIG1hbCBsYSBjYW50aWRhZCBkZSB1bmlkYWRlcyBlbiBgUHJlc2VudGFjaW9uYCAoeSBwb3IgZW5kZSBlbiB1bmlkYWRlcyksIGFmZWN0YW5kbyBlbCBjYWxjdWxvIGRlIHByZWNpb3MgdW5pdGFyaW9zLgo8YnI+PGJyPgpVdGlsaXphbmRvIGV4cHJlc2lvbmVzIHJlZ3VsYXJlcyBwb2RlbW9zIHF1ZWRhcm5vcyBjb24gbG9zIGTDrWdpdG9zLCBzZWFuIHVubyBvIG3DoXMsIHF1ZSBlc3TDoW4gc2VndWlkb3MgZGUgIlVuIiBvICJ1biIgZW4gbGEgdmFyaWFibGUgYE5vbWJyZWAuIE5vcyBxdWVkYW1vcyBjb24gZXN0YSBpbmZvcm1hY2nDs24gZW4gbGEgdmFyaWFibGUgYHVuaWRhZGVzX3JlZ2V4YCB5IHJlc3VtaW1vcyBzdSBjb21wb3J0YW1pZW50by4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUodW5pZGFkZXNfcmVnZXggPSBhcy5udW1lcmljKHN0cl9leHRyYWN0KE5vbWJyZSwgJ1xcZCsoPz1cXHMqW1V1XW4/KScpKSkKCnByZXNlbnRhY2lvbl9yZWdleCA8LSBkYXRvcyAlPiUgCiAgY291bnQodW5pZGFkZXNfcmVnZXgpICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgCiAgbXV0YXRlKHBvcmNlbnRhamUgPSBuL3N1bShuKSwKICAgICAgICAgYWN1bXVsYWRvID0gY3Vtc3VtKHBvcmNlbnRhamUpLAogICAgICAgICBwb3JjZW50YWplID0gcGVyY2VudChwb3JjZW50YWplKSwKICAgICAgICAgYWN1bXVsYWRvID0gcGVyY2VudChhY3VtdWxhZG8pKQpwcmVzZW50YWNpb25fcmVnZXgKYGBgCgpOw7N0ZXNlIHF1ZSBoYXkgcGVxdWXDsWFzIGRpZmVyZW5jaWFzIHJlc3BlY3RvIGRlbCBjdWFkcm8gYW50ZXJpb3IgKGVuIGxhcyAzMCB1bmlkYWRlcyBwb3IgZWplbXBsbykuIEVuIGVzdGUgY2FzbywgbGFzIHVuaWRhZGVzIHNlIGVuY3VlbnRyYW4gbcOhcyBjb25jZW50cmFkYXMgZW4gdmFsb3JlcyBwb3B1bGFyZXMuIFBvZGVtb3MgaWRlbnRpZmljYXIgY3XDoW5kbyBhbWJhcyBpbmZvcm1hY2lvbmVzIChsYSBjb250ZW5pZGEgZW4gYHVuaWRhZGVzYCB5IGVuIGB1bmlkYWRlc19yZWdleGApIGNvaW5jaWRlbiB5IGN1w6FuZG8gbm8uIENyZWFtb3MgbGEgdmFyaWFibGUgYGlndWFsYCBxdWUgdG9tYSB2YWxvciBUUlVFIGN1YW5kbyBzb24gaWd1YWxlcywgeSBGQUxTRSBjdWFuZG8gbm8uIEEgY29udGludWFjacOzbiwgZW4gbGEgdGFibGEgYGNvbXBhcm9fdW5pZGFkZXNgIHNlIHJlYWxpemEgdW4gY29udGVvIGRlIG9ic2VydmFjaW9uZXMgcGFyYSBhbWJhcyB2YXJpYWJsZXMsIHNlIGlkZW50aWZpY2FuIGxhcyBzaXR1YWNpb25lcyBkZSBjb2luY2lkZW5jaWEgeSBkaWZlcmVuY2lhIHkgc2Ugb3JkZW5hbiBsb3MgZGF0b3MgcGFyYSB2ZXIgcHJpbWVybyBsYXMgZGlmZXJlbmNpYXMsIHNlZ8O6biBsYSBtYWduaXR1ZC4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUoaWd1YWwgPSBjYXNlX3doZW4odW5pZGFkZXMgPT0gdW5pZGFkZXNfcmVnZXggfiBULAogICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlkYWRlcyAhPSB1bmlkYWRlc19yZWdleCB+IEYpKQoKY29tcGFyb191bmlkYWRlcyA8LSBkYXRvcyAlPiUgCiAgY291bnQodW5pZGFkZXMsIHVuaWRhZGVzX3JlZ2V4KSAlPiUgCiAgbXV0YXRlKGlndWFsID0gY2FzZV93aGVuKHVuaWRhZGVzID09IHVuaWRhZGVzX3JlZ2V4IH4gVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pZGFkZXMgIT0gdW5pZGFkZXNfcmVnZXggfiBGKSkgJT4lIAogIGFycmFuZ2UoaWd1YWwsIC1uKQoKY29tcGFyb191bmlkYWRlcwpgYGAKRW4gcGFydGljdWxhciwgaGF5IGNhc29zIHF1ZSBmdWVyb24gaW5mb3JtYWRvcyBjb21vIGRlIDEgbyAxNiB1bmlkYWRlcyB5IGVuIHJlYWxpZGFkIGVyYW4gZGUgOCAodGllbmUgc2VudGlkbyBxdWUgZXN0ZSDDumx0aW1vIHNlYSBlbCB2ZXJkYWRlcm8gdmFsb3IpLCBjYXNvcyBxdWUgZnVlcm9uIGluZm9ybWFkb3MgY29tbyBkZSAxIG8gMjcgdW5pZGFkZXMgeSBlbiByZWFsaWRhZCBlcmFuIGRlIDE2LCBvIGNhc29zIHF1ZSBmdWVyb24gaW5mb3JtYWRvcyBjb21vIGRlIDEgdW5pZGFkIHkgZW4gcmVhbGlkYWQgZXJhbiBkZSAzMCwgZXRjLiBDb21vIHB1ZWRlIHZlcnNlIGEgY29udGludWFjacOzbiwgaGF5IGVuIHRvdGFsIDIxOCBjYXNvcyBlbiBxdWUgbGEgaW5mb3JtYWNpw7NuIG5vIGNvaW5jaWRlLCBsbyBxdWUgcmVwcmVzZW50YSBlbCAwLjI2JSBkZSBsYSBpbmZvcm1hY2nDs24gKG1lam9yw7MgbXVjaMOtc2ltbyBlbiBjb21wYXJhY2nDs24gYSByZWxldmFtaWVudG9zIGFudGVyaW9yZXMpLCB5IHPDs2xvIDYgY2Fzb3MgZW4gcXVlIG5vIGhhYsOtYSBpbmZvcm1hY2nDs24gc29icmUgbGEgY2FudGlkYWQgZGUgdW5pZGFkZXMgZW4gbGEgZGVzY3JpcGNpw7NuIGRlbCBhcnTDrWN1bG8uCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyAlPiUgCiAgZ3JvdXBfYnkoaWd1YWwpICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIAogIG11dGF0ZShwb3JjID0gcGVyY2VudChuL3N1bShuKSkpCmBgYAoKVmFsZSBsYSBwZW5hIGRlc3RhY2FyIHF1ZSBlc3RvcyBlcnJvcmVzIGNvcnJlc3BvbmRlbiBhIHRvZGFzIGxhcyByZWdpb25lcywgbWF5b3JtZW50ZSBjb25jZW50cmFkb3MgZW4gR0JBLCB5IGVuIDUgbWFyY2FzIGRpZmVyZW50ZXMuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIERpc3RyaWJ1Y2lvbiBkZSBsb3MgZGF0b3MgcXVlIHF1ZXJlbW9zIHNhY2FyIGVudHJlIGxhcyByZWdpb25lcwpkYXRvcyAlPiUgCiAgZmlsdGVyKGlndWFsID09IEZBTFNFKSAlPiUgCiAgY291bnQoUmVnaW9uKQoKIyBEaXN0cmlidWNpb24gZGUgbG9zIGRhdG9zIHF1ZSBxdWVyZW1vcyBzYWNhciBlbnRyZSBsYXMgbWFyY2FzCmRhdG9zICU+JSAKICBmaWx0ZXIoaWd1YWwgPT0gRkFMU0UpICU+JSAKICBjb3VudChNYXJjYSkKYGBgCgojIyMgQWNsYXJhY2nDs24KCkVuIHVuIGVqZXJjaWNpbyBhbnRlcmlvciAoc2VwdGllbWJyZSAyMDE5KSwgcHJlc2NpbmRpbW9zIGRlIGxvcyB2YWxvcmVzIGZhbHRhbnRlcyBlbiBgdW5pZGFkZXNfcmVnZXhgIChwb3IgbcOhcyBxdWUgdGVuZ2FuIHZhbG9yIGVuIGB1bmlkYWRlc2AsIGFxdWVsbGEgcXVlIHN1cmdlIGRlIGxhIHZhcmlhYmxlIGBQcmVzZW50YWNpw7NuYCkuIFZlcmlmaWNhbW9zIGFxdWVsbG9zIGNhc29zIGVuIHF1ZSBgdW5pZGFkZXNfcmVnZXhgIChxdWUgc3VyZ2UgZGVsIHRleHRvIGVuIGBOb21icmVgKSBubyBjb2luY2lkZSBjb24gbGEgdmFyaWFibGUgYHVuaWRhZGVzYCwgeSBlc3RhYmxlY2ltb3MgcXVlIGxhcyBjYW50aWRhZGVzIHJlZmVyaWRhcyBhIGxhcyB1bmlkYWRlcyBwb3IgcGFxdWV0ZSBwYXJlY2VuIHNlciBtZWpvciBjYXB0YWRhcyBjb24gZWwgbcOpdG9kbyBkZSByZWdleCBzb2JyZSBlbCB0ZXh0byBkZWwgYE5vbWJyZWAgZGVsIHByb2R1Y3RvLCByZXNwZWN0byBkZSBsbyBzdXJnaWRvIGRlIGxhIGluZm9ybWFjacOzbiBkZSBsYSBww6FnaW5hIGNvbW8gYFByZXNlbnRhY2nDs25gLiBOb3MgcXVlZGFtb3MgY29uIGB1bmlkYWRlc19yZWdleGAgcGFyYSBjYWxjdWxhciBlbCBwcmVjaW8gcG9yIHVuaWRhZCBkZSBsb3MgcHJvZHVjdG9zLgoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyBFc3RlIGNvZGlnbyBlc3RhIGFudWxhZG8uIEVzIGxvIHF1ZSBlc3RhYmEgZW4gZWwgZWplcmNpY2lvIGFudGVyaW9yCnVuaWRhZGVzLmZhbHRhbnRlcyA8LSBkYXRvcyAlPiUgCiAgZmlsdGVyKGlzLm5hKHVuaWRhZGVzLnJlZ2V4KSkgJT4lIAogIHNlbGVjdChOb21icmUsIHVuaWRhZGVzLnJlZ2V4LCBQcmVzZW50YWNpw7NuLCB1bmlkYWRlcykgJT4lIAogIGdyb3VwX2J5KE5vbWJyZSwgdW5pZGFkZXMucmVnZXgsIFByZXNlbnRhY2nDs24sIHVuaWRhZGVzKSAlPiUgCiAgc3VtbWFyaXNlKG4oKSkKCmRhdG9zIDwtIGRhdG9zICU+JSAKICBmaWx0ZXIoIWlzLm5hKHVuaWRhZGVzLnJlZ2V4KSkKCmthYmxlKHVuaWRhZGVzLmZhbHRhbnRlcykgJT4lIAogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRikKCnZlcmlmIDwtIGRhdG9zICU+JSAKICBmaWx0ZXIodW5pZGFkZXMucmVnZXggIT0gdW5pZGFkZXMpICU+JSAKICBncm91cF9ieShOb21icmUsIHVuaWRhZGVzLCB1bmlkYWRlcy5yZWdleCkgJT4lIAogIHN1bW1hcmlzZShuPW4oKSkgJT4lIAogIGFycmFuZ2UoLW4pCgprYWJsZSh2ZXJpZikgJT4lIAogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRikKYGBgCgpFc3RhIHZleiwgZGFkbyBxdWUgZWwgcG9yY2VudGFqZSBkZSBhcXVlbGxvcyBjYXNvcyBlbiBxdWUgbm8gY29pbmNpZGVuIGB1bmlkYWRlc2AgeSBgdW5pZGFkZXNfcmVnZXhgLCBqdW50byBhIGxvcyBjYXNvcyBlbiBxdWUgYHVuaWRhZGVzX3JlZ2V4YCBmaWd1cmEgY29tbyBgTkFgLCBhbGNhbnphbiBzb2xhbWVudGUgdW4gMC4yNyUsIHNlIHByZXNjaW5kaXLDoSBkZSBlbGxvcy4gCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyA8LSBkYXRvcyAlPiUgCiAgZmlsdGVyKGlndWFsID09IFRSVUUpCmBgYAoKX19TZSBkZXNjYXJ0YW4gMjI0IGNhc29zX18geSBhaG9yYSBjb250YW1vcyBjb24gYHIgY2FudChucm93KGRhdG9zKSlgIG9ic2VydmFjaW9uZXMuIFRhbWJpw6luIHBvZGVtb3MgZGVzaGFjZXJub3MgZGUgdmFyaWFibGVzIHF1ZSBubyB2YW1vcyBhIHV0aWxpemFyIGVuIGVsIGVqZXJjaWNpbyBkZSBlc3RpbWFjacOzbi4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgRGVzY2FydG8gbGFzIHZhcmlhYmxlcyBxdWUgbm8gdm95IGEgdXNhcgpkYXRvcyA8LSBkYXRvcyAlPiUgCiAgc2VsZWN0KC1QcmVzZW50YWNpw7NuLCAtdW5pZGFkZXNfcmVnZXgsIC1pZ3VhbCkKYGBgCiAgICAgICAgCiMjIEPDoWxjdWxvIGRlbCBwcmVjaW8gcG9yIHVuaWRhZAoKQ3JlbyBsYSB2YXJpYWJsZSBgcHJlY2lvX3VuaWRhZGAsIGRpdmlkaWVuZG8gZWwgYFByZWNpby5kZS5saXN0YWAgcG9yIGxhcyBgdW5pZGFkZXNgLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgPC0gZGF0b3MgJT4lIAogIG11dGF0ZShwcmVjaW9fdW5pZGFkID0gcm91bmQoUHJlY2lvLmRlLmxpc3RhL3VuaWRhZGVzLCAyKSkKYGBgCgojIyBHcsOhZmljb3MgZGVsIHByZWNpbyBwb3IgdW5pZGFkCgpBaG9yYSBwb2RlbW9zIG9ic2VydmFyIGxhIGRpc3RyaWJ1Y2nDs24gZGUgZXN0YSBudWV2YSB2YXJpYWJsZSBjb24gbG9zIG1pc21vcyBncsOhZmljb3MgcXVlIHV0aWxpemFtb3MgYW50ZXMuCgpgYGB7ciBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTcsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRvcywgYWVzKHggPSBwcmVjaW9fdW5pZGFkLCB5ID0gQ2F0ZWdvcsOtYSwgZmlsbCA9IENhdGVnb3LDrWEpKSArCiAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhzY2FsZSA9IDIsIGJhbmR3aWR0aCA9IDEuMjUpICsgIyBlbCBiYW5kd2lkdGggYW50ZXJpb3IgZXN0YWJhIGVuIDEwCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAzMCkpICsgIyBFbiBlbCBhbnRlcmlvciBlbCBsaW1pdGUgZXN0YWJhIGVuIDIwCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygicmVkIiwgInZpb2xldHJlZCIpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gcG9yIHVuaWRhZCBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIiwKICAgICAgIHN1YnRpdGxlID0gZGF0ZSwKICAgICAgIHggPSAiUHJlY2lvIHBvciB1bmlkYWQiLAogICAgICAgeSA9ICIiLAogICAgICAgY2FwdGlvbiA9ICJGdWVudGU6ICNNZW5zdHJ1QWNjacOzbiIpCmBgYAoKRXN0YSB2ZXosIHBhcmEgcmVhbGl6YXIgZWwgZ3LDoWZpY28gcG9yIGNhdGVnb3LDrWFzIHkgcmVnaW9uZXMsIHBvZGVtb3Mgb3JkZW5hciBhIGVzdGFzIMO6bHRpbWFzIHNlZ8O6biBzdSBwcmVjaW8gcHJvbWVkaW8gZW4gZWwgZ3LDoWZpY28uIFBhcmEgZWxsbyBjb25zdHJ1aW1vcyB1biB2ZWN0b3IgcXVlIGxhcyBhbG9qZSBlbiBvcmRlbiwgbGxhbWFkbyBgcmVnX29yZGVuYWRhc2AuIEx1ZWdvLCBwaXNhbW9zIGxhIHZhcmlhYmxlIGBSZWdpb25gIGVuIGxvcyBkYXRvcyBwYXJhIHF1ZSBzZWEgZGUgdGlwbyBmYWN0b3IsIHkgZWwgb3JkZW4gZGUgbGEgbWlzbWEgZXN0w6kgZGV0ZXJtaW5hZG8gc2Vnw7puIGVsIHZlY3RvciBwcmV2aWFtZW50ZSBkZWZpbmlkby4KCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcmVnX29yZGVuYWRhcyA8LSBkYXRvcyAlPiUgCiAgZ3JvdXBfYnkoUmVnaW9uKSAlPiUgCiAgc3VtbWFyaXNlKHByb21lZGlvID0gbWVhbihwcmVjaW9fdW5pZGFkKSkgJT4lIAogIGFycmFuZ2UocHJvbWVkaW8pICUkJSBSZWdpb24KCmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUoUmVnaW9uID0gZmFjdG9yKFJlZ2lvbiwgbGV2ZWxzID0gcmVnX29yZGVuYWRhcykpCmBgYAoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZGF0b3MsIGFlcyh4ID0gcHJlY2lvX3VuaWRhZCwgeSA9IFJlZ2lvbiwgZmlsbCA9IENhdGVnb3LDrWEsIGFscGhhID0gUmVnaW9uKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2NhbGUgPSAyLCBiYW5kd2lkdGggPSAxLjI1KSArICMgZWwgYmFuZHdpZHRoIGFudGVyaW9yIGVzdGFiYSBlbiAxCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQiLCAidmlvbGV0cmVkIikpKwogIGZhY2V0X3dyYXAoLiB+IENhdGVnb3LDrWEpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAzMCkpICsgIyBFc3RlIHZhbG9yIHNlIGFjdHVhbGl6YSBzZWd1biBpbmZsYWNpb24sIGEgb2pvCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gcG9yIHVuaWRhZCBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIHkgcmVnacOzbiIsCiAgICAgICBzdWJ0aXRsZSA9IGRhdGUsCiAgICAgICB4ID0gIlByZWNpbyBwb3IgdW5pZGFkIiwKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiAjTWVuc3RydUFjY2nDs24iKQpgYGAKCiMjIDIsNSAlIGRlIGxvcyBleHRyZW1vcyBkZSBsYSBkaXN0cmlidWNpw7NuCgpBZGljaW9uYWxtZW50ZSwgY29tbyBlbCBjw6FsY3VsbyBsbyByZWFsaXphcmVtb3MgYWdyZWdhbmRvIGxvcyBwcmVjaW9zIGRlIGFjdWVyZG8gYSB1bmEgbWVkaWEgYWxwaGEgcG9kYWRhIGNvbiBhbHBoYSA9IDIsNSUgKG8gc2VhLCBpZ25vcmFuZG8gbG9zIHZhbG9yZXMgc3VwZXJpb3JlcyBlIGluZmVyaW9yZXMgcGFyYSBldml0YXIgbGEgaW50cnVzacOzbiBkZSBvdXRsaWVycyBhIHBlc2FyIGRlIGxhIGxpbXBpZXphKSwgcHJlc2VudGFtb3MgZ3LDoWZpY29zIHF1ZSBqdXN0YW1lbnRlIG11ZXN0cmFuIGxhcyAiY29sYXMiIGRlIGxhIGRpc3RyaWJ1Y2nDs24gcXVlIHNlIGVzdGFyw61hbiBvYnZpYW5kby4KCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGRhdG9zLCBhZXMoeCA9IHByZWNpb191bmlkYWQsIHkgPSBDYXRlZ29yw61hLCBmaWxsID0gZmFjdG9yKC4ucXVhbnRpbGUuLikpKSArCiAgc3RhdF9kZW5zaXR5X3JpZGdlcyhnZW9tID0gImRlbnNpdHlfcmlkZ2VzX2dyYWRpZW50IiwgCiAgICAgICAgICAgICAgICAgICAgICBjYWxjX2VjZGYgPSBUUlVFLCBxdWFudGlsZXMgPSBjKDAuMDI1LCAwLjk3NSksCiAgICAgICAgICAgICAgICAgICAgICBiYW5kd2lkdGggPSAxLjI1LCBzY2FsZSA9IDEuNSkgKyAjIEVsIGJhbmR3aWR0aCBhbnRlcmlvciBlc3RhYmEgZW4gMC43NQogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiUHJvYmFiaWxpZGFkIiwgCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygidmlvbGV0cmVkMSIsICJyZWQyIiwgInZpb2xldHJlZDEiKSwKICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIyLDUgJSIsICI5NSwwICUiLCAiMiw1ICUiKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDMwKSkgKyAjIEVsIGxpbWl0ZSBhbnRlcmlvciBlc3RhYmEgZW4gMjAKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gcG9yIHVuaWRhZCBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIiwKICAgICAgIHN1YnRpdGxlID0gcGFzdGUoZGF0ZSksCiAgICAgICB4ID0gIlByZWNpbyBwb3IgdW5pZGFkIiwKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiAjTWVuc3RydUFjY2nDs24iKQpgYGAKClJlYWxpemFtb3MgZWwgbWlzbW8gZ3LDoWZpY28gcG9yIGNhZGEgcHJvdmluY2lhLCB5YSBxdWUgZXNhIHNlcsOhIGxhIHByaW1lciB1bmlkYWQgZGUgYWdyZWdhY2nDs24gcGFyYSBlbCBjw6FsY3VsbyB0b3RhbCBhIG5pdmVsIG5hY2lvbmFsLgoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwcm92X29yZGVuYWRhcyA8LSBkYXRvcyAlPiUgCiAgZ3JvdXBfYnkoUHJvdmluY2lhKSAlPiUgCiAgc3VtbWFyaXNlKHByb21lZGlvID0gbWVhbihwcmVjaW9fdW5pZGFkKSkgJT4lIAogIGFycmFuZ2UocHJvbWVkaW8pICUkJSAKICBQcm92aW5jaWEKCmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUoUHJvdmluY2lhID0gZmFjdG9yKFByb3ZpbmNpYSwgbGV2ZWxzID0gcHJvdl9vcmRlbmFkYXMpKQpgYGAKCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTksIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRvcywgYWVzKHggPSBwcmVjaW9fdW5pZGFkLCB5ID0gUHJvdmluY2lhLCAKICAgICAgICAgICAgICAgICAgZmlsbCA9IGZhY3RvciguLnF1YW50aWxlLi4pKSkgKwogIHN0YXRfZGVuc2l0eV9yaWRnZXMoZ2VvbSA9ICJkZW5zaXR5X3JpZGdlc19ncmFkaWVudCIsIAogICAgICAgICAgICAgICAgICAgICAgY2FsY19lY2RmID0gVFJVRSwgcXVhbnRpbGVzID0gYygwLjAyNSwgMC45NzUpLAogICAgICAgICAgICAgICAgICAgICAgYmFuZHdpZHRoID0gMS4yNSwgc2NhbGUgPSAyKSArCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJQcm9iYWJpbGlkYWQiLCAKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ2aW9sZXRyZWQxIiwgInJlZDIiLCAidmlvbGV0cmVkMSIpLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjIsNSAlIiwgIjk1LDAgJSIsICIyLDUgJSIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMzApKSArICMgRWwgbGltaXRlIGFudGVyaW9yIGVzdGFiYSBlbiAyMAogIGZhY2V0X3dyYXAoLiB+IENhdGVnb3LDrWEpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gcG9yIHVuaWRhZCBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIHkgcHJvdmluY2lhIiwKICAgICAgIHN1YnRpdGxlID0gcGFzdGUoZGF0ZSwgIi4gIiksCiAgICAgICB4ID0gIlByZWNpbyBwb3IgdW5pZGFkIiwKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiAjTWVuc3RydUFjY2nDs24iKQpgYGAKCiMjIEFww6luZGljZTogUHJlY2lvcyBpZ3VhbGVzIGEgY2VybwoKRW4gZXN0YSBvY2FzacOzbiwgbm8gaGF5IHByZWNpb3MgaWd1YWxlcyBhIGNlcm8sIGNvbiBsbyBxdWUgc2UgcHJlc2NpbmRlIGRlIGRpY2hvIGFuw6FsaXNpcy4KICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgIAoKRmluYWxtZW50ZSwgZ3VhcmRhbW9zIGVzdGEgbnVldmEgdmVyc2nDs24gZGVsIGRhdGFzZXQgZW4gZm9ybWF0byAuUkRTIHBhcmEgY29udGludWFyIGVuIGVsIHNpZ3VpZW50ZSBzY3JpcHQgY29uIGVsIGPDoWxjdWxvIGRlIGN1w6FudG8gY3Vlc3RhIG1lbnN0cnVhci4KCmBgYHtyIGVjaG89VFJVRX0KI3NhdmVSRFMoZGF0b3MsIGZpbGUgPSAiRnVlbnRlcy9wcmVjaW9zLWdlc3Rpb24tbWVuc3RydWFsLTIwMjEtMDktMTctbGltcGlvLlJEUyIpCmBgYAo=