1 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:

  1. Identificar a grupos de individuos con perfiles similares en sus respuestas en las categorías de variables medidas.
  2. 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.

2 Preparación del ambiente.

Antes de comenzar, es recomendable ajustar la configuración de R al ambiente de trabajo.

2.1 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"

2.2 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

2.3 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

3 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.

4 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"

4.1 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.

4.2 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)
*Scree plot* o porcentajes de inercia explicada por cada dimensión nueva.

Scree plot o porcentajes de inercia explicada por cada dimensión nueva.

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)

4.3 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
 Biplot o gráfica con la proyección de individuos y variables.

Biplot o gráfica con la proyección de individuos y variables.

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)

4.4 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"

5 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

5.1 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()
            )
Biplot de correlaciones entre variables y dimensiones.

Biplot de correlaciones entre variables y dimensiones.

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.

5.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
Biplot de asociación entre categorías y dimensiones

Biplot de asociación entre categorías y dimensiones

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
Biplot de asociación entre categorías y dimensiones y cambio de colores.

Biplot de asociación entre categorías y dimensiones y cambio de colores.

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.

5.3 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
Biplot de asociación entre categorías y dimensiones con señalización de la calidad de representación.

Biplot de asociación entre categorías y dimensiones con señalización de la calidad de representación.

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
Biplot de asociación entre categorías y dimensiones con transparencia según el nivel de calidad.

Biplot de asociación entre categorías y dimensiones con transparencia según el nivel de calidad.

5.4 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 las dimensiones 1 y 2.

Contribución de las categorías a las dimensiones 1 y 2.

# 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
Contribución de las categorías a las dimensiones 1 y 2.

Contribución de las categorías a las dimensiones 1 y 2.

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
Contribución total de las categorías a las dimensiones 1 y 2.

Contribución total de las categorías a las dimensiones 1 y 2.

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
Biplot de distribución de las categorías activas señaladas por su contribución a cada dimensión.

Biplot de distribución de las categorías activas señaladas por su contribución a cada dimensión.

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
Biplot de la distribución de las categorías señalando su contribución mediante el nivel de transparencia de sus puntos geométricos.

Biplot de la distribución de las categorías señalando su contribución mediante el nivel de transparencia de sus puntos geométricos.

6 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.

6.1 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
Biplot de distribución de los encuestados por Latinobarómetro, señalados por la calidad de su representación en el gráfico (cos2).

Biplot de distribución de los encuestados por Latinobarómetro, señalados por la calidad de su representación en el gráfico (cos2).

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.

6.2 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
Biplot de distribución de los encuestados por Latinobarómetro, señalados por la contribución de su representación en el gráfico.

Biplot de distribución de los encuestados por Latinobarómetro, señalados por la contribución de su representación en el gráfico.

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
Gráficas de barras para los 20 casos con mayor contribución a las dimensiones 1 y 2.

Gráficas de barras para los 20 casos con mayor contribución a las dimensiones 1 y 2.

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)
Gráfica de barras sobre la calidad de representación de cada individuo sobre los ejes 1 y 2.

Gráfica de barras sobre la calidad de representación de cada individuo sobre los ejes 1 y 2.

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

7 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()
             )
Biplot con la distribución de los individuos, agrupados por colores y con elipses de confianza.

Biplot con la distribución de los individuos, agrupados por colores y con elipses de confianza.

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=