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==