#Crear un vector de datos
datos <- c(100, 200, 300, 400, 500)
#Calcular el total y promedio
total <- sum(datos)
promedio <- mean(datos)
#Mostrar resultados
cat("Total:", total, "\n")
Total: 1500
cat("Promedio;", promedio, "\n")
Promedio; 300
Graficar los datos con ggplot2 library(ggplot2) df <- data.frame
(x = 1:5, y = datos) LO antes mencionado es una formula para crear una
data.frame donde en “X = 1:5” significa que estoy indicando que serán 1
columna y 5 filas respectivamente.
df <- data.frame (x = 1:5, y = datos)
df
Paleta de hex color para definir a traves de un codigo el color El
simbolo “+” añade una linea de codigo que en ggplot es como una
library("ggplot2")
ggplot(df, aes(x = x, y = y)) +
geom_bar(stat = "identity", fill = "#a346f0") +
scale_x_continuous(breaks = 1:5,
labels = c("Edad", "Peso", "C", "D", "E")) +
labs(title = "grafico de barras", x = "Índice", y = "Valores")

PARA RENOMBRAR EN ESCALA: scale_x_continuous(breaks = 1:5, labels =
c(“Edad”, “Peso”, “C”, “D”, “E”)) +
PARA RENOMBRAR COMO FACTOR: library(ggplot2)
library(ggplot2)
ggplot(df, aes(x = factor(x, labels = c(“A”, “B”, “C”, “D”, “E”)), y
= y)) + geom_bar(stat = “identity”, fill = “#fc03df”) + labs(title =
“Gráfico de barras”, x = “Índice”, y = “Valores”)
install.packages("gapminder")
library("gapminder")
#install.packages("tidyverse")
library("tidyverse")
gapdata2007 <- gapminder %>% filter(year == 2007)
gapdata2007$year
[1] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[10] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[19] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[28] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[37] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[46] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[55] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[64] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[73] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[82] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[91] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[100] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[109] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[118] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[127] 2007 2007 2007 2007 2007 2007 2007 2007 2007
[136] 2007 2007 2007 2007 2007 2007 2007
Escoger objetos geometricos geom_point() aes()
gapdata2007 %>%
ggplot(aes(x = gdpPercap, y = lifeExp, colour = continent)) +
geom_point(shape=8)

shape es para elegir como quieres la forma en la que se representan
los valores en la grafica 0 cuadrado 1 circulo 2 triangulo 4 x 8 * 15
cuadrado relleno 16 circulo relleno 17 triangulo relleno 21 circulo
relleno con contorno 22 cuadrado relleno con contorno 23 rombo relleno
con contorno
Se puede separar todo en varias graficas agregando una linea extra al
codigo
facet_wrap(continent)
gapdata2007 %>%
ggplot(aes(x = gdpPercap, y = lifeExp, colour = continent)) +
geom_point(shape=8) +
facet_wrap(~continent)

Elegir el fondo: default theme_bw theme_dark theme_classic
gapdata2007 %>%
ggplot(aes(x = gdpPercap, y = lifeExp, colour = continent)) +
geom_point(shape=8) +
facet_wrap(~continent) +
theme_bw()

¿Qué son las Estadísticas Vitales? Las estadísticas vitales son
métricas clave que permiten analizar el estado de salud de una
población. Entre las más comunes se encuentran:
- Tasa de natalidad: Número de nacimientos por cada 1,000
habitantes.
Tasa de mortalidad: Número de muertes por cada 1,000 habitantes.
Tasa de letalidad: Porcentaje de personas fallecidas entre las que
padecieron una enfermedad específica.
Crear un Dataset Ficticio Usaremos un conjunto de datos ficticio para
realizar los cálculos:
# Crear un conjunto de datos ficticio
datos <- data.frame(
region = c("Norte", "Sur", "Este", "Oeste"),
poblacion = c(100000, 75000, 50000, 60000),
nacimientos = c(1200, 800, 600, 700),
muertes = c(900, 500, 300, 400),
casos_enfermedad = c(1500, 1000, 800, 900),
fallecidos_enfermedad = c(200, 150, 100, 120)
)
# Mostrar los primeros datos
print(datos)
Tasa de Mortalidad ¿Qué es la Tasa de Mortalidad? La Tasa de
Mortalidad mide el número de muertes en una población por cada 1,000
habitantes durante un período determinado.
Es una métrica crucial para evaluar el impacto de factores que
afectan la salud pública.
Fórmula La fórmula general para calcular la Tasa de Mortalidad
es:
Numero de muertes / población total * 1000
Donde:
- Número de Muertes: Total de personas fallecidas en un año.
Población Total: Número total de habitantes en la población.
# Datos
muertes <- 900 # Número de muertes en un año
poblacion_total <- 100000 # Población total en ese año
# Cálculo de la tasa de mortalidad
tasa_mortalidad <- (muertes / poblacion_total) * 1000
# Resultado
cat("Tasa de mortalidad:", tasa_mortalidad, "muertes por cada 1,000 habitantes\n")
Tasa de mortalidad: 9 muertes por cada 1,000 habitantes
Visualización de Tasa de Mortalidad Usamos un gráfico de barras para
visualizar las tasas de mortalidad en diferentes regiones:
library(ggplot2)
str(datos)
'data.frame': 4 obs. of 6 variables:
$ region : chr "Norte" "Sur" "Este" "Oeste"
$ poblacion : num 100000 75000 50000 60000
$ nacimientos : num 1200 800 600 700
$ muertes : num 900 500 300 400
$ casos_enfermedad : num 1500 1000 800 900
$ fallecidos_enfermedad: num 200 150 100 120
print(datos)
library(ggplot2)
# Calcular tasas de mortalidad
datos$tasa_mortalidad <- (datos$muertes / datos$poblacion) * 1000
print(datos)
GRAFICOS:
# Gráfico
ggplot(datos, aes(x = region, y = tasa_mortalidad, fill = region)) +
geom_bar(stat = "identity") +
labs(title = "Tasa de Mortalidad por Región", x = "Región", y = "Tasa de Mortalidad (por 1,000 habitantes)") +
theme_classic()

Conclusión La Tasa de Mortalidad es un indicador fundamental para
medir el impacto de condiciones de salud y factores socioeconómicos en
una población.
Comparar tasas entre regiones puede ayudar a identificar áreas que
necesitan mayor atención.
Tasa de Letalidad ¿Qué es la Tasa de Letalidad? La Tasa de Letalidad
mide el porcentaje de personas fallecidas entre las que han padecido una
enfermedad específica.
Es una métrica crucial para evaluar la gravedad de una enfermedad y
la efectividad de las intervenciones médicas.
Fórmula La fórmula general para calcular la Tasa de Letalidad es:
Tasa de letalidad = numero de fallecidos / numero de casos * 100
=
Donde:
- Número de Fallecidos: Total de personas que han muerto debido a la
enfermedad. -
-Número de Casos: Total de personas diagnosticadas con la
enfermedad.
Implementación en R Calculemos la Tasa de Letalidad usando un ejemplo
práctico:
Datos_fallecidos <- 200 # Número de fallecidos por la enfermedad
casos <- 1500 # Número total de casos registrados
# Cálculo de la tasa de letalidad
tasa_letalidad <- (Datos_fallecidos / casos) * 100
# Resultado
cat("Tasa de letalidad:", tasa_letalidad, "% de los casos fallecen\n")
Tasa de letalidad: 13.33333 % de los casos fallecen
# Calcular tasas de letalidad
datos$tasa_letalidad <- (datos$fallecidos / datos$casos) * 100
# Gráfico
ggplot(datos, aes(x = region, y = tasa_letalidad, fill = region)) +
geom_bar(stat = "identity") +
labs(title = "Tasa de Letalidad por Región",
x = "Región", y = "Tasa de Letalidad (%)") +
theme_minimal()

Conclusión La Tasa de Letalidad es un indicador clave para evaluar la
severidad de una enfermedad y el impacto de las intervenciones médicas.
Un análisis detallado puede ayudar a identificar áreas prioritarias para
la asignación de recursos.
Tasa de Natalidad ¿Qué es la Tasa de Natalidad? La Tasa de Natalidad
mide el número de nacimientos en una población por cada 1,000 habitantes
durante un período determinado.
Es una métrica clave para analizar la dinámica poblacional y evaluar
tendencias demográficas.
Fórmula La fórmula general para calcular la Tasa de Natalidad es:
Tasa de natalidad = numero de nacimientos / total de la población *
1000 =
Implementación en R Calculemos la Tasa de Natalidad usando un ejemplo
práctico:
# Datos
nacimientos <- 1500 # Número de nacimientos en un año
poblacion_total <- 100000 # Población total en ese año
# Cálculo de la tasa de natalidad
tasa_natalidad <- (nacimientos / poblacion_total) * 1000
# Resultado
cat("Tasa de natalidad:", tasa_natalidad, "nacimientos por cada 1,000 habitantes\n")
Tasa de natalidad: 15 nacimientos por cada 1,000 habitantes
datos
# Calcular tasas de natalidad
datos$tasa_natalidad <- (datos$nacimientos / datos$poblacion) * 1000
# Gráfico
ggplot(datos, aes(x = region, y = tasa_natalidad, fill = region)) +
geom_bar(stat = "identity") +
labs(title = "Tasa de Natalidad por Región",
x = "Región", y = "Tasa de Natalidad (por 1,000 habitantes)") +
theme_minimal()

Conclusión La Tasa de Natalidad es una herramienta esencial en
epidemiología para entender la dinámica poblacional. Usarla en conjunto
con otras métricas puede proporcionar una visión completa de las
tendencias demográficas y necesidades de salud pública.
Ventajas de flextable: Interactividad: Permite crear tablas
fácilmente exportables a Word o PowerPoint.
Estilo Personalizable: Cambia colores, fuentes y bordes sin
complicaciones.
Soporte para Reportes: Ideal para informes en formatos
reproducibles.
Ambas opciones (kableExtra y flextable) son más simples y versátiles
que gtable para este caso de uso.
#install.packages("tidyverse")
library(tidyverse)
install.packages("flextable")
library(flextable)
# Crear el conjunto de datos
datos <- data.frame(
region = c("Norte", "Sur", "Este", "Oeste"),
poblacion = c(100000, 75000, 50000, 60000),
nacimientos = c(1200, 800, 600, 700),
muertes = c(900, 500, 300, 400),
casos_enfermedad = c(1500, 1000, 800, 900),
fallecidos_enfermedad = c(200, 150, 100, 120)
)
# Calcular las tasas
datos$tasa_natalidad <- (datos$nacimientos / datos$poblacion) * 1000
datos$tasa_mortalidad <- (datos$muertes / datos$poblacion) * 1000
datos$tasa_incidencia <- (datos$casos_enfermedad / datos$poblacion) * 1000
datos$tasa_letalidad <- (datos$fallecidos_enfermedad / datos$casos_enfermedad) * 100
# Redondear solo columnas numéricas
datos_redondeados <- datos %>%
mutate_if(is.numeric, round, 2)
# Crear la tabla con flextable
flextable(datos_redondeados) %>%
autofit()
region | poblacion | nacimientos | muertes | casos_enfermedad | fallecidos_enfermedad | tasa_natalidad | tasa_mortalidad | tasa_incidencia | tasa_letalidad |
|---|
Norte | 100,000 | 1,200 | 900 | 1,500 | 200 | 12.00 | 9.00 | 15.00 | 13.33 |
Sur | 75,000 | 800 | 500 | 1,000 | 150 | 10.67 | 6.67 | 13.33 | 15.00 |
Este | 50,000 | 600 | 300 | 800 | 100 | 12.00 | 6.00 | 16.00 | 12.50 |
Oeste | 60,000 | 700 | 400 | 900 | 120 | 11.67 | 6.67 | 15.00 | 13.33 |
Cálculo de Frecuencias
El análisis de frecuencias es una técnica básica pero esencial en
epidemiología. Permite describir cómo se distribuyen los datos en
categorías específicas y es especialmente útil para analizar variables
categóricas como sexo, grupo de edad, o estado de enfermedad.
Cargar Librerías Primero, cargamos las librerías necesarias para el
análisis:
library(dplyr)
# Para manipulación de datos %>% %>% %>% %>% %>% control + shift + m =
# %>% %>% %>% %>% %>% %>% %>%
library(ggplot2) # Para visualización de datos
library(tidyverse)
# control + alt + *+ = ~
#install.packages("janitor")
library(janitor) # Para generar tablas de frecuencias
Crear un Conjunto de Datos de Ejemplo Usaremos un dataset ficticio
para calcular las frecuencias:
# Crear un conjunto de datos ficticio
datos <- data.frame(
sexo = c("F", "M", "F", "F", "M", "F", "M", "M", "F", "M"),
grupo_edad = c("0-19", "20-39", "20-39", "40-59", "40-59", "60+", "20-39", "60+", "40-59", "0-19")
)
# Mostrar los primeros datos
head(datos)
str(datos)
'data.frame': 10 obs. of 2 variables:
$ sexo : chr "F" "M" "F" "F" ...
$ grupo_edad: chr "0-19" "20-39" "20-39" "40-59" ...
Tablas de Frecuencias Tabla de Frecuencias con table Podemos calcular
frecuencias simples usando table:
# Calcular frecuencias para la variable "sexo"
tabla_sexo <- table(datos$sexo)
tabla_sexo
F M
5 5
Tabla de Frecuencias Cruzadas con table Para analizar dos
variables:
# Tabla cruzada entre "sexo" y "grupo_edad"
tabla_cruzada <- table(datos$sexo, datos$grupo_edad)
tabla_cruzada
0-19 20-39 40-59 60+
F 1 1 2 1
M 1 2 1 1
Tablas Limpias con janitor El paquete janitor genera tablas de
frecuencias ordenadas:
#install.packages("janitor")
library(janitor)
# Tabla de frecuencias con proporciones
tabla_ordenada <- datos %>%
tabyl(sexo) %>%
adorn_totals("row") %>%
adorn_pct_formatting()
tabla_ordenada
sexo n percent
F 5 50.0%
M 5 50.0%
Total 10 100.0%
flextable(tabla_ordenada)
sexo | n | percent |
|---|
F | 5 | 50.0% |
M | 5 | 50.0% |
Total | 10 | 100.0% |
Paquete janitor ¿Qué es janitor? janitor es un paquete diseñado para
limpiar datos y realizar análisis exploratorios rápidos. Es
particularmente útil para manejar tablas y datos categóricos, como
calcular frecuencias y proporciones.
Características Principales de janitor: Limpieza de Nombres de
Columnas:
Convierte nombres de columnas en formato limpio y consistente,
eliminando espacios o caracteres especiales.
library(janitor)
datos2 <- data.frame("Nombre Columna 1" = c(1, 2), "Otra Columna" = c(3, 4))
datos_clean <- clean_names(datos2) #función clean_names
print(datos_clean) # nombres: nombre_columna_1, otra_columna
Tablas de Frecuencias:
Genera tablas de frecuencias simples y cruzadas.
Incluye totales y porcentajes para facilitar la interpretación.
library(janitor)
tabla <- datos %>% tabyl(grupo_edad)
print(tabla)
grupo_edad n percent
0-19 2 0.2
20-39 3 0.3
40-59 3 0.3
60+ 2 0.2
str(datos)
'data.frame': 10 obs. of 2 variables:
$ sexo : chr "F" "M" "F" "F" ...
$ grupo_edad: chr "0-19" "20-39" "20-39" "40-59" ...
Tablas de Frecuencias Tabla de Frecuencias con table Podemos calcular
frecuencias simples usando table:
# Calcular frecuencias para la variable "sexo"
tabla_sexo <- table(datos$sexo)
tabla_sexo
F M
5 5
Tabla de Frecuencias Cruzadas con table Para analizar dos
variables:
# Tabla cruzada entre "sexo" y "grupo_edad"
tabla_cruzada <- table(datos$sexo, datos$grupo_edad)
tabla_cruzada
0-19 20-39 40-59 60+
F 1 1 2 1
M 1 2 1 1
Tablas Limpias con janitor El paquete janitor genera tablas de
frecuencias ordenadas:
#install.packages("janitor")
library(janitor)
# Tabla de frecuencias con proporciones
tabla_ordenada <- datos %>%
tabyl(sexo) %>%
adorn_totals("row") %>%
adorn_pct_formatting()
tabla_ordenada
sexo n percent
F 5 50.0%
M 5 50.0%
Total 10 100.0%
library(flextable)
flextable(tabla_ordenada)
sexo | n | percent |
|---|
F | 5 | 50.0% |
M | 5 | 50.0% |
Total | 10 | 100.0% |
NA
Paquete janitor ¿Qué es janitor? janitor es un paquete diseñado para
limpiar datos y realizar análisis exploratorios rápidos. Es
particularmente útil para manejar tablas y datos categóricos, como
calcular frecuencias y proporciones.
Características Principales de janitor: Limpieza de Nombres de
Columnas:
Convierte nombres de columnas en formato limpio y consistente,
eliminando espacios o caracteres especiales.
library(janitor)
datos2 <- data.frame("Nombre Columna 1" = c(1, 2), "Otra Columna" = c(3, 4))
datos_clean <- clean_names(datos2) #función clean_names
print(datos_clean) # nombres: nombre_columna_1, otra_columna
Tablas de Frecuencias:
Genera tablas de frecuencias simples y cruzadas.
Incluye totales y porcentajes para facilitar la interpretación.
library(janitor)
tabla <- datos %>% tabyl(grupo_edad)
print(tabla)
grupo_edad n percent
0-19 2 0.2
20-39 3 0.3
40-59 3 0.3
60+ 2 0.2
Tablas Ordenadas y Proporciones:
Añade totales y porcentajes a tablas de manera automática.
grupoedad<-tabla %>% adorn_totals("row") %>% adorn_pct_formatting()
grupoedad
grupo_edad n percent
0-19 2 20.0%
20-39 3 30.0%
40-59 3 30.0%
60+ 2 20.0%
Total 10 100.0%
flextable(grupoedad)
grupo_edad | n | percent |
|---|
0-19 | 2 | 20.0% |
20-39 | 3 | 30.0% |
40-59 | 3 | 30.0% |
60+ | 2 | 20.0% |
Total | 10 | 100.0% |
Detección de Duplicados:
Identifica valores duplicados en tus datos.
datos3 <- data.frame(id = c(1, 1, 2, 3), valor = c(10, 10, 20, 30))
datos3
get_dupes(datos3, id)
¿Cuándo usar janitor? Cuando necesitas calcular frecuencias
rápidamente.
Para limpiar nombres de columnas automáticamente.
Al trabajar con datos categóricos donde las proporciones y totales
son importantes.
Visualización de Frecuencias Gráfico de Barras con ggplot2 Un gráfico
de barras es ideal para visualizar frecuencias categóricas:
# Crear un gráfico de barras para "grupo_edad"
ggplot(datos, aes(x = grupo_edad, fill = grupo_edad)) +
geom_bar() +
labs(title = "Frecuencia por Grupo de Edad",
x = "Grupo de Edad",
y = "Frecuencia") +
theme_minimal()

datos %>% ggplot(aes(grupo_edad, fill= grupo_edad))+
geom_bar()

Gráfico de Pastel con ggplot2 Un gráfico de pastel es útil para
mostrar proporciones:
# Calcular proporciones
proporciones <- datos %>%
group_by(sexo) %>%
summarise(frecuencia = n()) %>%
mutate(proporcion = frecuencia / sum(frecuencia))
# Crear un gráfico de pastel
ggplot(proporciones, aes(x = "", y = proporcion, fill = sexo)) +
geom_col(width = 1) +
coord_polar(theta = "y") +
theme_void()+
labs(title = "Distribución por Sexo")

sexo | n | percent |
|---|
F | 5 | 50.0% |
M | 5 | 50.0% |
Total | 10 | 100.0% |
Tablas y Gráficos en un Reporte Combinar Resultados en una Tabla
Resumen Podemos combinar frecuencias y proporciones en una tabla
clara:
# Tabla resumen de frecuencias y proporciones
tabla_resumen <- datos %>%
group_by(sexo) %>%
summarise(
frecuencia = n(),
proporcion = n() / nrow(datos)
)
tabla_resumen
Exportar Gráficos y Tablas Guardar gráficos y tablas para incluirlos
en reportes:
# Guardar el gráfico de barras como imagen
ggsave("frecuencia_grupo_edad.png")
Medidas de frecuencia Las medidas de frecuencia son herramientas
clave en epidemiología para cuantificar el impacto de enfermedades en
una población. Las principales métricas son:
Prevalencia: Proporción de individuos enfermos en un momento
concreto. Incidencia acumulada: Probabilidad de que un individuo enferme
durante un período. Densidad de incidencia: Velocidad con la que
aparecen nuevos casos en una población. Dataset Simulado Crear un
Dataset Ficticio Usamos un conjunto de datos simulado para calcular
estas métricas.
# Crear un conjunto de datos ficticio
datos <- data.frame(
id = 1:100, # Identificación de individuos
inicio_riesgo = c(rep(0, 80), rep(1, 20)), # 0 = no enfermo al inicio 1= enfermo
casos_nuevos = c(rep(0, 90), rep(1, 10)), # Casos nuevos al final del período
tiempo_observacion = c(rep(1, 50), rep(2, 30), rep(3, 20)) # Tiempo observado en años
)
# Mostrar los primeros datos
head(datos)
Cálculo de Prevalencia ¿Qué es la Prevalencia? La prevalencia mide la
proporción de personas afectadas por una enfermedad en un momento
dado.
Fórmula: Prevalencia = casos existentes / población total
# Calcular prevalencia al inicio del período
poblacion_total <- nrow(datos)
poblacion_total <- 100
casos_existentes <- 20
casos_existentes <- sum(datos$inicio_riesgo == 1)
casos_existentes <- sum(datos$inicio_riesgo != 0)
prevalencia <- casos_existentes / poblacion_total
cat("Prevalencia:", round(prevalencia * 100, 2), "%\n")
Prevalencia: 20 %
cat("Prevalencia:", prevalencia*100, "%\n")
Prevalencia: 20 %
Interpretación: Este valor indica el porcentaje de la población
afectada al inicio del estudio.
Cálculo de Incidencia Acumulada ¿Qué es la Incidencia Acumulada? La
incidencia acumulada mide la proporción de nuevos casos en una población
en riesgo durante un período.
Fórmula:
Incidencia acumulada = casos nuevos observados / población en riesgo
al inicio
# Calcular incidencia acumulada
casos_nuevos <- sum(datos$casos_nuevos)
casos_nuevos <- 10
poblacion_riesgo <- sum(datos$inicio_riesgo == 0)
poblacion_riesgo <- sum(datos$inicio_riesgo != 1)
poblacion_riesgo <- 80
incidencia_acumulada <- casos_nuevos / poblacion_riesgo
cat("Incidencia Acumulada:", round(incidencia_acumulada * 100, 2), "%\n")
Incidencia Acumulada: 12.5 %
Interpretación: Este valor indica el riesgo de desarrollar la
enfermedad durante el período de observación.
Cálculo de Densidad de Incidencia ¿Qué es la Densidad de Incidencia?
La densidad de incidencia mide la velocidad con la que aparecen nuevos
casos en una población durante períodos de tiempo acumulados.
Fórmula: densidad de incidencia = casos nuevos observados / ñsuma de
los períodes de riesgo
# Calcular densidad de incidencia
tiempo_total <- sum(datos$tiempo_observacion)
densidad_incidencia <- casos_nuevos / tiempo_total
cat("Densidad de Incidencia:", round(densidad_incidencia, 2), "casos por persona-año\n")
Densidad de Incidencia: 0.06 casos por persona-año
Interpretación: Este valor representa cuántos casos nuevos se generan
por persona-año.
Visualización de las Métricas Gráfico Comparativo
library(ggplot2)
# Crear datos para el gráfico
resultados <- data.frame(
medida = c("Prevalencia", "Incidencia Acumulada", "Densidad de Incidencia"),
valor = c(prevalencia * 100, incidencia_acumulada * 100, densidad_incidencia)
)
# Gráfico de barras
ggplot(resultados, aes(x = medida, y = valor, fill = medida)) +
geom_bar(stat = "identity") +
labs(title = "Medidas de Frecuencia Epidemiológica",
x = "Medida", y = "Valor (%)") +
theme_minimal()

Herramientas adicionales Número básico de Reproducción R0 Aalgunas
herramientas adicionales y modernas que se usan para analizar el impacto
de enfermedades en una población incluyen:
El número básico de reproducción R₀ es una métrica clave en
epidemiología para estimar cuántos casos secundarios genera un caso
inicial en una población completamente susceptible. Es esencial para
evaluar el potencial de propagación de enfermedades infecciosas como el
COVID-19.
El número básico de reproducción R₀ indica el promedio de casos
secundarios generados por un caso inicial en una población completamente
susceptible.
Cómo calcular R₀ El cálculo de R₀ puede realizarse usando varias
metodologías. Una de las más comunes se basa en la relación:
R0 = β x D
Donde:
β (tasa de transmisión): Probabilidad de que una persona infectada
transmita la enfermedad por unidad de tiempo.
D (duración infecciosa): Tiempo promedio durante el cual una persona
infectada puede transmitir la enfermedad.
Para calcularlo usando datos reales del COVID-19, podemos usar un
data.frame simulado o datos reales si se dispone de ellos.
Usamos un conjunto de datos que simula la propagación del COVID-19 en
una población.
## Dataset Simulado de COVID-19
set.seed(123)
datos <- data.frame(
id = 1:30,
fecha = seq(as.Date("2020-03-01"), as.Date("2020-03-30"), by = "days"),
nuevos_casos = round(runif(30, 50, 150)), # Nuevos casos diarios
recuperados = round(runif(30, 30, 100)), # Recuperaciones diarias
fallecidos = round(runif(30, 1, 10))) # Fallecimientos diarios
# Mostrar los primeros datos
head(datos)
Calcular R₀: Método Simplificado Definición Para estimar R₀,
necesitamos:
Duración infecciosa promedio (D): Asumimos 10 días para COVID-19.
Crecimiento exponencial (λ): Calculado a partir de la tasa de nuevos
casos diarios.
Paso 1: Calcular Crecimiento Diario
# Crecimiento diario de casos
datos$crecimiento <- c(NA, diff(datos$nuevos_casos))
# Calcular el promedio del crecimiento diario
lambda <- mean(datos$crecimiento, na.rm = TRUE)
cat("Crecimiento diario promedio (λ):", round(lambda, 2), "casos por día\n")
Crecimiento diario promedio (λ): -0.48 casos por día
Paso 2: Calcular R₀
# Asumimos una duración infecciosa promedio D = 10 días
D <- 10
# Estimación de R₀
R0 <- lambda * D
cat("Número básico de reproducción (R₀):", round(R0, 2), "\n")
Número básico de reproducción (R₀): -4.83
Visualización del Número R₀ Gráfico de Nuevos Casos
library(ggplot2)
ggplot(datos, aes(x = fecha, y = nuevos_casos)) +
geom_line(color = "blue", size = 1) +
geom_point(color = "red") +
labs(title = "Nuevos Casos Diarios de COVID-19",
x = "Fecha", y = "Nuevos Casos") +
theme_minimal()

Reflexión ¿Cómo influye la duración infecciosa promedio (D) en el
cálculo de R₀?
¿Qué intervenciones (como cuarentenas o vacunación) pueden reducir β
y, por ende, R₀?
¿Qué significa un R₀ > 1 para la propagación de la enfermedad?
Detalles del Ejemplo Duración Infecciosa Promedio (D): Se puede
ajustar con base en evidencia clínica, como estudios que estimen cuánto
tiempo los pacientes con COVID-19 son infecciosos. Datos Simulados: En
este ejemplo, los datos son generados aleatoriamente. Puedes
reemplazarlos con datos reales del COVID-19 de fuentes como Our World in
Data o bases gubernamentales. Crecimiento Diario (λ): El crecimiento
promedio se calcula con la diferencia diaria de nuevos casos.
Uso de Paquetes Adicionales Si deseas usar herramientas específicas
para el cálculo de R₀, puedes explorar paquetes como EpiEstim:
install.packages("EpiEstim")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:
https://cran.rstudio.com/bin/windows/Rtools/
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/SparseM_1.84-2.zip'
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/MatrixModels_0.5-4.zip'
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/mcmc_0.9-8.zip'
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/quantreg_6.1.zip'
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/MCMCpack_1.7-1.zip'
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/aweek_1.0.3.zip'
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/coarseDataTools_0.7.2.zip'
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/fitdistrplus_1.2-4.zip'
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/coda_0.19-4.1.zip'
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/incidence_1.7.6.zip'
probando la URL 'https://cran.rstudio.com/bin/windows/contrib/4.5/EpiEstim_2.2-5.zip'
package ‘SparseM’ successfully unpacked and MD5 sums checked
package ‘MatrixModels’ successfully unpacked and MD5 sums checked
package ‘mcmc’ successfully unpacked and MD5 sums checked
package ‘quantreg’ successfully unpacked and MD5 sums checked
package ‘MCMCpack’ successfully unpacked and MD5 sums checked
package ‘aweek’ successfully unpacked and MD5 sums checked
package ‘coarseDataTools’ successfully unpacked and MD5 sums checked
package ‘fitdistrplus’ successfully unpacked and MD5 sums checked
package ‘coda’ successfully unpacked and MD5 sums checked
package ‘incidence’ successfully unpacked and MD5 sums checked
package ‘EpiEstim’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\Silvi\AppData\Local\Temp\RtmpeidSPm\downloaded_packages
library(EpiEstim)
# Calcular R₀ usando EpiEstim (reemplazar con datos reales)
res <- estimate_R(
incid = datos$nuevos_casos,
method = "parametric_si",
config = make_config(list(mean_si = 4, std_si = 2))
)
print(res$R)
Simulamos el brote epidemico (ficticio):
set.seed(123)
dias <- 30
casos <- round(runif(dias, min = 10, max = 100))
datos <- data.frame(
fecha = seq(as.Date("2020-01-01"), by = "days", length.out = dias),
nuevos_casos = casos
)
# Mostrar los primeros datos
head(datos)
Configuración del Intervalo Serial Definir el Intervalo Serial El
intervalo serial representa el tiempo promedio entre infecciones
primarias y secundarias. En COVID-19, estudios sugieren una distribución
gamma con:
Media: 4 días
Desviación estándar: 2 días
# Configurar el intervalo serial
config <- make_config(
list(mean_si = 4, std_si = 2)) # Normalmente, make_config se utiliza para crear o gestionar configuraciones
Calcular el Número de Reproducción Efectivo (Rₑ) Estimar Rₑ Usamos
los datos diarios de nuevos casos para calcular Rₑ.
# Estimar Rₑ usando EpiEstim
resultado <- estimate_R(
incid = datos$nuevos_casos,
method = "parametric_si",
config = config
)
# Mostrar resultados
print(resultado$R)
Visualización de Rₑ Gráfico de la Evolución de Rₑ Creamos un gráfico
que muestra cómo Rₑ cambia con el tiempo, lo que puede indicar el
impacto de intervenciones.
# Gráfico de Rₑ
plot(
resultado,
what = "R",
legend = FALSE,
main = "Evolución del Número de Reproducción Efectivo (Rₑ)"
)

Interpretación:
Rₑ > 1: La epidemia está en expansión.
Rₑ < 1: La epidemia está disminuyendo.
La función estimate_R del paquete {EpiEstim} en R se utiliza para
estimar el número de reproducción efectivo (Rₑ), es una métrica clave en
epidemiología para medir la capacidad de transmisión de una enfermedad
infecciosa en una población a lo largo del tiempo.
Practica Introducción En esta práctica calcularemos , Rₑ y R para
varias enfermedades infecciosas utilizando parámetros reales. Estos
valores son cruciales para comprender la dinámica de transmisión y el
impacto de medidas de control.
Valores para las enfermedades Infecciosas COVID-19 (SARS-CoV-2):
Tasa de transmisión: ~99.4% (alta transmisión en entornos cerrados)
.
Tasa de mortalidad: 0.185% .
Duración infecciosa: ~10 días .
Distanciamiento social: ~30% puede reducir significativamente la
transmisión.
Referencia: Estimation of the reproduction number of SARS-CoV-2.
MERS-CoV (Middle East Respiratory Syndrome):
Tasa de transmisión: ~5% (en contactos domiciliarios).
Tasa de mortalidad: ~35%.
Duración infecciosa: ~14 días.
Referencia: Emerging respiratory viral infections: MERS-CoV and
influenza.
Influenza Estacional:
Tasa de transmisión: ~50–75%.
Tasa de mortalidad: ~0.1%.
Duración infecciosa: ~7 días.
Referencia: Influenza and tuberculosis co-infection: A systematic
review.
Tuberculosis:
Tasa de transmisión: ~30% (en contactos cercanos).
Tasa de mortalidad: ~15%.
Duración infecciosa: Meses a años sin tratamiento.
Referencia: Tuberculosis and Covid-19 Co-Infection.
Sarampión:
Tasa de transmisión: 90–100% (muy alta).
Tasa de mortalidad: ~0.2% en países desarrollados; más alta en
contextos sin vacunación.
Duración infecciosa: ~8 días.
Referencia: Molecular and Cellular Mechanisms of M. tuberculosis and
SARS-CoV-2 Infections.
Simularemos la propagación de 5 enfermedades infecciosas con
diferentes tasas de transmisión, mortalidad y duración infecciosa. Estas
simulaciones se basarán en parámetros obtenidos de la literatura
científica.
# Parámetros de las enfermedades
enfermedades <- data.frame(
Enfermedad = c("COVID-19", "MERS-CoV", "Influenza Estacional", "Tuberculosis", "Sarampión"),
Tasa_Transmision = c(99.4, 5, 60, 30, 95), # Porcentaje
Tasa_Mortalidad = c(0.185, 35, 0.1, 15, 0.2), # Porcentaje
Duracion_Infecciosa = c(10, 14, 7, 180, 8), # Días
Distanciamiento_Social = c(30, 0, 15, 10, 0), # Porcentaje
Poblacion = c(1000000, 1000000, 1000000, 1000000, 1000000) # Población para simulación
)
Cálculo de R₀ Fórmula de R₀ R₀ (Número básico de reproducción):
Representa el número promedio de infecciones secundarias causadas por
un individuo infectado en una población completamente susceptible.
Fórmula: R0 = Tasa de transmisión x Duración infecciosa
# Calcular R₀ para cada enfermedad
enfermedades$R0 <- (enfermedades$Tasa_Transmision / 100) * enfermedades$Duracion_Infecciosa
# Mostrar resultados
enfermedades[c("Enfermedad", "R0")]
Cálculo de Rₑ Fórmula de Rₑ Calcula Re onsiderando que no toda la
población es susceptible (debido a inmunidad o intervenciones).
Fórmula:
Re = Ro * susceptibles / población total
# Considerar 70% de la población inicial como susceptibles
enfermedades$Susceptibles <- enfermedades$Poblacion * 0.7
# Calcular Rₑ
enfermedades$Re <- enfermedades$R0 * (enfermedades$Susceptibles / enfermedades$Poblacion)
# Mostrar resultados
enfermedades[c("Enfermedad", "R0", "Re")]
Cálculo de Rₜ Dinámica Temporal de Rₜ Consideramos intervenciones
como distanciamiento social y cambios en los susceptibles a lo largo del
tiempo.
# Crear un data frame para simular la dinámica temporal
dias <- 30
resultado_rt <- data.frame()
for (i in 1:nrow(enfermedades)) {
enfermedad <- enfermedades[i, ]
susceptibles <- enfermedad$Susceptibles
rt <- numeric(dias)
for (t in 1:dias) {
rt[t] <- enfermedad$R0 * (susceptibles / enfermedad$Poblacion) * (1 - enfermedad$Distanciamiento_Social / 100)
susceptibles <- max(0, susceptibles - (susceptibles * enfermedad$Tasa_Transmision / 100)) # Reducir susceptibles
}
resultado_rt <- rbind(resultado_rt, data.frame(Dia = 1:dias, R_t = rt, Enfermedad = enfermedad$Enfermedad))
}
# Mostrar resultados para una enfermedad
head(resultado_rt[resultado_rt$Enfermedad == "COVID-19", ])
Visualización de Rₜ Gráfico para Cada Enfermedad
library(ggplot2)
# Gráfico de Rₜ
ggplot(resultado_rt, aes(x = Dia, y = R_t, color = Enfermedad)) +
geom_line(size = 1) +
geom_hline(yintercept = 1, linetype = "dashed", color = "red") +
labs(title = "Evolución de Rt por Enfermedad",
x = "Días", y = "Rt") +
theme_minimal() +
scale_color_brewer(palette = "Set1")

Bonus track: Podemos crear una función en R para simular la
enfermedad En el siguiente bloque de codigo se crea la función
simular_enfermedad
# Crear una función de simulación
simular_enfermedad <- function(enfermedad, tasa_transmision, tasa_mortalidad, duracion, dist_social, poblacion = 1000) {
dias <- 30
infecciosos <- 1 # Casos iniciales
recuperados <- 0
fallecidos <- 0
susceptibles <- poblacion - infecciosos
resultado <- data.frame(Dia = 1:dias, Infectados = NA, Recuperados = NA, Fallecidos = NA, Susceptibles = NA)
for (dia in 1:dias) {
nuevas_infecciones <- round((infecciosos * tasa_transmision / 100) * (1 - dist_social / 100))
nuevas_infecciones <- min(nuevas_infecciones, susceptibles) # No exceder susceptibles
nuevos_recuperados <- ifelse(dia > duracion, infecciosos / duracion, 0)
nuevos_fallecidos <- round((tasa_mortalidad / 100) * infecciosos)
infecciosos <- infecciosos + nuevas_infecciones - nuevos_recuperados - nuevos_fallecidos
recuperados <- recuperados + nuevos_recuperados
fallecidos <- fallecidos + nuevos_fallecidos
susceptibles <- poblacion - infecciosos - recuperados - fallecidos
resultado[dia, ] <- c(dia, infecciosos, recuperados, fallecidos, susceptibles)
}
return(resultado)
}
Una vez creada la función ahora podemos utilizarla: Vamos a crear un
objeto que garde los datos simulados de una enfermedad ( puede ser de
los datos que ya revisamos en la literatura)
Simulación de ejemplo para COVID-19
sim_covid <- simular_enfermedad( “COVID-19”, tasa_transmision =
99.4, tasa_mortalidad = 20, duracion = 10, dist_social = 30, poblacion =
1000 )
# Simulación de ejemplo para COVID-19
sim_covid <- simular_enfermedad(
"COVID-19", tasa_transmision = 99.4, tasa_mortalidad = 20,
duracion = 10, dist_social = 30, poblacion = 1000
)
library(ggplot2)
# Gráfico para COVID-19
ggplot(sim_covid, aes(x = Dia)) +
geom_line(aes(y = Infectados, color = "Infectados")) +
geom_line(aes(y = Recuperados, color = "Recuperados")) +
geom_line(aes(y = Fallecidos, color = "Fallecidos")) +
geom_line(aes(y = Susceptibles, color = "Susceptibles")) +
labs(title = "Simulación de Covid-19",
x = "Días", y = "Número de Personas") +
scale_color_manual(name = "Estado", values = c("Infectados" = "red",
"Recuperados" = "green",
"Fallecidos" = "black",
"Susceptibles" = "blue")) +
theme_minimal()

Conclusión La simulación permite visualizar la dinámica de
transmisión y el impacto de intervenciones como el distanciamiento
social. Los resultados pueden usarse para planificar respuestas ante
brotes reales.
Además, permite analizar la dinámica de la propagación de
enfermedades bajo diferentes escenarios de intervención y parámetros
epidemiológicos.
Siguientes pasos:
Ajustar parámetros para escenarios específicos.
Comparar entre diferentes poblaciones y entornos.
Calculo de tamaño muestral Introducción El cálculo del tamaño de
muestra es una etapa crucial en el diseño de estudios. Cuando deseamos
estimar una proporción, debemos considerar: 1. Nivel de confianza (Zα):
Representa la probabilidad de que el intervalo de confianza contenga el
valor verdadero. Ejemplo: 95% (( Z = 1.96 )). 2. Precisión deseada (( e
)): Diferencia máxima aceptable entre la proporción estimada y la real.
3. Proporción esperada (( p )): Estimación inicial basada en literatura
o estudios previos.
En este ejercicio, utilizaremos el paquete pwr para calcular el
tamaño de muestra necesario para conocer la prevalencia de diabetes en
una población, suponiendo que: - Nivel de confianza: 95% - Precisión
deseada: 5% - Proporción esperada: 50% (0.5).
Instalación y configuración de paquetes Primero, asegurémonos de
instalar y cargar los paquetes necesarios.
Paquete pwr
# Ejecutar solo una vez si no está instalado:
# install.packages("pwr")
library(pwr)
Fórmula para estimar el tamaño de muestra El cálculo del tamaño de
muestra para estimar una proporción se realiza con la fórmula:
Fórmula tamaño de muestra para proporción Donde:
Z: valor correspondiente al nivel de confianza (por ejemplo, Z = 1.96
para 95 %). p: proporción esperada. e: precisión deseada (error máximo
permitido). Aunque el paquete pwr simplifica este cálculo, también
podemos hacerlo de forma manual paso a paso en R.
Cálculo del tamaño de muestra Método 1: Cálculo manual Utilizando
directamente la fórmula clásica para proporciones en población
“infinita”:
# Parámetros
Z <- 1.96 # Nivel de confianza para 95 %
p <- 0.5 # Proporción esperada
e <- 0.05 # Precisión deseada (5 %)
# Cálculo del tamaño de muestra
n_manual <- (Z^2 * p * (1 - p)) / (e^2)
cat("Tamaño de muestra necesario (método manual):",
ceiling(n_manual), "\n")
Tamaño de muestra necesario (método manual): 385
Método 2: Uso del paquete pwr El paquete pwr proporciona una forma
más general, basada en tamaño de efecto (h) y poder estadístico.
Supongamos que queremos detectar una diferencia entre una proporción
nula p0 = 0.5 y una proporción alternativa p1 = 0.6 con α = 0.05 y poder
80 %:
# Parámetros para prueba de una proporción
p0 <- 0.5 # Proporción nula
p1 <- 0.6 # Proporción alternativa
# Tamaño de efecto de Cohen (h) para proporciones
h <- ES.h(p1 = p1, p2 = p0)
# Cálculo del tamaño de muestra con pwr.p.test
res_pwr <- pwr.p.test(h = h,
sig.level = 0.05,
power = 0.80,
alternative = "two.sided")
n_pwr <- ceiling(res_pwr$n)
cat("Tamaño de muestra necesario (pwr.p.test):",
n_pwr, "\n")
Tamaño de muestra necesario (pwr.p.test): 194
Tamaño de muestra en poblaciones finitas Cuando se conoce el tamaño
total de la población, se ajusta el tamaño de muestra mediante la
fórmula para poblaciones finitas:
Fórmula población finita Donde:
N: tamaño de la población. Z: valor correspondiente al nivel de
confianza. p: proporción esperada. q = 1 − p. d: precisión deseada. En
este ejercicio, calculamos el tamaño de muestra para:
N = 10,000 Nivel de confianza: 95 % (Z = 1.96) Proporción esperada: p
= 0.05 (5 %) Precisión deseada: d = 0.03 (3 %)
# Parámetros
N <- 10000 # Tamaño de la población
Z <- 1.96 # Nivel de confianza para 95 %
p <- 0.05 # Proporción esperada (5 %)
q <- 1 - p # Complemento de la proporción
d <- 0.03 # Precisión deseada (3 %)
# Cálculo del tamaño de muestra para población finita
n_finita <- (N * Z^2 * p * q) /
((d^2 * (N - 1)) + (Z^2 * p * q))
cat("Tamaño de muestra necesario (N = 10,000):",
ceiling(n_finita), "\n")
Tamaño de muestra necesario (N = 10,000): 199
Paso 2: Variación del tamaño de muestra según la precisión Creamos un
gráfico que muestre cómo cambia el tamaño de muestra con distintos
valores de d:
library(ggplot2)
# Secuencia de precisiones posibles
precisiones <- seq(0.01, 0.10, by = 0.01)
tam_muestra <- sapply(precisiones, function(d){
(N * Z^2 * p * q) /
((d^2 * (N - 1)) + (Z^2 * p * q))
})
# Data frame para graficar
datos_grafico <- data.frame(
precision = precisiones,
tamano_muestra = ceiling(tam_muestra)
)
ggplot(datos_grafico,
aes(x = precision, y = tamano_muestra)) +
geom_line() +
geom_point() +
labs(
title = "Relación entre precisión (d) y tamaño de muestra\n(N = 10,000)",
x = "Precisión deseada (d)",
y = "Tamaño de muestra"
) +
theme_minimal()

Ejemplo adicional: población de 15,000 habitantes Ahora calculamos el
tamaño de muestra para estimar la prevalencia de diabetes en una
población finita de 15,000 habitantes, con:
Seguridad: 95 % Precisión: 3 % (d = 0.03) Proporción esperada: p =
0.05 (5 %)
# Parámetros
N <- 15000 # Tamaño de la población
Z <- 1.96 # Nivel de confianza para 95 %
p <- 0.05 # Proporción esperada (5 %)
q <- 1 - p
d <- 0.03 # Precisión deseada (3 %)
# Cálculo para población finita
n_finita_15000 <- (N * Z^2 * p * q) /
((d^2 * (N - 1)) + (Z^2 * p * q))
cat("Tamaño de muestra necesario (N = 15,000):",
ceiling(n_finita_15000), "\n")
Tamaño de muestra necesario (N = 15,000): 201
Exploración gráfica (N = 15,000)
precisiones <- seq(0.01, 0.10, by = 0.01)
tam_muestra <- sapply(precisiones, function(d){
(N * Z^2 * p * q) /
((d^2 * (N - 1)) + (Z^2 * p * q))
})
datos_grafico <- data.frame(
precision = precisiones,
tamano_muestra = ceiling(tam_muestra)
)
ggplot(datos_grafico,
aes(x = precision, y = tamano_muestra)) +
geom_line() +
geom_point() +
labs(
title = "Relación entre precisión (d) y tamaño de muestra\n(N = 15,000)",
x = "Precisión deseada (d)",
y = "Tamaño de muestra"
) +
theme_minimal()

Tamaño de muestra para estimar una media
# Parámetros
Z <- 1.96 # Nivel de confianza (95 %)
S2 <- 250 # Varianza (S^2)
d <- 3 # Precisión deseada
# Cálculo del tamaño de muestra
n_media_manual <- (Z^2 * S2) / (d^2)
cat("Tamaño de muestra (media, método manual):",
ceiling(n_media_manual), "\n")
Tamaño de muestra (media, método manual): 107
Tamaño de muestra para media con
# Parámetros
Z <- 1.96 # Nivel de confianza (95 %)
S2 <- 250 # Varianza (S^2)
d <- 3 # Precisión deseada
# Cálculo del tamaño de muestra
n_manual <- (Z^2 * S2) / (d^2)
cat("Tamaño de muestra (media, método manual):",
ceiling(n_manual), "\n")
Tamaño de muestra (media, método manual): 107
Comparación de dos proporciones
# Parámetros
Z_alpha <- 1.645 # Nivel de confianza ~95 % (una cola)
Z_beta <- 0.842 # Poder estadístico 80 %
p1 <- 0.7 # Proporción 1
p2 <- 0.9 # Proporción 2
p <- (p1 + p2) / 2 # Promedio de proporciones
# Cálculo del tamaño de muestra (por grupo)
n_dos_prop_manual <- (
(Z_alpha * sqrt(2 * p * (1 - p)) +
Z_beta * sqrt(p1 * (1 - p1) + p2 * (1 - p2)))^2
) / (p1 - p2)^2
cat("Tamaño de muestra por grupo (dos proporciones, manual):",
ceiling(n_dos_prop_manual), "\n")
Tamaño de muestra por grupo (dos proporciones, manual): 49
# Cálculo del tamaño del efecto h para dos proporciones
h <- ES.h(p1 = p1, p2 = p2)
# Tamaño de muestra por grupo con pwr.2p.test
res_2p <- pwr.2p.test(
h = h,
sig.level = 0.05,
power = 0.80,
alternative = "two.sided"
)
cat("Tamaño de muestra por grupo (dos proporciones, pwr):",
ceiling(res_2p$n), "\n")
Tamaño de muestra por grupo (dos proporciones, pwr): 60
Comparación de dos medias:
# Parámetros
Z_alpha <- 1.645 # Nivel de confianza ~95 % (una cola)
Z_beta <- 1.282 # Poder estadístico 90 %
S <- 16 # Desviación estándar
d_mean <- 15 # Diferencia esperada entre medias
# Cálculo del tamaño de muestra por grupo
n_dos_medias <- (2 * (Z_alpha + Z_beta)^2 * S^2) / (d_mean^2)
cat("Tamaño de muestra por grupo (dos medias, manual):",
ceiling(n_dos_medias), "\n")
Tamaño de muestra por grupo (dos medias, manual): 20
LS0tDQp0aXRsZTogIkVzdGFkw61zdGljYXMgVml0YWxlcyBlbiBFcGlkZW1pb2xvZ8OtYSINCmF1dGhvcjogIkxpYy4gU2lsdmlhIE1vbnRlcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiNDcmVhciB1biB2ZWN0b3IgZGUgZGF0b3MNCg0KYGBge3J9DQpkYXRvcyA8LSBjKDEwMCwgMjAwLCAzMDAsIDQwMCwgNTAwKQ0KYGBgDQoNCiNDYWxjdWxhciBlbCB0b3RhbCB5IHByb21lZGlvDQoNCmBgYHtyfQ0KdG90YWwgPC0gc3VtKGRhdG9zKQ0KcHJvbWVkaW8gPC0gbWVhbihkYXRvcykNCmBgYA0KDQojTW9zdHJhciByZXN1bHRhZG9zDQoNCmBgYHtyfQ0KY2F0KCJUb3RhbDoiLCB0b3RhbCwgIlxuIikNCmBgYA0KDQpgYGB7cn0NCmNhdCgiUHJvbWVkaW87IiwgcHJvbWVkaW8sICJcbiIpDQpgYGANCg0KR3JhZmljYXIgbG9zIGRhdG9zIGNvbiBnZ3Bsb3QyIGxpYnJhcnkoZ2dwbG90MikgZGYgXDwtIGRhdGEuZnJhbWUgKHggPSAxOjUsIHkgPSBkYXRvcykgTE8gYW50ZXMgbWVuY2lvbmFkbyBlcyB1bmEgZm9ybXVsYSBwYXJhIGNyZWFyIHVuYSBkYXRhLmZyYW1lIGRvbmRlIGVuICJYID0gMTo1IiBzaWduaWZpY2EgcXVlIGVzdG95IGluZGljYW5kbyBxdWUgc2Vyw6FuIDEgY29sdW1uYSB5IDUgZmlsYXMgcmVzcGVjdGl2YW1lbnRlLg0KDQpgYGB7cn0NCmRmIDwtIGRhdGEuZnJhbWUgKHggPSAxOjUsIHkgPSBkYXRvcykgDQpkZg0KYGBgDQoNClBhbGV0YSBkZSBoZXggY29sb3IgcGFyYSBkZWZpbmlyIGEgdHJhdmVzIGRlIHVuIGNvZGlnbyBlbCBjb2xvciBFbCBzaW1ib2xvICIrIiBhw7FhZGUgdW5hIGxpbmVhIGRlIGNvZGlnbyBxdWUgZW4gZ2dwbG90IGVzIGNvbW8gdW5hDQoNCmBgYHtyfQ0KbGlicmFyeSgiZ2dwbG90MiIpDQpnZ3Bsb3QoZGYsIGFlcyh4ID0geCwgeSA9IHkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNhMzQ2ZjAiKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjUsDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJFZGFkIiwgIlBlc28iLCAiQyIsICJEIiwgIkUiKSkgKw0KICBsYWJzKHRpdGxlID0gImdyYWZpY28gZGUgYmFycmFzIiwgeCA9ICLDjW5kaWNlIiwgeSA9ICJWYWxvcmVzIikNCmBgYA0KDQpQQVJBIFJFTk9NQlJBUiBFTiBFU0NBTEE6IHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjUsIGxhYmVscyA9IGMoIkVkYWQiLCAiUGVzbyIsICJDIiwgIkQiLCAiRSIpKSArDQoNClBBUkEgUkVOT01CUkFSIENPTU8gRkFDVE9SOiBsaWJyYXJ5KGdncGxvdDIpDQoNCmxpYnJhcnkoZ2dwbG90MikNCg0KZ2dwbG90KGRmLCBhZXMoeCA9IGZhY3Rvcih4LCBsYWJlbHMgPSBjKCJBIiwgIkIiLCAiQyIsICJEIiwgIkUiKSksIHkgPSB5KSkgKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjZmMwM2RmIikgKyBsYWJzKHRpdGxlID0gIkdyw6FmaWNvIGRlIGJhcnJhcyIsIHggPSAiw41uZGljZSIsIHkgPSAiVmFsb3JlcyIpDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiZ2FwbWluZGVyIikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoImdhcG1pbmRlciIpDQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCmxpYnJhcnkoInRpZHl2ZXJzZSIpDQpgYGANCg0KYGBge3J9DQoNCmdhcGRhdGEyMDA3IDwtIGdhcG1pbmRlciAlPiUgZmlsdGVyKHllYXIgPT0gMjAwNykNCg0KZ2FwZGF0YTIwMDckeWVhcg0KYGBgDQoNCkVzY29nZXIgb2JqZXRvcyBnZW9tZXRyaWNvcyBnZW9tX3BvaW50KCkgYWVzKCkNCg0KYGBge3J9DQpnYXBkYXRhMjAwNyAlPiUgDQogIGdncGxvdChhZXMoeCA9IGdkcFBlcmNhcCwgeSA9ICBsaWZlRXhwLCBjb2xvdXIgPSBjb250aW5lbnQpKSArDQogIGdlb21fcG9pbnQoc2hhcGU9OCkNCmBgYA0KDQpzaGFwZSBlcyBwYXJhIGVsZWdpciBjb21vIHF1aWVyZXMgbGEgZm9ybWEgZW4gbGEgcXVlIHNlIHJlcHJlc2VudGFuIGxvcyB2YWxvcmVzIGVuIGxhIGdyYWZpY2EgMCBjdWFkcmFkbyAxIGNpcmN1bG8gMiB0cmlhbmd1bG8gNCB4IDggXCogMTUgY3VhZHJhZG8gcmVsbGVubyAxNiBjaXJjdWxvIHJlbGxlbm8gMTcgdHJpYW5ndWxvIHJlbGxlbm8gMjEgY2lyY3VsbyByZWxsZW5vIGNvbiBjb250b3JubyAyMiBjdWFkcmFkbyByZWxsZW5vIGNvbiBjb250b3JubyAyMyByb21ibyByZWxsZW5vIGNvbiBjb250b3Jubw0KDQpTZSBwdWVkZSBzZXBhcmFyIHRvZG8gZW4gdmFyaWFzIGdyYWZpY2FzIGFncmVnYW5kbyB1bmEgbGluZWEgZXh0cmEgYWwgY29kaWdvDQoNCmZhY2V0X3dyYXAoY29udGluZW50KQ0KDQpgYGB7cn0NCmdhcGRhdGEyMDA3ICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZ2RwUGVyY2FwLCB5ID0gIGxpZmVFeHAsIGNvbG91ciA9IGNvbnRpbmVudCkpICsNCiAgZ2VvbV9wb2ludChzaGFwZT04KSArDQogIGZhY2V0X3dyYXAofmNvbnRpbmVudCkNCmBgYA0KDQpFbGVnaXIgZWwgZm9uZG86IGRlZmF1bHQgdGhlbWVfYncgdGhlbWVfZGFyayB0aGVtZV9jbGFzc2ljDQoNCmBgYHtyfQ0KZ2FwZGF0YTIwMDcgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBnZHBQZXJjYXAsIHkgPSAgbGlmZUV4cCwgY29sb3VyID0gY29udGluZW50KSkgKw0KICBnZW9tX3BvaW50KHNoYXBlPTgpICsNCiAgZmFjZXRfd3JhcCh+Y29udGluZW50KSArDQogIHRoZW1lX2J3KCkNCmBgYA0KDQrCv1F1w6kgc29uIGxhcyBFc3RhZMOtc3RpY2FzIFZpdGFsZXM/IExhcyBlc3RhZMOtc3RpY2FzIHZpdGFsZXMgc29uIG3DqXRyaWNhcyBjbGF2ZSBxdWUgcGVybWl0ZW4gYW5hbGl6YXIgZWwgZXN0YWRvIGRlIHNhbHVkIGRlIHVuYSBwb2JsYWNpw7NuLiBFbnRyZSBsYXMgbcOhcyBjb211bmVzIHNlIGVuY3VlbnRyYW46DQoNCi0gICBUYXNhIGRlIG5hdGFsaWRhZDogTsO6bWVybyBkZSBuYWNpbWllbnRvcyBwb3IgY2FkYSAxLDAwMCBoYWJpdGFudGVzLg0KDQpUYXNhIGRlIG1vcnRhbGlkYWQ6IE7Dum1lcm8gZGUgbXVlcnRlcyBwb3IgY2FkYSAxLDAwMCBoYWJpdGFudGVzLg0KDQpUYXNhIGRlIGxldGFsaWRhZDogUG9yY2VudGFqZSBkZSBwZXJzb25hcyBmYWxsZWNpZGFzIGVudHJlIGxhcyBxdWUgcGFkZWNpZXJvbiB1bmEgZW5mZXJtZWRhZCBlc3BlY8OtZmljYS4NCg0KQ3JlYXIgdW4gRGF0YXNldCBGaWN0aWNpbyBVc2FyZW1vcyB1biBjb25qdW50byBkZSBkYXRvcyBmaWN0aWNpbyBwYXJhIHJlYWxpemFyIGxvcyBjw6FsY3Vsb3M6DQoNCmBgYHtyfQ0KIyBDcmVhciB1biBjb25qdW50byBkZSBkYXRvcyBmaWN0aWNpbw0KZGF0b3MgPC0gZGF0YS5mcmFtZSgNCiAgcmVnaW9uID0gYygiTm9ydGUiLCAiU3VyIiwgIkVzdGUiLCAiT2VzdGUiKSwNCiAgcG9ibGFjaW9uID0gYygxMDAwMDAsIDc1MDAwLCA1MDAwMCwgNjAwMDApLA0KICBuYWNpbWllbnRvcyA9IGMoMTIwMCwgODAwLCA2MDAsIDcwMCksDQogIG11ZXJ0ZXMgPSBjKDkwMCwgNTAwLCAzMDAsIDQwMCksDQogIGNhc29zX2VuZmVybWVkYWQgPSBjKDE1MDAsIDEwMDAsIDgwMCwgOTAwKSwNCiAgZmFsbGVjaWRvc19lbmZlcm1lZGFkID0gYygyMDAsIDE1MCwgMTAwLCAxMjApDQopDQoNCiMgTW9zdHJhciBsb3MgcHJpbWVyb3MgZGF0b3MNCnByaW50KGRhdG9zKQ0KYGBgDQoNClRhc2EgZGUgTW9ydGFsaWRhZCDCv1F1w6kgZXMgbGEgVGFzYSBkZSBNb3J0YWxpZGFkPyBMYSBUYXNhIGRlIE1vcnRhbGlkYWQgbWlkZSBlbCBuw7ptZXJvIGRlIG11ZXJ0ZXMgZW4gdW5hIHBvYmxhY2nDs24gcG9yIGNhZGEgMSwwMDAgaGFiaXRhbnRlcyBkdXJhbnRlIHVuIHBlcsOtb2RvIGRldGVybWluYWRvLg0KDQpFcyB1bmEgbcOpdHJpY2EgY3J1Y2lhbCBwYXJhIGV2YWx1YXIgZWwgaW1wYWN0byBkZSBmYWN0b3JlcyBxdWUgYWZlY3RhbiBsYSBzYWx1ZCBww7pibGljYS4NCg0KRsOzcm11bGEgTGEgZsOzcm11bGEgZ2VuZXJhbCBwYXJhIGNhbGN1bGFyIGxhIFRhc2EgZGUgTW9ydGFsaWRhZCBlczoNCg0KTnVtZXJvIGRlIG11ZXJ0ZXMgLyBwb2JsYWNpw7NuIHRvdGFsIFwqIDEwMDANCg0KRG9uZGU6DQoNCi0gICBOw7ptZXJvIGRlIE11ZXJ0ZXM6IFRvdGFsIGRlIHBlcnNvbmFzIGZhbGxlY2lkYXMgZW4gdW4gYcOxby4NCg0KUG9ibGFjacOzbiBUb3RhbDogTsO6bWVybyB0b3RhbCBkZSBoYWJpdGFudGVzIGVuIGxhIHBvYmxhY2nDs24uDQoNCmBgYHtyfQ0KIyBEYXRvcw0KbXVlcnRlcyA8LSA5MDAgICMgTsO6bWVybyBkZSBtdWVydGVzIGVuIHVuIGHDsW8NCnBvYmxhY2lvbl90b3RhbCA8LSAxMDAwMDAgICMgUG9ibGFjacOzbiB0b3RhbCBlbiBlc2UgYcOxbw0KDQojIEPDoWxjdWxvIGRlIGxhIHRhc2EgZGUgbW9ydGFsaWRhZA0KdGFzYV9tb3J0YWxpZGFkIDwtIChtdWVydGVzIC8gcG9ibGFjaW9uX3RvdGFsKSAqIDEwMDANCg0KIyBSZXN1bHRhZG8NCmNhdCgiVGFzYSBkZSBtb3J0YWxpZGFkOiIsIHRhc2FfbW9ydGFsaWRhZCwgIm11ZXJ0ZXMgcG9yIGNhZGEgMSwwMDAgaGFiaXRhbnRlc1xuIikNCmBgYA0KDQpWaXN1YWxpemFjacOzbiBkZSBUYXNhIGRlIE1vcnRhbGlkYWQgVXNhbW9zIHVuIGdyw6FmaWNvIGRlIGJhcnJhcyBwYXJhIHZpc3VhbGl6YXIgbGFzIHRhc2FzIGRlIG1vcnRhbGlkYWQgZW4gZGlmZXJlbnRlcyByZWdpb25lczoNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCnN0cihkYXRvcykNCmBgYA0KDQpgYGB7cn0NCnByaW50KGRhdG9zKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KYGBgDQoNCmBgYHtyfQ0KIyBDYWxjdWxhciB0YXNhcyBkZSBtb3J0YWxpZGFkDQoNCmRhdG9zJHRhc2FfbW9ydGFsaWRhZCA8LSAoZGF0b3MkbXVlcnRlcyAvIGRhdG9zJHBvYmxhY2lvbikgKiAxMDAwDQoNCnByaW50KGRhdG9zKQ0KYGBgDQoNCkdSQUZJQ09TOg0KDQpgYGB7cn0NCiMgR3LDoWZpY28NCmdncGxvdChkYXRvcywgYWVzKHggPSByZWdpb24sIHkgPSB0YXNhX21vcnRhbGlkYWQsIGZpbGwgPSByZWdpb24pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnModGl0bGUgPSAiVGFzYSBkZSBNb3J0YWxpZGFkIHBvciBSZWdpw7NuIiwgeCA9ICJSZWdpw7NuIiwgeSA9ICJUYXNhIGRlIE1vcnRhbGlkYWQgKHBvciAxLDAwMCBoYWJpdGFudGVzKSIpICsNCiAgdGhlbWVfY2xhc3NpYygpDQpgYGANCg0KQ29uY2x1c2nDs24gTGEgVGFzYSBkZSBNb3J0YWxpZGFkIGVzIHVuIGluZGljYWRvciBmdW5kYW1lbnRhbCBwYXJhIG1lZGlyIGVsIGltcGFjdG8gZGUgY29uZGljaW9uZXMgZGUgc2FsdWQgeSBmYWN0b3JlcyBzb2Npb2Vjb27Ds21pY29zIGVuIHVuYSBwb2JsYWNpw7NuLg0KDQpDb21wYXJhciB0YXNhcyBlbnRyZSByZWdpb25lcyBwdWVkZSBheXVkYXIgYSBpZGVudGlmaWNhciDDoXJlYXMgcXVlIG5lY2VzaXRhbiBtYXlvciBhdGVuY2nDs24uDQoNClRhc2EgZGUgTGV0YWxpZGFkIMK/UXXDqSBlcyBsYSBUYXNhIGRlIExldGFsaWRhZD8gTGEgVGFzYSBkZSBMZXRhbGlkYWQgbWlkZSBlbCBwb3JjZW50YWplIGRlIHBlcnNvbmFzIGZhbGxlY2lkYXMgZW50cmUgbGFzIHF1ZSBoYW4gcGFkZWNpZG8gdW5hIGVuZmVybWVkYWQgZXNwZWPDrWZpY2EuDQoNCkVzIHVuYSBtw6l0cmljYSBjcnVjaWFsIHBhcmEgZXZhbHVhciBsYSBncmF2ZWRhZCBkZSB1bmEgZW5mZXJtZWRhZCB5IGxhIGVmZWN0aXZpZGFkIGRlIGxhcyBpbnRlcnZlbmNpb25lcyBtw6lkaWNhcy4NCg0KRsOzcm11bGEgTGEgZsOzcm11bGEgZ2VuZXJhbCBwYXJhIGNhbGN1bGFyIGxhIFRhc2EgZGUgTGV0YWxpZGFkIGVzOg0KDQpUYXNhIGRlIGxldGFsaWRhZCA9IG51bWVybyBkZSBmYWxsZWNpZG9zIC8gbnVtZXJvIGRlIGNhc29zIFwqIDEwMCA9DQoNCkRvbmRlOg0KDQotICAgTsO6bWVybyBkZSBGYWxsZWNpZG9zOiBUb3RhbCBkZSBwZXJzb25hcyBxdWUgaGFuIG11ZXJ0byBkZWJpZG8gYSBsYSBlbmZlcm1lZGFkLiAtDQoNCi1Ow7ptZXJvIGRlIENhc29zOiBUb3RhbCBkZSBwZXJzb25hcyBkaWFnbm9zdGljYWRhcyBjb24gbGEgZW5mZXJtZWRhZC4NCg0KSW1wbGVtZW50YWNpw7NuIGVuIFIgQ2FsY3VsZW1vcyBsYSBUYXNhIGRlIExldGFsaWRhZCB1c2FuZG8gdW4gZWplbXBsbyBwcsOhY3RpY286DQoNCmBgYHtyfQ0KRGF0b3NfZmFsbGVjaWRvcyA8LSAyMDAgIyBOw7ptZXJvIGRlIGZhbGxlY2lkb3MgcG9yIGxhIGVuZmVybWVkYWQgDQpjYXNvcyA8LSAxNTAwICMgTsO6bWVybyB0b3RhbCBkZSBjYXNvcyByZWdpc3RyYWRvcw0KDQojIEPDoWxjdWxvIGRlIGxhIHRhc2EgZGUgbGV0YWxpZGFkDQoNCnRhc2FfbGV0YWxpZGFkIDwtIChEYXRvc19mYWxsZWNpZG9zIC8gY2Fzb3MpICogMTAwDQoNCiMgUmVzdWx0YWRvDQoNCmNhdCgiVGFzYSBkZSBsZXRhbGlkYWQ6IiwgdGFzYV9sZXRhbGlkYWQsICIlIGRlIGxvcyBjYXNvcyBmYWxsZWNlblxuIikNCmBgYA0KDQpgYGB7cn0NCiMgQ2FsY3VsYXIgdGFzYXMgZGUgbGV0YWxpZGFkDQpkYXRvcyR0YXNhX2xldGFsaWRhZCA8LSAoZGF0b3MkZmFsbGVjaWRvcyAvIGRhdG9zJGNhc29zKSAqIDEwMCAgICAgICAgICAgICAgICANCmBgYA0KDQpgYGB7cn0NCiMgR3LDoWZpY28NCmdncGxvdChkYXRvcywgYWVzKHggPSByZWdpb24sIHkgPSB0YXNhX2xldGFsaWRhZCwgZmlsbCA9IHJlZ2lvbikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJUYXNhIGRlIExldGFsaWRhZCBwb3IgUmVnacOzbiIsDQogICAgICAgeCA9ICJSZWdpw7NuIiwgeSA9ICJUYXNhIGRlIExldGFsaWRhZCAoJSkiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCkNvbmNsdXNpw7NuIExhIFRhc2EgZGUgTGV0YWxpZGFkIGVzIHVuIGluZGljYWRvciBjbGF2ZSBwYXJhIGV2YWx1YXIgbGEgc2V2ZXJpZGFkIGRlIHVuYSBlbmZlcm1lZGFkIHkgZWwgaW1wYWN0byBkZSBsYXMgaW50ZXJ2ZW5jaW9uZXMgbcOpZGljYXMuIFVuIGFuw6FsaXNpcyBkZXRhbGxhZG8gcHVlZGUgYXl1ZGFyIGEgaWRlbnRpZmljYXIgw6FyZWFzIHByaW9yaXRhcmlhcyBwYXJhIGxhIGFzaWduYWNpw7NuIGRlIHJlY3Vyc29zLg0KDQpUYXNhIGRlIE5hdGFsaWRhZCDCv1F1w6kgZXMgbGEgVGFzYSBkZSBOYXRhbGlkYWQ/IExhIFRhc2EgZGUgTmF0YWxpZGFkIG1pZGUgZWwgbsO6bWVybyBkZSBuYWNpbWllbnRvcyBlbiB1bmEgcG9ibGFjacOzbiBwb3IgY2FkYSAxLDAwMCBoYWJpdGFudGVzIGR1cmFudGUgdW4gcGVyw61vZG8gZGV0ZXJtaW5hZG8uDQoNCkVzIHVuYSBtw6l0cmljYSBjbGF2ZSBwYXJhIGFuYWxpemFyIGxhIGRpbsOhbWljYSBwb2JsYWNpb25hbCB5IGV2YWx1YXIgdGVuZGVuY2lhcyBkZW1vZ3LDoWZpY2FzLg0KDQpGw7NybXVsYSBMYSBmw7NybXVsYSBnZW5lcmFsIHBhcmEgY2FsY3VsYXIgbGEgVGFzYSBkZSBOYXRhbGlkYWQgZXM6DQoNClRhc2EgZGUgbmF0YWxpZGFkID0gbnVtZXJvIGRlIG5hY2ltaWVudG9zIC8gdG90YWwgZGUgbGEgcG9ibGFjacOzbiBcKiAxMDAwID0NCg0KSW1wbGVtZW50YWNpw7NuIGVuIFIgQ2FsY3VsZW1vcyBsYSBUYXNhIGRlIE5hdGFsaWRhZCB1c2FuZG8gdW4gZWplbXBsbyBwcsOhY3RpY286DQoNCmBgYHtyfQ0KIyBEYXRvcw0KDQpuYWNpbWllbnRvcyA8LSAxNTAwICAjIE7Dum1lcm8gZGUgbmFjaW1pZW50b3MgZW4gdW4gYcOxbw0KcG9ibGFjaW9uX3RvdGFsIDwtIDEwMDAwMCAgIyBQb2JsYWNpw7NuIHRvdGFsIGVuIGVzZSBhw7FvDQoNCiMgQ8OhbGN1bG8gZGUgbGEgdGFzYSBkZSBuYXRhbGlkYWQNCnRhc2FfbmF0YWxpZGFkIDwtIChuYWNpbWllbnRvcyAvIHBvYmxhY2lvbl90b3RhbCkgKiAxMDAwDQoNCiMgUmVzdWx0YWRvDQpjYXQoIlRhc2EgZGUgbmF0YWxpZGFkOiIsIHRhc2FfbmF0YWxpZGFkLCAibmFjaW1pZW50b3MgcG9yIGNhZGEgMSwwMDAgaGFiaXRhbnRlc1xuIikNCmBgYA0KDQpgYGB7cn0NCmRhdG9zDQpgYGANCg0KYGBge3J9DQojIENhbGN1bGFyIHRhc2FzIGRlIG5hdGFsaWRhZA0KZGF0b3MkdGFzYV9uYXRhbGlkYWQgPC0gKGRhdG9zJG5hY2ltaWVudG9zIC8gZGF0b3MkcG9ibGFjaW9uKSAqIDEwMDANCg0KIyBHcsOhZmljbw0KZ2dwbG90KGRhdG9zLCBhZXMoeCA9IHJlZ2lvbiwgeSA9IHRhc2FfbmF0YWxpZGFkLCBmaWxsID0gcmVnaW9uKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gIlRhc2EgZGUgTmF0YWxpZGFkIHBvciBSZWdpw7NuIiwNCiAgICAgICB4ID0gIlJlZ2nDs24iLCB5ID0gIlRhc2EgZGUgTmF0YWxpZGFkIChwb3IgMSwwMDAgaGFiaXRhbnRlcykiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCkNvbmNsdXNpw7NuIExhIFRhc2EgZGUgTmF0YWxpZGFkIGVzIHVuYSBoZXJyYW1pZW50YSBlc2VuY2lhbCBlbiBlcGlkZW1pb2xvZ8OtYSBwYXJhIGVudGVuZGVyIGxhIGRpbsOhbWljYSBwb2JsYWNpb25hbC4gVXNhcmxhIGVuIGNvbmp1bnRvIGNvbiBvdHJhcyBtw6l0cmljYXMgcHVlZGUgcHJvcG9yY2lvbmFyIHVuYSB2aXNpw7NuIGNvbXBsZXRhIGRlIGxhcyB0ZW5kZW5jaWFzIGRlbW9ncsOhZmljYXMgeSBuZWNlc2lkYWRlcyBkZSBzYWx1ZCBww7pibGljYS4NCg0KVmVudGFqYXMgZGUgZmxleHRhYmxlOiBJbnRlcmFjdGl2aWRhZDogUGVybWl0ZSBjcmVhciB0YWJsYXMgZsOhY2lsbWVudGUgZXhwb3J0YWJsZXMgYSBXb3JkIG8gUG93ZXJQb2ludC4NCg0KRXN0aWxvIFBlcnNvbmFsaXphYmxlOiBDYW1iaWEgY29sb3JlcywgZnVlbnRlcyB5IGJvcmRlcyBzaW4gY29tcGxpY2FjaW9uZXMuDQoNClNvcG9ydGUgcGFyYSBSZXBvcnRlczogSWRlYWwgcGFyYSBpbmZvcm1lcyBlbiBmb3JtYXRvcyByZXByb2R1Y2libGVzLg0KDQpBbWJhcyBvcGNpb25lcyAoa2FibGVFeHRyYSB5IGZsZXh0YWJsZSkgc29uIG3DoXMgc2ltcGxlcyB5IHZlcnPDoXRpbGVzIHF1ZSBndGFibGUgcGFyYSBlc3RlIGNhc28gZGUgdXNvLg0KDQpgYGB7cn0NCg0KI2luc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiZmxleHRhYmxlIikNCmxpYnJhcnkoZmxleHRhYmxlKQ0KYGBgDQoNCmBgYHtyfQ0KIyBDcmVhciBlbCBjb25qdW50byBkZSBkYXRvcw0KZGF0b3MgPC0gZGF0YS5mcmFtZSgNCiAgcmVnaW9uID0gYygiTm9ydGUiLCAiU3VyIiwgIkVzdGUiLCAiT2VzdGUiKSwNCiAgcG9ibGFjaW9uID0gYygxMDAwMDAsIDc1MDAwLCA1MDAwMCwgNjAwMDApLA0KICBuYWNpbWllbnRvcyA9IGMoMTIwMCwgODAwLCA2MDAsIDcwMCksDQogIG11ZXJ0ZXMgPSBjKDkwMCwgNTAwLCAzMDAsIDQwMCksDQogIGNhc29zX2VuZmVybWVkYWQgPSBjKDE1MDAsIDEwMDAsIDgwMCwgOTAwKSwNCiAgZmFsbGVjaWRvc19lbmZlcm1lZGFkID0gYygyMDAsIDE1MCwgMTAwLCAxMjApDQopDQoNCiMgQ2FsY3VsYXIgbGFzIHRhc2FzDQpkYXRvcyR0YXNhX25hdGFsaWRhZCA8LSAoZGF0b3MkbmFjaW1pZW50b3MgLyBkYXRvcyRwb2JsYWNpb24pICogMTAwMA0KZGF0b3MkdGFzYV9tb3J0YWxpZGFkIDwtIChkYXRvcyRtdWVydGVzIC8gZGF0b3MkcG9ibGFjaW9uKSAqIDEwMDANCmRhdG9zJHRhc2FfaW5jaWRlbmNpYSA8LSAoZGF0b3MkY2Fzb3NfZW5mZXJtZWRhZCAvIGRhdG9zJHBvYmxhY2lvbikgKiAxMDAwDQpkYXRvcyR0YXNhX2xldGFsaWRhZCA8LSAoZGF0b3MkZmFsbGVjaWRvc19lbmZlcm1lZGFkIC8gZGF0b3MkY2Fzb3NfZW5mZXJtZWRhZCkgKiAxMDANCg0KIyBSZWRvbmRlYXIgc29sbyBjb2x1bW5hcyBudW3DqXJpY2FzDQpkYXRvc19yZWRvbmRlYWRvcyA8LSBkYXRvcyAlPiUNCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHJvdW5kLCAyKQ0KDQojIENyZWFyIGxhIHRhYmxhIGNvbiBmbGV4dGFibGUNCmZsZXh0YWJsZShkYXRvc19yZWRvbmRlYWRvcykgJT4lDQogIGF1dG9maXQoKQ0KYGBgDQoNCkPDoWxjdWxvIGRlIEZyZWN1ZW5jaWFzDQoNCkVsIGFuw6FsaXNpcyBkZSBmcmVjdWVuY2lhcyBlcyB1bmEgdMOpY25pY2EgYsOhc2ljYSBwZXJvIGVzZW5jaWFsIGVuIGVwaWRlbWlvbG9nw61hLiBQZXJtaXRlIGRlc2NyaWJpciBjw7NtbyBzZSBkaXN0cmlidXllbiBsb3MgZGF0b3MgZW4gY2F0ZWdvcsOtYXMgZXNwZWPDrWZpY2FzIHkgZXMgZXNwZWNpYWxtZW50ZSDDunRpbCBwYXJhIGFuYWxpemFyIHZhcmlhYmxlcyBjYXRlZ8OzcmljYXMgY29tbyBzZXhvLCBncnVwbyBkZSBlZGFkLCBvIGVzdGFkbyBkZSBlbmZlcm1lZGFkLg0KDQpDYXJnYXIgTGlicmVyw61hcyBQcmltZXJvLCBjYXJnYW1vcyBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzIHBhcmEgZWwgYW7DoWxpc2lzOg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpICAgIA0KIyBQYXJhIG1hbmlwdWxhY2nDs24gZGUgZGF0b3MgJT4lICU+JSAlPiUgJT4lICU+JSAgY29udHJvbCArIHNoaWZ0ICsgbSA9IA0KIyAlPiUgJT4lICU+JSAlPiUgJT4lICU+JSAlPiUgDQpsaWJyYXJ5KGdncGxvdDIpICAgIyBQYXJhIHZpc3VhbGl6YWNpw7NuIGRlIGRhdG9zDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KIyBjb250cm9sICsgYWx0ICsgKisgPSB+IA0KDQojaW5zdGFsbC5wYWNrYWdlcygiamFuaXRvciIpDQpsaWJyYXJ5KGphbml0b3IpICAgIyBQYXJhIGdlbmVyYXIgdGFibGFzIGRlIGZyZWN1ZW5jaWFzDQpgYGANCg0KQ3JlYXIgdW4gQ29uanVudG8gZGUgRGF0b3MgZGUgRWplbXBsbyBVc2FyZW1vcyB1biBkYXRhc2V0IGZpY3RpY2lvIHBhcmEgY2FsY3VsYXIgbGFzIGZyZWN1ZW5jaWFzOg0KDQpgYGB7cn0NCiMgQ3JlYXIgdW4gY29uanVudG8gZGUgZGF0b3MgZmljdGljaW8NCmRhdG9zIDwtIGRhdGEuZnJhbWUoDQogIHNleG8gPSBjKCJGIiwgIk0iLCAiRiIsICJGIiwgIk0iLCAiRiIsICJNIiwgIk0iLCAiRiIsICJNIiksDQogIGdydXBvX2VkYWQgPSBjKCIwLTE5IiwgIjIwLTM5IiwgIjIwLTM5IiwgIjQwLTU5IiwgIjQwLTU5IiwgIjYwKyIsICIyMC0zOSIsICI2MCsiLCAiNDAtNTkiLCAiMC0xOSIpDQopDQoNCiMgTW9zdHJhciBsb3MgcHJpbWVyb3MgZGF0b3MNCmhlYWQoZGF0b3MpDQpgYGANCg0KYGBge3J9DQpzdHIoZGF0b3MpDQpgYGANCg0KVGFibGFzIGRlIEZyZWN1ZW5jaWFzIFRhYmxhIGRlIEZyZWN1ZW5jaWFzIGNvbiB0YWJsZSBQb2RlbW9zIGNhbGN1bGFyIGZyZWN1ZW5jaWFzIHNpbXBsZXMgdXNhbmRvIHRhYmxlOg0KDQpgYGB7cn0NCiMgQ2FsY3VsYXIgZnJlY3VlbmNpYXMgcGFyYSBsYSB2YXJpYWJsZSAic2V4byINCnRhYmxhX3NleG8gPC0gdGFibGUoZGF0b3Mkc2V4bykNCnRhYmxhX3NleG8NCmBgYA0KDQpUYWJsYSBkZSBGcmVjdWVuY2lhcyBDcnV6YWRhcyBjb24gdGFibGUgUGFyYSBhbmFsaXphciBkb3MgdmFyaWFibGVzOg0KDQpgYGB7cn0NCiMgVGFibGEgY3J1emFkYSBlbnRyZSAic2V4byIgeSAiZ3J1cG9fZWRhZCINCnRhYmxhX2NydXphZGEgPC0gdGFibGUoZGF0b3Mkc2V4bywgZGF0b3MkZ3J1cG9fZWRhZCkNCnRhYmxhX2NydXphZGENCmBgYA0KDQpUYWJsYXMgTGltcGlhcyBjb24gamFuaXRvciBFbCBwYXF1ZXRlIGphbml0b3IgZ2VuZXJhIHRhYmxhcyBkZSBmcmVjdWVuY2lhcyBvcmRlbmFkYXM6DQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoImphbml0b3IiKQ0KbGlicmFyeShqYW5pdG9yKQ0KIyBUYWJsYSBkZSBmcmVjdWVuY2lhcyBjb24gcHJvcG9yY2lvbmVzDQoNCnRhYmxhX29yZGVuYWRhIDwtIGRhdG9zICU+JQ0KICB0YWJ5bChzZXhvKSAlPiUNCiAgYWRvcm5fdG90YWxzKCJyb3ciKSAlPiUNCiAgYWRvcm5fcGN0X2Zvcm1hdHRpbmcoKQ0KDQp0YWJsYV9vcmRlbmFkYQ0KYGBgDQoNCmBgYHtyfQ0KZmxleHRhYmxlKHRhYmxhX29yZGVuYWRhKQ0KYGBgDQoNClBhcXVldGUgamFuaXRvciDCv1F1w6kgZXMgamFuaXRvcj8gamFuaXRvciBlcyB1biBwYXF1ZXRlIGRpc2XDsWFkbyBwYXJhIGxpbXBpYXIgZGF0b3MgeSByZWFsaXphciBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvcyByw6FwaWRvcy4gRXMgcGFydGljdWxhcm1lbnRlIMO6dGlsIHBhcmEgbWFuZWphciB0YWJsYXMgeSBkYXRvcyBjYXRlZ8Ozcmljb3MsIGNvbW8gY2FsY3VsYXIgZnJlY3VlbmNpYXMgeSBwcm9wb3JjaW9uZXMuDQoNCkNhcmFjdGVyw61zdGljYXMgUHJpbmNpcGFsZXMgZGUgamFuaXRvcjogTGltcGllemEgZGUgTm9tYnJlcyBkZSBDb2x1bW5hczoNCg0KQ29udmllcnRlIG5vbWJyZXMgZGUgY29sdW1uYXMgZW4gZm9ybWF0byBsaW1waW8geSBjb25zaXN0ZW50ZSwgZWxpbWluYW5kbyBlc3BhY2lvcyBvIGNhcmFjdGVyZXMgZXNwZWNpYWxlcy4NCg0KYGBge3J9DQpsaWJyYXJ5KGphbml0b3IpDQpkYXRvczIgPC0gZGF0YS5mcmFtZSgiTm9tYnJlIENvbHVtbmEgMSIgPSBjKDEsIDIpLCAiT3RyYSBDb2x1bW5hIiA9IGMoMywgNCkpDQoNCmRhdG9zX2NsZWFuIDwtIGNsZWFuX25hbWVzKGRhdG9zMikgI2Z1bmNpw7NuIGNsZWFuX25hbWVzDQoNCnByaW50KGRhdG9zX2NsZWFuKSAgIyBub21icmVzOiBub21icmVfY29sdW1uYV8xLCBvdHJhX2NvbHVtbmENCmBgYA0KDQpUYWJsYXMgZGUgRnJlY3VlbmNpYXM6DQoNCkdlbmVyYSB0YWJsYXMgZGUgZnJlY3VlbmNpYXMgc2ltcGxlcyB5IGNydXphZGFzLg0KDQpJbmNsdXllIHRvdGFsZXMgeSBwb3JjZW50YWplcyBwYXJhIGZhY2lsaXRhciBsYSBpbnRlcnByZXRhY2nDs24uDQoNCmBgYHtyfQ0KbGlicmFyeShqYW5pdG9yKQ0KdGFibGEgPC0gZGF0b3MgJT4lIHRhYnlsKGdydXBvX2VkYWQpDQpgYGANCg0KYGBge3J9DQpwcmludCh0YWJsYSkNCmBgYA0KDQpgYGB7cn0NCnN0cihkYXRvcykNCmBgYA0KDQpUYWJsYXMgZGUgRnJlY3VlbmNpYXMgVGFibGEgZGUgRnJlY3VlbmNpYXMgY29uIHRhYmxlIFBvZGVtb3MgY2FsY3VsYXIgZnJlY3VlbmNpYXMgc2ltcGxlcyB1c2FuZG8gdGFibGU6DQoNCmBgYHtyfQ0KIyBDYWxjdWxhciBmcmVjdWVuY2lhcyBwYXJhIGxhIHZhcmlhYmxlICJzZXhvIg0KdGFibGFfc2V4byA8LSB0YWJsZShkYXRvcyRzZXhvKQ0KdGFibGFfc2V4bw0KYGBgDQoNClRhYmxhIGRlIEZyZWN1ZW5jaWFzIENydXphZGFzIGNvbiB0YWJsZSBQYXJhIGFuYWxpemFyIGRvcyB2YXJpYWJsZXM6DQoNCmBgYHtyfQ0KIyBUYWJsYSBjcnV6YWRhIGVudHJlICJzZXhvIiB5ICJncnVwb19lZGFkIg0KdGFibGFfY3J1emFkYSA8LSB0YWJsZShkYXRvcyRzZXhvLCBkYXRvcyRncnVwb19lZGFkKQ0KdGFibGFfY3J1emFkYQ0KYGBgDQoNClRhYmxhcyBMaW1waWFzIGNvbiBqYW5pdG9yIEVsIHBhcXVldGUgamFuaXRvciBnZW5lcmEgdGFibGFzIGRlIGZyZWN1ZW5jaWFzIG9yZGVuYWRhczoNCg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygiamFuaXRvciIpDQpsaWJyYXJ5KGphbml0b3IpDQojIFRhYmxhIGRlIGZyZWN1ZW5jaWFzIGNvbiBwcm9wb3JjaW9uZXMNCg0KdGFibGFfb3JkZW5hZGEgPC0gZGF0b3MgJT4lDQogIHRhYnlsKHNleG8pICU+JQ0KICBhZG9ybl90b3RhbHMoInJvdyIpICU+JQ0KICBhZG9ybl9wY3RfZm9ybWF0dGluZygpDQoNCnRhYmxhX29yZGVuYWRhDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGZsZXh0YWJsZSkNCmBgYA0KDQpgYGB7cn0NCmZsZXh0YWJsZSh0YWJsYV9vcmRlbmFkYSkNCg0KYGBgDQoNClBhcXVldGUgamFuaXRvciDCv1F1w6kgZXMgamFuaXRvcj8gamFuaXRvciBlcyB1biBwYXF1ZXRlIGRpc2XDsWFkbyBwYXJhIGxpbXBpYXIgZGF0b3MgeSByZWFsaXphciBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvcyByw6FwaWRvcy4gRXMgcGFydGljdWxhcm1lbnRlIMO6dGlsIHBhcmEgbWFuZWphciB0YWJsYXMgeSBkYXRvcyBjYXRlZ8Ozcmljb3MsIGNvbW8gY2FsY3VsYXIgZnJlY3VlbmNpYXMgeSBwcm9wb3JjaW9uZXMuDQoNCkNhcmFjdGVyw61zdGljYXMgUHJpbmNpcGFsZXMgZGUgamFuaXRvcjogTGltcGllemEgZGUgTm9tYnJlcyBkZSBDb2x1bW5hczoNCg0KQ29udmllcnRlIG5vbWJyZXMgZGUgY29sdW1uYXMgZW4gZm9ybWF0byBsaW1waW8geSBjb25zaXN0ZW50ZSwgZWxpbWluYW5kbyBlc3BhY2lvcyBvIGNhcmFjdGVyZXMgZXNwZWNpYWxlcy4NCg0KYGBge3J9DQpsaWJyYXJ5KGphbml0b3IpDQpkYXRvczIgPC0gZGF0YS5mcmFtZSgiTm9tYnJlIENvbHVtbmEgMSIgPSBjKDEsIDIpLCAiT3RyYSBDb2x1bW5hIiA9IGMoMywgNCkpDQoNCmRhdG9zX2NsZWFuIDwtIGNsZWFuX25hbWVzKGRhdG9zMikgI2Z1bmNpw7NuIGNsZWFuX25hbWVzDQoNCnByaW50KGRhdG9zX2NsZWFuKSAgIyBub21icmVzOiBub21icmVfY29sdW1uYV8xLCBvdHJhX2NvbHVtbmENCmBgYA0KDQpUYWJsYXMgZGUgRnJlY3VlbmNpYXM6DQoNCkdlbmVyYSB0YWJsYXMgZGUgZnJlY3VlbmNpYXMgc2ltcGxlcyB5IGNydXphZGFzLg0KDQpJbmNsdXllIHRvdGFsZXMgeSBwb3JjZW50YWplcyBwYXJhIGZhY2lsaXRhciBsYSBpbnRlcnByZXRhY2nDs24uDQoNCmBgYHtyfQ0KbGlicmFyeShqYW5pdG9yKQ0KDQp0YWJsYSA8LSBkYXRvcyAlPiUgdGFieWwoZ3J1cG9fZWRhZCkNCg0KcHJpbnQodGFibGEpDQpgYGANCg0KVGFibGFzIE9yZGVuYWRhcyB5IFByb3BvcmNpb25lczoNCg0KQcOxYWRlIHRvdGFsZXMgeSBwb3JjZW50YWplcyBhIHRhYmxhcyBkZSBtYW5lcmEgYXV0b23DoXRpY2EuDQoNCmBgYHtyfQ0KZ3J1cG9lZGFkPC10YWJsYSAlPiUgYWRvcm5fdG90YWxzKCJyb3ciKSAlPiUgYWRvcm5fcGN0X2Zvcm1hdHRpbmcoKQ0KDQpncnVwb2VkYWQNCmBgYA0KDQpgYGB7cn0NCmZsZXh0YWJsZShncnVwb2VkYWQpDQpgYGANCg0KRGV0ZWNjacOzbiBkZSBEdXBsaWNhZG9zOg0KDQpJZGVudGlmaWNhIHZhbG9yZXMgZHVwbGljYWRvcyBlbiB0dXMgZGF0b3MuDQoNCmBgYHtyfQ0KZGF0b3MzIDwtIGRhdGEuZnJhbWUoaWQgPSBjKDEsIDEsIDIsIDMpLCB2YWxvciA9IGMoMTAsIDEwLCAyMCwgMzApKQ0KDQpkYXRvczMNCmBgYA0KDQpgYGB7cn0NCmdldF9kdXBlcyhkYXRvczMsIGlkKQ0KYGBgDQoNCsK/Q3XDoW5kbyB1c2FyIGphbml0b3I/IEN1YW5kbyBuZWNlc2l0YXMgY2FsY3VsYXIgZnJlY3VlbmNpYXMgcsOhcGlkYW1lbnRlLg0KDQpQYXJhIGxpbXBpYXIgbm9tYnJlcyBkZSBjb2x1bW5hcyBhdXRvbcOhdGljYW1lbnRlLg0KDQpBbCB0cmFiYWphciBjb24gZGF0b3MgY2F0ZWfDs3JpY29zIGRvbmRlIGxhcyBwcm9wb3JjaW9uZXMgeSB0b3RhbGVzIHNvbiBpbXBvcnRhbnRlcy4NCg0KVmlzdWFsaXphY2nDs24gZGUgRnJlY3VlbmNpYXMgR3LDoWZpY28gZGUgQmFycmFzIGNvbiBnZ3Bsb3QyIFVuIGdyw6FmaWNvIGRlIGJhcnJhcyBlcyBpZGVhbCBwYXJhIHZpc3VhbGl6YXIgZnJlY3VlbmNpYXMgY2F0ZWfDs3JpY2FzOg0KDQpgYGB7cn0NCiMgQ3JlYXIgdW4gZ3LDoWZpY28gZGUgYmFycmFzIHBhcmEgImdydXBvX2VkYWQiDQpnZ3Bsb3QoZGF0b3MsIGFlcyh4ID0gZ3J1cG9fZWRhZCwgZmlsbCA9IGdydXBvX2VkYWQpKSArDQogIGdlb21fYmFyKCkgKw0KICBsYWJzKHRpdGxlID0gIkZyZWN1ZW5jaWEgcG9yIEdydXBvIGRlIEVkYWQiLA0KICAgICAgIHggPSAiR3J1cG8gZGUgRWRhZCIsDQogICAgICAgeSA9ICJGcmVjdWVuY2lhIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCmRhdG9zICU+JSBnZ3Bsb3QoYWVzKGdydXBvX2VkYWQsIGZpbGw9IGdydXBvX2VkYWQpKSsNCiAgZ2VvbV9iYXIoKQ0KYGBgDQoNCkdyw6FmaWNvIGRlIFBhc3RlbCBjb24gZ2dwbG90MiBVbiBncsOhZmljbyBkZSBwYXN0ZWwgZXMgw7p0aWwgcGFyYSBtb3N0cmFyIHByb3BvcmNpb25lczoNCg0KYGBge3J9DQojIENhbGN1bGFyIHByb3BvcmNpb25lcw0KcHJvcG9yY2lvbmVzIDwtIGRhdG9zICU+JQ0KICBncm91cF9ieShzZXhvKSAlPiUNCiAgc3VtbWFyaXNlKGZyZWN1ZW5jaWEgPSBuKCkpICU+JQ0KICBtdXRhdGUocHJvcG9yY2lvbiA9IGZyZWN1ZW5jaWEgLyBzdW0oZnJlY3VlbmNpYSkpDQoNCiMgQ3JlYXIgdW4gZ3LDoWZpY28gZGUgcGFzdGVsDQpnZ3Bsb3QocHJvcG9yY2lvbmVzLCBhZXMoeCA9ICIiLCB5ID0gcHJvcG9yY2lvbiwgZmlsbCA9IHNleG8pKSArDQogIGdlb21fY29sKHdpZHRoID0gMSkgKw0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKw0KICAgdGhlbWVfdm9pZCgpKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gcG9yIFNleG8iKSANCmBgYA0KDQoNCmBgYHtyfQ0KZmxleHRhYmxlKHRhYmxhX29yZGVuYWRhKQ0KYGBgDQoNClRhYmxhcyB5IEdyw6FmaWNvcyBlbiB1biBSZXBvcnRlDQpDb21iaW5hciBSZXN1bHRhZG9zIGVuIHVuYSBUYWJsYSBSZXN1bWVuDQpQb2RlbW9zIGNvbWJpbmFyIGZyZWN1ZW5jaWFzIHkgcHJvcG9yY2lvbmVzIGVuIHVuYSB0YWJsYSBjbGFyYToNCg0KDQpgYGB7cn0NCiMgVGFibGEgcmVzdW1lbiBkZSBmcmVjdWVuY2lhcyB5IHByb3BvcmNpb25lcw0KdGFibGFfcmVzdW1lbiA8LSBkYXRvcyAlPiUNCiAgZ3JvdXBfYnkoc2V4bykgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBmcmVjdWVuY2lhID0gbigpLA0KICAgIHByb3BvcmNpb24gPSBuKCkgLyBucm93KGRhdG9zKQ0KICApDQoNCnRhYmxhX3Jlc3VtZW4NCmBgYA0KDQpFeHBvcnRhciBHcsOhZmljb3MgeSBUYWJsYXMNCkd1YXJkYXIgZ3LDoWZpY29zIHkgdGFibGFzIHBhcmEgaW5jbHVpcmxvcyBlbiByZXBvcnRlczoNCg0KYGBge3J9DQojIEd1YXJkYXIgZWwgZ3LDoWZpY28gZGUgYmFycmFzIGNvbW8gaW1hZ2VuDQpnZ3NhdmUoImZyZWN1ZW5jaWFfZ3J1cG9fZWRhZC5wbmciKQ0KYGBgDQoNCmBgYHtyfQ0KIyBFeHBvcnRhciBsYSB0YWJsYSByZXN1bWVuIGNvbW8gQ1NWDQp3cml0ZS5jc3YodGFibGFfcmVzdW1lbiwgInRhYmxhX3Jlc3VtZW4uY3N2IikNCmBgYA0KDQoNCk1lZGlkYXMgZGUgZnJlY3VlbmNpYQ0KTGFzIG1lZGlkYXMgZGUgZnJlY3VlbmNpYSBzb24gaGVycmFtaWVudGFzIGNsYXZlIGVuIGVwaWRlbWlvbG9nw61hIHBhcmEgY3VhbnRpZmljYXIgZWwgaW1wYWN0byBkZSBlbmZlcm1lZGFkZXMgZW4gdW5hIHBvYmxhY2nDs24uIExhcyBwcmluY2lwYWxlcyBtw6l0cmljYXMgc29uOg0KDQpQcmV2YWxlbmNpYTogUHJvcG9yY2nDs24gZGUgaW5kaXZpZHVvcyBlbmZlcm1vcyBlbiB1biBtb21lbnRvIGNvbmNyZXRvLg0KSW5jaWRlbmNpYSBhY3VtdWxhZGE6IFByb2JhYmlsaWRhZCBkZSBxdWUgdW4gaW5kaXZpZHVvIGVuZmVybWUgZHVyYW50ZSB1biBwZXLDrW9kby4NCkRlbnNpZGFkIGRlIGluY2lkZW5jaWE6IFZlbG9jaWRhZCBjb24gbGEgcXVlIGFwYXJlY2VuIG51ZXZvcyBjYXNvcyBlbiB1bmEgcG9ibGFjacOzbi4NCkRhdGFzZXQgU2ltdWxhZG8NCkNyZWFyIHVuIERhdGFzZXQgRmljdGljaW8NClVzYW1vcyB1biBjb25qdW50byBkZSBkYXRvcyBzaW11bGFkbyBwYXJhIGNhbGN1bGFyIGVzdGFzIG3DqXRyaWNhcy4NCg0KYGBge3J9DQojIENyZWFyIHVuIGNvbmp1bnRvIGRlIGRhdG9zIGZpY3RpY2lvDQpkYXRvcyA8LSBkYXRhLmZyYW1lKA0KICBpZCA9IDE6MTAwLCAgIyBJZGVudGlmaWNhY2nDs24gZGUgaW5kaXZpZHVvcw0KICBpbmljaW9fcmllc2dvID0gYyhyZXAoMCwgODApLCByZXAoMSwgMjApKSwgICMgMCA9IG5vIGVuZmVybW8gYWwgaW5pY2lvIDE9IGVuZmVybW8gDQogIGNhc29zX251ZXZvcyA9IGMocmVwKDAsIDkwKSwgcmVwKDEsIDEwKSksICAjIENhc29zIG51ZXZvcyBhbCBmaW5hbCBkZWwgcGVyw61vZG8NCiAgdGllbXBvX29ic2VydmFjaW9uID0gYyhyZXAoMSwgNTApLCByZXAoMiwgMzApLCByZXAoMywgMjApKSAgIyBUaWVtcG8gb2JzZXJ2YWRvIGVuIGHDsW9zDQogICkNCg0KIyBNb3N0cmFyIGxvcyBwcmltZXJvcyBkYXRvcw0KaGVhZChkYXRvcykNCmBgYA0KDQpDw6FsY3VsbyBkZSBQcmV2YWxlbmNpYQ0Kwr9RdcOpIGVzIGxhIFByZXZhbGVuY2lhPw0KTGEgcHJldmFsZW5jaWEgbWlkZSBsYSBwcm9wb3JjacOzbiBkZSBwZXJzb25hcyBhZmVjdGFkYXMgcG9yIHVuYSBlbmZlcm1lZGFkIGVuIHVuIG1vbWVudG8gZGFkby4NCg0KRsOzcm11bGE6DQpQcmV2YWxlbmNpYSA9IGNhc29zIGV4aXN0ZW50ZXMgLyBwb2JsYWNpw7NuIHRvdGFsDQoNCmBgYHtyfQ0KIyBDYWxjdWxhciBwcmV2YWxlbmNpYSBhbCBpbmljaW8gZGVsIHBlcsOtb2RvDQpwb2JsYWNpb25fdG90YWwgPC0gbnJvdyhkYXRvcykNCnBvYmxhY2lvbl90b3RhbCA8LSAxMDANCg0KY2Fzb3NfZXhpc3RlbnRlcyA8LSAyMA0KDQpjYXNvc19leGlzdGVudGVzIDwtIHN1bShkYXRvcyRpbmljaW9fcmllc2dvID09IDEpDQoNCmNhc29zX2V4aXN0ZW50ZXMgPC0gc3VtKGRhdG9zJGluaWNpb19yaWVzZ28gIT0gMCkNCg0KcHJldmFsZW5jaWEgPC0gY2Fzb3NfZXhpc3RlbnRlcyAvIHBvYmxhY2lvbl90b3RhbA0KDQoNCmNhdCgiUHJldmFsZW5jaWE6Iiwgcm91bmQocHJldmFsZW5jaWEgKiAxMDAsIDIpLCAiJVxuIikNCmBgYA0KYGBge3J9DQpjYXQoIlByZXZhbGVuY2lhOiIsIHByZXZhbGVuY2lhKjEwMCwgIiVcbiIpDQpgYGANCkludGVycHJldGFjacOzbjogRXN0ZSB2YWxvciBpbmRpY2EgZWwgcG9yY2VudGFqZSBkZSBsYSBwb2JsYWNpw7NuIGFmZWN0YWRhIGFsIGluaWNpbyBkZWwgZXN0dWRpby4NCg0KQ8OhbGN1bG8gZGUgSW5jaWRlbmNpYSBBY3VtdWxhZGENCsK/UXXDqSBlcyBsYSBJbmNpZGVuY2lhIEFjdW11bGFkYT8NCkxhIGluY2lkZW5jaWEgYWN1bXVsYWRhIG1pZGUgbGEgcHJvcG9yY2nDs24gZGUgbnVldm9zIGNhc29zIGVuIHVuYSBwb2JsYWNpw7NuIGVuIHJpZXNnbyBkdXJhbnRlIHVuIHBlcsOtb2RvLg0KDQpGw7NybXVsYToNCg0KSW5jaWRlbmNpYSBhY3VtdWxhZGEgPSBjYXNvcyBudWV2b3Mgb2JzZXJ2YWRvcyAvIHBvYmxhY2nDs24gZW4gcmllc2dvIGFsIGluaWNpbw0KDQpgYGB7cn0NCiMgQ2FsY3VsYXIgaW5jaWRlbmNpYSBhY3VtdWxhZGENCmNhc29zX251ZXZvcyA8LSBzdW0oZGF0b3MkY2Fzb3NfbnVldm9zKQ0KDQpjYXNvc19udWV2b3MgPC0gMTANCg0KcG9ibGFjaW9uX3JpZXNnbyA8LSBzdW0oZGF0b3MkaW5pY2lvX3JpZXNnbyA9PSAwKQ0KDQpwb2JsYWNpb25fcmllc2dvIDwtIHN1bShkYXRvcyRpbmljaW9fcmllc2dvICE9IDEpDQoNCnBvYmxhY2lvbl9yaWVzZ28gPC0gODANCg0KaW5jaWRlbmNpYV9hY3VtdWxhZGEgPC0gY2Fzb3NfbnVldm9zIC8gcG9ibGFjaW9uX3JpZXNnbw0KDQpjYXQoIkluY2lkZW5jaWEgQWN1bXVsYWRhOiIsIHJvdW5kKGluY2lkZW5jaWFfYWN1bXVsYWRhICogMTAwLCAyKSwgIiVcbiIpDQpgYGANCg0KSW50ZXJwcmV0YWNpw7NuOiBFc3RlIHZhbG9yIGluZGljYSBlbCByaWVzZ28gZGUgZGVzYXJyb2xsYXIgbGEgZW5mZXJtZWRhZCBkdXJhbnRlIGVsIHBlcsOtb2RvIGRlIG9ic2VydmFjacOzbi4NCg0KQ8OhbGN1bG8gZGUgRGVuc2lkYWQgZGUgSW5jaWRlbmNpYQ0Kwr9RdcOpIGVzIGxhIERlbnNpZGFkIGRlIEluY2lkZW5jaWE/DQpMYSBkZW5zaWRhZCBkZSBpbmNpZGVuY2lhIG1pZGUgbGEgdmVsb2NpZGFkIGNvbiBsYSBxdWUgYXBhcmVjZW4gbnVldm9zIGNhc29zIGVuIHVuYSBwb2JsYWNpw7NuIGR1cmFudGUgcGVyw61vZG9zIGRlIHRpZW1wbyBhY3VtdWxhZG9zLg0KDQpGw7NybXVsYToNCmRlbnNpZGFkIGRlIGluY2lkZW5jaWEgPSBjYXNvcyBudWV2b3Mgb2JzZXJ2YWRvcyAvIMOxc3VtYSBkZSBsb3MgcGVyw61vZGVzIGRlIHJpZXNnbw0KDQpgYGB7cn0NCiMgQ2FsY3VsYXIgZGVuc2lkYWQgZGUgaW5jaWRlbmNpYQ0KdGllbXBvX3RvdGFsIDwtIHN1bShkYXRvcyR0aWVtcG9fb2JzZXJ2YWNpb24pDQoNCmRlbnNpZGFkX2luY2lkZW5jaWEgPC0gY2Fzb3NfbnVldm9zIC8gdGllbXBvX3RvdGFsDQoNCmNhdCgiRGVuc2lkYWQgZGUgSW5jaWRlbmNpYToiLCByb3VuZChkZW5zaWRhZF9pbmNpZGVuY2lhLCAyKSwgImNhc29zIHBvciBwZXJzb25hLWHDsW9cbiIpDQpgYGANCg0KSW50ZXJwcmV0YWNpw7NuOiBFc3RlIHZhbG9yIHJlcHJlc2VudGEgY3XDoW50b3MgY2Fzb3MgbnVldm9zIHNlIGdlbmVyYW4gcG9yIHBlcnNvbmEtYcOxby4NCg0KVmlzdWFsaXphY2nDs24gZGUgbGFzIE3DqXRyaWNhcw0KR3LDoWZpY28gQ29tcGFyYXRpdm8NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgQ3JlYXIgZGF0b3MgcGFyYSBlbCBncsOhZmljbw0KcmVzdWx0YWRvcyA8LSBkYXRhLmZyYW1lKA0KICBtZWRpZGEgPSBjKCJQcmV2YWxlbmNpYSIsICJJbmNpZGVuY2lhIEFjdW11bGFkYSIsICJEZW5zaWRhZCBkZSBJbmNpZGVuY2lhIiksDQogIHZhbG9yID0gYyhwcmV2YWxlbmNpYSAqIDEwMCwgaW5jaWRlbmNpYV9hY3VtdWxhZGEgKiAxMDAsIGRlbnNpZGFkX2luY2lkZW5jaWEpDQopDQoNCiMgR3LDoWZpY28gZGUgYmFycmFzDQpnZ3Bsb3QocmVzdWx0YWRvcywgYWVzKHggPSBtZWRpZGEsIHkgPSB2YWxvciwgZmlsbCA9IG1lZGlkYSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJNZWRpZGFzIGRlIEZyZWN1ZW5jaWEgRXBpZGVtaW9sw7NnaWNhIiwNCiAgICAgICB4ID0gIk1lZGlkYSIsIHkgPSAiVmFsb3IgKCUpIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoNCkhlcnJhbWllbnRhcyBhZGljaW9uYWxlcw0KTsO6bWVybyBiw6FzaWNvIGRlIFJlcHJvZHVjY2nDs24gUjANCkFhbGd1bmFzIGhlcnJhbWllbnRhcyBhZGljaW9uYWxlcyB5IG1vZGVybmFzIHF1ZSBzZSB1c2FuIHBhcmEgYW5hbGl6YXIgZWwgaW1wYWN0byBkZSBlbmZlcm1lZGFkZXMgZW4gdW5hIHBvYmxhY2nDs24gaW5jbHV5ZW46DQoNCkVsIG7Dum1lcm8gYsOhc2ljbyBkZSByZXByb2R1Y2Npw7NuIFLigoAgZXMgdW5hIG3DqXRyaWNhIGNsYXZlIGVuIGVwaWRlbWlvbG9nw61hIHBhcmEgZXN0aW1hciBjdcOhbnRvcyBjYXNvcyBzZWN1bmRhcmlvcyBnZW5lcmEgdW4gY2FzbyBpbmljaWFsIGVuIHVuYSBwb2JsYWNpw7NuIGNvbXBsZXRhbWVudGUgc3VzY2VwdGlibGUuIEVzIGVzZW5jaWFsIHBhcmEgZXZhbHVhciBlbCBwb3RlbmNpYWwgZGUgcHJvcGFnYWNpw7NuIGRlIGVuZmVybWVkYWRlcyBpbmZlY2Npb3NhcyBjb21vIGVsIENPVklELTE5Lg0KDQpFbCBuw7ptZXJvIGLDoXNpY28gZGUgcmVwcm9kdWNjacOzbiBS4oKAIGluZGljYSBlbCBwcm9tZWRpbyBkZSBjYXNvcyBzZWN1bmRhcmlvcyBnZW5lcmFkb3MgcG9yIHVuIGNhc28gaW5pY2lhbCBlbiB1bmEgcG9ibGFjacOzbiBjb21wbGV0YW1lbnRlIHN1c2NlcHRpYmxlLg0KDQpDw7NtbyBjYWxjdWxhciBS4oKADQpFbCBjw6FsY3VsbyBkZSBS4oKAIHB1ZWRlIHJlYWxpemFyc2UgdXNhbmRvIHZhcmlhcyBtZXRvZG9sb2fDrWFzLiBVbmEgZGUgbGFzIG3DoXMgY29tdW5lcyBzZSBiYXNhIGVuIGxhIHJlbGFjacOzbjoNCg0KUjAgPSDOsiB4IEQNCg0KRG9uZGU6DQoNCs6yICh0YXNhIGRlIHRyYW5zbWlzacOzbik6IFByb2JhYmlsaWRhZCBkZSBxdWUgdW5hIHBlcnNvbmEgaW5mZWN0YWRhIHRyYW5zbWl0YSBsYSBlbmZlcm1lZGFkIHBvciB1bmlkYWQgZGUgdGllbXBvLg0KDQpEIChkdXJhY2nDs24gaW5mZWNjaW9zYSk6IFRpZW1wbyBwcm9tZWRpbyBkdXJhbnRlIGVsIGN1YWwgdW5hIHBlcnNvbmEgaW5mZWN0YWRhIHB1ZWRlIHRyYW5zbWl0aXIgbGEgZW5mZXJtZWRhZC4NCg0KUGFyYSBjYWxjdWxhcmxvIHVzYW5kbyBkYXRvcyByZWFsZXMgZGVsIENPVklELTE5LCBwb2RlbW9zIHVzYXIgdW4gZGF0YS5mcmFtZSBzaW11bGFkbyBvIGRhdG9zIHJlYWxlcyBzaSBzZSBkaXNwb25lIGRlIGVsbG9zLg0KDQpVc2Ftb3MgdW4gY29uanVudG8gZGUgZGF0b3MgcXVlIHNpbXVsYSBsYSBwcm9wYWdhY2nDs24gZGVsIENPVklELTE5IGVuIHVuYSBwb2JsYWNpw7NuLg0KDQpgYGB7cn0NCiMjIERhdGFzZXQgU2ltdWxhZG8gZGUgQ09WSUQtMTkNCg0Kc2V0LnNlZWQoMTIzKQ0KDQpkYXRvcyA8LSBkYXRhLmZyYW1lKA0KICBpZCA9IDE6MzAsDQogIGZlY2hhID0gc2VxKGFzLkRhdGUoIjIwMjAtMDMtMDEiKSwgYXMuRGF0ZSgiMjAyMC0wMy0zMCIpLCBieSA9ICJkYXlzIiksDQogIG51ZXZvc19jYXNvcyA9IHJvdW5kKHJ1bmlmKDMwLCA1MCwgMTUwKSksICAjIE51ZXZvcyBjYXNvcyBkaWFyaW9zDQogIHJlY3VwZXJhZG9zID0gcm91bmQocnVuaWYoMzAsIDMwLCAxMDApKSwgICMgUmVjdXBlcmFjaW9uZXMgZGlhcmlhcw0KICBmYWxsZWNpZG9zID0gcm91bmQocnVuaWYoMzAsIDEsIDEwKSkpICAgICAgIyBGYWxsZWNpbWllbnRvcyBkaWFyaW9zDQoNCg0KIyBNb3N0cmFyIGxvcyBwcmltZXJvcyBkYXRvcw0KaGVhZChkYXRvcykNCmBgYA0KDQpgYGB7cn0NClZpZXcoZGF0b3MpDQpgYGANCg0KQ2FsY3VsYXIgUuKCgDogTcOpdG9kbyBTaW1wbGlmaWNhZG8NCkRlZmluaWNpw7NuDQpQYXJhIGVzdGltYXIgUuKCgCwgbmVjZXNpdGFtb3M6DQoNCkR1cmFjacOzbiBpbmZlY2Npb3NhIHByb21lZGlvIChEKTogQXN1bWltb3MgMTAgZMOtYXMgcGFyYSBDT1ZJRC0xOS4NCg0KQ3JlY2ltaWVudG8gZXhwb25lbmNpYWwgKM67KTogQ2FsY3VsYWRvIGEgcGFydGlyIGRlIGxhIHRhc2EgZGUgbnVldm9zIGNhc29zIGRpYXJpb3MuDQoNClBhc28gMTogQ2FsY3VsYXIgQ3JlY2ltaWVudG8gRGlhcmlvDQoNCg0KYGBge3J9DQojIENyZWNpbWllbnRvIGRpYXJpbyBkZSBjYXNvcw0KZGF0b3MkY3JlY2ltaWVudG8gPC0gYyhOQSwgZGlmZihkYXRvcyRudWV2b3NfY2Fzb3MpKQ0KDQojIENhbGN1bGFyIGVsIHByb21lZGlvIGRlbCBjcmVjaW1pZW50byBkaWFyaW8NCmxhbWJkYSA8LSBtZWFuKGRhdG9zJGNyZWNpbWllbnRvLCBuYS5ybSA9IFRSVUUpDQoNCmNhdCgiQ3JlY2ltaWVudG8gZGlhcmlvIHByb21lZGlvICjOuyk6Iiwgcm91bmQobGFtYmRhLCAyKSwgImNhc29zIHBvciBkw61hXG4iKQ0KYGBgDQoNClBhc28gMjogQ2FsY3VsYXIgUuKCgA0KDQpgYGB7cn0NCiMgQXN1bWltb3MgdW5hIGR1cmFjacOzbiBpbmZlY2Npb3NhIHByb21lZGlvIEQgPSAxMCBkw61hcw0KRCA8LSAxMA0KDQojIEVzdGltYWNpw7NuIGRlIFLigoANClIwIDwtIGxhbWJkYSAqIEQNCmNhdCgiTsO6bWVybyBiw6FzaWNvIGRlIHJlcHJvZHVjY2nDs24gKFLigoApOiIsIHJvdW5kKFIwLCAyKSwgIlxuIikNCmBgYA0KDQpWaXN1YWxpemFjacOzbiBkZWwgTsO6bWVybyBS4oKADQpHcsOhZmljbyBkZSBOdWV2b3MgQ2Fzb3MNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCmdncGxvdChkYXRvcywgYWVzKHggPSBmZWNoYSwgeSA9IG51ZXZvc19jYXNvcykpICsNCiAgZ2VvbV9saW5lKGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJOdWV2b3MgQ2Fzb3MgRGlhcmlvcyBkZSBDT1ZJRC0xOSIsDQogICAgICAgeCA9ICJGZWNoYSIsIHkgPSAiTnVldm9zIENhc29zIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoNClJlZmxleGnDs24NCsK/Q8OzbW8gaW5mbHV5ZSBsYSBkdXJhY2nDs24gaW5mZWNjaW9zYSBwcm9tZWRpbyAoRCkgZW4gZWwgY8OhbGN1bG8gZGUgUuKCgD8NCg0Kwr9RdcOpIGludGVydmVuY2lvbmVzIChjb21vIGN1YXJlbnRlbmFzIG8gdmFjdW5hY2nDs24pIHB1ZWRlbiByZWR1Y2lyIM6yIHksIHBvciBlbmRlLCBS4oKAPw0KDQrCv1F1w6kgc2lnbmlmaWNhIHVuIFLigoAgPiAxIHBhcmEgbGEgcHJvcGFnYWNpw7NuIGRlIGxhIGVuZmVybWVkYWQ/DQoNCkRldGFsbGVzIGRlbCBFamVtcGxvDQpEdXJhY2nDs24gSW5mZWNjaW9zYSBQcm9tZWRpbyAoRCk6DQpTZSBwdWVkZSBhanVzdGFyIGNvbiBiYXNlIGVuIGV2aWRlbmNpYSBjbMOtbmljYSwgY29tbyBlc3R1ZGlvcyBxdWUgZXN0aW1lbiBjdcOhbnRvIHRpZW1wbyBsb3MgcGFjaWVudGVzIGNvbiBDT1ZJRC0xOSBzb24gaW5mZWNjaW9zb3MuDQpEYXRvcyBTaW11bGFkb3M6DQpFbiBlc3RlIGVqZW1wbG8sIGxvcyBkYXRvcyBzb24gZ2VuZXJhZG9zIGFsZWF0b3JpYW1lbnRlLiBQdWVkZXMgcmVlbXBsYXphcmxvcyBjb24gZGF0b3MgcmVhbGVzIGRlbCBDT1ZJRC0xOSBkZSBmdWVudGVzIGNvbW8gT3VyIFdvcmxkIGluIERhdGEgbyBiYXNlcyBndWJlcm5hbWVudGFsZXMuDQpDcmVjaW1pZW50byBEaWFyaW8gKM67KToNCkVsIGNyZWNpbWllbnRvIHByb21lZGlvIHNlIGNhbGN1bGEgY29uIGxhIGRpZmVyZW5jaWEgZGlhcmlhIGRlIG51ZXZvcyBjYXNvcy4NCg0KVXNvIGRlIFBhcXVldGVzIEFkaWNpb25hbGVzDQpTaSBkZXNlYXMgdXNhciBoZXJyYW1pZW50YXMgZXNwZWPDrWZpY2FzIHBhcmEgZWwgY8OhbGN1bG8gZGUgUuKCgCwgcHVlZGVzIGV4cGxvcmFyIHBhcXVldGVzIGNvbW8gRXBpRXN0aW06DQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiRXBpRXN0aW0iKQ0KbGlicmFyeShFcGlFc3RpbSkNCg0KIyBDYWxjdWxhciBS4oKAIHVzYW5kbyBFcGlFc3RpbSAocmVlbXBsYXphciBjb24gZGF0b3MgcmVhbGVzKQ0KcmVzIDwtIGVzdGltYXRlX1IoDQogIGluY2lkID0gZGF0b3MkbnVldm9zX2Nhc29zLA0KICBtZXRob2QgPSAicGFyYW1ldHJpY19zaSIsDQogIGNvbmZpZyA9IG1ha2VfY29uZmlnKGxpc3QobWVhbl9zaSA9IDQsIHN0ZF9zaSA9IDIpKQ0KKQ0KYGBgDQpgYGB7cn0NCnByaW50KHJlcyRSKQ0KYGBgDQoNCg0KU2ltdWxhbW9zIGVsIGJyb3RlIGVwaWRlbWljbyAoZmljdGljaW8pOg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCmRpYXMgPC0gMzANCg0KY2Fzb3MgPC0gcm91bmQocnVuaWYoZGlhcywgbWluID0gMTAsIG1heCA9IDEwMCkpDQoNCmRhdG9zIDwtIGRhdGEuZnJhbWUoDQogIGZlY2hhID0gc2VxKGFzLkRhdGUoIjIwMjAtMDEtMDEiKSwgYnkgPSAiZGF5cyIsIGxlbmd0aC5vdXQgPSBkaWFzKSwNCiAgbnVldm9zX2Nhc29zID0gY2Fzb3MNCikNCg0KIyBNb3N0cmFyIGxvcyBwcmltZXJvcyBkYXRvcw0KaGVhZChkYXRvcykNCmBgYA0KDQoNCkNvbmZpZ3VyYWNpw7NuIGRlbCBJbnRlcnZhbG8gU2VyaWFsDQpEZWZpbmlyIGVsIEludGVydmFsbyBTZXJpYWwNCkVsIGludGVydmFsbyBzZXJpYWwgcmVwcmVzZW50YSBlbCB0aWVtcG8gcHJvbWVkaW8gZW50cmUgaW5mZWNjaW9uZXMgcHJpbWFyaWFzIHkgc2VjdW5kYXJpYXMuIEVuIENPVklELTE5LCBlc3R1ZGlvcyBzdWdpZXJlbiB1bmEgZGlzdHJpYnVjacOzbiBnYW1tYSBjb246DQoNCk1lZGlhOiA0IGTDrWFzDQoNCkRlc3ZpYWNpw7NuIGVzdMOhbmRhcjogMiBkw61hcw0KDQpgYGB7cn0NCiMgQ29uZmlndXJhciBlbCBpbnRlcnZhbG8gc2VyaWFsDQpjb25maWcgPC0gbWFrZV9jb25maWcoDQogIGxpc3QobWVhbl9zaSA9IDQsIHN0ZF9zaSA9IDIpKSAjIE5vcm1hbG1lbnRlLCBtYWtlX2NvbmZpZyBzZSB1dGlsaXphIHBhcmEgY3JlYXIgbyBnZXN0aW9uYXIgY29uZmlndXJhY2lvbmVzDQpgYGANCg0KQ2FsY3VsYXIgZWwgTsO6bWVybyBkZSBSZXByb2R1Y2Npw7NuIEVmZWN0aXZvIChS4oKRKQ0KRXN0aW1hciBS4oKRDQpVc2Ftb3MgbG9zIGRhdG9zIGRpYXJpb3MgZGUgbnVldm9zIGNhc29zIHBhcmEgY2FsY3VsYXIgUuKCkS4NCg0KYGBge3J9DQojIEVzdGltYXIgUuKCkSB1c2FuZG8gRXBpRXN0aW0NCnJlc3VsdGFkbyA8LSBlc3RpbWF0ZV9SKA0KICBpbmNpZCA9IGRhdG9zJG51ZXZvc19jYXNvcywNCiAgbWV0aG9kID0gInBhcmFtZXRyaWNfc2kiLA0KICBjb25maWcgPSBjb25maWcNCikNCmBgYA0KDQpgYGB7cn0NCiMgTW9zdHJhciByZXN1bHRhZG9zDQpwcmludChyZXN1bHRhZG8kUikNCmBgYA0KDQoNClZpc3VhbGl6YWNpw7NuIGRlIFLigpENCkdyw6FmaWNvIGRlIGxhIEV2b2x1Y2nDs24gZGUgUuKCkQ0KQ3JlYW1vcyB1biBncsOhZmljbyBxdWUgbXVlc3RyYSBjw7NtbyBS4oKRIGNhbWJpYSBjb24gZWwgdGllbXBvLCBsbyBxdWUgcHVlZGUgaW5kaWNhciBlbCBpbXBhY3RvIGRlIGludGVydmVuY2lvbmVzLg0KDQpgYGB7cn0NCiMgR3LDoWZpY28gZGUgUuKCkQ0KcGxvdCgNCiAgcmVzdWx0YWRvLA0KICB3aGF0ID0gIlIiLA0KICBsZWdlbmQgPSBGQUxTRSwNCiAgbWFpbiA9ICJFdm9sdWNpw7NuIGRlbCBOw7ptZXJvIGRlIFJlcHJvZHVjY2nDs24gRWZlY3Rpdm8gKFLigpEpIg0KKQ0KYGBgDQoNCg0KDQpJbnRlcnByZXRhY2nDs246DQoNClLigpEgPiAxOiBMYSBlcGlkZW1pYSBlc3TDoSBlbiBleHBhbnNpw7NuLg0KDQpS4oKRIDwgMTogTGEgZXBpZGVtaWEgZXN0w6EgZGlzbWludXllbmRvLg0KDQpMYSBmdW5jacOzbiBlc3RpbWF0ZV9SIGRlbCBwYXF1ZXRlIHtFcGlFc3RpbX0gZW4gUiBzZSB1dGlsaXphIHBhcmEgZXN0aW1hciBlbCBuw7ptZXJvIGRlIHJlcHJvZHVjY2nDs24gZWZlY3Rpdm8gKFLigpEpLCBlcyB1bmEgbcOpdHJpY2EgY2xhdmUgZW4gZXBpZGVtaW9sb2fDrWEgcGFyYSBtZWRpciBsYSBjYXBhY2lkYWQgZGUgdHJhbnNtaXNpw7NuIGRlIHVuYSBlbmZlcm1lZGFkIGluZmVjY2lvc2EgZW4gdW5hIHBvYmxhY2nDs24gYSBsbyBsYXJnbyBkZWwgdGllbXBvLg0KDQpQcmFjdGljYQ0KSW50cm9kdWNjacOzbg0KRW4gZXN0YSBwcsOhY3RpY2EgY2FsY3VsYXJlbW9zICwgUuKCkSB5IFIgcGFyYSB2YXJpYXMgZW5mZXJtZWRhZGVzIGluZmVjY2lvc2FzIHV0aWxpemFuZG8gcGFyw6FtZXRyb3MgcmVhbGVzLiBFc3RvcyB2YWxvcmVzIHNvbiBjcnVjaWFsZXMgcGFyYSBjb21wcmVuZGVyIGxhIGRpbsOhbWljYSBkZSB0cmFuc21pc2nDs24geSBlbCBpbXBhY3RvIGRlIG1lZGlkYXMgZGUgY29udHJvbC4NCg0KVmFsb3JlcyBwYXJhIGxhcyBlbmZlcm1lZGFkZXMgSW5mZWNjaW9zYXMNCkNPVklELTE5IChTQVJTLUNvVi0yKToNCg0KVGFzYSBkZSB0cmFuc21pc2nDs246IH45OS40JSAoYWx0YSB0cmFuc21pc2nDs24gZW4gZW50b3Jub3MgY2VycmFkb3MpIC4NCg0KVGFzYSBkZSBtb3J0YWxpZGFkOiAwLjE4NSUgLg0KDQpEdXJhY2nDs24gaW5mZWNjaW9zYTogfjEwIGTDrWFzIC4NCg0KRGlzdGFuY2lhbWllbnRvIHNvY2lhbDogfjMwJSBwdWVkZSByZWR1Y2lyIHNpZ25pZmljYXRpdmFtZW50ZSBsYSB0cmFuc21pc2nDs24uDQoNClJlZmVyZW5jaWE6IEVzdGltYXRpb24gb2YgdGhlIHJlcHJvZHVjdGlvbiBudW1iZXIgb2YgU0FSUy1Db1YtMi4NCg0KTUVSUy1Db1YgKE1pZGRsZSBFYXN0IFJlc3BpcmF0b3J5IFN5bmRyb21lKToNCg0KVGFzYSBkZSB0cmFuc21pc2nDs246IH41JSAoZW4gY29udGFjdG9zIGRvbWljaWxpYXJpb3MpLg0KDQpUYXNhIGRlIG1vcnRhbGlkYWQ6IH4zNSUuDQoNCkR1cmFjacOzbiBpbmZlY2Npb3NhOiB+MTQgZMOtYXMuDQoNClJlZmVyZW5jaWE6IEVtZXJnaW5nIHJlc3BpcmF0b3J5IHZpcmFsIGluZmVjdGlvbnM6IE1FUlMtQ29WIGFuZCBpbmZsdWVuemEuDQoNCkluZmx1ZW56YSBFc3RhY2lvbmFsOg0KDQpUYXNhIGRlIHRyYW5zbWlzacOzbjogfjUw4oCTNzUlLg0KDQpUYXNhIGRlIG1vcnRhbGlkYWQ6IH4wLjElLg0KDQpEdXJhY2nDs24gaW5mZWNjaW9zYTogfjcgZMOtYXMuDQoNClJlZmVyZW5jaWE6IEluZmx1ZW56YSBhbmQgdHViZXJjdWxvc2lzIGNvLWluZmVjdGlvbjogQSBzeXN0ZW1hdGljIHJldmlldy4NCg0KVHViZXJjdWxvc2lzOg0KDQpUYXNhIGRlIHRyYW5zbWlzacOzbjogfjMwJSAoZW4gY29udGFjdG9zIGNlcmNhbm9zKS4NCg0KVGFzYSBkZSBtb3J0YWxpZGFkOiB+MTUlLg0KDQpEdXJhY2nDs24gaW5mZWNjaW9zYTogTWVzZXMgYSBhw7FvcyBzaW4gdHJhdGFtaWVudG8uDQoNClJlZmVyZW5jaWE6IFR1YmVyY3Vsb3NpcyBhbmQgQ292aWQtMTkgQ28tSW5mZWN0aW9uLg0KDQpTYXJhbXBpw7NuOg0KDQpUYXNhIGRlIHRyYW5zbWlzacOzbjogOTDigJMxMDAlIChtdXkgYWx0YSkuDQoNClRhc2EgZGUgbW9ydGFsaWRhZDogfjAuMiUgZW4gcGHDrXNlcyBkZXNhcnJvbGxhZG9zOyBtw6FzIGFsdGEgZW4gY29udGV4dG9zIHNpbiB2YWN1bmFjacOzbi4NCg0KRHVyYWNpw7NuIGluZmVjY2lvc2E6IH44IGTDrWFzLg0KDQpSZWZlcmVuY2lhOiBNb2xlY3VsYXIgYW5kIENlbGx1bGFyIE1lY2hhbmlzbXMgb2YgTS4gdHViZXJjdWxvc2lzIGFuZCBTQVJTLUNvVi0yIEluZmVjdGlvbnMuDQoNClNpbXVsYXJlbW9zIGxhIHByb3BhZ2FjacOzbiBkZSA1IGVuZmVybWVkYWRlcyBpbmZlY2Npb3NhcyBjb24gZGlmZXJlbnRlcyB0YXNhcyBkZSB0cmFuc21pc2nDs24sIG1vcnRhbGlkYWQgeSBkdXJhY2nDs24gaW5mZWNjaW9zYS4gRXN0YXMgc2ltdWxhY2lvbmVzIHNlIGJhc2Fyw6FuIGVuIHBhcsOhbWV0cm9zIG9idGVuaWRvcyBkZSBsYSBsaXRlcmF0dXJhIGNpZW50w61maWNhLg0KDQpgYGB7cn0NCiMgUGFyw6FtZXRyb3MgZGUgbGFzIGVuZmVybWVkYWRlcw0KZW5mZXJtZWRhZGVzIDwtIGRhdGEuZnJhbWUoDQogIEVuZmVybWVkYWQgPSBjKCJDT1ZJRC0xOSIsICJNRVJTLUNvViIsICJJbmZsdWVuemEgRXN0YWNpb25hbCIsICJUdWJlcmN1bG9zaXMiLCAiU2FyYW1wacOzbiIpLA0KICBUYXNhX1RyYW5zbWlzaW9uID0gYyg5OS40LCA1LCA2MCwgMzAsIDk1KSwgIyBQb3JjZW50YWplDQogIFRhc2FfTW9ydGFsaWRhZCA9IGMoMC4xODUsIDM1LCAwLjEsIDE1LCAwLjIpLCAjIFBvcmNlbnRhamUNCiAgRHVyYWNpb25fSW5mZWNjaW9zYSA9IGMoMTAsIDE0LCA3LCAxODAsIDgpLCAjIETDrWFzDQogIERpc3RhbmNpYW1pZW50b19Tb2NpYWwgPSBjKDMwLCAwLCAxNSwgMTAsIDApLCAjIFBvcmNlbnRhamUNCiAgUG9ibGFjaW9uID0gYygxMDAwMDAwLCAxMDAwMDAwLCAxMDAwMDAwLCAxMDAwMDAwLCAxMDAwMDAwKSAjIFBvYmxhY2nDs24gcGFyYSBzaW11bGFjacOzbg0KKQ0KYGBgDQoNCkPDoWxjdWxvIGRlIFLigoANCkbDs3JtdWxhIGRlIFLigoANClLigoAgKE7Dum1lcm8gYsOhc2ljbyBkZSByZXByb2R1Y2Npw7NuKToNCg0KUmVwcmVzZW50YSBlbCBuw7ptZXJvIHByb21lZGlvIGRlIGluZmVjY2lvbmVzIHNlY3VuZGFyaWFzIGNhdXNhZGFzIHBvciB1biBpbmRpdmlkdW8gaW5mZWN0YWRvIGVuIHVuYSBwb2JsYWNpw7NuIGNvbXBsZXRhbWVudGUgc3VzY2VwdGlibGUuDQoNCkbDs3JtdWxhOg0KUjAgPSBUYXNhIGRlIHRyYW5zbWlzacOzbiB4IER1cmFjacOzbiBpbmZlY2Npb3NhDQoNCmBgYHtyfQ0KIyBDYWxjdWxhciBS4oKAIHBhcmEgY2FkYSBlbmZlcm1lZGFkDQplbmZlcm1lZGFkZXMkUjAgPC0gKGVuZmVybWVkYWRlcyRUYXNhX1RyYW5zbWlzaW9uIC8gMTAwKSAqIGVuZmVybWVkYWRlcyREdXJhY2lvbl9JbmZlY2Npb3NhDQoNCiMgTW9zdHJhciByZXN1bHRhZG9zDQplbmZlcm1lZGFkZXNbYygiRW5mZXJtZWRhZCIsICJSMCIpXQ0KYGBgDQoNCkPDoWxjdWxvIGRlIFLigpENCkbDs3JtdWxhIGRlIFLigpENCkNhbGN1bGEgUmUgb25zaWRlcmFuZG8gcXVlIG5vIHRvZGEgbGEgcG9ibGFjacOzbiBlcyBzdXNjZXB0aWJsZSAoZGViaWRvIGEgaW5tdW5pZGFkIG8gaW50ZXJ2ZW5jaW9uZXMpLg0KDQpGw7NybXVsYToNCg0KUmUgPSBSbyAqIHN1c2NlcHRpYmxlcyAvIHBvYmxhY2nDs24gdG90YWwNCg0KYGBge3J9DQojIENvbnNpZGVyYXIgNzAlIGRlIGxhIHBvYmxhY2nDs24gaW5pY2lhbCBjb21vIHN1c2NlcHRpYmxlcw0KZW5mZXJtZWRhZGVzJFN1c2NlcHRpYmxlcyA8LSBlbmZlcm1lZGFkZXMkUG9ibGFjaW9uICogMC43DQoNCiMgQ2FsY3VsYXIgUuKCkQ0KZW5mZXJtZWRhZGVzJFJlIDwtIGVuZmVybWVkYWRlcyRSMCAqIChlbmZlcm1lZGFkZXMkU3VzY2VwdGlibGVzIC8gZW5mZXJtZWRhZGVzJFBvYmxhY2lvbikNCg0KIyBNb3N0cmFyIHJlc3VsdGFkb3MNCmVuZmVybWVkYWRlc1tjKCJFbmZlcm1lZGFkIiwgIlIwIiwgIlJlIildDQpgYGANCg0KQ8OhbGN1bG8gZGUgUuKCnA0KRGluw6FtaWNhIFRlbXBvcmFsIGRlIFLigpwNCkNvbnNpZGVyYW1vcyBpbnRlcnZlbmNpb25lcyBjb21vIGRpc3RhbmNpYW1pZW50byBzb2NpYWwgeSBjYW1iaW9zIGVuIGxvcyBzdXNjZXB0aWJsZXMgYSBsbyBsYXJnbyBkZWwgdGllbXBvLg0KDQpgYGB7cn0NCiMgQ3JlYXIgdW4gZGF0YSBmcmFtZSBwYXJhIHNpbXVsYXIgbGEgZGluw6FtaWNhIHRlbXBvcmFsDQpkaWFzIDwtIDMwDQpyZXN1bHRhZG9fcnQgPC0gZGF0YS5mcmFtZSgpDQoNCmZvciAoaSBpbiAxOm5yb3coZW5mZXJtZWRhZGVzKSkgew0KICBlbmZlcm1lZGFkIDwtIGVuZmVybWVkYWRlc1tpLCBdDQogIHN1c2NlcHRpYmxlcyA8LSBlbmZlcm1lZGFkJFN1c2NlcHRpYmxlcw0KICBydCA8LSBudW1lcmljKGRpYXMpDQogIA0KICBmb3IgKHQgaW4gMTpkaWFzKSB7DQogICAgcnRbdF0gPC0gZW5mZXJtZWRhZCRSMCAqIChzdXNjZXB0aWJsZXMgLyBlbmZlcm1lZGFkJFBvYmxhY2lvbikgKiAoMSAtIGVuZmVybWVkYWQkRGlzdGFuY2lhbWllbnRvX1NvY2lhbCAvIDEwMCkNCiAgICBzdXNjZXB0aWJsZXMgPC0gbWF4KDAsIHN1c2NlcHRpYmxlcyAtIChzdXNjZXB0aWJsZXMgKiBlbmZlcm1lZGFkJFRhc2FfVHJhbnNtaXNpb24gLyAxMDApKSAjIFJlZHVjaXIgc3VzY2VwdGlibGVzDQogIH0NCiAgDQogIHJlc3VsdGFkb19ydCA8LSByYmluZChyZXN1bHRhZG9fcnQsIGRhdGEuZnJhbWUoRGlhID0gMTpkaWFzLCBSX3QgPSBydCwgRW5mZXJtZWRhZCA9IGVuZmVybWVkYWQkRW5mZXJtZWRhZCkpDQp9DQoNCiMgTW9zdHJhciByZXN1bHRhZG9zIHBhcmEgdW5hIGVuZmVybWVkYWQNCmhlYWQocmVzdWx0YWRvX3J0W3Jlc3VsdGFkb19ydCRFbmZlcm1lZGFkID09ICJDT1ZJRC0xOSIsIF0pDQpgYGANCg0KVmlzdWFsaXphY2nDs24gZGUgUuKCnA0KR3LDoWZpY28gcGFyYSBDYWRhIEVuZmVybWVkYWQNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgR3LDoWZpY28gZGUgUuKCnA0KZ2dwbG90KHJlc3VsdGFkb19ydCwgYWVzKHggPSBEaWEsIHkgPSBSX3QsIGNvbG9yID0gRW5mZXJtZWRhZCkpICsNCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJFdm9sdWNpw7NuIGRlIFJ0IHBvciBFbmZlcm1lZGFkIiwgDQogICAgICAgeCA9ICJEw61hcyIsIHkgPSAiUnQiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDEiKQ0KYGBgDQoNCg0KQm9udXMgdHJhY2s6DQpQb2RlbW9zIGNyZWFyIHVuYSBmdW5jacOzbiBlbiBSIHBhcmEgc2ltdWxhciBsYSBlbmZlcm1lZGFkDQpFbiBlbCBzaWd1aWVudGUgYmxvcXVlIGRlIGNvZGlnbyBzZSBjcmVhIGxhIGZ1bmNpw7NuIHNpbXVsYXJfZW5mZXJtZWRhZA0KDQpgYGB7cn0NCiMgQ3JlYXIgdW5hIGZ1bmNpw7NuIGRlIHNpbXVsYWNpw7NuDQpzaW11bGFyX2VuZmVybWVkYWQgPC0gZnVuY3Rpb24oZW5mZXJtZWRhZCwgdGFzYV90cmFuc21pc2lvbiwgdGFzYV9tb3J0YWxpZGFkLCBkdXJhY2lvbiwgZGlzdF9zb2NpYWwsIHBvYmxhY2lvbiA9IDEwMDApIHsNCiAgZGlhcyA8LSAzMA0KICBpbmZlY2Npb3NvcyA8LSAxICAjIENhc29zIGluaWNpYWxlcw0KICByZWN1cGVyYWRvcyA8LSAwDQogIGZhbGxlY2lkb3MgPC0gMA0KICBzdXNjZXB0aWJsZXMgPC0gcG9ibGFjaW9uIC0gaW5mZWNjaW9zb3MNCiAgDQogIHJlc3VsdGFkbyA8LSBkYXRhLmZyYW1lKERpYSA9IDE6ZGlhcywgSW5mZWN0YWRvcyA9IE5BLCBSZWN1cGVyYWRvcyA9IE5BLCBGYWxsZWNpZG9zID0gTkEsIFN1c2NlcHRpYmxlcyA9IE5BKQ0KICANCiAgZm9yIChkaWEgaW4gMTpkaWFzKSB7DQogICAgbnVldmFzX2luZmVjY2lvbmVzIDwtIHJvdW5kKChpbmZlY2Npb3NvcyAqIHRhc2FfdHJhbnNtaXNpb24gLyAxMDApICogKDEgLSBkaXN0X3NvY2lhbCAvIDEwMCkpDQogICAgbnVldmFzX2luZmVjY2lvbmVzIDwtIG1pbihudWV2YXNfaW5mZWNjaW9uZXMsIHN1c2NlcHRpYmxlcykgICMgTm8gZXhjZWRlciBzdXNjZXB0aWJsZXMNCiAgICANCiAgICBudWV2b3NfcmVjdXBlcmFkb3MgPC0gaWZlbHNlKGRpYSA+IGR1cmFjaW9uLCBpbmZlY2Npb3NvcyAvIGR1cmFjaW9uLCAwKQ0KICAgIG51ZXZvc19mYWxsZWNpZG9zIDwtIHJvdW5kKCh0YXNhX21vcnRhbGlkYWQgLyAxMDApICogaW5mZWNjaW9zb3MpDQogICAgDQogICAgaW5mZWNjaW9zb3MgPC0gaW5mZWNjaW9zb3MgKyBudWV2YXNfaW5mZWNjaW9uZXMgLSBudWV2b3NfcmVjdXBlcmFkb3MgLSBudWV2b3NfZmFsbGVjaWRvcw0KICAgIHJlY3VwZXJhZG9zIDwtIHJlY3VwZXJhZG9zICsgbnVldm9zX3JlY3VwZXJhZG9zDQogICAgZmFsbGVjaWRvcyA8LSBmYWxsZWNpZG9zICsgbnVldm9zX2ZhbGxlY2lkb3MNCiAgICBzdXNjZXB0aWJsZXMgPC0gcG9ibGFjaW9uIC0gaW5mZWNjaW9zb3MgLSByZWN1cGVyYWRvcyAtIGZhbGxlY2lkb3MNCiAgICANCiAgICByZXN1bHRhZG9bZGlhLCBdIDwtIGMoZGlhLCBpbmZlY2Npb3NvcywgcmVjdXBlcmFkb3MsIGZhbGxlY2lkb3MsIHN1c2NlcHRpYmxlcykNCiAgfQ0KICByZXR1cm4ocmVzdWx0YWRvKQ0KfQ0KYGBgDQoNCg0KVW5hIHZleiBjcmVhZGEgbGEgZnVuY2nDs24gYWhvcmEgcG9kZW1vcyB1dGlsaXphcmxhOg0KVmFtb3MgYSBjcmVhciB1biBvYmpldG8gcXVlIGdhcmRlIGxvcyBkYXRvcyBzaW11bGFkb3MgZGUgdW5hIGVuZmVybWVkYWQgKCBwdWVkZSBzZXIgZGUgbG9zIGRhdG9zIHF1ZSB5YSByZXZpc2Ftb3MgZW4gbGEgbGl0ZXJhdHVyYSkNCg0KDQojIFNpbXVsYWNpw7NuIGRlIGVqZW1wbG8gcGFyYSBDT1ZJRC0xOQ0Kc2ltX2NvdmlkIDwtIHNpbXVsYXJfZW5mZXJtZWRhZCgNCiAgIkNPVklELTE5IiwgdGFzYV90cmFuc21pc2lvbiA9IDk5LjQsIHRhc2FfbW9ydGFsaWRhZCA9IDIwLCANCiAgZHVyYWNpb24gPSAxMCwgZGlzdF9zb2NpYWwgPSAzMCwgcG9ibGFjaW9uID0gMTAwMA0KKQ0KDQpgYGB7cn0NCiMgU2ltdWxhY2nDs24gZGUgZWplbXBsbyBwYXJhIENPVklELTE5DQpzaW1fY292aWQgPC0gc2ltdWxhcl9lbmZlcm1lZGFkKA0KICAiQ09WSUQtMTkiLCB0YXNhX3RyYW5zbWlzaW9uID0gOTkuNCwgdGFzYV9tb3J0YWxpZGFkID0gMjAsIA0KICBkdXJhY2lvbiA9IDEwLCBkaXN0X3NvY2lhbCA9IDMwLCBwb2JsYWNpb24gPSAxMDAwDQopDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBHcsOhZmljbyBwYXJhIENPVklELTE5DQpnZ3Bsb3Qoc2ltX2NvdmlkLCBhZXMoeCA9IERpYSkpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gSW5mZWN0YWRvcywgY29sb3IgPSAiSW5mZWN0YWRvcyIpKSArDQogIGdlb21fbGluZShhZXMoeSA9IFJlY3VwZXJhZG9zLCBjb2xvciA9ICJSZWN1cGVyYWRvcyIpKSArDQogIGdlb21fbGluZShhZXMoeSA9IEZhbGxlY2lkb3MsIGNvbG9yID0gIkZhbGxlY2lkb3MiKSkgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBTdXNjZXB0aWJsZXMsIGNvbG9yID0gIlN1c2NlcHRpYmxlcyIpKSArDQogIGxhYnModGl0bGUgPSAiU2ltdWxhY2nDs24gZGUgQ292aWQtMTkiLCANCiAgICAgICB4ID0gIkTDrWFzIiwgeSA9ICJOw7ptZXJvIGRlIFBlcnNvbmFzIikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJFc3RhZG8iLCB2YWx1ZXMgPSBjKCJJbmZlY3RhZG9zIiA9ICJyZWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUmVjdXBlcmFkb3MiID0gImdyZWVuIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZhbGxlY2lkb3MiID0gImJsYWNrIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlN1c2NlcHRpYmxlcyIgPSAiYmx1ZSIpKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCkNvbmNsdXNpw7NuDQpMYSBzaW11bGFjacOzbiBwZXJtaXRlIHZpc3VhbGl6YXIgbGEgZGluw6FtaWNhIGRlIHRyYW5zbWlzacOzbiB5IGVsIGltcGFjdG8gZGUgaW50ZXJ2ZW5jaW9uZXMgY29tbyBlbCBkaXN0YW5jaWFtaWVudG8gc29jaWFsLiBMb3MgcmVzdWx0YWRvcyBwdWVkZW4gdXNhcnNlIHBhcmEgcGxhbmlmaWNhciByZXNwdWVzdGFzIGFudGUgYnJvdGVzIHJlYWxlcy4NCg0KQWRlbcOhcywgcGVybWl0ZSBhbmFsaXphciBsYSBkaW7DoW1pY2EgZGUgbGEgcHJvcGFnYWNpw7NuIGRlIGVuZmVybWVkYWRlcyBiYWpvIGRpZmVyZW50ZXMgZXNjZW5hcmlvcyBkZSBpbnRlcnZlbmNpw7NuIHkgcGFyw6FtZXRyb3MgZXBpZGVtaW9sw7NnaWNvcy4NCg0KU2lndWllbnRlcyBwYXNvczoNCg0KQWp1c3RhciBwYXLDoW1ldHJvcyBwYXJhIGVzY2VuYXJpb3MgZXNwZWPDrWZpY29zLg0KDQpDb21wYXJhciBlbnRyZSBkaWZlcmVudGVzIHBvYmxhY2lvbmVzIHkgZW50b3Jub3MuDQoNCkNhbGN1bG8gZGUgdGFtYcOxbyBtdWVzdHJhbA0KSW50cm9kdWNjacOzbg0KRWwgY8OhbGN1bG8gZGVsIHRhbWHDsW8gZGUgbXVlc3RyYSBlcyB1bmEgZXRhcGEgY3J1Y2lhbCBlbiBlbCBkaXNlw7FvIGRlIGVzdHVkaW9zLiBDdWFuZG8gZGVzZWFtb3MgZXN0aW1hciB1bmEgcHJvcG9yY2nDs24sIGRlYmVtb3MgY29uc2lkZXJhcjogMS4gTml2ZWwgZGUgY29uZmlhbnphIChazrEpOiBSZXByZXNlbnRhIGxhIHByb2JhYmlsaWRhZCBkZSBxdWUgZWwgaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBjb250ZW5nYSBlbCB2YWxvciB2ZXJkYWRlcm8uIEVqZW1wbG86IDk1JSAoKCBaID0gMS45NiApKS4gMi4gUHJlY2lzacOzbiBkZXNlYWRhICgoIGUgKSk6IERpZmVyZW5jaWEgbcOheGltYSBhY2VwdGFibGUgZW50cmUgbGEgcHJvcG9yY2nDs24gZXN0aW1hZGEgeSBsYSByZWFsLiAzLiBQcm9wb3JjacOzbiBlc3BlcmFkYSAoKCBwICkpOiBFc3RpbWFjacOzbiBpbmljaWFsIGJhc2FkYSBlbiBsaXRlcmF0dXJhIG8gZXN0dWRpb3MgcHJldmlvcy4NCg0KRW4gZXN0ZSBlamVyY2ljaW8sIHV0aWxpemFyZW1vcyBlbCBwYXF1ZXRlIHB3ciBwYXJhIGNhbGN1bGFyIGVsIHRhbWHDsW8gZGUgbXVlc3RyYSBuZWNlc2FyaW8gcGFyYSBjb25vY2VyIGxhIHByZXZhbGVuY2lhIGRlIGRpYWJldGVzIGVuIHVuYSBwb2JsYWNpw7NuLCBzdXBvbmllbmRvIHF1ZTogLSBOaXZlbCBkZSBjb25maWFuemE6IDk1JSAtIFByZWNpc2nDs24gZGVzZWFkYTogNSUgLSBQcm9wb3JjacOzbiBlc3BlcmFkYTogNTAlICgwLjUpLg0KDQpJbnN0YWxhY2nDs24geSBjb25maWd1cmFjacOzbiBkZSBwYXF1ZXRlcw0KUHJpbWVybywgYXNlZ3Vyw6ltb25vcyBkZSBpbnN0YWxhciB5IGNhcmdhciBsb3MgcGFxdWV0ZXMgbmVjZXNhcmlvcy4NCg0KUGFxdWV0ZSBwd3INCg0KYGBge3J9DQojIEVqZWN1dGFyIHNvbG8gdW5hIHZleiBzaSBubyBlc3TDoSBpbnN0YWxhZG86DQojIGluc3RhbGwucGFja2FnZXMoInB3ciIpDQoNCmxpYnJhcnkocHdyKQ0KYGBgDQoNCg0KRsOzcm11bGEgcGFyYSBlc3RpbWFyIGVsIHRhbWHDsW8gZGUgbXVlc3RyYQ0KRWwgY8OhbGN1bG8gZGVsIHRhbWHDsW8gZGUgbXVlc3RyYSBwYXJhIGVzdGltYXIgdW5hIHByb3BvcmNpw7NuIHNlIHJlYWxpemEgY29uIGxhIGbDs3JtdWxhOg0KDQoNCg0KRsOzcm11bGEgdGFtYcOxbyBkZSBtdWVzdHJhIHBhcmEgcHJvcG9yY2nDs24NCkRvbmRlOg0KDQpaOiB2YWxvciBjb3JyZXNwb25kaWVudGUgYWwgbml2ZWwgZGUgY29uZmlhbnphIChwb3IgZWplbXBsbywgWiA9IDEuOTYgcGFyYSA5NSAlKS4NCnA6IHByb3BvcmNpw7NuIGVzcGVyYWRhLg0KZTogcHJlY2lzacOzbiBkZXNlYWRhIChlcnJvciBtw6F4aW1vIHBlcm1pdGlkbykuDQpBdW5xdWUgZWwgcGFxdWV0ZSBwd3Igc2ltcGxpZmljYSBlc3RlIGPDoWxjdWxvLCB0YW1iacOpbiBwb2RlbW9zIGhhY2VybG8gZGUgZm9ybWEgbWFudWFsIHBhc28gYSBwYXNvIGVuIFIuDQoNCkPDoWxjdWxvIGRlbCB0YW1hw7FvIGRlIG11ZXN0cmENCk3DqXRvZG8gMTogQ8OhbGN1bG8gbWFudWFsDQpVdGlsaXphbmRvIGRpcmVjdGFtZW50ZSBsYSBmw7NybXVsYSBjbMOhc2ljYSBwYXJhIHByb3BvcmNpb25lcyBlbiBwb2JsYWNpw7NuIOKAnGluZmluaXRh4oCdOg0KDQoNCmBgYHtyfQ0KIyBQYXLDoW1ldHJvcw0KWiA8LSAxLjk2ICAgIyBOaXZlbCBkZSBjb25maWFuemEgcGFyYSA5NSAlDQpwIDwtIDAuNSAgICAjIFByb3BvcmNpw7NuIGVzcGVyYWRhDQplIDwtIDAuMDUgICAjIFByZWNpc2nDs24gZGVzZWFkYSAoNSAlKQ0KDQojIEPDoWxjdWxvIGRlbCB0YW1hw7FvIGRlIG11ZXN0cmENCm5fbWFudWFsIDwtIChaXjIgKiBwICogKDEgLSBwKSkgLyAoZV4yKQ0KDQpjYXQoIlRhbWHDsW8gZGUgbXVlc3RyYSBuZWNlc2FyaW8gKG3DqXRvZG8gbWFudWFsKToiLA0KICAgIGNlaWxpbmcobl9tYW51YWwpLCAiXG4iKQ0KYGBgDQoNCk3DqXRvZG8gMjogVXNvIGRlbCBwYXF1ZXRlIHB3cg0KRWwgcGFxdWV0ZSBwd3IgcHJvcG9yY2lvbmEgdW5hIGZvcm1hIG3DoXMgZ2VuZXJhbCwgYmFzYWRhIGVuIHRhbWHDsW8gZGUgZWZlY3RvIChoKSB5IHBvZGVyIGVzdGFkw61zdGljby4NCg0KU3Vwb25nYW1vcyBxdWUgcXVlcmVtb3MgZGV0ZWN0YXIgdW5hIGRpZmVyZW5jaWEgZW50cmUgdW5hIHByb3BvcmNpw7NuIG51bGEgcDAgPSAwLjUgeSB1bmEgcHJvcG9yY2nDs24gYWx0ZXJuYXRpdmEgcDEgPSAwLjYgY29uIM6xID0gMC4wNSB5IHBvZGVyIDgwICU6DQoNCmBgYHtyfQ0KIyBQYXLDoW1ldHJvcyBwYXJhIHBydWViYSBkZSB1bmEgcHJvcG9yY2nDs24NCnAwIDwtIDAuNSAgICMgUHJvcG9yY2nDs24gbnVsYQ0KcDEgPC0gMC42ICAgIyBQcm9wb3JjacOzbiBhbHRlcm5hdGl2YQ0KDQojIFRhbWHDsW8gZGUgZWZlY3RvIGRlIENvaGVuIChoKSBwYXJhIHByb3BvcmNpb25lcw0KaCA8LSBFUy5oKHAxID0gcDEsIHAyID0gcDApDQoNCiMgQ8OhbGN1bG8gZGVsIHRhbWHDsW8gZGUgbXVlc3RyYSBjb24gcHdyLnAudGVzdA0KcmVzX3B3ciA8LSBwd3IucC50ZXN0KGggPSBoLA0KICAgICAgICAgICAgICAgICAgICAgIHNpZy5sZXZlbCA9IDAuMDUsDQogICAgICAgICAgICAgICAgICAgICAgcG93ZXIgPSAwLjgwLA0KICAgICAgICAgICAgICAgICAgICAgIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpDQoNCm5fcHdyIDwtIGNlaWxpbmcocmVzX3B3ciRuKQ0KDQpjYXQoIlRhbWHDsW8gZGUgbXVlc3RyYSBuZWNlc2FyaW8gKHB3ci5wLnRlc3QpOiIsDQogICAgbl9wd3IsICJcbiIpDQpgYGANCg0KVGFtYcOxbyBkZSBtdWVzdHJhIGVuIHBvYmxhY2lvbmVzIGZpbml0YXMNCkN1YW5kbyBzZSBjb25vY2UgZWwgdGFtYcOxbyB0b3RhbCBkZSBsYSBwb2JsYWNpw7NuLCBzZSBhanVzdGEgZWwgdGFtYcOxbyBkZSBtdWVzdHJhIG1lZGlhbnRlIGxhIGbDs3JtdWxhIHBhcmEgcG9ibGFjaW9uZXMgZmluaXRhczoNCg0KDQoNCkbDs3JtdWxhIHBvYmxhY2nDs24gZmluaXRhDQpEb25kZToNCg0KTjogdGFtYcOxbyBkZSBsYSBwb2JsYWNpw7NuLg0KWjogdmFsb3IgY29ycmVzcG9uZGllbnRlIGFsIG5pdmVsIGRlIGNvbmZpYW56YS4NCnA6IHByb3BvcmNpw7NuIGVzcGVyYWRhLg0KcSA9IDEg4oiSIHAuDQpkOiBwcmVjaXNpw7NuIGRlc2VhZGEuDQpFbiBlc3RlIGVqZXJjaWNpbywgY2FsY3VsYW1vcyBlbCB0YW1hw7FvIGRlIG11ZXN0cmEgcGFyYToNCg0KTiA9IDEwLDAwMA0KTml2ZWwgZGUgY29uZmlhbnphOiA5NSAlIChaID0gMS45NikNClByb3BvcmNpw7NuIGVzcGVyYWRhOiBwID0gMC4wNSAoNSAlKQ0KUHJlY2lzacOzbiBkZXNlYWRhOiBkID0gMC4wMyAoMyAlKQ0KDQoNCmBgYHtyfQ0KIyBQYXLDoW1ldHJvcw0KTiA8LSAxMDAwMCAgICMgVGFtYcOxbyBkZSBsYSBwb2JsYWNpw7NuDQpaIDwtIDEuOTYgICAgIyBOaXZlbCBkZSBjb25maWFuemEgcGFyYSA5NSAlDQpwIDwtIDAuMDUgICAgIyBQcm9wb3JjacOzbiBlc3BlcmFkYSAoNSAlKQ0KcSA8LSAxIC0gcCAgICMgQ29tcGxlbWVudG8gZGUgbGEgcHJvcG9yY2nDs24NCmQgPC0gMC4wMyAgICAjIFByZWNpc2nDs24gZGVzZWFkYSAoMyAlKQ0KDQojIEPDoWxjdWxvIGRlbCB0YW1hw7FvIGRlIG11ZXN0cmEgcGFyYSBwb2JsYWNpw7NuIGZpbml0YQ0Kbl9maW5pdGEgPC0gKE4gKiBaXjIgKiBwICogcSkgLw0KICAoKGReMiAqIChOIC0gMSkpICsgKFpeMiAqIHAgKiBxKSkNCg0KY2F0KCJUYW1hw7FvIGRlIG11ZXN0cmEgbmVjZXNhcmlvIChOID0gMTAsMDAwKToiLA0KICAgIGNlaWxpbmcobl9maW5pdGEpLCAiXG4iKQ0KYGBgDQpQYXNvIDI6IFZhcmlhY2nDs24gZGVsIHRhbWHDsW8gZGUgbXVlc3RyYSBzZWfDum4gbGEgcHJlY2lzacOzbg0KQ3JlYW1vcyB1biBncsOhZmljbyBxdWUgbXVlc3RyZSBjw7NtbyBjYW1iaWEgZWwgdGFtYcOxbyBkZSBtdWVzdHJhIGNvbiBkaXN0aW50b3MgdmFsb3JlcyBkZSBkOg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBTZWN1ZW5jaWEgZGUgcHJlY2lzaW9uZXMgcG9zaWJsZXMNCnByZWNpc2lvbmVzIDwtIHNlcSgwLjAxLCAwLjEwLCBieSA9IDAuMDEpDQoNCnRhbV9tdWVzdHJhIDwtIHNhcHBseShwcmVjaXNpb25lcywgZnVuY3Rpb24oZCl7DQogIChOICogWl4yICogcCAqIHEpIC8NCiAgICAoKGReMiAqIChOIC0gMSkpICsgKFpeMiAqIHAgKiBxKSkNCn0pDQoNCiMgRGF0YSBmcmFtZSBwYXJhIGdyYWZpY2FyDQpkYXRvc19ncmFmaWNvIDwtIGRhdGEuZnJhbWUoDQogIHByZWNpc2lvbiAgICAgID0gcHJlY2lzaW9uZXMsDQogIHRhbWFub19tdWVzdHJhID0gY2VpbGluZyh0YW1fbXVlc3RyYSkNCikNCg0KZ2dwbG90KGRhdG9zX2dyYWZpY28sDQogICAgICAgYWVzKHggPSBwcmVjaXNpb24sIHkgPSB0YW1hbm9fbXVlc3RyYSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJlbGFjacOzbiBlbnRyZSBwcmVjaXNpw7NuIChkKSB5IHRhbWHDsW8gZGUgbXVlc3RyYVxuKE4gPSAxMCwwMDApIiwNCiAgICB4ICAgICA9ICJQcmVjaXNpw7NuIGRlc2VhZGEgKGQpIiwNCiAgICB5ICAgICA9ICJUYW1hw7FvIGRlIG11ZXN0cmEiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpFamVtcGxvIGFkaWNpb25hbDogcG9ibGFjacOzbiBkZSAxNSwwMDAgaGFiaXRhbnRlcw0KQWhvcmEgY2FsY3VsYW1vcyBlbCB0YW1hw7FvIGRlIG11ZXN0cmEgcGFyYSBlc3RpbWFyIGxhIHByZXZhbGVuY2lhIGRlIGRpYWJldGVzIGVuIHVuYSBwb2JsYWNpw7NuIGZpbml0YSBkZSAxNSwwMDAgaGFiaXRhbnRlcywgY29uOg0KDQpTZWd1cmlkYWQ6IDk1ICUNClByZWNpc2nDs246IDMgJSAoZCA9IDAuMDMpDQpQcm9wb3JjacOzbiBlc3BlcmFkYTogcCA9IDAuMDUgKDUgJSkNCg0KYGBge3J9DQojIFBhcsOhbWV0cm9zDQpOIDwtIDE1MDAwICAgIyBUYW1hw7FvIGRlIGxhIHBvYmxhY2nDs24NClogPC0gMS45NiAgICAjIE5pdmVsIGRlIGNvbmZpYW56YSBwYXJhIDk1ICUNCnAgPC0gMC4wNSAgICAjIFByb3BvcmNpw7NuIGVzcGVyYWRhICg1ICUpDQpxIDwtIDEgLSBwDQpkIDwtIDAuMDMgICAgIyBQcmVjaXNpw7NuIGRlc2VhZGEgKDMgJSkNCg0KIyBDw6FsY3VsbyBwYXJhIHBvYmxhY2nDs24gZmluaXRhDQpuX2Zpbml0YV8xNTAwMCA8LSAoTiAqIFpeMiAqIHAgKiBxKSAvDQogICgoZF4yICogKE4gLSAxKSkgKyAoWl4yICogcCAqIHEpKQ0KDQpjYXQoIlRhbWHDsW8gZGUgbXVlc3RyYSBuZWNlc2FyaW8gKE4gPSAxNSwwMDApOiIsDQogICAgY2VpbGluZyhuX2Zpbml0YV8xNTAwMCksICJcbiIpDQpgYGANCkV4cGxvcmFjacOzbiBncsOhZmljYSAoTiA9IDE1LDAwMCkNCg0KYGBge3J9DQpwcmVjaXNpb25lcyA8LSBzZXEoMC4wMSwgMC4xMCwgYnkgPSAwLjAxKQ0KDQp0YW1fbXVlc3RyYSA8LSBzYXBwbHkocHJlY2lzaW9uZXMsIGZ1bmN0aW9uKGQpew0KICAoTiAqIFpeMiAqIHAgKiBxKSAvDQogICAgKChkXjIgKiAoTiAtIDEpKSArIChaXjIgKiBwICogcSkpDQp9KQ0KDQpkYXRvc19ncmFmaWNvIDwtIGRhdGEuZnJhbWUoDQogIHByZWNpc2lvbiAgICAgID0gcHJlY2lzaW9uZXMsDQogIHRhbWFub19tdWVzdHJhID0gY2VpbGluZyh0YW1fbXVlc3RyYSkNCikNCg0KZ2dwbG90KGRhdG9zX2dyYWZpY28sDQogICAgICAgYWVzKHggPSBwcmVjaXNpb24sIHkgPSB0YW1hbm9fbXVlc3RyYSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJlbGFjacOzbiBlbnRyZSBwcmVjaXNpw7NuIChkKSB5IHRhbWHDsW8gZGUgbXVlc3RyYVxuKE4gPSAxNSwwMDApIiwNCiAgICB4ICAgICA9ICJQcmVjaXNpw7NuIGRlc2VhZGEgKGQpIiwNCiAgICB5ICAgICA9ICJUYW1hw7FvIGRlIG11ZXN0cmEiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoNClRhbWHDsW8gZGUgbXVlc3RyYSBwYXJhIGVzdGltYXIgdW5hIG1lZGlhDQoNCmBgYHtyfQ0KIyBQYXLDoW1ldHJvcw0KWiAgPC0gMS45NiAgICMgTml2ZWwgZGUgY29uZmlhbnphICg5NSAlKQ0KUzIgPC0gMjUwICAgICMgVmFyaWFuemEgKFNeMikNCmQgIDwtIDMgICAgICAjIFByZWNpc2nDs24gZGVzZWFkYQ0KDQojIEPDoWxjdWxvIGRlbCB0YW1hw7FvIGRlIG11ZXN0cmENCm5fbWVkaWFfbWFudWFsIDwtIChaXjIgKiBTMikgLyAoZF4yKQ0KDQpjYXQoIlRhbWHDsW8gZGUgbXVlc3RyYSAobWVkaWEsIG3DqXRvZG8gbWFudWFsKToiLA0KICAgIGNlaWxpbmcobl9tZWRpYV9tYW51YWwpLCAiXG4iKQ0KYGBgDQoNClRhbWHDsW8gZGUgbXVlc3RyYSBwYXJhIG1lZGlhIGNvbg0KDQpgYGB7cn0NCiMgUGFyw6FtZXRyb3MNClogIDwtIDEuOTYgICAjIE5pdmVsIGRlIGNvbmZpYW56YSAoOTUgJSkNClMyIDwtIDI1MCAgICAjIFZhcmlhbnphIChTXjIpDQpkICA8LSAzICAgICAgIyBQcmVjaXNpw7NuIGRlc2VhZGENCg0KIyBDw6FsY3VsbyBkZWwgdGFtYcOxbyBkZSBtdWVzdHJhDQpuX21hbnVhbCA8LSAoWl4yICogUzIpIC8gKGReMikNCg0KY2F0KCJUYW1hw7FvIGRlIG11ZXN0cmEgKG1lZGlhLCBtw6l0b2RvIG1hbnVhbCk6IiwNCiAgICBjZWlsaW5nKG5fbWFudWFsKSwgIlxuIikNCmBgYA0KDQpDb21wYXJhY2nDs24gZGUgZG9zIHByb3BvcmNpb25lcw0KDQpgYGB7cn0NCiMgUGFyw6FtZXRyb3MNClpfYWxwaGEgPC0gMS42NDUgICMgTml2ZWwgZGUgY29uZmlhbnphIH45NSAlICh1bmEgY29sYSkNClpfYmV0YSAgPC0gMC44NDIgICMgUG9kZXIgZXN0YWTDrXN0aWNvIDgwICUNCnAxIDwtIDAuNyAgICAgICAgICMgUHJvcG9yY2nDs24gMQ0KcDIgPC0gMC45ICAgICAgICAgIyBQcm9wb3JjacOzbiAyDQpwICA8LSAocDEgKyBwMikgLyAyICAjIFByb21lZGlvIGRlIHByb3BvcmNpb25lcw0KDQojIEPDoWxjdWxvIGRlbCB0YW1hw7FvIGRlIG11ZXN0cmEgKHBvciBncnVwbykNCm5fZG9zX3Byb3BfbWFudWFsIDwtICgNCiAgKFpfYWxwaGEgKiBzcXJ0KDIgKiBwICogKDEgLSBwKSkgKw0KICAgICBaX2JldGEgICogc3FydChwMSAqICgxIC0gcDEpICsgcDIgKiAoMSAtIHAyKSkpXjINCikgLyAocDEgLSBwMileMg0KDQpjYXQoIlRhbWHDsW8gZGUgbXVlc3RyYSBwb3IgZ3J1cG8gKGRvcyBwcm9wb3JjaW9uZXMsIG1hbnVhbCk6IiwNCiAgICBjZWlsaW5nKG5fZG9zX3Byb3BfbWFudWFsKSwgIlxuIikNCmBgYA0KYGBge3J9DQojIEPDoWxjdWxvIGRlbCB0YW1hw7FvIGRlbCBlZmVjdG8gaCBwYXJhIGRvcyBwcm9wb3JjaW9uZXMNCmggPC0gRVMuaChwMSA9IHAxLCBwMiA9IHAyKQ0KDQojIFRhbWHDsW8gZGUgbXVlc3RyYSBwb3IgZ3J1cG8gY29uIHB3ci4ycC50ZXN0DQpyZXNfMnAgPC0gcHdyLjJwLnRlc3QoDQogIGggICAgICAgICA9IGgsDQogIHNpZy5sZXZlbCA9IDAuMDUsDQogIHBvd2VyICAgICA9IDAuODAsDQogIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCINCikNCg0KY2F0KCJUYW1hw7FvIGRlIG11ZXN0cmEgcG9yIGdydXBvIChkb3MgcHJvcG9yY2lvbmVzLCBwd3IpOiIsDQogICAgY2VpbGluZyhyZXNfMnAkbiksICJcbiIpDQpgYGANCg0KQ29tcGFyYWNpw7NuIGRlIGRvcyBtZWRpYXM6DQoNCmBgYHtyfQ0KIyBQYXLDoW1ldHJvcw0KWl9hbHBoYSA8LSAxLjY0NSAgIyBOaXZlbCBkZSBjb25maWFuemEgfjk1ICUgKHVuYSBjb2xhKQ0KWl9iZXRhICA8LSAxLjI4MiAgIyBQb2RlciBlc3RhZMOtc3RpY28gOTAgJQ0KUyAgICAgICA8LSAxNiAgICAgIyBEZXN2aWFjacOzbiBlc3TDoW5kYXINCmRfbWVhbiAgPC0gMTUgICAgICMgRGlmZXJlbmNpYSBlc3BlcmFkYSBlbnRyZSBtZWRpYXMNCg0KIyBDw6FsY3VsbyBkZWwgdGFtYcOxbyBkZSBtdWVzdHJhIHBvciBncnVwbw0Kbl9kb3NfbWVkaWFzIDwtICgyICogKFpfYWxwaGEgKyBaX2JldGEpXjIgKiBTXjIpIC8gKGRfbWVhbl4yKQ0KDQpjYXQoIlRhbWHDsW8gZGUgbXVlc3RyYSBwb3IgZ3J1cG8gKGRvcyBtZWRpYXMsIG1hbnVhbCk6IiwNCiAgICBjZWlsaW5nKG5fZG9zX21lZGlhcyksICJcbiIpDQpgYGANCg0K