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]
LS0tDQp0aXRsZTogIioqdGZjX2dkZF8yMDI1XzJncnVwb181KioiDQpzdWJ0aXRsZTogIkVzdHVkaW8gZGUgQW7DoWxpc2lzIE11bHRpdmFyaWFkbyBjb24gYmFzZSBlbiB1biBjb25qdW50byBkZSBkYXRvcyBzb2JyZSByZWdpc3Ryb3MgZGUgdmVoaWN1bG9zIHVzYWRvcyBjb24gZWwgZmluIGRlIHByZWRlY2lyIHN1IHByZWNpbyBzZWfDum4gc3VzIGNvbmRpY2lvbmVzLiINCmF1dGhvcjogIlBvcjogUGFvbGEgQ2FzdHJvIChwYW9sYS5hbmRyZWEuY2FzdHJvQGNvcnJlb3VuaXZhbGxlLmVkdS5jbyksQW5naWUgVsOhc2NvbmV6IFZhbGVuY2lhIChhbmdpZS52YXNjb25lekBjb3JyZW91bml2YWxsZS5lZHUuY28pLE1hcmlhIEpvc2UgQmFuZGVyYXMgUml2YXMgKGJhbmRlcmFzLm1hcmlhQGNvcnJlb3VuaXZhbGxlLmVkdS5jbyksTHVpcyBGZXJuYW5kbyBNb3JhbGVzIFBlbmFnb3MgKGx1aXMubW9yYWxlcy5wZW5hZ29zQGNvcnJlb3VuaXZhbGxlLmVkdS5jbyksR2lybWFuIEFuZHLDqXMgQ3VlcnZvIEFyYW5nbyAoZ2lybWFuLmN1ZXJ2b0Bjb3JyZW91bml2YWxsZS5lZHUuY28pIg0KZGF0ZTogIlRyYWJham8gZWxhYm9yYWRvIGVuIGVsIHBlcmlvZG8gYWNhZMOpbWljbyBjb21wcmVuZGlkbyBlbnRyZSBhZ29zdG8geSBkaWNpZW1icmUgZGVsIGHDsW8gMjAyNSwgY29tbyBhY3RpdmlkYWQgZm9ybWF0aXZhIHkgZXZhbHVhdGl2YSBkZWwgY3Vyc28gR2VzdGnDs24gZGUgRGF0b3MgcGFyYSBpbmdlbmllcsOtYSBJbmR1c3RyaWFsLiINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IGx1bWVuDQpiaWJsaW9ncmFwaHk6IGJpYmxpb2dyYWZpYV9NRS5iaWINCmNzbDogYXBhLmNzbA0KbGluay1jaXRhdGlvbnM6IHllcw0KLS0tDQo8IS0tIENvbmZpZ3VyYWNpw7NuIEdsb2JhbCBkZSBSIC0tPi0tLQ0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoY29ycnBsb3QpDQpsaWJyYXJ5KEdHYWxseSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoYW5kcmV3cykNCmxpYnJhcnkodGNsdGspDQpsaWJyYXJ5KGFwbHBhY2spDQpsaWJyYXJ5KGdyYXBoaWNzKQ0KbGlicmFyeShyZXNoYXBlMikNCmxpYnJhcnkoRmFjdG9NaW5lUikNCmxpYnJhcnkoZmFjdG9leHRyYSkNCmxpYnJhcnkocHN5Y2gpDQpsaWJyYXJ5KEZhY3RvQ2xhc3MpDQpsaWJyYXJ5KGNsdXN0ZXIpDQpsaWJyYXJ5KGRlbmRleHRlbmQpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KbGlicmFyeShOYkNsdXN0KQ0KbGlicmFyeShzdGFyZ2F6ZXIpDQojbGlicmFyeShnZ3BhaXJzKQ0KbGlicmFyeShtdm5vcm1hbFRlc3QpDQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPVRSVUUpDQoNCnZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMIDwtIHJlYWRfZXhjZWwoInZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMLnhsc3giKQ0KDQpgYGANCg0KIyMgKipGYXNlIDEgW0Rlc2NyaXBjaW9uZXMgTXVsdGl2YXJpYW50ZXNdKiogDQoNCiMjIyAxLjEuIE9iamV0aXZvcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFbCBvYmpldGl2byBkZSBlc3RlIHByb3llY3RvIGVzIGFwbGljYXIgdMOpY25pY2FzIGRlIGFuw6FsaXNpcyBtdWx0aXZhcmlhZG8gcGFyYSBnZXN0aW9uYXIgZWwgY29uanVudG8gZGUgZGF0b3MgYXByb2JhZG8sIGNvcnJlc3BvbmRpZW50ZSBhIHJlZ2lzdHJvcyByZWxhY2lvbmFkb3MgY29uIHByZWRpY2Npw7NuIGRlIHByZWNpb3MgZGUgdmVow61jdWxvcyB1c2Fkb3MuIEVsIHByb3DDs3NpdG8gZXMgb3JnYW5pemFyIHkgcHJvY2VzYXIgZWZpY2F6bWVudGUgbGEgaW5mb3JtYWNpw7NuLCBkZXNhcnJvbGxhbmRvIGhhYmlsaWRhZGVzIGVuIGxhIGdlc3Rpw7NuIHkgYW7DoWxpc2lzIGRlIGRhdG9zLiBFc3RlIHRyYWJham8gc2UgZW5tYXJjYSBkZW50cm8gZGVsIGN1cnNvIGRlICoqR2VzdGnDs24gZGUgRGF0b3MqKiwgZGljdGFkbyBwb3IgZWwgUHJvZmVzb3IgR2lhbmNhcmxvIExpYnJlcm9zIExvbmRvw7FvIGVuIGxhIFVuaXZlcnNpZGFkIGRlbCBWYWxsZS4gDQoNCjxhIG5hbWU9InNlYzEuMiI+PC9hPg0KDQojIyMgMS4yLiBEZXNjcmlwY2nDs24gZGUgbG9zIGRhdG9zIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQoNCkVsIGNvbmp1bnRvIGRlIGRhdG9zIGZ1ZSBvYnRlbmlkbyBlbiBzdSB0b3RhbGlkYWQgZGUgICoqS2FnZ2xlKio6IChodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL21ldGF3YXZlL3ZlaGljbGUtcHJpY2UtcHJlZGljdGlvbikgS2FnZ2xlIGVzIHVuYSBwbGF0YWZvcm1hIGVuIGzDrW5lYSBkZSBjaWVuY2lhIGRlIGRhdG9zIHkgYXByZW5kaXphamUgYXV0b23DoXRpY28sIHByb3BpZWRhZCBkZSBHb29nbGUgTExDLiBFc3RhIGZhY2lsaXRhIGxhIHBhcnRpY2lwYWNpw7NuIGVuIGNvbXBldGVuY2lhcyBkb25kZSBsYXMgZW1wcmVzYXMgcHVibGljYW4gY29uanVudG9zIGRlIGRhdG9zIHkgcHJvYmxlbWFzLCBwZXJtaXRpZW5kbyBhIGxvcyB1c3VhcmlvcyBkZXNhcnJvbGxhciBtb2RlbG9zIHByZWRpY3Rpdm9zIHkgY29tcGV0aXIuIExhIHBsYXRhZm9ybWEgdGFtYmnDqW4gb2ZyZWNlIG5vdGVib29rcyBwYXJhIGNvbXBhcnRpciB5IGNvbGFib3JhciBlbiBwcm95ZWN0b3MgdXRpbGl6YW5kbyBQeXRob24geSBSLCBhc8OtIGNvbW8gdW5hIGFtcGxpYSBjb2xlY2Npw7NuIGRlIGNvbmp1bnRvcyBkZSBkYXRvcyBkZSBhY2Nlc28gcMO6YmxpY28uIEFkZW3DoXMsIEthZ2dsZSBMZWFybiwgdW5hIHNlY2Npw7NuIGRlIGxhIHBsYXRhZm9ybWEgZGVkaWNhZGEgYSBsYSBlZHVjYWNpw7NuIHkgZWwgYXByZW5kaXphamUgZW4gY2llbmNpYSBkZSBkYXRvcyB5IGFwcmVuZGl6YWplIGF1dG9tw6F0aWNvIHByb3BvcmNpb25hIHR1dG9yaWFsZXMgeSBjdXJzb3MgaW50ZXJhY3Rpdm9zIGVuIHRlbWFzIGNvbW8gUHl0aG9uLCBTUUwsIHZpc3VhbGl6YWNpw7NuIGRlIGRhdG9zIHkgYXByZW5kaXphamUgYXV0b23DoXRpY28sIGRpcmlnaWRvcyBhIHByaW5jaXBpYW50ZXMgeSB1c3VhcmlvcyBhdmFuemFkb3MuDQoNCkVzdGUgY29uanVudG8gZGUgZGF0b3Mgc2UgcmVsYWNpb25hIGNvbiBkaXZlcnNhcyDDoXJlYXMgZGUgbGEgaW5nZW5pZXLDrWEgaW5kdXN0cmlhbCwgZGViaWRvIGEgcXVlIHN1IGRlc2Fycm9sbG8geSBhbsOhbGlzaXMgaW1wbGljYW4gbGEgYXBsaWNhY2nDs24gZGUgcHJpbmNpcGlvcyBwcm9waW9zIGRlIGxhIGRpc2NpcGxpbmEuIEVuIHByaW1lciBsdWdhciwgc2UgdmluY3VsYSBjb24gbGEgKiplc3RhZMOtc3RpY2EgeSBlbCBhbsOhbGlzaXMgZGUgZGF0b3MoMi5vcGVyYXRpb25zIHJlc2VhcmNoIHkgYW5hbHlzaXMpKiosIGFsIGVtcGxlYXIgbcOpdG9kb3MgZXN0YWTDrXN0aWNvcyBwYXJhIGVzdHVkaWFyIGxhIGluZm9ybWFjacOzbiB5IGdlbmVyYXIgbW9kZWxvcyBwcmVkaWN0aXZvcyBwcmVjaXNvcy4gVGFtYmnDqW4sIHNlIGFzb2NpYSBjb24gbGEgKipnZXN0acOzbiBkZSBsYSBjYWxpZGFkICg1LnF1YWxpdHkgeSByZWxpYWJpbGl0eSBlbmdpbmVlcmluZykqKiwgcG9ycXVlIGdhcmFudGl6YSBxdWUgbG9zIGRhdG9zIHNlYW4gY29oZXJlbnRlcywgY29tcGxldG9zIHkgY29uZmlhYmxlcy4gQXNpbWlzbW8sIGludGVydmllbmUgbGEgKippbnZlc3RpZ2FjacOzbiBkZSBvcGVyYWNpb25lcyAoNy5vcGVyYXRpb25zIGVuZ2luZWVyaW5nIHkgbWFuYWdlbWVudCkqKiwgcXVlIHBlcm1pdGUgb3B0aW1pemFyIGxvcyBhbGdvcml0bW9zIHV0aWxpemFkb3MgcGFyYSBlc3RpbWFyIGxvcyBwcmVjaW9zIGRlIG1hbmVyYSBlZmljaWVudGUuIEVuIGN1YW50byBhbCAqKmFuw6FsaXNpcyBlY29uw7NtaWNvIGRlIGluZ2VuaWVyw61hICgzLmVuZ2luZWVyaW5nIGVjb25vbWljIGFuYWx5c2lzKSoqLCBzZSB2ZSByZWZsZWphZG8gZW4gZWwgYW7DoWxpc2lzIGRlIGxhIHJlbnRhYmlsaWRhZCB5IGxhIGRlcHJlY2lhY2nDs24gZGUgbG9zIHZlaMOtY3Vsb3MgYSBsbyBsYXJnbyBkZWwgdGllbXBvLHRhbWJpw6luLHNlIHZlIHJlcHJlc2VudGFkbyBlbiBlbCBlc3R1ZGlvIGRlbCBraWxvbWV0cmFqZSB5IGxhIGFudGlnw7xlZGFkIGNvbW8gZmFjdG9yZXMgcXVlIGluZmx1eWVuIGVuIGVsIHByZWNpbyBkZSBsb3MgYXV0b23Ds3ZpbGVzLiBBZGljaW9uYWxtZW50ZSwgZWwgZXN0dWRpbyBzZSByZWxhY2lvbmEgY29uIGxhICoqZ2VzdGnDs24gZGUgcHJveWVjdG9zICg5LmVuZ2luZWVyaW5nIG1hbmFnZW1ldCkqKiwgYWwgcmVxdWVyaXIgdW5hIHBsYW5lYWNpw7NuIGVzdHJ1Y3R1cmFkYSBwYXJhIGVsIGRlc2Fycm9sbG8geSBlamVjdWNpw7NuIGRlbCBzY3JpcHQgZ2VuZXJhZG9yIGRlIGxvcyBkYXRvcy4gRGUgaWd1YWwgbWFuZXJhLCBsb3MgKipzaXN0ZW1hcyBkZSBpbmZvcm1hY2nDs24gKDExLmluZm9ybWF0aW9uIGVuZ2luZWVyaW5nKSoqIGRlc2VtcGXDsWFuIHVuIHBhcGVsIGZ1bmRhbWVudGFsIGVuIGVsIGFsbWFjZW5hbWllbnRvLCBvcmdhbml6YWNpw7NuIHkgcHJvY2VzYW1pZW50byBkZSBsb3MgcmVnaXN0cm9zLCBkZSBpZ3VhbCBtYW5lcmEsIHNlIGV2aWRlbmNpYSBlbiBlbCB1c28gZGUgaGVycmFtaWVudGFzIGNvbXB1dGFjaW9uYWxlcyBjb21vIFB5dGhvbiwgcXVlIHBlcm1pdGVuIGNyZWFyIHNvbHVjaW9uZXMgYXV0b21hdGl6YWRhcyB5IGFwbGljYWJsZXMgYWwgZW50b3JubyBpbmR1c3RyaWFsLg0KDQpTZWfDum4gbGEgZGVzY3JpcGNpw7NuIGRlbCBjb25qdW50byBkZSBkYXRvcyBlbGVnaWRvIGVuIGxhIHBsYXRhZm9ybWEga2FnZ2xlLCBlc3RlIGZ1ZSBkaXNlw7FhZG8gY29uIGVsIHByb3DDs3NpdG8gZGUgY3JlYXIgdW5hIGJhc2Ugc8OzbGlkYSBwYXJhIGVsIGVudHJlbmFtaWVudG8gZGUgbW9kZWxvcyBkZSBwcmVkaWNjacOzbiBkZSBwcmVjaW9zIGF1dG9tb3RyaWNlcyBkZSBhbHRhIHByZWNpc2nDs24uIENvbnRpZW5lIHVuIHRvdGFsIGRlIDEuMDAwLjAwMCByZWdpc3Ryb3MgcXVlIHJlcHJlc2VudGFuIHVuYSBhbXBsaWEgdmFyaWVkYWQgZGUgbWFyY2FzLCBtb2RlbG9zIHkgZXNwZWNpZmljYWNpb25lcywgYWJhcmNhbmRvIDI1IGRlIGxhcyBtYXJjYXMgbcOhcyBjb211bmVzIGVuIGVsIG1lcmNhZG8gYXV0b21vdG9yLiBDYWRhIHJlZ2lzdHJvIGZ1ZSBjb25zdHJ1aWRvIGNvbnNpZGVyYW5kbyByZWxhY2lvbmVzIHkgZGlzdHJpYnVjaW9uZXMgcmVhbGlzdGFzIGVudHJlIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGRlbCB2ZWjDrWN1bG8geSBzdSB2YWxvciBjb21lcmNpYWwsIGNvbiBlbCBmaW4gZGUgcmVmbGVqYXIgY29tcG9ydGFtaWVudG9zIG9ic2VydmFibGVzIGVuIGNvbnRleHRvcyByZWFsZXMgZGUgY29tcHJhdmVudGEuIExhIGzDs2dpY2EgaW1wbGVtZW50YWRhIGVuIGxhIGdlbmVyYWNpw7NuIGRlIGxvcyBkYXRvcyBjb250ZW1wbGEgZmFjdG9yZXMgY29tbyBsYSBkZXByZWNpYWNpw7NuLCBlbCBkZXNnYXN0ZSB5IGVsIHByZWNpbyBkZSBtYXJjYS4gRW4gcHJpbWVyIGx1Z2FyLCBsYSBkZXByZWNpYWNpw7NuIHNlIG1vZGVsYSBjb21vIGxhIHByaW5jaXBhbCB2YXJpYWJsZSBxdWUgZGV0ZXJtaW5hIGxhIHJlZHVjY2nDs24gZGVsIHByZWNpbyBjb24gZWwgcGFzbyBkZWwgdGllbXBvLCBzaWd1aWVuZG8gdW5hIGN1cnZhIGRlIGRlY2xpdmUgZGUgdGlwbyBleHBvbmVuY2lhbC4gRW4gc2VndW5kbyBsdWdhciwgZWwgZGVzZ2FzdGUgc2UgYXNvY2lhIGRpcmVjdGFtZW50ZSBjb24gZWwga2lsb21ldHJhamUsIGVsIGN1YWwgc2UgY29ycmVsYWNpb25hIGNvbiBsYSBhbnRpZ8O8ZWRhZCBkZWwgdmVow61jdWxvIHkgZWplcmNlIHVuIGVmZWN0byBuZWdhdGl2byBzb2JyZSBlbCBwcmVjaW8gZmluYWwuIEZpbmFsbWVudGUsIGVsIHByZWNpbyBkZSBsYSBtYXJjYSBhY3TDumEgY29tbyB1bmEgdmFyaWFibGUgZGUgcmVmZXJlbmNpYSBxdWUgcmVmbGVqYSBlbCBwb3NpY2lvbmFtaWVudG8gZGVsIG1lcmNhZG8gZGUgY2FkYSBtYXJjYSBlbiBlbCBtdW5kbyByZWFsLiANCih0aXBvX2RlX3ZhcmlhYmxlOjplc2NhbGFfZGVfbWVkaWNpw7NuW29yZGVuYW1pZW50b10pOg0KDQotICoqa2lsb21ldHJhamUqKiAoY3VhbnRpdGF0aXZhOjpyYXrDs24pOiBSZXByZXNlbnRhIGxhIGRpc3RhbmNpYSB0b3RhbCByZWNvcnJpZGEgcG9yIGVsIHZlaMOtY3VsbyBkZXNkZSBzdSBmYWJyaWNhY2nDs24gaGFzdGEgbGEgZmVjaGEgZGVsIHJlZ2lzdHJvLCBtZWRpZGEgZW4ga2lsw7NtZXRyb3MuIA0KDQotICoqa2lsb21ldHJhamVfcG9yX2HDsW8qKiAoY3VhbnRpdGF0aXZhOjpyYXrDs24pOiBFc3RhIHZhcmlhYmxlIGV4cHJlc2EgZWwgcHJvbWVkaW8gZGUga2lsw7NtZXRyb3MgcmVjb3JyaWRvcyBhbnVhbG1lbnRlIHBvciBlbCB2ZWjDrWN1bG8uIFNlIG9idGllbmUgZGl2aWRpZW5kbyBlbCBraWxvbWV0cmFqZSB0b3RhbCBlbnRyZSBsYSBlZGFkIGRlbCBhdXRvbcOzdmlsLiANCg0KLSAqKm51bWVyb19kZV9wcm9waWV0YXJpb3NfYW50ZXJpb3JlcyoqIChjdWFudGl0YXRpdmE6OnJhesOzbik6IEluZGljYSBjdcOhbnRhcyBwZXJzb25hcyBoYW4gc2lkbyBkdWXDsWFzIGRlbCB2ZWjDrWN1bG8gYW50ZXMgZGVsIHJlZ2lzdHJvIGFjdHVhbC4gDQoNCi0gKiplZGFkX2RlbF92ZWjDrWN1bG8qKiAoY3VhbnRpdGF0aXZhOjpyYXrDs24pOiBDb3JyZXNwb25kZSBhbCBuw7ptZXJvIGRlIGHDsW9zIHRyYW5zY3Vycmlkb3MgZGVzZGUgbGEgZmVjaGEgZGUgZmFicmljYWNpw7NuIGRlbCB2ZWjDrWN1bG8gaGFzdGEgbGEgYWN0dWFsaWRhZC4gDQoNCi0gKipwcmVjaW8qKiAoY3VhbnRpdGF0aXZhOjpyYXrDs24pOiBFeHByZXNhIGVsIHByZWNpbyBhY3R1YWwgZXN0aW1hZG8gZGVsIHZlaMOtY3VsbyBlbiBlbCBtZXJjYWRvIGRlIHVzYWRvcy4NCg0KLSAqKnRyYW5zbWlzaW9uKiogKGN1YWxpdGF0aXZhOjpub21pbmFsKTogRGVzY3JpYmUgZWwgdGlwbyBkZSBzaXN0ZW1hIGRlIGNhbWJpbyBkZSBtYXJjaGFzIGRlbCB2ZWjDrWN1bG8sIGNvZGlmaWNhZG8gY29tbyAxIHBhcmEgdHJhbnNtaXNpw7NuIG1hbnVhbCB5IDAgcGFyYSBhdXRvbcOhdGljYS4gRXN0YSBlcyBsYSB2YXJpYWJsZSBkZSBkZWNpc2nDs24gcXVlIHNlIGlkZW50aWZpY2EgZW4gZXN0ZSBjb25qdW50by4NCg0KLSAqKm1hcmNhX2RlbF92ZWhpY3VsbyoqIChjdWFsaXRhdGl2YTo6bm9taW5hbCk6IElkZW50aWZpY2EgZWwgbm9tYnJlIGRlbCBmYWJyaWNhbnRlIGRlbCBhdXRvbcOzdmlsLiANCg0KLSAqKmHDsW9fZGVfZmFicmljYWNpb24qKiAoY3VhbnRpdGF0aXZhOjpyYXrDs24pOiBJbmRpY2EgZWwgYcOxbyBjYWxlbmRhcmlvIGVuIGVsIHF1ZSBlbCB2ZWjDrWN1bG8gZnVlIHByb2R1Y2lkby4gDQoNCi0gKipjb2xvcl9leHRlcmlvcioqIChjdWFsaXRhdGl2YTo6bm9taW5hbCk6IEhhY2UgcmVmZXJlbmNpYSBhbCBjb2xvciB2aXNpYmxlIGRlIGxhIGNhcnJvY2Vyw61hIGRlbCB2ZWjDrWN1bG8uIA0KDQotICoqdGlwb19kZV9jb21idXN0aWJsZSoqIChjdWFsaXRhdGl2YTo6bm9taW5hbCk6IEVzcGVjaWZpY2EgZWwgdGlwbyBkZSBlbmVyZ8OtYSBxdWUgdXRpbGl6YSBlbCB2ZWjDrWN1bG8gcGFyYSBzdSBmdW5jaW9uYW1pZW50by4gTG9zIHZhbG9yZXMgY29tdW5lcyBpbmNsdXllbiBnYXNvbGluYSwgZGnDqXNlbCwgaMOtYnJpZG8geSBlbMOpY3RyaWNvLiANCg0KDQoNCg0KDQojIyMjIEVzdHJ1Y3R1cmEgZGVsIENvbmp1bnRvIGRlIERhdG9zIEVUTA0KDQpgYGB7ciBFc3RydWN0dXJhX0Nvbmp1bnRvX2RlX0RhdG9zX0RlcHVyYWRvLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnN0cih2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCkNCmBgYA0KDQojIyMjIENvbmp1bnRvIGRlIERhdG9zIE9yaWdpbmFsIERlcHVyYWRvDQoNCmBgYHtyIENvbmp1bnRvX2RlX0RhdG9zX0RlcHVyYWRvLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMDQoNCmBgYA0KDQojIyMgMS4zLiBFc3RpbWFjaW9uZXMgbXVsdGl2YXJpYWRhcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFbCAqKnZlY3RvciBkZSBtZWRpYXMqKiB5IGxhICoqbWF0cml6IGRlIHZhcmlhbnphcy1jb3ZhcmlhbnphcyoqIGNvbmZvcm1hbiB1biBjb25qdW50byBkZSBoZXJyYW1pZW50YXMgZnVuZGFtZW50YWxlcyBwYXJhIGRlc2NyaWJpciBlbCBjb21wb3J0YW1pZW50byBwb3NpY2lvbmFsLCBkaXNwZXJzaXZvIHkgY29ycmVsYWNpb25hbCBkZSBsYXMgdmFyaWFibGVzIGFsZWF0b3JpYXMgZW4gdW4gY29uanVudG8gZGUgZGF0b3MuIEVzdGFzIG1lZGlkYXMgc29uIGVzZW5jaWFsZXMgZW4gZWwgYW7DoWxpc2lzIG11bHRpdmFyaWFkbywgeWEgcXVlIHBlcm1pdGVuIGNhcHR1cmFyIHRhbnRvIGxhIHRlbmRlbmNpYSBjZW50cmFsIGNvbW8gbGFzIGludGVyZGVwZW5kZW5jaWFzIGVudHJlIGxhcyB2YXJpYWJsZXMuDQoNCkVsIHZlY3RvciBkZSBtZWRpYXMgcmVmbGVqYSBlbCB2YWxvciBlc3BlcmFkbyBvIHB1bnRvIG1lZGlvIGRlIGNhZGEgdmFyaWFibGUsIHNpbnRldGl6YW5kbyBsYSBpbmZvcm1hY2nDs24gZGUgdG9kb3MgbG9zIHJlZ2lzdHJvcyBkaXNwb25pYmxlcyBlbiBlbCBjb25qdW50byBkZSBkYXRvcy4gUG9yIHN1IHBhcnRlLCBsYSBtYXRyaXogZGUgdmFyaWFuemFzLWNvdmFyaWFuemFzIGRlc2NyaWJlIGxhIHZhcmlhYmlsaWRhZCB5IGxhcyByZWxhY2lvbmVzIGVudHJlIGxhcyB2YXJpYWJsZXMuIEVuIHN1IGRpYWdvbmFsIHByaW5jaXBhbCwgZXN0aW1hIGxhcyBkaXNwZXJzaW9uZXMgaW5kaXZpZHVhbGVzIGRlIGNhZGEgdmFyaWFibGUgcmVzcGVjdG8gYSBzdSBtZWRpYSwgbWllbnRyYXMgcXVlIGxvcyBlbGVtZW50b3MgcG9yIGVuY2ltYSBvIHBvciBkZWJham8gZGUgZXN0YSBkaWFnb25hbCByZXByZXNlbnRhbiBsYXMgY292YXJpYW56YXMgZW50cmUgcGFyZXMgZGUgdmFyaWFibGVzLCBtb3N0cmFuZG8gbGFzIHJlbGFjaW9uZXMgbGluZWFsZXMgZXhpc3RlbnRlcyBlbnRyZSBlbGxhcy4NCg0KDQoNCiMjIyNWZWN0b3IgZGUgUHJvbWVkaW9zIHkgQm94cGxvdHMgDQoNCmBgYHtyIFZlY3Rvcl9kZV9NZWRpYXNfeV9Cb3hwbG90cywgZmlnLmFsaWduID0gJ2NlbnRlcid9DQphcHBseSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIDIsIG1lYW4pDQp2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF9SZWR1Y2lkbyA9IHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXQ0Kbm9tYnJlc19ib3hwbG90cyA8LSBjKCJraWxvbWV0cmFqZSIsIkNhbnRfcHJvcGlldGFyaW9zIiwiRWRhZF9WZWjDrWN1bG8iLCJLaWxvbWV0cmFqZV9hw7FvIiwiUHJlY2lvIikNCnBhcihtZnJvdyA9IGMoMSwgbmNvbCh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF9SZWR1Y2lkbykpKQ0KaW52aXNpYmxlKGxhcHBseSgxOm5jb2wodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfUmVkdWNpZG8pLCBmdW5jdGlvbihpKSB7DQogIGJveHBsb3QodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfUmVkdWNpZG9bLCBpXSwNCiAgICAgICAgICBtYWluID0gbm9tYnJlc19ib3hwbG90c1tpXSl9KSkNCg0KYGBgDQoNCg0KIyMjI01hdHJpeiBkZSB2YXJpYW56YXMtY292YXJpYW56YXMNCmBgYHtyIE1hdHJpel9kZV92YXJpYW56YXMtY292YXJpYW56YXMsIGZpZy5hbGlnbj0nY2VudGVyJ30NCnJvdW5kKGNvdih2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0pLDIpDQpgYGANCg0KIyMjI01hdHJpeiBkZSBjb3JyZWxhY2lvbmVzDQpgYGB7ciBNYXRyaXpfZGVfY29ycmVsYWNpb25lcywgZmlnLmFsaWduPSdjZW50ZXInfQ0Kcm91bmQoY29yKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSksMykNCmBgYA0KDQojIyMgMS40LiBQbGFudGVhbWllbnRvIHkgRGVzYXJyb2xsbyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpDb24gYmFzZSBlbiBsYSBwZXN0YcOxYSAqKlZlY3RvciBkZSBNZWRpYXMqKiB5ICoqQm94cGxvdHMqKiwgc2UgcHVlZGUgb2JzZXJ2YXIgcXVlIGxhcyB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcyBhbmFsaXphZGFzIG11ZXN0cmFuIHBhdHJvbmVzIGRlIGRpc3RyaWJ1Y2nDs24gcGFydGljdWxhcmVzLg0KDQpMYSB2YXJpYWJsZSAqKmtpbG9tZXRyYWplKiogcHJlc2VudGEgdW5hIGRpc3RyaWJ1Y2nDs24gY29uIGNvbGEgYSBsYSBkZXJlY2hhLCBsbyBxdWUgc3VnaWVyZSBxdWUgbGEgbWF5b3LDrWEgZGUgbG9zIHZlaMOtY3Vsb3MgdGllbmVuIHJlY29ycmlkb3MgbW9kZXJhZG9zLCBwZXJvIGFsZ3Vub3MgcHJlc2VudGFuIGtpbG9tZXRyYWplcyBtdXkgZWxldmFkb3MgcXVlIGV4dGllbmRlbiBsYSBjb2xhIHN1cGVyaW9yLg0KTGEgdmFyaWFibGUgKipDYW50X3Byb3BpZXRhcmlvcyoqIHRpZW5kZSBhIHRvbWFyIHZhbG9yZXMgYmFqb3MgZW4gbGEgbWF5b3LDrWEgZGUgbG9zIGNhc29zLCB5YSBxdWUgbGEgbWF5b3IgcGFydGUgZGUgbG9zIHZlaMOtY3Vsb3Mgc3VlbGVuIHRlbmVyIHBvY29zIHByb3BpZXRhcmlvcyBwcmV2aW9zOyBzaW4gZW1iYXJnbywgdGFtYmnDqW4gcHVlZGVuIGFwYXJlY2VyIHZhbG9yZXMgYXTDrXBpY29zIGFzb2NpYWRvcyBhIGF1dG9tw7N2aWxlcyBjb24gbcO6bHRpcGxlcyB0cmFuc2ZlcmVuY2lhcy4NCg0KTGEgKipFZGFkX1ZlaMOtY3VsbyoqIHB1ZWRlIHByZXNlbnRhciBjaWVydGEgYXNpbWV0csOtYSBoYWNpYSBsYSBkZXJlY2hhLCB5YSBxdWUgcHJlZG9taW5hbiB2ZWjDrWN1bG9zIHJlbGF0aXZhbWVudGUgcmVjaWVudGVzLCBtaWVudHJhcyBxdWUgYWxndW5vcyBtb2RlbG9zIG3DoXMgYW50aWd1b3MgZ2VuZXJhbiBsYSBleHRlbnNpw7NuIGRlIGxhIGNvbGEuDQoNCkVuIGN1YW50byBhIGxhIHZhcmlhYmxlICoqS2lsb21ldHJhamVfYcOxbyoqLCBlc3TDoSBnZW5lcmFsbWVudGUgcHJlc2VudGEgdW5hIGRpc3RyaWJ1Y2nDs24gY29uIGNvbGEgYSBsYSBkZXJlY2hhLCBkYWRvIHF1ZSBsYSBtYXlvcsOtYSBkZSBsb3MgdmVow61jdWxvcyB0aWVuZW4gdW4gdXNvIGFudWFsIG1vZGVyYWRvLCBwZXJvIGFsZ3Vub3MgcmVnaXN0cmFuIHVuIHVzbyBtdXkgaW50ZW5zaXZvIHF1ZSBpbmNyZW1lbnRhIG5vdGFibGVtZW50ZSBsb3MgdmFsb3JlcyBzdXBlcmlvcmVzLg0KDQpGaW5hbG1lbnRlLCBsYSB2YXJpYWJsZSAqKlByZWNpbyoqIHRhbWJpw6luIHB1ZWRlIG1vc3RyYXIgdW5hIGxpZ2VyYSBjb2xhIGhhY2lhIGxhIGRlcmVjaGEsIGluZGljYW5kbyBxdWUgbGEgbWF5b3LDrWEgZGUgbG9zIHZlaMOtY3Vsb3Mgc2UgY29uY2VudHJhbiBlbiByYW5nb3MgZGUgcHJlY2lvcyBtZWRpb3MsIG1pZW50cmFzIHF1ZSB1bm9zIHBvY29zLCBjb24gY2FyYWN0ZXLDrXN0aWNhcyBwYXJ0aWN1bGFyZXMgbyBnYW1hcyBzdXBlcmlvcmVzLCBlbGV2YW4gbGEgY29sYSBzdXBlcmlvciBkZSBsYSBkaXN0cmlidWNpw7NuLg0KDQpDb24gYmFzZSBlbiBsYSAqKm1hdHJpeiBkZSB2YXJpYW56YXMtY292YXJpYW56YXMqKiB5IGxhICoqbWF0cml6IGRlIGNvcnJlbGFjaW9uZXMqKiwgc2UgaWRlbnRpZmljYSBxdWUgbGFzIHJlbGFjaW9uZXMgbGluZWFsZXMgZW50cmUgbGFzIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzIHN1ZWxlbiBzZXIgZGUgYmFqYSBhIG1vZGVyYWRhIGludGVuc2lkYWQuDQoNCkVzIGNvbcO6biBxdWUgdmFyaWFibGVzIGNvbW8gKipraWxvbWV0cmFqZSoqIHkgKipFZGFkX1ZlaMOtY3VsbyoqIHByZXNlbnRlbiB1bmEgY29ycmVsYWNpw7NuIHBvc2l0aXZhLCB5YSBxdWUgbG9zIHZlaMOtY3Vsb3MgbcOhcyBhbnRpZ3VvcyB0aWVuZGVuIGEgaGFiZXIgcmVjb3JyaWRvIG1heW9yZXMgZGlzdGFuY2lhcy4NCg0KUG9yIG90cm8gbGFkbywgdmFyaWFibGVzIGNvbW8gKipQcmVjaW8qKiBwdWVkZW4gbW9zdHJhciBjb3JyZWxhY2lvbmVzIG1vZGVyYWRhcyBvIGTDqWJpbGVzIGNvbiAqKktpbG9tZXRyYWplX2HDsW8qKiBvICoqQ2FudF9wcm9waWV0YXJpb3MqKiwgbG8gcXVlIHN1Z2llcmUgcXVlIHN1IGluZmx1ZW5jaWEgZGlyZWN0YSBubyBlcyBlc3RyaWN0YW1lbnRlIGxpbmVhbC4NCg0KRW4gZ2VuZXJhbCwgbG9zIGNvZWZpY2llbnRlcyBkZSBjb3JyZWxhY2nDs24gY2VyY2Fub3MgYSBjZXJvIGluZGljYW4gcXVlICoqbm8gZXhpc3RlbiByZWxhY2lvbmVzIGxpbmVhbGVzIGZ1ZXJ0ZXMqKiBlbnRyZSBsYXMgdmFyaWFibGVzLCBwb3IgbG8gcXVlIHN1cyBlZmVjdG9zIG11dHVvcyBzb24gbGltaXRhZG9zLiBFc3RvIGFicmUgbGEgcG9zaWJpbGlkYWQgZGUgaW50ZXJhY2Npb25lcyBubyBsaW5lYWxlcyBvIGRlIHF1ZSBjYWRhIHZhcmlhYmxlIGNhcHR1cmUgZGltZW5zaW9uZXMgZGlzdGludGFzIGRlbCBlc3RhZG8sIGhpc3RvcmlhbCB5IHZhbG9yIGRlbCB2ZWjDrWN1bG8uIEVzdG9zIGFzcGVjdG9zIHNlIGV4cGxvcmFuIGNvbiBtYXlvciBkZXRhbGxlIGVuIGxhIFtzZWNjacOzbiAxLjVdKCNzZWMxLjUpIA0KDQojIyMgMS41LiBHcsOhZmljYXMgbXVsdGl2YXJpYWRhcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFbiBnZW5lcmFsLCBsb3MgKipncsOhZmljb3MgbXVsdGl2YXJpYWRvcyoqIGN1bXBsZW4gZG9zIG9iamV0aXZvcyBlc2VuY2lhbGVzOiBwcmltZXJvLCBheXVkYW4gYSBjb21wYXJhciBlbCBjb21wb3J0YW1pZW50byBkZSBwb2JsYWNpb25lcyBkZSBlc3R1ZGlvIGNvbiBiYXNlIGVuIHZhcmlhYmxlcyBjYXRlZ8OzcmljYXMgeSBmYWNpbGl0YW4gbGEgY29tcHJlbnNpw7NuIGRlIGxhIGVzdHJ1Y3R1cmEgZGUgY29ycmVsYWNpw7NuIGVudHJlIHZhcmlhcyB2YXJpYWJsZXMuIEFkZW3DoXMsIHBlcm1pdGVuIGlkZW50aWZpY2FyIHBhdHJvbmVzLCB0ZW5kZW5jaWFzLCB5IHBvc2libGVzIG91dGxpZXJzIGVuIGxvcyBkYXRvcywgc2ltcGxpZmljYW5kbyBsYSBpbnRlcnByZXRhY2nDs24gZGUgcmVsYWNpb25lcyBjb21wbGVqYXMgeSBkZXN0YWNhbmRvIGxhcyBjYXJhY3RlcsOtc3RpY2FzIG3DoXMgc2lnbmlmaWNhdGl2YXMgZGUgbG9zIG1pc21vcyAoQWxkw6FzLCAyMDE3KS4gRW4gZXN0ZSBzZW50aWRvLCBlbCBjb25qdW50byBkZSBkYXRvcyBkZSB0cmFiYWpvIHRlbmRyw6EgYXBveW8gZGVzY3JpcHRpdm8gZ3LDoWZpY28gYSB0cmF2w6lzIGRlIHRyZXMgZGlhZ3JhbWFzOiB1bm8gY29uanVudG8gcXVlIGludGVncmEgZGlzcGVyc2nDs24sIGRpc3RyaWJ1Y2nDs24geSBjb3JyZWxhY2lvbmVzOyBvdHJvIGJhc2FkbyBlbiBsYSByZW5kZXJpemFjacOzbiBkZSBwb2zDrWdvbm9zOyB5LCBwb3Igw7psdGltbywgdW5vIHF1ZSByZWN1cnJlIGEgbGFzIGNhcmFzIGRlIENoZXJub2ZmLg0KDQoNCiMjIyMgRGlhZ3JhbWEgQ29uanVudG8gZGUgRGlzcGVyc2nDs24sIERpc3RyaWJ1Y2nDs24geSBDb3JyZWxhY2lvbmVzIFtTQV0NCmBgYHtyIERpYWdyYW1hX0NEX3ZlaGljbGVfcHJpY2VfcHJlZGljdGlvbiwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQpnZ3BhaXJzKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSkNCmBgYA0KDQoNCiMjIyMgRGlhZ3JhbWEgQ29uanVudG8gZGUgRGlzcGVyc2nDs24sIERpc3RyaWJ1Y2nDs24geSBDb3JyZWxhY2lvbmVzIFtDQV0NCmBgYHtyIERpYWdyYW1hX2Rpc3BlcnNpb25fZ2VuZGVyLCBmaWcuYWxpZ249J2NlbnRlcid9DQp2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCR0cmFuc21pc2lvbiA8LSBmYWN0b3IodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwkdHJhbnNtaXNpb24pDQpsZXZlbHM9IGMgKDAsMSkNCmxhYmVscz0gYyAoICJhdXRvbWF0aWNvIiAsICJtYW51YWwiKQ0KZ2dwYWlycyh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCwgY29sdW1uID0gYygzLDcsOCw5LDEwKSwgYWVzKGNvbG9yID0gdHJhbnNtaXNpb24sIGFscGhhID0gMC41KSwgdXBwZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSB3cmFwKCJjb3IiLCBzaXplID0gMi41KSkpDQoNCmBgYA0KDQoNCiMjIyMgRGlhZ3JhbWEgZGUgRXN0cmVsbGFzDQpgYGB7ciBEaWFncmFtYV9kZV9Fc3RyZWxsYXMsIGZpZy5hbGlnbj0nY2VudGVyJ30NCnNldC5zZWVkKDA1MTgwMikNCnZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvID0gdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbc2FtcGxlKDE6bnJvdyh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTCksMjMpLC1jKDEsMiw0LDUsNildDQpzdGFycyh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2FkbywgbGVuID0gMSwgY2V4ID0gMC40LCBrZXkubG9jID0gYygxMCwgMiksIGRyYXcuc2VnbWVudHMgPSBUUlVFKQ0KYGBgDQoNCiMjIyMgY2FyYXMgZGUgY2hlcm5vZmYNCmBgYHtyIGNhcmFzX2RlX2NoZXJub2ZmLCBmaWcuYWxpZ249J2NlbnRlcid9DQpzZXQuc2VlZCgwNTE4MDIpDQp2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2FkbyA9IHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMIFtzYW1wbGUoMTpucm93KHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMKSwyMyksLWMoMSwyLDQsNSw2KV0NCmZhY2VzKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvKQ0KYGBgDQoNCg0KIyMjIDEuNi4gTm9ybWFsaWRhZCBtdWx0aXZhcmlhZGEgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KRXMgcG9zaWJsZSBhbmFsaXphciBvIGRldGVybWluYXIgbGEgZGlzdHJpYnVjacOzbiBtdWx0aXZhcmlhZGEgZGUgdW4gY29uanVudG8gZGUgZGF0b3MgbWVkaWFudGUgbcOpdG9kb3MgZGVzY3JpcHRpdm9zLCBjb21vIGxvcyBncsOhZmljb3MsIG8gaW5mZXJlbmNpYWxlcywgY29tbyBsYXMgcHJ1ZWJhcyBlc3RhZMOtc3RpY2FzLiBNaWVudHJhcyBxdWUgbG9zIHByb2NlZGltaWVudG9zIGluZmVyZW5jaWFsZXMgcGVybWl0ZW4gb2J0ZW5lciBjb25jbHVzaW9uZXMgbcOhcyBnZW5lcmFsaXphYmxlcywgbG9zIGdyw6FmaWNvcyByZXN1bHRhbiDDunRpbGVzIGNvbW8gc29wb3J0ZSBwYXJhIGxhIGludGVycHJldGFjacOzbiBkZSBsb3MgcmVzdWx0YWRvcy4NCg0KRW4gZXN0ZSBhcGFydGFkbyBzZSBhYm9yZGEgbGEgYXBsaWNhY2nDs24gZGUgcHJvY2VkaW1pZW50b3MgaW5mZXJlbmNpYWxlcyBwYXJhIHZlcmlmaWNhciBzaSBlbCBjb25qdW50byBkZSBkYXRvcyBkZSB0cmFiYWpvLCByZXNwZWN0byBhIHN1cyB2YXJpYWJsZXMgbnVtw6lyaWNhcywgc2lndWUgdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIG11bHRpdmFyaWFkYSAoRE5NKS4gTGFzIHBydWViYXMgZGUgbm9ybWFsaWRhZCBtdWx0aXZhcmlhZGEgKFBOTSkgcXVlIHNlIGFwbGljYXLDoW4gc29uOiBNYXJkaWEsIEhlbnplLVppcmtsZXIsIERvb3JuaWstSGFuc2VuIHkgUm95c3Rvbi4gRXN0YXMgcHJ1ZWJhcyBkZSBub3JtYWxpZGFkIHNlIHJlYWxpemFuIGJham8gdW4gbml2ZWwgZGUgc2lnbmlmaWNhbmNpYSBkZXRlcm1pbmFkbyAkXGFscGhhID0gMC4wNSQgeSBhIGxhcyBoaXDDs3Rlc2lzOiQkSF8wOiBcdGV4dCB7TGFzIHZhcmlhYmxlcyB0aWVuZW4gdW5hIEROTX0kJCAkJEhfMTogXHRleHQge0xhcyB2YXJpYWJsZXMgTk8gdGllbmVuIHVuYSBETk19JCQgDQoNCkxhICoqcHJ1ZWJhIGRlIE1hcmRpYSoqIHNlIGZ1bmRhbWVudGEgZW4gbGFzIGV4dGVuc2lvbmVzIGRlIGFzaW1ldHLDrWEgeSBjdXJ0b3NpcywgZWwgY3VhZHJhZG8gZGUgbGEgZGlzdGFuY2lhIGRlIE1haGFsYW5vYmlzLCBlbCBuw7ptZXJvIGRlIHZhcmlhYmxlcyAkcCQgYSBhbmFsaXphciB5IGVsIG7Dum1lcm8gZGUgcmVnaXN0cm9zICRuJC4gQXNpbWlzbW8sIHNlIGNvbnNpZGVyYSBxdWUgbGEgZXN0YWTDrXN0aWNhIGRlIGxhIHBydWViYSBwYXJhIGxhIGFzaW1ldHLDrWEgc2lndWUgdW5hIGRpc3RyaWJ1Y2nDs24gJFxjaGleMiQsIG1pZW50cmFzIHF1ZSBsYSBlc3RhZMOtc3RpY2EgcGFyYSBsYSBjdXJ0b3NpcyBzZSBkaXN0cmlidXllIGRlIG1hbmVyYSBhcHJveGltYWRhIGRlIGZvcm1hIG5vcm1hbC4gDQoNCkxhICoqcHJ1ZWJhIGRlIEhlbnplLVppcmtsZXIqKiBzZSBiYXNhIGVuIGxhIGRpc3RhbmNpYSBmdW5jaW9uYWwsIHlhIHF1ZSBzaSBlbCBjb25qdW50byBkZSBkYXRvcyBzaWd1ZSB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwgbXVsdGl2YXJpYWRhLCBlbCBlc3RhZMOtc3RpY28gZGUgbGEgcHJ1ZWJhIHNlIGRpc3RyaWJ1eWUgZGUgbWFuZXJhIGFwcm94aW1hZGEgY29tbyB1bmEgbG9nbm9ybWFsLCBjb24gcGFyw6FtZXRyb3MgZGUgbWVkaWEgJFxtdSQgeSB2YXJpYW56YSAkXHNpZ21hXjIkLiANCg0KTGEgKipwcnVlYmEgZGUgRG9vcm5pay1IYW5zZW4qKiBzZSBiYXNhIGVuIGxhIGFzaW1ldHLDrWEgeSBsYSBjdXJ0b3NpcyBkZSB1biBjb25qdW50byBkZSBkYXRvcyBtdWx0aXZhcmlhZG9zLCBsb3MgY3VhbGVzIHNlIHRyYW5zZm9ybWFuIHBhcmEgYXNlZ3VyYXIgbGEgaW5kZXBlbmRlbmNpYS4gU2UgY29uc2lkZXJhIG3DoXMgcG90ZW50ZSBxdWUgbGEgcHJ1ZWJhIGRlIFNoYXBpcm8tV2lsayBlbiBjYXNvcyBtdWx0aXZhcmlhZG9zLiBFbCBlc3RhZMOtc3RpY28gZGUgbGEgcHJ1ZWJhIHNlIGRlZmluZSBjb21vIGxhIHN1bWEgZGUgbGFzIHRyYW5zZm9ybWFjaW9uZXMgYWwgY3VhZHJhZG8gZGUgbGEgYXNpbWV0csOtYSB5IGxhIGN1cnRvc2lzLCB5IHNpZ3VlIGFwcm94aW1hZGFtZW50ZSB1bmEgZGlzdHJpYnVjacOzbiAkXGNoaV4yJC4gDQoNClBvciBvdHJvIGxhZG8sIGxhIHBydWViYSBkZSBSb3lzdG9uIHV0aWxpemEgbGFzICoqcHJ1ZWJhcyBkZSBTaGFwaXJvLVdpbGsgbyBTaGFwaXJvLUZyYW5jaWEqKiBwYXJhIGV2YWx1YXIgbGEgbm9ybWFsaWRhZCBtdWx0aXZhcmlhZGEuIFNpIGxhIGN1cnRvc2lzIGVzIG1heW9yIHF1ZSAzLCBzZSBlbXBsZWEgU2hhcGlyby1GcmFuY2lhIHBhcmEgZGlzdHJpYnVjaW9uZXMgbGVwdG9jw7pydGljYXMsIG1pZW50cmFzIHF1ZSBwYXJhIGRpc3RyaWJ1Y2lvbmVzIHBsYXRpY8O6cnRpY2FzIHNlIHV0aWxpemEgU2hhcGlyby1XaWxrLiBMb3MgcGFyw6FtZXRyb3MgZW4gZXN0YSBwcnVlYmEgc2Ugb2J0aWVuZW4gbWVkaWFudGUgYXByb3hpbWFjaW9uZXMgcG9saW5vbWlhbGVzLg0KDQoNCiMjIyMgUE5NIE1hcmRpYQ0KYGBge3IgUE5NX01hcmRpYSwgZmlnLmFsaWduPSdjZW50ZXInfQ0Kc2V0LnNlZWQoMDUxODAyKQ0KdmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfNUsgPSANCnZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMW3NhbXBsZSgxOm5yb3codmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVEwpLDUwMDApLC1jKDEsMiw0LDUsNildDQoNCm1hcmRpYSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF81SykNCg0KYGBgDQoNCiMjIyMgUE5NIEhlbnplLVppcmtsZXINCmBgYHtyIFBOTV9IZW56ZS1aaXJrbGVyLCBmaWcuYWxpZ249J2NlbnRlcid9DQptaHoodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExfNUspDQpgYGANCg0KIyMjIyBQTk0gDQpgYGB7ciBQTk1fRG9vcm5pa19IYW5zZW4sIGZpZy5hbGlnbj0nY2VudGVyJ30NCm1zayh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTF81SywgMTApDQpgYGANCg0KIyMjIyBQTk0gDQpgYGB7ciBQTk1fUm95c3RvbiwgZmlnLmFsaWduID0gJ2NlbnRlcid9DQptdm5UZXN0KHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMXzVLLCAxMCkNCmBgYA0KDQojIyMxLjcuIEludGVycHJldGFjacOzbiBub3JtYWxpZGFkIG11bHRpdmFyaWFkYSB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQoNCg0KIyMgKipGYXNlIDIgW0NvbXBvbmVudGVzIFByaW5jaXBhbGVzXSoqDQoNCkVuIGVzdGEgKipzZWd1bmRhIGV0YXBhKiogZGVsIGVzdHVkaW8sIHNlIHByZXNlbnRhcsOhbiBjw6FsY3Vsb3MsIHZpc3VhbGl6YWNpb25lcyBlIGludGVycHJldGFjaW9uZXMgYmFzYWRhcyBlbiBlbCBjb25qdW50byBkZSBkYXRvcyBhbmFsaXphZG8gcHJldmlhbWVudGUgZW4gbGEgW0Zhc2UgMV0oI3NlYzEpLiBBaG9yYSwgZWwgZW5mb3F1ZSBzZSBjZW50cmFyw6EgZW4gZWwgYW7DoWxpc2lzIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzIChBQ1ApIGFwbGljYWRvIGEgbGFzIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzLCBpbmNsdXllbmRvIGFzcGVjdG9zIGNvbW8gbGEgc2VsZWNjacOzbiBkZSBjb21wb25lbnRlcywgY2FsaWRhZCBkZSByZXByZXNlbnRhY2nDs24sIGNvbnRyaWJ1Y2lvbmVzIHkgc3UgaW50ZXJwcmV0YWNpw7NuLg0KDQojIyMgMi4xLiBPYmpldGl2b3MNCg0KRWwgKipBQ1AqKiBzZSBsb2dyYSBhIGxvIGxhcmdvIGRlIGxhcyBzaWd1aWVudGVzIGZhc2VzOiBnZW5lcmFjacOzbiBkZSBudWV2YXMgdmFyaWFibGVzLCByZWR1Y2Npw7NuIGRpbWVuc2lvbmFsIGRlbCBlc3BhY2lvIGRlIGxvcyBkYXRvcywgZWxpbWluYWNpw7NuIGRlIHZhcmlhYmxlcyBkZSBwb2NvIGFwb3J0ZSBlIGludGVycHJldGFjacOzbiBkZSBsb3MgY29tcG9uZW50ZXMgcmVzdWx0YW50ZXMgZW4gZWwgY29udGV4dG8gZGVsIHByb2JsZW1hIGRlbCBjdWFsIHNlIG9idHV2aWVyb24gbG9zIGRhdG8uDQoNCkVzdGltYWRvIGxlY3Rvciwgc2kgZGVzZWEgZXhwbG9yYXIgbG9zIGZ1bmRhbWVudG9zIGRlIGVzdGUgYW7DoWxpc2lzIGNvbiBtYXlvciBwcm9mdW5kaWRhZC4gTG9zIGRldGFsbGVzIGRlbCBjb25qdW50byBkZSBkYXRvcyBzZSBlbmN1ZW50cmFuIGRlc2NyaXRvcyBlbiBsYSBbU2VjY2nDs24gMS4yXSgjc2VjMS4yKSwgbWllbnRyYXMgcXVlIGxvcyBwcmluY2lwaW9zIHRlw7NyaWNvcyBxdWUgc3VzdGVudGFuIGVzdGUgZXN0dWRpbyBlc3TDoW4gY3VpZGFkb3NhbWVudGUgZGVzYXJyb2xsYWRvcyBlbiBsYSBkZW5vbWluYWRhIFtGYXNlIDFdKCNzZWMxKS4gVW5hIGxlY3R1cmEgZGV0ZW5pZGEgZGUgZXN0YXMgc2VjY2lvbmVzIGVucmlxdWVjZXLDoSBzdSBjb21wcmVuc2nDs24geSBhcHJlY2lhY2nDs24gZGVsIHRyYWJham8gcHJlc2VudGFkby4NCg0KIyMjIDIuMi4gU2VsZWNjacOzbiBkZSBDb21wb25lbnRlcyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQpFbCBBbsOhbGlzaXMgZGUgQ29tcG9uZW50ZXMgUHJpbmNpcGFsZXMgKiooQUNQKSoqIHBlcm1pdGUgcmVvcmdhbml6YXIgdW4gY29uanVudG8gZGUgZGF0b3MgbXVsdGl2YXJpYWRvIGFsIHJlZHVjaXIgZWwgbsO6bWVybyBkZSB2YXJpYWJsZXMsIHNpbiByZXF1ZXJpciBzdXBvc2ljaW9uZXMgZXNwZWPDrWZpY2FzIHNvYnJlIGxhIGRpc3RyaWJ1Y2nDs24gZGUgcHJvYmFiaWxpZGFkIGRlIGVzdGFzLiBFc3RhIHJlZHVjY2nDs24gc2UgYWxjYW56YSBtZWRpYW50ZSBsYSBjcmVhY2nDs24gZGUgY29tYmluYWNpb25lcyBsaW5lYWxlcyBkZSBsYXMgdmFyaWFibGVzIG9yaWdpbmFsZXMsIGRpc2XDsWFkYXMgcGFyYSBjYXB0YXIgbGEgbWF5b3IgdmFyaWFiaWxpZGFkIHBvc2libGUgZW4gbG9zIGRhdG9zLiBEZSBlc3RlIG1vZG8sIGVsICoqQUNQKiogZ2VuZXJhIG51ZXZhcyB2YXJpYWJsZXMsIGRlbm9taW5hZGFzIGNvbXBvbmVudGVzIHByaW5jaXBhbGVzLCBxdWUgcHJlc2VudGFuIGluZGVwZW5kZW5jaWEgZXN0YWTDrXN0aWNhIHkgYXVzZW5jaWEgZGUgY29ycmVsYWNpw7NuLCBzaWVtcHJlIGJham8gZWwgc3VwdWVzdG8gZGUgbm9ybWFsaWRhZC4NCg0KDQojIyMgMi4zLiBDYWxpZGFkIGRlIFJlcHJlc2VudGFjacOzbg0KDQojIyMjIE1hdHJpeiBBQ1ANCmBgYHtyIE1hdHJpel9BQ1AsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZ2V0X2VpZ2VudmFsdWUoUENBKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSwgbmNwID0gNiwgc2NhbGUudW5pdCA9IFRSVUUsIGdyYXBoID0gRikpDQpgYGANCg0KIyMjIyBNYXRyaXogZGUgQ29ycmVsYWNpb25lcw0KYGBge3IgTWF0cml6X2RlX0NvcnJlbGFjaW9uZXN9DQpyb3VuZChjb3IodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNildKSwyKQ0KYGBgDQoNCiMjIyMgVmFsb3JlcyB5IFZlY3RvcmVzIFByb3Bpb3MNCmBgYHtyIFZhbG9yZXNfeV9WZWN0b3Jlc19Qcm9waW9zLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnByaW5jb21wKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSwgY29yID0gVFJVRSkkc2Rldl4yDQpwcmluY29tcCh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIGNvciA9IFRSVUUpJGxvYWRpbmdzWyAsMTo1XQ0KYGBgDQoNCiMjIyMgQ29ycmVsYWNpb25lcyBDb21wYXJhZGFzDQpgYGB7ciBDb3JyZWxhY2lvbmVzX0NvbXBhcmFkYXMsIGZpZy5hbGlnbj0nY2VudGVyJ30NCnBhcihtZnJvdz1jKDEsMikpDQpjb3JycGxvdDo6Y29ycnBsb3QoY29yKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSksIG1ldGhvZCA9ICJjb2xvciIsIHR5cGUgPSAidXBwZXIiLCBudW1iZXIuY2V4ID0gMC40KQ0KY29ycnBsb3Q6OmNvcnJwbG90KGNvcihwcmluY29tcCh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIGNvciA9IFRSVUUpJHNjb3JlcyksIG1ldGhvZCA9ICJjb2xvciIsIHR5cGUgPSAidXBwZXIiLCBudW1iZXIuY2V4ID0gMC40KQ0KYGBgDQoNCiMjIyMgR3LDoWZpY28gZGUgQ2F0dGVsbA0KYGBge3IgR3JhZmljb19kZV9DYXR0ZWxsLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmZ2aXpfZWlnKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIHNjYWxlLnVuaXQgPSBULCBncmFwaCA9IEYpLCBhZGRsYWJlbHMgPSBULCB5bGltPWMoMCw5MCksIG1haW4gPSAiIikNCmBgYA0KDQojIyMjIEdyw6FmaWNvIGRlIENhdHRlbGwtS2Fpc2VyDQpgYGB7ciBHcmFmaWNvX2RlX0NhdHRlbGxfS2Fpc2VyLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCnNjcmVlKHZlaGljbGVfcHJpY2VfcHJlZGljdGlvbl9tb2RpZmljYWRvX01VRVNUUkVBRE8yMEtfRVRMWywtYygxLDIsNCw1LDYpXSxmYWN0b3JzID0gRkFMU0UsIHBjID0gVFJVRSwgbWFpbiA9IiIpDQpgYGANCg0KDQojIyMgSW50ZXJwcmV0YWNpw7NuIHkgYW7DoWxpc2lzey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KDQojIyMgMi40LiBDb250cmlidWNpb25lcyB5IEJpcGxvdHMgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KQmFzYWRvIGVuIGxhcyB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcyBkZWwgY29uanVudG8gZGUgZGF0b3MgZGVzY3JpdG8gZW4gbGEgW3NlY2Npw7NuIDEuMl0oI3NlYzEuMiksIHNlIHJlcXVpZXJlIGRldGVybWluYXIgbGFzIGNvbnRyaWJ1Y2lvbmVzIGRlIGNhZGEgdmFyaWFibGUgZW4gbGEgY29uc3RydWNjacOzbiBkZSBsYXMgY29tcG9uZW50ZXMuDQoNCkxhIG5hdmVnYWNpw7NuIGEgdHJhdsOpcyBkZSBsYXMgcGVzdGHDsWFzIGZhY2lsaXRhIGxhIHZpc3VhbGl6YWNpw7NuIGRlIGxhcyBjb250cmlidWNpb25lcyBkZSBsYXMgdmFyaWFibGVzIGRlbCBjb25qdW50byBkZSBkYXRvcyBlbiBmb3JtYSBkZSByZXByZXNlbnRhY2lvbmVzIG51bcOpcmljYXMgeSBncsOhZmljYXMsIHBlcm1pdGllbmRvIGNvbXByZW5kZXIgY8OzbW8gY2FkYSB2YXJpYWJsZSBpbmZsdXllIGVuIGxhIGNvbnN0cnVjY2nDs24gZGUgbGFzIGNvbXBvbmVudGVzLiBFc3RvIHBlcm1pdGUgYW5hbGl6YXIgbGEgcHJvcG9yY2nDs24gZGUgdmFyaWFiaWxpZGFkIHF1ZSBjYWRhIHZhcmlhYmxlIGFwb3J0YSBhIGxhIHZhcmlhYmlsaWRhZCB0b3RhbCBkZSBsYSBjb21wb25lbnRlIGNvbiBsYSBxdWUgZXN0w6EgYXNvY2lhZGEuDQoNCkxhICoqTWF0cml6IGRlIENvbnRyaWJ1Y2lvbmVzKiogbXVlc3RyYSBjw7NtbyBjYWRhIHZhcmlhYmxlIGNvbnRyaWJ1eWUgYSBsYSByZXRlbmNpw7NuIGRlIHZhcmlhYmlsaWRhZCBlbiBsYSBjb25zdHJ1Y2Npw7NuIGRlIGNhZGEgY29tcG9uZW50ZS4gTG9zIGRpYWdyYW1hcyBkZSBiYXJyYXMsIHF1ZSBzZSB2aXN1YWxpemFuIGVuIGxhcyBwZXN0YcOxYXMgZGVzZGUgKipDb250cmlidWNpb25lcyBhIEQxKiogaGFzdGEgKipDb250cmlidWNpb25lcyBhIEQ1KiosIGlsdXN0cmFuIGxhcyBjb250cmlidWNpb25lcyBlc3BlY8OtZmljYXMgZGUgbGFzIHZhcmlhYmxlcyBwYXJhIGV4cGxpY2FyIGxhIHZhcmlhYmlsaWRhZCBlbiBjYWRhIGNvbXBvbmVudGUuIENhZGEgZ3LDoWZpY28gaW5jbHV5ZSB1bmEgbMOtbmVhIHF1ZSBpbmRpY2EgbGEgKmNvbnRyaWJ1Y2nDs24gbWVkaWEqLCBsbyBxdWUgZmFjaWxpdGEgbGEgaWRlbnRpZmljYWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMgcXVlIHRpZW5lbiBtYXlvciBpbXBhY3RvIGVuIGxhIGV4cGxpY2FjacOzbiBkZSBsYSB2YXJpYWJpbGlkYWQgZGUgbG9zIGNvbXBvbmVudGVzLg0KDQpFbiAqKkNvbnRyaWJ1Y2lvbmVzIGEgRDEqKiBzZSB2aXN1YWxpemEgcXVlIGxhcyB2YXJpYWJsZXMgcG9yIGVuY2ltYSBkZSBsYSBjb250cmlidWNpw7NuIG1lZGlhOiAqKmtpbG9tZXRyYWplKiosKiphbnRpZ3VlZGFkX3ZlaGljdWxvKiogeSAqKnByZWNpbyoqICwgbG9zIGNlbnRlIGVsICQ3NiwwNSUkICBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIGNvbXBvbmVudGUgMS4NCg0KRW4gKipDb250cmlidWNpb25lcyBhIEQyKiogc2UgdmlzdWFsaXphIHF1ZSBsYXMgdmFyaWFibGVzIHBvciBlbmNpbWEgZGUgbGEgY29udHJpYnVjacOzbiBtZWRpYTogKipraWxvbWV0cmFqZV9hbnVhbCoqIHF1ZSByZXRpZW5lIGFwcm94aW1hZGFtZW50ZSBlbCAkNzAsOTglJCBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIGNvbXBvbmVudGUgMi4NCg0KRW4gKipDb250cmlidWNpb25lcyBhIEQzKiogc2UgdmlzdWFsaXphIHF1ZSBsYXMgdmFyaWFibGVzIHBvciBlbmNpbWEgZGUgbGEgY29udHJpYnVjacOzbiBtZWRpYTogKipjYW50X3Byb3BpZXRhcmlvcyoqIHkgKipwcmVjaW8qKiBxdWUgcmV0aWVuZW4gYXByb3hpbWFkYW1lbnRlIGVsICQ5Niw2OCUkIGRlIGxhIHZhcmlhYmlsaWRhZCBkZWwgY29tcG9uZW50ZSAzLg0KDQpFbiAqKkNvbnRyaWJ1Y2lvbmVzIGEgRDQqKiBzZSB2aXN1YWxpemEgcXVlIGxhIHZhcmlhYmxlIHBvciBlbmNpbWEgZGUgbGEgY29udHJpYnVjacOzbiBtZWRpYTogKipwcmVjaW8qIHkgKiphbnRpZ3VlZGFkX3ZlaGljdWxvKiogcXVlIHJldGllbmVuIGFwcm94aW1hZGFtZW50ZSBlbCAkNjAsNDMlJCBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIGNvbXBvbmVuZXRlIDQuDQoNCkVuICoqQ29udHJpYnVjaW9uZXMgYSBENSoqIHNlIHZpc3VhbGl6YSBxdWUgbGFzIHZhcmlhYmxlcyBwb3IgZW5jaW1hIGRlIGxhIGNvbnRyaWJ1Y2nDs24gbWVkaWE6ICoqa2lsb21ldHJhamUqKiB5ICoqYW50aWd1ZWRhZF92ZWhpY3VsbyoqIHF1ZSByZXRpZW5lbiBhcHJveGltYWRhbWVudGVlbCAkODQsMSUkIGRlIGxhIHZhcmlhYmlsaWRhZCBkZWwgY29tcG9uZW50ZSA1Lg0KDQpDb24gbG9zIGRhdG9zIHByb2Nlc2Fkb3MgaGFzdGEgYWhvcmEgc2UgcHVlZGUgcHJvY2VkZXIgY29uIGxhIGludGVwcmV0YWNpw7NuIGRlIGxvcyBjb21wb25lbnRlcy4NCg0KDQojIyMgMi41LiBEZXNhcnJvbGxvIGRlbCBhbsOhbGlzaXMNCg0KIyMjIyBDw61yY3VsbyBkZSBDb3JyZWxhY2lvbmVzDQpgYGB7ciBDaXJjdWxvX2RlX0NvcnJlbGFjaW9uZXMsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9wY2FfdmFyKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIHNjYWxlLnVuaXQgPSBULCBncmFwaCA9IEYpLGNvbC52YXI9IiMzQjgzQkQiLCByZXBlbCA9IFQsIGNvbC5jaXJjbGUgPSAiI0NEQ0RDRCIsIGdndGhlbWUgPSB0aGVtZV9idygpKQ0KYGBgDQoNCiMjIyMgTWF0cml6IGRlIFJlcHJlc2VudGFjacOzbg0KYGBge3IgTWF0cml6X2RlX1JlcHJlc3NlbnRhY2lvbl9DT1MyLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCihnZXRfcGNhX3ZhcihQQ0EodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNildLCBuY3AgPSA1LCBzY2FsZS51bml0ID0gVFJVRSwgZ3JhcGggPSBGKSkpJGNvczINCmBgYA0KDQojIyMjIENhbGlkYWQgZGUgUmVwcmVzZW50YWNpw7NuDQpgYGB7ciBDYWxpZGFkX2RlX2xhX1JlcHJlc2VudGFjaW9uLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmZ2aXpfcGNhX3ZhcihQQ0EodmVoaWNsZV9wcmljZV9wcmVkaWN0aW9uX21vZGlmaWNhZG9fTVVFU1RSRUFETzIwS19FVExbLC1jKDEsMiw0LDUsNildLCBuY3AgPSA1LCBzY2FsZS51bml0ID0gVFJVRSwgZ3JhcGggPSBGKSwgY29sLnZhcj0iY29zMiIsIGdyYWRpZW50LmNvbHM9YygiIzAwQUZCQiIsIiNFN0I4MDAiLCIjRkM0RTA3IiksIHJlcGVsID0gVFJVRSkNCmBgYA0KDQojIyMjIENvb3JkZW5hZGFzIEluZGl2aWR1YWxlcw0KYGBge3IgQ29vcmRlbmFkYXNfUmVnaXN0cm9zLCBmaWcuYWxpZ24gPSAnY2VudGVyJ30NCmhlYWQoKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDUsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpKSRpbmQkY29vcmQsIG4gPSAyM0wpDQpgYGANCg0KIyMjIDIuNi4gQ29udHJpYnVjaW9uZXMgey50YWJzZXQgLnRhYnNldC1waWxsc30NCiMjIzIuNy4gUGxhbnRlYW1pZW50byB5IERlc2Fycm9sbG8gey50YWJzZXQgLnRhYnNldC1waWxsc30NCiMjIyMgTWF0cml6IGRlIENvbnRyaWJ1Y2lvbmVzDQpgYGB7ciBNYXRyaXpfZGVfQ29udHJpYnVjaW9uZXMsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KKGdldF9wY2FfdmFyKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDUsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpKSkkY29udHJpYg0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBEMQ0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzEsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDEsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBEMg0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzIsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDIsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBEMw0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzMsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDMsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBENA0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzQsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDQsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyMgQ29udHJpYnVjaW9uZXMgYSBENQ0KYGBge3IgQ29udHJpYnVjaW9uZXNfRElNXzUsIGZpZy5hbGlnbiA9ICdjZW50ZXInfQ0KZnZpel9jb250cmliKFBDQSh2ZWhpY2xlX3ByaWNlX3ByZWRpY3Rpb25fbW9kaWZpY2Fkb19NVUVTVFJFQURPMjBLX0VUTFssLWMoMSwyLDQsNSw2KV0sIG5jcCA9IDYsIHNjYWxlLnVuaXQgPSBUUlVFLCBncmFwaCA9IEYpLCBjaG9pY2UgPSAidmFyIiwgYXhlcyA9IDUsIHRvcCA9IDEwKQ0KYGBgDQoNCiMjIyAyLjguIEludGVycHJldGFjacOzbiB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KUmVwcmVzZW50YXIgbG9zIHJlZ2lzdHJvcyBlbiB1biBlc3BhY2lvIGRlIGRpbWVuc2lvbmVzIHJlZHVjaWRhcyBwZXJtaXRlIHNpdHVhcmxvcyBlbiB1biBwbGFubyBkZSBmYWN0b3JlcywgbG8gcXVlIGZhY2lsaXRhIHN1IGFuw6FsaXNpcyBlIGludGVycHJldGFjacOzbi4gTGFzIHZhcmlhYmxlcyByZWR1Y2lkYXMgc2UgY29ycmVzcG9uZGVuIGNvbiBsYXMgY29tcG9uZW50ZXMgcHJpbmNpcGFsZXMsIHF1ZSBzZSB1dGlsaXphbiBjb21vIGVqZXMgZW4gZWwgcGxhbm8geSBjdXlvcyB2YWxvcmVzIHNvbiBsb3MgcHVudGFqZXMgZGUgbGFzIGNvbXBvbmVudGVzLiBMYSBkaXN0YW5jaWEgZW50cmUgbG9zIHB1bnRvcyByZXByZXNlbnRhZG9zIHBvciBlc3RvcyBwdW50YWplcyBlcyBjbGF2ZSBwYXJhIGlkZW50aWZpY2FyIHNpbWlsaXR1ZGVzIGVudHJlIGxvcyBwZXJmaWxlcyBkZSBsYXMgb2JzZXJ2YWNpb25lcy4gTm8gb2JzdGFudGUsIGxhcyBzaW1pbGl0dWRlcyBwdWVkZW4gYXBhcmVjZXIgc29sbyBlbiBhbGd1bmFzIHZhcmlhYmxlcyB5IG5vIGVuIHRvZGFzLiBBc8OtLCBzZSBidXNjYSBxdWUgbGFzIGRpc3RhbmNpYXMgZW4gZWwgZXNwYWNpbyBkZSBhbHRhIGRpbWVuc2nDs24gc2UgY29uc2VydmVuIGVuIGVsIGVzcGFjaW8gcmVkdWNpZG8sIG1hbnRlbmllbmRvIGxhIGVzdHJ1Y3R1cmEgZGUgbGFzIHJlbGFjaW9uZXMgZW50cmUgbG9zIGRhdG9zLiBTZWfDum4gW0BBRURNRGlhei1Nb3JhbGVzMWVkXS4NCg0KDQojIyMgMi45LiBQbGFudGVhbWllbnRvIHkgRGVzYXJyb2xsbyB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQoNCg0KIyMjIyBCaXBsb3QgZGUgVmFyaWFibGVzIHkgUmVnaXN0cm9zIFtmaWx0cm86Q2hlc3RQYWluXQ0KYGBge3IgQmlwbG90X1ZhcmlhYmxlc19SZWdpc3Ryb3NfRmlsdHJvX2NoZXN0cGFpbn0NCg0KDQogICAgICAgICAgICANCmBgYA0KDQoNCiMjIyMgQmlwbG90IGRlIFZhcmlhYmxlcyB5IFJlZ2lzdHJvcyBbZmlsdHJvOkdlbmRlcl0NCmBgYHtyIEJpcGxvdF9kZV9WYXJpYWJsZXNfeV9SZWdpc3Ryb3NfZmlsdHJvX0dlbmRlcn0NCg0KDQpgYGANCg0KDQojIyMjIEJpcGxvdCBkZSBWYXJpYWJsZXMgeSBSZWdpc3Ryb3MgW2ZpbHRybzpOLm9mIE1ham9yIFZlc3NlbHNdDQpgYGB7ciBCaXBsb3RfZGVfVmFyaWFibGVzX3lfUmVnaXN0cm9zX2ZpbHRyb19yZXN0aW5nZWxlY3Ryb30NCg0KYGBgDQoNCiMjIyMgQ29vcmRlbmFkYXMgSW5kaXZpZHVhbGVzIFtDaGVzdFBhaW5dDQpgYGB7ciBjb29yZGVuYWRhc19pbmRpdmlkdWFsZXN9DQpgYGANCg0KPGEgbmFtZT0ic2VjMyI+PC9hPg0KDQojIyAqKkZhc2UgMyBbQ29ycmVzcG9uZGVuY2lhc10qKg0KDQojIyMgMy4xLiBPYmpldGl2b3MNCiMjIyAzLjIuIENvcnJlc3BvbmRlbmNpYXMgU2ltcGxlcw0KIyMjIDMuMy4gQ29ycmVzcG9uZGVuY2lhcyBNw7psdGlwbGVzDQoNCiMjICoqRmFzZSA0IFtDb25nbG9tZXJhZG9zXSoqDQoNCiMjIyA0LjEuIE9iamV0aXZvcw0KIyMjIDQuMi4gQWdydXBhY2nDs24gSmVyw6FycXVpY2ENCiMjIyA0LjMuIEFncnVwYWNpw7NuIE5vLUplcsOhcnF1aWNhDQoNCiMjICoqRmFzZSA1IFtBbsOhbGlzaXMgZGUgUmVncmVzacOzbl0qKg0KDQojIyMgNS4xLiBPYmpldGl2b3MNCiMjIyA1LjIuIFJlZ3Jlc2nDs24gTGluZWFsIFNpbXBsZQ0KIyMjIDUuMy4gUmVncmVzacOzbiBMaW5lYWwgTcO6bHRpcGxlDQojIyMgNS40LiBSZWdyZXNpw7NuIExvZ8Otc3RpY2EgU2ltcGxlDQojIyMgNS41LiBBanVzdGUgZGUgVmFyaWFuemENCg0KIyMgKio2LiBDb25jbHVzaW9uZXMqKg0KDQojIyAqKjcuIEJpYmxpb2dyYWbDrWEqKg==