hllinas2023

1 Librerías

1.0.1 Para PCA

El software R dispone de varias funciones de diferentes paquetes para calcular PCA:

  • prcomp y princomp, del paquete stats.

  • PCA del paquete FactoMineR.

  • dudi.pca del paquete ade4.

  • epPCA del paquete ExPosition.

Sin importar la función que elija emplear, es posible extraer y representar de manera sencilla los resultados del PCA mediante las funciones del paquete factoextra. En este documento, se hará uso de los paquetes FactoMineR y ade4 para los análisis y factoextra para la visualización basada en ggplot2.

library(FactoMineR)
library(factoextra)
library(ade4)

1.0.2 Para otros análisis

library(aplore3)       #Base de datos para los ejemplos
library(lsm)           #Base de datos para ejemplos y estimaciones del Log-verosimilitud
library(tidyverse)     #Incluye a dplyr y ggplot2
library(stringr)       #Reemplazar caracteres en un data frame
library(outliers)      #outliers::grubbs.test
library(EnvStats)      #EnvStats::rosnerTest
library(DMwR2)         #LOF (Local Outlier Factor)
library(rgl)           #rgl::plot3d
library(corrplot)      #Matriz de correlaciones
library(textshape)     #column_to_rownames

2 Ejemplo: Enunciado

Los datos se recogieron aplicando una encuesta a una muestra de estudiantes universitarios. Es un data frame con 800 observaciones y 66 variables. Con estos datos llevaremos a cabo un PCA.

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"

Se resalta que sólo algunos de estos individuos y variables se utilizarán para realizar el análisis de componentes principales.

dat <- datosCompleto[1:23, 21:30]
attach(dat)
head(dat,4) 
SemAcum Exam1 Exam2 Exam3 Exam4 ExamAcum Definitive Expense Income Gas
4.25 1.5 5.0 5.0 4.5 16.0 4.000 48.9 1.61 27.45
2.80 2.3 4.9 3.7 3.3 14.2 3.550 72.1 2.07 24.17
4.15 3.4 3.6 2.0 1.9 10.9 2.725 85.2 2.84 22.27
3.20 2.5 4.2 5.0 2.5 14.2 3.550 56.6 1.55 23.08

3 Ejemplo: Solución (factoMineR::PCA)

3.0.1 Descripción de la función factoMineR::PCA

Usaremos la función PCA del paquete FactoMineR. Un formato simple es:

PCA(X, scale.unit = TRUE, ncp = 5, graph = TRUE)

Aquí:

  • X: es un data frame. Las filas son individuos y las columnas son variables numéricas.

  • scale.unit: un valor lógico. Si es TRUE, los datos se escalan a la varianza unitaria antes del análisis. Esta estandarización a la misma escala evita que algunas variablesse vuelvan dominantes sólo por sus grandes unidades de medida. Hace variables comparables.

  • ncp: número de dimensiones conservadas en los resultados finales.

  • graph: valor lógico. Si es TRUE se muestra un gráfico.

3.0.2 Aplicación de la función factoMineR::PCA

El código R siguiente, calcula el análisis de componentes principales en los individuos activos/variables:

#library(FactoMineR)
res.pca <- PCA(dat, scale.unit = TRUE, graph = FALSE)
res.pca
## **Results for the Principal Component Analysis (PCA)**
## The analysis was performed on 23 individuals, described by 10 variables
## *The results are available in the following objects:
## 
##    name               description                          
## 1  "$eig"             "eigenvalues"                        
## 2  "$var"             "results for the variables"          
## 3  "$var$coord"       "coord. for the variables"           
## 4  "$var$cor"         "correlations variables - dimensions"
## 5  "$var$cos2"        "cos2 for the variables"             
## 6  "$var$contrib"     "contributions of the variables"     
## 7  "$ind"             "results for the individuals"        
## 8  "$ind$coord"       "coord. for the individuals"         
## 9  "$ind$cos2"        "cos2 for the individuals"           
## 10 "$ind$contrib"     "contributions of the individuals"   
## 11 "$call"            "summary statistics"                 
## 12 "$call$centre"     "mean of the variables"              
## 13 "$call$ecart.type" "standard error of the variables"    
## 14 "$call$row.w"      "weights for the individuals"        
## 15 "$call$col.w"      "weights for the variables"

El resultado obtenido al utilizar la función PCA almacena una gran cantidad de información distribuida en varias listas y matrices distintas. Estos datos se detallan más adelante.

4 Ejemplo: Solución (factoextra)

4.0.1 Visualización e interpretación

Utilizaremos el paquete factoextra para facilitar la interpretación del Análisis de Componentes Principales (ACP). Independientemente de la función que elija utilizar, ya sea stats::prcomp, FactoMiner::PCA, ade4::dudi.pca o ExPosition::epPCA, se podrá extraer y visualizar los resultados del ACP de manera sencilla utilizando las funciones incluidas en el paquete factoextra.

Estas funciones abarcan:

  • get_eigenvalue(res.pca): Permite extraer los valores propios o las varianzas de los componentes principales.

  • fviz_eig(res.pca): Facilita la visualización de los valores propios.

  • get_pca_ind(res.pca), get_pca_var(res.pca): Extraen los resultados para individuos y variables, respectivamente.

  • fviz_pca_ind(res.pca), fviz_pca_var(res.pca): Facilitan la visualización de los resultados para individuos y variables, respectivamente.

  • fviz_pca_biplot(res.pca): Genera un biplot de individuos y variables.

Más adelante, se ilustrarán cada una de estas funciones.

4.0.2 Eigenvalores / Varianzas

Como hemos explicado en secciones previas, los valores propios cuantifican la cantidad de variación preservada por cada componente principal. Los valores propios tienden a ser más altos para los primeros componentes principales y disminuyen para los siguientes. En otras palabras, los primeros componentes principales representan las direcciones con la mayor variabilidad en el conjunto de datos. Analizamos los valores propios para determinar cuántos componentes principales deben considerarse. Estos valores propios, junto con la proporción de varianza (es decir, la información) conservada por los componentes principales (PC), pueden ser obtenidos utilizando la función get_eigenvalue del paquete factoextra.

#library(factoextra)
eig.val <- get_eigenvalue(res.pca)
eig.val
eigenvalue variance.percent cumulative.variance.percent
Dim.1 3.6816251 36.8162507 36.81625
Dim.2 2.3533760 23.5337601 60.35001
Dim.3 1.4550018 14.5500185 74.90003
Dim.4 0.9056978 9.0569776 83.95701
Dim.5 0.6778436 6.7784358 90.73544
Dim.6 0.4981466 4.9814661 95.71691
Dim.7 0.3604352 3.6043517 99.32126
Dim.8 0.0678739 0.6787395 100.00000
Dim.9 0.0000000 0.0000000 100.00000
Dim.10 0.0000000 0.0000000 100.00000

Interpretaciones:

  1. La suma de todos los valores propios resulta en una varianza total de 10 (porque estamos utilizando 10 variables y las variables están estandarizadas).

  2. La contribución de cada valor propio a la variación se presenta en la segunda columna (eigenvalue).

  3. Por ejemplo, al dividir 3.68 entre 10 (y multiplicando por 100), obtenemos 36.82%, lo que equivale aproximadamente al 36.82% de la variación explicada por este primer valor propio (ver primera fila, tercera columna variance.percent).

  4. El porcentaje acumulado de variación explicada se calcula sumando las proporciones sucesivas de variación explicada para obtener el total acumulado.

  5. Por ejemplo, sumando el 36.82% y el 23.53%, obtenemos 60.3500108% (véase segunda fila y última columna cumulative.variance.percent), y así sucesivamente. Por lo tanto, aproximadamente el 60.35% de la variación se explica por los dos primeros valores propios en conjunto.

  6. En nuestro análisis, los tres primeros componentes principales explican el 74.9% de la variación. Este es un porcentaje aceptablemente alto.

4.0.3 Scree plot

El scree plot puede generarse utilizando la función fviz_eig o fviz_screeplot del paquete factoextra (se genera exactamente la misma gráfica).

# Primera opción: 
fviz_eig(res.pca, addlabels = TRUE, ylim = c(0, 50))

# Segunda opción: 
fviz_screeplot(res.pca, addlabels = TRUE, ylim = c(0, 50))

Basándonos en el diagrama anterior, quizás podríamos focalizarnos en el componente principal número 4. Este componente retiene el 83.96% de la información (varianza) presente en los datos, junto con los 3 primeros componentes principales.

5 Ejemplo: Solución (get_pca_var)

5.0.1 Argumentos de get_pca_var

Una manera simple de obtener los resultados para las variables de una salida de PCA es emplear la función get_pca_var del paquete factoextra. Esta función genera una serie de matrices que contienen toda la información relevante para las variables activas, incluyendo las coordenadas, correlaciones entre variables y ejes, el coseno al cuadrado, y las contribuciones.

var <- get_pca_var(res.pca)
var
## Principal Component Analysis Results for variables
##  ===================================================
##   Name       Description                                    
## 1 "$coord"   "Coordinates for the variables"                
## 2 "$cor"     "Correlations between variables and dimensions"
## 3 "$cos2"    "Cos2 for the variables"                       
## 4 "$contrib" "contributions of the variables"

Los argumentos de la función get_pca_var pueden ser empleados en la representación gráfica de las variables de la siguiente manera:

  • var$coord: Proporciona las coordenadas de las variables para la creación de un gráfico de dispersión.

  • var$cos2: Indica la calidad de la representación de las variables en el mapa de factores. Se obtiene calculando el cuadrado de las coordenadas: var.cos2 = var.coord * var.coord.

  • var$contrib: Contiene las contribuciones (en porcentaje) de las variables a los componentes principales. La contribución de una variable (var) a un componente principal específico se calcula como: (var.cos2 * 100) / (cos2 total del componente).

Se resalta el hecho que es factible representar variables y asignarles colores basados en:

  1. Su grado de relevancia en el mapa de factores (cos2).

  2. Su influencia en los componentes principales.

5.0.2 Valores de get_pca_var

Las diferentes componentes se pueden obtener así:

# Coordenadas de las variables (basado en correlaciones)
var$coord

# Cos2: calidad en el mapa de factores
var$cos2

# Contribuciones para los componentes principales
var$contrib

Más adelante, se explicará cómo representar gráficamente variables y deducir conclusiones sobre las relaciones entre ellas. Luego, se resaltan las variables según:

  1. Su eficacia en la representación en el mapa factorial.

  2. Su influencia en los componentes principales.

6 Ejemplo: Solución (var$coord)

6.0.1 var$coord (valores)

La relación entre una variable y un componente principal (CP) se emplea para expresar las coordenadas de la variable en el CP. La forma de representar las variables difiere del modo en que se representan las observaciones: mientras que las observaciones se muestran mediante sus proyecciones, las variables se representan a través de sus correlaciones.

# Coordenadas de las variables (basado en correlaciones)
var$coord
Dim.1 Dim.2 Dim.3 Dim.4 Dim.5
SemAcum -0.2145226 -0.2150557 0.8047447 -0.1562923 0.0355458
Exam1 0.5709592 -0.2550984 0.0462131 -0.7147055 0.2467163
Exam2 0.6901879 -0.0463324 0.4696794 0.1688567 -0.4721958
Exam3 0.0983160 0.7566005 0.3211927 0.3224122 0.2235646
Exam4 0.4369816 0.5862562 -0.4814517 0.0561226 0.1721912
ExamAcum 0.8881031 0.4242131 0.1491313 -0.0844806 0.0178113
Definitive 0.8881031 0.4242131 0.1491313 -0.0844806 0.0178113
Expense 0.5967389 -0.6454569 0.0130003 0.3889590 0.2013494
Income 0.5735832 -0.6798013 0.0064262 0.2589400 0.3300029
Gas -0.6083446 0.2917306 0.4527719 0.0473446 0.4037740

6.0.2 var$coord (círculo de correlaciones)

Con el siguiente código se grafican las variables:

fviz_pca_var(res.pca, col.var = "red", 
             repel= TRUE # Evita traslapamiento de textos
             )

El diagrama mencionado anteriormente es también referido como un diagrama de correlación de variables. Este diagrama ilustra las relaciones entre todas las variables y puede ser interpretado de la siguiente manera:

  • Las variables que tienen una correlación positiva tienden a agruparse cercanas entre sí en el gráfico.

  • Las variables que tienen una correlación negativa tienden a ubicarse en lados opuestos del origen del gráfico (en cuadrantes opuestos).

  • La distancia entre las variables y el origen del gráfico indica la calidad de las variables en el mapa factorial. Las variables que están más alejadas del origen del gráfico están más claramente representadas en el mapa factorial.

7 Ejemplo: Solución (var$cos2)

7.0.1 var$cos2 (calidad de la representación)

La medida de la calidad de la representación, es decir de cuán bien las variables están representadas en el mapa factorial se conoce como cos2 (cuadrado del coseno, coordenadas cuadradas), el cual se puede obtener de la siguiente manera:

var$cos2
Dim.1 Dim.2 Dim.3 Dim.4 Dim.5
SemAcum 0.0460200 0.0462489 0.6476140 0.0244273 0.0012635
Exam1 0.3259944 0.0650752 0.0021356 0.5108040 0.0608689
Exam2 0.4763594 0.0021467 0.2205987 0.0285126 0.2229689
Exam3 0.0096660 0.5724443 0.1031648 0.1039497 0.0499811
Exam4 0.1909530 0.3436963 0.2317957 0.0031497 0.0296498
ExamAcum 0.7887271 0.1799568 0.0222401 0.0071370 0.0003172
Definitive 0.7887271 0.1799568 0.0222401 0.0071370 0.0003172
Expense 0.3560973 0.4166146 0.0001690 0.1512891 0.0405416
Income 0.3289977 0.4621297 0.0000413 0.0670499 0.1089019
Gas 0.3700832 0.0851067 0.2050024 0.0022415 0.1630334

7.0.2 var$cos2 (matriz de correlaciones)

Se puede visualizar el coseno cuadrado de las variables en todas las dimensiones utilizando la función corrplot del paquete corrplot (el argumento is.corr=FALSE) nos permite visualizar una matrix de valores que no son correlaciones:

corrplot(var$cos2, 
         is.corr=FALSE,   
         tl.col = "black", 
         #addCoef.col = 'grey50', #Agregar valores
         #number.cex = 0.7,       #Tamaño de los valores
         bg = "lightblue",        #Color del fondo
         tl.srt = 90,
         title="Matriz de correlaciones", 
         #tl.cex=1.5,            #Tamaño de las vars y Dims
         #cex.main=2.0,          #Tamaño del título
         #type="lower",
         mar=c(0,0,4,0),        #Ubicación del título
        )

7.0.3 var$cos2 (diagrama de barras)

Con la función fviz_cos2del paquete factoextra, también, es posible crear un diagrama de barras para el cos2de las variables:

# cos2 total de las variables sobre Dim.1 y Dim.2
fviz_cos2(res.pca, choice = "var", axes = 1:2)

7.0.4 var$cos2 (interpetaciones iniciales)

  1. Un coseno cuadrado alto indica una buena representación de la variable en el componente principal. En este caso, la variable está posicionada cerca de la circunferencia del círculo de correlación.

  2. Un coseno cuadrado bajo indica que la variable no está perfectamente representada por los componentes principales. En este caso, la variable está cerca del centro del círculo.

7.0.5 var$cos2 (interpetaciones de la suma total)

  1. Para una variable dada, la suma de los cosenos al cuadrado en todas las componentes principales es igual a uno.

  2. Si una variable está perfectamente representada por solo dos componentes principales (Dim.1 y Dim.2), la suma de los cosenos al cuadrado en estas dos CPs es igual a uno. En este caso, las variables estarán posicionadas en el círculo de correlaciones.

  3. Para algunas variables, puede ser necesario más de 2 componentes para representar perfectamente los datos. En este caso, las variables estarán posicionadas dentro del círculo de correlaciones.

7.0.6 var$cos2 (interpetaciones resumidas)

En resumen:

  1. Los valores de cosenos al cuadrado se utilizan para estimar la calidad de la representación.

  2. Cuanto más cerca esté una variable del círculo de correlaciones, mejor será su representación en el mapa factorial (y más importante será interpretar estas componentes).

  3. Las variables que están cerca del centro del gráfico son menos importantes para las primeras componentes.

7.0.7 var$cos2 (argumento gradient.cols)

Es posible colorear las variables según sus valores cos2 utilizando el argumento col.var = "cos2". Esto produce colores degradados. En este caso, se puede utilizar el argumento gradient.col para proporcionar un color personalizado.

Por ejemplo, gradient.cols = c("green", "brown", "blue") significa que:

  1. Las variables con valores bajos de cos2 serán coloreadas en verde.

  2. Las variables con valores medios de cos2 serán coloreadas en marrón.

  3. Las variables con valores altos de cos2 serán coloreadas en azul.

#Color por valores cos2: calidad sobre el mapa factorial
fviz_pca_var(res.pca, col.var = "cos2",
             gradient.cols = c("green", "brown", "blue"),
             title="Gradiente de las variables por cos2",
             repel = TRUE # Evita traslapamiento de textos
             )

7.0.8 var$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.var = "cos2":

# Cambiar la transpariencia por valores de cos2
fviz_pca_var(res.pca, alpha.var = "cos2",
             col.var = "red",
             title="Transpariencia de las variables por cos2",
             repel = TRUE # Evita traslapamiento de textos
             )

8 Ejemplo: Solución (var$contrib)

8.0.1 var$contrib (general)

Las contribuciones de las variables a la variabilidad de un componente principal determinado se expresan en porcentaje. En este sentido:

  • Las variables que están correlacionadas con PC1 (es decir, Dim.1) y PC2 (es decir, Dim.2) son las más importantes para explicar la variabilidad del conjunto de datos.

  • Las variables que no se correlacionan con ningún PC o se correlacionan con las últimas dimensiones son variables con escasa contribución y pueden eliminarse para simplificar el análisis general.

8.0.2 var$contrib (en R)

La contribución de las variables puede extraerse de la siguiente manera :

var$contrib
Dim.1 Dim.2 Dim.3 Dim.4 Dim.5
SemAcum 1.2499904 1.9652166 44.5094960 2.6970691 0.1864002
Exam1 8.8546321 2.7651851 0.1467796 56.3989472 8.9797893
Exam2 12.9388341 0.0912175 15.1614053 3.1481343 32.8938508
Exam3 0.2625478 24.3243861 7.0903539 11.4773003 7.3735463
Exam4 5.1866485 14.6043942 15.9309580 0.3477698 4.3741351
ExamAcum 21.4233418 7.6467496 1.5285300 0.7880084 0.0468019
Definitive 21.4233418 7.6467496 1.5285300 0.7880084 0.0468019
Expense 9.6722852 17.7028490 0.0116157 16.7041480 5.9809625
Income 8.9362085 19.6368851 0.0028382 7.4031247 16.0659323
Gas 10.0521700 3.6163671 14.0894932 0.2474898 24.0517798

Cuanto mayor sea el valor de la contribución, más contribuye la variable al componente.

8.0.3 var$contrib (correlaciones)

Es posible utilizar la función corrplot del paquete corrplot para resaltar las variables que más contribuyen para cada dimensión.

corrplot(var$contrib, 
         is.corr=FALSE,   
         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 vars y Dims
         #cex.main=2.0,          #Tamaño del título
         #type="lower",
         mar=c(0,0,4,0)          #Ubicación del título
         )

8.0.4 var$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 variables. Si los datos contienen muchas variables, se puede optar por mostrar solo las variables que más contribuyen. El siguiente código en R muestra las 10 variables principales que contribuyen a los componentes principales.

# Contribuciones de las variables a PC1
p1 <- fviz_contrib(res.pca, choice = "var", axes = 1, top = 10)

# Contribuciones de las variables a PC2
p2 <- fviz_contrib(res.pca, choice = "var", axes = 2, top = 10)

8.0.5 var$contrib (diagrama de barra para el total)

A continuación, se puede visualizar la contribución total a PC1 y PC2:

fviz_contrib(res.pca, choice = "var", axes = 1:2, top = 10)

8.0.6 var$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(variables)}} \;=\; \frac{1}{10}(100)\;=\; 10\, \%\]

(1/length(dat))*100
## [1] 10

Interpretación No. 3:

Para un componente dado, una variable con una contribución mayor que este umbral podría considerarse importante en la contribución al componente.

Interpretación No. 4:

Se debe tener en cuenta que la contribución total de una variable dada, en la explicación de las variaciones retenidas por dos componentes principales, digamos PC1 y PC2, se calcula como

\[ \mbox{Contrib} = \frac{C_1 \, \lambda_1 \; +\; C_2 \, \lambda_2}{\lambda_1 \;+\; \lambda_2}\]

donde:

  • \(C_1\) y \(C_2\) son las contribuciones de la variable en PC1 y PC2, respectivamente.

  • \(\lambda_1\) y \(\lambda_2\) son los eigenvalores de PC1 y PC2, respectivamente.

Interpretación No. 5:

Recordar que los eigenvalores miden la cantidad de variación retenida por cada PC. En este caso, la contribución promedio esperada (umbral) se calcula de la siguiente manera: Como se mencionó anteriormente, si las contribuciones de las 10 variables fueran uniformes, la contribución promedio esperada de una variable para PC1 y PC2 es:

\[ \mbox{Contrib} \; =\; \frac{10 \, \lambda_1 \; +\; 10 \, \lambda_2}{\lambda_1 \;+\; \lambda_2}\; =\; 10\]

Se puede observar que la variable ExamAcum contribuyen más a las dimensiones 1 y 2.

8.0.7 var$contrib (círculo de correlaciones)

Las variables más importantes pueden ser resaltadas en el gráfico de correlación de la siguiente manera:

fviz_pca_var(res.pca, col.var = "contrib", 
             repel= TRUE, # Evita traslapamiento de textos,
             )

8.0.8 var$contrib (argumento gradient.cols)

Como ya se explicó, gradient.cols = c("green", "brown", "blue") significa que:

  1. Las variables con valores bajos de cos2 serán coloreadas en verde.

  2. Las variables con valores medios de cos2 serán coloreadas en marrón.

  3. Las variables con valores altos de cos2 serán coloreadas en azul.

fviz_pca_var(res.pca, col.var = "contrib", 
             repel= TRUE, # Evita traslapamiento de textos,
             gradient.cols = c("green", "brown", "blue"),
             )

8.0.9 var$contrib (transpariencias con alpha.var)

Tenga en cuenta que también es posible cambiar la transparencia de las variables según sus valores de contribución utilizando la opción alpha.var = "contrib":

# Cambiar la transpariencia para las contribuciones
fviz_pca_var(res.pca, alpha.var = "contrib",
             col.var = "red",
             #title="Transpariencia de las variables por contribución", 
             repel= TRUE # Evita traslapamiento de textos,
             )

8.0.10 var$contrib (círculo por variable continua)

En las secciones anteriores, demostramos cómo colorear variables según sus contribuciones y su coseno al cuadrado. Es importante destacar que también es posible colorear variables según cualquier variable continua personalizada. La variable de coloración debe tener la misma longitud que el número de variables activas en el ACP (aquí, $n=$10. Ejemplo:

# Create a random continuous variable of length 10
set.seed(123)
my.cont.var <- rnorm(10)

# Color variables by the continuous variable
fviz_pca_var(res.pca, col.var = my.cont.var,
             gradient.cols = c("green", "brown", "blue"),
             repel=TRUE, 
             title="Correlaciones entre las variables por variable continua", 
             legend.title = "Continua"
             )

8.0.11 var$contrib (círculo de correlaciones por grupos)

También es factible alterar el color de las variables basándose en grupos definidos por una variable cualitativa o categórica (comúnmente conocida como factor en R). Dado que no disponemos de ninguna variable de agrupación en nuestros conjuntos de datos para clasificar las variables, optaremos por crear una. En el siguiente ejemplo práctico, inicialmente clasificamos las variables en tres grupos mediante el algoritmo de agrupación kmeans (en otros documentos se explica esta teoría). Posteriormente, empleamos los clústeres obtenidos mediante el algoritmo kmeans para asignar colores a las variables. Para más detalles sobre clustering, puede consultarse la bibliografía recomendada.

# Crear una variable grupal con kmeans
# Crear 3 clúster (centers = 3)
set.seed(123)
res.km <- kmeans(var$coord, centers = 3, nstart = 25)

# Extraer etiquetas de los clúster 
grp   <- as.factor(res.km$cluster)
grp
##    SemAcum      Exam1      Exam2      Exam3      Exam4   ExamAcum Definitive 
##          1          3          2          2          2          2          2 
##    Expense     Income        Gas 
##          3          3          1 
## Levels: 1 2 3

El círculo de correlaciones por grupos es el siguiente:

# Colores de las variables por grupos
fviz_pca_var(res.pca, col.var = grp, 
             palette = c("blue", "brown", "green"),
             legend.title = "Cluster",
             title="Correlaciones entre las variables por grupos", 
             repel= TRUE # Evita traslapamiento de textos
             )

Es importante tener en cuenta que:

  1. Si deseamos modificar los colores de los grupos, debemos emplear el parámetro palette.

  2. Para ajustar los colores de los gradientes, es necesario utilizar el parámetro gradient.cols. Más adelante, se presenta un ejemplo utilizando este argumento.

8.0.12 var$contrib (función dimdesc)

Anteriormente se explicó cómo destacar las variables en función de su contribución a los componentes principales.

La función dimdesc en FactoMineR puede ser empleada para identificar las variables más relevantemente vinculadas a un componente principal específico. Este enfoque resulta útil para determinar la asociación significativa entre las variables y un componente principal dado, y puede ser utilizado de la siguiente manera:

res.desc <- dimdesc(res.pca, axes = c(1,2), proba = 0.05)
# Descripción de la dimensión 1
res.desc$Dim.1
## 
## Link between the variable and the continuous variables (R-square)
## =================================================================================
##            correlation      p.value
## Definitive   0.8881031 1.560010e-08
## ExamAcum     0.8881031 1.560010e-08
## Exam2        0.6901879 2.677184e-04
## Expense      0.5967389 2.648620e-03
## Income       0.5735832 4.216409e-03
## Exam1        0.5709592 4.435181e-03
## Exam4        0.4369816 3.707266e-02
## Gas         -0.6083446 2.070330e-03
# Descripción de la dimensión 2
res.desc$Dim.2
## 
## Link between the variable and the continuous variables (R-square)
## =================================================================================
##            correlation      p.value
## Exam3        0.7566005 2.944647e-05
## Exam4        0.5862562 3.282977e-03
## Definitive   0.4242131 4.365105e-02
## ExamAcum     0.4242131 4.365105e-02
## Expense     -0.6454569 8.807127e-04
## Income      -0.6798013 3.593497e-04

En las salida anteriores, cuando sale $quanti, indica resultados para variables cuantitativas. Es importante destacar que las variables están ordenadas según el \(p\)-valor de la correlación.

9 Ejemplo: Solución (get_pca_ind)

9.0.1 ind (gráficos de resultados)

Los resultados para individuos pueden ser obtenidos utilizando la función get_pca_ind del paquete factoextra. De manera similar a get_pca_var, la función get_pca_ind proporciona una lista de matrices que contienen todos los resultados para los individuos (coordenadas, correlación entre variables y ejes, cosenos al cuadrado y contribuciones).

ind <- get_pca_ind(res.pca)
ind
## Principal Component Analysis Results for individuals
##  ===================================================
##   Name       Description                       
## 1 "$coord"   "Coordinates for the individuals" 
## 2 "$cos2"    "Cos2 for the individuals"        
## 3 "$contrib" "contributions of the individuals"

Para acceder a las diferentes componentes:

# Coordenadas de los individuos
ind$coord

# Calidad de los individuos
ind$cos2

# Contribuciones de los individuos
ind$contrib

9.0.2 ind (gráfico simple)

Se utiliza la función fviz_pca_ind para producir el gráfico de individuos:

fviz_pca_ind(res.pca,
             title="Individuos"
             )

9.0.3 ind: gráfico según cos2

Se puede colorear a los individuos según sus valores de cos2 (al igual que se hace con las variables).

fviz_pca_ind(res.pca, col.ind = "cos2",
             gradient.cols = c("blue", "brown", "green"),
             title="Individuos de acuerdo a cos2", 
             repel= TRUE # Evita traslapamiento de textos
             )

Obsérvese que en el gráfico, las personas similares se agrupan juntas.

9.0.4 ind (tamaño del punto según cos2)

Se puede ajustar también el tamaño del punto de acuerdo al cos2 de los individuos correspondientes.

fviz_pca_ind(res.pca, pointsize = "cos2",
             pointshape = 21, 
             fill = "red",
             repel = TRUE # Evita traslapamiento de textos
             )

9.0.5 ind (tamaño del punto y gradient según cos2)

Para cambiar tanto el tamaño dl punto como el color por cos2:

fviz_pca_ind(res.pca, col.ind = "cos2", pointsize = "cos2",
             gradient.cols = c("blue", "brown", "green"),
             repel = TRUE # Evita traslapamiento de textos
             )

9.0.6 ind (diagrama de contribución a un componente)

Para generar un gráfico de barras de la calidad de representación (cos2) de los individuos en el mapa factorial, se puede emplear la función fviz_cos2 como se ha descrito previamente para las variables:

fviz_cos2(res.pca, choice = "ind")

9.0.7 ind (diagrama de contribución a dos componentes)

Para visualizar la contribución de los individuos a los dos primeros componentes principales, escribe lo siguiente:

fviz_contrib(res.pca, choice = "ind", axes = 1:2)

9.0.8 ind (colorear por variable continua)

En cuanto a las variables, los individuos pueden ser coloreados según cualquier variable continua personalizada especificando el argumento col.ind.

#Genera una variable continua aleatoria de longitud 23 
#(la misma longitud que el número de individuos activos en el PCA).
set.seed(123)
my.cont.var <- rnorm(23)

# Colorear las variables según la variable continua
fviz_pca_ind(res.pca, col.ind = my.cont.var,
             gradient.cols = c("blue", "brown", "green"),
             legend.title = "Scale"
             )

9.0.9 ind (colorear por grupos)

Aquí describimos cómo colorear a individuos por grupo. Además, mostramos cómo agregar elipses de concentración y elipses de confianza por grupos. Para esto, para estas secciones, utilizaremos los datos dat2, construido de tal manera que contenga las variables de dat y cualquier variable categórica (como, por ejemplo, Gender, SES, Economic, etc, o grupos generados aleatoriamente.

dat1 <- datosCompleto[1:50, ]
dat2 <- datosCompleto[1:50, c(22:25,28:30)]
attach(dat2)
head(dat2,4) 
Exam1 Exam2 Exam3 Exam4 Expense Income Gas
1.5 5.0 5.0 4.5 48.9 1.61 27.45
2.3 4.9 3.7 3.3 72.1 2.07 24.17
3.4 3.6 2.0 1.9 85.2 2.84 22.27
2.5 4.2 5.0 2.5 56.6 1.55 23.08
# PCA
dat2.pca <- PCA(dat2, scale.unit = TRUE, graph = FALSE)

Generaremos la variable grupal con kmeans y la anexaremos a los datos originales.

# Crear 3 clúster (centers = 3)
set.seed(123)
res2.km <- kmeans(dat2, centers = 3, nstart = 25)

# Extraer etiquetas de los clúster 
cluster_labels <- res2.km$cluster

# Añadir etiquetas de los clúster a los datos originales
dat1$Cluster <- cluster_labels

gr <- as.factor(dat1$Cluster)
gr_name <- "Clusters"

9.0.10 ind (elipses de concentración)

En el código R (que se muestra abajo), los argumentos habillage o col.ind se pueden utilizar para especificar la variable de factor para colorear a los individuos por grupos. Para agregar una elipse de concentración alrededor de cada grupo, especifique el argumento addEllipses = TRUE. El argumento pallete se puede utilizar para cambiar los colores de los grupos.

fviz_pca_ind(dat2.pca,
             geom.ind = "point", # mostrar solo puntos (no "texto")
             col.ind = gr   ,    # color por grupos
             palette = c("blue", "brown", "green", "yellow", "pink"),
             addEllipses = TRUE, # concentración de elipses
             legend.title = gr_name
            )

9.0.11 ind (elipses de confianza)

Para eliminar el punto medio del grupo, especifique el argumento mean.point = FALSE. Si desea elipses de confianza en lugar de elipses de concentración, utilice ellipse.type = "confidence".

# Añadir elipses de confianza
fviz_pca_ind(dat2.pca, 
             geom.ind = "point", 
             col.ind = gr,
             palette = c("blue", "brown", "green"),
             addEllipses = TRUE, 
             ellipse.type = "confidence",
             legend.title = gr_name
             )

9.0.12 ind (elipses: más paletas de colores)

Téngase en cuenta que los valores permitidos para la paleta incluyen:

  • "grey" para paletas de colores grises;

  • Paletas brewer como "RdBu", "Blues", …; Para ver todas, escriba esto en R: RColorBrewer::display.brewer.all().

  • Paleta de colores personalizada, por ejemplo c("blue", "red");

  • Ppaletas de revistas científicas del paquete ggsci. Por ejemplo: "npg", "aaas", "lancet", "jco", "ucscgb", "uchicago", "simpsons" y "rickandmorty".

Por ejemplo, con la paleta simpsons:

fviz_pca_ind(dat2.pca,
             label = "none",       # Ocultar las etiquetas delos individuos
             col.ind = gr,         # Color por grupos
             addEllipses = TRUE,   # Elipses de concentración
             palette = "simpsons",
             legend.title = gr_name
             )

10 Ejemplo: Solución (personalizar gráficos)

10.0.1 Dimensiones (axes)

Por defecto, las variables/individuos se representan en las dimensiones 1 y 2. Si se desea visualizarlos en las dimensiones 2 y 3, por ejemplo, se debe especificar el argumento axes = c(2, 3).

# Variables sobre las dimensiones 2 y 3
fviz_pca_var(res.pca, 
             axes = c(2, 3), 
             col.var = "red",
             repel=TRUE)

# Individuos sobre las dimensiones 2 y 3
fviz_pca_ind(res.pca, 
             axes = c(2, 3),
             col.ind = "darkblue",
             repel=TRUE)

10.0.2 Graficar elementos (geom)

1. Argumento geom:

El argumento geom (por geometría) y sus derivados se utilizan para especificar los elementos geométricos o elementos gráficos a utilizar en la representación gráfica.

2. Argumento geom.var:

Es un texto que especifica la geometría a utilizar para representar las variables. Los valores permitidos son la combinación de c(“point”, “arrow”, “text”):

  • Se usa geom.var = “point” para mostrar solo puntos.

  • Se usa geom.var = “text” para mostrar solo etiquetas de texto.

  • Se usa geom.var = c(“point”, “text”) para mostrar tanto puntos como etiquetas de texto.

  • Se usa geom.var = c(“arrow”, “text”) para mostrar flechas y etiquetas (predeterminado).

# Mostrar tanto puntos como etiquetas de texto
fviz_pca_var(res.pca, 
             geom.var = c("point", "text"), 
             col.var = "red",
             repel=TRUE
             )

3. Argumento geom.ind:

Es un texto que especifica la geometría a utilizar para trazar los individuos. Los valores permitidos son la combinación de c("point", "text").

  • Se usa geom.ind = "point" para mostrar solo puntos.

  • Se usa geom.ind = "text" para mostrar solo etiquetas de texto.

  • Se usa geom.ind = c("point", "text") para mostrar tanto puntos como etiquetas de texto (por defecto).

# Mostrar sólo etiquetas de texto individuales
fviz_pca_ind(res.pca, 
             geom.ind = "text",
             col.ind= "darkblue",
             repel=TRUE)

10.0.3 Tamaño y forma (label, arrow)

  1. Tamaño de etiqueta: tamaño de la fuente para las etiquetas de texto, por ejemplo: labelsize = 4.3.

  2. Tamaño de flecha: el tamaño de las flechas. Controla el grosor de las flechas, por ejemplo: arrowsize = 1.2.

  3. Tamaño de punto: el tamaño de los puntos, por ejemplo: pointsize = 2.5.

  4. Forma de punto: la forma de los puntos, pointshape = 10. Se puede ejecutar ggpubr::show_point_shapes para ver las formas de punto disponibles.

# Cambiar el tamaño delas flechas en las etiquetas
fviz_pca_var(res.pca, 
             labelsize = 4.3,
             arrowsize = 1.2, 
             repel = TRUE
             )

# Cambiar el tamaño de los puntos, la forma y el color de relleno
# Cambiar el tamaño de las etiquetas
fviz_pca_ind(res.pca,
             pointsize = 3.5, 
             pointshape = 20, 
             fill = "darkgreen",
             labelsize = 4.3, 
             repel = TRUE
             )

10.0.4 Elipses (addEllipses)

Como describimos en secciones anteriores, al colorear individuos por grupos, se puede agregar elipses de concentración de puntos usando el argumento addEllipses = TRUE. Obsérvese que el argumento ellipse.type se puede utilizar para cambiar el tipo de elipses. Los valores posibles son:

  • "convex": traza la envolvente convexa de un conjunto de puntos.

  • "confidence": traza elipses de confianza alrededor de los puntos medios del grupo como la función coord.ellipse en el paquete FactoMineR.

  • "t": asume una distribución \(t\)-multivariada.

  • "norm": asume una distribución normal-multivariada.

  • “euclid”: dibuja un círculo con el radio igual al nivel, representando la distancia euclidiana desde el centro. Esta elipse probablemente no aparecerá circular a menos que se aplique coord_fixed.

El argumento ellipse.level también está disponible para cambiar el tamaño de la elipse de concentración en la probabilidad normal. Por ejemplo, puede especificar ellipse.level = 0.95 o ellipse.level = 0.66.

# Elipses de confianza
fviz_pca_ind(dat2.pca, 
             geom.ind = "point",
             col.ind = gr,   # Color por grupos
             palette = c("blue", "brown", "green"),
             addEllipses = TRUE, 
             ellipse.type = "confidence",
             legend.title = gr_name
             )

# Envolvente convexa
fviz_pca_ind(dat2.pca, 
             geom.ind = "point",
             col.ind = gr,   # Color por grupos
             palette = c("blue", "brown", "green"),
             addEllipses = TRUE, 
             ellipse.type = "convex",
             legend.title = gr_name
             )

10.0.5 Puntos medios por grupo (mean.point)

Cuando se colorean individuos por grupos (ver secciones anteriores), los puntos medios de los grupos (baricentros) también se muestran de forma predeterminada. Para eliminar los puntos medios, se puede utilizar el argumento mean.point = FALSE.

fviz_pca_ind(dat2.pca,
             geom.ind = "point",     # Muestra solo puntos (pero no "texto")
             col.ind = gr,           # Color por grupos
             palette = c("blue", "brown", "green", "yellow", "pink"),
             legend.title = gr_name,
             mean.point = FALSE
             )

10.0.6 Tipo de línea (axes.linetype)

El argumento axes.linetype se puede utilizar para especificar el tipo de línea de los ejes. El valor predeterminado es "dashed" (rayado). Los valores permitidos incluyen "blank" (en blanco), "solid" (sólido), "dotted" (punteado), etc. Para ver todos los valores posibles, escriba ggpubr::show_line_types. Para eliminar las líneas de los ejes, utilice axes.linetype = "blank":

fviz_pca_var(res.pca,
             axes.linetype = "blank",
             col.var="red", 
             repel=TRUE)

10.0.7 Apariencia gráfica (ggpar)

Para cambiar fácilmente la apariencia gráfica de cualquier ggplot, puede utilizar la función ggpar del paquete ggpubr. Los parámetros gráficos que se pueden cambiar usando ggpar incluyen:

  • Títulos principales, etiquetas de ejes y títulos de leyenda.

  • Posición de la leyenda. Valores posibles: "top" (arriba), "bottom" (abajo), "left" (izquierda), "right” (derecha), "none" (ninguno).

  • Paleta de colores.

  • Temas. Los valores permitidos incluyen: theme_gray, theme_bw, theme_minimal, theme_classic, theme_void.

ind.p <- fviz_pca_ind(dat2.pca, 
                      geom = "point", 
                      col.ind = gr
                      )
ggpubr::ggpar(ind.p,
              title = "Principal Component Analysis",
              subtitle = "Survey data set",
              caption = "Source: factoextra",
              xlab = "PC1", 
              ylab = "PC2",
              legend.title = gr_name, 
              legend.position = "top",
              ggtheme = theme_gray(), 
              palette = "jco"
              )

11 Ejemplo: Solución (biplot)

11.0.1 biplot (función)

Para hacer un biplot simple de individuos y variables:

fviz_pca_biplot(res.pca, 
                repel = TRUE,
                col.var = "darkblue", # Color de las variables
                col.ind = "darkgreen" # Color de los individuos
                )

11.0.2 biplot (interpretaciones)

  1. Es importante tener en cuenta que el biplot puede ser útil solo cuando hay un bajo número de variables e individuos en el conjunto de datos; de lo contrario, el gráfico final sería ilegible.

  2. Además, las coordenadas de los individuos y las variables no están construidas en el mismo espacio.

  3. Por lo tanto, en principio, en un biplot, debería centrarte principalmente en la dirección de las variables y no en sus posiciones absolutas en el gráfico.

  4. con respecto a las observaciones anteriores, existe una técnica multivariante que se llama HJ_biplot y que resuelve el tema del espacio dimensional. En R, se visualizar a través del paquete LDABiplots: Biplot Graphical Interface for LDA Models.

De manera general, un biplot se puede interpretar como se explica en los comentarios 5 y 6:

  1. Un individuo que se encuentra en el mismo lado de una variable dada tiene un valor alto para esta variable.

  2. Un individuo que se encuentra en el lado opuesto de una variable dada tiene un valor bajo para esta variable.

11.0.3 biplot (combinando opciones)

Ahora, utilizando la salida dat2.pca, vamos a:

  • Crear un biplot de individuos y variables.

  • Cambiar el color de los individuos por grupos (que sería gr): col.ind = gr.

  • Mostrar solo las etiquetas para variables: label = "var" o usar geom.ind = "point".

fviz_pca_biplot(dat2.pca,
                col.ind = gr,
                palette = "jco",
                addEllipses = TRUE, 
                label = "var",
                col.var = "black", 
                repel = TRUE,
                legend.title = "Gender"
                )

11.0.4 biplot (individuos y variables por grupo)

En el siguiente ejemplo, queremos colorear tanto a individuos como variables por grupos. El truco consiste en utilizar pointshape = 21 para los puntos individuales. Esta forma de punto en particular puede ser rellenada por un color usando el argumento fill.ind. El color de la línea de borde de los puntos individuales se establece en "black" usando col.ind. Para colorear las variables por grupos, se utilizará el argumento col.var. Para personalizar los colores de individuos y variables, utilizamos las funciones auxiliares fill_palette y color_palette en el paquete ggpubr.

#MyVars <- factor(c("SemAcum","Exam1","Exam2","Exam3","Exam4","ExamAcum","Definitive","Expense","Income","Gas"))
MyVars <- factor(c("Exam","Exam","Exam","Exam","Expense","Income","Gas"))

fviz_pca_biplot(dat2.pca,
# LLenando individuos por grupos
geom.ind = "point",
pointshape = 21,
pointsize = 2.5,
fill.ind = gr,
col.ind = "black",

# Color de las variables por grupos
col.var = MyVars,
legend.title = list(fill = gr_name, color = "Variables"),
repel = TRUE 
)+
  
ggpubr::fill_palette("jco")+ # Color de los individuos
  
ggpubr::color_palette("npg") # Color de las variables

11.0.5 biplot (opciones más complejas)

Un ejemplo más complejo consiste en asignar colores a los individuos según los grupos a los que pertenecen (colores discretos) y a las variables según sus contribuciones a los componentes principales (colores en degradado). Además, cambiaremos la transparencia de las variables según sus contribuciones utilizando el argumento alpha.var.

fviz_pca_biplot(dat2.pca,
                # Individuos
                geom.ind = "point",
                fill.ind = gr, 
                col.ind = "black",
                pointshape = 21, 
                pointsize = 2,
                palette = "jco",
                addEllipses = TRUE,
                
                # Variables
                alpha.var ="contrib", 
                col.var = "contrib",
                repel=TRUE,
                gradient.cols = "aaas",
                legend.title = list(fill = gr_name, 
                                    color = "Contrib",
                                    alpha = "Contrib")
                )

12 Tópicos sumplementarios

No hacer click aquí: Pendiente

13 Ejercicios

13.0.1 Ejercicio 1

Supongamos que se tienen 6 observaciones \(x_1, \ldots, x_6\) en dos dimensiones, cada observación corresponde a un rectángulo y las variables son longitud de la base y la altura del rectángulo (véase la figura 13.1).

**Rectángulo**

Figure 13.1: Rectángulo

La matriz de datos es:

\[X\; =\; \begin{pmatrix} 2.0 & 2.0\\ 1.5& 0.5 \\ 0.7 & 0.5\\ 0.5 & 1.5\\ 0.5& 0.7\\ 0.7 & 0.7 \end{pmatrix}\]

Con estos datos, halle:

  1. La matriz \(Y= \log (X)\) (logaritmo con base 10). Es decir, aplique el logaritmo teniendo en cuenta cada una de las componentes y defina la matriz resultante como \(Y\).

  2. La matriz \(S\) de varianzas-covarianzas de \(Y\).

  3. Los valores \(\lambda_i\) y vectores \(v_i\) propios de \(S\).

  4. Las dos componentes \(F_1\) y \(F_2\) evaluadas en los seis rectángulos. Recuerde que cada componente \(F_i\) será un vector de la misma longitud de \(Y_i\) y se calculará así: \[F_i \;= \; Y v_i\]

13.0.2 Ejercicio 2

Las cuatro notas parciales de un determinado curso en una prestigiosa universidad se muestran en la tabla de abajo, en el orden alfabético por apellidos de los estudiantes. El objetivo es saber si existe algún tipo de ordenación de los estudiantes de este grupo, distinto al de promediar las notas de estos estudiantes. Aplique PCA para determinar esto.

Sugerencia:

  1. Halle los valores de las componentes principales para las notas de los 33 estudiantes.

  2. Ordene en forma descendente estos resultados por la primera componente principal.

  3. Compare estos resultados con los obtenidos en la nota definitiva.

id = 1:33
P1 = c(2.30, 3.50, 4.10, 5.00, 2.70, 2.70, 2.90, 2.40, 3.20, 3.80, 4.90, 4.50, 2.70, 2.90, 2.70, 2.70, 2.90, 3.00, 3.10, 3.50, 3.50, 2.70, 2.90, 3.00, 2.70, 3.50, 5.00, 4.90, 3.60, 3.00, 3.10, 4.70, 3.00)
P2 = c(3.40, 3.30, 4.10, 3.00, 2.50, 3.20, 2.80, 2.80, 3.20, 2.80, 4.80, 2.80, 2.80, 2.80, 2.80, 2.60, 3.30, 2.80, 2.80, 2.90, 2.60, 2.80, 2.80, 2.90, 3.40, 3.00, 3.50, 3.20, 2.90, 2.80, 2.80, 5.00, 2.90)
P3 = c(2.90, 3.50, 4.50, 4.00, 2.70, 4.40, 2.80, 2.50, 2.00, 3.00, 5.00, 4.50, 2.50, 2.80, 2.80, 2.60, 3.00, 2.80, 2.80, 3.50, 4.30, 2.00, 2.50, 2.50,  2.00, 4.00, 4.90, 2.80, 2.00, 3.90, 2.00, 3.80, 3.30)
P4 = c(3.30, 3.00, 3.70, 3.00, 3.00, 3.30, 3.50, 3.50, 3.90, 3.50, 3.00, 3.00, 2.90, 3.50, 3.00, 2.80, 2.80, 3.40, 3.30, 3.50, 3.50, 3.60, 3.00, 2.80, 3.00, 3.00, 3.00, 3.50, 4.00, 3.50, 3.60, 3.00, 2.80)
Def = c(2.98, 3.33, 4.10, 3.75, 2.73, 3.40, 3.00, 2.80, 3.08, 3.28, 4.43, 3.70, 2.73, 3.00, 2.83, 2.68, 3.00, 3.00, 3.00, 3.35, 3.48, 2.78, 2.80, 2.80, 2.78, 3.38, 4.10, 3.60, 3.13, 3.30, 2.98, 4.13, 3.00)
datos <- data.frame(id, P1, P2, P3, P4, Def)
print(datos)
##    id  P1  P2  P3  P4  Def
## 1   1 2.3 3.4 2.9 3.3 2.98
## 2   2 3.5 3.3 3.5 3.0 3.33
## 3   3 4.1 4.1 4.5 3.7 4.10
## 4   4 5.0 3.0 4.0 3.0 3.75
## 5   5 2.7 2.5 2.7 3.0 2.73
## 6   6 2.7 3.2 4.4 3.3 3.40
## 7   7 2.9 2.8 2.8 3.5 3.00
## 8   8 2.4 2.8 2.5 3.5 2.80
## 9   9 3.2 3.2 2.0 3.9 3.08
## 10 10 3.8 2.8 3.0 3.5 3.28
## 11 11 4.9 4.8 5.0 3.0 4.43
## 12 12 4.5 2.8 4.5 3.0 3.70
## 13 13 2.7 2.8 2.5 2.9 2.73
## 14 14 2.9 2.8 2.8 3.5 3.00
## 15 15 2.7 2.8 2.8 3.0 2.83
## 16 16 2.7 2.6 2.6 2.8 2.68
## 17 17 2.9 3.3 3.0 2.8 3.00
## 18 18 3.0 2.8 2.8 3.4 3.00
## 19 19 3.1 2.8 2.8 3.3 3.00
## 20 20 3.5 2.9 3.5 3.5 3.35
## 21 21 3.5 2.6 4.3 3.5 3.48
## 22 22 2.7 2.8 2.0 3.6 2.78
## 23 23 2.9 2.8 2.5 3.0 2.80
## 24 24 3.0 2.9 2.5 2.8 2.80
## 25 25 2.7 3.4 2.0 3.0 2.78
## 26 26 3.5 3.0 4.0 3.0 3.38
## 27 27 5.0 3.5 4.9 3.0 4.10
## 28 28 4.9 3.2 2.8 3.5 3.60
## 29 29 3.6 2.9 2.0 4.0 3.13
## 30 30 3.0 2.8 3.9 3.5 3.30
## 31 31 3.1 2.8 2.0 3.6 2.98
## 32 32 4.7 5.0 3.8 3.0 4.13
## 33 33 3.0 2.9 3.3 2.8 3.00

13.0.3 Ejercicio 3

Considere la recomendación de inversión que aparecen en la tabla de la figura 13.2. Cada empresa de gestión financiera tiene un conjunto de porcentajes recomendados en cada uno de los ocho tipos de inversión diferentes. Estos suman 100%, por lo que el objetivo del ejerccio es encontrar un resumen de datos de menor dimensión que represente dicha información.

# Crear el data frame con los datos proporcionados

Manager = c("Alliance Bernstein", "Atlantic Trust", "Bank of America", "BNY Mellon", "Bessemer", "Brown Advisory", "Citi Private Bank", "Constellation", "Deutsche Bank", "Fidelity", "Fiduciary Trust", "Fifth Third Bank","GenSpring", "Glenmede", "Harris Private Bank", "Highmount Capital", "Janney Montgomery", "JPMorgan", "Legg Mason", "Northern Trust", "PNC Asset Mgmt", "Charles Schwab", "SunTrust","UBS", "US Bank", "Wells Fargo", "Wilmington Trust")
S_US = c(45, 28, 53, 26, 19, 29, 18, 20, 29, 40, 40, 28, 13, 35, 54, 25, 47, 20, 55, 24, 40, 29, 26, 32, 43, 27, 27)
S_Non_US = c(3, 6, 9, 9, 9, 13, 27, 10, 14, 14, 10, 9, 8, 12, 10, 5, 4, 9, 3, 8, 8, 20, 6, 10, 16, 13, 11)
S_Dev = c(17, 9, 3, 10, 3, 12, 3, 10, 6, 4, 13, 7, 5, 5, 4, 10, 4, 5, 7, 5, 2, 5, 5, 7, 7, 5, 4)
B_US = c(35, 30, 28, 30, 20, 19, 18, 25, 29, 35, 31, 36, 18, 18, 18, 40, 26, 22, 17, 31, 30, 29, 25, 27, 21, 21, 31)
B_Non_US = c(0, 3, 1, 0, 4, 3, 16, 5, 2, 2, 0, 0, 8, 2, 0, 5, 4, 3, 0, 0, 0, 1, 7, 6, 3, 4, 1)
B_Dev = c(0, 0, 1, 0, 5, 0, 1, 0, 4, 0, 0, 0, 0, 3, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0)
Alternative = c(0, 24, 0, 25, 34, 20, 17, 30, 17, 6, 5, 15, 45, 23, 15, 15, 10, 38, 15, 32, 20, 11, 30, 17, 10, 28, 27)
Cash = c(0, 0, 5, 0, 6, 4, 0, 0, 2, 0, 2, 5, 5, 2, 0, 0, 0, 3, 3, 0, 0, 5, 3, 2, 0, 0, 0)

# Crear el data frame
invest <- data.frame(Manager, S_US, S_Non_US, S_Dev, B_US, B_Non_US, B_Dev, Alternative, Cash)
**Asignaciones de inversión recomendadas (en %) por las empresas de gestión financieras a principios de 2011**

Figure 13.2: Asignaciones de inversión recomendadas (en %) por las empresas de gestión financieras a principios de 2011

13.0.4 Ejercicio 4

Considere nuevamente los datos del ejercicio anterior.

  1. Haga un biplot de las dos primeras componentes principales de recomendaciones de inversión. Observe que Legg Mason (LM) y Harris (HPB) aparecen en la parte superior y Highmount (HC) en la inferior abajo (por lo menos a mí me aparece así). ¿A qué se debe? ¿Qué representa el segundo componente principal el eje vertical?

  2. Halle los valores propios y los vectores propios de la matriz de correlación de los datos de recomendación de inversión.

  3. Muestre que los vectores propios representan las varianzas de los componentes componentes principales de la matriz de correlaciones y verifique que son iguales a los valores obtenidos de los componentes principales.

13.0.5 Ejercicio 5

Los siguientes datos describen el rendimiento de los atletas durante dos eventos deportivos (Desctar y OlympicG). Contiene 27 individuos (atletas) descritos mediante 13 variables. Se resalta que sólo algunos de estos individuos y variables se utilizarán para realizar el análisis de componentes principales.

datos <- factoextra::decathlon2
attach(datos)
dat <- datos[1:23, 1:10]

Con estos datos llevar a cabo un PCA.

  1. Comience examinando las desviaciones estándar de cada variable.

  2. Realice un análisis de componentes principales de estos datos y observe el biplot. Interprete las cargas de los dos primeros componentes principales. ¿Están fuertemente ponderados hacia las mayores desviaciones estándar encontradas en la parte (a)?

  3. Repita el análisis de componentes principales en la matriz de correlación escalada de los datos. ¿Cómo interpreta este biplot?

  4. ¿Qué análisis le parece más útil: el análisis de componentes principales escalado o sin escala para estos datos?

13.0.6 Ejercicio 6

Examine los datos de USJudgeRatings en la librería datasets. Este conjunto de datos contiene las valoraciones de 43 jueces de tribunales superiores de EE.UU. por parte de abogados. Cada uno de los jueces es evaluado en función de 12 atributos, como atributos como la conducta, la preparación para el juicio, la solidez de las sentencias y el número de contactos que cada abogado tuvo con el juez. Consulte el archivo de ayuda de R para más información sobre este conjunto de datos.

library(datasets)
head(USJudgeRatings)
##                CONT INTG DMNR DILG CFMG DECI PREP FAMI ORAL WRIT PHYS RTEN
## AARONSON,L.H.   5.7  7.9  7.7  7.3  7.1  7.4  7.1  7.1  7.1  7.0  8.3  7.8
## ALEXANDER,J.M.  6.8  8.9  8.8  8.5  7.8  8.1  8.0  8.0  7.8  7.9  8.5  8.7
## ARMENTANO,A.J.  7.2  8.1  7.8  7.8  7.5  7.6  7.5  7.5  7.3  7.4  7.9  7.8
## BERDON,R.I.     6.8  8.8  8.5  8.8  8.3  8.5  8.7  8.7  8.4  8.5  8.8  8.7
## BRACKEN,J.J.    7.3  6.4  4.3  6.5  6.0  6.2  5.7  5.7  5.1  5.3  5.5  4.8
## BURNS,E.B.      6.2  8.8  8.7  8.5  7.9  8.0  8.1  8.0  8.0  8.0  8.6  8.6
  1. Examine el diagrama de dispersión por pares de estos datos (con el comando pairs) para revelar que algunas variables están muy correlacionadas.
pairs(USJudgeRatings)

  1. Realice un análisis de componentes principales para estos datos. Los dos primeros componentes de explican el 94% de la variabilidad. El segundo componente es casi totalmente el número de contactos, y el primer componente es esencialmente todas las demás variables, todas con el mismo peso. Interprete este resultado.

13.0.7 Ejercicio 7

Se administraron seis pruebas diferentes de inteligencia y capacidad a 112 personas. La matriz de covarianza (pero no los datos originales) de los resultados de las pruebas se encuentra en ability.cov en la librería datasets.

library(datasets)
ability.cov
## $cov
##         general picture  blocks   maze reading   vocab
## general  24.641   5.991  33.520  6.023  20.755  29.701
## picture   5.991   6.700  18.137  1.782   4.936   7.204
## blocks   33.520  18.137 149.831 19.424  31.430  50.753
## maze      6.023   1.782  19.424 12.711   4.757   9.075
## reading  20.755   4.936  31.430  4.757  52.604  66.762
## vocab    29.701   7.204  50.753  9.075  66.762 135.292
## 
## $center
## [1] 0 0 0 0 0 0
## 
## $n.obs
## [1] 112

Las seis pruebas se denominan: general, picture, blocks, maze (laberinto), reading y vocabulary. En el archivo de ayuda de R puede encontrar más información.

  1. Realice un análisis de componentes principales utilizando la matriz de covarianza e identifique las variables que contribuyen en mayor medida a los dos primeros componentes principales. ¿Cómo interpreta estos componentes principales?

  2. Convierta las covarianzas en matrices de correlación, con ayuda de la función cov2cor.

ability.cor <- cov2cor(ability.cov$cov)
ability.cor
##           general   picture    blocks      maze   reading     vocab
## general 1.0000000 0.4662649 0.5516632 0.3403250 0.5764799 0.5144058
## picture 0.4662649 1.0000000 0.5724364 0.1930992 0.2629229 0.2392766
## blocks  0.5516632 0.5724364 1.0000000 0.4450901 0.3540252 0.3564715
## maze    0.3403250 0.1930992 0.4450901 1.0000000 0.1839645 0.2188370
## reading 0.5764799 0.2629229 0.3540252 0.1839645 1.0000000 0.7913779
## vocab   0.5144058 0.2392766 0.3564715 0.2188370 0.7913779 1.0000000
  1. Realice un análisis de componentes principales utilizando la matriz de correlaciones. Examine las cargas e interprete los dos primeros componentes principales. Compare este resumen de datos con las partes (a) y (b). ¿En qué se diferencian? difieren? ¿En qué se parecen?

  2. ¿Cree que es más apropiado examinar la covarianza o la correlación en un análisis de componentes principales de estos datos?

Bibliografía

Consultar el documento RPubs :: Análisis multivariado (bibliografía).

 

 
If you found any ERRORS or have SUGGESTIONS, please report them to my email. Thanks.  
LS0tDQp0aXRsZTogIkFOw4FMSVNJUyBERSBDT01QT05FTlRFUyBQUklOQ0lQQUxFUyINCnN1YnRpdGxlOiA8aDE+KipBcGxpY2FjacOzbioqPC9oMT4NCg0KYXV0aG9yOiANCiAgLSBuYW1lICAgICAgICAgIDogIkRyLiByZXIuIG5hdC4gSHVtYmVydG8gTExpbsOhcyBTb2xhbm8iDQogICAgYWZmaWxpYXRpb24gICA6ICJEZXBhcnRhbWVudG8gZGUgTWF0ZW3DoXRpY2FzIHkgRXN0YWTDrXN0aWNhLCBVbml2ZXJzaWRhZCBkZWwgTm9ydGUgKEJhcnJhbnF1aWxsYSwgQ29sb21iaWEpIg0KICAgICAjY29ycmVzcG9uZGluZyA6IHllcyAgICAjIERlZmluZSBvbmx5IG9uZSBjb3JyZXNwb25kaW5nIGF1dGhvcg0KICAgICAjYWRkcmVzcyAgICAgICA6ICJEZXBhcnRhbWVudG8gZGUgTWF0ZW3DoXRpY2FzIHkgRXN0YWTDrXN0aWNhIg0KICAgIGVtYWlsICAgICAgICAgOiB8DQogICAgICBobGxpbmFzQHVuaW5vcnRlLmVkdS5jbw0KICAgICAgDQogICAgICBbQmlvZ3JhcGhpY2FsIHNrZXRjaF0oaHR0cHM6Ly9ycHVicy5jb20vaGxsaW5hcy9CaW9fU2tldGNoKQ0KICAgICAgDQogICAgICBgciBmb3JtYXQoU3lzLnRpbWUoKSwgIiVkLyVtLyV5IilgIA0KICAgICAgDQogICAgICNyb2xlOiAgICAgICAgICMgQ29udHJpYnV0b3JzaGlwIHJvbGVzIChlLmcuLCBDUmVkaVQsIGh0dHBzOi8vY2FzcmFpLm9yZy9jcmVkaXQvKQ0KICAjICAgIC0gQ29uY2VwdHVhbGl6YXRpb24NCiAgIyAgICAtIFdyaXRpbmcgLSBPcmlnaW5hbCBEcmFmdCBQcmVwYXJhdGlvbg0KICAjICAgIC0gV3JpdGluZyAtIFJldmlldyAmIEVkaXRpbmcNCiAjIC0gbmFtZSAgICAgICAgICA6ICJBdXRvciBudW1lcm8gMiINCiAjICAgYWZmaWxpYXRpb24gICA6ICIxLDIiDQogIyAgIHJvbGU6DQogIyAgICAgLSBXcml0aW5nIC0gUmV2aWV3ICYgRWRpdGluZw0KICAgICAjYWZmaWxpYXRpb246DQogICMtIGlkICAgICAgICAgICAgOiAiMSINCiAgIyAgaW5zdGl0dXRpb24gICA6ICJVbml2ZXJzaWRhZCBkZWwgTm9ydGUgKEJhcnJhbnF1aWxsYSwgQ29sb21iaWEpIg0KICAjIVtdKGhsbGluYXMuanBnKXt3aWR0aD0xaW59IA0KICANCiNkYXRlOiAnYHIgZm9ybWF0KFN5cy50aW1lKCksICIlZC8lbS8leSIpYCcgICMgdmVyIGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi1jb29rYm9vay91cGRhdGUtZGF0ZS5odG1sDQpvdXRwdXQ6IA0KICAgIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjogDQogICAgICAgICAgI09KTyBTYWxlbiBjYXBpdHVsb3MsIHNlY2Npb25lcyB5IFRlb3JlbWFzDQogICAgI2Jvb2tkb3duOjpodG1sX2Jvb2s6DQogICAgICAgICAgI09KTyBFUlJPUiBTYWxlbiB0ZW9yZW1hcywgcGVybyBubyBzYWxlbiBsb3MgY2FwaXR1bG9zIA0KICAgICNodG1sX2RvY3VtZW50Og0KICAgICAgICAgIHRvYzogdHJ1ZSAgICAgICMgdGFibGUgb2YgY29udGVudCB0cnVlDQogICAgICAgICAgdG9jX2RlcHRoOiA0ICAgIyB1cHRvIHRocmVlIGRlcHRocyBvZiBoZWFkaW5ncyAoc3BlY2lmaWVkIGJ5ICMsICMjIGFuZCAjIyMpDQogICAgICAgICAgdG9jX2Zsb2F0OiB0cnVlICNDb24gdHJ1ZSwgdG9jIHNhbGUgYWwgbWFyZ2VuIGl6cXVpZXJkbyBkZSBsYSBww6FnaW5hOyBkZSBsbyBjb250cmFyaW8sIGFycmliYQ0KICAgICAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICAgICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQ0KICAgICAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZSAgICMgaWYgeW91IHdhbnQgbnVtYmVyIHNlY3Rpb25zIGF0IGVhY2ggdGFibGUgaGVhZGVyDQogICAgICAgICAgI3RoZW1lOiBzYW5kc3RvbmUNCiAgICAgICAgICAjdGhlbWU6IHVuaXRlZCAgIyBtYW55IG9wdGlvbnMgZm9yIHRoZW1lLCB0aGlzIG9uZSBpcyBteSBmYXZvcml0ZS4NCiAgICAgICAgICAjdGhlbWU6IGZsYXRseSAgIyANCiAgICAgICAgICAjdGhlbWU6IGNlcnVsZWFuICAjIA0KICAgICAgICAgICNoaWdobGlnaHQ6IHRhbmdvICAjIHNwZWNpZmllcyB0aGUgc3ludGF4IGhpZ2hsaWdodGluZyBzdHlsZQ0KICAgICAgICAgICNjc3M6IFNjcmlwdHMgYWNjZXNvcmlvcy9lc3RpbG9ib3Rvbi5jc3MNCiAgICAgICAgICAjY3NzOiBteS5jc3MgICAjIHlvdSBjYW4gYWRkIHlvdXIgY3VzdG9tIGNzcywgc2hvdWxkIGJlIGluIHNhbWUgZm9sZGVyDQogICAgICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgICAgICAgICNoaWdobGlnaHQ6IHRhbmdvICAjIGNhbWJpYXIgY29sb3IgZGUgbGlicmFyeSBlbiBhenVsDQogICAgIyBib29rZG93bjo6Z2l0Ym9vazoNCiAgICAjICAgICAgaW5jbHVkZXM6DQogICAgIyAgICAgICAgaW5faGVhZGVyOiBoZWFkZXIuaHRtbA0KICAgICMgYm9va2Rvd246OnBkZl9ib29rOg0KICAgICMgICAgICAga2VlcF90ZXg6IHllcw0KICAgICMgYm9va2Rvd246Omh0bWxfYm9vazoNCiAgICAjICAgICAgIGNzczogdG9jLmNzcw0KICAgICMgYm9va2Rvd246Omh0bWxfYm9vazoNCiAgICAjICAgICAgICAgaW5jbHVkZXM6DQogICAgIyAgICAgICAgICAgaW5faGVhZGVyOiBzdHlsZS5jc3MNCiAgICAjYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOiBkZWZhdWx0DQogICAgIyBib29rZG93bjo6cGRmX2RvY3VtZW50MjoNCiAgICAjICAgICAga2VlcF90ZXg6IHRydWUNCiAgICAjYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYg0KICAgIG1hdGhqYXg6ICJodHRwOi8vZXhhbXBsZS5jb20vbWF0aGpheC9NYXRoSmF4LmpzP2NvbmZpZz1UZVgtQU1TLU1NTF9IVE1Mb3JNTUwiDQpoZWFkZXItaW5jbHVkZXM6DQogICAgXHVzZXBhY2thZ2VbeDExbmFtZXNde3hjb2xvcn0gDQogICAgDQpjc2w6IHNjaWVuY2UuY3NsDQojT2pvOiBTZSB1dGlsaXphIGxlbmd1YWplIFlBTUwNCg0KYWJzdHJhY3Q6IHwNCiAqKkVuIFtScHViczo6IHRvY10oaHR0cHM6Ly9ycHVicy5jb20vaGxsaW5hcy90b2MpIHNlIHB1ZWRlbiB2ZXIgb3Ryb3MgZG9jdW1lbnRvcyBkZSBwb3NpYmxlIGludGVyw6lzLioqDQogIA0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcuYWxpZ249ImNlbnRlciIsICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFIywNCiAgICAgICAgICAgICAgICAgICAgICAjc3R5bGUgPSAiY29sb3I6ZGFya2JsdWUiDQogICAgICAgICAgICAgICAgICAgICMgY2xhc3Muc291cmNlPSJiZy1kYW5nZXIiLCBjbGFzcy5vdXRwdXQ9ImJnLXdhcm5pbmciICAgI0NvbG9yZXMgZGVudHJvIGRlbCBjaHVuaw0KICAgICAgICAgICAgICAgICAgICAgKQ0KbGlicmFyeShyZ2wpDQprbml0cjo6a25pdF9ob29rcyRzZXQod2ViZ2wgPSBob29rX3dlYmdsKQ0KYGBgDQoNCg0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQ0KaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duL2xhbmd1YWdlLWVuZ2luZXMuaHRtbA0KDQpodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ib29rZG93bi9tYXJrZG93bi1zeW50YXguaHRtbA0KDQpodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ib29rZG93bi9hLXNpbmdsZS1kb2N1bWVudC5odG1sDQoNCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL2Jvb2tkb3duL21hcmtkb3duLWV4dGVuc2lvbnMtYnktYm9va2Rvd24uaHRtbA0KDQpodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vYm9va2Rvd24tbWFya2Rvd24uaHRtbCAgIyBUZW9yZW1zIGFuZCBwcm9vZnMNCg0KaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvYm9va2Rvd24vbWFya2Rvd24tZXh0ZW5zaW9ucy1ieS1ib29rZG93bi5odG1sI3RoZW9yZW1zDQoNCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL2Jvb2tkb3duL2h0bWwuaHRtbA0KDQpodHRwczovL3d3dy5kYXRhLXRvLXZpei5jb20vDQogIA0KW1JwdWJzXShsaW5rKQ0KICANCihcI2VxOmVjLSksICBFY3VhY2lvbiBcQHJlZihlcTplYy0pLCBGaWd1cmEgXEByZWYoZmlnOkZpZy0pLCBUYWJsZSBcQHJlZih0YWI6bXRjYXJzKSwgVGhlb3JlbSBcQHJlZih0aG06Ym9yaW5nKQ0KDQoNCiMgVGl0dWxvIHsjVGl0dWxvU2VjY2lvbn0gICBcQHJlZihUaXR1bG9TZWNjaW9uKQ0KICANCiMgRm9yIEhUTUwsIHdlIGNhbiBzZXQgY29sb3Igd2l0aCBDU1MsIGUuZy4sIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkOyI+dGV4dDwvc3Bhbj4NCiAgDQojIGh0dHBzOi8vcmFkaWFudC1yc3RhdHMuZ2l0aHViLmlvL2RvY3MvbW9kZWwvbG9naXN0aWMuaHRtbCBTaGlubnkgTG9naXQgIA0KICANCmBgYA0KDQpgYGB7ciwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0NCiNMYSBmb3RvIHRhbWHDsW8gY8OpZHVsYQ0KDQpodG1sdG9vbHM6OmltZyhzcmMgPSBrbml0cjo6aW1hZ2VfdXJpKGZpbGUucGF0aChSLmhvbWUoImRvYyIpLCAiaHRtbCIsICJsb2dvLmpwZyIpKSwgDQogICAgICAgICAgICAgICBhbHQgPSAnaGxsaW5hcycsIA0KICAgICAgICAgICAgICAgc3R5bGUgPSAncG9zaXRpb246YWJzb2x1dGU7IHRvcDowOyByaWdodDowOyBwYWRkaW5nOjEwcHg7JyAjLA0KICAgICAgICAgICAgICAgd2lkdGggPSAiMjAwcHgiKSAgIyBBcXXDrSBlc3BlY2lmaWNhcyBlbCBhbmNobyBkZXNlYWRvIGVuIHDDrXhlbGVzIG8gcG9yY2VudGFqZQ0KYGBgDQoNCg0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCB9DQojIExhIGZvdG8gZ3JhbmRlDQoNCmh0bWx0b29sczo6aW1nKHNyYyA9IGtuaXRyOjppbWFnZV91cmkoImhsbGluYXMyMDIzLmpwZyIpLCANCiAgICAgICAgICAgICAgIGFsdCA9ICdobGxpbmFzMjAyMycsIA0KICAgICAgICAgICAgICAgc3R5bGUgPSAncG9zaXRpb246YWJzb2x1dGU7IHRvcDowOyByaWdodDowOyBwYWRkaW5nOjFweDsnLA0KICAgICAgICAgICAgICAgd2lkdGg9IjE1JSIpDQpgYGANCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAgLS0+DQoNCmBgYHtjc3MsIGVjaG89RkFMU0V9DQouY29sdW1ucyB7ZGlzcGxheTogZmxleDt9DQpoMSB7Y29sb3I6IGRhcmtibHVlO30NCmgzIHtjb2xvcjogZGFya2dyZWVuO30NCmg0IHtjb2xvcjogZ3JlZW47fQ0KYGBgDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yICAtLT4NCg0KIyBMaWJyZXLDrWFzDQoNCiMjIyBQYXJhIFBDQQ0KDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0KIyAgaHR0cHM6Ly9ycHVicy5jb20vQWxlbWEvMTAwMDU4Mg0KDQojIGh0dHBzOi8vd3d3LmdlZWtzZm9yZ2Vla3Mub3JnL2NvbnRleHR1YWwtb3V0bGllcnMvDQpgYGANCg0KRWwgc29mdHdhcmUgUiBkaXNwb25lIGRlIHZhcmlhcyBmdW5jaW9uZXMgZGUgZGlmZXJlbnRlcyBwYXF1ZXRlcyBwYXJhIGNhbGN1bGFyIFBDQToNCg0KICAgLSBgcHJjb21wYCB5IGBwcmluY29tcGAsIGRlbCBwYXF1ZXRlIGBzdGF0c2AuDQogICAgICAgIA0KICAgLSBgUENBYCBkZWwgcGFxdWV0ZSBgRmFjdG9NaW5lUmAuDQogICAgDQogICAtIGBkdWRpLnBjYWAgZGVsIHBhcXVldGUgYGFkZTRgLg0KICAgIA0KICAgLSBgZXBQQ0FgIGRlbCBwYXF1ZXRlIGBFeFBvc2l0aW9uYC4NCiAgICAgICAgDQoNClNpbiBpbXBvcnRhciBsYSBmdW5jacOzbiBxdWUgZWxpamEgZW1wbGVhciwgZXMgcG9zaWJsZSBleHRyYWVyIHkgcmVwcmVzZW50YXIgZGUgbWFuZXJhIHNlbmNpbGxhIGxvcyByZXN1bHRhZG9zIGRlbCBQQ0EgbWVkaWFudGUgbGFzIGZ1bmNpb25lcyBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAuIEVuIGVzdGUgZG9jdW1lbnRvLCBzZSBoYXLDoSB1c28gZGUgbG9zIHBhcXVldGVzIGBGYWN0b01pbmVSYCB5IGBhZGU0YCAgcGFyYSBsb3MgYW7DoWxpc2lzIHkgYGZhY3RvZXh0cmFgIHBhcmEgbGEgdmlzdWFsaXphY2nDs24gYmFzYWRhIGVuIGBnZ3Bsb3QyYC4NCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShGYWN0b01pbmVSKQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KbGlicmFyeShhZGU0KQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAgLS0+DQoNCiMjIyBQYXJhIG90cm9zIGFuw6FsaXNpcw0KDQpgYGB7ciwgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQpsaWJyYXJ5KGFwbG9yZTMpICAgICAgICNCYXNlIGRlIGRhdG9zIHBhcmEgbG9zIGVqZW1wbG9zDQpsaWJyYXJ5KGxzbSkgICAgICAgICAgICNCYXNlIGRlIGRhdG9zIHBhcmEgZWplbXBsb3MgeSBlc3RpbWFjaW9uZXMgZGVsIExvZy12ZXJvc2ltaWxpdHVkDQpsaWJyYXJ5KGtuaXRyKSAgICAgICAgICNFZGl0YXIgdGFibGFzIGNvbiBrYWJsZSgpDQpsaWJyYXJ5KGthYmxlRXh0cmEpICAgICNFZGl0YXIgdGFibGFzIG3DoXMgZXN0aWxpemFkYXMNCmxpYnJhcnkodGlkeXZlcnNlKSAgICAgI0luY2x1eWUgYSBkcGx5ciB5IGdncGxvdDINCmxpYnJhcnkoc3RyaW5ncikgICAgICAgI1JlZW1wbGF6YXIgY2FyYWN0ZXJlcyBlbiB1biBkYXRhIGZyYW1lDQpsaWJyYXJ5KG91dGxpZXJzKSAgICAgICNvdXRsaWVyczo6Z3J1YmJzLnRlc3QNCmxpYnJhcnkoRW52U3RhdHMpICAgICAgI0VudlN0YXRzOjpyb3NuZXJUZXN0DQpsaWJyYXJ5KERNd1IyKSAgICAgICAgICNMT0YgKExvY2FsIE91dGxpZXIgRmFjdG9yKQ0KbGlicmFyeShyZ2wpICAgICAgICAgICAjcmdsOjpwbG90M2RgDQpsaWJyYXJ5KGNvcnJwbG90KSAgICAgICNNYXRyaXogZGUgY29ycmVsYWNpb25lcw0KbGlicmFyeSh0ZXh0c2hhcGUpICAgICAjY29sdW1uX3RvX3Jvd25hbWVzDQojb3B0c19rbml0JHNldChldmFsLmFmdGVyID0gJ2ZpZy5jYXAnKQ0KYGBgDQoNCmBgYHtjc3MsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9DQojaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNDEwMzA0NzcvY2hhbmdpbmctY2h1bmstYmFja2dyb3VuZC1jb2xvci1pbi1ybWFya2Rvd24NCg0KLmJhZENvZGUgew0KYmFja2dyb3VuZC1jb2xvcjogcmVkOw0KfQ0KYGBgDQoNCmBgYHtyLCAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0NCmxpYnJhcnkoYXBsb3JlMykgICAgICAgI0Jhc2UgZGUgZGF0b3MgcGFyYSBsb3MgZWplbXBsb3MNCmxpYnJhcnkobHNtKSAgICAgICAgICAgI0Jhc2UgZGUgZGF0b3MgcGFyYSBlamVtcGxvcyB5IGVzdGltYWNpb25lcyBkZWwgTG9nLXZlcm9zaW1pbGl0dWQNCmxpYnJhcnkodGlkeXZlcnNlKSAgICAgI0luY2x1eWUgYSBkcGx5ciB5IGdncGxvdDINCmxpYnJhcnkoc3RyaW5ncikgICAgICAgI1JlZW1wbGF6YXIgY2FyYWN0ZXJlcyBlbiB1biBkYXRhIGZyYW1lDQpsaWJyYXJ5KG91dGxpZXJzKSAgICAgICNvdXRsaWVyczo6Z3J1YmJzLnRlc3QNCmxpYnJhcnkoRW52U3RhdHMpICAgICAgI0VudlN0YXRzOjpyb3NuZXJUZXN0DQpsaWJyYXJ5KERNd1IyKSAgICAgICAgICNMT0YgKExvY2FsIE91dGxpZXIgRmFjdG9yKQ0KbGlicmFyeShyZ2wpICAgICAgICAgICAjcmdsOjpwbG90M2QNCmxpYnJhcnkoY29ycnBsb3QpICAgICAgI01hdHJpeiBkZSBjb3JyZWxhY2lvbmVzDQpsaWJyYXJ5KHRleHRzaGFwZSkgICAgICNjb2x1bW5fdG9fcm93bmFtZXMNCmBgYA0KDQoNCg0KDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBFamVtcGxvOiBFbnVuY2lhZG8NCg0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQpMb3MgZGF0b3MgdXRpbGl6YWRvcyBlbiBlc3RlIGVqZW1wbG8gZGVzY3JpYmVuIGVsIHJlbmRpbWllbnRvIGRlIGxvcyBhdGxldGFzIGR1cmFudGUgZG9zIGV2ZW50b3MgZGVwb3J0aXZvcyAoRGVzY3RhciB5IE9seW1waWNHKS4gQ29udGllbmUgMjcgaW5kaXZpZHVvcyAoYXRsZXRhcykgZGVzY3JpdG9zIG1lZGlhbnRlIDEzIHZhcmlhYmxlcy4gQ29uIGVzdG9zIGRhdG9zIGxsZXZhcmVtb3MgYSBjYWJvIHVuIFBDQS4gDQoNCg0KI2BgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGF0b3NDb21wbGV0byA8LSBmYWN0b2V4dHJhOjpkZWNhdGhsb24yDQphdHRhY2goZGF0b3NDb21wbGV0bykNCiNgYGANCg0KDQojYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpuYW1lcyhkYXRvc0NvbXBsZXRvKQ0KI2BgYA0KDQpTZSByZXNhbHRhIHF1ZSBzw7NsbyBhbGd1bm9zIGRlIGVzdG9zIGluZGl2aWR1b3MgeSB2YXJpYWJsZXMgc2UgdXRpbGl6YXLDoW4gcGFyYSByZWFsaXphciBlbCBhbsOhbGlzaXMgZGUgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMuIA0KDQojYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRhdCA8LSBkYXRvc0NvbXBsZXRvWzE6MjMsIDE6MTBdDQphdHRhY2goZGF0KQ0KaGVhZChkYXQsNCkpIA0KI2BgYA0KDQojYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRhdCA8LSBkYXRvc0NvbXBsZXRvWzE6MjMsIDE6MTBdDQphdHRhY2goZGF0KQ0Ka2FibGUoaGVhZChkYXQsNCksYWxpZ24gPSAiY2NjIikgJT4lIyBTZSBuZWNlc2l0YSBsaWJyYXJ5KGtuaXRyKSANCmthYmxlX3N0eWxpbmcoKSAlPiUgICAgICAgICAgICAgICAgI2xpYnJhcnkoa2FibGVFeHRyYSkuLi4uIFNvbG8gcGFyYSBrbml0IHRvIGh0bWwNCmthYmxlX2NsYXNzaWNfMihmdWxsX3dpZHRoID0gRikgICAjbGlicmFyeShrYWJsZUV4dHJhKS4uLi5Tb2xvIHBhcmEga25pdCB0byBodG1sDQojYGBgDQoNCg0KYGBgDQoNCg0KDQoNCg0KTG9zIGRhdG9zIHNlIHJlY29naWVyb24gYXBsaWNhbmRvIHVuYSBlbmN1ZXN0YSBhIHVuYSBtdWVzdHJhIGRlIGVzdHVkaWFudGVzIHVuaXZlcnNpdGFyaW9zLiBFcyB1biBkYXRhIGZyYW1lIGNvbiA4MDAgb2JzZXJ2YWNpb25lcyB5IDY2IHZhcmlhYmxlcy4gQ29uIGVzdG9zIGRhdG9zIGxsZXZhcmVtb3MgYSBjYWJvIHVuIFBDQS4gDQoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkYXRvc0NvbXBsZXRvIDwtIGxzbTo6c3VydmV5DQojZGF0b3NDb21wbGV0byA8LSB0ZXh0c2hhcGU6OmNvbHVtbl90b19yb3duYW1lcyhkYXQsIGxvYz0xKQ0KI2RhdG9zQ29tcGxldG8gJT4lIHJlbW92ZV9yb3duYW1lcyAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhcj0ibmFtZXMiKSAgICNsaWJyYXJ5KHRpZHl2ZXJzZSkNCmF0dGFjaChkYXRvc0NvbXBsZXRvKQ0KYGBgDQoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpuYW1lcyhkYXRvc0NvbXBsZXRvKQ0KYGBgDQoNClNlIHJlc2FsdGEgcXVlIHPDs2xvIGFsZ3Vub3MgZGUgZXN0b3MgaW5kaXZpZHVvcyB5IHZhcmlhYmxlcyBzZSB1dGlsaXphcsOhbiBwYXJhIHJlYWxpemFyIGVsIGFuw6FsaXNpcyBkZSBjb21wb25lbnRlcyBwcmluY2lwYWxlcy4gDQoNCg0KYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRhdCA8LSBkYXRvc0NvbXBsZXRvWzE6MjMsIDIxOjMwXQ0KYXR0YWNoKGRhdCkNCmhlYWQoZGF0LDQpIA0KYGBgDQoNCg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI2RhdCA8LSBkYXRvc0NvbXBsZXRvWzE6MjMsIGMoNSw3LDgsOSwxMywxNSwyMSwyNywyOSwzMCldICMgcHJpbWVyIGludGVudG8NCmRhdCA8LSBkYXRvc0NvbXBsZXRvWzE6MjMsIDIxOjMwXQ0KYXR0YWNoKGRhdCkNCmthYmxlKGhlYWQoZGF0LDQpLGFsaWduID0gImNjYyIpICU+JSMgU2UgbmVjZXNpdGEgbGlicmFyeShrbml0cikgDQprYWJsZV9zdHlsaW5nKCkgJT4lICAgICAgICAgICAgICAgICNsaWJyYXJ5KGthYmxlRXh0cmEpLi4uLiBTb2xvIHBhcmEga25pdCB0byBodG1sDQprYWJsZV9jbGFzc2ljXzIoZnVsbF93aWR0aCA9IEYpICAgI2xpYnJhcnkoa2FibGVFeHRyYSkuLi4uU29sbyBwYXJhIGtuaXQgdG8gaHRtbA0KYGBgDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBFamVtcGxvOiBTb2x1Y2nDs24gKGBmYWN0b01pbmVSOjpQQ0FgKQ0KDQojIyMgRGVzY3JpcGNpw7NuIGRlIGxhIGZ1bmNpw7NuIGBmYWN0b01pbmVSOjpQQ0FgDQoNClVzYXJlbW9zIGxhIGZ1bmNpw7NuIGBQQ0FgIGRlbCBwYXF1ZXRlIGBGYWN0b01pbmVSYC4gVW4gZm9ybWF0byBzaW1wbGUgZXM6IA0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NClBDQShYLCBzY2FsZS51bml0ID0gVFJVRSwgbmNwID0gNSwgZ3JhcGggPSBUUlVFKQ0KYGBgDQoNCkFxdcOtOiANCiAgDQogICsgYFhgOiBlcyB1biBkYXRhIGZyYW1lLiBMYXMgZmlsYXMgc29uIGluZGl2aWR1b3MgeSBsYXMgY29sdW1uYXMgc29uIHZhcmlhYmxlcyBudW3DqXJpY2FzLg0KICANCiAgKyBgc2NhbGUudW5pdGA6IHVuIHZhbG9yIGzDs2dpY28uIFNpIGVzIGBUUlVFYCwgbG9zIGRhdG9zIHNlIGVzY2FsYW4gYSBsYSB2YXJpYW56YSB1bml0YXJpYSBhbnRlcyBkZWwgYW7DoWxpc2lzLiBFc3RhIGVzdGFuZGFyaXphY2nDs24gYSBsYSBtaXNtYSBlc2NhbGEgZXZpdGEgcXVlIGFsZ3VuYXMgdmFyaWFibGVzc2UgdnVlbHZhbiBkb21pbmFudGVzIHPDs2xvIHBvciBzdXMgZ3JhbmRlcyB1bmlkYWRlcyBkZSBtZWRpZGEuIEhhY2UgdmFyaWFibGVzIGNvbXBhcmFibGVzLg0KICANCiAgKyBgbmNwYDogbsO6bWVybyBkZSBkaW1lbnNpb25lcyBjb25zZXJ2YWRhcyBlbiBsb3MgcmVzdWx0YWRvcyBmaW5hbGVzLg0KICANCiAgKyBgZ3JhcGhgOiB2YWxvciBsw7NnaWNvLiBTaSBlcyBgVFJVRWAgc2UgbXVlc3RyYSB1biBncsOhZmljby4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIEFwbGljYWNpw7NuIGRlIGxhIGZ1bmNpw7NuIGBmYWN0b01pbmVSOjpQQ0FgDQoNCkVsIGPDs2RpZ28gUiBzaWd1aWVudGUsIGNhbGN1bGEgZWwgYW7DoWxpc2lzIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIGVuIGxvcyBpbmRpdmlkdW9zIGFjdGl2b3MvdmFyaWFibGVzOg0KDQpgYGB7cn0NCiNsaWJyYXJ5KEZhY3RvTWluZVIpDQpyZXMucGNhIDwtIFBDQShkYXQsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEZBTFNFKQ0KcmVzLnBjYQ0KYGBgDQoNCkVsIHJlc3VsdGFkbyBvYnRlbmlkbyBhbCB1dGlsaXphciBsYSBmdW5jacOzbiBgUENBYCBhbG1hY2VuYSB1bmEgZ3JhbiBjYW50aWRhZCBkZSBpbmZvcm1hY2nDs24gZGlzdHJpYnVpZGEgZW4gdmFyaWFzIGxpc3RhcyB5IG1hdHJpY2VzIGRpc3RpbnRhcy4gRXN0b3MgZGF0b3Mgc2UgZGV0YWxsYW4gbcOhcyBhZGVsYW50ZS4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBFamVtcGxvOiBTb2x1Y2nDs24gKGBmYWN0b2V4dHJhYCkNCg0KIyMjIFZpc3VhbGl6YWNpw7NuIGUgaW50ZXJwcmV0YWNpw7NuDQoNClV0aWxpemFyZW1vcyBlbCBwYXF1ZXRlIGBmYWN0b2V4dHJhYCBwYXJhIGZhY2lsaXRhciBsYSBpbnRlcnByZXRhY2nDs24gZGVsIEFuw6FsaXNpcyBkZSBDb21wb25lbnRlcyBQcmluY2lwYWxlcyAoQUNQKS4gSW5kZXBlbmRpZW50ZW1lbnRlIGRlIGxhIGZ1bmNpw7NuIHF1ZSBlbGlqYSB1dGlsaXphciwgeWEgc2VhIGBzdGF0czo6cHJjb21wYCwgYEZhY3RvTWluZXI6OlBDQWAsIGBhZGU0OjpkdWRpLnBjYWAgIG8gYEV4UG9zaXRpb246OmVwUENBYCwgc2UgcG9kcsOhIGV4dHJhZXIgeSB2aXN1YWxpemFyIGxvcyByZXN1bHRhZG9zIGRlbCBBQ1AgZGUgbWFuZXJhIHNlbmNpbGxhIHV0aWxpemFuZG8gbGFzIGZ1bmNpb25lcyBpbmNsdWlkYXMgZW4gZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAuDQoNCkVzdGFzIGZ1bmNpb25lcyBhYmFyY2FuOg0KICANCiAgKyBgZ2V0X2VpZ2VudmFsdWUocmVzLnBjYSlgOiBQZXJtaXRlIGV4dHJhZXIgbG9zIHZhbG9yZXMgcHJvcGlvcyBvIGxhcyB2YXJpYW56YXMgZGUgbG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLg0KICANCiAgKyBgZnZpel9laWcocmVzLnBjYSlgOiBGYWNpbGl0YSBsYSB2aXN1YWxpemFjacOzbiBkZSBsb3MgdmFsb3JlcyBwcm9waW9zLg0KICANCiAgKyBgZ2V0X3BjYV9pbmQocmVzLnBjYSlgLCBgZ2V0X3BjYV92YXIocmVzLnBjYSlgOiBFeHRyYWVuIGxvcyByZXN1bHRhZG9zIHBhcmEgaW5kaXZpZHVvcyB5IHZhcmlhYmxlcywgcmVzcGVjdGl2YW1lbnRlLg0KICANCiAgKyBgZnZpel9wY2FfaW5kKHJlcy5wY2EpYCwgYGZ2aXpfcGNhX3ZhcihyZXMucGNhKWA6IEZhY2lsaXRhbiBsYSB2aXN1YWxpemFjacOzbiBkZSBsb3MgcmVzdWx0YWRvcyBwYXJhIGluZGl2aWR1b3MgeSB2YXJpYWJsZXMsIHJlc3BlY3RpdmFtZW50ZS4NCiAgDQogICsgYGZ2aXpfcGNhX2JpcGxvdChyZXMucGNhKWA6IEdlbmVyYSB1biBiaXBsb3QgZGUgaW5kaXZpZHVvcyB5IHZhcmlhYmxlcy4NCg0KTcOhcyBhZGVsYW50ZSwgc2UgaWx1c3RyYXLDoW4gY2FkYSB1bmEgZGUgZXN0YXMgZnVuY2lvbmVzLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRWlnZW52YWxvcmVzIC8gVmFyaWFuemFzDQoNCkNvbW8gaGVtb3MgZXhwbGljYWRvIGVuIHNlY2Npb25lcyBwcmV2aWFzLCBsb3MgdmFsb3JlcyBwcm9waW9zIGN1YW50aWZpY2FuIGxhIGNhbnRpZGFkIGRlIHZhcmlhY2nDs24gcHJlc2VydmFkYSBwb3IgY2FkYSBjb21wb25lbnRlIHByaW5jaXBhbC4gTG9zIHZhbG9yZXMgcHJvcGlvcyB0aWVuZGVuIGEgc2VyIG3DoXMgYWx0b3MgcGFyYSBsb3MgcHJpbWVyb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgeSBkaXNtaW51eWVuIHBhcmEgbG9zIHNpZ3VpZW50ZXMuIEVuIG90cmFzIHBhbGFicmFzLCBsb3MgcHJpbWVyb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgcmVwcmVzZW50YW4gbGFzIGRpcmVjY2lvbmVzIGNvbiBsYSBtYXlvciB2YXJpYWJpbGlkYWQgZW4gZWwgY29uanVudG8gZGUgZGF0b3MuIEFuYWxpemFtb3MgbG9zIHZhbG9yZXMgcHJvcGlvcyBwYXJhIGRldGVybWluYXIgY3XDoW50b3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgZGViZW4gY29uc2lkZXJhcnNlLiBFc3RvcyB2YWxvcmVzIHByb3Bpb3MsIGp1bnRvIGNvbiBsYSBwcm9wb3JjacOzbiBkZSB2YXJpYW56YSAoZXMgZGVjaXIsIGxhIGluZm9ybWFjacOzbikgY29uc2VydmFkYSBwb3IgbG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIChQQyksIHB1ZWRlbiBzZXIgb2J0ZW5pZG9zIHV0aWxpemFuZG8gbGEgZnVuY2nDs24gYGdldF9laWdlbnZhbHVlYCBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9DQojbGlicmFyeShmYWN0b2V4dHJhKQ0KZWlnLnZhbCA8LSBnZXRfZWlnZW52YWx1ZShyZXMucGNhKQ0KZWlnLnZhbA0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCiNsaWJyYXJ5KGZhY3RvZXh0cmEpDQplaWcudmFsIDwtIGdldF9laWdlbnZhbHVlKHJlcy5wY2EpDQoNCmthYmxlKGVpZy52YWwsIGFsaWduID0gImNjYyIpICU+JSMgU2UgbmVjZXNpdGEgbGlicmFyeShrbml0cikgDQprYWJsZV9zdHlsaW5nKCkgJT4lICAgICAgICAgICAgICAgICNsaWJyYXJ5KGthYmxlRXh0cmEpLi4uLiBTb2xvIHBhcmEga25pdCB0byBodG1sDQprYWJsZV9jbGFzc2ljXzIoZnVsbF93aWR0aCA9IEYpICAgI2xpYnJhcnkoa2FibGVFeHRyYSkuLi4uU29sbyBwYXJhIGtuaXQgdG8gaHRtbA0KYGBgDQoNCg0KDQoqKkludGVycHJldGFjaW9uZXM6ICoqDQoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQpuY29sKGRhdCkNCmNsYXNzKGVpZy52YWwpICMgRXMgdW5hIG1hdHJpeCwgYXJyZWdsbw0KZWlnLnZhbFsxLDFdDQplaWcudmFsWzEsMl0NCmVpZy52YWxbMiwyXQ0KZWlnLnZhbFsyLDNdDQplaWcudmFsWzMsM10NCmBgYA0KDQoNCiAgMS4gTGEgc3VtYSBkZSB0b2RvcyBsb3MgdmFsb3JlcyBwcm9waW9zIHJlc3VsdGEgZW4gdW5hIHZhcmlhbnphIHRvdGFsIGRlIGByIG5jb2woZGF0KWAgKHBvcnF1ZSBlc3RhbW9zIHV0aWxpemFuZG8gYHIgbmNvbChkYXQpYCB2YXJpYWJsZXMgeSBsYXMgdmFyaWFibGVzIGVzdMOhbiBlc3RhbmRhcml6YWRhcykuIA0KICANCiAgMi4gTGEgY29udHJpYnVjacOzbiBkZSBjYWRhIHZhbG9yIHByb3BpbyBhIGxhIHZhcmlhY2nDs24gc2UgcHJlc2VudGEgZW4gbGEgc2VndW5kYSBjb2x1bW5hIChgZWlnZW52YWx1ZWApLiANCiAgDQogIDMuIFBvciBlamVtcGxvLCBhbCBkaXZpZGlyIGByIHJvdW5kKGVpZy52YWxbMSwxXSwyKWAgIGVudHJlIGByIG5jb2woZGF0KWAgKHkgbXVsdGlwbGljYW5kbyBwb3IgMTAwKSwgb2J0ZW5lbW9zIGByIHJvdW5kKGVpZy52YWxbMSwyXSwyKWAlLCBsbyBxdWUgZXF1aXZhbGUgYXByb3hpbWFkYW1lbnRlIGFsICBgciByb3VuZChlaWcudmFsWzEsMl0sMilgJSBkZSBsYSB2YXJpYWNpw7NuIGV4cGxpY2FkYSBwb3IgZXN0ZSBwcmltZXIgdmFsb3IgcHJvcGlvICh2ZXIgcHJpbWVyYSBmaWxhLCB0ZXJjZXJhIGNvbHVtbmEgYHZhcmlhbmNlLnBlcmNlbnRgKS4gDQogIA0KICA0LiBFbCBwb3JjZW50YWplIGFjdW11bGFkbyBkZSB2YXJpYWNpw7NuIGV4cGxpY2FkYSBzZSBjYWxjdWxhIHN1bWFuZG8gbGFzIHByb3BvcmNpb25lcyBzdWNlc2l2YXMgZGUgdmFyaWFjacOzbiBleHBsaWNhZGEgcGFyYSBvYnRlbmVyIGVsIHRvdGFsIGFjdW11bGFkby4gDQogIA0KICA1LiBQb3IgZWplbXBsbywgc3VtYW5kbyBlbCBgciByb3VuZChlaWcudmFsWzEsMl0sMilgJSB5IGVsIGByIHJvdW5kKGVpZy52YWxbMiwyXSwyKWAlLCBvYnRlbmVtb3MgYHIgZWlnLnZhbFsyLDNdYCUgKHbDqWFzZSBzZWd1bmRhIGZpbGEgeSDDumx0aW1hIGNvbHVtbmEgYGN1bXVsYXRpdmUudmFyaWFuY2UucGVyY2VudGApLCB5IGFzw60gc3VjZXNpdmFtZW50ZS4gUG9yIGxvIHRhbnRvLCBhcHJveGltYWRhbWVudGUgZWwgYHIgcm91bmQoZWlnLnZhbFsyLDNdLDIpYCUgZGUgbGEgdmFyaWFjacOzbiBzZSBleHBsaWNhIHBvciBsb3MgZG9zIHByaW1lcm9zIHZhbG9yZXMgcHJvcGlvcyBlbiBjb25qdW50by4NCiAgDQogIDYuIEVuIG51ZXN0cm8gYW7DoWxpc2lzLCBsb3MgdHJlcyBwcmltZXJvcyBjb21wb25lbnRlcyBwcmluY2lwYWxlcyBleHBsaWNhbiBlbCBgciByb3VuZChlaWcudmFsWzMsM10sMilgJSBkZSBsYSB2YXJpYWNpw7NuLiBFc3RlIGVzIHVuIHBvcmNlbnRhamUgYWNlcHRhYmxlbWVudGUgYWx0by4NCiAgDQoNCg0KICANCiANCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgU2NyZWUgcGxvdA0KDQpFbCAqKnNjcmVlIHBsb3QqKiBwdWVkZSBnZW5lcmFyc2UgdXRpbGl6YW5kbyBsYSBmdW5jacOzbiBgZnZpel9laWdgIG8gYGZ2aXpfc2NyZWVwbG90YCBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAgKHNlIGdlbmVyYSBleGFjdGFtZW50ZSBsYSBtaXNtYSBncsOhZmljYSkuDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0NCiMgUHJpbWVyYSBvcGNpw7NuOiANCmZ2aXpfZWlnKHJlcy5wY2EsIGFkZGxhYmVscyA9IFRSVUUsIHlsaW0gPSBjKDAsIDUwKSkNCg0KIyBTZWd1bmRhIG9wY2nDs246IA0KZnZpel9zY3JlZXBsb3QocmVzLnBjYSwgYWRkbGFiZWxzID0gVFJVRSwgeWxpbSA9IGMoMCwgNTApKQ0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCmZ2aXpfZWlnKHJlcy5wY2EsIGFkZGxhYmVscyA9IFRSVUUsIHlsaW0gPSBjKDAsIDUwKSkNCiNmdml6X3NjcmVlcGxvdChyZXMucGNhLCBhZGRsYWJlbHMgPSBUUlVFLCB5bGltID0gYygwLCA1MCkpDQpgYGANCg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0NCm5jb2woZGF0KQ0KY2xhc3MoZWlnLnZhbCkgIyBFcyB1bmEgbWF0cml4LCBhcnJlZ2xvDQplaWcudmFsWzEsMV0NCmVpZy52YWxbMSwyXQ0KZWlnLnZhbFsyLDJdDQplaWcudmFsWzIsM10NCmVpZy52YWxbMywzXQ0KZWlnLnZhbFs0LDNdDQpgYGANCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCAgZWNobz1GQUxTRX0NCkNvbXBfc2NyZWUgPC0gNA0KYGBgDQoNCg0KQmFzw6FuZG9ub3MgZW4gZWwgZGlhZ3JhbWEgYW50ZXJpb3IsIHF1aXrDoXMgcG9kcsOtYW1vcyBmb2NhbGl6YXJub3MgZW4gZWwgY29tcG9uZW50ZSBwcmluY2lwYWwgbsO6bWVybyBgciBDb21wX3NjcmVlYC4gRXN0ZSBjb21wb25lbnRlIHJldGllbmUgZWwgYHIgcm91bmQoZWlnLnZhbFs0LDNdLDIpYCUgZGUgbGEgaW5mb3JtYWNpw7NuICh2YXJpYW56YSkgcHJlc2VudGUgZW4gbG9zIGRhdG9zLCBqdW50byBjb24gbG9zIGByIENvbXBfc2NyZWUtMWAgcHJpbWVyb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMuDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgZ2V0X3BjYV92YXJgKQ0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBBcmd1bWVudG9zIGRlIGBnZXRfcGNhX3ZhcmANCg0KVW5hIG1hbmVyYSBzaW1wbGUgZGUgb2J0ZW5lciBsb3MgcmVzdWx0YWRvcyBwYXJhIGxhcyB2YXJpYWJsZXMgZGUgdW5hIHNhbGlkYSBkZSBQQ0EgZXMgZW1wbGVhciBsYSBmdW5jacOzbiBgZ2V0X3BjYV92YXJgIGRlbCBwYXF1ZXRlIGBmYWN0b2V4dHJhYC4gRXN0YSBmdW5jacOzbiBnZW5lcmEgdW5hIHNlcmllIGRlIG1hdHJpY2VzIHF1ZSBjb250aWVuZW4gdG9kYSBsYSBpbmZvcm1hY2nDs24gcmVsZXZhbnRlIHBhcmEgbGFzIHZhcmlhYmxlcyBhY3RpdmFzLCBpbmNsdXllbmRvIGxhcyBjb29yZGVuYWRhcywgY29ycmVsYWNpb25lcyBlbnRyZSB2YXJpYWJsZXMgeSBlamVzLCBlbCBjb3Nlbm8gYWwgY3VhZHJhZG8sIHkgbGFzIGNvbnRyaWJ1Y2lvbmVzLg0KDQoNCmBgYHtyfQ0KdmFyIDwtIGdldF9wY2FfdmFyKHJlcy5wY2EpDQp2YXINCmBgYA0KDQpMb3MgYXJndW1lbnRvcyBkZSBsYSBmdW5jacOzbiBgZ2V0X3BjYV92YXJgIHB1ZWRlbiBzZXIgZW1wbGVhZG9zIGVuIGxhIHJlcHJlc2VudGFjacOzbiBncsOhZmljYSBkZSBsYXMgdmFyaWFibGVzIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQogIA0KICArIGB2YXIkY29vcmRgOiBQcm9wb3JjaW9uYSBsYXMgY29vcmRlbmFkYXMgZGUgbGFzIHZhcmlhYmxlcyBwYXJhIGxhIGNyZWFjacOzbiBkZSB1biBncsOhZmljbyBkZSBkaXNwZXJzacOzbi4NCiAgDQogICsgYHZhciRjb3MyYDogSW5kaWNhIGxhIGNhbGlkYWQgZGUgbGEgcmVwcmVzZW50YWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgZW4gZWwgbWFwYSBkZSBmYWN0b3Jlcy4gU2Ugb2J0aWVuZSBjYWxjdWxhbmRvIGVsIGN1YWRyYWRvIGRlIGxhcyBjb29yZGVuYWRhczogYHZhci5jb3MyYCA9IGB2YXIuY29vcmQgKiB2YXIuY29vcmRgLg0KICANCiAgKyBgdmFyJGNvbnRyaWJgOiBDb250aWVuZSBsYXMgY29udHJpYnVjaW9uZXMgKGVuIHBvcmNlbnRhamUpIGRlIGxhcyB2YXJpYWJsZXMgYSBsb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMuIExhIGNvbnRyaWJ1Y2nDs24gZGUgdW5hIHZhcmlhYmxlIChgdmFyYCkgYSB1biBjb21wb25lbnRlIHByaW5jaXBhbCBlc3BlY8OtZmljbyBzZSBjYWxjdWxhIGNvbW86IGAodmFyLmNvczIgKiAxMDApIC8gKGNvczIgdG90YWwgZGVsIGNvbXBvbmVudGUpYC4NCiAgDQoNClNlIHJlc2FsdGEgZWwgaGVjaG8gcXVlIGVzIGZhY3RpYmxlIHJlcHJlc2VudGFyIHZhcmlhYmxlcyB5IGFzaWduYXJsZXMgY29sb3JlcyBiYXNhZG9zIGVuOiANCiAgDQogIGEpIFN1IGdyYWRvIGRlIHJlbGV2YW5jaWEgZW4gZWwgbWFwYSBkZSBmYWN0b3JlcyAoYGNvczJgKS4NCiAgDQogIGIpIFN1IGluZmx1ZW5jaWEgZW4gbG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLg0KICANCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgVmFsb3JlcyBkZSBgZ2V0X3BjYV92YXJgDQoNCkxhcyBkaWZlcmVudGVzIGNvbXBvbmVudGVzIHNlIHB1ZWRlbiBvYnRlbmVyIGFzw606IA0KDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBDb29yZGVuYWRhcyBkZSBsYXMgdmFyaWFibGVzIChiYXNhZG8gZW4gY29ycmVsYWNpb25lcykNCnZhciRjb29yZA0KDQojIENvczI6IGNhbGlkYWQgZW4gZWwgbWFwYSBkZSBmYWN0b3Jlcw0KdmFyJGNvczINCg0KIyBDb250cmlidWNpb25lcyBwYXJhIGxvcyBjb21wb25lbnRlcyBwcmluY2lwYWxlcw0KdmFyJGNvbnRyaWINCmBgYA0KDQpNw6FzIGFkZWxhbnRlLCBzZSBleHBsaWNhcsOhIGPDs21vIHJlcHJlc2VudGFyIGdyw6FmaWNhbWVudGUgdmFyaWFibGVzIHkgZGVkdWNpciBjb25jbHVzaW9uZXMgc29icmUgbGFzIHJlbGFjaW9uZXMgZW50cmUgZWxsYXMuIEx1ZWdvLCBzZSByZXNhbHRhbiBsYXMgdmFyaWFibGVzIHNlZ8O6bjoNCiAgDQogIGEpIFN1IGVmaWNhY2lhIGVuIGxhIHJlcHJlc2VudGFjacOzbiBlbiBlbCBtYXBhIGZhY3RvcmlhbC4gDQogIA0KICBiKSBTdSBpbmZsdWVuY2lhIGVuIGxvcyBjb21wb25lbnRlcyBwcmluY2lwYWxlcy4NCiAgDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgdmFyJGNvb3JkYCkNCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYHZhciRjb29yZGAgKHZhbG9yZXMpDQoNCkxhIHJlbGFjacOzbiBlbnRyZSB1bmEgdmFyaWFibGUgeSB1biBjb21wb25lbnRlIHByaW5jaXBhbCAoQ1ApIHNlIGVtcGxlYSBwYXJhIGV4cHJlc2FyIGxhcyBjb29yZGVuYWRhcyBkZSBsYSB2YXJpYWJsZSBlbiBlbCBDUC4gTGEgZm9ybWEgZGUgcmVwcmVzZW50YXIgbGFzIHZhcmlhYmxlcyBkaWZpZXJlIGRlbCBtb2RvIGVuIHF1ZSBzZSByZXByZXNlbnRhbiBsYXMgb2JzZXJ2YWNpb25lczogbWllbnRyYXMgcXVlIGxhcyBvYnNlcnZhY2lvbmVzIHNlIG11ZXN0cmFuIG1lZGlhbnRlIHN1cyBwcm95ZWNjaW9uZXMsIGxhcyB2YXJpYWJsZXMgc2UgcmVwcmVzZW50YW4gYSB0cmF2w6lzIGRlIHN1cyBjb3JyZWxhY2lvbmVzLg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgQ29vcmRlbmFkYXMgZGUgbGFzIHZhcmlhYmxlcyAoYmFzYWRvIGVuIGNvcnJlbGFjaW9uZXMpDQp2YXIkY29vcmQNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCiMgQ29vcmRlbmFkYXMgZGUgbGFzIHZhcmlhYmxlcyAoYmFzYWRvIGVuIGNvcnJlbGFjaW9uZXMpDQprYWJsZSh2YXIkY29vcmQsIGFsaWduID0gImNjYyIpICU+JSMgU2UgbmVjZXNpdGEgbGlicmFyeShrbml0cikgDQprYWJsZV9zdHlsaW5nKCkgJT4lICAgICAgICAgICAgICAgICNsaWJyYXJ5KGthYmxlRXh0cmEpLi4uLiBTb2xvIHBhcmEga25pdCB0byBodG1sDQprYWJsZV9jbGFzc2ljXzIoZnVsbF93aWR0aCA9IEYpICAgI2xpYnJhcnkoa2FibGVFeHRyYSkuLi4uU29sbyBwYXJhIGtuaXQgdG8gaHRtbA0KYGBgDQoNCiMjIyBgdmFyJGNvb3JkYCAoY8OtcmN1bG8gZGUgY29ycmVsYWNpb25lcykNCg0KQ29uIGVsIHNpZ3VpZW50ZSBjw7NkaWdvIHNlIGdyYWZpY2FuIGxhcyB2YXJpYWJsZXM6IA0KDQpgYGB7cn0NCmZ2aXpfcGNhX3ZhcihyZXMucGNhLCBjb2wudmFyID0gInJlZCIsIA0KICAgICAgICAgICAgIHJlcGVsPSBUUlVFICMgRXZpdGEgdHJhc2xhcGFtaWVudG8gZGUgdGV4dG9zDQogICAgICAgICAgICAgKQ0KYGBgDQoNCkVsIGRpYWdyYW1hIG1lbmNpb25hZG8gYW50ZXJpb3JtZW50ZSBlcyB0YW1iacOpbiByZWZlcmlkbyBjb21vIHVuICpkaWFncmFtYSBkZSBjb3JyZWxhY2nDs24qIGRlIHZhcmlhYmxlcy4gRXN0ZSBkaWFncmFtYSBpbHVzdHJhIGxhcyByZWxhY2lvbmVzIGVudHJlIHRvZGFzIGxhcyB2YXJpYWJsZXMgeSBwdWVkZSBzZXIgaW50ZXJwcmV0YWRvIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQogIA0KICArIExhcyB2YXJpYWJsZXMgcXVlIHRpZW5lbiB1bmEgY29ycmVsYWNpw7NuIHBvc2l0aXZhIHRpZW5kZW4gYSBhZ3J1cGFyc2UgY2VyY2FuYXMgZW50cmUgc8OtIGVuIGVsIGdyw6FmaWNvLg0KICANCiAgKyBMYXMgdmFyaWFibGVzIHF1ZSB0aWVuZW4gdW5hIGNvcnJlbGFjacOzbiBuZWdhdGl2YSB0aWVuZGVuIGEgdWJpY2Fyc2UgZW4gbGFkb3Mgb3B1ZXN0b3MgZGVsIG9yaWdlbiBkZWwgZ3LDoWZpY28gKGVuIGN1YWRyYW50ZXMgb3B1ZXN0b3MpLg0KICANCiAgKyBMYSBkaXN0YW5jaWEgZW50cmUgbGFzIHZhcmlhYmxlcyB5IGVsIG9yaWdlbiBkZWwgZ3LDoWZpY28gaW5kaWNhIGxhIGNhbGlkYWQgZGUgbGFzIHZhcmlhYmxlcyBlbiBlbCBtYXBhIGZhY3RvcmlhbC4gTGFzIHZhcmlhYmxlcyBxdWUgZXN0w6FuIG3DoXMgYWxlamFkYXMgZGVsIG9yaWdlbiBkZWwgZ3LDoWZpY28gZXN0w6FuIG3DoXMgY2xhcmFtZW50ZSByZXByZXNlbnRhZGFzIGVuIGVsIG1hcGEgZmFjdG9yaWFsLg0KICANCiAgDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBFamVtcGxvOiBTb2x1Y2nDs24gKGB2YXIkY29zMmApICANCiAgDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGB2YXIkY29zMmAgKGNhbGlkYWQgZGUgbGEgcmVwcmVzZW50YWNpw7NuKQ0KDQoNCkxhIG1lZGlkYSBkZSBsYSBjYWxpZGFkIGRlIGxhIHJlcHJlc2VudGFjacOzbiwgZXMgZGVjaXIgZGUgY3XDoW4gYmllbiBsYXMgdmFyaWFibGVzIGVzdMOhbiByZXByZXNlbnRhZGFzIGVuIGVsIG1hcGEgZmFjdG9yaWFsIHNlIGNvbm9jZSBjb21vIGBjb3MyYCAoKmN1YWRyYWRvIGRlbCBjb3Nlbm8qLCAqY29vcmRlbmFkYXMgY3VhZHJhZGFzKiksIGVsIGN1YWwgc2UgcHVlZGUgb2J0ZW5lciAgZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCnZhciRjb3MyDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQprYWJsZSh2YXIkY29zMiwgYWxpZ24gPSAiY2NjIikgJT4lIyBTZSBuZWNlc2l0YSBsaWJyYXJ5KGtuaXRyKSANCmthYmxlX3N0eWxpbmcoKSAlPiUgICAgICAgICAgICAgICAgI2xpYnJhcnkoa2FibGVFeHRyYSkuLi4uIFNvbG8gcGFyYSBrbml0IHRvIGh0bWwNCmthYmxlX2NsYXNzaWNfMihmdWxsX3dpZHRoID0gRikgICAjbGlicmFyeShrYWJsZUV4dHJhKS4uLi5Tb2xvIHBhcmEga25pdCB0byBodG1sDQpgYGANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGB2YXIkY29zMmAgKG1hdHJpeiBkZSBjb3JyZWxhY2lvbmVzKQ0KDQpTZSBwdWVkZSB2aXN1YWxpemFyIGVsICpjb3Nlbm8gY3VhZHJhZG8qIGRlIGxhcyB2YXJpYWJsZXMgZW4gdG9kYXMgbGFzIGRpbWVuc2lvbmVzIHV0aWxpemFuZG8gbGEgZnVuY2nDs24gYGNvcnJwbG90YCBkZWwgcGFxdWV0ZSBgY29ycnBsb3RgIChlbCBhcmd1bWVudG8gYGlzLmNvcnI9RkFMU0VgKSBub3MgcGVybWl0ZSB2aXN1YWxpemFyIHVuYSBtYXRyaXggZGUgdmFsb3JlcyBxdWUgbm8gc29uIGNvcnJlbGFjaW9uZXM6IA0KICANCmBgYHtyfQ0KY29ycnBsb3QodmFyJGNvczIsIA0KICAgICAgICAgaXMuY29ycj1GQUxTRSwgICANCiAgICAgICAgIHRsLmNvbCA9ICJibGFjayIsIA0KICAgICAgICAgI2FkZENvZWYuY29sID0gJ2dyZXk1MCcsICNBZ3JlZ2FyIHZhbG9yZXMNCiAgICAgICAgICNudW1iZXIuY2V4ID0gMC43LCAgICAgICAjVGFtYcOxbyBkZSBsb3MgdmFsb3Jlcw0KICAgICAgICAgYmcgPSAibGlnaHRibHVlIiwgICAgICAgICNDb2xvciBkZWwgZm9uZG8NCiAgICAgICAgIHRsLnNydCA9IDkwLA0KICAgICAgICAgdGl0bGU9Ik1hdHJpeiBkZSBjb3JyZWxhY2lvbmVzIiwgDQogICAgICAgICAjdGwuY2V4PTEuNSwgICAgICAgICAgICAjVGFtYcOxbyBkZSBsYXMgdmFycyB5IERpbXMNCiAgICAgICAgICNjZXgubWFpbj0yLjAsICAgICAgICAgICNUYW1hw7FvIGRlbCB0w610dWxvDQogICAgICAgICAjdHlwZT0ibG93ZXIiLA0KICAgICAgICAgbWFyPWMoMCwwLDQsMCksICAgICAgICAjVWJpY2FjacOzbiBkZWwgdMOtdHVsbw0KICAgICAgICApDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgdmFyJGNvczJgIChkaWFncmFtYSBkZSBiYXJyYXMpDQoNCkNvbiBsYSBmdW5jacOzbiBgZnZpel9jb3MyYGRlbCBwYXF1ZXRlIGBmYWN0b2V4dHJhYCwgdGFtYmnDqW4sIGVzIHBvc2libGUgY3JlYXIgdW4gZGlhZ3JhbWEgZGUgYmFycmFzIHBhcmEgZWwgYGNvczJgZGUgbGFzIHZhcmlhYmxlczoNCg0KYGBge3J9DQojIGNvczIgdG90YWwgZGUgbGFzIHZhcmlhYmxlcyBzb2JyZSBEaW0uMSB5IERpbS4yDQpmdml6X2NvczIocmVzLnBjYSwgY2hvaWNlID0gInZhciIsIGF4ZXMgPSAxOjIpDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgdmFyJGNvczJgIChpbnRlcnBldGFjaW9uZXMgaW5pY2lhbGVzKQ0KICANCiAgMS4gVW4gY29zZW5vIGN1YWRyYWRvIGFsdG8gaW5kaWNhIHVuYSBidWVuYSByZXByZXNlbnRhY2nDs24gZGUgbGEgdmFyaWFibGUgZW4gZWwgY29tcG9uZW50ZSBwcmluY2lwYWwuIEVuIGVzdGUgY2FzbywgbGEgdmFyaWFibGUgZXN0w6EgcG9zaWNpb25hZGEgY2VyY2EgZGUgbGEgY2lyY3VuZmVyZW5jaWEgZGVsIGPDrXJjdWxvIGRlIGNvcnJlbGFjacOzbi4NCiAgDQogIDIuIFVuIGNvc2VubyBjdWFkcmFkbyBiYWpvIGluZGljYSBxdWUgbGEgdmFyaWFibGUgbm8gZXN0w6EgcGVyZmVjdGFtZW50ZSByZXByZXNlbnRhZGEgcG9yIGxvcyBjb21wb25lbnRlcyBwcmluY2lwYWxlcy4gRW4gZXN0ZSBjYXNvLCBsYSB2YXJpYWJsZSBlc3TDoSBjZXJjYSBkZWwgY2VudHJvIGRlbCBjw61yY3Vsby4NCiAgDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGB2YXIkY29zMmAgKGludGVycGV0YWNpb25lcyBkZSBsYSBzdW1hIHRvdGFsKQ0KICANCjMuIFBhcmEgdW5hIHZhcmlhYmxlIGRhZGEsIGxhIHN1bWEgZGUgbG9zIGNvc2Vub3MgYWwgY3VhZHJhZG8gZW4gdG9kYXMgbGFzIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIGVzIGlndWFsIGEgdW5vLiANCg0KNC4gU2kgdW5hIHZhcmlhYmxlIGVzdMOhIHBlcmZlY3RhbWVudGUgcmVwcmVzZW50YWRhIHBvciBzb2xvIGRvcyBjb21wb25lbnRlcyBwcmluY2lwYWxlcyAoRGltLjEgeSBEaW0uMiksIGxhIHN1bWEgZGUgbG9zIGNvc2Vub3MgYWwgY3VhZHJhZG8gZW4gZXN0YXMgZG9zIENQcyBlcyBpZ3VhbCBhIHVuby4gRW4gZXN0ZSBjYXNvLCBsYXMgdmFyaWFibGVzIGVzdGFyw6FuIHBvc2ljaW9uYWRhcyBlbiBlbCBjw61yY3VsbyBkZSBjb3JyZWxhY2lvbmVzLiANCg0KNS4gUGFyYSBhbGd1bmFzIHZhcmlhYmxlcywgcHVlZGUgc2VyIG5lY2VzYXJpbyBtw6FzIGRlIDIgY29tcG9uZW50ZXMgcGFyYSByZXByZXNlbnRhciBwZXJmZWN0YW1lbnRlIGxvcyBkYXRvcy4gRW4gZXN0ZSBjYXNvLCBsYXMgdmFyaWFibGVzIGVzdGFyw6FuIHBvc2ljaW9uYWRhcyBkZW50cm8gZGVsIGPDrXJjdWxvIGRlIGNvcnJlbGFjaW9uZXMuIA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYHZhciRjb3MyYCAoaW50ZXJwZXRhY2lvbmVzIHJlc3VtaWRhcykNCg0KRW4gcmVzdW1lbjoNCg0KNi4gTG9zIHZhbG9yZXMgZGUgY29zZW5vcyBhbCBjdWFkcmFkbyBzZSB1dGlsaXphbiBwYXJhIGVzdGltYXIgbGEgY2FsaWRhZCBkZSBsYSByZXByZXNlbnRhY2nDs24uDQoNCjcuIEN1YW50byBtw6FzIGNlcmNhIGVzdMOpIHVuYSB2YXJpYWJsZSBkZWwgY8OtcmN1bG8gZGUgY29ycmVsYWNpb25lcywgbWVqb3Igc2Vyw6Egc3UgcmVwcmVzZW50YWNpw7NuIGVuIGVsIG1hcGEgZmFjdG9yaWFsICh5IG3DoXMgaW1wb3J0YW50ZSBzZXLDoSBpbnRlcnByZXRhciBlc3RhcyBjb21wb25lbnRlcykuDQoNCjguIExhcyB2YXJpYWJsZXMgcXVlIGVzdMOhbiBjZXJjYSBkZWwgY2VudHJvIGRlbCBncsOhZmljbyBzb24gbWVub3MgaW1wb3J0YW50ZXMgcGFyYSBsYXMgcHJpbWVyYXMgY29tcG9uZW50ZXMuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYHZhciRjb3MyYCAoYXJndW1lbnRvIGBncmFkaWVudC5jb2xzYCkNCg0KRXMgcG9zaWJsZSBjb2xvcmVhciBsYXMgdmFyaWFibGVzIHNlZ8O6biBzdXMgdmFsb3JlcyBgY29zMmAgdXRpbGl6YW5kbyBlbCBhcmd1bWVudG8gYGNvbC52YXIgPSAiY29zMiJgLiBFc3RvIHByb2R1Y2UgY29sb3JlcyBkZWdyYWRhZG9zLiBFbiBlc3RlIGNhc28sIHNlIHB1ZWRlIHV0aWxpemFyIGVsIGFyZ3VtZW50byBgZ3JhZGllbnQuY29sYCBwYXJhIHByb3BvcmNpb25hciB1biBjb2xvciBwZXJzb25hbGl6YWRvLiANCg0KUG9yIGVqZW1wbG8sIGBncmFkaWVudC5jb2xzID0gYygiZ3JlZW4iLCAiYnJvd24iLCAiYmx1ZSIpYCBzaWduaWZpY2EgcXVlOg0KDQoxLiBMYXMgdmFyaWFibGVzIGNvbiB2YWxvcmVzIGJham9zIGRlIGBjb3MyYCBzZXLDoW4gY29sb3JlYWRhcyBlbiAqdmVyZGUqLg0KDQoyLiBMYXMgdmFyaWFibGVzIGNvbiB2YWxvcmVzIG1lZGlvcyBkZSBgY29zMmAgc2Vyw6FuIGNvbG9yZWFkYXMgZW4gKm1hcnLDs24qLg0KDQozLiBMYXMgdmFyaWFibGVzIGNvbiB2YWxvcmVzIGFsdG9zIGRlIGBjb3MyYCBzZXLDoW4gY29sb3JlYWRhcyBlbiAqYXp1bCouDQoNCg0KYGBge3J9DQojQ29sb3IgcG9yIHZhbG9yZXMgY29zMjogY2FsaWRhZCBzb2JyZSBlbCBtYXBhIGZhY3RvcmlhbA0KZnZpel9wY2FfdmFyKHJlcy5wY2EsIGNvbC52YXIgPSAiY29zMiIsDQogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoImdyZWVuIiwgImJyb3duIiwgImJsdWUiKSwNCiAgICAgICAgICAgICB0aXRsZT0iR3JhZGllbnRlIGRlIGxhcyB2YXJpYWJsZXMgcG9yIGNvczIiLA0KICAgICAgICAgICAgIHJlcGVsID0gVFJVRSAjIEV2aXRhIHRyYXNsYXBhbWllbnRvIGRlIHRleHRvcw0KICAgICAgICAgICAgICkNCmBgYA0KDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGB2YXIkY29zMmAgKHRyYW5zcGFyaWVuY2lhcyBjb24gYGFscGhhLnZhcmApDQoNClRhbWJpw6luIGVzIHBvc2libGUgYWp1c3RhciBsYSB0cmFuc3BhcmVuY2lhIGRlIGxhcyB2YXJpYWJsZXMgc2Vnw7puIGxvcyB2YWxvcmVzIGRlIGBjb3MyYCB1dGlsaXphbmRvIGxhIG9wY2nDs24gYGFscGhhLnZhciA9ICJjb3MyImA6IA0KDQpgYGB7cn0NCiMgQ2FtYmlhciBsYSB0cmFuc3BhcmllbmNpYSBwb3IgdmFsb3JlcyBkZSBjb3MyDQpmdml6X3BjYV92YXIocmVzLnBjYSwgYWxwaGEudmFyID0gImNvczIiLA0KICAgICAgICAgICAgIGNvbC52YXIgPSAicmVkIiwNCiAgICAgICAgICAgICB0aXRsZT0iVHJhbnNwYXJpZW5jaWEgZGUgbGFzIHZhcmlhYmxlcyBwb3IgY29zMiIsDQogICAgICAgICAgICAgcmVwZWwgPSBUUlVFICMgRXZpdGEgdHJhc2xhcGFtaWVudG8gZGUgdGV4dG9zDQogICAgICAgICAgICAgKQ0KYGBgDQoNCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEVqZW1wbG86IFNvbHVjacOzbiAoYHZhciRjb250cmliYCkgIA0KICANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGB2YXIkY29udHJpYmAgKGdlbmVyYWwpDQoNCkxhcyBjb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGEgbGEgdmFyaWFiaWxpZGFkIGRlIHVuIGNvbXBvbmVudGUgcHJpbmNpcGFsIGRldGVybWluYWRvIHNlIGV4cHJlc2FuIGVuIHBvcmNlbnRhamUuIEVuIGVzdGUgc2VudGlkbzogDQogIA0KICArIExhcyB2YXJpYWJsZXMgcXVlIGVzdMOhbiBjb3JyZWxhY2lvbmFkYXMgY29uIFBDMSAoZXMgZGVjaXIsIERpbS4xKSB5IFBDMiAoZXMgZGVjaXIsIERpbS4yKSBzb24gbGFzIG3DoXMgaW1wb3J0YW50ZXMgcGFyYSBleHBsaWNhciBsYSB2YXJpYWJpbGlkYWQgZGVsIGNvbmp1bnRvIGRlIGRhdG9zLg0KICANCiAgKyBMYXMgdmFyaWFibGVzIHF1ZSBubyBzZSBjb3JyZWxhY2lvbmFuIGNvbiBuaW5nw7puIFBDIG8gc2UgY29ycmVsYWNpb25hbiBjb24gbGFzIMO6bHRpbWFzIGRpbWVuc2lvbmVzICBzb24gdmFyaWFibGVzIGNvbiBlc2Nhc2EgY29udHJpYnVjacOzbiB5IHB1ZWRlbiBlbGltaW5hcnNlIHBhcmEgc2ltcGxpZmljYXIgZWwgYW7DoWxpc2lzIGdlbmVyYWwuDQogIA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGB2YXIkY29udHJpYmAgKGVuIFIpDQoNCkxhIGNvbnRyaWJ1Y2nDs24gZGUgbGFzIHZhcmlhYmxlcyBwdWVkZSBleHRyYWVyc2UgZGUgbGEgc2lndWllbnRlIG1hbmVyYSA6DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KdmFyJGNvbnRyaWINCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmthYmxlKHZhciRjb250cmliLCBhbGlnbiA9ICJjY2MiKSAlPiUjIFNlIG5lY2VzaXRhIGxpYnJhcnkoa25pdHIpIA0Ka2FibGVfc3R5bGluZygpICU+JSAgICAgICAgICAgICAgICAjbGlicmFyeShrYWJsZUV4dHJhKS4uLi4gU29sbyBwYXJhIGtuaXQgdG8gaHRtbA0Ka2FibGVfY2xhc3NpY18yKGZ1bGxfd2lkdGggPSBGKSAgICNsaWJyYXJ5KGthYmxlRXh0cmEpLi4uLlNvbG8gcGFyYSBrbml0IHRvIGh0bWwNCmBgYA0KDQoNCkN1YW50byBtYXlvciBzZWEgZWwgdmFsb3IgZGUgbGEgY29udHJpYnVjacOzbiwgbcOhcyBjb250cmlidXllIGxhIHZhcmlhYmxlIGFsIGNvbXBvbmVudGUuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYHZhciRjb250cmliYCAoY29ycmVsYWNpb25lcykNCg0KRXMgcG9zaWJsZSB1dGlsaXphciBsYSBmdW5jacOzbiBgY29ycnBsb3RgIGRlbCBwYXF1ZXRlIGBjb3JycGxvdGAgcGFyYSByZXNhbHRhciBsYXMgdmFyaWFibGVzIHF1ZSBtw6FzIGNvbnRyaWJ1eWVuIHBhcmEgY2FkYSBkaW1lbnNpw7NuLg0KDQpgYGB7cn0NCmNvcnJwbG90KHZhciRjb250cmliLCANCiAgICAgICAgIGlzLmNvcnI9RkFMU0UsICAgDQogICAgICAgICB0bC5jb2wgPSAiYmxhY2siLCANCiAgICAgICAgICNhZGRDb2VmLmNvbCA9ICdncmV5NTAnLCAjQWdyZWdhciB2YWxvcmVzDQogICAgICAgICAjbnVtYmVyLmNleCA9IDAuNywgICAgICAgI1RhbWHDsW8gZGUgbG9zIHZhbG9yZXMNCiAgICAgICAgIHRsLnNydCA9IDkwLCANCiAgICAgICAgIGJnID0gImxpZ2h0Ymx1ZSIsICAgICAgICAjQ29sb3IgZGVsIGZvbmRvDQogICAgICAgICB0aXRsZT0iTWF0cml6IGRlIGNvcnJlbGFjaW9uZXMiLCANCiAgICAgICAgICN0bC5jZXg9MS41LCAgICAgICAgICAgICNUYW1hw7FvIGRlIGxhcyB2YXJzIHkgRGltcw0KICAgICAgICAgI2NleC5tYWluPTIuMCwgICAgICAgICAgI1RhbWHDsW8gZGVsIHTDrXR1bG8NCiAgICAgICAgICN0eXBlPSJsb3dlciIsDQogICAgICAgICBtYXI9YygwLDAsNCwwKSAgICAgICAgICAjVWJpY2FjacOzbiBkZWwgdMOtdHVsbw0KICAgICAgICAgKQ0KYGBgDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgdmFyJGNvbnRyaWJgIChkaWFncmFtYXMgZGUgYmFycmEgZGUgY2FkYSB2YXJpYWJsZSkNCg0KDQpMYSBmdW5jacOzbiBgZnZpel9jb250cmliYCBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAgc2UgcHVlZGUgZW1wbGVhciBwYXJhIGRpYnVqYXIgdW4gZ3LDoWZpY28gZGUgYmFycmFzIGRlIGxhcyBjb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzLiBTaSBsb3MgZGF0b3MgY29udGllbmVuIG11Y2hhcyB2YXJpYWJsZXMsIHNlIHB1ZWRlIG9wdGFyIHBvciBtb3N0cmFyIHNvbG8gbGFzIHZhcmlhYmxlcyBxdWUgbcOhcyBjb250cmlidXllbi4gRWwgc2lndWllbnRlIGPDs2RpZ28gZW4gUiBtdWVzdHJhIGxhcyAxMCB2YXJpYWJsZXMgcHJpbmNpcGFsZXMgcXVlIGNvbnRyaWJ1eWVuIGEgbG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLg0KDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBDb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGEgUEMxDQpwMSA8LSBmdml6X2NvbnRyaWIocmVzLnBjYSwgY2hvaWNlID0gInZhciIsIGF4ZXMgPSAxLCB0b3AgPSAxMCkNCg0KIyBDb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGEgUEMyDQpwMiA8LSBmdml6X2NvbnRyaWIocmVzLnBjYSwgY2hvaWNlID0gInZhciIsIGF4ZXMgPSAyLCB0b3AgPSAxMCkNCg0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBDb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGEgUEMxDQpwMSA8LSBmdml6X2NvbnRyaWIocmVzLnBjYSwgY2hvaWNlID0gInZhciIsIGF4ZXMgPSAxLCB0b3AgPSAxMCkgDQoNCiMgQ29udHJpYnVjaW9uZXMgZGUgbGFzIHZhcmlhYmxlcyBhIFBDMg0KcDIgPC0gZnZpel9jb250cmliKHJlcy5wY2EsIGNob2ljZSA9ICJ2YXIiLCBheGVzID0gMiwgdG9wID0gMTApDQoNCmxpYnJhcnkoZ3JpZEV4dHJhKSANCg0KZ3JpZC5hcnJhbmdlKHAxLHAyLCBuY29sPTIsIG5yb3cgPTEpDQpgYGANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGB2YXIkY29udHJpYmAgKGRpYWdyYW1hIGRlIGJhcnJhIHBhcmEgZWwgdG90YWwpDQoNCg0KQSBjb250aW51YWNpw7NuLCBzZSBwdWVkZSB2aXN1YWxpemFyIGxhIGNvbnRyaWJ1Y2nDs24gdG90YWwgYSBQQzEgeSBQQzI6IA0KDQpgYGB7cn0NCmZ2aXpfY29udHJpYihyZXMucGNhLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDE6MiwgdG9wID0gMTApDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgdmFyJGNvbnRyaWJgIChJbnRlcnByZXRhY2lvbmVzKSANCg0KKipJbnRlcnByZXRhY2nDs24gTm8uIDE6ICoqDQoNCkxhIGzDrW5lYSByb2phIGRpc2NvbnRpbnVhIGVuIGVsIGdyw6FmaWNvIGFudGVyaW9yIGluZGljYSBsYSBjb250cmlidWNpw7NuIHByb21lZGlvIGVzcGVyYWRhLiANCg0KKipJbnRlcnByZXRhY2nDs24gTm8uIDI6ICoqDQogIA0KU2kgbGEgY29udHJpYnVjacOzbiBkZSBsYXMgdmFyaWFibGVzIGZ1ZXNlIHVuaWZvcm1lLCBlbCB2YWxvciBlc3BlcmFkbyBzZXLDrWEgDQogIA0KICAkJFxmcmFjezF9e1xtYm94e2xvbmdpdHVkKHZhcmlhYmxlcyl9fSBcOz1cOyBcZnJhY3sxfXsxMH0oMTAwKVw7PVw7IDEwXCwgXCUkJA0KICANCiAgYGBge3J9DQogICgxL2xlbmd0aChkYXQpKSoxMDANCiAgYGBgDQoqKkludGVycHJldGFjacOzbiBOby4gMzogKioNCg0KUGFyYSB1biBjb21wb25lbnRlIGRhZG8sIHVuYSB2YXJpYWJsZSBjb24gdW5hIGNvbnRyaWJ1Y2nDs24gbWF5b3IgcXVlIGVzdGUgdW1icmFsIHBvZHLDrWEgY29uc2lkZXJhcnNlIGltcG9ydGFudGUgZW4gbGEgY29udHJpYnVjacOzbiBhbCBjb21wb25lbnRlLiANCiAgDQogIA0KKipJbnRlcnByZXRhY2nDs24gTm8uIDQ6ICoqDQoNClNlIGRlYmUgdGVuZXIgZW4gY3VlbnRhIHF1ZSBsYSBjb250cmlidWNpw7NuIHRvdGFsIGRlIHVuYSB2YXJpYWJsZSBkYWRhLCBlbiBsYSBleHBsaWNhY2nDs24gZGUgbGFzIHZhcmlhY2lvbmVzIHJldGVuaWRhcyBwb3IgZG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLCBkaWdhbW9zIFBDMSB5IFBDMiwgc2UgY2FsY3VsYSBjb21vIA0KICANCiAgDQogICQkIFxtYm94e0NvbnRyaWJ9ID0gXGZyYWN7Q18xIFwsIFxsYW1iZGFfMSBcOyArXDsgIENfMiBcLCAgXGxhbWJkYV8yfXtcbGFtYmRhXzEgXDsrXDsgIFxsYW1iZGFfMn0kJA0KICANCiAgZG9uZGU6DQogICAgDQogICArICRDXzEkIHkgJENfMiQgc29uIGxhcyBjb250cmlidWNpb25lcyBkZSBsYSB2YXJpYWJsZSBlbiBQQzEgeSBQQzIsIHJlc3BlY3RpdmFtZW50ZS4NCiAgICANCiAgICsgJFxsYW1iZGFfMSQgeSAkXGxhbWJkYV8yJCBzb24gbG9zIGVpZ2VudmFsb3JlcyBkZSBQQzEgeSBQQzIsIHJlc3BlY3RpdmFtZW50ZS4gDQogICAgDQogIA0KKipJbnRlcnByZXRhY2nDs24gTm8uIDU6ICoqDQoNClJlY29yZGFyIHF1ZSBsb3MgZWlnZW52YWxvcmVzIG1pZGVuIGxhIGNhbnRpZGFkIGRlIHZhcmlhY2nDs24gcmV0ZW5pZGEgcG9yIGNhZGEgUEMuIEVuIGVzdGUgY2FzbywgbGEgY29udHJpYnVjacOzbiBwcm9tZWRpbyBlc3BlcmFkYSAodW1icmFsKSBzZSBjYWxjdWxhIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6IENvbW8gc2UgbWVuY2lvbsOzIGFudGVyaW9ybWVudGUsIHNpIGxhcyBjb250cmlidWNpb25lcyBkZSBsYXMgMTAgdmFyaWFibGVzIGZ1ZXJhbiB1bmlmb3JtZXMsIGxhIGNvbnRyaWJ1Y2nDs24gcHJvbWVkaW8gZXNwZXJhZGEgZGUgdW5hIHZhcmlhYmxlIHBhcmEgUEMxIHkgUEMyIGVzOiANCiAgDQogICQkIFxtYm94e0NvbnRyaWJ9IFw7ID1cOyAgXGZyYWN7MTAgXCwgXGxhbWJkYV8xIFw7ICtcOyAgMTAgXCwgIFxsYW1iZGFfMn17XGxhbWJkYV8xIFw7K1w7ICBcbGFtYmRhXzJ9XDsgPVw7IDEwJCQNCiAgDQogIA0KU2UgcHVlZGUgb2JzZXJ2YXIgcXVlIGxhIHZhcmlhYmxlIGBFeGFtQWN1bWAgY29udHJpYnV5ZW4gbcOhcyBhIGxhcyBkaW1lbnNpb25lcyAxIHkgMi4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGB2YXIkY29udHJpYmAgKGPDrXJjdWxvIGRlIGNvcnJlbGFjaW9uZXMpIA0KDQpMYXMgdmFyaWFibGVzIG3DoXMgaW1wb3J0YW50ZXMgcHVlZGVuIHNlciByZXNhbHRhZGFzIGVuIGVsIGdyw6FmaWNvIGRlIGNvcnJlbGFjacOzbiBkZSBsYSBzaWd1aWVudGUgbWFuZXJhOg0KDQpgYGB7cn0NCmZ2aXpfcGNhX3ZhcihyZXMucGNhLCBjb2wudmFyID0gImNvbnRyaWIiLCANCiAgICAgICAgICAgICByZXBlbD0gVFJVRSwgIyBFdml0YSB0cmFzbGFwYW1pZW50byBkZSB0ZXh0b3MsDQogICAgICAgICAgICAgKQ0KDQpgYGANCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYHZhciRjb250cmliYCAoYXJndW1lbnRvIGBncmFkaWVudC5jb2xzYCkNCg0KQ29tbyB5YSBzZSBleHBsaWPDsywgYGdyYWRpZW50LmNvbHMgPSBjKCJncmVlbiIsICJicm93biIsICJibHVlIilgIHNpZ25pZmljYSBxdWU6DQoNCjEuIExhcyB2YXJpYWJsZXMgY29uIHZhbG9yZXMgYmFqb3MgZGUgYGNvczJgIHNlcsOhbiBjb2xvcmVhZGFzIGVuICp2ZXJkZSouDQoNCjIuIExhcyB2YXJpYWJsZXMgY29uIHZhbG9yZXMgbWVkaW9zIGRlIGBjb3MyYCBzZXLDoW4gY29sb3JlYWRhcyBlbiAqbWFycsOzbiouDQoNCjMuIExhcyB2YXJpYWJsZXMgY29uIHZhbG9yZXMgYWx0b3MgZGUgYGNvczJgIHNlcsOhbiBjb2xvcmVhZGFzIGVuICphenVsKi4NCg0KDQpgYGB7cn0NCmZ2aXpfcGNhX3ZhcihyZXMucGNhLCBjb2wudmFyID0gImNvbnRyaWIiLCANCiAgICAgICAgICAgICByZXBlbD0gVFJVRSwgIyBFdml0YSB0cmFzbGFwYW1pZW50byBkZSB0ZXh0b3MsDQogICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9IGMoImdyZWVuIiwgImJyb3duIiwgImJsdWUiKSwNCiAgICAgICAgICAgICApDQoNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGB2YXIkY29udHJpYmAgKHRyYW5zcGFyaWVuY2lhcyBjb24gYGFscGhhLnZhcmApDQoNClRlbmdhIGVuIGN1ZW50YSBxdWUgdGFtYmnDqW4gZXMgcG9zaWJsZSBjYW1iaWFyIGxhIHRyYW5zcGFyZW5jaWEgZGUgbGFzIHZhcmlhYmxlcyBzZWfDum4gc3VzIHZhbG9yZXMgZGUgY29udHJpYnVjacOzbiB1dGlsaXphbmRvIGxhIG9wY2nDs24gYGFscGhhLnZhciA9ICJjb250cmliImA6DQoNCmBgYHtyfQ0KIyBDYW1iaWFyIGxhIHRyYW5zcGFyaWVuY2lhIHBhcmEgbGFzIGNvbnRyaWJ1Y2lvbmVzDQpmdml6X3BjYV92YXIocmVzLnBjYSwgYWxwaGEudmFyID0gImNvbnRyaWIiLA0KICAgICAgICAgICAgIGNvbC52YXIgPSAicmVkIiwNCiAgICAgICAgICAgICAjdGl0bGU9IlRyYW5zcGFyaWVuY2lhIGRlIGxhcyB2YXJpYWJsZXMgcG9yIGNvbnRyaWJ1Y2nDs24iLCANCiAgICAgICAgICAgICByZXBlbD0gVFJVRSAjIEV2aXRhIHRyYXNsYXBhbWllbnRvIGRlIHRleHRvcywNCiAgICAgICAgICAgICApDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgdmFyJGNvbnRyaWJgIChjw61yY3VsbyBwb3IgdmFyaWFibGUgY29udGludWEpDQoNCkVuIGxhcyBzZWNjaW9uZXMgYW50ZXJpb3JlcywgZGVtb3N0cmFtb3MgY8OzbW8gY29sb3JlYXIgdmFyaWFibGVzIHNlZ8O6biBzdXMgY29udHJpYnVjaW9uZXMgeSBzdSBjb3Nlbm8gYWwgY3VhZHJhZG8uIEVzIGltcG9ydGFudGUgZGVzdGFjYXIgcXVlIHRhbWJpw6luIGVzIHBvc2libGUgY29sb3JlYXIgdmFyaWFibGVzIHNlZ8O6biBjdWFscXVpZXIgdmFyaWFibGUgY29udGludWEgcGVyc29uYWxpemFkYS4gTGEgdmFyaWFibGUgZGUgY29sb3JhY2nDs24gZGViZSB0ZW5lciBsYSBtaXNtYSBsb25naXR1ZCBxdWUgZWwgbsO6bWVybyBkZSB2YXJpYWJsZXMgYWN0aXZhcyBlbiBlbCBBQ1AgKGFxdcOtLCAkbj0kYHIgbmNvbChkYXQpYC4gRWplbXBsbzogDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSByYW5kb20gY29udGludW91cyB2YXJpYWJsZSBvZiBsZW5ndGggMTANCnNldC5zZWVkKDEyMykNCm15LmNvbnQudmFyIDwtIHJub3JtKDEwKQ0KDQojIENvbG9yIHZhcmlhYmxlcyBieSB0aGUgY29udGludW91cyB2YXJpYWJsZQ0KZnZpel9wY2FfdmFyKHJlcy5wY2EsIGNvbC52YXIgPSBteS5jb250LnZhciwNCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiZ3JlZW4iLCAiYnJvd24iLCAiYmx1ZSIpLA0KICAgICAgICAgICAgIHJlcGVsPVRSVUUsIA0KICAgICAgICAgICAgIHRpdGxlPSJDb3JyZWxhY2lvbmVzIGVudHJlIGxhcyB2YXJpYWJsZXMgcG9yIHZhcmlhYmxlIGNvbnRpbnVhIiwgDQogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gIkNvbnRpbnVhIg0KICAgICAgICAgICAgICkNCmBgYA0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgdmFyJGNvbnRyaWJgIChjw61yY3VsbyBkZSBjb3JyZWxhY2lvbmVzIHBvciBncnVwb3MpDQoNCg0KVGFtYmnDqW4gZXMgZmFjdGlibGUgYWx0ZXJhciBlbCBjb2xvciBkZSBsYXMgdmFyaWFibGVzIGJhc8OhbmRvc2UgZW4gZ3J1cG9zIGRlZmluaWRvcyBwb3IgdW5hIHZhcmlhYmxlICpjdWFsaXRhdGl2YSogbyAqY2F0ZWfDs3JpY2EqIChjb23Dum5tZW50ZSBjb25vY2lkYSBjb21vICpmYWN0b3IqIGVuIFIpLiBEYWRvIHF1ZSBubyBkaXNwb25lbW9zIGRlIG5pbmd1bmEgdmFyaWFibGUgZGUgYWdydXBhY2nDs24gZW4gbnVlc3Ryb3MgY29uanVudG9zIGRlIGRhdG9zIHBhcmEgY2xhc2lmaWNhciBsYXMgdmFyaWFibGVzLCBvcHRhcmVtb3MgcG9yIGNyZWFyIHVuYS4gRW4gZWwgc2lndWllbnRlIGVqZW1wbG8gcHLDoWN0aWNvLCBpbmljaWFsbWVudGUgY2xhc2lmaWNhbW9zIGxhcyB2YXJpYWJsZXMgZW4gdHJlcyBncnVwb3MgbWVkaWFudGUgZWwgKmFsZ29yaXRtbyBkZSBhZ3J1cGFjacOzbiBrbWVhbnMqIChlbiBvdHJvcyBkb2N1bWVudG9zIHNlIGV4cGxpY2EgZXN0YSB0ZW9yw61hKS4gUG9zdGVyaW9ybWVudGUsIGVtcGxlYW1vcyBsb3MgY2zDunN0ZXJlcyBvYnRlbmlkb3MgbWVkaWFudGUgZWwgKmFsZ29yaXRtbyBrbWVhbnMqIHBhcmEgYXNpZ25hciBjb2xvcmVzIGEgbGFzIHZhcmlhYmxlcy4gUGFyYSBtw6FzIGRldGFsbGVzIHNvYnJlIGNsdXN0ZXJpbmcsIHB1ZWRlIGNvbnN1bHRhcnNlICBsYSBiaWJsaW9ncmFmw61hIHJlY29tZW5kYWRhLg0KDQoNCmBgYHtyfQ0KIyBDcmVhciB1bmEgdmFyaWFibGUgZ3J1cGFsIGNvbiBrbWVhbnMNCiMgQ3JlYXIgMyBjbMO6c3RlciAoY2VudGVycyA9IDMpDQpzZXQuc2VlZCgxMjMpDQpyZXMua20gPC0ga21lYW5zKHZhciRjb29yZCwgY2VudGVycyA9IDMsIG5zdGFydCA9IDI1KQ0KDQojIEV4dHJhZXIgZXRpcXVldGFzIGRlIGxvcyBjbMO6c3RlciANCmdycCAgIDwtIGFzLmZhY3RvcihyZXMua20kY2x1c3RlcikNCmdycA0KYGBgDQoNCkVsIGPDrXJjdWxvIGRlIGNvcnJlbGFjaW9uZXMgcG9yIGdydXBvcyBlcyBlbCBzaWd1aWVudGU6IA0KDQoNCmBgYHtyfQ0KIyBDb2xvcmVzIGRlIGxhcyB2YXJpYWJsZXMgcG9yIGdydXBvcw0KZnZpel9wY2FfdmFyKHJlcy5wY2EsIGNvbC52YXIgPSBncnAsIA0KICAgICAgICAgICAgIHBhbGV0dGUgPSBjKCJibHVlIiwgImJyb3duIiwgImdyZWVuIiksDQogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gIkNsdXN0ZXIiLA0KICAgICAgICAgICAgIHRpdGxlPSJDb3JyZWxhY2lvbmVzIGVudHJlIGxhcyB2YXJpYWJsZXMgcG9yIGdydXBvcyIsIA0KICAgICAgICAgICAgIHJlcGVsPSBUUlVFICMgRXZpdGEgdHJhc2xhcGFtaWVudG8gZGUgdGV4dG9zDQogICAgICAgICAgICAgKQ0KYGBgDQoNCg0KRXMgaW1wb3J0YW50ZSB0ZW5lciBlbiBjdWVudGEgcXVlOiANCiAgDQogIDEuIFNpIGRlc2VhbW9zIG1vZGlmaWNhciBsb3MgY29sb3JlcyBkZSBsb3MgZ3J1cG9zLCBkZWJlbW9zIGVtcGxlYXIgZWwgcGFyw6FtZXRybyBgcGFsZXR0ZWAuIA0KICANCiAgMi4gUGFyYSBhanVzdGFyIGxvcyBjb2xvcmVzIGRlIGxvcyBncmFkaWVudGVzLCBlcyBuZWNlc2FyaW8gdXRpbGl6YXIgZWwgcGFyw6FtZXRybyBgZ3JhZGllbnQuY29sc2AuIE3DoXMgYWRlbGFudGUsIHNlIHByZXNlbnRhIHVuIGVqZW1wbG8gdXRpbGl6YW5kbyBlc3RlIGFyZ3VtZW50by4gDQogIA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGB2YXIkY29udHJpYmAgKGZ1bmNpw7NuIGBkaW1kZXNjYCkgDQoNCkFudGVyaW9ybWVudGUgc2UgZXhwbGljw7MgY8OzbW8gZGVzdGFjYXIgbGFzIHZhcmlhYmxlcyBlbiBmdW5jacOzbiBkZSBzdSBjb250cmlidWNpw7NuIGEgbG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLiANCg0KTGEgZnVuY2nDs24gYGRpbWRlc2NgIGVuIGBGYWN0b01pbmVSYCBwdWVkZSBzZXIgZW1wbGVhZGEgcGFyYSBpZGVudGlmaWNhciBsYXMgdmFyaWFibGVzIG3DoXMgcmVsZXZhbnRlbWVudGUgdmluY3VsYWRhcyBhIHVuIGNvbXBvbmVudGUgcHJpbmNpcGFsIGVzcGVjw61maWNvLiBFc3RlIGVuZm9xdWUgcmVzdWx0YSDDunRpbCBwYXJhIGRldGVybWluYXIgbGEgYXNvY2lhY2nDs24gc2lnbmlmaWNhdGl2YSBlbnRyZSBsYXMgdmFyaWFibGVzIHkgdW4gY29tcG9uZW50ZSBwcmluY2lwYWwgZGFkbywgeSBwdWVkZSBzZXIgdXRpbGl6YWRvIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQoNCmBgYHtyfQ0KcmVzLmRlc2MgPC0gZGltZGVzYyhyZXMucGNhLCBheGVzID0gYygxLDIpLCBwcm9iYSA9IDAuMDUpDQojIERlc2NyaXBjacOzbiBkZSBsYSBkaW1lbnNpw7NuIDENCnJlcy5kZXNjJERpbS4xDQpgYGANCmBgYHtyfQ0KIyBEZXNjcmlwY2nDs24gZGUgbGEgZGltZW5zacOzbiAyDQpyZXMuZGVzYyREaW0uMg0KYGBgDQoNCkVuIGxhcyBzYWxpZGEgYW50ZXJpb3JlcywgY3VhbmRvIHNhbGUgYCRxdWFudGlgLCBpbmRpY2EgcmVzdWx0YWRvcyBwYXJhIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzLiBFcyBpbXBvcnRhbnRlIGRlc3RhY2FyIHF1ZSBsYXMgdmFyaWFibGVzIGVzdMOhbiBvcmRlbmFkYXMgc2Vnw7puIGVsICRwJC12YWxvciBkZSBsYSBjb3JyZWxhY2nDs24uDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgZ2V0X3BjYV9pbmRgKSAgDQogIA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGluZGAgKGdyw6FmaWNvcyBkZSByZXN1bHRhZG9zKQ0KDQoNCkxvcyByZXN1bHRhZG9zIHBhcmEgaW5kaXZpZHVvcyBwdWVkZW4gc2VyIG9idGVuaWRvcyB1dGlsaXphbmRvIGxhIGZ1bmNpw7NuIGBnZXRfcGNhX2luZGAgZGVsIHBhcXVldGUgYGZhY3RvZXh0cmFgLiBEZSBtYW5lcmEgc2ltaWxhciBhIGBnZXRfcGNhX3ZhcmAsIGxhIGZ1bmNpw7NuIGBnZXRfcGNhX2luZGAgcHJvcG9yY2lvbmEgdW5hIGxpc3RhIGRlIG1hdHJpY2VzIHF1ZSBjb250aWVuZW4gdG9kb3MgbG9zIHJlc3VsdGFkb3MgcGFyYSBsb3MgaW5kaXZpZHVvcyAoY29vcmRlbmFkYXMsIGNvcnJlbGFjacOzbiBlbnRyZSB2YXJpYWJsZXMgeSBlamVzLCBjb3Nlbm9zIGFsIGN1YWRyYWRvIHkgY29udHJpYnVjaW9uZXMpLg0KDQpgYGB7cn0NCmluZCA8LSBnZXRfcGNhX2luZChyZXMucGNhKQ0KaW5kDQpgYGANCg0KUGFyYSBhY2NlZGVyIGEgbGFzIGRpZmVyZW50ZXMgY29tcG9uZW50ZXM6IA0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgQ29vcmRlbmFkYXMgZGUgbG9zIGluZGl2aWR1b3MNCmluZCRjb29yZA0KDQojIENhbGlkYWQgZGUgbG9zIGluZGl2aWR1b3MNCmluZCRjb3MyDQoNCiMgQ29udHJpYnVjaW9uZXMgZGUgbG9zIGluZGl2aWR1b3MNCmluZCRjb250cmliDQpgYGANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBpbmRgIChncsOhZmljbyBzaW1wbGUpDQoNCg0KU2UgdXRpbGl6YSBsYSBmdW5jacOzbiBgZnZpel9wY2FfaW5kYCBwYXJhIHByb2R1Y2lyIGVsIGdyw6FmaWNvIGRlIGluZGl2aWR1b3M6IA0KDQpgYGB7cn0NCmZ2aXpfcGNhX2luZChyZXMucGNhLA0KICAgICAgICAgICAgIHRpdGxlPSJJbmRpdmlkdW9zIg0KICAgICAgICAgICAgICkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBpbmRgOiBncsOhZmljbyBzZWfDum4gYGNvczJgDQoNCg0KU2UgcHVlZGUgY29sb3JlYXIgYSBsb3MgaW5kaXZpZHVvcyBzZWfDum4gc3VzIHZhbG9yZXMgZGUgYGNvczJgIChhbCBpZ3VhbCBxdWUgc2UgaGFjZSBjb24gbGFzIHZhcmlhYmxlcykuDQoNCg0KYGBge3J9DQpmdml6X3BjYV9pbmQocmVzLnBjYSwgY29sLmluZCA9ICJjb3MyIiwNCiAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gYygiYmx1ZSIsICJicm93biIsICJncmVlbiIpLA0KICAgICAgICAgICAgIHRpdGxlPSJJbmRpdmlkdW9zIGRlIGFjdWVyZG8gYSBjb3MyIiwgDQogICAgICAgICAgICAgcmVwZWw9IFRSVUUgIyBFdml0YSB0cmFzbGFwYW1pZW50byBkZSB0ZXh0b3MNCiAgICAgICAgICAgICApDQpgYGANCk9ic8OpcnZlc2UgcXVlIGVuIGVsIGdyw6FmaWNvLCBsYXMgcGVyc29uYXMgc2ltaWxhcmVzIHNlIGFncnVwYW4ganVudGFzLg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBpbmRgICh0YW1hw7FvIGRlbCBwdW50byBzZWfDum4gYGNvczJgKQ0KDQpTZSBwdWVkZSBhanVzdGFyIHRhbWJpw6luIGVsIHRhbWHDsW8gZGVsIHB1bnRvIGRlIGFjdWVyZG8gYWwgY29zMiBkZSBsb3MgaW5kaXZpZHVvcyBjb3JyZXNwb25kaWVudGVzLg0KDQpgYGB7cn0NCmZ2aXpfcGNhX2luZChyZXMucGNhLCBwb2ludHNpemUgPSAiY29zMiIsDQogICAgICAgICAgICAgcG9pbnRzaGFwZSA9IDIxLCANCiAgICAgICAgICAgICBmaWxsID0gInJlZCIsDQogICAgICAgICAgICAgcmVwZWwgPSBUUlVFICMgRXZpdGEgdHJhc2xhcGFtaWVudG8gZGUgdGV4dG9zDQogICAgICAgICAgICAgKQ0KYGBgDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBpbmRgICh0YW1hw7FvIGRlbCBwdW50byB5IGdyYWRpZW50IHNlZ8O6biBgY29zMmApDQoNClBhcmEgY2FtYmlhciB0YW50byBlbCB0YW1hw7FvIGRsIHB1bnRvIGNvbW8gZWwgY29sb3IgcG9yIGBjb3MyYDoNCg0KYGBge3J9DQpmdml6X3BjYV9pbmQocmVzLnBjYSwgY29sLmluZCA9ICJjb3MyIiwgcG9pbnRzaXplID0gImNvczIiLA0KICAgICAgICAgICAgIGdyYWRpZW50LmNvbHMgPSBjKCJibHVlIiwgImJyb3duIiwgImdyZWVuIiksDQogICAgICAgICAgICAgcmVwZWwgPSBUUlVFICMgRXZpdGEgdHJhc2xhcGFtaWVudG8gZGUgdGV4dG9zDQogICAgICAgICAgICAgKQ0KYGBgDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgaW5kYCAoZGlhZ3JhbWEgZGUgY29udHJpYnVjacOzbiBhIHVuIGNvbXBvbmVudGUpDQoNClBhcmEgZ2VuZXJhciB1biBncsOhZmljbyBkZSBiYXJyYXMgZGUgbGEgY2FsaWRhZCBkZSByZXByZXNlbnRhY2nDs24gKGBjb3MyYCkgZGUgbG9zIGluZGl2aWR1b3MgZW4gZWwgbWFwYSBmYWN0b3JpYWwsIHNlIHB1ZWRlIGVtcGxlYXIgbGEgZnVuY2nDs24gYGZ2aXpfY29zMmAgY29tbyBzZSBoYSBkZXNjcml0byBwcmV2aWFtZW50ZSBwYXJhIGxhcyB2YXJpYWJsZXM6DQoNCmBgYHtyfQ0KZnZpel9jb3MyKHJlcy5wY2EsIGNob2ljZSA9ICJpbmQiKQ0KYGBgDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBpbmRgIChkaWFncmFtYSBkZSBjb250cmlidWNpw7NuIGEgZG9zIGNvbXBvbmVudGVzKQ0KDQpQYXJhIHZpc3VhbGl6YXIgbGEgY29udHJpYnVjacOzbiBkZSBsb3MgaW5kaXZpZHVvcyBhIGxvcyBkb3MgcHJpbWVyb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMsIGVzY3JpYmUgbG8gc2lndWllbnRlOg0KDQpgYGB7cn0NCmZ2aXpfY29udHJpYihyZXMucGNhLCBjaG9pY2UgPSAiaW5kIiwgYXhlcyA9IDE6MikNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBpbmRgIChjb2xvcmVhciBwb3IgdmFyaWFibGUgY29udGludWEpDQoNCkVuIGN1YW50byBhIGxhcyB2YXJpYWJsZXMsIGxvcyBpbmRpdmlkdW9zIHB1ZWRlbiBzZXIgY29sb3JlYWRvcyBzZWfDum4gY3VhbHF1aWVyIHZhcmlhYmxlIGNvbnRpbnVhIHBlcnNvbmFsaXphZGEgZXNwZWNpZmljYW5kbyBlbCBhcmd1bWVudG8gYGNvbC5pbmRgLg0KDQoNCmBgYHtyfQ0KI0dlbmVyYSB1bmEgdmFyaWFibGUgY29udGludWEgYWxlYXRvcmlhIGRlIGxvbmdpdHVkIDIzIA0KIyhsYSBtaXNtYSBsb25naXR1ZCBxdWUgZWwgbsO6bWVybyBkZSBpbmRpdmlkdW9zIGFjdGl2b3MgZW4gZWwgUENBKS4NCnNldC5zZWVkKDEyMykNCm15LmNvbnQudmFyIDwtIHJub3JtKDIzKQ0KDQojIENvbG9yZWFyIGxhcyB2YXJpYWJsZXMgc2Vnw7puIGxhIHZhcmlhYmxlIGNvbnRpbnVhDQpmdml6X3BjYV9pbmQocmVzLnBjYSwgY29sLmluZCA9IG15LmNvbnQudmFyLA0KICAgICAgICAgICAgIGdyYWRpZW50LmNvbHMgPSBjKCJibHVlIiwgImJyb3duIiwgImdyZWVuIiksDQogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gIlNjYWxlIg0KICAgICAgICAgICAgICkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBpbmRgIChjb2xvcmVhciBwb3IgZ3J1cG9zKQ0KDQpBcXXDrSBkZXNjcmliaW1vcyBjw7NtbyBjb2xvcmVhciBhIGluZGl2aWR1b3MgcG9yIGdydXBvLiBBZGVtw6FzLCBtb3N0cmFtb3MgY8OzbW8gYWdyZWdhciBlbGlwc2VzIGRlIGNvbmNlbnRyYWNpw7NuIHkgZWxpcHNlcyBkZSBjb25maWFuemEgcG9yIGdydXBvcy4gUGFyYSBlc3RvLCBwYXJhIGVzdGFzIHNlY2Npb25lcywgdXRpbGl6YXJlbW9zIGxvcyBkYXRvcyBgZGF0MmAsIGNvbnN0cnVpZG8gZGUgdGFsIG1hbmVyYSBxdWUgY29udGVuZ2EgbGFzIHZhcmlhYmxlcyBkZSBgZGF0YCB5IGN1YWxxdWllciB2YXJpYWJsZSBjYXRlZ8OzcmljYSAoY29tbywgcG9yIGVqZW1wbG8sIGBHZW5kZXJgLCAgYFNFU2AsIGBFY29ub21pY2AsIGV0YywgbyBncnVwb3MgZ2VuZXJhZG9zIGFsZWF0b3JpYW1lbnRlLg0KDQoNCg0KYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRhdDEgPC0gZGF0b3NDb21wbGV0b1sxOjUwLCBdDQpkYXQyIDwtIGRhdG9zQ29tcGxldG9bMTo1MCwgYygyMjoyNSwyODozMCldDQphdHRhY2goZGF0MikNCmhlYWQoZGF0Miw0KSANCmBgYA0KDQoNCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNkYXQgPC0gZGF0b3NDb21wbGV0b1sxOjIzLCBjKDUsNyw4LDksMTMsMTUsMjEsMjcsMjksMzApXSAjIHByaW1lciBpbnRlbnRvDQpkYXQxIDwtIGRhdG9zQ29tcGxldG9bMTo1MCwgXQ0KZGF0MiA8LSBkYXRvc0NvbXBsZXRvWzE6NTAsIGMoMjI6MjUsMjg6MzApXQ0KI2RhdDIgPC0gZGF0b3NDb21wbGV0b1ssIGMoMyw0LDYsMTEsMjcsMjgsMjksMzMpXQ0KYXR0YWNoKGRhdDIpDQprYWJsZShoZWFkKGRhdDIsNCksYWxpZ24gPSAiY2NjIikgJT4lIyBTZSBuZWNlc2l0YSBsaWJyYXJ5KGtuaXRyKSANCmthYmxlX3N0eWxpbmcoKSAlPiUgICAgICAgICAgICAgICAgI2xpYnJhcnkoa2FibGVFeHRyYSkuLi4uIFNvbG8gcGFyYSBrbml0IHRvIGh0bWwNCmthYmxlX2NsYXNzaWNfMihmdWxsX3dpZHRoID0gRikgICAjbGlicmFyeShrYWJsZUV4dHJhKS4uLi5Tb2xvIHBhcmEga25pdCB0byBodG1sDQpgYGANCg0KYGBge3J9DQojIFBDQQ0KZGF0Mi5wY2EgPC0gUENBKGRhdDIsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEZBTFNFKQ0KYGBgDQoNCkdlbmVyYXJlbW9zIGxhIHZhcmlhYmxlIGdydXBhbCBjb24gYGttZWFuc2AgeSBsYSBhbmV4YXJlbW9zIGEgbG9zIGRhdG9zIG9yaWdpbmFsZXMuIA0KDQpgYGB7cn0NCiMgQ3JlYXIgMyBjbMO6c3RlciAoY2VudGVycyA9IDMpDQpzZXQuc2VlZCgxMjMpDQpyZXMyLmttIDwtIGttZWFucyhkYXQyLCBjZW50ZXJzID0gMywgbnN0YXJ0ID0gMjUpDQoNCiMgRXh0cmFlciBldGlxdWV0YXMgZGUgbG9zIGNsw7pzdGVyIA0KY2x1c3Rlcl9sYWJlbHMgPC0gcmVzMi5rbSRjbHVzdGVyDQoNCiMgQcOxYWRpciBldGlxdWV0YXMgZGUgbG9zIGNsw7pzdGVyIGEgbG9zIGRhdG9zIG9yaWdpbmFsZXMNCmRhdDEkQ2x1c3RlciA8LSBjbHVzdGVyX2xhYmVscw0KDQpnciA8LSBhcy5mYWN0b3IoZGF0MSRDbHVzdGVyKQ0KZ3JfbmFtZSA8LSAiQ2x1c3RlcnMiDQpgYGANCg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgaW5kYCAoZWxpcHNlcyBkZSBjb25jZW50cmFjacOzbikNCg0KDQpFbiBlbCBjw7NkaWdvIFIgKHF1ZSBzZSBtdWVzdHJhIGFiYWpvKSwgbG9zIGFyZ3VtZW50b3MgYGhhYmlsbGFnZWAgbyBgY29sLmluZCBzZSBwdWVkZWBuIHV0aWxpemFyIHBhcmEgZXNwZWNpZmljYXIgbGEgdmFyaWFibGUgZGUgZmFjdG9yIHBhcmEgY29sb3JlYXIgYSBsb3MgaW5kaXZpZHVvcyBwb3IgZ3J1cG9zLiBQYXJhIGFncmVnYXIgdW5hIGVsaXBzZSBkZSBjb25jZW50cmFjacOzbiBhbHJlZGVkb3IgZGUgY2FkYSBncnVwbywgZXNwZWNpZmlxdWUgZWwgYXJndW1lbnRvIGBhZGRFbGxpcHNlcyA9IFRSVUVgLiBFbCBhcmd1bWVudG8gYHBhbGxldGVgIHNlIHB1ZWRlIHV0aWxpemFyIHBhcmEgY2FtYmlhciBsb3MgY29sb3JlcyBkZSBsb3MgZ3J1cG9zLg0KDQoNCg0KYGBge3J9DQpmdml6X3BjYV9pbmQoZGF0Mi5wY2EsDQogICAgICAgICAgICAgZ2VvbS5pbmQgPSAicG9pbnQiLCAjIG1vc3RyYXIgc29sbyBwdW50b3MgKG5vICJ0ZXh0byIpDQogICAgICAgICAgICAgY29sLmluZCA9IGdyICAgLCAgICAjIGNvbG9yIHBvciBncnVwb3MNCiAgICAgICAgICAgICBwYWxldHRlID0gYygiYmx1ZSIsICJicm93biIsICJncmVlbiIsICJ5ZWxsb3ciLCAicGluayIpLA0KICAgICAgICAgICAgIGFkZEVsbGlwc2VzID0gVFJVRSwgIyBjb25jZW50cmFjacOzbiBkZSBlbGlwc2VzDQogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZ3JfbmFtZQ0KICAgICAgICAgICAgKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGluZGAgKGVsaXBzZXMgZGUgY29uZmlhbnphKQ0KDQpQYXJhIGVsaW1pbmFyIGVsIHB1bnRvIG1lZGlvIGRlbCBncnVwbywgZXNwZWNpZmlxdWUgZWwgYXJndW1lbnRvIGBtZWFuLnBvaW50ID0gRkFMU0VgLiBTaSBkZXNlYSBlbGlwc2VzIGRlIGNvbmZpYW56YSBlbiBsdWdhciBkZSBlbGlwc2VzIGRlIGNvbmNlbnRyYWNpw7NuLCB1dGlsaWNlIGBlbGxpcHNlLnR5cGUgPSAiY29uZmlkZW5jZSJgLg0KDQoNCmBgYHtyfQ0KIyBBw7FhZGlyIGVsaXBzZXMgZGUgY29uZmlhbnphDQpmdml6X3BjYV9pbmQoZGF0Mi5wY2EsIA0KICAgICAgICAgICAgIGdlb20uaW5kID0gInBvaW50IiwgDQogICAgICAgICAgICAgY29sLmluZCA9IGdyLA0KICAgICAgICAgICAgIHBhbGV0dGUgPSBjKCJibHVlIiwgImJyb3duIiwgImdyZWVuIiksDQogICAgICAgICAgICAgYWRkRWxsaXBzZXMgPSBUUlVFLCANCiAgICAgICAgICAgICBlbGxpcHNlLnR5cGUgPSAiY29uZmlkZW5jZSIsDQogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZ3JfbmFtZQ0KICAgICAgICAgICAgICkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBpbmRgIChlbGlwc2VzOiBtw6FzIHBhbGV0YXMgZGUgY29sb3JlcykNCg0KVMOpbmdhc2UgZW4gY3VlbnRhIHF1ZSBsb3MgdmFsb3JlcyBwZXJtaXRpZG9zIHBhcmEgbGEgcGFsZXRhIGluY2x1eWVuOg0KICANCiAgKyBgImdyZXkiYCBwYXJhIHBhbGV0YXMgZGUgY29sb3JlcyBncmlzZXM7DQogIA0KICArIFBhbGV0YXMgYnJld2VyIGNvbW8gYCJSZEJ1ImAsIGAiQmx1ZXMiYCwgLi4uOyBQYXJhIHZlciB0b2RhcywgZXNjcmliYSBlc3RvIGVuIFI6IGBSQ29sb3JCcmV3ZXI6OmRpc3BsYXkuYnJld2VyLmFsbCgpYC4NCiAgDQogICsgUGFsZXRhIGRlIGNvbG9yZXMgcGVyc29uYWxpemFkYSwgcG9yIGVqZW1wbG8gYGMoImJsdWUiLCAicmVkIilgOw0KICANCiAgKyBQcGFsZXRhcyBkZSByZXZpc3RhcyBjaWVudMOtZmljYXMgZGVsIHBhcXVldGUgYGdnc2NpYC4gUG9yIGVqZW1wbG86IGAibnBnImAsIGAiYWFhcyJgLCBgImxhbmNldCJgLCBgImpjbyJgLCBgInVjc2NnYiJgLCBgInVjaGljYWdvImAsIGAic2ltcHNvbnMiYCB5IGAicmlja2FuZG1vcnR5ImAuDQogDQpQb3IgZWplbXBsbywgY29uIGxhIHBhbGV0YSBgc2ltcHNvbnNgOiANCiAgDQpgYGB7cn0NCmZ2aXpfcGNhX2luZChkYXQyLnBjYSwNCiAgICAgICAgICAgICBsYWJlbCA9ICJub25lIiwgICAgICAgIyBPY3VsdGFyIGxhcyBldGlxdWV0YXMgZGVsb3MgaW5kaXZpZHVvcw0KICAgICAgICAgICAgIGNvbC5pbmQgPSBnciwgICAgICAgICAjIENvbG9yIHBvciBncnVwb3MNCiAgICAgICAgICAgICBhZGRFbGxpcHNlcyA9IFRSVUUsICAgIyBFbGlwc2VzIGRlIGNvbmNlbnRyYWNpw7NuDQogICAgICAgICAgICAgcGFsZXR0ZSA9ICJzaW1wc29ucyIsDQogICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gZ3JfbmFtZQ0KICAgICAgICAgICAgICkNCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEVqZW1wbG86IFNvbHVjacOzbiAocGVyc29uYWxpemFyIGdyw6FmaWNvcykgIA0KICANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIERpbWVuc2lvbmVzIChgYXhlc2ApDQoNClBvciBkZWZlY3RvLCBsYXMgdmFyaWFibGVzL2luZGl2aWR1b3Mgc2UgcmVwcmVzZW50YW4gZW4gbGFzIGRpbWVuc2lvbmVzIDEgeSAyLiBTaSBzZSBkZXNlYSB2aXN1YWxpemFybG9zIGVuIGxhcyBkaW1lbnNpb25lcyAyIHkgMywgcG9yIGVqZW1wbG8sIHNlIGRlYmUgZXNwZWNpZmljYXIgZWwgYXJndW1lbnRvIGBheGVzID0gYygyLCAzKWAuDQoNCg0KYGBge3J9DQojIFZhcmlhYmxlcyBzb2JyZSBsYXMgZGltZW5zaW9uZXMgMiB5IDMNCmZ2aXpfcGNhX3ZhcihyZXMucGNhLCANCiAgICAgICAgICAgICBheGVzID0gYygyLCAzKSwgDQogICAgICAgICAgICAgY29sLnZhciA9ICJyZWQiLA0KICAgICAgICAgICAgIHJlcGVsPVRSVUUpDQoNCiMgSW5kaXZpZHVvcyBzb2JyZSBsYXMgZGltZW5zaW9uZXMgMiB5IDMNCmZ2aXpfcGNhX2luZChyZXMucGNhLCANCiAgICAgICAgICAgICBheGVzID0gYygyLCAzKSwNCiAgICAgICAgICAgICBjb2wuaW5kID0gImRhcmtibHVlIiwNCiAgICAgICAgICAgICByZXBlbD1UUlVFKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgR3JhZmljYXIgZWxlbWVudG9zIChgZ2VvbWApDQoNCioqMS4gQXJndW1lbnRvIGBnZW9tYDoqKg0KDQpFbCBhcmd1bWVudG8gYGdlb21gIChwb3IgZ2VvbWV0csOtYSkgeSBzdXMgZGVyaXZhZG9zIHNlIHV0aWxpemFuIHBhcmEgZXNwZWNpZmljYXIgbG9zIGVsZW1lbnRvcyBnZW9tw6l0cmljb3MgbyBlbGVtZW50b3MgZ3LDoWZpY29zIGEgdXRpbGl6YXIgZW4gbGEgcmVwcmVzZW50YWNpw7NuIGdyw6FmaWNhLg0KDQoqKjIuIEFyZ3VtZW50byBgZ2VvbS52YXJgOioqDQoNCkVzIHVuIHRleHRvIHF1ZSBlc3BlY2lmaWNhIGxhIGdlb21ldHLDrWEgYSB1dGlsaXphciBwYXJhIHJlcHJlc2VudGFyIGxhcyB2YXJpYWJsZXMuIExvcyB2YWxvcmVzIHBlcm1pdGlkb3Mgc29uIGxhIGNvbWJpbmFjacOzbiBkZSBgYyjigJxwb2ludOKAnSwg4oCcYXJyb3figJ0sIOKAnHRleHTigJ0pYDoNCiAgDQogICsgU2UgdXNhIGBnZW9tLnZhciA9IOKAnHBvaW504oCdYCBwYXJhIG1vc3RyYXIgc29sbyBwdW50b3MuDQogIA0KICArIFNlIHVzYSBgZ2VvbS52YXIgPSDigJx0ZXh04oCdYCBwYXJhIG1vc3RyYXIgc29sbyBldGlxdWV0YXMgZGUgdGV4dG8uDQogIA0KICArIFNlIHVzYSBgZ2VvbS52YXIgPSBjKOKAnHBvaW504oCdLCDigJx0ZXh04oCdKWAgcGFyYSBtb3N0cmFyIHRhbnRvIHB1bnRvcyBjb21vIGV0aXF1ZXRhcyBkZSB0ZXh0by4NCiAgDQogICsgU2UgdXNhIGBnZW9tLnZhciA9IGMo4oCcYXJyb3figJ0sIOKAnHRleHTigJ0pYCBwYXJhIG1vc3RyYXIgZmxlY2hhcyB5IGV0aXF1ZXRhcyAocHJlZGV0ZXJtaW5hZG8pLg0KDQoNCmBgYHtyfQ0KIyBNb3N0cmFyIHRhbnRvIHB1bnRvcyBjb21vIGV0aXF1ZXRhcyBkZSB0ZXh0bw0KZnZpel9wY2FfdmFyKHJlcy5wY2EsIA0KICAgICAgICAgICAgIGdlb20udmFyID0gYygicG9pbnQiLCAidGV4dCIpLCANCiAgICAgICAgICAgICBjb2wudmFyID0gInJlZCIsDQogICAgICAgICAgICAgcmVwZWw9VFJVRQ0KICAgICAgICAgICAgICkNCmBgYA0KDQoNCioqMy4gQXJndW1lbnRvIGBnZW9tLmluZGA6KioNCg0KRXMgdW4gdGV4dG8gcXVlIGVzcGVjaWZpY2EgbGEgZ2VvbWV0csOtYSBhIHV0aWxpemFyIHBhcmEgdHJhemFyIGxvcyBpbmRpdmlkdW9zLiBMb3MgdmFsb3JlcyBwZXJtaXRpZG9zIHNvbiBsYSBjb21iaW5hY2nDs24gZGUgYGMoInBvaW50IiwgInRleHQiKS5gDQogIA0KICArIFNlIHVzYSBgZ2VvbS5pbmQgPSAicG9pbnQiYCBwYXJhIG1vc3RyYXIgc29sbyBwdW50b3MuDQogIA0KICArIFNlIHVzYSBgZ2VvbS5pbmQgPSAidGV4dCJgIHBhcmEgbW9zdHJhciBzb2xvIGV0aXF1ZXRhcyBkZSB0ZXh0by4NCiAgDQogICsgU2UgdXNhIGBnZW9tLmluZCA9IGMoInBvaW50IiwgInRleHQiKWAgcGFyYSBtb3N0cmFyIHRhbnRvIHB1bnRvcyBjb21vIGV0aXF1ZXRhcyBkZSB0ZXh0byAocG9yIGRlZmVjdG8pLg0KICANCg0KYGBge3J9DQojIE1vc3RyYXIgc8OzbG8gZXRpcXVldGFzIGRlIHRleHRvIGluZGl2aWR1YWxlcw0KZnZpel9wY2FfaW5kKHJlcy5wY2EsIA0KICAgICAgICAgICAgIGdlb20uaW5kID0gInRleHQiLA0KICAgICAgICAgICAgIGNvbC5pbmQ9ICJkYXJrYmx1ZSIsDQogICAgICAgICAgICAgcmVwZWw9VFJVRSkNCmBgYA0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBUYW1hw7FvIHkgZm9ybWEgKGBsYWJlbGAsIGBhcnJvd2ApDQoNCjEuICpUYW1hw7FvIGRlIGV0aXF1ZXRhKjogdGFtYcOxbyBkZSBsYSBmdWVudGUgcGFyYSBsYXMgZXRpcXVldGFzIGRlIHRleHRvLCBwb3IgZWplbXBsbzogYGxhYmVsc2l6ZSA9IDQuM2AuDQoNCjIuICpUYW1hw7FvIGRlIGZsZWNoYSo6IGVsIHRhbWHDsW8gZGUgbGFzIGZsZWNoYXMuIENvbnRyb2xhIGVsIGdyb3NvciBkZSBsYXMgZmxlY2hhcywgcG9yIGVqZW1wbG86IGBhcnJvd3NpemUgPSAxLjJgLg0KDQozLiAqVGFtYcOxbyBkZSBwdW50byo6IGVsIHRhbWHDsW8gZGUgbG9zIHB1bnRvcywgcG9yIGVqZW1wbG86IGBwb2ludHNpemUgPSAyLjVgLg0KDQo0LiAqRm9ybWEgZGUgcHVudG8qOiBsYSBmb3JtYSBkZSBsb3MgcHVudG9zLCBgcG9pbnRzaGFwZSA9IDEwYC4gU2UgcHVlZGUgZWplY3V0YXIgYGdncHVicjo6c2hvd19wb2ludF9zaGFwZXNgIHBhcmEgdmVyIGxhcyBmb3JtYXMgZGUgcHVudG8gZGlzcG9uaWJsZXMuDQoNCg0KYGBge3J9DQojIENhbWJpYXIgZWwgdGFtYcOxbyBkZWxhcyBmbGVjaGFzIGVuIGxhcyBldGlxdWV0YXMNCmZ2aXpfcGNhX3ZhcihyZXMucGNhLCANCiAgICAgICAgICAgICBsYWJlbHNpemUgPSA0LjMsDQogICAgICAgICAgICAgYXJyb3dzaXplID0gMS4yLCANCiAgICAgICAgICAgICByZXBlbCA9IFRSVUUNCiAgICAgICAgICAgICApDQoNCiMgQ2FtYmlhciBlbCB0YW1hw7FvIGRlIGxvcyBwdW50b3MsIGxhIGZvcm1hIHkgZWwgY29sb3IgZGUgcmVsbGVubw0KIyBDYW1iaWFyIGVsIHRhbWHDsW8gZGUgbGFzIGV0aXF1ZXRhcw0KZnZpel9wY2FfaW5kKHJlcy5wY2EsDQogICAgICAgICAgICAgcG9pbnRzaXplID0gMy41LCANCiAgICAgICAgICAgICBwb2ludHNoYXBlID0gMjAsIA0KICAgICAgICAgICAgIGZpbGwgPSAiZGFya2dyZWVuIiwNCiAgICAgICAgICAgICBsYWJlbHNpemUgPSA0LjMsIA0KICAgICAgICAgICAgIHJlcGVsID0gVFJVRQ0KICAgICAgICAgICAgICkNCmBgYA0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBFbGlwc2VzIChgYWRkRWxsaXBzZXNgKQ0KDQpDb21vIGRlc2NyaWJpbW9zIGVuIHNlY2Npb25lcyBhbnRlcmlvcmVzLCBhbCBjb2xvcmVhciBpbmRpdmlkdW9zIHBvciBncnVwb3MsIHNlIHB1ZWRlIGFncmVnYXIgZWxpcHNlcyBkZSBjb25jZW50cmFjacOzbiBkZSBwdW50b3MgdXNhbmRvIGVsIGFyZ3VtZW50byBgYWRkRWxsaXBzZXMgPSBUUlVFYC4gT2Jzw6lydmVzZSBxdWUgZWwgYXJndW1lbnRvIGBlbGxpcHNlLnR5cGVgIHNlIHB1ZWRlIHV0aWxpemFyIHBhcmEgY2FtYmlhciBlbCB0aXBvIGRlIGVsaXBzZXMuIExvcyB2YWxvcmVzIHBvc2libGVzIHNvbjoNCiAgDQogICsgYCJjb252ZXgiYDogdHJhemEgbGEgZW52b2x2ZW50ZSBjb252ZXhhIGRlIHVuIGNvbmp1bnRvIGRlIHB1bnRvcy4NCiAgDQogICsgYCJjb25maWRlbmNlImA6IHRyYXphIGVsaXBzZXMgZGUgY29uZmlhbnphIGFscmVkZWRvciBkZSBsb3MgcHVudG9zIG1lZGlvcyBkZWwgZ3J1cG8gY29tbyBsYSBmdW5jacOzbiBgY29vcmQuZWxsaXBzZWAgZW4gZWwgcGFxdWV0ZSBgRmFjdG9NaW5lUmAuDQogIA0KICArIGAidCJgOiBhc3VtZSB1bmEgZGlzdHJpYnVjacOzbiAkdCQtbXVsdGl2YXJpYWRhLg0KICANCiAgKyBgIm5vcm0iYDogYXN1bWUgdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsLW11bHRpdmFyaWFkYS4NCiAgDQogICsgYOKAnGV1Y2xpZOKAnWA6IGRpYnVqYSB1biBjw61yY3VsbyBjb24gZWwgcmFkaW8gaWd1YWwgYWwgbml2ZWwsIHJlcHJlc2VudGFuZG8gbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEgZGVzZGUgZWwgY2VudHJvLiBFc3RhIGVsaXBzZSBwcm9iYWJsZW1lbnRlIG5vIGFwYXJlY2Vyw6EgY2lyY3VsYXIgYSBtZW5vcyBxdWUgc2UgYXBsaXF1ZSBgY29vcmRfZml4ZWRgLg0KICANCg0KRWwgYXJndW1lbnRvIGBlbGxpcHNlLmxldmVsYCB0YW1iacOpbiBlc3TDoSBkaXNwb25pYmxlIHBhcmEgY2FtYmlhciBlbCB0YW1hw7FvIGRlIGxhIGVsaXBzZSBkZSBjb25jZW50cmFjacOzbiBlbiBsYSBwcm9iYWJpbGlkYWQgbm9ybWFsLiBQb3IgZWplbXBsbywgcHVlZGUgZXNwZWNpZmljYXIgYGVsbGlwc2UubGV2ZWwgPSAwLjk1YCBvIGBlbGxpcHNlLmxldmVsID0gMC42NmAuDQoNCg0KYGBge3J9DQojIEVsaXBzZXMgZGUgY29uZmlhbnphDQpmdml6X3BjYV9pbmQoZGF0Mi5wY2EsIA0KICAgICAgICAgICAgIGdlb20uaW5kID0gInBvaW50IiwNCiAgICAgICAgICAgICBjb2wuaW5kID0gZ3IsICAgIyBDb2xvciBwb3IgZ3J1cG9zDQogICAgICAgICAgICAgcGFsZXR0ZSA9IGMoImJsdWUiLCAiYnJvd24iLCAiZ3JlZW4iKSwNCiAgICAgICAgICAgICBhZGRFbGxpcHNlcyA9IFRSVUUsIA0KICAgICAgICAgICAgIGVsbGlwc2UudHlwZSA9ICJjb25maWRlbmNlIiwNCiAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBncl9uYW1lDQogICAgICAgICAgICAgKQ0KDQojIEVudm9sdmVudGUgY29udmV4YQ0KZnZpel9wY2FfaW5kKGRhdDIucGNhLCANCiAgICAgICAgICAgICBnZW9tLmluZCA9ICJwb2ludCIsDQogICAgICAgICAgICAgY29sLmluZCA9IGdyLCAgICMgQ29sb3IgcG9yIGdydXBvcw0KICAgICAgICAgICAgIHBhbGV0dGUgPSBjKCJibHVlIiwgImJyb3duIiwgImdyZWVuIiksDQogICAgICAgICAgICAgYWRkRWxsaXBzZXMgPSBUUlVFLCANCiAgICAgICAgICAgICBlbGxpcHNlLnR5cGUgPSAiY29udmV4IiwNCiAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBncl9uYW1lDQogICAgICAgICAgICAgKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgUHVudG9zIG1lZGlvcyBwb3IgZ3J1cG8gKGBtZWFuLnBvaW50YCkNCg0KQ3VhbmRvIHNlIGNvbG9yZWFuIGluZGl2aWR1b3MgcG9yIGdydXBvcyAodmVyIHNlY2Npb25lcyBhbnRlcmlvcmVzKSwgbG9zIHB1bnRvcyBtZWRpb3MgZGUgbG9zIGdydXBvcyAoYmFyaWNlbnRyb3MpIHRhbWJpw6luIHNlIG11ZXN0cmFuIGRlIGZvcm1hIHByZWRldGVybWluYWRhLiBQYXJhIGVsaW1pbmFyIGxvcyBwdW50b3MgbWVkaW9zLCBzZSBwdWVkZSB1dGlsaXphciBlbCBhcmd1bWVudG8gYG1lYW4ucG9pbnQgPSBGQUxTRWAuDQoNCg0KYGBge3J9DQpmdml6X3BjYV9pbmQoZGF0Mi5wY2EsDQogICAgICAgICAgICAgZ2VvbS5pbmQgPSAicG9pbnQiLCAgICAgIyBNdWVzdHJhIHNvbG8gcHVudG9zIChwZXJvIG5vICJ0ZXh0byIpDQogICAgICAgICAgICAgY29sLmluZCA9IGdyLCAgICAgICAgICAgIyBDb2xvciBwb3IgZ3J1cG9zDQogICAgICAgICAgICAgcGFsZXR0ZSA9IGMoImJsdWUiLCAiYnJvd24iLCAiZ3JlZW4iLCAieWVsbG93IiwgInBpbmsiKSwNCiAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBncl9uYW1lLA0KICAgICAgICAgICAgIG1lYW4ucG9pbnQgPSBGQUxTRQ0KICAgICAgICAgICAgICkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIFRpcG8gZGUgbMOtbmVhIChgYXhlcy5saW5ldHlwZWApDQoNCkVsIGFyZ3VtZW50byBgYXhlcy5saW5ldHlwZWAgc2UgcHVlZGUgdXRpbGl6YXIgcGFyYSBlc3BlY2lmaWNhciBlbCB0aXBvIGRlIGzDrW5lYSBkZSBsb3MgZWplcy4gRWwgdmFsb3IgcHJlZGV0ZXJtaW5hZG8gZXMgYCJkYXNoZWQiYCAocmF5YWRvKS4gTG9zIHZhbG9yZXMgcGVybWl0aWRvcyBpbmNsdXllbiBgImJsYW5rImAgKGVuIGJsYW5jbyksIGAic29saWQiYCAoc8OzbGlkbyksIGAiZG90dGVkIiAocHVudGVhZG8pYCwgZXRjLiBQYXJhIHZlciB0b2RvcyBsb3MgdmFsb3JlcyBwb3NpYmxlcywgZXNjcmliYSBgZ2dwdWJyOjpzaG93X2xpbmVfdHlwZXNgLiBQYXJhIGVsaW1pbmFyIGxhcyBsw61uZWFzIGRlIGxvcyBlamVzLCB1dGlsaWNlIGBheGVzLmxpbmV0eXBlID0gImJsYW5rImA6DQoNCg0KYGBge3J9DQpmdml6X3BjYV92YXIocmVzLnBjYSwNCiAgICAgICAgICAgICBheGVzLmxpbmV0eXBlID0gImJsYW5rIiwNCiAgICAgICAgICAgICBjb2wudmFyPSJyZWQiLCANCiAgICAgICAgICAgICByZXBlbD1UUlVFKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgQXBhcmllbmNpYSBncsOhZmljYSAoYGdncGFyYCkNCg0KUGFyYSBjYW1iaWFyIGbDoWNpbG1lbnRlIGxhIGFwYXJpZW5jaWEgZ3LDoWZpY2EgZGUgY3VhbHF1aWVyIGdncGxvdCwgcHVlZGUgdXRpbGl6YXIgbGEgZnVuY2nDs24gYGdncGFyYCBkZWwgcGFxdWV0ZSBgZ2dwdWJyYC4gTG9zIHBhcsOhbWV0cm9zIGdyw6FmaWNvcyBxdWUgc2UgcHVlZGVuIGNhbWJpYXIgdXNhbmRvIGBnZ3BhcmAgaW5jbHV5ZW46DQogIA0KICArIFTDrXR1bG9zIHByaW5jaXBhbGVzLCBldGlxdWV0YXMgZGUgZWplcyB5IHTDrXR1bG9zIGRlIGxleWVuZGEuDQogIA0KICArIFBvc2ljacOzbiBkZSBsYSBsZXllbmRhLiBWYWxvcmVzIHBvc2libGVzOiBgInRvcCJgIChhcnJpYmEpLCBgImJvdHRvbSJgIChhYmFqbyksIGAibGVmdCJgIChpenF1aWVyZGEpLCBgInJpZ2h0YCIgKGRlcmVjaGEpLCBgIm5vbmUiYCAobmluZ3VubykuDQogIA0KICArIFBhbGV0YSBkZSBjb2xvcmVzLg0KICANCiAgKyBUZW1hcy4gTG9zIHZhbG9yZXMgcGVybWl0aWRvcyBpbmNsdXllbjogYHRoZW1lX2dyYXlgLCBgdGhlbWVfYndgLCBgdGhlbWVfbWluaW1hbGAsIGB0aGVtZV9jbGFzc2ljYCwgYHRoZW1lX3ZvaWRgLg0KICANCmBgYHtyfQ0KaW5kLnAgPC0gZnZpel9wY2FfaW5kKGRhdDIucGNhLCANCiAgICAgICAgICAgICAgICAgICAgICBnZW9tID0gInBvaW50IiwgDQogICAgICAgICAgICAgICAgICAgICAgY29sLmluZCA9IGdyDQogICAgICAgICAgICAgICAgICAgICAgKQ0KZ2dwdWJyOjpnZ3BhcihpbmQucCwNCiAgICAgICAgICAgICAgdGl0bGUgPSAiUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyIsDQogICAgICAgICAgICAgIHN1YnRpdGxlID0gIlN1cnZleSBkYXRhIHNldCIsDQogICAgICAgICAgICAgIGNhcHRpb24gPSAiU291cmNlOiBmYWN0b2V4dHJhIiwNCiAgICAgICAgICAgICAgeGxhYiA9ICJQQzEiLCANCiAgICAgICAgICAgICAgeWxhYiA9ICJQQzIiLA0KICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBncl9uYW1lLCANCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsDQogICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9ncmF5KCksIA0KICAgICAgICAgICAgICBwYWxldHRlID0gImpjbyINCiAgICAgICAgICAgICAgKQ0KYGBgDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbzogU29sdWNpw7NuIChgYmlwbG90YCkgIA0KICANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgYmlwbG90YCAoZnVuY2nDs24pDQoNClBhcmEgaGFjZXIgdW4gYmlwbG90IHNpbXBsZSBkZSBpbmRpdmlkdW9zIHkgdmFyaWFibGVzOg0KDQpgYGB7cn0NCmZ2aXpfcGNhX2JpcGxvdChyZXMucGNhLCANCiAgICAgICAgICAgICAgICByZXBlbCA9IFRSVUUsDQogICAgICAgICAgICAgICAgY29sLnZhciA9ICJkYXJrYmx1ZSIsICMgQ29sb3IgZGUgbGFzIHZhcmlhYmxlcw0KICAgICAgICAgICAgICAgIGNvbC5pbmQgPSAiZGFya2dyZWVuIiAjIENvbG9yIGRlIGxvcyBpbmRpdmlkdW9zDQogICAgICAgICAgICAgICAgKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgYGJpcGxvdGAgKGludGVycHJldGFjaW9uZXMpDQogIA0KICAxLiBFcyBpbXBvcnRhbnRlIHRlbmVyIGVuIGN1ZW50YSBxdWUgZWwgYmlwbG90IHB1ZWRlIHNlciDDunRpbCBzb2xvIGN1YW5kbyBoYXkgdW4gYmFqbyBuw7ptZXJvIGRlIHZhcmlhYmxlcyBlIGluZGl2aWR1b3MgZW4gZWwgY29uanVudG8gZGUgZGF0b3M7IGRlIGxvIGNvbnRyYXJpbywgZWwgZ3LDoWZpY28gZmluYWwgc2Vyw61hIGlsZWdpYmxlLiANCiAgDQogIDIuIEFkZW3DoXMsIGxhcyBjb29yZGVuYWRhcyBkZSBsb3MgaW5kaXZpZHVvcyB5IGxhcyB2YXJpYWJsZXMgbm8gZXN0w6FuIGNvbnN0cnVpZGFzIGVuIGVsIG1pc21vIGVzcGFjaW8uIA0KICAzLiBQb3IgbG8gdGFudG8sIGVuIHByaW5jaXBpbywgZW4gdW4gYmlwbG90LCBkZWJlcsOtYSBjZW50cmFydGUgcHJpbmNpcGFsbWVudGUgZW4gbGEgZGlyZWNjacOzbiBkZSBsYXMgdmFyaWFibGVzIHkgbm8gZW4gc3VzIHBvc2ljaW9uZXMgYWJzb2x1dGFzIGVuIGVsIGdyw6FmaWNvLiANCiAgDQogIDQuICBjb24gcmVzcGVjdG8gYSBsYXMgb2JzZXJ2YWNpb25lcyBhbnRlcmlvcmVzLCBleGlzdGUgdW5hIHTDqWNuaWNhIG11bHRpdmFyaWFudGUgcXVlIHNlIGxsYW1hIGBISl9iaXBsb3RgIHkgcXVlIHJlc3VlbHZlIGVsIHRlbWEgZGVsIGVzcGFjaW8gZGltZW5zaW9uYWwuIEVuIFIsIHNlIHZpc3VhbGl6YXIgYSB0cmF2w6lzIGRlbCBwYXF1ZXRlIFtMREFCaXBsb3RzOiBCaXBsb3QgR3JhcGhpY2FsIEludGVyZmFjZSBmb3IgTERBIE1vZGVsc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL0xEQUJpcGxvdHMvKS4gDQogIA0KRGUgbWFuZXJhIGdlbmVyYWwsIHVuIGJpcGxvdCBzZSBwdWVkZSBpbnRlcnByZXRhciBjb21vIHNlIGV4cGxpY2EgZW4gbG9zIGNvbWVudGFyaW9zIDUgeSA2OiANCiAgDQogIDUuIFVuIGluZGl2aWR1byBxdWUgc2UgZW5jdWVudHJhIGVuIGVsIG1pc21vIGxhZG8gZGUgdW5hIHZhcmlhYmxlIGRhZGEgdGllbmUgdW4gdmFsb3IgYWx0byBwYXJhIGVzdGEgdmFyaWFibGUuDQogICAgDQogIDYuIFVuIGluZGl2aWR1byBxdWUgc2UgZW5jdWVudHJhIGVuIGVsIGxhZG8gb3B1ZXN0byBkZSB1bmEgdmFyaWFibGUgZGFkYSB0aWVuZSB1biB2YWxvciBiYWpvIHBhcmEgZXN0YSB2YXJpYWJsZS4gDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQogIA0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgYmlwbG90YCAoY29tYmluYW5kbyBvcGNpb25lcykNCg0KQWhvcmEsIHV0aWxpemFuZG8gbGEgc2FsaWRhIGRhdDIucGNhLCB2YW1vcyBhOg0KICANCiAgKyBDcmVhciB1biBiaXBsb3QgZGUgaW5kaXZpZHVvcyB5IHZhcmlhYmxlcy4NCiAgDQogICsgQ2FtYmlhciBlbCBjb2xvciBkZSBsb3MgaW5kaXZpZHVvcyBwb3IgZ3J1cG9zIChxdWUgc2Vyw61hIGBncmApOiBgY29sLmluZCA9IGdyYC4NCiAgDQogICsgTW9zdHJhciBzb2xvIGxhcyBldGlxdWV0YXMgcGFyYSB2YXJpYWJsZXM6IGBsYWJlbCA9ICJ2YXIiYCBvIHVzYXIgYGdlb20uaW5kID0gInBvaW50ImAuDQogIA0KDQoNCmBgYHtyfQ0KZnZpel9wY2FfYmlwbG90KGRhdDIucGNhLA0KICAgICAgICAgICAgICAgIGNvbC5pbmQgPSBnciwNCiAgICAgICAgICAgICAgICBwYWxldHRlID0gImpjbyIsDQogICAgICAgICAgICAgICAgYWRkRWxsaXBzZXMgPSBUUlVFLCANCiAgICAgICAgICAgICAgICBsYWJlbCA9ICJ2YXIiLA0KICAgICAgICAgICAgICAgIGNvbC52YXIgPSAiYmxhY2siLCANCiAgICAgICAgICAgICAgICByZXBlbCA9IFRSVUUsDQogICAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gIkdlbmRlciINCiAgICAgICAgICAgICAgICApDQpgYGANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBiaXBsb3RgIChpbmRpdmlkdW9zIHkgdmFyaWFibGVzIHBvciBncnVwbykNCg0KRW4gZWwgc2lndWllbnRlIGVqZW1wbG8sIHF1ZXJlbW9zIGNvbG9yZWFyIHRhbnRvIGEgaW5kaXZpZHVvcyBjb21vIHZhcmlhYmxlcyBwb3IgZ3J1cG9zLiBFbCB0cnVjbyBjb25zaXN0ZSBlbiB1dGlsaXphciBgcG9pbnRzaGFwZSA9IDIxYCBwYXJhIGxvcyBwdW50b3MgaW5kaXZpZHVhbGVzLiBFc3RhIGZvcm1hIGRlIHB1bnRvIGVuIHBhcnRpY3VsYXIgcHVlZGUgc2VyIHJlbGxlbmFkYSBwb3IgdW4gY29sb3IgdXNhbmRvIGVsIGFyZ3VtZW50byBgZmlsbC5pbmRgLiBFbCBjb2xvciBkZSBsYSBsw61uZWEgZGUgYm9yZGUgZGUgbG9zIHB1bnRvcyBpbmRpdmlkdWFsZXMgc2UgZXN0YWJsZWNlIGVuIGAiYmxhY2siYCB1c2FuZG8gYGNvbC5pbmRgLiBQYXJhIGNvbG9yZWFyIGxhcyB2YXJpYWJsZXMgcG9yIGdydXBvcywgc2UgdXRpbGl6YXLDoSBlbCBhcmd1bWVudG8gYGNvbC52YXJgLiBQYXJhIHBlcnNvbmFsaXphciBsb3MgY29sb3JlcyBkZSBpbmRpdmlkdW9zIHkgdmFyaWFibGVzLCB1dGlsaXphbW9zIGxhcyBmdW5jaW9uZXMgYXV4aWxpYXJlcyBgZmlsbF9wYWxldHRlYCB5IGBjb2xvcl9wYWxldHRlYCBlbiBlbCBwYXF1ZXRlIGBnZ3B1YnJgLg0KDQoNCg0KYGBge3J9DQojTXlWYXJzIDwtIGZhY3RvcihjKCJTZW1BY3VtIiwiRXhhbTEiLCJFeGFtMiIsIkV4YW0zIiwiRXhhbTQiLCJFeGFtQWN1bSIsIkRlZmluaXRpdmUiLCJFeHBlbnNlIiwiSW5jb21lIiwiR2FzIikpDQpNeVZhcnMgPC0gZmFjdG9yKGMoIkV4YW0iLCJFeGFtIiwiRXhhbSIsIkV4YW0iLCJFeHBlbnNlIiwiSW5jb21lIiwiR2FzIikpDQoNCmZ2aXpfcGNhX2JpcGxvdChkYXQyLnBjYSwNCiMgTExlbmFuZG8gaW5kaXZpZHVvcyBwb3IgZ3J1cG9zDQpnZW9tLmluZCA9ICJwb2ludCIsDQpwb2ludHNoYXBlID0gMjEsDQpwb2ludHNpemUgPSAyLjUsDQpmaWxsLmluZCA9IGdyLA0KY29sLmluZCA9ICJibGFjayIsDQoNCiMgQ29sb3IgZGUgbGFzIHZhcmlhYmxlcyBwb3IgZ3J1cG9zDQpjb2wudmFyID0gTXlWYXJzLA0KbGVnZW5kLnRpdGxlID0gbGlzdChmaWxsID0gZ3JfbmFtZSwgY29sb3IgPSAiVmFyaWFibGVzIiksDQpyZXBlbCA9IFRSVUUgDQopKw0KICANCmdncHVicjo6ZmlsbF9wYWxldHRlKCJqY28iKSsgIyBDb2xvciBkZSBsb3MgaW5kaXZpZHVvcw0KICANCmdncHVicjo6Y29sb3JfcGFsZXR0ZSgibnBnIikgIyBDb2xvciBkZSBsYXMgdmFyaWFibGVzDQpgYGANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBgYmlwbG90YCAob3BjaW9uZXMgbcOhcyBjb21wbGVqYXMpDQoNClVuIGVqZW1wbG8gbcOhcyBjb21wbGVqbyBjb25zaXN0ZSBlbiBhc2lnbmFyIGNvbG9yZXMgYSBsb3MgaW5kaXZpZHVvcyBzZWfDum4gbG9zIGdydXBvcyBhIGxvcyBxdWUgcGVydGVuZWNlbiAoY29sb3JlcyBkaXNjcmV0b3MpIHkgYSBsYXMgdmFyaWFibGVzIHNlZ8O6biBzdXMgY29udHJpYnVjaW9uZXMgYSBsb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgKGNvbG9yZXMgZW4gZGVncmFkYWRvKS4gQWRlbcOhcywgY2FtYmlhcmVtb3MgbGEgdHJhbnNwYXJlbmNpYSBkZSBsYXMgdmFyaWFibGVzIHNlZ8O6biBzdXMgY29udHJpYnVjaW9uZXMgdXRpbGl6YW5kbyBlbCBhcmd1bWVudG8gYWxwaGEudmFyLg0KDQoNCmBgYHtyfQ0KZnZpel9wY2FfYmlwbG90KGRhdDIucGNhLA0KICAgICAgICAgICAgICAgICMgSW5kaXZpZHVvcw0KICAgICAgICAgICAgICAgIGdlb20uaW5kID0gInBvaW50IiwNCiAgICAgICAgICAgICAgICBmaWxsLmluZCA9IGdyLCANCiAgICAgICAgICAgICAgICBjb2wuaW5kID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICBwb2ludHNoYXBlID0gMjEsIA0KICAgICAgICAgICAgICAgIHBvaW50c2l6ZSA9IDIsDQogICAgICAgICAgICAgICAgcGFsZXR0ZSA9ICJqY28iLA0KICAgICAgICAgICAgICAgIGFkZEVsbGlwc2VzID0gVFJVRSwNCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAjIFZhcmlhYmxlcw0KICAgICAgICAgICAgICAgIGFscGhhLnZhciA9ImNvbnRyaWIiLCANCiAgICAgICAgICAgICAgICBjb2wudmFyID0gImNvbnRyaWIiLA0KICAgICAgICAgICAgICAgIHJlcGVsPVRSVUUsDQogICAgICAgICAgICAgICAgZ3JhZGllbnQuY29scyA9ICJhYWFzIiwNCiAgICAgICAgICAgICAgICBsZWdlbmQudGl0bGUgPSBsaXN0KGZpbGwgPSBncl9uYW1lLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIkNvbnRyaWIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAiQ29udHJpYiIpDQogICAgICAgICAgICAgICAgKQ0KYGBgDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBUw7NwaWNvcyBzdW1wbGVtZW50YXJpb3MgDQoNCg0KDQpbTm8gaGFjZXIgY2xpY2sgYXF1w61dKE9KT0pPSk8pOiBQZW5kaWVudGUNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBDYXDDrXR1bG8gRWplcmNpY2lvcyAtLT4NCg0KIyBFamVyY2ljaW9zDQoNCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQojIEVuIGVsIGxpYnJvIFIyMDI1IFplbHRlcm1hbiwgcGFnaW5hIDIxNCB5IDIxNywgaGF5IDIgZWplbXBsb3MgcXVlIG5vIGhlIHV0aWxpemFkbw0KDQojIEVuIGVsIGxpYnJvIFIyMDI1IFplbHRlcm1hbiwgIHBhZ2luYSAyMjMsIGhheSBtdWNob3MgZWplcmNpY2lvcyBxdWUgbm8gaGUgdXRpbGl6YWRvDQoNCiMgVmVyIGxpYnJvIGRlIEdpZ2FwZWRpYSAtLT4gTXVsdGl2YXJpYWRvIC0tPiBmYWN0b3JpYWwtLT4gUjIwMTUgUGFnZXMtTXVsdGlwbGUgRmFjdG9yIEFuYWx5c2lzIGJ5IEV4YW1wbGUgVXNpbmcgUjogIA0KICAgICAjZGF0b3MgQmFjY2FsYXVyZWF0ZSBkZSBGYWN0b01pbmVSDQpgYGANCg0KDQpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQ0KbGlicmFyeShGYWN0b01pbmVSKQ0KQmFjY2FsYXVyZWF0ZQ0KYGBgDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIEVqZXJjaWNpbyAxDQoNCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQojIEVqZW1wbG8gMi42LjEuIGRlbCBsaWJybyBkZSBNYXJ0w61uIETDrWF6LCBwYWdpbmEgNTENCmBgYA0KDQpTdXBvbmdhbW9zIHF1ZSBzZSB0aWVuZW4gNiBvYnNlcnZhY2lvbmVzICR4XzEsIFxsZG90cywgeF82JCBlbiBkb3MgZGltZW5zaW9uZXMsIGNhZGEgb2JzZXJ2YWNpw7NuIGNvcnJlc3BvbmRlDQphIHVuIHJlY3TDoW5ndWxvIHkgbGFzIHZhcmlhYmxlcyBzb24gbG9uZ2l0dWQgZGUgbGEgYmFzZSB5IGxhIGFsdHVyYSBkZWwgcmVjdMOhbmd1bG8gKHbDqWFzZSBsYSBmaWd1cmEgXEByZWYoZmlnOlJlY3Rhbmd1bG8xKSkuIA0KDQo8Y2VudGVyPg0KYGBge3IgUmVjdGFuZ3VsbzEsIGVjaG89RkFMU0UsIGZpZy5jYXAgPSAiKipSZWN0w6FuZ3VsbyoqIiwgb3V0LndpZHRoID0gIjUwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJSZWN0YW5ndWxvMS5wbmciKQ0KDQojT3RyYSBtYW5lcmEsIHBlcm8gIHNhbGUgZWwgY2FwdGlvbjoNCiM8Y2VudGVyPg0KIyFbKCNmaWc6RmlnLWNhcHRpb24pIE1pIGZpZ3VyYV0oTm9tYnJlLnBuZyl7d2lkdGg9NDAwcHh9DQojPC9jZW50ZXI+DQpgYGANCjwvY2VudGVyPg0KDQpMYSBtYXRyaXogZGUgZGF0b3MgZXM6IA0KDQokJFhcOyA9XDsgIFxiZWdpbntwbWF0cml4fQ0KIDIuMCAmIDIuMFxcIA0KIDEuNSYgMC41IFxcIA0KMC43ICYgMC41XFwgDQowLjUgJiAxLjVcXCANCiAwLjUmIDAuN1xcIA0KMC43ICYgMC43DQpcZW5ke3BtYXRyaXh9JCQNCg0KDQpDb24gZXN0b3MgZGF0b3MsIGhhbGxlOiANCg0KKGEpIExhIG1hdHJpeiAkWT0gXGxvZyAoWCkkIChsb2dhcml0bW8gY29uIGJhc2UgMTApLiBFcyBkZWNpciwgYXBsaXF1ZSBlbCBsb2dhcml0bW8gdGVuaWVuZG8gZW4gY3VlbnRhIGNhZGEgdW5hIGRlIGxhcyBjb21wb25lbnRlcyB5IGRlZmluYSBsYSBtYXRyaXogcmVzdWx0YW50ZSBjb21vICRZJC4NCg0KKGIpIExhIG1hdHJpeiAkUyQgZGUgdmFyaWFuemFzLWNvdmFyaWFuemFzIGRlICRZJC4NCg0KKGMpIExvcyB2YWxvcmVzICRcbGFtYmRhX2kkIHkgdmVjdG9yZXMgJHZfaSQgcHJvcGlvcyAgZGUgJFMkLg0KDQooZCkgTGFzIGRvcyBjb21wb25lbnRlcyAkRl8xJCB5ICRGXzIkIGV2YWx1YWRhcyBlbiBsb3Mgc2VpcyByZWN0w6FuZ3Vsb3MuIFJlY3VlcmRlIHF1ZSBjYWRhIGNvbXBvbmVudGUgICRGX2kkIHNlcsOhIHVuIHZlY3RvciBkZSBsYSBtaXNtYSBsb25naXR1ZCBkZSAkWV9pJCB5IHNlIGNhbGN1bGFyw6EgYXPDrTogDQokJEZfaSBcOz0gXDsgWSB2X2kkJA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KDQojIyMgRWplcmNpY2lvIDINCg0KYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCiMgRWplbXBsbyAyLjYuMi4gZGVsIGxpYnJvIGRlIE1hcnTDrW4gRMOtYXosIHBhZ2luYSA1Mw0KYGBgDQoNCg0KTGFzIGN1YXRybyBub3RhcyBwYXJjaWFsZXMgZGUgdW4gZGV0ZXJtaW5hZG8gY3Vyc28gZW4gdW5hIHByZXN0aWdpb3NhICB1bml2ZXJzaWRhZCBzZSBtdWVzdHJhbiBlbiBsYSB0YWJsYSBkZSBhYmFqbywgZW4gZWwgb3JkZW4NCmFsZmFiw6l0aWNvIHBvciBhcGVsbGlkb3MgZGUgbG9zIGVzdHVkaWFudGVzLiBFbCBvYmpldGl2byBlcyBzYWJlciBzaSBleGlzdGUgYWxnw7puIHRpcG8gZGUgb3JkZW5hY2nDs24gZGUgbG9zIGVzdHVkaWFudGVzIGRlIGVzdGUgZ3J1cG8sIGRpc3RpbnRvIGFsIGRlIHByb21lZGlhciBsYXMgbm90YXMgZGUgZXN0b3MgZXN0dWRpYW50ZXMuIEFwbGlxdWUgUENBIHBhcmEgZGV0ZXJtaW5hciBlc3RvLiANCg0KKipTdWdlcmVuY2lhOioqIA0KDQooYSkgSGFsbGUgbG9zIHZhbG9yZXMgZGUgbGFzIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIHBhcmEgbGFzIG5vdGFzIGRlIGxvcyAzMyBlc3R1ZGlhbnRlcy4gDQoNCihiKSBPcmRlbmUgZW4gZm9ybWEgZGVzY2VuZGVudGUgZXN0b3MgcmVzdWx0YWRvcyBwb3IgbGEgcHJpbWVyYSBjb21wb25lbnRlIHByaW5jaXBhbC4gDQoNCihjKSBDb21wYXJlIGVzdG9zIHJlc3VsdGFkb3MgY29uIGxvcyBvYnRlbmlkb3MgZW4gbGEgbm90YSBkZWZpbml0aXZhLiANCg0KDQpgYGB7cn0NCmlkID0gMTozMw0KUDEgPSBjKDIuMzAsIDMuNTAsIDQuMTAsIDUuMDAsIDIuNzAsIDIuNzAsIDIuOTAsIDIuNDAsIDMuMjAsIDMuODAsIDQuOTAsIDQuNTAsIDIuNzAsIDIuOTAsIDIuNzAsIDIuNzAsIDIuOTAsIDMuMDAsIDMuMTAsIDMuNTAsIDMuNTAsIDIuNzAsIDIuOTAsIDMuMDAsIDIuNzAsIDMuNTAsIDUuMDAsIDQuOTAsIDMuNjAsIDMuMDAsIDMuMTAsIDQuNzAsIDMuMDApDQpQMiA9IGMoMy40MCwgMy4zMCwgNC4xMCwgMy4wMCwgMi41MCwgMy4yMCwgMi44MCwgMi44MCwgMy4yMCwgMi44MCwgNC44MCwgMi44MCwgMi44MCwgMi44MCwgMi44MCwgMi42MCwgMy4zMCwgMi44MCwgMi44MCwgMi45MCwgMi42MCwgMi44MCwgMi44MCwgMi45MCwgMy40MCwgMy4wMCwgMy41MCwgMy4yMCwgMi45MCwgMi44MCwgMi44MCwgNS4wMCwgMi45MCkNClAzID0gYygyLjkwLCAzLjUwLCA0LjUwLCA0LjAwLCAyLjcwLCA0LjQwLCAyLjgwLCAyLjUwLCAyLjAwLCAzLjAwLCA1LjAwLCA0LjUwLCAyLjUwLCAyLjgwLCAyLjgwLCAyLjYwLCAzLjAwLCAyLjgwLCAyLjgwLCAzLjUwLCA0LjMwLCAyLjAwLCAyLjUwLCAyLjUwLCAgMi4wMCwgNC4wMCwgNC45MCwgMi44MCwgMi4wMCwgMy45MCwgMi4wMCwgMy44MCwgMy4zMCkNClA0ID0gYygzLjMwLCAzLjAwLCAzLjcwLCAzLjAwLCAzLjAwLCAzLjMwLCAzLjUwLCAzLjUwLCAzLjkwLCAzLjUwLCAzLjAwLCAzLjAwLCAyLjkwLCAzLjUwLCAzLjAwLCAyLjgwLCAyLjgwLCAzLjQwLCAzLjMwLCAzLjUwLCAzLjUwLCAzLjYwLCAzLjAwLCAyLjgwLCAzLjAwLCAzLjAwLCAzLjAwLCAzLjUwLCA0LjAwLCAzLjUwLCAzLjYwLCAzLjAwLCAyLjgwKQ0KRGVmID0gYygyLjk4LCAzLjMzLCA0LjEwLCAzLjc1LCAyLjczLCAzLjQwLCAzLjAwLCAyLjgwLCAzLjA4LCAzLjI4LCA0LjQzLCAzLjcwLCAyLjczLCAzLjAwLCAyLjgzLCAyLjY4LCAzLjAwLCAzLjAwLCAzLjAwLCAzLjM1LCAzLjQ4LCAyLjc4LCAyLjgwLCAyLjgwLCAyLjc4LCAzLjM4LCA0LjEwLCAzLjYwLCAzLjEzLCAzLjMwLCAyLjk4LCA0LjEzLCAzLjAwKQ0KYGBgDQoNCg0KYGBge3J9DQpkYXRvcyA8LSBkYXRhLmZyYW1lKGlkLCBQMSwgUDIsIFAzLCBQNCwgRGVmKQ0KcHJpbnQoZGF0b3MpDQpgYGANCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoNCiMjIyBFamVyY2ljaW8gMw0KDQpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQ0KIyBzZWNjacOzbiA4LjIuIGRlbCBsaWJybyBSMjAyNSBaZWx0ZXJtYW4sIHBhZ2luYSAyMTANCmBgYA0KDQpDb25zaWRlcmUgbGEgcmVjb21lbmRhY2nDs24gZGUgaW52ZXJzacOzbiBxdWUgYXBhcmVjZW4gZW4gbGEgdGFibGEgZGUgbGEgZmlndXJhIFxAcmVmKGZpZzpGaWd1cmFFamVyY2ljaW8zKS4gQ2FkYSBlbXByZXNhIGRlIGdlc3Rpw7NuIGZpbmFuY2llcmEgdGllbmUgdW4gY29uanVudG8gZGUgcG9yY2VudGFqZXMgcmVjb21lbmRhZG9zIGVuIGNhZGEgdW5vIGRlIGxvcyBvY2hvIHRpcG9zIGRlIGludmVyc2nDs24gZGlmZXJlbnRlcy4NCkVzdG9zIHN1bWFuIDEwMCUsIHBvciBsbyBxdWUgZWwgb2JqZXRpdm8gZGVsIGVqZXJjY2lvIGVzIGVuY29udHJhciB1biByZXN1bWVuIGRlIGRhdG9zIGRlIG1lbm9yIGRpbWVuc2nDs24gcXVlIHJlcHJlc2VudGUgZGljaGEgaW5mb3JtYWNpw7NuLg0KDQoNCmBgYHtyfQ0KIyBDcmVhciBlbCBkYXRhIGZyYW1lIGNvbiBsb3MgZGF0b3MgcHJvcG9yY2lvbmFkb3MNCg0KTWFuYWdlciA9IGMoIkFsbGlhbmNlIEJlcm5zdGVpbiIsICJBdGxhbnRpYyBUcnVzdCIsICJCYW5rIG9mIEFtZXJpY2EiLCAiQk5ZIE1lbGxvbiIsICJCZXNzZW1lciIsICJCcm93biBBZHZpc29yeSIsICJDaXRpIFByaXZhdGUgQmFuayIsICJDb25zdGVsbGF0aW9uIiwgIkRldXRzY2hlIEJhbmsiLCAiRmlkZWxpdHkiLCAiRmlkdWNpYXJ5IFRydXN0IiwgIkZpZnRoIFRoaXJkIEJhbmsiLCJHZW5TcHJpbmciLCAiR2xlbm1lZGUiLCAiSGFycmlzIFByaXZhdGUgQmFuayIsICJIaWdobW91bnQgQ2FwaXRhbCIsICJKYW5uZXkgTW9udGdvbWVyeSIsICJKUE1vcmdhbiIsICJMZWdnIE1hc29uIiwgIk5vcnRoZXJuIFRydXN0IiwgIlBOQyBBc3NldCBNZ210IiwgIkNoYXJsZXMgU2Nod2FiIiwgIlN1blRydXN0IiwiVUJTIiwgIlVTIEJhbmsiLCAiV2VsbHMgRmFyZ28iLCAiV2lsbWluZ3RvbiBUcnVzdCIpDQpTX1VTID0gYyg0NSwgMjgsIDUzLCAyNiwgMTksIDI5LCAxOCwgMjAsIDI5LCA0MCwgNDAsIDI4LCAxMywgMzUsIDU0LCAyNSwgNDcsIDIwLCA1NSwgMjQsIDQwLCAyOSwgMjYsIDMyLCA0MywgMjcsIDI3KQ0KU19Ob25fVVMgPSBjKDMsIDYsIDksIDksIDksIDEzLCAyNywgMTAsIDE0LCAxNCwgMTAsIDksIDgsIDEyLCAxMCwgNSwgNCwgOSwgMywgOCwgOCwgMjAsIDYsIDEwLCAxNiwgMTMsIDExKQ0KU19EZXYgPSBjKDE3LCA5LCAzLCAxMCwgMywgMTIsIDMsIDEwLCA2LCA0LCAxMywgNywgNSwgNSwgNCwgMTAsIDQsIDUsIDcsIDUsIDIsIDUsIDUsIDcsIDcsIDUsIDQpDQpCX1VTID0gYygzNSwgMzAsIDI4LCAzMCwgMjAsIDE5LCAxOCwgMjUsIDI5LCAzNSwgMzEsIDM2LCAxOCwgMTgsIDE4LCA0MCwgMjYsIDIyLCAxNywgMzEsIDMwLCAyOSwgMjUsIDI3LCAyMSwgMjEsIDMxKQ0KQl9Ob25fVVMgPSBjKDAsIDMsIDEsIDAsIDQsIDMsIDE2LCA1LCAyLCAyLCAwLCAwLCA4LCAyLCAwLCA1LCA0LCAzLCAwLCAwLCAwLCAxLCA3LCA2LCAzLCA0LCAxKQ0KQl9EZXYgPSBjKDAsIDAsIDEsIDAsIDUsIDAsIDEsIDAsIDQsIDAsIDAsIDAsIDAsIDMsIDAsIDAsIDUsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDIsIDApDQpBbHRlcm5hdGl2ZSA9IGMoMCwgMjQsIDAsIDI1LCAzNCwgMjAsIDE3LCAzMCwgMTcsIDYsIDUsIDE1LCA0NSwgMjMsIDE1LCAxNSwgMTAsIDM4LCAxNSwgMzIsIDIwLCAxMSwgMzAsIDE3LCAxMCwgMjgsIDI3KQ0KQ2FzaCA9IGMoMCwgMCwgNSwgMCwgNiwgNCwgMCwgMCwgMiwgMCwgMiwgNSwgNSwgMiwgMCwgMCwgMCwgMywgMywgMCwgMCwgNSwgMywgMiwgMCwgMCwgMCkNCg0KIyBDcmVhciBlbCBkYXRhIGZyYW1lDQppbnZlc3QgPC0gZGF0YS5mcmFtZShNYW5hZ2VyLCBTX1VTLCBTX05vbl9VUywgU19EZXYsIEJfVVMsIEJfTm9uX1VTLCBCX0RldiwgQWx0ZXJuYXRpdmUsIENhc2gpDQoNCmBgYA0KDQo8Y2VudGVyPg0KYGBge3IgRmlndXJhRWplcmNpY2lvMywgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKkFzaWduYWNpb25lcyBkZSBpbnZlcnNpw7NuIHJlY29tZW5kYWRhcyAoZW4gJSkgcG9yIGxhcyBlbXByZXNhcyBkZSBnZXN0acOzbiBmaW5hbmNpZXJhcyBhIHByaW5jaXBpb3MgZGUgMjAxMSoqIiwgb3V0LndpZHRoID0gIjcwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJUYWJsYTFfNV9wMjEwX1IyMDE1X1plbHRlcm1hbi5wbmciKQ0KDQojT3RyYSBtYW5lcmEsIHBlcm8gIHNhbGUgZWwgY2FwdGlvbjoNCiM8Y2VudGVyPg0KIyFbKCNmaWc6RmlnLWNhcHRpb24pIE1pIGZpZ3VyYV0oTm9tYnJlLnBuZyl7d2lkdGg9NDAwcHh9DQojPC9jZW50ZXI+DQpgYGANCjwvY2VudGVyPg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCg0KIyMjIEVqZXJjaWNpbyA0DQoNCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQojIHNlY2Npw7NuIDguMS4gZGVsIGxpYnJvIFIyMDI1IFplbHRlcm1hbiwgcGFnaW5hIDIyMw0KYGBgDQoNCkNvbnNpZGVyZSBudWV2YW1lbnRlIGxvcyBkYXRvcyBkZWwgZWplcmNpY2lvIGFudGVyaW9yLiANCg0KKGEpIEhhZ2EgdW4gYmlwbG90IGRlIGxhcyBkb3MgcHJpbWVyYXMgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgZGUgcmVjb21lbmRhY2lvbmVzIGRlIGludmVyc2nDs24uIE9ic2VydmUgcXVlIExlZ2cgTWFzb24gKExNKSB5DQpIYXJyaXMgKEhQQikgYXBhcmVjZW4gZW4gbGEgcGFydGUgc3VwZXJpb3IgeSBIaWdobW91bnQgKEhDKSBlbiBsYSBpbmZlcmlvciBhYmFqbyAocG9yIGxvIG1lbm9zIGEgbcOtIG1lIGFwYXJlY2UgYXPDrSkuIMK/QSBxdcOpIHNlIGRlYmU/IMK/UXXDqSByZXByZXNlbnRhIGVsIHNlZ3VuZG8gY29tcG9uZW50ZSBwcmluY2lwYWwgZWwgZWplIHZlcnRpY2FsPw0KDQooYikgSGFsbGUgbG9zIHZhbG9yZXMgcHJvcGlvcyB5IGxvcyB2ZWN0b3JlcyBwcm9waW9zIGRlIGxhIG1hdHJpeiBkZSBjb3JyZWxhY2nDs24gZGUgbG9zIGRhdG9zIGRlIHJlY29tZW5kYWNpw7NuIGRlIGludmVyc2nDs24uIA0KDQooYykgTXVlc3RyZSBxdWUgbG9zIHZlY3RvcmVzIHByb3Bpb3MgcmVwcmVzZW50YW4gbGFzIHZhcmlhbnphcyBkZSBsb3MgY29tcG9uZW50ZXMgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgZGUgbGEgbWF0cml6IGRlIGNvcnJlbGFjaW9uZXMgeSB2ZXJpZmlxdWUgcXVlIHNvbiBpZ3VhbGVzIGEgbG9zIHZhbG9yZXMgb2J0ZW5pZG9zIGRlIGxvcyBjb21wb25lbnRlcyBwcmluY2lwYWxlcy4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIEVqZXJjaWNpbyA1DQoNCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQojIHNlY2Npw7NuIDguMy4gZGVsIGxpYnJvIFIyMDI1IFplbHRlcm1hbiwgcGFnaW5hIDIyNQ0KIyBMb3MgZGF0b3Mgc29uIHV0aWxpemFkb3MgZW4gZWwgbGlicm8gZGUgS2Fzc2FtYmFyYQ0KYGBgDQoNCkxvcyBzaWd1aWVudGVzIGRhdG9zIGRlc2NyaWJlbiBlbCByZW5kaW1pZW50byBkZSBsb3MgYXRsZXRhcyBkdXJhbnRlIGRvcyBldmVudG9zIGRlcG9ydGl2b3MgKERlc2N0YXIgeSBPbHltcGljRykuIENvbnRpZW5lIDI3IGluZGl2aWR1b3MgKGF0bGV0YXMpIGRlc2NyaXRvcyBtZWRpYW50ZSAxMyB2YXJpYWJsZXMuIFNlIHJlc2FsdGEgcXVlIHPDs2xvIGFsZ3Vub3MgZGUgZXN0b3MgaW5kaXZpZHVvcyB5IHZhcmlhYmxlcyBzZSB1dGlsaXphcsOhbiBwYXJhIHJlYWxpemFyIGVsIGFuw6FsaXNpcyBkZSBjb21wb25lbnRlcyBwcmluY2lwYWxlcy4gDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGF0b3MgPC0gZmFjdG9leHRyYTo6ZGVjYXRobG9uMg0KYXR0YWNoKGRhdG9zKQ0KZGF0IDwtIGRhdG9zWzE6MjMsIDE6MTBdDQpgYGANCg0KDQpDb24gZXN0b3MgZGF0b3MgbGxldmFyIGEgY2FibyB1biBQQ0EuIA0KDQooYSkgQ29taWVuY2UgZXhhbWluYW5kbyBsYXMgZGVzdmlhY2lvbmVzIGVzdMOhbmRhciBkZSBjYWRhIHZhcmlhYmxlLg0KDQooYikgUmVhbGljZSB1biBhbsOhbGlzaXMgZGUgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgZGUgZXN0b3MgZGF0b3MgeSBvYnNlcnZlIGVsIGJpcGxvdC4gSW50ZXJwcmV0ZSBsYXMgY2FyZ2FzIGRlIGxvcyBkb3MgcHJpbWVyb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMuICDCv0VzdMOhbiBmdWVydGVtZW50ZSBwb25kZXJhZG9zIGhhY2lhIGxhcyBtYXlvcmVzIGRlc3ZpYWNpb25lcyBlc3TDoW5kYXIgZW5jb250cmFkYXMgZW4gbGEgcGFydGUgKGEpPw0KDQooYykgUmVwaXRhIGVsIGFuw6FsaXNpcyBkZSBjb21wb25lbnRlcyBwcmluY2lwYWxlcyBlbiBsYSBtYXRyaXogZGUgY29ycmVsYWNpw7NuIGVzY2FsYWRhIGRlIGxvcyBkYXRvcy4gwr9Dw7NtbyBpbnRlcnByZXRhIGVzdGUNCmJpcGxvdD8NCg0KKGQpIMK/UXXDqSBhbsOhbGlzaXMgbGUgcGFyZWNlIG3DoXMgw7p0aWw6IGVsIGFuw6FsaXNpcyBkZSBjb21wb25lbnRlcyBwcmluY2lwYWxlcyBlc2NhbGFkbyBvIHNpbiBlc2NhbGEgcGFyYSBlc3RvcyBkYXRvcz8NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KDQojIyMgRWplcmNpY2lvIDYNCg0KYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCiMgc2VjY2nDs24gOC41LiBkZWwgbGlicm8gUjIwMjUgWmVsdGVybWFuLCBwYWdpbmEgMjI2DQpgYGANCg0KRXhhbWluZSBsb3MgZGF0b3MgZGUgYFVTSnVkZ2VSYXRpbmdzYCBlbiBsYSBsaWJyZXLDrWEgYGRhdGFzZXRzYC4gRXN0ZSBjb25qdW50byBkZSBkYXRvcyBjb250aWVuZSBsYXMgdmFsb3JhY2lvbmVzIGRlIDQzIGp1ZWNlcyBkZSB0cmlidW5hbGVzIHN1cGVyaW9yZXMgZGUgRUUuVVUuIHBvciBwYXJ0ZSBkZSBhYm9nYWRvcy4gQ2FkYSB1bm8gZGUgbG9zIGp1ZWNlcyBlcyBldmFsdWFkbyBlbiBmdW5jacOzbiBkZSAxMiBhdHJpYnV0b3MsIGNvbW8NCmF0cmlidXRvcyBjb21vIGxhIGNvbmR1Y3RhLCBsYSBwcmVwYXJhY2nDs24gcGFyYSBlbCBqdWljaW8sIGxhIHNvbGlkZXogZGUgbGFzIHNlbnRlbmNpYXMgeSBlbCBuw7ptZXJvIGRlIGNvbnRhY3RvcyBxdWUgY2FkYSBhYm9nYWRvIHR1dm8gY29uIGVsIGp1ZXouIENvbnN1bHRlIGVsIGFyY2hpdm8gZGUgYXl1ZGEgZGUgYFJgIHBhcmEgbcOhcyBpbmZvcm1hY2nDs24gc29icmUgZXN0ZSBjb25qdW50byBkZSBkYXRvcy4NCg0KYGBge3J9DQpsaWJyYXJ5KGRhdGFzZXRzKQ0KaGVhZChVU0p1ZGdlUmF0aW5ncykNCmBgYA0KDQooYSkgRXhhbWluZSBlbCBkaWFncmFtYSBkZSBkaXNwZXJzacOzbiBwb3IgcGFyZXMgZGUgZXN0b3MgZGF0b3MgKGNvbiBlbCBjb21hbmRvIGBwYWlyc2ApIHBhcmEgcmV2ZWxhciBxdWUgYWxndW5hcyB2YXJpYWJsZXMgZXN0w6FuIG11eSBjb3JyZWxhY2lvbmFkYXMuDQoNCmBgYHtyfQ0KcGFpcnMoVVNKdWRnZVJhdGluZ3MpDQpgYGANCg0KDQooYikgUmVhbGljZSB1biBhbsOhbGlzaXMgZGUgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgcGFyYSBlc3RvcyBkYXRvcy4gTG9zIGRvcyBwcmltZXJvcyBjb21wb25lbnRlcyBkZSBleHBsaWNhbiBlbCA5NCUgZGUgbGEgdmFyaWFiaWxpZGFkLiBFbCBzZWd1bmRvIGNvbXBvbmVudGUgZXMgY2FzaSB0b3RhbG1lbnRlIGVsIG7Dum1lcm8gZGUgY29udGFjdG9zLCB5IGVsIHByaW1lciBjb21wb25lbnRlIGVzIGVzZW5jaWFsbWVudGUgdG9kYXMgbGFzIGRlbcOhcyB2YXJpYWJsZXMsIHRvZGFzIGNvbiBlbCBtaXNtbyBwZXNvLiBJbnRlcnByZXRlIGVzdGUgcmVzdWx0YWRvLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoNCiMjIyBFamVyY2ljaW8gNw0KDQpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQ0KIyBzZWNjacOzbiA4LjYuIGRlbCBsaWJybyBSMjAyNSBaZWx0ZXJtYW4sIHBhZ2luYSAyMjYNCmBgYA0KDQpTZSBhZG1pbmlzdHJhcm9uIHNlaXMgcHJ1ZWJhcyBkaWZlcmVudGVzIGRlIGludGVsaWdlbmNpYSB5IGNhcGFjaWRhZCBhIDExMiBwZXJzb25hcy4gTGEgbWF0cml6IGRlIGNvdmFyaWFuemEgKHBlcm8gbm8gbG9zIGRhdG9zIG9yaWdpbmFsZXMpIGRlIGxvcyByZXN1bHRhZG9zIGRlIGxhcyBwcnVlYmFzIHNlIGVuY3VlbnRyYSBlbiBgYWJpbGl0eS5jb3ZgIGVuIGxhIGxpYnJlcsOtYSBgZGF0YXNldHNgLiANCg0KYGBge3J9DQpsaWJyYXJ5KGRhdGFzZXRzKQ0KYWJpbGl0eS5jb3YNCmBgYA0KDQpMYXMgc2VpcyBwcnVlYmFzIHNlIGRlbm9taW5hbjogIGBnZW5lcmFsYCwgYHBpY3R1cmVgLCBgYmxvY2tzYCwgYG1hemVgIChsYWJlcmludG8pLCBgcmVhZGluZ2AgeSBgdm9jYWJ1bGFyeWAuIEVuIGVsIGFyY2hpdm8gZGUgYXl1ZGEgZGUgUiBwdWVkZSBlbmNvbnRyYXIgbcOhcyBpbmZvcm1hY2nDs24uDQoNCihhKSBSZWFsaWNlIHVuIGFuw6FsaXNpcyBkZSBjb21wb25lbnRlcyBwcmluY2lwYWxlcyB1dGlsaXphbmRvIGxhIG1hdHJpeiBkZSBjb3ZhcmlhbnphIGUgaWRlbnRpZmlxdWUgbGFzIHZhcmlhYmxlcyBxdWUgY29udHJpYnV5ZW4gZW4gbWF5b3IgbWVkaWRhIGEgbG9zIGRvcyBwcmltZXJvcyBjb21wb25lbnRlcyBwcmluY2lwYWxlcy4gwr9Dw7NtbyBpbnRlcnByZXRhIGVzdG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzPw0KDQoNCmBgYHtyLCBlY2hvPSBGQUxTRSwgZXZhbD1GQUxTRX0NCiNsaWJyYXJ5KEZhY3RvTWluZVIpDQpyZXMucGNhIDwtIFBDQShhYmlsaXR5LmNvdiwgc2NhbGUudW5pdCA9IFRSVUUsIGdyYXBoID0gRkFMU0UpDQpyZXMucGNhDQpgYGANCg0KKGIpIENvbnZpZXJ0YSAgbGFzIGNvdmFyaWFuemFzIGVuIG1hdHJpY2VzIGRlIGNvcnJlbGFjacOzbiwgY29uIGF5dWRhIGRlIGxhIGZ1bmNpw7NuICBgY292MmNvcmAuIA0KDQpgYGB7cn0NCmFiaWxpdHkuY29yIDwtIGNvdjJjb3IoYWJpbGl0eS5jb3YkY292KQ0KYWJpbGl0eS5jb3INCmBgYA0KDQooYykgUmVhbGljZSB1biBhbsOhbGlzaXMgZGUgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgdXRpbGl6YW5kbyBsYSBtYXRyaXogZGUgY29ycmVsYWNpb25lcy4gRXhhbWluZSBsYXMgY2FyZ2FzIGUgaW50ZXJwcmV0ZSBsb3MgZG9zIHByaW1lcm9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLiBDb21wYXJlIGVzdGUgcmVzdW1lbiBkZSBkYXRvcyBjb24gbGFzIHBhcnRlcyAoYSkgeSAoYikuIMK/RW4gcXXDqSBzZSBkaWZlcmVuY2lhbj8gZGlmaWVyZW4/IMK/RW4gcXXDqSBzZSBwYXJlY2VuPw0KDQpgYGB7ciwgZWNobz0gRkFMU0UsIGV2YWw9RkFMU0V9DQojbGlicmFyeShGYWN0b01pbmVSKQ0KcmVzLnBjYSA8LSBQQ0EoYWJpbGl0eS5jb3YsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEZBTFNFKQ0KcmVzLnBjYQ0KYGBgDQoNCihkKSDCv0NyZWUgcXVlIGVzIG3DoXMgYXByb3BpYWRvIGV4YW1pbmFyIGxhIGNvdmFyaWFuemEgbyBsYSBjb3JyZWxhY2nDs24gZW4gdW4gYW7DoWxpc2lzIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIGRlIGVzdG9zIGRhdG9zPw0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQoNCjwhLS0gQ2Fww610dWxvIEJpYmxpb2dyYWbDrWEtLT4NCg0KDQojIEJpYmxpb2dyYWbDrWEgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCiAgDQpDb25zdWx0YXIgZWwgZG9jdW1lbnRvIFtSUHVicyA6OiBBbsOhbGlzaXMgbXVsdGl2YXJpYWRvIChiaWJsaW9ncmFmw61hKV0oaHR0cHM6Ly9ycHVicy5jb20vaGxsaW5hcy9SX011bHRpdmFyaWFkb19CaWJsaW9ncmFmaWEpLg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KDQombmJzcDsNCg0KDQombmJzcDsNCjxjZW50ZXI+DQp+fn4NCklmIHlvdSBmb3VuZCBhbnkgRVJST1JTIG9yIGhhdmUgU1VHR0VTVElPTlMsIHBsZWFzZSByZXBvcnQgdGhlbSB0byBteSBlbWFpbC4gVGhhbmtzLiAgDQp+fn4NCjwvY2VudGVyPg0KDQoNCg==