hllinas2023

1 Librerías

1.0.1 Para clúster

library(factoextra)
library(cluster)

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(ggplot2)
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(heatmaply)     #Matriz de correlaciones
library(ggcorrplot)    #Matriz de correlaciones
library(corrplot)      #Matriz de correlaciones
library(textshape)     #column_to_rownames
library(openxlsx)      #Librería para escribir archivos de Excel

2 Introducción

  1. El análisis de Cluster se refiere a un conjunto de técnicas en los métodos de interdependencia donde no se distingue entre variables dependientes e independientes.

  2. Su objetivo es formar grupos a partir de elementos, donde cada grupo está compuesto por elementos lo más similares posible entre sí y, al mismo tiempo, lo más diferentes posible de los elementos de otros grupos.

  3. La agrupación se realiza considerando las variables disponibles, y se utiliza como base para la clasificación.

  4. Por lo general, se espera que estos grupos sean mutuamente exclusivos y selectivamente exhaustivos.

  5. En el análisis de Cluster, los casos o las variables pueden ser agrupados. Es una técnica descriptiva y a veces exploratoria, pero no explicativa.

  6. La diversidad de situaciones que se presentan para utilizar este método, con numerosos casos y variables, a menudo dificulta la clasificación.

  7. Además, la variedad de formas de medir la similitud entre elementos y los diferentes procedimientos de agrupación aumentan el riesgo de conclusiones que pueden no reflejar la realidad del estudio.

  8. La representatividad de las muestras y la atención a la multicolinealidad son aspectos importantes en el análisis de Cluster.

  9. La posibilidad de influencia del analista es alta, y es común que las variables se presenten en diferentes unidades o escalas de medición, lo que sugiere la conveniencia de normalizarlas.

  10. Cuando se enfrenta multicolinealidad o un gran número de variables, lo que podría dificultar el análisis o generar redundancia en la identificación de atributos similares, es recomendable recurrir a técnicas que sinteticen la información, como el Análisis de Componentes Principales (PCA) y el Análisis Factorial (EFA).

  11. En este modelo, es prudente excluir los valores atípicos del análisis o tratarlos de manera especial.

3 Comentarios generales

3.0.1 Aplicabilidad

El análisis clúster es una tarea de clasificación y ha tenido una amplia aplicación en diversas disciplinas a lo largo del tiempo. Por ejemplo:

  1. En astronomía se utilizan para identificar y clasificar conjuntos de objetos como galaxias y supergalaxias (agrupar estrellas en el universo en base a su brillantez luminosa).

  2. En el campo del Marketing, son útiles para segmentar mercados y realizar investigaciones de mercado (crear conjuntos de consumidores según sus inclinaciones hacia productos recién lanzados).

  3. En el area financiero, se pueden categorizar las instituciones bancarias con miras a identificar las áreas más provechosas para inversiones.

  4. En Biología para identificar áreas como la taxonomía y el análisis de microarrays.

  5. En Ciencias Ambientales, donde se clasifican ríos para establecer tipologías basadas en la calidad del agua o detectar agrupaciones de municipios en una región específica que presenten patrones similares de consumo de agua, con el propósito de encontrar políticas sostenibles y áreas con consumo excesivo para abordar problemas potenciales.

  6. En Psicología, Sociología, Economía, Ingeniería, entre otros campos, estas técnicas también se aplican de manera efectiva para diversos propósitos.

3.0.2 Técnica de agrupación de variables y de casos

Como técnica de agrupación de variables.

  1. El análisis de clúster guarda similitudes con el análisis factorial.

  2. Sin embargo, mientras que el análisis factorial puede ser rígido en algunos de sus supuestos, como la linealidad, la normalidad y la necesidad de variables cuantitativas, y tiende a estimar la matriz de distancias de manera uniforme, el análisis de clúster es menos restrictivo en sus supuestos.

  3. El análisis de clúster no requiere linealidad ni simetría, y puede manejar variables categóricas.

  4. Además, ofrece una variedad de métodos para estimar la matriz de distancias.

Como técnica de agrupación de casos.

  1. El análisis de clúster es similar al análisis discriminante.

  2. Sin embargo, mientras que el análisis discriminante se enfoca en agrupar variables y clasificar los casos utilizando un criterio o variable dependiente (los grupos de clasificación), el análisis de clúster se centra en agrupar objetos.

  3. Es decir, identifica el número óptimo de grupos y su composición basándose únicamente en la similitud entre los casos.

  4. Además, el análisis de clúster no asume una distribución específica para las variables.

3.0.3 Inconvenientes del Análisis Clúster

  1. Este tipo de análisis se centra en la descripción y comprensión de los datos en lugar de realizar inferencias o aplicar teorías específicas.

  2. Suele emplearse como un enfoque exploratorio.

  3. Lo anterior implica que no proporciona respuestas definitivas; más bien, las soluciones son variadas y dependen tanto de las variables examinadas como del método de análisis de clúster utilizado.

4 Medidas de distancia para agrupamiento

Para el agrupamiento de los individuos (u objetos) se utilizan medidas de distancia, que se pueden clasificar de la siguiente manera:

  1. Medidas basadas en correlaciones (Predominan los patrones de variación).

  2. Medidas basadas en distancias geométricas (Predominan los patrones de medición).

  3. Medidas basadas en índices de similitud.

Véase la Figura 4.1. A continuación se explicarán cada una de ellas.

**Medidas de distancias para agrupamiento**

Figure 4.1: Medidas de distancias para agrupamiento

5 Distancias basadas en correlaciones

5.0.1 Correlaciones: descripción

  1. Predominan los patrones de variación. Esta predominancia de patrones de variación se refleja en las medidas de correlación.

  2. Estas medidas son principalmente cuantitativas, aunque también es posible calcular coeficientes de correlación para variables no métricas, como las ordinales o nominales, como los coeficientes de correlación de Spearman o Kendall.

  3. En un conjunto de variables, dos objetos se consideran muy similares si tienen correlaciones altas y poco similares si tienen correlaciones bajas.

  4. Es importante señalar que la correlación proporciona información sobre cómo varían dos variables, más que sobre la magnitud de las mismas.

  5. La distancia basada en correlaciones se define restando el coeficiente de correlación de 1.

  6. Se pueden usar diferentes tipos de métodos de correlación, como las que se explican en la siguiente sección.

5.0.2 Correlaciones: tipos

Hay varios tipos de distancias:

  1. Pearson.

  2. Coseno de Eisen.

  3. Spearman.

  4. Kendall.

Véase la Figura 5.1. A continuación se explicarán cada una de ellas.

**Medidas de distancias para agrupamiento (basada en correlaciones)**

Figure 5.1: Medidas de distancias para agrupamiento (basada en correlaciones)

6 Pearson

6.0.1 Pearson: correlación

La correlación de Pearson mide el grado de relación lineal entre dos perfiles y se define como:

\[r_{\text{pear}}(x, y) \; =\; \frac{\sum\limits_{i=1}^{n}(x_i - \bar{x})(y_i - \bar{y})}{\sqrt{\sum\limits_{i=1}^{n}(x_i - \bar{x})^2 \sum\limits_{i=1}^{n}(y_i - \bar{y})^2}}\]

En la fórmula anterior:

  1. \(x\) e \(y\) son dos vectores de longitud \(n\).

  2. \(\bar{x}\) y \(\bar{y}\) representan las medias de \(x\) e \(y\), respectivamente.

  3. Gráficamente, la correlación puede visualizarse de varias maneras. Mostraré brevemente las más importantes.

6.0.2 Pearson: heatmap

Primera forma:

Usando ggcorrplot::ggcorrplot.

library(ggplot2)
library(ggcorrplot)

ggcorrplot::ggcorrplot(cor(mtcars))

Segunda forma:

Usando heatmap::heatmaply_cor.

library(heatmaply)

heatmaply_cor(x = cor(mtcars),
              xlab = "Features",
              ylab = "Features",
              k_col = 2,
              k_row = 2)

6.0.3 Pearson: distancia

La distancia basada en la correlación de Pearson se define como:

\[d_{\text{pear}}(x, y) \; =\; 1 \; -\; r_{\text{pear}}(x, y)\]

7 Coseno de Eisen

Es un caso especial de la correlación de Pearson con \(\bar{x}\) y \(\bar{y}\) (reemplazados ambos por cero):

\[ d_{\text{eisen}}(x, y) \;=\; 1 \;-\; \frac{\sum\limits_{i=1}^{n} x_i y_i}{\sqrt{\sum\limits_{i=1}^{n} x_i^2} \sqrt{\sum\limits_{i=1}^{n} y_i^2}}\]

8 Spearman

8.0.1 Spearman: correlación

El coeficiente de correlación de Spearman se calcula así:

\[r_{\text{spear}} \;=\;\frac{\sum\limits_{i=1}^{n} (x'_i - \bar{x}') (y'_i - \bar{y}')}{\sqrt{\sum\limits_{i=1}^{n} (x'_i - \bar{x}')^2} \sqrt{\sum\limits_{i=1}^{n} (y'_i - \bar{y}')^2}} \;\approx\; 1 \,-\, \frac{6\sum\limits_{i=1}^n d_i^2}{n(n^2\,-\, 1)}\]

donde

\[x'_i = \text{rank}(x_i), \qquad y'_i = \text{rank}(y_i)\]

y \(d_i = x'_i-y'_i\) es la diferencia de rangos entre las dos variables.

8.0.2 Spearman: distancia

Con lo anterior, la distancia de correlación de Spearman se calcula así:

\[ d_{\text{spear}}(x, y) \;=\; 1 \;-\; r_{\text{spear}} \]

8.0.3 Spearman: ejemplo

Medimos el tiempo de reacción de 8 jugadores de videos juegos y les preguntamos su edad. Nuestro objetivo es calcular la correlación de rangos de Spearman. Para esto, asignamos un rango a cada individuo tanto para el tiempo de reacción como para la edad. La situación se muetra en la Figura 8.1.

**Situación para calcular la correlación  de Spearman**

Figure 8.1: Situación para calcular la correlación de Spearman

Dado que el tiempo de reacción ya está ordenado por tamaño, asignamos el rango 1 al valor más pequeño (12), el rango 2 al segundo valor más pequeño (15), y así sucesivamente. Llevamos a cabo el mismo procedimiento para asignar rangos a las edades. Sabiendo que los promedios de los rangos son iguales a 4.5, entonces,

\[r_{\text{spear}} \;\approx\; 1 \,-\, \frac{6\sum\limits_{i=1}^n d_i^2}{n(n^2\,-\, 1)} \;=\;1 \,-\, \frac{(6)(8)}{8(64\,-\, 1)} \;=\; 1 \,-\,\frac{48}{504} \;=\; 0.905\]

Por esta razon,

\[ d_{\text{spear}}(x, y) \;=\; 1 \;-\; 0.905 \;=\; 0.095 \]

9 Kendall

9.0.1 Kendall: combinaciones

El método de correlación de Kendall mide la correspondencia entre el rango de las variables \(x\) e \(y\). Si \(n\) es el tamaño de \(x\) e \(y\), entonces, el número total de combinaciones posibles de \(x\) con las observaciones \(y\) es:

\[{n\choose 2} \; =\; \frac{1}{2}n(n-1)\]

9.0.2 Kendall: correlacion

Se comienza ordenando los pares por los valores de \(x\). Si \(x\) e \(y\) están correlacionados, entonces tendrían los mismos órdenes de rango relativos. Ahora, para cada \(y_i\), se cuenta el número de \(y_j > y_i\) (pares concordantes \(c\)) y el número de \(y_j < y_i\) (pares discordantes \(d\)). Con lo anterior, se define el coeficiente de correlación \(\tau\) de Kendall como:

\[\tau \; =\; \frac{n_c - n_d}{\frac{1}{2}n(n-1)}\]

9.0.3 Kendall: distancia

La distancia de correlación de Kendall se define de la siguiente manera:

\[d_{\text{kend}}(x, y) \;=\; 1 \;-\; \tau\]

Donde:

  • \(n_c\): número total de pares concordantes.

  • \(n_d\): número total de pares discordantes.

  • \(n\): tamaño de \(x\) e \(y\).

9.0.4 Kendall: ejemplo

Imaginemos que un doctor y una doctora evalúan a 6 pacientes en términos de salud física, ordenándolos de manera descendente.

En este caso, consideramos que la doctora actúa como referencia y los pacientes se numeran del 1 al 6 según su clasificación por la doctora.

La situación se ilustra en la Figura 9.1.

**Situación para calcular la correlación  de Kendall**

Figure 9.1: Situación para calcular la correlación de Kendall

  1. Esto nos permite comparar los rangos asignados por ambos doctores.

  2. Por ejemplo, si un paciente está clasificado como el segundo por la doctora, pero como el primero por el doctor.

  3. Nos interesa determinar si hay una correlación entre estas dos evaluaciones utilizando la \(\tau\) de Kendall.

  4. Para calcularla, solo necesitamos los rangos asignados por el médico.

  5. A partir de aquí, es sencillo determinar el número de pares concordantes y discordantes.

  6. En nuestro ejemplo, encontramos un total de \(n_c=11\) pares concordantes y \(n_d=4\) pares discordantes.

  7. Por lo tanto, el coeficiente de correlación de Kendall y la distancia correspondiente son respectivamente:

\[\tau \; =\; \frac{11 \,-\, 4}{\frac{1}{2}6(6-1)} \;\; \frac{7}{15}\; =\; 0.47, \qquad d_{\text{kend}}(x, y) \;=\; 1 \;-\; 0.47\;=\; 0.53\]

10 Distancias basadas en correlaciones: observaciones

Es importante tener en cuenta que:

  1. El análisis de correlación de Pearson es el método más comúnmente utilizado.

  2. También se conoce como correlación paramétrica y depende de la distribución de los datos.

  3. Las correlaciones de Kendall y Spearman son no paramétricas y se utilizan para realizar análisis de correlación basados en rangos.

  4. La correlación de Kendall debe preferirse a la correlación de Spearman cuando hay muy pocos datos y muchos empates de rango.

  5. Como ya se comentó antes, a diferencia del coeficiente de correlación de Pearson, la correlación de Kendall es una medida de correlación no paramétrica. Para calcular la correlación de Kendall, los datos deben estar distribuidos de forma no normal y las dos variables deben estar en una escala ordinal.

11 Medidas basadas en distancias geométricas

11.0.1 Medidas de distancias: descripción

  1. Los patrones de medición predominan en las medidas de distancia, y son las más utilizadas.

  2. Sea dada una población o muestra de elementos definidos por un conjunto de variables.

  3. Representemos con \(d(x,y)\) la distancia entre dos elementos cualesquiera \(x\) y \(y\) de la población (o muestra).

  4. La distancia \(d\) debe cumplir ciertas condiciones:

    1. No negatividad: \(d(x,y) \geq 0\).

    2. Reflexividad: \(d(x,y) = d(y,x)\).

    3. Desigualdad triangular: Si \(w\) es otro vector del mismo espacio, entonces:

    \[d(x,y) \leq d(x,w) + d(w,y)\]

11.0.2 Distancias geométricas: tipos

Como medidas de distancias se tienen entre otras las siguientes:

  1. Distancia euclidiana.

  2. Distancia de Minkowski.

  3. Distancia City Block o de Manhattan.

  4. Distancia de Chebyshev.

  5. Distancia de Malahanobis.

  6. Distancia de Hamming.

Véase la Figura 11.1. A continuación se explicarán algunas de ellas.

**Medidas de distancias para agrupamiento (basada en distancias geométricas)**

Figure 11.1: Medidas de distancias para agrupamiento (basada en distancias geométricas)

11.0.3 Distancias geométricas: gráficos iniciales

Véase la Figura 11.2.

**Medidas de distancias**

Figure 11.2: Medidas de distancias

11.0.4 Distancias geométricas: comparaciones

Véase la Figura 11.3.

**Medidas de distancias**

Figure 11.3: Medidas de distancias

12 Distancia euclidiana

12.0.1 Euclidiana: descripción

  1. La distancia euclidiana es adecuada cuando se trabaja con ejes ortogonales.

  2. La distancia euclidiana entre dos puntos p y q se define como la longitud del segmento que une ambos puntos.

  3. En coordenadas cartesianas, la distancia euclidiana se calcula empleando el teorema de Pitágoras.

12.0.2 Euclidiana: Fórmula

Si tenemos dos vectores \(x\) y \(y\), definidos por los vectores \(\mathbf{x} = (x_1, x_2, \ldots, x_n)\) y \(\mathbf{b} = (y_1, y_2, \ldots, y_n)\) respectivamente, entonces la distancia euclidiana entre \(xA\) y \(y\), denotada como \(d_e(x,y)\), se calcula como:

\[d_e(x,y) = \sqrt{\sum_{i=1}^{n} (x_i - y_i)^2}\]

12.0.3 Euclidiana: bidimensional

Para el caso bidimensional, véase la Figura 12.1.

**Distancia euclidiana**

Figure 12.1: Distancia euclidiana

13 Distancia de Minkowski

13.0.1 Minkowski: descripción

  1. La distancia de Mikowski representa la distancia entre dos puntos con un recorrido perpendicular (segmentos de rectas paralelos a los ejes coordenados).

  2. En muchos casos proporciona resultados similares a los de la distancia euclidiana.

13.0.2 Minkowski: Fórmula

Si consideramos los elementos \(x\) y \(y\) mencionados anteriormente, la distancia de Mikowski entre \(x\) y \(y\), denotada como \(d_m(x,y)\), se calcula como:

\[ d_m(x,y;p) \;=\; \left( \sum_{i=1}^{n} |x_i - y_i|^p \right)^{1/p}, \quad p \geq 1. \]

13.0.3 Minkowski: bidimensional

La Figura 13.1 muestra círculos unitarios (el conjunto de niveles de la función de distancia donde todos los puntos están a la distancia unitaria del centro) con varios valores de \(p\).

**Distancia de Minkowski en el plano ($n=2$) para diferentes valores de $p$**

Figure 13.1: Distancia de Minkowski en el plano (\(n=2\)) para diferentes valores de \(p\)

14 Distancia de Manhattan

14.0.1 Manhattan: descripción

  1. La fórmula de la distancia euclidiana es útil para calcular distancias teóricas, pero en entornos urbanos reales, como una ciudad, rara vez es posible moverse de un punto a otro en línea recta debido a obstáculos como cercas, edificios y calles.

  2. En cambio, debemos seguir rutas trazadas por calles, que generalmente forman una cuadrícula. En este contexto urbano, la distancia Manhattan resulta más práctica, ya que permite calcular la distancia entre dos puntos en una cuadrícula uniforme, como las cuadras de una ciudad o un tablero de ajedrez.

  3. Esta medida es especialmente útil en entornos urbanos debido a la disposición de las calles en forma de cuadrícula, como es el caso de muchas áreas de la isla de Manhattan (véase la Figura 14.1), de ahí su nombre, aunque Broadway es una excepción a este diseño de cuadrícula.

**Isla de Manhattan**

Figure 14.1: Isla de Manhattan

14.0.2 Manhattan: fórmula

A la distancia de Minkowski se le denomina distancia City Block o de Manhattan si \(p=1\). Es decir,

\[d_{man}(x,y) \;=\; \sum_{i=1}^{n} |x_i - y_i|\]

14.0.3 Manhattan: visualización

Para una visualización, véase la Figura 14.2.

**Distancia de Manhattan**

Figure 14.2: Distancia de Manhattan

14.0.4 Manhattan: ejemplo

Se mostarrá un ejemplo gráfico de la distancia de manhattan para el caso de un sector de Barranquilla (Colombia). En ella, se compara también con la distancia euclidiana. Véase la Figura 14.3.

**Distancia de Manhattan versus euclidiana**

Figure 14.3: Distancia de Manhattan versus euclidiana

15 Distancia de Chebyshev

15.0.1 Chebyshev: fórmula

La distancia de Chebyshev se calcula como:

\[ d_{ch}(x,y) = \max_{i=1,\ldots,n} |x_i - y_i|. \]

15.0.2 Chebyshev: gráfico comparativo

En la Figura 15.1 se muestra gráficamente la comparación de las distancias de Chebyshev, euclidiana y taxicab para la hipotenusa de un triángulo 3-4-5 en un tablero de ajedrez.

**Comparación de las distancias de Chebyshev, euclidiana y taxicab para la hipotenusa de un triángulo 3-4-5 en un tablero de ajedrez.**

Figure 15.1: Comparación de las distancias de Chebyshev, euclidiana y taxicab para la hipotenusa de un triángulo 3-4-5 en un tablero de ajedrez.

15.0.3 Chebyshev: observación

En el caso límite de \(p\) (cuando alcanza el infinito), se cumple que:

\[\lim\limits_{p \,\to \, \infty} d_m(x,y;p) \; = \; d_{ch}(x,y) \]

16 Distancia de Malahanobis

16.0.1 Mahalanobis: descripción

  1. La distancia de Mahalanobis tiene una métrica diferente a la euclidiana y es recomendable para situaciones en las que hay multicolinealidad.

  2. Coincide con la distancia euclidiana para variables estandarizadas cuando las correlaciones son nulas.

16.0.2 Mahalanobis: fórmula

Si \(\Sigma\) es la matriz de varianza-covarianza, esta distancia se calcula a partir de la expresión:

\[d(x,y) = (x - y)^T \Sigma^{-1} (x - y)\]

16.0.3 Mahalanobis: gráfica

En la Figura 16.1 se muestra gráficamente diferentes distancias de Malahanobis. En ella vemos que resultan claramente patrones elípticos.

**Distancias de Malahanobis.**

Figure 16.1: Distancias de Malahanobis.

17 Medidas basadas en índices de similitud

17.0.1 Similitud: tipos

Como medidas de distancias basadas en índices de similitud se tienen, entre otras, las siguientes:

  1. ïndice de Sokal y Michener.

  2. Índice de Rogers y Tanimoto.

  3. Índice de Sokal y Sneath.

Véase la Figura 17.1. Más adelante, se explicarán estos índices.

**Medidas de distancias para agrupamiento (basada en índices de similitud)**

Figure 17.1: Medidas de distancias para agrupamiento (basada en índices de similitud)

17.0.2 Similitud: descripción

Tiene una naturaleza cualitativa y denotaremos la similitud entre \(x\) y \(y\) como \(S_{xy}\).

17.0.3 Similitud: condiciones

Las medidas de similitud deben cumplir con las siguientes codiciones:

  1. \(S_{xy} = S_{yx}\).

  2. \(S_{xx} = S_{yy}\).

  3. Si \(S_{xy}\) y \(S_{yw}\) son grandes, entonces \(S_{xw}\) también lo es.

17.0.4 Similitud: métodos de cálculo

  1. Las medidas de similitud pueden obtenerse de diversas formas, ya sea interrogando directamente a las personas sobre su percepción o midiendo las características o atributos (posesión de).

  2. Un caso particular es el uso de variables binarias, con valores 0 y 1, a partir de las cuales se construyen índices.

17.0.5 Similitud: posibilidades de coincidencia

Las posibilidades de coincidencia son:

\[\begin{align*} p & = \text{número de coincidencias positivas (1,1)} \\ n & = \text{número de coincidencias negativas (0,0)} \\ d & = \text{número de diferencias (1,0)} \\ e & = \text{número de diferencias (0,1)} \\ t & = p + n + d + e \end{align*}\]

17.0.6 Similitud: índices de coincidencias

La combinación de estas situaciones da lugar a una amplia gama de índices, según se prioricen las coincidencias positivas, negativas o las diferencias de uno u otro tipo. Algunos de estos índices son:

  1. Índice de Sokal y Michener.

\[I \;=\; \frac{{p + n}}{t} \]

  1. Índice de Rogers y Tanimoto.

\[I \;=\; \frac{{t - (d + e)}}{{t + (d + e)}} \;=\; \frac{{p + n}}{{p + n + 2(d + e)}}\]

  1. Índice de Sokal y Sneath.

\[I \;=\; \frac{p}{{p + n + 2(d + e)}}\]

18 ¿Cuál distancia escoger?

  1. La selección de medidas de distancia es fundamental, ya que ejerce una fuerte influencia en los resultados de agrupamiento.

  2. En la mayoría de los software de agrupamiento convencionales, la medida de distancia por defecto es la euclidiana.

  3. Sin embargo, según el tipo de datos y las interrogantes del investigador, es posible que se prefieran otras medidas de disimilitud.

  4. Por ejemplo, en el análisis de datos de expresión génica se recurre frecuentemente a la distancia basada en correlación.

  5. Esta medida de distancia basada en correlación considera dos elementos como similares si sus características están altamente correlacionadas, incluso si los valores observados difieren significativamente en términos de distancia euclidiana.

  6. De hecho, la distancia entre dos elementos es nula cuando están perfectamente correlacionados.

  7. No obstante, la correlación de Pearson puede ser bastante susceptible a valores atípicos.

  8. Aunque este aspecto no suele ser problemático al agrupar muestras, dado que se calcula la correlación entre miles de genes, sí es relevante al agrupar genes, donde es fundamental tener en cuenta la posible influencia de valores atípicos.

  9. Para mitigar este efecto, es posible emplear la correlación de Spearman en lugar de la de Pearson.

  10. Si nuestro objetivo es identificar grupos de observaciones con perfiles generales similares independientemente de sus magnitudes, es aconsejable optar por la distancia basada en correlación como medida de disimilitud.

  11. Este enfoque resulta especialmente pertinente en el análisis de datos de expresión génica, donde nos interesa considerar genes similares cuando presentan patrones de “subida” y “bajada” conjuntos.

  12. También es aplicable en el ámbito del marketing si deseamos identificar grupos de consumidores con las mismas preferencias en términos de productos, sin importar el volumen de compra.

  13. En contraposición, si se utiliza la distancia euclidiana, es probable que las observaciones con valores altos de características se agrupen entre sí, al igual que las observaciones con valores bajos de características.

19 Estandarización de datos

19.0.1 Estandarización: explicación

  1. La importancia de las medidas de distancia está estrechamente ligada a la escala en la que se toman las mediciones.

  2. Por lo tanto, es común estandarizar las variables antes de calcular las diferencias entre observaciones.

  3. Este proceso es especialmente recomendable cuando las variables se miden en escalas distintas (por ejemplo, kilogramos, kilómetros, centímetros, etc.), ya que de lo contrario, las medidas de diferencia resultantes podrían estar considerablemente afectadas.

  4. El propósito principal es lograr que las variables sean comparables. Normalmente, las variables se estandarizan para tener una desviación estándar de uno y una media de cero.

  5. La estandarización de datos es una técnica muy utilizada en el análisis de datos de expresión génica antes de realizar agrupaciones.

  6. También puede ser útil escalar los datos cuando la media y/o la desviación estándar de las variables son muy diferentes.

19.0.2 Estandarización: fórmula

Al estandarizar las variables, los datos pueden ser transformados de la siguiente manera:

\[\frac{x_i \,-\, centro(x)}{escala(x)}\]

19.0.3 Estandarización: interpretación

En la formula anterior:

  1. El centro de los datos (representado por \(x\)) puede ser tanto la media como la mediana de los valores de \(x\).

  2. La escala (representada también por \(x\)) puede tomar la forma de la desviación estándar (SD), el rango intercuartil o la MAD (desviación absoluta mediana).

  3. Tmabién existe la llamada fórmula de normalización (escala min-max):

\[\frac{x_i \,-\, \min(x)}{\max(x) \,-\, \min(x)}\]

19.0.4 Estandarización: ejemplo

Véase la Figura 19.1.

**Datos estandarizados y normalizados**

Figure 19.1: Datos estandarizados y normalizados

19.0.5 Observación

La estandarización contribuye a que los cuatro métodos de medida de distancia (Euclidiana, Manhattan, Correlación y Eisen) se vuelvan más homogéneos de lo que serían con datos no transformados.

19.0.6 Función scale en R

La función base de R, scale, puede emplearse para estandarizar los datos, operando sobre una matriz numérica y aplicando la escala a las columnas correspondientes.

19.0.7 Distancia euclidiana vs Pearson

  1. Es importante tener en cuenta que, al estandarizar los datos, se establece una relación funcional entre el coeficiente de correlación de Pearson \(r_{euc}=r(x, y)\) y la distancia euclidiana.

  2. Si \(x\) e \(y\) son dos vectores estandarizados (de tamaño \(n\)) con media cero y longitud 1, esta relación puede expresarse como:

\[d_{euc}(x, y) \;=\; \sqrt{2n\,(1 - r_{euc})}\]

  1. Por lo tanto, el resultado obtenido mediante las medidas de correlación de Pearson y las distancias euclidianas estandarizadas son comparables.

20 Procedimientos de agrupación

Para la agrupación existen dos tipos de procedimientos o métodos de clasificación:

  1. Jerárquicos.

  2. No jerárquicos.

Véase la Figura 20.1. A continuación, explicaremos cada uno de ellos.

**Procedimientos jerárquicos y no jerárquicos**

Figure 20.1: Procedimientos jerárquicos y no jerárquicos

21 Procedimientos jerárquicos

21.0.1 Jerárquico: descripción

Explicaremos ciertas directrices para definir cómo se agrupan los elementos. En este sentido, cuando se tenga una población grande, el objetivo es organizarla en una jerarquía de partes, dividiéndola en varios subconjuntos de manera que:

  1. No compartan elementos entre sí.

  2. Cada subconjunto esté contenido dentro del otro.

21.0.2 Jerárquico: observacion

El número de subgrupos generados depende del orden en el que se aborde el proceso.

21.0.3 Jerárquico: gráficos

En los enfoques jerárquicos, se emplean gráficos para simplificar la comprensión de los conjuntos de datos. Entre ellos, los más comunes destacan los dendogramas (figura 21.1) y los mapas de calor (heatmap, figura 21.2).

**Dendograma**

Figure 21.1: Dendograma

**Heatmap (mapa de calor)**

Figure 21.2: Heatmap (mapa de calor)

21.0.4 Jerárquico: tipos

Dentro de los métodos jerárquicos, se pueden identificar los siguientes procedimientos:

  1. Ascendente (o aglomerativos).

  2. Descendente (o divisivos).

Véase la Figura 21.3. A continuación, explicaremos cada uno de ellos.

**Procedimientos jerárquicos ascendentes y no ascendentes**

Figure 21.3: Procedimientos jerárquicos ascendentes y no ascendentes

22 Procedimiento jerárquico ascendente (aglomerativo)

22.0.1 Jerárquico ascendente: descripción

  1. Inicia con un número de grupos igual al de individuos disponibles (u objetos que tengamos que clasificar).

  2. En cada paso se recalculan las distancias entre los grupos existentes

  3. Estos grupos se van fusionando entre sí, agrupando a los individuos más similares basándose en un criterio específico.

  4. Finalmente, culmina con un único grupo que incluye a todos los elementos de la población.

  5. Una vez que se ha formado un grupo, no se desintegra, incluso si algún individuo tiene más afinidad con los elementos de un grupo recién formado.

22.0.2 Jerárquico ascendente: tipos

En los métodos jerárquicos ascendentes, hay varias formas de definir cómo se agrupan los elementos. Dentro de los métodos jerárquicos ascendentes más comunes, sobresalen tres en particular:

  1. Los denominados de unión.

  2. Los basados en el centroide.

  3. Los que lo hacen con base en la varianza.

23 Procedimiento jerárquico descendente

  1. El proceso implica lo opuesto al anterior.

  2. Comienza con el conjunto completo, es decir, la población, y luego se divide en subconjuntos sucesivos hasta que se alcanza un grupo que contiene un único elemento.

24 Procedimientos jerárquicos: métodos

24.0.1 Tipos de métodos

Los métodos de clasificación más comunes son:

  1. Vecino más cercano.

  2. Vecino más lejano.

  3. Vínculo medio.

  4. Centroide.

Véase la Figura 24.1. A continuación, explicaremos cada uno de ellos.

**Distancias en procedimientos jerárquicos**

Figure 24.1: Distancias en procedimientos jerárquicos

24.0.2 El vecino más cercano

  1. En este proceso, la medida de distancia entre dos conjuntos se determina por la distancia entre los elementos más próximos que pertenecen a grupos diferentes.

  2. Los dos primeros elementos a agrupar son aquellos con la distancia más pequeña entre ellos.

  3. Luego, se encuentra la siguiente distancia mínima y se agrega un tercer elemento al grupo, o bien se forma otro grupo con dos elementos.

  4. Este proceso continúa hasta que todos los elementos estén clasificados en un solo grupo.

  5. Generalmene, se utiliza la distancia euclidiana.

  6. Véase la situación gráfica que aparece en la Figura 24.2.

**Vecino más cercano**

Figure 24.2: Vecino más cercano

24.0.3 El vecino más cercano: ejemplo

  1. Considere la Figura 24.3.

  2. El objetivo es identificar el individuo (u objeto) representado por el círculo verde.

  3. Si consideramos \(k = 3\), se clasifica como un triángulo, debido a que dentro del círculo que lo contiene hay un cuadrado y dos triángulos.

  4. Por otro lado, si \(k = 5\), se clasifica como un cuadrado, dado que dentro del círculo exterior hay dos triángulos y tres cuadrados.

**Ejemplo para el vecino más cercano**

Figure 24.3: Ejemplo para el vecino más cercano

24.0.4 El vecino más lejano

  1. Esta nueva propuesta es una variante del enfoque anterior.

  2. Ahora la medida de distancia entre grupos se define como la distancia entre los dos elementos más alejados, cada uno perteneciente a un grupo diferente.

  3. Véase la situación gráfica que aparece en la Figura 24.4.

**Vecino más lejano**

Figure 24.4: Vecino más lejano

24.0.5 Vinculo medio

  1. En este contexto, el cálculo de la distancia entre grupos no se limita a solo dos elementos.

  2. Se emplea la media para determinar dicha distancia, pero este enfoque tiene varias modalidades.

  3. La media puede ser:

    1. La distancia promedio entre pares de objetos de los dos grupos, ya sea sin ponderación o ponderada según el tamaño de los grupos o

    2. El número de elementos en cada uno, especialmente cuando se trata de grupos de tamaños muy dispares.

  4. Los grupos resultantes muestran una varianza similar y generalmente pequeña.

  5. Véase la situación gráfica que aparece en la Figura 24.5.

**Vínculo medio**

Figure 24.5: Vínculo medio

24.0.6 Método del centroide

  1. El punto central de un conjunto, también conocido como centroide, se encuentra en el punto medio de un espacio de \(K\) dimensiones definido por las \(k\) variables analizadas.

  2. Conforme se agregan elementos al conjunto, tanto el número de elementos como su centroide pueden cambiar.

  3. Los enfoques que se basan en el centroide calculan la distancia entre conjuntos tomando la distancia entre sus respectivos centroides.

  4. Al centrarse en los puntos medios, los valores atípicos no afectan significativamente este método.

  5. Este enfoque tiene variaciones que pueden tener en cuenta o no el tamaño de los conjuntos (particularmente cuando los conjuntos son notablemente diferentes).

  6. Véase la situación gráfica que aparece en la Figura 24.6.

**Método del centroide**

Figure 24.6: Método del centroide

25 Procedimientos no jerárquicos

25.0.1 No jerárquicos: descripción

  1. Comienzan con un clúster que engloba a todos los elementos y en cada paso se divide el grupo más heterogéneo.

  2. El algoritmo acaba con tantos clusters (de un elemento cada uno) como objetos se hayan clasificado.

  3. A partir de un conjunto de \(n\) individuos, se requiere crear \(k\) grupos, donde \(k<n\).

  4. La elección de \(k\) es determinada por el analista basándose en experiencia previa o algún conocimiento específico del tema en estudio.

  5. En este método, los grupos se definen de antemano.

  6. Los enfoques no jerárquicos buscan alcanzar un óptimo global en lugar de subóptimos sucesivos en cada etapa de agrupación.

  7. Esto permite la reasignación de un elemento a un grupo diferente en etapas posteriores, en comparación con el grupo al que inicialmente fue asignado.

  8. Estos enfoques no jerárquicos también son conocidos como de \(k\)-medias,

25.0.2 No jerárquicos: tipos

Se distinguen por tres tipos diferentes:

  1. Umbral secuencial.

  2. Umbral paralelo.

  3. Métodos de optimización.

Véase la Figura 25.1. A continuación, explicaremos cada uno de ellos.

**Método del centroide**

Figure 25.1: Método del centroide

25.0.3 No jerárquicos: umbral secuencial

  1. Una vez que se ha seleccionado un centro para un grupo, todos los elementos de una población que se encuentren dentro de un cierto valor o umbral son asignados a dicho grupo.

  2. Este proceso se repite seleccionando nuevos centros y formando nuevos grupos. Es importante destacar que una vez que un elemento ha sido asignado a un grupo, no se considera para la asignación a otro grupo.

25.0.4 No jerárquicos: umbral Paralelo

  1. Esta opción establece varios centros de grupos desde el inicio. Los objetos se asignan a un centro dentro del umbral definido, eligiendo el centro más cercano.

  2. Las distancias pueden ajustarse a medida que avanza el proceso, o incluso pueden dejarse fuera aquellos elementos que no caigan dentro del umbral establecido para ningún centro.

25.0.5 No jerárquicos: métodos de optimización

  1. La distinción radica en su capacidad para la reasignación de objetos.

  2. Lo anterior implica que un objeto asignado a un grupo puede ser transferido a otro grupo.

26 Jerárquico vs no jerárquico

  1. Es aconsejable emplear una variedad de métodos, tanto jerárquicos como no jerárquicos, con el fin de aumentar la confiabilidad de las conclusiones alcanzadas.

  2. Dado que el principal desafío del algoritmo de \(k\)-medias radica en determinar el número óptimo de grupos, se sugiere emplear inicialmente algún método jerárquico para identificar un número de grupos que resulte razonable y coherente.

  3. Una vez establecido el número de grupos y su composición, la interpretación de cada uno de ellos se lleva a cabo mediante la consideración de las características de los elementos que los conforman.

  4. Esto implica analizar si ciertas características están más prominentemente representadas en algunos grupos que en otros, utilizando estadísticas descriptivas de las variables originales agrupadas.

  5. Este enfoque permite nombrar o clasificar los grupos, similar al análisis factorial en el caso de las variables latentes.

  6. La interpretación en el contexto de métodos no jerárquicos se enriquece aún más al recurrir a un análisis de varianza para examinar las diferencias entre los grupos.

  7. Este análisis se centra en la variabilidad pequeña dentro de los grupos y la variabilidad grande entre los grupos, lo que proporciona una comprensión más profunda de las características distintivas de cada grupo.

27 Pasos (jerárquico ascendente)

El proceso que se debe seguir en un Análisis Clúster Jerárquico ascendente se puede resumir como sigue:

Paso 1: Selección de las variables. Se aconseja que las variables tengan características similares (continuas, categóricas, etc.).

Paso 2: Detección de valores atípicos. La presencia de elementos significativamente diferentes al resto puede afectar considerablemente los resultados del análisis de clústeres.

Paso 3: Elección de una medida de similitud entre objetos y obtención de la matriz de distancias. Estas medidas ayudan a establecer los grupos iniciales en un análisis de clustering.

Paso 4: Identificar los clústeres más similares.

Paso 5: Fusionar estos dos clústeres en uno nuevo que contenga al menos dos elementos, reduciendo así en uno el número total de clústeres.

Paso 6: Calcular la distancia entre este clúster y el resto. Diferentes métodos de cálculo de distancias entre clústeres pueden conducir a agrupaciones distintas, lo que implica que no existe una agrupación única.

Paso 7: Repetir los pasos del 4 al 6 hasta que todos los elementos estén agrupados en un único clúster.

Paso 8: Puede dibujar el dendograma.

El proceso de agrupación jerárquica se puede representar visualmente mediante un dendrograma. En este diagrama, los objetos similares se conectan entre sí y su posición está determinada por el nivel de similitud o disimilitud entre ellos.

28 Ejemplo (jerárquico ascendente)

28.0.1 Datos para el ejemplo

Vamos a seguir el procedimiento descrito utilizando un ejemplo simple. Este ejemplo consta de 5 objetos (A, B, C, D, E) y 2 variables (\(X_1\), \(X_2\)). Los datos se muestran a continuación:

datos <- data.frame(
  ID = c("A", "B", "C", "D", "E"),
  x1 = c(1.0, 2.0, 4.0, 7.0, 5.0),
  x2 = c(1.0, 1.0, 5.0, 7.0, 7.0))

print(datos)
##   ID x1 x2
## 1  A  1  1
## 2  B  2  1
## 3  C  4  5
## 4  D  7  7
## 5  E  5  7

28.0.2 Pasos 1 y 2

Con ayuda del diagrama de dispersión, vemos que no hay valores atípicos.

ggplot(datos,aes(x = x1, y = x2, color=ID)) + 
                geom_point(size = 3) +
                scale_color_brewer(palette="Set1") +
                labs(x = "x1", y = "x2", 
                     title = "Diagrama de dispersión") 

28.0.3 Paso 3

Distancia euclidiana.

La medida de distancia que utilizaremos entre los objetos será la distancia euclidiana, cuya expresión se define como sigue

\[D(A, B) = \sqrt{ (x_{A_1} - x_{B_1})^2 + (x_{A_2} - x_{B_2})^2 }\]

# Función para calcular la distancia euclidiana
distancia_euclidiana <- function(x1, y1, x2, y2){sqrt((x2 - x1)^2 + (y2 - y1)^2)}

Distancia euclidiana entre A y B

Esta expresión representa la distancia euclidiana entre dos puntos \(A\) y \(B\) en un espacio bidimensional definido por las coordenadas \(x_1\) y \(x_2\). Así, por ejemplo, la distancia entre el clúster \(A\) y el clúster \(B\) es:

\[D(A, B) \;=\; \sqrt{ (2.0 - 1.0)^2 + (1.0 - 1.0)^2 } \;=\; 1.0\]

# Calcular la distancia euclidiana de A a B
distancia_AB <- distancia_euclidiana( datos$x1[datos$ID == "A"], 
                                      datos$x2[datos$ID == "A"], 
                                      datos$x1[datos$ID == "B"], 
                                      datos$x2[datos$ID == "B"] )
print(distancia_AB)
## [1] 1

Distancia euclidiana entre todos los puntos.

Calculamos la distancia Euclidiana entre todos los puntos y obtenemos la siguiente matriz de distancias Euclidianas entre los objetos:

# Calcular las distancias euclidianas entre todos los pares de puntos
distancias <- matrix(NA, nrow = nrow(datos), ncol = nrow(datos))

rownames(distancias) <- datos$ID
colnames(distancias) <- datos$ID

for (i in 1:nrow(datos)) {
      for (j in 1:nrow(datos)) {
           distancias[i, j] <- distancia_euclidiana( datos$x1[i],   
                                                     datos$x2[i],
                                                     datos$x1[j],
                                                     datos$x2[j])
                                }
                          }
distancias <- round(distancias, 2)
print(distancias)
##      A    B    C    D    E
## A 0.00 1.00 5.00 8.49 7.21
## B 1.00 0.00 4.47 7.81 6.71
## C 5.00 4.47 0.00 3.61 2.24
## D 8.49 7.81 3.61 0.00 2.00
## E 7.21 6.71 2.24 2.00 0.00
datos <- data.frame(
  ID = c("A", "B", "C", "D", "E"),
  x1 = c(1.0, 2.0, 4.0, 7.0, 5.0),
  x2 = c(1.0, 1.0, 5.0, 7.0, 7.0))

distancias <- dist(datos[, c("x1", "x2")])

library(factoextra)
fviz_dist(distancias)

Distancia euclidiana entre todos los puntos (como matriz triangular inferior).

# Calcular las distancias euclidianas entre todos los pares de puntos (matriz triangular inferior)
distancias <- matrix(NA, nrow = nrow(datos), ncol = nrow(datos))

rownames(distancias) <- datos$ID
colnames(distancias) <- datos$ID

for (i in 1:nrow(datos)) {
        for (j in 1:(i-1)) {
          distancias[i, j] <- distancia_euclidiana( datos$x1[i], 
                                                    datos$x2[i], 
                                                    datos$x1[j],
                                                    datos$x2[j] )
                            }
                          }

distancias <- round(distancias, 2)
print(distancias)
##      A    B    C  D  E
## A 0.00   NA   NA NA NA
## B 1.00   NA   NA NA NA
## C 5.00 4.47   NA NA NA
## D 8.49 7.81 3.61 NA NA
## E 7.21 6.71 2.24  2 NA

Estamos empleando el método jerárquico ascendente, por lo que inicialmente tenemos 5 clústeres, uno por cada uno de los objetos a clasificar.

28.0.4 Paso 4

Examinamos la matriz de distancias para identificar los objetos más similares, que en nuestro caso son \(A\) y \(B\), con la menor distancia (igual a 1).

28.0.5 Paso 5

Fusionamos los clústeres más similares para formar un nuevo clúster que incluye a \(A\) y \(B\). Así, se crean los clústeres: \(AB\), \(C\), \(D\) y \(E\).

28.0.6 Paso 6

Centroide de A y B.

Para determinar la distancia entre el clúster \(AB\) y los objetos \(C\), \(D\) y \(E\), empleamos el centroide como la representación del clúster \(AB\). Esto implica utilizar un punto cuyas coordenadas sean las medias de los valores de las componentes de las variables. Así, obtenemos las coordenadas del clúster \(AB\) como

\[\text{Coordenadas del centroide AB} \;=\; \left( \frac{{x_A + x_B}}{2},\, \frac{{y_A + y_B}}{2} \right) \;=\; \left( \frac{{1.0 + 2.0}}{2},\, \frac{{1.0 + 1.0}}{2} \right) \;=\; \left(1.5,\, 1.0\right)\]

Nuevos datos basados en el centroide de A y B.

La nueva tabla de datos es la siguiente:

datos <- data.frame(
  ID = c("AB", "C", "D", "E"),
  x1 = c(1.5, 4.0, 7.0, 5.0),
  x2 = c(1.0, 5.0, 7.0, 7.0))

print(datos)
##   ID  x1 x2
## 1 AB 1.5  1
## 2  C 4.0  5
## 3  D 7.0  7
## 4  E 5.0  7

28.0.7 Paso 7a

Iteramos nuevamente desde el paso 4 hasta que todos los objetos se agrupen en un único clúster.

Paso 4.

Con los nuevos datos, calculamos la matriz de distancias.

# Calcular las distancias euclidianas entre todos los pares de puntos (matriz triangular inferior)
distancias <- matrix(NA, nrow = nrow(datos), ncol = nrow(datos))

rownames(distancias) <- datos$ID
colnames(distancias) <- datos$ID

for (i in 1:nrow(datos)) {
        for (j in 1:(i-1)) {
          distancias[i, j] <- distancia_euclidiana( datos$x1[i], 
                                                    datos$x2[i], 
                                                    datos$x1[j],
                                                    datos$x2[j] )
                            }
                          }

distancias <- round(distancias, 2)
print(distancias)
##      AB    C  D  E
## AB 0.00   NA NA NA
## C  4.72   NA NA NA
## D  8.14 3.61 NA NA
## E  6.95 2.24  2 NA

Paso 5.

Identificamos que los clústeres más similares son \(D\) y \(E\), con una distancia de 2.0, los cuales se combinan en un nuevo clúster llamado \(DE\). Ahora tenemos tres clústeres: \(AB\), \(C\), \(DE\).

Paso 6.

Determinamos el centroide del nuevo clúster, el cual es el punto: \[\text{Coordenadas del centroide DE} \;=\; \left(\frac{7.0+5.0}{2},\, \frac{7.0+7.0}{2}\right) \;=\; (6.0,\, 7.0)\]

En consecuencia, actualizamos la tabla de datos:

datos <- data.frame(
  ID = c("AB", "C", "DE"),
  x1 = c(1.5, 4.0, 6.0),
  x2 = c(1.0, 5.0, 7.0))

print(datos)
##   ID  x1 x2
## 1 AB 1.5  1
## 2  C 4.0  5
## 3 DE 6.0  7

28.0.8 Paso 7b

Iteramos nuevamente desde el paso 4 hasta que todos los objetos se agrupen en un único clúster.

Paso 4.

Con los nuevos datos, calculamos la matriz de distancias.

# Calcular las distancias euclidianas entre todos los pares de puntos (matriz triangular inferior)
distancias <- matrix(NA, nrow = nrow(datos), ncol = nrow(datos))

rownames(distancias) <- datos$ID
colnames(distancias) <- datos$ID

for (i in 1:nrow(datos)) {
        for (j in 1:(i-1)) {
          distancias[i, j] <- distancia_euclidiana( datos$x1[i], 
                                                    datos$x2[i], 
                                                    datos$x1[j],
                                                    datos$x2[j] )
                            }
                          }

distancias <- round(distancias, 2)
print(distancias)
##      AB    C DE
## AB 0.00   NA NA
## C  4.72   NA NA
## DE 7.50 2.83 NA

Paso 5.

Identificamos que los clústeres más similares son \(C\) y \(DE\), con una distancia de 2.83 entre ellos. Estos se combinan para formar un nuevo clúster denominado CDE. En este punto, hemos generado dos clústeres: \(AB\) y \(CDE\).

Paso 6.

Determinamos el centroide del nuevo clúster \(CDE\) calculando las medias de las coordenadas de sus componentes:

\[\text{Coordenadas del centroide CDE} \;=\; \left(\frac{4.0+5.0+7.0}{3},\, \frac{5.0+7.0+7.0}{3}\right) \;=\; (5.3,\, 6.3)\]

Posteriormente, creamos una nueva tabla de datos.

datos <- data.frame(
  ID = c("AB", "CDE"),
  x1 = c(1.5, 5.3),
  x2 = c(1.0, 6.3))

print(datos)
##    ID  x1  x2
## 1  AB 1.5 1.0
## 2 CDE 5.3 6.3

28.0.9 Paso 7c

Iteramos nuevamente desde el paso 4 hasta que todos los objetos se agrupen en un único clúster.

Paso 4.

Con los nuevos datos, calculamos la matriz de distancias.

# Calcular las distancias euclidianas entre todos los pares de puntos (matriz triangular inferior)
distancias <- matrix(NA, nrow = nrow(datos), ncol = nrow(datos))

rownames(distancias) <- datos$ID
colnames(distancias) <- datos$ID

for (i in 1:nrow(datos)) {
        for (j in 1:(i-1)) {
          distancias[i, j] <- distancia_euclidiana( datos$x1[i], 
                                                    datos$x2[i], 
                                                    datos$x1[j],
                                                    datos$x2[j] )
                            }
                          }

distancias <- round(distancias, 2)
print(distancias)
##       AB CDE
## AB  0.00  NA
## CDE 6.52  NA

En este último paso, observamos que hay solo dos clústeres con una distancia de 6.5 entre ellos. Estos dos clústeres se fusionarán en un único clúster en el siguiente paso, lo que marcará el final del proceso.

28.0.10 Paso 8a: dendograma

A continuación, visualizaremos el proceso de fusión de manera gráfica utilizando un dendrograma.

# Cargar las librerías necesarias
library(ggplot2)
library(dendextend)

# Crear los datos
datos <- data.frame(
  ID = c("A", "B", "C", "D", "E"),
  x1 = c(1.0, 2.0, 4.0, 7.0, 5.0),
  x2 = c(1.0, 1.0, 5.0, 7.0, 7.0))

# Convertir los datos en una matriz de distancias
distancias <- dist(datos[, c("x1", "x2")])

# Calcular el dendrograma
dendrograma <- as.dendrogram(hclust(distancias))

# Establecer las etiquetas de los objetos
labels <- datos$ID

# Asignar etiquetas al dendrograma
labels(dendrograma) <- labels

# Graficar el dendrograma
plot(dendrograma, main = "Dendrograma", xlab = "Objetos", ylab = "Distancia")

29 La función hclust

29.0.1 hclust: Observaciones generales

  1. La función hclust se utiliza para realizar un agrupamiento jerárquico de un conjunto de datos. T

  2. La función hclust proporciona varios métodos que se pueden utilizar para realizar agrupamientos jerárquicos.

  3. Estos métodos determinan cómo se calculan las distancias entre los grupos en cada paso del algoritmo de agrupamiento.

  4. Estos métodos son útiles para diferentes tipos de datos y pueden conducir a diferentes estructuras de agrupamiento. La elección del método depende del tipo de datos y del objetivo del análisis.

29.0.2 hclust: métodos

Aquí están algunos de los métodos disponibles y para qué se utilizan:

1. method = complete" (también conocido como método de enlace completo).

  • Este método calcula la distancia máxima entre los puntos de los dos grupos.

  • La distancia entre dos grupos se define como la mayor distancia entre un punto del primer grupo y un punto del segundo grupo.

  • Se utiliza cuando se quiere evitar que los puntos lejanos de un grupo afecten demasiado al cálculo de la distancia entre grupos.

2. method = "single" (también conocido como método de enlace simple).

  • Este método calcula la distancia mínima entre los puntos de los dos grupos.

  • La distancia entre dos grupos se define como la menor distancia entre un punto del primer grupo y un punto del segundo grupo.

+Este método es sensible a puntos atípicos y puede generar grupos alargados.

3. method = "average" (también conocido como método de enlace promedio).

  • Este método calcula la distancia promedio entre todos los pares de puntos de los dos grupos.

  • La distancia entre dos grupos se define como el promedio de todas las distancias entre los puntos de los dos grupos.

  • Es un método más robusto que el enlace simple y menos sensible a puntos atípicos.

4. method = "ward.D" (método de Ward con la distancia al cuadrado).

  • Este método minimiza la varianza cuando se fusionan dos grupos. Utiliza la distancia al cuadrado entre los centroides de los grupos para evaluar cuánto aumentará la varianza total cuando se fusionen dos grupos.

  • Se utiliza cuando se desea que los grupos resultantes tengan una varianza mínima dentro de ellos.

5. method = "ward.D2" (método de Ward con la distancia euclidiana al cuadrado).

  • Similar a "ward.D", pero utiliza la distancia euclidiana al cuadrado entre los centroides de los grupos.

  • Su fórmula es diferente a la de "ward.D".

29.0.3 hclust: ejemplo anterior (alturas)

En el código mostrado en el paso 8b del ejemplo anterior:

1. Objeto.

La función hclust toma como entrada una matriz de distancias entre los puntos de datos y devuelve un objeto de tipo hclust, que representa la jerarquía de agrupamientos.

2. output.

  1. Se puede definir el objeto correspondiente así y obtener el output correspondiente:
hclust_obj <- hclust(distancias)
hclust_obj
## 
## Call:
## hclust(d = distancias)
## 
## Cluster method   : complete 
## Distance         : euclidean 
## Number of objects: 5

3. Alturas en el dendograma.

Con el objeto hclust_obj, se pueden obtener las alturas de los clústeres:

heights <- hclust_obj$height
heights
## [1] 1.000000 2.000000 3.605551 8.485281

29.0.4 hclust: ejemplo con otros métodos

Se puede cambiar el criterio utilizado en el análisis de conglomerados (cluster analysis) para medir la distancia entre dos grupos de datos. Por ejemplo, se puede agregar el argumento method = "ward.D" (o method = "ward.D2") dentro de la función hclust.

1. Calcular el dendrograma con el método ward.D

hclust_obj_D <- hclust(distancias, method = "ward.D")
plot(hclust_obj_D, labels = datos$ID, main = "Dendrograma", xlab = "Objetos", ylab = "Distancia")

2. Calcular el dendrograma con el método ward.D2.

hclust_obj_D2 <- hclust(distancias, method = "ward.D2")
plot(hclust_obj_D2, labels = datos$ID, main = "Dendrograma", xlab = "Objetos", ylab = "Distancia")

30 Distancias para datos numéricos

30.0.1 Base de datos

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

datosCompleto <- lsm::survey
#datosCompleto <- textshape::column_to_rownames(dat, loc=1)
#datosCompleto %>% remove_rownames %>% column_to_rownames(var="names")   #library(tidyverse)
attach(datosCompleto)
names(datosCompleto)
##  [1] "Observation"  "ID"           "Gender"       "Like"         "Age"         
##  [6] "Smoke"        "Height"       "Weight"       "BMI"          "School"      
## [11] "SES"          "Enrollment"   "Score"        "MotherHeight" "MotherAge"   
## [16] "MotherCHD"    "FatherHeight" "FatherAge"    "FatherCHD"    "Status"      
## [21] "SemAcum"      "Exam1"        "Exam2"        "Exam3"        "Exam4"       
## [26] "ExamAcum"     "Definitive"   "Expense"      "Income"       "Gas"         
## [31] "Course"       "Law"          "Economic"     "Race"         "Region"      
## [36] "EMO1"         "EMO2"         "EMO3"         "EMO4"         "EMO5"        
## [41] "GOAL1"        "GOAL2"        "GOAL3"        "Pre_STAT1"    "Pre_STAT2"   
## [46] "Pre_STAT3"    "Pre_STAT4"    "Post_STAT1"   "Post_STAT2"   "Post_STAT3"  
## [51] "Post_STAT4"   "Pre_IDARE1"   "Pre_IDARE2"   "Pre_IDARE3"   "Pre_IDARE4"  
## [56] "Pre_IDARE5"   "Post_IDARE1"  "Post_IDARE2"  "Post_IDARE3"  "Post_IDARE4" 
## [61] "Post_IDARE5"  "PSICO1"       "PSICO2"       "PSICO3"       "PSICO4"      
## [66] "PSICO5"

30.0.2 Solo datos numéricos

Solo utilizaremos algunas variables numéricas.

dat <- datosCompleto[, 21:24]
names(dat)
## [1] "SemAcum" "Exam1"   "Exam2"   "Exam3"

30.0.3 Ejemplo: muestreo

Seleccionaremos aleatoriamente solo una parte de los datos tomando 15 filas al azar de las primeras 50 filas disponibles en el conjunto de datos. Esto lo haremos utilizando la función sample. Después, normalizaremos los datos utilizando la función scale.

set.seed(123) # Semilla
ss <- sample(1:50, 15) # Tomando 15 filas aleatoriamente
df <- dat[ss, ] # Subconjunto de las 15 filas
df.scaled <- scale(df) # Estandarizando las variables
##  [1] 31 15 14  3 42 43 37 48 25 26 27  5 40 28  9
## # A tibble: 15 × 4
##    SemAcum Exam1 Exam2 Exam3
##      <dbl> <dbl> <dbl> <dbl>
##  1    4.35   1     2     2.8
##  2    4.1    2.8   2.3   3.5
##  3    3      2.7   2.3   3.3
##  4    4.15   3.4   3.6   2  
##  5    3.5    4.3   3     2.4
##  6    4.2    4     3     5  
##  7    2.7    5     3.2   2.6
##  8    3.9    4     4     1.5
##  9    2.7    2.5   3     4  
## 10    2.8    4.2   4.7   3.2
## 11    3.55   4.7   3.8   2.9
## 12    3.45   3.1   3.5   5  
## 13    4.3    3.2   1.7   1.2
## 14    2.85   3.1   3     2.9
## 15    4.3    2.5   3.3   3.8
##           SemAcum       Exam1      Exam2      Exam3
##  [1,]  1.18475533 -2.29767791 -1.3783042 -0.2479779
##  [2,]  0.79503318 -0.55014823 -1.0001110  0.3870874
##  [3,] -0.91974427 -0.64723321 -1.0001110  0.2056402
##  [4,]  0.87297761  0.03236166  0.6387263 -0.9737669
##  [5,] -0.14029997  0.90612650 -0.1176601 -0.6108724
##  [6,]  0.95092204  0.61487155 -0.1176601  1.7479417
##  [7,] -1.38741085  1.58572137  0.1344687 -0.4294251
##  [8,]  0.48325547  0.61487155  1.1429840 -1.4273850
##  [9,] -1.38741085 -0.84140318 -0.1176601  0.8407055
## [10,] -1.23152199  0.80904152  2.0254349  0.1149166
## [11,] -0.06235554  1.29446643  0.8908552 -0.1572543
## [12,] -0.21824440 -0.25889329  0.5126619  1.7479417
## [13,]  1.10681090 -0.16180830 -1.7564974 -1.6995558
## [14,] -1.15357756 -0.25889329 -0.1176601 -0.1572543
## [15,]  1.10681090 -0.84140318  0.2605331  0.6592583
## attr(,"scaled:center")
##  SemAcum    Exam1    Exam2    Exam3 
## 3.590000 3.366667 3.093333 3.073333 
## attr(,"scaled:scale")
##   SemAcum     Exam1     Exam2     Exam3 
## 0.6414827 1.0300254 0.7932453 1.1022488

30.0.4 Funciones y paquetes en R

Hay diversas funciones y paquetes en R que proporcionan opciones para calcular distancias entre pares de observaciones:

  1. La función dist, parte de la base de R y del paquete stats, se utiliza exclusivamente con datos numéricos como entrada.

  2. La función get_dist, del paquete factoextra, también requiere datos numéricos como entrada. A diferencia de la función dist estándar, esta ofrece soporte para medidas de distancia basadas en correlación, como los métodos pearson, kendall y spearman.

  3. La función daisy, del paquete cluster, es capaz de manejar otros tipos de variables, como nominales, ordinales y binarias (asimétricas). En estos casos, automáticamente emplea el coeficiente de Gower como métrica. Esta es una de las medidas de proximidad más populares para datos de tipos mixtos. Para obtener más detalles, se puede consultar la documentación de R de la función daisy (?daisy).

Todas estas funciones calculan las distancias entre las filas de los datos.

30.0.5 Distancia euclidiana

Para calcular la distancia euclidiana, se puede emplear la función dist básica de R de la siguiente manera:

dist.eucl <- dist(df.scaled, method = "euclidean") 
dist.eucl
##            1         2         3         4         5         6         7
## 2  1.9370290                                                            
## 3  2.7389205 1.7270814                                                  
## 4  3.1814260 2.2097750 2.7843293                                        
## 5  3.7068923 2.1840851 2.1132610 1.5792433                              
## 6  3.7564000 2.0030518 2.8722316 2.8853442 2.6152627                    
## 7  4.9008401 3.3584170 2.6259050 2.8412790 1.4538318 3.3488574          
## 8  4.0893693 3.0560829 3.2895203 0.9753186 1.6521402 3.4482800 2.5406630
## 9  3.3928204 2.4150322 1.1993505 3.1204570 2.5915679 2.9002783 2.7509516
## 10 5.2160554 3.8964506 3.3734404 2.8531285 2.5139246 3.4728074 2.1212246
## 11 4.4290068 2.8301554 2.8657910 1.7883004 1.1746300 2.4769852 1.5769586
## 12 3.6992566 2.2917171 2.3043624 2.9494381 2.7064102 1.5898808 3.1070098
## 13 2.6111536 2.2746898 2.9230901 2.5211598 2.5625748 3.8985331 3.8031549
## 14 3.3499101 2.2264188 1.0563607 2.3303580 1.6092768 2.9702114 1.8960293
## 15 2.3739580 1.3584312 2.4371337 1.9047163 2.5229759 1.8636789 3.6487258
##            8         9        10        11        12        13        14
## 2                                                                       
## 3                                                                       
## 4                                                                       
## 5                                                                       
## 6                                                                       
## 7                                                                       
## 8                                                                       
## 9  3.5147669                                                            
## 10 2.4770097 2.8049768                                                  
## 11 1.5608784 2.8863017 1.7216084                                        
## 12 3.4257222 1.7107459 2.6687955 2.4919931                              
## 13 3.0778438 3.9776509 4.8995584 3.5881550 4.3358414                    
## 14 2.5778175 1.1789485 2.4111186 2.1496034 2.2140293 3.1911226          
## 15 2.7644813 2.5292480 3.4063110 2.6444069 1.8286306 3.1771474 2.5016788

Es relevante notar que los valores permitidos para el parámetro method incluyen uno de los siguientes: euclidean, maximum, manhattan, canberra, binary, minkowski.

30.0.6 Distancia euclidiana como matriz

Para hacer más fácil la visualización de la información de distancia generada por la función dist, se puede redefinir el vector de distancia en una matriz utilizando la función as.matrix.

# Redefiniendo como una matriz.
# Subconjunto de las 3 primeras filas y colunas y redondeando los valores. 
round(as.matrix(dist.eucl)[1:3, 1:3], 1)
##     1   2   3
## 1 0.0 1.9 2.7
## 2 1.9 0.0 1.7
## 3 2.7 1.7 0.0

30.0.7 Distancia euclidiana: interpretación

  1. En esta matriz, cada valor indica la distancia entre objetos.

  2. Los valores en la diagonal de la matriz muestran la distancia entre un objeto y sí mismo, lo cual siempre es cero.

  3. En este conjunto de datos, las columnas representan variables.

  4. Por lo tanto, si deseamos calcular distancias entre pares de variables, primero debemos cambiar la disposición de los datos para tener las variables en las filas antes de emplear la función dist.

  5. Recuerde que, para hacer esta transposición de datos, utilizamos la función t.

30.0.8 Distancias basadas en correlaciones

Las distancias que se derivan de correlaciones son ampliamente empleadas en el análisis de datos de expresión genética. La función get_dist del paquete factoextra permite calcular estas distancias, utilizando métodos de correlación como pearson, spearman o kendall.

# Calculando
library("factoextra")
dist.cor <- get_dist(df.scaled, method = "pearson")

# Mostrando un subconjunto
round(as.matrix(dist.cor)[1:3, 1:3], 1)
##     1   2   3
## 1 0.0 0.1 1.0
## 2 0.1 0.0 0.6
## 3 1.0 0.6 0.0

31 Distancias para datos mixtos

31.0.1 Datos mixtos

df.mix <- datosCompleto[1:23, c(21:24, 36:40)]
attach(df.mix)
head(df.mix,4) 
## # A tibble: 4 × 9
##   SemAcum Exam1 Exam2 Exam3  EMO1  EMO2  EMO3  EMO4  EMO5
##     <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1    4.25   1.5   5     5       1     2     2     1     4
## 2    2.8    2.3   4.9   3.7     4     4     1     2     1
## 3    4.15   3.4   3.6   2       3     1     3     3     2
## 4    3.2    2.5   4.2   5       4     2     3     1     2
names(df.mix)
## [1] "SemAcum" "Exam1"   "Exam2"   "Exam3"   "EMO1"    "EMO2"    "EMO3"   
## [8] "EMO4"    "EMO5"

31.0.2 Structure de los datos mixtos

# Data structure
str(df.mix)
## tibble [23 × 9] (S3: tbl_df/tbl/data.frame)
##  $ SemAcum: num [1:23] 4.25 2.8 4.15 3.2 3.45 2.75 2.7 4.35 4.3 2.8 ...
##  $ Exam1  : num [1:23] 1.5 2.3 3.4 2.5 3.1 3.8 5 4 2.5 2.4 ...
##  $ Exam2  : num [1:23] 5 4.9 3.6 4.2 3.5 4.4 3 2.3 3.3 2.6 ...
##  $ Exam3  : num [1:23] 5 3.7 2 5 5 4.2 3.5 4.6 3.8 4.3 ...
##  $ EMO1   : num [1:23] 1 4 3 4 2 3 2 3 4 2 ...
##  $ EMO2   : num [1:23] 2 4 1 2 1 1 4 1 2 2 ...
##  $ EMO3   : num [1:23] 2 1 3 3 2 4 2 4 3 3 ...
##  $ EMO4   : num [1:23] 1 2 3 1 4 2 3 2 1 1 ...
##  $ EMO5   : num [1:23] 4 1 2 2 2 2 1 1 2 2 ...

31.0.3 Función cluster::daisy

La función daisy del paquete cluster ofrece una solución (la métrica de Gower) para calcular la matriz de distancias en situaciones donde los datos contienen columnas no numéricas. El código R a continuación aplica la función daisy a datos que contienen variables factor, ordenadas y numéricas.

library(cluster)
dd <- daisy(df.mix)
round(as.matrix(dd)[1:3, 1:3], 2)
##      1    2    3
## 1 0.00 5.33 5.35
## 2 5.33 0.00 4.86
## 3 5.35 4.86 0.00

32 Visualizando matrices de distancia

32.0.1 La gráfica

  1. Una manera sencilla de representar visualmente las matrices de distancia es emplear la función fviz_dist del paquete factoextra.

  2. También se pueden utilizar otros métodos especializados, como el agrupamiento jerárquico aglomerativo (agglomerative hierarchical clustering) o el mapa de calor (heatmap).

Para utilizar fviz_dist, simplemente se debe escribir:

library(factoextra)
fviz_dist(dist.eucl)

32.0.2 Interpretación

El nivel de color varía según el valor de la disimilitud entre las observaciones será:

  1. Rojo intenso si \(dist(x_i, x_j) = 0\). Es decir, si hay alta similaridad (o, baja disimilaridad).

  2. Azul intenso si \(dist(x_i, x_j) = 1\). Es decir, si hay baja similaridad.

Los objetos pertenecientes al mismo grupo se muestran en orden consecutivo.

33 Ejercicios

Pendiente

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.  
LS0tDQp0aXRsZTogIkFOw4FMSVNJUyBERSBDT05HTE9NRVJBRE9TIg0Kc3VidGl0bGU6IDxoMT4qKlRlb3LDrWEqKjwvaDE+DQoNCmF1dGhvcjogDQogIC0gbmFtZSAgICAgICAgICA6ICJEci4gcmVyLiBuYXQuIEh1bWJlcnRvIExMaW7DoXMgU29sYW5vIg0KICAgIGFmZmlsaWF0aW9uICAgOiAiRGVwYXJ0YW1lbnRvIGRlIE1hdGVtw6F0aWNhcyB5IEVzdGFkw61zdGljYSwgVW5pdmVyc2lkYWQgZGVsIE5vcnRlIChCYXJyYW5xdWlsbGEsIENvbG9tYmlhKSINCiAgICAgI2NvcnJlc3BvbmRpbmcgOiB5ZXMgICAgIyBEZWZpbmUgb25seSBvbmUgY29ycmVzcG9uZGluZyBhdXRob3INCiAgICAgI2FkZHJlc3MgICAgICAgOiAiRGVwYXJ0YW1lbnRvIGRlIE1hdGVtw6F0aWNhcyB5IEVzdGFkw61zdGljYSINCiAgICBlbWFpbCAgICAgICAgIDogfA0KICAgICAgaGxsaW5hc0B1bmlub3J0ZS5lZHUuY28NCiAgICAgIA0KICAgICAgW0Jpb2dyYXBoaWNhbCBza2V0Y2hdKGh0dHBzOi8vcnB1YnMuY29tL2hsbGluYXMvQmlvX1NrZXRjaCkNCiAgICAgIA0KICAgICAgYHIgZm9ybWF0KFN5cy50aW1lKCksICIlZC8lbS8leSIpYCANCiAgICAgIA0KICAgICAjcm9sZTogICAgICAgICAjIENvbnRyaWJ1dG9yc2hpcCByb2xlcyAoZS5nLiwgQ1JlZGlULCBodHRwczovL2Nhc3JhaS5vcmcvY3JlZGl0LykNCiAgIyAgICAtIENvbmNlcHR1YWxpemF0aW9uDQogICMgICAgLSBXcml0aW5nIC0gT3JpZ2luYWwgRHJhZnQgUHJlcGFyYXRpb24NCiAgIyAgICAtIFdyaXRpbmcgLSBSZXZpZXcgJiBFZGl0aW5nDQogIyAtIG5hbWUgICAgICAgICAgOiAiQXV0b3IgbnVtZXJvIDIiDQogIyAgIGFmZmlsaWF0aW9uICAgOiAiMSwyIg0KICMgICByb2xlOg0KICMgICAgIC0gV3JpdGluZyAtIFJldmlldyAmIEVkaXRpbmcNCiAgICAgI2FmZmlsaWF0aW9uOg0KICAjLSBpZCAgICAgICAgICAgIDogIjEiDQogICMgIGluc3RpdHV0aW9uICAgOiAiVW5pdmVyc2lkYWQgZGVsIE5vcnRlIChCYXJyYW5xdWlsbGEsIENvbG9tYmlhKSINCiAgIyFbXShobGxpbmFzLmpwZyl7d2lkdGg9MWlufSANCiAgDQojZGF0ZTogJ2ByIGZvcm1hdChTeXMudGltZSgpLCAiJWQvJW0vJXkiKWAnICAjIHZlciBodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24tY29va2Jvb2svdXBkYXRlLWRhdGUuaHRtbA0Kb3V0cHV0OiANCiAgICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6IA0KICAgICAgICAgICNPSk8gU2FsZW4gY2FwaXR1bG9zLCBzZWNjaW9uZXMgeSBUZW9yZW1hcw0KICAgICNib29rZG93bjo6aHRtbF9ib29rOg0KICAgICAgICAgICNPSk8gRVJST1IgU2FsZW4gdGVvcmVtYXMsIHBlcm8gbm8gc2FsZW4gbG9zIGNhcGl0dWxvcyANCiAgICAjaHRtbF9kb2N1bWVudDoNCiAgICAgICAgICB0b2M6IHRydWUgICAgICAjIHRhYmxlIG9mIGNvbnRlbnQgdHJ1ZQ0KICAgICAgICAgIHRvY19kZXB0aDogNCAgICMgdXB0byB0aHJlZSBkZXB0aHMgb2YgaGVhZGluZ3MgKHNwZWNpZmllZCBieSAjLCAjIyBhbmQgIyMjKQ0KICAgICAgICAgIHRvY19mbG9hdDogdHJ1ZSAjQ29uIHRydWUsIHRvYyBzYWxlIGFsIG1hcmdlbiBpenF1aWVyZG8gZGUgbGEgcMOhZ2luYTsgZGUgbG8gY29udHJhcmlvLCBhcnJpYmENCiAgICAgICAgICBjb2xsYXBzZWQ6IGZhbHNlDQogICAgICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UNCiAgICAgICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUgICAjIGlmIHlvdSB3YW50IG51bWJlciBzZWN0aW9ucyBhdCBlYWNoIHRhYmxlIGhlYWRlcg0KICAgICAgICAgICN0aGVtZTogc2FuZHN0b25lDQogICAgICAgICAgI3RoZW1lOiB1bml0ZWQgICMgbWFueSBvcHRpb25zIGZvciB0aGVtZSwgdGhpcyBvbmUgaXMgbXkgZmF2b3JpdGUuDQogICAgICAgICAgI3RoZW1lOiBmbGF0bHkgICMgDQogICAgICAgICAgI3RoZW1lOiBjZXJ1bGVhbiAgIyANCiAgICAgICAgICAjaGlnaGxpZ2h0OiB0YW5nbyAgIyBzcGVjaWZpZXMgdGhlIHN5bnRheCBoaWdobGlnaHRpbmcgc3R5bGUNCiAgICAgICAgICAjY3NzOiBTY3JpcHRzIGFjY2Vzb3Jpb3MvZXN0aWxvYm90b24uY3NzDQogICAgICAgICAgI2NzczogbXkuY3NzICAgIyB5b3UgY2FuIGFkZCB5b3VyIGN1c3RvbSBjc3MsIHNob3VsZCBiZSBpbiBzYW1lIGZvbGRlcg0KICAgICAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICAgICAgICAjaGlnaGxpZ2h0OiB0YW5nbyAgIyBjYW1iaWFyIGNvbG9yIGRlIGxpYnJhcnkgZW4gYXp1bA0KICAgICMgYm9va2Rvd246OmdpdGJvb2s6DQogICAgIyAgICAgIGluY2x1ZGVzOg0KICAgICMgICAgICAgIGluX2hlYWRlcjogaGVhZGVyLmh0bWwNCiAgICAjIGJvb2tkb3duOjpwZGZfYm9vazoNCiAgICAjICAgICAgIGtlZXBfdGV4OiB5ZXMNCiAgICAjIGJvb2tkb3duOjpodG1sX2Jvb2s6DQogICAgIyAgICAgICBjc3M6IHRvYy5jc3MNCiAgICAjIGJvb2tkb3duOjpodG1sX2Jvb2s6DQogICAgIyAgICAgICAgIGluY2x1ZGVzOg0KICAgICMgICAgICAgICAgIGluX2hlYWRlcjogc3R5bGUuY3NzDQogICAgI2Jvb2tkb3duOjpodG1sX2RvY3VtZW50MjogZGVmYXVsdA0KICAgICMgYm9va2Rvd246OnBkZl9kb2N1bWVudDI6DQogICAgIyAgICAgIGtlZXBfdGV4OiB0cnVlDQogICAgI2JpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWINCiAgICBtYXRoamF4OiAiaHR0cDovL2V4YW1wbGUuY29tL21hdGhqYXgvTWF0aEpheC5qcz9jb25maWc9VGVYLUFNUy1NTUxfSFRNTG9yTU1MIg0KaGVhZGVyLWluY2x1ZGVzOg0KICAgIFx1c2VwYWNrYWdlW3gxMW5hbWVzXXt4Y29sb3J9IA0KICAgIA0KY3NsOiBzY2llbmNlLmNzbA0KI09qbzogU2UgdXRpbGl6YSBsZW5ndWFqZSBZQU1MDQoNCmFic3RyYWN0OiB8DQogKipFbiBbUnB1YnM6OiB0b2NdKGh0dHBzOi8vcnB1YnMuY29tL2hsbGluYXMvdG9jKSBzZSBwdWVkZW4gdmVyIG90cm9zIGRvY3VtZW50b3MgZGUgcG9zaWJsZSBpbnRlcsOpcy4qKg0KICANCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZmlnLmFsaWduPSJjZW50ZXIiLCAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSMsDQogICAgICAgICAgICAgICAgICAgICAgI3N0eWxlID0gImNvbG9yOmRhcmtibHVlIg0KICAgICAgICAgICAgICAgICAgICAjIGNsYXNzLnNvdXJjZT0iYmctZGFuZ2VyIiwgY2xhc3Mub3V0cHV0PSJiZy13YXJuaW5nIiAgICNDb2xvcmVzIGRlbnRybyBkZWwgY2h1bmsNCiAgICAgICAgICAgICAgICAgICAgICkNCmxpYnJhcnkocmdsKQ0Ka25pdHI6OmtuaXRfaG9va3Mkc2V0KHdlYmdsID0gaG9va193ZWJnbCkNCmBgYA0KDQoNCg0KDQpgYGB7ciwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0NCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9sYW5ndWFnZS1lbmdpbmVzLmh0bWwNCg0KaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvYm9va2Rvd24vbWFya2Rvd24tc3ludGF4Lmh0bWwNCg0KaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvYm9va2Rvd24vYS1zaW5nbGUtZG9jdW1lbnQuaHRtbA0KDQpodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ib29rZG93bi9tYXJrZG93bi1leHRlbnNpb25zLWJ5LWJvb2tkb3duLmh0bWwNCg0KaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duL2Jvb2tkb3duLW1hcmtkb3duLmh0bWwgICMgVGVvcmVtcyBhbmQgcHJvb2ZzDQoNCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL2Jvb2tkb3duL21hcmtkb3duLWV4dGVuc2lvbnMtYnktYm9va2Rvd24uaHRtbCN0aGVvcmVtcw0KDQpodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ib29rZG93bi9odG1sLmh0bWwNCg0KaHR0cHM6Ly93d3cuZGF0YS10by12aXouY29tLw0KICANCltScHVic10obGluaykNCiAgDQooXCNlcTplYy0pLCAgRWN1YWNpb24gXEByZWYoZXE6ZWMtKSwgRmlndXJhIFxAcmVmKGZpZzpGaWctKSwgVGFibGUgXEByZWYodGFiOm10Y2FycyksIFRoZW9yZW0gXEByZWYodGhtOmJvcmluZykNCg0KDQojIFRpdHVsbyB7I1RpdHVsb1NlY2Npb259ICAgXEByZWYoVGl0dWxvU2VjY2lvbikNCiAgDQojIEZvciBIVE1MLCB3ZSBjYW4gc2V0IGNvbG9yIHdpdGggQ1NTLCBlLmcuLCA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZDsiPnRleHQ8L3NwYW4+DQogIA0KIyBodHRwczovL3JhZGlhbnQtcnN0YXRzLmdpdGh1Yi5pby9kb2NzL21vZGVsL2xvZ2lzdGljLmh0bWwgU2hpbm55IExvZ2l0ICANCiAgDQpgYGANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0NCiNMYSBmb3RvIHRhbWHDsW8gY8OpZHVsYQ0KDQpodG1sdG9vbHM6OmltZyhzcmMgPSBrbml0cjo6aW1hZ2VfdXJpKGZpbGUucGF0aChSLmhvbWUoImRvYyIpLCAiaHRtbCIsICJsb2dvLmpwZyIpKSwgDQogICAgICAgICAgICAgICBhbHQgPSAnaGxsaW5hcycsIA0KICAgICAgICAgICAgICAgc3R5bGUgPSAncG9zaXRpb246YWJzb2x1dGU7IHRvcDowOyByaWdodDowOyBwYWRkaW5nOjEwcHg7JyAjLA0KICAgICAgICAgICAgICAgd2lkdGggPSAiMjAwcHgiKSAgIyBBcXXDrSBlc3BlY2lmaWNhcyBlbCBhbmNobyBkZXNlYWRvIGVuIHDDrXhlbGVzIG8gcG9yY2VudGFqZQ0KYGBgDQoNCg0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCB9DQojIExhIGZvdG8gZ3JhbmRlDQoNCmh0bWx0b29sczo6aW1nKHNyYyA9IGtuaXRyOjppbWFnZV91cmkoImhsbGluYXMyMDIzLmpwZyIpLCANCiAgICAgICAgICAgICAgIGFsdCA9ICdobGxpbmFzMjAyMycsIA0KICAgICAgICAgICAgICAgc3R5bGUgPSAncG9zaXRpb246YWJzb2x1dGU7IHRvcDowOyByaWdodDowOyBwYWRkaW5nOjFweDsnLA0KICAgICAgICAgICAgICAgd2lkdGg9IjE1JSIpDQpgYGANCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAgLS0+DQoNCmBgYHtjc3MsIGVjaG89RkFMU0V9DQouY29sdW1ucyB7ZGlzcGxheTogZmxleDt9DQpoMSB7Y29sb3I6IGRhcmtibHVlO30NCmgzIHtjb2xvcjogZGFya2dyZWVuO30NCmg0IHtjb2xvcjogZ3JlZW47fQ0KYGBgDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBDYXDDrXR1bG8gIC0tPg0KDQoNCmBgYHtjc3MsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9DQojaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNDEwMzA0NzcvY2hhbmdpbmctY2h1bmstYmFja2dyb3VuZC1jb2xvci1pbi1ybWFya2Rvd24NCg0KLmJhZENvZGUgew0KYmFja2dyb3VuZC1jb2xvcjogcmVkOw0KfQ0KYGBgDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgTGlicmVyw61hcw0KDQojIyMgUGFyYSBjbMO6c3Rlcg0KDQpgYGB7cn0NCmxpYnJhcnkoZmFjdG9leHRyYSkNCmxpYnJhcnkoY2x1c3RlcikNCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAgLS0+DQoNCiMjIyBQYXJhIG90cm9zIGFuw6FsaXNpcw0KDQpgYGB7ciwgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9DQpsaWJyYXJ5KGFwbG9yZTMpICAgICAgICNCYXNlIGRlIGRhdG9zIHBhcmEgbG9zIGVqZW1wbG9zDQpsaWJyYXJ5KGxzbSkgICAgICAgICAgICNCYXNlIGRlIGRhdG9zIHBhcmEgZWplbXBsb3MgeSBlc3RpbWFjaW9uZXMgZGVsIExvZy12ZXJvc2ltaWxpdHVkDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkgICAgICNJbmNsdXllIGEgZHBseXIgeSBnZ3Bsb3QyDQpsaWJyYXJ5KHN0cmluZ3IpICAgICAgICNSZWVtcGxhemFyIGNhcmFjdGVyZXMgZW4gdW4gZGF0YSBmcmFtZQ0KbGlicmFyeShvdXRsaWVycykgICAgICAjb3V0bGllcnM6OmdydWJicy50ZXN0DQpsaWJyYXJ5KEVudlN0YXRzKSAgICAgICNFbnZTdGF0czo6cm9zbmVyVGVzdA0KbGlicmFyeShETXdSMikgICAgICAgICAjTE9GIChMb2NhbCBPdXRsaWVyIEZhY3RvcikNCmxpYnJhcnkocmdsKSAgICAgICAgICAgI3JnbDo6cGxvdDNkDQpsaWJyYXJ5KGhlYXRtYXBseSkgICAgICNNYXRyaXogZGUgY29ycmVsYWNpb25lcw0KbGlicmFyeShnZ2NvcnJwbG90KSAgICAjTWF0cml6IGRlIGNvcnJlbGFjaW9uZXMNCmxpYnJhcnkoY29ycnBsb3QpICAgICAgI01hdHJpeiBkZSBjb3JyZWxhY2lvbmVzDQpsaWJyYXJ5KHRleHRzaGFwZSkgICAgICNjb2x1bW5fdG9fcm93bmFtZXMNCmxpYnJhcnkob3Blbnhsc3gpICAgICAgI0xpYnJlcsOtYSBwYXJhIGVzY3JpYmlyIGFyY2hpdm9zIGRlIEV4Y2VsDQojb3B0c19rbml0JHNldChldmFsLmFmdGVyID0gJ2ZpZy5jYXAnKQ0KYGBgDQoNCmBgYHtjc3MsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9DQojaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNDEwMzA0NzcvY2hhbmdpbmctY2h1bmstYmFja2dyb3VuZC1jb2xvci1pbi1ybWFya2Rvd24NCg0KLmJhZENvZGUgew0KYmFja2dyb3VuZC1jb2xvcjogcmVkOw0KfQ0KYGBgDQoNCmBgYHtyLCAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0NCmxpYnJhcnkoYXBsb3JlMykgICAgICAgI0Jhc2UgZGUgZGF0b3MgcGFyYSBsb3MgZWplbXBsb3MNCmxpYnJhcnkobHNtKSAgICAgICAgICAgI0Jhc2UgZGUgZGF0b3MgcGFyYSBlamVtcGxvcyB5IGVzdGltYWNpb25lcyBkZWwgTG9nLXZlcm9zaW1pbGl0dWQNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkodGlkeXZlcnNlKSAgICAgI0luY2x1eWUgYSBkcGx5ciB5IGdncGxvdDINCmxpYnJhcnkoc3RyaW5ncikgICAgICAgI1JlZW1wbGF6YXIgY2FyYWN0ZXJlcyBlbiB1biBkYXRhIGZyYW1lDQpsaWJyYXJ5KG91dGxpZXJzKSAgICAgICNvdXRsaWVyczo6Z3J1YmJzLnRlc3QNCmxpYnJhcnkoRW52U3RhdHMpICAgICAgI0VudlN0YXRzOjpyb3NuZXJUZXN0DQpsaWJyYXJ5KERNd1IyKSAgICAgICAgICNMT0YgKExvY2FsIE91dGxpZXIgRmFjdG9yKQ0KbGlicmFyeShyZ2wpICAgICAgICAgICAjcmdsOjpwbG90M2QNCmxpYnJhcnkoaGVhdG1hcGx5KSAgICAgI01hdHJpeiBkZSBjb3JyZWxhY2lvbmVzDQpsaWJyYXJ5KGdnY29ycnBsb3QpICAgICNNYXRyaXogZGUgY29ycmVsYWNpb25lcw0KbGlicmFyeShjb3JycGxvdCkgICAgICAjTWF0cml6IGRlIGNvcnJlbGFjaW9uZXMNCmxpYnJhcnkodGV4dHNoYXBlKSAgICAgI2NvbHVtbl90b19yb3duYW1lcw0KbGlicmFyeShvcGVueGxzeCkgICAgICAjTGlicmVyw61hIHBhcmEgZXNjcmliaXIgYXJjaGl2b3MgZGUgRXhjZWwNCmBgYA0KDQoNCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEludHJvZHVjY2nDs24NCg0KMS4gRWwgYW7DoWxpc2lzIGRlIENsdXN0ZXIgc2UgcmVmaWVyZSBhIHVuIGNvbmp1bnRvIGRlIHTDqWNuaWNhcyBlbiBsb3MgbcOpdG9kb3MgZGUgaW50ZXJkZXBlbmRlbmNpYSBkb25kZSBubyBzZSBkaXN0aW5ndWUgZW50cmUgdmFyaWFibGVzIGRlcGVuZGllbnRlcyBlIGluZGVwZW5kaWVudGVzLiANCg0KMi4gU3Ugb2JqZXRpdm8gZXMgZm9ybWFyIGdydXBvcyBhIHBhcnRpciBkZSBlbGVtZW50b3MsIGRvbmRlIGNhZGEgZ3J1cG8gZXN0w6EgY29tcHVlc3RvIHBvciBlbGVtZW50b3MgbG8gbcOhcyBzaW1pbGFyZXMgcG9zaWJsZSBlbnRyZSBzw60geSwgYWwgbWlzbW8gdGllbXBvLCBsbyBtw6FzIGRpZmVyZW50ZXMgcG9zaWJsZSBkZSBsb3MgZWxlbWVudG9zIGRlIG90cm9zIGdydXBvcy4NCg0KMy4gTGEgYWdydXBhY2nDs24gc2UgcmVhbGl6YSBjb25zaWRlcmFuZG8gbGFzIHZhcmlhYmxlcyBkaXNwb25pYmxlcywgeSBzZSB1dGlsaXphIGNvbW8gYmFzZSBwYXJhIGxhIGNsYXNpZmljYWNpw7NuLiANCg0KNC4gUG9yIGxvIGdlbmVyYWwsIHNlIGVzcGVyYSBxdWUgZXN0b3MgZ3J1cG9zIHNlYW4gbXV0dWFtZW50ZSBleGNsdXNpdm9zIHkgc2VsZWN0aXZhbWVudGUgZXhoYXVzdGl2b3MuDQoNCjUuIEVuIGVsIGFuw6FsaXNpcyBkZSBDbHVzdGVyLCBsb3MgY2Fzb3MgbyBsYXMgdmFyaWFibGVzIHB1ZWRlbiBzZXIgYWdydXBhZG9zLiBFcyB1bmEgdMOpY25pY2EgZGVzY3JpcHRpdmEgeSBhIHZlY2VzIGV4cGxvcmF0b3JpYSwgcGVybyBubyBleHBsaWNhdGl2YS4gDQoNCjYuIExhIGRpdmVyc2lkYWQgZGUgc2l0dWFjaW9uZXMgcXVlIHNlIHByZXNlbnRhbiBwYXJhIHV0aWxpemFyIGVzdGUgbcOpdG9kbywgY29uIG51bWVyb3NvcyBjYXNvcyB5IHZhcmlhYmxlcywgYSBtZW51ZG8gZGlmaWN1bHRhIGxhIGNsYXNpZmljYWNpw7NuLiANCg0KNy4gQWRlbcOhcywgbGEgdmFyaWVkYWQgZGUgZm9ybWFzIGRlIG1lZGlyIGxhIHNpbWlsaXR1ZCBlbnRyZSBlbGVtZW50b3MgeSBsb3MgZGlmZXJlbnRlcyBwcm9jZWRpbWllbnRvcyBkZSBhZ3J1cGFjacOzbiBhdW1lbnRhbiBlbCByaWVzZ28gZGUgY29uY2x1c2lvbmVzIHF1ZSBwdWVkZW4gbm8gcmVmbGVqYXIgbGEgcmVhbGlkYWQgZGVsIGVzdHVkaW8uDQoNCjguIExhIHJlcHJlc2VudGF0aXZpZGFkIGRlIGxhcyBtdWVzdHJhcyB5IGxhIGF0ZW5jacOzbiBhIGxhIG11bHRpY29saW5lYWxpZGFkIHNvbiBhc3BlY3RvcyBpbXBvcnRhbnRlcyBlbiBlbCBhbsOhbGlzaXMgZGUgQ2x1c3Rlci4gDQoNCjkuIExhIHBvc2liaWxpZGFkIGRlIGluZmx1ZW5jaWEgZGVsIGFuYWxpc3RhIGVzIGFsdGEsIHkgZXMgY29tw7puIHF1ZSBsYXMgdmFyaWFibGVzIHNlIHByZXNlbnRlbiBlbiBkaWZlcmVudGVzIHVuaWRhZGVzIG8gZXNjYWxhcyBkZSBtZWRpY2nDs24sIGxvIHF1ZSBzdWdpZXJlIGxhIGNvbnZlbmllbmNpYSBkZSBub3JtYWxpemFybGFzLg0KDQoxMC4gQ3VhbmRvIHNlIGVuZnJlbnRhIG11bHRpY29saW5lYWxpZGFkIG8gdW4gZ3JhbiBuw7ptZXJvIGRlIHZhcmlhYmxlcywgbG8gcXVlIHBvZHLDrWEgZGlmaWN1bHRhciBlbCBhbsOhbGlzaXMgbyBnZW5lcmFyIHJlZHVuZGFuY2lhIGVuIGxhIGlkZW50aWZpY2FjacOzbiBkZSBhdHJpYnV0b3Mgc2ltaWxhcmVzLCBlcyByZWNvbWVuZGFibGUgcmVjdXJyaXIgYSB0w6ljbmljYXMgcXVlIHNpbnRldGljZW4gbGEgaW5mb3JtYWNpw7NuLCBjb21vIGVsIEFuw6FsaXNpcyBkZSBDb21wb25lbnRlcyBQcmluY2lwYWxlcyAoUENBKSB5IGVsIEFuw6FsaXNpcyBGYWN0b3JpYWwgKEVGQSkuIA0KDQoxMS4gRW4gZXN0ZSBtb2RlbG8sIGVzIHBydWRlbnRlIGV4Y2x1aXIgbG9zIHZhbG9yZXMgYXTDrXBpY29zIGRlbCBhbsOhbGlzaXMgbyB0cmF0YXJsb3MgZGUgbWFuZXJhIGVzcGVjaWFsLg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBDb21lbnRhcmlvcyBnZW5lcmFsZXMNCg0KIyMjIEFwbGljYWJpbGlkYWQNCg0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQojIEJVRU5POiAgaHR0cHM6Ly93cGQudWdyLmVzL35iaW9lc3RhZC9ndWlhLXNwc3MvcHJhY3RpY2EtOC8NCmBgYA0KDQoNCkVsIGFuw6FsaXNpcyBjbMO6c3RlciBlcyB1bmEgdGFyZWEgZGUgY2xhc2lmaWNhY2nDs24geSBoYSB0ZW5pZG8gdW5hIGFtcGxpYSBhcGxpY2FjacOzbiBlbiBkaXZlcnNhcyBkaXNjaXBsaW5hcyBhIGxvIGxhcmdvIGRlbCB0aWVtcG8uIFBvciBlamVtcGxvOg0KDQoxLiBFbiBhc3Ryb25vbcOtYSBzZSB1dGlsaXphbiBwYXJhIGlkZW50aWZpY2FyIHkgY2xhc2lmaWNhciBjb25qdW50b3MgZGUgb2JqZXRvcyBjb21vIGdhbGF4aWFzIHkgc3VwZXJnYWxheGlhcyAoYWdydXBhciBlc3RyZWxsYXMgZW4gZWwgdW5pdmVyc28gZW4gYmFzZSBhIHN1IGJyaWxsYW50ZXogbHVtaW5vc2EpLiANCg0KMi4gRW4gZWwgY2FtcG8gZGVsIE1hcmtldGluZywgc29uIMO6dGlsZXMgcGFyYSBzZWdtZW50YXIgbWVyY2Fkb3MgeSByZWFsaXphciBpbnZlc3RpZ2FjaW9uZXMgZGUgbWVyY2FkbyAoY3JlYXIgY29uanVudG9zIGRlIGNvbnN1bWlkb3JlcyBzZWfDum4gc3VzIGluY2xpbmFjaW9uZXMgaGFjaWEgcHJvZHVjdG9zIHJlY2nDqW4gbGFuemFkb3MpLiANCg0KMy4gRW4gZWwgYXJlYSBmaW5hbmNpZXJvLCBzZSBwdWVkZW4gY2F0ZWdvcml6YXIgbGFzIGluc3RpdHVjaW9uZXMgYmFuY2FyaWFzIGNvbiBtaXJhcyBhIGlkZW50aWZpY2FyIGxhcyDDoXJlYXMgbcOhcyBwcm92ZWNob3NhcyBwYXJhIGludmVyc2lvbmVzLg0KDQo0LiBFbiBCaW9sb2fDrWEgcGFyYSBpZGVudGlmaWNhciDDoXJlYXMgY29tbyBsYSB0YXhvbm9tw61hIHkgZWwgYW7DoWxpc2lzIGRlIG1pY3JvYXJyYXlzLiANCg0KNS4gRW4gQ2llbmNpYXMgQW1iaWVudGFsZXMsIGRvbmRlIHNlIGNsYXNpZmljYW4gcsOtb3MgcGFyYSBlc3RhYmxlY2VyIHRpcG9sb2fDrWFzIGJhc2FkYXMgZW4gbGEgY2FsaWRhZCBkZWwgYWd1YSBvIGRldGVjdGFyIGFncnVwYWNpb25lcyBkZSBtdW5pY2lwaW9zIGVuIHVuYSByZWdpw7NuIGVzcGVjw61maWNhIHF1ZSBwcmVzZW50ZW4gcGF0cm9uZXMgc2ltaWxhcmVzIGRlIGNvbnN1bW8gZGUgYWd1YSwgY29uIGVsIHByb3DDs3NpdG8gZGUgZW5jb250cmFyIHBvbMOtdGljYXMgc29zdGVuaWJsZXMgeSDDoXJlYXMgY29uIGNvbnN1bW8gZXhjZXNpdm8gcGFyYSBhYm9yZGFyIHByb2JsZW1hcyBwb3RlbmNpYWxlcy4gDQoNCjYuIEVuIFBzaWNvbG9nw61hLCBTb2Npb2xvZ8OtYSwgRWNvbm9tw61hLCBJbmdlbmllcsOtYSwgZW50cmUgb3Ryb3MgY2FtcG9zLCBlc3RhcyB0w6ljbmljYXMgdGFtYmnDqW4gc2UgYXBsaWNhbiBkZSBtYW5lcmEgZWZlY3RpdmEgcGFyYSBkaXZlcnNvcyBwcm9ww7NzaXRvcy4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIFTDqWNuaWNhIGRlIGFncnVwYWNpw7NuIGRlIHZhcmlhYmxlcyB5IGRlIGNhc29zDQoNCioqQ29tbyB0w6ljbmljYSBkZSBhZ3J1cGFjacOzbiBkZSB2YXJpYWJsZXMuKioNCg0KMS4gRWwgYW7DoWxpc2lzIGRlIGNsw7pzdGVyIGd1YXJkYSBzaW1pbGl0dWRlcyBjb24gZWwgYW7DoWxpc2lzIGZhY3RvcmlhbC4gDQoNCjIuIFNpbiBlbWJhcmdvLCBtaWVudHJhcyBxdWUgZWwgYW7DoWxpc2lzIGZhY3RvcmlhbCBwdWVkZSBzZXIgcsOtZ2lkbyBlbiBhbGd1bm9zIGRlIHN1cyBzdXB1ZXN0b3MsIGNvbW8gbGEgbGluZWFsaWRhZCwgbGEgbm9ybWFsaWRhZCB5IGxhIG5lY2VzaWRhZCBkZSB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcywgeSB0aWVuZGUgYSBlc3RpbWFyIGxhIG1hdHJpeiBkZSBkaXN0YW5jaWFzIGRlIG1hbmVyYSB1bmlmb3JtZSwgZWwgYW7DoWxpc2lzIGRlIGNsw7pzdGVyIGVzIG1lbm9zIHJlc3RyaWN0aXZvIGVuIHN1cyBzdXB1ZXN0b3MuIA0KDQozLiBFbCBhbsOhbGlzaXMgZGUgY2zDunN0ZXIgbm8gcmVxdWllcmUgbGluZWFsaWRhZCBuaSBzaW1ldHLDrWEsIHkgcHVlZGUgbWFuZWphciB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzLiANCg0KNC4gQWRlbcOhcywgb2ZyZWNlIHVuYSB2YXJpZWRhZCBkZSBtw6l0b2RvcyBwYXJhIGVzdGltYXIgbGEgbWF0cml6IGRlIGRpc3RhbmNpYXMuDQoNCioqQ29tbyB0w6ljbmljYSBkZSBhZ3J1cGFjacOzbiBkZSBjYXNvcy4qKg0KDQo1LiBFbCBhbsOhbGlzaXMgZGUgY2zDunN0ZXIgZXMgc2ltaWxhciBhbCBhbsOhbGlzaXMgZGlzY3JpbWluYW50ZS4gDQoNCjYuIFNpbiBlbWJhcmdvLCBtaWVudHJhcyBxdWUgZWwgYW7DoWxpc2lzIGRpc2NyaW1pbmFudGUgc2UgZW5mb2NhIGVuIGFncnVwYXIgdmFyaWFibGVzIHkgY2xhc2lmaWNhciBsb3MgY2Fzb3MgdXRpbGl6YW5kbyB1biBjcml0ZXJpbyBvIHZhcmlhYmxlIGRlcGVuZGllbnRlIChsb3MgZ3J1cG9zIGRlIGNsYXNpZmljYWNpw7NuKSwgZWwgYW7DoWxpc2lzIGRlIGNsw7pzdGVyIHNlIGNlbnRyYSBlbiBhZ3J1cGFyIG9iamV0b3MuIA0KDQo3LiBFcyBkZWNpciwgaWRlbnRpZmljYSBlbCBuw7ptZXJvIMOzcHRpbW8gZGUgZ3J1cG9zIHkgc3UgY29tcG9zaWNpw7NuIGJhc8OhbmRvc2Ugw7puaWNhbWVudGUgZW4gbGEgc2ltaWxpdHVkIGVudHJlIGxvcyBjYXNvcy4gDQoNCjguIEFkZW3DoXMsIGVsIGFuw6FsaXNpcyBkZSBjbMO6c3RlciBubyBhc3VtZSB1bmEgZGlzdHJpYnVjacOzbiBlc3BlY8OtZmljYSBwYXJhIGxhcyB2YXJpYWJsZXMuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgSW5jb252ZW5pZW50ZXMgZGVsIEFuw6FsaXNpcyBDbMO6c3Rlcg0KDQoxLiBFc3RlIHRpcG8gZGUgYW7DoWxpc2lzIHNlIGNlbnRyYSBlbiBsYSBkZXNjcmlwY2nDs24geSBjb21wcmVuc2nDs24gZGUgbG9zIGRhdG9zIGVuIGx1Z2FyIGRlIHJlYWxpemFyIGluZmVyZW5jaWFzIG8gYXBsaWNhciB0ZW9yw61hcyBlc3BlY8OtZmljYXMuIA0KDQoyLiBTdWVsZSBlbXBsZWFyc2UgY29tbyB1biBlbmZvcXVlIGV4cGxvcmF0b3Jpby4NCg0KMy4gTG8gYW50ZXJpb3IgaW1wbGljYSBxdWUgbm8gcHJvcG9yY2lvbmEgcmVzcHVlc3RhcyBkZWZpbml0aXZhczsgbcOhcyBiaWVuLCBsYXMgc29sdWNpb25lcyBzb24gdmFyaWFkYXMgeSBkZXBlbmRlbiB0YW50byBkZSBsYXMgdmFyaWFibGVzIGV4YW1pbmFkYXMgY29tbyBkZWwgbcOpdG9kbyBkZSBhbsOhbGlzaXMgZGUgY2zDunN0ZXIgdXRpbGl6YWRvLg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KDQojIE1lZGlkYXMgZGUgZGlzdGFuY2lhIHBhcmEgYWdydXBhbWllbnRvICAgIA0KDQpQYXJhIGVsIGFncnVwYW1pZW50byBkZSBsb3MgaW5kaXZpZHVvcyAodSBvYmpldG9zKSBzZSB1dGlsaXphbiBtZWRpZGFzIGRlIGRpc3RhbmNpYSwgcXVlIHNlIHB1ZWRlbiBjbGFzaWZpY2FyIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6IA0KICANCiAgMS4gTWVkaWRhcyBiYXNhZGFzIGVuIGNvcnJlbGFjaW9uZXMgKFByZWRvbWluYW4gbG9zIHBhdHJvbmVzIGRlIHZhcmlhY2nDs24pLg0KICANCiAgMi4gTWVkaWRhcyBiYXNhZGFzIGVuIGRpc3RhbmNpYXMgZ2VvbcOpdHJpY2FzIChQcmVkb21pbmFuIGxvcyBwYXRyb25lcyBkZSBtZWRpY2nDs24pLg0KICANCiAgMy4gTWVkaWRhcyBiYXNhZGFzIGVuIMOtbmRpY2VzIGRlIHNpbWlsaXR1ZC4NCiAgDQoNClbDqWFzZSBsYSBGaWd1cmEgXEByZWYoZmlnOmRpc3RhbmNpYTApLiBBIGNvbnRpbnVhY2nDs24gc2UgZXhwbGljYXLDoW4gY2FkYSB1bmEgZGUgZWxsYXMuIA0KDQoNCg0KDQogDQo8Y2VudGVyPg0KDQpgYGB7ciBkaXN0YW5jaWEwLCBlY2hvPUZBTFNFLCBmaWcuY2FwID0gIioqTWVkaWRhcyBkZSBkaXN0YW5jaWFzIHBhcmEgYWdydXBhbWllbnRvKioiLCBvdXQud2lkdGggPSAiODAlIn0NCiMgZmlnLndpZHRoID0gMjAgIyBObyBmdW5jaW9uYSBlc3RhIG9wY2lvbiBlbiBlbCBjaHVuaw0KDQojaHR0cDovL3pldnJvc3MuY29tL2Jsb2cvMjAxNy8wNi8xOS90aXBzLWFuZC10cmlja3MtZm9yLXdvcmtpbmctd2l0aC1pbWFnZXMtYW5kLWZpZ3VyZXMtaW4tci1tYXJrZG93bi1kb2N1bWVudHMvDQojIFBhZ2luYSAzNTkgZGUgUjIwMTUtRnJpZW5kbHkNCg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImRpc3RhbmNpYTAucG5nIikNCg0KI090cmEgbWFuZXJhLCBwZXJvICBzYWxlIGVsIGNhcHRpb246DQojPGNlbnRlcj4NCiMhWygjZmlnOkZpZy1jYXB0aW9uKSBNaSBmaWd1cmFdKE5vbWJyZS5wbmcpe3dpZHRoPTQwMHB4fQ0KIzwvY2VudGVyPg0KYGBgDQo8L2NlbnRlcj4NCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRGlzdGFuY2lhcyBiYXNhZGFzIGVuIGNvcnJlbGFjaW9uZXMNCg0KIyMjIENvcnJlbGFjaW9uZXM6IGRlc2NyaXBjacOzbg0KICANCiAgMS4gUHJlZG9taW5hbiBsb3MgcGF0cm9uZXMgZGUgdmFyaWFjacOzbi4gRXN0YSBwcmVkb21pbmFuY2lhIGRlIHBhdHJvbmVzIGRlIHZhcmlhY2nDs24gc2UgcmVmbGVqYSBlbiBsYXMgbWVkaWRhcyBkZSBjb3JyZWxhY2nDs24uIA0KICANCiAgMi4gRXN0YXMgbWVkaWRhcyBzb24gcHJpbmNpcGFsbWVudGUgY3VhbnRpdGF0aXZhcywgYXVucXVlIHRhbWJpw6luIGVzIHBvc2libGUgY2FsY3VsYXIgY29lZmljaWVudGVzIGRlIGNvcnJlbGFjacOzbiBwYXJhIHZhcmlhYmxlcyBubyBtw6l0cmljYXMsIGNvbW8gbGFzIG9yZGluYWxlcyBvIG5vbWluYWxlcywgY29tbyBsb3MgY29lZmljaWVudGVzIGRlIGNvcnJlbGFjacOzbiBkZSBTcGVhcm1hbiBvIEtlbmRhbGwuIA0KICANCiAgMy4gRW4gdW4gY29uanVudG8gZGUgdmFyaWFibGVzLCBkb3Mgb2JqZXRvcyBzZSBjb25zaWRlcmFuIG11eSBzaW1pbGFyZXMgc2kgdGllbmVuIGNvcnJlbGFjaW9uZXMgYWx0YXMgeSBwb2NvIHNpbWlsYXJlcyBzaSB0aWVuZW4gY29ycmVsYWNpb25lcyBiYWphcy4gDQogIA0KICA0LiBFcyBpbXBvcnRhbnRlIHNlw7FhbGFyIHF1ZSBsYSBjb3JyZWxhY2nDs24gcHJvcG9yY2lvbmEgaW5mb3JtYWNpw7NuIHNvYnJlIGPDs21vIHZhcsOtYW4gZG9zIHZhcmlhYmxlcywgbcOhcyBxdWUgc29icmUgbGEgbWFnbml0dWQgZGUgbGFzIG1pc21hcy4NCiAgDQogIDUuICBMYSBkaXN0YW5jaWEgYmFzYWRhIGVuIGNvcnJlbGFjaW9uZXMgc2UgZGVmaW5lIHJlc3RhbmRvIGVsIGNvZWZpY2llbnRlIGRlIGNvcnJlbGFjacOzbiBkZSAxLiANCiAgDQogIA0KICA2LiBTZSBwdWVkZW4gdXNhciBkaWZlcmVudGVzIHRpcG9zIGRlIG3DqXRvZG9zIGRlIGNvcnJlbGFjacOzbiwgY29tbyBsYXMgcXVlIHNlIGV4cGxpY2FuIGVuIGxhIHNpZ3VpZW50ZSBzZWNjacOzbi4gDQogIA0KICANCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgQ29ycmVsYWNpb25lczogdGlwb3MNCg0KSGF5IHZhcmlvcyB0aXBvcyBkZSBkaXN0YW5jaWFzOiANCg0KMS4gUGVhcnNvbi4NCg0KMi4gQ29zZW5vIGRlIEVpc2VuLg0KDQozLiBTcGVhcm1hbi4NCg0KNC4gS2VuZGFsbC4NCg0KDQpWw6lhc2UgbGEgRmlndXJhIFxAcmVmKGZpZzpkaXN0YW5jaWEwYSkuIEEgY29udGludWFjacOzbiBzZSBleHBsaWNhcsOhbiBjYWRhIHVuYSBkZSBlbGxhcy4gDQoNCg0KIA0KPGNlbnRlcj4NCg0KYGBge3IgZGlzdGFuY2lhMGEsIGVjaG89RkFMU0UsIGZpZy5jYXAgPSAiKipNZWRpZGFzIGRlIGRpc3RhbmNpYXMgcGFyYSBhZ3J1cGFtaWVudG8gKGJhc2FkYSBlbiBjb3JyZWxhY2lvbmVzKSoqIiwgb3V0LndpZHRoID0gIjgwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJkaXN0YW5jaWEwYS5wbmciKQ0KDQojT3RyYSBtYW5lcmEsIHBlcm8gIHNhbGUgZWwgY2FwdGlvbjoNCiM8Y2VudGVyPg0KIyFbKCNmaWc6RmlnLWNhcHRpb24pIE1pIGZpZ3VyYV0oTm9tYnJlLnBuZyl7d2lkdGg9NDAwcHh9DQojPC9jZW50ZXI+DQpgYGANCjwvY2VudGVyPg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIFBlYXJzb24NCg0KIyMjIFBlYXJzb246IGNvcnJlbGFjacOzbg0KDQpMYSBjb3JyZWxhY2nDs24gZGUgUGVhcnNvbiBtaWRlIGVsIGdyYWRvIGRlIHJlbGFjacOzbiBsaW5lYWwgZW50cmUgZG9zIHBlcmZpbGVzIHkgc2UgZGVmaW5lIGNvbW86ICAgIA0KDQokJHJfe1x0ZXh0e3BlYXJ9fSh4LCB5KSBcOyA9XDsgICBcZnJhY3tcc3VtXGxpbWl0c197aT0xfV57bn0oeF9pIC0gXGJhcnt4fSkoeV9pIC0gXGJhcnt5fSl9e1xzcXJ0e1xzdW1cbGltaXRzX3tpPTF9XntufSh4X2kgLSBcYmFye3h9KV4yIFxzdW1cbGltaXRzX3tpPTF9XntufSh5X2kgLSBcYmFye3l9KV4yfX0kJA0KDQpFbiBsYSBmw7NybXVsYSBhbnRlcmlvcjogDQoNCjEuICR4JCBlICR5JCBzb24gZG9zIHZlY3RvcmVzIGRlIGxvbmdpdHVkICRuJC4NCg0KMi4gJFxiYXJ7eH0kIHkgJFxiYXJ7eX0kIHJlcHJlc2VudGFuIGxhcyBtZWRpYXMgZGUgJHgkIGUgJHkkLCByZXNwZWN0aXZhbWVudGUuDQoNCjMuIEdyw6FmaWNhbWVudGUsIGxhIGNvcnJlbGFjacOzbiBwdWVkZSB2aXN1YWxpemFyc2UgZGUgdmFyaWFzIG1hbmVyYXMuIE1vc3RyYXLDqSBicmV2ZW1lbnRlIGxhcyBtw6FzIGltcG9ydGFudGVzLiANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIFBlYXJzb246IGhlYXRtYXANCg0KKipQcmltZXJhIGZvcm1hOioqDQoNClVzYW5kbyBgZ2djb3JycGxvdDo6Z2djb3JycGxvdGAuIA0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2djb3JycGxvdCkNCg0KZ2djb3JycGxvdDo6Z2djb3JycGxvdChjb3IobXRjYXJzKSkNCmBgYA0KDQoNCioqU2VndW5kYSBmb3JtYToqKg0KDQpVc2FuZG8gYGhlYXRtYXA6OmhlYXRtYXBseV9jb3JgLiANCg0KDQpgYGB7cn0NCmxpYnJhcnkoaGVhdG1hcGx5KQ0KDQpoZWF0bWFwbHlfY29yKHggPSBjb3IobXRjYXJzKSwNCiAgICAgICAgICAgICAgeGxhYiA9ICJGZWF0dXJlcyIsDQogICAgICAgICAgICAgIHlsYWIgPSAiRmVhdHVyZXMiLA0KICAgICAgICAgICAgICBrX2NvbCA9IDIsDQogICAgICAgICAgICAgIGtfcm93ID0gMikNCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgUGVhcnNvbjogZGlzdGFuY2lhDQoNCkxhIGRpc3RhbmNpYSBiYXNhZGEgZW4gbGEgY29ycmVsYWNpw7NuIGRlIFBlYXJzb24gc2UgZGVmaW5lIGNvbW86IA0KDQokJGRfe1x0ZXh0e3BlYXJ9fSh4LCB5KSBcOyA9XDsgIDEgXDsgLVw7ICByX3tcdGV4dHtwZWFyfX0oeCwgeSkkJA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCiAgDQogIA0KIyBDb3Nlbm8gZGUgRWlzZW4gDQoNCkVzIHVuIGNhc28gZXNwZWNpYWwgZGUgbGEgY29ycmVsYWNpw7NuIGRlIFBlYXJzb24gY29uICRcYmFye3h9JCB5ICRcYmFye3l9JCAocmVlbXBsYXphZG9zIGFtYm9zIHBvciBjZXJvKToNCg0KJCQgZF97XHRleHR7ZWlzZW59fSh4LCB5KSBcOz1cOyAgMSBcOy1cOyBcZnJhY3tcc3VtXGxpbWl0c197aT0xfV57bn0geF9pIHlfaX17XHNxcnR7XHN1bVxsaW1pdHNfe2k9MX1ee259IHhfaV4yfSBcc3FydHtcc3VtXGxpbWl0c197aT0xfV57bn0geV9pXjJ9fSQkDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIFNwZWFybWFuDQoNCiMjIyBTcGVhcm1hbjogY29ycmVsYWNpw7NuDQoNCkVsIGNvZWZpY2llbnRlIGRlIGNvcnJlbGFjacOzbiBkZSBTcGVhcm1hbiBzZSBjYWxjdWxhIGFzw606IA0KDQokJHJfe1x0ZXh0e3NwZWFyfX0gXDs9XDtcZnJhY3tcc3VtXGxpbWl0c197aT0xfV57bn0gKHgnX2kgLSBcYmFye3h9JykgKHknX2kgLSBcYmFye3l9Jyl9e1xzcXJ0e1xzdW1cbGltaXRzX3tpPTF9XntufSAoeCdfaSAtIFxiYXJ7eH0nKV4yfSBcc3FydHtcc3VtXGxpbWl0c197aT0xfV57bn0gKHknX2kgLSBcYmFye3l9JyleMn19IFw7XGFwcHJveFw7IDEgXCwtXCwgXGZyYWN7NlxzdW1cbGltaXRzX3tpPTF9Xm4gZF9pXjJ9e24obl4yXCwtXCwgMSl9JCQNCg0KZG9uZGUgDQoNCiQkeCdfaSA9IFx0ZXh0e3Jhbmt9KHhfaSksIFxxcXVhZCB5J19pID0gXHRleHR7cmFua30oeV9pKSQkDQoNCnkgJGRfaSA9IHgnX2kteSdfaSQgZXMgbGEgZGlmZXJlbmNpYSBkZSByYW5nb3MgZW50cmUgbGFzIGRvcyB2YXJpYWJsZXMuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgU3BlYXJtYW46IGRpc3RhbmNpYQ0KDQpDb24gbG8gYW50ZXJpb3IsIGxhIGRpc3RhbmNpYSBkZSBjb3JyZWxhY2nDs24gZGUgU3BlYXJtYW4gc2UgY2FsY3VsYSBhc8OtOg0KDQokJCBkX3tcdGV4dHtzcGVhcn19KHgsIHkpIFw7PVw7ICAxIFw7LVw7IHJfe1x0ZXh0e3NwZWFyfX0gJCQNCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KICANCg0KIyMjIFNwZWFybWFuOiBlamVtcGxvDQoNCk1lZGltb3MgZWwgdGllbXBvIGRlIHJlYWNjacOzbiBkZSA4IGp1Z2Fkb3JlcyBkZSB2aWRlb3MganVlZ29zIHkgbGVzIHByZWd1bnRhbW9zIHN1IGVkYWQuIE51ZXN0cm8gb2JqZXRpdm8gZXMgY2FsY3VsYXIgbGEgY29ycmVsYWNpw7NuIGRlIHJhbmdvcyBkZSBTcGVhcm1hbi4gUGFyYSBlc3RvLCBhc2lnbmFtb3MgdW4gcmFuZ28gYSBjYWRhIGluZGl2aWR1byB0YW50byBwYXJhIGVsIHRpZW1wbyBkZSByZWFjY2nDs24gY29tbyBwYXJhIGxhIGVkYWQuIExhIHNpdHVhY2nDs24gc2UgbXVldHJhIGVuIGxhIEZpZ3VyYSBcQHJlZihmaWc6U3BlYXJtYW4xKS4gDQoNCjxjZW50ZXI+DQoNCmBgYHtyIFNwZWFybWFuMSwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKlNpdHVhY2nDs24gcGFyYSBjYWxjdWxhciBsYSBjb3JyZWxhY2nDs24gIGRlIFNwZWFybWFuKioiLCBvdXQud2lkdGggPSAiNjAlIn0NCiMgZmlnLndpZHRoID0gMjAgIyBObyBmdW5jaW9uYSBlc3RhIG9wY2lvbiBlbiBlbCBjaHVuaw0KDQojaHR0cDovL3pldnJvc3MuY29tL2Jsb2cvMjAxNy8wNi8xOS90aXBzLWFuZC10cmlja3MtZm9yLXdvcmtpbmctd2l0aC1pbWFnZXMtYW5kLWZpZ3VyZXMtaW4tci1tYXJrZG93bi1kb2N1bWVudHMvDQojIFBhZ2luYSAzNTkgZGUgUjIwMTUtRnJpZW5kbHkNCg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIlNwZWFybWFuMS5wbmciKQ0KDQojT3RyYSBtYW5lcmEsIHBlcm8gIHNhbGUgZWwgY2FwdGlvbjoNCiM8Y2VudGVyPg0KIyFbKCNmaWc6RmlnLWNhcHRpb24pIE1pIGZpZ3VyYV0oTm9tYnJlLnBuZyl7d2lkdGg9NDAwcHh9DQojPC9jZW50ZXI+DQpgYGANCjwvY2VudGVyPg0KDQpEYWRvIHF1ZSBlbCB0aWVtcG8gZGUgcmVhY2Npw7NuIHlhIGVzdMOhIG9yZGVuYWRvIHBvciB0YW1hw7FvLCBhc2lnbmFtb3MgZWwgcmFuZ28gMSBhbCB2YWxvciBtw6FzIHBlcXVlw7FvICgxMiksIGVsIHJhbmdvIDIgYWwgc2VndW5kbyB2YWxvciBtw6FzIHBlcXVlw7FvICgxNSksIHkgYXPDrSBzdWNlc2l2YW1lbnRlLiBMbGV2YW1vcyBhIGNhYm8gZWwgbWlzbW8gcHJvY2VkaW1pZW50byBwYXJhIGFzaWduYXIgcmFuZ29zIGEgbGFzIGVkYWRlcy4gU2FiaWVuZG8gcXVlIGxvcyBwcm9tZWRpb3MgZGUgbG9zIHJhbmdvcyBzb24gaWd1YWxlcyBhIDQuNSwgZW50b25jZXMsIA0KDQokJHJfe1x0ZXh0e3NwZWFyfX0gIFw7XGFwcHJveFw7IDEgXCwtXCwgXGZyYWN7NlxzdW1cbGltaXRzX3tpPTF9Xm4gZF9pXjJ9e24obl4yXCwtXCwgMSl9IFw7PVw7MSBcLC1cLCBcZnJhY3soNikoOCl9ezgoNjRcLC1cLCAxKX0gXDs9XDsgMSBcLC1cLFxmcmFjezQ4fXs1MDR9IFw7PVw7IDAuOTA1JCQNCg0KUG9yIGVzdGEgcmF6b24sIA0KDQokJCBkX3tcdGV4dHtzcGVhcn19KHgsIHkpIFw7PVw7ICAxIFw7LVw7IDAuOTA1IFw7PVw7IDAuMDk1ICQkDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQogIA0KDQojIEtlbmRhbGwNCg0KIyMjIEtlbmRhbGw6IGNvbWJpbmFjaW9uZXMNCg0KRWwgbcOpdG9kbyBkZSBjb3JyZWxhY2nDs24gZGUgS2VuZGFsbCBtaWRlIGxhIGNvcnJlc3BvbmRlbmNpYSBlbnRyZSBlbCByYW5nbyBkZSBsYXMgdmFyaWFibGVzICR4JCBlICR5JC4gU2kgJG4kIGVzIGVsIHRhbWHDsW8gZGUgJHgkIGUgJHkkLCBlbnRvbmNlcywgZWwgbsO6bWVybyB0b3RhbCBkZSBjb21iaW5hY2lvbmVzIHBvc2libGVzIGRlICR4JCBjb24gbGFzIG9ic2VydmFjaW9uZXMgJHkkIGVzOiANCg0KJCR7blxjaG9vc2UgMn0gIFw7ID1cOyBcZnJhY3sxfXsyfW4obi0xKSQkDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KICANCg0KIyMjIEtlbmRhbGw6IGNvcnJlbGFjaW9uDQoNCg0KU2UgY29taWVuemEgb3JkZW5hbmRvIGxvcyBwYXJlcyBwb3IgbG9zIHZhbG9yZXMgZGUgJHgkLiBTaSAkeCQgZSAkeSQgZXN0w6FuIGNvcnJlbGFjaW9uYWRvcywgZW50b25jZXMgdGVuZHLDrWFuIGxvcyBtaXNtb3Mgw7NyZGVuZXMgZGUgcmFuZ28gcmVsYXRpdm9zLiBBaG9yYSwgcGFyYSBjYWRhICR5X2kkLCBzZSBjdWVudGEgZWwgbsO6bWVybyBkZSAkeV9qID4geV9pJCAocGFyZXMgY29uY29yZGFudGVzICRjJCkgeSBlbCBuw7ptZXJvIGRlICR5X2ogPCB5X2kkIChwYXJlcyBkaXNjb3JkYW50ZXMgJGQkKS4gQ29uIGxvIGFudGVyaW9yLCBzZSBkZWZpbmUgZWwgY29lZmljaWVudGUgZGUgY29ycmVsYWNpw7NuICRcdGF1JCBkZSBLZW5kYWxsIGNvbW86DQoNCiQkXHRhdSBcOyA9XDsgXGZyYWN7bl9jIC0gbl9kfXtcZnJhY3sxfXsyfW4obi0xKX0kJA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCiAgDQoNCiMjIyBLZW5kYWxsOiBkaXN0YW5jaWENCg0KDQpMYSBkaXN0YW5jaWEgZGUgY29ycmVsYWNpw7NuIGRlIEtlbmRhbGwgc2UgZGVmaW5lIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQoNCiQkZF97XHRleHR7a2VuZH19KHgsIHkpIFw7PVw7ICAxIFw7LVw7IFx0YXUkJA0KDQpEb25kZToNCg0KLSAkbl9jJDogbsO6bWVybyB0b3RhbCBkZSBwYXJlcyBjb25jb3JkYW50ZXMuDQoNCi0gJG5fZCQ6IG7Dum1lcm8gdG90YWwgZGUgcGFyZXMgZGlzY29yZGFudGVzLg0KDQotICRuJDogdGFtYcOxbyBkZSAkeCQgZSAkeSQuDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQogIA0KDQojIyMgS2VuZGFsbDogZWplbXBsbw0KDQpJbWFnaW5lbW9zIHF1ZSB1biBkb2N0b3IgeSB1bmEgZG9jdG9yYSBldmFsw7phbiBhIDYgcGFjaWVudGVzIGVuIHTDqXJtaW5vcyBkZSBzYWx1ZCBmw61zaWNhLCBvcmRlbsOhbmRvbG9zIGRlIG1hbmVyYSBkZXNjZW5kZW50ZS4gDQoNCkVuIGVzdGUgY2FzbywgY29uc2lkZXJhbW9zIHF1ZSBsYSBkb2N0b3JhIGFjdMO6YSBjb21vIHJlZmVyZW5jaWEgeSBsb3MgcGFjaWVudGVzIHNlIG51bWVyYW4gZGVsIDEgYWwgNiBzZWfDum4gc3UgY2xhc2lmaWNhY2nDs24gcG9yIGxhIGRvY3RvcmEuIA0KDQpMYSBzaXR1YWNpw7NuIHNlIGlsdXN0cmEgZW4gbGEgRmlndXJhIFxAcmVmKGZpZzpLZW5kYWxsMSkuIA0KDQo8Y2VudGVyPg0KDQpgYGB7ciBLZW5kYWxsMSwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKlNpdHVhY2nDs24gcGFyYSBjYWxjdWxhciBsYSBjb3JyZWxhY2nDs24gIGRlIEtlbmRhbGwqKiIsIG91dC53aWR0aCA9ICI2MCUifQ0KIyBmaWcud2lkdGggPSAyMCAjIE5vIGZ1bmNpb25hIGVzdGEgb3BjaW9uIGVuIGVsIGNodW5rDQoNCiNodHRwOi8vemV2cm9zcy5jb20vYmxvZy8yMDE3LzA2LzE5L3RpcHMtYW5kLXRyaWNrcy1mb3Itd29ya2luZy13aXRoLWltYWdlcy1hbmQtZmlndXJlcy1pbi1yLW1hcmtkb3duLWRvY3VtZW50cy8NCiMgUGFnaW5hIDM1OSBkZSBSMjAxNS1GcmllbmRseQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiS2VuZGFsbDEucG5nIikNCg0KI090cmEgbWFuZXJhLCBwZXJvICBzYWxlIGVsIGNhcHRpb246DQojPGNlbnRlcj4NCiMhWygjZmlnOkZpZy1jYXB0aW9uKSBNaSBmaWd1cmFdKE5vbWJyZS5wbmcpe3dpZHRoPTQwMHB4fQ0KIzwvY2VudGVyPg0KYGBgDQo8L2NlbnRlcj4NCg0KMS4gRXN0byBub3MgcGVybWl0ZSBjb21wYXJhciBsb3MgcmFuZ29zIGFzaWduYWRvcyBwb3IgYW1ib3MgZG9jdG9yZXMuIA0KDQoyLiBQb3IgZWplbXBsbywgc2kgdW4gcGFjaWVudGUgZXN0w6EgY2xhc2lmaWNhZG8gY29tbyBlbCBzZWd1bmRvIHBvciBsYSBkb2N0b3JhLCBwZXJvIGNvbW8gZWwgcHJpbWVybyBwb3IgZWwgZG9jdG9yLiANCg0KMy4gTm9zIGludGVyZXNhIGRldGVybWluYXIgc2kgaGF5IHVuYSBjb3JyZWxhY2nDs24gZW50cmUgZXN0YXMgZG9zIGV2YWx1YWNpb25lcyB1dGlsaXphbmRvIGxhICRcdGF1JCBkZSBLZW5kYWxsLiANCg0KNC4gUGFyYSBjYWxjdWxhcmxhLCBzb2xvIG5lY2VzaXRhbW9zIGxvcyByYW5nb3MgYXNpZ25hZG9zIHBvciBlbCBtw6lkaWNvLiANCg0KNS4gQSBwYXJ0aXIgZGUgYXF1w60sIGVzIHNlbmNpbGxvIGRldGVybWluYXIgZWwgbsO6bWVybyBkZSBwYXJlcyBjb25jb3JkYW50ZXMgeSBkaXNjb3JkYW50ZXMuIA0KDQo2LiBFbiBudWVzdHJvIGVqZW1wbG8sIGVuY29udHJhbW9zIHVuIHRvdGFsIGRlICRuX2M9MTEkIHBhcmVzIGNvbmNvcmRhbnRlcyB5ICRuX2Q9NCQgcGFyZXMgZGlzY29yZGFudGVzLiANCg0KNy4gUG9yIGxvIHRhbnRvLCBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gZGUgS2VuZGFsbCB5IGxhIGRpc3RhbmNpYSBjb3JyZXNwb25kaWVudGUgc29uIHJlc3BlY3RpdmFtZW50ZTogDQoNCiQkXHRhdSBcOyA9XDsgXGZyYWN7MTEgXCwtXCwgNH17XGZyYWN7MX17Mn02KDYtMSl9IFw7XDsgXGZyYWN7N317MTV9XDsgPVw7IDAuNDcsIFxxcXVhZCBkX3tcdGV4dHtrZW5kfX0oeCwgeSkgXDs9XDsgIDEgXDstXDsgMC40N1w7PVw7IDAuNTMkJA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KICANCg0KIyBEaXN0YW5jaWFzIGJhc2FkYXMgZW4gY29ycmVsYWNpb25lczogb2JzZXJ2YWNpb25lcw0KDQpFcyBpbXBvcnRhbnRlIHRlbmVyIGVuIGN1ZW50YSBxdWU6DQoNCjEuICBFbCBhbsOhbGlzaXMgZGUgY29ycmVsYWNpw7NuIGRlIFBlYXJzb24gZXMgZWwgbcOpdG9kbyBtw6FzIGNvbcO6bm1lbnRlIHV0aWxpemFkby4gDQoNCjIuIFRhbWJpw6luIHNlIGNvbm9jZSBjb21vIGNvcnJlbGFjacOzbiBwYXJhbcOpdHJpY2EgeSBkZXBlbmRlIGRlIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zLg0KDQozLiAgTGFzIGNvcnJlbGFjaW9uZXMgZGUgS2VuZGFsbCB5IFNwZWFybWFuIHNvbiBubyBwYXJhbcOpdHJpY2FzIHkgc2UgdXRpbGl6YW4gcGFyYSByZWFsaXphciBhbsOhbGlzaXMgZGUgY29ycmVsYWNpw7NuIGJhc2Fkb3MgZW4gcmFuZ29zLg0KDQo0LiBMYSBjb3JyZWxhY2nDs24gZGUgS2VuZGFsbCBkZWJlIHByZWZlcmlyc2UgYSBsYSBjb3JyZWxhY2nDs24gZGUgU3BlYXJtYW4gY3VhbmRvIGhheSBtdXkgcG9jb3MgZGF0b3MgeSBtdWNob3MgZW1wYXRlcyBkZSByYW5nby4gDQoNCjUuIENvbW8geWEgc2UgY29tZW50w7MgYW50ZXMsIGEgZGlmZXJlbmNpYSBkZWwgY29lZmljaWVudGUgZGUgY29ycmVsYWNpw7NuIGRlIFBlYXJzb24sIGxhIGNvcnJlbGFjacOzbiBkZSBLZW5kYWxsIGVzIHVuYSBtZWRpZGEgZGUgY29ycmVsYWNpw7NuIG5vIHBhcmFtw6l0cmljYS4gUGFyYSBjYWxjdWxhciBsYSBjb3JyZWxhY2nDs24gZGUgS2VuZGFsbCwgbG9zIGRhdG9zIGRlYmVuIGVzdGFyIGRpc3RyaWJ1aWRvcyBkZSBmb3JtYSBubyBub3JtYWwgeSBsYXMgZG9zIHZhcmlhYmxlcyBkZWJlbiBlc3RhciBlbiB1bmEgZXNjYWxhIG9yZGluYWwuDQoNCg0KICANCiAgDQogIA0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgTWVkaWRhcyBiYXNhZGFzIGVuIGRpc3RhbmNpYXMgZ2VvbcOpdHJpY2FzIA0KDQojIyMgTWVkaWRhcyBkZSBkaXN0YW5jaWFzOiBkZXNjcmlwY2nDs24gDQoNCjEuIExvcyBwYXRyb25lcyBkZSBtZWRpY2nDs24gcHJlZG9taW5hbiBlbiBsYXMgbWVkaWRhcyBkZSBkaXN0YW5jaWEsIHkgc29uIGxhcyBtw6FzIHV0aWxpemFkYXMuIA0KDQoyLiBTZWEgZGFkYSB1bmEgcG9ibGFjacOzbiBvIG11ZXN0cmEgZGUgZWxlbWVudG9zIGRlZmluaWRvcyBwb3IgdW4gY29uanVudG8gZGUgdmFyaWFibGVzLg0KDQozLiBSZXByZXNlbnRlbW9zIGNvbiAkZCh4LHkpJCBsYSBkaXN0YW5jaWEgZW50cmUgZG9zIGVsZW1lbnRvcyBjdWFsZXNxdWllcmEgJHgkIHkgJHkkIGRlIGxhIHBvYmxhY2nDs24gKG8gbXVlc3RyYSkuDQoNCjQuIExhIGRpc3RhbmNpYSAkZCQgZGViZSBjdW1wbGlyIGNpZXJ0YXMgY29uZGljaW9uZXM6DQogICAgDQogICAgYS4gKk5vIG5lZ2F0aXZpZGFkKjogJGQoeCx5KSBcZ2VxIDAkLg0KICAgIA0KICAgIGIuICpSZWZsZXhpdmlkYWQqOiAkZCh4LHkpID0gZCh5LHgpJC4NCiAgICANCiAgICBjLiAqRGVzaWd1YWxkYWQgdHJpYW5ndWxhcio6IFNpICR3JCBlcyBvdHJvIHZlY3RvciBkZWwgbWlzbW8gZXNwYWNpbywgZW50b25jZXM6DQogICAgDQogICAgJCRkKHgseSkgXGxlcSBkKHgsdykgKyBkKHcseSkkJA0KICAgIA0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBEaXN0YW5jaWFzIGdlb23DqXRyaWNhczogdGlwb3MNCg0KQ29tbyBtZWRpZGFzIGRlIGRpc3RhbmNpYXMgc2UgdGllbmVuIGVudHJlIG90cmFzIGxhcyBzaWd1aWVudGVzOiANCg0KMS4gRGlzdGFuY2lhIGV1Y2xpZGlhbmEuDQoNCjIuIERpc3RhbmNpYSBkZSBNaW5rb3dza2kuDQoNCjMuIERpc3RhbmNpYSBDaXR5IEJsb2NrIG8gZGUgTWFuaGF0dGFuLg0KDQo0LiBEaXN0YW5jaWEgZGUgQ2hlYnlzaGV2Lg0KDQo1LiBEaXN0YW5jaWEgZGUgTWFsYWhhbm9iaXMuIA0KDQo2LiBEaXN0YW5jaWEgZGUgSGFtbWluZy4gDQoNClbDqWFzZSBsYSBGaWd1cmEgXEByZWYoZmlnOmRpc3RhbmNpYTBiKS4gQSBjb250aW51YWNpw7NuIHNlIGV4cGxpY2Fyw6FuIGFsZ3VuYXMgZGUgZWxsYXMuIA0KDQoNCiANCjxjZW50ZXI+DQoNCmBgYHtyIGRpc3RhbmNpYTBiLCBlY2hvPUZBTFNFLCBmaWcuY2FwID0gIioqTWVkaWRhcyBkZSBkaXN0YW5jaWFzIHBhcmEgYWdydXBhbWllbnRvIChiYXNhZGEgZW4gZGlzdGFuY2lhcyBnZW9tw6l0cmljYXMpKioiLCBvdXQud2lkdGggPSAiODAlIn0NCiMgZmlnLndpZHRoID0gMjAgIyBObyBmdW5jaW9uYSBlc3RhIG9wY2lvbiBlbiBlbCBjaHVuaw0KDQojaHR0cDovL3pldnJvc3MuY29tL2Jsb2cvMjAxNy8wNi8xOS90aXBzLWFuZC10cmlja3MtZm9yLXdvcmtpbmctd2l0aC1pbWFnZXMtYW5kLWZpZ3VyZXMtaW4tci1tYXJrZG93bi1kb2N1bWVudHMvDQojIFBhZ2luYSAzNTkgZGUgUjIwMTUtRnJpZW5kbHkNCg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImRpc3RhbmNpYTBiLnBuZyIpDQoNCiNPdHJhIG1hbmVyYSwgcGVybyAgc2FsZSBlbCBjYXB0aW9uOg0KIzxjZW50ZXI+DQojIVsoI2ZpZzpGaWctY2FwdGlvbikgTWkgZmlndXJhXShOb21icmUucG5nKXt3aWR0aD00MDBweH0NCiM8L2NlbnRlcj4NCmBgYA0KPC9jZW50ZXI+DQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIERpc3RhbmNpYXMgZ2VvbcOpdHJpY2FzOiBncsOhZmljb3MgaW5pY2lhbGVzDQoNClbDqWFzZSBsYSBGaWd1cmEgXEByZWYoZmlnOmRpc3RhbmNpYTEpLiANCg0KIA0KPGNlbnRlcj4NCg0KYGBge3IgZGlzdGFuY2lhMSwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKk1lZGlkYXMgZGUgZGlzdGFuY2lhcyoqIiwgb3V0LndpZHRoID0gIjcwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJkaXN0YW5jaWExLnBuZyIpDQoNCiNPdHJhIG1hbmVyYSwgcGVybyAgc2FsZSBlbCBjYXB0aW9uOg0KIzxjZW50ZXI+DQojIVsoI2ZpZzpGaWctY2FwdGlvbikgTWkgZmlndXJhXShOb21icmUucG5nKXt3aWR0aD00MDBweH0NCiM8L2NlbnRlcj4NCmBgYA0KPC9jZW50ZXI+DQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRGlzdGFuY2lhcyBnZW9tw6l0cmljYXM6IGNvbXBhcmFjaW9uZXMNCg0KDQpWw6lhc2UgbGEgRmlndXJhIFxAcmVmKGZpZzpkaXN0YW5jaWEyKS4gDQoNCiANCjxjZW50ZXI+DQoNCmBgYHtyIGRpc3RhbmNpYTIsIGVjaG89RkFMU0UsIGZpZy5jYXAgPSAiKipNZWRpZGFzIGRlIGRpc3RhbmNpYXMqKiIsIG91dC53aWR0aCA9ICIxMDAlIn0NCiMgZmlnLndpZHRoID0gMjAgIyBObyBmdW5jaW9uYSBlc3RhIG9wY2lvbiBlbiBlbCBjaHVuaw0KDQojIE9KTzogaHR0cHM6Ly9tZWRpdW0uY29tL0Blc2thbmRhci5zYWhlbC9leHBsb3JpbmctY29tbW9uLWRpc3RhbmNlLW1lYXN1cmVzLWZvci1tYWNoaW5lLWxlYXJuaW5nLWFuZC1kYXRhLXNjaWVuY2UtYS1jb21wYXJhdGl2ZS1hbmFseXNpcy1lYTAyMTZjOTNiYTMNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJkaXN0YW5jaWEyLnBuZyIpDQoNCiNPdHJhIG1hbmVyYSwgcGVybyAgc2FsZSBlbCBjYXB0aW9uOg0KIzxjZW50ZXI+DQojIVsoI2ZpZzpGaWctY2FwdGlvbikgTWkgZmlndXJhXShOb21icmUucG5nKXt3aWR0aD00MDBweH0NCiM8L2NlbnRlcj4NCmBgYA0KPC9jZW50ZXI+DQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIERpc3RhbmNpYSBldWNsaWRpYW5hDQoNCiMjIyBFdWNsaWRpYW5hOiBkZXNjcmlwY2nDs24NCg0KMS4gTGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEgZXMgYWRlY3VhZGEgY3VhbmRvIHNlIHRyYWJhamEgY29uIGVqZXMgb3J0b2dvbmFsZXMuIA0KDQoyLiBMYSBkaXN0YW5jaWEgZXVjbGlkaWFuYSBlbnRyZSBkb3MgcHVudG9zIHAgeSBxIHNlIGRlZmluZSBjb21vIGxhIGxvbmdpdHVkIGRlbCBzZWdtZW50byBxdWUgdW5lIGFtYm9zIHB1bnRvcy4NCg0KMy4gRW4gY29vcmRlbmFkYXMgY2FydGVzaWFuYXMsIGxhIGRpc3RhbmNpYSBldWNsaWRpYW5hIHNlIGNhbGN1bGEgZW1wbGVhbmRvIGVsIHRlb3JlbWEgZGUgUGl0w6Fnb3Jhcy4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KDQojIyMgRXVjbGlkaWFuYTogRsOzcm11bGENCg0KU2kgdGVuZW1vcyBkb3MgdmVjdG9yZXMgJHgkIHkgJHkkLCBkZWZpbmlkb3MgcG9yIGxvcyB2ZWN0b3JlcyAkXG1hdGhiZnt4fSA9ICh4XzEsIHhfMiwgXGxkb3RzLCB4X24pJCB5ICRcbWF0aGJme2J9ID0gKHlfMSwgeV8yLCBcbGRvdHMsIHlfbikkIHJlc3BlY3RpdmFtZW50ZSwgZW50b25jZXMgbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEgZW50cmUgJHhBJCB5ICR5JCwgZGVub3RhZGEgY29tbyAkZF9lKHgseSkkLCBzZSBjYWxjdWxhIGNvbW86DQoNCiQkZF9lKHgseSkgPSBcc3FydHtcc3VtX3tpPTF9XntufSAoeF9pIC0geV9pKV4yfSQkDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoNCiMjIyBFdWNsaWRpYW5hOiBiaWRpbWVuc2lvbmFsDQoNClBhcmEgZWwgY2FzbyBiaWRpbWVuc2lvbmFsLCB2w6lhc2UgbGEgRmlndXJhIFxAcmVmKGZpZzpFdWNsaWRpYW5hMSkuIA0KDQo8Y2VudGVyPg0KDQpgYGB7ciBFdWNsaWRpYW5hMSwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKkRpc3RhbmNpYSBldWNsaWRpYW5hKioiLCBvdXQud2lkdGggPSAiNjAlIn0NCiMgZmlnLndpZHRoID0gMjAgIyBObyBmdW5jaW9uYSBlc3RhIG9wY2lvbiBlbiBlbCBjaHVuaw0KDQojaHR0cDovL3pldnJvc3MuY29tL2Jsb2cvMjAxNy8wNi8xOS90aXBzLWFuZC10cmlja3MtZm9yLXdvcmtpbmctd2l0aC1pbWFnZXMtYW5kLWZpZ3VyZXMtaW4tci1tYXJrZG93bi1kb2N1bWVudHMvDQojIFBhZ2luYSAzNTkgZGUgUjIwMTUtRnJpZW5kbHkNCg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkV1Y2xpZGlhbmExLnBuZyIpDQoNCiNPdHJhIG1hbmVyYSwgcGVybyAgc2FsZSBlbCBjYXB0aW9uOg0KIzxjZW50ZXI+DQojIVsoI2ZpZzpGaWctY2FwdGlvbikgTWkgZmlndXJhXShOb21icmUucG5nKXt3aWR0aD00MDBweH0NCiM8L2NlbnRlcj4NCmBgYA0KPC9jZW50ZXI+DQoNCg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCg0KIyBEaXN0YW5jaWEgZGUgTWlua293c2tpDQoNCiMjIyBNaW5rb3dza2k6IGRlc2NyaXBjacOzbg0KDQoxLiBMYSBkaXN0YW5jaWEgZGUgTWlrb3dza2kgcmVwcmVzZW50YSBsYSBkaXN0YW5jaWEgZW50cmUgZG9zIHB1bnRvcyBjb24gdW4gcmVjb3JyaWRvIHBlcnBlbmRpY3VsYXIgKHNlZ21lbnRvcyBkZSByZWN0YXMgcGFyYWxlbG9zIGEgbG9zIGVqZXMgY29vcmRlbmFkb3MpLg0KDQoyLiBFbiBtdWNob3MgY2Fzb3MgcHJvcG9yY2lvbmEgcmVzdWx0YWRvcyBzaW1pbGFyZXMgYSBsb3MgZGUgbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEuIA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgTWlua293c2tpOiBGw7NybXVsYQ0KDQpTaSBjb25zaWRlcmFtb3MgbG9zIGVsZW1lbnRvcyAkeCQgeSAkeSQgbWVuY2lvbmFkb3MgYW50ZXJpb3JtZW50ZSwgbGEgZGlzdGFuY2lhIGRlIE1pa293c2tpIGVudHJlICR4JCB5ICR5JCwgZGVub3RhZGEgY29tbyAkZF9tKHgseSkkLCBzZSBjYWxjdWxhIGNvbW86DQoNCiQkDQpkX20oeCx5O3ApICBcOz1cOyAgIFxsZWZ0KCBcc3VtX3tpPTF9XntufSB8eF9pIC0geV9pfF5wIFxyaWdodCleezEvcH0sIFxxdWFkIHAgXGdlcSAxLg0KJCQNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBNaW5rb3dza2k6IGJpZGltZW5zaW9uYWwNCg0KDQpMYSBGaWd1cmEgIFxAcmVmKGZpZzpNaW5rMSkgbXVlc3RyYSBjw61yY3Vsb3MgdW5pdGFyaW9zIChlbCBjb25qdW50byBkZSBuaXZlbGVzIGRlIGxhIGZ1bmNpw7NuIGRlIGRpc3RhbmNpYSBkb25kZSB0b2RvcyBsb3MgcHVudG9zIGVzdMOhbiBhIGxhIGRpc3RhbmNpYSB1bml0YXJpYSBkZWwgY2VudHJvKSBjb24gdmFyaW9zIHZhbG9yZXMgZGUgJHAkLg0KDQo8Y2VudGVyPg0KDQpgYGB7ciBNaW5rMSwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKkRpc3RhbmNpYSBkZSBNaW5rb3dza2kgZW4gZWwgcGxhbm8gKCRuPTIkKSBwYXJhIGRpZmVyZW50ZXMgdmFsb3JlcyBkZSAkcCQqKiIsIG91dC53aWR0aCA9ICI3MCUifQ0KIyBmaWcud2lkdGggPSAyMCAjIE5vIGZ1bmNpb25hIGVzdGEgb3BjaW9uIGVuIGVsIGNodW5rDQoNCiNodHRwOi8vemV2cm9zcy5jb20vYmxvZy8yMDE3LzA2LzE5L3RpcHMtYW5kLXRyaWNrcy1mb3Itd29ya2luZy13aXRoLWltYWdlcy1hbmQtZmlndXJlcy1pbi1yLW1hcmtkb3duLWRvY3VtZW50cy8NCiMgUGFnaW5hIDM1OSBkZSBSMjAxNS1GcmllbmRseQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiTWluazEucG5nIikNCg0KI090cmEgbWFuZXJhLCBwZXJvICBzYWxlIGVsIGNhcHRpb246DQojPGNlbnRlcj4NCiMhWygjZmlnOkZpZy1jYXB0aW9uKSBNaSBmaWd1cmFdKE5vbWJyZS5wbmcpe3dpZHRoPTQwMHB4fQ0KIzwvY2VudGVyPg0KYGBgDQo8L2NlbnRlcj4NCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoNCiMgRGlzdGFuY2lhIGRlIE1hbmhhdHRhbg0KDQojIyMgTWFuaGF0dGFuOiBkZXNjcmlwY2nDs24NCg0KMS4gTGEgZsOzcm11bGEgZGUgbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEgZXMgw7p0aWwgcGFyYSBjYWxjdWxhciBkaXN0YW5jaWFzIHRlw7NyaWNhcywgcGVybyBlbiBlbnRvcm5vcyB1cmJhbm9zIHJlYWxlcywgY29tbyB1bmEgY2l1ZGFkLCByYXJhIHZleiBlcyBwb3NpYmxlIG1vdmVyc2UgZGUgdW4gcHVudG8gYSBvdHJvIGVuIGzDrW5lYSByZWN0YSBkZWJpZG8gYSBvYnN0w6FjdWxvcyBjb21vIGNlcmNhcywgZWRpZmljaW9zIHkgY2FsbGVzLiANCg0KMi4gRW4gY2FtYmlvLCBkZWJlbW9zIHNlZ3VpciBydXRhcyB0cmF6YWRhcyBwb3IgY2FsbGVzLCBxdWUgZ2VuZXJhbG1lbnRlIGZvcm1hbiB1bmEgY3VhZHLDrWN1bGEuIEVuIGVzdGUgY29udGV4dG8gdXJiYW5vLCBsYSBkaXN0YW5jaWEgTWFuaGF0dGFuIHJlc3VsdGEgbcOhcyBwcsOhY3RpY2EsIHlhIHF1ZSBwZXJtaXRlIGNhbGN1bGFyIGxhIGRpc3RhbmNpYSBlbnRyZSBkb3MgcHVudG9zIGVuIHVuYSBjdWFkcsOtY3VsYSB1bmlmb3JtZSwgY29tbyBsYXMgY3VhZHJhcyBkZSB1bmEgY2l1ZGFkIG8gdW4gdGFibGVybyBkZSBhamVkcmV6LiANCg0KDQozLiBFc3RhIG1lZGlkYSBlcyBlc3BlY2lhbG1lbnRlIMO6dGlsIGVuIGVudG9ybm9zIHVyYmFub3MgZGViaWRvIGEgbGEgZGlzcG9zaWNpw7NuIGRlIGxhcyBjYWxsZXMgZW4gZm9ybWEgZGUgY3VhZHLDrWN1bGEsIGNvbW8gZXMgZWwgY2FzbyBkZSBtdWNoYXMgw6FyZWFzIGRlIGxhIGlzbGEgZGUgTWFuaGF0dGFuICh2w6lhc2UgbGEgRmlndXJhIFxAcmVmKGZpZzpNYW4xKSksIGRlIGFow60gc3Ugbm9tYnJlLCBhdW5xdWUgQnJvYWR3YXkgZXMgdW5hIGV4Y2VwY2nDs24gYSBlc3RlIGRpc2XDsW8gZGUgY3VhZHLDrWN1bGEuIA0KDQoNCjxjZW50ZXI+DQoNCmBgYHtyIE1hbjEsIGVjaG89RkFMU0UsIGZpZy5jYXAgPSAiKipJc2xhIGRlIE1hbmhhdHRhbioqIiwgb3V0LndpZHRoID0gIjgwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJNYW4xLnBuZyIpDQoNCiNPdHJhIG1hbmVyYSwgcGVybyAgc2FsZSBlbCBjYXB0aW9uOg0KIzxjZW50ZXI+DQojIVsoI2ZpZzpGaWctY2FwdGlvbikgTWkgZmlndXJhXShOb21icmUucG5nKXt3aWR0aD00MDBweH0NCiM8L2NlbnRlcj4NCmBgYA0KPC9jZW50ZXI+DQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIE1hbmhhdHRhbjogZsOzcm11bGENCg0KQSBsYSBkaXN0YW5jaWEgZGUgTWlua293c2tpIHNlIGxlIGRlbm9taW5hIGRpc3RhbmNpYSBDaXR5IEJsb2NrIG8gZGUgTWFuaGF0dGFuIHNpICRwPTEkLiBFcyBkZWNpciwgDQoNCiQkZF97bWFufSh4LHkpIFw7PVw7ICBcc3VtX3tpPTF9XntufSB8eF9pIC0geV9pfCQkDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgTWFuaGF0dGFuOiB2aXN1YWxpemFjacOzbg0KDQpQYXJhIHVuYSB2aXN1YWxpemFjacOzbiwgdsOpYXNlIGxhIEZpZ3VyYSBcQHJlZihmaWc6TWFuMikuIA0KDQo8Y2VudGVyPg0KDQpgYGB7ciBNYW4yLCBlY2hvPUZBTFNFLCBmaWcuY2FwID0gIioqRGlzdGFuY2lhIGRlIE1hbmhhdHRhbioqIiwgb3V0LndpZHRoID0gIjgwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJNYW4yLnBuZyIpDQoNCiNPdHJhIG1hbmVyYSwgcGVybyAgc2FsZSBlbCBjYXB0aW9uOg0KIzxjZW50ZXI+DQojIVsoI2ZpZzpGaWctY2FwdGlvbikgTWkgZmlndXJhXShOb21icmUucG5nKXt3aWR0aD00MDBweH0NCiM8L2NlbnRlcj4NCmBgYA0KPC9jZW50ZXI+DQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIE1hbmhhdHRhbjogZWplbXBsbw0KDQoNClNlIG1vc3RhcnLDoSB1biBlamVtcGxvIGdyw6FmaWNvIGRlIGxhIGRpc3RhbmNpYSBkZSBtYW5oYXR0YW4gcGFyYSBlbCBjYXNvIGRlIHVuIHNlY3RvciBkZSBCYXJyYW5xdWlsbGEgKENvbG9tYmlhKS4gRW4gZWxsYSwgc2UgY29tcGFyYSB0YW1iacOpbiBjb24gbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEuIFbDqWFzZSBsYSBGaWd1cmEgXEByZWYoZmlnOk1hbjMpLiANCg0KPGNlbnRlcj4NCg0KYGBge3IgTWFuMywgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKkRpc3RhbmNpYSBkZSBNYW5oYXR0YW4gdmVyc3VzIGV1Y2xpZGlhbmEqKiIsIG91dC53aWR0aCA9ICI4MCUifQ0KIyBmaWcud2lkdGggPSAyMCAjIE5vIGZ1bmNpb25hIGVzdGEgb3BjaW9uIGVuIGVsIGNodW5rDQoNCiNodHRwOi8vemV2cm9zcy5jb20vYmxvZy8yMDE3LzA2LzE5L3RpcHMtYW5kLXRyaWNrcy1mb3Itd29ya2luZy13aXRoLWltYWdlcy1hbmQtZmlndXJlcy1pbi1yLW1hcmtkb3duLWRvY3VtZW50cy8NCiMgUGFnaW5hIDM1OSBkZSBSMjAxNS1GcmllbmRseQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiTWFuMy5wbmciKQ0KDQojT3RyYSBtYW5lcmEsIHBlcm8gIHNhbGUgZWwgY2FwdGlvbjoNCiM8Y2VudGVyPg0KIyFbKCNmaWc6RmlnLWNhcHRpb24pIE1pIGZpZ3VyYV0oTm9tYnJlLnBuZyl7d2lkdGg9NDAwcHh9DQojPC9jZW50ZXI+DQpgYGANCjwvY2VudGVyPg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIERpc3RhbmNpYSBkZSBDaGVieXNoZXYNCg0KDQojIyMgQ2hlYnlzaGV2OiBmw7NybXVsYQ0KDQpMYSBkaXN0YW5jaWEgZGUgQ2hlYnlzaGV2IHNlIGNhbGN1bGEgY29tbzoNCg0KJCQNCmRfe2NofSh4LHkpID0gXG1heF97aT0xLFxsZG90cyxufSB8eF9pIC0geV9pfC4NCiQkDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgQ2hlYnlzaGV2OiBncsOhZmljbyBjb21wYXJhdGl2bw0KDQpFbiBsYSBGaWd1cmEgXEByZWYoZmlnOkNoZTEpIHNlIG11ZXN0cmEgZ3LDoWZpY2FtZW50ZSBsYSBjb21wYXJhY2nDs24gZGUgbGFzIGRpc3RhbmNpYXMgZGUgQ2hlYnlzaGV2LCBldWNsaWRpYW5hIHkgdGF4aWNhYiBwYXJhIGxhIGhpcG90ZW51c2EgZGUgdW4gdHJpw6FuZ3VsbyAzLTQtNSBlbiB1biB0YWJsZXJvIGRlIGFqZWRyZXouDQoNCg0KPGNlbnRlcj4NCg0KYGBge3IgQ2hlMSwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKkNvbXBhcmFjacOzbiBkZSBsYXMgZGlzdGFuY2lhcyBkZSBDaGVieXNoZXYsIGV1Y2xpZGlhbmEgeSB0YXhpY2FiIHBhcmEgbGEgaGlwb3RlbnVzYSBkZSB1biB0cmnDoW5ndWxvIDMtNC01IGVuIHVuIHRhYmxlcm8gZGUgYWplZHJlei4qKiIsIG91dC53aWR0aCA9ICI1MCUifQ0KIyBmaWcud2lkdGggPSAyMCAjIE5vIGZ1bmNpb25hIGVzdGEgb3BjaW9uIGVuIGVsIGNodW5rDQoNCiNodHRwOi8vemV2cm9zcy5jb20vYmxvZy8yMDE3LzA2LzE5L3RpcHMtYW5kLXRyaWNrcy1mb3Itd29ya2luZy13aXRoLWltYWdlcy1hbmQtZmlndXJlcy1pbi1yLW1hcmtkb3duLWRvY3VtZW50cy8NCiMgUGFnaW5hIDM1OSBkZSBSMjAxNS1GcmllbmRseQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiQ2hlMS5wbmciKQ0KDQojT3RyYSBtYW5lcmEsIHBlcm8gIHNhbGUgZWwgY2FwdGlvbjoNCiM8Y2VudGVyPg0KIyFbKCNmaWc6RmlnLWNhcHRpb24pIE1pIGZpZ3VyYV0oTm9tYnJlLnBuZyl7d2lkdGg9NDAwcHh9DQojPC9jZW50ZXI+DQpgYGANCjwvY2VudGVyPg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBDaGVieXNoZXY6IG9ic2VydmFjacOzbg0KDQpFbiBlbCBjYXNvIGzDrW1pdGUgZGUgJHAkIChjdWFuZG8gYWxjYW56YSBlbCBpbmZpbml0byksIHNlIGN1bXBsZSBxdWU6DQoNCiQkXGxpbVxsaW1pdHNfe3AgXCxcdG8gXCwgXGluZnR5fSBkX20oeCx5O3ApIFw7ID0gXDsgZF97Y2h9KHgseSkgJCQNCg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRGlzdGFuY2lhIGRlIE1hbGFoYW5vYmlzDQoNCiMjIyBNYWhhbGFub2JpczogZGVzY3JpcGNpw7NuDQoNCjEuIExhIGRpc3RhbmNpYSBkZSBNYWhhbGFub2JpcyB0aWVuZSB1bmEgbcOpdHJpY2EgZGlmZXJlbnRlIGEgbGEgZXVjbGlkaWFuYSB5IGVzIHJlY29tZW5kYWJsZSBwYXJhIHNpdHVhY2lvbmVzIGVuIGxhcyBxdWUgaGF5IG11bHRpY29saW5lYWxpZGFkLiANCg0KMi4gQ29pbmNpZGUgY29uIGxhIGRpc3RhbmNpYSBldWNsaWRpYW5hIHBhcmEgdmFyaWFibGVzIGVzdGFuZGFyaXphZGFzIGN1YW5kbyBsYXMgY29ycmVsYWNpb25lcyBzb24gbnVsYXMuIA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIE1haGFsYW5vYmlzOiBmw7NybXVsYQ0KDQpTaSAkXFNpZ21hJCBlcyBsYSBtYXRyaXogZGUgdmFyaWFuemEtY292YXJpYW56YSwgZXN0YSBkaXN0YW5jaWEgc2UgY2FsY3VsYSBhIHBhcnRpciBkZSBsYSBleHByZXNpw7NuOg0KDQokJGQoeCx5KSA9ICh4IC0geSleVCBcU2lnbWFeey0xfSAoeCAtIHkpJCQNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBNYWhhbGFub2JpczogZ3LDoWZpY2ENCg0KDQpFbiBsYSBGaWd1cmEgXEByZWYoZmlnOk1haGExKSBzZSBtdWVzdHJhIGdyw6FmaWNhbWVudGUgZGlmZXJlbnRlcyBkaXN0YW5jaWFzIGRlIE1hbGFoYW5vYmlzLiBFbiBlbGxhIHZlbW9zIHF1ZSByZXN1bHRhbiBjbGFyYW1lbnRlIHBhdHJvbmVzIGVsw61wdGljb3MuIA0KDQoNCjxjZW50ZXI+DQoNCmBgYHtyIE1haGExLCBlY2hvPUZBTFNFLCBmaWcuY2FwID0gIioqRGlzdGFuY2lhcyBkZSBNYWxhaGFub2Jpcy4qKiIsIG91dC53aWR0aCA9ICI3MCUifQ0KIyBmaWcud2lkdGggPSAyMCAjIE5vIGZ1bmNpb25hIGVzdGEgb3BjaW9uIGVuIGVsIGNodW5rDQoNCiNodHRwOi8vemV2cm9zcy5jb20vYmxvZy8yMDE3LzA2LzE5L3RpcHMtYW5kLXRyaWNrcy1mb3Itd29ya2luZy13aXRoLWltYWdlcy1hbmQtZmlndXJlcy1pbi1yLW1hcmtkb3duLWRvY3VtZW50cy8NCiMgUGFnaW5hIDM1OSBkZSBSMjAxNS1GcmllbmRseQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiTWFoYTEucG5nIikNCg0KI090cmEgbWFuZXJhLCBwZXJvICBzYWxlIGVsIGNhcHRpb246DQojPGNlbnRlcj4NCiMhWygjZmlnOkZpZy1jYXB0aW9uKSBNaSBmaWd1cmFdKE5vbWJyZS5wbmcpe3dpZHRoPTQwMHB4fQ0KIzwvY2VudGVyPg0KYGBgDQo8L2NlbnRlcj4NCg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgTWVkaWRhcyBiYXNhZGFzIGVuIMOtbmRpY2VzIGRlIHNpbWlsaXR1ZA0KDQoNCg0KIyMjIFNpbWlsaXR1ZDogdGlwb3MNCg0KQ29tbyBtZWRpZGFzIGRlIGRpc3RhbmNpYXMgYmFzYWRhcyBlbiDDrW5kaWNlcyBkZSBzaW1pbGl0dWQgc2UgdGllbmVuLCBlbnRyZSBvdHJhcywgbGFzIHNpZ3VpZW50ZXM6IA0KDQoxLiDDr25kaWNlIGRlIFNva2FsIHkgTWljaGVuZXIuDQoNCjIuIMONbmRpY2UgZGUgUm9nZXJzIHkgVGFuaW1vdG8uDQoNCjMuIMONbmRpY2UgZGUgU29rYWwgeSBTbmVhdGguIA0KDQpWw6lhc2UgbGEgRmlndXJhIFxAcmVmKGZpZzpkaXN0YW5jaWEwYykuIE3DoXMgYWRlbGFudGUsIHNlIGV4cGxpY2Fyw6FuIGVzdG9zIMOtbmRpY2VzLiANCg0KDQogDQo8Y2VudGVyPg0KDQpgYGB7ciBkaXN0YW5jaWEwYywgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKk1lZGlkYXMgZGUgZGlzdGFuY2lhcyBwYXJhIGFncnVwYW1pZW50byAoYmFzYWRhIGVuIMOtbmRpY2VzIGRlIHNpbWlsaXR1ZCkqKiIsIG91dC53aWR0aCA9ICI4MCUifQ0KIyBmaWcud2lkdGggPSAyMCAjIE5vIGZ1bmNpb25hIGVzdGEgb3BjaW9uIGVuIGVsIGNodW5rDQoNCiNodHRwOi8vemV2cm9zcy5jb20vYmxvZy8yMDE3LzA2LzE5L3RpcHMtYW5kLXRyaWNrcy1mb3Itd29ya2luZy13aXRoLWltYWdlcy1hbmQtZmlndXJlcy1pbi1yLW1hcmtkb3duLWRvY3VtZW50cy8NCiMgUGFnaW5hIDM1OSBkZSBSMjAxNS1GcmllbmRseQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZGlzdGFuY2lhMGMucG5nIikNCg0KI090cmEgbWFuZXJhLCBwZXJvICBzYWxlIGVsIGNhcHRpb246DQojPGNlbnRlcj4NCiMhWygjZmlnOkZpZy1jYXB0aW9uKSBNaSBmaWd1cmFdKE5vbWJyZS5wbmcpe3dpZHRoPTQwMHB4fQ0KIzwvY2VudGVyPg0KYGBgDQo8L2NlbnRlcj4NCg0KDQoNCg0KIyMjIFNpbWlsaXR1ZDogZGVzY3JpcGNpw7NuDQoNClRpZW5lIHVuYSBuYXR1cmFsZXphIGN1YWxpdGF0aXZhIHkgZGVub3RhcmVtb3MgbGEgc2ltaWxpdHVkIGVudHJlICR4JCB5ICR5JCBjb21vICRTX3t4eX0kLiAgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgU2ltaWxpdHVkOiBjb25kaWNpb25lcw0KDQpMYXMgbWVkaWRhcyBkZSBzaW1pbGl0dWQgZGViZW4gY3VtcGxpciBjb24gbGFzIHNpZ3VpZW50ZXMgY29kaWNpb25lczoNCg0KMS4gJFNfe3h5fSA9IFNfe3l4fSQuIA0KDQoyLiAkU197eHh9ID0gU197eXl9JC4NCg0KMy4gU2kgJFNfe3h5fSQgeSAkU197eXd9JCBzb24gZ3JhbmRlcywgZW50b25jZXMgJFNfe3h3fSQgdGFtYmnDqW4gbG8gZXMuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoNCiMjIyBTaW1pbGl0dWQ6IG3DqXRvZG9zIGRlIGPDoWxjdWxvDQoNCjEuIExhcyBtZWRpZGFzIGRlIHNpbWlsaXR1ZCBwdWVkZW4gb2J0ZW5lcnNlIGRlIGRpdmVyc2FzIGZvcm1hcywgeWEgc2VhIGludGVycm9nYW5kbyBkaXJlY3RhbWVudGUgYSBsYXMgcGVyc29uYXMgc29icmUgc3UgcGVyY2VwY2nDs24gbyBtaWRpZW5kbyBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBvIGF0cmlidXRvcyAocG9zZXNpw7NuIGRlKS4gDQoNCjIuIFVuIGNhc28gcGFydGljdWxhciBlcyBlbCB1c28gZGUgdmFyaWFibGVzIGJpbmFyaWFzLCBjb24gdmFsb3JlcyAwIHkgMSwgYSBwYXJ0aXIgZGUgbGFzIGN1YWxlcyBzZSBjb25zdHJ1eWVuIMOtbmRpY2VzLiANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCg0KIyMjIFNpbWlsaXR1ZDogcG9zaWJpbGlkYWRlcyBkZSBjb2luY2lkZW5jaWENCg0KTGFzIHBvc2liaWxpZGFkZXMgZGUgY29pbmNpZGVuY2lhIHNvbjoNCg0KXGJlZ2lue2FsaWduKn0NCnAgJiA9IFx0ZXh0e27Dum1lcm8gZGUgY29pbmNpZGVuY2lhcyBwb3NpdGl2YXMgKDEsMSl9IFxcDQpuICYgPSBcdGV4dHtuw7ptZXJvIGRlIGNvaW5jaWRlbmNpYXMgbmVnYXRpdmFzICgwLDApfSBcXA0KZCAmID0gXHRleHR7bsO6bWVybyBkZSBkaWZlcmVuY2lhcyAoMSwwKX0gXFwNCmUgJiA9IFx0ZXh0e27Dum1lcm8gZGUgZGlmZXJlbmNpYXMgKDAsMSl9IFxcDQp0ICYgPSBwICsgbiArIGQgKyBlDQpcZW5ke2FsaWduKn0NCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCg0KIyMjIFNpbWlsaXR1ZDogw61uZGljZXMgZGUgY29pbmNpZGVuY2lhcw0KDQpMYSBjb21iaW5hY2nDs24gZGUgZXN0YXMgc2l0dWFjaW9uZXMgZGEgbHVnYXIgYSB1bmEgYW1wbGlhIGdhbWEgZGUgw61uZGljZXMsIHNlZ8O6biBzZSBwcmlvcmljZW4gbGFzIGNvaW5jaWRlbmNpYXMgcG9zaXRpdmFzLCBuZWdhdGl2YXMgbyBsYXMgZGlmZXJlbmNpYXMgZGUgdW5vIHUgb3RybyB0aXBvLiBBbGd1bm9zIGRlIGVzdG9zIMOtbmRpY2VzIHNvbjoNCg0KDQoxLiAqw41uZGljZSBkZSBTb2thbCB5IE1pY2hlbmVyLioNCg0KDQokJEkgXDs9XDsgXGZyYWN7e3AgKyBufX17dH0gICQkDQoNCjIuICrDjW5kaWNlIGRlIFJvZ2VycyB5IFRhbmltb3RvLioNCg0KJCRJICAgXDs9XDsgIFxmcmFje3t0IC0gKGQgKyBlKX19e3t0ICsgKGQgKyBlKX19ICBcOz1cOyAgXGZyYWN7e3AgKyBufX17e3AgKyBuICsgMihkICsgZSl9fSQkDQoNCjMuICrDjW5kaWNlIGRlIFNva2FsIHkgU25lYXRoLioNCg0KJCRJICAgXDs9XDsgIFxmcmFje3B9e3twICsgbiArIDIoZCArIGUpfX0kJA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyDCv0N1w6FsIGRpc3RhbmNpYSBlc2NvZ2VyPw0KDQoxLiBMYSBzZWxlY2Npw7NuIGRlIG1lZGlkYXMgZGUgZGlzdGFuY2lhIGVzIGZ1bmRhbWVudGFsLCB5YSBxdWUgZWplcmNlIHVuYSBmdWVydGUgaW5mbHVlbmNpYSBlbiBsb3MgcmVzdWx0YWRvcyBkZSBhZ3J1cGFtaWVudG8uIA0KDQoyLiBFbiBsYSBtYXlvcsOtYSBkZSBsb3Mgc29mdHdhcmUgZGUgYWdydXBhbWllbnRvIGNvbnZlbmNpb25hbGVzLCBsYSBtZWRpZGEgZGUgZGlzdGFuY2lhIHBvciBkZWZlY3RvIGVzIGxhIGV1Y2xpZGlhbmEuIA0KDQozLiBTaW4gZW1iYXJnbywgc2Vnw7puIGVsIHRpcG8gZGUgZGF0b3MgeSBsYXMgaW50ZXJyb2dhbnRlcyBkZWwgaW52ZXN0aWdhZG9yLCBlcyBwb3NpYmxlIHF1ZSBzZSBwcmVmaWVyYW4gb3RyYXMgbWVkaWRhcyBkZSBkaXNpbWlsaXR1ZC4gDQoNCjQuIFBvciBlamVtcGxvLCBlbiBlbCBhbsOhbGlzaXMgZGUgZGF0b3MgZGUgZXhwcmVzacOzbiBnw6luaWNhIHNlIHJlY3VycmUgZnJlY3VlbnRlbWVudGUgYSBsYSBkaXN0YW5jaWEgYmFzYWRhIGVuIGNvcnJlbGFjacOzbi4NCg0KNS4gRXN0YSBtZWRpZGEgZGUgZGlzdGFuY2lhIGJhc2FkYSBlbiBjb3JyZWxhY2nDs24gY29uc2lkZXJhIGRvcyBlbGVtZW50b3MgY29tbyBzaW1pbGFyZXMgc2kgc3VzIGNhcmFjdGVyw61zdGljYXMgZXN0w6FuIGFsdGFtZW50ZSBjb3JyZWxhY2lvbmFkYXMsIGluY2x1c28gc2kgbG9zIHZhbG9yZXMgb2JzZXJ2YWRvcyBkaWZpZXJlbiBzaWduaWZpY2F0aXZhbWVudGUgZW4gdMOpcm1pbm9zIGRlIGRpc3RhbmNpYSBldWNsaWRpYW5hLiANCg0KNi4gRGUgaGVjaG8sIGxhIGRpc3RhbmNpYSBlbnRyZSBkb3MgZWxlbWVudG9zIGVzIG51bGEgY3VhbmRvIGVzdMOhbiBwZXJmZWN0YW1lbnRlIGNvcnJlbGFjaW9uYWRvcy4gDQoNCjcuIE5vIG9ic3RhbnRlLCBsYSBjb3JyZWxhY2nDs24gZGUgUGVhcnNvbiBwdWVkZSBzZXIgYmFzdGFudGUgc3VzY2VwdGlibGUgYSB2YWxvcmVzIGF0w61waWNvcy4gDQoNCjguIEF1bnF1ZSBlc3RlIGFzcGVjdG8gbm8gc3VlbGUgc2VyIHByb2JsZW3DoXRpY28gYWwgYWdydXBhciBtdWVzdHJhcywgZGFkbyBxdWUgc2UgY2FsY3VsYSBsYSBjb3JyZWxhY2nDs24gZW50cmUgbWlsZXMgZGUgZ2VuZXMsIHPDrSBlcyByZWxldmFudGUgYWwgYWdydXBhciBnZW5lcywgZG9uZGUgZXMgZnVuZGFtZW50YWwgdGVuZXIgZW4gY3VlbnRhIGxhIHBvc2libGUgaW5mbHVlbmNpYSBkZSB2YWxvcmVzIGF0w61waWNvcy4gDQoNCjkuIFBhcmEgbWl0aWdhciBlc3RlIGVmZWN0bywgZXMgcG9zaWJsZSBlbXBsZWFyIGxhIGNvcnJlbGFjacOzbiBkZSBTcGVhcm1hbiBlbiBsdWdhciBkZSBsYSBkZSBQZWFyc29uLg0KDQoxMC4gU2kgbnVlc3RybyBvYmpldGl2byBlcyBpZGVudGlmaWNhciBncnVwb3MgZGUgb2JzZXJ2YWNpb25lcyBjb24gcGVyZmlsZXMgZ2VuZXJhbGVzIHNpbWlsYXJlcyBpbmRlcGVuZGllbnRlbWVudGUgZGUgc3VzIG1hZ25pdHVkZXMsIGVzIGFjb25zZWphYmxlIG9wdGFyIHBvciBsYSBkaXN0YW5jaWEgYmFzYWRhIGVuIGNvcnJlbGFjacOzbiBjb21vIG1lZGlkYSBkZSBkaXNpbWlsaXR1ZC4gDQoNCjExLiBFc3RlIGVuZm9xdWUgcmVzdWx0YSBlc3BlY2lhbG1lbnRlIHBlcnRpbmVudGUgZW4gZWwgYW7DoWxpc2lzIGRlIGRhdG9zIGRlIGV4cHJlc2nDs24gZ8OpbmljYSwgZG9uZGUgbm9zIGludGVyZXNhIGNvbnNpZGVyYXIgZ2VuZXMgc2ltaWxhcmVzIGN1YW5kbyBwcmVzZW50YW4gcGF0cm9uZXMgZGUgInN1YmlkYSIgeSAiYmFqYWRhIiBjb25qdW50b3MuIA0KDQoxMi4gVGFtYmnDqW4gZXMgYXBsaWNhYmxlIGVuIGVsIMOhbWJpdG8gZGVsIG1hcmtldGluZyBzaSBkZXNlYW1vcyBpZGVudGlmaWNhciBncnVwb3MgZGUgY29uc3VtaWRvcmVzIGNvbiBsYXMgbWlzbWFzIHByZWZlcmVuY2lhcyBlbiB0w6lybWlub3MgZGUgcHJvZHVjdG9zLCBzaW4gaW1wb3J0YXIgZWwgdm9sdW1lbiBkZSBjb21wcmEuDQoNCjEzLiBFbiBjb250cmFwb3NpY2nDs24sIHNpIHNlIHV0aWxpemEgbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEsIGVzIHByb2JhYmxlIHF1ZSBsYXMgb2JzZXJ2YWNpb25lcyBjb24gdmFsb3JlcyBhbHRvcyBkZSBjYXJhY3RlcsOtc3RpY2FzIHNlIGFncnVwZW4gZW50cmUgc8OtLCBhbCBpZ3VhbCBxdWUgbGFzIG9ic2VydmFjaW9uZXMgY29uIHZhbG9yZXMgYmFqb3MgZGUgY2FyYWN0ZXLDrXN0aWNhcy4NCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRXN0YW5kYXJpemFjacOzbiBkZSBkYXRvcw0KDQojIyMgRXN0YW5kYXJpemFjacOzbjogZXhwbGljYWNpw7NuDQoNCjEuIExhIGltcG9ydGFuY2lhIGRlIGxhcyBtZWRpZGFzIGRlIGRpc3RhbmNpYSBlc3TDoSBlc3RyZWNoYW1lbnRlIGxpZ2FkYSBhIGxhIGVzY2FsYSBlbiBsYSBxdWUgc2UgdG9tYW4gbGFzIG1lZGljaW9uZXMuIA0KDQoyLiBQb3IgbG8gdGFudG8sIGVzIGNvbcO6biBlc3RhbmRhcml6YXIgbGFzIHZhcmlhYmxlcyBhbnRlcyBkZSBjYWxjdWxhciBsYXMgZGlmZXJlbmNpYXMgZW50cmUgb2JzZXJ2YWNpb25lcy4gDQoNCjMuIEVzdGUgcHJvY2VzbyBlcyBlc3BlY2lhbG1lbnRlIHJlY29tZW5kYWJsZSBjdWFuZG8gbGFzIHZhcmlhYmxlcyBzZSBtaWRlbiBlbiBlc2NhbGFzIGRpc3RpbnRhcyAocG9yIGVqZW1wbG8sIGtpbG9ncmFtb3MsIGtpbMOzbWV0cm9zLCBjZW50w61tZXRyb3MsIGV0Yy4pLCB5YSBxdWUgZGUgbG8gY29udHJhcmlvLCBsYXMgbWVkaWRhcyBkZSBkaWZlcmVuY2lhIHJlc3VsdGFudGVzIHBvZHLDrWFuIGVzdGFyIGNvbnNpZGVyYWJsZW1lbnRlIGFmZWN0YWRhcy4NCg0KNC4gRWwgcHJvcMOzc2l0byBwcmluY2lwYWwgZXMgbG9ncmFyIHF1ZSBsYXMgdmFyaWFibGVzIHNlYW4gY29tcGFyYWJsZXMuIE5vcm1hbG1lbnRlLCBsYXMgdmFyaWFibGVzIHNlIGVzdGFuZGFyaXphbiBwYXJhIHRlbmVyIHVuYSBkZXN2aWFjacOzbiBlc3TDoW5kYXIgZGUgdW5vIHkgdW5hIG1lZGlhIGRlIGNlcm8uDQoNCjUuIExhIGVzdGFuZGFyaXphY2nDs24gZGUgZGF0b3MgZXMgdW5hIHTDqWNuaWNhIG11eSB1dGlsaXphZGEgZW4gZWwgYW7DoWxpc2lzIGRlIGRhdG9zIGRlIGV4cHJlc2nDs24gZ8OpbmljYSBhbnRlcyBkZSByZWFsaXphciBhZ3J1cGFjaW9uZXMuDQoNCjYuIFRhbWJpw6luIHB1ZWRlIHNlciDDunRpbCBlc2NhbGFyIGxvcyBkYXRvcyBjdWFuZG8gbGEgbWVkaWEgeS9vIGxhIGRlc3ZpYWNpw7NuIGVzdMOhbmRhciBkZSBsYXMgdmFyaWFibGVzIHNvbiBtdXkgZGlmZXJlbnRlcy4NCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBFc3RhbmRhcml6YWNpw7NuOiBmw7NybXVsYSANCg0KQWwgZXN0YW5kYXJpemFyIGxhcyB2YXJpYWJsZXMsIGxvcyBkYXRvcyBwdWVkZW4gc2VyIHRyYW5zZm9ybWFkb3MgZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KJCRcZnJhY3t4X2kgXCwtXCwgY2VudHJvKHgpfXtlc2NhbGEoeCl9JCQNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBFc3RhbmRhcml6YWNpw7NuOiBpbnRlcnByZXRhY2nDs24NCg0KRW4gbGEgZm9ybXVsYSBhbnRlcmlvcjogDQoNCjEuIEVsIGNlbnRybyBkZSBsb3MgZGF0b3MgKHJlcHJlc2VudGFkbyBwb3IgJHgkKSBwdWVkZSBzZXIgdGFudG8gbGEgbWVkaWEgY29tbyBsYSBtZWRpYW5hIGRlIGxvcyB2YWxvcmVzIGRlICR4JC4NCg0KMi4gTGEgZXNjYWxhIChyZXByZXNlbnRhZGEgdGFtYmnDqW4gcG9yICR4JCkgcHVlZGUgdG9tYXIgbGEgZm9ybWEgZGUgbGEgZGVzdmlhY2nDs24gZXN0w6FuZGFyIChTRCksIGVsIHJhbmdvIGludGVyY3VhcnRpbCBvIGxhIE1BRCAoZGVzdmlhY2nDs24gYWJzb2x1dGEgbWVkaWFuYSkuDQoNCjMuIFRtYWJpw6luIGV4aXN0ZSBsYSBsbGFtYWRhIGbDs3JtdWxhIGRlIG5vcm1hbGl6YWNpw7NuIChlc2NhbGEgbWluLW1heCk6IA0KDQokJFxmcmFje3hfaSBcLC1cLCBcbWluKHgpfXtcbWF4KHgpIFwsLVwsIFxtaW4oeCl9JCQNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIEVzdGFuZGFyaXphY2nDs246IGVqZW1wbG8NCg0KVsOpYXNlIGxhIEZpZ3VyYSBcQHJlZihmaWc6c3RkMSkuICANCg0KPGNlbnRlcj4NCg0KYGBge3Igc3RkMSwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKkRhdG9zIGVzdGFuZGFyaXphZG9zIHkgbm9ybWFsaXphZG9zKioiLCBvdXQud2lkdGggPSAiNzAlIn0NCiMgZmlnLndpZHRoID0gMjAgIyBObyBmdW5jaW9uYSBlc3RhIG9wY2lvbiBlbiBlbCBjaHVuaw0KDQojaHR0cDovL3pldnJvc3MuY29tL2Jsb2cvMjAxNy8wNi8xOS90aXBzLWFuZC10cmlja3MtZm9yLXdvcmtpbmctd2l0aC1pbWFnZXMtYW5kLWZpZ3VyZXMtaW4tci1tYXJrZG93bi1kb2N1bWVudHMvDQojIFBhZ2luYSAzNTkgZGUgUjIwMTUtRnJpZW5kbHkNCg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoInN0ZDEucG5nIikNCg0KI090cmEgbWFuZXJhLCBwZXJvICBzYWxlIGVsIGNhcHRpb246DQojPGNlbnRlcj4NCiMhWygjZmlnOkZpZy1jYXB0aW9uKSBNaSBmaWd1cmFdKE5vbWJyZS5wbmcpe3dpZHRoPTQwMHB4fQ0KIzwvY2VudGVyPg0KYGBgDQo8L2NlbnRlcj4NCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBPYnNlcnZhY2nDs24NCg0KTGEgZXN0YW5kYXJpemFjacOzbiBjb250cmlidXllIGEgcXVlIGxvcyBjdWF0cm8gbcOpdG9kb3MgZGUgbWVkaWRhIGRlIGRpc3RhbmNpYSAoRXVjbGlkaWFuYSwgTWFuaGF0dGFuLCBDb3JyZWxhY2nDs24geSBFaXNlbikgc2UgdnVlbHZhbiBtw6FzIGhvbW9nw6luZW9zIGRlIGxvIHF1ZSBzZXLDrWFuIGNvbiBkYXRvcyBubyB0cmFuc2Zvcm1hZG9zLg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIEZ1bmNpw7NuIGBzY2FsZWAgZW4gUg0KDQpMYSBmdW5jacOzbiBiYXNlIGRlIFIsICBgc2NhbGVgLCBwdWVkZSBlbXBsZWFyc2UgcGFyYSBlc3RhbmRhcml6YXIgbG9zIGRhdG9zLCBvcGVyYW5kbyBzb2JyZSB1bmEgbWF0cml6IG51bcOpcmljYSB5IGFwbGljYW5kbyBsYSBlc2NhbGEgYSBsYXMgY29sdW1uYXMgY29ycmVzcG9uZGllbnRlcy4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIERpc3RhbmNpYSBldWNsaWRpYW5hIHZzIFBlYXJzb24NCg0KMS4gRXMgaW1wb3J0YW50ZSB0ZW5lciBlbiBjdWVudGEgcXVlLCBhbCBlc3RhbmRhcml6YXIgbG9zIGRhdG9zLCBzZSBlc3RhYmxlY2UgdW5hIHJlbGFjacOzbiBmdW5jaW9uYWwgZW50cmUgZWwgY29lZmljaWVudGUgZGUgY29ycmVsYWNpw7NuIGRlIFBlYXJzb24gJHJfe2V1Y309cih4LCB5KSQgeSBsYSBkaXN0YW5jaWEgZXVjbGlkaWFuYS4gDQoNCg0KMi4gU2kgJHgkIGUgJHkkIHNvbiBkb3MgdmVjdG9yZXMgZXN0YW5kYXJpemFkb3MgKGRlIHRhbWHDsW8gJG4kKSBjb24gbWVkaWEgY2VybyB5IGxvbmdpdHVkIDEsIGVzdGEgcmVsYWNpw7NuIHB1ZWRlIGV4cHJlc2Fyc2UgY29tbzoNCg0KJCRkX3tldWN9KHgsIHkpICBcOz1cOyBcc3FydHsyblwsKDEgLSByX3tldWN9KX0kJA0KDQozLiAgUG9yIGxvIHRhbnRvLCBlbCByZXN1bHRhZG8gb2J0ZW5pZG8gbWVkaWFudGUgbGFzIG1lZGlkYXMgZGUgY29ycmVsYWNpw7NuIGRlIFBlYXJzb24geSBsYXMgZGlzdGFuY2lhcyBldWNsaWRpYW5hcyBlc3RhbmRhcml6YWRhcyBzb24gY29tcGFyYWJsZXMuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojICBQcm9jZWRpbWllbnRvcyBkZSBhZ3J1cGFjacOzbg0KDQpQYXJhIGxhIGFncnVwYWNpw7NuIGV4aXN0ZW4gZG9zIHRpcG9zIGRlIHByb2NlZGltaWVudG9zIG8gbcOpdG9kb3MgZGUgY2xhc2lmaWNhY2nDs246IA0KDQoxLiBKZXLDoXJxdWljb3MuIA0KDQoyLiBObyBqZXLDoXJxdWljb3MuICANCg0KVsOpYXNlIGxhIEZpZ3VyYSBcQHJlZihmaWc6Z3J1cG8xKS4gIEEgY29udGludWFjacOzbiwgZXhwbGljYXJlbW9zIGNhZGEgdW5vIGRlIGVsbG9zLg0KDQoNCg0KDQo8Y2VudGVyPg0KDQpgYGB7ciBncnVwbzEsIGVjaG89RkFMU0UsIGZpZy5jYXAgPSAiKipQcm9jZWRpbWllbnRvcyBqZXLDoXJxdWljb3MgeSBubyBqZXLDoXJxdWljb3MqKiIsIG91dC53aWR0aCA9ICIxMDAlIn0NCiMgZmlnLndpZHRoID0gMjAgIyBObyBmdW5jaW9uYSBlc3RhIG9wY2lvbiBlbiBlbCBjaHVuaw0KDQojaHR0cDovL3pldnJvc3MuY29tL2Jsb2cvMjAxNy8wNi8xOS90aXBzLWFuZC10cmlja3MtZm9yLXdvcmtpbmctd2l0aC1pbWFnZXMtYW5kLWZpZ3VyZXMtaW4tci1tYXJrZG93bi1kb2N1bWVudHMvDQojIFBhZ2luYSAzNTkgZGUgUjIwMTUtRnJpZW5kbHkNCg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImdydXBvMS5wbmciKQ0KDQojT3RyYSBtYW5lcmEsIHBlcm8gIHNhbGUgZWwgY2FwdGlvbjoNCiM8Y2VudGVyPg0KIyFbKCNmaWc6RmlnLWNhcHRpb24pIE1pIGZpZ3VyYV0oTm9tYnJlLnBuZyl7d2lkdGg9NDAwcHh9DQojPC9jZW50ZXI+DQpgYGANCjwvY2VudGVyPg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIFByb2NlZGltaWVudG9zIGplcsOhcnF1aWNvcw0KDQojIyMgSmVyw6FycXVpY286IGRlc2NyaXBjacOzbiANCg0KRXhwbGljYXJlbW9zIGNpZXJ0YXMgZGlyZWN0cmljZXMgcGFyYSBkZWZpbmlyIGPDs21vIHNlIGFncnVwYW4gbG9zIGVsZW1lbnRvcy4gRW4gZXN0ZSBzZW50aWRvLCBjdWFuZG8gc2UgdGVuZ2EgdW5hIHBvYmxhY2nDs24gZ3JhbmRlLCBlbCBvYmpldGl2byBlcyBvcmdhbml6YXJsYSBlbiB1bmEgamVyYXJxdcOtYSBkZSBwYXJ0ZXMsIGRpdmlkacOpbmRvbGEgZW4gdmFyaW9zIHN1YmNvbmp1bnRvcyBkZSBtYW5lcmEgcXVlOg0KICANCjEuIE5vIGNvbXBhcnRhbiBlbGVtZW50b3MgZW50cmUgc8OtLg0KICANCjIuIENhZGEgc3ViY29uanVudG8gZXN0w6kgY29udGVuaWRvIGRlbnRybyBkZWwgb3Ryby4gDQogIA0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyAgSmVyw6FycXVpY286IG9ic2VydmFjaW9uDQoNCg0KRWwgbsO6bWVybyBkZSBzdWJncnVwb3MgZ2VuZXJhZG9zIGRlcGVuZGUgZGVsIG9yZGVuIGVuIGVsIHF1ZSBzZSBhYm9yZGUgZWwgcHJvY2Vzby4gDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBKZXLDoXJxdWljbzogZ3LDoWZpY29zDQoNCkVuIGxvcyBlbmZvcXVlcyBqZXLDoXJxdWljb3MsIHNlIGVtcGxlYW4gZ3LDoWZpY29zIHBhcmEgc2ltcGxpZmljYXIgbGEgY29tcHJlbnNpw7NuIGRlIGxvcyBjb25qdW50b3MgZGUgZGF0b3MuIEVudHJlIGVsbG9zLCBsb3MgbcOhcyBjb211bmVzIGRlc3RhY2FuIGxvcyAqZGVuZG9ncmFtYXMqIChmaWd1cmEgXEByZWYoZmlnOkRlbmRvMSkpIHkgbG9zICptYXBhcyBkZSBjYWxvciogKCpoZWF0bWFwKiwgZmlndXJhIFxAcmVmKGZpZzpIZWF0bWFwMSkpLiANCg0KPGNlbnRlcj4NCg0KYGBge3IgRGVuZG8xLCBlY2hvPUZBTFNFLCBmaWcuY2FwID0gIioqRGVuZG9ncmFtYSoqIiwgb3V0LndpZHRoID0gIjYwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJEZW5kbzEucG5nIikNCg0KI090cmEgbWFuZXJhLCBwZXJvICBzYWxlIGVsIGNhcHRpb246DQojPGNlbnRlcj4NCiMhWygjZmlnOkZpZy1jYXB0aW9uKSBNaSBmaWd1cmFdKE5vbWJyZS5wbmcpe3dpZHRoPTQwMHB4fQ0KIzwvY2VudGVyPg0KYGBgDQo8L2NlbnRlcj4NCg0KDQo8Y2VudGVyPg0KDQpgYGB7ciBIZWF0bWFwMSwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKkhlYXRtYXAgKG1hcGEgZGUgY2Fsb3IpKioiLCBvdXQud2lkdGggPSAiNjAlIn0NCiMgZmlnLndpZHRoID0gMjAgIyBObyBmdW5jaW9uYSBlc3RhIG9wY2lvbiBlbiBlbCBjaHVuaw0KDQojaHR0cDovL3pldnJvc3MuY29tL2Jsb2cvMjAxNy8wNi8xOS90aXBzLWFuZC10cmlja3MtZm9yLXdvcmtpbmctd2l0aC1pbWFnZXMtYW5kLWZpZ3VyZXMtaW4tci1tYXJrZG93bi1kb2N1bWVudHMvDQojIFBhZ2luYSAzNTkgZGUgUjIwMTUtRnJpZW5kbHkNCg0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkhlYXRtYXAxLnBuZyIpDQoNCiNPdHJhIG1hbmVyYSwgcGVybyAgc2FsZSBlbCBjYXB0aW9uOg0KIzxjZW50ZXI+DQojIVsoI2ZpZzpGaWctY2FwdGlvbikgTWkgZmlndXJhXShOb21icmUucG5nKXt3aWR0aD00MDBweH0NCiM8L2NlbnRlcj4NCmBgYA0KPC9jZW50ZXI+DQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjICBKZXLDoXJxdWljbzogdGlwb3MNCg0KRGVudHJvIGRlIGxvcyBtw6l0b2RvcyBqZXLDoXJxdWljb3MsIHNlIHB1ZWRlbiBpZGVudGlmaWNhciBsb3Mgc2lndWllbnRlcyBwcm9jZWRpbWllbnRvczogDQoNCjEuIEFzY2VuZGVudGUgKG8gYWdsb21lcmF0aXZvcykuDQoNCjIuIERlc2NlbmRlbnRlIChvIGRpdmlzaXZvcykuDQoNCg0KVsOpYXNlIGxhIEZpZ3VyYSBcQHJlZihmaWc6Z3J1cG8yKS4gIEEgY29udGludWFjacOzbiwgZXhwbGljYXJlbW9zIGNhZGEgdW5vIGRlIGVsbG9zLg0KDQoNCjxjZW50ZXI+DQoNCmBgYHtyIGdydXBvMiwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKlByb2NlZGltaWVudG9zIGplcsOhcnF1aWNvcyBhc2NlbmRlbnRlcyB5IG5vIGFzY2VuZGVudGVzKioiLCBvdXQud2lkdGggPSAiMTAwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJncnVwbzIucG5nIikNCg0KI090cmEgbWFuZXJhLCBwZXJvICBzYWxlIGVsIGNhcHRpb246DQojPGNlbnRlcj4NCiMhWygjZmlnOkZpZy1jYXB0aW9uKSBNaSBmaWd1cmFdKE5vbWJyZS5wbmcpe3dpZHRoPTQwMHB4fQ0KIzwvY2VudGVyPg0KYGBgDQo8L2NlbnRlcj4NCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIFByb2NlZGltaWVudG8gamVyw6FycXVpY28gYXNjZW5kZW50ZSAoYWdsb21lcmF0aXZvKQ0KDQojIyMgSmVyw6FycXVpY28gYXNjZW5kZW50ZTogZGVzY3JpcGNpw7NuDQoNCjEuIEluaWNpYSBjb24gdW4gbsO6bWVybyBkZSBncnVwb3MgaWd1YWwgYWwgZGUgaW5kaXZpZHVvcyBkaXNwb25pYmxlcyAodSBvYmpldG9zIHF1ZSB0ZW5nYW1vcyBxdWUgY2xhc2lmaWNhcikuDQoNCjIuIEVuIGNhZGEgcGFzbyBzZSByZWNhbGN1bGFuIGxhcyBkaXN0YW5jaWFzIGVudHJlIGxvcyBncnVwb3MgZXhpc3RlbnRlcw0KDQoyLiBFc3RvcyBncnVwb3Mgc2UgdmFuIGZ1c2lvbmFuZG8gZW50cmUgc8OtLCBhZ3J1cGFuZG8gYSBsb3MgaW5kaXZpZHVvcyBtw6FzIHNpbWlsYXJlcyBiYXPDoW5kb3NlIGVuIHVuIGNyaXRlcmlvIGVzcGVjw61maWNvLiANCg0KMy4gRmluYWxtZW50ZSwgY3VsbWluYSBjb24gdW4gw7puaWNvIGdydXBvIHF1ZSBpbmNsdXllIGEgdG9kb3MgbG9zIGVsZW1lbnRvcyBkZSBsYSBwb2JsYWNpw7NuLiANCg0KNC4gVW5hIHZleiBxdWUgc2UgaGEgZm9ybWFkbyB1biBncnVwbywgbm8gc2UgZGVzaW50ZWdyYSwgaW5jbHVzbyBzaSBhbGfDum4gaW5kaXZpZHVvIHRpZW5lIG3DoXMgYWZpbmlkYWQgY29uIGxvcyBlbGVtZW50b3MgZGUgdW4gZ3J1cG8gcmVjacOpbiBmb3JtYWRvLg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyAgSmVyw6FycXVpY28gYXNjZW5kZW50ZTogdGlwb3MNCg0KRW4gbG9zIG3DqXRvZG9zIGplcsOhcnF1aWNvcyBhc2NlbmRlbnRlcywgaGF5IHZhcmlhcyBmb3JtYXMgZGUgZGVmaW5pciBjw7NtbyBzZSBhZ3J1cGFuIGxvcyBlbGVtZW50b3MuIERlbnRybyBkZSBsb3MgbcOpdG9kb3MgamVyw6FycXVpY29zIGFzY2VuZGVudGVzIG3DoXMgY29tdW5lcywgc29icmVzYWxlbiB0cmVzIGVuIHBhcnRpY3VsYXI6DQoNCjEuIExvcyBkZW5vbWluYWRvcyBkZSB1bmnDs24uDQoNCjIuIExvcyBiYXNhZG9zIGVuIGVsIGNlbnRyb2lkZS4NCg0KMy4gTG9zIHF1ZSBsbyBoYWNlbiBjb24gYmFzZSBlbiBsYSB2YXJpYW56YS4NCiANCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgUHJvY2VkaW1pZW50byBqZXLDoXJxdWljbyBkZXNjZW5kZW50ZQ0KDQoxLiBFbCBwcm9jZXNvIGltcGxpY2EgbG8gb3B1ZXN0byBhbCBhbnRlcmlvci4NCg0KMi4gQ29taWVuemEgY29uIGVsIGNvbmp1bnRvIGNvbXBsZXRvLCBlcyBkZWNpciwgbGEgcG9ibGFjacOzbiwgeSBsdWVnbyBzZSBkaXZpZGUgZW4gc3ViY29uanVudG9zIHN1Y2VzaXZvcyBoYXN0YSBxdWUgc2UgYWxjYW56YSB1biBncnVwbyBxdWUgY29udGllbmUgdW4gw7puaWNvIGVsZW1lbnRvLg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgUHJvY2VkaW1pZW50b3MgamVyw6FycXVpY29zOiBtw6l0b2Rvcw0KDQoNCg0KIyMjIFRpcG9zICBkZSBtw6l0b2Rvcw0KDQpMb3MgbcOpdG9kb3MgZGUgY2xhc2lmaWNhY2nDs24gIG3DoXMgY29tdW5lcyBzb246IA0KDQoNCjEuIFZlY2lubyBtw6FzIGNlcmNhbm8uIA0KDQoyLiBWZWNpbm8gbcOhcyBsZWphbm8uDQoNCjMuIFbDrW5jdWxvIG1lZGlvLg0KDQo0LiBDZW50cm9pZGUuIA0KDQoNClbDqWFzZSBsYSBGaWd1cmEgXEByZWYoZmlnOmdydXBvMykuICBBIGNvbnRpbnVhY2nDs24sIGV4cGxpY2FyZW1vcyBjYWRhIHVubyBkZSBlbGxvcy4NCg0KDQo8Y2VudGVyPg0KDQpgYGB7ciBncnVwbzMsIGVjaG89RkFMU0UsIGZpZy5jYXAgPSAiKipEaXN0YW5jaWFzIGVuIHByb2NlZGltaWVudG9zIGplcsOhcnF1aWNvcyoqIiwgb3V0LndpZHRoID0gIjEwMCUifQ0KIyBmaWcud2lkdGggPSAyMCAjIE5vIGZ1bmNpb25hIGVzdGEgb3BjaW9uIGVuIGVsIGNodW5rDQoNCiNodHRwOi8vemV2cm9zcy5jb20vYmxvZy8yMDE3LzA2LzE5L3RpcHMtYW5kLXRyaWNrcy1mb3Itd29ya2luZy13aXRoLWltYWdlcy1hbmQtZmlndXJlcy1pbi1yLW1hcmtkb3duLWRvY3VtZW50cy8NCiMgUGFnaW5hIDM1OSBkZSBSMjAxNS1GcmllbmRseQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZ3J1cG8zLnBuZyIpDQoNCiNPdHJhIG1hbmVyYSwgcGVybyAgc2FsZSBlbCBjYXB0aW9uOg0KIzxjZW50ZXI+DQojIVsoI2ZpZzpGaWctY2FwdGlvbikgTWkgZmlndXJhXShOb21icmUucG5nKXt3aWR0aD00MDBweH0NCiM8L2NlbnRlcj4NCmBgYA0KPC9jZW50ZXI+DQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRWwgdmVjaW5vIG3DoXMgY2VyY2Fubw0KDQoxLiBFbiBlc3RlIHByb2Nlc28sIGxhIG1lZGlkYSBkZSBkaXN0YW5jaWEgZW50cmUgZG9zIGNvbmp1bnRvcyBzZSBkZXRlcm1pbmEgcG9yIGxhIGRpc3RhbmNpYSBlbnRyZSBsb3MgZWxlbWVudG9zIG3DoXMgcHLDs3hpbW9zIHF1ZSBwZXJ0ZW5lY2VuIGEgZ3J1cG9zIGRpZmVyZW50ZXMuIA0KDQoyLiBMb3MgZG9zIHByaW1lcm9zIGVsZW1lbnRvcyBhIGFncnVwYXIgc29uIGFxdWVsbG9zIGNvbiBsYSBkaXN0YW5jaWEgbcOhcyBwZXF1ZcOxYSBlbnRyZSBlbGxvcy4gDQoNCjMuIEx1ZWdvLCBzZSBlbmN1ZW50cmEgbGEgc2lndWllbnRlIGRpc3RhbmNpYSBtw61uaW1hIHkgc2UgYWdyZWdhIHVuIHRlcmNlciBlbGVtZW50byBhbCBncnVwbywgbyBiaWVuIHNlIGZvcm1hIG90cm8gZ3J1cG8gY29uIGRvcyBlbGVtZW50b3MuIA0KDQo0LiBFc3RlIHByb2Nlc28gY29udGluw7phIGhhc3RhIHF1ZSB0b2RvcyBsb3MgZWxlbWVudG9zIGVzdMOpbiBjbGFzaWZpY2Fkb3MgZW4gdW4gc29sbyBncnVwby4NCg0KNS4gR2VuZXJhbG1lbmUsIHNlIHV0aWxpemEgbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEuIA0KDQo2LiBWw6lhc2UgbGEgc2l0dWFjacOzbiBncsOhZmljYSBxdWUgYXBhcmVjZSBlbiBsYSBGaWd1cmEgXEByZWYoZmlnOmtubjApLg0KDQo8Y2VudGVyPg0KDQpgYGB7ciBrbm4wLCBlY2hvPUZBTFNFLCBmaWcuY2FwID0gIioqVmVjaW5vIG3DoXMgY2VyY2FubyoqIiwgb3V0LndpZHRoID0gIjQwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHBzOi8vd3d3LmZ1ZW50ZXJyZWJvbGxvLmNvbS9FY29ub21pY2FzL0VDT05PTUVUUklBL1NFR01FTlRBQ0lPTi9DT05HTE9NRVJBRE9TL2Nvbmdsb21lcmFkb3MucGRmDQoNCiNodHRwOi8vemV2cm9zcy5jb20vYmxvZy8yMDE3LzA2LzE5L3RpcHMtYW5kLXRyaWNrcy1mb3Itd29ya2luZy13aXRoLWltYWdlcy1hbmQtZmlndXJlcy1pbi1yLW1hcmtkb3duLWRvY3VtZW50cy8NCiMgUGFnaW5hIDM1OSBkZSBSMjAxNS1GcmllbmRseQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygia25uMC5wbmciKQ0KDQojT3RyYSBtYW5lcmEsIHBlcm8gIHNhbGUgZWwgY2FwdGlvbjoNCiM8Y2VudGVyPg0KIyFbKCNmaWc6RmlnLWNhcHRpb24pIE1pIGZpZ3VyYV0oTm9tYnJlLnBuZyl7d2lkdGg9NDAwcHh9DQojPC9jZW50ZXI+DQpgYGANCjwvY2VudGVyPg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRWwgdmVjaW5vIG3DoXMgY2VyY2FubzogZWplbXBsbw0KDQoNCjEuIENvbnNpZGVyZSBsYSBGaWd1cmEgXEByZWYoZmlnOmtubjEpLiAgDQoNCjIuIEVsIG9iamV0aXZvIGVzIGlkZW50aWZpY2FyIGVsIGluZGl2aWR1byAodSBvYmpldG8pIHJlcHJlc2VudGFkbyBwb3IgZWwgY8OtcmN1bG8gdmVyZGUuIA0KDQozLiBTaSBjb25zaWRlcmFtb3MgJGsgPSAzJCwgc2UgY2xhc2lmaWNhIGNvbW8gdW4gdHJpw6FuZ3VsbywgZGViaWRvIGEgcXVlIGRlbnRybyBkZWwgY8OtcmN1bG8gcXVlIGxvIGNvbnRpZW5lIGhheSB1biBjdWFkcmFkbyB5IGRvcyB0cmnDoW5ndWxvcy4gDQoNCjQuIFBvciBvdHJvIGxhZG8sIHNpICRrID0gNSQsIHNlIGNsYXNpZmljYSBjb21vIHVuIGN1YWRyYWRvLCBkYWRvIHF1ZSBkZW50cm8gZGVsIGPDrXJjdWxvIGV4dGVyaW9yIGhheSBkb3MgdHJpw6FuZ3Vsb3MgeSB0cmVzIGN1YWRyYWRvcy4NCg0KPGNlbnRlcj4NCg0KYGBge3Iga25uMSwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKkVqZW1wbG8gcGFyYSBlbCB2ZWNpbm8gbcOhcyBjZXJjYW5vKioiLCBvdXQud2lkdGggPSAiNDAlIn0NCiMgZmlnLndpZHRoID0gMjAgIyBObyBmdW5jaW9uYSBlc3RhIG9wY2lvbiBlbiBlbCBjaHVuaw0KDQojaHR0cHM6Ly93d3cuZnVlbnRlcnJlYm9sbG8uY29tL0Vjb25vbWljYXMvRUNPTk9NRVRSSUEvU0VHTUVOVEFDSU9OL0NPTkdMT01FUkFET1MvY29uZ2xvbWVyYWRvcy5wZGYNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJrbm4xLnBuZyIpDQoNCiNPdHJhIG1hbmVyYSwgcGVybyAgc2FsZSBlbCBjYXB0aW9uOg0KIzxjZW50ZXI+DQojIVsoI2ZpZzpGaWctY2FwdGlvbikgTWkgZmlndXJhXShOb21icmUucG5nKXt3aWR0aD00MDBweH0NCiM8L2NlbnRlcj4NCmBgYA0KPC9jZW50ZXI+DQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIEVsIHZlY2lubyBtw6FzIGxlamFubw0KDQoxLiBFc3RhIG51ZXZhIHByb3B1ZXN0YSBlcyB1bmEgdmFyaWFudGUgZGVsIGVuZm9xdWUgYW50ZXJpb3IuDQoNCjIuIEFob3JhIGxhIG1lZGlkYSBkZSBkaXN0YW5jaWEgZW50cmUgZ3J1cG9zIHNlIGRlZmluZSBjb21vIGxhIGRpc3RhbmNpYSBlbnRyZSBsb3MgZG9zIGVsZW1lbnRvcyBtw6FzIGFsZWphZG9zLCBjYWRhIHVubyBwZXJ0ZW5lY2llbnRlIGEgdW4gZ3J1cG8gZGlmZXJlbnRlLg0KDQozLiBWw6lhc2UgbGEgc2l0dWFjacOzbiBncsOhZmljYSBxdWUgYXBhcmVjZSBlbiBsYSBGaWd1cmEgXEByZWYoZmlnOmtubjIpLg0KDQo8Y2VudGVyPg0KDQpgYGB7ciBrbm4yLCBlY2hvPUZBTFNFLCBmaWcuY2FwID0gIioqVmVjaW5vIG3DoXMgbGVqYW5vKioiLCBvdXQud2lkdGggPSAiNDAlIn0NCiMgZmlnLndpZHRoID0gMjAgIyBObyBmdW5jaW9uYSBlc3RhIG9wY2lvbiBlbiBlbCBjaHVuaw0KDQojaHR0cHM6Ly93d3cuZnVlbnRlcnJlYm9sbG8uY29tL0Vjb25vbWljYXMvRUNPTk9NRVRSSUEvU0VHTUVOVEFDSU9OL0NPTkdMT01FUkFET1MvY29uZ2xvbWVyYWRvcy5wZGYNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJrbm4yLnBuZyIpDQoNCiNPdHJhIG1hbmVyYSwgcGVybyAgc2FsZSBlbCBjYXB0aW9uOg0KIzxjZW50ZXI+DQojIVsoI2ZpZzpGaWctY2FwdGlvbikgTWkgZmlndXJhXShOb21icmUucG5nKXt3aWR0aD00MDBweH0NCiM8L2NlbnRlcj4NCmBgYA0KPC9jZW50ZXI+DQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBWaW5jdWxvIG1lZGlvDQoNCjEuIEVuIGVzdGUgY29udGV4dG8sIGVsIGPDoWxjdWxvIGRlIGxhIGRpc3RhbmNpYSBlbnRyZSBncnVwb3Mgbm8gc2UgbGltaXRhIGEgc29sbyBkb3MgZWxlbWVudG9zLiANCg0KMi4gU2UgZW1wbGVhIGxhIG1lZGlhIHBhcmEgZGV0ZXJtaW5hciBkaWNoYSBkaXN0YW5jaWEsIHBlcm8gZXN0ZSBlbmZvcXVlIHRpZW5lIHZhcmlhcyBtb2RhbGlkYWRlcy4gDQoNCjMuIExhIG1lZGlhIHB1ZWRlIHNlcjogDQogICAgDQogICAgYS4gTGEgZGlzdGFuY2lhIHByb21lZGlvIGVudHJlIHBhcmVzIGRlIG9iamV0b3MgZGUgbG9zIGRvcyBncnVwb3MsIHlhIHNlYSBzaW4gcG9uZGVyYWNpw7NuIG8gcG9uZGVyYWRhIHNlZ8O6biBlbCB0YW1hw7FvIGRlIGxvcyBncnVwb3MgIG8gDQogICAgDQogICAgYi4gRWwgbsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSB1bm8sIGVzcGVjaWFsbWVudGUgY3VhbmRvIHNlIHRyYXRhIGRlIGdydXBvcyBkZSB0YW1hw7FvcyBtdXkgZGlzcGFyZXMuIA0KDQo0LiBMb3MgZ3J1cG9zIHJlc3VsdGFudGVzIG11ZXN0cmFuIHVuYSB2YXJpYW56YSBzaW1pbGFyIHkgZ2VuZXJhbG1lbnRlIHBlcXVlw7FhLg0KDQoNCjUuIFbDqWFzZSBsYSBzaXR1YWNpw7NuIGdyw6FmaWNhIHF1ZSBhcGFyZWNlIGVuIGxhIEZpZ3VyYSBcQHJlZihmaWc6a25uMykuDQoNCjxjZW50ZXI+DQoNCmBgYHtyIGtubjMsIGVjaG89RkFMU0UsIGZpZy5jYXAgPSAiKipWw61uY3VsbyBtZWRpbyoqIiwgb3V0LndpZHRoID0gIjQwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHBzOi8vd3d3LmZ1ZW50ZXJyZWJvbGxvLmNvbS9FY29ub21pY2FzL0VDT05PTUVUUklBL1NFR01FTlRBQ0lPTi9DT05HTE9NRVJBRE9TL2Nvbmdsb21lcmFkb3MucGRmDQoNCiNodHRwOi8vemV2cm9zcy5jb20vYmxvZy8yMDE3LzA2LzE5L3RpcHMtYW5kLXRyaWNrcy1mb3Itd29ya2luZy13aXRoLWltYWdlcy1hbmQtZmlndXJlcy1pbi1yLW1hcmtkb3duLWRvY3VtZW50cy8NCiMgUGFnaW5hIDM1OSBkZSBSMjAxNS1GcmllbmRseQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygia25uMy5wbmciKQ0KDQojT3RyYSBtYW5lcmEsIHBlcm8gIHNhbGUgZWwgY2FwdGlvbjoNCiM8Y2VudGVyPg0KIyFbKCNmaWc6RmlnLWNhcHRpb24pIE1pIGZpZ3VyYV0oTm9tYnJlLnBuZyl7d2lkdGg9NDAwcHh9DQojPC9jZW50ZXI+DQpgYGANCjwvY2VudGVyPg0KDQogPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyAgTcOpdG9kbyBkZWwgY2VudHJvaWRlDQogICANCjEuIEVsIHB1bnRvIGNlbnRyYWwgZGUgdW4gY29uanVudG8sIHRhbWJpw6luIGNvbm9jaWRvIGNvbW8gY2VudHJvaWRlLCBzZSBlbmN1ZW50cmEgZW4gZWwgcHVudG8gbWVkaW8gZGUgdW4gZXNwYWNpbyBkZSAkSyQgZGltZW5zaW9uZXMgZGVmaW5pZG8gcG9yIGxhcyAkayQgdmFyaWFibGVzIGFuYWxpemFkYXMuIA0KDQoyLiBDb25mb3JtZSBzZSBhZ3JlZ2FuIGVsZW1lbnRvcyBhbCBjb25qdW50bywgdGFudG8gZWwgbsO6bWVybyBkZSBlbGVtZW50b3MgY29tbyBzdSBjZW50cm9pZGUgcHVlZGVuIGNhbWJpYXIuIA0KDQozLiBMb3MgZW5mb3F1ZXMgcXVlIHNlIGJhc2FuIGVuIGVsIGNlbnRyb2lkZSBjYWxjdWxhbiBsYSBkaXN0YW5jaWEgZW50cmUgY29uanVudG9zIHRvbWFuZG8gbGEgZGlzdGFuY2lhIGVudHJlIHN1cyByZXNwZWN0aXZvcyBjZW50cm9pZGVzLiANCg0KNC4gQWwgY2VudHJhcnNlIGVuIGxvcyBwdW50b3MgbWVkaW9zLCBsb3MgdmFsb3JlcyBhdMOtcGljb3Mgbm8gYWZlY3RhbiBzaWduaWZpY2F0aXZhbWVudGUgZXN0ZSBtw6l0b2RvLiANCg0KNS4gRXN0ZSBlbmZvcXVlIHRpZW5lIHZhcmlhY2lvbmVzIHF1ZSBwdWVkZW4gdGVuZXIgZW4gY3VlbnRhIG8gbm8gZWwgdGFtYcOxbyBkZSBsb3MgY29uanVudG9zIChwYXJ0aWN1bGFybWVudGUgY3VhbmRvIGxvcyBjb25qdW50b3Mgc29uIG5vdGFibGVtZW50ZSBkaWZlcmVudGVzKS4NCg0KNi4gVsOpYXNlIGxhIHNpdHVhY2nDs24gZ3LDoWZpY2EgcXVlIGFwYXJlY2UgZW4gbGEgRmlndXJhIFxAcmVmKGZpZzprbm40KS4NCg0KPGNlbnRlcj4NCg0KYGBge3Iga25uNCwgZWNobz1GQUxTRSwgZmlnLmNhcCA9ICIqKk3DqXRvZG8gZGVsIGNlbnRyb2lkZSoqIiwgb3V0LndpZHRoID0gIjQwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHBzOi8vd3d3LmZ1ZW50ZXJyZWJvbGxvLmNvbS9FY29ub21pY2FzL0VDT05PTUVUUklBL1NFR01FTlRBQ0lPTi9DT05HTE9NRVJBRE9TL2Nvbmdsb21lcmFkb3MucGRmDQoNCiNodHRwOi8vemV2cm9zcy5jb20vYmxvZy8yMDE3LzA2LzE5L3RpcHMtYW5kLXRyaWNrcy1mb3Itd29ya2luZy13aXRoLWltYWdlcy1hbmQtZmlndXJlcy1pbi1yLW1hcmtkb3duLWRvY3VtZW50cy8NCiMgUGFnaW5hIDM1OSBkZSBSMjAxNS1GcmllbmRseQ0KDQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygia25uNC5wbmciKQ0KDQojT3RyYSBtYW5lcmEsIHBlcm8gIHNhbGUgZWwgY2FwdGlvbjoNCiM8Y2VudGVyPg0KIyFbKCNmaWc6RmlnLWNhcHRpb24pIE1pIGZpZ3VyYV0oTm9tYnJlLnBuZyl7d2lkdGg9NDAwcHh9DQojPC9jZW50ZXI+DQpgYGANCjwvY2VudGVyPg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBQcm9jZWRpbWllbnRvcyBubyBqZXLDoXJxdWljb3MNCg0KIyMjIE5vIGplcsOhcnF1aWNvczogZGVzY3JpcGNpw7NuDQoNCjEuIENvbWllbnphbiBjb24gdW4gY2zDunN0ZXIgcXVlIGVuZ2xvYmEgYSB0b2RvcyBsb3MgZWxlbWVudG9zIHkgZW4gY2FkYSBwYXNvIHNlIGRpdmlkZSBlbCBncnVwbyBtw6FzIGhldGVyb2fDqW5lby4gDQoNCjIuIEVsIGFsZ29yaXRtbyBhY2FiYSBjb24gdGFudG9zIGNsdXN0ZXJzIChkZSB1biBlbGVtZW50byBjYWRhIHVubykgY29tbyBvYmpldG9zIHNlIGhheWFuIGNsYXNpZmljYWRvLg0KDQozLiBBIHBhcnRpciBkZSB1biBjb25qdW50byBkZSAkbiQgaW5kaXZpZHVvcywgc2UgcmVxdWllcmUgY3JlYXIgJGskIGdydXBvcywgZG9uZGUgJGs8biQuIA0KDQo0LiBMYSBlbGVjY2nDs24gZGUgJGskIGVzIGRldGVybWluYWRhIHBvciBlbCBhbmFsaXN0YSBiYXPDoW5kb3NlIGVuIGV4cGVyaWVuY2lhIHByZXZpYSBvIGFsZ8O6biBjb25vY2ltaWVudG8gZXNwZWPDrWZpY28gZGVsIHRlbWEgZW4gZXN0dWRpby4gDQoNCjUuIEVuIGVzdGUgbcOpdG9kbywgbG9zIGdydXBvcyBzZSBkZWZpbmVuIGRlIGFudGVtYW5vLiANCg0KNi4gTG9zIGVuZm9xdWVzIG5vIGplcsOhcnF1aWNvcyBidXNjYW4gYWxjYW56YXIgdW4gw7NwdGltbyBnbG9iYWwgZW4gbHVnYXIgZGUgc3Viw7NwdGltb3Mgc3VjZXNpdm9zIGVuIGNhZGEgZXRhcGEgZGUgYWdydXBhY2nDs24uIA0KDQo3LiBFc3RvIHBlcm1pdGUgbGEgcmVhc2lnbmFjacOzbiBkZSB1biBlbGVtZW50byBhIHVuIGdydXBvIGRpZmVyZW50ZSBlbiBldGFwYXMgcG9zdGVyaW9yZXMsIGVuIGNvbXBhcmFjacOzbiBjb24gZWwgZ3J1cG8gYWwgcXVlIGluaWNpYWxtZW50ZSBmdWUgYXNpZ25hZG8uIA0KDQo4LiBFc3RvcyBlbmZvcXVlcyBubyBqZXLDoXJxdWljb3MgdGFtYmnDqW4gc29uIGNvbm9jaWRvcyBjb21vIGRlICRrJC1tZWRpYXMsIA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgTm8gamVyw6FycXVpY29zOiB0aXBvcw0KDQoNClNlIGRpc3Rpbmd1ZW4gcG9yIHRyZXMgdGlwb3MgZGlmZXJlbnRlczoNCg0KMS4gVW1icmFsIHNlY3VlbmNpYWwuDQoNCjIuIFVtYnJhbCBwYXJhbGVsby4gDQoNCjMuIE3DqXRvZG9zIGRlIG9wdGltaXphY2nDs24uIA0KDQoNCg0KDQpWw6lhc2UgbGEgRmlndXJhIFxAcmVmKGZpZzpncnVwbzQpLiBBIGNvbnRpbnVhY2nDs24sIGV4cGxpY2FyZW1vcyBjYWRhIHVubyBkZSBlbGxvcy4NCg0KPGNlbnRlcj4NCg0KYGBge3IgZ3J1cG80LCBlY2hvPUZBTFNFLCBmaWcuY2FwID0gIioqTcOpdG9kbyBkZWwgY2VudHJvaWRlKioiLCBvdXQud2lkdGggPSAiMTAwJSJ9DQojIGZpZy53aWR0aCA9IDIwICMgTm8gZnVuY2lvbmEgZXN0YSBvcGNpb24gZW4gZWwgY2h1bmsNCg0KI2h0dHA6Ly96ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLw0KIyBQYWdpbmEgMzU5IGRlIFIyMDE1LUZyaWVuZGx5DQoNCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJncnVwbzQucG5nIikNCg0KI090cmEgbWFuZXJhLCBwZXJvICBzYWxlIGVsIGNhcHRpb246DQojPGNlbnRlcj4NCiMhWygjZmlnOkZpZy1jYXB0aW9uKSBNaSBmaWd1cmFdKE5vbWJyZS5wbmcpe3dpZHRoPTQwMHB4fQ0KIzwvY2VudGVyPg0KYGBgDQo8L2NlbnRlcj4NCiAgICANCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgTm8gamVyw6FycXVpY29zOiB1bWJyYWwgc2VjdWVuY2lhbA0KDQoxLiBVbmEgdmV6IHF1ZSBzZSBoYSBzZWxlY2Npb25hZG8gdW4gY2VudHJvIHBhcmEgdW4gZ3J1cG8sIHRvZG9zIGxvcyBlbGVtZW50b3MgZGUgdW5hIHBvYmxhY2nDs24gcXVlIHNlIGVuY3VlbnRyZW4gZGVudHJvIGRlIHVuIGNpZXJ0byB2YWxvciBvIHVtYnJhbCBzb24gYXNpZ25hZG9zIGEgZGljaG8gZ3J1cG8uIA0KDQoyLiBFc3RlIHByb2Nlc28gc2UgcmVwaXRlIHNlbGVjY2lvbmFuZG8gbnVldm9zIGNlbnRyb3MgeSBmb3JtYW5kbyBudWV2b3MgZ3J1cG9zLiBFcyBpbXBvcnRhbnRlIGRlc3RhY2FyIHF1ZSB1bmEgdmV6IHF1ZSB1biBlbGVtZW50byBoYSBzaWRvIGFzaWduYWRvIGEgdW4gZ3J1cG8sIG5vIHNlIGNvbnNpZGVyYSBwYXJhIGxhIGFzaWduYWNpw7NuIGEgb3RybyBncnVwby4NCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBObyBqZXLDoXJxdWljb3M6IHVtYnJhbCBQYXJhbGVsbw0KDQoxLiBFc3RhIG9wY2nDs24gZXN0YWJsZWNlIHZhcmlvcyBjZW50cm9zIGRlIGdydXBvcyBkZXNkZSBlbCBpbmljaW8uIExvcyBvYmpldG9zIHNlIGFzaWduYW4gYSB1biBjZW50cm8gZGVudHJvIGRlbCB1bWJyYWwgZGVmaW5pZG8sIGVsaWdpZW5kbyBlbCBjZW50cm8gbcOhcyBjZXJjYW5vLiANCg0KMi4gTGFzIGRpc3RhbmNpYXMgcHVlZGVuIGFqdXN0YXJzZSBhIG1lZGlkYSBxdWUgYXZhbnphIGVsIHByb2Nlc28sIG8gaW5jbHVzbyBwdWVkZW4gZGVqYXJzZSBmdWVyYSBhcXVlbGxvcyBlbGVtZW50b3MgcXVlIG5vIGNhaWdhbiBkZW50cm8gZGVsIHVtYnJhbCBlc3RhYmxlY2lkbyBwYXJhIG5pbmfDum4gY2VudHJvLg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIE5vIGplcsOhcnF1aWNvczogbcOpdG9kb3MgZGUgb3B0aW1pemFjacOzbg0KDQoxLiBMYSBkaXN0aW5jacOzbiByYWRpY2EgZW4gc3UgY2FwYWNpZGFkIHBhcmEgbGEgcmVhc2lnbmFjacOzbiBkZSBvYmpldG9zLg0KDQoyLiBMbyBhbnRlcmlvciBpbXBsaWNhIHF1ZSB1biBvYmpldG8gYXNpZ25hZG8gYSB1biBncnVwbyBwdWVkZSBzZXIgdHJhbnNmZXJpZG8gYSBvdHJvIGdydXBvLg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIEplcsOhcnF1aWNvIHZzIG5vIGplcsOhcnF1aWNvDQoNCjEuIEVzIGFjb25zZWphYmxlIGVtcGxlYXIgdW5hIHZhcmllZGFkIGRlIG3DqXRvZG9zLCB0YW50byBqZXLDoXJxdWljb3MgY29tbyBubyBqZXLDoXJxdWljb3MsIGNvbiBlbCBmaW4gZGUgYXVtZW50YXIgbGEgY29uZmlhYmlsaWRhZCBkZSBsYXMgY29uY2x1c2lvbmVzIGFsY2FuemFkYXMuDQoNCjIuIERhZG8gcXVlIGVsIHByaW5jaXBhbCBkZXNhZsOtbyBkZWwgYWxnb3JpdG1vIGRlICRrJC1tZWRpYXMgcmFkaWNhIGVuIGRldGVybWluYXIgZWwgbsO6bWVybyDDs3B0aW1vIGRlIGdydXBvcywgc2Ugc3VnaWVyZSBlbXBsZWFyIGluaWNpYWxtZW50ZSBhbGfDum4gbcOpdG9kbyBqZXLDoXJxdWljbyBwYXJhIGlkZW50aWZpY2FyIHVuIG7Dum1lcm8gZGUgZ3J1cG9zIHF1ZSByZXN1bHRlIHJhem9uYWJsZSB5IGNvaGVyZW50ZS4gDQoNCjMuIFVuYSB2ZXogZXN0YWJsZWNpZG8gZWwgbsO6bWVybyBkZSBncnVwb3MgeSBzdSBjb21wb3NpY2nDs24sIGxhIGludGVycHJldGFjacOzbiBkZSBjYWRhIHVubyBkZSBlbGxvcyBzZSBsbGV2YSBhIGNhYm8gbWVkaWFudGUgbGEgY29uc2lkZXJhY2nDs24gZGUgbGFzIGNhcmFjdGVyw61zdGljYXMgZGUgbG9zIGVsZW1lbnRvcyBxdWUgbG9zIGNvbmZvcm1hbi4gDQoNCg0KNC4gRXN0byBpbXBsaWNhIGFuYWxpemFyIHNpIGNpZXJ0YXMgY2FyYWN0ZXLDrXN0aWNhcyBlc3TDoW4gbcOhcyBwcm9taW5lbnRlbWVudGUgcmVwcmVzZW50YWRhcyBlbiBhbGd1bm9zIGdydXBvcyBxdWUgZW4gb3Ryb3MsIHV0aWxpemFuZG8gZXN0YWTDrXN0aWNhcyBkZXNjcmlwdGl2YXMgZGUgbGFzIHZhcmlhYmxlcyBvcmlnaW5hbGVzIGFncnVwYWRhcy4gDQoNCjUuIEVzdGUgZW5mb3F1ZSBwZXJtaXRlIG5vbWJyYXIgbyBjbGFzaWZpY2FyIGxvcyBncnVwb3MsIHNpbWlsYXIgYWwgYW7DoWxpc2lzIGZhY3RvcmlhbCBlbiBlbCBjYXNvIGRlIGxhcyB2YXJpYWJsZXMgbGF0ZW50ZXMuDQoNCjYuIExhIGludGVycHJldGFjacOzbiBlbiBlbCBjb250ZXh0byBkZSBtw6l0b2RvcyBubyBqZXLDoXJxdWljb3Mgc2UgZW5yaXF1ZWNlIGHDum4gbcOhcyBhbCByZWN1cnJpciBhIHVuIGFuw6FsaXNpcyBkZSB2YXJpYW56YSBwYXJhIGV4YW1pbmFyIGxhcyBkaWZlcmVuY2lhcyBlbnRyZSBsb3MgZ3J1cG9zLiANCg0KNy4gRXN0ZSBhbsOhbGlzaXMgc2UgY2VudHJhIGVuIGxhIHZhcmlhYmlsaWRhZCBwZXF1ZcOxYSBkZW50cm8gZGUgbG9zIGdydXBvcyB5IGxhIHZhcmlhYmlsaWRhZCBncmFuZGUgZW50cmUgbG9zIGdydXBvcywgbG8gcXVlIHByb3BvcmNpb25hIHVuYSBjb21wcmVuc2nDs24gbcOhcyBwcm9mdW5kYSBkZSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBkaXN0aW50aXZhcyBkZSBjYWRhIGdydXBvLg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgUGFzb3MgKGplcsOhcnF1aWNvIGFzY2VuZGVudGUpDQoNCkVsIHByb2Nlc28gcXVlIHNlIGRlYmUgc2VndWlyIGVuIHVuIEFuw6FsaXNpcyBDbMO6c3RlciBKZXLDoXJxdWljbyBhc2NlbmRlbnRlIHNlIHB1ZWRlIHJlc3VtaXIgY29tbyBzaWd1ZToNCg0KKipQYXNvIDE6KiogKlNlbGVjY2nDs24gZGUgbGFzIHZhcmlhYmxlcyouIFNlIGFjb25zZWphIHF1ZSBsYXMgdmFyaWFibGVzIHRlbmdhbiBjYXJhY3RlcsOtc3RpY2FzIHNpbWlsYXJlcyAoY29udGludWFzLCBjYXRlZ8OzcmljYXMsIGV0Yy4pLg0KDQoqKlBhc28gMjoqKiAqRGV0ZWNjacOzbiBkZSB2YWxvcmVzIGF0w61waWNvcyouIExhIHByZXNlbmNpYSBkZSBlbGVtZW50b3Mgc2lnbmlmaWNhdGl2YW1lbnRlIGRpZmVyZW50ZXMgYWwgcmVzdG8gcHVlZGUgYWZlY3RhciBjb25zaWRlcmFibGVtZW50ZSBsb3MgcmVzdWx0YWRvcyBkZWwgYW7DoWxpc2lzIGRlIGNsw7pzdGVyZXMuDQoNCg0KKipQYXNvIDM6KiogKkVsZWNjacOzbiBkZSB1bmEgbWVkaWRhICBkZSBzaW1pbGl0dWQgZW50cmUgb2JqZXRvcyB5IG9idGVuY2nDs24gZGUgbGEgbWF0cml6IGRlIGRpc3RhbmNpYXMqLiBFc3RhcyBtZWRpZGFzIGF5dWRhbiBhIGVzdGFibGVjZXIgbG9zIGdydXBvcyBpbmljaWFsZXMgZW4gdW4gYW7DoWxpc2lzIGRlIGNsdXN0ZXJpbmcuDQoNCioqUGFzbyA0OioqIElkZW50aWZpY2FyIGxvcyBjbMO6c3RlcmVzIG3DoXMgc2ltaWxhcmVzLg0KDQoqKlBhc28gNToqKiBGdXNpb25hciBlc3RvcyBkb3MgY2zDunN0ZXJlcyBlbiB1bm8gbnVldm8gcXVlIGNvbnRlbmdhIGFsIG1lbm9zIGRvcyBlbGVtZW50b3MsIHJlZHVjaWVuZG8gYXPDrSBlbiB1bm8gZWwgbsO6bWVybyB0b3RhbCBkZSBjbMO6c3RlcmVzLg0KDQoqKlBhc28gNjoqKiAqQ2FsY3VsYXIgbGEgZGlzdGFuY2lhIGVudHJlIGVzdGUgY2zDunN0ZXIgeSBlbCByZXN0byouIERpZmVyZW50ZXMgbcOpdG9kb3MgZGUgY8OhbGN1bG8gZGUgZGlzdGFuY2lhcyBlbnRyZSBjbMO6c3RlcmVzIHB1ZWRlbiBjb25kdWNpciBhIGFncnVwYWNpb25lcyBkaXN0aW50YXMsIGxvIHF1ZSBpbXBsaWNhIHF1ZSBubyBleGlzdGUgdW5hIGFncnVwYWNpw7NuIMO6bmljYS4NCg0KKipQYXNvIDc6KiogUmVwZXRpciBsb3MgcGFzb3MgZGVsIDQgYWwgNiBoYXN0YSBxdWUgdG9kb3MgbG9zIGVsZW1lbnRvcyBlc3TDqW4gYWdydXBhZG9zIGVuIHVuIMO6bmljbyBjbMO6c3Rlci4NCg0KKipQYXNvIDg6KiogUHVlZGUgZGlidWphciBlbCBkZW5kb2dyYW1hLg0KDQpFbCBwcm9jZXNvIGRlIGFncnVwYWNpw7NuIGplcsOhcnF1aWNhIHNlIHB1ZWRlIHJlcHJlc2VudGFyIHZpc3VhbG1lbnRlIG1lZGlhbnRlIHVuIGRlbmRyb2dyYW1hLiBFbiBlc3RlIGRpYWdyYW1hLCBsb3Mgb2JqZXRvcyBzaW1pbGFyZXMgc2UgY29uZWN0YW4gZW50cmUgc8OtIHkgc3UgcG9zaWNpw7NuIGVzdMOhIGRldGVybWluYWRhIHBvciBlbCBuaXZlbCBkZSBzaW1pbGl0dWQgbyBkaXNpbWlsaXR1ZCBlbnRyZSBlbGxvcy4NCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMgRWplbXBsbyAoamVyw6FycXVpY28gYXNjZW5kZW50ZSkNCg0KIyMjIERhdG9zIHBhcmEgZWwgZWplbXBsbw0KDQpWYW1vcyBhIHNlZ3VpciBlbCBwcm9jZWRpbWllbnRvIGRlc2NyaXRvIHV0aWxpemFuZG8gdW4gZWplbXBsbyBzaW1wbGUuIEVzdGUgZWplbXBsbyBjb25zdGEgZGUgNSBvYmpldG9zIChBLCBCLCBDLCBELCBFKSB5IDIgdmFyaWFibGVzICgkWF8xJCwgJFhfMiQpLiBMb3MgZGF0b3Mgc2UgbXVlc3RyYW4gYSBjb250aW51YWNpw7NuOg0KDQpgYGB7cn0NCmRhdG9zIDwtIGRhdGEuZnJhbWUoDQogIElEID0gYygiQSIsICJCIiwgIkMiLCAiRCIsICJFIiksDQogIHgxID0gYygxLjAsIDIuMCwgNC4wLCA3LjAsIDUuMCksDQogIHgyID0gYygxLjAsIDEuMCwgNS4wLCA3LjAsIDcuMCkpDQoNCnByaW50KGRhdG9zKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgUGFzb3MgMSB5IDINCg0KQ29uIGF5dWRhIGRlbCAgZGlhZ3JhbWEgZGUgZGlzcGVyc2nDs24sIHZlbW9zIHF1ZSBubyBoYXkgdmFsb3JlcyBhdMOtcGljb3MuDQoNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0b3MsYWVzKHggPSB4MSwgeSA9IHgyLCBjb2xvcj1JRCkpICsgDQogICAgICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplID0gMykgKw0KICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIikgKw0KICAgICAgICAgICAgICAgIGxhYnMoeCA9ICJ4MSIsIHkgPSAieDIiLCANCiAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkRpYWdyYW1hIGRlIGRpc3BlcnNpw7NuIikgDQpgYGANCg0KDQpgYGB7ciwgZXZhbD1GQUxTRSxlY2hvPUZBTFNFfQ0KZ2dwbG90KGRhdG9zLCBhZXMoeCA9IHgxLCB5ID0geDIsIGxhYmVsID0gSUQpKSArDQogICAgICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG9yID0gImJsdWUiKSArDQogICAgICAgICAgICAgIGdlb21fdGV4dCh2anVzdCA9IC0wLjUpICsNCiAgICAgICAgICAgICAgbGFicyh4ID0gIngxIiwgeSA9ICJ4MiIsIA0KICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkRpYWdyYW1hIGRlIGRpc3BlcnNpw7NuIikgKw0KICAgICAgICAgICAgICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KDQojIyMgUGFzbyAzDQoNCioqRGlzdGFuY2lhIGV1Y2xpZGlhbmEuKioNCg0KTGEgbWVkaWRhIGRlIGRpc3RhbmNpYSBxdWUgdXRpbGl6YXJlbW9zIGVudHJlIGxvcyBvYmpldG9zIHNlcsOhIGxhIGRpc3RhbmNpYSBldWNsaWRpYW5hLCBjdXlhIGV4cHJlc2nDs24gc2UgZGVmaW5lIGNvbW8gc2lndWUNCg0KJCREKEEsIEIpID0gXHNxcnR7ICh4X3tBXzF9IC0geF97Ql8xfSleMiArICh4X3tBXzJ9IC0geF97Ql8yfSleMiB9JCQNCg0KYGBge3J9DQojIEZ1bmNpw7NuIHBhcmEgY2FsY3VsYXIgbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmENCmRpc3RhbmNpYV9ldWNsaWRpYW5hIDwtIGZ1bmN0aW9uKHgxLCB5MSwgeDIsIHkyKXtzcXJ0KCh4MiAtIHgxKV4yICsgKHkyIC0geTEpXjIpfQ0KYGBgDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCioqRGlzdGFuY2lhIGV1Y2xpZGlhbmEgZW50cmUgQSB5IEIqKg0KDQpFc3RhIGV4cHJlc2nDs24gcmVwcmVzZW50YSBsYSBkaXN0YW5jaWEgZXVjbGlkaWFuYSBlbnRyZSBkb3MgcHVudG9zICRBJCB5ICRCJA0KIGVuIHVuIGVzcGFjaW8gYmlkaW1lbnNpb25hbCBkZWZpbmlkbyBwb3IgbGFzIGNvb3JkZW5hZGFzICR4XzEkIHkgJHhfMiQuIEFzw60sIHBvciBlamVtcGxvLCBsYSBkaXN0YW5jaWEgZW50cmUgZWwgY2zDunN0ZXIgJEEkIHkgZWwgY2zDunN0ZXIgJEIkIGVzOg0KIA0KJCREKEEsIEIpIFw7PVw7IFxzcXJ0eyAoMi4wIC0gMS4wKV4yICsgKDEuMCAtIDEuMCleMiB9IFw7PVw7IDEuMCQkDQogDQpgYGB7cn0NCiMgQ2FsY3VsYXIgbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEgZGUgQSBhIEINCmRpc3RhbmNpYV9BQiA8LSBkaXN0YW5jaWFfZXVjbGlkaWFuYSggZGF0b3MkeDFbZGF0b3MkSUQgPT0gIkEiXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdG9zJHgyW2RhdG9zJElEID09ICJBIl0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRvcyR4MVtkYXRvcyRJRCA9PSAiQiJdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0b3MkeDJbZGF0b3MkSUQgPT0gIkIiXSApDQpwcmludChkaXN0YW5jaWFfQUIpDQpgYGANCiANCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoqKkRpc3RhbmNpYSBldWNsaWRpYW5hIGVudHJlIHRvZG9zIGxvcyBwdW50b3MuKioNCg0KQ2FsY3VsYW1vcyBsYSBkaXN0YW5jaWEgRXVjbGlkaWFuYSBlbnRyZSB0b2RvcyBsb3MgcHVudG9zIHkgb2J0ZW5lbW9zIGxhIHNpZ3VpZW50ZSBtYXRyaXogZGUgZGlzdGFuY2lhcyBFdWNsaWRpYW5hcyBlbnRyZSBsb3Mgb2JqZXRvczogDQoNCmBgYHtyfQ0KIyBDYWxjdWxhciBsYXMgZGlzdGFuY2lhcyBldWNsaWRpYW5hcyBlbnRyZSB0b2RvcyBsb3MgcGFyZXMgZGUgcHVudG9zDQpkaXN0YW5jaWFzIDwtIG1hdHJpeChOQSwgbnJvdyA9IG5yb3coZGF0b3MpLCBuY29sID0gbnJvdyhkYXRvcykpDQoNCnJvd25hbWVzKGRpc3RhbmNpYXMpIDwtIGRhdG9zJElEDQpjb2xuYW1lcyhkaXN0YW5jaWFzKSA8LSBkYXRvcyRJRA0KDQpmb3IgKGkgaW4gMTpucm93KGRhdG9zKSkgew0KICAgICAgZm9yIChqIGluIDE6bnJvdyhkYXRvcykpIHsNCiAgICAgICAgICAgZGlzdGFuY2lhc1tpLCBqXSA8LSBkaXN0YW5jaWFfZXVjbGlkaWFuYSggZGF0b3MkeDFbaV0sICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdG9zJHgyW2ldLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRvcyR4MVtqXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0b3MkeDJbal0pDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KZGlzdGFuY2lhcyA8LSByb3VuZChkaXN0YW5jaWFzLCAyKQ0KcHJpbnQoZGlzdGFuY2lhcykNCmBgYA0KDQoNCmBgYHtyfQ0KZGF0b3MgPC0gZGF0YS5mcmFtZSgNCiAgSUQgPSBjKCJBIiwgIkIiLCAiQyIsICJEIiwgIkUiKSwNCiAgeDEgPSBjKDEuMCwgMi4wLCA0LjAsIDcuMCwgNS4wKSwNCiAgeDIgPSBjKDEuMCwgMS4wLCA1LjAsIDcuMCwgNy4wKSkNCg0KZGlzdGFuY2lhcyA8LSBkaXN0KGRhdG9zWywgYygieDEiLCAieDIiKV0pDQoNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmZ2aXpfZGlzdChkaXN0YW5jaWFzKQ0KYGBgDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KKipEaXN0YW5jaWEgZXVjbGlkaWFuYSBlbnRyZSB0b2RvcyBsb3MgcHVudG9zIChjb21vIG1hdHJpeiB0cmlhbmd1bGFyIGluZmVyaW9yKS4qKg0KDQpgYGB7cn0NCiMgQ2FsY3VsYXIgbGFzIGRpc3RhbmNpYXMgZXVjbGlkaWFuYXMgZW50cmUgdG9kb3MgbG9zIHBhcmVzIGRlIHB1bnRvcyAobWF0cml6IHRyaWFuZ3VsYXIgaW5mZXJpb3IpDQpkaXN0YW5jaWFzIDwtIG1hdHJpeChOQSwgbnJvdyA9IG5yb3coZGF0b3MpLCBuY29sID0gbnJvdyhkYXRvcykpDQoNCnJvd25hbWVzKGRpc3RhbmNpYXMpIDwtIGRhdG9zJElEDQpjb2xuYW1lcyhkaXN0YW5jaWFzKSA8LSBkYXRvcyRJRA0KDQpmb3IgKGkgaW4gMTpucm93KGRhdG9zKSkgew0KICAgICAgICBmb3IgKGogaW4gMTooaS0xKSkgew0KICAgICAgICAgIGRpc3RhbmNpYXNbaSwgal0gPC0gZGlzdGFuY2lhX2V1Y2xpZGlhbmEoIGRhdG9zJHgxW2ldLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRvcyR4MltpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0b3MkeDFbal0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0b3MkeDJbal0gKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KDQpkaXN0YW5jaWFzIDwtIHJvdW5kKGRpc3RhbmNpYXMsIDIpDQpwcmludChkaXN0YW5jaWFzKQ0KYGBgDQoNCiANCiBFc3RhbW9zIGVtcGxlYW5kbyBlbCBtw6l0b2RvIGplcsOhcnF1aWNvIGFzY2VuZGVudGUsIHBvciBsbyBxdWUgaW5pY2lhbG1lbnRlIHRlbmVtb3MgNSBjbMO6c3RlcmVzLCB1bm8gcG9yIGNhZGEgdW5vIGRlIGxvcyBvYmpldG9zIGEgY2xhc2lmaWNhci4NCiANCiANCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgUGFzbyA0DQogDQogRXhhbWluYW1vcyBsYSBtYXRyaXogZGUgZGlzdGFuY2lhcyBwYXJhIGlkZW50aWZpY2FyIGxvcyBvYmpldG9zIG3DoXMgc2ltaWxhcmVzLCBxdWUgZW4gbnVlc3RybyBjYXNvIHNvbiAkQSQgeSAkQiQsIGNvbiBsYSBtZW5vciBkaXN0YW5jaWEgKGlndWFsIGEgMSkuDQogDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIFBhc28gNQ0KDQpGdXNpb25hbW9zIGxvcyBjbMO6c3RlcmVzIG3DoXMgc2ltaWxhcmVzIHBhcmEgZm9ybWFyIHVuIG51ZXZvIGNsw7pzdGVyIHF1ZSBpbmNsdXllIGEgJEEkIHkgJEIkLiBBc8OtLCBzZSBjcmVhbiBsb3MgY2zDunN0ZXJlczogJEFCJCwgJEMkLCAkRCQgeSAkRSQuDQoNCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIFBhc28gNg0KDQoNCg0KDQoqKkNlbnRyb2lkZSBkZSBBIHkgQi4qKg0KDQpQYXJhIGRldGVybWluYXIgbGEgZGlzdGFuY2lhIGVudHJlIGVsIGNsw7pzdGVyICRBQiQgeSBsb3Mgb2JqZXRvcyAkQyQsICREJCB5ICRFJCwgZW1wbGVhbW9zIGVsIGNlbnRyb2lkZSBjb21vIGxhIHJlcHJlc2VudGFjacOzbiBkZWwgY2zDunN0ZXIgJEFCJC4gRXN0byBpbXBsaWNhIHV0aWxpemFyIHVuIHB1bnRvIGN1eWFzIGNvb3JkZW5hZGFzIHNlYW4gbGFzIG1lZGlhcyBkZSBsb3MgdmFsb3JlcyBkZSBsYXMgY29tcG9uZW50ZXMgZGUgbGFzIHZhcmlhYmxlcy4gQXPDrSwgb2J0ZW5lbW9zIGxhcyBjb29yZGVuYWRhcyBkZWwgY2zDunN0ZXIgJEFCJCBjb21vIA0KDQokJFx0ZXh0e0Nvb3JkZW5hZGFzIGRlbCBjZW50cm9pZGUgQUJ9IFw7PVw7IFxsZWZ0KCBcZnJhY3t7eF9BICsgeF9CfX17Mn0sXCwgXGZyYWN7e3lfQSArIHlfQn19ezJ9IFxyaWdodCkgXDs9XDsgXGxlZnQoIFxmcmFje3sxLjAgKyAyLjB9fXsyfSxcLCBcZnJhY3t7MS4wICsgMS4wfX17Mn0gXHJpZ2h0KSBcOz1cOyBcbGVmdCgxLjUsXCwgMS4wXHJpZ2h0KSQkDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoqKk51ZXZvcyBkYXRvcyBiYXNhZG9zIGVuIGVsIGNlbnRyb2lkZSBkZSBBIHkgQi4qKg0KDQpMYSBudWV2YSB0YWJsYSBkZSBkYXRvcyBlcyBsYSBzaWd1aWVudGU6DQoNCmBgYHtyfQ0KZGF0b3MgPC0gZGF0YS5mcmFtZSgNCiAgSUQgPSBjKCJBQiIsICJDIiwgIkQiLCAiRSIpLA0KICB4MSA9IGMoMS41LCA0LjAsIDcuMCwgNS4wKSwNCiAgeDIgPSBjKDEuMCwgNS4wLCA3LjAsIDcuMCkpDQoNCnByaW50KGRhdG9zKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgUGFzbyA3YQ0KDQpJdGVyYW1vcyBudWV2YW1lbnRlIGRlc2RlIGVsIHBhc28gNCBoYXN0YSBxdWUgdG9kb3MgbG9zIG9iamV0b3Mgc2UgYWdydXBlbiBlbiB1biDDum5pY28gY2zDunN0ZXIuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoqKlBhc28gNC4qKg0KDQpDb24gbG9zIG51ZXZvcyBkYXRvcywgY2FsY3VsYW1vcyBsYSBtYXRyaXogZGUgZGlzdGFuY2lhcy4NCg0KYGBge3J9DQojIENhbGN1bGFyIGxhcyBkaXN0YW5jaWFzIGV1Y2xpZGlhbmFzIGVudHJlIHRvZG9zIGxvcyBwYXJlcyBkZSBwdW50b3MgKG1hdHJpeiB0cmlhbmd1bGFyIGluZmVyaW9yKQ0KZGlzdGFuY2lhcyA8LSBtYXRyaXgoTkEsIG5yb3cgPSBucm93KGRhdG9zKSwgbmNvbCA9IG5yb3coZGF0b3MpKQ0KDQpyb3duYW1lcyhkaXN0YW5jaWFzKSA8LSBkYXRvcyRJRA0KY29sbmFtZXMoZGlzdGFuY2lhcykgPC0gZGF0b3MkSUQNCg0KZm9yIChpIGluIDE6bnJvdyhkYXRvcykpIHsNCiAgICAgICAgZm9yIChqIGluIDE6KGktMSkpIHsNCiAgICAgICAgICBkaXN0YW5jaWFzW2ksIGpdIDwtIGRpc3RhbmNpYV9ldWNsaWRpYW5hKCBkYXRvcyR4MVtpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0b3MkeDJbaV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdG9zJHgxW2pdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdG9zJHgyW2pdICkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICAgIH0NCg0KZGlzdGFuY2lhcyA8LSByb3VuZChkaXN0YW5jaWFzLCAyKQ0KcHJpbnQoZGlzdGFuY2lhcykNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KKipQYXNvIDUuKioNCg0KSWRlbnRpZmljYW1vcyBxdWUgbG9zIGNsw7pzdGVyZXMgbcOhcyBzaW1pbGFyZXMgc29uICREJCB5ICRFJCwgY29uIHVuYSBkaXN0YW5jaWEgZGUgMi4wLCBsb3MgY3VhbGVzIHNlIGNvbWJpbmFuIGVuIHVuIG51ZXZvIGNsw7pzdGVyIGxsYW1hZG8gJERFJC4gQWhvcmEgdGVuZW1vcyB0cmVzIGNsw7pzdGVyZXM6ICRBQiQsICRDJCwgJERFJC4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KKipQYXNvIDYuKioNCg0KRGV0ZXJtaW5hbW9zIGVsIGNlbnRyb2lkZSBkZWwgbnVldm8gY2zDunN0ZXIsIGVsIGN1YWwgZXMgZWwgcHVudG86DQokJFx0ZXh0e0Nvb3JkZW5hZGFzIGRlbCBjZW50cm9pZGUgREV9IFw7PVw7IFxsZWZ0KFxmcmFjezcuMCs1LjB9ezJ9LFwsIFxmcmFjezcuMCs3LjB9ezJ9XHJpZ2h0KSBcOz1cOyAoNi4wLFwsIDcuMCkkJA0KDQpFbiBjb25zZWN1ZW5jaWEsIGFjdHVhbGl6YW1vcyBsYSB0YWJsYSBkZSBkYXRvczogDQoNCg0KYGBge3J9DQpkYXRvcyA8LSBkYXRhLmZyYW1lKA0KICBJRCA9IGMoIkFCIiwgIkMiLCAiREUiKSwNCiAgeDEgPSBjKDEuNSwgNC4wLCA2LjApLA0KICB4MiA9IGMoMS4wLCA1LjAsIDcuMCkpDQoNCnByaW50KGRhdG9zKQ0KYGBgDQoNCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgUGFzbyA3Yg0KDQpJdGVyYW1vcyBudWV2YW1lbnRlIGRlc2RlIGVsIHBhc28gNCBoYXN0YSBxdWUgdG9kb3MgbG9zIG9iamV0b3Mgc2UgYWdydXBlbiBlbiB1biDDum5pY28gY2zDunN0ZXIuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoqKlBhc28gNC4qKg0KDQpDb24gbG9zIG51ZXZvcyBkYXRvcywgY2FsY3VsYW1vcyBsYSBtYXRyaXogZGUgZGlzdGFuY2lhcy4NCg0KYGBge3J9DQojIENhbGN1bGFyIGxhcyBkaXN0YW5jaWFzIGV1Y2xpZGlhbmFzIGVudHJlIHRvZG9zIGxvcyBwYXJlcyBkZSBwdW50b3MgKG1hdHJpeiB0cmlhbmd1bGFyIGluZmVyaW9yKQ0KZGlzdGFuY2lhcyA8LSBtYXRyaXgoTkEsIG5yb3cgPSBucm93KGRhdG9zKSwgbmNvbCA9IG5yb3coZGF0b3MpKQ0KDQpyb3duYW1lcyhkaXN0YW5jaWFzKSA8LSBkYXRvcyRJRA0KY29sbmFtZXMoZGlzdGFuY2lhcykgPC0gZGF0b3MkSUQNCg0KZm9yIChpIGluIDE6bnJvdyhkYXRvcykpIHsNCiAgICAgICAgZm9yIChqIGluIDE6KGktMSkpIHsNCiAgICAgICAgICBkaXN0YW5jaWFzW2ksIGpdIDwtIGRpc3RhbmNpYV9ldWNsaWRpYW5hKCBkYXRvcyR4MVtpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0b3MkeDJbaV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdG9zJHgxW2pdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdG9zJHgyW2pdICkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICAgIH0NCg0KZGlzdGFuY2lhcyA8LSByb3VuZChkaXN0YW5jaWFzLCAyKQ0KcHJpbnQoZGlzdGFuY2lhcykNCmBgYA0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoqKlBhc28gNS4qKg0KDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0KZGF0b3MgPC0gZGF0YS5mcmFtZSgNCiAgSUQgPSBjKCJBIiwgIkIiLCAiQyIsICJEIiwgIkUiKSwNCiAgeDEgPSBjKDEuMCwgMi4wLCA0LjAsIDcuMCwgNS4wKSwNCiAgeDIgPSBjKDEuMCwgMS4wLCA1LjAsIDcuMCwgNy4wKSkNCg0KIyBDb29yZGVuYWRhcyBkZSBsb3MgcHVudG9zIGVuIGVsIGNsdXN0ZXIgQyB5IERFDQpjb29yZGVuYWRhc19DIDwtIGRhdG9zW2RhdG9zJElEICVpbiUgYygiQyIpLCBjKCJ4MSIsICJ4MiIpXQ0KY29vcmRlbmFkYXNfREUgPC0gZGF0b3NbZGF0b3MkSUQgJWluJSBjKCJEIiwgIkUiKSwgYygieDEiLCAieDIiKV0NCg0KIyBDYWxjdWxhciBlbCBjZW50cm9pZGUgZGUgY2FkYSBjbHVzdGVyIChwcm9tZWRpbyBkZSBsYXMgY29vcmRlbmFkYXMpDQpjZW50cm9pZF9DIDwtIGNvbE1lYW5zKGNvb3JkZW5hZGFzX0MpDQpjZW50cm9pZF9ERSA8LSBjb2xNZWFucyhjb29yZGVuYWRhc19ERSkNCg0KIyBDYWxjdWxhciBsYSBkaXN0YW5jaWEgZXVjbGlkaWFuYSBlbnRyZSBsb3MgY2VudHJvaWRlcyBkZSBsb3MgY2x1c3RlcnMgQyB5IERFDQpkaXN0YW5jaWFfY2VudHJvaWRlcyA8LSBzcXJ0KHN1bSgoY2VudHJvaWRfQyAtIGNlbnRyb2lkX0RFKV4yKSkNCg0KZGlzdGFuY2lhX2NlbnRyb2lkZXMNCmBgYA0KDQoNCklkZW50aWZpY2Ftb3MgcXVlIGxvcyBjbMO6c3RlcmVzIG3DoXMgc2ltaWxhcmVzIHNvbiAkQyQgeSAkREUkLCBjb24gdW5hIGRpc3RhbmNpYSBkZSAyLjgzIGVudHJlIGVsbG9zLiBFc3RvcyBzZSBjb21iaW5hbiBwYXJhIGZvcm1hciB1biBudWV2byBjbMO6c3RlciBkZW5vbWluYWRvIENERS4gRW4gZXN0ZSBwdW50bywgaGVtb3MgZ2VuZXJhZG8gZG9zIGNsw7pzdGVyZXM6ICRBQiQgeSAkQ0RFJC4NCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCioqUGFzbyA2LioqDQoNCkRldGVybWluYW1vcyBlbCBjZW50cm9pZGUgZGVsIG51ZXZvIGNsw7pzdGVyICRDREUkIGNhbGN1bGFuZG8gbGFzIG1lZGlhcyBkZSBsYXMgY29vcmRlbmFkYXMgZGUgc3VzIGNvbXBvbmVudGVzOg0KDQokJFx0ZXh0e0Nvb3JkZW5hZGFzIGRlbCBjZW50cm9pZGUgQ0RFfSBcOz1cOyBcbGVmdChcZnJhY3s0LjArNS4wKzcuMH17M30sXCwgXGZyYWN7NS4wKzcuMCs3LjB9ezN9XHJpZ2h0KSBcOz1cOyAoNS4zLFwsIDYuMykkJA0KDQoNClBvc3Rlcmlvcm1lbnRlLCBjcmVhbW9zIHVuYSBudWV2YSB0YWJsYSBkZSBkYXRvcy4NCg0KDQpgYGB7cn0NCmRhdG9zIDwtIGRhdGEuZnJhbWUoDQogIElEID0gYygiQUIiLCAiQ0RFIiksDQogIHgxID0gYygxLjUsIDUuMyksDQogIHgyID0gYygxLjAsIDYuMykpDQoNCnByaW50KGRhdG9zKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgUGFzbyA3Yw0KDQpJdGVyYW1vcyBudWV2YW1lbnRlIGRlc2RlIGVsIHBhc28gNCBoYXN0YSBxdWUgdG9kb3MgbG9zIG9iamV0b3Mgc2UgYWdydXBlbiBlbiB1biDDum5pY28gY2zDunN0ZXIuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQoqKlBhc28gNC4qKg0KDQpDb24gbG9zIG51ZXZvcyBkYXRvcywgY2FsY3VsYW1vcyBsYSBtYXRyaXogZGUgZGlzdGFuY2lhcy4NCg0KYGBge3J9DQojIENhbGN1bGFyIGxhcyBkaXN0YW5jaWFzIGV1Y2xpZGlhbmFzIGVudHJlIHRvZG9zIGxvcyBwYXJlcyBkZSBwdW50b3MgKG1hdHJpeiB0cmlhbmd1bGFyIGluZmVyaW9yKQ0KZGlzdGFuY2lhcyA8LSBtYXRyaXgoTkEsIG5yb3cgPSBucm93KGRhdG9zKSwgbmNvbCA9IG5yb3coZGF0b3MpKQ0KDQpyb3duYW1lcyhkaXN0YW5jaWFzKSA8LSBkYXRvcyRJRA0KY29sbmFtZXMoZGlzdGFuY2lhcykgPC0gZGF0b3MkSUQNCg0KZm9yIChpIGluIDE6bnJvdyhkYXRvcykpIHsNCiAgICAgICAgZm9yIChqIGluIDE6KGktMSkpIHsNCiAgICAgICAgICBkaXN0YW5jaWFzW2ksIGpdIDwtIGRpc3RhbmNpYV9ldWNsaWRpYW5hKCBkYXRvcyR4MVtpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0b3MkeDJbaV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdG9zJHgxW2pdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdG9zJHgyW2pdICkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICAgIH0NCg0KZGlzdGFuY2lhcyA8LSByb3VuZChkaXN0YW5jaWFzLCAyKQ0KcHJpbnQoZGlzdGFuY2lhcykNCmBgYA0KDQpgYGB7ciwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0NCmRhdG9zIDwtIGRhdGEuZnJhbWUoDQogIElEID0gYygiQSIsICJCIiwgIkMiLCAiRCIsICJFIiksDQogIHgxID0gYygxLjAsIDIuMCwgNC4wLCA3LjAsIDUuMCksDQogIHgyID0gYygxLjAsIDEuMCwgNS4wLCA3LjAsIDcuMCkpDQoNCiMgQ29vcmRlbmFkYXMgZGUgbG9zIHB1bnRvcyBlbiBsb3MgY2x1c3RlcnMgQUIgeSBDREUNCmNvb3JkZW5hZGFzX0FCIDwtIGRhdG9zW2RhdG9zJElEICVpbiUgYygiQSIsICJCIiksIGMoIngxIiwgIngyIildDQpjb29yZGVuYWRhc19DREUgPC0gZGF0b3NbZGF0b3MkSUQgJWluJSBjKCJDIiwgIkQiLCAiRSIpLCBjKCJ4MSIsICJ4MiIpXQ0KDQojIENhbGN1bGFyIGVsIGNlbnRyb2lkZSBkZSBjYWRhIGNsdXN0ZXIgKHByb21lZGlvIGRlIGxhcyBjb29yZGVuYWRhcykNCmNlbnRyb2lkX0FCIDwtIGNvbE1lYW5zKGNvb3JkZW5hZGFzX0FCKQ0KY2VudHJvaWRfQ0RFIDwtIGNvbE1lYW5zKGNvb3JkZW5hZGFzX0NERSkNCg0KIyBDYWxjdWxhciBsYSBkaXN0YW5jaWEgZXVjbGlkaWFuYSBlbnRyZSBsb3MgY2VudHJvaWRlcyBkZSBsb3MgY2x1c3RlcnMgQUIgeSBDREUNCmRpc3RhbmNpYV9jZW50cm9pZGVzX0FCX0NERSA8LSBzcXJ0KHN1bSgoY2VudHJvaWRfQUIgLSBjZW50cm9pZF9DREUpXjIpKQ0KDQpkaXN0YW5jaWFfY2VudHJvaWRlc19BQl9DREUNCmBgYA0KDQoNCg0KRW4gZXN0ZSDDumx0aW1vIHBhc28sIG9ic2VydmFtb3MgcXVlIGhheSBzb2xvIGRvcyBjbMO6c3RlcmVzIGNvbiB1bmEgZGlzdGFuY2lhIGRlIDYuNSBlbnRyZSBlbGxvcy4gRXN0b3MgZG9zIGNsw7pzdGVyZXMgc2UgZnVzaW9uYXLDoW4gZW4gdW4gw7puaWNvIGNsw7pzdGVyIGVuIGVsIHNpZ3VpZW50ZSBwYXNvLCBsbyBxdWUgbWFyY2Fyw6EgZWwgZmluYWwgZGVsIHByb2Nlc28uDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgUGFzbyA4YTogZGVuZG9ncmFtYQ0KDQpBIGNvbnRpbnVhY2nDs24sIHZpc3VhbGl6YXJlbW9zIGVsIHByb2Nlc28gZGUgZnVzacOzbiBkZSBtYW5lcmEgZ3LDoWZpY2EgdXRpbGl6YW5kbyB1biBkZW5kcm9ncmFtYS4NCg0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQojIENhcmdhciBsYSBsaWJyZXLDrWEgbmVjZXNhcmlhDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRlbmRleHRlbmQpDQoNCiMgQ3JlYXIgbG9zIGRhdG9zDQpkYXRvcyA8LSBkYXRhLmZyYW1lKA0KICBJRCA9IGMoIkEiLCAiQiIsICJDIiwgIkQiLCAiRSIpLA0KICB4MSA9IGMoMS4wLCAyLjAsIDQuMCwgNy4wLCA1LjApLA0KICB4MiA9IGMoMS4wLCAxLjAsIDUuMCwgNy4wLCA3LjApKQ0KDQojIENvbnZlcnRpciBsb3MgZGF0b3MgZW4gdW5hIG1hdHJpeiBkZSBkaXN0YW5jaWFzDQpkaXN0YW5jaWFzIDwtIGRpc3QoZGF0b3NbLCBjKCJ4MSIsICJ4MiIpXSkNCg0KIyBDYWxjdWxhciBlbCBkZW5kcm9ncmFtYQ0KZGVuZHJvZ3JhbWEgPC0gYXMuZGVuZHJvZ3JhbShoY2x1c3QoZGlzdGFuY2lhcykpDQoNCiMgR3JhZmljYXIgZWwgZGVuZHJvZ3JhbWENCnBsb3QoZGVuZHJvZ3JhbWEsIG1haW4gPSAiRGVuZHJvZ3JhbWEiLCB4bGFiID0gIk9iamV0b3MiLCB5bGFiID0gIkRpc3RhbmNpYSIpDQpgYGANCg0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQpkZiA8LSBkYXRhLmZyYW1lKA0KICBJRCA9IGMoIkEiLCAiQiIsICJDIiwgIkQiLCAiRSIpLA0KICB4MSA9IGMoMS4wLCAyLjAsIDQuMCwgNy4wLCA1LjApLA0KICB4MiA9IGMoMS4wLCAxLjAsIDUuMCwgNy4wLCA3LjApKQ0KDQpyZXMuZGlzdCA8LSBkaXN0KGRmLCBtZXRob2QgPSAiZXVjbGlkZWFuIikNCg0KcmVzLmhjIDwtIGhjbHVzdChkID0gcmVzLmRpc3QsIG1ldGhvZCA9ICJ3YXJkLkQyIikNCg0KIyBjZXg6IGxhYmVsIHNpemUNCmxpYnJhcnkoImZhY3RvZXh0cmEiKQ0KZnZpel9kZW5kKHJlcy5oYywgY2V4ID0gMC41KQ0KYGBgDQoNCg0KYGBge3J9DQojIENhcmdhciBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRlbmRleHRlbmQpDQoNCiMgQ3JlYXIgbG9zIGRhdG9zDQpkYXRvcyA8LSBkYXRhLmZyYW1lKA0KICBJRCA9IGMoIkEiLCAiQiIsICJDIiwgIkQiLCAiRSIpLA0KICB4MSA9IGMoMS4wLCAyLjAsIDQuMCwgNy4wLCA1LjApLA0KICB4MiA9IGMoMS4wLCAxLjAsIDUuMCwgNy4wLCA3LjApKQ0KDQojIENvbnZlcnRpciBsb3MgZGF0b3MgZW4gdW5hIG1hdHJpeiBkZSBkaXN0YW5jaWFzDQpkaXN0YW5jaWFzIDwtIGRpc3QoZGF0b3NbLCBjKCJ4MSIsICJ4MiIpXSkNCg0KIyBDYWxjdWxhciBlbCBkZW5kcm9ncmFtYQ0KZGVuZHJvZ3JhbWEgPC0gYXMuZGVuZHJvZ3JhbShoY2x1c3QoZGlzdGFuY2lhcykpDQoNCiMgRXN0YWJsZWNlciBsYXMgZXRpcXVldGFzIGRlIGxvcyBvYmpldG9zDQpsYWJlbHMgPC0gZGF0b3MkSUQNCg0KIyBBc2lnbmFyIGV0aXF1ZXRhcyBhbCBkZW5kcm9ncmFtYQ0KbGFiZWxzKGRlbmRyb2dyYW1hKSA8LSBsYWJlbHMNCg0KIyBHcmFmaWNhciBlbCBkZW5kcm9ncmFtYQ0KcGxvdChkZW5kcm9ncmFtYSwgbWFpbiA9ICJEZW5kcm9ncmFtYSIsIHhsYWIgPSAiT2JqZXRvcyIsIHlsYWIgPSAiRGlzdGFuY2lhIikNCmBgYA0KDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0KIyBBZ3JlZ2FyIHRleHRvIHBhcmEgbG9zIGNsdXN0ZXJzIGZ1c2lvbmFkb3MNCnRleHQoMy41LCAxMCwgIkNsdXN0ZXIgQUIiLCBjZXggPSAwLjgpDQp0ZXh0KDksIDEwLCAiQ2x1c3RlciBERSIsIGNleCA9IDAuOCkNCnRleHQoNiwgMTUsICJDbHVzdGVyIENERSIsIGNleCA9IDAuOCkNCmBgYA0KDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0KIyBDYXJnYXIgbGFzIGxpYnJlcsOtYXMgbmVjZXNhcmlhcw0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkZW5kZXh0ZW5kKQ0KDQojIENyZWFyIGxvcyBkYXRvcw0KZGF0b3MgPC0gZGF0YS5mcmFtZSgNCiAgSUQgPSBjKCJBIiwgIkIiLCAiQyIsICJEIiwgIkUiKSwNCiAgeDEgPSBjKDEuMCwgMi4wLCA0LjAsIDcuMCwgNS4wKSwNCiAgeDIgPSBjKDEuMCwgMS4wLCA1LjAsIDcuMCwgNy4wKSkNCg0KIyBDb252ZXJ0aXIgbG9zIGRhdG9zIGVuIHVuYSBtYXRyaXogZGUgZGlzdGFuY2lhcw0KZGlzdGFuY2lhcyA8LSBkaXN0KGRhdG9zWywgYygieDEiLCAieDIiKV0pDQoNCiMgQ2FsY3VsYXIgZWwgZGVuZHJvZ3JhbWENCmRlbmRyb2dyYW1hIDwtIGFzLmRlbmRyb2dyYW0oaGNsdXN0KGRpc3RhbmNpYXMpKQ0KDQojIENvbnZlcnRpciBlbCBkZW5kcm9ncmFtYSBhIHVuIG9iamV0byBjb21wYXRpYmxlIGNvbiBnZ3Bsb3QyDQpkZW5kX2dncGxvdCA8LSBhcy5nZ2RlbmQoZGVuZHJvZ3JhbWEpDQoNCiMgQ3JlYXIgZWwgZGVuZHJvZ3JhbWEgdXRpbGl6YW5kbyBnZ3Bsb3QNCmdncGxvdChkZW5kX2dncGxvdCwgaG9yaXogPSBGQUxTRSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArDQogIGxhYnMoeCA9ICJPYmpldG9zIiwgeSA9ICJEaXN0YW5jaWEiLCB0aXRsZSA9ICJEZW5kcm9ncmFtYSIpDQpgYGANCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0KI2h0dHBzOi8vcnB1YnMuY29tL0NDaGFycmlhLzY0MjgyMg0KYGBgDQoNCg0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQojIENhcmdhciBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRlbmRleHRlbmQpDQoNCiMgQ3JlYXIgbG9zIGRhdG9zDQpkYXRvcyA8LSBkYXRhLmZyYW1lKA0KICBJRCA9IGMoIkEiLCAiQiIsICJDIiwgIkQiLCAiRSIpLA0KICB4MSA9IGMoMS4wLCAyLjAsIDQuMCwgNy4wLCA1LjApLA0KICB4MiA9IGMoMS4wLCAxLjAsIDUuMCwgNy4wLCA3LjApKQ0KDQojIENvbnZlcnRpciBsb3MgZGF0b3MgZW4gdW5hIG1hdHJpeiBkZSBkaXN0YW5jaWFzDQptYXRyaXpEaXN0YW5jaWFzIDwtIGRpc3QoZGF0b3NbLCBjKCJ4MSIsICJ4MiIpXSkNCg0KDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbWF0cml6TG9uZzwtIG1lbHQoZGF0YS5tYXRyaXgobWF0cml6RGlzdGFuY2lhcykpDQpoZWFkKG1hdHJpekxvbmcpDQoNCmdyYWZpY2E8LSBnZ3Bsb3QobWF0cml6TG9uZywgYWVzKHg9VmFyMSwgeT1WYXIyLCBmaWxsPW1hdHJpekxvbmckdmFsdWUpKQ0KZ3JhZmljYTwtIGdyYWZpY2ErZ2VvbV90aWxlKCkgKyBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAibWFnbWEiKQ0KZ3JhZmljYSA8LSBncmFmaWNhICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpDQoNCmdyYWZpY2ENCg0KI1JlYWxpemFtb3MgZWwgRGVuZHJvZ3JhbWENCmhjMjAwODwtaGNsdXN0KG1hdHJpekRpc3RhbmNpYXMpDQpoYzIwMDgNCg0KI0dyYWZpY2Ftb3MgZWwgRGVuZHJvZ3JhbWENCmxpYnJhcnkoZ2dkZW5kcm8pDQpncmFmaWNhX0RlbmRvZ3JhbWE8LWdnZGVuZHJvZ3JhbShoYzIwMDgscm90YXRlID0gRkFMU0UsIHNpemU9MikNCmdyYWZpY2FfRGVuZG9ncmFtYQ0KYGBgDQoNCg0KYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9DQojRGFyIGNvbG9yIGEgbG9zIGJyYXpvcyBkZWwgZGVuZHJvZ3JhbWENCg0KZGhjMjAwOCA8LSBhcy5kZW5kcm9ncmFtKGhjMjAwOCkNCg0KIyBGdW5jacOzbiBwYXJhIGNvbG9yZWFyIGxvcyBicmF6b3MNCmNvbGJyYW5jaGVzIDwtIGZ1bmN0aW9uKG4sIGNvbCkNCiAgew0KICBhIDwtIGF0dHJpYnV0ZXMobikgIyBFbmN1ZW50cmEgbG9zIGF0cmlidXRvcyBkZWwgbm9kbw0KICAjIENvbG9yIGVkZ2VzIHdpdGggcmVxdWVzdGVkIGNvbG9yDQogIGF0dHIobiwgImVkZ2VQYXIiKSA8LSBjKGEkZWRnZVBhciwgbGlzdChjb2w9Y29sLCBsd2Q9MikpDQogIG4gIyBEb24ndCBmb3JnZXQgdG8gcmV0dXJuIHRoZSBub2RlIQ0KICB9DQoNCiMgQ29sb3JlYSBlbCBwcmltZXIgc3ViLWJyYXpvIGRlbCBwcmltZXIgYnJhem8gZW4gcm9qbywNCiMgZWwgc2VndW5kbyBzdWItYnJhem8gZW4gbmFyYW5qYSB5IGVsIHNlZ3VuZG8gYnJhem8gZW4gYXp1bA0KZGhjMjAwOFtbMV1dW1sxXV0gPSBkZW5kcmFwcGx5KGRoYzIwMDhbWzFdXVtbMV1dLCBjb2xicmFuY2hlcywgInJlZCIpDQpkaGMyMDA4W1sxXV1bWzJdXSA9IGRlbmRyYXBwbHkoZGhjMjAwOFtbMV1dW1syXV0sIGNvbGJyYW5jaGVzLCAib3JhbmdlIikNCmRoYzIwMDhbWzJdXVtbMV1dID0gZGVuZHJhcHBseShkaGMyMDA4W1syXV1bWzFdXSwgY29sYnJhbmNoZXMsICJncmVlbiIpDQpkaGMyMDA4W1syXV1bWzJdXSA9IGRlbmRyYXBwbHkoZGhjMjAwOFtbMl1dW1syXV0sIGNvbGJyYW5jaGVzLCAiYmx1ZSIpDQoNCiNkaGMyMDA4W1syXV1bWzJdXVtbMV1dW1syXV1bWzJdXSA9IGRlbmRyYXBwbHkoZGhjMjAwOFtbMl1dW1syXV1bWzFdXVtbMl1dW1syXV0sIGNvbGJyYW5jaGVzLCAiYmx1ZSIpDQoNCiMgUGxvdA0KcGxvdChkaGMyMDA4KQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIExhIGZ1bmNpw7NuIGBoY2x1c3RgDQoNCiMjIyBgaGNsdXN0YDogT2JzZXJ2YWNpb25lcyBnZW5lcmFsZXMNCg0KMS4gTGEgZnVuY2nDs24gYGhjbHVzdGAgc2UgdXRpbGl6YSBwYXJhIHJlYWxpemFyIHVuIGFncnVwYW1pZW50byBqZXLDoXJxdWljbyBkZSB1biBjb25qdW50byBkZSBkYXRvcy4gVA0KDQoyLiBMYSBmdW5jacOzbiBgaGNsdXN0YCBwcm9wb3JjaW9uYSB2YXJpb3MgbcOpdG9kb3MgcXVlIHNlIHB1ZWRlbiB1dGlsaXphciBwYXJhIHJlYWxpemFyIGFncnVwYW1pZW50b3MgamVyw6FycXVpY29zLiANCg0KMy4gRXN0b3MgbcOpdG9kb3MgZGV0ZXJtaW5hbiBjw7NtbyBzZSBjYWxjdWxhbiBsYXMgZGlzdGFuY2lhcyBlbnRyZSBsb3MgZ3J1cG9zIGVuIGNhZGEgcGFzbyBkZWwgYWxnb3JpdG1vIGRlIGFncnVwYW1pZW50by4gDQoNCjQuIEVzdG9zIG3DqXRvZG9zIHNvbiDDunRpbGVzIHBhcmEgZGlmZXJlbnRlcyB0aXBvcyBkZSBkYXRvcyB5IHB1ZWRlbiBjb25kdWNpciBhIGRpZmVyZW50ZXMgZXN0cnVjdHVyYXMgZGUgYWdydXBhbWllbnRvLiBMYSBlbGVjY2nDs24gZGVsIG3DqXRvZG8gZGVwZW5kZSBkZWwgdGlwbyBkZSBkYXRvcyB5IGRlbCBvYmpldGl2byBkZWwgYW7DoWxpc2lzLg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBoY2x1c3RgOiBtw6l0b2Rvcw0KDQoNCkFxdcOtIGVzdMOhbiBhbGd1bm9zIGRlIGxvcyBtw6l0b2RvcyBkaXNwb25pYmxlcyB5IHBhcmEgcXXDqSBzZSB1dGlsaXphbjoNCg0KKioxLiBgbWV0aG9kID0gY29tcGxldGUiYCAodGFtYmnDqW4gY29ub2NpZG8gY29tbyBtw6l0b2RvIGRlIGVubGFjZSBjb21wbGV0bykuKioNCiAgDQogICsgRXN0ZSBtw6l0b2RvIGNhbGN1bGEgbGEgZGlzdGFuY2lhIG3DoXhpbWEgZW50cmUgbG9zIHB1bnRvcyBkZSBsb3MgZG9zIGdydXBvcy4NCiAgDQogICsgTGEgZGlzdGFuY2lhIGVudHJlIGRvcyBncnVwb3Mgc2UgZGVmaW5lIGNvbW8gbGEgbWF5b3IgZGlzdGFuY2lhIGVudHJlIHVuIHB1bnRvIGRlbCBwcmltZXIgZ3J1cG8geSB1biBwdW50byBkZWwgc2VndW5kbyBncnVwby4gDQogIA0KICArIFNlIHV0aWxpemEgY3VhbmRvIHNlIHF1aWVyZSBldml0YXIgcXVlIGxvcyBwdW50b3MgbGVqYW5vcyBkZSB1biBncnVwbyBhZmVjdGVuIGRlbWFzaWFkbyBhbCBjw6FsY3VsbyBkZSBsYSBkaXN0YW5jaWEgZW50cmUgZ3J1cG9zLg0KDQoqKjIuIGBtZXRob2QgPSAic2luZ2xlImAgKHRhbWJpw6luIGNvbm9jaWRvIGNvbW8gbcOpdG9kbyBkZSBlbmxhY2Ugc2ltcGxlKS4qKg0KICANCiAgKyBFc3RlIG3DqXRvZG8gY2FsY3VsYSBsYSBkaXN0YW5jaWEgbcOtbmltYSBlbnRyZSBsb3MgcHVudG9zIGRlIGxvcyBkb3MgZ3J1cG9zLiANCiAgDQogICsgTGEgZGlzdGFuY2lhIGVudHJlIGRvcyBncnVwb3Mgc2UgZGVmaW5lIGNvbW8gbGEgbWVub3IgZGlzdGFuY2lhIGVudHJlIHVuIHB1bnRvIGRlbCBwcmltZXIgZ3J1cG8geSB1biBwdW50byBkZWwgc2VndW5kbyBncnVwby4gDQogIA0KICArRXN0ZSBtw6l0b2RvIGVzIHNlbnNpYmxlIGEgcHVudG9zIGF0w61waWNvcyB5IHB1ZWRlIGdlbmVyYXIgZ3J1cG9zIGFsYXJnYWRvcy4NCg0KKiozLiBgbWV0aG9kID0gImF2ZXJhZ2UiYCAodGFtYmnDqW4gY29ub2NpZG8gY29tbyBtw6l0b2RvIGRlIGVubGFjZSBwcm9tZWRpbykuKioNCiAgDQogICsgRXN0ZSBtw6l0b2RvIGNhbGN1bGEgbGEgZGlzdGFuY2lhIHByb21lZGlvIGVudHJlIHRvZG9zIGxvcyBwYXJlcyBkZSBwdW50b3MgZGUgbG9zIGRvcyBncnVwb3MuIA0KICANCiAgKyBMYSBkaXN0YW5jaWEgZW50cmUgZG9zIGdydXBvcyBzZSBkZWZpbmUgY29tbyBlbCBwcm9tZWRpbyBkZSB0b2RhcyBsYXMgZGlzdGFuY2lhcyBlbnRyZSBsb3MgcHVudG9zIGRlIGxvcyBkb3MgZ3J1cG9zLiANCiAgDQogICsgRXMgdW4gbcOpdG9kbyBtw6FzIHJvYnVzdG8gcXVlIGVsIGVubGFjZSBzaW1wbGUgeSBtZW5vcyBzZW5zaWJsZSBhIHB1bnRvcyBhdMOtcGljb3MuDQoNCioqNC4gYG1ldGhvZCA9ICAid2FyZC5EImAgKG3DqXRvZG8gZGUgV2FyZCBjb24gbGEgZGlzdGFuY2lhIGFsIGN1YWRyYWRvKS4qKg0KICANCiAgKyBFc3RlIG3DqXRvZG8gbWluaW1pemEgbGEgdmFyaWFuemEgY3VhbmRvIHNlIGZ1c2lvbmFuIGRvcyBncnVwb3MuIFV0aWxpemEgbGEgZGlzdGFuY2lhIGFsIGN1YWRyYWRvIGVudHJlIGxvcyBjZW50cm9pZGVzIGRlIGxvcyBncnVwb3MgcGFyYSBldmFsdWFyIGN1w6FudG8gYXVtZW50YXLDoSBsYSB2YXJpYW56YSB0b3RhbCBjdWFuZG8gc2UgZnVzaW9uZW4gZG9zIGdydXBvcy4gDQogIA0KICArIFNlIHV0aWxpemEgY3VhbmRvIHNlIGRlc2VhIHF1ZSBsb3MgZ3J1cG9zIHJlc3VsdGFudGVzIHRlbmdhbiB1bmEgdmFyaWFuemEgbcOtbmltYSBkZW50cm8gZGUgZWxsb3MuDQoNCioqNS4gYG1ldGhvZCA9ICJ3YXJkLkQyImAgKG3DqXRvZG8gZGUgV2FyZCBjb24gbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEgYWwgY3VhZHJhZG8pLioqDQoNCiAgKyBTaW1pbGFyIGEgYCJ3YXJkLkQiYCwgcGVybyB1dGlsaXphIGxhIGRpc3RhbmNpYSBldWNsaWRpYW5hIGFsIGN1YWRyYWRvIGVudHJlIGxvcyBjZW50cm9pZGVzIGRlIGxvcyBncnVwb3MuDQogIA0KICArIFN1IGbDs3JtdWxhIGVzIGRpZmVyZW50ZSBhIGxhIGRlIGAid2FyZC5EImAuIA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBoY2x1c3RgOiBlamVtcGxvIGFudGVyaW9yIChhbHR1cmFzKQ0KDQpFbiBlbCBjw7NkaWdvIG1vc3RyYWRvIGVuIGVsIHBhc28gOGIgZGVsIGVqZW1wbG8gYW50ZXJpb3I6IA0KDQoqKjEuIE9iamV0by4qKg0KDQpMYSBmdW5jacOzbiBgaGNsdXN0YCB0b21hIGNvbW8gZW50cmFkYSB1bmEgbWF0cml6IGRlIGRpc3RhbmNpYXMgZW50cmUgbG9zIHB1bnRvcyBkZSBkYXRvcyB5IGRldnVlbHZlIHVuIG9iamV0byBkZSB0aXBvIGBoY2x1c3RgLCBxdWUgcmVwcmVzZW50YSBsYSBqZXJhcnF1w61hIGRlIGFncnVwYW1pZW50b3MuIA0KDQoqKjIuIG91dHB1dC4qKg0KDQoyLiBTZSBwdWVkZSBkZWZpbmlyIGVsIG9iamV0byBjb3JyZXNwb25kaWVudGUgYXPDrSB5IG9idGVuZXIgZWwgb3V0cHV0IGNvcnJlc3BvbmRpZW50ZTogDQoNCmBgYHtyfQ0KaGNsdXN0X29iaiA8LSBoY2x1c3QoZGlzdGFuY2lhcykNCmhjbHVzdF9vYmoNCmBgYA0KDQoqKjMuIEFsdHVyYXMgZW4gZWwgZGVuZG9ncmFtYS4qKg0KDQpDb24gZWwgb2JqZXRvIGBoY2x1c3Rfb2JqYCwgc2UgcHVlZGVuIG9idGVuZXIgbGFzIGFsdHVyYXMgZGUgbG9zIGNsw7pzdGVyZXM6ICANCg0KYGBge3J9DQpoZWlnaHRzIDwtIGhjbHVzdF9vYmokaGVpZ2h0DQpoZWlnaHRzDQpgYGANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBoY2x1c3RgOiBlamVtcGxvIGNvbiBvdHJvcyBtw6l0b2Rvcw0KDQpTZSBwdWVkZSBjYW1iaWFyIGVsIGNyaXRlcmlvIHV0aWxpemFkbyBlbiBlbCBhbsOhbGlzaXMgZGUgY29uZ2xvbWVyYWRvcyAoY2x1c3RlciBhbmFseXNpcykgcGFyYSBtZWRpciBsYSBkaXN0YW5jaWEgZW50cmUgZG9zIGdydXBvcyBkZSBkYXRvcy4gUG9yIGVqZW1wbG8sIHNlIHB1ZWRlIGFncmVnYXIgZWwgYXJndW1lbnRvICBgbWV0aG9kID0gIndhcmQuRCJgIChvIGBtZXRob2QgPSAid2FyZC5EMiJgKSBkZW50cm8gZGUgbGEgZnVuY2nDs24gYGhjbHVzdGAuIA0KDQoqKjEuIENhbGN1bGFyIGVsIGRlbmRyb2dyYW1hIGNvbiBlbCBtw6l0b2RvIGB3YXJkLkRgKioNCg0KDQpgYGB7cn0NCmhjbHVzdF9vYmpfRCA8LSBoY2x1c3QoZGlzdGFuY2lhcywgbWV0aG9kID0gIndhcmQuRCIpDQpwbG90KGhjbHVzdF9vYmpfRCwgbGFiZWxzID0gZGF0b3MkSUQsIG1haW4gPSAiRGVuZHJvZ3JhbWEiLCB4bGFiID0gIk9iamV0b3MiLCB5bGFiID0gIkRpc3RhbmNpYSIpDQpgYGANCg0KKioyLiBDYWxjdWxhciBlbCBkZW5kcm9ncmFtYSBjb24gZWwgbcOpdG9kbyBgd2FyZC5EMmAuKioNCg0KDQpgYGB7cn0NCmhjbHVzdF9vYmpfRDIgPC0gaGNsdXN0KGRpc3RhbmNpYXMsIG1ldGhvZCA9ICJ3YXJkLkQyIikNCnBsb3QoaGNsdXN0X29ial9EMiwgbGFiZWxzID0gZGF0b3MkSUQsIG1haW4gPSAiRGVuZHJvZ3JhbWEiLCB4bGFiID0gIk9iamV0b3MiLCB5bGFiID0gIkRpc3RhbmNpYSIpDQpgYGANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBEaXN0YW5jaWFzIHBhcmEgZGF0b3MgbnVtw6lyaWNvcw0KDQojIyMgQmFzZSBkZSBkYXRvcw0KDQpMb3MgZGF0b3Mgc2UgcmVjb2dpZXJvbiBhcGxpY2FuZG8gdW5hIGVuY3Vlc3RhIGEgdW5hIG11ZXN0cmEgZGUgZXN0dWRpYW50ZXMgdW5pdmVyc2l0YXJpb3MuIEVzIHVuIGRhdGEgZnJhbWUgY29uIDgwMCBvYnNlcnZhY2lvbmVzIHkgNjYgdmFyaWFibGVzLiAgDQoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkYXRvc0NvbXBsZXRvIDwtIGxzbTo6c3VydmV5DQojZGF0b3NDb21wbGV0byA8LSB0ZXh0c2hhcGU6OmNvbHVtbl90b19yb3duYW1lcyhkYXQsIGxvYz0xKQ0KI2RhdG9zQ29tcGxldG8gJT4lIHJlbW92ZV9yb3duYW1lcyAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhcj0ibmFtZXMiKSAgICNsaWJyYXJ5KHRpZHl2ZXJzZSkNCmF0dGFjaChkYXRvc0NvbXBsZXRvKQ0KYGBgDQoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpuYW1lcyhkYXRvc0NvbXBsZXRvKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgU29sbyBkYXRvcyBudW3DqXJpY29zDQoNCg0KU29sbyB1dGlsaXphcmVtb3MgYWxndW5hcyB2YXJpYWJsZXMgbnVtw6lyaWNhcy4gDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KZGF0IDwtIGRhdG9zQ29tcGxldG9bLCAyMToyNF0NCm5hbWVzKGRhdCkNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmRhdCA8LSBkYXRvc0NvbXBsZXRvWywgMjE6MjRdDQpuYW1lcyhkYXQpDQpgYGANCg0KDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRWplbXBsbzogbXVlc3RyZW8NCg0KU2VsZWNjaW9uYXJlbW9zIGFsZWF0b3JpYW1lbnRlIHNvbG8gdW5hIHBhcnRlIGRlIGxvcyBkYXRvcyB0b21hbmRvIDE1IGZpbGFzIGFsIGF6YXIgZGUgbGFzIHByaW1lcmFzIDUwIGZpbGFzIGRpc3BvbmlibGVzIGVuIGVsIGNvbmp1bnRvIGRlIGRhdG9zLiBFc3RvIGxvIGhhcmVtb3MgdXRpbGl6YW5kbyBsYSBmdW5jacOzbiBgc2FtcGxlYC4gRGVzcHXDqXMsIG5vcm1hbGl6YXJlbW9zIGxvcyBkYXRvcyB1dGlsaXphbmRvIGxhIGZ1bmNpw7NuIGBzY2FsZWAuDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0Kc2V0LnNlZWQoMTIzKSAjIFNlbWlsbGENCnNzIDwtIHNhbXBsZSgxOjUwLCAxNSkgIyBUb21hbmRvIDE1IGZpbGFzIGFsZWF0b3JpYW1lbnRlDQpkZiA8LSBkYXRbc3MsIF0gIyBTdWJjb25qdW50byBkZSBsYXMgMTUgZmlsYXMNCmRmLnNjYWxlZCA8LSBzY2FsZShkZikgIyBFc3RhbmRhcml6YW5kbyBsYXMgdmFyaWFibGVzDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQpzZXQuc2VlZCgxMjMpICMgU2VtaWxsYQ0Kc3MgPC0gc2FtcGxlKDE6NTAsIDE1KSAjIFRvbWFuZG8gMTUgZmlsYXMgYWxlYXRvcmlhbWVudGUNCnNzDQpkZiA8LSBkYXRbc3MsIF0gIyBTdWJjb25qdW50byBkZSBsYXMgMTUgZmlsYXMNCmRmDQpkZi5zY2FsZWQgPC0gc2NhbGUoZGYpICMgRXN0YW5kYXJpemFuZG8gbGFzIHZhcmlhYmxlcw0KZGYuc2NhbGVkDQpgYGANCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIEZ1bmNpb25lcyB5IHBhcXVldGVzIGVuIFINCg0KSGF5IGRpdmVyc2FzIGZ1bmNpb25lcyB5IHBhcXVldGVzIGVuIFIgcXVlIHByb3BvcmNpb25hbiBvcGNpb25lcyBwYXJhIGNhbGN1bGFyIGRpc3RhbmNpYXMgZW50cmUgcGFyZXMgZGUgb2JzZXJ2YWNpb25lczoNCiAgDQogIDEuIExhIGZ1bmNpw7NuIGBkaXN0YCwgcGFydGUgZGUgbGEgYmFzZSBkZSBSIHkgZGVsIHBhcXVldGUgYHN0YXRzYCwgc2UgdXRpbGl6YSBleGNsdXNpdmFtZW50ZSBjb24gZGF0b3MgbnVtw6lyaWNvcyBjb21vIGVudHJhZGEuDQogIA0KICAyLiBMYSBmdW5jacOzbiBgZ2V0X2Rpc3RgLCBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAsIHRhbWJpw6luIHJlcXVpZXJlIGRhdG9zIG51bcOpcmljb3MgY29tbyBlbnRyYWRhLiBBIGRpZmVyZW5jaWEgZGUgbGEgZnVuY2nDs24gYGRpc3RgIGVzdMOhbmRhciwgZXN0YSBvZnJlY2Ugc29wb3J0ZSBwYXJhIG1lZGlkYXMgZGUgZGlzdGFuY2lhIGJhc2FkYXMgZW4gY29ycmVsYWNpw7NuLCBjb21vIGxvcyBtw6l0b2RvcyBgcGVhcnNvbmAsIGBrZW5kYWxsYCB5IGBzcGVhcm1hbmAuDQogIA0KICAzLiBMYSBmdW5jacOzbiBgZGFpc3lgLCBkZWwgcGFxdWV0ZSBgY2x1c3RlcmAsIGVzIGNhcGF6IGRlIG1hbmVqYXIgb3Ryb3MgdGlwb3MgZGUgdmFyaWFibGVzLCBjb21vIG5vbWluYWxlcywgb3JkaW5hbGVzIHkgYmluYXJpYXMgKGFzaW3DqXRyaWNhcykuIEVuIGVzdG9zIGNhc29zLCBhdXRvbcOhdGljYW1lbnRlIGVtcGxlYSBlbCBjb2VmaWNpZW50ZSBkZSBHb3dlciBjb21vIG3DqXRyaWNhLiBFc3RhIGVzIHVuYSBkZSBsYXMgbWVkaWRhcyBkZSBwcm94aW1pZGFkIG3DoXMgcG9wdWxhcmVzIHBhcmEgZGF0b3MgZGUgdGlwb3MgbWl4dG9zLiBQYXJhIG9idGVuZXIgbcOhcyBkZXRhbGxlcywgc2UgcHVlZGUgY29uc3VsdGFyIGxhIGRvY3VtZW50YWNpw7NuIGRlIFIgZGUgbGEgZnVuY2nDs24gYGRhaXN5YCAoYD9kYWlzeWApLg0KDQpUb2RhcyBlc3RhcyBmdW5jaW9uZXMgY2FsY3VsYW4gbGFzIGRpc3RhbmNpYXMgZW50cmUgbGFzIGZpbGFzIGRlIGxvcyBkYXRvcy4NCg0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIERpc3RhbmNpYSBldWNsaWRpYW5hDQoNClBhcmEgY2FsY3VsYXIgbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEsIHNlIHB1ZWRlIGVtcGxlYXIgbGEgZnVuY2nDs24gYGRpc3RgIGLDoXNpY2EgZGUgUiBkZSBsYSBzaWd1aWVudGUgbWFuZXJhOg0KDQpgYGB7cn0NCmRpc3QuZXVjbCA8LSBkaXN0KGRmLnNjYWxlZCwgbWV0aG9kID0gImV1Y2xpZGVhbiIpIA0KZGlzdC5ldWNsDQpgYGANCg0KRXMgcmVsZXZhbnRlIG5vdGFyIHF1ZSBsb3MgdmFsb3JlcyBwZXJtaXRpZG9zIHBhcmEgZWwgcGFyw6FtZXRybyBgbWV0aG9kYCBpbmNsdXllbiB1bm8gZGUgbG9zIHNpZ3VpZW50ZXM6IGBldWNsaWRlYW5gLCBgbWF4aW11bWAsIGBtYW5oYXR0YW5gLCBgY2FuYmVycmFgLCBgYmluYXJ5YCwgYG1pbmtvd3NraWAuDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBTZXBhcmFkb3IgLS0+DQoNCiMjIyBEaXN0YW5jaWEgZXVjbGlkaWFuYSBjb21vIG1hdHJpeg0KDQpQYXJhIGhhY2VyIG3DoXMgZsOhY2lsIGxhIHZpc3VhbGl6YWNpw7NuIGRlIGxhIGluZm9ybWFjacOzbiBkZSBkaXN0YW5jaWEgZ2VuZXJhZGEgcG9yIGxhIGZ1bmNpw7NuIGBkaXN0YCwgc2UgcHVlZGUgcmVkZWZpbmlyIGVsIHZlY3RvciBkZSBkaXN0YW5jaWEgZW4gdW5hIG1hdHJpeiB1dGlsaXphbmRvIGxhIGZ1bmNpw7NuIGBhcy5tYXRyaXhgLg0KDQpgYGB7cn0NCiMgUmVkZWZpbmllbmRvIGNvbW8gdW5hIG1hdHJpei4NCiMgU3ViY29uanVudG8gZGUgbGFzIDMgcHJpbWVyYXMgZmlsYXMgeSBjb2x1bmFzIHkgcmVkb25kZWFuZG8gbG9zIHZhbG9yZXMuIA0Kcm91bmQoYXMubWF0cml4KGRpc3QuZXVjbClbMTozLCAxOjNdLCAxKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRGlzdGFuY2lhIGV1Y2xpZGlhbmE6IGludGVycHJldGFjacOzbg0KDQoxLiBFbiBlc3RhIG1hdHJpeiwgY2FkYSB2YWxvciBpbmRpY2EgbGEgZGlzdGFuY2lhIGVudHJlIG9iamV0b3MuIA0KDQoyLiBMb3MgdmFsb3JlcyBlbiBsYSBkaWFnb25hbCBkZSBsYSBtYXRyaXogbXVlc3RyYW4gbGEgZGlzdGFuY2lhIGVudHJlIHVuIG9iamV0byB5IHPDrSBtaXNtbywgbG8gY3VhbCBzaWVtcHJlIGVzIGNlcm8uDQoNCjMuIEVuIGVzdGUgY29uanVudG8gZGUgZGF0b3MsIGxhcyBjb2x1bW5hcyByZXByZXNlbnRhbiB2YXJpYWJsZXMuIA0KDQo0LiBQb3IgbG8gdGFudG8sIHNpIGRlc2VhbW9zIGNhbGN1bGFyIGRpc3RhbmNpYXMgZW50cmUgcGFyZXMgZGUgdmFyaWFibGVzLCBwcmltZXJvIGRlYmVtb3MgY2FtYmlhciBsYSBkaXNwb3NpY2nDs24gZGUgbG9zIGRhdG9zIHBhcmEgdGVuZXIgbGFzIHZhcmlhYmxlcyBlbiBsYXMgZmlsYXMgYW50ZXMgZGUgZW1wbGVhciBsYSBmdW5jacOzbiBgZGlzdGAuIA0KDQo1LiBSZWN1ZXJkZSBxdWUsIHBhcmEgaGFjZXIgZXN0YSB0cmFuc3Bvc2ljacOzbiBkZSBkYXRvcywgdXRpbGl6YW1vcyBsYSBmdW5jacOzbiBgdGAuDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRGlzdGFuY2lhcyBiYXNhZGFzIGVuIGNvcnJlbGFjaW9uZXMNCg0KTGFzIGRpc3RhbmNpYXMgcXVlIHNlIGRlcml2YW4gZGUgY29ycmVsYWNpb25lcyBzb24gYW1wbGlhbWVudGUgZW1wbGVhZGFzIGVuIGVsIGFuw6FsaXNpcyBkZSBkYXRvcyBkZSBleHByZXNpw7NuIGdlbsOpdGljYS4gTGEgZnVuY2nDs24gYGdldF9kaXN0YCBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAgcGVybWl0ZSBjYWxjdWxhciBlc3RhcyBkaXN0YW5jaWFzLCB1dGlsaXphbmRvIG3DqXRvZG9zIGRlIGNvcnJlbGFjacOzbiBjb21vIGBwZWFyc29uYCwgYHNwZWFybWFuYCBvIGBrZW5kYWxsYC4NCg0KYGBge3J9DQojIENhbGN1bGFuZG8NCmxpYnJhcnkoImZhY3RvZXh0cmEiKQ0KZGlzdC5jb3IgPC0gZ2V0X2Rpc3QoZGYuc2NhbGVkLCBtZXRob2QgPSAicGVhcnNvbiIpDQoNCiMgTW9zdHJhbmRvIHVuIHN1YmNvbmp1bnRvDQpyb3VuZChhcy5tYXRyaXgoZGlzdC5jb3IpWzE6MywgMTozXSwgMSkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyBEaXN0YW5jaWFzIHBhcmEgZGF0b3MgbWl4dG9zDQoNCiMjIyBEYXRvcyBtaXh0b3MNCg0KDQpgYGB7ciAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRmLm1peCA8LSBkYXRvc0NvbXBsZXRvWzE6MjMsIGMoMjE6MjQsIDM2OjQwKV0NCmF0dGFjaChkZi5taXgpDQpoZWFkKGRmLm1peCw0KSANCm5hbWVzKGRmLm1peCkNCmBgYA0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUgLS0+DQo8IS0tIFNlcGFyYWRvciAtLT4NCg0KIyMjIGBTdHJ1Y3R1cmVgIGRlIGxvcyBkYXRvcyBtaXh0b3MNCg0KYGBge3J9DQojIERhdGEgc3RydWN0dXJlDQpzdHIoZGYubWl4KQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgRnVuY2nDs24gYGNsdXN0ZXI6OmRhaXN5YA0KDQpMYSBmdW5jacOzbiBgZGFpc3lgIGRlbCBwYXF1ZXRlIGBjbHVzdGVyYCBvZnJlY2UgdW5hIHNvbHVjacOzbiAobGEgbcOpdHJpY2EgZGUgR293ZXIpIHBhcmEgY2FsY3VsYXIgbGEgbWF0cml6IGRlIGRpc3RhbmNpYXMgZW4gc2l0dWFjaW9uZXMgZG9uZGUgbG9zIGRhdG9zIGNvbnRpZW5lbiBjb2x1bW5hcyBubyBudW3DqXJpY2FzLiBFbCBjw7NkaWdvIFIgYSBjb250aW51YWNpw7NuIGFwbGljYSBsYSBmdW5jacOzbiBgZGFpc3lgIGEgZGF0b3MgIHF1ZSBjb250aWVuZW4gdmFyaWFibGVzIGZhY3Rvciwgb3JkZW5hZGFzIHkgbnVtw6lyaWNhcy4NCg0KDQpgYGB7cn0NCmxpYnJhcnkoY2x1c3RlcikNCmRkIDwtIGRhaXN5KGRmLm1peCkNCnJvdW5kKGFzLm1hdHJpeChkZClbMTozLCAxOjNdLCAyKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIFZpc3VhbGl6YW5kbyBtYXRyaWNlcyBkZSBkaXN0YW5jaWENCg0KIyMjIExhIGdyw6FmaWNhDQogIA0KICAxLiBVbmEgbWFuZXJhIHNlbmNpbGxhIGRlIHJlcHJlc2VudGFyIHZpc3VhbG1lbnRlIGxhcyBtYXRyaWNlcyBkZSBkaXN0YW5jaWEgZXMgZW1wbGVhciBsYSBmdW5jacOzbiBgZnZpel9kaXN0YCBkZWwgcGFxdWV0ZSBgZmFjdG9leHRyYWAuIA0KICANCiAgMi4gVGFtYmnDqW4gc2UgcHVlZGVuIHV0aWxpemFyIG90cm9zIG3DqXRvZG9zIGVzcGVjaWFsaXphZG9zLCBjb21vIGVsICphZ3J1cGFtaWVudG8gamVyw6FycXVpY28gYWdsb21lcmF0aXZvKiAgKCphZ2dsb21lcmF0aXZlIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nKikgbyBlbCAqbWFwYSBkZSBjYWxvciogKCpoZWF0bWFwKikuIA0KDQpQYXJhIHV0aWxpemFyIGBmdml6X2Rpc3RgLCBzaW1wbGVtZW50ZSBzZSBkZWJlIGVzY3JpYmlyOiANCg0KYGBge3J9DQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpmdml6X2Rpc3QoZGlzdC5ldWNsKQ0KYGBgDQoNCjwhLS0gJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCjwhLS0gU2VwYXJhZG9yIC0tPg0KDQojIyMgSW50ZXJwcmV0YWNpw7NuDQoNCkVsIG5pdmVsIGRlIGNvbG9yIHZhcsOtYSBzZWfDum4gZWwgdmFsb3IgZGUgbGEgZGlzaW1pbGl0dWQgZW50cmUgbGFzIG9ic2VydmFjaW9uZXMgc2Vyw6E6IA0KICANCiAgMS4gUm9qbyBpbnRlbnNvIHNpICRkaXN0KHhfaSwgeF9qKSA9IDAkLiBFcyBkZWNpciwgc2kgaGF5IGFsdGEgc2ltaWxhcmlkYWQgKG8sIGJhamEgZGlzaW1pbGFyaWRhZCkuICANCiAgDQogIDIuIEF6dWwgaW50ZW5zbyBzaSAkZGlzdCh4X2ksIHhfaikgPSAxJC4gRXMgZGVjaXIsIHNpIGhheSBiYWphIHNpbWlsYXJpZGFkLiAgDQoNCkxvcyBvYmpldG9zIHBlcnRlbmVjaWVudGVzIGFsIG1pc21vIGdydXBvIHNlIG11ZXN0cmFuIGVuIG9yZGVuIGNvbnNlY3V0aXZvLg0KDQoNCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KPCEtLSBDYXDDrXR1bG8gRWplcmNpY2lvcyAtLT4NCg0KIyBFamVyY2ljaW9zDQoNClBlbmRpZW50ZQ0KDQo8IS0tICUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlIC0tPg0KDQo8IS0tIENhcMOtdHVsbyBCaWJsaW9ncmFmw61hLS0+DQoNCg0KIyBCaWJsaW9ncmFmw61hIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9DQogIA0KQ29uc3VsdGFyIGVsIGRvY3VtZW50byBbUlB1YnMgOjogQW7DoWxpc2lzIG11bHRpdmFyaWFkbyAoYmlibGlvZ3JhZsOtYSldKGh0dHBzOi8vcnB1YnMuY29tL2hsbGluYXMvUl9NdWx0aXZhcmlhZG9fQmlibGlvZ3JhZmlhKS4NCg0KPCEtLSAlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSUlJSAtLT4NCg0KJm5ic3A7DQoNCg0KJm5ic3A7DQo8Y2VudGVyPg0Kfn5+DQpJZiB5b3UgZm91bmQgYW55IEVSUk9SUyBvciBoYXZlIFNVR0dFU1RJT05TLCBwbGVhc2UgcmVwb3J0IHRoZW0gdG8gbXkgZW1haWwuIFRoYW5rcy4gIA0Kfn5+DQo8L2NlbnRlcj4NCg0KDQo=