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 1.000.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 × 10] (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 ...

Conjunto de Datos Original Depurado

vehicle_price_prediction_modificado_MUESTREADO20K_ETL
## # A tibble: 19,798 × 10
##    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
## # ℹ 6 more variables: tipo_de_combustible <chr>, color_exterior <chr>,
## #   cant_propietarios <dbl>, antiguedad_vehiculo <dbl>,
## #   kilometraje_anual <dbl>, precio <dbl>

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)], 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)]
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)]),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)]),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)])

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)]
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)]
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 Doornik-Hansen 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 Shapiro-Wilk 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 Royston utiliza las pruebas de Shapiro-Wilk o Shapiro-Francia para evaluar la normalidad multivariada. Si la curtosis es mayor que 3, se emplea Shapiro-Francia para distribuciones leptocúrticas, mientras que para distribuciones platicúrticas se utiliza Shapiro-Wilk. Los parámetros en esta prueba se obtienen mediante aproximaciones polinomiales.

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

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

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

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.7. Interpretación normalidad multivariada {.tabset .tabset-pills}

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 denominada 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. Calidad de Representación

Matriz ACP

get_eigenvalue(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6)], 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)]),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)], 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)], 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)]), method = "color", type = "upper", number.cex = 0.4)
corrplot::corrplot(cor(princomp(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6)], 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)], 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)],factors = FALSE, pc = TRUE, main ="")

Interpretación y análisis

2.4. Contribuciones y Biplots

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.

Con los datos procesados hasta ahora se puede proceder con la intepretación de los componentes.

2.5. Desarrollo del análisis

Círculo de Correlaciones

fviz_pca_var(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6)], 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)], 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)], 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)], 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

2.6. Contribuciones

###2.7. Planteamiento y Desarrollo {.tabset .tabset-pills} #### Matriz de Contribuciones

(get_pca_var(PCA(vehicle_price_prediction_modificado_MUESTREADO20K_ETL[,-c(1,2,4,5,6)], 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)], 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)], 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)], 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)], 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)], 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. Planteamiento y Desarrollo

Biplot de Variables y Registros [filtro:ChestPain]

Biplot de Variables y Registros [filtro:Gender]

Biplot de Variables y Registros [filtro:N.of Major Vessels]

Coordenadas Individuales [ChestPain]

Fase 3 [Correspondencias]

3.1. Objetivos

3.2. Correspondencias Simples

3.3. Correspondencias Múltiples

Fase 4 [Conglomerados]

4.1. Objetivos

4.2. Agrupación Jerárquica

4.3. Agrupación No-Jerárquica

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

Díaz Morales, L. G., & Morales Rivera, M. A. (2012). Análisis estadístico de datos multivariados (1st ed.). UNAL.
LS0tDQp0aXRsZTogIioqdGZjX2dkZF8yMDI1XzJncnVwb181KioiDQpzdWJ0aXRsZTogIkVzdHVkaW8gZGUgQW7DoWxpc2lzIE11bHRpdmFyaWFkbyBjb24gYmFzZSBlbiB1biBjb25qdW50byBkZSBkYXRvcyBzb2JyZSByZWdpc3Ryb3MgZGUgdmVoaWN1bG9zIHVzYWRvcyBjb24gZWwgZmluIGRlIHByZWRlY2lyIHN1IHByZWNpbyBzZWfDum4gc3VzIGNvbmRpY2lvbmVzLiINCmF1dGhvcjogIlBvcjogUGFvbGEgQ2FzdHJvIChwYW9sYS5hbmRyZWEuY2FzdHJvQGNvcnJlb3VuaXZhbGxlLmVkdS5jbyksQW5naWUgVsOhc2NvbmV6IFZhbGVuY2lhIChhbmdpZS52YXNjb25lekBjb3JyZW91bml2YWxsZS5lZHUuY28pLE1hcmlhIEpvc2UgQmFuZGVyYXMgUml2YXMgKGJhbmRlcmFzLm1hcmlhQGNvcnJlb3VuaXZhbGxlLmVkdS5jbyksTHVpcyBGZXJuYW5kbyBNb3JhbGVzIFBlbmFnb3MgKGx1aXMubW9yYWxlcy5wZW5hZ29zQGNvcnJlb3VuaXZhbGxlLmVkdS5jbyksR2lybWFuIEFuZHLDqXMgQ3VlcnZvIEFyYW5nbyAoZ2lybWFuLmN1ZXJ2b0Bjb3JyZW91bml2YWxsZS5lZHUuY28pIg0KZGF0ZTogIlRyYWJham8gZWxhYm9yYWRvIGVuIGVsIHBlcmlvZG8gYWNhZMOpbWljbyBjb21wcmVuZGlkbyBlbnRyZSBhZ29zdG8geSBkaWNpZW1icmUgZGVsIGHDsW8gMjAyNSwgY29tbyBhY3RpdmlkYWQgZm9ybWF0aXZhIHkgZXZhbHVhdGl2YSBkZWwgY3Vyc28gR2VzdGnDs24gZGUgRGF0b3MgcGFyYSBpbmdlbmllcsOtYSBJbmR1c3RyaWFsLiINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IGx1bWVuDQpiaWJsaW9ncmFwaHk6IGJpYmxpb2dyYWZpYV9NRS5iaWINCmNzbDogYXBhLmNzbA0KbGluay1jaXRhdGlvbnM6IHllcw0KLS0tDQo8IS0tIENvbmZpZ3VyYWNpw7NuIEdsb2JhbCBkZSBSIC0tPi0tLQ0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoY29ycnBsb3QpDQpsaWJyYXJ5KEdHYWxseSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoYW5kcmV3cykNCmxpYnJhcnkodGNsdGspDQpsaWJyYXJ5KGFwbHBhY2spDQpsaWJyYXJ5KGdyYXBoaWNzKQ0KbGlicmFyeShyZXNoYXBlMikNCmxpYnJhcnkoRmFjdG9NaW5lUikNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmxpYnJhcnkocHN5Y2gpDQpsaWJyYXJ5KEZhY3RvQ2xhc3MpDQpsaWJyYXJ5KGNsdXN0ZXIpDQpsaWJyYXJ5KGRlbmRleHRlbmQpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KbGlicmFyeShOYkNsdXN0KQ0KbGlicmFyeShzdGFyZ2F6ZXIpDQojbGlicmFyeShnZ3BhaXJzKQ0KbGlicmFyeShtdm5vcm1hbFRlc3QpDQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPVRSVUUpDQoNCnZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMIDwtIHJlYWRfZXhjZWwoInZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMLnhsc3giKQ0KDQpgYGANCg0KIyMgKipGYXNlIDEgW0Rlc2NyaXBjaW9uZXMgTXVsdGl2YXJpYW50ZXNdKiogDQoNCiMjIyAxLjEuIE9iamV0aXZvcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFbCBvYmpldGl2byBkZSBlc3RlIHByb3llY3RvIGVzIGFwbGljYXIgdMOpY25pY2FzIGRlIGFuw6FsaXNpcyBtdWx0aXZhcmlhZG8gcGFyYSBnZXN0aW9uYXIgZWwgY29uanVudG8gZGUgZGF0b3MgYXByb2JhZG8sIGNvcnJlc3BvbmRpZW50ZSBhIHJlZ2lzdHJvcyByZWxhY2lvbmFkb3MgY29uIHByZWRpY2Npw7NuIGRlIHByZWNpb3MgZGUgdmVow61jdWxvcyB1c2Fkb3MuIEVsIHByb3DDs3NpdG8gZXMgb3JnYW5pemFyIHkgcHJvY2VzYXIgZWZpY2F6bWVudGUgbGEgaW5mb3JtYWNpw7NuLCBkZXNhcnJvbGxhbmRvIGhhYmlsaWRhZGVzIGVuIGxhIGdlc3Rpw7NuIHkgYW7DoWxpc2lzIGRlIGRhdG9zLiBFc3RlIHRyYWJham8gc2UgZW5tYXJjYSBkZW50cm8gZGVsIGN1cnNvIGRlICoqR2VzdGnDs24gZGUgRGF0b3MqKiwgZGljdGFkbyBwb3IgZWwgUHJvZmVzb3IgR2lhbmNhcmxvIExpYnJlcm9zIExvbmRvw7FvIGVuIGxhIFVuaXZlcnNpZGFkIGRlbCBWYWxsZS4gDQoNCjxhIG5hbWU9InNlYzEuMiI+PC9hPg0KDQojIyMgMS4yLiBEZXNjcmlwY2nDs24gZGUgbG9zIGRhdG9zIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQoNCkVsIGNvbmp1bnRvIGRlIGRhdG9zIGZ1ZSBvYnRlbmlkbyBlbiBzdSB0b3RhbGlkYWQgZGUgICoqS2FnZ2xlKio6IChodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL21ldGF3YXZlL3ZlaGljbGUtcHJpY2UtcHJlZGljdGlvbikgS2FnZ2xlIGVzIHVuYSBwbGF0YWZvcm1hIGVuIGzDrW5lYSBkZSBjaWVuY2lhIGRlIGRhdG9zIHkgYXByZW5kaXphamUgYXV0b23DoXRpY28sIHByb3BpZWRhZCBkZSBHb29nbGUgTExDLiBFc3RhIGZhY2lsaXRhIGxhIHBhcnRpY2lwYWNpw7NuIGVuIGNvbXBldGVuY2lhcyBkb25kZSBsYXMgZW1wcmVzYXMgcHVibGljYW4gY29uanVudG9zIGRlIGRhdG9zIHkgcHJvYmxlbWFzLCBwZXJtaXRpZW5kbyBhIGxvcyB1c3VhcmlvcyBkZXNhcnJvbGxhciBtb2RlbG9zIHByZWRpY3Rpdm9zIHkgY29tcGV0aXIuIExhIHBsYXRhZm9ybWEgdGFtYmnDqW4gb2ZyZWNlIG5vdGVib29rcyBwYXJhIGNvbXBhcnRpciB5IGNvbGFib3JhciBlbiBwcm95ZWN0b3MgdXRpbGl6YW5kbyBQeXRob24geSBSLCBhc8OtIGNvbW8gdW5hIGFtcGxpYSBjb2xlY2Npw7NuIGRlIGNvbmp1bnRvcyBkZSBkYXRvcyBkZSBhY2Nlc28gcMO6YmxpY28uIEFkZW3DoXMsIEthZ2dsZSBMZWFybiwgdW5hIHNlY2Npw7NuIGRlIGxhIHBsYXRhZm9ybWEgZGVkaWNhZGEgYSBsYSBlZHVjYWNpw7NuIHkgZWwgYXByZW5kaXphamUgZW4gY2llbmNpYSBkZSBkYXRvcyB5IGFwcmVuZGl6YWplIGF1dG9tw6F0aWNvIHByb3BvcmNpb25hIHR1dG9yaWFsZXMgeSBjdXJzb3MgaW50ZXJhY3Rpdm9zIGVuIHRlbWFzIGNvbW8gUHl0aG9uLCBTUUwsIHZpc3VhbGl6YWNpw7NuIGRlIGRhdG9zIHkgYXByZW5kaXphamUgYXV0b23DoXRpY28sIGRpcmlnaWRvcyBhIHByaW5jaXBpYW50ZXMgeSB1c3VhcmlvcyBhdmFuemFkb3MuDQoNCkVzdGUgY29uanVudG8gZGUgZGF0b3Mgc2UgcmVsYWNpb25hIGNvbiBkaXZlcnNhcyDDoXJlYXMgZGUgbGEgaW5nZW5pZXLDrWEgaW5kdXN0cmlhbCwgZGViaWRvIGEgcXVlIHN1IGRlc2Fycm9sbG8geSBhbsOhbGlzaXMgaW1wbGljYW4gbGEgYXBsaWNhY2nDs24gZGUgcHJpbmNpcGlvcyBwcm9waW9zIGRlIGxhIGRpc2NpcGxpbmEuIEVuIHByaW1lciBsdWdhciwgc2UgdmluY3VsYSBjb24gbGEgKiplc3RhZMOtc3RpY2EgeSBlbCBhbsOhbGlzaXMgZGUgZGF0b3MoMi5vcGVyYXRpb25zIHJlc2VhcmNoIHkgYW5hbHlzaXMpKiosIGFsIGVtcGxlYXIgbcOpdG9kb3MgZXN0YWTDrXN0aWNvcyBwYXJhIGVzdHVkaWFyIGxhIGluZm9ybWFjacOzbiB5IGdlbmVyYXIgbW9kZWxvcyBwcmVkaWN0aXZvcyBwcmVjaXNvcy4gVGFtYmnDqW4sIHNlIGFzb2NpYSBjb24gbGEgKipnZXN0acOzbiBkZSBsYSBjYWxpZGFkICg1LnF1YWxpdHkgeSByZWxpYWJpbGl0eSBlbmdpbmVlcmluZykqKiwgcG9ycXVlIGdhcmFudGl6YSBxdWUgbG9zIGRhdG9zIHNlYW4gY29oZXJlbnRlcywgY29tcGxldG9zIHkgY29uZmlhYmxlcy4gQXNpbWlzbW8sIGludGVydmllbmUgbGEgKippbnZlc3RpZ2FjacOzbiBkZSBvcGVyYWNpb25lcyAoNy5vcGVyYXRpb25zIGVuZ2luZWVyaW5nIHkgbWFuYWdlbWVudCkqKiwgcXVlIHBlcm1pdGUgb3B0aW1pemFyIGxvcyBhbGdvcml0bW9zIHV0aWxpemFkb3MgcGFyYSBlc3RpbWFyIGxvcyBwcmVjaW9zIGRlIG1hbmVyYSBlZmljaWVudGUuIEVuIGN1YW50byBhbCAqKmFuw6FsaXNpcyBlY29uw7NtaWNvIGRlIGluZ2VuaWVyw61hICgzLmVuZ2luZWVyaW5nIGVjb25vbWljIGFuYWx5c2lzKSoqLCBzZSB2ZSByZWZsZWphZG8gZW4gZWwgYW7DoWxpc2lzIGRlIGxhIHJlbnRhYmlsaWRhZCB5IGxhIGRlcHJlY2lhY2nDs24gZGUgbG9zIHZlaMOtY3Vsb3MgYSBsbyBsYXJnbyBkZWwgdGllbXBvLHRhbWJpw6luLHNlIHZlIHJlcHJlc2VudGFkbyBlbiBlbCBlc3R1ZGlvIGRlbCBraWxvbWV0cmFqZSB5IGxhIGFudGlnw7xlZGFkIGNvbW8gZmFjdG9yZXMgcXVlIGluZmx1eWVuIGVuIGVsIHByZWNpbyBkZSBsb3MgYXV0b23Ds3ZpbGVzLiBBZGljaW9uYWxtZW50ZSwgZWwgZXN0dWRpbyBzZSByZWxhY2lvbmEgY29uIGxhICoqZ2VzdGnDs24gZGUgcHJveWVjdG9zICg5LmVuZ2luZWVyaW5nIG1hbmFnZW1ldCkqKiwgYWwgcmVxdWVyaXIgdW5hIHBsYW5lYWNpw7NuIGVzdHJ1Y3R1cmFkYSBwYXJhIGVsIGRlc2Fycm9sbG8geSBlamVjdWNpw7NuIGRlbCBzY3JpcHQgZ2VuZXJhZG9yIGRlIGxvcyBkYXRvcy4gRGUgaWd1YWwgbWFuZXJhLCBsb3MgKipzaXN0ZW1hcyBkZSBpbmZvcm1hY2nDs24gKDExLmluZm9ybWF0aW9uIGVuZ2luZWVyaW5nKSoqIGRlc2VtcGXDsWFuIHVuIHBhcGVsIGZ1bmRhbWVudGFsIGVuIGVsIGFsbWFjZW5hbWllbnRvLCBvcmdhbml6YWNpw7NuIHkgcHJvY2VzYW1pZW50byBkZSBsb3MgcmVnaXN0cm9zLCBkZSBpZ3VhbCBtYW5lcmEsIHNlIGV2aWRlbmNpYSBlbiBlbCB1c28gZGUgaGVycmFtaWVudGFzIGNvbXB1dGFjaW9uYWxlcyBjb21vIFB5dGhvbiwgcXVlIHBlcm1pdGVuIGNyZWFyIHNvbHVjaW9uZXMgYXV0b21hdGl6YWRhcyB5IGFwbGljYWJsZXMgYWwgZW50b3JubyBpbmR1c3RyaWFsLg0KDQpTZWfDum4gbGEgZGVzY3JpcGNpw7NuIGRlbCBjb25qdW50byBkZSBkYXRvcyBlbGVnaWRvIGVuIGxhIHBsYXRhZm9ybWEga2FnZ2xlLCBlc3RlIGZ1ZSBkaXNlw7FhZG8gY29uIGVsIHByb3DDs3NpdG8gZGUgY3JlYXIgdW5hIGJhc2Ugc8OzbGlkYSBwYXJhIGVsIGVudHJlbmFtaWVudG8gZGUgbW9kZWxvcyBkZSBwcmVkaWNjacOzbiBkZSBwcmVjaW9zIGF1dG9tb3RyaWNlcyBkZSBhbHRhIHByZWNpc2nDs24uIENvbnRpZW5lIHVuIHRvdGFsIGRlIDEuMDAwLjAwMCByZWdpc3Ryb3MgcXVlIHJlcHJlc2VudGFuIHVuYSBhbXBsaWEgdmFyaWVkYWQgZGUgbWFyY2FzLCBtb2RlbG9zIHkgZXNwZWNpZmljYWNpb25lcywgYWJhcmNhbmRvIDI1IGRlIGxhcyBtYXJjYXMgbcOhcyBjb211bmVzIGVuIGVsIG1lcmNhZG8gYXV0b21vdG9yLiBDYWRhIHJlZ2lzdHJvIGZ1ZSBjb25zdHJ1aWRvIGNvbnNpZGVyYW5kbyByZWxhY2lvbmVzIHkgZGlzdHJpYnVjaW9uZXMgcmVhbGlzdGFzIGVudHJlIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGRlbCB2ZWjDrWN1bG8geSBzdSB2YWxvciBjb21lcmNpYWwsIGNvbiBlbCBmaW4gZGUgcmVmbGVqYXIgY29tcG9ydGFtaWVudG9zIG9ic2VydmFibGVzIGVuIGNvbnRleHRvcyByZWFsZXMgZGUgY29tcHJhdmVudGEuIExhIGzDs2dpY2EgaW1wbGVtZW50YWRhIGVuIGxhIGdlbmVyYWNpw7NuIGRlIGxvcyBkYXRvcyBjb250ZW1wbGEgZmFjdG9yZXMgY29tbyBsYSBkZXByZWNpYWNpw7NuLCBlbCBkZXNnYXN0ZSB5IGVsIHByZWNpbyBkZSBtYXJjYS4gRW4gcHJpbWVyIGx1Z2FyLCBsYSBkZXByZWNpYWNpw7NuIHNlIG1vZGVsYSBjb21vIGxhIHByaW5jaXBhbCB2YXJpYWJsZSBxdWUgZGV0ZXJtaW5hIGxhIHJlZHVjY2nDs24gZGVsIHByZWNpbyBjb24gZWwgcGFzbyBkZWwgdGllbXBvLCBzaWd1aWVuZG8gdW5hIGN1cnZhIGRlIGRlY2xpdmUgZGUgdGlwbyBleHBvbmVuY2lhbC4gRW4gc2VndW5kbyBsdWdhciwgZWwgZGVzZ2FzdGUgc2UgYXNvY2lhIGRpcmVjdGFtZW50ZSBjb24gZWwga2lsb21ldHJhamUsIGVsIGN1YWwgc2UgY29ycmVsYWNpb25hIGNvbiBsYSBhbnRpZ8O8ZWRhZCBkZWwgdmVow61jdWxvIHkgZWplcmNlIHVuIGVmZWN0byBuZWdhdGl2byBzb2JyZSBlbCBwcmVjaW8gZmluYWwuIEZpbmFsbWVudGUsIGVsIHByZWNpbyBkZSBsYSBtYXJjYSBhY3TDumEgY29tbyB1bmEgdmFyaWFibGUgZGUgcmVmZXJlbmNpYSBxdWUgcmVmbGVqYSBlbCBwb3NpY2lvbmFtaWVudG8gZGVsIG1lcmNhZG8gZGUgY2FkYSBtYXJjYSBlbiBlbCBtdW5kbyByZWFsLiANCih0aXBvX2RlX3ZhcmlhYmxlOjplc2NhbGFfZGVfbWVkaWNpw7NuW29yZGVuYW1pZW50b10pOg0KDQotICoqa2lsb21ldHJhamUqKiAoY3VhbnRpdGF0aXZhOjpyYXrDs24pOiBSZXByZXNlbnRhIGxhIGRpc3RhbmNpYSB0b3RhbCByZWNvcnJpZGEgcG9yIGVsIHZlaMOtY3VsbyBkZXNkZSBzdSBmYWJyaWNhY2nDs24gaGFzdGEgbGEgZmVjaGEgZGVsIHJlZ2lzdHJvLCBtZWRpZGEgZW4ga2lsw7NtZXRyb3MuIA0KDQotICoqa2lsb21ldHJhamVfcG9yX2HDsW8qKiAoY3VhbnRpdGF0aXZhOjpyYXrDs24pOiBFc3RhIHZhcmlhYmxlIGV4cHJlc2EgZWwgcHJvbWVkaW8gZGUga2lsw7NtZXRyb3MgcmVjb3JyaWRvcyBhbnVhbG1lbnRlIHBvciBlbCB2ZWjDrWN1bG8uIFNlIG9idGllbmUgZGl2aWRpZW5kbyBlbCBraWxvbWV0cmFqZSB0b3RhbCBlbnRyZSBsYSBlZGFkIGRlbCBhdXRvbcOzdmlsLiANCg0KLSAqKm51bWVyb19kZV9wcm9waWV0YXJpb3NfYW50ZXJpb3JlcyoqIChjdWFudGl0YXRpdmE6OnJhesOzbik6IEluZGljYSBjdcOhbnRhcyBwZXJzb25hcyBoYW4gc2lkbyBkdWXDsWFzIGRlbCB2ZWjDrWN1bG8gYW50ZXMgZGVsIHJlZ2lzdHJvIGFjdHVhbC4gDQoNCi0gKiplZGFkX2RlbF92ZWjDrWN1bG8qKiAoY3VhbnRpdGF0aXZhOjpyYXrDs24pOiBDb3JyZXNwb25kZSBhbCBuw7ptZXJvIGRlIGHDsW9zIHRyYW5zY3Vycmlkb3MgZGVzZGUgbGEgZmVjaGEgZGUgZmFicmljYWNpw7NuIGRlbCB2ZWjDrWN1bG8gaGFzdGEgbGEgYWN0dWFsaWRhZC4gDQoNCi0gKipwcmVjaW8qKiAoY3VhbnRpdGF0aXZhOjpyYXrDs24pOiBFeHByZXNhIGVsIHByZWNpbyBhY3R1YWwgZXN0aW1hZG8gZGVsIHZlaMOtY3VsbyBlbiBlbCBtZXJjYWRvIGRlIHVzYWRvcy4NCg0KLSAqKnRyYW5zbWlzaW9uKiogKGN1YWxpdGF0aXZhOjpub21pbmFsKTogRGVzY3JpYmUgZWwgdGlwbyBkZSBzaXN0ZW1hIGRlIGNhbWJpbyBkZSBtYXJjaGFzIGRlbCB2ZWjDrWN1bG8sIGNvZGlmaWNhZG8gY29tbyAxIHBhcmEgdHJhbnNtaXNpw7NuIG1hbnVhbCB5IDAgcGFyYSBhdXRvbcOhdGljYS4gRXN0YSBlcyBsYSB2YXJpYWJsZSBkZSBkZWNpc2nDs24gcXVlIHNlIGlkZW50aWZpY2EgZW4gZXN0ZSBjb25qdW50by4NCg0KLSAqKm1hcmNhX2RlbF92ZWhpY3VsbyoqIChjdWFsaXRhdGl2YTo6bm9taW5hbCk6IElkZW50aWZpY2EgZWwgbm9tYnJlIGRlbCBmYWJyaWNhbnRlIGRlbCBhdXRvbcOzdmlsLiANCg0KLSAqKmHDsW9fZGVfZmFicmljYWNpb24qKiAoY3VhbnRpdGF0aXZhOjpyYXrDs24pOiBJbmRpY2EgZWwgYcOxbyBjYWxlbmRhcmlvIGVuIGVsIHF1ZSBlbCB2ZWjDrWN1bG8gZnVlIHByb2R1Y2lkby4gDQoNCi0gKipjb2xvcl9leHRlcmlvcioqIChjdWFsaXRhdGl2YTo6bm9taW5hbCk6IEhhY2UgcmVmZXJlbmNpYSBhbCBjb2xvciB2aXNpYmxlIGRlIGxhIGNhcnJvY2Vyw61hIGRlbCB2ZWjDrWN1bG8uIA0KDQotICoqdGlwb19kZV9jb21idXN0aWJsZSoqIChjdWFsaXRhdGl2YTo6bm9taW5hbCk6IEVzcGVjaWZpY2EgZWwgdGlwbyBkZSBlbmVyZ8OtYSBxdWUgdXRpbGl6YSBlbCB2ZWjDrWN1bG8gcGFyYSBzdSBmdW5jaW9uYW1pZW50by4gTG9zIHZhbG9yZXMgY29tdW5lcyBpbmNsdXllbiBnYXNvbGluYSwgZGnDqXNlbCwgaMOtYnJpZG8geSBlbMOpY3RyaWNvLiANCg0KDQoNCg0KDQojIyMjIEVzdHJ1Y3R1cmEgZGVsIENvbmp1bnRvIGRlIERhdG9zIEVUTA0KDQpgYGB7ciBFc3RydWN0dXJhX0Nvbmp1bnRvX2RlX0RhdG9zX0RlcHVyYWRvLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnN0cih2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCkNCmBgYA0KDQojIyMjIENvbmp1bnRvIGRlIERhdG9zIE9yaWdpbmFsIERlcHVyYWRvDQoNCmBgYHtyIENvbmp1bnRvX2RlX0RhdG9zX0RlcHVyYWRvLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMDQoNCmBgYA0KDQojIyMgMS4zLiBFc3RpbWFjaW9uZXMgbXVsdGl2YXJpYWRhcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFbCAqKnZlY3RvciBkZSBtZWRpYXMqKiB5IGxhICoqbWF0cml6IGRlIHZhcmlhbnphcy1jb3ZhcmlhbnphcyoqIGNvbmZvcm1hbiB1biBjb25qdW50byBkZSBoZXJyYW1pZW50YXMgZnVuZGFtZW50YWxlcyBwYXJhIGRlc2NyaWJpciBlbCBjb21wb3J0YW1pZW50byBwb3NpY2lvbmFsLCBkaXNwZXJzaXZvIHkgY29ycmVsYWNpb25hbCBkZSBsYXMgdmFyaWFibGVzIGFsZWF0b3JpYXMgZW4gdW4gY29uanVudG8gZGUgZGF0b3MuIEVzdGFzIG1lZGlkYXMgc29uIGVzZW5jaWFsZXMgZW4gZWwgYW7DoWxpc2lzIG11bHRpdmFyaWFkbywgeWEgcXVlIHBlcm1pdGVuIGNhcHR1cmFyIHRhbnRvIGxhIHRlbmRlbmNpYSBjZW50cmFsIGNvbW8gbGFzIGludGVyZGVwZW5kZW5jaWFzIGVudHJlIGxhcyB2YXJpYWJsZXMuDQoNCkVsIHZlY3RvciBkZSBtZWRpYXMgcmVmbGVqYSBlbCB2YWxvciBlc3BlcmFkbyBvIHB1bnRvIG1lZGlvIGRlIGNhZGEgdmFyaWFibGUsIHNpbnRldGl6YW5kbyBsYSBpbmZvcm1hY2nDs24gZGUgdG9kb3MgbG9zIHJlZ2lzdHJvcyBkaXNwb25pYmxlcyBlbiBlbCBjb25qdW50byBkZSBkYXRvcy4gUG9yIHN1IHBhcnRlLCBsYSBtYXRyaXogZGUgdmFyaWFuemFzLWNvdmFyaWFuemFzIGRlc2NyaWJlIGxhIHZhcmlhYmlsaWRhZCB5IGxhcyByZWxhY2lvbmVzIGVudHJlIGxhcyB2YXJpYWJsZXMuIEVuIHN1IGRpYWdvbmFsIHByaW5jaXBhbCwgZXN0aW1hIGxhcyBkaXNwZXJzaW9uZXMgaW5kaXZpZHVhbGVzIGRlIGNhZGEgdmFyaWFibGUgcmVzcGVjdG8gYSBzdSBtZWRpYSwgbWllbnRyYXMgcXVlIGxvcyBlbGVtZW50b3MgcG9yIGVuY2ltYSBvIHBvciBkZWJham8gZGUgZXN0YSBkaWFnb25hbCByZXByZXNlbnRhbiBsYXMgY292YXJpYW56YXMgZW50cmUgcGFyZXMgZGUgdmFyaWFibGVzLCBtb3N0cmFuZG8gbGFzIHJlbGFjaW9uZXMgbGluZWFsZXMgZXhpc3RlbnRlcyBlbnRyZSBlbGxhcy4NCg0KDQoNCiMjIyNWZWN0b3IgZGUgUHJvbWVkaW9zIHkgQm94cGxvdHMgDQoNCmBgYHtyIFZlY3Rvcl9kZV9NZWRpYXNfeV9Cb3hwbG90cywgZmlnLmFsaWduID0gJ2NlbnRlcid9DQphcHBseSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIDIsIG1lYW4pDQp2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF9SZWR1Y2lkbyA9IHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXQ0Kbm9tYnJlc19ib3hwbG90cyA8LSBjKCJraWxvbWV0cmFqZSIsIkNhbnRfcHJvcGlldGFyaW9zIiwiRWRhZF9WZWjDrWN1bG8iLCJLaWxvbWV0cmFqZV9hw7FvIiwiUHJlY2lvIikNCnBhcihtZnJvdyA9IGMoMSwgbmNvbCh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF9SZWR1Y2lkbykpKQ0KaW52aXNpYmxlKGxhcHBseSgxOm5jb2wodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfUmVkdWNpZG8pLCBmdW5jdGlvbihpKSB7DQogIGJveHBsb3QodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfUmVkdWNpZG9bLCBpXSwNCiAgICAgICAgICBtYWluID0gbm9tYnJlc19ib3hwbG90c1tpXSl9KSkNCg0KYGBgDQoNCg0KIyMjI01hdHJpeiBkZSB2YXJpYW56YXMtY292YXJpYW56YXMNCmBgYHtyIE1hdHJpel9kZV92YXJpYW56YXMtY292YXJpYW56YXMsIGZpZy5hbGlnbj0nY2VudGVyJ30NCnJvdW5kKGNvdih2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0pLDIpDQpgYGANCg0KIyMjI01hdHJpeiBkZSBjb3JyZWxhY2lvbmVzDQpgYGB7ciBNYXRyaXpfZGVfY29ycmVsYWNpb25lcywgZmlnLmFsaWduPSdjZW50ZXInfQ0Kcm91bmQoY29yKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSksMykNCmBgYA0KDQojIyMgMS40LiBQbGFudGVhbWllbnRvIHkgRGVzYXJyb2xsbyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpDb24gYmFzZSBlbiBsYSBwZXN0YcOxYSAqKlZlY3RvciBkZSBNZWRpYXMqKiB5ICoqQm94cGxvdHMqKiwgc2UgcHVlZGUgb2JzZXJ2YXIgcXVlIGxhcyB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcyBhbmFsaXphZGFzIG11ZXN0cmFuIHBhdHJvbmVzIGRlIGRpc3RyaWJ1Y2nDs24gcGFydGljdWxhcmVzLg0KDQpMYSB2YXJpYWJsZSAqKmtpbG9tZXRyYWplKiogcHJlc2VudGEgdW5hIGRpc3RyaWJ1Y2nDs24gY29uIGNvbGEgYSBsYSBkZXJlY2hhLCBsbyBxdWUgc3VnaWVyZSBxdWUgbGEgbWF5b3LDrWEgZGUgbG9zIHZlaMOtY3Vsb3MgdGllbmVuIHJlY29ycmlkb3MgbW9kZXJhZG9zLCBwZXJvIGFsZ3Vub3MgcHJlc2VudGFuIGtpbG9tZXRyYWplcyBtdXkgZWxldmFkb3MgcXVlIGV4dGllbmRlbiBsYSBjb2xhIHN1cGVyaW9yLg0KTGEgdmFyaWFibGUgKipDYW50X3Byb3BpZXRhcmlvcyoqIHRpZW5kZSBhIHRvbWFyIHZhbG9yZXMgYmFqb3MgZW4gbGEgbWF5b3LDrWEgZGUgbG9zIGNhc29zLCB5YSBxdWUgbGEgbWF5b3IgcGFydGUgZGUgbG9zIHZlaMOtY3Vsb3Mgc3VlbGVuIHRlbmVyIHBvY29zIHByb3BpZXRhcmlvcyBwcmV2aW9zOyBzaW4gZW1iYXJnbywgdGFtYmnDqW4gcHVlZGVuIGFwYXJlY2VyIHZhbG9yZXMgYXTDrXBpY29zIGFzb2NpYWRvcyBhIGF1dG9tw7N2aWxlcyBjb24gbcO6bHRpcGxlcyB0cmFuc2ZlcmVuY2lhcy4NCg0KTGEgKipFZGFkX1ZlaMOtY3VsbyoqIHB1ZWRlIHByZXNlbnRhciBjaWVydGEgYXNpbWV0csOtYSBoYWNpYSBsYSBkZXJlY2hhLCB5YSBxdWUgcHJlZG9taW5hbiB2ZWjDrWN1bG9zIHJlbGF0aXZhbWVudGUgcmVjaWVudGVzLCBtaWVudHJhcyBxdWUgYWxndW5vcyBtb2RlbG9zIG3DoXMgYW50aWd1b3MgZ2VuZXJhbiBsYSBleHRlbnNpw7NuIGRlIGxhIGNvbGEuDQoNCkVuIGN1YW50byBhIGxhIHZhcmlhYmxlICoqS2lsb21ldHJhamVfYcOxbyoqLCBlc3TDoSBnZW5lcmFsbWVudGUgcHJlc2VudGEgdW5hIGRpc3RyaWJ1Y2nDs24gY29uIGNvbGEgYSBsYSBkZXJlY2hhLCBkYWRvIHF1ZSBsYSBtYXlvcsOtYSBkZSBsb3MgdmVow61jdWxvcyB0aWVuZW4gdW4gdXNvIGFudWFsIG1vZGVyYWRvLCBwZXJvIGFsZ3Vub3MgcmVnaXN0cmFuIHVuIHVzbyBtdXkgaW50ZW5zaXZvIHF1ZSBpbmNyZW1lbnRhIG5vdGFibGVtZW50ZSBsb3MgdmFsb3JlcyBzdXBlcmlvcmVzLg0KDQpGaW5hbG1lbnRlLCBsYSB2YXJpYWJsZSAqKlByZWNpbyoqIHRhbWJpw6luIHB1ZWRlIG1vc3RyYXIgdW5hIGxpZ2VyYSBjb2xhIGhhY2lhIGxhIGRlcmVjaGEsIGluZGljYW5kbyBxdWUgbGEgbWF5b3LDrWEgZGUgbG9zIHZlaMOtY3Vsb3Mgc2UgY29uY2VudHJhbiBlbiByYW5nb3MgZGUgcHJlY2lvcyBtZWRpb3MsIG1pZW50cmFzIHF1ZSB1bm9zIHBvY29zLCBjb24gY2FyYWN0ZXLDrXN0aWNhcyBwYXJ0aWN1bGFyZXMgbyBnYW1hcyBzdXBlcmlvcmVzLCBlbGV2YW4gbGEgY29sYSBzdXBlcmlvciBkZSBsYSBkaXN0cmlidWNpw7NuLg0KDQpDb24gYmFzZSBlbiBsYSAqKm1hdHJpeiBkZSB2YXJpYW56YXMtY292YXJpYW56YXMqKiB5IGxhICoqbWF0cml6IGRlIGNvcnJlbGFjaW9uZXMqKiwgc2UgaWRlbnRpZmljYSBxdWUgbGFzIHJlbGFjaW9uZXMgbGluZWFsZXMgZW50cmUgbGFzIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzIHN1ZWxlbiBzZXIgZGUgYmFqYSBhIG1vZGVyYWRhIGludGVuc2lkYWQuDQoNCkVzIGNvbcO6biBxdWUgdmFyaWFibGVzIGNvbW8gKipraWxvbWV0cmFqZSoqIHkgKipFZGFkX1ZlaMOtY3VsbyoqIHByZXNlbnRlbiB1bmEgY29ycmVsYWNpw7NuIHBvc2l0aXZhLCB5YSBxdWUgbG9zIHZlaMOtY3Vsb3MgbcOhcyBhbnRpZ3VvcyB0aWVuZGVuIGEgaGFiZXIgcmVjb3JyaWRvIG1heW9yZXMgZGlzdGFuY2lhcy4NCg0KUG9yIG90cm8gbGFkbywgdmFyaWFibGVzIGNvbW8gKipQcmVjaW8qKiBwdWVkZW4gbW9zdHJhciBjb3JyZWxhY2lvbmVzIG1vZGVyYWRhcyBvIGTDqWJpbGVzIGNvbiAqKktpbG9tZXRyYWplX2HDsW8qKiBvICoqQ2FudF9wcm9waWV0YXJpb3MqKiwgbG8gcXVlIHN1Z2llcmUgcXVlIHN1IGluZmx1ZW5jaWEgZGlyZWN0YSBubyBlcyBlc3RyaWN0YW1lbnRlIGxpbmVhbC4NCg0KRW4gZ2VuZXJhbCwgbG9zIGNvZWZpY2llbnRlcyBkZSBjb3JyZWxhY2nDs24gY2VyY2Fub3MgYSBjZXJvIGluZGljYW4gcXVlICoqbm8gZXhpc3RlbiByZWxhY2lvbmVzIGxpbmVhbGVzIGZ1ZXJ0ZXMqKiBlbnRyZSBsYXMgdmFyaWFibGVzLCBwb3IgbG8gcXVlIHN1cyBlZmVjdG9zIG11dHVvcyBzb24gbGltaXRhZG9zLiBFc3RvIGFicmUgbGEgcG9zaWJpbGlkYWQgZGUgaW50ZXJhY2Npb25lcyBubyBsaW5lYWxlcyBvIGRlIHF1ZSBjYWRhIHZhcmlhYmxlIGNhcHR1cmUgZGltZW5zaW9uZXMgZGlzdGludGFzIGRlbCBlc3RhZG8sIGhpc3RvcmlhbCB5IHZhbG9yIGRlbCB2ZWjDrWN1bG8uIEVzdG9zIGFzcGVjdG9zIHNlIGV4cGxvcmFuIGNvbiBtYXlvciBkZXRhbGxlIGVuIGxhIFtzZWNjacOzbiAxLjVdKCNzZWMxLjUpIA0KDQojIyMgMS41LiBHcsOhZmljYXMgbXVsdGl2YXJpYWRhcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFbiBnZW5lcmFsLCBsb3MgKipncsOhZmljb3MgbXVsdGl2YXJpYWRvcyoqIGN1bXBsZW4gZG9zIG9iamV0aXZvcyBlc2VuY2lhbGVzOiBwcmltZXJvLCBheXVkYW4gYSBjb21wYXJhciBlbCBjb21wb3J0YW1pZW50byBkZSBwb2JsYWNpb25lcyBkZSBlc3R1ZGlvIGNvbiBiYXNlIGVuIHZhcmlhYmxlcyBjYXRlZ8OzcmljYXMgeSBmYWNpbGl0YW4gbGEgY29tcHJlbnNpw7NuIGRlIGxhIGVzdHJ1Y3R1cmEgZGUgY29ycmVsYWNpw7NuIGVudHJlIHZhcmlhcyB2YXJpYWJsZXMuIEFkZW3DoXMsIHBlcm1pdGVuIGlkZW50aWZpY2FyIHBhdHJvbmVzLCB0ZW5kZW5jaWFzLCB5IHBvc2libGVzIG91dGxpZXJzIGVuIGxvcyBkYXRvcywgc2ltcGxpZmljYW5kbyBsYSBpbnRlcnByZXRhY2nDs24gZGUgcmVsYWNpb25lcyBjb21wbGVqYXMgeSBkZXN0YWNhbmRvIGxhcyBjYXJhY3RlcsOtc3RpY2FzIG3DoXMgc2lnbmlmaWNhdGl2YXMgZGUgbG9zIG1pc21vcyAoQWxkw6FzLCAyMDE3KS4gRW4gZXN0ZSBzZW50aWRvLCBlbCBjb25qdW50byBkZSBkYXRvcyBkZSB0cmFiYWpvIHRlbmRyw6EgYXBveW8gZGVzY3JpcHRpdm8gZ3LDoWZpY28gYSB0cmF2w6lzIGRlIHRyZXMgZGlhZ3JhbWFzOiB1bm8gY29uanVudG8gcXVlIGludGVncmEgZGlzcGVyc2nDs24sIGRpc3RyaWJ1Y2nDs24geSBjb3JyZWxhY2lvbmVzOyBvdHJvIGJhc2FkbyBlbiBsYSByZW5kZXJpemFjacOzbiBkZSBwb2zDrWdvbm9zOyB5LCBwb3Igw7psdGltbywgdW5vIHF1ZSByZWN1cnJlIGEgbGFzIGNhcmFzIGRlIENoZXJub2ZmLg0KDQoNCiMjIyMgRGlhZ3JhbWEgQ29uanVudG8gZGUgRGlzcGVyc2nDs24sIERpc3RyaWJ1Y2nDs24geSBDb3JyZWxhY2lvbmVzIFtTQV0NCmBgYHtyIERpYWdyYW1hX0NEX3ZlaGljbGVfcHJpY2VfcHJlZGljdGlvbiwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQpnZ3BhaXJzKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSkNCmBgYA0KDQoNCiMjIyMgRGlhZ3JhbWEgQ29uanVudG8gZGUgRGlzcGVyc2nDs24sIERpc3RyaWJ1Y2nDs24geSBDb3JyZWxhY2lvbmVzIFtDQV0NCmBgYHtyIERpYWdyYW1hX2Rpc3BlcnNpb25fZ2VuZGVyLCBmaWcuYWxpZ249J2NlbnRlcid9DQp2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0cmFuc21pc2lvbiA8LSBmYWN0b3IodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdHJhbnNtaXNpb24pDQpsZXZlbHM9IGMgKDAsMSkNCmxhYmVscz0gYyAoICJhdXRvbWF0aWNvIiAsICJtYW51YWwiKQ0KZ2dwYWlycyh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCwgY29sdW1uID0gYygzLDcsOCw5LDEwKSwgYWVzKGNvbG9yID0gdHJhbnNtaXNpb24sIGFscGhhID0gMC41KSwgdXBwZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSB3cmFwKCJjb3IiLCBzaXplID0gMi41KSkpDQoNCmBgYA0KDQoNCiMjIyMgRGlhZ3JhbWEgZGUgRXN0cmVsbGFzDQpgYGB7ciBEaWFncmFtYV9kZV9Fc3RyZWxsYXMsIGZpZy5hbGlnbj0nY2VudGVyJ30NCnNldC5zZWVkKDA1MTgwMikNCnZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvID0gdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbc2FtcGxlKDE6bnJvdyh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCksMjMpLC1jKDEsMiw0LDUsNildDQpzdGFycyh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2FkbywgbGVuID0gMSwgY2V4ID0gMC40LCBrZXkubG9jID0gYygxMCwgMiksIGRyYXcuc2VnbWVudHMgPSBUUlVFKQ0KYGBgDQoNCiMjIyMgY2FyYXMgZGUgY2hlcm5vZmYNCmBgYHtyIGNhcmFzX2RlX2NoZXJub2ZmLCBmaWcuYWxpZ249J2NlbnRlcid9DQpzZXQuc2VlZCgwNTE4MDIpDQp2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2FkbyA9IHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMIFtzYW1wbGUoMTpucm93KHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMKSwyMyksLWMoMSwyLDQsNSw2KV0NCmZhY2VzKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvKQ0KYGBgDQoNCg0KIyMjIDEuNi4gTm9ybWFsaWRhZCBtdWx0aXZhcmlhZGEgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KRXMgcG9zaWJsZSBhbmFsaXphciBvIGRldGVybWluYXIgbGEgZGlzdHJpYnVjacOzbiBtdWx0aXZhcmlhZGEgZGUgdW4gY29uanVudG8gZGUgZGF0b3MgbWVkaWFudGUgbcOpdG9kb3MgZGVzY3JpcHRpdm9zLCBjb21vIGxvcyBncsOhZmljb3MsIG8gaW5mZXJlbmNpYWxlcywgY29tbyBsYXMgcHJ1ZWJhcyBlc3RhZMOtc3RpY2FzLiBNaWVudHJhcyBxdWUgbG9zIHByb2NlZGltaWVudG9zIGluZmVyZW5jaWFsZXMgcGVybWl0ZW4gb2J0ZW5lciBjb25jbHVzaW9uZXMgbcOhcyBnZW5lcmFsaXphYmxlcywgbG9zIGdyw6FmaWNvcyByZXN1bHRhbiDDunRpbGVzIGNvbW8gc29wb3J0ZSBwYXJhIGxhIGludGVycHJldGFjacOzbiBkZSBsb3MgcmVzdWx0YWRvcy4NCg0KRW4gZXN0ZSBhcGFydGFkbyBzZSBhYm9yZGEgbGEgYXBsaWNhY2nDs24gZGUgcHJvY2VkaW1pZW50b3MgaW5mZXJlbmNpYWxlcyBwYXJhIHZlcmlmaWNhciBzaSBlbCBjb25qdW50byBkZSBkYXRvcyBkZSB0cmFiYWpvLCByZXNwZWN0byBhIHN1cyB2YXJpYWJsZXMgbnVtw6lyaWNhcywgc2lndWUgdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIG11bHRpdmFyaWFkYSAoRE5NKS4gTGFzIHBydWViYXMgZGUgbm9ybWFsaWRhZCBtdWx0aXZhcmlhZGEgKFBOTSkgcXVlIHNlIGFwbGljYXLDoW4gc29uOiBNYXJkaWEsIEhlbnplLVppcmtsZXIsIERvb3JuaWstSGFuc2VuIHkgUm95c3Rvbi4gRXN0YXMgcHJ1ZWJhcyBkZSBub3JtYWxpZGFkIHNlIHJlYWxpemFuIGJham8gdW4gbml2ZWwgZGUgc2lnbmlmaWNhbmNpYSBkZXRlcm1pbmFkbyAkXGFscGhhID0gMC4wNSQgeSBhIGxhcyBoaXDDs3Rlc2lzOiQkSF8wOiBcdGV4dCB7TGFzIHZhcmlhYmxlcyB0aWVuZW4gdW5hIEROTX0kJCAkJEhfMTogXHRleHQge0xhcyB2YXJpYWJsZXMgTk8gdGllbmVuIHVuYSBETk19JCQgDQoNCkxhICoqcHJ1ZWJhIGRlIE1hcmRpYSoqIHNlIGZ1bmRhbWVudGEgZW4gbGFzIGV4dGVuc2lvbmVzIGRlIGFzaW1ldHLDrWEgeSBjdXJ0b3NpcywgZWwgY3VhZHJhZG8gZGUgbGEgZGlzdGFuY2lhIGRlIE1haGFsYW5vYmlzLCBlbCBuw7ptZXJvIGRlIHZhcmlhYmxlcyAkcCQgYSBhbmFsaXphciB5IGVsIG7Dum1lcm8gZGUgcmVnaXN0cm9zICRuJC4gQXNpbWlzbW8sIHNlIGNvbnNpZGVyYSBxdWUgbGEgZXN0YWTDrXN0aWNhIGRlIGxhIHBydWViYSBwYXJhIGxhIGFzaW1ldHLDrWEgc2lndWUgdW5hIGRpc3RyaWJ1Y2nDs24gJFxjaGleMiQsIG1pZW50cmFzIHF1ZSBsYSBlc3RhZMOtc3RpY2EgcGFyYSBsYSBjdXJ0b3NpcyBzZSBkaXN0cmlidXllIGRlIG1hbmVyYSBhcHJveGltYWRhIGRlIGZvcm1hIG5vcm1hbC4gDQoNCkxhICoqcHJ1ZWJhIGRlIEhlbnplLVppcmtsZXIqKiBzZSBiYXNhIGVuIGxhIGRpc3RhbmNpYSBmdW5jaW9uYWwsIHlhIHF1ZSBzaSBlbCBjb25qdW50byBkZSBkYXRvcyBzaWd1ZSB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwgbXVsdGl2YXJpYWRhLCBlbCBlc3RhZMOtc3RpY28gZGUgbGEgcHJ1ZWJhIHNlIGRpc3RyaWJ1eWUgZGUgbWFuZXJhIGFwcm94aW1hZGEgY29tbyB1bmEgbG9nbm9ybWFsLCBjb24gcGFyw6FtZXRyb3MgZGUgbWVkaWEgJFxtdSQgeSB2YXJpYW56YSAkXHNpZ21hXjIkLiANCg0KTGEgKipwcnVlYmEgZGUgRG9vcm5pay1IYW5zZW4qKiBzZSBiYXNhIGVuIGxhIGFzaW1ldHLDrWEgeSBsYSBjdXJ0b3NpcyBkZSB1biBjb25qdW50byBkZSBkYXRvcyBtdWx0aXZhcmlhZG9zLCBsb3MgY3VhbGVzIHNlIHRyYW5zZm9ybWFuIHBhcmEgYXNlZ3VyYXIgbGEgaW5kZXBlbmRlbmNpYS4gU2UgY29uc2lkZXJhIG3DoXMgcG90ZW50ZSBxdWUgbGEgcHJ1ZWJhIGRlIFNoYXBpcm8tV2lsayBlbiBjYXNvcyBtdWx0aXZhcmlhZG9zLiBFbCBlc3RhZMOtc3RpY28gZGUgbGEgcHJ1ZWJhIHNlIGRlZmluZSBjb21vIGxhIHN1bWEgZGUgbGFzIHRyYW5zZm9ybWFjaW9uZXMgYWwgY3VhZHJhZG8gZGUgbGEgYXNpbWV0csOtYSB5IGxhIGN1cnRvc2lzLCB5IHNpZ3VlIGFwcm94aW1hZGFtZW50ZSB1bmEgZGlzdHJpYnVjacOzbiAkXGNoaV4yJC4gDQoNClBvciBvdHJvIGxhZG8sIGxhIHBydWViYSBkZSBSb3lzdG9uIHV0aWxpemEgbGFzICoqcHJ1ZWJhcyBkZSBTaGFwaXJvLVdpbGsgbyBTaGFwaXJvLUZyYW5jaWEqKiBwYXJhIGV2YWx1YXIgbGEgbm9ybWFsaWRhZCBtdWx0aXZhcmlhZGEuIFNpIGxhIGN1cnRvc2lzIGVzIG1heW9yIHF1ZSAzLCBzZSBlbXBsZWEgU2hhcGlyby1GcmFuY2lhIHBhcmEgZGlzdHJpYnVjaW9uZXMgbGVwdG9jw7pydGljYXMsIG1pZW50cmFzIHF1ZSBwYXJhIGRpc3RyaWJ1Y2lvbmVzIHBsYXRpY8O6cnRpY2FzIHNlIHV0aWxpemEgU2hhcGlyby1XaWxrLiBMb3MgcGFyw6FtZXRyb3MgZW4gZXN0YSBwcnVlYmEgc2Ugb2J0aWVuZW4gbWVkaWFudGUgYXByb3hpbWFjaW9uZXMgcG9saW5vbWlhbGVzLg0KDQoNCiMjIyMgUE5NIE1hcmRpYQ0KYGBge3IgUE5NX01hcmRpYSwgZmlnLmFsaWduPSdjZW50ZXInfQ0Kc2V0LnNlZWQoMDUxODAyKQ0KdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfNUsgPSANCnZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMW3NhbXBsZSgxOm5yb3codmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwpLDUwMDApLC1jKDEsMiw0LDUsNildDQoNCm1hcmRpYSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF81SykNCg0KYGBgDQoNCiMjIyMgUE5NIEhlbnplLVppcmtsZXINCmBgYHtyIFBOTV9IZW56ZS1aaXJrbGVyLCBmaWcuYWxpZ249J2NlbnRlcid9DQptaHoodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfNUspDQpgYGANCg0KIyMjIyBQTk0gDQpgYGB7ciBQTk1fRG9vcm5pa19IYW5zZW4sIGZpZy5hbGlnbj0nY2VudGVyJ30NCm1zayh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF81SywgMTApDQpgYGANCg0KIyMjIyBQTk0gDQpgYGB7ciBQTk1fUm95c3RvbiwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQptdm5UZXN0KHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMXzVLLCAxMCkNCmBgYA0KDQojIyMxLjcuIEludGVycHJldGFjacOzbiBub3JtYWxpZGFkIG11bHRpdmFyaWFkYSB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQoNCg0KIyMgKipGYXNlIDIgW0NvbXBvbmVudGVzIFByaW5jaXBhbGVzXSoqDQoNCkVuIGVzdGEgKipzZWd1bmRhIGV0YXBhKiogZGVsIGVzdHVkaW8sIHNlIHByZXNlbnRhcsOhbiBjw6FsY3Vsb3MsIHZpc3VhbGl6YWNpb25lcyBlIGludGVycHJldGFjaW9uZXMgYmFzYWRhcyBlbiBlbCBjb25qdW50byBkZSBkYXRvcyBhbmFsaXphZG8gcHJldmlhbWVudGUgZW4gbGEgW0Zhc2UgMV0oI3NlYzEpLiBBaG9yYSwgZWwgZW5mb3F1ZSBzZSBjZW50cmFyw6EgZW4gZWwgYW7DoWxpc2lzIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIChBQ1ApIGFwbGljYWRvIGEgbGFzIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzLCBpbmNsdXllbmRvIGFzcGVjdG9zIGNvbW8gbGEgc2VsZWNjacOzbiBkZSBjb21wb25lbnRlcywgY2FsaWRhZCBkZSByZXByZXNlbnRhY2nDs24sIGNvbnRyaWJ1Y2lvbmVzIHkgc3UgaW50ZXJwcmV0YWNpw7NuLg0KDQojIyMgMi4xLiBPYmpldGl2b3MNCg0KRWwgKipBQ1AqKiBzZSBsb2dyYSBhIGxvIGxhcmdvIGRlIGxhcyBzaWd1aWVudGVzIGZhc2VzOiBnZW5lcmFjacOzbiBkZSBudWV2YXMgdmFyaWFibGVzLCByZWR1Y2Npw7NuIGRpbWVuc2lvbmFsIGRlbCBlc3BhY2lvIGRlIGxvcyBkYXRvcywgZWxpbWluYWNpw7NuIGRlIHZhcmlhYmxlcyBkZSBwb2NvIGFwb3J0ZSBlIGludGVycHJldGFjacOzbiBkZSBsb3MgY29tcG9uZW50ZXMgcmVzdWx0YW50ZXMgZW4gZWwgY29udGV4dG8gZGVsIHByb2JsZW1hIGRlbCBjdWFsIHNlIG9idHV2aWVyb24gbG9zIGRhdG8uDQoNCkVzdGltYWRvIGxlY3Rvciwgc2kgZGVzZWEgZXhwbG9yYXIgbG9zIGZ1bmRhbWVudG9zIGRlIGVzdGUgYW7DoWxpc2lzIGNvbiBtYXlvciBwcm9mdW5kaWRhZC4gTG9zIGRldGFsbGVzIGRlbCBjb25qdW50byBkZSBkYXRvcyBzZSBlbmN1ZW50cmFuIGRlc2NyaXRvcyBlbiBsYSBbU2VjY2nDs24gMS4yXSgjc2VjMS4yKSwgbWllbnRyYXMgcXVlIGxvcyBwcmluY2lwaW9zIHRlw7NyaWNvcyBxdWUgc3VzdGVudGFuIGVzdGUgZXN0dWRpbyBlc3TDoW4gY3VpZGFkb3NhbWVudGUgZGVzYXJyb2xsYWRvcyBlbiBsYSBkZW5vbWluYWRhIFtGYXNlIDFdKCNzZWMxKS4gVW5hIGxlY3R1cmEgZGV0ZW5pZGEgZGUgZXN0YXMgc2VjY2lvbmVzIGVucmlxdWVjZXLDoSBzdSBjb21wcmVuc2nDs24geSBhcHJlY2lhY2nDs24gZGVsIHRyYWJham8gcHJlc2VudGFkby4NCg0KIyMjIDIuMi4gU2VsZWNjacOzbiBkZSBDb21wb25lbnRlcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFbCBBbsOhbGlzaXMgZGUgQ29tcG9uZW50ZXMgUHJpbmNpcGFsZXMgKiooQUNQKSoqIHBlcm1pdGUgcmVvcmdhbml6YXIgdW4gY29uanVudG8gZGUgZGF0b3MgbXVsdGl2YXJpYWRvIGFsIHJlZHVjaXIgZWwgbsO6bWVybyBkZSB2YXJpYWJsZXMsIHNpbiByZXF1ZXJpciBzdXBvc2ljaW9uZXMgZXNwZWPDrWZpY2FzIHNvYnJlIGxhIGRpc3RyaWJ1Y2nDs24gZGUgcHJvYmFiaWxpZGFkIGRlIGVzdGFzLiBFc3RhIHJlZHVjY2nDs24gc2UgYWxjYW56YSBtZWRpYW50ZSBsYSBjcmVhY2nDs24gZGUgY29tYmluYWNpb25lcyBsaW5lYWxlcyBkZSBsYXMgdmFyaWFibGVzIG9yaWdpbmFsZXMsIGRpc2XDsWFkYXMgcGFyYSBjYXB0YXIgbGEgbWF5b3IgdmFyaWFiaWxpZGFkIHBvc2libGUgZW4gbG9zIGRhdG9zLiBEZSBlc3RlIG1vZG8sIGVsICoqQUNQKiogZ2VuZXJhIG51ZXZhcyB2YXJpYWJsZXMsIGRlbm9taW5hZGFzIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLCBxdWUgcHJlc2VudGFuIGluZGVwZW5kZW5jaWEgZXN0YWTDrXN0aWNhIHkgYXVzZW5jaWEgZGUgY29ycmVsYWNpw7NuLCBzaWVtcHJlIGJham8gZWwgc3VwdWVzdG8gZGUgbm9ybWFsaWRhZC4NCg0KDQojIyMgMi4zLiBDYWxpZGFkIGRlIFJlcHJlc2VudGFjacOzbg0KDQojIyMjIE1hdHJpeiBBQ1ANCmBgYHtyIE1hdHJpel9BQ1AsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZ2V0X2VpZ2VudmFsdWUoUENBKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSwgbmNwID0gNiwgc2NhbGUudW5pdCA9IFRSVUUsIGdyYXBoID0gRikpDQpgYGANCg0KIyMjIyBNYXRyaXogZGUgQ29ycmVsYWNpb25lcw0KYGBge3IgTWF0cml6X2RlX0NvcnJlbGFjaW9uZXN9DQpyb3VuZChjb3IodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNildKSwyKQ0KYGBgDQoNCiMjIyMgVmFsb3JlcyB5IFZlY3RvcmVzIFByb3Bpb3MNCmBgYHtyIFZhbG9yZXNfeV9WZWN0b3Jlc19Qcm9waW9zLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnByaW5jb21wKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSwgY29yID0gVFJVRSkkc2Rldl4yDQpwcmluY29tcCh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIGNvciA9IFRSVUUpJGxvYWRpbmdzWyAsMTo1XQ0KYGBgDQoNCiMjIyMgQ29ycmVsYWNpb25lcyBDb21wYXJhZGFzDQpgYGB7ciBDb3JyZWxhY2lvbmVzX0NvbXBhcmFkYXMsIGZpZy5hbGlnbj0nY2VudGVyJ30NCnBhcihtZnJvdz1jKDEsMikpDQpjb3JycGxvdDo6Y29ycnBsb3QoY29yKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSksIG1ldGhvZCA9ICJjb2xvciIsIHR5cGUgPSAidXBwZXIiLCBudW1iZXIuY2V4ID0gMC40KQ0KY29ycnBsb3Q6OmNvcnJwbG90KGNvcihwcmluY29tcCh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIGNvciA9IFRSVUUpJHNjb3JlcyksIG1ldGhvZCA9ICJjb2xvciIsIHR5cGUgPSAidXBwZXIiLCBudW1iZXIuY2V4ID0gMC40KQ0KYGBgDQoNCiMjIyMgR3LDoWZpY28gZGUgQ2F0dGVsbA0KYGBge3IgR3JhZmljb19kZV9DYXR0ZWxsLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmZ2aXpfZWlnKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIHNjYWxlLnVuaXQgPSBULCBncmFwaCA9IEYpLCBhZGRsYWJlbHMgPSBULCB5bGltPWMoMCw5MCksIG1haW4gPSAiIikNCmBgYA0KDQojIyMjIEdyw6FmaWNvIGRlIENhdHRlbGwtS2Fpc2VyDQpgYGB7ciBHcmFmaWNvX2RlX0NhdHRlbGxfS2Fpc2VyLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnNjcmVlKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSxmYWN0b3JzID0gRkFMU0UsIHBjID0gVFJVRSwgbWFpbiA9IiIpDQpgYGANCg0KDQojIyMgSW50ZXJwcmV0YWNpw7NuIHkgYW7DoWxpc2lzey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KDQojIyMgMi40LiBDb250cmlidWNpb25lcyB5IEJpcGxvdHMgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KQmFzYWRvIGVuIGxhcyB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcyBkZWwgY29uanVudG8gZGUgZGF0b3MgZGVzY3JpdG8gZW4gbGEgW3NlY2Npw7NuIDEuMl0oI3NlYzEuMiksIHNlIHJlcXVpZXJlIGRldGVybWluYXIgbGFzIGNvbnRyaWJ1Y2lvbmVzIGRlIGNhZGEgdmFyaWFibGUgZW4gbGEgY29uc3RydWNjacOzbiBkZSBsYXMgY29tcG9uZW50ZXMuDQoNCkxhIG5hdmVnYWNpw7NuIGEgdHJhdsOpcyBkZSBsYXMgcGVzdGHDsWFzIGZhY2lsaXRhIGxhIHZpc3VhbGl6YWNpw7NuIGRlIGxhcyBjb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGRlbCBjb25qdW50byBkZSBkYXRvcyBlbiBmb3JtYSBkZSByZXByZXNlbnRhY2lvbmVzIG51bcOpcmljYXMgeSBncsOhZmljYXMsIHBlcm1pdGllbmRvIGNvbXByZW5kZXIgY8OzbW8gY2FkYSB2YXJpYWJsZSBpbmZsdXllIGVuIGxhIGNvbnN0cnVjY2nDs24gZGUgbGFzIGNvbXBvbmVudGVzLiBFc3RvIHBlcm1pdGUgYW5hbGl6YXIgbGEgcHJvcG9yY2nDs24gZGUgdmFyaWFiaWxpZGFkIHF1ZSBjYWRhIHZhcmlhYmxlIGFwb3J0YSBhIGxhIHZhcmlhYmlsaWRhZCB0b3RhbCBkZSBsYSBjb21wb25lbnRlIGNvbiBsYSBxdWUgZXN0w6EgYXNvY2lhZGEuDQoNCkxhICoqTWF0cml6IGRlIENvbnRyaWJ1Y2lvbmVzKiogbXVlc3RyYSBjw7NtbyBjYWRhIHZhcmlhYmxlIGNvbnRyaWJ1eWUgYSBsYSByZXRlbmNpw7NuIGRlIHZhcmlhYmlsaWRhZCBlbiBsYSBjb25zdHJ1Y2Npw7NuIGRlIGNhZGEgY29tcG9uZW50ZS4gTG9zIGRpYWdyYW1hcyBkZSBiYXJyYXMsIHF1ZSBzZSB2aXN1YWxpemFuIGVuIGxhcyBwZXN0YcOxYXMgZGVzZGUgKipDb250cmlidWNpb25lcyBhIEQxKiogaGFzdGEgKipDb250cmlidWNpb25lcyBhIEQ1KiosIGlsdXN0cmFuIGxhcyBjb250cmlidWNpb25lcyBlc3BlY8OtZmljYXMgZGUgbGFzIHZhcmlhYmxlcyBwYXJhIGV4cGxpY2FyIGxhIHZhcmlhYmlsaWRhZCBlbiBjYWRhIGNvbXBvbmVudGUuIENhZGEgZ3LDoWZpY28gaW5jbHV5ZSB1bmEgbMOtbmVhIHF1ZSBpbmRpY2EgbGEgKmNvbnRyaWJ1Y2nDs24gbWVkaWEqLCBsbyBxdWUgZmFjaWxpdGEgbGEgaWRlbnRpZmljYWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgcXVlIHRpZW5lbiBtYXlvciBpbXBhY3RvIGVuIGxhIGV4cGxpY2FjacOzbiBkZSBsYSB2YXJpYWJpbGlkYWQgZGUgbG9zIGNvbXBvbmVudGVzLg0KDQpFbiAqKkNvbnRyaWJ1Y2lvbmVzIGEgRDEqKiBzZSB2aXN1YWxpemEgcXVlIGxhcyB2YXJpYWJsZXMgcG9yIGVuY2ltYSBkZSBsYSBjb250cmlidWNpw7NuIG1lZGlhOiAqKmtpbG9tZXRyYWplKiosKiphbnRpZ3VlZGFkX3ZlaGljdWxvKiogeSAqKnByZWNpbyoqICwgbG9zIGNlbnRlIGVsICQ3NiwwNSUkICBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIGNvbXBvbmVudGUgMS4NCg0KRW4gKipDb250cmlidWNpb25lcyBhIEQyKiogc2UgdmlzdWFsaXphIHF1ZSBsYXMgdmFyaWFibGVzIHBvciBlbmNpbWEgZGUgbGEgY29udHJpYnVjacOzbiBtZWRpYTogKipraWxvbWV0cmFqZV9hbnVhbCoqIHF1ZSByZXRpZW5lIGFwcm94aW1hZGFtZW50ZSBlbCAkNzAsOTglJCBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIGNvbXBvbmVudGUgMi4NCg0KRW4gKipDb250cmlidWNpb25lcyBhIEQzKiogc2UgdmlzdWFsaXphIHF1ZSBsYXMgdmFyaWFibGVzIHBvciBlbmNpbWEgZGUgbGEgY29udHJpYnVjacOzbiBtZWRpYTogKipjYW50X3Byb3BpZXRhcmlvcyoqIHkgKipwcmVjaW8qKiBxdWUgcmV0aWVuZW4gYXByb3hpbWFkYW1lbnRlIGVsICQ5Niw2OCUkIGRlIGxhIHZhcmlhYmlsaWRhZCBkZWwgY29tcG9uZW50ZSAzLg0KDQpFbiAqKkNvbnRyaWJ1Y2lvbmVzIGEgRDQqKiBzZSB2aXN1YWxpemEgcXVlIGxhIHZhcmlhYmxlIHBvciBlbmNpbWEgZGUgbGEgY29udHJpYnVjacOzbiBtZWRpYTogKipwcmVjaW8qIHkgKiphbnRpZ3VlZGFkX3ZlaGljdWxvKiogcXVlIHJldGllbmVuIGFwcm94aW1hZGFtZW50ZSBlbCAkNjAsNDMlJCBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIGNvbXBvbmVuZXRlIDQuDQoNCkVuICoqQ29udHJpYnVjaW9uZXMgYSBENSoqIHNlIHZpc3VhbGl6YSBxdWUgbGFzIHZhcmlhYmxlcyBwb3IgZW5jaW1hIGRlIGxhIGNvbnRyaWJ1Y2nDs24gbWVkaWE6ICoqa2lsb21ldHJhamUqKiB5ICoqYW50aWd1ZWRhZF92ZWhpY3VsbyoqIHF1ZSByZXRpZW5lbiBhcHJveGltYWRhbWVudGVlbCAkODQsMSUkIGRlIGxhIHZhcmlhYmlsaWRhZCBkZWwgY29tcG9uZW50ZSA1Lg0KDQpDb24gbG9zIGRhdG9zIHByb2Nlc2Fkb3MgaGFzdGEgYWhvcmEgc2UgcHVlZGUgcHJvY2VkZXIgY29uIGxhIGludGVwcmV0YWNpw7NuIGRlIGxvcyBjb21wb25lbnRlcy4NCg0KDQojIyMgMi41LiBEZXNhcnJvbGxvIGRlbCBhbsOhbGlzaXMNCg0KIyMjIyBDw61yY3VsbyBkZSBDb3JyZWxhY2lvbmVzDQpgYGB7ciBDaXJjdWxvX2RlX0NvcnJlbGFjaW9uZXMsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9wY2FfdmFyKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIHNjYWxlLnVuaXQgPSBULCBncmFwaCA9IEYpLGNvbC52YXI9IiMzQjgzQkQiLCByZXBlbCA9IFQsIGNvbC5jaXJjbGUgPSAiI0NEQ0RDRCIsIGdndGhlbWUgPSB0aGVtZV9idygpKQ0KYGBgDQoNCiMjIyMgTWF0cml6IGRlIFJlcHJlc2VudGFjacOzbg0KYGBge3IgTWF0cml6X2RlX1JlcHJlc3NlbnRhY2lvbl9DT1MyLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCihnZXRfcGNhX3ZhcihQQ0EodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNildLCBuY3AgPSA1LCBzY2FsZS51bml0ID0gVFJVRSwgZ3JhcGggPSBGKSkpJGNvczINCmBgYA0KDQojIyMjIENhbGlkYWQgZGUgUmVwcmVzZW50YWNpw7NuDQpgYGB7ciBDYWxpZGFkX2RlX2xhX1JlcHJlc2VudGFjaW9uLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmZ2aXpfcGNhX3ZhcihQQ0EodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNildLCBuY3AgPSA1LCBzY2FsZS51bml0ID0gVFJVRSwgZ3JhcGggPSBGKSwgY29sLnZhcj0iY29zMiIsIGdyYWRpZW50LmNvbHM9YygiIzAwQUZCQiIsIiNFN0I4MDAiLCIjRkM0RTA3IiksIHJlcGVsID0gVFJVRSkNCmBgYA0KDQojIyMjIENvb3JkZW5hZGFzIEluZGl2aWR1YWxlcw0KYGBge3IgQ29vcmRlbmFkYXNfUmVnaXN0cm9zLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmhlYWQoKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDUsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpKSRpbmQkY29vcmQsIG4gPSAyM0wpDQpgYGANCg0KIyMjIDIuNi4gQ29udHJpYnVjaW9uZXMgey50YWJzZXQgLnRhYnNldC1waWxsc30NCiMjIzIuNy4gUGxhbnRlYW1pZW50byB5IERlc2Fycm9sbG8gey50YWJzZXQgLnRhYnNldC1waWxsc30NCiMjIyMgTWF0cml6IGRlIENvbnRyaWJ1Y2lvbmVzDQpgYGB7ciBNYXRyaXpfZGVfQ29udHJpYnVjaW9uZXMsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KKGdldF9wY2FfdmFyKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDUsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpKSkkY29udHJpYg0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBEMQ0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzEsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDEsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBEMg0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzIsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDIsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBEMw0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzMsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDMsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBENA0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzQsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDQsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBENQ0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzUsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDUsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyAyLjguIEludGVycHJldGFjacOzbiB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KUmVwcmVzZW50YXIgbG9zIHJlZ2lzdHJvcyBlbiB1biBlc3BhY2lvIGRlIGRpbWVuc2lvbmVzIHJlZHVjaWRhcyBwZXJtaXRlIHNpdHVhcmxvcyBlbiB1biBwbGFubyBkZSBmYWN0b3JlcywgbG8gcXVlIGZhY2lsaXRhIHN1IGFuw6FsaXNpcyBlIGludGVycHJldGFjacOzbi4gTGFzIHZhcmlhYmxlcyByZWR1Y2lkYXMgc2UgY29ycmVzcG9uZGVuIGNvbiBsYXMgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMsIHF1ZSBzZSB1dGlsaXphbiBjb21vIGVqZXMgZW4gZWwgcGxhbm8geSBjdXlvcyB2YWxvcmVzIHNvbiBsb3MgcHVudGFqZXMgZGUgbGFzIGNvbXBvbmVudGVzLiBMYSBkaXN0YW5jaWEgZW50cmUgbG9zIHB1bnRvcyByZXByZXNlbnRhZG9zIHBvciBlc3RvcyBwdW50YWplcyBlcyBjbGF2ZSBwYXJhIGlkZW50aWZpY2FyIHNpbWlsaXR1ZGVzIGVudHJlIGxvcyBwZXJmaWxlcyBkZSBsYXMgb2JzZXJ2YWNpb25lcy4gTm8gb2JzdGFudGUsIGxhcyBzaW1pbGl0dWRlcyBwdWVkZW4gYXBhcmVjZXIgc29sbyBlbiBhbGd1bmFzIHZhcmlhYmxlcyB5IG5vIGVuIHRvZGFzLiBBc8OtLCBzZSBidXNjYSBxdWUgbGFzIGRpc3RhbmNpYXMgZW4gZWwgZXNwYWNpbyBkZSBhbHRhIGRpbWVuc2nDs24gc2UgY29uc2VydmVuIGVuIGVsIGVzcGFjaW8gcmVkdWNpZG8sIG1hbnRlbmllbmRvIGxhIGVzdHJ1Y3R1cmEgZGUgbGFzIHJlbGFjaW9uZXMgZW50cmUgbG9zIGRhdG9zLiBTZWfDum4gW0BBRURNRGlhei1Nb3JhbGVzMWVkXS4NCg0KDQojIyMgMi45LiBQbGFudGVhbWllbnRvIHkgRGVzYXJyb2xsbyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQoNCg0KIyMjIyBCaXBsb3QgZGUgVmFyaWFibGVzIHkgUmVnaXN0cm9zIFtmaWx0cm86Q2hlc3RQYWluXQ0KYGBge3IgQmlwbG90X1ZhcmlhYmxlc19SZWdpc3Ryb3NfRmlsdHJvX2NoZXN0cGFpbn0NCg0KDQogICAgICAgICAgICANCmBgYA0KDQoNCiMjIyMgQmlwbG90IGRlIFZhcmlhYmxlcyB5IFJlZ2lzdHJvcyBbZmlsdHJvOkdlbmRlcl0NCmBgYHtyIEJpcGxvdF9kZV9WYXJpYWJsZXNfeV9SZWdpc3Ryb3NfZmlsdHJvX0dlbmRlcn0NCg0KDQpgYGANCg0KDQojIyMjIEJpcGxvdCBkZSBWYXJpYWJsZXMgeSBSZWdpc3Ryb3MgW2ZpbHRybzpOLm9mIE1ham9yIFZlc3NlbHNdDQpgYGB7ciBCaXBsb3RfZGVfVmFyaWFibGVzX3lfUmVnaXN0cm9zX2ZpbHRyb19yZXN0aW5nZWxlY3Ryb30NCg0KYGBgDQoNCiMjIyMgQ29vcmRlbmFkYXMgSW5kaXZpZHVhbGVzIFtDaGVzdFBhaW5dDQpgYGB7ciBjb29yZGVuYWRhc19pbmRpdmlkdWFsZXN9DQpgYGANCg0KPGEgbmFtZT0ic2VjMyI+PC9hPg0KDQojIyAqKkZhc2UgMyBbQ29ycmVzcG9uZGVuY2lhc10qKg0KDQojIyMgMy4xLiBPYmpldGl2b3MNCiMjIyAzLjIuIENvcnJlc3BvbmRlbmNpYXMgU2ltcGxlcw0KIyMjIDMuMy4gQ29ycmVzcG9uZGVuY2lhcyBNw7psdGlwbGVzDQoNCiMjICoqRmFzZSA0IFtDb25nbG9tZXJhZG9zXSoqDQoNCiMjIyA0LjEuIE9iamV0aXZvcw0KIyMjIDQuMi4gQWdydXBhY2nDs24gSmVyw6FycXVpY2ENCiMjIyA0LjMuIEFncnVwYWNpw7NuIE5vLUplcsOhcnF1aWNhDQoNCiMjICoqRmFzZSA1IFtBbsOhbGlzaXMgZGUgUmVncmVzacOzbl0qKg0KDQojIyMgNS4xLiBPYmpldGl2b3MNCiMjIyA1LjIuIFJlZ3Jlc2nDs24gTGluZWFsIFNpbXBsZQ0KIyMjIDUuMy4gUmVncmVzacOzbiBMaW5lYWwgTcO6bHRpcGxlDQojIyMgNS40LiBSZWdyZXNpw7NuIExvZ8Otc3RpY2EgU2ltcGxlDQojIyMgNS41LiBBanVzdGUgZGUgVmFyaWFuemENCg0KIyMgKio2LiBDb25jbHVzaW9uZXMqKg0KDQojIyAqKjcuIEJpYmxpb2dyYWbDrWEqKg==