Ejemplo: Enunciado
Base de datos
Los datos se recogieron aplicando una encuesta a una muestra de estudiantes universitarios. Es un data frame con 800 observaciones y 66 variables.
datosCompleto <- lsm::survey
#datosCompleto <- textshape::column_to_rownames(dat, loc=1)
#datosCompleto %>% remove_rownames %>% column_to_rownames(var="names") #library(tidyverse)
attach(datosCompleto)
names(datosCompleto)
## [1] "Observation" "ID" "Gender" "Like" "Age"
## [6] "Smoke" "Height" "Weight" "BMI" "School"
## [11] "SES" "Enrollment" "Score" "MotherHeight" "MotherAge"
## [16] "MotherCHD" "FatherHeight" "FatherAge" "FatherCHD" "Status"
## [21] "SemAcum" "Exam1" "Exam2" "Exam3" "Exam4"
## [26] "ExamAcum" "Definitive" "Expense" "Income" "Gas"
## [31] "Course" "Law" "Economic" "Race" "Region"
## [36] "EMO1" "EMO2" "EMO3" "EMO4" "EMO5"
## [41] "GOAL1" "GOAL2" "GOAL3" "Pre_STAT1" "Pre_STAT2"
## [46] "Pre_STAT3" "Pre_STAT4" "Post_STAT1" "Post_STAT2" "Post_STAT3"
## [51] "Post_STAT4" "Pre_IDARE1" "Pre_IDARE2" "Pre_IDARE3" "Pre_IDARE4"
## [56] "Pre_IDARE5" "Post_IDARE1" "Post_IDARE2" "Post_IDARE3" "Post_IDARE4"
## [61] "Post_IDARE5" "PSICO1" "PSICO2" "PSICO3" "PSICO4"
## [66] "PSICO5"
Datos para el CA
Los datos deben ser una tabla de contingencia. Por esta razón, solo consideraremos las siguientes dos variables para realizar el análisis de correspondencia:
Post_STAT1
: “I like statistics”, con las siguientes codificaciones: 1= Strongly disagree; 2= Disagree; 3= Undecided; 4= Agree; 5= Strongly agree.
PSICO1
: “I feel good”, con las siguientes codificaciones: 1=Almost never; 2= Sometimes; 3= Frequently; 4= Almost always.
df <- datosCompleto[,c(48,62)]
names(df) <- c("Stat_num", "Psico_a")
attach(df)
# Cambiar los niveles de la variable STAT
df$Stat <- factor(df$Stat_num, levels = c(1, 2, 3, 4, 5), labels = c("1.Str.Disagree", "2.Disagree", "3.Undecided", "4.Agree", "5.Str.Agree"))
# Cambiar los niveles de la variable Psico
df$Psico <- factor(df$Psico_a, levels = c("Almost never", "Sometimes", "Frequently", "Almost always"), labels = c("1.Never", "2.Some.", "3.Freq.", "4.Always"))
attach(df)
Ejemplo: Solución (gráfica de tablas)
balloonplot
: general
La tabla de contingencia anterior no es muy grande. Por lo tanto, es fácil inspeccionar visualmente e interpretar los perfiles de filas y columnas. La tabla de contingencia puede visualizarse utilizando las funciones balloonplot
del paquete gplots
y mosaicplot
del paquete graphics
.
library(gplots)
# Convertir los datos como una tabla
tabla <- as.table(as.matrix(dat))
# Grafica el balloonplot con el tamaño de fuente ajustado
balloonplot(t(tabla), main ="Statistic vs Feeling",
xlab ="I feel good:",
ylab="I like Stat:",
label = FALSE,
show.margins = TRUE,
#show.margins = FALSE
)
balloonplot
: otros argumentos
Tenga en cuenta que las sumas de filas y columnas se imprimen por defecto en los márgenes inferior y derecho, respectivamente.
respectivamente. Estos valores se ocultan, en el gráfico anterior, utilizando el argumento show.margins = FALSE
.
library(ggpubr)
tabla.df <- data.frame(t(tabla))
#Defino paleta de colores
#my_cols <- c("#0D0887FF", "#6A00A8FF", "#B12A90FF","#E16462FF", "#FCA636FF", "#F0F921FF")
my_cols <- c("blue", "white", "red")
ggballoonplot(tabla.df, main ="Estadística vs Sentimiento",
xlab ="Me siento bien",
ylab="Me gusta la Estadística",
fill = "value",
size=10,
#shape = 23,
show.label = TRUE
)+
scale_fill_gradientn(colors = my_cols)

Ejemplo: Solución (visualización)
Visualización e interpretación
Utilizaremos las siguientes funciones [en factoextra
] para ayudar en la interpretación y visualización del análisis de correspondencias:
get_eigenvalue(res.ca)
: Extrae los valores propios/varianzas retenidas por cada dimensión (eje)
fviz_eig(res.ca)
: Visualiza los valores propios
get_ca_row(res.ca)
, get_ca_col(res.ca)
: Extrae los resultados para filas y columnas, respectivamente.
fviz_ca_row(res.ca)
, fviz_ca_col(res.ca)
: Visualiza los resultados para filas y columnas, respectivamente.
fviz_ca_biplot(res.ca)
: Crea un biplot de filas y columnas.
En las secciones siguientes, ilustraremos cada una de estas funciones.
Significancia estadística
Para las interpretaciones que se obtengan con el análisis de correspondencia, primero, es necesario determinar si hay una dependencia significativa entre las filas y columnas. Un enfoque riguroso es utilizar la estadística de chi-cuadrado para examinar la asociación entre las variables de fila y columna. Esta información se encuentra en la parte superior del informe generado por la función summary(res.ca)
o print(res.ca)
.
summary(res.ca)
##
## Call:
## CA(X = tabla, graph = FALSE)
##
## The chi square of independence between the two variables is equal to 24.71265 (p-value = 0.01624481 ).
##
## Eigenvalues
## Dim.1 Dim.2 Dim.3
## Variance 0.024 0.006 0.000
## % of var. 78.194 20.237 1.569
## Cumulative % of var. 78.194 98.431 100.000
##
## Rows
## Iner*1000 Dim.1 ctr cos2 Dim.2 ctr cos2
## 1.Str.Disagree | 5.812 | -0.112 11.072 0.462 | 0.120 49.444 0.534 |
## 2.Disagree | 0.444 | -0.004 0.013 0.007 | 0.025 1.971 0.278 |
## 3.Undecided | 8.600 | -0.167 23.366 0.659 | -0.121 46.772 0.341 |
## 4.Agree | 0.228 | 0.017 0.215 0.229 | -0.013 0.528 0.145 |
## 5.Str.Agree | 15.923 | 0.285 65.334 0.995 | -0.020 1.285 0.005 |
## Dim.3 ctr cos2
## 1.Str.Disagree 0.011 5.166 0.004 |
## 2.Disagree -0.040 65.260 0.715 |
## 3.Undecided 0.000 0.000 0.000 |
## 4.Agree 0.028 29.303 0.626 |
## 5.Str.Agree 0.003 0.272 0.000 |
##
## Columns
## Iner*1000 Dim.1 ctr cos2 Dim.2 ctr cos2
## 1.Never | 21.624 | 0.752 87.824 0.985 | -0.091 5.007 0.015 |
## 2.Some. | 5.110 | 0.036 1.194 0.057 | 0.148 76.825 0.943 |
## 3.Freq. | 3.518 | -0.075 10.972 0.756 | -0.039 11.315 0.202 |
## 4.Always | 0.755 | -0.003 0.009 0.003 | -0.040 6.852 0.570 |
## Dim.3 ctr cos2
## 1.Never -0.021 3.405 0.001 |
## 2.Some. -0.001 0.023 0.000 |
## 3.Freq. -0.018 30.284 0.042 |
## 4.Always 0.035 66.288 0.427 |
Un valor alto de la estadística de chi-cuadrado indica una fuerte conexión entre las variables de fila y columna. En nuestro ejemplo, la asociación es altamente significativa (chi-cuadrado = 24.7126467, p-valor = 0.0162448).
#Chi-square statistics
chi2 <- chisq_test$statistic
# Degree of freedom
df <- (nrow(tabla) - 1) * (ncol(tabla) - 1)
# P-value
pval <- pchisq(chi2, df = df, lower.tail = FALSE)
pval
## X-squared
## 0.01624481
Valores y vectores propios
Primero, recordemos que evaluamos los eigenvalores para determinar la cantidad de ejes a considerar. Podemos obtener los eigenvalores y la proporción de varianza retenida por los diferentes ejes utilizando la función get_eigenvalue
del paquete factoextra
. Los eigenvalores son grandes para el primer eje y pequeños para los ejes siguientes.
library(factoextra)
eig.val <- get_eigenvalue(res.ca)
eig.val
## eigenvalue variance.percent cumulative.variance.percent
## Dim.1 0.0242457526 78.194234 78.19423
## Dim.2 0.0062749588 20.237178 98.43141
## Dim.3 0.0004863735 1.568588 100.00000
Los valores propios representan la cantidad de información preservada por cada eje. Las dimensiones se ordenan de manera descendente y se enumeran según la varianza explicada en la solución. La primera dimensión explica la mayor parte de la varianza, seguida por la segunda dimensión, y así sucesivamente.
El porcentaje acumulado explicado se obtiene sumando las proporciones sucesivas de variación explicada para obtener el total acumulado. Por ejemplo, 78.19% más 20.24% es igual a 98.43%, y así sucesivamente. Por lo tanto, aproximadamente el 98.43% de la variación está explicada por las primeras dos dimensiones.
Los valores propios se pueden utilizar para determinar el número de ejes a retener. No hay una “regla general” para elegir el número de dimensiones a mantener para la interpretación de los datos. Depende de la pregunta de investigación y de las necesidades del investigador. Por ejemplo, si el investigador está satisfecho con el 80% de las varianzas totales explicadas, entonces debe usar el número de dimensiones necesario para lograr eso.
Se debe tener en cuenta que una buena reducción de dimensiones se logra cuando las primeras dimensiones explican una gran proporción de la variabilidad.
En nuestro análisis, el primer eje explica el 78.19% de la variación. Este es un porcentaje acpatblemente grande.
Scree plot
Un método alternativo para determinar el número de dimensiones es observar un gráfico Scree, que es el gráfico de valores propios/varianzas ordenados de mayor a menor. El número de componentes se determina en el punto en el que los valores propios restantes son todos relativamente pequeños y de tamaño comparable. El gráfico Scree se puede producir utilizando la función fviz_eig
o fviz_screeplot
del paquete factoextra
.
fviz_screeplot(res.ca, addlabels = TRUE, ylim = c(0, 100))
El punto en el que el scree plot muestra una curvatura (llamada “codo”, “elbow”) puede considerarse como indicativo de una dimensionalidad óptima. También es posible calcular un valor propio promedio por encima del cual el eje debe mantenerse en la solución.
Nuestros datos contienen 5 filas y 4 columnas. Si los datos fueran aleatorios, el valor esperado del valor propio para cada eje sería
\[\frac{1}{\mbox{Número de filas}\; -\; 1} \;=\; \frac{1}{4} \;=\; 25\% \quad \mbox{en términos de filas} \]
1/(nrow(tabla) -1)
## [1] 0.25
Del mismo modo, el eje promedio debería representar
\[\frac{1}{\mbox{Número de columnas}\; -\; 1} \;=\; \frac{1}{3} \;=\; 33.3\% \quad \mbox{en términos de las 4 columnas} \]
1/(ncol(tabla) -1)
## [1] 0.3333333
Se resalta el hecho de que cualquier eje con una contribución mayor que el máximo de estos dos porcentajes debe considerarse importante e incluirse en la solución para la interpretación de los datos. El código R a continuación dibuja elscree plot con una línea roja discontinua que especifica el valor propio promedio:
fviz_screeplot(res.ca) +
geom_hline(yintercept=33.33, linetype=2, color="red")

El gráfico indica que solo se deben utilizar la dimensión 1 para la solución. Las dimensiones 2 y 3, que solo explican el 21.81% de la inercia total, está por debajo del valor propio promedio (33.33%) y es demasiado insignificante para un análisis adicional. Aunque se pueden emplear más de 1 dimensión, es improbable que las dimensiones adicionales contribuyan significativamente a comprender la relación entre las filas y columnas. La dimensión 1 representa aproximadamente el 78.19% de la inercia total, respectivamente, lo que equivale a un total acumulado del 78.19% de la inercia retenida por esta dimensión.
Biplot
La función fviz_ca_biplot
del paquete factoextra
puede ser usado para dibujar el biplot de las variables filas y columnas.
#repel= TRUE para evitar traslapamiento de textos
fviz_ca_biplot(res.ca, repel = TRUE)

Observaciones:
El gráfico anterior se denomina diagrama simétrico (symetric plot).
Muestra un patrón global dentro de los datos.
Las filas están representadas por puntos azules y las columnas por triángulos rojos.
La distancia entre cualquier par de puntos de fila o columna proporciona una medida de su similitud (o disimilitud).
Los puntos de fila con perfiles similares están cerca en el mapa de factores. Lo mismo ocurre para los puntos de columna.
Representa los perfiles de fila y columna simultáneamente en un espacio común. En este caso, solo la distancia entre puntos de fila o la distancia entre puntos de columna puede ser realmente interpretada. La distancia entre cualquier ítem de fila y columna no tiene un significado claro. Solo se pueden hacer afirmaciones generales sobre el patrón observado.
Para interpretar la distancia entre puntos de columna y fila, los perfiles de columna deben presentarse en el espacio de fila o viceversa. Este tipo de mapa se denomina biplot asimétrico y se describe en siguientes secciones.
El siguiente paso para la interpretación es determinar qué variables de fila y columna contribuyen más en la definición de las diferentes dimensiones retenidas en el modelo.
Interpreataciones para nuestro ejemplo:
En nuestro ejemplo, este gráfico muestra que:
Las personas que algunas veces se sienten bien, están completamente en desacuerdo de que les gusta la estadística.
Las personas que casi siempre se sienten bien, están de acuerdo en que les gusta la estadística.
Ejemplo: Solución (get_ca_row
)
Argumentos de get_ca_row
Primero, la función get_ca_row
en factoextra
se utiliza para extraer los resultados de las variables de fila. Esta función devuelve una lista que contiene las coordenadas
, cos2
, contribución
y inercia
de las variables de fila.
row <- get_ca_row(res.ca)
row
## Correspondence Analysis - Results for rows
## ===================================================
## Name Description
## 1 "$coord" "Coordinates for the rows"
## 2 "$cos2" "Cos2 for the rows"
## 3 "$contrib" "contributions of the rows"
## 4 "$inertia" "Inertia of the rows"
Primero, los elementos de la función get_ca_row
pueden utilizarse en la representación de filas de la siguiente manera:
row$coord
: coordenadas de cada punto de fila en cada dimensión (1, 2 y 3). Se utilizan para crear el gráfico de dispersión.
row$cos2
: calidad de representación de las filas.
col$contrib
: contribución de las filas (en %) a la definición de las dimensiones.
Es posible graficar los puntos de fila y colorearlos según:
su calidad en el mapa factorial (cos2
) o
sus valores de contribución a la definición de dimensiones (contrib
).
Valores de get_ca_row
Los diferentes componentes pueden accederse de la siguiente manera:
# Coordenadas de puntos de filas
head(row$coord)
# Cos2: calidad del mapa factorial
head(row$cos2)
# Contribuciones a las componenentes principales
head(row$contrib)
Primero, explicamos cómo visualizar solo los puntos de fila. Luego, destacamos las filas según:
Su calidad de representación en el mapa factorial o
sus contribuciones a las dimensiones.
Ejemplo: Solución (row$coord
)
row$coord
: valores
El código R proporcionado muestra las coordenadas de cada punto de fila en cada dimensión (1, 2 y 3):
head(row$coord)
## Dim 1 Dim 2 Dim 3
## 1.Str.Disagree -0.111854843 0.12025260 1.082141e-02
## 2.Disagree -0.003954693 0.02474074 -3.963913e-02
## 3.Undecided -0.167466854 -0.12053505 8.418317e-05
## 4.Agree 0.016707622 -0.01331322 2.761046e-02
## 5.Str.Agree 0.285397494 -0.02036543 2.605985e-03
row$coord
: gráficas
Use la función fviz_ca_row
del paquete factoextra
para visualizar solo puntos de filas:
fviz_ca_row(res.ca, repel = TRUE)

row$coord
: gráficas (col.row
, shape.row
)
Se puede modificar el color y la forma de los puntos de fila utilizando los argumentos col.row
y shape.row
de la siguiente manera:
fviz_ca_row(res.ca, col.row="steelblue", shape.row = 15)

El diagrama exhibe las relaciones entre los puntos de fila:
Las filas que comparten un perfil parecido están agrupadas.
Las filas con correlación negativa se ubican en lados opuestos del origen del diagrama (cuadrantes contrapuestos).
La distancia entre los puntos de fila y el origen evalúa la calidad de los puntos de fila en el mapa de factores. Los puntos de fila que se encuentran distantes del origen están bien representados en el mapa de factores.
Ejemplo: Solución (row$cos2
)
row$cos2
: calidad de la representación
El análisis ha demostrado que se pudo representar la tabla de contingencia en un espacio de baja dimensión mediante el análisis de correspondencia. Las dimensiones 1 y 2 son suficientes para retener la mayor parte de la variación de los datos. Aunque, es importante tener en cuenta que algunos puntos no se muestran tan bien en ambas dimensiones. La calidad de la representación de las filas en el mapa de factores se evalúa mediante el coseno al cuadrado (cos2
) o las correlaciones al cuadrado, que indican la asociación entre las filas/columnas y un eje específico. El cos2
de los puntos de las filas se puede calcular de la siguiente manera:
head(row$cos2, 4)
## Dim 1 Dim 2 Dim 3
## 1.Str.Disagree 0.461861598 0.5338156 4.322851e-03
## 2.Disagree 0.007112126 0.2783552 7.145327e-01
## 3.Undecided 0.658741127 0.3412587 1.664591e-07
## 4.Agree 0.229046707 0.1454323 6.255210e-01
row$cos2
: interpetaciones resumidas
Los valores de cos2
están comprendidos entre 0 y 1.
La suma de los cos2
para las filas en todas las dimensiones de CA es igual a uno.
La calidad de la representación de una fila o columna en n dimensiones es simplemente la suma del coseno al cuadrado de esa fila o columna sobre las $n4 dimensiones.
Si un elemento de fila está bien representado por dos dimensiones, la suma de los cos2
se acerca a uno.
Para algunos de los elementos de fila, se requieren más de 2 dimensiones para representar perfectamente los datos.
row$cos2
: argumento gradient.cols
Es posible colorear los puntos de las filas según sus valores de cos2
utilizando el argumento col.row = "cos2"
. Esto produce colores degradados. En este caso, se puede utilizar el argumento gradient.cols
para proporcionar un color personalizado.
Por ejemplo, gradient.cols = c("green", "brown", "blue")
significa que:
Las variables con valores bajos de cos2
serán coloreadas en verde.
Las variables con valores medios de cos2
serán coloreadas en marrón.
Las variables con valores altos de cos2
serán coloreadas en azul.
# Color por valores cos2: caliad del mapa factorial
MisColores <- c("green", "brown", "blue")
fviz_ca_row(res.ca, col.row = "cos2",
gradient.cols = MisColores,
repel = TRUE)

row$cos2
: transpariencias con alpha.var
También es posible ajustar la transparencia de las variables según los valores de cos2
utilizando la opción alpha.row = "cos2"
:
# Cambiar la transpariencia por valores de cos2
fviz_ca_row(res.ca, alpha.row = "cos2",
col.row = "red",
title="Transpariencia de las filas por cos2",
repel = TRUE # Evita traslapamiento de textos
)

row$cos2
: correlaciones
Se puede representar gráficamente el cos2
de los puntos de fila en todas las dimensiones utilizando el paquete corrplot
.
library("corrplot")
corrplot(row$cos2,
is.corr=FALSE, # Se puede activar o no
tl.col = "black",
#addCoef.col = 'grey50', #Agregar valores
#number.cex = 0.7, #Tamaño de los valores
tl.srt = 90,
bg = "lightblue", #Color del fondo
title="Matriz de correlaciones",
#tl.cex=1.5, #Tamaño de las fuentes
#cex.main=2.0, #Tamaño del título
#type="lower",
mar=c(0,0,4,0)
)

Se debe tener en cuenta que todos los puntos de fila excepto 4.Agree
y 2.Disagree
están bien representados por las dos primeras dimensiones. Esto sugiere que la posición del punto correspondiente a esos ítems en el gráfico de dispersión debe interpretarse con cierta precaución. Es probable que una solución de dimensiones superiores sea necesaria para los ítems mencionados.
row$cos2
: diagrama de barras
También es posible crear un diagrama de barra para lo valores cos2
usando la función fviz_cos2
del paquete
factoextra
.
# Cos2 de las filas sobre las dimensiones 1 y 2
fviz_cos2(res.ca, choice = "row", axes = 1:2)

Ejemplo: Solución (row$contrib
)
row$contrib
: general
La contribución de las filas (en %) a la definición de las dimensiones se puede extraer de la siguiente manera:
head(row$contrib)
## Dim 1 Dim 2 Dim 3
## 1.Str.Disagree 11.07163352 49.4442575 5.165779e+00
## 2.Disagree 0.01303039 1.9705261 6.525984e+01
## 3.Undecided 23.36628187 46.7717224 2.943393e-04
## 4.Agree 0.21523931 0.5280598 2.930254e+01
## 5.Str.Agree 65.33381490 1.2854342 2.715484e-01
Las variables de fila con un valor más alto son las que más contribuyen a la definición de las dimensiones.
Las filas que más contribuyen a Dim.1
y Dim.2
son las más importantes para explicar la variabilidad en el conjunto de datos.
Las filas que no contribuyen mucho a ninguna dimensión o que contribuyen a las últimas dimensiones son menos importantes.
row$contrib
: correlaciones
Es posible utilizar la función corrplot
del paquete corrplot
para resaltar los puntos de fila que más contribuyen para cada dimensión:
library("corrplot")
corrplot(row$contrib,
is.corr=FALSE, #No se puede desactivar este argumento
tl.col = "black",
#addCoef.col = 'grey50', #Agregar valores
#number.cex = 0.7, #Tamaño de los valores
tl.srt = 90,
bg = "lightblue", #Color del fondo
title="Matriz de correlaciones",
#tl.cex=1.5, #Tamaño de las fuentes
#cex.main=2.0, #Tamaño del título
#type="lower",
mar=c(0,0,4,0) #Ubicación del título
)

row$contrib
: diagramas de barra de cada variable
La función fviz_contrib
del paquete factoextra
se puede emplear para dibujar un gráfico de barras de las contribuciones de las filas. Si los datos contienen muchas filas, se puede optar por mostrar solo las filas que más contribuyen. El siguiente código en R muestra las 10 filas principales que contribuyen a las dimensiones.
# Contribuciones de las variables a la dimensión 1
p1 <- fviz_contrib(res.ca, choice = "row", axes = 1, top = 10)
# Contribuciones de las variables a la dimensión 2
p2 <- fviz_contrib(res.ca, choice = "row", axes = 2, top = 10)

row$contrib
: diagrama de barra para la total
A continuación, se puede visualizar la contribución total a las dimensiones 1 y 2:
fviz_contrib(res.ca, choice = "row", axes = 1:2, top = 10)

row$contrib
: Interpretaciones
Interpretación No. 1:
La línea roja discontinua en el gráfico anterior indica la contribución promedio esperada.
Interpretación No. 2:
Si la contribución de las variables fuese uniforme, el valor esperado sería
\[\frac{1}{\mbox{longitud(filas)}} \;=\; \frac{1}{5}(100)\;=\; 20\, \%\]
(1/nrow(tabla))*100
## [1] 20
Interpretación No. 3:
Para una dimensión dada, una fila con una contribución mayor que este umbral podría considerarse importante en la contribución a la dimensión.
Interpretación No. 4:
Se puede observar que la variable 5.Str.Agree
contribuye más a las dimensiones 1 y 2.
row$contrib
: argumento gradient.cols
Como ya se explicó, gradient.cols = c("green", "brown", "blue")
significa que:
Las variables con valores bajos de cos2
serán coloreadas en verde.
Las variables con valores medios de cos2
serán coloreadas en marrón.
Las variables con valores altos de cos2
serán coloreadas en azul.
MisColores <- c("green", "brown", "blue")
fviz_ca_row(res.ca, col.row = "contrib",
repel= TRUE, # Evita traslapamiento de textos,
gradient.cols = MisColores,
)

Interpretaciones:
El gráfico de dispersión ofrece una idea de qué polo de las dimensiones están contribuyendo realmente las categorías de las filas.
Es evidente que las categorías de filas 1.Sdr.Disagree
, y 3.Undecided
tienen una contribución importante al polo negativo de la primera dimensión.
Mientras que la categoría 5.Str.Agee
tienen una contribución mayor al polo positivo de la primera dimensión; etc., …
En otras palabras, la dimensión 1 está principalmente definida por la oposición de 1.Sdr.Disagree
, y 3.Undecided
(polo negativo), y 5.Str.Agee
(polo positivo).
row$contrib
: transpariencias con alpha.var
Tenga en cuenta que también es posible cambiar la transparencia de las filas según sus valores de contribución utilizando la opción alpha.row = "contrib"
:
# Cambiar la transpariencia para las contribuciones
fviz_ca_row(res.ca, alpha.row = "contrib",
col.row = "red",
#title="Transpariencia de las variables por contribución",
repel= TRUE # Evita traslapamiento de textos,
)
Ejemplo: Solución (get_ca_col
)
Argumentos de get_ca_col
Primero, la función get_ca_col
en factoextra
se utiliza para extraer los resultados de las variables de columna. Esta función devuelve una lista que contiene las coordenadas
, cos2
, contribución
y inercia
de las variables de columna.
col <- get_ca_col(res.ca)
col
## Correspondence Analysis - Results for columns
## ===================================================
## Name Description
## 1 "$coord" "Coordinates for the columns"
## 2 "$cos2" "Cos2 for the columns"
## 3 "$contrib" "contributions of the columns"
## 4 "$inertia" "Inertia of the columns"
Primero, los elementos de la función get_ca_col
pueden utilizarse en la representación de columnas de la siguiente manera:
col$coord
: coordenadas de cada punto de columna en cada dimensión (1, 2 y 3). Se utilizan para crear el gráfico de dispersión.
col$cos2
: calidad de representación de las columnas.
col$contrib
: contribución de las columnas (en %) a la definición de las dimensiones.
Es posible graficar los puntos de columna y colorearlos según:
su calidad en el mapa factorial (cos2
) o
sus valores de contribución a la definición de dimensiones (contrib
).
Valores de get_ca_col
Los diferentes componentes pueden accederse de la siguiente manera:
# Coordenadas de puntos de columnas
head(col$coord)
# Cos2: calidad del mapa factorial
head(col$cos2)
# Contribuciones a las componenentes principales
head(col$contrib)
Primero, explicamos cómo visualizar solo los puntos de columna. Luego, destacamos las columnas según:
Su calidad de representación en el mapa factorial o
sus contribuciones a las dimensiones.
Ejemplo: Solución (col$coord
)
col$coord
: valores
El código R proporcionado muestra las coordenadas de cada punto de columna en cada dimensión (1, 2 y 3):
head(col$coord)
## Dim 1 Dim 2 Dim 3
## 1.Never 0.752130742 -0.09136182 -0.0209745336
## 2.Some. 0.036317454 0.14817248 -0.0007129501
## 3.Freq. -0.074894871 -0.03869211 -0.0176229137
## 4.Always -0.002846801 -0.04001735 0.0346516993
col$coord
: gráficas
Use la función fviz_ca_col
del paquete factoextra
para visualizar solo puntos de columnas:
fviz_ca_col(res.ca, repel = TRUE)

col$coord
: gráficas (col.col
, shape.col
)
Se puede modificar el color y la forma de los puntos de columna utilizando los argumentos col.col
y shape.col
de la siguiente manera:
fviz_ca_col(res.ca, col.col="steelblue", shape.col = 15)

El diagrama exhibe las relaciones entre los puntos de columna:
Las columnas que comparten un perfil parecido están agrupadas.
Las columnas con correlación negativa se ubican en lados opuestos del origen del diagrama (cuadrantes contrapuestos).
La distancia entre los puntos de columna y el origen evalúa la calidad de los puntos de columna en el mapa de factores. Los puntos de columna que se encuentran distantes del origen están bien representados en el mapa de factores.
Ejemplo: Solución (col$cos2
)
col$cos2
: calidad de la representación
El análisis ha demostrado que se pudo representar la tabla de contingencia en un espacio de baja dimensión mediante el análisis de correspondencia. Las dimensiones 1 y 2 son suficientes para retener la mayor parte de la variación de los datos. Aunque, es importante tener en cuenta que algunos puntos no se muestran tan bien en ambas dimensiones. La calidad de la representación de las columnas en el mapa de factores se evalúa mediante el coseno al cuadrado (cos2
) o las correlaciones al cuadrado, que indican la asociación entre las columnas/columnas y un eje específico. El cos2
de los puntos de las columnas se puede calcular de la siguiente manera:
head(col$cos2, 4)
## Dim 1 Dim 2 Dim 3
## 1.Never 0.984704779 0.01452944 7.657799e-04
## 2.Some. 0.056669516 0.94330864 2.183921e-05
## 3.Freq. 0.756279688 0.20184735 4.187296e-02
## 4.Always 0.002883846 0.56984185 4.272743e-01
col$cos2
: interpetaciones resumidas
Los valores de cos2
están comprendidos entre 0 y 1.
La suma de los cos2
para las columnas en todas las dimensiones de CA es igual a uno.
La calidad de la representación de una columna o columna en n dimensiones es simplemente la suma del coseno al cuadrado de esa columna o columna sobre las $n4 dimensiones.
Si un elemento de columna está bien representado por dos dimensiones, la suma de los cos2
se acerca a uno.
Para algunos de los elementos de columna, se requieren más de 2 dimensiones para representar perfectamente los datos.
col$cos2
: argumento gradient.cols
Es posible colorear los puntos de las columnas según sus valores de cos2
utilizando el argumento col.col = "cos2"
. Esto produce colores degradados. En este caso, se puede utilizar el argumento gradient.cols
para proporcionar un color personalizado.
Por ejemplo, gradient.cols = c("green", "brown", "blue")
significa que:
Las variables con valores bajos de cos2
serán coloreadas en verde.
Las variables con valores medios de cos2
serán coloreadas en marrón.
Las variables con valores altos de cos2
serán coloreadas en azul.
# Color por valores cos2: caliad del mapa factorial
MisColores <- c("green", "brown", "blue")
fviz_ca_col(res.ca, col.col = "cos2",
gradient.cols = MisColores,
repel = TRUE)

col$cos2
: transpariencias con alpha.var
También es posible ajustar la transparencia de las variables según los valores de cos2
utilizando la opción alpha.col = "cos2"
:
# Cambiar la transpariencia por valores de cos2
fviz_ca_col(res.ca, alpha.col = "cos2",
col.col = "red",
title="Transpariencia de las columnas por cos2",
repel = TRUE # Evita traslapamiento de textos
)

col$cos2
: correlaciones
Se puede representar gráficamente el cos2
de los puntos de columna en todas las dimensiones utilizando el paquete corrplot
.
library("corrplot")
corrplot(col$cos2,
is.corr=FALSE, # Se puede activar o no
tl.col = "black",
#addCoef.col = 'grey50', #Agregar valores
#number.cex = 0.7, #Tamaño de los valores
tl.srt = 90,
bg = "lightblue", #Color del fondo
title="Matriz de correlaciones",
#tl.cex=1.5, #Tamaño de las fuentes
#cex.main=2.0, #Tamaño del título
#type="lower",
mar=c(0,0,4,0)
)

Se debe tener en cuenta que todos los puntos de columna excepto 4.Agree
y 2.Disagree
están bien representados por las dos primeras dimensiones. Esto sugiere que la posición del punto correspondiente a esos ítems en el gráfico de dispersión debe interpretarse con cierta precaución. Es probable que una solución de dimensiones superiores sea necesaria para los ítems mencionados.
col$cos2
: diagrama de barras
También es posible crear un diagrama de barra para lo valores cos2
usando la función fviz_cos2
del paquete
factoextra
.
# Cos2 de las columnas sobre las dimensiones 1 y 2
fviz_cos2(res.ca, choice = "col", axes = 1:2)

Recordar:
El valor de cos2
está entre 0 y 1.
Un cos2
cercano a 1 corresponde a variables de columna/fila que están bien representadas en el mapa factorial.
Observa que solo el elemento de columna 4.Always
no se muestra muy bien en las dos primeras dimensiones. La posición de este elemento debe interpretarse con precaución en el espacio formado por las dimensiones 1 y 2.
Ejemplo: Solución (col$contrib
)
col$contrib
: general
La contribución de las columnas (en %) a la definición de las dimensiones se puede extraer de la siguiente manera:
head(col$contrib)
## Dim 1 Dim 2 Dim 3
## 1.Never 87.824147724 5.007046 3.40469080
## 2.Some. 1.194468904 76.825244 0.02294712
## 3.Freq. 10.972408380 11.315334 30.28440358
## 4.Always 0.008974992 6.852376 66.28795851
Las variables de columna con un valor más alto son las que más contribuyen a la definición de las dimensiones.
Las columnas que más contribuyen a Dim.1
y Dim.2
son las más importantes para explicar la variabilidad en el conjunto de datos.
Las columnas que no contribuyen mucho a ninguna dimensión o que contribuyen a las últimas dimensiones son menos importantes.
col$contrib
: correlaciones
Es posible utilizar la función corrplot
del paquete corrplot
para resaltar los puntos de columna que más contribuyen para cada dimensión:
library("corrplot")
corrplot(col$contrib,
is.corr=FALSE, #No se puede desactivar este argumento
tl.col = "black",
#addCoef.col = 'grey50', #Agregar valores
#number.cex = 0.7, #Tamaño de los valores
tl.srt = 90,
bg = "lightblue", #Color del fondo
title="Matriz de correlaciones",
#tl.cex=1.5, #Tamaño de las fuentes
#cex.main=2.0, #Tamaño del título
#type="lower",
mar=c(0,0,4,0) #Ubicación del título
)

col$contrib
: diagramas de barra de cada variable
La función fviz_contrib
del paquete factoextra
se puede emplear para dibujar un gráfico de barras de las contribuciones de las columnas. Si los datos contienen muchas columnas, se puede optar por mostrar solo las columnas que más contribuyen. El siguiente código en R muestra las 10 columnas principales que contribuyen a las dimensiones.
# Contribuciones de las variables a la dimensión 1
p1 <- fviz_contrib(res.ca, choice = "col", axes = 1, top = 10)
# Contribuciones de las variables a la dimensión 2
p2 <- fviz_contrib(res.ca, choice = "col", axes = 2, top = 10)

col$contrib
: diagrama de barra para la total
A continuación, se puede visualizar la contribución total a las dimensiones 1 y 2:
fviz_contrib(res.ca, choice = "col", axes = 1:2, top = 10)

col$contrib
: interpretaciones
Interpretación No. 1:
La línea roja discontinua en el gráfico anterior indica la contribución promedio esperada.
Interpretación No. 2:
Si la contribución de las variables fuese uniforme, el valor esperado sería
\[\frac{1}{\mbox{longitud(columnas)}} \;=\; \frac{1}{5}(100)\;=\; 20\, \%\]
(1/nrow(tabla))*100
## [1] 20
Interpretación No. 3:
Para una dimensión dada, una columna con una contribución mayor que este umbral podría considerarse importante en la contribución a la dimensión.
Interpretación No. 4:
Se puede observar que la variable 5.Str.Agree
contribuye más a las dimensiones 1 y 2.
col$contrib
: argumento gradient.cols
Como ya se explicó, gradient.cols = c("green", "brown", "blue")
significa que:
Las variables con valores bajos de cos2
serán coloreadas en verde.
Las variables con valores medios de cos2
serán coloreadas en marrón.
Las variables con valores altos de cos2
serán coloreadas en azul.
MisColores <- c("green", "brown", "blue")
fviz_ca_col(res.ca, col.col = "contrib",
repel= TRUE, # Evita traslapamiento de textos,
gradient.cols = MisColores,
)

Interpretaciones:
El gráfico de dispersión ofrece una idea de qué polo de las dimensiones están contribuyendo realmente las categorías de las columnas.
Es evidente que las categorías de columnas 1.Sdr.Disagree
, y 3.Undecided
tienen una contribución importante al polo negativo de la primera dimensión.
Mientras que la categoría 5.Str.Agee
tienen una contribución mayor al polo positivo de la primera dimensión; etc., …
En otras palabras, la dimensión 1 está principalmente definida por la oposición de 1.Sdr.Disagree
, y 3.Undecided
(polo negativo), y 5.Str.Agee
(polo positivo).
col$contrib
: transpariencias con alpha.var
Tenga en cuenta que también es posible cambiar la transparencia de las columnas según sus valores de contribución utilizando la opción alpha.col = "contrib"
:
# Cambiar la transpariencia para las contribuciones
fviz_ca_col(res.ca, alpha.col = "contrib",
col.col = "red",
#title="Transpariencia de las variables por contribución",
repel= TRUE # Evita traslapamiento de textos,
)

Ejemplo: Solución (biplot
)
El biplot es una representación gráfica de filas y columnas en 2 o 3 dimensiones. Ya hemos descrito cómo crear biplots de AC en secciones anteriore. Aquí, describiremos diferentes tipos de biplots de AC.
biplot
: simétrico
Como se mencionó anteriormente:
El gráfico estándar del análisis de correspondencia es un biplot simétrico en el que tanto las filas (puntos azules) como las columnas (triángulos rojos) están representados en el mismo espacio utilizando las coordenadas principales.
Estas coordenadas representan los perfiles de filas y columnas.
En este caso, solo la distancia entre puntos de fila o la distancia entre puntos de columna puede interpretarse realmente.
Con un gráfico simétrico, la interdistancia entre filas y columnas no puede interpretarse. Solo se pueden hacer afirmaciones generales sobre el patrón.
Recuerde el código R para hacer un biplot simple de individuos y variables:
fviz_ca_biplot(res.ca,
repel = TRUE,
)

- Observe que, para interpretar la distancia entre los puntos de columna y los puntos de fila, la forma más sencilla es hacer un gráfico asimétrico. Esto implica que los perfiles de columna deben presentarse en el espacio de fila o viceversa.
biplot
: asimétrico, descripción
Para crear un biplot asimétrico, se grafican los puntos de las filas (o columnas) a partir de las coordenadas estándar s y los perfiles de las columnas (o las filas) se grafican a partir de las coordenadas principales (P).
Para un eje dado, las coordenadas estándar y principales están relacionadas de la siguiente manera:
\[P \; = \; s \, \sqrt{\lambda}\]
donde
biplot
: asimétrico (fviz_ca_biplot
con map
)
Dependiendo de la situación, se pueden establecer otros tipos de visualización utilizando el argumento map
en la función fviz_ca_biplot
del paquete factoextra
. Las opciones permitidas para el argumento map
son:
rowprincipal
. Estos son los llamados biplots asimétricos, con filas en las coordenadas principales (también conocidos como preservación métrica de fila). En este caso, las columnas están representadas en el espacio de fila
colprincipal
. También llamados biplots asimétricos. En este caso, con columnas en coordenadas estándar (también conocidos como preservación métrica de columna, respectivamente). Para esta situación, las filas están representadas en el espacio de columna.
symbiplot
. Tanto las filas como las columnas se escalan para tener varianzas iguales a los valores singulares (raíces cuadradas de los valores propios), lo que da un biplot simétrico pero no preserva métricas de fila o columna.
rowgab
. Son mapas asimétricos, con filas en coordenadas principales y columnas en coordenadas estándar multiplicadas por la masa.
colgab
. Son mapas asimétricos, con columnas en coordenadas principales y filas en coordenadas estándar multiplicadas por la masa.
colgreen
: Son los llamados biplots de contribución que muestran visualmente los puntos más contribuyentes, con columnas en coordenadas principales y filas en coordenadas estándar multiplicadas por la raíz cuadrada de la masa.
rowgreen
. Son los llamados biplots de contribución que muestran visualmente los puntos más contribuyentes, con filas en coordenadas principales y columnas en coordenadas estándar multiplicadas por la raíz cuadrada de la masa.
biplot
: asimétrico (en R)
El código R a continuación dibuja un biplot asimétrico estándar:
fviz_ca_biplot(res.ca,
map ="rowprincipal",
arrow = c(TRUE, TRUE),
repel = TRUE)
Observaciones:
Observe que se utiliza el argumento arrow
.
arrow
es un vector de dos valores lógicos que especifican si el gráfico debe contener puntos (FALSE, por defecto) o flechas (TRUE).
El primer valor establece las filas y el segundo valor establece las columnas.
Si el ángulo entre dos flechas es agudo, entonces hay una fuerte asociación entre la fila y la columna correspondientes.
Para interpretar la distancia entre filas y una columna, se debería proyectar perpendicularmente los puntos de la fila sobre la flecha de la columna.
biplot
: contribution (general)
En el biplot simétrico estándar (mencionado en la sección anterior), resulta difícil identificar los puntos que más contribuyen a la solución del CA.
Para solucionar este detalle, hay una nueva visualización escalada (llamada biplot de contribución
).
Este gráfico incorpora la contribución de los puntos.
En esta representación, los puntos que contribuyen muy poco a la solución están cerca del centro del biplot y son relativamente poco importantes para la interpretación.
biplot
: contribution (en R)
Un biplot de contribución puede dibujarse utilizando el argumento map = "rowgreen"
o map = "colgreen"
.
En primer lugar, hay que decidir si se analizan las contribuciones de las filas o las columnas a la definición de los ejes.
En nuestro ejemplo, interpretaremos la contribución de las filas a los ejes. Se utiliza el argumento map = "rowgreen"
.
En este caso, hay que recordar que las columnas están en coordenadas principales y las filas en coordenadas estándar multiplicadas por la raíz cuadrada de la masa.
Para una fila dada, el cuadrado de la nueva coordenada en un eje \(j\) es exactamente la contribución de esta fila a la inercia del eje \(j\).
fviz_ca_biplot(res.ca,
map ="colgreen",
arrow = c(TRUE, FALSE),
repel = TRUE)
biplot
: contribution (interpretación)
En el gráfico anterior, la posición de los puntos de perfil de columna no cambia con respecto a la del biplot convencional. Sin embargo, las distancias de los puntos de fila desde el origen del gráfico están relacionadas con sus contribuciones al mapa factorial bidimensional.
Mientras más cerca esté una flecha (en términos de distancia angular) de un eje, mayor es la contribución de la categoría de fila en ese eje en relación con el otro eje.
Si la flecha está a medio camino entre los dos, su categoría de fila contribuye a los dos ejes en la misma medida.
Es evidente que la categoría de fila Str.Agree
tiene una contribución importante al polo positivo de la primera dimensión.
Mientras que las categorías 1.Str.Disagree
y 3.Undecided
tienen una contribución importante al polo negativo de la primera dimensión.
La Dimensión 2 está principalmente definida por las categorías de fila 1.Str.Disagree
y 3.Undecided
.
La categoría de fila 4.Agree
contribuye a los dos ejes en la misma medida.
Ejemplo: Solución (descripción de la dimensión)
dimdesc
: descripción de la dimensión
Para identificar con facilidad los puntos de fila y columna más relacionados con las dimensiones principales, se puede emplear la función dimdesc
en FactoMineR
. Las variables de fila y columna se organizan según sus coordenadas en la salida de dimdesc
.
# Descripción de la dimensión
res.desc <- dimdesc(res.ca, axes = c(1,2))
res.desc
## $`Dim 1`
## $`Dim 1`$row
## coord
## 3.Undecided -0.167466854
## 1.Str.Disagree -0.111854843
## 2.Disagree -0.003954693
## 4.Agree 0.016707622
## 5.Str.Agree 0.285397494
##
## $`Dim 1`$col
## coord
## 3.Freq. -0.074894871
## 4.Always -0.002846801
## 2.Some. 0.036317454
## 1.Never 0.752130742
dimdesc
: dimensión 1 por filas
res.desc[[1]]$row
## coord
## 3.Undecided -0.167466854
## 1.Str.Disagree -0.111854843
## 2.Disagree -0.003954693
## 4.Agree 0.016707622
## 5.Str.Agree 0.285397494
dimdesc
: dimensión 1 por columnas
res.desc[[1]]$col
## coord
## 3.Freq. -0.074894871
## 4.Always -0.002846801
## 2.Some. 0.036317454
## 1.Never 0.752130742
dimdesc
: dimensión 2 por filas
res.desc[[2]]$row
## coord
## 3.Undecided -0.12053505
## 5.Str.Agree -0.02036543
## 4.Agree -0.01331322
## 2.Disagree 0.02474074
## 1.Str.Disagree 0.12025260
dimdesc
: dimensión 2 por columnas
res.desc[[2]]$col
## coord
## 1.Never -0.09136182
## 4.Always -0.04001735
## 3.Freq. -0.03869211
## 2.Some. 0.14817248
Ejercicios
Ejercicio 1
Se tienen datos sobre la adquisición de cuatro marcas específicas de un producto por parte de diferentes grupos de consumidores. Estos datos se presentan en la tabla a continuación, donde cada celda indica la cantidad de personas que regularmente compran el producto de la marca \(i= A, B, C, D\) y pertenecen al grupo \(j=1,2,3\).
datos <- data.frame(
Marca = c("A", "B", "C", "D"),
Grupo_1 = c(30, 30, 80, 80),
Grupo_2 = c(30, 130, 30, 30),
Grupo_3 = c(155, 30, 30, 5)
)
print(datos)
## Marca Grupo_1 Grupo_2 Grupo_3
## 1 A 30 30 155
## 2 B 30 130 30
## 3 C 80 30 30
## 4 D 80 30 5
Aplique CA para validar las percepciones que se deducen de la tabla en cuanto a la proximidad entre las marcas.
Ejercicio 2
Considere la matriz de frecuencias \((n_{ij})\) contenida en la tabla de abajo. En esta tabla, las filas \((i = 1, 2, 3, 4)\) son el color de los ojos y las columnas \((j = 1, 2, 3, 4, 5)\) el color del cabello, cuyas modalidades varían de claro a oscuro. Para encontrar la representación más adecuada de estos datos, es necesario comparar las filas y las columnas de la tabla. Tal comparación implica usar una medida de distancia apropiada. El análisis de correspondencias permite describir las proximidades existentes entre los perfiles, color del cabello (perfil fila) y color de los ojos (perfil columna), de acuerdo con la partición que se haga de los individuos, sea por filas o por columnas. Lleve a cabo el CA correspondiente.
# Crear los vectores para cada fila y columna
Color_de_ojos <- c("O_Claro", "O_Azul", "O_Medio", "O_Oscuro")
Rubio <- c(688, 326, 343, 98)
Rojo <- c(116, 38, 84, 48)
Medio <- c(584, 241, 909, 403)
Oscuro <- c(188, 110, 412, 681)
Negro <- c(4, 3, 26, 85)
Total_ni. <- c(1580, 718, 1774, 1315)
# Calcular los totales por columna
Total_n.j <- c("Total", sum(Rubio), sum(Rojo), sum(Medio), sum(Oscuro), sum(Negro), sum(Total_ni.))
# Construir el data frame
df <- data.frame(Color_de_ojos, Rubio, Rojo, Medio, Oscuro, Negro, Total_ni.)
# Añadir la fila de totales al final del data frame
df <- rbind(df, Total_n.j)
# Cambiar los nombres de las columnas
names(df) <- c("Color", "C_Rubio", "C_Rojo", "C_Medio", "C_Oscuro", "C_Negro", "Total")
df
## Color C_Rubio C_Rojo C_Medio C_Oscuro C_Negro Total
## 1 O_Claro 688 116 584 188 4 1580
## 2 O_Azul 326 38 241 110 3 718
## 3 O_Medio 343 84 909 412 26 1774
## 4 O_Oscuro 98 48 403 681 85 1315
## 5 Total 1455 286 2137 1391 118 5387
Ejercicio 3
El conjunto de datos suicide
de la librería faraway
del software R contiene los datos de un año de suicidios en el Reino Unido clasificados por sexo, edad y método.
library(faraway)
suicide
## y cause age sex
## 1 398 drug y m
## 2 121 gas y m
## 3 455 hang y m
## 4 155 gun y m
## 5 55 jump y m
## 6 124 other y m
## 7 399 drug m m
## 8 82 gas m m
## 9 797 hang m m
## 10 168 gun m m
## 11 51 jump m m
## 12 82 other m m
## 13 93 drug o m
## 14 6 gas o m
## 15 316 hang o m
## 16 33 gun o m
## 17 26 jump o m
## 18 14 other o m
## 19 259 drug y f
## 20 15 gas y f
## 21 95 hang y f
## 22 14 gun y f
## 23 40 jump y f
## 24 38 other y f
## 25 450 drug m f
## 26 13 gas m f
## 27 450 hang m f
## 28 26 gun m f
## 29 71 jump m f
## 30 60 other m f
## 31 154 drug o f
## 32 5 gas o f
## 33 185 hang o f
## 34 7 gun o f
## 35 38 jump o f
## 36 10 other o f
Combine el sexo y la edad de los sujetos en un factor simple de seis niveles que contiene todas las combinaciones de sexo y edad. Conduzca un análisis de correspondencia y dé una interpretación de los gráficos y resultados obtenidos.
Repita el análisis de correspondencia separadamente para hombres y mujeres. ¿Revela este análisis algo nuevo comparado con el análisis combinado del punto anterior?
Ejercicio 4
La tabla de abajo muestra los datos de 538 pacientes que fueron clasificados en función de 4 tipologías de la enfermedad de Hodgkin (LP, NS, MC, LD) y su respuesta a un tratamiento (Positivo, Parcial, Nulo) al cabo de tres meses. Conduzca un análisis de correspondencias y discuta si el tratamiento actúa igual en todas las tipologías.
Tipología <- c("LP", "NS", "MC", "LD")
Positiva <- c(74, 68, 154, 18)
Parcial <- c(18, 16, 54, 10)
Nula <- c(12, 12, 58, 44)
df <- data.frame(Tipología, Positiva, Parcial, Nula)
print(df)
## Tipología Positiva Parcial Nula
## 1 LP 74 18 12
## 2 NS 68 16 12
## 3 MC 154 54 58
## 4 LD 18 10 44
LS0tDQp0aXRsZTogIkFOw4FMSVNJUyBERSBDT1JSRVNQT05ERU5DSUEiDQpzdWJ0aXRsZTogPGgxPioqQXBsaWNhY2nDs24qKjwvaDE+DQoNCmF1dGhvcjogDQogIC0gbmFtZSAgICAgICAgICA6ICJEci4gcmVyLiBuYXQuIEh1bWJlcnRvIExMaW7DoXMgU29sYW5vIg0KICAgIGFmZmlsaWF0aW9uICAgOiAiRGVwYXJ0YW1lbnRvIGRlIE1hdGVtw6F0aWNhcyB5IEVzdGFkw61zdGljYSwgVW5pdmVyc2lkYWQgZGVsIE5vcnRlIChCYXJyYW5xdWlsbGEsIENvbG9tYmlhKSINCiAgICAgI2NvcnJlc3BvbmRpbmcgOiB5ZXMgICAgIyBEZWZpbmUgb25seSBvbmUgY29ycmVzcG9uZGluZyBhdXRob3INCiAgICAgI2FkZHJlc3MgICAgICAgOiAiRGVwYXJ0YW1lbnRvIGRlIE1hdGVtw6F0aWNhcyB5IEVzdGFkw61zdGljYSINCiAgICBlbWFpbCAgICAgICAgIDogfA0KICAgICAgaGxsaW5hc0B1bmlub3J0ZS5lZHUuY28NCiAgICAgIA0KICAgICAgW0Jpb2dyYXBoaWNhbCBza2V0Y2hdKGh0dHBzOi8vcnB1YnMuY29tL2hsbGluYXMvQmlvX1NrZXRjaCkNCiAgICAgIA0KICAgICAgYHIgZm9ybWF0KFN5cy50aW1lKCksICIlZC8lbS8leSIpYCANCiAgICAgIA0KICAgICAjcm9sZTogICAgICAgICAjIENvbnRyaWJ1dG9yc2hpcCByb2xlcyAoZS5nLiwgQ1JlZGlULCBodHRwczovL2Nhc3JhaS5vcmcvY3JlZGl0LykNCiAgIyAgICAtIENvbmNlcHR1YWxpemF0aW9uDQogICMgICAgLSBXcml0aW5nIC0gT3JpZ2luYWwgRHJhZnQgUHJlcGFyYXRpb24NCiAgIyAgICAtIFdyaXRpbmcgLSBSZXZpZXcgJiBFZGl0aW5nDQogIyAtIG5hbWUgICAgICAgICAgOiAiQXV0b3IgbnVtZXJvIDIiDQogIyAgIGFmZmlsaWF0aW9uICAgOiAiMSwyIg0KICMgICByb2xlOg0KICMgICAgIC0gV3JpdGluZyAtIFJldmlldyAmIEVkaXRpbmcNCiAgICAgI2FmZmlsaWF0aW9uOg0KICAjLSBpZCAgICAgICAgICAgIDogIjEiDQogICMgIGluc3RpdHV0aW9uICAgOiAiVW5pdmVyc2lkYWQgZGVsIE5vcnRlIChCYXJyYW5xdWlsbGEsIENvbG9tYmlhKSINCiAgIyFbXShobGxpbmFzLmpwZyl7d2lkdGg9MWlufSANCiAgDQojZGF0ZTogJ2ByIGZvcm1hdChTeXMudGltZSgpLCAiJWQvJW0vJXkiKWAnICAjIHZlciBodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24tY29va2Jvb2svdXBkYXRlLWRhdGUuaHRtbA0Kb3V0cHV0OiANCiAgICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6IA0KICAgICAgICAgICNPSk8gU2FsZW4gY2FwaXR1bG9zLCBzZWNjaW9uZXMgeSBUZW9yZW1hcw0KICAgICNib29rZG93bjo6aHRtbF9ib29rOg0KICAgICAgICAgICNPSk8gRVJST1IgU2FsZW4gdGVvcmVtYXMsIHBlcm8gbm8gc2FsZW4gbG9zIGNhcGl0dWxvcyANCiAgICAjaHRtbF9kb2N1bWVudDoNCiAgICAgICAgICB0b2M6IHRydWUgICAgICAjIHRhYmxlIG9mIGNvbnRlbnQgdHJ1ZQ0KICAgICAgICAgIHRvY19kZXB0aDogNCAgICMgdXB0byB0aHJlZSBkZXB0aHMgb2YgaGVhZGluZ3MgKHNwZWNpZmllZCBieSAjLCAjIyBhbmQgIyMjKQ0KICAgICAgICAgIHRvY19mbG9hdDogdHJ1ZSAjQ29uIHRydWUsIHRvYyBzYWxlIGFsIG1hcmdlbiBpenF1aWVyZG8gZGUgbGEgcMOhZ2luYTsgZGUgbG8gY29udHJhcmlvLCBhcnJpYmENCiAgICAgICAgICBjb2xsYXBzZWQ6IGZhbHNlDQogICAgICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UNCiAgICAgICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUgICAjIGlmIHlvdSB3YW50IG51bWJlciBzZWN0aW9ucyBhdCBlYWNoIHRhYmxlIGhlYWRlcg0KICAgICAgICAgICN0aGVtZTogc2FuZHN0b25lDQogICAgICAgICAgI3RoZW1lOiB1bml0ZWQgICMgbWFueSBvcHRpb25zIGZvciB0aGVtZSwgdGhpcyBvbmUgaXMgbXkgZmF2b3JpdGUuDQogICAgICAgICAgI3RoZW1lOiBmbGF0bHkgICMgDQogICAgICAgICAgI3RoZW1lOiBjZXJ1bGVhbiAgIyANCiAgICAgICAgICAjaGlnaGxpZ2h0OiB0YW5nbyAgIyBzcGVjaWZpZXMgdGhlIHN5bnRheCBoaWdobGlnaHRpbmcgc3R5bGUNCiAgICAgICAgICAjY3NzOiBTY3JpcHRzIGFjY2Vzb3Jpb3MvZXN0aWxvYm90b24uY3NzDQogICAgICAgICAgI2NzczogbXkuY3NzICAgIyB5b3UgY2FuIGFkZCB5b3VyIGN1c3RvbSBjc3MsIHNob3VsZCBiZSBpbiBzYW1lIGZvbGRlcg0KICAgICAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICAgICAgICAjaGlnaGxpZ2h0OiB0YW5nbyAgIyBjYW1iaWFyIGNvbG9yIGRlIGxpYnJhcnkgZW4gYXp1bA0KICAgICMgYm9va2Rvd246OmdpdGJvb2s6DQogICAgIyAgICAgIGluY2x1ZGVzOg0KICAgICMgICAgICAgIGluX2hlYWRlcjogaGVhZGVyLmh0bWwNCiAgICAjIGJvb2tkb3duOjpwZGZfYm9vazoNCiAgICAjICAgICAgIGtlZXBfdGV4OiB5ZXMNCiAgICAjIGJvb2tkb3duOjpodG1sX2Jvb2s6DQogICAgIyAgICAgICBjc3M6IHRvYy5jc3MNCiAgICAjIGJvb2tkb3duOjpodG1sX2Jvb2s6DQogICAgIyAgICAgICAgIGluY2x1ZGVzOg0KICAgICMgICAgICAgICAgIGluX2hlYWRlcjogc3R5bGUuY3NzDQogICAgI2Jvb2tkb3duOjpodG1sX2RvY3VtZW50MjogZGVmYXVsdA0KICAgICMgYm9va2Rvd246OnBkZl9kb2N1bWVudDI6DQogICAgIyAgICAgIGtlZXBfdGV4OiB0cnVlDQogICAgI2JpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWINCiAgICBtYXRoamF4OiAiaHR0cDovL2V4YW1wbGUuY29tL21hdGhqYXgvTWF0aEpheC5qcz9jb25maWc9VGVYLUFNUy1NTUxfSFRNTG9yTU1MIg0KaGVhZGVyLWluY2x1ZGVzOg0KICAgIFx1c2VwYWNrYWdlW3gxMW5hbWVzXXt4Y29sb3J9IA0KICAgIA0KY3NsOiBzY2llbmNlLmNzbA0KI09qbzogU2UgdXRpbGl6YSBsZW5ndWFqZSBZQU1MDQoNCmFic3RyYWN0OiB8DQogKipFbiBbUnB1YnM6OiB0b2NdKGh0dHBzOi8vcnB1YnMuY29tL2hsbGluYXMvdG9jKSBzZSBwdWVkZW4gdmVyIG90cm9zIGRvY3VtZW50b3MgZGUgcG9zaWJsZSBpbnRlcsOpcy4qKg0KICANCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZmlnLmFsaWduPSJjZW50ZXIiLCAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSMsDQogICAgICAgICAgICAgICAgICAgICAgI3N0eWxlID0gImNvbG9yOmRhcmtibHVlIg0KICAgICAgICAgICAgICAgICAgICAjIGNsYXNzLnNvdXJjZT0iYmctZGFuZ2VyIiwgY2xhc3Mub3V0cHV0PSJiZy13YXJuaW5nIiAgICNDb2xvcmVzIGRlbnRybyBkZWwgY2h1bmsNCiAgICAgICAgICAgICAgICAgICAgICkNCmxpYnJhcnkocmdsKQ0Ka25pdHI6OmtuaXRfaG9va3Mkc2V0KHdlYmdsID0gaG9va193ZWJnbCkNCmBgYA0KDQoNCg0KDQpgYGB7ciwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0NCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9sYW5ndWFnZS1lbmdpbmVzLmh0bWwNCg0KaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvYm9va2Rvd24vbWFya2Rvd24tc3ludGF4Lmh0bWwNCg0KaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvYm9va2Rvd24vYS1zaW5nbGUtZG9jdW1lbnQuaHRtbA0KDQpodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ib29rZG93bi9tYXJrZG93bi1leHRlbnNpb25zLWJ5LWJvb2tkb3duLmh0bWwNCg0KaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duL2Jvb2tkb3duLW1hcmtkb3duLmh0bWwgICMgVGVvcmVtcyBhbmQgcHJvb2ZzDQoNCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL2Jvb2tkb3duL21hcmtkb3duLWV4dGVuc2lvbnMtYnktYm9va2Rvd24uaHRtbCN0aGVvcmVtcw0KDQpodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ib29rZG93bi9odG1sLmh0bWwNCg0KaHR0cHM6Ly93d3cuZGF0YS10by12aXouY29tLw0KICANCltScHVic10obGluaykNCiAgDQooXCNlcTplYy0pLCAgRWN1YWNpb24gXEByZWYoZXE6ZWMtKSwgRmlndXJhIFxAcmVmKGZpZzpGaWctKSwgVGFibGUgXEByZWYodGFiOm10Y2FycyksIFRoZW9yZW0gXEByZWYodGhtOmJvcmluZykNCg0KDQojIFRpdHVsbyB7I1RpdHVsb1NlY2Npb259ICAgXEByZWYoVGl0dWxvU2VjY2lvbikNCiAgDQojIEZvciBIVE1MLCB3ZSBjYW4gc2V0IGNvbG9yIHdpdGggQ1NTLCBlLmcuLCA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZDsiPnRleHQ8L3NwYW4+DQogIA0KIyBodHRwczovL3JhZGlhbnQtcnN0YXRzLmdpdGh1Yi5pby9kb2NzL21vZGVsL2xvZ2lzdGljLmh0bWwgU2hpbm55IExvZ2l0ICANCiAgDQpgYGANCg0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQojTGEgZm90byB0YW1hw7FvIGPDqWR1bGENCg0KaHRtbHRvb2xzOjppbWcoc3JjID0ga25pdHI6OmltYWdlX3VyaShmaWxlLnBhdGgoUi5ob21lKCJkb2MiKSwgImh0bWwiLCAibG9nby5qcGciKSksIA0KICAgICAgICAgICAgICAgYWx0ID0gJ2hsbGluYXMnLCANCiAgICAgICAgICAgICAgIHN0eWxlID0gJ3Bvc2l0aW9uOmFic29sdXRlOyB0b3A6MDsgcmlnaHQ6MDsgcGFkZGluZzoxMHB4OycgIywNCiAgICAgICAgICAgICAgIHdpZHRoID0gIjIwMHB4IikgICMgQXF1w60gZXNwZWNpZmljYXMgZWwgYW5jaG8gZGVzZWFkbyBlbiBww614ZWxlcyBvIHBvcmNlbnRhamUNCmBgYA0KDQoNCg0KDQpgYGB7ciwgZWNobz1GQUxTRSwgfQ0KIyBMYSBmb3RvIGdyYW5kZQ0KDQpodG1sdG9vbHM6OmltZyhzcmMgPSBrbml0cjo6aW1hZ2VfdXJpKCJobGxpbmFzMjAyMy5qcGciKSwgDQogICAgICAgICAgICAgICBhbHQgPSAnaGxsaW5hczIwMjMnLCANCiAgICAgICAgICAgICAgIHN0eWxlID0gJ3Bvc2l0aW9uOmFic29sdXRlOyB0b3A6MDsgcmlnaHQ6MDsgcGFkZGluZzoxcHg7JywNCiAgICAgICAgICAgICAgIHdpZHRoPSIxNSUiKQ0KYGBgDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgIC0tPg0KDQpgYGB7Y3NzLCBlY2hvPUZBTFNFfQ0KLmNvbHVtbnMge2Rpc3BsYXk6IGZsZXg7fQ0KaDEge2NvbG9yOiBkYXJrYmx1ZTt9DQpoMyB7Y29sb3I6IGRhcmtncmVlbjt9DQpoNCB7Y29sb3I6IGdyZWVuO30NCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAgLS0+DQoNCiMgTGlicmVyw61hcw0KDQojIyMgUGFyYSBDQQ0KDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0KIyAgaHR0cHM6Ly9ycHVicy5jb20vQWxlbWEvMTAwMDU4Mg0KDQojIGh0dHBzOi8vd3d3LmdlZWtzZm9yZ2Vla3Mub3JnL2NvbnRleHR1YWwtb3V0bGllcnMvDQpgYGANCg0KRWwgc29mdHdhcmUgUiBkaXNwb25lIGRlIHZhcmlhcyBmdW5jaW9uZXMgZGUgZGlmZXJlbnRlcyBwYXF1ZXRlcyBwYXJhIGNhbGN1bGFyIGFuw6FsaXNpcyBkZSBjb3JyZXNwb25kZW5jaWEgKENBKToNCg0KICAgLSBgY2FgLCBkZWwgcGFxdWV0ZSBgY2FgLg0KICAgICAgICANCiAgIC0gYENBYCBkZWwgcGFxdWV0ZSBgRmFjdG9NaW5lUmAuDQogICAgDQogICAtIGBkdWRpLmNvYWAgZGVsIHBhcXVldGUgYGFkZTRgLg0KICAgIA0KICAgLSBgZXBQQ0FgIGRlbCBwYXF1ZXRlIGBFeFBvc2l0aW9uYC4NCg0KICAgLSBgY29ycmVzcG9uZGAgZGVsIHBhcXVldGUgYE1BU1NgLg0KICAgICAgICANCg0KU2luIGltcG9ydGFyIGxhIGZ1bmNpw7NuIHF1ZSBlbGlqYSBlbXBsZWFyLCBlcyBwb3NpYmxlIGV4dHJhZXIgeSByZXByZXNlbnRhciBkZSBtYW5lcmEgc2VuY2lsbGEgbG9zIHJlc3VsdGFkb3MgZGVsIENBIG1lZGlhbnRlIGxhcyBmdW5jaW9uZXMgZGVsIHBhcXVldGUgYGZhY3RvZXh0cmFgLiBFbiBlc3RlIGRvY3VtZW50bywgc2UgaGFyw6EgdXNvIGRlIGxvcyBwYXF1ZXRlcyBgRmFjdG9NaW5lUmAgeSBgYWRlNGAgIHBhcmEgbG9zIGFuw6FsaXNpcyB5IGBmYWN0b2V4dHJhYCBwYXJhIGxhIHZpc3VhbGl6YWNpw7NuIGJhc2FkYSBlbiBgZ2dwbG90MmAuDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoRmFjdG9NaW5lUikNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmxpYnJhcnkoYWRlNCkNCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAgLS0+DQoNCiMjIyBQYXJhIG90cm9zIGFuw6FsaXNpcw0KDQpgYGB7ciwgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQpsaWJyYXJ5KGFwbG9yZTMpICAgICAgICNCYXNlIGRlIGRhdG9zIHBhcmEgbG9zIGVqZW1wbG9zDQpsaWJyYXJ5KGxzbSkgICAgICAgICAgICNCYXNlIGRlIGRhdG9zIHBhcmEgZWplbXBsb3MgeSBlc3RpbWFjaW9uZXMgZGVsIExvZy12ZXJvc2ltaWxpdHVkDQpsaWJyYXJ5KGtuaXRyKSAgICAgICAgICNFZGl0YXIgdGFibGFzIGNvbiBrYWJsZSgpDQpsaWJyYXJ5KGthYmxlRXh0cmEpICAgICNFZGl0YXIgdGFibGFzIG3DoXMgZXN0aWxpemFkYXMNCmxpYnJhcnkodGlkeXZlcnNlKSAgICAgI0luY2x1eWUgYSBkcGx5ciB5IGdncGxvdDINCmxpYnJhcnkoc3RyaW5ncikgICAgICAgI1JlZW1wbGF6YXIgY2FyYWN0ZXJlcyBlbiB1biBkYXRhIGZyYW1lDQpsaWJyYXJ5KG91dGxpZXJzKSAgICAgICNvdXRsaWVyczo6Z3J1YmJzLnRlc3QNCmxpYnJhcnkoRW52U3RhdHMpICAgICAgI0VudlN0YXRzOjpyb3NuZXJUZXN0DQpsaWJyYXJ5KERNd1IyKSAgICAgICAgICNMT0YgKExvY2FsIE91dGxpZXIgRmFjdG9yKQ0KbGlicmFyeShyZ2wpICAgICAgICAgICAjcmdsOjpwbG90M2RgDQpsaWJyYXJ5KGNvcnJwbG90KSAgICAgICNNYXRyaXogZGUgY29ycmVsYWNpb25lcw0KbGlicmFyeSh0ZXh0c2hhcGUpICAgICAjY29sdW1uX3RvX3Jvd25hbWVzDQpsaWJyYXJ5KGdwbG90cykgICAgICAgICNiYWxsb29ucGxvdA0KbGlicmFyeShnZ3B1YnIpICAgICAgICAjZ2diYWxsb29ucGxvdA0KbGlicmFyeShncmFwaGljcykgICAgICAjbW9zYWljcGxvdCBkZWwgcGFxdWV0ZSBgZ3JhcGhpY3NgDQoNCiNvcHRzX2tuaXQkc2V0KGV2YWwuYWZ0ZXIgPSAnZmlnLmNhcCcpDQpgYGANCg0KYGBge2NzcywgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0NCiNodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80MTAzMDQ3Ny9jaGFuZ2luZy1jaHVuay1iYWNrZ3JvdW5kLWNvbG9yLWluLXJtYXJrZG93bg0KDQouYmFkQ29kZSB7DQpiYWNrZ3JvdW5kLWNvbG9yOiByZWQ7DQp9DQpgYGANCg0KYGBge3IsICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQ0KbGlicmFyeShhcGxvcmUzKSAgICAgICAjQmFzZSBkZSBkYXRvcyBwYXJhIGxvcyBlamVtcGxvcw0KbGlicmFyeShsc20pICAgICAgICAgICAjQmFzZSBkZSBkYXRvcyBwYXJhIGVqZW1wbG9zIHkgZXN0aW1hY2lvbmVzIGRlbCBMb2ctdmVyb3NpbWlsaXR1ZA0KbGlicmFyeSh0aWR5dmVyc2UpICAgICAjSW5jbHV5ZSBhIGRwbHlyIHkgZ2dwbG90Mg0KbGlicmFyeShzdHJpbmdyKSAgICAgICAjUmVlbXBsYXphciBjYXJhY3RlcmVzIGVuIHVuIGRhdGEgZnJhbWUNCmxpYnJhcnkob3V0bGllcnMpICAgICAgI291dGxpZXJzOjpncnViYnMudGVzdA0KbGlicmFyeShFbnZTdGF0cykgICAgICAjRW52U3RhdHM6OnJvc25lclRlc3QNCmxpYnJhcnkoRE13UjIpICAgICAgICAgI0xPRiAoTG9jYWwgT3V0bGllciBGYWN0b3IpDQpsaWJyYXJ5KHJnbCkgICAgICAgICAgICNyZ2w6OnBsb3QzZA0KbGlicmFyeShjb3JycGxvdCkgICAgICAjTWF0cml6IGRlIGNvcnJlbGFjaW9uZXMNCmxpYnJhcnkodGV4dHNoYXBlKSAgICAgI2NvbHVtbl90b19yb3duYW1lcw0KbGlicmFyeShncGxvdHMpICAgICAgICAjYmFsbG9vbnBsb3QNCmxpYnJhcnkoZ2dwdWJyKSAgICAgICAgI2dnYmFsbG9vbnBsb3QNCmxpYnJhcnkoZ3JhcGhpY3MpICAgICAgI21vc2FpY3Bsb3QgZGVsIHBhcXVldGUgYGdyYXBoaWNzYA0KYGBgDQoNCg0KDQoNCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEVqZW1wbG86IEVudW5jaWFkbw0KDQpgYGB7ciwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0NCkxvcyBkYXRvcyB1dGlsaXphZG9zIGVuIGVzdGUgZWplbXBsbyBkZXNjcmliZW4gZWwgcmVuZGltaWVudG8gZGUgbG9zIGF0bGV0YXMgZHVyYW50ZSBkb3MgZXZlbnRvcyBkZXBvcnRpdm9zIChEZXNjdGFyIHkgT2x5bXBpY0cpLiBDb250aWVuZSAyNyBpbmRpdmlkdW9zIChhdGxldGFzKSBkZXNjcml0b3MgbWVkaWFudGUgMTMgdmFyaWFibGVzLiBDb24gZXN0b3MgZGF0b3MgbGxldmFyZW1vcyBhIGNhYm8gdW4gUENBLiANCg0KDQojYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkYXRvc0NvbXBsZXRvIDwtIGZhY3RvZXh0cmE6OmRlY2F0aGxvbjINCmF0dGFjaChkYXRvc0NvbXBsZXRvKQ0KI2BgYA0KDQoNCiNgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCm5hbWVzKGRhdG9zQ29tcGxldG8pDQojYGBgDQoNClNlIHJlc2FsdGEgcXVlIHPDs2xvIGFsZ3Vub3MgZGUgZXN0b3MgaW5kaXZpZHVvcyB5IHZhcmlhYmxlcyBzZSB1dGlsaXphcsOhbiBwYXJhIHJlYWxpemFyIGVsIGFuw6FsaXNpcyBkZSBjb3JyZXNwb25kZW5jaWFzLiANCg0KI2BgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkYXQgPC0gZGF0b3NDb21wbGV0b1sxOjIzLCAxOjEwXQ0KYXR0YWNoKGRhdCkNCmhlYWQoZGF0LDQpKSANCiNgYGANCg0KI2BgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkYXQgPC0gZGF0b3NDb21wbGV0b1sxOjIzLCAxOjEwXQ0KYXR0YWNoKGRhdCkNCmthYmxlKGhlYWQoZGF0LDQpLGFsaWduID0gImNjYyIpICU+JSMgU2UgbmVjZXNpdGEgbGlicmFyeShrbml0cikgDQprYWJsZV9zdHlsaW5nKCkgJT4lICAgICAgICAgICAgICAgICNsaWJyYXJ5KGthYmxlRXh0cmEpLi4uLiBTb2xvIHBhcmEga25pdCB0byBodG1sDQprYWJsZV9jbGFzc2ljXzIoZnVsbF93aWR0aCA9IEYpICAgI2xpYnJhcnkoa2FibGVFeHRyYSkuLi4uU29sbyBwYXJhIGtuaXQgdG8gaHRtbA0KI2BgYA0KDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBCYXNlIGRlIGRhdG9zDQoNCg0KTG9zIGRhdG9zIHNlIHJlY29naWVyb24gYXBsaWNhbmRvIHVuYSBlbmN1ZXN0YSBhIHVuYSBtdWVzdHJhIGRlIGVzdHVkaWFudGVzIHVuaXZlcnNpdGFyaW9zLiBFcyB1biBkYXRhIGZyYW1lIGNvbiA4MDAgb2JzZXJ2YWNpb25lcyB5IDY2IHZhcmlhYmxlcy4gDQoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkYXRvc0NvbXBsZXRvIDwtIGxzbTo6c3VydmV5DQojZGF0b3NDb21wbGV0byA8LSB0ZXh0c2hhcGU6OmNvbHVtbl90b19yb3duYW1lcyhkYXQsIGxvYz0xKQ0KI2RhdG9zQ29tcGxldG8gJT4lIHJlbW92ZV9yb3duYW1lcyAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhcj0ibmFtZXMiKSAgICNsaWJyYXJ5KHRpZHl2ZXJzZSkNCmF0dGFjaChkYXRvc0NvbXBsZXRvKQ0KYGBgDQoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpuYW1lcyhkYXRvc0NvbXBsZXRvKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRGF0b3MgcGFyYSBlbCBDQQ0KDQpMb3MgZGF0b3MgZGViZW4gc2VyIHVuYSB0YWJsYSBkZSBjb250aW5nZW5jaWEuIFBvciBlc3RhIHJhesOzbiwgc29sbyBjb25zaWRlcmFyZW1vcyBsYXMgc2lndWllbnRlcyBkb3MgdmFyaWFibGVzIHBhcmEgcmVhbGl6YXIgZWwgYW7DoWxpc2lzIGRlIGNvcnJlc3BvbmRlbmNpYTogDQogIA0KICANCiAgKyBgUG9zdF9TVEFUMWA6ICJJIGxpa2Ugc3RhdGlzdGljcyIsIGNvbiBsYXMgc2lndWllbnRlcyBjb2RpZmljYWNpb25lczogMT0gU3Ryb25nbHkgZGlzYWdyZWU7IDI9IERpc2FncmVlOyAgMz0gVW5kZWNpZGVkOyA0PSBBZ3JlZTsgNT0gU3Ryb25nbHkgYWdyZWUuDQogIA0KICArIGBQU0lDTzFgOiAiSSBmZWVsIGdvb2QiLCBjb24gbGFzIHNpZ3VpZW50ZXMgY29kaWZpY2FjaW9uZXM6IDE9QWxtb3N0IG5ldmVyOyAyPSBTb21ldGltZXM7IDM9IEZyZXF1ZW50bHk7IDQ9IEFsbW9zdCBhbHdheXMuDQogIA0KICANCg0KDQoNCmBgYHtyfQ0KZGYgPC0gZGF0b3NDb21wbGV0b1ssYyg0OCw2MildDQpuYW1lcyhkZikgPC0gYygiU3RhdF9udW0iLCAiUHNpY29fYSIpDQphdHRhY2goZGYpDQoNCiMgQ2FtYmlhciBsb3Mgbml2ZWxlcyBkZSBsYSB2YXJpYWJsZSBTVEFUDQpkZiRTdGF0IDwtIGZhY3RvcihkZiRTdGF0X251bSwgbGV2ZWxzID0gYygxLCAyLCAzLCA0LCA1KSwgbGFiZWxzID0gYygiMS5TdHIuRGlzYWdyZWUiLCAiMi5EaXNhZ3JlZSIsICIzLlVuZGVjaWRlZCIsICI0LkFncmVlIiwgIjUuU3RyLkFncmVlIikpDQoNCiMgQ2FtYmlhciBsb3Mgbml2ZWxlcyBkZSBsYSB2YXJpYWJsZSBQc2ljbw0KZGYkUHNpY28gPC0gZmFjdG9yKGRmJFBzaWNvX2EsIGxldmVscyA9IGMoIkFsbW9zdCBuZXZlciIsICJTb21ldGltZXMiLCAiRnJlcXVlbnRseSIsICJBbG1vc3QgYWx3YXlzIiksIGxhYmVscyA9IGMoIjEuTmV2ZXIiLCAiMi5Tb21lLiIsICIzLkZyZXEuIiwgIjQuQWx3YXlzIikpDQoNCmF0dGFjaChkZikNCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEVqZW1wbG86IFNvbHVjacOzbiAoYHRhYmxlYCkNCg0KTGEgdGFibGEgZGUgY29udGluZ2VuY2lhIGVzOiANCg0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQpkYXQgPC0gdGFibGUoU3RhdCwgUHNpY28pDQpkYXQNCg0Ka2FibGUoZGF0LGFsaWduID0gImNjYyIpICU+JSMgU2UgbmVjZXNpdGEgbGlicmFyeShrbml0cikgDQprYWJsZV9zdHlsaW5nKCkgJT4lICAgICAgICAgICAgICAgICNsaWJyYXJ5KGthYmxlRXh0cmEpLi4uLiBTb2xvIHBhcmEga25pdCB0byBodG1sDQprYWJsZV9jbGFzc2ljXzIoZnVsbF93aWR0aCA9IEYpICAgI2xpYnJhcnkoa2FibGVFeHRyYSkuLi4uU29sbyBwYXJhIGtuaXQgdG8gaHRtbA0KYGBgDQoNCg0KYGBge3J9DQpkYXQgPC0gdGFibGUoU3RhdCwgUHNpY28pDQpkYXQNCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEVqZW1wbG86IFNvbHVjacOzbiAoZ3LDoWZpY2EgZGUgdGFibGFzKQ0KDQojIyMgYGJhbGxvb25wbG90YDogZ2VuZXJhbA0KDQpMYSB0YWJsYSBkZSBjb250aW5nZW5jaWEgYW50ZXJpb3Igbm8gZXMgbXV5IGdyYW5kZS4gUG9yIGxvIHRhbnRvLCBlcyBmw6FjaWwgaW5zcGVjY2lvbmFyIHZpc3VhbG1lbnRlIGUgaW50ZXJwcmV0YXIgbG9zIHBlcmZpbGVzIGRlIGZpbGFzIHkgY29sdW1uYXMuIExhIHRhYmxhIGRlIGNvbnRpbmdlbmNpYSBwdWVkZSB2aXN1YWxpemFyc2UgdXRpbGl6YW5kbyBsYXMgZnVuY2lvbmVzIGBiYWxsb29ucGxvdGAgZGVsIHBhcXVldGUgYGdwbG90c2AgeSBgbW9zYWljcGxvdGAgZGVsIHBhcXVldGUgYGdyYXBoaWNzYC4NCg0KDQpgYGB7cn0NCmxpYnJhcnkoZ3Bsb3RzKQ0KDQojIENvbnZlcnRpciBsb3MgZGF0b3MgY29tbyB1bmEgdGFibGEgDQoNCnRhYmxhIDwtIGFzLnRhYmxlKGFzLm1hdHJpeChkYXQpKQ0KDQojIEdyYWZpY2EgZWwgYmFsbG9vbnBsb3QgY29uIGVsIHRhbWHDsW8gZGUgZnVlbnRlIGFqdXN0YWRvDQoNCmJhbGxvb25wbG90KHQodGFibGEpLCBtYWluID0iU3RhdGlzdGljIHZzIEZlZWxpbmciLCANCiAgICAgICAgICAgIHhsYWIgPSJJIGZlZWwgZ29vZDoiLCANCiAgICAgICAgICAgIHlsYWI9IkkgbGlrZSBTdGF0OiIsDQogICAgICAgICAgICBsYWJlbCA9IEZBTFNFLCANCiAgICAgICAgICAgIHNob3cubWFyZ2lucyA9IFRSVUUsDQogICAgICAgICAgICAjc2hvdy5tYXJnaW5zID0gRkFMU0UNCiAgICAgICAgICAgICkNCmBgYA0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgYmFsbG9vbnBsb3RgOiBvdHJvcyBhcmd1bWVudG9zIA0KDQpUZW5nYSBlbiBjdWVudGEgcXVlIGxhcyBzdW1hcyBkZSBmaWxhcyB5IGNvbHVtbmFzIHNlIGltcHJpbWVuIHBvciBkZWZlY3RvIGVuIGxvcyBtw6FyZ2VuZXMgaW5mZXJpb3IgeSBkZXJlY2hvLCByZXNwZWN0aXZhbWVudGUuDQpyZXNwZWN0aXZhbWVudGUuIEVzdG9zIHZhbG9yZXMgc2Ugb2N1bHRhbiwgZW4gZWwgZ3LDoWZpY28gYW50ZXJpb3IsIHV0aWxpemFuZG8gZWwgYXJndW1lbnRvIGBzaG93Lm1hcmdpbnMgPSBGQUxTRWAuDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGdncHVicikNCnRhYmxhLmRmIDwtIGRhdGEuZnJhbWUodCh0YWJsYSkpDQoNCiNEZWZpbm8gcGFsZXRhIGRlIGNvbG9yZXMNCiNteV9jb2xzIDwtIGMoIiMwRDA4ODdGRiIsICIjNkEwMEE4RkYiLCAiI0IxMkE5MEZGIiwiI0UxNjQ2MkZGIiwgIiNGQ0E2MzZGRiIsICIjRjBGOTIxRkYiKQ0KbXlfY29scyA8LSBjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpDQoNCmdnYmFsbG9vbnBsb3QodGFibGEuZGYsIG1haW4gPSJFc3RhZMOtc3RpY2EgdnMgU2VudGltaWVudG8iLCANCiAgICAgICAgICAgIHhsYWIgPSJNZSBzaWVudG8gYmllbiIsIA0KICAgICAgICAgICAgeWxhYj0iTWUgZ3VzdGEgbGEgRXN0YWTDrXN0aWNhIiwNCiAgICAgICAgICAgZmlsbCA9ICJ2YWx1ZSIsDQogICAgICAgICAgIHNpemU9MTAsDQogICAgICAgICAgICNzaGFwZSA9IDIzLCANCiAgICAgICAgICAgc2hvdy5sYWJlbCA9IFRSVUUNCiAgICAgICAgICAgKSsNCiAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IG15X2NvbHMpDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgY2hpc3EudGVzdGApDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgY2hpc3EudGVzdGA6IHBydWViYSBjaGktY3VhZHJhZGENCg0KU2UgcHVlZGUgZW1wbGVhciBsYSBwcnVlYmEgZGUgQ2hpLWN1YWRyYWRvIHBhcmEgYW5hbGl6YXIgc2kgZXhpc3RlIHVuYSBkZXBlbmRlbmNpYSBzaWduaWZpY2F0aXZhIGVudHJlIGxhcyBjYXRlZ29yw61hcyBkZSBmaWxhcyB5IGNvbHVtbmFzIGVuIHVuYSB0YWJsYSBkZSBjb250aW5nZW5jaWEgcGVxdWXDsWEuDQoNCg0KDQpgYGB7cn0NCmNoaXNxX3Rlc3QgPC0gY2hpc3EudGVzdCh0YWJsYSkNCmNoaXNxX3Rlc3QNCmBgYA0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgY2hpc3EudGVzdGA6IGludGVycHJldGFjacOzbg0KDQoNCkVuIG51ZXN0cm8gZWplbXBsbywgbGFzIHZhcmlhYmxlcyBkZSBmaWxhIHkgY29sdW1uYSBlc3TDoW4gYXNvY2lhZGFzIGRlIG1hbmVyYSBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhIChwLXZhbHVlID0gYHIgY2hpc3FfdGVzdCRwLnZhbHVlYCA8IDAuMDUpLg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgQ0FgKQ0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYENBYDogZnVuY2nDs24gZW4gUg0KDQpTZSBwdWVkZSB1c2FyIGxhIGZ1bmNpw7NuIGBDQWAgZGVsIHBhcXVldGUgYEZBY3RvTWluZXJgLiBFbCBmb3JtYXRvIGLDoXNpY28gZXM6IA0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCkNBKGRmLCBuY3AgPSA1LCBncmFwaCA9IFRSVUUpDQpgYGANCg0KQXF1w606IA0KDQorIGBkZmAgZXMgdW4gZGF0YSBmcmFtZSAodGFibGEgZGUgY29udGluZ2VuY2lhKS4NCg0KKyBgbmNwYCBlcyBlbCBuw7ptZXJvIGRlIGRpbWVuc2lvbmVzICBxdWUgc2UgbWFudGllbmVuIGVuIGxvcyByZXN1bHRhZG9zIGZpbmFsZXMuDQoNCisgYGdyYXBoYCBlcyB1biB2YWxvciBsw7NnaWNvLiBTaSBzZSBlc2NyaWJlIGBUUlVFYCwgc2UgbXVlc3RyYSB1bmEgZ3LDoWZpY2EuDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgQ0FgOiBjb24gbnVlc3RybyBlamVtcGxvDQoNCkVuIG51ZXN0cm8gZWplbXBsbzogDQoNCmBgYHtyfQ0KbGlicmFyeSgiRmFjdG9NaW5lUiIpDQpyZXMuY2EgPC0gQ0EodGFibGEsIGdyYXBoID0gRkFMU0UpDQpyZXMuY2ENCmBgYA0KRWwgb2JqZXRvIGByZXMuY2FgLCBjcmVhZG8gbWVkaWFudGUgbGEgZnVuY2nDs24gYENBYCBjb250aWVuZSB1bmEgZ3JhbiBjYW50aWRhZCBkZSBpbmZvcm1hY2nDs24gcHJvdmVuaWVudGUgZGUgZGl2ZXJzYXMgbGlzdGFzIHkgbWF0cmljZXMuIExvcyBkZXRhbGxlcyBkZSBlc3RvcyB2YWxvcmVzIHNlIGV4cGxpY2FuIGVuIGxhcyBzaWd1aWVudGVzIHNlY2Npb25lcy4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBFamVtcGxvOiBTb2x1Y2nDs24gKHZpc3VhbGl6YWNpw7NuKQ0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgVmlzdWFsaXphY2nDs24gZSBpbnRlcnByZXRhY2nDs24NCg0KVXRpbGl6YXJlbW9zIGxhcyBzaWd1aWVudGVzIGZ1bmNpb25lcyBbZW4gYGZhY3RvZXh0cmFgXSBwYXJhIGF5dWRhciBlbiBsYSBpbnRlcnByZXRhY2nDs24geSB2aXN1YWxpemFjacOzbiBkZWwgYW7DoWxpc2lzIGRlIGNvcnJlc3BvbmRlbmNpYXM6DQogIA0KICAxLiBgZ2V0X2VpZ2VudmFsdWUocmVzLmNhKWA6IEV4dHJhZSBsb3MgdmFsb3JlcyBwcm9waW9zL3ZhcmlhbnphcyByZXRlbmlkYXMgcG9yIGNhZGEgZGltZW5zacOzbiAoZWplKQ0KICANCiAgMi4gYGZ2aXpfZWlnKHJlcy5jYSlgOiBWaXN1YWxpemEgbG9zIHZhbG9yZXMgcHJvcGlvcw0KICANCiAgMy4gYGdldF9jYV9yb3cocmVzLmNhKWAsIGBnZXRfY2FfY29sKHJlcy5jYSlgOiBFeHRyYWUgbG9zIHJlc3VsdGFkb3MgcGFyYSBmaWxhcyB5IGNvbHVtbmFzLCByZXNwZWN0aXZhbWVudGUuDQogIA0KICA0LiBgZnZpel9jYV9yb3cocmVzLmNhKWAsIGBmdml6X2NhX2NvbChyZXMuY2EpYDogVmlzdWFsaXphIGxvcyByZXN1bHRhZG9zIHBhcmEgZmlsYXMgeSBjb2x1bW5hcywgcmVzcGVjdGl2YW1lbnRlLg0KICANCiAgNS4gYGZ2aXpfY2FfYmlwbG90KHJlcy5jYSlgOiBDcmVhIHVuIGJpcGxvdCBkZSBmaWxhcyB5IGNvbHVtbmFzLg0KDQpFbiBsYXMgc2VjY2lvbmVzIHNpZ3VpZW50ZXMsIGlsdXN0cmFyZW1vcyBjYWRhIHVuYSBkZSBlc3RhcyBmdW5jaW9uZXMuDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIFNpZ25pZmljYW5jaWEgZXN0YWTDrXN0aWNhDQoNClBhcmEgbGFzIGludGVycHJldGFjaW9uZXMgcXVlIHNlIG9idGVuZ2FuIGNvbiBlbCBhbsOhbGlzaXMgZGUgY29ycmVzcG9uZGVuY2lhLCBwcmltZXJvLCBlcyBuZWNlc2FyaW8gZGV0ZXJtaW5hciBzaSBoYXkgdW5hIGRlcGVuZGVuY2lhIHNpZ25pZmljYXRpdmEgZW50cmUgbGFzIGZpbGFzIHkgY29sdW1uYXMuIFVuIGVuZm9xdWUgcmlndXJvc28gZXMgdXRpbGl6YXIgbGEgZXN0YWTDrXN0aWNhIGRlIGNoaS1jdWFkcmFkbyBwYXJhIGV4YW1pbmFyIGxhIGFzb2NpYWNpw7NuIGVudHJlIGxhcyB2YXJpYWJsZXMgZGUgZmlsYSB5IGNvbHVtbmEuIEVzdGEgaW5mb3JtYWNpw7NuIHNlIGVuY3VlbnRyYSBlbiBsYSBwYXJ0ZSBzdXBlcmlvciBkZWwgaW5mb3JtZSBnZW5lcmFkbyBwb3IgbGEgZnVuY2nDs24gYHN1bW1hcnkocmVzLmNhKWAgbyBgcHJpbnQocmVzLmNhKWAuDQoNCg0KYGBge3J9DQpzdW1tYXJ5KHJlcy5jYSkNCg0KYGBgDQoNCg0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQpjaGlzcSRzdGF0aXN0aWMNCmBgYA0KDQoNCg0KYGBge3IsIGVjaG89RkFMU0V9DQojQ2hpLXNxdWFyZSBzdGF0aXN0aWNzDQpjaGkyIDwtIGNoaXNxX3Rlc3Qkc3RhdGlzdGljDQoNCiMgRGVncmVlIG9mIGZyZWVkb20NCmRmIDwtIChucm93KHRhYmxhKSAtIDEpICogKG5jb2wodGFibGEpIC0gMSkNCg0KIyBQLXZhbHVlDQpwdmFsIDwtIHBjaGlzcShjaGkyLCBkZiA9IGRmLCBsb3dlci50YWlsID0gRkFMU0UpDQpgYGANCg0KDQpVbiB2YWxvciBhbHRvIGRlIGxhIGVzdGFkw61zdGljYSBkZSBjaGktY3VhZHJhZG8gaW5kaWNhIHVuYSBmdWVydGUgY29uZXhpw7NuIGVudHJlIGxhcyB2YXJpYWJsZXMgZGUgZmlsYSB5IGNvbHVtbmEuIEVuIG51ZXN0cm8gZWplbXBsbywgbGEgYXNvY2lhY2nDs24gZXMgYWx0YW1lbnRlIHNpZ25pZmljYXRpdmEgKGNoaS1jdWFkcmFkbyA9IGByIGNoaTIgYCwgcC12YWxvciA9IGByIHB2YWxgKS4NCg0KYGBge3J9DQojQ2hpLXNxdWFyZSBzdGF0aXN0aWNzDQpjaGkyIDwtIGNoaXNxX3Rlc3Qkc3RhdGlzdGljDQoNCiMgRGVncmVlIG9mIGZyZWVkb20NCmRmIDwtIChucm93KHRhYmxhKSAtIDEpICogKG5jb2wodGFibGEpIC0gMSkNCg0KIyBQLXZhbHVlDQpwdmFsIDwtIHBjaGlzcShjaGkyLCBkZiA9IGRmLCBsb3dlci50YWlsID0gRkFMU0UpDQpwdmFsDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBWYWxvcmVzIHkgdmVjdG9yZXMgcHJvcGlvcw0KDQoNClByaW1lcm8sIHJlY29yZGVtb3MgcXVlIGV2YWx1YW1vcyBsb3MgZWlnZW52YWxvcmVzIHBhcmEgZGV0ZXJtaW5hciBsYSBjYW50aWRhZCBkZSBlamVzIGEgY29uc2lkZXJhci4gUG9kZW1vcyBvYnRlbmVyIGxvcyBlaWdlbnZhbG9yZXMgeSBsYSBwcm9wb3JjacOzbiBkZSB2YXJpYW56YSByZXRlbmlkYSBwb3IgbG9zIGRpZmVyZW50ZXMgZWplcyB1dGlsaXphbmRvIGxhIGZ1bmNpw7NuIGBnZXRfZWlnZW52YWx1ZWAgZGVsIHBhcXVldGUgYGZhY3RvZXh0cmFgLiBMb3MgZWlnZW52YWxvcmVzIHNvbiBncmFuZGVzIHBhcmEgZWwgcHJpbWVyIGVqZSB5IHBlcXVlw7FvcyBwYXJhIGxvcyBlamVzIHNpZ3VpZW50ZXMuDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQplaWcudmFsIDwtIGdldF9laWdlbnZhbHVlKHJlcy5jYSkNCmVpZy52YWwNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0NCnJvdW5kKGVpZy52YWxbMSwyXSwgMikNCiAgICAgIA0Kcm91bmQoZWlnLnZhbFsyLDJdLCAyKQ0KDQpgYGANCg0KDQpMb3MgdmFsb3JlcyBwcm9waW9zIHJlcHJlc2VudGFuIGxhIGNhbnRpZGFkIGRlIGluZm9ybWFjacOzbiBwcmVzZXJ2YWRhIHBvciBjYWRhIGVqZS4gTGFzIGRpbWVuc2lvbmVzIHNlIG9yZGVuYW4gZGUgbWFuZXJhIGRlc2NlbmRlbnRlIHkgc2UgZW51bWVyYW4gc2Vnw7puIGxhIHZhcmlhbnphIGV4cGxpY2FkYSBlbiBsYSBzb2x1Y2nDs24uIExhIHByaW1lcmEgZGltZW5zacOzbiBleHBsaWNhIGxhIG1heW9yIHBhcnRlIGRlIGxhIHZhcmlhbnphLCBzZWd1aWRhIHBvciBsYSBzZWd1bmRhIGRpbWVuc2nDs24sIHkgYXPDrSBzdWNlc2l2YW1lbnRlLg0KDQpFbCBwb3JjZW50YWplIGFjdW11bGFkbyBleHBsaWNhZG8gc2Ugb2J0aWVuZSBzdW1hbmRvIGxhcyBwcm9wb3JjaW9uZXMgc3VjZXNpdmFzIGRlIHZhcmlhY2nDs24gZXhwbGljYWRhIHBhcmEgb2J0ZW5lciBlbCB0b3RhbCBhY3VtdWxhZG8uIFBvciBlamVtcGxvLCBgciByb3VuZChlaWcudmFsWzEsMl0sIDIpYCUgbcOhcyBgciByb3VuZChlaWcudmFsWzIsMl0sIDIpYCUgZXMgaWd1YWwgYSBgciByb3VuZChlaWcudmFsWzEsMl0sIDIpICtyb3VuZChlaWcudmFsWzIsMl0sIDIpYCUsIHkgYXPDrSBzdWNlc2l2YW1lbnRlLiBQb3IgbG8gdGFudG8sIGFwcm94aW1hZGFtZW50ZSBlbCBgciByb3VuZChlaWcudmFsWzEsMl0sIDIpICtyb3VuZChlaWcudmFsWzIsMl0sIDIpYCUgZGUgbGEgdmFyaWFjacOzbiBlc3TDoSBleHBsaWNhZGEgcG9yIGxhcyBwcmltZXJhcyBkb3MgZGltZW5zaW9uZXMuDQoNCkxvcyB2YWxvcmVzIHByb3Bpb3Mgc2UgcHVlZGVuIHV0aWxpemFyIHBhcmEgZGV0ZXJtaW5hciBlbCBuw7ptZXJvIGRlIGVqZXMgYSByZXRlbmVyLiBObyBoYXkgdW5hICJyZWdsYSBnZW5lcmFsIiBwYXJhIGVsZWdpciBlbCBuw7ptZXJvIGRlIGRpbWVuc2lvbmVzIGEgbWFudGVuZXIgcGFyYSBsYSBpbnRlcnByZXRhY2nDs24gZGUgbG9zIGRhdG9zLiBEZXBlbmRlIGRlIGxhIHByZWd1bnRhIGRlIGludmVzdGlnYWNpw7NuIHkgZGUgbGFzIG5lY2VzaWRhZGVzIGRlbCBpbnZlc3RpZ2Fkb3IuIFBvciBlamVtcGxvLCBzaSBlbCBpbnZlc3RpZ2Fkb3IgZXN0w6Egc2F0aXNmZWNobyBjb24gZWwgODAlIGRlIGxhcyB2YXJpYW56YXMgdG90YWxlcyBleHBsaWNhZGFzLCBlbnRvbmNlcyBkZWJlIHVzYXIgZWwgbsO6bWVybyBkZSBkaW1lbnNpb25lcyBuZWNlc2FyaW8gcGFyYSBsb2dyYXIgZXNvLg0KDQpTZSBkZWJlIHRlbmVyIGVuIGN1ZW50YSBxdWUgdW5hIGJ1ZW5hIHJlZHVjY2nDs24gZGUgZGltZW5zaW9uZXMgc2UgbG9ncmEgY3VhbmRvIGxhcyBwcmltZXJhcyBkaW1lbnNpb25lcyBleHBsaWNhbiB1bmEgZ3JhbiBwcm9wb3JjacOzbiBkZSBsYSB2YXJpYWJpbGlkYWQuDQoNCkVuIG51ZXN0cm8gYW7DoWxpc2lzLCBlbCBwcmltZXIgZWplIGV4cGxpY2EgZWwgYHIgcm91bmQoZWlnLnZhbFsxLDJdLCAyKWAlIGRlIGxhIHZhcmlhY2nDs24uIEVzdGUgZXMgdW4gcG9yY2VudGFqZSBhY3BhdGJsZW1lbnRlIGdyYW5kZS4NCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgU2NyZWUgcGxvdA0KDQpVbiBtw6l0b2RvIGFsdGVybmF0aXZvIHBhcmEgZGV0ZXJtaW5hciBlbCBuw7ptZXJvIGRlIGRpbWVuc2lvbmVzIGVzIG9ic2VydmFyIHVuIGdyw6FmaWNvIFNjcmVlLCBxdWUgZXMgZWwgZ3LDoWZpY28gZGUgdmFsb3JlcyBwcm9waW9zL3ZhcmlhbnphcyBvcmRlbmFkb3MgZGUgbWF5b3IgYSBtZW5vci4gRWwgbsO6bWVybyBkZSBjb21wb25lbnRlcyBzZSBkZXRlcm1pbmEgZW4gZWwgcHVudG8gZW4gZWwgcXVlIGxvcyB2YWxvcmVzIHByb3Bpb3MgcmVzdGFudGVzIHNvbiB0b2RvcyByZWxhdGl2YW1lbnRlIHBlcXVlw7FvcyB5IGRlIHRhbWHDsW8gY29tcGFyYWJsZS4gRWwgZ3LDoWZpY28gU2NyZWUgc2UgcHVlZGUgcHJvZHVjaXIgdXRpbGl6YW5kbyBsYSBmdW5jacOzbiBgZnZpel9laWdgIG8gYGZ2aXpfc2NyZWVwbG90YCBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAuDQoNCg0KYGBge3J9DQpmdml6X3NjcmVlcGxvdChyZXMuY2EsIGFkZGxhYmVscyA9IFRSVUUsIHlsaW0gPSBjKDAsIDEwMCkpDQpgYGANCkVsIHB1bnRvIGVuIGVsIHF1ZSBlbCBzY3JlZSBwbG90IG11ZXN0cmEgdW5hIGN1cnZhdHVyYSAobGxhbWFkYSAiY29kbyIsICJlbGJvdyIpIHB1ZWRlIGNvbnNpZGVyYXJzZSBjb21vIGluZGljYXRpdm8gZGUgdW5hIGRpbWVuc2lvbmFsaWRhZCDDs3B0aW1hLiBUYW1iacOpbiBlcyBwb3NpYmxlIGNhbGN1bGFyIHVuIHZhbG9yIHByb3BpbyBwcm9tZWRpbyBwb3IgZW5jaW1hIGRlbCBjdWFsIGVsIGVqZSBkZWJlIG1hbnRlbmVyc2UgZW4gbGEgc29sdWNpw7NuLiANCg0KYGBge3IsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9DQpkaW0odGFibGEuZGYpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9DQp0YWJsYSA8LSBhcy50YWJsZShhcy5tYXRyaXgoZGF0KSkNCnRhYmxhDQpjbGFzcyh0YWJsYSkNCm5jb2wodGFibGEpDQpgYGANCg0KTnVlc3Ryb3MgZGF0b3MgY29udGllbmVuIGByIG5yb3codGFibGEpYCBmaWxhcyB5IGByIG5jb2wodGFibGEpYCBjb2x1bW5hcy4gU2kgbG9zIGRhdG9zIGZ1ZXJhbiBhbGVhdG9yaW9zLCBlbCB2YWxvciBlc3BlcmFkbyBkZWwgdmFsb3IgcHJvcGlvIHBhcmEgY2FkYSBlamUgc2Vyw61hIA0KDQokJFxmcmFjezF9e1xtYm94e07Dum1lcm8gZGUgZmlsYXN9XDsgLVw7IDF9IFw7PVw7IFxmcmFjezF9ezR9IFw7PVw7IDI1XCUgXHF1YWQgXG1ib3h7ZW4gdMOpcm1pbm9zIGRlIGZpbGFzfSAkJA0KDQpgYGB7cn0NCjEvKG5yb3codGFibGEpIC0xKQ0KYGBgDQoNCkRlbCBtaXNtbyBtb2RvLCBlbCBlamUgcHJvbWVkaW8gZGViZXLDrWEgcmVwcmVzZW50YXIgDQoNCiQkXGZyYWN7MX17XG1ib3h7TsO6bWVybyBkZSBjb2x1bW5hc31cOyAtXDsgMX0gXDs9XDsgXGZyYWN7MX17M30gXDs9XDsgMzMuM1wlIFxxdWFkIFxtYm94e2VuIHTDqXJtaW5vcyBkZSBsYXMgNCBjb2x1bW5hc30gJCQNCg0KYGBge3J9DQoxLyhuY29sKHRhYmxhKSAtMSkNCmBgYA0KDQpTZSByZXNhbHRhIGVsIGhlY2hvIGRlIHF1ZSBjdWFscXVpZXIgZWplIGNvbiB1bmEgY29udHJpYnVjacOzbiBtYXlvciBxdWUgZWwgbcOheGltbyBkZSBlc3RvcyBkb3MgcG9yY2VudGFqZXMgZGViZSBjb25zaWRlcmFyc2UgaW1wb3J0YW50ZSBlIGluY2x1aXJzZSBlbiBsYSBzb2x1Y2nDs24gcGFyYSBsYSBpbnRlcnByZXRhY2nDs24gZGUgbG9zIGRhdG9zLiBFbCBjw7NkaWdvIFIgYSBjb250aW51YWNpw7NuIGRpYnVqYSBlbHNjcmVlIHBsb3QgY29uIHVuYSBsw61uZWEgcm9qYSBkaXNjb250aW51YSBxdWUgZXNwZWNpZmljYSBlbCB2YWxvciBwcm9waW8gcHJvbWVkaW86DQoNCmBgYHtyfQ0KZnZpel9zY3JlZXBsb3QocmVzLmNhKSArDQpnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MzMuMzMsIGxpbmV0eXBlPTIsIGNvbG9yPSJyZWQiKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KYSA8LSByb3VuZChlaWcudmFsWzIsMl0sIDIpICtyb3VuZChlaWcudmFsWzMsMl0sMikNCmIgPC0gKCgxLyhuY29sKHRhYmxhKSAtMSkpKSoxMDANCmIgPC0gcm91bmQoYiwgMikNCmBgYA0KDQpFbCBncsOhZmljbyBpbmRpY2EgcXVlIHNvbG8gc2UgZGViZW4gdXRpbGl6YXIgbGEgZGltZW5zacOzbiAxIHBhcmEgbGEgc29sdWNpw7NuLiBMYXMgZGltZW5zaW9uZXMgMiB5IDMsIHF1ZSBzb2xvIGV4cGxpY2FuIGVsIGByIGFgJSBkZSBsYSBpbmVyY2lhIHRvdGFsLCBlc3TDoSBwb3IgZGViYWpvIGRlbCB2YWxvciBwcm9waW8gcHJvbWVkaW8gKGByIGJgJSkgeSBlcyBkZW1hc2lhZG8gaW5zaWduaWZpY2FudGUgcGFyYSB1biBhbsOhbGlzaXMgYWRpY2lvbmFsLiBBdW5xdWUgc2UgcHVlZGVuIGVtcGxlYXIgbcOhcyBkZSAxIGRpbWVuc2nDs24sIGVzIGltcHJvYmFibGUgcXVlIGxhcyBkaW1lbnNpb25lcyBhZGljaW9uYWxlcyBjb250cmlidXlhbiBzaWduaWZpY2F0aXZhbWVudGUgYSBjb21wcmVuZGVyIGxhIHJlbGFjacOzbiBlbnRyZSBsYXMgZmlsYXMgeSBjb2x1bW5hcy4gTGEgZGltZW5zacOzbiAxIHJlcHJlc2VudGEgYXByb3hpbWFkYW1lbnRlIGVsIGByIHJvdW5kKGVpZy52YWxbMSwyXSwgMilgJSBkZSBsYSBpbmVyY2lhIHRvdGFsLCByZXNwZWN0aXZhbWVudGUsIGxvIHF1ZSBlcXVpdmFsZSBhIHVuIHRvdGFsIGFjdW11bGFkbyBkZWwgYHIgcm91bmQoZWlnLnZhbFsxLDJdLCAyKWAlIGRlIGxhIGluZXJjaWEgcmV0ZW5pZGEgcG9yIGVzdGEgZGltZW5zacOzbi4gDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBCaXBsb3QNCg0KTGEgZnVuY2nDs24gYGZ2aXpfY2FfYmlwbG90YCBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAgcHVlZGUgc2VyIHVzYWRvIHBhcmEgZGlidWphciBlbCBiaXBsb3QgZGUgbGFzIHZhcmlhYmxlcyBmaWxhcyB5IGNvbHVtbmFzLiANCg0KYGBge3J9DQojcmVwZWw9IFRSVUUgcGFyYSBldml0YXIgdHJhc2xhcGFtaWVudG8gZGUgdGV4dG9zDQpmdml6X2NhX2JpcGxvdChyZXMuY2EsIHJlcGVsID0gVFJVRSkNCmBgYA0KDQoqKk9ic2VydmFjaW9uZXM6KioNCg0KMS4gRWwgZ3LDoWZpY28gYW50ZXJpb3Igc2UgZGVub21pbmEgKmRpYWdyYW1hIHNpbcOpdHJpY28qICgqc3ltZXRyaWMgcGxvdCopLiANCg0KMi4gTXVlc3RyYSB1biBwYXRyw7NuIGdsb2JhbCBkZW50cm8gZGUgbG9zIGRhdG9zLiANCg0KMy4gTGFzIGZpbGFzIGVzdMOhbiByZXByZXNlbnRhZGFzIHBvciBwdW50b3MgYXp1bGVzIHkgbGFzIGNvbHVtbmFzIHBvciB0cmnDoW5ndWxvcyByb2pvcy4gDQoNCjQuIExhIGRpc3RhbmNpYSBlbnRyZSBjdWFscXVpZXIgcGFyIGRlIHB1bnRvcyBkZSBmaWxhIG8gY29sdW1uYSBwcm9wb3JjaW9uYSB1bmEgbWVkaWRhIGRlIHN1IHNpbWlsaXR1ZCAobyBkaXNpbWlsaXR1ZCkuIA0KDQo1LiBMb3MgcHVudG9zIGRlIGZpbGEgY29uIHBlcmZpbGVzIHNpbWlsYXJlcyBlc3TDoW4gY2VyY2EgZW4gZWwgbWFwYSBkZSBmYWN0b3Jlcy4gTG8gbWlzbW8gb2N1cnJlIHBhcmEgbG9zIHB1bnRvcyBkZSBjb2x1bW5hLiANCiAgDQo2LiBSZXByZXNlbnRhIGxvcyBwZXJmaWxlcyBkZSBmaWxhIHkgY29sdW1uYSBzaW11bHTDoW5lYW1lbnRlIGVuIHVuIGVzcGFjaW8gY29tw7puLiBFbiBlc3RlIGNhc28sIHNvbG8gbGEgZGlzdGFuY2lhIGVudHJlIHB1bnRvcyBkZSBmaWxhIG8gbGEgZGlzdGFuY2lhIGVudHJlIHB1bnRvcyBkZSBjb2x1bW5hIHB1ZWRlIHNlciByZWFsbWVudGUgaW50ZXJwcmV0YWRhLiBMYSBkaXN0YW5jaWEgZW50cmUgY3VhbHF1aWVyIMOtdGVtIGRlIGZpbGEgeSBjb2x1bW5hIG5vIHRpZW5lIHVuIHNpZ25pZmljYWRvIGNsYXJvLiBTb2xvIHNlIHB1ZWRlbiBoYWNlciBhZmlybWFjaW9uZXMgZ2VuZXJhbGVzIHNvYnJlIGVsIHBhdHLDs24gb2JzZXJ2YWRvLg0KDQo3LiBQYXJhIGludGVycHJldGFyIGxhIGRpc3RhbmNpYSBlbnRyZSBwdW50b3MgZGUgY29sdW1uYSB5IGZpbGEsIGxvcyBwZXJmaWxlcyBkZSBjb2x1bW5hIGRlYmVuIHByZXNlbnRhcnNlIGVuIGVsIGVzcGFjaW8gZGUgZmlsYSBvIHZpY2V2ZXJzYS4gRXN0ZSB0aXBvIGRlIG1hcGEgc2UgZGVub21pbmEgKmJpcGxvdCBhc2ltw6l0cmljbyogeSBzZSBkZXNjcmliZSBlbiBzaWd1aWVudGVzIHNlY2Npb25lcy4NCg0KOC4gRWwgc2lndWllbnRlIHBhc28gcGFyYSBsYSBpbnRlcnByZXRhY2nDs24gZXMgZGV0ZXJtaW5hciBxdcOpIHZhcmlhYmxlcyBkZSBmaWxhIHkgY29sdW1uYSBjb250cmlidXllbiBtw6FzIGVuIGxhIGRlZmluaWNpw7NuIGRlIGxhcyBkaWZlcmVudGVzIGRpbWVuc2lvbmVzIHJldGVuaWRhcyBlbiBlbCBtb2RlbG8uIA0KDQoNCioqSW50ZXJwcmVhdGFjaW9uZXMgcGFyYSBudWVzdHJvIGVqZW1wbG86KioNCg0KOS4gRW4gbnVlc3RybyBlamVtcGxvLCBlc3RlIGdyw6FmaWNvIG11ZXN0cmEgcXVlOg0KICAgIA0KICAgICsgTGFzIHBlcnNvbmFzIHF1ZSBhbGd1bmFzIHZlY2VzIHNlIHNpZW50ZW4gYmllbiwgZXN0w6FuIGNvbXBsZXRhbWVudGUgZW4gZGVzYWN1ZXJkbyBkZSBxdWUgbGVzIGd1c3RhIGxhIGVzdGFkw61zdGljYS4gDQogICAgDQogICAgKyBMYXMgcGVyc29uYXMgcXVlIGNhc2kgc2llbXByZSBzZSBzaWVudGVuIGJpZW4sIGVzdMOhbiBkZSBhY3VlcmRvIGVuIHF1ZSBsZXMgZ3VzdGEgbGEgZXN0YWTDrXN0aWNhLg0KICAgIA0KYGBge3IsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9DQojIGBQb3N0X1NUQVQxYDogIkkgbGlrZSBzdGF0aXN0aWNzIiwgY29uIGxhcyBzaWd1aWVudGVzIGNvZGlmaWNhY2lvbmVzOiAxPSBTdHJvbmdseSBhZ3JlZTsgMj0gRGlzYWdyZWU7ICAzPSBVbmRlY2lkZWQ7IDQ9IEFncmVlOyA1PSBTdHJvbmdseSBhZ3JlZS4NCg0KIyBgUFNJQ08xYDogIkkgZmVlbCBnb29kIiwgY29uIGxhcyBzaWd1aWVudGVzIGNvZGlmaWNhY2lvbmVzOiAxPUFsbW9zdCBuZXZlcjsgMj0gU29tZXRpbWVzOyAzPSBGcmVxdWVudGx5OyA0PSBBbG1vc3QgYWx3YXlzLg0KDQpgYGANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBFamVtcGxvOiBTb2x1Y2nDs24gKGBnZXRfY2Ffcm93YCkNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIEFyZ3VtZW50b3MgZGUgYGdldF9jYV9yb3dgDQoNClByaW1lcm8sIGxhIGZ1bmNpw7NuIGBnZXRfY2Ffcm93YCBlbiBgZmFjdG9leHRyYWAgc2UgdXRpbGl6YSBwYXJhIGV4dHJhZXIgbG9zIHJlc3VsdGFkb3MgZGUgbGFzIHZhcmlhYmxlcyBkZSBmaWxhLiBFc3RhIGZ1bmNpw7NuIGRldnVlbHZlIHVuYSBsaXN0YSBxdWUgY29udGllbmUgbGFzIGBjb29yZGVuYWRhc2AsIGBjb3MyYCwgYGNvbnRyaWJ1Y2nDs25gIHkgYGluZXJjaWFgIGRlIGxhcyB2YXJpYWJsZXMgZGUgZmlsYS4gDQoNCg0KYGBge3J9DQpyb3cgPC0gZ2V0X2NhX3JvdyhyZXMuY2EpDQpyb3cNCmBgYA0KDQpQcmltZXJvLCBsb3MgZWxlbWVudG9zIGRlIGxhIGZ1bmNpw7NuIGBnZXRfY2Ffcm93YCBwdWVkZW4gdXRpbGl6YXJzZSBlbiBsYSByZXByZXNlbnRhY2nDs24gZGUgZmlsYXMgZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KICANCiAgMS4gYHJvdyRjb29yZGA6IGNvb3JkZW5hZGFzIGRlIGNhZGEgcHVudG8gZGUgZmlsYSBlbiBjYWRhIGRpbWVuc2nDs24gKDEsIDIgeSAzKS4gU2UgdXRpbGl6YW4gcGFyYSBjcmVhciBlbCBncsOhZmljbyBkZSBkaXNwZXJzacOzbi4NCiAgDQogIDIuIGByb3ckY29zMmA6IGNhbGlkYWQgZGUgcmVwcmVzZW50YWNpw7NuIGRlIGxhcyBmaWxhcy4NCiAgDQogIDMuIGBjb2wkY29udHJpYmA6IGNvbnRyaWJ1Y2nDs24gZGUgbGFzIGZpbGFzIChlbiAlKSBhIGxhIGRlZmluaWNpw7NuIGRlIGxhcyBkaW1lbnNpb25lcy4NCg0KDQpFcyBwb3NpYmxlIGdyYWZpY2FyIGxvcyBwdW50b3MgZGUgZmlsYSB5IGNvbG9yZWFybG9zIHNlZ8O6bjoNCiAgDQogIGEpIHN1IGNhbGlkYWQgZW4gZWwgbWFwYSBmYWN0b3JpYWwgKGBjb3MyYCkgbyANCiAgDQogIGIpIHN1cyB2YWxvcmVzIGRlIGNvbnRyaWJ1Y2nDs24gYSBsYSBkZWZpbmljacOzbiBkZSBkaW1lbnNpb25lcyAoYGNvbnRyaWJgKS4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIFZhbG9yZXMgZGUgYGdldF9jYV9yb3dgDQoNCkxvcyBkaWZlcmVudGVzIGNvbXBvbmVudGVzIHB1ZWRlbiBhY2NlZGVyc2UgZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgQ29vcmRlbmFkYXMgZGUgcHVudG9zIGRlIGZpbGFzDQpoZWFkKHJvdyRjb29yZCkNCg0KIyBDb3MyOiBjYWxpZGFkIGRlbCBtYXBhIGZhY3RvcmlhbA0KaGVhZChyb3ckY29zMikNCg0KIyBDb250cmlidWNpb25lcyBhIGxhcyBjb21wb25lbmVudGVzIHByaW5jaXBhbGVzDQpoZWFkKHJvdyRjb250cmliKQ0KYGBgDQoNCg0KUHJpbWVybywgZXhwbGljYW1vcyBjw7NtbyB2aXN1YWxpemFyIHNvbG8gbG9zIHB1bnRvcyBkZSBmaWxhLiBMdWVnbywgZGVzdGFjYW1vcyBsYXMgZmlsYXMgc2Vnw7puOg0KDQphKSBTdSBjYWxpZGFkIGRlIHJlcHJlc2VudGFjacOzbiBlbiBlbCBtYXBhIGZhY3RvcmlhbCBvIA0KDQpiKSBzdXMgY29udHJpYnVjaW9uZXMgYSBsYXMgZGltZW5zaW9uZXMuDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgcm93JGNvb3JkYCkNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGByb3ckY29vcmRgOiB2YWxvcmVzIA0KDQpFbCBjw7NkaWdvIFIgcHJvcG9yY2lvbmFkbyBtdWVzdHJhIGxhcyBjb29yZGVuYWRhcyBkZSBjYWRhIHB1bnRvIGRlIGZpbGEgZW4gY2FkYSBkaW1lbnNpw7NuICgxLCAyIHkgMyk6DQoNCmBgYHtyfQ0KaGVhZChyb3ckY29vcmQpDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgcm93JGNvb3JkYDogZ3LDoWZpY2FzDQoNClVzZSBsYSBmdW5jacOzbiBgZnZpel9jYV9yb3dgICBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAgcGFyYSB2aXN1YWxpemFyIHNvbG8gcHVudG9zIGRlIGZpbGFzOiANCg0KYGBge3J9DQpmdml6X2NhX3JvdyhyZXMuY2EsIHJlcGVsID0gVFJVRSkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGByb3ckY29vcmRgOiBncsOhZmljYXMgKGBjb2wucm93YCwgYHNoYXBlLnJvd2ApDQoNCg0KU2UgcHVlZGUgbW9kaWZpY2FyIGVsIGNvbG9yIHkgbGEgZm9ybWEgZGUgbG9zIHB1bnRvcyBkZSBmaWxhIHV0aWxpemFuZG8gbG9zIGFyZ3VtZW50b3MgYGNvbC5yb3dgIHkgYHNoYXBlLnJvd2AgZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KYGBge3J9DQpmdml6X2NhX3JvdyhyZXMuY2EsIGNvbC5yb3c9InN0ZWVsYmx1ZSIsIHNoYXBlLnJvdyA9IDE1KQ0KYGBgDQoNCkVsIGRpYWdyYW1hIGV4aGliZSBsYXMgcmVsYWNpb25lcyBlbnRyZSBsb3MgcHVudG9zIGRlIGZpbGE6DQoNCjEuIExhcyBmaWxhcyBxdWUgY29tcGFydGVuIHVuIHBlcmZpbCBwYXJlY2lkbyBlc3TDoW4gYWdydXBhZGFzLg0KDQoyLiBMYXMgZmlsYXMgY29uIGNvcnJlbGFjacOzbiBuZWdhdGl2YSBzZSB1YmljYW4gZW4gbGFkb3Mgb3B1ZXN0b3MgZGVsIG9yaWdlbiBkZWwgZGlhZ3JhbWEgKGN1YWRyYW50ZXMgY29udHJhcHVlc3RvcykuDQoNCjMuIExhIGRpc3RhbmNpYSBlbnRyZSBsb3MgcHVudG9zIGRlIGZpbGEgeSBlbCBvcmlnZW4gZXZhbMO6YSBsYSBjYWxpZGFkIGRlIGxvcyBwdW50b3MgZGUgZmlsYSBlbiBlbCBtYXBhIGRlIGZhY3RvcmVzLiBMb3MgcHVudG9zIGRlIGZpbGEgcXVlIHNlIGVuY3VlbnRyYW4gZGlzdGFudGVzIGRlbCBvcmlnZW4gZXN0w6FuIGJpZW4gcmVwcmVzZW50YWRvcyBlbiBlbCBtYXBhIGRlIGZhY3RvcmVzLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEVqZW1wbG86IFNvbHVjacOzbiAoYHJvdyRjb3MyYCkgIA0KICANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgcm93JGNvczJgOiBjYWxpZGFkIGRlIGxhIHJlcHJlc2VudGFjacOzbg0KDQoNCkVsIGFuw6FsaXNpcyBoYSBkZW1vc3RyYWRvIHF1ZSBzZSBwdWRvIHJlcHJlc2VudGFyIGxhIHRhYmxhIGRlIGNvbnRpbmdlbmNpYSBlbiB1biBlc3BhY2lvIGRlIGJhamEgZGltZW5zacOzbiBtZWRpYW50ZSBlbCBhbsOhbGlzaXMgZGUgY29ycmVzcG9uZGVuY2lhLiBMYXMgZGltZW5zaW9uZXMgMSB5IDIgc29uIHN1ZmljaWVudGVzIHBhcmEgcmV0ZW5lciBsYSBtYXlvciBwYXJ0ZSBkZSBsYSB2YXJpYWNpw7NuIGRlIGxvcyBkYXRvcy4gQXVucXVlLCBlcyBpbXBvcnRhbnRlIHRlbmVyIGVuIGN1ZW50YSBxdWUgYWxndW5vcyBwdW50b3Mgbm8gc2UgbXVlc3RyYW4gdGFuIGJpZW4gZW4gYW1iYXMgZGltZW5zaW9uZXMuIExhIGNhbGlkYWQgZGUgbGEgcmVwcmVzZW50YWNpw7NuIGRlIGxhcyBmaWxhcyBlbiBlbCBtYXBhIGRlIGZhY3RvcmVzIHNlIGV2YWzDumEgbWVkaWFudGUgZWwgY29zZW5vIGFsIGN1YWRyYWRvIChgY29zMmApIG8gbGFzIGNvcnJlbGFjaW9uZXMgYWwgY3VhZHJhZG8sIHF1ZSBpbmRpY2FuIGxhIGFzb2NpYWNpw7NuIGVudHJlIGxhcyBmaWxhcy9jb2x1bW5hcyB5IHVuIGVqZSBlc3BlY8OtZmljby4gRWwgYGNvczJgIGRlIGxvcyBwdW50b3MgZGUgbGFzIGZpbGFzIHNlIHB1ZWRlIGNhbGN1bGFyIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQoNCg0KDQpgYGB7cn0NCmhlYWQocm93JGNvczIsIDQpDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgcm93JGNvczJgOiBpbnRlcnBldGFjaW9uZXMgcmVzdW1pZGFzDQoNCg0KMS4gTG9zIHZhbG9yZXMgZGUgYGNvczJgIGVzdMOhbiBjb21wcmVuZGlkb3MgZW50cmUgMCB5IDEuIA0KDQoyLiBMYSBzdW1hIGRlIGxvcyBgY29zMmAgcGFyYSBsYXMgZmlsYXMgZW4gdG9kYXMgbGFzIGRpbWVuc2lvbmVzIGRlIENBIGVzIGlndWFsIGEgdW5vLiANCg0KMy4gTGEgY2FsaWRhZCBkZSBsYSByZXByZXNlbnRhY2nDs24gZGUgdW5hIGZpbGEgbyBjb2x1bW5hIGVuIG4gZGltZW5zaW9uZXMgZXMgc2ltcGxlbWVudGUgbGEgc3VtYSBkZWwgY29zZW5vIGFsIGN1YWRyYWRvIGRlIGVzYSBmaWxhIG8gY29sdW1uYSBzb2JyZSBsYXMgJG40IGRpbWVuc2lvbmVzLg0KDQo0LiBTaSB1biBlbGVtZW50byBkZSBmaWxhIGVzdMOhIGJpZW4gcmVwcmVzZW50YWRvIHBvciBkb3MgZGltZW5zaW9uZXMsIGxhIHN1bWEgZGUgbG9zIGBjb3MyYCBzZSBhY2VyY2EgYSB1bm8uIA0KDQo1LiBQYXJhIGFsZ3Vub3MgZGUgbG9zIGVsZW1lbnRvcyBkZSBmaWxhLCBzZSByZXF1aWVyZW4gbcOhcyBkZSAyIGRpbWVuc2lvbmVzIHBhcmEgcmVwcmVzZW50YXIgcGVyZmVjdGFtZW50ZSBsb3MgZGF0b3MuIA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYHJvdyRjb3MyYDogYXJndW1lbnRvIGBncmFkaWVudC5jb2xzYA0KDQpFcyBwb3NpYmxlIGNvbG9yZWFyIGxvcyBwdW50b3MgZGUgbGFzIGZpbGFzIHNlZ8O6biBzdXMgdmFsb3JlcyBkZSBgY29zMmAgdXRpbGl6YW5kbyBlbCBhcmd1bWVudG8gYGNvbC5yb3cgPSAiY29zMiJgLiBFc3RvIHByb2R1Y2UgY29sb3JlcyBkZWdyYWRhZG9zLiBFbiBlc3RlIGNhc28sIHNlIHB1ZWRlIHV0aWxpemFyIGVsIGFyZ3VtZW50byBgZ3JhZGllbnQuY29sc2AgcGFyYSBwcm9wb3JjaW9uYXIgdW4gY29sb3IgcGVyc29uYWxpemFkby4gDQoNClBvciBlamVtcGxvLCBgZ3JhZGllbnQuY29scyA9IGMoImdyZWVuIiwgImJyb3duIiwgImJsdWUiKWAgc2lnbmlmaWNhIHF1ZToNCg0KMS4gTGFzIHZhcmlhYmxlcyBjb24gdmFsb3JlcyBiYWpvcyBkZSBgY29zMmAgc2Vyw6FuIGNvbG9yZWFkYXMgZW4gKnZlcmRlKi4NCg0KMi4gTGFzIHZhcmlhYmxlcyBjb24gdmFsb3JlcyBtZWRpb3MgZGUgYGNvczJgIHNlcsOhbiBjb2xvcmVhZGFzIGVuICptYXJyw7NuKi4NCg0KMy4gTGFzIHZhcmlhYmxlcyBjb24gdmFsb3JlcyBhbHRvcyBkZSBgY29zMmAgc2Vyw6FuIGNvbG9yZWFkYXMgZW4gKmF6dWwqLg0KDQpgYGB7cn0NCiMgQ29sb3IgcG9yIHZhbG9yZXMgY29zMjogY2FsaWFkIGRlbCBtYXBhIGZhY3RvcmlhbA0KDQpNaXNDb2xvcmVzIDwtIGMoImdyZWVuIiwgImJyb3duIiwgImJsdWUiKQ0KDQpmdml6X2NhX3JvdyhyZXMuY2EsIGNvbC5yb3cgPSAiY29zMiIsDQogICAgICAgICAgICBncmFkaWVudC5jb2xzID0gTWlzQ29sb3JlcywNCiAgICAgICAgICAgIHJlcGVsID0gVFJVRSkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGByb3ckY29zMmA6IHRyYW5zcGFyaWVuY2lhcyBjb24gYGFscGhhLnZhcmANCg0KVGFtYmnDqW4gZXMgcG9zaWJsZSBhanVzdGFyIGxhIHRyYW5zcGFyZW5jaWEgZGUgbGFzIHZhcmlhYmxlcyBzZWfDum4gbG9zIHZhbG9yZXMgZGUgYGNvczJgIHV0aWxpemFuZG8gbGEgb3BjacOzbiBgYWxwaGEucm93ID0gImNvczIiYDogDQoNCmBgYHtyfQ0KIyBDYW1iaWFyIGxhIHRyYW5zcGFyaWVuY2lhIHBvciB2YWxvcmVzIGRlIGNvczINCg0KZnZpel9jYV9yb3cocmVzLmNhLCBhbHBoYS5yb3cgPSAiY29zMiIsDQogICAgICAgICAgICAgY29sLnJvdyA9ICJyZWQiLA0KICAgICAgICAgICAgIHRpdGxlPSJUcmFuc3BhcmllbmNpYSBkZSBsYXMgZmlsYXMgcG9yIGNvczIiLA0KICAgICAgICAgICAgIHJlcGVsID0gVFJVRSAjIEV2aXRhIHRyYXNsYXBhbWllbnRvIGRlIHRleHRvcw0KICAgICAgICAgICAgICkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGByb3ckY29zMmA6IGNvcnJlbGFjaW9uZXMNCg0KU2UgcHVlZGUgcmVwcmVzZW50YXIgZ3LDoWZpY2FtZW50ZSBlbCBgY29zMmAgZGUgbG9zIHB1bnRvcyBkZSBmaWxhIGVuIHRvZGFzIGxhcyBkaW1lbnNpb25lcyB1dGlsaXphbmRvIGVsIHBhcXVldGUgYGNvcnJwbG90YC4NCg0KDQpgYGB7cn0NCmxpYnJhcnkoImNvcnJwbG90IikNCmNvcnJwbG90KHJvdyRjb3MyLCANCiAgICAgICAgIGlzLmNvcnI9RkFMU0UsICMgU2UgcHVlZGUgYWN0aXZhciBvIG5vDQogICAgICAgICB0bC5jb2wgPSAiYmxhY2siLCANCiAgICAgICAgICNhZGRDb2VmLmNvbCA9ICdncmV5NTAnLCAjQWdyZWdhciB2YWxvcmVzDQogICAgICAgICAjbnVtYmVyLmNleCA9IDAuNywgICAgICAgI1RhbWHDsW8gZGUgbG9zIHZhbG9yZXMNCiAgICAgICAgIHRsLnNydCA9IDkwLCANCiAgICAgICAgIGJnID0gImxpZ2h0Ymx1ZSIsICAgICAgICAjQ29sb3IgZGVsIGZvbmRvDQogICAgICAgICB0aXRsZT0iTWF0cml6IGRlIGNvcnJlbGFjaW9uZXMiLCANCiAgICAgICAgICN0bC5jZXg9MS41LCAgICAgICAgICAgICNUYW1hw7FvIGRlIGxhcyBmdWVudGVzDQogICAgICAgICAjY2V4Lm1haW49Mi4wLCAgICAgICAgICAjVGFtYcOxbyBkZWwgdMOtdHVsbw0KICAgICAgICAgI3R5cGU9Imxvd2VyIiwNCiAgICAgICAgIG1hcj1jKDAsMCw0LDApIA0KICAgICAgICAgKQ0KYGBgDQoNClNlIGRlYmUgdGVuZXIgZW4gY3VlbnRhIHF1ZSB0b2RvcyBsb3MgcHVudG9zIGRlIGZpbGEgZXhjZXB0byBgNC5BZ3JlZWAgeSBgMi5EaXNhZ3JlZWAgZXN0w6FuIGJpZW4gcmVwcmVzZW50YWRvcyBwb3IgbGFzIGRvcyBwcmltZXJhcyBkaW1lbnNpb25lcy4gRXN0byBzdWdpZXJlIHF1ZSBsYSBwb3NpY2nDs24gZGVsIHB1bnRvIGNvcnJlc3BvbmRpZW50ZSBhIGVzb3Mgw610ZW1zIGVuIGVsIGdyw6FmaWNvIGRlIGRpc3BlcnNpw7NuIGRlYmUgaW50ZXJwcmV0YXJzZSBjb24gY2llcnRhIHByZWNhdWNpw7NuLiBFcyBwcm9iYWJsZSBxdWUgdW5hIHNvbHVjacOzbiBkZSBkaW1lbnNpb25lcyBzdXBlcmlvcmVzIHNlYSBuZWNlc2FyaWEgcGFyYSBsb3Mgw610ZW1zIG1lbmNpb25hZG9zLg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGByb3ckY29zMmA6IGRpYWdyYW1hIGRlIGJhcnJhcw0KDQpUYW1iacOpbiBlcyBwb3NpYmxlIGNyZWFyIHVuIGRpYWdyYW1hIGRlIGJhcnJhIHBhcmEgbG8gdmFsb3JlcyBgY29zMmAgdXNhbmRvIGxhIGZ1bmNpw7NuIGBmdml6X2NvczJgIGRlbCBwYXF1ZXRlIA0KYGZhY3RvZXh0cmFgLg0KDQpgYGB7cn0NCiMgQ29zMiBkZSBsYXMgZmlsYXMgc29icmUgbGFzIGRpbWVuc2lvbmVzIDEgeSAyDQoNCmZ2aXpfY29zMihyZXMuY2EsIGNob2ljZSA9ICJyb3ciLCBheGVzID0gMToyKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEVqZW1wbG86IFNvbHVjacOzbiAoYHJvdyRjb250cmliYCkNCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYHJvdyRjb250cmliYDogZ2VuZXJhbA0KDQpMYSBjb250cmlidWNpw7NuIGRlIGxhcyBmaWxhcyAoZW4gJSkgYSBsYSBkZWZpbmljacOzbiBkZSBsYXMgZGltZW5zaW9uZXMgc2UgcHVlZGUgZXh0cmFlciBkZSBsYSBzaWd1aWVudGUgbWFuZXJhOg0KDQoNCmBgYHtyfQ0KaGVhZChyb3ckY29udHJpYikNCmBgYA0KDQpMYXMgdmFyaWFibGVzIGRlIGZpbGEgY29uIHVuIHZhbG9yIG3DoXMgYWx0byBzb24gbGFzIHF1ZSBtw6FzIGNvbnRyaWJ1eWVuIGEgbGEgZGVmaW5pY2nDs24gZGUgbGFzIGRpbWVuc2lvbmVzLg0KDQogICsgTGFzIGZpbGFzIHF1ZSBtw6FzIGNvbnRyaWJ1eWVuIGEgYERpbS4xYCB5IGBEaW0uMmAgc29uIGxhcyBtw6FzIGltcG9ydGFudGVzIHBhcmEgZXhwbGljYXIgbGEgdmFyaWFiaWxpZGFkIGVuIGVsIGNvbmp1bnRvIGRlIGRhdG9zLg0KICAgIA0KICArIExhcyBmaWxhcyBxdWUgbm8gY29udHJpYnV5ZW4gbXVjaG8gYSBuaW5ndW5hIGRpbWVuc2nDs24gbyBxdWUgY29udHJpYnV5ZW4gYSBsYXMgw7psdGltYXMgZGltZW5zaW9uZXMgc29uIG1lbm9zIGltcG9ydGFudGVzLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYHJvdyRjb250cmliYDogY29ycmVsYWNpb25lcw0KDQpFcyBwb3NpYmxlIHV0aWxpemFyIGxhIGZ1bmNpw7NuIGBjb3JycGxvdGAgZGVsIHBhcXVldGUgYGNvcnJwbG90YCBwYXJhIHJlc2FsdGFyIGxvcyBwdW50b3MgZGUgZmlsYSBxdWUgbcOhcyBjb250cmlidXllbiBwYXJhIGNhZGEgZGltZW5zacOzbjoNCg0KDQpgYGB7cn0NCmxpYnJhcnkoImNvcnJwbG90IikNCmNvcnJwbG90KHJvdyRjb250cmliLCANCiAgICAgICAgIGlzLmNvcnI9RkFMU0UsICAgICAgICAgICAgI05vIHNlIHB1ZWRlIGRlc2FjdGl2YXIgZXN0ZSBhcmd1bWVudG8NCiAgICAgICAgIHRsLmNvbCA9ICJibGFjayIsIA0KICAgICAgICAgI2FkZENvZWYuY29sID0gJ2dyZXk1MCcsICNBZ3JlZ2FyIHZhbG9yZXMNCiAgICAgICAgICNudW1iZXIuY2V4ID0gMC43LCAgICAgICAjVGFtYcOxbyBkZSBsb3MgdmFsb3Jlcw0KICAgICAgICAgdGwuc3J0ID0gOTAsIA0KICAgICAgICAgYmcgPSAibGlnaHRibHVlIiwgICAgICAgICNDb2xvciBkZWwgZm9uZG8NCiAgICAgICAgIHRpdGxlPSJNYXRyaXogZGUgY29ycmVsYWNpb25lcyIsIA0KICAgICAgICAgI3RsLmNleD0xLjUsICAgICAgICAgICAgI1RhbWHDsW8gZGUgbGFzIGZ1ZW50ZXMNCiAgICAgICAgICNjZXgubWFpbj0yLjAsICAgICAgICAgICNUYW1hw7FvIGRlbCB0w610dWxvDQogICAgICAgICAjdHlwZT0ibG93ZXIiLA0KICAgICAgICAgbWFyPWMoMCwwLDQsMCkgICAgICAgICAgI1ViaWNhY2nDs24gZGVsIHTDrXR1bG8NCiAgICAgICAgICkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGByb3ckY29udHJpYmA6IGRpYWdyYW1hcyBkZSBiYXJyYSBkZSBjYWRhIHZhcmlhYmxlDQoNCg0KTGEgZnVuY2nDs24gYGZ2aXpfY29udHJpYmAgZGVsIHBhcXVldGUgYGZhY3RvZXh0cmFgIHNlIHB1ZWRlIGVtcGxlYXIgcGFyYSBkaWJ1amFyIHVuIGdyw6FmaWNvIGRlIGJhcnJhcyBkZSBsYXMgY29udHJpYnVjaW9uZXMgZGUgbGFzIGZpbGFzLiBTaSBsb3MgZGF0b3MgY29udGllbmVuIG11Y2hhcyBmaWxhcywgc2UgcHVlZGUgb3B0YXIgcG9yIG1vc3RyYXIgc29sbyBsYXMgZmlsYXMgcXVlIG3DoXMgY29udHJpYnV5ZW4uIEVsIHNpZ3VpZW50ZSBjw7NkaWdvIGVuIFIgbXVlc3RyYSBsYXMgMTAgZmlsYXMgcHJpbmNpcGFsZXMgcXVlIGNvbnRyaWJ1eWVuIGEgbGFzIGRpbWVuc2lvbmVzLg0KDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBDb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGEgbGEgZGltZW5zacOzbiAxDQpwMSA8LSBmdml6X2NvbnRyaWIocmVzLmNhLCBjaG9pY2UgPSAicm93IiwgYXhlcyA9IDEsIHRvcCA9IDEwKQ0KDQojIENvbnRyaWJ1Y2lvbmVzIGRlIGxhcyB2YXJpYWJsZXMgYSBsYSBkaW1lbnNpw7NuIDINCnAyIDwtIGZ2aXpfY29udHJpYihyZXMuY2EsIGNob2ljZSA9ICJyb3ciLCBheGVzID0gMiwgdG9wID0gMTApDQoNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCiMgQ29udHJpYnVjaW9uZXMgZGUgbGFzIHZhcmlhYmxlcyBhIGxhIGRpbWVuc2nDs24gMQ0KcDEgPC0gZnZpel9jb250cmliKHJlcy5jYSwgY2hvaWNlID0gInJvdyIsIGF4ZXMgPSAxLCB0b3AgPSAxMCkNCg0KIyBDb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGEgbGEgZGltZW5zacOzbiAyDQpwMiA8LSBmdml6X2NvbnRyaWIocmVzLmNhLCBjaG9pY2UgPSAicm93IiwgYXhlcyA9IDIsIHRvcCA9IDEwKQ0KDQpsaWJyYXJ5KGdyaWRFeHRyYSkgDQoNCmdyaWQuYXJyYW5nZShwMSxwMiwgbmNvbD0yLCBucm93ID0xKQ0KYGBgDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgcm93JGNvbnRyaWJgOiBkaWFncmFtYSBkZSBiYXJyYSBwYXJhIGxhIHRvdGFsDQoNCg0KQSBjb250aW51YWNpw7NuLCBzZSBwdWVkZSB2aXN1YWxpemFyIGxhIGNvbnRyaWJ1Y2nDs24gdG90YWwgYSBsYXMgZGltZW5zaW9uZXMgMSB5IDI6IA0KDQpgYGB7cn0NCmZ2aXpfY29udHJpYihyZXMuY2EsIGNob2ljZSA9ICJyb3ciLCBheGVzID0gMToyLCB0b3AgPSAxMCkNCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYHJvdyRjb250cmliYDogSW50ZXJwcmV0YWNpb25lcyANCg0KKipJbnRlcnByZXRhY2nDs24gTm8uIDE6ICoqDQoNCkxhIGzDrW5lYSByb2phIGRpc2NvbnRpbnVhIGVuIGVsIGdyw6FmaWNvIGFudGVyaW9yIGluZGljYSBsYSBjb250cmlidWNpw7NuIHByb21lZGlvIGVzcGVyYWRhLiANCg0KKipJbnRlcnByZXRhY2nDs24gTm8uIDI6ICoqDQogIA0KU2kgbGEgY29udHJpYnVjacOzbiBkZSBsYXMgdmFyaWFibGVzIGZ1ZXNlIHVuaWZvcm1lLCBlbCB2YWxvciBlc3BlcmFkbyBzZXLDrWEgDQogIA0KICAkJFxmcmFjezF9e1xtYm94e2xvbmdpdHVkKGZpbGFzKX19IFw7PVw7IFxmcmFjezF9ezV9KDEwMClcOz1cOyAyMFwsIFwlJCQNCiAgDQpgYGB7cn0NCiAgKDEvbnJvdyh0YWJsYSkpKjEwMA0KYGBgDQoNCg0KKipJbnRlcnByZXRhY2nDs24gTm8uIDM6ICoqDQoNClBhcmEgdW5hIGRpbWVuc2nDs24gZGFkYSwgdW5hIGZpbGEgY29uIHVuYSBjb250cmlidWNpw7NuIG1heW9yIHF1ZSBlc3RlIHVtYnJhbCBwb2Ryw61hIGNvbnNpZGVyYXJzZSBpbXBvcnRhbnRlIGVuIGxhIGNvbnRyaWJ1Y2nDs24gYSBsYSBkaW1lbnNpw7NuLiANCiAgDQogIA0KKipJbnRlcnByZXRhY2nDs24gTm8uIDQ6ICoqDQoNClNlIHB1ZWRlIG9ic2VydmFyIHF1ZSBsYSB2YXJpYWJsZSBgNS5TdHIuQWdyZWVgIGNvbnRyaWJ1eWUgbcOhcyBhIGxhcyBkaW1lbnNpb25lcyAxIHkgMi4NCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYHJvdyRjb250cmliYDogYXJndW1lbnRvIGBncmFkaWVudC5jb2xzYA0KDQpDb21vIHlhIHNlIGV4cGxpY8OzLCBgZ3JhZGllbnQuY29scyA9IGMoImdyZWVuIiwgImJyb3duIiwgImJsdWUiKWAgc2lnbmlmaWNhIHF1ZToNCg0KMS4gTGFzIHZhcmlhYmxlcyBjb24gdmFsb3JlcyBiYWpvcyBkZSBgY29zMmAgc2Vyw6FuIGNvbG9yZWFkYXMgZW4gKnZlcmRlKi4NCg0KMi4gTGFzIHZhcmlhYmxlcyBjb24gdmFsb3JlcyBtZWRpb3MgZGUgYGNvczJgIHNlcsOhbiBjb2xvcmVhZGFzIGVuICptYXJyw7NuKi4NCg0KMy4gTGFzIHZhcmlhYmxlcyBjb24gdmFsb3JlcyBhbHRvcyBkZSBgY29zMmAgc2Vyw6FuIGNvbG9yZWFkYXMgZW4gKmF6dWwqLg0KDQoNCmBgYHtyfQ0KTWlzQ29sb3JlcyA8LSBjKCJncmVlbiIsICJicm93biIsICJibHVlIikNCiAgDQpmdml6X2NhX3JvdyhyZXMuY2EsIGNvbC5yb3cgPSAiY29udHJpYiIsIA0KICAgICAgICAgICAgIHJlcGVsPSBUUlVFLCAjIEV2aXRhIHRyYXNsYXBhbWllbnRvIGRlIHRleHRvcywNCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gTWlzQ29sb3JlcywNCiAgICAgICAgICAgICApDQoNCmBgYA0KDQoqKkludGVycHJldGFjaW9uZXM6KioNCg0KMS4gRWwgZ3LDoWZpY28gZGUgZGlzcGVyc2nDs24gb2ZyZWNlIHVuYSBpZGVhIGRlIHF1w6kgcG9sbyBkZSBsYXMgZGltZW5zaW9uZXMgZXN0w6FuIGNvbnRyaWJ1eWVuZG8gcmVhbG1lbnRlIGxhcyBjYXRlZ29yw61hcyBkZSBsYXMgZmlsYXMuDQoNCjIuIEVzIGV2aWRlbnRlIHF1ZSBsYXMgY2F0ZWdvcsOtYXMgZGUgZmlsYXMgYDEuU2RyLkRpc2FncmVlYCwgIHkgYDMuVW5kZWNpZGVkYCB0aWVuZW4gdW5hIGNvbnRyaWJ1Y2nDs24gaW1wb3J0YW50ZSBhbCBwb2xvIG5lZ2F0aXZvIGRlIGxhIHByaW1lcmEgZGltZW5zacOzbi4gDQoNCjMuIE1pZW50cmFzIHF1ZSBsYSBjYXRlZ29yw61hICBgNS5TdHIuQWdlZWAgdGllbmVuIHVuYSBjb250cmlidWNpw7NuIG1heW9yIGFsIHBvbG8gcG9zaXRpdm8gZGUgbGEgcHJpbWVyYSBkaW1lbnNpw7NuOyBldGMuLCAuLi4NCg0KNC4gRW4gb3RyYXMgcGFsYWJyYXMsIGxhIGRpbWVuc2nDs24gMSBlc3TDoSBwcmluY2lwYWxtZW50ZSBkZWZpbmlkYSBwb3IgbGEgb3Bvc2ljacOzbiBkZSBgMS5TZHIuRGlzYWdyZWVgLCAgeSBgMy5VbmRlY2lkZWRgIChwb2xvIG5lZ2F0aXZvKSwgeSBgNS5TdHIuQWdlZWAgKHBvbG8gcG9zaXRpdm8pLg0KDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGByb3ckY29udHJpYmA6IHRyYW5zcGFyaWVuY2lhcyBjb24gYGFscGhhLnZhcmANCg0KVGVuZ2EgZW4gY3VlbnRhIHF1ZSB0YW1iacOpbiBlcyBwb3NpYmxlIGNhbWJpYXIgbGEgdHJhbnNwYXJlbmNpYSBkZSBsYXMgZmlsYXMgc2Vnw7puIHN1cyB2YWxvcmVzIGRlIGNvbnRyaWJ1Y2nDs24gdXRpbGl6YW5kbyBsYSBvcGNpw7NuIGBhbHBoYS5yb3cgPSAiY29udHJpYiJgOg0KDQpgYGB7cn0NCiMgQ2FtYmlhciBsYSB0cmFuc3BhcmllbmNpYSBwYXJhIGxhcyBjb250cmlidWNpb25lcw0KZnZpel9jYV9yb3cocmVzLmNhLCBhbHBoYS5yb3cgPSAiY29udHJpYiIsDQogICAgICAgICAgICAgY29sLnJvdyA9ICJyZWQiLA0KICAgICAgICAgICAgICN0aXRsZT0iVHJhbnNwYXJpZW5jaWEgZGUgbGFzIHZhcmlhYmxlcyBwb3IgY29udHJpYnVjacOzbiIsIA0KICAgICAgICAgICAgIHJlcGVsPSBUUlVFICMgRXZpdGEgdHJhc2xhcGFtaWVudG8gZGUgdGV4dG9zLA0KICAgICAgICAgICAgICkNCmBgYA0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgZ2V0X2NhX2NvbGApDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBBcmd1bWVudG9zIGRlIGBnZXRfY2FfY29sYA0KDQpQcmltZXJvLCBsYSBmdW5jacOzbiBgZ2V0X2NhX2NvbGAgZW4gYGZhY3RvZXh0cmFgIHNlIHV0aWxpemEgcGFyYSBleHRyYWVyIGxvcyByZXN1bHRhZG9zIGRlIGxhcyB2YXJpYWJsZXMgZGUgY29sdW1uYS4gRXN0YSBmdW5jacOzbiBkZXZ1ZWx2ZSB1bmEgbGlzdGEgcXVlIGNvbnRpZW5lIGxhcyBgY29vcmRlbmFkYXNgLCBgY29zMmAsIGBjb250cmlidWNpw7NuYCB5IGBpbmVyY2lhYCBkZSBsYXMgdmFyaWFibGVzIGRlIGNvbHVtbmEuIA0KDQoNCmBgYHtyfQ0KY29sIDwtIGdldF9jYV9jb2wocmVzLmNhKQ0KY29sDQpgYGANCg0KUHJpbWVybywgbG9zIGVsZW1lbnRvcyBkZSBsYSBmdW5jacOzbiBgZ2V0X2NhX2NvbGAgcHVlZGVuIHV0aWxpemFyc2UgZW4gbGEgcmVwcmVzZW50YWNpw7NuIGRlIGNvbHVtbmFzIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQoNCiAgDQogIDEuIGBjb2wkY29vcmRgOiBjb29yZGVuYWRhcyBkZSBjYWRhIHB1bnRvIGRlIGNvbHVtbmEgZW4gY2FkYSBkaW1lbnNpw7NuICgxLCAyIHkgMykuIFNlIHV0aWxpemFuIHBhcmEgY3JlYXIgZWwgZ3LDoWZpY28gZGUgZGlzcGVyc2nDs24uDQogIA0KICAyLiBgY29sJGNvczJgOiBjYWxpZGFkIGRlIHJlcHJlc2VudGFjacOzbiBkZSBsYXMgY29sdW1uYXMuDQogIA0KICAzLiBgY29sJGNvbnRyaWJgOiBjb250cmlidWNpw7NuIGRlIGxhcyBjb2x1bW5hcyAoZW4gJSkgYSBsYSBkZWZpbmljacOzbiBkZSBsYXMgZGltZW5zaW9uZXMuDQoNCg0KRXMgcG9zaWJsZSBncmFmaWNhciBsb3MgcHVudG9zIGRlIGNvbHVtbmEgeSBjb2xvcmVhcmxvcyBzZWfDum46DQogIA0KICBhKSBzdSBjYWxpZGFkIGVuIGVsIG1hcGEgZmFjdG9yaWFsIChgY29zMmApIG8gDQogIA0KICBiKSBzdXMgdmFsb3JlcyBkZSBjb250cmlidWNpw7NuIGEgbGEgZGVmaW5pY2nDs24gZGUgZGltZW5zaW9uZXMgKGBjb250cmliYCkuDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBWYWxvcmVzIGRlIGBnZXRfY2FfY29sYA0KDQpMb3MgZGlmZXJlbnRlcyBjb21wb25lbnRlcyBwdWVkZW4gYWNjZWRlcnNlIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojIENvb3JkZW5hZGFzIGRlIHB1bnRvcyBkZSBjb2x1bW5hcw0KaGVhZChjb2wkY29vcmQpDQoNCiMgQ29zMjogY2FsaWRhZCBkZWwgbWFwYSBmYWN0b3JpYWwNCmhlYWQoY29sJGNvczIpDQoNCiMgQ29udHJpYnVjaW9uZXMgYSBsYXMgY29tcG9uZW5lbnRlcyBwcmluY2lwYWxlcw0KaGVhZChjb2wkY29udHJpYikNCmBgYA0KDQoNClByaW1lcm8sIGV4cGxpY2Ftb3MgY8OzbW8gdmlzdWFsaXphciBzb2xvIGxvcyBwdW50b3MgZGUgY29sdW1uYS4gTHVlZ28sIGRlc3RhY2Ftb3MgbGFzIGNvbHVtbmFzIHNlZ8O6bjoNCg0KYSkgU3UgY2FsaWRhZCBkZSByZXByZXNlbnRhY2nDs24gZW4gZWwgbWFwYSBmYWN0b3JpYWwgbyANCg0KYikgc3VzIGNvbnRyaWJ1Y2lvbmVzIGEgbGFzIGRpbWVuc2lvbmVzLg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgY29sJGNvb3JkYCkNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgY29sJGNvb3JkYDogdmFsb3Jlcw0KDQpFbCBjw7NkaWdvIFIgcHJvcG9yY2lvbmFkbyBtdWVzdHJhIGxhcyBjb29yZGVuYWRhcyBkZSBjYWRhIHB1bnRvIGRlIGNvbHVtbmEgZW4gY2FkYSBkaW1lbnNpw7NuICgxLCAyIHkgMyk6DQoNCmBgYHtyfQ0KaGVhZChjb2wkY29vcmQpDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgY29sJGNvb3JkYDogZ3LDoWZpY2FzDQoNClVzZSBsYSBmdW5jacOzbiBgZnZpel9jYV9jb2xgICBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAgcGFyYSB2aXN1YWxpemFyIHNvbG8gcHVudG9zIGRlIGNvbHVtbmFzOiANCg0KYGBge3J9DQpmdml6X2NhX2NvbChyZXMuY2EsIHJlcGVsID0gVFJVRSkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBjb2wkY29vcmRgOiBncsOhZmljYXMgKGBjb2wuY29sYCwgYHNoYXBlLmNvbGApDQoNCg0KU2UgcHVlZGUgbW9kaWZpY2FyIGVsIGNvbG9yIHkgbGEgZm9ybWEgZGUgbG9zIHB1bnRvcyBkZSBjb2x1bW5hIHV0aWxpemFuZG8gbG9zIGFyZ3VtZW50b3MgYGNvbC5jb2xgIHkgYHNoYXBlLmNvbGAgZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KYGBge3J9DQpmdml6X2NhX2NvbChyZXMuY2EsIGNvbC5jb2w9InN0ZWVsYmx1ZSIsIHNoYXBlLmNvbCA9IDE1KQ0KYGBgDQoNCkVsIGRpYWdyYW1hIGV4aGliZSBsYXMgcmVsYWNpb25lcyBlbnRyZSBsb3MgcHVudG9zIGRlIGNvbHVtbmE6DQoNCjEuIExhcyBjb2x1bW5hcyBxdWUgY29tcGFydGVuIHVuIHBlcmZpbCBwYXJlY2lkbyBlc3TDoW4gYWdydXBhZGFzLg0KDQoyLiBMYXMgY29sdW1uYXMgY29uIGNvcnJlbGFjacOzbiBuZWdhdGl2YSBzZSB1YmljYW4gZW4gbGFkb3Mgb3B1ZXN0b3MgZGVsIG9yaWdlbiBkZWwgZGlhZ3JhbWEgKGN1YWRyYW50ZXMgY29udHJhcHVlc3RvcykuDQoNCjMuIExhIGRpc3RhbmNpYSBlbnRyZSBsb3MgcHVudG9zIGRlIGNvbHVtbmEgeSBlbCBvcmlnZW4gZXZhbMO6YSBsYSBjYWxpZGFkIGRlIGxvcyBwdW50b3MgZGUgY29sdW1uYSBlbiBlbCBtYXBhIGRlIGZhY3RvcmVzLiBMb3MgcHVudG9zIGRlIGNvbHVtbmEgcXVlIHNlIGVuY3VlbnRyYW4gZGlzdGFudGVzIGRlbCBvcmlnZW4gZXN0w6FuIGJpZW4gcmVwcmVzZW50YWRvcyBlbiBlbCBtYXBhIGRlIGZhY3RvcmVzLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEVqZW1wbG86IFNvbHVjacOzbiAoYGNvbCRjb3MyYCkgIA0KICANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgY29sJGNvczJgOiBjYWxpZGFkIGRlIGxhIHJlcHJlc2VudGFjacOzbg0KDQoNCkVsIGFuw6FsaXNpcyBoYSBkZW1vc3RyYWRvIHF1ZSBzZSBwdWRvIHJlcHJlc2VudGFyIGxhIHRhYmxhIGRlIGNvbnRpbmdlbmNpYSBlbiB1biBlc3BhY2lvIGRlIGJhamEgZGltZW5zacOzbiBtZWRpYW50ZSBlbCBhbsOhbGlzaXMgZGUgY29ycmVzcG9uZGVuY2lhLiBMYXMgZGltZW5zaW9uZXMgMSB5IDIgc29uIHN1ZmljaWVudGVzIHBhcmEgcmV0ZW5lciBsYSBtYXlvciBwYXJ0ZSBkZSBsYSB2YXJpYWNpw7NuIGRlIGxvcyBkYXRvcy4gQXVucXVlLCBlcyBpbXBvcnRhbnRlIHRlbmVyIGVuIGN1ZW50YSBxdWUgYWxndW5vcyBwdW50b3Mgbm8gc2UgbXVlc3RyYW4gdGFuIGJpZW4gZW4gYW1iYXMgZGltZW5zaW9uZXMuIExhIGNhbGlkYWQgZGUgbGEgcmVwcmVzZW50YWNpw7NuIGRlIGxhcyBjb2x1bW5hcyBlbiBlbCBtYXBhIGRlIGZhY3RvcmVzIHNlIGV2YWzDumEgbWVkaWFudGUgZWwgY29zZW5vIGFsIGN1YWRyYWRvIChgY29zMmApIG8gbGFzIGNvcnJlbGFjaW9uZXMgYWwgY3VhZHJhZG8sIHF1ZSBpbmRpY2FuIGxhIGFzb2NpYWNpw7NuIGVudHJlIGxhcyBjb2x1bW5hcy9jb2x1bW5hcyB5IHVuIGVqZSBlc3BlY8OtZmljby4gRWwgYGNvczJgIGRlIGxvcyBwdW50b3MgZGUgbGFzIGNvbHVtbmFzIHNlIHB1ZWRlIGNhbGN1bGFyIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQoNCg0KDQpgYGB7cn0NCmhlYWQoY29sJGNvczIsIDQpDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgY29sJGNvczJgOiBpbnRlcnBldGFjaW9uZXMgcmVzdW1pZGFzDQoNCg0KMS4gTG9zIHZhbG9yZXMgZGUgYGNvczJgIGVzdMOhbiBjb21wcmVuZGlkb3MgZW50cmUgMCB5IDEuIA0KDQoyLiBMYSBzdW1hIGRlIGxvcyBgY29zMmAgcGFyYSBsYXMgY29sdW1uYXMgZW4gdG9kYXMgbGFzIGRpbWVuc2lvbmVzIGRlIENBIGVzIGlndWFsIGEgdW5vLiANCg0KMy4gTGEgY2FsaWRhZCBkZSBsYSByZXByZXNlbnRhY2nDs24gZGUgdW5hIGNvbHVtbmEgbyBjb2x1bW5hIGVuIG4gZGltZW5zaW9uZXMgZXMgc2ltcGxlbWVudGUgbGEgc3VtYSBkZWwgY29zZW5vIGFsIGN1YWRyYWRvIGRlIGVzYSBjb2x1bW5hIG8gY29sdW1uYSBzb2JyZSBsYXMgJG40IGRpbWVuc2lvbmVzLg0KDQo0LiBTaSB1biBlbGVtZW50byBkZSBjb2x1bW5hIGVzdMOhIGJpZW4gcmVwcmVzZW50YWRvIHBvciBkb3MgZGltZW5zaW9uZXMsIGxhIHN1bWEgZGUgbG9zIGBjb3MyYCBzZSBhY2VyY2EgYSB1bm8uIA0KDQo1LiBQYXJhIGFsZ3Vub3MgZGUgbG9zIGVsZW1lbnRvcyBkZSBjb2x1bW5hLCBzZSByZXF1aWVyZW4gbcOhcyBkZSAyIGRpbWVuc2lvbmVzIHBhcmEgcmVwcmVzZW50YXIgcGVyZmVjdGFtZW50ZSBsb3MgZGF0b3MuIA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGNvbCRjb3MyYDogYXJndW1lbnRvIGBncmFkaWVudC5jb2xzYA0KDQpFcyBwb3NpYmxlIGNvbG9yZWFyIGxvcyBwdW50b3MgZGUgbGFzIGNvbHVtbmFzIHNlZ8O6biBzdXMgdmFsb3JlcyBkZSBgY29zMmAgdXRpbGl6YW5kbyBlbCBhcmd1bWVudG8gYGNvbC5jb2wgPSAiY29zMiJgLiBFc3RvIHByb2R1Y2UgY29sb3JlcyBkZWdyYWRhZG9zLiBFbiBlc3RlIGNhc28sIHNlIHB1ZWRlIHV0aWxpemFyIGVsIGFyZ3VtZW50byBgZ3JhZGllbnQuY29sc2AgcGFyYSBwcm9wb3JjaW9uYXIgdW4gY29sb3IgcGVyc29uYWxpemFkby4gDQoNClBvciBlamVtcGxvLCBgZ3JhZGllbnQuY29scyA9IGMoImdyZWVuIiwgImJyb3duIiwgImJsdWUiKWAgc2lnbmlmaWNhIHF1ZToNCg0KMS4gTGFzIHZhcmlhYmxlcyBjb24gdmFsb3JlcyBiYWpvcyBkZSBgY29zMmAgc2Vyw6FuIGNvbG9yZWFkYXMgZW4gKnZlcmRlKi4NCg0KMi4gTGFzIHZhcmlhYmxlcyBjb24gdmFsb3JlcyBtZWRpb3MgZGUgYGNvczJgIHNlcsOhbiBjb2xvcmVhZGFzIGVuICptYXJyw7NuKi4NCg0KMy4gTGFzIHZhcmlhYmxlcyBjb24gdmFsb3JlcyBhbHRvcyBkZSBgY29zMmAgc2Vyw6FuIGNvbG9yZWFkYXMgZW4gKmF6dWwqLg0KDQpgYGB7cn0NCiMgQ29sb3IgcG9yIHZhbG9yZXMgY29zMjogY2FsaWFkIGRlbCBtYXBhIGZhY3RvcmlhbA0KDQpNaXNDb2xvcmVzIDwtIGMoImdyZWVuIiwgImJyb3duIiwgImJsdWUiKQ0KDQpmdml6X2NhX2NvbChyZXMuY2EsIGNvbC5jb2wgPSAiY29zMiIsDQogICAgICAgICAgICBncmFkaWVudC5jb2xzID0gTWlzQ29sb3JlcywNCiAgICAgICAgICAgIHJlcGVsID0gVFJVRSkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBjb2wkY29zMmA6IHRyYW5zcGFyaWVuY2lhcyBjb24gYGFscGhhLnZhcmANCg0KVGFtYmnDqW4gZXMgcG9zaWJsZSBhanVzdGFyIGxhIHRyYW5zcGFyZW5jaWEgZGUgbGFzIHZhcmlhYmxlcyBzZWfDum4gbG9zIHZhbG9yZXMgZGUgYGNvczJgIHV0aWxpemFuZG8gbGEgb3BjacOzbiBgYWxwaGEuY29sID0gImNvczIiYDogDQoNCmBgYHtyfQ0KIyBDYW1iaWFyIGxhIHRyYW5zcGFyaWVuY2lhIHBvciB2YWxvcmVzIGRlIGNvczINCg0KZnZpel9jYV9jb2wocmVzLmNhLCBhbHBoYS5jb2wgPSAiY29zMiIsDQogICAgICAgICAgICAgY29sLmNvbCA9ICJyZWQiLA0KICAgICAgICAgICAgIHRpdGxlPSJUcmFuc3BhcmllbmNpYSBkZSBsYXMgY29sdW1uYXMgcG9yIGNvczIiLA0KICAgICAgICAgICAgIHJlcGVsID0gVFJVRSAjIEV2aXRhIHRyYXNsYXBhbWllbnRvIGRlIHRleHRvcw0KICAgICAgICAgICAgICkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBjb2wkY29zMmA6IGNvcnJlbGFjaW9uZXMNCg0KU2UgcHVlZGUgcmVwcmVzZW50YXIgZ3LDoWZpY2FtZW50ZSBlbCBgY29zMmAgZGUgbG9zIHB1bnRvcyBkZSBjb2x1bW5hIGVuIHRvZGFzIGxhcyBkaW1lbnNpb25lcyB1dGlsaXphbmRvIGVsIHBhcXVldGUgYGNvcnJwbG90YC4NCg0KDQpgYGB7cn0NCmxpYnJhcnkoImNvcnJwbG90IikNCmNvcnJwbG90KGNvbCRjb3MyLCANCiAgICAgICAgIGlzLmNvcnI9RkFMU0UsICMgU2UgcHVlZGUgYWN0aXZhciBvIG5vDQogICAgICAgICB0bC5jb2wgPSAiYmxhY2siLCANCiAgICAgICAgICNhZGRDb2VmLmNvbCA9ICdncmV5NTAnLCAjQWdyZWdhciB2YWxvcmVzDQogICAgICAgICAjbnVtYmVyLmNleCA9IDAuNywgICAgICAgI1RhbWHDsW8gZGUgbG9zIHZhbG9yZXMNCiAgICAgICAgIHRsLnNydCA9IDkwLCANCiAgICAgICAgIGJnID0gImxpZ2h0Ymx1ZSIsICAgICAgICAjQ29sb3IgZGVsIGZvbmRvDQogICAgICAgICB0aXRsZT0iTWF0cml6IGRlIGNvcnJlbGFjaW9uZXMiLCANCiAgICAgICAgICN0bC5jZXg9MS41LCAgICAgICAgICAgICNUYW1hw7FvIGRlIGxhcyBmdWVudGVzDQogICAgICAgICAjY2V4Lm1haW49Mi4wLCAgICAgICAgICAjVGFtYcOxbyBkZWwgdMOtdHVsbw0KICAgICAgICAgI3R5cGU9Imxvd2VyIiwNCiAgICAgICAgIG1hcj1jKDAsMCw0LDApIA0KICAgICAgICAgKQ0KYGBgDQoNClNlIGRlYmUgdGVuZXIgZW4gY3VlbnRhIHF1ZSB0b2RvcyBsb3MgcHVudG9zIGRlIGNvbHVtbmEgZXhjZXB0byBgNC5BZ3JlZWAgeSBgMi5EaXNhZ3JlZWAgZXN0w6FuIGJpZW4gcmVwcmVzZW50YWRvcyBwb3IgbGFzIGRvcyBwcmltZXJhcyBkaW1lbnNpb25lcy4gRXN0byBzdWdpZXJlIHF1ZSBsYSBwb3NpY2nDs24gZGVsIHB1bnRvIGNvcnJlc3BvbmRpZW50ZSBhIGVzb3Mgw610ZW1zIGVuIGVsIGdyw6FmaWNvIGRlIGRpc3BlcnNpw7NuIGRlYmUgaW50ZXJwcmV0YXJzZSBjb24gY2llcnRhIHByZWNhdWNpw7NuLiBFcyBwcm9iYWJsZSBxdWUgdW5hIHNvbHVjacOzbiBkZSBkaW1lbnNpb25lcyBzdXBlcmlvcmVzIHNlYSBuZWNlc2FyaWEgcGFyYSBsb3Mgw610ZW1zIG1lbmNpb25hZG9zLg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBjb2wkY29zMmA6IGRpYWdyYW1hIGRlIGJhcnJhcw0KDQpUYW1iacOpbiBlcyBwb3NpYmxlIGNyZWFyIHVuIGRpYWdyYW1hIGRlIGJhcnJhIHBhcmEgbG8gdmFsb3JlcyBgY29zMmAgdXNhbmRvIGxhIGZ1bmNpw7NuIGBmdml6X2NvczJgIGRlbCBwYXF1ZXRlIA0KYGZhY3RvZXh0cmFgLg0KDQpgYGB7cn0NCiMgQ29zMiBkZSBsYXMgY29sdW1uYXMgc29icmUgbGFzIGRpbWVuc2lvbmVzIDEgeSAyDQoNCmZ2aXpfY29zMihyZXMuY2EsIGNob2ljZSA9ICJjb2wiLCBheGVzID0gMToyKQ0KYGBgDQoNCg0KKipSZWNvcmRhcjogKioNCg0KDQoxLiBFbCB2YWxvciBkZSBgY29zMmAgZXN0w6EgZW50cmUgMCB5IDEuIA0KDQoyLiBVbiBgY29zMmAgY2VyY2FubyBhIDEgY29ycmVzcG9uZGUgYSB2YXJpYWJsZXMgZGUgY29sdW1uYS9maWxhIHF1ZSBlc3TDoW4gYmllbiByZXByZXNlbnRhZGFzIGVuIGVsIG1hcGEgZmFjdG9yaWFsLg0KDQozLiBPYnNlcnZhIHF1ZSBzb2xvIGVsIGVsZW1lbnRvIGRlIGNvbHVtbmEgYDQuQWx3YXlzYCAgbm8gc2UgbXVlc3RyYSBtdXkgYmllbiBlbiBsYXMgZG9zIHByaW1lcmFzIGRpbWVuc2lvbmVzLiBMYSBwb3NpY2nDs24gZGUgZXN0ZSBlbGVtZW50byBkZWJlIGludGVycHJldGFyc2UgY29uIHByZWNhdWNpw7NuIGVuIGVsIGVzcGFjaW8gZm9ybWFkbyBwb3IgbGFzIGRpbWVuc2lvbmVzIDEgeSAyLg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgY29sJGNvbnRyaWJgKQ0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGNvbCRjb250cmliYDogZ2VuZXJhbA0KDQpMYSBjb250cmlidWNpw7NuIGRlIGxhcyBjb2x1bW5hcyAoZW4gJSkgYSBsYSBkZWZpbmljacOzbiBkZSBsYXMgZGltZW5zaW9uZXMgc2UgcHVlZGUgZXh0cmFlciBkZSBsYSBzaWd1aWVudGUgbWFuZXJhOg0KDQoNCmBgYHtyfQ0KaGVhZChjb2wkY29udHJpYikNCmBgYA0KDQpMYXMgdmFyaWFibGVzIGRlIGNvbHVtbmEgY29uIHVuIHZhbG9yIG3DoXMgYWx0byBzb24gbGFzIHF1ZSBtw6FzIGNvbnRyaWJ1eWVuIGEgbGEgZGVmaW5pY2nDs24gZGUgbGFzIGRpbWVuc2lvbmVzLg0KDQogICsgTGFzIGNvbHVtbmFzIHF1ZSBtw6FzIGNvbnRyaWJ1eWVuIGEgYERpbS4xYCB5IGBEaW0uMmAgc29uIGxhcyBtw6FzIGltcG9ydGFudGVzIHBhcmEgZXhwbGljYXIgbGEgdmFyaWFiaWxpZGFkIGVuIGVsIGNvbmp1bnRvIGRlIGRhdG9zLg0KICAgIA0KICArIExhcyBjb2x1bW5hcyBxdWUgbm8gY29udHJpYnV5ZW4gbXVjaG8gYSBuaW5ndW5hIGRpbWVuc2nDs24gbyBxdWUgY29udHJpYnV5ZW4gYSBsYXMgw7psdGltYXMgZGltZW5zaW9uZXMgc29uIG1lbm9zIGltcG9ydGFudGVzLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGNvbCRjb250cmliYDogY29ycmVsYWNpb25lcw0KDQpFcyBwb3NpYmxlIHV0aWxpemFyIGxhIGZ1bmNpw7NuIGBjb3JycGxvdGAgZGVsIHBhcXVldGUgYGNvcnJwbG90YCBwYXJhIHJlc2FsdGFyIGxvcyBwdW50b3MgZGUgY29sdW1uYSBxdWUgbcOhcyBjb250cmlidXllbiBwYXJhIGNhZGEgZGltZW5zacOzbjoNCg0KDQpgYGB7cn0NCmxpYnJhcnkoImNvcnJwbG90IikNCmNvcnJwbG90KGNvbCRjb250cmliLCANCiAgICAgICAgIGlzLmNvcnI9RkFMU0UsICAgICAgICAgICAgI05vIHNlIHB1ZWRlIGRlc2FjdGl2YXIgZXN0ZSBhcmd1bWVudG8NCiAgICAgICAgIHRsLmNvbCA9ICJibGFjayIsIA0KICAgICAgICAgI2FkZENvZWYuY29sID0gJ2dyZXk1MCcsICNBZ3JlZ2FyIHZhbG9yZXMNCiAgICAgICAgICNudW1iZXIuY2V4ID0gMC43LCAgICAgICAjVGFtYcOxbyBkZSBsb3MgdmFsb3Jlcw0KICAgICAgICAgdGwuc3J0ID0gOTAsIA0KICAgICAgICAgYmcgPSAibGlnaHRibHVlIiwgICAgICAgICNDb2xvciBkZWwgZm9uZG8NCiAgICAgICAgIHRpdGxlPSJNYXRyaXogZGUgY29ycmVsYWNpb25lcyIsIA0KICAgICAgICAgI3RsLmNleD0xLjUsICAgICAgICAgICAgI1RhbWHDsW8gZGUgbGFzIGZ1ZW50ZXMNCiAgICAgICAgICNjZXgubWFpbj0yLjAsICAgICAgICAgICNUYW1hw7FvIGRlbCB0w610dWxvDQogICAgICAgICAjdHlwZT0ibG93ZXIiLA0KICAgICAgICAgbWFyPWMoMCwwLDQsMCkgICAgICAgICAgI1ViaWNhY2nDs24gZGVsIHTDrXR1bG8NCiAgICAgICAgICkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBjb2wkY29udHJpYmA6IGRpYWdyYW1hcyBkZSBiYXJyYSBkZSBjYWRhIHZhcmlhYmxlDQoNCg0KTGEgZnVuY2nDs24gYGZ2aXpfY29udHJpYmAgZGVsIHBhcXVldGUgYGZhY3RvZXh0cmFgIHNlIHB1ZWRlIGVtcGxlYXIgcGFyYSBkaWJ1amFyIHVuIGdyw6FmaWNvIGRlIGJhcnJhcyBkZSBsYXMgY29udHJpYnVjaW9uZXMgZGUgbGFzIGNvbHVtbmFzLiBTaSBsb3MgZGF0b3MgY29udGllbmVuIG11Y2hhcyBjb2x1bW5hcywgc2UgcHVlZGUgb3B0YXIgcG9yIG1vc3RyYXIgc29sbyBsYXMgY29sdW1uYXMgcXVlIG3DoXMgY29udHJpYnV5ZW4uIEVsIHNpZ3VpZW50ZSBjw7NkaWdvIGVuIFIgbXVlc3RyYSBsYXMgMTAgY29sdW1uYXMgcHJpbmNpcGFsZXMgcXVlIGNvbnRyaWJ1eWVuIGEgbGFzIGRpbWVuc2lvbmVzLg0KDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBDb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGEgbGEgZGltZW5zacOzbiAxDQpwMSA8LSBmdml6X2NvbnRyaWIocmVzLmNhLCBjaG9pY2UgPSAiY29sIiwgYXhlcyA9IDEsIHRvcCA9IDEwKQ0KDQojIENvbnRyaWJ1Y2lvbmVzIGRlIGxhcyB2YXJpYWJsZXMgYSBsYSBkaW1lbnNpw7NuIDINCnAyIDwtIGZ2aXpfY29udHJpYihyZXMuY2EsIGNob2ljZSA9ICJjb2wiLCBheGVzID0gMiwgdG9wID0gMTApDQoNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCiMgQ29udHJpYnVjaW9uZXMgZGUgbGFzIHZhcmlhYmxlcyBhIGxhIGRpbWVuc2nDs24gMQ0KcDEgPC0gZnZpel9jb250cmliKHJlcy5jYSwgY2hvaWNlID0gImNvbCIsIGF4ZXMgPSAxLCB0b3AgPSAxMCkNCg0KIyBDb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGEgbGEgZGltZW5zacOzbiAyDQpwMiA8LSBmdml6X2NvbnRyaWIocmVzLmNhLCBjaG9pY2UgPSAiY29sIiwgYXhlcyA9IDIsIHRvcCA9IDEwKQ0KDQpsaWJyYXJ5KGdyaWRFeHRyYSkgDQoNCmdyaWQuYXJyYW5nZShwMSxwMiwgbmNvbD0yLCBucm93ID0xKQ0KYGBgDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgY29sJGNvbnRyaWJgOiBkaWFncmFtYSBkZSBiYXJyYSBwYXJhIGxhIHRvdGFsDQoNCg0KQSBjb250aW51YWNpw7NuLCBzZSBwdWVkZSB2aXN1YWxpemFyIGxhIGNvbnRyaWJ1Y2nDs24gdG90YWwgYSBsYXMgZGltZW5zaW9uZXMgMSB5IDI6IA0KDQpgYGB7cn0NCmZ2aXpfY29udHJpYihyZXMuY2EsIGNob2ljZSA9ICJjb2wiLCBheGVzID0gMToyLCB0b3AgPSAxMCkNCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGNvbCRjb250cmliYDogaW50ZXJwcmV0YWNpb25lcw0KDQoqKkludGVycHJldGFjacOzbiBOby4gMTogKioNCg0KTGEgbMOtbmVhIHJvamEgZGlzY29udGludWEgZW4gZWwgZ3LDoWZpY28gYW50ZXJpb3IgaW5kaWNhIGxhIGNvbnRyaWJ1Y2nDs24gcHJvbWVkaW8gZXNwZXJhZGEuIA0KDQoqKkludGVycHJldGFjacOzbiBOby4gMjogKioNCiAgDQpTaSBsYSBjb250cmlidWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgZnVlc2UgdW5pZm9ybWUsIGVsIHZhbG9yIGVzcGVyYWRvIHNlcsOtYSANCiAgDQogICQkXGZyYWN7MX17XG1ib3h7bG9uZ2l0dWQoY29sdW1uYXMpfX0gXDs9XDsgXGZyYWN7MX17NX0oMTAwKVw7PVw7IDIwXCwgXCUkJA0KICANCmBgYHtyfQ0KICAoMS9ucm93KHRhYmxhKSkqMTAwDQpgYGANCg0KDQoqKkludGVycHJldGFjacOzbiBOby4gMzogKioNCg0KUGFyYSB1bmEgZGltZW5zacOzbiBkYWRhLCB1bmEgY29sdW1uYSBjb24gdW5hIGNvbnRyaWJ1Y2nDs24gbWF5b3IgcXVlIGVzdGUgdW1icmFsIHBvZHLDrWEgY29uc2lkZXJhcnNlIGltcG9ydGFudGUgZW4gbGEgY29udHJpYnVjacOzbiBhIGxhIGRpbWVuc2nDs24uIA0KICANCiAgDQoqKkludGVycHJldGFjacOzbiBOby4gNDogKioNCg0KU2UgcHVlZGUgb2JzZXJ2YXIgcXVlIGxhIHZhcmlhYmxlIGA1LlN0ci5BZ3JlZWAgY29udHJpYnV5ZSBtw6FzIGEgbGFzIGRpbWVuc2lvbmVzIDEgeSAyLg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgY29sJGNvbnRyaWJgOiBhcmd1bWVudG8gYGdyYWRpZW50LmNvbHNgDQoNCkNvbW8geWEgc2UgZXhwbGljw7MsIGBncmFkaWVudC5jb2xzID0gYygiZ3JlZW4iLCAiYnJvd24iLCAiYmx1ZSIpYCBzaWduaWZpY2EgcXVlOg0KDQoxLiBMYXMgdmFyaWFibGVzIGNvbiB2YWxvcmVzIGJham9zIGRlIGBjb3MyYCBzZXLDoW4gY29sb3JlYWRhcyBlbiAqdmVyZGUqLg0KDQoyLiBMYXMgdmFyaWFibGVzIGNvbiB2YWxvcmVzIG1lZGlvcyBkZSBgY29zMmAgc2Vyw6FuIGNvbG9yZWFkYXMgZW4gKm1hcnLDs24qLg0KDQozLiBMYXMgdmFyaWFibGVzIGNvbiB2YWxvcmVzIGFsdG9zIGRlIGBjb3MyYCBzZXLDoW4gY29sb3JlYWRhcyBlbiAqYXp1bCouDQoNCg0KYGBge3J9DQpNaXNDb2xvcmVzIDwtIGMoImdyZWVuIiwgImJyb3duIiwgImJsdWUiKQ0KICANCmZ2aXpfY2FfY29sKHJlcy5jYSwgY29sLmNvbCA9ICJjb250cmliIiwgDQogICAgICAgICAgICAgcmVwZWw9IFRSVUUsICMgRXZpdGEgdHJhc2xhcGFtaWVudG8gZGUgdGV4dG9zLA0KICAgICAgICAgICAgIGdyYWRpZW50LmNvbHMgPSBNaXNDb2xvcmVzLA0KICAgICAgICAgICAgICkNCg0KYGBgDQoNCioqSW50ZXJwcmV0YWNpb25lczoqKg0KDQoxLiBFbCBncsOhZmljbyBkZSBkaXNwZXJzacOzbiBvZnJlY2UgdW5hIGlkZWEgZGUgcXXDqSBwb2xvIGRlIGxhcyBkaW1lbnNpb25lcyBlc3TDoW4gY29udHJpYnV5ZW5kbyByZWFsbWVudGUgbGFzIGNhdGVnb3LDrWFzIGRlIGxhcyBjb2x1bW5hcy4NCg0KMi4gRXMgZXZpZGVudGUgcXVlIGxhcyBjYXRlZ29yw61hcyBkZSBjb2x1bW5hcyBgMS5TZHIuRGlzYWdyZWVgLCAgeSBgMy5VbmRlY2lkZWRgIHRpZW5lbiB1bmEgY29udHJpYnVjacOzbiBpbXBvcnRhbnRlIGFsIHBvbG8gbmVnYXRpdm8gZGUgbGEgcHJpbWVyYSBkaW1lbnNpw7NuLiANCg0KMy4gTWllbnRyYXMgcXVlIGxhIGNhdGVnb3LDrWEgIGA1LlN0ci5BZ2VlYCB0aWVuZW4gdW5hIGNvbnRyaWJ1Y2nDs24gbWF5b3IgYWwgcG9sbyBwb3NpdGl2byBkZSBsYSBwcmltZXJhIGRpbWVuc2nDs247IGV0Yy4sIC4uLg0KDQo0LiBFbiBvdHJhcyBwYWxhYnJhcywgbGEgZGltZW5zacOzbiAxIGVzdMOhIHByaW5jaXBhbG1lbnRlIGRlZmluaWRhIHBvciBsYSBvcG9zaWNpw7NuIGRlIGAxLlNkci5EaXNhZ3JlZWAsICB5IGAzLlVuZGVjaWRlZGAgKHBvbG8gbmVnYXRpdm8pLCB5IGA1LlN0ci5BZ2VlYCAocG9sbyBwb3NpdGl2bykuDQoNCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGNvbCRjb250cmliYDogdHJhbnNwYXJpZW5jaWFzIGNvbiBgYWxwaGEudmFyYA0KDQpUZW5nYSBlbiBjdWVudGEgcXVlIHRhbWJpw6luIGVzIHBvc2libGUgY2FtYmlhciBsYSB0cmFuc3BhcmVuY2lhIGRlIGxhcyBjb2x1bW5hcyBzZWfDum4gc3VzIHZhbG9yZXMgZGUgY29udHJpYnVjacOzbiB1dGlsaXphbmRvIGxhIG9wY2nDs24gYGFscGhhLmNvbCA9ICJjb250cmliImA6DQoNCmBgYHtyfQ0KIyBDYW1iaWFyIGxhIHRyYW5zcGFyaWVuY2lhIHBhcmEgbGFzIGNvbnRyaWJ1Y2lvbmVzDQpmdml6X2NhX2NvbChyZXMuY2EsIGFscGhhLmNvbCA9ICJjb250cmliIiwNCiAgICAgICAgICAgICBjb2wuY29sID0gInJlZCIsDQogICAgICAgICAgICAgI3RpdGxlPSJUcmFuc3BhcmllbmNpYSBkZSBsYXMgdmFyaWFibGVzIHBvciBjb250cmlidWNpw7NuIiwgDQogICAgICAgICAgICAgcmVwZWw9IFRSVUUgIyBFdml0YSB0cmFzbGFwYW1pZW50byBkZSB0ZXh0b3MsDQogICAgICAgICAgICAgKQ0KYGBgDQoNCg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgYmlwbG90YCkgIA0KICANCg0KRWwgYmlwbG90IGVzIHVuYSByZXByZXNlbnRhY2nDs24gZ3LDoWZpY2EgZGUgZmlsYXMgeSBjb2x1bW5hcyBlbiAyIG8gMyBkaW1lbnNpb25lcy4gWWEgaGVtb3MgZGVzY3JpdG8gY8OzbW8gY3JlYXIgYmlwbG90cyBkZSBBQyBlbiBzZWNjaW9uZXMgYW50ZXJpb3JlLiBBcXXDrSwgZGVzY3JpYmlyZW1vcyBkaWZlcmVudGVzIHRpcG9zIGRlIGJpcGxvdHMgZGUgQUMuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGJpcGxvdGA6IHNpbcOpdHJpY28NCg0KQ29tbyBzZSBtZW5jaW9uw7MgYW50ZXJpb3JtZW50ZTogDQoNCjEuIEVsIGdyw6FmaWNvIGVzdMOhbmRhciBkZWwgYW7DoWxpc2lzIGRlIGNvcnJlc3BvbmRlbmNpYSBlcyB1biBiaXBsb3Qgc2ltw6l0cmljbyBlbiBlbCBxdWUgdGFudG8gbGFzIGZpbGFzIChwdW50b3MgYXp1bGVzKSBjb21vIGxhcyBjb2x1bW5hcyAodHJpw6FuZ3Vsb3Mgcm9qb3MpIGVzdMOhbiByZXByZXNlbnRhZG9zIGVuIGVsIG1pc21vIGVzcGFjaW8gdXRpbGl6YW5kbyBsYXMgY29vcmRlbmFkYXMgcHJpbmNpcGFsZXMuIA0KDQoyLiBFc3RhcyBjb29yZGVuYWRhcyByZXByZXNlbnRhbiBsb3MgcGVyZmlsZXMgZGUgZmlsYXMgeSBjb2x1bW5hcy4gDQoNCjMuIEVuIGVzdGUgY2Fzbywgc29sbyBsYSBkaXN0YW5jaWEgZW50cmUgcHVudG9zIGRlIGZpbGEgbyBsYSBkaXN0YW5jaWEgZW50cmUgcHVudG9zIGRlIGNvbHVtbmEgcHVlZGUgaW50ZXJwcmV0YXJzZSByZWFsbWVudGUuDQoNCjQuIENvbiB1biBncsOhZmljbyBzaW3DqXRyaWNvLCBsYSBpbnRlcmRpc3RhbmNpYSBlbnRyZSBmaWxhcyB5IGNvbHVtbmFzIG5vIHB1ZWRlIGludGVycHJldGFyc2UuIFNvbG8gc2UgcHVlZGVuIGhhY2VyIGFmaXJtYWNpb25lcyBnZW5lcmFsZXMgc29icmUgZWwgcGF0csOzbi4NCg0KNS4gUmVjdWVyZGUgZWwgY8OzZGlnbyBSIHBhcmEgaGFjZXIgdW4gYmlwbG90IHNpbXBsZSBkZSBpbmRpdmlkdW9zIHkgdmFyaWFibGVzOg0KDQpgYGB7cn0NCmZ2aXpfY2FfYmlwbG90KHJlcy5jYSwgDQogICAgICAgICAgICAgICAgcmVwZWwgPSBUUlVFLA0KICAgICAgICAgICAgICAgICkNCmBgYA0KDQo2LiBPYnNlcnZlIHF1ZSwgcGFyYSBpbnRlcnByZXRhciBsYSBkaXN0YW5jaWEgZW50cmUgbG9zIHB1bnRvcyBkZSBjb2x1bW5hIHkgbG9zIHB1bnRvcyBkZSBmaWxhLCBsYSBmb3JtYSBtw6FzIHNlbmNpbGxhIGVzIGhhY2VyIHVuIGdyw6FmaWNvIGFzaW3DqXRyaWNvLiBFc3RvIGltcGxpY2EgcXVlIGxvcyBwZXJmaWxlcyBkZSBjb2x1bW5hIGRlYmVuIHByZXNlbnRhcnNlIGVuIGVsIGVzcGFjaW8gZGUgZmlsYSBvIHZpY2V2ZXJzYS4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBiaXBsb3RgOiBhc2ltw6l0cmljbywgZGVzY3JpcGNpw7NuDQoNClBhcmEgY3JlYXIgdW4gKmJpcGxvdCBhc2ltw6l0cmljbyosIHNlIGdyYWZpY2FuIGxvcyBwdW50b3MgZGUgbGFzIGZpbGFzIChvIGNvbHVtbmFzKSBhIHBhcnRpciBkZSBsYXMgY29vcmRlbmFkYXMgZXN0w6FuZGFyIHMgeSBsb3MgcGVyZmlsZXMgZGUgbGFzIGNvbHVtbmFzIChvIGxhcyBmaWxhcykgc2UgZ3JhZmljYW4gYSBwYXJ0aXIgZGUgbGFzIGNvb3JkZW5hZGFzIHByaW5jaXBhbGVzIChQKS4NCg0KUGFyYSB1biBlamUgZGFkbywgbGFzIGNvb3JkZW5hZGFzIGVzdMOhbmRhciB5IHByaW5jaXBhbGVzIGVzdMOhbiByZWxhY2lvbmFkYXMgZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KJCRQIFw7ID0gXDsgcyBcLCBcc3FydHtcbGFtYmRhfSQkDQpkb25kZSANCiAgDQogICsgJFAkIGVzIGxhIGNvb3JkZW5hZGEgcHJpbmNpcGFsIGRlIHVuYSBmaWxhIChvIGNvbHVtbmEpIGVuIGVsIGVqZS4NCiAgDQogICsgJFxsYW1iZGEkIGVzIGVsIHZhbG9yIHByb3BpbyBkZWwgZWplLg0KICANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgYmlwbG90YDogYXNpbcOpdHJpY28gKGBmdml6X2NhX2JpcGxvdGAgY29uIGBtYXBgKQ0KDQpEZXBlbmRpZW5kbyBkZSBsYSBzaXR1YWNpw7NuLCBzZSBwdWVkZW4gZXN0YWJsZWNlciBvdHJvcyB0aXBvcyBkZSB2aXN1YWxpemFjacOzbiB1dGlsaXphbmRvIGVsIGFyZ3VtZW50byBgbWFwYCAgZW4gbGEgZnVuY2nDs24gYGZ2aXpfY2FfYmlwbG90YCBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAuIExhcyBvcGNpb25lcyBwZXJtaXRpZGFzIHBhcmEgZWwgYXJndW1lbnRvIGBtYXBgIHNvbjoNCg0KMS4gYHJvd3ByaW5jaXBhbGAuICBFc3RvcyBzb24gbG9zIGxsYW1hZG9zICpiaXBsb3RzIGFzaW3DqXRyaWNvcyosIGNvbiBmaWxhcyBlbiBsYXMgY29vcmRlbmFkYXMgcHJpbmNpcGFsZXMgKHRhbWJpw6luIGNvbm9jaWRvcyBjb21vIHByZXNlcnZhY2nDs24gbcOpdHJpY2EgZGUgZmlsYSkuIEVuIGVzdGUgY2FzbywgbGFzIGNvbHVtbmFzIGVzdMOhbiByZXByZXNlbnRhZGFzIGVuIGVsIGVzcGFjaW8gZGUgZmlsYQ0KDQoyLiBgY29scHJpbmNpcGFsYC4gVGFtYmnDqW4gbGxhbWFkb3MgKmJpcGxvdHMgYXNpbcOpdHJpY29zKi4gRW4gZXN0ZSBjYXNvLCBjb24gY29sdW1uYXMgZW4gY29vcmRlbmFkYXMgZXN0w6FuZGFyICh0YW1iacOpbiBjb25vY2lkb3MgY29tbyBwcmVzZXJ2YWNpw7NuIG3DqXRyaWNhIGRlIGNvbHVtbmEsIHJlc3BlY3RpdmFtZW50ZSkuIFBhcmEgZXN0YSBzaXR1YWNpw7NuLCBsYXMgZmlsYXMgZXN0w6FuIHJlcHJlc2VudGFkYXMgZW4gZWwgZXNwYWNpbyBkZSBjb2x1bW5hLg0KDQozLiBgc3ltYmlwbG90YC4gVGFudG8gbGFzIGZpbGFzIGNvbW8gbGFzIGNvbHVtbmFzIHNlIGVzY2FsYW4gcGFyYSB0ZW5lciB2YXJpYW56YXMgaWd1YWxlcyBhIGxvcyB2YWxvcmVzIHNpbmd1bGFyZXMgKHJhw61jZXMgY3VhZHJhZGFzIGRlIGxvcyB2YWxvcmVzIHByb3Bpb3MpLCBsbyBxdWUgZGEgdW4gYmlwbG90IHNpbcOpdHJpY28gcGVybyBubyBwcmVzZXJ2YSBtw6l0cmljYXMgZGUgZmlsYSBvIGNvbHVtbmEuDQoNCjQuIGByb3dnYWJgLiAgU29uIG1hcGFzIGFzaW3DqXRyaWNvcywgY29uIGZpbGFzIGVuIGNvb3JkZW5hZGFzIHByaW5jaXBhbGVzIHkgY29sdW1uYXMgZW4gY29vcmRlbmFkYXMgZXN0w6FuZGFyIG11bHRpcGxpY2FkYXMgcG9yIGxhIG1hc2EuDQoNCjUuIGBjb2xnYWJgLiBTb24gbWFwYXMgYXNpbcOpdHJpY29zLCBjb24gY29sdW1uYXMgZW4gY29vcmRlbmFkYXMgcHJpbmNpcGFsZXMgeSBmaWxhcyBlbiBjb29yZGVuYWRhcyBlc3TDoW5kYXIgbXVsdGlwbGljYWRhcyBwb3IgbGEgbWFzYS4NCg0KNi4gYGNvbGdyZWVuYDogU29uIGxvcyBsbGFtYWRvcyBiaXBsb3RzIGRlIGNvbnRyaWJ1Y2nDs24gcXVlIG11ZXN0cmFuIHZpc3VhbG1lbnRlIGxvcyBwdW50b3MgbcOhcyBjb250cmlidXllbnRlcywgY29uIGNvbHVtbmFzIGVuIGNvb3JkZW5hZGFzIHByaW5jaXBhbGVzIHkgZmlsYXMgZW4gY29vcmRlbmFkYXMgZXN0w6FuZGFyIG11bHRpcGxpY2FkYXMgcG9yIGxhIHJhw616IGN1YWRyYWRhIGRlIGxhIG1hc2EuDQoNCjcuIGByb3dncmVlbmAuIFNvbiBsb3MgbGxhbWFkb3MgYmlwbG90cyBkZSBjb250cmlidWNpw7NuIHF1ZSBtdWVzdHJhbiB2aXN1YWxtZW50ZSBsb3MgcHVudG9zIG3DoXMgY29udHJpYnV5ZW50ZXMsIGNvbiBmaWxhcyBlbiBjb29yZGVuYWRhcyBwcmluY2lwYWxlcyB5IGNvbHVtbmFzIGVuIGNvb3JkZW5hZGFzIGVzdMOhbmRhciBtdWx0aXBsaWNhZGFzIHBvciBsYSByYcOteiBjdWFkcmFkYSBkZSBsYSBtYXNhLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGJpcGxvdGA6IGFzaW3DqXRyaWNvIChlbiBSKQ0KDQpFbCBjw7NkaWdvIFIgYSBjb250aW51YWNpw7NuIGRpYnVqYSB1biBiaXBsb3QgYXNpbcOpdHJpY28gZXN0w6FuZGFyOg0KDQpgYGB7cn0NCmZ2aXpfY2FfYmlwbG90KHJlcy5jYSwNCiAgICAgICAgICAgICAgICBtYXAgPSJyb3dwcmluY2lwYWwiLCANCiAgICAgICAgICAgICAgICBhcnJvdyA9IGMoVFJVRSwgVFJVRSksDQogICAgICAgICAgICAgICAgcmVwZWwgPSBUUlVFKQ0KYGBgDQoqKk9ic2VydmFjaW9uZXM6KioNCg0KMS4gT2JzZXJ2ZSBxdWUgc2UgdXRpbGl6YSBlbCBhcmd1bWVudG8gYGFycm93YC4NCg0KMi4gYGFycm93YCBlcyB1biB2ZWN0b3IgZGUgZG9zIHZhbG9yZXMgbMOzZ2ljb3MgcXVlIGVzcGVjaWZpY2FuIHNpIGVsIGdyw6FmaWNvIGRlYmUgY29udGVuZXIgcHVudG9zIChGQUxTRSwgcG9yIGRlZmVjdG8pIG8gZmxlY2hhcyAoVFJVRSkuIA0KDQozLiBFbCBwcmltZXIgdmFsb3IgZXN0YWJsZWNlIGxhcyBmaWxhcyB5IGVsIHNlZ3VuZG8gdmFsb3IgZXN0YWJsZWNlIGxhcyBjb2x1bW5hcy4NCg0KNC4gU2kgZWwgw6FuZ3VsbyBlbnRyZSBkb3MgZmxlY2hhcyBlcyBhZ3VkbywgZW50b25jZXMgaGF5IHVuYSBmdWVydGUgYXNvY2lhY2nDs24gZW50cmUgbGEgZmlsYSB5IGxhIGNvbHVtbmEgY29ycmVzcG9uZGllbnRlcy4gDQoNCjUuIFBhcmEgaW50ZXJwcmV0YXIgbGEgZGlzdGFuY2lhIGVudHJlIGZpbGFzIHkgdW5hIGNvbHVtbmEsIHNlIGRlYmVyw61hIHByb3llY3RhciBwZXJwZW5kaWN1bGFybWVudGUgbG9zIHB1bnRvcyBkZSBsYSBmaWxhIHNvYnJlIGxhIGZsZWNoYSBkZSBsYSBjb2x1bW5hLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGJpcGxvdGA6ICBjb250cmlidXRpb24gKGdlbmVyYWwpDQoNCjEuIEVuIGVsIGJpcGxvdCBzaW3DqXRyaWNvIGVzdMOhbmRhciAobWVuY2lvbmFkbyBlbiBsYSBzZWNjacOzbiBhbnRlcmlvciksIHJlc3VsdGEgZGlmw61jaWwgaWRlbnRpZmljYXIgbG9zIHB1bnRvcyBxdWUgbcOhcyBjb250cmlidXllbiBhIGxhIHNvbHVjacOzbiBkZWwgQ0EuDQoNCjIuIFBhcmEgc29sdWNpb25hciBlc3RlIGRldGFsbGUsIGhheSB1bmEgbnVldmEgdmlzdWFsaXphY2nDs24gZXNjYWxhZGEgKGxsYW1hZGEgYGJpcGxvdCBkZSBjb250cmlidWNpw7NuYCkuDQoNCjMuIEVzdGUgZ3LDoWZpY28gaW5jb3Jwb3JhIGxhIGNvbnRyaWJ1Y2nDs24gZGUgbG9zIHB1bnRvcy4NCg0KNC4gRW4gZXN0YSByZXByZXNlbnRhY2nDs24sIGxvcyBwdW50b3MgcXVlIGNvbnRyaWJ1eWVuIG11eSBwb2NvIGEgbGEgc29sdWNpw7NuIGVzdMOhbiBjZXJjYSBkZWwgY2VudHJvIGRlbCBiaXBsb3QgeSBzb24gcmVsYXRpdmFtZW50ZSBwb2NvIGltcG9ydGFudGVzIHBhcmEgbGEgaW50ZXJwcmV0YWNpw7NuLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGJpcGxvdGA6ICBjb250cmlidXRpb24gKGVuIFIpDQoNCjEuIFVuIGJpcGxvdCBkZSBjb250cmlidWNpw7NuIHB1ZWRlIGRpYnVqYXJzZSB1dGlsaXphbmRvIGVsIGFyZ3VtZW50byBgbWFwID0gInJvd2dyZWVuImAgbyBgbWFwID0gImNvbGdyZWVuImAuDQoNCjIuIEVuIHByaW1lciBsdWdhciwgaGF5IHF1ZSBkZWNpZGlyIHNpIHNlIGFuYWxpemFuIGxhcyBjb250cmlidWNpb25lcyBkZSBsYXMgZmlsYXMgbyBsYXMgY29sdW1uYXMgYSBsYSBkZWZpbmljacOzbiBkZSBsb3MgZWplcy4NCg0KMy4gRW4gbnVlc3RybyBlamVtcGxvLCBpbnRlcnByZXRhcmVtb3MgbGEgY29udHJpYnVjacOzbiBkZSBsYXMgZmlsYXMgYSBsb3MgZWplcy4gU2UgdXRpbGl6YSBlbCBhcmd1bWVudG8gYG1hcCA9ICJyb3dncmVlbiJgLiANCg0KNC4gRW4gZXN0ZSBjYXNvLCBoYXkgcXVlIHJlY29yZGFyIHF1ZSBsYXMgY29sdW1uYXMgZXN0w6FuIGVuIGNvb3JkZW5hZGFzIHByaW5jaXBhbGVzIHkgbGFzIGZpbGFzIGVuIGNvb3JkZW5hZGFzIGVzdMOhbmRhciBtdWx0aXBsaWNhZGFzIHBvciBsYSByYcOteiBjdWFkcmFkYSBkZSBsYSBtYXNhLiANCg0KNS4gUGFyYSB1bmEgZmlsYSBkYWRhLCBlbCBjdWFkcmFkbyBkZSBsYSBudWV2YSBjb29yZGVuYWRhIGVuIHVuIGVqZSAkaiQgZXMgZXhhY3RhbWVudGUgbGEgY29udHJpYnVjacOzbiBkZSBlc3RhIGZpbGEgYSBsYSBpbmVyY2lhIGRlbCBlamUgJGokLg0KDQpgYGB7cn0NCmZ2aXpfY2FfYmlwbG90KHJlcy5jYSwgDQogICAgICAgICAgICAgICBtYXAgPSJjb2xncmVlbiIsIA0KICAgICAgICAgICAgICAgYXJyb3cgPSBjKFRSVUUsIEZBTFNFKSwNCiAgICAgICAgICAgICAgICByZXBlbCA9IFRSVUUpDQpgYGANCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGJpcGxvdGA6ICBjb250cmlidXRpb24gKGludGVycHJldGFjacOzbikNCg0KMS4gRW4gZWwgZ3LDoWZpY28gYW50ZXJpb3IsIGxhIHBvc2ljacOzbiBkZSBsb3MgcHVudG9zIGRlIHBlcmZpbCBkZSBjb2x1bW5hIG5vIGNhbWJpYSBjb24gcmVzcGVjdG8gYSBsYSBkZWwgYmlwbG90IGNvbnZlbmNpb25hbC4gU2luIGVtYmFyZ28sIGxhcyBkaXN0YW5jaWFzIGRlIGxvcyBwdW50b3MgZGUgZmlsYSBkZXNkZSBlbCBvcmlnZW4gZGVsIGdyw6FmaWNvIGVzdMOhbiByZWxhY2lvbmFkYXMgY29uIHN1cyBjb250cmlidWNpb25lcyBhbCBtYXBhIGZhY3RvcmlhbCBiaWRpbWVuc2lvbmFsLg0KDQoyLiBNaWVudHJhcyBtw6FzIGNlcmNhIGVzdMOpIHVuYSBmbGVjaGEgKGVuIHTDqXJtaW5vcyBkZSBkaXN0YW5jaWEgYW5ndWxhcikgZGUgdW4gZWplLCBtYXlvciBlcyBsYSBjb250cmlidWNpw7NuIGRlIGxhIGNhdGVnb3LDrWEgZGUgZmlsYSBlbiBlc2UgZWplIGVuIHJlbGFjacOzbiBjb24gZWwgb3RybyBlamUuIA0KDQozLiBTaSBsYSBmbGVjaGEgZXN0w6EgYSBtZWRpbyBjYW1pbm8gZW50cmUgbG9zIGRvcywgc3UgY2F0ZWdvcsOtYSBkZSBmaWxhIGNvbnRyaWJ1eWUgYSBsb3MgZG9zIGVqZXMgZW4gbGEgbWlzbWEgbWVkaWRhLg0KDQo0LiBFcyBldmlkZW50ZSBxdWUgbGEgY2F0ZWdvcsOtYSBkZSBmaWxhIGBTdHIuQWdyZWVgIHRpZW5lIHVuYSBjb250cmlidWNpw7NuIGltcG9ydGFudGUgYWwgcG9sbyBwb3NpdGl2byBkZSBsYSBwcmltZXJhIGRpbWVuc2nDs24uDQoNCjUuIE1pZW50cmFzIHF1ZSBsYXMgY2F0ZWdvcsOtYXMgIGAxLlN0ci5EaXNhZ3JlZWAgeSBgMy5VbmRlY2lkZWRgIHRpZW5lbiB1bmEgY29udHJpYnVjacOzbiBpbXBvcnRhbnRlIGFsIHBvbG8gbmVnYXRpdm8gZGUgbGEgcHJpbWVyYSBkaW1lbnNpw7NuLg0KDQo2LiBMYSBEaW1lbnNpw7NuIDIgZXN0w6EgcHJpbmNpcGFsbWVudGUgZGVmaW5pZGEgcG9yIGxhcyBjYXRlZ29yw61hcyBkZSBmaWxhIGAxLlN0ci5EaXNhZ3JlZWAgeSBgMy5VbmRlY2lkZWRgLg0KDQo3LiBMYSBjYXRlZ29yw61hIGRlIGZpbGEgYDQuQWdyZWVgIGNvbnRyaWJ1eWUgYSBsb3MgZG9zIGVqZXMgZW4gbGEgbWlzbWEgbWVkaWRhLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEVqZW1wbG86IFNvbHVjacOzbiAoZGVzY3JpcGNpw7NuIGRlIGxhIGRpbWVuc2nDs24pICANCg0KDQojIyMgYGRpbWRlc2NgOiBkZXNjcmlwY2nDs24gZGUgbGEgZGltZW5zacOzbg0KDQpQYXJhIGlkZW50aWZpY2FyIGNvbiBmYWNpbGlkYWQgbG9zIHB1bnRvcyBkZSBmaWxhIHkgY29sdW1uYSBtw6FzIHJlbGFjaW9uYWRvcyBjb24gbGFzIGRpbWVuc2lvbmVzIHByaW5jaXBhbGVzLCBzZSBwdWVkZSBlbXBsZWFyIGxhIGZ1bmNpw7NuIGBkaW1kZXNjYCBlbiBgRmFjdG9NaW5lUmAuIExhcyB2YXJpYWJsZXMgZGUgZmlsYSB5IGNvbHVtbmEgc2Ugb3JnYW5pemFuIHNlZ8O6biBzdXMgY29vcmRlbmFkYXMgZW4gbGEgc2FsaWRhIGRlIGBkaW1kZXNjYC4NCg0KDQpgYGB7cn0NCiMgRGVzY3JpcGNpw7NuIGRlIGxhIGRpbWVuc2nDs24gDQpyZXMuZGVzYyA8LSBkaW1kZXNjKHJlcy5jYSwgYXhlcyA9IGMoMSwyKSkNCnJlcy5kZXNjDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCg0KIyMjIGBkaW1kZXNjYDogZGltZW5zacOzbiAxIHBvciBmaWxhcw0KDQoNCmBgYHtyfQ0KcmVzLmRlc2NbWzFdXSRyb3cNCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoNCiMjIyBgZGltZGVzY2A6IGRpbWVuc2nDs24gMSBwb3IgY29sdW1uYXMNCg0KYGBge3J9DQpyZXMuZGVzY1tbMV1dJGNvbA0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoNCiMjIyBgZGltZGVzY2A6IGRpbWVuc2nDs24gMiBwb3IgZmlsYXMNCg0KYGBge3J9DQpyZXMuZGVzY1tbMl1dJHJvdw0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoNCiMjIyBgZGltZGVzY2A6IGRpbWVuc2nDs24gMiBwb3IgY29sdW1uYXMNCg0KDQpgYGB7cn0NCnJlcy5kZXNjW1syXV0kY29sDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgVMOzcGljb3Mgc3VtcGxlbWVudGFyaW9zIA0KDQoNCg0KW05vIGhhY2VyIGNsaWNrIGFxdcOtXShPSk9KT0pPKTogUGVuZGllbnRlDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gQ2Fww610dWxvIEVqZXJjaWNpb3MgLS0+DQoNCiMgRWplcmNpY2lvcw0KDQpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQ0KIyBkYXRhIENoaWxkcmVuIGVuIEZhY3RvTWluZVIgIGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9GYWN0b01pbmVSL0ZhY3RvTWluZVIucGRmDQpgYGANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIEVqZXJjaWNpbyAxDQoNCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQojIEVqZW1wbG8gNC40LiBkZWwgbGlicm8gZGUgTWFydMOtbiBEw61heiwgcGFnaW5hIDcyDQpgYGANCg0KU2UgdGllbmVuIGRhdG9zIHNvYnJlIGxhIGFkcXVpc2ljacOzbiBkZSBjdWF0cm8gbWFyY2FzIGVzcGVjw61maWNhcyBkZSB1biBwcm9kdWN0byBwb3IgcGFydGUgZGUgZGlmZXJlbnRlcyBncnVwb3MgZGUgY29uc3VtaWRvcmVzLiBFc3RvcyBkYXRvcyBzZSBwcmVzZW50YW4gZW4gbGEgdGFibGEgYSBjb250aW51YWNpw7NuLCBkb25kZSBjYWRhIGNlbGRhIGluZGljYSBsYSBjYW50aWRhZCBkZSBwZXJzb25hcyBxdWUgcmVndWxhcm1lbnRlIGNvbXByYW4gZWwgcHJvZHVjdG8gZGUgbGEgbWFyY2EgJGk9IEEsIEIsIEMsIEQkIHkgcGVydGVuZWNlbiBhbCBncnVwbyAkaj0xLDIsMyQuDQoNCg0KYGBge3J9DQpkYXRvcyA8LSBkYXRhLmZyYW1lKA0KICBNYXJjYSA9IGMoIkEiLCAiQiIsICJDIiwgIkQiKSwNCiAgR3J1cG9fMSA9IGMoMzAsIDMwLCA4MCwgODApLA0KICBHcnVwb18yID0gYygzMCwgMTMwLCAzMCwgMzApLA0KICBHcnVwb18zID0gYygxNTUsIDMwLCAzMCwgNSkNCikNCg0KcHJpbnQoZGF0b3MpDQpgYGANCg0KDQpcYmVnaW57dGFibGV9W2hdDQpcY2VudGVyaW5nDQpcYmVnaW57dGFidWxhcn17fGN8Y3xjfGN8fQ0KXGhsaW5lDQokTWFyY2EkICYgJEdydXBvIDEkICYgJEdydXBvIDIkICYgJEdydXBvIDMkIFxcDQpcaGxpbmUNCiRBJCAgICAgJiAzMCAgICAgJiAzMCAgICAgJiAxNTUgICAgXFwNCiRCJCAgICAgJiAzMCAgICAgJiAxMzAgICAgJiAzMCAgICAgXFwNCiRDJCAgICAgJiA4MCAgICAgJiAzMCAgICAgJiAzMCAgICAgXFwNCiREJCAgICAgJiA4MCAgICAgJiAzMCAgICAgJiA1IFxcDQpcaGxpbmUNClxlbmR7dGFidWxhcn0NClxlbmR7dGFibGV9DQoNClxub2luZGVudCBBcGxpcXVlIENBIHBhcmEgdmFsaWRhciBsYXMgcGVyY2VwY2lvbmVzIHF1ZSBzZSBkZWR1Y2VuIGRlIGxhIHRhYmxhIGVuIGN1YW50byBhIGxhIHByb3hpbWlkYWQgZW50cmUgbGFzIG1hcmNhcy4NCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRWplcmNpY2lvIDINCg0KYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCiMgQ2FwaXR1bG8gY29ycmVzcG9uZGVjaWEuIEVqZW1wbG8gZGVsIGxpYnJvIGRlIFVubmFsDQpgYGANCg0KQ29uc2lkZXJlIGxhIG1hdHJpeiBkZSBmcmVjdWVuY2lhcyAkKG5fe2lqfSkkIGNvbnRlbmlkYSBlbiBsYSB0YWJsYSBkZSBhYmFqby4gRW4gZXN0YSB0YWJsYSwgbGFzIGZpbGFzICQoaSA9IDEsIDIsIDMsIDQpJCBzb24gZWwgY29sb3IgZGUgbG9zIG9qb3MgeSBsYXMgY29sdW1uYXMgJChqID0gMSwgMiwgMywgNCwgNSkkIGVsIGNvbG9yIGRlbCBjYWJlbGxvLCBjdXlhcyBtb2RhbGlkYWRlcyB2YXLDrWFuIGRlIGNsYXJvIGEgb3NjdXJvLiBQYXJhIGVuY29udHJhciBsYSByZXByZXNlbnRhY2nDs24gbcOhcyBhZGVjdWFkYSBkZSBlc3RvcyBkYXRvcywgZXMgbmVjZXNhcmlvIGNvbXBhcmFyIGxhcyBmaWxhcyB5IGxhcyBjb2x1bW5hcyBkZSBsYSB0YWJsYS4gVGFsIGNvbXBhcmFjacOzbiBpbXBsaWNhIHVzYXIgdW5hIG1lZGlkYSBkZSBkaXN0YW5jaWEgYXByb3BpYWRhLiBFbCBhbsOhbGlzaXMgZGUgY29ycmVzcG9uZGVuY2lhcyBwZXJtaXRlIGRlc2NyaWJpciBsYXMgcHJveGltaWRhZGVzIGV4aXN0ZW50ZXMgZW50cmUgbG9zIHBlcmZpbGVzLCBjb2xvciBkZWwgY2FiZWxsbyAocGVyZmlsIGZpbGEpIHkgY29sb3IgZGUgbG9zIG9qb3MgKHBlcmZpbCBjb2x1bW5hKSwgZGUgYWN1ZXJkbyBjb24gbGEgcGFydGljacOzbiBxdWUgc2UgaGFnYSBkZSBsb3MgaW5kaXZpZHVvcywgc2VhIHBvciBmaWxhcyBvIHBvciBjb2x1bW5hcy4gTGxldmUgYSBjYWJvIGVsIENBIGNvcnJlc3BvbmRpZW50ZS4gDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0KIyBJbnN0YWxhciBlIGltcG9ydGFyIGVsIHBhcXVldGUgJ3h0YWJsZScgc2kgbm8gZXN0w6EgaW5zdGFsYWRvDQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoInh0YWJsZSIsIHF1aWV0bHkgPSBUUlVFKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ4dGFibGUiKQ0KfQ0KbGlicmFyeSh4dGFibGUpDQoNCiMgQ3JlYXIgbG9zIHZlY3RvcmVzIHBhcmEgY2FkYSBmaWxhIHkgY29sdW1uYQ0KQ29sb3IgPC0gYygiT2pvc19DbGFyb3MgKEMpIiwgIk9qb3NfQXp1bGVzIChBKSIsICJPam9zX01lZGlvIChNKSIsICJPam9zX09zY3Vyb3MgKE8pIikNClJ1YmlvIDwtIGMoNjg4LCAzMjYsIDM0MywgOTgpDQpSb2pvIDwtIGMoMTE2LCAzOCwgODQsIDQ4KQ0KTWVkaW8gPC0gYyg1ODQsIDI0MSwgOTA5LCA0MDMpDQpPc2N1cm8gPC0gYygxODgsIDExMCwgNDEyLCA2ODEpDQpOZWdybyA8LSBjKDQsIDMsIDI2LCA4NSkNClRvdGFsIDwtIGMoMTU4MCwgNzE4LCAxNzc0LCAxMzE1KQ0KDQojIENhbGN1bGFyIGxvcyB0b3RhbGVzIHBvciBjb2x1bW5hDQpUb3RhbF9uaiA8LSBjKHN1bShSdWJpbyksIHN1bShSb2pvKSwgc3VtKE1lZGlvKSwgc3VtKE9zY3VybyksIHN1bShOZWdybyksIHN1bShUb3RhbCkpDQoNCiMgQ29uc3RydWlyIGVsIGRhdGEgZnJhbWUNCmRmIDwtIGRhdGEuZnJhbWUoQ29sb3JfZGVfb2pvcywgUnViaW8sIFJvam8sIE1lZGlvLCBPc2N1cm8sIE5lZ3JvLCBUb3RhbCkNClRvdGFsX25qIDwtIGRhdGEuZnJhbWUoIiIsICIiLCAiIiwgIiIsICIiLCAiIiwgVG90YWxfbmopDQpuYW1lcyhUb3RhbF9uaikgPC0gbmFtZXMoZGYpDQoNCiMgQ3JlYXIgbGEgdGFibGEgY29uIGVsIHBhcXVldGUgJ3h0YWJsZScNCnRhYmxhIDwtIHJiaW5kKGRmLCBUb3RhbF9uaikNCnJvd25hbWVzKHRhYmxhKSA8LSBOVUxMDQoNCiMgQ2FtYmlhciBsb3Mgbm9tYnJlcyBkZSBsYXMgY29sdW1uYXMNCm5hbWVzKHRhYmxhKSA8LSBjKCJDb2xvciIsICJDYWJlbGxvX1J1YmlvIChydSkiLCAiQ2FiZWxsb19Sb2pvIChyKSIsICJDYWJlbGxvX01lZGlvIChtKSIsICJDYWJlbGxvX09zY3VybyAobykiLCAiQ2FiZWxsb19OZWdybyAobikiLCAiVG90YWwgKG5pLikiKQ0KDQp0YWJsYQ0KDQojIEltcHJpbWlyIGxhIHRhYmxhIGVuIGZvcm1hdG8gTGFUZVgNCnByaW50KHh0YWJsZSh0YWJsYSwgY2FwdGlvbiA9ICJGcmVjdWVuY2lhcyBhYnNvbHV0YXMuIiwgbGFiZWwgPSAidGFiLTMtMS1mLWEiKSwgaW5jbHVkZS5yb3duYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCg0KYGBge3J9DQojIENyZWFyIGxvcyB2ZWN0b3JlcyBwYXJhIGNhZGEgZmlsYSB5IGNvbHVtbmENCkNvbG9yX2RlX29qb3MgPC0gYygiT19DbGFybyIsICJPX0F6dWwiLCAiT19NZWRpbyIsICJPX09zY3VybyIpDQpSdWJpbyA8LSBjKDY4OCwgMzI2LCAzNDMsIDk4KQ0KUm9qbyA8LSBjKDExNiwgMzgsIDg0LCA0OCkNCk1lZGlvIDwtIGMoNTg0LCAyNDEsIDkwOSwgNDAzKQ0KT3NjdXJvIDwtIGMoMTg4LCAxMTAsIDQxMiwgNjgxKQ0KTmVncm8gPC0gYyg0LCAzLCAyNiwgODUpDQpUb3RhbF9uaS4gPC0gYygxNTgwLCA3MTgsIDE3NzQsIDEzMTUpDQoNCiMgQ2FsY3VsYXIgbG9zIHRvdGFsZXMgcG9yIGNvbHVtbmENClRvdGFsX24uaiA8LSBjKCJUb3RhbCIsIHN1bShSdWJpbyksIHN1bShSb2pvKSwgc3VtKE1lZGlvKSwgc3VtKE9zY3VybyksIHN1bShOZWdybyksIHN1bShUb3RhbF9uaS4pKQ0KDQojIENvbnN0cnVpciBlbCBkYXRhIGZyYW1lDQpkZiA8LSBkYXRhLmZyYW1lKENvbG9yX2RlX29qb3MsIFJ1YmlvLCBSb2pvLCBNZWRpbywgT3NjdXJvLCBOZWdybywgVG90YWxfbmkuKQ0KDQojIEHDsWFkaXIgbGEgZmlsYSBkZSB0b3RhbGVzIGFsIGZpbmFsIGRlbCBkYXRhIGZyYW1lDQpkZiA8LSByYmluZChkZiwgVG90YWxfbi5qKQ0KDQojIENhbWJpYXIgbG9zIG5vbWJyZXMgZGUgbGFzIGNvbHVtbmFzDQpuYW1lcyhkZikgPC0gYygiQ29sb3IiLCAiQ19SdWJpbyIsICJDX1Jvam8iLCAiQ19NZWRpbyIsICJDX09zY3VybyIsICJDX05lZ3JvIiwgIlRvdGFsIikNCg0KZGYNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIEVqZXJjaWNpbyAzDQoNCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQojIENhcGl0dWxvIGNvcnJlc3BvbmRlY2lhLiBFamVyY2ljaW8gMSBkZWwgbGlicm8gZGUgVW5uYWwNCmBgYA0KDQpFbCBjb25qdW50byBkZSBkYXRvcyBgc3VpY2lkZWAgZGUgbGEgbGlicmVyw61hIGBmYXJhd2F5YCBkZWwgc29mdHdhcmUgUiBjb250aWVuZSBsb3MgZGF0b3MgZGUgdW4gYcOxbyBkZSBzdWljaWRpb3MgZW4gZWwgUmVpbm8gVW5pZG8gY2xhc2lmaWNhZG9zIHBvciBzZXhvLCBlZGFkIHkgbcOpdG9kby4NCg0KYGBge3J9DQpsaWJyYXJ5KGZhcmF3YXkpDQpzdWljaWRlDQpgYGANCg0KDQooYSkgQ29tYmluZSBlbCBzZXhvIHkgbGEgZWRhZCBkZSBsb3Mgc3VqZXRvcyBlbiB1biBmYWN0b3Igc2ltcGxlIGRlIHNlaXMgbml2ZWxlcyBxdWUgY29udGllbmUgdG9kYXMgbGFzIGNvbWJpbmFjaW9uZXMgZGUgc2V4byB5IGVkYWQuIENvbmR1emNhIHVuIGFuw6FsaXNpcyBkZSBjb3JyZXNwb25kZW5jaWEgeSBkw6kgdW5hIGludGVycHJldGFjacOzbiBkZSBsb3MgZ3LDoWZpY29zIHkgcmVzdWx0YWRvcyBvYnRlbmlkb3MuDQoNCihiKSBSZXBpdGEgZWwgYW7DoWxpc2lzIGRlIGNvcnJlc3BvbmRlbmNpYSBzZXBhcmFkYW1lbnRlIHBhcmEgaG9tYnJlcyB5IG11amVyZXMuIMK/UmV2ZWxhIGVzdGUgYW7DoWxpc2lzIGFsZ28gbnVldm8gY29tcGFyYWRvIGNvbiBlbCBhbsOhbGlzaXMgY29tYmluYWRvIGRlbCBwdW50byBhbnRlcmlvcj8NCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRWplcmNpY2lvIDQNCg0KYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCiMgQ2FwaXR1bG8gY29ycmVzcG9uZGVjaWEuIEVqZXJjaWNpbyAyIGRlbCBsaWJybyBkZSBVbm5hbA0KYGBgDQpMYSB0YWJsYSBkZSBhYmFqbyBtdWVzdHJhIGxvcyBkYXRvcyBkZSA1MzggcGFjaWVudGVzIHF1ZSBmdWVyb24gY2xhc2lmaWNhZG9zIGVuIGZ1bmNpw7NuIGRlIDQgdGlwb2xvZ8OtYXMgZGUgbGEgZW5mZXJtZWRhZCBkZSBIb2Rna2luIChMUCwgTlMsIE1DLCBMRCkgeSBzdSByZXNwdWVzdGEgYSB1biB0cmF0YW1pZW50byAoUG9zaXRpdm8sIFBhcmNpYWwsIE51bG8pIGFsIGNhYm8gZGUgdHJlcyBtZXNlcy4gQ29uZHV6Y2EgdW4gYW7DoWxpc2lzIGRlIGNvcnJlc3BvbmRlbmNpYXMgeSBkaXNjdXRhIHNpIGVsIHRyYXRhbWllbnRvIGFjdMO6YSBpZ3VhbCBlbiB0b2RhcyBsYXMgdGlwb2xvZ8OtYXMuDQoNCmBgYHtyfQ0KVGlwb2xvZ8OtYSA8LSBjKCJMUCIsICJOUyIsICJNQyIsICJMRCIpDQpQb3NpdGl2YSA8LSBjKDc0LCA2OCwgMTU0LCAxOCkNClBhcmNpYWwgPC0gYygxOCwgMTYsIDU0LCAxMCkNCk51bGEgPC0gYygxMiwgMTIsIDU4LCA0NCkNCg0KZGYgPC0gZGF0YS5mcmFtZShUaXBvbG9nw61hLCBQb3NpdGl2YSwgUGFyY2lhbCwgTnVsYSkNCg0KcHJpbnQoZGYpDQpgYGANCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQoNCjwhLS0gQ2Fww610dWxvIEJpYmxpb2dyYWbDrWEtLT4NCg0KDQojIEJpYmxpb2dyYWbDrWEgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCiAgDQpDb25zdWx0YXIgZWwgZG9jdW1lbnRvIFtSUHVicyA6OiBBbsOhbGlzaXMgbXVsdGl2YXJpYWRvIChiaWJsaW9ncmFmw61hKV0oaHR0cHM6Ly9ycHVicy5jb20vaGxsaW5hcy9SX011bHRpdmFyaWFkb19CaWJsaW9ncmFmaWEpLg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KDQombmJzcDsNCg0KDQombmJzcDsNCjxjZW50ZXI+DQp+fn4NCklmIHlvdSBmb3VuZCBhbnkgRVJST1JTIG9yIGhhdmUgU1VHR0VTVElPTlMsIHBsZWFzZSByZXBvcnQgdGhlbSB0byBteSBlbWFpbC4gVGhhbmtzLiAgDQp+fn4NCjwvY2VudGVyPg0KDQoNCg==