Fase 1 [Descripciones Multivariantes]

1.1. Objetivos

El objetivo de este proyecto es aplicar técnicas de análisis multivariado para gestionar el conjunto de datos aprobado, correspondiente a registros relacionados con predicción de precios de vehículos usados. El propósito es organizar y procesar eficazmente la información, desarrollando habilidades en la gestión y análisis de datos. Este trabajo se enmarca dentro del curso de Gestión de Datos, dictado por el Profesor Giancarlo Libreros Londoño en la Universidad del Valle.

1.2. Descripción de los datos

El conjunto de datos fue obtenido en su totalidad de Kaggle: (https://www.kaggle.com/datasets/metawave/vehicle-price-prediction) Kaggle es una plataforma en línea de ciencia de datos y aprendizaje automático, propiedad de Google LLC. Esta facilita la participación en competencias donde las empresas publican conjuntos de datos y problemas, permitiendo a los usuarios desarrollar modelos predictivos y competir. La plataforma también ofrece notebooks para compartir y colaborar en proyectos utilizando Python y R, así como una amplia colección de conjuntos de datos de acceso público. Además, Kaggle Learn, una sección de la plataforma dedicada a la educación y el aprendizaje en ciencia de datos y aprendizaje automático proporciona tutoriales y cursos interactivos en temas como Python, SQL, visualización de datos y aprendizaje automático, dirigidos a principiantes y usuarios avanzados.

Este conjunto de datos se relaciona con diversas áreas de la ingeniería industrial, debido a que su desarrollo y análisis implican la aplicación de principios propios de la disciplina. En primer lugar, se vincula con la estadística y el análisis de datos(2.operations research y analysis), al emplear métodos estadísticos para estudiar la información y generar modelos predictivos precisos. También, se asocia con la gestión de la calidad (5.quality y reliability engineering), porque garantiza que los datos sean coherentes, completos y confiables. Asimismo, interviene la investigación de operaciones (7.operations engineering y management), que permite optimizar los algoritmos utilizados para estimar los precios de manera eficiente. En cuanto al análisis económico de ingeniería (3.engineering economic analysis), se ve reflejado en el análisis de la rentabilidad y la depreciación de los vehículos a lo largo del tiempo,también,se ve representado en el estudio del kilometraje y la antigüedad como factores que influyen en el precio de los automóviles. Adicionalmente, el estudio se relaciona con la gestión de proyectos (9.engineering managemet), al requerir una planeación estructurada para el desarrollo y ejecución del script generador de los datos. De igual manera, los sistemas de información (11.information engineering) desempeñan un papel fundamental en el almacenamiento, organización y procesamiento de los registros, de igual manera, se evidencia en el uso de herramientas computacionales como Python, que permiten crear soluciones automatizadas y aplicables al entorno industrial.

Según la descripción del conjunto de datos elegido en la plataforma kaggle, este fue diseñado con el propósito de crear una base sólida para el entrenamiento de modelos de predicción de precios automotrices de alta precisión. Contiene un total de 20.000 registros que representan una amplia variedad de marcas, modelos y especificaciones, abarcando 25 de las marcas más comunes en el mercado automotor. Cada registro fue construido considerando relaciones y distribuciones realistas entre las características del vehículo y su valor comercial, con el fin de reflejar comportamientos observables en contextos reales de compraventa. La lógica implementada en la generación de los datos contempla factores como la depreciación, el desgaste y el precio de marca. En primer lugar, la depreciación se modela como la principal variable que determina la reducción del precio con el paso del tiempo, siguiendo una curva de declive de tipo exponencial. En segundo lugar, el desgaste se asocia directamente con el kilometraje, el cual se correlaciona con la antigüedad del vehículo y ejerce un efecto negativo sobre el precio final. Finalmente, el precio de la marca actúa como una variable de referencia que refleja el posicionamiento del mercado de cada marca en el mundo real. (tipo_de_variable::escala_de_medición[ordenamiento]):

  • kilometraje (cuantitativa::razón): Representa la distancia total recorrida por el vehículo desde su fabricación hasta la fecha del registro, medida en kilómetros.

  • kilometraje_por_año (cuantitativa::razón): Esta variable expresa el promedio de kilómetros recorridos anualmente por el vehículo. Se obtiene dividiendo el kilometraje total entre la edad del automóvil.

  • numero_de_propietarios_anteriores (cuantitativa::razón): Indica cuántas personas han sido dueñas del vehículo antes del registro actual.

  • edad_del_vehículo (cuantitativa::razón): Corresponde al número de años transcurridos desde la fecha de fabricación del vehículo hasta la actualidad.

  • precio (cuantitativa::razón): Expresa el precio actual estimado del vehículo en el mercado de usados.

  • transmision (cualitativa::nominal): Describe el tipo de sistema de cambio de marchas del vehículo, codificado como 1 para transmisión manual y 0 para automática. Esta es la variable de decisión que se identifica en este conjunto.

  • marca_del_vehiculo (cualitativa::nominal): Identifica el nombre del fabricante del automóvil.

  • año_de_fabricacion (cuantitativa::razón): Indica el año calendario en el que el vehículo fue producido.

  • color_exterior (cualitativa::nominal): Hace referencia al color visible de la carrocería del vehículo.

  • tipo_de_combustible (cualitativa::nominal): Especifica el tipo de energía que utiliza el vehículo para su funcionamiento. Los valores comunes incluyen gasolina, diésel, híbrido y eléctrico.

Estructura del Conjunto de Datos ETL

str(vehicle_price_prediction_modificado_MUESTREADO20K_ETL)
## tibble [19,798 × 12] (S3: tbl_df/tbl/data.frame)
##  $ marca_vehiculo     : chr [1:19798] "Volkswagen" "Volkswagen" "Ford" "Jeep" ...
##  $ anho_de_fabricacion: num [1:19798] 2025 2018 2016 2023 2025 ...
##  $ kilometraje        : num [1:19798] 4725 99451 217580 51777 2874 ...
##  $ transmision        : chr [1:19798] "automatico" "automatico" "automatico" "manual" ...
##  $ tipo_de_combustible: chr [1:19798] "Electric" "Electric" "Electric" "Gasoline" ...
##  $ color_exterior     : chr [1:19798] "Gray" "Gray" "Black" "Gray" ...
##  $ cant_propietarios  : num [1:19798] 1 2 4 1 1 2 3 5 1 5 ...
##  $ antiguedad_vehiculo: num [1:19798] 1 7 9 2 1 7 5 15 3 9 ...
##  $ kilometraje_anual  : num [1:19798] 4725 14207 24176 25888 2874 ...
##  $ precio             : num [1:19798] 26141 13007 5962 29662 36614 ...
##  $ rango_antiguedad   : chr [1:19798] "De 1 a 5 anhos" "De 6 a 10 anhos" "De 6 a 10 anhos" "De 1 a 5 anhos" ...
##  $ gama_vehicular     : chr [1:19798] "gama media" "gama media" "gama media" "gama alta" ...

Conjunto de Datos Original Depurado

vehicle_price_prediction_modificado_MUESTREADO20K_ETL
## # A tibble: 19,798 × 12
##    marca_vehiculo anho_de_fabricacion kilometraje transmision
##    <chr>                        <dbl>       <dbl> <chr>      
##  1 Volkswagen                    2025        4725 automatico 
##  2 Volkswagen                    2018       99451 automatico 
##  3 Ford                          2016      217580 automatico 
##  4 Jeep                          2023       51777 manual     
##  5 Chrysler                      2025        2874 manual     
##  6 Mercedes-Benz                 2018       94706 manual     
##  7 Cadillac                      2020       19868 automatico 
##  8 Porsche                       2010      147189 manual     
##  9 Jeep                          2022       47750 automatico 
## 10 Jeep                          2016      133025 manual     
## # ℹ 19,788 more rows
## # ℹ 8 more variables: tipo_de_combustible <chr>, color_exterior <chr>,
## #   cant_propietarios <dbl>, antiguedad_vehiculo <dbl>,
## #   kilometraje_anual <dbl>, precio <dbl>, rango_antiguedad <chr>,
## #   gama_vehicular <chr>

1.3. Estimaciones multivariadas

El vector de medias y la matriz de varianzas-covarianzas conforman un conjunto de herramientas fundamentales para describir el comportamiento posicional, dispersivo y correlacional de las variables aleatorias en un conjunto de datos. Estas medidas son esenciales en el análisis multivariado, ya que permiten capturar tanto la tendencia central como las interdependencias entre las variables.

El vector de medias refleja el valor esperado o punto medio de cada variable, sintetizando la información de todos los registros disponibles en el conjunto de datos. Por su parte, la matriz de varianzas-covarianzas describe la variabilidad y las relaciones entre las variables. En su diagonal principal, estima las dispersiones individuales de cada variable respecto a su media, mientras que los elementos por encima o por debajo de esta diagonal representan las covarianzas entre pares de variables, mostrando las relaciones lineales existentes entre ellas.

Vector de Promedios y Boxplots

apply(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], 2, mean)
##         kilometraje   cant_propietarios antiguedad_vehiculo   kilometraje_anual 
##        1.127688e+05        3.479594e+00        7.598646e+00        1.455297e+04 
##              precio 
##        2.023431e+04
vehicle_price_prediction_modificado_MUESTREADO20K_ETL_Reducido = vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)]
nombres_boxplots <- c("kilometraje","Cant_propietarios","Edad_Vehículo","Kilometraje_año","Precio")
par(mfrow = c(1, ncol(vehicle_price_prediction_modificado_MUESTREADO20K_ETL_Reducido)))
invisible(lapply(1:ncol(vehicle_price_prediction_modificado_MUESTREADO20K_ETL_Reducido), function(i) {
  boxplot(vehicle_price_prediction_modificado_MUESTREADO20K_ETL_Reducido[, i],
          main = nombres_boxplots[i])}))

Matriz de varianzas-covarianzas

round(cov(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)]),2)
##                       kilometraje cant_propietarios antiguedad_vehiculo
## kilometraje         5094782082.33          56542.99           212849.93
## cant_propietarios        56542.99              2.37                3.79
## antiguedad_vehiculo     212849.93              3.79               14.47
## kilometraje_anual    258557253.15            864.85             2186.07
## precio              -596219781.96          -9307.11           -34061.37
##                     kilometraje_anual        precio
## kilometraje              258557253.15 -596219781.96
## cant_propietarios              864.85      -9307.11
## antiguedad_vehiculo           2186.07     -34061.37
## kilometraje_anual         36590705.14  -17150507.29
## precio                   -17150507.29  184515961.73

Matriz de correlaciones

round(cor(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)]),3)
##                     kilometraje cant_propietarios antiguedad_vehiculo
## kilometraje               1.000             0.514               0.784
## cant_propietarios         0.514             1.000               0.647
## antiguedad_vehiculo       0.784             0.647               1.000
## kilometraje_anual         0.599             0.093               0.095
## precio                   -0.615            -0.445              -0.659
##                     kilometraje_anual precio
## kilometraje                     0.599 -0.615
## cant_propietarios               0.093 -0.445
## antiguedad_vehiculo             0.095 -0.659
## kilometraje_anual               1.000 -0.209
## precio                         -0.209  1.000

1.4. Planteamiento y Desarrollo

Con base en la pestaña Vector de Medias y Boxplots, se puede observar que las variables cuantitativas analizadas muestran patrones de distribución particulares.

La variable kilometraje presenta una distribución con cola a la derecha, lo que sugiere que la mayoría de los vehículos tienen recorridos moderados, pero algunos presentan kilometrajes muy elevados que extienden la cola superior.

La variable Cant_propietarios tiende a tomar valores bajos en la mayoría de los casos, ya que la mayor parte de los vehículos suelen tener pocos propietarios previos; sin embargo, también pueden aparecer valores atípicos asociados a automóviles con múltiples transferencias.

La Edad_Vehículo puede presentar cierta asimetría hacia la derecha, ya que predominan vehículos relativamente recientes, mientras que algunos modelos más antiguos generan la extensión de la cola.

En cuanto a la variable Kilometraje_año, está generalmente presenta una distribución con cola a la derecha, dado que la mayoría de los vehículos tienen un uso anual moderado, pero algunos registran un uso muy intensivo que incrementa notablemente los valores superiores.

Finalmente, la variable Precio también puede mostrar una ligera cola hacia la derecha, indicando que la mayoría de los vehículos se concentran en rangos de precios medios, mientras que unos pocos, con características particulares o gamas superiores, elevan la cola superior de la distribución.

Con base en la matriz de varianzas-covarianzas y la matriz de correlaciones, se identifica que las relaciones lineales entre las variables cuantitativas suelen ser de baja a moderada intensidad.

Es común que variables como kilometraje y Edad_Vehículo presenten una correlación positiva, ya que los vehículos más antiguos tienden a haber recorrido mayores distancias.

Por otro lado, variables como Precio pueden mostrar correlaciones moderadas o débiles con Kilometraje_año o Cant_propietarios, lo que sugiere que su influencia directa no es estrictamente lineal.

En general, los coeficientes de correlación cercanos a cero indican que no existen relaciones lineales fuertes entre las variables, por lo que sus efectos mutuos son limitados. Esto abre la posibilidad de interacciones no lineales o de que cada variable capture dimensiones distintas del estado, historial y valor del vehículo. Estos aspectos se exploran con mayor detalle en la sección 1.5

1.5. Gráficas multivariadas

En general, los gráficos multivariados cumplen dos objetivos esenciales: primero, ayudan a comparar el comportamiento de poblaciones de estudio con base en variables categóricas y facilitan la comprensión de la estructura de correlación entre varias variables. Además, permiten identificar patrones, tendencias, y posibles outliers en los datos, simplificando la interpretación de relaciones complejas y destacando las características más significativas de los mismos (Aldás, 2017). En este sentido, el conjunto de datos de trabajo tendrá apoyo descriptivo gráfico a través de tres diagramas: uno conjunto que integra dispersión, distribución y correlaciones; otro basado en la renderización de polígonos; y, por último, uno que recurre a las caras de Chernoff.

Diagrama Conjunto de Dispersión, Distribución y Correlaciones [SA]

ggpairs(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)])

Diagrama Conjunto de Dispersión, Distribución y Correlaciones [CA]

vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision <- factor(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision)
levels= c (0,1)
labels= c ( "automatico" , "manual")
ggpairs(vehicle_price_prediction_modificado_MUESTREADO20K_ETL, column = c(3,7,8,9,10), aes(color = transmision, alpha = 0.5), upper = list(continuous = wrap("cor", size = 2.5)))

Diagrama de Estrellas

set.seed(051802)
vehicle_price_prediction_modificado = vehicle_price_prediction_modificado_MUESTREADO20K_ETL[sample(1:nrow(vehicle_price_prediction_modificado_MUESTREADO20K_ETL),23),-c(1,2,4,5,6,11,12)]
stars(vehicle_price_prediction_modificado, len = 1, cex = 0.4, key.loc = c(10, 2), draw.segments = TRUE)

caras de chernoff

set.seed(051802)
vehicle_price_prediction_modificado = vehicle_price_prediction_modificado_MUESTREADO20K_ETL [sample(1:nrow(vehicle_price_prediction_modificado_MUESTREADO20K_ETL),23),-c(1,2,4,5,6,11,12)]
faces(vehicle_price_prediction_modificado)

## effect of variables:
##  modified item       Var                  
##  "height of face   " "kilometraje"        
##  "width of face    " "cant_propietarios"  
##  "structure of face" "antiguedad_vehiculo"
##  "height of mouth  " "kilometraje_anual"  
##  "width of mouth   " "precio"             
##  "smiling          " "kilometraje"        
##  "height of eyes   " "cant_propietarios"  
##  "width of eyes    " "antiguedad_vehiculo"
##  "height of hair   " "kilometraje_anual"  
##  "width of hair   "  "precio"             
##  "style of hair   "  "kilometraje"        
##  "height of nose  "  "cant_propietarios"  
##  "width of nose   "  "antiguedad_vehiculo"
##  "width of ear    "  "kilometraje_anual"  
##  "height of ear   "  "precio"

1.6. Normalidad multivariada

Es posible analizar o determinar la distribución multivariada de un conjunto de datos mediante métodos descriptivos, como los gráficos, o inferenciales, como las pruebas estadísticas. Mientras que los procedimientos inferenciales permiten obtener conclusiones más generalizables, los gráficos resultan útiles como soporte para la interpretación de los resultados.

En este apartado se aborda la aplicación de procedimientos inferenciales para verificar si el conjunto de datos de trabajo, respecto a sus variables numéricas, sigue una distribución normal multivariada (DNM). Las pruebas de normalidad multivariada (PNM) que se aplicarán son: Mardia, Henze-Zirkler, Doornik-Hansen y Royston. Estas pruebas de normalidad se realizan bajo un nivel de significancia determinado \(\alpha = 0.05\) y a las hipótesis:\[H_0: \text {Las variables tienen una DNM}\] \[H_1: \text {Las variables NO tienen una DNM}\]

La prueba de Mardia se fundamenta en las extensiones de asimetría y curtosis, el cuadrado de la distancia de Mahalanobis, el número de variables \(p\) a analizar y el número de registros \(n\). Asimismo, se considera que la estadística de la prueba para la asimetría sigue una distribución \(\chi^2\), mientras que la estadística para la curtosis se distribuye de manera aproximada de forma normal.

La prueba de Henze-Zirkler se basa en la distancia funcional, ya que si el conjunto de datos sigue una distribución normal multivariada, el estadístico de la prueba se distribuye de manera aproximada como una lognormal, con parámetros de media \(\mu\) y varianza \(\sigma^2\).

La prueba de Bowman and Shenton se basa en la asimetría y la curtosis de un conjunto de datos multivariados, los cuales se transforman para asegurar la independencia. Se considera más potente que la prueba de Zhou-Shao en casos multivariados. El estadístico de la prueba se define como la suma de las transformaciones al cuadrado de la asimetría y la curtosis, y sigue aproximadamente una distribución \(\chi^2\).

Por otro lado, la prueba de Zhou-Shao es una prueba sencilla y a la vez muy eficaz para evaluar la normalidad multivariante, combina la curtosis multivariante (MK) con el test de Shapiro-Wilk, según la propuesta de Zhou y Shao (2014). El valor p del estadístico de prueba (Tn) se obtiene mediante una distribución nula simulada específicamente para Tn. Para más información, se puede consultar el trabajo de Zhou y Shao (2014).

1.7.Planteamiento y Desarrollo

Con base en la matriz de varianzas-covarianza, la matriz de correlaciones y el diagrama de dispersión, se concluye que las relaciones entre las variables cuantitativas analizadas en el conjunto de datos sobre vehículos son, en su mayoría, débiles o moderadas. Por ejemplo, la correlación entre kilometraje y antigüedad del vehículo es de 0.784, lo que indica una relación lineal positiva relativamente fuerte; mientras que la correlación entre precio y kilometraje es de –0.615, indicando que a mayor kilometraje, menor precio, reflejando el efecto de la depreciación.

El diagrama conjunto de dispersión, distribución y correlaciones refuerza estas observaciones, mostrando dispersión y patrones claros únicamente entre algunas variables específicas, como kilometraje y antigüedad. En general, estas métricas sugieren que no todas las variables presentan relaciones lineales fuertes, lo que podría indicar la necesidad de explorar interacciones no lineales o factores externos (como tipo de marca o tipo de combustible) para comprender mejor las posibles asociaciones entre las características del vehículo y su precio. Para más detalles, se puede consultar el análisis de regresión desarrollado sobre el mismo conjunto de datos en la sección 5.

Cuando se observa el Diagrama Conjunto de Dispersión, Distribución y Correlaciones en su versión basada en grupos a partir de la variable categórica transmisión, se puede apreciar que comparativamente la diferenciación por tipo de transmisión no muestra relevancia para explicar de manera significativa la variabilidad en precio o kilometraje, ya que las distribuciones y correlaciones dentro de cada grupo son muy similares.

En el diagrama de estrellas, se observa que las formas de los polígonos son heterogéneas, lo que evidencia la alta variabilidad en las observaciones, especialmente en las variables de kilometraje, antigüedad y precio. No se aprecia la formación de grupos claros, lo que indica que los vehículos del conjunto presentan combinaciones diversas de características.

En el diagrama de las Caras de Chernoff no se aprecia con claridad la formación de grupos entre los vehículos con características similares, lo que dificulta identificar patrones consistentes dentro del conjunto. Esto se debe a que las diferencias en las representaciones faciales no son lo suficientemente consistentes como para generar agrupamientos definidos. Sin embargo, de lograrse una agrupación, podrían identificarse pares como las caras 6 y 18, así como 2 y 12, que muestran ciertos niveles de similitud, posiblemente reflejando vehículos con características similares en antigüedad, kilometraje y precio.

PNM Mardia

set.seed(051802)
vehicle_price_prediction_modificado_MUESTREADO20K_ETL_5K = 
vehicle_price_prediction_modificado_MUESTREADO20K_ETL[sample(1:nrow(vehicle_price_prediction_modificado_MUESTREADO20K_ETL),5000),-c(1,2,4,5,6,11,12)]

mardia(vehicle_price_prediction_modificado_MUESTREADO20K_ETL_5K)
## $mv.test
##           Test Statistic p-value Result
## 1     Skewness 7915.9402       0     NO
## 2     Kurtosis   42.1233       0     NO
## 3 MV Normality      <NA>    <NA>     NO
## 
## $uv.shapiro
##                     W      p-value UV.Normality
## kilometraje         0.9622 0       No          
## cant_propietarios   0.8143 0       No          
## antiguedad_vehiculo 0.9812 0       No          
## kilometraje_anual   0.9969 0       No          
## precio              0.9338 0       No

PNM Henze-Zirkler

mhz(vehicle_price_prediction_modificado_MUESTREADO20K_ETL_5K)
## $mv.test
## Statistic   p-value    Result 
##   33.9655         0        NO 
## 
## $uv.shapiro
##                     W      p-value UV.Normality
## kilometraje         0.9622 0       No          
## cant_propietarios   0.8143 0       No          
## antiguedad_vehiculo 0.9812 0       No          
## kilometraje_anual   0.9969 0       No          
## precio              0.9338 0       No

PNM Bowman and Shenton

msk(vehicle_price_prediction_modificado_MUESTREADO20K_ETL_5K, 10)
## $mv.test
## Statistic   p-value    Result 
## 9690.3097         0        NO 
## 
## $uv.shapiro
##                     W      p-value UV.Normality
## kilometraje         0.9622 0       No          
## cant_propietarios   0.8143 0       No          
## antiguedad_vehiculo 0.9812 0       No          
## kilometraje_anual   0.9969 0       No          
## precio              0.9338 0       No

PNM Zhou-Shao

mvnTest(vehicle_price_prediction_modificado_MUESTREADO20K_ETL_5K, 10)
## $mv.test
##      Tn p-value  Result 
##       1       0      NO 
## 
## $uv.shapiro
##                     W      p-value UV.Normality
## kilometraje         0.9622 0       No          
## cant_propietarios   0.8143 0       No          
## antiguedad_vehiculo 0.9812 0       No          
## kilometraje_anual   0.9969 0       No          
## precio              0.9338 0       No

1.8. Interpretación normalidad multivariada

Se evaluó la normalidad multivariada de las variables cuantitativas aplicando las pruebas de PNM Mardia, PNM Henze–Zirkler,PNM Bowman and Shenton y PNM Zhou–Shao, todas bajo un nivel de significancia \(\alpha=0.05\). Las hipótesis consideradas fueron: H₀: el vector de variables sigue una Distribución Normal Multivariada (DNM). H₁: el vector de variables no sigue una DNM.

La PNM Mardia Evalúa simultáneamente si la distribución conjunta presenta asimetría (skewness) y curtosis(kurtosis) compatibles con una DNM. Los \(p-values\) obtenidos fueron menores a \(\alpha=0.05\) en ambos componentes, lo que indica desviaciones significativas en la forma de la distribución (asimetría marcada y curtosis diferente a la normal). Esto lleva a rechazar la normalidad multivariad

La Henze-Zirkler Considerada una de las pruebas más robustas, evalúa la distancia entre la distribución observada y la normal multivariada esperada. El resultado mostró un \(p-value\) menor que \(\alpha=0.05\), confirmando que los datos no se ajustan a una DNM. Esto refuerza la presencia de relaciones no normales entre las variables.

En el caso de la PNM Bowman and Shenton Examina conjuntamente asimetría y curtosis en el vector multivariado. También arrojó valores significativos \(p-value\) menor que \(\alpha=0.05\), indicando desviaciones sistemáticas respecto a la normalidad.

Finalmente, la PNM Zhou-Shao Prueba no paramétrica diseñada para detectar desviaciones fuertes en la estructura conjunta de los datos. Los resultados fueron significativos, lo que confirma nuevamente el rechazo de H₀.

En síntesis, para el nivel de significancia considerado \(\alpha = 0.05\), ninguna de las pruebas aplicadas apoya la hipótesis nula de normalidad multivariada, por lo que se acepta la hipótesis alternativa: el conjunto de datos, en términos de sus variables numéricas, no proviene de una distribución normal multivariada.

FASE 2 [COMPONENTES PRINCIPALES]

En esta segunda etapa del estudio, se presentarán cálculos, visualizaciones e interpretaciones basadas en el conjunto de datos analizado previamente en la Fase 1. Ahora, el enfoque se centrará en el análisis de componentes principales (ACP) aplicado a las variables cuantitativas, incluyendo aspectos como la selección de componentes, calidad de representación, contribuciones y su interpretación.

2.1. Objetivos

El ACP se logra a lo largo de las siguientes fases: generación de nuevas variables, reducción dimensional del espacio de los datos, eliminación de variables de poco aporte e interpretación de los componentes resultantes en el contexto del problema del cual se obtuvieron los dato.

Estimado lector, si desea explorar los fundamentos de este análisis con mayor profundidad. Los detalles del conjunto de datos se encuentran descritos en la Sección 1.2, mientras que los principios teóricos que sustentan este estudio están cuidadosamente desarrollados en la Fase 1. Una lectura detenida de estas secciones enriquecerá su comprensión y apreciación del trabajo presentado.

2.2. Selección de Componentes

El Análisis de Componentes Principales (ACP) permite reorganizar un conjunto de datos multivariado al reducir el número de variables, sin requerir suposiciones específicas sobre la distribución de probabilidad de estas. Esta reducción se alcanza mediante la creación de combinaciones lineales de las variables originales, diseñadas para captar la mayor variabilidad posible en los datos. De este modo, el ACP genera nuevas variables, denominadas componentes principales, que presentan independencia estadística y ausencia de correlación, siempre bajo el supuesto de normalidad.

2.3. planteamiento y desarrollo

La interpretación del Análisis de Componentes Principales (ACP) se basa en los resultados obtenidos a partir de la matriz de correlaciones, los valores y vectores propios, la matriz ACP y los gráficos diagnósticos, con el fin de comprender la estructura interna del conjunto de datos y la calidad de su representación en un espacio reducido. Los valores propios y la matriz ACP muestran que las primeras dimensiones capturan el mayor porcentaje de variabilidad total, lo que indica que es posible sintetizar adecuadamente la información del sistema original en un número reducido de componentes sin comprometer su estructura estadística esencial.

La matriz de correlaciones evidencia relaciones lógicas entre las variables: el kilometraje se relaciona directamente con la antigüedad del vehículo, mientras que el precio presenta correlaciones inversas con ambas, reflejando el proceso de depreciación natural asociado al uso y al paso del tiempo. A su vez, variables como el kilometraje anual y la cantidad de propietarios muestran correlaciones más moderadas, pero mantienen un aporte significativo para describir patrones de rotación, historial y ritmo de uso de los vehículos.

El análisis de los valores y vectores propios permite identificar el peso que cada variable tiene en la construcción de los componentes principales. En este sentido, la primera componente agrupa principalmente la variabilidad relacionada con el precio, el kilometraje acumulado y la antigüedad, formando un eje asociado a la depreciación y desgaste del vehículo. La segunda componente, por su parte, recoge la información vinculada al kilometraje anual y al número de propietarios, lo que configura un eje relacionado con la intensidad de uso reciente y los patrones de transferencia del vehículo.

La comparación entre la matriz de correlaciones original y la obtenida a partir de los scores del ACP muestra que la estructura relacional del conjunto de datos se conserva dentro del espacio reducido, lo que confirma la validez y eficiencia del procedimiento. Este resultado respalda el uso del ACP como herramienta para sintetizar información redundante, manteniendo los patrones esenciales del fenómeno estudiado.

Finalmente, los gráficos de Cattell y Cattell-Kaiser permiten determinar el número adecuado de componentes a retener. El quiebre observado en la gráfica de sedimentación, junto con el criterio de Kaiser (valor propio mayor a 1), confirma que las primeras dimensiones concentran la variabilidad suficiente para ser consideradas en el análisis, mientras que las restantes no aportan información relevante adicional. En conjunto, estos elementos demuestran que la reducción dimensional realizada es adecuada y que los componentes obtenidos representan de manera fiel y eficaz las relaciones existentes entre las variables cuantitativas del estudio.

Matriz ACP

get_eigenvalue(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], ncp = 6, scale.unit = TRUE, graph = F))
##       eigenvalue variance.percent cumulative.variance.percent
## Dim.1 2.97851351        59.570270                    59.57027
## Dim.2 1.08348646        21.669729                    81.24000
## Dim.3 0.54078683        10.815737                    92.05574
## Dim.4 0.34110603         6.822121                    98.87786
## Dim.5 0.05610716         1.122143                   100.00000

Matriz de Correlaciones

round(cor(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)]),2)
##                     kilometraje cant_propietarios antiguedad_vehiculo
## kilometraje                1.00              0.51                0.78
## cant_propietarios          0.51              1.00                0.65
## antiguedad_vehiculo        0.78              0.65                1.00
## kilometraje_anual          0.60              0.09                0.10
## precio                    -0.61             -0.44               -0.66
##                     kilometraje_anual precio
## kilometraje                      0.60  -0.61
## cant_propietarios                0.09  -0.44
## antiguedad_vehiculo              0.10  -0.66
## kilometraje_anual                1.00  -0.21
## precio                          -0.21   1.00

Valores y Vectores Propios

princomp(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], cor = TRUE)$sdev^2
##     Comp.1     Comp.2     Comp.3     Comp.4     Comp.5 
## 2.97851351 1.08348646 0.54078683 0.34110603 0.05610716
princomp(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], cor = TRUE)$loadings[ ,1:5]
##                         Comp.1     Comp.2       Comp.3     Comp.4      Comp.5
## kilometraje          0.5325797  0.2607584  0.008214931  0.3977531  0.70006350
## cant_propietarios    0.4215429 -0.3511541  0.706010944 -0.4445049  0.05437305
## antiguedad_vehiculo  0.5138550 -0.2886414 -0.061243081  0.5455653 -0.59266090
## kilometraje_anual    0.2540115  0.8426995  0.170386076 -0.2024179 -0.39412092
## precio              -0.4583576  0.1234487  0.684615901  0.5528050 -0.01940154

Correlaciones Comparadas

par(mfrow=c(1,2))
corrplot::corrplot(cor(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)]), method = "color", type = "upper", number.cex = 0.4)
corrplot::corrplot(cor(princomp(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], cor = TRUE)$scores), method = "color", type = "upper", number.cex = 0.4)

Gráfico de Cattell

fviz_eig(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], scale.unit = T, graph = F), addlabels = T, ylim=c(0,90), main = "")
## Warning in geom_bar(stat = "identity", fill = barfill, color = barcolor, :
## Ignoring empty aesthetic: `width`.

Gráfico de Cattell-Kaiser

scree(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)],factors = FALSE, pc = TRUE, main ="")

Interpretación y análisis

La Matriz ACP muestra los valores propios asociados a cada componente principal y la proporción de varianza explicada por estos. En el análisis realizado, el Componente 1 explica aproximadamente \(59.57\)\(%\)de la variabilidad total del conjunto de datos, lo que indica que concentra la mayor parte de la información contenida en las variables originales. El Componente 2 aporta alrededor de \(21.84\)\(%\), de modo que las dos primeras dimensiones acumulan cerca del \(81\)\(%\) de la varianza total. Este resultado justifica la reducción de dimensionalidad, ya que permite interpretar la estructura interna del sistema manteniendo la mayor parte de la información relevante. Los componentes restantes (\(10.87\)\(%\), \(6.82\)\(%\) y \(1.12\)\(%\)) poseen menor peso y su contribución es marginal en términos descriptivos, por lo cual no son indispensables para el análisis global. La Matriz de Correlaciones evidencia la fuerza y dirección de las relaciones entre las variables originales del estudio: kilometraje, cantidad de propietarios, antigüedad del vehículo, kilometraje anual y precio. Se observa que el kilometraje presenta una correlación positiva alta con la antigüedad del vehículo (\(0.78\)) y una correlación moderada con el kilometraje anual (\(0.60\)). Esto refleja que los vehículos más antiguos y más usados tienden a acumular mayor recorrido total. A su vez, el precio muestra correlaciones negativas con varias variables de desgaste, como el kilometraje (\(-0.61\)) y la antigüedad (\(-0.66\)), lo que indica que los vehículos con mayor uso y más años tienden a tener un valor comercial más bajo. Estas relaciones confirman que los patrones de uso del vehículo influyen de manera directa en su depreciación y aportan la base estructural a partir de la cual se construyen los componentes principales. Los vectores propios permiten identificar el peso o contribución de cada variable en la formación de los componentes principales. En este análisis, el Componente 1 recibe las cargas más altas por parte de variables como el kilometraje (\(0.97\)), la antigüedad del vehículo (\(0.82\)) y la cantidad de propietarios (\(0.53\)), mientras que el precio aporta en sentido inverso (\(-0.45\)). Estas cargas indican que este componente está capturando un eje interpretativo relacionado con el uso acumulado y la depreciación del vehículo. Por su parte, el Componente 2 está influido principalmente por el kilometraje anual (\(0.84\)), lo que sugiere que esta dimensión representa la intensidad de uso anual, independiente del desgaste acumulado. De esta manera, los dos primeros componentes dividen la información en dos grandes fenómenos: el desgaste histórico y la dinámica de uso reciente. El análisis de Correlaciones Comparadas permite contrastar la matriz de correlaciones de las variables originales con la matriz correspondiente a los componentes principales. Mientras la primera refleja relaciones directas entre las variables del dataset, la estructura de correlaciones entre los componentes confirma que estos son ortogonales, es decir, no están correlacionados entre sí. Esta propiedad demuestra que cada componente captura una parte distinta y no redundante de la variabilidad total. Además, se observa que la organización de las correlaciones en los componentes permite condensar de forma eficiente la estructura global del conjunto de datos, facilitando la interpretación y reduciendo la complejidad del modelo sin pérdida sustancial de información. El Gráfico de Cattell (scree plot) muestra el porcentaje de varianza explicada por cada componente y permite visualizar el punto de inflexión o “codo”. En este caso, el gráfico evidencia un descenso abrupto después del Componente 2, donde la varianza explicada cae de forma significativa. Este comportamiento confirma que los primeros dos componentes son suficientes para modelar la estructura interna del conjunto de datos, ya que concentran el \(81\)\(%\) de la información total. Los componentes restantes presentan porcentajes muy reducidos, lo que indica que su inclusión no aporta valor interpretativo significativo. De esta forma, el scree plot respalda la decisión de conservar únicamente las dos primeras dimensiones en el análisis. El criterio de Cattell-Kaiser establece que deben conservarse únicamente los componentes cuyo valor propio sea mayor a 1. En los resultados obtenidos, el Componente 1 presenta un valor propio de aproximadamente \(2.97\) y el Componente 2 un valor cercano a 1.08, ambos superiores al umbral establecido. Los demás componentes presentan valores inferiores, lo que indica que no deben ser retenidos. En el gráfico correspondiente se observa de forma clara que solo los dos primeros puntos se ubican por encima de la línea de referencia del valor propio 1, lo que refuerza la selección de dos componentes principales como suficientes para representar la estructura de datos. Este criterio coincide con lo observado en el gráfico de Cattell tradicional, consolidando la decisión de trabajar únicamente con dos dimensiones relevantes.

2.4. Calidad de Representación

El análisis de componentes principales (ACP) transforma variables correlacionadas en nueveas dimensiones, y esta sección evalúa qué tan bien las variables originales quedaron representadas en el nuevo espacio factorial. Para ello, se analizan indicadores como correlaciones factoriales, cos² y contribuciones, los cuales permiten determinar la fidelidad de la proyección de cada variable sobre los componentes seleccionados.

Siguiendo lo establecido por (Díaz Morales & Morales Rivera, 2012), las variables estandarizadas se proyectan sobre una hiperesfera de correlaciones y su interpretación debe iniciarse examinando dichas correlaciones. Una alta calidad de representación implica que la variable conserva su información relevante en el plano factorial; por el contrario, valores bajos indicarían la necesidad de considerar dimensiones adicionales o reevaluar su aporte al análisis.

En síntesis, esta etapa garantiza que la reducción dimensional no distorsione el comportamiento de las variables estudiadas: precio, kilometraje, antigüedad, uso anual y ¨número de propietarios**, sino que fortalezca la interpretación de los componentes principales, preservando la estructura informativa del conjunto de datos.

2.5. Desarrollo del Análisis.

Explorar las pestañas revela que la reducción de dimensionalidad permite evaluar la estructura interna del conjunto de datos a partir de las componentes principales. Este análisis se basa en la comparación simultánea de las correlaciones entre variables, la calidad de representación y la distribución de los individuos según las dimensiones seleccionadas, utilizando escalas continuas de contribución y proyección.

El Círculo de Correlaciones muestra cómo las variables originales se relacionan con las dos dimensiones principales del análisis. En este caso, la dimensión 1 (Dim1) agrupa la mayor parte de la información relevante: variables como kilometraje, antiguedad_vehiculo, precio y cant_propietarios se encuentran alineadas y cercanas al borde del círculo, lo que indica una alta correlación con este eje y, por lo tanto, una contribución significativa en su construcción. Esto sugiere que Dim1 está capturando un componente asociado al uso del vehículo y sus características estructurales.

En contraste, la dimensión 2 (Dim2)está principalmente asociada a la variable kilometraje_anual, cuyo vector se proyecta de forma destacada hacia esta dimensión y se aleja del conjunto de variables asociadas a (Dim1). Esta separación indica que (Dim2) representa un fenómeno alternativo, relacionado con la intensidad de uso reciente del vehículo, diferenciándose claramente de los factores estructurales identificados en (Dim1). Las relaciones entre variables también se evidencian en la cercanía de los vectores: kilometraje y antiguedad_vehiculo muestran direcciones similares, lo que indica un patrón compartido en las dos dimensiones. Por otro lado, kilometraje_anual forma ángulos amplios (cercanos a la perpendicularidad) respecto a variables como precio o cant_propietarios, lo que sugiere una baja correlación entre estos atributos dentro del espacio definido por las dos componentes principales.

La matriz de representación (cos²) refleja qué tan bien cada variable queda proyectada en las dimensiones principales. En la dimensión 1(Dim1), destacan valores elevados para kilometraje (\(0.84\)), antiguedad_vehiculo \(0.78\), precio \(0.62\) y cant_propietarios \(0.52\), lo que confirma que estas variables están fuertemente asociadas con esta componente. Su variabilidad se concentra principalmente en este eje, reforzando su papel dentro del patrón estructural del análisis. Por su parte, la dimensión 2(Dim2) muestra una representación muy alta para kilometraje_anual \(0.76\), indicando que esta variable se explica mejor desde este eje y no desde la primera componente. El resto de variables presenta valores bajos de cos² en (Dim2), lo que implica que su estructura se distribuye de manera predominante hacia la primera dimensión. En conjunto, la matriz permite diferenciar claramente entre variables de naturaleza estructural altamente representadas en (Dim1)y variables de comportamiento reciente representadas en (Dim2), mostrando la coherencia interna del modelo.

El gráfico de Calidad de Representación refuerza la interpretación anterior al mostrar mediante una escala continua de colores qué tan bien se ajusta cada variable al plano formado por (Dim1) y (Dim2). Las tonalidades cálidas asociadas a kilometraje, antiguedad_vehiculo, precio y cant_propietarios evidencian que estas variables poseen una alta precisión de proyección en la primera dimensión, siendo las mejor representadas en el espacio factorial. En contraste, kilometraje_anual obtiene su mejor calidad de representación en la dimensión 2(Dim2), donde presenta un cos² de \(0.76\). Este patrón indica que su contribución se distribuye principalmente hacia este eje, resultando en un vector claramente diferenciado en el gráfico. Variables con colores más fríos reflejan una representación parcial o baja, indicando que una parte de su variabilidad depende de dimensiones adicionales más allá de las dos principales. Este análisis permite identificar de manera visual la complementariedad entre las variables que construyen (Dim1) y aquellas que aportan distintivamente a (Dim2), enriqueciendo la interpretación global del modelo.

Las coordenadas individuales muestran cómo se distribuyen los registros del conjunto de datos en el espacio definido por las dos dimensiones principales. En la dimensión 1(Dim1), algunos individuos presentan valores negativos pronunciados como los registros (1, 5 y 7), lo que sugiere que comparten características asociadas con niveles bajos en las variables que más influyen a este componente. Por el contrario, registros como el (15, 19 y 20) exhiben valores positivos altos, representando perfiles opuestos y posiblemente más favorecedores en términos de uso, antigüedad o precio. En la dimensión 2(Dim2), destacan individuos como el (4, 3 y 19), que se proyectan de manera positiva, mostrando comportamientos diferenciados respecto al kilometraje anual. Por otro lado, registros como el (8, 11 y 14) se proyectan negativamente en esta dimensión, reflejando perfiles distintos en relación con esta variable. Estas coordenadas permiten identificar grupos de individuos con comportamientos similares y detectar patrones que contribuyen a la comprensión multidimensional del conjunto de datos.

Círculo de Correlaciones

fviz_pca_var(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], scale.unit = T, graph = F),col.var="#3B83BD", repel = T, col.circle = "#CDCDCD", ggtheme = theme_bw())
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## ℹ The deprecated feature was likely used in the ggpubr package.
##   Please report the issue at <https://github.com/kassambara/ggpubr/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## ℹ The deprecated feature was likely used in the factoextra package.
##   Please report the issue at <https://github.com/kassambara/factoextra/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Matriz de Representación

(get_pca_var(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], ncp = 5, scale.unit = TRUE, graph = F)))$cos2
##                         Dim.1      Dim.2        Dim.3      Dim.4        Dim.5
## kilometraje         0.8448288 0.07367161 3.649505e-05 0.05396555 2.749750e-02
## cant_propietarios   0.5292770 0.13360382 2.695560e-01 0.06739729 1.658768e-04
## antiguedad_vehiculo 0.7864674 0.09026943 2.028337e-03 0.10152732 1.970747e-02
## kilometraje_anual   0.1921791 0.76942972 1.569981e-02 0.01397614 8.715198e-03
## precio              0.6257611 0.01651188 2.534662e-01 0.10423973 2.111985e-05

Calidad de Representación

fviz_pca_var(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], ncp = 5, scale.unit = TRUE, graph = F), col.var="cos2", gradient.cols=c("#00AFBB","#E7B800","#FC4E07"), repel = TRUE)

Coordenadas Individuales

head((PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], ncp = 5, scale.unit = TRUE, graph = F))$ind$coord, n = 23L)
##         Dim.1      Dim.2       Dim.3       Dim.4        Dim.5
## 1  -2.9885593 -0.6439590 -1.02221922 -0.26357471 -0.512910572
## 2  -0.3559620  0.2203184 -1.04430563 -0.01552121  0.056717977
## 3   1.9995718  1.3687996 -0.22017108 -0.26800124 -0.221391807
## 4  -1.7324783  2.4323698 -0.25931943 -0.42282232  0.565354503
## 5  -3.4335027 -0.8134123 -0.54671977  0.21427486 -0.600400726
## 6  -0.9626471  0.2547214 -0.25319592  0.63538226  0.082057861
## 7  -2.3365104 -1.3135935  0.58372128  0.46634789 -0.135775419
## 8   1.3011388 -1.3964842  0.70656794  1.18169952  0.460538636
## 9  -1.9089958  0.9157192 -0.76158165 -0.13354432  0.105204478
## 10  1.0030109 -0.4110688  0.32972386 -0.41813967 -0.029154220
## 11  0.8858730 -0.9926864  0.21143619 -0.27168782  0.085752227
## 12 -0.3641176  0.3090336  0.40375865 -0.70946941  0.008146841
## 13 -0.6885553 -0.2267846  0.06772581 -1.11749848 -0.074277137
## 14  0.6880992 -0.7979359  0.05314280 -0.85188762 -0.017475836
## 15  3.9395361 -0.3278491 -0.33350917  1.26332302 -0.158258622
## 16 -2.3754259  1.1918650  0.04705684  0.48369728  0.159472403
## 17 -1.6371942  0.2208996 -0.34152906 -0.10711355 -0.006130197
## 18 -1.5513544  0.7647061  0.62794549 -0.38959403  0.100861889
## 19  2.9392124  1.4337508  0.80379875  0.77458460 -0.527445715
## 20  3.7427049 -0.7409900 -0.28118181  1.45673514  0.082198934
## 21 -2.3305783 -0.3888566 -0.47895794 -0.46894017 -0.270329244
## 22  1.3512690  1.1303789  0.35434010  0.21005078 -0.156106998
## 23  2.4701779 -0.4583225 -0.27211059  0.05714113 -0.049370791

Planteamiento y Desarrollo

El análisis se realiza aplicando un Análisis de Componentes Principales (ACP) con el objetivo de identificar la estructura interna de las variables estudiadas y determinar su contribución dentro de los ejes principales. Para ello se emplean diferentes salidas estadísticas: la matriz de correlaciones, el círculo de correlaciones, la gráfica de calidad de representación (cos²) y las coordenadas individuales. Cada uno de estos elementos permite evaluar la relación entre variables, su aporte a los componentes principales y el grado de representación en el plano factorial. Con base en estas salidas, se desarrolla el análisis del comportamiento de las variables dentro de los dos primeros componentes del ACP, que concentran la mayor proporción de información del sistema.

2.6. Contribuciones

Los autores (Díaz Morales & Morales Rivera, 2012) señalan que la interpretación de los resultados está estrechamente ligada al cálculo de elementos como coordenadas, contribuciones y cosenos cuadrados. Por lo tanto, es esencial que las variables estén bien conceptualizadas y contextualizadas para facilitar su comprensión. En este sentido, analizar la contribución de cada variable a una componente ayuda a interpretar los resultados, mostrando cómo cada una influye en la definición de las componentes generadas. Este análisis se lleva a cabo en esta sección para determinar el aporte de cada variable en la construcción de las componentes.

2.7. Planteamiento y Desarrollo

Basado en las variables cuantitativas del conjunto de datos descrito en la sección 1.2, se requiere determinar las contribuciones de cada variable en la construcción de las componentes.

La navegación a través de las pestañas facilita la visualización de las contribuciones de las variables del conjunto de datos en forma de representaciones numéricas y gráficas, permitiendo comprender cómo cada variable influye en la construcción de las componentes. Esto permite analizar la proporción de variabilidad que cada variable aporta a la variabilidad total de la componente con la que está asociada.

La Matriz de Contribuciones muestra cómo cada variable contribuye a la retención de variabilidad en la construcción de cada componente. Los diagramas de barras, que se visualizan en las pestañas desde Contribuciones a D1 hasta Contribuciones a D5, ilustran las contribuciones específicas de las variables para explicar la variabilidad en cada componente. Cada gráfico incluye una línea que indica la contribución media, lo que facilita la identificación de las variables que tienen mayor impacto en la explicación de la variabilidad de los componentes.

En Contribuciones a D1 se visualiza que las variables por encima de la contribución media: kilometraje,antiguedad_vehiculo y precio , los cente el \(76,05%\) de la variabilidad del componente 1.

En Contribuciones a D2 se visualiza que las variables por encima de la contribución media: kilometraje_anual que retiene aproximadamente el \(70,98%\) de la variabilidad del componente 2.

En Contribuciones a D3 se visualiza que las variables por encima de la contribución media: cant_propietarios y precio que retienen aproximadamente el \(96,68%\) de la variabilidad del componente 3.

En Contribuciones a D4 se visualiza que la variable por encima de la contribución media: precio* y antiguedad_vehiculo** que retienen aproximadamente el \(60,43%\) de la variabilidad del componenete 4.

En Contribuciones a D5 se visualiza que las variables por encima de la contribución media: kilometraje y antiguedad_vehiculo que retienen aproximadamenteel \(84,1%\) de la variabilidad del componente 5.

Matriz de Contribuciones

(get_pca_var(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], ncp = 5, scale.unit = TRUE, graph = F)))$contrib
##                         Dim.1     Dim.2       Dim.3     Dim.4       Dim.5
## kilometraje         28.364110  6.799495  0.00674851 15.820756 49.00889073
## cant_propietarios   17.769838 12.330917 49.84514529 19.758456  0.29564285
## antiguedad_vehiculo 26.404696  8.331385  0.37507149 29.764153 35.12469469
## kilometraje_anual    6.452182 71.014244  2.90314150  4.097302 15.53312974
## precio              21.009173  1.523958 46.86989321 30.559333  0.03764199

Contribuciones a D1

fviz_contrib(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], ncp = 6, scale.unit = TRUE, graph = F), choice = "var", axes = 1, top = 10)

Contribuciones a D2

fviz_contrib(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], ncp = 6, scale.unit = TRUE, graph = F), choice = "var", axes = 2, top = 10)

Contribuciones a D3

fviz_contrib(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], ncp = 6, scale.unit = TRUE, graph = F), choice = "var", axes = 3, top = 10)

Contribuciones a D4

fviz_contrib(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], ncp = 6, scale.unit = TRUE, graph = F), choice = "var", axes = 4, top = 10)

Contribuciones a D5

fviz_contrib(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6,11,12)], ncp = 6, scale.unit = TRUE, graph = F), choice = "var", axes = 5, top = 10)

2.8. Interpretación

Representar los registros en un espacio de dimensiones reducidas permite situarlos en un plano de factores, lo que facilita su análisis e interpretación. Las variables reducidas se corresponden con las componentes principales, que se utilizan como ejes en el plano y cuyos valores son los puntajes de las componentes. La distancia entre los puntos representados por estos puntajes es clave para identificar similitudes entre los perfiles de las observaciones. No obstante, las similitudes pueden aparecer solo en algunas variables y no en todas. Así, se busca que las distancias en el espacio de alta dimensión se conserven en el espacio reducido, manteniendo la estructura de las relaciones entre los datos. Según (Díaz Morales & Morales Rivera, 2012).

2.9. Biplots de componentes principales [variables cuantitativas]

El biplot correspondiente al tipo de combustible (eléctrico, gasolina y diésel) presenta una diferenciación más evidente en comparación con la transmisión. Los vehículos eléctricos tienden a agruparse en zonas asociadas a menor antigüedad y menor kilometraje acumulado, lo cual es consistente con su adopción más reciente en el mercado. Por otro lado, los vehículos diésel y gasolina muestran una mayor dispersión, especialmente en regiones relacionadas con altos niveles de kilometraje y antigüedad.

La orientación de las variables sugiere que el tipo de combustible está relacionado con patrones específicos de uso y depreciación, lo que permite inferir que esta variable categórica contribuye de forma moderada a la diferenciación de las observaciones en el espacio de componentes principales.

En el biplot asociado al tipo de transmisión (automática y manual), se observa una mayor superposición entre ambos grupos en el plano de las dos primeras componentes principales. Aunque existen ligeras tendencias de separación en algunas regiones del espacio factorial, la dispersión general indica que el tipo de transmisión no es un factor dominante en la variabilidad capturada por Dim.1 y Dim.2.

Las variables numéricas mantienen la misma orientación estructural que en el análisis general, lo que confirma la estabilidad del modelo. Sin embargo, la ausencia de una separación marcada sugiere que las diferencias entre vehículos automáticos y manuales no explican de manera significativa los patrones principales asociados al desgaste, uso y precio del vehículo.

El biplot correspondiente a la gama vehicular (alta, media y baja) muestra una estructura clara en el plano factorial. La Dimensión 1, que concentra la mayor proporción de varianza, está fuertemente asociada a variables relacionadas con el uso acumulado y la depreciación, como el kilometraje y la antigüedad del vehículo, mientras que el precio se proyecta en sentido opuesto, reflejando su relación inversa con dichas variables.

Se observa que los vehículos de gama alta tienden a concentrarse en zonas asociadas a menores niveles de desgaste relativo y valores más altos de precio, mientras que los de gama baja se distribuyen hacia regiones donde predominan mayores valores de kilometraje y antigüedad. La gama media presenta una dispersión intermedia, lo cual indica una transición gradual entre ambos extremos. Esta representación evidencia que la gama vehicular es una variable categórica con capacidad para generar agrupaciones interpretables dentro del espacio reducido.

Biplot de Variables y Registros [filtro:tipo_de_combustible]

vehiculos_muestreado <- vehicle_price_prediction_modificado_MUESTREADO20K_ETL[
  sample(1:nrow(vehicle_price_prediction_modificado_MUESTREADO20K_ETL), 100),
  -c(1,4,6,11,12)]

vehiculos_muestreado$tipo_de_combustible <- factor(vehiculos_muestreado$tipo_de_combustible,
  levels = unique(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible),
  labels = unique(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible))

fviz_pca_biplot(PCA(vehiculos_muestreado[,], ncp = 5, scale.unit = TRUE, graph = FALSE, quali.sup = "tipo_de_combustible"), axes = c(1,2), repel = TRUE, habillage = "tipo_de_combustible")

Biplot de Variables y Registros [filtro:transmison]

set.seed(780729)

vehiculos_muestreado2 <- vehicle_price_prediction_modificado_MUESTREADO20K_ETL[sample(1:nrow(vehicle_price_prediction_modificado_MUESTREADO20K_ETL), 200), -c(1,5,6,11,12)]

vehiculos_muestreado2$transmision <- factor(vehiculos_muestreado2$transmision)

fviz_pca_biplot(PCA(vehiculos_muestreado2[,], ncp = 5, scale.unit = TRUE, graph = FALSE, quali.sup = "transmision"), axes = c(1,2), repel = TRUE, habillage = "transmision")

Biplot de Variables y Registros [filtro:gama_vehicular]

set.seed(780729)

vehiculos_muestreado3 <- vehicle_price_prediction_modificado_MUESTREADO20K_ETL[sample(1:nrow(vehicle_price_prediction_modificado_MUESTREADO20K_ETL), 150), -c(1,4,5,6,11)]

vehiculos_muestreado3$gama_vehicular <- trimws(vehiculos_muestreado3$gama_vehicular)
vehiculos_muestreado3$gama_vehicular <- as.factor(vehiculos_muestreado3$gama_vehicular)

idx_gama <- which(names(vehiculos_muestreado3) == "gama_vehicular")

fviz_pca_biplot(PCA(vehiculos_muestreado3, ncp = 5, scale.unit = TRUE, graph = FALSE, quali.sup = idx_gama), axes = c(1,2), repel = TRUE, habillage = "gama_vehicular")

Coordenadas Individuales [ChestPain]

pca_result <- PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[, -c(1,4,5,6,11,12)], ncp = 5, scale.unit = TRUE, graph = FALSE)
res.coord <- pca_result$ind$coord
head(res.coord)
##        Dim.1       Dim.2      Dim.3       Dim.4       Dim.5
## 1 -3.5230020 -0.72943069 -0.9779092 -0.49157509  0.60974655
## 2 -0.3877686  0.16962087 -1.0510735 -0.03636391 -0.06886444
## 3  1.8479242  1.59830110 -0.1969783 -0.34053882  0.23511225
## 4 -2.3406778  2.34766463 -0.2970047 -0.14085476 -0.66287489
## 5 -3.8935266 -0.98622682 -0.5392726  0.03766639  0.72343052
## 6 -0.9069173  0.07518764 -0.3198987  0.74232252 -0.07216449

FASE 3 [ANÁLISIS DE CORRESPONDENCIAS]

3.1. Objetivos

Se busca profundizar en el análisis multivariado de las variables cualitativas del conjunto de datos mediante técnicas de Análisis de Correspondencias Simples (ACS) y Múltiples (ACM). Los objetivos son: construir tablas de contingencia para identificar asociaciones entre categorías; generar la tabla disyuntiva completa necesaria para el ACM; evaluar la calidad de representación de las modalidades en los planos factoriales; analizar las contribuciones de cada categoría a la formación de las dimensiones; e interpretar los patrones de relación entre atributos vinculados a características técnicas y comerciales de los vehículos usados. Esto permitirá caracterizar la estructura cualitativa del conjunto de datos y fortalecer la comprensión de las asociaciones presentes entre las diferentes modalidades categórica.

3.2. Correspondencias Simples

Según (Aldás & Uriel, 2017),el análisis de correspondencias simple (ACS) tiene como propósito reducir la dimensionalidad de las relaciones entre categorías de dos variables categóricas, representándolas en un espacio multidimensional. Este método permite analizar gráficamente las distancias entre las categorías de las variables, facilitando la interpretación de tablas de contingencia. El número máximo de dimensiones necesarias para explicar dichas relaciones corresponde a uno menos el número de categorías de la variable con menor cantidad de niveles.

Asimismo, el ACS, basado en tablas de contingencia, puede ampliarse para incluir más de dos variables categóricas, lo que se conoce como Análisis de correspondencias múltiples (ACM). Este enfoque utiliza una tabla disyuntiva completa, permitiendo explorar y representar relaciones más complejas entre múltiples variables categóricas.

AC Parejas Totales

Contingencias
addmargins(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible))
##             
##              Diesel Electric Gasoline   Sum
##   automatico   3081     3634     3125  9840
##   manual       3204     3559     3195  9958
##   Sum          6285     7193     6320 19798
addmargins(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$marca_vehiculo))
##             
##              Acura  Audi   BMW Cadillac Chevrolet Chrysler Dodge  Ford   GMC
##   automatico   390   372   399      410       404      388   378   401   355
##   manual       404   362   417      381       366      390   400   407   375
##   Sum          794   734   816      791       770      778   778   808   730
##             
##              Honda Hyundai  Jeep   Kia Land Rover Lexus Mazda Mercedes-Benz
##   automatico   382     386   397   419        377   421   383           368
##   manual       427     377   439   417        423   404   394           395
##   Sum          809     763   836   836        800   825   777           763
##             
##              Nissan Porsche   Ram Subaru Tesla Toyota Volkswagen Volvo   Sum
##   automatico    405     380   403    398   428    385        420   391  9840
##   manual        394     389   392    417   396    403        398   391  9958
##   Sum           799     769   795    815   824    788        818   782 19798
addmargins(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$color_exterior))
##           
##            Black  Blue  Gray   Red Silver White   Sum
##   Diesel    1041  1064  1054  1044   1045  1037  6285
##   Electric  1183  1221  1203  1207   1220  1159  7193
##   Gasoline  1043  1000  1080  1081   1028  1088  6320
##   Sum       3267  3285  3337  3332   3293  3284 19798
Probabilidades
addmargins(prop.table(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible))*100)
##             
##                 Diesel  Electric  Gasoline       Sum
##   automatico  15.56218  18.35539  15.78442  49.70199
##   manual      16.18345  17.97656  16.13799  50.29801
##   Sum         31.74563  36.33195  31.92242 100.00000
addmargins(prop.table(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$gama_vehicular, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision))*100)
##             
##              automatico     manual        Sum
##   gama alta   21.886049  22.229518  44.115567
##   gama baja    5.904637   5.970300  11.874937
##   gama media  21.911304  22.098192  44.009496
##   Sum         49.701990  50.298010 100.000000
Frecuencias [CPF y CPC]
round(addmargins(prop.table(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$marca_vehiculo, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$gama_vehicular), 1)*100, 2), 2)
##                
##                 gama alta gama baja gama media Sum
##   Acura               100         0          0 100
##   Audi                100         0          0 100
##   BMW                 100         0          0 100
##   Cadillac            100         0          0 100
##   Chevrolet             0         0        100 100
##   Chrysler              0       100          0 100
##   Dodge                 0       100          0 100
##   Ford                  0         0        100 100
##   GMC                   0         0        100 100
##   Honda                 0         0        100 100
##   Hyundai               0         0        100 100
##   Jeep                100         0          0 100
##   Kia                   0         0        100 100
##   Land Rover          100         0          0 100
##   Lexus               100         0          0 100
##   Mazda                 0         0        100 100
##   Mercedes-Benz       100         0          0 100
##   Nissan                0         0        100 100
##   Porsche             100         0          0 100
##   Ram                   0       100          0 100
##   Subaru                0         0        100 100
##   Tesla               100         0          0 100
##   Toyota                0         0        100 100
##   Volkswagen            0         0        100 100
##   Volvo               100         0          0 100
round(addmargins(prop.table(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$gama_vehicular, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision), 2)*100, 1), 2)
##             
##              automatico manual
##   gama alta       44.03  44.20
##   gama baja       11.88  11.87
##   gama media      44.09  43.93
##   Sum            100.00 100.00
round(addmargins(prop.table(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$gama_vehicular, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$rango_antiguedad), 2)*100, 1), 2)
##             
##              De 1 a 5 anhos De 11 a 15 anhos De 16 a 20 anhos De 21 a 25 anhos
##   gama alta           43.61            43.20            39.53            72.73
##   gama baja           11.42            12.33            13.02             9.09
##   gama media          44.97            44.47            47.44            18.18
##   Sum                100.00           100.00           100.00           100.00
##             
##              De 6 a 10 anhos
##   gama alta            45.01
##   gama baja            11.92
##   gama media           43.06
##   Sum                 100.00
Perfiles [CPF y CPC]
plotct(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible),"row")

plotct(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible),"col")

plotct(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$gama_vehicular, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision),"row")

plotct(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$gama_vehicular, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision),"col")

plotct(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$marca_vehiculo, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$rango_antiguedad),"row")

plotct(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$marca_vehiculo, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$rango_antiguedad),"col")

Pruebas de Hipótesis
chisq.test(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible))
## 
##  Pearson's Chi-squared test
## 
## data:  table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision,     vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible)
## X-squared = 3.2613, df = 2, p-value = 0.1958
chisq.test(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible, vehicle_price_prediction_modificado_MUESTREADO20K_ETL$gama_vehicular))
## 
##  Pearson's Chi-squared test
## 
## data:  table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible,     vehicle_price_prediction_modificado_MUESTREADO20K_ETL$gama_vehicular)
## X-squared = 55.736, df = 4, p-value = 2.278e-11
chisq.test(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$gama_vehicular,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision))
## 
##  Pearson's Chi-squared test
## 
## data:  table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$gama_vehicular,     vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision)
## X-squared = 0.05513, df = 2, p-value = 0.9728

AC Pareja Única

Contingencias y Residuales [T-CP]
chisq.test(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible))$observed
##             
##              Diesel Electric Gasoline
##   automatico   3081     3634     3125
##   manual       3204     3559     3195
chisq.test(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible))$expected 
##             
##               Diesel Electric Gasoline
##   automatico 3123.77 3575.064 3141.166
##   manual     3161.23 3617.936 3178.834
chisq.test(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible))$residuals
##             
##                  Diesel   Electric   Gasoline
##   automatico -0.7652450  0.9856839 -0.2884371
##   manual      0.7606975 -0.9798264  0.2867230
chisq.test(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible))$stdres
##             
##                  Diesel   Electric   Gasoline
##   automatico -1.3060502  1.7418128 -0.4929168
##   manual      1.3060502 -1.7418128  0.4929168
Contribuciones [T-CP]
chisq.test(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible))$residuals^2/chisq.test(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible))$statistic*100
##             
##                 Diesel  Electric  Gasoline
##   automatico 17.956033 29.790971  2.551006
##   manual     17.743258 29.437955  2.520777
Correspondencia Simple Unidimensional [R-UR]
CA(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible), graph = FALSE)$eig
##         eigenvalue percentage of variance cumulative percentage of variance
## dim 1 0.0001647287                    100                               100
CA(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible), graph = FALSE)$col
## $coord
##                  [,1]
## Diesel    0.013610449
## Electric -0.016387293
## Gasoline  0.005115842
## 
## $contrib
##               [,1]
## Diesel   35.699290
## Electric 59.228926
## Gasoline  5.071784
## 
## $cos2
##          [,1]
## Diesel      1
## Electric    1
## Gasoline    1
## 
## $inertia
## [1] 5.880698e-05 9.756705e-05 8.354684e-06
CA(table(vehicle_price_prediction_modificado_MUESTREADO20K_ETL$transmision,vehicle_price_prediction_modificado_MUESTREADO20K_ETL$tipo_de_combustible), graph = FALSE)$row
## $coord
## automatico     manual 
## -0.0129114  0.0127584 
## 
## $contrib
## automatico     manual 
##   50.29801   49.70199 
## 
## $cos2
## automatico     manual 
##          1          1 
## 
## $inertia
## [1] 8.285527e-05 8.187345e-05

Interpretación

PENDIENTE

3.3. Correspondencias Múltiples

ACM

vehiculos_ACM <- vehicle_price_prediction_modificado_MUESTREADO20K_ETL[, c("marca_vehiculo","transmision", "tipo_de_combustible", "color_exterior", "rango_antiguedad", "gama_vehicular")]

vehiculos_ACM <- data.frame(lapply(vehiculos_ACM, factor))
suppressWarnings({res.acm <-  MCA(vehiculos_ACM, grap = FALSE)})

Biplot ACM

set.seed(780729)

muestra_ind <- sample(rownames(res.acm$ind$coord), 200)

fviz_mca_biplot(res.acm, select.ind = list(name = muestra_ind), repel = TRUE, col.var = "#E7B800", addEllipses = TRUE, ellipse.level = 0.95)

3.4. Planteamiento y Desarrollo

PENDIENTE TEXTO

Calidad de Representación

fviz_mca_var(res.acm, col.var ="cos2", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), repel = TRUE)

res.acm$var$cos2
##                         Dim 1        Dim 2        Dim 3        Dim 4
## Acura            5.035770e-02 8.869520e-04 8.793168e-03 5.060634e-04
## Audi             4.636672e-02 8.061675e-04 8.779201e-03 1.219769e-03
## BMW              5.155014e-02 9.101888e-04 1.055862e-02 7.694385e-04
## Cadillac         5.086842e-02 8.775054e-04 4.187430e-03 5.403148e-02
## Chevrolet        2.523497e-02 2.605493e-02 1.801036e-05 4.906790e-02
## Chrysler         5.915618e-02 2.430087e-01 2.858645e-03 2.000727e-03
## Dodge            6.067688e-02 2.435206e-01 3.236511e-04 7.968393e-03
## Ford             2.671172e-02 2.752083e-02 3.300120e-05 3.373976e-03
## GMC              2.385769e-02 2.457759e-02 4.099932e-06 4.534821e-03
## Honda            2.665728e-02 2.757816e-02 2.103184e-04 2.044526e-03
## Hyundai          2.483697e-02 2.586272e-02 7.289379e-05 2.249876e-02
## Jeep             5.264103e-02 9.418291e-04 1.291851e-02 1.806727e-02
## Kia              2.732602e-02 2.843147e-02 1.502554e-03 2.029010e-03
## Land Rover       5.179248e-02 8.910049e-04 1.972656e-03 4.129108e-02
## Lexus            5.225140e-02 9.430511e-04 1.188993e-02 2.299563e-03
## Mazda            2.506911e-02 2.634737e-02 1.400428e-03 3.576074e-04
## Mercedes-Benz    4.782750e-02 8.225865e-04 1.119905e-02 2.875776e-04
## Nissan           2.671071e-02 2.709664e-02 9.657051e-04 4.833067e-02
## Porsche          4.879477e-02 8.860352e-04 1.042043e-02 2.706600e-02
## Ram              6.136268e-02 2.486253e-01 9.358202e-05 1.855290e-02
## Subaru           2.673484e-02 2.784471e-02 1.137248e-04 1.303284e-02
## Tesla            6.846202e-02 8.601103e-04 5.688112e-01 1.192872e-03
## Toyota           2.614932e-02 2.676839e-02 2.491262e-04 2.567959e-03
## Volkswagen       2.644588e-02 2.797965e-02 1.333813e-03 4.144482e-03
## Volvo            4.985862e-02 8.803242e-04 6.575406e-03 6.291525e-02
## automatico       1.690556e-06 1.242999e-06 4.779801e-03 1.333779e-01
## manual           1.690556e-06 1.242999e-06 4.779801e-03 1.333779e-01
## Diesel           2.989273e-03 4.785014e-05 1.653804e-01 4.070690e-02
## Electric         1.281773e-02 2.005006e-05 6.199589e-01 2.396941e-04
## Gasoline         3.870262e-03 5.232462e-06 1.650547e-01 4.727756e-02
## Black            1.120794e-03 3.523465e-04 3.979895e-04 5.932554e-02
## Blue             3.502890e-04 8.147275e-05 1.025043e-03 6.509398e-02
## Gray             2.575701e-05 4.164688e-04 8.225308e-04 6.886595e-02
## Red              1.576704e-05 6.223926e-05 1.959001e-04 8.361682e-02
## Silver           9.609405e-05 9.180134e-05 2.985201e-04 4.260215e-02
## White            1.953976e-04 1.062182e-04 6.908157e-04 2.815173e-02
## De 1 a 5 anhos   8.886399e-05 6.705460e-04 5.553504e-04 5.854461e-05
## De 11 a 15 anhos 4.027563e-04 3.764817e-05 8.460948e-04 9.612648e-02
## De 16 a 20 anhos 6.825132e-04 2.253890e-06 1.571853e-03 4.814513e-02
## De 21 a 25 anhos 7.098615e-04 7.426594e-05 8.719183e-04 2.865472e-02
## De 6 a 10 anhos  9.745105e-04 3.600648e-04 1.276039e-04 8.913576e-02
## gama alta        9.786008e-01 1.666721e-02 3.147693e-03 5.285276e-06
## gama baja        1.974671e-01 8.011929e-01 7.386926e-04 4.759523e-06
## gama media       4.898686e-01 5.075851e-01 1.475072e-03 7.705888e-07
##                         Dim 5
## Acura            3.571619e-03
## Audi             2.115206e-02
## BMW              1.357393e-01
## Cadillac         1.653676e-02
## Chevrolet        4.296741e-03
## Chrysler         1.429842e-02
## Dodge            3.719678e-03
## Ford             1.176186e-03
## GMC              4.129635e-02
## Honda            1.214813e-02
## Hyundai          1.611443e-02
## Jeep             4.098400e-04
## Kia              9.150360e-04
## Land Rover       5.477063e-03
## Lexus            2.645775e-02
## Mazda            3.921421e-03
## Mercedes-Benz    2.493642e-02
## Nissan           6.658063e-05
## Porsche          1.604159e-03
## Ram              2.895645e-03
## Subaru           1.968382e-02
## Tesla            1.058218e-03
## Toyota           6.777681e-02
## Volkswagen       8.948485e-03
## Volvo            3.636847e-03
## automatico       2.343221e-02
## manual           2.343221e-02
## Diesel           1.962264e-02
## Electric         7.705978e-04
## Gasoline         1.237299e-02
## Black            3.307959e-02
## Blue             2.409383e-01
## Gray             4.010198e-04
## Red              1.427748e-01
## Silver           3.460726e-02
## White            7.391335e-03
## De 1 a 5 anhos   1.318635e-01
## De 11 a 15 anhos 4.934305e-03
## De 16 a 20 anhos 1.261499e-02
## De 21 a 25 anhos 4.444456e-02
## De 6 a 10 anhos  1.031195e-01
## gama alta        8.406437e-06
## gama baja        6.409971e-06
## gama media       1.563015e-06

Contribuciones

fviz_contrib(res.acm, choice = "var", axes = 1, top = 15)

fviz_contrib(res.acm, choice = "var", axes = 2, top = 15)

fviz_contrib(res.acm, choice = "var", axes = 3, top = 15)

fviz_contrib(res.acm, choice = "var", axes = 4, top = 15)

fviz_contrib(res.acm, choice = "var", axes = 5, top = 15)

Biplot con Contribuciones

fviz_mca_var(res.acm, col.var ="contrib", gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"), repel = TRUE)

FASE 4 [CONGLOMERADOS]

4.1. Objetivos

En esta cuarta etapa del estudio se presentarán cálculos, visualizaciones e interpretaciones, utilizando el conjunto de datos procesado en las fases previas (1, 2 y 3). El enfoque se centrará en el análisis de conglomerados, abarcando tanto su versión jerárquica mediante dendrogramas como la no jerárquica con K-medias.

4.2. Agrupación Jerárquica

4.3. Planteamiento y desarrollo

Campo Clasificador
campo_clasificador <- vehicle_price_prediction_modificado_MUESTREADO20K_ETL[, -c(1,4,5,6,11,12)]
campo_clasificador_esc <- scale(campo_clasificador)
head(campo_clasificador_esc)
##      anho_de_fabricacion kilometraje cant_propietarios antiguedad_vehiculo
## [1,]           1.9493739  -1.5136906        -1.6102856          -1.7349445
## [2,]           0.1440377  -0.1865822        -0.9608705          -0.1573987
## [3,]          -0.3717727   1.4684015         0.3379595           0.3684499
## [4,]           1.4335635  -0.8544935        -1.6102856          -1.4720202
## [5,]           1.9493739  -1.5396230        -1.6102856          -1.7349445
## [6,]           0.1440377  -0.2530595        -0.9608705          -0.1573987
##      kilometraje_anual     precio
## [1,]       -1.62471972  0.4348379
## [2,]       -0.05719441 -0.5320587
## [3,]        1.59083973 -1.0506963
## [4,]        1.87386055  0.6940463
## [5,]       -1.93071944  1.2058375
## [6,]       -0.16927859  0.6521578
Matriz de Disimilaridad (Muestra Reducida)
set.seed(780729)
muestra_disim <- campo_clasificador[sample(1:nrow(campo_clasificador), 50), ]
muestra_disim_esc <- scale(muestra_disim)
matriz_disim_muestra <- dist(muestra_disim_esc)
fviz_dist(matriz_disim_muestra)

Optimización de Mojena

Unión Simple
arbol_single <- hclust(matriz_disim_muestra, method = "single")
alturas <- arbol_single$height
media_alt <- mean(alturas)
sd_alt    <- sd(alturas)
k         <- 1.25   
punto_corte <- media_alt + k * sd_alt
punto_corte
## [1] 1.482305
num_clusters <- sum(alturas > punto_corte) + 1
num_clusters
## [1] 6
plot(arbol_single, hang = -1, cex = 0.8)
abline(h = punto_corte, col = "red", lwd = 2)

Unión Completa
arbol_complete <- hclust(matriz_disim_muestra, method = "complete")
alturas <- arbol_complete$height
media_alt <- mean(alturas)
sd_alt    <- sd(alturas)
k         <- 1.25 
punto_corte <- media_alt + k * sd_alt
punto_corte
## [1] 3.977752
num_clusters <- sum(alturas > punto_corte) + 1
num_clusters
## [1] 7
plot(arbol_complete, hang = -1, cex = 0.8)
abline(h = punto_corte, col = "red", lwd = 2)

Optimización de Mojena – Método de Unión Promedio
arbol_average <- hclust(matriz_disim_muestra, method = "average")
alturas <- arbol_average$height
media_alt <- mean(alturas)
sd_alt    <- sd(alturas)
k         <- 1.25   # Valor utilizado en C3

punto_corte <- media_alt + k * sd_alt
punto_corte
## [1] 2.615416
num_clusters <- sum(alturas > punto_corte) + 1
num_clusters
## [1] 5
plot(arbol_average, hang = -1, cex = 0.8)
abline(h = punto_corte, col = "red", lwd = 2)

Dendogramas Optimizados

Unión Simple
arbol_single <- hclust(matriz_disim_muestra, method = "single")
alturas <- arbol_single$height
media_alt <- mean(alturas)
sd_alt    <- sd(alturas)
k         <- 1.25  
punto_corte <- media_alt + k * sd_alt
num_clusters <- sum(alturas > punto_corte) + 1
num_clusters
## [1] 6
plot(arbol_single, hang = -1, cex = 0.8)
abline(h = punto_corte, col = "red", lwd = 2)

Unión Completa

arbol_complete <- hclust(matriz_disim_muestra, method = "complete")
alturas <- arbol_complete$height
media_alt <- mean(alturas)
sd_alt    <- sd(alturas)
k         <- 1.25  
punto_corte <- media_alt + k * sd_alt
num_clusters <- sum(alturas > punto_corte) + 1
num_clusters
## [1] 7
plot(arbol_complete, hang = -1, cex = 0.8)
abline(h = punto_corte, col = "red", lwd = 2)

Unión Promedio

arbol_average <- hclust(matriz_disim_muestra, method = "average")
alturas <- arbol_average$height
media_alt <- mean(alturas)
sd_alt    <- sd(alturas)
k         <- 1.25  
punto_corte <- media_alt + k * sd_alt
num_clusters <- sum(alturas > punto_corte) + 1
num_clusters
## [1] 5
plot(arbol_average, hang = -1, cex = 0.8)
abline(h = punto_corte, col = "red", lwd = 2)

4.4. Agrupación No-Jerárquica

(planteamiento y desarrollo)

K-Óptimo

Elbow
fviz_nbclust(muestra_disim_esc, kmeans, method = "wss") + geom_vline(xintercept = 3, linetype = 2)

Silhouette
fviz_nbclust(muestra_disim_esc, kmeans, method = "silhouette")

Gap Statistic
fviz_nbclust(muestra_disim_esc, kmeans, method = "gap_stat")

Majority Rule
suppressWarnings(NbClust(data = muestra_disim_esc, diss = NULL, distance = "euclidean", min.nc = 2, max.nc = 10, method = "kmeans")$Best.nc)

## *** : The Hubert index is a graphical method of determining the number of clusters.
##                 In the plot of Hubert index, we seek a significant knee that corresponds to a 
##                 significant increase of the value of the measure i.e the significant peak in Hubert
##                 index second differences plot. 
## 

## *** : The D index is a graphical method of determining the number of clusters. 
##                 In the plot of D index, we seek a significant knee (the significant peak in Dindex
##                 second differences plot) that corresponds to a significant increase of the value of
##                 the measure. 
##  
## ******************************************************************* 
## * Among all indices:                                                
## * 10 proposed 2 as the best number of clusters 
## * 2 proposed 3 as the best number of clusters 
## * 1 proposed 5 as the best number of clusters 
## * 3 proposed 6 as the best number of clusters 
## * 4 proposed 7 as the best number of clusters 
## * 1 proposed 9 as the best number of clusters 
## * 3 proposed 10 as the best number of clusters 
## 
##                    ***** Conclusion *****                            
##  
## * According to the majority rule, the best number of clusters is  2 
##  
##  
## *******************************************************************
##                     KL      CH Hartigan     CCC   Scott  Marriot   TrCovW
## Number_clusters 2.0000  2.0000    7.000 10.0000  6.0000      6.0   3.0000
## Value_Index     8.5543 39.3773    5.632 -0.8642 81.4951 231267.1 454.7494
##                 TraceW Friedman   Rubin Cindex      DB Silhouette   Duda
## Number_clusters 7.0000   9.0000  7.0000 6.0000 10.0000     2.0000 2.0000
## Value_Index     9.0311 733.6085 -0.3649 0.3057  0.9794     0.3571 0.8559
##                 PseudoT2  Beale Ratkowsky    Ball PtBiserial   Frey McClain
## Number_clusters   2.0000 2.0000    2.0000  3.0000     2.0000 2.0000  2.0000
## Value_Index       4.5439 0.6205    0.4447 36.1691     0.5426 1.4285  0.6455
##                   Dunn Hubert SDindex Dindex   SDbw
## Number_clusters 7.0000      0  5.0000      0 10.000
## Value_Index     0.2698      0  1.4572      0  0.205

Resultados K-Means

K-Óptimo [El_Ma-Rul 3]
set.seed(780729)
print(kmeans(muestra_disim_esc, 3, nstart = 25))
## K-means clustering with 3 clusters of sizes 17, 13, 20
## 
## Cluster means:
##   anho_de_fabricacion  kilometraje cant_propietarios antiguedad_vehiculo
## 1           1.0527782 -0.991557575        -0.9516427          -1.0539870
## 2          -0.9626618  1.283701458         0.9338126           0.9722892
## 3          -0.2691313  0.008417991         0.2019181           0.2639010
##   kilometraje_anual       precio
## 1        -0.3845563  0.781076380
## 2         0.6723867 -1.012802831
## 3        -0.1101785 -0.005593083
## 
## Clustering vector:
##  [1] 3 3 3 3 2 3 1 3 1 3 3 1 2 2 3 1 3 2 1 3 1 1 3 2 1 1 2 2 2 3 3 1 1 1 3 2 1 2
## [39] 3 1 3 1 3 2 3 2 3 2 1 1
## 
## Within cluster sum of squares by cluster:
## [1] 45.33382 31.85847 53.87605
##  (between_SS / total_SS =  55.4 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"
K-Óptimo [sil 4]
set.seed(780729)
print(kmeans(muestra_disim_esc, 4, nstart = 25))
## K-means clustering with 4 clusters of sizes 18, 12, 11, 9
## 
## Cluster means:
##   anho_de_fabricacion kilometraje cant_propietarios antiguedad_vehiculo
## 1           0.4784556 -0.28029973        -0.7056937          -0.4997015
## 2          -0.9643870  1.32587144         0.9259680           0.9740513
## 3          -0.6972946  0.07071651         0.9166972           0.7012370
## 4           1.1811872 -1.29366041        -0.9436444          -1.1563996
##   kilometraje_anual      precio
## 1         0.3589002  0.21686402
## 2         0.7258692 -1.08050995
## 3        -0.4745193  0.09417451
## 4        -1.1056579  0.89184971
## 
## Clustering vector:
##  [1] 1 1 1 3 3 3 4 1 4 1 3 1 2 2 1 1 1 2 4 3 4 1 3 2 4 1 2 2 2 1 3 1 1 1 1 2 1 2
## [39] 3 4 3 4 3 2 1 2 3 2 4 4
## 
## Within cluster sum of squares by cluster:
## [1] 40.66154 30.40914 17.42986 20.61837
##  (between_SS / total_SS =  62.9 %)
## 
## Available components:
## 
## [1] "cluster"      "centers"      "totss"        "withinss"     "tot.withinss"
## [6] "betweenss"    "size"         "iter"         "ifault"

Gráficos K-Means

K-Óptimo [Elb_Ma-Rul 3]
fviz_cluster(kmeans(muestra_disim_esc, 3, nstart = 25), data = muestra_disim_esc, palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#E7B801"), ellipse.type = "euclid", star.plot = TRUE, repel = TRUE, ggtheme = theme_minimal()
)

K-Óptimo [sil 4]
fviz_cluster(kmeans(muestra_disim_esc, 2, nstart = 25), data = muestra_disim_esc, palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#E7B801"), ellipse.type = "euclid", star.plot = TRUE, repel = TRUE, ggtheme = theme_minimal()
)

Fase 5 [Análisis de Regresión]

5.1. Objetivos

5.2. Regresión Lineal Simple

5.3. Regresión Lineal Múltiple

5.4. Regresión Logística Simple

5.5. Ajuste de Varianza

6. Conclusiones

7. Bibliografía

Aldás, J., & Uriel, E. (2017). Análisis multivariante aplicado con R (2nd ed.). ALFACENTAURO.
Díaz Morales, L. G., & Morales Rivera, M. A. (2012). Análisis estadístico de datos multivariados (1st ed.). UNAL.
LS0tDQp0aXRsZTogIioqdGZjX2dkZF8yMDI1XzJncnVwb181KioiDQpzdWJ0aXRsZTogIkVzdHVkaW8gZGUgQW7DoWxpc2lzIE11bHRpdmFyaWFkbyBjb24gYmFzZSBlbiB1biBjb25qdW50byBkZSBkYXRvcyBzb2JyZSByZWdpc3Ryb3MgZGUgdmVoaWN1bG9zIHVzYWRvcyBjb24gZWwgZmluIGRlIHByZWRlY2lyIHN1IHByZWNpbyBzZWfDum4gc3VzIGNvbmRpY2lvbmVzLiINCmF1dGhvcjogIlBvcjogUGFvbGEgQ2FzdHJvIChwYW9sYS5hbmRyZWEuY2FzdHJvQGNvcnJlb3VuaXZhbGxlLmVkdS5jbyksQW5naWUgVsOhc2NvbmV6IFZhbGVuY2lhIChhbmdpZS52YXNjb25lekBjb3JyZW91bml2YWxsZS5lZHUuY28pLE1hcmlhIEpvc2UgQmFuZGVyYXMgUml2YXMgKGJhbmRlcmFzLm1hcmlhQGNvcnJlb3VuaXZhbGxlLmVkdS5jbyksTHVpcyBGZXJuYW5kbyBNb3JhbGVzIFBlbmFnb3MgKGx1aXMubW9yYWxlcy5wZW5hZ29zQGNvcnJlb3VuaXZhbGxlLmVkdS5jbyksR2lybWFuIEFuZHLDqXMgQ3VlcnZvIEFyYW5nbyAoZ2lybWFuLmN1ZXJ2b0Bjb3JyZW91bml2YWxsZS5lZHUuY28pIg0KZGF0ZTogIlRyYWJham8gZWxhYm9yYWRvIGVuIGVsIHBlcmlvZG8gYWNhZMOpbWljbyBjb21wcmVuZGlkbyBlbnRyZSBhZ29zdG8geSBkaWNpZW1icmUgZGVsIGHDsW8gMjAyNSwgY29tbyBhY3RpdmlkYWQgZm9ybWF0aXZhIHkgZXZhbHVhdGl2YSBkZWwgY3Vyc28gR2VzdGnDs24gZGUgRGF0b3MgcGFyYSBpbmdlbmllcsOtYSBJbmR1c3RyaWFsLiINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IGx1bWVuDQpiaWJsaW9ncmFwaHk6IGJpYmxpb2dyYWZpYV9NRS5iaWINCmNzbDogYXBhLmNzbA0KbGluay1jaXRhdGlvbnM6IHllcw0KLS0tDQo8IS0tIENvbmZpZ3VyYWNpw7NuIEdsb2JhbCBkZSBSIC0tPi0tLQ0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoY29ycnBsb3QpDQpsaWJyYXJ5KEdHYWxseSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoYW5kcmV3cykNCmxpYnJhcnkodGNsdGspDQpsaWJyYXJ5KGFwbHBhY2spDQpsaWJyYXJ5KGdyYXBoaWNzKQ0KbGlicmFyeShyZXNoYXBlMikNCmxpYnJhcnkoRmFjdG9NaW5lUikNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmxpYnJhcnkocHN5Y2gpDQpsaWJyYXJ5KEZhY3RvQ2xhc3MpDQpsaWJyYXJ5KGNsdXN0ZXIpDQpsaWJyYXJ5KGRlbmRleHRlbmQpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KbGlicmFyeShOYkNsdXN0KQ0KbGlicmFyeShzdGFyZ2F6ZXIpDQojbGlicmFyeShnZ3BhaXJzKQ0KbGlicmFyeShtdm5vcm1hbFRlc3QpDQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPVRSVUUpDQoNCnZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMIDwtIHJlYWRfZXhjZWwoIkQ6L0dlc3Rpb25fZGVfRGF0b3MvdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwueGxzeCIpDQoNCmBgYA0KDQojIyAqKkZhc2UgMSBbRGVzY3JpcGNpb25lcyBNdWx0aXZhcmlhbnRlc10qKiANCg0KIyMjIDEuMS4gT2JqZXRpdm9zIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQoNCkVsIG9iamV0aXZvIGRlIGVzdGUgcHJveWVjdG8gZXMgYXBsaWNhciB0w6ljbmljYXMgZGUgYW7DoWxpc2lzIG11bHRpdmFyaWFkbyBwYXJhIGdlc3Rpb25hciBlbCBjb25qdW50byBkZSBkYXRvcyBhcHJvYmFkbywgY29ycmVzcG9uZGllbnRlIGEgcmVnaXN0cm9zIHJlbGFjaW9uYWRvcyBjb24gcHJlZGljY2nDs24gZGUgcHJlY2lvcyBkZSB2ZWjDrWN1bG9zIHVzYWRvcy4gRWwgcHJvcMOzc2l0byBlcyBvcmdhbml6YXIgeSBwcm9jZXNhciBlZmljYXptZW50ZSBsYSBpbmZvcm1hY2nDs24sIGRlc2Fycm9sbGFuZG8gaGFiaWxpZGFkZXMgZW4gbGEgZ2VzdGnDs24geSBhbsOhbGlzaXMgZGUgZGF0b3MuIEVzdGUgdHJhYmFqbyBzZSBlbm1hcmNhIGRlbnRybyBkZWwgY3Vyc28gZGUgKipHZXN0acOzbiBkZSBEYXRvcyoqLCBkaWN0YWRvIHBvciBlbCBQcm9mZXNvciBHaWFuY2FybG8gTGlicmVyb3MgTG9uZG/DsW8gZW4gbGEgVW5pdmVyc2lkYWQgZGVsIFZhbGxlLiANCg0KPGEgbmFtZT0ic2VjMS4yIj48L2E+DQoNCiMjIyAxLjIuIERlc2NyaXBjacOzbiBkZSBsb3MgZGF0b3Mgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KRWwgY29uanVudG8gZGUgZGF0b3MgZnVlIG9idGVuaWRvIGVuIHN1IHRvdGFsaWRhZCBkZSAgKipLYWdnbGUqKjogKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvbWV0YXdhdmUvdmVoaWNsZS1wcmljZS1wcmVkaWN0aW9uKSBLYWdnbGUgZXMgdW5hIHBsYXRhZm9ybWEgZW4gbMOtbmVhIGRlIGNpZW5jaWEgZGUgZGF0b3MgeSBhcHJlbmRpemFqZSBhdXRvbcOhdGljbywgcHJvcGllZGFkIGRlIEdvb2dsZSBMTEMuIEVzdGEgZmFjaWxpdGEgbGEgcGFydGljaXBhY2nDs24gZW4gY29tcGV0ZW5jaWFzIGRvbmRlIGxhcyBlbXByZXNhcyBwdWJsaWNhbiBjb25qdW50b3MgZGUgZGF0b3MgeSBwcm9ibGVtYXMsIHBlcm1pdGllbmRvIGEgbG9zIHVzdWFyaW9zIGRlc2Fycm9sbGFyIG1vZGVsb3MgcHJlZGljdGl2b3MgeSBjb21wZXRpci4gTGEgcGxhdGFmb3JtYSB0YW1iacOpbiBvZnJlY2Ugbm90ZWJvb2tzIHBhcmEgY29tcGFydGlyIHkgY29sYWJvcmFyIGVuIHByb3llY3RvcyB1dGlsaXphbmRvIFB5dGhvbiB5IFIsIGFzw60gY29tbyB1bmEgYW1wbGlhIGNvbGVjY2nDs24gZGUgY29uanVudG9zIGRlIGRhdG9zIGRlIGFjY2VzbyBww7pibGljby4gQWRlbcOhcywgS2FnZ2xlIExlYXJuLCB1bmEgc2VjY2nDs24gZGUgbGEgcGxhdGFmb3JtYSBkZWRpY2FkYSBhIGxhIGVkdWNhY2nDs24geSBlbCBhcHJlbmRpemFqZSBlbiBjaWVuY2lhIGRlIGRhdG9zIHkgYXByZW5kaXphamUgYXV0b23DoXRpY28gcHJvcG9yY2lvbmEgdHV0b3JpYWxlcyB5IGN1cnNvcyBpbnRlcmFjdGl2b3MgZW4gdGVtYXMgY29tbyBQeXRob24sIFNRTCwgdmlzdWFsaXphY2nDs24gZGUgZGF0b3MgeSBhcHJlbmRpemFqZSBhdXRvbcOhdGljbywgZGlyaWdpZG9zIGEgcHJpbmNpcGlhbnRlcyB5IHVzdWFyaW9zIGF2YW56YWRvcy4NCg0KRXN0ZSBjb25qdW50byBkZSBkYXRvcyBzZSByZWxhY2lvbmEgY29uIGRpdmVyc2FzIMOhcmVhcyBkZSBsYSBpbmdlbmllcsOtYSBpbmR1c3RyaWFsLCBkZWJpZG8gYSBxdWUgc3UgZGVzYXJyb2xsbyB5IGFuw6FsaXNpcyBpbXBsaWNhbiBsYSBhcGxpY2FjacOzbiBkZSBwcmluY2lwaW9zIHByb3Bpb3MgZGUgbGEgZGlzY2lwbGluYS4gRW4gcHJpbWVyIGx1Z2FyLCBzZSB2aW5jdWxhIGNvbiBsYSAqKmVzdGFkw61zdGljYSB5IGVsIGFuw6FsaXNpcyBkZSBkYXRvcygyLm9wZXJhdGlvbnMgcmVzZWFyY2ggeSBhbmFseXNpcykqKiwgYWwgZW1wbGVhciBtw6l0b2RvcyBlc3RhZMOtc3RpY29zIHBhcmEgZXN0dWRpYXIgbGEgaW5mb3JtYWNpw7NuIHkgZ2VuZXJhciBtb2RlbG9zIHByZWRpY3Rpdm9zIHByZWNpc29zLiBUYW1iacOpbiwgc2UgYXNvY2lhIGNvbiBsYSAqKmdlc3Rpw7NuIGRlIGxhIGNhbGlkYWQgKDUucXVhbGl0eSB5IHJlbGlhYmlsaXR5IGVuZ2luZWVyaW5nKSoqLCBwb3JxdWUgZ2FyYW50aXphIHF1ZSBsb3MgZGF0b3Mgc2VhbiBjb2hlcmVudGVzLCBjb21wbGV0b3MgeSBjb25maWFibGVzLiBBc2ltaXNtbywgaW50ZXJ2aWVuZSBsYSAqKmludmVzdGlnYWNpw7NuIGRlIG9wZXJhY2lvbmVzICg3Lm9wZXJhdGlvbnMgZW5naW5lZXJpbmcgeSBtYW5hZ2VtZW50KSoqLCBxdWUgcGVybWl0ZSBvcHRpbWl6YXIgbG9zIGFsZ29yaXRtb3MgdXRpbGl6YWRvcyBwYXJhIGVzdGltYXIgbG9zIHByZWNpb3MgZGUgbWFuZXJhIGVmaWNpZW50ZS4gRW4gY3VhbnRvIGFsICoqYW7DoWxpc2lzIGVjb27Ds21pY28gZGUgaW5nZW5pZXLDrWEgKDMuZW5naW5lZXJpbmcgZWNvbm9taWMgYW5hbHlzaXMpKiosIHNlIHZlIHJlZmxlamFkbyBlbiBlbCBhbsOhbGlzaXMgZGUgbGEgcmVudGFiaWxpZGFkIHkgbGEgZGVwcmVjaWFjacOzbiBkZSBsb3MgdmVow61jdWxvcyBhIGxvIGxhcmdvIGRlbCB0aWVtcG8sdGFtYmnDqW4sc2UgdmUgcmVwcmVzZW50YWRvIGVuIGVsIGVzdHVkaW8gZGVsIGtpbG9tZXRyYWplIHkgbGEgYW50aWfDvGVkYWQgY29tbyBmYWN0b3JlcyBxdWUgaW5mbHV5ZW4gZW4gZWwgcHJlY2lvIGRlIGxvcyBhdXRvbcOzdmlsZXMuIEFkaWNpb25hbG1lbnRlLCBlbCBlc3R1ZGlvIHNlIHJlbGFjaW9uYSBjb24gbGEgKipnZXN0acOzbiBkZSBwcm95ZWN0b3MgKDkuZW5naW5lZXJpbmcgbWFuYWdlbWV0KSoqLCBhbCByZXF1ZXJpciB1bmEgcGxhbmVhY2nDs24gZXN0cnVjdHVyYWRhIHBhcmEgZWwgZGVzYXJyb2xsbyB5IGVqZWN1Y2nDs24gZGVsIHNjcmlwdCBnZW5lcmFkb3IgZGUgbG9zIGRhdG9zLiBEZSBpZ3VhbCBtYW5lcmEsIGxvcyAqKnNpc3RlbWFzIGRlIGluZm9ybWFjacOzbiAoMTEuaW5mb3JtYXRpb24gZW5naW5lZXJpbmcpKiogZGVzZW1wZcOxYW4gdW4gcGFwZWwgZnVuZGFtZW50YWwgZW4gZWwgYWxtYWNlbmFtaWVudG8sIG9yZ2FuaXphY2nDs24geSBwcm9jZXNhbWllbnRvIGRlIGxvcyByZWdpc3Ryb3MsIGRlIGlndWFsIG1hbmVyYSwgc2UgZXZpZGVuY2lhIGVuIGVsIHVzbyBkZSBoZXJyYW1pZW50YXMgY29tcHV0YWNpb25hbGVzIGNvbW8gUHl0aG9uLCBxdWUgcGVybWl0ZW4gY3JlYXIgc29sdWNpb25lcyBhdXRvbWF0aXphZGFzIHkgYXBsaWNhYmxlcyBhbCBlbnRvcm5vIGluZHVzdHJpYWwuDQoNClNlZ8O6biBsYSBkZXNjcmlwY2nDs24gZGVsIGNvbmp1bnRvIGRlIGRhdG9zIGVsZWdpZG8gZW4gbGEgcGxhdGFmb3JtYSBrYWdnbGUsIGVzdGUgZnVlIGRpc2XDsWFkbyBjb24gZWwgcHJvcMOzc2l0byBkZSBjcmVhciB1bmEgYmFzZSBzw7NsaWRhIHBhcmEgZWwgZW50cmVuYW1pZW50byBkZSBtb2RlbG9zIGRlIHByZWRpY2Npw7NuIGRlIHByZWNpb3MgYXV0b21vdHJpY2VzIGRlIGFsdGEgcHJlY2lzacOzbi4gQ29udGllbmUgdW4gdG90YWwgZGUgMjAuMDAwIHJlZ2lzdHJvcyBxdWUgcmVwcmVzZW50YW4gdW5hIGFtcGxpYSB2YXJpZWRhZCBkZSBtYXJjYXMsIG1vZGVsb3MgeSBlc3BlY2lmaWNhY2lvbmVzLCBhYmFyY2FuZG8gMjUgZGUgbGFzIG1hcmNhcyBtw6FzIGNvbXVuZXMgZW4gZWwgbWVyY2FkbyBhdXRvbW90b3IuIENhZGEgcmVnaXN0cm8gZnVlIGNvbnN0cnVpZG8gY29uc2lkZXJhbmRvIHJlbGFjaW9uZXMgeSBkaXN0cmlidWNpb25lcyByZWFsaXN0YXMgZW50cmUgbGFzIGNhcmFjdGVyw61zdGljYXMgZGVsIHZlaMOtY3VsbyB5IHN1IHZhbG9yIGNvbWVyY2lhbCwgY29uIGVsIGZpbiBkZSByZWZsZWphciBjb21wb3J0YW1pZW50b3Mgb2JzZXJ2YWJsZXMgZW4gY29udGV4dG9zIHJlYWxlcyBkZSBjb21wcmF2ZW50YS4gTGEgbMOzZ2ljYSBpbXBsZW1lbnRhZGEgZW4gbGEgZ2VuZXJhY2nDs24gZGUgbG9zIGRhdG9zIGNvbnRlbXBsYSBmYWN0b3JlcyBjb21vIGxhIGRlcHJlY2lhY2nDs24sIGVsIGRlc2dhc3RlIHkgZWwgcHJlY2lvIGRlIG1hcmNhLiBFbiBwcmltZXIgbHVnYXIsIGxhIGRlcHJlY2lhY2nDs24gc2UgbW9kZWxhIGNvbW8gbGEgcHJpbmNpcGFsIHZhcmlhYmxlIHF1ZSBkZXRlcm1pbmEgbGEgcmVkdWNjacOzbiBkZWwgcHJlY2lvIGNvbiBlbCBwYXNvIGRlbCB0aWVtcG8sIHNpZ3VpZW5kbyB1bmEgY3VydmEgZGUgZGVjbGl2ZSBkZSB0aXBvIGV4cG9uZW5jaWFsLiBFbiBzZWd1bmRvIGx1Z2FyLCBlbCBkZXNnYXN0ZSBzZSBhc29jaWEgZGlyZWN0YW1lbnRlIGNvbiBlbCBraWxvbWV0cmFqZSwgZWwgY3VhbCBzZSBjb3JyZWxhY2lvbmEgY29uIGxhIGFudGlnw7xlZGFkIGRlbCB2ZWjDrWN1bG8geSBlamVyY2UgdW4gZWZlY3RvIG5lZ2F0aXZvIHNvYnJlIGVsIHByZWNpbyBmaW5hbC4gRmluYWxtZW50ZSwgZWwgcHJlY2lvIGRlIGxhIG1hcmNhIGFjdMO6YSBjb21vIHVuYSB2YXJpYWJsZSBkZSByZWZlcmVuY2lhIHF1ZSByZWZsZWphIGVsIHBvc2ljaW9uYW1pZW50byBkZWwgbWVyY2FkbyBkZSBjYWRhIG1hcmNhIGVuIGVsIG11bmRvIHJlYWwuIA0KKHRpcG9fZGVfdmFyaWFibGU6OmVzY2FsYV9kZV9tZWRpY2nDs25bb3JkZW5hbWllbnRvXSk6DQoNCi0gKipraWxvbWV0cmFqZSoqIChjdWFudGl0YXRpdmE6OnJhesOzbik6IFJlcHJlc2VudGEgbGEgZGlzdGFuY2lhIHRvdGFsIHJlY29ycmlkYSBwb3IgZWwgdmVow61jdWxvIGRlc2RlIHN1IGZhYnJpY2FjacOzbiBoYXN0YSBsYSBmZWNoYSBkZWwgcmVnaXN0cm8sIG1lZGlkYSBlbiBraWzDs21ldHJvcy4gDQoNCi0gKipraWxvbWV0cmFqZV9wb3JfYcOxbyoqIChjdWFudGl0YXRpdmE6OnJhesOzbik6IEVzdGEgdmFyaWFibGUgZXhwcmVzYSBlbCBwcm9tZWRpbyBkZSBraWzDs21ldHJvcyByZWNvcnJpZG9zIGFudWFsbWVudGUgcG9yIGVsIHZlaMOtY3Vsby4gU2Ugb2J0aWVuZSBkaXZpZGllbmRvIGVsIGtpbG9tZXRyYWplIHRvdGFsIGVudHJlIGxhIGVkYWQgZGVsIGF1dG9tw7N2aWwuIA0KDQotICoqbnVtZXJvX2RlX3Byb3BpZXRhcmlvc19hbnRlcmlvcmVzKiogKGN1YW50aXRhdGl2YTo6cmF6w7NuKTogSW5kaWNhIGN1w6FudGFzIHBlcnNvbmFzIGhhbiBzaWRvIGR1ZcOxYXMgZGVsIHZlaMOtY3VsbyBhbnRlcyBkZWwgcmVnaXN0cm8gYWN0dWFsLiANCg0KLSAqKmVkYWRfZGVsX3ZlaMOtY3VsbyoqIChjdWFudGl0YXRpdmE6OnJhesOzbik6IENvcnJlc3BvbmRlIGFsIG7Dum1lcm8gZGUgYcOxb3MgdHJhbnNjdXJyaWRvcyBkZXNkZSBsYSBmZWNoYSBkZSBmYWJyaWNhY2nDs24gZGVsIHZlaMOtY3VsbyBoYXN0YSBsYSBhY3R1YWxpZGFkLiANCg0KLSAqKnByZWNpbyoqIChjdWFudGl0YXRpdmE6OnJhesOzbik6IEV4cHJlc2EgZWwgcHJlY2lvIGFjdHVhbCBlc3RpbWFkbyBkZWwgdmVow61jdWxvIGVuIGVsIG1lcmNhZG8gZGUgdXNhZG9zLg0KDQotICoqdHJhbnNtaXNpb24qKiAoY3VhbGl0YXRpdmE6Om5vbWluYWwpOiBEZXNjcmliZSBlbCB0aXBvIGRlIHNpc3RlbWEgZGUgY2FtYmlvIGRlIG1hcmNoYXMgZGVsIHZlaMOtY3VsbywgY29kaWZpY2FkbyBjb21vIDEgcGFyYSB0cmFuc21pc2nDs24gbWFudWFsIHkgMCBwYXJhIGF1dG9tw6F0aWNhLiBFc3RhIGVzIGxhIHZhcmlhYmxlIGRlIGRlY2lzacOzbiBxdWUgc2UgaWRlbnRpZmljYSBlbiBlc3RlIGNvbmp1bnRvLg0KDQotICoqbWFyY2FfZGVsX3ZlaGljdWxvKiogKGN1YWxpdGF0aXZhOjpub21pbmFsKTogSWRlbnRpZmljYSBlbCBub21icmUgZGVsIGZhYnJpY2FudGUgZGVsIGF1dG9tw7N2aWwuIA0KDQotICoqYcOxb19kZV9mYWJyaWNhY2lvbioqIChjdWFudGl0YXRpdmE6OnJhesOzbik6IEluZGljYSBlbCBhw7FvIGNhbGVuZGFyaW8gZW4gZWwgcXVlIGVsIHZlaMOtY3VsbyBmdWUgcHJvZHVjaWRvLiANCg0KLSAqKmNvbG9yX2V4dGVyaW9yKiogKGN1YWxpdGF0aXZhOjpub21pbmFsKTogSGFjZSByZWZlcmVuY2lhIGFsIGNvbG9yIHZpc2libGUgZGUgbGEgY2Fycm9jZXLDrWEgZGVsIHZlaMOtY3Vsby4gDQoNCi0gKip0aXBvX2RlX2NvbWJ1c3RpYmxlKiogKGN1YWxpdGF0aXZhOjpub21pbmFsKTogRXNwZWNpZmljYSBlbCB0aXBvIGRlIGVuZXJnw61hIHF1ZSB1dGlsaXphIGVsIHZlaMOtY3VsbyBwYXJhIHN1IGZ1bmNpb25hbWllbnRvLiBMb3MgdmFsb3JlcyBjb211bmVzIGluY2x1eWVuIGdhc29saW5hLCBkacOpc2VsLCBow61icmlkbyB5IGVsw6ljdHJpY28uIA0KDQoNCiMjIyMgRXN0cnVjdHVyYSBkZWwgQ29uanVudG8gZGUgRGF0b3MgRVRMDQoNCmBgYHtyIEVzdHJ1Y3R1cmFfQ29uanVudG9fZGVfRGF0b3NfRGVwdXJhZG8sIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0Kc3RyKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMKQ0KYGBgDQoNCiMjIyMgQ29uanVudG8gZGUgRGF0b3MgT3JpZ2luYWwgRGVwdXJhZG8NCg0KYGBge3IgQ29uanVudG9fZGVfRGF0b3NfRGVwdXJhZG8sIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwNCg0KYGBgDQoNCiMjIyAxLjMuIEVzdGltYWNpb25lcyBtdWx0aXZhcmlhZGFzIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQoNCkVsICoqdmVjdG9yIGRlIG1lZGlhcyoqIHkgbGEgKiptYXRyaXogZGUgdmFyaWFuemFzLWNvdmFyaWFuemFzKiogY29uZm9ybWFuIHVuIGNvbmp1bnRvIGRlIGhlcnJhbWllbnRhcyBmdW5kYW1lbnRhbGVzIHBhcmEgZGVzY3JpYmlyIGVsIGNvbXBvcnRhbWllbnRvIHBvc2ljaW9uYWwsIGRpc3BlcnNpdm8geSBjb3JyZWxhY2lvbmFsIGRlIGxhcyB2YXJpYWJsZXMgYWxlYXRvcmlhcyBlbiB1biBjb25qdW50byBkZSBkYXRvcy4gRXN0YXMgbWVkaWRhcyBzb24gZXNlbmNpYWxlcyBlbiBlbCBhbsOhbGlzaXMgbXVsdGl2YXJpYWRvLCB5YSBxdWUgcGVybWl0ZW4gY2FwdHVyYXIgdGFudG8gbGEgdGVuZGVuY2lhIGNlbnRyYWwgY29tbyBsYXMgaW50ZXJkZXBlbmRlbmNpYXMgZW50cmUgbGFzIHZhcmlhYmxlcy4NCg0KRWwgdmVjdG9yIGRlIG1lZGlhcyByZWZsZWphIGVsIHZhbG9yIGVzcGVyYWRvIG8gcHVudG8gbWVkaW8gZGUgY2FkYSB2YXJpYWJsZSwgc2ludGV0aXphbmRvIGxhIGluZm9ybWFjacOzbiBkZSB0b2RvcyBsb3MgcmVnaXN0cm9zIGRpc3BvbmlibGVzIGVuIGVsIGNvbmp1bnRvIGRlIGRhdG9zLiBQb3Igc3UgcGFydGUsIGxhIG1hdHJpeiBkZSB2YXJpYW56YXMtY292YXJpYW56YXMgZGVzY3JpYmUgbGEgdmFyaWFiaWxpZGFkIHkgbGFzIHJlbGFjaW9uZXMgZW50cmUgbGFzIHZhcmlhYmxlcy4gRW4gc3UgZGlhZ29uYWwgcHJpbmNpcGFsLCBlc3RpbWEgbGFzIGRpc3BlcnNpb25lcyBpbmRpdmlkdWFsZXMgZGUgY2FkYSB2YXJpYWJsZSByZXNwZWN0byBhIHN1IG1lZGlhLCBtaWVudHJhcyBxdWUgbG9zIGVsZW1lbnRvcyBwb3IgZW5jaW1hIG8gcG9yIGRlYmFqbyBkZSBlc3RhIGRpYWdvbmFsIHJlcHJlc2VudGFuIGxhcyBjb3ZhcmlhbnphcyBlbnRyZSBwYXJlcyBkZSB2YXJpYWJsZXMsIG1vc3RyYW5kbyBsYXMgcmVsYWNpb25lcyBsaW5lYWxlcyBleGlzdGVudGVzIGVudHJlIGVsbGFzLg0KDQoNCg0KIyMjIyBWZWN0b3IgZGUgUHJvbWVkaW9zIHkgQm94cGxvdHMgDQoNCmBgYHtyIFZlY3Rvcl9kZV9NZWRpYXNfeV9Cb3hwbG90cywgZmlnLmFsaWduID0gJ2NlbnRlcid9DQphcHBseSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIDIsIG1lYW4pDQp2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF9SZWR1Y2lkbyA9IHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYsMTEsMTIpXQ0Kbm9tYnJlc19ib3hwbG90cyA8LSBjKCJraWxvbWV0cmFqZSIsIkNhbnRfcHJvcGlldGFyaW9zIiwiRWRhZF9WZWjDrWN1bG8iLCJLaWxvbWV0cmFqZV9hw7FvIiwiUHJlY2lvIikNCnBhcihtZnJvdyA9IGMoMSwgbmNvbCh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF9SZWR1Y2lkbykpKQ0KaW52aXNpYmxlKGxhcHBseSgxOm5jb2wodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfUmVkdWNpZG8pLCBmdW5jdGlvbihpKSB7DQogIGJveHBsb3QodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfUmVkdWNpZG9bLCBpXSwNCiAgICAgICAgICBtYWluID0gbm9tYnJlc19ib3hwbG90c1tpXSl9KSkNCg0KYGBgDQoNCg0KIyMjIyBNYXRyaXogZGUgdmFyaWFuemFzLWNvdmFyaWFuemFzDQpgYGB7ciBNYXRyaXpfZGVfdmFyaWFuemFzLWNvdmFyaWFuemFzLCBmaWcuYWxpZ249J2NlbnRlcid9DQpyb3VuZChjb3YodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNiwxMSwxMildKSwyKQ0KYGBgDQoNCiMjIyMgTWF0cml6IGRlIGNvcnJlbGFjaW9uZXMNCmBgYHtyIE1hdHJpel9kZV9jb3JyZWxhY2lvbmVzLCBmaWcuYWxpZ249J2NlbnRlcid9DQpyb3VuZChjb3IodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNiwxMSwxMildKSwzKQ0KYGBgDQoNCiMjIyAxLjQuIFBsYW50ZWFtaWVudG8geSBEZXNhcnJvbGxvIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQoNCkNvbiBiYXNlIGVuIGxhIHBlc3Rhw7FhICoqVmVjdG9yIGRlIE1lZGlhcyoqIHkgKipCb3hwbG90cyoqLCBzZSBwdWVkZSBvYnNlcnZhciBxdWUgbGFzIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzIGFuYWxpemFkYXMgbXVlc3RyYW4gcGF0cm9uZXMgZGUgZGlzdHJpYnVjacOzbiBwYXJ0aWN1bGFyZXMuDQoNCkxhIHZhcmlhYmxlICoqa2lsb21ldHJhamUqKiBwcmVzZW50YSB1bmEgZGlzdHJpYnVjacOzbiBjb24gY29sYSBhIGxhIGRlcmVjaGEsIGxvIHF1ZSBzdWdpZXJlIHF1ZSBsYSBtYXlvcsOtYSBkZSBsb3MgdmVow61jdWxvcyB0aWVuZW4gcmVjb3JyaWRvcyBtb2RlcmFkb3MsIHBlcm8gYWxndW5vcyBwcmVzZW50YW4ga2lsb21ldHJhamVzIG11eSBlbGV2YWRvcyBxdWUgZXh0aWVuZGVuIGxhIGNvbGEgc3VwZXJpb3IuDQoNCkxhIHZhcmlhYmxlICoqQ2FudF9wcm9waWV0YXJpb3MqKiB0aWVuZGUgYSB0b21hciB2YWxvcmVzIGJham9zIGVuIGxhIG1heW9yw61hIGRlIGxvcyBjYXNvcywgeWEgcXVlIGxhIG1heW9yIHBhcnRlIGRlIGxvcyB2ZWjDrWN1bG9zIHN1ZWxlbiB0ZW5lciBwb2NvcyBwcm9waWV0YXJpb3MgcHJldmlvczsgc2luIGVtYmFyZ28sIHRhbWJpw6luIHB1ZWRlbiBhcGFyZWNlciB2YWxvcmVzIGF0w61waWNvcyBhc29jaWFkb3MgYSBhdXRvbcOzdmlsZXMgY29uIG3Dumx0aXBsZXMgdHJhbnNmZXJlbmNpYXMuDQoNCkxhICoqRWRhZF9WZWjDrWN1bG8qKiBwdWVkZSBwcmVzZW50YXIgY2llcnRhIGFzaW1ldHLDrWEgaGFjaWEgbGEgZGVyZWNoYSwgeWEgcXVlIHByZWRvbWluYW4gdmVow61jdWxvcyByZWxhdGl2YW1lbnRlIHJlY2llbnRlcywgbWllbnRyYXMgcXVlIGFsZ3Vub3MgbW9kZWxvcyBtw6FzIGFudGlndW9zIGdlbmVyYW4gbGEgZXh0ZW5zacOzbiBkZSBsYSBjb2xhLg0KDQpFbiBjdWFudG8gYSBsYSB2YXJpYWJsZSAqKktpbG9tZXRyYWplX2HDsW8qKiwgZXN0w6EgZ2VuZXJhbG1lbnRlIHByZXNlbnRhIHVuYSBkaXN0cmlidWNpw7NuIGNvbiBjb2xhIGEgbGEgZGVyZWNoYSwgZGFkbyBxdWUgbGEgbWF5b3LDrWEgZGUgbG9zIHZlaMOtY3Vsb3MgdGllbmVuIHVuIHVzbyBhbnVhbCBtb2RlcmFkbywgcGVybyBhbGd1bm9zIHJlZ2lzdHJhbiB1biB1c28gbXV5IGludGVuc2l2byBxdWUgaW5jcmVtZW50YSBub3RhYmxlbWVudGUgbG9zIHZhbG9yZXMgc3VwZXJpb3Jlcy4NCg0KRmluYWxtZW50ZSwgbGEgdmFyaWFibGUgKipQcmVjaW8qKiB0YW1iacOpbiBwdWVkZSBtb3N0cmFyIHVuYSBsaWdlcmEgY29sYSBoYWNpYSBsYSBkZXJlY2hhLCBpbmRpY2FuZG8gcXVlIGxhIG1heW9yw61hIGRlIGxvcyB2ZWjDrWN1bG9zIHNlIGNvbmNlbnRyYW4gZW4gcmFuZ29zIGRlIHByZWNpb3MgbWVkaW9zLCBtaWVudHJhcyBxdWUgdW5vcyBwb2NvcywgY29uIGNhcmFjdGVyw61zdGljYXMgcGFydGljdWxhcmVzIG8gZ2FtYXMgc3VwZXJpb3JlcywgZWxldmFuIGxhIGNvbGEgc3VwZXJpb3IgZGUgbGEgZGlzdHJpYnVjacOzbi4NCg0KQ29uIGJhc2UgZW4gbGEgKiptYXRyaXogZGUgdmFyaWFuemFzLWNvdmFyaWFuemFzKiogeSBsYSAqKm1hdHJpeiBkZSBjb3JyZWxhY2lvbmVzKiosIHNlIGlkZW50aWZpY2EgcXVlIGxhcyByZWxhY2lvbmVzIGxpbmVhbGVzIGVudHJlIGxhcyB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcyBzdWVsZW4gc2VyIGRlIGJhamEgYSBtb2RlcmFkYSBpbnRlbnNpZGFkLg0KDQpFcyBjb23Dum4gcXVlIHZhcmlhYmxlcyBjb21vICoqa2lsb21ldHJhamUqKiB5ICoqRWRhZF9WZWjDrWN1bG8qKiBwcmVzZW50ZW4gdW5hIGNvcnJlbGFjacOzbiBwb3NpdGl2YSwgeWEgcXVlIGxvcyB2ZWjDrWN1bG9zIG3DoXMgYW50aWd1b3MgdGllbmRlbiBhIGhhYmVyIHJlY29ycmlkbyBtYXlvcmVzIGRpc3RhbmNpYXMuDQoNClBvciBvdHJvIGxhZG8sIHZhcmlhYmxlcyBjb21vICoqUHJlY2lvKiogcHVlZGVuIG1vc3RyYXIgY29ycmVsYWNpb25lcyBtb2RlcmFkYXMgbyBkw6liaWxlcyBjb24gKipLaWxvbWV0cmFqZV9hw7FvKiogbyAqKkNhbnRfcHJvcGlldGFyaW9zKiosIGxvIHF1ZSBzdWdpZXJlIHF1ZSBzdSBpbmZsdWVuY2lhIGRpcmVjdGEgbm8gZXMgZXN0cmljdGFtZW50ZSBsaW5lYWwuDQoNCkVuIGdlbmVyYWwsIGxvcyBjb2VmaWNpZW50ZXMgZGUgY29ycmVsYWNpw7NuIGNlcmNhbm9zIGEgY2VybyBpbmRpY2FuIHF1ZSAqKm5vIGV4aXN0ZW4gcmVsYWNpb25lcyBsaW5lYWxlcyBmdWVydGVzKiogZW50cmUgbGFzIHZhcmlhYmxlcywgcG9yIGxvIHF1ZSBzdXMgZWZlY3RvcyBtdXR1b3Mgc29uIGxpbWl0YWRvcy4gRXN0byBhYnJlIGxhIHBvc2liaWxpZGFkIGRlIGludGVyYWNjaW9uZXMgbm8gbGluZWFsZXMgbyBkZSBxdWUgY2FkYSB2YXJpYWJsZSBjYXB0dXJlIGRpbWVuc2lvbmVzIGRpc3RpbnRhcyBkZWwgZXN0YWRvLCBoaXN0b3JpYWwgeSB2YWxvciBkZWwgdmVow61jdWxvLiBFc3RvcyBhc3BlY3RvcyBzZSBleHBsb3JhbiBjb24gbWF5b3IgZGV0YWxsZSBlbiBsYSBbc2VjY2nDs24gMS41XSgjc2VjMS41KSANCg0KIyMjIDEuNS4gR3LDoWZpY2FzIG11bHRpdmFyaWFkYXMgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KRW4gZ2VuZXJhbCwgbG9zICoqZ3LDoWZpY29zIG11bHRpdmFyaWFkb3MqKiBjdW1wbGVuIGRvcyBvYmpldGl2b3MgZXNlbmNpYWxlczogcHJpbWVybywgYXl1ZGFuIGEgY29tcGFyYXIgZWwgY29tcG9ydGFtaWVudG8gZGUgcG9ibGFjaW9uZXMgZGUgZXN0dWRpbyBjb24gYmFzZSBlbiB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzIHkgZmFjaWxpdGFuIGxhIGNvbXByZW5zacOzbiBkZSBsYSBlc3RydWN0dXJhIGRlIGNvcnJlbGFjacOzbiBlbnRyZSB2YXJpYXMgdmFyaWFibGVzLiBBZGVtw6FzLCBwZXJtaXRlbiBpZGVudGlmaWNhciBwYXRyb25lcywgdGVuZGVuY2lhcywgeSBwb3NpYmxlcyBvdXRsaWVycyBlbiBsb3MgZGF0b3MsIHNpbXBsaWZpY2FuZG8gbGEgaW50ZXJwcmV0YWNpw7NuIGRlIHJlbGFjaW9uZXMgY29tcGxlamFzIHkgZGVzdGFjYW5kbyBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBtw6FzIHNpZ25pZmljYXRpdmFzIGRlIGxvcyBtaXNtb3MgKEFsZMOhcywgMjAxNykuIEVuIGVzdGUgc2VudGlkbywgZWwgY29uanVudG8gZGUgZGF0b3MgZGUgdHJhYmFqbyB0ZW5kcsOhIGFwb3lvIGRlc2NyaXB0aXZvIGdyw6FmaWNvIGEgdHJhdsOpcyBkZSB0cmVzIGRpYWdyYW1hczogdW5vIGNvbmp1bnRvIHF1ZSBpbnRlZ3JhIGRpc3BlcnNpw7NuLCBkaXN0cmlidWNpw7NuIHkgY29ycmVsYWNpb25lczsgb3RybyBiYXNhZG8gZW4gbGEgcmVuZGVyaXphY2nDs24gZGUgcG9sw61nb25vczsgeSwgcG9yIMO6bHRpbW8sIHVubyBxdWUgcmVjdXJyZSBhIGxhcyBjYXJhcyBkZSBDaGVybm9mZi4NCg0KDQojIyMjIERpYWdyYW1hIENvbmp1bnRvIGRlIERpc3BlcnNpw7NuLCBEaXN0cmlidWNpw7NuIHkgQ29ycmVsYWNpb25lcyBbU0FdDQpgYGB7ciBEaWFncmFtYV9DRF92ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb24sIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZ2dwYWlycyh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0pDQpgYGANCg0KDQojIyMjIERpYWdyYW1hIENvbmp1bnRvIGRlIERpc3BlcnNpw7NuLCBEaXN0cmlidWNpw7NuIHkgQ29ycmVsYWNpb25lcyBbQ0FdDQpgYGB7ciBEaWFncmFtYV9kaXNwZXJzaW9uX2dlbmRlciwgZmlnLmFsaWduPSdjZW50ZXInfQ0KdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdHJhbnNtaXNpb24gPC0gZmFjdG9yKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRyYW5zbWlzaW9uKQ0KbGV2ZWxzPSBjICgwLDEpDQpsYWJlbHM9IGMgKCAiYXV0b21hdGljbyIgLCAibWFudWFsIikNCmdncGFpcnModmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwsIGNvbHVtbiA9IGMoMyw3LDgsOSwxMCksIGFlcyhjb2xvciA9IHRyYW5zbWlzaW9uLCBhbHBoYSA9IDAuNSksIHVwcGVyID0gbGlzdChjb250aW51b3VzID0gd3JhcCgiY29yIiwgc2l6ZSA9IDIuNSkpKQ0KDQpgYGANCg0KDQojIyMjIERpYWdyYW1hIGRlIEVzdHJlbGxhcw0KYGBge3IgRGlhZ3JhbWFfZGVfRXN0cmVsbGFzLCBmaWcuYWxpZ249J2NlbnRlcid9DQpzZXQuc2VlZCgwNTE4MDIpDQp2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2FkbyA9IHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMW3NhbXBsZSgxOm5yb3codmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwpLDIzKSwtYygxLDIsNCw1LDYsMTEsMTIpXQ0Kc3RhcnModmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG8sIGxlbiA9IDEsIGNleCA9IDAuNCwga2V5LmxvYyA9IGMoMTAsIDIpLCBkcmF3LnNlZ21lbnRzID0gVFJVRSkNCmBgYA0KDQojIyMjIGNhcmFzIGRlIGNoZXJub2ZmDQpgYGB7ciBjYXJhc19kZV9jaGVybm9mZiwgZmlnLmFsaWduPSdjZW50ZXInfQ0Kc2V0LnNlZWQoMDUxODAyKQ0KdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG8gPSB2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCBbc2FtcGxlKDE6bnJvdyh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCksMjMpLC1jKDEsMiw0LDUsNiwxMSwxMildDQpmYWNlcyh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2FkbykNCmBgYA0KDQojIyMgMS42LiBOb3JtYWxpZGFkIG11bHRpdmFyaWFkYSB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFcyBwb3NpYmxlIGFuYWxpemFyIG8gZGV0ZXJtaW5hciBsYSBkaXN0cmlidWNpw7NuIG11bHRpdmFyaWFkYSBkZSB1biBjb25qdW50byBkZSBkYXRvcyBtZWRpYW50ZSBtw6l0b2RvcyBkZXNjcmlwdGl2b3MsIGNvbW8gbG9zIGdyw6FmaWNvcywgbyBpbmZlcmVuY2lhbGVzLCBjb21vIGxhcyBwcnVlYmFzIGVzdGFkw61zdGljYXMuIE1pZW50cmFzIHF1ZSBsb3MgcHJvY2VkaW1pZW50b3MgaW5mZXJlbmNpYWxlcyBwZXJtaXRlbiBvYnRlbmVyIGNvbmNsdXNpb25lcyBtw6FzIGdlbmVyYWxpemFibGVzLCBsb3MgZ3LDoWZpY29zIHJlc3VsdGFuIMO6dGlsZXMgY29tbyBzb3BvcnRlIHBhcmEgbGEgaW50ZXJwcmV0YWNpw7NuIGRlIGxvcyByZXN1bHRhZG9zLg0KDQpFbiBlc3RlIGFwYXJ0YWRvIHNlIGFib3JkYSBsYSBhcGxpY2FjacOzbiBkZSBwcm9jZWRpbWllbnRvcyBpbmZlcmVuY2lhbGVzIHBhcmEgdmVyaWZpY2FyIHNpIGVsIGNvbmp1bnRvIGRlIGRhdG9zIGRlIHRyYWJham8sIHJlc3BlY3RvIGEgc3VzIHZhcmlhYmxlcyBudW3DqXJpY2FzLCBzaWd1ZSB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwgbXVsdGl2YXJpYWRhIChETk0pLiBMYXMgcHJ1ZWJhcyBkZSBub3JtYWxpZGFkIG11bHRpdmFyaWFkYSAoUE5NKSBxdWUgc2UgYXBsaWNhcsOhbiBzb246IE1hcmRpYSwgSGVuemUtWmlya2xlciwgRG9vcm5pay1IYW5zZW4geSBSb3lzdG9uLiBFc3RhcyBwcnVlYmFzIGRlIG5vcm1hbGlkYWQgc2UgcmVhbGl6YW4gYmFqbyB1biBuaXZlbCBkZSBzaWduaWZpY2FuY2lhIGRldGVybWluYWRvICRcYWxwaGEgPSAwLjA1JCB5IGEgbGFzIGhpcMOzdGVzaXM6JCRIXzA6IFx0ZXh0IHtMYXMgdmFyaWFibGVzIHRpZW5lbiB1bmEgRE5NfSQkICQkSF8xOiBcdGV4dCB7TGFzIHZhcmlhYmxlcyBOTyB0aWVuZW4gdW5hIEROTX0kJCANCg0KTGEgKipwcnVlYmEgZGUgTWFyZGlhKiogc2UgZnVuZGFtZW50YSBlbiBsYXMgZXh0ZW5zaW9uZXMgZGUgYXNpbWV0csOtYSB5IGN1cnRvc2lzLCBlbCBjdWFkcmFkbyBkZSBsYSBkaXN0YW5jaWEgZGUgTWFoYWxhbm9iaXMsIGVsIG7Dum1lcm8gZGUgdmFyaWFibGVzICRwJCBhIGFuYWxpemFyIHkgZWwgbsO6bWVybyBkZSByZWdpc3Ryb3MgJG4kLiBBc2ltaXNtbywgc2UgY29uc2lkZXJhIHF1ZSBsYSBlc3RhZMOtc3RpY2EgZGUgbGEgcHJ1ZWJhIHBhcmEgbGEgYXNpbWV0csOtYSBzaWd1ZSB1bmEgZGlzdHJpYnVjacOzbiAkXGNoaV4yJCwgbWllbnRyYXMgcXVlIGxhIGVzdGFkw61zdGljYSBwYXJhIGxhIGN1cnRvc2lzIHNlIGRpc3RyaWJ1eWUgZGUgbWFuZXJhIGFwcm94aW1hZGEgZGUgZm9ybWEgbm9ybWFsLiANCg0KTGEgKipwcnVlYmEgZGUgSGVuemUtWmlya2xlcioqIHNlIGJhc2EgZW4gbGEgZGlzdGFuY2lhIGZ1bmNpb25hbCwgeWEgcXVlIHNpIGVsIGNvbmp1bnRvIGRlIGRhdG9zIHNpZ3VlIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbCBtdWx0aXZhcmlhZGEsIGVsIGVzdGFkw61zdGljbyBkZSBsYSBwcnVlYmEgc2UgZGlzdHJpYnV5ZSBkZSBtYW5lcmEgYXByb3hpbWFkYSBjb21vIHVuYSBsb2dub3JtYWwsIGNvbiBwYXLDoW1ldHJvcyBkZSBtZWRpYSAkXG11JCB5IHZhcmlhbnphICRcc2lnbWFeMiQuIA0KDQpMYSAqKnBydWViYSBkZSBCb3dtYW4gYW5kIFNoZW50b24qKiBzZSBiYXNhIGVuIGxhIGFzaW1ldHLDrWEgeSBsYSBjdXJ0b3NpcyBkZSB1biBjb25qdW50byBkZSBkYXRvcyBtdWx0aXZhcmlhZG9zLCBsb3MgY3VhbGVzIHNlIHRyYW5zZm9ybWFuIHBhcmEgYXNlZ3VyYXIgbGEgaW5kZXBlbmRlbmNpYS4gU2UgY29uc2lkZXJhIG3DoXMgcG90ZW50ZSBxdWUgbGEgcHJ1ZWJhIGRlIFpob3UtU2hhbyBlbiBjYXNvcyBtdWx0aXZhcmlhZG9zLiBFbCBlc3RhZMOtc3RpY28gZGUgbGEgcHJ1ZWJhIHNlIGRlZmluZSBjb21vIGxhIHN1bWEgZGUgbGFzIHRyYW5zZm9ybWFjaW9uZXMgYWwgY3VhZHJhZG8gZGUgbGEgYXNpbWV0csOtYSB5IGxhIGN1cnRvc2lzLCB5IHNpZ3VlIGFwcm94aW1hZGFtZW50ZSB1bmEgZGlzdHJpYnVjacOzbiAkXGNoaV4yJC4gDQoNClBvciBvdHJvIGxhZG8sIGxhICoqcHJ1ZWJhIGRlIFpob3UtU2hhbyoqIGVzIHVuYSBwcnVlYmEgc2VuY2lsbGEgeSBhIGxhIHZleiBtdXkgZWZpY2F6IHBhcmEgZXZhbHVhciBsYSBub3JtYWxpZGFkIG11bHRpdmFyaWFudGUsIGNvbWJpbmEgbGEgY3VydG9zaXMgbXVsdGl2YXJpYW50ZSAoTUspIGNvbiBlbCB0ZXN0IGRlIFNoYXBpcm8tV2lsaywgc2Vnw7puIGxhIHByb3B1ZXN0YSBkZSBaaG91IHkgU2hhbyAoMjAxNCkuIEVsIHZhbG9yIHAgZGVsIGVzdGFkw61zdGljbyBkZSBwcnVlYmEgKFRuKSBzZSBvYnRpZW5lIG1lZGlhbnRlIHVuYSBkaXN0cmlidWNpw7NuIG51bGEgc2ltdWxhZGEgZXNwZWPDrWZpY2FtZW50ZSBwYXJhIFRuLiBQYXJhIG3DoXMgaW5mb3JtYWNpw7NuLCBzZSBwdWVkZSBjb25zdWx0YXIgZWwgdHJhYmFqbyBkZSBaaG91IHkgU2hhbyAoMjAxNCkuDQoNCiMjIyAxLjcuUGxhbnRlYW1pZW50byB5IERlc2Fycm9sbG97LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpDb24gYmFzZSBlbiBsYSAqKm1hdHJpeiBkZSB2YXJpYW56YXMtY292YXJpYW56YSoqLCBsYSAqKm1hdHJpeiBkZSBjb3JyZWxhY2lvbmVzKiogeSBlbCAqKmRpYWdyYW1hIGRlIGRpc3BlcnNpw7NuKiosIHNlIGNvbmNsdXllIHF1ZSBsYXMgcmVsYWNpb25lcyBlbnRyZSBsYXMgdmFyaWFibGVzIGN1YW50aXRhdGl2YXMgYW5hbGl6YWRhcyBlbiBlbCBjb25qdW50byBkZSBkYXRvcyBzb2JyZSB2ZWjDrWN1bG9zIHNvbiwgZW4gc3UgbWF5b3LDrWEsIGTDqWJpbGVzIG8gbW9kZXJhZGFzLiBQb3IgZWplbXBsbywgbGEgY29ycmVsYWNpw7NuIGVudHJlICoqa2lsb21ldHJhamUqKiB5ICoqYW50aWfDvGVkYWQgZGVsIHZlaMOtY3VsbyoqIGVzIGRlIDAuNzg0LCBsbyBxdWUgaW5kaWNhIHVuYSByZWxhY2nDs24gbGluZWFsIHBvc2l0aXZhIHJlbGF0aXZhbWVudGUgZnVlcnRlOyBtaWVudHJhcyBxdWUgbGEgY29ycmVsYWNpw7NuIGVudHJlICoqcHJlY2lvKiogeSAqKmtpbG9tZXRyYWplKiogZXMgZGUg4oCTMC42MTUsIGluZGljYW5kbyBxdWUgYSBtYXlvciBraWxvbWV0cmFqZSwgbWVub3IgcHJlY2lvLCByZWZsZWphbmRvIGVsIGVmZWN0byBkZSBsYSBkZXByZWNpYWNpw7NuLg0KDQpFbCBkaWFncmFtYSBjb25qdW50byBkZSBkaXNwZXJzacOzbiwgZGlzdHJpYnVjacOzbiB5IGNvcnJlbGFjaW9uZXMgcmVmdWVyemEgZXN0YXMgb2JzZXJ2YWNpb25lcywgbW9zdHJhbmRvIGRpc3BlcnNpw7NuIHkgcGF0cm9uZXMgY2xhcm9zIMO6bmljYW1lbnRlIGVudHJlIGFsZ3VuYXMgdmFyaWFibGVzIGVzcGVjw61maWNhcywgY29tbyBraWxvbWV0cmFqZSB5IGFudGlnw7xlZGFkLiBFbiBnZW5lcmFsLCBlc3RhcyBtw6l0cmljYXMgc3VnaWVyZW4gcXVlIG5vIHRvZGFzIGxhcyB2YXJpYWJsZXMgcHJlc2VudGFuIHJlbGFjaW9uZXMgbGluZWFsZXMgZnVlcnRlcywgbG8gcXVlIHBvZHLDrWEgaW5kaWNhciBsYSBuZWNlc2lkYWQgZGUgZXhwbG9yYXIgaW50ZXJhY2Npb25lcyBubyBsaW5lYWxlcyBvIGZhY3RvcmVzIGV4dGVybm9zIChjb21vIHRpcG8gZGUgbWFyY2EgbyB0aXBvIGRlIGNvbWJ1c3RpYmxlKSBwYXJhIGNvbXByZW5kZXIgbWVqb3IgbGFzIHBvc2libGVzIGFzb2NpYWNpb25lcyBlbnRyZSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBkZWwgdmVow61jdWxvIHkgc3UgcHJlY2lvLiBQYXJhIG3DoXMgZGV0YWxsZXMsIHNlIHB1ZWRlIGNvbnN1bHRhciBlbCBhbsOhbGlzaXMgZGUgcmVncmVzacOzbiBkZXNhcnJvbGxhZG8gc29icmUgZWwgbWlzbW8gY29uanVudG8gZGUgZGF0b3MgZW4gbGEgc2VjY2nDs24gNS4NCg0KQ3VhbmRvIHNlIG9ic2VydmEgZWwgRGlhZ3JhbWEgQ29uanVudG8gZGUgRGlzcGVyc2nDs24sIERpc3RyaWJ1Y2nDs24geSBDb3JyZWxhY2lvbmVzIGVuIHN1IHZlcnNpw7NuIGJhc2FkYSBlbiBncnVwb3MgYSBwYXJ0aXIgZGUgbGEgdmFyaWFibGUgY2F0ZWfDs3JpY2EgdHJhbnNtaXNpw7NuLCBzZSBwdWVkZSBhcHJlY2lhciBxdWUgY29tcGFyYXRpdmFtZW50ZSBsYSBkaWZlcmVuY2lhY2nDs24gcG9yIHRpcG8gZGUgdHJhbnNtaXNpw7NuIG5vIG11ZXN0cmEgcmVsZXZhbmNpYSBwYXJhIGV4cGxpY2FyIGRlIG1hbmVyYSBzaWduaWZpY2F0aXZhIGxhIHZhcmlhYmlsaWRhZCBlbiBwcmVjaW8gbyBraWxvbWV0cmFqZSwgeWEgcXVlIGxhcyBkaXN0cmlidWNpb25lcyB5IGNvcnJlbGFjaW9uZXMgZGVudHJvIGRlIGNhZGEgZ3J1cG8gc29uIG11eSBzaW1pbGFyZXMuDQoNCkVuIGVsIGRpYWdyYW1hIGRlIGVzdHJlbGxhcywgc2Ugb2JzZXJ2YSBxdWUgbGFzIGZvcm1hcyBkZSBsb3MgcG9sw61nb25vcyBzb24gaGV0ZXJvZ8OpbmVhcywgbG8gcXVlIGV2aWRlbmNpYSBsYSBhbHRhIHZhcmlhYmlsaWRhZCBlbiBsYXMgb2JzZXJ2YWNpb25lcywgZXNwZWNpYWxtZW50ZSBlbiBsYXMgdmFyaWFibGVzIGRlIGtpbG9tZXRyYWplLCBhbnRpZ8O8ZWRhZCB5IHByZWNpby4gTm8gc2UgYXByZWNpYSBsYSBmb3JtYWNpw7NuIGRlIGdydXBvcyBjbGFyb3MsIGxvIHF1ZSBpbmRpY2EgcXVlIGxvcyB2ZWjDrWN1bG9zIGRlbCBjb25qdW50byBwcmVzZW50YW4gY29tYmluYWNpb25lcyBkaXZlcnNhcyBkZSBjYXJhY3RlcsOtc3RpY2FzLg0KDQpFbiBlbCBkaWFncmFtYSBkZSBsYXMgQ2FyYXMgZGUgQ2hlcm5vZmYgbm8gc2UgYXByZWNpYSBjb24gY2xhcmlkYWQgbGEgZm9ybWFjacOzbiBkZSBncnVwb3MgZW50cmUgbG9zIHZlaMOtY3Vsb3MgY29uIGNhcmFjdGVyw61zdGljYXMgc2ltaWxhcmVzLCBsbyBxdWUgZGlmaWN1bHRhIGlkZW50aWZpY2FyIHBhdHJvbmVzIGNvbnNpc3RlbnRlcyBkZW50cm8gZGVsIGNvbmp1bnRvLiBFc3RvIHNlIGRlYmUgYSBxdWUgbGFzIGRpZmVyZW5jaWFzIGVuIGxhcyByZXByZXNlbnRhY2lvbmVzIGZhY2lhbGVzIG5vIHNvbiBsbyBzdWZpY2llbnRlbWVudGUgY29uc2lzdGVudGVzIGNvbW8gcGFyYSBnZW5lcmFyIGFncnVwYW1pZW50b3MgZGVmaW5pZG9zLiBTaW4gZW1iYXJnbywgZGUgbG9ncmFyc2UgdW5hIGFncnVwYWNpw7NuLCBwb2Ryw61hbiBpZGVudGlmaWNhcnNlIHBhcmVzIGNvbW8gbGFzIGNhcmFzIDYgeSAxOCwgYXPDrSBjb21vIDIgeSAxMiwgcXVlIG11ZXN0cmFuIGNpZXJ0b3Mgbml2ZWxlcyBkZSBzaW1pbGl0dWQsIHBvc2libGVtZW50ZSByZWZsZWphbmRvIHZlaMOtY3Vsb3MgY29uIGNhcmFjdGVyw61zdGljYXMgc2ltaWxhcmVzIGVuIGFudGlnw7xlZGFkLCBraWxvbWV0cmFqZSB5IHByZWNpby4NCg0KDQoNCiMjIyMgUE5NIE1hcmRpYQ0KYGBge3IgUE5NX01hcmRpYSwgZmlnLmFsaWduPSdjZW50ZXInfQ0Kc2V0LnNlZWQoMDUxODAyKQ0KdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfNUsgPSANCnZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMW3NhbXBsZSgxOm5yb3codmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwpLDUwMDApLC1jKDEsMiw0LDUsNiwxMSwxMildDQoNCm1hcmRpYSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF81SykNCg0KYGBgDQoNCiMjIyMgUE5NIEhlbnplLVppcmtsZXINCmBgYHtyIFBOTV9IZW56ZS1aaXJrbGVyLCBmaWcuYWxpZ249J2NlbnRlcid9DQptaHoodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfNUspDQpgYGANCg0KIyMjIyBQTk0gQm93bWFuIGFuZCBTaGVudG9uDQpgYGB7ciBQTk1fRG9vcm5pa19IYW5zZW4sIGZpZy5hbGlnbj0nY2VudGVyJ30NCm1zayh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF81SywgMTApDQpgYGANCg0KIyMjIyBQTk0gWmhvdS1TaGFvDQpgYGB7ciBQTk1fUm95c3RvbiwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQptdm5UZXN0KHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMXzVLLCAxMCkNCmBgYA0KDQojIyMgMS44LiBJbnRlcnByZXRhY2nDs24gbm9ybWFsaWRhZCBtdWx0aXZhcmlhZGEgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KU2UgZXZhbHXDsyBsYSBub3JtYWxpZGFkIG11bHRpdmFyaWFkYSBkZSBsYXMgdmFyaWFibGVzIGN1YW50aXRhdGl2YXMgYXBsaWNhbmRvIGxhcyBwcnVlYmFzIGRlICoqUE5NIE1hcmRpYSoqLCAqKlBOTSBIZW56ZeKAk1ppcmtsZXIqKiwqKlBOTSBCb3dtYW4gYW5kIFNoZW50b24qKiB5ICoqUE5NIFpob3XigJNTaGFvKiosIHRvZGFzIGJham8gdW4gbml2ZWwgZGUgc2lnbmlmaWNhbmNpYSAkXGFscGhhPTAuMDUkLiBMYXMgaGlww7N0ZXNpcyBjb25zaWRlcmFkYXMgZnVlcm9uOg0KSOKCgDogZWwgdmVjdG9yIGRlIHZhcmlhYmxlcyBzaWd1ZSB1bmEgRGlzdHJpYnVjacOzbiBOb3JtYWwgTXVsdGl2YXJpYWRhIChETk0pLg0KSOKCgTogZWwgdmVjdG9yIGRlIHZhcmlhYmxlcyBubyBzaWd1ZSB1bmEgRE5NLg0KDQpMYSAqKlBOTSBNYXJkaWEqKiBFdmFsw7phIHNpbXVsdMOhbmVhbWVudGUgc2kgbGEgZGlzdHJpYnVjacOzbiBjb25qdW50YSBwcmVzZW50YSBhc2ltZXRyw61hIChza2V3bmVzcykgeSBjdXJ0b3NpcyhrdXJ0b3NpcykgY29tcGF0aWJsZXMgY29uIHVuYSBETk0uDQpMb3MgJHAtdmFsdWVzJCBvYnRlbmlkb3MgZnVlcm9uIG1lbm9yZXMgYSAkXGFscGhhPTAuMDUkIGVuIGFtYm9zIGNvbXBvbmVudGVzLCBsbyBxdWUgaW5kaWNhIGRlc3ZpYWNpb25lcyBzaWduaWZpY2F0aXZhcyBlbiBsYSBmb3JtYSBkZSBsYSBkaXN0cmlidWNpw7NuIChhc2ltZXRyw61hIG1hcmNhZGEgeSBjdXJ0b3NpcyBkaWZlcmVudGUgYSBsYSBub3JtYWwpLiBFc3RvIGxsZXZhIGEgcmVjaGF6YXIgbGEgbm9ybWFsaWRhZCBtdWx0aXZhcmlhZA0KDQpMYSAqKkhlbnplLVppcmtsZXIqKiBDb25zaWRlcmFkYSB1bmEgZGUgbGFzIHBydWViYXMgbcOhcyByb2J1c3RhcywgZXZhbMO6YSBsYSBkaXN0YW5jaWEgZW50cmUgbGEgZGlzdHJpYnVjacOzbiBvYnNlcnZhZGEgeSBsYSBub3JtYWwgbXVsdGl2YXJpYWRhIGVzcGVyYWRhLg0KRWwgcmVzdWx0YWRvIG1vc3Ryw7MgdW4gJHAtdmFsdWUkIG1lbm9yIHF1ZSAkXGFscGhhPTAuMDUkLCBjb25maXJtYW5kbyBxdWUgbG9zIGRhdG9zIG5vIHNlIGFqdXN0YW4gYSB1bmEgRE5NLiBFc3RvIHJlZnVlcnphIGxhIHByZXNlbmNpYSBkZSByZWxhY2lvbmVzIG5vIG5vcm1hbGVzIGVudHJlIGxhcyB2YXJpYWJsZXMuDQoNCkVuIGVsIGNhc28gZGUgbGEgKipQTk0gQm93bWFuIGFuZCBTaGVudG9uKiogRXhhbWluYSBjb25qdW50YW1lbnRlIGFzaW1ldHLDrWEgeSBjdXJ0b3NpcyBlbiBlbCB2ZWN0b3IgbXVsdGl2YXJpYWRvLg0KVGFtYmnDqW4gYXJyb2rDsyB2YWxvcmVzIHNpZ25pZmljYXRpdm9zICRwLXZhbHVlJCBtZW5vciBxdWUgJFxhbHBoYT0wLjA1JCwgaW5kaWNhbmRvIGRlc3ZpYWNpb25lcyBzaXN0ZW3DoXRpY2FzIHJlc3BlY3RvIGEgbGEgbm9ybWFsaWRhZC4NCg0KRmluYWxtZW50ZSwgbGEgKipQTk0gWmhvdS1TaGFvKiogUHJ1ZWJhIG5vIHBhcmFtw6l0cmljYSBkaXNlw7FhZGEgcGFyYSBkZXRlY3RhciBkZXN2aWFjaW9uZXMgZnVlcnRlcyBlbiBsYSBlc3RydWN0dXJhIGNvbmp1bnRhIGRlIGxvcyBkYXRvcy4NCkxvcyByZXN1bHRhZG9zIGZ1ZXJvbiBzaWduaWZpY2F0aXZvcywgbG8gcXVlIGNvbmZpcm1hIG51ZXZhbWVudGUgZWwgcmVjaGF6byBkZSBI4oKALg0KDQpFbiBzw61udGVzaXMsIHBhcmEgZWwgbml2ZWwgZGUgc2lnbmlmaWNhbmNpYSBjb25zaWRlcmFkbyAkXGFscGhhID0gMC4wNSQsIG5pbmd1bmEgZGUgbGFzIHBydWViYXMgYXBsaWNhZGFzIGFwb3lhIGxhIGhpcMOzdGVzaXMgbnVsYSBkZSBub3JtYWxpZGFkIG11bHRpdmFyaWFkYSwgcG9yIGxvIHF1ZSBzZSBhY2VwdGEgbGEgaGlww7N0ZXNpcyBhbHRlcm5hdGl2YTogZWwgY29uanVudG8gZGUgZGF0b3MsIGVuIHTDqXJtaW5vcyBkZSBzdXMgdmFyaWFibGVzIG51bcOpcmljYXMsIG5vIHByb3ZpZW5lIGRlIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbCBtdWx0aXZhcmlhZGEuDQoNCiMjICoqRkFTRSAyIFtDT01QT05FTlRFUyBQUklOQ0lQQUxFU10qKg0KDQpFbiBlc3RhICoqc2VndW5kYSBldGFwYSoqIGRlbCBlc3R1ZGlvLCBzZSBwcmVzZW50YXLDoW4gY8OhbGN1bG9zLCB2aXN1YWxpemFjaW9uZXMgZSBpbnRlcnByZXRhY2lvbmVzIGJhc2FkYXMgZW4gZWwgY29uanVudG8gZGUgZGF0b3MgYW5hbGl6YWRvIHByZXZpYW1lbnRlIGVuIGxhIFtGYXNlIDFdKCNzZWMxKS4gQWhvcmEsIGVsIGVuZm9xdWUgc2UgY2VudHJhcsOhIGVuIGVsIGFuw6FsaXNpcyBkZSBjb21wb25lbnRlcyBwcmluY2lwYWxlcyAoQUNQKSBhcGxpY2FkbyBhIGxhcyB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcywgaW5jbHV5ZW5kbyBhc3BlY3RvcyBjb21vIGxhIHNlbGVjY2nDs24gZGUgY29tcG9uZW50ZXMsIGNhbGlkYWQgZGUgcmVwcmVzZW50YWNpw7NuLCBjb250cmlidWNpb25lcyB5IHN1IGludGVycHJldGFjacOzbi4NCg0KIyMjIDIuMS4gT2JqZXRpdm9zDQoNCkVsICoqQUNQKiogc2UgbG9ncmEgYSBsbyBsYXJnbyBkZSBsYXMgc2lndWllbnRlcyBmYXNlczogZ2VuZXJhY2nDs24gZGUgbnVldmFzIHZhcmlhYmxlcywgcmVkdWNjacOzbiBkaW1lbnNpb25hbCBkZWwgZXNwYWNpbyBkZSBsb3MgZGF0b3MsIGVsaW1pbmFjacOzbiBkZSB2YXJpYWJsZXMgZGUgcG9jbyBhcG9ydGUgZSBpbnRlcnByZXRhY2nDs24gZGUgbG9zIGNvbXBvbmVudGVzIHJlc3VsdGFudGVzIGVuIGVsIGNvbnRleHRvIGRlbCBwcm9ibGVtYSBkZWwgY3VhbCBzZSBvYnR1dmllcm9uIGxvcyBkYXRvLg0KDQpFc3RpbWFkbyBsZWN0b3IsIHNpIGRlc2VhIGV4cGxvcmFyIGxvcyBmdW5kYW1lbnRvcyBkZSBlc3RlIGFuw6FsaXNpcyBjb24gbWF5b3IgcHJvZnVuZGlkYWQuIExvcyBkZXRhbGxlcyBkZWwgY29uanVudG8gZGUgZGF0b3Mgc2UgZW5jdWVudHJhbiBkZXNjcml0b3MgZW4gbGEgW1NlY2Npw7NuIDEuMl0oI3NlYzEuMiksIG1pZW50cmFzIHF1ZSBsb3MgcHJpbmNpcGlvcyB0ZcOzcmljb3MgcXVlIHN1c3RlbnRhbiBlc3RlIGVzdHVkaW8gZXN0w6FuIGN1aWRhZG9zYW1lbnRlIGRlc2Fycm9sbGFkb3MgZW4gbGEgW0Zhc2UgMV0oI3NlYzEpLiBVbmEgbGVjdHVyYSBkZXRlbmlkYSBkZSBlc3RhcyBzZWNjaW9uZXMgZW5yaXF1ZWNlcsOhIHN1IGNvbXByZW5zacOzbiB5IGFwcmVjaWFjacOzbiBkZWwgdHJhYmFqbyBwcmVzZW50YWRvLg0KDQojIyMgMi4yLiBTZWxlY2Npw7NuIGRlIENvbXBvbmVudGVzIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQoNCkVsIEFuw6FsaXNpcyBkZSBDb21wb25lbnRlcyBQcmluY2lwYWxlcyAqKihBQ1ApKiogcGVybWl0ZSByZW9yZ2FuaXphciB1biBjb25qdW50byBkZSBkYXRvcyBtdWx0aXZhcmlhZG8gYWwgcmVkdWNpciBlbCBuw7ptZXJvIGRlIHZhcmlhYmxlcywgc2luIHJlcXVlcmlyIHN1cG9zaWNpb25lcyBlc3BlY8OtZmljYXMgc29icmUgbGEgZGlzdHJpYnVjacOzbiBkZSBwcm9iYWJpbGlkYWQgZGUgZXN0YXMuIEVzdGEgcmVkdWNjacOzbiBzZSBhbGNhbnphIG1lZGlhbnRlIGxhIGNyZWFjacOzbiBkZSBjb21iaW5hY2lvbmVzIGxpbmVhbGVzIGRlIGxhcyB2YXJpYWJsZXMgb3JpZ2luYWxlcywgZGlzZcOxYWRhcyBwYXJhIGNhcHRhciBsYSBtYXlvciB2YXJpYWJpbGlkYWQgcG9zaWJsZSBlbiBsb3MgZGF0b3MuIERlIGVzdGUgbW9kbywgZWwgKipBQ1AqKiBnZW5lcmEgbnVldmFzIHZhcmlhYmxlcywgZGVub21pbmFkYXMgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMsIHF1ZSBwcmVzZW50YW4gaW5kZXBlbmRlbmNpYSBlc3RhZMOtc3RpY2EgeSBhdXNlbmNpYSBkZSBjb3JyZWxhY2nDs24sIHNpZW1wcmUgYmFqbyBlbCBzdXB1ZXN0byBkZSBub3JtYWxpZGFkLg0KDQojIyMgMi4zLiBwbGFudGVhbWllbnRvIHkgZGVzYXJyb2xsbyANCg0KTGEgaW50ZXJwcmV0YWNpw7NuIGRlbCBBbsOhbGlzaXMgZGUgQ29tcG9uZW50ZXMgUHJpbmNpcGFsZXMgKiooQUNQKSoqIHNlIGJhc2EgZW4gbG9zIHJlc3VsdGFkb3Mgb2J0ZW5pZG9zIGEgcGFydGlyIGRlIGxhICoqbWF0cml6IGRlIGNvcnJlbGFjaW9uZXMqKiwgbG9zICoqdmFsb3JlcyB5IHZlY3RvcmVzIHByb3Bpb3MqKiwgbGEgKiptYXRyaXogQUNQKiogeSBsb3MgZ3LDoWZpY29zIGRpYWduw7NzdGljb3MsIGNvbiBlbCBmaW4gZGUgY29tcHJlbmRlciBsYSBlc3RydWN0dXJhIGludGVybmEgZGVsIGNvbmp1bnRvIGRlIGRhdG9zIHkgbGEgY2FsaWRhZCBkZSBzdSByZXByZXNlbnRhY2nDs24gZW4gdW4gZXNwYWNpbyByZWR1Y2lkby4gTG9zICoqdmFsb3JlcyBwcm9waW9zKiogeSBsYSAqKm1hdHJpeiBBQ1AqKiBtdWVzdHJhbiBxdWUgbGFzIHByaW1lcmFzIGRpbWVuc2lvbmVzIGNhcHR1cmFuIGVsIG1heW9yIHBvcmNlbnRhamUgZGUgdmFyaWFiaWxpZGFkIHRvdGFsLCBsbyBxdWUgaW5kaWNhIHF1ZSBlcyBwb3NpYmxlIHNpbnRldGl6YXIgYWRlY3VhZGFtZW50ZSBsYSBpbmZvcm1hY2nDs24gZGVsIHNpc3RlbWEgb3JpZ2luYWwgZW4gdW4gbsO6bWVybyByZWR1Y2lkbyBkZSBjb21wb25lbnRlcyBzaW4gY29tcHJvbWV0ZXIgc3UgZXN0cnVjdHVyYSBlc3RhZMOtc3RpY2EgZXNlbmNpYWwuDQoNCioqTGEgbWF0cml6IGRlIGNvcnJlbGFjaW9uZXMqKiBldmlkZW5jaWEgcmVsYWNpb25lcyBsw7NnaWNhcyBlbnRyZSBsYXMgdmFyaWFibGVzOiBlbCAqKmtpbG9tZXRyYWplKiogc2UgcmVsYWNpb25hIGRpcmVjdGFtZW50ZSBjb24gbGEgKiphbnRpZ8O8ZWRhZCBkZWwgdmVow61jdWxvKiosIG1pZW50cmFzIHF1ZSBlbCBwcmVjaW8gcHJlc2VudGEgY29ycmVsYWNpb25lcyBpbnZlcnNhcyBjb24gYW1iYXMsIHJlZmxlamFuZG8gZWwgcHJvY2VzbyBkZSBkZXByZWNpYWNpw7NuIG5hdHVyYWwgYXNvY2lhZG8gYWwgdXNvIHkgYWwgcGFzbyBkZWwgdGllbXBvLiBBIHN1IHZleiwgdmFyaWFibGVzIGNvbW8gZWwgKipraWxvbWV0cmFqZSBhbnVhbCoqIHkgbGEgKipjYW50aWRhZCBkZSBwcm9waWV0YXJpb3MqKiBtdWVzdHJhbiBjb3JyZWxhY2lvbmVzIG3DoXMgbW9kZXJhZGFzLCBwZXJvIG1hbnRpZW5lbiB1biBhcG9ydGUgc2lnbmlmaWNhdGl2byBwYXJhIGRlc2NyaWJpciBwYXRyb25lcyBkZSByb3RhY2nDs24sIGhpc3RvcmlhbCB5IHJpdG1vIGRlIHVzbyBkZSBsb3MgdmVow61jdWxvcy4NCg0KRWwgYW7DoWxpc2lzIGRlIGxvcyAqKnZhbG9yZXMgeSB2ZWN0b3JlcyBwcm9waW9zKiogcGVybWl0ZSBpZGVudGlmaWNhciBlbCBwZXNvIHF1ZSBjYWRhIHZhcmlhYmxlIHRpZW5lIGVuIGxhIGNvbnN0cnVjY2nDs24gZGUgbG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLiBFbiBlc3RlIHNlbnRpZG8sIGxhIHByaW1lcmEgY29tcG9uZW50ZSBhZ3J1cGEgcHJpbmNpcGFsbWVudGUgbGEgdmFyaWFiaWxpZGFkIHJlbGFjaW9uYWRhIGNvbiBlbCAqKnByZWNpbyoqLCBlbCAqKmtpbG9tZXRyYWplIGFjdW11bGFkbyoqIHkgbGEgKiphbnRpZ8O8ZWRhZCoqLCBmb3JtYW5kbyB1biBlamUgYXNvY2lhZG8gYSBsYSBkZXByZWNpYWNpw7NuIHkgZGVzZ2FzdGUgZGVsIHZlaMOtY3Vsby4gTGEgc2VndW5kYSBjb21wb25lbnRlLCBwb3Igc3UgcGFydGUsIHJlY29nZSBsYSBpbmZvcm1hY2nDs24gdmluY3VsYWRhIGFsICoqa2lsb21ldHJhamUgYW51YWwqKiB5IGFsICoqbsO6bWVybyBkZSBwcm9waWV0YXJpb3MqKiwgbG8gcXVlIGNvbmZpZ3VyYSB1biBlamUgcmVsYWNpb25hZG8gY29uIGxhIGludGVuc2lkYWQgZGUgdXNvIHJlY2llbnRlIHkgbG9zIHBhdHJvbmVzIGRlIHRyYW5zZmVyZW5jaWEgZGVsIHZlaMOtY3Vsby4NCg0KTGEgY29tcGFyYWNpw7NuIGVudHJlIGxhICoqbWF0cml6IGRlIGNvcnJlbGFjaW9uZXMqKiBvcmlnaW5hbCB5IGxhIG9idGVuaWRhIGEgcGFydGlyIGRlIGxvcyBzY29yZXMgZGVsIEFDUCBtdWVzdHJhIHF1ZSBsYSBlc3RydWN0dXJhIHJlbGFjaW9uYWwgZGVsIGNvbmp1bnRvIGRlIGRhdG9zIHNlIGNvbnNlcnZhIGRlbnRybyBkZWwgZXNwYWNpbyByZWR1Y2lkbywgbG8gcXVlIGNvbmZpcm1hIGxhIHZhbGlkZXogeSBlZmljaWVuY2lhIGRlbCBwcm9jZWRpbWllbnRvLiBFc3RlIHJlc3VsdGFkbyByZXNwYWxkYSBlbCB1c28gZGVsIEFDUCBjb21vIGhlcnJhbWllbnRhIHBhcmEgc2ludGV0aXphciBpbmZvcm1hY2nDs24gcmVkdW5kYW50ZSwgbWFudGVuaWVuZG8gbG9zIHBhdHJvbmVzIGVzZW5jaWFsZXMgZGVsIGZlbsOzbWVubyBlc3R1ZGlhZG8uDQoNCkZpbmFsbWVudGUsIGxvcyBncsOhZmljb3MgZGUgKipDYXR0ZWxsKiogeSAqKkNhdHRlbGwtS2Fpc2VyKiogcGVybWl0ZW4gZGV0ZXJtaW5hciBlbCBuw7ptZXJvIGFkZWN1YWRvIGRlIGNvbXBvbmVudGVzIGEgcmV0ZW5lci4gRWwgcXVpZWJyZSBvYnNlcnZhZG8gZW4gbGEgZ3LDoWZpY2EgZGUgc2VkaW1lbnRhY2nDs24sIGp1bnRvIGNvbiBlbCBjcml0ZXJpbyBkZSBLYWlzZXIgKHZhbG9yIHByb3BpbyBtYXlvciBhIDEpLCBjb25maXJtYSBxdWUgbGFzIHByaW1lcmFzIGRpbWVuc2lvbmVzIGNvbmNlbnRyYW4gbGEgdmFyaWFiaWxpZGFkIHN1ZmljaWVudGUgcGFyYSBzZXIgY29uc2lkZXJhZGFzIGVuIGVsIGFuw6FsaXNpcywgbWllbnRyYXMgcXVlIGxhcyByZXN0YW50ZXMgbm8gYXBvcnRhbiBpbmZvcm1hY2nDs24gcmVsZXZhbnRlIGFkaWNpb25hbC4gRW4gY29uanVudG8sIGVzdG9zIGVsZW1lbnRvcyBkZW11ZXN0cmFuIHF1ZSBsYSByZWR1Y2Npw7NuIGRpbWVuc2lvbmFsIHJlYWxpemFkYSBlcyBhZGVjdWFkYSB5IHF1ZSBsb3MgY29tcG9uZW50ZXMgb2J0ZW5pZG9zIHJlcHJlc2VudGFuIGRlIG1hbmVyYSBmaWVsIHkgZWZpY2F6IGxhcyByZWxhY2lvbmVzIGV4aXN0ZW50ZXMgZW50cmUgbGFzIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzIGRlbCBlc3R1ZGlvLg0KDQoNCg0KIyMjIyBNYXRyaXogQUNQDQpgYGB7ciBNYXRyaXpfQUNQLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmdldF9laWdlbnZhbHVlKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpKQ0KYGBgDQoNCiMjIyMgTWF0cml6IGRlIENvcnJlbGFjaW9uZXMNCmBgYHtyIE1hdHJpel9kZV9Db3JyZWxhY2lvbmVzfQ0Kcm91bmQoY29yKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYsMTEsMTIpXSksMikNCmBgYA0KDQojIyMjIFZhbG9yZXMgeSBWZWN0b3JlcyBQcm9waW9zDQpgYGB7ciBWYWxvcmVzX3lfVmVjdG9yZXNfUHJvcGlvcywgZmlnLmFsaWduID0gJ2NlbnRlcid9DQpwcmluY29tcCh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIGNvciA9IFRSVUUpJHNkZXZeMg0KcHJpbmNvbXAodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNiwxMSwxMildLCBjb3IgPSBUUlVFKSRsb2FkaW5nc1sgLDE6NV0NCmBgYA0KDQojIyMjIENvcnJlbGFjaW9uZXMgQ29tcGFyYWRhcw0KYGBge3IgQ29ycmVsYWNpb25lc19Db21wYXJhZGFzLCBmaWcuYWxpZ249J2NlbnRlcid9DQpwYXIobWZyb3c9YygxLDIpKQ0KY29ycnBsb3Q6OmNvcnJwbG90KGNvcih2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0pLCBtZXRob2QgPSAiY29sb3IiLCB0eXBlID0gInVwcGVyIiwgbnVtYmVyLmNleCA9IDAuNCkNCmNvcnJwbG90Ojpjb3JycGxvdChjb3IocHJpbmNvbXAodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNiwxMSwxMildLCBjb3IgPSBUUlVFKSRzY29yZXMpLCBtZXRob2QgPSAiY29sb3IiLCB0eXBlID0gInVwcGVyIiwgbnVtYmVyLmNleCA9IDAuNCkNCmBgYA0KDQojIyMjIEdyw6FmaWNvIGRlIENhdHRlbGwNCmBgYHtyIEdyYWZpY29fZGVfQ2F0dGVsbCwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQpmdml6X2VpZyhQQ0EodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNiwxMSwxMildLCBzY2FsZS51bml0ID0gVCwgZ3JhcGggPSBGKSwgYWRkbGFiZWxzID0gVCwgeWxpbT1jKDAsOTApLCBtYWluID0gIiIpDQpgYGANCg0KIyMjIyBHcsOhZmljbyBkZSBDYXR0ZWxsLUthaXNlcg0KYGBge3IgR3JhZmljb19kZV9DYXR0ZWxsX0thaXNlciwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQpzY3JlZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sZmFjdG9ycyA9IEZBTFNFLCBwYyA9IFRSVUUsIG1haW4gPSIiKQ0KYGBgDQoNCg0KIyMjIEludGVycHJldGFjacOzbiB5IGFuw6FsaXNpc3sudGFic2V0IC50YWJzZXQtcGlsbHN9DQpMYSAqKk1hdHJpeiBBQ1AqKiBtdWVzdHJhIGxvcyB2YWxvcmVzIHByb3Bpb3MgYXNvY2lhZG9zIGEgY2FkYSBjb21wb25lbnRlIHByaW5jaXBhbCB5IGxhIHByb3BvcmNpw7NuIGRlIHZhcmlhbnphIGV4cGxpY2FkYSBwb3IgZXN0b3MuIEVuIGVsIGFuw6FsaXNpcyByZWFsaXphZG8sIGVsIENvbXBvbmVudGUgMSBleHBsaWNhIGFwcm94aW1hZGFtZW50ZSAkNTkuNTckJCUkZGUgbGEgdmFyaWFiaWxpZGFkIHRvdGFsIGRlbCBjb25qdW50byBkZSBkYXRvcywgbG8gcXVlIGluZGljYSBxdWUgY29uY2VudHJhIGxhIG1heW9yIHBhcnRlIGRlIGxhIGluZm9ybWFjacOzbiBjb250ZW5pZGEgZW4gbGFzIHZhcmlhYmxlcyBvcmlnaW5hbGVzLiBFbCBDb21wb25lbnRlIDIgYXBvcnRhIGFscmVkZWRvciBkZSAkMjEuODQkJCUkLCBkZSBtb2RvIHF1ZSBsYXMgZG9zIHByaW1lcmFzIGRpbWVuc2lvbmVzIGFjdW11bGFuIGNlcmNhIGRlbCAkODEkJCUkIGRlIGxhIHZhcmlhbnphIHRvdGFsLiBFc3RlIHJlc3VsdGFkbyBqdXN0aWZpY2EgbGEgcmVkdWNjacOzbiBkZSBkaW1lbnNpb25hbGlkYWQsIHlhIHF1ZSBwZXJtaXRlIGludGVycHJldGFyIGxhIGVzdHJ1Y3R1cmEgaW50ZXJuYSBkZWwgc2lzdGVtYSBtYW50ZW5pZW5kbyBsYSBtYXlvciBwYXJ0ZSBkZSBsYSBpbmZvcm1hY2nDs24gcmVsZXZhbnRlLiBMb3MgY29tcG9uZW50ZXMgcmVzdGFudGVzICgkMTAuODckJCUkLCAkNi44MiQkJSQgeSAkMS4xMiQkJSQpIHBvc2VlbiBtZW5vciBwZXNvIHkgc3UgY29udHJpYnVjacOzbiBlcyBtYXJnaW5hbCBlbiB0w6lybWlub3MgZGVzY3JpcHRpdm9zLCBwb3IgbG8gY3VhbCBubyBzb24gaW5kaXNwZW5zYWJsZXMgcGFyYSBlbCBhbsOhbGlzaXMgZ2xvYmFsLg0KTGEgKipNYXRyaXogZGUgQ29ycmVsYWNpb25lcyoqIGV2aWRlbmNpYSBsYSBmdWVyemEgeSBkaXJlY2Npw7NuIGRlIGxhcyByZWxhY2lvbmVzIGVudHJlIGxhcyB2YXJpYWJsZXMgb3JpZ2luYWxlcyBkZWwgZXN0dWRpbzogKipraWxvbWV0cmFqZSoqLCAqKmNhbnRpZGFkIGRlIHByb3BpZXRhcmlvcyoqLCAqKmFudGlnw7xlZGFkIGRlbCB2ZWjDrWN1bG8qKiwgKipraWxvbWV0cmFqZSBhbnVhbCoqIHkgKipwcmVjaW8qKi4gU2Ugb2JzZXJ2YSBxdWUgZWwga2lsb21ldHJhamUgcHJlc2VudGEgdW5hIGNvcnJlbGFjacOzbiBwb3NpdGl2YSBhbHRhIGNvbiBsYSBhbnRpZ8O8ZWRhZCBkZWwgdmVow61jdWxvICgkMC43OCQpIHkgdW5hIGNvcnJlbGFjacOzbiBtb2RlcmFkYSBjb24gZWwga2lsb21ldHJhamUgYW51YWwgKCQwLjYwJCkuIEVzdG8gcmVmbGVqYSBxdWUgbG9zIHZlaMOtY3Vsb3MgbcOhcyBhbnRpZ3VvcyB5IG3DoXMgdXNhZG9zIHRpZW5kZW4gYSBhY3VtdWxhciBtYXlvciByZWNvcnJpZG8gdG90YWwuIEEgc3UgdmV6LCBlbCBwcmVjaW8gbXVlc3RyYSBjb3JyZWxhY2lvbmVzIG5lZ2F0aXZhcyBjb24gdmFyaWFzIHZhcmlhYmxlcyBkZSBkZXNnYXN0ZSwgY29tbyBlbCAqKmtpbG9tZXRyYWplKiogKCQtMC42MSQpIHkgbGEgKiphbnRpZ8O8ZWRhZCoqICgkLTAuNjYkKSwgbG8gcXVlIGluZGljYSBxdWUgbG9zIHZlaMOtY3Vsb3MgY29uIG1heW9yIHVzbyB5IG3DoXMgYcOxb3MgdGllbmRlbiBhIHRlbmVyIHVuIHZhbG9yIGNvbWVyY2lhbCBtw6FzIGJham8uIEVzdGFzIHJlbGFjaW9uZXMgY29uZmlybWFuIHF1ZSBsb3MgcGF0cm9uZXMgZGUgdXNvIGRlbCB2ZWjDrWN1bG8gaW5mbHV5ZW4gZGUgbWFuZXJhIGRpcmVjdGEgZW4gc3UgZGVwcmVjaWFjacOzbiB5IGFwb3J0YW4gbGEgYmFzZSBlc3RydWN0dXJhbCBhIHBhcnRpciBkZSBsYSBjdWFsIHNlIGNvbnN0cnV5ZW4gbG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLg0KTG9zICoqdmVjdG9yZXMgcHJvcGlvcyoqIHBlcm1pdGVuIGlkZW50aWZpY2FyIGVsIHBlc28gbyBjb250cmlidWNpw7NuIGRlIGNhZGEgdmFyaWFibGUgZW4gbGEgZm9ybWFjacOzbiBkZSBsb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMuIEVuIGVzdGUgYW7DoWxpc2lzLCBlbCBDb21wb25lbnRlIDEgcmVjaWJlIGxhcyBjYXJnYXMgbcOhcyBhbHRhcyBwb3IgcGFydGUgZGUgdmFyaWFibGVzIGNvbW8gZWwgKipraWxvbWV0cmFqZSoqICgkMC45NyQpLCBsYSAqKmFudGlnw7xlZGFkIGRlbCB2ZWjDrWN1bG8qKiAoJDAuODIkKSB5IGxhICoqY2FudGlkYWQgZGUgcHJvcGlldGFyaW9zKiogKCQwLjUzJCksIG1pZW50cmFzIHF1ZSBlbCBwcmVjaW8gYXBvcnRhIGVuIHNlbnRpZG8gaW52ZXJzbyAoJC0wLjQ1JCkuIEVzdGFzIGNhcmdhcyBpbmRpY2FuIHF1ZSBlc3RlIGNvbXBvbmVudGUgZXN0w6EgY2FwdHVyYW5kbyB1biBlamUgaW50ZXJwcmV0YXRpdm8gcmVsYWNpb25hZG8gY29uIGVsIHVzbyBhY3VtdWxhZG8geSBsYSBkZXByZWNpYWNpw7NuIGRlbCB2ZWjDrWN1bG8uIFBvciBzdSBwYXJ0ZSwgZWwgQ29tcG9uZW50ZSAyIGVzdMOhIGluZmx1aWRvIHByaW5jaXBhbG1lbnRlIHBvciBlbCAqKmtpbG9tZXRyYWplIGFudWFsKiogKCQwLjg0JCksIGxvIHF1ZSBzdWdpZXJlIHF1ZSBlc3RhIGRpbWVuc2nDs24gcmVwcmVzZW50YSBsYSBpbnRlbnNpZGFkIGRlIHVzbyBhbnVhbCwgaW5kZXBlbmRpZW50ZSBkZWwgZGVzZ2FzdGUgYWN1bXVsYWRvLiBEZSBlc3RhIG1hbmVyYSwgbG9zIGRvcyBwcmltZXJvcyBjb21wb25lbnRlcyBkaXZpZGVuIGxhIGluZm9ybWFjacOzbiBlbiBkb3MgZ3JhbmRlcyBmZW7Ds21lbm9zOiBlbCBkZXNnYXN0ZSBoaXN0w7NyaWNvIHkgbGEgZGluw6FtaWNhIGRlIHVzbyByZWNpZW50ZS4NCkVsIGFuw6FsaXNpcyBkZSAqKkNvcnJlbGFjaW9uZXMgQ29tcGFyYWRhcyoqIHBlcm1pdGUgY29udHJhc3RhciBsYSBtYXRyaXogZGUgY29ycmVsYWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIG9yaWdpbmFsZXMgY29uIGxhIG1hdHJpeiBjb3JyZXNwb25kaWVudGUgYSBsb3MgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMuIE1pZW50cmFzIGxhIHByaW1lcmEgcmVmbGVqYSByZWxhY2lvbmVzIGRpcmVjdGFzIGVudHJlIGxhcyB2YXJpYWJsZXMgZGVsIGRhdGFzZXQsIGxhIGVzdHJ1Y3R1cmEgZGUgY29ycmVsYWNpb25lcyBlbnRyZSBsb3MgY29tcG9uZW50ZXMgY29uZmlybWEgcXVlIGVzdG9zIHNvbiBvcnRvZ29uYWxlcywgZXMgZGVjaXIsIG5vIGVzdMOhbiBjb3JyZWxhY2lvbmFkb3MgZW50cmUgc8OtLiBFc3RhIHByb3BpZWRhZCBkZW11ZXN0cmEgcXVlIGNhZGEgY29tcG9uZW50ZSBjYXB0dXJhIHVuYSBwYXJ0ZSBkaXN0aW50YSB5IG5vIHJlZHVuZGFudGUgZGUgbGEgdmFyaWFiaWxpZGFkIHRvdGFsLiBBZGVtw6FzLCBzZSBvYnNlcnZhIHF1ZSBsYSBvcmdhbml6YWNpw7NuIGRlIGxhcyBjb3JyZWxhY2lvbmVzIGVuIGxvcyBjb21wb25lbnRlcyBwZXJtaXRlIGNvbmRlbnNhciBkZSBmb3JtYSBlZmljaWVudGUgbGEgZXN0cnVjdHVyYSBnbG9iYWwgZGVsIGNvbmp1bnRvIGRlIGRhdG9zLCBmYWNpbGl0YW5kbyBsYSBpbnRlcnByZXRhY2nDs24geSByZWR1Y2llbmRvIGxhIGNvbXBsZWppZGFkIGRlbCBtb2RlbG8gc2luIHDDqXJkaWRhIHN1c3RhbmNpYWwgZGUgaW5mb3JtYWNpw7NuLg0KRWwgKipHcsOhZmljbyBkZSBDYXR0ZWxsKiogKHNjcmVlIHBsb3QpIG11ZXN0cmEgZWwgcG9yY2VudGFqZSBkZSB2YXJpYW56YSBleHBsaWNhZGEgcG9yIGNhZGEgY29tcG9uZW50ZSB5IHBlcm1pdGUgdmlzdWFsaXphciBlbCBwdW50byBkZSBpbmZsZXhpw7NuIG8g4oCcY29kb+KAnS4gRW4gZXN0ZSBjYXNvLCBlbCBncsOhZmljbyBldmlkZW5jaWEgdW4gZGVzY2Vuc28gYWJydXB0byBkZXNwdcOpcyBkZWwgQ29tcG9uZW50ZSAyLCBkb25kZSBsYSB2YXJpYW56YSBleHBsaWNhZGEgY2FlIGRlIGZvcm1hIHNpZ25pZmljYXRpdmEuIEVzdGUgY29tcG9ydGFtaWVudG8gY29uZmlybWEgcXVlIGxvcyBwcmltZXJvcyBkb3MgY29tcG9uZW50ZXMgc29uIHN1ZmljaWVudGVzIHBhcmEgbW9kZWxhciBsYSBlc3RydWN0dXJhIGludGVybmEgZGVsIGNvbmp1bnRvIGRlIGRhdG9zLCB5YSBxdWUgY29uY2VudHJhbiBlbCAkODEkJCUkIGRlIGxhIGluZm9ybWFjacOzbiB0b3RhbC4gTG9zIGNvbXBvbmVudGVzIHJlc3RhbnRlcyBwcmVzZW50YW4gcG9yY2VudGFqZXMgbXV5IHJlZHVjaWRvcywgbG8gcXVlIGluZGljYSBxdWUgc3UgaW5jbHVzacOzbiBubyBhcG9ydGEgdmFsb3IgaW50ZXJwcmV0YXRpdm8gc2lnbmlmaWNhdGl2by4gRGUgZXN0YSBmb3JtYSwgZWwgc2NyZWUgcGxvdCByZXNwYWxkYSBsYSBkZWNpc2nDs24gZGUgY29uc2VydmFyIMO6bmljYW1lbnRlIGxhcyBkb3MgcHJpbWVyYXMgZGltZW5zaW9uZXMgZW4gZWwgYW7DoWxpc2lzLg0KRWwgY3JpdGVyaW8gZGUgKipDYXR0ZWxsLUthaXNlcioqIGVzdGFibGVjZSBxdWUgZGViZW4gY29uc2VydmFyc2Ugw7puaWNhbWVudGUgbG9zIGNvbXBvbmVudGVzIGN1eW8gdmFsb3IgcHJvcGlvIHNlYSBtYXlvciBhIDEuIEVuIGxvcyByZXN1bHRhZG9zIG9idGVuaWRvcywgZWwgQ29tcG9uZW50ZSAxIHByZXNlbnRhIHVuIHZhbG9yIHByb3BpbyBkZSBhcHJveGltYWRhbWVudGUgJDIuOTckIHkgZWwgQ29tcG9uZW50ZSAyIHVuIHZhbG9yIGNlcmNhbm8gYSAxLjA4LCBhbWJvcyBzdXBlcmlvcmVzIGFsIHVtYnJhbCBlc3RhYmxlY2lkby4gTG9zIGRlbcOhcyBjb21wb25lbnRlcyBwcmVzZW50YW4gdmFsb3JlcyBpbmZlcmlvcmVzLCBsbyBxdWUgaW5kaWNhIHF1ZSBubyBkZWJlbiBzZXIgcmV0ZW5pZG9zLiBFbiBlbCBncsOhZmljbyBjb3JyZXNwb25kaWVudGUgc2Ugb2JzZXJ2YSBkZSBmb3JtYSBjbGFyYSBxdWUgc29sbyBsb3MgZG9zIHByaW1lcm9zIHB1bnRvcyBzZSB1YmljYW4gcG9yIGVuY2ltYSBkZSBsYSBsw61uZWEgZGUgcmVmZXJlbmNpYSBkZWwgdmFsb3IgcHJvcGlvIDEsIGxvIHF1ZSByZWZ1ZXJ6YSBsYSBzZWxlY2Npw7NuIGRlIGRvcyBjb21wb25lbnRlcyBwcmluY2lwYWxlcyBjb21vIHN1ZmljaWVudGVzIHBhcmEgcmVwcmVzZW50YXIgbGEgZXN0cnVjdHVyYSBkZSBkYXRvcy4gRXN0ZSBjcml0ZXJpbyBjb2luY2lkZSBjb24gbG8gb2JzZXJ2YWRvIGVuIGVsIGdyw6FmaWNvIGRlIENhdHRlbGwgdHJhZGljaW9uYWwsIGNvbnNvbGlkYW5kbyBsYSBkZWNpc2nDs24gZGUgdHJhYmFqYXIgw7puaWNhbWVudGUgY29uIGRvcyBkaW1lbnNpb25lcyByZWxldmFudGVzLg0KDQojIyMgMi40LiBDYWxpZGFkIGRlIFJlcHJlc2VudGFjacOzbg0KDQpFbCBhbsOhbGlzaXMgZGUgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgKiooQUNQKSoqIHRyYW5zZm9ybWEgdmFyaWFibGVzIGNvcnJlbGFjaW9uYWRhcyBlbiBudWV2ZWFzIGRpbWVuc2lvbmVzLCB5IGVzdGEgc2VjY2nDs24gZXZhbMO6YSAgcXXDqSB0YW4gYmllbiBsYXMgdmFyaWFibGVzIG9yaWdpbmFsZXMgcXVlZGFyb24gcmVwcmVzZW50YWRhcyBlbiBlbCBudWV2byBlc3BhY2lvIGZhY3RvcmlhbC4gUGFyYSBlbGxvLCBzZSBhbmFsaXphbiBpbmRpY2Fkb3JlcyBjb21vIGNvcnJlbGFjaW9uZXMgZmFjdG9yaWFsZXMsIGNvc8KyIHkgY29udHJpYnVjaW9uZXMsIGxvcyBjdWFsZXMgcGVybWl0ZW4gZGV0ZXJtaW5hciBsYSBmaWRlbGlkYWQgZGUgbGEgcHJveWVjY2nDs24gZGUgY2FkYSB2YXJpYWJsZSBzb2JyZSBsb3MgY29tcG9uZW50ZXMgc2VsZWNjaW9uYWRvcy4NCg0KU2lndWllbmRvIGxvIGVzdGFibGVjaWRvIHBvciBbQEFFRE1EaWF6LU1vcmFsZXMxZWRdLCBsYXMgdmFyaWFibGVzIGVzdGFuZGFyaXphZGFzIHNlIHByb3llY3RhbiBzb2JyZSB1bmEgaGlwZXJlc2ZlcmEgZGUgY29ycmVsYWNpb25lcyB5IHN1IGludGVycHJldGFjacOzbiBkZWJlIGluaWNpYXJzZSBleGFtaW5hbmRvIGRpY2hhcyBjb3JyZWxhY2lvbmVzLiBVbmEgYWx0YSBjYWxpZGFkIGRlIHJlcHJlc2VudGFjacOzbiBpbXBsaWNhIHF1ZSBsYSB2YXJpYWJsZSBjb25zZXJ2YSBzdSBpbmZvcm1hY2nDs24gcmVsZXZhbnRlIGVuIGVsIHBsYW5vIGZhY3RvcmlhbDsgcG9yIGVsIGNvbnRyYXJpbywgdmFsb3JlcyBiYWpvcyBpbmRpY2Fyw61hbiBsYSBuZWNlc2lkYWQgZGUgY29uc2lkZXJhciBkaW1lbnNpb25lcyBhZGljaW9uYWxlcyBvIHJlZXZhbHVhciBzdSBhcG9ydGUgYWwgYW7DoWxpc2lzLg0KDQpFbiBzw61udGVzaXMsIGVzdGEgZXRhcGEgZ2FyYW50aXphIHF1ZSBsYSByZWR1Y2Npw7NuIGRpbWVuc2lvbmFsIG5vIGRpc3RvcnNpb25lIGVsIGNvbXBvcnRhbWllbnRvIGRlIGxhcyB2YXJpYWJsZXMgZXN0dWRpYWRhczogcHJlY2lvLCAqKmtpbG9tZXRyYWplKiosICoqYW50aWfDvGVkYWQqKiwgKip1c28gYW51YWwgeSDCqCoqbsO6bWVybyBkZSBwcm9waWV0YXJpb3MqKiwgc2lubyBxdWUgZm9ydGFsZXpjYSBsYSBpbnRlcnByZXRhY2nDs24gZGUgbG9zIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLCBwcmVzZXJ2YW5kbyBsYSBlc3RydWN0dXJhIGluZm9ybWF0aXZhIGRlbCBjb25qdW50byBkZSBkYXRvcy4NCg0KDQojIyMgMi41LiAgRGVzYXJyb2xsbyBkZWwgQW7DoWxpc2lzLiB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFeHBsb3JhciBsYXMgcGVzdGHDsWFzIHJldmVsYSBxdWUgbGEgcmVkdWNjacOzbiBkZSBkaW1lbnNpb25hbGlkYWQgcGVybWl0ZSBldmFsdWFyIGxhIGVzdHJ1Y3R1cmEgaW50ZXJuYSBkZWwgY29uanVudG8gZGUgZGF0b3MgYSBwYXJ0aXIgZGUgbGFzIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLiBFc3RlIGFuw6FsaXNpcyBzZSBiYXNhIGVuIGxhIGNvbXBhcmFjacOzbiBzaW11bHTDoW5lYSBkZSBsYXMgY29ycmVsYWNpb25lcyBlbnRyZSB2YXJpYWJsZXMsIGxhIGNhbGlkYWQgZGUgcmVwcmVzZW50YWNpw7NuIHkgbGEgZGlzdHJpYnVjacOzbiBkZSBsb3MgaW5kaXZpZHVvcyBzZWfDum4gbGFzIGRpbWVuc2lvbmVzIHNlbGVjY2lvbmFkYXMsIHV0aWxpemFuZG8gZXNjYWxhcyBjb250aW51YXMgZGUgY29udHJpYnVjacOzbiB5IHByb3llY2Npw7NuLg0KDQpFbCAqKkPDrXJjdWxvIGRlIENvcnJlbGFjaW9uZXMqKiBtdWVzdHJhIGPDs21vIGxhcyB2YXJpYWJsZXMgb3JpZ2luYWxlcyBzZSByZWxhY2lvbmFuIGNvbiBsYXMgZG9zIGRpbWVuc2lvbmVzIHByaW5jaXBhbGVzIGRlbCBhbsOhbGlzaXMuIEVuIGVzdGUgY2FzbywgbGEgKipkaW1lbnNpw7NuIDEgKERpbTEpKiogYWdydXBhIGxhIG1heW9yIHBhcnRlIGRlIGxhIGluZm9ybWFjacOzbiByZWxldmFudGU6IHZhcmlhYmxlcyBjb21vICoqa2lsb21ldHJhamUqKiwgKiphbnRpZ3VlZGFkX3ZlaGljdWxvKiosICoqcHJlY2lvKiogeSAqKmNhbnRfcHJvcGlldGFyaW9zKiogc2UgZW5jdWVudHJhbiBhbGluZWFkYXMgeSBjZXJjYW5hcyBhbCBib3JkZSBkZWwgY8OtcmN1bG8sIGxvIHF1ZSBpbmRpY2EgdW5hIGFsdGEgY29ycmVsYWNpw7NuIGNvbiBlc3RlIGVqZSB5LCBwb3IgbG8gdGFudG8sIHVuYSBjb250cmlidWNpw7NuIHNpZ25pZmljYXRpdmEgZW4gc3UgY29uc3RydWNjacOzbi4gRXN0byBzdWdpZXJlIHF1ZSBEaW0xIGVzdMOhIGNhcHR1cmFuZG8gdW4gY29tcG9uZW50ZSBhc29jaWFkbyBhbCB1c28gZGVsIHZlaMOtY3VsbyB5IHN1cyBjYXJhY3RlcsOtc3RpY2FzIGVzdHJ1Y3R1cmFsZXMuDQoNCkVuIGNvbnRyYXN0ZSwgbGEgKipkaW1lbnNpw7NuIDIgKERpbTIpKiplc3TDoSBwcmluY2lwYWxtZW50ZSBhc29jaWFkYSBhIGxhIHZhcmlhYmxlICoqa2lsb21ldHJhamVfYW51YWwqKiwgY3V5byB2ZWN0b3Igc2UgcHJveWVjdGEgZGUgZm9ybWEgZGVzdGFjYWRhIGhhY2lhIGVzdGEgZGltZW5zacOzbiB5IHNlIGFsZWphIGRlbCBjb25qdW50byBkZSB2YXJpYWJsZXMgYXNvY2lhZGFzIGEgKiooRGltMSkqKi4gRXN0YSBzZXBhcmFjacOzbiBpbmRpY2EgcXVlICoqKERpbTIpKiogcmVwcmVzZW50YSB1biBmZW7Ds21lbm8gYWx0ZXJuYXRpdm8sIHJlbGFjaW9uYWRvIGNvbiBsYSBpbnRlbnNpZGFkIGRlIHVzbyByZWNpZW50ZSBkZWwgdmVow61jdWxvLCBkaWZlcmVuY2nDoW5kb3NlIGNsYXJhbWVudGUgZGUgbG9zIGZhY3RvcmVzIGVzdHJ1Y3R1cmFsZXMgaWRlbnRpZmljYWRvcyBlbiAqKihEaW0xKSoqLg0KTGFzIHJlbGFjaW9uZXMgZW50cmUgdmFyaWFibGVzIHRhbWJpw6luIHNlIGV2aWRlbmNpYW4gZW4gbGEgY2VyY2Fuw61hIGRlIGxvcyB2ZWN0b3JlczogKipraWxvbWV0cmFqZSoqIHkgKiphbnRpZ3VlZGFkX3ZlaGljdWxvKiogbXVlc3RyYW4gZGlyZWNjaW9uZXMgc2ltaWxhcmVzLCBsbyBxdWUgaW5kaWNhIHVuIHBhdHLDs24gY29tcGFydGlkbyBlbiBsYXMgZG9zIGRpbWVuc2lvbmVzLiBQb3Igb3RybyBsYWRvLCAqKmtpbG9tZXRyYWplX2FudWFsKiogZm9ybWEgw6FuZ3Vsb3MgYW1wbGlvcyAoY2VyY2Fub3MgYSBsYSBwZXJwZW5kaWN1bGFyaWRhZCkgcmVzcGVjdG8gYSB2YXJpYWJsZXMgY29tbyAqKnByZWNpbyoqIG8gKipjYW50X3Byb3BpZXRhcmlvcyoqLCBsbyBxdWUgc3VnaWVyZSB1bmEgYmFqYSBjb3JyZWxhY2nDs24gZW50cmUgZXN0b3MgYXRyaWJ1dG9zIGRlbnRybyBkZWwgZXNwYWNpbyBkZWZpbmlkbyBwb3IgbGFzIGRvcyBjb21wb25lbnRlcyBwcmluY2lwYWxlcy4NCg0KTGEgKiptYXRyaXogZGUgcmVwcmVzZW50YWNpw7NuKiogKGNvc8KyKSByZWZsZWphIHF1w6kgdGFuIGJpZW4gY2FkYSB2YXJpYWJsZSBxdWVkYSBwcm95ZWN0YWRhIGVuIGxhcyBkaW1lbnNpb25lcyBwcmluY2lwYWxlcy4gRW4gbGEgKipkaW1lbnNpw7NuIDEoRGltMSkqKiwgZGVzdGFjYW4gdmFsb3JlcyBlbGV2YWRvcyBwYXJhICoqa2lsb21ldHJhamUqKiAoJDAuODQkKSwgKiphbnRpZ3VlZGFkX3ZlaGljdWxvKiogJDAuNzgkLCAqKnByZWNpbyoqICQwLjYyJCB5ICoqY2FudF9wcm9waWV0YXJpb3MqKiAkMC41MiQsIGxvIHF1ZSBjb25maXJtYSBxdWUgZXN0YXMgdmFyaWFibGVzIGVzdMOhbiBmdWVydGVtZW50ZSBhc29jaWFkYXMgY29uIGVzdGEgY29tcG9uZW50ZS4gU3UgdmFyaWFiaWxpZGFkIHNlIGNvbmNlbnRyYSBwcmluY2lwYWxtZW50ZSBlbiBlc3RlIGVqZSwgcmVmb3J6YW5kbyBzdSBwYXBlbCBkZW50cm8gZGVsIHBhdHLDs24gZXN0cnVjdHVyYWwgZGVsIGFuw6FsaXNpcy4NClBvciBzdSBwYXJ0ZSwgbGEgKipkaW1lbnNpw7NuIDIoRGltMikqKiBtdWVzdHJhIHVuYSByZXByZXNlbnRhY2nDs24gbXV5IGFsdGEgcGFyYSAqKmtpbG9tZXRyYWplX2FudWFsKiogJDAuNzYkLCBpbmRpY2FuZG8gcXVlIGVzdGEgdmFyaWFibGUgc2UgZXhwbGljYSBtZWpvciBkZXNkZSBlc3RlIGVqZSB5IG5vIGRlc2RlIGxhIHByaW1lcmEgY29tcG9uZW50ZS4gRWwgcmVzdG8gZGUgdmFyaWFibGVzIHByZXNlbnRhIHZhbG9yZXMgYmFqb3MgZGUgY29zwrIgZW4gKiooRGltMikqKiwgbG8gcXVlIGltcGxpY2EgcXVlIHN1IGVzdHJ1Y3R1cmEgc2UgZGlzdHJpYnV5ZSBkZSBtYW5lcmEgcHJlZG9taW5hbnRlIGhhY2lhIGxhIHByaW1lcmEgZGltZW5zacOzbi4NCkVuIGNvbmp1bnRvLCBsYSBtYXRyaXogcGVybWl0ZSBkaWZlcmVuY2lhciBjbGFyYW1lbnRlIGVudHJlIHZhcmlhYmxlcyBkZSBuYXR1cmFsZXphIGVzdHJ1Y3R1cmFsIGFsdGFtZW50ZSByZXByZXNlbnRhZGFzIGVuICoqKERpbTEpKip5IHZhcmlhYmxlcyBkZSBjb21wb3J0YW1pZW50byByZWNpZW50ZSByZXByZXNlbnRhZGFzIGVuICoqKERpbTIpKiosIG1vc3RyYW5kbyBsYSBjb2hlcmVuY2lhIGludGVybmEgZGVsIG1vZGVsby4NCg0KRWwgKipncsOhZmljbyBkZSBDYWxpZGFkIGRlIFJlcHJlc2VudGFjacOzbioqIHJlZnVlcnphIGxhIGludGVycHJldGFjacOzbiBhbnRlcmlvciBhbCBtb3N0cmFyIG1lZGlhbnRlIHVuYSBlc2NhbGEgY29udGludWEgZGUgY29sb3JlcyBxdcOpIHRhbiBiaWVuIHNlIGFqdXN0YSBjYWRhIHZhcmlhYmxlIGFsIHBsYW5vIGZvcm1hZG8gcG9yICoqKERpbTEpKiogeSAqKihEaW0yKSoqLiBMYXMgdG9uYWxpZGFkZXMgY8OhbGlkYXMgYXNvY2lhZGFzIGEgKipraWxvbWV0cmFqZSoqLCAqKmFudGlndWVkYWRfdmVoaWN1bG8qKiwgKipwcmVjaW8qKiB5ICoqY2FudF9wcm9waWV0YXJpb3MqKiBldmlkZW5jaWFuIHF1ZSBlc3RhcyB2YXJpYWJsZXMgcG9zZWVuIHVuYSBhbHRhIHByZWNpc2nDs24gZGUgcHJveWVjY2nDs24gZW4gbGEgcHJpbWVyYSBkaW1lbnNpw7NuLCBzaWVuZG8gbGFzIG1lam9yIHJlcHJlc2VudGFkYXMgZW4gZWwgZXNwYWNpbyBmYWN0b3JpYWwuDQpFbiBjb250cmFzdGUsICoqa2lsb21ldHJhamVfYW51YWwqKiBvYnRpZW5lIHN1IG1lam9yIGNhbGlkYWQgZGUgcmVwcmVzZW50YWNpw7NuIGVuIGxhICoqZGltZW5zacOzbiAyKERpbTIpKiosIGRvbmRlIHByZXNlbnRhIHVuIGNvc8KyIGRlICQwLjc2JC4gRXN0ZSBwYXRyw7NuIGluZGljYSBxdWUgc3UgY29udHJpYnVjacOzbiBzZSBkaXN0cmlidXllIHByaW5jaXBhbG1lbnRlIGhhY2lhIGVzdGUgZWplLCByZXN1bHRhbmRvIGVuIHVuIHZlY3RvciBjbGFyYW1lbnRlIGRpZmVyZW5jaWFkbyBlbiBlbCBncsOhZmljby4gVmFyaWFibGVzIGNvbiBjb2xvcmVzIG3DoXMgZnLDrW9zIHJlZmxlamFuIHVuYSByZXByZXNlbnRhY2nDs24gcGFyY2lhbCBvIGJhamEsIGluZGljYW5kbyBxdWUgdW5hIHBhcnRlIGRlIHN1IHZhcmlhYmlsaWRhZCBkZXBlbmRlIGRlIGRpbWVuc2lvbmVzIGFkaWNpb25hbGVzIG3DoXMgYWxsw6EgZGUgbGFzIGRvcyBwcmluY2lwYWxlcy4NCkVzdGUgYW7DoWxpc2lzIHBlcm1pdGUgaWRlbnRpZmljYXIgZGUgbWFuZXJhIHZpc3VhbCBsYSBjb21wbGVtZW50YXJpZWRhZCBlbnRyZSBsYXMgdmFyaWFibGVzIHF1ZSBjb25zdHJ1eWVuICoqKERpbTEpKiogeSBhcXVlbGxhcyBxdWUgYXBvcnRhbiBkaXN0aW50aXZhbWVudGUgYSAqKihEaW0yKSoqLCBlbnJpcXVlY2llbmRvIGxhIGludGVycHJldGFjacOzbiBnbG9iYWwgZGVsIG1vZGVsby4NCg0KTGFzICoqY29vcmRlbmFkYXMgaW5kaXZpZHVhbGVzKiogbXVlc3RyYW4gY8OzbW8gc2UgZGlzdHJpYnV5ZW4gbG9zIHJlZ2lzdHJvcyBkZWwgY29uanVudG8gZGUgZGF0b3MgZW4gZWwgZXNwYWNpbyBkZWZpbmlkbyBwb3IgbGFzIGRvcyBkaW1lbnNpb25lcyBwcmluY2lwYWxlcy4gRW4gbGEgKipkaW1lbnNpw7NuIDEoRGltMSkqKiwgYWxndW5vcyBpbmRpdmlkdW9zIHByZXNlbnRhbiB2YWxvcmVzIG5lZ2F0aXZvcyBwcm9udW5jaWFkb3MgY29tbyBsb3MgcmVnaXN0cm9zICoqKDEsIDUgeSA3KSoqLCBsbyBxdWUgc3VnaWVyZSBxdWUgY29tcGFydGVuIGNhcmFjdGVyw61zdGljYXMgYXNvY2lhZGFzIGNvbiBuaXZlbGVzIGJham9zIGVuIGxhcyB2YXJpYWJsZXMgcXVlIG3DoXMgaW5mbHV5ZW4gYSBlc3RlIGNvbXBvbmVudGUuIFBvciBlbCBjb250cmFyaW8sIHJlZ2lzdHJvcyBjb21vIGVsICoqKDE1LCAxOSB5IDIwKSoqIGV4aGliZW4gdmFsb3JlcyBwb3NpdGl2b3MgYWx0b3MsIHJlcHJlc2VudGFuZG8gcGVyZmlsZXMgb3B1ZXN0b3MgeSBwb3NpYmxlbWVudGUgbcOhcyBmYXZvcmVjZWRvcmVzIGVuIHTDqXJtaW5vcyBkZSB1c28sIGFudGlnw7xlZGFkIG8gcHJlY2lvLg0KRW4gbGEgKipkaW1lbnNpw7NuIDIoRGltMikqKiwgZGVzdGFjYW4gaW5kaXZpZHVvcyBjb21vIGVsICoqKDQsIDMgeSAxOSkqKiwgcXVlIHNlIHByb3llY3RhbiBkZSBtYW5lcmEgcG9zaXRpdmEsIG1vc3RyYW5kbyBjb21wb3J0YW1pZW50b3MgZGlmZXJlbmNpYWRvcyByZXNwZWN0byBhbCAqKmtpbG9tZXRyYWplIGFudWFsKiouIFBvciBvdHJvIGxhZG8sIHJlZ2lzdHJvcyBjb21vIGVsICoqKDgsIDExIHkgMTQpKiogc2UgcHJveWVjdGFuIG5lZ2F0aXZhbWVudGUgZW4gZXN0YSBkaW1lbnNpw7NuLCByZWZsZWphbmRvIHBlcmZpbGVzIGRpc3RpbnRvcyBlbiByZWxhY2nDs24gY29uIGVzdGEgdmFyaWFibGUuDQpFc3RhcyBjb29yZGVuYWRhcyBwZXJtaXRlbiBpZGVudGlmaWNhciBncnVwb3MgZGUgaW5kaXZpZHVvcyBjb24gY29tcG9ydGFtaWVudG9zIHNpbWlsYXJlcyB5IGRldGVjdGFyIHBhdHJvbmVzIHF1ZSBjb250cmlidXllbiBhIGxhIGNvbXByZW5zacOzbiBtdWx0aWRpbWVuc2lvbmFsIGRlbCBjb25qdW50byBkZSBkYXRvcy4NCg0KIyMjIyBDw61yY3VsbyBkZSBDb3JyZWxhY2lvbmVzDQpgYGB7ciBDaXJjdWxvX2RlX0NvcnJlbGFjaW9uZXMsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9wY2FfdmFyKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIHNjYWxlLnVuaXQgPSBULCBncmFwaCA9IEYpLGNvbC52YXI9IiMzQjgzQkQiLCByZXBlbCA9IFQsIGNvbC5jaXJjbGUgPSAiI0NEQ0RDRCIsIGdndGhlbWUgPSB0aGVtZV9idygpKQ0KYGBgDQoNCiMjIyMgTWF0cml6IGRlIFJlcHJlc2VudGFjacOzbg0KYGBge3IgTWF0cml6X2RlX1JlcHJlc3NlbnRhY2lvbl9DT1MyLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCihnZXRfcGNhX3ZhcihQQ0EodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNiwxMSwxMildLCBuY3AgPSA1LCBzY2FsZS51bml0ID0gVFJVRSwgZ3JhcGggPSBGKSkpJGNvczINCmBgYA0KDQojIyMjIENhbGlkYWQgZGUgUmVwcmVzZW50YWNpw7NuDQpgYGB7ciBDYWxpZGFkX2RlX2xhX1JlcHJlc2VudGFjaW9uLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmZ2aXpfcGNhX3ZhcihQQ0EodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNiwxMSwxMildLCBuY3AgPSA1LCBzY2FsZS51bml0ID0gVFJVRSwgZ3JhcGggPSBGKSwgY29sLnZhcj0iY29zMiIsIGdyYWRpZW50LmNvbHM9YygiIzAwQUZCQiIsIiNFN0I4MDAiLCIjRkM0RTA3IiksIHJlcGVsID0gVFJVRSkNCmBgYA0KDQojIyMjIENvb3JkZW5hZGFzIEluZGl2aWR1YWxlcw0KYGBge3IgQ29vcmRlbmFkYXNfUmVnaXN0cm9zLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmhlYWQoKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIG5jcCA9IDUsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpKSRpbmQkY29vcmQsIG4gPSAyM0wpDQpgYGANCg0KIyMjIFBsYW50ZWFtaWVudG8geSBEZXNhcnJvbGxvIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQoNCkVsIGFuw6FsaXNpcyBzZSByZWFsaXphIGFwbGljYW5kbyB1biBBbsOhbGlzaXMgZGUgQ29tcG9uZW50ZXMgUHJpbmNpcGFsZXMgKEFDUCkgY29uIGVsIG9iamV0aXZvIGRlIGlkZW50aWZpY2FyIGxhIGVzdHJ1Y3R1cmEgaW50ZXJuYSBkZSBsYXMgdmFyaWFibGVzIGVzdHVkaWFkYXMgeSBkZXRlcm1pbmFyIHN1IGNvbnRyaWJ1Y2nDs24gZGVudHJvIGRlIGxvcyBlamVzIHByaW5jaXBhbGVzLiBQYXJhIGVsbG8gc2UgZW1wbGVhbiBkaWZlcmVudGVzIHNhbGlkYXMgZXN0YWTDrXN0aWNhczogbGEgbWF0cml6IGRlIGNvcnJlbGFjaW9uZXMsIGVsIGPDrXJjdWxvIGRlIGNvcnJlbGFjaW9uZXMsIGxhIGdyw6FmaWNhIGRlIGNhbGlkYWQgZGUgcmVwcmVzZW50YWNpw7NuIChjb3PCsikgeSBsYXMgY29vcmRlbmFkYXMgaW5kaXZpZHVhbGVzLiBDYWRhIHVubyBkZSBlc3RvcyBlbGVtZW50b3MgcGVybWl0ZSBldmFsdWFyIGxhIHJlbGFjacOzbiBlbnRyZSB2YXJpYWJsZXMsIHN1IGFwb3J0ZSBhIGxvcyBjb21wb25lbnRlcyBwcmluY2lwYWxlcyB5IGVsIGdyYWRvIGRlIHJlcHJlc2VudGFjacOzbiBlbiBlbCBwbGFubyBmYWN0b3JpYWwuIENvbiBiYXNlIGVuIGVzdGFzIHNhbGlkYXMsIHNlIGRlc2Fycm9sbGEgZWwgYW7DoWxpc2lzIGRlbCBjb21wb3J0YW1pZW50byBkZSBsYXMgdmFyaWFibGVzIGRlbnRybyBkZSBsb3MgZG9zIHByaW1lcm9zIGNvbXBvbmVudGVzIGRlbCBBQ1AsIHF1ZSBjb25jZW50cmFuIGxhIG1heW9yIHByb3BvcmNpw7NuIGRlIGluZm9ybWFjacOzbiBkZWwgc2lzdGVtYS4NCg0KIyMjIDIuNi4gQ29udHJpYnVjaW9uZXMgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KTG9zIGF1dG9yZXMgW0BBRURNRGlhei1Nb3JhbGVzMWVkXSBzZcOxYWxhbiBxdWUgbGEgaW50ZXJwcmV0YWNpw7NuIGRlIGxvcyByZXN1bHRhZG9zIGVzdMOhIGVzdHJlY2hhbWVudGUgbGlnYWRhIGFsIGPDoWxjdWxvIGRlIGVsZW1lbnRvcyBjb21vIGNvb3JkZW5hZGFzLCBjb250cmlidWNpb25lcyB5IGNvc2Vub3MgY3VhZHJhZG9zLiBQb3IgbG8gdGFudG8sIGVzIGVzZW5jaWFsIHF1ZSBsYXMgdmFyaWFibGVzIGVzdMOpbiBiaWVuIGNvbmNlcHR1YWxpemFkYXMgeSBjb250ZXh0dWFsaXphZGFzIHBhcmEgZmFjaWxpdGFyIHN1IGNvbXByZW5zacOzbi4gRW4gZXN0ZSBzZW50aWRvLCBhbmFsaXphciBsYSBjb250cmlidWNpw7NuIGRlIGNhZGEgdmFyaWFibGUgYSB1bmEgY29tcG9uZW50ZSBheXVkYSBhIGludGVycHJldGFyIGxvcyByZXN1bHRhZG9zLCBtb3N0cmFuZG8gY8OzbW8gY2FkYSB1bmEgaW5mbHV5ZSBlbiBsYSBkZWZpbmljacOzbiBkZSBsYXMgY29tcG9uZW50ZXMgZ2VuZXJhZGFzLiBFc3RlIGFuw6FsaXNpcyBzZSBsbGV2YSBhIGNhYm8gZW4gZXN0YSBzZWNjacOzbiBwYXJhIGRldGVybWluYXIgZWwgYXBvcnRlIGRlIGNhZGEgdmFyaWFibGUgZW4gbGEgY29uc3RydWNjacOzbiBkZSBsYXMgY29tcG9uZW50ZXMuDQoNCg0KIyMjIDIuNy4gUGxhbnRlYW1pZW50byB5IERlc2Fycm9sbG8gey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KQmFzYWRvIGVuIGxhcyB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcyBkZWwgY29uanVudG8gZGUgZGF0b3MgZGVzY3JpdG8gZW4gbGEgW3NlY2Npw7NuIDEuMl0oI3NlYzEuMiksIHNlIHJlcXVpZXJlIGRldGVybWluYXIgbGFzIGNvbnRyaWJ1Y2lvbmVzIGRlIGNhZGEgdmFyaWFibGUgZW4gbGEgY29uc3RydWNjacOzbiBkZSBsYXMgY29tcG9uZW50ZXMuDQoNCkxhIG5hdmVnYWNpw7NuIGEgdHJhdsOpcyBkZSBsYXMgcGVzdGHDsWFzIGZhY2lsaXRhIGxhIHZpc3VhbGl6YWNpw7NuIGRlIGxhcyBjb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGRlbCBjb25qdW50byBkZSBkYXRvcyBlbiBmb3JtYSBkZSByZXByZXNlbnRhY2lvbmVzIG51bcOpcmljYXMgeSBncsOhZmljYXMsIHBlcm1pdGllbmRvIGNvbXByZW5kZXIgY8OzbW8gY2FkYSB2YXJpYWJsZSBpbmZsdXllIGVuIGxhIGNvbnN0cnVjY2nDs24gZGUgbGFzIGNvbXBvbmVudGVzLiBFc3RvIHBlcm1pdGUgYW5hbGl6YXIgbGEgcHJvcG9yY2nDs24gZGUgdmFyaWFiaWxpZGFkIHF1ZSBjYWRhIHZhcmlhYmxlIGFwb3J0YSBhIGxhIHZhcmlhYmlsaWRhZCB0b3RhbCBkZSBsYSBjb21wb25lbnRlIGNvbiBsYSBxdWUgZXN0w6EgYXNvY2lhZGEuDQoNCkxhICoqTWF0cml6IGRlIENvbnRyaWJ1Y2lvbmVzKiogbXVlc3RyYSBjw7NtbyBjYWRhIHZhcmlhYmxlIGNvbnRyaWJ1eWUgYSBsYSByZXRlbmNpw7NuIGRlIHZhcmlhYmlsaWRhZCBlbiBsYSBjb25zdHJ1Y2Npw7NuIGRlIGNhZGEgY29tcG9uZW50ZS4gTG9zIGRpYWdyYW1hcyBkZSBiYXJyYXMsIHF1ZSBzZSB2aXN1YWxpemFuIGVuIGxhcyBwZXN0YcOxYXMgZGVzZGUgKipDb250cmlidWNpb25lcyBhIEQxKiogaGFzdGEgKipDb250cmlidWNpb25lcyBhIEQ1KiosIGlsdXN0cmFuIGxhcyBjb250cmlidWNpb25lcyBlc3BlY8OtZmljYXMgZGUgbGFzIHZhcmlhYmxlcyBwYXJhIGV4cGxpY2FyIGxhIHZhcmlhYmlsaWRhZCBlbiBjYWRhIGNvbXBvbmVudGUuIENhZGEgZ3LDoWZpY28gaW5jbHV5ZSB1bmEgbMOtbmVhIHF1ZSBpbmRpY2EgbGEgKmNvbnRyaWJ1Y2nDs24gbWVkaWEqLCBsbyBxdWUgZmFjaWxpdGEgbGEgaWRlbnRpZmljYWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgcXVlIHRpZW5lbiBtYXlvciBpbXBhY3RvIGVuIGxhIGV4cGxpY2FjacOzbiBkZSBsYSB2YXJpYWJpbGlkYWQgZGUgbG9zIGNvbXBvbmVudGVzLg0KDQpFbiAqKkNvbnRyaWJ1Y2lvbmVzIGEgRDEqKiBzZSB2aXN1YWxpemEgcXVlIGxhcyB2YXJpYWJsZXMgcG9yIGVuY2ltYSBkZSBsYSBjb250cmlidWNpw7NuIG1lZGlhOiAqKmtpbG9tZXRyYWplKiosKiphbnRpZ3VlZGFkX3ZlaGljdWxvKiogeSAqKnByZWNpbyoqICwgbG9zIGNlbnRlIGVsICQ3NiwwNSUkICBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIGNvbXBvbmVudGUgMS4NCg0KRW4gKipDb250cmlidWNpb25lcyBhIEQyKiogc2UgdmlzdWFsaXphIHF1ZSBsYXMgdmFyaWFibGVzIHBvciBlbmNpbWEgZGUgbGEgY29udHJpYnVjacOzbiBtZWRpYTogKipraWxvbWV0cmFqZV9hbnVhbCoqIHF1ZSByZXRpZW5lIGFwcm94aW1hZGFtZW50ZSBlbCAkNzAsOTglJCBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIGNvbXBvbmVudGUgMi4NCg0KRW4gKipDb250cmlidWNpb25lcyBhIEQzKiogc2UgdmlzdWFsaXphIHF1ZSBsYXMgdmFyaWFibGVzIHBvciBlbmNpbWEgZGUgbGEgY29udHJpYnVjacOzbiBtZWRpYTogKipjYW50X3Byb3BpZXRhcmlvcyoqIHkgKipwcmVjaW8qKiBxdWUgcmV0aWVuZW4gYXByb3hpbWFkYW1lbnRlIGVsICQ5Niw2OCUkIGRlIGxhIHZhcmlhYmlsaWRhZCBkZWwgY29tcG9uZW50ZSAzLg0KDQpFbiAqKkNvbnRyaWJ1Y2lvbmVzIGEgRDQqKiBzZSB2aXN1YWxpemEgcXVlIGxhIHZhcmlhYmxlIHBvciBlbmNpbWEgZGUgbGEgY29udHJpYnVjacOzbiBtZWRpYTogKipwcmVjaW8qIHkgKiphbnRpZ3VlZGFkX3ZlaGljdWxvKiogcXVlIHJldGllbmVuIGFwcm94aW1hZGFtZW50ZSBlbCAkNjAsNDMlJCBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIGNvbXBvbmVuZXRlIDQuDQoNCkVuICoqQ29udHJpYnVjaW9uZXMgYSBENSoqIHNlIHZpc3VhbGl6YSBxdWUgbGFzIHZhcmlhYmxlcyBwb3IgZW5jaW1hIGRlIGxhIGNvbnRyaWJ1Y2nDs24gbWVkaWE6ICoqa2lsb21ldHJhamUqKiB5ICoqYW50aWd1ZWRhZF92ZWhpY3VsbyoqIHF1ZSByZXRpZW5lbiBhcHJveGltYWRhbWVudGVlbCAkODQsMSUkIGRlIGxhIHZhcmlhYmlsaWRhZCBkZWwgY29tcG9uZW50ZSA1Lg0KDQoNCiMjIyMgTWF0cml6IGRlIENvbnRyaWJ1Y2lvbmVzDQpgYGB7ciBNYXRyaXpfZGVfQ29udHJpYnVjaW9uZXMsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KKGdldF9wY2FfdmFyKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIG5jcCA9IDUsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpKSkkY29udHJpYg0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBEMQ0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzEsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDEsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBEMg0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzIsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDIsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBEMw0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzMsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDMsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBENA0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzQsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDQsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBENQ0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzUsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2LDExLDEyKV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDUsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyAyLjguIEludGVycHJldGFjacOzbiB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KUmVwcmVzZW50YXIgbG9zIHJlZ2lzdHJvcyBlbiB1biBlc3BhY2lvIGRlIGRpbWVuc2lvbmVzIHJlZHVjaWRhcyBwZXJtaXRlIHNpdHVhcmxvcyBlbiB1biBwbGFubyBkZSBmYWN0b3JlcywgbG8gcXVlIGZhY2lsaXRhIHN1IGFuw6FsaXNpcyBlIGludGVycHJldGFjacOzbi4gTGFzIHZhcmlhYmxlcyByZWR1Y2lkYXMgc2UgY29ycmVzcG9uZGVuIGNvbiBsYXMgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMsIHF1ZSBzZSB1dGlsaXphbiBjb21vIGVqZXMgZW4gZWwgcGxhbm8geSBjdXlvcyB2YWxvcmVzIHNvbiBsb3MgcHVudGFqZXMgZGUgbGFzIGNvbXBvbmVudGVzLiBMYSBkaXN0YW5jaWEgZW50cmUgbG9zIHB1bnRvcyByZXByZXNlbnRhZG9zIHBvciBlc3RvcyBwdW50YWplcyBlcyBjbGF2ZSBwYXJhIGlkZW50aWZpY2FyIHNpbWlsaXR1ZGVzIGVudHJlIGxvcyBwZXJmaWxlcyBkZSBsYXMgb2JzZXJ2YWNpb25lcy4gTm8gb2JzdGFudGUsIGxhcyBzaW1pbGl0dWRlcyBwdWVkZW4gYXBhcmVjZXIgc29sbyBlbiBhbGd1bmFzIHZhcmlhYmxlcyB5IG5vIGVuIHRvZGFzLiBBc8OtLCBzZSBidXNjYSBxdWUgbGFzIGRpc3RhbmNpYXMgZW4gZWwgZXNwYWNpbyBkZSBhbHRhIGRpbWVuc2nDs24gc2UgY29uc2VydmVuIGVuIGVsIGVzcGFjaW8gcmVkdWNpZG8sIG1hbnRlbmllbmRvIGxhIGVzdHJ1Y3R1cmEgZGUgbGFzIHJlbGFjaW9uZXMgZW50cmUgbG9zIGRhdG9zLiBTZWfDum4gW0BBRURNRGlhei1Nb3JhbGVzMWVkXS4NCg0KDQoNCiMjIyAyLjkuIEJpcGxvdHMgZGUgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMgW3ZhcmlhYmxlcyBjdWFudGl0YXRpdmFzXSB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFbCBiaXBsb3QgY29ycmVzcG9uZGllbnRlIGFsICoqdGlwbyBkZSBjb21idXN0aWJsZSoqIChlbMOpY3RyaWNvLCBnYXNvbGluYSB5IGRpw6lzZWwpIHByZXNlbnRhIHVuYSBkaWZlcmVuY2lhY2nDs24gbcOhcyBldmlkZW50ZSBlbiBjb21wYXJhY2nDs24gY29uIGxhIHRyYW5zbWlzacOzbi4gTG9zIHZlaMOtY3Vsb3MgZWzDqWN0cmljb3MgdGllbmRlbiBhIGFncnVwYXJzZSBlbiB6b25hcyBhc29jaWFkYXMgYSBtZW5vciBhbnRpZ8O8ZWRhZCB5IG1lbm9yIGtpbG9tZXRyYWplIGFjdW11bGFkbywgbG8gY3VhbCBlcyBjb25zaXN0ZW50ZSBjb24gc3UgYWRvcGNpw7NuIG3DoXMgcmVjaWVudGUgZW4gZWwgbWVyY2Fkby4gUG9yIG90cm8gbGFkbywgbG9zIHZlaMOtY3Vsb3MgZGnDqXNlbCB5IGdhc29saW5hIG11ZXN0cmFuIHVuYSBtYXlvciBkaXNwZXJzacOzbiwgZXNwZWNpYWxtZW50ZSBlbiByZWdpb25lcyByZWxhY2lvbmFkYXMgY29uIGFsdG9zIG5pdmVsZXMgZGUga2lsb21ldHJhamUgeSBhbnRpZ8O8ZWRhZC4NCg0KTGEgb3JpZW50YWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgc3VnaWVyZSBxdWUgZWwgdGlwbyBkZSBjb21idXN0aWJsZSBlc3TDoSByZWxhY2lvbmFkbyBjb24gcGF0cm9uZXMgZXNwZWPDrWZpY29zIGRlIHVzbyB5IGRlcHJlY2lhY2nDs24sIGxvIHF1ZSBwZXJtaXRlIGluZmVyaXIgcXVlIGVzdGEgdmFyaWFibGUgY2F0ZWfDs3JpY2EgY29udHJpYnV5ZSBkZSBmb3JtYSBtb2RlcmFkYSBhIGxhIGRpZmVyZW5jaWFjacOzbiBkZSBsYXMgb2JzZXJ2YWNpb25lcyBlbiBlbCBlc3BhY2lvIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLg0KDQpFbiBlbCBiaXBsb3QgYXNvY2lhZG8gYWwgKip0aXBvIGRlIHRyYW5zbWlzacOzbioqIChhdXRvbcOhdGljYSB5IG1hbnVhbCksIHNlIG9ic2VydmEgdW5hIG1heW9yIHN1cGVycG9zaWNpw7NuIGVudHJlIGFtYm9zIGdydXBvcyBlbiBlbCBwbGFubyBkZSBsYXMgZG9zIHByaW1lcmFzIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLiBBdW5xdWUgZXhpc3RlbiBsaWdlcmFzIHRlbmRlbmNpYXMgZGUgc2VwYXJhY2nDs24gZW4gYWxndW5hcyByZWdpb25lcyBkZWwgZXNwYWNpbyBmYWN0b3JpYWwsIGxhIGRpc3BlcnNpw7NuIGdlbmVyYWwgaW5kaWNhIHF1ZSBlbCB0aXBvIGRlIHRyYW5zbWlzacOzbiBubyBlcyB1biBmYWN0b3IgZG9taW5hbnRlIGVuIGxhIHZhcmlhYmlsaWRhZCBjYXB0dXJhZGEgcG9yIERpbS4xIHkgRGltLjIuDQoNCkxhcyB2YXJpYWJsZXMgbnVtw6lyaWNhcyBtYW50aWVuZW4gbGEgbWlzbWEgb3JpZW50YWNpw7NuIGVzdHJ1Y3R1cmFsIHF1ZSBlbiBlbCBhbsOhbGlzaXMgZ2VuZXJhbCwgbG8gcXVlIGNvbmZpcm1hIGxhIGVzdGFiaWxpZGFkIGRlbCBtb2RlbG8uIFNpbiBlbWJhcmdvLCBsYSBhdXNlbmNpYSBkZSB1bmEgc2VwYXJhY2nDs24gbWFyY2FkYSBzdWdpZXJlIHF1ZSBsYXMgZGlmZXJlbmNpYXMgZW50cmUgdmVow61jdWxvcyBhdXRvbcOhdGljb3MgeSBtYW51YWxlcyBubyBleHBsaWNhbiBkZSBtYW5lcmEgc2lnbmlmaWNhdGl2YSBsb3MgcGF0cm9uZXMgcHJpbmNpcGFsZXMgYXNvY2lhZG9zIGFsIGRlc2dhc3RlLCB1c28geSBwcmVjaW8gZGVsIHZlaMOtY3Vsby4NCg0KRWwgYmlwbG90IGNvcnJlc3BvbmRpZW50ZSBhIGxhICoqZ2FtYSB2ZWhpY3VsYXIqKiAoYWx0YSwgbWVkaWEgeSBiYWphKSBtdWVzdHJhIHVuYSBlc3RydWN0dXJhIGNsYXJhIGVuIGVsIHBsYW5vIGZhY3RvcmlhbC4gTGEgRGltZW5zacOzbiAxLCBxdWUgY29uY2VudHJhIGxhIG1heW9yIHByb3BvcmNpw7NuIGRlIHZhcmlhbnphLCBlc3TDoSBmdWVydGVtZW50ZSBhc29jaWFkYSBhIHZhcmlhYmxlcyByZWxhY2lvbmFkYXMgY29uIGVsIHVzbyBhY3VtdWxhZG8geSBsYSBkZXByZWNpYWNpw7NuLCBjb21vIGVsIGtpbG9tZXRyYWplIHkgbGEgYW50aWfDvGVkYWQgZGVsIHZlaMOtY3VsbywgbWllbnRyYXMgcXVlIGVsIHByZWNpbyBzZSBwcm95ZWN0YSBlbiBzZW50aWRvIG9wdWVzdG8sIHJlZmxlamFuZG8gc3UgcmVsYWNpw7NuIGludmVyc2EgY29uIGRpY2hhcyB2YXJpYWJsZXMuDQoNClNlIG9ic2VydmEgcXVlIGxvcyB2ZWjDrWN1bG9zIGRlIGdhbWEgYWx0YSB0aWVuZGVuIGEgY29uY2VudHJhcnNlIGVuIHpvbmFzIGFzb2NpYWRhcyBhIG1lbm9yZXMgbml2ZWxlcyBkZSBkZXNnYXN0ZSByZWxhdGl2byB5IHZhbG9yZXMgbcOhcyBhbHRvcyBkZSBwcmVjaW8sIG1pZW50cmFzIHF1ZSBsb3MgZGUgZ2FtYSBiYWphIHNlIGRpc3RyaWJ1eWVuIGhhY2lhIHJlZ2lvbmVzIGRvbmRlIHByZWRvbWluYW4gbWF5b3JlcyB2YWxvcmVzIGRlIGtpbG9tZXRyYWplIHkgYW50aWfDvGVkYWQuIExhIGdhbWEgbWVkaWEgcHJlc2VudGEgdW5hIGRpc3BlcnNpw7NuIGludGVybWVkaWEsIGxvIGN1YWwgaW5kaWNhIHVuYSB0cmFuc2ljacOzbiBncmFkdWFsIGVudHJlIGFtYm9zIGV4dHJlbW9zLiBFc3RhIHJlcHJlc2VudGFjacOzbiBldmlkZW5jaWEgcXVlIGxhIGdhbWEgdmVoaWN1bGFyIGVzIHVuYSB2YXJpYWJsZSBjYXRlZ8OzcmljYSBjb24gY2FwYWNpZGFkIHBhcmEgZ2VuZXJhciBhZ3J1cGFjaW9uZXMgaW50ZXJwcmV0YWJsZXMgZGVudHJvIGRlbCBlc3BhY2lvIHJlZHVjaWRvLg0KDQoNCiMjIyMgQmlwbG90IGRlIFZhcmlhYmxlcyB5IFJlZ2lzdHJvcyBbZmlsdHJvOnRpcG9fZGVfY29tYnVzdGlibGVdDQoNCmBgYHtyIEJpcGxvdF9WYXJpYWJsZXNfUmVnaXN0cm9zX0ZpbHRyb190aXBvX2RlX2NvbWJ1c3RpYmxlfQ0KdmVoaWN1bG9zX211ZXN0cmVhZG8gPC0gdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbDQogIHNhbXBsZSgxOm5yb3codmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwpLCAxMDApLA0KICAtYygxLDQsNiwxMSwxMildDQoNCnZlaGljdWxvc19tdWVzdHJlYWRvJHRpcG9fZGVfY29tYnVzdGlibGUgPC0gZmFjdG9yKHZlaGljdWxvc19tdWVzdHJlYWRvJHRpcG9fZGVfY29tYnVzdGlibGUsDQogIGxldmVscyA9IHVuaXF1ZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0aXBvX2RlX2NvbWJ1c3RpYmxlKSwNCiAgbGFiZWxzID0gdW5pcXVlKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRpcG9fZGVfY29tYnVzdGlibGUpKQ0KDQpmdml6X3BjYV9iaXBsb3QoUENBKHZlaGljdWxvc19tdWVzdHJlYWRvWyxdLCBuY3AgPSA1LCBzY2FsZS51bml0ID0gVFJVRSwgZ3JhcGggPSBGQUxTRSwgcXVhbGkuc3VwID0gInRpcG9fZGVfY29tYnVzdGlibGUiKSwgYXhlcyA9IGMoMSwyKSwgcmVwZWwgPSBUUlVFLCBoYWJpbGxhZ2UgPSAidGlwb19kZV9jb21idXN0aWJsZSIpDQoNCmBgYA0KDQojIyMjIEJpcGxvdCBkZSBWYXJpYWJsZXMgeSBSZWdpc3Ryb3MgW2ZpbHRybzp0cmFuc21pc29uXQ0KYGBge3IgQmlwbG90X2RlX1ZhcmlhYmxlc195X1JlZ2lzdHJvc19maWx0cm9fdHJhbnNtaXNpb259DQpzZXQuc2VlZCg3ODA3MjkpDQoNCnZlaGljdWxvc19tdWVzdHJlYWRvMiA8LSB2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFtzYW1wbGUoMTpucm93KHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMKSwgMjAwKSwgLWMoMSw1LDYsMTEsMTIpXQ0KDQp2ZWhpY3Vsb3NfbXVlc3RyZWFkbzIkdHJhbnNtaXNpb24gPC0gZmFjdG9yKHZlaGljdWxvc19tdWVzdHJlYWRvMiR0cmFuc21pc2lvbikNCg0KZnZpel9wY2FfYmlwbG90KFBDQSh2ZWhpY3Vsb3NfbXVlc3RyZWFkbzJbLF0sIG5jcCA9IDUsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEZBTFNFLCBxdWFsaS5zdXAgPSAidHJhbnNtaXNpb24iKSwgYXhlcyA9IGMoMSwyKSwgcmVwZWwgPSBUUlVFLCBoYWJpbGxhZ2UgPSAidHJhbnNtaXNpb24iKQ0KDQpgYGANCg0KIyMjIyBCaXBsb3QgZGUgVmFyaWFibGVzIHkgUmVnaXN0cm9zIFtmaWx0cm86Z2FtYV92ZWhpY3VsYXJdDQpgYGB7ciBCaXBsb3RfZGVfVmFyaWFibGVzX3lfUmVnaXN0cm9zX2ZpbHRyb19nYW1hX3ZlaGljdWxhcn0NCnNldC5zZWVkKDc4MDcyOSkNCg0KdmVoaWN1bG9zX211ZXN0cmVhZG8zIDwtIHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMW3NhbXBsZSgxOm5yb3codmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwpLCAxNTApLCAtYygxLDQsNSw2LDExKV0NCg0KdmVoaWN1bG9zX211ZXN0cmVhZG8zJGdhbWFfdmVoaWN1bGFyIDwtIHRyaW13cyh2ZWhpY3Vsb3NfbXVlc3RyZWFkbzMkZ2FtYV92ZWhpY3VsYXIpDQp2ZWhpY3Vsb3NfbXVlc3RyZWFkbzMkZ2FtYV92ZWhpY3VsYXIgPC0gYXMuZmFjdG9yKHZlaGljdWxvc19tdWVzdHJlYWRvMyRnYW1hX3ZlaGljdWxhcikNCg0KaWR4X2dhbWEgPC0gd2hpY2gobmFtZXModmVoaWN1bG9zX211ZXN0cmVhZG8zKSA9PSAiZ2FtYV92ZWhpY3VsYXIiKQ0KDQpmdml6X3BjYV9iaXBsb3QoUENBKHZlaGljdWxvc19tdWVzdHJlYWRvMywgbmNwID0gNSwgc2NhbGUudW5pdCA9IFRSVUUsIGdyYXBoID0gRkFMU0UsIHF1YWxpLnN1cCA9IGlkeF9nYW1hKSwgYXhlcyA9IGMoMSwyKSwgcmVwZWwgPSBUUlVFLCBoYWJpbGxhZ2UgPSAiZ2FtYV92ZWhpY3VsYXIiKQ0KYGBgDQoNCiMjIyMgQ29vcmRlbmFkYXMgSW5kaXZpZHVhbGVzIFtDaGVzdFBhaW5dDQpgYGB7ciBjb29yZGVuYWRhc19pbmRpdmlkdWFsZXN9DQpwY2FfcmVzdWx0IDwtIFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssIC1jKDEsNCw1LDYsMTEsMTIpXSwgbmNwID0gNSwgc2NhbGUudW5pdCA9IFRSVUUsIGdyYXBoID0gRkFMU0UpDQpyZXMuY29vcmQgPC0gcGNhX3Jlc3VsdCRpbmQkY29vcmQNCmhlYWQocmVzLmNvb3JkKQ0KYGBgDQoNCjxhIG5hbWU9InNlYzMiPjwvYT4NCg0KIyMgKipGQVNFIDMgW0FOw4FMSVNJUyBERSBDT1JSRVNQT05ERU5DSUFTXSoqDQoNCiMjIyAzLjEuIE9iamV0aXZvcw0KDQpTZSBidXNjYSBwcm9mdW5kaXphciBlbiBlbCBhbsOhbGlzaXMgbXVsdGl2YXJpYWRvIGRlIGxhcyB2YXJpYWJsZXMgY3VhbGl0YXRpdmFzIGRlbCBjb25qdW50byBkZSBkYXRvcyBtZWRpYW50ZSB0w6ljbmljYXMgZGUgQW7DoWxpc2lzIGRlIENvcnJlc3BvbmRlbmNpYXMgU2ltcGxlcyAqKihBQ1MpKiogeSBNw7psdGlwbGVzICoqKEFDTSkqKi4gTG9zIG9iamV0aXZvcyBzb246IGNvbnN0cnVpciB0YWJsYXMgZGUgY29udGluZ2VuY2lhIHBhcmEgaWRlbnRpZmljYXIgYXNvY2lhY2lvbmVzIGVudHJlIGNhdGVnb3LDrWFzOyBnZW5lcmFyIGxhIHRhYmxhIGRpc3l1bnRpdmEgY29tcGxldGEgbmVjZXNhcmlhIHBhcmEgZWwgQUNNOyBldmFsdWFyIGxhIGNhbGlkYWQgZGUgcmVwcmVzZW50YWNpw7NuIGRlIGxhcyBtb2RhbGlkYWRlcyBlbiBsb3MgcGxhbm9zIGZhY3RvcmlhbGVzOyBhbmFsaXphciBsYXMgY29udHJpYnVjaW9uZXMgZGUgY2FkYSBjYXRlZ29yw61hIGEgbGEgZm9ybWFjacOzbiBkZSBsYXMgZGltZW5zaW9uZXM7IGUgaW50ZXJwcmV0YXIgbG9zIHBhdHJvbmVzIGRlIHJlbGFjacOzbiBlbnRyZSBhdHJpYnV0b3MgdmluY3VsYWRvcyBhIGNhcmFjdGVyw61zdGljYXMgdMOpY25pY2FzIHkgY29tZXJjaWFsZXMgZGUgbG9zIHZlaMOtY3Vsb3MgdXNhZG9zLiBFc3RvIHBlcm1pdGlyw6EgY2FyYWN0ZXJpemFyIGxhIGVzdHJ1Y3R1cmEgY3VhbGl0YXRpdmEgZGVsIGNvbmp1bnRvIGRlIGRhdG9zIHkgZm9ydGFsZWNlciBsYSBjb21wcmVuc2nDs24gZGUgbGFzIGFzb2NpYWNpb25lcyBwcmVzZW50ZXMgZW50cmUgbGFzIGRpZmVyZW50ZXMgbW9kYWxpZGFkZXMgY2F0ZWfDs3JpY2EuDQoNCiMjIyAzLjIuIENvcnJlc3BvbmRlbmNpYXMgU2ltcGxlcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpTZWfDum4gW0BBTUFSQWxkYXMtVXJpZWwyZWRdLGVsICoqYW7DoWxpc2lzIGRlIGNvcnJlc3BvbmRlbmNpYXMqKiBzaW1wbGUgKiooQUNTKSoqIHRpZW5lIGNvbW8gcHJvcMOzc2l0byByZWR1Y2lyIGxhIGRpbWVuc2lvbmFsaWRhZCBkZSBsYXMgcmVsYWNpb25lcyBlbnRyZSBjYXRlZ29yw61hcyBkZSBkb3MgdmFyaWFibGVzIGNhdGVnw7NyaWNhcywgcmVwcmVzZW50w6FuZG9sYXMgZW4gdW4gZXNwYWNpbyBtdWx0aWRpbWVuc2lvbmFsLiBFc3RlIG3DqXRvZG8gcGVybWl0ZSBhbmFsaXphciBncsOhZmljYW1lbnRlIGxhcyBkaXN0YW5jaWFzIGVudHJlIGxhcyBjYXRlZ29yw61hcyBkZSBsYXMgdmFyaWFibGVzLCBmYWNpbGl0YW5kbyBsYSBpbnRlcnByZXRhY2nDs24gZGUgdGFibGFzIGRlIGNvbnRpbmdlbmNpYS4gRWwgbsO6bWVybyBtw6F4aW1vIGRlIGRpbWVuc2lvbmVzIG5lY2VzYXJpYXMgcGFyYSBleHBsaWNhciBkaWNoYXMgcmVsYWNpb25lcyBjb3JyZXNwb25kZSBhIHVubyBtZW5vcyBlbCBuw7ptZXJvIGRlIGNhdGVnb3LDrWFzIGRlIGxhIHZhcmlhYmxlIGNvbiBtZW5vciBjYW50aWRhZCBkZSBuaXZlbGVzLg0KDQpBc2ltaXNtbywgZWwgKipBQ1MqKiwgYmFzYWRvIGVuIHRhYmxhcyBkZSBjb250aW5nZW5jaWEsIHB1ZWRlIGFtcGxpYXJzZSBwYXJhIGluY2x1aXIgbcOhcyBkZSBkb3MgdmFyaWFibGVzIGNhdGVnw7NyaWNhcywgbG8gcXVlIHNlIGNvbm9jZSBjb21vICoqQW7DoWxpc2lzIGRlIGNvcnJlc3BvbmRlbmNpYXMgbcO6bHRpcGxlcyAoQUNNKSoqLiBFc3RlIGVuZm9xdWUgdXRpbGl6YSB1bmEgdGFibGEgZGlzeXVudGl2YSBjb21wbGV0YSwgcGVybWl0aWVuZG8gZXhwbG9yYXIgeSByZXByZXNlbnRhciByZWxhY2lvbmVzIG3DoXMgY29tcGxlamFzIGVudHJlIG3Dumx0aXBsZXMgdmFyaWFibGVzIGNhdGVnw7NyaWNhcy4NCg0KDQojIyMjIEFDIFBhcmVqYXMgVG90YWxlcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQojIyMjIyBDb250aW5nZW5jaWFzDQpgYGB7ciBUYWJsYXNfZGVfQ29udGluZ2VuY2lhLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmFkZG1hcmdpbnModGFibGUodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdHJhbnNtaXNpb24sIHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRpcG9fZGVfY29tYnVzdGlibGUpKQ0KYWRkbWFyZ2lucyh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0cmFuc21pc2lvbiwgdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkbWFyY2FfdmVoaWN1bG8pKQ0KYWRkbWFyZ2lucyh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0aXBvX2RlX2NvbWJ1c3RpYmxlLHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJGNvbG9yX2V4dGVyaW9yKSkNCmBgYA0KDQojIyMjIyBQcm9iYWJpbGlkYWRlcw0KYGBge3IgVGFibGFzX2RlX1Byb2JhYmlsaWRhZGVzLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmFkZG1hcmdpbnMocHJvcC50YWJsZSh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0cmFuc21pc2lvbiwgdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdGlwb19kZV9jb21idXN0aWJsZSkpKjEwMCkNCmFkZG1hcmdpbnMocHJvcC50YWJsZSh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCRnYW1hX3ZlaGljdWxhciwgdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdHJhbnNtaXNpb24pKSoxMDApDQpgYGANCg0KIyMjIyMgRnJlY3VlbmNpYXMgW0NQRiB5IENQQ10NCmBgYHtyIFRhYmxhc19kZV9GcmVjdWVuY2lhc19Db25kaWNpb25hZGFzLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnJvdW5kKGFkZG1hcmdpbnMocHJvcC50YWJsZSh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCRtYXJjYV92ZWhpY3VsbywgdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkZ2FtYV92ZWhpY3VsYXIpLCAxKSoxMDAsIDIpLCAyKQ0KDQoNCnJvdW5kKGFkZG1hcmdpbnMocHJvcC50YWJsZSh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCRnYW1hX3ZlaGljdWxhciwgdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdHJhbnNtaXNpb24pLCAyKSoxMDAsIDEpLCAyKQ0KDQpyb3VuZChhZGRtYXJnaW5zKHByb3AudGFibGUodGFibGUodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkZ2FtYV92ZWhpY3VsYXIsIHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHJhbmdvX2FudGlndWVkYWQpLCAyKSoxMDAsIDEpLCAyKQ0KDQpgYGANCg0KIyMjIyMgUGVyZmlsZXMgW0NQRiB5IENQQ10NCmBgYHtyIEdyYWZpY29zX2RlX1BlcmZpbGVzLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnBsb3RjdCh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0cmFuc21pc2lvbiwgdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdGlwb19kZV9jb21idXN0aWJsZSksInJvdyIpDQpwbG90Y3QodGFibGUodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdHJhbnNtaXNpb24sIHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRpcG9fZGVfY29tYnVzdGlibGUpLCJjb2wiKQ0KDQpwbG90Y3QodGFibGUodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkZ2FtYV92ZWhpY3VsYXIsIHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRyYW5zbWlzaW9uKSwicm93IikNCnBsb3RjdCh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCRnYW1hX3ZlaGljdWxhciwgdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdHJhbnNtaXNpb24pLCJjb2wiKQ0KDQpwbG90Y3QodGFibGUodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkbWFyY2FfdmVoaWN1bG8sIHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHJhbmdvX2FudGlndWVkYWQpLCJyb3ciKQ0KcGxvdGN0KHRhYmxlKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJG1hcmNhX3ZlaGljdWxvLCB2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCRyYW5nb19hbnRpZ3VlZGFkKSwiY29sIikNCg0KDQpgYGANCg0KIyMjIyMgUHJ1ZWJhcyBkZSBIaXDDs3Rlc2lzDQpgYGB7ciBQcnVlYmFzX2RlX0NvcnJlc3BvbmRlbmNpYSwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQpjaGlzcS50ZXN0KHRhYmxlKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRyYW5zbWlzaW9uLCB2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0aXBvX2RlX2NvbWJ1c3RpYmxlKSkNCmNoaXNxLnRlc3QodGFibGUodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdGlwb19kZV9jb21idXN0aWJsZSwgdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkZ2FtYV92ZWhpY3VsYXIpKQ0KY2hpc3EudGVzdCh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCRnYW1hX3ZlaGljdWxhcix2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0cmFuc21pc2lvbikpDQpgYGANCg0KIyMjIyBBQyBQYXJlamEgw5puaWNhIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQoNCiMjIyMjIENvbnRpbmdlbmNpYXMgeSBSZXNpZHVhbGVzIFtULUNQXQ0KYGBge3IgQ29udGluZ2VuY2lhc195X1Jlc2lkdWFsZXMsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KY2hpc3EudGVzdCh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0cmFuc21pc2lvbix2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0aXBvX2RlX2NvbWJ1c3RpYmxlKSkkb2JzZXJ2ZWQNCmNoaXNxLnRlc3QodGFibGUodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdHJhbnNtaXNpb24sdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdGlwb19kZV9jb21idXN0aWJsZSkpJGV4cGVjdGVkIA0KY2hpc3EudGVzdCh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0cmFuc21pc2lvbix2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0aXBvX2RlX2NvbWJ1c3RpYmxlKSkkcmVzaWR1YWxzDQpjaGlzcS50ZXN0KHRhYmxlKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRyYW5zbWlzaW9uLHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRpcG9fZGVfY29tYnVzdGlibGUpKSRzdGRyZXMNCmBgYA0KDQojIyMjIyBDb250cmlidWNpb25lcyBbVC1DUF0NCmBgYHtyIENvbnRyaWJ1Y2lvbmVzX1ItVVIsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KY2hpc3EudGVzdCh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0cmFuc21pc2lvbix2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0aXBvX2RlX2NvbWJ1c3RpYmxlKSkkcmVzaWR1YWxzXjIvY2hpc3EudGVzdCh0YWJsZSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0cmFuc21pc2lvbix2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0aXBvX2RlX2NvbWJ1c3RpYmxlKSkkc3RhdGlzdGljKjEwMA0KYGBgDQoNCiMjIyMjIENvcnJlc3BvbmRlbmNpYSBTaW1wbGUgVW5pZGltZW5zaW9uYWwgW1ItVVJdDQpgYGB7ciBCaXBsb3RfQ29ycmVzcG9uZGVuY2lhX1NpbXBsZV9SLVVSLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCkNBKHRhYmxlKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRyYW5zbWlzaW9uLHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRpcG9fZGVfY29tYnVzdGlibGUpLCBncmFwaCA9IEZBTFNFKSRlaWcNCkNBKHRhYmxlKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRyYW5zbWlzaW9uLHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRpcG9fZGVfY29tYnVzdGlibGUpLCBncmFwaCA9IEZBTFNFKSRjb2wNCkNBKHRhYmxlKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRyYW5zbWlzaW9uLHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMJHRpcG9fZGVfY29tYnVzdGlibGUpLCBncmFwaCA9IEZBTFNFKSRyb3cNCiANCmBgYA0KDQojIyMjIEludGVycHJldGFjacOzbiANClBFTkRJRU5URQ0KDQoNCg0KIyMjIDMuMy4gQ29ycmVzcG9uZGVuY2lhcyBNw7psdGlwbGVzIA0KDQojIyMjIEFDTQ0KYGBge3IgQUNNLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCg0KdmVoaWN1bG9zX0FDTSA8LSB2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssIGMoIm1hcmNhX3ZlaGljdWxvIiwidHJhbnNtaXNpb24iLCAidGlwb19kZV9jb21idXN0aWJsZSIsICJjb2xvcl9leHRlcmlvciIsICJyYW5nb19hbnRpZ3VlZGFkIiwgImdhbWFfdmVoaWN1bGFyIildDQoNCnZlaGljdWxvc19BQ00gPC0gZGF0YS5mcmFtZShsYXBwbHkodmVoaWN1bG9zX0FDTSwgZmFjdG9yKSkNCnN1cHByZXNzV2FybmluZ3Moe3Jlcy5hY20gPC0gIE1DQSh2ZWhpY3Vsb3NfQUNNLCBncmFwID0gRkFMU0UpfSkNCg0KYGBgDQoNCiMjIyMgQmlwbG90IEFDTQ0KYGBge3IgQmlwbG90X0FDTV9tdWVzdHJhLCBmaWcuYWxpZ249J2NlbnRlcid9DQoNCnNldC5zZWVkKDc4MDcyOSkNCg0KbXVlc3RyYV9pbmQgPC0gc2FtcGxlKHJvd25hbWVzKHJlcy5hY20kaW5kJGNvb3JkKSwgMjAwKQ0KDQpmdml6X21jYV9iaXBsb3QocmVzLmFjbSwgc2VsZWN0LmluZCA9IGxpc3QobmFtZSA9IG11ZXN0cmFfaW5kKSwgcmVwZWwgPSBUUlVFLCBjb2wudmFyID0gIiNFN0I4MDAiLCBhZGRFbGxpcHNlcyA9IFRSVUUsIGVsbGlwc2UubGV2ZWwgPSAwLjk1KQ0KDQpgYGANCg0KDQojIyMgMy40LiBQbGFudGVhbWllbnRvIHkgRGVzYXJyb2xsbyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KUEVORElFTlRFIFRFWFRPIA0KDQojIyMjIENhbGlkYWQgZGUgUmVwcmVzZW50YWNpw7NuDQpgYGB7ciBDYWxpZGFkX2RlX1JlcHJlc2VudGFjaW9uX0FDTSwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQpmdml6X21jYV92YXIocmVzLmFjbSwgY29sLnZhciA9ImNvczIiLCBncmFkaWVudC5jb2xzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSwgcmVwZWwgPSBUUlVFKQ0KcmVzLmFjbSR2YXIkY29zMg0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMNCmBgYHtyIENvbnRyaWJ1Y2lvbmVzX0FDTSwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQpmdml6X2NvbnRyaWIocmVzLmFjbSwgY2hvaWNlID0gInZhciIsIGF4ZXMgPSAxLCB0b3AgPSAxNSkNCmZ2aXpfY29udHJpYihyZXMuYWNtLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDIsIHRvcCA9IDE1KQ0KZnZpel9jb250cmliKHJlcy5hY20sIGNob2ljZSA9ICJ2YXIiLCBheGVzID0gMywgdG9wID0gMTUpDQpmdml6X2NvbnRyaWIocmVzLmFjbSwgY2hvaWNlID0gInZhciIsIGF4ZXMgPSA0LCB0b3AgPSAxNSkNCmZ2aXpfY29udHJpYihyZXMuYWNtLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDUsIHRvcCA9IDE1KQ0KYGBgDQoNCiMjIyMgQmlwbG90IGNvbiBDb250cmlidWNpb25lcw0KYGBge3IgQmlwbG90X2Nvbl9Db250cmlidWNpb25lc19BQ00sIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9tY2FfdmFyKHJlcy5hY20sIGNvbC52YXIgPSJjb250cmliIiwgZ3JhZGllbnQuY29scyA9IGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksIHJlcGVsID0gVFJVRSkNCmBgYA0KDQoNCiMjICoqRkFTRSA0IFtDT05HTE9NRVJBRE9TXSoqDQoNCiMjIyA0LjEuIE9iamV0aXZvcw0KDQpFbiBlc3RhICoqY3VhcnRhIGV0YXBhKiogZGVsIGVzdHVkaW8gc2UgcHJlc2VudGFyw6FuIGPDoWxjdWxvcywgdmlzdWFsaXphY2lvbmVzIGUgaW50ZXJwcmV0YWNpb25lcywgdXRpbGl6YW5kbyBlbCBjb25qdW50byBkZSBkYXRvcyBwcm9jZXNhZG8gZW4gbGFzIGZhc2VzIHByZXZpYXMgKiooMSwgMiB5IDMpKiouIEVsIGVuZm9xdWUgc2UgY2VudHJhcsOhIGVuIGVsICoqYW7DoWxpc2lzIGRlIGNvbmdsb21lcmFkb3MqKiwgYWJhcmNhbmRvIHRhbnRvIHN1IHZlcnNpw7NuIGplcsOhcnF1aWNhIG1lZGlhbnRlIGRlbmRyb2dyYW1hcyBjb21vIGxhIG5vIGplcsOhcnF1aWNhIGNvbiBLLW1lZGlhcy4NCg0KDQoNCiMjIyA0LjIuIEFncnVwYWNpw7NuIEplcsOhcnF1aWNhDQoNCiMjIyA0LjMuIFBsYW50ZWFtaWVudG8geSBkZXNhcnJvbGxvDQoNCiMjIyMjIENhbXBvIENsYXNpZmljYWRvcg0KYGBge3IgQ2FtcG9fQ2xhc2lmaWNhZG9yLCBmaWcuYWxpZ249J2NlbnRlcid9DQpjYW1wb19jbGFzaWZpY2Fkb3IgPC0gdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLCAtYygxLDQsNSw2LDExLDEyKV0NCmNhbXBvX2NsYXNpZmljYWRvcl9lc2MgPC0gc2NhbGUoY2FtcG9fY2xhc2lmaWNhZG9yKQ0KaGVhZChjYW1wb19jbGFzaWZpY2Fkb3JfZXNjKQ0KDQpgYGANCg0KIyMjIyMgTWF0cml6IGRlIERpc2ltaWxhcmlkYWQgKE11ZXN0cmEgUmVkdWNpZGEpDQpgYGB7ciBNYXRyaXpfRGlzaW1pbGFyaWRhZF9NdWVzdHJhLCBmaWcuYWxpZ249J2NlbnRlcid9DQpzZXQuc2VlZCg3ODA3MjkpDQptdWVzdHJhX2Rpc2ltIDwtIGNhbXBvX2NsYXNpZmljYWRvcltzYW1wbGUoMTpucm93KGNhbXBvX2NsYXNpZmljYWRvciksIDUwKSwgXQ0KbXVlc3RyYV9kaXNpbV9lc2MgPC0gc2NhbGUobXVlc3RyYV9kaXNpbSkNCm1hdHJpel9kaXNpbV9tdWVzdHJhIDwtIGRpc3QobXVlc3RyYV9kaXNpbV9lc2MpDQpmdml6X2Rpc3QobWF0cml6X2Rpc2ltX211ZXN0cmEpDQpgYGANCg0KIyMjIyBPcHRpbWl6YWNpw7NuIGRlIE1vamVuYSB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQojIyMjIyBVbmnDs24gU2ltcGxlDQpgYGB7ciBNb2plbmFfVW5pw7NuU2ltcGxlLCBmaWcuYWxpZ249J2NlbnRlcid9DQphcmJvbF9zaW5nbGUgPC0gaGNsdXN0KG1hdHJpel9kaXNpbV9tdWVzdHJhLCBtZXRob2QgPSAic2luZ2xlIikNCmFsdHVyYXMgPC0gYXJib2xfc2luZ2xlJGhlaWdodA0KbWVkaWFfYWx0IDwtIG1lYW4oYWx0dXJhcykNCnNkX2FsdCAgICA8LSBzZChhbHR1cmFzKQ0KayAgICAgICAgIDwtIDEuMjUgICANCnB1bnRvX2NvcnRlIDwtIG1lZGlhX2FsdCArIGsgKiBzZF9hbHQNCnB1bnRvX2NvcnRlDQpudW1fY2x1c3RlcnMgPC0gc3VtKGFsdHVyYXMgPiBwdW50b19jb3J0ZSkgKyAxDQpudW1fY2x1c3RlcnMNCnBsb3QoYXJib2xfc2luZ2xlLCBoYW5nID0gLTEsIGNleCA9IDAuOCkNCmFibGluZShoID0gcHVudG9fY29ydGUsIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQ0KDQpgYGANCg0KDQojIyMjIyBVbmnDs24gQ29tcGxldGENCmBgYHtyIE1vamVuYV9VbmnDs25Db21wbGV0YSwgZmlnLmFsaWduPSdjZW50ZXInfQ0KYXJib2xfY29tcGxldGUgPC0gaGNsdXN0KG1hdHJpel9kaXNpbV9tdWVzdHJhLCBtZXRob2QgPSAiY29tcGxldGUiKQ0KYWx0dXJhcyA8LSBhcmJvbF9jb21wbGV0ZSRoZWlnaHQNCm1lZGlhX2FsdCA8LSBtZWFuKGFsdHVyYXMpDQpzZF9hbHQgICAgPC0gc2QoYWx0dXJhcykNCmsgICAgICAgICA8LSAxLjI1IA0KcHVudG9fY29ydGUgPC0gbWVkaWFfYWx0ICsgayAqIHNkX2FsdA0KcHVudG9fY29ydGUNCm51bV9jbHVzdGVycyA8LSBzdW0oYWx0dXJhcyA+IHB1bnRvX2NvcnRlKSArIDENCm51bV9jbHVzdGVycw0KcGxvdChhcmJvbF9jb21wbGV0ZSwgaGFuZyA9IC0xLCBjZXggPSAwLjgpDQphYmxpbmUoaCA9IHB1bnRvX2NvcnRlLCBjb2wgPSAicmVkIiwgbHdkID0gMikNCmBgYA0KDQoNCiMjIyMjIE9wdGltaXphY2nDs24gZGUgTW9qZW5hIOKAkyBNw6l0b2RvIGRlIFVuacOzbiBQcm9tZWRpbw0KYGBge3IgTW9qZW5hX1VuacOzblByb21lZGlvLCBmaWcuYWxpZ249J2NlbnRlcid9DQphcmJvbF9hdmVyYWdlIDwtIGhjbHVzdChtYXRyaXpfZGlzaW1fbXVlc3RyYSwgbWV0aG9kID0gImF2ZXJhZ2UiKQ0KYWx0dXJhcyA8LSBhcmJvbF9hdmVyYWdlJGhlaWdodA0KbWVkaWFfYWx0IDwtIG1lYW4oYWx0dXJhcykNCnNkX2FsdCAgICA8LSBzZChhbHR1cmFzKQ0KayAgICAgICAgIDwtIDEuMjUgICAjIFZhbG9yIHV0aWxpemFkbyBlbiBDMw0KDQpwdW50b19jb3J0ZSA8LSBtZWRpYV9hbHQgKyBrICogc2RfYWx0DQpwdW50b19jb3J0ZQ0KbnVtX2NsdXN0ZXJzIDwtIHN1bShhbHR1cmFzID4gcHVudG9fY29ydGUpICsgMQ0KbnVtX2NsdXN0ZXJzDQpwbG90KGFyYm9sX2F2ZXJhZ2UsIGhhbmcgPSAtMSwgY2V4ID0gMC44KQ0KYWJsaW5lKGggPSBwdW50b19jb3J0ZSwgY29sID0gInJlZCIsIGx3ZCA9IDIpDQpgYGANCg0KDQojIyMjIERlbmRvZ3JhbWFzIE9wdGltaXphZG9zIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQoNCiMjIyMjIFVuacOzbiBTaW1wbGUNCmBgYHtyIERlbmRyb19TaW1wbGVfT3B0aW1pemFkbywgZmlnLmFsaWduPSdjZW50ZXInfQ0KYXJib2xfc2luZ2xlIDwtIGhjbHVzdChtYXRyaXpfZGlzaW1fbXVlc3RyYSwgbWV0aG9kID0gInNpbmdsZSIpDQphbHR1cmFzIDwtIGFyYm9sX3NpbmdsZSRoZWlnaHQNCm1lZGlhX2FsdCA8LSBtZWFuKGFsdHVyYXMpDQpzZF9hbHQgICAgPC0gc2QoYWx0dXJhcykNCmsgICAgICAgICA8LSAxLjI1ICANCnB1bnRvX2NvcnRlIDwtIG1lZGlhX2FsdCArIGsgKiBzZF9hbHQNCm51bV9jbHVzdGVycyA8LSBzdW0oYWx0dXJhcyA+IHB1bnRvX2NvcnRlKSArIDENCm51bV9jbHVzdGVycw0KcGxvdChhcmJvbF9zaW5nbGUsIGhhbmcgPSAtMSwgY2V4ID0gMC44KQ0KYWJsaW5lKGggPSBwdW50b19jb3J0ZSwgY29sID0gInJlZCIsIGx3ZCA9IDIpDQpgYGANCg0KIyMjIyBVbmnDs24gQ29tcGxldGENCmBgYHtyIERlbmRyb19Db21wbGV0b19PcHRpbWl6YWRvLCBmaWcuYWxpZ249J2NlbnRlcid9DQphcmJvbF9jb21wbGV0ZSA8LSBoY2x1c3QobWF0cml6X2Rpc2ltX211ZXN0cmEsIG1ldGhvZCA9ICJjb21wbGV0ZSIpDQphbHR1cmFzIDwtIGFyYm9sX2NvbXBsZXRlJGhlaWdodA0KbWVkaWFfYWx0IDwtIG1lYW4oYWx0dXJhcykNCnNkX2FsdCAgICA8LSBzZChhbHR1cmFzKQ0KayAgICAgICAgIDwtIDEuMjUgIA0KcHVudG9fY29ydGUgPC0gbWVkaWFfYWx0ICsgayAqIHNkX2FsdA0KbnVtX2NsdXN0ZXJzIDwtIHN1bShhbHR1cmFzID4gcHVudG9fY29ydGUpICsgMQ0KbnVtX2NsdXN0ZXJzDQpwbG90KGFyYm9sX2NvbXBsZXRlLCBoYW5nID0gLTEsIGNleCA9IDAuOCkNCmFibGluZShoID0gcHVudG9fY29ydGUsIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQ0KYGBgDQoNCiMjIyMgIFVuacOzbiBQcm9tZWRpbw0KYGBge3IgRGVuZHJvX1Byb21lZGlvX09wdGltaXphZG8sIGZpZy5hbGlnbj0nY2VudGVyJ30NCmFyYm9sX2F2ZXJhZ2UgPC0gaGNsdXN0KG1hdHJpel9kaXNpbV9tdWVzdHJhLCBtZXRob2QgPSAiYXZlcmFnZSIpDQphbHR1cmFzIDwtIGFyYm9sX2F2ZXJhZ2UkaGVpZ2h0DQptZWRpYV9hbHQgPC0gbWVhbihhbHR1cmFzKQ0Kc2RfYWx0ICAgIDwtIHNkKGFsdHVyYXMpDQprICAgICAgICAgPC0gMS4yNSAgDQpwdW50b19jb3J0ZSA8LSBtZWRpYV9hbHQgKyBrICogc2RfYWx0DQpudW1fY2x1c3RlcnMgPC0gc3VtKGFsdHVyYXMgPiBwdW50b19jb3J0ZSkgKyAxDQpudW1fY2x1c3RlcnMNCnBsb3QoYXJib2xfYXZlcmFnZSwgaGFuZyA9IC0xLCBjZXggPSAwLjgpDQphYmxpbmUoaCA9IHB1bnRvX2NvcnRlLCBjb2wgPSAicmVkIiwgbHdkID0gMikNCmBgYA0KDQojIyMgNC40LiBBZ3J1cGFjacOzbiBOby1KZXLDoXJxdWljYSANCg0KKHBsYW50ZWFtaWVudG8geSBkZXNhcnJvbGxvKQ0KDQojIyMjIEstw5NwdGltbyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQojIyMjIyBFbGJvdw0KYGBge3IgRWxib3csIGZpZy5hbGlnbj0nY2VudGVyJ30NCmZ2aXpfbmJjbHVzdChtdWVzdHJhX2Rpc2ltX2VzYywga21lYW5zLCBtZXRob2QgPSAid3NzIikgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAzLCBsaW5ldHlwZSA9IDIpDQpgYGANCg0KIyMjIyMgU2lsaG91ZXR0ZQ0KYGBge3IgU2lsaG91ZXR0ZSxmaWcuYWxpZ249J2NlbnRlcid9DQpmdml6X25iY2x1c3QobXVlc3RyYV9kaXNpbV9lc2MsIGttZWFucywgbWV0aG9kID0gInNpbGhvdWV0dGUiKQ0KDQpgYGANCg0KIyMjIyMgR2FwIFN0YXRpc3RpYw0KYGBge3IgR2FwX1N0YXRpc3RpYyxmaWcuYWxpZ249J2NlbnRlcid9DQpmdml6X25iY2x1c3QobXVlc3RyYV9kaXNpbV9lc2MsIGttZWFucywgbWV0aG9kID0gImdhcF9zdGF0IikNCg0KYGBgDQoNCiMjIyMjIE1ham9yaXR5IFJ1bGUNCmBgYHtyIE1ham9yaXR5X1J1bGUsIGZpZy5hbGlnbj0nY2VudGVyJ30NCnN1cHByZXNzV2FybmluZ3MoTmJDbHVzdChkYXRhID0gbXVlc3RyYV9kaXNpbV9lc2MsIGRpc3MgPSBOVUxMLCBkaXN0YW5jZSA9ICJldWNsaWRlYW4iLCBtaW4ubmMgPSAyLCBtYXgubmMgPSAxMCwgbWV0aG9kID0gImttZWFucyIpJEJlc3QubmMpDQoNCmBgYA0KDQojIyMjIFJlc3VsdGFkb3MgSy1NZWFuc3sudGFic2V0IC50YWJzZXQtcGlsbHN9DQoNCiMjIyMjIEstw5NwdGltbyBbRWxfTWEtUnVsIDNdDQpgYGB7ciBrLW9wdGltb3MsIGZpZy5hbGlnbj0nY2VudGVyJ30NCnNldC5zZWVkKDc4MDcyOSkNCnByaW50KGttZWFucyhtdWVzdHJhX2Rpc2ltX2VzYywgMywgbnN0YXJ0ID0gMjUpKQ0KYGBgDQoNCiMjIyMjIEstw5NwdGltbyBbc2lsIDRdDQpgYGB7ciBrLW9wdGltb19zaWwsIGZpZy5hbGlnbj0nY2VudGVyJ30NCnNldC5zZWVkKDc4MDcyOSkNCnByaW50KGttZWFucyhtdWVzdHJhX2Rpc2ltX2VzYywgNCwgbnN0YXJ0ID0gMjUpKQ0KYGBgDQoNCiMjIyMgR3LDoWZpY29zIEstTWVhbnN7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQojIyMjIyBLLcOTcHRpbW8gW0VsYl9NYS1SdWwgM10NCmBgYHtyIEdyYWZfRWxiX01hLVJ1bCwgZmlnLmFsaWduPSdjZW50ZXInfQ0KZnZpel9jbHVzdGVyKGttZWFucyhtdWVzdHJhX2Rpc2ltX2VzYywgMywgbnN0YXJ0ID0gMjUpLCBkYXRhID0gbXVlc3RyYV9kaXNpbV9lc2MsIHBhbGV0dGUgPSBjKCIjMkU5RkRGIiwgIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRTdCODAxIiksIGVsbGlwc2UudHlwZSA9ICJldWNsaWQiLCBzdGFyLnBsb3QgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCkNCikNCmBgYA0KDQojIyMjIyBLLcOTcHRpbW8gIFtzaWwgNF0NCmBgYHtyIEdyYWZfc2lsLCBmaWcuYWxpZ249J2NlbnRlcid9DQpmdml6X2NsdXN0ZXIoa21lYW5zKG11ZXN0cmFfZGlzaW1fZXNjLCAyLCBuc3RhcnQgPSAyNSksIGRhdGEgPSBtdWVzdHJhX2Rpc2ltX2VzYywgcGFsZXR0ZSA9IGMoIiMyRTlGREYiLCAiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNFN0I4MDEiKSwgZWxsaXBzZS50eXBlID0gImV1Y2xpZCIsIHN0YXIucGxvdCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgZ2d0aGVtZSA9IHRoZW1lX21pbmltYWwoKQ0KKQ0KDQpgYGANCg0KPGEgbmFtZT0ic2VjNSI+PC9hPg0KDQojIyAqKkZhc2UgNSBbQW7DoWxpc2lzIGRlIFJlZ3Jlc2nDs25dKioNCg0KIyMjIDUuMS4gT2JqZXRpdm9zDQojIyMgNS4yLiBSZWdyZXNpw7NuIExpbmVhbCBTaW1wbGUNCiMjIyA1LjMuIFJlZ3Jlc2nDs24gTGluZWFsIE3Dumx0aXBsZQ0KIyMjIDUuNC4gUmVncmVzacOzbiBMb2fDrXN0aWNhIFNpbXBsZQ0KIyMjIDUuNS4gQWp1c3RlIGRlIFZhcmlhbnphDQoNCiMjICoqNi4gQ29uY2x1c2lvbmVzKioNCg0KIyMgKio3LiBCaWJsaW9ncmFmw61hKio=