Introduccion

En este reporte están los códigos de los resultados de la tesis de Pregrado Elaboracion de una matriz de respuestas biológicas frente a la temperatura e hipoxia para la evaluación de riesgos en cultivo de fondo de Argopecten purpuratus, concha de abanico, en la Bahía de Sechura

Para la ejecución de la tesis se utilizaron los datos del artículo Cueto-Vega et al. 2022 y los datos recopilados por Aguirre-Velarde durante la mortalidad de concha de abanico del 2019.

Programa de monitoreo Parámetro ambiental Periodo de registro
Cueto-Vega et al.2022 Temperatura y Saturacion OD 07/11/2013-07/10/2015 & 23/03/2017-07/02/2018
Aguirre-Velarde Temperatura y Saturacion OD 08/01/2019-26/03/2019

Limpiando los datos

Para limpiar las base de datos se seguiran los siguientes pasos:

  1. Uniformizar el formato de las horas: timezone UTC, con el nombre Hora_Lima
  2. Asignar el mismo nombre a la variable temperatura de fondo: Temp_fond
  3. Asignar el mismo nombre a la variable saturacion de oxigeno disuelto: DO_sat
  4. En caso haya mas de un dato por hora, btener un valor promedio
  5. Verificar si hay filas duplicadas, valores NA, valores negativos.
  6. Asignar una columna con el nombre de la base de datos de origen.

Limpieza de bdd: Cueto-Vega et al. 2022

constante_loggers <- read_csv("datos/bd-ARTURO-PICES_Sechura_Stressors/CONSTANTE_loggers_historico.csv") %>%
  mutate(
    Hora_Lima = as.POSIXct(Hora_Lima, format = "%Y-%m-%d %H:%M:%S", tz = "UTC"),
    Temp_fond = Temp  
    ) %>%
  select(Hora_Lima, Temp_fond, DO_sat) %>%
  group_by(Hora_Lima) %>% 
  summarise(
    Temp_fond = mean(Temp_fond, na.rm = TRUE),
    DO_sat = mean(DO_sat, na.rm = TRUE)
    ) 

valores_duplicados <- constante_loggers$Hora_Lima[duplicated(constante_loggers$Hora_Lima)]
print(unique(valores_duplicados)) 

colSums(is.na(constante_loggers))  
eliminar <- which(apply(is.na(constante_loggers), 1, any)) #Hay 11821 filas que no tiene datos de DO_sat
constante_loggers <- constante_loggers[-eliminar, ] 
colSums(is.nan(as.matrix(constante_loggers)))  
any(constante_loggers < 0, na.rm = TRUE)
constante_loggers <- filter(constante_loggers, DO_sat >= 0, DO_sat <=100, !is.na(DO_sat))

constante_loggers <- constante_loggers %>%
  mutate(
    bdd = "Cueto-Vega_2022",
    Zona = "Constante") 

Limpeza de bdd: Aguirre-Velarde 2019 Los datos recopilados por Aguirre-Velarde en el 2019 estan conformados por dos archivos csv:

  • Constante_loggers.csv (08 enero 2019 - 04 marzo 2019)
### BDD Constante_loggers ####
constante_TDO <- read.csv("datos/Informe_SechuraMort2019/Constante_loggers.csv", header = TRUE, dec = ".", sep = ",") %>%
  mutate(
    Hora_Lima = as.POSIXct(Hora_Lima, format = "%d/%m/%Y %H:%M", tz="UTC"),
    Temp_fond = Temp  
    ) %>%
  select(Hora_Lima, Temp_fond, DO_sat) %>%
  group_by(Hora_Lima) %>% 
  summarise(
    Temp_fond = mean(Temp_fond, na.rm = TRUE),
    DO_sat = mean(DO_sat, na.rm = TRUE)
    )

valores_duplicados <- constante_TDO$Hora_Lima[duplicated(constante_TDO$Hora_Lima)]
print(unique(valores_duplicados)) 

colSums(is.na(constante_TDO))  
which(apply(is.na(constante_TDO), 1, any)) #La fila 1321 no tiene datos
constante_TDO <- constante_TDO[-1321, ]

colSums(is.nan(as.matrix(constante_TDO)))  

any(constante_TDO < 0, na.rm = TRUE)

constante_TDO <- constante_TDO %>%
  mutate(
    bdd = "Constante_TDO",
    Zona = "Constante")  
  • Constante_multi.csv (05 marzo - 26 de marzo 2019)

En esta base de datos, el oxígeno esta en mg/L, por lo que se debe convertir DO_c (mg/l) en DO_sat (%). Para ello, se seguirán las ecuaciones propuestas por Benson y Krause, 1984; utilizadas por YDOC: empresa holandesa especializada en mediciones por data loggers.

### BDD constante_multi ######
constante_multi <- read.csv("datos/Informe_SechuraMort2019/constante_multi.csv", 
                            header = TRUE, dec = ".", sep = ",") %>%
  mutate(
    Hora_Lima = as.POSIXct(Hora_Lima, format = "%d/%m/%Y %H:%M:%S", tz="UTC"),
    Hora_Lima = make_datetime(year(Hora_Lima), month(Hora_Lima), day(Hora_Lima), hour(Hora_Lima)),
    DO_c = DO_fond,  
    Temp_fond = T_fond,
    Temp_kelvin = Temp_fond + 273.15  # Convertir temperatura a Kelvin
  ) %>%
  select(Hora_Lima, Temp_fond, Temp_kelvin, DO_c) %>%
  group_by(Hora_Lima) %>%
  summarise(
    Temp_fond = mean(Temp_fond, na.rm = TRUE),
    DO_c = mean(DO_c, na.rm = TRUE),
    Temp_kelvin=mean(Temp_kelvin, na.rm=TRUE)
  )

valores_duplicados <- constante_multi$Hora_Lima[duplicated(constante_multi$Hora_Lima)]
print(unique(valores_duplicados))

colSums(is.na(constante_multi))
eliminar <- which(apply(is.na(constante_multi), 1, any))
constante_multi <- constante_multi[-eliminar,] 
colSums(is.nan(as.matrix(constante_multi)))

any(constante_TDO < 0, na.rm = TRUE)

## Convertir DO_c (mg/l) en DO_sat (%) siguiendo ecuaciones de Benson and Krause, 1984
# Definir salinidad en ppt (g/kg)
SAL <- 35

# Calcular DO_C (corrigiendo por salinidad)
constante_multi <- constante_multi %>%
  mutate(
    DO_C = DO_c * exp(-1 * SAL * (0.017674 + (-10.754 + 2140.7 / Temp_kelvin) / Temp_kelvin))
  )

# Calcular DO saturado en mg/L
constante_multi <- constante_multi %>%
  mutate(
    DO_sat_mgL = exp(-139.34411 + (1.575701e5 + (-6.642308e7 + 
                                                   (1.2438e10 - 8.621949e11 / Temp_kelvin) / Temp_kelvin) / Temp_kelvin) / Temp_kelvin) *
      exp(-1 * SAL * (0.017674 + (-10.754 + 2140.7 / Temp_kelvin) / Temp_kelvin))
  )

# Calcular DO saturado en % 
constante_multi <- constante_multi %>%
  mutate(
    DO_sat = (DO_C / DO_sat_mgL) * 100
  ) %>%
select(Hora_Lima, Temp_fond, DO_sat) 

#Agregar columnas bdd
constante_multi <- constante_multi %>%
  mutate(
    bdd = "Constante_multi",
    Zona = "Constante") 

Finalmente, las bases de datos se unirán en una sola, la cual será llamada “constante”. En esta nueva bdd, se agregará la columna “Mortalidad”.

  • Mortalidad 2015: 21 febrero - 02 marzo - 15 marzo 2015
  • Mortalidad 2019: 19 febrero - 04 marzo - 13 marzo 2019
  • No mortalidad: resto de datos
barrancos <- read_csv("datos/bd-ARTURO-PICES_Sechura_Stressors/BARRANCOS_loggers_historico.csv") %>%
  mutate(
    Hora_Lima = as.POSIXct(Hora_Lima, format = "%Y-%m-%d %H:%M:%S", tz = "UTC"),
    Temp_fond = Temp  
  ) %>%
  select(Hora_Lima, Temp_fond, DO_sat) %>%
  group_by(Hora_Lima) %>% 
  summarise(
    Temp_fond = mean(Temp_fond, na.rm = TRUE),
    DO_sat = mean(DO_sat, na.rm = TRUE)
  ) 
  valores_duplicados <- barrancos$Hora_Lima[duplicated(barrancos$Hora_Lima)]
  a <- colSums(is.na(barrancos))  
  eliminar <- which(apply(is.na(barrancos), 1, any)) 
  barrancos <- barrancos[-eliminar, ] 
  a <- colSums(is.nan(as.matrix(barrancos)))  
  a <- any(barrancos < 0, na.rm = TRUE)
  barrancos <- filter(barrancos, DO_sat >= 0, DO_sat <=100, !is.na(DO_sat))
  barrancos <- barrancos %>%
    mutate(
      bdd = "Cueto-Vega_2022",
      Zona = "Barrancos")  

  barrancos_filtr <- barrancos %>%
  filter(Hora_Lima >= as.POSIXct("2015-02-21", tz="UTC") & Hora_Lima <= as.POSIXct("2015-03-15", tz="UTC"))
constante <-  bind_rows(constante_loggers, constante_TDO, constante_multi) 

total <-  bind_rows(constante, barrancos_filtr) 

total <- total %>%
  mutate(
    Year = format(Hora_Lima, "%Y"),  # Extraer el año
    Mortalidad = case_when(
      (Zona == "Barrancos" & Hora_Lima >= as.POSIXct("2015-02-21", tz = "UTC") & Hora_Lima < as.POSIXct("2015-03-15", tz = "UTC")) ~ "Mortalidad 2015 - Barrancos",
      (Zona == "Constante" & Hora_Lima >= as.POSIXct("2015-02-21", tz = "UTC") & Hora_Lima < as.POSIXct("2015-03-15", tz = "UTC")) ~ "Mortalidad 2015 - Constante",
      (Zona == "Constante" & Hora_Lima >= as.POSIXct("2019-02-19", tz = "UTC") & Hora_Lima < as.POSIXct("2019-03-13", tz = "UTC")) ~ "Mortalidad 2019 - Constante",
      TRUE ~ "No Mortalidad"
    )
  )

# Contar observaciones por categoría de Mortalidad y Zona
conteo_obs <- total %>%
  group_by(Mortalidad) %>%
  summarise(Conteo = n(), .groups = "drop")

# Ver los resultados
print(conteo_obs)

Visualizacion de datos:

Mortalidad 2015 y 2019

De oxígeno disuelto y temperatura, en fondo, durante la mortalidad 2015 y 2019

Diferencias durante la Mortalidad 2015: Barrancos vs Constante??

# Función para agregar grupos según huecos mayores a 24 horas
agregar_grupos <- function(data) {
  data <- data %>%
    arrange(Hora_Lima) %>%  # Asegúrate de que esté ordenado por tiempo
    mutate(
      time_diff = as.numeric(difftime(Hora_Lima, lag(Hora_Lima), units = "hours")),
      group = cumsum(ifelse(is.na(time_diff) | time_diff > 24, 1, 0))
    )
  return(data)
}

#Periodos a graficar 
barrancos_2015 <- barrancos %>%
  filter(Hora_Lima >= as.POSIXct("2015-01-08", tz="UTC") & Hora_Lima <= as.POSIXct("2015-03-18", tz="UTC"))

constante_2015 <- constante %>%
  filter(Hora_Lima >= as.POSIXct("2015-01-08", tz="UTC") & Hora_Lima <= as.POSIXct("2015-03-18", tz="UTC"))

constante_2019 <- constante %>%
  filter(Hora_Lima >= as.POSIXct("2019-01-08", tz="UTC") & Hora_Lima <= as.POSIXct("2019-03-18", tz="UTC"))

# Aplicar la función a los datasets
barrancos_2015 <- agregar_grupos(barrancos_2015)
constante_2015 <-  agregar_grupos(constante_2015)
constante_2019 <- agregar_grupos(constante_2019)

# Actualizar los gráficos para usar 'group'
grafico_barrancos_2015 <- ggplot(barrancos_2015, aes(x = Hora_Lima, y = DO_sat, group = group)) +
  geom_rect(aes(xmin = as.POSIXct("2015-03-02", tz = "UTC"),
                xmax = as.POSIXct("2015-03-14", tz = "UTC"),
                ymin = -Inf, ymax = Inf),
            fill = "pink", alpha = 0.03) +  
  geom_line(color = "black", size = 0.5) +  
  geom_hline(yintercept = 24.4, color = "red", linetype = "solid", size = 0.5) +  
  annotate("text", x = as.POSIXct("2015-01-17", tz = "UTC"), y = 26.5,
           label = "Punto crítico de oxígeno", color = "red", size = 4) +
  scale_x_datetime(date_breaks = "1 week", date_labels = "%d/%b") +  
  labs( x="",
    y = "Saturación de oxígeno (%)",
    title = "Mortalidad 2015 - Barrancos") +
  theme_minimal(base_size = 12) 

grafico_constante_2015 <- ggplot(constante_2015, aes(x = Hora_Lima, y = DO_sat, group = group)) +
  geom_rect(aes(xmin = as.POSIXct("2015-03-02", tz = "UTC"),
                xmax = as.POSIXct("2015-03-14", tz = "UTC"),
                ymin = -Inf, ymax = Inf),
            fill = "pink", alpha = 0.03) +  
  geom_line(color = "black", size = 0.5) +  
  geom_hline(yintercept = 24.4, color = "red", linetype = "solid", size = 0.5) +  
  annotate("text", x = as.POSIXct("2015-01-18", tz = "UTC"), y = 26.5,
           label = "Punto crítico de oxígeno", color = "red", size = 4) +
  scale_x_datetime(date_breaks = "1 week", date_labels = "%d/%b") +  
  labs( x= "",
    y = "Saturación de oxígeno (%)", title = "Mortalidad 2015 - Constante") +
  theme_minimal(base_size = 12) 

grafico_constante_2019 <- ggplot(constante_2019, aes(x = Hora_Lima, y = DO_sat, group = group)) +
  geom_rect(aes(xmin = as.POSIXct("2019-03-04", tz = "UTC"),
                xmax = as.POSIXct("2019-03-13", tz = "UTC"),
                ymin = -Inf, ymax = Inf),
            fill = "pink", alpha = 0.03) +  
  geom_line(color = "black", size = 0.5) +  
  geom_hline(yintercept = 24, color = "red", linetype = "solid", size = 0.5) +  
  annotate("text", x = as.POSIXct("2019-01-16", tz = "UTC"), y = 26.5,
           label = "Punto crítico de oxígeno", color = "red", size = 4) +
  scale_x_datetime(date_breaks = "1 week", date_labels = "%d/%b") + 
  labs(y = "Saturación de oxígeno (%)", title = "Mortalidad 2019", x = "Tiempo (día/mes)") +
  theme_minimal(base_size = 12) 

# Combinar los gráficos
grid.arrange(
  grafico_barrancos_2015, 
  grafico_constante_2015, 
  grafico_constante_2019, 
  ncol = 1)

Análisis estadísticos

ver cuantos datos por grupo : cuantos registros por hora para cada tipo de mortalidad (histograma) ver normalidad de los datos por grupo

Deberia hacer bootstrapping?

Para realizar el análisis estadístico, se llevará a cabo un análisis preliminar para determinar si los datos cumplen con los requisitos para realizar análisis paramétricos o no paramétricos. Este análisis preliminar incluirá las pruebas de normalidad (Shapiro-Wilk) y homogeneidad de varianzas (Levene). Dependiendo de los resultados de este análisis preliminar, se emplearán las pruebas estadísticas adecuadas para determinar si existen diferencias significativas (p-valor < 0.05) durante el tiempo de muestreo. Si los datos cumplen con los supuestos de normalidad y homogeneidad de varianzas, se utilizará el análisis de varianza (ANOVA). En caso contrario, se emplearán pruebas no paramétricas como la prueba de Kruskal-Wallis. Los análisis y gráficos serán realizados en R Studio (versión 4. 3. 0; R Core Team, 2023).

Normalidad - Prueba de Shapiro-Wilk

Resultados

# Categorías únicas de mortalidad
categorias <- c("Mortalidad 2015 - Barrancos","Mortalidad 2015 - Constante","Mortalidad 2019 - Constante")

# Función para evaluar cada categoría
shapiro <- function(categoria, data) {
  # Filtrar el grupo
  datos <- data %>% filter(Mortalidad == categoria)
  
  # Normalidad: Shapiro-Wilk
  shapiro_result <- shapiro.test(datos$DO_sat)
  print(paste("Prueba de Shapiro-Wilk para", categoria, ":", shapiro_result$p.value))
  
}

# Aplicar la función a cada categoría
walk(categorias, ~ shapiro(.x, total))
## [1] "Prueba de Shapiro-Wilk para Mortalidad 2015 - Barrancos : 8.25766075342584e-14"
## [1] "Prueba de Shapiro-Wilk para Mortalidad 2015 - Constante : 2.85939201546272e-09"
## [1] "Prueba de Shapiro-Wilk para Mortalidad 2019 - Constante : 3.45117739406515e-16"
datos_nomortalidad<- total %>%
  filter(Mortalidad == "No Mortalidad")
kolmogorov_result <- ks.test(x=datos_nomortalidad$DO_sat,y='pnorm',alternative='two.sided')
  print(paste("Prueba de Kolmogorov-Smirnov para el periodo de No Mortalidad:",
            format(kolmogorov_result$p.value, scientific = TRUE)))
## [1] "Prueba de Kolmogorov-Smirnov para el periodo de No Mortalidad: 0e+00"

Plots

# Categorías únicas de mortalidad
categorias <- c("Mortalidad 2015 - Barrancos","Mortalidad 2015 - Constante","Mortalidad 2019 - Constante", "No Mortalidad")
# Función para procesar cada categoría
plots <- function(categoria, data) {
  # Filtrar el grupo
  datos <- data %>% filter(Mortalidad == categoria)
  
  # Curva de densidad
  densidad <- ggplot(datos, aes(x = DO_sat)) +
    geom_density(fill = "#56B4E9", alpha = 0.5, color = "#0072B2", size = 1.2) +
    labs(
      title = paste("Curva de densidad -", categoria),
      x = "Saturación de Oxígeno (DO_sat)",
      y = "Densidad"
    ) +
    theme_minimal(base_size = 14) +
    theme(
      plot.title = element_text(face = "bold", size = 16),
      axis.title = element_text(size = 14)
    )

  # Boxplot horizontal
  boxplot <- ggplot(datos, aes(x = DO_sat, y = "")) +
    geom_boxplot(fill = "#E69F00", color = "black", alpha = 0.7, width = 0.3) +
    labs(x = "Saturación de Oxígeno (DO_sat)", y = "") +
    theme_minimal(base_size = 14) +
    theme(
      axis.title.y = element_blank(),
      axis.text.y = element_blank(),
      axis.ticks.y = element_blank(),
      plot.title = element_blank()
    )

  # Combinar el gráfico de densidad y el boxplot
  combinado <- densidad / boxplot + plot_layout(heights = c(3, 1))
  print(combinado)
}

# Aplicar la función a cada categoría
walk(categorias, ~ plots(.x, total))

Homogeneidad de varianzas - Prueba de Levene

Resultados

# Homogeneidad de varianzas: Prueba de Levene
levene_result <- leveneTest(DO_sat ~ Mortalidad, data = total)
# Extraer el valor p del resultado
p_value_levene <- signif(levene_result$`Pr(>F)`[1], digits = 3)
# Crear un mensaje personalizado
cat("Prueba de Levene para homogeneidad de varianzas: p =", p_value_levene, "\n")
## Prueba de Levene para homogeneidad de varianzas: p = 1.29e-84

Plots

ggplot(total, aes(x = Mortalidad, y = DO_sat, fill = Mortalidad)) +
  geom_boxplot(alpha = 0.7, outlier.shape = NA) + # Sin outliers para no duplicar puntos
  geom_jitter(width = 0.2, size = 2, alpha = 0.6, color = "black") +
  scale_fill_manual(values = c("#56B4E9", "#E69F00", "#009E73", "#D55E00")) +
  labs(
    title = "Dispersion de SatOD por Mortalidad",
    x = "Mortalidad",
    y = ""
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "none"
  )

ggplot(total, aes(x = DO_sat, fill = Mortalidad)) +
  geom_density(alpha = 0.6) +
  scale_fill_manual(values = c("#56B4E9", "#E69F00", "#009E73", "#D55E00")) +
  labs(
    title = "Densidad de DO_sat por Mortalidad",
    x = "(DO_sat)",
    y = "Densidad"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.title = element_blank()
  )

Pruebas No Parametricas

Si los datos no son normales o no cumplen la homogeneidad: Usar la prueba de Kruskal-Wallis seguida de un análisis post-hoc (Dunn o Wilcoxon) para comparaciones múltiples. comparacion con unequal variances??

# # Kruskal-Wallis
kruskal_result <- kruskal.test(DO_sat ~ Mortalidad, data = total)
kruskal_result
## 
##  Kruskal-Wallis rank sum test
## 
## data:  DO_sat by Mortalidad
## Kruskal-Wallis chi-squared = 800.2, df = 3, p-value < 2.2e-16
# Post-hoc con Dunn
dunn_result <- dunnTest(DO_sat ~ Mortalidad, data = total, method = "bonferroni")

# Extraer los resultados en formato de dataframe
tabla_dunn <- as.data.frame(dunn_result$res)

# Renombrar columnas para que sean más legibles
colnames(tabla_dunn) <- c("Comparacion", "Estadistico Z", "P sin ajustar", "P ajustado")

# Crear la tabla con gt
tabla_dunn %>%
  gt() %>%
  tab_header(
    title = "Resultados del Test de Dunn",
    subtitle = "Comparaciones de Sat_OD entre grupos de Mortalidad"
  ) %>%
  fmt_number(
    columns = c("Estadistico Z", "P sin ajustar", "P ajustado"),
    decimals = 3
  ) %>%
  cols_label(
    `Comparacion` = "Grupos Comparados",
    `Estadistico Z` = "Estadístico Z",
    `P sin ajustar` = "P-valor (sin ajustar)",
    `P ajustado` = "P-valor (ajustado)"
  )
Resultados del Test de Dunn
Comparaciones de Sat_OD entre grupos de Mortalidad
Grupos Comparados Estadístico Z P-valor (sin ajustar) P-valor (ajustado)
Mortalidad 2015 - Barrancos - Mortalidad 2015 - Constante −16.722 0.000 0.000
Mortalidad 2015 - Barrancos - Mortalidad 2019 - Constante 2.694 0.007 0.042
Mortalidad 2015 - Constante - Mortalidad 2019 - Constante 19.150 0.000 0.000
Mortalidad 2015 - Barrancos - No Mortalidad −18.120 0.000 0.000
Mortalidad 2015 - Constante - No Mortalidad 5.219 0.000 0.000
Mortalidad 2019 - Constante - No Mortalidad −21.282 0.000 0.000

Bootstrapping?

Varaibilidad Diaria de la Saturación OD

Para el análisis de datos, primero se realizará la caracterización ambiental de los registros hipóxicos en Constante. Para ello se analizará la variabilidad diaria de la saturación de OD en el fondo, los registros se clasificarán entre día (06:00 – 17:59) y noche (18:00 – 05:59), y se representarán mediante diagrama de cajas. Para evaluar la variabilidad del ciclo diario se ajustará una función sinusoidal a las medianas del análisis del diagrama de caja, con el fin de determinar y comparar la amplitud y la fase del ciclo diario durante el tiempo de muestreo. Este análisis sigue la metodología planteada por Igarza et al. (2024).

# Extraer solo la Hora en una nueva columna
total <- total %>%
  mutate(
    Hora = as.integer(format(Hora_Lima, "%H")),
    DiaNoche = ifelse(Hora >= 6 & Hora <= 17, "Día", "Noche")
  )

# Definir los colores
colores <- c("Día" = "gray100", "Noche" = "gray80")

# Crear el gráfico con boxplots por cada hora
ggplot(total, aes(x = factor(Hora), y = DO_sat, fill = DiaNoche)) +
  geom_boxplot(width = 0.6, alpha = 0.8, outlier.alpha = 0.5, outlier.size = 1) +
  facet_wrap(~ Mortalidad, ncol = 2) +  # Una faceta por cada periodo de mortalidad
  labs(
    x = "Hora del Día",
    y = "Saturación OD (%)",
    fill = "Momento del Día",
    title = "Variabilidad Diara de Saturación de Oxígeno"
  ) +
  scale_x_discrete(breaks = seq(0, 23, by = 2)) +
  scale_fill_manual(values = colores) +
  geom_hline(yintercept = 24.4, linetype = "dashed", color = "red", size = 0.5) +
  theme_minimal() +
  theme(
    strip.background = element_rect(fill = "gray95", color = "black"),  # Fondo de las facetas
    strip.text = element_text(face = "bold", size = 12),  # Texto en las facetas
    axis.text = element_text(size = 10),  # Tamaño de texto de los ejes
    axis.title = element_text(size = 12),  # Tamaño de texto de títulos de ejes
    panel.grid.major = element_blank(),  # Quitar líneas de grilla mayor
    panel.grid.minor = element_blank(),  # Quitar líneas de grilla menor
    axis.line = element_line(color = "black"),  # Añadir líneas de los ejes
    axis.ticks = element_line(color = "black")  # Añadir marcas en los ejes
  )

# 1. Calcular la mediana de DO_sat por Hora y Mortalidad
mediana_por_hora <- total %>%
  group_by(Mortalidad, Hora) %>%
  summarise(
    Mediana_DO_sat = median(DO_sat, na.rm = TRUE),
    .groups = "drop"
  )

# 2. Definir la función sinusoidal
sinusoidal <- function(x, amplitud, frecuencia, fase, desplazamiento) {
  amplitud * sin(frecuencia * x + fase) + desplazamiento
}

# 3. Ajustar la función sinusoidal a los datos
ajustes <- mediana_por_hora %>%
  group_by(Mortalidad) %>%
  summarise(
    # Calcular parámetros iniciales
    amplitud_inicio = (max(Mediana_DO_sat, na.rm = TRUE) - min(Mediana_DO_sat, na.rm = TRUE)) / 2,
    desplazamiento_inicio = mean(Mediana_DO_sat, na.rm = TRUE),
    ajuste = list(
      nlsLM(
        Mediana_DO_sat ~ sinusoidal(Hora, amplitud, frecuencia, fase, desplazamiento),
        data = cur_data(),
        start = list(
          amplitud = amplitud_inicio,
          frecuencia = 2 * pi / 24, # Frecuencia para ciclo de 24 horas
          fase = 0, # Inicialmente sin desplazamiento
          desplazamiento = desplazamiento_inicio
        )
      )
    ),
    .groups = "drop"
  )

# 4. Extraer los parámetros ajustados y corregir amplitud y fase
parametros <- ajustes %>%
  mutate(
    coeficientes = map(ajuste, coef)
  ) %>%
  select(Mortalidad, coeficientes) %>%
  unnest_wider(coeficientes) %>%
  mutate(
    Amplitud = abs(amplitud), # Asegurar amplitud positiva
    Fase = ifelse(amplitud < 0, fase + pi, fase), # Corregir fase si amplitud era negativa
    Horamax = (-Fase / frecuencia) %% 24 # Calcular la hora del máximo y asegurar 0-24
  ) %>%
  select(Mortalidad, Amplitud, Frecuencia = frecuencia, Fase, Desplazamiento = desplazamiento, Horamax)

# Imprimir los parámetros ajustados
print(parametros)
## # A tibble: 4 × 6
##   Mortalidad                  Amplitud Frecuencia  Fase Desplazamiento Horamax
##   <chr>                          <dbl>      <dbl> <dbl>          <dbl>   <dbl>
## 1 Mortalidad 2015 - Barrancos     8.62      0.324  3.30           15.4   13.8 
## 2 Mortalidad 2015 - Constante    12.1       0.353 -2.88           46.0    8.16
## 3 Mortalidad 2019 - Constante     6.92      0.310  3.24           12.6   13.6 
## 4 No Mortalidad                   3.46      0.298  3.24           33.5   13.1
# 5. Crear datos ajustados con la onda sinusoidal
datos_ajustados <- mediana_por_hora %>%
  left_join(parametros, by = "Mortalidad") %>%
  mutate(
    Ajuste = Amplitud * sin(Frecuencia * Hora + Fase) + Desplazamiento
  )

# 6. Graficar datos reales y ajustados con escala fija de 0 a 100
ggplot(datos_ajustados, aes(x = Hora)) +
  geom_line(aes(y = Ajuste, color = Mortalidad), linetype = "dashed") +
  geom_point(aes(y = Mediana_DO_sat, color = Mortalidad), size = 1) +
  facet_wrap(~ Mortalidad, scales = "fixed") +  # Escala fija en Y
  scale_y_continuous(limits = c(0, 60)) +  # Fijar límites de 0 a 100
  labs(
    title = "Ajuste de función sinusoidal",
    x = "Hora del día",
    y = "Mediana de Saturación de Oxígeno (DO_sat)"
  ) +
  theme_minimal()

# 7. Crear datos ajustados sin desplazamiento vertical (solo amplitud y fase)
datos_ajustados_sin_d <- mediana_por_hora %>%
  left_join(parametros, by = "Mortalidad") %>%
  mutate(
    Ajuste_sin_d = Amplitud * sin(Frecuencia * Hora + Fase)  # Eliminar el desplazamiento vertical
  )

# 8. Graficar las ondas sinusoidales sin desplazamiento vertical
ggplot(datos_ajustados_sin_d, aes(x = Hora, y = Ajuste_sin_d, color = Mortalidad)) +
  geom_line(size = 1, linetype = "solid") +
  labs(
    title = "Comparación de ondas sinusoidales",
    x = "Hora del día",
    y = "Oscilación relativa de DO_sat"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    legend.position = "bottom",
    legend.title = element_blank()
  )

La amplitud indica cuánto varía la saturación de oxígeno a lo largo del día, desde el nivel medio (Desplazamiento) hasta los picos (positivos o negativos). Es una medida de la variabilidad diaria:

Mayor amplitud → Mayor variación diaria entre día y noche. Menor amplitud → Ciclo diario menos marcado (saturación más estable).

La frecuencia está relacionada con el número de ciclos completados en un período de tiempo. Interpretación: La frecuencia debería ser aproximadamente 0.2618 si las oscilaciones ocurren exactamente cada 24 horas. Tus resultados tienen ligeras diferencias:

  • Mortalidad 2015 - Constante (0.353): Frecuencia un poco mayor, lo que podría indicar oscilaciones más rápidas (ligeramente desfasadas del ciclo diario perfecto).

  • No Mortalidad (0.298): Frecuencia más baja, lo que sugiere oscilaciones más lentas y un ciclo más “extendido”.

En general, estas pequeñas diferencias podrían deberse a ruido o a fenómenos biológicos que desvíen el ciclo de un patrón estrictamente diario.

La fase indica el desplazamiento horizontal de la onda sinusoidal, es decir, en qué momento del día ocurre el máximo o mínimo de saturación.

Indicadores de hipoxia

Se evaluará la variabilidad de hipoxia mediante los siguientes indicadores: el porcentaje de registros hipóxicos, las horas de hipoxia al día, la mediana de saturación de OD al día y el valor mínimo de saturación de OD al día.

Después del análisis de la variabilidad del ciclo diario de saturación de OD, se realizará el análisis de los eventos hipóxicos. Para determinar un evento hipóxico, este debe ser igual o inferior al 24.4% de saturación de OD y durar al menos seis horas consecutivas (Shields y Weidman, 2008).

Numero de horas hipoxicas al dia

Numero de horas hipoxicas al dia:

# Función para agregar columna de hipoxia
agregar_columna_hipoxia <- function(data) {
  data$Hipoxia <- ifelse(data$DO_sat <= 24.4, 1, 0)
  return(data)
}

total <- agregar_columna_hipoxia(total)

# Función para calcular horas de hipoxia por día
calcular_horas_hipoxia <- function(df) {
  df %>%
    mutate(Dia = as.Date(Hora_Lima)) %>%
    group_by(Dia, Mortalidad) %>%
    summarise(Horas_Hipoxia = sum(Hipoxia), .groups = 'drop')
}

horas_hipoxicas <- calcular_horas_hipoxia(total)

# Normalidad de los datos
horas_hipoxicas %>%
  group_by(Mortalidad) %>%
  summarise(
    mensaje = paste(
      "Prueba de Shapiro-Wilk para", 
      first(Mortalidad), # Obtén el nombre del grupo
      ": p =", signif(shapiro.test(Horas_Hipoxia)$p.value, digits = 3)
    )
  ) %>%
  pull(mensaje) %>% # Extrae solo los mensajes
  cat(sep = "\n") # Los imprime línea por línea
## Prueba de Shapiro-Wilk para Mortalidad 2015 - Barrancos : p = 0.0238
## Prueba de Shapiro-Wilk para Mortalidad 2015 - Constante : p = 2.25e-05
## Prueba de Shapiro-Wilk para Mortalidad 2019 - Constante : p = 0.00032
## Prueba de Shapiro-Wilk para No Mortalidad : p = 5.03e-28
# Homogeneidad de los datos
levene_result<- leveneTest(Horas_Hipoxia ~ Mortalidad, data = horas_hipoxicas)
# Extraer el valor p del resultado
p_value_levene <- signif(levene_result$`Pr(>F)`[1], digits = 3)

# Crear un mensaje personalizado
cat("Prueba de Levene para homogeneidad de varianzas: p =", p_value_levene, "\n")
## Prueba de Levene para homogeneidad de varianzas: p = 0.659
# Kruskal-Wallis
kruskal_result <- kruskal.test(Horas_Hipoxia ~ Mortalidad, data = horas_hipoxicas)
print(kruskal_result)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  Horas_Hipoxia by Mortalidad
## Kruskal-Wallis chi-squared = 29.169, df = 3, p-value = 2.063e-06
# Post-hoc con Dunn para identificar diferencias entre pares de grupos
dunn_result <- dunnTest(Horas_Hipoxia ~ Mortalidad, data = horas_hipoxicas, method = "bonferroni")

# Extraer los resultados en formato de dataframe
tabla_dunn <- as.data.frame(dunn_result$res)

# Renombrar columnas para que sean más legibles
colnames(tabla_dunn) <- c("Comparacion", "Estadistico Z", "P sin ajustar", "P ajustado")

# Crear la tabla con gt
tabla_dunn %>%
  gt() %>%
  tab_header(
    title = "Resultados del Test de Dunn",
    subtitle = "Comparaciones de Horas Hipoxicas entre grupos de Mortalidad"
  ) %>%
  fmt_number(
    columns = c("Estadistico Z", "P sin ajustar", "P ajustado"),
    decimals = 3
  ) %>%
  cols_label(
    `Comparacion` = "Grupos Comparados",
    `Estadistico Z` = "Estadístico Z",
    `P sin ajustar` = "P-valor (sin ajustar)",
    `P ajustado` = "P-valor (ajustado)"
  )
Resultados del Test de Dunn
Comparaciones de Horas Hipoxicas entre grupos de Mortalidad
Grupos Comparados Estadístico Z P-valor (sin ajustar) P-valor (ajustado)
Mortalidad 2015 - Barrancos - Mortalidad 2015 - Constante 3.627 0.000 0.002
Mortalidad 2015 - Barrancos - Mortalidad 2019 - Constante 0.297 0.766 1.000
Mortalidad 2015 - Constante - Mortalidad 2019 - Constante −3.507 0.000 0.003
Mortalidad 2015 - Barrancos - No Mortalidad 3.749 0.000 0.001
Mortalidad 2015 - Constante - No Mortalidad −1.301 0.193 1.000
Mortalidad 2019 - Constante - No Mortalidad 3.696 0.000 0.001

Cual tipo de grafico usar?

# Boxplots
ggplot(horas_hipoxicas, aes(x = Mortalidad, y = Horas_Hipoxia, fill = Mortalidad)) +
  geom_boxplot(alpha = 0.7, outlier.shape = NA) +
  geom_jitter(width = 0.2, size = 2, alpha = 0.6, color = "black") +
  scale_fill_manual(values = c("#56B4E9", "#E69F00", "#009E73", "#D55E00")) +
  labs(
    title = "Horas Hipóxicas al día",
    x = "",
    y = "Horas"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "none"
  )

# Violinplot
ggplot(horas_hipoxicas, aes(x = Mortalidad, y = Horas_Hipoxia, fill = Mortalidad)) +
  geom_violin(trim = FALSE, alpha = 0.6, color = "black") +
  geom_boxplot(width = 0.1, outlier.shape = NA, alpha = 0.5) +
  scale_fill_manual(values = c("#56B4E9", "#E69F00", "#009E73", "#D55E00")) +
  labs(
    title = "Horas Hipóxicas al día",
    x = "",
    y = "Horas"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "none"
  )

# Reordenar los niveles de la variable 'Mortalidad'
horas_hipoxicas$Mortalidad <- factor(
  horas_hipoxicas$Mortalidad,
  levels = c(
    "Mortalidad 2015 - Barrancos",
    "Mortalidad 2019 - Constante",
    "Mortalidad 2015 - Constante",
    "No Mortalidad"
  ),
  labels = c(
    "Mortalidad 2015\nBarrancos",
    "Mortalidad 2019\nConstante",
    "Mortalidad 2015\nConstante",
    "No Mortalidad"
  )
)

# Stats + graph
ggbetweenstats(
  data = horas_hipoxicas,
  x = Mortalidad,
  y = Horas_Hipoxia,
  title = NULL, # Elimina el título
  results.subtitle = F, # Elimina el subtítulo que contiene la ecuación
  xlab = "",
  ylab = "Horas en hipoxia al día",
  type = "nonparametric", # Usa Kruskal-Wallis como test principal
  pairwise.comparisons = TRUE, # Comparaciones post-hoc entre grupos
  var.equal = FALSE,
  pairwise.display = "significant", # Solo muestra pares significativos
  p.adjust.method = "bonferroni", # Corrección para múltiples comparaciones
  ggtheme = ggplot2::theme_minimal(), # Tema minimalista
  violin.args = list(width = 0, linewidth = 0) # Para quitar el violin plot
) +
  # Personalización del tema
  ggplot2::theme(
    plot.title = ggplot2::element_text(size = 0), # Quita el título
    plot.subtitle = ggplot2::element_text(size = 0), # Quita el subtítulo
    legend.text = ggplot2::element_text(size = 12), # Tamaño del texto de la leyenda
    axis.text = ggplot2::element_text(size = 12, color = "black"), # Tamaño y color del texto de los ejes
    axis.title = ggplot2::element_text(size = 14), # Tamaño de título de los ejes
    axis.ticks.length = ggplot2::unit(5, "pt"), # Longitud de los ticks
    axis.ticks = ggplot2::element_line(color = "black"), # Color de los ticks
    axis.line = ggplot2::element_line(color = "black", size = 0.5), # Líneas de los ejes
    panel.grid.major = ggplot2::element_blank(), # Elimina las líneas de la grilla mayor
    panel.grid.minor = ggplot2::element_blank()  # Elimina las líneas de la grilla menor
  ) +
  ggplot2::scale_color_manual(values = c("#56B4E9", "red", "green", "#D55E00"))

Porcentaje de registros hipóxicos al día

Porcentaje de registros hipóxicos al dia:

# Función para calcular el porcentaje de horas hipóxicas por día
calcular_porcentaje_hipoxia <- function(df) {
  df %>%
    mutate(Dia = as.Date(Hora_Lima)) %>%
    group_by(Dia, Mortalidad) %>%
    summarise(
      Horas_Hipoxia = sum(Hipoxia),  # Contar las horas hipóxicas
      Horas_Totales = n(),  # Contar el número total de registros por día
      Porcentaje = (Horas_Hipoxia / Horas_Totales) * 100,  # Calcular el porcentaje de horas hipóxicas
      .groups = 'drop'
    )
}

# Aplicar la función a tu dataframe
porcentaje_hipoxia <- calcular_porcentaje_hipoxia(total)

# Normalidad de los datos
porcentaje_hipoxia %>%
  group_by(Mortalidad) %>%
  summarise(
    mensaje = paste(
      "Prueba de Shapiro-Wilk para", 
      first(Mortalidad), # Obtén el nombre del grupo
      ": p =", signif(shapiro.test(Porcentaje)$p.value, digits = 3)
    )
  ) %>%
  pull(mensaje) %>% # Extrae solo los mensajes
  cat(sep = "\n") # Los imprime línea por línea
## Prueba de Shapiro-Wilk para Mortalidad 2015 - Barrancos : p = 0.000592
## Prueba de Shapiro-Wilk para Mortalidad 2015 - Constante : p = 1.45e-05
## Prueba de Shapiro-Wilk para Mortalidad 2019 - Constante : p = 2.91e-05
## Prueba de Shapiro-Wilk para No Mortalidad : p = 7.13e-28
# Homogeneidad de los datos
levene_result<- leveneTest(Porcentaje ~ Mortalidad, data = porcentaje_hipoxia)
p_value_levene <- signif(levene_result$`Pr(>F)`[1], digits = 3)
cat("Prueba de Levene para homogeneidad de varianzas: p =", p_value_levene, "\n")
## Prueba de Levene para homogeneidad de varianzas: p = 0.00132
# Kruskal-Wallis
kruskal_result <- kruskal.test(Porcentaje ~ Mortalidad, data = porcentaje_hipoxia)
print(kruskal_result)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  Porcentaje by Mortalidad
## Kruskal-Wallis chi-squared = 52.345, df = 3, p-value = 2.529e-11
# Post-hoc con Dunn para identificar diferencias entre pares de grupos
dunn_result <- dunnTest(Porcentaje ~ Mortalidad, data = porcentaje_hipoxia, method = "bonferroni")

# Extraer los resultados en formato de dataframe
tabla_dunn <- as.data.frame(dunn_result$res)

# Renombrar columnas para que sean más legibles
colnames(tabla_dunn) <- c("Comparacion", "Estadistico Z", "P sin ajustar", "P ajustado")

# Crear la tabla con gt
tabla_dunn %>%
  gt() %>%
  tab_header(
    title = "Resultados del Test de Dunn",
    subtitle = "Comparaciones de Porcentaje de registros hipoxicos entre grupos de Mortalidad"
  ) %>%
  fmt_number(
    columns = c("Estadistico Z", "P sin ajustar", "P ajustado"),
    decimals = 3
  ) %>%
  cols_label(
    `Comparacion` = "Grupos Comparados",
    `Estadistico Z` = "Estadístico Z",
    `P sin ajustar` = "P-valor (sin ajustar)",
    `P ajustado` = "P-valor (ajustado)"
  )
Resultados del Test de Dunn
Comparaciones de Porcentaje de registros hipoxicos entre grupos de Mortalidad
Grupos Comparados Estadístico Z P-valor (sin ajustar) P-valor (ajustado)
Mortalidad 2015 - Barrancos - Mortalidad 2015 - Constante 3.696 0.000 0.001
Mortalidad 2015 - Barrancos - Mortalidad 2019 - Constante −1.108 0.268 1.000
Mortalidad 2015 - Constante - Mortalidad 2019 - Constante −4.985 0.000 0.000
Mortalidad 2015 - Barrancos - No Mortalidad 3.969 0.000 0.000
Mortalidad 2015 - Constante - No Mortalidad −1.177 0.239 1.000
Mortalidad 2019 - Constante - No Mortalidad 5.993 0.000 0.000
ggplot(porcentaje_hipoxia, aes(x = Mortalidad, y = Porcentaje, fill = Mortalidad)) +
  geom_boxplot(alpha = 0.7, outlier.shape = NA) +
  geom_jitter(width = 0.2, size = 2, alpha = 0.6, color = "black") +
  scale_fill_manual(values = c("#56B4E9", "#E69F00", "#009E73", "#D55E00")) +
  labs(
    title = "Registros Hipóxicos al día",
    x = "",
    y = "Porcentaje %"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "none"
  )

ggplot(porcentaje_hipoxia, aes(x = Mortalidad, y = Porcentaje, fill = Mortalidad)) +
  geom_violin(trim = FALSE, alpha = 0.6, color = "black") +
  geom_boxplot(width = 0.1, outlier.shape = NA, alpha = 0.5) +
  scale_fill_manual(values = c("#56B4E9", "#E69F00", "#009E73", "#D55E00")) +
  labs(
    title = "Registros Hipóxicos al día",
    x = "",
    y = "Porcentaje %"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "none"
  )

# Reordenar los niveles de la variable 'Mortalidad'
porcentaje_hipoxia$Mortalidad <- factor(
  porcentaje_hipoxia$Mortalidad,
  levels = c(
    "Mortalidad 2015 - Barrancos",
    "Mortalidad 2019 - Constante",
    "Mortalidad 2015 - Constante",
    "No Mortalidad"
  ),
  labels = c(
    "Mortalidad 2015\nBarrancos",
    "Mortalidad 2019\nConstante",
    "Mortalidad 2015\nConstante",
    "No Mortalidad"
  )
)


# Stats + graph
ggbetweenstats(
  data = porcentaje_hipoxia,
  x = Mortalidad,
  y = Porcentaje,
  title = NULL, # Elimina el título
  results.subtitle =F, # Elimina el subtítulo que contiene la ecuación
  xlab = "",
  ylab = "Registros hipóxicos al día (%)",
  type = "nonparametric", # Usa Kruskal-Wallis como test principal
  pairwise.comparisons = TRUE, # Comparaciones post-hoc entre grupos
  var.equal = FALSE,
  pairwise.display = "significant", # Solo muestra pares significativos
  p.adjust.method = "bonferroni", # Corrección para múltiples comparaciones
  ggtheme = ggplot2::theme_minimal(), # Tema minimalista
  violin.args = list(width = 0, linewidth = 0) # Para quitar el violin plot
) +
  # Paleta de colores personalizada
  ggplot2::scale_color_manual(values = c("#56B4E9", "red", "green", "#D55E00")) +
  
  # Personalización del tema
  ggplot2::theme(
    plot.title = ggplot2::element_text(size = 0), # Quita el título
    plot.subtitle = ggplot2::element_text(size = 0), # Quita el subtítulo
    legend.text = ggplot2::element_text(size = 12), # Tamaño del texto de la leyenda
    axis.text = ggplot2::element_text(size = 12, color = "black"), # Tamaño y color del texto de los ejes
    axis.title = ggplot2::element_text(size = 14), # Tamaño del título de los ejes
    axis.ticks.length = ggplot2::unit(5, "pt"), # Longitud de los ticks
    axis.ticks = ggplot2::element_line(color = "black"), # Color de los ticks
    axis.line = ggplot2::element_line(color = "black", size = 0.5), # Líneas de los ejes
    panel.grid.major = ggplot2::element_blank(), # Elimina las líneas de la grilla mayor
    panel.grid.minor = ggplot2::element_blank()  # Elimina las líneas de la grilla menor
  )

Minimo de Sat OD al dia

Minimo de Saturacion de oxígeno al día:

# Función para calcular mínimo de DO_sat por día 
calcular_min_od <- function(df) {
  df %>%
    mutate(Dia = as.Date(Hora_Lima)) %>%
    group_by(Dia, Mortalidad) %>%
    summarise(minimo = min(DO_sat), .groups = 'drop')
}

# Aplicar calcular_min_od a cada conjunto de datos
min_od <- calcular_min_od(total)

# Normalidad de los datos
min_od %>%
  group_by(Mortalidad) %>%
  summarise(
    mensaje = paste(
      "Prueba de Shapiro-Wilk para", 
      first(Mortalidad), # Obtén el nombre del grupo
      ": p =", signif(shapiro.test(minimo)$p.value, digits = 3)
    )
  ) %>%
  pull(mensaje) %>% # Extrae solo los mensajes
  cat(sep = "\n") # Los imprime línea por línea
## Prueba de Shapiro-Wilk para Mortalidad 2015 - Barrancos : p = 2.85e-05
## Prueba de Shapiro-Wilk para Mortalidad 2015 - Constante : p = 0.325
## Prueba de Shapiro-Wilk para Mortalidad 2019 - Constante : p = 0.000499
## Prueba de Shapiro-Wilk para No Mortalidad : p = 3.28e-16
# Homogeneidad de los datos
levene_result<- leveneTest(minimo ~ Mortalidad, data = min_od)
p_value_levene <- signif(levene_result$`Pr(>F)`[1], digits = 3)
cat("Prueba de Levene para homogeneidad de varianzas: p =", p_value_levene, "\n")
## Prueba de Levene para homogeneidad de varianzas: p = 1.51e-07
# Kruskal-Wallis
kruskal_result <- kruskal.test(minimo ~ Mortalidad, data = min_od)
print(kruskal_result)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  minimo by Mortalidad
## Kruskal-Wallis chi-squared = 58.723, df = 3, p-value = 1.102e-12
# Post-hoc con Dunn para identificar diferencias entre pares de grupos
dunn_result <- dunnTest(minimo ~ Mortalidad, data = min_od, method = "bonferroni")

# Extraer los resultados en formato de dataframe
tabla_dunn <- as.data.frame(dunn_result$res)

# Renombrar columnas para que sean más legibles
colnames(tabla_dunn) <- c("Comparacion", "Estadistico Z", "P sin ajustar", "P ajustado")

# Crear la tabla con gt
tabla_dunn %>%
  gt() %>%
  tab_header(
    title = "Resultados del Test de Dunn",
    subtitle = "Comparaciones de Porcentaje de registros hipoxicos entre grupos de Mortalidad"
  ) %>%
  fmt_number(
    columns = c("Estadistico Z", "P sin ajustar", "P ajustado"),
    decimals = 3
  ) %>%
  cols_label(
    `Comparacion` = "Grupos Comparados",
    `Estadistico Z` = "Estadístico Z",
    `P sin ajustar` = "P-valor (sin ajustar)",
    `P ajustado` = "P-valor (ajustado)"
  )
Resultados del Test de Dunn
Comparaciones de Porcentaje de registros hipoxicos entre grupos de Mortalidad
Grupos Comparados Estadístico Z P-valor (sin ajustar) P-valor (ajustado)
Mortalidad 2015 - Barrancos - Mortalidad 2015 - Constante −3.661 0.000 0.002
Mortalidad 2015 - Barrancos - Mortalidad 2019 - Constante 1.432 0.152 0.913
Mortalidad 2015 - Constante - Mortalidad 2019 - Constante 5.272 0.000 0.000
Mortalidad 2015 - Barrancos - No Mortalidad −4.006 0.000 0.000
Mortalidad 2015 - Constante - No Mortalidad 1.091 0.275 1.000
Mortalidad 2019 - Constante - No Mortalidad −6.508 0.000 0.000
ggplot(min_od, aes(x = Mortalidad, y = minimo, fill = Mortalidad)) +
  geom_boxplot(alpha = 0.7, outlier.shape = NA) +
  geom_jitter(width = 0.2, size = 2, alpha = 0.6, color = "black") +
  scale_fill_manual(values = c("#56B4E9", "#E69F00", "#009E73", "#D55E00")) +
  labs(
    title = "Minima saturacion de oxígeno al día",
    x = "",
    y = "Saturacion OD (%)"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "none"
  )

ggplot(min_od, aes(x = Mortalidad, y = minimo, fill = Mortalidad)) +
  geom_violin(trim = FALSE, alpha = 0.6, color = "black") +
  geom_boxplot(width = 0.1, outlier.shape = NA, alpha = 0.5) +
  scale_fill_manual(values = c("#56B4E9", "#E69F00", "#009E73", "#D55E00")) +
  labs(
    title = "Minima saturacion de oxígeno al día",
    x = "",
    y = "Saturacion de OD (%)"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "none"
  )

# Reordenar los niveles de la variable 'Mortalidad'
min_od$Mortalidad <- factor(
  min_od$Mortalidad,
  levels = c(
    "Mortalidad 2015 - Barrancos",
    "Mortalidad 2019 - Constante",
    "Mortalidad 2015 - Constante",
    "No Mortalidad"
  ),
  labels = c(
    "Mortalidad 2015\nBarrancos",
    "Mortalidad 2019\nConstante",
    "Mortalidad 2015\nConstante",
    "No Mortalidad"
  )
)

# Stats + graph
ggbetweenstats(
  data = min_od,
  x = Mortalidad,
  y = minimo,
  title = NULL, # Elimina el título
  results.subtitle = F, # Elimina el subtítulo que contiene la ecuación
  xlab = "",
  ylab = "Minima saturación OD al día (%)",
  type = "nonparametric", # Usa Kruskal-Wallis como test principal
  pairwise.comparisons = TRUE, # Comparaciones post-hoc entre grupos
  var.equal = FALSE,
  pairwise.display = "significant", # Solo muestra pares significativos
  p.adjust.method = "bonferroni", # Corrección para múltiples comparaciones
  ggtheme = ggplot2::theme_minimal(), # Tema minimalista
  violin.args = list(width = 0, linewidth = 0) # Para quitar el violin plot
) +
  # Paleta de colores personalizada
  ggplot2::scale_color_manual(values = c("#56B4E9", "red", "green", "#D55E00")) +
  
  # Personalización del tema
  ggplot2::theme(
    plot.title = ggplot2::element_text(size = 0), # Quita el título
    plot.subtitle = ggplot2::element_text(size = 0), # Quita el subtítulo
    legend.text = ggplot2::element_text(size = 12), # Tamaño del texto de la leyenda
    axis.text = ggplot2::element_text(size = 12, color = "black"), # Tamaño y color del texto de los ejes
    axis.title = ggplot2::element_text(size = 14), # Tamaño del título de los ejes
    axis.ticks.length = ggplot2::unit(5, "pt"), # Longitud de los ticks
    axis.ticks = ggplot2::element_line(color = "black"), # Color de los ticks
    axis.line = ggplot2::element_line(color = "black", size = 0.5), # Líneas de los ejes
    panel.grid.major = ggplot2::element_blank(), # Elimina las líneas de la grilla mayor
    panel.grid.minor = ggplot2::element_blank()  # Elimina las líneas de la grilla menor
  )

Mediana de Sat OD al dia

Mediana de Saturacion de oxigeno al dia:

# Función para calcular mediana de DO_sat por día y zona
calcular_median_od <- function(df) {
  df %>%
    mutate(Dia = as.Date(Hora_Lima)) %>%
    group_by(Dia, Mortalidad) %>%
    summarise(median= median(DO_sat), .groups = 'drop')
}

# Aplicar calcular_min_od a cada conjunto de datos
med_od <- calcular_median_od(total)

# Normalidad de los datos
med_od %>%
  group_by(Mortalidad) %>%
  summarise(
    mensaje = paste(
      "Prueba de Shapiro-Wilk para", 
      first(Mortalidad), # Obtén el nombre del grupo
      ": p =", signif(shapiro.test(median)$p.value, digits = 3)
    )
  ) %>%
  pull(mensaje) %>% # Extrae solo los mensajes
  cat(sep = "\n") # Los imprime línea por línea
## Prueba de Shapiro-Wilk para Mortalidad 2015 - Barrancos : p = 0.00683
## Prueba de Shapiro-Wilk para Mortalidad 2015 - Constante : p = 0.2
## Prueba de Shapiro-Wilk para Mortalidad 2019 - Constante : p = 0.143
## Prueba de Shapiro-Wilk para No Mortalidad : p = 8.92e-11
# Homogeneidad de los datos
levene_result<- leveneTest(median ~ Mortalidad, data = med_od)
p_value_levene <- signif(levene_result$`Pr(>F)`[1], digits = 3)
cat("Prueba de Levene para homogeneidad de varianzas: p =", p_value_levene, "\n")
## Prueba de Levene para homogeneidad de varianzas: p = 4.54e-06
# Kruskal-Wallis
kruskal_result <- kruskal.test(median ~ Mortalidad, data = med_od)
print(kruskal_result)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  median by Mortalidad
## Kruskal-Wallis chi-squared = 63.399, df = 3, p-value = 1.104e-13
# Post-hoc con Dunn para identificar diferencias entre pares de grupos
dunn_result <- dunnTest(median ~ Mortalidad, data = med_od, method = "bonferroni")

# Extraer los resultados en formato de dataframe
tabla_dunn <- as.data.frame(dunn_result$res)

# Renombrar columnas para que sean más legibles
colnames(tabla_dunn) <- c("Comparacion", "Estadistico Z", "P sin ajustar", "P ajustado")

# Crear la tabla con gt
tabla_dunn %>%
  gt() %>%
  tab_header(
    title = "Resultados del Test de Dunn",
    subtitle = "Comparaciones de Porcentaje de registros hipoxicos entre grupos de Mortalidad"
  ) %>%
  fmt_number(
    columns = c("Estadistico Z", "P sin ajustar", "P ajustado"),
    decimals = 3
  ) %>%
  cols_label(
    `Comparacion` = "Grupos Comparados",
    `Estadistico Z` = "Estadístico Z",
    `P sin ajustar` = "P-valor (sin ajustar)",
    `P ajustado` = "P-valor (ajustado)"
  )
Resultados del Test de Dunn
Comparaciones de Porcentaje de registros hipoxicos entre grupos de Mortalidad
Grupos Comparados Estadístico Z P-valor (sin ajustar) P-valor (ajustado)
Mortalidad 2015 - Barrancos - Mortalidad 2015 - Constante −3.946 0.000 0.000
Mortalidad 2015 - Barrancos - Mortalidad 2019 - Constante 1.340 0.180 1.000
Mortalidad 2015 - Constante - Mortalidad 2019 - Constante 5.478 0.000 0.000
Mortalidad 2015 - Barrancos - No Mortalidad −4.278 0.000 0.000
Mortalidad 2015 - Constante - No Mortalidad 1.216 0.224 1.000
Mortalidad 2019 - Constante - No Mortalidad −6.672 0.000 0.000
ggplot(med_od, aes(x = Mortalidad, y = median, fill = Mortalidad)) +
  geom_boxplot(alpha = 0.7, outlier.shape = NA) +
  geom_jitter(width = 0.2, size = 2, alpha = 0.6, color = "black") +
  scale_fill_manual(values = c("#56B4E9", "#E69F00", "#009E73", "#D55E00")) +
  labs(
    title = "Mediana de la saturacion de oxígeno al día",
    x = "",
    y = "Saturacion OD (%)"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "none"
  )

ggplot(med_od, aes(x = Mortalidad, y = median, fill = Mortalidad)) +
  geom_violin(trim = FALSE, alpha = 0.6, color = "black") +
  geom_boxplot(width = 0.1, outlier.shape = NA, alpha = 0.5) +
  scale_fill_manual(values = c("#56B4E9", "#E69F00", "#009E73", "#D55E00")) +
  labs(
    title = "Mediana de la saturacion de oxígeno al día",
    x = "",
    y = "Saturacion de OD (%)"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16),
    legend.position = "none"
  )

# Crear el gráficO

med_od$Mortalidad <- factor(
  med_od$Mortalidad,
  levels = c(
    "Mortalidad 2015 - Barrancos",
    "Mortalidad 2019 - Constante",
    "Mortalidad 2015 - Constante",
    "No Mortalidad"
  ),
  labels = c(
    "Mortalidad 2015\nBarrancos",
    "Mortalidad 2019\nConstante",
    "Mortalidad 2015\nConstante",
    "No Mortalidad"
  )
)


# Stats + graph
ggbetweenstats(
  data = med_od,
  x = Mortalidad,
  y = median,
  title = NULL, # Elimina el título
  results.subtitle = FALSE, # Elimina el subtítulo que contiene la ecuación
  xlab = "",
  ylab = "Mediana de Saturación OD al día (%)",
  type = "nonparametric", # Usa Kruskal-Wallis como test principal
  pairwise.comparisons = TRUE, # Comparaciones post-hoc entre grupos
  var.equal = FALSE,
  pairwise.display = "significant", # Solo muestra pares significativos
  p.adjust.method = "bonferroni", # Corrección para múltiples comparaciones
  ggtheme = ggplot2::theme_minimal(), # Tema minimalista
  violin.args = list(width = 0, linewidth = 0) # Para quitar el violin plot
) +
  # Paleta de colores personalizada
  ggplot2::scale_color_manual(values = c("#56B4E9", "red", "green", "#D55E00")) +
  
  # Personalización del tema
  ggplot2::theme(
    plot.title = ggplot2::element_text(size = 0), # Quita el título
    legend.text = ggplot2::element_text(size = 12), # Tamaño del texto de la leyenda
    axis.text = ggplot2::element_text(size = 12, color = "black"), # Tamaño y color del texto de los ejes
    axis.title = ggplot2::element_text(size = 14), # Tamaño del título de los ejes
    axis.ticks.length = ggplot2::unit(5, "pt"), # Longitud de los ticks
    axis.ticks = ggplot2::element_line(color = "black"), # Color de los ticks
    axis.line = ggplot2::element_line(color = "black", size = 0.5), # Líneas de los ejes
    panel.grid.major = ggplot2::element_blank(), # Elimina las líneas de la grilla mayor
    panel.grid.minor = ggplot2::element_blank()  # Elimina las líneas de la grilla menor
  )

Desarrollo de una matriz de respuesas biologicas de A. purpuratus frente a la temperatura e hipoxia

BARRANCOS MORTALIDAD 2015

# Ahora asignamos la categoria de Temp_fond y DO_sat
df_indice <- barrancos_2015

df_indice <- df_indice %>%
  mutate(
    Categoria_T = case_when(
      Temp_fond <= 16 ~ "<=16",
      Temp_fond > 16 & Temp_fond <= 20 ~ "]16-20]",
      Temp_fond > 20 & Temp_fond <= 25 ~ "]20-25]",
      Temp_fond > 25 & Temp_fond <= 29 ~ "]25-29]",
      Temp_fond > 29 ~ ">29"
    ),
    Categoria_DO = case_when(
      DO_sat <= 2 ~ "<=2",
      DO_sat > 2 & DO_sat <= 5 ~ "]2-5]",
      DO_sat > 5 & DO_sat <= 24.4 ~ "]5-24]",
      DO_sat > 24.4 ~ ">24"
    ),
    Categoria_total = paste(Categoria_T, Categoria_DO, sep = ";")
  )

# Identificar los cambios en las categorías de Categoria_total dentro de cada group 
df_indice <- df_indice %>%
  group_by(group) %>%
  mutate(change = Categoria_total != lag(Categoria_total, default = first(Categoria_total))) %>%
  mutate(group_id = cumsum(change)) %>%
  ungroup ()

# Calcular la fecha de inicio y fin de cada grupo de categorías continuas
df_agrupado <- df_indice %>%
  group_by(
    group,
    group_id) %>%
  summarize(
    fecha_inicio = min(Hora_Lima),
    fecha_fin = max(Hora_Lima),
    duracion = as.numeric(difftime(max(Hora_Lima), min(Hora_Lima), units = "hours"))+1,
    Categoria_total = first(Categoria_total),
    Categoria_DO = first (Categoria_DO))

# Agregar columna Hipoxico con valores Hipoxia o Normoxia
df_agrupado <- df_agrupado %>%
 mutate(Hipoxia = ifelse(Categoria_DO %in% c("<=2", "]2-5]","]5-24]"), "Hipoxia", "Normoxia")) #%>%
  #ungroup() #%>% # Eliminar agrupaciones activas
  #select(-group)

# Crear una copia del dataframe original
df_resultado <- df_agrupado

# Identificar periodos menores a 6 horas
df_resultado <- df_resultado %>%
  mutate(is_short = duracion < 6)

# Procesar los bloques
procesar_bloques <- function(df) {
  bloque_id <- 1
  df <- df %>%
    mutate(bloque = 0)  # Inicializamos con 0 para los bloques
  
  for (i in 1:nrow(df)) {
    if (i == 1) {
      # Asignar el primer bloque
      df$bloque[i] <- bloque_id
    } else if (df$group[i] != df$group[i - 1]) {
      # Si cambia el grupo, crear un nuevo bloque
      bloque_id <- bloque_id + 1
      df$bloque[i] <- bloque_id
    } else if (df$is_short[i - 1] && df$is_short[i]) {
      # Si el periodo actual y el anterior son cortos, pertenecen al mismo bloque
      df$bloque[i] <- bloque_id
    } else if (df$is_short[i - 1] && !df$is_short[i]) {
      # Si el periodo anterior era corto pero este no, verificamos la duración acumulada
      bloque_duracion <- sum(df$duracion[df$bloque == bloque_id])
      if (bloque_duracion < 6) {
        # Vía B: Ignorar la interrupción y extender el bloque al siguiente
        df$bloque[i] <- bloque_id
      } else {
        # Vía A: Crear un nuevo bloque
        bloque_id <- bloque_id + 1
        df$bloque[i] <- bloque_id
      }
    } else {
      # Crear un nuevo bloque
      bloque_id <- bloque_id + 1
      df$bloque[i] <- bloque_id
    }
  }
  
  return(df)
}

df_resultado <- procesar_bloques(df_resultado)

# Calcular resultados finales por bloque
df_final <- df_resultado %>%
  group_by(bloque, group) %>%
  summarize(
    fecha_inicio = min(fecha_inicio),
    fecha_fin = max(fecha_fin),
    duracion_total = sum(duracion),
    Categoria_total = Categoria_total[which.max(duracion)],
    Categoria_DO = Categoria_DO[which.max(duracion)]
  ) %>%
  ungroup()

# Agrupar por bloques consecutivos con el mismo Categoria_total
df_consolidado <- df_final %>%
  mutate(
    grupo_categoria = cumsum(Categoria_total != lag(Categoria_total, default = first(Categoria_total)))
  ) %>%
  group_by(grupo_categoria,group) %>%
  summarize(
    fecha_inicio = min(fecha_inicio),
    fecha_fin = max(fecha_fin),
    duracion = sum(duracion_total),
    Categoria_total = first(Categoria_total),
    Categoria_DO = first(Categoria_DO) # Consideramos la misma lógica para Categoria_DO
  ) %>%
  ungroup()


# Asignar las categorias
df_consolidado <- df_consolidado %>%
  mutate(
    Indice = case_when(
      duracion < 12 & Categoria_total == "<=16;>24" ~ "Inocuo",
      duracion < 12 & Categoria_total == "<=16;]5-24]" ~ "Estres fisiologico",
      duracion<12 & Categoria_total == "<=16;]2-5]"~ "Estres fisiologico",
      duracion<12 & Categoria_total =="<=16;<=2" ~ "Estres fisiologico",
      duracion<12 & Categoria_total == "]16-20];>24" ~ "Inocuo",
      duracion<12 & Categoria_total == "]16-20];]5-24]" ~ "Estres fisiologico",
      duracion<12 & Categoria_total =="]16-20];]2-5]" ~ "Sin informacion",
      duracion<12 & Categoria_total == "]16-20];<=2" ~ "Sin informacion",
      duracion<12 & Categoria_total == "]20-25];>24" ~ "Inocuo",
      duracion <12 & Categoria_total == "]20-25];]5-24]"~"Estres fisiologico",
      duracion<12 & Categoria_total == "]20-25];]2-5]" ~ "Sin informacion",
      duracion<12 & Categoria_total == "]20-25];<=2" ~ "Probabilidad de mortalidad",
      duracion<12 & Categoria_total == "25-29];>24" ~ "Sin informacion",
      duracion <12 & Categoria_total == "]25-29];]5-24]"~"Sin informacion",
      duracion<12 & Categoria_total == "]25-29];]2-5]" ~ "Sin informacion",
      duracion<12 & Categoria_total == "]25-29];<=2" ~ "Probabilidad de mortalidad",
      duracion<12 & Categoria_total == ">29;>24" ~ "Probabilidad de mortalidad",
      duracion <12 & Categoria_total == ">29;5-24]"~ "Letal",
      duracion<12 & Categoria_total== ">29;]2-5]" ~ "Letal",
      duracion<12 & Categoria_total == ">29;<=2" ~ "Letal",
      duracion >= 12 & duracion < 24 & Categoria_total == "<=16;>24" ~ "Inocuo",
      duracion >= 12 & duracion < 24 & Categoria_total == "<=16;]5-24]" ~ "Estres fisiologico",
      duracion >= 12 & duracion < 24  & Categoria_total == "<=16;]2-5]"  ~ "Estres fisiologico",
      duracion >= 12 & duracion < 24  & Categoria_total == "<=16;<=2"  ~ "Estres fisiologico",
      duracion >= 12 & duracion < 24 & Categoria_total == "]16-20];>24" ~ "Inocuo",
      duracion >= 12 & duracion < 24  & Categoria_total == "]16-20];]5-24]"  ~ "Estres fisiologico",
      duracion >= 12 & duracion < 24 & Categoria_total == "]16-20];]2-5]"  ~ "Sin informacion",
      duracion >= 12 & duracion < 24 & Categoria_total == "]16-20];<=2"  ~ "Probabilidad de mortalidad",
      duracion >= 12 & duracion < 24 & Categoria_total == "]20-25];>24"  ~ "Inocuo",
      duracion >= 12 & duracion < 24 & Categoria_total == "]20-25];]5-24]"  ~ "Estres fisiologico",
      duracion >= 12 & duracion < 24 & Categoria_total == "]20-25];]2-5]"  ~ "Sin informacion",
      duracion >= 12 & duracion < 24 & Categoria_total == "]20-25];<=2"  ~ "Letal",
      duracion >= 12 & duracion < 24 & Categoria_total == "]25-29];>24"   ~ "Sin informacion",
      duracion >= 12 & duracion < 24 &Categoria_total == "]25-29];]5-24]"  ~ "Sin informacion",
      duracion >= 12 & duracion < 24 & Categoria_total == "]25-29];]2-5]"   ~ "Sin informacion",
      duracion >= 12 & duracion < 24 & Categoria_total == "]25-29];<=2"  ~ "Letal",
      duracion >= 12 & duracion < 24 & Categoria_total == ">29;>24"  ~ "Probabilidad de mortalidad",
      duracion >= 12 & duracion < 24 & Categoria_total == ">29;5-24]"  ~ "Letal",
      duracion >= 12 & duracion < 24 & Categoria_total == ">29;]2-5]"  ~ "Letal",
      duracion >= 12 & duracion < 24 & Categoria_total  == ">29;<=2"  ~ "Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == "<=16;>24"  ~ "Inocuo",
      duracion >= 24 & duracion < 48 & Categoria_total == "<=16;]5-24]" ~ "Estres fisiologico",
      duracion >= 24 & duracion < 48 & Categoria_total == "<=16;]2-5]"  ~ "Estres fisiologico",
      duracion >= 24 & duracion < 48 & Categoria_total == "<=16;<=2" ~ "Probabilidad de mortalidad",
      duracion >= 24 & duracion < 48 & Categoria_total == "]16-20];>24" ~ "Inocuo",
      duracion >= 24 & duracion < 48 & Categoria_total == "]16-20];]5-24]" ~ "Estres fisiologico",
      duracion >= 24 & duracion < 48 & Categoria_total == "]16-20];]2-5]" ~ "Estres fisiologico",
      duracion >= 24 & duracion < 48 & Categoria_total == "]16-20];<=2"  ~ "Probabilidad de mortalidad",
      duracion >= 24 & duracion < 48 & Categoria_total == "]20-25];>24" ~ "Inocuo",
      duracion >= 24 & duracion < 48 & Categoria_total == "]20-25];]5-24]" ~ "Estres fisiologico",
      duracion >= 24 & duracion < 48 & Categoria_total == "]20-25];]2-5]" ~ "Probabilidad de mortalidad",
      duracion >= 24 & duracion < 48 & Categoria_total == "]20-25];<=2" ~ "Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == "]25-29];>24" ~ "Probabilidad de mortalidad",
      duracion >= 24 & duracion < 48 & Categoria_total == "]25-29];]5-24]" ~ "Probabilidad de mortalidad",
      duracion >= 24 & duracion < 48 & Categoria_total == "]25-29];]2-5]" ~ "Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == "]25-29];<=2" ~ "Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == ">29;>24"~ "Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == ">29;5-24]"~"Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == ">29;]2-5]"~"Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == ">29;<=2" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == "<=16;>24" ~ "Inocuo",
      duracion >= 48 & duracion < 120 & Categoria_total == "<=16;]5-24]" ~ "Probabilidad de mortalidad",
      duracion >= 48 & duracion < 120 & Categoria_total == "<=16;]2-5]" ~ "Probabilidad de mortalidad",
      duracion >= 48 & duracion < 120 & Categoria_total == "<=16;<=2" ~ "Letal",
      duracion >= 48 & duracion < 120& Categoria_total == "]16-20];>24" ~ "Inocuo",
      duracion >= 48 & duracion < 120& Categoria_total == "]16-20];]5-24]" ~ "Sin informacion",
      duracion >= 48 & duracion < 120 & Categoria_total == "]16-20];]2-5]" ~ "Sin informacion",
      duracion >= 48 & duracion < 120 & Categoria_total == "]16-20];<=2" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == "]20-25];>24" ~ "Inocuo",
      duracion >= 48 & duracion < 120& Categoria_total == "]20-25];]5-24]" ~ "Sin informacion",
      duracion >= 48 & duracion < 120 & Categoria_total == "]20-25];]2-5]" ~ "Sin informacion",
      duracion >= 48 & duracion < 120 & Categoria_total == "]20-25];<=2" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == "]25-29];>24" ~ "Probabilidad de mortalidad",
      duracion >= 48 & duracion < 120 & Categoria_total == "]25-29];]5-24]" ~ "Sin informacion",
      duracion >= 48 & duracion < 120 & Categoria_total == "]25-29];]2-5]" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == "]25-29];<=2" ~ "Letal",
      duracion >= 48 & duracion < 120& Categoria_total == ">29;>24" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == ">29;5-24]" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == ">29;]2-5]" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == ">29;<=2" ~ "Letal",
      duracion >=120 & Categoria_total == "<=16;>24" ~ "Inocuo",
      duracion >=120 & Categoria_total == "]16-20];>24" ~ "Inocuo",
      duracion >=120 & Categoria_total == "]20-25];>24" ~ "Inocuo",
      TRUE ~ "Sin informacion"
    )
  )

# Ordenar el dataframe por fecha de inicio
df_consolidado <- df_consolidado %>% arrange(fecha_inicio)

# Convertir las columnas de fecha a POSIXct si no lo están
df_consolidado$fecha_inicio <- as.POSIXct(df_consolidado$fecha_inicio, tz="UTC")
df_consolidado$fecha_fin <- as.POSIXct(df_consolidado$fecha_fin, tz="UTC")

#Función para calcular el punto medio de un intervalo de fechas
interval_midpoint <- function(start, end) {
  return(start + (end - start) / 2)
}

# Agregar la columna Hora_Lima a df_agrupado usando interval_midpoint
df_consolidado <- df_consolidado %>%
  mutate(Hora_Lima = interval_midpoint(fecha_inicio, fecha_fin))

# Definir los colores de las categorías
colores_categorias <- c("Letal" = "#800000",  # Rojo oscuro
                        "Probabilidad de mortalidad" = "red",
                        "Estres fisiologico" = "orange",
                        "Inocuo" = "green",
                        "Sin informacion" = "grey")


ggplot() +
  # Capa 1: fondo con rectángulos de df_consolidado
  geom_rect(
    data = df_consolidado,
    aes(
      xmin = as.POSIXct(fecha_inicio, tz = "UTC"),
      xmax = as.POSIXct(fecha_fin, tz = "UTC"),
      ymin = -Inf,
      ymax = Inf,
      fill = Indice
    ),
    alpha = 0.8,
    color = NA
  ) +
  scale_fill_manual(values = colores_categorias) +
  
  # Capa 2: líneas de barrancos_2015 con agrupación
  geom_line(
    data = barrancos_2015,
    aes(x = Hora_Lima, y = DO_sat, group = group),
    color = "black"
  ) +
  
  # Capa 3: punto crítico de oxígeno
  geom_text(
    data = data.frame(
      x = as.POSIXct("2015-01-15", tz = "UTC"),
      y = 27,
      label = "Punto crítico de oxígeno"
    ),
    aes(x = x, y = y, label = label),
    color = "red",
    size = 3.5
  ) +
  
  # Capa 4: línea horizontal crítica
  geom_hline(yintercept = 24, color = "red") +
  
  # Tema y personalización
  theme_minimal() +
  scale_x_datetime(breaks = "1 week", date_labels = "%d/%b") +
  labs(x = "", y = "Saturación de oxígeno (%)", title = "Mortalidad 2015 - Barrancos") +
  theme(
    title = element_text(size = 20),
    axis.text.x = element_text(size = 10, color = "black"),
    axis.text.y = element_text(size = 14, color = "black"),
    axis.title.x = element_text(size = 16),
    axis.title.y = element_text(size = 16),
    legend.text = element_text(size = 12),
    legend.title = element_text(size = 14),
    legend.position = "bottom",
    axis.ticks.length = unit(5, "pt"), # Longitud de los ticks
    axis.ticks.x = element_line(color = "black"), # Color de los ticks X
    axis.ticks.y = element_line(color = "black"),  # Color de los ticks Y
    axis.line.x = element_line(color = "black", size = 0.5), # Línea horizontal del eje
    axis.line.y = element_line(color = "black", size = 0.5)  # Línea vertical del eje
  ) +
  
  # Anotaciones adicionales
  annotate(
    "rect",
    xmin = as.POSIXct("2015-03-02", tz = "UTC"),
    xmax = as.POSIXct("2015-03-15", tz = "UTC"),
    ymin = -Inf,
    ymax = Inf,
    alpha = 0,
    color = "#636363",
    size = 0.7,
    linetype = "dashed"
  ) +
  geom_text(
    data = data.frame(
      x = as.POSIXct("2015-03-09", tz = "UTC"),
      y = 98,
      label = "Mortalidad"
    ),
    aes(x = x, y = y, label = label),
    color = "#636363",
    size = 4
  )

CONSTANTE MORTALIDAD 2019

# Ahora asignamos la categoria de Temp_fond y DO_sat
df_indice <- constante_2019

df_indice <- df_indice %>%
  mutate(
    Categoria_T = case_when(
      Temp_fond <= 16 ~ "<=16",
      Temp_fond > 16 & Temp_fond <= 20 ~ "]16-20]",
      Temp_fond > 20 & Temp_fond <= 25 ~ "]20-25]",
      Temp_fond > 25 & Temp_fond <= 29 ~ "]25-29]",
      Temp_fond > 29 ~ ">29"
    ),
    Categoria_DO = case_when(
      DO_sat <= 2 ~ "<=2",
      DO_sat > 2 & DO_sat <= 5 ~ "]2-5]",
      DO_sat > 5 & DO_sat <= 24.4 ~ "]5-24]",
      DO_sat > 24.4 ~ ">24"
    ),
    Categoria_total = paste(Categoria_T, Categoria_DO, sep = ";")
  )

# Identificar los cambios en las categorías de Categoria_total dentro de cada group 
df_indice <- df_indice %>%
  group_by(group) %>%
  mutate(change = Categoria_total != lag(Categoria_total, default = first(Categoria_total))) %>%
  mutate(group_id = cumsum(change)) %>%
  ungroup ()

# Calcular la fecha de inicio y fin de cada grupo de categorías continuas
df_agrupado <- df_indice %>%
  group_by(
    group,
    group_id) %>%
  summarize(
    fecha_inicio = min(Hora_Lima),
    fecha_fin = max(Hora_Lima),
    duracion = as.numeric(difftime(max(Hora_Lima), min(Hora_Lima), units = "hours"))+1,
    Categoria_total = first(Categoria_total),
    Categoria_DO = first (Categoria_DO))

# Agregar columna Hipoxico con valores Hipoxia o Normoxia
df_agrupado <- df_agrupado %>%
 mutate(Hipoxia = ifelse(Categoria_DO %in% c("<=2", "]2-5]","]5-24]"), "Hipoxia", "Normoxia")) #%>%
  #ungroup() #%>% # Eliminar agrupaciones activas
  #select(-group)

# Crear una copia del dataframe original
df_resultado <- df_agrupado

# Identificar periodos menores a 6 horas
df_resultado <- df_resultado %>%
  mutate(is_short = duracion < 6)

# Procesar los bloques
procesar_bloques <- function(df) {
  bloque_id <- 1
  df <- df %>%
    mutate(bloque = 0)  # Inicializamos con 0 para los bloques
  
  for (i in 1:nrow(df)) {
    if (i == 1) {
      # Asignar el primer bloque
      df$bloque[i] <- bloque_id
    } else if (df$group[i] != df$group[i - 1]) {
      # Si cambia el grupo, crear un nuevo bloque
      bloque_id <- bloque_id + 1
      df$bloque[i] <- bloque_id
    } else if (df$is_short[i - 1] && df$is_short[i]) {
      # Si el periodo actual y el anterior son cortos, pertenecen al mismo bloque
      df$bloque[i] <- bloque_id
    } else if (df$is_short[i - 1] && !df$is_short[i]) {
      # Si el periodo anterior era corto pero este no, verificamos la duración acumulada
      bloque_duracion <- sum(df$duracion[df$bloque == bloque_id])
      if (bloque_duracion < 6) {
        # Vía B: Ignorar la interrupción y extender el bloque al siguiente
        df$bloque[i] <- bloque_id
      } else {
        # Vía A: Crear un nuevo bloque
        bloque_id <- bloque_id + 1
        df$bloque[i] <- bloque_id
      }
    } else {
      # Crear un nuevo bloque
      bloque_id <- bloque_id + 1
      df$bloque[i] <- bloque_id
    }
  }
  
  return(df)
}

df_resultado <- procesar_bloques(df_resultado)

# Calcular resultados finales por bloque
df_final <- df_resultado %>%
  group_by(bloque, group) %>%
  summarize(
    fecha_inicio = min(fecha_inicio),
    fecha_fin = max(fecha_fin),
    duracion_total = sum(duracion),
    Categoria_total = Categoria_total[which.max(duracion)],
    Categoria_DO = Categoria_DO[which.max(duracion)]
  ) %>%
  ungroup()

# Agrupar por bloques consecutivos con el mismo Categoria_total
df_consolidado <- df_final %>%
  mutate(
    grupo_categoria = cumsum(Categoria_total != lag(Categoria_total, default = first(Categoria_total)))
  ) %>%
  group_by(grupo_categoria,group) %>%
  summarize(
    fecha_inicio = min(fecha_inicio),
    fecha_fin = max(fecha_fin),
    duracion = sum(duracion_total),
    Categoria_total = first(Categoria_total),
    Categoria_DO = first(Categoria_DO) # Consideramos la misma lógica para Categoria_DO
  ) %>%
  ungroup()


# Asignar las categorias
df_consolidado <- df_consolidado %>%
  mutate(
    Indice = case_when(
      duracion < 12 & Categoria_total == "<=16;>24" ~ "Inocuo",
      duracion < 12 & Categoria_total == "<=16;]5-24]" ~ "Estres fisiologico",
      duracion<12 & Categoria_total == "<=16;]2-5]"~ "Estres fisiologico",
      duracion<12 & Categoria_total =="<=16;<=2" ~ "Estres fisiologico",
      duracion<12 & Categoria_total == "]16-20];>24" ~ "Inocuo",
      duracion<12 & Categoria_total == "]16-20];]5-24]" ~ "Estres fisiologico",
      duracion<12 & Categoria_total =="]16-20];]2-5]" ~ "Sin informacion",
      duracion<12 & Categoria_total == "]16-20];<=2" ~ "Sin informacion",
      duracion<12 & Categoria_total == "]20-25];>24" ~ "Inocuo",
      duracion <12 & Categoria_total == "]20-25];]5-24]"~"Estres fisiologico",
      duracion<12 & Categoria_total == "]20-25];]2-5]" ~ "Sin informacion",
      duracion<12 & Categoria_total == "]20-25];<=2" ~ "Probabilidad de mortalidad",
      duracion<12 & Categoria_total == "25-29];>24" ~ "Sin informacion",
      duracion <12 & Categoria_total == "]25-29];]5-24]"~"Sin informacion",
      duracion<12 & Categoria_total == "]25-29];]2-5]" ~ "Sin informacion",
      duracion<12 & Categoria_total == "]25-29];<=2" ~ "Probabilidad de mortalidad",
      duracion<12 & Categoria_total == ">29;>24" ~ "Probabilidad de mortalidad",
      duracion <12 & Categoria_total == ">29;5-24]"~ "Letal",
      duracion<12 & Categoria_total== ">29;]2-5]" ~ "Letal",
      duracion<12 & Categoria_total == ">29;<=2" ~ "Letal",
      duracion >= 12 & duracion < 24 & Categoria_total == "<=16;>24" ~ "Inocuo",
      duracion >= 12 & duracion < 24 & Categoria_total == "<=16;]5-24]" ~ "Estres fisiologico",
      duracion >= 12 & duracion < 24  & Categoria_total == "<=16;]2-5]"  ~ "Estres fisiologico",
      duracion >= 12 & duracion < 24  & Categoria_total == "<=16;<=2"  ~ "Estres fisiologico",
      duracion >= 12 & duracion < 24 & Categoria_total == "]16-20];>24" ~ "Inocuo",
      duracion >= 12 & duracion < 24  & Categoria_total == "]16-20];]5-24]"  ~ "Estres fisiologico",
      duracion >= 12 & duracion < 24 & Categoria_total == "]16-20];]2-5]"  ~ "Sin informacion",
      duracion >= 12 & duracion < 24 & Categoria_total == "]16-20];<=2"  ~ "Probabilidad de mortalidad",
      duracion >= 12 & duracion < 24 & Categoria_total == "]20-25];>24"  ~ "Inocuo",
      duracion >= 12 & duracion < 24 & Categoria_total == "]20-25];]5-24]"  ~ "Estres fisiologico",
      duracion >= 12 & duracion < 24 & Categoria_total == "]20-25];]2-5]"  ~ "Sin informacion",
      duracion >= 12 & duracion < 24 & Categoria_total == "]20-25];<=2"  ~ "Letal",
      duracion >= 12 & duracion < 24 & Categoria_total == "]25-29];>24"   ~ "Sin informacion",
      duracion >= 12 & duracion < 24 &Categoria_total == "]25-29];]5-24]"  ~ "Sin informacion",
      duracion >= 12 & duracion < 24 & Categoria_total == "]25-29];]2-5]"   ~ "Sin informacion",
      duracion >= 12 & duracion < 24 & Categoria_total == "]25-29];<=2"  ~ "Letal",
      duracion >= 12 & duracion < 24 & Categoria_total == ">29;>24"  ~ "Probabilidad de mortalidad",
      duracion >= 12 & duracion < 24 & Categoria_total == ">29;5-24]"  ~ "Letal",
      duracion >= 12 & duracion < 24 & Categoria_total == ">29;]2-5]"  ~ "Letal",
      duracion >= 12 & duracion < 24 & Categoria_total  == ">29;<=2"  ~ "Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == "<=16;>24"  ~ "Inocuo",
      duracion >= 24 & duracion < 48 & Categoria_total == "<=16;]5-24]" ~ "Estres fisiologico",
      duracion >= 24 & duracion < 48 & Categoria_total == "<=16;]2-5]"  ~ "Estres fisiologico",
      duracion >= 24 & duracion < 48 & Categoria_total == "<=16;<=2" ~ "Probabilidad de mortalidad",
      duracion >= 24 & duracion < 48 & Categoria_total == "]16-20];>24" ~ "Inocuo",
      duracion >= 24 & duracion < 48 & Categoria_total == "]16-20];]5-24]" ~ "Estres fisiologico",
      duracion >= 24 & duracion < 48 & Categoria_total == "]16-20];]2-5]" ~ "Estres fisiologico",
      duracion >= 24 & duracion < 48 & Categoria_total == "]16-20];<=2"  ~ "Probabilidad de mortalidad",
      duracion >= 24 & duracion < 48 & Categoria_total == "]20-25];>24" ~ "Inocuo",
      duracion >= 24 & duracion < 48 & Categoria_total == "]20-25];]5-24]" ~ "Estres fisiologico",
      duracion >= 24 & duracion < 48 & Categoria_total == "]20-25];]2-5]" ~ "Probabilidad de mortalidad",
      duracion >= 24 & duracion < 48 & Categoria_total == "]20-25];<=2" ~ "Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == "]25-29];>24" ~ "Probabilidad de mortalidad",
      duracion >= 24 & duracion < 48 & Categoria_total == "]25-29];]5-24]" ~ "Probabilidad de mortalidad",
      duracion >= 24 & duracion < 48 & Categoria_total == "]25-29];]2-5]" ~ "Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == "]25-29];<=2" ~ "Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == ">29;>24"~ "Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == ">29;5-24]"~"Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == ">29;]2-5]"~"Letal",
      duracion >= 24 & duracion < 48 & Categoria_total == ">29;<=2" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == "<=16;>24" ~ "Inocuo",
      duracion >= 48 & duracion < 120 & Categoria_total == "<=16;]5-24]" ~ "Probabilidad de mortalidad",
      duracion >= 48 & duracion < 120 & Categoria_total == "<=16;]2-5]" ~ "Probabilidad de mortalidad",
      duracion >= 48 & duracion < 120 & Categoria_total == "<=16;<=2" ~ "Letal",
      duracion >= 48 & duracion < 120& Categoria_total == "]16-20];>24" ~ "Inocuo",
      duracion >= 48 & duracion < 120& Categoria_total == "]16-20];]5-24]" ~ "Sin informacion",
      duracion >= 48 & duracion < 120 & Categoria_total == "]16-20];]2-5]" ~ "Sin informacion",
      duracion >= 48 & duracion < 120 & Categoria_total == "]16-20];<=2" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == "]20-25];>24" ~ "Inocuo",
      duracion >= 48 & duracion < 120& Categoria_total == "]20-25];]5-24]" ~ "Sin informacion",
      duracion >= 48 & duracion < 120 & Categoria_total == "]20-25];]2-5]" ~ "Sin informacion",
      duracion >= 48 & duracion < 120 & Categoria_total == "]20-25];<=2" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == "]25-29];>24" ~ "Probabilidad de mortalidad",
      duracion >= 48 & duracion < 120 & Categoria_total == "]25-29];]5-24]" ~ "Sin informacion",
      duracion >= 48 & duracion < 120 & Categoria_total == "]25-29];]2-5]" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == "]25-29];<=2" ~ "Letal",
      duracion >= 48 & duracion < 120& Categoria_total == ">29;>24" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == ">29;5-24]" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == ">29;]2-5]" ~ "Letal",
      duracion >= 48 & duracion < 120 & Categoria_total == ">29;<=2" ~ "Letal",
      duracion >=120 & Categoria_total == "<=16;>24" ~ "Inocuo",
      duracion >=120 & Categoria_total == "]16-20];>24" ~ "Inocuo",
      duracion >=120 & Categoria_total == "]20-25];>24" ~ "Inocuo",
      TRUE ~ "Sin informacion"
    )
  )

# Ordenar el dataframe por fecha de inicio
df_consolidado <- df_consolidado %>% arrange(fecha_inicio)

# Convertir las columnas de fecha a POSIXct si no lo están
df_consolidado$fecha_inicio <- as.POSIXct(df_consolidado$fecha_inicio, tz="UTC")
df_consolidado$fecha_fin <- as.POSIXct(df_consolidado$fecha_fin, tz="UTC")

#Función para calcular el punto medio de un intervalo de fechas
interval_midpoint <- function(start, end) {
  return(start + (end - start) / 2)
}

# Agregar la columna Hora_Lima a df_agrupado usando interval_midpoint
df_consolidado <- df_consolidado %>%
  mutate(Hora_Lima = interval_midpoint(fecha_inicio, fecha_fin))

# Definir los colores de las categorías
colores_categorias <- c("Letal" = "#800000",  # Rojo oscuro
                        "Probabilidad de mortalidad" = "red",
                        "Estres fisiologico" = "orange",
                        "Inocuo" = "green",
                        "Sin informacion" = "grey")

df_consolidado <- df_consolidado %>%
  mutate(fecha_fin = fecha_fin - microseconds(1))  # Restamos 1 segundo para que fecha_fin sea inclusiva

ggplot() +
  # Capa 1: fondo con rectángulos de df_consolidado
  geom_rect(
    data = df_consolidado,
    aes(
      xmin = as.POSIXct(fecha_inicio, tz = "UTC"),
      xmax = as.POSIXct(fecha_fin, tz = "UTC"),
      ymin = -Inf,
      ymax = Inf,
      fill = Indice
    ),
    alpha = 0.8,
    color = NA
  ) +
  scale_fill_manual(values = colores_categorias) +
  
  # Capa 2: líneas de constnate_2019 con agrupación
  geom_line(
    data = constante_2019,
    aes(x = Hora_Lima, y = DO_sat, group = group),
    color = "black"
  ) +
  
  # Capa 3: punto crítico de oxígeno
  geom_text(
    data = data.frame(
      x = as.POSIXct("2019-01-15", tz = "UTC"),
      y = 27,
      label = "Punto crítico de oxígeno"
    ),
    aes(x = x, y = y, label = label),
    color = "red",
    size = 3.5
  ) +
  
  # Capa 4: línea horizontal crítica
  geom_hline(yintercept = 24, color = "red") +
  
  # Tema y personalización
  theme_minimal() +
  scale_x_datetime(breaks = "1 week", date_labels = "%d/%b") +
  labs(x = "", y = "Saturación de oxígeno (%)", title = "Mortalidad 2019 - Constante") +
  theme(
    title = element_text(size = 20),
    axis.text.x = element_text(size = 10, color = "black"),
    axis.text.y = element_text(size = 14, color = "black"),
    axis.title.x = element_text(size = 16),
    axis.title.y = element_text(size = 16),
    legend.text = element_text(size = 12),
    legend.title = element_text(size = 14),
    legend.position = "bottom",
    axis.ticks.length = unit(5, "pt"), # Longitud de los ticks
    axis.ticks.x = element_line(color = "black"), # Color de los ticks X
    axis.ticks.y = element_line(color = "black"),  # Color de los ticks Y
    axis.line.x = element_line(color = "black", size = 0.5), # Línea horizontal del eje
    axis.line.y = element_line(color = "black", size = 0.5)  # Línea vertical del eje
  ) +
  
  # Anotaciones adicionales
  annotate(
    "rect",
    xmin = as.POSIXct("2019-03-04", tz = "UTC"),
    xmax = as.POSIXct("2019-03-13", tz = "UTC"),
    ymin = -Inf,
    ymax = Inf,
    alpha = 0,
    color = "#636363",
    size = 0.7,
    linetype = "dashed"
  ) +
  geom_text(
    data = data.frame(
      x = as.POSIXct("2019-03-10", tz = "UTC"),
      y = 98,
      label = "Mortalidad"
    ),
    aes(x = x, y = y, label = label),
    color = "#636363",
    size = 4
  )

Puntos negativos:

  • Antes del periodo de Mortalidad, no sale “Probabilidad de mortalidad”, por lo que, en ese caso, el sistema de alerta temprana no funciona.

  • Durante la Mortalidad, el periodo de letalidad es muy corto, no abarca el evento entero.

  • Podría ser todo letal, pero la toma de datos durante la mortalidad no fue estrictamente todas las horas, por ende, no cumple con el criterio de duracion >6h… dificil de clasificar dentro de la categoria Letal.

LS0tDQp0aXRsZTogIlJlcG9ydGUgVGVzaXMgUHJlZ3JhZG8iDQpzdWJ0aXRsZTogIlJlc3VsdGFkb3MiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KYXV0aG9yOiAiUmViZWNhIENhbXBvcyBDdWVsbGFyIg0KZGF0ZTogIjIwMjUtMDEtMTgiDQotLS0NCiMgSW50cm9kdWNjaW9uDQoNCkVuIGVzdGUgcmVwb3J0ZSBlc3TDoW4gbG9zIGPDs2RpZ29zIGRlIGxvcyByZXN1bHRhZG9zIGRlIGxhIHRlc2lzIGRlIFByZWdyYWRvICoqRWxhYm9yYWNpb24gZGUgdW5hIG1hdHJpeiBkZSByZXNwdWVzdGFzIGJpb2zDs2dpY2FzIGZyZW50ZSBhIGxhIHRlbXBlcmF0dXJhIGUgaGlwb3hpYSBwYXJhIGxhIGV2YWx1YWNpw7NuIGRlIHJpZXNnb3MgZW4gY3VsdGl2byBkZSBmb25kbyBkZSAqQXJnb3BlY3RlbiBwdXJwdXJhdHVzKiwgY29uY2hhIGRlIGFiYW5pY28sIGVuIGxhIEJhaMOtYSBkZSBTZWNodXJhKioNCg0KUGFyYSBsYSBlamVjdWNpw7NuIGRlIGxhIHRlc2lzIHNlIHV0aWxpemFyb24gbG9zIGRhdG9zIGRlbCBhcnTDrWN1bG8gKipbQ3VldG8tVmVnYSBldCBhbC4gMjAyMl0oaHR0cHM6Ly9vbmxpbmVsaWJyYXJ5LndpbGV5LmNvbS9kb2kvZnVsbC8xMC4xMTExL2p3YXMuMTI3NzcpKiogeSBsb3MgZGF0b3MgcmVjb3BpbGFkb3MgcG9yICoqQWd1aXJyZS1WZWxhcmRlKiogZHVyYW50ZSBsYSBtb3J0YWxpZGFkIGRlIGNvbmNoYSBkZSBhYmFuaWNvIGRlbCAyMDE5Lg0KPGJyPiAgICAgIA0KPHRhYmxlPg0KUHJvZ3JhbWEgZGUgbW9uaXRvcmVvICAgICAgICBQYXLDoW1ldHJvIGFtYmllbnRhbCAgICAgICAgIFBlcmlvZG8gZGUgcmVnaXN0cm8gDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gICAtLS0tLS0tLS0tLS0tLS0tLS0tLS0gDQpDdWV0by1WZWdhIGV0IGFsLjIwMjIgICAgICAgIFRlbXBlcmF0dXJhIHkgU2F0dXJhY2lvbiBPRCAgMDcvMTEvMjAxMy0wNy8xMC8yMDE1ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICoqJioqICAyMy8wMy8yMDE3LTA3LzAyLzIwMTggDQpBZ3VpcnJlLVZlbGFyZGUgICAgICAgICAgICAgIFRlbXBlcmF0dXJhIHkgU2F0dXJhY2lvbiBPRCAgMDgvMDEvMjAxOS0yNi8wMy8yMDE5ICAgICAgICAgIA0KDQo8L3RhYmxlPg0KDQojIExpbXBpYW5kbyBsb3MgZGF0b3MgDQpQYXJhIGxpbXBpYXIgbGFzIGJhc2UgZGUgZGF0b3Mgc2Ugc2VndWlyYW4gbG9zIHNpZ3VpZW50ZXMgcGFzb3M6DQoNCiAxLiBVbmlmb3JtaXphciBlbCBmb3JtYXRvIGRlIGxhcyBob3JhczogdGltZXpvbmUgVVRDLCBjb24gZWwgbm9tYnJlIEhvcmFfTGltYQ0KIDIuIEFzaWduYXIgZWwgbWlzbW8gbm9tYnJlIGEgbGEgdmFyaWFibGUgdGVtcGVyYXR1cmEgZGUgZm9uZG86IFRlbXBfZm9uZA0KIDMuIEFzaWduYXIgZWwgbWlzbW8gbm9tYnJlIGEgbGEgdmFyaWFibGUgc2F0dXJhY2lvbiBkZSBveGlnZW5vIGRpc3VlbHRvOiBET19zYXQNCiA0LiBFbiBjYXNvIGhheWEgbWFzIGRlIHVuIGRhdG8gcG9yIGhvcmEsIGJ0ZW5lciB1biB2YWxvciBwcm9tZWRpbw0KIDUuIFZlcmlmaWNhciBzaSBoYXkgZmlsYXMgZHVwbGljYWRhcywgdmFsb3JlcyBOQSwgdmFsb3JlcyBuZWdhdGl2b3MuDQogNi4gQXNpZ25hciB1bmEgY29sdW1uYSBjb24gZWwgbm9tYnJlIGRlIGxhIGJhc2UgZGUgZGF0b3MgZGUgb3JpZ2VuLg0KDQpgYGB7cn0NCiN8IGluY2x1ZGUgPSBGQUxTRQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoc24pDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHBhdGNod29yaykNCmxpYnJhcnkoY2FyKQ0KbGlicmFyeShnZ2Rpc3QpIA0KbGlicmFyeShwdXJycikNCmxpYnJhcnkoRlNBKQ0KbGlicmFyeShndCkNCmxpYnJhcnkoZ2dzdGF0c3Bsb3QpDQpsaWJyYXJ5KG1pbnBhY2subG0pDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShwbG90bHkpDQpgYGANCioqTGltcGllemEgZGUgYmRkOiBDdWV0by1WZWdhIGV0IGFsLiAyMDIyKioNCmBgYHtyIGxpbXBpYW5kbyBDdWV0by1WZWdhLCBlY2hvPVRSVUUscmVzdWx0cz0iaGlkZSIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpjb25zdGFudGVfbG9nZ2VycyA8LSByZWFkX2NzdigiZGF0b3MvYmQtQVJUVVJPLVBJQ0VTX1NlY2h1cmFfU3RyZXNzb3JzL0NPTlNUQU5URV9sb2dnZXJzX2hpc3Rvcmljby5jc3YiKSAlPiUNCiAgbXV0YXRlKA0KICAgIEhvcmFfTGltYSA9IGFzLlBPU0lYY3QoSG9yYV9MaW1hLCBmb3JtYXQgPSAiJVktJW0tJWQgJUg6JU06JVMiLCB0eiA9ICJVVEMiKSwNCiAgICBUZW1wX2ZvbmQgPSBUZW1wICANCiAgICApICU+JQ0KICBzZWxlY3QoSG9yYV9MaW1hLCBUZW1wX2ZvbmQsIERPX3NhdCkgJT4lDQogIGdyb3VwX2J5KEhvcmFfTGltYSkgJT4lIA0KICBzdW1tYXJpc2UoDQogICAgVGVtcF9mb25kID0gbWVhbihUZW1wX2ZvbmQsIG5hLnJtID0gVFJVRSksDQogICAgRE9fc2F0ID0gbWVhbihET19zYXQsIG5hLnJtID0gVFJVRSkNCiAgICApIA0KDQp2YWxvcmVzX2R1cGxpY2Fkb3MgPC0gY29uc3RhbnRlX2xvZ2dlcnMkSG9yYV9MaW1hW2R1cGxpY2F0ZWQoY29uc3RhbnRlX2xvZ2dlcnMkSG9yYV9MaW1hKV0NCnByaW50KHVuaXF1ZSh2YWxvcmVzX2R1cGxpY2Fkb3MpKSANCg0KY29sU3Vtcyhpcy5uYShjb25zdGFudGVfbG9nZ2VycykpICANCmVsaW1pbmFyIDwtIHdoaWNoKGFwcGx5KGlzLm5hKGNvbnN0YW50ZV9sb2dnZXJzKSwgMSwgYW55KSkgI0hheSAxMTgyMSBmaWxhcyBxdWUgbm8gdGllbmUgZGF0b3MgZGUgRE9fc2F0DQpjb25zdGFudGVfbG9nZ2VycyA8LSBjb25zdGFudGVfbG9nZ2Vyc1stZWxpbWluYXIsIF0gDQpjb2xTdW1zKGlzLm5hbihhcy5tYXRyaXgoY29uc3RhbnRlX2xvZ2dlcnMpKSkgIA0KYW55KGNvbnN0YW50ZV9sb2dnZXJzIDwgMCwgbmEucm0gPSBUUlVFKQ0KY29uc3RhbnRlX2xvZ2dlcnMgPC0gZmlsdGVyKGNvbnN0YW50ZV9sb2dnZXJzLCBET19zYXQgPj0gMCwgRE9fc2F0IDw9MTAwLCAhaXMubmEoRE9fc2F0KSkNCg0KY29uc3RhbnRlX2xvZ2dlcnMgPC0gY29uc3RhbnRlX2xvZ2dlcnMgJT4lDQogIG11dGF0ZSgNCiAgICBiZGQgPSAiQ3VldG8tVmVnYV8yMDIyIiwNCiAgICBab25hID0gIkNvbnN0YW50ZSIpIA0KYGBgDQoqKkxpbXBlemEgZGUgYmRkOiBBZ3VpcnJlLVZlbGFyZGUgMjAxOSoqDQpMb3MgZGF0b3MgcmVjb3BpbGFkb3MgcG9yIEFndWlycmUtVmVsYXJkZSBlbiBlbCAyMDE5IGVzdGFuIGNvbmZvcm1hZG9zIHBvciBkb3MgYXJjaGl2b3MgY3N2Og0KDQoqIENvbnN0YW50ZV9sb2dnZXJzLmNzdiAoMDggZW5lcm8gMjAxOSAtIDA0IG1hcnpvIDIwMTkpDQpgYGB7ciBsaW1waWFuZG8gQ29uc3RhbnRlX2xvZ2dlcnMsIGVjaG89VFJVRSwgcmVzdWx0cz0iaGlkZSIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMgQkREIENvbnN0YW50ZV9sb2dnZXJzICMjIyMNCmNvbnN0YW50ZV9URE8gPC0gcmVhZC5jc3YoImRhdG9zL0luZm9ybWVfU2VjaHVyYU1vcnQyMDE5L0NvbnN0YW50ZV9sb2dnZXJzLmNzdiIsIGhlYWRlciA9IFRSVUUsIGRlYyA9ICIuIiwgc2VwID0gIiwiKSAlPiUNCiAgbXV0YXRlKA0KICAgIEhvcmFfTGltYSA9IGFzLlBPU0lYY3QoSG9yYV9MaW1hLCBmb3JtYXQgPSAiJWQvJW0vJVkgJUg6JU0iLCB0ej0iVVRDIiksDQogICAgVGVtcF9mb25kID0gVGVtcCAgDQogICAgKSAlPiUNCiAgc2VsZWN0KEhvcmFfTGltYSwgVGVtcF9mb25kLCBET19zYXQpICU+JQ0KICBncm91cF9ieShIb3JhX0xpbWEpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIFRlbXBfZm9uZCA9IG1lYW4oVGVtcF9mb25kLCBuYS5ybSA9IFRSVUUpLA0KICAgIERPX3NhdCA9IG1lYW4oRE9fc2F0LCBuYS5ybSA9IFRSVUUpDQogICAgKQ0KDQp2YWxvcmVzX2R1cGxpY2Fkb3MgPC0gY29uc3RhbnRlX1RETyRIb3JhX0xpbWFbZHVwbGljYXRlZChjb25zdGFudGVfVERPJEhvcmFfTGltYSldDQpwcmludCh1bmlxdWUodmFsb3Jlc19kdXBsaWNhZG9zKSkgDQoNCmNvbFN1bXMoaXMubmEoY29uc3RhbnRlX1RETykpICANCndoaWNoKGFwcGx5KGlzLm5hKGNvbnN0YW50ZV9URE8pLCAxLCBhbnkpKSAjTGEgZmlsYSAxMzIxIG5vIHRpZW5lIGRhdG9zDQpjb25zdGFudGVfVERPIDwtIGNvbnN0YW50ZV9URE9bLTEzMjEsIF0NCg0KY29sU3Vtcyhpcy5uYW4oYXMubWF0cml4KGNvbnN0YW50ZV9URE8pKSkgIA0KDQphbnkoY29uc3RhbnRlX1RETyA8IDAsIG5hLnJtID0gVFJVRSkNCg0KY29uc3RhbnRlX1RETyA8LSBjb25zdGFudGVfVERPICU+JQ0KICBtdXRhdGUoDQogICAgYmRkID0gIkNvbnN0YW50ZV9URE8iLA0KICAgIFpvbmEgPSAiQ29uc3RhbnRlIikgIA0KYGBgIA0KKiBDb25zdGFudGVfbXVsdGkuY3N2ICgwNSBtYXJ6byAtIDI2IGRlIG1hcnpvIDIwMTkpDQoNCkVuIGVzdGEgYmFzZSBkZSBkYXRvcywgZWwgb3jDrWdlbm8gZXN0YSBlbiBtZy9MLCBwb3IgbG8gcXVlIHNlIGRlYmUgY29udmVydGlyIERPX2MgKG1nL2wpIGVuIERPX3NhdCAoJSkuIFBhcmEgZWxsbywgc2Ugc2VndWlyw6FuIGxhcyBlY3VhY2lvbmVzIHByb3B1ZXN0YXMgcG9yIEJlbnNvbiB5IEtyYXVzZSwgMTk4NDsgdXRpbGl6YWRhcyBwb3IgW1lET0NdKGh0dHBzOi8veWRvYy5iaXovZGlzc29sdmVkLW94eWdlbi1tZWFzdXJlbWVudHMvKTogZW1wcmVzYSBob2xhbmRlc2EgZXNwZWNpYWxpemFkYSBlbiBtZWRpY2lvbmVzIHBvciBkYXRhIGxvZ2dlcnMuDQpgYGB7ciBsaW1waWFuZG8gQ29uc3RhbnRlX211bHRpLCBlY2hvPVRSVUUsIHJlc3VsdHM9ImhpZGUiLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMjIEJERCBjb25zdGFudGVfbXVsdGkgIyMjIyMjDQpjb25zdGFudGVfbXVsdGkgPC0gcmVhZC5jc3YoImRhdG9zL0luZm9ybWVfU2VjaHVyYU1vcnQyMDE5L2NvbnN0YW50ZV9tdWx0aS5jc3YiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkZXIgPSBUUlVFLCBkZWMgPSAiLiIsIHNlcCA9ICIsIikgJT4lDQogIG11dGF0ZSgNCiAgICBIb3JhX0xpbWEgPSBhcy5QT1NJWGN0KEhvcmFfTGltYSwgZm9ybWF0ID0gIiVkLyVtLyVZICVIOiVNOiVTIiwgdHo9IlVUQyIpLA0KICAgIEhvcmFfTGltYSA9IG1ha2VfZGF0ZXRpbWUoeWVhcihIb3JhX0xpbWEpLCBtb250aChIb3JhX0xpbWEpLCBkYXkoSG9yYV9MaW1hKSwgaG91cihIb3JhX0xpbWEpKSwNCiAgICBET19jID0gRE9fZm9uZCwgIA0KICAgIFRlbXBfZm9uZCA9IFRfZm9uZCwNCiAgICBUZW1wX2tlbHZpbiA9IFRlbXBfZm9uZCArIDI3My4xNSAgIyBDb252ZXJ0aXIgdGVtcGVyYXR1cmEgYSBLZWx2aW4NCiAgKSAlPiUNCiAgc2VsZWN0KEhvcmFfTGltYSwgVGVtcF9mb25kLCBUZW1wX2tlbHZpbiwgRE9fYykgJT4lDQogIGdyb3VwX2J5KEhvcmFfTGltYSkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBUZW1wX2ZvbmQgPSBtZWFuKFRlbXBfZm9uZCwgbmEucm0gPSBUUlVFKSwNCiAgICBET19jID0gbWVhbihET19jLCBuYS5ybSA9IFRSVUUpLA0KICAgIFRlbXBfa2VsdmluPW1lYW4oVGVtcF9rZWx2aW4sIG5hLnJtPVRSVUUpDQogICkNCg0KdmFsb3Jlc19kdXBsaWNhZG9zIDwtIGNvbnN0YW50ZV9tdWx0aSRIb3JhX0xpbWFbZHVwbGljYXRlZChjb25zdGFudGVfbXVsdGkkSG9yYV9MaW1hKV0NCnByaW50KHVuaXF1ZSh2YWxvcmVzX2R1cGxpY2Fkb3MpKQ0KDQpjb2xTdW1zKGlzLm5hKGNvbnN0YW50ZV9tdWx0aSkpDQplbGltaW5hciA8LSB3aGljaChhcHBseShpcy5uYShjb25zdGFudGVfbXVsdGkpLCAxLCBhbnkpKQ0KY29uc3RhbnRlX211bHRpIDwtIGNvbnN0YW50ZV9tdWx0aVstZWxpbWluYXIsXSANCmNvbFN1bXMoaXMubmFuKGFzLm1hdHJpeChjb25zdGFudGVfbXVsdGkpKSkNCg0KYW55KGNvbnN0YW50ZV9URE8gPCAwLCBuYS5ybSA9IFRSVUUpDQoNCiMjIENvbnZlcnRpciBET19jIChtZy9sKSBlbiBET19zYXQgKCUpIHNpZ3VpZW5kbyBlY3VhY2lvbmVzIGRlIEJlbnNvbiBhbmQgS3JhdXNlLCAxOTg0DQojIERlZmluaXIgc2FsaW5pZGFkIGVuIHBwdCAoZy9rZykNClNBTCA8LSAzNQ0KDQojIENhbGN1bGFyIERPX0MgKGNvcnJpZ2llbmRvIHBvciBzYWxpbmlkYWQpDQpjb25zdGFudGVfbXVsdGkgPC0gY29uc3RhbnRlX211bHRpICU+JQ0KICBtdXRhdGUoDQogICAgRE9fQyA9IERPX2MgKiBleHAoLTEgKiBTQUwgKiAoMC4wMTc2NzQgKyAoLTEwLjc1NCArIDIxNDAuNyAvIFRlbXBfa2VsdmluKSAvIFRlbXBfa2VsdmluKSkNCiAgKQ0KDQojIENhbGN1bGFyIERPIHNhdHVyYWRvIGVuIG1nL0wNCmNvbnN0YW50ZV9tdWx0aSA8LSBjb25zdGFudGVfbXVsdGkgJT4lDQogIG11dGF0ZSgNCiAgICBET19zYXRfbWdMID0gZXhwKC0xMzkuMzQ0MTEgKyAoMS41NzU3MDFlNSArICgtNi42NDIzMDhlNyArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDEuMjQzOGUxMCAtIDguNjIxOTQ5ZTExIC8gVGVtcF9rZWx2aW4pIC8gVGVtcF9rZWx2aW4pIC8gVGVtcF9rZWx2aW4pIC8gVGVtcF9rZWx2aW4pICoNCiAgICAgIGV4cCgtMSAqIFNBTCAqICgwLjAxNzY3NCArICgtMTAuNzU0ICsgMjE0MC43IC8gVGVtcF9rZWx2aW4pIC8gVGVtcF9rZWx2aW4pKQ0KICApDQoNCiMgQ2FsY3VsYXIgRE8gc2F0dXJhZG8gZW4gJSANCmNvbnN0YW50ZV9tdWx0aSA8LSBjb25zdGFudGVfbXVsdGkgJT4lDQogIG11dGF0ZSgNCiAgICBET19zYXQgPSAoRE9fQyAvIERPX3NhdF9tZ0wpICogMTAwDQogICkgJT4lDQpzZWxlY3QoSG9yYV9MaW1hLCBUZW1wX2ZvbmQsIERPX3NhdCkgDQoNCiNBZ3JlZ2FyIGNvbHVtbmFzIGJkZA0KY29uc3RhbnRlX211bHRpIDwtIGNvbnN0YW50ZV9tdWx0aSAlPiUNCiAgbXV0YXRlKA0KICAgIGJkZCA9ICJDb25zdGFudGVfbXVsdGkiLA0KICAgIFpvbmEgPSAiQ29uc3RhbnRlIikgDQoNCmBgYA0KRmluYWxtZW50ZSwgbGFzIGJhc2VzIGRlIGRhdG9zIHNlIHVuaXLDoW4gZW4gdW5hIHNvbGEsIGxhIGN1YWwgc2Vyw6EgbGxhbWFkYSAqKiJjb25zdGFudGUiLioqDQpFbiBlc3RhIG51ZXZhIGJkZCwgc2UgYWdyZWdhcsOhIGxhIGNvbHVtbmEgIk1vcnRhbGlkYWQiLiAgDQoNCiogTW9ydGFsaWRhZCAyMDE1OiAyMSBmZWJyZXJvIC0gKiowMiBtYXJ6byAtIDE1IG1hcnpvIDIwMTUqKg0KKiBNb3J0YWxpZGFkIDIwMTk6IDE5IGZlYnJlcm8gLSAqKjA0IG1hcnpvIC0gMTMgbWFyem8gMjAxOSoqDQoqIE5vIG1vcnRhbGlkYWQ6IHJlc3RvIGRlIGRhdG9zDQpgYGB7ciwgZWNobz1UUlVFLCByZXN1bHRzPSJoaWRlIiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmJhcnJhbmNvcyA8LSByZWFkX2NzdigiZGF0b3MvYmQtQVJUVVJPLVBJQ0VTX1NlY2h1cmFfU3RyZXNzb3JzL0JBUlJBTkNPU19sb2dnZXJzX2hpc3Rvcmljby5jc3YiKSAlPiUNCiAgbXV0YXRlKA0KICAgIEhvcmFfTGltYSA9IGFzLlBPU0lYY3QoSG9yYV9MaW1hLCBmb3JtYXQgPSAiJVktJW0tJWQgJUg6JU06JVMiLCB0eiA9ICJVVEMiKSwNCiAgICBUZW1wX2ZvbmQgPSBUZW1wICANCiAgKSAlPiUNCiAgc2VsZWN0KEhvcmFfTGltYSwgVGVtcF9mb25kLCBET19zYXQpICU+JQ0KICBncm91cF9ieShIb3JhX0xpbWEpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIFRlbXBfZm9uZCA9IG1lYW4oVGVtcF9mb25kLCBuYS5ybSA9IFRSVUUpLA0KICAgIERPX3NhdCA9IG1lYW4oRE9fc2F0LCBuYS5ybSA9IFRSVUUpDQogICkgDQogIHZhbG9yZXNfZHVwbGljYWRvcyA8LSBiYXJyYW5jb3MkSG9yYV9MaW1hW2R1cGxpY2F0ZWQoYmFycmFuY29zJEhvcmFfTGltYSldDQogIGEgPC0gY29sU3Vtcyhpcy5uYShiYXJyYW5jb3MpKSAgDQogIGVsaW1pbmFyIDwtIHdoaWNoKGFwcGx5KGlzLm5hKGJhcnJhbmNvcyksIDEsIGFueSkpIA0KICBiYXJyYW5jb3MgPC0gYmFycmFuY29zWy1lbGltaW5hciwgXSANCiAgYSA8LSBjb2xTdW1zKGlzLm5hbihhcy5tYXRyaXgoYmFycmFuY29zKSkpICANCiAgYSA8LSBhbnkoYmFycmFuY29zIDwgMCwgbmEucm0gPSBUUlVFKQ0KICBiYXJyYW5jb3MgPC0gZmlsdGVyKGJhcnJhbmNvcywgRE9fc2F0ID49IDAsIERPX3NhdCA8PTEwMCwgIWlzLm5hKERPX3NhdCkpDQogIGJhcnJhbmNvcyA8LSBiYXJyYW5jb3MgJT4lDQogICAgbXV0YXRlKA0KICAgICAgYmRkID0gIkN1ZXRvLVZlZ2FfMjAyMiIsDQogICAgICBab25hID0gIkJhcnJhbmNvcyIpICANCg0KICBiYXJyYW5jb3NfZmlsdHIgPC0gYmFycmFuY29zICU+JQ0KICBmaWx0ZXIoSG9yYV9MaW1hID49IGFzLlBPU0lYY3QoIjIwMTUtMDItMjEiLCB0ej0iVVRDIikgJiBIb3JhX0xpbWEgPD0gYXMuUE9TSVhjdCgiMjAxNS0wMy0xNSIsIHR6PSJVVEMiKSkNCg0KYGBgDQoNCmBgYHtyLCBlY2hvPVRSVUUscmVzdWx0cz0iaGlkZSIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpjb25zdGFudGUgPC0gIGJpbmRfcm93cyhjb25zdGFudGVfbG9nZ2VycywgY29uc3RhbnRlX1RETywgY29uc3RhbnRlX211bHRpKSANCg0KdG90YWwgPC0gIGJpbmRfcm93cyhjb25zdGFudGUsIGJhcnJhbmNvc19maWx0cikgDQoNCnRvdGFsIDwtIHRvdGFsICU+JQ0KICBtdXRhdGUoDQogICAgWWVhciA9IGZvcm1hdChIb3JhX0xpbWEsICIlWSIpLCAgIyBFeHRyYWVyIGVsIGHDsW8NCiAgICBNb3J0YWxpZGFkID0gY2FzZV93aGVuKA0KICAgICAgKFpvbmEgPT0gIkJhcnJhbmNvcyIgJiBIb3JhX0xpbWEgPj0gYXMuUE9TSVhjdCgiMjAxNS0wMi0yMSIsIHR6ID0gIlVUQyIpICYgSG9yYV9MaW1hIDwgYXMuUE9TSVhjdCgiMjAxNS0wMy0xNSIsIHR6ID0gIlVUQyIpKSB+ICJNb3J0YWxpZGFkIDIwMTUgLSBCYXJyYW5jb3MiLA0KICAgICAgKFpvbmEgPT0gIkNvbnN0YW50ZSIgJiBIb3JhX0xpbWEgPj0gYXMuUE9TSVhjdCgiMjAxNS0wMi0yMSIsIHR6ID0gIlVUQyIpICYgSG9yYV9MaW1hIDwgYXMuUE9TSVhjdCgiMjAxNS0wMy0xNSIsIHR6ID0gIlVUQyIpKSB+ICJNb3J0YWxpZGFkIDIwMTUgLSBDb25zdGFudGUiLA0KICAgICAgKFpvbmEgPT0gIkNvbnN0YW50ZSIgJiBIb3JhX0xpbWEgPj0gYXMuUE9TSVhjdCgiMjAxOS0wMi0xOSIsIHR6ID0gIlVUQyIpICYgSG9yYV9MaW1hIDwgYXMuUE9TSVhjdCgiMjAxOS0wMy0xMyIsIHR6ID0gIlVUQyIpKSB+ICJNb3J0YWxpZGFkIDIwMTkgLSBDb25zdGFudGUiLA0KICAgICAgVFJVRSB+ICJObyBNb3J0YWxpZGFkIg0KICAgICkNCiAgKQ0KDQojIENvbnRhciBvYnNlcnZhY2lvbmVzIHBvciBjYXRlZ29yw61hIGRlIE1vcnRhbGlkYWQgeSBab25hDQpjb250ZW9fb2JzIDwtIHRvdGFsICU+JQ0KICBncm91cF9ieShNb3J0YWxpZGFkKSAlPiUNCiAgc3VtbWFyaXNlKENvbnRlbyA9IG4oKSwgLmdyb3VwcyA9ICJkcm9wIikNCg0KIyBWZXIgbG9zIHJlc3VsdGFkb3MNCnByaW50KGNvbnRlb19vYnMpDQpgYGANCg0KIyBWaXN1YWxpemFjaW9uIGRlIGRhdG9zOiANCg0KIyMgTW9ydGFsaWRhZCAyMDE1IHkgMjAxOSANCg0KRGUgb3jDrWdlbm8gZGlzdWVsdG8geSB0ZW1wZXJhdHVyYSwgZW4gZm9uZG8sIGR1cmFudGUgbGEgbW9ydGFsaWRhZCAyMDE1IHkgMjAxOQ0KDQoqKkRpZmVyZW5jaWFzIGR1cmFudGUgbGEgTW9ydGFsaWRhZCAyMDE1OiBCYXJyYW5jb3MgdnMgQ29uc3RhbnRlPz8qKg0KDQpgYGB7ciwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTgsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgRnVuY2nDs24gcGFyYSBhZ3JlZ2FyIGdydXBvcyBzZWfDum4gaHVlY29zIG1heW9yZXMgYSAyNCBob3Jhcw0KYWdyZWdhcl9ncnVwb3MgPC0gZnVuY3Rpb24oZGF0YSkgew0KICBkYXRhIDwtIGRhdGEgJT4lDQogICAgYXJyYW5nZShIb3JhX0xpbWEpICU+JSAgIyBBc2Vnw7pyYXRlIGRlIHF1ZSBlc3TDqSBvcmRlbmFkbyBwb3IgdGllbXBvDQogICAgbXV0YXRlKA0KICAgICAgdGltZV9kaWZmID0gYXMubnVtZXJpYyhkaWZmdGltZShIb3JhX0xpbWEsIGxhZyhIb3JhX0xpbWEpLCB1bml0cyA9ICJob3VycyIpKSwNCiAgICAgIGdyb3VwID0gY3Vtc3VtKGlmZWxzZShpcy5uYSh0aW1lX2RpZmYpIHwgdGltZV9kaWZmID4gMjQsIDEsIDApKQ0KICAgICkNCiAgcmV0dXJuKGRhdGEpDQp9DQoNCiNQZXJpb2RvcyBhIGdyYWZpY2FyIA0KYmFycmFuY29zXzIwMTUgPC0gYmFycmFuY29zICU+JQ0KICBmaWx0ZXIoSG9yYV9MaW1hID49IGFzLlBPU0lYY3QoIjIwMTUtMDEtMDgiLCB0ej0iVVRDIikgJiBIb3JhX0xpbWEgPD0gYXMuUE9TSVhjdCgiMjAxNS0wMy0xOCIsIHR6PSJVVEMiKSkNCg0KY29uc3RhbnRlXzIwMTUgPC0gY29uc3RhbnRlICU+JQ0KICBmaWx0ZXIoSG9yYV9MaW1hID49IGFzLlBPU0lYY3QoIjIwMTUtMDEtMDgiLCB0ej0iVVRDIikgJiBIb3JhX0xpbWEgPD0gYXMuUE9TSVhjdCgiMjAxNS0wMy0xOCIsIHR6PSJVVEMiKSkNCg0KY29uc3RhbnRlXzIwMTkgPC0gY29uc3RhbnRlICU+JQ0KICBmaWx0ZXIoSG9yYV9MaW1hID49IGFzLlBPU0lYY3QoIjIwMTktMDEtMDgiLCB0ej0iVVRDIikgJiBIb3JhX0xpbWEgPD0gYXMuUE9TSVhjdCgiMjAxOS0wMy0xOCIsIHR6PSJVVEMiKSkNCg0KIyBBcGxpY2FyIGxhIGZ1bmNpw7NuIGEgbG9zIGRhdGFzZXRzDQpiYXJyYW5jb3NfMjAxNSA8LSBhZ3JlZ2FyX2dydXBvcyhiYXJyYW5jb3NfMjAxNSkNCmNvbnN0YW50ZV8yMDE1IDwtICBhZ3JlZ2FyX2dydXBvcyhjb25zdGFudGVfMjAxNSkNCmNvbnN0YW50ZV8yMDE5IDwtIGFncmVnYXJfZ3J1cG9zKGNvbnN0YW50ZV8yMDE5KQ0KDQojIEFjdHVhbGl6YXIgbG9zIGdyw6FmaWNvcyBwYXJhIHVzYXIgJ2dyb3VwJw0KZ3JhZmljb19iYXJyYW5jb3NfMjAxNSA8LSBnZ3Bsb3QoYmFycmFuY29zXzIwMTUsIGFlcyh4ID0gSG9yYV9MaW1hLCB5ID0gRE9fc2F0LCBncm91cCA9IGdyb3VwKSkgKw0KICBnZW9tX3JlY3QoYWVzKHhtaW4gPSBhcy5QT1NJWGN0KCIyMDE1LTAzLTAyIiwgdHogPSAiVVRDIiksDQogICAgICAgICAgICAgICAgeG1heCA9IGFzLlBPU0lYY3QoIjIwMTUtMDMtMTQiLCB0eiA9ICJVVEMiKSwNCiAgICAgICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IEluZiksDQogICAgICAgICAgICBmaWxsID0gInBpbmsiLCBhbHBoYSA9IDAuMDMpICsgIA0KICBnZW9tX2xpbmUoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC41KSArICANCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMjQuNCwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAic29saWQiLCBzaXplID0gMC41KSArICANCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gYXMuUE9TSVhjdCgiMjAxNS0wMS0xNyIsIHR6ID0gIlVUQyIpLCB5ID0gMjYuNSwNCiAgICAgICAgICAgbGFiZWwgPSAiUHVudG8gY3LDrXRpY28gZGUgb3jDrWdlbm8iLCBjb2xvciA9ICJyZWQiLCBzaXplID0gNCkgKw0KICBzY2FsZV94X2RhdGV0aW1lKGRhdGVfYnJlYWtzID0gIjEgd2VlayIsIGRhdGVfbGFiZWxzID0gIiVkLyViIikgKyAgDQogIGxhYnMoIHg9IiIsDQogICAgeSA9ICJTYXR1cmFjacOzbiBkZSBveMOtZ2VubyAoJSkiLA0KICAgIHRpdGxlID0gIk1vcnRhbGlkYWQgMjAxNSAtIEJhcnJhbmNvcyIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgDQoNCmdyYWZpY29fY29uc3RhbnRlXzIwMTUgPC0gZ2dwbG90KGNvbnN0YW50ZV8yMDE1LCBhZXMoeCA9IEhvcmFfTGltYSwgeSA9IERPX3NhdCwgZ3JvdXAgPSBncm91cCkpICsNCiAgZ2VvbV9yZWN0KGFlcyh4bWluID0gYXMuUE9TSVhjdCgiMjAxNS0wMy0wMiIsIHR6ID0gIlVUQyIpLA0KICAgICAgICAgICAgICAgIHhtYXggPSBhcy5QT1NJWGN0KCIyMDE1LTAzLTE0IiwgdHogPSAiVVRDIiksDQogICAgICAgICAgICAgICAgeW1pbiA9IC1JbmYsIHltYXggPSBJbmYpLA0KICAgICAgICAgICAgZmlsbCA9ICJwaW5rIiwgYWxwaGEgPSAwLjAzKSArICANCiAgZ2VvbV9saW5lKGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuNSkgKyAgDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDI0LjQsIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gInNvbGlkIiwgc2l6ZSA9IDAuNSkgKyAgDQogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IGFzLlBPU0lYY3QoIjIwMTUtMDEtMTgiLCB0eiA9ICJVVEMiKSwgeSA9IDI2LjUsDQogICAgICAgICAgIGxhYmVsID0gIlB1bnRvIGNyw610aWNvIGRlIG94w61nZW5vIiwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDQpICsNCiAgc2NhbGVfeF9kYXRldGltZShkYXRlX2JyZWFrcyA9ICIxIHdlZWsiLCBkYXRlX2xhYmVscyA9ICIlZC8lYiIpICsgIA0KICBsYWJzKCB4PSAiIiwNCiAgICB5ID0gIlNhdHVyYWNpw7NuIGRlIG94w61nZW5vICglKSIsIHRpdGxlID0gIk1vcnRhbGlkYWQgMjAxNSAtIENvbnN0YW50ZSIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgDQoNCmdyYWZpY29fY29uc3RhbnRlXzIwMTkgPC0gZ2dwbG90KGNvbnN0YW50ZV8yMDE5LCBhZXMoeCA9IEhvcmFfTGltYSwgeSA9IERPX3NhdCwgZ3JvdXAgPSBncm91cCkpICsNCiAgZ2VvbV9yZWN0KGFlcyh4bWluID0gYXMuUE9TSVhjdCgiMjAxOS0wMy0wNCIsIHR6ID0gIlVUQyIpLA0KICAgICAgICAgICAgICAgIHhtYXggPSBhcy5QT1NJWGN0KCIyMDE5LTAzLTEzIiwgdHogPSAiVVRDIiksDQogICAgICAgICAgICAgICAgeW1pbiA9IC1JbmYsIHltYXggPSBJbmYpLA0KICAgICAgICAgICAgZmlsbCA9ICJwaW5rIiwgYWxwaGEgPSAwLjAzKSArICANCiAgZ2VvbV9saW5lKGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuNSkgKyAgDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDI0LCBjb2xvciA9ICJyZWQiLCBsaW5ldHlwZSA9ICJzb2xpZCIsIHNpemUgPSAwLjUpICsgIA0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSBhcy5QT1NJWGN0KCIyMDE5LTAxLTE2IiwgdHogPSAiVVRDIiksIHkgPSAyNi41LA0KICAgICAgICAgICBsYWJlbCA9ICJQdW50byBjcsOtdGljbyBkZSBveMOtZ2VubyIsIGNvbG9yID0gInJlZCIsIHNpemUgPSA0KSArDQogIHNjYWxlX3hfZGF0ZXRpbWUoZGF0ZV9icmVha3MgPSAiMSB3ZWVrIiwgZGF0ZV9sYWJlbHMgPSAiJWQvJWIiKSArIA0KICBsYWJzKHkgPSAiU2F0dXJhY2nDs24gZGUgb3jDrWdlbm8gKCUpIiwgdGl0bGUgPSAiTW9ydGFsaWRhZCAyMDE5IiwgeCA9ICJUaWVtcG8gKGTDrWEvbWVzKSIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgDQoNCiMgQ29tYmluYXIgbG9zIGdyw6FmaWNvcw0KZ3JpZC5hcnJhbmdlKA0KICBncmFmaWNvX2JhcnJhbmNvc18yMDE1LCANCiAgZ3JhZmljb19jb25zdGFudGVfMjAxNSwgDQogIGdyYWZpY29fY29uc3RhbnRlXzIwMTksIA0KICBuY29sID0gMSkNCmBgYA0KDQojIEFuw6FsaXNpcyBlc3RhZMOtc3RpY29zDQoNCnZlciBjdWFudG9zIGRhdG9zIHBvciBncnVwbyA6IGN1YW50b3MgcmVnaXN0cm9zIHBvciBob3JhIHBhcmEgY2FkYSB0aXBvIGRlIG1vcnRhbGlkYWQgKGhpc3RvZ3JhbWEpIA0KdmVyIG5vcm1hbGlkYWQgZGUgbG9zIGRhdG9zIHBvciBncnVwbw0KDQpEZWJlcmlhIGhhY2VyIGJvb3RzdHJhcHBpbmc/DQoNCg0KUGFyYSByZWFsaXphciBlbCBhbsOhbGlzaXMgZXN0YWTDrXN0aWNvLCBzZSBsbGV2YXLDoSBhIGNhYm8gdW4gYW7DoWxpc2lzIHByZWxpbWluYXIgcGFyYSBkZXRlcm1pbmFyIHNpIGxvcyBkYXRvcyBjdW1wbGVuIGNvbiBsb3MgcmVxdWlzaXRvcyBwYXJhIHJlYWxpemFyIGFuw6FsaXNpcyBwYXJhbcOpdHJpY29zIG8gbm8gcGFyYW3DqXRyaWNvcy4gRXN0ZSBhbsOhbGlzaXMgcHJlbGltaW5hciBpbmNsdWlyw6EgbGFzIHBydWViYXMgZGUgbm9ybWFsaWRhZCAoU2hhcGlyby1XaWxrKSB5IGhvbW9nZW5laWRhZCBkZSB2YXJpYW56YXMgKExldmVuZSkuIERlcGVuZGllbmRvIGRlIGxvcyByZXN1bHRhZG9zIGRlIGVzdGUgYW7DoWxpc2lzIHByZWxpbWluYXIsIHNlIGVtcGxlYXLDoW4gbGFzIHBydWViYXMgZXN0YWTDrXN0aWNhcyBhZGVjdWFkYXMgcGFyYSBkZXRlcm1pbmFyIHNpIGV4aXN0ZW4gZGlmZXJlbmNpYXMgc2lnbmlmaWNhdGl2YXMgKHAtdmFsb3IgPCAwLjA1KSAqKmR1cmFudGUgZWwgdGllbXBvIGRlIG11ZXN0cmVvKiouIFNpIGxvcyBkYXRvcyBjdW1wbGVuIGNvbiBsb3Mgc3VwdWVzdG9zIGRlIG5vcm1hbGlkYWQgeSBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzLCBzZSB1dGlsaXphcsOhIGVsIGFuw6FsaXNpcyBkZSB2YXJpYW56YSAoQU5PVkEpLiBFbiBjYXNvIGNvbnRyYXJpbywgc2UgZW1wbGVhcsOhbiBwcnVlYmFzIG5vIHBhcmFtw6l0cmljYXMgY29tbyBsYSBwcnVlYmEgZGUgS3J1c2thbC1XYWxsaXMuIExvcyBhbsOhbGlzaXMgeSBncsOhZmljb3Mgc2Vyw6FuIHJlYWxpemFkb3MgZW4gUiBTdHVkaW8gKHZlcnNpw7NuIDQuIDMuIDA7IFIgQ29yZSBUZWFtLCAyMDIzKS4NCg0KIyMgTm9ybWFsaWRhZCAtIFBydWViYSBkZSBTaGFwaXJvLVdpbGsgey50YWJzZXR9DQoNCiMjIyBSZXN1bHRhZG9zDQoNCmBgYHtyLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgQ2F0ZWdvcsOtYXMgw7puaWNhcyBkZSBtb3J0YWxpZGFkDQpjYXRlZ29yaWFzIDwtIGMoIk1vcnRhbGlkYWQgMjAxNSAtIEJhcnJhbmNvcyIsIk1vcnRhbGlkYWQgMjAxNSAtIENvbnN0YW50ZSIsIk1vcnRhbGlkYWQgMjAxOSAtIENvbnN0YW50ZSIpDQoNCiMgRnVuY2nDs24gcGFyYSBldmFsdWFyIGNhZGEgY2F0ZWdvcsOtYQ0Kc2hhcGlybyA8LSBmdW5jdGlvbihjYXRlZ29yaWEsIGRhdGEpIHsNCiAgIyBGaWx0cmFyIGVsIGdydXBvDQogIGRhdG9zIDwtIGRhdGEgJT4lIGZpbHRlcihNb3J0YWxpZGFkID09IGNhdGVnb3JpYSkNCiAgDQogICMgTm9ybWFsaWRhZDogU2hhcGlyby1XaWxrDQogIHNoYXBpcm9fcmVzdWx0IDwtIHNoYXBpcm8udGVzdChkYXRvcyRET19zYXQpDQogIHByaW50KHBhc3RlKCJQcnVlYmEgZGUgU2hhcGlyby1XaWxrIHBhcmEiLCBjYXRlZ29yaWEsICI6Iiwgc2hhcGlyb19yZXN1bHQkcC52YWx1ZSkpDQogIA0KfQ0KDQojIEFwbGljYXIgbGEgZnVuY2nDs24gYSBjYWRhIGNhdGVnb3LDrWENCndhbGsoY2F0ZWdvcmlhcywgfiBzaGFwaXJvKC54LCB0b3RhbCkpDQoNCmRhdG9zX25vbW9ydGFsaWRhZDwtIHRvdGFsICU+JQ0KICBmaWx0ZXIoTW9ydGFsaWRhZCA9PSAiTm8gTW9ydGFsaWRhZCIpDQprb2xtb2dvcm92X3Jlc3VsdCA8LSBrcy50ZXN0KHg9ZGF0b3Nfbm9tb3J0YWxpZGFkJERPX3NhdCx5PSdwbm9ybScsYWx0ZXJuYXRpdmU9J3R3by5zaWRlZCcpDQogIHByaW50KHBhc3RlKCJQcnVlYmEgZGUgS29sbW9nb3Jvdi1TbWlybm92IHBhcmEgZWwgcGVyaW9kbyBkZSBObyBNb3J0YWxpZGFkOiIsDQogICAgICAgICAgICBmb3JtYXQoa29sbW9nb3Jvdl9yZXN1bHQkcC52YWx1ZSwgc2NpZW50aWZpYyA9IFRSVUUpKSkNCmBgYA0KDQojIyMgUGxvdHMNCg0KYGBge3IsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQ2F0ZWdvcsOtYXMgw7puaWNhcyBkZSBtb3J0YWxpZGFkDQpjYXRlZ29yaWFzIDwtIGMoIk1vcnRhbGlkYWQgMjAxNSAtIEJhcnJhbmNvcyIsIk1vcnRhbGlkYWQgMjAxNSAtIENvbnN0YW50ZSIsIk1vcnRhbGlkYWQgMjAxOSAtIENvbnN0YW50ZSIsICJObyBNb3J0YWxpZGFkIikNCiMgRnVuY2nDs24gcGFyYSBwcm9jZXNhciBjYWRhIGNhdGVnb3LDrWENCnBsb3RzIDwtIGZ1bmN0aW9uKGNhdGVnb3JpYSwgZGF0YSkgew0KICAjIEZpbHRyYXIgZWwgZ3J1cG8NCiAgZGF0b3MgPC0gZGF0YSAlPiUgZmlsdGVyKE1vcnRhbGlkYWQgPT0gY2F0ZWdvcmlhKQ0KICANCiAgIyBDdXJ2YSBkZSBkZW5zaWRhZA0KICBkZW5zaWRhZCA8LSBnZ3Bsb3QoZGF0b3MsIGFlcyh4ID0gRE9fc2F0KSkgKw0KICAgIGdlb21fZGVuc2l0eShmaWxsID0gIiM1NkI0RTkiLCBhbHBoYSA9IDAuNSwgY29sb3IgPSAiIzAwNzJCMiIsIHNpemUgPSAxLjIpICsNCiAgICBsYWJzKA0KICAgICAgdGl0bGUgPSBwYXN0ZSgiQ3VydmEgZGUgZGVuc2lkYWQgLSIsIGNhdGVnb3JpYSksDQogICAgICB4ID0gIlNhdHVyYWNpw7NuIGRlIE94w61nZW5vIChET19zYXQpIiwNCiAgICAgIHkgPSAiRGVuc2lkYWQiDQogICAgKSArDQogICAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKw0KICAgIHRoZW1lKA0KICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYpLA0KICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpDQogICAgKQ0KDQogICMgQm94cGxvdCBob3Jpem9udGFsDQogIGJveHBsb3QgPC0gZ2dwbG90KGRhdG9zLCBhZXMoeCA9IERPX3NhdCwgeSA9ICIiKSkgKw0KICAgIGdlb21fYm94cGxvdChmaWxsID0gIiNFNjlGMDAiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43LCB3aWR0aCA9IDAuMykgKw0KICAgIGxhYnMoeCA9ICJTYXR1cmFjacOzbiBkZSBPeMOtZ2VubyAoRE9fc2F0KSIsIHkgPSAiIikgKw0KICAgIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsNCiAgICB0aGVtZSgNCiAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKQ0KICAgICkNCg0KICAjIENvbWJpbmFyIGVsIGdyw6FmaWNvIGRlIGRlbnNpZGFkIHkgZWwgYm94cGxvdA0KICBjb21iaW5hZG8gPC0gZGVuc2lkYWQgLyBib3hwbG90ICsgcGxvdF9sYXlvdXQoaGVpZ2h0cyA9IGMoMywgMSkpDQogIHByaW50KGNvbWJpbmFkbykNCn0NCg0KIyBBcGxpY2FyIGxhIGZ1bmNpw7NuIGEgY2FkYSBjYXRlZ29yw61hDQp3YWxrKGNhdGVnb3JpYXMsIH4gcGxvdHMoLngsIHRvdGFsKSkNCmBgYA0KDQojIyBIb21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzIC0gUHJ1ZWJhIGRlIExldmVuZSB7LnRhYnNldH0NCg0KIyMjIFJlc3VsdGFkb3MNCg0KYGBge3IsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgSG9tb2dlbmVpZGFkIGRlIHZhcmlhbnphczogUHJ1ZWJhIGRlIExldmVuZQ0KbGV2ZW5lX3Jlc3VsdCA8LSBsZXZlbmVUZXN0KERPX3NhdCB+IE1vcnRhbGlkYWQsIGRhdGEgPSB0b3RhbCkNCiMgRXh0cmFlciBlbCB2YWxvciBwIGRlbCByZXN1bHRhZG8NCnBfdmFsdWVfbGV2ZW5lIDwtIHNpZ25pZihsZXZlbmVfcmVzdWx0JGBQcig+RilgWzFdLCBkaWdpdHMgPSAzKQ0KIyBDcmVhciB1biBtZW5zYWplIHBlcnNvbmFsaXphZG8NCmNhdCgiUHJ1ZWJhIGRlIExldmVuZSBwYXJhIGhvbW9nZW5laWRhZCBkZSB2YXJpYW56YXM6IHAgPSIsIHBfdmFsdWVfbGV2ZW5lLCAiXG4iKQ0KDQpgYGANCg0KIyMjIFBsb3RzDQoNCmBgYHtyLCBlY2hvPVRSVUUsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmdncGxvdCh0b3RhbCwgYWVzKHggPSBNb3J0YWxpZGFkLCB5ID0gRE9fc2F0LCBmaWxsID0gTW9ydGFsaWRhZCkpICsNCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43LCBvdXRsaWVyLnNoYXBlID0gTkEpICsgIyBTaW4gb3V0bGllcnMgcGFyYSBubyBkdXBsaWNhciBwdW50b3MNCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjIsIHNpemUgPSAyLCBhbHBoYSA9IDAuNiwgY29sb3IgPSAiYmxhY2siKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM1NkI0RTkiLCAiI0U2OUYwMCIsICIjMDA5RTczIiwgIiNENTVFMDAiKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRpc3BlcnNpb24gZGUgU2F0T0QgcG9yIE1vcnRhbGlkYWQiLA0KICAgIHggPSAiTW9ydGFsaWRhZCIsDQogICAgeSA9ICIiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KDQpnZ3Bsb3QodG90YWwsIGFlcyh4ID0gRE9fc2F0LCBmaWxsID0gTW9ydGFsaWRhZCkpICsNCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC42KSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM1NkI0RTkiLCAiI0U2OUYwMCIsICIjMDA5RTczIiwgIiNENTVFMDAiKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRlbnNpZGFkIGRlIERPX3NhdCBwb3IgTW9ydGFsaWRhZCIsDQogICAgeCA9ICIoRE9fc2F0KSIsDQogICAgeSA9ICJEZW5zaWRhZCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYpLA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKQ0KICApDQoNCmBgYA0KDQoNCiMjIFBydWViYXMgTm8gUGFyYW1ldHJpY2FzDQoNClNpIGxvcyBkYXRvcyBubyBzb24gbm9ybWFsZXMgbyBubyBjdW1wbGVuIGxhIGhvbW9nZW5laWRhZDogVXNhciBsYSBwcnVlYmEgZGUgS3J1c2thbC1XYWxsaXMgc2VndWlkYSBkZSB1biBhbsOhbGlzaXMgcG9zdC1ob2MgKER1bm4gbyBXaWxjb3hvbikgcGFyYSBjb21wYXJhY2lvbmVzIG3Dumx0aXBsZXMuDQpjb21wYXJhY2lvbiBjb24gdW5lcXVhbCB2YXJpYW5jZXM/Pw0KDQpgYGB7ciwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyAjIEtydXNrYWwtV2FsbGlzDQprcnVza2FsX3Jlc3VsdCA8LSBrcnVza2FsLnRlc3QoRE9fc2F0IH4gTW9ydGFsaWRhZCwgZGF0YSA9IHRvdGFsKQ0Ka3J1c2thbF9yZXN1bHQNCg0KIyBQb3N0LWhvYyBjb24gRHVubg0KZHVubl9yZXN1bHQgPC0gZHVublRlc3QoRE9fc2F0IH4gTW9ydGFsaWRhZCwgZGF0YSA9IHRvdGFsLCBtZXRob2QgPSAiYm9uZmVycm9uaSIpDQoNCiMgRXh0cmFlciBsb3MgcmVzdWx0YWRvcyBlbiBmb3JtYXRvIGRlIGRhdGFmcmFtZQ0KdGFibGFfZHVubiA8LSBhcy5kYXRhLmZyYW1lKGR1bm5fcmVzdWx0JHJlcykNCg0KIyBSZW5vbWJyYXIgY29sdW1uYXMgcGFyYSBxdWUgc2VhbiBtw6FzIGxlZ2libGVzDQpjb2xuYW1lcyh0YWJsYV9kdW5uKSA8LSBjKCJDb21wYXJhY2lvbiIsICJFc3RhZGlzdGljbyBaIiwgIlAgc2luIGFqdXN0YXIiLCAiUCBhanVzdGFkbyIpDQoNCiMgQ3JlYXIgbGEgdGFibGEgY29uIGd0DQp0YWJsYV9kdW5uICU+JQ0KICBndCgpICU+JQ0KICB0YWJfaGVhZGVyKA0KICAgIHRpdGxlID0gIlJlc3VsdGFkb3MgZGVsIFRlc3QgZGUgRHVubiIsDQogICAgc3VidGl0bGUgPSAiQ29tcGFyYWNpb25lcyBkZSBTYXRfT0QgZW50cmUgZ3J1cG9zIGRlIE1vcnRhbGlkYWQiDQogICkgJT4lDQogIGZtdF9udW1iZXIoDQogICAgY29sdW1ucyA9IGMoIkVzdGFkaXN0aWNvIFoiLCAiUCBzaW4gYWp1c3RhciIsICJQIGFqdXN0YWRvIiksDQogICAgZGVjaW1hbHMgPSAzDQogICkgJT4lDQogIGNvbHNfbGFiZWwoDQogICAgYENvbXBhcmFjaW9uYCA9ICJHcnVwb3MgQ29tcGFyYWRvcyIsDQogICAgYEVzdGFkaXN0aWNvIFpgID0gIkVzdGFkw61zdGljbyBaIiwNCiAgICBgUCBzaW4gYWp1c3RhcmAgPSAiUC12YWxvciAoc2luIGFqdXN0YXIpIiwNCiAgICBgUCBhanVzdGFkb2AgPSAiUC12YWxvciAoYWp1c3RhZG8pIg0KICApDQoNCmBgYA0KDQojIyBCb290c3RyYXBwaW5nPw0KDQojIFZhcmFpYmlsaWRhZCBEaWFyaWEgZGUgbGEgU2F0dXJhY2nDs24gT0QgDQoNClBhcmEgZWwgYW7DoWxpc2lzIGRlIGRhdG9zLCBwcmltZXJvIHNlIHJlYWxpemFyw6EgbGEgY2FyYWN0ZXJpemFjacOzbiBhbWJpZW50YWwgZGUgbG9zIHJlZ2lzdHJvcyBoaXDDs3hpY29zIGVuIENvbnN0YW50ZS4gUGFyYSBlbGxvIHNlIGFuYWxpemFyw6EgbGEgdmFyaWFiaWxpZGFkIGRpYXJpYSBkZSBsYSBzYXR1cmFjacOzbiBkZSBPRCBlbiBlbCBmb25kbywgbG9zIHJlZ2lzdHJvcyBzZSBjbGFzaWZpY2Fyw6FuIGVudHJlIGTDrWEgKDA2OjAwIOKAkyAxNzo1OSkgeSBub2NoZSAoMTg6MDAg4oCTIDA1OjU5KSwgeSBzZSByZXByZXNlbnRhcsOhbiBtZWRpYW50ZSBkaWFncmFtYSBkZSBjYWphcy4gKipQYXJhIGV2YWx1YXIgbGEgdmFyaWFiaWxpZGFkIGRlbCBjaWNsbyBkaWFyaW8gc2UgYWp1c3RhcsOhIHVuYSBmdW5jacOzbiBzaW51c29pZGFsIGEgbGFzIG1lZGlhbmFzIGRlbCBhbsOhbGlzaXMgZGVsIGRpYWdyYW1hIGRlIGNhamEsIGNvbiBlbCBmaW4gZGUgZGV0ZXJtaW5hciB5IGNvbXBhcmFyIGxhIGFtcGxpdHVkIHkgbGEgZmFzZSBkZWwgY2ljbG8gZGlhcmlvIGR1cmFudGUgZWwgdGllbXBvIGRlIG11ZXN0cmVvLiBFc3RlIGFuw6FsaXNpcyBzaWd1ZSBsYSBtZXRvZG9sb2fDrWEgcGxhbnRlYWRhIHBvciBJZ2FyemEgZXQgYWwuICgyMDI0KSoqLg0KDQpgYGB7ciwgZWNobz1UUlVFLCBmaWcud2lkdGg9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgRXh0cmFlciBzb2xvIGxhIEhvcmEgZW4gdW5hIG51ZXZhIGNvbHVtbmENCnRvdGFsIDwtIHRvdGFsICU+JQ0KICBtdXRhdGUoDQogICAgSG9yYSA9IGFzLmludGVnZXIoZm9ybWF0KEhvcmFfTGltYSwgIiVIIikpLA0KICAgIERpYU5vY2hlID0gaWZlbHNlKEhvcmEgPj0gNiAmIEhvcmEgPD0gMTcsICJEw61hIiwgIk5vY2hlIikNCiAgKQ0KDQojIERlZmluaXIgbG9zIGNvbG9yZXMNCmNvbG9yZXMgPC0gYygiRMOtYSIgPSAiZ3JheTEwMCIsICJOb2NoZSIgPSAiZ3JheTgwIikNCg0KIyBDcmVhciBlbCBncsOhZmljbyBjb24gYm94cGxvdHMgcG9yIGNhZGEgaG9yYQ0KZ2dwbG90KHRvdGFsLCBhZXMoeCA9IGZhY3RvcihIb3JhKSwgeSA9IERPX3NhdCwgZmlsbCA9IERpYU5vY2hlKSkgKw0KICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjYsIGFscGhhID0gMC44LCBvdXRsaWVyLmFscGhhID0gMC41LCBvdXRsaWVyLnNpemUgPSAxKSArDQogIGZhY2V0X3dyYXAofiBNb3J0YWxpZGFkLCBuY29sID0gMikgKyAgIyBVbmEgZmFjZXRhIHBvciBjYWRhIHBlcmlvZG8gZGUgbW9ydGFsaWRhZA0KICBsYWJzKA0KICAgIHggPSAiSG9yYSBkZWwgRMOtYSIsDQogICAgeSA9ICJTYXR1cmFjacOzbiBPRCAoJSkiLA0KICAgIGZpbGwgPSAiTW9tZW50byBkZWwgRMOtYSIsDQogICAgdGl0bGUgPSAiVmFyaWFiaWxpZGFkIERpYXJhIGRlIFNhdHVyYWNpw7NuIGRlIE94w61nZW5vIg0KICApICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShicmVha3MgPSBzZXEoMCwgMjMsIGJ5ID0gMikpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JlcykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAyNC40LCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMC41KSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5OTUiLCBjb2xvciA9ICJibGFjayIpLCAgIyBGb25kbyBkZSBsYXMgZmFjZXRhcw0KICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEyKSwgICMgVGV4dG8gZW4gbGFzIGZhY2V0YXMNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwgICMgVGFtYcOxbyBkZSB0ZXh0byBkZSBsb3MgZWplcw0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgICMgVGFtYcOxbyBkZSB0ZXh0byBkZSB0w610dWxvcyBkZSBlamVzDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgICMgUXVpdGFyIGzDrW5lYXMgZGUgZ3JpbGxhIG1heW9yDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgICMgUXVpdGFyIGzDrW5lYXMgZGUgZ3JpbGxhIG1lbm9yDQogICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiksICAjIEHDsWFkaXIgbMOtbmVhcyBkZSBsb3MgZWplcw0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siKSAgIyBBw7FhZGlyIG1hcmNhcyBlbiBsb3MgZWplcw0KICApDQpgYGANCmBgYHtyLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgMS4gQ2FsY3VsYXIgbGEgbWVkaWFuYSBkZSBET19zYXQgcG9yIEhvcmEgeSBNb3J0YWxpZGFkDQptZWRpYW5hX3Bvcl9ob3JhIDwtIHRvdGFsICU+JQ0KICBncm91cF9ieShNb3J0YWxpZGFkLCBIb3JhKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIE1lZGlhbmFfRE9fc2F0ID0gbWVkaWFuKERPX3NhdCwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkNCg0KIyAyLiBEZWZpbmlyIGxhIGZ1bmNpw7NuIHNpbnVzb2lkYWwNCnNpbnVzb2lkYWwgPC0gZnVuY3Rpb24oeCwgYW1wbGl0dWQsIGZyZWN1ZW5jaWEsIGZhc2UsIGRlc3BsYXphbWllbnRvKSB7DQogIGFtcGxpdHVkICogc2luKGZyZWN1ZW5jaWEgKiB4ICsgZmFzZSkgKyBkZXNwbGF6YW1pZW50bw0KfQ0KDQojIDMuIEFqdXN0YXIgbGEgZnVuY2nDs24gc2ludXNvaWRhbCBhIGxvcyBkYXRvcw0KYWp1c3RlcyA8LSBtZWRpYW5hX3Bvcl9ob3JhICU+JQ0KICBncm91cF9ieShNb3J0YWxpZGFkKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgICMgQ2FsY3VsYXIgcGFyw6FtZXRyb3MgaW5pY2lhbGVzDQogICAgYW1wbGl0dWRfaW5pY2lvID0gKG1heChNZWRpYW5hX0RPX3NhdCwgbmEucm0gPSBUUlVFKSAtIG1pbihNZWRpYW5hX0RPX3NhdCwgbmEucm0gPSBUUlVFKSkgLyAyLA0KICAgIGRlc3BsYXphbWllbnRvX2luaWNpbyA9IG1lYW4oTWVkaWFuYV9ET19zYXQsIG5hLnJtID0gVFJVRSksDQogICAgYWp1c3RlID0gbGlzdCgNCiAgICAgIG5sc0xNKA0KICAgICAgICBNZWRpYW5hX0RPX3NhdCB+IHNpbnVzb2lkYWwoSG9yYSwgYW1wbGl0dWQsIGZyZWN1ZW5jaWEsIGZhc2UsIGRlc3BsYXphbWllbnRvKSwNCiAgICAgICAgZGF0YSA9IGN1cl9kYXRhKCksDQogICAgICAgIHN0YXJ0ID0gbGlzdCgNCiAgICAgICAgICBhbXBsaXR1ZCA9IGFtcGxpdHVkX2luaWNpbywNCiAgICAgICAgICBmcmVjdWVuY2lhID0gMiAqIHBpIC8gMjQsICMgRnJlY3VlbmNpYSBwYXJhIGNpY2xvIGRlIDI0IGhvcmFzDQogICAgICAgICAgZmFzZSA9IDAsICMgSW5pY2lhbG1lbnRlIHNpbiBkZXNwbGF6YW1pZW50bw0KICAgICAgICAgIGRlc3BsYXphbWllbnRvID0gZGVzcGxhemFtaWVudG9faW5pY2lvDQogICAgICAgICkNCiAgICAgICkNCiAgICApLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQojIDQuIEV4dHJhZXIgbG9zIHBhcsOhbWV0cm9zIGFqdXN0YWRvcyB5IGNvcnJlZ2lyIGFtcGxpdHVkIHkgZmFzZQ0KcGFyYW1ldHJvcyA8LSBhanVzdGVzICU+JQ0KICBtdXRhdGUoDQogICAgY29lZmljaWVudGVzID0gbWFwKGFqdXN0ZSwgY29lZikNCiAgKSAlPiUNCiAgc2VsZWN0KE1vcnRhbGlkYWQsIGNvZWZpY2llbnRlcykgJT4lDQogIHVubmVzdF93aWRlcihjb2VmaWNpZW50ZXMpICU+JQ0KICBtdXRhdGUoDQogICAgQW1wbGl0dWQgPSBhYnMoYW1wbGl0dWQpLCAjIEFzZWd1cmFyIGFtcGxpdHVkIHBvc2l0aXZhDQogICAgRmFzZSA9IGlmZWxzZShhbXBsaXR1ZCA8IDAsIGZhc2UgKyBwaSwgZmFzZSksICMgQ29ycmVnaXIgZmFzZSBzaSBhbXBsaXR1ZCBlcmEgbmVnYXRpdmENCiAgICBIb3JhbWF4ID0gKC1GYXNlIC8gZnJlY3VlbmNpYSkgJSUgMjQgIyBDYWxjdWxhciBsYSBob3JhIGRlbCBtw6F4aW1vIHkgYXNlZ3VyYXIgMC0yNA0KICApICU+JQ0KICBzZWxlY3QoTW9ydGFsaWRhZCwgQW1wbGl0dWQsIEZyZWN1ZW5jaWEgPSBmcmVjdWVuY2lhLCBGYXNlLCBEZXNwbGF6YW1pZW50byA9IGRlc3BsYXphbWllbnRvLCBIb3JhbWF4KQ0KDQojIEltcHJpbWlyIGxvcyBwYXLDoW1ldHJvcyBhanVzdGFkb3MNCnByaW50KHBhcmFtZXRyb3MpDQoNCiMgNS4gQ3JlYXIgZGF0b3MgYWp1c3RhZG9zIGNvbiBsYSBvbmRhIHNpbnVzb2lkYWwNCmRhdG9zX2FqdXN0YWRvcyA8LSBtZWRpYW5hX3Bvcl9ob3JhICU+JQ0KICBsZWZ0X2pvaW4ocGFyYW1ldHJvcywgYnkgPSAiTW9ydGFsaWRhZCIpICU+JQ0KICBtdXRhdGUoDQogICAgQWp1c3RlID0gQW1wbGl0dWQgKiBzaW4oRnJlY3VlbmNpYSAqIEhvcmEgKyBGYXNlKSArIERlc3BsYXphbWllbnRvDQogICkNCg0KIyA2LiBHcmFmaWNhciBkYXRvcyByZWFsZXMgeSBhanVzdGFkb3MgY29uIGVzY2FsYSBmaWphIGRlIDAgYSAxMDANCmdncGxvdChkYXRvc19hanVzdGFkb3MsIGFlcyh4ID0gSG9yYSkpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gQWp1c3RlLCBjb2xvciA9IE1vcnRhbGlkYWQpLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGdlb21fcG9pbnQoYWVzKHkgPSBNZWRpYW5hX0RPX3NhdCwgY29sb3IgPSBNb3J0YWxpZGFkKSwgc2l6ZSA9IDEpICsNCiAgZmFjZXRfd3JhcCh+IE1vcnRhbGlkYWQsIHNjYWxlcyA9ICJmaXhlZCIpICsgICMgRXNjYWxhIGZpamEgZW4gWQ0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA2MCkpICsgICMgRmlqYXIgbMOtbWl0ZXMgZGUgMCBhIDEwMA0KICBsYWJzKA0KICAgIHRpdGxlID0gIkFqdXN0ZSBkZSBmdW5jacOzbiBzaW51c29pZGFsIiwNCiAgICB4ID0gIkhvcmEgZGVsIGTDrWEiLA0KICAgIHkgPSAiTWVkaWFuYSBkZSBTYXR1cmFjacOzbiBkZSBPeMOtZ2VubyAoRE9fc2F0KSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQojIDcuIENyZWFyIGRhdG9zIGFqdXN0YWRvcyBzaW4gZGVzcGxhemFtaWVudG8gdmVydGljYWwgKHNvbG8gYW1wbGl0dWQgeSBmYXNlKQ0KZGF0b3NfYWp1c3RhZG9zX3Npbl9kIDwtIG1lZGlhbmFfcG9yX2hvcmEgJT4lDQogIGxlZnRfam9pbihwYXJhbWV0cm9zLCBieSA9ICJNb3J0YWxpZGFkIikgJT4lDQogIG11dGF0ZSgNCiAgICBBanVzdGVfc2luX2QgPSBBbXBsaXR1ZCAqIHNpbihGcmVjdWVuY2lhICogSG9yYSArIEZhc2UpICAjIEVsaW1pbmFyIGVsIGRlc3BsYXphbWllbnRvIHZlcnRpY2FsDQogICkNCg0KIyA4LiBHcmFmaWNhciBsYXMgb25kYXMgc2ludXNvaWRhbGVzIHNpbiBkZXNwbGF6YW1pZW50byB2ZXJ0aWNhbA0KZ2dwbG90KGRhdG9zX2FqdXN0YWRvc19zaW5fZCwgYWVzKHggPSBIb3JhLCB5ID0gQWp1c3RlX3Npbl9kLCBjb2xvciA9IE1vcnRhbGlkYWQpKSArDQogIGdlb21fbGluZShzaXplID0gMSwgbGluZXR5cGUgPSAic29saWQiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ29tcGFyYWNpw7NuIGRlIG9uZGFzIHNpbnVzb2lkYWxlcyIsDQogICAgeCA9ICJIb3JhIGRlbCBkw61hIiwNCiAgICB5ID0gIk9zY2lsYWNpw7NuIHJlbGF0aXZhIGRlIERPX3NhdCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpDQogICkNCmBgYA0KTGEgYW1wbGl0dWQgaW5kaWNhIGN1w6FudG8gdmFyw61hIGxhIHNhdHVyYWNpw7NuIGRlIG94w61nZW5vIGEgbG8gbGFyZ28gZGVsIGTDrWEsIGRlc2RlIGVsIG5pdmVsIG1lZGlvIChEZXNwbGF6YW1pZW50bykgaGFzdGEgbG9zIHBpY29zIChwb3NpdGl2b3MgbyBuZWdhdGl2b3MpLiBFcyB1bmEgbWVkaWRhIGRlIGxhIHZhcmlhYmlsaWRhZCBkaWFyaWE6DQoNCk1heW9yIGFtcGxpdHVkIOKGkiBNYXlvciB2YXJpYWNpw7NuIGRpYXJpYSBlbnRyZSBkw61hIHkgbm9jaGUuDQpNZW5vciBhbXBsaXR1ZCDihpIgQ2ljbG8gZGlhcmlvIG1lbm9zIG1hcmNhZG8gKHNhdHVyYWNpw7NuIG3DoXMgZXN0YWJsZSkuDQoNCkxhIGZyZWN1ZW5jaWEgZXN0w6EgcmVsYWNpb25hZGEgY29uIGVsIG7Dum1lcm8gZGUgY2ljbG9zIGNvbXBsZXRhZG9zIGVuIHVuIHBlcsOtb2RvIGRlIHRpZW1wby4gSW50ZXJwcmV0YWNpw7NuOg0KTGEgZnJlY3VlbmNpYSBkZWJlcsOtYSBzZXIgYXByb3hpbWFkYW1lbnRlIDAuMjYxOCBzaSBsYXMgb3NjaWxhY2lvbmVzIG9jdXJyZW4gZXhhY3RhbWVudGUgY2FkYSAyNCBob3Jhcy4NClR1cyByZXN1bHRhZG9zIHRpZW5lbiBsaWdlcmFzIGRpZmVyZW5jaWFzOg0KDQoqIE1vcnRhbGlkYWQgMjAxNSAtIENvbnN0YW50ZSAoMC4zNTMpOiBGcmVjdWVuY2lhIHVuIHBvY28gbWF5b3IsIGxvIHF1ZSBwb2Ryw61hIGluZGljYXIgb3NjaWxhY2lvbmVzIG3DoXMgcsOhcGlkYXMgKGxpZ2VyYW1lbnRlIGRlc2Zhc2FkYXMgZGVsIGNpY2xvIGRpYXJpbyBwZXJmZWN0bykuDQoNCiogTm8gTW9ydGFsaWRhZCAoMC4yOTgpOiBGcmVjdWVuY2lhIG3DoXMgYmFqYSwgbG8gcXVlIHN1Z2llcmUgb3NjaWxhY2lvbmVzIG3DoXMgbGVudGFzIHkgdW4gY2ljbG8gbcOhcyAiZXh0ZW5kaWRvIi4NCg0KRW4gZ2VuZXJhbCwgZXN0YXMgcGVxdWXDsWFzIGRpZmVyZW5jaWFzIHBvZHLDrWFuIGRlYmVyc2UgYSBydWlkbyBvIGEgZmVuw7NtZW5vcyBiaW9sw7NnaWNvcyBxdWUgZGVzdsOtZW4gZWwgY2ljbG8gZGUgdW4gcGF0csOzbiBlc3RyaWN0YW1lbnRlIGRpYXJpby4NCg0KTGEgZmFzZSBpbmRpY2EgZWwgZGVzcGxhemFtaWVudG8gaG9yaXpvbnRhbCBkZSBsYSBvbmRhIHNpbnVzb2lkYWwsIGVzIGRlY2lyLCBlbiBxdcOpIG1vbWVudG8gZGVsIGTDrWEgb2N1cnJlIGVsIG3DoXhpbW8gbyBtw61uaW1vIGRlIHNhdHVyYWNpw7NuLg0KDQojIEluZGljYWRvcmVzIGRlIGhpcG94aWEgey50YWJzZXR9DQoNClNlIGV2YWx1YXLDoSBsYSB2YXJpYWJpbGlkYWQgZGUgaGlwb3hpYSBtZWRpYW50ZSBsb3Mgc2lndWllbnRlcyBpbmRpY2Fkb3JlczogZWwgcG9yY2VudGFqZSBkZSByZWdpc3Ryb3MgaGlww7N4aWNvcywgbGFzIGhvcmFzIGRlIGhpcG94aWEgYWwgZMOtYSwgbGEgbWVkaWFuYSBkZSBzYXR1cmFjacOzbiBkZSBPRCBhbCBkw61hIHkgZWwgdmFsb3IgbcOtbmltbyBkZSBzYXR1cmFjacOzbiBkZSBPRCBhbCBkw61hLiANCg0KRGVzcHXDqXMgZGVsIGFuw6FsaXNpcyBkZSBsYSB2YXJpYWJpbGlkYWQgZGVsIGNpY2xvIGRpYXJpbyBkZSBzYXR1cmFjacOzbiBkZSBPRCwgc2UgcmVhbGl6YXLDoSBlbCAqKmFuw6FsaXNpcyBkZSBsb3MgZXZlbnRvcyBoaXDDs3hpY29zKiouIFBhcmEgZGV0ZXJtaW5hciB1biBldmVudG8gaGlww7N4aWNvLCBlc3RlIGRlYmUgc2VyIGlndWFsIG8gaW5mZXJpb3IgYWwgMjQuNCUgZGUgc2F0dXJhY2nDs24gZGUgT0QgeSBkdXJhciBhbCBtZW5vcyBzZWlzIGhvcmFzIGNvbnNlY3V0aXZhcyAoU2hpZWxkcyB5IFdlaWRtYW4sIDIwMDgpLg0KDQojIyBOdW1lcm8gZGUgaG9yYXMgaGlwb3hpY2FzIGFsIGRpYQ0KDQoqKk51bWVybyBkZSBob3JhcyBoaXBveGljYXMgYWwgZGlhOioqDQoNCmBgYHtyLCBlY2hvPVRSVUUsIGZpZy53aWR0aD0xMCxtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBGdW5jacOzbiBwYXJhIGFncmVnYXIgY29sdW1uYSBkZSBoaXBveGlhDQphZ3JlZ2FyX2NvbHVtbmFfaGlwb3hpYSA8LSBmdW5jdGlvbihkYXRhKSB7DQogIGRhdGEkSGlwb3hpYSA8LSBpZmVsc2UoZGF0YSRET19zYXQgPD0gMjQuNCwgMSwgMCkNCiAgcmV0dXJuKGRhdGEpDQp9DQoNCnRvdGFsIDwtIGFncmVnYXJfY29sdW1uYV9oaXBveGlhKHRvdGFsKQ0KDQojIEZ1bmNpw7NuIHBhcmEgY2FsY3VsYXIgaG9yYXMgZGUgaGlwb3hpYSBwb3IgZMOtYQ0KY2FsY3VsYXJfaG9yYXNfaGlwb3hpYSA8LSBmdW5jdGlvbihkZikgew0KICBkZiAlPiUNCiAgICBtdXRhdGUoRGlhID0gYXMuRGF0ZShIb3JhX0xpbWEpKSAlPiUNCiAgICBncm91cF9ieShEaWEsIE1vcnRhbGlkYWQpICU+JQ0KICAgIHN1bW1hcmlzZShIb3Jhc19IaXBveGlhID0gc3VtKEhpcG94aWEpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KfQ0KDQpob3Jhc19oaXBveGljYXMgPC0gY2FsY3VsYXJfaG9yYXNfaGlwb3hpYSh0b3RhbCkNCg0KIyBOb3JtYWxpZGFkIGRlIGxvcyBkYXRvcw0KaG9yYXNfaGlwb3hpY2FzICU+JQ0KICBncm91cF9ieShNb3J0YWxpZGFkKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lbnNhamUgPSBwYXN0ZSgNCiAgICAgICJQcnVlYmEgZGUgU2hhcGlyby1XaWxrIHBhcmEiLCANCiAgICAgIGZpcnN0KE1vcnRhbGlkYWQpLCAjIE9idMOpbiBlbCBub21icmUgZGVsIGdydXBvDQogICAgICAiOiBwID0iLCBzaWduaWYoc2hhcGlyby50ZXN0KEhvcmFzX0hpcG94aWEpJHAudmFsdWUsIGRpZ2l0cyA9IDMpDQogICAgKQ0KICApICU+JQ0KICBwdWxsKG1lbnNhamUpICU+JSAjIEV4dHJhZSBzb2xvIGxvcyBtZW5zYWplcw0KICBjYXQoc2VwID0gIlxuIikgIyBMb3MgaW1wcmltZSBsw61uZWEgcG9yIGzDrW5lYQ0KDQojIEhvbW9nZW5laWRhZCBkZSBsb3MgZGF0b3MNCmxldmVuZV9yZXN1bHQ8LSBsZXZlbmVUZXN0KEhvcmFzX0hpcG94aWEgfiBNb3J0YWxpZGFkLCBkYXRhID0gaG9yYXNfaGlwb3hpY2FzKQ0KIyBFeHRyYWVyIGVsIHZhbG9yIHAgZGVsIHJlc3VsdGFkbw0KcF92YWx1ZV9sZXZlbmUgPC0gc2lnbmlmKGxldmVuZV9yZXN1bHQkYFByKD5GKWBbMV0sIGRpZ2l0cyA9IDMpDQoNCiMgQ3JlYXIgdW4gbWVuc2FqZSBwZXJzb25hbGl6YWRvDQpjYXQoIlBydWViYSBkZSBMZXZlbmUgcGFyYSBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzOiBwID0iLCBwX3ZhbHVlX2xldmVuZSwgIlxuIikNCg0KIyBLcnVza2FsLVdhbGxpcw0Ka3J1c2thbF9yZXN1bHQgPC0ga3J1c2thbC50ZXN0KEhvcmFzX0hpcG94aWEgfiBNb3J0YWxpZGFkLCBkYXRhID0gaG9yYXNfaGlwb3hpY2FzKQ0KcHJpbnQoa3J1c2thbF9yZXN1bHQpDQoNCiMgUG9zdC1ob2MgY29uIER1bm4gcGFyYSBpZGVudGlmaWNhciBkaWZlcmVuY2lhcyBlbnRyZSBwYXJlcyBkZSBncnVwb3MNCmR1bm5fcmVzdWx0IDwtIGR1bm5UZXN0KEhvcmFzX0hpcG94aWEgfiBNb3J0YWxpZGFkLCBkYXRhID0gaG9yYXNfaGlwb3hpY2FzLCBtZXRob2QgPSAiYm9uZmVycm9uaSIpDQoNCiMgRXh0cmFlciBsb3MgcmVzdWx0YWRvcyBlbiBmb3JtYXRvIGRlIGRhdGFmcmFtZQ0KdGFibGFfZHVubiA8LSBhcy5kYXRhLmZyYW1lKGR1bm5fcmVzdWx0JHJlcykNCg0KIyBSZW5vbWJyYXIgY29sdW1uYXMgcGFyYSBxdWUgc2VhbiBtw6FzIGxlZ2libGVzDQpjb2xuYW1lcyh0YWJsYV9kdW5uKSA8LSBjKCJDb21wYXJhY2lvbiIsICJFc3RhZGlzdGljbyBaIiwgIlAgc2luIGFqdXN0YXIiLCAiUCBhanVzdGFkbyIpDQoNCiMgQ3JlYXIgbGEgdGFibGEgY29uIGd0DQp0YWJsYV9kdW5uICU+JQ0KICBndCgpICU+JQ0KICB0YWJfaGVhZGVyKA0KICAgIHRpdGxlID0gIlJlc3VsdGFkb3MgZGVsIFRlc3QgZGUgRHVubiIsDQogICAgc3VidGl0bGUgPSAiQ29tcGFyYWNpb25lcyBkZSBIb3JhcyBIaXBveGljYXMgZW50cmUgZ3J1cG9zIGRlIE1vcnRhbGlkYWQiDQogICkgJT4lDQogIGZtdF9udW1iZXIoDQogICAgY29sdW1ucyA9IGMoIkVzdGFkaXN0aWNvIFoiLCAiUCBzaW4gYWp1c3RhciIsICJQIGFqdXN0YWRvIiksDQogICAgZGVjaW1hbHMgPSAzDQogICkgJT4lDQogIGNvbHNfbGFiZWwoDQogICAgYENvbXBhcmFjaW9uYCA9ICJHcnVwb3MgQ29tcGFyYWRvcyIsDQogICAgYEVzdGFkaXN0aWNvIFpgID0gIkVzdGFkw61zdGljbyBaIiwNCiAgICBgUCBzaW4gYWp1c3RhcmAgPSAiUC12YWxvciAoc2luIGFqdXN0YXIpIiwNCiAgICBgUCBhanVzdGFkb2AgPSAiUC12YWxvciAoYWp1c3RhZG8pIg0KICApDQoNCmBgYA0KDQpDdWFsIHRpcG8gZGUgZ3JhZmljbyB1c2FyPw0KYGBge3IsIGVjaG89VFJVRSwgZmlnLndpZHRoPTEwLG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEJveHBsb3RzDQpnZ3Bsb3QoaG9yYXNfaGlwb3hpY2FzLCBhZXMoeCA9IE1vcnRhbGlkYWQsIHkgPSBIb3Jhc19IaXBveGlhLCBmaWxsID0gTW9ydGFsaWRhZCkpICsNCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43LCBvdXRsaWVyLnNoYXBlID0gTkEpICsNCiAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjIsIHNpemUgPSAyLCBhbHBoYSA9IDAuNiwgY29sb3IgPSAiYmxhY2siKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM1NkI0RTkiLCAiI0U2OUYwMCIsICIjMDA5RTczIiwgIiNENTVFMDAiKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkhvcmFzIEhpcMOzeGljYXMgYWwgZMOtYSIsDQogICAgeCA9ICIiLA0KICAgIHkgPSAiSG9yYXMiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KDQojIFZpb2xpbnBsb3QNCmdncGxvdChob3Jhc19oaXBveGljYXMsIGFlcyh4ID0gTW9ydGFsaWRhZCwgeSA9IEhvcmFzX0hpcG94aWEsIGZpbGwgPSBNb3J0YWxpZGFkKSkgKw0KICBnZW9tX3Zpb2xpbih0cmltID0gRkFMU0UsIGFscGhhID0gMC42LCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0gMC41KSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM1NkI0RTkiLCAiI0U2OUYwMCIsICIjMDA5RTczIiwgIiNENTVFMDAiKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkhvcmFzIEhpcMOzeGljYXMgYWwgZMOtYSIsDQogICAgeCA9ICIiLA0KICAgIHkgPSAiSG9yYXMiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KDQojIFJlb3JkZW5hciBsb3Mgbml2ZWxlcyBkZSBsYSB2YXJpYWJsZSAnTW9ydGFsaWRhZCcNCmhvcmFzX2hpcG94aWNhcyRNb3J0YWxpZGFkIDwtIGZhY3RvcigNCiAgaG9yYXNfaGlwb3hpY2FzJE1vcnRhbGlkYWQsDQogIGxldmVscyA9IGMoDQogICAgIk1vcnRhbGlkYWQgMjAxNSAtIEJhcnJhbmNvcyIsDQogICAgIk1vcnRhbGlkYWQgMjAxOSAtIENvbnN0YW50ZSIsDQogICAgIk1vcnRhbGlkYWQgMjAxNSAtIENvbnN0YW50ZSIsDQogICAgIk5vIE1vcnRhbGlkYWQiDQogICksDQogIGxhYmVscyA9IGMoDQogICAgIk1vcnRhbGlkYWQgMjAxNVxuQmFycmFuY29zIiwNCiAgICAiTW9ydGFsaWRhZCAyMDE5XG5Db25zdGFudGUiLA0KICAgICJNb3J0YWxpZGFkIDIwMTVcbkNvbnN0YW50ZSIsDQogICAgIk5vIE1vcnRhbGlkYWQiDQogICkNCikNCg0KIyBTdGF0cyArIGdyYXBoDQpnZ2JldHdlZW5zdGF0cygNCiAgZGF0YSA9IGhvcmFzX2hpcG94aWNhcywNCiAgeCA9IE1vcnRhbGlkYWQsDQogIHkgPSBIb3Jhc19IaXBveGlhLA0KICB0aXRsZSA9IE5VTEwsICMgRWxpbWluYSBlbCB0w610dWxvDQogIHJlc3VsdHMuc3VidGl0bGUgPSBGLCAjIEVsaW1pbmEgZWwgc3VidMOtdHVsbyBxdWUgY29udGllbmUgbGEgZWN1YWNpw7NuDQogIHhsYWIgPSAiIiwNCiAgeWxhYiA9ICJIb3JhcyBlbiBoaXBveGlhIGFsIGTDrWEiLA0KICB0eXBlID0gIm5vbnBhcmFtZXRyaWMiLCAjIFVzYSBLcnVza2FsLVdhbGxpcyBjb21vIHRlc3QgcHJpbmNpcGFsDQogIHBhaXJ3aXNlLmNvbXBhcmlzb25zID0gVFJVRSwgIyBDb21wYXJhY2lvbmVzIHBvc3QtaG9jIGVudHJlIGdydXBvcw0KICB2YXIuZXF1YWwgPSBGQUxTRSwNCiAgcGFpcndpc2UuZGlzcGxheSA9ICJzaWduaWZpY2FudCIsICMgU29sbyBtdWVzdHJhIHBhcmVzIHNpZ25pZmljYXRpdm9zDQogIHAuYWRqdXN0Lm1ldGhvZCA9ICJib25mZXJyb25pIiwgIyBDb3JyZWNjacOzbiBwYXJhIG3Dumx0aXBsZXMgY29tcGFyYWNpb25lcw0KICBnZ3RoZW1lID0gZ2dwbG90Mjo6dGhlbWVfbWluaW1hbCgpLCAjIFRlbWEgbWluaW1hbGlzdGENCiAgdmlvbGluLmFyZ3MgPSBsaXN0KHdpZHRoID0gMCwgbGluZXdpZHRoID0gMCkgIyBQYXJhIHF1aXRhciBlbCB2aW9saW4gcGxvdA0KKSArDQogICMgUGVyc29uYWxpemFjacOzbiBkZWwgdGVtYQ0KICBnZ3Bsb3QyOjp0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAwKSwgIyBRdWl0YSBlbCB0w610dWxvDQogICAgcGxvdC5zdWJ0aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMCksICMgUXVpdGEgZWwgc3VidMOtdHVsbw0KICAgIGxlZ2VuZC50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMiksICMgVGFtYcOxbyBkZWwgdGV4dG8gZGUgbGEgbGV5ZW5kYQ0KICAgIGF4aXMudGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIsIGNvbG9yID0gImJsYWNrIiksICMgVGFtYcOxbyB5IGNvbG9yIGRlbCB0ZXh0byBkZSBsb3MgZWplcw0KICAgIGF4aXMudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwgIyBUYW1hw7FvIGRlIHTDrXR1bG8gZGUgbG9zIGVqZXMNCiAgICBheGlzLnRpY2tzLmxlbmd0aCA9IGdncGxvdDI6OnVuaXQoNSwgInB0IiksICMgTG9uZ2l0dWQgZGUgbG9zIHRpY2tzDQogICAgYXhpcy50aWNrcyA9IGdncGxvdDI6OmVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLCAjIENvbG9yIGRlIGxvcyB0aWNrcw0KICAgIGF4aXMubGluZSA9IGdncGxvdDI6OmVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjUpLCAjIEzDrW5lYXMgZGUgbG9zIGVqZXMNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLCAjIEVsaW1pbmEgbGFzIGzDrW5lYXMgZGUgbGEgZ3JpbGxhIG1heW9yDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSAgIyBFbGltaW5hIGxhcyBsw61uZWFzIGRlIGxhIGdyaWxsYSBtZW5vcg0KICApICsNCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiM1NkI0RTkiLCAicmVkIiwgImdyZWVuIiwgIiNENTVFMDAiKSkNCg0KDQoNCmBgYA0KDQojIyBQb3JjZW50YWplIGRlIHJlZ2lzdHJvcyBoaXDDs3hpY29zIGFsIGTDrWENCg0KKipQb3JjZW50YWplIGRlIHJlZ2lzdHJvcyBoaXDDs3hpY29zIGFsIGRpYToqKg0KDQpgYGB7ciwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBGdW5jacOzbiBwYXJhIGNhbGN1bGFyIGVsIHBvcmNlbnRhamUgZGUgaG9yYXMgaGlww7N4aWNhcyBwb3IgZMOtYQ0KY2FsY3VsYXJfcG9yY2VudGFqZV9oaXBveGlhIDwtIGZ1bmN0aW9uKGRmKSB7DQogIGRmICU+JQ0KICAgIG11dGF0ZShEaWEgPSBhcy5EYXRlKEhvcmFfTGltYSkpICU+JQ0KICAgIGdyb3VwX2J5KERpYSwgTW9ydGFsaWRhZCkgJT4lDQogICAgc3VtbWFyaXNlKA0KICAgICAgSG9yYXNfSGlwb3hpYSA9IHN1bShIaXBveGlhKSwgICMgQ29udGFyIGxhcyBob3JhcyBoaXDDs3hpY2FzDQogICAgICBIb3Jhc19Ub3RhbGVzID0gbigpLCAgIyBDb250YXIgZWwgbsO6bWVybyB0b3RhbCBkZSByZWdpc3Ryb3MgcG9yIGTDrWENCiAgICAgIFBvcmNlbnRhamUgPSAoSG9yYXNfSGlwb3hpYSAvIEhvcmFzX1RvdGFsZXMpICogMTAwLCAgIyBDYWxjdWxhciBlbCBwb3JjZW50YWplIGRlIGhvcmFzIGhpcMOzeGljYXMNCiAgICAgIC5ncm91cHMgPSAnZHJvcCcNCiAgICApDQp9DQoNCiMgQXBsaWNhciBsYSBmdW5jacOzbiBhIHR1IGRhdGFmcmFtZQ0KcG9yY2VudGFqZV9oaXBveGlhIDwtIGNhbGN1bGFyX3BvcmNlbnRhamVfaGlwb3hpYSh0b3RhbCkNCg0KIyBOb3JtYWxpZGFkIGRlIGxvcyBkYXRvcw0KcG9yY2VudGFqZV9oaXBveGlhICU+JQ0KICBncm91cF9ieShNb3J0YWxpZGFkKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lbnNhamUgPSBwYXN0ZSgNCiAgICAgICJQcnVlYmEgZGUgU2hhcGlyby1XaWxrIHBhcmEiLCANCiAgICAgIGZpcnN0KE1vcnRhbGlkYWQpLCAjIE9idMOpbiBlbCBub21icmUgZGVsIGdydXBvDQogICAgICAiOiBwID0iLCBzaWduaWYoc2hhcGlyby50ZXN0KFBvcmNlbnRhamUpJHAudmFsdWUsIGRpZ2l0cyA9IDMpDQogICAgKQ0KICApICU+JQ0KICBwdWxsKG1lbnNhamUpICU+JSAjIEV4dHJhZSBzb2xvIGxvcyBtZW5zYWplcw0KICBjYXQoc2VwID0gIlxuIikgIyBMb3MgaW1wcmltZSBsw61uZWEgcG9yIGzDrW5lYQ0KDQojIEhvbW9nZW5laWRhZCBkZSBsb3MgZGF0b3MNCmxldmVuZV9yZXN1bHQ8LSBsZXZlbmVUZXN0KFBvcmNlbnRhamUgfiBNb3J0YWxpZGFkLCBkYXRhID0gcG9yY2VudGFqZV9oaXBveGlhKQ0KcF92YWx1ZV9sZXZlbmUgPC0gc2lnbmlmKGxldmVuZV9yZXN1bHQkYFByKD5GKWBbMV0sIGRpZ2l0cyA9IDMpDQpjYXQoIlBydWViYSBkZSBMZXZlbmUgcGFyYSBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzOiBwID0iLCBwX3ZhbHVlX2xldmVuZSwgIlxuIikNCg0KIyBLcnVza2FsLVdhbGxpcw0Ka3J1c2thbF9yZXN1bHQgPC0ga3J1c2thbC50ZXN0KFBvcmNlbnRhamUgfiBNb3J0YWxpZGFkLCBkYXRhID0gcG9yY2VudGFqZV9oaXBveGlhKQ0KcHJpbnQoa3J1c2thbF9yZXN1bHQpDQoNCiMgUG9zdC1ob2MgY29uIER1bm4gcGFyYSBpZGVudGlmaWNhciBkaWZlcmVuY2lhcyBlbnRyZSBwYXJlcyBkZSBncnVwb3MNCmR1bm5fcmVzdWx0IDwtIGR1bm5UZXN0KFBvcmNlbnRhamUgfiBNb3J0YWxpZGFkLCBkYXRhID0gcG9yY2VudGFqZV9oaXBveGlhLCBtZXRob2QgPSAiYm9uZmVycm9uaSIpDQoNCiMgRXh0cmFlciBsb3MgcmVzdWx0YWRvcyBlbiBmb3JtYXRvIGRlIGRhdGFmcmFtZQ0KdGFibGFfZHVubiA8LSBhcy5kYXRhLmZyYW1lKGR1bm5fcmVzdWx0JHJlcykNCg0KIyBSZW5vbWJyYXIgY29sdW1uYXMgcGFyYSBxdWUgc2VhbiBtw6FzIGxlZ2libGVzDQpjb2xuYW1lcyh0YWJsYV9kdW5uKSA8LSBjKCJDb21wYXJhY2lvbiIsICJFc3RhZGlzdGljbyBaIiwgIlAgc2luIGFqdXN0YXIiLCAiUCBhanVzdGFkbyIpDQoNCiMgQ3JlYXIgbGEgdGFibGEgY29uIGd0DQp0YWJsYV9kdW5uICU+JQ0KICBndCgpICU+JQ0KICB0YWJfaGVhZGVyKA0KICAgIHRpdGxlID0gIlJlc3VsdGFkb3MgZGVsIFRlc3QgZGUgRHVubiIsDQogICAgc3VidGl0bGUgPSAiQ29tcGFyYWNpb25lcyBkZSBQb3JjZW50YWplIGRlIHJlZ2lzdHJvcyBoaXBveGljb3MgZW50cmUgZ3J1cG9zIGRlIE1vcnRhbGlkYWQiDQogICkgJT4lDQogIGZtdF9udW1iZXIoDQogICAgY29sdW1ucyA9IGMoIkVzdGFkaXN0aWNvIFoiLCAiUCBzaW4gYWp1c3RhciIsICJQIGFqdXN0YWRvIiksDQogICAgZGVjaW1hbHMgPSAzDQogICkgJT4lDQogIGNvbHNfbGFiZWwoDQogICAgYENvbXBhcmFjaW9uYCA9ICJHcnVwb3MgQ29tcGFyYWRvcyIsDQogICAgYEVzdGFkaXN0aWNvIFpgID0gIkVzdGFkw61zdGljbyBaIiwNCiAgICBgUCBzaW4gYWp1c3RhcmAgPSAiUC12YWxvciAoc2luIGFqdXN0YXIpIiwNCiAgICBgUCBhanVzdGFkb2AgPSAiUC12YWxvciAoYWp1c3RhZG8pIg0KICApDQoNCmBgYA0KDQpgYGB7ciwgZWNobz1UUlVFLCBmaWcud2lkdGg9MTAsbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmdncGxvdChwb3JjZW50YWplX2hpcG94aWEsIGFlcyh4ID0gTW9ydGFsaWRhZCwgeSA9IFBvcmNlbnRhamUsIGZpbGwgPSBNb3J0YWxpZGFkKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcsIG91dGxpZXIuc2hhcGUgPSBOQSkgKw0KICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMiwgc2l6ZSA9IDIsIGFscGhhID0gMC42LCBjb2xvciA9ICJibGFjayIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzU2QjRFOSIsICIjRTY5RjAwIiwgIiMwMDlFNzMiLCAiI0Q1NUUwMCIpKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUmVnaXN0cm9zIEhpcMOzeGljb3MgYWwgZMOtYSIsDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUG9yY2VudGFqZSAlIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkNCg0KDQpnZ3Bsb3QocG9yY2VudGFqZV9oaXBveGlhLCBhZXMoeCA9IE1vcnRhbGlkYWQsIHkgPSBQb3JjZW50YWplLCBmaWxsID0gTW9ydGFsaWRhZCkpICsNCiAgZ2VvbV92aW9saW4odHJpbSA9IEZBTFNFLCBhbHBoYSA9IDAuNiwgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMSwgb3V0bGllci5zaGFwZSA9IE5BLCBhbHBoYSA9IDAuNSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjNTZCNEU5IiwgIiNFNjlGMDAiLCAiIzAwOUU3MyIsICIjRDU1RTAwIikpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSZWdpc3Ryb3MgSGlww7N4aWNvcyBhbCBkw61hIiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQb3JjZW50YWplICUiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KDQojIFJlb3JkZW5hciBsb3Mgbml2ZWxlcyBkZSBsYSB2YXJpYWJsZSAnTW9ydGFsaWRhZCcNCnBvcmNlbnRhamVfaGlwb3hpYSRNb3J0YWxpZGFkIDwtIGZhY3RvcigNCiAgcG9yY2VudGFqZV9oaXBveGlhJE1vcnRhbGlkYWQsDQogIGxldmVscyA9IGMoDQogICAgIk1vcnRhbGlkYWQgMjAxNSAtIEJhcnJhbmNvcyIsDQogICAgIk1vcnRhbGlkYWQgMjAxOSAtIENvbnN0YW50ZSIsDQogICAgIk1vcnRhbGlkYWQgMjAxNSAtIENvbnN0YW50ZSIsDQogICAgIk5vIE1vcnRhbGlkYWQiDQogICksDQogIGxhYmVscyA9IGMoDQogICAgIk1vcnRhbGlkYWQgMjAxNVxuQmFycmFuY29zIiwNCiAgICAiTW9ydGFsaWRhZCAyMDE5XG5Db25zdGFudGUiLA0KICAgICJNb3J0YWxpZGFkIDIwMTVcbkNvbnN0YW50ZSIsDQogICAgIk5vIE1vcnRhbGlkYWQiDQogICkNCikNCg0KDQojIFN0YXRzICsgZ3JhcGgNCmdnYmV0d2VlbnN0YXRzKA0KICBkYXRhID0gcG9yY2VudGFqZV9oaXBveGlhLA0KICB4ID0gTW9ydGFsaWRhZCwNCiAgeSA9IFBvcmNlbnRhamUsDQogIHRpdGxlID0gTlVMTCwgIyBFbGltaW5hIGVsIHTDrXR1bG8NCiAgcmVzdWx0cy5zdWJ0aXRsZSA9RiwgIyBFbGltaW5hIGVsIHN1YnTDrXR1bG8gcXVlIGNvbnRpZW5lIGxhIGVjdWFjacOzbg0KICB4bGFiID0gIiIsDQogIHlsYWIgPSAiUmVnaXN0cm9zIGhpcMOzeGljb3MgYWwgZMOtYSAoJSkiLA0KICB0eXBlID0gIm5vbnBhcmFtZXRyaWMiLCAjIFVzYSBLcnVza2FsLVdhbGxpcyBjb21vIHRlc3QgcHJpbmNpcGFsDQogIHBhaXJ3aXNlLmNvbXBhcmlzb25zID0gVFJVRSwgIyBDb21wYXJhY2lvbmVzIHBvc3QtaG9jIGVudHJlIGdydXBvcw0KICB2YXIuZXF1YWwgPSBGQUxTRSwNCiAgcGFpcndpc2UuZGlzcGxheSA9ICJzaWduaWZpY2FudCIsICMgU29sbyBtdWVzdHJhIHBhcmVzIHNpZ25pZmljYXRpdm9zDQogIHAuYWRqdXN0Lm1ldGhvZCA9ICJib25mZXJyb25pIiwgIyBDb3JyZWNjacOzbiBwYXJhIG3Dumx0aXBsZXMgY29tcGFyYWNpb25lcw0KICBnZ3RoZW1lID0gZ2dwbG90Mjo6dGhlbWVfbWluaW1hbCgpLCAjIFRlbWEgbWluaW1hbGlzdGENCiAgdmlvbGluLmFyZ3MgPSBsaXN0KHdpZHRoID0gMCwgbGluZXdpZHRoID0gMCkgIyBQYXJhIHF1aXRhciBlbCB2aW9saW4gcGxvdA0KKSArDQogICMgUGFsZXRhIGRlIGNvbG9yZXMgcGVyc29uYWxpemFkYQ0KICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzU2QjRFOSIsICJyZWQiLCAiZ3JlZW4iLCAiI0Q1NUUwMCIpKSArDQogIA0KICAjIFBlcnNvbmFsaXphY2nDs24gZGVsIHRlbWENCiAgZ2dwbG90Mjo6dGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMCksICMgUXVpdGEgZWwgdMOtdHVsbw0KICAgIHBsb3Quc3VidGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDApLCAjIFF1aXRhIGVsIHN1YnTDrXR1bG8NCiAgICBsZWdlbmQudGV4dCA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTIpLCAjIFRhbWHDsW8gZGVsIHRleHRvIGRlIGxhIGxleWVuZGENCiAgICBheGlzLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBjb2xvciA9ICJibGFjayIpLCAjIFRhbWHDsW8geSBjb2xvciBkZWwgdGV4dG8gZGUgbG9zIGVqZXMNCiAgICBheGlzLnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxNCksICMgVGFtYcOxbyBkZWwgdMOtdHVsbyBkZSBsb3MgZWplcw0KICAgIGF4aXMudGlja3MubGVuZ3RoID0gZ2dwbG90Mjo6dW5pdCg1LCAicHQiKSwgIyBMb25naXR1ZCBkZSBsb3MgdGlja3MNCiAgICBheGlzLnRpY2tzID0gZ2dwbG90Mjo6ZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiksICMgQ29sb3IgZGUgbG9zIHRpY2tzDQogICAgYXhpcy5saW5lID0gZ2dwbG90Mjo6ZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuNSksICMgTMOtbmVhcyBkZSBsb3MgZWplcw0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBnZ3Bsb3QyOjplbGVtZW50X2JsYW5rKCksICMgRWxpbWluYSBsYXMgbMOtbmVhcyBkZSBsYSBncmlsbGEgbWF5b3INCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpICAjIEVsaW1pbmEgbGFzIGzDrW5lYXMgZGUgbGEgZ3JpbGxhIG1lbm9yDQogICkNCg0KDQpgYGANCg0KIyMgTWluaW1vIGRlIFNhdCBPRCBhbCBkaWENCg0KKipNaW5pbW8gZGUgU2F0dXJhY2lvbiBkZSBveMOtZ2VubyBhbCBkw61hOioqDQpgYGB7ciwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBGdW5jacOzbiBwYXJhIGNhbGN1bGFyIG3DrW5pbW8gZGUgRE9fc2F0IHBvciBkw61hIA0KY2FsY3VsYXJfbWluX29kIDwtIGZ1bmN0aW9uKGRmKSB7DQogIGRmICU+JQ0KICAgIG11dGF0ZShEaWEgPSBhcy5EYXRlKEhvcmFfTGltYSkpICU+JQ0KICAgIGdyb3VwX2J5KERpYSwgTW9ydGFsaWRhZCkgJT4lDQogICAgc3VtbWFyaXNlKG1pbmltbyA9IG1pbihET19zYXQpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KfQ0KDQojIEFwbGljYXIgY2FsY3VsYXJfbWluX29kIGEgY2FkYSBjb25qdW50byBkZSBkYXRvcw0KbWluX29kIDwtIGNhbGN1bGFyX21pbl9vZCh0b3RhbCkNCg0KIyBOb3JtYWxpZGFkIGRlIGxvcyBkYXRvcw0KbWluX29kICU+JQ0KICBncm91cF9ieShNb3J0YWxpZGFkKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lbnNhamUgPSBwYXN0ZSgNCiAgICAgICJQcnVlYmEgZGUgU2hhcGlyby1XaWxrIHBhcmEiLCANCiAgICAgIGZpcnN0KE1vcnRhbGlkYWQpLCAjIE9idMOpbiBlbCBub21icmUgZGVsIGdydXBvDQogICAgICAiOiBwID0iLCBzaWduaWYoc2hhcGlyby50ZXN0KG1pbmltbykkcC52YWx1ZSwgZGlnaXRzID0gMykNCiAgICApDQogICkgJT4lDQogIHB1bGwobWVuc2FqZSkgJT4lICMgRXh0cmFlIHNvbG8gbG9zIG1lbnNhamVzDQogIGNhdChzZXAgPSAiXG4iKSAjIExvcyBpbXByaW1lIGzDrW5lYSBwb3IgbMOtbmVhDQoNCiMgSG9tb2dlbmVpZGFkIGRlIGxvcyBkYXRvcw0KbGV2ZW5lX3Jlc3VsdDwtIGxldmVuZVRlc3QobWluaW1vIH4gTW9ydGFsaWRhZCwgZGF0YSA9IG1pbl9vZCkNCnBfdmFsdWVfbGV2ZW5lIDwtIHNpZ25pZihsZXZlbmVfcmVzdWx0JGBQcig+RilgWzFdLCBkaWdpdHMgPSAzKQ0KY2F0KCJQcnVlYmEgZGUgTGV2ZW5lIHBhcmEgaG9tb2dlbmVpZGFkIGRlIHZhcmlhbnphczogcCA9IiwgcF92YWx1ZV9sZXZlbmUsICJcbiIpDQoNCiMgS3J1c2thbC1XYWxsaXMNCmtydXNrYWxfcmVzdWx0IDwtIGtydXNrYWwudGVzdChtaW5pbW8gfiBNb3J0YWxpZGFkLCBkYXRhID0gbWluX29kKQ0KcHJpbnQoa3J1c2thbF9yZXN1bHQpDQoNCiMgUG9zdC1ob2MgY29uIER1bm4gcGFyYSBpZGVudGlmaWNhciBkaWZlcmVuY2lhcyBlbnRyZSBwYXJlcyBkZSBncnVwb3MNCmR1bm5fcmVzdWx0IDwtIGR1bm5UZXN0KG1pbmltbyB+IE1vcnRhbGlkYWQsIGRhdGEgPSBtaW5fb2QsIG1ldGhvZCA9ICJib25mZXJyb25pIikNCg0KIyBFeHRyYWVyIGxvcyByZXN1bHRhZG9zIGVuIGZvcm1hdG8gZGUgZGF0YWZyYW1lDQp0YWJsYV9kdW5uIDwtIGFzLmRhdGEuZnJhbWUoZHVubl9yZXN1bHQkcmVzKQ0KDQojIFJlbm9tYnJhciBjb2x1bW5hcyBwYXJhIHF1ZSBzZWFuIG3DoXMgbGVnaWJsZXMNCmNvbG5hbWVzKHRhYmxhX2R1bm4pIDwtIGMoIkNvbXBhcmFjaW9uIiwgIkVzdGFkaXN0aWNvIFoiLCAiUCBzaW4gYWp1c3RhciIsICJQIGFqdXN0YWRvIikNCg0KIyBDcmVhciBsYSB0YWJsYSBjb24gZ3QNCnRhYmxhX2R1bm4gJT4lDQogIGd0KCkgJT4lDQogIHRhYl9oZWFkZXIoDQogICAgdGl0bGUgPSAiUmVzdWx0YWRvcyBkZWwgVGVzdCBkZSBEdW5uIiwNCiAgICBzdWJ0aXRsZSA9ICJDb21wYXJhY2lvbmVzIGRlIFBvcmNlbnRhamUgZGUgcmVnaXN0cm9zIGhpcG94aWNvcyBlbnRyZSBncnVwb3MgZGUgTW9ydGFsaWRhZCINCiAgKSAlPiUNCiAgZm10X251bWJlcigNCiAgICBjb2x1bW5zID0gYygiRXN0YWRpc3RpY28gWiIsICJQIHNpbiBhanVzdGFyIiwgIlAgYWp1c3RhZG8iKSwNCiAgICBkZWNpbWFscyA9IDMNCiAgKSAlPiUNCiAgY29sc19sYWJlbCgNCiAgICBgQ29tcGFyYWNpb25gID0gIkdydXBvcyBDb21wYXJhZG9zIiwNCiAgICBgRXN0YWRpc3RpY28gWmAgPSAiRXN0YWTDrXN0aWNvIFoiLA0KICAgIGBQIHNpbiBhanVzdGFyYCA9ICJQLXZhbG9yIChzaW4gYWp1c3RhcikiLA0KICAgIGBQIGFqdXN0YWRvYCA9ICJQLXZhbG9yIChhanVzdGFkbykiDQogICkNCg0KYGBgDQoNCmBgYHtyLCBlY2hvPVRSVUUsIGZpZy53aWR0aD0xMCxtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQpnZ3Bsb3QobWluX29kLCBhZXMoeCA9IE1vcnRhbGlkYWQsIHkgPSBtaW5pbW8sIGZpbGwgPSBNb3J0YWxpZGFkKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcsIG91dGxpZXIuc2hhcGUgPSBOQSkgKw0KICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMiwgc2l6ZSA9IDIsIGFscGhhID0gMC42LCBjb2xvciA9ICJibGFjayIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzU2QjRFOSIsICIjRTY5RjAwIiwgIiMwMDlFNzMiLCAiI0Q1NUUwMCIpKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTWluaW1hIHNhdHVyYWNpb24gZGUgb3jDrWdlbm8gYWwgZMOtYSIsDQogICAgeCA9ICIiLA0KICAgIHkgPSAiU2F0dXJhY2lvbiBPRCAoJSkiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KDQoNCmdncGxvdChtaW5fb2QsIGFlcyh4ID0gTW9ydGFsaWRhZCwgeSA9IG1pbmltbywgZmlsbCA9IE1vcnRhbGlkYWQpKSArDQogIGdlb21fdmlvbGluKHRyaW0gPSBGQUxTRSwgYWxwaGEgPSAwLjYsIGNvbG9yID0gImJsYWNrIikgKw0KICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjEsIG91dGxpZXIuc2hhcGUgPSBOQSwgYWxwaGEgPSAwLjUpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzU2QjRFOSIsICIjRTY5RjAwIiwgIiMwMDlFNzMiLCAiI0Q1NUUwMCIpKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTWluaW1hIHNhdHVyYWNpb24gZGUgb3jDrWdlbm8gYWwgZMOtYSIsDQogICAgeCA9ICIiLA0KICAgIHkgPSAiU2F0dXJhY2lvbiBkZSBPRCAoJSkiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KDQoNCiMgUmVvcmRlbmFyIGxvcyBuaXZlbGVzIGRlIGxhIHZhcmlhYmxlICdNb3J0YWxpZGFkJw0KbWluX29kJE1vcnRhbGlkYWQgPC0gZmFjdG9yKA0KICBtaW5fb2QkTW9ydGFsaWRhZCwNCiAgbGV2ZWxzID0gYygNCiAgICAiTW9ydGFsaWRhZCAyMDE1IC0gQmFycmFuY29zIiwNCiAgICAiTW9ydGFsaWRhZCAyMDE5IC0gQ29uc3RhbnRlIiwNCiAgICAiTW9ydGFsaWRhZCAyMDE1IC0gQ29uc3RhbnRlIiwNCiAgICAiTm8gTW9ydGFsaWRhZCINCiAgKSwNCiAgbGFiZWxzID0gYygNCiAgICAiTW9ydGFsaWRhZCAyMDE1XG5CYXJyYW5jb3MiLA0KICAgICJNb3J0YWxpZGFkIDIwMTlcbkNvbnN0YW50ZSIsDQogICAgIk1vcnRhbGlkYWQgMjAxNVxuQ29uc3RhbnRlIiwNCiAgICAiTm8gTW9ydGFsaWRhZCINCiAgKQ0KKQ0KDQojIFN0YXRzICsgZ3JhcGgNCmdnYmV0d2VlbnN0YXRzKA0KICBkYXRhID0gbWluX29kLA0KICB4ID0gTW9ydGFsaWRhZCwNCiAgeSA9IG1pbmltbywNCiAgdGl0bGUgPSBOVUxMLCAjIEVsaW1pbmEgZWwgdMOtdHVsbw0KICByZXN1bHRzLnN1YnRpdGxlID0gRiwgIyBFbGltaW5hIGVsIHN1YnTDrXR1bG8gcXVlIGNvbnRpZW5lIGxhIGVjdWFjacOzbg0KICB4bGFiID0gIiIsDQogIHlsYWIgPSAiTWluaW1hIHNhdHVyYWNpw7NuIE9EIGFsIGTDrWEgKCUpIiwNCiAgdHlwZSA9ICJub25wYXJhbWV0cmljIiwgIyBVc2EgS3J1c2thbC1XYWxsaXMgY29tbyB0ZXN0IHByaW5jaXBhbA0KICBwYWlyd2lzZS5jb21wYXJpc29ucyA9IFRSVUUsICMgQ29tcGFyYWNpb25lcyBwb3N0LWhvYyBlbnRyZSBncnVwb3MNCiAgdmFyLmVxdWFsID0gRkFMU0UsDQogIHBhaXJ3aXNlLmRpc3BsYXkgPSAic2lnbmlmaWNhbnQiLCAjIFNvbG8gbXVlc3RyYSBwYXJlcyBzaWduaWZpY2F0aXZvcw0KICBwLmFkanVzdC5tZXRob2QgPSAiYm9uZmVycm9uaSIsICMgQ29ycmVjY2nDs24gcGFyYSBtw7psdGlwbGVzIGNvbXBhcmFjaW9uZXMNCiAgZ2d0aGVtZSA9IGdncGxvdDI6OnRoZW1lX21pbmltYWwoKSwgIyBUZW1hIG1pbmltYWxpc3RhDQogIHZpb2xpbi5hcmdzID0gbGlzdCh3aWR0aCA9IDAsIGxpbmV3aWR0aCA9IDApICMgUGFyYSBxdWl0YXIgZWwgdmlvbGluIHBsb3QNCikgKw0KICAjIFBhbGV0YSBkZSBjb2xvcmVzIHBlcnNvbmFsaXphZGENCiAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiM1NkI0RTkiLCAicmVkIiwgImdyZWVuIiwgIiNENTVFMDAiKSkgKw0KICANCiAgIyBQZXJzb25hbGl6YWNpw7NuIGRlbCB0ZW1hDQogIGdncGxvdDI6OnRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDApLCAjIFF1aXRhIGVsIHTDrXR1bG8NCiAgICBwbG90LnN1YnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAwKSwgIyBRdWl0YSBlbCBzdWJ0w610dWxvDQogICAgbGVnZW5kLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgIyBUYW1hw7FvIGRlbCB0ZXh0byBkZSBsYSBsZXllbmRhDQogICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSwgIyBUYW1hw7FvIHkgY29sb3IgZGVsIHRleHRvIGRlIGxvcyBlamVzDQogICAgYXhpcy50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAjIFRhbWHDsW8gZGVsIHTDrXR1bG8gZGUgbG9zIGVqZXMNCiAgICBheGlzLnRpY2tzLmxlbmd0aCA9IGdncGxvdDI6OnVuaXQoNSwgInB0IiksICMgTG9uZ2l0dWQgZGUgbG9zIHRpY2tzDQogICAgYXhpcy50aWNrcyA9IGdncGxvdDI6OmVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLCAjIENvbG9yIGRlIGxvcyB0aWNrcw0KICAgIGF4aXMubGluZSA9IGdncGxvdDI6OmVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjUpLCAjIEzDrW5lYXMgZGUgbG9zIGVqZXMNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLCAjIEVsaW1pbmEgbGFzIGzDrW5lYXMgZGUgbGEgZ3JpbGxhIG1heW9yDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSAgIyBFbGltaW5hIGxhcyBsw61uZWFzIGRlIGxhIGdyaWxsYSBtZW5vcg0KICApDQoNCg0KDQoNCmBgYA0KDQojIyBNZWRpYW5hIGRlIFNhdCBPRCBhbCBkaWENCg0KKipNZWRpYW5hIGRlIFNhdHVyYWNpb24gZGUgb3hpZ2VubyBhbCBkaWE6KioNCg0KYGBge3IsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgRnVuY2nDs24gcGFyYSBjYWxjdWxhciBtZWRpYW5hIGRlIERPX3NhdCBwb3IgZMOtYSB5IHpvbmENCmNhbGN1bGFyX21lZGlhbl9vZCA8LSBmdW5jdGlvbihkZikgew0KICBkZiAlPiUNCiAgICBtdXRhdGUoRGlhID0gYXMuRGF0ZShIb3JhX0xpbWEpKSAlPiUNCiAgICBncm91cF9ieShEaWEsIE1vcnRhbGlkYWQpICU+JQ0KICAgIHN1bW1hcmlzZShtZWRpYW49IG1lZGlhbihET19zYXQpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KfQ0KDQojIEFwbGljYXIgY2FsY3VsYXJfbWluX29kIGEgY2FkYSBjb25qdW50byBkZSBkYXRvcw0KbWVkX29kIDwtIGNhbGN1bGFyX21lZGlhbl9vZCh0b3RhbCkNCg0KIyBOb3JtYWxpZGFkIGRlIGxvcyBkYXRvcw0KbWVkX29kICU+JQ0KICBncm91cF9ieShNb3J0YWxpZGFkKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lbnNhamUgPSBwYXN0ZSgNCiAgICAgICJQcnVlYmEgZGUgU2hhcGlyby1XaWxrIHBhcmEiLCANCiAgICAgIGZpcnN0KE1vcnRhbGlkYWQpLCAjIE9idMOpbiBlbCBub21icmUgZGVsIGdydXBvDQogICAgICAiOiBwID0iLCBzaWduaWYoc2hhcGlyby50ZXN0KG1lZGlhbikkcC52YWx1ZSwgZGlnaXRzID0gMykNCiAgICApDQogICkgJT4lDQogIHB1bGwobWVuc2FqZSkgJT4lICMgRXh0cmFlIHNvbG8gbG9zIG1lbnNhamVzDQogIGNhdChzZXAgPSAiXG4iKSAjIExvcyBpbXByaW1lIGzDrW5lYSBwb3IgbMOtbmVhDQoNCiMgSG9tb2dlbmVpZGFkIGRlIGxvcyBkYXRvcw0KbGV2ZW5lX3Jlc3VsdDwtIGxldmVuZVRlc3QobWVkaWFuIH4gTW9ydGFsaWRhZCwgZGF0YSA9IG1lZF9vZCkNCnBfdmFsdWVfbGV2ZW5lIDwtIHNpZ25pZihsZXZlbmVfcmVzdWx0JGBQcig+RilgWzFdLCBkaWdpdHMgPSAzKQ0KY2F0KCJQcnVlYmEgZGUgTGV2ZW5lIHBhcmEgaG9tb2dlbmVpZGFkIGRlIHZhcmlhbnphczogcCA9IiwgcF92YWx1ZV9sZXZlbmUsICJcbiIpDQoNCiMgS3J1c2thbC1XYWxsaXMNCmtydXNrYWxfcmVzdWx0IDwtIGtydXNrYWwudGVzdChtZWRpYW4gfiBNb3J0YWxpZGFkLCBkYXRhID0gbWVkX29kKQ0KcHJpbnQoa3J1c2thbF9yZXN1bHQpDQoNCiMgUG9zdC1ob2MgY29uIER1bm4gcGFyYSBpZGVudGlmaWNhciBkaWZlcmVuY2lhcyBlbnRyZSBwYXJlcyBkZSBncnVwb3MNCmR1bm5fcmVzdWx0IDwtIGR1bm5UZXN0KG1lZGlhbiB+IE1vcnRhbGlkYWQsIGRhdGEgPSBtZWRfb2QsIG1ldGhvZCA9ICJib25mZXJyb25pIikNCg0KIyBFeHRyYWVyIGxvcyByZXN1bHRhZG9zIGVuIGZvcm1hdG8gZGUgZGF0YWZyYW1lDQp0YWJsYV9kdW5uIDwtIGFzLmRhdGEuZnJhbWUoZHVubl9yZXN1bHQkcmVzKQ0KDQojIFJlbm9tYnJhciBjb2x1bW5hcyBwYXJhIHF1ZSBzZWFuIG3DoXMgbGVnaWJsZXMNCmNvbG5hbWVzKHRhYmxhX2R1bm4pIDwtIGMoIkNvbXBhcmFjaW9uIiwgIkVzdGFkaXN0aWNvIFoiLCAiUCBzaW4gYWp1c3RhciIsICJQIGFqdXN0YWRvIikNCg0KIyBDcmVhciBsYSB0YWJsYSBjb24gZ3QNCnRhYmxhX2R1bm4gJT4lDQogIGd0KCkgJT4lDQogIHRhYl9oZWFkZXIoDQogICAgdGl0bGUgPSAiUmVzdWx0YWRvcyBkZWwgVGVzdCBkZSBEdW5uIiwNCiAgICBzdWJ0aXRsZSA9ICJDb21wYXJhY2lvbmVzIGRlIFBvcmNlbnRhamUgZGUgcmVnaXN0cm9zIGhpcG94aWNvcyBlbnRyZSBncnVwb3MgZGUgTW9ydGFsaWRhZCINCiAgKSAlPiUNCiAgZm10X251bWJlcigNCiAgICBjb2x1bW5zID0gYygiRXN0YWRpc3RpY28gWiIsICJQIHNpbiBhanVzdGFyIiwgIlAgYWp1c3RhZG8iKSwNCiAgICBkZWNpbWFscyA9IDMNCiAgKSAlPiUNCiAgY29sc19sYWJlbCgNCiAgICBgQ29tcGFyYWNpb25gID0gIkdydXBvcyBDb21wYXJhZG9zIiwNCiAgICBgRXN0YWRpc3RpY28gWmAgPSAiRXN0YWTDrXN0aWNvIFoiLA0KICAgIGBQIHNpbiBhanVzdGFyYCA9ICJQLXZhbG9yIChzaW4gYWp1c3RhcikiLA0KICAgIGBQIGFqdXN0YWRvYCA9ICJQLXZhbG9yIChhanVzdGFkbykiDQogICkNCmBgYA0KDQoNCg0KYGBge3IsIGVjaG89VFJVRSwgZmlnLndpZHRoPTEwLG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpnZ3Bsb3QobWVkX29kLCBhZXMoeCA9IE1vcnRhbGlkYWQsIHkgPSBtZWRpYW4sIGZpbGwgPSBNb3J0YWxpZGFkKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcsIG91dGxpZXIuc2hhcGUgPSBOQSkgKw0KICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMiwgc2l6ZSA9IDIsIGFscGhhID0gMC42LCBjb2xvciA9ICJibGFjayIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzU2QjRFOSIsICIjRTY5RjAwIiwgIiMwMDlFNzMiLCAiI0Q1NUUwMCIpKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTWVkaWFuYSBkZSBsYSBzYXR1cmFjaW9uIGRlIG94w61nZW5vIGFsIGTDrWEiLA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlNhdHVyYWNpb24gT0QgKCUpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkNCg0KDQpnZ3Bsb3QobWVkX29kLCBhZXMoeCA9IE1vcnRhbGlkYWQsIHkgPSBtZWRpYW4sIGZpbGwgPSBNb3J0YWxpZGFkKSkgKw0KICBnZW9tX3Zpb2xpbih0cmltID0gRkFMU0UsIGFscGhhID0gMC42LCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gMC4xLCBvdXRsaWVyLnNoYXBlID0gTkEsIGFscGhhID0gMC41KSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM1NkI0RTkiLCAiI0U2OUYwMCIsICIjMDA5RTczIiwgIiNENTVFMDAiKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIk1lZGlhbmEgZGUgbGEgc2F0dXJhY2lvbiBkZSBveMOtZ2VubyBhbCBkw61hIiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICJTYXR1cmFjaW9uIGRlIE9EICglKSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICApDQoNCg0KDQoNCg0KDQoNCiMgQ3JlYXIgZWwgZ3LDoWZpY08NCg0KbWVkX29kJE1vcnRhbGlkYWQgPC0gZmFjdG9yKA0KICBtZWRfb2QkTW9ydGFsaWRhZCwNCiAgbGV2ZWxzID0gYygNCiAgICAiTW9ydGFsaWRhZCAyMDE1IC0gQmFycmFuY29zIiwNCiAgICAiTW9ydGFsaWRhZCAyMDE5IC0gQ29uc3RhbnRlIiwNCiAgICAiTW9ydGFsaWRhZCAyMDE1IC0gQ29uc3RhbnRlIiwNCiAgICAiTm8gTW9ydGFsaWRhZCINCiAgKSwNCiAgbGFiZWxzID0gYygNCiAgICAiTW9ydGFsaWRhZCAyMDE1XG5CYXJyYW5jb3MiLA0KICAgICJNb3J0YWxpZGFkIDIwMTlcbkNvbnN0YW50ZSIsDQogICAgIk1vcnRhbGlkYWQgMjAxNVxuQ29uc3RhbnRlIiwNCiAgICAiTm8gTW9ydGFsaWRhZCINCiAgKQ0KKQ0KDQoNCiMgU3RhdHMgKyBncmFwaA0KZ2diZXR3ZWVuc3RhdHMoDQogIGRhdGEgPSBtZWRfb2QsDQogIHggPSBNb3J0YWxpZGFkLA0KICB5ID0gbWVkaWFuLA0KICB0aXRsZSA9IE5VTEwsICMgRWxpbWluYSBlbCB0w610dWxvDQogIHJlc3VsdHMuc3VidGl0bGUgPSBGQUxTRSwgIyBFbGltaW5hIGVsIHN1YnTDrXR1bG8gcXVlIGNvbnRpZW5lIGxhIGVjdWFjacOzbg0KICB4bGFiID0gIiIsDQogIHlsYWIgPSAiTWVkaWFuYSBkZSBTYXR1cmFjacOzbiBPRCBhbCBkw61hICglKSIsDQogIHR5cGUgPSAibm9ucGFyYW1ldHJpYyIsICMgVXNhIEtydXNrYWwtV2FsbGlzIGNvbW8gdGVzdCBwcmluY2lwYWwNCiAgcGFpcndpc2UuY29tcGFyaXNvbnMgPSBUUlVFLCAjIENvbXBhcmFjaW9uZXMgcG9zdC1ob2MgZW50cmUgZ3J1cG9zDQogIHZhci5lcXVhbCA9IEZBTFNFLA0KICBwYWlyd2lzZS5kaXNwbGF5ID0gInNpZ25pZmljYW50IiwgIyBTb2xvIG11ZXN0cmEgcGFyZXMgc2lnbmlmaWNhdGl2b3MNCiAgcC5hZGp1c3QubWV0aG9kID0gImJvbmZlcnJvbmkiLCAjIENvcnJlY2Npw7NuIHBhcmEgbcO6bHRpcGxlcyBjb21wYXJhY2lvbmVzDQogIGdndGhlbWUgPSBnZ3Bsb3QyOjp0aGVtZV9taW5pbWFsKCksICMgVGVtYSBtaW5pbWFsaXN0YQ0KICB2aW9saW4uYXJncyA9IGxpc3Qod2lkdGggPSAwLCBsaW5ld2lkdGggPSAwKSAjIFBhcmEgcXVpdGFyIGVsIHZpb2xpbiBwbG90DQopICsNCiAgIyBQYWxldGEgZGUgY29sb3JlcyBwZXJzb25hbGl6YWRhDQogIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjNTZCNEU5IiwgInJlZCIsICJncmVlbiIsICIjRDU1RTAwIikpICsNCiAgDQogICMgUGVyc29uYWxpemFjacOzbiBkZWwgdGVtYQ0KICBnZ3Bsb3QyOjp0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAwKSwgIyBRdWl0YSBlbCB0w610dWxvDQogICAgbGVnZW5kLnRleHQgPSBnZ3Bsb3QyOjplbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgIyBUYW1hw7FvIGRlbCB0ZXh0byBkZSBsYSBsZXllbmRhDQogICAgYXhpcy50ZXh0ID0gZ2dwbG90Mjo6ZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgY29sb3IgPSAiYmxhY2siKSwgIyBUYW1hw7FvIHkgY29sb3IgZGVsIHRleHRvIGRlIGxvcyBlamVzDQogICAgYXhpcy50aXRsZSA9IGdncGxvdDI6OmVsZW1lbnRfdGV4dChzaXplID0gMTQpLCAjIFRhbWHDsW8gZGVsIHTDrXR1bG8gZGUgbG9zIGVqZXMNCiAgICBheGlzLnRpY2tzLmxlbmd0aCA9IGdncGxvdDI6OnVuaXQoNSwgInB0IiksICMgTG9uZ2l0dWQgZGUgbG9zIHRpY2tzDQogICAgYXhpcy50aWNrcyA9IGdncGxvdDI6OmVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLCAjIENvbG9yIGRlIGxvcyB0aWNrcw0KICAgIGF4aXMubGluZSA9IGdncGxvdDI6OmVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjUpLCAjIEzDrW5lYXMgZGUgbG9zIGVqZXMNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZ2dwbG90Mjo6ZWxlbWVudF9ibGFuaygpLCAjIEVsaW1pbmEgbGFzIGzDrW5lYXMgZGUgbGEgZ3JpbGxhIG1heW9yDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGdncGxvdDI6OmVsZW1lbnRfYmxhbmsoKSAgIyBFbGltaW5hIGxhcyBsw61uZWFzIGRlIGxhIGdyaWxsYSBtZW5vcg0KICApDQoNCmBgYA0KDQoNCiMgRGVzYXJyb2xsbyBkZSB1bmEgbWF0cml6IGRlIHJlc3B1ZXNhcyBiaW9sb2dpY2FzIGRlICpBLiBwdXJwdXJhdHVzKiBmcmVudGUgYSBsYSB0ZW1wZXJhdHVyYSBlIGhpcG94aWENCg0KYGBge3IgcHJlc3N1cmUsIGVjaG89RkFMU0UsIGZpZy5jYXA9IiIsIG91dC53aWR0aCA9ICc3MCUnfQ0KaW5jbHVkZV9ncmFwaGljcygiSW5kaWNlMS5wbmciKQ0KaW5jbHVkZV9ncmFwaGljcygiSW5kaWNlMi5wbmciKQ0KaW5jbHVkZV9ncmFwaGljcygiSW5kaWNlMy5wbmciKQ0KaW5jbHVkZV9ncmFwaGljcygiSW5kaWNlNC5wbmciKQ0KYGBgDQoNCioqQkFSUkFOQ09TIE1PUlRBTElEQUQgMjAxNSoqDQoNCmBgYHtyLCBlY2hvPVRSVUUsZmlnLndpZHRoPTgsICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojIEFob3JhIGFzaWduYW1vcyBsYSBjYXRlZ29yaWEgZGUgVGVtcF9mb25kIHkgRE9fc2F0DQpkZl9pbmRpY2UgPC0gYmFycmFuY29zXzIwMTUNCg0KZGZfaW5kaWNlIDwtIGRmX2luZGljZSAlPiUNCiAgbXV0YXRlKA0KICAgIENhdGVnb3JpYV9UID0gY2FzZV93aGVuKA0KICAgICAgVGVtcF9mb25kIDw9IDE2IH4gIjw9MTYiLA0KICAgICAgVGVtcF9mb25kID4gMTYgJiBUZW1wX2ZvbmQgPD0gMjAgfiAiXTE2LTIwXSIsDQogICAgICBUZW1wX2ZvbmQgPiAyMCAmIFRlbXBfZm9uZCA8PSAyNSB+ICJdMjAtMjVdIiwNCiAgICAgIFRlbXBfZm9uZCA+IDI1ICYgVGVtcF9mb25kIDw9IDI5IH4gIl0yNS0yOV0iLA0KICAgICAgVGVtcF9mb25kID4gMjkgfiAiPjI5Ig0KICAgICksDQogICAgQ2F0ZWdvcmlhX0RPID0gY2FzZV93aGVuKA0KICAgICAgRE9fc2F0IDw9IDIgfiAiPD0yIiwNCiAgICAgIERPX3NhdCA+IDIgJiBET19zYXQgPD0gNSB+ICJdMi01XSIsDQogICAgICBET19zYXQgPiA1ICYgRE9fc2F0IDw9IDI0LjQgfiAiXTUtMjRdIiwNCiAgICAgIERPX3NhdCA+IDI0LjQgfiAiPjI0Ig0KICAgICksDQogICAgQ2F0ZWdvcmlhX3RvdGFsID0gcGFzdGUoQ2F0ZWdvcmlhX1QsIENhdGVnb3JpYV9ETywgc2VwID0gIjsiKQ0KICApDQoNCiMgSWRlbnRpZmljYXIgbG9zIGNhbWJpb3MgZW4gbGFzIGNhdGVnb3LDrWFzIGRlIENhdGVnb3JpYV90b3RhbCBkZW50cm8gZGUgY2FkYSBncm91cCANCmRmX2luZGljZSA8LSBkZl9pbmRpY2UgJT4lDQogIGdyb3VwX2J5KGdyb3VwKSAlPiUNCiAgbXV0YXRlKGNoYW5nZSA9IENhdGVnb3JpYV90b3RhbCAhPSBsYWcoQ2F0ZWdvcmlhX3RvdGFsLCBkZWZhdWx0ID0gZmlyc3QoQ2F0ZWdvcmlhX3RvdGFsKSkpICU+JQ0KICBtdXRhdGUoZ3JvdXBfaWQgPSBjdW1zdW0oY2hhbmdlKSkgJT4lDQogIHVuZ3JvdXAgKCkNCg0KIyBDYWxjdWxhciBsYSBmZWNoYSBkZSBpbmljaW8geSBmaW4gZGUgY2FkYSBncnVwbyBkZSBjYXRlZ29yw61hcyBjb250aW51YXMNCmRmX2FncnVwYWRvIDwtIGRmX2luZGljZSAlPiUNCiAgZ3JvdXBfYnkoDQogICAgZ3JvdXAsDQogICAgZ3JvdXBfaWQpICU+JQ0KICBzdW1tYXJpemUoDQogICAgZmVjaGFfaW5pY2lvID0gbWluKEhvcmFfTGltYSksDQogICAgZmVjaGFfZmluID0gbWF4KEhvcmFfTGltYSksDQogICAgZHVyYWNpb24gPSBhcy5udW1lcmljKGRpZmZ0aW1lKG1heChIb3JhX0xpbWEpLCBtaW4oSG9yYV9MaW1hKSwgdW5pdHMgPSAiaG91cnMiKSkrMSwNCiAgICBDYXRlZ29yaWFfdG90YWwgPSBmaXJzdChDYXRlZ29yaWFfdG90YWwpLA0KICAgIENhdGVnb3JpYV9ETyA9IGZpcnN0IChDYXRlZ29yaWFfRE8pKQ0KDQojIEFncmVnYXIgY29sdW1uYSBIaXBveGljbyBjb24gdmFsb3JlcyBIaXBveGlhIG8gTm9ybW94aWENCmRmX2FncnVwYWRvIDwtIGRmX2FncnVwYWRvICU+JQ0KIG11dGF0ZShIaXBveGlhID0gaWZlbHNlKENhdGVnb3JpYV9ETyAlaW4lIGMoIjw9MiIsICJdMi01XSIsIl01LTI0XSIpLCAiSGlwb3hpYSIsICJOb3Jtb3hpYSIpKSAjJT4lDQogICN1bmdyb3VwKCkgIyU+JSAjIEVsaW1pbmFyIGFncnVwYWNpb25lcyBhY3RpdmFzDQogICNzZWxlY3QoLWdyb3VwKQ0KDQojIENyZWFyIHVuYSBjb3BpYSBkZWwgZGF0YWZyYW1lIG9yaWdpbmFsDQpkZl9yZXN1bHRhZG8gPC0gZGZfYWdydXBhZG8NCg0KIyBJZGVudGlmaWNhciBwZXJpb2RvcyBtZW5vcmVzIGEgNiBob3Jhcw0KZGZfcmVzdWx0YWRvIDwtIGRmX3Jlc3VsdGFkbyAlPiUNCiAgbXV0YXRlKGlzX3Nob3J0ID0gZHVyYWNpb24gPCA2KQ0KDQojIFByb2Nlc2FyIGxvcyBibG9xdWVzDQpwcm9jZXNhcl9ibG9xdWVzIDwtIGZ1bmN0aW9uKGRmKSB7DQogIGJsb3F1ZV9pZCA8LSAxDQogIGRmIDwtIGRmICU+JQ0KICAgIG11dGF0ZShibG9xdWUgPSAwKSAgIyBJbmljaWFsaXphbW9zIGNvbiAwIHBhcmEgbG9zIGJsb3F1ZXMNCiAgDQogIGZvciAoaSBpbiAxOm5yb3coZGYpKSB7DQogICAgaWYgKGkgPT0gMSkgew0KICAgICAgIyBBc2lnbmFyIGVsIHByaW1lciBibG9xdWUNCiAgICAgIGRmJGJsb3F1ZVtpXSA8LSBibG9xdWVfaWQNCiAgICB9IGVsc2UgaWYgKGRmJGdyb3VwW2ldICE9IGRmJGdyb3VwW2kgLSAxXSkgew0KICAgICAgIyBTaSBjYW1iaWEgZWwgZ3J1cG8sIGNyZWFyIHVuIG51ZXZvIGJsb3F1ZQ0KICAgICAgYmxvcXVlX2lkIDwtIGJsb3F1ZV9pZCArIDENCiAgICAgIGRmJGJsb3F1ZVtpXSA8LSBibG9xdWVfaWQNCiAgICB9IGVsc2UgaWYgKGRmJGlzX3Nob3J0W2kgLSAxXSAmJiBkZiRpc19zaG9ydFtpXSkgew0KICAgICAgIyBTaSBlbCBwZXJpb2RvIGFjdHVhbCB5IGVsIGFudGVyaW9yIHNvbiBjb3J0b3MsIHBlcnRlbmVjZW4gYWwgbWlzbW8gYmxvcXVlDQogICAgICBkZiRibG9xdWVbaV0gPC0gYmxvcXVlX2lkDQogICAgfSBlbHNlIGlmIChkZiRpc19zaG9ydFtpIC0gMV0gJiYgIWRmJGlzX3Nob3J0W2ldKSB7DQogICAgICAjIFNpIGVsIHBlcmlvZG8gYW50ZXJpb3IgZXJhIGNvcnRvIHBlcm8gZXN0ZSBubywgdmVyaWZpY2Ftb3MgbGEgZHVyYWNpw7NuIGFjdW11bGFkYQ0KICAgICAgYmxvcXVlX2R1cmFjaW9uIDwtIHN1bShkZiRkdXJhY2lvbltkZiRibG9xdWUgPT0gYmxvcXVlX2lkXSkNCiAgICAgIGlmIChibG9xdWVfZHVyYWNpb24gPCA2KSB7DQogICAgICAgICMgVsOtYSBCOiBJZ25vcmFyIGxhIGludGVycnVwY2nDs24geSBleHRlbmRlciBlbCBibG9xdWUgYWwgc2lndWllbnRlDQogICAgICAgIGRmJGJsb3F1ZVtpXSA8LSBibG9xdWVfaWQNCiAgICAgIH0gZWxzZSB7DQogICAgICAgICMgVsOtYSBBOiBDcmVhciB1biBudWV2byBibG9xdWUNCiAgICAgICAgYmxvcXVlX2lkIDwtIGJsb3F1ZV9pZCArIDENCiAgICAgICAgZGYkYmxvcXVlW2ldIDwtIGJsb3F1ZV9pZA0KICAgICAgfQ0KICAgIH0gZWxzZSB7DQogICAgICAjIENyZWFyIHVuIG51ZXZvIGJsb3F1ZQ0KICAgICAgYmxvcXVlX2lkIDwtIGJsb3F1ZV9pZCArIDENCiAgICAgIGRmJGJsb3F1ZVtpXSA8LSBibG9xdWVfaWQNCiAgICB9DQogIH0NCiAgDQogIHJldHVybihkZikNCn0NCg0KZGZfcmVzdWx0YWRvIDwtIHByb2Nlc2FyX2Jsb3F1ZXMoZGZfcmVzdWx0YWRvKQ0KDQojIENhbGN1bGFyIHJlc3VsdGFkb3MgZmluYWxlcyBwb3IgYmxvcXVlDQpkZl9maW5hbCA8LSBkZl9yZXN1bHRhZG8gJT4lDQogIGdyb3VwX2J5KGJsb3F1ZSwgZ3JvdXApICU+JQ0KICBzdW1tYXJpemUoDQogICAgZmVjaGFfaW5pY2lvID0gbWluKGZlY2hhX2luaWNpbyksDQogICAgZmVjaGFfZmluID0gbWF4KGZlY2hhX2ZpbiksDQogICAgZHVyYWNpb25fdG90YWwgPSBzdW0oZHVyYWNpb24pLA0KICAgIENhdGVnb3JpYV90b3RhbCA9IENhdGVnb3JpYV90b3RhbFt3aGljaC5tYXgoZHVyYWNpb24pXSwNCiAgICBDYXRlZ29yaWFfRE8gPSBDYXRlZ29yaWFfRE9bd2hpY2gubWF4KGR1cmFjaW9uKV0NCiAgKSAlPiUNCiAgdW5ncm91cCgpDQoNCiMgQWdydXBhciBwb3IgYmxvcXVlcyBjb25zZWN1dGl2b3MgY29uIGVsIG1pc21vIENhdGVnb3JpYV90b3RhbA0KZGZfY29uc29saWRhZG8gPC0gZGZfZmluYWwgJT4lDQogIG11dGF0ZSgNCiAgICBncnVwb19jYXRlZ29yaWEgPSBjdW1zdW0oQ2F0ZWdvcmlhX3RvdGFsICE9IGxhZyhDYXRlZ29yaWFfdG90YWwsIGRlZmF1bHQgPSBmaXJzdChDYXRlZ29yaWFfdG90YWwpKSkNCiAgKSAlPiUNCiAgZ3JvdXBfYnkoZ3J1cG9fY2F0ZWdvcmlhLGdyb3VwKSAlPiUNCiAgc3VtbWFyaXplKA0KICAgIGZlY2hhX2luaWNpbyA9IG1pbihmZWNoYV9pbmljaW8pLA0KICAgIGZlY2hhX2ZpbiA9IG1heChmZWNoYV9maW4pLA0KICAgIGR1cmFjaW9uID0gc3VtKGR1cmFjaW9uX3RvdGFsKSwNCiAgICBDYXRlZ29yaWFfdG90YWwgPSBmaXJzdChDYXRlZ29yaWFfdG90YWwpLA0KICAgIENhdGVnb3JpYV9ETyA9IGZpcnN0KENhdGVnb3JpYV9ETykgIyBDb25zaWRlcmFtb3MgbGEgbWlzbWEgbMOzZ2ljYSBwYXJhIENhdGVnb3JpYV9ETw0KICApICU+JQ0KICB1bmdyb3VwKCkNCg0KDQojIEFzaWduYXIgbGFzIGNhdGVnb3JpYXMNCmRmX2NvbnNvbGlkYWRvIDwtIGRmX2NvbnNvbGlkYWRvICU+JQ0KICBtdXRhdGUoDQogICAgSW5kaWNlID0gY2FzZV93aGVuKA0KICAgICAgZHVyYWNpb24gPCAxMiAmIENhdGVnb3JpYV90b3RhbCA9PSAiPD0xNjs+MjQiIH4gIklub2N1byIsDQogICAgICBkdXJhY2lvbiA8IDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2O101LTI0XSIgfiAiRXN0cmVzIGZpc2lvbG9naWNvIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2O10yLTVdIn4gIkVzdHJlcyBmaXNpb2xvZ2ljbyIsDQogICAgICBkdXJhY2lvbjwxMiAmIENhdGVnb3JpYV90b3RhbCA9PSI8PTE2Ozw9MiIgfiAiRXN0cmVzIGZpc2lvbG9naWNvIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdOz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdO101LTI0XSIgfiAiRXN0cmVzIGZpc2lvbG9naWNvIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09Il0xNi0yMF07XTItNV0iIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbjwxMiAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTE2LTIwXTs8PTIiIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbjwxMiAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTs+MjQiIH4gIklub2N1byIsDQogICAgICBkdXJhY2lvbiA8MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07XTUtMjRdIn4iRXN0cmVzIGZpc2lvbG9naWNvIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjAtMjVdO10yLTVdIiB+ICJTaW4gaW5mb3JtYWNpb24iLA0KICAgICAgZHVyYWNpb248MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07PD0yIiB+ICJQcm9iYWJpbGlkYWQgZGUgbW9ydGFsaWRhZCIsDQogICAgICBkdXJhY2lvbjwxMiAmIENhdGVnb3JpYV90b3RhbCA9PSAiMjUtMjldOz4yNCIgfiAiU2luIGluZm9ybWFjaW9uIiwNCiAgICAgIGR1cmFjaW9uIDwxMiAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTtdNS0yNF0ifiJTaW4gaW5mb3JtYWNpb24iLA0KICAgICAgZHVyYWNpb248MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yNS0yOV07XTItNV0iIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbjwxMiAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTs8PTIiIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7PjI0IiB+ICJQcm9iYWJpbGlkYWQgZGUgbW9ydGFsaWRhZCIsDQogICAgICBkdXJhY2lvbiA8MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIj4yOTs1LTI0XSJ+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbjwxMiAmIENhdGVnb3JpYV90b3RhbD09ICI+Mjk7XTItNV0iIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7PD0yIiB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7PjI0IiB+ICJJbm9jdW8iLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2O101LTI0XSIgfiAiRXN0cmVzIGZpc2lvbG9naWNvIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7XTItNV0iICB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICAmIENhdGVnb3JpYV90b3RhbCA9PSAiPD0xNjs8PTIiICB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdOz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07XTUtMjRdIiAgfiAiRXN0cmVzIGZpc2lvbG9naWNvIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTE2LTIwXTtdMi01XSIgIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07PD0yIiAgfiAiUHJvYmFiaWxpZGFkIGRlIG1vcnRhbGlkYWQiLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjAtMjVdOz4yNCIgIH4gIklub2N1byIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07XTUtMjRdIiAgfiAiRXN0cmVzIGZpc2lvbG9naWNvIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTtdMi01XSIgIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07PD0yIiAgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjUtMjldOz4yNCIgICB+ICJTaW4gaW5mb3JtYWNpb24iLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICZDYXRlZ29yaWFfdG90YWwgPT0gIl0yNS0yOV07XTUtMjRdIiAgfiAiU2luIGluZm9ybWFjaW9uIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTtdMi01XSIgICB+ICJTaW4gaW5mb3JtYWNpb24iLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjUtMjldOzw9MiIgIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPjI5Oz4yNCIgIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPjI5OzUtMjRdIiAgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7XTItNV0iICB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgID09ICI+Mjk7PD0yIiAgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2Oz4yNCIgIH4gIklub2N1byIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7XTUtMjRdIiB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2O10yLTVdIiAgfiAiRXN0cmVzIGZpc2lvbG9naWNvIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPD0xNjs8PTIiIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTE2LTIwXTs+MjQiIH4gIklub2N1byIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07XTUtMjRdIiB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdO10yLTVdIiB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdOzw9MiIgIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTs+MjQiIH4gIklub2N1byIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07XTUtMjRdIiB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjAtMjVdO10yLTVdIiB+ICJQcm9iYWJpbGlkYWQgZGUgbW9ydGFsaWRhZCIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07PD0yIiB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yNS0yOV07PjI0IiB+ICJQcm9iYWJpbGlkYWQgZGUgbW9ydGFsaWRhZCIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yNS0yOV07XTUtMjRdIiB+ICJQcm9iYWJpbGlkYWQgZGUgbW9ydGFsaWRhZCIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yNS0yOV07XTItNV0iIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTs8PTIiIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPjI5Oz4yNCJ+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIj4yOTs1LTI0XSJ+IkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPjI5O10yLTVdIn4iTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7PD0yIiB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2Oz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7XTUtMjRdIiB+ICJQcm9iYWJpbGlkYWQgZGUgbW9ydGFsaWRhZCIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2O10yLTVdIiB+ICJQcm9iYWJpbGlkYWQgZGUgbW9ydGFsaWRhZCIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2Ozw9MiIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdOz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTE2LTIwXTtdNS0yNF0iIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdO10yLTVdIiB+ICJTaW4gaW5mb3JtYWNpb24iLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTE2LTIwXTs8PTIiIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07PjI0IiB+ICJJbm9jdW8iLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjAtMjVdO101LTI0XSIgfiAiU2luIGluZm9ybWFjaW9uIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07XTItNV0iIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjAtMjVdOzw9MiIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTs+MjQiIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yNS0yOV07XTUtMjRdIiB+ICJTaW4gaW5mb3JtYWNpb24iLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTtdMi01XSIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTs8PTIiIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAmIENhdGVnb3JpYV90b3RhbCA9PSAiPjI5Oz4yNCIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPjI5OzUtMjRdIiB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7XTItNV0iIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIj4yOTs8PTIiIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49MTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2Oz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uID49MTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdOz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uID49MTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjAtMjVdOz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIFRSVUUgfiAiU2luIGluZm9ybWFjaW9uIg0KICAgICkNCiAgKQ0KDQojIE9yZGVuYXIgZWwgZGF0YWZyYW1lIHBvciBmZWNoYSBkZSBpbmljaW8NCmRmX2NvbnNvbGlkYWRvIDwtIGRmX2NvbnNvbGlkYWRvICU+JSBhcnJhbmdlKGZlY2hhX2luaWNpbykNCg0KIyBDb252ZXJ0aXIgbGFzIGNvbHVtbmFzIGRlIGZlY2hhIGEgUE9TSVhjdCBzaSBubyBsbyBlc3TDoW4NCmRmX2NvbnNvbGlkYWRvJGZlY2hhX2luaWNpbyA8LSBhcy5QT1NJWGN0KGRmX2NvbnNvbGlkYWRvJGZlY2hhX2luaWNpbywgdHo9IlVUQyIpDQpkZl9jb25zb2xpZGFkbyRmZWNoYV9maW4gPC0gYXMuUE9TSVhjdChkZl9jb25zb2xpZGFkbyRmZWNoYV9maW4sIHR6PSJVVEMiKQ0KDQojRnVuY2nDs24gcGFyYSBjYWxjdWxhciBlbCBwdW50byBtZWRpbyBkZSB1biBpbnRlcnZhbG8gZGUgZmVjaGFzDQppbnRlcnZhbF9taWRwb2ludCA8LSBmdW5jdGlvbihzdGFydCwgZW5kKSB7DQogIHJldHVybihzdGFydCArIChlbmQgLSBzdGFydCkgLyAyKQ0KfQ0KDQojIEFncmVnYXIgbGEgY29sdW1uYSBIb3JhX0xpbWEgYSBkZl9hZ3J1cGFkbyB1c2FuZG8gaW50ZXJ2YWxfbWlkcG9pbnQNCmRmX2NvbnNvbGlkYWRvIDwtIGRmX2NvbnNvbGlkYWRvICU+JQ0KICBtdXRhdGUoSG9yYV9MaW1hID0gaW50ZXJ2YWxfbWlkcG9pbnQoZmVjaGFfaW5pY2lvLCBmZWNoYV9maW4pKQ0KDQojIERlZmluaXIgbG9zIGNvbG9yZXMgZGUgbGFzIGNhdGVnb3LDrWFzDQpjb2xvcmVzX2NhdGVnb3JpYXMgPC0gYygiTGV0YWwiID0gIiM4MDAwMDAiLCAgIyBSb2pvIG9zY3Vybw0KICAgICAgICAgICAgICAgICAgICAgICAgIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiA9ICJyZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIkVzdHJlcyBmaXNpb2xvZ2ljbyIgPSAib3JhbmdlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJJbm9jdW8iID0gImdyZWVuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJTaW4gaW5mb3JtYWNpb24iID0gImdyZXkiKQ0KDQoNCmdncGxvdCgpICsNCiAgIyBDYXBhIDE6IGZvbmRvIGNvbiByZWN0w6FuZ3Vsb3MgZGUgZGZfY29uc29saWRhZG8NCiAgZ2VvbV9yZWN0KA0KICAgIGRhdGEgPSBkZl9jb25zb2xpZGFkbywNCiAgICBhZXMoDQogICAgICB4bWluID0gYXMuUE9TSVhjdChmZWNoYV9pbmljaW8sIHR6ID0gIlVUQyIpLA0KICAgICAgeG1heCA9IGFzLlBPU0lYY3QoZmVjaGFfZmluLCB0eiA9ICJVVEMiKSwNCiAgICAgIHltaW4gPSAtSW5mLA0KICAgICAgeW1heCA9IEluZiwNCiAgICAgIGZpbGwgPSBJbmRpY2UNCiAgICApLA0KICAgIGFscGhhID0gMC44LA0KICAgIGNvbG9yID0gTkENCiAgKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yZXNfY2F0ZWdvcmlhcykgKw0KICANCiAgIyBDYXBhIDI6IGzDrW5lYXMgZGUgYmFycmFuY29zXzIwMTUgY29uIGFncnVwYWNpw7NuDQogIGdlb21fbGluZSgNCiAgICBkYXRhID0gYmFycmFuY29zXzIwMTUsDQogICAgYWVzKHggPSBIb3JhX0xpbWEsIHkgPSBET19zYXQsIGdyb3VwID0gZ3JvdXApLA0KICAgIGNvbG9yID0gImJsYWNrIg0KICApICsNCiAgDQogICMgQ2FwYSAzOiBwdW50byBjcsOtdGljbyBkZSBveMOtZ2Vubw0KICBnZW9tX3RleHQoDQogICAgZGF0YSA9IGRhdGEuZnJhbWUoDQogICAgICB4ID0gYXMuUE9TSVhjdCgiMjAxNS0wMS0xNSIsIHR6ID0gIlVUQyIpLA0KICAgICAgeSA9IDI3LA0KICAgICAgbGFiZWwgPSAiUHVudG8gY3LDrXRpY28gZGUgb3jDrWdlbm8iDQogICAgKSwNCiAgICBhZXMoeCA9IHgsIHkgPSB5LCBsYWJlbCA9IGxhYmVsKSwNCiAgICBjb2xvciA9ICJyZWQiLA0KICAgIHNpemUgPSAzLjUNCiAgKSArDQogIA0KICAjIENhcGEgNDogbMOtbmVhIGhvcml6b250YWwgY3LDrXRpY2ENCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMjQsIGNvbG9yID0gInJlZCIpICsNCiAgDQogICMgVGVtYSB5IHBlcnNvbmFsaXphY2nDs24NCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgc2NhbGVfeF9kYXRldGltZShicmVha3MgPSAiMSB3ZWVrIiwgZGF0ZV9sYWJlbHMgPSAiJWQvJWIiKSArDQogIGxhYnMoeCA9ICIiLCB5ID0gIlNhdHVyYWNpw7NuIGRlIG94w61nZW5vICglKSIsIHRpdGxlID0gIk1vcnRhbGlkYWQgMjAxNSAtIEJhcnJhbmNvcyIpICsNCiAgdGhlbWUoDQogICAgdGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG9yID0gImJsYWNrIiksDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBjb2xvciA9ICJibGFjayIpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLA0KICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgYXhpcy50aWNrcy5sZW5ndGggPSB1bml0KDUsICJwdCIpLCAjIExvbmdpdHVkIGRlIGxvcyB0aWNrcw0KICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLCAjIENvbG9yIGRlIGxvcyB0aWNrcyBYDQogICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiksICAjIENvbG9yIGRlIGxvcyB0aWNrcyBZDQogICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC41KSwgIyBMw61uZWEgaG9yaXpvbnRhbCBkZWwgZWplDQogICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC41KSAgIyBMw61uZWEgdmVydGljYWwgZGVsIGVqZQ0KICApICsNCiAgDQogICMgQW5vdGFjaW9uZXMgYWRpY2lvbmFsZXMNCiAgYW5ub3RhdGUoDQogICAgInJlY3QiLA0KICAgIHhtaW4gPSBhcy5QT1NJWGN0KCIyMDE1LTAzLTAyIiwgdHogPSAiVVRDIiksDQogICAgeG1heCA9IGFzLlBPU0lYY3QoIjIwMTUtMDMtMTUiLCB0eiA9ICJVVEMiKSwNCiAgICB5bWluID0gLUluZiwNCiAgICB5bWF4ID0gSW5mLA0KICAgIGFscGhhID0gMCwNCiAgICBjb2xvciA9ICIjNjM2MzYzIiwNCiAgICBzaXplID0gMC43LA0KICAgIGxpbmV0eXBlID0gImRhc2hlZCINCiAgKSArDQogIGdlb21fdGV4dCgNCiAgICBkYXRhID0gZGF0YS5mcmFtZSgNCiAgICAgIHggPSBhcy5QT1NJWGN0KCIyMDE1LTAzLTA5IiwgdHogPSAiVVRDIiksDQogICAgICB5ID0gOTgsDQogICAgICBsYWJlbCA9ICJNb3J0YWxpZGFkIg0KICAgICksDQogICAgYWVzKHggPSB4LCB5ID0geSwgbGFiZWwgPSBsYWJlbCksDQogICAgY29sb3IgPSAiIzYzNjM2MyIsDQogICAgc2l6ZSA9IDQNCiAgKQ0KDQpgYGANCg0KKipDT05TVEFOVEUgTU9SVEFMSURBRCAyMDE5KioNCg0KYGBge3IsIGVjaG89VFJVRSxmaWcud2lkdGg9OCwgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQoNCiMgQWhvcmEgYXNpZ25hbW9zIGxhIGNhdGVnb3JpYSBkZSBUZW1wX2ZvbmQgeSBET19zYXQNCmRmX2luZGljZSA8LSBjb25zdGFudGVfMjAxOQ0KDQpkZl9pbmRpY2UgPC0gZGZfaW5kaWNlICU+JQ0KICBtdXRhdGUoDQogICAgQ2F0ZWdvcmlhX1QgPSBjYXNlX3doZW4oDQogICAgICBUZW1wX2ZvbmQgPD0gMTYgfiAiPD0xNiIsDQogICAgICBUZW1wX2ZvbmQgPiAxNiAmIFRlbXBfZm9uZCA8PSAyMCB+ICJdMTYtMjBdIiwNCiAgICAgIFRlbXBfZm9uZCA+IDIwICYgVGVtcF9mb25kIDw9IDI1IH4gIl0yMC0yNV0iLA0KICAgICAgVGVtcF9mb25kID4gMjUgJiBUZW1wX2ZvbmQgPD0gMjkgfiAiXTI1LTI5XSIsDQogICAgICBUZW1wX2ZvbmQgPiAyOSB+ICI+MjkiDQogICAgKSwNCiAgICBDYXRlZ29yaWFfRE8gPSBjYXNlX3doZW4oDQogICAgICBET19zYXQgPD0gMiB+ICI8PTIiLA0KICAgICAgRE9fc2F0ID4gMiAmIERPX3NhdCA8PSA1IH4gIl0yLTVdIiwNCiAgICAgIERPX3NhdCA+IDUgJiBET19zYXQgPD0gMjQuNCB+ICJdNS0yNF0iLA0KICAgICAgRE9fc2F0ID4gMjQuNCB+ICI+MjQiDQogICAgKSwNCiAgICBDYXRlZ29yaWFfdG90YWwgPSBwYXN0ZShDYXRlZ29yaWFfVCwgQ2F0ZWdvcmlhX0RPLCBzZXAgPSAiOyIpDQogICkNCg0KIyBJZGVudGlmaWNhciBsb3MgY2FtYmlvcyBlbiBsYXMgY2F0ZWdvcsOtYXMgZGUgQ2F0ZWdvcmlhX3RvdGFsIGRlbnRybyBkZSBjYWRhIGdyb3VwIA0KZGZfaW5kaWNlIDwtIGRmX2luZGljZSAlPiUNCiAgZ3JvdXBfYnkoZ3JvdXApICU+JQ0KICBtdXRhdGUoY2hhbmdlID0gQ2F0ZWdvcmlhX3RvdGFsICE9IGxhZyhDYXRlZ29yaWFfdG90YWwsIGRlZmF1bHQgPSBmaXJzdChDYXRlZ29yaWFfdG90YWwpKSkgJT4lDQogIG11dGF0ZShncm91cF9pZCA9IGN1bXN1bShjaGFuZ2UpKSAlPiUNCiAgdW5ncm91cCAoKQ0KDQojIENhbGN1bGFyIGxhIGZlY2hhIGRlIGluaWNpbyB5IGZpbiBkZSBjYWRhIGdydXBvIGRlIGNhdGVnb3LDrWFzIGNvbnRpbnVhcw0KZGZfYWdydXBhZG8gPC0gZGZfaW5kaWNlICU+JQ0KICBncm91cF9ieSgNCiAgICBncm91cCwNCiAgICBncm91cF9pZCkgJT4lDQogIHN1bW1hcml6ZSgNCiAgICBmZWNoYV9pbmljaW8gPSBtaW4oSG9yYV9MaW1hKSwNCiAgICBmZWNoYV9maW4gPSBtYXgoSG9yYV9MaW1hKSwNCiAgICBkdXJhY2lvbiA9IGFzLm51bWVyaWMoZGlmZnRpbWUobWF4KEhvcmFfTGltYSksIG1pbihIb3JhX0xpbWEpLCB1bml0cyA9ICJob3VycyIpKSsxLA0KICAgIENhdGVnb3JpYV90b3RhbCA9IGZpcnN0KENhdGVnb3JpYV90b3RhbCksDQogICAgQ2F0ZWdvcmlhX0RPID0gZmlyc3QgKENhdGVnb3JpYV9ETykpDQoNCiMgQWdyZWdhciBjb2x1bW5hIEhpcG94aWNvIGNvbiB2YWxvcmVzIEhpcG94aWEgbyBOb3Jtb3hpYQ0KZGZfYWdydXBhZG8gPC0gZGZfYWdydXBhZG8gJT4lDQogbXV0YXRlKEhpcG94aWEgPSBpZmVsc2UoQ2F0ZWdvcmlhX0RPICVpbiUgYygiPD0yIiwgIl0yLTVdIiwiXTUtMjRdIiksICJIaXBveGlhIiwgIk5vcm1veGlhIikpICMlPiUNCiAgI3VuZ3JvdXAoKSAjJT4lICMgRWxpbWluYXIgYWdydXBhY2lvbmVzIGFjdGl2YXMNCiAgI3NlbGVjdCgtZ3JvdXApDQoNCiMgQ3JlYXIgdW5hIGNvcGlhIGRlbCBkYXRhZnJhbWUgb3JpZ2luYWwNCmRmX3Jlc3VsdGFkbyA8LSBkZl9hZ3J1cGFkbw0KDQojIElkZW50aWZpY2FyIHBlcmlvZG9zIG1lbm9yZXMgYSA2IGhvcmFzDQpkZl9yZXN1bHRhZG8gPC0gZGZfcmVzdWx0YWRvICU+JQ0KICBtdXRhdGUoaXNfc2hvcnQgPSBkdXJhY2lvbiA8IDYpDQoNCiMgUHJvY2VzYXIgbG9zIGJsb3F1ZXMNCnByb2Nlc2FyX2Jsb3F1ZXMgPC0gZnVuY3Rpb24oZGYpIHsNCiAgYmxvcXVlX2lkIDwtIDENCiAgZGYgPC0gZGYgJT4lDQogICAgbXV0YXRlKGJsb3F1ZSA9IDApICAjIEluaWNpYWxpemFtb3MgY29uIDAgcGFyYSBsb3MgYmxvcXVlcw0KICANCiAgZm9yIChpIGluIDE6bnJvdyhkZikpIHsNCiAgICBpZiAoaSA9PSAxKSB7DQogICAgICAjIEFzaWduYXIgZWwgcHJpbWVyIGJsb3F1ZQ0KICAgICAgZGYkYmxvcXVlW2ldIDwtIGJsb3F1ZV9pZA0KICAgIH0gZWxzZSBpZiAoZGYkZ3JvdXBbaV0gIT0gZGYkZ3JvdXBbaSAtIDFdKSB7DQogICAgICAjIFNpIGNhbWJpYSBlbCBncnVwbywgY3JlYXIgdW4gbnVldm8gYmxvcXVlDQogICAgICBibG9xdWVfaWQgPC0gYmxvcXVlX2lkICsgMQ0KICAgICAgZGYkYmxvcXVlW2ldIDwtIGJsb3F1ZV9pZA0KICAgIH0gZWxzZSBpZiAoZGYkaXNfc2hvcnRbaSAtIDFdICYmIGRmJGlzX3Nob3J0W2ldKSB7DQogICAgICAjIFNpIGVsIHBlcmlvZG8gYWN0dWFsIHkgZWwgYW50ZXJpb3Igc29uIGNvcnRvcywgcGVydGVuZWNlbiBhbCBtaXNtbyBibG9xdWUNCiAgICAgIGRmJGJsb3F1ZVtpXSA8LSBibG9xdWVfaWQNCiAgICB9IGVsc2UgaWYgKGRmJGlzX3Nob3J0W2kgLSAxXSAmJiAhZGYkaXNfc2hvcnRbaV0pIHsNCiAgICAgICMgU2kgZWwgcGVyaW9kbyBhbnRlcmlvciBlcmEgY29ydG8gcGVybyBlc3RlIG5vLCB2ZXJpZmljYW1vcyBsYSBkdXJhY2nDs24gYWN1bXVsYWRhDQogICAgICBibG9xdWVfZHVyYWNpb24gPC0gc3VtKGRmJGR1cmFjaW9uW2RmJGJsb3F1ZSA9PSBibG9xdWVfaWRdKQ0KICAgICAgaWYgKGJsb3F1ZV9kdXJhY2lvbiA8IDYpIHsNCiAgICAgICAgIyBWw61hIEI6IElnbm9yYXIgbGEgaW50ZXJydXBjacOzbiB5IGV4dGVuZGVyIGVsIGJsb3F1ZSBhbCBzaWd1aWVudGUNCiAgICAgICAgZGYkYmxvcXVlW2ldIDwtIGJsb3F1ZV9pZA0KICAgICAgfSBlbHNlIHsNCiAgICAgICAgIyBWw61hIEE6IENyZWFyIHVuIG51ZXZvIGJsb3F1ZQ0KICAgICAgICBibG9xdWVfaWQgPC0gYmxvcXVlX2lkICsgMQ0KICAgICAgICBkZiRibG9xdWVbaV0gPC0gYmxvcXVlX2lkDQogICAgICB9DQogICAgfSBlbHNlIHsNCiAgICAgICMgQ3JlYXIgdW4gbnVldm8gYmxvcXVlDQogICAgICBibG9xdWVfaWQgPC0gYmxvcXVlX2lkICsgMQ0KICAgICAgZGYkYmxvcXVlW2ldIDwtIGJsb3F1ZV9pZA0KICAgIH0NCiAgfQ0KICANCiAgcmV0dXJuKGRmKQ0KfQ0KDQpkZl9yZXN1bHRhZG8gPC0gcHJvY2VzYXJfYmxvcXVlcyhkZl9yZXN1bHRhZG8pDQoNCiMgQ2FsY3VsYXIgcmVzdWx0YWRvcyBmaW5hbGVzIHBvciBibG9xdWUNCmRmX2ZpbmFsIDwtIGRmX3Jlc3VsdGFkbyAlPiUNCiAgZ3JvdXBfYnkoYmxvcXVlLCBncm91cCkgJT4lDQogIHN1bW1hcml6ZSgNCiAgICBmZWNoYV9pbmljaW8gPSBtaW4oZmVjaGFfaW5pY2lvKSwNCiAgICBmZWNoYV9maW4gPSBtYXgoZmVjaGFfZmluKSwNCiAgICBkdXJhY2lvbl90b3RhbCA9IHN1bShkdXJhY2lvbiksDQogICAgQ2F0ZWdvcmlhX3RvdGFsID0gQ2F0ZWdvcmlhX3RvdGFsW3doaWNoLm1heChkdXJhY2lvbildLA0KICAgIENhdGVnb3JpYV9ETyA9IENhdGVnb3JpYV9ET1t3aGljaC5tYXgoZHVyYWNpb24pXQ0KICApICU+JQ0KICB1bmdyb3VwKCkNCg0KIyBBZ3J1cGFyIHBvciBibG9xdWVzIGNvbnNlY3V0aXZvcyBjb24gZWwgbWlzbW8gQ2F0ZWdvcmlhX3RvdGFsDQpkZl9jb25zb2xpZGFkbyA8LSBkZl9maW5hbCAlPiUNCiAgbXV0YXRlKA0KICAgIGdydXBvX2NhdGVnb3JpYSA9IGN1bXN1bShDYXRlZ29yaWFfdG90YWwgIT0gbGFnKENhdGVnb3JpYV90b3RhbCwgZGVmYXVsdCA9IGZpcnN0KENhdGVnb3JpYV90b3RhbCkpKQ0KICApICU+JQ0KICBncm91cF9ieShncnVwb19jYXRlZ29yaWEsZ3JvdXApICU+JQ0KICBzdW1tYXJpemUoDQogICAgZmVjaGFfaW5pY2lvID0gbWluKGZlY2hhX2luaWNpbyksDQogICAgZmVjaGFfZmluID0gbWF4KGZlY2hhX2ZpbiksDQogICAgZHVyYWNpb24gPSBzdW0oZHVyYWNpb25fdG90YWwpLA0KICAgIENhdGVnb3JpYV90b3RhbCA9IGZpcnN0KENhdGVnb3JpYV90b3RhbCksDQogICAgQ2F0ZWdvcmlhX0RPID0gZmlyc3QoQ2F0ZWdvcmlhX0RPKSAjIENvbnNpZGVyYW1vcyBsYSBtaXNtYSBsw7NnaWNhIHBhcmEgQ2F0ZWdvcmlhX0RPDQogICkgJT4lDQogIHVuZ3JvdXAoKQ0KDQoNCiMgQXNpZ25hciBsYXMgY2F0ZWdvcmlhcw0KZGZfY29uc29saWRhZG8gPC0gZGZfY29uc29saWRhZG8gJT4lDQogIG11dGF0ZSgNCiAgICBJbmRpY2UgPSBjYXNlX3doZW4oDQogICAgICBkdXJhY2lvbiA8IDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2Oz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uIDwgMTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7XTUtMjRdIiB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb248MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7XTItNV0ifiAiRXN0cmVzIGZpc2lvbG9naWNvIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09Ijw9MTY7PD0yIiB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb248MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07PjI0IiB+ICJJbm9jdW8iLA0KICAgICAgZHVyYWNpb248MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07XTUtMjRdIiB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb248MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0iXTE2LTIwXTtdMi01XSIgfiAiU2luIGluZm9ybWFjaW9uIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdOzw9MiIgfiAiU2luIGluZm9ybWFjaW9uIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjAtMjVdOz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uIDwxMiAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTtdNS0yNF0ifiJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb248MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07XTItNV0iIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbjwxMiAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTs8PTIiIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICIyNS0yOV07PjI0IiB+ICJTaW4gaW5mb3JtYWNpb24iLA0KICAgICAgZHVyYWNpb24gPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjUtMjldO101LTI0XSJ+IlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbjwxMiAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTtdMi01XSIgfiAiU2luIGluZm9ybWFjaW9uIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjUtMjldOzw9MiIgfiAiUHJvYmFiaWxpZGFkIGRlIG1vcnRhbGlkYWQiLA0KICAgICAgZHVyYWNpb248MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIj4yOTs+MjQiIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uIDwxMiAmIENhdGVnb3JpYV90b3RhbCA9PSAiPjI5OzUtMjRdIn4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uPDEyICYgQ2F0ZWdvcmlhX3RvdGFsPT0gIj4yOTtdMi01XSIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb248MTIgJiBDYXRlZ29yaWFfdG90YWwgPT0gIj4yOTs8PTIiIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPD0xNjs+MjQiIH4gIklub2N1byIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7XTUtMjRdIiB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICAmIENhdGVnb3JpYV90b3RhbCA9PSAiPD0xNjtdMi01XSIgIH4gIkVzdHJlcyBmaXNpb2xvZ2ljbyIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2Ozw9MiIgIH4gIkVzdHJlcyBmaXNpb2xvZ2ljbyIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07PjI0IiB+ICJJbm9jdW8iLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTE2LTIwXTtdNS0yNF0iICB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdO10yLTVdIiAgfiAiU2luIGluZm9ybWFjaW9uIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTE2LTIwXTs8PTIiICB+ICJQcm9iYWJpbGlkYWQgZGUgbW9ydGFsaWRhZCIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07PjI0IiAgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTtdNS0yNF0iICB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjAtMjVdO10yLTVdIiAgfiAiU2luIGluZm9ybWFjaW9uIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTs8PTIiICB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yNS0yOV07PjI0IiAgIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJkNhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTtdNS0yNF0iICB+ICJTaW4gaW5mb3JtYWNpb24iLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjUtMjldO10yLTVdIiAgIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yNS0yOV07PD0yIiAgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7PjI0IiAgfiAiUHJvYmFiaWxpZGFkIGRlIG1vcnRhbGlkYWQiLA0KICAgICAgZHVyYWNpb24gPj0gMTIgJiBkdXJhY2lvbiA8IDI0ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7NS0yNF0iICB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSAxMiAmIGR1cmFjaW9uIDwgMjQgJiBDYXRlZ29yaWFfdG90YWwgPT0gIj4yOTtdMi01XSIgIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDEyICYgZHVyYWNpb24gPCAyNCAmIENhdGVnb3JpYV90b3RhbCAgPT0gIj4yOTs8PTIiICB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7PjI0IiAgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPD0xNjtdNS0yNF0iIH4gIkVzdHJlcyBmaXNpb2xvZ2ljbyIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7XTItNV0iICB+ICJFc3RyZXMgZmlzaW9sb2dpY28iLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI8PTE2Ozw9MiIgfiAiUHJvYmFiaWxpZGFkIGRlIG1vcnRhbGlkYWQiLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdOz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTE2LTIwXTtdNS0yNF0iIH4gIkVzdHJlcyBmaXNpb2xvZ2ljbyIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07XTItNV0iIH4gIkVzdHJlcyBmaXNpb2xvZ2ljbyIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07PD0yIiAgfiAiUHJvYmFiaWxpZGFkIGRlIG1vcnRhbGlkYWQiLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjAtMjVdOz4yNCIgfiAiSW5vY3VvIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTtdNS0yNF0iIH4gIkVzdHJlcyBmaXNpb2xvZ2ljbyIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07XTItNV0iIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTs8PTIiIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTs+MjQiIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTtdNS0yNF0iIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTtdMi01XSIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjUtMjldOzw9MiIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7PjI0In4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDI0ICYgZHVyYWNpb24gPCA0OCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPjI5OzUtMjRdIn4iTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gMjQgJiBkdXJhY2lvbiA8IDQ4ICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7XTItNV0ifiJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSAyNCAmIGR1cmFjaW9uIDwgNDggJiBDYXRlZ29yaWFfdG90YWwgPT0gIj4yOTs8PTIiIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7PjI0IiB+ICJJbm9jdW8iLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPD0xNjtdNS0yNF0iIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7XTItNV0iIH4gIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7PD0yIiB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07PjI0IiB+ICJJbm9jdW8iLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdO101LTI0XSIgfiAiU2luIGluZm9ybWFjaW9uIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07XTItNV0iIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMTYtMjBdOzw9MiIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTs+MjQiIH4gIklub2N1byIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07XTUtMjRdIiB+ICJTaW4gaW5mb3JtYWNpb24iLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTIwLTI1XTtdMi01XSIgfiAiU2luIGluZm9ybWFjaW9uIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07PD0yIiB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjUtMjldOz4yNCIgfiAiUHJvYmFiaWxpZGFkIGRlIG1vcnRhbGlkYWQiLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCAmIENhdGVnb3JpYV90b3RhbCA9PSAiXTI1LTI5XTtdNS0yNF0iIH4gIlNpbiBpbmZvcm1hY2lvbiIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjUtMjldO10yLTVdIiB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICJdMjUtMjldOzw9MiIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7PjI0IiB+ICJMZXRhbCIsDQogICAgICBkdXJhY2lvbiA+PSA0OCAmIGR1cmFjaW9uIDwgMTIwICYgQ2F0ZWdvcmlhX3RvdGFsID09ICI+Mjk7NS0yNF0iIH4gIkxldGFsIiwNCiAgICAgIGR1cmFjaW9uID49IDQ4ICYgZHVyYWNpb24gPCAxMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIj4yOTtdMi01XSIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0gNDggJiBkdXJhY2lvbiA8IDEyMCAmIENhdGVnb3JpYV90b3RhbCA9PSAiPjI5Ozw9MiIgfiAiTGV0YWwiLA0KICAgICAgZHVyYWNpb24gPj0xMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIjw9MTY7PjI0IiB+ICJJbm9jdW8iLA0KICAgICAgZHVyYWNpb24gPj0xMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0xNi0yMF07PjI0IiB+ICJJbm9jdW8iLA0KICAgICAgZHVyYWNpb24gPj0xMjAgJiBDYXRlZ29yaWFfdG90YWwgPT0gIl0yMC0yNV07PjI0IiB+ICJJbm9jdW8iLA0KICAgICAgVFJVRSB+ICJTaW4gaW5mb3JtYWNpb24iDQogICAgKQ0KICApDQoNCiMgT3JkZW5hciBlbCBkYXRhZnJhbWUgcG9yIGZlY2hhIGRlIGluaWNpbw0KZGZfY29uc29saWRhZG8gPC0gZGZfY29uc29saWRhZG8gJT4lIGFycmFuZ2UoZmVjaGFfaW5pY2lvKQ0KDQojIENvbnZlcnRpciBsYXMgY29sdW1uYXMgZGUgZmVjaGEgYSBQT1NJWGN0IHNpIG5vIGxvIGVzdMOhbg0KZGZfY29uc29saWRhZG8kZmVjaGFfaW5pY2lvIDwtIGFzLlBPU0lYY3QoZGZfY29uc29saWRhZG8kZmVjaGFfaW5pY2lvLCB0ej0iVVRDIikNCmRmX2NvbnNvbGlkYWRvJGZlY2hhX2ZpbiA8LSBhcy5QT1NJWGN0KGRmX2NvbnNvbGlkYWRvJGZlY2hhX2ZpbiwgdHo9IlVUQyIpDQoNCiNGdW5jacOzbiBwYXJhIGNhbGN1bGFyIGVsIHB1bnRvIG1lZGlvIGRlIHVuIGludGVydmFsbyBkZSBmZWNoYXMNCmludGVydmFsX21pZHBvaW50IDwtIGZ1bmN0aW9uKHN0YXJ0LCBlbmQpIHsNCiAgcmV0dXJuKHN0YXJ0ICsgKGVuZCAtIHN0YXJ0KSAvIDIpDQp9DQoNCiMgQWdyZWdhciBsYSBjb2x1bW5hIEhvcmFfTGltYSBhIGRmX2FncnVwYWRvIHVzYW5kbyBpbnRlcnZhbF9taWRwb2ludA0KZGZfY29uc29saWRhZG8gPC0gZGZfY29uc29saWRhZG8gJT4lDQogIG11dGF0ZShIb3JhX0xpbWEgPSBpbnRlcnZhbF9taWRwb2ludChmZWNoYV9pbmljaW8sIGZlY2hhX2ZpbikpDQoNCiMgRGVmaW5pciBsb3MgY29sb3JlcyBkZSBsYXMgY2F0ZWdvcsOtYXMNCmNvbG9yZXNfY2F0ZWdvcmlhcyA8LSBjKCJMZXRhbCIgPSAiIzgwMDAwMCIsICAjIFJvam8gb3NjdXJvDQogICAgICAgICAgICAgICAgICAgICAgICAiUHJvYmFiaWxpZGFkIGRlIG1vcnRhbGlkYWQiID0gInJlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAiRXN0cmVzIGZpc2lvbG9naWNvIiA9ICJvcmFuZ2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIklub2N1byIgPSAiZ3JlZW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgIlNpbiBpbmZvcm1hY2lvbiIgPSAiZ3JleSIpDQoNCmRmX2NvbnNvbGlkYWRvIDwtIGRmX2NvbnNvbGlkYWRvICU+JQ0KICBtdXRhdGUoZmVjaGFfZmluID0gZmVjaGFfZmluIC0gbWljcm9zZWNvbmRzKDEpKSAgIyBSZXN0YW1vcyAxIHNlZ3VuZG8gcGFyYSBxdWUgZmVjaGFfZmluIHNlYSBpbmNsdXNpdmENCg0KZ2dwbG90KCkgKw0KICAjIENhcGEgMTogZm9uZG8gY29uIHJlY3TDoW5ndWxvcyBkZSBkZl9jb25zb2xpZGFkbw0KICBnZW9tX3JlY3QoDQogICAgZGF0YSA9IGRmX2NvbnNvbGlkYWRvLA0KICAgIGFlcygNCiAgICAgIHhtaW4gPSBhcy5QT1NJWGN0KGZlY2hhX2luaWNpbywgdHogPSAiVVRDIiksDQogICAgICB4bWF4ID0gYXMuUE9TSVhjdChmZWNoYV9maW4sIHR6ID0gIlVUQyIpLA0KICAgICAgeW1pbiA9IC1JbmYsDQogICAgICB5bWF4ID0gSW5mLA0KICAgICAgZmlsbCA9IEluZGljZQ0KICAgICksDQogICAgYWxwaGEgPSAwLjgsDQogICAgY29sb3IgPSBOQQ0KICApICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3Jlc19jYXRlZ29yaWFzKSArDQogIA0KICAjIENhcGEgMjogbMOtbmVhcyBkZSBjb25zdG5hdGVfMjAxOSBjb24gYWdydXBhY2nDs24NCiAgZ2VvbV9saW5lKA0KICAgIGRhdGEgPSBjb25zdGFudGVfMjAxOSwNCiAgICBhZXMoeCA9IEhvcmFfTGltYSwgeSA9IERPX3NhdCwgZ3JvdXAgPSBncm91cCksDQogICAgY29sb3IgPSAiYmxhY2siDQogICkgKw0KICANCiAgIyBDYXBhIDM6IHB1bnRvIGNyw610aWNvIGRlIG94w61nZW5vDQogIGdlb21fdGV4dCgNCiAgICBkYXRhID0gZGF0YS5mcmFtZSgNCiAgICAgIHggPSBhcy5QT1NJWGN0KCIyMDE5LTAxLTE1IiwgdHogPSAiVVRDIiksDQogICAgICB5ID0gMjcsDQogICAgICBsYWJlbCA9ICJQdW50byBjcsOtdGljbyBkZSBveMOtZ2VubyINCiAgICApLA0KICAgIGFlcyh4ID0geCwgeSA9IHksIGxhYmVsID0gbGFiZWwpLA0KICAgIGNvbG9yID0gInJlZCIsDQogICAgc2l6ZSA9IDMuNQ0KICApICsNCiAgDQogICMgQ2FwYSA0OiBsw61uZWEgaG9yaXpvbnRhbCBjcsOtdGljYQ0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAyNCwgY29sb3IgPSAicmVkIikgKw0KICANCiAgIyBUZW1hIHkgcGVyc29uYWxpemFjacOzbg0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBzY2FsZV94X2RhdGV0aW1lKGJyZWFrcyA9ICIxIHdlZWsiLCBkYXRlX2xhYmVscyA9ICIlZC8lYiIpICsNCiAgbGFicyh4ID0gIiIsIHkgPSAiU2F0dXJhY2nDs24gZGUgb3jDrWdlbm8gKCUpIiwgdGl0bGUgPSAiTW9ydGFsaWRhZCAyMDE5IC0gQ29uc3RhbnRlIikgKw0KICB0aGVtZSgNCiAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3IgPSAiYmxhY2siKSwNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGNvbG9yID0gImJsYWNrIiksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwNCiAgICBheGlzLnRpY2tzLmxlbmd0aCA9IHVuaXQoNSwgInB0IiksICMgTG9uZ2l0dWQgZGUgbG9zIHRpY2tzDQogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiksICMgQ29sb3IgZGUgbG9zIHRpY2tzIFgNCiAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siKSwgICMgQ29sb3IgZGUgbG9zIHRpY2tzIFkNCiAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjUpLCAjIEzDrW5lYSBob3Jpem9udGFsIGRlbCBlamUNCiAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjUpICAjIEzDrW5lYSB2ZXJ0aWNhbCBkZWwgZWplDQogICkgKw0KICANCiAgIyBBbm90YWNpb25lcyBhZGljaW9uYWxlcw0KICBhbm5vdGF0ZSgNCiAgICAicmVjdCIsDQogICAgeG1pbiA9IGFzLlBPU0lYY3QoIjIwMTktMDMtMDQiLCB0eiA9ICJVVEMiKSwNCiAgICB4bWF4ID0gYXMuUE9TSVhjdCgiMjAxOS0wMy0xMyIsIHR6ID0gIlVUQyIpLA0KICAgIHltaW4gPSAtSW5mLA0KICAgIHltYXggPSBJbmYsDQogICAgYWxwaGEgPSAwLA0KICAgIGNvbG9yID0gIiM2MzYzNjMiLA0KICAgIHNpemUgPSAwLjcsDQogICAgbGluZXR5cGUgPSAiZGFzaGVkIg0KICApICsNCiAgZ2VvbV90ZXh0KA0KICAgIGRhdGEgPSBkYXRhLmZyYW1lKA0KICAgICAgeCA9IGFzLlBPU0lYY3QoIjIwMTktMDMtMTAiLCB0eiA9ICJVVEMiKSwNCiAgICAgIHkgPSA5OCwNCiAgICAgIGxhYmVsID0gIk1vcnRhbGlkYWQiDQogICAgKSwNCiAgICBhZXMoeCA9IHgsIHkgPSB5LCBsYWJlbCA9IGxhYmVsKSwNCiAgICBjb2xvciA9ICIjNjM2MzYzIiwNCiAgICBzaXplID0gNA0KICApDQpgYGANCg0KKipQdW50b3MgbmVnYXRpdm9zOioqIA0KDQoqIEFudGVzIGRlbCBwZXJpb2RvIGRlIE1vcnRhbGlkYWQsIG5vIHNhbGUgIlByb2JhYmlsaWRhZCBkZSBtb3J0YWxpZGFkIiwgcG9yIGxvIHF1ZSwgZW4gZXNlIGNhc28sIGVsIHNpc3RlbWEgZGUgYWxlcnRhIHRlbXByYW5hIG5vIGZ1bmNpb25hLiANCg0KKiBEdXJhbnRlIGxhIE1vcnRhbGlkYWQsIGVsIHBlcmlvZG8gZGUgbGV0YWxpZGFkIGVzIG11eSBjb3J0bywgbm8gYWJhcmNhIGVsIGV2ZW50byBlbnRlcm8uIA0KDQoqIFBvZHLDrWEgc2VyIHRvZG8gbGV0YWwsIHBlcm8gbGEgdG9tYSBkZSBkYXRvcyBkdXJhbnRlIGxhIG1vcnRhbGlkYWQgbm8gZnVlIGVzdHJpY3RhbWVudGUgdG9kYXMgbGFzIGhvcmFzLCBwb3IgZW5kZSwgbm8gY3VtcGxlIGNvbiBlbCBjcml0ZXJpbyBkZSBkdXJhY2lvbiA+NmguLi4gZGlmaWNpbCBkZSBjbGFzaWZpY2FyIGRlbnRybyBkZSBsYSBjYXRlZ29yaWEgTGV0YWwuIA0KDQo=