Universidad Nacional de Cuyo Facultad de Ingeniería
Ingeniería Industrial Mendoza - Argentina \(\dagger^{[1 y 3]}\) [ricardo.palma]
[victoria.palma]@ingenieria.uncuyo.edu.ar
Universidad Católica Boliviana Departamento de
Ingeniería Industrial La Paz - Bolivia \(\ddagger²\) flopez@ucb.edu.bo
Bases para un framework de estrategia de manufactura basado en
gemelos digitales
Resumen
Resumen El presente material aborda el uso de un método que aparece
muy frecuentemente en la literatura denominado AHP. Fue creado por Tomas
L. Saaty y dentro de sus múltiples posibilidades de uso, la más
destacada es el ranking de alternativas o la selección de una de ellas.
Se ha concebido como paso previo al desarrollo de un gemelo digital y
posteriormente la implementación de una sombra digital de una empresa
pequeña del centro oeste argentino. parap poder definir la tecnología de
la sombra digital se han contemplado tres alternativas (A1-un sistema
SAP, A2-Oddo CRM, A3-Un BSC con Power BI) Para realizar este proceso se
parte del método de los factores ponderales y a partir de crear un
vector de pesos relativos de los criterios de selección se confronta el
desempeño de cada alternativa se obtiene un vector columna de ranking
que muestra el desempeño de las alternativas A frente de los diferentes
escenarios.
En el método de Saaty se agrega un interesante procedimiento basado
en el autovector y autovalor de las matrices que intervienen para
calcular el grado de inconsistencia del debate de los decisores. Esto
elimina el sesgo que los decisores o metodólogos pudiesen inducir en el
método de los factores ponderales.
Contexto de la Excelencia Operacional en la Estrategia de
Manufactura Global
La excelencia operacional es un enfoque que busca la mejora continua
en todos los aspectos de un negocio para lograr una ejecución más
eficiente y consistente que la competencia. Esto implica optimizar
procesos, reducir costos, mejorar la calidad y fomentar una cultura de
innovación. Los gemelos digitales, por su parte, son réplicas virtuales
de un objeto o sistema físico que se actualizan en tiempo real con datos
de sensores. Su función es simular, analizar y optimizar el rendimiento
del sistema real.
La relación entre ambos conceptos, AHP y
EO, es directa y simbiótica. Los gemelos digitales se
convierten en una herramienta crucial para alcanzar la excelencia
operacional. Permiten simular escenarios, identificar cuellos de
botella, prever fallos y evaluar el impacto de diferentes decisiones
antes de implementarlas en el mundo físico. Esta capacidad de análisis y
predicción en tiempo real es clave para la mejora continua y la
optimización de procesos, que son los pilares de la excelencia
operacional.
En este contexto, el método de Tomás Saaty (Proceso de Jerarquía
Analítica o AHP) podría utilizarse como una herramienta para la
concepción de alternativas para el gemelo digital. El AHP es un método
de toma de decisiones multicriterio que ayuda a estructurar un problema
complejo en una jerarquía de objetivos, criterios y alternativas. Se
basa en comparaciones por pares para asignar pesos y prioridades a cada
elemento.
Análisis de Decisiones usando la Metodología AHP
(Analytic Hierarchy Process de Thomas Saaty)
1. Introducción
Este documento implementa la metodología AHP (Analytic Hierarchy
Process) desarrollada por Thomas Saaty para la toma de decisiones
multicriterio. Analizaremos 3 alternativas usando
5 criterios de selección. Estos han surgido de un
estudio previo basado en el benchmarking de Excelencia Operacional de un
sector empresarios que incluye una cadena de abastecimiento que abarca
una producción primaria (cosecha), manufactura, logística y distribución
y finalmente logística reversa de envases junto a disposición final de
residuos (pasivado para relleno sanitario o fertilizante) o uso como
insumo en otras cadenas de valor (economía circular)
Problema de Decisión
Objetivo: Seleccionar la mejor alternativa de
inversión tecnológica para la empresa mencionada que tiene como
fortaleza el “preparedness” para la transformación
digital
Alternativas:
- A1: Sistema ERP
- A2: Plataforma CRM
- A3: Solución de Business Intelligence
Criterios de Evaluación:
- C1: Costo de implementación
- C2: Facilidad de uso
- C3: Funcionalidad
- C4: Soporte técnico
- C5: Escalabilidad
2. Configuración del Entorno de R
Funciones y Matrices CR
# Cargar librerías necesarias
library(knitr)
library(ggplot2)
library(dplyr)
library(reshape2)
library(RColorBrewer)
# Función para calcular el vector propio principal
calcular_vector_propio <- function(matriz) {
eigenvalues <- eigen(matriz)
max_index <- which.max(eigenvalues$values)
vector_propio <- abs(eigenvalues$vectors[, max_index])
return(vector_propio / sum(vector_propio))
}
# Función para calcular el Índice de Consistencia (CI)
calcular_CI <- function(matriz) {
n <- nrow(matriz)
eigenvalues <- eigen(matriz)$values
lambda_max <- max(Re(eigenvalues))
CI <- (lambda_max - n) / (n - 1)
return(CI)
}
# Función para calcular el Ratio de Consistencia (CR)
calcular_CR <- function(CI, n) {
# Índices de consistencia aleatoria según Saaty
RI <- c(0, 0, 0.58, 0.90, 1.12, 1.24, 1.32, 1.41, 1.45, 1.49)
if (n <= 10) {
CR <- CI / RI[n]
} else {
CR <- NA
}
return(CR)
}
3. Matrices de Comparación por Pares
3.1 Matriz de Comparación de Criterios
# Matriz de comparación por pares de criterios (5x5)
# Escala de Saaty: 1=igual, 3=moderadamente más importante, 5=fuertemente más importante,
# 7=muy fuertemente más importante, 9=extremadamente más importante
criterios_matriz <- matrix(c(
1, 1/3, 1/2, 2, 1/4, # C1: Costo
3, 1, 2, 3, 1/2, # C2: Facilidad de uso
2, 1/2, 1, 3, 1/3, # C3: Funcionalidad
1/2, 1/3, 1/3, 1, 1/5, # C4: Soporte técnico
4, 2, 3, 5, 1 # C5: Escalabilidad
), nrow = 5, byrow = TRUE)
rownames(criterios_matriz) <- c("Costo", "Facilidad_uso", "Funcionalidad", "Soporte", "Escalabilidad")
colnames(criterios_matriz) <- c("Costo", "Facilidad_uso", "Funcionalidad", "Soporte", "Escalabilidad")
print("Matriz de Comparación de Criterios:")
## [1] "Matriz de Comparación de Criterios:"
kable(round(criterios_matriz, 3))
| Costo |
1.0 |
0.333 |
0.500 |
2 |
0.250 |
| Facilidad_uso |
3.0 |
1.000 |
2.000 |
3 |
0.500 |
| Funcionalidad |
2.0 |
0.500 |
1.000 |
3 |
0.333 |
| Soporte |
0.5 |
0.333 |
0.333 |
1 |
0.200 |
| Escalabilidad |
4.0 |
2.000 |
3.000 |
5 |
1.000 |
3.2 Cálculo de Pesos de Criterios
# Calcular vector propio (pesos de criterios)
pesos_criterios <- calcular_vector_propio(criterios_matriz)
names(pesos_criterios) <- rownames(criterios_matriz)
# Calcular consistencia
CI_criterios <- calcular_CI(criterios_matriz)
CR_criterios <- calcular_CR(CI_criterios, 5)
print("Pesos de los Criterios:")
## [1] "Pesos de los Criterios:"
kable(data.frame(
Criterio = names(pesos_criterios),
Peso = round(pesos_criterios, 4),
Porcentaje = paste0(round(pesos_criterios * 100, 2), "%")
))
| Costo |
Costo |
0.0987 |
9.87% |
| Facilidad_uso |
Facilidad_uso |
0.2521 |
25.21% |
| Funcionalidad |
Funcionalidad |
0.1623 |
16.23% |
| Soporte |
Soporte |
0.0665 |
6.65% |
| Escalabilidad |
Escalabilidad |
0.4205 |
42.05% |
print(paste("Índice de Consistencia (CI):", round(CI_criterios, 4)))
## [1] "Índice de Consistencia (CI): 0.0215"
print(paste("Ratio de Consistencia (CR):", round(CR_criterios, 4)))
## [1] "Ratio de Consistencia (CR): 0.0192"
if (CR_criterios < 0.1) {
print("✓ La matriz de criterios es consistente (CR < 0.10)")
} else {
print("la matriz de criterios presenta inconsistencias (CR ≥ 0.10)")
}
## [1] "✓ La matriz de criterios es consistente (CR < 0.10)"
4. Matrices de Comparación de Alternativas
4.1 Criterio 1: Costo de Implementación
# Matriz de comparación de alternativas respecto al costo
# (menor costo es mejor)
costo_matriz <- matrix(c(
1, 1/2, 3, # ERP vs CRM, ERP vs BI
2, 1, 5, # CRM vs ERP, CRM vs BI
1/3, 1/5, 1 # BI vs ERP, BI vs CRM
), nrow = 3, byrow = TRUE)
rownames(costo_matriz) <- c("ERP", "CRM", "BI")
colnames(costo_matriz) <- c("ERP", "CRM", "BI")
pesos_costo <- calcular_vector_propio(costo_matriz)
names(pesos_costo) <- rownames(costo_matriz)
print("Matriz - Costo de Implementación:")
## [1] "Matriz - Costo de Implementación:"
kable(round(costo_matriz, 3))
| ERP |
1.000 |
0.5 |
3 |
| CRM |
2.000 |
1.0 |
5 |
| BI |
0.333 |
0.2 |
1 |
print("Pesos para Costo:")
## [1] "Pesos para Costo:"
kable(data.frame(Alternativa = names(pesos_costo), Peso = round(pesos_costo, 4)))
| ERP |
ERP |
0.3090 |
| CRM |
CRM |
0.5816 |
| BI |
BI |
0.1095 |
4.2 Criterio 2: Facilidad de Uso
facilidad_matriz <- matrix(c(
1, 1/3, 1/2, # ERP vs CRM, ERP vs BI
3, 1, 2, # CRM vs ERP, CRM vs BI
2, 1/2, 1 # BI vs ERP, BI vs CRM
), nrow = 3, byrow = TRUE)
rownames(facilidad_matriz) <- c("ERP", "CRM", "BI")
colnames(facilidad_matriz) <- c("ERP", "CRM", "BI")
pesos_facilidad <- calcular_vector_propio(facilidad_matriz)
names(pesos_facilidad) <- rownames(facilidad_matriz)
print("Matriz - Facilidad de Uso:")
## [1] "Matriz - Facilidad de Uso:"
kable(round(facilidad_matriz, 3))
| ERP |
1 |
0.333 |
0.5 |
| CRM |
3 |
1.000 |
2.0 |
| BI |
2 |
0.500 |
1.0 |
print("Pesos para Facilidad de Uso:")
## [1] "Pesos para Facilidad de Uso:"
kable(data.frame(Alternativa = names(pesos_facilidad), Peso = round(pesos_facilidad, 4)))
| ERP |
ERP |
0.1634 |
| CRM |
CRM |
0.5396 |
| BI |
BI |
0.2970 |
4.3 Criterio 3: Funcionalidad
funcionalidad_matriz <- matrix(c(
1, 2, 1/2, # ERP vs CRM, ERP vs BI
1/2, 1, 1/3, # CRM vs ERP, CRM vs BI
2, 3, 1 # BI vs ERP, BI vs CRM
), nrow = 3, byrow = TRUE)
rownames(funcionalidad_matriz) <- c("ERP", "CRM", "BI")
colnames(funcionalidad_matriz) <- c("ERP", "CRM", "BI")
pesos_funcionalidad <- calcular_vector_propio(funcionalidad_matriz)
names(pesos_funcionalidad) <- rownames(funcionalidad_matriz)
print("Matriz - Funcionalidad:")
## [1] "Matriz - Funcionalidad:"
kable(round(funcionalidad_matriz, 3))
| ERP |
1.0 |
2 |
0.500 |
| CRM |
0.5 |
1 |
0.333 |
| BI |
2.0 |
3 |
1.000 |
print("Pesos para Funcionalidad:")
## [1] "Pesos para Funcionalidad:"
kable(data.frame(Alternativa = names(pesos_funcionalidad), Peso = round(pesos_funcionalidad, 4)))
| ERP |
ERP |
0.2970 |
| CRM |
CRM |
0.1634 |
| BI |
BI |
0.5396 |
4.4 Criterio 4: Soporte Técnico
soporte_matriz <- matrix(c(
1, 3, 2, # ERP vs CRM, ERP vs BI
1/3, 1, 1/2, # CRM vs ERP, CRM vs BI
1/2, 2, 1 # BI vs ERP, BI vs CRM
), nrow = 3, byrow = TRUE)
rownames(soporte_matriz) <- c("ERP", "CRM", "BI")
colnames(soporte_matriz) <- c("ERP", "CRM", "BI")
pesos_soporte <- calcular_vector_propio(soporte_matriz)
names(pesos_soporte) <- rownames(soporte_matriz)
print("Matriz - Soporte Técnico:")
## [1] "Matriz - Soporte Técnico:"
kable(round(soporte_matriz, 3))
| ERP |
1.000 |
3 |
2.0 |
| CRM |
0.333 |
1 |
0.5 |
| BI |
0.500 |
2 |
1.0 |
print("Pesos para Soporte Técnico:")
## [1] "Pesos para Soporte Técnico:"
kable(data.frame(Alternativa = names(pesos_soporte), Peso = round(pesos_soporte, 4)))
| ERP |
ERP |
0.5396 |
| CRM |
CRM |
0.1634 |
| BI |
BI |
0.2970 |
4.5 Criterio 5: Escalabilidad
escalabilidad_matriz <- matrix(c(
1, 1/2, 2, # ERP vs CRM, ERP vs BI
2, 1, 4, # CRM vs ERP, CRM vs BI
1/2, 1/4, 1 # BI vs ERP, BI vs CRM
), nrow = 3, byrow = TRUE)
rownames(escalabilidad_matriz) <- c("ERP", "CRM", "BI")
colnames(escalabilidad_matriz) <- c("ERP", "CRM", "BI")
pesos_escalabilidad <- calcular_vector_propio(escalabilidad_matriz)
names(pesos_escalabilidad) <- rownames(escalabilidad_matriz)
print("Matriz - Escalabilidad:")
## [1] "Matriz - Escalabilidad:"
kable(round(escalabilidad_matriz, 3))
| ERP |
1.0 |
0.50 |
2 |
| CRM |
2.0 |
1.00 |
4 |
| BI |
0.5 |
0.25 |
1 |
print("Pesos para Escalabilidad:")
## [1] "Pesos para Escalabilidad:"
kable(data.frame(Alternativa = names(pesos_escalabilidad), Peso = round(pesos_escalabilidad, 4)))
| ERP |
ERP |
0.2857 |
| CRM |
CRM |
0.5714 |
| BI |
BI |
0.1429 |
5. Cálculo de Puntuaciones Finales
# Crear matriz de decisión
matriz_decision <- cbind(pesos_costo, pesos_facilidad, pesos_funcionalidad, pesos_soporte, pesos_escalabilidad)
colnames(matriz_decision) <- c("Costo", "Facilidad_uso", "Funcionalidad", "Soporte", "Escalabilidad")
print("Matriz de Decisión (Pesos de alternativas por criterio):")
## [1] "Matriz de Decisión (Pesos de alternativas por criterio):"
kable(round(matriz_decision, 4))
| ERP |
0.3090 |
0.1634 |
0.2970 |
0.5396 |
0.2857 |
| CRM |
0.5816 |
0.5396 |
0.1634 |
0.1634 |
0.5714 |
| BI |
0.1095 |
0.2970 |
0.5396 |
0.2970 |
0.1429 |
# Calcular puntuaciones finales
puntuaciones_finales <- matriz_decision %*% pesos_criterios
puntuaciones_finales <- as.vector(puntuaciones_finales)
names(puntuaciones_finales) <- c("Sistema ERP", "Plataforma CRM", "Solución BI")
# Crear tabla de resultados
resultados <- data.frame(
Alternativa = names(puntuaciones_finales),
Puntuacion = round(puntuaciones_finales, 4),
Porcentaje = paste0(round(puntuaciones_finales * 100, 2), "%"),
Ranking = rank(-puntuaciones_finales)
)
print("RESULTADOS FINALES:")
## [1] "RESULTADOS FINALES:"
kable(resultados[order(-resultados$Puntuacion), ])
| Plataforma CRM |
Plataforma CRM |
0.4711 |
47.11% |
1 |
| Sistema ERP |
Sistema ERP |
0.2759 |
27.59% |
2 |
| Solución BI |
Solución BI |
0.2530 |
25.3% |
3 |
6. Análisis de Sensibilidad por Criterios
# Crear matriz detallada para análisis
contribuciones <- matriz_decision * matrix(rep(pesos_criterios, each = 3), nrow = 3)
rownames(contribuciones) <- c("Sistema ERP", "Plataforma CRM", "Solución BI")
colnames(contribuciones) <- c("Costo", "Facilidad de Uso", "Funcionalidad", "Soporte", "Escalabilidad")
print("Contribución de cada criterio a la puntuación final:")
## [1] "Contribución de cada criterio a la puntuación final:"
kable(round(contribuciones, 4))
| Sistema ERP |
0.0305 |
0.0412 |
0.0482 |
0.0359 |
0.1201 |
| Plataforma CRM |
0.0574 |
0.1361 |
0.0265 |
0.0109 |
0.2403 |
| Solución BI |
0.0108 |
0.0749 |
0.0876 |
0.0197 |
0.0601 |
7. Visualizaciones
7.1 Gráfico Comparativo de Alternativas
# Preparar datos para visualización
datos_viz <- data.frame(
Alternativa = rep(names(puntuaciones_finales), 2),
Valor = c(puntuaciones_finales, puntuaciones_finales),
Tipo = rep(c("Puntuación Final", "Porcentaje"), each = 3),
Valor_Pct = c(puntuaciones_finales, puntuaciones_finales * 100)
)
# Gráfico de barras comparativo
p1 <- ggplot(datos_viz[datos_viz$Tipo == "Puntuación Final", ],
aes(x = reorder(Alternativa, -Valor), y = Valor, fill = Alternativa)) +
geom_bar(stat = "identity", alpha = 0.8, width = 0.6) +
geom_text(aes(label = paste0(round(Valor, 3), "\n(", round(Valor_Pct, 1), "%)")),
vjust = -0.5, size = 4, fontface = "bold") +
scale_fill_brewer(type = "qual", palette = "Set2") +
labs(title = "Comparación de Alternativas - Metodología AHP",
subtitle = paste("Ganador:", names(puntuaciones_finales)[which.max(puntuaciones_finales)]),
x = "Alternativas",
y = "Puntuación AHP",
caption = "Metodología: Analytic Hierarchy Process (Thomas Saaty)") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
plot.subtitle = element_text(hjust = 0.5, size = 12, color = "darkgreen"),
axis.text.x = element_text(angle = 0, hjust = 0.5),
legend.position = "none") +
ylim(0, max(puntuaciones_finales) * 1.2)
print(p1)

7.2 Gráfico de Contribuciones por Criterio
# Preparar datos para gráfico de contribuciones
contrib_long <- melt(contribuciones)
colnames(contrib_long) <- c("Alternativa", "Criterio", "Contribucion")
# Gráfico de barras apiladas
p2 <- ggplot(contrib_long, aes(x = Alternativa, y = Contribucion, fill = Criterio)) +
geom_bar(stat = "identity", position = "stack") +
scale_fill_brewer(type = "qual", palette = "Set3") +
labs(title = "Contribución de cada Criterio por Alternativa",
subtitle = "Análisis de Sensibilidad - Metodología AHP",
x = "Alternativas",
y = "Contribución a la Puntuación Final",
fill = "Criterios") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
plot.subtitle = element_text(hjust = 0.5, size = 12),
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom") +
guides(fill = guide_legend(nrow = 1))
print(p2)

7.3 Gráfico Radar de Alternativas
# Preparar datos para gráfico radar
radar_data <- as.data.frame(matriz_decision)
radar_data$Alternativa <- rownames(radar_data)
# Convertir a formato largo
radar_long <- melt(radar_data, id.vars = "Alternativa")
colnames(radar_long) <- c("Alternativa", "Criterio", "Valor")
# Gráfico de coordenadas polares (pseudo-radar)
p3 <- ggplot(radar_long, aes(x = Criterio, y = Valor, color = Alternativa, group = Alternativa)) +
geom_line(size = 1.2, alpha = 0.8) +
geom_point(size = 3, alpha = 0.9) +
coord_polar() +
scale_color_brewer(type = "qual", palette = "Dark2") +
labs(title = "Perfil de Alternativas por Criterio",
subtitle = "Gráfico Radar - Análisis Multicriterio AHP",
y = "Puntuación por Criterio") +
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
plot.subtitle = element_text(hjust = 0.5, size = 12),
axis.text.x = element_text(size = 10),
legend.position = "bottom")
print(p3)

8. Resumen Ejecutivo
mejor_alternativa <- names(puntuaciones_finales)[which.max(puntuaciones_finales)]
puntuacion_mejor <- max(puntuaciones_finales)
cat("========== RESUMEN EJECUTIVO ==========\n")
## ========== RESUMEN EJECUTIVO ==========
cat("Metodología: Analytic Hierarchy Process (AHP) - Thomas Saaty\n")
## Metodología: Analytic Hierarchy Process (AHP) - Thomas Saaty
cat("Criterios evaluados:", length(pesos_criterios), "\n")
## Criterios evaluados: 5
cat("Alternativas analizadas:", length(puntuaciones_finales), "\n")
## Alternativas analizadas: 3
cat("Consistencia de juicios: CR =", round(CR_criterios, 3),
ifelse(CR_criterios < 0.1, "(Aceptable)", "(Revisar)"), "\n\n")
## Consistencia de juicios: CR = 0.019 (Aceptable)
cat("RECOMENDACIÓN:\n")
## RECOMENDACIÓN:
cat("La mejor alternativa es:", mejor_alternativa, "\n")
## La mejor alternativa es: Plataforma CRM
cat("Puntuación AHP:", round(puntuacion_mejor, 4),
paste0("(", round(puntuacion_mejor * 100, 1), "%)"), "\n\n")
## Puntuación AHP: 0.4711 (47.1%)
cat("RANKING COMPLETO:\n")
## RANKING COMPLETO:
for(i in order(-puntuaciones_finales)) {
cat(paste0(which(order(-puntuaciones_finales) == i), "° ",
names(puntuaciones_finales)[i], ": ",
round(puntuaciones_finales[i], 4),
" (", round(puntuaciones_finales[i] * 100, 1), "%)\n"))
}
## 1° Plataforma CRM: 0.4711 (47.1%)
## 2° Sistema ERP: 0.2759 (27.6%)
## 3° Solución BI: 0.253 (25.3%)
cat("\nCRITERIO MÁS IMPORTANTE:", names(pesos_criterios)[which.max(pesos_criterios)],
paste0("(", round(max(pesos_criterios) * 100, 1), "%)"))
##
## CRITERIO MÁS IMPORTANTE: Escalabilidad (42%)
Nota metodológica: Este análisis implementa la
metodología AHP desarrollada por Thomas Saaty, utilizando comparaciones
por pares con la escala fundamental de 1-9 y verificando la consistencia
mediante el Ratio de Consistencia (CR). Se recomienda que CR < 0.10
para considerar los juicios como consistentes.
** link to https://rpubs.com/ricardorpama/1338567**
cite: Palma, R. R. (2025). Excelencia Operacional Bases para un
framework de estrategia de manufactura. Zenodo. https://doi.org/10.5281/zenodo.16945306
LS0tCnRpdGxlOiAiPGNlbnRlcj5FeGNlbGVuY2lhIE9wZXJhY2lvbmFsPC9jZW50ZXI+IgphdXRob3I6ICc8Y2VudGVyPkF1dGhvcjogUmljYXJkbyBSLlBhbG1hICRcZGFnZ2VyXjEkIFswMDAwLTAwMDItMTg2NC03NjI1XSwgRmVybmFuZG8gQS4gTG9wZXogJFxkZGFnZ2VyXjIkLCA8YnI+VmljdG9yaWEgSW7DqXMgUGFsbWEgQ2llcmkgJFxkYWdnZXJeMyRbMDAwOS0wMDA4LTY2MDEtNDQyOF0gPC9jZW50ZXI+ICcKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA1CiAgICB0b2NfZmxvYXQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFCiAgd29yZF9kb2N1bWVudDogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKQpgYGAKPGNlbnRlcj4KPGhyPgoqKlVuaXZlcnNpZGFkIE5hY2lvbmFsIGRlIEN1eW8qKgpGYWN1bHRhZCBkZSBJbmdlbmllcsOtYQpJbmdlbmllcsOtYSBJbmR1c3RyaWFsCk1lbmRvemEgLSBBcmdlbnRpbmEKJFxkYWdnZXJee1sxIHkgM119JCBbcmljYXJkby5wYWxtYV0gW3ZpY3RvcmlhLnBhbG1hXUBpbmdlbmllcmlhLnVuY3V5by5lZHUuYXIKCioqVW5pdmVyc2lkYWQgQ2F0w7NsaWNhIEJvbGl2aWFuYSoqCkRlcGFydGFtZW50byBkZSBJbmdlbmllcsOtYSBJbmR1c3RyaWFsCkxhIFBheiAtIEJvbGl2aWEKJFxkZGFnZ2VywrIkIGZsb3BlekB1Y2IuZWR1LmJvIAoKPGhyPgo8L2NlbnRlcj4KCiMjIEJhc2VzIHBhcmEgdW4gZnJhbWV3b3JrIGRlIGVzdHJhdGVnaWEgZGUgbWFudWZhY3R1cmEgYmFzYWRvIGVuIGdlbWVsb3MgZGlnaXRhbGVzCgoKCgojIyMgUmVzdW1lbgoKUmVzdW1lbgpFbCBwcmVzZW50ZSBtYXRlcmlhbCBhYm9yZGEgZWwgdXNvIGRlIHVuIG3DqXRvZG8gcXVlIGFwYXJlY2UgbXV5IGZyZWN1ZW50ZW1lbnRlIGVuIGxhIGxpdGVyYXR1cmEgZGVub21pbmFkbyBBSFAuIEZ1ZSBjcmVhZG8gcG9yIFRvbWFzIEwuIFNhYXR5IHkgZGVudHJvIGRlIHN1cyBtw7psdGlwbGVzIHBvc2liaWxpZGFkZXMgZGUgdXNvLCBsYSBtw6FzIGRlc3RhY2FkYSBlcyBlbCByYW5raW5nIGRlIGFsdGVybmF0aXZhcyBvIGxhIHNlbGVjY2nDs24gZGUgdW5hIGRlIGVsbGFzLgpTZSBoYSBjb25jZWJpZG8gY29tbyBwYXNvIHByZXZpbyBhbCBkZXNhcnJvbGxvIGRlIHVuIGdlbWVsbyBkaWdpdGFsIHkgcG9zdGVyaW9ybWVudGUgbGEgaW1wbGVtZW50YWNpw7NuIGRlIHVuYSBzb21icmEgZGlnaXRhbCBkZSB1bmEgZW1wcmVzYSBwZXF1ZcOxYSBkZWwgY2VudHJvIG9lc3RlIGFyZ2VudGluby4KcGFyYXAgcG9kZXIgZGVmaW5pciBsYSB0ZWNub2xvZ8OtYSBkZSBsYSBzb21icmEgZGlnaXRhbCBzZSBoYW4gY29udGVtcGxhZG8gdHJlcyBhbHRlcm5hdGl2YXMgKEExLXVuIHNpc3RlbWEgU0FQLCBBMi1PZGRvIENSTSwgQTMtVW4gQlNDIGNvbiBQb3dlciBCSSkKUGFyYSByZWFsaXphciBlc3RlIHByb2Nlc28gc2UgcGFydGUgZGVsIG3DqXRvZG8gZGUgbG9zIGZhY3RvcmVzIHBvbmRlcmFsZXMgeSBhIHBhcnRpciBkZSBjcmVhciB1biB2ZWN0b3IgZGUgcGVzb3MgcmVsYXRpdm9zIGRlIGxvcyBjcml0ZXJpb3MgZGUgc2VsZWNjacOzbiBzZSBjb25mcm9udGEgZWwgZGVzZW1wZcOxbyBkZSBjYWRhIGFsdGVybmF0aXZhIHNlIG9idGllbmUgdW4gdmVjdG9yIGNvbHVtbmEgZGUgcmFua2luZyBxdWUgbXVlc3RyYSBlbCBkZXNlbXBlw7FvIGRlIGxhcyBhbHRlcm5hdGl2YXMgQSBmcmVudGUgZGUgbG9zIGRpZmVyZW50ZXMgZXNjZW5hcmlvcy4KCkVuIGVsIG3DqXRvZG8gZGUgU2FhdHkgc2UgYWdyZWdhIHVuIGludGVyZXNhbnRlIHByb2NlZGltaWVudG8gYmFzYWRvIGVuIGVsIGF1dG92ZWN0b3IgeSBhdXRvdmFsb3IgZGUgbGFzIG1hdHJpY2VzIHF1ZSBpbnRlcnZpZW5lbiBwYXJhIGNhbGN1bGFyIGVsIGdyYWRvIGRlIGluY29uc2lzdGVuY2lhIGRlbCBkZWJhdGUgZGUgbG9zIGRlY2lzb3Jlcy4gRXN0byBlbGltaW5hIGVsIHNlc2dvIHF1ZSBsb3MgZGVjaXNvcmVzIG8gbWV0b2TDs2xvZ29zIHB1ZGllc2VuIGluZHVjaXIgZW4gZWwgbcOpdG9kbyBkZSBsb3MgZmFjdG9yZXMgcG9uZGVyYWxlcy4KCiMjIENvbnRleHRvIGRlIGxhIEV4Y2VsZW5jaWEgT3BlcmFjaW9uYWwgZW4gbGEgRXN0cmF0ZWdpYSBkZSBNYW51ZmFjdHVyYSBHbG9iYWwKCkxhIGV4Y2VsZW5jaWEgb3BlcmFjaW9uYWwgZXMgdW4gZW5mb3F1ZSBxdWUgYnVzY2EgbGEgbWVqb3JhIGNvbnRpbnVhIGVuIHRvZG9zIGxvcyBhc3BlY3RvcyBkZSB1biBuZWdvY2lvIHBhcmEgbG9ncmFyIHVuYSBlamVjdWNpw7NuIG3DoXMgZWZpY2llbnRlIHkgY29uc2lzdGVudGUgcXVlIGxhIGNvbXBldGVuY2lhLiBFc3RvIGltcGxpY2Egb3B0aW1pemFyIHByb2Nlc29zLCByZWR1Y2lyIGNvc3RvcywgbWVqb3JhciBsYSBjYWxpZGFkIHkgZm9tZW50YXIgdW5hIGN1bHR1cmEgZGUgaW5ub3ZhY2nDs24uIExvcyBnZW1lbG9zIGRpZ2l0YWxlcywgcG9yIHN1IHBhcnRlLCBzb24gcsOpcGxpY2FzIHZpcnR1YWxlcyBkZSB1biBvYmpldG8gbyBzaXN0ZW1hIGbDrXNpY28gcXVlIHNlIGFjdHVhbGl6YW4gZW4gdGllbXBvIHJlYWwgY29uIGRhdG9zIGRlIHNlbnNvcmVzLiBTdSBmdW5jacOzbiBlcyBzaW11bGFyLCBhbmFsaXphciB5IG9wdGltaXphciBlbCByZW5kaW1pZW50byBkZWwgc2lzdGVtYSByZWFsLgoKTGEgcmVsYWNpw7NuIGVudHJlIGFtYm9zIGNvbmNlcHRvcywgKipBSFAqKiB5ICoqRU8qKiwgZXMgZGlyZWN0YSB5IHNpbWJpw7N0aWNhLiBMb3MgZ2VtZWxvcyBkaWdpdGFsZXMgc2UgY29udmllcnRlbiBlbiB1bmEgaGVycmFtaWVudGEgY3J1Y2lhbCBwYXJhIGFsY2FuemFyIGxhIGV4Y2VsZW5jaWEgb3BlcmFjaW9uYWwuIFBlcm1pdGVuIHNpbXVsYXIgZXNjZW5hcmlvcywgaWRlbnRpZmljYXIgY3VlbGxvcyBkZSBib3RlbGxhLCBwcmV2ZXIgZmFsbG9zIHkgZXZhbHVhciBlbCBpbXBhY3RvIGRlIGRpZmVyZW50ZXMgZGVjaXNpb25lcyBhbnRlcyBkZSBpbXBsZW1lbnRhcmxhcyBlbiBlbCBtdW5kbyBmw61zaWNvLiBFc3RhIGNhcGFjaWRhZCBkZSBhbsOhbGlzaXMgeSBwcmVkaWNjacOzbiBlbiB0aWVtcG8gcmVhbCBlcyBjbGF2ZSBwYXJhIGxhIG1lam9yYSBjb250aW51YSB5IGxhIG9wdGltaXphY2nDs24gZGUgcHJvY2Vzb3MsIHF1ZSBzb24gbG9zIHBpbGFyZXMgZGUgbGEgZXhjZWxlbmNpYSBvcGVyYWNpb25hbC4KCkVuIGVzdGUgY29udGV4dG8sIGVsIG3DqXRvZG8gZGUgVG9tw6FzIFNhYXR5IChQcm9jZXNvIGRlIEplcmFycXXDrWEgQW5hbMOtdGljYSBvIEFIUCkgcG9kcsOtYSB1dGlsaXphcnNlIGNvbW8gdW5hIGhlcnJhbWllbnRhIHBhcmEgbGEgY29uY2VwY2nDs24gZGUgYWx0ZXJuYXRpdmFzIHBhcmEgZWwgZ2VtZWxvIGRpZ2l0YWwuIEVsIEFIUCBlcyB1biBtw6l0b2RvIGRlIHRvbWEgZGUgZGVjaXNpb25lcyBtdWx0aWNyaXRlcmlvIHF1ZSBheXVkYSBhIGVzdHJ1Y3R1cmFyIHVuIHByb2JsZW1hIGNvbXBsZWpvIGVuIHVuYSBqZXJhcnF1w61hIGRlIG9iamV0aXZvcywgY3JpdGVyaW9zIHkgYWx0ZXJuYXRpdmFzLiBTZSBiYXNhIGVuIGNvbXBhcmFjaW9uZXMgcG9yIHBhcmVzIHBhcmEgYXNpZ25hciBwZXNvcyB5IHByaW9yaWRhZGVzIGEgY2FkYSBlbGVtZW50by4KCgojIyBBbsOhbGlzaXMgZGUgRGVjaXNpb25lcyB1c2FuZG8gbGEgTWV0b2RvbG9nw61hIEFIUAojIyMjIyAoQW5hbHl0aWMgSGllcmFyY2h5IFByb2Nlc3MgZGUgVGhvbWFzIFNhYXR5KQoKIyMgMS4gSW50cm9kdWNjacOzbgoKRXN0ZSBkb2N1bWVudG8gaW1wbGVtZW50YSBsYSBtZXRvZG9sb2fDrWEgQUhQIChBbmFseXRpYyBIaWVyYXJjaHkgUHJvY2VzcykgZGVzYXJyb2xsYWRhIHBvciBUaG9tYXMgU2FhdHkgcGFyYSBsYSB0b21hIGRlIGRlY2lzaW9uZXMgbXVsdGljcml0ZXJpby4gQW5hbGl6YXJlbW9zICoqMyBhbHRlcm5hdGl2YXMqKiB1c2FuZG8gKio1IGNyaXRlcmlvcyBkZSBzZWxlY2Npw7NuKiouIEVzdG9zIGhhbiBzdXJnaWRvIGRlIHVuIGVzdHVkaW8gcHJldmlvIGJhc2FkbyBlbiBlbCBiZW5jaG1hcmtpbmcgZGUgRXhjZWxlbmNpYSBPcGVyYWNpb25hbCBkZSB1biBzZWN0b3IgZW1wcmVzYXJpb3MgcXVlIGluY2x1eWUgdW5hIGNhZGVuYSBkZSBhYmFzdGVjaW1pZW50byBxdWUgYWJhcmNhIHVuYSBwcm9kdWNjacOzbiBwcmltYXJpYSAoY29zZWNoYSksIG1hbnVmYWN0dXJhLCBsb2fDrXN0aWNhIHkgZGlzdHJpYnVjacOzbiB5IGZpbmFsbWVudGUgbG9nw61zdGljYSByZXZlcnNhIGRlIGVudmFzZXMganVudG8gYSBkaXNwb3NpY2nDs24gZmluYWwgZGUgcmVzaWR1b3MgKHBhc2l2YWRvIHBhcmEgcmVsbGVubyBzYW5pdGFyaW8gbyBmZXJ0aWxpemFudGUpIG8gdXNvIGNvbW8gaW5zdW1vIGVuIG90cmFzIGNhZGVuYXMgZGUgdmFsb3IgKGVjb25vbcOtYSBjaXJjdWxhcikKCgojIyMgUHJvYmxlbWEgZGUgRGVjaXNpw7NuCgoqKk9iamV0aXZvOioqIFNlbGVjY2lvbmFyIGxhIG1lam9yIGFsdGVybmF0aXZhIGRlIGludmVyc2nDs24gdGVjbm9sw7NnaWNhIHBhcmEgbGEgZW1wcmVzYSBtZW5jaW9uYWRhIHF1ZSB0aWVuZSBjb21vIGZvcnRhbGV6YSBlbCAqKiJwcmVwYXJlZG5lc3MiIHBhcmEgbGEgdHJhbnNmb3JtYWNpw7NuIGRpZ2l0YWwqKgoKKipBbHRlcm5hdGl2YXM6KioKCiogQTE6IFNpc3RlbWEgRVJQIAoqIEEyOiBQbGF0YWZvcm1hIENSTSAgCiogQTM6IFNvbHVjacOzbiBkZSBCdXNpbmVzcyBJbnRlbGxpZ2VuY2UKCioqQ3JpdGVyaW9zIGRlIEV2YWx1YWNpw7NuOioqCgoqIEMxOiBDb3N0byBkZSBpbXBsZW1lbnRhY2nDs24KKiBDMjogRmFjaWxpZGFkIGRlIHVzbwoqIEMzOiBGdW5jaW9uYWxpZGFkCiogQzQ6IFNvcG9ydGUgdMOpY25pY28KKiBDNTogRXNjYWxhYmlsaWRhZAoKIyMgMi4gQ29uZmlndXJhY2nDs24gZGVsIEVudG9ybm8gZGUgUgoKIyMjIEZ1bmNpb25lcyB5IE1hdHJpY2VzIENSCgpgYGB7ciBsaWJyYXJpZXN9CiMgQ2FyZ2FyIGxpYnJlcsOtYXMgbmVjZXNhcmlhcwpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQoKIyBGdW5jacOzbiBwYXJhIGNhbGN1bGFyIGVsIHZlY3RvciBwcm9waW8gcHJpbmNpcGFsCmNhbGN1bGFyX3ZlY3Rvcl9wcm9waW8gPC0gZnVuY3Rpb24obWF0cml6KSB7CiAgZWlnZW52YWx1ZXMgPC0gZWlnZW4obWF0cml6KQogIG1heF9pbmRleCA8LSB3aGljaC5tYXgoZWlnZW52YWx1ZXMkdmFsdWVzKQogIHZlY3Rvcl9wcm9waW8gPC0gYWJzKGVpZ2VudmFsdWVzJHZlY3RvcnNbLCBtYXhfaW5kZXhdKQogIHJldHVybih2ZWN0b3JfcHJvcGlvIC8gc3VtKHZlY3Rvcl9wcm9waW8pKQp9CgojIEZ1bmNpw7NuIHBhcmEgY2FsY3VsYXIgZWwgw41uZGljZSBkZSBDb25zaXN0ZW5jaWEgKENJKQpjYWxjdWxhcl9DSSA8LSBmdW5jdGlvbihtYXRyaXopIHsKICBuIDwtIG5yb3cobWF0cml6KQogIGVpZ2VudmFsdWVzIDwtIGVpZ2VuKG1hdHJpeikkdmFsdWVzCiAgbGFtYmRhX21heCA8LSBtYXgoUmUoZWlnZW52YWx1ZXMpKQogIENJIDwtIChsYW1iZGFfbWF4IC0gbikgLyAobiAtIDEpCiAgcmV0dXJuKENJKQp9CgojIEZ1bmNpw7NuIHBhcmEgY2FsY3VsYXIgZWwgUmF0aW8gZGUgQ29uc2lzdGVuY2lhIChDUikKY2FsY3VsYXJfQ1IgPC0gZnVuY3Rpb24oQ0ksIG4pIHsKICAjIMONbmRpY2VzIGRlIGNvbnNpc3RlbmNpYSBhbGVhdG9yaWEgc2Vnw7puIFNhYXR5CiAgUkkgPC0gYygwLCAwLCAwLjU4LCAwLjkwLCAxLjEyLCAxLjI0LCAxLjMyLCAxLjQxLCAxLjQ1LCAxLjQ5KQogIGlmIChuIDw9IDEwKSB7CiAgICBDUiA8LSBDSSAvIFJJW25dCiAgfSBlbHNlIHsKICAgIENSIDwtIE5BCiAgfQogIHJldHVybihDUikKfQpgYGAKCgojIyAzLiBNYXRyaWNlcyBkZSBDb21wYXJhY2nDs24gcG9yIFBhcmVzCgojIyMgMy4xIE1hdHJpeiBkZSBDb21wYXJhY2nDs24gZGUgQ3JpdGVyaW9zCgpgYGB7ciBtYXRyaXpfY3JpdGVyaW9zfQojIE1hdHJpeiBkZSBjb21wYXJhY2nDs24gcG9yIHBhcmVzIGRlIGNyaXRlcmlvcyAoNXg1KQojIEVzY2FsYSBkZSBTYWF0eTogMT1pZ3VhbCwgMz1tb2RlcmFkYW1lbnRlIG3DoXMgaW1wb3J0YW50ZSwgNT1mdWVydGVtZW50ZSBtw6FzIGltcG9ydGFudGUsCiMgICAgICAgICAgICAgICAgICA3PW11eSBmdWVydGVtZW50ZSBtw6FzIGltcG9ydGFudGUsIDk9ZXh0cmVtYWRhbWVudGUgbcOhcyBpbXBvcnRhbnRlCgpjcml0ZXJpb3NfbWF0cml6IDwtIG1hdHJpeChjKAogIDEsICAgMS8zLCAxLzIsIDIsICAgMS80LCAgIyBDMTogQ29zdG8KICAzLCAgIDEsICAgMiwgICAzLCAgIDEvMiwgICMgQzI6IEZhY2lsaWRhZCBkZSB1c28KICAyLCAgIDEvMiwgMSwgICAzLCAgIDEvMywgICMgQzM6IEZ1bmNpb25hbGlkYWQKICAxLzIsIDEvMywgMS8zLCAxLCAgIDEvNSwgICMgQzQ6IFNvcG9ydGUgdMOpY25pY28KICA0LCAgIDIsICAgMywgICA1LCAgIDEgICAgICMgQzU6IEVzY2FsYWJpbGlkYWQKKSwgbnJvdyA9IDUsIGJ5cm93ID0gVFJVRSkKCnJvd25hbWVzKGNyaXRlcmlvc19tYXRyaXopIDwtIGMoIkNvc3RvIiwgIkZhY2lsaWRhZF91c28iLCAiRnVuY2lvbmFsaWRhZCIsICJTb3BvcnRlIiwgIkVzY2FsYWJpbGlkYWQiKQpjb2xuYW1lcyhjcml0ZXJpb3NfbWF0cml6KSA8LSBjKCJDb3N0byIsICJGYWNpbGlkYWRfdXNvIiwgIkZ1bmNpb25hbGlkYWQiLCAiU29wb3J0ZSIsICJFc2NhbGFiaWxpZGFkIikKCnByaW50KCJNYXRyaXogZGUgQ29tcGFyYWNpw7NuIGRlIENyaXRlcmlvczoiKQprYWJsZShyb3VuZChjcml0ZXJpb3NfbWF0cml6LCAzKSkKYGBgCgoKIyMjIDMuMiBDw6FsY3VsbyBkZSBQZXNvcyBkZSBDcml0ZXJpb3MKCmBgYHtyIHBlc29zX2NyaXRlcmlvc30KIyBDYWxjdWxhciB2ZWN0b3IgcHJvcGlvIChwZXNvcyBkZSBjcml0ZXJpb3MpCnBlc29zX2NyaXRlcmlvcyA8LSBjYWxjdWxhcl92ZWN0b3JfcHJvcGlvKGNyaXRlcmlvc19tYXRyaXopCm5hbWVzKHBlc29zX2NyaXRlcmlvcykgPC0gcm93bmFtZXMoY3JpdGVyaW9zX21hdHJpeikKCiMgQ2FsY3VsYXIgY29uc2lzdGVuY2lhCkNJX2NyaXRlcmlvcyA8LSBjYWxjdWxhcl9DSShjcml0ZXJpb3NfbWF0cml6KQpDUl9jcml0ZXJpb3MgPC0gY2FsY3VsYXJfQ1IoQ0lfY3JpdGVyaW9zLCA1KQoKcHJpbnQoIlBlc29zIGRlIGxvcyBDcml0ZXJpb3M6IikKa2FibGUoZGF0YS5mcmFtZSgKICBDcml0ZXJpbyA9IG5hbWVzKHBlc29zX2NyaXRlcmlvcyksCiAgUGVzbyA9IHJvdW5kKHBlc29zX2NyaXRlcmlvcywgNCksCiAgUG9yY2VudGFqZSA9IHBhc3RlMChyb3VuZChwZXNvc19jcml0ZXJpb3MgKiAxMDAsIDIpLCAiJSIpCikpCgpwcmludChwYXN0ZSgiw41uZGljZSBkZSBDb25zaXN0ZW5jaWEgKENJKToiLCByb3VuZChDSV9jcml0ZXJpb3MsIDQpKSkKcHJpbnQocGFzdGUoIlJhdGlvIGRlIENvbnNpc3RlbmNpYSAoQ1IpOiIsIHJvdW5kKENSX2NyaXRlcmlvcywgNCkpKQoKaWYgKENSX2NyaXRlcmlvcyA8IDAuMSkgewogIHByaW50KCLinJMgTGEgbWF0cml6IGRlIGNyaXRlcmlvcyBlcyBjb25zaXN0ZW50ZSAoQ1IgPCAwLjEwKSIpCn0gZWxzZSB7CiAgcHJpbnQoImxhIG1hdHJpeiBkZSBjcml0ZXJpb3MgcHJlc2VudGEgaW5jb25zaXN0ZW5jaWFzIChDUiDiiaUgMC4xMCkiKQp9CmBgYAoKCgojIyA0LiBNYXRyaWNlcyBkZSBDb21wYXJhY2nDs24gZGUgQWx0ZXJuYXRpdmFzCgojIyMgNC4xIENyaXRlcmlvIDE6IENvc3RvIGRlIEltcGxlbWVudGFjacOzbgoKYGBge3IgYWx0ZXJuYXRpdmFzX2Nvc3RvfQojIE1hdHJpeiBkZSBjb21wYXJhY2nDs24gZGUgYWx0ZXJuYXRpdmFzIHJlc3BlY3RvIGFsIGNvc3RvCiMgKG1lbm9yIGNvc3RvIGVzIG1lam9yKQpjb3N0b19tYXRyaXogPC0gbWF0cml4KGMoCiAgMSwgICAxLzIsIDMsICAgICMgRVJQIHZzIENSTSwgRVJQIHZzIEJJCiAgMiwgICAxLCAgIDUsICAgICMgQ1JNIHZzIEVSUCwgQ1JNIHZzIEJJICAKICAxLzMsIDEvNSwgMSAgICAgIyBCSSB2cyBFUlAsIEJJIHZzIENSTQopLCBucm93ID0gMywgYnlyb3cgPSBUUlVFKQoKcm93bmFtZXMoY29zdG9fbWF0cml6KSA8LSBjKCJFUlAiLCAiQ1JNIiwgIkJJIikKY29sbmFtZXMoY29zdG9fbWF0cml6KSA8LSBjKCJFUlAiLCAiQ1JNIiwgIkJJIikKCnBlc29zX2Nvc3RvIDwtIGNhbGN1bGFyX3ZlY3Rvcl9wcm9waW8oY29zdG9fbWF0cml6KQpuYW1lcyhwZXNvc19jb3N0bykgPC0gcm93bmFtZXMoY29zdG9fbWF0cml6KQoKcHJpbnQoIk1hdHJpeiAtIENvc3RvIGRlIEltcGxlbWVudGFjacOzbjoiKQprYWJsZShyb3VuZChjb3N0b19tYXRyaXosIDMpKQpwcmludCgiUGVzb3MgcGFyYSBDb3N0bzoiKQprYWJsZShkYXRhLmZyYW1lKEFsdGVybmF0aXZhID0gbmFtZXMocGVzb3NfY29zdG8pLCBQZXNvID0gcm91bmQocGVzb3NfY29zdG8sIDQpKSkKYGBgCgoKCiMjIyA0LjIgQ3JpdGVyaW8gMjogRmFjaWxpZGFkIGRlIFVzbwoKYGBge3IgYWx0ZXJuYXRpdmFzX2ZhY2lsaWRhZH0KZmFjaWxpZGFkX21hdHJpeiA8LSBtYXRyaXgoYygKICAxLCAgIDEvMywgMS8yLCAgIyBFUlAgdnMgQ1JNLCBFUlAgdnMgQkkKICAzLCAgIDEsICAgMiwgICAgIyBDUk0gdnMgRVJQLCBDUk0gdnMgQkkKICAyLCAgIDEvMiwgMSAgICAgIyBCSSB2cyBFUlAsIEJJIHZzIENSTQopLCBucm93ID0gMywgYnlyb3cgPSBUUlVFKQoKcm93bmFtZXMoZmFjaWxpZGFkX21hdHJpeikgPC0gYygiRVJQIiwgIkNSTSIsICJCSSIpCmNvbG5hbWVzKGZhY2lsaWRhZF9tYXRyaXopIDwtIGMoIkVSUCIsICJDUk0iLCAiQkkiKQoKcGVzb3NfZmFjaWxpZGFkIDwtIGNhbGN1bGFyX3ZlY3Rvcl9wcm9waW8oZmFjaWxpZGFkX21hdHJpeikKbmFtZXMocGVzb3NfZmFjaWxpZGFkKSA8LSByb3duYW1lcyhmYWNpbGlkYWRfbWF0cml6KQoKcHJpbnQoIk1hdHJpeiAtIEZhY2lsaWRhZCBkZSBVc286IikKa2FibGUocm91bmQoZmFjaWxpZGFkX21hdHJpeiwgMykpCnByaW50KCJQZXNvcyBwYXJhIEZhY2lsaWRhZCBkZSBVc286IikKa2FibGUoZGF0YS5mcmFtZShBbHRlcm5hdGl2YSA9IG5hbWVzKHBlc29zX2ZhY2lsaWRhZCksIFBlc28gPSByb3VuZChwZXNvc19mYWNpbGlkYWQsIDQpKSkKYGBgCgoKIyMjIDQuMyBDcml0ZXJpbyAzOiBGdW5jaW9uYWxpZGFkCgpgYGB7ciBhbHRlcm5hdGl2YXNfZnVuY2lvbmFsaWRhZH0KZnVuY2lvbmFsaWRhZF9tYXRyaXogPC0gbWF0cml4KGMoCiAgMSwgICAyLCAgIDEvMiwgICMgRVJQIHZzIENSTSwgRVJQIHZzIEJJCiAgMS8yLCAxLCAgIDEvMywgICMgQ1JNIHZzIEVSUCwgQ1JNIHZzIEJJCiAgMiwgICAzLCAgIDEgICAgICMgQkkgdnMgRVJQLCBCSSB2cyBDUk0KKSwgbnJvdyA9IDMsIGJ5cm93ID0gVFJVRSkKCnJvd25hbWVzKGZ1bmNpb25hbGlkYWRfbWF0cml6KSA8LSBjKCJFUlAiLCAiQ1JNIiwgIkJJIikKY29sbmFtZXMoZnVuY2lvbmFsaWRhZF9tYXRyaXopIDwtIGMoIkVSUCIsICJDUk0iLCAiQkkiKQoKcGVzb3NfZnVuY2lvbmFsaWRhZCA8LSBjYWxjdWxhcl92ZWN0b3JfcHJvcGlvKGZ1bmNpb25hbGlkYWRfbWF0cml6KQpuYW1lcyhwZXNvc19mdW5jaW9uYWxpZGFkKSA8LSByb3duYW1lcyhmdW5jaW9uYWxpZGFkX21hdHJpeikKCnByaW50KCJNYXRyaXogLSBGdW5jaW9uYWxpZGFkOiIpCmthYmxlKHJvdW5kKGZ1bmNpb25hbGlkYWRfbWF0cml6LCAzKSkKcHJpbnQoIlBlc29zIHBhcmEgRnVuY2lvbmFsaWRhZDoiKQprYWJsZShkYXRhLmZyYW1lKEFsdGVybmF0aXZhID0gbmFtZXMocGVzb3NfZnVuY2lvbmFsaWRhZCksIFBlc28gPSByb3VuZChwZXNvc19mdW5jaW9uYWxpZGFkLCA0KSkpCmBgYAoKIyMjIDQuNCBDcml0ZXJpbyA0OiBTb3BvcnRlIFTDqWNuaWNvCgpgYGB7ciBhbHRlcm5hdGl2YXNfc29wb3J0ZX0Kc29wb3J0ZV9tYXRyaXogPC0gbWF0cml4KGMoCiAgMSwgICAzLCAgIDIsICAgICMgRVJQIHZzIENSTSwgRVJQIHZzIEJJCiAgMS8zLCAxLCAgIDEvMiwgICMgQ1JNIHZzIEVSUCwgQ1JNIHZzIEJJCiAgMS8yLCAyLCAgIDEgICAgICMgQkkgdnMgRVJQLCBCSSB2cyBDUk0KKSwgbnJvdyA9IDMsIGJ5cm93ID0gVFJVRSkKCnJvd25hbWVzKHNvcG9ydGVfbWF0cml6KSA8LSBjKCJFUlAiLCAiQ1JNIiwgIkJJIikKY29sbmFtZXMoc29wb3J0ZV9tYXRyaXopIDwtIGMoIkVSUCIsICJDUk0iLCAiQkkiKQoKcGVzb3Nfc29wb3J0ZSA8LSBjYWxjdWxhcl92ZWN0b3JfcHJvcGlvKHNvcG9ydGVfbWF0cml6KQpuYW1lcyhwZXNvc19zb3BvcnRlKSA8LSByb3duYW1lcyhzb3BvcnRlX21hdHJpeikKCnByaW50KCJNYXRyaXogLSBTb3BvcnRlIFTDqWNuaWNvOiIpCmthYmxlKHJvdW5kKHNvcG9ydGVfbWF0cml6LCAzKSkKcHJpbnQoIlBlc29zIHBhcmEgU29wb3J0ZSBUw6ljbmljbzoiKQprYWJsZShkYXRhLmZyYW1lKEFsdGVybmF0aXZhID0gbmFtZXMocGVzb3Nfc29wb3J0ZSksIFBlc28gPSByb3VuZChwZXNvc19zb3BvcnRlLCA0KSkpCmBgYAoKIyMjIDQuNSBDcml0ZXJpbyA1OiBFc2NhbGFiaWxpZGFkCgpgYGB7ciBhbHRlcm5hdGl2YXNfZXNjYWxhYmlsaWRhZH0KZXNjYWxhYmlsaWRhZF9tYXRyaXogPC0gbWF0cml4KGMoCiAgMSwgICAxLzIsIDIsICAgICMgRVJQIHZzIENSTSwgRVJQIHZzIEJJCiAgMiwgICAxLCAgIDQsICAgICMgQ1JNIHZzIEVSUCwgQ1JNIHZzIEJJCiAgMS8yLCAxLzQsIDEgICAgICMgQkkgdnMgRVJQLCBCSSB2cyBDUk0KKSwgbnJvdyA9IDMsIGJ5cm93ID0gVFJVRSkKCnJvd25hbWVzKGVzY2FsYWJpbGlkYWRfbWF0cml6KSA8LSBjKCJFUlAiLCAiQ1JNIiwgIkJJIikKY29sbmFtZXMoZXNjYWxhYmlsaWRhZF9tYXRyaXopIDwtIGMoIkVSUCIsICJDUk0iLCAiQkkiKQoKcGVzb3NfZXNjYWxhYmlsaWRhZCA8LSBjYWxjdWxhcl92ZWN0b3JfcHJvcGlvKGVzY2FsYWJpbGlkYWRfbWF0cml6KQpuYW1lcyhwZXNvc19lc2NhbGFiaWxpZGFkKSA8LSByb3duYW1lcyhlc2NhbGFiaWxpZGFkX21hdHJpeikKCnByaW50KCJNYXRyaXogLSBFc2NhbGFiaWxpZGFkOiIpCmthYmxlKHJvdW5kKGVzY2FsYWJpbGlkYWRfbWF0cml6LCAzKSkKcHJpbnQoIlBlc29zIHBhcmEgRXNjYWxhYmlsaWRhZDoiKQprYWJsZShkYXRhLmZyYW1lKEFsdGVybmF0aXZhID0gbmFtZXMocGVzb3NfZXNjYWxhYmlsaWRhZCksIFBlc28gPSByb3VuZChwZXNvc19lc2NhbGFiaWxpZGFkLCA0KSkpCmBgYAoKIyMgNS4gQ8OhbGN1bG8gZGUgUHVudHVhY2lvbmVzIEZpbmFsZXMKCmBgYHtyIHB1bnR1YWNpb25lc19maW5hbGVzfQojIENyZWFyIG1hdHJpeiBkZSBkZWNpc2nDs24KbWF0cml6X2RlY2lzaW9uIDwtIGNiaW5kKHBlc29zX2Nvc3RvLCBwZXNvc19mYWNpbGlkYWQsIHBlc29zX2Z1bmNpb25hbGlkYWQsIHBlc29zX3NvcG9ydGUsIHBlc29zX2VzY2FsYWJpbGlkYWQpCmNvbG5hbWVzKG1hdHJpel9kZWNpc2lvbikgPC0gYygiQ29zdG8iLCAiRmFjaWxpZGFkX3VzbyIsICJGdW5jaW9uYWxpZGFkIiwgIlNvcG9ydGUiLCAiRXNjYWxhYmlsaWRhZCIpCgpwcmludCgiTWF0cml6IGRlIERlY2lzacOzbiAoUGVzb3MgZGUgYWx0ZXJuYXRpdmFzIHBvciBjcml0ZXJpbyk6IikKa2FibGUocm91bmQobWF0cml6X2RlY2lzaW9uLCA0KSkKCiMgQ2FsY3VsYXIgcHVudHVhY2lvbmVzIGZpbmFsZXMKcHVudHVhY2lvbmVzX2ZpbmFsZXMgPC0gbWF0cml6X2RlY2lzaW9uICUqJSBwZXNvc19jcml0ZXJpb3MKcHVudHVhY2lvbmVzX2ZpbmFsZXMgPC0gYXMudmVjdG9yKHB1bnR1YWNpb25lc19maW5hbGVzKQpuYW1lcyhwdW50dWFjaW9uZXNfZmluYWxlcykgPC0gYygiU2lzdGVtYSBFUlAiLCAiUGxhdGFmb3JtYSBDUk0iLCAiU29sdWNpw7NuIEJJIikKCiMgQ3JlYXIgdGFibGEgZGUgcmVzdWx0YWRvcwpyZXN1bHRhZG9zIDwtIGRhdGEuZnJhbWUoCiAgQWx0ZXJuYXRpdmEgPSBuYW1lcyhwdW50dWFjaW9uZXNfZmluYWxlcyksCiAgUHVudHVhY2lvbiA9IHJvdW5kKHB1bnR1YWNpb25lc19maW5hbGVzLCA0KSwKICBQb3JjZW50YWplID0gcGFzdGUwKHJvdW5kKHB1bnR1YWNpb25lc19maW5hbGVzICogMTAwLCAyKSwgIiUiKSwKICBSYW5raW5nID0gcmFuaygtcHVudHVhY2lvbmVzX2ZpbmFsZXMpCikKCnByaW50KCJSRVNVTFRBRE9TIEZJTkFMRVM6IikKa2FibGUocmVzdWx0YWRvc1tvcmRlcigtcmVzdWx0YWRvcyRQdW50dWFjaW9uKSwgXSkKYGBgCgoKCiMjIDYuIEFuw6FsaXNpcyBkZSBTZW5zaWJpbGlkYWQgcG9yIENyaXRlcmlvcwoKYGBge3IgYW5hbGlzaXNfc2Vuc2liaWxpZGFkfQojIENyZWFyIG1hdHJpeiBkZXRhbGxhZGEgcGFyYSBhbsOhbGlzaXMKY29udHJpYnVjaW9uZXMgPC0gbWF0cml6X2RlY2lzaW9uICogbWF0cml4KHJlcChwZXNvc19jcml0ZXJpb3MsIGVhY2ggPSAzKSwgbnJvdyA9IDMpCnJvd25hbWVzKGNvbnRyaWJ1Y2lvbmVzKSA8LSBjKCJTaXN0ZW1hIEVSUCIsICJQbGF0YWZvcm1hIENSTSIsICJTb2x1Y2nDs24gQkkiKQpjb2xuYW1lcyhjb250cmlidWNpb25lcykgPC0gYygiQ29zdG8iLCAiRmFjaWxpZGFkIGRlIFVzbyIsICJGdW5jaW9uYWxpZGFkIiwgIlNvcG9ydGUiLCAiRXNjYWxhYmlsaWRhZCIpCgpwcmludCgiQ29udHJpYnVjacOzbiBkZSBjYWRhIGNyaXRlcmlvIGEgbGEgcHVudHVhY2nDs24gZmluYWw6IikKa2FibGUocm91bmQoY29udHJpYnVjaW9uZXMsIDQpKQpgYGAKCiMjIDcuIFZpc3VhbGl6YWNpb25lcwoKIyMjIDcuMSBHcsOhZmljbyBDb21wYXJhdGl2byBkZSBBbHRlcm5hdGl2YXMKCmBgYHtyIGdyYWZpY29fY29tcGFyYXRpdm8sIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04fQojIFByZXBhcmFyIGRhdG9zIHBhcmEgdmlzdWFsaXphY2nDs24KZGF0b3Nfdml6IDwtIGRhdGEuZnJhbWUoCiAgQWx0ZXJuYXRpdmEgPSByZXAobmFtZXMocHVudHVhY2lvbmVzX2ZpbmFsZXMpLCAyKSwKICBWYWxvciA9IGMocHVudHVhY2lvbmVzX2ZpbmFsZXMsIHB1bnR1YWNpb25lc19maW5hbGVzKSwKICBUaXBvID0gcmVwKGMoIlB1bnR1YWNpw7NuIEZpbmFsIiwgIlBvcmNlbnRhamUiKSwgZWFjaCA9IDMpLAogIFZhbG9yX1BjdCA9IGMocHVudHVhY2lvbmVzX2ZpbmFsZXMsIHB1bnR1YWNpb25lc19maW5hbGVzICogMTAwKQopCgojIEdyw6FmaWNvIGRlIGJhcnJhcyBjb21wYXJhdGl2bwpwMSA8LSBnZ3Bsb3QoZGF0b3Nfdml6W2RhdG9zX3ZpeiRUaXBvID09ICJQdW50dWFjacOzbiBGaW5hbCIsIF0sIAogICAgICAgICAgICAgYWVzKHggPSByZW9yZGVyKEFsdGVybmF0aXZhLCAtVmFsb3IpLCB5ID0gVmFsb3IsIGZpbGwgPSBBbHRlcm5hdGl2YSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgYWxwaGEgPSAwLjgsIHdpZHRoID0gMC42KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChyb3VuZChWYWxvciwgMyksICJcbigiLCByb3VuZChWYWxvcl9QY3QsIDEpLCAiJSkiKSksIAogICAgICAgICAgICB2anVzdCA9IC0wLjUsIHNpemUgPSA0LCBmb250ZmFjZSA9ICJib2xkIikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAiU2V0MiIpICsKICBsYWJzKHRpdGxlID0gIkNvbXBhcmFjacOzbiBkZSBBbHRlcm5hdGl2YXMgLSBNZXRvZG9sb2fDrWEgQUhQIiwKICAgICAgIHN1YnRpdGxlID0gcGFzdGUoIkdhbmFkb3I6IiwgbmFtZXMocHVudHVhY2lvbmVzX2ZpbmFsZXMpW3doaWNoLm1heChwdW50dWFjaW9uZXNfZmluYWxlcyldKSwKICAgICAgIHggPSAiQWx0ZXJuYXRpdmFzIiwKICAgICAgIHkgPSAiUHVudHVhY2nDs24gQUhQIiwKICAgICAgIGNhcHRpb24gPSAiTWV0b2RvbG9nw61hOiBBbmFseXRpYyBIaWVyYXJjaHkgUHJvY2VzcyAoVGhvbWFzIFNhYXR5KSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEyLCBjb2xvciA9ICJkYXJrZ3JlZW4iKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMC41KSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICB5bGltKDAsIG1heChwdW50dWFjaW9uZXNfZmluYWxlcykgKiAxLjIpCgpwcmludChwMSkKYGBgCgojIyMgNy4yIEdyw6FmaWNvIGRlIENvbnRyaWJ1Y2lvbmVzIHBvciBDcml0ZXJpbwoKYGBge3IgZ3JhZmljb19jcml0ZXJpb3MsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04fQojIFByZXBhcmFyIGRhdG9zIHBhcmEgZ3LDoWZpY28gZGUgY29udHJpYnVjaW9uZXMKY29udHJpYl9sb25nIDwtIG1lbHQoY29udHJpYnVjaW9uZXMpCmNvbG5hbWVzKGNvbnRyaWJfbG9uZykgPC0gYygiQWx0ZXJuYXRpdmEiLCAiQ3JpdGVyaW8iLCAiQ29udHJpYnVjaW9uIikKCiMgR3LDoWZpY28gZGUgYmFycmFzIGFwaWxhZGFzCnAyIDwtIGdncGxvdChjb250cmliX2xvbmcsIGFlcyh4ID0gQWx0ZXJuYXRpdmEsIHkgPSBDb250cmlidWNpb24sIGZpbGwgPSBDcml0ZXJpbykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIodHlwZSA9ICJxdWFsIiwgcGFsZXR0ZSA9ICJTZXQzIikgKwogIGxhYnModGl0bGUgPSAiQ29udHJpYnVjacOzbiBkZSBjYWRhIENyaXRlcmlvIHBvciBBbHRlcm5hdGl2YSIsCiAgICAgICBzdWJ0aXRsZSA9ICJBbsOhbGlzaXMgZGUgU2Vuc2liaWxpZGFkIC0gTWV0b2RvbG9nw61hIEFIUCIsCiAgICAgICB4ID0gIkFsdGVybmF0aXZhcyIsCiAgICAgICB5ID0gIkNvbnRyaWJ1Y2nDs24gYSBsYSBQdW50dWFjacOzbiBGaW5hbCIsCiAgICAgICBmaWxsID0gIkNyaXRlcmlvcyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQobnJvdyA9IDEpKQoKcHJpbnQocDIpCmBgYAoKIyMjIDcuMyBHcsOhZmljbyBSYWRhciBkZSBBbHRlcm5hdGl2YXMKCmBgYHtyIGdyYWZpY29fcmFkYXIsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KIyBQcmVwYXJhciBkYXRvcyBwYXJhIGdyw6FmaWNvIHJhZGFyCnJhZGFyX2RhdGEgPC0gYXMuZGF0YS5mcmFtZShtYXRyaXpfZGVjaXNpb24pCnJhZGFyX2RhdGEkQWx0ZXJuYXRpdmEgPC0gcm93bmFtZXMocmFkYXJfZGF0YSkKCiMgQ29udmVydGlyIGEgZm9ybWF0byBsYXJnbwpyYWRhcl9sb25nIDwtIG1lbHQocmFkYXJfZGF0YSwgaWQudmFycyA9ICJBbHRlcm5hdGl2YSIpCmNvbG5hbWVzKHJhZGFyX2xvbmcpIDwtIGMoIkFsdGVybmF0aXZhIiwgIkNyaXRlcmlvIiwgIlZhbG9yIikKCiMgR3LDoWZpY28gZGUgY29vcmRlbmFkYXMgcG9sYXJlcyAocHNldWRvLXJhZGFyKQpwMyA8LSBnZ3Bsb3QocmFkYXJfbG9uZywgYWVzKHggPSBDcml0ZXJpbywgeSA9IFZhbG9yLCBjb2xvciA9IEFsdGVybmF0aXZhLCBncm91cCA9IEFsdGVybmF0aXZhKSkgKwogIGdlb21fbGluZShzaXplID0gMS4yLCBhbHBoYSA9IDAuOCkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGFscGhhID0gMC45KSArCiAgY29vcmRfcG9sYXIoKSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAiRGFyazIiKSArCiAgbGFicyh0aXRsZSA9ICJQZXJmaWwgZGUgQWx0ZXJuYXRpdmFzIHBvciBDcml0ZXJpbyIsCiAgICAgICBzdWJ0aXRsZSA9ICJHcsOhZmljbyBSYWRhciAtIEFuw6FsaXNpcyBNdWx0aWNyaXRlcmlvIEFIUCIsCiAgICAgICB5ID0gIlB1bnR1YWNpw7NuIHBvciBDcml0ZXJpbyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNCwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEyKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKcHJpbnQocDMpCmBgYAoKIyMgOC4gUmVzdW1lbiBFamVjdXRpdm8KCmBgYHtyIHJlc3VtZW59Cm1lam9yX2FsdGVybmF0aXZhIDwtIG5hbWVzKHB1bnR1YWNpb25lc19maW5hbGVzKVt3aGljaC5tYXgocHVudHVhY2lvbmVzX2ZpbmFsZXMpXQpwdW50dWFjaW9uX21lam9yIDwtIG1heChwdW50dWFjaW9uZXNfZmluYWxlcykKCgpjYXQoIj09PT09PT09PT0gUkVTVU1FTiBFSkVDVVRJVk8gPT09PT09PT09PVxuIikKY2F0KCJNZXRvZG9sb2fDrWE6IEFuYWx5dGljIEhpZXJhcmNoeSBQcm9jZXNzIChBSFApIC0gVGhvbWFzIFNhYXR5XG4iKQpjYXQoIkNyaXRlcmlvcyBldmFsdWFkb3M6IiwgbGVuZ3RoKHBlc29zX2NyaXRlcmlvcyksICJcbiIpCmNhdCgiQWx0ZXJuYXRpdmFzIGFuYWxpemFkYXM6IiwgbGVuZ3RoKHB1bnR1YWNpb25lc19maW5hbGVzKSwgIlxuIikKY2F0KCJDb25zaXN0ZW5jaWEgZGUganVpY2lvczogQ1IgPSIsIHJvdW5kKENSX2NyaXRlcmlvcywgMyksIAogICAgaWZlbHNlKENSX2NyaXRlcmlvcyA8IDAuMSwgIihBY2VwdGFibGUpIiwgIihSZXZpc2FyKSIpLCAiXG5cbiIpCgpjYXQoIlJFQ09NRU5EQUNJw5NOOlxuIikKY2F0KCJMYSBtZWpvciBhbHRlcm5hdGl2YSBlczoiLCBtZWpvcl9hbHRlcm5hdGl2YSwgIlxuIikKY2F0KCJQdW50dWFjacOzbiBBSFA6Iiwgcm91bmQocHVudHVhY2lvbl9tZWpvciwgNCksIAogICAgcGFzdGUwKCIoIiwgcm91bmQocHVudHVhY2lvbl9tZWpvciAqIDEwMCwgMSksICIlKSIpLCAiXG5cbiIpCgpjYXQoIlJBTktJTkcgQ09NUExFVE86XG4iKQpmb3IoaSBpbiBvcmRlcigtcHVudHVhY2lvbmVzX2ZpbmFsZXMpKSB7CiAgY2F0KHBhc3RlMCh3aGljaChvcmRlcigtcHVudHVhY2lvbmVzX2ZpbmFsZXMpID09IGkpLCAiwrAgIiwgCiAgICAgICAgICAgICBuYW1lcyhwdW50dWFjaW9uZXNfZmluYWxlcylbaV0sICI6ICIsIAogICAgICAgICAgICAgcm91bmQocHVudHVhY2lvbmVzX2ZpbmFsZXNbaV0sIDQpLCAKICAgICAgICAgICAgICIgKCIsIHJvdW5kKHB1bnR1YWNpb25lc19maW5hbGVzW2ldICogMTAwLCAxKSwgIiUpXG4iKSkKfQoKY2F0KCJcbkNSSVRFUklPIE3DgVMgSU1QT1JUQU5URToiLCBuYW1lcyhwZXNvc19jcml0ZXJpb3MpW3doaWNoLm1heChwZXNvc19jcml0ZXJpb3MpXSwgCiAgICBwYXN0ZTAoIigiLCByb3VuZChtYXgocGVzb3NfY3JpdGVyaW9zKSAqIDEwMCwgMSksICIlKSIpKQpgYGAKCgoqKk5vdGEgbWV0b2RvbMOzZ2ljYToqKiBFc3RlIGFuw6FsaXNpcyBpbXBsZW1lbnRhIGxhIG1ldG9kb2xvZ8OtYSBBSFAgZGVzYXJyb2xsYWRhIHBvciBUaG9tYXMgU2FhdHksIHV0aWxpemFuZG8gY29tcGFyYWNpb25lcyBwb3IgcGFyZXMgY29uIGxhIGVzY2FsYSBmdW5kYW1lbnRhbCBkZSAxLTkgeSB2ZXJpZmljYW5kbyBsYSBjb25zaXN0ZW5jaWEgbWVkaWFudGUgZWwgUmF0aW8gZGUgQ29uc2lzdGVuY2lhIChDUikuIFNlIHJlY29taWVuZGEgcXVlIENSIDwgMC4xMCBwYXJhIGNvbnNpZGVyYXIgbG9zIGp1aWNpb3MgY29tbyBjb25zaXN0ZW50ZXMuCgoKCioqIGxpbmsgdG8gPGh0dHBzOi8vcnB1YnMuY29tL3JpY2FyZG9ycGFtYS8xMzM4NTY3PioqCgpjaXRlOiBQYWxtYSwgUi4gUi4gKDIwMjUpLiBFeGNlbGVuY2lhIE9wZXJhY2lvbmFsIEJhc2VzIHBhcmEgdW4gZnJhbWV3b3JrIGRlIGVzdHJhdGVnaWEgZGUgbWFudWZhY3R1cmEuIFplbm9kby4gaHR0cHM6Ly9kb2kub3JnLzEwLjUyODEvemVub2RvLjE2OTQ1MzA2Cg==