# Instalar paquetes si no están disponibles (ejecutar una sola vez)
# install.packages("devtools")
# devtools::install_github("centromagis/paqueteMODELOS", force = TRUE)
# install.packages(c("tidyverse","plotly","leaflet","car","lmtest",
#                    "nortest","kableExtra","modelsummary","GGally"))

library(paqueteMODELOS)   # datos vivienda
library(tidyverse)         # manipulación y visualización
library(plotly)            # gráficos interactivos
library(leaflet)           # mapas interactivos
library(car)               # VIF y diagnósticos
library(lmtest)            # prueba Durbin-Watson
library(nortest)           # pruebas de normalidad adicionales
library(kableExtra)        # tablas estilizadas
library(modelsummary)      # comparación de modelos
library(GGally)            # matriz de correlaciones

# Carga del dataset
data("vivienda")

1 Introducción

El mercado inmobiliario de Cali refleja una dinámica compleja en la que el precio de las viviendas es el resultado de múltiples factores: características físicas del inmueble, estrato socioeconómico, zona de la ciudad y tipo de propiedad, entre otros. Comprender cómo interactúan estas variables es esencial para que los agentes del sector puedan asesorar a sus clientes con información objetiva y cuantificable.

C&A (Casas y Apartamentos), agencia dirigida por María, enfrenta una solicitud concreta: orientar a una compañía internacional en la adquisición de dos viviendas para ubicar a dos de sus empleados en Cali. Cada caso tiene perfiles distintos en cuanto a tipo de inmueble, zona, características físicas y presupuesto disponible. Dar una respuesta sólida requiere ir más allá de la experiencia empírica: es necesario aplicar herramientas estadísticas formales que permitan estimar precios, cuantificar la incertidumbre y filtrar las opciones reales de mercado.

Este informe aplica regresión lineal múltiple (MCO) sobre los datos de oferta inmobiliaria de Cali de los últimos tres meses. El análisis se estructura en siete pasos para cada solicitud: depuración y filtro de datos, análisis exploratorio con visualizaciones interactivas, estimación e interpretación del modelo, validación de supuestos estadísticos, predicción del precio puntual con intervalo de confianza, e identificación de ofertas concretas georreferenciadas en mapas interactivos.

2 Planteamiento de la solicitud

María recibió una solicitud formal de una compañía internacional que requiere ubicar a dos empleados en Cali. La Tabla 1 resume las condiciones específicas de cada caso.

solicitud <- data.frame(
  Característica    = c("Tipo", "Área construida (m²)", "Parqueaderos",
                        "Baños", "Habitaciones", "Estrato", "Zona",
                        "Crédito preaprobado (millones COP)"),
  `Vivienda 1`      = c("Casa",  "200", "1", "2", "4", "4 o 5", "Norte", "350"),
  `Vivienda 2`      = c("Apartamento", "300", "3", "3", "5", "5 o 6", "Sur", "850"),
  check.names       = FALSE
)

mi_tabla(
  solicitud,
  titulo    = "Características de las viviendas solicitadas por la compañía internacional.",
  digits    = 0,
  num_cols  = dplyr::where(~ FALSE)
)
Tabla 1. Características de las viviendas solicitadas por la compañía internacional.
Característica Vivienda 1 Vivienda 2
Tipo Casa Apartamento
Área construida (m²) 200 300
Parqueaderos 1 3
Baños 2 3
Habitaciones 4 5
Estrato 4 o 5 5 o 6
Zona Norte Sur
Crédito preaprobado (millones COP) 350 850

3 Resolución de la solicitud

3.1 Solicitud 1: Casa zona norte

3.1.1 Filtro inicial y depuración

Se realizó un filtro sobre la base vivienda seleccionando únicamente los registros correspondientes a casas ubicadas en la Zona Norte de Cali. Adicionalmente se verificó la presencia de valores faltantes en las variables clave del modelo y se identificaron registros duplicados.

# Filtro: casas en Zona Norte
base1 <- vivienda %>%
  filter(tipo == "Casa", zona == "Zona Norte")

cat("Registros en base1:", nrow(base1), "\n")
## Registros en base1: 722
cat("Valores faltantes por variable:\n")
## Valores faltantes por variable:
print(colSums(is.na(base1)))
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0          372            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##          287            0            0            0            0            0 
##      latitud 
##            0
cat("\nRegistros duplicados:", sum(duplicated(base1)), "\n")
## 
## Registros duplicados: 0
base1 %>%
  head(3) %>%
  mi_tabla(titulo = "Primeros 3 registros – Casas Zona Norte")
Tabla 2. Primeros 3 registros – Casas Zona Norte
id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
1209 Zona Norte 02 5 320 150 2 4 6 Casa acopi -76.513 3.480
1592 Zona Norte 02 5 780 380 2 3 3 Casa acopi -76.517 3.487
4057 Zona Norte 02 6 750 445 NA 7 6 Casa acopi -76.530 3.385
base1 %>%
  count(tipo, name = "n") %>%
  mi_tabla(titulo = "Verificación: tipo de inmueble en base1")
Tabla 3. Verificación: tipo de inmueble en base1
tipo n
Casa 722
base1 %>%
  count(zona, name = "n") %>%
  mi_tabla(titulo = "Verificación: zona en base1")
Tabla 4. Verificación: zona en base1
zona n
Zona Norte 722
base1 %>%
  count(estrato, name = "n") %>%
  arrange(estrato) %>%
  mi_tabla(titulo = "Distribución por estrato – Casas Zona Norte")
Tabla 5. Distribución por estrato – Casas Zona Norte
estrato n
3 235
4 161
5 271
6 55

Interpretación del filtro: La base1 contiene exclusivamente casas de la Zona Norte, lo cual queda confirmado por las tablas de verificación. Se observa que no hay registros de otros tipos de inmueble ni de otras zonas. La distribución por estrato permite anticipar que el análisis se concentrará en estratos medios-altos. Los valores faltantes y duplicados identificados serán considerados antes de la estimación del modelo.

mapa_base1 <- leaflet(data = base1) %>%
  addTiles() %>%
  addCircleMarkers(
    lng    = ~longitud,
    lat    = ~latitud,
    color  = "steelblue",
    radius = 5,
    popup  = ~paste0(
      "<b>Barrio:</b> ", barrio, "<br>",
      "<b>Precio:</b> $", preciom, " M<br>",
      "<b>Área:</b> ", areaconst, " m²<br>",
      "<b>Estrato:</b> ", estrato
    )
  ) %>%
  addLegend("bottomright", colors = "steelblue",
            labels = "Casas - Zona Norte", title = "base1")

htmltools::tagList(mapa_base1)
.FIG_N <- .FIG_N + 1
knitr::asis_output(sprintf(
  '<div id="mapa_base1" style="text-align:center; margin-top:6px;">
   <strong>Figura %d.</strong> Ubicación geográfica de las casas en Zona Norte de Cali
   </div>', .FIG_N
))
Figura 1. Ubicación geográfica de las casas en Zona Norte de Cali

Análisis del mapa: Al visualizar los puntos sobre el mapa de Cali, es posible que algunos marcadores aparezcan fuera del polígono esperado para la Zona Norte. Esto se puede deber a dos razones principales: (1) la clasificación por zona es autodeclarada por el oferente y puede contener imprecisiones, y (2) los límites administrativos entre zonas no están definidos con precisión en la base de datos. En un análisis más riguroso se recomendaría validar las coordenadas con un shapefile oficial de las comunas de Cali, y reclasificar o eliminar los puntos que queden fuera del área norte antes de modelar.

3.1.2 Análisis exploratorio

Se construyó una matriz de correlaciones entre las variables numéricas relevantes y tres gráficos interactivos que permiten explorar la relación del precio con el área construida, el número de habitaciones y el estrato socioeconómico.

# Estadísticas descriptivas de las variables del modelo
base1 %>%
  select(preciom, areaconst, estrato, habitaciones, parqueaderos, banios) %>%
  summary() %>%
  print()
##     preciom         areaconst         estrato       habitaciones   
##  Min.   :  89.0   Min.   :  30.0   Min.   :3.000   Min.   : 0.000  
##  1st Qu.: 261.2   1st Qu.: 140.0   1st Qu.:3.000   1st Qu.: 3.000  
##  Median : 390.0   Median : 240.0   Median :4.000   Median : 4.000  
##  Mean   : 445.9   Mean   : 264.9   Mean   :4.202   Mean   : 4.507  
##  3rd Qu.: 550.0   3rd Qu.: 336.8   3rd Qu.:5.000   3rd Qu.: 5.000  
##  Max.   :1940.0   Max.   :1440.0   Max.   :6.000   Max.   :10.000  
##                                                                    
##   parqueaderos        banios      
##  Min.   : 1.000   Min.   : 0.000  
##  1st Qu.: 1.000   1st Qu.: 2.000  
##  Median : 2.000   Median : 3.000  
##  Mean   : 2.182   Mean   : 3.555  
##  3rd Qu.: 3.000   3rd Qu.: 4.000  
##  Max.   :10.000   Max.   :10.000  
##  NA's   :287
vars_num <- base1 %>%
  select(preciom, areaconst, estrato, banios, habitaciones, parqueaderos)

p_pairs <- ggpairs(
  vars_num,
  title = "Matriz de correlaciones – Casas Zona Norte",
  lower = list(continuous = wrap("smooth", alpha = 0.3, color = "steelblue")),
  diag  = list(continuous = wrap("densityDiag", fill = "steelblue", alpha = 0.4)),
  upper = list(continuous = wrap("cor", size = 3.5))
) + theme_minimal()

mi_figura(
  plot   = p_pairs,
  id     = "correlacion_base1",
  titulo = "Matriz de correlaciones – Casas Zona Norte"
)
Figura 2. Matriz de correlaciones – Casas Zona Norte
p1 <- plot_ly(base1,
              x = ~areaconst, y = ~preciom,
              color = ~factor(estrato), colors = "Set1",
              type = "scatter", mode = "markers",
              marker = list(size = 8, opacity = 0.7),
              text = ~paste("Barrio:", barrio,
                            "<br>Precio: $", preciom, "M",
                            "<br>Área:", areaconst, "m²",
                            "<br>Estrato:", estrato)) %>%
  layout(
    title  = "Precio vs Área construida – Casas Zona Norte",
    xaxis  = list(title = "Área construida (m²)"),
    yaxis  = list(title = "Precio (millones COP)"),
    legend = list(title = list(text = "Estrato"))
  )

htmltools::tagList(p1)
.FIG_N <- .FIG_N + 1
knitr::asis_output(sprintf(
  '<div id="precio_area1" style="text-align:center; margin-top:6px;">
   <strong>Figura %d.</strong> Precio vs Área construida por estrato (interactivo)
   </div>', .FIG_N
))
Figura 3. Precio vs Área construida por estrato (interactivo)
p2 <- plot_ly(base1,
              x = ~habitaciones, y = ~preciom,
              color = ~factor(estrato), colors = "Set2",
              type = "scatter", mode = "markers",
              marker = list(size = 8, opacity = 0.7),
              text = ~paste("Barrio:", barrio,
                            "<br>Precio: $", preciom, "M",
                            "<br>Habitaciones:", habitaciones)) %>%
  layout(
    title  = "Precio vs Número de habitaciones – Casas Zona Norte",
    xaxis  = list(title = "Habitaciones"),
    yaxis  = list(title = "Precio (millones COP)"),
    legend = list(title = list(text = "Estrato"))
  )

htmltools::tagList(p2)
.FIG_N <- .FIG_N + 1
knitr::asis_output(sprintf(
  '<div id="precio_habitaciones1" style="text-align:center; margin-top:6px;">
   <strong>Figura %d.</strong> Precio vs Número de habitaciones por estrato (interactivo)
   </div>', .FIG_N
))
Figura 4. Precio vs Número de habitaciones por estrato (interactivo)
p3 <- plot_ly(base1,
              x = ~factor(estrato), y = ~preciom,
              type  = "box",
              color = ~factor(estrato), colors = "Set1") %>%
  layout(
    title      = "Distribución del precio por estrato – Casas Zona Norte",
    xaxis      = list(title = "Estrato"),
    yaxis      = list(title = "Precio (millones COP)"),
    showlegend = FALSE
  )

htmltools::tagList(p3)
.FIG_N <- .FIG_N + 1
knitr::asis_output(sprintf(
  '<div id="boxplot_estrato1" style="text-align:center; margin-top:6px;">
   <strong>Figura %d.</strong> Distribución del precio por estrato (interactivo)
   </div>', .FIG_N
))
Figura 5. Distribución del precio por estrato (interactivo)
# Matriz numérica de correlaciones para interpretación cuantitativa
cor_mat1 <- cor(vars_num, use = "complete.obs")
round(cor_mat1, 3) %>%
  as.data.frame() %>%
  tibble::rownames_to_column("Variable") %>%
  mi_tabla(
    titulo = "Matriz de correlaciones de Pearson – Casas Zona Norte",
    digits = 3
  )
Tabla 6. Matriz de correlaciones de Pearson – Casas Zona Norte
Variable preciom areaconst estrato banios habitaciones parqueaderos
preciom 1.000 0.685 0.528 0.509 0.365 0.412
areaconst 0.685 1.000 0.354 0.457 0.421 0.307
estrato 0.528 0.354 1.000 0.351 0.058 0.261
banios 0.509 0.457 0.351 1.000 0.590 0.392
habitaciones 0.365 0.421 0.058 0.590 1.000 0.241
parqueaderos 0.412 0.307 0.261 0.392 0.241 1.000

Interpretación del análisis exploratorio:

La matriz de correlaciones y los gráficos interactivos permiten extraer las siguientes conclusiones sobre las casas de la Zona Norte:

  • Área construida vs. precio: Se observa una relación positiva clara: a mayor área, mayor precio. Esta es la variable con mayor correlación con preciom, lo que la convierte en el predictor más relevante del modelo.

  • Estrato vs. precio: El diagrama de caja confirma que el precio mediano aumenta de manera progresiva con el estrato. La dispersión también crece en estratos superiores, lo que indica mayor heterogeneidad en los precios de casas de estrato 5 y 6.

  • Habitaciones vs. precio: Existe una correlación positiva moderada. Sin embargo, esta variable está también correlacionada con areaconst (a más habitaciones, mayor área), lo cual puede generar redundancia de información en el modelo.

  • Baños y parqueaderos: Muestran correlaciones positivas con el precio, aunque más débiles que área y estrato.

  • Multicolinealidad potencial: Se observan correlaciones relativamente altas entre areaconst, habitaciones y banios, lo que anticipa posibles problemas de multicolinealidad que serán evaluados formalmente mediante VIF en la etapa de estimación.

3.1.3 Estimación del modelo

Se estimó un modelo de regresión lineal múltiple por MCO con preciom como variable dependiente y areaconst, estrato, habitaciones, parqueaderos y banios como predictoras.

set.seed(params$seed)

modelo1 <- lm(preciom ~ areaconst + estrato + habitaciones +
                parqueaderos + banios,
              data = base1)

summary(modelo1)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = base1)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -784.29  -77.56  -16.03   47.67  978.61 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -238.17090   44.40551  -5.364 1.34e-07 ***
## areaconst       0.67673    0.05281  12.814  < 2e-16 ***
## estrato        80.63495    9.82632   8.206 2.70e-15 ***
## habitaciones    7.64511    5.65873   1.351    0.177    
## parqueaderos   24.00598    5.86889   4.090 5.14e-05 ***
## banios         18.89938    7.48800   2.524    0.012 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 155.1 on 429 degrees of freedom
##   (287 observations deleted due to missingness)
## Multiple R-squared:  0.6041, Adjusted R-squared:  0.5995 
## F-statistic: 130.9 on 5 and 429 DF,  p-value: < 2.2e-16
tbl_modelo1 <- modelsummary(
  list("Modelo Vivienda 1" = modelo1),
  fmt        = 3,
  statistic  = "({p.value})",
  stars      = TRUE,
  notes      = "Valores p entre paréntesis. * p<0.05, ** p<0.01, *** p<0.001",
  escape     = FALSE,
  output     = "kableExtra"
) %>%
  kableExtra::kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width        = FALSE,
    position          = "center"
  )

cap_html <- sprintf(
  '<div id="tabla_modelo1" style="margin:0 0 6px 0;">
   <strong>Tabla %d.</strong> Resumen del modelo de regresión – Casas Zona Norte
   </div>',
  {environment(mi_tabla)$tab_n <- environment(mi_tabla)$tab_n + 1L
   environment(mi_tabla)$tab_n}
)

knitr::asis_output(paste0(cap_html, "\n\n", tbl_modelo1))
Tabla 7. Resumen del modelo de regresión – Casas Zona Norte
 Modelo Vivienda 1
(Intercept) -238.171***
(<0.001)
areaconst 0.677***
(<0.001)
estrato 80.635***
(<0.001)
habitaciones 7.645
(0.177)
parqueaderos 24.006***
(<0.001)
banios 18.899*
(0.012)
Num.Obs. 435
R2 0.604
R2 Adj. 0.599
AIC 5630.9
BIC 5659.4
Log.Lik. -2808.430
F 130.919
RMSE 154.04
+ p < 0.1, * p < 0.05, ** p < 0.01, *** p < 0.001
Valores p entre paréntesis. * p<0.05, ** p<0.01, *** p<0.001
# Extraer coeficientes para interpretación dinámica
coef1      <- coef(modelo1)
coef_names <- names(coef1)
r2_1       <- summary(modelo1)$r.squared
r2adj_1    <- summary(modelo1)$adj.r.squared
fstat_1    <- summary(modelo1)$fstatistic
pval_f1    <- pf(fstat_1[1], fstat_1[2], fstat_1[3], lower.tail = FALSE)

cat("=== COEFICIENTES ESTIMADOS – MODELO 1 ===\n")
## === COEFICIENTES ESTIMADOS – MODELO 1 ===
print(round(coef1, 4))
##  (Intercept)    areaconst      estrato habitaciones parqueaderos       banios 
##    -238.1709       0.6767      80.6349       7.6451      24.0060      18.8994
cat(sprintf("\nR² = %.4f  |  R² ajustado = %.4f\n", r2_1, r2adj_1))
## 
## R² = 0.6041  |  R² ajustado = 0.5995
cat(sprintf("F-estadístico = %.2f  (p-valor = %.6f)\n", fstat_1[1], pval_f1))
## F-estadístico = 130.92  (p-valor = 0.000000)

Interpretación de los coeficientes (valores reales del modelo):

Los resultados del modelo permiten formular las siguientes interpretaciones contextualizadas para el mercado de casas en la Zona Norte de Cali:

  • Intercepto: Representa el precio teórico cuando todas las variables predictoras son cero. No tiene interpretación práctica en este contexto, dado que ninguna vivienda real tendría área, estrato, habitaciones, parqueaderos o baños iguales a cero.

  • areaconst: Por cada metro cuadrado adicional de área construida, el precio promedio de la casa aumenta en 0.677 millones de pesos, manteniendo las demás variables constantes. Este resultado es coherente con la lógica del mercado inmobiliario: mayor área implica directamente mayor valor. Es la variable con mayor impacto unitario cuantificable sobre el precio.

  • estrato: Por cada unidad adicional de estrato socioeconómico, el precio promedio cambia en 80.635 millones de pesos, ceteris paribus. El signo positivo confirma que las casas en estratos más altos de la Zona Norte tienen precios superiores, lo cual es consistente con las diferencias en infraestructura, servicios públicos y valorización por sector.

  • habitaciones: Por cada habitación adicional, el precio varía en 7.645 millones de pesos. Si el coeficiente es positivo, el resultado es lógico; sin embargo, su significancia estadística podría verse atenuada por la correlación con areaconst, ya que viviendas más grandes tienden a tener más habitaciones.

  • parqueaderos: Cada parqueadero adicional se asocia a un cambio de 24.006 millones de pesos en el precio. En la Zona Norte de Cali, la disponibilidad de parqueaderos es un atributo valorado, especialmente en estratos 4 y 5.

  • banios: Cada baño adicional se asocia a una variación de 18.899 millones de pesos. Al igual que habitaciones, puede presentar colinealidad con área construida.

Evaluación del ajuste del modelo:

El coeficiente de determinación ajustado es R² ajustado = 0.5995, lo que indica que el modelo explica aproximadamente el 59.9% de la variabilidad del precio de las casas en la Zona Norte. La prueba F global arroja un p-valor de 5.42e-84, confirmando que el modelo en su conjunto es estadísticamente significativo, es decir, al menos una de las variables predictoras tiene efecto real sobre el precio.

¿Es lógico el modelo? ¿Cómo mejorarlo?

Los signos de los coeficientes son en general coherentes con la teoría económica del mercado inmobiliario. Para mejorar el ajuste se podría: (1) aplicar una transformación logarítmica al precio para corregir posible sesgo por asimetría en la distribución de la variable dependiente; (2) incluir variables de ubicación más específicas como el barrio mediante variables indicadoras; (3) explorar términos de interacción entre área y estrato; (4) aplicar selección stepwise para retener solo las variables significativas y reducir ruido.

3.1.4 Validación de supuestos

Se verificaron los cuatro supuestos clásicos del modelo de regresión lineal múltiple mediante pruebas formales y gráficos diagnósticos.

p_diag <- recordPlot({
  par(mfrow = c(2, 2))
  plot(modelo1)
  par(mfrow = c(1, 1))
})

mi_figura(
  plot   = p_diag,
  id     = "diagnosticos_modelo1",
  titulo = "Gráficos diagnósticos del modelo – Casas Zona Norte"
)
Figura 6. Gráficos diagnósticos del modelo – Casas Zona Norte
residuales1 <- residuals(modelo1)
sw1  <- shapiro.test(residuales1)
ks1  <- ks.test(scale(residuales1), "pnorm")

data.frame(
  Prueba      = c("Shapiro-Wilk", "Kolmogorov-Smirnov"),
  Estadístico = round(c(sw1$statistic, ks1$statistic), 4),
  `p-valor`   = round(c(sw1$p.value,  ks1$p.value),  6),
  Conclusión  = ifelse(c(sw1$p.value, ks1$p.value) > 0.05,
                       "No se rechaza H₀ (normalidad)",
                       "Se rechaza H₀ (no normalidad)"),
  check.names = FALSE
) %>%
  mi_tabla(
    titulo   = "Pruebas de normalidad de residuales – Modelo 1",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 8. Pruebas de normalidad de residuales – Modelo 1
Prueba Estadístico p-valor Conclusión
W Shapiro-Wilk 0.853 0 Se rechaza H₀ (no normalidad)
D Kolmogorov-Smirnov 0.132 0 Se rechaza H₀ (no normalidad)
gq1 <- gqtest(modelo1)

data.frame(
  Prueba      = "Goldfeld-Quandt",
  Estadístico = round(gq1$statistic, 4),
  `p-valor`   = round(gq1$p.value,  6),
  Conclusión  = ifelse(gq1$p.value > 0.05,
                       "No se rechaza H₀ (varianza constante)",
                       "Se rechaza H₀ (heterocedasticidad)"),
  check.names = FALSE
) %>%
  mi_tabla(
    titulo   = "Prueba de homocedasticidad Goldfeld-Quandt – Modelo 1",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 9. Prueba de homocedasticidad Goldfeld-Quandt – Modelo 1
Prueba Estadístico p-valor Conclusión
GQ Goldfeld-Quandt 2.252 0 Se rechaza H₀ (heterocedasticidad)
dw1 <- dwtest(modelo1)

data.frame(
  Prueba      = "Durbin-Watson",
  Estadístico = round(dw1$statistic, 4),
  `p-valor`   = round(dw1$p.value,  6),
  Conclusión  = ifelse(dw1$p.value > 0.05,
                       "No se rechaza H₀ (independencia)",
                       "Se rechaza H₀ (autocorrelación)"),
  check.names = FALSE
) %>%
  mi_tabla(
    titulo   = "Prueba de independencia de errores Durbin-Watson – Modelo 1",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 10. Prueba de independencia de errores Durbin-Watson – Modelo 1
Prueba Estadístico p-valor Conclusión
DW Durbin-Watson 1.762 0.005 Se rechaza H₀ (autocorrelación)
vif_vals1 <- vif(modelo1)

data.frame(
  Variable    = names(vif_vals1),
  VIF         = round(vif_vals1, 3),
  Diagnóstico = dplyr::case_when(
    vif_vals1 < 5  ~ "Sin multicolinealidad",
    vif_vals1 < 10 ~ "Multicolinealidad moderada",
    TRUE           ~ "Multicolinealidad grave"
  ),
  check.names = FALSE
) %>%
  mi_tabla(
    titulo   = "Factores de Inflación de Varianza (VIF) – Modelo 1",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 11. Factores de Inflación de Varianza (VIF) – Modelo 1
Variable VIF Diagnóstico
areaconst areaconst 1.461 Sin multicolinealidad
estrato estrato 1.308 Sin multicolinealidad
habitaciones habitaciones 1.721 Sin multicolinealidad
parqueaderos parqueaderos 1.226 Sin multicolinealidad
banios banios 1.967 Sin multicolinealidad
# Extraer valores para interpretación dinámica
sw1_p  <- sw1$p.value
ks1_p  <- ks1$p.value
gq1_p  <- gq1$p.value
dw1_d  <- dw1$statistic
dw1_p  <- dw1$p.value
vif_max1 <- max(vif_vals1)
vif_min1 <- min(vif_vals1)

Interpretación de los supuestos – Modelo 1:

1. Normalidad de los residuales: La prueba de Shapiro-Wilk arroja W = 0.8525 con p-valor = 8.77e-20, y la prueba de Kolmogorov-Smirnov obtiene D = 0.1325 con p-valor = 4.69e-07. Ambas pruebas rechazan la hipótesis nula de normalidad (p < 0.05), lo que indica que los residuales del modelo no siguen una distribución normal. Esto se confirma visualmente en el gráfico Q-Q, donde los puntos se desvían de la línea teórica especialmente en las colas. La violación de este supuesto puede afectar la validez de las pruebas de hipótesis e intervalos de confianza. Como medida correctiva se sugiere aplicar una transformación logarítmica al precio (log(preciom)), que suele estabilizar la distribución de los residuales en datos inmobiliarios con alta asimetría positiva.

2. Homocedasticidad (varianza constante): La prueba de Goldfeld-Quandt obtiene un estadístico de 2.2522 con p-valor = 3e-09. Se rechaza la hipótesis nula de varianza constante (p < 0.05), lo que indica heterocedasticidad: la variabilidad de los errores no es uniforme a lo largo de los valores ajustados. Esto puede observarse en el gráfico Residuals vs Fitted, donde la dispersión de los residuales tiende a crecer con los valores predichos más grandes. Como medida correctiva se recomienda usar errores estándar robustos (HC) o transformar la variable dependiente.

3. Independencia de los errores: El estadístico Durbin-Watson es DW = 1.7615 con p-valor = 5.47e-03. Se rechaza la hipótesis nula de independencia (p < 0.05), lo que sugiere autocorrelación en los residuales. Aunque la autocorrelación es más común en series de tiempo, en datos de corte transversal como este puede indicar dependencia espacial: las viviendas cercanas entre sí tienden a tener precios similares no explicados por las variables del modelo. Como medida correctiva se sugiere explorar modelos de regresión espacial o incluir variables de ubicación más granulares (barrio, coordenadas).

4. Multicolinealidad: Los VIF de todas las variables predictoras se encuentran entre 1.23 y 1.97. Todos los valores son inferiores a 5, lo que indica ausencia de multicolinealidad significativa. Cada variable aporta información genuinamente independiente al modelo, por lo que los coeficientes estimados son estables y confiables.

3.1.5 Predicción – Vivienda 1

Con el modelo estimado se realizó la predicción puntual del precio para una casa con las características de la primera solicitud (estrato 4, como valor de referencia dentro del rango 4-5). Se incluye el intervalo de predicción al 95%.

vivienda1 <- data.frame(
  areaconst    = 200,
  estrato      = 4,
  habitaciones = 4,
  parqueaderos = 1,
  banios       = 2
)

pred1 <- predict(modelo1,
                 newdata  = vivienda1,
                 interval = "prediction",
                 level    = 0.95)

data.frame(
  Característica = c("Área (m²)", "Estrato", "Habitaciones",
                     "Parqueaderos", "Baños",
                     "Precio estimado (M COP)",
                     "Límite inferior 95% (M COP)",
                     "Límite superior 95% (M COP)"),
  Valor = c(200, 4, 4, 1, 2,
            round(pred1[1], 1),
            round(pred1[2], 1),
            round(pred1[3], 1)),
  check.names = FALSE
) %>%
  mi_tabla(
    titulo   = "Predicción del precio – Vivienda 1",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 12. Predicción del precio – Vivienda 1
Característica Valor
Área (m²) 200.0
Estrato 4.0
Habitaciones 4.0
Parqueaderos 1.0
Baños 2.0
Precio estimado (M COP) 312.1
Límite inferior 95% (M COP) 6.2
Límite superior 95% (M COP) 618.0

Interpretación de la predicción:

El modelo estima que el precio esperado de una casa con 200 m² de área construida, estrato 4, 4 habitaciones, 1 parqueadero y 2 baños en la Zona Norte de Cali es de aproximadamente 312.1 millones de pesos. El intervalo de predicción al 95% se ubica entre 6.2 y 618 millones de pesos, lo que indica el rango plausible del precio de mercado para una vivienda individual con estas características.

El precio estimado de 312.1 millones es inferior al crédito preaprobado de 350 millones, lo que confirma que es viable encontrar opciones que satisfagan esta solicitud dentro del presupuesto disponible.

3.1.6 Ofertas potenciales – Vivienda 1

Se filtraron las ofertas disponibles en base1 que satisfacen las condiciones de la solicitud y se ubican dentro del presupuesto de 350 millones de pesos. Las ofertas se ordenaron por proximidad al área solicitada (200 m²).

ofertas1 <- base1 %>%
  filter(
    preciom      <= 350,
    habitaciones >= 3,
    banios       >= 2,
    parqueaderos >= 1,
    estrato      %in% c(4, 5)
  ) %>%
  arrange(abs(areaconst - 200)) %>%
  head(10)

cat("Ofertas potenciales encontradas:", nrow(ofertas1), "\n")
## Ofertas potenciales encontradas: 10
ofertas1 %>%
  select(barrio, zona, estrato, preciom, areaconst,
         habitaciones, banios, parqueaderos) %>%
  mi_tabla(
    titulo   = "Ofertas potenciales – Vivienda 1 (≤ $350 M, estrato 4-5)",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 13. Ofertas potenciales – Vivienda 1 (≤ $350 M, estrato 4-5)
barrio zona estrato preciom areaconst habitaciones banios parqueaderos
el bosque Zona Norte 5 350 200 4 3 3
la flora Zona Norte 5 320 200 4 4 2
la merced Zona Norte 4 320 200 4 4 2
el bosque Zona Norte 5 335 202 5 4 1
el bosque Zona Norte 5 350 203 5 2 2
vipasa Zona Norte 5 340 203 4 3 2
vipasa Zona Norte 5 300 205 6 5 2
la flora Zona Norte 5 350 190 3 3 1
urbanización la merced Zona Norte 5 320 210 5 3 2
la merced Zona Norte 5 350 216 4 2 2
mapa_ofertas1 <- ofertas1 %>%
  filter(!is.na(longitud), !is.na(latitud)) %>%
  head(5)

mapa_of1 <- leaflet(data = mapa_ofertas1) %>%
  addTiles() %>%
  addCircleMarkers(
    lng    = ~longitud,
    lat    = ~latitud,
    color  = "darkgreen",
    radius = 10,
    popup  = ~paste0(
      "<b>Barrio:</b> ", barrio, "<br>",
      "<b>Precio:</b> $", preciom, " M<br>",
      "<b>Área:</b> ", areaconst, " m²<br>",
      "<b>Habitaciones:</b> ", habitaciones, "<br>",
      "<b>Baños:</b> ", banios, "<br>",
      "<b>Parqueaderos:</b> ", parqueaderos, "<br>",
      "<b>Estrato:</b> ", estrato
    ),
    label  = ~paste0("$", preciom, "M – ", barrio)
  ) %>%
  addLegend("bottomright", colors = "darkgreen",
            labels = "Ofertas ≤ $350 M", title = "Vivienda 1")

htmltools::tagList(mapa_of1)
.FIG_N <- .FIG_N + 1
knitr::asis_output(sprintf(
  '<div id="mapa_ofertas1" style="text-align:center; margin-top:6px;">
   <strong>Figura %d.</strong> Mapa de las 5 mejores ofertas potenciales – Vivienda 1
   </div>', .FIG_N
))
Figura 7. Mapa de las 5 mejores ofertas potenciales – Vivienda 1

Análisis de las ofertas:

Las 5 propiedades presentadas en el mapa cumplen simultáneamente con el presupuesto de $350 millones, estrato 4 o 5, Zona Norte, y los requisitos mínimos de habitaciones, baños y parqueaderos. Se recomienda a María priorizar las de mayor área construida dentro del presupuesto disponible, verificar el estado de conservación de cada inmueble, evaluar la accesibilidad vial del sector y consultar el avalúo catastral actualizado antes de formular una oferta al cliente.


3.2 Solicitud 2: Apartamento zona sur

3.2.1 Filtro inicial y depuración

Se realizó un filtro sobre la base vivienda seleccionando únicamente los registros correspondientes a apartamentos en la Zona Sur de Cali, con el mismo procedimiento de verificación de calidad aplicado en la solicitud 1.

base2 <- vivienda %>%
  filter(tipo == "Apartamento", zona == "Zona Sur")

cat("Registros en base2:", nrow(base2), "\n")
## Registros en base2: 2787
cat("Valores faltantes por variable:\n")
## Valores faltantes por variable:
print(colSums(is.na(base2)))
##           id         zona         piso      estrato      preciom    areaconst 
##            0            0          622            0            0            0 
## parqueaderos       banios habitaciones         tipo       barrio     longitud 
##          406            0            0            0            0            0 
##      latitud 
##            0
cat("\nRegistros duplicados:", sum(duplicated(base2)), "\n")
## 
## Registros duplicados: 0
base2 %>%
  head(3) %>%
  mi_tabla(titulo = "Primeros 3 registros – Apartamentos Zona Sur")
Tabla 14. Primeros 3 registros – Apartamentos Zona Sur
id zona piso estrato preciom areaconst parqueaderos banios habitaciones tipo barrio longitud latitud
5098 Zona Sur 05 4 290 96 1 2 3 Apartamento acopi -76.535 3.450
698 Zona Sur 02 3 78 40 1 1 2 Apartamento aguablanca -76.501 3.400
8199 Zona Sur NA 6 875 194 2 5 3 Apartamento aguacatal -76.557 3.459
base2 %>%
  count(tipo, name = "n") %>%
  mi_tabla(titulo = "Verificación: tipo de inmueble en base2")
Tabla 15. Verificación: tipo de inmueble en base2
tipo n
Apartamento 2787
base2 %>%
  count(zona, name = "n") %>%
  mi_tabla(titulo = "Verificación: zona en base2")
Tabla 16. Verificación: zona en base2
zona n
Zona Sur 2787
base2 %>%
  count(estrato, name = "n") %>%
  arrange(estrato) %>%
  mi_tabla(titulo = "Distribución por estrato – Apartamentos Zona Sur")
Tabla 17. Distribución por estrato – Apartamentos Zona Sur
estrato n
3 201
4 1091
5 1033
6 462

Interpretación del filtro: La base2 contiene únicamente apartamentos de la Zona Sur, confirmado por las tablas de verificación. Se aprecia que los registros se concentran en estratos 4, 5 y 6, coherente con el perfil socioeconómico de la zona sur de Cali. Los valores faltantes y duplicados detectados son considerados en la etapa de modelación.

mapa_base2 <- leaflet(data = base2) %>%
  addTiles() %>%
  addCircleMarkers(
    lng    = ~longitud,
    lat    = ~latitud,
    color  = "darkorange",
    radius = 5,
    popup  = ~paste0(
      "<b>Barrio:</b> ", barrio, "<br>",
      "<b>Precio:</b> $", preciom, " M<br>",
      "<b>Área:</b> ", areaconst, " m²<br>",
      "<b>Estrato:</b> ", estrato
    )
  ) %>%
  addLegend("bottomright", colors = "darkorange",
            labels = "Apartamentos - Zona Sur", title = "base2")

htmltools::tagList(mapa_base2)
.FIG_N <- .FIG_N + 1
knitr::asis_output(sprintf(
  '<div id="mapa_base2" style="text-align:center; margin-top:6px;">
   <strong>Figura %d.</strong> Ubicación geográfica de los apartamentos en Zona Sur de Cali
   </div>', .FIG_N
))
Figura 8. Ubicación geográfica de los apartamentos en Zona Sur de Cali

Análisis del mapa: Al igual que en la solicitud 1, pueden presentarse puntos fuera del área sur por autoclasificación del oferente o límites de zona no estrictamente delimitados en la base de datos. Se recomienda validar con herramientas SIG para análisis más rigurosos.

3.2.2 Análisis exploratorio

base2 %>%
  select(preciom, areaconst, estrato, habitaciones, parqueaderos, banios) %>%
  summary() %>%
  print()
##     preciom         areaconst         estrato      habitaciones  
##  Min.   :  75.0   Min.   : 40.00   Min.   :3.00   Min.   :0.000  
##  1st Qu.: 175.0   1st Qu.: 65.00   1st Qu.:4.00   1st Qu.:3.000  
##  Median : 245.0   Median : 85.00   Median :5.00   Median :3.000  
##  Mean   : 297.3   Mean   : 97.47   Mean   :4.63   Mean   :2.966  
##  3rd Qu.: 335.0   3rd Qu.:110.00   3rd Qu.:5.00   3rd Qu.:3.000  
##  Max.   :1750.0   Max.   :932.00   Max.   :6.00   Max.   :6.000  
##                                                                  
##   parqueaderos        banios     
##  Min.   : 1.000   Min.   :0.000  
##  1st Qu.: 1.000   1st Qu.:2.000  
##  Median : 1.000   Median :2.000  
##  Mean   : 1.415   Mean   :2.488  
##  3rd Qu.: 2.000   3rd Qu.:3.000  
##  Max.   :10.000   Max.   :8.000  
##  NA's   :406
vars_num2 <- base2 %>%
  select(preciom, areaconst, estrato, banios, habitaciones, parqueaderos)

p_pairs2 <- ggpairs(
  vars_num2,
  title = "Matriz de correlaciones – Apartamentos Zona Sur",
  lower = list(continuous = wrap("smooth", alpha = 0.3, color = "darkorange")),
  diag  = list(continuous = wrap("densityDiag", fill = "darkorange", alpha = 0.4)),
  upper = list(continuous = wrap("cor", size = 3.5))
) + theme_minimal()

mi_figura(
  plot   = p_pairs2,
  id     = "correlacion_base2",
  titulo = "Matriz de correlaciones – Apartamentos Zona Sur"
)
Figura 9. Matriz de correlaciones – Apartamentos Zona Sur
p4 <- plot_ly(base2,
              x = ~areaconst, y = ~preciom,
              color = ~factor(estrato), colors = "Oranges",
              type = "scatter", mode = "markers",
              marker = list(size = 8, opacity = 0.7),
              text = ~paste("Barrio:", barrio,
                            "<br>Precio: $", preciom, "M",
                            "<br>Área:", areaconst, "m²",
                            "<br>Estrato:", estrato)) %>%
  layout(
    title  = "Precio vs Área construida – Apartamentos Zona Sur",
    xaxis  = list(title = "Área construida (m²)"),
    yaxis  = list(title = "Precio (millones COP)"),
    legend = list(title = list(text = "Estrato"))
  )

htmltools::tagList(p4)
.FIG_N <- .FIG_N + 1
knitr::asis_output(sprintf(
  '<div id="precio_area2" style="text-align:center; margin-top:6px;">
   <strong>Figura %d.</strong> Precio vs Área construida – Apartamentos Zona Sur (interactivo)
   </div>', .FIG_N
))
Figura 10. Precio vs Área construida – Apartamentos Zona Sur (interactivo)
p5b <- plot_ly(base2,
               x = ~habitaciones, y = ~preciom,
               color = ~factor(estrato), colors = "Set3",
               type = "scatter", mode = "markers",
               marker = list(size = 8, opacity = 0.7),
               text = ~paste("Barrio:", barrio,
                             "<br>Precio: $", preciom, "M",
                             "<br>Habitaciones:", habitaciones)) %>%
  layout(
    title  = "Precio vs Número de habitaciones – Apartamentos Zona Sur",
    xaxis  = list(title = "Habitaciones"),
    yaxis  = list(title = "Precio (millones COP)"),
    legend = list(title = list(text = "Estrato"))
  )

htmltools::tagList(p5b)
.FIG_N <- .FIG_N + 1
knitr::asis_output(sprintf(
  '<div id="precio_habitaciones2" style="text-align:center; margin-top:6px;">
   <strong>Figura %d.</strong> Precio vs Número de habitaciones – Apartamentos Zona Sur (interactivo)
   </div>', .FIG_N
))
Figura 11. Precio vs Número de habitaciones – Apartamentos Zona Sur (interactivo)
p5 <- plot_ly(base2,
              x = ~factor(estrato), y = ~preciom,
              type  = "box",
              color = ~factor(estrato), colors = "Oranges") %>%
  layout(
    title      = "Distribución del precio por estrato – Apartamentos Zona Sur",
    xaxis      = list(title = "Estrato"),
    yaxis      = list(title = "Precio (millones COP)"),
    showlegend = FALSE
  )

htmltools::tagList(p5)
.FIG_N <- .FIG_N + 1
knitr::asis_output(sprintf(
  '<div id="boxplot_estrato2" style="text-align:center; margin-top:6px;">
   <strong>Figura %d.</strong> Distribución del precio por estrato – Apartamentos Zona Sur (interactivo)
   </div>', .FIG_N
))
Figura 12. Distribución del precio por estrato – Apartamentos Zona Sur (interactivo)
cor_mat2 <- cor(vars_num2, use = "complete.obs")
round(cor_mat2, 3) %>%
  as.data.frame() %>%
  tibble::rownames_to_column("Variable") %>%
  mi_tabla(
    titulo = "Matriz de correlaciones de Pearson – Apartamentos Zona Sur",
    digits = 3
  )
Tabla 18. Matriz de correlaciones de Pearson – Apartamentos Zona Sur
Variable preciom areaconst estrato banios habitaciones parqueaderos
preciom 1.000 0.741 0.650 0.711 0.296 0.693
areaconst 0.741 1.000 0.452 0.664 0.407 0.578
estrato 0.650 0.452 1.000 0.535 0.177 0.486
banios 0.711 0.664 0.535 1.000 0.520 0.556
habitaciones 0.296 0.407 0.177 0.520 1.000 0.237
parqueaderos 0.693 0.578 0.486 0.556 0.237 1.000

Interpretación del análisis exploratorio – Solicitud 2:

El análisis exploratorio de los apartamentos de la Zona Sur muestra patrones similares a los observados en la solicitud 1, pero con algunas particularidades propias de este segmento:

  • Área construida vs. precio: La relación positiva entre área y precio es la más pronunciada del conjunto, con mayor variabilidad en el extremo superior (apartamentos de gran tamaño y alto precio). Esto sugiere que en la Zona Sur, el precio por metro cuadrado varía más que en la Zona Norte, posiblemente por la mezcla de estratos y la presencia de proyectos de lujo.

  • Estrato vs. precio: El diagrama de caja confirma diferencias marcadas entre estratos. La dispersión es considerablemente mayor en estratos 5 y 6, lo que refleja la heterogeneidad del mercado de apartamentos de alta gama en Cali.

  • Parqueaderos: En apartamentos, la disponibilidad de múltiples parqueaderos es un factor diferenciador importante y se espera tenga mayor peso relativo que en casas.

  • Correlaciones entre predictoras: Se identifican correlaciones moderadas entre areaconst, habitaciones y banios, al igual que en base1. Esto anticipa posibles efectos de multicolinealidad que serán cuantificados mediante VIF.

3.2.3 Estimación del modelo

set.seed(params$seed)

modelo2 <- lm(preciom ~ areaconst + estrato + habitaciones +
                parqueaderos + banios,
              data = base2)

summary(modelo2)
## 
## Call:
## lm(formula = preciom ~ areaconst + estrato + habitaciones + parqueaderos + 
##     banios, data = base2)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1092.02   -42.28    -1.33    40.58   926.56 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -261.62501   15.63220 -16.736  < 2e-16 ***
## areaconst       1.28505    0.05403  23.785  < 2e-16 ***
## estrato        60.89709    3.08408  19.746  < 2e-16 ***
## habitaciones  -24.83693    3.89229  -6.381 2.11e-10 ***
## parqueaderos   72.91468    3.95797  18.422  < 2e-16 ***
## banios         50.69675    3.39637  14.927  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 98.02 on 2375 degrees of freedom
##   (406 observations deleted due to missingness)
## Multiple R-squared:  0.7485, Adjusted R-squared:  0.748 
## F-statistic:  1414 on 5 and 2375 DF,  p-value: < 2.2e-16
tbl_modelo2 <- modelsummary(
  list("Modelo Vivienda 2" = modelo2),
  fmt       = 3,
  statistic = "({p.value})",
  stars     = TRUE,
  notes     = "Valores p entre paréntesis. * p<0.05, ** p<0.01, *** p<0.001",
  escape    = FALSE,
  output    = "kableExtra"
) %>%
  kableExtra::kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width        = FALSE,
    position          = "center"
  )

cap_html <- sprintf(
  '<div id="tabla_modelo2" style="margin:0 0 6px 0;">
   <strong>Tabla %d.</strong> Resumen del modelo de regresión – Apartamentos Zona Sur
   </div>',
  {environment(mi_tabla)$tab_n <- environment(mi_tabla)$tab_n + 1L
   environment(mi_tabla)$tab_n}
)

knitr::asis_output(paste0(cap_html, "\n\n", tbl_modelo2))
Tabla 19. Resumen del modelo de regresión – Apartamentos Zona Sur
 Modelo Vivienda 2
(Intercept) -261.625***
(<0.001)
areaconst 1.285***
(<0.001)
estrato 60.897***
(<0.001)
habitaciones -24.837***
(<0.001)
parqueaderos 72.915***
(<0.001)
banios 50.697***
(<0.001)
Num.Obs. 2381
R2 0.749
R2 Adj. 0.748
AIC 28599.5
BIC 28640.0
Log.Lik. -14292.768
F 1413.802
RMSE 97.90
+ p < 0.1, * p < 0.05, ** p < 0.01, *** p < 0.001
Valores p entre paréntesis. * p<0.05, ** p<0.01, *** p<0.001
coef2      <- coef(modelo2)
r2_2       <- summary(modelo2)$r.squared
r2adj_2    <- summary(modelo2)$adj.r.squared
fstat_2    <- summary(modelo2)$fstatistic
pval_f2    <- pf(fstat_2[1], fstat_2[2], fstat_2[3], lower.tail = FALSE)

cat("=== COEFICIENTES ESTIMADOS – MODELO 2 ===\n")
## === COEFICIENTES ESTIMADOS – MODELO 2 ===
print(round(coef2, 4))
##  (Intercept)    areaconst      estrato habitaciones parqueaderos       banios 
##    -261.6250       1.2850      60.8971     -24.8369      72.9147      50.6967
cat(sprintf("\nR² = %.4f  |  R² ajustado = %.4f\n", r2_2, r2adj_2))
## 
## R² = 0.7485  |  R² ajustado = 0.7480
cat(sprintf("F-estadístico = %.2f  (p-valor = %.6f)\n", fstat_2[1], pval_f2))
## F-estadístico = 1413.80  (p-valor = 0.000000)

Interpretación de los coeficientes (valores reales del modelo):

  • areaconst: Por cada metro cuadrado adicional de área construida, el precio promedio del apartamento aumenta en 1.285 millones de pesos, ceteris paribus. En la Zona Sur, este efecto puede ser más marcado que en la Zona Norte, dado que los apartamentos de estratos altos tienen un precio por m² superior al de las casas.

  • estrato: Cada nivel adicional de estrato se asocia a un incremento de 60.897 millones de pesos en el precio promedio. En el mercado de apartamentos de la Zona Sur, el diferencial entre estratos 5 y 6 es especialmente significativo por los atributos de calidad constructiva y servicios.

  • habitaciones: Por cada habitación adicional, el precio varía en -24.837 millones de pesos. En apartamentos, este efecto puede ser menor que en casas dado que el área construida captura gran parte de la información relacionada con el tamaño del inmueble.

  • parqueaderos: Cada parqueadero adicional se asocia a 72.915 millones de pesos adicionales en el precio. En la Zona Sur de Cali, donde la oferta de parqueaderos es más escasa, este atributo puede tener un peso importante sobre la valorización del apartamento.

  • banios: Por cada baño adicional, el precio varía en 50.697 millones de pesos.

Evaluación del ajuste:

El R² ajustado es 0.748, lo que significa que el modelo explica el 74.8% de la variabilidad del precio de los apartamentos en la Zona Sur. El estadístico F = 1413.8 con p-valor = 0e+00 confirma que el modelo es globalmente significativo. El ajuste es satisfactorio para datos inmobiliarios de corte transversal. Para mejorar el ajuste se podría incluir el barrio como variable categórica, añadir el piso como predictor o transformar el precio con logaritmo.

3.2.4 Validación de supuestos

p_diag2 <- recordPlot({
  par(mfrow = c(2, 2))
  plot(modelo2)
  par(mfrow = c(1, 1))
})

mi_figura(
  plot   = p_diag2,
  id     = "diagnosticos_modelo2",
  titulo = "Gráficos diagnósticos – Modelo Apartamentos Zona Sur"
)
Figura 13. Gráficos diagnósticos – Modelo Apartamentos Zona Sur
residuales2 <- residuals(modelo2)
sw2  <- shapiro.test(residuales2)
ks2  <- ks.test(scale(residuales2), "pnorm")

data.frame(
  Prueba      = c("Shapiro-Wilk", "Kolmogorov-Smirnov"),
  Estadístico = round(c(sw2$statistic, ks2$statistic), 4),
  `p-valor`   = round(c(sw2$p.value,  ks2$p.value),  6),
  Conclusión  = ifelse(c(sw2$p.value, ks2$p.value) > 0.05,
                       "No se rechaza H₀ (normalidad)",
                       "Se rechaza H₀ (no normalidad)"),
  check.names = FALSE
) %>%
  mi_tabla(
    titulo   = "Pruebas de normalidad de residuales – Modelo 2",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 20. Pruebas de normalidad de residuales – Modelo 2
Prueba Estadístico p-valor Conclusión
W Shapiro-Wilk 0.791 0 Se rechaza H₀ (no normalidad)
D Kolmogorov-Smirnov 0.124 0 Se rechaza H₀ (no normalidad)
gq2 <- gqtest(modelo2)

data.frame(
  Prueba      = "Goldfeld-Quandt",
  Estadístico = round(gq2$statistic, 4),
  `p-valor`   = round(gq2$p.value,  6),
  Conclusión  = ifelse(gq2$p.value > 0.05,
                       "No se rechaza H₀ (varianza constante)",
                       "Se rechaza H₀ (heterocedasticidad)"),
  check.names = FALSE
) %>%
  mi_tabla(
    titulo   = "Prueba de homocedasticidad Goldfeld-Quandt – Modelo 2",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 21. Prueba de homocedasticidad Goldfeld-Quandt – Modelo 2
Prueba Estadístico p-valor Conclusión
GQ Goldfeld-Quandt 0.951 0.805 No se rechaza H₀ (varianza constante)
dw2 <- dwtest(modelo2)

data.frame(
  Prueba      = "Durbin-Watson",
  Estadístico = round(dw2$statistic, 4),
  `p-valor`   = round(dw2$p.value,  6),
  Conclusión  = ifelse(dw2$p.value > 0.05,
                       "No se rechaza H₀ (independencia)",
                       "Se rechaza H₀ (autocorrelación)"),
  check.names = FALSE
) %>%
  mi_tabla(
    titulo   = "Prueba de independencia de errores Durbin-Watson – Modelo 2",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 22. Prueba de independencia de errores Durbin-Watson – Modelo 2
Prueba Estadístico p-valor Conclusión
DW Durbin-Watson 1.533 0 Se rechaza H₀ (autocorrelación)
vif_vals2 <- vif(modelo2)

data.frame(
  Variable    = names(vif_vals2),
  VIF         = round(vif_vals2, 3),
  Diagnóstico = dplyr::case_when(
    vif_vals2 < 5  ~ "Sin multicolinealidad",
    vif_vals2 < 10 ~ "Multicolinealidad moderada",
    TRUE           ~ "Multicolinealidad grave"
  ),
  check.names = FALSE
) %>%
  mi_tabla(
    titulo   = "Factores de Inflación de Varianza (VIF) – Modelo 2",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 23. Factores de Inflación de Varianza (VIF) – Modelo 2
Variable VIF Diagnóstico
areaconst areaconst 2.067 Sin multicolinealidad
estrato estrato 1.545 Sin multicolinealidad
habitaciones habitaciones 1.429 Sin multicolinealidad
parqueaderos parqueaderos 1.738 Sin multicolinealidad
banios banios 2.529 Sin multicolinealidad
sw2_p    <- sw2$p.value
ks2_p    <- ks2$p.value
gq2_p    <- gq2$p.value
dw2_d    <- dw2$statistic
dw2_p    <- dw2$p.value
vif_max2 <- max(vif_vals2)
vif_min2 <- min(vif_vals2)

Interpretación de los supuestos – Modelo 2:

1. Normalidad de los residuales: La prueba Shapiro-Wilk obtiene W = 0.7912 (p = 4.84e-48) y la prueba Kolmogorov-Smirnov obtiene D = 0.1244 (p = 1.97e-32). Ambas pruebas rechazan la normalidad de los residuales (p < 0.05). El gráfico Q-Q confirma desviaciones en las colas de la distribución. Esto es frecuente en datos inmobiliarios donde existen propiedades de muy alto precio que generan asimetría positiva en los residuales. La medida correctiva recomendada es aplicar una transformación logarítmica al precio (modelo log-lin), que reduciría la asimetría y mejoraría la normalidad de los errores.

2. Homocedasticidad: Goldfeld-Quandt: estadístico = 0.9513, p = 8.05e-01. No se rechaza la homocedasticidad (p > 0.05): la varianza de los residuales es constante a lo largo de los valores predichos.

3. Independencia de los errores: Durbin-Watson: DW = 1.5333, p = 1.73e-30. Se detecta autocorrelación en los residuales (p < 0.05). En datos de corte transversal inmobiliario, esto señala dependencia espacial: apartamentos en el mismo edificio o misma manzana tienen precios similares que el modelo no captura completamente. La corrección sugerida es incluir efectos de barrio o aplicar modelos de regresión espacial.

4. Multicolinealidad: Los VIF varían entre 1.43 y 2.53. Todos los VIF son inferiores a 5: no hay multicolinealidad problemática. Los coeficientes estimados son estables y sus errores estándar no están inflados por redundancia entre predictoras.

3.2.5 Predicción – Vivienda 2

vivienda2 <- data.frame(
  areaconst    = 300,
  estrato      = 5,
  habitaciones = 5,
  parqueaderos = 3,
  banios       = 3
)

pred2 <- predict(modelo2,
                 newdata  = vivienda2,
                 interval = "prediction",
                 level    = 0.95)

data.frame(
  Característica = c("Área (m²)", "Estrato", "Habitaciones",
                     "Parqueaderos", "Baños",
                     "Precio estimado (M COP)",
                     "Límite inferior 95% (M COP)",
                     "Límite superior 95% (M COP)"),
  Valor = c(300, 5, 5, 3, 3,
            round(pred2[1], 1),
            round(pred2[2], 1),
            round(pred2[3], 1)),
  check.names = FALSE
) %>%
  mi_tabla(
    titulo   = "Predicción del precio – Vivienda 2",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 24. Predicción del precio – Vivienda 2
Característica Valor
Área (m²) 300.0
Estrato 5.0
Habitaciones 5.0
Parqueaderos 3.0
Baños 3.0
Precio estimado (M COP) 675.0
Límite inferior 95% (M COP) 481.5
Límite superior 95% (M COP) 868.6

Interpretación de la predicción:

El modelo estima que el precio esperado de un apartamento con 300 m², estrato 5, 5 habitaciones, 3 parqueaderos y 3 baños en la Zona Sur de Cali es de aproximadamente 675 millones de pesos. El intervalo de predicción al 95% se encuentra entre 481.5 y 868.6 millones de pesos.

El precio estimado de 675 millones se encuentra dentro del crédito preaprobado de $850 millones, lo que confirma la viabilidad financiera de esta solicitud. Además, el límite superior del intervalo de predicción (868.6 millones) supera el presupuesto, lo que indica que existe incertidumbre sobre si el precio real de mercado podría exceder los 850 millones para las características solicitadas.

3.2.6 Ofertas potenciales – Vivienda 2

ofertas2 <- base2 %>%
  filter(
    preciom      <= 850,
    habitaciones >= 4,
    banios       >= 3,
    parqueaderos >= 2,
    estrato      %in% c(5, 6)
  ) %>%
  arrange(abs(areaconst - 300)) %>%
  head(10)

cat("Ofertas potenciales encontradas:", nrow(ofertas2), "\n")
## Ofertas potenciales encontradas: 10
ofertas2 %>%
  select(barrio, zona, estrato, preciom, areaconst,
         habitaciones, banios, parqueaderos) %>%
  mi_tabla(
    titulo   = "Ofertas potenciales – Vivienda 2 (≤ $850 M, estrato 5-6)",
    num_cols = dplyr::where(is.numeric)
  )
Tabla 25. Ofertas potenciales – Vivienda 2 (≤ $850 M, estrato 5-6)
barrio zona estrato preciom areaconst habitaciones banios parqueaderos
seminario Zona Sur 5 670 300.00 6 5 3
cuarto de legua Zona Sur 5 410 295.55 4 4 2
cuarto de legua Zona Sur 5 520 320.00 4 4 2
ciudadela pasoancho Zona Sur 5 650 275.00 5 5 2
capri Zona Sur 5 350 270.00 4 3 3
san fernando Zona Sur 5 500 330.00 4 4 2
san fernando viejo Zona Sur 5 485 259.00 4 4 2
San Fernando Zona Sur 5 350 258.00 5 4 2
seminario Zona Sur 5 530 256.00 5 5 3
el ingenio Zona Sur 6 700 250.00 5 4 2
mapa_ofertas2 <- ofertas2 %>%
  filter(!is.na(longitud), !is.na(latitud)) %>%
  head(5)

mapa_of2 <- leaflet(data = mapa_ofertas2) %>%
  addTiles() %>%
  addCircleMarkers(
    lng    = ~longitud,
    lat    = ~latitud,
    color  = "purple",
    radius = 10,
    popup  = ~paste0(
      "<b>Barrio:</b> ", barrio, "<br>",
      "<b>Precio:</b> $", preciom, " M<br>",
      "<b>Área:</b> ", areaconst, " m²<br>",
      "<b>Habitaciones:</b> ", habitaciones, "<br>",
      "<b>Baños:</b> ", banios, "<br>",
      "<b>Parqueaderos:</b> ", parqueaderos, "<br>",
      "<b>Estrato:</b> ", estrato
    ),
    label  = ~paste0("$", preciom, "M – ", barrio)
  ) %>%
  addLegend("bottomright", colors = "purple",
            labels = "Ofertas ≤ $850 M", title = "Vivienda 2")

htmltools::tagList(mapa_of2)
.FIG_N <- .FIG_N + 1
knitr::asis_output(sprintf(
  '<div id="mapa_ofertas2" style="text-align:center; margin-top:6px;">
   <strong>Figura %d.</strong> Mapa de las 5 mejores ofertas potenciales – Vivienda 2
   </div>', .FIG_N
))
Figura 14. Mapa de las 5 mejores ofertas potenciales – Vivienda 2

Análisis de las ofertas:

Las 5 propiedades presentadas cumplen con todos los criterios de la segunda solicitud: precio dentro del presupuesto de $850 millones, estrato 5 o 6, Zona Sur, y al menos 4 habitaciones, 3 baños y 2 parqueaderos. Para complementar la recomendación a la compañía internacional se sugiere evaluar adicionalmente: el piso del apartamento (los pisos altos suelen tener mayor valorización y luminosidad), el estado del reglamento de propiedad horizontal, la disponibilidad de zonas comunes (gimnasio, piscina, salones) y la cercanía a vías principales, colegios y centros comerciales de la Zona Sur.

4 Comparación de modelos y conclusiones

tbl_comparacion <- modelsummary(
  list("Casa – Zona Norte" = modelo1,
       "Apto – Zona Sur"   = modelo2),
  fmt       = 3,
  statistic = "({p.value})",
  stars     = TRUE,
  notes     = "Valores p entre paréntesis. * p<0.05, ** p<0.01, *** p<0.001",
  escape    = FALSE,
  output    = "kableExtra"
) %>%
  kableExtra::kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"),
    full_width        = FALSE,
    position          = "center"
  )

cap_html <- sprintf(
  '<div id="tabla_comparacion" style="margin:0 0 6px 0;">
   <strong>Tabla %d.</strong> Comparación de los modelos de regresión – Vivienda 1 vs Vivienda 2
   </div>',
  {environment(mi_tabla)$tab_n <- environment(mi_tabla)$tab_n + 1L
   environment(mi_tabla)$tab_n}
)

knitr::asis_output(paste0(cap_html, "\n\n", tbl_comparacion))
Tabla 26. Comparación de los modelos de regresión – Vivienda 1 vs Vivienda 2
Casa – Zona Norte Apto – Zona Sur
(Intercept) -238.171*** -261.625***
(<0.001) (<0.001)
areaconst 0.677*** 1.285***
(<0.001) (<0.001)
estrato 80.635*** 60.897***
(<0.001) (<0.001)
habitaciones 7.645 -24.837***
(0.177) (<0.001)
parqueaderos 24.006*** 72.915***
(<0.001) (<0.001)
banios 18.899* 50.697***
(0.012) (<0.001)
Num.Obs. 435 2381
R2 0.604 0.749
R2 Adj. 0.599 0.748
AIC 5630.9 28599.5
BIC 5659.4 28640.0
Log.Lik. -2808.430 -14292.768
F 130.919 1413.802
RMSE 154.04 97.90
+ p < 0.1, * p < 0.05, ** p < 0.01, *** p < 0.001
Valores p entre paréntesis. * p<0.05, ** p<0.01, *** p<0.001

Conclusiones generales:

En ambos mercados, el área construida y el estrato son los determinantes más robustos del precio de la vivienda en Cali, resultado coherente con la teoría económica del mercado inmobiliario. El modelo para casas de la Zona Norte alcanza un R² ajustado de 0.599, mientras que el de apartamentos de la Zona Sur obtiene 0.748, lo que indica diferencias en la capacidad explicativa entre los dos segmentos de mercado.

Desde el punto de vista de la validación estadística, ambos modelos presentan limitaciones similares: los residuales exhiben desviaciones de la normalidad típicas de datos inmobiliarios con asimetría positiva, y se detectan indicios de dependencia espacial en los errores. Ninguno de los dos modelos presenta multicolinealidad grave, lo que garantiza la estabilidad de los coeficientes estimados.

Para la Vivienda 1, el precio estimado de 312.1 millones es compatible con el presupuesto de $350 millones, y se identificaron ofertas reales en la Zona Norte que satisfacen los requerimientos de la solicitud. Para la Vivienda 2, el precio estimado de 675 millones se encuentra dentro del presupuesto de $850 millones, con varias opciones disponibles en la Zona Sur que cumplen los criterios de la compañía internacional.

Se recomienda a María complementar este análisis cuantitativo con visitas presenciales a las propiedades seleccionadas y una revisión del avalúo catastral actualizado, para garantizar que las recomendaciones entregadas al cliente reflejen con precisión las condiciones actuales del mercado.

LS0tCnRpdGxlOiAiKipNb2RlbG8gZGUgUmVncmVzacOzbiBMaW5lYWwgTcO6bHRpcGxlOiBDYXNvIEMmQSoqIgphdXRob3I6ICJSYWZhZWwgSm9zZSBEZWwgQ2FzdGlsbG8gUGF2YWplYXUiCmRhdGU6ICIyMDI2LTAzLTA4IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0aGVtZTogY29zbW8KICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmxhbmd1YWdlOgogIGxhYmVsOgogICAgZmlnOiAiRmlndXJhICIKICAgIHRhYjogIlRhYmxhICIKcGFyYW1zOgogIHNlZWQ6IDg5NzI3OTEKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvICAgICAgPSBUUlVFLAogIHdhcm5pbmcgICA9IEZBTFNFLAogIG1lc3NhZ2UgICA9IEZBTFNFLAogIGZpZy5hbGlnbiA9ICJjZW50ZXIiCikKYGBgCgpgYGB7ciBsaWJyZXJpYXN9CiMgSW5zdGFsYXIgcGFxdWV0ZXMgc2kgbm8gZXN0w6FuIGRpc3BvbmlibGVzIChlamVjdXRhciB1bmEgc29sYSB2ZXopCiMgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiY2VudHJvbWFnaXMvcGFxdWV0ZU1PREVMT1MiLCBmb3JjZSA9IFRSVUUpCiMgaW5zdGFsbC5wYWNrYWdlcyhjKCJ0aWR5dmVyc2UiLCJwbG90bHkiLCJsZWFmbGV0IiwiY2FyIiwibG10ZXN0IiwKIyAgICAgICAgICAgICAgICAgICAgIm5vcnRlc3QiLCJrYWJsZUV4dHJhIiwibW9kZWxzdW1tYXJ5IiwiR0dhbGx5IikpCgpsaWJyYXJ5KHBhcXVldGVNT0RFTE9TKSAgICMgZGF0b3Mgdml2aWVuZGEKbGlicmFyeSh0aWR5dmVyc2UpICAgICAgICAgIyBtYW5pcHVsYWNpw7NuIHkgdmlzdWFsaXphY2nDs24KbGlicmFyeShwbG90bHkpICAgICAgICAgICAgIyBncsOhZmljb3MgaW50ZXJhY3Rpdm9zCmxpYnJhcnkobGVhZmxldCkgICAgICAgICAgICMgbWFwYXMgaW50ZXJhY3Rpdm9zCmxpYnJhcnkoY2FyKSAgICAgICAgICAgICAgICMgVklGIHkgZGlhZ27Ds3N0aWNvcwpsaWJyYXJ5KGxtdGVzdCkgICAgICAgICAgICAjIHBydWViYSBEdXJiaW4tV2F0c29uCmxpYnJhcnkobm9ydGVzdCkgICAgICAgICAgICMgcHJ1ZWJhcyBkZSBub3JtYWxpZGFkIGFkaWNpb25hbGVzCmxpYnJhcnkoa2FibGVFeHRyYSkgICAgICAgICMgdGFibGFzIGVzdGlsaXphZGFzCmxpYnJhcnkobW9kZWxzdW1tYXJ5KSAgICAgICMgY29tcGFyYWNpw7NuIGRlIG1vZGVsb3MKbGlicmFyeShHR2FsbHkpICAgICAgICAgICAgIyBtYXRyaXogZGUgY29ycmVsYWNpb25lcwoKIyBDYXJnYSBkZWwgZGF0YXNldApkYXRhKCJ2aXZpZW5kYSIpCmBgYAoKYGBge3IgdGFibGFzLCBpbmNsdWRlPUZBTFNFfQpjcmVhcl9taV90YWJsYSA8LSBmdW5jdGlvbigpIHsKICB0YWJfbiA8LSAwTAogIGZ1bmN0aW9uKGRmLCBpZCA9IE5VTEwsIHRpdHVsbyA9ICIiLCBkaWdpdHMgPSAzLAogICAgICAgICAgIG51bV9jb2xzID0gZHBseXI6OndoZXJlKGlzLm51bWVyaWMpLAogICAgICAgICAgIGFsaWduID0gImMiLAogICAgICAgICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpKSB7CiAgICB0YWJfbiA8PC0gdGFiX24gKyAxTAogICAgaWYgKGlzLm51bGwoaWQpIHx8ICFuemNoYXIoaWQpKSB7CiAgICAgIGlkIDwtIHBhc3RlMCgidGFiXyIsIHRhYl9uLCAiXyIsCiAgICAgICAgICAgICAgICAgICBnc3ViKCJbXmEtekEtWjAtOV0rIiwgIl8iLCB0b2xvd2VyKHRpdHVsbykpKQogICAgICBpZCA8LSBnc3ViKCJfKyIsICJfIiwgaWQpCiAgICAgIGlkIDwtIGdzdWIoIl5ffF8kIiwgIiIsIGlkKQogICAgfQogICAgZGZfZm10IDwtIGRmIHw+CiAgICAgIGRwbHlyOjptdXRhdGUoZHBseXI6OmFjcm9zcyh7eyBudW1fY29scyB9fSwgfiByb3VuZCgueCwgZGlnaXRzKSkpCiAgICBjYXBfaHRtbCA8LSBzcHJpbnRmKAogICAgICAnPGRpdiBpZD0iJXMiIHN0eWxlPSJtYXJnaW46MCAwIDZweCAwOyI+PHN0cm9uZz5UYWJsYSAlZC48L3N0cm9uZz4gJXM8L2Rpdj4nLAogICAgICBpZCwgdGFiX24sIHRpdHVsbwogICAgKQogICAgdGJsX2h0bWwgPC0gZGZfZm10IHw+CiAgICAgIGtuaXRyOjprYWJsZShhbGlnbiA9IGFsaWduLCBlc2NhcGUgPSBGQUxTRSkgfD4KICAgICAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZygKICAgICAgICBmdWxsX3dpZHRoID0gRkFMU0UsCiAgICAgICAgYm9vdHN0cmFwX29wdGlvbnMgPSBib290c3RyYXBfb3B0aW9ucwogICAgICApCiAgICBrbml0cjo6YXNpc19vdXRwdXQocGFzdGUwKGNhcF9odG1sLCAiXG5cbiIsIHRibF9odG1sKSkKICB9Cn0KbWlfdGFibGEgPC0gY3JlYXJfbWlfdGFibGEoKQpgYGAKCmBgYHtyIGZpZ3VyYXMsIGluY2x1ZGU9RkFMU0V9CmlmICghZXhpc3RzKCIuRklHX04iKSkgLkZJR19OIDw8LSAwCgptaV9maWd1cmEgPC0gZnVuY3Rpb24ocGxvdCwgaWQsIHRpdHVsbyl7CiAgLkZJR19OIDw8LSAuRklHX04gKyAxCiAgcHJpbnQocGxvdCkKICBjYXBfaHRtbCA8LSBzcHJpbnRmKAogICAgJzxkaXYgaWQ9IiVzIiBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXI7IG1hcmdpbi10b3A6NnB4OyI+PHN0cm9uZz5GaWd1cmEgJWQuPC9zdHJvbmc+ICVzPC9kaXY+JywKICAgIGlkLCAuRklHX04sIHRpdHVsbwogICkKICBrbml0cjo6YXNpc19vdXRwdXQoY2FwX2h0bWwpCn0KYGBgCgoKIyAqKkludHJvZHVjY2nDs24qKgoKRWwgbWVyY2FkbyBpbm1vYmlsaWFyaW8gZGUgQ2FsaSByZWZsZWphIHVuYSBkaW7DoW1pY2EgY29tcGxlamEgZW4gbGEgcXVlIGVsIHByZWNpbyBkZSBsYXMgdml2aWVuZGFzIGVzIGVsIHJlc3VsdGFkbyBkZSBtw7psdGlwbGVzIGZhY3RvcmVzOiBjYXJhY3RlcsOtc3RpY2FzIGbDrXNpY2FzIGRlbCBpbm11ZWJsZSwgZXN0cmF0byBzb2Npb2Vjb27Ds21pY28sIHpvbmEgZGUgbGEgY2l1ZGFkIHkgdGlwbyBkZSBwcm9waWVkYWQsIGVudHJlIG90cm9zLiBDb21wcmVuZGVyIGPDs21vIGludGVyYWN0w7phbiBlc3RhcyB2YXJpYWJsZXMgZXMgZXNlbmNpYWwgcGFyYSBxdWUgbG9zIGFnZW50ZXMgZGVsIHNlY3RvciBwdWVkYW4gYXNlc29yYXIgYSBzdXMgY2xpZW50ZXMgY29uIGluZm9ybWFjacOzbiBvYmpldGl2YSB5IGN1YW50aWZpY2FibGUuCgpDJkEgKENhc2FzIHkgQXBhcnRhbWVudG9zKSwgYWdlbmNpYSBkaXJpZ2lkYSBwb3IgTWFyw61hLCBlbmZyZW50YSB1bmEgc29saWNpdHVkIGNvbmNyZXRhOiBvcmllbnRhciBhIHVuYSBjb21wYcOxw61hIGludGVybmFjaW9uYWwgZW4gbGEgYWRxdWlzaWNpw7NuIGRlIGRvcyB2aXZpZW5kYXMgcGFyYSB1YmljYXIgYSBkb3MgZGUgc3VzIGVtcGxlYWRvcyBlbiBDYWxpLiBDYWRhIGNhc28gdGllbmUgcGVyZmlsZXMgZGlzdGludG9zIGVuIGN1YW50byBhIHRpcG8gZGUgaW5tdWVibGUsIHpvbmEsIGNhcmFjdGVyw61zdGljYXMgZsOtc2ljYXMgeSBwcmVzdXB1ZXN0byBkaXNwb25pYmxlLiBEYXIgdW5hIHJlc3B1ZXN0YSBzw7NsaWRhIHJlcXVpZXJlIGlyIG3DoXMgYWxsw6EgZGUgbGEgZXhwZXJpZW5jaWEgZW1ww61yaWNhOiBlcyBuZWNlc2FyaW8gYXBsaWNhciBoZXJyYW1pZW50YXMgZXN0YWTDrXN0aWNhcyBmb3JtYWxlcyBxdWUgcGVybWl0YW4gZXN0aW1hciBwcmVjaW9zLCBjdWFudGlmaWNhciBsYSBpbmNlcnRpZHVtYnJlIHkgZmlsdHJhciBsYXMgb3BjaW9uZXMgcmVhbGVzIGRlIG1lcmNhZG8uCgpFc3RlIGluZm9ybWUgYXBsaWNhIHJlZ3Jlc2nDs24gbGluZWFsIG3Dumx0aXBsZSAoTUNPKSBzb2JyZSBsb3MgZGF0b3MgZGUgb2ZlcnRhIGlubW9iaWxpYXJpYSBkZSBDYWxpIGRlIGxvcyDDumx0aW1vcyB0cmVzIG1lc2VzLiBFbCBhbsOhbGlzaXMgc2UgZXN0cnVjdHVyYSBlbiBzaWV0ZSBwYXNvcyBwYXJhIGNhZGEgc29saWNpdHVkOiBkZXB1cmFjacOzbiB5IGZpbHRybyBkZSBkYXRvcywgYW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBjb24gdmlzdWFsaXphY2lvbmVzIGludGVyYWN0aXZhcywgZXN0aW1hY2nDs24gZSBpbnRlcnByZXRhY2nDs24gZGVsIG1vZGVsbywgdmFsaWRhY2nDs24gZGUgc3VwdWVzdG9zIGVzdGFkw61zdGljb3MsIHByZWRpY2Npw7NuIGRlbCBwcmVjaW8gcHVudHVhbCBjb24gaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSwgZSBpZGVudGlmaWNhY2nDs24gZGUgb2ZlcnRhcyBjb25jcmV0YXMgZ2VvcnJlZmVyZW5jaWFkYXMgZW4gbWFwYXMgaW50ZXJhY3Rpdm9zLgoKIyAqKlBsYW50ZWFtaWVudG8gZGUgbGEgc29saWNpdHVkKioKCk1hcsOtYSByZWNpYmnDsyB1bmEgc29saWNpdHVkIGZvcm1hbCBkZSB1bmEgY29tcGHDscOtYSBpbnRlcm5hY2lvbmFsIHF1ZSByZXF1aWVyZSB1YmljYXIgYSBkb3MgZW1wbGVhZG9zIGVuIENhbGkuIExhIFRhYmxhIDEgcmVzdW1lIGxhcyBjb25kaWNpb25lcyBlc3BlY8OtZmljYXMgZGUgY2FkYSBjYXNvLgoKYGBge3IgY2FyYWN0ZXJpc3RpY2FzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzb2xpY2l0dWQgPC0gZGF0YS5mcmFtZSgKICBDYXJhY3RlcsOtc3RpY2EgICAgPSBjKCJUaXBvIiwgIsOBcmVhIGNvbnN0cnVpZGEgKG3CsikiLCAiUGFycXVlYWRlcm9zIiwKICAgICAgICAgICAgICAgICAgICAgICAgIkJhw7FvcyIsICJIYWJpdGFjaW9uZXMiLCAiRXN0cmF0byIsICJab25hIiwKICAgICAgICAgICAgICAgICAgICAgICAgIkNyw6lkaXRvIHByZWFwcm9iYWRvIChtaWxsb25lcyBDT1ApIiksCiAgYFZpdmllbmRhIDFgICAgICAgPSBjKCJDYXNhIiwgICIyMDAiLCAiMSIsICIyIiwgIjQiLCAiNCBvIDUiLCAiTm9ydGUiLCAiMzUwIiksCiAgYFZpdmllbmRhIDJgICAgICAgPSBjKCJBcGFydGFtZW50byIsICIzMDAiLCAiMyIsICIzIiwgIjUiLCAiNSBvIDYiLCAiU3VyIiwgIjg1MCIpLAogIGNoZWNrLm5hbWVzICAgICAgID0gRkFMU0UKKQoKbWlfdGFibGEoCiAgc29saWNpdHVkLAogIHRpdHVsbyAgICA9ICJDYXJhY3RlcsOtc3RpY2FzIGRlIGxhcyB2aXZpZW5kYXMgc29saWNpdGFkYXMgcG9yIGxhIGNvbXBhw7HDrWEgaW50ZXJuYWNpb25hbC4iLAogIGRpZ2l0cyAgICA9IDAsCiAgbnVtX2NvbHMgID0gZHBseXI6OndoZXJlKH4gRkFMU0UpCikKYGBgCgojICoqUmVzb2x1Y2nDs24gZGUgbGEgc29saWNpdHVkKioKCiMjICoqU29saWNpdHVkIDE6IENhc2Egem9uYSBub3J0ZSoqCgojIyMgRmlsdHJvIGluaWNpYWwgeSBkZXB1cmFjacOzbgoKU2UgcmVhbGl6w7MgdW4gZmlsdHJvIHNvYnJlIGxhIGJhc2UgYHZpdmllbmRhYCBzZWxlY2Npb25hbmRvIMO6bmljYW1lbnRlIGxvcyByZWdpc3Ryb3MgY29ycmVzcG9uZGllbnRlcyBhICoqY2FzYXMqKiB1YmljYWRhcyBlbiBsYSAqKlpvbmEgTm9ydGUqKiBkZSBDYWxpLiBBZGljaW9uYWxtZW50ZSBzZSB2ZXJpZmljw7MgbGEgcHJlc2VuY2lhIGRlIHZhbG9yZXMgZmFsdGFudGVzIGVuIGxhcyB2YXJpYWJsZXMgY2xhdmUgZGVsIG1vZGVsbyB5IHNlIGlkZW50aWZpY2Fyb24gcmVnaXN0cm9zIGR1cGxpY2Fkb3MuCgpgYGB7ciBmaWx0cm8tYmFzZTF9CiMgRmlsdHJvOiBjYXNhcyBlbiBab25hIE5vcnRlCmJhc2UxIDwtIHZpdmllbmRhICU+JQogIGZpbHRlcih0aXBvID09ICJDYXNhIiwgem9uYSA9PSAiWm9uYSBOb3J0ZSIpCgpjYXQoIlJlZ2lzdHJvcyBlbiBiYXNlMToiLCBucm93KGJhc2UxKSwgIlxuIikKY2F0KCJWYWxvcmVzIGZhbHRhbnRlcyBwb3IgdmFyaWFibGU6XG4iKQpwcmludChjb2xTdW1zKGlzLm5hKGJhc2UxKSkpCmNhdCgiXG5SZWdpc3Ryb3MgZHVwbGljYWRvczoiLCBzdW0oZHVwbGljYXRlZChiYXNlMSkpLCAiXG4iKQpgYGAKCmBgYHtyIHByaW1lcm9zLXJlZ2lzdHJvczF9CmJhc2UxICU+JQogIGhlYWQoMykgJT4lCiAgbWlfdGFibGEodGl0dWxvID0gIlByaW1lcm9zIDMgcmVnaXN0cm9zIOKAkyBDYXNhcyBab25hIE5vcnRlIikKYGBgCgpgYGB7ciB2ZXJpZmljYWNpb24tYmFzZTF9CmJhc2UxICU+JQogIGNvdW50KHRpcG8sIG5hbWUgPSAibiIpICU+JQogIG1pX3RhYmxhKHRpdHVsbyA9ICJWZXJpZmljYWNpw7NuOiB0aXBvIGRlIGlubXVlYmxlIGVuIGJhc2UxIikKCmJhc2UxICU+JQogIGNvdW50KHpvbmEsIG5hbWUgPSAibiIpICU+JQogIG1pX3RhYmxhKHRpdHVsbyA9ICJWZXJpZmljYWNpw7NuOiB6b25hIGVuIGJhc2UxIikKCmJhc2UxICU+JQogIGNvdW50KGVzdHJhdG8sIG5hbWUgPSAibiIpICU+JQogIGFycmFuZ2UoZXN0cmF0bykgJT4lCiAgbWlfdGFibGEodGl0dWxvID0gIkRpc3RyaWJ1Y2nDs24gcG9yIGVzdHJhdG8g4oCTIENhc2FzIFpvbmEgTm9ydGUiKQpgYGAKCioqSW50ZXJwcmV0YWNpw7NuIGRlbCBmaWx0cm86KiogTGEgYmFzZTEgY29udGllbmUgZXhjbHVzaXZhbWVudGUgY2FzYXMgZGUgbGEgWm9uYSBOb3J0ZSwgbG8gY3VhbCBxdWVkYSBjb25maXJtYWRvIHBvciBsYXMgdGFibGFzIGRlIHZlcmlmaWNhY2nDs24uIFNlIG9ic2VydmEgcXVlIG5vIGhheSByZWdpc3Ryb3MgZGUgb3Ryb3MgdGlwb3MgZGUgaW5tdWVibGUgbmkgZGUgb3RyYXMgem9uYXMuIExhIGRpc3RyaWJ1Y2nDs24gcG9yIGVzdHJhdG8gcGVybWl0ZSBhbnRpY2lwYXIgcXVlIGVsIGFuw6FsaXNpcyBzZSBjb25jZW50cmFyw6EgZW4gZXN0cmF0b3MgbWVkaW9zLWFsdG9zLiBMb3MgdmFsb3JlcyBmYWx0YW50ZXMgeSBkdXBsaWNhZG9zIGlkZW50aWZpY2Fkb3Mgc2Vyw6FuIGNvbnNpZGVyYWRvcyBhbnRlcyBkZSBsYSBlc3RpbWFjacOzbiBkZWwgbW9kZWxvLgoKYGBge3IgbWFwYS1iYXNlMSwgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9NC44fQptYXBhX2Jhc2UxIDwtIGxlYWZsZXQoZGF0YSA9IGJhc2UxKSAlPiUKICBhZGRUaWxlcygpICU+JQogIGFkZENpcmNsZU1hcmtlcnMoCiAgICBsbmcgICAgPSB+bG9uZ2l0dWQsCiAgICBsYXQgICAgPSB+bGF0aXR1ZCwKICAgIGNvbG9yICA9ICJzdGVlbGJsdWUiLAogICAgcmFkaXVzID0gNSwKICAgIHBvcHVwICA9IH5wYXN0ZTAoCiAgICAgICI8Yj5CYXJyaW86PC9iPiAiLCBiYXJyaW8sICI8YnI+IiwKICAgICAgIjxiPlByZWNpbzo8L2I+ICQiLCBwcmVjaW9tLCAiIE08YnI+IiwKICAgICAgIjxiPsOBcmVhOjwvYj4gIiwgYXJlYWNvbnN0LCAiIG3Csjxicj4iLAogICAgICAiPGI+RXN0cmF0bzo8L2I+ICIsIGVzdHJhdG8KICAgICkKICApICU+JQogIGFkZExlZ2VuZCgiYm90dG9tcmlnaHQiLCBjb2xvcnMgPSAic3RlZWxibHVlIiwKICAgICAgICAgICAgbGFiZWxzID0gIkNhc2FzIC0gWm9uYSBOb3J0ZSIsIHRpdGxlID0gImJhc2UxIikKCmh0bWx0b29sczo6dGFnTGlzdChtYXBhX2Jhc2UxKQouRklHX04gPC0gLkZJR19OICsgMQprbml0cjo6YXNpc19vdXRwdXQoc3ByaW50ZigKICAnPGRpdiBpZD0ibWFwYV9iYXNlMSIgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyOyBtYXJnaW4tdG9wOjZweDsiPgogICA8c3Ryb25nPkZpZ3VyYSAlZC48L3N0cm9uZz4gVWJpY2FjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgY2FzYXMgZW4gWm9uYSBOb3J0ZSBkZSBDYWxpCiAgIDwvZGl2PicsIC5GSUdfTgopKQpgYGAKCioqQW7DoWxpc2lzIGRlbCBtYXBhOioqIEFsIHZpc3VhbGl6YXIgbG9zIHB1bnRvcyBzb2JyZSBlbCBtYXBhIGRlIENhbGksIGVzIHBvc2libGUgcXVlIGFsZ3Vub3MgbWFyY2Fkb3JlcyBhcGFyZXpjYW4gZnVlcmEgZGVsIHBvbMOtZ29ubyBlc3BlcmFkbyBwYXJhIGxhIFpvbmEgTm9ydGUuIEVzdG8gc2UgcHVlZGUgZGViZXIgYSBkb3MgcmF6b25lcyBwcmluY2lwYWxlczogKDEpIGxhIGNsYXNpZmljYWNpw7NuIHBvciB6b25hIGVzIGF1dG9kZWNsYXJhZGEgcG9yIGVsIG9mZXJlbnRlIHkgcHVlZGUgY29udGVuZXIgaW1wcmVjaXNpb25lcywgeSAoMikgbG9zIGzDrW1pdGVzIGFkbWluaXN0cmF0aXZvcyBlbnRyZSB6b25hcyBubyBlc3TDoW4gZGVmaW5pZG9zIGNvbiBwcmVjaXNpw7NuIGVuIGxhIGJhc2UgZGUgZGF0b3MuIEVuIHVuIGFuw6FsaXNpcyBtw6FzIHJpZ3Vyb3NvIHNlIHJlY29tZW5kYXLDrWEgdmFsaWRhciBsYXMgY29vcmRlbmFkYXMgY29uIHVuIHNoYXBlZmlsZSBvZmljaWFsIGRlIGxhcyBjb211bmFzIGRlIENhbGksIHkgcmVjbGFzaWZpY2FyIG8gZWxpbWluYXIgbG9zIHB1bnRvcyBxdWUgcXVlZGVuIGZ1ZXJhIGRlbCDDoXJlYSBub3J0ZSBhbnRlcyBkZSBtb2RlbGFyLgoKIyMjIEFuw6FsaXNpcyBleHBsb3JhdG9yaW8KClNlIGNvbnN0cnV5w7MgdW5hIG1hdHJpeiBkZSBjb3JyZWxhY2lvbmVzIGVudHJlIGxhcyB2YXJpYWJsZXMgbnVtw6lyaWNhcyByZWxldmFudGVzIHkgdHJlcyBncsOhZmljb3MgaW50ZXJhY3Rpdm9zIHF1ZSBwZXJtaXRlbiBleHBsb3JhciBsYSByZWxhY2nDs24gZGVsIHByZWNpbyBjb24gZWwgw6FyZWEgY29uc3RydWlkYSwgZWwgbsO6bWVybyBkZSBoYWJpdGFjaW9uZXMgeSBlbCBlc3RyYXRvIHNvY2lvZWNvbsOzbWljby4KCmBgYHtyIGVkYS1yZXN1bWVuMX0KIyBFc3RhZMOtc3RpY2FzIGRlc2NyaXB0aXZhcyBkZSBsYXMgdmFyaWFibGVzIGRlbCBtb2RlbG8KYmFzZTEgJT4lCiAgc2VsZWN0KHByZWNpb20sIGFyZWFjb25zdCwgZXN0cmF0bywgaGFiaXRhY2lvbmVzLCBwYXJxdWVhZGVyb3MsIGJhbmlvcykgJT4lCiAgc3VtbWFyeSgpICU+JQogIHByaW50KCkKYGBgCgpgYGB7ciBlZGEtY29ycmVsYWNpb24xfQp2YXJzX251bSA8LSBiYXNlMSAlPiUKICBzZWxlY3QocHJlY2lvbSwgYXJlYWNvbnN0LCBlc3RyYXRvLCBiYW5pb3MsIGhhYml0YWNpb25lcywgcGFycXVlYWRlcm9zKQoKcF9wYWlycyA8LSBnZ3BhaXJzKAogIHZhcnNfbnVtLAogIHRpdGxlID0gIk1hdHJpeiBkZSBjb3JyZWxhY2lvbmVzIOKAkyBDYXNhcyBab25hIE5vcnRlIiwKICBsb3dlciA9IGxpc3QoY29udGludW91cyA9IHdyYXAoInNtb290aCIsIGFscGhhID0gMC4zLCBjb2xvciA9ICJzdGVlbGJsdWUiKSksCiAgZGlhZyAgPSBsaXN0KGNvbnRpbnVvdXMgPSB3cmFwKCJkZW5zaXR5RGlhZyIsIGZpbGwgPSAic3RlZWxibHVlIiwgYWxwaGEgPSAwLjQpKSwKICB1cHBlciA9IGxpc3QoY29udGludW91cyA9IHdyYXAoImNvciIsIHNpemUgPSAzLjUpKQopICsgdGhlbWVfbWluaW1hbCgpCgptaV9maWd1cmEoCiAgcGxvdCAgID0gcF9wYWlycywKICBpZCAgICAgPSAiY29ycmVsYWNpb25fYmFzZTEiLAogIHRpdHVsbyA9ICJNYXRyaXogZGUgY29ycmVsYWNpb25lcyDigJMgQ2FzYXMgWm9uYSBOb3J0ZSIKKQpgYGAKCmBgYHtyIHBsb3RseS1wcmVjaW8tYXJlYTF9CnAxIDwtIHBsb3RfbHkoYmFzZTEsCiAgICAgICAgICAgICAgeCA9IH5hcmVhY29uc3QsIHkgPSB+cHJlY2lvbSwKICAgICAgICAgICAgICBjb2xvciA9IH5mYWN0b3IoZXN0cmF0byksIGNvbG9ycyA9ICJTZXQxIiwKICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiLAogICAgICAgICAgICAgIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDgsIG9wYWNpdHkgPSAwLjcpLAogICAgICAgICAgICAgIHRleHQgPSB+cGFzdGUoIkJhcnJpbzoiLCBiYXJyaW8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPlByZWNpbzogJCIsIHByZWNpb20sICJNIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+w4FyZWE6IiwgYXJlYWNvbnN0LCAibcKyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+RXN0cmF0bzoiLCBlc3RyYXRvKSkgJT4lCiAgbGF5b3V0KAogICAgdGl0bGUgID0gIlByZWNpbyB2cyDDgXJlYSBjb25zdHJ1aWRhIOKAkyBDYXNhcyBab25hIE5vcnRlIiwKICAgIHhheGlzICA9IGxpc3QodGl0bGUgPSAiw4FyZWEgY29uc3RydWlkYSAobcKyKSIpLAogICAgeWF4aXMgID0gbGlzdCh0aXRsZSA9ICJQcmVjaW8gKG1pbGxvbmVzIENPUCkiKSwKICAgIGxlZ2VuZCA9IGxpc3QodGl0bGUgPSBsaXN0KHRleHQgPSAiRXN0cmF0byIpKQogICkKCmh0bWx0b29sczo6dGFnTGlzdChwMSkKLkZJR19OIDwtIC5GSUdfTiArIDEKa25pdHI6OmFzaXNfb3V0cHV0KHNwcmludGYoCiAgJzxkaXYgaWQ9InByZWNpb19hcmVhMSIgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyOyBtYXJnaW4tdG9wOjZweDsiPgogICA8c3Ryb25nPkZpZ3VyYSAlZC48L3N0cm9uZz4gUHJlY2lvIHZzIMOBcmVhIGNvbnN0cnVpZGEgcG9yIGVzdHJhdG8gKGludGVyYWN0aXZvKQogICA8L2Rpdj4nLCAuRklHX04KKSkKYGBgCgpgYGB7ciBwbG90bHktcHJlY2lvLWhhYml0YWNpb25lczF9CnAyIDwtIHBsb3RfbHkoYmFzZTEsCiAgICAgICAgICAgICAgeCA9IH5oYWJpdGFjaW9uZXMsIHkgPSB+cHJlY2lvbSwKICAgICAgICAgICAgICBjb2xvciA9IH5mYWN0b3IoZXN0cmF0byksIGNvbG9ycyA9ICJTZXQyIiwKICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiLAogICAgICAgICAgICAgIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDgsIG9wYWNpdHkgPSAwLjcpLAogICAgICAgICAgICAgIHRleHQgPSB+cGFzdGUoIkJhcnJpbzoiLCBiYXJyaW8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPlByZWNpbzogJCIsIHByZWNpb20sICJNIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+SGFiaXRhY2lvbmVzOiIsIGhhYml0YWNpb25lcykpICU+JQogIGxheW91dCgKICAgIHRpdGxlICA9ICJQcmVjaW8gdnMgTsO6bWVybyBkZSBoYWJpdGFjaW9uZXMg4oCTIENhc2FzIFpvbmEgTm9ydGUiLAogICAgeGF4aXMgID0gbGlzdCh0aXRsZSA9ICJIYWJpdGFjaW9uZXMiKSwKICAgIHlheGlzICA9IGxpc3QodGl0bGUgPSAiUHJlY2lvIChtaWxsb25lcyBDT1ApIiksCiAgICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gbGlzdCh0ZXh0ID0gIkVzdHJhdG8iKSkKICApCgpodG1sdG9vbHM6OnRhZ0xpc3QocDIpCi5GSUdfTiA8LSAuRklHX04gKyAxCmtuaXRyOjphc2lzX291dHB1dChzcHJpbnRmKAogICc8ZGl2IGlkPSJwcmVjaW9faGFiaXRhY2lvbmVzMSIgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyOyBtYXJnaW4tdG9wOjZweDsiPgogICA8c3Ryb25nPkZpZ3VyYSAlZC48L3N0cm9uZz4gUHJlY2lvIHZzIE7Dum1lcm8gZGUgaGFiaXRhY2lvbmVzIHBvciBlc3RyYXRvIChpbnRlcmFjdGl2bykKICAgPC9kaXY+JywgLkZJR19OCikpCmBgYAoKYGBge3IgcGxvdGx5LWJveHBsb3QtZXN0cmF0bzF9CnAzIDwtIHBsb3RfbHkoYmFzZTEsCiAgICAgICAgICAgICAgeCA9IH5mYWN0b3IoZXN0cmF0byksIHkgPSB+cHJlY2lvbSwKICAgICAgICAgICAgICB0eXBlICA9ICJib3giLAogICAgICAgICAgICAgIGNvbG9yID0gfmZhY3Rvcihlc3RyYXRvKSwgY29sb3JzID0gIlNldDEiKSAlPiUKICBsYXlvdXQoCiAgICB0aXRsZSAgICAgID0gIkRpc3RyaWJ1Y2nDs24gZGVsIHByZWNpbyBwb3IgZXN0cmF0byDigJMgQ2FzYXMgWm9uYSBOb3J0ZSIsCiAgICB4YXhpcyAgICAgID0gbGlzdCh0aXRsZSA9ICJFc3RyYXRvIiksCiAgICB5YXhpcyAgICAgID0gbGlzdCh0aXRsZSA9ICJQcmVjaW8gKG1pbGxvbmVzIENPUCkiKSwKICAgIHNob3dsZWdlbmQgPSBGQUxTRQogICkKCmh0bWx0b29sczo6dGFnTGlzdChwMykKLkZJR19OIDwtIC5GSUdfTiArIDEKa25pdHI6OmFzaXNfb3V0cHV0KHNwcmludGYoCiAgJzxkaXYgaWQ9ImJveHBsb3RfZXN0cmF0bzEiIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlcjsgbWFyZ2luLXRvcDo2cHg7Ij4KICAgPHN0cm9uZz5GaWd1cmEgJWQuPC9zdHJvbmc+IERpc3RyaWJ1Y2nDs24gZGVsIHByZWNpbyBwb3IgZXN0cmF0byAoaW50ZXJhY3Rpdm8pCiAgIDwvZGl2PicsIC5GSUdfTgopKQpgYGAKCmBgYHtyIGNvcnJlbGFjaW9uLW51bWVyaWNhMX0KIyBNYXRyaXogbnVtw6lyaWNhIGRlIGNvcnJlbGFjaW9uZXMgcGFyYSBpbnRlcnByZXRhY2nDs24gY3VhbnRpdGF0aXZhCmNvcl9tYXQxIDwtIGNvcih2YXJzX251bSwgdXNlID0gImNvbXBsZXRlLm9icyIpCnJvdW5kKGNvcl9tYXQxLCAzKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oIlZhcmlhYmxlIikgJT4lCiAgbWlfdGFibGEoCiAgICB0aXR1bG8gPSAiTWF0cml6IGRlIGNvcnJlbGFjaW9uZXMgZGUgUGVhcnNvbiDigJMgQ2FzYXMgWm9uYSBOb3J0ZSIsCiAgICBkaWdpdHMgPSAzCiAgKQpgYGAKCioqSW50ZXJwcmV0YWNpw7NuIGRlbCBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvOioqCgpMYSBtYXRyaXogZGUgY29ycmVsYWNpb25lcyB5IGxvcyBncsOhZmljb3MgaW50ZXJhY3Rpdm9zIHBlcm1pdGVuIGV4dHJhZXIgbGFzIHNpZ3VpZW50ZXMgY29uY2x1c2lvbmVzIHNvYnJlIGxhcyBjYXNhcyBkZSBsYSBab25hIE5vcnRlOgoKLSAqKsOBcmVhIGNvbnN0cnVpZGEgdnMuIHByZWNpbzoqKiBTZSBvYnNlcnZhIHVuYSByZWxhY2nDs24gcG9zaXRpdmEgY2xhcmE6IGEgbWF5b3Igw6FyZWEsIG1heW9yIHByZWNpby4gRXN0YSBlcyBsYSB2YXJpYWJsZSBjb24gbWF5b3IgY29ycmVsYWNpw7NuIGNvbiBgcHJlY2lvbWAsIGxvIHF1ZSBsYSBjb252aWVydGUgZW4gZWwgcHJlZGljdG9yIG3DoXMgcmVsZXZhbnRlIGRlbCBtb2RlbG8uCgotICoqRXN0cmF0byB2cy4gcHJlY2lvOioqIEVsIGRpYWdyYW1hIGRlIGNhamEgY29uZmlybWEgcXVlIGVsIHByZWNpbyBtZWRpYW5vIGF1bWVudGEgZGUgbWFuZXJhIHByb2dyZXNpdmEgY29uIGVsIGVzdHJhdG8uIExhIGRpc3BlcnNpw7NuIHRhbWJpw6luIGNyZWNlIGVuIGVzdHJhdG9zIHN1cGVyaW9yZXMsIGxvIHF1ZSBpbmRpY2EgbWF5b3IgaGV0ZXJvZ2VuZWlkYWQgZW4gbG9zIHByZWNpb3MgZGUgY2FzYXMgZGUgZXN0cmF0byA1IHkgNi4KCi0gKipIYWJpdGFjaW9uZXMgdnMuIHByZWNpbzoqKiBFeGlzdGUgdW5hIGNvcnJlbGFjacOzbiBwb3NpdGl2YSBtb2RlcmFkYS4gU2luIGVtYmFyZ28sIGVzdGEgdmFyaWFibGUgZXN0w6EgdGFtYmnDqW4gY29ycmVsYWNpb25hZGEgY29uIGBhcmVhY29uc3RgIChhIG3DoXMgaGFiaXRhY2lvbmVzLCBtYXlvciDDoXJlYSksIGxvIGN1YWwgcHVlZGUgZ2VuZXJhciByZWR1bmRhbmNpYSBkZSBpbmZvcm1hY2nDs24gZW4gZWwgbW9kZWxvLgoKLSAqKkJhw7FvcyB5IHBhcnF1ZWFkZXJvczoqKiBNdWVzdHJhbiBjb3JyZWxhY2lvbmVzIHBvc2l0aXZhcyBjb24gZWwgcHJlY2lvLCBhdW5xdWUgbcOhcyBkw6liaWxlcyBxdWUgw6FyZWEgeSBlc3RyYXRvLgoKLSAqKk11bHRpY29saW5lYWxpZGFkIHBvdGVuY2lhbDoqKiBTZSBvYnNlcnZhbiBjb3JyZWxhY2lvbmVzIHJlbGF0aXZhbWVudGUgYWx0YXMgZW50cmUgYGFyZWFjb25zdGAsIGBoYWJpdGFjaW9uZXNgIHkgYGJhbmlvc2AsIGxvIHF1ZSBhbnRpY2lwYSBwb3NpYmxlcyBwcm9ibGVtYXMgZGUgbXVsdGljb2xpbmVhbGlkYWQgcXVlIHNlcsOhbiBldmFsdWFkb3MgZm9ybWFsbWVudGUgbWVkaWFudGUgVklGIGVuIGxhIGV0YXBhIGRlIGVzdGltYWNpw7NuLgoKIyMjIEVzdGltYWNpw7NuIGRlbCBtb2RlbG8KClNlIGVzdGltw7MgdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsIG3Dumx0aXBsZSBwb3IgTUNPIGNvbiBgcHJlY2lvbWAgY29tbyB2YXJpYWJsZSBkZXBlbmRpZW50ZSB5IGBhcmVhY29uc3RgLCBgZXN0cmF0b2AsIGBoYWJpdGFjaW9uZXNgLCBgcGFycXVlYWRlcm9zYCB5IGBiYW5pb3NgIGNvbW8gcHJlZGljdG9yYXMuCgpgYGB7ciBtb2RlbG8tcmxtMX0Kc2V0LnNlZWQocGFyYW1zJHNlZWQpCgptb2RlbG8xIDwtIGxtKHByZWNpb20gfiBhcmVhY29uc3QgKyBlc3RyYXRvICsgaGFiaXRhY2lvbmVzICsKICAgICAgICAgICAgICAgIHBhcnF1ZWFkZXJvcyArIGJhbmlvcywKICAgICAgICAgICAgICBkYXRhID0gYmFzZTEpCgpzdW1tYXJ5KG1vZGVsbzEpCmBgYAoKYGBge3IgdGFibGEtY29lZmljaWVudGVzMX0KdGJsX21vZGVsbzEgPC0gbW9kZWxzdW1tYXJ5KAogIGxpc3QoIk1vZGVsbyBWaXZpZW5kYSAxIiA9IG1vZGVsbzEpLAogIGZtdCAgICAgICAgPSAzLAogIHN0YXRpc3RpYyAgPSAiKHtwLnZhbHVlfSkiLAogIHN0YXJzICAgICAgPSBUUlVFLAogIG5vdGVzICAgICAgPSAiVmFsb3JlcyBwIGVudHJlIHBhcsOpbnRlc2lzLiAqIHA8MC4wNSwgKiogcDwwLjAxLCAqKiogcDwwLjAwMSIsCiAgZXNjYXBlICAgICA9IEZBTFNFLAogIG91dHB1dCAgICAgPSAia2FibGVFeHRyYSIKKSAlPiUKICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpLAogICAgZnVsbF93aWR0aCAgICAgICAgPSBGQUxTRSwKICAgIHBvc2l0aW9uICAgICAgICAgID0gImNlbnRlciIKICApCgpjYXBfaHRtbCA8LSBzcHJpbnRmKAogICc8ZGl2IGlkPSJ0YWJsYV9tb2RlbG8xIiBzdHlsZT0ibWFyZ2luOjAgMCA2cHggMDsiPgogICA8c3Ryb25nPlRhYmxhICVkLjwvc3Ryb25nPiBSZXN1bWVuIGRlbCBtb2RlbG8gZGUgcmVncmVzacOzbiDigJMgQ2FzYXMgWm9uYSBOb3J0ZQogICA8L2Rpdj4nLAogIHtlbnZpcm9ubWVudChtaV90YWJsYSkkdGFiX24gPC0gZW52aXJvbm1lbnQobWlfdGFibGEpJHRhYl9uICsgMUwKICAgZW52aXJvbm1lbnQobWlfdGFibGEpJHRhYl9ufQopCgprbml0cjo6YXNpc19vdXRwdXQocGFzdGUwKGNhcF9odG1sLCAiXG5cbiIsIHRibF9tb2RlbG8xKSkKYGBgCgpgYGB7ciBpbnRlcnByZXRhY2lvbi1jb2VmaWNpZW50ZXMxfQojIEV4dHJhZXIgY29lZmljaWVudGVzIHBhcmEgaW50ZXJwcmV0YWNpw7NuIGRpbsOhbWljYQpjb2VmMSAgICAgIDwtIGNvZWYobW9kZWxvMSkKY29lZl9uYW1lcyA8LSBuYW1lcyhjb2VmMSkKcjJfMSAgICAgICA8LSBzdW1tYXJ5KG1vZGVsbzEpJHIuc3F1YXJlZApyMmFkal8xICAgIDwtIHN1bW1hcnkobW9kZWxvMSkkYWRqLnIuc3F1YXJlZApmc3RhdF8xICAgIDwtIHN1bW1hcnkobW9kZWxvMSkkZnN0YXRpc3RpYwpwdmFsX2YxICAgIDwtIHBmKGZzdGF0XzFbMV0sIGZzdGF0XzFbMl0sIGZzdGF0XzFbM10sIGxvd2VyLnRhaWwgPSBGQUxTRSkKCmNhdCgiPT09IENPRUZJQ0lFTlRFUyBFU1RJTUFET1Mg4oCTIE1PREVMTyAxID09PVxuIikKcHJpbnQocm91bmQoY29lZjEsIDQpKQpjYXQoc3ByaW50ZigiXG5SwrIgPSAlLjRmICB8ICBSwrIgYWp1c3RhZG8gPSAlLjRmXG4iLCByMl8xLCByMmFkal8xKSkKY2F0KHNwcmludGYoIkYtZXN0YWTDrXN0aWNvID0gJS4yZiAgKHAtdmFsb3IgPSAlLjZmKVxuIiwgZnN0YXRfMVsxXSwgcHZhbF9mMSkpCmBgYAoKKipJbnRlcnByZXRhY2nDs24gZGUgbG9zIGNvZWZpY2llbnRlcyAodmFsb3JlcyByZWFsZXMgZGVsIG1vZGVsbyk6KioKCkxvcyByZXN1bHRhZG9zIGRlbCBtb2RlbG8gcGVybWl0ZW4gZm9ybXVsYXIgbGFzIHNpZ3VpZW50ZXMgaW50ZXJwcmV0YWNpb25lcyBjb250ZXh0dWFsaXphZGFzIHBhcmEgZWwgbWVyY2FkbyBkZSBjYXNhcyBlbiBsYSBab25hIE5vcnRlIGRlIENhbGk6CgotICoqSW50ZXJjZXB0bzoqKiBSZXByZXNlbnRhIGVsIHByZWNpbyB0ZcOzcmljbyBjdWFuZG8gdG9kYXMgbGFzIHZhcmlhYmxlcyBwcmVkaWN0b3JhcyBzb24gY2Vyby4gTm8gdGllbmUgaW50ZXJwcmV0YWNpw7NuIHByw6FjdGljYSBlbiBlc3RlIGNvbnRleHRvLCBkYWRvIHF1ZSBuaW5ndW5hIHZpdmllbmRhIHJlYWwgdGVuZHLDrWEgw6FyZWEsIGVzdHJhdG8sIGhhYml0YWNpb25lcywgcGFycXVlYWRlcm9zIG8gYmHDsW9zIGlndWFsZXMgYSBjZXJvLgoKLSAqKmBhcmVhY29uc3RgOioqIFBvciBjYWRhIG1ldHJvIGN1YWRyYWRvIGFkaWNpb25hbCBkZSDDoXJlYSBjb25zdHJ1aWRhLCBlbCBwcmVjaW8gcHJvbWVkaW8gZGUgbGEgY2FzYSAqKmF1bWVudGEgZW4gYHIgcm91bmQoY29lZjFbImFyZWFjb25zdCJdLCAzKWAgbWlsbG9uZXMgZGUgcGVzb3MqKiwgbWFudGVuaWVuZG8gbGFzIGRlbcOhcyB2YXJpYWJsZXMgY29uc3RhbnRlcy4gRXN0ZSByZXN1bHRhZG8gZXMgY29oZXJlbnRlIGNvbiBsYSBsw7NnaWNhIGRlbCBtZXJjYWRvIGlubW9iaWxpYXJpbzogbWF5b3Igw6FyZWEgaW1wbGljYSBkaXJlY3RhbWVudGUgbWF5b3IgdmFsb3IuIEVzIGxhIHZhcmlhYmxlIGNvbiBtYXlvciBpbXBhY3RvIHVuaXRhcmlvIGN1YW50aWZpY2FibGUgc29icmUgZWwgcHJlY2lvLgoKLSAqKmBlc3RyYXRvYDoqKiBQb3IgY2FkYSB1bmlkYWQgYWRpY2lvbmFsIGRlIGVzdHJhdG8gc29jaW9lY29uw7NtaWNvLCBlbCBwcmVjaW8gcHJvbWVkaW8gKipjYW1iaWEgZW4gYHIgcm91bmQoY29lZjFbImVzdHJhdG8iXSwgMylgIG1pbGxvbmVzIGRlIHBlc29zKiosIGNldGVyaXMgcGFyaWJ1cy4gRWwgc2lnbm8gcG9zaXRpdm8gY29uZmlybWEgcXVlIGxhcyBjYXNhcyBlbiBlc3RyYXRvcyBtw6FzIGFsdG9zIGRlIGxhIFpvbmEgTm9ydGUgdGllbmVuIHByZWNpb3Mgc3VwZXJpb3JlcywgbG8gY3VhbCBlcyBjb25zaXN0ZW50ZSBjb24gbGFzIGRpZmVyZW5jaWFzIGVuIGluZnJhZXN0cnVjdHVyYSwgc2VydmljaW9zIHDDumJsaWNvcyB5IHZhbG9yaXphY2nDs24gcG9yIHNlY3Rvci4KCi0gKipgaGFiaXRhY2lvbmVzYDoqKiBQb3IgY2FkYSBoYWJpdGFjacOzbiBhZGljaW9uYWwsIGVsIHByZWNpbyB2YXLDrWEgZW4gKipgciByb3VuZChjb2VmMVsiaGFiaXRhY2lvbmVzIl0sIDMpYCBtaWxsb25lcyBkZSBwZXNvcyoqLiBTaSBlbCBjb2VmaWNpZW50ZSBlcyBwb3NpdGl2bywgZWwgcmVzdWx0YWRvIGVzIGzDs2dpY287IHNpbiBlbWJhcmdvLCBzdSBzaWduaWZpY2FuY2lhIGVzdGFkw61zdGljYSBwb2Ryw61hIHZlcnNlIGF0ZW51YWRhIHBvciBsYSBjb3JyZWxhY2nDs24gY29uIGBhcmVhY29uc3RgLCB5YSBxdWUgdml2aWVuZGFzIG3DoXMgZ3JhbmRlcyB0aWVuZGVuIGEgdGVuZXIgbcOhcyBoYWJpdGFjaW9uZXMuCgotICoqYHBhcnF1ZWFkZXJvc2A6KiogQ2FkYSBwYXJxdWVhZGVybyBhZGljaW9uYWwgc2UgYXNvY2lhIGEgdW4gY2FtYmlvIGRlICoqYHIgcm91bmQoY29lZjFbInBhcnF1ZWFkZXJvcyJdLCAzKWAgbWlsbG9uZXMgZGUgcGVzb3MqKiBlbiBlbCBwcmVjaW8uIEVuIGxhIFpvbmEgTm9ydGUgZGUgQ2FsaSwgbGEgZGlzcG9uaWJpbGlkYWQgZGUgcGFycXVlYWRlcm9zIGVzIHVuIGF0cmlidXRvIHZhbG9yYWRvLCBlc3BlY2lhbG1lbnRlIGVuIGVzdHJhdG9zIDQgeSA1LgoKLSAqKmBiYW5pb3NgOioqIENhZGEgYmHDsW8gYWRpY2lvbmFsIHNlIGFzb2NpYSBhIHVuYSB2YXJpYWNpw7NuIGRlICoqYHIgcm91bmQoY29lZjFbImJhbmlvcyJdLCAzKWAgbWlsbG9uZXMgZGUgcGVzb3MqKi4gQWwgaWd1YWwgcXVlIGhhYml0YWNpb25lcywgcHVlZGUgcHJlc2VudGFyIGNvbGluZWFsaWRhZCBjb24gw6FyZWEgY29uc3RydWlkYS4KCioqRXZhbHVhY2nDs24gZGVsIGFqdXN0ZSBkZWwgbW9kZWxvOioqCgpFbCBjb2VmaWNpZW50ZSBkZSBkZXRlcm1pbmFjacOzbiBhanVzdGFkbyBlcyAqKlLCsiBhanVzdGFkbyA9IGByIHJvdW5kKHIyYWRqXzEsIDQpYCoqLCBsbyBxdWUgaW5kaWNhIHF1ZSBlbCBtb2RlbG8gZXhwbGljYSBhcHJveGltYWRhbWVudGUgZWwgKipgciByb3VuZChyMmFkal8xICogMTAwLCAxKWAlIGRlIGxhIHZhcmlhYmlsaWRhZCBkZWwgcHJlY2lvKiogZGUgbGFzIGNhc2FzIGVuIGxhIFpvbmEgTm9ydGUuIExhIHBydWViYSBGIGdsb2JhbCBhcnJvamEgdW4gcC12YWxvciBkZSBgciBmb3JtYXQocHZhbF9mMSwgc2NpZW50aWZpYyA9IFRSVUUsIGRpZ2l0cyA9IDMpYCwgY29uZmlybWFuZG8gcXVlIGVsIG1vZGVsbyBlbiBzdSBjb25qdW50byBlcyBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZvLCBlcyBkZWNpciwgYWwgbWVub3MgdW5hIGRlIGxhcyB2YXJpYWJsZXMgcHJlZGljdG9yYXMgdGllbmUgZWZlY3RvIHJlYWwgc29icmUgZWwgcHJlY2lvLgoKKirCv0VzIGzDs2dpY28gZWwgbW9kZWxvPyDCv0PDs21vIG1lam9yYXJsbz8qKgoKTG9zIHNpZ25vcyBkZSBsb3MgY29lZmljaWVudGVzIHNvbiBlbiBnZW5lcmFsIGNvaGVyZW50ZXMgY29uIGxhIHRlb3LDrWEgZWNvbsOzbWljYSBkZWwgbWVyY2FkbyBpbm1vYmlsaWFyaW8uIFBhcmEgbWVqb3JhciBlbCBhanVzdGUgc2UgcG9kcsOtYTogKDEpIGFwbGljYXIgdW5hIHRyYW5zZm9ybWFjacOzbiBsb2dhcsOtdG1pY2EgYWwgcHJlY2lvIHBhcmEgY29ycmVnaXIgcG9zaWJsZSBzZXNnbyBwb3IgYXNpbWV0csOtYSBlbiBsYSBkaXN0cmlidWNpw7NuIGRlIGxhIHZhcmlhYmxlIGRlcGVuZGllbnRlOyAoMikgaW5jbHVpciB2YXJpYWJsZXMgZGUgdWJpY2FjacOzbiBtw6FzIGVzcGVjw61maWNhcyBjb21vIGVsIGJhcnJpbyBtZWRpYW50ZSB2YXJpYWJsZXMgaW5kaWNhZG9yYXM7ICgzKSBleHBsb3JhciB0w6lybWlub3MgZGUgaW50ZXJhY2Npw7NuIGVudHJlIMOhcmVhIHkgZXN0cmF0bzsgKDQpIGFwbGljYXIgc2VsZWNjacOzbiBzdGVwd2lzZSBwYXJhIHJldGVuZXIgc29sbyBsYXMgdmFyaWFibGVzIHNpZ25pZmljYXRpdmFzIHkgcmVkdWNpciBydWlkby4KCiMjIyBWYWxpZGFjacOzbiBkZSBzdXB1ZXN0b3MKClNlIHZlcmlmaWNhcm9uIGxvcyBjdWF0cm8gc3VwdWVzdG9zIGNsw6FzaWNvcyBkZWwgbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsIG3Dumx0aXBsZSBtZWRpYW50ZSBwcnVlYmFzIGZvcm1hbGVzIHkgZ3LDoWZpY29zIGRpYWduw7NzdGljb3MuCgpgYGB7ciBzdXB1ZXN0b3MtZ3JhZmljb3MxfQpwX2RpYWcgPC0gcmVjb3JkUGxvdCh7CiAgcGFyKG1mcm93ID0gYygyLCAyKSkKICBwbG90KG1vZGVsbzEpCiAgcGFyKG1mcm93ID0gYygxLCAxKSkKfSkKCm1pX2ZpZ3VyYSgKICBwbG90ICAgPSBwX2RpYWcsCiAgaWQgICAgID0gImRpYWdub3N0aWNvc19tb2RlbG8xIiwKICB0aXR1bG8gPSAiR3LDoWZpY29zIGRpYWduw7NzdGljb3MgZGVsIG1vZGVsbyDigJMgQ2FzYXMgWm9uYSBOb3J0ZSIKKQpgYGAKCmBgYHtyIHN1cHVlc3RvLW5vcm1hbGlkYWQxfQpyZXNpZHVhbGVzMSA8LSByZXNpZHVhbHMobW9kZWxvMSkKc3cxICA8LSBzaGFwaXJvLnRlc3QocmVzaWR1YWxlczEpCmtzMSAgPC0ga3MudGVzdChzY2FsZShyZXNpZHVhbGVzMSksICJwbm9ybSIpCgpkYXRhLmZyYW1lKAogIFBydWViYSAgICAgID0gYygiU2hhcGlyby1XaWxrIiwgIktvbG1vZ29yb3YtU21pcm5vdiIpLAogIEVzdGFkw61zdGljbyA9IHJvdW5kKGMoc3cxJHN0YXRpc3RpYywga3MxJHN0YXRpc3RpYyksIDQpLAogIGBwLXZhbG9yYCAgID0gcm91bmQoYyhzdzEkcC52YWx1ZSwgIGtzMSRwLnZhbHVlKSwgIDYpLAogIENvbmNsdXNpw7NuICA9IGlmZWxzZShjKHN3MSRwLnZhbHVlLCBrczEkcC52YWx1ZSkgPiAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICJObyBzZSByZWNoYXphIEjigoAgKG5vcm1hbGlkYWQpIiwKICAgICAgICAgICAgICAgICAgICAgICAiU2UgcmVjaGF6YSBI4oKAIChubyBub3JtYWxpZGFkKSIpLAogIGNoZWNrLm5hbWVzID0gRkFMU0UKKSAlPiUKICBtaV90YWJsYSgKICAgIHRpdHVsbyAgID0gIlBydWViYXMgZGUgbm9ybWFsaWRhZCBkZSByZXNpZHVhbGVzIOKAkyBNb2RlbG8gMSIsCiAgICBudW1fY29scyA9IGRwbHlyOjp3aGVyZShpcy5udW1lcmljKQogICkKYGBgCgpgYGB7ciBzdXB1ZXN0by1ob21vY2VkYXN0aWNpZGFkMX0KZ3ExIDwtIGdxdGVzdChtb2RlbG8xKQoKZGF0YS5mcmFtZSgKICBQcnVlYmEgICAgICA9ICJHb2xkZmVsZC1RdWFuZHQiLAogIEVzdGFkw61zdGljbyA9IHJvdW5kKGdxMSRzdGF0aXN0aWMsIDQpLAogIGBwLXZhbG9yYCAgID0gcm91bmQoZ3ExJHAudmFsdWUsICA2KSwKICBDb25jbHVzacOzbiAgPSBpZmVsc2UoZ3ExJHAudmFsdWUgPiAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICJObyBzZSByZWNoYXphIEjigoAgKHZhcmlhbnphIGNvbnN0YW50ZSkiLAogICAgICAgICAgICAgICAgICAgICAgICJTZSByZWNoYXphIEjigoAgKGhldGVyb2NlZGFzdGljaWRhZCkiKSwKICBjaGVjay5uYW1lcyA9IEZBTFNFCikgJT4lCiAgbWlfdGFibGEoCiAgICB0aXR1bG8gICA9ICJQcnVlYmEgZGUgaG9tb2NlZGFzdGljaWRhZCBHb2xkZmVsZC1RdWFuZHQg4oCTIE1vZGVsbyAxIiwKICAgIG51bV9jb2xzID0gZHBseXI6OndoZXJlKGlzLm51bWVyaWMpCiAgKQpgYGAKCmBgYHtyIHN1cHVlc3RvLWluZGVwZW5kZW5jaWExfQpkdzEgPC0gZHd0ZXN0KG1vZGVsbzEpCgpkYXRhLmZyYW1lKAogIFBydWViYSAgICAgID0gIkR1cmJpbi1XYXRzb24iLAogIEVzdGFkw61zdGljbyA9IHJvdW5kKGR3MSRzdGF0aXN0aWMsIDQpLAogIGBwLXZhbG9yYCAgID0gcm91bmQoZHcxJHAudmFsdWUsICA2KSwKICBDb25jbHVzacOzbiAgPSBpZmVsc2UoZHcxJHAudmFsdWUgPiAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICJObyBzZSByZWNoYXphIEjigoAgKGluZGVwZW5kZW5jaWEpIiwKICAgICAgICAgICAgICAgICAgICAgICAiU2UgcmVjaGF6YSBI4oKAIChhdXRvY29ycmVsYWNpw7NuKSIpLAogIGNoZWNrLm5hbWVzID0gRkFMU0UKKSAlPiUKICBtaV90YWJsYSgKICAgIHRpdHVsbyAgID0gIlBydWViYSBkZSBpbmRlcGVuZGVuY2lhIGRlIGVycm9yZXMgRHVyYmluLVdhdHNvbiDigJMgTW9kZWxvIDEiLAogICAgbnVtX2NvbHMgPSBkcGx5cjo6d2hlcmUoaXMubnVtZXJpYykKICApCmBgYAoKYGBge3IgdmlmMX0KdmlmX3ZhbHMxIDwtIHZpZihtb2RlbG8xKQoKZGF0YS5mcmFtZSgKICBWYXJpYWJsZSAgICA9IG5hbWVzKHZpZl92YWxzMSksCiAgVklGICAgICAgICAgPSByb3VuZCh2aWZfdmFsczEsIDMpLAogIERpYWduw7NzdGljbyA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICB2aWZfdmFsczEgPCA1ICB+ICJTaW4gbXVsdGljb2xpbmVhbGlkYWQiLAogICAgdmlmX3ZhbHMxIDwgMTAgfiAiTXVsdGljb2xpbmVhbGlkYWQgbW9kZXJhZGEiLAogICAgVFJVRSAgICAgICAgICAgfiAiTXVsdGljb2xpbmVhbGlkYWQgZ3JhdmUiCiAgKSwKICBjaGVjay5uYW1lcyA9IEZBTFNFCikgJT4lCiAgbWlfdGFibGEoCiAgICB0aXR1bG8gICA9ICJGYWN0b3JlcyBkZSBJbmZsYWNpw7NuIGRlIFZhcmlhbnphIChWSUYpIOKAkyBNb2RlbG8gMSIsCiAgICBudW1fY29scyA9IGRwbHlyOjp3aGVyZShpcy5udW1lcmljKQogICkKYGBgCgpgYGB7ciBpbnRlcnByZXRhY2lvbi1zdXB1ZXN0b3MxfQojIEV4dHJhZXIgdmFsb3JlcyBwYXJhIGludGVycHJldGFjacOzbiBkaW7DoW1pY2EKc3cxX3AgIDwtIHN3MSRwLnZhbHVlCmtzMV9wICA8LSBrczEkcC52YWx1ZQpncTFfcCAgPC0gZ3ExJHAudmFsdWUKZHcxX2QgIDwtIGR3MSRzdGF0aXN0aWMKZHcxX3AgIDwtIGR3MSRwLnZhbHVlCnZpZl9tYXgxIDwtIG1heCh2aWZfdmFsczEpCnZpZl9taW4xIDwtIG1pbih2aWZfdmFsczEpCmBgYAoKKipJbnRlcnByZXRhY2nDs24gZGUgbG9zIHN1cHVlc3RvcyDigJMgTW9kZWxvIDE6KioKCioqMS4gTm9ybWFsaWRhZCBkZSBsb3MgcmVzaWR1YWxlczoqKgpMYSBwcnVlYmEgZGUgU2hhcGlyby1XaWxrIGFycm9qYSBXID0gYHIgcm91bmQoc3cxJHN0YXRpc3RpYywgNClgIGNvbiBwLXZhbG9yID0gYHIgZm9ybWF0KHN3MV9wLCBzY2llbnRpZmljID0gVFJVRSwgZGlnaXRzID0gMylgLCB5IGxhIHBydWViYSBkZSBLb2xtb2dvcm92LVNtaXJub3Ygb2J0aWVuZSBEID0gYHIgcm91bmQoa3MxJHN0YXRpc3RpYywgNClgIGNvbiBwLXZhbG9yID0gYHIgZm9ybWF0KGtzMV9wLCBzY2llbnRpZmljID0gVFJVRSwgZGlnaXRzID0gMylgLiBgciBpZihzdzFfcCA8IDAuMDUpICJBbWJhcyBwcnVlYmFzIHJlY2hhemFuIGxhIGhpcMOzdGVzaXMgbnVsYSBkZSBub3JtYWxpZGFkIChwIDwgMC4wNSksIGxvIHF1ZSBpbmRpY2EgcXVlIGxvcyByZXNpZHVhbGVzIGRlbCBtb2RlbG8gbm8gc2lndWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbC4gRXN0byBzZSBjb25maXJtYSB2aXN1YWxtZW50ZSBlbiBlbCBncsOhZmljbyBRLVEsIGRvbmRlIGxvcyBwdW50b3Mgc2UgZGVzdsOtYW4gZGUgbGEgbMOtbmVhIHRlw7NyaWNhIGVzcGVjaWFsbWVudGUgZW4gbGFzIGNvbGFzLiBMYSB2aW9sYWNpw7NuIGRlIGVzdGUgc3VwdWVzdG8gcHVlZGUgYWZlY3RhciBsYSB2YWxpZGV6IGRlIGxhcyBwcnVlYmFzIGRlIGhpcMOzdGVzaXMgZSBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YS4gQ29tbyBtZWRpZGEgY29ycmVjdGl2YSBzZSBzdWdpZXJlIGFwbGljYXIgdW5hIHRyYW5zZm9ybWFjacOzbiBsb2dhcsOtdG1pY2EgYWwgcHJlY2lvIChsb2cocHJlY2lvbSkpLCBxdWUgc3VlbGUgZXN0YWJpbGl6YXIgbGEgZGlzdHJpYnVjacOzbiBkZSBsb3MgcmVzaWR1YWxlcyBlbiBkYXRvcyBpbm1vYmlsaWFyaW9zIGNvbiBhbHRhIGFzaW1ldHLDrWEgcG9zaXRpdmEuIiBlbHNlICJObyBzZSByZWNoYXphIGxhIGhpcMOzdGVzaXMgbnVsYSBkZSBub3JtYWxpZGFkIGVuIG5pbmd1bmEgcHJ1ZWJhIChwID4gMC4wNSksIGxvIHF1ZSBpbmRpY2EgcXVlIGxvcyByZXNpZHVhbGVzIHNvbiBjb25zaXN0ZW50ZXMgY29uIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbC4gRXN0ZSBzdXB1ZXN0byBzZSBjdW1wbGUgc2F0aXNmYWN0b3JpYW1lbnRlLiJgIAoKKioyLiBIb21vY2VkYXN0aWNpZGFkICh2YXJpYW56YSBjb25zdGFudGUpOioqCkxhIHBydWViYSBkZSBHb2xkZmVsZC1RdWFuZHQgb2J0aWVuZSB1biBlc3RhZMOtc3RpY28gZGUgYHIgcm91bmQoZ3ExJHN0YXRpc3RpYywgNClgIGNvbiBwLXZhbG9yID0gYHIgZm9ybWF0KGdxMV9wLCBzY2llbnRpZmljID0gVFJVRSwgZGlnaXRzID0gMylgLiBgciBpZihncTFfcCA8IDAuMDUpICJTZSByZWNoYXphIGxhIGhpcMOzdGVzaXMgbnVsYSBkZSB2YXJpYW56YSBjb25zdGFudGUgKHAgPCAwLjA1KSwgbG8gcXVlIGluZGljYSBoZXRlcm9jZWRhc3RpY2lkYWQ6IGxhIHZhcmlhYmlsaWRhZCBkZSBsb3MgZXJyb3JlcyBubyBlcyB1bmlmb3JtZSBhIGxvIGxhcmdvIGRlIGxvcyB2YWxvcmVzIGFqdXN0YWRvcy4gRXN0byBwdWVkZSBvYnNlcnZhcnNlIGVuIGVsIGdyw6FmaWNvIFJlc2lkdWFscyB2cyBGaXR0ZWQsIGRvbmRlIGxhIGRpc3BlcnNpw7NuIGRlIGxvcyByZXNpZHVhbGVzIHRpZW5kZSBhIGNyZWNlciBjb24gbG9zIHZhbG9yZXMgcHJlZGljaG9zIG3DoXMgZ3JhbmRlcy4gQ29tbyBtZWRpZGEgY29ycmVjdGl2YSBzZSByZWNvbWllbmRhIHVzYXIgZXJyb3JlcyBlc3TDoW5kYXIgcm9idXN0b3MgKEhDKSBvIHRyYW5zZm9ybWFyIGxhIHZhcmlhYmxlIGRlcGVuZGllbnRlLiIgZWxzZSAiTm8gc2UgcmVjaGF6YSBsYSBoaXDDs3Rlc2lzIG51bGEgKHAgPiAwLjA1KTogbGEgdmFyaWFuemEgZGUgbG9zIGVycm9yZXMgZXMgY29uc3RhbnRlIGEgbG8gbGFyZ28gZGVsIHJhbmdvIGRlIHByZWRpY2Npw7NuLiBFbCBzdXB1ZXN0byBkZSBob21vY2VkYXN0aWNpZGFkIHNlIGN1bXBsZSBwYXJhIGVzdGUgbW9kZWxvLiJgIAoKKiozLiBJbmRlcGVuZGVuY2lhIGRlIGxvcyBlcnJvcmVzOioqCkVsIGVzdGFkw61zdGljbyBEdXJiaW4tV2F0c29uIGVzIERXID0gYHIgcm91bmQoZHcxX2QsIDQpYCBjb24gcC12YWxvciA9IGByIGZvcm1hdChkdzFfcCwgc2NpZW50aWZpYyA9IFRSVUUsIGRpZ2l0cyA9IDMpYC4gYHIgaWYoZHcxX3AgPCAwLjA1KSAiU2UgcmVjaGF6YSBsYSBoaXDDs3Rlc2lzIG51bGEgZGUgaW5kZXBlbmRlbmNpYSAocCA8IDAuMDUpLCBsbyBxdWUgc3VnaWVyZSBhdXRvY29ycmVsYWNpw7NuIGVuIGxvcyByZXNpZHVhbGVzLiBBdW5xdWUgbGEgYXV0b2NvcnJlbGFjacOzbiBlcyBtw6FzIGNvbcO6biBlbiBzZXJpZXMgZGUgdGllbXBvLCBlbiBkYXRvcyBkZSBjb3J0ZSB0cmFuc3ZlcnNhbCBjb21vIGVzdGUgcHVlZGUgaW5kaWNhciBkZXBlbmRlbmNpYSBlc3BhY2lhbDogbGFzIHZpdmllbmRhcyBjZXJjYW5hcyBlbnRyZSBzw60gdGllbmRlbiBhIHRlbmVyIHByZWNpb3Mgc2ltaWxhcmVzIG5vIGV4cGxpY2Fkb3MgcG9yIGxhcyB2YXJpYWJsZXMgZGVsIG1vZGVsby4gQ29tbyBtZWRpZGEgY29ycmVjdGl2YSBzZSBzdWdpZXJlIGV4cGxvcmFyIG1vZGVsb3MgZGUgcmVncmVzacOzbiBlc3BhY2lhbCBvIGluY2x1aXIgdmFyaWFibGVzIGRlIHViaWNhY2nDs24gbcOhcyBncmFudWxhcmVzIChiYXJyaW8sIGNvb3JkZW5hZGFzKS4iIGVsc2UgIk5vIHNlIHJlY2hhemEgbGEgaGlww7N0ZXNpcyBudWxhIChwID4gMC4wNSk6IGxvcyBlcnJvcmVzIHNvbiBpbmRlcGVuZGllbnRlcyBlbnRyZSBzw60uIEVsIHN1cHVlc3RvIGRlIGluZGVwZW5kZW5jaWEgc2UgY3VtcGxlIHNhdGlzZmFjdG9yaWFtZW50ZS4iYCAKCioqNC4gTXVsdGljb2xpbmVhbGlkYWQ6KioKTG9zIFZJRiBkZSB0b2RhcyBsYXMgdmFyaWFibGVzIHByZWRpY3RvcmFzIHNlIGVuY3VlbnRyYW4gZW50cmUgYHIgcm91bmQodmlmX21pbjEsIDIpYCB5IGByIHJvdW5kKHZpZl9tYXgxLCAyKWAuIGByIGlmKHZpZl9tYXgxIDwgNSkgIlRvZG9zIGxvcyB2YWxvcmVzIHNvbiBpbmZlcmlvcmVzIGEgNSwgbG8gcXVlIGluZGljYSBhdXNlbmNpYSBkZSBtdWx0aWNvbGluZWFsaWRhZCBzaWduaWZpY2F0aXZhLiBDYWRhIHZhcmlhYmxlIGFwb3J0YSBpbmZvcm1hY2nDs24gZ2VudWluYW1lbnRlIGluZGVwZW5kaWVudGUgYWwgbW9kZWxvLCBwb3IgbG8gcXVlIGxvcyBjb2VmaWNpZW50ZXMgZXN0aW1hZG9zIHNvbiBlc3RhYmxlcyB5IGNvbmZpYWJsZXMuIiBlbHNlIGlmKHZpZl9tYXgxIDwgMTApICJBbGd1bm9zIFZJRiBzdXBlcmFuIDUsIGxvIHF1ZSBpbmRpY2EgbXVsdGljb2xpbmVhbGlkYWQgbW9kZXJhZGEuIExhcyB2YXJpYWJsZXMgYWZlY3RhZGFzIGNvbXBhcnRlbiBpbmZvcm1hY2nDs24gcmVkdW5kYW50ZSwgbG8gcXVlIGluZmxhIHN1cyBlcnJvcmVzIGVzdMOhbmRhciB5IHB1ZWRlIGRpZmljdWx0YXIgbGEgaW50ZXJwcmV0YWNpw7NuIGluZGl2aWR1YWwgZGUgc3VzIGNvZWZpY2llbnRlcy4gU2Ugc3VnaWVyZSBjb25zaWRlcmFyIGxhIGVsaW1pbmFjacOzbiBkZSBsYSB2YXJpYWJsZSBjb24gbWF5b3IgVklGIG8gYXBsaWNhciBQQ0EuIiBlbHNlICJFeGlzdGVuIFZJRiBzdXBlcmlvcmVzIGEgMTAsIGxvIHF1ZSBpbmRpY2EgbXVsdGljb2xpbmVhbGlkYWQgZ3JhdmUuIFNlIHJlY29taWVuZGEgZWxpbWluYXIgdmFyaWFibGVzIHJlZHVuZGFudGVzLCBjcmVhciDDrW5kaWNlcyBjb21wdWVzdG9zIG8gYXBsaWNhciByZWdyZXNpw7NuIFJpZGdlL0xhc3NvIHBhcmEgZXN0YWJpbGl6YXIgbGFzIGVzdGltYWNpb25lcy4iYCAKCiMjIyBQcmVkaWNjacOzbiDigJMgVml2aWVuZGEgMQoKQ29uIGVsIG1vZGVsbyBlc3RpbWFkbyBzZSByZWFsaXrDsyBsYSBwcmVkaWNjacOzbiBwdW50dWFsIGRlbCBwcmVjaW8gcGFyYSB1bmEgY2FzYSBjb24gbGFzIGNhcmFjdGVyw61zdGljYXMgZGUgbGEgcHJpbWVyYSBzb2xpY2l0dWQgKGVzdHJhdG8gNCwgY29tbyB2YWxvciBkZSByZWZlcmVuY2lhIGRlbnRybyBkZWwgcmFuZ28gNC01KS4gU2UgaW5jbHV5ZSBlbCBpbnRlcnZhbG8gZGUgcHJlZGljY2nDs24gYWwgOTUlLgoKYGBge3IgcHJlZGljY2lvbjF9CnZpdmllbmRhMSA8LSBkYXRhLmZyYW1lKAogIGFyZWFjb25zdCAgICA9IDIwMCwKICBlc3RyYXRvICAgICAgPSA0LAogIGhhYml0YWNpb25lcyA9IDQsCiAgcGFycXVlYWRlcm9zID0gMSwKICBiYW5pb3MgICAgICAgPSAyCikKCnByZWQxIDwtIHByZWRpY3QobW9kZWxvMSwKICAgICAgICAgICAgICAgICBuZXdkYXRhICA9IHZpdmllbmRhMSwKICAgICAgICAgICAgICAgICBpbnRlcnZhbCA9ICJwcmVkaWN0aW9uIiwKICAgICAgICAgICAgICAgICBsZXZlbCAgICA9IDAuOTUpCgpkYXRhLmZyYW1lKAogIENhcmFjdGVyw61zdGljYSA9IGMoIsOBcmVhIChtwrIpIiwgIkVzdHJhdG8iLCAiSGFiaXRhY2lvbmVzIiwKICAgICAgICAgICAgICAgICAgICAgIlBhcnF1ZWFkZXJvcyIsICJCYcOxb3MiLAogICAgICAgICAgICAgICAgICAgICAiUHJlY2lvIGVzdGltYWRvIChNIENPUCkiLAogICAgICAgICAgICAgICAgICAgICAiTMOtbWl0ZSBpbmZlcmlvciA5NSUgKE0gQ09QKSIsCiAgICAgICAgICAgICAgICAgICAgICJMw61taXRlIHN1cGVyaW9yIDk1JSAoTSBDT1ApIiksCiAgVmFsb3IgPSBjKDIwMCwgNCwgNCwgMSwgMiwKICAgICAgICAgICAgcm91bmQocHJlZDFbMV0sIDEpLAogICAgICAgICAgICByb3VuZChwcmVkMVsyXSwgMSksCiAgICAgICAgICAgIHJvdW5kKHByZWQxWzNdLCAxKSksCiAgY2hlY2submFtZXMgPSBGQUxTRQopICU+JQogIG1pX3RhYmxhKAogICAgdGl0dWxvICAgPSAiUHJlZGljY2nDs24gZGVsIHByZWNpbyDigJMgVml2aWVuZGEgMSIsCiAgICBudW1fY29scyA9IGRwbHlyOjp3aGVyZShpcy5udW1lcmljKQogICkKYGBgCgoqKkludGVycHJldGFjacOzbiBkZSBsYSBwcmVkaWNjacOzbjoqKgoKRWwgbW9kZWxvIGVzdGltYSBxdWUgZWwgcHJlY2lvIGVzcGVyYWRvIGRlIHVuYSBjYXNhIGNvbiAyMDAgbcKyIGRlIMOhcmVhIGNvbnN0cnVpZGEsIGVzdHJhdG8gNCwgNCBoYWJpdGFjaW9uZXMsIDEgcGFycXVlYWRlcm8geSAyIGJhw7FvcyBlbiBsYSBab25hIE5vcnRlIGRlIENhbGkgZXMgZGUgYXByb3hpbWFkYW1lbnRlICoqYHIgcm91bmQocHJlZDFbMV0sIDEpYCBtaWxsb25lcyBkZSBwZXNvcyoqLiBFbCBpbnRlcnZhbG8gZGUgcHJlZGljY2nDs24gYWwgOTUlIHNlIHViaWNhIGVudHJlICoqYHIgcm91bmQocHJlZDFbMl0sIDEpYCoqIHkgKipgciByb3VuZChwcmVkMVszXSwgMSlgIG1pbGxvbmVzIGRlIHBlc29zKiosIGxvIHF1ZSBpbmRpY2EgZWwgcmFuZ28gcGxhdXNpYmxlIGRlbCBwcmVjaW8gZGUgbWVyY2FkbyBwYXJhIHVuYSB2aXZpZW5kYSBpbmRpdmlkdWFsIGNvbiBlc3RhcyBjYXJhY3RlcsOtc3RpY2FzLgoKYHIgaWYocHJlZDFbMV0gPD0gMzUwKSBwYXN0ZTAoIkVsIHByZWNpbyBlc3RpbWFkbyBkZSAiLCByb3VuZChwcmVkMVsxXSwgMSksICIgbWlsbG9uZXMgZXMgKippbmZlcmlvciBhbCBjcsOpZGl0byBwcmVhcHJvYmFkbyBkZSAzNTAgbWlsbG9uZXMqKiwgbG8gcXVlIGNvbmZpcm1hIHF1ZSBlcyB2aWFibGUgZW5jb250cmFyIG9wY2lvbmVzIHF1ZSBzYXRpc2ZhZ2FuIGVzdGEgc29saWNpdHVkIGRlbnRybyBkZWwgcHJlc3VwdWVzdG8gZGlzcG9uaWJsZS4iKSBlbHNlIHBhc3RlMCgiRWwgcHJlY2lvIGVzdGltYWRvIGRlICIsIHJvdW5kKHByZWQxWzFdLCAxKSwgIiBtaWxsb25lcyAqKnN1cGVyYSBlbCBjcsOpZGl0byBwcmVhcHJvYmFkbyBkZSAzNTAgbWlsbG9uZXMqKi4gRXN0byBzdWdpZXJlIHF1ZSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBzb2xpY2l0YWRhcyAoMjAwIG3CsiwgZXN0cmF0byA0LCA0IGhhYml0YWNpb25lcykgcHVlZGVuIHNlciBkaWbDrWNpbGVzIGRlIGVuY29udHJhciBkZW50cm8gZGVsIHByZXN1cHVlc3RvLiBTZSByZWNvbWllbmRhIGZsZXhpYmlsaXphciBhbGd1bmEgZGUgbGFzIGNvbmRpY2lvbmVzLCBwb3IgZWplbXBsbyByZWR1Y2lyIGVsIMOhcmVhIG9iamV0aXZvIG8gY29uc2lkZXJhciBlc3RyYXRvIDMuIilgCgojIyMgT2ZlcnRhcyBwb3RlbmNpYWxlcyDigJMgVml2aWVuZGEgMQoKU2UgZmlsdHJhcm9uIGxhcyBvZmVydGFzIGRpc3BvbmlibGVzIGVuIGJhc2UxIHF1ZSBzYXRpc2ZhY2VuIGxhcyBjb25kaWNpb25lcyBkZSBsYSBzb2xpY2l0dWQgeSBzZSB1YmljYW4gZGVudHJvIGRlbCBwcmVzdXB1ZXN0byBkZSAzNTAgbWlsbG9uZXMgZGUgcGVzb3MuIExhcyBvZmVydGFzIHNlIG9yZGVuYXJvbiBwb3IgcHJveGltaWRhZCBhbCDDoXJlYSBzb2xpY2l0YWRhICgyMDAgbcKyKS4KCmBgYHtyIG9mZXJ0YXMxfQpvZmVydGFzMSA8LSBiYXNlMSAlPiUKICBmaWx0ZXIoCiAgICBwcmVjaW9tICAgICAgPD0gMzUwLAogICAgaGFiaXRhY2lvbmVzID49IDMsCiAgICBiYW5pb3MgICAgICAgPj0gMiwKICAgIHBhcnF1ZWFkZXJvcyA+PSAxLAogICAgZXN0cmF0byAgICAgICVpbiUgYyg0LCA1KQogICkgJT4lCiAgYXJyYW5nZShhYnMoYXJlYWNvbnN0IC0gMjAwKSkgJT4lCiAgaGVhZCgxMCkKCmNhdCgiT2ZlcnRhcyBwb3RlbmNpYWxlcyBlbmNvbnRyYWRhczoiLCBucm93KG9mZXJ0YXMxKSwgIlxuIikKCm9mZXJ0YXMxICU+JQogIHNlbGVjdChiYXJyaW8sIHpvbmEsIGVzdHJhdG8sIHByZWNpb20sIGFyZWFjb25zdCwKICAgICAgICAgaGFiaXRhY2lvbmVzLCBiYW5pb3MsIHBhcnF1ZWFkZXJvcykgJT4lCiAgbWlfdGFibGEoCiAgICB0aXR1bG8gICA9ICJPZmVydGFzIHBvdGVuY2lhbGVzIOKAkyBWaXZpZW5kYSAxICjiiaQgJDM1MCBNLCBlc3RyYXRvIDQtNSkiLAogICAgbnVtX2NvbHMgPSBkcGx5cjo6d2hlcmUoaXMubnVtZXJpYykKICApCmBgYAoKYGBge3IgbWFwYS1vZmVydGFzMX0KbWFwYV9vZmVydGFzMSA8LSBvZmVydGFzMSAlPiUKICBmaWx0ZXIoIWlzLm5hKGxvbmdpdHVkKSwgIWlzLm5hKGxhdGl0dWQpKSAlPiUKICBoZWFkKDUpCgptYXBhX29mMSA8LSBsZWFmbGV0KGRhdGEgPSBtYXBhX29mZXJ0YXMxKSAlPiUKICBhZGRUaWxlcygpICU+JQogIGFkZENpcmNsZU1hcmtlcnMoCiAgICBsbmcgICAgPSB+bG9uZ2l0dWQsCiAgICBsYXQgICAgPSB+bGF0aXR1ZCwKICAgIGNvbG9yICA9ICJkYXJrZ3JlZW4iLAogICAgcmFkaXVzID0gMTAsCiAgICBwb3B1cCAgPSB+cGFzdGUwKAogICAgICAiPGI+QmFycmlvOjwvYj4gIiwgYmFycmlvLCAiPGJyPiIsCiAgICAgICI8Yj5QcmVjaW86PC9iPiAkIiwgcHJlY2lvbSwgIiBNPGJyPiIsCiAgICAgICI8Yj7DgXJlYTo8L2I+ICIsIGFyZWFjb25zdCwgIiBtwrI8YnI+IiwKICAgICAgIjxiPkhhYml0YWNpb25lczo8L2I+ICIsIGhhYml0YWNpb25lcywgIjxicj4iLAogICAgICAiPGI+QmHDsW9zOjwvYj4gIiwgYmFuaW9zLCAiPGJyPiIsCiAgICAgICI8Yj5QYXJxdWVhZGVyb3M6PC9iPiAiLCBwYXJxdWVhZGVyb3MsICI8YnI+IiwKICAgICAgIjxiPkVzdHJhdG86PC9iPiAiLCBlc3RyYXRvCiAgICApLAogICAgbGFiZWwgID0gfnBhc3RlMCgiJCIsIHByZWNpb20sICJNIOKAkyAiLCBiYXJyaW8pCiAgKSAlPiUKICBhZGRMZWdlbmQoImJvdHRvbXJpZ2h0IiwgY29sb3JzID0gImRhcmtncmVlbiIsCiAgICAgICAgICAgIGxhYmVscyA9ICJPZmVydGFzIOKJpCAkMzUwIE0iLCB0aXRsZSA9ICJWaXZpZW5kYSAxIikKCmh0bWx0b29sczo6dGFnTGlzdChtYXBhX29mMSkKLkZJR19OIDwtIC5GSUdfTiArIDEKa25pdHI6OmFzaXNfb3V0cHV0KHNwcmludGYoCiAgJzxkaXYgaWQ9Im1hcGFfb2ZlcnRhczEiIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlcjsgbWFyZ2luLXRvcDo2cHg7Ij4KICAgPHN0cm9uZz5GaWd1cmEgJWQuPC9zdHJvbmc+IE1hcGEgZGUgbGFzIDUgbWVqb3JlcyBvZmVydGFzIHBvdGVuY2lhbGVzIOKAkyBWaXZpZW5kYSAxCiAgIDwvZGl2PicsIC5GSUdfTgopKQpgYGAKCioqQW7DoWxpc2lzIGRlIGxhcyBvZmVydGFzOioqCgpMYXMgYHIgbnJvdyhtYXBhX29mZXJ0YXMxKWAgcHJvcGllZGFkZXMgcHJlc2VudGFkYXMgZW4gZWwgbWFwYSBjdW1wbGVuIHNpbXVsdMOhbmVhbWVudGUgY29uIGVsIHByZXN1cHVlc3RvIGRlICQzNTAgbWlsbG9uZXMsIGVzdHJhdG8gNCBvIDUsIFpvbmEgTm9ydGUsIHkgbG9zIHJlcXVpc2l0b3MgbcOtbmltb3MgZGUgaGFiaXRhY2lvbmVzLCBiYcOxb3MgeSBwYXJxdWVhZGVyb3MuIFNlIHJlY29taWVuZGEgYSBNYXLDrWEgcHJpb3JpemFyIGxhcyBkZSBtYXlvciDDoXJlYSBjb25zdHJ1aWRhIGRlbnRybyBkZWwgcHJlc3VwdWVzdG8gZGlzcG9uaWJsZSwgdmVyaWZpY2FyIGVsIGVzdGFkbyBkZSBjb25zZXJ2YWNpw7NuIGRlIGNhZGEgaW5tdWVibGUsIGV2YWx1YXIgbGEgYWNjZXNpYmlsaWRhZCB2aWFsIGRlbCBzZWN0b3IgeSBjb25zdWx0YXIgZWwgYXZhbMO6byBjYXRhc3RyYWwgYWN0dWFsaXphZG8gYW50ZXMgZGUgZm9ybXVsYXIgdW5hIG9mZXJ0YSBhbCBjbGllbnRlLgoKLS0tCgojIyAqKlNvbGljaXR1ZCAyOiBBcGFydGFtZW50byB6b25hIHN1cioqCgojIyMgRmlsdHJvIGluaWNpYWwgeSBkZXB1cmFjacOzbgoKU2UgcmVhbGl6w7MgdW4gZmlsdHJvIHNvYnJlIGxhIGJhc2UgYHZpdmllbmRhYCBzZWxlY2Npb25hbmRvIMO6bmljYW1lbnRlIGxvcyByZWdpc3Ryb3MgY29ycmVzcG9uZGllbnRlcyBhICoqYXBhcnRhbWVudG9zKiogZW4gbGEgKipab25hIFN1cioqIGRlIENhbGksIGNvbiBlbCBtaXNtbyBwcm9jZWRpbWllbnRvIGRlIHZlcmlmaWNhY2nDs24gZGUgY2FsaWRhZCBhcGxpY2FkbyBlbiBsYSBzb2xpY2l0dWQgMS4KCmBgYHtyIGZpbHRyby1iYXNlMn0KYmFzZTIgPC0gdml2aWVuZGEgJT4lCiAgZmlsdGVyKHRpcG8gPT0gIkFwYXJ0YW1lbnRvIiwgem9uYSA9PSAiWm9uYSBTdXIiKQoKY2F0KCJSZWdpc3Ryb3MgZW4gYmFzZTI6IiwgbnJvdyhiYXNlMiksICJcbiIpCmNhdCgiVmFsb3JlcyBmYWx0YW50ZXMgcG9yIHZhcmlhYmxlOlxuIikKcHJpbnQoY29sU3Vtcyhpcy5uYShiYXNlMikpKQpjYXQoIlxuUmVnaXN0cm9zIGR1cGxpY2Fkb3M6Iiwgc3VtKGR1cGxpY2F0ZWQoYmFzZTIpKSwgIlxuIikKYGBgCgpgYGB7ciBwcmltZXJvcy1yZWdpc3Ryb3MyfQpiYXNlMiAlPiUKICBoZWFkKDMpICU+JQogIG1pX3RhYmxhKHRpdHVsbyA9ICJQcmltZXJvcyAzIHJlZ2lzdHJvcyDigJMgQXBhcnRhbWVudG9zIFpvbmEgU3VyIikKYGBgCgpgYGB7ciB2ZXJpZmljYWNpb24tYmFzZTJ9CmJhc2UyICU+JQogIGNvdW50KHRpcG8sIG5hbWUgPSAibiIpICU+JQogIG1pX3RhYmxhKHRpdHVsbyA9ICJWZXJpZmljYWNpw7NuOiB0aXBvIGRlIGlubXVlYmxlIGVuIGJhc2UyIikKCmJhc2UyICU+JQogIGNvdW50KHpvbmEsIG5hbWUgPSAibiIpICU+JQogIG1pX3RhYmxhKHRpdHVsbyA9ICJWZXJpZmljYWNpw7NuOiB6b25hIGVuIGJhc2UyIikKCmJhc2UyICU+JQogIGNvdW50KGVzdHJhdG8sIG5hbWUgPSAibiIpICU+JQogIGFycmFuZ2UoZXN0cmF0bykgJT4lCiAgbWlfdGFibGEodGl0dWxvID0gIkRpc3RyaWJ1Y2nDs24gcG9yIGVzdHJhdG8g4oCTIEFwYXJ0YW1lbnRvcyBab25hIFN1ciIpCmBgYAoKKipJbnRlcnByZXRhY2nDs24gZGVsIGZpbHRybzoqKiBMYSBiYXNlMiBjb250aWVuZSDDum5pY2FtZW50ZSBhcGFydGFtZW50b3MgZGUgbGEgWm9uYSBTdXIsIGNvbmZpcm1hZG8gcG9yIGxhcyB0YWJsYXMgZGUgdmVyaWZpY2FjacOzbi4gU2UgYXByZWNpYSBxdWUgbG9zIHJlZ2lzdHJvcyBzZSBjb25jZW50cmFuIGVuIGVzdHJhdG9zIDQsIDUgeSA2LCBjb2hlcmVudGUgY29uIGVsIHBlcmZpbCBzb2Npb2Vjb27Ds21pY28gZGUgbGEgem9uYSBzdXIgZGUgQ2FsaS4gTG9zIHZhbG9yZXMgZmFsdGFudGVzIHkgZHVwbGljYWRvcyBkZXRlY3RhZG9zIHNvbiBjb25zaWRlcmFkb3MgZW4gbGEgZXRhcGEgZGUgbW9kZWxhY2nDs24uCgpgYGB7ciBtYXBhLWJhc2UyfQptYXBhX2Jhc2UyIDwtIGxlYWZsZXQoZGF0YSA9IGJhc2UyKSAlPiUKICBhZGRUaWxlcygpICU+JQogIGFkZENpcmNsZU1hcmtlcnMoCiAgICBsbmcgICAgPSB+bG9uZ2l0dWQsCiAgICBsYXQgICAgPSB+bGF0aXR1ZCwKICAgIGNvbG9yICA9ICJkYXJrb3JhbmdlIiwKICAgIHJhZGl1cyA9IDUsCiAgICBwb3B1cCAgPSB+cGFzdGUwKAogICAgICAiPGI+QmFycmlvOjwvYj4gIiwgYmFycmlvLCAiPGJyPiIsCiAgICAgICI8Yj5QcmVjaW86PC9iPiAkIiwgcHJlY2lvbSwgIiBNPGJyPiIsCiAgICAgICI8Yj7DgXJlYTo8L2I+ICIsIGFyZWFjb25zdCwgIiBtwrI8YnI+IiwKICAgICAgIjxiPkVzdHJhdG86PC9iPiAiLCBlc3RyYXRvCiAgICApCiAgKSAlPiUKICBhZGRMZWdlbmQoImJvdHRvbXJpZ2h0IiwgY29sb3JzID0gImRhcmtvcmFuZ2UiLAogICAgICAgICAgICBsYWJlbHMgPSAiQXBhcnRhbWVudG9zIC0gWm9uYSBTdXIiLCB0aXRsZSA9ICJiYXNlMiIpCgpodG1sdG9vbHM6OnRhZ0xpc3QobWFwYV9iYXNlMikKLkZJR19OIDwtIC5GSUdfTiArIDEKa25pdHI6OmFzaXNfb3V0cHV0KHNwcmludGYoCiAgJzxkaXYgaWQ9Im1hcGFfYmFzZTIiIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlcjsgbWFyZ2luLXRvcDo2cHg7Ij4KICAgPHN0cm9uZz5GaWd1cmEgJWQuPC9zdHJvbmc+IFViaWNhY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbG9zIGFwYXJ0YW1lbnRvcyBlbiBab25hIFN1ciBkZSBDYWxpCiAgIDwvZGl2PicsIC5GSUdfTgopKQpgYGAKCioqQW7DoWxpc2lzIGRlbCBtYXBhOioqIEFsIGlndWFsIHF1ZSBlbiBsYSBzb2xpY2l0dWQgMSwgcHVlZGVuIHByZXNlbnRhcnNlIHB1bnRvcyBmdWVyYSBkZWwgw6FyZWEgc3VyIHBvciBhdXRvY2xhc2lmaWNhY2nDs24gZGVsIG9mZXJlbnRlIG8gbMOtbWl0ZXMgZGUgem9uYSBubyBlc3RyaWN0YW1lbnRlIGRlbGltaXRhZG9zIGVuIGxhIGJhc2UgZGUgZGF0b3MuIFNlIHJlY29taWVuZGEgdmFsaWRhciBjb24gaGVycmFtaWVudGFzIFNJRyBwYXJhIGFuw6FsaXNpcyBtw6FzIHJpZ3Vyb3Nvcy4KCiMjIyBBbsOhbGlzaXMgZXhwbG9yYXRvcmlvCgpgYGB7ciBlZGEtcmVzdW1lbjJ9CmJhc2UyICU+JQogIHNlbGVjdChwcmVjaW9tLCBhcmVhY29uc3QsIGVzdHJhdG8sIGhhYml0YWNpb25lcywgcGFycXVlYWRlcm9zLCBiYW5pb3MpICU+JQogIHN1bW1hcnkoKSAlPiUKICBwcmludCgpCmBgYAoKYGBge3IgZWRhLWNvcnJlbGFjaW9uMn0KdmFyc19udW0yIDwtIGJhc2UyICU+JQogIHNlbGVjdChwcmVjaW9tLCBhcmVhY29uc3QsIGVzdHJhdG8sIGJhbmlvcywgaGFiaXRhY2lvbmVzLCBwYXJxdWVhZGVyb3MpCgpwX3BhaXJzMiA8LSBnZ3BhaXJzKAogIHZhcnNfbnVtMiwKICB0aXRsZSA9ICJNYXRyaXogZGUgY29ycmVsYWNpb25lcyDigJMgQXBhcnRhbWVudG9zIFpvbmEgU3VyIiwKICBsb3dlciA9IGxpc3QoY29udGludW91cyA9IHdyYXAoInNtb290aCIsIGFscGhhID0gMC4zLCBjb2xvciA9ICJkYXJrb3JhbmdlIikpLAogIGRpYWcgID0gbGlzdChjb250aW51b3VzID0gd3JhcCgiZGVuc2l0eURpYWciLCBmaWxsID0gImRhcmtvcmFuZ2UiLCBhbHBoYSA9IDAuNCkpLAogIHVwcGVyID0gbGlzdChjb250aW51b3VzID0gd3JhcCgiY29yIiwgc2l6ZSA9IDMuNSkpCikgKyB0aGVtZV9taW5pbWFsKCkKCm1pX2ZpZ3VyYSgKICBwbG90ICAgPSBwX3BhaXJzMiwKICBpZCAgICAgPSAiY29ycmVsYWNpb25fYmFzZTIiLAogIHRpdHVsbyA9ICJNYXRyaXogZGUgY29ycmVsYWNpb25lcyDigJMgQXBhcnRhbWVudG9zIFpvbmEgU3VyIgopCmBgYAoKYGBge3IgcGxvdGx5LXByZWNpby1hcmVhMn0KcDQgPC0gcGxvdF9seShiYXNlMiwKICAgICAgICAgICAgICB4ID0gfmFyZWFjb25zdCwgeSA9IH5wcmVjaW9tLAogICAgICAgICAgICAgIGNvbG9yID0gfmZhY3Rvcihlc3RyYXRvKSwgY29sb3JzID0gIk9yYW5nZXMiLAogICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIsCiAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChzaXplID0gOCwgb3BhY2l0eSA9IDAuNyksCiAgICAgICAgICAgICAgdGV4dCA9IH5wYXN0ZSgiQmFycmlvOiIsIGJhcnJpbywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+UHJlY2lvOiAkIiwgcHJlY2lvbSwgIk0iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj7DgXJlYToiLCBhcmVhY29uc3QsICJtwrIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5Fc3RyYXRvOiIsIGVzdHJhdG8pKSAlPiUKICBsYXlvdXQoCiAgICB0aXRsZSAgPSAiUHJlY2lvIHZzIMOBcmVhIGNvbnN0cnVpZGEg4oCTIEFwYXJ0YW1lbnRvcyBab25hIFN1ciIsCiAgICB4YXhpcyAgPSBsaXN0KHRpdGxlID0gIsOBcmVhIGNvbnN0cnVpZGEgKG3CsikiKSwKICAgIHlheGlzICA9IGxpc3QodGl0bGUgPSAiUHJlY2lvIChtaWxsb25lcyBDT1ApIiksCiAgICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gbGlzdCh0ZXh0ID0gIkVzdHJhdG8iKSkKICApCgpodG1sdG9vbHM6OnRhZ0xpc3QocDQpCi5GSUdfTiA8LSAuRklHX04gKyAxCmtuaXRyOjphc2lzX291dHB1dChzcHJpbnRmKAogICc8ZGl2IGlkPSJwcmVjaW9fYXJlYTIiIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlcjsgbWFyZ2luLXRvcDo2cHg7Ij4KICAgPHN0cm9uZz5GaWd1cmEgJWQuPC9zdHJvbmc+IFByZWNpbyB2cyDDgXJlYSBjb25zdHJ1aWRhIOKAkyBBcGFydGFtZW50b3MgWm9uYSBTdXIgKGludGVyYWN0aXZvKQogICA8L2Rpdj4nLCAuRklHX04KKSkKYGBgCgpgYGB7ciBwbG90bHktcHJlY2lvLWhhYml0YWNpb25lczJ9CnA1YiA8LSBwbG90X2x5KGJhc2UyLAogICAgICAgICAgICAgICB4ID0gfmhhYml0YWNpb25lcywgeSA9IH5wcmVjaW9tLAogICAgICAgICAgICAgICBjb2xvciA9IH5mYWN0b3IoZXN0cmF0byksIGNvbG9ycyA9ICJTZXQzIiwKICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIiwKICAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChzaXplID0gOCwgb3BhY2l0eSA9IDAuNyksCiAgICAgICAgICAgICAgIHRleHQgPSB+cGFzdGUoIkJhcnJpbzoiLCBiYXJyaW8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5QcmVjaW86ICQiLCBwcmVjaW9tLCAiTSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5IYWJpdGFjaW9uZXM6IiwgaGFiaXRhY2lvbmVzKSkgJT4lCiAgbGF5b3V0KAogICAgdGl0bGUgID0gIlByZWNpbyB2cyBOw7ptZXJvIGRlIGhhYml0YWNpb25lcyDigJMgQXBhcnRhbWVudG9zIFpvbmEgU3VyIiwKICAgIHhheGlzICA9IGxpc3QodGl0bGUgPSAiSGFiaXRhY2lvbmVzIiksCiAgICB5YXhpcyAgPSBsaXN0KHRpdGxlID0gIlByZWNpbyAobWlsbG9uZXMgQ09QKSIpLAogICAgbGVnZW5kID0gbGlzdCh0aXRsZSA9IGxpc3QodGV4dCA9ICJFc3RyYXRvIikpCiAgKQoKaHRtbHRvb2xzOjp0YWdMaXN0KHA1YikKLkZJR19OIDwtIC5GSUdfTiArIDEKa25pdHI6OmFzaXNfb3V0cHV0KHNwcmludGYoCiAgJzxkaXYgaWQ9InByZWNpb19oYWJpdGFjaW9uZXMyIiBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXI7IG1hcmdpbi10b3A6NnB4OyI+CiAgIDxzdHJvbmc+RmlndXJhICVkLjwvc3Ryb25nPiBQcmVjaW8gdnMgTsO6bWVybyBkZSBoYWJpdGFjaW9uZXMg4oCTIEFwYXJ0YW1lbnRvcyBab25hIFN1ciAoaW50ZXJhY3Rpdm8pCiAgIDwvZGl2PicsIC5GSUdfTgopKQpgYGAKCmBgYHtyIHBsb3RseS1ib3hwbG90LWVzdHJhdG8yfQpwNSA8LSBwbG90X2x5KGJhc2UyLAogICAgICAgICAgICAgIHggPSB+ZmFjdG9yKGVzdHJhdG8pLCB5ID0gfnByZWNpb20sCiAgICAgICAgICAgICAgdHlwZSAgPSAiYm94IiwKICAgICAgICAgICAgICBjb2xvciA9IH5mYWN0b3IoZXN0cmF0byksIGNvbG9ycyA9ICJPcmFuZ2VzIikgJT4lCiAgbGF5b3V0KAogICAgdGl0bGUgICAgICA9ICJEaXN0cmlidWNpw7NuIGRlbCBwcmVjaW8gcG9yIGVzdHJhdG8g4oCTIEFwYXJ0YW1lbnRvcyBab25hIFN1ciIsCiAgICB4YXhpcyAgICAgID0gbGlzdCh0aXRsZSA9ICJFc3RyYXRvIiksCiAgICB5YXhpcyAgICAgID0gbGlzdCh0aXRsZSA9ICJQcmVjaW8gKG1pbGxvbmVzIENPUCkiKSwKICAgIHNob3dsZWdlbmQgPSBGQUxTRQogICkKCmh0bWx0b29sczo6dGFnTGlzdChwNSkKLkZJR19OIDwtIC5GSUdfTiArIDEKa25pdHI6OmFzaXNfb3V0cHV0KHNwcmludGYoCiAgJzxkaXYgaWQ9ImJveHBsb3RfZXN0cmF0bzIiIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlcjsgbWFyZ2luLXRvcDo2cHg7Ij4KICAgPHN0cm9uZz5GaWd1cmEgJWQuPC9zdHJvbmc+IERpc3RyaWJ1Y2nDs24gZGVsIHByZWNpbyBwb3IgZXN0cmF0byDigJMgQXBhcnRhbWVudG9zIFpvbmEgU3VyIChpbnRlcmFjdGl2bykKICAgPC9kaXY+JywgLkZJR19OCikpCmBgYAoKYGBge3IgY29ycmVsYWNpb24tbnVtZXJpY2EyfQpjb3JfbWF0MiA8LSBjb3IodmFyc19udW0yLCB1c2UgPSAiY29tcGxldGUub2JzIikKcm91bmQoY29yX21hdDIsIDMpICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUKICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiVmFyaWFibGUiKSAlPiUKICBtaV90YWJsYSgKICAgIHRpdHVsbyA9ICJNYXRyaXogZGUgY29ycmVsYWNpb25lcyBkZSBQZWFyc29uIOKAkyBBcGFydGFtZW50b3MgWm9uYSBTdXIiLAogICAgZGlnaXRzID0gMwogICkKYGBgCgoqKkludGVycHJldGFjacOzbiBkZWwgYW7DoWxpc2lzIGV4cGxvcmF0b3JpbyDigJMgU29saWNpdHVkIDI6KioKCkVsIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgbG9zIGFwYXJ0YW1lbnRvcyBkZSBsYSBab25hIFN1ciBtdWVzdHJhIHBhdHJvbmVzIHNpbWlsYXJlcyBhIGxvcyBvYnNlcnZhZG9zIGVuIGxhIHNvbGljaXR1ZCAxLCBwZXJvIGNvbiBhbGd1bmFzIHBhcnRpY3VsYXJpZGFkZXMgcHJvcGlhcyBkZSBlc3RlIHNlZ21lbnRvOgoKLSAqKsOBcmVhIGNvbnN0cnVpZGEgdnMuIHByZWNpbzoqKiBMYSByZWxhY2nDs24gcG9zaXRpdmEgZW50cmUgw6FyZWEgeSBwcmVjaW8gZXMgbGEgbcOhcyBwcm9udW5jaWFkYSBkZWwgY29uanVudG8sIGNvbiBtYXlvciB2YXJpYWJpbGlkYWQgZW4gZWwgZXh0cmVtbyBzdXBlcmlvciAoYXBhcnRhbWVudG9zIGRlIGdyYW4gdGFtYcOxbyB5IGFsdG8gcHJlY2lvKS4gRXN0byBzdWdpZXJlIHF1ZSBlbiBsYSBab25hIFN1ciwgZWwgcHJlY2lvIHBvciBtZXRybyBjdWFkcmFkbyB2YXLDrWEgbcOhcyBxdWUgZW4gbGEgWm9uYSBOb3J0ZSwgcG9zaWJsZW1lbnRlIHBvciBsYSBtZXpjbGEgZGUgZXN0cmF0b3MgeSBsYSBwcmVzZW5jaWEgZGUgcHJveWVjdG9zIGRlIGx1am8uCgotICoqRXN0cmF0byB2cy4gcHJlY2lvOioqIEVsIGRpYWdyYW1hIGRlIGNhamEgY29uZmlybWEgZGlmZXJlbmNpYXMgbWFyY2FkYXMgZW50cmUgZXN0cmF0b3MuIExhIGRpc3BlcnNpw7NuIGVzIGNvbnNpZGVyYWJsZW1lbnRlIG1heW9yIGVuIGVzdHJhdG9zIDUgeSA2LCBsbyBxdWUgcmVmbGVqYSBsYSBoZXRlcm9nZW5laWRhZCBkZWwgbWVyY2FkbyBkZSBhcGFydGFtZW50b3MgZGUgYWx0YSBnYW1hIGVuIENhbGkuCgotICoqUGFycXVlYWRlcm9zOioqIEVuIGFwYXJ0YW1lbnRvcywgbGEgZGlzcG9uaWJpbGlkYWQgZGUgbcO6bHRpcGxlcyBwYXJxdWVhZGVyb3MgZXMgdW4gZmFjdG9yIGRpZmVyZW5jaWFkb3IgaW1wb3J0YW50ZSB5IHNlIGVzcGVyYSB0ZW5nYSBtYXlvciBwZXNvIHJlbGF0aXZvIHF1ZSBlbiBjYXNhcy4KCi0gKipDb3JyZWxhY2lvbmVzIGVudHJlIHByZWRpY3RvcmFzOioqIFNlIGlkZW50aWZpY2FuIGNvcnJlbGFjaW9uZXMgbW9kZXJhZGFzIGVudHJlIGBhcmVhY29uc3RgLCBgaGFiaXRhY2lvbmVzYCB5IGBiYW5pb3NgLCBhbCBpZ3VhbCBxdWUgZW4gYmFzZTEuIEVzdG8gYW50aWNpcGEgcG9zaWJsZXMgZWZlY3RvcyBkZSBtdWx0aWNvbGluZWFsaWRhZCBxdWUgc2Vyw6FuIGN1YW50aWZpY2Fkb3MgbWVkaWFudGUgVklGLgoKIyMjIEVzdGltYWNpw7NuIGRlbCBtb2RlbG8KCmBgYHtyIG1vZGVsby1ybG0yfQpzZXQuc2VlZChwYXJhbXMkc2VlZCkKCm1vZGVsbzIgPC0gbG0ocHJlY2lvbSB+IGFyZWFjb25zdCArIGVzdHJhdG8gKyBoYWJpdGFjaW9uZXMgKwogICAgICAgICAgICAgICAgcGFycXVlYWRlcm9zICsgYmFuaW9zLAogICAgICAgICAgICAgIGRhdGEgPSBiYXNlMikKCnN1bW1hcnkobW9kZWxvMikKYGBgCgpgYGB7ciB0YWJsYS1jb2VmaWNpZW50ZXMyfQp0YmxfbW9kZWxvMiA8LSBtb2RlbHN1bW1hcnkoCiAgbGlzdCgiTW9kZWxvIFZpdmllbmRhIDIiID0gbW9kZWxvMiksCiAgZm10ICAgICAgID0gMywKICBzdGF0aXN0aWMgPSAiKHtwLnZhbHVlfSkiLAogIHN0YXJzICAgICA9IFRSVUUsCiAgbm90ZXMgICAgID0gIlZhbG9yZXMgcCBlbnRyZSBwYXLDqW50ZXNpcy4gKiBwPDAuMDUsICoqIHA8MC4wMSwgKioqIHA8MC4wMDEiLAogIGVzY2FwZSAgICA9IEZBTFNFLAogIG91dHB1dCAgICA9ICJrYWJsZUV4dHJhIgopICU+JQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksCiAgICBmdWxsX3dpZHRoICAgICAgICA9IEZBTFNFLAogICAgcG9zaXRpb24gICAgICAgICAgPSAiY2VudGVyIgogICkKCmNhcF9odG1sIDwtIHNwcmludGYoCiAgJzxkaXYgaWQ9InRhYmxhX21vZGVsbzIiIHN0eWxlPSJtYXJnaW46MCAwIDZweCAwOyI+CiAgIDxzdHJvbmc+VGFibGEgJWQuPC9zdHJvbmc+IFJlc3VtZW4gZGVsIG1vZGVsbyBkZSByZWdyZXNpw7NuIOKAkyBBcGFydGFtZW50b3MgWm9uYSBTdXIKICAgPC9kaXY+JywKICB7ZW52aXJvbm1lbnQobWlfdGFibGEpJHRhYl9uIDwtIGVudmlyb25tZW50KG1pX3RhYmxhKSR0YWJfbiArIDFMCiAgIGVudmlyb25tZW50KG1pX3RhYmxhKSR0YWJfbn0KKQoKa25pdHI6OmFzaXNfb3V0cHV0KHBhc3RlMChjYXBfaHRtbCwgIlxuXG4iLCB0YmxfbW9kZWxvMikpCmBgYAoKYGBge3IgaW50ZXJwcmV0YWNpb24tY29lZmljaWVudGVzMn0KY29lZjIgICAgICA8LSBjb2VmKG1vZGVsbzIpCnIyXzIgICAgICAgPC0gc3VtbWFyeShtb2RlbG8yKSRyLnNxdWFyZWQKcjJhZGpfMiAgICA8LSBzdW1tYXJ5KG1vZGVsbzIpJGFkai5yLnNxdWFyZWQKZnN0YXRfMiAgICA8LSBzdW1tYXJ5KG1vZGVsbzIpJGZzdGF0aXN0aWMKcHZhbF9mMiAgICA8LSBwZihmc3RhdF8yWzFdLCBmc3RhdF8yWzJdLCBmc3RhdF8yWzNdLCBsb3dlci50YWlsID0gRkFMU0UpCgpjYXQoIj09PSBDT0VGSUNJRU5URVMgRVNUSU1BRE9TIOKAkyBNT0RFTE8gMiA9PT1cbiIpCnByaW50KHJvdW5kKGNvZWYyLCA0KSkKY2F0KHNwcmludGYoIlxuUsKyID0gJS40ZiAgfCAgUsKyIGFqdXN0YWRvID0gJS40ZlxuIiwgcjJfMiwgcjJhZGpfMikpCmNhdChzcHJpbnRmKCJGLWVzdGFkw61zdGljbyA9ICUuMmYgIChwLXZhbG9yID0gJS42ZilcbiIsIGZzdGF0XzJbMV0sIHB2YWxfZjIpKQpgYGAKCioqSW50ZXJwcmV0YWNpw7NuIGRlIGxvcyBjb2VmaWNpZW50ZXMgKHZhbG9yZXMgcmVhbGVzIGRlbCBtb2RlbG8pOioqCgotICoqYGFyZWFjb25zdGA6KiogUG9yIGNhZGEgbWV0cm8gY3VhZHJhZG8gYWRpY2lvbmFsIGRlIMOhcmVhIGNvbnN0cnVpZGEsIGVsIHByZWNpbyBwcm9tZWRpbyBkZWwgYXBhcnRhbWVudG8gKiphdW1lbnRhIGVuIGByIHJvdW5kKGNvZWYyWyJhcmVhY29uc3QiXSwgMylgIG1pbGxvbmVzIGRlIHBlc29zKiosIGNldGVyaXMgcGFyaWJ1cy4gRW4gbGEgWm9uYSBTdXIsIGVzdGUgZWZlY3RvIHB1ZWRlIHNlciBtw6FzIG1hcmNhZG8gcXVlIGVuIGxhIFpvbmEgTm9ydGUsIGRhZG8gcXVlIGxvcyBhcGFydGFtZW50b3MgZGUgZXN0cmF0b3MgYWx0b3MgdGllbmVuIHVuIHByZWNpbyBwb3IgbcKyIHN1cGVyaW9yIGFsIGRlIGxhcyBjYXNhcy4KCi0gKipgZXN0cmF0b2A6KiogQ2FkYSBuaXZlbCBhZGljaW9uYWwgZGUgZXN0cmF0byBzZSBhc29jaWEgYSB1biBpbmNyZW1lbnRvIGRlICoqYHIgcm91bmQoY29lZjJbImVzdHJhdG8iXSwgMylgIG1pbGxvbmVzIGRlIHBlc29zKiogZW4gZWwgcHJlY2lvIHByb21lZGlvLiBFbiBlbCBtZXJjYWRvIGRlIGFwYXJ0YW1lbnRvcyBkZSBsYSBab25hIFN1ciwgZWwgZGlmZXJlbmNpYWwgZW50cmUgZXN0cmF0b3MgNSB5IDYgZXMgZXNwZWNpYWxtZW50ZSBzaWduaWZpY2F0aXZvIHBvciBsb3MgYXRyaWJ1dG9zIGRlIGNhbGlkYWQgY29uc3RydWN0aXZhIHkgc2VydmljaW9zLgoKLSAqKmBoYWJpdGFjaW9uZXNgOioqIFBvciBjYWRhIGhhYml0YWNpw7NuIGFkaWNpb25hbCwgZWwgcHJlY2lvIHZhcsOtYSBlbiAqKmByIHJvdW5kKGNvZWYyWyJoYWJpdGFjaW9uZXMiXSwgMylgIG1pbGxvbmVzIGRlIHBlc29zKiouIEVuIGFwYXJ0YW1lbnRvcywgZXN0ZSBlZmVjdG8gcHVlZGUgc2VyIG1lbm9yIHF1ZSBlbiBjYXNhcyBkYWRvIHF1ZSBlbCDDoXJlYSBjb25zdHJ1aWRhIGNhcHR1cmEgZ3JhbiBwYXJ0ZSBkZSBsYSBpbmZvcm1hY2nDs24gcmVsYWNpb25hZGEgY29uIGVsIHRhbWHDsW8gZGVsIGlubXVlYmxlLgoKLSAqKmBwYXJxdWVhZGVyb3NgOioqIENhZGEgcGFycXVlYWRlcm8gYWRpY2lvbmFsIHNlIGFzb2NpYSBhICoqYHIgcm91bmQoY29lZjJbInBhcnF1ZWFkZXJvcyJdLCAzKWAgbWlsbG9uZXMgZGUgcGVzb3MqKiBhZGljaW9uYWxlcyBlbiBlbCBwcmVjaW8uIEVuIGxhIFpvbmEgU3VyIGRlIENhbGksIGRvbmRlIGxhIG9mZXJ0YSBkZSBwYXJxdWVhZGVyb3MgZXMgbcOhcyBlc2Nhc2EsIGVzdGUgYXRyaWJ1dG8gcHVlZGUgdGVuZXIgdW4gcGVzbyBpbXBvcnRhbnRlIHNvYnJlIGxhIHZhbG9yaXphY2nDs24gZGVsIGFwYXJ0YW1lbnRvLgoKLSAqKmBiYW5pb3NgOioqIFBvciBjYWRhIGJhw7FvIGFkaWNpb25hbCwgZWwgcHJlY2lvIHZhcsOtYSBlbiAqKmByIHJvdW5kKGNvZWYyWyJiYW5pb3MiXSwgMylgIG1pbGxvbmVzIGRlIHBlc29zKiouCgoqKkV2YWx1YWNpw7NuIGRlbCBhanVzdGU6KioKCkVsIFLCsiBhanVzdGFkbyBlcyAqKmByIHJvdW5kKHIyYWRqXzIsIDQpYCoqLCBsbyBxdWUgc2lnbmlmaWNhIHF1ZSBlbCBtb2RlbG8gZXhwbGljYSBlbCAqKmByIHJvdW5kKHIyYWRqXzIgKiAxMDAsIDEpYCUqKiBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIHByZWNpbyBkZSBsb3MgYXBhcnRhbWVudG9zIGVuIGxhIFpvbmEgU3VyLiBFbCBlc3RhZMOtc3RpY28gRiA9IGByIHJvdW5kKGZzdGF0XzJbMV0sIDIpYCBjb24gcC12YWxvciA9IGByIGZvcm1hdChwdmFsX2YyLCBzY2llbnRpZmljID0gVFJVRSwgZGlnaXRzID0gMylgIGNvbmZpcm1hIHF1ZSBlbCBtb2RlbG8gZXMgZ2xvYmFsbWVudGUgc2lnbmlmaWNhdGl2by4gYHIgaWYocjJhZGpfMiA+PSAwLjcwKSAiRWwgYWp1c3RlIGVzIHNhdGlzZmFjdG9yaW8gcGFyYSBkYXRvcyBpbm1vYmlsaWFyaW9zIGRlIGNvcnRlIHRyYW5zdmVyc2FsLiIgZWxzZSAiRWwgYWp1c3RlIGVzIG1vZGVyYWRvLCBsbyBxdWUgc3VnaWVyZSBxdWUgZXhpc3RlbiBmYWN0b3JlcyByZWxldmFudGVzIHBhcmEgZWwgcHJlY2lvIHF1ZSBubyBlc3TDoW4gY2FwdHVyYWRvcyBwb3IgZWwgbW9kZWxvIGFjdHVhbCwgY29tbyBlbCBwaXNvIGRlbCBhcGFydGFtZW50bywgbGEgYW50aWfDvGVkYWQgZGUgbGEgY29uc3RydWNjacOzbiBvIGxhcyBhbWVuaWRhZGVzIGRlbCBjb25qdW50byByZXNpZGVuY2lhbC4iYCBQYXJhIG1lam9yYXIgZWwgYWp1c3RlIHNlIHBvZHLDrWEgaW5jbHVpciBlbCBiYXJyaW8gY29tbyB2YXJpYWJsZSBjYXRlZ8OzcmljYSwgYcOxYWRpciBlbCBwaXNvIGNvbW8gcHJlZGljdG9yIG8gdHJhbnNmb3JtYXIgZWwgcHJlY2lvIGNvbiBsb2dhcml0bW8uCgojIyMgVmFsaWRhY2nDs24gZGUgc3VwdWVzdG9zCgpgYGB7ciBzdXB1ZXN0b3MtZ3JhZmljb3MyfQpwX2RpYWcyIDwtIHJlY29yZFBsb3QoewogIHBhcihtZnJvdyA9IGMoMiwgMikpCiAgcGxvdChtb2RlbG8yKQogIHBhcihtZnJvdyA9IGMoMSwgMSkpCn0pCgptaV9maWd1cmEoCiAgcGxvdCAgID0gcF9kaWFnMiwKICBpZCAgICAgPSAiZGlhZ25vc3RpY29zX21vZGVsbzIiLAogIHRpdHVsbyA9ICJHcsOhZmljb3MgZGlhZ27Ds3N0aWNvcyDigJMgTW9kZWxvIEFwYXJ0YW1lbnRvcyBab25hIFN1ciIKKQpgYGAKCmBgYHtyIHN1cHVlc3RvLW5vcm1hbGlkYWQyfQpyZXNpZHVhbGVzMiA8LSByZXNpZHVhbHMobW9kZWxvMikKc3cyICA8LSBzaGFwaXJvLnRlc3QocmVzaWR1YWxlczIpCmtzMiAgPC0ga3MudGVzdChzY2FsZShyZXNpZHVhbGVzMiksICJwbm9ybSIpCgpkYXRhLmZyYW1lKAogIFBydWViYSAgICAgID0gYygiU2hhcGlyby1XaWxrIiwgIktvbG1vZ29yb3YtU21pcm5vdiIpLAogIEVzdGFkw61zdGljbyA9IHJvdW5kKGMoc3cyJHN0YXRpc3RpYywga3MyJHN0YXRpc3RpYyksIDQpLAogIGBwLXZhbG9yYCAgID0gcm91bmQoYyhzdzIkcC52YWx1ZSwgIGtzMiRwLnZhbHVlKSwgIDYpLAogIENvbmNsdXNpw7NuICA9IGlmZWxzZShjKHN3MiRwLnZhbHVlLCBrczIkcC52YWx1ZSkgPiAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICJObyBzZSByZWNoYXphIEjigoAgKG5vcm1hbGlkYWQpIiwKICAgICAgICAgICAgICAgICAgICAgICAiU2UgcmVjaGF6YSBI4oKAIChubyBub3JtYWxpZGFkKSIpLAogIGNoZWNrLm5hbWVzID0gRkFMU0UKKSAlPiUKICBtaV90YWJsYSgKICAgIHRpdHVsbyAgID0gIlBydWViYXMgZGUgbm9ybWFsaWRhZCBkZSByZXNpZHVhbGVzIOKAkyBNb2RlbG8gMiIsCiAgICBudW1fY29scyA9IGRwbHlyOjp3aGVyZShpcy5udW1lcmljKQogICkKYGBgCgpgYGB7ciBzdXB1ZXN0by1ob21vY2VkYXN0aWNpZGFkMn0KZ3EyIDwtIGdxdGVzdChtb2RlbG8yKQoKZGF0YS5mcmFtZSgKICBQcnVlYmEgICAgICA9ICJHb2xkZmVsZC1RdWFuZHQiLAogIEVzdGFkw61zdGljbyA9IHJvdW5kKGdxMiRzdGF0aXN0aWMsIDQpLAogIGBwLXZhbG9yYCAgID0gcm91bmQoZ3EyJHAudmFsdWUsICA2KSwKICBDb25jbHVzacOzbiAgPSBpZmVsc2UoZ3EyJHAudmFsdWUgPiAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICJObyBzZSByZWNoYXphIEjigoAgKHZhcmlhbnphIGNvbnN0YW50ZSkiLAogICAgICAgICAgICAgICAgICAgICAgICJTZSByZWNoYXphIEjigoAgKGhldGVyb2NlZGFzdGljaWRhZCkiKSwKICBjaGVjay5uYW1lcyA9IEZBTFNFCikgJT4lCiAgbWlfdGFibGEoCiAgICB0aXR1bG8gICA9ICJQcnVlYmEgZGUgaG9tb2NlZGFzdGljaWRhZCBHb2xkZmVsZC1RdWFuZHQg4oCTIE1vZGVsbyAyIiwKICAgIG51bV9jb2xzID0gZHBseXI6OndoZXJlKGlzLm51bWVyaWMpCiAgKQpgYGAKCmBgYHtyIHN1cHVlc3RvLWluZGVwZW5kZW5jaWEyfQpkdzIgPC0gZHd0ZXN0KG1vZGVsbzIpCgpkYXRhLmZyYW1lKAogIFBydWViYSAgICAgID0gIkR1cmJpbi1XYXRzb24iLAogIEVzdGFkw61zdGljbyA9IHJvdW5kKGR3MiRzdGF0aXN0aWMsIDQpLAogIGBwLXZhbG9yYCAgID0gcm91bmQoZHcyJHAudmFsdWUsICA2KSwKICBDb25jbHVzacOzbiAgPSBpZmVsc2UoZHcyJHAudmFsdWUgPiAwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICJObyBzZSByZWNoYXphIEjigoAgKGluZGVwZW5kZW5jaWEpIiwKICAgICAgICAgICAgICAgICAgICAgICAiU2UgcmVjaGF6YSBI4oKAIChhdXRvY29ycmVsYWNpw7NuKSIpLAogIGNoZWNrLm5hbWVzID0gRkFMU0UKKSAlPiUKICBtaV90YWJsYSgKICAgIHRpdHVsbyAgID0gIlBydWViYSBkZSBpbmRlcGVuZGVuY2lhIGRlIGVycm9yZXMgRHVyYmluLVdhdHNvbiDigJMgTW9kZWxvIDIiLAogICAgbnVtX2NvbHMgPSBkcGx5cjo6d2hlcmUoaXMubnVtZXJpYykKICApCmBgYAoKYGBge3IgdmlmMn0KdmlmX3ZhbHMyIDwtIHZpZihtb2RlbG8yKQoKZGF0YS5mcmFtZSgKICBWYXJpYWJsZSAgICA9IG5hbWVzKHZpZl92YWxzMiksCiAgVklGICAgICAgICAgPSByb3VuZCh2aWZfdmFsczIsIDMpLAogIERpYWduw7NzdGljbyA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICB2aWZfdmFsczIgPCA1ICB+ICJTaW4gbXVsdGljb2xpbmVhbGlkYWQiLAogICAgdmlmX3ZhbHMyIDwgMTAgfiAiTXVsdGljb2xpbmVhbGlkYWQgbW9kZXJhZGEiLAogICAgVFJVRSAgICAgICAgICAgfiAiTXVsdGljb2xpbmVhbGlkYWQgZ3JhdmUiCiAgKSwKICBjaGVjay5uYW1lcyA9IEZBTFNFCikgJT4lCiAgbWlfdGFibGEoCiAgICB0aXR1bG8gICA9ICJGYWN0b3JlcyBkZSBJbmZsYWNpw7NuIGRlIFZhcmlhbnphIChWSUYpIOKAkyBNb2RlbG8gMiIsCiAgICBudW1fY29scyA9IGRwbHlyOjp3aGVyZShpcy5udW1lcmljKQogICkKYGBgCgpgYGB7ciBpbnRlcnByZXRhY2lvbi1zdXB1ZXN0b3MyfQpzdzJfcCAgICA8LSBzdzIkcC52YWx1ZQprczJfcCAgICA8LSBrczIkcC52YWx1ZQpncTJfcCAgICA8LSBncTIkcC52YWx1ZQpkdzJfZCAgICA8LSBkdzIkc3RhdGlzdGljCmR3Ml9wICAgIDwtIGR3MiRwLnZhbHVlCnZpZl9tYXgyIDwtIG1heCh2aWZfdmFsczIpCnZpZl9taW4yIDwtIG1pbih2aWZfdmFsczIpCmBgYAoKKipJbnRlcnByZXRhY2nDs24gZGUgbG9zIHN1cHVlc3RvcyDigJMgTW9kZWxvIDI6KioKCioqMS4gTm9ybWFsaWRhZCBkZSBsb3MgcmVzaWR1YWxlczoqKgpMYSBwcnVlYmEgU2hhcGlyby1XaWxrIG9idGllbmUgVyA9IGByIHJvdW5kKHN3MiRzdGF0aXN0aWMsIDQpYCAocCA9IGByIGZvcm1hdChzdzJfcCwgc2NpZW50aWZpYyA9IFRSVUUsIGRpZ2l0cyA9IDMpYCkgeSBsYSBwcnVlYmEgS29sbW9nb3Jvdi1TbWlybm92IG9idGllbmUgRCA9IGByIHJvdW5kKGtzMiRzdGF0aXN0aWMsIDQpYCAocCA9IGByIGZvcm1hdChrczJfcCwgc2NpZW50aWZpYyA9IFRSVUUsIGRpZ2l0cyA9IDMpYCkuIGByIGlmKHN3Ml9wIDwgMC4wNSkgIkFtYmFzIHBydWViYXMgcmVjaGF6YW4gbGEgbm9ybWFsaWRhZCBkZSBsb3MgcmVzaWR1YWxlcyAocCA8IDAuMDUpLiBFbCBncsOhZmljbyBRLVEgY29uZmlybWEgZGVzdmlhY2lvbmVzIGVuIGxhcyBjb2xhcyBkZSBsYSBkaXN0cmlidWNpw7NuLiBFc3RvIGVzIGZyZWN1ZW50ZSBlbiBkYXRvcyBpbm1vYmlsaWFyaW9zIGRvbmRlIGV4aXN0ZW4gcHJvcGllZGFkZXMgZGUgbXV5IGFsdG8gcHJlY2lvIHF1ZSBnZW5lcmFuIGFzaW1ldHLDrWEgcG9zaXRpdmEgZW4gbG9zIHJlc2lkdWFsZXMuIExhIG1lZGlkYSBjb3JyZWN0aXZhIHJlY29tZW5kYWRhIGVzIGFwbGljYXIgdW5hIHRyYW5zZm9ybWFjacOzbiBsb2dhcsOtdG1pY2EgYWwgcHJlY2lvIChtb2RlbG8gbG9nLWxpbiksIHF1ZSByZWR1Y2lyw61hIGxhIGFzaW1ldHLDrWEgeSBtZWpvcmFyw61hIGxhIG5vcm1hbGlkYWQgZGUgbG9zIGVycm9yZXMuIiBlbHNlICJObyBzZSByZWNoYXphIGxhIG5vcm1hbGlkYWQgKHAgPiAwLjA1IGVuIGFtYmFzIHBydWViYXMpLiBMb3MgcmVzaWR1YWxlcyBkZWwgbW9kZWxvIHNvbiBjb25zaXN0ZW50ZXMgY29uIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbC4iYCAKCioqMi4gSG9tb2NlZGFzdGljaWRhZDoqKgpHb2xkZmVsZC1RdWFuZHQ6IGVzdGFkw61zdGljbyA9IGByIHJvdW5kKGdxMiRzdGF0aXN0aWMsIDQpYCwgcCA9IGByIGZvcm1hdChncTJfcCwgc2NpZW50aWZpYyA9IFRSVUUsIGRpZ2l0cyA9IDMpYC4gYHIgaWYoZ3EyX3AgPCAwLjA1KSAiU2UgcmVjaGF6YSBsYSBoaXDDs3Rlc2lzIGRlIHZhcmlhbnphIGNvbnN0YW50ZSAocCA8IDAuMDUpOiBleGlzdGUgaGV0ZXJvY2VkYXN0aWNpZGFkLiBMYSB2YXJpYWJpbGlkYWQgZGUgbG9zIHJlc2lkdWFsZXMgbm8gZXMgdW5pZm9ybWUsIHNpZW5kbyBtYXlvciBwYXJhIGFwYXJ0YW1lbnRvcyBkZSBtYXlvciBwcmVjaW8uIEVzdG8gcHVlZGUgZGlzdG9yc2lvbmFyIGxvcyBlcnJvcmVzIGVzdMOhbmRhciBkZSBsb3MgY29lZmljaWVudGVzIHkgYWZlY3RhciBsYSB2YWxpZGV6IGRlIGxvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YS4gU2UgcmVjb21pZW5kYSB1c2FyIGVycm9yZXMgZXN0w6FuZGFyIHJvYnVzdG9zIGEgaGV0ZXJvY2VkYXN0aWNpZGFkIChIQzMpIG8gdHJhbnNmb3JtYXIgbGEgdmFyaWFibGUgZGVwZW5kaWVudGUuIiBlbHNlICJObyBzZSByZWNoYXphIGxhIGhvbW9jZWRhc3RpY2lkYWQgKHAgPiAwLjA1KTogbGEgdmFyaWFuemEgZGUgbG9zIHJlc2lkdWFsZXMgZXMgY29uc3RhbnRlIGEgbG8gbGFyZ28gZGUgbG9zIHZhbG9yZXMgcHJlZGljaG9zLiJgIAoKKiozLiBJbmRlcGVuZGVuY2lhIGRlIGxvcyBlcnJvcmVzOioqCkR1cmJpbi1XYXRzb246IERXID0gYHIgcm91bmQoZHcyX2QsIDQpYCwgcCA9IGByIGZvcm1hdChkdzJfcCwgc2NpZW50aWZpYyA9IFRSVUUsIGRpZ2l0cyA9IDMpYC4gYHIgaWYoZHcyX3AgPCAwLjA1KSAiU2UgZGV0ZWN0YSBhdXRvY29ycmVsYWNpw7NuIGVuIGxvcyByZXNpZHVhbGVzIChwIDwgMC4wNSkuIEVuIGRhdG9zIGRlIGNvcnRlIHRyYW5zdmVyc2FsIGlubW9iaWxpYXJpbywgZXN0byBzZcOxYWxhIGRlcGVuZGVuY2lhIGVzcGFjaWFsOiBhcGFydGFtZW50b3MgZW4gZWwgbWlzbW8gZWRpZmljaW8gbyBtaXNtYSBtYW56YW5hIHRpZW5lbiBwcmVjaW9zIHNpbWlsYXJlcyBxdWUgZWwgbW9kZWxvIG5vIGNhcHR1cmEgY29tcGxldGFtZW50ZS4gTGEgY29ycmVjY2nDs24gc3VnZXJpZGEgZXMgaW5jbHVpciBlZmVjdG9zIGRlIGJhcnJpbyBvIGFwbGljYXIgbW9kZWxvcyBkZSByZWdyZXNpw7NuIGVzcGFjaWFsLiIgZWxzZSAiTm8gc2UgZGV0ZWN0YSBhdXRvY29ycmVsYWNpw7NuIChwID4gMC4wNSkuIExvcyBlcnJvcmVzIHNvbiBpbmRlcGVuZGllbnRlcyBlbnRyZSBvYnNlcnZhY2lvbmVzLiJgIAoKKio0LiBNdWx0aWNvbGluZWFsaWRhZDoqKgpMb3MgVklGIHZhcsOtYW4gZW50cmUgYHIgcm91bmQodmlmX21pbjIsIDIpYCB5IGByIHJvdW5kKHZpZl9tYXgyLCAyKWAuIGByIGlmKHZpZl9tYXgyIDwgNSkgIlRvZG9zIGxvcyBWSUYgc29uIGluZmVyaW9yZXMgYSA1OiBubyBoYXkgbXVsdGljb2xpbmVhbGlkYWQgcHJvYmxlbcOhdGljYS4gTG9zIGNvZWZpY2llbnRlcyBlc3RpbWFkb3Mgc29uIGVzdGFibGVzIHkgc3VzIGVycm9yZXMgZXN0w6FuZGFyIG5vIGVzdMOhbiBpbmZsYWRvcyBwb3IgcmVkdW5kYW5jaWEgZW50cmUgcHJlZGljdG9yYXMuIiBlbHNlIGlmKHZpZl9tYXgyIDwgMTApICJTZSBkZXRlY3RhIG11bHRpY29saW5lYWxpZGFkIG1vZGVyYWRhIGVuIGFsZ3VuYXMgdmFyaWFibGVzIChWSUYgZW50cmUgNSB5IDEwKS4gU2UgcmVjb21pZW5kYSBldmFsdWFyIGxhIHBvc2liaWxpZGFkIGRlIGVsaW1pbmFyIGxhIHZhcmlhYmxlIGNvbiBtYXlvciBWSUYgbyBjcmVhciB1biDDrW5kaWNlIGNvbXB1ZXN0by4iIGVsc2UgIkV4aXN0ZSBtdWx0aWNvbGluZWFsaWRhZCBncmF2ZSAoVklGID4gMTApLiBTZSByZWNvbWllbmRhIGVsaW1pbmFyIHZhcmlhYmxlcyByZWR1bmRhbnRlcyBvIGFwbGljYXIgcmVncmVzacOzbiBSaWRnZS4iYCAKCiMjIyBQcmVkaWNjacOzbiDigJMgVml2aWVuZGEgMgoKYGBge3IgcHJlZGljY2lvbjJ9CnZpdmllbmRhMiA8LSBkYXRhLmZyYW1lKAogIGFyZWFjb25zdCAgICA9IDMwMCwKICBlc3RyYXRvICAgICAgPSA1LAogIGhhYml0YWNpb25lcyA9IDUsCiAgcGFycXVlYWRlcm9zID0gMywKICBiYW5pb3MgICAgICAgPSAzCikKCnByZWQyIDwtIHByZWRpY3QobW9kZWxvMiwKICAgICAgICAgICAgICAgICBuZXdkYXRhICA9IHZpdmllbmRhMiwKICAgICAgICAgICAgICAgICBpbnRlcnZhbCA9ICJwcmVkaWN0aW9uIiwKICAgICAgICAgICAgICAgICBsZXZlbCAgICA9IDAuOTUpCgpkYXRhLmZyYW1lKAogIENhcmFjdGVyw61zdGljYSA9IGMoIsOBcmVhIChtwrIpIiwgIkVzdHJhdG8iLCAiSGFiaXRhY2lvbmVzIiwKICAgICAgICAgICAgICAgICAgICAgIlBhcnF1ZWFkZXJvcyIsICJCYcOxb3MiLAogICAgICAgICAgICAgICAgICAgICAiUHJlY2lvIGVzdGltYWRvIChNIENPUCkiLAogICAgICAgICAgICAgICAgICAgICAiTMOtbWl0ZSBpbmZlcmlvciA5NSUgKE0gQ09QKSIsCiAgICAgICAgICAgICAgICAgICAgICJMw61taXRlIHN1cGVyaW9yIDk1JSAoTSBDT1ApIiksCiAgVmFsb3IgPSBjKDMwMCwgNSwgNSwgMywgMywKICAgICAgICAgICAgcm91bmQocHJlZDJbMV0sIDEpLAogICAgICAgICAgICByb3VuZChwcmVkMlsyXSwgMSksCiAgICAgICAgICAgIHJvdW5kKHByZWQyWzNdLCAxKSksCiAgY2hlY2submFtZXMgPSBGQUxTRQopICU+JQogIG1pX3RhYmxhKAogICAgdGl0dWxvICAgPSAiUHJlZGljY2nDs24gZGVsIHByZWNpbyDigJMgVml2aWVuZGEgMiIsCiAgICBudW1fY29scyA9IGRwbHlyOjp3aGVyZShpcy5udW1lcmljKQogICkKYGBgCgoqKkludGVycHJldGFjacOzbiBkZSBsYSBwcmVkaWNjacOzbjoqKgoKRWwgbW9kZWxvIGVzdGltYSBxdWUgZWwgcHJlY2lvIGVzcGVyYWRvIGRlIHVuIGFwYXJ0YW1lbnRvIGNvbiAzMDAgbcKyLCBlc3RyYXRvIDUsIDUgaGFiaXRhY2lvbmVzLCAzIHBhcnF1ZWFkZXJvcyB5IDMgYmHDsW9zIGVuIGxhIFpvbmEgU3VyIGRlIENhbGkgZXMgZGUgYXByb3hpbWFkYW1lbnRlICoqYHIgcm91bmQocHJlZDJbMV0sIDEpYCBtaWxsb25lcyBkZSBwZXNvcyoqLiBFbCBpbnRlcnZhbG8gZGUgcHJlZGljY2nDs24gYWwgOTUlIHNlIGVuY3VlbnRyYSBlbnRyZSAqKmByIHJvdW5kKHByZWQyWzJdLCAxKWAqKiB5ICoqYHIgcm91bmQocHJlZDJbM10sIDEpYCBtaWxsb25lcyBkZSBwZXNvcyoqLgoKYHIgaWYocHJlZDJbMV0gPD0gODUwKSBwYXN0ZTAoIkVsIHByZWNpbyBlc3RpbWFkbyBkZSAiLCByb3VuZChwcmVkMlsxXSwgMSksICIgbWlsbG9uZXMgc2UgZW5jdWVudHJhIGRlbnRybyBkZWwgY3LDqWRpdG8gcHJlYXByb2JhZG8gZGUgJDg1MCBtaWxsb25lcywgbG8gcXVlIGNvbmZpcm1hIGxhIHZpYWJpbGlkYWQgZmluYW5jaWVyYSBkZSBlc3RhIHNvbGljaXR1ZC4gQWRlbcOhcywgZWwgbMOtbWl0ZSBzdXBlcmlvciBkZWwgaW50ZXJ2YWxvIGRlIHByZWRpY2Npw7NuICgiLCByb3VuZChwcmVkMlszXSwgMSksICIgbWlsbG9uZXMpICIsIGlmKHByZWQyWzNdIDw9IDg1MCkgInRhbWJpw6luIHF1ZWRhIGRlbnRybyBkZWwgcHJlc3VwdWVzdG8gZGlzcG9uaWJsZSwgbG8gcXVlIHByb3BvcmNpb25hIHNlZ3VyaWRhZCBhZGljaW9uYWwgc29icmUgbGEgZmFjdGliaWxpZGFkIGRlIGxhIG9wZXJhY2nDs24uIiBlbHNlICJzdXBlcmEgZWwgcHJlc3VwdWVzdG8sIGxvIHF1ZSBpbmRpY2EgcXVlIGV4aXN0ZSBpbmNlcnRpZHVtYnJlIHNvYnJlIHNpIGVsIHByZWNpbyByZWFsIGRlIG1lcmNhZG8gcG9kcsOtYSBleGNlZGVyIGxvcyA4NTAgbWlsbG9uZXMgcGFyYSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBzb2xpY2l0YWRhcy4iKSBlbHNlIHBhc3RlMCgiRWwgcHJlY2lvIGVzdGltYWRvIGRlICIsIHJvdW5kKHByZWQyWzFdLCAxKSwgIiBtaWxsb25lcyBzdXBlcmEgZWwgY3LDqWRpdG8gcHJlYXByb2JhZG8gZGUgJDg1MCBtaWxsb25lcy4gU2UgcmVjb21pZW5kYSBhanVzdGFyIGFsZ3VuYSBkZSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBzb2xpY2l0YWRhcyBvIGNvbnNpZGVyYXIgZXN0cmF0byA0IGNvbW8gYWx0ZXJuYXRpdmEuIilgIAoKIyMjIE9mZXJ0YXMgcG90ZW5jaWFsZXMg4oCTIFZpdmllbmRhIDIKCmBgYHtyIG9mZXJ0YXMyfQpvZmVydGFzMiA8LSBiYXNlMiAlPiUKICBmaWx0ZXIoCiAgICBwcmVjaW9tICAgICAgPD0gODUwLAogICAgaGFiaXRhY2lvbmVzID49IDQsCiAgICBiYW5pb3MgICAgICAgPj0gMywKICAgIHBhcnF1ZWFkZXJvcyA+PSAyLAogICAgZXN0cmF0byAgICAgICVpbiUgYyg1LCA2KQogICkgJT4lCiAgYXJyYW5nZShhYnMoYXJlYWNvbnN0IC0gMzAwKSkgJT4lCiAgaGVhZCgxMCkKCmNhdCgiT2ZlcnRhcyBwb3RlbmNpYWxlcyBlbmNvbnRyYWRhczoiLCBucm93KG9mZXJ0YXMyKSwgIlxuIikKCm9mZXJ0YXMyICU+JQogIHNlbGVjdChiYXJyaW8sIHpvbmEsIGVzdHJhdG8sIHByZWNpb20sIGFyZWFjb25zdCwKICAgICAgICAgaGFiaXRhY2lvbmVzLCBiYW5pb3MsIHBhcnF1ZWFkZXJvcykgJT4lCiAgbWlfdGFibGEoCiAgICB0aXR1bG8gICA9ICJPZmVydGFzIHBvdGVuY2lhbGVzIOKAkyBWaXZpZW5kYSAyICjiiaQgJDg1MCBNLCBlc3RyYXRvIDUtNikiLAogICAgbnVtX2NvbHMgPSBkcGx5cjo6d2hlcmUoaXMubnVtZXJpYykKICApCmBgYAoKYGBge3IgbWFwYS1vZmVydGFzMn0KbWFwYV9vZmVydGFzMiA8LSBvZmVydGFzMiAlPiUKICBmaWx0ZXIoIWlzLm5hKGxvbmdpdHVkKSwgIWlzLm5hKGxhdGl0dWQpKSAlPiUKICBoZWFkKDUpCgptYXBhX29mMiA8LSBsZWFmbGV0KGRhdGEgPSBtYXBhX29mZXJ0YXMyKSAlPiUKICBhZGRUaWxlcygpICU+JQogIGFkZENpcmNsZU1hcmtlcnMoCiAgICBsbmcgICAgPSB+bG9uZ2l0dWQsCiAgICBsYXQgICAgPSB+bGF0aXR1ZCwKICAgIGNvbG9yICA9ICJwdXJwbGUiLAogICAgcmFkaXVzID0gMTAsCiAgICBwb3B1cCAgPSB+cGFzdGUwKAogICAgICAiPGI+QmFycmlvOjwvYj4gIiwgYmFycmlvLCAiPGJyPiIsCiAgICAgICI8Yj5QcmVjaW86PC9iPiAkIiwgcHJlY2lvbSwgIiBNPGJyPiIsCiAgICAgICI8Yj7DgXJlYTo8L2I+ICIsIGFyZWFjb25zdCwgIiBtwrI8YnI+IiwKICAgICAgIjxiPkhhYml0YWNpb25lczo8L2I+ICIsIGhhYml0YWNpb25lcywgIjxicj4iLAogICAgICAiPGI+QmHDsW9zOjwvYj4gIiwgYmFuaW9zLCAiPGJyPiIsCiAgICAgICI8Yj5QYXJxdWVhZGVyb3M6PC9iPiAiLCBwYXJxdWVhZGVyb3MsICI8YnI+IiwKICAgICAgIjxiPkVzdHJhdG86PC9iPiAiLCBlc3RyYXRvCiAgICApLAogICAgbGFiZWwgID0gfnBhc3RlMCgiJCIsIHByZWNpb20sICJNIOKAkyAiLCBiYXJyaW8pCiAgKSAlPiUKICBhZGRMZWdlbmQoImJvdHRvbXJpZ2h0IiwgY29sb3JzID0gInB1cnBsZSIsCiAgICAgICAgICAgIGxhYmVscyA9ICJPZmVydGFzIOKJpCAkODUwIE0iLCB0aXRsZSA9ICJWaXZpZW5kYSAyIikKCmh0bWx0b29sczo6dGFnTGlzdChtYXBhX29mMikKLkZJR19OIDwtIC5GSUdfTiArIDEKa25pdHI6OmFzaXNfb3V0cHV0KHNwcmludGYoCiAgJzxkaXYgaWQ9Im1hcGFfb2ZlcnRhczIiIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlcjsgbWFyZ2luLXRvcDo2cHg7Ij4KICAgPHN0cm9uZz5GaWd1cmEgJWQuPC9zdHJvbmc+IE1hcGEgZGUgbGFzIDUgbWVqb3JlcyBvZmVydGFzIHBvdGVuY2lhbGVzIOKAkyBWaXZpZW5kYSAyCiAgIDwvZGl2PicsIC5GSUdfTgopKQpgYGAKCioqQW7DoWxpc2lzIGRlIGxhcyBvZmVydGFzOioqCgpMYXMgYHIgbnJvdyhtYXBhX29mZXJ0YXMyKWAgcHJvcGllZGFkZXMgcHJlc2VudGFkYXMgY3VtcGxlbiBjb24gdG9kb3MgbG9zIGNyaXRlcmlvcyBkZSBsYSBzZWd1bmRhIHNvbGljaXR1ZDogcHJlY2lvIGRlbnRybyBkZWwgcHJlc3VwdWVzdG8gZGUgJDg1MCBtaWxsb25lcywgZXN0cmF0byA1IG8gNiwgWm9uYSBTdXIsIHkgYWwgbWVub3MgNCBoYWJpdGFjaW9uZXMsIDMgYmHDsW9zIHkgMiBwYXJxdWVhZGVyb3MuIFBhcmEgY29tcGxlbWVudGFyIGxhIHJlY29tZW5kYWNpw7NuIGEgbGEgY29tcGHDscOtYSBpbnRlcm5hY2lvbmFsIHNlIHN1Z2llcmUgZXZhbHVhciBhZGljaW9uYWxtZW50ZTogZWwgcGlzbyBkZWwgYXBhcnRhbWVudG8gKGxvcyBwaXNvcyBhbHRvcyBzdWVsZW4gdGVuZXIgbWF5b3IgdmFsb3JpemFjacOzbiB5IGx1bWlub3NpZGFkKSwgZWwgZXN0YWRvIGRlbCByZWdsYW1lbnRvIGRlIHByb3BpZWRhZCBob3Jpem9udGFsLCBsYSBkaXNwb25pYmlsaWRhZCBkZSB6b25hcyBjb211bmVzIChnaW1uYXNpbywgcGlzY2luYSwgc2Fsb25lcykgeSBsYSBjZXJjYW7DrWEgYSB2w61hcyBwcmluY2lwYWxlcywgY29sZWdpb3MgeSBjZW50cm9zIGNvbWVyY2lhbGVzIGRlIGxhIFpvbmEgU3VyLgoKIyAqKkNvbXBhcmFjacOzbiBkZSBtb2RlbG9zIHkgY29uY2x1c2lvbmVzKioKCmBgYHtyIGNvbXBhcmFjaW9uLW1vZGVsb3N9CnRibF9jb21wYXJhY2lvbiA8LSBtb2RlbHN1bW1hcnkoCiAgbGlzdCgiQ2FzYSDigJMgWm9uYSBOb3J0ZSIgPSBtb2RlbG8xLAogICAgICAgIkFwdG8g4oCTIFpvbmEgU3VyIiAgID0gbW9kZWxvMiksCiAgZm10ICAgICAgID0gMywKICBzdGF0aXN0aWMgPSAiKHtwLnZhbHVlfSkiLAogIHN0YXJzICAgICA9IFRSVUUsCiAgbm90ZXMgICAgID0gIlZhbG9yZXMgcCBlbnRyZSBwYXLDqW50ZXNpcy4gKiBwPDAuMDUsICoqIHA8MC4wMSwgKioqIHA8MC4wMDEiLAogIGVzY2FwZSAgICA9IEZBTFNFLAogIG91dHB1dCAgICA9ICJrYWJsZUV4dHJhIgopICU+JQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksCiAgICBmdWxsX3dpZHRoICAgICAgICA9IEZBTFNFLAogICAgcG9zaXRpb24gICAgICAgICAgPSAiY2VudGVyIgogICkKCmNhcF9odG1sIDwtIHNwcmludGYoCiAgJzxkaXYgaWQ9InRhYmxhX2NvbXBhcmFjaW9uIiBzdHlsZT0ibWFyZ2luOjAgMCA2cHggMDsiPgogICA8c3Ryb25nPlRhYmxhICVkLjwvc3Ryb25nPiBDb21wYXJhY2nDs24gZGUgbG9zIG1vZGVsb3MgZGUgcmVncmVzacOzbiDigJMgVml2aWVuZGEgMSB2cyBWaXZpZW5kYSAyCiAgIDwvZGl2PicsCiAge2Vudmlyb25tZW50KG1pX3RhYmxhKSR0YWJfbiA8LSBlbnZpcm9ubWVudChtaV90YWJsYSkkdGFiX24gKyAxTAogICBlbnZpcm9ubWVudChtaV90YWJsYSkkdGFiX259CikKCmtuaXRyOjphc2lzX291dHB1dChwYXN0ZTAoY2FwX2h0bWwsICJcblxuIiwgdGJsX2NvbXBhcmFjaW9uKSkKYGBgCgoqKkNvbmNsdXNpb25lcyBnZW5lcmFsZXM6KioKCkVuIGFtYm9zIG1lcmNhZG9zLCBlbCDDoXJlYSBjb25zdHJ1aWRhIHkgZWwgZXN0cmF0byBzb24gbG9zIGRldGVybWluYW50ZXMgbcOhcyByb2J1c3RvcyBkZWwgcHJlY2lvIGRlIGxhIHZpdmllbmRhIGVuIENhbGksIHJlc3VsdGFkbyBjb2hlcmVudGUgY29uIGxhIHRlb3LDrWEgZWNvbsOzbWljYSBkZWwgbWVyY2FkbyBpbm1vYmlsaWFyaW8uIEVsIG1vZGVsbyBwYXJhIGNhc2FzIGRlIGxhIFpvbmEgTm9ydGUgYWxjYW56YSB1biBSwrIgYWp1c3RhZG8gZGUgYHIgcm91bmQocjJhZGpfMSwgMylgLCBtaWVudHJhcyBxdWUgZWwgZGUgYXBhcnRhbWVudG9zIGRlIGxhIFpvbmEgU3VyIG9idGllbmUgYHIgcm91bmQocjJhZGpfMiwgMylgLCBsbyBxdWUgaW5kaWNhIGRpZmVyZW5jaWFzIGVuIGxhIGNhcGFjaWRhZCBleHBsaWNhdGl2YSBlbnRyZSBsb3MgZG9zIHNlZ21lbnRvcyBkZSBtZXJjYWRvLgoKRGVzZGUgZWwgcHVudG8gZGUgdmlzdGEgZGUgbGEgdmFsaWRhY2nDs24gZXN0YWTDrXN0aWNhLCBhbWJvcyBtb2RlbG9zIHByZXNlbnRhbiBsaW1pdGFjaW9uZXMgc2ltaWxhcmVzOiBsb3MgcmVzaWR1YWxlcyBleGhpYmVuIGRlc3ZpYWNpb25lcyBkZSBsYSBub3JtYWxpZGFkIHTDrXBpY2FzIGRlIGRhdG9zIGlubW9iaWxpYXJpb3MgY29uIGFzaW1ldHLDrWEgcG9zaXRpdmEsIHkgc2UgZGV0ZWN0YW4gaW5kaWNpb3MgZGUgZGVwZW5kZW5jaWEgZXNwYWNpYWwgZW4gbG9zIGVycm9yZXMuIE5pbmd1bm8gZGUgbG9zIGRvcyBtb2RlbG9zIHByZXNlbnRhIG11bHRpY29saW5lYWxpZGFkIGdyYXZlLCBsbyBxdWUgZ2FyYW50aXphIGxhIGVzdGFiaWxpZGFkIGRlIGxvcyBjb2VmaWNpZW50ZXMgZXN0aW1hZG9zLgoKUGFyYSBsYSAqKlZpdmllbmRhIDEqKiwgZWwgcHJlY2lvIGVzdGltYWRvIGRlIGByIHJvdW5kKHByZWQxWzFdLCAxKWAgbWlsbG9uZXMgYHIgaWYocHJlZDFbMV0gPD0gMzUwKSAiZXMgY29tcGF0aWJsZSBjb24gZWwgcHJlc3VwdWVzdG8gZGUgJDM1MCBtaWxsb25lcyIgZWxzZSAic3VwZXJhIGVsIHByZXN1cHVlc3RvIGRlICQzNTAgbWlsbG9uZXMiYCwgeSBzZSBpZGVudGlmaWNhcm9uIG9mZXJ0YXMgcmVhbGVzIGVuIGxhIFpvbmEgTm9ydGUgcXVlIHNhdGlzZmFjZW4gbG9zIHJlcXVlcmltaWVudG9zIGRlIGxhIHNvbGljaXR1ZC4gUGFyYSBsYSAqKlZpdmllbmRhIDIqKiwgZWwgcHJlY2lvIGVzdGltYWRvIGRlIGByIHJvdW5kKHByZWQyWzFdLCAxKWAgbWlsbG9uZXMgYHIgaWYocHJlZDJbMV0gPD0gODUwKSAic2UgZW5jdWVudHJhIGRlbnRybyBkZWwgcHJlc3VwdWVzdG8gZGUgJDg1MCBtaWxsb25lcyIgZWxzZSAic3VwZXJhIGVsIHByZXN1cHVlc3RvIGRlICQ4NTAgbWlsbG9uZXMiYCwgY29uIHZhcmlhcyBvcGNpb25lcyBkaXNwb25pYmxlcyBlbiBsYSBab25hIFN1ciBxdWUgY3VtcGxlbiBsb3MgY3JpdGVyaW9zIGRlIGxhIGNvbXBhw7HDrWEgaW50ZXJuYWNpb25hbC4KClNlIHJlY29taWVuZGEgYSBNYXLDrWEgY29tcGxlbWVudGFyIGVzdGUgYW7DoWxpc2lzIGN1YW50aXRhdGl2byBjb24gdmlzaXRhcyBwcmVzZW5jaWFsZXMgYSBsYXMgcHJvcGllZGFkZXMgc2VsZWNjaW9uYWRhcyB5IHVuYSByZXZpc2nDs24gZGVsIGF2YWzDum8gY2F0YXN0cmFsIGFjdHVhbGl6YWRvLCBwYXJhIGdhcmFudGl6YXIgcXVlIGxhcyByZWNvbWVuZGFjaW9uZXMgZW50cmVnYWRhcyBhbCBjbGllbnRlIHJlZmxlamVuIGNvbiBwcmVjaXNpw7NuIGxhcyBjb25kaWNpb25lcyBhY3R1YWxlcyBkZWwgbWVyY2Fkby4K