Actividad 04. K-Medias (Distancia - Canberra y
Gap_Stat)
Introducción
El Análisis de Clusters mediante el Algoritmo de K-Medias es un
algoritmo de agrupamiento no supervisado que divide un conjunto de datos
en K grupos o clústeres. Su objetivo es minimizar la varianza
intra-clúster (la distancia entre los puntos y su centroide). Se
caracteriza porque requiere especificar el número de clústeres (K),asume
que los clústeres son esféricos y de similar tamaño; y comúnmente
utilizala distancia Euclidiana pero se puede adaptar a otras métricas
(como Canberra).
La distancia de Canberra es una medida de disimilitud entre dos
vectores numéricos. Es útil cuando el análisis de datos cuenta con
muchas dimensiones (features), principalmente cuando los datos contienen
valores cercanos a cero, ya que penaliza más las pequeñas diferencias
relativas.
Asimismo, el Estadístico de Brecha (Gap Statistic) es una técnica
utilizada para determinar el número óptimo de clústeres (k) al aplicar
el algoritmo K-Means. A diferencia del método del codo (Elbow Method),
que se basa únicamente en la variación interna de los clústeres (Wk), el
Gap Statistic compara ese valor con el esperado bajo una distribución de
referencia aleatoria, es decir, sin una estructura de clústeres
definida. Mientras que el método del codo identifica el k óptimo
mediante un punto de inflexión en la curva de Wk, el Gap Statistic
selecciona el valor de k en el que la diferencia entre el logaritmo de
la dispersión observada y la esperada (log(Wk)) es máxima y presenta
estabilidad. Dicho enfoque es especialmente recomendable en escenarios
donde los datos contienen ruido o la estructura de los clústeres no es
evidente a simple vista.
EDA
A continuación se carga la base de datos a ser analizada: ‘USArrests’
de la librería ‘spData’. El presente conjunto de datos proporciona una
visión cuantitativa de la criminalidad registrada en los Estados Unidos
en 1973, enfocándose en tres delitos graves: homicidio, asalto y
violación. Cada una de estas categorías muestra la tasa de arrestos por
cada 100,000 habitantes en los 50 estados del país. Además, se incluye
una variable que representa el grado de urbanización de cada estado,
expresado como el porcentaje de la población que reside en zonas
urbanas. Esta información es útil para analizar la relación entre el
entorno urbano y la incidencia delictiva, así como para identificar
patrones geográficos y sociales relacionados con la criminalidad en ese
periodo histórico.
data("USArrests")
head(USArrests)
## Murder Assault UrbanPop Rape
## Alabama 13.2 236 58 21.2
## Alaska 10.0 263 48 44.5
## Arizona 8.1 294 80 31.0
## Arkansas 8.8 190 50 19.5
## California 9.0 276 91 40.6
## Colorado 7.9 204 78 38.7
## Rows: 50
## Columns: 4
## $ Murder <dbl> 13.2, 10.0, 8.1, 8.8, 9.0, 7.9, 3.3, 5.9, 15.4, 17.4, 5.3, 2.…
## $ Assault <int> 236, 263, 294, 190, 276, 204, 110, 238, 335, 211, 46, 120, 24…
## $ UrbanPop <int> 58, 48, 80, 50, 91, 78, 77, 72, 80, 60, 83, 54, 83, 65, 57, 6…
## $ Rape <dbl> 21.2, 44.5, 31.0, 19.5, 40.6, 38.7, 11.1, 15.8, 31.9, 25.8, 2…
Con base al EDA se determina que existen dos patrones claros de
criminalidad entre los estados de EE.UU. representados en los clusters,
donde un cluster representa estados con alta criminalidad; y el otro,
estados con baja criminalidad. Lo anterior debido a que las variables
Murder, Assault y Rape están negativamente correlacionadas con el número
de cluster asignado (r ≈ -0.83), lo que sugiere que los clusters
capturan niveles distintos de criminalidad.
Correlaciones
Murder y Assault: Correlación fuerte y positiva (r ≈ 0.80),
indicando que los estados con mayor tasa de asesinatos tienden también a
tener mayores tasas de asaltos.
Rape se correlaciona de forma moderada con: Assault (r ≈ 0.66)
& Murder (r ≈ 0.56)
UrbanPop (porcentaje de población urbana) muestra baja o nula
correlación con otras variables, lo que sugiere que la urbanización no
se asocia directamente con las tasas de crimen reportadas en este
conjunto de datos.
Distribución de variables
Murder y Assault están sesgadas a la derecha, indicando que la
mayoría de los estados tienen tasas bajas, pero algunos tienen valores
muy altos.
Rape también tiene cierta asimetría. Mientras que, UrbanPop tiene
una distribución más uniforme.
Los gráficos de dispersión muestran agrupaciones claras, sobre
todo entre variables altamente correlacionadas (como Murder
vs. Assault).
library(ggplot2)
library(GGally)
# Histogramas
USArrests_long <- USArrests %>%
tidyr::pivot_longer(cols = everything(), names_to = "Variable", values_to = "Valor")
ggplot(USArrests_long, aes(x = Valor)) +
geom_histogram(bins = 20, fill = "steelblue", color = "black") +
facet_wrap(~ Variable, scales = "free", ncol = 2) +
labs(title = "Histogramas de variables en USArrests") +
theme_minimal()

# Boxplots
ggplot(USArrests_long, aes(x = Variable, y = Valor, fill = Variable)) +
geom_boxplot() +
labs(title = "Boxplots por variable en USArrests") +
theme_minimal() +
theme(legend.position = "none")

# Matriz de correlación
ggpairs(USArrests,
lower = list(continuous = "smooth"),
diag = list(continuous = "barDiag"),
upper = list(continuous = "cor")) +
ggtitle("Matriz de correlación y relaciones entre variables en USArrests")

Escala de variables
Al momento de realizar el análisis de conglomerados se estandarizan
todas las variables, para evitar dar un mayor peso a una variable por
tener magnitudes mayores
scaled <- USArrests %>%
scale() %>%
as.data.frame()
#Verificar brevemente que en efecto nuestra nueva base de datos esté centrada en '0' y tenga desviación estándar unitaria ('1')
print("Means")
## [1] "Means"
sapply(scaled, mean) %>% round(4)
## Murder Assault UrbanPop Rape
## 0 0 0 0
print("Standard Deviations")
## [1] "Standard Deviations"
## Murder Assault UrbanPop Rape
## 1 1 1 1
## 'data.frame': 50 obs. of 4 variables:
## $ Murder : num 1.2426 0.5079 0.0716 0.2323 0.2783 ...
## $ Assault : num 0.783 1.107 1.479 0.231 1.263 ...
## $ UrbanPop: num -0.521 -1.212 0.999 -1.074 1.759 ...
## $ Rape : num -0.00342 2.4842 1.04288 -0.18492 2.06782 ...
Análisis de la viabilidad de esta base de datos a contener
conglomerados
set.seed(2025)
cluster_td <-
get_clust_tendency(
scaled,
n = 25,
gradient = list(low = "white",
high = "steelblue")
)
cluster_td$plot #Se pueden identificar dos posibles clusters.

Muestra y análisis del Estadístico de Hopkin
Se obtiene un valor de 0.61 que al estar cercano a 1, indica que los
datos tienen una tendencia a formar clústeres (estructura no
aleatoria).
## [1] 0.6115733
# El estadistico es cercano a 1 (0.61), lo cual indica que el dataset tiene tendencia a ser clusterizada.
Matriz de similitudes con la función de distancia Canberra y
Gap_Stat
Distancia Canberra:
El primer gráfico (Euclídeo) muestra similitudes pero con
patrones menos claros.
La matriz de distancia Canberra muestra divisiones más marcadas,
lo que facilita la detección de grupos.
Áreas blancas indican gran similitud; áreas oscuras, gran
diferencia.
fviz_dist(
get_dist(scaled, method="canberra"),
order = TRUE,
show_labels = FALSE,
lab_size = NULL,
gradient = list(low = "white", high = "steelblue")
)

#Utilizando la distancia 'Canberra' se ven mucho más claros los dos posibles clusters.
Número óptimo de Clusters ‘k’
Gap Statistic:
Se obtuvo que el máximo valor del gap para k = 2, lo que sugiere que
2 grupos es lo más adecuado.
#Gap_Stat
fviz_nbclust(scaled, kmeans, method = "gap_stat") # 2 o 3 clusters

Creación de ‘k’ clusters con el algoritmo
K-medias
set.seed(2025)
km_cluster <- kmeans(scaled, 2, nstart = 25)
USArrests$km_cluster <- km_cluster$cluster
glimpse(USArrests)
## Rows: 50
## Columns: 5
## $ Murder <dbl> 13.2, 10.0, 8.1, 8.8, 9.0, 7.9, 3.3, 5.9, 15.4, 17.4, 5.3, …
## $ Assault <int> 236, 263, 294, 190, 276, 204, 110, 238, 335, 211, 46, 120, …
## $ UrbanPop <int> 58, 48, 80, 50, 91, 78, 77, 72, 80, 60, 83, 54, 83, 65, 57,…
## $ Rape <dbl> 21.2, 44.5, 31.0, 19.5, 40.6, 38.7, 11.1, 15.8, 31.9, 25.8,…
## $ km_cluster <int> 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 1,…
Visualización de ‘k’ clusters
Visualización de distribución de Murder por cluster
Cluster 1: Alta Criminalidad
Mediana ≈ 12 homicidios por 100 000 hab.
IQR ≈ [10 – 14] (el 50 % de los estados en este cluster está
entre esos valores).
Valores máximos llegan a ~18, mínimos cerca de 8.
Cluster 2: Baja Criminalidad
Mediana ≈ 5 homicidios por 100 000 hab.
IQR ≈ [3 – 7].
Rango total entre ~1 y ~11, claramente por debajo de los valores
de Cluster 1.
library(ggplot2)
ggplot(USArrests, aes(x = as.factor(km_cluster), y = Murder, fill = as.factor(km_cluster))) +
geom_boxplot() +
labs(title = "Distribución de 'Murder' por Cluster",
x = "Cluster",
y = "Tasa de Homicidios") +
theme_minimal()

Mapa de EE.UU. coloreado según el cluster asignado a cada
estado
Los estados del norte y oeste tienden a agruparse en el Cluster 2 –
Menor criminalidad, mientras que los estados del sur y este se
concentran en el Cluster 1 – Mayor criminalidad. Esta distribución
sugiere una posible relación entre ubicación geográfica, factores
socioeconómicos y niveles de criminalidad.
El Cluster 1 - Mayor criminalidad agrupa estados
que, según los datos usados en tu análisis, presentan niveles
relativamente más altos de criminalidad:
Sur de EE.UU.: Alabama, Georgia, Louisiana, Mississippi, North
Carolina, South Carolina, Tennessee, Texas. Esta región es consistente
en datos históricos de mayor criminalidad en EE.UU., particularmente en
crímenes violentos.
Costa Oeste y Suroeste: California, Arizona, Nevada, New Mexico,
Colorado. Algunos de estos estados tienen grandes ciudades y corredores
migratorios.
Grandes estados urbanos del norte: Illinois (Chicago), New York
(NYC), Michigan (Detroit), Maryland (Baltimore). En estas zonas la
criminalidad suele estar concentrada en áreas urbanas
específicas.
Los estados agrupados en el “Cluster 2 - Menos
criminalidad”, lo que indica que comparten características
comunes relacionadas con bajos niveles de criminalidad. Dicho clúster
abarca estados de distintas regiones del país:
Noreste: Vermont, New Hampshire, Massachusetts, Maine.
Medio Oeste: Iowa, Minnesota, Wisconsin, Ohio.
Noroeste: Idaho, Montana, Wyoming.
Sur: Arkansas, Kentucky, Virginia, West Virginia.
Pacífico: Oregon, Washington, Hawaii.
library(dplyr)
library(usmap)
library(ggplot2)
# Añadir columna de estado como variable
USArrests$state <- rownames(USArrests)
# Añadir la variable de clúster como factor
USArrests$cluster <- factor(km_cluster$cluster)
# Crear dataframe con nombres de estados compatibles con usmap
USArrests_map <- USArrests %>%
mutate(state = state.name[match(state, state.name)]) %>%
select(state, cluster) %>%
filter(!is.na(state) & !is.na(cluster)) # Asegura que no haya NAs
# Crear el mapa sin "NA" en la leyenda
plot_usmap(data = USArrests_map, values = "cluster", regions = "states") +
scale_fill_manual(
values = c("1" = "steelblue", "2" = "goldenrod"),
name = "Clúster",
na.value = "gray90", # Color de los estados sin datos
na.translate = FALSE # <- Evita que aparezca "NA" en la leyenda
) +
labs(
title = "Clusters de criminalidad en EE.UU. (USArrests)",
subtitle = "k = 2, basado en tasas de Murder, Assault, Rape y UrbanPop"
) +
theme_minimal()

Tabla de centroides estandarizados resultantes del análisis
k-means
tabla_resumen <- USArrests %>%
group_by(cluster) %>%
summarise(
N = n(),
Murder = round(mean(Murder), 2),
Assault = round(mean(Assault), 2),
UrbanPop = round(mean(UrbanPop), 2),
Rape = round(mean(Rape), 2)
)
print(tabla_resumen)
## # A tibble: 2 × 6
## cluster N Murder Assault UrbanPop Rape
## <int> <int> <dbl> <dbl> <dbl> <dbl>
## 1 1 20 12.2 255. 68.4 29.2
## 2 2 30 4.87 114. 63.6 15.9
centroides_std <- as.data.frame(km_cluster$centers) %>%
tibble::rownames_to_column(var = "cluster")
print(centroides_std)
## cluster Murder Assault UrbanPop Rape
## 1 1 1.004934 1.0138274 0.1975853 0.8469650
## 2 2 -0.669956 -0.6758849 -0.1317235 -0.5646433
Modelo de Random Forest para Clasificar
Clusters
El modelo de Random Forest aplicado a la clasificación de clústeres
(resultado de kmeans) se comportó de manera óptima tanto en
entrenamiento como en prueba. El mejor desempeño se logra con mtry = 1,
es decir, considerando solo 1 predictor aleatorio por división.
library(randomForest)
library(caret)
library(randomForest)
library(caret)
library(dplyr)
rf_data <- USArrests %>%
select(Murder, Assault, UrbanPop, Rape) %>%
mutate(km_cluster = as.factor(km_cluster$cluster)) # agregar cluster como variable objetivo
set.seed(123)
index <- createDataPartition(rf_data$km_cluster, p = 0.8, list = FALSE)
train_dt <- rf_data[index, ]
test_dt <- rf_data[-index, ]
trControl <- trainControl(method = "cv", number = 10)
tuneGrid <- expand.grid(mtry = 1:(ncol(train_dt) - 1)) # -1 porque la última es la variable objetivo
set.seed(123)
modelRF <- train(km_cluster ~ .,
data = train_dt,
method = "rf",
trControl = trControl,
tuneGrid = tuneGrid,
ntree = 500)
print(modelRF)
## Random Forest
##
## 40 samples
## 4 predictor
## 2 classes: '1', '2'
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 36, 35, 37, 36, 36, 37, ...
## Resampling results across tuning parameters:
##
## mtry Accuracy Kappa
## 1 1.000 1.00
## 2 0.975 0.95
## 3 0.975 0.95
## 4 0.975 0.95
##
## Accuracy was used to select the optimal model using the largest value.
## The final value used for the model was mtry = 1.
Importancia de variable según Random Forest
Por lo tanto, la criminalidad violenta (Murder, Assault, Rape) define
los clústeres, no tanto la urbanización.
rf_model <- randomForest(km_cluster ~ ., data = train_dt, mtry = modelRF$bestTune$mtry, importance = TRUE)
varImpPlot(rf_model)

varImp(modelRF, scale = TRUE)
## rf variable importance
##
## Overall
## Murder 100.00
## Assault 87.37
## Rape 63.83
## UrbanPop 0.00
Precisión de Random Forest
- El rendimiento en test es perfecto, lo cual puede deberse al tamaño
reducido de muestra (n=10).
preds <- predict(modelRF, newdata = test_dt)
confusionMatrix(preds, test_dt$km_cluster)
## Confusion Matrix and Statistics
##
## Reference
## Prediction 1 2
## 1 4 0
## 2 0 6
##
## Accuracy : 1
## 95% CI : (0.6915, 1)
## No Information Rate : 0.6
## P-Value [Acc > NIR] : 0.006047
##
## Kappa : 1
##
## Mcnemar's Test P-Value : NA
##
## Sensitivity : 1.0
## Specificity : 1.0
## Pos Pred Value : 1.0
## Neg Pred Value : 1.0
## Prevalence : 0.4
## Detection Rate : 0.4
## Detection Prevalence : 0.4
## Balanced Accuracy : 1.0
##
## 'Positive' Class : 1
##
Conclusión
El análisis del conjunto de datos USArrests revela que existen dos
grupos claramente diferenciados entre los estados de EE.UU. en función
de los delitos (asesinato, asalto, violación) y la proporción de
población urbana. La segmentación mediante K-means clustering muestra
una clara separación geográfica y de características criminales. El uso
de métricas de distancia como Canberra, junto con el estadístico de
Hopkins y el método de Gap Statistic, permite confirmar la validez de la
agrupación.
El Clúster 1, compuesto por 20 estados, agrupa principalmente a los
estados del norte y oeste, y se caracteriza por niveles más elevados de
criminalidad en los indicadores analizados. Estos estados presentan
valores por encima del promedio en asesinatos, asaltos y violaciones,
así como una mayor proporción de población urbana.
Por otro lado, el Clúster 2, que incluye a 30 estados del sur y este,
muestra un perfil opuesto: niveles más bajos de delitos violentos y
menor urbanización. Esta división no solo es estadísticamente sólida,
sino que también presenta una clara correspondencia geográfica, lo que
sugiere que los factores regionales pueden estar influyendo en los
patrones delictivos.
Por último, la validación del modelo con un algoritmo de random
forest mostró una exactitud del 100% en la clasificación de los
clústeres, y la importancia de variables indica que los delitos como
asesinato y asalto son los predictores más relevantes en la segmentación
de los estados.
Referencias
Ketchen, D. J., & Shook, C. L. (1996). The application of cluster
analysis in strategic management research: An analysis and critique.
Strategic Management Journal, 17(6), 441–458.
Lance, G. N., & Williams, W. T. (1967). A general theory of
classificatory sorting strategies: I. Hierarchical systems. The Computer
Journal.
Sneath, P.H.A., & Sokal, R.R. (1973). Numerical Taxonomy. W. H.
Freeman and Company.
MacQueen, J. (1967). Some methods for classification and analysis of
multivariate observations. Proceedings of the Fifth Berkeley Symposium
on Mathematical Statistics and Probability.
Tan, P.-N., Steinbach, M., & Kumar, V. (2018). Introduction to
Data Mining. Pearson.
LS0tDQp0aXRsZTogIkNsdXN0ZXJpemFjacOzbiB1dGlsaXphbmRvIEstTWVkaWFzIg0Kc3VidGl0bGU6ICJBY3RpdmlkYWQgMDQiDQphdXRob3I6ICJFcXVpcG8gNyINCmRhdGU6ICIyMDI1LTAzLTI4Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQotLS0NCg0KIVtdKGh0dHBzOi8vY2l0cmlzLXVjLm9yZy93cC1jb250ZW50L3VwbG9hZHMvMjAxOS8xMC9UZWMtZGUtTW9udGVycmV5LWxvZ28taG9yaXpvbnRhbC1ibHVlLnBuZykNCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyIj4NCiAgPHA+PHN0cm9uZz5QbGFuZWFjacOzbiBlc3RyYXTDqWdpY2EgYmFzYWRhIGVuIGFuYWzDrXRpY2EgcHJlc2NyaXB0aXZhPC9zdHJvbmc+PC9wPg0KICA8cD48c3Ryb25nPkdydXBvIDUwMzwvc3Ryb25nPjwvcD4NCiAgPHA+PHN0cm9uZz5Qcm9mZXNvciBSb2RvbGZvIE1pZ3VlbCBHYW1lcm9zPC9zdHJvbmc+PC9wPg0KPC9kaXY+DQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlciI+DQogIDxwPjxzdHJvbmc+RXF1aXBvIDc6PC9zdHJvbmc+PC9wPg0KICA8cD5BMDA4MzMxMTMgLSBBdnJpbCBMb2JhdG88L3A+DQogIDxwPkEwMTc3MTEyNyAtIExlc2x5IERhcmlhbiBSb21lcm8gVsOhenF1ZXo8L3A+DQogIDxwPkEwMDgzMTEwNSAtIEphem3DrW4gZGVsIENhcm1lbiBDb3J0ZXogTWVuZG96YTwvcD4NCiAgPHA+QTAxMjg0NjExIC0gTGlzc2V0IEhlcm7DoW5kZXo8L3A+DQo8L2Rpdj4NCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoDQoJZWNobyA9IFRSVUUsDQoJbWVzc2FnZSA9IEZBTFNFLA0KCXdhcm5pbmcgPSBGQUxTRQ0KKQ0KI2luc3RhbGwucGFja2FnZXMoInJuYXR1cmFsZWFydGhoaXJlcyIsIHJlcG9zID0gImh0dHBzOi8vcGFja2FnZXMucm9wZW5zY2kub3JnIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpDQpwYWNtYW46OnBfbG9hZChkcGx5ciwgZ2dwbG90MiwgY2FyLCB0c2VyaWVzLCBjb3JycGxvdCwgcGF0Y2h3b3JrLCByZWFkeGwsIHBzeWNoLCBtYXBzLCBNQVNTLCBBRVIsIHF1YW50bW9kLCBzdGF0cywgc2NhbGVzLCBkbG9va3IsIERhdGFFeHBsb3JlciwgdGlkeXIsIGtuaXRyLCBSQ29sb3JCcmV3ZXIsIHBsb3RseSwgZm9yZWNhc3QsIHRzZXJpZXMsIG9wZW54bHN4LCB2YXJzLCB0aWR5dmVyc2UsIGxtdGVzdCwgdXJjYSwgYVRTQSwgZmFjdG9leHRyYSwgZ2dwbG90MiwgbmFuaWFyLCB0c2VyaWVzLCBjb3JycGxvdCwgcGF0Y2h3b3JrLCByZWFkeGwsIHBzeWNoLCBtYXBzLCBzZiwgcm5hdHVyYWxlYXJ0aCwgcm5hdHVyYWxlYXJ0aGRhdGEsIHN0cmluZ2ksIHNjYWxlcywgZGxvb2tyLCBEYXRhRXhwbG9yZXIsIHRpZHlyLCBrbml0ciwgUkNvbG9yQnJld2VyLCBwbG90bHksIGZvcmVjYXN0LCB0c2VyaWVzLCBvcGVueGxzeCwgdmFycywgbG10ZXN0LCB0aWJibGUsIFNNQ1JNLCBjYXJldCwgcmFuZG9tRm9yZXN0LCB0cmVlKQ0KYGBgDQoNCiMgKipBY3RpdmlkYWQgMDQuIEstTWVkaWFzIChEaXN0YW5jaWEgLSBDYW5iZXJyYSB5IEdhcF9TdGF0KSoqDQoNCiMjICoqSW50cm9kdWNjacOzbioqDQoNCkVsIEFuw6FsaXNpcyBkZSBDbHVzdGVycyBtZWRpYW50ZSBlbCBBbGdvcml0bW8gZGUgSy1NZWRpYXMgZXMgdW4gYWxnb3JpdG1vIGRlIGFncnVwYW1pZW50byBubyBzdXBlcnZpc2FkbyBxdWUgZGl2aWRlIHVuIGNvbmp1bnRvIGRlIGRhdG9zIGVuIEsgZ3J1cG9zIG8gY2zDunN0ZXJlcy4gU3Ugb2JqZXRpdm8gZXMgbWluaW1pemFyIGxhIHZhcmlhbnphIGludHJhLWNsw7pzdGVyIChsYSBkaXN0YW5jaWEgZW50cmUgbG9zIHB1bnRvcyB5IHN1IGNlbnRyb2lkZSkuIFNlIGNhcmFjdGVyaXphIHBvcnF1ZSByZXF1aWVyZSBlc3BlY2lmaWNhciBlbCBuw7ptZXJvIGRlIGNsw7pzdGVyZXMgKEspLGFzdW1lIHF1ZSBsb3MgY2zDunN0ZXJlcyBzb24gZXNmw6lyaWNvcyB5IGRlIHNpbWlsYXIgdGFtYcOxbzsgeSBjb23Dum5tZW50ZSB1dGlsaXphbGEgZGlzdGFuY2lhIEV1Y2xpZGlhbmEgcGVybyBzZSBwdWVkZSBhZGFwdGFyIGEgb3RyYXMgbcOpdHJpY2FzIChjb21vIENhbmJlcnJhKS4NCg0KTGEgZGlzdGFuY2lhIGRlIENhbmJlcnJhIGVzIHVuYSBtZWRpZGEgZGUgZGlzaW1pbGl0dWQgZW50cmUgZG9zIHZlY3RvcmVzIG51bcOpcmljb3MuIEVzIMO6dGlsIGN1YW5kbyBlbCBhbsOhbGlzaXMgZGUgZGF0b3MgY3VlbnRhIGNvbiBtdWNoYXMgZGltZW5zaW9uZXMgKGZlYXR1cmVzKSwgcHJpbmNpcGFsbWVudGUgY3VhbmRvIGxvcyBkYXRvcyBjb250aWVuZW4gdmFsb3JlcyBjZXJjYW5vcyBhIGNlcm8sIHlhIHF1ZSBwZW5hbGl6YSBtw6FzIGxhcyBwZXF1ZcOxYXMgZGlmZXJlbmNpYXMgcmVsYXRpdmFzLg0KDQpBc2ltaXNtbywgZWwgRXN0YWTDrXN0aWNvIGRlIEJyZWNoYSAoR2FwIFN0YXRpc3RpYykgZXMgdW5hIHTDqWNuaWNhIHV0aWxpemFkYSBwYXJhIGRldGVybWluYXIgZWwgbsO6bWVybyDDs3B0aW1vIGRlIGNsw7pzdGVyZXMgKGspIGFsIGFwbGljYXIgZWwgYWxnb3JpdG1vIEstTWVhbnMuIEEgZGlmZXJlbmNpYSBkZWwgbcOpdG9kbyBkZWwgY29kbyAoRWxib3cgTWV0aG9kKSwgcXVlIHNlIGJhc2Egw7puaWNhbWVudGUgZW4gbGEgdmFyaWFjacOzbiBpbnRlcm5hIGRlIGxvcyBjbMO6c3RlcmVzIChXayksIGVsIEdhcCBTdGF0aXN0aWMgY29tcGFyYSBlc2UgdmFsb3IgY29uIGVsIGVzcGVyYWRvIGJham8gdW5hIGRpc3RyaWJ1Y2nDs24gZGUgcmVmZXJlbmNpYSBhbGVhdG9yaWEsIGVzIGRlY2lyLCBzaW4gdW5hIGVzdHJ1Y3R1cmEgZGUgY2zDunN0ZXJlcyBkZWZpbmlkYS4gTWllbnRyYXMgcXVlIGVsIG3DqXRvZG8gZGVsIGNvZG8gaWRlbnRpZmljYSBlbCBrIMOzcHRpbW8gbWVkaWFudGUgdW4gcHVudG8gZGUgaW5mbGV4acOzbiBlbiBsYSBjdXJ2YSBkZSBXaywgZWwgR2FwIFN0YXRpc3RpYyBzZWxlY2Npb25hIGVsIHZhbG9yIGRlIGsgZW4gZWwgcXVlIGxhIGRpZmVyZW5jaWEgZW50cmUgZWwgbG9nYXJpdG1vIGRlIGxhIGRpc3BlcnNpw7NuIG9ic2VydmFkYSB5IGxhIGVzcGVyYWRhIChsb2coV2spKSBlcyBtw6F4aW1hIHkgcHJlc2VudGEgZXN0YWJpbGlkYWQuIERpY2hvIGVuZm9xdWUgZXMgZXNwZWNpYWxtZW50ZSByZWNvbWVuZGFibGUgZW4gZXNjZW5hcmlvcyBkb25kZSBsb3MgZGF0b3MgY29udGllbmVuIHJ1aWRvIG8gbGEgZXN0cnVjdHVyYSBkZSBsb3MgY2zDunN0ZXJlcyBubyBlcyBldmlkZW50ZSBhIHNpbXBsZSB2aXN0YS4NCg0KDQojIyAqKkVEQSoqDQoNCkEgY29udGludWFjacOzbiBzZSBjYXJnYSBsYSBiYXNlIGRlIGRhdG9zIGEgc2VyIGFuYWxpemFkYTogJ1VTQXJyZXN0cycgZGUgbGEgbGlicmVyw61hICdzcERhdGEnLiBFbCBwcmVzZW50ZSBjb25qdW50byBkZSBkYXRvcyBwcm9wb3JjaW9uYSB1bmEgdmlzacOzbiBjdWFudGl0YXRpdmEgZGUgbGEgY3JpbWluYWxpZGFkIHJlZ2lzdHJhZGEgZW4gbG9zIEVzdGFkb3MgVW5pZG9zIGVuIDE5NzMsIGVuZm9jw6FuZG9zZSBlbiB0cmVzIGRlbGl0b3MgZ3JhdmVzOiBob21pY2lkaW8sIGFzYWx0byB5IHZpb2xhY2nDs24uIENhZGEgdW5hIGRlIGVzdGFzIGNhdGVnb3LDrWFzIG11ZXN0cmEgbGEgdGFzYSBkZSBhcnJlc3RvcyBwb3IgY2FkYSAxMDAsMDAwIGhhYml0YW50ZXMgZW4gbG9zIDUwIGVzdGFkb3MgZGVsIHBhw61zLiBBZGVtw6FzLCBzZSBpbmNsdXllIHVuYSB2YXJpYWJsZSBxdWUgcmVwcmVzZW50YSBlbCBncmFkbyBkZSB1cmJhbml6YWNpw7NuIGRlIGNhZGEgZXN0YWRvLCBleHByZXNhZG8gY29tbyBlbCBwb3JjZW50YWplIGRlIGxhIHBvYmxhY2nDs24gcXVlIHJlc2lkZSBlbiB6b25hcyB1cmJhbmFzLiBFc3RhIGluZm9ybWFjacOzbiBlcyDDunRpbCBwYXJhIGFuYWxpemFyIGxhIHJlbGFjacOzbiBlbnRyZSBlbCBlbnRvcm5vIHVyYmFubyB5IGxhIGluY2lkZW5jaWEgZGVsaWN0aXZhLCBhc8OtIGNvbW8gcGFyYSBpZGVudGlmaWNhciBwYXRyb25lcyBnZW9ncsOhZmljb3MgeSBzb2NpYWxlcyByZWxhY2lvbmFkb3MgY29uIGxhIGNyaW1pbmFsaWRhZCBlbiBlc2UgcGVyaW9kbyBoaXN0w7NyaWNvLg0KDQpgYGB7cn0NCmRhdGEoIlVTQXJyZXN0cyIpDQpoZWFkKFVTQXJyZXN0cykNCmdsaW1wc2UoVVNBcnJlc3RzKQ0KYGBgDQoNCkNvbiBiYXNlIGFsIEVEQSBzZSBkZXRlcm1pbmEgcXVlIGV4aXN0ZW4gZG9zIHBhdHJvbmVzIGNsYXJvcyBkZSBjcmltaW5hbGlkYWQgZW50cmUgbG9zIGVzdGFkb3MgZGUgRUUuVVUuIHJlcHJlc2VudGFkb3MgZW4gbG9zIGNsdXN0ZXJzLCBkb25kZSB1biBjbHVzdGVyIHJlcHJlc2VudGEgZXN0YWRvcyBjb24gYWx0YSBjcmltaW5hbGlkYWQ7IHkgZWwgb3RybywgZXN0YWRvcyBjb24gYmFqYSBjcmltaW5hbGlkYWQuIExvIGFudGVyaW9yIGRlYmlkbyBhIHF1ZSBsYXMgdmFyaWFibGVzIE11cmRlciwgQXNzYXVsdCB5IFJhcGUgZXN0w6FuIG5lZ2F0aXZhbWVudGUgY29ycmVsYWNpb25hZGFzIGNvbiBlbCBuw7ptZXJvIGRlIGNsdXN0ZXIgYXNpZ25hZG8gKHIg4omIIC0wLjgzKSwgbG8gcXVlIHN1Z2llcmUgcXVlIGxvcyBjbHVzdGVycyBjYXB0dXJhbiBuaXZlbGVzIGRpc3RpbnRvcyBkZSBjcmltaW5hbGlkYWQuDQoNCioqQ29ycmVsYWNpb25lcyoqDQoNCiogTXVyZGVyIHkgQXNzYXVsdDogQ29ycmVsYWNpw7NuIGZ1ZXJ0ZSB5IHBvc2l0aXZhIChyIOKJiCAwLjgwKSwgaW5kaWNhbmRvIHF1ZSBsb3MgZXN0YWRvcyBjb24gbWF5b3IgdGFzYSBkZSBhc2VzaW5hdG9zIHRpZW5kZW4gdGFtYmnDqW4gYSB0ZW5lciBtYXlvcmVzIHRhc2FzIGRlIGFzYWx0b3MuDQoNCiogUmFwZSBzZSBjb3JyZWxhY2lvbmEgZGUgZm9ybWEgbW9kZXJhZGEgY29uOiBBc3NhdWx0IChyIOKJiCAwLjY2KSAmIE11cmRlciAociDiiYggMC41NikNCg0KKiBVcmJhblBvcCAocG9yY2VudGFqZSBkZSBwb2JsYWNpw7NuIHVyYmFuYSkgbXVlc3RyYSBiYWphIG8gbnVsYSBjb3JyZWxhY2nDs24gY29uIG90cmFzIHZhcmlhYmxlcywgbG8gcXVlIHN1Z2llcmUgcXVlIGxhIHVyYmFuaXphY2nDs24gbm8gc2UgYXNvY2lhIGRpcmVjdGFtZW50ZSBjb24gbGFzIHRhc2FzIGRlIGNyaW1lbiByZXBvcnRhZGFzIGVuIGVzdGUgY29uanVudG8gZGUgZGF0b3MuDQoNCioqRGlzdHJpYnVjacOzbiBkZSB2YXJpYWJsZXMqKg0KDQoqIE11cmRlciB5IEFzc2F1bHQgZXN0w6FuIHNlc2dhZGFzIGEgbGEgZGVyZWNoYSwgaW5kaWNhbmRvIHF1ZSBsYSBtYXlvcsOtYSBkZSBsb3MgZXN0YWRvcyB0aWVuZW4gdGFzYXMgYmFqYXMsIHBlcm8gYWxndW5vcyB0aWVuZW4gdmFsb3JlcyBtdXkgYWx0b3MuDQoNCiogUmFwZSB0YW1iacOpbiB0aWVuZSBjaWVydGEgYXNpbWV0csOtYS4gTWllbnRyYXMgcXVlLCBVcmJhblBvcCB0aWVuZSB1bmEgZGlzdHJpYnVjacOzbiBtw6FzIHVuaWZvcm1lLg0KDQoqIExvcyBncsOhZmljb3MgZGUgZGlzcGVyc2nDs24gbXVlc3RyYW4gYWdydXBhY2lvbmVzIGNsYXJhcywgc29icmUgdG9kbyBlbnRyZSB2YXJpYWJsZXMgYWx0YW1lbnRlIGNvcnJlbGFjaW9uYWRhcyAoY29tbyBNdXJkZXIgdnMuIEFzc2F1bHQpLg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoR0dhbGx5KQ0KIyBIaXN0b2dyYW1hcyANClVTQXJyZXN0c19sb25nIDwtIFVTQXJyZXN0cyAlPiUNCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLCBuYW1lc190byA9ICJWYXJpYWJsZSIsIHZhbHVlc190byA9ICJWYWxvciIpDQoNCmdncGxvdChVU0FycmVzdHNfbG9uZywgYWVzKHggPSBWYWxvcikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDIwLCBmaWxsID0gInN0ZWVsYmx1ZSIsIGNvbG9yID0gImJsYWNrIikgKw0KICBmYWNldF93cmFwKH4gVmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlIiwgbmNvbCA9IDIpICsNCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW1hcyBkZSB2YXJpYWJsZXMgZW4gVVNBcnJlc3RzIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBCb3hwbG90cw0KZ2dwbG90KFVTQXJyZXN0c19sb25nLCBhZXMoeCA9IFZhcmlhYmxlLCB5ID0gVmFsb3IsIGZpbGwgPSBWYXJpYWJsZSkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKHRpdGxlID0gIkJveHBsb3RzIHBvciB2YXJpYWJsZSBlbiBVU0FycmVzdHMiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KIyBNYXRyaXogZGUgY29ycmVsYWNpw7NuDQpnZ3BhaXJzKFVTQXJyZXN0cywNCiAgICAgICAgbG93ZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSAic21vb3RoIiksDQogICAgICAgIGRpYWcgPSBsaXN0KGNvbnRpbnVvdXMgPSAiYmFyRGlhZyIpLA0KICAgICAgICB1cHBlciA9IGxpc3QoY29udGludW91cyA9ICJjb3IiKSkgKw0KICBnZ3RpdGxlKCJNYXRyaXogZGUgY29ycmVsYWNpw7NuIHkgcmVsYWNpb25lcyBlbnRyZSB2YXJpYWJsZXMgZW4gVVNBcnJlc3RzIikNCmBgYA0KDQoNCiMjICoqRXNjYWxhIGRlIHZhcmlhYmxlcyoqDQoNCkFsIG1vbWVudG8gZGUgcmVhbGl6YXIgZWwgYW7DoWxpc2lzIGRlIGNvbmdsb21lcmFkb3Mgc2UgZXN0YW5kYXJpemFuIHRvZGFzIGxhcyB2YXJpYWJsZXMsIHBhcmEgZXZpdGFyIGRhciB1biBtYXlvciBwZXNvIGEgdW5hIHZhcmlhYmxlIHBvciB0ZW5lciBtYWduaXR1ZGVzIG1heW9yZXMNCg0KYGBge3J9DQpzY2FsZWQgPC0gVVNBcnJlc3RzICU+JQ0KICBzY2FsZSgpICU+JSANCiAgYXMuZGF0YS5mcmFtZSgpDQoNCiNWZXJpZmljYXIgYnJldmVtZW50ZSBxdWUgZW4gZWZlY3RvIG51ZXN0cmEgbnVldmEgYmFzZSBkZSBkYXRvcyBlc3TDqSBjZW50cmFkYSBlbiAnMCcgeSB0ZW5nYSBkZXN2aWFjacOzbiBlc3TDoW5kYXIgdW5pdGFyaWEgKCcxJykNCnByaW50KCJNZWFucyIpDQpzYXBwbHkoc2NhbGVkLCBtZWFuKSAlPiUgIHJvdW5kKDQpDQpwcmludCgiU3RhbmRhcmQgRGV2aWF0aW9ucyIpDQpzYXBwbHkoc2NhbGVkLCBzZCkNCg0Kc3RyKHNjYWxlZCkNCmBgYA0KDQojIyAqKkFuw6FsaXNpcyBkZSBsYSB2aWFiaWxpZGFkIGRlIGVzdGEgYmFzZSBkZSBkYXRvcyBhIGNvbnRlbmVyIGNvbmdsb21lcmFkb3MqKg0KYGBge3J9DQpzZXQuc2VlZCgyMDI1KQ0KDQpjbHVzdGVyX3RkIDwtIA0KICBnZXRfY2x1c3RfdGVuZGVuY3koDQogICAgc2NhbGVkLA0KICAgIG4gPSAyNSwNCiAgICBncmFkaWVudCA9IGxpc3QobG93ID0gIndoaXRlIiwgIA0KICAgICAgICAgICAgICAgICAgICBoaWdoID0gInN0ZWVsYmx1ZSIpDQogICAgKQ0KDQpjbHVzdGVyX3RkJHBsb3QgI1NlIHB1ZWRlbiBpZGVudGlmaWNhciBkb3MgcG9zaWJsZXMgY2x1c3RlcnMuDQpgYGANCg0KIyMgKipNdWVzdHJhIHkgYW7DoWxpc2lzIGRlbCBFc3RhZMOtc3RpY28gZGUgSG9wa2luKioNCg0KU2Ugb2J0aWVuZSB1biB2YWxvciBkZSAwLjYxIHF1ZSBhbCBlc3RhciBjZXJjYW5vIGEgMSwgaW5kaWNhIHF1ZSBsb3MgZGF0b3MgdGllbmVuIHVuYSB0ZW5kZW5jaWEgYSBmb3JtYXIgY2zDunN0ZXJlcyAoZXN0cnVjdHVyYSBubyBhbGVhdG9yaWEpLg0KDQpgYGB7cn0NCmNsdXN0ZXJfdGQkaG9wa2luc19zdGF0IA0KDQojIEVsIGVzdGFkaXN0aWNvIGVzIGNlcmNhbm8gYSAxICgwLjYxKSwgbG8gY3VhbCBpbmRpY2EgcXVlIGVsIGRhdGFzZXQgdGllbmUgdGVuZGVuY2lhIGEgc2VyICAgY2x1c3Rlcml6YWRhLiANCmBgYA0KDQojIyAqKk1hdHJpeiBkZSBzaW1pbGl0dWRlcyBjb24gbGEgZnVuY2nDs24gZGUgZGlzdGFuY2lhIENhbmJlcnJhIHkgR2FwX1N0YXQqKg0KDQoqKkRpc3RhbmNpYSBDYW5iZXJyYToqKg0KDQoqIEVsIHByaW1lciBncsOhZmljbyAoRXVjbMOtZGVvKSBtdWVzdHJhIHNpbWlsaXR1ZGVzIHBlcm8gY29uIHBhdHJvbmVzIG1lbm9zIGNsYXJvcy4NCg0KKiBMYSBtYXRyaXogZGUgZGlzdGFuY2lhIENhbmJlcnJhIG11ZXN0cmEgZGl2aXNpb25lcyBtw6FzIG1hcmNhZGFzLCBsbyBxdWUgZmFjaWxpdGEgbGEgZGV0ZWNjacOzbiBkZSBncnVwb3MuDQoNCiogw4FyZWFzIGJsYW5jYXMgaW5kaWNhbiBncmFuIHNpbWlsaXR1ZDsgw6FyZWFzIG9zY3VyYXMsIGdyYW4gZGlmZXJlbmNpYS4NCg0KYGBge3J9DQogZnZpel9kaXN0KA0KICAgICBnZXRfZGlzdChzY2FsZWQsIG1ldGhvZD0iY2FuYmVycmEiKSwNCiAgICAgb3JkZXIgPSBUUlVFLA0KICAgICBzaG93X2xhYmVscyA9IEZBTFNFLA0KICAgICBsYWJfc2l6ZSA9IE5VTEwsDQogICAgIGdyYWRpZW50ID0gbGlzdChsb3cgPSAid2hpdGUiLCBoaWdoID0gInN0ZWVsYmx1ZSIpDQopDQoNCiNVdGlsaXphbmRvIGxhIGRpc3RhbmNpYSAnQ2FuYmVycmEnIHNlIHZlbiBtdWNobyBtw6FzIGNsYXJvcyBsb3MgZG9zIHBvc2libGVzIGNsdXN0ZXJzLiANCmBgYA0KDQojIyAqKk7Dum1lcm8gw7NwdGltbyBkZSBDbHVzdGVycyAnaycqKg0KDQoqKkdhcCBTdGF0aXN0aWM6KioNCg0KU2Ugb2J0dXZvIHF1ZSBlbCBtw6F4aW1vIHZhbG9yIGRlbCBnYXAgcGFyYSBrID0gMiwgbG8gcXVlIHN1Z2llcmUgcXVlIDIgZ3J1cG9zIGVzIGxvIG3DoXMgYWRlY3VhZG8uDQoNCmBgYHtyfQ0KI0dhcF9TdGF0DQpmdml6X25iY2x1c3Qoc2NhbGVkLCBrbWVhbnMsIG1ldGhvZCA9ICJnYXBfc3RhdCIpICMgMiBvIDMgY2x1c3RlcnMNCmBgYA0KDQojIyAqKkNyZWFjacOzbiBkZSAnaycgY2x1c3RlcnMgY29uIGVsIGFsZ29yaXRtbyBLLW1lZGlhcyoqDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMjAyNSkNCmttX2NsdXN0ZXIgPC0ga21lYW5zKHNjYWxlZCwgMiwgbnN0YXJ0ID0gMjUpDQoNClVTQXJyZXN0cyRrbV9jbHVzdGVyIDwtIGttX2NsdXN0ZXIkY2x1c3Rlcg0KZ2xpbXBzZShVU0FycmVzdHMpDQpgYGANCg0KIyMgKipWaXN1YWxpemFjacOzbiBkZSAnaycgY2x1c3RlcnMqKg0KDQojIyMgUmVwcmVzZW50YWNpw7NuIGRlIGxvcyBjbHVzdGVycyBmb3JtYWRvcyBjb24gay1tZWFucw0KDQoqIExvcyBkYXRvcyBzZSBwcm95ZWN0YW4gZW4gMiBkaW1lbnNpb25lcyAocHJvYmFibGVtZW50ZSBQQ0EpIHBhcmEgdmlzdWFsaXphciBsYSBzZXBhcmFjacOzbiBkZSBncnVwb3MuDQoNCiogU2UgaWRlbnRpZmljYW4gZG9zIGdydXBvcyBjbGFyYW1lbnRlIGRpZmVyZW5jaWFkb3MsIGRlc3RhY2Fkb3MgcG9yIGNvbG9yZXMgeSBlbGlwc2VzIHF1ZSBpbmRpY2FuIGxhIGRpc3BlcnNpw7NuIGRlbnRybyBkZSBjYWRhIGNsw7pzdGVyLg0KDQoqIFNlIG11ZXN0cmEgcXVlIE1pc3NvdXJpIGFwYXJlY2UgY29tbyB1biBwdW50byBpbnRlcm1lZGlvIGVudHJlIGFtYm9zIGNsw7pzdGVyZXMsIGxvIHF1ZSBzdWdpZXJlIHF1ZSBjb21wYXJ0ZSBjYXJhY3RlcsOtc3RpY2FzIHRhbnRvIGRlIGVzdGFkb3MgY29uIGFsdGEgY29tbyBjb24gYmFqYSBjcmltaW5hbGlkYWQsIHNpZW5kbyB1biBjYXNvIGxpbcOtdHJvZmUgbyBkZSB0cmFuc2ljacOzbi4NCg0KYGBge3J9DQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KDQojIFBDQQ0KcGNhX3Jlc3VsdCA8LSBwcmNvbXAoc2NhbGVkKQ0KcGNhX2Nvb3JkcyA8LSBhcy5kYXRhLmZyYW1lKHBjYV9yZXN1bHQkeFssIDE6Ml0pDQpwY2FfY29vcmRzJHN0YXRlIDwtIHJvd25hbWVzKFVTQXJyZXN0cykNCnBjYV9jb29yZHMkY2x1c3RlciA8LSBVU0FycmVzdHMkY2x1c3Rlcg0KDQojIEdyw6FmaWNvIGJhc2UgY29uIHB1bnRvcyB5IGVsaXBzZXMNCnBsb3RfYmFzZSA8LSBmdml6X2NsdXN0ZXIob2JqZWN0ID0ga21fY2x1c3RlciwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBzY2FsZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGVsbGlwc2UudHlwZSA9ICJub3JtIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbSA9ICJwb2ludCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHBhbGV0dGUgPSAiamNvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWFpbiA9ICIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpKQ0KDQojIEFncmVnYXIgZXRpcXVldGFzIGRlIGxvcyBlc3RhZG9zIGVuIHN1cyBwdW50b3MNCnBsb3RfYmFzZSArDQogIGdlb21fdGV4dChkYXRhID0gcGNhX2Nvb3JkcywgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGxhYmVsID0gc3RhdGUpLA0KICAgICAgICAgICAgc2l6ZSA9IDMsIHZqdXN0ID0gLTAuNSkNCg0KYGBgDQoNCmBgYHtyfQ0KVVNBcnJlc3RzICU+JQ0KICBncm91cF9ieShrbV9jbHVzdGVyKSAlPiUNCiAgc3VtbWFyaXNlKG1lYW5fbXVyZGVyID0gcm91bmQobWVhbihNdXJkZXIpLCAyKSwNCiAgICAgICAgICAgIG1lYW5fYXNzYXVsdCA9IHJvdW5kKG1lYW4oQXNzYXVsdCksIDIpLA0KICAgICAgICAgICAgbWVhbl91cmJhbnBvcCA9IHJvdW5kKG1lYW4oVXJiYW5Qb3ApLCAyKSwNCiAgICAgICAgICAgIG1lYW5fcmFwZSA9IHJvdW5kKG1lYW4oUmFwZSksIDIpLA0KICAgICAgICAgICAgbWVtYmVycyA9IG4oKSkNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkocGxvdGx5KQ0KDQpwbG90X2x5KGRhdGEgPSBVU0FycmVzdHMsIA0KICAgICAgICB4ID0gfk11cmRlciwgDQogICAgICAgIHkgPSB+QXNzYXVsdCwgDQogICAgICAgIHogPSB+UmFwZSwgDQogICAgICAgIHR5cGUgPSAic2NhdHRlcjNkIiwgDQogICAgICAgIG1vZGUgPSAibWFya2VycyIsIA0KICAgICAgICBjb2xvciA9IGFzLmZhY3RvcihVU0FycmVzdHMka21fY2x1c3RlcikpICU+JQ0KICBsYXlvdXQodGl0bGUgPSAiQ2x1c3RlcnMgZGUgVVNBcnJlc3RzIGVuIDNEIiwNCiAgICAgICAgIHNjZW5lID0gbGlzdCgNCiAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIk11cmRlciIpLA0KICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiQXNzYXVsdCIpLA0KICAgICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAiUmFwZSIpKSkNCmBgYA0KDQojIyMgVmlzdWFsaXphY2nDs24gZGUgZGlzdHJpYnVjacOzbiBkZSBNdXJkZXIgcG9yIGNsdXN0ZXINCg0KKipDbHVzdGVyIDE6IEFsdGEgQ3JpbWluYWxpZGFkKioNCg0KKiBNZWRpYW5hIOKJiCAxMiBob21pY2lkaW9zIHBvciAxMDAgMDAwIGhhYi4NCg0KKiBJUVIg4omIIFsxMCDigJMgMTRdIChlbCA1MCAlIGRlIGxvcyBlc3RhZG9zIGVuIGVzdGUgY2x1c3RlciBlc3TDoSBlbnRyZSBlc29zIHZhbG9yZXMpLg0KDQoqIFZhbG9yZXMgbcOheGltb3MgbGxlZ2FuIGEgfjE4LCBtw61uaW1vcyBjZXJjYSBkZSA4Lg0KDQoqKkNsdXN0ZXIgMjogQmFqYSBDcmltaW5hbGlkYWQqKg0KDQoqIE1lZGlhbmEg4omIIDUgaG9taWNpZGlvcyBwb3IgMTAwIDAwMCBoYWIuDQoNCiogSVFSIOKJiCBbMyDigJMgN10uDQoNCiogUmFuZ28gdG90YWwgZW50cmUgfjEgeSB+MTEsIGNsYXJhbWVudGUgcG9yIGRlYmFqbyBkZSBsb3MgdmFsb3JlcyBkZSBDbHVzdGVyIDEuDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpnZ3Bsb3QoVVNBcnJlc3RzLCBhZXMoeCA9IGFzLmZhY3RvcihrbV9jbHVzdGVyKSwgeSA9IE11cmRlciwgZmlsbCA9IGFzLmZhY3RvcihrbV9jbHVzdGVyKSkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgJ011cmRlcicgcG9yIENsdXN0ZXIiLA0KICAgICAgIHggPSAiQ2x1c3RlciIsDQogICAgICAgeSA9ICJUYXNhIGRlIEhvbWljaWRpb3MiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCg0KIyMjIE1hcGEgZGUgRUUuVVUuIGNvbG9yZWFkbyBzZWfDum4gZWwgY2x1c3RlciBhc2lnbmFkbyBhIGNhZGEgZXN0YWRvDQoNCkxvcyBlc3RhZG9zIGRlbCBub3J0ZSB5IG9lc3RlIHRpZW5kZW4gYSBhZ3J1cGFyc2UgZW4gZWwgQ2x1c3RlciAyIOKAkyBNZW5vciBjcmltaW5hbGlkYWQsIG1pZW50cmFzIHF1ZSBsb3MgZXN0YWRvcyBkZWwgc3VyIHkgZXN0ZSBzZSBjb25jZW50cmFuIGVuIGVsIENsdXN0ZXIgMSDigJMgTWF5b3IgY3JpbWluYWxpZGFkLiBFc3RhIGRpc3RyaWJ1Y2nDs24gc3VnaWVyZSB1bmEgcG9zaWJsZSByZWxhY2nDs24gZW50cmUgdWJpY2FjacOzbiBnZW9ncsOhZmljYSwgZmFjdG9yZXMgc29jaW9lY29uw7NtaWNvcyB5IG5pdmVsZXMgZGUgY3JpbWluYWxpZGFkLg0KDQpFbCAqKkNsdXN0ZXIgMSAtIE1heW9yIGNyaW1pbmFsaWRhZCoqIGFncnVwYSBlc3RhZG9zIHF1ZSwgc2Vnw7puIGxvcyBkYXRvcyB1c2Fkb3MgZW4gdHUgYW7DoWxpc2lzLCBwcmVzZW50YW4gbml2ZWxlcyByZWxhdGl2YW1lbnRlIG3DoXMgYWx0b3MgZGUgY3JpbWluYWxpZGFkOg0KDQoqIFN1ciBkZSBFRS5VVS46IEFsYWJhbWEsIEdlb3JnaWEsIExvdWlzaWFuYSwgTWlzc2lzc2lwcGksIE5vcnRoIENhcm9saW5hLCBTb3V0aCBDYXJvbGluYSwgVGVubmVzc2VlLCBUZXhhcy4gRXN0YSByZWdpw7NuIGVzIGNvbnNpc3RlbnRlIGVuIGRhdG9zIGhpc3TDs3JpY29zIGRlIG1heW9yIGNyaW1pbmFsaWRhZCBlbiBFRS5VVS4sIHBhcnRpY3VsYXJtZW50ZSBlbiBjcsOtbWVuZXMgdmlvbGVudG9zLg0KDQoqIENvc3RhIE9lc3RlIHkgU3Vyb2VzdGU6IENhbGlmb3JuaWEsIEFyaXpvbmEsIE5ldmFkYSwgTmV3IE1leGljbywgQ29sb3JhZG8uIEFsZ3Vub3MgZGUgZXN0b3MgZXN0YWRvcyB0aWVuZW4gZ3JhbmRlcyBjaXVkYWRlcyB5IGNvcnJlZG9yZXMgbWlncmF0b3Jpb3MuDQoNCiogR3JhbmRlcyBlc3RhZG9zIHVyYmFub3MgZGVsIG5vcnRlOiBJbGxpbm9pcyAoQ2hpY2FnbyksIE5ldyBZb3JrIChOWUMpLCBNaWNoaWdhbiAoRGV0cm9pdCksIE1hcnlsYW5kIChCYWx0aW1vcmUpLiBFbiBlc3RhcyB6b25hcyBsYSBjcmltaW5hbGlkYWQgc3VlbGUgZXN0YXIgY29uY2VudHJhZGEgZW4gw6FyZWFzIHVyYmFuYXMgZXNwZWPDrWZpY2FzLg0KDQoNCkxvcyBlc3RhZG9zIGFncnVwYWRvcyBlbiBlbCAqKiJDbHVzdGVyIDIgLSBNZW5vcyBjcmltaW5hbGlkYWQiKiosIGxvIHF1ZSBpbmRpY2EgcXVlIGNvbXBhcnRlbiBjYXJhY3RlcsOtc3RpY2FzIGNvbXVuZXMgcmVsYWNpb25hZGFzIGNvbiBiYWpvcyBuaXZlbGVzIGRlIGNyaW1pbmFsaWRhZC4gRGljaG8gY2zDunN0ZXIgYWJhcmNhIGVzdGFkb3MgZGUgZGlzdGludGFzIHJlZ2lvbmVzIGRlbCBwYcOtczoNCg0KKiBOb3Jlc3RlOiBWZXJtb250LCBOZXcgSGFtcHNoaXJlLCBNYXNzYWNodXNldHRzLCBNYWluZS4NCg0KKiBNZWRpbyBPZXN0ZTogSW93YSwgTWlubmVzb3RhLCBXaXNjb25zaW4sIE9oaW8uDQoNCiogTm9yb2VzdGU6IElkYWhvLCBNb250YW5hLCBXeW9taW5nLg0KDQoqIFN1cjogQXJrYW5zYXMsIEtlbnR1Y2t5LCBWaXJnaW5pYSwgV2VzdCBWaXJnaW5pYS4NCg0KKiBQYWPDrWZpY286IE9yZWdvbiwgV2FzaGluZ3RvbiwgSGF3YWlpLg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHVzbWFwKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIEHDsWFkaXIgY29sdW1uYSBkZSBlc3RhZG8gY29tbyB2YXJpYWJsZQ0KVVNBcnJlc3RzJHN0YXRlIDwtIHJvd25hbWVzKFVTQXJyZXN0cykNCg0KIyBBw7FhZGlyIGxhIHZhcmlhYmxlIGRlIGNsw7pzdGVyIGNvbW8gZmFjdG9yDQpVU0FycmVzdHMkY2x1c3RlciA8LSBmYWN0b3Ioa21fY2x1c3RlciRjbHVzdGVyKQ0KDQojIENyZWFyIGRhdGFmcmFtZSBjb24gbm9tYnJlcyBkZSBlc3RhZG9zIGNvbXBhdGlibGVzIGNvbiB1c21hcA0KVVNBcnJlc3RzX21hcCA8LSBVU0FycmVzdHMgJT4lDQogIG11dGF0ZShzdGF0ZSA9IHN0YXRlLm5hbWVbbWF0Y2goc3RhdGUsIHN0YXRlLm5hbWUpXSkgJT4lDQogIHNlbGVjdChzdGF0ZSwgY2x1c3RlcikgJT4lDQogIGZpbHRlcighaXMubmEoc3RhdGUpICYgIWlzLm5hKGNsdXN0ZXIpKSAgIyBBc2VndXJhIHF1ZSBubyBoYXlhIE5Bcw0KDQojIENyZWFyIGVsIG1hcGEgc2luICJOQSIgZW4gbGEgbGV5ZW5kYQ0KcGxvdF91c21hcChkYXRhID0gVVNBcnJlc3RzX21hcCwgdmFsdWVzID0gImNsdXN0ZXIiLCByZWdpb25zID0gInN0YXRlcyIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwoDQogICAgdmFsdWVzID0gYygiMSIgPSAic3RlZWxibHVlIiwgIjIiID0gImdvbGRlbnJvZCIpLA0KICAgIG5hbWUgPSAiQ2zDunN0ZXIiLA0KICAgIG5hLnZhbHVlID0gImdyYXk5MCIsICAgICAgICMgQ29sb3IgZGUgbG9zIGVzdGFkb3Mgc2luIGRhdG9zDQogICAgbmEudHJhbnNsYXRlID0gRkFMU0UgICAgICAgIyA8LSBFdml0YSBxdWUgYXBhcmV6Y2EgIk5BIiBlbiBsYSBsZXllbmRhDQogICkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkNsdXN0ZXJzIGRlIGNyaW1pbmFsaWRhZCBlbiBFRS5VVS4gKFVTQXJyZXN0cykiLA0KICAgIHN1YnRpdGxlID0gImsgPSAyLCBiYXNhZG8gZW4gdGFzYXMgZGUgTXVyZGVyLCBBc3NhdWx0LCBSYXBlIHkgVXJiYW5Qb3AiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoNCiMjIyBNZWRpYXMgb3JpZ2luYWxlcyBwb3IgY2x1c3RlciB5IGxpc3RhZG8gZGUgZXN0YWRvcyBhZ3J1cGFkb3MNCg0KKiBFbCBDbHVzdGVyIDEgdGllbmUgdmFsb3JlcyBtw6FzIGJham9zIGVuIGNyw61tZW5lcyB5IHBvYmxhY2nDs24gdXJiYW5hLg0KDQoqIEVsIENsdXN0ZXIgMiBhZ3J1cGEgZXN0YWRvcyBjb24gbWF5b3JlcyB0YXNhcyBkZSBhc2FsdG8sIGFzZXNpbmF0bywgdmlvbGFjacOzbiB5IG1heW9yIHVyYmFuaXphY2nDs24uDQoNCkVzdG8gcmVmdWVyemEgbGEgaWRlYSBkZSBxdWUgbG9zIGVzdGFkb3MgbcOhcyB1cmJhbml6YWRvcyB0aWVuZGVuIGEgdGVuZXIgbWF5b3IgaW5jaWRlbmNpYSBkZSBjaWVydG9zIGRlbGl0b3MuDQoNCmBgYHtyfQ0KVVNBcnJlc3RzJGNsdXN0ZXIgPC0ga21fY2x1c3RlciRjbHVzdGVyDQoNCmFnZ3JlZ2F0ZSguIH4gY2x1c3RlciwgDQogICAgICAgICAgZGF0YSA9IFVTQXJyZXN0c1ssIGMoIk11cmRlciIsIkFzc2F1bHQiLCJVcmJhblBvcCIsIlJhcGUiLCJjbHVzdGVyIildLA0KICAgICAgICAgIEZVTiAgPSBtZWFuKQ0KDQpzcGxpdChyb3duYW1lcyhVU0FycmVzdHMpLCBVU0FycmVzdHMkY2x1c3RlcikNCmBgYA0KDQojIyMgVGFibGEgcmVzdW1lbiBkZSB0YW1hw7FvIHkgbWVkaWFzIHBvciBjbHVzdGVyIGVuIHVuaWRhZGVzIG9yaWdpbmFsZXMNCg0KU2UgaWRlbnRpZmljYW4gcXVlIGxvcyBjbHVzdGVycyBlc3RhbiBjb21wdWVzdG9zIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQoNCiogQ2x1c3RlciAxOiAxOSBlc3RhZG9zIGNvbiBtZW5vciBjcmltaW5hbGlkYWQuDQoNCiogQ2x1c3RlciAyOiAzMSBlc3RhZG9zIGNvbiBtYXlvcmVzIHRhc2FzIGRlbGljdGl2YXMuDQoNCmBgYHtyfQ0KbGlicmFyeShrbml0cikNCg0KdGFibGFfcmVzdW1lbiA8LSBVU0FycmVzdHMgJT4lDQogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgTiAgICAgICA9IG4oKSwNCiAgICBNdXJkZXIgID0gcm91bmQobWVhbihNdXJkZXIpLCAyKSwNCiAgICBBc3NhdWx0ID0gcm91bmQobWVhbihBc3NhdWx0KSwgMiksDQogICAgVXJiYW5Qb3A9IHJvdW5kKG1lYW4oVXJiYW5Qb3ApLDIpLA0KICAgIFJhcGUgICAgPSByb3VuZChtZWFuKFJhcGUpLCAyKQ0KICApDQoNCmthYmxlKHRhYmxhX3Jlc3VtZW4sIGNhcHRpb24gPSAiUmVzdW1lbiBwb3IgY2x1c3RlciAodW5pZGFkZXMgb3JpZ2luYWxlcykiKQ0KDQpjZW50cm9pZGVzX3N0ZCA8LSBkYXRhLmZyYW1lKA0KICBjbHVzdGVyID0gcm93bmFtZXMoa21fY2x1c3RlciRjZW50ZXJzKSwNCiAga21fY2x1c3RlciRjZW50ZXJzDQopDQoNCmthYmxlKGNlbnRyb2lkZXNfc3RkLCBkaWdpdHMgPSAzLCBjYXB0aW9uID0gIkNlbnRyb2lkZXMgZXN0YW5kYXJpemFkb3MiKQ0KYGBgDQoNCiMjIyBUYWJsYSBkZSBjZW50cm9pZGVzIGVzdGFuZGFyaXphZG9zIHJlc3VsdGFudGVzIGRlbCBhbsOhbGlzaXMgay1tZWFucw0KYGBge3J9DQp0YWJsYV9yZXN1bWVuIDwtIFVTQXJyZXN0cyAlPiUNCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBOICAgICAgICA9IG4oKSwNCiAgICBNdXJkZXIgICA9IHJvdW5kKG1lYW4oTXVyZGVyKSwgICAyKSwNCiAgICBBc3NhdWx0ICA9IHJvdW5kKG1lYW4oQXNzYXVsdCksICAyKSwNCiAgICBVcmJhblBvcCA9IHJvdW5kKG1lYW4oVXJiYW5Qb3ApLCAyKSwNCiAgICBSYXBlICAgICA9IHJvdW5kKG1lYW4oUmFwZSksICAgICAyKQ0KICApDQoNCnByaW50KHRhYmxhX3Jlc3VtZW4pDQoNCmNlbnRyb2lkZXNfc3RkIDwtIGFzLmRhdGEuZnJhbWUoa21fY2x1c3RlciRjZW50ZXJzKSAlPiUNCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4odmFyID0gImNsdXN0ZXIiKQ0KDQpwcmludChjZW50cm9pZGVzX3N0ZCkNCmBgYA0KDQojIyAqKk1vZGVsbyBkZSBSYW5kb20gRm9yZXN0IHBhcmEgQ2xhc2lmaWNhciBDbHVzdGVycyoqDQoNCkVsIG1vZGVsbyBkZSBSYW5kb20gRm9yZXN0IGFwbGljYWRvIGEgbGEgY2xhc2lmaWNhY2nDs24gZGUgY2zDunN0ZXJlcyAocmVzdWx0YWRvIGRlIGttZWFucykgc2UgY29tcG9ydMOzIGRlIG1hbmVyYSDDs3B0aW1hIHRhbnRvIGVuIGVudHJlbmFtaWVudG8gY29tbyBlbiBwcnVlYmEuIEVsIG1lam9yIGRlc2VtcGXDsW8gc2UgbG9ncmEgY29uIG10cnkgPSAxLCBlcyBkZWNpciwgY29uc2lkZXJhbmRvIHNvbG8gMSBwcmVkaWN0b3IgYWxlYXRvcmlvIHBvciBkaXZpc2nDs24uDQoNCmBgYHtyfQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShkcGx5cikNCg0KcmZfZGF0YSA8LSBVU0FycmVzdHMgJT4lDQogIHNlbGVjdChNdXJkZXIsIEFzc2F1bHQsIFVyYmFuUG9wLCBSYXBlKSAlPiUNCiAgbXV0YXRlKGttX2NsdXN0ZXIgPSBhcy5mYWN0b3Ioa21fY2x1c3RlciRjbHVzdGVyKSkgICMgYWdyZWdhciBjbHVzdGVyIGNvbW8gdmFyaWFibGUgb2JqZXRpdm8NCg0Kc2V0LnNlZWQoMTIzKQ0KaW5kZXggPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihyZl9kYXRhJGttX2NsdXN0ZXIsIHAgPSAwLjgsIGxpc3QgPSBGQUxTRSkNCnRyYWluX2R0IDwtIHJmX2RhdGFbaW5kZXgsIF0NCnRlc3RfZHQgIDwtIHJmX2RhdGFbLWluZGV4LCBdDQpgYGANCg0KYGBge3J9DQp0ckNvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDEwKQ0KdHVuZUdyaWQgIDwtIGV4cGFuZC5ncmlkKG10cnkgPSAxOihuY29sKHRyYWluX2R0KSAtIDEpKSAgIyAtMSBwb3JxdWUgbGEgw7psdGltYSBlcyBsYSB2YXJpYWJsZSBvYmpldGl2bw0KDQpzZXQuc2VlZCgxMjMpDQptb2RlbFJGIDwtIHRyYWluKGttX2NsdXN0ZXIgfiAuLCANCiAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluX2R0LCANCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJmIiwgDQogICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyQ29udHJvbCwNCiAgICAgICAgICAgICAgICAgdHVuZUdyaWQgPSB0dW5lR3JpZCwNCiAgICAgICAgICAgICAgICAgbnRyZWUgPSA1MDApDQoNCnByaW50KG1vZGVsUkYpDQpgYGANCg0KIyMjIEltcG9ydGFuY2lhIGRlIHZhcmlhYmxlIHNlZ8O6biBSYW5kb20gRm9yZXN0DQoNCiogTXVyZGVyIGVzIGVsIHByZWRpY3RvciBtw6FzIGltcG9ydGFudGUgZW4gbGEgY2xhc2lmaWNhY2nDs24gZGUgY2zDunN0ZXJlcy4NCg0KKiBVcmJhblBvcCBubyBhcG9ydGEgdmFsb3IgcHJlZGljdGl2byAoaW1wb3J0YW5jaWEgPSAwKS4NCg0KUG9yIGxvIHRhbnRvLCBsYSBjcmltaW5hbGlkYWQgdmlvbGVudGEgKE11cmRlciwgQXNzYXVsdCwgUmFwZSkgZGVmaW5lIGxvcyBjbMO6c3RlcmVzLCBubyB0YW50byBsYSB1cmJhbml6YWNpw7NuLg0KDQpgYGB7cn0NCnJmX21vZGVsIDwtIHJhbmRvbUZvcmVzdChrbV9jbHVzdGVyIH4gLiwgZGF0YSA9IHRyYWluX2R0LCBtdHJ5ID0gbW9kZWxSRiRiZXN0VHVuZSRtdHJ5LCBpbXBvcnRhbmNlID0gVFJVRSkNCnZhckltcFBsb3QocmZfbW9kZWwpDQp2YXJJbXAobW9kZWxSRiwgc2NhbGUgPSBUUlVFKQ0KYGBgDQoNCiMjIyBQcmVjaXNpw7NuIGRlIFJhbmRvbSBGb3Jlc3QNCg0KKiBFbCByZW5kaW1pZW50byBlbiB0ZXN0IGVzIHBlcmZlY3RvLCBsbyBjdWFsIHB1ZWRlIGRlYmVyc2UgYWwgdGFtYcOxbyByZWR1Y2lkbyBkZSBtdWVzdHJhIChuPTEwKS4NCg0KYGBge3J9DQpwcmVkcyA8LSBwcmVkaWN0KG1vZGVsUkYsIG5ld2RhdGEgPSB0ZXN0X2R0KQ0KY29uZnVzaW9uTWF0cml4KHByZWRzLCB0ZXN0X2R0JGttX2NsdXN0ZXIpDQpgYGANCg0KIyMgKipDb25jbHVzacOzbioqDQoNCkVsIGFuw6FsaXNpcyBkZWwgY29uanVudG8gZGUgZGF0b3MgVVNBcnJlc3RzIHJldmVsYSBxdWUgZXhpc3RlbiBkb3MgZ3J1cG9zIGNsYXJhbWVudGUgZGlmZXJlbmNpYWRvcyBlbnRyZSBsb3MgZXN0YWRvcyBkZSBFRS5VVS4gZW4gZnVuY2nDs24gZGUgbG9zIGRlbGl0b3MgKGFzZXNpbmF0bywgYXNhbHRvLCB2aW9sYWNpw7NuKSB5IGxhIHByb3BvcmNpw7NuIGRlIHBvYmxhY2nDs24gdXJiYW5hLiBMYSBzZWdtZW50YWNpw7NuIG1lZGlhbnRlIEstbWVhbnMgY2x1c3RlcmluZyBtdWVzdHJhIHVuYSBjbGFyYSBzZXBhcmFjacOzbiBnZW9ncsOhZmljYSB5IGRlIGNhcmFjdGVyw61zdGljYXMgY3JpbWluYWxlcy4gRWwgdXNvIGRlIG3DqXRyaWNhcyBkZSBkaXN0YW5jaWEgY29tbyBDYW5iZXJyYSwganVudG8gY29uIGVsIGVzdGFkw61zdGljbyBkZSBIb3BraW5zIHkgZWwgbcOpdG9kbyBkZSBHYXAgU3RhdGlzdGljLCBwZXJtaXRlIGNvbmZpcm1hciBsYSB2YWxpZGV6IGRlIGxhIGFncnVwYWNpw7NuLg0KDQpFbCBDbMO6c3RlciAxLCBjb21wdWVzdG8gcG9yIDIwIGVzdGFkb3MsIGFncnVwYSBwcmluY2lwYWxtZW50ZSBhIGxvcyBlc3RhZG9zIGRlbCBub3J0ZSB5IG9lc3RlLCB5IHNlIGNhcmFjdGVyaXphIHBvciBuaXZlbGVzIG3DoXMgZWxldmFkb3MgZGUgY3JpbWluYWxpZGFkIGVuIGxvcyBpbmRpY2Fkb3JlcyBhbmFsaXphZG9zLiBFc3RvcyBlc3RhZG9zIHByZXNlbnRhbiB2YWxvcmVzIHBvciBlbmNpbWEgZGVsIHByb21lZGlvIGVuIGFzZXNpbmF0b3MsIGFzYWx0b3MgeSB2aW9sYWNpb25lcywgYXPDrSBjb21vIHVuYSBtYXlvciBwcm9wb3JjacOzbiBkZSBwb2JsYWNpw7NuIHVyYmFuYS4NCg0KUG9yIG90cm8gbGFkbywgZWwgQ2zDunN0ZXIgMiwgcXVlIGluY2x1eWUgYSAzMCBlc3RhZG9zIGRlbCBzdXIgeSBlc3RlLCBtdWVzdHJhIHVuIHBlcmZpbCBvcHVlc3RvOiBuaXZlbGVzIG3DoXMgYmFqb3MgZGUgZGVsaXRvcyB2aW9sZW50b3MgeSBtZW5vciB1cmJhbml6YWNpw7NuLiBFc3RhIGRpdmlzacOzbiBubyBzb2xvIGVzIGVzdGFkw61zdGljYW1lbnRlIHPDs2xpZGEsIHNpbm8gcXVlIHRhbWJpw6luIHByZXNlbnRhIHVuYSBjbGFyYSBjb3JyZXNwb25kZW5jaWEgZ2VvZ3LDoWZpY2EsIGxvIHF1ZSBzdWdpZXJlIHF1ZSBsb3MgZmFjdG9yZXMgcmVnaW9uYWxlcyBwdWVkZW4gZXN0YXIgaW5mbHV5ZW5kbyBlbiBsb3MgcGF0cm9uZXMgZGVsaWN0aXZvcy4NCg0KUG9yIMO6bHRpbW8sIGxhIHZhbGlkYWNpw7NuIGRlbCBtb2RlbG8gY29uIHVuIGFsZ29yaXRtbyBkZSByYW5kb20gZm9yZXN0IG1vc3Ryw7MgdW5hIGV4YWN0aXR1ZCBkZWwgMTAwJSBlbiBsYSBjbGFzaWZpY2FjacOzbiBkZSBsb3MgY2zDunN0ZXJlcywgeSBsYSBpbXBvcnRhbmNpYSBkZSB2YXJpYWJsZXMgaW5kaWNhIHF1ZSBsb3MgZGVsaXRvcyBjb21vIGFzZXNpbmF0byB5IGFzYWx0byBzb24gbG9zIHByZWRpY3RvcmVzIG3DoXMgcmVsZXZhbnRlcyBlbiBsYSBzZWdtZW50YWNpw7NuIGRlIGxvcyBlc3RhZG9zLg0KDQoNCiMjICoqUmVmZXJlbmNpYXMqKg0KDQpLZXRjaGVuLCBELiBKLiwgJiBTaG9vaywgQy4gTC4gKDE5OTYpLiBUaGUgYXBwbGljYXRpb24gb2YgY2x1c3RlciBhbmFseXNpcyBpbiBzdHJhdGVnaWMgbWFuYWdlbWVudCByZXNlYXJjaDogQW4gYW5hbHlzaXMgYW5kIGNyaXRpcXVlLiBTdHJhdGVnaWMgTWFuYWdlbWVudCBKb3VybmFsLCAxNyg2KSwgNDQx4oCTNDU4Lg0KDQpMYW5jZSwgRy4gTi4sICYgV2lsbGlhbXMsIFcuIFQuICgxOTY3KS4gQSBnZW5lcmFsIHRoZW9yeSBvZiBjbGFzc2lmaWNhdG9yeSBzb3J0aW5nIHN0cmF0ZWdpZXM6IEkuIEhpZXJhcmNoaWNhbCBzeXN0ZW1zLiBUaGUgQ29tcHV0ZXIgSm91cm5hbC4NCg0KU25lYXRoLCBQLkguQS4sICYgU29rYWwsIFIuUi4gKDE5NzMpLiBOdW1lcmljYWwgVGF4b25vbXkuIFcuIEguIEZyZWVtYW4gYW5kIENvbXBhbnkuDQoNCk1hY1F1ZWVuLCBKLiAoMTk2NykuIFNvbWUgbWV0aG9kcyBmb3IgY2xhc3NpZmljYXRpb24gYW5kIGFuYWx5c2lzIG9mIG11bHRpdmFyaWF0ZSBvYnNlcnZhdGlvbnMuIFByb2NlZWRpbmdzIG9mIHRoZSBGaWZ0aCBCZXJrZWxleSBTeW1wb3NpdW0gb24gTWF0aGVtYXRpY2FsIFN0YXRpc3RpY3MgYW5kIFByb2JhYmlsaXR5Lg0KDQpUYW4sIFAuLU4uLCBTdGVpbmJhY2gsIE0uLCAmIEt1bWFyLCBWLiAoMjAxOCkuIEludHJvZHVjdGlvbiB0byBEYXRhIE1pbmluZy4gUGVhcnNvbi4=