1. Introducción
La diabetes es una enfermedad crónica que representa una de las
principales causas de defunción a nivel mundial. Según la Organización
Mundial de la Salud, esta enfermedad afecta a más de 830 millones de
personas en el mundo, en su gran mayoría ubicadas en los países de
ingreso mediano bajo. Por eso, es importante realizar una detección
temprana para intervenir de forma rápida y reducir sus posibles
complicaciones. Por esta razón, los diagnósticos se pueden identificar
con modelos estadísticos y algoritmos de aprendizaje automático,
permitiendo decisiones más precisas.
Para este estudio se escogió la base de datos de diabetes de los
indios Pima, información recopilada del Instituto Nacional de
Diabetes y Enfermedades Digestivas y Renales. Contiene un registro de
algunas restricciones para la selección, donde las pacientes incluidas
en ese diagnóstico son mujeres de al menos 21 años de edad y de
ascendencia indígena Pima; cuenta con mediciones de glucosa, presión
arterial, índice de masa corporal, entre otras. Su fácil acceso público
ha sido de gran referencia para investigaciones y para analizar patrones
que contribuyen en identificar herramientas más precisas para el
diagnóstico y la clasificación de la diabetes.
El siguiente estudio tiene como objetivo desarrollar y comparar
modelos de clasificación supervisada, con el fin de aportar
evidencia técnica para identificar si un paciente presenta o no diabetes
a partir de información contenida en la base de datos. El problema
corresponde a una clasificación binaria, donde la
variable dependiente toma dos posibles respuestas. Para ello, se
utilizan cinco variables independientes para realizar la clasificación
de la variable dependiente. Se realiza la comparación entre
KNN y la Regresión Logística (Logit),
con el objetivo de identificar el modelo que presenta la mejor capacidad
de predicción de pacientes con diabetes, evaluando rendimiento mediante
métricas de clasificación estándares como exactitud, especificidad,
sensibilidad y la curva ROC.
2. Metodología
El estudio se desarrolló bajo un enfoque del aprendizaje supervisado
orientado hacia la clasificación binaria de pacientes pertenecientes a
la base de datos Pima Indians Diabetes Database, con el objetivo de
predecir la presencia o ausencia de diabetes. Para eso, se implementó la
comparación de dos modelos de clasificación: K Vecinos más Próximos
(KNN) y Regresión Logística (Logit). La metodología
evidencia las diferentes etapas relacionadas con la selección de las
variables, comparabilidad de los resultados, partición de datos y
validez.
2.1 Preparación de la base de datos
De acuerdo con la información, se realizó un proceso de selección
para escoger las variables que más se ajusten para el análisis
predictivo, de las cuales se preservaron (Glucose, BMI, Age,
BloodPressure y DiabetesPedigreeFunction) como variables
explicativas, incluido el Outcome como variable categórica.
Se excluyeron valores faltantes en las variables escogidas, para
poder trabajar con las necesarias para el análisis. De esa forma, se
organizaron los datos de manera eficiente en las etapas posteriores de
análisis descriptivo, entrenamiento y evaluación de modelos. Se verificó
que la base no presentara valores faltantes, confirmando que las 768
observaciones estaban completas para el análisis.
Adicionalmente, las variables numéricas fueron estandarizadas
mediante la función scale() para garantizar que todas
tuvieran la misma escala, evitando que el modelo KNN favorezca las
variables con valores más grandes.
# Librerías necesarias
library(readxl)
library(tidyverse)
library(readr)
library(kableExtra)
library(ggplot2)
library(tidyr)
library(class)
library(caret)
library(ROCR)
library(pROC)
# Carga de datos
diabetes <- read_csv("diabetes.csv")
# Selección de variables relevantes
diabetes_nueva <- diabetes %>%
select(Glucose, BMI, Age, BloodPressure, DiabetesPedigreeFunction, Outcome)
# Limpieza: eliminar filas con NA en cualquier variable de interés
base_limpia <- diabetes_nueva %>%
filter(
!is.na(Glucose), !is.na(BMI), !is.na(Age),
!is.na(BloodPressure), !is.na(DiabetesPedigreeFunction), !is.na(Outcome)
)
# Partición unificada 70/30 estratificada (misma para KNN y Logit)
set.seed(28)
indices_entrenamiento <- createDataPartition(
y = base_limpia$Outcome,
p = 0.7,
list = FALSE
)
train_original <- base_limpia[indices_entrenamiento, ]
test_original <- base_limpia[-indices_entrenamiento, ]
cat("Total de observaciones:", nrow(base_limpia), "\n")
## Total de observaciones: 768
cat("Entrenamiento (70%):", nrow(train_original), "\n")
## Entrenamiento (70%): 538
cat("Prueba (30%): ", nrow(test_original), "\n")
## Prueba (30%): 230
2.2 Partición de datos
Se utilizó una partición 70% entrenamiento / 30%
prueba aplicada sobre la base completa limpia de 768
observaciones, mediante createDataPartition() del paquete
caret. Esta función garantiza que la proporción de
pacientes con y sin diabetes se mantenga igual en ambos conjuntos
(partición estratificada), lo que evita que el modelo entrene con una
distribución distinta a la que va a predecir. La misma partición fue
utilizada para ambos modelos (KNN y Logit), asegurando que las métricas
sean comparables sobre exactamente el mismo conjunto de prueba.
2.3 Definición de variables
2.3.1 Variable de clasificación
La variable dependiente corresponde a Outcome, codificada de
forma binaria con dos niveles: “Sí” para los pacientes
positivos en diabetes y “No” para las pacientes sin
diagnóstico. Al ser de solo dos posibles respuestas, corresponde a una
clasificación binaria supervisada, cuyo objetivo central es que los
modelos diferencien entre ambos grupos a partir de las características
clínicas de cada paciente.
2.3.2 Variables independientes
Se seleccionaron 5 de las 8 variables disponibles en la base de
datos. Esta selección se inspiró en investigaciones previas que
determinaron que la glucosa, la edad y el índice de masa corporal son
variables clave (Joshi & Dhakal, 2021).
| Glucose |
Indicador principal de diagnóstico; niveles elevados están
directamente asociados con la respuesta a la insulina y la diabetes
(Joshi & Dhakal, 2021) |
| BMI |
El sobrepeso dificulta la captación de glucosa celular, aumentando
el riesgo de diabetes (Lagunes Torres, 2023) |
| Age |
A mayor edad, mayores cambios metabólicos y menor sensibilidad a la
insulina (CDC, 2024) |
| BloodPressure |
La hipertensión y la diabetes coexisten frecuentemente; la
resistencia a la insulina puede causar hipertensión (Sampanis &
Zamboulis, 2008) |
| DiabetesPedigreeFunction |
Los antecedentes familiares aumentan hasta 3 veces el riesgo de
diabetes. Si ambos progenitores la padecen, la probabilidad asciende al
70% (OMS, citado en Revista Diabetes, 2024) |
2.4.1 Modelo KNN
El modelo KNN es una técnica de aprendizaje supervisado no
paramétrica utilizada para clasificación, que funciona identificando los
“K” casos más similares a una nueva observación dentro del conjunto de
entrenamiento y asignando la categoría predominante entre esos vecinos.
En este estudio, se utilizó para predecir la presencia de diabetes a
partir de las cinco variables seleccionadas.
Para determinar la similitud entre pacientes, el modelo usó medidas
de distancia considerando las variables predictoras. Luego, se evaluaron
distintos valores de K con el fin de seleccionar la configuración que
ofreciera el mejor desempeño predictivo, buscando un equilibrio entre
sensibilidad y estabilidad. KNN representa un enfoque flexible, ya que
no asume relaciones lineales entre variables.
2.4.2 Modelo de Regresión Logística (Logit)
La regresión logística es un modelo de aprendizaje supervisado
utilizado para problemas de clasificación binaria, que permite estimar
la probabilidad de ocurrencia de un evento a partir de múltiples
variables independientes. En esta investigación, se aplicó para calcular
la probabilidad de que una paciente presente diabetes utilizando las
mismas variables seleccionadas para KNN.
El modelo Logit utiliza una función logística para transformar las
variables predictoras en probabilidades entre 0 y 1, permitiendo
clasificar pacientes e interpretar cómo cada variable influye en el
riesgo de diabetes. A diferencia del modelo KNN, la regresión logística
ofrece una ventaja metodológica importante al permitir interpretar cómo
cada variable influye sobre la probabilidad de desarrollar diabetes,
facilitando una comprensión más estructurada del fenómeno estudiado.
3. Análisis Descriptivo
3.1 Variable de Clasificación
La variable de clasificación se encuentra nombrada como
Outcome. En la base de datos se encontraron 768 observaciones,
de las cuales 500 pacientes (65.1%) corresponden a los que no tienen
diabetes y 268 pacientes (34.9%) son los que tienen diabetes. En otras
palabras, 2 de cada 3 pacientes pertenecen al grupo que no tiene
diabetes y 1 de cada 3 sí tiene diabetes.
Este resultado demuestra que las pacientes sin diabetes tienen la
mayor proporción de datos. Esta distribución es importante porque al
usar los modelos de clasificación como KNN o Logit, el algoritmo podría
tener mayor tendencia a predecir la categoría mayoritaria, aspecto que
debe considerarse al interpretar las métricas.
diabetes_nueva %>%
mutate(Diagnostico = ifelse(Outcome == 1, "Sí tiene diabetes", "No tiene diabetes")) %>%
ggplot(aes(x = Diagnostico, fill = Diagnostico)) +
geom_bar(width = 0.52, color = "white", linewidth = 0.5) +
geom_text(
stat = "count",
aes(label = paste0(after_stat(count), "\n(",
round(after_stat(count) / n_total * 100, 1), "%)")),
vjust = -0.4, fontface = "bold", size = 4.8
) +
scale_fill_manual(values = c("Sí tiene diabetes" = col_si,
"No tiene diabetes" = col_no)) +
scale_y_continuous(limits = c(0, 620)) +
labs(
title = "Distribución del diagnóstico de diabetes",
subtitle = "Base de datos Pima Indians (n = 768)",
x = NULL, y = "Número de pacientes"
) +
theme_minimal(base_size = 13) +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", color = "#2c3e50"),
plot.subtitle = element_text(color = col_neu)
)

3.2 Análisis descriptivo de variables cuantitativas
Se realizó un análisis descriptivo de las variables cuantitativas
sobre medidas de tendencia central como la media y la mediana, al igual
que valores extremos y distribución interna de los datos. A continuación
se presenta el resumen estadístico de las cinco variables
seleccionadas.
# CORRECCIÓN: se excluye Outcome (factor) del summary numérico
summary(diabetes_nueva %>% select(-Outcome))
## Glucose BMI Age BloodPressure
## Min. : 0.0 Min. : 0.00 Min. :21.00 Min. : 0.00
## 1st Qu.: 99.0 1st Qu.:27.30 1st Qu.:24.00 1st Qu.: 62.00
## Median :117.0 Median :32.00 Median :29.00 Median : 72.00
## Mean :120.9 Mean :31.99 Mean :33.24 Mean : 69.11
## 3rd Qu.:140.2 3rd Qu.:36.60 3rd Qu.:41.00 3rd Qu.: 80.00
## Max. :199.0 Max. :67.10 Max. :81.00 Max. :122.00
## DiabetesPedigreeFunction
## Min. :0.0780
## 1st Qu.:0.2437
## Median :0.3725
## Mean :0.4719
## 3rd Qu.:0.6262
## Max. :2.4200
Glucosa: presenta un rango entre 0 y 199, con media
de 120.9 y mediana de 117. La proximidad entre ambas sugiere
distribución relativamente estable en la zona central; sin embargo, la
media levemente superior indica que algunos valores altos desplazan el
promedio. El 50% central de las pacientes se concentra entre 99 y 140.2
mg/dL.
BMI: varía entre 0 y 67.10, con media y mediana casi
idénticas (~32), indicando equilibrio en la distribución central. El
rango intercuartílico (27.30–36.60) más estrecho que el de glucosa
refleja mayor estabilidad relativa. Los valores máximos elevados podrían
indicar casos extremos de alta masa corporal.
Age: media de 33.24 años y mediana de 29, lo que
indica concentración en la adultez joven/temprana. El rango (21–81 años)
refleja amplia diversidad generacional, aunque los cuartiles (24–41
años) confirman que la mayor concentración es en adultos jóvenes.
BloodPressure: media de 69.11 y mediana de 72. El
50% central se encuentra entre 62 y 80 mmHg, comportamiento estable
dentro de rangos considerados moderados (≤ 120/80 mmHg). Se presentan
valores “0” que podrían representar datos faltantes.
DiabetesPedigreeFunction: media de 0.4719 y mediana
de 0.3725. La media superior a la mediana indica distribución inclinada
hacia valores superiores, generada por pacientes con antecedentes
hereditarios más altos. El rango intercuartílico (0.24–0.63) muestra que
la mayoría se concentra en niveles moderados.
3.3 Distribución individual de variables numéricas
Las siguientes gráficas muestran la distribución de frecuencias de
cada variable explicativa. Su análisis permite identificar la forma de
la distribución, la presencia de asimetrías y posibles valores atípicos
antes de construir los modelos.
diabetes_larga <- diabetes_nueva %>%
select(-Outcome) %>%
pivot_longer(everything(), names_to = "Variable", values_to = "Valor") %>%
mutate(Variable = recode(Variable,
Glucose = "Glucosa",
BMI = "Índice de Masa Corporal (BMI)",
Age = "Edad",
BloodPressure = "Presión Arterial",
DiabetesPedigreeFunction = "Predisposición Familiar"
))
colores_hist <- c(
"Glucosa" = "#2980B9",
"Índice de Masa Corporal (BMI)" = "#E74C3C",
"Edad" = "#8E44AD",
"Presión Arterial" = "#F39C12",
"Predisposición Familiar" = "#27AE60"
)
ggplot(diabetes_larga, aes(x = Valor, fill = Variable)) +
geom_histogram(bins = 28, alpha = 0.85, color = "white", linewidth = 0.3) +
scale_fill_manual(values = colores_hist) +
facet_wrap(~ Variable, scales = "free", ncol = 2) +
labs(
title = "Distribución de las variables explicativas",
subtitle = "Base de datos Pima Indians (n = 768)",
x = "Valor", y = "Frecuencia"
) +
theme_minimal(base_size = 12) +
theme(
legend.position = "none",
strip.text = element_text(face = "bold", color = "#2c3e50"),
plot.title = element_text(face = "bold", color = "#2c3e50"),
plot.subtitle = element_text(color = col_neu)
)

Distribución de la Glucosa: se observa una
concentración importante en valores intermedios (cercanos a 100–140
mg/dL), consistente con la media y mediana identificadas. El histograma
muestra una ligera asimetría positiva, con extensión hacia valores altos
cercanos a 200, asociados a mayor riesgo de diabetes. Se observan
valores cercanos a cero que podrían representar datos faltantes o
atípicos.
Distribución del BMI: concentración principal entre
25 y 40, con frecuencia alta en valores cercanos a 30–35. El histograma
muestra un único pico principal, lo que indica que la mayoría presenta
un nivel de masa homogéneo. Un subconjunto muy reducido de pacientes
presenta valores elevados, posiblemente indicando obesidad severa. Al
igual que en glucosa, hay valores cercanos a 0 que podrían corresponder
a datos faltantes.
Distribución de la Edad: mayor concentración entre
los 20 y 25 años. La distribución presenta una asimetría positiva (sesgo
a la derecha), ya que las frecuencias disminuyen a medida que aumenta la
edad. Existen pocos pacientes adultos mayores en comparación con los
pacientes jóvenes.
Distribución de la Presión Arterial: concentración
principal entre 60 y 85 mmHg, con un pico cercano a 70–80 mmHg. La
distribución presenta una forma cercana a una campana con ligera
asimetría positiva. Se evidencia el valor “0”, que puede representar
datos faltantes.
Distribución del Índice de Predisposición: mayor
concentración entre 0.1 y 0.6. La distribución presenta una marcada
asimetría positiva, ya que la mayor parte de los datos se concentra en
valores bajos y la cola se extiende hacia la derecha (valores cercanos a
2.5). Esta variable no sigue una distribución normal.
3.4 Relación entre las variables numéricas y la diabetes
Los diagramas de caja permiten observar si cada variable presenta
diferencias entre el grupo con diabetes (1) y sin diabetes (0), lo cual
anticipa su capacidad discriminatoria dentro de los modelos de
clasificación.
diabetes_box <- diabetes_nueva %>%
pivot_longer(
cols = c(Glucose, BMI, Age, BloodPressure, DiabetesPedigreeFunction),
names_to = "Variable",
values_to = "Valor"
) %>%
mutate(
Variable = recode(Variable,
Glucose = "Glucosa",
BMI = "Índice de Masa Corporal",
Age = "Edad",
BloodPressure = "Presión Arterial",
DiabetesPedigreeFunction = "Predisposición Familiar"
),
Diagnostico = ifelse(Outcome == 1, "Con diabetes", "Sin diabetes")
)
ggplot(diabetes_box, aes(x = Diagnostico, y = Valor, fill = Diagnostico)) +
geom_boxplot(
alpha = 0.8,
outlier.shape = 21,
outlier.size = 1.5,
outlier.fill = "white",
outlier.color = "gray50"
) +
scale_fill_manual(values = c("Con diabetes" = col_si, "Sin diabetes" = col_no)) +
facet_wrap(~ Variable, scales = "free_y", ncol = 2) +
labs(
title = "Distribución de variables por grupo de diagnóstico",
subtitle = "Comparación entre pacientes con y sin diabetes",
x = NULL, y = "Valor"
) +
theme_minimal(base_size = 12) +
theme(
legend.position = "none",
strip.text = element_text(face = "bold", color = "#2c3e50"),
plot.title = element_text(face = "bold", color = "#2c3e50"),
plot.subtitle = element_text(color = col_neu)
)

Glucosa según Diabetes: los pacientes diagnosticados
con diabetes presentan niveles de glucosa claramente más elevados. La
mediana del grupo diabético es mayor, lo que indica que al menos la
mitad de las personas diabéticas tienen niveles altos de glucosa en
comparación con el grupo sin diabetes. El grupo diabético también
muestra mayor dispersión (caja más amplia y bigotes más largos),
mientras que el grupo sin diabetes presenta una distribución más
concentrada. Se evidencian valores atípicos en ambos grupos. Esta
variable es la de mayor capacidad discriminatoria en el estudio
(MedlinePlus, s.f.).
BMI según Diabetes: los pacientes con diabetes
presentan valores de BMI más elevados. La caja del grupo sin diabetes es
más amplia (mayor dispersión), mientras que la del grupo con diabetes es
más estrecha (valores más concentrados alrededor de la mediana). Ambos
grupos muestran valores atípicos, incluyendo un valor máximo de 67.10
kg/m² y valores cercanos a 0.
Edad según Diabetes: las pacientes sin diabetes
presentan una mediana de aproximadamente 29 años, con una caja más
estrecha y concentración en pacientes jóvenes. Las pacientes con
diabetes muestran una mediana superior cercana a los 35 años, con mayor
variación. El grupo sin diabetes presenta varios valores atípicos por
encima de los 60 años, llegando hasta los 81 años. La diferencia entre
medianas confirma que la edad tiene capacidad discriminatoria relevante
para el modelo.
Presión Arterial según Diabetes: ambos grupos
presentan una distribución muy similar, con medianas cercanas entre sí
(~72 y ~75 mmHg). Ambos grupos tienen valores atípicos en los extremos.
Esta variable evidencia poca diferencia entre grupos, lo que limita su
capacidad discriminatoria individual.
Predisposición Familiar según Diabetes: las
pacientes sin diabetes presentan una mediana de aproximadamente 0.35,
con caja más estrecha. Las pacientes con diabetes muestran una mediana
ligeramente superior (~0.48) y mayor variación. Las pacientes con
diabetes tienden a presentar una predisposición familiar ligeramente más
alta.
3.5 Estadísticas por Grupo
media_variables <- diabetes_nueva %>%
group_by(Outcome) %>%
summarise(
`Glucosa` = round(mean(Glucose), 2),
`BMI` = round(mean(BMI), 2),
`Edad` = round(mean(Age), 2),
`Presión Arterial` = round(mean(BloodPressure), 2),
`Predisposición Fam.` = round(mean(DiabetesPedigreeFunction), 4)
) %>%
mutate(Outcome = ifelse(Outcome == 1, "Con diabetes", "Sin diabetes")) %>%
rename(Grupo = Outcome)
media_variables %>%
kable(caption = "Tabla 1. Medias de las variables explicativas por grupo de diagnóstico") %>%
kable_styling(
full_width = FALSE,
position = "center",
bootstrap_options = c("striped", "hover", "condensed")
) %>%
row_spec(0, bold = TRUE, color = "white", background = "#2C3E50") %>%
row_spec(1, background = "#FADBD8") %>%
row_spec(2, background = "#D6EAF8")
Tabla 1. Medias de las variables explicativas por grupo de diagnóstico
|
Grupo
|
Glucosa
|
BMI
|
Edad
|
Presión Arterial
|
Predisposición Fam.
|
|
Sin diabetes
|
109.98
|
30.30
|
31.19
|
68.18
|
0.4297
|
|
Con diabetes
|
141.26
|
35.14
|
37.07
|
70.82
|
0.5505
|
Interpretación de la tabla de medias: La tabla
confirma las diferencias observadas en los diagramas de caja. Las
pacientes con diabetes presentan valores promedio más altos en todas las
variables.
- Glucosa: diferencia de ~31.28 mg/dL (141.26 vs
109.98). Es la variable con mayor poder diferenciador, confirmando su
rol como determinante principal para el análisis.
- BMI: diferencia de ~3.87 kg/m² (35.14 vs 30.30).
Las pacientes con diabetes presentan obesidad moderada (>30),
mientras que las sin diabetes se encuentran en el límite (OMS,
2025).
- Edad: diferencia de ~6 años (37.07 vs 31.19).
Confirma que las pacientes diabéticas tienden a ser mayores.
- Presión arterial y predisposición familiar:
diferencias más pequeñas (2.64 mmHg y 0.12 puntos respectivamente),
coherente con lo observado en los diagramas de caja.
En síntesis, la glucosa, el IMC y la edad son las variables con mayor
poder diferenciador, lo que anticipa que tendrán mayor peso en los
modelos de clasificación.
4. Modelos de Clasificación
4.1 Modelo KNN
Preparación y estandarización
Dado que KNN opera con distancias euclidianas, es imprescindible
estandarizar las variables para evitar que aquellas con mayor escala
dominen el cálculo de similitud entre pacientes.
# Variables a escalar
vars_pred <- c("Glucose", "BMI", "Age", "BloodPressure", "DiabetesPedigreeFunction")
# Calcular media y sd del entrenamiento para escalar ambos conjuntos con los mismos parámetros
# (buena práctica: el test nunca informa los parámetros de escalado)
medias_train <- colMeans(train_original[, vars_pred])
sds_train <- apply(train_original[, vars_pred], 2, sd)
escalar_con_train <- function(df) {
df_esc <- df
for (v in vars_pred) {
df_esc[[paste0(v, "_esc")]] <- (df[[v]] - medias_train[v]) / sds_train[v]
}
df_esc
}
knn_entrena <- escalar_con_train(train_original)
knn_test <- escalar_con_train(test_original)
# Convertir Outcome a factor
knn_entrena$Outcome <- factor(knn_entrena$Outcome, levels = c(0, 1))
knn_test$Outcome <- factor(knn_test$Outcome, levels = c(0, 1))
# Nombres de columnas escaladas
vars_esc <- paste0(vars_pred, "_esc")
# Matrices de entrada y vectores de salida para knn()
knn_entrena_input <- knn_entrena[, vars_esc]
knn_test_input <- knn_test[, vars_esc]
knn_entrena_output <- knn_entrena$Outcome
knn_test_output <- knn_test$Outcome
cat("Entrenamiento KNN:", nrow(knn_entrena), "observaciones\n")
## Entrenamiento KNN: 538 observaciones
cat("Prueba KNN: ", nrow(knn_test), "observaciones\n")
## Prueba KNN: 230 observaciones
4.1.1 Selección del parámetro óptimo de k
Para determinar el valor óptimo de k, se utilizó el paquete
caret evaluando 200 valores de k mediante un remuestreo de
25 repeticiones sobre los 300 pacientes de entrenamiento. Este método
prueba cada valor de k con grupos diferentes de pacientes, lo que
permite obtener un resultado más confiable para predecir el diagnóstico
de diabetes.
# Curva de precisión exploratoria k = 1 a 50
k_vals <- 1:50
resultado <- data.frame(k = k_vals, precision = NA_real_)
for (n in k_vals) {
pred_k <- knn(
train = knn_entrena_input,
cl = knn_entrena_output,
test = knn_test_input,
k = n
)
resultado$precision[n] <- mean(pred_k == knn_test_output)
}
k_opt <- resultado$k[which.max(resultado$precision)]
prec_op <- round(max(resultado$precision) * 100, 1)
ggplot(resultado, aes(x = k, y = precision)) +
geom_line(color = col_no, linewidth = 0.9) +
geom_point(color = col_no, size = 1.5, alpha = 0.6) +
geom_vline(xintercept = k_opt, linetype = "dashed",
color = col_si, linewidth = 0.9) +
annotate("label",
x = k_opt + 2, y = min(resultado$precision) + 0.005,
label = paste0("k óptimo = ", k_opt, "\nPrecisión = ", prec_op, "%"),
fill = "#FDFEFE", color = col_si, size = 3.5, hjust = 0
) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
labs(
title = "Precisión del modelo KNN según el número de vecinos (k)",
subtitle = paste0("Evaluado sobre el conjunto de prueba (n = ", nrow(knn_test), ")"),
x = "Número de vecinos (k)", y = "Precisión"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", color = "#2c3e50"),
plot.subtitle = element_text(color = col_neu)
)

La gráfica muestra que con k=1 la precisión es muy baja (~67%),
reflejando alta inestabilidad. Entre k=1 y k=5 la precisión sube
rápidamente hasta ~75%, para luego bajar alrededor de k=8. A partir de
ese punto mejora hasta alcanzar su máximo. Esto confirma que valores muy
pequeños generan predicciones poco confiables, mientras que valores
moderados ofrecen el mejor desempeño.
# Entrenamiento con validación cruzada via caret (tuneLength = 200 valores de k)
set.seed(28)
knn_entrenado <- train(
Outcome ~ Glucose_esc + BMI_esc + Age_esc +
BloodPressure_esc + DiabetesPedigreeFunction_esc,
data = knn_entrena,
method = "knn",
tuneLength = 200
)
plot(knn_entrenado,
main = "Accuracy Bootstrap según número de vecinos (caret)",
col = col_no)

La gráfica de accuracy con remuestreo muestra que con valores
pequeños de k la exactitud comienza alrededor del 66%, mejorando
progresivamente hasta alcanzar su punto máximo en k =
53 con 71.60%. A partir de ese punto la
exactitud cae de forma continua hasta aproximadamente k = 220, donde se
estabiliza alrededor del 63%. Consultar más de 220 pacientes similares
hace que el modelo pierda totalmente su capacidad discriminatoria. Por
esta razón, k = 53 fue adoptado como el parámetro
definitivo.
4.1.2 Matriz de confusión y métricas
# Predicciones de clase y probabilidades sobre el conjunto de prueba
knn_prediccion <- predict(knn_entrenado, newdata = knn_test)
prob_knn_prediccion <- predict(knn_entrenado, newdata = knn_test, type = "prob")
cm_knn <- confusionMatrix(knn_prediccion, knn_test$Outcome)
cm_knn
## Confusion Matrix and Statistics
##
## Reference
## Prediction 0 1
## 0 137 35
## 1 15 43
##
## Accuracy : 0.7826
## 95% CI : (0.7236, 0.8341)
## No Information Rate : 0.6609
## P-Value [Acc > NIR] : 3.677e-05
##
## Kappa : 0.4827
##
## Mcnemar's Test P-Value : 0.00721
##
## Sensitivity : 0.9013
## Specificity : 0.5513
## Pos Pred Value : 0.7965
## Neg Pred Value : 0.7414
## Prevalence : 0.6609
## Detection Rate : 0.5957
## Detection Prevalence : 0.7478
## Balanced Accuracy : 0.7263
##
## 'Positive' Class : 0
##
Resultados KNN (k = 53):
Al evaluar el modelo sobre los 200 pacientes del conjunto de prueba,
se obtuvo una exactitud global del 75%, superando la
tasa de no información del 69.5%, lo que confirma que el modelo aporta
valor real al diagnóstico.
- Sensibilidad: 87.77% — de las 139 pacientes sanas,
el modelo identificó correctamente 122. Esto equivale a descartar
correctamente la enfermedad en casi 9 de cada 10 pacientes sanas.
- Especificidad: 45.90% — de las 61 pacientes
diabéticas, solo se identificaron correctamente 28. Más de la mitad de
las pacientes con diabetes fueron clasificadas como sanas.
- Valor predictivo positivo: 78.71% — cuando el
modelo predice que una paciente no tiene diabetes, acierta casi 8 de
cada 10 veces.
- Valor predictivo negativo: 62.22% — cuando predice
que sí tiene diabetes, acierta solo 6 de cada 10 veces.
- Kappa: 0.36 — acuerdo moderado entre predicciones y
valores reales.
- Exactitud balanceada: 66.84% — el modelo tiene
mejor desempeño identificando pacientes sanas que pacientes
diabéticas.
4.1.3 Curva ROC — KNN
# CORRECCIÓN: se usa la probabilidad de la clase positiva (1 = con diabetes)
# en lugar de as.numeric(knn_prediccion), que daba un AUC distorsionado
prob_pos_knn <- prob_knn_prediccion[, "1"]
pred_roc <- prediction(prob_pos_knn, as.numeric(as.character(knn_test$Outcome)))
perf_roc <- performance(pred_roc, "tpr", "fpr")
auc_knn <- performance(pred_roc, "auc")
auc_knn_valor <- round(auc_knn@y.values[[1]], 3)
fpr_vals <- unlist(perf_roc@x.values)
tpr_vals <- unlist(perf_roc@y.values)
roc_df <- data.frame(FPR = fpr_vals, TPR = tpr_vals)
ggplot(roc_df, aes(x = FPR, y = TPR)) +
geom_line(color = col_no, linewidth = 1.1) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = col_neu) +
annotate("label",
x = 0.65, y = 0.15,
label = paste0("AUC = ", auc_knn_valor),
fill = "#EBF5FB", color = col_no, size = 4.2, fontface = "bold"
) +
labs(
title = "Curva ROC — Modelo KNN",
x = "Tasa de Falsos Positivos (1 − Especificidad)",
y = "Tasa de Verdaderos Positivos (Sensibilidad)"
) +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold", color = "#2c3e50"))

La curva ROC del modelo KNN evaluada sobre el conjunto de prueba
muestra un AUC de 0.828, lo que indica que el modelo
tiene un 82.8% de probabilidad de clasificar correctamente a una
paciente diabética por encima de una sana; este valor se considera
aceptable. Este resultado es coherente con lo observado en la matriz de
confusión, donde el modelo mostró buen desempeño identificando pacientes
sanas pero falló en más de la mitad de los casos diabéticos.
4.2 Modelo de Regresión Logística (Logit)
Con el propósito de complementar el análisis y comparar distintos
enfoques de clasificación, se implementó un modelo de regresión
logística utilizando el mismo conjunto de variables previamente
seleccionadas. Este modelo permitió estimar la probabilidad de que una
paciente presente diabetes a partir de factores clínicos, físicos y
hereditarios.
Partición de datos
El modelo Logit utiliza la misma partición 70/30
generada al inicio con createDataPartition, garantizando
que la evaluación sea directamente comparable con el modelo KNN sobre
exactamente los mismos pacientes de prueba.
# Reutilizar la partición unificada: train_original y test_original
mydata <- train_original
mydata$Outcome_f <- factor(mydata$Outcome, levels = c(0, 1), labels = c("No", "Si"))
test_logit <- test_original
test_logit$Outcome_f <- factor(test_logit$Outcome, levels = c(0, 1), labels = c("No", "Si"))
cat("Entrenamiento Logit:", nrow(mydata), "observaciones\n")
## Entrenamiento Logit: 538 observaciones
cat("Prueba Logit: ", nrow(test_logit), "observaciones\n")
## Prueba Logit: 230 observaciones
4.2.1 Ajuste e interpretación general del modelo
fit_logit <- glm(
Outcome ~ Glucose + BMI + Age + BloodPressure + DiabetesPedigreeFunction,
data = mydata,
family = binomial()
)
summary(fit_logit)
##
## Call:
## glm(formula = Outcome ~ Glucose + BMI + Age + BloodPressure +
## DiabetesPedigreeFunction, family = binomial(), data = mydata)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -8.236548 0.837875 -9.830 < 2e-16 ***
## Glucose 0.030894 0.004007 7.710 1.25e-14 ***
## BMI 0.089473 0.016367 5.467 4.59e-08 ***
## Age 0.031563 0.009445 3.342 0.000833 ***
## BloodPressure -0.008420 0.006583 -1.279 0.200835
## DiabetesPedigreeFunction 0.674548 0.356042 1.895 0.058149 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 698.73 on 537 degrees of freedom
## Residual deviance: 527.52 on 532 degrees of freedom
## AIC: 539.52
##
## Number of Fisher Scoring iterations: 5
En términos generales, el modelo evidenció que variables como la
glucosa, el índice de masa corporal y la edad presentan
una influencia positiva sobre la probabilidad estimada de diabetes,
resultado consistente con la literatura médica y con el análisis
exploratorio realizado. Pacientes con mayores niveles de glucosa, mayor
BMI o mayor edad tienden a presentar un mayor riesgo de diagnóstico
positivo. La presión arterial mostró una capacidad explicativa más
moderada, mientras que la función de pedigrí diabético aportó
información asociada a la predisposición hereditaria. Las variables con
p-valor < 0.05 son estadísticamente significativas
en la predicción.
4.2.2 Desempeño predictivo del modelo
# Predicción con umbral estándar de 0.5
p_hat <- predict(fit_logit, newdata = test_logit, type = "response")
pred_clase <- factor(ifelse(p_hat >= 0.5, "Si", "No"), levels = c("Si", "No"))
confusionMatrix(pred_clase, test_logit$Outcome_f, positive = "Si")
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Si
## No 136 32
## Si 16 46
##
## Accuracy : 0.7913
## 95% CI : (0.733, 0.8419)
## No Information Rate : 0.6609
## P-Value [Acc > NIR] : 9.854e-06
##
## Kappa : 0.5099
##
## Mcnemar's Test P-Value : 0.03038
##
## Sensitivity : 0.5897
## Specificity : 0.8947
## Pos Pred Value : 0.7419
## Neg Pred Value : 0.8095
## Prevalence : 0.3391
## Detection Rate : 0.2000
## Detection Prevalence : 0.2696
## Balanced Accuracy : 0.7422
##
## 'Positive' Class : Si
##
A continuación, se aplica el índice de Youden para
encontrar el umbral de clasificación que maximiza simultáneamente la
sensibilidad y la especificidad, en lugar del umbral estándar de
0.5.
roc_o <- roc(response = test_logit$Outcome_f, predictor = p_hat, levels = c("No", "Si"))
thr <- coords(roc_o, x = "best", best.method = "youden", ret = "threshold")
umbral <- as.numeric(thr)
auc_val <- auc(roc_o)
auc_val_r <- round(as.numeric(auc_val), 3)
roc_data <- data.frame(
FPR = rev(1 - roc_o$specificities),
TPR = rev(roc_o$sensitivities)
)
ggplot(roc_data, aes(x = FPR, y = TPR)) +
geom_line(color = col_si, linewidth = 1.1) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = col_neu) +
annotate("label",
x = 0.65, y = 0.15,
label = paste0("AUC = ", auc_val_r,
"\nUmbral óptimo = ", round(umbral, 3)),
fill = "#FDEDEC", color = col_si, size = 3.8, fontface = "bold"
) +
labs(
title = "Curva ROC — Regresión Logística (Logit)",
x = "Tasa de Falsos Positivos (1 − Especificidad)",
y = "Tasa de Verdaderos Positivos (Sensibilidad)"
) +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold", color = "#2c3e50"))

# Reclasificación con umbral óptimo de Youden
pred_clase <- factor(ifelse(p_hat >= umbral, "Si", "No"), levels = c("Si", "No"))
cm_logit <- confusionMatrix(pred_clase, test_logit$Outcome_f, positive = "Si")
cm_logit
## Confusion Matrix and Statistics
##
## Reference
## Prediction No Si
## No 119 19
## Si 33 59
##
## Accuracy : 0.7739
## 95% CI : (0.7143, 0.8263)
## No Information Rate : 0.6609
## P-Value [Acc > NIR] : 0.0001244
##
## Kappa : 0.5167
##
## Mcnemar's Test P-Value : 0.0714235
##
## Sensitivity : 0.7564
## Specificity : 0.7829
## Pos Pred Value : 0.6413
## Neg Pred Value : 0.8623
## Prevalence : 0.3391
## Detection Rate : 0.2565
## Detection Prevalence : 0.4000
## Balanced Accuracy : 0.7697
##
## 'Positive' Class : Si
##
Resultados Regresión Logística (umbral óptimo de Youden =
0.32):
Al evaluar el modelo sobre el conjunto de prueba, la regresión
logística alcanzó una exactitud global del 80.73%,
clasificando correctamente aproximadamente 8 de cada 10 pacientes.
- Sensibilidad: 73.13% — logró identificar
correctamente una proporción importante de pacientes que realmente
presentan diabetes, reduciendo falsos negativos.
- Especificidad: 84.80% — alta capacidad para
identificar correctamente pacientes sin diabetes, reduciendo falsos
positivos.
- Valor predictivo positivo (PPV): 72.06% — cuando
clasifica a una paciente como positiva, la predicción tiene una
probabilidad alta de ser correcta.
- Valor predictivo negativo (NPV): 85.48% — refuerza
la confiabilidad del modelo para clasificar pacientes sin la
enfermedad.
- Exactitud balanceada: 78.97% — desempeño
relativamente equilibrado entre sensibilidad y especificidad.
- AUC: 0.835 — capacidad discriminatoria superior al
modelo KNN.
5. Comparación de Modelos
Al comparar los resultados obtenidos entre KNN y la regresión
logística, se identificaron diferencias importantes en el desempeño
predictivo. A continuación se presenta la tabla resumen y la gráfica
comparativa.
comparacion_modelos <- data.frame(
Modelo = c("KNN", "Logit"),
Accuracy = c(cm_knn$overall["Accuracy"], cm_logit$overall["Accuracy"]),
Sensibilidad = c(cm_knn$byClass["Sensitivity"], cm_logit$byClass["Sensitivity"]),
Especificidad = c(cm_knn$byClass["Specificity"], cm_logit$byClass["Specificity"]),
Precision = c(cm_knn$byClass["Pos Pred Value"], cm_logit$byClass["Pos Pred Value"]),
AUC = c(auc_knn_valor, auc_val_r)
)
comparacion_modelos %>%
mutate(across(where(is.numeric), ~ round(.x, 3))) %>%
kable(
col.names = c("Modelo", "Exactitud", "Sensibilidad",
"Especificidad", "Precisión", "AUC"),
caption = "Tabla 2. Comparación de métricas de clasificación — KNN vs. Regresión Logística"
) %>%
kable_styling(
full_width = FALSE,
position = "center",
bootstrap_options = c("striped", "hover", "condensed")
) %>%
row_spec(0, bold = TRUE, color = "white", background = "#2C3E50") %>%
row_spec(1, background = "#D6EAF8") %>%
row_spec(2, background = "#FADBD8")
Tabla 2. Comparación de métricas de clasificación — KNN vs. Regresión
Logística
|
Modelo
|
Exactitud
|
Sensibilidad
|
Especificidad
|
Precisión
|
AUC
|
|
KNN
|
0.783
|
0.901
|
0.551
|
0.797
|
0.828
|
|
Logit
|
0.774
|
0.756
|
0.783
|
0.641
|
0.835
|
comparacion_modelos %>%
pivot_longer(-Modelo, names_to = "Metrica", values_to = "Valor") %>%
mutate(Metrica = factor(Metrica,
levels = c("Accuracy", "Sensibilidad", "Especificidad", "Precision", "AUC")
)) %>%
ggplot(aes(x = Metrica, y = Valor, fill = Modelo)) +
geom_col(position = "dodge", width = 0.58, alpha = 0.88, color = "white") +
geom_text(
aes(label = round(Valor, 3)),
position = position_dodge(width = 0.58),
vjust = -0.5, size = 3.2, fontface = "bold"
) +
scale_fill_manual(values = c("KNN" = col_no, "Logit" = col_si)) +
scale_y_continuous(limits = c(0, 1.1),
labels = scales::percent_format(accuracy = 1)) +
labs(
title = "Comparación de métricas entre KNN y Regresión Logística",
subtitle = "Evaluadas sobre el conjunto de prueba",
x = "Métrica", y = "Valor", fill = "Modelo"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", color = "#2c3e50"),
plot.subtitle = element_text(color = col_neu),
legend.position = "top"
)

5.2 Curvas ROC comparativas
# Curva ROC del KNN usando pROC (misma librería que Logit para gráfico unificado)
roc_knn <- roc(
response = knn_test$Outcome,
predictor = prob_knn_prediccion[, "1"],
levels = c("0", "1")
)
# Construir data frame con ambas curvas para ggplot
roc_knn_df <- data.frame(
FPR = rev(1 - roc_knn$specificities),
TPR = rev(roc_knn$sensitivities),
Modelo = "KNN"
)
roc_logit_df <- data.frame(
FPR = rev(1 - roc_o$specificities),
TPR = rev(roc_o$sensitivities),
Modelo = "Logit"
)
roc_comparacion <- bind_rows(roc_knn_df, roc_logit_df)
ggplot(roc_comparacion, aes(x = FPR, y = TPR, color = Modelo)) +
geom_line(linewidth = 1.2) +
geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = col_neu) +
annotate("label",
x = 0.62, y = 0.22,
label = paste0("AUC KNN = ", auc_knn_valor,
"\nAUC Logit = ", auc_val_r),
fill = "#FDFEFE", color = "#2c3e50", size = 3.8, fontface = "bold", hjust = 0
) +
scale_color_manual(values = c("KNN" = col_no, "Logit" = col_si)) +
labs(
title = "Curvas ROC comparativas — KNN vs. Regresión Logística",
subtitle = "Evaluadas sobre el mismo conjunto de prueba (partición 70/30)",
x = "Tasa de Falsos Positivos (1 − Especificidad)",
y = "Tasa de Verdaderos Positivos (Sensibilidad)",
color = "Modelo"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", color = "#2c3e50"),
plot.subtitle = element_text(color = col_neu),
legend.position = "top"
)

Interpretación comparativa:
- Exactitud global: el modelo Logit presentó un mejor
resultado (80.73% vs 75.00%), clasificando correctamente una mayor
proporción de pacientes.
- Sensibilidad: KNN mostró una ventaja considerable
(87.77% vs 73.13%), siendo más efectivo para detectar pacientes que
realmente presentan diabetes. Desde una perspectiva médica, esto puede
ser valioso cuando la prioridad es maximizar la detección temprana.
- Especificidad: la regresión logística presentó una
superioridad muy marcada (84.80% vs 45.90%), siendo significativamente
más precisa para identificar pacientes sin diabetes y reduciendo falsos
positivos.
- AUC: favorece ampliamente a Logit (0.835 vs 0.828),
confirmando una capacidad considerablemente superior para diferenciar
entre ambas clases a distintos niveles de decisión.
Ambos modelos presentan fortalezas distintas. KNN destacó por su alta
sensibilidad; sin embargo, su baja especificidad y menor AUC reflejan
mayor tendencia a cometer falsos positivos. La regresión logística no
solo presentó mejores métricas globales, sino que además ofrece una
ventaja interpretativa, permitiendo comprender cómo cada variable
influye sobre la probabilidad de desarrollar diabetes. En consecuencia,
la regresión logística se posiciona como el modelo más
adecuado para este estudio, por su mayor exactitud, mejor
especificidad, superior AUC y utilidad interpretativa.
6. Conclusiones
Limitaciones del estudio: El análisis se restringe a
mujeres indígenas Pima mayores de 21 años, por lo que los resultados no
son directamente generalizables a otras poblaciones. Se detectaron
valores de 0 en variables como glucosa y presión arterial que podrían
corresponder a datos faltantes no tratados explícitamente, lo que puede
afectar la capacidad predictiva de los modelos. La partición 70/30 con
semilla fija garantiza reproducibilidad, pero los resultados podrían
variar con otras semillas aleatorias.
A partir del análisis comparativo entre los modelos KNN y Regresión
Logística para la clasificación de pacientes con diabetes en la base de
datos Pima Indians, se concluye:
La glucosa, el BMI y la edad son las variables
con mayor poder diferenciador entre pacientes con y sin diabetes,
confirmando los hallazgos de la literatura científica previa. La presión
arterial mostró la menor capacidad discriminatoria individual.
El modelo de Regresión Logística supera al KNN
en exactitud global, especificidad y AUC (0.835 vs 0.828), como se
evidencia tanto en la tabla de métricas como en las curvas ROC
comparativas, consolidándose como el modelo más robusto dentro del
análisis realizado.
El modelo KNN destacó por su alta sensibilidad
(87.77%), lo que lo convierte en una alternativa útil cuando el objetivo
principal es detectar la mayor cantidad posible de casos positivos,
aunque a costa de una elevada tasa de falsos positivos.
La optimización del umbral de clasificación
mediante el índice de Youden mejoró el balance entre sensibilidad y
especificidad en el modelo Logit, permitiendo una clasificación más
equilibrada en ambas clases.
Desde el punto de vista clínico, dado que los falsos
negativos (no detectar una enfermedad presente) tienen
consecuencias más graves que los falsos positivos, la regresión
logística representa la herramienta más completa y equilibrada para este
problema de diagnóstico.
7. Referencias
- CDC. (2024). Factores de riesgo de la diabetes. Centers for Disease
Control and Prevention. https://www.cdc.gov/diabetes/es/risk-factors/factores-de-riesgo-de-la-diabetes.html
- Genfar. (2021). ¿Cuáles son los valores normales de la presión
arterial? https://www.genfar.com/te-cuidamos/cuales-son-los-valores-normales-de-la-presion-arterial/
- Joshi, R. D., & Dhakal, C. K. (2021). Predicting type 2 diabetes
using logistic regression and machine learning approaches.
International Journal of Environmental Research and Public Health,
18(14), 7346. https://pmc.ncbi.nlm.nih.gov/articles/PMC8306487/
- Lagunes Torres, A. (2023). Relación entre el índice de masa corporal
y la diabetes tipo 2. Revista Mexicana de Endocrinología.
- MedlinePlus. (s.f.). Glucosa en sangre. https://medlineplus.gov/spanish/bloodglucose.html
- OMS. (citado en Revista Diabetes, 2024). Herencia de obesidad y
diabetes: más allá de nuestros genes. https://www.revistadiabetes.org/investigacion/herencia-de-obesidad-y-diabetes-mas-alla-de-nuestros-genes/
- OMS. (2025). Obesidad y sobrepeso. https://www.who.int/es/news-room/fact-sheets/detail/obesity-and-overweight
- Sampanis, C., & Zamboulis, C. (2008). Hypertension and diabetes
mellitus. Hippokratia, 12(1), 12–15.
- WHO. (2024). Diabetes. https://www.who.int/es/news-room/fact-sheets/detail/diabetes
LS0tDQp0aXRsZTogIkNsYXNpZmljYWNpw7NuIGRlIERpYWJldGVzIG1lZGlhbnRlIEtOTiB5IFJlZ3Jlc2nDs24gTG9nw61zdGljYSINCnN1YnRpdGxlOiAiQW7DoWxpc2lzIENvbXBhcmF0aXZvIGRlIE1vZGVsb3MgU3VwZXJ2aXNhZG9zIOKAlCBCYXNlIGRlIERhdG9zIFBpbWEgSW5kaWFucyINCmF1dGhvcjogIkZhYmlhbiBWZWxhc3F1ZXogKDIzMjgyODApLEthcmVuIEFudGUoKSxOYXRoYWxpYSBCZW5hdmlkZXMoMjQzOTAwMCksQ3Jpc3RpYW4gU2FudGEoMjQyMDIzMCkiDQpkYXRlOiAiMjAyNi8wNS8xNSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IGZhbHNlDQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICBjb2RlX2ZvbGRpbmc6ICJoaWRlIg0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQpgYGB7Y3NzLCBlY2hvPUZBTFNFfQ0KLyog4pSA4pSAIEZ1ZW50ZSB5IGN1ZXJwbyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgKi8NCmJvZHkgew0KICBmb250LWZhbWlseTogJ1NlZ29lIFVJJywgQXJpYWwsIHNhbnMtc2VyaWY7DQogIGZvbnQtc2l6ZTogMTVweDsNCiAgY29sb3I6ICMyYzNlNTA7DQogIGxpbmUtaGVpZ2h0OiAxLjg7DQogIGJhY2tncm91bmQtY29sb3I6ICNmZmZmZmY7DQp9DQoNCi8qIOKUgOKUgCBFbmNhYmV6YWRvcyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIAgKi8NCmgxIHsNCiAgZm9udC1zaXplOiAxLjlyZW07DQogIGNvbG9yOiAjMWEyNTJmOw0KICBib3JkZXItYm90dG9tOiAzcHggc29saWQgIzI5ODBiOTsNCiAgcGFkZGluZy1ib3R0b206IDhweDsNCiAgbWFyZ2luLXRvcDogNDVweDsNCiAgbWFyZ2luLWJvdHRvbTogMTZweDsNCn0NCmgyIHsNCiAgZm9udC1zaXplOiAxLjRyZW07DQogIGNvbG9yOiAjMmMzZTUwOw0KICBib3JkZXItbGVmdDogNXB4IHNvbGlkICMyOTgwYjk7DQogIHBhZGRpbmctbGVmdDogMTJweDsNCiAgbWFyZ2luLXRvcDogMzJweDsNCiAgbWFyZ2luLWJvdHRvbTogMTJweDsNCn0NCmgzIHsNCiAgZm9udC1zaXplOiAxLjE1cmVtOw0KICBjb2xvcjogIzM0NDk1ZTsNCiAgbWFyZ2luLXRvcDogMjJweDsNCiAgbWFyZ2luLWJvdHRvbTogMTBweDsNCn0NCg0KLyog4pSA4pSAIENhamFzIGRlIHRleHRvIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCAqLw0KLmludGVycHJldGFjaW9uIHsNCiAgYmFja2dyb3VuZC1jb2xvcjogI2VhZjRmYjsNCiAgYm9yZGVyLWxlZnQ6IDVweCBzb2xpZCAjMjk4MGI5Ow0KICBib3JkZXItcmFkaXVzOiA2cHg7DQogIHBhZGRpbmc6IDEzcHggMThweDsNCiAgbWFyZ2luOiAxNHB4IDAgMjBweCAwOw0KICBmb250LXNpemU6IDE0LjVweDsNCn0NCi5yZXN1bHRhZG8tY2xhdmUgew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjZWFmYWYxOw0KICBib3JkZXItbGVmdDogNXB4IHNvbGlkICMyN2FlNjA7DQogIGJvcmRlci1yYWRpdXM6IDZweDsNCiAgcGFkZGluZzogMTNweCAxOHB4Ow0KICBtYXJnaW46IDE0cHggMCAyMHB4IDA7DQogIGZvbnQtc2l6ZTogMTQuNXB4Ow0KfQ0KLmFkdmVydGVuY2lhIHsNCiAgYmFja2dyb3VuZC1jb2xvcjogI2ZlZjllNzsNCiAgYm9yZGVyLWxlZnQ6IDVweCBzb2xpZCAjZjM5YzEyOw0KICBib3JkZXItcmFkaXVzOiA2cHg7DQogIHBhZGRpbmc6IDEzcHggMThweDsNCiAgbWFyZ2luOiAxNHB4IDAgMjBweCAwOw0KICBmb250LXNpemU6IDE0LjVweDsNCn0NCg0KLyog4pSA4pSAIEPDs2RpZ28g4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAICovDQpwcmUgew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjRmNmY3Ow0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRlMWU0Ow0KICBib3JkZXItcmFkaXVzOiA2cHg7DQogIGZvbnQtc2l6ZTogMTNweDsNCn0NCg0KLyog4pSA4pSAIFRhYmxhIGRlIGNvbnRlbmlkb3Mg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAICovDQoudG9jaWZ5IHsNCiAgYm9yZGVyOiBub25lOw0KICBib3JkZXItcmFkaXVzOiA2cHg7DQogIGJhY2tncm91bmQ6ICNmNGY2Zjc7DQogIGZvbnQtc2l6ZTogMTMuNXB4Ow0KfQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCBjYWNoZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgbWVzc2FnZSA9IEZBTFNFLA0KICB3YXJuaW5nID0gRkFMU0UsDQogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLA0KICBmaWcud2lkdGggID0gOCwNCiAgZmlnLmhlaWdodCA9IDUsDQogIGRwaSA9IDE1MA0KKQ0KDQojIFBhbGV0YSBnbG9iYWwgKHNlIHVzYSBlbiB0b2RvcyBsb3MgZ3LDoWZpY29zKQ0KY29sX3NpICA8LSAiI0U3NEMzQyIgICAjIHJvam8gIOKAlCBjb24gZGlhYmV0ZXMNCmNvbF9ubyAgPC0gIiMyOTgwQjkiICAgIyBhenVsICDigJQgc2luIGRpYWJldGVzDQpjb2xfbmV1IDwtICIjN0Y4QzhEIiAgICMgZ3JpcyAg4oCUIG5ldXRybyAvIHJlZmVyZW5jaWENCmBgYA0KDQotLS0NCg0KIyAxLiBJbnRyb2R1Y2Npw7NuDQoNCkxhIGRpYWJldGVzIGVzIHVuYSBlbmZlcm1lZGFkIGNyw7NuaWNhIHF1ZSByZXByZXNlbnRhIHVuYSBkZSBsYXMgcHJpbmNpcGFsZXMgY2F1c2FzIGRlIGRlZnVuY2nDs24gYSBuaXZlbCBtdW5kaWFsLiBTZWfDum4gbGEgT3JnYW5pemFjacOzbiBNdW5kaWFsIGRlIGxhIFNhbHVkLCBlc3RhIGVuZmVybWVkYWQgYWZlY3RhIGEgbcOhcyBkZSA4MzAgbWlsbG9uZXMgZGUgcGVyc29uYXMgZW4gZWwgbXVuZG8sIGVuIHN1IGdyYW4gbWF5b3LDrWEgdWJpY2FkYXMgZW4gbG9zIHBhw61zZXMgZGUgaW5ncmVzbyBtZWRpYW5vIGJham8uIFBvciBlc28sIGVzIGltcG9ydGFudGUgcmVhbGl6YXIgdW5hIGRldGVjY2nDs24gdGVtcHJhbmEgcGFyYSBpbnRlcnZlbmlyIGRlIGZvcm1hIHLDoXBpZGEgeSByZWR1Y2lyIHN1cyBwb3NpYmxlcyBjb21wbGljYWNpb25lcy4gUG9yIGVzdGEgcmF6w7NuLCBsb3MgZGlhZ27Ds3N0aWNvcyBzZSBwdWVkZW4gaWRlbnRpZmljYXIgY29uIG1vZGVsb3MgZXN0YWTDrXN0aWNvcyB5IGFsZ29yaXRtb3MgZGUgYXByZW5kaXphamUgYXV0b23DoXRpY28sIHBlcm1pdGllbmRvIGRlY2lzaW9uZXMgbcOhcyBwcmVjaXNhcy4NCg0KUGFyYSBlc3RlIGVzdHVkaW8gc2UgZXNjb2dpw7MgbGEgKmJhc2UgZGUgZGF0b3MgZGUgZGlhYmV0ZXMgZGUgbG9zIGluZGlvcyBQaW1hKiwgaW5mb3JtYWNpw7NuIHJlY29waWxhZGEgZGVsIEluc3RpdHV0byBOYWNpb25hbCBkZSBEaWFiZXRlcyB5IEVuZmVybWVkYWRlcyBEaWdlc3RpdmFzIHkgUmVuYWxlcy4gQ29udGllbmUgdW4gcmVnaXN0cm8gZGUgYWxndW5hcyByZXN0cmljY2lvbmVzIHBhcmEgbGEgc2VsZWNjacOzbiwgZG9uZGUgbGFzIHBhY2llbnRlcyBpbmNsdWlkYXMgZW4gZXNlIGRpYWduw7NzdGljbyBzb24gbXVqZXJlcyBkZSBhbCBtZW5vcyAyMSBhw7FvcyBkZSBlZGFkIHkgZGUgYXNjZW5kZW5jaWEgaW5kw61nZW5hIFBpbWE7IGN1ZW50YSBjb24gbWVkaWNpb25lcyBkZSBnbHVjb3NhLCBwcmVzacOzbiBhcnRlcmlhbCwgw61uZGljZSBkZSBtYXNhIGNvcnBvcmFsLCBlbnRyZSBvdHJhcy4gU3UgZsOhY2lsIGFjY2VzbyBww7pibGljbyBoYSBzaWRvIGRlIGdyYW4gcmVmZXJlbmNpYSBwYXJhIGludmVzdGlnYWNpb25lcyB5IHBhcmEgYW5hbGl6YXIgcGF0cm9uZXMgcXVlIGNvbnRyaWJ1eWVuIGVuIGlkZW50aWZpY2FyIGhlcnJhbWllbnRhcyBtw6FzIHByZWNpc2FzIHBhcmEgZWwgZGlhZ27Ds3N0aWNvIHkgbGEgY2xhc2lmaWNhY2nDs24gZGUgbGEgZGlhYmV0ZXMuDQoNCkVsIHNpZ3VpZW50ZSBlc3R1ZGlvIHRpZW5lIGNvbW8gb2JqZXRpdm8gKmRlc2Fycm9sbGFyIHkgY29tcGFyYXIgbW9kZWxvcyBkZSBjbGFzaWZpY2FjacOzbiBzdXBlcnZpc2FkYSosIGNvbiBlbCBmaW4gZGUgYXBvcnRhciBldmlkZW5jaWEgdMOpY25pY2EgcGFyYSBpZGVudGlmaWNhciBzaSB1biBwYWNpZW50ZSBwcmVzZW50YSBvIG5vIGRpYWJldGVzIGEgcGFydGlyIGRlIGluZm9ybWFjacOzbiBjb250ZW5pZGEgZW4gbGEgYmFzZSBkZSBkYXRvcy4gRWwgcHJvYmxlbWEgY29ycmVzcG9uZGUgYSB1bmEgKipjbGFzaWZpY2FjacOzbiBiaW5hcmlhKiosIGRvbmRlIGxhIHZhcmlhYmxlIGRlcGVuZGllbnRlIHRvbWEgZG9zIHBvc2libGVzIHJlc3B1ZXN0YXMuIFBhcmEgZWxsbywgc2UgdXRpbGl6YW4gY2luY28gdmFyaWFibGVzIGluZGVwZW5kaWVudGVzIHBhcmEgcmVhbGl6YXIgbGEgY2xhc2lmaWNhY2nDs24gZGUgbGEgdmFyaWFibGUgZGVwZW5kaWVudGUuIFNlIHJlYWxpemEgbGEgY29tcGFyYWNpw7NuIGVudHJlICoqS05OKiogeSBsYSAqKlJlZ3Jlc2nDs24gTG9nw61zdGljYSAoTG9naXQpKiosIGNvbiBlbCBvYmpldGl2byBkZSBpZGVudGlmaWNhciBlbCBtb2RlbG8gcXVlIHByZXNlbnRhIGxhIG1lam9yIGNhcGFjaWRhZCBkZSBwcmVkaWNjacOzbiBkZSBwYWNpZW50ZXMgY29uIGRpYWJldGVzLCBldmFsdWFuZG8gcmVuZGltaWVudG8gbWVkaWFudGUgbcOpdHJpY2FzIGRlIGNsYXNpZmljYWNpw7NuIGVzdMOhbmRhcmVzIGNvbW8gZXhhY3RpdHVkLCBlc3BlY2lmaWNpZGFkLCBzZW5zaWJpbGlkYWQgeSBsYSBjdXJ2YSBST0MuDQoNCi0tLQ0KDQojIDIuIE1ldG9kb2xvZ8OtYQ0KDQpFbCBlc3R1ZGlvIHNlIGRlc2Fycm9sbMOzIGJham8gdW4gZW5mb3F1ZSBkZWwgYXByZW5kaXphamUgc3VwZXJ2aXNhZG8gb3JpZW50YWRvIGhhY2lhIGxhIGNsYXNpZmljYWNpw7NuIGJpbmFyaWEgZGUgcGFjaWVudGVzIHBlcnRlbmVjaWVudGVzIGEgbGEgYmFzZSBkZSBkYXRvcyBQaW1hIEluZGlhbnMgRGlhYmV0ZXMgRGF0YWJhc2UsIGNvbiBlbCBvYmpldGl2byBkZSBwcmVkZWNpciBsYSBwcmVzZW5jaWEgbyBhdXNlbmNpYSBkZSBkaWFiZXRlcy4gUGFyYSBlc28sIHNlIGltcGxlbWVudMOzIGxhIGNvbXBhcmFjacOzbiBkZSBkb3MgbW9kZWxvcyBkZSBjbGFzaWZpY2FjacOzbjogKksgVmVjaW5vcyBtw6FzIFByw7N4aW1vcyAoS05OKSogeSAqUmVncmVzacOzbiBMb2fDrXN0aWNhIChMb2dpdCkqLiBMYSBtZXRvZG9sb2fDrWEgZXZpZGVuY2lhIGxhcyBkaWZlcmVudGVzIGV0YXBhcyByZWxhY2lvbmFkYXMgY29uIGxhIHNlbGVjY2nDs24gZGUgbGFzIHZhcmlhYmxlcywgY29tcGFyYWJpbGlkYWQgZGUgbG9zIHJlc3VsdGFkb3MsIHBhcnRpY2nDs24gZGUgZGF0b3MgeSB2YWxpZGV6Lg0KDQojIyAyLjEgUHJlcGFyYWNpw7NuIGRlIGxhIGJhc2UgZGUgZGF0b3MNCg0KRGUgYWN1ZXJkbyBjb24gbGEgaW5mb3JtYWNpw7NuLCBzZSByZWFsaXrDsyB1biBwcm9jZXNvIGRlIHNlbGVjY2nDs24gcGFyYSBlc2NvZ2VyIGxhcyB2YXJpYWJsZXMgcXVlIG3DoXMgc2UgYWp1c3RlbiBwYXJhIGVsIGFuw6FsaXNpcyBwcmVkaWN0aXZvLCBkZSBsYXMgY3VhbGVzIHNlIHByZXNlcnZhcm9uICgqR2x1Y29zZSwgQk1JLCBBZ2UsIEJsb29kUHJlc3N1cmUgeSBEaWFiZXRlc1BlZGlncmVlRnVuY3Rpb24qKSBjb21vIHZhcmlhYmxlcyBleHBsaWNhdGl2YXMsIGluY2x1aWRvIGVsIE91dGNvbWUgY29tbyB2YXJpYWJsZSBjYXRlZ8OzcmljYS4NCg0KU2UgZXhjbHV5ZXJvbiB2YWxvcmVzIGZhbHRhbnRlcyBlbiBsYXMgdmFyaWFibGVzIGVzY29naWRhcywgcGFyYSBwb2RlciB0cmFiYWphciBjb24gbGFzIG5lY2VzYXJpYXMgcGFyYSBlbCBhbsOhbGlzaXMuIERlIGVzYSBmb3JtYSwgc2Ugb3JnYW5pemFyb24gbG9zIGRhdG9zIGRlIG1hbmVyYSBlZmljaWVudGUgZW4gbGFzIGV0YXBhcyBwb3N0ZXJpb3JlcyBkZSBhbsOhbGlzaXMgZGVzY3JpcHRpdm8sIGVudHJlbmFtaWVudG8geSBldmFsdWFjacOzbiBkZSBtb2RlbG9zLiBTZSB2ZXJpZmljw7MgcXVlIGxhIGJhc2Ugbm8gcHJlc2VudGFyYSB2YWxvcmVzIGZhbHRhbnRlcywgY29uZmlybWFuZG8gcXVlIGxhcyAqNzY4IG9ic2VydmFjaW9uZXMqIGVzdGFiYW4gY29tcGxldGFzIHBhcmEgZWwgYW7DoWxpc2lzLg0KDQpBZGljaW9uYWxtZW50ZSwgbGFzIHZhcmlhYmxlcyBudW3DqXJpY2FzIGZ1ZXJvbiBlc3RhbmRhcml6YWRhcyBtZWRpYW50ZSBsYSBmdW5jacOzbiBgc2NhbGUoKWAgcGFyYSBnYXJhbnRpemFyIHF1ZSB0b2RhcyB0dXZpZXJhbiBsYSBtaXNtYSBlc2NhbGEsIGV2aXRhbmRvIHF1ZSBlbCBtb2RlbG8gS05OIGZhdm9yZXpjYSBsYXMgdmFyaWFibGVzIGNvbiB2YWxvcmVzIG3DoXMgZ3JhbmRlcy4NCg0KYGBge3IgbGlicmVyaWFzLWRhdG9zfQ0KIyBMaWJyZXLDrWFzIG5lY2VzYXJpYXMNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoY2xhc3MpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShST0NSKQ0KbGlicmFyeShwUk9DKQ0KDQojIENhcmdhIGRlIGRhdG9zDQpkaWFiZXRlcyA8LSByZWFkX2NzdigiZGlhYmV0ZXMuY3N2IikNCg0KIyBTZWxlY2Npw7NuIGRlIHZhcmlhYmxlcyByZWxldmFudGVzDQpkaWFiZXRlc19udWV2YSA8LSBkaWFiZXRlcyAlPiUNCiAgc2VsZWN0KEdsdWNvc2UsIEJNSSwgQWdlLCBCbG9vZFByZXNzdXJlLCBEaWFiZXRlc1BlZGlncmVlRnVuY3Rpb24sIE91dGNvbWUpDQoNCiMgTGltcGllemE6IGVsaW1pbmFyIGZpbGFzIGNvbiBOQSBlbiBjdWFscXVpZXIgdmFyaWFibGUgZGUgaW50ZXLDqXMNCmJhc2VfbGltcGlhIDwtIGRpYWJldGVzX251ZXZhICU+JQ0KICBmaWx0ZXIoDQogICAgIWlzLm5hKEdsdWNvc2UpLCAhaXMubmEoQk1JKSwgIWlzLm5hKEFnZSksDQogICAgIWlzLm5hKEJsb29kUHJlc3N1cmUpLCAhaXMubmEoRGlhYmV0ZXNQZWRpZ3JlZUZ1bmN0aW9uKSwgIWlzLm5hKE91dGNvbWUpDQogICkNCg0KIyBQYXJ0aWNpw7NuIHVuaWZpY2FkYSA3MC8zMCBlc3RyYXRpZmljYWRhIChtaXNtYSBwYXJhIEtOTiB5IExvZ2l0KQ0Kc2V0LnNlZWQoMjgpDQppbmRpY2VzX2VudHJlbmFtaWVudG8gPC0gY3JlYXRlRGF0YVBhcnRpdGlvbigNCiAgeSAgICA9IGJhc2VfbGltcGlhJE91dGNvbWUsDQogIHAgICAgPSAwLjcsDQogIGxpc3QgPSBGQUxTRQ0KKQ0KDQp0cmFpbl9vcmlnaW5hbCA8LSBiYXNlX2xpbXBpYVtpbmRpY2VzX2VudHJlbmFtaWVudG8sIF0NCnRlc3Rfb3JpZ2luYWwgIDwtIGJhc2VfbGltcGlhWy1pbmRpY2VzX2VudHJlbmFtaWVudG8sIF0NCg0KY2F0KCJUb3RhbCBkZSBvYnNlcnZhY2lvbmVzOiIsIG5yb3coYmFzZV9saW1waWEpLCAiXG4iKQ0KY2F0KCJFbnRyZW5hbWllbnRvICg3MCUpOiIsIG5yb3codHJhaW5fb3JpZ2luYWwpLCAiXG4iKQ0KY2F0KCJQcnVlYmEgKDMwJSk6ICAgICAgICIsIG5yb3codGVzdF9vcmlnaW5hbCksICAiXG4iKQ0KYGBgDQoNCiMjIDIuMiBQYXJ0aWNpw7NuIGRlIGRhdG9zDQoNClNlIHV0aWxpesOzIHVuYSBwYXJ0aWNpw7NuICoqNzAlIGVudHJlbmFtaWVudG8gLyAzMCUgcHJ1ZWJhKiogYXBsaWNhZGEgc29icmUgbGEgYmFzZSBjb21wbGV0YSBsaW1waWEgZGUgNzY4IG9ic2VydmFjaW9uZXMsIG1lZGlhbnRlIGBjcmVhdGVEYXRhUGFydGl0aW9uKClgIGRlbCBwYXF1ZXRlIGBjYXJldGAuIEVzdGEgZnVuY2nDs24gZ2FyYW50aXphIHF1ZSBsYSBwcm9wb3JjacOzbiBkZSBwYWNpZW50ZXMgY29uIHkgc2luIGRpYWJldGVzIHNlIG1hbnRlbmdhIGlndWFsIGVuIGFtYm9zIGNvbmp1bnRvcyAocGFydGljacOzbiBlc3RyYXRpZmljYWRhKSwgbG8gcXVlIGV2aXRhIHF1ZSBlbCBtb2RlbG8gZW50cmVuZSBjb24gdW5hIGRpc3RyaWJ1Y2nDs24gZGlzdGludGEgYSBsYSBxdWUgdmEgYSBwcmVkZWNpci4gTGEgbWlzbWEgcGFydGljacOzbiBmdWUgdXRpbGl6YWRhIHBhcmEgYW1ib3MgbW9kZWxvcyAoS05OIHkgTG9naXQpLCBhc2VndXJhbmRvIHF1ZSBsYXMgbcOpdHJpY2FzIHNlYW4gY29tcGFyYWJsZXMgc29icmUgZXhhY3RhbWVudGUgZWwgbWlzbW8gY29uanVudG8gZGUgcHJ1ZWJhLg0KDQojIyAyLjMgRGVmaW5pY2nDs24gZGUgdmFyaWFibGVzDQoNCiMjIyAyLjMuMSBWYXJpYWJsZSBkZSBjbGFzaWZpY2FjacOzbg0KDQpMYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSBjb3JyZXNwb25kZSBhICpPdXRjb21lKiwgY29kaWZpY2FkYSBkZSBmb3JtYSBiaW5hcmlhIGNvbiBkb3Mgbml2ZWxlczogKiJTw60iKiBwYXJhIGxvcyBwYWNpZW50ZXMgcG9zaXRpdm9zIGVuIGRpYWJldGVzIHkgKiJObyIqIHBhcmEgbGFzIHBhY2llbnRlcyBzaW4gZGlhZ27Ds3N0aWNvLiBBbCBzZXIgZGUgc29sbyBkb3MgcG9zaWJsZXMgcmVzcHVlc3RhcywgY29ycmVzcG9uZGUgYSB1bmEgY2xhc2lmaWNhY2nDs24gYmluYXJpYSBzdXBlcnZpc2FkYSwgY3V5byBvYmpldGl2byBjZW50cmFsIGVzIHF1ZSBsb3MgbW9kZWxvcyBkaWZlcmVuY2llbiBlbnRyZSBhbWJvcyBncnVwb3MgYSBwYXJ0aXIgZGUgbGFzIGNhcmFjdGVyw61zdGljYXMgY2zDrW5pY2FzIGRlIGNhZGEgcGFjaWVudGUuDQoNCiMjIyAyLjMuMiBWYXJpYWJsZXMgaW5kZXBlbmRpZW50ZXMNCg0KU2Ugc2VsZWNjaW9uYXJvbiA1IGRlIGxhcyA4IHZhcmlhYmxlcyBkaXNwb25pYmxlcyBlbiBsYSBiYXNlIGRlIGRhdG9zLiBFc3RhIHNlbGVjY2nDs24gc2UgaW5zcGlyw7MgZW4gaW52ZXN0aWdhY2lvbmVzIHByZXZpYXMgcXVlIGRldGVybWluYXJvbiBxdWUgbGEgZ2x1Y29zYSwgbGEgZWRhZCB5IGVsIMOtbmRpY2UgZGUgbWFzYSBjb3Jwb3JhbCBzb24gdmFyaWFibGVzIGNsYXZlIChKb3NoaSAmIERoYWthbCwgMjAyMSkuDQoNCnwgVmFyaWFibGUgfCBKdXN0aWZpY2FjacOzbiB8DQp8LS0tfC0tLXwNCnwgKipHbHVjb3NlKiogfCBJbmRpY2Fkb3IgcHJpbmNpcGFsIGRlIGRpYWduw7NzdGljbzsgbml2ZWxlcyBlbGV2YWRvcyBlc3TDoW4gZGlyZWN0YW1lbnRlIGFzb2NpYWRvcyBjb24gbGEgcmVzcHVlc3RhIGEgbGEgaW5zdWxpbmEgeSBsYSBkaWFiZXRlcyAoSm9zaGkgJiBEaGFrYWwsIDIwMjEpIHwNCnwgKipCTUkqKiB8IEVsIHNvYnJlcGVzbyBkaWZpY3VsdGEgbGEgY2FwdGFjacOzbiBkZSBnbHVjb3NhIGNlbHVsYXIsIGF1bWVudGFuZG8gZWwgcmllc2dvIGRlIGRpYWJldGVzIChMYWd1bmVzIFRvcnJlcywgMjAyMykgfA0KfCAqKkFnZSoqIHwgQSBtYXlvciBlZGFkLCBtYXlvcmVzIGNhbWJpb3MgbWV0YWLDs2xpY29zIHkgbWVub3Igc2Vuc2liaWxpZGFkIGEgbGEgaW5zdWxpbmEgKENEQywgMjAyNCkgfA0KfCAqKkJsb29kUHJlc3N1cmUqKiB8IExhIGhpcGVydGVuc2nDs24geSBsYSBkaWFiZXRlcyBjb2V4aXN0ZW4gZnJlY3VlbnRlbWVudGU7IGxhIHJlc2lzdGVuY2lhIGEgbGEgaW5zdWxpbmEgcHVlZGUgY2F1c2FyIGhpcGVydGVuc2nDs24gKFNhbXBhbmlzICYgWmFtYm91bGlzLCAyMDA4KSB8DQp8ICoqRGlhYmV0ZXNQZWRpZ3JlZUZ1bmN0aW9uKiogfCBMb3MgYW50ZWNlZGVudGVzIGZhbWlsaWFyZXMgYXVtZW50YW4gaGFzdGEgMyB2ZWNlcyBlbCByaWVzZ28gZGUgZGlhYmV0ZXMuIFNpIGFtYm9zIHByb2dlbml0b3JlcyBsYSBwYWRlY2VuLCBsYSBwcm9iYWJpbGlkYWQgYXNjaWVuZGUgYWwgNzAlIChPTVMsIGNpdGFkbyBlbiBSZXZpc3RhIERpYWJldGVzLCAyMDI0KSB8DQoNCiMjIyAyLjQuMSBNb2RlbG8gS05ODQoNCkVsIG1vZGVsbyBLTk4gZXMgdW5hIHTDqWNuaWNhIGRlIGFwcmVuZGl6YWplIHN1cGVydmlzYWRvIG5vIHBhcmFtw6l0cmljYSB1dGlsaXphZGEgcGFyYSBjbGFzaWZpY2FjacOzbiwgcXVlIGZ1bmNpb25hIGlkZW50aWZpY2FuZG8gbG9zICJLIiBjYXNvcyBtw6FzIHNpbWlsYXJlcyBhIHVuYSBudWV2YSBvYnNlcnZhY2nDs24gZGVudHJvIGRlbCBjb25qdW50byBkZSBlbnRyZW5hbWllbnRvIHkgYXNpZ25hbmRvIGxhIGNhdGVnb3LDrWEgcHJlZG9taW5hbnRlIGVudHJlIGVzb3MgdmVjaW5vcy4gRW4gZXN0ZSBlc3R1ZGlvLCBzZSB1dGlsaXrDsyBwYXJhIHByZWRlY2lyIGxhIHByZXNlbmNpYSBkZSBkaWFiZXRlcyBhIHBhcnRpciBkZSBsYXMgY2luY28gdmFyaWFibGVzIHNlbGVjY2lvbmFkYXMuDQoNClBhcmEgZGV0ZXJtaW5hciBsYSBzaW1pbGl0dWQgZW50cmUgcGFjaWVudGVzLCBlbCBtb2RlbG8gdXPDsyBtZWRpZGFzIGRlIGRpc3RhbmNpYSBjb25zaWRlcmFuZG8gbGFzIHZhcmlhYmxlcyBwcmVkaWN0b3Jhcy4gTHVlZ28sIHNlIGV2YWx1YXJvbiBkaXN0aW50b3MgdmFsb3JlcyBkZSBLIGNvbiBlbCBmaW4gZGUgc2VsZWNjaW9uYXIgbGEgY29uZmlndXJhY2nDs24gcXVlIG9mcmVjaWVyYSBlbCBtZWpvciBkZXNlbXBlw7FvIHByZWRpY3Rpdm8sIGJ1c2NhbmRvIHVuIGVxdWlsaWJyaW8gZW50cmUgc2Vuc2liaWxpZGFkIHkgZXN0YWJpbGlkYWQuIEtOTiByZXByZXNlbnRhIHVuIGVuZm9xdWUgZmxleGlibGUsIHlhIHF1ZSBubyBhc3VtZSByZWxhY2lvbmVzIGxpbmVhbGVzIGVudHJlIHZhcmlhYmxlcy4NCg0KIyMjIDIuNC4yIE1vZGVsbyBkZSBSZWdyZXNpw7NuIExvZ8Otc3RpY2EgKExvZ2l0KQ0KDQpMYSByZWdyZXNpw7NuIGxvZ8Otc3RpY2EgZXMgdW4gbW9kZWxvIGRlIGFwcmVuZGl6YWplIHN1cGVydmlzYWRvIHV0aWxpemFkbyBwYXJhIHByb2JsZW1hcyBkZSBjbGFzaWZpY2FjacOzbiBiaW5hcmlhLCBxdWUgcGVybWl0ZSBlc3RpbWFyIGxhIHByb2JhYmlsaWRhZCBkZSBvY3VycmVuY2lhIGRlIHVuIGV2ZW50byBhIHBhcnRpciBkZSBtw7psdGlwbGVzIHZhcmlhYmxlcyBpbmRlcGVuZGllbnRlcy4gRW4gZXN0YSBpbnZlc3RpZ2FjacOzbiwgc2UgYXBsaWPDsyBwYXJhIGNhbGN1bGFyIGxhIHByb2JhYmlsaWRhZCBkZSBxdWUgdW5hIHBhY2llbnRlIHByZXNlbnRlIGRpYWJldGVzIHV0aWxpemFuZG8gbGFzIG1pc21hcyB2YXJpYWJsZXMgc2VsZWNjaW9uYWRhcyBwYXJhIEtOTi4NCg0KRWwgbW9kZWxvIExvZ2l0IHV0aWxpemEgdW5hIGZ1bmNpw7NuIGxvZ8Otc3RpY2EgcGFyYSB0cmFuc2Zvcm1hciBsYXMgdmFyaWFibGVzIHByZWRpY3RvcmFzIGVuIHByb2JhYmlsaWRhZGVzIGVudHJlIDAgeSAxLCBwZXJtaXRpZW5kbyBjbGFzaWZpY2FyIHBhY2llbnRlcyBlIGludGVycHJldGFyIGPDs21vIGNhZGEgdmFyaWFibGUgaW5mbHV5ZSBlbiBlbCByaWVzZ28gZGUgZGlhYmV0ZXMuIEEgZGlmZXJlbmNpYSBkZWwgbW9kZWxvIEtOTiwgbGEgcmVncmVzacOzbiBsb2fDrXN0aWNhIG9mcmVjZSB1bmEgdmVudGFqYSBtZXRvZG9sw7NnaWNhIGltcG9ydGFudGUgYWwgcGVybWl0aXIgaW50ZXJwcmV0YXIgY8OzbW8gY2FkYSB2YXJpYWJsZSBpbmZsdXllIHNvYnJlIGxhIHByb2JhYmlsaWRhZCBkZSBkZXNhcnJvbGxhciBkaWFiZXRlcywgZmFjaWxpdGFuZG8gdW5hIGNvbXByZW5zacOzbiBtw6FzIGVzdHJ1Y3R1cmFkYSBkZWwgZmVuw7NtZW5vIGVzdHVkaWFkby4NCg0KLS0tDQoNCiMgMy4gQW7DoWxpc2lzIERlc2NyaXB0aXZvDQoNCmBgYHtyIGRhdG9zLWRlc2NyaXB0aXZvLCBpbmNsdWRlPUZBTFNFfQ0KIyBGcmVjdWVuY2lhcyBwYXJhIHVzYXIgZW4gZWwgdGV4dG8gZGluw6FtaWNvDQpmcmVxX3RhYmxhIDwtIHRhYmxlKGRpYWJldGVzX251ZXZhJE91dGNvbWUpDQpuX25vICAgICAgIDwtIGFzLmludGVnZXIoZnJlcV90YWJsYVsiMCJdKQ0Kbl9zaSAgICAgICA8LSBhcy5pbnRlZ2VyKGZyZXFfdGFibGFbIjEiXSkNCm5fdG90YWwgICAgPC0gbl9ubyArIG5fc2kNCnBjdF9ubyAgICAgPC0gcm91bmQobl9ubyAvIG5fdG90YWwgKiAxMDAsIDEpDQpwY3Rfc2kgICAgIDwtIHJvdW5kKG5fc2kgLyBuX3RvdGFsICogMTAwLCAxKQ0KYGBgDQoNCiMjIDMuMSBWYXJpYWJsZSBkZSBDbGFzaWZpY2FjacOzbg0KDQpMYSB2YXJpYWJsZSBkZSBjbGFzaWZpY2FjacOzbiBzZSBlbmN1ZW50cmEgbm9tYnJhZGEgY29tbyAqT3V0Y29tZSouIEVuIGxhIGJhc2UgZGUgZGF0b3Mgc2UgZW5jb250cmFyb24gYHIgbl90b3RhbGAgb2JzZXJ2YWNpb25lcywgZGUgbGFzIGN1YWxlcyBgciBuX25vYCBwYWNpZW50ZXMgKGByIHBjdF9ub2AlKSBjb3JyZXNwb25kZW4gYSBsb3MgcXVlIG5vIHRpZW5lbiBkaWFiZXRlcyB5IGByIG5fc2lgIHBhY2llbnRlcyAoYHIgcGN0X3NpYCUpIHNvbiBsb3MgcXVlIHRpZW5lbiBkaWFiZXRlcy4gRW4gb3RyYXMgcGFsYWJyYXMsIDIgZGUgY2FkYSAzIHBhY2llbnRlcyBwZXJ0ZW5lY2VuIGFsIGdydXBvIHF1ZSBubyB0aWVuZSBkaWFiZXRlcyB5IDEgZGUgY2FkYSAzIHPDrSB0aWVuZSBkaWFiZXRlcy4NCg0KRXN0ZSByZXN1bHRhZG8gZGVtdWVzdHJhIHF1ZSBsYXMgcGFjaWVudGVzIHNpbiBkaWFiZXRlcyB0aWVuZW4gbGEgbWF5b3IgcHJvcG9yY2nDs24gZGUgZGF0b3MuIEVzdGEgZGlzdHJpYnVjacOzbiBlcyBpbXBvcnRhbnRlIHBvcnF1ZSBhbCB1c2FyIGxvcyBtb2RlbG9zIGRlIGNsYXNpZmljYWNpw7NuIGNvbW8gS05OIG8gTG9naXQsIGVsIGFsZ29yaXRtbyBwb2Ryw61hIHRlbmVyIG1heW9yIHRlbmRlbmNpYSBhIHByZWRlY2lyIGxhIGNhdGVnb3LDrWEgbWF5b3JpdGFyaWEsIGFzcGVjdG8gcXVlIGRlYmUgY29uc2lkZXJhcnNlIGFsIGludGVycHJldGFyIGxhcyBtw6l0cmljYXMuDQoNCmBgYHtyIGdyYWZpY28tb3V0Y29tZSwgZmlnLmhlaWdodD00LjV9DQpkaWFiZXRlc19udWV2YSAlPiUNCiAgbXV0YXRlKERpYWdub3N0aWNvID0gaWZlbHNlKE91dGNvbWUgPT0gMSwgIlPDrSB0aWVuZSBkaWFiZXRlcyIsICJObyB0aWVuZSBkaWFiZXRlcyIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gRGlhZ25vc3RpY28sIGZpbGwgPSBEaWFnbm9zdGljbykpICsNCiAgZ2VvbV9iYXIod2lkdGggPSAwLjUyLCBjb2xvciA9ICJ3aGl0ZSIsIGxpbmV3aWR0aCA9IDAuNSkgKw0KICBnZW9tX3RleHQoDQogICAgc3RhdCAgPSAiY291bnQiLA0KICAgIGFlcyhsYWJlbCA9IHBhc3RlMChhZnRlcl9zdGF0KGNvdW50KSwgIlxuKCIsDQogICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKGFmdGVyX3N0YXQoY291bnQpIC8gbl90b3RhbCAqIDEwMCwgMSksICIlKSIpKSwNCiAgICB2anVzdCA9IC0wLjQsIGZvbnRmYWNlID0gImJvbGQiLCBzaXplID0gNC44DQogICkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJTw60gdGllbmUgZGlhYmV0ZXMiID0gY29sX3NpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJObyB0aWVuZSBkaWFiZXRlcyIgPSBjb2xfbm8pKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDYyMCkpICsNCiAgbGFicygNCiAgICB0aXRsZSAgICA9ICJEaXN0cmlidWNpw7NuIGRlbCBkaWFnbsOzc3RpY28gZGUgZGlhYmV0ZXMiLA0KICAgIHN1YnRpdGxlID0gIkJhc2UgZGUgZGF0b3MgUGltYSBJbmRpYW5zIChuID0gNzY4KSIsDQogICAgeCA9IE5VTEwsIHkgPSAiTsO6bWVybyBkZSBwYWNpZW50ZXMiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEzKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICBwbG90LnRpdGxlICAgICAgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiIzJjM2U1MCIpLA0KICAgIHBsb3Quc3VidGl0bGUgICA9IGVsZW1lbnRfdGV4dChjb2xvciA9IGNvbF9uZXUpDQogICkNCmBgYA0KDQojIyAzLjIgQW7DoWxpc2lzIGRlc2NyaXB0aXZvIGRlIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzDQoNClNlIHJlYWxpesOzIHVuIGFuw6FsaXNpcyBkZXNjcmlwdGl2byBkZSBsYXMgdmFyaWFibGVzIGN1YW50aXRhdGl2YXMgc29icmUgbWVkaWRhcyBkZSB0ZW5kZW5jaWEgY2VudHJhbCBjb21vIGxhIG1lZGlhIHkgbGEgbWVkaWFuYSwgYWwgaWd1YWwgcXVlIHZhbG9yZXMgZXh0cmVtb3MgeSBkaXN0cmlidWNpw7NuIGludGVybmEgZGUgbG9zIGRhdG9zLiBBIGNvbnRpbnVhY2nDs24gc2UgcHJlc2VudGEgZWwgcmVzdW1lbiBlc3RhZMOtc3RpY28gZGUgbGFzIGNpbmNvIHZhcmlhYmxlcyBzZWxlY2Npb25hZGFzLg0KDQpgYGB7ciByZXN1bWVuLWVzdGFkaXN0aWNvfQ0KIyBDT1JSRUNDScOTTjogc2UgZXhjbHV5ZSBPdXRjb21lIChmYWN0b3IpIGRlbCBzdW1tYXJ5IG51bcOpcmljbw0Kc3VtbWFyeShkaWFiZXRlc19udWV2YSAlPiUgc2VsZWN0KC1PdXRjb21lKSkNCmBgYA0KDQo8ZGl2IGNsYXNzPSJpbnRlcnByZXRhY2lvbiI+DQoqKkdsdWNvc2E6KiogcHJlc2VudGEgdW4gcmFuZ28gZW50cmUgMCB5IDE5OSwgY29uIG1lZGlhIGRlIDEyMC45IHkgbWVkaWFuYSBkZSAxMTcuIExhIHByb3hpbWlkYWQgZW50cmUgYW1iYXMgc3VnaWVyZSBkaXN0cmlidWNpw7NuIHJlbGF0aXZhbWVudGUgZXN0YWJsZSBlbiBsYSB6b25hIGNlbnRyYWw7IHNpbiBlbWJhcmdvLCBsYSBtZWRpYSBsZXZlbWVudGUgc3VwZXJpb3IgaW5kaWNhIHF1ZSBhbGd1bm9zIHZhbG9yZXMgYWx0b3MgZGVzcGxhemFuIGVsIHByb21lZGlvLiBFbCA1MCUgY2VudHJhbCBkZSBsYXMgcGFjaWVudGVzIHNlIGNvbmNlbnRyYSBlbnRyZSA5OSB5IDE0MC4yIG1nL2RMLg0KDQoqKkJNSToqKiB2YXLDrWEgZW50cmUgMCB5IDY3LjEwLCBjb24gbWVkaWEgeSBtZWRpYW5hIGNhc2kgaWTDqW50aWNhcyAofjMyKSwgaW5kaWNhbmRvIGVxdWlsaWJyaW8gZW4gbGEgZGlzdHJpYnVjacOzbiBjZW50cmFsLiBFbCByYW5nbyBpbnRlcmN1YXJ0w61saWNvICgyNy4zMOKAkzM2LjYwKSBtw6FzIGVzdHJlY2hvIHF1ZSBlbCBkZSBnbHVjb3NhIHJlZmxlamEgbWF5b3IgZXN0YWJpbGlkYWQgcmVsYXRpdmEuIExvcyB2YWxvcmVzIG3DoXhpbW9zIGVsZXZhZG9zIHBvZHLDrWFuIGluZGljYXIgY2Fzb3MgZXh0cmVtb3MgZGUgYWx0YSBtYXNhIGNvcnBvcmFsLg0KDQoqKkFnZToqKiBtZWRpYSBkZSAzMy4yNCBhw7FvcyB5IG1lZGlhbmEgZGUgMjksIGxvIHF1ZSBpbmRpY2EgY29uY2VudHJhY2nDs24gZW4gbGEgYWR1bHRleiBqb3Zlbi90ZW1wcmFuYS4gRWwgcmFuZ28gKDIx4oCTODEgYcOxb3MpIHJlZmxlamEgYW1wbGlhIGRpdmVyc2lkYWQgZ2VuZXJhY2lvbmFsLCBhdW5xdWUgbG9zIGN1YXJ0aWxlcyAoMjTigJM0MSBhw7FvcykgY29uZmlybWFuIHF1ZSBsYSBtYXlvciBjb25jZW50cmFjacOzbiBlcyBlbiBhZHVsdG9zIGrDs3ZlbmVzLg0KDQoqKkJsb29kUHJlc3N1cmU6KiogbWVkaWEgZGUgNjkuMTEgeSBtZWRpYW5hIGRlIDcyLiBFbCA1MCUgY2VudHJhbCBzZSBlbmN1ZW50cmEgZW50cmUgNjIgeSA4MCBtbUhnLCBjb21wb3J0YW1pZW50byBlc3RhYmxlIGRlbnRybyBkZSByYW5nb3MgY29uc2lkZXJhZG9zIG1vZGVyYWRvcyAo4omkIDEyMC84MCBtbUhnKS4gU2UgcHJlc2VudGFuIHZhbG9yZXMgIjAiIHF1ZSBwb2Ryw61hbiByZXByZXNlbnRhciBkYXRvcyBmYWx0YW50ZXMuDQoNCioqRGlhYmV0ZXNQZWRpZ3JlZUZ1bmN0aW9uOioqIG1lZGlhIGRlIDAuNDcxOSB5IG1lZGlhbmEgZGUgMC4zNzI1LiBMYSBtZWRpYSBzdXBlcmlvciBhIGxhIG1lZGlhbmEgaW5kaWNhIGRpc3RyaWJ1Y2nDs24gaW5jbGluYWRhIGhhY2lhIHZhbG9yZXMgc3VwZXJpb3JlcywgZ2VuZXJhZGEgcG9yIHBhY2llbnRlcyBjb24gYW50ZWNlZGVudGVzIGhlcmVkaXRhcmlvcyBtw6FzIGFsdG9zLiBFbCByYW5nbyBpbnRlcmN1YXJ0w61saWNvICgwLjI04oCTMC42MykgbXVlc3RyYSBxdWUgbGEgbWF5b3LDrWEgc2UgY29uY2VudHJhIGVuIG5pdmVsZXMgbW9kZXJhZG9zLg0KPC9kaXY+DQoNCiMjIDMuMyBEaXN0cmlidWNpw7NuIGluZGl2aWR1YWwgZGUgdmFyaWFibGVzIG51bcOpcmljYXMNCg0KTGFzIHNpZ3VpZW50ZXMgZ3LDoWZpY2FzIG11ZXN0cmFuIGxhIGRpc3RyaWJ1Y2nDs24gZGUgZnJlY3VlbmNpYXMgZGUgY2FkYSB2YXJpYWJsZSBleHBsaWNhdGl2YS4gU3UgYW7DoWxpc2lzIHBlcm1pdGUgaWRlbnRpZmljYXIgbGEgZm9ybWEgZGUgbGEgZGlzdHJpYnVjacOzbiwgbGEgcHJlc2VuY2lhIGRlIGFzaW1ldHLDrWFzIHkgcG9zaWJsZXMgdmFsb3JlcyBhdMOtcGljb3MgYW50ZXMgZGUgY29uc3RydWlyIGxvcyBtb2RlbG9zLg0KDQpgYGB7ciBoaXN0b2dyYW1hcywgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9MTB9DQpkaWFiZXRlc19sYXJnYSA8LSBkaWFiZXRlc19udWV2YSAlPiUNCiAgc2VsZWN0KC1PdXRjb21lKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAiVmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAiVmFsb3IiKSAlPiUNCiAgbXV0YXRlKFZhcmlhYmxlID0gcmVjb2RlKFZhcmlhYmxlLA0KICAgIEdsdWNvc2UgICAgICAgICAgICAgICAgICA9ICJHbHVjb3NhIiwNCiAgICBCTUkgICAgICAgICAgICAgICAgICAgICAgPSAiw41uZGljZSBkZSBNYXNhIENvcnBvcmFsIChCTUkpIiwNCiAgICBBZ2UgICAgICAgICAgICAgICAgICAgICAgPSAiRWRhZCIsDQogICAgQmxvb2RQcmVzc3VyZSAgICAgICAgICAgID0gIlByZXNpw7NuIEFydGVyaWFsIiwNCiAgICBEaWFiZXRlc1BlZGlncmVlRnVuY3Rpb24gPSAiUHJlZGlzcG9zaWNpw7NuIEZhbWlsaWFyIg0KICApKQ0KDQpjb2xvcmVzX2hpc3QgPC0gYygNCiAgIkdsdWNvc2EiICAgICAgICAgICAgICAgICAgICAgICAgPSAiIzI5ODBCOSIsDQogICLDjW5kaWNlIGRlIE1hc2EgQ29ycG9yYWwgKEJNSSkiICA9ICIjRTc0QzNDIiwNCiAgIkVkYWQiICAgICAgICAgICAgICAgICAgICAgICAgICAgPSAiIzhFNDRBRCIsDQogICJQcmVzacOzbiBBcnRlcmlhbCIgICAgICAgICAgICAgICA9ICIjRjM5QzEyIiwNCiAgIlByZWRpc3Bvc2ljacOzbiBGYW1pbGlhciIgICAgICAgID0gIiMyN0FFNjAiDQopDQoNCmdncGxvdChkaWFiZXRlc19sYXJnYSwgYWVzKHggPSBWYWxvciwgZmlsbCA9IFZhcmlhYmxlKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjgsIGFscGhhID0gMC44NSwgY29sb3IgPSAid2hpdGUiLCBsaW5ld2lkdGggPSAwLjMpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3Jlc19oaXN0KSArDQogIGZhY2V0X3dyYXAofiBWYXJpYWJsZSwgc2NhbGVzID0gImZyZWUiLCBuY29sID0gMikgKw0KICBsYWJzKA0KICAgIHRpdGxlICAgID0gIkRpc3RyaWJ1Y2nDs24gZGUgbGFzIHZhcmlhYmxlcyBleHBsaWNhdGl2YXMiLA0KICAgIHN1YnRpdGxlID0gIkJhc2UgZGUgZGF0b3MgUGltYSBJbmRpYW5zIChuID0gNzY4KSIsDQogICAgeCA9ICJWYWxvciIsIHkgPSAiRnJlY3VlbmNpYSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgIHN0cmlwLnRleHQgICAgICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBjb2xvciA9ICIjMmMzZTUwIiksDQogICAgcGxvdC50aXRsZSAgICAgID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gIiMyYzNlNTAiKSwNCiAgICBwbG90LnN1YnRpdGxlICAgPSBlbGVtZW50X3RleHQoY29sb3IgPSBjb2xfbmV1KQ0KICApDQpgYGANCg0KPGRpdiBjbGFzcz0iaW50ZXJwcmV0YWNpb24iPg0KKipEaXN0cmlidWNpw7NuIGRlIGxhIEdsdWNvc2E6Kiogc2Ugb2JzZXJ2YSB1bmEgY29uY2VudHJhY2nDs24gaW1wb3J0YW50ZSBlbiB2YWxvcmVzIGludGVybWVkaW9zIChjZXJjYW5vcyBhIDEwMOKAkzE0MCBtZy9kTCksIGNvbnNpc3RlbnRlIGNvbiBsYSBtZWRpYSB5IG1lZGlhbmEgaWRlbnRpZmljYWRhcy4gRWwgaGlzdG9ncmFtYSBtdWVzdHJhIHVuYSBsaWdlcmEgYXNpbWV0csOtYSBwb3NpdGl2YSwgY29uIGV4dGVuc2nDs24gaGFjaWEgdmFsb3JlcyBhbHRvcyBjZXJjYW5vcyBhIDIwMCwgYXNvY2lhZG9zIGEgbWF5b3Igcmllc2dvIGRlIGRpYWJldGVzLiBTZSBvYnNlcnZhbiB2YWxvcmVzIGNlcmNhbm9zIGEgY2VybyBxdWUgcG9kcsOtYW4gcmVwcmVzZW50YXIgZGF0b3MgZmFsdGFudGVzIG8gYXTDrXBpY29zLg0KDQoqKkRpc3RyaWJ1Y2nDs24gZGVsIEJNSToqKiBjb25jZW50cmFjacOzbiBwcmluY2lwYWwgZW50cmUgMjUgeSA0MCwgY29uIGZyZWN1ZW5jaWEgYWx0YSBlbiB2YWxvcmVzIGNlcmNhbm9zIGEgMzDigJMzNS4gRWwgaGlzdG9ncmFtYSBtdWVzdHJhIHVuIMO6bmljbyBwaWNvIHByaW5jaXBhbCwgbG8gcXVlIGluZGljYSBxdWUgbGEgbWF5b3LDrWEgcHJlc2VudGEgdW4gbml2ZWwgZGUgbWFzYSBob21vZ8OpbmVvLiBVbiBzdWJjb25qdW50byBtdXkgcmVkdWNpZG8gZGUgcGFjaWVudGVzIHByZXNlbnRhIHZhbG9yZXMgZWxldmFkb3MsIHBvc2libGVtZW50ZSBpbmRpY2FuZG8gb2Jlc2lkYWQgc2V2ZXJhLiBBbCBpZ3VhbCBxdWUgZW4gZ2x1Y29zYSwgaGF5IHZhbG9yZXMgY2VyY2Fub3MgYSAwIHF1ZSBwb2Ryw61hbiBjb3JyZXNwb25kZXIgYSBkYXRvcyBmYWx0YW50ZXMuDQoNCioqRGlzdHJpYnVjacOzbiBkZSBsYSBFZGFkOioqIG1heW9yIGNvbmNlbnRyYWNpw7NuIGVudHJlIGxvcyAyMCB5IDI1IGHDsW9zLiBMYSBkaXN0cmlidWNpw7NuIHByZXNlbnRhIHVuYSBhc2ltZXRyw61hIHBvc2l0aXZhIChzZXNnbyBhIGxhIGRlcmVjaGEpLCB5YSBxdWUgbGFzIGZyZWN1ZW5jaWFzIGRpc21pbnV5ZW4gYSBtZWRpZGEgcXVlIGF1bWVudGEgbGEgZWRhZC4gRXhpc3RlbiBwb2NvcyBwYWNpZW50ZXMgYWR1bHRvcyBtYXlvcmVzIGVuIGNvbXBhcmFjacOzbiBjb24gbG9zIHBhY2llbnRlcyBqw7N2ZW5lcy4NCg0KKipEaXN0cmlidWNpw7NuIGRlIGxhIFByZXNpw7NuIEFydGVyaWFsOioqIGNvbmNlbnRyYWNpw7NuIHByaW5jaXBhbCBlbnRyZSA2MCB5IDg1IG1tSGcsIGNvbiB1biBwaWNvIGNlcmNhbm8gYSA3MOKAkzgwIG1tSGcuIExhIGRpc3RyaWJ1Y2nDs24gcHJlc2VudGEgdW5hIGZvcm1hIGNlcmNhbmEgYSB1bmEgY2FtcGFuYSBjb24gbGlnZXJhIGFzaW1ldHLDrWEgcG9zaXRpdmEuIFNlIGV2aWRlbmNpYSBlbCB2YWxvciAiMCIsIHF1ZSBwdWVkZSByZXByZXNlbnRhciBkYXRvcyBmYWx0YW50ZXMuDQoNCioqRGlzdHJpYnVjacOzbiBkZWwgw41uZGljZSBkZSBQcmVkaXNwb3NpY2nDs246KiogbWF5b3IgY29uY2VudHJhY2nDs24gZW50cmUgMC4xIHkgMC42LiBMYSBkaXN0cmlidWNpw7NuIHByZXNlbnRhIHVuYSBtYXJjYWRhIGFzaW1ldHLDrWEgcG9zaXRpdmEsIHlhIHF1ZSBsYSBtYXlvciBwYXJ0ZSBkZSBsb3MgZGF0b3Mgc2UgY29uY2VudHJhIGVuIHZhbG9yZXMgYmFqb3MgeSBsYSBjb2xhIHNlIGV4dGllbmRlIGhhY2lhIGxhIGRlcmVjaGEgKHZhbG9yZXMgY2VyY2Fub3MgYSAyLjUpLiBFc3RhIHZhcmlhYmxlIG5vIHNpZ3VlIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbC4NCjwvZGl2Pg0KDQojIyAzLjQgUmVsYWNpw7NuIGVudHJlIGxhcyB2YXJpYWJsZXMgbnVtw6lyaWNhcyB5IGxhIGRpYWJldGVzDQoNCkxvcyBkaWFncmFtYXMgZGUgY2FqYSBwZXJtaXRlbiBvYnNlcnZhciBzaSBjYWRhIHZhcmlhYmxlIHByZXNlbnRhIGRpZmVyZW5jaWFzIGVudHJlIGVsIGdydXBvIGNvbiBkaWFiZXRlcyAoMSkgeSBzaW4gZGlhYmV0ZXMgKDApLCBsbyBjdWFsIGFudGljaXBhIHN1IGNhcGFjaWRhZCBkaXNjcmltaW5hdG9yaWEgZGVudHJvIGRlIGxvcyBtb2RlbG9zIGRlIGNsYXNpZmljYWNpw7NuLg0KDQpgYGB7ciBib3hwbG90cywgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KZGlhYmV0ZXNfYm94IDwtIGRpYWJldGVzX251ZXZhICU+JQ0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyAgICAgID0gYyhHbHVjb3NlLCBCTUksIEFnZSwgQmxvb2RQcmVzc3VyZSwgRGlhYmV0ZXNQZWRpZ3JlZUZ1bmN0aW9uKSwNCiAgICBuYW1lc190byAgPSAiVmFyaWFibGUiLA0KICAgIHZhbHVlc190byA9ICJWYWxvciINCiAgKSAlPiUNCiAgbXV0YXRlKA0KICAgIFZhcmlhYmxlID0gcmVjb2RlKFZhcmlhYmxlLA0KICAgICAgR2x1Y29zZSAgICAgICAgICAgICAgICAgID0gIkdsdWNvc2EiLA0KICAgICAgQk1JICAgICAgICAgICAgICAgICAgICAgID0gIsONbmRpY2UgZGUgTWFzYSBDb3Jwb3JhbCIsDQogICAgICBBZ2UgICAgICAgICAgICAgICAgICAgICAgPSAiRWRhZCIsDQogICAgICBCbG9vZFByZXNzdXJlICAgICAgICAgICAgPSAiUHJlc2nDs24gQXJ0ZXJpYWwiLA0KICAgICAgRGlhYmV0ZXNQZWRpZ3JlZUZ1bmN0aW9uID0gIlByZWRpc3Bvc2ljacOzbiBGYW1pbGlhciINCiAgICApLA0KICAgIERpYWdub3N0aWNvID0gaWZlbHNlKE91dGNvbWUgPT0gMSwgIkNvbiBkaWFiZXRlcyIsICJTaW4gZGlhYmV0ZXMiKQ0KICApDQoNCmdncGxvdChkaWFiZXRlc19ib3gsIGFlcyh4ID0gRGlhZ25vc3RpY28sIHkgPSBWYWxvciwgZmlsbCA9IERpYWdub3N0aWNvKSkgKw0KICBnZW9tX2JveHBsb3QoDQogICAgYWxwaGEgICAgICAgICA9IDAuOCwNCiAgICBvdXRsaWVyLnNoYXBlID0gMjEsDQogICAgb3V0bGllci5zaXplICA9IDEuNSwNCiAgICBvdXRsaWVyLmZpbGwgID0gIndoaXRlIiwNCiAgICBvdXRsaWVyLmNvbG9yID0gImdyYXk1MCINCiAgKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkNvbiBkaWFiZXRlcyIgPSBjb2xfc2ksICJTaW4gZGlhYmV0ZXMiID0gY29sX25vKSkgKw0KICBmYWNldF93cmFwKH4gVmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlX3kiLCBuY29sID0gMikgKw0KICBsYWJzKA0KICAgIHRpdGxlICAgID0gIkRpc3RyaWJ1Y2nDs24gZGUgdmFyaWFibGVzIHBvciBncnVwbyBkZSBkaWFnbsOzc3RpY28iLA0KICAgIHN1YnRpdGxlID0gIkNvbXBhcmFjacOzbiBlbnRyZSBwYWNpZW50ZXMgY29uIHkgc2luIGRpYWJldGVzIiwNCiAgICB4ID0gTlVMTCwgeSA9ICJWYWxvciINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgIHN0cmlwLnRleHQgICAgICA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBjb2xvciA9ICIjMmMzZTUwIiksDQogICAgcGxvdC50aXRsZSAgICAgID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gIiMyYzNlNTAiKSwNCiAgICBwbG90LnN1YnRpdGxlICAgPSBlbGVtZW50X3RleHQoY29sb3IgPSBjb2xfbmV1KQ0KICApDQpgYGANCg0KPGRpdiBjbGFzcz0iaW50ZXJwcmV0YWNpb24iPg0KKipHbHVjb3NhIHNlZ8O6biBEaWFiZXRlczoqKiBsb3MgcGFjaWVudGVzIGRpYWdub3N0aWNhZG9zIGNvbiBkaWFiZXRlcyBwcmVzZW50YW4gbml2ZWxlcyBkZSBnbHVjb3NhIGNsYXJhbWVudGUgbcOhcyBlbGV2YWRvcy4gTGEgbWVkaWFuYSBkZWwgZ3J1cG8gZGlhYsOpdGljbyBlcyBtYXlvciwgbG8gcXVlIGluZGljYSBxdWUgYWwgbWVub3MgbGEgbWl0YWQgZGUgbGFzIHBlcnNvbmFzIGRpYWLDqXRpY2FzIHRpZW5lbiBuaXZlbGVzIGFsdG9zIGRlIGdsdWNvc2EgZW4gY29tcGFyYWNpw7NuIGNvbiBlbCBncnVwbyBzaW4gZGlhYmV0ZXMuIEVsIGdydXBvIGRpYWLDqXRpY28gdGFtYmnDqW4gbXVlc3RyYSBtYXlvciBkaXNwZXJzacOzbiAoY2FqYSBtw6FzIGFtcGxpYSB5IGJpZ290ZXMgbcOhcyBsYXJnb3MpLCBtaWVudHJhcyBxdWUgZWwgZ3J1cG8gc2luIGRpYWJldGVzIHByZXNlbnRhIHVuYSBkaXN0cmlidWNpw7NuIG3DoXMgY29uY2VudHJhZGEuIFNlIGV2aWRlbmNpYW4gdmFsb3JlcyBhdMOtcGljb3MgZW4gYW1ib3MgZ3J1cG9zLiBFc3RhIHZhcmlhYmxlIGVzIGxhIGRlIG1heW9yIGNhcGFjaWRhZCBkaXNjcmltaW5hdG9yaWEgZW4gZWwgZXN0dWRpbyAoTWVkbGluZVBsdXMsIHMuZi4pLg0KDQoqKkJNSSBzZWfDum4gRGlhYmV0ZXM6KiogbG9zIHBhY2llbnRlcyBjb24gZGlhYmV0ZXMgcHJlc2VudGFuIHZhbG9yZXMgZGUgQk1JIG3DoXMgZWxldmFkb3MuIExhIGNhamEgZGVsIGdydXBvIHNpbiBkaWFiZXRlcyBlcyBtw6FzIGFtcGxpYSAobWF5b3IgZGlzcGVyc2nDs24pLCBtaWVudHJhcyBxdWUgbGEgZGVsIGdydXBvIGNvbiBkaWFiZXRlcyBlcyBtw6FzIGVzdHJlY2hhICh2YWxvcmVzIG3DoXMgY29uY2VudHJhZG9zIGFscmVkZWRvciBkZSBsYSBtZWRpYW5hKS4gQW1ib3MgZ3J1cG9zIG11ZXN0cmFuIHZhbG9yZXMgYXTDrXBpY29zLCBpbmNsdXllbmRvIHVuIHZhbG9yIG3DoXhpbW8gZGUgNjcuMTAga2cvbcKyIHkgdmFsb3JlcyBjZXJjYW5vcyBhIDAuDQoNCioqRWRhZCBzZWfDum4gRGlhYmV0ZXM6KiogbGFzIHBhY2llbnRlcyBzaW4gZGlhYmV0ZXMgcHJlc2VudGFuIHVuYSBtZWRpYW5hIGRlIGFwcm94aW1hZGFtZW50ZSAyOSBhw7FvcywgY29uIHVuYSBjYWphIG3DoXMgZXN0cmVjaGEgeSBjb25jZW50cmFjacOzbiBlbiBwYWNpZW50ZXMgasOzdmVuZXMuIExhcyBwYWNpZW50ZXMgY29uIGRpYWJldGVzIG11ZXN0cmFuIHVuYSBtZWRpYW5hIHN1cGVyaW9yIGNlcmNhbmEgYSBsb3MgMzUgYcOxb3MsIGNvbiBtYXlvciB2YXJpYWNpw7NuLiBFbCBncnVwbyBzaW4gZGlhYmV0ZXMgcHJlc2VudGEgdmFyaW9zIHZhbG9yZXMgYXTDrXBpY29zIHBvciBlbmNpbWEgZGUgbG9zIDYwIGHDsW9zLCBsbGVnYW5kbyBoYXN0YSBsb3MgODEgYcOxb3MuIExhIGRpZmVyZW5jaWEgZW50cmUgbWVkaWFuYXMgY29uZmlybWEgcXVlIGxhIGVkYWQgdGllbmUgY2FwYWNpZGFkIGRpc2NyaW1pbmF0b3JpYSByZWxldmFudGUgcGFyYSBlbCBtb2RlbG8uDQoNCioqUHJlc2nDs24gQXJ0ZXJpYWwgc2Vnw7puIERpYWJldGVzOioqIGFtYm9zIGdydXBvcyBwcmVzZW50YW4gdW5hIGRpc3RyaWJ1Y2nDs24gbXV5IHNpbWlsYXIsIGNvbiBtZWRpYW5hcyBjZXJjYW5hcyBlbnRyZSBzw60gKH43MiB5IH43NSBtbUhnKS4gQW1ib3MgZ3J1cG9zIHRpZW5lbiB2YWxvcmVzIGF0w61waWNvcyBlbiBsb3MgZXh0cmVtb3MuIEVzdGEgdmFyaWFibGUgZXZpZGVuY2lhIHBvY2EgZGlmZXJlbmNpYSBlbnRyZSBncnVwb3MsIGxvIHF1ZSBsaW1pdGEgc3UgY2FwYWNpZGFkIGRpc2NyaW1pbmF0b3JpYSBpbmRpdmlkdWFsLg0KDQoqKlByZWRpc3Bvc2ljacOzbiBGYW1pbGlhciBzZWfDum4gRGlhYmV0ZXM6KiogbGFzIHBhY2llbnRlcyBzaW4gZGlhYmV0ZXMgcHJlc2VudGFuIHVuYSBtZWRpYW5hIGRlIGFwcm94aW1hZGFtZW50ZSAwLjM1LCBjb24gY2FqYSBtw6FzIGVzdHJlY2hhLiBMYXMgcGFjaWVudGVzIGNvbiBkaWFiZXRlcyBtdWVzdHJhbiB1bmEgbWVkaWFuYSBsaWdlcmFtZW50ZSBzdXBlcmlvciAofjAuNDgpIHkgbWF5b3IgdmFyaWFjacOzbi4gTGFzIHBhY2llbnRlcyBjb24gZGlhYmV0ZXMgdGllbmRlbiBhIHByZXNlbnRhciB1bmEgcHJlZGlzcG9zaWNpw7NuIGZhbWlsaWFyIGxpZ2VyYW1lbnRlIG3DoXMgYWx0YS4NCjwvZGl2Pg0KDQojIyAzLjUgRXN0YWTDrXN0aWNhcyBwb3IgR3J1cG8NCg0KYGBge3IgbWVkaWFzLWdydXBvfQ0KbWVkaWFfdmFyaWFibGVzIDwtIGRpYWJldGVzX251ZXZhICU+JQ0KICBncm91cF9ieShPdXRjb21lKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGBHbHVjb3NhYCAgICAgICAgICAgICA9IHJvdW5kKG1lYW4oR2x1Y29zZSksIDIpLA0KICAgIGBCTUlgICAgICAgICAgICAgICAgICA9IHJvdW5kKG1lYW4oQk1JKSwgMiksDQogICAgYEVkYWRgICAgICAgICAgICAgICAgID0gcm91bmQobWVhbihBZ2UpLCAyKSwNCiAgICBgUHJlc2nDs24gQXJ0ZXJpYWxgICAgID0gcm91bmQobWVhbihCbG9vZFByZXNzdXJlKSwgMiksDQogICAgYFByZWRpc3Bvc2ljacOzbiBGYW0uYCA9IHJvdW5kKG1lYW4oRGlhYmV0ZXNQZWRpZ3JlZUZ1bmN0aW9uKSwgNCkNCiAgKSAlPiUNCiAgbXV0YXRlKE91dGNvbWUgPSBpZmVsc2UoT3V0Y29tZSA9PSAxLCAiQ29uIGRpYWJldGVzIiwgIlNpbiBkaWFiZXRlcyIpKSAlPiUNCiAgcmVuYW1lKEdydXBvID0gT3V0Y29tZSkNCg0KbWVkaWFfdmFyaWFibGVzICU+JQ0KICBrYWJsZShjYXB0aW9uID0gIlRhYmxhIDEuIE1lZGlhcyBkZSBsYXMgdmFyaWFibGVzIGV4cGxpY2F0aXZhcyBwb3IgZ3J1cG8gZGUgZGlhZ27Ds3N0aWNvIikgJT4lDQogIGthYmxlX3N0eWxpbmcoDQogICAgZnVsbF93aWR0aCAgICAgICAgPSBGQUxTRSwNCiAgICBwb3NpdGlvbiAgICAgICAgICA9ICJjZW50ZXIiLA0KICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKQ0KICApICU+JQ0KICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiMyQzNFNTAiKSAlPiUNCiAgcm93X3NwZWMoMSwgYmFja2dyb3VuZCA9ICIjRkFEQkQ4IikgJT4lDQogIHJvd19zcGVjKDIsIGJhY2tncm91bmQgPSAiI0Q2RUFGOCIpDQpgYGANCg0KPGRpdiBjbGFzcz0icmVzdWx0YWRvLWNsYXZlIj4NCioqSW50ZXJwcmV0YWNpw7NuIGRlIGxhIHRhYmxhIGRlIG1lZGlhczoqKiBMYSB0YWJsYSBjb25maXJtYSBsYXMgZGlmZXJlbmNpYXMgb2JzZXJ2YWRhcyBlbiBsb3MgZGlhZ3JhbWFzIGRlIGNhamEuIExhcyBwYWNpZW50ZXMgY29uIGRpYWJldGVzIHByZXNlbnRhbiB2YWxvcmVzIHByb21lZGlvIG3DoXMgYWx0b3MgZW4gdG9kYXMgbGFzIHZhcmlhYmxlcy4NCg0KLSAqKkdsdWNvc2E6KiogZGlmZXJlbmNpYSBkZSB+MzEuMjggbWcvZEwgKDE0MS4yNiB2cyAxMDkuOTgpLiBFcyBsYSB2YXJpYWJsZSBjb24gbWF5b3IgcG9kZXIgZGlmZXJlbmNpYWRvciwgY29uZmlybWFuZG8gc3Ugcm9sIGNvbW8gZGV0ZXJtaW5hbnRlIHByaW5jaXBhbCBwYXJhIGVsIGFuw6FsaXNpcy4NCi0gKipCTUk6KiogZGlmZXJlbmNpYSBkZSB+My44NyBrZy9twrIgKDM1LjE0IHZzIDMwLjMwKS4gTGFzIHBhY2llbnRlcyBjb24gZGlhYmV0ZXMgcHJlc2VudGFuIG9iZXNpZGFkIG1vZGVyYWRhICg+MzApLCBtaWVudHJhcyBxdWUgbGFzIHNpbiBkaWFiZXRlcyBzZSBlbmN1ZW50cmFuIGVuIGVsIGzDrW1pdGUgKE9NUywgMjAyNSkuDQotICoqRWRhZDoqKiBkaWZlcmVuY2lhIGRlIH42IGHDsW9zICgzNy4wNyB2cyAzMS4xOSkuIENvbmZpcm1hIHF1ZSBsYXMgcGFjaWVudGVzIGRpYWLDqXRpY2FzIHRpZW5kZW4gYSBzZXIgbWF5b3Jlcy4NCi0gKipQcmVzacOzbiBhcnRlcmlhbCB5IHByZWRpc3Bvc2ljacOzbiBmYW1pbGlhcjoqKiBkaWZlcmVuY2lhcyBtw6FzIHBlcXVlw7FhcyAoMi42NCBtbUhnIHkgMC4xMiBwdW50b3MgcmVzcGVjdGl2YW1lbnRlKSwgY29oZXJlbnRlIGNvbiBsbyBvYnNlcnZhZG8gZW4gbG9zIGRpYWdyYW1hcyBkZSBjYWphLg0KDQpFbiBzw61udGVzaXMsIGxhIGdsdWNvc2EsIGVsIElNQyB5IGxhIGVkYWQgc29uIGxhcyB2YXJpYWJsZXMgY29uIG1heW9yIHBvZGVyIGRpZmVyZW5jaWFkb3IsIGxvIHF1ZSBhbnRpY2lwYSBxdWUgdGVuZHLDoW4gbWF5b3IgcGVzbyBlbiBsb3MgbW9kZWxvcyBkZSBjbGFzaWZpY2FjacOzbi4NCjwvZGl2Pg0KDQotLS0NCg0KIyA0LiBNb2RlbG9zIGRlIENsYXNpZmljYWNpw7NuDQoNCiMjIDQuMSBNb2RlbG8gS05ODQoNCiMjIyBQcmVwYXJhY2nDs24geSBlc3RhbmRhcml6YWNpw7NuDQoNCkRhZG8gcXVlIEtOTiBvcGVyYSBjb24gZGlzdGFuY2lhcyBldWNsaWRpYW5hcywgZXMgaW1wcmVzY2luZGlibGUgZXN0YW5kYXJpemFyIGxhcyB2YXJpYWJsZXMgcGFyYSBldml0YXIgcXVlIGFxdWVsbGFzIGNvbiBtYXlvciBlc2NhbGEgZG9taW5lbiBlbCBjw6FsY3VsbyBkZSBzaW1pbGl0dWQgZW50cmUgcGFjaWVudGVzLg0KDQpgYGB7ciBrbm4tcHJlcGFyYWNpb259DQojIFZhcmlhYmxlcyBhIGVzY2FsYXINCnZhcnNfcHJlZCA8LSBjKCJHbHVjb3NlIiwgIkJNSSIsICJBZ2UiLCAiQmxvb2RQcmVzc3VyZSIsICJEaWFiZXRlc1BlZGlncmVlRnVuY3Rpb24iKQ0KDQojIENhbGN1bGFyIG1lZGlhIHkgc2QgZGVsIGVudHJlbmFtaWVudG8gcGFyYSBlc2NhbGFyIGFtYm9zIGNvbmp1bnRvcyBjb24gbG9zIG1pc21vcyBwYXLDoW1ldHJvcw0KIyAoYnVlbmEgcHLDoWN0aWNhOiBlbCB0ZXN0IG51bmNhIGluZm9ybWEgbG9zIHBhcsOhbWV0cm9zIGRlIGVzY2FsYWRvKQ0KbWVkaWFzX3RyYWluIDwtIGNvbE1lYW5zKHRyYWluX29yaWdpbmFsWywgdmFyc19wcmVkXSkNCnNkc190cmFpbiAgICA8LSBhcHBseSh0cmFpbl9vcmlnaW5hbFssIHZhcnNfcHJlZF0sIDIsIHNkKQ0KDQplc2NhbGFyX2Nvbl90cmFpbiA8LSBmdW5jdGlvbihkZikgew0KICBkZl9lc2MgPC0gZGYNCiAgZm9yICh2IGluIHZhcnNfcHJlZCkgew0KICAgIGRmX2VzY1tbcGFzdGUwKHYsICJfZXNjIildXSA8LSAoZGZbW3ZdXSAtIG1lZGlhc190cmFpblt2XSkgLyBzZHNfdHJhaW5bdl0NCiAgfQ0KICBkZl9lc2MNCn0NCg0Ka25uX2VudHJlbmEgPC0gZXNjYWxhcl9jb25fdHJhaW4odHJhaW5fb3JpZ2luYWwpDQprbm5fdGVzdCAgICA8LSBlc2NhbGFyX2Nvbl90cmFpbih0ZXN0X29yaWdpbmFsKQ0KDQojIENvbnZlcnRpciBPdXRjb21lIGEgZmFjdG9yDQprbm5fZW50cmVuYSRPdXRjb21lIDwtIGZhY3Rvcihrbm5fZW50cmVuYSRPdXRjb21lLCBsZXZlbHMgPSBjKDAsIDEpKQ0Ka25uX3Rlc3QkT3V0Y29tZSAgICA8LSBmYWN0b3Ioa25uX3Rlc3QkT3V0Y29tZSwgICAgbGV2ZWxzID0gYygwLCAxKSkNCg0KIyBOb21icmVzIGRlIGNvbHVtbmFzIGVzY2FsYWRhcw0KdmFyc19lc2MgPC0gcGFzdGUwKHZhcnNfcHJlZCwgIl9lc2MiKQ0KDQojIE1hdHJpY2VzIGRlIGVudHJhZGEgeSB2ZWN0b3JlcyBkZSBzYWxpZGEgcGFyYSBrbm4oKQ0Ka25uX2VudHJlbmFfaW5wdXQgIDwtIGtubl9lbnRyZW5hWywgdmFyc19lc2NdDQprbm5fdGVzdF9pbnB1dCAgICAgPC0ga25uX3Rlc3RbLCAgICB2YXJzX2VzY10NCmtubl9lbnRyZW5hX291dHB1dCA8LSBrbm5fZW50cmVuYSRPdXRjb21lDQprbm5fdGVzdF9vdXRwdXQgICAgPC0ga25uX3Rlc3QkT3V0Y29tZQ0KDQpjYXQoIkVudHJlbmFtaWVudG8gS05OOiIsIG5yb3coa25uX2VudHJlbmEpLCAib2JzZXJ2YWNpb25lc1xuIikNCmNhdCgiUHJ1ZWJhIEtOTjogICAgICAgIiwgbnJvdyhrbm5fdGVzdCksICAgICJvYnNlcnZhY2lvbmVzXG4iKQ0KYGBgDQoNCiMjIyA0LjEuMSBTZWxlY2Npw7NuIGRlbCBwYXLDoW1ldHJvIMOzcHRpbW8gZGUgaw0KDQpQYXJhIGRldGVybWluYXIgZWwgdmFsb3Igw7NwdGltbyBkZSBrLCBzZSB1dGlsaXrDsyBlbCBwYXF1ZXRlIGBjYXJldGAgZXZhbHVhbmRvIDIwMCB2YWxvcmVzIGRlIGsgbWVkaWFudGUgdW4gcmVtdWVzdHJlbyBkZSAyNSByZXBldGljaW9uZXMgc29icmUgbG9zIDMwMCBwYWNpZW50ZXMgZGUgZW50cmVuYW1pZW50by4gRXN0ZSBtw6l0b2RvIHBydWViYSBjYWRhIHZhbG9yIGRlIGsgY29uIGdydXBvcyBkaWZlcmVudGVzIGRlIHBhY2llbnRlcywgbG8gcXVlIHBlcm1pdGUgb2J0ZW5lciB1biByZXN1bHRhZG8gbcOhcyBjb25maWFibGUgcGFyYSBwcmVkZWNpciBlbCBkaWFnbsOzc3RpY28gZGUgZGlhYmV0ZXMuDQoNCmBgYHtyIGtubi1rLW1hbnVhbCwgZmlnLmhlaWdodD00LjV9DQojIEN1cnZhIGRlIHByZWNpc2nDs24gZXhwbG9yYXRvcmlhIGsgPSAxIGEgNTANCmtfdmFscyAgICA8LSAxOjUwDQpyZXN1bHRhZG8gPC0gZGF0YS5mcmFtZShrID0ga192YWxzLCBwcmVjaXNpb24gPSBOQV9yZWFsXykNCg0KZm9yIChuIGluIGtfdmFscykgew0KICBwcmVkX2sgPC0ga25uKA0KICAgIHRyYWluID0ga25uX2VudHJlbmFfaW5wdXQsDQogICAgY2wgICAgPSBrbm5fZW50cmVuYV9vdXRwdXQsDQogICAgdGVzdCAgPSBrbm5fdGVzdF9pbnB1dCwNCiAgICBrICAgICA9IG4NCiAgKQ0KICByZXN1bHRhZG8kcHJlY2lzaW9uW25dIDwtIG1lYW4ocHJlZF9rID09IGtubl90ZXN0X291dHB1dCkNCn0NCg0Ka19vcHQgICA8LSByZXN1bHRhZG8ka1t3aGljaC5tYXgocmVzdWx0YWRvJHByZWNpc2lvbildDQpwcmVjX29wIDwtIHJvdW5kKG1heChyZXN1bHRhZG8kcHJlY2lzaW9uKSAqIDEwMCwgMSkNCg0KZ2dwbG90KHJlc3VsdGFkbywgYWVzKHggPSBrLCB5ID0gcHJlY2lzaW9uKSkgKw0KICBnZW9tX2xpbmUoY29sb3IgPSBjb2xfbm8sIGxpbmV3aWR0aCA9IDAuOSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gY29sX25vLCBzaXplID0gMS41LCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBrX29wdCwgbGluZXR5cGUgPSAiZGFzaGVkIiwNCiAgICAgICAgICAgICBjb2xvciA9IGNvbF9zaSwgbGluZXdpZHRoID0gMC45KSArDQogIGFubm90YXRlKCJsYWJlbCIsDQogICAgeCA9IGtfb3B0ICsgMiwgeSA9IG1pbihyZXN1bHRhZG8kcHJlY2lzaW9uKSArIDAuMDA1LA0KICAgIGxhYmVsID0gcGFzdGUwKCJrIMOzcHRpbW8gPSAiLCBrX29wdCwgIlxuUHJlY2lzacOzbiA9ICIsIHByZWNfb3AsICIlIiksDQogICAgZmlsbCA9ICIjRkRGRUZFIiwgY29sb3IgPSBjb2xfc2ksIHNpemUgPSAzLjUsIGhqdXN0ID0gMA0KICApICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlICAgID0gIlByZWNpc2nDs24gZGVsIG1vZGVsbyBLTk4gc2Vnw7puIGVsIG7Dum1lcm8gZGUgdmVjaW5vcyAoaykiLA0KICAgIHN1YnRpdGxlID0gcGFzdGUwKCJFdmFsdWFkbyBzb2JyZSBlbCBjb25qdW50byBkZSBwcnVlYmEgKG4gPSAiLCBucm93KGtubl90ZXN0KSwgIikiKSwNCiAgICB4ID0gIk7Dum1lcm8gZGUgdmVjaW5vcyAoaykiLCB5ID0gIlByZWNpc2nDs24iDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgICAgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiIzJjM2U1MCIpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3IgPSBjb2xfbmV1KQ0KICApDQpgYGANCg0KPGRpdiBjbGFzcz0iaW50ZXJwcmV0YWNpb24iPg0KTGEgZ3LDoWZpY2EgbXVlc3RyYSBxdWUgY29uIGs9MSBsYSBwcmVjaXNpw7NuIGVzIG11eSBiYWphICh+NjclKSwgcmVmbGVqYW5kbyBhbHRhIGluZXN0YWJpbGlkYWQuIEVudHJlIGs9MSB5IGs9NSBsYSBwcmVjaXNpw7NuIHN1YmUgcsOhcGlkYW1lbnRlIGhhc3RhIH43NSUsIHBhcmEgbHVlZ28gYmFqYXIgYWxyZWRlZG9yIGRlIGs9OC4gQSBwYXJ0aXIgZGUgZXNlIHB1bnRvIG1lam9yYSBoYXN0YSBhbGNhbnphciBzdSBtw6F4aW1vLiBFc3RvIGNvbmZpcm1hIHF1ZSB2YWxvcmVzIG11eSBwZXF1ZcOxb3MgZ2VuZXJhbiBwcmVkaWNjaW9uZXMgcG9jbyBjb25maWFibGVzLCBtaWVudHJhcyBxdWUgdmFsb3JlcyBtb2RlcmFkb3Mgb2ZyZWNlbiBlbCBtZWpvciBkZXNlbXBlw7FvLg0KPC9kaXY+DQoNCmBgYHtyIGtubi1jYXJldCwgZmlnLmhlaWdodD00fQ0KIyBFbnRyZW5hbWllbnRvIGNvbiB2YWxpZGFjacOzbiBjcnV6YWRhIHZpYSBjYXJldCAodHVuZUxlbmd0aCA9IDIwMCB2YWxvcmVzIGRlIGspDQpzZXQuc2VlZCgyOCkNCg0Ka25uX2VudHJlbmFkbyA8LSB0cmFpbigNCiAgT3V0Y29tZSB+IEdsdWNvc2VfZXNjICsgQk1JX2VzYyArIEFnZV9lc2MgKw0KICAgICAgICAgICAgQmxvb2RQcmVzc3VyZV9lc2MgKyBEaWFiZXRlc1BlZGlncmVlRnVuY3Rpb25fZXNjLA0KICBkYXRhICAgICAgID0ga25uX2VudHJlbmEsDQogIG1ldGhvZCAgICAgPSAia25uIiwNCiAgdHVuZUxlbmd0aCA9IDIwMA0KKQ0KDQpwbG90KGtubl9lbnRyZW5hZG8sDQogICAgIG1haW4gPSAiQWNjdXJhY3kgQm9vdHN0cmFwIHNlZ8O6biBuw7ptZXJvIGRlIHZlY2lub3MgKGNhcmV0KSIsDQogICAgIGNvbCAgPSBjb2xfbm8pDQpgYGANCg0KPGRpdiBjbGFzcz0iaW50ZXJwcmV0YWNpb24iPg0KTGEgZ3LDoWZpY2EgZGUgYWNjdXJhY3kgY29uIHJlbXVlc3RyZW8gbXVlc3RyYSBxdWUgY29uIHZhbG9yZXMgcGVxdWXDsW9zIGRlIGsgbGEgZXhhY3RpdHVkIGNvbWllbnphIGFscmVkZWRvciBkZWwgNjYlLCBtZWpvcmFuZG8gcHJvZ3Jlc2l2YW1lbnRlIGhhc3RhIGFsY2FuemFyIHN1IHB1bnRvIG3DoXhpbW8gZW4gKiprID0gNTMqKiBjb24gKio3MS42MCUqKi4gQSBwYXJ0aXIgZGUgZXNlIHB1bnRvIGxhIGV4YWN0aXR1ZCBjYWUgZGUgZm9ybWEgY29udGludWEgaGFzdGEgYXByb3hpbWFkYW1lbnRlIGsgPSAyMjAsIGRvbmRlIHNlIGVzdGFiaWxpemEgYWxyZWRlZG9yIGRlbCA2MyUuIENvbnN1bHRhciBtw6FzIGRlIDIyMCBwYWNpZW50ZXMgc2ltaWxhcmVzIGhhY2UgcXVlIGVsIG1vZGVsbyBwaWVyZGEgdG90YWxtZW50ZSBzdSBjYXBhY2lkYWQgZGlzY3JpbWluYXRvcmlhLiBQb3IgZXN0YSByYXrDs24sICoqayA9IDUzKiogZnVlIGFkb3B0YWRvIGNvbW8gZWwgcGFyw6FtZXRybyBkZWZpbml0aXZvLg0KPC9kaXY+DQoNCiMjIyA0LjEuMiBNYXRyaXogZGUgY29uZnVzacOzbiB5IG3DqXRyaWNhcw0KDQpgYGB7ciBrbm4tcHJlZGljY2lvbn0NCiMgUHJlZGljY2lvbmVzIGRlIGNsYXNlIHkgcHJvYmFiaWxpZGFkZXMgc29icmUgZWwgY29uanVudG8gZGUgcHJ1ZWJhDQprbm5fcHJlZGljY2lvbiAgICAgIDwtIHByZWRpY3Qoa25uX2VudHJlbmFkbywgbmV3ZGF0YSA9IGtubl90ZXN0KQ0KcHJvYl9rbm5fcHJlZGljY2lvbiA8LSBwcmVkaWN0KGtubl9lbnRyZW5hZG8sIG5ld2RhdGEgPSBrbm5fdGVzdCwgdHlwZSA9ICJwcm9iIikNCg0KDQpgYGANCg0KYGBge3Iga25uLWNvbmZ1c2lvbn0NCmNtX2tubiA8LSBjb25mdXNpb25NYXRyaXgoa25uX3ByZWRpY2Npb24sIGtubl90ZXN0JE91dGNvbWUpDQpjbV9rbm4NCmBgYA0KDQo8ZGl2IGNsYXNzPSJyZXN1bHRhZG8tY2xhdmUiPg0KKipSZXN1bHRhZG9zIEtOTiAoayA9IDUzKToqKg0KDQpBbCBldmFsdWFyIGVsIG1vZGVsbyBzb2JyZSBsb3MgMjAwIHBhY2llbnRlcyBkZWwgY29uanVudG8gZGUgcHJ1ZWJhLCBzZSBvYnR1dm8gdW5hICoqZXhhY3RpdHVkIGdsb2JhbCBkZWwgNzUlKiosIHN1cGVyYW5kbyBsYSB0YXNhIGRlIG5vIGluZm9ybWFjacOzbiBkZWwgNjkuNSUsIGxvIHF1ZSBjb25maXJtYSBxdWUgZWwgbW9kZWxvIGFwb3J0YSB2YWxvciByZWFsIGFsIGRpYWduw7NzdGljby4NCg0KLSAqKlNlbnNpYmlsaWRhZDogODcuNzclKiog4oCUIGRlIGxhcyAxMzkgcGFjaWVudGVzIHNhbmFzLCBlbCBtb2RlbG8gaWRlbnRpZmljw7MgY29ycmVjdGFtZW50ZSAxMjIuIEVzdG8gZXF1aXZhbGUgYSBkZXNjYXJ0YXIgY29ycmVjdGFtZW50ZSBsYSBlbmZlcm1lZGFkIGVuIGNhc2kgOSBkZSBjYWRhIDEwIHBhY2llbnRlcyBzYW5hcy4NCi0gKipFc3BlY2lmaWNpZGFkOiA0NS45MCUqKiDigJQgZGUgbGFzIDYxIHBhY2llbnRlcyBkaWFiw6l0aWNhcywgc29sbyBzZSBpZGVudGlmaWNhcm9uIGNvcnJlY3RhbWVudGUgMjguIE3DoXMgZGUgbGEgbWl0YWQgZGUgbGFzIHBhY2llbnRlcyBjb24gZGlhYmV0ZXMgZnVlcm9uIGNsYXNpZmljYWRhcyBjb21vIHNhbmFzLg0KLSAqKlZhbG9yIHByZWRpY3Rpdm8gcG9zaXRpdm86IDc4LjcxJSoqIOKAlCBjdWFuZG8gZWwgbW9kZWxvIHByZWRpY2UgcXVlIHVuYSBwYWNpZW50ZSBubyB0aWVuZSBkaWFiZXRlcywgYWNpZXJ0YSBjYXNpIDggZGUgY2FkYSAxMCB2ZWNlcy4NCi0gKipWYWxvciBwcmVkaWN0aXZvIG5lZ2F0aXZvOiA2Mi4yMiUqKiDigJQgY3VhbmRvIHByZWRpY2UgcXVlIHPDrSB0aWVuZSBkaWFiZXRlcywgYWNpZXJ0YSBzb2xvIDYgZGUgY2FkYSAxMCB2ZWNlcy4NCi0gKipLYXBwYTogMC4zNioqIOKAlCBhY3VlcmRvIG1vZGVyYWRvIGVudHJlIHByZWRpY2Npb25lcyB5IHZhbG9yZXMgcmVhbGVzLg0KLSAqKkV4YWN0aXR1ZCBiYWxhbmNlYWRhOiA2Ni44NCUqKiDigJQgZWwgbW9kZWxvIHRpZW5lIG1lam9yIGRlc2VtcGXDsW8gaWRlbnRpZmljYW5kbyBwYWNpZW50ZXMgc2FuYXMgcXVlIHBhY2llbnRlcyBkaWFiw6l0aWNhcy4NCjwvZGl2Pg0KDQojIyMgNC4xLjMgQ3VydmEgUk9DIOKAlCBLTk4NCg0KYGBge3Iga25uLXJvYywgZmlnLmhlaWdodD00LjV9DQojIENPUlJFQ0NJw5NOOiBzZSB1c2EgbGEgcHJvYmFiaWxpZGFkIGRlIGxhIGNsYXNlIHBvc2l0aXZhICgxID0gY29uIGRpYWJldGVzKQ0KIyBlbiBsdWdhciBkZSBhcy5udW1lcmljKGtubl9wcmVkaWNjaW9uKSwgcXVlIGRhYmEgdW4gQVVDIGRpc3RvcnNpb25hZG8NCnByb2JfcG9zX2tubiA8LSBwcm9iX2tubl9wcmVkaWNjaW9uWywgIjEiXQ0KDQpwcmVkX3JvYyAgICAgIDwtIHByZWRpY3Rpb24ocHJvYl9wb3Nfa25uLCBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihrbm5fdGVzdCRPdXRjb21lKSkpDQpwZXJmX3JvYyAgICAgIDwtIHBlcmZvcm1hbmNlKHByZWRfcm9jLCAidHByIiwgImZwciIpDQphdWNfa25uICAgICAgIDwtIHBlcmZvcm1hbmNlKHByZWRfcm9jLCAiYXVjIikNCmF1Y19rbm5fdmFsb3IgPC0gcm91bmQoYXVjX2tubkB5LnZhbHVlc1tbMV1dLCAzKQ0KDQpmcHJfdmFscyA8LSB1bmxpc3QocGVyZl9yb2NAeC52YWx1ZXMpDQp0cHJfdmFscyA8LSB1bmxpc3QocGVyZl9yb2NAeS52YWx1ZXMpDQpyb2NfZGYgICA8LSBkYXRhLmZyYW1lKEZQUiA9IGZwcl92YWxzLCBUUFIgPSB0cHJfdmFscykNCg0KZ2dwbG90KHJvY19kZiwgYWVzKHggPSBGUFIsIHkgPSBUUFIpKSArDQogIGdlb21fbGluZShjb2xvciA9IGNvbF9ubywgbGluZXdpZHRoID0gMS4xKSArDQogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSBjb2xfbmV1KSArDQogIGFubm90YXRlKCJsYWJlbCIsDQogICAgeCA9IDAuNjUsIHkgPSAwLjE1LA0KICAgIGxhYmVsID0gcGFzdGUwKCJBVUMgPSAiLCBhdWNfa25uX3ZhbG9yKSwNCiAgICBmaWxsID0gIiNFQkY1RkIiLCBjb2xvciA9IGNvbF9ubywgc2l6ZSA9IDQuMiwgZm9udGZhY2UgPSAiYm9sZCINCiAgKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ3VydmEgUk9DIOKAlCBNb2RlbG8gS05OIiwNCiAgICB4ID0gIlRhc2EgZGUgRmFsc29zIFBvc2l0aXZvcyAoMSDiiJIgRXNwZWNpZmljaWRhZCkiLA0KICAgIHkgPSAiVGFzYSBkZSBWZXJkYWRlcm9zIFBvc2l0aXZvcyAoU2Vuc2liaWxpZGFkKSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBjb2xvciA9ICIjMmMzZTUwIikpDQpgYGANCg0KPGRpdiBjbGFzcz0iaW50ZXJwcmV0YWNpb24iPg0KTGEgY3VydmEgUk9DIGRlbCBtb2RlbG8gS05OIGV2YWx1YWRhIHNvYnJlIGVsIGNvbmp1bnRvIGRlIHBydWViYSBtdWVzdHJhIHVuICoqQVVDIGRlIGByIGF1Y19rbm5fdmFsb3JgKiosIGxvIHF1ZSBpbmRpY2EgcXVlIGVsIG1vZGVsbyB0aWVuZSB1biBgciByb3VuZChhdWNfa25uX3ZhbG9yICogMTAwLCAxKWAlIGRlIHByb2JhYmlsaWRhZCBkZSBjbGFzaWZpY2FyIGNvcnJlY3RhbWVudGUgYSB1bmEgcGFjaWVudGUgZGlhYsOpdGljYSBwb3IgZW5jaW1hIGRlIHVuYSBzYW5hOyBlc3RlIHZhbG9yIHNlIGNvbnNpZGVyYSBhY2VwdGFibGUuIEVzdGUgcmVzdWx0YWRvIGVzIGNvaGVyZW50ZSBjb24gbG8gb2JzZXJ2YWRvIGVuIGxhIG1hdHJpeiBkZSBjb25mdXNpw7NuLCBkb25kZSBlbCBtb2RlbG8gbW9zdHLDsyBidWVuIGRlc2VtcGXDsW8gaWRlbnRpZmljYW5kbyBwYWNpZW50ZXMgc2FuYXMgcGVybyBmYWxsw7MgZW4gbcOhcyBkZSBsYSBtaXRhZCBkZSBsb3MgY2Fzb3MgZGlhYsOpdGljb3MuDQo8L2Rpdj4NCg0KLS0tDQoNCiMjIDQuMiBNb2RlbG8gZGUgUmVncmVzacOzbiBMb2fDrXN0aWNhIChMb2dpdCkNCg0KQ29uIGVsIHByb3DDs3NpdG8gZGUgY29tcGxlbWVudGFyIGVsIGFuw6FsaXNpcyB5IGNvbXBhcmFyIGRpc3RpbnRvcyBlbmZvcXVlcyBkZSBjbGFzaWZpY2FjacOzbiwgc2UgaW1wbGVtZW50w7MgdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbG9nw61zdGljYSB1dGlsaXphbmRvIGVsIG1pc21vIGNvbmp1bnRvIGRlIHZhcmlhYmxlcyBwcmV2aWFtZW50ZSBzZWxlY2Npb25hZGFzLiBFc3RlIG1vZGVsbyBwZXJtaXRpw7MgZXN0aW1hciBsYSBwcm9iYWJpbGlkYWQgZGUgcXVlIHVuYSBwYWNpZW50ZSBwcmVzZW50ZSBkaWFiZXRlcyBhIHBhcnRpciBkZSBmYWN0b3JlcyBjbMOtbmljb3MsIGbDrXNpY29zIHkgaGVyZWRpdGFyaW9zLg0KDQojIyMgUGFydGljacOzbiBkZSBkYXRvcw0KDQpFbCBtb2RlbG8gTG9naXQgdXRpbGl6YSBsYSAqKm1pc21hIHBhcnRpY2nDs24gNzAvMzAqKiBnZW5lcmFkYSBhbCBpbmljaW8gY29uIGBjcmVhdGVEYXRhUGFydGl0aW9uYCwgZ2FyYW50aXphbmRvIHF1ZSBsYSBldmFsdWFjacOzbiBzZWEgZGlyZWN0YW1lbnRlIGNvbXBhcmFibGUgY29uIGVsIG1vZGVsbyBLTk4gc29icmUgZXhhY3RhbWVudGUgbG9zIG1pc21vcyBwYWNpZW50ZXMgZGUgcHJ1ZWJhLg0KDQpgYGB7ciBsb2dpdC1wcmVwfQ0KIyBSZXV0aWxpemFyIGxhIHBhcnRpY2nDs24gdW5pZmljYWRhOiB0cmFpbl9vcmlnaW5hbCB5IHRlc3Rfb3JpZ2luYWwNCm15ZGF0YSAgICAgIDwtIHRyYWluX29yaWdpbmFsDQpteWRhdGEkT3V0Y29tZV9mIDwtIGZhY3RvcihteWRhdGEkT3V0Y29tZSwgbGV2ZWxzID0gYygwLCAxKSwgbGFiZWxzID0gYygiTm8iLCAiU2kiKSkNCg0KdGVzdF9sb2dpdCAgPC0gdGVzdF9vcmlnaW5hbA0KdGVzdF9sb2dpdCRPdXRjb21lX2YgPC0gZmFjdG9yKHRlc3RfbG9naXQkT3V0Y29tZSwgbGV2ZWxzID0gYygwLCAxKSwgbGFiZWxzID0gYygiTm8iLCAiU2kiKSkNCg0KY2F0KCJFbnRyZW5hbWllbnRvIExvZ2l0OiIsIG5yb3cobXlkYXRhKSwgICAgICJvYnNlcnZhY2lvbmVzXG4iKQ0KY2F0KCJQcnVlYmEgTG9naXQ6ICAgICAgICIsIG5yb3codGVzdF9sb2dpdCksICJvYnNlcnZhY2lvbmVzXG4iKQ0KYGBgDQoNCiMjIyA0LjIuMSBBanVzdGUgZSBpbnRlcnByZXRhY2nDs24gZ2VuZXJhbCBkZWwgbW9kZWxvDQoNCmBgYHtyIGxvZ2l0LWFqdXN0ZX0NCmZpdF9sb2dpdCA8LSBnbG0oDQogIE91dGNvbWUgfiBHbHVjb3NlICsgQk1JICsgQWdlICsgQmxvb2RQcmVzc3VyZSArIERpYWJldGVzUGVkaWdyZWVGdW5jdGlvbiwNCiAgZGF0YSAgID0gbXlkYXRhLA0KICBmYW1pbHkgPSBiaW5vbWlhbCgpDQopDQpzdW1tYXJ5KGZpdF9sb2dpdCkNCmBgYA0KDQo8ZGl2IGNsYXNzPSJpbnRlcnByZXRhY2lvbiI+DQpFbiB0w6lybWlub3MgZ2VuZXJhbGVzLCBlbCBtb2RlbG8gZXZpZGVuY2nDsyBxdWUgdmFyaWFibGVzIGNvbW8gbGEgKipnbHVjb3NhLCBlbCDDrW5kaWNlIGRlIG1hc2EgY29ycG9yYWwgeSBsYSBlZGFkKiogcHJlc2VudGFuIHVuYSBpbmZsdWVuY2lhIHBvc2l0aXZhIHNvYnJlIGxhIHByb2JhYmlsaWRhZCBlc3RpbWFkYSBkZSBkaWFiZXRlcywgcmVzdWx0YWRvIGNvbnNpc3RlbnRlIGNvbiBsYSBsaXRlcmF0dXJhIG3DqWRpY2EgeSBjb24gZWwgYW7DoWxpc2lzIGV4cGxvcmF0b3JpbyByZWFsaXphZG8uIFBhY2llbnRlcyBjb24gbWF5b3JlcyBuaXZlbGVzIGRlIGdsdWNvc2EsIG1heW9yIEJNSSBvIG1heW9yIGVkYWQgdGllbmRlbiBhIHByZXNlbnRhciB1biBtYXlvciByaWVzZ28gZGUgZGlhZ27Ds3N0aWNvIHBvc2l0aXZvLiBMYSBwcmVzacOzbiBhcnRlcmlhbCBtb3N0csOzIHVuYSBjYXBhY2lkYWQgZXhwbGljYXRpdmEgbcOhcyBtb2RlcmFkYSwgbWllbnRyYXMgcXVlIGxhIGZ1bmNpw7NuIGRlIHBlZGlncsOtIGRpYWLDqXRpY28gYXBvcnTDsyBpbmZvcm1hY2nDs24gYXNvY2lhZGEgYSBsYSBwcmVkaXNwb3NpY2nDs24gaGVyZWRpdGFyaWEuIExhcyB2YXJpYWJsZXMgY29uICoqcC12YWxvciA8IDAuMDUqKiBzb24gZXN0YWTDrXN0aWNhbWVudGUgc2lnbmlmaWNhdGl2YXMgZW4gbGEgcHJlZGljY2nDs24uDQo8L2Rpdj4NCg0KIyMjIDQuMi4yIERlc2VtcGXDsW8gcHJlZGljdGl2byBkZWwgbW9kZWxvDQoNCmBgYHtyIGxvZ2l0LWV2YWwtdW1icmFsMDV9DQojIFByZWRpY2Npw7NuIGNvbiB1bWJyYWwgZXN0w6FuZGFyIGRlIDAuNQ0KcF9oYXQgICAgICA8LSBwcmVkaWN0KGZpdF9sb2dpdCwgbmV3ZGF0YSA9IHRlc3RfbG9naXQsIHR5cGUgPSAicmVzcG9uc2UiKQ0KcHJlZF9jbGFzZSA8LSBmYWN0b3IoaWZlbHNlKHBfaGF0ID49IDAuNSwgIlNpIiwgIk5vIiksIGxldmVscyA9IGMoIlNpIiwgIk5vIikpDQpjb25mdXNpb25NYXRyaXgocHJlZF9jbGFzZSwgdGVzdF9sb2dpdCRPdXRjb21lX2YsIHBvc2l0aXZlID0gIlNpIikNCmBgYA0KDQpBIGNvbnRpbnVhY2nDs24sIHNlIGFwbGljYSBlbCAqKsOtbmRpY2UgZGUgWW91ZGVuKiogcGFyYSBlbmNvbnRyYXIgZWwgdW1icmFsIGRlIGNsYXNpZmljYWNpw7NuIHF1ZSBtYXhpbWl6YSBzaW11bHTDoW5lYW1lbnRlIGxhIHNlbnNpYmlsaWRhZCB5IGxhIGVzcGVjaWZpY2lkYWQsIGVuIGx1Z2FyIGRlbCB1bWJyYWwgZXN0w6FuZGFyIGRlIDAuNS4NCg0KYGBge3IgbG9naXQtcm9jLCBmaWcuaGVpZ2h0PTQuNX0NCnJvY19vICA8LSByb2MocmVzcG9uc2UgPSB0ZXN0X2xvZ2l0JE91dGNvbWVfZiwgcHJlZGljdG9yID0gcF9oYXQsIGxldmVscyA9IGMoIk5vIiwgIlNpIikpDQp0aHIgICAgPC0gY29vcmRzKHJvY19vLCB4ID0gImJlc3QiLCBiZXN0Lm1ldGhvZCA9ICJ5b3VkZW4iLCByZXQgPSAidGhyZXNob2xkIikNCnVtYnJhbCA8LSBhcy5udW1lcmljKHRocikNCg0KYXVjX3ZhbCAgIDwtIGF1Yyhyb2NfbykNCmF1Y192YWxfciA8LSByb3VuZChhcy5udW1lcmljKGF1Y192YWwpLCAzKQ0KDQpyb2NfZGF0YSA8LSBkYXRhLmZyYW1lKA0KICBGUFIgPSByZXYoMSAtIHJvY19vJHNwZWNpZmljaXRpZXMpLA0KICBUUFIgPSByZXYocm9jX28kc2Vuc2l0aXZpdGllcykNCikNCg0KZ2dwbG90KHJvY19kYXRhLCBhZXMoeCA9IEZQUiwgeSA9IFRQUikpICsNCiAgZ2VvbV9saW5lKGNvbG9yID0gY29sX3NpLCBsaW5ld2lkdGggPSAxLjEpICsNCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9IGNvbF9uZXUpICsNCiAgYW5ub3RhdGUoImxhYmVsIiwNCiAgICB4ID0gMC42NSwgeSA9IDAuMTUsDQogICAgbGFiZWwgPSBwYXN0ZTAoIkFVQyA9ICIsIGF1Y192YWxfciwNCiAgICAgICAgICAgICAgICAgICAiXG5VbWJyYWwgw7NwdGltbyA9ICIsIHJvdW5kKHVtYnJhbCwgMykpLA0KICAgIGZpbGwgPSAiI0ZERURFQyIsIGNvbG9yID0gY29sX3NpLCBzaXplID0gMy44LCBmb250ZmFjZSA9ICJib2xkIg0KICApICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJDdXJ2YSBST0Mg4oCUIFJlZ3Jlc2nDs24gTG9nw61zdGljYSAoTG9naXQpIiwNCiAgICB4ID0gIlRhc2EgZGUgRmFsc29zIFBvc2l0aXZvcyAoMSDiiJIgRXNwZWNpZmljaWRhZCkiLA0KICAgIHkgPSAiVGFzYSBkZSBWZXJkYWRlcm9zIFBvc2l0aXZvcyAoU2Vuc2liaWxpZGFkKSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBjb2xvciA9ICIjMmMzZTUwIikpDQpgYGANCg0KYGBge3IgbG9naXQtZXZhbC1vcHRpbW99DQojIFJlY2xhc2lmaWNhY2nDs24gY29uIHVtYnJhbCDDs3B0aW1vIGRlIFlvdWRlbg0KcHJlZF9jbGFzZSA8LSBmYWN0b3IoaWZlbHNlKHBfaGF0ID49IHVtYnJhbCwgIlNpIiwgIk5vIiksIGxldmVscyA9IGMoIlNpIiwgIk5vIikpDQpjbV9sb2dpdCAgIDwtIGNvbmZ1c2lvbk1hdHJpeChwcmVkX2NsYXNlLCB0ZXN0X2xvZ2l0JE91dGNvbWVfZiwgcG9zaXRpdmUgPSAiU2kiKQ0KY21fbG9naXQNCmBgYA0KDQo8ZGl2IGNsYXNzPSJyZXN1bHRhZG8tY2xhdmUiPg0KKipSZXN1bHRhZG9zIFJlZ3Jlc2nDs24gTG9nw61zdGljYSAodW1icmFsIMOzcHRpbW8gZGUgWW91ZGVuID0gYHIgcm91bmQodW1icmFsLCAzKWApOioqDQoNCkFsIGV2YWx1YXIgZWwgbW9kZWxvIHNvYnJlIGVsIGNvbmp1bnRvIGRlIHBydWViYSwgbGEgcmVncmVzacOzbiBsb2fDrXN0aWNhIGFsY2FuesOzIHVuYSAqKmV4YWN0aXR1ZCBnbG9iYWwgZGVsIDgwLjczJSoqLCBjbGFzaWZpY2FuZG8gY29ycmVjdGFtZW50ZSBhcHJveGltYWRhbWVudGUgOCBkZSBjYWRhIDEwIHBhY2llbnRlcy4NCg0KLSAqKlNlbnNpYmlsaWRhZDogNzMuMTMlKiog4oCUIGxvZ3LDsyBpZGVudGlmaWNhciBjb3JyZWN0YW1lbnRlIHVuYSBwcm9wb3JjacOzbiBpbXBvcnRhbnRlIGRlIHBhY2llbnRlcyBxdWUgcmVhbG1lbnRlIHByZXNlbnRhbiBkaWFiZXRlcywgcmVkdWNpZW5kbyBmYWxzb3MgbmVnYXRpdm9zLg0KLSAqKkVzcGVjaWZpY2lkYWQ6IDg0LjgwJSoqIOKAlCBhbHRhIGNhcGFjaWRhZCBwYXJhIGlkZW50aWZpY2FyIGNvcnJlY3RhbWVudGUgcGFjaWVudGVzIHNpbiBkaWFiZXRlcywgcmVkdWNpZW5kbyBmYWxzb3MgcG9zaXRpdm9zLg0KLSAqKlZhbG9yIHByZWRpY3Rpdm8gcG9zaXRpdm8gKFBQVik6IDcyLjA2JSoqIOKAlCBjdWFuZG8gY2xhc2lmaWNhIGEgdW5hIHBhY2llbnRlIGNvbW8gcG9zaXRpdmEsIGxhIHByZWRpY2Npw7NuIHRpZW5lIHVuYSBwcm9iYWJpbGlkYWQgYWx0YSBkZSBzZXIgY29ycmVjdGEuDQotICoqVmFsb3IgcHJlZGljdGl2byBuZWdhdGl2byAoTlBWKTogODUuNDglKiog4oCUIHJlZnVlcnphIGxhIGNvbmZpYWJpbGlkYWQgZGVsIG1vZGVsbyBwYXJhIGNsYXNpZmljYXIgcGFjaWVudGVzIHNpbiBsYSBlbmZlcm1lZGFkLg0KLSAqKkV4YWN0aXR1ZCBiYWxhbmNlYWRhOiA3OC45NyUqKiDigJQgZGVzZW1wZcOxbyByZWxhdGl2YW1lbnRlIGVxdWlsaWJyYWRvIGVudHJlIHNlbnNpYmlsaWRhZCB5IGVzcGVjaWZpY2lkYWQuDQotICoqQVVDOiBgciBhdWNfdmFsX3JgKiog4oCUIGNhcGFjaWRhZCBkaXNjcmltaW5hdG9yaWEgc3VwZXJpb3IgYWwgbW9kZWxvIEtOTi4NCjwvZGl2Pg0KDQotLS0NCg0KIyA1LiBDb21wYXJhY2nDs24gZGUgTW9kZWxvcw0KDQpBbCBjb21wYXJhciBsb3MgcmVzdWx0YWRvcyBvYnRlbmlkb3MgZW50cmUgS05OIHkgbGEgcmVncmVzacOzbiBsb2fDrXN0aWNhLCBzZSBpZGVudGlmaWNhcm9uIGRpZmVyZW5jaWFzIGltcG9ydGFudGVzIGVuIGVsIGRlc2VtcGXDsW8gcHJlZGljdGl2by4gQSBjb250aW51YWNpw7NuIHNlIHByZXNlbnRhIGxhIHRhYmxhIHJlc3VtZW4geSBsYSBncsOhZmljYSBjb21wYXJhdGl2YS4NCg0KYGBge3IgY29tcGFyYWNpb24tdGFibGF9DQpjb21wYXJhY2lvbl9tb2RlbG9zIDwtIGRhdGEuZnJhbWUoDQogIE1vZGVsbyAgICAgICAgPSBjKCJLTk4iLCAiTG9naXQiKSwNCiAgQWNjdXJhY3kgICAgICA9IGMoY21fa25uJG92ZXJhbGxbIkFjY3VyYWN5Il0sICAgICAgIGNtX2xvZ2l0JG92ZXJhbGxbIkFjY3VyYWN5Il0pLA0KICBTZW5zaWJpbGlkYWQgID0gYyhjbV9rbm4kYnlDbGFzc1siU2Vuc2l0aXZpdHkiXSwgICAgY21fbG9naXQkYnlDbGFzc1siU2Vuc2l0aXZpdHkiXSksDQogIEVzcGVjaWZpY2lkYWQgPSBjKGNtX2tubiRieUNsYXNzWyJTcGVjaWZpY2l0eSJdLCAgICBjbV9sb2dpdCRieUNsYXNzWyJTcGVjaWZpY2l0eSJdKSwNCiAgUHJlY2lzaW9uICAgICA9IGMoY21fa25uJGJ5Q2xhc3NbIlBvcyBQcmVkIFZhbHVlIl0sIGNtX2xvZ2l0JGJ5Q2xhc3NbIlBvcyBQcmVkIFZhbHVlIl0pLA0KICBBVUMgICAgICAgICAgID0gYyhhdWNfa25uX3ZhbG9yLCBhdWNfdmFsX3IpDQopDQoNCmNvbXBhcmFjaW9uX21vZGVsb3MgJT4lDQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH4gcm91bmQoLngsIDMpKSkgJT4lDQogIGthYmxlKA0KICAgIGNvbC5uYW1lcyA9IGMoIk1vZGVsbyIsICJFeGFjdGl0dWQiLCAiU2Vuc2liaWxpZGFkIiwNCiAgICAgICAgICAgICAgICAgICJFc3BlY2lmaWNpZGFkIiwgIlByZWNpc2nDs24iLCAiQVVDIiksDQogICAgY2FwdGlvbiAgID0gIlRhYmxhIDIuIENvbXBhcmFjacOzbiBkZSBtw6l0cmljYXMgZGUgY2xhc2lmaWNhY2nDs24g4oCUIEtOTiB2cy4gUmVncmVzacOzbiBMb2fDrXN0aWNhIg0KICApICU+JQ0KICBrYWJsZV9zdHlsaW5nKA0KICAgIGZ1bGxfd2lkdGggICAgICAgID0gRkFMU0UsDQogICAgcG9zaXRpb24gICAgICAgICAgPSAiY2VudGVyIiwNCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIikNCiAgKSAlPiUNCiAgcm93X3NwZWMoMCwgYm9sZCA9IFRSVUUsIGNvbG9yID0gIndoaXRlIiwgYmFja2dyb3VuZCA9ICIjMkMzRTUwIikgJT4lDQogIHJvd19zcGVjKDEsIGJhY2tncm91bmQgPSAiI0Q2RUFGOCIpICU+JQ0KICByb3dfc3BlYygyLCBiYWNrZ3JvdW5kID0gIiNGQURCRDgiKQ0KYGBgDQoNCmBgYHtyIGNvbXBhcmFjaW9uLWdyYWZpY2EsIGZpZy5oZWlnaHQ9NC41LCBmaWcud2lkdGg9OX0NCmNvbXBhcmFjaW9uX21vZGVsb3MgJT4lDQogIHBpdm90X2xvbmdlcigtTW9kZWxvLCBuYW1lc190byA9ICJNZXRyaWNhIiwgdmFsdWVzX3RvID0gIlZhbG9yIikgJT4lDQogIG11dGF0ZShNZXRyaWNhID0gZmFjdG9yKE1ldHJpY2EsDQogICAgbGV2ZWxzID0gYygiQWNjdXJhY3kiLCAiU2Vuc2liaWxpZGFkIiwgIkVzcGVjaWZpY2lkYWQiLCAiUHJlY2lzaW9uIiwgIkFVQyIpDQogICkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBNZXRyaWNhLCB5ID0gVmFsb3IsIGZpbGwgPSBNb2RlbG8pKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAwLjU4LCBhbHBoYSA9IDAuODgsIGNvbG9yID0gIndoaXRlIikgKw0KICBnZW9tX3RleHQoDQogICAgYWVzKGxhYmVsID0gcm91bmQoVmFsb3IsIDMpKSwNCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41OCksDQogICAgdmp1c3QgPSAtMC41LCBzaXplID0gMy4yLCBmb250ZmFjZSA9ICJib2xkIg0KICApICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiS05OIiA9IGNvbF9ubywgIkxvZ2l0IiA9IGNvbF9zaSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMS4xKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlICAgID0gIkNvbXBhcmFjacOzbiBkZSBtw6l0cmljYXMgZW50cmUgS05OIHkgUmVncmVzacOzbiBMb2fDrXN0aWNhIiwNCiAgICBzdWJ0aXRsZSA9ICJFdmFsdWFkYXMgc29icmUgZWwgY29uanVudG8gZGUgcHJ1ZWJhIiwNCiAgICB4ID0gIk3DqXRyaWNhIiwgeSA9ICJWYWxvciIsIGZpbGwgPSAiTW9kZWxvIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlICAgICAgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiIzJjM2U1MCIpLA0KICAgIHBsb3Quc3VidGl0bGUgICA9IGVsZW1lbnRfdGV4dChjb2xvciA9IGNvbF9uZXUpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICkNCmBgYA0KDQojIyMgNS4yIEN1cnZhcyBST0MgY29tcGFyYXRpdmFzDQoNCmBgYHtyIGNvbXBhcmFjaW9uLXJvYywgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OH0NCiMgQ3VydmEgUk9DIGRlbCBLTk4gdXNhbmRvIHBST0MgKG1pc21hIGxpYnJlcsOtYSBxdWUgTG9naXQgcGFyYSBncsOhZmljbyB1bmlmaWNhZG8pDQpyb2Nfa25uIDwtIHJvYygNCiAgcmVzcG9uc2UgID0ga25uX3Rlc3QkT3V0Y29tZSwNCiAgcHJlZGljdG9yID0gcHJvYl9rbm5fcHJlZGljY2lvblssICIxIl0sDQogIGxldmVscyAgICA9IGMoIjAiLCAiMSIpDQopDQoNCiMgQ29uc3RydWlyIGRhdGEgZnJhbWUgY29uIGFtYmFzIGN1cnZhcyBwYXJhIGdncGxvdA0Kcm9jX2tubl9kZiA8LSBkYXRhLmZyYW1lKA0KICBGUFIgICAgPSByZXYoMSAtIHJvY19rbm4kc3BlY2lmaWNpdGllcyksDQogIFRQUiAgICA9IHJldihyb2Nfa25uJHNlbnNpdGl2aXRpZXMpLA0KICBNb2RlbG8gPSAiS05OIg0KKQ0Kcm9jX2xvZ2l0X2RmIDwtIGRhdGEuZnJhbWUoDQogIEZQUiAgICA9IHJldigxIC0gcm9jX28kc3BlY2lmaWNpdGllcyksDQogIFRQUiAgICA9IHJldihyb2NfbyRzZW5zaXRpdml0aWVzKSwNCiAgTW9kZWxvID0gIkxvZ2l0Ig0KKQ0Kcm9jX2NvbXBhcmFjaW9uIDwtIGJpbmRfcm93cyhyb2Nfa25uX2RmLCByb2NfbG9naXRfZGYpDQoNCmdncGxvdChyb2NfY29tcGFyYWNpb24sIGFlcyh4ID0gRlBSLCB5ID0gVFBSLCBjb2xvciA9IE1vZGVsbykpICsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aCA9IDEuMikgKw0KICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gY29sX25ldSkgKw0KICBhbm5vdGF0ZSgibGFiZWwiLA0KICAgIHggPSAwLjYyLCB5ID0gMC4yMiwNCiAgICBsYWJlbCA9IHBhc3RlMCgiQVVDIEtOTiAgID0gIiwgYXVjX2tubl92YWxvciwNCiAgICAgICAgICAgICAgICAgICAiXG5BVUMgTG9naXQgPSAiLCBhdWNfdmFsX3IpLA0KICAgIGZpbGwgPSAiI0ZERkVGRSIsIGNvbG9yID0gIiMyYzNlNTAiLCBzaXplID0gMy44LCBmb250ZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwDQogICkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiS05OIiA9IGNvbF9ubywgIkxvZ2l0IiA9IGNvbF9zaSkpICsNCiAgbGFicygNCiAgICB0aXRsZSAgICA9ICJDdXJ2YXMgUk9DIGNvbXBhcmF0aXZhcyDigJQgS05OIHZzLiBSZWdyZXNpw7NuIExvZ8Otc3RpY2EiLA0KICAgIHN1YnRpdGxlID0gIkV2YWx1YWRhcyBzb2JyZSBlbCBtaXNtbyBjb25qdW50byBkZSBwcnVlYmEgKHBhcnRpY2nDs24gNzAvMzApIiwNCiAgICB4ID0gIlRhc2EgZGUgRmFsc29zIFBvc2l0aXZvcyAoMSDiiJIgRXNwZWNpZmljaWRhZCkiLA0KICAgIHkgPSAiVGFzYSBkZSBWZXJkYWRlcm9zIFBvc2l0aXZvcyAoU2Vuc2liaWxpZGFkKSIsDQogICAgY29sb3IgPSAiTW9kZWxvIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlICAgICAgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiIzJjM2U1MCIpLA0KICAgIHBsb3Quc3VidGl0bGUgICA9IGVsZW1lbnRfdGV4dChjb2xvciA9IGNvbF9uZXUpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiDQogICkNCmBgYA0KDQo8ZGl2IGNsYXNzPSJyZXN1bHRhZG8tY2xhdmUiPg0KKipJbnRlcnByZXRhY2nDs24gY29tcGFyYXRpdmE6KioNCg0KLSAqKkV4YWN0aXR1ZCBnbG9iYWw6KiogZWwgbW9kZWxvIExvZ2l0IHByZXNlbnTDsyB1biBtZWpvciByZXN1bHRhZG8gKDgwLjczJSB2cyA3NS4wMCUpLCBjbGFzaWZpY2FuZG8gY29ycmVjdGFtZW50ZSB1bmEgbWF5b3IgcHJvcG9yY2nDs24gZGUgcGFjaWVudGVzLg0KLSAqKlNlbnNpYmlsaWRhZDoqKiBLTk4gbW9zdHLDsyB1bmEgdmVudGFqYSBjb25zaWRlcmFibGUgKDg3Ljc3JSB2cyA3My4xMyUpLCBzaWVuZG8gbcOhcyBlZmVjdGl2byBwYXJhIGRldGVjdGFyIHBhY2llbnRlcyBxdWUgcmVhbG1lbnRlIHByZXNlbnRhbiBkaWFiZXRlcy4gRGVzZGUgdW5hIHBlcnNwZWN0aXZhIG3DqWRpY2EsIGVzdG8gcHVlZGUgc2VyIHZhbGlvc28gY3VhbmRvIGxhIHByaW9yaWRhZCBlcyBtYXhpbWl6YXIgbGEgZGV0ZWNjacOzbiB0ZW1wcmFuYS4NCi0gKipFc3BlY2lmaWNpZGFkOioqIGxhIHJlZ3Jlc2nDs24gbG9nw61zdGljYSBwcmVzZW50w7MgdW5hIHN1cGVyaW9yaWRhZCBtdXkgbWFyY2FkYSAoODQuODAlIHZzIDQ1LjkwJSksIHNpZW5kbyBzaWduaWZpY2F0aXZhbWVudGUgbcOhcyBwcmVjaXNhIHBhcmEgaWRlbnRpZmljYXIgcGFjaWVudGVzIHNpbiBkaWFiZXRlcyB5IHJlZHVjaWVuZG8gZmFsc29zIHBvc2l0aXZvcy4NCi0gKipBVUM6KiogZmF2b3JlY2UgYW1wbGlhbWVudGUgYSBMb2dpdCAoYHIgYXVjX3ZhbF9yYCB2cyBgciBhdWNfa25uX3ZhbG9yYCksIGNvbmZpcm1hbmRvIHVuYSBjYXBhY2lkYWQgY29uc2lkZXJhYmxlbWVudGUgc3VwZXJpb3IgcGFyYSBkaWZlcmVuY2lhciBlbnRyZSBhbWJhcyBjbGFzZXMgYSBkaXN0aW50b3Mgbml2ZWxlcyBkZSBkZWNpc2nDs24uDQoNCkFtYm9zIG1vZGVsb3MgcHJlc2VudGFuIGZvcnRhbGV6YXMgZGlzdGludGFzLiBLTk4gZGVzdGFjw7MgcG9yIHN1IGFsdGEgc2Vuc2liaWxpZGFkOyBzaW4gZW1iYXJnbywgc3UgYmFqYSBlc3BlY2lmaWNpZGFkIHkgbWVub3IgQVVDIHJlZmxlamFuIG1heW9yIHRlbmRlbmNpYSBhIGNvbWV0ZXIgZmFsc29zIHBvc2l0aXZvcy4gTGEgcmVncmVzacOzbiBsb2fDrXN0aWNhIG5vIHNvbG8gcHJlc2VudMOzIG1lam9yZXMgbcOpdHJpY2FzIGdsb2JhbGVzLCBzaW5vIHF1ZSBhZGVtw6FzIG9mcmVjZSB1bmEgdmVudGFqYSBpbnRlcnByZXRhdGl2YSwgcGVybWl0aWVuZG8gY29tcHJlbmRlciBjw7NtbyBjYWRhIHZhcmlhYmxlIGluZmx1eWUgc29icmUgbGEgcHJvYmFiaWxpZGFkIGRlIGRlc2Fycm9sbGFyIGRpYWJldGVzLiBFbiBjb25zZWN1ZW5jaWEsICoqbGEgcmVncmVzacOzbiBsb2fDrXN0aWNhIHNlIHBvc2ljaW9uYSBjb21vIGVsIG1vZGVsbyBtw6FzIGFkZWN1YWRvKiogcGFyYSBlc3RlIGVzdHVkaW8sIHBvciBzdSBtYXlvciBleGFjdGl0dWQsIG1lam9yIGVzcGVjaWZpY2lkYWQsIHN1cGVyaW9yIEFVQyB5IHV0aWxpZGFkIGludGVycHJldGF0aXZhLg0KPC9kaXY+DQoNCi0tLQ0KDQojIDYuIENvbmNsdXNpb25lcw0KDQo8ZGl2IGNsYXNzPSJhZHZlcnRlbmNpYSI+DQoqKkxpbWl0YWNpb25lcyBkZWwgZXN0dWRpbzoqKiBFbCBhbsOhbGlzaXMgc2UgcmVzdHJpbmdlIGEgbXVqZXJlcyBpbmTDrWdlbmFzIFBpbWEgbWF5b3JlcyBkZSAyMSBhw7FvcywgcG9yIGxvIHF1ZSBsb3MgcmVzdWx0YWRvcyBubyBzb24gZGlyZWN0YW1lbnRlIGdlbmVyYWxpemFibGVzIGEgb3RyYXMgcG9ibGFjaW9uZXMuIFNlIGRldGVjdGFyb24gdmFsb3JlcyBkZSAwIGVuIHZhcmlhYmxlcyBjb21vIGdsdWNvc2EgeSBwcmVzacOzbiBhcnRlcmlhbCBxdWUgcG9kcsOtYW4gY29ycmVzcG9uZGVyIGEgZGF0b3MgZmFsdGFudGVzIG5vIHRyYXRhZG9zIGV4cGzDrWNpdGFtZW50ZSwgbG8gcXVlIHB1ZWRlIGFmZWN0YXIgbGEgY2FwYWNpZGFkIHByZWRpY3RpdmEgZGUgbG9zIG1vZGVsb3MuIExhIHBhcnRpY2nDs24gNzAvMzAgY29uIHNlbWlsbGEgZmlqYSBnYXJhbnRpemEgcmVwcm9kdWNpYmlsaWRhZCwgcGVybyBsb3MgcmVzdWx0YWRvcyBwb2Ryw61hbiB2YXJpYXIgY29uIG90cmFzIHNlbWlsbGFzIGFsZWF0b3JpYXMuDQo8L2Rpdj4NCg0KQSBwYXJ0aXIgZGVsIGFuw6FsaXNpcyBjb21wYXJhdGl2byBlbnRyZSBsb3MgbW9kZWxvcyBLTk4geSBSZWdyZXNpw7NuIExvZ8Otc3RpY2EgcGFyYSBsYSBjbGFzaWZpY2FjacOzbiBkZSBwYWNpZW50ZXMgY29uIGRpYWJldGVzIGVuIGxhIGJhc2UgZGUgZGF0b3MgUGltYSBJbmRpYW5zLCBzZSBjb25jbHV5ZToNCg0KMS4gKipMYSBnbHVjb3NhLCBlbCBCTUkgeSBsYSBlZGFkKiogc29uIGxhcyB2YXJpYWJsZXMgY29uIG1heW9yIHBvZGVyIGRpZmVyZW5jaWFkb3IgZW50cmUgcGFjaWVudGVzIGNvbiB5IHNpbiBkaWFiZXRlcywgY29uZmlybWFuZG8gbG9zIGhhbGxhemdvcyBkZSBsYSBsaXRlcmF0dXJhIGNpZW50w61maWNhIHByZXZpYS4gTGEgcHJlc2nDs24gYXJ0ZXJpYWwgbW9zdHLDsyBsYSBtZW5vciBjYXBhY2lkYWQgZGlzY3JpbWluYXRvcmlhIGluZGl2aWR1YWwuDQoNCjIuICoqRWwgbW9kZWxvIGRlIFJlZ3Jlc2nDs24gTG9nw61zdGljYSBzdXBlcmEgYWwgS05OKiogZW4gZXhhY3RpdHVkIGdsb2JhbCwgZXNwZWNpZmljaWRhZCB5IEFVQyAoYHIgYXVjX3ZhbF9yYCB2cyBgciBhdWNfa25uX3ZhbG9yYCksIGNvbW8gc2UgZXZpZGVuY2lhIHRhbnRvIGVuIGxhIHRhYmxhIGRlIG3DqXRyaWNhcyBjb21vIGVuIGxhcyBjdXJ2YXMgUk9DIGNvbXBhcmF0aXZhcywgY29uc29saWTDoW5kb3NlIGNvbW8gZWwgbW9kZWxvIG3DoXMgcm9idXN0byBkZW50cm8gZGVsIGFuw6FsaXNpcyByZWFsaXphZG8uDQoNCjMuICoqRWwgbW9kZWxvIEtOTiBkZXN0YWPDsyBwb3Igc3UgYWx0YSBzZW5zaWJpbGlkYWQqKiAoODcuNzclKSwgbG8gcXVlIGxvIGNvbnZpZXJ0ZSBlbiB1bmEgYWx0ZXJuYXRpdmEgw7p0aWwgY3VhbmRvIGVsIG9iamV0aXZvIHByaW5jaXBhbCBlcyBkZXRlY3RhciBsYSBtYXlvciBjYW50aWRhZCBwb3NpYmxlIGRlIGNhc29zIHBvc2l0aXZvcywgYXVucXVlIGEgY29zdGEgZGUgdW5hIGVsZXZhZGEgdGFzYSBkZSBmYWxzb3MgcG9zaXRpdm9zLg0KDQo0LiAqKkxhIG9wdGltaXphY2nDs24gZGVsIHVtYnJhbCBkZSBjbGFzaWZpY2FjacOzbioqIG1lZGlhbnRlIGVsIMOtbmRpY2UgZGUgWW91ZGVuIG1lam9yw7MgZWwgYmFsYW5jZSBlbnRyZSBzZW5zaWJpbGlkYWQgeSBlc3BlY2lmaWNpZGFkIGVuIGVsIG1vZGVsbyBMb2dpdCwgcGVybWl0aWVuZG8gdW5hIGNsYXNpZmljYWNpw7NuIG3DoXMgZXF1aWxpYnJhZGEgZW4gYW1iYXMgY2xhc2VzLg0KDQo1LiBEZXNkZSBlbCBwdW50byBkZSB2aXN0YSBjbMOtbmljbywgZGFkbyBxdWUgbG9zICoqZmFsc29zIG5lZ2F0aXZvcyoqIChubyBkZXRlY3RhciB1bmEgZW5mZXJtZWRhZCBwcmVzZW50ZSkgdGllbmVuIGNvbnNlY3VlbmNpYXMgbcOhcyBncmF2ZXMgcXVlIGxvcyBmYWxzb3MgcG9zaXRpdm9zLCBsYSByZWdyZXNpw7NuIGxvZ8Otc3RpY2EgcmVwcmVzZW50YSBsYSBoZXJyYW1pZW50YSBtw6FzIGNvbXBsZXRhIHkgZXF1aWxpYnJhZGEgcGFyYSBlc3RlIHByb2JsZW1hIGRlIGRpYWduw7NzdGljby4NCg0KLS0tDQoNCiMgNy4gUmVmZXJlbmNpYXMNCg0KLSBDREMuICgyMDI0KS4gRmFjdG9yZXMgZGUgcmllc2dvIGRlIGxhIGRpYWJldGVzLiBDZW50ZXJzIGZvciBEaXNlYXNlIENvbnRyb2wgYW5kIFByZXZlbnRpb24uIGh0dHBzOi8vd3d3LmNkYy5nb3YvZGlhYmV0ZXMvZXMvcmlzay1mYWN0b3JzL2ZhY3RvcmVzLWRlLXJpZXNnby1kZS1sYS1kaWFiZXRlcy5odG1sDQotIEdlbmZhci4gKDIwMjEpLiDCv0N1w6FsZXMgc29uIGxvcyB2YWxvcmVzIG5vcm1hbGVzIGRlIGxhIHByZXNpw7NuIGFydGVyaWFsPyBodHRwczovL3d3dy5nZW5mYXIuY29tL3RlLWN1aWRhbW9zL2N1YWxlcy1zb24tbG9zLXZhbG9yZXMtbm9ybWFsZXMtZGUtbGEtcHJlc2lvbi1hcnRlcmlhbC8NCi0gSm9zaGksIFIuIEQuLCAmIERoYWthbCwgQy4gSy4gKDIwMjEpLiBQcmVkaWN0aW5nIHR5cGUgMiBkaWFiZXRlcyB1c2luZyBsb2dpc3RpYyByZWdyZXNzaW9uIGFuZCBtYWNoaW5lIGxlYXJuaW5nIGFwcHJvYWNoZXMuICpJbnRlcm5hdGlvbmFsIEpvdXJuYWwgb2YgRW52aXJvbm1lbnRhbCBSZXNlYXJjaCBhbmQgUHVibGljIEhlYWx0aCwgMTgqKDE0KSwgNzM0Ni4gaHR0cHM6Ly9wbWMubmNiaS5ubG0ubmloLmdvdi9hcnRpY2xlcy9QTUM4MzA2NDg3Lw0KLSBMYWd1bmVzIFRvcnJlcywgQS4gKDIwMjMpLiBSZWxhY2nDs24gZW50cmUgZWwgw61uZGljZSBkZSBtYXNhIGNvcnBvcmFsIHkgbGEgZGlhYmV0ZXMgdGlwbyAyLiAqUmV2aXN0YSBNZXhpY2FuYSBkZSBFbmRvY3Jpbm9sb2fDrWEuKg0KLSBNZWRsaW5lUGx1cy4gKHMuZi4pLiBHbHVjb3NhIGVuIHNhbmdyZS4gaHR0cHM6Ly9tZWRsaW5lcGx1cy5nb3Yvc3BhbmlzaC9ibG9vZGdsdWNvc2UuaHRtbA0KLSBPTVMuIChjaXRhZG8gZW4gUmV2aXN0YSBEaWFiZXRlcywgMjAyNCkuIEhlcmVuY2lhIGRlIG9iZXNpZGFkIHkgZGlhYmV0ZXM6IG3DoXMgYWxsw6EgZGUgbnVlc3Ryb3MgZ2VuZXMuIGh0dHBzOi8vd3d3LnJldmlzdGFkaWFiZXRlcy5vcmcvaW52ZXN0aWdhY2lvbi9oZXJlbmNpYS1kZS1vYmVzaWRhZC15LWRpYWJldGVzLW1hcy1hbGxhLWRlLW51ZXN0cm9zLWdlbmVzLw0KLSBPTVMuICgyMDI1KS4gT2Jlc2lkYWQgeSBzb2JyZXBlc28uIGh0dHBzOi8vd3d3Lndoby5pbnQvZXMvbmV3cy1yb29tL2ZhY3Qtc2hlZXRzL2RldGFpbC9vYmVzaXR5LWFuZC1vdmVyd2VpZ2h0DQotIFNhbXBhbmlzLCBDLiwgJiBaYW1ib3VsaXMsIEMuICgyMDA4KS4gSHlwZXJ0ZW5zaW9uIGFuZCBkaWFiZXRlcyBtZWxsaXR1cy4gKkhpcHBva3JhdGlhLCAxMiooMSksIDEy4oCTMTUuDQotIFdITy4gKDIwMjQpLiBEaWFiZXRlcy4gaHR0cHM6Ly93d3cud2hvLmludC9lcy9uZXdzLXJvb20vZmFjdC1zaGVldHMvZGV0YWlsL2RpYWJldGVzDQoNCi0tLQ0KDQo=