Introducción

En este documento empezaremos con los aspectos básicos de cómo usar la base de datos del Barómetro de las Américas de LAPOP para fines estadísticos. En primer lugar, veremos aspectos básicos de cómo describir una variable mediante una tabla de distribución de frecuencias y cómo graficar esa variable mediante gráficos circulares o de barras. Para eso, vamos a usar los informes regionales “El pulso de la democracia”, con los resultados de la ronda 2021, disponible aquí, y con los resultados de la ronda 2018/19, disponible aquí.

Uno de los resultados más relevantes en la ronda 2021 presenta los resultados sobre apoyo a la democracia en la región. Para la ronda 2018/19, una de las secciones de este informe, reporta los datos sobre redes sociales y actitudes políticas. En esta sección, se presentan datos sobre el uso de internet y el uso de redes sociales, en general y por país. Con los datos del Barómetro de las Américas se puede saber el porcentaje de hogares con acceso a celulares, con acceso a internet, así como el porcentaje de personas que usa Whatsapp, Facebook o Twitter. En este documento vamos a repasar estos resultados.

Sobre la base de datos

Los datos que vamos a usar deben citarse de la siguiente manera: Fuente: Barómetro de las Américas por el Proyecto de Opinión Pública de América Latina (LAPOP), wwww.LapopSurveys.org. En este documento se carga nuevamente desde cero una base de datos recortada. Se recomienda nuevamente limpiar el Environment de los objetos usados en módulos anteriores.

Esta base de datos se encuentra alojada en el repositorio “materials_edu” de la cuenta de LAPOP en GitHub. Mediante la librería rio y el comando import se puede importar esta base de datos desde este repositorio. Además, se seleccionan los datos de países con códigos menores o iguales a 35, es decir, se eliminan las observaciones de Estados Unidos y Canadá.

library(rio)
lapop18 = import("https://raw.github.com/lapop-central/materials_edu/main/LAPOP_AB_Merge_2018_v1.0.sav")
lapop18 = subset(lapop18, pais<=35)

También cargamos la base de datos de la ronda 2021.

lapop21 = import("https://raw.github.com/lapop-central/materials_edu/main/lapop21.RData")
lapop21 = subset(lapop21, pais<=35)

Apoyo a la democracia

En el reporte de El Pulso de la Democracia 2021 se presenta los resultados del apoyo a la democracia por país. El gráfico 1.1 muestra el porcentaje de personas en cada país que apoya a la democracia en abstracto.

En los módulos anteriores se vio cómo recodificar la variable ING4, medida originalmente en una escala del 1 al 7, donde 1 significa “muy en desacuerdo” y 7 significa “muy de acuerdo”. Los valores entre 5 a 7 son recodificados como “1”, que identifica a aquellos que apoyan a la democracia. El resto se recodifica como “0”, aquellos que no apoyan a la democracia. Esta recodificación se guarda en una nueva variable “ing4rec”.

library(car)
lapop21$ing4rec = car::recode(lapop21$ing4, "1:4=0; 5:7=1")

En sentido estricto, esta variable no es numérica, a pesar que está definida en la base de datos como “dbl”, que es un tipo de variable numérica. Esta variable es de tipo cualitativo, nominal, que en R se define como factor. Para tener correctamente definida y etiquetada esta variable, se tiene que transformar. En primer lugar se define como factor con el comando as.factor.

lapop21$ing4rec = as.factor(lapop21$ing4rec)

Una variable de tipo factor puede tener etiquetas por cada código numérico. La definición de etiquetas tiene el objetivo que en cualquier tabla o gráfico no aparezca el código numérico, sino la etiqueta correspondiente. Esto se hace usando el comando levels. Luego, esta variable se puede describir con el comando table, que nos brinda las frecuencias absolutas por cada categoría de la variable.

levels(lapop21$ing4rec) = c("No", "Sí")
table(lapop21$ing4rec)
## 
##    No    Sí 
## 20523 36240

Describir la variable

Como vimos en el módulo sobre Manejo de Datos, se puede usar el comando prop.table para tener las frecuencias relativas y el comando round para mostrar solo un decimal.

round(prop.table(table(lapop21$ing4rec))*100, 1)
## 
##   No   Sí 
## 36.2 63.8

Este gráfico muestra los resultados de las 2 categorías definidas de la variable de apoyo a la democracia. Sin embargo, esta variable tiene valores perdidos. Para poder tener una tabla con los valores perdidos, se puede usar el comando table con la especificación useNA = "always".

round(prop.table(table(lapop21$ing4rec, useNA = "always"))*100, 1)
## 
##   No   Sí <NA> 
## 33.8 59.7  6.4

En esta tabla se ve que existe un 6.4% de casos perdidos del total de observaciones. La presentación de valores perdidos en tablas o gráficos depende del investigador. Aquí vamos a presentar los gráficos sobre los datos válidos.

Graficar la variable

Una variable de tipo “factor” se puede graficar de varias maneras. Una posibilidad es tener un gráfico circular. Se puede usar el comando pie que es parte de la sintaxis básica de R. Dentro de este comando se puede anidar el comando table para graficar estos valores.

pie(table(lapop21$ing4rec))

Este gráfico tiene algunas opciones de personalización. Por ejemplo, la especificación labels=… sirve para incluir el número de casos de cada sector y la especificación col=… sirve para definir los colores de los sectores.

pie(table(lapop21$ing4rec), labels=table(lapop21$ing4rec), col=1:2)

Otra opción es usar un gráfico de barras. Usando los comandos básicos de R, se puede usar el comando barplot.

barplot(prop.table(table(lapop21$ing4rec))*100, col=1:2)

Los comando de base de R tienen un nivel de personalización, pero existe una librería especializada para hacer gráficos llamada ggplot con más opciones gráficas. En esta serie de módulos vamos a usar esta librería.

Por ejemplo, para reproducir un gráfico de barras de la variable de apoyo a la democracia se llama a la librería ggplot2. Para graficar los datos de una variable de tipo factor, tenemos dos opciones: hacerlo desde la misma base de datos original o crear un nuevo objeto que guarde los resultados en una tabla.

En este ejemplo partiremos de la segunda opción por ser más simple. Lo primero que tenemos que hacer es guardar la tabla en un objeto, como un dataframe. Para esto usamos el comando as.data.frame donde anidamos el código para producir la tabla. Este comando crea dos columna, “Var1” que guarda las etiquetas y “Freq” que guarda el valor de los porcentajes.

tabla1 = as.data.frame(round(prop.table(table(lapop21$ing4rec))*100, 1))
tabla1
##   Var1 Freq
## 1   No 36.2
## 2   Sí 63.8

Luego, tenemos que definir son los datos que se van a usar con la especificación data=tabla1. Ojo, no usaremos la base de datos original “lapop21”, sino la “tabla1” donde hemos guardado los resultados.

El comando ggplot trabaja sumando capas. La especificación aes sirve para definir la “estética” del gráfico. Generalmente se usa para indicar qué variable se va a graficar en qué eje (x o y). También se puede usar la especificación fill= para definir los grupos que se van a generar. En este caso, en el eje X queremos las categorías “Sí” y “No” y en el eje Y, los datos de “Freq”.

Luego de especificar los datos y los ejes, se tiene que especificar el tipo de gráfico que se quiere realizar. Esto se hace con las geometrías (“geom_xxx”). Se define un gráfico de barras simple, usando el comando geom_bar(...), donde internamente especificamos stat="identity" para que este comando trabaje con los datos tal cual están en la tabla. También se define el ancho de la barra con la especificación width. Con la especificación labs se define las etiquetas de ejes y el “caption”. Finalmente, con la especificación coord_cartesian se define los límites del eje Y de 0 a 80. Se debe notar que el gráfico no presenta una columna para el porcentaje de valores perdidos. Presentar esta columna es opción del investigador.

library(ggplot2)
ggplot(data=tabla1, aes(x=Var1, y=Freq))+
  geom_bar(stat = "identity", width=0.5)+
  labs(x="Apoyo a la democracia", y="Porcentaje", 
       caption="Barómetro de las Américas por LAPOP, 2021")+
  coord_cartesian(ylim=c(0, 80))

Hasta aquí se ha presentado un gráfico de barras de la variable apoyo a la democracia para toda la muestra, que incluye a todos los países. El gráfico 1.1 muestra el porcentaje que apoya a la democracia por país. Este tipo de gráfico se verá más adelante.

Usuarios de redes sociales

Ahora se usará un ejemplo del reporte El Pulso de la Democracia de la ronda 2018/19. Se seguirá procedimientos similares a la sección anterior y se replicarán algunos gráficos del mismo reporte de esa ronda. Las variables con las que se trabajará son: SMEDIA1. ¿Tiene usted cuenta de Facebook?; SMEDIA4. ¿Tiene usted cuenta de Twitter?; SMEDIA7. ¿Tiene usted cuenta de Whatsapp?. Estas preguntas tienen como opciones de respuesta:

  1. No

Al momento de leer la base de datos en R, este programa importa las variables como “num”, que la mayoría de funciones en R trata como numéricas. Estas variables se tienen que convertir a variables de tipo “factor” con el comando as.factor, pues son variables categóricas. Esta nuevas variables las guardamos en el dataframe.

lapop18$smedia1r = as.factor(lapop18$smedia1)
lapop18$smedia4r = as.factor(lapop18$smedia4)
lapop18$smedia7r = as.factor(lapop18$smedia7)

Estas nuevas variables de tipo factor se tienen que etiquetar con el comando levels. Se usa un vector con las etiquetas concatenadas, usando el comando c().

levels(lapop18$smedia1r) = c("Sí", "No")
levels(lapop18$smedia4r) = c("Sí", "No")
levels(lapop18$smedia7r) = c("Sí", "No")

Calcular las variables de usuarios de redes sociales

Como vimos en un módulo anterior, se puede calcular nuevas variables con valores condicionales de otras variables usando el comando ifelse. De esta manera, se crea las variables de usuarios de redes sociales.

lapop18$fb_user = ifelse(lapop18$smedia1==1 & lapop18$smedia2<=4, 1, 0)
lapop18$tw_user = ifelse(lapop18$smedia4==1 & lapop18$smedia5<=4, 1, 0)
lapop18$wa_user = ifelse(lapop18$smedia7==1 & lapop18$smedia8<=4, 1, 0)

Describir las variables

Con las variables listas, ahora procedemos a hacer las tablas generales con el comando table. Se puede notar el uso de # como forma de hacer anotaciones, que no son código en R.

table(lapop18$smedia1r) #Facebook
## 
##    Sí    No 
## 15389 11573
table(lapop18$smedia4r) #Twitter
## 
##    Sí    No 
##  2363 24558
table(lapop18$smedia7r) #Whatsapp
## 
##    Sí    No 
## 17446  9569

Este comando table nos brinda las frecuencias absolutas (número de observaciones) por cada categoría de las variables (en este caso Sí y No). Para obtener las frecuencias relativas, usaremos el comando prop.table, donde se anida el comando anterior table.

prop.table(table(lapop18$smedia1r))
## 
##        Sí        No 
## 0.5707663 0.4292337
prop.table(table(lapop18$smedia4r))
## 
##         Sí         No 
## 0.08777534 0.91222466
prop.table(table(lapop18$smedia7r))
## 
##        Sí        No 
## 0.6457894 0.3542106

Sin embargo, el comando prop.table nos devuelve demasiados decimales y las frecuencias relativas en una escala de 0 a 1. Para redondear esta cifra usamos el comando round, que nos permite especificar el número de decimales que se quiere mostrar. Tanto el comando table, como prop.table se anidan dentro de este nuevo comando. En este caso se ha usado 3 decimales, para cuando se multiplique por 100, quede en forma de porcentaje con 1 decimal.

round(prop.table(table(lapop18$smedia1r)), 3)*100
## 
##   Sí   No 
## 57.1 42.9
round(prop.table(table(lapop18$smedia4r)), 3)*100
## 
##   Sí   No 
##  8.8 91.2
round(prop.table(table(lapop18$smedia7r)), 3)*100
## 
##   Sí   No 
## 64.6 35.4

No es práctico presentar 3 tablas cuando las variables tienen las mismas categorías de respuesta. Para fines de presentación podría ser mejor construir una sola tabla. Se puede guardar las tablas parciales en nuevos objetos con el operador <- y luego unirlas como filas con el comando rbind en un nuevo dataframe “tabla”, de tal manera que las respuestas a cada red social aparezcan en filas.

Facebook = round(prop.table(table(lapop18$smedia1r)), 3)*100
Twitter = round(prop.table(table(lapop18$smedia4r)), 3)*100
Whatsapp = round(prop.table(table(lapop18$smedia7r)), 3)*100
tabla2 = as.data.frame(rbind(Facebook, Twitter, Whatsapp))
tabla2
##            Sí   No
## Facebook 57.1 42.9
## Twitter   8.8 91.2
## Whatsapp 64.6 35.4

Para tener una mejor presentación de la tabla, se puede usar el comando kable del paquete knitr, usando la tabla construida anteriormente.

library(knitr)
knitr::kable(tabla2, format="markdown")
No
Facebook 57.1 42.9
Twitter 8.8 91.2
Whatsapp 64.6 35.4

Graficar las variables

En el Gráfico 3.1 del reporte se observa que se reportan estos datos mediante un gráfico de sectores circulares.

Se puede reproducir ese gráfico usando el comando pie que es parte de la sintaxis básica de R. Dentro de este comando se puede anidar el comando table para graficar estos valores.

pie(table(lapop18$smedia1r))

También se podría pensar en un gráfico de barras. Usando los comandos básicos de R, se puede usar el comando barplot.

barplot(prop.table(table(lapop18$smedia1r)))

Estos comandos gráficos tienen opciones para adecuar el gráfico, por ejemplo, para incluir los porcentajes y adecuar las escalas.

Pero, como mencionamos más arriba, para tener más opciones gráficas, usaremos el paquete ggplot para reproducir el gráfico circular y a lo largo de estos módulos.

Lo primero que tenemos que hacer es crear una tabla que guarde los datos que queremos graficar sobre los usuarios de Facebook. Recordemos que tenemos una tabla con estos resultados donde la primera fila muestra las etiquetas “Sí” y “No” y la segunda fila los porcentajes. Requerimos que las etiquetas estén como columnas y los porcentajes también. Para esto tenemos que transponer la tabla, que significa “darle la vuelta”. Luego, esta nueva tabla la guardamos como un dataframe con el comando as.data.frame que crea tres columnas “Var1” (sin interés), “Var2” con las etiquetas y Freq con los porcentajes.

Face = as.data.frame(t(Facebook))
Face
##   Var1 Var2 Freq
## 1    A   Sí 57.1
## 2    A   No 42.9

Con esta tabla podemos crear un gráfico de barras como el visto más arriba. Otro tipo de barras que se usa frecuentemente es del tipo de barras apiladas al 100%.

Vamos a crear una barra apilada con estos resultados. A diferencia del gráfico de barras convencional, las barras apiladas requieren que en la aes(x="", y=Freq, fill=Var2). Es decir, que no haya etiquetas en el eje X, que el eje Y muestre los porcentajes (guardados en “Freq”) y que la barra esté separada por las categorías (guardadas en “Var2”).

Se agrega una capa de texto, con la especificación geom_text. Dentro de esta especificación se determina una “estética” con la etiqueta del dato aes(label=...), donde se junta con el comando paste el dato del porcentaje “per” y el símbolo “%”, con un espacio (sep=...) entre ellos. Se establece el color de la fuente con color="...". Se ajusta a blanco para que contraste con los colores del gráfico circular. Con el comando hjust=... se ajusta la posición horizontal de este texto. El comando ggplot puede incluir varios “temas” para el gráfico. En este caso se ha usado theme_void() que indica un fondo vacío. Finalmente, con la especificación scale_fill_discrete(name=...) se puede cambiar el título de la leyenda para que no aparezca el nombre de la variable, sino una etiqueta más adecuada.

ggplot(data=Face, aes(x="", y=Freq, fill=Var2))+
  geom_bar(width=1, stat="identity")+
  geom_text(aes(label=paste(Freq, "%", sep="")), color="white",
            position=position_stack(vjust=0.5), size=3)+
  theme_void()+
  scale_fill_discrete(name="¿Usa Facebook?")

Para crear un gráfico circular, no existe una “geometría” en ggplot. Sin embargo, para genera el gráfico circular, se tiene que agregar otro capa coord_polar, que transforma la barra a coordenadas polares, creando un gráfico circular. Todo el resto del código es similar al anterior.

ggplot(data=Face, aes(x="", y=Freq, fill=Var2))+
  geom_bar(width=1, stat="identity")+
  geom_text(aes(label=paste(Freq, "%", sep="")), color="white",
            position=position_stack(vjust=0.5), size=3)+
  coord_polar("y")+
  theme_void()+
  scale_fill_discrete(name="¿Usa Facebook?")

Si quisiéramos regresar a hacer un gráfico de barras, podemos incluir el texto de los valores con geom_text, el título general del gráfico con title dentro de labs, los nombres de los ejes y el “caption”.

ggplot(Face, aes(x=Var2, y=Freq))+
  geom_bar(stat="identity",  width=0.5)+
  geom_text(aes(label=paste(Freq, "%", sep="")), color="black", vjust=-0.5)+
  labs(title="¿Qué tan frecuente se usan las redes sociales?", 
       x="Usuario de Facebook", y="Porcentaje", 
       caption="Barómetro de las Américas por LAPOP, 2018/19")+
  coord_cartesian(ylim=c(0, 60))

Resumen

En este documento se ha trabajado con variables categóricas nominales, como apoyo a la democracia o si usa o no usa redes sociales. Se ha presentando las formas de cómo describir en tablas de frecuencia y cómo graficar estas variables, mediante gráficos circulares o de barras.

Cálculos incluyendo el efecto de diseño

Estos últimos resultados de la ronda 2018/19 no son exactamente iguales a los del reporte pues LAPOP incluye el efecto del diseño muestral en sus cálculos. Según esta sintaxis, se encuentra que el 57.1% de entrevistados reporta ser usuario de Facebook, cuando en el reporte aparece 56.2%. Lo mismo con Twitter, que aquí se calcula en 8.8% y en el reporte 7.9%; y con Whatsapp que aquí aparece con 64.6% y en el reporte con 64.4%. Como se indicó en el documento sobre el uso de los factores de expansión usando los datos del Barómetro de las Américas (disponible aquí), hay varias maneras de reproducir los resultados incorporando el efecto de diseño. Una primera opción es usar el comando freq que permite la inclusión de una variable de factor de expansión, como “weight1500”. Se incluye la especificación plot=F para no producir los gráficos de barras.

library(descr)
descr::freq(lapop18$fb_user, lapop18$weight1500, plot = F)
## lapop18$fb_user 
##       Frequency Percent Valid Percent
## 0         11337  41.988         43.77
## 1         14564  53.939         56.23
## NA's       1100   4.073              
## Total     27000 100.000        100.00
descr::freq(lapop18$tw_user, lapop18$weight1500, plot = F)
## lapop18$tw_user 
##       Frequency Percent Valid Percent
## 0         23819  88.220        92.023
## 1          2065   7.647         7.977
## NA's       1116   4.133              
## Total     27000 100.000       100.000
descr::freq(lapop18$wa_user, lapop18$weight1500, plot = F)
## lapop18$wa_user 
##       Frequency Percent Valid Percent
## 0          9252  34.266         35.63
## 1         16714  61.903         64.37
## NA's       1035   3.832              
## Total     27000 100.000        100.00

Sin considerar el efecto de diseño, se tiene que 57.1% de entrevistados cuenta con una cuenta de Facebook. Este porcentaje varía a 55.2% si se incluye la variable de expansión, que es el valor que se muestra en el reporte. Estos resultados ponderados también se pueden guardar en objetos y luego graficar de la misma manera que se ha hecho con los resultados sin ponderar.

Para el caso de Facebook, la tabla se puede guardar como un dataframe, usando el comando as.data.frame. Esta tabla incluye datos que no requerimos, como la fila de NA´s y del total y como la columna de Percent. Estas filas y esta columna se borran usando la especificación [-c(3,4), -2].

Luego, se le cambia el nombre a las columnas para evitar el nombre “Valid Percent”. Se las nombre simplemente como “freq” y “per”. Esta columna “per” es la que tiene los datos que graficaremos. Finalmente, se añade una columna “lab” con las etiquetas de cada fila de resultados.

fb = as.data.frame(descr::freq(lapop18$fb_user, lapop18$weight1500, 
                               plot = F))
fb = fb[-c(3,4), -2]
colnames(fb) = c("freq", "per")
fb$lab = c("No", "Sí")
fb
##       freq      per lab
## 0 11336.69 43.77052  No
## 1 14563.60 56.22948  Sí

Con este nuevo dataframe podemos replicar los mismo códigos usados más arriba para hacer un gráfico de barras o un gráfico circular. El siguiente código muestra el gráfico de barras. Nótese que ahora se usa el dataframe “fb” y que en aes se especifica que en el eje X deben estar los datos de la columna “lab” y en el eje Y los datos de la columna “per”.

ggplot(data=fb, aes(x=lab, y=per))+
  geom_bar(stat="identity",  width=0.5)+
  geom_text(aes(label=paste(round(per, 1), "%", sep="")), 
            color="black", vjust=-0.5)+
  labs(title="¿Qué tan frecuente se usan las redes sociales?", 
       x="Usuario de Facebook", y="Porcentaje", 
       caption="Barómetro de las Américas por LAPOP, 2018/19")+
  coord_cartesian(ylim=c(0, 60))

Esto mismo se puede hacer para crear un gráfico circular. Este gráfico reproduce los resultados hallados en el Gráfico 3.1 del reporte.

ggplot(data=fb, aes(x=2, y=per, fill=lab))+
  geom_bar(stat="identity")+
  geom_text(aes(label=paste(round(per, 1), "%", sep="")), color="white", 
            position=position_stack(vjust=0.5), size=3)+
  coord_polar("y")+
  theme_void()+
  labs(title="¿Qué tan frecuente se usan las redes sociales?", 
       caption="Barómetro de las Américas por LAPOP, 2018/19")+
  scale_fill_discrete(name="¿Usa Facebook?")+
  xlim(0.5, 2.5)

La segunda opción para reproducir los datos del reporte exactamente es mediante el paquete survey. Como se indicó en esta sección, primero se tiene que definir el diseño muestral con el comando svydesign.

library(survey)
diseno18 = svydesign(ids = ~upm, strata = ~estratopri, 
                     weights = ~weight1500, nest=TRUE, data=lapop18)

Una vez creado los datos con el factor de expansión en el objeto “diseno18”, se puede usar los comandos nativos del paquete survey para realizar cálculos. Por ejemplo, para calcular la tabla de distribución de frecuencias se puede usar el comando svytable.

svytable(~fb_user, design=diseno18)
## fb_user
##        0        1 
## 11336.69 14563.60

Estas frecuencias se pueden anidar en el comando prop.table para calcular los porcentajes de usuarios de redes sociales. Estos resultados son iguales a los mostrados en los gráficos anteriores y a los que aparecen en el reporte.

Estos datos también se pueden guardar en un dataframe que se adapta para graficar, siguiendo el mismo procedimiento que en los gráficos anteriores.

prop.table(svytable(~fb_user, design=diseno18))
## fb_user
##         0         1 
## 0.4377052 0.5622948
prop.table(svytable(~tw_user, design=diseno18))
## tw_user
##          0          1 
## 0.92023002 0.07976998
prop.table(svytable(~wa_user, design=diseno18))
## wa_user
##         0         1 
## 0.3563091 0.6436909
LS0tCnRpdGxlOiAiRXN0YWTDrXN0aWNhIGRlc2NyaXB0aXZhIHVzYW5kbyBlbCBCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgKDEpIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICB0b2NfZGVwdGg6IDEKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBmbGF0bHkKICAgICNjb2RlX2ZvbGRpbmc6IGhpZGUKZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IHNlbnRlbmNlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUUpCmBgYAoKYGBge2NzcyBjb2xvciwgZWNobz1GQUxTRX0KLmNvbHVtbnMge2Rpc3BsYXk6IGZsZXg7fQpoMSB7Y29sb3I6ICMzMzY2Q0M7fQpgYGAKCiMgSW50cm9kdWNjacOzbgoKRW4gZXN0ZSBkb2N1bWVudG8gZW1wZXphcmVtb3MgY29uIGxvcyBhc3BlY3RvcyBiw6FzaWNvcyBkZSBjw7NtbyB1c2FyIGxhIGJhc2UgZGUgZGF0b3MgZGVsIEJhcsOzbWV0cm8gZGUgbGFzIEFtw6lyaWNhcyBkZSBMQVBPUCBwYXJhIGZpbmVzIGVzdGFkw61zdGljb3MuCkVuIHByaW1lciBsdWdhciwgdmVyZW1vcyBhc3BlY3RvcyBiw6FzaWNvcyBkZSBjw7NtbyBkZXNjcmliaXIgdW5hIHZhcmlhYmxlIG1lZGlhbnRlIHVuYSB0YWJsYSBkZSBkaXN0cmlidWNpw7NuIGRlIGZyZWN1ZW5jaWFzIHkgY8OzbW8gZ3JhZmljYXIgZXNhIHZhcmlhYmxlIG1lZGlhbnRlIGdyw6FmaWNvcyBjaXJjdWxhcmVzIG8gZGUgYmFycmFzLgpQYXJhIGVzbywgdmFtb3MgYSB1c2FyIGxvcyBpbmZvcm1lcyByZWdpb25hbGVzICJFbCBwdWxzbyBkZSBsYSBkZW1vY3JhY2lhIiwgY29uIGxvcyByZXN1bHRhZG9zIGRlIGxhIHJvbmRhIDIwMjEsIGRpc3BvbmlibGUgW2FxdcOtXShodHRwczovL3d3dy52YW5kZXJiaWx0LmVkdS9sYXBvcC9hYjIwMjEvMjAyMV9MQVBPUF9BbWVyaWNhc0Jhcm9tZXRlcl8yMDIxX1B1bHNlX29mX0RlbW9jcmFjeS5wZGYpLCB5IGNvbiBsb3MgcmVzdWx0YWRvcyBkZSBsYSByb25kYSAyMDE4LzE5LCBkaXNwb25pYmxlIFthcXXDrV0oaHR0cHM6Ly93d3cudmFuZGVyYmlsdC5lZHUvbGFwb3AvYWIyMDE4LzIwMTgtMTlfQW1lcmljYXNCYXJvbWV0ZXJfUmVnaW9uYWxfUmVwb3J0X1NwYW5pc2hfV18wMy4yNy4yMC5wZGZ4KS4KClVubyBkZSBsb3MgcmVzdWx0YWRvcyBtw6FzIHJlbGV2YW50ZXMgZW4gbGEgcm9uZGEgMjAyMSBwcmVzZW50YSBsb3MgcmVzdWx0YWRvcyBzb2JyZSBhcG95byBhIGxhIGRlbW9jcmFjaWEgZW4gbGEgcmVnacOzbi4KUGFyYSBsYSByb25kYSAyMDE4LzE5LCB1bmEgZGUgbGFzIHNlY2Npb25lcyBkZSBlc3RlIGluZm9ybWUsIHJlcG9ydGEgbG9zIGRhdG9zIHNvYnJlIHJlZGVzIHNvY2lhbGVzIHkgYWN0aXR1ZGVzIHBvbMOtdGljYXMuCkVuIGVzdGEgc2VjY2nDs24sIHNlIHByZXNlbnRhbiBkYXRvcyBzb2JyZSBlbCB1c28gZGUgaW50ZXJuZXQgeSBlbCB1c28gZGUgcmVkZXMgc29jaWFsZXMsIGVuIGdlbmVyYWwgeSBwb3IgcGHDrXMuCkNvbiBsb3MgZGF0b3MgZGVsIEJhcsOzbWV0cm8gZGUgbGFzIEFtw6lyaWNhcyBzZSBwdWVkZSBzYWJlciBlbCBwb3JjZW50YWplIGRlIGhvZ2FyZXMgY29uIGFjY2VzbyBhIGNlbHVsYXJlcywgY29uIGFjY2VzbyBhIGludGVybmV0LCBhc8OtIGNvbW8gZWwgcG9yY2VudGFqZSBkZSBwZXJzb25hcyBxdWUgdXNhIFdoYXRzYXBwLCBGYWNlYm9vayBvIFR3aXR0ZXIuCkVuIGVzdGUgZG9jdW1lbnRvIHZhbW9zIGEgcmVwYXNhciBlc3RvcyByZXN1bHRhZG9zLgoKIyBTb2JyZSBsYSBiYXNlIGRlIGRhdG9zCgpMb3MgZGF0b3MgcXVlIHZhbW9zIGEgdXNhciBkZWJlbiBjaXRhcnNlIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6IEZ1ZW50ZTogQmFyw7NtZXRybyBkZSBsYXMgQW3DqXJpY2FzIHBvciBlbCBQcm95ZWN0byBkZSBPcGluacOzbiBQw7pibGljYSBkZSBBbcOpcmljYSBMYXRpbmEgKExBUE9QKSwgd3d3dy5MYXBvcFN1cnZleXMub3JnLgpFbiBlc3RlIGRvY3VtZW50byBzZSBjYXJnYSBudWV2YW1lbnRlIGRlc2RlIGNlcm8gdW5hIGJhc2UgZGUgZGF0b3MgcmVjb3J0YWRhLgpTZSByZWNvbWllbmRhIG51ZXZhbWVudGUgbGltcGlhciBlbCBFbnZpcm9ubWVudCBkZSBsb3Mgb2JqZXRvcyB1c2Fkb3MgZW4gbcOzZHVsb3MgYW50ZXJpb3Jlcy4KCkVzdGEgYmFzZSBkZSBkYXRvcyBzZSBlbmN1ZW50cmEgYWxvamFkYSBlbiBlbCByZXBvc2l0b3JpbyAibWF0ZXJpYWxzX2VkdSIgZGUgbGEgY3VlbnRhIGRlIExBUE9QIGVuIEdpdEh1Yi4KTWVkaWFudGUgbGEgbGlicmVyw61hIGByaW9gIHkgZWwgY29tYW5kbyBgaW1wb3J0YCBzZSBwdWVkZSBpbXBvcnRhciBlc3RhIGJhc2UgZGUgZGF0b3MgZGVzZGUgZXN0ZSByZXBvc2l0b3Jpby4KQWRlbcOhcywgc2Ugc2VsZWNjaW9uYW4gbG9zIGRhdG9zIGRlIHBhw61zZXMgY29uIGPDs2RpZ29zIG1lbm9yZXMgbyBpZ3VhbGVzIGEgMzUsIGVzIGRlY2lyLCBzZSBlbGltaW5hbiBsYXMgb2JzZXJ2YWNpb25lcyBkZSBFc3RhZG9zIFVuaWRvcyB5IENhbmFkw6EuCgpgYGB7ciBiYXNlLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHJpbykKbGFwb3AxOCA9IGltcG9ydCgiaHR0cHM6Ly9yYXcuZ2l0aHViLmNvbS9sYXBvcC1jZW50cmFsL21hdGVyaWFsc19lZHUvbWFpbi9MQVBPUF9BQl9NZXJnZV8yMDE4X3YxLjAuc2F2IikKbGFwb3AxOCA9IHN1YnNldChsYXBvcDE4LCBwYWlzPD0zNSkKYGBgCgpUYW1iacOpbiBjYXJnYW1vcyBsYSBiYXNlIGRlIGRhdG9zIGRlIGxhIHJvbmRhIDIwMjEuCgpgYGB7ciBiYXNlMjF9CmxhcG9wMjEgPSBpbXBvcnQoImh0dHBzOi8vcmF3LmdpdGh1Yi5jb20vbGFwb3AtY2VudHJhbC9tYXRlcmlhbHNfZWR1L21haW4vbGFwb3AyMS5SRGF0YSIpCmxhcG9wMjEgPSBzdWJzZXQobGFwb3AyMSwgcGFpczw9MzUpCmBgYAoKIyBBcG95byBhIGxhIGRlbW9jcmFjaWEKCkVuIGVsIHJlcG9ydGUgZGUgRWwgUHVsc28gZGUgbGEgRGVtb2NyYWNpYSAyMDIxIHNlIHByZXNlbnRhIGxvcyByZXN1bHRhZG9zIGRlbCBhcG95byBhIGxhIGRlbW9jcmFjaWEgcG9yIHBhw61zLgpFbCBncsOhZmljbyAxLjEgbXVlc3RyYSBlbCBwb3JjZW50YWplIGRlIHBlcnNvbmFzIGVuIGNhZGEgcGHDrXMgcXVlIGFwb3lhIGEgbGEgZGVtb2NyYWNpYSBlbiBhYnN0cmFjdG8uCgohW10oR3JhZmljbzEuMS5wbmcpCgpFbiBsb3MgbcOzZHVsb3MgYW50ZXJpb3JlcyBzZSB2aW8gY8OzbW8gcmVjb2RpZmljYXIgbGEgdmFyaWFibGUgSU5HNCwgbWVkaWRhIG9yaWdpbmFsbWVudGUgZW4gdW5hIGVzY2FsYSBkZWwgMSBhbCA3LCBkb25kZSAxIHNpZ25pZmljYSAibXV5IGVuIGRlc2FjdWVyZG8iIHkgNyBzaWduaWZpY2EgIm11eSBkZSBhY3VlcmRvIi4KTG9zIHZhbG9yZXMgZW50cmUgNSBhIDcgc29uIHJlY29kaWZpY2Fkb3MgY29tbyAiMSIsIHF1ZSBpZGVudGlmaWNhIGEgYXF1ZWxsb3MgcXVlIGFwb3lhbiBhIGxhIGRlbW9jcmFjaWEuCkVsIHJlc3RvIHNlIHJlY29kaWZpY2EgY29tbyAiMCIsIGFxdWVsbG9zIHF1ZSBubyBhcG95YW4gYSBsYSBkZW1vY3JhY2lhLgpFc3RhIHJlY29kaWZpY2FjacOzbiBzZSBndWFyZGEgZW4gdW5hIG51ZXZhIHZhcmlhYmxlICJpbmc0cmVjIi4KCmBgYHtyIGFwb3lvfQpsaWJyYXJ5KGNhcikKbGFwb3AyMSRpbmc0cmVjID0gY2FyOjpyZWNvZGUobGFwb3AyMSRpbmc0LCAiMTo0PTA7IDU6Nz0xIikKYGBgCgpFbiBzZW50aWRvIGVzdHJpY3RvLCBlc3RhIHZhcmlhYmxlIG5vIGVzIG51bcOpcmljYSwgYSBwZXNhciBxdWUgZXN0w6EgZGVmaW5pZGEgZW4gbGEgYmFzZSBkZSBkYXRvcyBjb21vICJkYmwiLCBxdWUgZXMgdW4gdGlwbyBkZSB2YXJpYWJsZSBudW3DqXJpY2EuCkVzdGEgdmFyaWFibGUgZXMgZGUgdGlwbyBjdWFsaXRhdGl2bywgbm9taW5hbCwgcXVlIGVuIFIgc2UgZGVmaW5lIGNvbW8gZmFjdG9yLgpQYXJhIHRlbmVyIGNvcnJlY3RhbWVudGUgZGVmaW5pZGEgeSBldGlxdWV0YWRhIGVzdGEgdmFyaWFibGUsIHNlIHRpZW5lIHF1ZSB0cmFuc2Zvcm1hci4KRW4gcHJpbWVyIGx1Z2FyIHNlIGRlZmluZSBjb21vIGZhY3RvciBjb24gZWwgY29tYW5kbyBgYXMuZmFjdG9yYC4KCmBgYHtyIGFwb3lvIHJlY30KbGFwb3AyMSRpbmc0cmVjID0gYXMuZmFjdG9yKGxhcG9wMjEkaW5nNHJlYykKYGBgCgpVbmEgdmFyaWFibGUgZGUgdGlwbyBmYWN0b3IgcHVlZGUgdGVuZXIgZXRpcXVldGFzIHBvciBjYWRhIGPDs2RpZ28gbnVtw6lyaWNvLgpMYSBkZWZpbmljacOzbiBkZSBldGlxdWV0YXMgdGllbmUgZWwgb2JqZXRpdm8gcXVlIGVuIGN1YWxxdWllciB0YWJsYSBvIGdyw6FmaWNvIG5vIGFwYXJlemNhIGVsIGPDs2RpZ28gbnVtw6lyaWNvLCBzaW5vIGxhIGV0aXF1ZXRhIGNvcnJlc3BvbmRpZW50ZS4KRXN0byBzZSBoYWNlIHVzYW5kbyBlbCBjb21hbmRvIGBsZXZlbHNgLgpMdWVnbywgZXN0YSB2YXJpYWJsZSBzZSBwdWVkZSBkZXNjcmliaXIgY29uIGVsIGNvbWFuZG8gYHRhYmxlYCwgcXVlIG5vcyBicmluZGEgbGFzIGZyZWN1ZW5jaWFzIGFic29sdXRhcyBwb3IgY2FkYSBjYXRlZ29yw61hIGRlIGxhIHZhcmlhYmxlLgoKYGBge3IgYXBveW8gbGFiZWxzfQpsZXZlbHMobGFwb3AyMSRpbmc0cmVjKSA9IGMoIk5vIiwgIlPDrSIpCnRhYmxlKGxhcG9wMjEkaW5nNHJlYykKYGBgCgojIyBEZXNjcmliaXIgbGEgdmFyaWFibGUKCkNvbW8gdmltb3MgZW4gZWwgbcOzZHVsbyBzb2JyZSBNYW5lam8gZGUgRGF0b3MsIHNlIHB1ZWRlIHVzYXIgZWwgY29tYW5kbyBgcHJvcC50YWJsZWAgcGFyYSB0ZW5lciBsYXMgZnJlY3VlbmNpYXMgcmVsYXRpdmFzIHkgZWwgY29tYW5kbyBgcm91bmRgIHBhcmEgbW9zdHJhciBzb2xvIHVuIGRlY2ltYWwuCgpgYGB7ciBhcG95byBkZXNjfQpyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkaW5nNHJlYykpKjEwMCwgMSkKYGBgCgpFc3RlIGdyw6FmaWNvIG11ZXN0cmEgbG9zIHJlc3VsdGFkb3MgZGUgbGFzIDIgY2F0ZWdvcsOtYXMgZGVmaW5pZGFzIGRlIGxhIHZhcmlhYmxlIGRlIGFwb3lvIGEgbGEgZGVtb2NyYWNpYS4KU2luIGVtYmFyZ28sIGVzdGEgdmFyaWFibGUgdGllbmUgdmFsb3JlcyBwZXJkaWRvcy4KUGFyYSBwb2RlciB0ZW5lciB1bmEgdGFibGEgY29uIGxvcyB2YWxvcmVzIHBlcmRpZG9zLCBzZSBwdWVkZSB1c2FyIGVsIGNvbWFuZG8gYHRhYmxlYCBjb24gbGEgZXNwZWNpZmljYWNpw7NuIGB1c2VOQSA9ICJhbHdheXMiYC4KCmBgYHtyIGFwb3lvIHJvdW5kfQpyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkaW5nNHJlYywgdXNlTkEgPSAiYWx3YXlzIikpKjEwMCwgMSkKYGBgCgpFbiBlc3RhIHRhYmxhIHNlIHZlIHF1ZSBleGlzdGUgdW4gNi40JSBkZSBjYXNvcyBwZXJkaWRvcyBkZWwgdG90YWwgZGUgb2JzZXJ2YWNpb25lcy4KTGEgcHJlc2VudGFjacOzbiBkZSB2YWxvcmVzIHBlcmRpZG9zIGVuIHRhYmxhcyBvIGdyw6FmaWNvcyBkZXBlbmRlIGRlbCBpbnZlc3RpZ2Fkb3IuCkFxdcOtIHZhbW9zIGEgcHJlc2VudGFyIGxvcyBncsOhZmljb3Mgc29icmUgbG9zIGRhdG9zIHbDoWxpZG9zLgoKIyMgR3JhZmljYXIgbGEgdmFyaWFibGUKClVuYSB2YXJpYWJsZSBkZSB0aXBvICJmYWN0b3IiIHNlIHB1ZWRlIGdyYWZpY2FyIGRlIHZhcmlhcyBtYW5lcmFzLgpVbmEgcG9zaWJpbGlkYWQgZXMgdGVuZXIgdW4gZ3LDoWZpY28gY2lyY3VsYXIuClNlIHB1ZWRlIHVzYXIgZWwgY29tYW5kbyBgcGllYCBxdWUgZXMgcGFydGUgZGUgbGEgc2ludGF4aXMgYsOhc2ljYSBkZSBSLgpEZW50cm8gZGUgZXN0ZSBjb21hbmRvIHNlIHB1ZWRlIGFuaWRhciBlbCBjb21hbmRvIGB0YWJsZWAgcGFyYSBncmFmaWNhciBlc3RvcyB2YWxvcmVzLgoKYGBge3IgcGllfQpwaWUodGFibGUobGFwb3AyMSRpbmc0cmVjKSkKYGBgCgpFc3RlIGdyw6FmaWNvIHRpZW5lIGFsZ3VuYXMgb3BjaW9uZXMgZGUgcGVyc29uYWxpemFjacOzbi4KUG9yIGVqZW1wbG8sIGxhIGVzcGVjaWZpY2FjacOzbiBgbGFiZWxzPeKApmAgc2lydmUgcGFyYSBpbmNsdWlyIGVsIG7Dum1lcm8gZGUgY2Fzb3MgZGUgY2FkYSBzZWN0b3IgeSBsYSBlc3BlY2lmaWNhY2nDs24gYGNvbD3igKZgIHNpcnZlIHBhcmEgZGVmaW5pciBsb3MgY29sb3JlcyBkZSBsb3Mgc2VjdG9yZXMuCgpgYGB7ciBwaWUgY29sb3J9CnBpZSh0YWJsZShsYXBvcDIxJGluZzRyZWMpLCBsYWJlbHM9dGFibGUobGFwb3AyMSRpbmc0cmVjKSwgY29sPTE6MikKYGBgCgpPdHJhIG9wY2nDs24gZXMgdXNhciB1biBncsOhZmljbyBkZSBiYXJyYXMuClVzYW5kbyBsb3MgY29tYW5kb3MgYsOhc2ljb3MgZGUgUiwgc2UgcHVlZGUgdXNhciBlbCBjb21hbmRvIGBiYXJwbG90YC4KCmBgYHtyIGJhcnJhfQpiYXJwbG90KHByb3AudGFibGUodGFibGUobGFwb3AyMSRpbmc0cmVjKSkqMTAwLCBjb2w9MToyKQpgYGAKCkxvcyBjb21hbmRvIGRlIGJhc2UgZGUgUiB0aWVuZW4gdW4gbml2ZWwgZGUgcGVyc29uYWxpemFjacOzbiwgcGVybyBleGlzdGUgdW5hIGxpYnJlcsOtYSBlc3BlY2lhbGl6YWRhIHBhcmEgaGFjZXIgZ3LDoWZpY29zIGxsYW1hZGEgYGdncGxvdGAgY29uIG3DoXMgb3BjaW9uZXMgZ3LDoWZpY2FzLgpFbiBlc3RhIHNlcmllIGRlIG3Ds2R1bG9zIHZhbW9zIGEgdXNhciBlc3RhIGxpYnJlcsOtYS4KClBvciBlamVtcGxvLCBwYXJhIHJlcHJvZHVjaXIgdW4gZ3LDoWZpY28gZGUgYmFycmFzIGRlIGxhIHZhcmlhYmxlIGRlIGFwb3lvIGEgbGEgZGVtb2NyYWNpYSBzZSBsbGFtYSBhIGxhIGxpYnJlcsOtYSBgZ2dwbG90MmAuClBhcmEgZ3JhZmljYXIgbG9zIGRhdG9zIGRlIHVuYSB2YXJpYWJsZSBkZSB0aXBvIGZhY3RvciwgdGVuZW1vcyBkb3Mgb3BjaW9uZXM6IGhhY2VybG8gZGVzZGUgbGEgbWlzbWEgYmFzZSBkZSBkYXRvcyBvcmlnaW5hbCBvIGNyZWFyIHVuIG51ZXZvIG9iamV0byBxdWUgZ3VhcmRlIGxvcyByZXN1bHRhZG9zIGVuIHVuYSB0YWJsYS4KCkVuIGVzdGUgZWplbXBsbyBwYXJ0aXJlbW9zIGRlIGxhIHNlZ3VuZGEgb3BjacOzbiBwb3Igc2VyIG3DoXMgc2ltcGxlLgpMbyBwcmltZXJvIHF1ZSB0ZW5lbW9zIHF1ZSBoYWNlciBlcyBndWFyZGFyIGxhIHRhYmxhIGVuIHVuIG9iamV0bywgY29tbyB1biBkYXRhZnJhbWUuClBhcmEgZXN0byB1c2Ftb3MgZWwgY29tYW5kbyBgYXMuZGF0YS5mcmFtZWAgZG9uZGUgYW5pZGFtb3MgZWwgY8OzZGlnbyBwYXJhIHByb2R1Y2lyIGxhIHRhYmxhLgpFc3RlIGNvbWFuZG8gY3JlYSBkb3MgY29sdW1uYSwgIlZhcjEiIHF1ZSBndWFyZGEgbGFzIGV0aXF1ZXRhcyB5ICJGcmVxIiBxdWUgZ3VhcmRhIGVsIHZhbG9yIGRlIGxvcyBwb3JjZW50YWplcy4KCmBgYHtyIHRhYmxhMX0KdGFibGExID0gYXMuZGF0YS5mcmFtZShyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkaW5nNHJlYykpKjEwMCwgMSkpCnRhYmxhMQpgYGAKCkx1ZWdvLCB0ZW5lbW9zIHF1ZSBkZWZpbmlyIHNvbiBsb3MgZGF0b3MgcXVlIHNlIHZhbiBhIHVzYXIgY29uIGxhIGVzcGVjaWZpY2FjacOzbiBgZGF0YT10YWJsYTFgLgpPam8sIG5vIHVzYXJlbW9zIGxhIGJhc2UgZGUgZGF0b3Mgb3JpZ2luYWwgImxhcG9wMjEiLCBzaW5vIGxhICJ0YWJsYTEiIGRvbmRlIGhlbW9zIGd1YXJkYWRvIGxvcyByZXN1bHRhZG9zLgoKRWwgY29tYW5kbyBgZ2dwbG90YCB0cmFiYWphIHN1bWFuZG8gY2FwYXMuCkxhIGVzcGVjaWZpY2FjacOzbiBgYWVzYCBzaXJ2ZSBwYXJhIGRlZmluaXIgbGEgImVzdMOpdGljYSIgZGVsIGdyw6FmaWNvLgpHZW5lcmFsbWVudGUgc2UgdXNhIHBhcmEgaW5kaWNhciBxdcOpIHZhcmlhYmxlIHNlIHZhIGEgZ3JhZmljYXIgZW4gcXXDqSBlamUgKHggbyB5KS4KVGFtYmnDqW4gc2UgcHVlZGUgdXNhciBsYSBlc3BlY2lmaWNhY2nDs24gYGZpbGw9YCBwYXJhIGRlZmluaXIgbG9zIGdydXBvcyBxdWUgc2UgdmFuIGEgZ2VuZXJhci4KRW4gZXN0ZSBjYXNvLCBlbiBlbCBlamUgWCBxdWVyZW1vcyBsYXMgY2F0ZWdvcsOtYXMgIlPDrSIgeSAiTm8iIHkgZW4gZWwgZWplIFksIGxvcyBkYXRvcyBkZSAiRnJlcSIuCgpMdWVnbyBkZSBlc3BlY2lmaWNhciBsb3MgZGF0b3MgeSBsb3MgZWplcywgc2UgdGllbmUgcXVlIGVzcGVjaWZpY2FyIGVsIHRpcG8gZGUgZ3LDoWZpY28gcXVlIHNlIHF1aWVyZSByZWFsaXphci4KRXN0byBzZSBoYWNlIGNvbiBsYXMgZ2VvbWV0csOtYXMgKCJnZW9tX3h4eCIpLgpTZSBkZWZpbmUgdW4gZ3LDoWZpY28gZGUgYmFycmFzIHNpbXBsZSwgdXNhbmRvIGVsIGNvbWFuZG8gYGdlb21fYmFyKC4uLilgLCBkb25kZSBpbnRlcm5hbWVudGUgZXNwZWNpZmljYW1vcyBgc3RhdD0iaWRlbnRpdHkiYCBwYXJhIHF1ZSBlc3RlIGNvbWFuZG8gdHJhYmFqZSBjb24gbG9zIGRhdG9zIHRhbCBjdWFsIGVzdMOhbiBlbiBsYSB0YWJsYS4KVGFtYmnDqW4gc2UgZGVmaW5lIGVsIGFuY2hvIGRlIGxhIGJhcnJhIGNvbiBsYSBlc3BlY2lmaWNhY2nDs24gYHdpZHRoYC4KQ29uIGxhIGVzcGVjaWZpY2FjacOzbiBgbGFic2Agc2UgZGVmaW5lIGxhcyBldGlxdWV0YXMgZGUgZWplcyB5IGVsICJjYXB0aW9uIi4KRmluYWxtZW50ZSwgY29uIGxhIGVzcGVjaWZpY2FjacOzbiBgY29vcmRfY2FydGVzaWFuYCBzZSBkZWZpbmUgbG9zIGzDrW1pdGVzIGRlbCBlamUgWSBkZSAwIGEgODAuClNlIGRlYmUgbm90YXIgcXVlIGVsIGdyw6FmaWNvIG5vIHByZXNlbnRhIHVuYSBjb2x1bW5hIHBhcmEgZWwgcG9yY2VudGFqZSBkZSB2YWxvcmVzIHBlcmRpZG9zLgpQcmVzZW50YXIgZXN0YSBjb2x1bW5hIGVzIG9wY2nDs24gZGVsIGludmVzdGlnYWRvci4KCmBgYHtyIGdnIHRhYmxhfQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdChkYXRhPXRhYmxhMSwgYWVzKHg9VmFyMSwgeT1GcmVxKSkrCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoPTAuNSkrCiAgbGFicyh4PSJBcG95byBhIGxhIGRlbW9jcmFjaWEiLCB5PSJQb3JjZW50YWplIiwgCiAgICAgICBjYXB0aW9uPSJCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgcG9yIExBUE9QLCAyMDIxIikrCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCA4MCkpCmBgYAoKSGFzdGEgYXF1w60gc2UgaGEgcHJlc2VudGFkbyB1biBncsOhZmljbyBkZSBiYXJyYXMgZGUgbGEgdmFyaWFibGUgYXBveW8gYSBsYSBkZW1vY3JhY2lhIHBhcmEgdG9kYSBsYSBtdWVzdHJhLCBxdWUgaW5jbHV5ZSBhIHRvZG9zIGxvcyBwYcOtc2VzLgpFbCBncsOhZmljbyAxLjEgbXVlc3RyYSBlbCBwb3JjZW50YWplIHF1ZSBhcG95YSBhIGxhIGRlbW9jcmFjaWEgcG9yIHBhw61zLgpFc3RlIHRpcG8gZGUgZ3LDoWZpY28gc2UgdmVyw6EgbcOhcyBhZGVsYW50ZS4KCiMgVXN1YXJpb3MgZGUgcmVkZXMgc29jaWFsZXMKCkFob3JhIHNlIHVzYXLDoSB1biBlamVtcGxvIGRlbCByZXBvcnRlIEVsIFB1bHNvIGRlIGxhIERlbW9jcmFjaWEgZGUgbGEgcm9uZGEgMjAxOC8xOS4KU2Ugc2VndWlyw6EgcHJvY2VkaW1pZW50b3Mgc2ltaWxhcmVzIGEgbGEgc2VjY2nDs24gYW50ZXJpb3IgeSBzZSByZXBsaWNhcsOhbiBhbGd1bm9zIGdyw6FmaWNvcyBkZWwgbWlzbW8gcmVwb3J0ZSBkZSBlc2Egcm9uZGEuCkxhcyB2YXJpYWJsZXMgY29uIGxhcyBxdWUgc2UgdHJhYmFqYXLDoSBzb246IFNNRURJQTEuCsK/VGllbmUgdXN0ZWQgY3VlbnRhIGRlIEZhY2Vib29rPzsKU01FRElBNC4Kwr9UaWVuZSB1c3RlZCBjdWVudGEgZGUgVHdpdHRlcj87ClNNRURJQTcuCsK/VGllbmUgdXN0ZWQgY3VlbnRhIGRlIFdoYXRzYXBwPy4KRXN0YXMgcHJlZ3VudGFzIHRpZW5lbiBjb21vIG9wY2lvbmVzIGRlIHJlc3B1ZXN0YToKCjEuICBTw60KCjIuICBObwoKQWwgbW9tZW50byBkZSBsZWVyIGxhIGJhc2UgZGUgZGF0b3MgZW4gUiwgZXN0ZSBwcm9ncmFtYSBpbXBvcnRhIGxhcyB2YXJpYWJsZXMgY29tbyAibnVtIiwgcXVlIGxhIG1heW9yw61hIGRlIGZ1bmNpb25lcyBlbiBSIHRyYXRhIGNvbW8gbnVtw6lyaWNhcy4KRXN0YXMgdmFyaWFibGVzIHNlIHRpZW5lbiBxdWUgY29udmVydGlyIGEgdmFyaWFibGVzIGRlIHRpcG8gImZhY3RvciIgY29uIGVsIGNvbWFuZG8gYGFzLmZhY3RvcmAsIHB1ZXMgc29uIHZhcmlhYmxlcyBjYXRlZ8OzcmljYXMuCkVzdGEgbnVldmFzIHZhcmlhYmxlcyBsYXMgZ3VhcmRhbW9zIGVuIGVsIGRhdGFmcmFtZS4KCmBgYHtyIGZhY3Rvcn0KbGFwb3AxOCRzbWVkaWExciA9IGFzLmZhY3RvcihsYXBvcDE4JHNtZWRpYTEpCmxhcG9wMTgkc21lZGlhNHIgPSBhcy5mYWN0b3IobGFwb3AxOCRzbWVkaWE0KQpsYXBvcDE4JHNtZWRpYTdyID0gYXMuZmFjdG9yKGxhcG9wMTgkc21lZGlhNykKYGBgCgpFc3RhcyBudWV2YXMgdmFyaWFibGVzIGRlIHRpcG8gZmFjdG9yIHNlIHRpZW5lbiBxdWUgZXRpcXVldGFyIGNvbiBlbCBjb21hbmRvIGBsZXZlbHNgLgpTZSB1c2EgdW4gdmVjdG9yIGNvbiBsYXMgZXRpcXVldGFzIGNvbmNhdGVuYWRhcywgdXNhbmRvIGVsIGNvbWFuZG8gYGMoKWAuCgpgYGB7ciBldGlxdWV0YX0KbGV2ZWxzKGxhcG9wMTgkc21lZGlhMXIpID0gYygiU8OtIiwgIk5vIikKbGV2ZWxzKGxhcG9wMTgkc21lZGlhNHIpID0gYygiU8OtIiwgIk5vIikKbGV2ZWxzKGxhcG9wMTgkc21lZGlhN3IpID0gYygiU8OtIiwgIk5vIikKYGBgCgojIyBDYWxjdWxhciBsYXMgdmFyaWFibGVzIGRlIHVzdWFyaW9zIGRlIHJlZGVzIHNvY2lhbGVzCgpDb21vIHZpbW9zIGVuIHVuIG3Ds2R1bG8gYW50ZXJpb3IsIHNlIHB1ZWRlIGNhbGN1bGFyIG51ZXZhcyB2YXJpYWJsZXMgY29uIHZhbG9yZXMgY29uZGljaW9uYWxlcyBkZSBvdHJhcyB2YXJpYWJsZXMgdXNhbmRvIGVsIGNvbWFuZG8gYGlmZWxzZWAuCkRlIGVzdGEgbWFuZXJhLCBzZSBjcmVhIGxhcyB2YXJpYWJsZXMgZGUgdXN1YXJpb3MgZGUgcmVkZXMgc29jaWFsZXMuCgpgYGB7ciB1c3VhcmlvfQpsYXBvcDE4JGZiX3VzZXIgPSBpZmVsc2UobGFwb3AxOCRzbWVkaWExPT0xICYgbGFwb3AxOCRzbWVkaWEyPD00LCAxLCAwKQpsYXBvcDE4JHR3X3VzZXIgPSBpZmVsc2UobGFwb3AxOCRzbWVkaWE0PT0xICYgbGFwb3AxOCRzbWVkaWE1PD00LCAxLCAwKQpsYXBvcDE4JHdhX3VzZXIgPSBpZmVsc2UobGFwb3AxOCRzbWVkaWE3PT0xICYgbGFwb3AxOCRzbWVkaWE4PD00LCAxLCAwKQpgYGAKCiMjIERlc2NyaWJpciBsYXMgdmFyaWFibGVzCgpDb24gbGFzIHZhcmlhYmxlcyBsaXN0YXMsIGFob3JhIHByb2NlZGVtb3MgYSBoYWNlciBsYXMgdGFibGFzIGdlbmVyYWxlcyBjb24gZWwgY29tYW5kbyBgdGFibGVgLgpTZSBwdWVkZSBub3RhciBlbCB1c28gZGUgYCNgIGNvbW8gZm9ybWEgZGUgaGFjZXIgYW5vdGFjaW9uZXMsIHF1ZSBubyBzb24gY8OzZGlnbyBlbiBSLgoKYGBge3IgdGFibGFzfQp0YWJsZShsYXBvcDE4JHNtZWRpYTFyKSAjRmFjZWJvb2sKdGFibGUobGFwb3AxOCRzbWVkaWE0cikgI1R3aXR0ZXIKdGFibGUobGFwb3AxOCRzbWVkaWE3cikgI1doYXRzYXBwCmBgYAoKRXN0ZSBjb21hbmRvIGB0YWJsZWAgbm9zIGJyaW5kYSBsYXMgZnJlY3VlbmNpYXMgYWJzb2x1dGFzIChuw7ptZXJvIGRlIG9ic2VydmFjaW9uZXMpIHBvciBjYWRhIGNhdGVnb3LDrWEgZGUgbGFzIHZhcmlhYmxlcyAoZW4gZXN0ZSBjYXNvIFPDrSB5IE5vKS4KUGFyYSBvYnRlbmVyIGxhcyBmcmVjdWVuY2lhcyByZWxhdGl2YXMsIHVzYXJlbW9zIGVsIGNvbWFuZG8gYHByb3AudGFibGVgLCBkb25kZSBzZSBhbmlkYSBlbCBjb21hbmRvIGFudGVyaW9yIGB0YWJsZWAuCgpgYGB7ciBwcm9wb3JjaW9uZXN9CnByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWExcikpCnByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWE0cikpCnByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWE3cikpCmBgYAoKU2luIGVtYmFyZ28sIGVsIGNvbWFuZG8gYHByb3AudGFibGVgIG5vcyBkZXZ1ZWx2ZSBkZW1hc2lhZG9zIGRlY2ltYWxlcyB5IGxhcyBmcmVjdWVuY2lhcyByZWxhdGl2YXMgZW4gdW5hIGVzY2FsYSBkZSAwIGEgMS4KUGFyYSByZWRvbmRlYXIgZXN0YSBjaWZyYSB1c2Ftb3MgZWwgY29tYW5kbyBgcm91bmRgLCBxdWUgbm9zIHBlcm1pdGUgZXNwZWNpZmljYXIgZWwgbsO6bWVybyBkZSBkZWNpbWFsZXMgcXVlIHNlIHF1aWVyZSBtb3N0cmFyLgpUYW50byBlbCBjb21hbmRvIGB0YWJsZWAsIGNvbW8gYHByb3AudGFibGVgIHNlIGFuaWRhbiBkZW50cm8gZGUgZXN0ZSBudWV2byBjb21hbmRvLgpFbiBlc3RlIGNhc28gc2UgaGEgdXNhZG8gMyBkZWNpbWFsZXMsIHBhcmEgY3VhbmRvIHNlIG11bHRpcGxpcXVlIHBvciAxMDAsIHF1ZWRlIGVuIGZvcm1hIGRlIHBvcmNlbnRhamUgY29uIDEgZGVjaW1hbC4KCmBgYHtyIHRhYmxhfQpyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc21lZGlhMXIpKSwgMykqMTAwCnJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWE0cikpLCAzKSoxMDAKcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNtZWRpYTdyKSksIDMpKjEwMApgYGAKCk5vIGVzIHByw6FjdGljbyBwcmVzZW50YXIgMyB0YWJsYXMgY3VhbmRvIGxhcyB2YXJpYWJsZXMgdGllbmVuIGxhcyBtaXNtYXMgY2F0ZWdvcsOtYXMgZGUgcmVzcHVlc3RhLgpQYXJhIGZpbmVzIGRlIHByZXNlbnRhY2nDs24gcG9kcsOtYSBzZXIgbWVqb3IgY29uc3RydWlyIHVuYSBzb2xhIHRhYmxhLgpTZSBwdWVkZSBndWFyZGFyIGxhcyB0YWJsYXMgcGFyY2lhbGVzIGVuIG51ZXZvcyBvYmpldG9zIGNvbiBlbCBvcGVyYWRvciBgPC1gIHkgbHVlZ28gdW5pcmxhcyBjb21vIGZpbGFzIGNvbiBlbCBjb21hbmRvIGByYmluZGAgZW4gdW4gbnVldm8gZGF0YWZyYW1lICJ0YWJsYSIsIGRlIHRhbCBtYW5lcmEgcXVlIGxhcyByZXNwdWVzdGFzIGEgY2FkYSByZWQgc29jaWFsIGFwYXJlemNhbiBlbiBmaWxhcy4KCmBgYHtyIHRhYmxhanVudGF9CkZhY2Vib29rID0gcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNtZWRpYTFyKSksIDMpKjEwMApUd2l0dGVyID0gcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNtZWRpYTRyKSksIDMpKjEwMApXaGF0c2FwcCA9IHJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWE3cikpLCAzKSoxMDAKdGFibGEyID0gYXMuZGF0YS5mcmFtZShyYmluZChGYWNlYm9vaywgVHdpdHRlciwgV2hhdHNhcHApKQp0YWJsYTIKYGBgCgpQYXJhIHRlbmVyIHVuYSBtZWpvciBwcmVzZW50YWNpw7NuIGRlIGxhIHRhYmxhLCBzZSBwdWVkZSB1c2FyIGVsIGNvbWFuZG8gYGthYmxlYCBkZWwgcGFxdWV0ZSBga25pdHJgLCB1c2FuZG8gbGEgdGFibGEgY29uc3RydWlkYSBhbnRlcmlvcm1lbnRlLgoKYGBge3IgdGFibGFtZWpvcmFkYSwgcmVzdWx0cz0nYXNpcyd9CmxpYnJhcnkoa25pdHIpCmtuaXRyOjprYWJsZSh0YWJsYTIsIGZvcm1hdD0ibWFya2Rvd24iKQpgYGAKCiMjIEdyYWZpY2FyIGxhcyB2YXJpYWJsZXMKCkVuIGVsIEdyw6FmaWNvIDMuMSBkZWwgcmVwb3J0ZSBzZSBvYnNlcnZhIHF1ZSBzZSByZXBvcnRhbiBlc3RvcyBkYXRvcyBtZWRpYW50ZSB1biBncsOhZmljbyBkZSBzZWN0b3JlcyBjaXJjdWxhcmVzLgoKIVtdKEdyYWYzLjEucG5nKXt3aWR0aD0iNDE4In0KClNlIHB1ZWRlIHJlcHJvZHVjaXIgZXNlIGdyw6FmaWNvIHVzYW5kbyBlbCBjb21hbmRvIGBwaWVgIHF1ZSBlcyBwYXJ0ZSBkZSBsYSBzaW50YXhpcyBiw6FzaWNhIGRlIFIuCkRlbnRybyBkZSBlc3RlIGNvbWFuZG8gc2UgcHVlZGUgYW5pZGFyIGVsIGNvbWFuZG8gYHRhYmxlYCBwYXJhIGdyYWZpY2FyIGVzdG9zIHZhbG9yZXMuCgpgYGB7ciBwaWUyfQpwaWUodGFibGUobGFwb3AxOCRzbWVkaWExcikpCmBgYAoKVGFtYmnDqW4gc2UgcG9kcsOtYSBwZW5zYXIgZW4gdW4gZ3LDoWZpY28gZGUgYmFycmFzLgpVc2FuZG8gbG9zIGNvbWFuZG9zIGLDoXNpY29zIGRlIFIsIHNlIHB1ZWRlIHVzYXIgZWwgY29tYW5kbyBgYmFycGxvdGAuCgpgYGB7ciBiYXJyYXMgc2ltcGxlfQpiYXJwbG90KHByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWExcikpKQpgYGAKCkVzdG9zIGNvbWFuZG9zIGdyw6FmaWNvcyB0aWVuZW4gb3BjaW9uZXMgcGFyYSBhZGVjdWFyIGVsIGdyw6FmaWNvLCBwb3IgZWplbXBsbywgcGFyYSBpbmNsdWlyIGxvcyBwb3JjZW50YWplcyB5IGFkZWN1YXIgbGFzIGVzY2FsYXMuCgpQZXJvLCBjb21vIG1lbmNpb25hbW9zIG3DoXMgYXJyaWJhLCBwYXJhIHRlbmVyIG3DoXMgb3BjaW9uZXMgZ3LDoWZpY2FzLCB1c2FyZW1vcyBlbCBwYXF1ZXRlIGBnZ3Bsb3RgIHBhcmEgcmVwcm9kdWNpciBlbCBncsOhZmljbyBjaXJjdWxhciB5IGEgbG8gbGFyZ28gZGUgZXN0b3MgbcOzZHVsb3MuCgpMbyBwcmltZXJvIHF1ZSB0ZW5lbW9zIHF1ZSBoYWNlciBlcyBjcmVhciB1bmEgdGFibGEgcXVlIGd1YXJkZSBsb3MgZGF0b3MgcXVlIHF1ZXJlbW9zIGdyYWZpY2FyIHNvYnJlIGxvcyB1c3VhcmlvcyBkZSBGYWNlYm9vay4KUmVjb3JkZW1vcyBxdWUgdGVuZW1vcyB1bmEgdGFibGEgY29uIGVzdG9zIHJlc3VsdGFkb3MgZG9uZGUgbGEgcHJpbWVyYSBmaWxhIG11ZXN0cmEgbGFzIGV0aXF1ZXRhcyAiU8OtIiB5ICJObyIgeSBsYSBzZWd1bmRhIGZpbGEgbG9zIHBvcmNlbnRhamVzLgpSZXF1ZXJpbW9zIHF1ZSBsYXMgZXRpcXVldGFzIGVzdMOpbiBjb21vIGNvbHVtbmFzIHkgbG9zIHBvcmNlbnRhamVzIHRhbWJpw6luLgpQYXJhIGVzdG8gdGVuZW1vcyBxdWUgdHJhbnNwb25lciBsYSB0YWJsYSwgcXVlIHNpZ25pZmljYSAiZGFybGUgbGEgdnVlbHRhIi4KTHVlZ28sIGVzdGEgbnVldmEgdGFibGEgbGEgZ3VhcmRhbW9zIGNvbW8gdW4gZGF0YWZyYW1lIGNvbiBlbCBjb21hbmRvIGBhcy5kYXRhLmZyYW1lYCBxdWUgY3JlYSB0cmVzIGNvbHVtbmFzICJWYXIxIiAoc2luIGludGVyw6lzKSwgIlZhcjIiIGNvbiBsYXMgZXRpcXVldGFzIHkgRnJlcSBjb24gbG9zIHBvcmNlbnRhamVzLgoKYGBge3IgdGFibGEgRmFjZX0KRmFjZSA9IGFzLmRhdGEuZnJhbWUodChGYWNlYm9vaykpCkZhY2UKYGBgCgpDb24gZXN0YSB0YWJsYSBwb2RlbW9zIGNyZWFyIHVuIGdyw6FmaWNvIGRlIGJhcnJhcyBjb21vIGVsIHZpc3RvIG3DoXMgYXJyaWJhLgpPdHJvIHRpcG8gZGUgYmFycmFzIHF1ZSBzZSB1c2EgZnJlY3VlbnRlbWVudGUgZXMgZGVsIHRpcG8gZGUgYmFycmFzIGFwaWxhZGFzIGFsIDEwMCUuCgpWYW1vcyBhIGNyZWFyIHVuYSBiYXJyYSBhcGlsYWRhIGNvbiBlc3RvcyByZXN1bHRhZG9zLgpBIGRpZmVyZW5jaWEgZGVsIGdyw6FmaWNvIGRlIGJhcnJhcyBjb252ZW5jaW9uYWwsIGxhcyBiYXJyYXMgYXBpbGFkYXMgcmVxdWllcmVuIHF1ZSBlbiBsYSBgYWVzKHg9IiIsIHk9RnJlcSwgZmlsbD1WYXIyKWAuCkVzIGRlY2lyLCBxdWUgbm8gaGF5YSBldGlxdWV0YXMgZW4gZWwgZWplIFgsIHF1ZSBlbCBlamUgWSBtdWVzdHJlIGxvcyBwb3JjZW50YWplcyAoZ3VhcmRhZG9zIGVuICJGcmVxIikgeSBxdWUgbGEgYmFycmEgZXN0w6kgc2VwYXJhZGEgcG9yIGxhcyBjYXRlZ29yw61hcyAoZ3VhcmRhZGFzIGVuICJWYXIyIikuCgpTZSBhZ3JlZ2EgdW5hIGNhcGEgZGUgdGV4dG8sIGNvbiBsYSBlc3BlY2lmaWNhY2nDs24gYGdlb21fdGV4dGAuCkRlbnRybyBkZSBlc3RhIGVzcGVjaWZpY2FjacOzbiBzZSBkZXRlcm1pbmEgdW5hICJlc3TDqXRpY2EiIGNvbiBsYSBldGlxdWV0YSBkZWwgZGF0byBgYWVzKGxhYmVsPS4uLilgLCBkb25kZSBzZSBqdW50YSBjb24gZWwgY29tYW5kbyBgcGFzdGVgIGVsIGRhdG8gZGVsIHBvcmNlbnRhamUgInBlciIgeSBlbCBzw61tYm9sbyAiJSIsIGNvbiB1biBlc3BhY2lvIChgc2VwPS4uLmApIGVudHJlIGVsbG9zLgpTZSBlc3RhYmxlY2UgZWwgY29sb3IgZGUgbGEgZnVlbnRlIGNvbiBgY29sb3I9Ii4uLiJgLgpTZSBhanVzdGEgYSBibGFuY28gcGFyYSBxdWUgY29udHJhc3RlIGNvbiBsb3MgY29sb3JlcyBkZWwgZ3LDoWZpY28gY2lyY3VsYXIuCkNvbiBlbCBjb21hbmRvIGBoanVzdD0uLi5gIHNlIGFqdXN0YSBsYSBwb3NpY2nDs24gaG9yaXpvbnRhbCBkZSBlc3RlIHRleHRvLgpFbCBjb21hbmRvIGBnZ3Bsb3RgIHB1ZWRlIGluY2x1aXIgdmFyaW9zICJ0ZW1hcyIgcGFyYSBlbCBncsOhZmljby4KRW4gZXN0ZSBjYXNvIHNlIGhhIHVzYWRvIGB0aGVtZV92b2lkKClgIHF1ZSBpbmRpY2EgdW4gZm9uZG8gdmFjw61vLgpGaW5hbG1lbnRlLCBjb24gbGEgZXNwZWNpZmljYWNpw7NuIGBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9Li4uKWAgc2UgcHVlZGUgY2FtYmlhciBlbCB0w610dWxvIGRlIGxhIGxleWVuZGEgcGFyYSBxdWUgbm8gYXBhcmV6Y2EgZWwgbm9tYnJlIGRlIGxhIHZhcmlhYmxlLCBzaW5vIHVuYSBldGlxdWV0YSBtw6FzIGFkZWN1YWRhLgoKYGBge3IgZ2cgYXBpbGFkYX0KZ2dwbG90KGRhdGE9RmFjZSwgYWVzKHg9IiIsIHk9RnJlcSwgZmlsbD1WYXIyKSkrCiAgZ2VvbV9iYXIod2lkdGg9MSwgc3RhdD0iaWRlbnRpdHkiKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKEZyZXEsICIlIiwgc2VwPSIiKSksIGNvbG9yPSJ3aGl0ZSIsCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIHNpemU9MykrCiAgdGhlbWVfdm9pZCgpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZT0iwr9Vc2EgRmFjZWJvb2s/IikKYGBgCgpQYXJhIGNyZWFyIHVuIGdyw6FmaWNvIGNpcmN1bGFyLCBubyBleGlzdGUgdW5hICJnZW9tZXRyw61hIiBlbiBgZ2dwbG90YC4KU2luIGVtYmFyZ28sIHBhcmEgZ2VuZXJhIGVsIGdyw6FmaWNvIGNpcmN1bGFyLCBzZSB0aWVuZSBxdWUgYWdyZWdhciBvdHJvIGNhcGEgYGNvb3JkX3BvbGFyYCwgcXVlIHRyYW5zZm9ybWEgbGEgYmFycmEgYSBjb29yZGVuYWRhcyBwb2xhcmVzLCBjcmVhbmRvIHVuIGdyw6FmaWNvIGNpcmN1bGFyLgpUb2RvIGVsIHJlc3RvIGRlbCBjw7NkaWdvIGVzIHNpbWlsYXIgYWwgYW50ZXJpb3IuCgpgYGB7ciBnZyBwaWUyfQpnZ3Bsb3QoZGF0YT1GYWNlLCBhZXMoeD0iIiwgeT1GcmVxLCBmaWxsPVZhcjIpKSsKICBnZW9tX2Jhcih3aWR0aD0xLCBzdGF0PSJpZGVudGl0eSIpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUoRnJlcSwgIiUiLCBzZXA9IiIpKSwgY29sb3I9IndoaXRlIiwKICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSwgc2l6ZT0zKSsKICBjb29yZF9wb2xhcigieSIpKwogIHRoZW1lX3ZvaWQoKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9IsK/VXNhIEZhY2Vib29rPyIpCmBgYAoKU2kgcXVpc2nDqXJhbW9zIHJlZ3Jlc2FyIGEgaGFjZXIgdW4gZ3LDoWZpY28gZGUgYmFycmFzLCBwb2RlbW9zIGluY2x1aXIgZWwgdGV4dG8gZGUgbG9zIHZhbG9yZXMgY29uIGBnZW9tX3RleHRgLCBlbCB0w610dWxvIGdlbmVyYWwgZGVsIGdyw6FmaWNvIGNvbiBgdGl0bGVgIGRlbnRybyBkZSBgbGFic2AsIGxvcyBub21icmVzIGRlIGxvcyBlamVzIHkgZWwgImNhcHRpb24iLgoKYGBge3IgYmFycmEgZmFjZX0KZ2dwbG90KEZhY2UsIGFlcyh4PVZhcjIsIHk9RnJlcSkpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgIHdpZHRoPTAuNSkrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZShGcmVxLCAiJSIsIHNlcD0iIikpLCBjb2xvcj0iYmxhY2siLCB2anVzdD0tMC41KSsKICBsYWJzKHRpdGxlPSLCv1F1w6kgdGFuIGZyZWN1ZW50ZSBzZSB1c2FuIGxhcyByZWRlcyBzb2NpYWxlcz8iLCAKICAgICAgIHg9IlVzdWFyaW8gZGUgRmFjZWJvb2siLCB5PSJQb3JjZW50YWplIiwgCiAgICAgICBjYXB0aW9uPSJCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgcG9yIExBUE9QLCAyMDE4LzE5IikrCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCA2MCkpCmBgYAoKIyBSZXN1bWVuCgpFbiBlc3RlIGRvY3VtZW50byBzZSBoYSB0cmFiYWphZG8gY29uIHZhcmlhYmxlcyBjYXRlZ8OzcmljYXMgbm9taW5hbGVzLCBjb21vIGFwb3lvIGEgbGEgZGVtb2NyYWNpYSBvIHNpIHVzYSBvIG5vIHVzYSByZWRlcyBzb2NpYWxlcy4KU2UgaGEgcHJlc2VudGFuZG8gbGFzIGZvcm1hcyBkZSBjw7NtbyBkZXNjcmliaXIgZW4gdGFibGFzIGRlIGZyZWN1ZW5jaWEgeSBjw7NtbyBncmFmaWNhciBlc3RhcyB2YXJpYWJsZXMsIG1lZGlhbnRlIGdyw6FmaWNvcyBjaXJjdWxhcmVzIG8gZGUgYmFycmFzLgoKIyBDw6FsY3Vsb3MgaW5jbHV5ZW5kbyBlbCBlZmVjdG8gZGUgZGlzZcOxbwoKRXN0b3Mgw7psdGltb3MgcmVzdWx0YWRvcyBkZSBsYSByb25kYSAyMDE4LzE5IG5vIHNvbiBleGFjdGFtZW50ZSBpZ3VhbGVzIGEgbG9zIGRlbCByZXBvcnRlIHB1ZXMgTEFQT1AgaW5jbHV5ZSBlbCBlZmVjdG8gZGVsIGRpc2XDsW8gbXVlc3RyYWwgZW4gc3VzIGPDoWxjdWxvcy4KU2Vnw7puIGVzdGEgc2ludGF4aXMsIHNlIGVuY3VlbnRyYSBxdWUgZWwgNTcuMSUgZGUgZW50cmV2aXN0YWRvcyByZXBvcnRhIHNlciB1c3VhcmlvIGRlIEZhY2Vib29rLCBjdWFuZG8gZW4gZWwgcmVwb3J0ZSBhcGFyZWNlIDU2LjIlLgpMbyBtaXNtbyBjb24gVHdpdHRlciwgcXVlIGFxdcOtIHNlIGNhbGN1bGEgZW4gOC44JSB5IGVuIGVsIHJlcG9ydGUgNy45JTsgeSBjb24gV2hhdHNhcHAgcXVlIGFxdcOtIGFwYXJlY2UgY29uIDY0LjYlIHkgZW4gZWwgcmVwb3J0ZSBjb24gNjQuNCUuCkNvbW8gc2UgaW5kaWPDsyBlbiBlbCBkb2N1bWVudG8gc29icmUgZWwgdXNvIGRlIGxvcyBmYWN0b3JlcyBkZSBleHBhbnNpw7NuIHVzYW5kbyBsb3MgZGF0b3MgZGVsIEJhcsOzbWV0cm8gZGUgbGFzIEFtw6lyaWNhcyAoZGlzcG9uaWJsZSBbYXF1w61dKGh0dHBzOi8vYXJ0dXJvbWFsZG9uYWRvLmdpdGh1Yi5pby9CYXJvbWV0cm9FZHVfV2ViL0V4cGFuc2lvbi5odG1sKSksIGhheSB2YXJpYXMgbWFuZXJhcyBkZSByZXByb2R1Y2lyIGxvcyByZXN1bHRhZG9zIGluY29ycG9yYW5kbyBlbCBlZmVjdG8gZGUgZGlzZcOxby4KVW5hIHByaW1lcmEgb3BjacOzbiBlcyB1c2FyIGVsIGNvbWFuZG8gYGZyZXFgIHF1ZSBwZXJtaXRlIGxhIGluY2x1c2nDs24gZGUgdW5hIHZhcmlhYmxlIGRlIGZhY3RvciBkZSBleHBhbnNpw7NuLCBjb21vICJ3ZWlnaHQxNTAwIi4KU2UgaW5jbHV5ZSBsYSBlc3BlY2lmaWNhY2nDs24gYHBsb3Q9RmAgcGFyYSBubyBwcm9kdWNpciBsb3MgZ3LDoWZpY29zIGRlIGJhcnJhcy4KCmBgYHtyIGRlc2NyaXB0aXZvcyBwb25kZXJhZG9zfQpsaWJyYXJ5KGRlc2NyKQpkZXNjcjo6ZnJlcShsYXBvcDE4JGZiX3VzZXIsIGxhcG9wMTgkd2VpZ2h0MTUwMCwgcGxvdCA9IEYpCmRlc2NyOjpmcmVxKGxhcG9wMTgkdHdfdXNlciwgbGFwb3AxOCR3ZWlnaHQxNTAwLCBwbG90ID0gRikKZGVzY3I6OmZyZXEobGFwb3AxOCR3YV91c2VyLCBsYXBvcDE4JHdlaWdodDE1MDAsIHBsb3QgPSBGKQpgYGAKClNpbiBjb25zaWRlcmFyIGVsIGVmZWN0byBkZSBkaXNlw7FvLCBzZSB0aWVuZSBxdWUgNTcuMSUgZGUgZW50cmV2aXN0YWRvcyBjdWVudGEgY29uIHVuYSBjdWVudGEgZGUgRmFjZWJvb2suCkVzdGUgcG9yY2VudGFqZSB2YXLDrWEgYSA1NS4yJSBzaSBzZSBpbmNsdXllIGxhIHZhcmlhYmxlIGRlIGV4cGFuc2nDs24sIHF1ZSBlcyBlbCB2YWxvciBxdWUgc2UgbXVlc3RyYSBlbiBlbCByZXBvcnRlLgpFc3RvcyByZXN1bHRhZG9zIHBvbmRlcmFkb3MgdGFtYmnDqW4gc2UgcHVlZGVuIGd1YXJkYXIgZW4gb2JqZXRvcyB5IGx1ZWdvIGdyYWZpY2FyIGRlIGxhIG1pc21hIG1hbmVyYSBxdWUgc2UgaGEgaGVjaG8gY29uIGxvcyByZXN1bHRhZG9zIHNpbiBwb25kZXJhci4KClBhcmEgZWwgY2FzbyBkZSBGYWNlYm9vaywgbGEgdGFibGEgc2UgcHVlZGUgZ3VhcmRhciBjb21vIHVuIGRhdGFmcmFtZSwgdXNhbmRvIGVsIGNvbWFuZG8gYGFzLmRhdGEuZnJhbWVgLgpFc3RhIHRhYmxhIGluY2x1eWUgZGF0b3MgcXVlIG5vIHJlcXVlcmltb3MsIGNvbW8gbGEgZmlsYSBkZSBOQcK0cyB5IGRlbCB0b3RhbCB5IGNvbW8gbGEgY29sdW1uYSBkZSBQZXJjZW50LgpFc3RhcyBmaWxhcyB5IGVzdGEgY29sdW1uYSBzZSBib3JyYW4gdXNhbmRvIGxhIGVzcGVjaWZpY2FjacOzbiBgWy1jKDMsNCksIC0yXWAuCgpMdWVnbywgc2UgbGUgY2FtYmlhIGVsIG5vbWJyZSBhIGxhcyBjb2x1bW5hcyBwYXJhIGV2aXRhciBlbCBub21icmUgIlZhbGlkIFBlcmNlbnQiLgpTZSBsYXMgbm9tYnJlIHNpbXBsZW1lbnRlIGNvbW8gImZyZXEiIHkgInBlciIuCkVzdGEgY29sdW1uYSAicGVyIiBlcyBsYSBxdWUgdGllbmUgbG9zIGRhdG9zIHF1ZSBncmFmaWNhcmVtb3MuCkZpbmFsbWVudGUsIHNlIGHDsWFkZSB1bmEgY29sdW1uYSAibGFiIiBjb24gbGFzIGV0aXF1ZXRhcyBkZSBjYWRhIGZpbGEgZGUgcmVzdWx0YWRvcy4KCmBgYHtyIHRhYmxhIGZifQpmYiA9IGFzLmRhdGEuZnJhbWUoZGVzY3I6OmZyZXEobGFwb3AxOCRmYl91c2VyLCBsYXBvcDE4JHdlaWdodDE1MDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdCA9IEYpKQpmYiA9IGZiWy1jKDMsNCksIC0yXQpjb2xuYW1lcyhmYikgPSBjKCJmcmVxIiwgInBlciIpCmZiJGxhYiA9IGMoIk5vIiwgIlPDrSIpCmZiCmBgYAoKQ29uIGVzdGUgbnVldm8gZGF0YWZyYW1lIHBvZGVtb3MgcmVwbGljYXIgbG9zIG1pc21vIGPDs2RpZ29zIHVzYWRvcyBtw6FzIGFycmliYSBwYXJhIGhhY2VyIHVuIGdyw6FmaWNvIGRlIGJhcnJhcyBvIHVuIGdyw6FmaWNvIGNpcmN1bGFyLgpFbCBzaWd1aWVudGUgY8OzZGlnbyBtdWVzdHJhIGVsIGdyw6FmaWNvIGRlIGJhcnJhcy4KTsOzdGVzZSBxdWUgYWhvcmEgc2UgdXNhIGVsIGRhdGFmcmFtZSAiZmIiIHkgcXVlIGVuIGFlcyBzZSBlc3BlY2lmaWNhIHF1ZSBlbiBlbCBlamUgWCBkZWJlbiBlc3RhciBsb3MgZGF0b3MgZGUgbGEgY29sdW1uYSAibGFiIiB5IGVuIGVsIGVqZSBZIGxvcyBkYXRvcyBkZSBsYSBjb2x1bW5hICJwZXIiLgoKYGBge3IgYmFycmFzIHBvbmRlcmFkYXN9CmdncGxvdChkYXRhPWZiLCBhZXMoeD1sYWIsIHk9cGVyKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCAgd2lkdGg9MC41KSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKHJvdW5kKHBlciwgMSksICIlIiwgc2VwPSIiKSksIAogICAgICAgICAgICBjb2xvcj0iYmxhY2siLCB2anVzdD0tMC41KSsKICBsYWJzKHRpdGxlPSLCv1F1w6kgdGFuIGZyZWN1ZW50ZSBzZSB1c2FuIGxhcyByZWRlcyBzb2NpYWxlcz8iLCAKICAgICAgIHg9IlVzdWFyaW8gZGUgRmFjZWJvb2siLCB5PSJQb3JjZW50YWplIiwgCiAgICAgICBjYXB0aW9uPSJCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgcG9yIExBUE9QLCAyMDE4LzE5IikrCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCA2MCkpCmBgYAoKRXN0byBtaXNtbyBzZSBwdWVkZSBoYWNlciBwYXJhIGNyZWFyIHVuIGdyw6FmaWNvIGNpcmN1bGFyLgpFc3RlIGdyw6FmaWNvIHJlcHJvZHVjZSBsb3MgcmVzdWx0YWRvcyBoYWxsYWRvcyBlbiBlbCBHcsOhZmljbyAzLjEgZGVsIHJlcG9ydGUuCgpgYGB7ciBwaWUgcG9uZGVyYWRvfQpnZ3Bsb3QoZGF0YT1mYiwgYWVzKHg9MiwgeT1wZXIsIGZpbGw9bGFiKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKHJvdW5kKHBlciwgMSksICIlIiwgc2VwPSIiKSksIGNvbG9yPSJ3aGl0ZSIsIAogICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBzaXplPTMpKwogIGNvb3JkX3BvbGFyKCJ5IikrCiAgdGhlbWVfdm9pZCgpKwogIGxhYnModGl0bGU9IsK/UXXDqSB0YW4gZnJlY3VlbnRlIHNlIHVzYW4gbGFzIHJlZGVzIHNvY2lhbGVzPyIsIAogICAgICAgY2FwdGlvbj0iQmFyw7NtZXRybyBkZSBsYXMgQW3DqXJpY2FzIHBvciBMQVBPUCwgMjAxOC8xOSIpKwogIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZT0iwr9Vc2EgRmFjZWJvb2s/IikrCiAgeGxpbSgwLjUsIDIuNSkKYGBgCgpMYSBzZWd1bmRhIG9wY2nDs24gcGFyYSByZXByb2R1Y2lyIGxvcyBkYXRvcyBkZWwgcmVwb3J0ZSBleGFjdGFtZW50ZSBlcyBtZWRpYW50ZSBlbCBwYXF1ZXRlIGBzdXJ2ZXlgLgpDb21vIHNlIGluZGljw7MgZW4gZXN0YSBbc2VjY2nDs25dKGh0dHBzOi8vYXJ0dXJvbWFsZG9uYWRvLmdpdGh1Yi5pby9CYXJvbWV0cm9FZHVfV2ViL0V4cGFuc2lvbi5odG1sKSwgcHJpbWVybyBzZSB0aWVuZSBxdWUgZGVmaW5pciBlbCBkaXNlw7FvIG11ZXN0cmFsIGNvbiBlbCBjb21hbmRvIGBzdnlkZXNpZ25gLgoKYGBge3Igc3VydmV5fQpsaWJyYXJ5KHN1cnZleSkKZGlzZW5vMTggPSBzdnlkZXNpZ24oaWRzID0gfnVwbSwgc3RyYXRhID0gfmVzdHJhdG9wcmksIAogICAgICAgICAgICAgICAgICAgICB3ZWlnaHRzID0gfndlaWdodDE1MDAsIG5lc3Q9VFJVRSwgZGF0YT1sYXBvcDE4KQpgYGAKClVuYSB2ZXogY3JlYWRvIGxvcyBkYXRvcyBjb24gZWwgZmFjdG9yIGRlIGV4cGFuc2nDs24gZW4gZWwgb2JqZXRvICJkaXNlbm8xOCIsIHNlIHB1ZWRlIHVzYXIgbG9zIGNvbWFuZG9zIG5hdGl2b3MgZGVsIHBhcXVldGUgYHN1cnZleWAgcGFyYSByZWFsaXphciBjw6FsY3Vsb3MuClBvciBlamVtcGxvLCBwYXJhIGNhbGN1bGFyIGxhIHRhYmxhIGRlIGRpc3RyaWJ1Y2nDs24gZGUgZnJlY3VlbmNpYXMgc2UgcHVlZGUgdXNhciBlbCBjb21hbmRvIGBzdnl0YWJsZWAuCgpgYGB7ciBzdnl0YWJsZX0Kc3Z5dGFibGUofmZiX3VzZXIsIGRlc2lnbj1kaXNlbm8xOCkKYGBgCgpFc3RhcyBmcmVjdWVuY2lhcyBzZSBwdWVkZW4gYW5pZGFyIGVuIGVsIGNvbWFuZG8gYHByb3AudGFibGVgIHBhcmEgY2FsY3VsYXIgbG9zIHBvcmNlbnRhamVzIGRlIHVzdWFyaW9zIGRlIHJlZGVzIHNvY2lhbGVzLgpFc3RvcyByZXN1bHRhZG9zIHNvbiBpZ3VhbGVzIGEgbG9zIG1vc3RyYWRvcyBlbiBsb3MgZ3LDoWZpY29zIGFudGVyaW9yZXMgeSBhIGxvcyBxdWUgYXBhcmVjZW4gZW4gZWwgcmVwb3J0ZS4KCkVzdG9zIGRhdG9zIHRhbWJpw6luIHNlIHB1ZWRlbiBndWFyZGFyIGVuIHVuIGRhdGFmcmFtZSBxdWUgc2UgYWRhcHRhIHBhcmEgZ3JhZmljYXIsIHNpZ3VpZW5kbyBlbCBtaXNtbyBwcm9jZWRpbWllbnRvIHF1ZSBlbiBsb3MgZ3LDoWZpY29zIGFudGVyaW9yZXMuCgpgYGB7ciBzdnl0YWJsZSBwcm9wfQpwcm9wLnRhYmxlKHN2eXRhYmxlKH5mYl91c2VyLCBkZXNpZ249ZGlzZW5vMTgpKQpwcm9wLnRhYmxlKHN2eXRhYmxlKH50d191c2VyLCBkZXNpZ249ZGlzZW5vMTgpKQpwcm9wLnRhYmxlKHN2eXRhYmxlKH53YV91c2VyLCBkZXNpZ249ZGlzZW5vMTgpKQpgYGAK