Los votos son contados correctamente
En esta sección se va a usar la variable COUNTFAIR1. Los votos son
contados correcta y justamente. ¿Diría usted que sucede siempre, algunas
veces o nunca? El gráfico 2.5 del reporte el Pulso de la Democracia,
disponible aquí,
presenta los resultados de esta variable por país.
De la misma manera que con las variables nominales, estas variables
tienen que ser declaradas como “factor” en nuevas variables.
library(haven)
lapop21$countfair1r = as.factor(lapop21$countfair1)
Luego, estas variables se tienen que etiquetar y generar las tablas
descriptivas básicas, con el comando table
.
levels(lapop21$countfair1r) <- c("Siempre", "Algunas veces", "Nunca")
table(lapop21$countfair1r)
##
## Siempre Algunas veces Nunca
## 3477 5235 1698
Para calcular las tablas con porcentajes, redondeados a un decimal,
usamos prop.table
y round
. Nuevamente, estos
porcentajes no son exactamente iguales a los presentados en el reporte
debido a que estos cálculos no incluyen el factor de expansión.
round(prop.table(table(lapop21$countfair1r)), 3)*100
##
## Siempre Algunas veces Nunca
## 33.4 50.3 16.3
Como se mencionó en la sección anterior, se puede graficar esta
variable usando el comando barplot
.
barplot(prop.table(table(lapop21$countfair1r))*100)
Otra opción es elaborar el gráfico de barras usando la librería
ggplot
. Una primera opción es trabajar directamente de la
base de datos. El siguiente código, sin embargo, muestra una gran barra
del porcentaje de casos perdidos. Esto se debe a que esta pregunta se
realizó a la mitad de la muestra. Se registra NA a la otra mitad a la
que no se le hizo esta pregunta.
library(ggplot2)
ggplot(data=lapop21, aes(x=countfair1r))+
geom_bar(aes(y=..prop..*100, group=1), width=0.5)+
labs(x="¿Los votos son contados correctamente?", y="Porcentaje",
caption="Barómetro de las Américas por LAPOP, 2021")+
coord_cartesian(ylim=c(0, 100))
Para evitar que el gráfico presente la barra de NAs, estas
observaciones se tienen que filtrar antes de producir el gráfico. Tal
como indicamos en el módulo anterior, se filtra los NAs de la variable
“countfair1r” con el comando subset
y la especificación
!is.na
.
ggplot(data=subset(lapop21, !is.na(countfair1r)), aes(x=countfair1r))+
geom_bar(aes(y=..prop..*100, group=1), width=0.5)+
labs(x="¿Los votos son contados correctamente?", y="Porcentaje",
caption="Barómetro de las Américas por LAPOP, 2021")+
coord_cartesian(ylim=c(0, 60))
Otra opción, que simplifica el código, es crear una tabla de
frecuencias de esta variable con el comando table
y
prop.table
. Esta table se redondea a un decimal con el
comando round
y se guarda como un dataframe con el comando
as.data.frame
en un objeto “count”. Esta tabla almacena dos
columnas, la primera llamada “Var1” con las etiquetas de la variable y
la segunda llamada “Freq” con los porcentajes.
count <- as.data.frame(round(prop.table(table(lapop21$countfair1r)), 3)*100)
count
Podemos usar esta tabla “count” para producir el gráfico de barras
con el comando ggplot
. En la especificación
aes
se define que los valores de la columna “Var1” se
presenten en el eje X y los valores de la columna a “Freq” en el eje Y.
Se define un gráfico de barras simple, usando el comando
geom_bar()
, donde internamente se define el ancho de la
barra. Con la especificación labs
se define las etiquetas
de ejes y el “caption”.
ggplot(data=count, aes(x=Var1, y=Freq))+
geom_bar(stat="identity", width=0.5)+
geom_text(aes(label=paste(Freq, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
labs(x="Los votos se cuentan justamente", y="Porcentaje",
caption="Barómetro de las Américas por LAPOP, 2021")
El gráfico 2.5 presenta una barra apilada con los datos por cada
país. Primero presentaremos el gráfico de barras apilado usando los
datos de toda la ronda 2021 del Barómetro de las Américas, es decir de
todos los países. Para producir una barra apilada horizontal, se usará
la variable “Freq” ahora en el eje X. Se usará la opción
fill
para dividir esta barra por los valores de la variable
“Var1”. Como en el eje Y no se mostrará una variable se define como
""
. De la misma manera que se cambiaron las variables en
los ejes, también se cambian las etiquetas en labs
. En esta
especificación se cambia la etiqueta de la leyenda con
fill
.
ggplot(data=count, aes(fill=Var1, x=Freq, y=""))+
geom_bar(stat="identity", width=0.3)+
geom_text(aes(label=paste(Freq, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
labs(x="Porcentaje", y="", fill="Los votos se cuentan justamente",
caption="Barómetro de las Américas por LAPOP, 2021")
Para replicar el gráfico comparativo por país se requiere crear la
tabla de contingencia entre la variable “countfair” y “pais”. Esta tabla
cruzada se guarda en un objeto “count_pais”. Se debe notar que el
dataframe que se crea crea una fila por cada valor de “countfair” en
cada país. De esta manera tenemos 3 opciones x 20 países = 60 filas.
count_pais = as.data.frame(round(prop.table(table(lapop21$pais, lapop21$countfair1r), 1), 3)*100)
count_pais
En esta tabla se calculan los datos por cada valor de la variable
“pais”, incluso cuando no se tiene datos de la variable “countfair”,
debido a que la pregunta no se realizó en ese país. Por este motivo se
tienen que eliminar las filas de los países en los que no se recogió
esta información. Esto se hace con la especificación
[-c(filas),]
. Luego se crea un vector con los nombres de
los países. Esta lista se repite 3 veces (15 países restantes x 3
opciones). Este vector se agrega al dataframe en una columna “pais”.
count_pais = count_pais[-c(1:4,18,21:24,38,41:44,58),]
pais = c("Nicaragua","Costa Rica", "Panamá", "Colombia", "Ecuador", "Bolivia", "Perú",
"Paraguay", "Chile", "Uruguay", "Brasil", "Argentina", "Rep. Dom.","Jamaica", "Guyana", "Nicaragua","Costa Rica", "Panamá", "Colombia", "Ecuador", "Bolivia", "Perú",
"Paraguay", "Chile", "Uruguay", "Brasil", "Argentina", "Rep. Dom.","Jamaica", "Guyana","Nicaragua","Costa Rica", "Panamá", "Colombia", "Ecuador", "Bolivia", "Perú",
"Paraguay", "Chile", "Uruguay", "Brasil", "Argentina", "Rep. Dom.","Jamaica", "Guyana")
count_pais$pais = pais
count_pais
Con este dataframe “count_pais” ya tenemos los elementos para
replicar el gráfico de barras apiladas. En la especificación
aes
se define que en el eje X se grafiquen los porcentajes,
en el eje Y los países y cada barra se divida por la columna Var2.
ggplot(data=count_pais, aes(x=Freq, y=pais, fill=Var2))+
geom_bar(stat="identity", width=0.3)+
geom_text(aes(label=paste(Freq, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=2)+
labs(x="Porcentaje", y="País", fill="Los votos se cuentan justamente",
caption="Barómetro de las Américas por LAPOP, 2021")
Frecuencia de uso de redes sociales
En la ronda 2018/19 se evaluó el uso de redes sociales. De esta
manera, se analizaron las variables SMEDIA2. ¿Con qué frecuencia ve
contenido en Facebook?, SMEDIA5.¿Con qué frecuencia ve contenido en
Twitter? y SMEDIA8.¿Con qué frecuencia usa Whatsapp? Estas variables
tienen como opciones de respuesta:
- Diariamente
- Algunas veces a la semana
- Algunas veces al mes
- Algunas veces al año
- Nunca
De la misma manera que con las variables nominales, estas variables
tienen que ser declaradas como “factor” en nuevas variables.
lapop18$smedia2r = as.factor(lapop18$smedia2)
lapop18$smedia5r = as.factor(lapop18$smedia5)
lapop18$smedia8r = as.factor(lapop18$smedia8)
La nota a pie 15 del reporte indica que “los entrevistados que
reportan nunca ver contenido en Facebook y Twitter, y quienes indican
que nunca usan Whatsapp, son considerados como no usuarios de estas
redes sociales” (p. 64). Por este motivo, el gráfico 3.3 de frecuencia
de uso de redes sociales (pag. 57) solo incluyen las categorías
“Diariamente”, “Algunas veces a la semana”, “Algunas veces al mes” y
“Algunas veces al año”. Se excluya la categoría “Nunca”.
En las nuevas variables vamos a declarar el valor 5, correspondiente
a “nunca”, como “NA”, es decir, como valor perdido en R.
library(car)
lapop18$smedia2r = car::recode(lapop18$smedia2r, "5=NA")
lapop18$smedia5r = car::recode(lapop18$smedia5r, "5=NA")
lapop18$smedia8r = car::recode(lapop18$smedia8r, "5=NA")
Luego, estas variables se tienen que etiquetar y generar las tablas
descriptivas básicas, con el comando table
.
levels(lapop18$smedia2r) <- c("Diariamente", "Algunas veces a la semana",
"Algunas veces al mes", "Algunas veces al año")
levels(lapop18$smedia5r) <- c("Diariamente", "Algunas veces a la semana",
"Algunas veces al mes", "Algunas veces al año")
levels(lapop18$smedia8r) <- c("Diariamente", "Algunas veces a la semana",
"Algunas veces al mes", "Algunas veces al año")
table(lapop18$smedia2r)
##
## Diariamente Algunas veces a la semana Algunas veces al mes
## 8633 4927 1286
## Algunas veces al año
## 282
table(lapop18$smedia5r)
##
## Diariamente Algunas veces a la semana Algunas veces al mes
## 795 728 422
## Algunas veces al año
## 193
table(lapop18$smedia8r)
##
## Diariamente Algunas veces a la semana Algunas veces al mes
## 14151 2646 495
## Algunas veces al año
## 50
Para calcular las tablas con porcentajes, redondeados a un decimal,
usamos prop.table
y round
. Nuevamente, estos
porcentajes no son exactamente iguales a los presentados en el reporte
debido a que estos cálculos no incluyen el factor de expansión.
round(prop.table(table(lapop18$smedia2r)), 3)*100
##
## Diariamente Algunas veces a la semana Algunas veces al mes
## 57.1 32.6 8.5
## Algunas veces al año
## 1.9
round(prop.table(table(lapop18$smedia5r)), 3)*100
##
## Diariamente Algunas veces a la semana Algunas veces al mes
## 37.2 34.1 19.7
## Algunas veces al año
## 9.0
round(prop.table(table(lapop18$smedia8r)), 3)*100
##
## Diariamente Algunas veces a la semana Algunas veces al mes
## 81.6 15.3 2.9
## Algunas veces al año
## 0.3
Para presentar todos los datos en una tabla conjunta, se guarda la
tabla de cada red social en un nuevo objeto de R (llamado como cada red
social). Luego, todas estas tablas parciales, que contienen las mismas
opciones de respuesta, se unen como filas con el comando
rbind
. Esta nueva tabla conjunta se guarda como un nuevo
dataframe “tabla”.
Facebook <- round(prop.table(table(lapop18$smedia2r)), 3)*100
Twitter <- round(prop.table(table(lapop18$smedia5r)), 3)*100
Whatsapp <- round(prop.table(table(lapop18$smedia8r)), 3)*100
tabla <- as.data.frame(rbind(Facebook, Twitter, Whatsapp))
tabla
Para tener una mejor presentación de la tabla, se puede usar el
comando kable
del paquete knitr
o el comando
formattable
del paquete del mismo nombre.
library(knitr)
kable(head(tabla), format="markdown", digits=1)
Facebook |
57.1 |
32.6 |
8.5 |
1.9 |
Twitter |
37.2 |
34.1 |
19.7 |
9.0 |
Whatsapp |
81.6 |
15.3 |
2.9 |
0.3 |
library(formattable)
formattable(tabla)
|
Diariamente
|
Algunas veces a la semana
|
Algunas veces al mes
|
Algunas veces al año
|
Facebook
|
57.1
|
32.6
|
8.5
|
1.9
|
Twitter
|
37.2
|
34.1
|
19.7
|
9.0
|
Whatsapp
|
81.6
|
15.3
|
2.9
|
0.3
|
Para graficar esta variable no vamos a seguir el mismo procedimiento
que en el módulo anterior. En este módulo vamos a trabajar directamente
desde la tabla creada con los porcentajes de las tres redes sociales.
Esta tabla tiene a cada red social en las filas y las opciones de
respuesta en las columnas. Para poder graficar estos datos se requiere
que las redes sociales estén en las columnas y las opciones de respuesta
en las filas, por lo que en primer lugar vamos a transponer esta tabla.
Este procedimiento lo hacemos usando la librería data.table
y el comando transpose
. Estos datos transpuestos los
guardamos en una nueva tabla “tabla_tr”.
Este comando transpone los datos, pero deja sin nombrar las filas y
columnas. Primero se nombran las columnas con el comando
colnames
usando los nombres de las filas de “tabla”. Luego
se nombran las filas con el comando rownames
usando los
nombres de las columnas de “tabla”.
Finalmente, requerimos una columna dentro de “tabla_tr” que incluya
las etiquetas de respuesta de las preguntas de smedia. Estas etiquetas
están como nombres de filas. Para incluirlas como una variable más, se
agrega una variable “tabla_tr$lab” al que se le asigna los nombres de
las filas con row.names
.
library(data.table)
tabla_tr = data.frame(t(tabla[]))
colnames(tabla_tr) = rownames(tabla)
rownames(tabla_tr) = colnames(tabla)
tabla_tr$lab <- rownames(tabla_tr)
tabla_tr
En segundo lugar, se activa la librería ggplot2
para
graficar los datos guardados en “tabla_tr” con el comando
ggplot
. Dentro de este comando se especifica que se
trabajará con el dataframe “tabla_tr” (no con lapop18) y se especifica
la “estética”, es decir que en el eje X no se incluirá una variable, que
en el eje Y se incluirá los datos de “Facebook” del dataframe “tabla_tr”
y que se dividirá por categorías de la variable guardadas en “lab”.
Luego se añade la capa geom_bar
para indicar que se
graficará en barras de ancho (width
) 1 y que la barra
replicará lo especificado en la estética (stat="identity"
).
Con geom_text
se agrega las etiquetas de los datos, con el
símbolo de porcentaje, y se especifica la posición del texto con
position=position_stack(…)
y el tamaño con
size=3
. Con coord_polar
se transforma las
barras en un gráfico circular de sectores. Finalmente, se define el
“tema” con theme_void
indicando un fondo blanco y se
modifica la etiqueta de la leyenda con
scale_fill_discrete
.
library(ggplot2)
ggplot(data=tabla_tr, aes(x="", y=Facebook, fill=lab))+
geom_bar(width=1, stat="identity")+
geom_text(aes(label=paste(Facebook, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
coord_polar("y", start=0)+
theme_void()+
scale_fill_discrete(name="Frecuencia de uso de Facebook")
En el gráfico 3.3 del reporte “El Pulso de la Democracia” se presenta
un gráfico circular tipo “donna”. Para reproducir exactamente este tipo
de gráfico, se tiene que acomodar unos detalles de la sintaxis anterior.
Se establece “x=2” en la “estética” y se establece límites en el eje X,
entre 0.5 y 2.5, para que cuando se rote el eje, se cree el “hueco”
dentro del círculo.
ggplot(data=tabla_tr, aes(x=2, y=Facebook, fill=lab))+
geom_bar(stat="identity")+
geom_text(aes(label=paste(Facebook, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
coord_polar("y")+
theme_void()+
scale_fill_discrete(name="Frecuencia de uso de Facebook")+
labs(title="Frecuencia con la que ve contenido en Facebbok",
caption="Barómetro de las Américas por LAPOP, 2018/19")+
xlim(0.5, 2.5)
Para replicar el gráfico de barras, se hacen algunas modificaciones
en el código anterior. Por ejemplo, en la “estética”, ahora se indica
que en el eje X va la variable “smedia2r” y en el eje Y el porcentaje
“per”. Se elimina, además, la especificación de las coordenadas polares.
Se agrega un título al gráfico, etiquetas a los ejes y un caption con la
especificación labs
. Finalmente, se define el eje Y entre 0
y 60 con la especificación coord_cartesian
. Un tema
importante es que este gráfico también se puede guardar en un objeto en
R, que llamaremos “graf1”.
graf1 <- ggplot(tabla_tr, aes(x=lab, y=Facebook))+
geom_bar(stat="identity", width=0.5)+
geom_text(aes(label=paste(Facebook, "%", sep="")), color="black", vjust=-0.5)+
labs(title="Frecuencia de uso de redes sociales", x="Frecuencia de uso de Facebook", y="Porcentaje", caption="Barómetro de las Américas por LAPOP, 2018/19")+
coord_cartesian(ylim=c(0, 60))
graf1
Guardar un gráfico en un objeto nos permite luego incorporar más
capas o mejoras en el gráfico. El gráfico anterior, por ejemplo, tiene
las etiquetas de “Frecuencia de uso” en una sola línea, por lo se
podrían trasponer. Para mejorar esta visualización se puede inclinar
estas etiquetas, pero si se quisiera mantener la horizontalidad para
facilitar la lectura, lo que se puede hacer es separar las etiquetas
largas en dos o más líneas. Esto se puede hacer, por ejemplo, creando un
vector con las nuevas etiquetas. Las etiquetas largas se pueden partir
en líneas mediante la inclusión de \n
entre los textos que
se quiera separar. Luego, al objeto “graf1” se le puede agregar una
nueva capa para reemplazar las etiquetas con las nuevas divididas en
líneas. Esto se hace con la especificación scale_x_discrete
donde se indica que las etiquetas usen el vector creado.
etiq <- c("Diariamente", "Algunas veces\na la semana", "Algunas veces\nal mes",
"Algunas veces\nal año")
graf1 +
scale_x_discrete(labels=etiq)
De esta manera el gráfico queda más legible. Hasta aquí se ha
replicado las tablas y gráficos que se usaron con las variables
nominales, ahora usando variables ordinales. Si se quiere replicar el
gráfico circular de las otras redes sociales, se puede ejecutar el mismo
código, pero cambiando la columna de la red social. Para Twitter, por
ejemplo, se tendría.
graf2 <- ggplot(data=tabla_tr, aes(x=2, y=Twitter, fill=lab))+
geom_bar(stat="identity")+
geom_text(aes(label=paste(Twitter, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
coord_polar("y")+
theme_void()+
scale_fill_discrete(name="Frecuencia de uso de Twitter")+
labs(title="Frecuencia con la que ve contenido en Twitter",
caption="Barómetro de las Américas por LAPOP, 2018/19")+
xlim(0.5, 2.5)
graf2
Cruce de variables
En la tabla 3.1 (pag. 55) del reporte “El pulso de la democracia” se
presenta los porcentajes de uso de las redes sociales por país. Luego,
en la página 56 se presenta un cuadro con el porcentaje de usuarios de
redes sociales por características sociodemográficas, por ejemplo,
urbano/rural, hombre, edad promedio, riqueza promedio y años de
estudio.
Empezaremos replicando los datos generales del uso de redes sociales
que se reporta en el gráfico 3.1. Para replicar esta tabla primero se
tiene que definir la variable “pais” y las variables de uso de redes
sociales (smedia1, smedia4 y smedia7).
lapop18$smedia1r = as.factor(lapop18$smedia1)
lapop18$smedia4r = as.factor(lapop18$smedia4)
lapop18$smedia7r = as.factor(lapop18$smedia7)
levels(lapop18$smedia1r) <- c("Sí", "No")
levels(lapop18$smedia4r) <- c("Sí", "No")
levels(lapop18$smedia7r) <- c("Sí", "No")
lapop18$pais = as.factor(lapop18$pais)
levels(lapop18$pais) <- c("México", "Guatemala", "El Salvador", "Honduras",
"Nicaragua","Costa Rica", "Panamá", "Colombia",
"Ecuador", "Bolivia", "Perú", "Paraguay",
"Chile", "Uruguay", "Brasil", "Argentina",
"Rep. Dom.", "Jamaica")
table(lapop18$pais) #País
##
## México Guatemala El Salvador Honduras Nicaragua Costa Rica
## 1580 1596 1511 1560 1547 1501
## Panamá Colombia Ecuador Bolivia Perú Paraguay
## 1559 1663 1533 1682 1521 1515
## Chile Uruguay Brasil Argentina Rep. Dom. Jamaica
## 1638 1581 1498 1528 1516 1513
table(lapop18$smedia1r) #Facebook
##
## Sí No
## 15389 11573
Sin embargo, la variable “usuario” de cada red social se calcula como
condición de dos variables, como se vio en el documento sobre manejo de
datos, con el siguiente código.
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)
Esta variables son graficadas en el reporte en el Gráfico 3.1. Para
reproducir estos datos, se puede describir estas variables.
prop.table(table(lapop18$fb_user))*100
##
## 0 1
## 43.8289 56.1711
prop.table(table(lapop18$tw_user))*100
##
## 0 1
## 92.056769 7.943231
prop.table(table(lapop18$wa_user))*100
##
## 0 1
## 35.76561 64.23439
Como en gráficos anteriores, con estos datos se puede crear un
dataframe que se utilizaría para hacer los gráficos circulares mostrados
en el reporte.
Para replicar el cuadro de uso de redes sociales por país, primero,
se crean las tablas bivariadas con el porcentaje de los que usan y el
porcentaje de los que no usan cada red social en cada país. Estas tablas
se guardan en objetos de R. Luego se unen estos objetos usando los
comandos cbind
para juntar las columnas y
as.data.frame
para unir las tablas como un dataframe. Esta
tabla presenta también los porcentajes de los que No usan estas redes
sociales. Para presentar una tabla que incluya solo a los que sí usan
las redes sociales, se eliminan estas columnas, usando la especificación
[, c(-1,-3,-5)]
, que indica que se quiere eliminar las
columnas 1, 3 y 5.Finalmente, se cambia el nombre de las columnas del
dataframe.
fbpais <- round(prop.table(table(lapop18$pais, lapop18$fb_user), 1), 3)*100
twpais <- round(prop.table(table(lapop18$pais, lapop18$tw_user), 1), 3)*100
whpais <- round(prop.table(table(lapop18$pais, lapop18$wa_user), 1), 3)*100
tablapais <- as.data.frame(cbind(fbpais, twpais, whpais))
tablapais <- tablapais[, c(-1,-3,-5)]
varnames <- c("Usa Facebook", "Usa Twitter", "Usa Whatsapp")
colnames(tablapais) <- varnames
tablapais
Para tener una mejor presentación de la tabla se tienen dos
alternativas: la primera con la librería knitr
y la otra
con la librería formattable
.
library(knitr)
kable(head(tablapais), format="markdown", digits=1)
México |
47.9 |
7.6 |
55.1 |
Guatemala |
43.2 |
6.5 |
47.6 |
El Salvador |
56.2 |
6.7 |
56.0 |
Honduras |
44.6 |
4.8 |
46.9 |
Nicaragua |
48.1 |
5.8 |
47.7 |
Costa Rica |
66.6 |
8.0 |
81.6 |
library(formattable)
formattable(tablapais)
|
Usa Facebook
|
Usa Twitter
|
Usa Whatsapp
|
México
|
47.9
|
7.6
|
55.1
|
Guatemala
|
43.2
|
6.5
|
47.6
|
El Salvador
|
56.2
|
6.7
|
56.0
|
Honduras
|
44.6
|
4.8
|
46.9
|
Nicaragua
|
48.1
|
5.8
|
47.7
|
Costa Rica
|
66.6
|
8.0
|
81.6
|
Panamá
|
34.6
|
5.8
|
56.7
|
Colombia
|
60.0
|
10.7
|
63.5
|
Ecuador
|
66.9
|
11.2
|
60.2
|
Bolivia
|
57.9
|
5.6
|
63.5
|
Perú
|
61.4
|
7.6
|
58.6
|
Paraguay
|
60.5
|
8.0
|
69.2
|
Chile
|
62.9
|
9.2
|
75.5
|
Uruguay
|
66.5
|
9.8
|
80.0
|
Brasil
|
59.2
|
7.9
|
74.9
|
Argentina
|
67.3
|
12.9
|
78.9
|
Rep. Dom.
|
61.9
|
9.5
|
68.2
|
Jamaica
|
45.9
|
4.5
|
68.1
|
Cruce con variables sociodemográficas
En la página 56 del reporte “El pulso de la democracia” se presenta
los resultados del cruce entre las variables uso de redes sociales y
variables sociodemográficas como urbano/rural, sexo, edad, riqueza y
años de educación.
La variable “q1” registra el género del entrevistado. Esta variable
está codificada de la siguiente manera:
- Hombre
- Mujer
Para construir una variable “dummy” llamada “hombre”, de tal manera
que hombre sea 1 y mujer sea 0, una forma de hacerlo es de manera
algebraica (2-variable q1). De esta manera, ahora los hombres mantiene
el valor 1 (2-1) y las mujeres pasar a ser 0 (2-2). En este caso, la
nueva variable “hombre” se crea como una una variable numérica. Vamos a
mantener a la variable como “num” para, más abajo, poder calcular la
media de esta variable (cosa que no se puede hacer de una variable
declarada como factor).
lapop18$hombre <- 2-lapop18$q1
table(lapop18$hombre)
##
## 0 1
## 14084 13943
La variable urbano/rural se llama “ur” en la base de datos y está
codificada de la siguiente manera:
- Urbano
- Rural
De la misma manera que con género, se usa la fórmula 2- variable ur,
pero esta variable sí se convierte en factor y se etiqueta.
lapop18$urban <- 2-lapop18$ur
lapop18$urban = as.factor(lapop18$urban)
levels(lapop18$urban) <- c("Rural", "Urbano")
table(lapop18$urban)
##
## Rural Urbano
## 8089 19953
Se presentará las tablas cruzadas del uso de redes sociales por
alguno de las variable sociodemográficas, para entender mejor cómo se
construye la tabla general. Por ejemplo, el reporte muestra en la Tabla
3.2, luego de la columna de población general, las columnas para
usuarios y no usuarios de Whatsapp (variable “wa_user”) y en las filas,
la primera corresponde a urbano (variable “urban”, donde 0 es rural y 1
urbano). Se presenta que entre los usuarios de Whatsapp, el 76.7% son
urbanos y entre los no usuarios, el 62% son urbanos. Estos datos se
generan con el comando table
que permite hacer una tabla de
contingencia de 2 variables. En este caso se tiene que notar que cada
variable tiene un título. De esta manera el comando es
table(título1 = var1, título2 = var2)
. Luego, se usa el
comando prop.table
para que no se muestre las
observaciones, sino los porcentajes. Este comando permite calcular los
porcentajes sobre el total (la opción por defecto), sobre las filas y
sobre las columnas. Para calcular sobre las columnas se debe especificar
prop.table(table(...), 2)
. Si se quisiera el porcentaje
sobre las filas, el código sería prop.table(table(...), 1)
.
Esta tabla se pueden guardar como un dataframe con el comando
as.data.frame
en un nuevo objeto “t1”.
t1 <- as.data.frame(round(prop.table(table(Urbano = lapop18$urban, Usuario = lapop18$wa_user), 2)*100, 1))
t1
La filas correspondientes a “Urbano” de esta tabla reproducen los
datos de la Tabla 3.2: 62.1% son urbanos entre los no usuarios de
Whatsapp y 76.7% son urbanos entre los usuarios.
Ahora se presentará la tabla entre usuarios de Facebook (variable
“fb_user”) y hombre (variable “hombre”), pero presentando solo los
porcentajes usados en la tabla y ahora usando el estilo de código del
Tidyverse, usando el operador “pipe”. Lo primero es definir la variable
“fb_user” como un factor y etiquetarla. Luego, se usa el comando
subset
para filtrar los casos perdidos en la variable
“fb_user”. Luego se pide que los resultados se agrupen por categorías de
la variable “fb_user”. Con el comando summarise
se guarda
en la columna “hombre” el promedio de la variable “hombre”, con el
comando mean
que incluye la especificación
na.rm=T
para no incluir en el cálculo los valores perdidos.
En este caso se aprovecha que la variable “hombre” es una variable
dummy, de tal manera que el promedio corresponde a la proporción de
hombres.
lapop18$fb_user = as.factor(lapop18$fb_user)
levels(lapop18$fb_user) <- c("No usuario", "Usuario")
tabla1 <- subset(lapop18, !is.na(fb_user)) %>% #Para no incluir al grupo de NA de usuarios de Facebook
group_by(fb_user) %>%
dplyr::summarise(Hombre=mean(hombre, na.rm=T)*100) #Se incluye na.rm=T porque hombre tiene NAs
tabla1
Estos son los porcentajes para los usuarios de Facebook, en la fila
de la variable Hombre de la Tabla 3.2. Es decir, entre los no usuarios,
49.9% son hombres y entre los usuarios este porcentaje es 49.7%. Hasta
aquí se ha reconstruido algunos resultados de la Tabla 3.2. Los demás
datos pueden seguir siendo reconstruidos mediante combinaciones de las
variables de usuarios de redes sociales y las variables
sociodemográficas.
Gráfico de barras de dos variables
El cruce entre usuarios de Whatsapp y la variable urbano se puede ver
también en un gráfico de barras agrupadas. Lo primero que haremos es
definir la variable “wa_user” como factor y etiquetarla. Luego, se
requiere crear una tabla con los datos agrupados. Se puede usar el
dataframe “t1” creado anteriormente, pero aquí usaremos nuevamente el
operador “pipe” para recrear los datos. Para esto, se agrupa tanto por
uso de Whatsapp como por urbano/rural, es decir, en cuatro
combinaciones. En cada subgrupo se calcula el n. Dado que los % se
tienen que calcular por cada grupo de “wa_user”, se vuelve a agrupar y
se calcula los % de cada subgrupo, de tal manera que los porcentajes
sumen 100% en cada subgrupo de “wa_user”.
lapop18$wa_user = as.factor(lapop18$wa_user)
levels(lapop18$wa_user) <- c("No usuario", "Usuario")
face <- subset(lapop18, !is.na(wa_user)) %>% #Se usa !is.na para que no se reporte los NA en la tabla
group_by(wa_user, urban) %>% #Se configuran los grupos
dplyr::count() %>% #Se calcula el n
group_by(wa_user) %>% #Se agrupa por usuario de Whatsapp
dplyr::mutate(porcentaje = round(n/sum(n), 3)*100) #Se calcula el porcentaje en cada grupo de Whatsapp
face
Los datos se esta nueva tabla son exactamente iguales a los de “t1”.
Con la tabla lista, se usa el comando ggplot
definiendo que
“wa_user” sea la variable en el eje X, que el eje Y sea el porcentaje y
que los subgrupos se formen por la variable “urban” con la
especificación fill
. Se usa la especificación
dodge
en geom_bar
para tener las barras
separadas por cada grupo.
ggplot(data=face, aes(x=wa_user, y=porcentaje, fill=urban, ymax=100))+
geom_bar(position="dodge", stat="identity")+
geom_text(aes(label=paste(porcentaje, "%", sep="")),
position=position_dodge(width=0.9), vjust=-0.25)+
ylab("Porcentaje")+
xlab("Usuario de Whatsapp")
Si quisiéramos hacer el gráfico con barras apiladas, se tiene que
cambiar la especificación de position="stack"
en
geom_bar
y la especificación
position=position_stack()
de geom_text
.
ggplot(data=face, aes(x=wa_user, y=porcentaje, fill=urban, ymax=100))+
geom_bar(position="stack", stat="identity")+
geom_text(aes(label=paste(porcentaje, "%", sep="")),
position=position_stack(), vjust=2.5)+
ylab("Porcentaje")+
xlab("Usuario de Whatsapp")
En ambos casos las barras celestes indican los porcentajes reportados
en la tabla 3.2 del reporte y corresponden a la proporción de personas
que viven en el ámbito urbano entre los usuarios y los no usuarios.
Cálculos incluyendo el efecto de diseño
Ejemplo con datos de la ronda 2021
Con los datos de la ronda 2021 del Barómetro de las Américas, hemos
calculado los porcentajes de la variable que mide si los votos se han
contado justamente. El gráfico que hemos creado ha sido para el total de
la muestra, es decir, de todos los países. El Gráfico 2.5 del reporte El
Pulso de la Democracia presenta los resultados para cada país.
Si calculáramos los porcentajes con el comando table
y
prop.table
tendríamos resultados diferentes a los mostrados
en el gráfico. Por ejemplo, en el país 5, que es Nicaragua, los
resultados indican que 26% de ciudadanos de ese país indica que los
votos siempre se cuentan justamente, 49% que algunas veces se cuentan
justamente y 24.4% que nunca. Sin embargo, el gráfico indica que en
Nicaragua, 29% indica que nunca de cuenta justamente, 45% indica que
algunas veces y 25% que siempre. Estos porcentajes no corresponden a los
que se encuentran con estos comandos.
round(prop.table(table(lapop21$pais, lapop21$countfair1r), 1), 3)*100
##
## Siempre Algunas veces Nunca
## 1
## 2
## 3
## 4
## 5 26.2 49.4 24.4
## 6 52.3 40.2 7.5
## 7 27.6 57.1 15.4
## 8 18.1 50.4 31.5
## 9 21.5 59.1 19.4
## 10 24.5 59.2 16.3
## 11 25.1 61.1 13.8
## 12 25.9 48.3 25.8
## 13 64.1 30.1 5.8
## 14 80.0 16.9 3.0
## 15 48.1 35.7 16.1
## 17 31.5 51.0 17.5
## 21 25.2 60.1 14.7
## 22
## 23 17.9 67.9 14.2
## 24 17.0 65.1 17.8
Esta diferencia es debido a que los comandos table
y
prop.table
no incluyen el efecto de diseño y el factor de
expansión en los cálculos. Más información sobre estas diferencias se
encuentra aquí.
Para replicar los resultados del Gráfico 2.5 hay algunas opciones. La
primera es mediante la librería especializada survey
.
Para poder usar esta librería, primero debemos preparar la base de
datos, eliminando los valores perdidos de las variables que definen el
diseño. Un paso adicional es transformar las variables del dataframe.
Esto es debido a que cuando se importan, el sistema lee las variables
como tipo “haven_labelled”, es decir, mantiene las etiquetas de las
variables, con lo que se podría producir un libro de códigos. Esto es
útil en otras ocasiones, pero genera problemas con la librería
survey
. Para esto transformamos las variables a otro tipo
con el comando sapply
.
lapop21 = subset(lapop21, !is.na(weight1500))
sapply(lapop21, haven::zap_labels)
Una vez preparada la base de datos, se activa la librería y se define
el diseño. En el módulo anterior, también usamos esta librería para
calcular los resultados con el efecto de diseño en la ronda 2018. A
diferencia de ese código, es que la ronda 2021 del Barómetro de las
Américas utilizó la modalidad telefónica, y no cara a cara, por lo que
ahora la unidad primaria de muestreo es el individuo, y así está
definida en la variable “upm”. La variable que define los estratos es
“strata” (y no “estratopri” como en la ronda 2018). La variable de
ponderación sigue siendo “weight1500”.
Con estos datos calculamos guardamos el diseño en un objeto
“diseno21”.
library(survey)
diseno21 = svydesign(ids = ~upm, strata = ~strata, weights = ~weight1500, nest=TRUE, data=lapop21)
La librería survey
incluye comandos nativos para hacer
múltiples operaciones que incluyan el efecto de diseño. Uno de esos
comandos es svytable
que nos permite hacer la tabla cruzada
entre la variable “countfair1r” y “pais”, especificando el diseño. Este
comando nos devuelve las frecuencias absolutas ponderadas, por lo que se
puede anidar en el comando prop.table
para calcular los
porcentajes desde las frecuencias absolutas ponderadas y dentro del
comando count
para redondear los porcentajes, y dentro del
comando as.data.table
para guardar la tabla en un objeto
“votoxpais” como un dataframe, que nos permita la manipulación con
ggplot
luego.
votoxpais = as.data.frame(round(prop.table(svytable(~pais+countfair1r, design=diseno21), 1)*100, 0))
votoxpais$pais = pais
votoxpais
ggplot(data=votoxpais, aes(fill=countfair1r, x=Freq, y=pais))+
geom_bar(stat="identity", width=0.3)+
geom_text(aes(label=paste(Freq, "%", sep="")), color="white",
position=position_stack(vjust=0.5), size=3)+
labs(x="Porcentaje", y="País", fill="Los votos se cuentan justamente",
caption="Barómetro de las Américas por LAPOP, 2021")
Este gráfico reproduce exactamente los resultados mostrados en el
Gráfico 2.5 del reporte, aunque en un orden diferente.
Ejemplo con los datos de la ronda 2018/19
La pequeña diferencia entre los porcentajes que se muestran en el
Gráfico 3.3 y los mostrados en la sección “Describir las variables”
puede deberse a que en todos las tablas y gráficos anteriores no se
incluye el factor de expansión. Si se incluyera, usando la variable
“weight1500”, se replicarían los porcentajes mostrados en el informe.
Por ejemplo, para el uso de Whatsapp, se puede usar el comando
freq
de la librería descr
que permite incluir
una variable de ponderación.
Esta tabla luego se puede guardar en un dataframe, al que se le
pueden eliminar las filas y columnas que no se requieren, y se les puede
cambiar el nombre a las columnas. y agregar las etiquetas.
tabla2 <- as.data.frame(descr::freq(lapop18$smedia8r, lapop18$weight1500, plot=F))
tabla2 <- tabla2[-c(5,6), -2]
colnames(tabla2) <- c("frec", "per")
tabla2$lab <- rownames(tabla2)
tabla2
Con este nuevo dataframe, se puede replicar el gráfico de Whatsapp,
con los datos ponderados, usando el código de ggplot
.
ggplot(data=tabla2, 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()+
scale_fill_discrete(name="Frecuencia de uso de Facebook")+
labs(title="Frecuencia con la que ve contenido en Facebook",
caption="Barómetro de las Américas por LAPOP, 2018/19")+
xlim(0.5, 2.5)
Además del comando freq
, también se puede usar la
librería survey
y el comando nativo
svytable
.
library(survey)
diseno18<-svydesign(ids = ~upm, strata = ~estratopri, weights = ~weight1500, nest=TRUE, data=lapop18)
Los resultados que se obtienen son iguales que con el método anterior
y a los presentados en el reporte. Estos resultados también se pueden
guardar en un “dataframe” para hacer el gráfico.
prop.table(svytable(~smedia8r, design=diseno18))*100
## smedia8r
## Diariamente Algunas veces a la semana Algunas veces al mes
## 81.6626475 15.2056787 2.8473540
## Algunas veces al año
## 0.2843197
La sección “Cruce con variables” presenta los datos de usuarios de
redes sociales por país. Para construir la tabla considerando el efecto
de diseño, también se puede usar el comando nativo svytable
que permite calcular una tabla bivariada. De la misma manera que en caso
no ponderado, las tablas parciales de cada red social se guardan en unos
objetos de tipo lista, los que se juntan como un “dataframe” y se edita
para presentar solo los datos de los usuarios de cada red social por
país.
fbpais_2 <- round(prop.table(svytable(~pais+fb_user, design=diseno18), 1), 3)*100
twpais_2 <- round(prop.table(svytable(~pais+tw_user, design=diseno18), 1), 3)*100
wapais_2 <- round(prop.table(svytable(~pais+wa_user, design=diseno18), 1), 3)*100
tablapais_2 <- as.data.frame(cbind(fbpais_2, twpais_2, wapais_2))
tablapais_2 <- tablapais_2[, c(-1,-3,-5)]
varnames <- c("Usa Facebook", "Usa Twitter", "Usa Whatsapp")
colnames(tablapais_2) <- varnames
tablapais_2
Por último, la sección “Cruce con variables sociodemográficas”
reproduce los resultados de la Tabla 3.2 del reporte. De la misma manera
que en el caso anterior, se puede usar el comando nativo
svytable
para realizar el cruce entre las variables de uso
de redes sociales y la variable urbano. Los resultados de la fila Urbano
en cada red social corresponderían a la primera fila de resultados de la
Tabla 3.2.
round(prop.table(svytable(~urban+wa_user, design=diseno18), 2), 3)*100
## wa_user
## urban No usuario Usuario
## Rural 38.0 23.3
## Urbano 62.0 76.7
round(prop.table(svytable(~urban+fb_user, design=diseno18), 2), 3)*100
## fb_user
## urban No usuario Usuario
## Rural 35.6 23.0
## Urbano 64.4 77.0
round(prop.table(svytable(~urban+tw_user, design=diseno18), 2), 3)*100
## tw_user
## urban 0 1
## Rural 29.7 15.3
## Urbano 70.3 84.7
De esta manera se pueden calcular las tablas de distribución de
frecuencias y las tablas bivariadas (o de contingencia) incluyendo el
efecto de diseño o el factor de expansión.
LS0tCnRpdGxlOiAiRXN0YWTDrXN0aWNhIGRlc2NyaXB0aXZhIHVzYW5kbyBlbCBCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgKDIpIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICB0b2NfZGVwdGg6IDEKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBmbGF0bHkKICAgIGRmX3ByaW50OiBwYWdlZAogICAgc2VsZl9jb250YWluZWQ6IG5vCiAgICBrZWVwX21kOiB5ZXMKICAgICNjb2RlX2ZvbGRpbmc6IGhpZGUKZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IHNlbnRlbmNlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsIGNhY2hlPVRSVUUpCmBgYAoKYGBge2NzcyBjb2xvciwgZWNobz1GQUxTRX0KLmNvbHVtbnMge2Rpc3BsYXk6IGZsZXg7fQpoMSB7Y29sb3I6ICMzMzY2Q0M7fQpgYGAKCiMgSW50cm9kdWNjacOzbgoKRW4gZXN0ZSBkb2N1bWVudG8gdmFtb3MgYSBjb250aW51YXIgdXNhbmRvIGVsIMO6bHRpbW8gaW5mb3JtZSByZWdpb25hbCAiRWwgcHVsc28gZGUgbGEgZGVtb2NyYWNpYSIsIGRpc3BvbmlibGUgW2FxdcOtXShodHRwczovL3d3dy52YW5kZXJiaWx0LmVkdS9sYXBvcC9hYjIwMTgvMjAxOC0xOV9BbWVyaWNhc0Jhcm9tZXRlcl9SZWdpb25hbF9SZXBvcnRfU3BhbmlzaF9XXzAzLjI3LjIwLnBkZiksIGRvbmRlIHNlIHByZXNlbnRhbiBsb3MgcHJpbmNpcGFsZXMgaGFsbGF6Z29zIGRlIGxhIHJvbmRhIDIwMTgvMTkgZGVsIEJhcsOzbWV0cm8gZGUgbGFzIEFtw6lyaWNhcy4KVW5hIGRlIGxhcyBzZWNjaW9uZXMgZGUgZXN0ZSBpbmZvcm1lLCByZXBvcnRhIGxvcyBkYXRvcyBzb2JyZSByZWRlcyBzb2NpYWxlcyB5IGFjdGl0dWRlcyBwb2zDrXRpY2FzLgpFbiBlc3RhIHNlY2Npw7NuLCBzZSBwcmVzZW50YW4gZGF0b3Mgc29icmUgZWwgdXNvIGRlIGludGVybmV0IHkgZWwgdXNvIGRlIHJlZGVzIHNvY2lhbGVzLCBlbiBnZW5lcmFsIHkgcG9yIHBhw61zLgpFbiBlc3RlIGNhc28gdmFtb3MgYSB0cmFiYWphciBjb24gbGEgZnJlY3VlbmNpYSBkZSB1c28gZGUgbGFzIHJlZGVzIHNvY2lhbGVzLgpFbiBlc3RlIGRvY3VtZW50byB2YW1vcyBhIGFuYWxpemFyIGRlc2NyaXB0aXZhbWVudGUgZXN0YXMgdmFyaWFibGVzIHNvYnJlIGZyZWN1ZW5jaWEgZGUgdXNvIGRlIHJlZGVzIHNvY2lhbGVzLCB2YXJpYWJsZXMgZGUgdGlwbyBvcmRpbmFsIChvIGRlIGZhY3RvciwgZW4gZWwgbGVuZ3VhamUgZGUgUikuCgojIFNvYnJlIGxhIGJhc2UgZGUgZGF0b3MKCkxvcyBkYXRvcyBxdWUgdmFtb3MgYSB1c2FyIGRlYmVuIGNpdGFyc2UgZGUgbGEgc2lndWllbnRlIG1hbmVyYTogRnVlbnRlOiBCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgcG9yIGVsIFByb3llY3RvIGRlIE9waW5pw7NuIFDDumJsaWNhIGRlIEFtw6lyaWNhIExhdGluYSAoTEFQT1ApLCB3d3d3LkxhcG9wU3VydmV5cy5vcmcuCkVuIGVzdGUgZG9jdW1lbnRvIHNlIGNhcmdhIG51ZXZhbWVudGUgdW5hIGJhc2UgZGUgZGF0b3MgcmVjb3J0YWRhLgpQYXJhIHJlcHJvZHVjaXIgbG9zIHJlc3VsdGFkb3MgbW9zdHJhZG9zIGVuIGVzdGEgc2VjY2nDs24gc2UgZGViZSBsaW1waWFyIGVuIEVudmlyb25tZW50LgoKRXN0YSBiYXNlIGRlIGRhdG9zIHNlIGVuY3VlbnRyYSBhbG9qYWRhIGVuIGVsIHJlcG9zaXRvcmlvICJtYXRlcmlhbHNfZWR1IiBkZSBsYSBjdWVudGEgZGUgTEFQT1AgZW4gR2l0SHViLgpNZWRpYW50ZSBsYSBsaWJyZXLDrWEgYHJpb2AgeSBlbCBjb21hbmRvIGBpbXBvcnRgIHNlIHB1ZWRlIGltcG9ydGFyIGVzdGEgYmFzZSBkZSBkYXRvcyBkZXNkZSBlc3RlIHJlcG9zaXRvcmlvLgpBZGVtw6FzLCBzZSBzZWxlY2Npb25hbiBsb3MgZGF0b3MgZGUgcGHDrXNlcyBjb24gY8OzZGlnb3MgbWVub3JlcyBvIGlndWFsZXMgYSAzNSwgZXMgZGVjaXIsIHNlIGVsaW1pbmEgbGFzIG9ic2VydmFjaW9uZXMgZGUgRXN0YWRvcyBVbmlkb3MgeSBDYW5hZMOhLgoKYGBge3IgYmFzZX0KbGlicmFyeShyaW8pCmxhcG9wMTggPC0gaW1wb3J0KCJodHRwczovL3Jhdy5naXRodWIuY29tL2xhcG9wLWNlbnRyYWwvbWF0ZXJpYWxzX2VkdS9tYWluL0xBUE9QX0FCX01lcmdlXzIwMThfdjEuMC5zYXYiKQpsYXBvcDE4IDwtIHN1YnNldChsYXBvcDE4LCBwYWlzPD0zNSkKYGBgCgpUYW1iacOpbiBjYXJnYW1vcyBsYSBiYXNlIGRlIGRhdG9zIGRlIGxhIHJvbmRhIDIwMjEuCgpgYGB7ciBiYXNlMjF9CmxhcG9wMjEgPSBpbXBvcnQoImxhcG9wMjEuUkRhdGEiKQpsYXBvcDIxIDwtIHN1YnNldChsYXBvcDIxLCBwYWlzPD0zNSkKYGBgCgojIERlc2NyaWJpciB5IGdyYWZpY2FyIGxhcyB2YXJpYWJsZXMKCkVuIGVsIGRvY3VtZW50byBzb2JyZSBlc3RhZMOtc3RpY2EgZGVzY3JpcHRpdmEsIHF1ZSBzZSBwdWVkZSB2ZXIgW2FxdcOtXShodHRwczovL3JwdWJzLmNvbS9hcnR1cm9fbWFsZG9uYWRvLzY5Njc3MCksIHNlIHRyYWJhasOzIGNvbiB2YXJpYWJsZXMgbm9taW5hbGVzLCBjb24gb3BjaW9uZXMgZGUgcmVzcHVlc3RhIGRpY290w7NtaWNhIChTw60vTm8pLgpFbiBlc3RlIGRvY3VtZW50byBzZSB2YSBhIHRyYWJhamFyIGNvbiB2YXJpYWJsZXMgb3JkaW5hbGVzIHBvbGl0w7NtaWNhcy4KCiMgTG9zIHZvdG9zIHNvbiBjb250YWRvcyBjb3JyZWN0YW1lbnRlCgpFbiBlc3RhIHNlY2Npw7NuIHNlIHZhIGEgdXNhciBsYSB2YXJpYWJsZSBDT1VOVEZBSVIxLgpMb3Mgdm90b3Mgc29uIGNvbnRhZG9zIGNvcnJlY3RhIHkganVzdGFtZW50ZS4Kwr9EaXLDrWEgdXN0ZWQgcXVlIHN1Y2VkZSBzaWVtcHJlLCBhbGd1bmFzIHZlY2VzIG8gbnVuY2E/CkVsIGdyw6FmaWNvIDIuNSBkZWwgcmVwb3J0ZSBlbCBQdWxzbyBkZSBsYSBEZW1vY3JhY2lhLCBkaXNwb25pYmxlIFthcXXDrV0oaHR0cHM6Ly93d3cudmFuZGVyYmlsdC5lZHUvbGFwb3AvYWIyMDIxLzIwMjFfTEFQT1BfQW1lcmljYXNCYXJvbWV0ZXJfUHVsc2Vfb2ZfRGVtb2NyYWN5LnBkZiksIHByZXNlbnRhIGxvcyByZXN1bHRhZG9zIGRlIGVzdGEgdmFyaWFibGUgcG9yIHBhw61zLgoKIVtdKEZpZ3VyZTIuNS5wbmcpe3dpZHRoPSI1MTkifQoKRGUgbGEgbWlzbWEgbWFuZXJhIHF1ZSBjb24gbGFzIHZhcmlhYmxlcyBub21pbmFsZXMsIGVzdGFzIHZhcmlhYmxlcyB0aWVuZW4gcXVlIHNlciBkZWNsYXJhZGFzIGNvbW8gImZhY3RvciIgZW4gbnVldmFzIHZhcmlhYmxlcy4KCmBgYHtyIGZhY3RvcjF9CmxpYnJhcnkoaGF2ZW4pCmxhcG9wMjEkY291bnRmYWlyMXIgPSBhcy5mYWN0b3IobGFwb3AyMSRjb3VudGZhaXIxKQpgYGAKCkx1ZWdvLCBlc3RhcyB2YXJpYWJsZXMgc2UgdGllbmVuIHF1ZSBldGlxdWV0YXIgeSBnZW5lcmFyIGxhcyB0YWJsYXMgZGVzY3JpcHRpdmFzIGLDoXNpY2FzLCBjb24gZWwgY29tYW5kbyBgdGFibGVgLgoKYGBge3IgZXRpcXVldGFzMX0KbGV2ZWxzKGxhcG9wMjEkY291bnRmYWlyMXIpIDwtIGMoIlNpZW1wcmUiLCAiQWxndW5hcyB2ZWNlcyIsICJOdW5jYSIpCnRhYmxlKGxhcG9wMjEkY291bnRmYWlyMXIpCmBgYAoKUGFyYSBjYWxjdWxhciBsYXMgdGFibGFzIGNvbiBwb3JjZW50YWplcywgcmVkb25kZWFkb3MgYSB1biBkZWNpbWFsLCB1c2Ftb3MgYHByb3AudGFibGVgIHkgYHJvdW5kYC4KTnVldmFtZW50ZSwgZXN0b3MgcG9yY2VudGFqZXMgbm8gc29uIGV4YWN0YW1lbnRlIGlndWFsZXMgYSBsb3MgcHJlc2VudGFkb3MgZW4gZWwgcmVwb3J0ZSBkZWJpZG8gYSBxdWUgZXN0b3MgY8OhbGN1bG9zIG5vIGluY2x1eWVuIGVsIGZhY3RvciBkZSBleHBhbnNpw7NuLgoKYGBge3IgcG9yY2VudGFqZXMxfQpyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkY291bnRmYWlyMXIpKSwgMykqMTAwCmBgYAoKQ29tbyBzZSBtZW5jaW9uw7MgZW4gbGEgc2VjY2nDs24gYW50ZXJpb3IsIHNlIHB1ZWRlIGdyYWZpY2FyIGVzdGEgdmFyaWFibGUgdXNhbmRvIGVsIGNvbWFuZG8gYGJhcnBsb3RgLgoKYGBge3IgYmFycmFzMX0KYmFycGxvdChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMjEkY291bnRmYWlyMXIpKSoxMDApCmBgYAoKT3RyYSBvcGNpw7NuIGVzIGVsYWJvcmFyIGVsIGdyw6FmaWNvIGRlIGJhcnJhcyB1c2FuZG8gbGEgbGlicmVyw61hIGBnZ3Bsb3RgLgpVbmEgcHJpbWVyYSBvcGNpw7NuIGVzIHRyYWJhamFyIGRpcmVjdGFtZW50ZSBkZSBsYSBiYXNlIGRlIGRhdG9zLgpFbCBzaWd1aWVudGUgY8OzZGlnbywgc2luIGVtYmFyZ28sIG11ZXN0cmEgdW5hIGdyYW4gYmFycmEgZGVsIHBvcmNlbnRhamUgZGUgY2Fzb3MgcGVyZGlkb3MuCkVzdG8gc2UgZGViZSBhIHF1ZSBlc3RhIHByZWd1bnRhIHNlIHJlYWxpesOzIGEgbGEgbWl0YWQgZGUgbGEgbXVlc3RyYS4KU2UgcmVnaXN0cmEgTkEgYSBsYSBvdHJhIG1pdGFkIGEgbGEgcXVlIG5vIHNlIGxlIGhpem8gZXN0YSBwcmVndW50YS4KCmBgYHtyIGdnYmFycmFzMWF9CmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRhdGE9bGFwb3AyMSwgYWVzKHg9Y291bnRmYWlyMXIpKSsKICBnZW9tX2JhcihhZXMoeT0uLnByb3AuLioxMDAsIGdyb3VwPTEpLCB3aWR0aD0wLjUpKwogIGxhYnMoeD0iwr9Mb3Mgdm90b3Mgc29uIGNvbnRhZG9zIGNvcnJlY3RhbWVudGU/IiwgeT0iUG9yY2VudGFqZSIsIAogICAgICAgY2FwdGlvbj0iQmFyw7NtZXRybyBkZSBsYXMgQW3DqXJpY2FzIHBvciBMQVBPUCwgMjAyMSIpKwogIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwgMTAwKSkKYGBgCgpQYXJhIGV2aXRhciBxdWUgZWwgZ3LDoWZpY28gcHJlc2VudGUgbGEgYmFycmEgZGUgTkFzLCBlc3RhcyBvYnNlcnZhY2lvbmVzIHNlIHRpZW5lbiBxdWUgZmlsdHJhciBhbnRlcyBkZSBwcm9kdWNpciBlbCBncsOhZmljby4KVGFsIGNvbW8gaW5kaWNhbW9zIGVuIGVsIG3Ds2R1bG8gYW50ZXJpb3IsIHNlIGZpbHRyYSBsb3MgTkFzIGRlIGxhIHZhcmlhYmxlICJjb3VudGZhaXIxciIgY29uIGVsIGNvbWFuZG8gYHN1YnNldGAgeSBsYSBlc3BlY2lmaWNhY2nDs24gYCFpcy5uYWAuCgpgYGB7ciBnZ2JhcnJhczFifQpnZ3Bsb3QoZGF0YT1zdWJzZXQobGFwb3AyMSwgIWlzLm5hKGNvdW50ZmFpcjFyKSksIGFlcyh4PWNvdW50ZmFpcjFyKSkrCiAgZ2VvbV9iYXIoYWVzKHk9Li5wcm9wLi4qMTAwLCBncm91cD0xKSwgd2lkdGg9MC41KSsKICBsYWJzKHg9IsK/TG9zIHZvdG9zIHNvbiBjb250YWRvcyBjb3JyZWN0YW1lbnRlPyIsIHk9IlBvcmNlbnRhamUiLCAKICAgICAgIGNhcHRpb249IkJhcsOzbWV0cm8gZGUgbGFzIEFtw6lyaWNhcyBwb3IgTEFQT1AsIDIwMjEiKSsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDYwKSkKYGBgCgpPdHJhIG9wY2nDs24sIHF1ZSBzaW1wbGlmaWNhIGVsIGPDs2RpZ28sIGVzIGNyZWFyIHVuYSB0YWJsYSBkZSBmcmVjdWVuY2lhcyBkZSBlc3RhIHZhcmlhYmxlIGNvbiBlbCBjb21hbmRvIGB0YWJsZWAgeSBgcHJvcC50YWJsZWAuCkVzdGEgdGFibGUgc2UgcmVkb25kZWEgYSB1biBkZWNpbWFsIGNvbiBlbCBjb21hbmRvIGByb3VuZGAgeSBzZSBndWFyZGEgY29tbyB1biBkYXRhZnJhbWUgY29uIGVsIGNvbWFuZG8gYGFzLmRhdGEuZnJhbWVgIGVuIHVuIG9iamV0byAiY291bnQiLgpFc3RhIHRhYmxhIGFsbWFjZW5hIGRvcyBjb2x1bW5hcywgbGEgcHJpbWVyYSBsbGFtYWRhICJWYXIxIiBjb24gbGFzIGV0aXF1ZXRhcyBkZSBsYSB2YXJpYWJsZSB5IGxhIHNlZ3VuZGEgbGxhbWFkYSAiRnJlcSIgY29uIGxvcyBwb3JjZW50YWplcy4KCmBgYHtyIHRhYmxhMWF9CmNvdW50IDwtIGFzLmRhdGEuZnJhbWUocm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDIxJGNvdW50ZmFpcjFyKSksIDMpKjEwMCkKY291bnQKYGBgCgpQb2RlbW9zIHVzYXIgZXN0YSB0YWJsYSAiY291bnQiIHBhcmEgcHJvZHVjaXIgZWwgZ3LDoWZpY28gZGUgYmFycmFzIGNvbiBlbCBjb21hbmRvIGBnZ3Bsb3RgLgpFbiBsYSBlc3BlY2lmaWNhY2nDs24gYGFlc2Agc2UgZGVmaW5lIHF1ZSBsb3MgdmFsb3JlcyBkZSBsYSBjb2x1bW5hICJWYXIxIiBzZSBwcmVzZW50ZW4gZW4gZWwgZWplIFggeSBsb3MgdmFsb3JlcyBkZSBsYSBjb2x1bW5hIGEgIkZyZXEiIGVuIGVsIGVqZSBZLgpTZSBkZWZpbmUgdW4gZ3LDoWZpY28gZGUgYmFycmFzIHNpbXBsZSwgdXNhbmRvIGVsIGNvbWFuZG8gYGdlb21fYmFyKClgLCBkb25kZSBpbnRlcm5hbWVudGUgc2UgZGVmaW5lIGVsIGFuY2hvIGRlIGxhIGJhcnJhLgpDb24gbGEgZXNwZWNpZmljYWNpw7NuIGBsYWJzYCBzZSBkZWZpbmUgbGFzIGV0aXF1ZXRhcyBkZSBlamVzIHkgZWwgImNhcHRpb24iLgoKYGBge3IgZ2diYXJyYXMxY30KZ2dwbG90KGRhdGE9Y291bnQsIGFlcyh4PVZhcjEsIHk9RnJlcSkpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MC41KSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKEZyZXEsICIlIiwgc2VwPSIiKSksIGNvbG9yPSJ3aGl0ZSIsIAogICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBzaXplPTMpKwogIGxhYnMoeD0iTG9zIHZvdG9zIHNlIGN1ZW50YW4ganVzdGFtZW50ZSIsIHk9IlBvcmNlbnRhamUiLCAKICAgICAgIGNhcHRpb249IkJhcsOzbWV0cm8gZGUgbGFzIEFtw6lyaWNhcyBwb3IgTEFQT1AsIDIwMjEiKQpgYGAKCkVsIGdyw6FmaWNvIDIuNSBwcmVzZW50YSB1bmEgYmFycmEgYXBpbGFkYSBjb24gbG9zIGRhdG9zIHBvciBjYWRhIHBhw61zLgpQcmltZXJvIHByZXNlbnRhcmVtb3MgZWwgZ3LDoWZpY28gZGUgYmFycmFzIGFwaWxhZG8gdXNhbmRvIGxvcyBkYXRvcyBkZSB0b2RhIGxhIHJvbmRhIDIwMjEgZGVsIEJhcsOzbWV0cm8gZGUgbGFzIEFtw6lyaWNhcywgZXMgZGVjaXIgZGUgdG9kb3MgbG9zIHBhw61zZXMuClBhcmEgcHJvZHVjaXIgdW5hIGJhcnJhIGFwaWxhZGEgaG9yaXpvbnRhbCwgc2UgdXNhcsOhIGxhIHZhcmlhYmxlICJGcmVxIiBhaG9yYSBlbiBlbCBlamUgWC4KU2UgdXNhcsOhIGxhIG9wY2nDs24gYGZpbGxgIHBhcmEgZGl2aWRpciBlc3RhIGJhcnJhIHBvciBsb3MgdmFsb3JlcyBkZSBsYSB2YXJpYWJsZSAiVmFyMSIuCkNvbW8gZW4gZWwgZWplIFkgbm8gc2UgbW9zdHJhcsOhIHVuYSB2YXJpYWJsZSBzZSBkZWZpbmUgY29tbyBgIiJgLgpEZSBsYSBtaXNtYSBtYW5lcmEgcXVlIHNlIGNhbWJpYXJvbiBsYXMgdmFyaWFibGVzIGVuIGxvcyBlamVzLCB0YW1iacOpbiBzZSBjYW1iaWFuIGxhcyBldGlxdWV0YXMgZW4gYGxhYnNgLgpFbiBlc3RhIGVzcGVjaWZpY2FjacOzbiBzZSBjYW1iaWEgbGEgZXRpcXVldGEgZGUgbGEgbGV5ZW5kYSBjb24gYGZpbGxgLgoKYGBge3IgZ2diYXJyYXMxZH0KZ2dwbG90KGRhdGE9Y291bnQsIGFlcyhmaWxsPVZhcjEsIHg9RnJlcSwgeT0iIikpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MC4zKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKEZyZXEsICIlIiwgc2VwPSIiKSksIGNvbG9yPSJ3aGl0ZSIsIAogICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBzaXplPTMpKwogIGxhYnMoeD0iUG9yY2VudGFqZSIsIHk9IiIsIGZpbGw9IkxvcyB2b3RvcyBzZSBjdWVudGFuIGp1c3RhbWVudGUiLAogICAgICAgY2FwdGlvbj0iQmFyw7NtZXRybyBkZSBsYXMgQW3DqXJpY2FzIHBvciBMQVBPUCwgMjAyMSIpCmBgYAoKUGFyYSByZXBsaWNhciBlbCBncsOhZmljbyBjb21wYXJhdGl2byBwb3IgcGHDrXMgc2UgcmVxdWllcmUgY3JlYXIgbGEgdGFibGEgZGUgY29udGluZ2VuY2lhIGVudHJlIGxhIHZhcmlhYmxlICJjb3VudGZhaXIiIHkgInBhaXMiLgpFc3RhIHRhYmxhIGNydXphZGEgc2UgZ3VhcmRhIGVuIHVuIG9iamV0byAiY291bnRfcGFpcyIuClNlIGRlYmUgbm90YXIgcXVlIGVsIGRhdGFmcmFtZSBxdWUgc2UgY3JlYSBjcmVhIHVuYSBmaWxhIHBvciBjYWRhIHZhbG9yIGRlICJjb3VudGZhaXIiIGVuIGNhZGEgcGHDrXMuCkRlIGVzdGEgbWFuZXJhIHRlbmVtb3MgMyBvcGNpb25lcyB4IDIwIHBhw61zZXMgPSA2MCBmaWxhcy4KCmBgYHtyIHRhYmxhMWJ9CmNvdW50X3BhaXMgPSBhcy5kYXRhLmZyYW1lKHJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AyMSRwYWlzLCBsYXBvcDIxJGNvdW50ZmFpcjFyKSwgMSksIDMpKjEwMCkKY291bnRfcGFpcwpgYGAKCkVuIGVzdGEgdGFibGEgc2UgY2FsY3VsYW4gbG9zIGRhdG9zIHBvciBjYWRhIHZhbG9yIGRlIGxhIHZhcmlhYmxlICJwYWlzIiwgaW5jbHVzbyBjdWFuZG8gbm8gc2UgdGllbmUgZGF0b3MgZGUgbGEgdmFyaWFibGUgImNvdW50ZmFpciIsIGRlYmlkbyBhIHF1ZSBsYSBwcmVndW50YSBubyBzZSByZWFsaXrDsyBlbiBlc2UgcGHDrXMuClBvciBlc3RlIG1vdGl2byBzZSB0aWVuZW4gcXVlIGVsaW1pbmFyIGxhcyBmaWxhcyBkZSBsb3MgcGHDrXNlcyBlbiBsb3MgcXVlIG5vIHNlIHJlY29nacOzIGVzdGEgaW5mb3JtYWNpw7NuLgpFc3RvIHNlIGhhY2UgY29uIGxhIGVzcGVjaWZpY2FjacOzbiBgWy1jKGZpbGFzKSxdYC4KTHVlZ28gc2UgY3JlYSB1biB2ZWN0b3IgY29uIGxvcyBub21icmVzIGRlIGxvcyBwYcOtc2VzLgpFc3RhIGxpc3RhIHNlIHJlcGl0ZSAzIHZlY2VzICgxNSBwYcOtc2VzIHJlc3RhbnRlcyB4IDMgb3BjaW9uZXMpLgpFc3RlIHZlY3RvciBzZSBhZ3JlZ2EgYWwgZGF0YWZyYW1lIGVuIHVuYSBjb2x1bW5hICJwYWlzIi4KCmBgYHtyIHRhYmxhMWN9CmNvdW50X3BhaXMgPSBjb3VudF9wYWlzWy1jKDE6NCwxOCwyMToyNCwzOCw0MTo0NCw1OCksXQpwYWlzID0gYygiTmljYXJhZ3VhIiwiQ29zdGEgUmljYSIsICJQYW5hbcOhIiwgIkNvbG9tYmlhIiwgIkVjdWFkb3IiLCAiQm9saXZpYSIsICJQZXLDuiIsCiAgICAgICAgIlBhcmFndWF5IiwgIkNoaWxlIiwgIlVydWd1YXkiLCAiQnJhc2lsIiwgIkFyZ2VudGluYSIsICJSZXAuIERvbS4iLCJKYW1haWNhIiwgIkd1eWFuYSIsICJOaWNhcmFndWEiLCJDb3N0YSBSaWNhIiwgIlBhbmFtw6EiLCAiQ29sb21iaWEiLCAiRWN1YWRvciIsICJCb2xpdmlhIiwgIlBlcsO6IiwKICAgICAgICAiUGFyYWd1YXkiLCAiQ2hpbGUiLCAiVXJ1Z3VheSIsICJCcmFzaWwiLCAiQXJnZW50aW5hIiwgIlJlcC4gRG9tLiIsIkphbWFpY2EiLCAiR3V5YW5hIiwiTmljYXJhZ3VhIiwiQ29zdGEgUmljYSIsICJQYW5hbcOhIiwgIkNvbG9tYmlhIiwgIkVjdWFkb3IiLCAiQm9saXZpYSIsICJQZXLDuiIsCiAgICAgICAgIlBhcmFndWF5IiwgIkNoaWxlIiwgIlVydWd1YXkiLCAiQnJhc2lsIiwgIkFyZ2VudGluYSIsICJSZXAuIERvbS4iLCJKYW1haWNhIiwgIkd1eWFuYSIpCmNvdW50X3BhaXMkcGFpcyA9IHBhaXMKY291bnRfcGFpcwpgYGAKCkNvbiBlc3RlIGRhdGFmcmFtZSAiY291bnRfcGFpcyIgeWEgdGVuZW1vcyBsb3MgZWxlbWVudG9zIHBhcmEgcmVwbGljYXIgZWwgZ3LDoWZpY28gZGUgYmFycmFzIGFwaWxhZGFzLgpFbiBsYSBlc3BlY2lmaWNhY2nDs24gYGFlc2Agc2UgZGVmaW5lIHF1ZSBlbiBlbCBlamUgWCBzZSBncmFmaXF1ZW4gbG9zIHBvcmNlbnRhamVzLCBlbiBlbCBlamUgWSBsb3MgcGHDrXNlcyB5IGNhZGEgYmFycmEgc2UgZGl2aWRhIHBvciBsYSBjb2x1bW5hIFZhcjIuCgpgYGB7ciBnZ2JhcnJhczFlfQpnZ3Bsb3QoZGF0YT1jb3VudF9wYWlzLCBhZXMoeD1GcmVxLCB5PXBhaXMsIGZpbGw9VmFyMikpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MC4zKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKEZyZXEsICIlIiwgc2VwPSIiKSksIGNvbG9yPSJ3aGl0ZSIsIAogICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBzaXplPTIpKwogIGxhYnMoeD0iUG9yY2VudGFqZSIsIHk9IlBhw61zIiwgZmlsbD0iTG9zIHZvdG9zIHNlIGN1ZW50YW4ganVzdGFtZW50ZSIsCiAgICAgICBjYXB0aW9uPSJCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgcG9yIExBUE9QLCAyMDIxIikKYGBgCgojIEZyZWN1ZW5jaWEgZGUgdXNvIGRlIHJlZGVzIHNvY2lhbGVzCgpFbiBsYSByb25kYSAyMDE4LzE5IHNlIGV2YWx1w7MgZWwgdXNvIGRlIHJlZGVzIHNvY2lhbGVzLgpEZSBlc3RhIG1hbmVyYSwgc2UgYW5hbGl6YXJvbiBsYXMgdmFyaWFibGVzIFNNRURJQTIuCsK/Q29uIHF1w6kgZnJlY3VlbmNpYSB2ZSBjb250ZW5pZG8gZW4gRmFjZWJvb2s/LApTTUVESUE1LsK/Q29uIHF1w6kgZnJlY3VlbmNpYSB2ZSBjb250ZW5pZG8gZW4gVHdpdHRlcj8KeSBTTUVESUE4LsK/Q29uIHF1w6kgZnJlY3VlbmNpYSB1c2EgV2hhdHNhcHA/CkVzdGFzIHZhcmlhYmxlcyB0aWVuZW4gY29tbyBvcGNpb25lcyBkZSByZXNwdWVzdGE6CgoxLiAgRGlhcmlhbWVudGUKMi4gIEFsZ3VuYXMgdmVjZXMgYSBsYSBzZW1hbmEKMy4gIEFsZ3VuYXMgdmVjZXMgYWwgbWVzCjQuICBBbGd1bmFzIHZlY2VzIGFsIGHDsW8KNS4gIE51bmNhCgpEZSBsYSBtaXNtYSBtYW5lcmEgcXVlIGNvbiBsYXMgdmFyaWFibGVzIG5vbWluYWxlcywgZXN0YXMgdmFyaWFibGVzIHRpZW5lbiBxdWUgc2VyIGRlY2xhcmFkYXMgY29tbyAiZmFjdG9yIiBlbiBudWV2YXMgdmFyaWFibGVzLgoKYGBge3IgZmFjdG9yMn0KbGFwb3AxOCRzbWVkaWEyciA9IGFzLmZhY3RvcihsYXBvcDE4JHNtZWRpYTIpCmxhcG9wMTgkc21lZGlhNXIgPSBhcy5mYWN0b3IobGFwb3AxOCRzbWVkaWE1KQpsYXBvcDE4JHNtZWRpYThyID0gYXMuZmFjdG9yKGxhcG9wMTgkc21lZGlhOCkKYGBgCgpMYSBub3RhIGEgcGllIDE1IGRlbCByZXBvcnRlIGluZGljYSBxdWUgImxvcyBlbnRyZXZpc3RhZG9zIHF1ZSByZXBvcnRhbiBudW5jYSB2ZXIgY29udGVuaWRvIGVuIEZhY2Vib29rIHkgVHdpdHRlciwgeSBxdWllbmVzIGluZGljYW4gcXVlIG51bmNhIHVzYW4gV2hhdHNhcHAsIHNvbiBjb25zaWRlcmFkb3MgY29tbyBubyB1c3VhcmlvcyBkZSBlc3RhcyByZWRlcyBzb2NpYWxlcyIgKHAuIDY0KS4KUG9yIGVzdGUgbW90aXZvLCBlbCBncsOhZmljbyAzLjMgZGUgZnJlY3VlbmNpYSBkZSB1c28gZGUgcmVkZXMgc29jaWFsZXMgKHBhZy4gNTcpIHNvbG8gaW5jbHV5ZW4gbGFzIGNhdGVnb3LDrWFzICJEaWFyaWFtZW50ZSIsICJBbGd1bmFzIHZlY2VzIGEgbGEgc2VtYW5hIiwgIkFsZ3VuYXMgdmVjZXMgYWwgbWVzIiB5ICJBbGd1bmFzIHZlY2VzIGFsIGHDsW8iLgpTZSBleGNsdXlhIGxhIGNhdGVnb3LDrWEgIk51bmNhIi4KCiFbXShHcmFmMy4zLnBuZyl7d2lkdGg9IjM5OCJ9CgpFbiBsYXMgbnVldmFzIHZhcmlhYmxlcyB2YW1vcyBhIGRlY2xhcmFyIGVsIHZhbG9yIDUsIGNvcnJlc3BvbmRpZW50ZSBhICJudW5jYSIsIGNvbW8gIk5BIiwgZXMgZGVjaXIsIGNvbW8gdmFsb3IgcGVyZGlkbyBlbiBSLgoKYGBge3IgZWxpbWluYXJ9CmxpYnJhcnkoY2FyKQpsYXBvcDE4JHNtZWRpYTJyID0gY2FyOjpyZWNvZGUobGFwb3AxOCRzbWVkaWEyciwgIjU9TkEiKQpsYXBvcDE4JHNtZWRpYTVyID0gY2FyOjpyZWNvZGUobGFwb3AxOCRzbWVkaWE1ciwgIjU9TkEiKQpsYXBvcDE4JHNtZWRpYThyID0gY2FyOjpyZWNvZGUobGFwb3AxOCRzbWVkaWE4ciwgIjU9TkEiKQpgYGAKCkx1ZWdvLCBlc3RhcyB2YXJpYWJsZXMgc2UgdGllbmVuIHF1ZSBldGlxdWV0YXIgeSBnZW5lcmFyIGxhcyB0YWJsYXMgZGVzY3JpcHRpdmFzIGLDoXNpY2FzLCBjb24gZWwgY29tYW5kbyBgdGFibGVgLgoKYGBge3IgZXRpcXVldGEyfQpsZXZlbHMobGFwb3AxOCRzbWVkaWEycikgPC0gYygiRGlhcmlhbWVudGUiLCAiQWxndW5hcyB2ZWNlcyBhIGxhIHNlbWFuYSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFsZ3VuYXMgdmVjZXMgYWwgbWVzIiwgIkFsZ3VuYXMgdmVjZXMgYWwgYcOxbyIpCmxldmVscyhsYXBvcDE4JHNtZWRpYTVyKSA8LSBjKCJEaWFyaWFtZW50ZSIsICJBbGd1bmFzIHZlY2VzIGEgbGEgc2VtYW5hIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQWxndW5hcyB2ZWNlcyBhbCBtZXMiLCAiQWxndW5hcyB2ZWNlcyBhbCBhw7FvIikKbGV2ZWxzKGxhcG9wMTgkc21lZGlhOHIpIDwtIGMoIkRpYXJpYW1lbnRlIiwgIkFsZ3VuYXMgdmVjZXMgYSBsYSBzZW1hbmEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBbGd1bmFzIHZlY2VzIGFsIG1lcyIsICJBbGd1bmFzIHZlY2VzIGFsIGHDsW8iKQp0YWJsZShsYXBvcDE4JHNtZWRpYTJyKQp0YWJsZShsYXBvcDE4JHNtZWRpYTVyKQp0YWJsZShsYXBvcDE4JHNtZWRpYThyKQpgYGAKClBhcmEgY2FsY3VsYXIgbGFzIHRhYmxhcyBjb24gcG9yY2VudGFqZXMsIHJlZG9uZGVhZG9zIGEgdW4gZGVjaW1hbCwgdXNhbW9zIGBwcm9wLnRhYmxlYCB5IGByb3VuZGAuCk51ZXZhbWVudGUsIGVzdG9zIHBvcmNlbnRhamVzIG5vIHNvbiBleGFjdGFtZW50ZSBpZ3VhbGVzIGEgbG9zIHByZXNlbnRhZG9zIGVuIGVsIHJlcG9ydGUgZGViaWRvIGEgcXVlIGVzdG9zIGPDoWxjdWxvcyBubyBpbmNsdXllbiBlbCBmYWN0b3IgZGUgZXhwYW5zacOzbi4KCmBgYHtyIHBvcmNlbnRhamVzMn0Kcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNtZWRpYTJyKSksIDMpKjEwMApyb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkc21lZGlhNXIpKSwgMykqMTAwCnJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWE4cikpLCAzKSoxMDAKYGBgCgpQYXJhIHByZXNlbnRhciB0b2RvcyBsb3MgZGF0b3MgZW4gdW5hIHRhYmxhIGNvbmp1bnRhLCBzZSBndWFyZGEgbGEgdGFibGEgZGUgY2FkYSByZWQgc29jaWFsIGVuIHVuIG51ZXZvIG9iamV0byBkZSBSIChsbGFtYWRvIGNvbW8gY2FkYSByZWQgc29jaWFsKS4KTHVlZ28sIHRvZGFzIGVzdGFzIHRhYmxhcyBwYXJjaWFsZXMsIHF1ZSBjb250aWVuZW4gbGFzIG1pc21hcyBvcGNpb25lcyBkZSByZXNwdWVzdGEsIHNlIHVuZW4gY29tbyBmaWxhcyBjb24gZWwgY29tYW5kbyBgcmJpbmRgLgpFc3RhIG51ZXZhIHRhYmxhIGNvbmp1bnRhIHNlIGd1YXJkYSBjb21vIHVuIG51ZXZvIGRhdGFmcmFtZSAidGFibGEiLgoKYGBge3IgdGFibGEyYX0KRmFjZWJvb2sgPC0gcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNtZWRpYTJyKSksIDMpKjEwMApUd2l0dGVyIDwtIHJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AxOCRzbWVkaWE1cikpLCAzKSoxMDAKV2hhdHNhcHAgPC0gcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHNtZWRpYThyKSksIDMpKjEwMAp0YWJsYSA8LSBhcy5kYXRhLmZyYW1lKHJiaW5kKEZhY2Vib29rLCBUd2l0dGVyLCBXaGF0c2FwcCkpCnRhYmxhCmBgYAoKUGFyYSB0ZW5lciB1bmEgbWVqb3IgcHJlc2VudGFjacOzbiBkZSBsYSB0YWJsYSwgc2UgcHVlZGUgdXNhciBlbCBjb21hbmRvIGBrYWJsZWAgZGVsIHBhcXVldGUgYGtuaXRyYCBvIGVsIGNvbWFuZG8gYGZvcm1hdHRhYmxlYCBkZWwgcGFxdWV0ZSBkZWwgbWlzbW8gbm9tYnJlLgoKYGBge3IgdGFibGEgbWVqb3JhZGF9CmxpYnJhcnkoa25pdHIpCmthYmxlKGhlYWQodGFibGEpLCBmb3JtYXQ9Im1hcmtkb3duIiwgZGlnaXRzPTEpCmxpYnJhcnkoZm9ybWF0dGFibGUpCmZvcm1hdHRhYmxlKHRhYmxhKQpgYGAKClBhcmEgZ3JhZmljYXIgZXN0YSB2YXJpYWJsZSBubyB2YW1vcyBhIHNlZ3VpciBlbCBtaXNtbyBwcm9jZWRpbWllbnRvIHF1ZSBlbiBlbCBtw7NkdWxvIGFudGVyaW9yLgpFbiBlc3RlIG3Ds2R1bG8gdmFtb3MgYSB0cmFiYWphciBkaXJlY3RhbWVudGUgZGVzZGUgbGEgdGFibGEgY3JlYWRhIGNvbiBsb3MgcG9yY2VudGFqZXMgZGUgbGFzIHRyZXMgcmVkZXMgc29jaWFsZXMuCkVzdGEgdGFibGEgdGllbmUgYSBjYWRhIHJlZCBzb2NpYWwgZW4gbGFzIGZpbGFzIHkgbGFzIG9wY2lvbmVzIGRlIHJlc3B1ZXN0YSBlbiBsYXMgY29sdW1uYXMuClBhcmEgcG9kZXIgZ3JhZmljYXIgZXN0b3MgZGF0b3Mgc2UgcmVxdWllcmUgcXVlIGxhcyByZWRlcyBzb2NpYWxlcyBlc3TDqW4gZW4gbGFzIGNvbHVtbmFzIHkgbGFzIG9wY2lvbmVzIGRlIHJlc3B1ZXN0YSBlbiBsYXMgZmlsYXMsIHBvciBsbyBxdWUgZW4gcHJpbWVyIGx1Z2FyIHZhbW9zIGEgdHJhbnNwb25lciBlc3RhIHRhYmxhLgpFc3RlIHByb2NlZGltaWVudG8gbG8gaGFjZW1vcyB1c2FuZG8gbGEgbGlicmVyw61hIGBkYXRhLnRhYmxlYCB5IGVsIGNvbWFuZG8gYHRyYW5zcG9zZWAuCkVzdG9zIGRhdG9zIHRyYW5zcHVlc3RvcyBsb3MgZ3VhcmRhbW9zIGVuIHVuYSBudWV2YSB0YWJsYSAidGFibGFfdHIiLgoKRXN0ZSBjb21hbmRvIHRyYW5zcG9uZSBsb3MgZGF0b3MsIHBlcm8gZGVqYSBzaW4gbm9tYnJhciBsYXMgZmlsYXMgeSBjb2x1bW5hcy4KUHJpbWVybyBzZSBub21icmFuIGxhcyBjb2x1bW5hcyBjb24gZWwgY29tYW5kbyBgY29sbmFtZXNgIHVzYW5kbyBsb3Mgbm9tYnJlcyBkZSBsYXMgZmlsYXMgZGUgInRhYmxhIi4KTHVlZ28gc2Ugbm9tYnJhbiBsYXMgZmlsYXMgY29uIGVsIGNvbWFuZG8gYHJvd25hbWVzYCB1c2FuZG8gbG9zIG5vbWJyZXMgZGUgbGFzIGNvbHVtbmFzIGRlICJ0YWJsYSIuCgpGaW5hbG1lbnRlLCByZXF1ZXJpbW9zIHVuYSBjb2x1bW5hIGRlbnRybyBkZSAidGFibGFfdHIiIHF1ZSBpbmNsdXlhIGxhcyBldGlxdWV0YXMgZGUgcmVzcHVlc3RhIGRlIGxhcyBwcmVndW50YXMgZGUgc21lZGlhLgpFc3RhcyBldGlxdWV0YXMgZXN0w6FuIGNvbW8gbm9tYnJlcyBkZSBmaWxhcy4KUGFyYSBpbmNsdWlybGFzIGNvbW8gdW5hIHZhcmlhYmxlIG3DoXMsIHNlIGFncmVnYSB1bmEgdmFyaWFibGUgInRhYmxhX3RyXCRsYWIiIGFsIHF1ZSBzZSBsZSBhc2lnbmEgbG9zIG5vbWJyZXMgZGUgbGFzIGZpbGFzIGNvbiBgcm93Lm5hbWVzYC4KCmBgYHtyIHRhYmxhIHRyYW5zcHVlc3RhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGRhdGEudGFibGUpCnRhYmxhX3RyID0gZGF0YS5mcmFtZSh0KHRhYmxhW10pKQpjb2xuYW1lcyh0YWJsYV90cikgPSByb3duYW1lcyh0YWJsYSkKcm93bmFtZXModGFibGFfdHIpID0gY29sbmFtZXModGFibGEpCnRhYmxhX3RyJGxhYiA8LSByb3duYW1lcyh0YWJsYV90cikKdGFibGFfdHIKYGBgCgpFbiBzZWd1bmRvIGx1Z2FyLCBzZSBhY3RpdmEgbGEgbGlicmVyw61hIGBnZ3Bsb3QyYCBwYXJhIGdyYWZpY2FyIGxvcyBkYXRvcyBndWFyZGFkb3MgZW4gInRhYmxhX3RyIiBjb24gZWwgY29tYW5kbyBgZ2dwbG90YC4KRGVudHJvIGRlIGVzdGUgY29tYW5kbyBzZSBlc3BlY2lmaWNhIHF1ZSBzZSB0cmFiYWphcsOhIGNvbiBlbCBkYXRhZnJhbWUgInRhYmxhX3RyIiAobm8gY29uIGxhcG9wMTgpIHkgc2UgZXNwZWNpZmljYSBsYSAiZXN0w6l0aWNhIiwgZXMgZGVjaXIgcXVlIGVuIGVsIGVqZSBYIG5vIHNlIGluY2x1aXLDoSB1bmEgdmFyaWFibGUsIHF1ZSBlbiBlbCBlamUgWSBzZSBpbmNsdWlyw6EgbG9zIGRhdG9zIGRlICJGYWNlYm9vayIgZGVsIGRhdGFmcmFtZSAidGFibGFfdHIiIHkgcXVlIHNlIGRpdmlkaXLDoSBwb3IgY2F0ZWdvcsOtYXMgZGUgbGEgdmFyaWFibGUgZ3VhcmRhZGFzIGVuICJsYWIiLgpMdWVnbyBzZSBhw7FhZGUgbGEgY2FwYSBgZ2VvbV9iYXJgIHBhcmEgaW5kaWNhciBxdWUgc2UgZ3JhZmljYXLDoSBlbiBiYXJyYXMgZGUgYW5jaG8gKGB3aWR0aGApIDEgeSBxdWUgbGEgYmFycmEgcmVwbGljYXLDoSBsbyBlc3BlY2lmaWNhZG8gZW4gbGEgZXN0w6l0aWNhIChgc3RhdD0iaWRlbnRpdHkiYCkuCkNvbiBgZ2VvbV90ZXh0YCBzZSBhZ3JlZ2EgbGFzIGV0aXF1ZXRhcyBkZSBsb3MgZGF0b3MsIGNvbiBlbCBzw61tYm9sbyBkZSBwb3JjZW50YWplLCB5IHNlIGVzcGVjaWZpY2EgbGEgcG9zaWNpw7NuIGRlbCB0ZXh0byBjb24gYHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKOKApilgIHkgZWwgdGFtYcOxbyBjb24gYHNpemU9M2AuCkNvbiBgY29vcmRfcG9sYXJgIHNlIHRyYW5zZm9ybWEgbGFzIGJhcnJhcyBlbiB1biBncsOhZmljbyBjaXJjdWxhciBkZSBzZWN0b3Jlcy4KRmluYWxtZW50ZSwgc2UgZGVmaW5lIGVsICJ0ZW1hIiBjb24gYHRoZW1lX3ZvaWRgIGluZGljYW5kbyB1biBmb25kbyBibGFuY28geSBzZSBtb2RpZmljYSBsYSBldGlxdWV0YSBkZSBsYSBsZXllbmRhIGNvbiBgc2NhbGVfZmlsbF9kaXNjcmV0ZWAuCgpgYGB7ciBncmFmaWNvIHBpZX0KbGlicmFyeShnZ3Bsb3QyKQpnZ3Bsb3QoZGF0YT10YWJsYV90ciwgYWVzKHg9IiIsIHk9RmFjZWJvb2ssIGZpbGw9bGFiKSkrCiAgZ2VvbV9iYXIod2lkdGg9MSwgc3RhdD0iaWRlbnRpdHkiKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKEZhY2Vib29rLCAiJSIsIHNlcD0iIikpLCBjb2xvcj0id2hpdGUiLCAKICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSwgc2l6ZT0zKSsKICBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApKwogIHRoZW1lX3ZvaWQoKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9IkZyZWN1ZW5jaWEgZGUgdXNvIGRlIEZhY2Vib29rIikKYGBgCgpFbiBlbCBncsOhZmljbyAzLjMgZGVsIHJlcG9ydGUgIkVsIFB1bHNvIGRlIGxhIERlbW9jcmFjaWEiIHNlIHByZXNlbnRhIHVuIGdyw6FmaWNvIGNpcmN1bGFyIHRpcG8gImRvbm5hIi4KUGFyYSByZXByb2R1Y2lyIGV4YWN0YW1lbnRlIGVzdGUgdGlwbyBkZSBncsOhZmljbywgc2UgdGllbmUgcXVlIGFjb21vZGFyIHVub3MgZGV0YWxsZXMgZGUgbGEgc2ludGF4aXMgYW50ZXJpb3IuClNlIGVzdGFibGVjZSAieD0yIiBlbiBsYSAiZXN0w6l0aWNhIiB5IHNlIGVzdGFibGVjZSBsw61taXRlcyBlbiBlbCBlamUgWCwgZW50cmUgMC41IHkgMi41LCBwYXJhIHF1ZSBjdWFuZG8gc2Ugcm90ZSBlbCBlamUsIHNlIGNyZWUgZWwgImh1ZWNvIiBkZW50cm8gZGVsIGPDrXJjdWxvLgoKYGBge3IgZG9uYX0KZ2dwbG90KGRhdGE9dGFibGFfdHIsIGFlcyh4PTIsIHk9RmFjZWJvb2ssIGZpbGw9bGFiKSkrCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKEZhY2Vib29rLCAiJSIsIHNlcD0iIikpLCBjb2xvcj0id2hpdGUiLCAKICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSwgc2l6ZT0zKSsKICBjb29yZF9wb2xhcigieSIpKwogIHRoZW1lX3ZvaWQoKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9IkZyZWN1ZW5jaWEgZGUgdXNvIGRlIEZhY2Vib29rIikrCiAgIGxhYnModGl0bGU9IkZyZWN1ZW5jaWEgY29uIGxhIHF1ZSB2ZSBjb250ZW5pZG8gZW4gRmFjZWJib2siLCAKICAgICAgICBjYXB0aW9uPSJCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgcG9yIExBUE9QLCAyMDE4LzE5IikrCiAgeGxpbSgwLjUsIDIuNSkKYGBgCgpQYXJhIHJlcGxpY2FyIGVsIGdyw6FmaWNvIGRlIGJhcnJhcywgc2UgaGFjZW4gYWxndW5hcyBtb2RpZmljYWNpb25lcyBlbiBlbCBjw7NkaWdvIGFudGVyaW9yLgpQb3IgZWplbXBsbywgZW4gbGEgImVzdMOpdGljYSIsIGFob3JhIHNlIGluZGljYSBxdWUgZW4gZWwgZWplIFggdmEgbGEgdmFyaWFibGUgInNtZWRpYTJyIiB5IGVuIGVsIGVqZSBZIGVsIHBvcmNlbnRhamUgInBlciIuClNlIGVsaW1pbmEsIGFkZW3DoXMsIGxhIGVzcGVjaWZpY2FjacOzbiBkZSBsYXMgY29vcmRlbmFkYXMgcG9sYXJlcy4KU2UgYWdyZWdhIHVuIHTDrXR1bG8gYWwgZ3LDoWZpY28sIGV0aXF1ZXRhcyBhIGxvcyBlamVzIHkgdW4gY2FwdGlvbiBjb24gbGEgZXNwZWNpZmljYWNpw7NuIGBsYWJzYC4KRmluYWxtZW50ZSwgc2UgZGVmaW5lIGVsIGVqZSBZIGVudHJlIDAgeSA2MCBjb24gbGEgZXNwZWNpZmljYWNpw7NuIGBjb29yZF9jYXJ0ZXNpYW5gLgpVbiB0ZW1hIGltcG9ydGFudGUgZXMgcXVlIGVzdGUgZ3LDoWZpY28gdGFtYmnDqW4gc2UgcHVlZGUgZ3VhcmRhciBlbiB1biBvYmpldG8gZW4gUiwgcXVlIGxsYW1hcmVtb3MgImdyYWYxIi4KCmBgYHtyIGdyYWZpY28gZGUgYmFycmFzfQpncmFmMSA8LSBnZ3Bsb3QodGFibGFfdHIsIGFlcyh4PWxhYiwgeT1GYWNlYm9vaykpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgIHdpZHRoPTAuNSkrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZShGYWNlYm9vaywgIiUiLCBzZXA9IiIpKSwgY29sb3I9ImJsYWNrIiwgdmp1c3Q9LTAuNSkrCiAgbGFicyh0aXRsZT0iRnJlY3VlbmNpYSBkZSB1c28gZGUgcmVkZXMgc29jaWFsZXMiLCB4PSJGcmVjdWVuY2lhIGRlIHVzbyBkZSBGYWNlYm9vayIsIHk9IlBvcmNlbnRhamUiLCBjYXB0aW9uPSJCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgcG9yIExBUE9QLCAyMDE4LzE5IikrCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCA2MCkpCmdyYWYxCmBgYAoKR3VhcmRhciB1biBncsOhZmljbyBlbiB1biBvYmpldG8gbm9zIHBlcm1pdGUgbHVlZ28gaW5jb3Jwb3JhciBtw6FzIGNhcGFzIG8gbWVqb3JhcyBlbiBlbCBncsOhZmljby4KRWwgZ3LDoWZpY28gYW50ZXJpb3IsIHBvciBlamVtcGxvLCB0aWVuZSBsYXMgZXRpcXVldGFzIGRlICJGcmVjdWVuY2lhIGRlIHVzbyIgZW4gdW5hIHNvbGEgbMOtbmVhLCBwb3IgbG8gc2UgcG9kcsOtYW4gdHJhc3BvbmVyLgpQYXJhIG1lam9yYXIgZXN0YSB2aXN1YWxpemFjacOzbiBzZSBwdWVkZSBpbmNsaW5hciBlc3RhcyBldGlxdWV0YXMsIHBlcm8gc2kgc2UgcXVpc2llcmEgbWFudGVuZXIgbGEgaG9yaXpvbnRhbGlkYWQgcGFyYSBmYWNpbGl0YXIgbGEgbGVjdHVyYSwgbG8gcXVlIHNlIHB1ZWRlIGhhY2VyIGVzIHNlcGFyYXIgbGFzIGV0aXF1ZXRhcyBsYXJnYXMgZW4gZG9zIG8gbcOhcyBsw61uZWFzLgpFc3RvIHNlIHB1ZWRlIGhhY2VyLCBwb3IgZWplbXBsbywgY3JlYW5kbyB1biB2ZWN0b3IgY29uIGxhcyBudWV2YXMgZXRpcXVldGFzLgpMYXMgZXRpcXVldGFzIGxhcmdhcyBzZSBwdWVkZW4gcGFydGlyIGVuIGzDrW5lYXMgbWVkaWFudGUgbGEgaW5jbHVzacOzbiBkZSBgXG5gIGVudHJlIGxvcyB0ZXh0b3MgcXVlIHNlIHF1aWVyYSBzZXBhcmFyLgpMdWVnbywgYWwgb2JqZXRvICJncmFmMSIgc2UgbGUgcHVlZGUgYWdyZWdhciB1bmEgbnVldmEgY2FwYSBwYXJhIHJlZW1wbGF6YXIgbGFzIGV0aXF1ZXRhcyBjb24gbGFzIG51ZXZhcyBkaXZpZGlkYXMgZW4gbMOtbmVhcy4KRXN0byBzZSBoYWNlIGNvbiBsYSBlc3BlY2lmaWNhY2nDs24gYHNjYWxlX3hfZGlzY3JldGVgIGRvbmRlIHNlIGluZGljYSBxdWUgbGFzIGV0aXF1ZXRhcyB1c2VuIGVsIHZlY3RvciBjcmVhZG8uCgpgYGB7ciBldGlxdWV0YXMgc3VwZXJwdWVzdGFzfQpldGlxIDwtIGMoIkRpYXJpYW1lbnRlIiwgIkFsZ3VuYXMgdmVjZXNcbmEgbGEgc2VtYW5hIiwgIkFsZ3VuYXMgdmVjZXNcbmFsIG1lcyIsIAogICAgICAgICAgIkFsZ3VuYXMgdmVjZXNcbmFsIGHDsW8iKQpncmFmMSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9ZXRpcSkKYGBgCgpEZSBlc3RhIG1hbmVyYSBlbCBncsOhZmljbyBxdWVkYSBtw6FzIGxlZ2libGUuCkhhc3RhIGFxdcOtIHNlIGhhIHJlcGxpY2FkbyBsYXMgdGFibGFzIHkgZ3LDoWZpY29zIHF1ZSBzZSB1c2Fyb24gY29uIGxhcyB2YXJpYWJsZXMgbm9taW5hbGVzLCBhaG9yYSB1c2FuZG8gdmFyaWFibGVzIG9yZGluYWxlcy4KU2kgc2UgcXVpZXJlIHJlcGxpY2FyIGVsIGdyw6FmaWNvIGNpcmN1bGFyIGRlIGxhcyBvdHJhcyByZWRlcyBzb2NpYWxlcywgc2UgcHVlZGUgZWplY3V0YXIgZWwgbWlzbW8gY8OzZGlnbywgcGVybyBjYW1iaWFuZG8gbGEgY29sdW1uYSBkZSBsYSByZWQgc29jaWFsLgpQYXJhIFR3aXR0ZXIsIHBvciBlamVtcGxvLCBzZSB0ZW5kcsOtYS4KCmBgYHtyIGdyYWZpY28gVHdpdHRlcn0KZ3JhZjIgPC0gZ2dwbG90KGRhdGE9dGFibGFfdHIsIGFlcyh4PTIsIHk9VHdpdHRlciwgZmlsbD1sYWIpKSsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUoVHdpdHRlciwgIiUiLCBzZXA9IiIpKSwgY29sb3I9IndoaXRlIiwgCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIHNpemU9MykrCiAgY29vcmRfcG9sYXIoInkiKSsKICB0aGVtZV92b2lkKCkrCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lPSJGcmVjdWVuY2lhIGRlIHVzbyBkZSBUd2l0dGVyIikrCiAgIGxhYnModGl0bGU9IkZyZWN1ZW5jaWEgY29uIGxhIHF1ZSB2ZSBjb250ZW5pZG8gZW4gVHdpdHRlciIsIAogICAgICAgIGNhcHRpb249IkJhcsOzbWV0cm8gZGUgbGFzIEFtw6lyaWNhcyBwb3IgTEFQT1AsIDIwMTgvMTkiKSsKICB4bGltKDAuNSwgMi41KQpncmFmMgpgYGAKCiMjIENydWNlIGRlIHZhcmlhYmxlcwoKRW4gbGEgdGFibGEgMy4xIChwYWcuIDU1KSBkZWwgcmVwb3J0ZSAiRWwgcHVsc28gZGUgbGEgZGVtb2NyYWNpYSIgc2UgcHJlc2VudGEgbG9zIHBvcmNlbnRhamVzIGRlIHVzbyBkZSBsYXMgcmVkZXMgc29jaWFsZXMgcG9yIHBhw61zLgpMdWVnbywgZW4gbGEgcMOhZ2luYSA1NiBzZSBwcmVzZW50YSB1biBjdWFkcm8gY29uIGVsIHBvcmNlbnRhamUgZGUgdXN1YXJpb3MgZGUgcmVkZXMgc29jaWFsZXMgcG9yIGNhcmFjdGVyw61zdGljYXMgc29jaW9kZW1vZ3LDoWZpY2FzLCBwb3IgZWplbXBsbywgdXJiYW5vL3J1cmFsLCBob21icmUsIGVkYWQgcHJvbWVkaW8sIHJpcXVlemEgcHJvbWVkaW8geSBhw7FvcyBkZSBlc3R1ZGlvLgoKIVtdKHRhYmxhMy4xLnBuZyl7d2lkdGg9IjQ4MSJ9CgpFbXBlemFyZW1vcyByZXBsaWNhbmRvIGxvcyBkYXRvcyBnZW5lcmFsZXMgZGVsIHVzbyBkZSByZWRlcyBzb2NpYWxlcyBxdWUgc2UgcmVwb3J0YSBlbiBlbCBncsOhZmljbyAzLjEuClBhcmEgcmVwbGljYXIgZXN0YSB0YWJsYSBwcmltZXJvIHNlIHRpZW5lIHF1ZSBkZWZpbmlyIGxhIHZhcmlhYmxlICJwYWlzIiB5IGxhcyB2YXJpYWJsZXMgZGUgdXNvIGRlIHJlZGVzIHNvY2lhbGVzIChzbWVkaWExLCBzbWVkaWE0IHkgc21lZGlhNykuCgpgYGB7ciBwYcOtc30KbGFwb3AxOCRzbWVkaWExciA9IGFzLmZhY3RvcihsYXBvcDE4JHNtZWRpYTEpCmxhcG9wMTgkc21lZGlhNHIgPSBhcy5mYWN0b3IobGFwb3AxOCRzbWVkaWE0KQpsYXBvcDE4JHNtZWRpYTdyID0gYXMuZmFjdG9yKGxhcG9wMTgkc21lZGlhNykKbGV2ZWxzKGxhcG9wMTgkc21lZGlhMXIpIDwtIGMoIlPDrSIsICJObyIpCmxldmVscyhsYXBvcDE4JHNtZWRpYTRyKSA8LSBjKCJTw60iLCAiTm8iKQpsZXZlbHMobGFwb3AxOCRzbWVkaWE3cikgPC0gYygiU8OtIiwgIk5vIikKbGFwb3AxOCRwYWlzID0gYXMuZmFjdG9yKGxhcG9wMTgkcGFpcykKbGV2ZWxzKGxhcG9wMTgkcGFpcykgPC0gYygiTcOpeGljbyIsICJHdWF0ZW1hbGEiLCAiRWwgU2FsdmFkb3IiLCAiSG9uZHVyYXMiLAogICAgICAgICAgICAgICAgICAgICAgICAiTmljYXJhZ3VhIiwiQ29zdGEgUmljYSIsICJQYW5hbcOhIiwgIkNvbG9tYmlhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICJFY3VhZG9yIiwgIkJvbGl2aWEiLCAiUGVyw7oiLCAiUGFyYWd1YXkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIkNoaWxlIiwgIlVydWd1YXkiLCAiQnJhc2lsIiwgIkFyZ2VudGluYSIsIAogICAgICAgICAgICAgICAgICAgICAgICAiUmVwLiBEb20uIiwgIkphbWFpY2EiKQp0YWJsZShsYXBvcDE4JHBhaXMpICNQYcOtcwp0YWJsZShsYXBvcDE4JHNtZWRpYTFyKSAjRmFjZWJvb2sKYGBgCgpTaW4gZW1iYXJnbywgbGEgdmFyaWFibGUgInVzdWFyaW8iIGRlIGNhZGEgcmVkIHNvY2lhbCBzZSBjYWxjdWxhIGNvbW8gY29uZGljacOzbiBkZSBkb3MgdmFyaWFibGVzLCBjb21vIHNlIHZpbyBlbiBlbCBkb2N1bWVudG8gc29icmUgbWFuZWpvIGRlIGRhdG9zLCBjb24gZWwgc2lndWllbnRlIGPDs2RpZ28uCgpgYGB7ciB1c3Vhcmlvc30KbGFwb3AxOCRmYl91c2VyIDwtIGlmZWxzZShsYXBvcDE4JHNtZWRpYTE9PTEgJiBsYXBvcDE4JHNtZWRpYTI8PTQsIDEsIDApCmxhcG9wMTgkdHdfdXNlciA8LSBpZmVsc2UobGFwb3AxOCRzbWVkaWE0PT0xICYgbGFwb3AxOCRzbWVkaWE1PD00LCAxLCAwKQpsYXBvcDE4JHdhX3VzZXIgPC0gaWZlbHNlKGxhcG9wMTgkc21lZGlhNz09MSAmIGxhcG9wMTgkc21lZGlhODw9NCwgMSwgMCkKYGBgCgpFc3RhIHZhcmlhYmxlcyBzb24gZ3JhZmljYWRhcyBlbiBlbCByZXBvcnRlIGVuIGVsIEdyw6FmaWNvIDMuMS4KUGFyYSByZXByb2R1Y2lyIGVzdG9zIGRhdG9zLCBzZSBwdWVkZSBkZXNjcmliaXIgZXN0YXMgdmFyaWFibGVzLgoKYGBge3IgdXNlcn0KcHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JGZiX3VzZXIpKSoxMDAKcHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHR3X3VzZXIpKSoxMDAKcHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHdhX3VzZXIpKSoxMDAKYGBgCgpDb21vIGVuIGdyw6FmaWNvcyBhbnRlcmlvcmVzLCBjb24gZXN0b3MgZGF0b3Mgc2UgcHVlZGUgY3JlYXIgdW4gZGF0YWZyYW1lIHF1ZSBzZSB1dGlsaXphcsOtYSBwYXJhIGhhY2VyIGxvcyBncsOhZmljb3MgY2lyY3VsYXJlcyBtb3N0cmFkb3MgZW4gZWwgcmVwb3J0ZS4KClBhcmEgcmVwbGljYXIgZWwgY3VhZHJvIGRlIHVzbyBkZSByZWRlcyBzb2NpYWxlcyBwb3IgcGHDrXMsIHByaW1lcm8sIHNlIGNyZWFuIGxhcyB0YWJsYXMgYml2YXJpYWRhcyBjb24gZWwgcG9yY2VudGFqZSBkZSBsb3MgcXVlIHVzYW4geSBlbCBwb3JjZW50YWplIGRlIGxvcyBxdWUgbm8gdXNhbiBjYWRhIHJlZCBzb2NpYWwgZW4gY2FkYSBwYcOtcy4KRXN0YXMgdGFibGFzIHNlIGd1YXJkYW4gZW4gb2JqZXRvcyBkZSBSLgpMdWVnbyBzZSB1bmVuIGVzdG9zIG9iamV0b3MgdXNhbmRvIGxvcyBjb21hbmRvcyBgY2JpbmRgIHBhcmEganVudGFyIGxhcyBjb2x1bW5hcyB5IGBhcy5kYXRhLmZyYW1lYCBwYXJhIHVuaXIgbGFzIHRhYmxhcyBjb21vIHVuIGRhdGFmcmFtZS4KRXN0YSB0YWJsYSBwcmVzZW50YSB0YW1iacOpbiBsb3MgcG9yY2VudGFqZXMgZGUgbG9zIHF1ZSBObyB1c2FuIGVzdGFzIHJlZGVzIHNvY2lhbGVzLgpQYXJhIHByZXNlbnRhciB1bmEgdGFibGEgcXVlIGluY2x1eWEgc29sbyBhIGxvcyBxdWUgc8OtIHVzYW4gbGFzIHJlZGVzIHNvY2lhbGVzLCBzZSBlbGltaW5hbiBlc3RhcyBjb2x1bW5hcywgdXNhbmRvIGxhIGVzcGVjaWZpY2FjacOzbiBgWywgYygtMSwtMywtNSldYCwgcXVlIGluZGljYSBxdWUgc2UgcXVpZXJlIGVsaW1pbmFyIGxhcyBjb2x1bW5hcyAxLCAzIHkgNS5GaW5hbG1lbnRlLCBzZSBjYW1iaWEgZWwgbm9tYnJlIGRlIGxhcyBjb2x1bW5hcyBkZWwgZGF0YWZyYW1lLgoKYGBge3IgdGFibGEgcG9yIHBhw61zfQpmYnBhaXMgPC0gcm91bmQocHJvcC50YWJsZSh0YWJsZShsYXBvcDE4JHBhaXMsIGxhcG9wMTgkZmJfdXNlciksIDEpLCAzKSoxMDAKdHdwYWlzIDwtIHJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AxOCRwYWlzLCBsYXBvcDE4JHR3X3VzZXIpLCAxKSwgMykqMTAwCndocGFpcyA8LSByb3VuZChwcm9wLnRhYmxlKHRhYmxlKGxhcG9wMTgkcGFpcywgbGFwb3AxOCR3YV91c2VyKSwgMSksIDMpKjEwMAp0YWJsYXBhaXMgPC0gYXMuZGF0YS5mcmFtZShjYmluZChmYnBhaXMsIHR3cGFpcywgd2hwYWlzKSkKdGFibGFwYWlzIDwtIHRhYmxhcGFpc1ssIGMoLTEsLTMsLTUpXQp2YXJuYW1lcyA8LSBjKCJVc2EgRmFjZWJvb2siLCAiVXNhIFR3aXR0ZXIiLCAiVXNhIFdoYXRzYXBwIikKY29sbmFtZXModGFibGFwYWlzKSA8LSB2YXJuYW1lcwp0YWJsYXBhaXMKYGBgCgpQYXJhIHRlbmVyIHVuYSBtZWpvciBwcmVzZW50YWNpw7NuIGRlIGxhIHRhYmxhIHNlIHRpZW5lbiBkb3MgYWx0ZXJuYXRpdmFzOiBsYSBwcmltZXJhIGNvbiBsYSBsaWJyZXLDrWEgYGtuaXRyYCB5IGxhIG90cmEgY29uIGxhIGxpYnJlcsOtYSBgZm9ybWF0dGFibGVgLgoKYGBge3IgdGFibGEgcG9yIHBhw61zIG1lam9yYWRhfQpsaWJyYXJ5KGtuaXRyKQprYWJsZShoZWFkKHRhYmxhcGFpcyksIGZvcm1hdD0ibWFya2Rvd24iLCBkaWdpdHM9MSkKbGlicmFyeShmb3JtYXR0YWJsZSkKZm9ybWF0dGFibGUodGFibGFwYWlzKQpgYGAKCiMjIENydWNlIGNvbiB2YXJpYWJsZXMgc29jaW9kZW1vZ3LDoWZpY2FzCgpFbiBsYSBww6FnaW5hIDU2IGRlbCByZXBvcnRlICJFbCBwdWxzbyBkZSBsYSBkZW1vY3JhY2lhIiBzZSBwcmVzZW50YSBsb3MgcmVzdWx0YWRvcyBkZWwgY3J1Y2UgZW50cmUgbGFzIHZhcmlhYmxlcyB1c28gZGUgcmVkZXMgc29jaWFsZXMgeSB2YXJpYWJsZXMgc29jaW9kZW1vZ3LDoWZpY2FzIGNvbW8gdXJiYW5vL3J1cmFsLCBzZXhvLCBlZGFkLCByaXF1ZXphIHkgYcOxb3MgZGUgZWR1Y2FjacOzbi4KCiFbXShUYWJsYTMuMi5wbmcpe3dpZHRoPSI2NjMifQoKTGEgdmFyaWFibGUgInExIiByZWdpc3RyYSBlbCBnw6luZXJvIGRlbCBlbnRyZXZpc3RhZG8uCkVzdGEgdmFyaWFibGUgZXN0w6EgY29kaWZpY2FkYSBkZSBsYSBzaWd1aWVudGUgbWFuZXJhOgoKMS4gIEhvbWJyZQoyLiAgTXVqZXIKClBhcmEgY29uc3RydWlyIHVuYSB2YXJpYWJsZSAiZHVtbXkiIGxsYW1hZGEgImhvbWJyZSIsIGRlIHRhbCBtYW5lcmEgcXVlIGhvbWJyZSBzZWEgMSB5IG11amVyIHNlYSAwLCB1bmEgZm9ybWEgZGUgaGFjZXJsbyBlcyBkZSBtYW5lcmEgYWxnZWJyYWljYSAoMi12YXJpYWJsZSBxMSkuCkRlIGVzdGEgbWFuZXJhLCBhaG9yYSBsb3MgaG9tYnJlcyBtYW50aWVuZSBlbCB2YWxvciAxICgyLTEpIHkgbGFzIG11amVyZXMgcGFzYXIgYSBzZXIgMCAoMi0yKS4KRW4gZXN0ZSBjYXNvLCBsYSBudWV2YSB2YXJpYWJsZSAiaG9tYnJlIiBzZSBjcmVhIGNvbW8gdW5hIHVuYSB2YXJpYWJsZSBudW3DqXJpY2EuClZhbW9zIGEgbWFudGVuZXIgYSBsYSB2YXJpYWJsZSBjb21vICJudW0iIHBhcmEsIG3DoXMgYWJham8sIHBvZGVyIGNhbGN1bGFyIGxhIG1lZGlhIGRlIGVzdGEgdmFyaWFibGUgKGNvc2EgcXVlIG5vIHNlIHB1ZWRlIGhhY2VyIGRlIHVuYSB2YXJpYWJsZSBkZWNsYXJhZGEgY29tbyBmYWN0b3IpLgoKYGBge3IgaG9tYnJlfQpsYXBvcDE4JGhvbWJyZSA8LSAyLWxhcG9wMTgkcTEKdGFibGUobGFwb3AxOCRob21icmUpCmBgYAoKTGEgdmFyaWFibGUgdXJiYW5vL3J1cmFsIHNlIGxsYW1hICJ1ciIgZW4gbGEgYmFzZSBkZSBkYXRvcyB5IGVzdMOhIGNvZGlmaWNhZGEgZGUgbGEgc2lndWllbnRlIG1hbmVyYToKCjEuICBVcmJhbm8KMi4gIFJ1cmFsCgpEZSBsYSBtaXNtYSBtYW5lcmEgcXVlIGNvbiBnw6luZXJvLCBzZSB1c2EgbGEgZsOzcm11bGEgMi0gdmFyaWFibGUgdXIsIHBlcm8gZXN0YSB2YXJpYWJsZSBzw60gc2UgY29udmllcnRlIGVuIGZhY3RvciB5IHNlIGV0aXF1ZXRhLgoKYGBge3IgdXJiYW5vfQpsYXBvcDE4JHVyYmFuIDwtIDItbGFwb3AxOCR1cgpsYXBvcDE4JHVyYmFuID0gYXMuZmFjdG9yKGxhcG9wMTgkdXJiYW4pCmxldmVscyhsYXBvcDE4JHVyYmFuKSA8LSBjKCJSdXJhbCIsICJVcmJhbm8iKQp0YWJsZShsYXBvcDE4JHVyYmFuKQpgYGAKClNlIHByZXNlbnRhcsOhIGxhcyB0YWJsYXMgY3J1emFkYXMgZGVsIHVzbyBkZSByZWRlcyBzb2NpYWxlcyBwb3IgYWxndW5vIGRlIGxhcyB2YXJpYWJsZSBzb2Npb2RlbW9ncsOhZmljYXMsIHBhcmEgZW50ZW5kZXIgbWVqb3IgY8OzbW8gc2UgY29uc3RydXllIGxhIHRhYmxhIGdlbmVyYWwuClBvciBlamVtcGxvLCBlbCByZXBvcnRlIG11ZXN0cmEgZW4gbGEgVGFibGEgMy4yLCBsdWVnbyBkZSBsYSBjb2x1bW5hIGRlIHBvYmxhY2nDs24gZ2VuZXJhbCwgbGFzIGNvbHVtbmFzIHBhcmEgdXN1YXJpb3MgeSBubyB1c3VhcmlvcyBkZSBXaGF0c2FwcCAodmFyaWFibGUgIndhX3VzZXIiKSB5IGVuIGxhcyBmaWxhcywgbGEgcHJpbWVyYSBjb3JyZXNwb25kZSBhIHVyYmFubyAodmFyaWFibGUgInVyYmFuIiwgZG9uZGUgMCBlcyBydXJhbCB5IDEgdXJiYW5vKS4KU2UgcHJlc2VudGEgcXVlIGVudHJlIGxvcyB1c3VhcmlvcyBkZSBXaGF0c2FwcCwgZWwgNzYuNyUgc29uIHVyYmFub3MgeSBlbnRyZSBsb3Mgbm8gdXN1YXJpb3MsIGVsIDYyJSBzb24gdXJiYW5vcy4KRXN0b3MgZGF0b3Mgc2UgZ2VuZXJhbiBjb24gZWwgY29tYW5kbyBgdGFibGVgIHF1ZSBwZXJtaXRlIGhhY2VyIHVuYSB0YWJsYSBkZSBjb250aW5nZW5jaWEgZGUgMiB2YXJpYWJsZXMuCkVuIGVzdGUgY2FzbyBzZSB0aWVuZSBxdWUgbm90YXIgcXVlIGNhZGEgdmFyaWFibGUgdGllbmUgdW4gdMOtdHVsby4KRGUgZXN0YSBtYW5lcmEgZWwgY29tYW5kbyBlcyBgdGFibGUodMOtdHVsbzEgPSB2YXIxLCB0w610dWxvMiA9IHZhcjIpYC4KTHVlZ28sIHNlIHVzYSBlbCBjb21hbmRvIGBwcm9wLnRhYmxlYCBwYXJhIHF1ZSBubyBzZSBtdWVzdHJlIGxhcyBvYnNlcnZhY2lvbmVzLCBzaW5vIGxvcyBwb3JjZW50YWplcy4KRXN0ZSBjb21hbmRvIHBlcm1pdGUgY2FsY3VsYXIgbG9zIHBvcmNlbnRhamVzIHNvYnJlIGVsIHRvdGFsIChsYSBvcGNpw7NuIHBvciBkZWZlY3RvKSwgc29icmUgbGFzIGZpbGFzIHkgc29icmUgbGFzIGNvbHVtbmFzLgpQYXJhIGNhbGN1bGFyIHNvYnJlIGxhcyBjb2x1bW5hcyBzZSBkZWJlIGVzcGVjaWZpY2FyIGBwcm9wLnRhYmxlKHRhYmxlKC4uLiksIDIpYC4KU2kgc2UgcXVpc2llcmEgZWwgcG9yY2VudGFqZSBzb2JyZSBsYXMgZmlsYXMsIGVsIGPDs2RpZ28gc2Vyw61hIGBwcm9wLnRhYmxlKHRhYmxlKC4uLiksIDEpYC4KRXN0YSB0YWJsYSBzZSBwdWVkZW4gZ3VhcmRhciBjb21vIHVuIGRhdGFmcmFtZSBjb24gZWwgY29tYW5kbyBgYXMuZGF0YS5mcmFtZWAgZW4gdW4gbnVldm8gb2JqZXRvICJ0MSIuCgpgYGB7ciB0YWJsYSBXaHhVcn0KdDEgPC0gYXMuZGF0YS5mcmFtZShyb3VuZChwcm9wLnRhYmxlKHRhYmxlKFVyYmFubyA9IGxhcG9wMTgkdXJiYW4sIFVzdWFyaW8gPSBsYXBvcDE4JHdhX3VzZXIpLCAyKSoxMDAsIDEpKQp0MQpgYGAKCkxhIGZpbGFzIGNvcnJlc3BvbmRpZW50ZXMgYSAiVXJiYW5vIiBkZSBlc3RhIHRhYmxhIHJlcHJvZHVjZW4gbG9zIGRhdG9zIGRlIGxhIFRhYmxhIDMuMjogNjIuMSUgc29uIHVyYmFub3MgZW50cmUgbG9zIG5vIHVzdWFyaW9zIGRlIFdoYXRzYXBwIHkgNzYuNyUgc29uIHVyYmFub3MgZW50cmUgbG9zIHVzdWFyaW9zLgoKQWhvcmEgc2UgcHJlc2VudGFyw6EgbGEgdGFibGEgZW50cmUgdXN1YXJpb3MgZGUgRmFjZWJvb2sgKHZhcmlhYmxlICJmYl91c2VyIikgeSBob21icmUgKHZhcmlhYmxlICJob21icmUiKSwgcGVybyBwcmVzZW50YW5kbyBzb2xvIGxvcyBwb3JjZW50YWplcyB1c2Fkb3MgZW4gbGEgdGFibGEgeSBhaG9yYSB1c2FuZG8gZWwgZXN0aWxvIGRlIGPDs2RpZ28gZGVsIFRpZHl2ZXJzZSwgdXNhbmRvIGVsIG9wZXJhZG9yICJwaXBlIi4KTG8gcHJpbWVybyBlcyBkZWZpbmlyIGxhIHZhcmlhYmxlICJmYl91c2VyIiBjb21vIHVuIGZhY3RvciB5IGV0aXF1ZXRhcmxhLgpMdWVnbywgc2UgdXNhIGVsIGNvbWFuZG8gYHN1YnNldGAgcGFyYSBmaWx0cmFyIGxvcyBjYXNvcyBwZXJkaWRvcyBlbiBsYSB2YXJpYWJsZSAiZmJfdXNlciIuCkx1ZWdvIHNlIHBpZGUgcXVlIGxvcyByZXN1bHRhZG9zIHNlIGFncnVwZW4gcG9yIGNhdGVnb3LDrWFzIGRlIGxhIHZhcmlhYmxlICJmYl91c2VyIi4KQ29uIGVsIGNvbWFuZG8gYHN1bW1hcmlzZWAgc2UgZ3VhcmRhIGVuIGxhIGNvbHVtbmEgImhvbWJyZSIgZWwgcHJvbWVkaW8gZGUgbGEgdmFyaWFibGUgImhvbWJyZSIsIGNvbiBlbCBjb21hbmRvIGBtZWFuYCBxdWUgaW5jbHV5ZSBsYSBlc3BlY2lmaWNhY2nDs24gYG5hLnJtPVRgIHBhcmEgbm8gaW5jbHVpciBlbiBlbCBjw6FsY3VsbyBsb3MgdmFsb3JlcyBwZXJkaWRvcy4KRW4gZXN0ZSBjYXNvIHNlIGFwcm92ZWNoYSBxdWUgbGEgdmFyaWFibGUgImhvbWJyZSIgZXMgdW5hIHZhcmlhYmxlIGR1bW15LCBkZSB0YWwgbWFuZXJhIHF1ZSBlbCBwcm9tZWRpbyBjb3JyZXNwb25kZSBhIGxhIHByb3BvcmNpw7NuIGRlIGhvbWJyZXMuCgpgYGB7ciB0YWJsIEZieEhvbWJyZSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGFwb3AxOCRmYl91c2VyID0gYXMuZmFjdG9yKGxhcG9wMTgkZmJfdXNlcikKbGV2ZWxzKGxhcG9wMTgkZmJfdXNlcikgPC0gYygiTm8gdXN1YXJpbyIsICJVc3VhcmlvIikKdGFibGExIDwtIHN1YnNldChsYXBvcDE4LCAhaXMubmEoZmJfdXNlcikpICU+JSAjUGFyYSBubyBpbmNsdWlyIGFsIGdydXBvIGRlIE5BIGRlIHVzdWFyaW9zIGRlIEZhY2Vib29rCiAgZ3JvdXBfYnkoZmJfdXNlcikgJT4lCiAgZHBseXI6OnN1bW1hcmlzZShIb21icmU9bWVhbihob21icmUsIG5hLnJtPVQpKjEwMCkgI1NlIGluY2x1eWUgbmEucm09VCBwb3JxdWUgaG9tYnJlIHRpZW5lIE5Bcwp0YWJsYTEKYGBgCgpFc3RvcyBzb24gbG9zIHBvcmNlbnRhamVzIHBhcmEgbG9zIHVzdWFyaW9zIGRlIEZhY2Vib29rLCBlbiBsYSBmaWxhIGRlIGxhIHZhcmlhYmxlIEhvbWJyZSBkZSBsYSBUYWJsYSAzLjIuCkVzIGRlY2lyLCBlbnRyZSBsb3Mgbm8gdXN1YXJpb3MsIDQ5LjklIHNvbiBob21icmVzIHkgZW50cmUgbG9zIHVzdWFyaW9zIGVzdGUgcG9yY2VudGFqZSBlcyA0OS43JS4KSGFzdGEgYXF1w60gc2UgaGEgcmVjb25zdHJ1aWRvIGFsZ3Vub3MgcmVzdWx0YWRvcyBkZSBsYSBUYWJsYSAzLjIuCkxvcyBkZW3DoXMgZGF0b3MgcHVlZGVuIHNlZ3VpciBzaWVuZG8gcmVjb25zdHJ1aWRvcyBtZWRpYW50ZSBjb21iaW5hY2lvbmVzIGRlIGxhcyB2YXJpYWJsZXMgZGUgdXN1YXJpb3MgZGUgcmVkZXMgc29jaWFsZXMgeSBsYXMgdmFyaWFibGVzIHNvY2lvZGVtb2dyw6FmaWNhcy4KCiMjIEdyw6FmaWNvIGRlIGJhcnJhcyBkZSBkb3MgdmFyaWFibGVzCgpFbCBjcnVjZSBlbnRyZSB1c3VhcmlvcyBkZSBXaGF0c2FwcCB5IGxhIHZhcmlhYmxlIHVyYmFubyBzZSBwdWVkZSB2ZXIgdGFtYmnDqW4gZW4gdW4gZ3LDoWZpY28gZGUgYmFycmFzIGFncnVwYWRhcy4KTG8gcHJpbWVybyBxdWUgaGFyZW1vcyBlcyBkZWZpbmlyIGxhIHZhcmlhYmxlICJ3YV91c2VyIiBjb21vIGZhY3RvciB5IGV0aXF1ZXRhcmxhLgpMdWVnbywgc2UgcmVxdWllcmUgY3JlYXIgdW5hIHRhYmxhIGNvbiBsb3MgZGF0b3MgYWdydXBhZG9zLgpTZSBwdWVkZSB1c2FyIGVsIGRhdGFmcmFtZSAidDEiIGNyZWFkbyBhbnRlcmlvcm1lbnRlLCBwZXJvIGFxdcOtIHVzYXJlbW9zIG51ZXZhbWVudGUgZWwgb3BlcmFkb3IgInBpcGUiIHBhcmEgcmVjcmVhciBsb3MgZGF0b3MuClBhcmEgZXN0bywgc2UgYWdydXBhIHRhbnRvIHBvciB1c28gZGUgV2hhdHNhcHAgY29tbyBwb3IgdXJiYW5vL3J1cmFsLCBlcyBkZWNpciwgZW4gY3VhdHJvIGNvbWJpbmFjaW9uZXMuCkVuIGNhZGEgc3ViZ3J1cG8gc2UgY2FsY3VsYSBlbCBuLgpEYWRvIHF1ZSBsb3MgJSBzZSB0aWVuZW4gcXVlIGNhbGN1bGFyIHBvciBjYWRhIGdydXBvIGRlICJ3YV91c2VyIiwgc2UgdnVlbHZlIGEgYWdydXBhciB5IHNlIGNhbGN1bGEgbG9zICUgZGUgY2FkYSBzdWJncnVwbywgZGUgdGFsIG1hbmVyYSBxdWUgbG9zIHBvcmNlbnRhamVzIHN1bWVuIDEwMCUgZW4gY2FkYSBzdWJncnVwbyBkZSAid2FfdXNlciIuCgpgYGB7ciB0YWJsYSB3YX0KbGFwb3AxOCR3YV91c2VyID0gYXMuZmFjdG9yKGxhcG9wMTgkd2FfdXNlcikKbGV2ZWxzKGxhcG9wMTgkd2FfdXNlcikgPC0gYygiTm8gdXN1YXJpbyIsICJVc3VhcmlvIikKZmFjZSA8LSBzdWJzZXQobGFwb3AxOCwgIWlzLm5hKHdhX3VzZXIpKSAlPiUgI1NlIHVzYSAhaXMubmEgcGFyYSBxdWUgbm8gc2UgcmVwb3J0ZSBsb3MgTkEgZW4gbGEgdGFibGEKICBncm91cF9ieSh3YV91c2VyLCB1cmJhbikgJT4lICNTZSBjb25maWd1cmFuIGxvcyBncnVwb3MKICBkcGx5cjo6Y291bnQoKSAlPiUgI1NlIGNhbGN1bGEgZWwgbgogIGdyb3VwX2J5KHdhX3VzZXIpICU+JSAjU2UgYWdydXBhIHBvciB1c3VhcmlvIGRlIFdoYXRzYXBwCiAgZHBseXI6Om11dGF0ZShwb3JjZW50YWplID0gcm91bmQobi9zdW0obiksIDMpKjEwMCkgI1NlIGNhbGN1bGEgZWwgcG9yY2VudGFqZSBlbiBjYWRhIGdydXBvIGRlIFdoYXRzYXBwCmZhY2UKYGBgCgpMb3MgZGF0b3Mgc2UgZXN0YSBudWV2YSB0YWJsYSBzb24gZXhhY3RhbWVudGUgaWd1YWxlcyBhIGxvcyBkZSAidDEiLgpDb24gbGEgdGFibGEgbGlzdGEsIHNlIHVzYSBlbCBjb21hbmRvIGBnZ3Bsb3RgIGRlZmluaWVuZG8gcXVlICJ3YV91c2VyIiBzZWEgbGEgdmFyaWFibGUgZW4gZWwgZWplIFgsIHF1ZSBlbCBlamUgWSBzZWEgZWwgcG9yY2VudGFqZSB5IHF1ZSBsb3Mgc3ViZ3J1cG9zIHNlIGZvcm1lbiBwb3IgbGEgdmFyaWFibGUgInVyYmFuIiBjb24gbGEgZXNwZWNpZmljYWNpw7NuIGBmaWxsYC4KU2UgdXNhIGxhIGVzcGVjaWZpY2FjacOzbiBgZG9kZ2VgIGVuIGBnZW9tX2JhcmAgcGFyYSB0ZW5lciBsYXMgYmFycmFzIHNlcGFyYWRhcyBwb3IgY2FkYSBncnVwby4KCmBgYHtyIGdyYWZpY28gYWdydXBhZG99CmdncGxvdChkYXRhPWZhY2UsIGFlcyh4PXdhX3VzZXIsIHk9cG9yY2VudGFqZSwgZmlsbD11cmJhbiwgeW1heD0xMDApKSsKICBnZW9tX2Jhcihwb3NpdGlvbj0iZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUocG9yY2VudGFqZSwgIiUiLCBzZXA9IiIpKSwgCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOSksIHZqdXN0PS0wLjI1KSsKICB5bGFiKCJQb3JjZW50YWplIikrCiAgeGxhYigiVXN1YXJpbyBkZSBXaGF0c2FwcCIpCmBgYAoKU2kgcXVpc2nDqXJhbW9zIGhhY2VyIGVsIGdyw6FmaWNvIGNvbiBiYXJyYXMgYXBpbGFkYXMsIHNlIHRpZW5lIHF1ZSBjYW1iaWFyIGxhIGVzcGVjaWZpY2FjacOzbiBkZSBgcG9zaXRpb249InN0YWNrImAgZW4gYGdlb21fYmFyYCB5IGxhIGVzcGVjaWZpY2FjacOzbiBgcG9zaXRpb249cG9zaXRpb25fc3RhY2soKWAgZGUgYGdlb21fdGV4dGAuCgpgYGB7ciBiYXJyYXMgYXBpbGFkYXN9CmdncGxvdChkYXRhPWZhY2UsIGFlcyh4PXdhX3VzZXIsIHk9cG9yY2VudGFqZSwgZmlsbD11cmJhbiwgeW1heD0xMDApKSsKICBnZW9tX2Jhcihwb3NpdGlvbj0ic3RhY2siLCBzdGF0PSJpZGVudGl0eSIpKwogIGdlb21fdGV4dChhZXMobGFiZWw9cGFzdGUocG9yY2VudGFqZSwgIiUiLCBzZXA9IiIpKSwgCiAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKCksIHZqdXN0PTIuNSkrCiAgeWxhYigiUG9yY2VudGFqZSIpKwogIHhsYWIoIlVzdWFyaW8gZGUgV2hhdHNhcHAiKQpgYGAKCkVuIGFtYm9zIGNhc29zIGxhcyBiYXJyYXMgY2VsZXN0ZXMgaW5kaWNhbiBsb3MgcG9yY2VudGFqZXMgcmVwb3J0YWRvcyBlbiBsYSB0YWJsYSAzLjIgZGVsIHJlcG9ydGUgeSBjb3JyZXNwb25kZW4gYSBsYSBwcm9wb3JjacOzbiBkZSBwZXJzb25hcyBxdWUgdml2ZW4gZW4gZWwgw6FtYml0byB1cmJhbm8gZW50cmUgbG9zIHVzdWFyaW9zIHkgbG9zIG5vIHVzdWFyaW9zLgoKIyBSZXN1bWVuCgpFbiBlc3RlIGRvY3VtZW50byBzZSBoYSB0cmFiYWphZG8gY29uIHZhcmlhYmxlIGNhdGVnw7NyaWNhcyBvcmRpbmFsZXMsIGNvbW8gbGEgZnJlY3VlbmNpYSBkZSB1c28gZGUgcmVkZXMgc29jaWFsZXMuClRhbWJpw6luIHNlIGhhIGludHJvZHVjaWRvIGFsIHVzbyBkZSB0YWJsYXMgZGUgY29udGluZ2VuY2lhIGRlIGRvcyB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzIHkgbGEgY3JlYWNpw7NuIGRlIGdyw6FmaWNvcyBkZSBiYXJyYXMgYWdydXBhZGFzIHBhcmEgMiB2YXJpYWJsZXMuCgojIEPDoWxjdWxvcyBpbmNsdXllbmRvIGVsIGVmZWN0byBkZSBkaXNlw7FvCgojIyBFamVtcGxvIGNvbiBkYXRvcyBkZSBsYSByb25kYSAyMDIxCgpDb24gbG9zIGRhdG9zIGRlIGxhIHJvbmRhIDIwMjEgZGVsIEJhcsOzbWV0cm8gZGUgbGFzIEFtw6lyaWNhcywgaGVtb3MgY2FsY3VsYWRvIGxvcyBwb3JjZW50YWplcyBkZSBsYSB2YXJpYWJsZSBxdWUgbWlkZSBzaSBsb3Mgdm90b3Mgc2UgaGFuIGNvbnRhZG8ganVzdGFtZW50ZS4KRWwgZ3LDoWZpY28gcXVlIGhlbW9zIGNyZWFkbyBoYSBzaWRvIHBhcmEgZWwgdG90YWwgZGUgbGEgbXVlc3RyYSwgZXMgZGVjaXIsIGRlIHRvZG9zIGxvcyBwYcOtc2VzLgpFbCBHcsOhZmljbyAyLjUgZGVsIHJlcG9ydGUgRWwgUHVsc28gZGUgbGEgRGVtb2NyYWNpYSBwcmVzZW50YSBsb3MgcmVzdWx0YWRvcyBwYXJhIGNhZGEgcGHDrXMuCgpTaSBjYWxjdWzDoXJhbW9zIGxvcyBwb3JjZW50YWplcyBjb24gZWwgY29tYW5kbyBgdGFibGVgIHkgYHByb3AudGFibGVgIHRlbmRyw61hbW9zIHJlc3VsdGFkb3MgZGlmZXJlbnRlcyBhIGxvcyBtb3N0cmFkb3MgZW4gZWwgZ3LDoWZpY28uClBvciBlamVtcGxvLCBlbiBlbCBwYcOtcyA1LCBxdWUgZXMgTmljYXJhZ3VhLCBsb3MgcmVzdWx0YWRvcyBpbmRpY2FuIHF1ZSAyNiUgZGUgY2l1ZGFkYW5vcyBkZSBlc2UgcGHDrXMgaW5kaWNhIHF1ZSBsb3Mgdm90b3Mgc2llbXByZSBzZSBjdWVudGFuIGp1c3RhbWVudGUsIDQ5JSBxdWUgYWxndW5hcyB2ZWNlcyBzZSBjdWVudGFuIGp1c3RhbWVudGUgeSAyNC40JSBxdWUgbnVuY2EuClNpbiBlbWJhcmdvLCBlbCBncsOhZmljbyBpbmRpY2EgcXVlIGVuIE5pY2FyYWd1YSwgMjklIGluZGljYSBxdWUgbnVuY2EgZGUgY3VlbnRhIGp1c3RhbWVudGUsIDQ1JSBpbmRpY2EgcXVlIGFsZ3VuYXMgdmVjZXMgeSAyNSUgcXVlIHNpZW1wcmUuCkVzdG9zIHBvcmNlbnRhamVzIG5vIGNvcnJlc3BvbmRlbiBhIGxvcyBxdWUgc2UgZW5jdWVudHJhbiBjb24gZXN0b3MgY29tYW5kb3MuCgpgYGB7ciBjcnVjZSBzaW4gcG9uZGVyYXJ9CnJvdW5kKHByb3AudGFibGUodGFibGUobGFwb3AyMSRwYWlzLCBsYXBvcDIxJGNvdW50ZmFpcjFyKSwgMSksIDMpKjEwMApgYGAKCkVzdGEgZGlmZXJlbmNpYSBlcyBkZWJpZG8gYSBxdWUgbG9zIGNvbWFuZG9zIGB0YWJsZWAgeSBgcHJvcC50YWJsZWAgbm8gaW5jbHV5ZW4gZWwgZWZlY3RvIGRlIGRpc2XDsW8geSBlbCBmYWN0b3IgZGUgZXhwYW5zacOzbiBlbiBsb3MgY8OhbGN1bG9zLgpNw6FzIGluZm9ybWFjacOzbiBzb2JyZSBlc3RhcyBkaWZlcmVuY2lhcyBzZSBlbmN1ZW50cmEgW2FxdcOtXShodHRwczovL2FydHVyb21hbGRvbmFkby5naXRodWIuaW8vQmFyb21ldHJvRWR1X1dlYi9FeHBhbnNpb24uaHRtbCkuCgpQYXJhIHJlcGxpY2FyIGxvcyByZXN1bHRhZG9zIGRlbCBHcsOhZmljbyAyLjUgaGF5IGFsZ3VuYXMgb3BjaW9uZXMuCkxhIHByaW1lcmEgZXMgbWVkaWFudGUgbGEgbGlicmVyw61hIGVzcGVjaWFsaXphZGEgYHN1cnZleWAuCgpQYXJhIHBvZGVyIHVzYXIgZXN0YSBsaWJyZXLDrWEsIHByaW1lcm8gZGViZW1vcyBwcmVwYXJhciBsYSBiYXNlIGRlIGRhdG9zLCBlbGltaW5hbmRvIGxvcyB2YWxvcmVzIHBlcmRpZG9zIGRlIGxhcyB2YXJpYWJsZXMgcXVlIGRlZmluZW4gZWwgZGlzZcOxby4KVW4gcGFzbyBhZGljaW9uYWwgZXMgdHJhbnNmb3JtYXIgbGFzIHZhcmlhYmxlcyBkZWwgZGF0YWZyYW1lLgpFc3RvIGVzIGRlYmlkbyBhIHF1ZSBjdWFuZG8gc2UgaW1wb3J0YW4sIGVsIHNpc3RlbWEgbGVlIGxhcyB2YXJpYWJsZXMgY29tbyB0aXBvICJoYXZlbl9sYWJlbGxlZCIsIGVzIGRlY2lyLCBtYW50aWVuZSBsYXMgZXRpcXVldGFzIGRlIGxhcyB2YXJpYWJsZXMsIGNvbiBsbyBxdWUgc2UgcG9kcsOtYSBwcm9kdWNpciB1biBsaWJybyBkZSBjw7NkaWdvcy4KRXN0byBlcyDDunRpbCBlbiBvdHJhcyBvY2FzaW9uZXMsIHBlcm8gZ2VuZXJhIHByb2JsZW1hcyBjb24gbGEgbGlicmVyw61hIGBzdXJ2ZXlgLgpQYXJhIGVzdG8gdHJhbnNmb3JtYW1vcyBsYXMgdmFyaWFibGVzIGEgb3RybyB0aXBvIGNvbiBlbCBjb21hbmRvIGBzYXBwbHlgLgoKYGBge3IgcHJlcGFyYWNpb24gZGUgYmFzZSwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30KbGFwb3AyMSA9IHN1YnNldChsYXBvcDIxLCAhaXMubmEod2VpZ2h0MTUwMCkpCnNhcHBseShsYXBvcDIxLCBoYXZlbjo6emFwX2xhYmVscykKYGBgCgpVbmEgdmV6IHByZXBhcmFkYSBsYSBiYXNlIGRlIGRhdG9zLCBzZSBhY3RpdmEgbGEgbGlicmVyw61hIHkgc2UgZGVmaW5lIGVsIGRpc2XDsW8uCkVuIGVsIG3Ds2R1bG8gYW50ZXJpb3IsIHRhbWJpw6luIHVzYW1vcyBlc3RhIGxpYnJlcsOtYSBwYXJhIGNhbGN1bGFyIGxvcyByZXN1bHRhZG9zIGNvbiBlbCBlZmVjdG8gZGUgZGlzZcOxbyBlbiBsYSByb25kYSAyMDE4LgpBIGRpZmVyZW5jaWEgZGUgZXNlIGPDs2RpZ28sIGVzIHF1ZSBsYSByb25kYSAyMDIxIGRlbCBCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgdXRpbGl6w7MgbGEgbW9kYWxpZGFkIHRlbGVmw7NuaWNhLCB5IG5vIGNhcmEgYSBjYXJhLCBwb3IgbG8gcXVlIGFob3JhIGxhIHVuaWRhZCBwcmltYXJpYSBkZSBtdWVzdHJlbyBlcyBlbCBpbmRpdmlkdW8sIHkgYXPDrSBlc3TDoSBkZWZpbmlkYSBlbiBsYSB2YXJpYWJsZSAidXBtIi4KTGEgdmFyaWFibGUgcXVlIGRlZmluZSBsb3MgZXN0cmF0b3MgZXMgInN0cmF0YSIgKHkgbm8gImVzdHJhdG9wcmkiIGNvbW8gZW4gbGEgcm9uZGEgMjAxOCkuCkxhIHZhcmlhYmxlIGRlIHBvbmRlcmFjacOzbiBzaWd1ZSBzaWVuZG8gIndlaWdodDE1MDAiLgoKQ29uIGVzdG9zIGRhdG9zIGNhbGN1bGFtb3MgZ3VhcmRhbW9zIGVsIGRpc2XDsW8gZW4gdW4gb2JqZXRvICJkaXNlbm8yMSIuCgpgYGB7ciBkaXNlbm99CmxpYnJhcnkoc3VydmV5KQpkaXNlbm8yMSA9IHN2eWRlc2lnbihpZHMgPSB+dXBtLCBzdHJhdGEgPSB+c3RyYXRhLCB3ZWlnaHRzID0gfndlaWdodDE1MDAsIG5lc3Q9VFJVRSwgZGF0YT1sYXBvcDIxKQpgYGAKCkxhIGxpYnJlcsOtYSBgc3VydmV5YCBpbmNsdXllIGNvbWFuZG9zIG5hdGl2b3MgcGFyYSBoYWNlciBtw7psdGlwbGVzIG9wZXJhY2lvbmVzIHF1ZSBpbmNsdXlhbiBlbCBlZmVjdG8gZGUgZGlzZcOxby4KVW5vIGRlIGVzb3MgY29tYW5kb3MgZXMgYHN2eXRhYmxlYCBxdWUgbm9zIHBlcm1pdGUgaGFjZXIgbGEgdGFibGEgY3J1emFkYSBlbnRyZSBsYSB2YXJpYWJsZSAiY291bnRmYWlyMXIiIHkgInBhaXMiLCBlc3BlY2lmaWNhbmRvIGVsIGRpc2XDsW8uCkVzdGUgY29tYW5kbyBub3MgZGV2dWVsdmUgbGFzIGZyZWN1ZW5jaWFzIGFic29sdXRhcyBwb25kZXJhZGFzLCBwb3IgbG8gcXVlIHNlIHB1ZWRlIGFuaWRhciBlbiBlbCBjb21hbmRvIGBwcm9wLnRhYmxlYCBwYXJhIGNhbGN1bGFyIGxvcyBwb3JjZW50YWplcyBkZXNkZSBsYXMgZnJlY3VlbmNpYXMgYWJzb2x1dGFzIHBvbmRlcmFkYXMgeSBkZW50cm8gZGVsIGNvbWFuZG8gYGNvdW50YCBwYXJhIHJlZG9uZGVhciBsb3MgcG9yY2VudGFqZXMsIHkgZGVudHJvIGRlbCBjb21hbmRvIGBhcy5kYXRhLnRhYmxlYCBwYXJhIGd1YXJkYXIgbGEgdGFibGEgZW4gdW4gb2JqZXRvICJ2b3RveHBhaXMiIGNvbW8gdW4gZGF0YWZyYW1lLCBxdWUgbm9zIHBlcm1pdGEgbGEgbWFuaXB1bGFjacOzbiBjb24gYGdncGxvdGAgbHVlZ28uCgpgYGB7ciB0YWJsYSBwb25kZXJhZGF9CnZvdG94cGFpcyA9IGFzLmRhdGEuZnJhbWUocm91bmQocHJvcC50YWJsZShzdnl0YWJsZSh+cGFpcytjb3VudGZhaXIxciwgZGVzaWduPWRpc2VubzIxKSwgMSkqMTAwLCAwKSkKdm90b3hwYWlzJHBhaXMgPSBwYWlzCnZvdG94cGFpcwpgYGAKCmBgYHtyIGdyYWZpY28gcG9uZGVyYWRvfQpnZ3Bsb3QoZGF0YT12b3RveHBhaXMsIGFlcyhmaWxsPWNvdW50ZmFpcjFyLCB4PUZyZXEsIHk9cGFpcykpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MC4zKSsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBhc3RlKEZyZXEsICIlIiwgc2VwPSIiKSksIGNvbG9yPSJ3aGl0ZSIsIAogICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLCBzaXplPTMpKwogIGxhYnMoeD0iUG9yY2VudGFqZSIsIHk9IlBhw61zIiwgZmlsbD0iTG9zIHZvdG9zIHNlIGN1ZW50YW4ganVzdGFtZW50ZSIsCiAgICAgICBjYXB0aW9uPSJCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgcG9yIExBUE9QLCAyMDIxIikKYGBgCgpFc3RlIGdyw6FmaWNvIHJlcHJvZHVjZSBleGFjdGFtZW50ZSBsb3MgcmVzdWx0YWRvcyBtb3N0cmFkb3MgZW4gZWwgR3LDoWZpY28gMi41IGRlbCByZXBvcnRlLCBhdW5xdWUgZW4gdW4gb3JkZW4gZGlmZXJlbnRlLgoKIyMgRWplbXBsbyBjb24gbG9zIGRhdG9zIGRlIGxhIHJvbmRhIDIwMTgvMTkKCkxhIHBlcXVlw7FhIGRpZmVyZW5jaWEgZW50cmUgbG9zIHBvcmNlbnRhamVzIHF1ZSBzZSBtdWVzdHJhbiBlbiBlbCBHcsOhZmljbyAzLjMgeSBsb3MgbW9zdHJhZG9zIGVuIGxhIHNlY2Npw7NuICJEZXNjcmliaXIgbGFzIHZhcmlhYmxlcyIgcHVlZGUgZGViZXJzZSBhIHF1ZSBlbiB0b2RvcyBsYXMgdGFibGFzIHkgZ3LDoWZpY29zIGFudGVyaW9yZXMgbm8gc2UgaW5jbHV5ZSBlbCBmYWN0b3IgZGUgZXhwYW5zacOzbi4KU2kgc2UgaW5jbHV5ZXJhLCB1c2FuZG8gbGEgdmFyaWFibGUgIndlaWdodDE1MDAiLCBzZSByZXBsaWNhcsOtYW4gbG9zIHBvcmNlbnRhamVzIG1vc3RyYWRvcyBlbiBlbCBpbmZvcm1lLgpQb3IgZWplbXBsbywgcGFyYSBlbCB1c28gZGUgV2hhdHNhcHAsIHNlIHB1ZWRlIHVzYXIgZWwgY29tYW5kbyBgZnJlcWAgZGUgbGEgbGlicmVyw61hIGBkZXNjcmAgcXVlIHBlcm1pdGUgaW5jbHVpciB1bmEgdmFyaWFibGUgZGUgcG9uZGVyYWNpw7NuLgoKRXN0YSB0YWJsYSBsdWVnbyBzZSBwdWVkZSBndWFyZGFyIGVuIHVuIGRhdGFmcmFtZSwgYWwgcXVlIHNlIGxlIHB1ZWRlbiBlbGltaW5hciBsYXMgZmlsYXMgeSBjb2x1bW5hcyBxdWUgbm8gc2UgcmVxdWllcmVuLCB5IHNlIGxlcyBwdWVkZSBjYW1iaWFyIGVsIG5vbWJyZSBhIGxhcyBjb2x1bW5hcy4KeSBhZ3JlZ2FyIGxhcyBldGlxdWV0YXMuCgpgYGB7ciB3YSBwb25kZXJhZG99CnRhYmxhMiA8LSBhcy5kYXRhLmZyYW1lKGRlc2NyOjpmcmVxKGxhcG9wMTgkc21lZGlhOHIsIGxhcG9wMTgkd2VpZ2h0MTUwMCwgcGxvdD1GKSkKdGFibGEyIDwtIHRhYmxhMlstYyg1LDYpLCAtMl0KY29sbmFtZXModGFibGEyKSA8LSBjKCJmcmVjIiwgInBlciIpCnRhYmxhMiRsYWIgPC0gcm93bmFtZXModGFibGEyKQp0YWJsYTIKYGBgCgpDb24gZXN0ZSBudWV2byBkYXRhZnJhbWUsIHNlIHB1ZWRlIHJlcGxpY2FyIGVsIGdyw6FmaWNvIGRlIFdoYXRzYXBwLCBjb24gbG9zIGRhdG9zIHBvbmRlcmFkb3MsIHVzYW5kbyBlbCBjw7NkaWdvIGRlIGBnZ3Bsb3RgLgoKYGBge3Igd2EgZ3JhZiBwb25kfQpnZ3Bsb3QoZGF0YT10YWJsYTIsIGFlcyh4PTIsIHk9cGVyLCBmaWxsPWxhYikpKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1wYXN0ZShyb3VuZChwZXIsIDEpLCAiJSIsIHNlcD0iIikpLCBjb2xvcj0id2hpdGUiLCAKICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSwgc2l6ZT0zKSsKICBjb29yZF9wb2xhcigieSIpKwogIHRoZW1lX3ZvaWQoKSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9IkZyZWN1ZW5jaWEgZGUgdXNvIGRlIEZhY2Vib29rIikrCiAgIGxhYnModGl0bGU9IkZyZWN1ZW5jaWEgY29uIGxhIHF1ZSB2ZSBjb250ZW5pZG8gZW4gRmFjZWJvb2siLCAKICAgICAgICBjYXB0aW9uPSJCYXLDs21ldHJvIGRlIGxhcyBBbcOpcmljYXMgcG9yIExBUE9QLCAyMDE4LzE5IikrCiAgeGxpbSgwLjUsIDIuNSkKYGBgCgpBZGVtw6FzIGRlbCBjb21hbmRvIGBmcmVxYCwgdGFtYmnDqW4gc2UgcHVlZGUgdXNhciBsYSBsaWJyZXLDrWEgYHN1cnZleWAgeSBlbCBjb21hbmRvIG5hdGl2byBgc3Z5dGFibGVgLgoKYGBge3Igc3VydmV5fQpsaWJyYXJ5KHN1cnZleSkKZGlzZW5vMTg8LXN2eWRlc2lnbihpZHMgPSB+dXBtLCBzdHJhdGEgPSB+ZXN0cmF0b3ByaSwgd2VpZ2h0cyA9IH53ZWlnaHQxNTAwLCBuZXN0PVRSVUUsIGRhdGE9bGFwb3AxOCkKYGBgCgpMb3MgcmVzdWx0YWRvcyBxdWUgc2Ugb2J0aWVuZW4gc29uIGlndWFsZXMgcXVlIGNvbiBlbCBtw6l0b2RvIGFudGVyaW9yIHkgYSBsb3MgcHJlc2VudGFkb3MgZW4gZWwgcmVwb3J0ZS4KRXN0b3MgcmVzdWx0YWRvcyB0YW1iacOpbiBzZSBwdWVkZW4gZ3VhcmRhciBlbiB1biAiZGF0YWZyYW1lIiBwYXJhIGhhY2VyIGVsIGdyw6FmaWNvLgoKYGBge3Igc3Z5dGFibGV9CnByb3AudGFibGUoc3Z5dGFibGUofnNtZWRpYThyLCBkZXNpZ249ZGlzZW5vMTgpKSoxMDAKYGBgCgpMYSBzZWNjacOzbiAiQ3J1Y2UgY29uIHZhcmlhYmxlcyIgcHJlc2VudGEgbG9zIGRhdG9zIGRlIHVzdWFyaW9zIGRlIHJlZGVzIHNvY2lhbGVzIHBvciBwYcOtcy4KUGFyYSBjb25zdHJ1aXIgbGEgdGFibGEgY29uc2lkZXJhbmRvIGVsIGVmZWN0byBkZSBkaXNlw7FvLCB0YW1iacOpbiBzZSBwdWVkZSB1c2FyIGVsIGNvbWFuZG8gbmF0aXZvIGBzdnl0YWJsZWAgcXVlIHBlcm1pdGUgY2FsY3VsYXIgdW5hIHRhYmxhIGJpdmFyaWFkYS4KRGUgbGEgbWlzbWEgbWFuZXJhIHF1ZSBlbiBjYXNvIG5vIHBvbmRlcmFkbywgbGFzIHRhYmxhcyBwYXJjaWFsZXMgZGUgY2FkYSByZWQgc29jaWFsIHNlIGd1YXJkYW4gZW4gdW5vcyBvYmpldG9zIGRlIHRpcG8gbGlzdGEsIGxvcyBxdWUgc2UganVudGFuIGNvbW8gdW4gImRhdGFmcmFtZSIgeSBzZSBlZGl0YSBwYXJhIHByZXNlbnRhciBzb2xvIGxvcyBkYXRvcyBkZSBsb3MgdXN1YXJpb3MgZGUgY2FkYSByZWQgc29jaWFsIHBvciBwYcOtcy4KCmBgYHtyIHN2eXRhYmxlIGJpdmFyaWFkYX0KZmJwYWlzXzIgPC0gcm91bmQocHJvcC50YWJsZShzdnl0YWJsZSh+cGFpcytmYl91c2VyLCBkZXNpZ249ZGlzZW5vMTgpLCAxKSwgMykqMTAwCnR3cGFpc18yIDwtIHJvdW5kKHByb3AudGFibGUoc3Z5dGFibGUofnBhaXMrdHdfdXNlciwgZGVzaWduPWRpc2VubzE4KSwgMSksIDMpKjEwMAp3YXBhaXNfMiA8LSByb3VuZChwcm9wLnRhYmxlKHN2eXRhYmxlKH5wYWlzK3dhX3VzZXIsIGRlc2lnbj1kaXNlbm8xOCksIDEpLCAzKSoxMDAKdGFibGFwYWlzXzIgPC0gYXMuZGF0YS5mcmFtZShjYmluZChmYnBhaXNfMiwgdHdwYWlzXzIsIHdhcGFpc18yKSkKdGFibGFwYWlzXzIgPC0gdGFibGFwYWlzXzJbLCBjKC0xLC0zLC01KV0KdmFybmFtZXMgPC0gYygiVXNhIEZhY2Vib29rIiwgIlVzYSBUd2l0dGVyIiwgIlVzYSBXaGF0c2FwcCIpCmNvbG5hbWVzKHRhYmxhcGFpc18yKSA8LSB2YXJuYW1lcwp0YWJsYXBhaXNfMgpgYGAKClBvciDDumx0aW1vLCBsYSBzZWNjacOzbiAiQ3J1Y2UgY29uIHZhcmlhYmxlcyBzb2Npb2RlbW9ncsOhZmljYXMiIHJlcHJvZHVjZSBsb3MgcmVzdWx0YWRvcyBkZSBsYSBUYWJsYSAzLjIgZGVsIHJlcG9ydGUuCkRlIGxhIG1pc21hIG1hbmVyYSBxdWUgZW4gZWwgY2FzbyBhbnRlcmlvciwgc2UgcHVlZGUgdXNhciBlbCBjb21hbmRvIG5hdGl2byBgc3Z5dGFibGVgIHBhcmEgcmVhbGl6YXIgZWwgY3J1Y2UgZW50cmUgbGFzIHZhcmlhYmxlcyBkZSB1c28gZGUgcmVkZXMgc29jaWFsZXMgeSBsYSB2YXJpYWJsZSB1cmJhbm8uCkxvcyByZXN1bHRhZG9zIGRlIGxhIGZpbGEgVXJiYW5vIGVuIGNhZGEgcmVkIHNvY2lhbCBjb3JyZXNwb25kZXLDrWFuIGEgbGEgcHJpbWVyYSBmaWxhIGRlIHJlc3VsdGFkb3MgZGUgbGEgVGFibGEgMy4yLgoKYGBge3J9CnJvdW5kKHByb3AudGFibGUoc3Z5dGFibGUofnVyYmFuK3dhX3VzZXIsIGRlc2lnbj1kaXNlbm8xOCksIDIpLCAzKSoxMDAKcm91bmQocHJvcC50YWJsZShzdnl0YWJsZSh+dXJiYW4rZmJfdXNlciwgZGVzaWduPWRpc2VubzE4KSwgMiksIDMpKjEwMApyb3VuZChwcm9wLnRhYmxlKHN2eXRhYmxlKH51cmJhbit0d191c2VyLCBkZXNpZ249ZGlzZW5vMTgpLCAyKSwgMykqMTAwCmBgYAoKRGUgZXN0YSBtYW5lcmEgc2UgcHVlZGVuIGNhbGN1bGFyIGxhcyB0YWJsYXMgZGUgZGlzdHJpYnVjacOzbiBkZSBmcmVjdWVuY2lhcyB5IGxhcyB0YWJsYXMgYml2YXJpYWRhcyAobyBkZSBjb250aW5nZW5jaWEpIGluY2x1eWVuZG8gZWwgZWZlY3RvIGRlIGRpc2XDsW8gbyBlbCBmYWN0b3IgZGUgZXhwYW5zacOzbi4K