Presentación
El Análisis de Correspondencias Múltiple (o
Multiple Correspondence Analysis [MCA]) es una
extensión del análisis simple de correspondencias, y permite reducir y
visualizar una tabla de contingencia que contenga más de dos variables
categóricas. Esta técnica también puede ser vista como una
generalización del Análisis de Componentes Principales, sin
embargo aquí se caracteriza porque las variables a analizar son
categóricas, en lugar de cuantitativas.
El MCA generalmente se usa para analizar a un
conjunto de datos provenientes de encuestas, y la meta de su uso es:
- Identificar a grupos de individuos con perfiles similares en sus
respuestas en las categorías de variables medidas.
- Evaluar las asociaciones existentes entre las categorías (o
atributos) de las variables categóricas.
Esta técnica se apoya, en gran medida, en métodos visuales para el
análisis de los resultados.
En esta presentación se realiza una introducción a la inplementación
de la técnica MCA para calcular y visualizar sus
resultados en R, para ello se utilizará la librería
FactoMineR() al momento de analizar los datos y, además, la
librería factoextra() para la visualización de los
resultados.
Además se busca presentar una manera para identificar a las variables
más relevantes en el conjunto de datos, y que tienen mayor contribución
en la explicación de las variaciones dentro de los datos. Y se muestra
la manera para predecir los resultados para individuos y variables
suplementarias. También se presenta la manera para filtrar los
resultados del análisis MCA con el fin de mantener solo
a las variables con mayor contribución.
Preparación del
ambiente.
Antes de comenzar, es recomendable ajustar la configuración de
R al ambiente de trabajo.
Idioma.
En un primer momento se recomienda cambiar el idioma en que
R lee la información, esto con el fin de ajustarla al
idioma español. De esta manera se podrán detectar los caracteres del
idioma, como los acentos o tíldes. Para hacerlo, se usa el comando
Sys.setlocale().
Sys.setlocale("LC_ALL", "en_US.UTF-8")
## [1] "en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8"
Librerías.
Otro elemento que se recomienda ajustar en un inicio consiste en la
instalación y carga de las librerías. Para el análisis de
MCA se utilizarán dos paqueterías especiales, una es
FactoMineR()y la otra es factoextra(), y esta
última se apoya en la librería ggplot(). En caso de no
haberlas instalado previamente, esto se puede hacer con el siguiente
comando.
install.packages(c("FactoMineR", "factoextra", "tidyverse", "naniar", "corrplot"))
Y una vez que han sido instaladas, se deben activar con el comando
library().
library(easypackages)
paquetes <- c("FactoMineR", "tidyverse", "factoextra", "haven", "naniar", "corrplot")
libraries(paquetes)
## Loading required package: FactoMineR
## Loading required package: tidyverse
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✓ ggplot2 3.3.5 ✓ purrr 0.3.4
## ✓ tibble 3.1.6 ✓ dplyr 1.0.8
## ✓ tidyr 1.2.0 ✓ stringr 1.4.0
## ✓ readr 2.1.2 ✓ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
## Loading required package: factoextra
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
## Loading required package: haven
## Loading required package: naniar
## Loading required package: corrplot
## corrplot 0.92 loaded
## All packages loaded successfully
Carga de los
datos
A continuación es recomendable cargar los datos en
R, para lo que se utiliza el data.frame de
la ola 2020 de la encuesta de Latinobarómetro. En la página de
dicha organización se encuentran disponibles las bases de datos, y
también es importante revisar el libro de
códigos, que permite identificar las codificaciones de los ítems y
los valores de respuesta posibles o atributos.
load("~/Dropbox/R/Latinobarometro_2020_Esp_Rdata_v1_0.rdata")
datos_lb <- Latinobarometro_2020_Esp
Preparación de los
datos y su descripción
En un primer momento es importante crear una sub sección de la
muestra, en la que se encuentren solo las variables de interés. A
partir de la encuesta de Latinobarómetro para la ola 2020 se
seleccionaron 10 variables, y donde “(\(k
=\))” se refiere a la cantidad de opciones de respuesta,
atributos o categorías posibles. Aquí se puede ver que todas estas
variables son de corte categórico.
- p1st - Satisfacción con la vida (k = 4).
- p4stgbs - Situación económica actual (k = 4).
- p10stgbs - Apoyo a la democracia (k = 3).
- P11STGBS_A - Satisfacción con la vida (k = 4).
- p13st_e - Confianza en el gobierno (k = 4).
- p17stgbs - Aprobación de la gestión del gobierno del presidente (k =
2).
- p18st - Escala Izquierda - Derecha (0, 10).
- p30st_a - Opinión sobre Estado Unidos de América (k = 4).
- p46stgbs - Interés en la política (k = 4).
- P51STGBS_B - Votó al partido del gobierno o de la oposición (k =
2).
Aquí se realizó la selección de las columnas o variables de interés
y, además, se cambió el nombre de dichas columnas. Se alcanza a observar
que existen valores negativos, mientras que existen otros valores muy
grandes (por ejemplo el valor “97” en la variable de auto ubicación
ideológica), que se pueden tratar como valores perdidos. Por ello se le
debe señalar como tal al conjunto de datos, para lo que se usa la
librería naniar().
na_strings <- c(0, 8, 9, -1, -2, -3, -4, -5, 97, 98, 99)
sub_datos <- datos_lb %>%
select(p1st, p4stgbs, p10stgbs, P11STGBS.A, p13st.e, p17stgbs, p18st, p30st.a, p46stgbs, P51STGBS.B) %>%
rename(satisf_vida = p1st,
sit_ec = p4stgbs,
apoyo_dem = p10stgbs,
satisf_dem = P11STGBS.A,
conf_gob = p13st.e,
aprob_gob = p17stgbs,
ubic_ideol = p18st,
op_eua = p30st.a,
int_pol = p46stgbs,
voto_gob = P51STGBS.B) %>%
naniar::replace_with_na_all(condition = ~.x %in% na_strings)
Ahora se solicita una revisión a la estructura de las variables de
interés, para ello se usa el comando str().
str(sub_datos)
## tibble [20,204 × 10] (S3: tbl_df/tbl/data.frame)
## $ satisf_vida: int [1:20204] 1 4 1 1 2 2 3 4 1 1 ...
## $ sit_ec : int [1:20204] 5 5 5 5 4 3 5 4 5 5 ...
## $ apoyo_dem : int [1:20204] 3 1 2 2 1 1 1 2 2 2 ...
## $ satisf_dem : int [1:20204] 4 4 4 4 3 2 3 3 3 4 ...
## $ conf_gob : int [1:20204] 4 4 1 4 2 3 4 3 4 4 ...
## $ aprob_gob : int [1:20204] 2 2 1 2 NA 1 2 2 2 2 ...
## $ ubic_ideol : int [1:20204] 5 5 5 10 NA NA NA 5 5 7 ...
## $ op_eua : int [1:20204] 2 1 2 1 2 2 2 3 4 1 ...
## $ int_pol : int [1:20204] 4 1 2 4 2 4 3 3 1 2 ...
## $ voto_gob : int [1:20204] NA 1 NA 2 2 NA NA NA NA 1 ...
Dicho resumen permite identificar que las variables fueron detectadas
por R del tipo integer (enteros), pero es
necesario transformarlas a otro formato tipo factor para
incluirlas en el análisis MCA. Para ello se utiliza el
comando factor().
sub_datos $ satisf_vida <- factor(sub_datos $ satisf_vida)
sub_datos $ sit_ec <- factor(sub_datos $ sit_ec)
sub_datos $ apoyo_dem <- factor(sub_datos $ apoyo_dem)
sub_datos $ satisf_dem <- factor(sub_datos $ satisf_dem)
sub_datos $ conf_gob <- factor(sub_datos $ conf_gob)
sub_datos $ aprob_gob <- factor(sub_datos $ aprob_gob)
sub_datos $ ubic_ideol <- factor(sub_datos $ ubic_ideol)
sub_datos $ op_eua <- factor(sub_datos $ op_eua)
sub_datos $ int_pol <- factor(sub_datos $ int_pol)
sub_datos $ voto_gob <- factor(sub_datos $ voto_gob)
Ahora se puede solicitar una revisión gráfica de la distribución de
las variables de interés, para ello se se utilizará el comando
for(), que permite repetir un mismo comando en varias
situaciones.
sub_datos <- na.omit(sub_datos)
for (i in 1:10){
plot(sub_datos[,i], main = colnames(sub_datos)[i],
ylab = "Cantidad", col ="steelblue", las = 2)
}










A partir de estas gráficas se debe identificar cuáles son las
opciones de respuesta o atributos que registraron una frecuencia muy
baja pues pueden distorsionar el análisis posterior y, por tanto, deben
ser removidas. En este ejercicio se decidió mantener todas las variables
y sus categorías.
Análisis inicial de
MCA
A continuación se inicia el análisis de MCA en
R, para lo que se usará inicialmente el comando
MCA(), que es parte de la librería
FactoMiner().
Su estructura es:
MCA(X, ncp = , graph = TRUE)
Los argumentos consisten en:
- X: un data frame con n filas (individuos) y p
columnas (variables categóricas).
- ncp: número de dimensiones a guardar en los resultados finales.
- graph: a partir de un valor lógico (
TRUE,
FALSE) se indica si se desea generar la gráfica
correspondiente.
En el código que está debajo, el análisis MCA se
realizará solo sobre los individuos y variables activas o de interés,
ubicadas en el data frame sub_datos.
mca_lb <- MCA(sub_datos, graph = FALSE)
El resultado generado se ha guardado en un objeto denominado
mca_lb, y que consiste en una lista que contiene
información diversa, correspondiente tanto a listas y matrices. Y para
darle un vistazo a su contenido se usa el comando
print().
print(mca_lb)
## **Results of the Multiple Correspondence Analysis (MCA)**
## The analysis was performed on 4569 individuals, described by 10 variables
## *The results are available in the following objects:
##
## name description
## 1 "$eig" "eigenvalues"
## 2 "$var" "results for the variables"
## 3 "$var$coord" "coord. of the categories"
## 4 "$var$cos2" "cos2 for the categories"
## 5 "$var$contrib" "contributions of the categories"
## 6 "$var$v.test" "v-test for the categories"
## 7 "$ind" "results for the individuals"
## 8 "$ind$coord" "coord. for the individuals"
## 9 "$ind$cos2" "cos2 for the individuals"
## 10 "$ind$contrib" "contributions of the individuals"
## 11 "$call" "intermediate results"
## 12 "$call$marge.col" "weights of columns"
## 13 "$call$marge.li" "weights of rows"
Visualización e
interpretación inicial del análisis MCA
Una de las características centrales de la técnica
MCA consiste en el apoyo de métodos visuales para la
interpretación de los resultados de los análisis. A continuación se usa
la librería factoextra(), que a su vez se apoya el la
librería ggplot2(), para generar las gráficas iniciales y,
así, avanzar en su interpretación.
Dicha librería contiene diversas funciones que trabajan sobre el
objeto resultante del análisis inicial de MCA, que se
irán revisando a continuación y que son:
get_eigenvalue(): extrae los eigenvalores o varianzas
retenidas por cada dimension o eje.
fviz_eig(): permite visualizar a los eigenvalores o
varianzas.
get_mca_ind(), get_mca_var(): extrae los
resultados tanto para individuos como para variables,
respectivamente.
fviz_mca_ind(), fviz_mca_var(): Permite
visualizar los resultados tanto para individuos o para variables,
respectivamente.
fviz_mca_biplot(): permite generar un biplot
combinando filas y columnas.
Eigenvalores /
varianzas
Siguiendo la lógica del análisis que existe en el Análisis de
Componentes Principales, que permite “reducir” las dimensiones
de un data frame a partir de generar nuevos ejes o componentes que
sirven a manera de “resumen” de las variables cuantitativas originales,
en el análisis MCA también es posible construir dichos
componentes o ejes a partir de variables categóricas.
Una vez que se generan los nuevos componentes, es importante
identificar la capacidad explicativa del total de los casos que cada una
proporciona. Para ello es importante revisar la proporción de varianzas
que “retiene” cada una de estas dimensiones o ejes. Y puede ser extraído
a partir de la función get_eigenvalue() de la siguiente
manera:
eig_val <- factoextra::get_eigenvalue(mca_lb)
head(eig_val)
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 0.2604405 8.681350 8.68135
## Dim.2 0.1719728 5.732428 14.41378
## Dim.3 0.1345808 4.486025 18.89980
## Dim.4 0.1240564 4.135215 23.03502
## Dim.5 0.1120294 3.734312 26.76933
## Dim.6 0.1106592 3.688641 30.45797
En la tabla anterior se muestran del lado de las columnas los
componentes o ejes nuevos, resultados del análisis MCA,
mientras que en la primer columna se muestran los eigenvalores o el
tamaño de las varianzas que explica cada uno, mientras que en la segunda
columna se muestra el porcentaje de la varianza total que es explicado
por cada eje o dimensión. En la tercer columna se muestra el porcentaje
de varianza acumulado.
También es posible visualizar los porcentajes de inercia explicados
por cada dimensión MCA, a partir de usar el comando
fviz_screeplot(), con el que se puede crear un “scree
plot.”
fviz_screeplot(mca_lb, addlabels = TRUE)
Una de las características propias del MCA radica en
que los componentes, dimensiones o factores creados no necesariamente
suelen explicar porcentajes amplios de varianzas totales. (Díaz Monroy & Morales Rivera, 2009)
Biplot o gráfica de
individuos y variables
Uno de los resultados más importantes del análisis
MCA consiste en la creación de un “biplot”,
mediante el que se puede graficar una nube de puntos fila (\(n\) puntos) y una nube de puntos columna
(\(p\) puntos), donde la primera se
corresponde a los individuos o casos, mientras que la segunda se refiere
a las variables contenidas en la matriz de datos.
A partir de esta graficación, el MCA “pone en evidencia
a los individuos con perfiles semejantes respecto a los atributos
seleccionados para su descripción.” (Díaz Monroy
& Morales Rivera, 2009, p. 123)
Para crear dicho “biplot” se utiliza el comando
fviz_mca_biplot(), que es parte de la paquetería
factoextra, y que se apoya en la paquetería
ggplot2, de la siguiente manera:
fviz_mca_biplot(mca_lb, # resultados del análisis MCA
repel = TRUE, # evitar la superposición de etiquetas en la gráfica
alpha.ind = 0.1, # nivel de transparencia de los puntos filas o casos
alpha.var = 1, # nivel de transparencia de los puntos columa o variables
max.overlaps = "ggrepel.max.overlaps",
ggtheme = theme_minimal()) # plantilla de estilo para la gráfica
## Warning: ggrepel: 4543 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
## Warning: ggrepel: 9 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
La gráfica muestra el patrón global de distribución de las
proyecciones tanto de los casos o individuos, así como de las variables
sobre cada uno de los ejes o dimensiones creadas. Los casos se
representan a partir de los puntos azules mientras que las variables lo
hacen a partir de los triángulos en color rojo.
A partir de esta representación gráfica se muestra la asociación
entre variables categóricas, tanto entre sí como con respecto a los
individuos.
La distancia entre cada punto correspondiente tanto a los individuos
como entre las columnas ofrece una forma de medición de su similaridad,
puesto que “la cercanía entre individuos en términos de semejanzas; es
decir, dos individuos son semejantes si han seleccionado globalmente las
mismas modalidades. La proximidad entre modalidades de variables
diferentes en términos de asociación, (…) y son próximas porque están
ligadas a los mismos individuos o individuos parecidos.” (Díaz Monroy & Morales Rivera, 2009, p.
123)
Descripción de las
dimensiones
Finalmente, en este análisis general de las correspondencias entre
individuos y categorías de variables en la construcción de las
dimensiones o ejes de resúmenes, también es posible identificar los
niveles de correlación de las variables y sus categorías con cada una de
las dimensiones. Esto ofrece información para identificar cuáles son las
columnas que ejercen mayor influencia sobre cada dimensión.
Para realizar este análisis de correlaciones se utiliza el comando
dimdes(), que es parte de la librería
FactoMineR.
res.desc <- dimdesc(mca_lb, #objeto tipo lista que contiene los resultados mca
axes = c(1,2) #definición de los ejes o dimensiones a describir
)
Con esto se crea un objeto tipo “lista” que contiene los valores de
correlación de las variables con las dimensiones solicitadas.
Posteriormente se deben extraer los valores de correlación, que serán
presentados en dos tablas para cada dimensión: una sobre la cualidad de
cada variable medida con el coeficiente de determinación (\(R^2\)) y su p-value asociado, y
otra que contiene a los valores estimados (correlación) para cada
categoría de las variables y el p-value para cada una de
ellas.
En el caso de la dimensión 1, se manda a llamar:
res.desc[[1]]
## $quali
## R2 p.value
## sit_ec 0.38118727 0.000000e+00
## satisf_dem 0.46849238 0.000000e+00
## conf_gob 0.65039668 0.000000e+00
## aprob_gob 0.54081986 0.000000e+00
## voto_gob 0.28808048 0.000000e+00
## satisf_vida 0.10826011 4.660485e-113
## ubic_ideol 0.06887687 1.980071e-66
## int_pol 0.05363284 2.846381e-54
## apoyo_dem 0.02393120 9.634473e-25
## op_eua 0.02072738 1.354963e-20
##
## $category
## Estimate p.value
## voto_gob=voto_gob_1 0.27434643 0.000000e+00
## aprob_gob=aprob_gob_1 0.37555269 0.000000e+00
## conf_gob=conf_gob_1 0.57259837 0.000000e+00
## satisf_dem=satisf_dem_1 0.48698454 2.761658e-235
## sit_ec=sit_ec_2 0.36623410 1.890249e-130
## satisf_dem=satisf_dem_2 0.22843939 5.317884e-107
## conf_gob=conf_gob_2 0.18932148 7.630936e-90
## sit_ec=sit_ec_3 0.02205284 7.077740e-77
## ubic_ideol=ubic_ideol_10 0.25773310 7.839772e-57
## satisf_vida=satisf_vida_1 0.29801304 2.280847e-56
## sit_ec=sit_ec_1 0.60520781 9.148929e-33
## int_pol=int_pol_1 0.17344150 6.331255e-30
## op_eua=op_eua_1 0.13552945 2.391722e-21
## apoyo_dem=apoyo_dem_1 0.08751211 1.532464e-20
## int_pol=int_pol_2 0.05496477 1.660624e-08
## ubic_ideol=ubic_ideol_7 0.08149846 3.544679e-03
## ubic_ideol=ubic_ideol_6 0.05928721 4.782715e-02
## op_eua=op_eua_4 -0.05170498 6.392488e-03
## op_eua=op_eua_2 -0.01883665 3.441081e-03
## int_pol=int_pol_3 -0.05437042 3.315859e-04
## ubic_ideol=ubic_ideol_2 -0.09358216 2.296164e-04
## op_eua=op_eua_3 -0.06498781 2.171486e-05
## ubic_ideol=ubic_ideol_4 -0.11830899 1.054518e-08
## ubic_ideol=ubic_ideol_3 -0.12939886 3.017020e-09
## ubic_ideol=ubic_ideol_5 -0.06135462 2.994714e-11
## conf_gob=conf_gob_3 -0.18171147 4.179583e-13
## apoyo_dem=apoyo_dem_3 -0.10427555 1.914078e-23
## satisf_dem=satisf_dem_3 -0.17367458 4.415512e-24
## int_pol=int_pol_4 -0.17403585 4.120979e-33
## satisf_vida=satisf_vida_3 -0.06634578 1.277449e-42
## satisf_vida=satisf_vida_4 -0.38778239 8.294719e-47
## sit_ec=sit_ec_4 -0.35009380 8.780552e-71
## sit_ec=sit_ec_5 -0.64340095 5.595353e-202
## satisf_dem=satisf_dem_4 -0.54174935 3.140675e-301
## voto_gob=voto_gob_2 -0.27434643 0.000000e+00
## aprob_gob=aprob_gob_2 -0.37555269 0.000000e+00
## conf_gob=conf_gob_4 -0.58020838 0.000000e+00
##
## attr(,"class")
## [1] "condes" "list"
En el caso de la dimensión 2, se manda a llamar:
res.desc[[2]]
## $quali
## R2 p.value
## satisf_dem 0.357510887 0.000000e+00
## conf_gob 0.384634097 0.000000e+00
## sit_ec 0.267607312 1.356225e-306
## ubic_ideol 0.210169198 3.228358e-228
## op_eua 0.182343956 6.384333e-199
## int_pol 0.164729569 8.146514e-178
## satisf_vida 0.147234995 2.718464e-157
## apoyo_dem 0.003824751 1.586756e-04
## aprob_gob 0.001212510 1.858353e-02
##
## $category
## Estimate p.value
## ubic_ideol=ubic_ideol_10 0.39020193 3.503201e-207
## satisf_dem=satisf_dem_4 0.23723223 7.082440e-188
## sit_ec=sit_ec_5 0.17527232 6.722647e-183
## op_eua=op_eua_1 0.26204657 4.981141e-164
## conf_gob=conf_gob_4 0.20858526 2.406257e-147
## conf_gob=conf_gob_1 0.30842301 2.040961e-138
## int_pol=int_pol_1 0.27275791 1.566249e-123
## satisf_vida=satisf_vida_4 0.52761756 7.853448e-110
## satisf_dem=satisf_dem_1 0.24715324 3.059079e-103
## sit_ec=sit_ec_1 0.63461294 1.084927e-67
## int_pol=int_pol_4 0.05435147 2.320050e-17
## op_eua=op_eua_4 0.07123437 2.501772e-10
## ubic_ideol=ubic_ideol_1 0.12778480 1.315656e-05
## apoyo_dem=apoyo_dem_1 0.03534108 2.927877e-05
## aprob_gob=aprob_gob_2 0.01444984 1.858353e-02
## aprob_gob=aprob_gob_1 -0.01444984 1.858353e-02
## apoyo_dem=apoyo_dem_2 -0.01955743 1.611219e-02
## apoyo_dem=apoyo_dem_3 -0.01578365 5.790567e-03
## ubic_ideol=ubic_ideol_2 -0.06555783 3.700282e-04
## ubic_ideol=ubic_ideol_3 -0.05354732 2.726278e-04
## sit_ec=sit_ec_2 -0.15468780 3.066286e-05
## sit_ec=sit_ec_4 -0.28735903 2.392387e-09
## satisf_vida=satisf_vida_3 -0.23935581 1.418354e-15
## ubic_ideol=ubic_ideol_6 -0.14665678 1.662106e-16
## satisf_dem=satisf_dem_2 -0.18264629 2.163448e-23
## ubic_ideol=ubic_ideol_5 -0.07206835 8.521778e-24
## ubic_ideol=ubic_ideol_4 -0.17168749 7.344219e-25
## int_pol=int_pol_2 -0.14140751 2.153093e-25
## satisf_vida=satisf_vida_1 -0.05396750 9.753558e-27
## op_eua=op_eua_3 -0.18825617 1.263517e-31
## satisf_vida=satisf_vida_2 -0.23429425 4.033288e-38
## int_pol=int_pol_3 -0.18570187 3.148398e-62
## op_eua=op_eua_2 -0.14502476 6.668086e-69
## conf_gob=conf_gob_2 -0.22701914 5.459266e-71
## sit_ec=sit_ec_3 -0.36783844 1.102299e-106
## conf_gob=conf_gob_3 -0.28998914 4.305739e-211
## satisf_dem=satisf_dem_3 -0.30173919 3.285517e-240
##
## attr(,"class")
## [1] "condes" "list"
Análisis sobre las
variables (columnas)
Al avanzar en el análisis de los resultados del MCA,
también es posible realizar la revisión de los resultados de manera
separada, ya sea que se revise, por un lado, el comportamiento de las
variables y, por el otro, de los casos o individuos.
A continuación se realiza el análisis por la revisión del
comportamiento de las variables o columnas del
data.frame(). En un primer momento se utiliza el comando
get_mca_var(), que permite extraer los resultados para las
categorías de las variables activas.
Esta función arroja una lista que contiene a las coordinadas de las
categorías de las variables para cada uno de los factores o dimensiones,
así como los valores de los cosenos elevados al cuadrado y la
contribución de las categorías sobre los factores o dimensiones.
variables <- get_mca_var(mca_lb)
variables
## Multiple Correspondence Analysis Results for variables
## ===================================================
## Name Description
## 1 "$coord" "Coordinates for categories"
## 2 "$cos2" "Cos2 for categories"
## 3 "$contrib" "contributions of categories"
Y también se puede acceder a los valores para cada uno de los
elementos de dicha lista, para lo que se muestra un vistazo a
continuación:
# Coordenadas
head(variables $ coord)
## Dim 1 Dim 2 Dim 3 Dim 4 Dim 5
## satisf_vida_1 0.29350235 0.2000625 -0.2755095 0.04215260 -0.46352340
## satisf_vida_2 0.01545312 -0.2347782 0.3099832 -0.30933013 0.20854056
## satisf_vida_3 -0.42045952 -0.2469837 -0.1282730 0.58143976 0.25693976
## satisf_vida_4 -1.05031523 1.6024993 0.1810480 -0.04968407 1.23313254
## sit_ec_1 1.43493665 2.0743641 -0.9203537 0.62333963 -2.29248464
## sit_ec_2 0.96666716 0.1710408 0.4497631 -0.40042970 0.01515545
# cosenos cuadrados: calidad en el mapa de factores
head(variables $ cos2)
## Dim 1 Dim 2 Dim 3 Dim 4 Dim 5
## satisf_vida_1 0.0533284632 0.024778059 0.046990403 1.099980e-03 0.1330084471
## satisf_vida_2 0.0001552323 0.035831523 0.062463421 6.220052e-02 0.0282703141
## satisf_vida_3 0.0401722082 0.013861619 0.003738936 7.682221e-02 0.0150016824
## satisf_vida_4 0.0441967965 0.102883842 0.001313224 9.889763e-05 0.0609215547
## sit_ec_1 0.0306432459 0.064038227 0.012606044 5.782542e-03 0.0782135826
## sit_ec_2 0.1213115322 0.003797933 0.026261276 2.081616e-02 0.0000298185
# Contribución en los factores o dimensiones
head(variables $ contrib)
## Dim 1 Dim 2 Dim 3 Dim 4 Dim 5
## satisf_vida_1 1.26469671 0.8899042 2.15656242 0.054764752 7.33302638
## satisf_vida_2 0.00361223 1.2627204 2.81283703 3.038620390 1.52932787
## satisf_vida_3 1.25686621 0.6567892 0.22637939 5.045907848 1.09113885
## satisf_vida_4 1.63163234 5.7521123 0.09382011 0.007664901 5.22852509
## sit_ec_1 1.15933933 3.6691357 0.92295423 0.459286604 6.87914850
## sit_ec_2 4.12271720 0.1954688 1.72712125 1.485153535 0.00235583
Correlaciones entre
variables y los factores creados
A partir de los resultados del análisis MCA se puede
evaluar gráficamente la asociación existente entre cada una de las
variables con respecto a las dimensiones o factores. Para ello se
utiliza fviz_mca_var(), dentro del que se utiliza el
argumento choice = "mca.cor", de la siguiente manera:
fviz_mca_var(mca_lb, # objeto lista de resultados mca
choice = "mca.cor", # tipo de análisis solicitado: correlaciones
repel = TRUE, # evitar la superposición de etiquetas
ggtheme = theme_minimal()
)
La gráfica permite identificar las variables que está más
correlacionadas con cada una de las dimensiones o factores creados. Las
coordenadas o distancias calculadas corresponden al valor de las
correlaciones cuadráticas entre las variables y las dimensiones.
En la gráfica se puede observar que las variables
voto_gob y aprob_gob son las más
correlacionadas con la dimensión 1, mientras que op_eua y
ubic_ideol están más asociadas con la dimensión 2.
Coordenadas para las
categorías de las variables activas
Si bien la gráfica anterior muestra la correlación de cada una de las
variables con respecto a las dimensiones, allí no se puede distinguir la
presencia de las categorías de respuestas en el mismo plano
cartesiano.
Para ello, es importante trabajar con el valor de las coordenadas de
cada categoría, que se calculó anteriormente, y que se puede revisar con
el comando (variable $ coord). A partir del comando
fviz_mca_var() se puede realizar dicha revisión gráfica
para evaluar visualmente la asociación entre cada categoría y las
dimensiones o factores creados.
fviz_mca_var(mca_lb, #objeto lista con resultados mca
repel = TRUE, # evitar el traslape de etiquetas
ggtheme = theme_minimal(),
max.overlaps = "ggrepel.max.overlaps"
)
## Warning: ggrepel: 6 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
Al gráfico anterior se le pueden realizar algunas modificaciones,
como cambiarle el color y las formas para representar a las categorías,
para ello se usan los argumentos col.var= y
shape.var= dentro del comando
fviz_mca_var().
fviz_mca_var(mca_lb, #objeto lista con resultados mca
repel = TRUE, # evitar el traslape de etiquetas
ggtheme = theme_minimal(),
max.overlaps = "ggrepel.max.overlaps", #ampliar el solapamiento donde ocurra
col.var="black", # cambiar el color a las variables
shape.var = 15 # cambiar la forma de representación de variables
)
## Warning: ggrepel: 6 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
La gráfica muestra las relaciones entre categorías de las variables,
con ajustes en las formas y color de representación de las
variables.
Dicha gráfica se puede interpretar de la siguiente manera:
- Las categorías con perfiles semejantes muestran agrupadas o cercanas
entre sí.
- Las variables que estén correlacionadas de manera negativa entre sí
estarán posicionadas en polos opuestos respecto al origen de la gráfica
(cuadrantes opuestos).
- La distancia que exista entre cada punto correspondiente a una
categoría y el origen, define la cualidad de la categoría en el mapa
Biplot. Los puntos de categorías que se encuentren alejados del
punto de origen tienden a estar mejor representadas en la gráfica.
Calidad de la
representación de las categorías
En la gráfica biplot creada a partir de los dos primeros
factores o dimensiones, se identificó que el primero explica 8.1% de la
varianza, mientras que el segundo explica 5.3%. Entre ambos abarcan solo
el 13.4% del comportamiento de los datos activos incluidos en el
análisis.
Debido a que los factores o dimensiones creadas tienden a representar
bajos niveles de varianza de la matriz de datos, puede ocurrir que no
todos los puntos estén igualmente proyectados en la gráfica
biplot
Ante esta situación, es importante revisar la calidad de la
representación de los puntos en la gráfica, para lo que es útil la
medida de los cosenos cuadráticos (cos^2), la que mide el grado de
asociación entre las categorías de cada variable y un eje o dimensión en
particular.
El coseno cuadrático (cos2) de cada categoría se puede extraer de la
siguiente manera:
head(round(variables $ cos2, 3), 5)
## Dim 1 Dim 2 Dim 3 Dim 4 Dim 5
## satisf_vida_1 0.053 0.025 0.047 0.001 0.133
## satisf_vida_2 0.000 0.036 0.062 0.062 0.028
## satisf_vida_3 0.040 0.014 0.004 0.077 0.015
## satisf_vida_4 0.044 0.103 0.001 0.000 0.061
## sit_ec_1 0.031 0.064 0.013 0.006 0.078
Si la categoría de una variable está bien representada por ambas
dimensiones o factores, la suma de los cosenos cuadráticos tendrá un
valor cercano a 1. Para algunos casos en las filas, se necesitarán más
de dos dimensiones para representar perfectamente a los datos.
La manera de revisar la distribución de los valores de la calidad de
representación de las categorías es mediante una gráfica de barras a
partir de la variable $cos2 dentro del comando
fviz_cos2().
fviz_cos2(mca_lb, #objeto tipo lista con resultados mca
choice = "var", # selección de las varianzas
axes = 1:2) # ejes o dimensiones considerar en la gráfica

A partir de esta gráfica se puede identificar que las primeras cinco
categorías con mayores valores son las que están mejor representadas en
la gráfica de dispersión, estas se ubican dentro de las variables de
“aprobación del gobierno en turno” y “confianza en el gobierno en
turno”, mientras que las que están por debajo del valor de 0.2 no
necesariamente cuentan con proyecciones adecuadas en la gráfica generada
a partir solo de las dimensiones 1 y 2. Por ello, la interpretación de
estas últimas categorías se debe realizar con cuidado (tal vez sea
necesaria una solución que incluya a una mayor cantidad de
dimensiones).
Una manera adicional de representar la calidad de las categorías en
el gráfico biplot es a partir de ajustar los colores para cada
punto proyectado, y tomando como criterio el valor del coseno cuadrático
(cos2). Para modificar el color de los puntos se utiliza el argumento
col.var=, con el que se producen colores en gradientes, que
se pueden ajustar a partir del argumento gradient.cols=.
Por ejemplo, si se ajustra `gradient.cols = c(“white”, “blue”, red”),
esto se traduce en:
- categorías con bajo valor de coseno cuadrático se colorearán en
blanco (“white”).
- categorías con valores medios de coseno cuadrático se colorearán en
azul (“blue”).
- categorías con valores alto de coseño cuadrático se colorearán en
“rojo” (“red”).
De manera que:
fviz_mca_var(mca_lb, #objeto tipo lista con resultados mca
col.var = "cos2", #definición de los colores a partir del valor cos2
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), #definición de la paleta de colores
repel = TRUE, # evitar solapamientos de etiquetas,
max.overlaps = "ggrepel.max.overlaps", #aumentar el tamaño de solapamientos
ggtheme = theme_minimal()
)
## Warning: ggrepel: 10 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
Adicionalmente, también es posible cambiar la intensidad de la
transparencia de las categorías de variables según el criterio de los
valores de la calidad de representación (cos2) mediante el argumento
alpha.var =, de la siguiente manera:
fviz_mca_var(mca_lb,
alpha.var="cos2",
repel = TRUE,
max.overlaps = "ggrepel.max.overlaps",
ggtheme = theme_minimal()
)
## Warning: ggrepel: 10 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
Contribución de las
categorías sobre las dimensiones creadas
Finalmente, es importante identificar cuáles son las categorías (no
solo las variables en sí mismas) que ejercen mayor influencia sobre el
comportamiento de las dimensiones o factores creados. Para ello es
importante revisar la contribución porcentual de cada categoría en la
definición de los ejes recuperados para el análisis.
Una manera inicial para revisar el porcentaje de contribución de cada
categoría sobre cada dimensión se logra mandando a llamar una tabla con
los valores porcentuales de cada categoría mediante el argumento
$contrib
head(round(variables $ contrib, 2))
## Dim 1 Dim 2 Dim 3 Dim 4 Dim 5
## satisf_vida_1 1.26 0.89 2.16 0.05 7.33
## satisf_vida_2 0.00 1.26 2.81 3.04 1.53
## satisf_vida_3 1.26 0.66 0.23 5.05 1.09
## satisf_vida_4 1.63 5.75 0.09 0.01 5.23
## sit_ec_1 1.16 3.67 0.92 0.46 6.88
## sit_ec_2 4.12 0.20 1.73 1.49 0.00
En dicha tabla se observan en el lado de las filas a cada una de las
categorías activas incluidas en el análisis, mientras que en las
columnas se ubican cada una de las dimensiones creadas.
Las categorías que más contribuyen a cada dimensión se corresponden
con aquellas que registran mayores valores porcentuales. Las categorías
que contribuyen en mayor medida sobre las dimensiones 1 y 2 son las que,
a su vez, tienen mayor influencia al explicar la variabilidad de la
matriz de datos.
Gráficamente se puede representar la contribución de cada categoría
sobre cada dimensión mediante el uso del comando
fviz_contrib(), con la que se crea una gráfica de
barras.
# Contribución de las categorías a la dimensión 1.
fviz_contrib(mca_lb, #objeto tipo lista con resultados mca
choice = "var", #criterio a representar: varianza
axes = 1, # selección del eje o dimensión a analizar = eje 1
top = 15) # selección de las 15 categorías con mayor contribuión
# Contribución de las categorías a la dimensión 2.
fviz_contrib(mca_lb, #objeto tipo lista con resultados mca
choice = "var", #criterio a representar: varianza
axes = 2, # selección del eje o dimensión a analizar = eje 2
top = 15) # selección de las 15 categorías con mayor contribución
En estas gráficas se incluyó una línea roja punteada, la que
representa el valor promedio esperado en dado caso que las
contribuciones de todas las categorías fueran uniformes. De manera que
aquellas que están por encima de dicha recta, se interpreta que tienen
una contribución importante mientras que las que están por debajo se
consideran con poca influencia sobre las dimensiones o factores.
A partir de las gráficas previas se puede establecer lo
siguiente:
- Se identificaron 11 categorías que tienen mayor contribución que el
resto sobre la definición de la dimensión 1, especialmente las
categorías 1 y 4 de la variable “confianza en el gobierno”, las
categorías 2 y 1 de la variable “aprobación del gobierno”, las
categorías 4 y 1 de la variable “satisfacción con la democracia”, la
categoría 2 de la variable “votó por el gobierno” y la categoría 5 de la
variable “percepción de la situación de la economía”.
- La cantidad de categorías que contribuyen a la dimensión 2 por
arriba del promedio esperado es mayor que en la primer dimensión. Y las
5 categorías que más influyen son la categoría 3 de la variable
“satisfacción con la democracia”, la categoría 3 de la variable
“confianza en el gobierno”, la categoría 5 de la variable “situación de
la economía”, la categoría 1 de la variable “interés en la política” y
la categoría 1 de la variable “confianza en el gobierno.”
A su vez, se puede calcular la contribución total de cada categoría a
cada una de las dimensiones de interés, que en este caso se limitan a
los ejes 1 y 2. Para ello se utiliza el mismo comando, solo se ajusta el
argumento sobre los ejes a seleccionar axes=.
# Total contribution to dimension 1 and 2
fviz_contrib(mca_lb, #objeto tipo lista con resultados mca
choice = "var", #criterio de representación = varianzas
axes = 1:2, # ejes seleccionados en la representación = ejes 1 y 2 simultáneos
top = 20) #selección de las 20 categorías con mayor contribución
En esta gráfica se identificaron 15 categorías que ejercen mayor
influencia que el promedio esperado del total de las columnas activas de
la matriz de datos. De estas:
- Las categorías 1 y 4 de la variable “confianza en el gobierno” son
las que ejercen mayor contribución.
- Existen otras cinco categorías que también son medianamente
relevantes, como lo son la categoría 4 de “satisfacción con la
democracia”, la categoría 5 de “situación de la economía”, la categoría
2 de “aprobación del gobierno”, la categoría 1 de “satisfacción con la
democracia”, y la categoría 1 de “aprobación del gobierno”.
- Se ubicaron otras ocho categorías con una influencia importante pero
de menor contribución, que van desde la categoría 2 de “votó al partido
del gobierno”, hasta la categoría 2 de “confianza en el gobierno.”
- El resto de las categorías se ubicaron por debajo del promedio
esperado, y por tanto pueden considerase poco relevantes para evaluar la
contribución de los ejes.
La contribución de las categorías puede representarse de manera
gráfica en el biplot que se ha trabajado hasta el momento, a
partir de señalarlo mediante la coloración de los puntos en la gráfica,
para lo que se usa el argumento col.var = "contrib" de la
siguiente manera:
fviz_mca_var(mca_lb, #objeto tipo lista con resultados mca
col.var = "contrib", #definir la coloración mediante la "contribución"
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), #selección de la paleta de colores
repel = TRUE, # evitar solapamiento de etiquetas
max.overlaps = "ggrepel.max.overlaps", #aumentar la cantidad de solapamientos
ggtheme = theme_minimal()
)
## Warning: ggrepel: 10 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
La gráfica permite identificar cuáles son la categorías que más están
contribuyendo en la construcción de la gráfica, así como los polos o
extremos de las dimensiones sobre las que están influyendo.
De manera que se observa que las categorías “conf_gob_1”,
“satisf_dem_1” y “aprob_gob_1” están influyendo fuertemente sobre los
valores positivos de la dimensión 1 y, en contraparte, las categorías
“conf_gob_4”, “satisf_dem_4”, “sit_ec_5” y “aprob_gob_2” lo están
haciendo sobre la parte negativa de la misma dimensión.
Por último, también es posible controlar la intensidad de la
transparencia de la proyección de cada punto correspondiente a las
categorías, a partir del criterio de los valores de su contribución
sobre las dimensiones. Para ello se utiliza el comando
alpha.var = "contrib" en el comando
fviz_mca_var().
fviz_mca_var(mca_lb, #objeto tipo lista con resultados mca
alpha.var="contrib", #control de la intensidad de la transparencia
repel = TRUE, # evitar solapamiento de etiquetas
max.overlaps = "ggrepel.max.overlaps", #aumentar la cantidad de solapamientos
ggtheme = theme_minimal()
)
## Warning: ggrepel: 10 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
Análisis sobre los
individuos
Por otro lado, también es posible realizar el análisis de
correspondencias sobre los perfiles de los individuos (filas) dentro del
MCA. Esto permite agrupar y ubicar a los individuos o
casos más semejantes entre sí, tomando en consideración sus respuestas a
las categorías seleccionadas; además, el análisis permite ubicar a los
casos o individuos que ejercen mayor influencia sobre la distribución
dentro del biplot con las dimensiones o ejes nuevos.
El comando get_mca_ind(), que es parte de la librería
factoextra(), permite extraer los resultados para los
individuos. Esta función arroja una lista en la que están contenidas las
coordenadas, los valores de los cosenos cuadráticos y las contribuciones
de cada uno de los casos o individuos (filas) de la matriz de datos.
indiv <- get_mca_ind(mca_lb)
indiv
## Multiple Correspondence Analysis Results for individuals
## ===================================================
## Name Description
## 1 "$coord" "Coordinates for the individuals"
## 2 "$cos2" "Cos2 for the individuals"
## 3 "$contrib" "contributions of the individuals"
Los resultados observados para los individuos siguen la misma lógica
de información que la que se describió arriba para las categorías de las
variables activas.
Se puede acceder a la información contenida en cada uno de los
elementos de la lista si se manda a llamar a cada elemento mediante el
signo “$”:
# coordinadas para las filas
head(indiv $ coord, 3)
## Dim 1 Dim 2 Dim 3 Dim 4 Dim 5
## 1 -0.6997875 1.2545334 0.1596905 -0.2323458 0.3506066
## 2 -0.6852106 1.0158574 -0.4754693 -0.3631857 -0.1149143
## 3 -0.4542715 0.6805767 -0.1955161 -0.7863946 0.2889284
# cualidad de la representación
head(indiv $ cos2, 3)
## Dim 1 Dim 2 Dim 3 Dim 4 Dim 5
## 1 0.10026154 0.3222303 0.005221074 0.01105278 0.025167623
## 2 0.15077195 0.3313889 0.072596784 0.04235746 0.004240533
## 3 0.05675603 0.1273899 0.010513472 0.17008341 0.022959448
# contribución de cada individuo
head(indiv $ contrib, 3)
## Dim 1 Dim 2 Dim 3 Dim 4 Dim 5
## 1 0.04115312 0.20030115 0.004147188 0.009524216 0.024015258
## 2 0.03945649 0.13133622 0.036765530 0.023271105 0.002579854
## 3 0.01734209 0.05894856 0.006216717 0.109103961 0.016309008
En la tabla anterior, cada fila se refiere a cada uno de los casos o
individuos activos presentes en la matriz de datos -solo se presentan a
los 3 primeros casos. Y en el resto de cada fila se identifica el valor
para el sujeto \(-i\) en cada una de
las dimensiones o ejes calculados.
Calidad de la
representación de los individuos en el análisis
MCA
A partir del comando fviz_mca_ind() es posible crear una
gráfica de dispersión para observar la distribución de las proyecciones
de cada individuo sobre el biplot con las dimensiones o ejes analizados.
Al igual que en el caso de la gráfica sobre las categorías, aquí también
es posible señalar mediante colores la calidad o la contribución de cada
individuo sobre la gráfica.
La manera de señalar la calidad de la representación de cada
individuo en el biplot es mediante el argumento
col.ind =, por ejemplo, es la siguiente:
fviz_mca_ind(mca_lb,
col.ind = "cos2", # colorear los casos a partir del criterio de valor cos^2
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE,
max.overlaps = "ggrepel.max.overlaps",
ggtheme = theme_minimal()
)
## Warning: ggrepel: 4541 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
A partir de este gráfico se observa la distribución de los individuos
activos en la matriz de datos, que se utilizaron para el análisis
MCA.
En esta representación se pueden observar que los casos con mejor
representación se ubican en colores cercanos al rojo, y se posicionan en
los extremos de la dimensión 1, y no necesariamente hay casos del mismo
color sobre la dimensión 2. Esto indica que la distribución de los casos
están mejor representados por la primera dimensión.
Por su parte, los casos con bajos niveles de cosenos cuadráticos
tenderán a ubicarse cercanos al centroide de la gráfica (coordenadas =
[0,0]), y están señalados con el color más parecido al turquesa. Esto se
puede interpretar como que las dimensiones o ejes utilizados en la
representación gráfica no son los que mejor ayudan a entender sus
comportamientos o sus perfiles, y tal vez existan otros ejes (que habría
que explorar) que mejor se ajusten a su distribución.
Contribución de los
casos al análisis MCA
En caso de querer identificar la contribución de cada caso o
individuo (fila) sobre la construcción de las dimensiones o ejes
calculados, es posible realizarlo a partir de retomar el comando
fviz_mca_ind(), en donde se puede utilizar el argumento
col.ind = contrib. Esto permitirá señalar el nivel de
contribución de cada caso mediante los gradientes de colores.
fviz_mca_ind(mca_lb,
col.ind = "contrib", # colorear los casos a partir del valor de contribución
gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
repel = TRUE,
max.overlaps = "ggrepel.max.overlaps",
ggtheme = theme_minimal()
)
## Warning: ggrepel: 4541 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps
A partir de esta gráfica se identifica que los casos con mayor
contribución en la construcción de las dimensiones o ejes calculados se
colorean en tonalidades rojizas, mientras que los de menor contribución
están iluminados en color verde turquesa.
Esta gráfica permite identificar que el caso con mayor contribución
es el número 3864. Por lo que sería interesante, posteriormente,
analizar a profundidad dicho caso.
También se puede comenzar a identificar “nubes” o grupos de casos
semejantes entre sí. De manera que los casos más cercanos entre sí se
corresponden con perfiles parecidos en sus respuestas a las distintas
categorías de las variables medidas, en función de la calidad de su
representación. Estos se ubican en mejor medida en los extremos del eje
o dimensión 1.
Por otro lado, también se pueden crear gráficas de barras para medir
la contribución de los individuos sobre las dimensiones o ejes creados,
a partir de sus cosenos cuadráticos y sus contribuciones. Para ello se
utiliza el comando fviz_contrib().
Por ejemplo, en la gráfica siguiente se identifican a los 20 casos o
individuos con mayor contribución sobre ambas dimensiones de manera
simultánea.
fviz_contrib(mca_lb, #objeto tipo lista con los resultados mca
choice = "ind", #selección de los individuos para representarlos
axes = 1:2, #ejes o dimensiones a incluir
top = 20) #selección de los 20 casos con mayor nivel
A partir de la gráfica de barras se puede identificar con mayor
claridad cuáles son los casos con mayor contribución sobre la
construcción de las dimensiones o ejes 1 y 2. Aquí se observa que el
caso 3864 es el más influyente, y posteriormente le siguen en igual
magnitud de contribución los casos 2143, 3534 y 3677, entre otros.
De manera parecida a las gráficas vistas más arriba, donde los casos
que se ubiquen por encima de la línea recta horizontal punteada de color
rojo, indica que su influencia cae por arriba del promedio esperado de
contribución para el total de casos.
Siguiendo la misma lógica de la gráfica de barras para evaluar la
contribución de cada individuo, este mismo ejercicio se puede realizar
para observar el nivel de calidad de representación de los individuos en
ambas dimensiones de la gráfica biplot. Para ello se utiliza el
comando fviz_cos2() de la siguiente manera:
fviz_cos2(mca_lb,
choice = "ind",
axes = 1:2,
top = 20)
A partir de esta gráfica se pueden identificar los casos con mayores
niveles de cosenos cuadráticos, y que suponen estar mejor representados
en el gráfico de barras. Como se puede ver, los casos con mayores
niveles de \(cos^2\) son el 2015 y el
2629. Les siguen siete casos más con el mismo valor (desde el 1746 hasta
3984).
Agrupamiento de
individuos
Otra manera de evaluar los perfiles de casos o individuos
distribuidos por la gráfica de los ejes o dimensiones calculadas, y así
identificar sus agrupamientos, se realiza mediante la coloración de los
casos y añadiéndole elipses indicativas sobre el centroide para cada
grupo y la amplitud de su distribución. Aquí se puede seguir trabajando
con el comando fviz_mca_ind().
Al intentar agrupar los casos mediante la coloración de los puntos o
proyecciones de cada individuo, se puede establecer a una variable tipo
factor() como el criterio para llevarlo a cabo. Para ello
se usa el argumento habillage=, donde se establece el
nombre de la variable que servirá para establecer la coloración de los
individuos y, así, agruparlos.
También se puede añadir una elipse de concentración en cada uno de
los grupos creados, mediante el argumento addEllipses=TRUE.
Si se desea establecer que el centro de la elipse de confianza se ubique
sobre el punto medio de cada categoría, se debe usar el argumento
ellipse.type = "confidence".
Finalmente, se usa el argumento palette= para cambiar
los colores de los grupos.
fviz_mca_ind(mca_lb, #objeto tipo lista con resultados mca
label = "none", # ocultar las etiquetas de los individuos
habillage = "satisf_dem", # colorear a los grupos
addEllipses = TRUE,
ggtheme = theme_minimal()
)
A partir de la gráfica se puede observar la manera en que se
distribuyen los casos si son agrupados a partir de la variable
“satisfacción con la democracia” (satisf_dem), que
se integra por 4 niveles (\(k=4\)).
Asimismo se observan las elipses que muestran el tamaño de la dispersión
de cada grupo. A partir de esto se puede interpretar que los grupos
correspondientes a las categorías 1 y 4 son los que permiten agrupan de
mejor manera, y lo más excluyente posible, a los individuos.
También es relevante observar que los grupos 2 y 3 son abarcados en
su mayoría por los grupos 1 y 4, respectivamente. Esto es debido a que
los primeros se comportan como subgrupos de los últimos. Esto permite
inferir que la variable de “satisfacción con la democracia”
pudiera integrarse en solo dos grupos.
Si también se desean graficar de manera simultánea las proyecciones
de los individuos utilizando dos variables categóricas como criterios
para agruparlos, se puede llamar el comando
fviz_ellipses(), dentro del que se recupera el objeto con
los resultados del análisis MCA.
fviz_ellipses(mca_lb, # objeto tipo lista con resultados mca
c("satisf_dem", "aprob_gob"), # definición de variables factor para agrupación
geom = "point", # tipo de representación de los individuos
alpha = 0.1 #transparencia de los puntos en la gráfica
)
## Warning: `gather_()` was deprecated in tidyr 1.2.0.
## Please use `gather()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

De lado izquierdo de la gráfica se observa la agrupación de los casos
a partir de la variable “aprobación del gobierno”
(aprob_gob \(k=2\)) y en
el lado derecho se observa la distribución de los casos agregados por la
variable “satisfacción con la democracia”
(satisf_dem, \(k=4\)).
Además, dentro de cada grupo de color se observan puntos con mayor
intensidad, los que se refieren a los centros (o promedios) de la
distribución de cada agrupación de individuos. Alrededor de estos puntos
se encuentran las elipses de distribución.
Es interesante observar que para la gráfica de la izquierda, los
centros de distribución de cada grupo se ubican casi encima de la línea
punteada horizontal, correspondiente a la dimensión o eje 1. En cambio,
en la gráfica de la derecha, ninguno de los centros de las elipses se
ubica sobre alguna de las líneas punteadas, pero se debe resaltar que
cada uno de ellos se posiciona dentro de cada uno de los cuadrantes en
que está dividido el biplot. Esto nos permite inferir la manera
en que cada nube o grupo de individuos se distribuye en la gráfica, así
como los perfiles dentro de cada grupo.
Referencias
Díaz Monroy, L. G., & Morales Rivera, M. A. (2009). Análisis
estadístico de datos categóricos. Universidad Nacional de Colombia.
Facultad de Ciencias.
LS0tCmF1dGhvcjogR3VzdGF2byBNYXJ0w61uZXogVmFsZGVzCmRhdGU6ICdgciBmb3JtYXQoU3lzLkRhdGUoKSlgJwp0aXRsZTogSW50cm9kdWNjacOzbiBhbCBBbsOhbGlzaXMgZGUgQ29ycmVzcG9uZGVuY2lhcyBNw7psdGlwbGVzIChNdWx0aXBsZSBDb3JyZXNwb25kZW5jZQogIEFuYWx5c2lzKS4Kc3VidGl0bGU6IFTDqWNuaWNhIGRlIGFncnVwYW1pZW50byBwYXJhIHZhcmlhYmxlcyBjYXRlZ8OzcmljYXMKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgdGhlbWU6IGNvc21vCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA2LjAKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKYmlibGlvZ3JhcGh5OiBtZXRvZG9sb2dpYS5iaWIKY3NsOiBhcGEuY3NsCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgo8IS0tLWh0dHA6Ly93d3cuc3RoZGEuY29tL2VuZ2xpc2gvYXJ0aWNsZXMvMzEtcHJpbmNpcGFsLWNvbXBvbmVudC1tZXRob2RzLWluLXItcHJhY3RpY2FsLWd1aWRlLzExNC1tY2EtbXVsdGlwbGUtY29ycmVzcG9uZGVuY2UtYW5hbHlzaXMtaW4tci1lc3NlbnRpYWxzLyAtLS0+CgojIFByZXNlbnRhY2nDs24KCkVsICoqQW7DoWxpc2lzIGRlIENvcnJlc3BvbmRlbmNpYXMgTcO6bHRpcGxlKiogKG8gKk11bHRpcGxlIENvcnJlc3BvbmRlbmNlIEFuYWx5c2lzKiBbKipNQ0EqKl0pIGVzIHVuYSBleHRlbnNpw7NuIGRlbCBhbsOhbGlzaXMgc2ltcGxlIGRlIGNvcnJlc3BvbmRlbmNpYXMsIHkgcGVybWl0ZSByZWR1Y2lyIHkgdmlzdWFsaXphciB1bmEgdGFibGEgZGUgY29udGluZ2VuY2lhIHF1ZSBjb250ZW5nYSBtw6FzIGRlIGRvcyB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzLiBFc3RhIHTDqWNuaWNhIHRhbWJpw6luIHB1ZWRlIHNlciB2aXN0YSBjb21vIHVuYSBnZW5lcmFsaXphY2nDs24gZGVsICpBbsOhbGlzaXMgZGUgQ29tcG9uZW50ZXMgUHJpbmNpcGFsZXMqLCBzaW4gZW1iYXJnbyBhcXXDrSBzZSBjYXJhY3Rlcml6YSBwb3JxdWUgbGFzIHZhcmlhYmxlcyBhIGFuYWxpemFyIHNvbiBjYXRlZ8OzcmljYXMsIGVuIGx1Z2FyIGRlIGN1YW50aXRhdGl2YXMuXAoKRWwgKipNQ0EqKiBnZW5lcmFsbWVudGUgc2UgdXNhIHBhcmEgYW5hbGl6YXIgYSB1biBjb25qdW50byBkZSBkYXRvcyBwcm92ZW5pZW50ZXMgZGUgZW5jdWVzdGFzLCB5IGxhIG1ldGEgZGUgc3UgdXNvIGVzOgoKMS4gIElkZW50aWZpY2FyIGEgZ3J1cG9zIGRlIGluZGl2aWR1b3MgY29uIHBlcmZpbGVzIHNpbWlsYXJlcyBlbiBzdXMgcmVzcHVlc3RhcyBlbiBsYXMgY2F0ZWdvcsOtYXMgZGUgdmFyaWFibGVzIG1lZGlkYXMuCjIuICBFdmFsdWFyIGxhcyBhc29jaWFjaW9uZXMgZXhpc3RlbnRlcyBlbnRyZSBsYXMgY2F0ZWdvcsOtYXMgKG8gYXRyaWJ1dG9zKSBkZSBsYXMgdmFyaWFibGVzIGNhdGVnw7NyaWNhcy4KCkVzdGEgdMOpY25pY2Egc2UgYXBveWEsIGVuIGdyYW4gbWVkaWRhLCBlbiBtw6l0b2RvcyB2aXN1YWxlcyBwYXJhIGVsIGFuw6FsaXNpcyBkZSBsb3MgcmVzdWx0YWRvcy5cCgpFbiBlc3RhIHByZXNlbnRhY2nDs24gc2UgcmVhbGl6YSB1bmEgaW50cm9kdWNjacOzbiBhIGxhIGlucGxlbWVudGFjacOzbiBkZSBsYSB0w6ljbmljYSAqKk1DQSoqIHBhcmEgY2FsY3VsYXIgeSB2aXN1YWxpemFyIHN1cyByZXN1bHRhZG9zIGVuICoqUioqLCBwYXJhIGVsbG8gc2UgdXRpbGl6YXLDoSBsYSBsaWJyZXLDrWEgYEZhY3RvTWluZVIoKWAgYWwgbW9tZW50byBkZSBhbmFsaXphciBsb3MgZGF0b3MgeSwgYWRlbcOhcywgbGEgbGlicmVyw61hIGBmYWN0b2V4dHJhKClgIHBhcmEgbGEgdmlzdWFsaXphY2nDs24gZGUgbG9zIHJlc3VsdGFkb3MuXAoKQWRlbcOhcyBzZSBidXNjYSBwcmVzZW50YXIgdW5hIG1hbmVyYSBwYXJhIGlkZW50aWZpY2FyIGEgbGFzIHZhcmlhYmxlcyBtw6FzIHJlbGV2YW50ZXMgZW4gZWwgY29uanVudG8gZGUgZGF0b3MsIHkgcXVlIHRpZW5lbiBtYXlvciBjb250cmlidWNpw7NuIGVuIGxhIGV4cGxpY2FjacOzbiBkZSBsYXMgdmFyaWFjaW9uZXMgZGVudHJvIGRlIGxvcyBkYXRvcy4gWSBzZSBtdWVzdHJhIGxhIG1hbmVyYSBwYXJhIHByZWRlY2lyIGxvcyByZXN1bHRhZG9zIHBhcmEgaW5kaXZpZHVvcyB5IHZhcmlhYmxlcyBzdXBsZW1lbnRhcmlhcy4gVGFtYmnDqW4gc2UgcHJlc2VudGEgbGEgbWFuZXJhIHBhcmEgZmlsdHJhciBsb3MgcmVzdWx0YWRvcyBkZWwgYW7DoWxpc2lzICoqTUNBKiogY29uIGVsIGZpbiBkZSBtYW50ZW5lciBzb2xvIGEgbGFzIHZhcmlhYmxlcyBjb24gbWF5b3IgY29udHJpYnVjacOzbi4KCiMgUHJlcGFyYWNpw7NuIGRlbCBhbWJpZW50ZS4KCkFudGVzIGRlIGNvbWVuemFyLCBlcyByZWNvbWVuZGFibGUgYWp1c3RhciBsYSBjb25maWd1cmFjacOzbiBkZSAqKlIqKiBhbCBhbWJpZW50ZSBkZSB0cmFiYWpvLgoKIyMgSWRpb21hLgoKRW4gdW4gcHJpbWVyIG1vbWVudG8gc2UgcmVjb21pZW5kYSBjYW1iaWFyIGVsIGlkaW9tYSBlbiBxdWUgKipSKiogbGVlIGxhIGluZm9ybWFjacOzbiwgZXN0byBjb24gZWwgZmluIGRlIGFqdXN0YXJsYSBhbCBpZGlvbWEgZXNwYcOxb2wuIERlIGVzdGEgbWFuZXJhIHNlIHBvZHLDoW4gZGV0ZWN0YXIgbG9zIGNhcmFjdGVyZXMgZGVsIGlkaW9tYSwgY29tbyBsb3MgYWNlbnRvcyBvIHTDrWxkZXMuIFBhcmEgaGFjZXJsbywgc2UgdXNhIGVsIGNvbWFuZG8gYFN5cy5zZXRsb2NhbGUoKWAuCgpgYGB7ciBpZGlvbWF9ClN5cy5zZXRsb2NhbGUoIkxDX0FMTCIsICJlbl9VUy5VVEYtOCIpCmBgYAoKIyMgTGlicmVyw61hcy4KCk90cm8gZWxlbWVudG8gcXVlIHNlIHJlY29taWVuZGEgYWp1c3RhciBlbiB1biBpbmljaW8gY29uc2lzdGUgZW4gbGEgaW5zdGFsYWNpw7NuIHkgY2FyZ2EgZGUgbGFzIGxpYnJlcsOtYXMuIFBhcmEgZWwgYW7DoWxpc2lzIGRlICoqTUNBKiogc2UgdXRpbGl6YXLDoW4gZG9zIHBhcXVldGVyw61hcyBlc3BlY2lhbGVzLCB1bmEgZXMgYEZhY3RvTWluZVIoKWB5IGxhIG90cmEgZXMgYGZhY3RvZXh0cmEoKWAsIHkgZXN0YSDDumx0aW1hIHNlIGFwb3lhIGVuIGxhIGxpYnJlcsOtYSBgZ2dwbG90KClgLiBFbiBjYXNvIGRlIG5vIGhhYmVybGFzIGluc3RhbGFkbyBwcmV2aWFtZW50ZSwgZXN0byBzZSBwdWVkZSBoYWNlciBjb24gZWwgc2lndWllbnRlIGNvbWFuZG8uCgogICAgaW5zdGFsbC5wYWNrYWdlcyhjKCJGYWN0b01pbmVSIiwgImZhY3RvZXh0cmEiLCAidGlkeXZlcnNlIiwgIm5hbmlhciIsICJjb3JycGxvdCIpKQoKWSB1bmEgdmV6IHF1ZSBoYW4gc2lkbyBpbnN0YWxhZGFzLCBzZSBkZWJlbiBhY3RpdmFyIGNvbiBlbCBjb21hbmRvIGBsaWJyYXJ5KClgLgoKYGBge3IgbGlicmVyaWFzfQpsaWJyYXJ5KGVhc3lwYWNrYWdlcykKcGFxdWV0ZXMgPC0gYygiRmFjdG9NaW5lUiIsICJ0aWR5dmVyc2UiLCAiZmFjdG9leHRyYSIsICJoYXZlbiIsICJuYW5pYXIiLCAiY29ycnBsb3QiKQpsaWJyYXJpZXMocGFxdWV0ZXMpCmBgYAoKIyMgQ2FyZ2EgZGUgbG9zIGRhdG9zCgpBIGNvbnRpbnVhY2nDs24gZXMgcmVjb21lbmRhYmxlIGNhcmdhciBsb3MgZGF0b3MgZW4gKipSKiosIHBhcmEgbG8gcXVlIHNlIHV0aWxpemEgZWwgYGRhdGEuZnJhbWVgIGRlIGxhIG9sYSAyMDIwIGRlIGxhIGVuY3Vlc3RhIGRlIExhdGlub2JhcsOzbWV0cm8uIEVuIGxhIFtww6FnaW5hXShodHRwczovL3d3dy5sYXRpbm9iYXJvbWV0cm8ub3JnL2xhdENvbnRlbnRzLmpzcCkgZGUgZGljaGEgb3JnYW5pemFjacOzbiBzZSBlbmN1ZW50cmFuIGRpc3BvbmlibGVzIGxhcyBiYXNlcyBkZSBkYXRvcywgeSB0YW1iacOpbiBlcyBpbXBvcnRhbnRlIHJldmlzYXIgZWwgW2xpYnJvIGRlIGPDs2RpZ29zXShodHRwczovL3d3dy5sYXRpbm9iYXJvbWV0cm8ub3JnL2xhdENvbnRlbnRzLmpzcCksIHF1ZSBwZXJtaXRlIGlkZW50aWZpY2FyIGxhcyBjb2RpZmljYWNpb25lcyBkZSBsb3Mgw610ZW1zIHkgbG9zIHZhbG9yZXMgZGUgcmVzcHVlc3RhIHBvc2libGVzIG8gYXRyaWJ1dG9zLgoKYGBge3IgZGF0b3N9CmxvYWQoIn4vRHJvcGJveC9SL0xhdGlub2Jhcm9tZXRyb18yMDIwX0VzcF9SZGF0YV92MV8wLnJkYXRhIikKZGF0b3NfbGIgPC0gTGF0aW5vYmFyb21ldHJvXzIwMjBfRXNwCmBgYAoKIyBQcmVwYXJhY2nDs24gZGUgbG9zIGRhdG9zIHkgc3UgZGVzY3JpcGNpw7NuCgpFbiB1biBwcmltZXIgbW9tZW50byBlcyBpbXBvcnRhbnRlIGNyZWFyIHVuYSBzdWIgc2VjY2nDs24gZGUgbGEgbXVlc3RyYSwgZW4gbGEgcXVlIHNlIGVuY3VlbnRyZW4gc29sbyBsYXMgdmFyaWFibGVzIGRlIGludGVyw6lzLsKgIEEgcGFydGlyIGRlIGxhIGVuY3Vlc3RhIGRlIExhdGlub2JhcsOzbWV0cm8gcGFyYSBsYSBvbGEgMjAyMCBzZSBzZWxlY2Npb25hcm9uIDEwIHZhcmlhYmxlcywgeSBkb25kZSAiKCRrID0kKSIgc2UgcmVmaWVyZSBhIGxhIGNhbnRpZGFkIGRlIG9wY2lvbmVzIGRlIHJlc3B1ZXN0YSwgYXRyaWJ1dG9zIG8gY2F0ZWdvcsOtYXMgcG9zaWJsZXMuIEFxdcOtIHNlIHB1ZWRlIHZlciBxdWUgdG9kYXMgZXN0YXMgdmFyaWFibGVzIHNvbiBkZSBjb3J0ZSBjYXRlZ8Ozcmljby4KCi0gICBwMXN0IC0gU2F0aXNmYWNjacOzbiBjb24gbGEgdmlkYSAoayA9IDQpLgotICAgcDRzdGdicyAtIFNpdHVhY2nDs24gZWNvbsOzbWljYSBhY3R1YWwgKGsgPSA0KS4KLSAgIHAxMHN0Z2JzIC0gQXBveW8gYSBsYSBkZW1vY3JhY2lhIChrID0gMykuCi0gICBQMTFTVEdCU19BIC0gU2F0aXNmYWNjacOzbiBjb24gbGEgdmlkYSAoayA9IDQpLgotICAgcDEzc3RfZSAtIENvbmZpYW56YSBlbiBlbCBnb2JpZXJubyAoayA9IDQpLgotICAgcDE3c3RnYnMgLSBBcHJvYmFjacOzbiBkZSBsYSBnZXN0acOzbiBkZWwgZ29iaWVybm8gZGVsIHByZXNpZGVudGUgKGsgPSAyKS4KLSAgIHAxOHN0IC0gRXNjYWxhIEl6cXVpZXJkYSAtIERlcmVjaGEgKDAsIDEwKS4KLSAgIHAzMHN0X2EgLSBPcGluacOzbiBzb2JyZSBFc3RhZG8gVW5pZG9zIGRlIEFtw6lyaWNhIChrID0gNCkuCi0gICBwNDZzdGdicyAtIEludGVyw6lzIGVuIGxhIHBvbMOtdGljYSAoayA9IDQpLgotICAgUDUxU1RHQlNfQiAtIFZvdMOzIGFsIHBhcnRpZG8gZGVsIGdvYmllcm5vIG8gZGUgbGEgb3Bvc2ljacOzbiAoayA9IDIpLgoKQXF1w60gc2UgcmVhbGl6w7MgbGEgc2VsZWNjacOzbiBkZSBsYXMgY29sdW1uYXMgbyB2YXJpYWJsZXMgZGUgaW50ZXLDqXMgeSwgYWRlbcOhcywgc2UgY2FtYmnDsyBlbCBub21icmUgZGUgZGljaGFzIGNvbHVtbmFzLiBTZSBhbGNhbnphIGEgb2JzZXJ2YXIgcXVlIGV4aXN0ZW4gdmFsb3JlcyBuZWdhdGl2b3MsIG1pZW50cmFzIHF1ZSBleGlzdGVuIG90cm9zIHZhbG9yZXMgbXV5IGdyYW5kZXMgKHBvciBlamVtcGxvIGVsIHZhbG9yICI5NyIgZW4gbGEgdmFyaWFibGUgZGUgYXV0byB1YmljYWNpw7NuIGlkZW9sw7NnaWNhKSwgcXVlIHNlIHB1ZWRlbiB0cmF0YXIgY29tbyB2YWxvcmVzIHBlcmRpZG9zLiBQb3IgZWxsbyBzZSBsZSBkZWJlIHNlw7FhbGFyIGNvbW8gdGFsIGFsIGNvbmp1bnRvIGRlIGRhdG9zLCBwYXJhIGxvIHF1ZSBzZSB1c2EgbGEgbGlicmVyw61hIGBuYW5pYXIoKWAuCgpgYGB7ciBzdWIgbXVlc3RyYX0KbmFfc3RyaW5ncyA8LSBjKDAsIDgsIDksIC0xLCAtMiwgLTMsIC00LCAtNSwgOTcsIDk4LCA5OSkKc3ViX2RhdG9zIDwtIGRhdG9zX2xiICU+JQogIHNlbGVjdChwMXN0LCBwNHN0Z2JzLCBwMTBzdGdicywgUDExU1RHQlMuQSwgcDEzc3QuZSwgcDE3c3RnYnMsIHAxOHN0LCBwMzBzdC5hLCBwNDZzdGdicywgUDUxU1RHQlMuQikgJT4lCiAgcmVuYW1lKHNhdGlzZl92aWRhID0gcDFzdCwKICAgICAgICAgc2l0X2VjID0gcDRzdGdicywKICAgICAgICAgYXBveW9fZGVtID0gcDEwc3RnYnMsCiAgICAgICAgIHNhdGlzZl9kZW0gPSBQMTFTVEdCUy5BLAogICAgICAgICBjb25mX2dvYiA9IHAxM3N0LmUsCiAgICAgICAgIGFwcm9iX2dvYiA9IHAxN3N0Z2JzLAogICAgICAgICB1YmljX2lkZW9sID0gcDE4c3QsCiAgICAgICAgIG9wX2V1YSA9IHAzMHN0LmEsCiAgICAgICAgIGludF9wb2wgPSBwNDZzdGdicywKICAgICAgICAgdm90b19nb2IgPSBQNTFTVEdCUy5CKSAlPiUKICBuYW5pYXI6OnJlcGxhY2Vfd2l0aF9uYV9hbGwoY29uZGl0aW9uID0gfi54ICVpbiUgbmFfc3RyaW5ncykKYGBgCgpBaG9yYSBzZSBzb2xpY2l0YSB1bmEgcmV2aXNpw7NuIGEgbGEgZXN0cnVjdHVyYSBkZSBsYXMgdmFyaWFibGVzIGRlIGludGVyw6lzLCBwYXJhIGVsbG8gc2UgdXNhIGVsIGNvbWFuZG8gYHN0cigpYC4KCmBgYHtyIHN1bW1hcnl9CnN0cihzdWJfZGF0b3MpCmBgYAoKRGljaG8gcmVzdW1lbiBwZXJtaXRlIGlkZW50aWZpY2FyIHF1ZSBsYXMgdmFyaWFibGVzIGZ1ZXJvbiBkZXRlY3RhZGFzIHBvciBgUmAgZGVsIHRpcG8gYGludGVnZXJgIChlbnRlcm9zKSwgcGVybyBlcyBuZWNlc2FyaW8gdHJhbnNmb3JtYXJsYXMgYSBvdHJvIGZvcm1hdG8gdGlwbyBgZmFjdG9yYCBwYXJhIGluY2x1aXJsYXMgZW4gZWwgYW7DoWxpc2lzICoqTUNBKiouIFBhcmEgZWxsbyBzZSB1dGlsaXphIGVsIGNvbWFuZG8gYGZhY3RvcigpYC5cCgpgYGB7ciBmYWN0b3J9CnN1Yl9kYXRvcyAkIHNhdGlzZl92aWRhIDwtIGZhY3RvcihzdWJfZGF0b3MgJCBzYXRpc2ZfdmlkYSkKc3ViX2RhdG9zICQgc2l0X2VjIDwtIGZhY3RvcihzdWJfZGF0b3MgJCBzaXRfZWMpCnN1Yl9kYXRvcyAkIGFwb3lvX2RlbSA8LSBmYWN0b3Ioc3ViX2RhdG9zICQgYXBveW9fZGVtKQpzdWJfZGF0b3MgJCBzYXRpc2ZfZGVtIDwtIGZhY3RvcihzdWJfZGF0b3MgJCBzYXRpc2ZfZGVtKQpzdWJfZGF0b3MgJCBjb25mX2dvYiA8LSBmYWN0b3Ioc3ViX2RhdG9zICQgY29uZl9nb2IpCnN1Yl9kYXRvcyAkIGFwcm9iX2dvYiA8LSBmYWN0b3Ioc3ViX2RhdG9zICQgYXByb2JfZ29iKQpzdWJfZGF0b3MgJCB1YmljX2lkZW9sIDwtIGZhY3RvcihzdWJfZGF0b3MgJCB1YmljX2lkZW9sKQpzdWJfZGF0b3MgJCBvcF9ldWEgPC0gZmFjdG9yKHN1Yl9kYXRvcyAkIG9wX2V1YSkKc3ViX2RhdG9zICQgaW50X3BvbCA8LSBmYWN0b3Ioc3ViX2RhdG9zICQgaW50X3BvbCkKc3ViX2RhdG9zICQgdm90b19nb2IgPC0gZmFjdG9yKHN1Yl9kYXRvcyAkIHZvdG9fZ29iKQoKYGBgCgpBaG9yYSBzZSBwdWVkZSBzb2xpY2l0YXIgdW5hIHJldmlzacOzbiBncsOhZmljYSBkZSBsYSBkaXN0cmlidWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgZGUgaW50ZXLDqXMsIHBhcmEgZWxsbyBzZSBzZSB1dGlsaXphcsOhIGVsIGNvbWFuZG8gYGZvcigpYCwgcXVlIHBlcm1pdGUgcmVwZXRpciB1biBtaXNtbyBjb21hbmRvIGVuIHZhcmlhcyBzaXR1YWNpb25lcy4KCmBgYHtyIGdyYWZpY2FzfQpzdWJfZGF0b3MgPC0gbmEub21pdChzdWJfZGF0b3MpCmZvciAoaSBpbiAxOjEwKXsKICBwbG90KHN1Yl9kYXRvc1ssaV0sIG1haW4gPSBjb2xuYW1lcyhzdWJfZGF0b3MpW2ldLAogICAgICAgeWxhYiA9ICJDYW50aWRhZCIsIGNvbCA9InN0ZWVsYmx1ZSIsIGxhcyA9IDIpCn0KYGBgCgpBIHBhcnRpciBkZSBlc3RhcyBncsOhZmljYXMgc2UgZGViZSBpZGVudGlmaWNhciBjdcOhbGVzIHNvbiBsYXMgb3BjaW9uZXMgZGUgcmVzcHVlc3RhIG8gYXRyaWJ1dG9zIHF1ZSByZWdpc3RyYXJvbiB1bmEgZnJlY3VlbmNpYSBtdXkgYmFqYSBwdWVzIHB1ZWRlbiBkaXN0b3JzaW9uYXIgZWwgYW7DoWxpc2lzIHBvc3RlcmlvciB5LCBwb3IgdGFudG8sIGRlYmVuIHNlciByZW1vdmlkYXMuIEVuIGVzdGUgZWplcmNpY2lvIHNlIGRlY2lkacOzIG1hbnRlbmVyIHRvZGFzIGxhcyB2YXJpYWJsZXMgeSBzdXMgY2F0ZWdvcsOtYXMuCgojIEFuw6FsaXNpcyBpbmljaWFsIGRlICoqTUNBKioKCkEgY29udGludWFjacOzbiBzZSBpbmljaWEgZWwgYW7DoWxpc2lzIGRlICoqTUNBKiogZW4gYFJgLCBwYXJhIGxvIHF1ZSBzZSB1c2Fyw6EgaW5pY2lhbG1lbnRlIGVsIGNvbWFuZG8gYE1DQSgpYCwgcXVlIGVzIHBhcnRlIGRlIGxhIGxpYnJlcsOtYSBgRmFjdG9NaW5lcigpYC5cClN1IGVzdHJ1Y3R1cmEgZXM6CgogICAgICAgIE1DQShYLCBuY3AgPSAsIGdyYXBoID0gVFJVRSkKCkxvcyBhcmd1bWVudG9zIGNvbnNpc3RlbiBlbjoKCi0gICBYOiB1biBkYXRhIGZyYW1lIGNvbiAqbiogZmlsYXMgKGluZGl2aWR1b3MpIHkgKnAqIGNvbHVtbmFzICh2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzKS4KLSAgIG5jcDogbsO6bWVybyBkZSBkaW1lbnNpb25lcyBhIGd1YXJkYXIgZW4gbG9zIHJlc3VsdGFkb3MgZmluYWxlcy4KLSAgIGdyYXBoOiBhIHBhcnRpciBkZSB1biB2YWxvciBsw7NnaWNvIChgVFJVRWAsIGBGQUxTRWApIHNlIGluZGljYSBzaSBzZSBkZXNlYSBnZW5lcmFyIGxhIGdyw6FmaWNhIGNvcnJlc3BvbmRpZW50ZS4KCkVuIGVsIGPDs2RpZ28gcXVlIGVzdMOhIGRlYmFqbywgZWwgYW7DoWxpc2lzICoqTUNBKiogc2UgcmVhbGl6YXLDoSBzb2xvIHNvYnJlIGxvcyBpbmRpdmlkdW9zIHkgdmFyaWFibGVzIGFjdGl2YXMgbyBkZSBpbnRlcsOpcywgdWJpY2FkYXMgZW4gZWwgZGF0YSBmcmFtZSBgc3ViX2RhdG9zYC4KCmBgYHtyIE1BQ19pbmljaWFsfQptY2FfbGIgPC0gTUNBKHN1Yl9kYXRvcywgZ3JhcGggPSBGQUxTRSkKYGBgCgpFbCByZXN1bHRhZG8gZ2VuZXJhZG8gc2UgaGEgZ3VhcmRhZG8gZW4gdW4gb2JqZXRvIGRlbm9taW5hZG8gYG1jYV9sYmAsIHkgcXVlIGNvbnNpc3RlIGVuIHVuYSBsaXN0YSBxdWUgY29udGllbmUgaW5mb3JtYWNpw7NuIGRpdmVyc2EsIGNvcnJlc3BvbmRpZW50ZSB0YW50byBhIGxpc3RhcyB5IG1hdHJpY2VzLiBZIHBhcmEgZGFybGUgdW4gdmlzdGF6byBhIHN1IGNvbnRlbmlkbyBzZSB1c2EgZWwgY29tYW5kbyBgcHJpbnQoKWAuCgpgYGB7ciBwcmludH0KcHJpbnQobWNhX2xiKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGUgaW50ZXJwcmV0YWNpw7NuIGluaWNpYWwgZGVsIGFuw6FsaXNpcyAqKk1DQSoqCgpVbmEgZGUgbGFzIGNhcmFjdGVyw61zdGljYXMgY2VudHJhbGVzIGRlIGxhIHTDqWNuaWNhICoqTUNBKiogY29uc2lzdGUgZW4gZWwgYXBveW8gZGUgbcOpdG9kb3MgdmlzdWFsZXMgcGFyYSBsYSBpbnRlcnByZXRhY2nDs24gZGUgbG9zIHJlc3VsdGFkb3MgZGUgbG9zIGFuw6FsaXNpcy4gQSBjb250aW51YWNpw7NuIHNlIHVzYSBsYSBsaWJyZXLDrWEgYGZhY3RvZXh0cmEoKWAsIHF1ZSBhIHN1IHZleiBzZSBhcG95YSBlbCBsYSBsaWJyZXLDrWEgYGdncGxvdDIoKWAsIHBhcmEgZ2VuZXJhciBsYXMgZ3LDoWZpY2FzIGluaWNpYWxlcyB5LCBhc8OtLCBhdmFuemFyIGVuIHN1IGludGVycHJldGFjacOzbi4KCkRpY2hhIGxpYnJlcsOtYSBjb250aWVuZSBkaXZlcnNhcyBmdW5jaW9uZXMgcXVlIHRyYWJhamFuIHNvYnJlIGVsIG9iamV0byByZXN1bHRhbnRlIGRlbCBhbsOhbGlzaXMgaW5pY2lhbCBkZSAqKk1DQSoqLCBxdWUgc2UgaXLDoW4gcmV2aXNhbmRvIGEgY29udGludWFjacOzbiB5IHF1ZSBzb246CgotICAgYGdldF9laWdlbnZhbHVlKClgOiBleHRyYWUgbG9zIGVpZ2VudmFsb3JlcyBvIHZhcmlhbnphcyByZXRlbmlkYXMgcG9yIGNhZGEgZGltZW5zaW9uIG8gZWplLgotICAgYGZ2aXpfZWlnKClgOiBwZXJtaXRlIHZpc3VhbGl6YXIgYSBsb3MgZWlnZW52YWxvcmVzIG8gdmFyaWFuemFzLgotICAgYGdldF9tY2FfaW5kKClgLCBgZ2V0X21jYV92YXIoKWA6IGV4dHJhZSBsb3MgcmVzdWx0YWRvcyB0YW50byBwYXJhIGluZGl2aWR1b3MgY29tbyBwYXJhIHZhcmlhYmxlcywgcmVzcGVjdGl2YW1lbnRlLgotICAgYGZ2aXpfbWNhX2luZCgpYCwgYGZ2aXpfbWNhX3ZhcigpYDogUGVybWl0ZSB2aXN1YWxpemFyIGxvcyByZXN1bHRhZG9zIHRhbnRvIHBhcmEgaW5kaXZpZHVvcyBvIHBhcmEgdmFyaWFibGVzLCByZXNwZWN0aXZhbWVudGUuCi0gICBgZnZpel9tY2FfYmlwbG90KClgOiBwZXJtaXRlIGdlbmVyYXIgdW4gKmJpcGxvdCogY29tYmluYW5kbyBmaWxhcyB5IGNvbHVtbmFzLgoKIyMgRWlnZW52YWxvcmVzIC8gdmFyaWFuemFzCgpTaWd1aWVuZG8gbGEgbMOzZ2ljYSBkZWwgYW7DoWxpc2lzIHF1ZSBleGlzdGUgZW4gZWwgKipBbsOhbGlzaXMgZGUgQ29tcG9uZW50ZXMgUHJpbmNpcGFsZXMqKiwgcXVlIHBlcm1pdGUgInJlZHVjaXIiIGxhcyBkaW1lbnNpb25lcyBkZSB1biBkYXRhIGZyYW1lIGEgcGFydGlyIGRlIGdlbmVyYXIgbnVldm9zIGVqZXMgbyBjb21wb25lbnRlcyBxdWUgc2lydmVuIGEgbWFuZXJhIGRlICJyZXN1bWVuIiBkZSBsYXMgdmFyaWFibGVzIGN1YW50aXRhdGl2YXMgb3JpZ2luYWxlcywgZW4gZWwgYW7DoWxpc2lzICoqTUNBKiogdGFtYmnDqW4gZXMgcG9zaWJsZSBjb25zdHJ1aXIgZGljaG9zIGNvbXBvbmVudGVzIG8gZWplcyBhIHBhcnRpciBkZSB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzLlwKClVuYSB2ZXogcXVlIHNlIGdlbmVyYW4gbG9zIG51ZXZvcyBjb21wb25lbnRlcywgZXMgaW1wb3J0YW50ZSBpZGVudGlmaWNhciBsYSBjYXBhY2lkYWQgZXhwbGljYXRpdmEgZGVsIHRvdGFsIGRlIGxvcyBjYXNvcyBxdWUgY2FkYSB1bmEgcHJvcG9yY2lvbmEuIFBhcmEgZWxsbyBlcyBpbXBvcnRhbnRlIHJldmlzYXIgbGEgcHJvcG9yY2nDs24gZGUgdmFyaWFuemFzIHF1ZSAicmV0aWVuZSIgY2FkYSB1bmEgZGUgZXN0YXMgZGltZW5zaW9uZXMgbyBlamVzLiBZIHB1ZWRlIHNlciBleHRyYcOtZG8gYSBwYXJ0aXIgZGUgbGEgZnVuY2nDs24gYGdldF9laWdlbnZhbHVlKClgIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6CgpgYGB7ciBlaWdlbnZhbHVlc30KZWlnX3ZhbCA8LSBmYWN0b2V4dHJhOjpnZXRfZWlnZW52YWx1ZShtY2FfbGIpCmhlYWQoZWlnX3ZhbCkKYGBgCgpFbiBsYSB0YWJsYSBhbnRlcmlvciBzZSBtdWVzdHJhbiBkZWwgbGFkbyBkZSBsYXMgY29sdW1uYXMgbG9zIGNvbXBvbmVudGVzIG8gZWplcyBudWV2b3MsIHJlc3VsdGFkb3MgZGVsIGFuw6FsaXNpcyAqKk1DQSoqLCBtaWVudHJhcyBxdWUgZW4gbGEgcHJpbWVyIGNvbHVtbmEgc2UgbXVlc3RyYW4gbG9zIGVpZ2VudmFsb3JlcyBvIGVsIHRhbWHDsW8gZGUgbGFzIHZhcmlhbnphcyBxdWUgZXhwbGljYSBjYWRhIHVubywgbWllbnRyYXMgcXVlIGVuIGxhIHNlZ3VuZGEgY29sdW1uYSBzZSBtdWVzdHJhIGVsIHBvcmNlbnRhamUgZGUgbGEgdmFyaWFuemEgdG90YWwgcXVlIGVzIGV4cGxpY2FkbyBwb3IgY2FkYSBlamUgbyBkaW1lbnNpw7NuLiBFbiBsYSB0ZXJjZXIgY29sdW1uYSBzZSBtdWVzdHJhIGVsIHBvcmNlbnRhamUgZGUgdmFyaWFuemEgYWN1bXVsYWRvLlwKClRhbWJpw6luIGVzIHBvc2libGUgdmlzdWFsaXphciBsb3MgcG9yY2VudGFqZXMgZGUgaW5lcmNpYSBleHBsaWNhZG9zIHBvciBjYWRhIGRpbWVuc2nDs24gKipNQ0EqKiwgYSBwYXJ0aXIgZGUgdXNhciBlbCBjb21hbmRvIGBmdml6X3NjcmVlcGxvdCgpYCwgY29uIGVsIHF1ZSBzZSBwdWVkZSBjcmVhciB1biAiKnNjcmVlIHBsb3QqLiIKCmBgYHtyIHNjcmVlX3Bsb3QsIGZpZy5jYXA9ICIqU2NyZWUgcGxvdCogbyBwb3JjZW50YWplcyBkZSBpbmVyY2lhIGV4cGxpY2FkYSBwb3IgY2FkYSBkaW1lbnNpw7NuIG51ZXZhLiJ9CmZ2aXpfc2NyZWVwbG90KG1jYV9sYiwgYWRkbGFiZWxzID0gVFJVRSkKYGBgCgpVbmEgZGUgbGFzIGNhcmFjdGVyw61zdGljYXMgcHJvcGlhcyBkZWwgKipNQ0EqKiByYWRpY2EgZW4gcXVlIGxvcyBjb21wb25lbnRlcywgZGltZW5zaW9uZXMgbyBmYWN0b3JlcyBjcmVhZG9zIG5vIG5lY2VzYXJpYW1lbnRlIHN1ZWxlbiBleHBsaWNhciBwb3JjZW50YWplcyBhbXBsaW9zIGRlIHZhcmlhbnphcyB0b3RhbGVzLiBbQGTDrWF6bW9ucm95MjAwOV1cCgojIyBCaXBsb3QgbyBncsOhZmljYSBkZSBpbmRpdmlkdW9zIHkgdmFyaWFibGVzCgpVbm8gZGUgbG9zIHJlc3VsdGFkb3MgbcOhcyBpbXBvcnRhbnRlcyBkZWwgYW7DoWxpc2lzICoqTUNBKiogY29uc2lzdGUgZW4gbGEgY3JlYWNpw7NuIGRlIHVuICIqYmlwbG90KiIsIG1lZGlhbnRlIGVsIHF1ZSBzZSBwdWVkZSBncmFmaWNhciB1bmEgbnViZSBkZSBwdW50b3MgZmlsYSAoJG4kIHB1bnRvcykgeSB1bmEgbnViZSBkZSBwdW50b3MgY29sdW1uYSAoJHAkIHB1bnRvcyksIGRvbmRlIGxhIHByaW1lcmEgc2UgY29ycmVzcG9uZGUgYSBsb3MgaW5kaXZpZHVvcyBvIGNhc29zLCBtaWVudHJhcyBxdWUgbGEgc2VndW5kYSBzZSByZWZpZXJlIGEgbGFzIHZhcmlhYmxlcyBjb250ZW5pZGFzIGVuIGxhIG1hdHJpeiBkZSBkYXRvcy5cCkEgcGFydGlyIGRlIGVzdGEgZ3JhZmljYWNpw7NuLCBlbCAqKk1DQSoqICJwb25lIGVuIGV2aWRlbmNpYSBhIGxvcyBpbmRpdmlkdW9zIGNvbiBwZXJmaWxlcyBzZW1lamFudGVzIHJlc3BlY3RvIGEgbG9zIGF0cmlidXRvcyBzZWxlY2Npb25hZG9zIHBhcmEgc3UgZGVzY3JpcGNpw7NuLiIgW0Bkw61hem1vbnJveTIwMDksIHAuIDEyM11cCgpQYXJhIGNyZWFyIGRpY2hvICJiaXBsb3QiIHNlIHV0aWxpemEgZWwgY29tYW5kbyBgZnZpel9tY2FfYmlwbG90KClgLCBxdWUgZXMgcGFydGUgZGUgbGEgcGFxdWV0ZXLDrWEgYGZhY3RvZXh0cmFgLCB5IHF1ZSBzZSBhcG95YSBlbiBsYSBwYXF1ZXRlcsOtYSBgZ2dwbG90MmAsIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6CgpgYGB7ciBiaXBsb3QsIGZpZy5jYXA9IiBCaXBsb3QgbyBncsOhZmljYSBjb24gbGEgcHJveWVjY2nDs24gZGUgaW5kaXZpZHVvcyB5IHZhcmlhYmxlcy4ifQpmdml6X21jYV9iaXBsb3QobWNhX2xiLCAjIHJlc3VsdGFkb3MgZGVsIGFuw6FsaXNpcyBNQ0EKICAgICAgICAgICAgICAgcmVwZWwgPSBUUlVFLCAjIGV2aXRhciBsYSBzdXBlcnBvc2ljacOzbiBkZSBldGlxdWV0YXMgZW4gbGEgZ3LDoWZpY2EKICAgICAgICAgICAgICAgYWxwaGEuaW5kID0gMC4xLCAjIG5pdmVsIGRlIHRyYW5zcGFyZW5jaWEgZGUgbG9zIHB1bnRvcyBmaWxhcyBvIGNhc29zCiAgICAgICAgICAgICAgIGFscGhhLnZhciA9IDEsICMgbml2ZWwgZGUgdHJhbnNwYXJlbmNpYSBkZSBsb3MgcHVudG9zIGNvbHVtYSBvIHZhcmlhYmxlcwogICAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSAiZ2dyZXBlbC5tYXgub3ZlcmxhcHMiLAogICAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpKSAjIHBsYW50aWxsYSBkZSBlc3RpbG8gcGFyYSBsYSBncsOhZmljYQpgYGAKCkxhIGdyw6FmaWNhIG11ZXN0cmEgZWwgcGF0csOzbiBnbG9iYWwgZGUgZGlzdHJpYnVjacOzbiBkZSBsYXMgcHJveWVjY2lvbmVzIHRhbnRvIGRlIGxvcyBjYXNvcyBvIGluZGl2aWR1b3MsIGFzw60gY29tbyBkZSBsYXMgdmFyaWFibGVzIHNvYnJlIGNhZGEgdW5vIGRlIGxvcyBlamVzIG8gZGltZW5zaW9uZXMgY3JlYWRhcy4gTG9zIGNhc29zIHNlIHJlcHJlc2VudGFuIGEgcGFydGlyIGRlIGxvcyBwdW50b3MgYXp1bGVzIG1pZW50cmFzIHF1ZSBsYXMgdmFyaWFibGVzIGxvIGhhY2VuIGEgcGFydGlyIGRlIGxvcyB0cmnDoW5ndWxvcyBlbiBjb2xvciByb2pvLlwKCkEgcGFydGlyIGRlIGVzdGEgcmVwcmVzZW50YWNpw7NuIGdyw6FmaWNhIHNlIG11ZXN0cmEgbGEgYXNvY2lhY2nDs24gZW50cmUgdmFyaWFibGVzIGNhdGVnw7NyaWNhcywgdGFudG8gZW50cmUgc8OtIGNvbW8gY29uIHJlc3BlY3RvIGEgbG9zIGluZGl2aWR1b3MuXAoKTGEgZGlzdGFuY2lhIGVudHJlIGNhZGEgcHVudG8gY29ycmVzcG9uZGllbnRlIHRhbnRvIGEgbG9zIGluZGl2aWR1b3MgY29tbyBlbnRyZSBsYXMgY29sdW1uYXMgb2ZyZWNlIHVuYSBmb3JtYSBkZSBtZWRpY2nDs24gZGUgc3Ugc2ltaWxhcmlkYWQsIHB1ZXN0byBxdWUgImxhIGNlcmNhbsOtYSBlbnRyZSBpbmRpdmlkdW9zIGVuIHTDqXJtaW5vcyBkZSBzZW1lamFuemFzOyBlcyBkZWNpciwgZG9zIGluZGl2aWR1b3Mgc29uIHNlbWVqYW50ZXMgc2kgaGFuIHNlbGVjY2lvbmFkbyBnbG9iYWxtZW50ZSBsYXMgbWlzbWFzIG1vZGFsaWRhZGVzLiBMYSBwcm94aW1pZGFkIGVudHJlIG1vZGFsaWRhZGVzIGRlIHZhcmlhYmxlcyBkaWZlcmVudGVzIGVuIHTDqXJtaW5vcyBkZSBhc29jaWFjacOzbiwgKC4uLikgeSBzb24gcHLDs3hpbWFzIHBvcnF1ZSBlc3TDoW4gbGlnYWRhcyBhIGxvcyBtaXNtb3MgaW5kaXZpZHVvcyBvIGluZGl2aWR1b3MgcGFyZWNpZG9zLiIgW0Bkw61hem1vbnJveTIwMDksIHAuIDEyM10KCiMjIERlc2NyaXBjacOzbiBkZSBsYXMgZGltZW5zaW9uZXMKCkZpbmFsbWVudGUsIGVuIGVzdGUgYW7DoWxpc2lzIGdlbmVyYWwgZGUgbGFzIGNvcnJlc3BvbmRlbmNpYXMgZW50cmUgaW5kaXZpZHVvcyB5IGNhdGVnb3LDrWFzIGRlIHZhcmlhYmxlcyBlbiBsYSBjb25zdHJ1Y2Npw7NuIGRlIGxhcyBkaW1lbnNpb25lcyBvIGVqZXMgZGUgcmVzw7ptZW5lcywgdGFtYmnDqW4gZXMgcG9zaWJsZSBpZGVudGlmaWNhciBsb3Mgbml2ZWxlcyBkZSBjb3JyZWxhY2nDs24gZGUgbGFzIHZhcmlhYmxlcyB5IHN1cyBjYXRlZ29yw61hcyBjb24gY2FkYSB1bmEgZGUgbGFzIGRpbWVuc2lvbmVzLiBFc3RvIG9mcmVjZSBpbmZvcm1hY2nDs24gcGFyYSBpZGVudGlmaWNhciBjdcOhbGVzIHNvbiBsYXMgY29sdW1uYXMgcXVlIGVqZXJjZW4gbWF5b3IgaW5mbHVlbmNpYSBzb2JyZSBjYWRhIGRpbWVuc2nDs24uXAoKUGFyYSByZWFsaXphciBlc3RlIGFuw6FsaXNpcyBkZSBjb3JyZWxhY2lvbmVzIHNlIHV0aWxpemEgZWwgY29tYW5kbyBgZGltZGVzKClgLCBxdWUgZXMgcGFydGUgZGUgbGEgbGlicmVyw61hIGBGYWN0b01pbmVSYC4KCmBgYHtyIGRlc2NyaXBfZGltc30KcmVzLmRlc2MgPC0gZGltZGVzYyhtY2FfbGIsICNvYmpldG8gdGlwbyBsaXN0YSBxdWUgY29udGllbmUgbG9zIHJlc3VsdGFkb3MgbWNhCiAgICAgICAgICAgICAgICAgICAgYXhlcyA9IGMoMSwyKSAjZGVmaW5pY2nDs24gZGUgbG9zIGVqZXMgbyBkaW1lbnNpb25lcyBhIGRlc2NyaWJpcgogICAgICAgICAgICAgICAgICAgICkKYGBgCgpDb24gZXN0byBzZSBjcmVhIHVuIG9iamV0byB0aXBvICJsaXN0YSIgcXVlIGNvbnRpZW5lIGxvcyB2YWxvcmVzIGRlIGNvcnJlbGFjacOzbiBkZSBsYXMgdmFyaWFibGVzIGNvbiBsYXMgZGltZW5zaW9uZXMgc29saWNpdGFkYXMuIFBvc3Rlcmlvcm1lbnRlIHNlIGRlYmVuIGV4dHJhZXIgbG9zIHZhbG9yZXMgZGUgY29ycmVsYWNpw7NuLCBxdWUgc2Vyw6FuIHByZXNlbnRhZG9zIGVuIGRvcyB0YWJsYXMgcGFyYSBjYWRhIGRpbWVuc2nDs246IHVuYSBzb2JyZSBsYSBjdWFsaWRhZCBkZSBjYWRhIHZhcmlhYmxlIG1lZGlkYSBjb24gZWwgY29lZmljaWVudGUgZGUgZGV0ZXJtaW5hY2nDs24gKCRSXjIkKSB5IHN1ICpwLXZhbHVlKiBhc29jaWFkbywgeSBvdHJhIHF1ZSBjb250aWVuZSBhIGxvcyB2YWxvcmVzIGVzdGltYWRvcyAoY29ycmVsYWNpw7NuKSBwYXJhIGNhZGEgY2F0ZWdvcsOtYSBkZSBsYXMgdmFyaWFibGVzIHkgZWwgKnAtdmFsdWUqIHBhcmEgY2FkYSB1bmEgZGUgZWxsYXMuXAoKRW4gZWwgY2FzbyBkZSBsYSBkaW1lbnNpw7NuIDEsIHNlIG1hbmRhIGEgbGxhbWFyOgoKYGBge3IgZGVzY3JpcF9kaW0xfQpyZXMuZGVzY1tbMV1dCmBgYAoKRW4gZWwgY2FzbyBkZSBsYSBkaW1lbnNpw7NuIDIsIHNlIG1hbmRhIGEgbGxhbWFyOgoKYGBge3J9CnJlcy5kZXNjW1syXV0KYGBgCgojIEFuw6FsaXNpcyBzb2JyZSBsYXMgdmFyaWFibGVzIChjb2x1bW5hcykKCkFsIGF2YW56YXIgZW4gZWwgYW7DoWxpc2lzIGRlIGxvcyByZXN1bHRhZG9zIGRlbCAqKk1DQSoqLCB0YW1iacOpbiBlcyBwb3NpYmxlIHJlYWxpemFyIGxhIHJldmlzacOzbiBkZSBsb3MgcmVzdWx0YWRvcyBkZSBtYW5lcmEgc2VwYXJhZGEsIHlhIHNlYSBxdWUgc2UgcmV2aXNlLCBwb3IgdW4gbGFkbywgZWwgY29tcG9ydGFtaWVudG8gZGUgbGFzIHZhcmlhYmxlcyB5LCBwb3IgZWwgb3RybywgZGUgbG9zIGNhc29zIG8gaW5kaXZpZHVvcy5cCgpBIGNvbnRpbnVhY2nDs24gc2UgcmVhbGl6YSBlbCBhbsOhbGlzaXMgcG9yIGxhIHJldmlzacOzbiBkZWwgY29tcG9ydGFtaWVudG8gZGUgbGFzIHZhcmlhYmxlcyBvIGNvbHVtbmFzIGRlbCBgZGF0YS5mcmFtZSgpYC4gRW4gdW4gcHJpbWVyIG1vbWVudG8gc2UgdXRpbGl6YSBlbCBjb21hbmRvIGBnZXRfbWNhX3ZhcigpYCwgcXVlIHBlcm1pdGUgZXh0cmFlciBsb3MgcmVzdWx0YWRvcyBwYXJhIGxhcyBjYXRlZ29yw61hcyBkZSBsYXMgdmFyaWFibGVzIGFjdGl2YXMuXAoKRXN0YSBmdW5jacOzbiBhcnJvamEgdW5hIGxpc3RhIHF1ZSBjb250aWVuZSBhIGxhcyBjb29yZGluYWRhcyBkZSBsYXMgY2F0ZWdvcsOtYXMgZGUgbGFzIHZhcmlhYmxlcyBwYXJhIGNhZGEgdW5vIGRlIGxvcyBmYWN0b3JlcyBvIGRpbWVuc2lvbmVzLCBhc8OtIGNvbW8gbG9zIHZhbG9yZXMgZGUgbG9zIGNvc2Vub3MgZWxldmFkb3MgYWwgY3VhZHJhZG8geSBsYSBjb250cmlidWNpw7NuIGRlIGxhcyBjYXRlZ29yw61hcyBzb2JyZSBsb3MgZmFjdG9yZXMgbyBkaW1lbnNpb25lcy5cCgpgYGB7ciBub21icmVzX3ZhcnNfbWNhfQp2YXJpYWJsZXMgPC0gZ2V0X21jYV92YXIobWNhX2xiKQp2YXJpYWJsZXMKYGBgCgpZIHRhbWJpw6luIHNlIHB1ZWRlIGFjY2VkZXIgYSBsb3MgdmFsb3JlcyBwYXJhIGNhZGEgdW5vIGRlIGxvcyBlbGVtZW50b3MgZGUgZGljaGEgbGlzdGEsIHBhcmEgbG8gcXVlIHNlIG11ZXN0cmEgdW4gdmlzdGF6byBhIGNvbnRpbnVhY2nDs246CgpgYGB7ciBoZWFkX3ZhcnN9CiMgQ29vcmRlbmFkYXMKaGVhZCh2YXJpYWJsZXMgJCBjb29yZCkKIyBjb3Nlbm9zIGN1YWRyYWRvczogY2FsaWRhZCBlbiBlbCBtYXBhIGRlIGZhY3RvcmVzCmhlYWQodmFyaWFibGVzICQgY29zMikKIyBDb250cmlidWNpw7NuIGVuIGxvcyBmYWN0b3JlcyBvIGRpbWVuc2lvbmVzCmhlYWQodmFyaWFibGVzICQgY29udHJpYikKYGBgCgojIyBDb3JyZWxhY2lvbmVzIGVudHJlIHZhcmlhYmxlcyB5IGxvcyBmYWN0b3JlcyBjcmVhZG9zCgpBIHBhcnRpciBkZSBsb3MgcmVzdWx0YWRvcyBkZWwgYW7DoWxpc2lzICoqTUNBKiogc2UgcHVlZGUgZXZhbHVhciBncsOhZmljYW1lbnRlIGxhIGFzb2NpYWNpw7NuIGV4aXN0ZW50ZSBlbnRyZSBjYWRhIHVuYSBkZSBsYXMgdmFyaWFibGVzIGNvbiByZXNwZWN0byBhIGxhcyBkaW1lbnNpb25lcyBvIGZhY3RvcmVzLiBQYXJhIGVsbG8gc2UgdXRpbGl6YSBgZnZpel9tY2FfdmFyKClgLCBkZW50cm8gZGVsIHF1ZSBzZSB1dGlsaXphIGVsIGFyZ3VtZW50byBgY2hvaWNlID0gIm1jYS5jb3IiYCwgZGUgbGEgc2lndWllbnRlIG1hbmVyYToKCmBgYHtyIGNvcnJlbF92YXJzX2RpbXMsIGZpZy5jYXA9IkJpcGxvdCBkZSBjb3JyZWxhY2lvbmVzIGVudHJlIHZhcmlhYmxlcyB5IGRpbWVuc2lvbmVzLiJ9CmZ2aXpfbWNhX3ZhcihtY2FfbGIsICMgb2JqZXRvIGxpc3RhIGRlIHJlc3VsdGFkb3MgbWNhCiAgICAgICAgICAgICBjaG9pY2UgPSAibWNhLmNvciIsICMgdGlwbyBkZSBhbsOhbGlzaXMgc29saWNpdGFkbzogY29ycmVsYWNpb25lcwogICAgICAgICAgICByZXBlbCA9IFRSVUUsICMgZXZpdGFyIGxhIHN1cGVycG9zaWNpw7NuIGRlIGV0aXF1ZXRhcwogICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpCiAgICAgICAgICAgICkKYGBgCgpMYSBncsOhZmljYSBwZXJtaXRlIGlkZW50aWZpY2FyIGxhcyB2YXJpYWJsZXMgcXVlIGVzdMOhIG3DoXMgY29ycmVsYWNpb25hZGFzIGNvbiBjYWRhIHVuYSBkZSBsYXMgZGltZW5zaW9uZXMgbyBmYWN0b3JlcyBjcmVhZG9zLiBMYXMgY29vcmRlbmFkYXMgbyBkaXN0YW5jaWFzIGNhbGN1bGFkYXMgY29ycmVzcG9uZGVuIGFsIHZhbG9yIGRlIGxhcyBjb3JyZWxhY2lvbmVzIGN1YWRyw6F0aWNhcyBlbnRyZSBsYXMgdmFyaWFibGVzIHkgbGFzIGRpbWVuc2lvbmVzLlwKCkVuIGxhIGdyw6FmaWNhIHNlIHB1ZWRlIG9ic2VydmFyIHF1ZSBsYXMgdmFyaWFibGVzIGB2b3RvX2dvYmAgeSBgYXByb2JfZ29iYCBzb24gbGFzIG3DoXMgY29ycmVsYWNpb25hZGFzIGNvbiBsYSBkaW1lbnNpw7NuIDEsIG1pZW50cmFzIHF1ZSBgb3BfZXVhYCB5IGB1YmljX2lkZW9sYCBlc3TDoW4gbcOhcyBhc29jaWFkYXMgY29uIGxhIGRpbWVuc2nDs24gMi5cCgojIyBDb29yZGVuYWRhcyBwYXJhIGxhcyBjYXRlZ29yw61hcyBkZSBsYXMgdmFyaWFibGVzIGFjdGl2YXMKClNpIGJpZW4gbGEgZ3LDoWZpY2EgYW50ZXJpb3IgbXVlc3RyYSBsYSBjb3JyZWxhY2nDs24gZGUgY2FkYSB1bmEgZGUgbGFzIHZhcmlhYmxlcyBjb24gcmVzcGVjdG8gYSBsYXMgZGltZW5zaW9uZXMsIGFsbMOtIG5vIHNlIHB1ZWRlIGRpc3Rpbmd1aXIgbGEgcHJlc2VuY2lhIGRlIGxhcyBjYXRlZ29yw61hcyBkZSByZXNwdWVzdGFzIGVuIGVsIG1pc21vIHBsYW5vIGNhcnRlc2lhbm8uXAoKUGFyYSBlbGxvLCBlcyBpbXBvcnRhbnRlIHRyYWJhamFyIGNvbiBlbCB2YWxvciBkZSBsYXMgY29vcmRlbmFkYXMgZGUgY2FkYSBjYXRlZ29yw61hLCBxdWUgc2UgY2FsY3Vsw7MgYW50ZXJpb3JtZW50ZSwgeSBxdWUgc2UgcHVlZGUgcmV2aXNhciBjb24gZWwgY29tYW5kbyBgKHZhcmlhYmxlICQgY29vcmQpYC4gQSBwYXJ0aXIgZGVsIGNvbWFuZG8gYGZ2aXpfbWNhX3ZhcigpYCBzZSBwdWVkZSByZWFsaXphciBkaWNoYSByZXZpc2nDs24gZ3LDoWZpY2EgcGFyYSBldmFsdWFyIHZpc3VhbG1lbnRlIGxhIGFzb2NpYWNpw7NuIGVudHJlIGNhZGEgY2F0ZWdvcsOtYSB5IGxhcyBkaW1lbnNpb25lcyBvIGZhY3RvcmVzIGNyZWFkb3MuXAoKYGBge3IgY29ycmVsX2NhdGVnc19kaW1zLCBmaWcuY2FwPSJCaXBsb3QgZGUgYXNvY2lhY2nDs24gZW50cmUgY2F0ZWdvcsOtYXMgeSBkaW1lbnNpb25lcyJ9CmZ2aXpfbWNhX3ZhcihtY2FfbGIsICNvYmpldG8gbGlzdGEgY29uIHJlc3VsdGFkb3MgbWNhIAogICAgICAgICAgICAgcmVwZWwgPSBUUlVFLCAjIGV2aXRhciBlbCB0cmFzbGFwZSBkZSBldGlxdWV0YXMKICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCksCiAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSAiZ2dyZXBlbC5tYXgub3ZlcmxhcHMiCiAgICAgICAgICAgICApCmBgYAoKQWwgZ3LDoWZpY28gYW50ZXJpb3Igc2UgbGUgcHVlZGVuIHJlYWxpemFyIGFsZ3VuYXMgbW9kaWZpY2FjaW9uZXMsIGNvbW8gY2FtYmlhcmxlIGVsIGNvbG9yIHkgbGFzIGZvcm1hcyBwYXJhIHJlcHJlc2VudGFyIGEgbGFzIGNhdGVnb3LDrWFzLCBwYXJhIGVsbG8gc2UgdXNhbiBsb3MgYXJndW1lbnRvcyBgY29sLnZhcj1gIHkgYHNoYXBlLnZhcj1gIGRlbnRybyBkZWwgY29tYW5kbyBgZnZpel9tY2FfdmFyKClgLgoKYGBge3IgY29ycmVsX2NhdGVnc19kaW1fY29sLCBmaWcuY2FwPSJCaXBsb3QgZGUgYXNvY2lhY2nDs24gZW50cmUgY2F0ZWdvcsOtYXMgeSBkaW1lbnNpb25lcyB5IGNhbWJpbyBkZSBjb2xvcmVzLiJ9CmZ2aXpfbWNhX3ZhcihtY2FfbGIsICNvYmpldG8gbGlzdGEgY29uIHJlc3VsdGFkb3MgbWNhIAogICAgICAgICAgICAgcmVwZWwgPSBUUlVFLCAjIGV2aXRhciBlbCB0cmFzbGFwZSBkZSBldGlxdWV0YXMKICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCksCiAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSAiZ2dyZXBlbC5tYXgub3ZlcmxhcHMiLCAjYW1wbGlhciBlbCBzb2xhcGFtaWVudG8gZG9uZGUgb2N1cnJhCiAgICAgICAgICAgICBjb2wudmFyPSJibGFjayIsICMgY2FtYmlhciBlbCBjb2xvciBhIGxhcyB2YXJpYWJsZXMKICAgICAgICAgICAgIHNoYXBlLnZhciA9IDE1ICMgY2FtYmlhciBsYSBmb3JtYSBkZSByZXByZXNlbnRhY2nDs24gZGUgdmFyaWFibGVzCiAgICAgICAgICAgICApCmBgYAoKTGEgZ3LDoWZpY2EgbXVlc3RyYSBsYXMgcmVsYWNpb25lcyBlbnRyZSBjYXRlZ29yw61hcyBkZSBsYXMgdmFyaWFibGVzLCBjb24gYWp1c3RlcyBlbiBsYXMgZm9ybWFzIHkgY29sb3IgZGUgcmVwcmVzZW50YWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMuXAoKRGljaGEgZ3LDoWZpY2Egc2UgcHVlZGUgaW50ZXJwcmV0YXIgZGUgbGEgc2lndWllbnRlIG1hbmVyYToKCi0gICBMYXMgY2F0ZWdvcsOtYXMgY29uIHBlcmZpbGVzIHNlbWVqYW50ZXMgbXVlc3RyYW4gYWdydXBhZGFzIG8gY2VyY2FuYXMgZW50cmUgc8OtLgotICAgTGFzIHZhcmlhYmxlcyBxdWUgZXN0w6luIGNvcnJlbGFjaW9uYWRhcyBkZSBtYW5lcmEgbmVnYXRpdmEgZW50cmUgc8OtIGVzdGFyw6FuIHBvc2ljaW9uYWRhcyBlbiBwb2xvcyBvcHVlc3RvcyByZXNwZWN0byBhbCBvcmlnZW4gZGUgbGEgZ3LDoWZpY2EgKGN1YWRyYW50ZXMgb3B1ZXN0b3MpLgotICAgTGEgZGlzdGFuY2lhIHF1ZSBleGlzdGEgZW50cmUgY2FkYSBwdW50byBjb3JyZXNwb25kaWVudGUgYSB1bmEgY2F0ZWdvcsOtYSB5IGVsIG9yaWdlbiwgZGVmaW5lIGxhIGN1YWxpZGFkIGRlIGxhIGNhdGVnb3LDrWEgZW4gZWwgbWFwYSAqQmlwbG90Ki4gTG9zIHB1bnRvcyBkZSBjYXRlZ29yw61hcyBxdWUgc2UgZW5jdWVudHJlbiBhbGVqYWRvcyBkZWwgcHVudG8gZGUgb3JpZ2VuIHRpZW5kZW4gYSBlc3RhciBtZWpvciByZXByZXNlbnRhZGFzIGVuIGxhIGdyw6FmaWNhLgoKIyMgQ2FsaWRhZCBkZSBsYSByZXByZXNlbnRhY2nDs24gZGUgbGFzIGNhdGVnb3LDrWFzCgpFbiBsYSBncsOhZmljYSAqYmlwbG90KiBjcmVhZGEgYSBwYXJ0aXIgZGUgbG9zIGRvcyBwcmltZXJvcyBmYWN0b3JlcyBvIGRpbWVuc2lvbmVzLCBzZSBpZGVudGlmaWPDsyBxdWUgZWwgcHJpbWVybyBleHBsaWNhIDguMSUgZGUgbGEgdmFyaWFuemEsIG1pZW50cmFzIHF1ZSBlbCBzZWd1bmRvIGV4cGxpY2EgNS4zJS4gRW50cmUgYW1ib3MgYWJhcmNhbiBzb2xvIGVsIDEzLjQlIGRlbCBjb21wb3J0YW1pZW50byBkZSBsb3MgZGF0b3MgYWN0aXZvcyBpbmNsdWlkb3MgZW4gZWwgYW7DoWxpc2lzLlwKCkRlYmlkbyBhIHF1ZSBsb3MgZmFjdG9yZXMgbyBkaW1lbnNpb25lcyBjcmVhZGFzIHRpZW5kZW4gYSByZXByZXNlbnRhciBiYWpvcyBuaXZlbGVzIGRlIHZhcmlhbnphIGRlIGxhIG1hdHJpeiBkZSBkYXRvcywgcHVlZGUgb2N1cnJpciBxdWUgbm8gdG9kb3MgbG9zIHB1bnRvcyBlc3TDqW4gaWd1YWxtZW50ZSBwcm95ZWN0YWRvcyBlbiBsYSBncsOhZmljYSAqYmlwbG90KlwKCkFudGUgZXN0YSBzaXR1YWNpw7NuLCBlcyBpbXBvcnRhbnRlIHJldmlzYXIgbGEgY2FsaWRhZCBkZSBsYSByZXByZXNlbnRhY2nDs24gZGUgbG9zIHB1bnRvcyBlbiBsYSBncsOhZmljYSwgcGFyYSBsbyBxdWUgZXMgw7p0aWwgbGEgbWVkaWRhIGRlIGxvcyBjb3Nlbm9zIGN1YWRyw6F0aWNvcyAoY29zXF4yKSwgbGEgcXVlIG1pZGUgZWwgZ3JhZG8gZGUgYXNvY2lhY2nDs24gZW50cmUgbGFzIGNhdGVnb3LDrWFzIGRlIGNhZGEgdmFyaWFibGUgeSB1biBlamUgbyBkaW1lbnNpw7NuIGVuIHBhcnRpY3VsYXIuCgpFbCBjb3Nlbm8gY3VhZHLDoXRpY28gKGNvczIpIGRlIGNhZGEgY2F0ZWdvcsOtYSBzZSBwdWVkZSBleHRyYWVyIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6CgpgYGB7ciBjb3Nlbm9zX2N1YV92YXJzfQpoZWFkKHJvdW5kKHZhcmlhYmxlcyAkIGNvczIsIDMpLCA1KQpgYGAKClNpIGxhIGNhdGVnb3LDrWEgZGUgdW5hIHZhcmlhYmxlIGVzdMOhIGJpZW4gcmVwcmVzZW50YWRhIHBvciBhbWJhcyBkaW1lbnNpb25lcyBvIGZhY3RvcmVzLCBsYSBzdW1hIGRlIGxvcyBjb3Nlbm9zIGN1YWRyw6F0aWNvcyB0ZW5kcsOhIHVuIHZhbG9yIGNlcmNhbm8gYSAxLiBQYXJhIGFsZ3Vub3MgY2Fzb3MgZW4gbGFzIGZpbGFzLCBzZSBuZWNlc2l0YXLDoW4gbcOhcyBkZSBkb3MgZGltZW5zaW9uZXMgcGFyYSByZXByZXNlbnRhciBwZXJmZWN0YW1lbnRlIGEgbG9zIGRhdG9zLlwKCkxhIG1hbmVyYSBkZSByZXZpc2FyIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIHZhbG9yZXMgZGUgbGEgY2FsaWRhZCBkZSByZXByZXNlbnRhY2nDs24gZGUgbGFzIGNhdGVnb3LDrWFzIGVzIG1lZGlhbnRlIHVuYSBncsOhZmljYSBkZSBiYXJyYXMgYSBwYXJ0aXIgZGUgbGEgdmFyaWFibGUgYCRjb3MyYCBkZW50cm8gZGVsIGNvbWFuZG8gYGZ2aXpfY29zMigpYC4KCmBgYHtyIGdyYWZfYmFyX2NvczJ9CmZ2aXpfY29zMihtY2FfbGIsICNvYmpldG8gdGlwbyBsaXN0YSBjb24gcmVzdWx0YWRvcyBtY2EgCiAgICAgICAgICBjaG9pY2UgPSAidmFyIiwgIyBzZWxlY2Npw7NuIGRlIGxhcyB2YXJpYW56YXMKICAgICAgICAgIGF4ZXMgPSAxOjIpICMgZWplcyBvIGRpbWVuc2lvbmVzIGNvbnNpZGVyYXIgZW4gbGEgZ3LDoWZpY2EKYGBgCgpBIHBhcnRpciBkZSBlc3RhIGdyw6FmaWNhIHNlIHB1ZWRlIGlkZW50aWZpY2FyIHF1ZSBsYXMgcHJpbWVyYXMgY2luY28gY2F0ZWdvcsOtYXMgY29uIG1heW9yZXMgdmFsb3JlcyBzb24gbGFzIHF1ZSBlc3TDoW4gbWVqb3IgcmVwcmVzZW50YWRhcyBlbiBsYSBncsOhZmljYSBkZSBkaXNwZXJzacOzbiwgZXN0YXMgc2UgdWJpY2FuIGRlbnRybyBkZSBsYXMgdmFyaWFibGVzIGRlICJhcHJvYmFjacOzbiBkZWwgZ29iaWVybm8gZW4gdHVybm8iIHkgImNvbmZpYW56YSBlbiBlbCBnb2JpZXJubyBlbiB0dXJubyIsIG1pZW50cmFzIHF1ZSBsYXMgcXVlIGVzdMOhbiBwb3IgZGViYWpvIGRlbCB2YWxvciBkZSAwLjIgbm8gbmVjZXNhcmlhbWVudGUgY3VlbnRhbiBjb24gcHJveWVjY2lvbmVzIGFkZWN1YWRhcyBlbiBsYSBncsOhZmljYSBnZW5lcmFkYSBhIHBhcnRpciBzb2xvIGRlIGxhcyBkaW1lbnNpb25lcyAxIHkgMi4gUG9yIGVsbG8sIGxhIGludGVycHJldGFjacOzbiBkZSBlc3RhcyDDumx0aW1hcyBjYXRlZ29yw61hcyBzZSBkZWJlIHJlYWxpemFyIGNvbiBjdWlkYWRvICh0YWwgdmV6IHNlYSBuZWNlc2FyaWEgdW5hIHNvbHVjacOzbiBxdWUgaW5jbHV5YSBhIHVuYSBtYXlvciBjYW50aWRhZCBkZSBkaW1lbnNpb25lcykuCgpVbmEgbWFuZXJhIGFkaWNpb25hbCBkZSByZXByZXNlbnRhciBsYSBjYWxpZGFkIGRlIGxhcyBjYXRlZ29yw61hcyBlbiBlbCBncsOhZmljbyAqYmlwbG90KiBlcyBhIHBhcnRpciBkZSBhanVzdGFyIGxvcyBjb2xvcmVzIHBhcmEgY2FkYSBwdW50byBwcm95ZWN0YWRvLCB5IHRvbWFuZG8gY29tbyBjcml0ZXJpbyBlbCB2YWxvciBkZWwgY29zZW5vIGN1YWRyw6F0aWNvIChjb3MyKS4gUGFyYSBtb2RpZmljYXIgZWwgY29sb3IgZGUgbG9zIHB1bnRvcyBzZSB1dGlsaXphIGVsIGFyZ3VtZW50byBgY29sLnZhcj1gLCBjb24gZWwgcXVlIHNlIHByb2R1Y2VuIGNvbG9yZXMgZW4gZ3JhZGllbnRlcywgcXVlIHNlIHB1ZWRlbiBhanVzdGFyIGEgcGFydGlyIGRlbCBhcmd1bWVudG8gYGdyYWRpZW50LmNvbHM9YC4gUG9yIGVqZW1wbG8sIHNpIHNlIGFqdXN0cmEgXGBncmFkaWVudC5jb2xzID0gYygid2hpdGUiLCAiYmx1ZSIsIHJlZCIpLCBlc3RvIHNlIHRyYWR1Y2UgZW46CgotICAgY2F0ZWdvcsOtYXMgY29uIGJham8gdmFsb3IgZGUgY29zZW5vIGN1YWRyw6F0aWNvIHNlIGNvbG9yZWFyw6FuIGVuIGJsYW5jbyAoIndoaXRlIikuCi0gICBjYXRlZ29yw61hcyBjb24gdmFsb3JlcyBtZWRpb3MgZGUgY29zZW5vIGN1YWRyw6F0aWNvIHNlIGNvbG9yZWFyw6FuIGVuIGF6dWwgKCJibHVlIikuCi0gICBjYXRlZ29yw61hcyBjb24gdmFsb3JlcyBhbHRvIGRlIGNvc2XDsW8gY3VhZHLDoXRpY28gc2UgY29sb3JlYXLDoW4gZW4gInJvam8iICgicmVkIikuCgpEZSBtYW5lcmEgcXVlOgoKYGBge3IgY29ycmVsX3ZhcnNfY29sb3JlcywgZmlnLmNhcD0iQmlwbG90IGRlIGFzb2NpYWNpw7NuIGVudHJlIGNhdGVnb3LDrWFzIHkgZGltZW5zaW9uZXMgY29uIHNlw7FhbGl6YWNpw7NuIGRlIGxhIGNhbGlkYWQgZGUgcmVwcmVzZW50YWNpw7NuLiJ9CmZ2aXpfbWNhX3ZhcihtY2FfbGIsICNvYmpldG8gdGlwbyBsaXN0YSBjb24gcmVzdWx0YWRvcyBtY2EKICAgICAgICAgICAgIGNvbC52YXIgPSAiY29zMiIsICNkZWZpbmljacOzbiBkZSBsb3MgY29sb3JlcyBhIHBhcnRpciBkZWwgdmFsb3IgY29zMgogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksICNkZWZpbmljacOzbiBkZSBsYSBwYWxldGEgZGUgY29sb3JlcwogICAgICAgICAgICAgcmVwZWwgPSBUUlVFLCAjIGV2aXRhciBzb2xhcGFtaWVudG9zIGRlIGV0aXF1ZXRhcywKICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9ICJnZ3JlcGVsLm1heC5vdmVybGFwcyIsICNhdW1lbnRhciBlbCB0YW1hw7FvIGRlIHNvbGFwYW1pZW50b3MKICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCkKICAgICAgICAgICAgICkKYGBgCgpBZGljaW9uYWxtZW50ZSwgdGFtYmnDqW4gZXMgcG9zaWJsZSBjYW1iaWFyIGxhIGludGVuc2lkYWQgZGUgbGEgdHJhbnNwYXJlbmNpYSBkZSBsYXMgY2F0ZWdvcsOtYXMgZGUgdmFyaWFibGVzIHNlZ8O6biBlbCBjcml0ZXJpbyBkZSBsb3MgdmFsb3JlcyBkZSBsYSBjYWxpZGFkIGRlIHJlcHJlc2VudGFjacOzbiAoY29zMikgbWVkaWFudGUgZWwgYXJndW1lbnRvIGBhbHBoYS52YXIgPWAsIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6CgpgYGB7ciBjb3JyZWxfdmFyc190cmFuc3AsIGZpZy5jYXA9IkJpcGxvdCBkZSBhc29jaWFjacOzbiBlbnRyZSBjYXRlZ29yw61hcyB5IGRpbWVuc2lvbmVzIGNvbiB0cmFuc3BhcmVuY2lhIHNlZ8O6biBlbCBuaXZlbCBkZSBjYWxpZGFkLiJ9CmZ2aXpfbWNhX3ZhcihtY2FfbGIsIAogICAgICAgICAgICAgYWxwaGEudmFyPSJjb3MyIiwKICAgICAgICAgICAgIHJlcGVsID0gVFJVRSwKICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9ICJnZ3JlcGVsLm1heC5vdmVybGFwcyIsCiAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpCiAgICAgICAgICAgICApCmBgYAoKIyMgQ29udHJpYnVjacOzbiBkZSBsYXMgY2F0ZWdvcsOtYXMgc29icmUgbGFzIGRpbWVuc2lvbmVzIGNyZWFkYXMKCkZpbmFsbWVudGUsIGVzIGltcG9ydGFudGUgaWRlbnRpZmljYXIgY3XDoWxlcyBzb24gbGFzIGNhdGVnb3LDrWFzIChubyBzb2xvIGxhcyB2YXJpYWJsZXMgZW4gc8OtIG1pc21hcykgcXVlIGVqZXJjZW4gbWF5b3IgaW5mbHVlbmNpYSBzb2JyZSBlbCBjb21wb3J0YW1pZW50byBkZSBsYXMgZGltZW5zaW9uZXMgbyBmYWN0b3JlcyBjcmVhZG9zLiBQYXJhIGVsbG8gZXMgaW1wb3J0YW50ZSByZXZpc2FyIGxhIGNvbnRyaWJ1Y2nDs24gcG9yY2VudHVhbCBkZSBjYWRhIGNhdGVnb3LDrWEgZW4gbGEgZGVmaW5pY2nDs24gZGUgbG9zIGVqZXMgcmVjdXBlcmFkb3MgcGFyYSBlbCBhbsOhbGlzaXMuCgpVbmEgbWFuZXJhIGluaWNpYWwgcGFyYSByZXZpc2FyIGVsIHBvcmNlbnRhamUgZGUgY29udHJpYnVjacOzbiBkZSBjYWRhIGNhdGVnb3LDrWEgc29icmUgY2FkYSBkaW1lbnNpw7NuIHNlIGxvZ3JhIG1hbmRhbmRvIGEgbGxhbWFyIHVuYSB0YWJsYSBjb24gbG9zIHZhbG9yZXMgcG9yY2VudHVhbGVzIGRlIGNhZGEgY2F0ZWdvcsOtYSBtZWRpYW50ZSBlbCBhcmd1bWVudG8gYCRjb250cmliYAoKYGBge3IgdGFibGFfY29udHJpYnVfY2F0ZWd9CmhlYWQocm91bmQodmFyaWFibGVzICQgY29udHJpYiwgMikpCmBgYAoKRW4gZGljaGEgdGFibGEgc2Ugb2JzZXJ2YW4gZW4gZWwgbGFkbyBkZSBsYXMgZmlsYXMgYSBjYWRhIHVuYSBkZSBsYXMgY2F0ZWdvcsOtYXMgYWN0aXZhcyBpbmNsdWlkYXMgZW4gZWwgYW7DoWxpc2lzLCBtaWVudHJhcyBxdWUgZW4gbGFzIGNvbHVtbmFzIHNlIHViaWNhbiBjYWRhIHVuYSBkZSBsYXMgZGltZW5zaW9uZXMgY3JlYWRhcy5cCgpMYXMgY2F0ZWdvcsOtYXMgcXVlIG3DoXMgY29udHJpYnV5ZW4gYSBjYWRhIGRpbWVuc2nDs24gc2UgY29ycmVzcG9uZGVuIGNvbiBhcXVlbGxhcyBxdWUgcmVnaXN0cmFuIG1heW9yZXMgdmFsb3JlcyBwb3JjZW50dWFsZXMuIExhcyBjYXRlZ29yw61hcyBxdWUgY29udHJpYnV5ZW4gZW4gbWF5b3IgbWVkaWRhIHNvYnJlIGxhcyBkaW1lbnNpb25lcyAxIHkgMiBzb24gbGFzIHF1ZSwgYSBzdSB2ZXosIHRpZW5lbiBtYXlvciBpbmZsdWVuY2lhIGFsIGV4cGxpY2FyIGxhIHZhcmlhYmlsaWRhZCBkZSBsYSBtYXRyaXogZGUgZGF0b3MuXAoKR3LDoWZpY2FtZW50ZSBzZSBwdWVkZSByZXByZXNlbnRhciBsYSBjb250cmlidWNpw7NuIGRlIGNhZGEgY2F0ZWdvcsOtYSBzb2JyZSBjYWRhIGRpbWVuc2nDs24gbWVkaWFudGUgZWwgdXNvIGRlbCBjb21hbmRvIGBmdml6X2NvbnRyaWIoKWAsIGNvbiBsYSBxdWUgc2UgY3JlYSB1bmEgZ3LDoWZpY2EgZGUgYmFycmFzLgoKYGBge3IgZ3JhZl9jb250cmliX2NhdGVnLCBmaWcuY2FwPSJDb250cmlidWNpw7NuIGRlIGxhcyBjYXRlZ29yw61hcyBhIGxhcyBkaW1lbnNpb25lcyAxIHkgMi4ifQojIENvbnRyaWJ1Y2nDs24gZGUgbGFzIGNhdGVnb3LDrWFzIGEgbGEgZGltZW5zacOzbiAxLgpmdml6X2NvbnRyaWIobWNhX2xiLCAjb2JqZXRvIHRpcG8gbGlzdGEgY29uIHJlc3VsdGFkb3MgbWNhCiAgICAgICAgICAgICBjaG9pY2UgPSAidmFyIiwgI2NyaXRlcmlvIGEgcmVwcmVzZW50YXI6IHZhcmlhbnphCiAgICAgICAgICAgICBheGVzID0gMSwgIyBzZWxlY2Npw7NuIGRlbCBlamUgbyBkaW1lbnNpw7NuIGEgYW5hbGl6YXIgPSBlamUgMQogICAgICAgICAgICAgdG9wID0gMTUpICMgc2VsZWNjacOzbiBkZSBsYXMgMTUgY2F0ZWdvcsOtYXMgY29uIG1heW9yIGNvbnRyaWJ1acOzbgojIENvbnRyaWJ1Y2nDs24gZGUgbGFzIGNhdGVnb3LDrWFzIGEgbGEgZGltZW5zacOzbiAyLgpmdml6X2NvbnRyaWIobWNhX2xiLCAjb2JqZXRvIHRpcG8gbGlzdGEgY29uIHJlc3VsdGFkb3MgbWNhIAogICAgICAgICAgICAgY2hvaWNlID0gInZhciIsICNjcml0ZXJpbyBhIHJlcHJlc2VudGFyOiB2YXJpYW56YQogICAgICAgICAgICAgYXhlcyA9IDIsICMgc2VsZWNjacOzbiBkZWwgZWplIG8gZGltZW5zacOzbiBhIGFuYWxpemFyID0gZWplIDIKICAgICAgICAgICAgIHRvcCA9IDE1KSAjIHNlbGVjY2nDs24gZGUgbGFzIDE1IGNhdGVnb3LDrWFzIGNvbiBtYXlvciBjb250cmlidWNpw7NuCmBgYAoKRW4gZXN0YXMgZ3LDoWZpY2FzIHNlIGluY2x1ecOzIHVuYSBsw61uZWEgcm9qYSBwdW50ZWFkYSwgbGEgcXVlIHJlcHJlc2VudGEgZWwgdmFsb3IgcHJvbWVkaW8gZXNwZXJhZG8gZW4gZGFkbyBjYXNvIHF1ZSBsYXMgY29udHJpYnVjaW9uZXMgZGUgdG9kYXMgbGFzIGNhdGVnb3LDrWFzIGZ1ZXJhbiB1bmlmb3JtZXMuIERlIG1hbmVyYSBxdWUgYXF1ZWxsYXMgcXVlIGVzdMOhbiBwb3IgZW5jaW1hIGRlIGRpY2hhIHJlY3RhLCBzZSBpbnRlcnByZXRhIHF1ZSB0aWVuZW4gdW5hIGNvbnRyaWJ1Y2nDs24gaW1wb3J0YW50ZSBtaWVudHJhcyBxdWUgbGFzIHF1ZSBlc3TDoW4gcG9yIGRlYmFqbyBzZSBjb25zaWRlcmFuIGNvbiBwb2NhIGluZmx1ZW5jaWEgc29icmUgbGFzIGRpbWVuc2lvbmVzIG8gZmFjdG9yZXMuXAoKQSBwYXJ0aXIgZGUgbGFzIGdyw6FmaWNhcyBwcmV2aWFzIHNlIHB1ZWRlIGVzdGFibGVjZXIgbG8gc2lndWllbnRlOgoKLSAgIFNlIGlkZW50aWZpY2Fyb24gMTEgY2F0ZWdvcsOtYXMgcXVlIHRpZW5lbiBtYXlvciBjb250cmlidWNpw7NuIHF1ZSBlbCByZXN0byBzb2JyZSBsYSBkZWZpbmljacOzbiBkZSBsYSBkaW1lbnNpw7NuIDEsIGVzcGVjaWFsbWVudGUgbGFzIGNhdGVnb3LDrWFzIDEgeSA0IGRlIGxhIHZhcmlhYmxlICJjb25maWFuemEgZW4gZWwgZ29iaWVybm8iLCBsYXMgY2F0ZWdvcsOtYXMgMiB5IDEgZGUgbGEgdmFyaWFibGUgImFwcm9iYWNpw7NuIGRlbCBnb2JpZXJubyIsIGxhcyBjYXRlZ29yw61hcyA0IHkgMSBkZSBsYSB2YXJpYWJsZSAic2F0aXNmYWNjacOzbiBjb24gbGEgZGVtb2NyYWNpYSIsIGxhIGNhdGVnb3LDrWEgMiBkZSBsYSB2YXJpYWJsZSAidm90w7MgcG9yIGVsIGdvYmllcm5vIiB5IGxhIGNhdGVnb3LDrWEgNSBkZSBsYSB2YXJpYWJsZSAicGVyY2VwY2nDs24gZGUgbGEgc2l0dWFjacOzbiBkZSBsYSBlY29ub23DrWEiLgotICAgTGEgY2FudGlkYWQgZGUgY2F0ZWdvcsOtYXMgcXVlIGNvbnRyaWJ1eWVuIGEgbGEgZGltZW5zacOzbiAyIHBvciBhcnJpYmEgZGVsIHByb21lZGlvIGVzcGVyYWRvIGVzIG1heW9yIHF1ZSBlbiBsYSBwcmltZXIgZGltZW5zacOzbi4gWSBsYXMgNSBjYXRlZ29yw61hcyBxdWUgbcOhcyBpbmZsdXllbiBzb24gbGEgY2F0ZWdvcsOtYSAzIGRlIGxhIHZhcmlhYmxlICJzYXRpc2ZhY2Npw7NuIGNvbiBsYSBkZW1vY3JhY2lhIiwgbGEgY2F0ZWdvcsOtYSAzIGRlIGxhIHZhcmlhYmxlICJjb25maWFuemEgZW4gZWwgZ29iaWVybm8iLCBsYSBjYXRlZ29yw61hIDUgZGUgbGEgdmFyaWFibGUgInNpdHVhY2nDs24gZGUgbGEgZWNvbm9tw61hIiwgbGEgY2F0ZWdvcsOtYSAxIGRlIGxhIHZhcmlhYmxlICJpbnRlcsOpcyBlbiBsYSBwb2zDrXRpY2EiIHkgbGEgY2F0ZWdvcsOtYSAxIGRlIGxhIHZhcmlhYmxlICJjb25maWFuemEgZW4gZWwgZ29iaWVybm8uIgoKQSBzdSB2ZXosIHNlIHB1ZWRlIGNhbGN1bGFyIGxhIGNvbnRyaWJ1Y2nDs24gdG90YWwgZGUgY2FkYSBjYXRlZ29yw61hIGEgY2FkYSB1bmEgZGUgbGFzIGRpbWVuc2lvbmVzIGRlIGludGVyw6lzLCBxdWUgZW4gZXN0ZSBjYXNvIHNlIGxpbWl0YW4gYSBsb3MgZWplcyAxIHkgMi4gUGFyYSBlbGxvIHNlIHV0aWxpemEgZWwgbWlzbW8gY29tYW5kbywgc29sbyBzZSBhanVzdGEgZWwgYXJndW1lbnRvIHNvYnJlIGxvcyBlamVzIGEgc2VsZWNjaW9uYXIgYGF4ZXM9YC4KCmBgYHtyIGdyYWZfY29udHJpYl9jYXRlZ190b3QsIGZpZy5jYXA9IkNvbnRyaWJ1Y2nDs24gdG90YWwgZGUgbGFzIGNhdGVnb3LDrWFzIGEgbGFzIGRpbWVuc2lvbmVzIDEgeSAyLiJ9CiMgVG90YWwgY29udHJpYnV0aW9uIHRvIGRpbWVuc2lvbiAxIGFuZCAyCmZ2aXpfY29udHJpYihtY2FfbGIsICNvYmpldG8gdGlwbyBsaXN0YSBjb24gcmVzdWx0YWRvcyBtY2EKICAgICAgICAgICAgIGNob2ljZSA9ICJ2YXIiLCAjY3JpdGVyaW8gZGUgcmVwcmVzZW50YWNpw7NuID0gdmFyaWFuemFzCiAgICAgICAgICAgICBheGVzID0gMToyLCAjIGVqZXMgc2VsZWNjaW9uYWRvcyBlbiBsYSByZXByZXNlbnRhY2nDs24gPSBlamVzIDEgeSAyIHNpbXVsdMOhbmVvcwogICAgICAgICAgICAgdG9wID0gMjApICNzZWxlY2Npw7NuIGRlIGxhcyAyMCBjYXRlZ29yw61hcyBjb24gbWF5b3IgY29udHJpYnVjacOzbgpgYGAKCkVuIGVzdGEgZ3LDoWZpY2Egc2UgaWRlbnRpZmljYXJvbiAxNSBjYXRlZ29yw61hcyBxdWUgZWplcmNlbiBtYXlvciBpbmZsdWVuY2lhIHF1ZSBlbCBwcm9tZWRpbyBlc3BlcmFkbyBkZWwgdG90YWwgZGUgbGFzIGNvbHVtbmFzIGFjdGl2YXMgZGUgbGEgbWF0cml6IGRlIGRhdG9zLiBEZSBlc3RhczoKCi0gICBMYXMgY2F0ZWdvcsOtYXMgMSB5IDQgZGUgbGEgdmFyaWFibGUgImNvbmZpYW56YSBlbiBlbCBnb2JpZXJubyIgc29uIGxhcyBxdWUgZWplcmNlbiBtYXlvciBjb250cmlidWNpw7NuLgotICAgRXhpc3RlbiBvdHJhcyBjaW5jbyBjYXRlZ29yw61hcyBxdWUgdGFtYmnDqW4gc29uIG1lZGlhbmFtZW50ZSByZWxldmFudGVzLCBjb21vIGxvIHNvbiBsYSBjYXRlZ29yw61hIDQgZGUgInNhdGlzZmFjY2nDs24gY29uIGxhIGRlbW9jcmFjaWEiLCBsYSBjYXRlZ29yw61hIDUgZGUgInNpdHVhY2nDs24gZGUgbGEgZWNvbm9tw61hIiwgbGEgY2F0ZWdvcsOtYSAyIGRlICJhcHJvYmFjacOzbiBkZWwgZ29iaWVybm8iLCBsYSBjYXRlZ29yw61hIDEgZGUgInNhdGlzZmFjY2nDs24gY29uIGxhIGRlbW9jcmFjaWEiLCB5IGxhIGNhdGVnb3LDrWEgMSBkZSAiYXByb2JhY2nDs24gZGVsIGdvYmllcm5vIi4KLSAgIFNlIHViaWNhcm9uIG90cmFzIG9jaG8gY2F0ZWdvcsOtYXMgY29uIHVuYSBpbmZsdWVuY2lhIGltcG9ydGFudGUgcGVybyBkZSBtZW5vciBjb250cmlidWNpw7NuLCBxdWUgdmFuIGRlc2RlIGxhIGNhdGVnb3LDrWEgMiBkZSAidm90w7MgYWwgcGFydGlkbyBkZWwgZ29iaWVybm8iLCBoYXN0YSBsYSBjYXRlZ29yw61hIDIgZGUgImNvbmZpYW56YSBlbiBlbCBnb2JpZXJuby4iCi0gICBFbCByZXN0byBkZSBsYXMgY2F0ZWdvcsOtYXMgc2UgdWJpY2Fyb24gcG9yIGRlYmFqbyBkZWwgcHJvbWVkaW8gZXNwZXJhZG8sIHkgcG9yIHRhbnRvIHB1ZWRlbiBjb25zaWRlcmFzZSBwb2NvIHJlbGV2YW50ZXMgcGFyYSBldmFsdWFyIGxhIGNvbnRyaWJ1Y2nDs24gZGUgbG9zIGVqZXMuCgpMYSBjb250cmlidWNpw7NuIGRlIGxhcyBjYXRlZ29yw61hcyBwdWVkZSByZXByZXNlbnRhcnNlIGRlIG1hbmVyYSBncsOhZmljYSBlbiBlbCAqYmlwbG90KiBxdWUgc2UgaGEgdHJhYmFqYWRvIGhhc3RhIGVsIG1vbWVudG8sIGEgcGFydGlyIGRlIHNlw7FhbGFybG8gbWVkaWFudGUgbGEgY29sb3JhY2nDs24gZGUgbG9zIHB1bnRvcyBlbiBsYSBncsOhZmljYSwgcGFyYSBsbyBxdWUgc2UgdXNhIGVsIGFyZ3VtZW50byBgY29sLnZhciA9ICJjb250cmliImAgZGUgbGEgc2lndWllbnRlIG1hbmVyYToKCmBgYHtyIGNvcnJlbF9jYXRlZ3NfY29udHJpYiwgZmlnLmNhcD0iQmlwbG90IGRlIGRpc3RyaWJ1Y2nDs24gZGUgbGFzIGNhdGVnb3LDrWFzIGFjdGl2YXMgc2XDsWFsYWRhcyBwb3Igc3UgY29udHJpYnVjacOzbiBhIGNhZGEgZGltZW5zacOzbi4ifQpmdml6X21jYV92YXIobWNhX2xiLCAjb2JqZXRvIHRpcG8gbGlzdGEgY29uIHJlc3VsdGFkb3MgbWNhIAogICAgICAgICAgICAgY29sLnZhciA9ICJjb250cmliIiwgI2RlZmluaXIgbGEgY29sb3JhY2nDs24gbWVkaWFudGUgbGEgImNvbnRyaWJ1Y2nDs24iCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwgI3NlbGVjY2nDs24gZGUgbGEgcGFsZXRhIGRlIGNvbG9yZXMKICAgICAgICAgICAgIHJlcGVsID0gVFJVRSwgIyBldml0YXIgc29sYXBhbWllbnRvIGRlIGV0aXF1ZXRhcwogICAgICAgICAgICAgbWF4Lm92ZXJsYXBzID0gImdncmVwZWwubWF4Lm92ZXJsYXBzIiwgI2F1bWVudGFyIGxhIGNhbnRpZGFkIGRlIHNvbGFwYW1pZW50b3MKICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCkKICAgICAgICAgICAgICkKYGBgCgpMYSBncsOhZmljYSBwZXJtaXRlIGlkZW50aWZpY2FyIGN1w6FsZXMgc29uIGxhIGNhdGVnb3LDrWFzIHF1ZSBtw6FzIGVzdMOhbiBjb250cmlidXllbmRvIGVuIGxhIGNvbnN0cnVjY2nDs24gZGUgbGEgZ3LDoWZpY2EsIGFzw60gY29tbyBsb3MgcG9sb3MgbyBleHRyZW1vcyBkZSBsYXMgZGltZW5zaW9uZXMgc29icmUgbGFzIHF1ZSBlc3TDoW4gaW5mbHV5ZW5kby5cCgpEZSBtYW5lcmEgcXVlIHNlIG9ic2VydmEgcXVlIGxhcyBjYXRlZ29yw61hcyAiY29uZl9nb2JfMSIsICJzYXRpc2ZfZGVtXzEiIHkgImFwcm9iX2dvYl8xIiBlc3TDoW4gaW5mbHV5ZW5kbyBmdWVydGVtZW50ZSBzb2JyZSBsb3MgdmFsb3JlcyBwb3NpdGl2b3MgZGUgbGEgZGltZW5zacOzbiAxIHksIGVuIGNvbnRyYXBhcnRlLCBsYXMgY2F0ZWdvcsOtYXMgImNvbmZfZ29iXzQiLCAic2F0aXNmX2RlbV80IiwgInNpdF9lY181IiB5ICJhcHJvYl9nb2JfMiIgbG8gZXN0w6FuIGhhY2llbmRvIHNvYnJlIGxhIHBhcnRlIG5lZ2F0aXZhIGRlIGxhIG1pc21hIGRpbWVuc2nDs24uXAoKUG9yIMO6bHRpbW8sIHRhbWJpw6luIGVzIHBvc2libGUgY29udHJvbGFyIGxhIGludGVuc2lkYWQgZGUgbGEgdHJhbnNwYXJlbmNpYSBkZSBsYSBwcm95ZWNjacOzbiBkZSBjYWRhIHB1bnRvIGNvcnJlc3BvbmRpZW50ZSBhIGxhcyBjYXRlZ29yw61hcywgYSBwYXJ0aXIgZGVsIGNyaXRlcmlvIGRlIGxvcyB2YWxvcmVzIGRlIHN1IGNvbnRyaWJ1Y2nDs24gc29icmUgbGFzIGRpbWVuc2lvbmVzLiBQYXJhIGVsbG8gc2UgdXRpbGl6YSBlbCBjb21hbmRvIGBhbHBoYS52YXIgPSAiY29udHJpYiJgIGVuIGVsIGNvbWFuZG8gYGZ2aXpfbWNhX3ZhcigpYC4KCmBgYHtyLCBmaWcuY2FwPSJCaXBsb3QgZGUgbGEgZGlzdHJpYnVjacOzbiBkZSBsYXMgY2F0ZWdvcsOtYXMgc2XDsWFsYW5kbyBzdSBjb250cmlidWNpw7NuIG1lZGlhbnRlIGVsIG5pdmVsIGRlIHRyYW5zcGFyZW5jaWEgZGUgc3VzIHB1bnRvcyBnZW9tw6l0cmljb3MuIn0KZnZpel9tY2FfdmFyKG1jYV9sYiwgI29iamV0byB0aXBvIGxpc3RhIGNvbiByZXN1bHRhZG9zIG1jYSAKICAgICAgICAgICAgIGFscGhhLnZhcj0iY29udHJpYiIsICNjb250cm9sIGRlIGxhIGludGVuc2lkYWQgZGUgbGEgdHJhbnNwYXJlbmNpYQogICAgICAgICAgICAgcmVwZWwgPSBUUlVFLCAjIGV2aXRhciBzb2xhcGFtaWVudG8gZGUgZXRpcXVldGFzCiAgICAgICAgICAgICBtYXgub3ZlcmxhcHMgPSAiZ2dyZXBlbC5tYXgub3ZlcmxhcHMiLCAjYXVtZW50YXIgbGEgY2FudGlkYWQgZGUgc29sYXBhbWllbnRvcwogICAgICAgICAgICAgZ2d0aGVtZSA9IHRoZW1lX21pbmltYWwoKQogICAgICAgICAgICAgKQpgYGAKCiMgQW7DoWxpc2lzIHNvYnJlIGxvcyBpbmRpdmlkdW9zCgpQb3Igb3RybyBsYWRvLCB0YW1iacOpbiBlcyBwb3NpYmxlIHJlYWxpemFyIGVsIGFuw6FsaXNpcyBkZSBjb3JyZXNwb25kZW5jaWFzIHNvYnJlIGxvcyBwZXJmaWxlcyBkZSBsb3MgaW5kaXZpZHVvcyAoZmlsYXMpIGRlbnRybyBkZWwgKipNQ0EqKi4gRXN0byBwZXJtaXRlIGFncnVwYXIgeSB1YmljYXIgYSBsb3MgaW5kaXZpZHVvcyBvIGNhc29zIG3DoXMgc2VtZWphbnRlcyBlbnRyZSBzw60sIHRvbWFuZG8gZW4gY29uc2lkZXJhY2nDs24gc3VzIHJlc3B1ZXN0YXMgYSBsYXMgY2F0ZWdvcsOtYXMgc2VsZWNjaW9uYWRhczsgYWRlbcOhcywgZWwgYW7DoWxpc2lzIHBlcm1pdGUgdWJpY2FyIGEgbG9zIGNhc29zIG8gaW5kaXZpZHVvcyBxdWUgZWplcmNlbiBtYXlvciBpbmZsdWVuY2lhIHNvYnJlIGxhIGRpc3RyaWJ1Y2nDs24gZGVudHJvIGRlbCAqYmlwbG90KiBjb24gbGFzIGRpbWVuc2lvbmVzIG8gZWplcyBudWV2b3MuXAoKRWwgY29tYW5kbyBgZ2V0X21jYV9pbmQoKWAsIHF1ZSBlcyBwYXJ0ZSBkZSBsYSBsaWJyZXLDrWEgYGZhY3RvZXh0cmEoKWAsIHBlcm1pdGUgZXh0cmFlciBsb3MgcmVzdWx0YWRvcyBwYXJhIGxvcyBpbmRpdmlkdW9zLiBFc3RhIGZ1bmNpw7NuIGFycm9qYSB1bmEgbGlzdGEgZW4gbGEgcXVlIGVzdMOhbiBjb250ZW5pZGFzIGxhcyBjb29yZGVuYWRhcywgbG9zIHZhbG9yZXMgZGUgbG9zIGNvc2Vub3MgY3VhZHLDoXRpY29zIHkgbGFzIGNvbnRyaWJ1Y2lvbmVzIGRlIGNhZGEgdW5vIGRlIGxvcyBjYXNvcyBvIGluZGl2aWR1b3MgKGZpbGFzKSBkZSBsYSBtYXRyaXogZGUgZGF0b3MuCgpgYGB7ciBvYmpldG9fbGlzdGFfaW5kaXZ9CmluZGl2IDwtIGdldF9tY2FfaW5kKG1jYV9sYikKaW5kaXYKYGBgCgpMb3MgcmVzdWx0YWRvcyBvYnNlcnZhZG9zIHBhcmEgbG9zIGluZGl2aWR1b3Mgc2lndWVuIGxhIG1pc21hIGzDs2dpY2EgZGUgaW5mb3JtYWNpw7NuIHF1ZSBsYSBxdWUgc2UgZGVzY3JpYmnDsyBhcnJpYmEgcGFyYSBsYXMgY2F0ZWdvcsOtYXMgZGUgbGFzIHZhcmlhYmxlcyBhY3RpdmFzLlwKClNlIHB1ZWRlIGFjY2VkZXIgYSBsYSBpbmZvcm1hY2nDs24gY29udGVuaWRhIGVuIGNhZGEgdW5vIGRlIGxvcyBlbGVtZW50b3MgZGUgbGEgbGlzdGEgc2kgc2UgbWFuZGEgYSBsbGFtYXIgYSBjYWRhIGVsZW1lbnRvIG1lZGlhbnRlIGVsIHNpZ25vICJcJCI6CgpgYGB7ciBlbGVtZW50b3NfbWNhX2luZGl2fQojIGNvb3JkaW5hZGFzIHBhcmEgbGFzIGZpbGFzCmhlYWQoaW5kaXYgJCBjb29yZCwgMykKIyBjdWFsaWRhZCBkZSBsYSByZXByZXNlbnRhY2nDs24KaGVhZChpbmRpdiAkIGNvczIsIDMpCiMgY29udHJpYnVjacOzbiBkZSBjYWRhIGluZGl2aWR1bwpoZWFkKGluZGl2ICQgY29udHJpYiwgMykKYGBgCgpFbiBsYSB0YWJsYSBhbnRlcmlvciwgY2FkYSBmaWxhIHNlIHJlZmllcmUgYSBjYWRhIHVubyBkZSBsb3MgY2Fzb3MgbyBpbmRpdmlkdW9zIGFjdGl2b3MgcHJlc2VudGVzIGVuIGxhIG1hdHJpeiBkZSBkYXRvcyAtc29sbyBzZSBwcmVzZW50YW4gYSBsb3MgMyBwcmltZXJvcyBjYXNvcy4gWSBlbiBlbCByZXN0byBkZSBjYWRhIGZpbGEgc2UgaWRlbnRpZmljYSBlbCB2YWxvciBwYXJhIGVsIHN1amV0byAkLWkkIGVuIGNhZGEgdW5hIGRlIGxhcyBkaW1lbnNpb25lcyBvIGVqZXMgY2FsY3VsYWRvcy5cCgojIyBDYWxpZGFkIGRlIGxhIHJlcHJlc2VudGFjacOzbiBkZSBsb3MgaW5kaXZpZHVvcyBlbiBlbCBhbsOhbGlzaXMgKipNQ0EqKgoKQSBwYXJ0aXIgZGVsIGNvbWFuZG8gYGZ2aXpfbWNhX2luZCgpYCBlcyBwb3NpYmxlIGNyZWFyIHVuYSBncsOhZmljYSBkZSBkaXNwZXJzacOzbiBwYXJhIG9ic2VydmFyIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbGFzIHByb3llY2Npb25lcyBkZSBjYWRhIGluZGl2aWR1byBzb2JyZSBlbCBiaXBsb3QgY29uIGxhcyBkaW1lbnNpb25lcyBvIGVqZXMgYW5hbGl6YWRvcy4gQWwgaWd1YWwgcXVlIGVuIGVsIGNhc28gZGUgbGEgZ3LDoWZpY2Egc29icmUgbGFzIGNhdGVnb3LDrWFzLCBhcXXDrSB0YW1iacOpbiBlcyBwb3NpYmxlIHNlw7FhbGFyIG1lZGlhbnRlIGNvbG9yZXMgbGEgY2FsaWRhZCBvIGxhIGNvbnRyaWJ1Y2nDs24gZGUgY2FkYSBpbmRpdmlkdW8gc29icmUgbGEgZ3LDoWZpY2EuXAoKTGEgbWFuZXJhIGRlIHNlw7FhbGFyIGxhIGNhbGlkYWQgZGUgbGEgcmVwcmVzZW50YWNpw7NuIGRlIGNhZGEgaW5kaXZpZHVvIGVuIGVsICpiaXBsb3QqIGVzIG1lZGlhbnRlIGVsIGFyZ3VtZW50byBgY29sLmluZCA9YCwgcG9yIGVqZW1wbG8sIGVzIGxhIHNpZ3VpZW50ZToKCmBgYHtyIGJpcGxvdF9tY2FfaW5kaXZfY29zMiwgZmlnLmNhcD0gIkJpcGxvdCBkZSBkaXN0cmlidWNpw7NuIGRlIGxvcyBlbmN1ZXN0YWRvcyBwb3IgTGF0aW5vYmFyw7NtZXRybywgc2XDsWFsYWRvcyBwb3IgbGEgY2FsaWRhZCBkZSBzdSByZXByZXNlbnRhY2nDs24gZW4gZWwgZ3LDoWZpY28gKGNvczIpLiJ9CmZ2aXpfbWNhX2luZChtY2FfbGIsIAogICAgICAgICAgICAgY29sLmluZCA9ICJjb3MyIiwgIyBjb2xvcmVhciBsb3MgY2Fzb3MgYSBwYXJ0aXIgZGVsIGNyaXRlcmlvIGRlIHZhbG9yIGNvc14yCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwKICAgICAgICAgICAgIHJlcGVsID0gVFJVRSwKICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9ICJnZ3JlcGVsLm1heC5vdmVybGFwcyIsCiAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpCiAgICAgICAgICAgICApCmBgYAoKQSBwYXJ0aXIgZGUgZXN0ZSBncsOhZmljbyBzZSBvYnNlcnZhIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIGluZGl2aWR1b3MgYWN0aXZvcyBlbiBsYSBtYXRyaXogZGUgZGF0b3MsIHF1ZSBzZSB1dGlsaXphcm9uIHBhcmEgZWwgYW7DoWxpc2lzICoqTUNBKiouXAoKRW4gZXN0YSByZXByZXNlbnRhY2nDs24gc2UgcHVlZGVuIG9ic2VydmFyIHF1ZSBsb3MgY2Fzb3MgY29uIG1lam9yIHJlcHJlc2VudGFjacOzbiBzZSB1YmljYW4gZW4gY29sb3JlcyBjZXJjYW5vcyBhbCByb2pvLCB5IHNlIHBvc2ljaW9uYW4gZW4gbG9zIGV4dHJlbW9zIGRlIGxhIGRpbWVuc2nDs24gMSwgeSBubyBuZWNlc2FyaWFtZW50ZSBoYXkgY2Fzb3MgZGVsIG1pc21vIGNvbG9yIHNvYnJlIGxhIGRpbWVuc2nDs24gMi4gRXN0byBpbmRpY2EgcXVlIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIGNhc29zIGVzdMOhbiBtZWpvciByZXByZXNlbnRhZG9zIHBvciBsYSBwcmltZXJhIGRpbWVuc2nDs24uCgpQb3Igc3UgcGFydGUsIGxvcyBjYXNvcyBjb24gYmFqb3Mgbml2ZWxlcyBkZSBjb3Nlbm9zIGN1YWRyw6F0aWNvcyB0ZW5kZXLDoW4gYSB1YmljYXJzZSBjZXJjYW5vcyBhbCBjZW50cm9pZGUgZGUgbGEgZ3LDoWZpY2EgKGNvb3JkZW5hZGFzID0gWzAsMF0pLCB5IGVzdMOhbiBzZcOxYWxhZG9zIGNvbiBlbCBjb2xvciBtw6FzIHBhcmVjaWRvIGFsIHR1cnF1ZXNhLiBFc3RvIHNlIHB1ZWRlIGludGVycHJldGFyIGNvbW8gcXVlIGxhcyBkaW1lbnNpb25lcyBvIGVqZXMgdXRpbGl6YWRvcyBlbiBsYSByZXByZXNlbnRhY2nDs24gZ3LDoWZpY2Egbm8gc29uIGxvcyBxdWUgbWVqb3IgYXl1ZGFuIGEgZW50ZW5kZXIgc3VzIGNvbXBvcnRhbWllbnRvcyBvIHN1cyBwZXJmaWxlcywgeSB0YWwgdmV6IGV4aXN0YW4gb3Ryb3MgZWplcyAocXVlIGhhYnLDrWEgcXVlIGV4cGxvcmFyKSBxdWUgbWVqb3Igc2UgYWp1c3RlbiBhIHN1IGRpc3RyaWJ1Y2nDs24uXAoKIyMgQ29udHJpYnVjacOzbiBkZSBsb3MgY2Fzb3MgYWwgYW7DoWxpc2lzICoqTUNBKioKCkVuIGNhc28gZGUgcXVlcmVyIGlkZW50aWZpY2FyIGxhIGNvbnRyaWJ1Y2nDs24gZGUgY2FkYSBjYXNvIG8gaW5kaXZpZHVvIChmaWxhKSBzb2JyZSBsYSBjb25zdHJ1Y2Npw7NuIGRlIGxhcyBkaW1lbnNpb25lcyBvIGVqZXMgY2FsY3VsYWRvcywgZXMgcG9zaWJsZSByZWFsaXphcmxvIGEgcGFydGlyIGRlIHJldG9tYXIgZWwgY29tYW5kbyBgZnZpel9tY2FfaW5kKClgLCBlbiBkb25kZSBzZSBwdWVkZSB1dGlsaXphciBlbCBhcmd1bWVudG8gYGNvbC5pbmQgPSBjb250cmliYC4gRXN0byBwZXJtaXRpcsOhIHNlw7FhbGFyIGVsIG5pdmVsIGRlIGNvbnRyaWJ1Y2nDs24gZGUgY2FkYSBjYXNvIG1lZGlhbnRlIGxvcyBncmFkaWVudGVzIGRlIGNvbG9yZXMuCgpgYGB7ciBiaXBsb3RfbWNhX2luZGl2X2NvbnRyaSwgZmlnLmNhcD0iQmlwbG90IGRlIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIGVuY3Vlc3RhZG9zIHBvciBMYXRpbm9iYXLDs21ldHJvLCBzZcOxYWxhZG9zIHBvciBsYSBjb250cmlidWNpw7NuIGRlIHN1IHJlcHJlc2VudGFjacOzbiBlbiBlbCBncsOhZmljby4ifQpmdml6X21jYV9pbmQobWNhX2xiLCAKICAgICAgICAgICAgIGNvbC5pbmQgPSAiY29udHJpYiIsICMgY29sb3JlYXIgbG9zIGNhc29zIGEgcGFydGlyIGRlbCB2YWxvciBkZSBjb250cmlidWNpw7NuCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwKICAgICAgICAgICAgIHJlcGVsID0gVFJVRSwKICAgICAgICAgICAgIG1heC5vdmVybGFwcyA9ICJnZ3JlcGVsLm1heC5vdmVybGFwcyIsCiAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpCikKYGBgCgpBIHBhcnRpciBkZSBlc3RhIGdyw6FmaWNhIHNlIGlkZW50aWZpY2EgcXVlIGxvcyBjYXNvcyBjb24gbWF5b3IgY29udHJpYnVjacOzbiBlbiBsYSBjb25zdHJ1Y2Npw7NuIGRlIGxhcyBkaW1lbnNpb25lcyBvIGVqZXMgY2FsY3VsYWRvcyBzZSBjb2xvcmVhbiBlbiB0b25hbGlkYWRlcyByb2ppemFzLCBtaWVudHJhcyBxdWUgbG9zIGRlIG1lbm9yIGNvbnRyaWJ1Y2nDs24gZXN0w6FuIGlsdW1pbmFkb3MgZW4gY29sb3IgdmVyZGUgdHVycXVlc2EuXAoKRXN0YSBncsOhZmljYSBwZXJtaXRlIGlkZW50aWZpY2FyIHF1ZSBlbCBjYXNvIGNvbiBtYXlvciBjb250cmlidWNpw7NuIGVzIGVsIG7Dum1lcm8gMzg2NC4gUG9yIGxvIHF1ZSBzZXLDrWEgaW50ZXJlc2FudGUsIHBvc3Rlcmlvcm1lbnRlLCBhbmFsaXphciBhIHByb2Z1bmRpZGFkIGRpY2hvIGNhc28uXAoKVGFtYmnDqW4gc2UgcHVlZGUgY29tZW56YXIgYSBpZGVudGlmaWNhciAibnViZXMiIG8gZ3J1cG9zIGRlIGNhc29zIHNlbWVqYW50ZXMgZW50cmUgc8OtLiBEZSBtYW5lcmEgcXVlIGxvcyBjYXNvcyBtw6FzIGNlcmNhbm9zIGVudHJlIHPDrSBzZSBjb3JyZXNwb25kZW4gY29uIHBlcmZpbGVzIHBhcmVjaWRvcyBlbiBzdXMgcmVzcHVlc3RhcyBhIGxhcyBkaXN0aW50YXMgY2F0ZWdvcsOtYXMgZGUgbGFzIHZhcmlhYmxlcyBtZWRpZGFzLCBlbiBmdW5jacOzbiBkZSBsYSBjYWxpZGFkIGRlIHN1IHJlcHJlc2VudGFjacOzbi4gRXN0b3Mgc2UgdWJpY2FuIGVuIG1lam9yIG1lZGlkYSBlbiBsb3MgZXh0cmVtb3MgZGVsIGVqZSBvIGRpbWVuc2nDs24gMS5cCgpQb3Igb3RybyBsYWRvLCB0YW1iacOpbiBzZSBwdWVkZW4gY3JlYXIgZ3LDoWZpY2FzIGRlIGJhcnJhcyBwYXJhIG1lZGlyIGxhIGNvbnRyaWJ1Y2nDs24gZGUgbG9zIGluZGl2aWR1b3Mgc29icmUgbGFzIGRpbWVuc2lvbmVzIG8gZWplcyBjcmVhZG9zLCBhIHBhcnRpciBkZSBzdXMgY29zZW5vcyBjdWFkcsOhdGljb3MgeSBzdXMgY29udHJpYnVjaW9uZXMuIFBhcmEgZWxsbyBzZSB1dGlsaXphIGVsIGNvbWFuZG8gYGZ2aXpfY29udHJpYigpYC5cCgpQb3IgZWplbXBsbywgZW4gbGEgZ3LDoWZpY2Egc2lndWllbnRlIHNlIGlkZW50aWZpY2FuIGEgbG9zIDIwIGNhc29zIG8gaW5kaXZpZHVvcyBjb24gbWF5b3IgY29udHJpYnVjacOzbiBzb2JyZSBhbWJhcyBkaW1lbnNpb25lcyBkZSBtYW5lcmEgc2ltdWx0w6FuZWEuCgpgYGB7ciBiYXJwbG90X2luZGl2X2NvbnRyaWIsIGZpZy5jYXA9Ikdyw6FmaWNhcyBkZSBiYXJyYXMgcGFyYSBsb3MgMjAgY2Fzb3MgY29uIG1heW9yIGNvbnRyaWJ1Y2nDs24gYSBsYXMgZGltZW5zaW9uZXMgMSB5IDIuIn0KZnZpel9jb250cmliKG1jYV9sYiwgI29iamV0byB0aXBvIGxpc3RhIGNvbiBsb3MgcmVzdWx0YWRvcyBtY2EKICAgICAgICAgICAgIGNob2ljZSA9ICJpbmQiLCAjc2VsZWNjacOzbiBkZSBsb3MgaW5kaXZpZHVvcyBwYXJhIHJlcHJlc2VudGFybG9zCiAgICAgICAgICAgICBheGVzID0gMToyLCAjZWplcyBvIGRpbWVuc2lvbmVzIGEgaW5jbHVpcgogICAgICAgICAgICAgdG9wID0gMjApICNzZWxlY2Npw7NuIGRlIGxvcyAyMCBjYXNvcyBjb24gbWF5b3Igbml2ZWwKYGBgCgpBIHBhcnRpciBkZSBsYSBncsOhZmljYSBkZSBiYXJyYXMgc2UgcHVlZGUgaWRlbnRpZmljYXIgY29uIG1heW9yIGNsYXJpZGFkIGN1w6FsZXMgc29uIGxvcyBjYXNvcyBjb24gbWF5b3IgY29udHJpYnVjacOzbiBzb2JyZSBsYSBjb25zdHJ1Y2Npw7NuIGRlIGxhcyBkaW1lbnNpb25lcyBvIGVqZXMgMSB5IDIuIEFxdcOtIHNlIG9ic2VydmEgcXVlIGVsIGNhc28gMzg2NCBlcyBlbCBtw6FzIGluZmx1eWVudGUsIHkgcG9zdGVyaW9ybWVudGUgbGUgc2lndWVuIGVuIGlndWFsIG1hZ25pdHVkIGRlIGNvbnRyaWJ1Y2nDs24gbG9zIGNhc29zIDIxNDMsIDM1MzQgeSAzNjc3LCBlbnRyZSBvdHJvcy5cCgpEZSBtYW5lcmEgcGFyZWNpZGEgYSBsYXMgZ3LDoWZpY2FzIHZpc3RhcyBtw6FzIGFycmliYSwgZG9uZGUgbG9zIGNhc29zIHF1ZSBzZSB1YmlxdWVuIHBvciBlbmNpbWEgZGUgbGEgbMOtbmVhIHJlY3RhIGhvcml6b250YWwgcHVudGVhZGEgZGUgY29sb3Igcm9qbywgaW5kaWNhIHF1ZSBzdSBpbmZsdWVuY2lhIGNhZSBwb3IgYXJyaWJhIGRlbCBwcm9tZWRpbyBlc3BlcmFkbyBkZSBjb250cmlidWNpw7NuIHBhcmEgZWwgdG90YWwgZGUgY2Fzb3MuXAoKU2lndWllbmRvIGxhIG1pc21hIGzDs2dpY2EgZGUgbGEgZ3LDoWZpY2EgZGUgYmFycmFzIHBhcmEgZXZhbHVhciBsYSBjb250cmlidWNpw7NuIGRlIGNhZGEgaW5kaXZpZHVvLCBlc3RlIG1pc21vIGVqZXJjaWNpbyBzZSBwdWVkZSByZWFsaXphciBwYXJhIG9ic2VydmFyIGVsIG5pdmVsIGRlIGNhbGlkYWQgZGUgcmVwcmVzZW50YWNpw7NuIGRlIGxvcyBpbmRpdmlkdW9zIGVuIGFtYmFzIGRpbWVuc2lvbmVzIGRlIGxhIGdyw6FmaWNhICpiaXBsb3QuKiBQYXJhIGVsbG8gc2UgdXRpbGl6YSBlbCBjb21hbmRvIGBmdml6X2NvczIoKWAgZGUgbGEgc2lndWllbnRlIG1hbmVyYToKCmBgYHtyIGJhcnBsb3RfbWNhX2NvczJfaW5kLCBmaWcuY2FwPSJHcsOhZmljYSBkZSBiYXJyYXMgc29icmUgbGEgY2FsaWRhZCBkZSByZXByZXNlbnRhY2nDs24gZGUgY2FkYSBpbmRpdmlkdW8gc29icmUgbG9zIGVqZXMgMSB5IDIuIn0KZnZpel9jb3MyKG1jYV9sYiwgCiAgICAgICAgICBjaG9pY2UgPSAiaW5kIiwgCiAgICAgICAgICBheGVzID0gMToyLCAKICAgICAgICAgIHRvcCA9IDIwKQpgYGAKCkEgcGFydGlyIGRlIGVzdGEgZ3LDoWZpY2Egc2UgcHVlZGVuIGlkZW50aWZpY2FyIGxvcyBjYXNvcyBjb24gbWF5b3JlcyBuaXZlbGVzIGRlIGNvc2Vub3MgY3VhZHLDoXRpY29zLCB5IHF1ZSBzdXBvbmVuIGVzdGFyIG1lam9yIHJlcHJlc2VudGFkb3MgZW4gZWwgZ3LDoWZpY28gZGUgYmFycmFzLiBDb21vIHNlIHB1ZWRlIHZlciwgbG9zIGNhc29zIGNvbiBtYXlvcmVzIG5pdmVsZXMgZGUgJGNvc14yJCBzb24gZWwgMjAxNSB5IGVsIDI2MjkuIExlcyBzaWd1ZW4gc2lldGUgY2Fzb3MgbcOhcyBjb24gZWwgbWlzbW8gdmFsb3IgKGRlc2RlIGVsIDE3NDYgaGFzdGEgMzk4NCkuXAoKIyBBZ3J1cGFtaWVudG8gZGUgaW5kaXZpZHVvcwoKT3RyYSBtYW5lcmEgZGUgZXZhbHVhciBsb3MgcGVyZmlsZXMgZGUgY2Fzb3MgbyBpbmRpdmlkdW9zIGRpc3RyaWJ1aWRvcyBwb3IgbGEgZ3LDoWZpY2EgZGUgbG9zIGVqZXMgbyBkaW1lbnNpb25lcyBjYWxjdWxhZGFzLCB5IGFzw60gaWRlbnRpZmljYXIgc3VzIGFncnVwYW1pZW50b3MsIHNlIHJlYWxpemEgbWVkaWFudGUgbGEgY29sb3JhY2nDs24gZGUgbG9zIGNhc29zIHkgYcOxYWRpw6luZG9sZSBlbGlwc2VzIGluZGljYXRpdmFzIHNvYnJlIGVsIGNlbnRyb2lkZSBwYXJhIGNhZGEgZ3J1cG8geSBsYSBhbXBsaXR1ZCBkZSBzdSBkaXN0cmlidWNpw7NuLiBBcXXDrSBzZSBwdWVkZSBzZWd1aXIgdHJhYmFqYW5kbyBjb24gZWwgY29tYW5kbyBgZnZpel9tY2FfaW5kKClgLlwKCkFsIGludGVudGFyIGFncnVwYXIgbG9zIGNhc29zIG1lZGlhbnRlIGxhIGNvbG9yYWNpw7NuIGRlIGxvcyBwdW50b3MgbyBwcm95ZWNjaW9uZXMgZGUgY2FkYSBpbmRpdmlkdW8sIHNlIHB1ZWRlIGVzdGFibGVjZXIgYSB1bmEgdmFyaWFibGUgdGlwbyBgZmFjdG9yKClgIGNvbW8gZWwgY3JpdGVyaW8gcGFyYSBsbGV2YXJsbyBhIGNhYm8uIFBhcmEgZWxsbyBzZSB1c2EgZWwgYXJndW1lbnRvIGBoYWJpbGxhZ2U9YCwgZG9uZGUgc2UgZXN0YWJsZWNlIGVsIG5vbWJyZSBkZSBsYSB2YXJpYWJsZSBxdWUgc2Vydmlyw6EgcGFyYSBlc3RhYmxlY2VyIGxhIGNvbG9yYWNpw7NuIGRlIGxvcyBpbmRpdmlkdW9zIHksIGFzw60sIGFncnVwYXJsb3MuXAoKVGFtYmnDqW4gc2UgcHVlZGUgYcOxYWRpciB1bmEgZWxpcHNlIGRlIGNvbmNlbnRyYWNpw7NuIGVuIGNhZGEgdW5vIGRlIGxvcyBncnVwb3MgY3JlYWRvcywgbWVkaWFudGUgZWwgYXJndW1lbnRvIGBhZGRFbGxpcHNlcz1UUlVFYC4gU2kgc2UgZGVzZWEgZXN0YWJsZWNlciBxdWUgZWwgY2VudHJvIGRlIGxhIGVsaXBzZSBkZSBjb25maWFuemEgc2UgdWJpcXVlIHNvYnJlIGVsIHB1bnRvIG1lZGlvIGRlIGNhZGEgY2F0ZWdvcsOtYSwgc2UgZGViZSB1c2FyIGVsIGFyZ3VtZW50byBgZWxsaXBzZS50eXBlID0gImNvbmZpZGVuY2UiYC5cCgpGaW5hbG1lbnRlLCBzZSB1c2EgZWwgYXJndW1lbnRvIGBwYWxldHRlPWAgcGFyYSBjYW1iaWFyIGxvcyBjb2xvcmVzIGRlIGxvcyBncnVwb3MuXAoKYGBge3IgYmlwbG90X21jYV9pbmRfZ3J1cCwgZmlnLmNhcD0iQmlwbG90IGNvbiBsYSBkaXN0cmlidWNpw7NuIGRlIGxvcyBpbmRpdmlkdW9zLCBhZ3J1cGFkb3MgcG9yIGNvbG9yZXMgeSBjb24gZWxpcHNlcyBkZSBjb25maWFuemEuIn0KZnZpel9tY2FfaW5kKG1jYV9sYiwgI29iamV0byB0aXBvIGxpc3RhIGNvbiByZXN1bHRhZG9zIG1jYSAKICAgICAgICAgICAgIGxhYmVsID0gIm5vbmUiLCAjIG9jdWx0YXIgbGFzIGV0aXF1ZXRhcyBkZSBsb3MgaW5kaXZpZHVvcwogICAgICAgICAgICAgaGFiaWxsYWdlID0gInNhdGlzZl9kZW0iLCAjIGNvbG9yZWFyIGEgbG9zIGdydXBvcyAKICAgICAgICAgICAgIGFkZEVsbGlwc2VzID0gVFJVRSwKICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCkKICAgICAgICAgICAgICkKYGBgCgpBIHBhcnRpciBkZSBsYSBncsOhZmljYSBzZSBwdWVkZSBvYnNlcnZhciBsYSBtYW5lcmEgZW4gcXVlIHNlIGRpc3RyaWJ1eWVuIGxvcyBjYXNvcyBzaSBzb24gYWdydXBhZG9zIGEgcGFydGlyIGRlIGxhIHZhcmlhYmxlICIqc2F0aXNmYWNjacOzbiBjb24gbGEgZGVtb2NyYWNpYSoiIChgc2F0aXNmX2RlbWApLCBxdWUgc2UgaW50ZWdyYSBwb3IgNCBuaXZlbGVzICgkaz00JCkuIEFzaW1pc21vIHNlIG9ic2VydmFuIGxhcyBlbGlwc2VzIHF1ZSBtdWVzdHJhbiBlbCB0YW1hw7FvIGRlIGxhIGRpc3BlcnNpw7NuIGRlIGNhZGEgZ3J1cG8uIEEgcGFydGlyIGRlIGVzdG8gc2UgcHVlZGUgaW50ZXJwcmV0YXIgcXVlIGxvcyBncnVwb3MgY29ycmVzcG9uZGllbnRlcyBhIGxhcyBjYXRlZ29yw61hcyAxIHkgNCBzb24gbG9zIHF1ZSBwZXJtaXRlbiBhZ3J1cGFuIGRlIG1lam9yIG1hbmVyYSwgeSBsbyBtw6FzIGV4Y2x1eWVudGUgcG9zaWJsZSwgYSBsb3MgaW5kaXZpZHVvcy5cCgpUYW1iacOpbiBlcyByZWxldmFudGUgb2JzZXJ2YXIgcXVlIGxvcyBncnVwb3MgMiB5IDMgc29uIGFiYXJjYWRvcyBlbiBzdSBtYXlvcsOtYSBwb3IgbG9zIGdydXBvcyAxIHkgNCwgcmVzcGVjdGl2YW1lbnRlLiBFc3RvIGVzIGRlYmlkbyBhIHF1ZSBsb3MgcHJpbWVyb3Mgc2UgY29tcG9ydGFuIGNvbW8gc3ViZ3J1cG9zIGRlIGxvcyDDumx0aW1vcy4gRXN0byBwZXJtaXRlIGluZmVyaXIgcXVlIGxhIHZhcmlhYmxlIGRlICIqc2F0aXNmYWNjacOzbiBjb24gbGEgZGVtb2NyYWNpYSoiIHB1ZGllcmEgaW50ZWdyYXJzZSBlbiBzb2xvIGRvcyBncnVwb3MuXAoKU2kgdGFtYmnDqW4gc2UgZGVzZWFuIGdyYWZpY2FyIGRlIG1hbmVyYSBzaW11bHTDoW5lYSBsYXMgcHJveWVjY2lvbmVzIGRlIGxvcyBpbmRpdmlkdW9zIHV0aWxpemFuZG8gZG9zIHZhcmlhYmxlcyBjYXRlZ8OzcmljYXMgY29tbyBjcml0ZXJpb3MgcGFyYSBhZ3J1cGFybG9zLCBzZSBwdWVkZSBsbGFtYXIgZWwgY29tYW5kbyBgZnZpel9lbGxpcHNlcygpYCwgZGVudHJvIGRlbCBxdWUgc2UgcmVjdXBlcmEgZWwgb2JqZXRvIGNvbiBsb3MgcmVzdWx0YWRvcyBkZWwgYW7DoWxpc2lzICoqTUNBKiouCgpgYGB7cn0KZnZpel9lbGxpcHNlcyhtY2FfbGIsICMgb2JqZXRvIHRpcG8gbGlzdGEgY29uIHJlc3VsdGFkb3MgbWNhCiAgICAgICAgICAgICAgYygic2F0aXNmX2RlbSIsICJhcHJvYl9nb2IiKSwgIyBkZWZpbmljacOzbiBkZSB2YXJpYWJsZXMgZmFjdG9yIHBhcmEgYWdydXBhY2nDs24KICAgICAgICAgICAgICBnZW9tID0gInBvaW50IiwgIyB0aXBvIGRlIHJlcHJlc2VudGFjacOzbiBkZSBsb3MgaW5kaXZpZHVvcwogICAgICAgICAgICAgIGFscGhhID0gMC4xICN0cmFuc3BhcmVuY2lhIGRlIGxvcyBwdW50b3MgZW4gbGEgZ3LDoWZpY2EKICAgICAgICAgICAgICApCmBgYAoKRGUgbGFkbyBpenF1aWVyZG8gZGUgbGEgZ3LDoWZpY2Egc2Ugb2JzZXJ2YSBsYSBhZ3J1cGFjacOzbiBkZSBsb3MgY2Fzb3MgYSBwYXJ0aXIgZGUgbGEgdmFyaWFibGUgIiphcHJvYmFjacOzbiBkZWwgZ29iaWVybm8qIiAoYGFwcm9iX2dvYmAgJGs9MiQpIHkgZW4gZWwgbGFkbyBkZXJlY2hvIHNlIG9ic2VydmEgbGEgZGlzdHJpYnVjacOzbiBkZSBsb3MgY2Fzb3MgYWdyZWdhZG9zIHBvciBsYSB2YXJpYWJsZSAiKnNhdGlzZmFjY2nDs24gY29uIGxhIGRlbW9jcmFjaWEqIiAoYHNhdGlzZl9kZW1gLCAkaz00JCkuXAoKQWRlbcOhcywgZGVudHJvIGRlIGNhZGEgZ3J1cG8gZGUgY29sb3Igc2Ugb2JzZXJ2YW4gcHVudG9zIGNvbiBtYXlvciBpbnRlbnNpZGFkLCBsb3MgcXVlIHNlIHJlZmllcmVuIGEgbG9zIGNlbnRyb3MgKG8gcHJvbWVkaW9zKSBkZSBsYSBkaXN0cmlidWNpw7NuIGRlIGNhZGEgYWdydXBhY2nDs24gZGUgaW5kaXZpZHVvcy4gQWxyZWRlZG9yIGRlIGVzdG9zIHB1bnRvcyBzZSBlbmN1ZW50cmFuIGxhcyBlbGlwc2VzIGRlIGRpc3RyaWJ1Y2nDs24uXAoKRXMgaW50ZXJlc2FudGUgb2JzZXJ2YXIgcXVlIHBhcmEgbGEgZ3LDoWZpY2EgZGUgbGEgaXpxdWllcmRhLCBsb3MgY2VudHJvcyBkZSBkaXN0cmlidWNpw7NuIGRlIGNhZGEgZ3J1cG8gc2UgdWJpY2FuIGNhc2kgZW5jaW1hIGRlIGxhIGzDrW5lYSBwdW50ZWFkYSBob3Jpem9udGFsLCBjb3JyZXNwb25kaWVudGUgYSBsYSBkaW1lbnNpw7NuIG8gZWplIDEuIEVuIGNhbWJpbywgZW4gbGEgZ3LDoWZpY2EgZGUgbGEgZGVyZWNoYSwgbmluZ3VubyBkZSBsb3MgY2VudHJvcyBkZSBsYXMgZWxpcHNlcyBzZSB1YmljYSBzb2JyZSBhbGd1bmEgZGUgbGFzIGzDrW5lYXMgcHVudGVhZGFzLCBwZXJvIHNlIGRlYmUgcmVzYWx0YXIgcXVlIGNhZGEgdW5vIGRlIGVsbG9zIHNlIHBvc2ljaW9uYSBkZW50cm8gZGUgY2FkYSB1bm8gZGUgbG9zIGN1YWRyYW50ZXMgZW4gcXVlIGVzdMOhIGRpdmlkaWRvIGVsICpiaXBsb3QuKiBFc3RvIG5vcyBwZXJtaXRlIGluZmVyaXIgbGEgbWFuZXJhIGVuIHF1ZSBjYWRhIG51YmUgbyBncnVwbyBkZSBpbmRpdmlkdW9zIHNlIGRpc3RyaWJ1eWUgZW4gbGEgZ3LDoWZpY2EsIGFzw60gY29tbyBsb3MgcGVyZmlsZXMgZGVudHJvIGRlIGNhZGEgZ3J1cG8uXAoKIyBSZWZlcmVuY2lhcwo=