library(ggplot2)
library(gridExtra)
library(GGally)
library(corrplot)
library(dplyr)
library(tidyr)
library(viridis)
library(reshape2)

# Configuración general
theme_set(theme_minimal(base_size = 11))

# NOTA: Reemplazar 'ckd_data' con el nombre real de tu dataframe
getwd()  
[1] "/Users/samircabrera/Development/Universidad/Inteligencia Artificial/Inteligencia-Artificial/Proyecto/Code/plots"
ckd_data <- read.csv("/Users/samircabrera/Development/Universidad/Inteligencia Artificial/Inteligencia-Artificial/Proyecto/Dataset/Chronic_Kidney_Dsease_data.csv")
plot_renal_pairs <- function(data, sample_size = 400) {
  renal_data <- data %>%
    select(GFR, SerumCreatinine, BUNLevels, ProteinInUrine, ACR, Diagnosis) %>%
    mutate(Diagnosis = factor(Diagnosis, labels = c("No CKD", "CKD"))) %>%
    group_by(Diagnosis) %>%
    slice_sample(n = sample_size / 2) %>%  # Mantiene proporción
    ungroup()
  
  ggpairs(renal_data,
          columns = 1:5,
          aes(color = Diagnosis, alpha = 0.6),
          upper = list(continuous = wrap("cor", size = 3.5, stars = FALSE)),
          lower = list(continuous = wrap("points", alpha = 0.4, size = 0.8)),
          diag = list(continuous = wrap("densityDiag", alpha = 0.6)),
          title = "Relaciones entre Marcadores Renales (Muestra Estratificada)") +
    theme_bw() +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
      strip.text = element_text(size = 9)
    )
}
plot_gfr_3d <- function(data) {
  n_per_group = 250
  data_plot <- data %>%
    mutate(Diagnosis = factor(Diagnosis, labels = c("No CKD", "CKD"))) %>%
    group_by(Diagnosis) %>%
    slice_sample(n = n_per_group) %>%  # Exactamente n_per_group de cada uno
    ungroup()
  
  ggplot(data_plot, aes(x = SerumCreatinine, y = GFR)) +
    geom_point(aes(color = Age, size = BMI), alpha = 0.6) +
    scale_color_viridis_c(option = "plasma") +
    scale_size_continuous(range = c(2, 6)) +
    geom_smooth(method = "loess", se = TRUE, color = "black", linewidth = 1) +
    facet_wrap(~Diagnosis, scales = "free") +
    labs(title = "GFR vs Creatinina Sérica por Diagnóstico",
         subtitle = sprintf("%d pacientes por grupo | Edad (color) y BMI (tamaño)", n_per_group),
         x = "Creatinina Sérica (mg/dL)",
         y = "GFR (mL/min/1.73m²)") +
    theme_minimal() +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
      plot.subtitle = element_text(hjust = 0.5, size = 10),
      strip.text = element_text(face = "bold", size = 11),
      legend.position = "bottom"
    )
}
plot_clinical_heatmap <- function(data) {
  # Crear estadios de CKD basados en GFR
  data_staged <- data %>%
    mutate(CKD_Stage = case_when(
      GFR >= 90 ~ "Normal (≥90)",
      GFR >= 60 ~ "Mild (60-89)",
      GFR >= 30 ~ "Moderate (30-59)",
      GFR >= 15 ~ "Severe (15-29)",
      TRUE ~ "Kidney Failure (<15)"
    )) %>%
    mutate(CKD_Stage = factor(CKD_Stage, 
                              levels = c("Normal (≥90)", "Mild (60-89)", 
                                         "Moderate (30-59)", "Severe (15-29)", 
                                         "Kidney Failure (<15)")))
  
  # Calcular promedios por estadio
  heatmap_data <- data_staged %>%
    group_by(CKD_Stage) %>%
    summarise(
      BMI = mean(BMI, na.rm = TRUE),
      SystolicBP = mean(SystolicBP, na.rm = TRUE),
      HbA1c = mean(HbA1c, na.rm = TRUE),
      Creatinine = mean(SerumCreatinine, na.rm = TRUE),
      Hemoglobin = mean(HemoglobinLevels, na.rm = TRUE),
      ProteinUrine = mean(ProteinInUrine, na.rm = TRUE),
      Fatigue = mean(FatigueLevels, na.rm = TRUE),
      QoL = mean(QualityOfLifeScore, na.rm = TRUE)
    ) %>%
    pivot_longer(-CKD_Stage, names_to = "Variable", values_to = "Value") %>%
    group_by(Variable) %>%
    mutate(Value_scaled = scale(Value)[,1])  # Estandarizar por variable
  
  ggplot(heatmap_data, aes(x = CKD_Stage, y = Variable, fill = Value_scaled)) +
    geom_tile(color = "white", size = 0.5) +
    geom_text(aes(label = round(Value, 1)), size = 3, color = "white") +
    scale_fill_gradient2(low = "#3B9AB2", mid = "#EBCC2A", high = "#F21A00",
                         midpoint = 0, name = "Z-score") +
    labs(title = "Perfil Clínico Promedio por Estadio de CKD",
         x = "Estadio de Enfermedad Renal",
         y = "Variable Clínica",
         caption = "Valores estandarizados (Z-scores) - números = valor real promedio") +
    theme(axis.text.x = element_text(angle = 45, hjust = 1),
          plot.title = element_text(hjust = 0.5, face = "bold"))
}
plot_parallel_coordinates <- function(data) {
  parallel_data <- data %>%
    select(BMI, PhysicalActivity, DietQuality, SleepQuality,
           AlcoholConsumption, Diagnosis) %>%
    mutate(Diagnosis = factor(Diagnosis, labels = c("No CKD", "CKD"))) %>%
    mutate(across(c(BMI, PhysicalActivity, DietQuality, SleepQuality, 
                    AlcoholConsumption), scale))
  
  parallel_long <- parallel_data %>%
    pivot_longer(cols = c(BMI, PhysicalActivity, DietQuality, 
                          SleepQuality, AlcoholConsumption),
                 names_to = "Variable", values_to = "Value") %>%
    mutate(Variable = factor(Variable, 
                             levels = c("BMI", "PhysicalActivity", "DietQuality",
                                        "SleepQuality", "AlcoholConsumption")))
  
  ggplot(parallel_long, aes(x = Variable, y = Value, fill = Diagnosis)) +
    geom_violin(alpha = 0.6, position = position_dodge(width = 0.9)) +
    geom_boxplot(width = 0.2, position = position_dodge(width = 0.9),
                 alpha = 0.8, outlier.alpha = 0.3) +
    scale_fill_manual(values = c("No CKD" = "#2ecc71", "CKD" = "#e74c3c")) +
    labs(title = "Distribución de Variables de Estilo de Vida",
         subtitle = "Comparación completa del dataset (violin + boxplot)",
         y = "Valor Estandarizado (Z-score)",
         x = NULL) +
    theme_minimal() +
    theme(
      axis.text.x = element_text(angle = 45, hjust = 1, size = 10),
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
      plot.subtitle = element_text(hjust = 0.5, size = 10),
      legend.position = "bottom"
    )
}
plot_demographic_boxplots <- function(data) {
  data_demo <- data %>%
    mutate(
      Gender = factor(Gender, labels = c("Male", "Female")),
      Ethnicity = factor(Ethnicity, labels = c("Caucasian", "African American", 
                                               "Asian", "Other")),
      SocioeconomicStatus = factor(SocioeconomicStatus, 
                                   labels = c("Low", "Middle", "High"))
    ) %>%
    select(Gender, Ethnicity, SocioeconomicStatus, GFR, HbA1c, 
           SystolicBP, QualityOfLifeScore) %>%
    pivot_longer(cols = c(GFR, HbA1c, SystolicBP, QualityOfLifeScore),
                 names_to = "Biomarker", values_to = "Value")
  
  ggplot(data_demo, aes(x = SocioeconomicStatus, y = Value, fill = Gender)) +
    geom_boxplot(alpha = 0.7, outlier.size = 0.5) +
    facet_grid(Biomarker ~ Ethnicity, scales = "free_y") +
    scale_fill_brewer(palette = "Set2") +
    labs(title = "Biomarcadores por Demografía (Género, Etnicidad, Estatus Socioeconómico)",
         x = "Estatus Socioeconómico",
         y = "Valor del Biomarcador") +
    theme(strip.text = element_text(face = "bold", size = 8),
          axis.text.x = element_text(angle = 45, hjust = 1),
          plot.title = element_text(hjust = 0.5, face = "bold", size = 11))
}
plot_qol_bubble <- function(data) {
  n_per_group = 50
  bubble_data <- data %>%
    mutate(
      Severity_Score = (SerumCreatinine - min(SerumCreatinine)) / 
        (max(SerumCreatinine) - min(SerumCreatinine)) * 10,
      Diagnosis = factor(Diagnosis, labels = c("No CKD", "CKD"))
    ) %>%
    group_by(Diagnosis) %>%
    slice_sample(n = n_per_group) %>%  # Exactamente n_per_group de cada uno
    ungroup()
  
  ggplot(bubble_data, aes(x = FatigueLevels, y = QualityOfLifeScore)) +
    geom_point(aes(size = Severity_Score, color = GFR), 
               alpha = 0.7, shape = 16) +
    scale_color_viridis_c(option = "magma", direction = -1, 
                          name = "GFR\n(mL/min/1.73m²)") +
    scale_size_continuous(range = c(2, 10), 
                          name = "Severidad\n(Creatinina)") +
    geom_smooth(method = "lm", se = TRUE, color = "black", 
                linetype = "dashed", linewidth = 1) +
    facet_wrap(~Diagnosis, scales = "free") +
    labs(title = "Calidad de Vida vs Fatiga por Diagnóstico",
         subtitle = sprintf("%d pacientes por grupo | Severidad en tamaño | GFR en color", n_per_group),
         x = "Nivel de Fatiga (0-10)",
         y = "Score de Calidad de Vida (0-100)") +
    theme_minimal() +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
      plot.subtitle = element_text(hjust = 0.5, size = 10),
      strip.text = element_text(face = "bold", size = 11),
      legend.position = "right",
      panel.grid.minor = element_blank()
    )
}
plot_lifestyle_vs_gfr <- function(data) {
  n_per_group = 100
  # Crear Healthy Lifestyle Score
  lifestyle_data <- data %>%
    mutate(
      # Normalizar cada componente a escala 0-10
      PA_score = (PhysicalActivity / 10) * 10,  # Ya está en 0-10
      Diet_score = DietQuality,  # Ya está en 0-10
      Sleep_score = ((SleepQuality - 4) / (10 - 4)) * 10,  # Normalizar de 4-10 a 0-10
      NoSmoking_score = (1 - Smoking) * 10,  # Invertir: no fumar = 10
      LowAlcohol_score = ((20 - AlcoholConsumption) / 20) * 10,  # Invertir: bajo alcohol = alto score
      
      # Calcular score promedio
      HealthyLifestyleScore = (PA_score + Diet_score + Sleep_score + 
                                 NoSmoking_score + LowAlcohol_score) / 5,
      
      Diagnosis = factor(Diagnosis, labels = c("No CKD", "CKD"))
    ) %>%
    group_by(Diagnosis) %>%
    slice_sample(n = n_per_group) %>%
    ungroup()
  
  ggplot(lifestyle_data, aes(x = HealthyLifestyleScore, y = GFR)) +
    geom_point(aes(color = Diagnosis, size = SerumCreatinine), alpha = 0.6) +
    geom_smooth(aes(color = Diagnosis), method = "lm", se = TRUE, linewidth = 1.2) +
    scale_color_manual(values = c("No CKD" = "#2ecc71", "CKD" = "#e74c3c")) +
    scale_size_continuous(range = c(1, 6), name = "Creatinina\n(mg/dL)") +
    labs(title = "Estilo de Vida Saludable vs Función Renal (GFR)",
         subtitle = sprintf("Muestra: %d pacientes por grupo", n_per_group),
         x = "Healthy Lifestyle Score (0-10)",
         y = "GFR (mL/min/1.73m²)") +
    theme_minimal() +
    theme(
      plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
      plot.subtitle = element_text(hjust = 0.5, size = 10, color = "gray30"),
      legend.position = "right",
      panel.grid.minor = element_blank()
    )
}
generate_all_plots <- function(data) {
  plots <- list()
  
  cat("Generando visualizaciones multivariables priorizadas...\n\n")
  
  cat("1. Pairplot de Variables Renales (Análisis principal)...\n")
  plots$renal_pairs <- plot_renal_pairs(data)
  print(plots$renal_pairs)
  
  cat("2. Heatmap de Perfiles Clínicos (Clusters y patrones)...\n")
  plots$heatmap <- plot_clinical_heatmap(data)
  print(plots$heatmap)
  
  cat("3. Lifestyle Score vs GFR (Impacto conductual)...\n")
  plots$lifestyle_gfr <- plot_lifestyle_vs_gfr(data)
  print(plots$lifestyle_gfr)
  
  cat("4. Scatterplot 4D (GFR-Creatinina-Edad-BMI)...\n")
  plots$gfr_3d <- plot_gfr_3d(data)
  print(plots$gfr_3d)
  
  cat("5. Parallel Coordinates (Factores de Riesgo)...\n")
  plots$parallel <- plot_parallel_coordinates(data)
  print(plots$parallel)
  
  cat("6. Boxplots Demográficos Facetados...\n")
  plots$demo_box <- plot_demographic_boxplots(data)
  print(plots$demo_box)
  
  cat("7. Bubble Chart (Calidad de Vida)...\n")
  plots$bubble <- plot_qol_bubble(data)
  print(plots$bubble)
  
  cat("\n Todas las visualizaciones generadas y priorizadas correctamente.\n")
  
  return(invisible(plots))
}
plots <- generate_all_plots(ckd_data)
Generando visualizaciones multivariables priorizadas...

1. Pairplot de Variables Renales (Análisis principal)...
2. Heatmap de Perfiles Clínicos (Clusters y patrones)...
3. Lifestyle Score vs GFR (Impacto conductual)...
4. Scatterplot 4D (GFR-Creatinina-Edad-BMI)...
5. Parallel Coordinates (Factores de Riesgo)...
6. Boxplots Demográficos Facetados...
7. Bubble Chart (Calidad de Vida)...

 Todas las visualizaciones generadas y priorizadas correctamente.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHJlc2hhcGUyKQoKIyBDb25maWd1cmFjacOzbiBnZW5lcmFsCnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDExKSkKCiMgTk9UQTogUmVlbXBsYXphciAnY2tkX2RhdGEnIGNvbiBlbCBub21icmUgcmVhbCBkZSB0dSBkYXRhZnJhbWUKZ2V0d2QoKSAgCmNrZF9kYXRhIDwtIHJlYWQuY3N2KCIvVXNlcnMvc2FtaXJjYWJyZXJhL0RldmVsb3BtZW50L1VuaXZlcnNpZGFkL0ludGVsaWdlbmNpYSBBcnRpZmljaWFsL0ludGVsaWdlbmNpYS1BcnRpZmljaWFsL1Byb3llY3RvL0RhdGFzZXQvQ2hyb25pY19LaWRuZXlfRHNlYXNlX2RhdGEuY3N2IikKYGBgCgpgYGB7cn0KcGxvdF9yZW5hbF9wYWlycyA8LSBmdW5jdGlvbihkYXRhLCBzYW1wbGVfc2l6ZSA9IDQwMCkgewogIHJlbmFsX2RhdGEgPC0gZGF0YSAlPiUKICAgIHNlbGVjdChHRlIsIFNlcnVtQ3JlYXRpbmluZSwgQlVOTGV2ZWxzLCBQcm90ZWluSW5VcmluZSwgQUNSLCBEaWFnbm9zaXMpICU+JQogICAgbXV0YXRlKERpYWdub3NpcyA9IGZhY3RvcihEaWFnbm9zaXMsIGxhYmVscyA9IGMoIk5vIENLRCIsICJDS0QiKSkpICU+JQogICAgZ3JvdXBfYnkoRGlhZ25vc2lzKSAlPiUKICAgIHNsaWNlX3NhbXBsZShuID0gc2FtcGxlX3NpemUgLyAyKSAlPiUgICMgTWFudGllbmUgcHJvcG9yY2nDs24KICAgIHVuZ3JvdXAoKQogIAogIGdncGFpcnMocmVuYWxfZGF0YSwKICAgICAgICAgIGNvbHVtbnMgPSAxOjUsCiAgICAgICAgICBhZXMoY29sb3IgPSBEaWFnbm9zaXMsIGFscGhhID0gMC42KSwKICAgICAgICAgIHVwcGVyID0gbGlzdChjb250aW51b3VzID0gd3JhcCgiY29yIiwgc2l6ZSA9IDMuNSwgc3RhcnMgPSBGQUxTRSkpLAogICAgICAgICAgbG93ZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSB3cmFwKCJwb2ludHMiLCBhbHBoYSA9IDAuNCwgc2l6ZSA9IDAuOCkpLAogICAgICAgICAgZGlhZyA9IGxpc3QoY29udGludW91cyA9IHdyYXAoImRlbnNpdHlEaWFnIiwgYWxwaGEgPSAwLjYpKSwKICAgICAgICAgIHRpdGxlID0gIlJlbGFjaW9uZXMgZW50cmUgTWFyY2Fkb3JlcyBSZW5hbGVzIChNdWVzdHJhIEVzdHJhdGlmaWNhZGEpIikgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZSgKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KSwKICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkKICAgICkKfQpgYGAKCmBgYHtyfQpwbG90X2dmcl8zZCA8LSBmdW5jdGlvbihkYXRhKSB7CiAgbl9wZXJfZ3JvdXAgPSAyNTAKICBkYXRhX3Bsb3QgPC0gZGF0YSAlPiUKICAgIG11dGF0ZShEaWFnbm9zaXMgPSBmYWN0b3IoRGlhZ25vc2lzLCBsYWJlbHMgPSBjKCJObyBDS0QiLCAiQ0tEIikpKSAlPiUKICAgIGdyb3VwX2J5KERpYWdub3NpcykgJT4lCiAgICBzbGljZV9zYW1wbGUobiA9IG5fcGVyX2dyb3VwKSAlPiUgICMgRXhhY3RhbWVudGUgbl9wZXJfZ3JvdXAgZGUgY2FkYSB1bm8KICAgIHVuZ3JvdXAoKQogIAogIGdncGxvdChkYXRhX3Bsb3QsIGFlcyh4ID0gU2VydW1DcmVhdGluaW5lLCB5ID0gR0ZSKSkgKwogICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBBZ2UsIHNpemUgPSBCTUkpLCBhbHBoYSA9IDAuNikgKwogICAgc2NhbGVfY29sb3JfdmlyaWRpc19jKG9wdGlvbiA9ICJwbGFzbWEiKSArCiAgICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDIsIDYpKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IFRSVUUsIGNvbG9yID0gImJsYWNrIiwgbGluZXdpZHRoID0gMSkgKwogICAgZmFjZXRfd3JhcCh+RGlhZ25vc2lzLCBzY2FsZXMgPSAiZnJlZSIpICsKICAgIGxhYnModGl0bGUgPSAiR0ZSIHZzIENyZWF0aW5pbmEgU8OpcmljYSBwb3IgRGlhZ27Ds3N0aWNvIiwKICAgICAgICAgc3VidGl0bGUgPSBzcHJpbnRmKCIlZCBwYWNpZW50ZXMgcG9yIGdydXBvIHwgRWRhZCAoY29sb3IpIHkgQk1JICh0YW1hw7FvKSIsIG5fcGVyX2dyb3VwKSwKICAgICAgICAgeCA9ICJDcmVhdGluaW5hIFPDqXJpY2EgKG1nL2RMKSIsCiAgICAgICAgIHkgPSAiR0ZSIChtTC9taW4vMS43M23CsikiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUoCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMCksCiAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDExKSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICAgICkKfQpgYGAKCmBgYHtyfQpwbG90X2NsaW5pY2FsX2hlYXRtYXAgPC0gZnVuY3Rpb24oZGF0YSkgewogICMgQ3JlYXIgZXN0YWRpb3MgZGUgQ0tEIGJhc2Fkb3MgZW4gR0ZSCiAgZGF0YV9zdGFnZWQgPC0gZGF0YSAlPiUKICAgIG11dGF0ZShDS0RfU3RhZ2UgPSBjYXNlX3doZW4oCiAgICAgIEdGUiA+PSA5MCB+ICJOb3JtYWwgKOKJpTkwKSIsCiAgICAgIEdGUiA+PSA2MCB+ICJNaWxkICg2MC04OSkiLAogICAgICBHRlIgPj0gMzAgfiAiTW9kZXJhdGUgKDMwLTU5KSIsCiAgICAgIEdGUiA+PSAxNSB+ICJTZXZlcmUgKDE1LTI5KSIsCiAgICAgIFRSVUUgfiAiS2lkbmV5IEZhaWx1cmUgKDwxNSkiCiAgICApKSAlPiUKICAgIG11dGF0ZShDS0RfU3RhZ2UgPSBmYWN0b3IoQ0tEX1N0YWdlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiTm9ybWFsICjiiaU5MCkiLCAiTWlsZCAoNjAtODkpIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1vZGVyYXRlICgzMC01OSkiLCAiU2V2ZXJlICgxNS0yOSkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS2lkbmV5IEZhaWx1cmUgKDwxNSkiKSkpCiAgCiAgIyBDYWxjdWxhciBwcm9tZWRpb3MgcG9yIGVzdGFkaW8KICBoZWF0bWFwX2RhdGEgPC0gZGF0YV9zdGFnZWQgJT4lCiAgICBncm91cF9ieShDS0RfU3RhZ2UpICU+JQogICAgc3VtbWFyaXNlKAogICAgICBCTUkgPSBtZWFuKEJNSSwgbmEucm0gPSBUUlVFKSwKICAgICAgU3lzdG9saWNCUCA9IG1lYW4oU3lzdG9saWNCUCwgbmEucm0gPSBUUlVFKSwKICAgICAgSGJBMWMgPSBtZWFuKEhiQTFjLCBuYS5ybSA9IFRSVUUpLAogICAgICBDcmVhdGluaW5lID0gbWVhbihTZXJ1bUNyZWF0aW5pbmUsIG5hLnJtID0gVFJVRSksCiAgICAgIEhlbW9nbG9iaW4gPSBtZWFuKEhlbW9nbG9iaW5MZXZlbHMsIG5hLnJtID0gVFJVRSksCiAgICAgIFByb3RlaW5VcmluZSA9IG1lYW4oUHJvdGVpbkluVXJpbmUsIG5hLnJtID0gVFJVRSksCiAgICAgIEZhdGlndWUgPSBtZWFuKEZhdGlndWVMZXZlbHMsIG5hLnJtID0gVFJVRSksCiAgICAgIFFvTCA9IG1lYW4oUXVhbGl0eU9mTGlmZVNjb3JlLCBuYS5ybSA9IFRSVUUpCiAgICApICU+JQogICAgcGl2b3RfbG9uZ2VyKC1DS0RfU3RhZ2UsIG5hbWVzX3RvID0gIlZhcmlhYmxlIiwgdmFsdWVzX3RvID0gIlZhbHVlIikgJT4lCiAgICBncm91cF9ieShWYXJpYWJsZSkgJT4lCiAgICBtdXRhdGUoVmFsdWVfc2NhbGVkID0gc2NhbGUoVmFsdWUpWywxXSkgICMgRXN0YW5kYXJpemFyIHBvciB2YXJpYWJsZQogIAogIGdncGxvdChoZWF0bWFwX2RhdGEsIGFlcyh4ID0gQ0tEX1N0YWdlLCB5ID0gVmFyaWFibGUsIGZpbGwgPSBWYWx1ZV9zY2FsZWQpKSArCiAgICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiLCBzaXplID0gMC41KSArCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoVmFsdWUsIDEpKSwgc2l6ZSA9IDMsIGNvbG9yID0gIndoaXRlIikgKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gIiMzQjlBQjIiLCBtaWQgPSAiI0VCQ0MyQSIsIGhpZ2ggPSAiI0YyMUEwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAsIG5hbWUgPSAiWi1zY29yZSIpICsKICAgIGxhYnModGl0bGUgPSAiUGVyZmlsIENsw61uaWNvIFByb21lZGlvIHBvciBFc3RhZGlvIGRlIENLRCIsCiAgICAgICAgIHggPSAiRXN0YWRpbyBkZSBFbmZlcm1lZGFkIFJlbmFsIiwKICAgICAgICAgeSA9ICJWYXJpYWJsZSBDbMOtbmljYSIsCiAgICAgICAgIGNhcHRpb24gPSAiVmFsb3JlcyBlc3RhbmRhcml6YWRvcyAoWi1zY29yZXMpIC0gbsO6bWVyb3MgPSB2YWxvciByZWFsIHByb21lZGlvIikgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpKQp9CmBgYAoKYGBge3J9CnBsb3RfcGFyYWxsZWxfY29vcmRpbmF0ZXMgPC0gZnVuY3Rpb24oZGF0YSkgewogIHBhcmFsbGVsX2RhdGEgPC0gZGF0YSAlPiUKICAgIHNlbGVjdChCTUksIFBoeXNpY2FsQWN0aXZpdHksIERpZXRRdWFsaXR5LCBTbGVlcFF1YWxpdHksCiAgICAgICAgICAgQWxjb2hvbENvbnN1bXB0aW9uLCBEaWFnbm9zaXMpICU+JQogICAgbXV0YXRlKERpYWdub3NpcyA9IGZhY3RvcihEaWFnbm9zaXMsIGxhYmVscyA9IGMoIk5vIENLRCIsICJDS0QiKSkpICU+JQogICAgbXV0YXRlKGFjcm9zcyhjKEJNSSwgUGh5c2ljYWxBY3Rpdml0eSwgRGlldFF1YWxpdHksIFNsZWVwUXVhbGl0eSwgCiAgICAgICAgICAgICAgICAgICAgQWxjb2hvbENvbnN1bXB0aW9uKSwgc2NhbGUpKQogIAogIHBhcmFsbGVsX2xvbmcgPC0gcGFyYWxsZWxfZGF0YSAlPiUKICAgIHBpdm90X2xvbmdlcihjb2xzID0gYyhCTUksIFBoeXNpY2FsQWN0aXZpdHksIERpZXRRdWFsaXR5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICBTbGVlcFF1YWxpdHksIEFsY29ob2xDb25zdW1wdGlvbiksCiAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiVmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiKSAlPiUKICAgIG11dGF0ZShWYXJpYWJsZSA9IGZhY3RvcihWYXJpYWJsZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQk1JIiwgIlBoeXNpY2FsQWN0aXZpdHkiLCAiRGlldFF1YWxpdHkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNsZWVwUXVhbGl0eSIsICJBbGNvaG9sQ29uc3VtcHRpb24iKSkpCiAgCiAgZ2dwbG90KHBhcmFsbGVsX2xvbmcsIGFlcyh4ID0gVmFyaWFibGUsIHkgPSBWYWx1ZSwgZmlsbCA9IERpYWdub3NpcykpICsKICAgIGdlb21fdmlvbGluKGFscGhhID0gMC42LCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKwogICAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwKICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuOCwgb3V0bGllci5hbHBoYSA9IDAuMykgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8gQ0tEIiA9ICIjMmVjYzcxIiwgIkNLRCIgPSAiI2U3NGMzYyIpKSArCiAgICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgVmFyaWFibGVzIGRlIEVzdGlsbyBkZSBWaWRhIiwKICAgICAgICAgc3VidGl0bGUgPSAiQ29tcGFyYWNpw7NuIGNvbXBsZXRhIGRlbCBkYXRhc2V0ICh2aW9saW4gKyBib3hwbG90KSIsCiAgICAgICAgIHkgPSAiVmFsb3IgRXN0YW5kYXJpemFkbyAoWi1zY29yZSkiLAogICAgICAgICB4ID0gTlVMTCkgKwogICAgdGhlbWVfbWluaW1hbCgpICsKICAgIHRoZW1lKAogICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHNpemUgPSAxMCksCiAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNCksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMCksCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgICApCn0KYGBgCgpgYGB7cn0KcGxvdF9kZW1vZ3JhcGhpY19ib3hwbG90cyA8LSBmdW5jdGlvbihkYXRhKSB7CiAgZGF0YV9kZW1vIDwtIGRhdGEgJT4lCiAgICBtdXRhdGUoCiAgICAgIEdlbmRlciA9IGZhY3RvcihHZW5kZXIsIGxhYmVscyA9IGMoIk1hbGUiLCAiRmVtYWxlIikpLAogICAgICBFdGhuaWNpdHkgPSBmYWN0b3IoRXRobmljaXR5LCBsYWJlbHMgPSBjKCJDYXVjYXNpYW4iLCAiQWZyaWNhbiBBbWVyaWNhbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc2lhbiIsICJPdGhlciIpKSwKICAgICAgU29jaW9lY29ub21pY1N0YXR1cyA9IGZhY3RvcihTb2Npb2Vjb25vbWljU3RhdHVzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJMb3ciLCAiTWlkZGxlIiwgIkhpZ2giKSkKICAgICkgJT4lCiAgICBzZWxlY3QoR2VuZGVyLCBFdGhuaWNpdHksIFNvY2lvZWNvbm9taWNTdGF0dXMsIEdGUiwgSGJBMWMsIAogICAgICAgICAgIFN5c3RvbGljQlAsIFF1YWxpdHlPZkxpZmVTY29yZSkgJT4lCiAgICBwaXZvdF9sb25nZXIoY29scyA9IGMoR0ZSLCBIYkExYywgU3lzdG9saWNCUCwgUXVhbGl0eU9mTGlmZVNjb3JlKSwKICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJCaW9tYXJrZXIiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiKQogIAogIGdncGxvdChkYXRhX2RlbW8sIGFlcyh4ID0gU29jaW9lY29ub21pY1N0YXR1cywgeSA9IFZhbHVlLCBmaWxsID0gR2VuZGVyKSkgKwogICAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43LCBvdXRsaWVyLnNpemUgPSAwLjUpICsKICAgIGZhY2V0X2dyaWQoQmlvbWFya2VyIH4gRXRobmljaXR5LCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKwogICAgbGFicyh0aXRsZSA9ICJCaW9tYXJjYWRvcmVzIHBvciBEZW1vZ3JhZsOtYSAoR8OpbmVybywgRXRuaWNpZGFkLCBFc3RhdHVzIFNvY2lvZWNvbsOzbWljbykiLAogICAgICAgICB4ID0gIkVzdGF0dXMgU29jaW9lY29uw7NtaWNvIiwKICAgICAgICAgeSA9ICJWYWxvciBkZWwgQmlvbWFyY2Fkb3IiKSArCiAgICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSA4KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBzaXplID0gMTEpKQp9CmBgYAoKYGBge3J9CnBsb3RfcW9sX2J1YmJsZSA8LSBmdW5jdGlvbihkYXRhKSB7CiAgbl9wZXJfZ3JvdXAgPSA1MAogIGJ1YmJsZV9kYXRhIDwtIGRhdGEgJT4lCiAgICBtdXRhdGUoCiAgICAgIFNldmVyaXR5X1Njb3JlID0gKFNlcnVtQ3JlYXRpbmluZSAtIG1pbihTZXJ1bUNyZWF0aW5pbmUpKSAvIAogICAgICAgIChtYXgoU2VydW1DcmVhdGluaW5lKSAtIG1pbihTZXJ1bUNyZWF0aW5pbmUpKSAqIDEwLAogICAgICBEaWFnbm9zaXMgPSBmYWN0b3IoRGlhZ25vc2lzLCBsYWJlbHMgPSBjKCJObyBDS0QiLCAiQ0tEIikpCiAgICApICU+JQogICAgZ3JvdXBfYnkoRGlhZ25vc2lzKSAlPiUKICAgIHNsaWNlX3NhbXBsZShuID0gbl9wZXJfZ3JvdXApICU+JSAgIyBFeGFjdGFtZW50ZSBuX3Blcl9ncm91cCBkZSBjYWRhIHVubwogICAgdW5ncm91cCgpCiAgCiAgZ2dwbG90KGJ1YmJsZV9kYXRhLCBhZXMoeCA9IEZhdGlndWVMZXZlbHMsIHkgPSBRdWFsaXR5T2ZMaWZlU2NvcmUpKSArCiAgICBnZW9tX3BvaW50KGFlcyhzaXplID0gU2V2ZXJpdHlfU2NvcmUsIGNvbG9yID0gR0ZSKSwgCiAgICAgICAgICAgICAgIGFscGhhID0gMC43LCBzaGFwZSA9IDE2KSArCiAgICBzY2FsZV9jb2xvcl92aXJpZGlzX2Mob3B0aW9uID0gIm1hZ21hIiwgZGlyZWN0aW9uID0gLTEsIAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiR0ZSXG4obUwvbWluLzEuNzNtwrIpIikgKwogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygyLCAxMCksIAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiU2V2ZXJpZGFkXG4oQ3JlYXRpbmluYSkiKSArCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFRSVUUsIGNvbG9yID0gImJsYWNrIiwgCiAgICAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLCBsaW5ld2lkdGggPSAxKSArCiAgICBmYWNldF93cmFwKH5EaWFnbm9zaXMsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgbGFicyh0aXRsZSA9ICJDYWxpZGFkIGRlIFZpZGEgdnMgRmF0aWdhIHBvciBEaWFnbsOzc3RpY28iLAogICAgICAgICBzdWJ0aXRsZSA9IHNwcmludGYoIiVkIHBhY2llbnRlcyBwb3IgZ3J1cG8gfCBTZXZlcmlkYWQgZW4gdGFtYcOxbyB8IEdGUiBlbiBjb2xvciIsIG5fcGVyX2dyb3VwKSwKICAgICAgICAgeCA9ICJOaXZlbCBkZSBGYXRpZ2EgKDAtMTApIiwKICAgICAgICAgeSA9ICJTY29yZSBkZSBDYWxpZGFkIGRlIFZpZGEgKDAtMTAwKSIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZSgKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KSwKICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEwKSwKICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTEpLAogICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpCiAgICApCn0KYGBgCgpgYGB7cn0KcGxvdF9saWZlc3R5bGVfdnNfZ2ZyIDwtIGZ1bmN0aW9uKGRhdGEpIHsKICBuX3Blcl9ncm91cCA9IDEwMAogICMgQ3JlYXIgSGVhbHRoeSBMaWZlc3R5bGUgU2NvcmUKICBsaWZlc3R5bGVfZGF0YSA8LSBkYXRhICU+JQogICAgbXV0YXRlKAogICAgICAjIE5vcm1hbGl6YXIgY2FkYSBjb21wb25lbnRlIGEgZXNjYWxhIDAtMTAKICAgICAgUEFfc2NvcmUgPSAoUGh5c2ljYWxBY3Rpdml0eSAvIDEwKSAqIDEwLCAgIyBZYSBlc3TDoSBlbiAwLTEwCiAgICAgIERpZXRfc2NvcmUgPSBEaWV0UXVhbGl0eSwgICMgWWEgZXN0w6EgZW4gMC0xMAogICAgICBTbGVlcF9zY29yZSA9ICgoU2xlZXBRdWFsaXR5IC0gNCkgLyAoMTAgLSA0KSkgKiAxMCwgICMgTm9ybWFsaXphciBkZSA0LTEwIGEgMC0xMAogICAgICBOb1Ntb2tpbmdfc2NvcmUgPSAoMSAtIFNtb2tpbmcpICogMTAsICAjIEludmVydGlyOiBubyBmdW1hciA9IDEwCiAgICAgIExvd0FsY29ob2xfc2NvcmUgPSAoKDIwIC0gQWxjb2hvbENvbnN1bXB0aW9uKSAvIDIwKSAqIDEwLCAgIyBJbnZlcnRpcjogYmFqbyBhbGNvaG9sID0gYWx0byBzY29yZQogICAgICAKICAgICAgIyBDYWxjdWxhciBzY29yZSBwcm9tZWRpbwogICAgICBIZWFsdGh5TGlmZXN0eWxlU2NvcmUgPSAoUEFfc2NvcmUgKyBEaWV0X3Njb3JlICsgU2xlZXBfc2NvcmUgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTm9TbW9raW5nX3Njb3JlICsgTG93QWxjb2hvbF9zY29yZSkgLyA1LAogICAgICAKICAgICAgRGlhZ25vc2lzID0gZmFjdG9yKERpYWdub3NpcywgbGFiZWxzID0gYygiTm8gQ0tEIiwgIkNLRCIpKQogICAgKSAlPiUKICAgIGdyb3VwX2J5KERpYWdub3NpcykgJT4lCiAgICBzbGljZV9zYW1wbGUobiA9IG5fcGVyX2dyb3VwKSAlPiUKICAgIHVuZ3JvdXAoKQogIAogIGdncGxvdChsaWZlc3R5bGVfZGF0YSwgYWVzKHggPSBIZWFsdGh5TGlmZXN0eWxlU2NvcmUsIHkgPSBHRlIpKSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IERpYWdub3Npcywgc2l6ZSA9IFNlcnVtQ3JlYXRpbmluZSksIGFscGhhID0gMC42KSArCiAgICBnZW9tX3Ntb290aChhZXMoY29sb3IgPSBEaWFnbm9zaXMpLCBtZXRob2QgPSAibG0iLCBzZSA9IFRSVUUsIGxpbmV3aWR0aCA9IDEuMikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk5vIENLRCIgPSAiIzJlY2M3MSIsICJDS0QiID0gIiNlNzRjM2MiKSkgKwogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygxLCA2KSwgbmFtZSA9ICJDcmVhdGluaW5hXG4obWcvZEwpIikgKwogICAgbGFicyh0aXRsZSA9ICJFc3RpbG8gZGUgVmlkYSBTYWx1ZGFibGUgdnMgRnVuY2nDs24gUmVuYWwgKEdGUikiLAogICAgICAgICBzdWJ0aXRsZSA9IHNwcmludGYoIk11ZXN0cmE6ICVkIHBhY2llbnRlcyBwb3IgZ3J1cG8iLCBuX3Blcl9ncm91cCksCiAgICAgICAgIHggPSAiSGVhbHRoeSBMaWZlc3R5bGUgU2NvcmUgKDAtMTApIiwKICAgICAgICAgeSA9ICJHRlIgKG1ML21pbi8xLjczbcKyKSIpICsKICAgIHRoZW1lX21pbmltYWwoKSArCiAgICB0aGVtZSgKICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0KSwKICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEwLCBjb2xvciA9ICJncmF5MzAiKSwKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKQogICAgKQp9CmBgYAoKYGBge3J9CmdlbmVyYXRlX2FsbF9wbG90cyA8LSBmdW5jdGlvbihkYXRhKSB7CiAgcGxvdHMgPC0gbGlzdCgpCiAgCiAgY2F0KCJHZW5lcmFuZG8gdmlzdWFsaXphY2lvbmVzIG11bHRpdmFyaWFibGVzIHByaW9yaXphZGFzLi4uXG5cbiIpCiAgCiAgY2F0KCIxLiBQYWlycGxvdCBkZSBWYXJpYWJsZXMgUmVuYWxlcyAoQW7DoWxpc2lzIHByaW5jaXBhbCkuLi5cbiIpCiAgcGxvdHMkcmVuYWxfcGFpcnMgPC0gcGxvdF9yZW5hbF9wYWlycyhkYXRhKQogIHByaW50KHBsb3RzJHJlbmFsX3BhaXJzKQogIAogIGNhdCgiMi4gSGVhdG1hcCBkZSBQZXJmaWxlcyBDbMOtbmljb3MgKENsdXN0ZXJzIHkgcGF0cm9uZXMpLi4uXG4iKQogIHBsb3RzJGhlYXRtYXAgPC0gcGxvdF9jbGluaWNhbF9oZWF0bWFwKGRhdGEpCiAgcHJpbnQocGxvdHMkaGVhdG1hcCkKICAKICBjYXQoIjMuIExpZmVzdHlsZSBTY29yZSB2cyBHRlIgKEltcGFjdG8gY29uZHVjdHVhbCkuLi5cbiIpCiAgcGxvdHMkbGlmZXN0eWxlX2dmciA8LSBwbG90X2xpZmVzdHlsZV92c19nZnIoZGF0YSkKICBwcmludChwbG90cyRsaWZlc3R5bGVfZ2ZyKQogIAogIGNhdCgiNC4gU2NhdHRlcnBsb3QgNEQgKEdGUi1DcmVhdGluaW5hLUVkYWQtQk1JKS4uLlxuIikKICBwbG90cyRnZnJfM2QgPC0gcGxvdF9nZnJfM2QoZGF0YSkKICBwcmludChwbG90cyRnZnJfM2QpCiAgCiAgY2F0KCI1LiBQYXJhbGxlbCBDb29yZGluYXRlcyAoRmFjdG9yZXMgZGUgUmllc2dvKS4uLlxuIikKICBwbG90cyRwYXJhbGxlbCA8LSBwbG90X3BhcmFsbGVsX2Nvb3JkaW5hdGVzKGRhdGEpCiAgcHJpbnQocGxvdHMkcGFyYWxsZWwpCiAgCiAgY2F0KCI2LiBCb3hwbG90cyBEZW1vZ3LDoWZpY29zIEZhY2V0YWRvcy4uLlxuIikKICBwbG90cyRkZW1vX2JveCA8LSBwbG90X2RlbW9ncmFwaGljX2JveHBsb3RzKGRhdGEpCiAgcHJpbnQocGxvdHMkZGVtb19ib3gpCiAgCiAgY2F0KCI3LiBCdWJibGUgQ2hhcnQgKENhbGlkYWQgZGUgVmlkYSkuLi5cbiIpCiAgcGxvdHMkYnViYmxlIDwtIHBsb3RfcW9sX2J1YmJsZShkYXRhKQogIHByaW50KHBsb3RzJGJ1YmJsZSkKICAKICBjYXQoIlxuIFRvZGFzIGxhcyB2aXN1YWxpemFjaW9uZXMgZ2VuZXJhZGFzIHkgcHJpb3JpemFkYXMgY29ycmVjdGFtZW50ZS5cbiIpCiAgCiAgcmV0dXJuKGludmlzaWJsZShwbG90cykpCn0KCgpgYGAKCmBgYHtyfQpwbG90cyA8LSBnZW5lcmF0ZV9hbGxfcGxvdHMoY2tkX2RhdGEpCmBgYAoKCg==