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-2020-03-23.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 <- "Marzo 2020"
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 86.260 observaciones. A su vez, podemos ver con qué variables contamos en el dataset:
names(datos)
[1] "Categoría" "Marca" "Nombre" "Presentación" "Comercio" "Sucursal"
[7] "Dirección" "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 22 marcas de productos, aunque con 9 de ellas se completa el 90% del total de productos. Las primeras 3 marcas concentran la mitad de las observaciones. Nuevamente aquí hay que tener en cuenta que no se trata exactamente de “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, 90 observaciones en Misiones) 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 tomamos como fuente el dataset que venimos utilizando, 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.
ggplot(datos, aes(x = Precio.de.lista, y = Categoría, fill = Categoría)) +
geom_density_ridges(scale = 3, bandwidth = 20) + # el bandwidth anterior estaba en 10
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:
ggplot(datos, 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 “8 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 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 27 unidades y en realidad eran de 16 (tiene sentido que este último sea el verdadero valor), o casos que fueron informados como de 1 o 54 unidades y en realidad eran de 8. Como puede verse a continuación, hay en total 1771 casos en que la información no coincide, lo que representa el 2% de la información.
datos %>%
group_by(igual) %>%
summarise(n = n()) %>%
mutate(porc = percent(n/sum(n)))
Vale la pena destacar que estos errores se presentan en todas las regiones, y concentrados en 5 marcas diferentes, aunque de las más populares en nuestro dataset.
# 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 el 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
. 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 2%, se prescindirá de todos ellos.
datos <- datos %>%
filter(igual == TRUE)
Se descartan 1.894 casos y ahora contamos con 86.260 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")
En este caso, la distribución de los precios de los tampones se entiende como más concentrada (ya no está tan marcada una bimodal) y con un rango de precios superior al de las toallitas.
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")
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-2020-03-23-limpio.RDS")
LS0tCnRpdGxlOiAiTGltcGllemEgeSBvcmdhbml6YWNpw7NuIGRlIGxvcyBkYXRvcyBkZWwgI01lbnN0cnVTY3JhcHBlciIKc3VidGl0bGU6ICIjTWVuc3RydUFjY2nDs24gLSBEYXRvcyBkZSBNYXJ6byAyMDIwIgphdXRob3I6ICJOYXRzdW1pIFNob2tpZGEgcGFyYSBFY29GZW1pRGF0YSIKZGF0ZTogIk1heW8gZGUgMjAyMCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2RlcHRoOiA1Ci0tLQoKIyMgUHJlc2VudGFjacOzbgoKRW4gZWwgbWFyY28gZGVsIGPDoWxjdWxvIGRlbCBjb3N0byBkZSBtZW5zdHJ1YXIgZW4gQXJnZW50aW5hLCBsbGV2YWRvIGEgY2FibyBkZXNkZSBsYSBjYW1wYcOxYSAjTWVuc3RydUFjY2nDs24geSBFY29GZW1pbml0YXMsIGVuIGVsIHByZXNlbnRlIGRvY3VtZW50byBkZSB0cmFiYWpvIHNlIGVuY3VlbnRyYSBsYSBleHBsb3JhY2nDs24sIG9yZ2FuaXphY2nDs24geSBsaW1waWV6YSBkZSBsb3MgZGF0b3Mgb2J0ZW5pZG9zIG1lZGlhbnRlIGVsICNNZW5zdHJ1U2NyYXBwZXIsIGRlc2Fycm9sbGFkbyBwb3IgTmF5bGEgUG9ydGFzIGRlIFtMQVNdIGRlIHNpc3RlbWFzLiBFbCAjTWVuc3RydVNjcmFwcGVyIGZ1ZSBlamVjdXRhZG8gZWwgZMOtYSAyMyBkZSBtYXJ6byBkZSAyMDIwIHNvYnJlIGxhIHDDoWdpbmEgUHJlY2lvcyBDbGFyb3MsIHN1bcOhbmRvc2UgZXN0YSBpbmZvcm1hY2nDs24gYSBsYSBvYnRlbmlkYSBhbnRlcmlvcm1lbnRlIGVuIFNlcHRpZW1icmUgeSBNYXJ6byBkZSAyMDE5LiBFbiBlc3RhIGluc3RhbmNpYSwgc2Ugb2J0dXZpZXJvbiA4OC4xNTQgb2JzZXJ2YWNpb25lcyBlbiB0b3RhbCwgbHVlZ28gZGUgNWhzIHF1ZSBkZW1vcsOzIGVuIGNvcnJlciBlbCBwcm9ncmFtYS4KCisgUmVzcGVjdG8gZGUgbG9zIHRhbXBvbmVzOiBTZSBvYnR1dmllcm9uIDg2IGlkcyBkZSBwcm9kdWN0b3MsIDIxMTIgc3VjdXJzYWxlcywgMTcyMTEgcHJlY2lvcyBkZSBwcm9kdWN0b3MuCisgUmVzcGVjdG8gZGUgbGFzIHRvYWxsaXRhczogU2Ugb2J0dXZpZXJvbiAxNjggaWRzIGRlIHByb2R1Y3RvcywgMjExMiBzdWN1cnNhbGVzLCA3MDk0MyBwcmVjaW9zIGRlIHByb2R1Y3Rvcy4KCkVuIGVsIGFyY2hpdm8gYFJFQURNRWAgZGUgbGEgY2FycGV0YSBgRnVlbnRlc2Agc2UgZW5jdWVudHJhbiBhY2xhcmFkYXMgdG9kYXMgbGFzIGZ1ZW50ZXMgYWRpY2lvbmFsZXMgYSBsYXMgcXVlIHNlIHJlY3VycmnDsyBwYXJhIHJlYWxpemFyIGVsIGPDoWxjdWxvLiBFbiBvdHJvIHNjcmlwdCBzZSBlbmN1ZW50cmEgZWwgY8OhbGN1bG8gcHJvcGlhbWVudGUgZGljaG8gZGVsIGNvc3RvIGFudWFsIGRlIG1lbnN0cnVhci4gCgojIyBQcmVwYXJhbmRvIGVsIGVudG9ybm8gZGUgdHJhYmFqbwoKQ29tZW56YW1vcyBsZXZhbnRhbmRvIGxhcyBsaWJyZXLDrWFzIG5lY2VzYXJpYXMsIGNhcmdhbmRvIGxvcyBkYXRvcyBzcmFwcGVhZG9zIGRlc2RlIGVsIGFyY2hpdm8gLmNzdiwgeSB1biBkaWNjaW9uYXJpbyBxdWUgaW5kaWNhIGEgcXXDqSByZWdpw7NuIHBlcnRlbmVjZSBjYWRhIHByb3ZpbmNpYSBkZWwgcGHDrXMuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KEVudlN0YXRzKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3JpZGdlcykKbGlicmFyeShvcGVueGxzeCkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoa2FibGVFeHRyYSkKCmRhdG9zIDwtIHJlYWQuY3N2KCJGdWVudGVzL3ByZWNpb3MtZ2VzdGlvbi1tZW5zdHJ1YWwtMjAyMC0wMy0yMy5jc3YiLCAKICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwgc2VwID0gIiwiLCBkZWMgPSAiLiIsIAogICAgICAgICAgICAgICAgICBmaWxsID0gVFJVRSwgZW5jb2RpbmcgPSAiVVRGLTgiKQoKcmVnaW9uZXMgPC0gb3Blbnhsc3g6OnJlYWQueGxzeCgiRnVlbnRlcy9wcm92aW5jaWFzX3JlZ2lvbmVzLnhsc3giKQpgYGAKClZpc3RhIHByZXZpYSBkZWwgZGF0YXNldDoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmhlYWQoZGF0b3MpCmBgYAoKVmlzdGEgcHJldmlhIGRlbCBkaWNjaW9uYXJpbyBkZSByZWdpb25lczoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmhlYWQocmVnaW9uZXMpCmBgYAoKRGVmaW5pbW9zIHVuYSBwZXF1ZcOxYSBmdW5jacOzbjogYGNhbnRgIG5vcyB2YSBhIGRldm9sdmVyIHVuIG7Dum1lcm8gZW4gZm9ybWF0byBjaGFyYWN0ZXIgKHRleHRvKSwgY29uIGNlcm8gZMOtZ2l0b3MsIGNvbiB1biBwdW50byBwYXJhIHNlcGFyYXIgbG9zIG1pbGVzLCB5IHVuYSBjb21hIHBhcmEgc2VwYXJhciBsb3MgZGVjaW1hbGVzLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY2FudCA8LSBmdW5jdGlvbih4KXsKICBmb3JtYXQoeCwgZGlnaXRzID0gMCwgYmlnLm1hcmsgPSAiLiIsIGRlY2ltYWwubWFyayA9ICIsIil9CmBgYAoKR3VhcmRhbW9zIGVsIHZhbG9yIGRlIGxhIGZlY2hhIGEgbGEgcXVlIGNvcnJlc3BvbmRlIGVsIGVqZXJjaWNpby4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdGUgPC0gIk1hcnpvIDIwMjAiCmBgYAoKIyMgRXhwbG9yYWNpw7NuIGRlIGxvcyBkYXRvcwoKQWwgZGF0YWZyYW1lIGBkYXRvc2AgbGUgcGVnYW1vcyBsb3MgdmFsb3JlcyBkZSBsYXMgcmVnaW9uZXMsIHVzYW5kbyBjb21vIHZhcmlhYmxlIGRlIGlkZW50aWZpY2FjacOzbiBhIGxhIGBQcm92aW5jaWFgLiBBIGNvbnRpbnVhY2nDs24gcG9kZW1vcyBib3JyYXIgZGUgbnVlc3RybyBlbnRvcm5vIGRlIHRyYWJham8gZWwgZWxlbWVudG8gYHJlZ2lvbmVzYC4gCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyA8LSBsZWZ0X2pvaW4oZGF0b3MsIHJlZ2lvbmVzLCBieSA9ICJQcm92aW5jaWEiKQpybShyZWdpb25lcykKYGBgCgpgZGF0b3NgIGN1ZW50YSBjb24gYHIgY2FudChucm93KGRhdG9zKSlgIG9ic2VydmFjaW9uZXMuIEEgc3UgdmV6LCBwb2RlbW9zIHZlciBjb24gcXXDqSB2YXJpYWJsZXMgY29udGFtb3MgZW4gZWwgZGF0YXNldDoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cm5hbWVzKGRhdG9zKQpgYGAKCkEgY29udGludWFjacOzbiwgZXhwbG9yYXJlbW9zIGVsIGNvbXBvcnRhbWllbnRvIGRlIGxhcyBkaWZlcmVudGVzIHZhcmlhYmxlcy4gQ29uIGBjb3VudCgpYCBwZWRpbW9zIHVuIGNvbnRlbyBkZSBvYnNlcnZhY2lvbmVzIHBhcmEgY2FkYSB2YWxvciBxdWUgdG9tYSBsYSB2YXJpYWJsZSBhY2xhcmFkYSwgY29uIGBhcnJhbmdlKClgIG9yZGVuYW1vcyBsb3MgZGF0b3MgZGUgZm9ybWEgZGVjcmVjaWVudGUgc2Vnw7puIGVsIGNvbnRlbyBhbnRlcmlvciwgeSBlbiBgbXV0YXRlKClgIHNlIGRlZmluZW4gbnVldmFzIHZhcmlhYmxlcyBwYXJhIG51ZXN0cm8gY3VhZHJvLiBQb3IgZWplbXBsbywgZWwgcG9yY2VudGFqZSBlcyBsYSBjYW50aWRhZCBkZSBjYWRhIGNhdGVnb3LDrWEgc29icmUgbGEgc3VtYSBkZSBsYXMgbWlzbWFzLCBleHByZXNhZGEgZW4gZm9ybWF0byBkZSBwb3JjZW50YWplLgoKIyMjIyBDYXRlZ29yw61hcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lIAogIGNvdW50KENhdGVnb3LDrWEpICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgCiAgbXV0YXRlKHBvcmNlbnRhamUgPSBwZXJjZW50KG4vc3VtKG4pKSkgCmBgYAoKQ2FiZSBkZXN0YWNhciBxdWUgZXN0YSBjb21wb3NpY2nDs24gY29ycmVzcG9uZGUgYSBsYSBkaXNwb25pYmlsaWRhZCBkZSBwcmVjaW9zLCBubyByZWZsZWphIGxhIGVzdHJ1Y3R1cmEgZGVsIGNvbnN1bW8uIE8gc2VhLCBubyBwb2RlbW9zIGRlY2lyIHF1ZSBzZSBjb25zdW1lbiBlbiB1biA4MCUgdG9hbGxpdGFzIHkgZW4gMjAlIHRhbXBvbmVzLiBMbyBxdWUgc8OtIHNhYmVtb3MgZXMgcXVlIHRlbmVtb3MgdW5hIG11ZXN0cmEgbXV5IGdyYW5kZSBkZSBwcmVjaW9zIHBhcmEgYW1iYXMgY2F0ZWdvcsOtYXMsIGF1bnF1ZSBkZWJlbW9zIHRlbmVyIGVuIGN1ZW50YSBxdWUgbGEgcMOhZ2luYSBkZSBQcmVjaW9zIENsYXJvcyBwdWVkZSB0ZW5lciB1biBzZXNnbyBwb3Igbm8gaW5jbHVpciBsb3MgY29tZXJjaW9zIHRyYWRpY2lvbmFsZXMgc2lubyDDum5pY2FtZW50ZSBncmFuZGVzIGNhZGVuYXMuCgojIyMjIE1hcmNhcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lIAogIGNvdW50KE1hcmNhKSAlPiUgCiAgYXJyYW5nZSgtbikgJT4lIAogIG11dGF0ZShwb3JjZW50YWplID0gbi9zdW0obiksCiAgICAgICAgIGFjdW11bGFkbyA9IGN1bXN1bShwb3JjZW50YWplKSwKICAgICAgICAgcG9yY2VudGFqZSA9IHBlcmNlbnQocG9yY2VudGFqZSksCiAgICAgICAgIGFjdW11bGFkbyA9IHBlcmNlbnQoYWN1bXVsYWRvKSkKYGBgCgpDb250YW1vcyBjb24gMjIgbWFyY2FzIGRlIHByb2R1Y3RvcywgYXVucXVlIGNvbiA5IGRlIGVsbGFzIHNlIGNvbXBsZXRhIGVsIDkwJSBkZWwgdG90YWwgZGUgcHJvZHVjdG9zLiBMYXMgcHJpbWVyYXMgMyBtYXJjYXMgY29uY2VudHJhbiBsYSBtaXRhZCBkZSBsYXMgb2JzZXJ2YWNpb25lcy4gTnVldmFtZW50ZSBhcXXDrSBoYXkgcXVlIHRlbmVyIGVuIGN1ZW50YSBxdWUgbm8gc2UgdHJhdGEgZXhhY3RhbWVudGUgZGUgImNvbmNlbnRyYWNpw7NuIGRlIG1lcmNhZG8iLgoKIyMjIyBQcmVzZW50YWNpw7NuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyAlPiUgCiAgY291bnQoUHJlc2VudGFjacOzbikgJT4lIAogIGFycmFuZ2UoLW4pICU+JSAKICBtdXRhdGUocG9yY2VudGFqZSA9IG4vc3VtKG4pLAogICAgICAgICBhY3VtdWxhZG8gPSBjdW1zdW0ocG9yY2VudGFqZSksCiAgICAgICAgIHBvcmNlbnRhamUgPSBwZXJjZW50KHBvcmNlbnRhamUpLAogICAgICAgICBhY3VtdWxhZG8gPSBwZXJjZW50KGFjdW11bGFkbykpCmBgYAoKQ2FzaSBlbCA5MCUgZGUgbG9zIHByb2R1Y3RvcyB2aWVuZW4gZW4gcGFxdWV0ZXMgZGUgOCBvIDE2IHVuaWRhZGVzLiBMdWVnbyBzZWd1aXJlbW9zIGFuYWxpemFuZG8gZXN0YSB2YXJpYWJsZSBlbiBwYXJ0aWN1bGFyLCBwb3JxdWUgbm9zIGludGVyZXNhIHBhcmEgY2FsY3VsYXIgbG9zIHByZWNpb3MgdW5pdGFyaW9zIGRlIGxvcyBwcm9kdWN0b3MsIHkgaGF5IHZhbG9yZXMgKGNvbW8gIjEuMCB1biIpIHF1ZSBzb24gcmFyb3MgeSwgZW4gY2FzbyBkZSB0cmF0YXJzZSBkZSBlcnJvcmVzLCBwb2Ryw61hbiBhcnJhc3RyYXIgcHJvYmxlbWFzIGhhY2lhIGVsIGPDoWxjdWxvIGRlIGVzb3MgcHJlY2lvcy4KCiMjIyMgUHJvdmluY2lhcwoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgJT4lIAogIGNvdW50KFByb3ZpbmNpYSkgJT4lIAogIGFycmFuZ2UoLW4pICU+JSAKICBtdXRhdGUocG9yY2VudGFqZSA9IG4vc3VtKG4pLAogICAgICAgICBhY3VtdWxhZG8gPSBjdW1zdW0ocG9yY2VudGFqZSksCiAgICAgICAgIHBvcmNlbnRhamUgPSBwZXJjZW50KHBvcmNlbnRhamUpLAogICAgICAgICBhY3VtdWxhZG8gPSBwZXJjZW50KGFjdW11bGFkbykpCmBgYAoKU2kgYmllbiBtw6FzIGRlIGxhIG1pdGFkIGRlIGxhcyBvYnNlcnZhY2lvbmVzIHNlIGNvbmNlbnRyYW4gZW4gQnVlbm9zIEFpcmVzIHkgQ0FCQSwgZXMgaW1wb3J0YW50ZSBzYWJlciBxdWUgc2UgY3VlbnRhIGNvbiBpbmZvcm1hY2nDs24gZGUgdG9kYXMgbGFzIHByb3ZpbmNpYXMgZGVsIHBhw61zLCB5IHF1ZSBpbmNsdXNvIGVuIGVsIHBlb3IgZGUgbG9zIGNhc29zIChwb3IgZWplbXBsbywgOTAgb2JzZXJ2YWNpb25lcyBlbiBNaXNpb25lcykgc2UgdHJhdGEgZGUgdW5hIGNhbnRpZGFkIHBhc2libGUgZGUgcHJvdmVlcm5vcyBlc3RpbWFjaW9uZXMgw7p0aWxlcy4KCiMjIyMgUmVnaW9uZXMKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zICU+JSAKICBjb3VudChSZWdpb24pICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgCiAgbXV0YXRlKHBvcmNlbnRhamUgPSBuL3N1bShuKSwKICAgICAgICAgYWN1bXVsYWRvID0gY3Vtc3VtKHBvcmNlbnRhamUpLAogICAgICAgICBwb3JjZW50YWplID0gcGVyY2VudChwb3JjZW50YWplKSwKICAgICAgICAgYWN1bXVsYWRvID0gcGVyY2VudChhY3VtdWxhZG8pKQpgYGAKCkVuIHTDqXJtaW5vcyByZWdpb25hbGVzIHNlZ3VpbW9zIHZpZW5kbyBlc2EgYXNpbWV0csOtYSBlbiBsYSBkaXNwb25pYmlsaWRhZCBkZSBkYXRvcywgcGVybyBoYXkgcXVlIHRlbmVyIGVuIGN1ZW50YSBxdWUgZWZlY3RpdmFtZW50ZSBoYXkgZGlmZXJlbmNpYXMgZGUgZXNjYWxhIGRlIG1lcmNhZG9zIGVuIHTDqXJtaW5vcyByZWdpb25hbGVzLgoKIyMjIyBQcmVjaW8gZGUgbGlzdGEKCkFob3JhIGdyYWZpY2Ftb3MgbGEgZGlzdHJpYnVjacOzbiBkZSBsb3MgcHJlY2lvcyBkZSBsaXN0YSAobyBzZWEsIHNpbiB0ZW5lciBlbiBjdWVudGEgbGFzIHVuaWRhZGVzIHBvciBwYXF1ZXRlKSBzZWfDum4gY2FkYSBjYXRlZ29yw61hLiBQYXJhIGVsbG8gdXRpbGl6YW1vcyBgZ2dwbG90MmAuIEVuIGxhIHByaW1lciBsw61uZWEgZGUgY8OzZGlnbyB0b21hbW9zIGNvbW8gZnVlbnRlIGVsIGRhdGFzZXQgcXVlIHZlbmltb3MgdXRpbGl6YW5kbywgZW4gZWwgYGVqZSB4YCBxdWVyZW1vcyBsb3MgcHJlY2lvcywgZW4gZWwgYGVqZSB5YCBxdWVyZW1vcyBjYWRhIGNhdGVnb3LDrWEsIHkgZWwgcmVsbGVubyBkZSBjYWRhIHBhcnRlIGRlbCBncsOhZmljbyB0YW1iacOpbiBzZWfDum4gbGFzIGNhdGVnb3LDrWFzIGRlIHByb2R1Y3Rvcy4gRW4gbGEgc2VndW5kYSBsw61uZWEgYWNsYXJhbW9zIHF1ZSBxdWVyZW1vcyB1biBncsOhZmljbyBkZSBkZW5zaWRhZCAocXVlIGVzIGNvbW8gdW4gaGlzdG9ncmFtYSBwZXJvIGVuIHZlcnNpw7NuIGNvbnRpbnVhKSwgbGEgZXNjYWxhIGhhY2UgYSBsYSBzdXBlcnBvc2ljacOzbiBkZSBsb3MgZ3JhZmljb3MgeSBlbCBgYmFuZHdpZHRoYCBvICJhbmNobyBkZSBiYW5kYSIgaW5kaWNhIGxhIGV4dGVuc2nDs24gZGVsIGludGVydmFsbyBkZSB2YWxvcmVzIGNvbiBsb3MgcXVlIHNlIHZhIGEgcmVhbGl6YXIgbGEgZXN0aW1hY2nDs24gZGVsIGdyw6FmaWNvIChvIHNlYSwgc2kgZWwgZ3LDoWZpY28gdmEgYSBzZXIgbcOhcyBkZXRhbGxpc3RhIHkgcG9yIGVuZGUgbcOhcyAicnVpZG9zbyIsIG8gbcOhcyBzdWF2ZSB5ICJyZWRvbmRlYWRvIikuIFNlIHB1ZWRlIGp1Z2FyIGNvbiBhbWJvcyB2YWxvcmVzIHBhcmEgdmVyIHN1cyBlZmVjdG9zLiBFbiBsYSB0ZXJjZXIgbMOtbmVhIGFjbGFyYW1vcyBxdWUgcXVlcmVtb3MgdW4gdGVtYSBtaW5pbWFsaXN0YSwgZW4gbGEgY3VhcnRhIHF1ZSBsYSBwYWxldGEgZGUgY29sb3JlcyBsYSB2YW1vcyBhIGFzaWduYSBkZSBtYW5lcmEgbWFudWFsLCBlbiBsYSBxdWludGEgcXVlIG5vIHF1ZXJlbW9zIHVuYSBsZXllbmRhIGFjbGFyYW5kbyBsb3MgY29sb3JlcyBkZSBjYWRhIGNhdGVnb3LDrWEgcG9ycXVlIHlhIGVzdMOhbiBhY2xhcmFkYXMgZW4gZWwgZWplIHkuIFkgcG9yIMO6bHRpbW8gYWNsYXJhbW9zIGxhcyBldGlxdWV0YXMgbmVjZXNhcmlhcy4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRvcywgYWVzKHggPSBQcmVjaW8uZGUubGlzdGEsIHkgPSBDYXRlZ29yw61hLCBmaWxsID0gQ2F0ZWdvcsOtYSkpICsKICBnZW9tX2RlbnNpdHlfcmlkZ2VzKHNjYWxlID0gMywgYmFuZHdpZHRoID0gMjApICsgIyBlbCBiYW5kd2lkdGggYW50ZXJpb3IgZXN0YWJhIGVuIDEwCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQiLCAidmlvbGV0cmVkIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIlByZWNpbyBkZSBsaXN0YSBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIiwKICAgICAgIHN1YnRpdGxlID0gZGF0ZSwKICAgICAgIHggPSAiUHJlY2lvIGRlIGxpc3RhIiwKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiAjTWVuc3RydUFjY2nDs24iKQpgYGAKCkEgcHJpbWVyYSB2aXN0YSwgbG9zIG5pdmVsZXMgZGUgcHJlY2lvcyBkZSB0b2FsbGl0YXMgeSB0YW1wb25lcyBzZSBkaXN0cmlidXllbiBlbiB1bmEgbWlzbWEgZXNjYWxhLiBFbiBlbCBjYXNvIGRlIGxvcyB0YW1wb25lcyBoYXkgdW5hIGRpc3RyaWJ1Y2nDs24gYmltb2RhbCwgcXVlIHB1ZWRlIGRlYmVyc2UgYSBsYSBhbXBsaWEgY2FudGlkYWQgZGUgcHJlc2VudGFjaW9uZXMgZGUgOCB5IDE2IHVuaWRhZGVzLgo8YnI+PGJyPgpUYW1iacOpbiBwb2RlbW9zIGdyYWZpY2FyIGxvcyBwcmVjaW9zIGRlIGNhZGEgY2F0ZWdvcsOtYSBwb3IgcmVnaW9uZXM6CmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CiNsaWJyYXJ5KGRpY2hyb21hdCkKI3BhbCA8LSBjb2xvclJhbXBQYWxldHRlKGMoInJlZCIsICJ2aW9sZXRyZWQiKSkoNikKIwojZ2dwbG90KGRhdG9zLCBhZXMoeCA9IFByZWNpby5kZS5saXN0YSwgeSA9IFJlZ2lvbiwgZmlsbCA9IFJlZ2lvbikpICsKIyAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhzY2FsZSA9IDIsIGJhbmR3aWR0aCA9IDEwKSArCiMgIHRoZW1lX21pbmltYWwoKSArCiMgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbCkrCiMgIGZhY2V0X3dyYXAoLiB+IENhdGVnb3LDrWEpICsKIyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRvcywgYWVzKHggPSBQcmVjaW8uZGUubGlzdGEsIHkgPSBSZWdpb24sIGZpbGwgPSBDYXRlZ29yw61hLCBhbHBoYSA9IFJlZ2lvbikpICsKICBnZW9tX2RlbnNpdHlfcmlkZ2VzKHNjYWxlID0gMiwgYmFuZHdpZHRoID0gMjApICsgIyBlbCBiYW5kd2lkdGggYW50ZXJpb3IgZXN0YWJhIGVuIDEwCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQiLCAidmlvbGV0cmVkIikpKwogIGZhY2V0X3dyYXAoLiB+IENhdGVnb3LDrWEpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIlByZWNpbyBkZSBsaXN0YSBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIHkgcmVnacOzbiIsCiAgICAgICBzdWJ0aXRsZSA9IGRhdGUsCiAgICAgICB4ID0gIlByZWNpbyBkZSBsaXN0YSIsCiAgICAgICB5ID0gIiIsCiAgICAgICBjYXB0aW9uID0gIkZ1ZW50ZTogI01lbnN0cnVBY2Npw7NuIikKYGBgCgpFbiBlc3RlIGNhc28gc2UgZW5jdWVudHJhbiBkaWZlcmVuY2lhcyBtw6FzIHF1ZSBuYWRhIGVudHJlIGxvcyB0YW1wb25lcywgbm8gYXPDrSBlbiBlbCBjYXNvIGRlIGxhcyB0b2FsbGl0YXMuIERhZG8gZWwgcGVzbyBkZSBHQkEgZW50cmUgbGFzIG9ic2VydmFjaW9uZXMsIHRpZW5lIHNlbnRpZG8gcXVlIGxhIGRpc3RyaWJ1Y2nDs24gZ2VuZXJhbCBzZSBhc2VtZWplIGEgbGEgZGUgZGljaGEgcmVnacOzbi4KCiMjIyBMaW1waWV6YSBkZSBsYSBjYW50aWRhZCBkZSB1bmlkYWRlcyAoUHJlc2VudGFjacOzbikKCkNvbW8gbWVuY2lvbsOhYmFtb3MgYW50ZXJpb3JtZW50ZSwgZXMgbmVjZXNhcmlvIHByZXN0YXJsZSBwYXJ0aWN1bGFyIGF0ZW5jacOzbiBhIGxhIHZhcmlhYmxlIGRlIGBQcmVzZW50YWNpw7NuYCwgcXVlIGluZGljYSBsYSBjYW50aWRhZCBkZSB1bmlkYWRlcyBwb3IgY2FkYSBwYXF1ZXRlLiBFbiBwcmltZXIgbHVnYXIsIHRlbmllbmRvIGVuIGN1ZW50YSBxdWUgZXN0w6EgZXhwcmVzYWRhIGNvbW8gIjggdW4uIiwgbW9kaWZpY2Ftb3MgbGEgdmFyaWFibGUgcGFyYSBxdWVkYXJub3Mgw7puaWNhbWVudGUgY29uIGxhcyB1bmlkYWRlcyBlbiBmb3JtYXRvIG51bcOpcmljby4gRXN0byBsbyBoYWNlbW9zIGNvbnZpcnRpZW5kbyBsYSB2YXJpYWJsZSBhbCB0aXBvIGNoYXJhY3RlciwgeSBsdWVnbyBxdWVkw6FuZG9ub3MgY29uIGFxdWVsbG9zIGNhcmFjdGVyZXMgZW50cmUgbGEgcHJpbWVyIHBvc2ljacOzbiB5IGFxdWVsbGEgcXVlIHNlIGVuY3VlbnRyYSA0IHBvc2ljaW9uZXMgcG9yIGRldHLDoXMgZGUgbGEgw7psdGltYSAob21pdGllbmRvIGFzw60gIi4wIHVuIikuIEVuIGxhIHRhYmxhIGBwcmVzZW50YWNpb25fbnJvc2AgcmVzdW1pbW9zIGVsIGNvbXBvcnRhbWllbnRvIGRlIGVzdGEgbnVldmEgdmFyaWFibGUgYHVuaWRhZGVzYC4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUoUHJlc2VudGFjacOzbiA9IGFzLmNoYXJhY3RlcihQcmVzZW50YWNpw7NuKSwKICAgICAgICAgdW5pZGFkZXMgPSBhcy5udW1lcmljKHN1YnN0cihQcmVzZW50YWNpw7NuLCAxLCBuY2hhcihQcmVzZW50YWNpw7NuKS00KSkpCgpwcmVzZW50YWNpb25fbnJvcyA8LSBkYXRvcyAlPiUgCiAgY291bnQodW5pZGFkZXMpICU+JSAKICBhcnJhbmdlKC1uKSAlPiUgCiAgbXV0YXRlKHBvcmNlbnRhamUgPSBuL3N1bShuKSwKICAgICAgICAgYWN1bXVsYWRvID0gY3Vtc3VtKHBvcmNlbnRhamUpLAogICAgICAgICBwb3JjZW50YWplID0gcGVyY2VudChwb3JjZW50YWplKSwKICAgICAgICAgYWN1bXVsYWRvID0gcGVyY2VudChhY3VtdWxhZG8pKQpwcmVzZW50YWNpb25fbnJvcwpgYGAKClNpbiBlbWJhcmdvLCBlbiBsYSBiYXNlIHB1ZWRlIHZlcnNlIHF1ZSBoYXkgY2Fzb3MgcXVlLCBkZSBhY3VlcmRvIGEgbGEgZGVzY3JpcGNpw7NuIGVuIGBOb21icmVgLCB0aWVuZW4gbWFsIGxhIGNhbnRpZGFkIGRlIHVuaWRhZGVzIGVuIGBQcmVzZW50YWNpb25gICh5IHBvciBlbmRlIGVuIHVuaWRhZGVzKSwgYWZlY3RhbmRvIGVsIGNhbGN1bG8gZGUgcHJlY2lvcyB1bml0YXJpb3MuCjxicj48YnI+ClV0aWxpemFuZG8gZXhwcmVzaW9uZXMgcmVndWxhcmVzIHBvZGVtb3MgcXVlZGFybm9zIGNvbiBsb3MgZMOtZ2l0b3MsIHNlYW4gdW5vIG8gbcOhcywgcXVlIGVzdMOhbiBzZWd1aWRvcyBkZSAiVW4iIG8gInVuIiBlbiBsYSB2YXJpYWJsZSBgTm9tYnJlYC4gTm9zIHF1ZWRhbW9zIGNvbiBlc3RhIGluZm9ybWFjacOzbiBlbiBsYSB2YXJpYWJsZSBgdW5pZGFkZXNfcmVnZXhgIHkgcmVzdW1pbW9zIHN1IGNvbXBvcnRhbWllbnRvLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgPC0gZGF0b3MgJT4lIAogIG11dGF0ZSh1bmlkYWRlc19yZWdleCA9IGFzLm51bWVyaWMoc3RyX2V4dHJhY3QoTm9tYnJlLCAnXFxkKyg/PVxccypbVXVdbj8pJykpKQoKcHJlc2VudGFjaW9uX3JlZ2V4IDwtIGRhdG9zICU+JSAKICBjb3VudCh1bmlkYWRlc19yZWdleCkgJT4lIAogIGFycmFuZ2UoLW4pICU+JSAKICBtdXRhdGUocG9yY2VudGFqZSA9IG4vc3VtKG4pLAogICAgICAgICBhY3VtdWxhZG8gPSBjdW1zdW0ocG9yY2VudGFqZSksCiAgICAgICAgIHBvcmNlbnRhamUgPSBwZXJjZW50KHBvcmNlbnRhamUpLAogICAgICAgICBhY3VtdWxhZG8gPSBwZXJjZW50KGFjdW11bGFkbykpCnByZXNlbnRhY2lvbl9yZWdleApgYGAKCk7Ds3Rlc2UgcXVlIGhheSBwZXF1ZcOxYXMgZGlmZXJlbmNpYXMgcmVzcGVjdG8gZGVsIGN1YWRybyBhbnRlcmlvci4gRW4gZXN0ZSBjYXNvLCBsYXMgdW5pZGFkZXMgc2UgZW5jdWVudHJhbiBtw6FzIGNvbmNlbnRyYWRhcyBlbiB2YWxvcmVzIHBvcHVsYXJlcy4gUG9kZW1vcyBpZGVudGlmaWNhciBjdcOhbmRvIGFtYmFzIGluZm9ybWFjaW9uZXMgKGxhIGNvbnRlbmlkYSBlbiBgdW5pZGFkZXNgIHkgZW4gYHVuaWRhZGVzX3JlZ2V4YCkgY29pbmNpZGVuIHkgY3XDoW5kbyBuby4gQ3JlYW1vcyBsYSB2YXJpYWJsZSBgaWd1YWxgIHF1ZSB0b21hIHZhbG9yIFRSVUUgY3VhbmRvIHNvbiBpZ3VhbGVzLCB5IEZBTFNFIGN1YW5kbyBuby4gQSBjb250aW51YWNpw7NuLCBlbiBsYSB0YWJsYSBgY29tcGFyb191bmlkYWRlc2Agc2UgcmVhbGl6YSB1biBjb250ZW8gZGUgb2JzZXJ2YWNpb25lcyBwYXJhIGFtYmFzIHZhcmlhYmxlcywgc2UgaWRlbnRpZmljYW4gbGFzIHNpdHVhY2lvbmVzIGRlIGNvaW5jaWRlbmNpYSB5IGRpZmVyZW5jaWEgeSBzZSBvcmRlbmFuIGxvcyBkYXRvcyBwYXJhIHZlciBwcmltZXJvIGxhcyBkaWZlcmVuY2lhcywgc2Vnw7puIGxhIG1hZ25pdHVkLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgPC0gZGF0b3MgJT4lIAogIG11dGF0ZShpZ3VhbCA9IGNhc2Vfd2hlbih1bmlkYWRlcyA9PSB1bmlkYWRlc19yZWdleCB+IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaWRhZGVzICE9IHVuaWRhZGVzX3JlZ2V4IH4gRikpCgpjb21wYXJvX3VuaWRhZGVzIDwtIGRhdG9zICU+JSAKICBjb3VudCh1bmlkYWRlcywgdW5pZGFkZXNfcmVnZXgpICU+JSAKICBtdXRhdGUoaWd1YWwgPSBjYXNlX3doZW4odW5pZGFkZXMgPT0gdW5pZGFkZXNfcmVnZXggfiBULAogICAgICAgICAgICAgICAgICAgICAgICAgICB1bmlkYWRlcyAhPSB1bmlkYWRlc19yZWdleCB+IEYpKSAlPiUgCiAgYXJyYW5nZShpZ3VhbCwgLW4pCgpjb21wYXJvX3VuaWRhZGVzCmBgYAoKRW4gcGFydGljdWxhciwgaGF5IGNhc29zIHF1ZSBmdWVyb24gaW5mb3JtYWRvcyBjb21vIGRlIDEgbyAyNyB1bmlkYWRlcyB5IGVuIHJlYWxpZGFkIGVyYW4gZGUgMTYgKHRpZW5lIHNlbnRpZG8gcXVlIGVzdGUgw7psdGltbyBzZWEgZWwgdmVyZGFkZXJvIHZhbG9yKSwgbyBjYXNvcyBxdWUgZnVlcm9uIGluZm9ybWFkb3MgY29tbyBkZSAxIG8gNTQgdW5pZGFkZXMgeSBlbiByZWFsaWRhZCBlcmFuIGRlIDguIENvbW8gcHVlZGUgdmVyc2UgYSBjb250aW51YWNpw7NuLCBoYXkgZW4gdG90YWwgMTc3MSBjYXNvcyBlbiBxdWUgbGEgaW5mb3JtYWNpw7NuIG5vIGNvaW5jaWRlLCBsbyBxdWUgcmVwcmVzZW50YSBlbCAyJSBkZSBsYSBpbmZvcm1hY2nDs24uCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYXRvcyAlPiUgCiAgZ3JvdXBfYnkoaWd1YWwpICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIAogIG11dGF0ZShwb3JjID0gcGVyY2VudChuL3N1bShuKSkpCmBgYAoKVmFsZSBsYSBwZW5hIGRlc3RhY2FyIHF1ZSBlc3RvcyBlcnJvcmVzIHNlIHByZXNlbnRhbiBlbiB0b2RhcyBsYXMgcmVnaW9uZXMsIHkgY29uY2VudHJhZG9zIGVuIDUgbWFyY2FzIGRpZmVyZW50ZXMsIGF1bnF1ZSBkZSBsYXMgbcOhcyBwb3B1bGFyZXMgZW4gbnVlc3RybyBkYXRhc2V0LiAKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgRGlzdHJpYnVjaW9uIGRlIGxvcyBkYXRvcyBxdWUgcXVlcmVtb3Mgc2FjYXIgZW50cmUgbGFzIHJlZ2lvbmVzCmRhdG9zICU+JSAKICBmaWx0ZXIoaWd1YWwgPT0gRkFMU0UpICU+JSAKICBjb3VudChSZWdpb24pCgojIERpc3RyaWJ1Y2lvbiBkZSBsb3MgZGF0b3MgcXVlIHF1ZXJlbW9zIHNhY2FyIGVudHJlIGxhcyBtYXJjYXMKZGF0b3MgJT4lIAogIGZpbHRlcihpZ3VhbCA9PSBGQUxTRSkgJT4lIAogIGNvdW50KE1hcmNhKQpgYGAKCiMjIyMgQWNsYXJhY2nDs24KCkVuIGVsIGVqZXJjaWNpbyBhbnRlcmlvciAoc2VwdGllbWJyZSAyMDE5KSwgcHJlc2NpbmRpbW9zIGRlIGxvcyB2YWxvcmVzIGZhbHRhbnRlcyBlbiBgdW5pZGFkZXNfcmVnZXhgIChwb3IgbcOhcyBxdWUgdGVuZ2FuIHZhbG9yIGVuIGB1bmlkYWRlc2AsIGFxdWVsbGEgcXVlIHN1cmdlIGRlIGxhIHZhcmlhYmxlIGBQcmVzZW50YWNpw7NuYCkuIFZlcmlmaWNhbW9zIGFxdWVsbG9zIGNhc29zIGVuIHF1ZSBgdW5pZGFkZXNfcmVnZXhgIChxdWUgc3VyZ2UgZGVsIHRleHRvIGVuIGBOb21icmVgKSBubyBjb2luY2lkZSBjb24gbGEgdmFyaWFibGUgYHVuaWRhZGVzYC4gRXN0YWJsZWNpbW9zIHF1ZSBsYXMgY2FudGlkYWRlcyByZWZlcmlkYXMgYSBsYXMgdW5pZGFkZXMgcG9yIHBhcXVldGUgcGFyZWNlbiBzZXIgbWVqb3IgY2FwdGFkYXMgY29uIGVsIG3DqXRvZG8gZGUgcmVnZXggc29icmUgZWwgdGV4dG8gZGVsIGBOb21icmVgIGRlbCBwcm9kdWN0bywgcmVzcGVjdG8gZGUgbG8gc3VyZ2lkbyBkZSBsYSBpbmZvcm1hY2nDs24gZGUgbGEgcMOhZ2luYSBjb21vIGBQcmVzZW50YWNpw7NuYC4gTm9zIHF1ZWRhbW9zIGNvbiBgdW5pZGFkZXNfcmVnZXhgIHBhcmEgY2FsY3VsYXIgZWwgcHJlY2lvIHBvciB1bmlkYWQgZGUgbG9zIHByb2R1Y3Rvcy4KCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CiMgRXN0ZSBjb2RpZ28gZXN0YSBhbnVsYWRvLiBFcyBsbyBxdWUgZXN0YWJhIGVuIGVsIGVqZXJjaWNpbyBhbnRlcmlvcgp1bmlkYWRlcy5mYWx0YW50ZXMgPC0gZGF0b3MgJT4lIAogIGZpbHRlcihpcy5uYSh1bmlkYWRlcy5yZWdleCkpICU+JSAKICBzZWxlY3QoTm9tYnJlLCB1bmlkYWRlcy5yZWdleCwgUHJlc2VudGFjacOzbiwgdW5pZGFkZXMpICU+JSAKICBncm91cF9ieShOb21icmUsIHVuaWRhZGVzLnJlZ2V4LCBQcmVzZW50YWNpw7NuLCB1bmlkYWRlcykgJT4lIAogIHN1bW1hcmlzZShuKCkpCgpkYXRvcyA8LSBkYXRvcyAlPiUgCiAgZmlsdGVyKCFpcy5uYSh1bmlkYWRlcy5yZWdleCkpCgprYWJsZSh1bmlkYWRlcy5mYWx0YW50ZXMpICU+JSAKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiLAogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEYpCgp2ZXJpZiA8LSBkYXRvcyAlPiUgCiAgZmlsdGVyKHVuaWRhZGVzLnJlZ2V4ICE9IHVuaWRhZGVzKSAlPiUgCiAgZ3JvdXBfYnkoTm9tYnJlLCB1bmlkYWRlcywgdW5pZGFkZXMucmVnZXgpICU+JSAKICBzdW1tYXJpc2Uobj1uKCkpICU+JSAKICBhcnJhbmdlKC1uKQoKa2FibGUodmVyaWYpICU+JSAKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiLAogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEYpCmBgYAoKRXN0YSB2ZXosIGRhZG8gcXVlIGVsIHBvcmNlbnRhamUgZGUgYXF1ZWxsb3MgY2Fzb3MgZW4gcXVlIG5vIGNvaW5jaWRlbiBgdW5pZGFkZXNgIHkgYHVuaWRhZGVzX3JlZ2V4YCwganVudG8gYSBsb3MgY2Fzb3MgZW4gcXVlIGB1bmlkYWRlc19yZWdleGAgZmlndXJhIGNvbW8gYE5BYCwgYWxjYW56YW4gc29sYW1lbnRlIHVuIDIlLCBzZSBwcmVzY2luZGlyw6EgZGUgdG9kb3MgZWxsb3MuIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGF0b3MgPC0gZGF0b3MgJT4lIAogIGZpbHRlcihpZ3VhbCA9PSBUUlVFKQpgYGAKCl9fU2UgZGVzY2FydGFuIDEuODk0IGNhc29zX18geSBhaG9yYSBjb250YW1vcyBjb24gYHIgY2FudChucm93KGRhdG9zKSlgIG9ic2VydmFjaW9uZXMuIFRhbWJpw6luIHBvZGVtb3MgZGVzaGFjZXJub3MgZGUgdmFyaWFibGVzIHF1ZSBubyB2YW1vcyBhIHV0aWxpemFyIGVuIGVsIGVqZXJjaWNpbyBkZSBlc3RpbWFjacOzbi4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgRGVzY2FydG8gbGFzIHZhcmlhYmxlcyBxdWUgbm8gdm95IGEgdXNhcgpkYXRvcyA8LSBkYXRvcyAlPiUgCiAgc2VsZWN0KC1QcmVzZW50YWNpw7NuLCAtdW5pZGFkZXNfcmVnZXgsIC1pZ3VhbCkKYGBgCiAgICAgICAgCiMjIyBDw6FsY3VsbyBkZWwgcHJlY2lvIHBvciB1bmlkYWQKCkNyZW8gbGEgdmFyaWFibGUgYHByZWNpb191bmlkYWRgLCBkaXZpZGllbmRvIGVsIGBQcmVjaW8uZGUubGlzdGFgIHBvciBsYXMgYHVuaWRhZGVzYC4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUocHJlY2lvX3VuaWRhZCA9IHJvdW5kKFByZWNpby5kZS5saXN0YS91bmlkYWRlcywgMikpCmBgYAoKIyMjIEdyw6FmaWNvcyBkZWwgcHJlY2lvIHBvciB1bmlkYWQKCkFob3JhIHBvZGVtb3Mgb2JzZXJ2YXIgbGEgZGlzdHJpYnVjacOzbiBkZSBlc3RhIG51ZXZhIHZhcmlhYmxlIGNvbiBsb3MgbWlzbW9zIGdyw6FmaWNvcyBxdWUgdXRpbGl6YW1vcyBhbnRlcy4KCmBgYHtyIGVjaG89VFJVRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9NywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGRhdG9zLCBhZXMoeCA9IHByZWNpb191bmlkYWQsIHkgPSBDYXRlZ29yw61hLCBmaWxsID0gQ2F0ZWdvcsOtYSkpICsKICBnZW9tX2RlbnNpdHlfcmlkZ2VzKHNjYWxlID0gMiwgYmFuZHdpZHRoID0gMS4yNSkgKyAjIGVsIGJhbmR3aWR0aCBhbnRlcmlvciBlc3RhYmEgZW4gMTAKICB0aGVtZV9taW5pbWFsKCkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDMwKSkgKyAjIEVuIGVsIGFudGVyaW9yIGVsIGxpbWl0ZSBlc3RhYmEgZW4gMjAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQiLCAidmlvbGV0cmVkIikpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKHRpdGxlID0gIlByZWNpbyBwb3IgdW5pZGFkIGRlIHByb2R1Y3RvcyBkZSBnZXN0acOzbiBtZW5zdHJ1YWwgc2Vnw7puIGNhdGVnb3LDrWEiLAogICAgICAgc3VidGl0bGUgPSBkYXRlLAogICAgICAgeCA9ICJQcmVjaW8gcG9yIHVuaWRhZCIsCiAgICAgICB5ID0gIiIsCiAgICAgICBjYXB0aW9uID0gIkZ1ZW50ZTogI01lbnN0cnVBY2Npw7NuIikKYGBgCgpFbiBlc3RlIGNhc28sIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIHByZWNpb3MgZGUgbG9zIHRhbXBvbmVzIHNlIGVudGllbmRlIGNvbW8gbcOhcyBjb25jZW50cmFkYSAoeWEgbm8gZXN0w6EgdGFuIG1hcmNhZGEgdW5hIGJpbW9kYWwpIHkgY29uIHVuIHJhbmdvIGRlIHByZWNpb3Mgc3VwZXJpb3IgYWwgZGUgbGFzIHRvYWxsaXRhcy4KPGJyPjxicj4KRXN0YSB2ZXosIHBhcmEgcmVhbGl6YXIgZWwgZ3LDoWZpY28gcG9yIGNhdGVnb3LDrWFzIHkgcmVnaW9uZXMsIHBvZGVtb3Mgb3JkZW5hciBhIGVzdGFzIMO6bHRpbWFzIHNlZ8O6biBzdSBwcmVjaW8gcHJvbWVkaW8gZW4gZWwgZ3LDoWZpY28uIFBhcmEgZWxsbyBjb25zdHJ1aW1vcyB1biB2ZWN0b3IgcXVlIGxhcyBhbG9qZSBlbiBvcmRlbiwgbGxhbWFkbyBgcmVnX29yZGVuYWRhc2AuIEx1ZWdvLCBwaXNhbW9zIGxhIHZhcmlhYmxlIGBSZWdpb25gIGVuIGxvcyBkYXRvcyBwYXJhIHF1ZSBzZWEgZGUgdGlwbyBmYWN0b3IsIHkgZWwgb3JkZW4gZGUgbGEgbWlzbWEgZXN0w6kgZGV0ZXJtaW5hZG8gc2Vnw7puIGVsIHZlY3RvciBwcmV2aWFtZW50ZSBkZWZpbmlkby4KCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcmVnX29yZGVuYWRhcyA8LSBkYXRvcyAlPiUgCiAgZ3JvdXBfYnkoUmVnaW9uKSAlPiUgCiAgc3VtbWFyaXNlKHByb21lZGlvID0gbWVhbihwcmVjaW9fdW5pZGFkKSkgJT4lIAogIGFycmFuZ2UocHJvbWVkaW8pICUkJSBSZWdpb24KCmRhdG9zIDwtIGRhdG9zICU+JSAKICBtdXRhdGUoUmVnaW9uID0gZmFjdG9yKFJlZ2lvbiwgbGV2ZWxzID0gcmVnX29yZGVuYWRhcykpCmBgYAoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZGF0b3MsIGFlcyh4ID0gcHJlY2lvX3VuaWRhZCwgeSA9IFJlZ2lvbiwgZmlsbCA9IENhdGVnb3LDrWEsIGFscGhhID0gUmVnaW9uKSkgKwogIGdlb21fZGVuc2l0eV9yaWRnZXMoc2NhbGUgPSAyLCBiYW5kd2lkdGggPSAxLjI1KSArICMgZWwgYmFuZHdpZHRoIGFudGVyaW9yIGVzdGFiYSBlbiAxCiAgdGhlbWVfbWluaW1hbCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJyZWQiLCAidmlvbGV0cmVkIikpKwogIGZhY2V0X3dyYXAoLiB+IENhdGVnb3LDrWEpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAzMCkpICsgIyBFc3RlIHZhbG9yIHNlIGFjdHVhbGl6YSBzZWd1biBpbmZsYWNpb24sIGEgb2pvCiAgbGFicyh0aXRsZSA9ICJQcmVjaW8gcG9yIHVuaWRhZCBkZSBwcm9kdWN0b3MgZGUgZ2VzdGnDs24gbWVuc3RydWFsIHNlZ8O6biBjYXRlZ29yw61hIHkgcmVnacOzbiIsCiAgICAgICBzdWJ0aXRsZSA9IGRhdGUsCiAgICAgICB4ID0gIlByZWNpbyBwb3IgdW5pZGFkIiwKICAgICAgIHkgPSAiIiwKICAgICAgIGNhcHRpb24gPSAiRnVlbnRlOiAjTWVuc3RydUFjY2nDs24iKQpgYGAKCiMjIyMgMiw1ICUgZGUgbG9zIGV4dHJlbW9zIGRlIGxhIGRpc3RyaWJ1Y2nDs24KCkFkaWNpb25hbG1lbnRlLCBjb21vIGVsIGPDoWxjdWxvIGxvIHJlYWxpemFyZW1vcyBhZ3JlZ2FuZG8gbG9zIHByZWNpb3MgZGUgYWN1ZXJkbyBhIHVuYSBtZWRpYSBhbHBoYSBwb2RhZGEgY29uIGFscGhhID0gMiw1JSAobyBzZWEsIGlnbm9yYW5kbyBsb3MgdmFsb3JlcyBzdXBlcmlvcmVzIGUgaW5mZXJpb3JlcyBwYXJhIGV2aXRhciBsYSBpbnRydXNpw7NuIGRlIG91dGxpZXJzIGEgcGVzYXIgZGUgbGEgbGltcGllemEpLCBwcmVzZW50YW1vcyBncsOhZmljb3MgcXVlIGp1c3RhbWVudGUgbXVlc3RyYW4gbGFzICJjb2xhcyIgZGUgbGEgZGlzdHJpYnVjacOzbiBxdWUgc2UgZXN0YXLDrWFuIG9idmlhbmRvLgoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZGF0b3MsIGFlcyh4ID0gcHJlY2lvX3VuaWRhZCwgeSA9IENhdGVnb3LDrWEsIGZpbGwgPSBmYWN0b3IoLi5xdWFudGlsZS4uKSkpICsKICBzdGF0X2RlbnNpdHlfcmlkZ2VzKGdlb20gPSAiZGVuc2l0eV9yaWRnZXNfZ3JhZGllbnQiLCAKICAgICAgICAgICAgICAgICAgICAgIGNhbGNfZWNkZiA9IFRSVUUsIHF1YW50aWxlcyA9IGMoMC4wMjUsIDAuOTc1KSwKICAgICAgICAgICAgICAgICAgICAgIGJhbmR3aWR0aCA9IDEuMjUsIHNjYWxlID0gMS41KSArICMgRWwgYmFuZHdpZHRoIGFudGVyaW9yIGVzdGFiYSBlbiAwLjc1CiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJQcm9iYWJpbGlkYWQiLCAKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCJ2aW9sZXRyZWQxIiwgInJlZDIiLCAidmlvbGV0cmVkMSIpLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjIsNSAlIiwgIjk1LDAgJSIsICIyLDUgJSIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMzApKSArICMgRWwgbGltaXRlIGFudGVyaW9yIGVzdGFiYSBlbiAyMAogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBsYWJzKHRpdGxlID0gIlByZWNpbyBwb3IgdW5pZGFkIGRlIHByb2R1Y3RvcyBkZSBnZXN0acOzbiBtZW5zdHJ1YWwgc2Vnw7puIGNhdGVnb3LDrWEiLAogICAgICAgc3VidGl0bGUgPSBwYXN0ZShkYXRlKSwKICAgICAgIHggPSAiUHJlY2lvIHBvciB1bmlkYWQiLAogICAgICAgeSA9ICIiLAogICAgICAgY2FwdGlvbiA9ICJGdWVudGU6ICNNZW5zdHJ1QWNjacOzbiIpCmBgYAoKUmVhbGl6YW1vcyBlbCBtaXNtbyBncsOhZmljbyBwb3IgY2FkYSBwcm92aW5jaWEsIHlhIHF1ZSBlc2Egc2Vyw6EgbGEgcHJpbWVyIHVuaWRhZCBkZSBhZ3JlZ2FjacOzbiBwYXJhIGVsIGPDoWxjdWxvIHRvdGFsIGEgbml2ZWwgbmFjaW9uYWwuCgpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnByb3Zfb3JkZW5hZGFzIDwtIGRhdG9zICU+JSAKICBncm91cF9ieShQcm92aW5jaWEpICU+JSAKICBzdW1tYXJpc2UocHJvbWVkaW8gPSBtZWFuKHByZWNpb191bmlkYWQpKSAlPiUgCiAgYXJyYW5nZShwcm9tZWRpbykgJSQlIAogIFByb3ZpbmNpYQoKZGF0b3MgPC0gZGF0b3MgJT4lIAogIG11dGF0ZShQcm92aW5jaWEgPSBmYWN0b3IoUHJvdmluY2lhLCBsZXZlbHMgPSBwcm92X29yZGVuYWRhcykpCmBgYAoKYGBge3IgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9OSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KGRhdG9zLCBhZXMoeCA9IHByZWNpb191bmlkYWQsIHkgPSBQcm92aW5jaWEsIAogICAgICAgICAgICAgICAgICBmaWxsID0gZmFjdG9yKC4ucXVhbnRpbGUuLikpKSArCiAgc3RhdF9kZW5zaXR5X3JpZGdlcyhnZW9tID0gImRlbnNpdHlfcmlkZ2VzX2dyYWRpZW50IiwgCiAgICAgICAgICAgICAgICAgICAgICBjYWxjX2VjZGYgPSBUUlVFLCBxdWFudGlsZXMgPSBjKDAuMDI1LCAwLjk3NSksCiAgICAgICAgICAgICAgICAgICAgICBiYW5kd2lkdGggPSAxLjI1LCBzY2FsZSA9IDIpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lID0gIlByb2JhYmlsaWRhZCIsIAogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoInZpb2xldHJlZDEiLCAicmVkMiIsICJ2aW9sZXRyZWQxIiksCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiMiw1ICUiLCAiOTUsMCAlIiwgIjIsNSAlIikpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAzMCkpICsgIyBFbCBsaW1pdGUgYW50ZXJpb3IgZXN0YWJhIGVuIDIwCiAgZmFjZXRfd3JhcCguIH4gQ2F0ZWdvcsOtYSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBsYWJzKHRpdGxlID0gIlByZWNpbyBwb3IgdW5pZGFkIGRlIHByb2R1Y3RvcyBkZSBnZXN0acOzbiBtZW5zdHJ1YWwgc2Vnw7puIGNhdGVnb3LDrWEgeSBwcm92aW5jaWEiLAogICAgICAgc3VidGl0bGUgPSBwYXN0ZShkYXRlLCAiLiAiKSwKICAgICAgIHggPSAiUHJlY2lvIHBvciB1bmlkYWQiLAogICAgICAgeSA9ICIiLAogICAgICAgY2FwdGlvbiA9ICJGdWVudGU6ICNNZW5zdHJ1QWNjacOzbiIpCmBgYAoKRmluYWxtZW50ZSwgZ3VhcmRhbW9zIGVzdGEgbnVldmEgdmVyc2nDs24gZGVsIGRhdGFzZXQgZW4gZm9ybWF0byAuUkRTIHBhcmEgY29udGludWFyIGVuIGVsIHNpZ3VpZW50ZSBzY3JpcHQgY29uIGVsIGPDoWxjdWxvIGRlIGN1w6FudG8gY3Vlc3RhIG1lbnN0cnVhci4KCmBgYHtyIGVjaG89VFJVRX0KIyBzYXZlUkRTKGRhdG9zLCBmaWxlID0gIkZ1ZW50ZXMvcHJlY2lvcy1nZXN0aW9uLW1lbnN0cnVhbC0yMDIwLTAzLTIzLWxpbXBpby5SRFMiKQpgYGAKCg==