Trabajo elaborado para la asignatura “Programación y manejo de datos en la era del Big Data” de la Universitat de València durante el curso 2020-2021. La página web de la asignatura puede verse aquí: https://perezp44.github.io/intro-ds-20-21-web/. Los trabajos de mis compañeros de curso pueden verse aquí.



1. Introducción

Los Juegos Olímpicos, son el mayor evento deportivo del mundo. En él participan atletas de diversas partes del mundo y son considerados como el evento deportivo con más participantes, con más de doscientas naciones participantes. Existen dos tipos, los de verano y los de invierno, sin embargo, nosotros vamos a centrarnos en los de verano.

La primera edición de los llamados Juegos Olímpicos de la era moderna se llevó a cabo en Atenas, capital de Grecia en 1896. Desde entonces se han realizado cada 4 años excepto las ediciones de 1916, 1940 y 1944, debido al estallido de la Primera y Segunda Guerra Mundial; y la de 2020 que ha sido postergada a 2021, por la pandemia de COVID-19.

Cargar paquetes

library(tidyverse)
library(highcharter)
library(gganimate)
library(ggplot2)
library(RColorBrewer)
library(patchwork)
library(plotly)
library(robservable)
library(gt)
library(ggthemes)
library(gghighlight)

Limpieza de los datos

Primero para buscar ideas de trabajos miramos en https://www.kaggle.com/ donde nos topamos con dos datasets muy interesantes, los cuales hemos utilizado para el trabajo. Son 120 years of Olympic history: athletes and results y Olympic Track & Field Results. En el primero tenemos datos de los atletas que han participado en los olimpiadas desde 1896 y en el segundo tenemos los tiempos y marcas en algunas de las pruebas para los tres primeros clasificados.

A continuación procedemos a la limpieza del dataset 120 years of Olympic history: athletes and results.


#Pesaban demasiado los datos originales como para subirlo al GitHub

# athletes <- rio::import(here::here("datos", "athlete_events.csv"))
# regions <- rio::import(here::here("datos", "noc_regions.csv"))

#unimos los datasets

#df <- left_join(athletes, regions)

#tratamos los datos

# df_summer_medals <- df %>% filter(!is.na(Medal)) %>% filter(Season == "Summer")

#ya lo tenemos para más tarde

# rio::export(df_summer_medals, "./datos/df_summer_medals.csv")

# ath <- athletes %>% select(ID, Name, Sex, Age, Weight, NOC, Year, Season, Sport, Medal, Team)

# rio::export(ath, "./datos/ath.csv")

#importamos 
athletes <- rio::import("./datos/ath.csv")

#importamos directamente el dataset con datos de verano y medallas
df_summer_medals <- rio::import(here::here("datos", "df_summer_medals.csv"))

str(df_summer_medals)
#> 'data.frame':    34088 obs. of  17 variables:
#>  $ ID    : int  4 15 15 17 17 17 17 17 21 25 ...
#>  $ Name  : chr  "Edgar Lindenau Aabye" "Arvo Ossian Aaltonen" "Arvo Ossian Aaltonen" "Paavo Johannes Aaltonen" ...
#>  $ Sex   : chr  "M" "M" "M" "M" ...
#>  $ Age   : int  34 30 30 28 28 28 28 32 27 24 ...
#>  $ Height: int  NA NA NA 175 175 175 175 175 163 NA ...
#>  $ Weight: num  NA NA NA 64 64 64 64 64 NA NA ...
#>  $ Team  : chr  "Denmark/Sweden" "Finland" "Finland" "Finland" ...
#>  $ NOC   : chr  "DEN" "FIN" "FIN" "FIN" ...
#>  $ Games : chr  "1900 Summer" "1920 Summer" "1920 Summer" "1948 Summer" ...
#>  $ Year  : int  1900 1920 1920 1948 1948 1948 1948 1952 2008 1920 ...
#>  $ Season: chr  "Summer" "Summer" "Summer" "Summer" ...
#>  $ City  : chr  "Paris" "Antwerpen" "Antwerpen" "London" ...
#>  $ Sport : chr  "Tug-Of-War" "Swimming" "Swimming" "Gymnastics" ...
#>  $ Event : chr  "Tug-Of-War Men's Tug-Of-War" "Swimming Men's 200 metres Breaststroke" "Swimming Men's 400 metres Breaststroke" "Gymnastics Men's Individual All-Around" ...
#>  $ Medal : chr  "Gold" "Bronze" "Bronze" "Bronze" ...
#>  $ region: chr  "Denmark" "Finland" "Finland" "Finland" ...
#>  $ notes : chr  "" "" "" "" ...

2. Evolución de las medallas por país

Para empezar vamos a observar la evolución de las medallas ganadas por país a lo largo del tiempo.

Durante toda la historia, el deporte ha sido el ejército simbólico de los países. Es por esto, por lo que estar alto en el medallero olímpico es una muestra de poder.

df_1 <- df_summer_medals %>% mutate(M = case_when(
                               is.na(Medal) ~ 0,
                               TRUE ~ 1)) %>%
                           select(Year, M, region) %>%
                           group_by(region, Year) %>%
                           summarise(Medallas_anyo = sum(M))%>%
                           arrange(region)


#grafica con robservable de https://observablehq.com/@juba/bar-chart-race

df_race <- df_1  %>% mutate(value = cumsum(Medallas_anyo)) %>%
                     rename(id = region, date = Year) %>%
                     arrange(date) %>%
                     select(-Medallas_anyo)

#añadimos años del boicot y alemania
z <- data.frame(id = c("USA","Russia","Germany", "Germany", "Germany"),
              date = c(1980, 1984, 1920, 1924, 1948),
              value = c(2626,1780, 197, 197, 541))

datos <- rbind(df_race,z)

df_race_1 <- datos %>% arrange(date)


robservable(
  "https://observablehq.com/@juba/bar-chart-race",
  include = c("viewof date", "chart", "draw", "styles"),
  hide = "draw",
  input = list(
    data = df_race_1, 
    title = "Evolución de las medallas",
    subtitle = "Juegos Olímpicos de verano de 1896 a 2016",
    source = "Fuente: 120 years of Olympic history: athletes and results"
  ),
  width = 700,
  height = 710
)

Podemos observar como desde 1920 ningún país ha logrado quitarle la delantera a Estados Unidos en el total de medallas. Para observar este fenómeno más de cerca podemos mirar la evolución de los 5 países con más medallas.

Evolución top 5 paises


a_top<- df_1%>% group_by(region) %>% summarise(n = sum(Medallas_anyo)) %>% arrange(desc(n)) %>% ungroup() %>% slice_max(n, n=5)

df_top <- df_1 %>% filter(region %in% c("USA","Russia","UK", "France", "Germany"))



p <- ggplot(df_top, aes(Year, Medallas_anyo, color = region)) + geom_line() + theme_solarized() + facet_grid(rows = vars(region)) +
labs(title = "Evolución de los top 5 Países con más medallas",
    subtitle = "Juegos Olímpicos de verano de 1896 a 2016",
    caption = "Fuente: 120 years of Olympic history: athletes and results",
    x = "Años",
    y = "Número de Medallas por año") + theme(legend.position = "none")

p

Podemos observar como Francia y Reino Unido, a pesar de haber empezado con buen pie en algunas de las primeras Olimpiadas, desde entonces han seguido un ritmo constante, mientras que los casos de Estado Unidos, Rusia y Alemania se caracterizan por periodos de crecimiento más elevados. Algunos ejemplos son las Olimpiadas de de 1936 que se celebraron en Berlin cuando Hitler estaba en el poder.

Juegos Olímpicos Berlín 1936

df_nazis <- df_summer_medals %>% filter(Year == 1936, region == "Germany") %>%
                                 mutate(Total = n()) %>%
                                 select(Total,Year, region, Medal) %>%
                                 mutate(Bronce = case_when(
                               Medal == "Bronze" ~ 1,
                               TRUE ~ 0)) %>%
                                mutate(Plata = case_when(
                               Medal == "Silver" ~ 1,
                               TRUE ~ 0)) %>%
                                mutate(Oro = case_when(
                               Medal == "Gold" ~ 1,
                               TRUE ~ 0)) %>%
                                mutate(Total_oro = sum(Oro)) %>%
                                mutate(Total_plata = sum(Plata))%>%
                                mutate(Total_bronce = sum(Bronce))%>%
                                distinct(region, .keep_all = TRUE)%>%
                              dplyr::relocate(Total, .after = Total_bronce) %>%
                                select(-c(Medal, Bronce, Plata, Oro))



urls_nazis <- "https://upload.wikimedia.org/wikipedia/commons/7/7e/Flag_variant_of_Nazi_Party_%281923%29.svg"
nazis_con_urls <- df_nazis %>% add_column(urls_nazis)

nazis_con_urls %>% gt() %>%
  gt::text_transform(locations = cells_body(columns = vars(urls_nazis)),
                     fn = function(x) {gt::web_image(x, height = 50)}) %>%
  data_color(columns = vars(Total_oro),
    colors = "yellow")%>%
   data_color(columns = vars(Total_plata),
    colors = "grey")%>%
   data_color(columns = vars(Total_bronce),
    colors = "sienna")
Year region Total_oro Total_plata Total_bronce Total urls_nazis
1936 Germany 93 70 61 224

Boicot EEUU - URSS

Durante la Guerra Fría las dos superpotencias, decidieron boicotearse. Fue en 1980 en los Juegos Olímpicos de Moscú, cuando Estados Unidos decidió no asistir. Cuatro años más tarde, en 1984 fue la URSS quien decidió no acudir a las Olimpiadas de Los Ángeles.En el siguiente mapa podemos ver como fue la distribución de las medallas durante esos Juegos Olímpicos.

#mapa boicot 1980 y 1984
world <- rnaturalearth::ne_countries(scale = "medium", returnclass = "sf")

#- quito Antarctica y Groenlandia
world <- world %>% filter(subregion != "Antarctica") %>% filter(admin != "Greenland")


df_mapa_boicot <- df_summer_medals %>% filter(Year %in% c("1980", "1984")) %>%
                                group_by(region, Year) %>%
                                summarise(n = n())

world_3 <- world %>% mutate(admin = case_when(
  admin == "The Bahamas" ~ "Bahamas",
  admin == "Republic of Serbia" ~ "Serbia",
  admin == "Trinidad and Tobago" ~ "Trinidad",
  admin == "United Kingdom" ~ "UK",
  admin == "United States of America" ~ "USA",
  TRUE  ~  admin ))

df_join_2 <- left_join(df_mapa_boicot , world_3, by = c("region" = "admin"))

df_world_3 <- df_join_2 %>% select(region, n, Year, geometry)

ggplot() + geom_sf(data = world, mapping = aes(geometry = geometry)) + geom_sf(df_world_3, mapping = aes(geometry = geometry, fill = n)) + facet_grid(rows = vars(Year))  + theme_light() + theme( panel.background = element_rect(fill = "aliceblue")) +
  labs(title = "Medallas conseguidas durante el Boicot Americano y el Ruso",
    subtitle = "Juegos Olímpicos de verano de 1896 a 2016",
    caption = "Fuente: 120 years of Olympic history: athletes and results",
    color = "Medallas") + scale_fill_viridis_c(option="plasma")

Podemos observar como en ambos Juegos Olímpicos el país anfitrión fue el claro vencedor. Más tarde veremos las consecuencias de albergar unos Juegos Olímpicos.

3. Atletas y resultados

Atletas con más medallas

Si ganar una medalla olímpica es complicado, no me quiero imaginar tenerlas a montones. Esto es lo que le sucede a los siguientes deportistas. La siguiente lista son los 30 atletas con más medallas. Son unos extreterrestres en lo suyo!


#atletas más medallas
aa <- df_summer_medals %>% select(-c( Weight, Team, NOC, Season, notes)) %>%          group_by(ID)%>%
            mutate(Medallas = n())%>%
            arrange(desc(Medallas))%>%
            distinct(Name, .keep_all = TRUE)%>%
            ungroup() %>%
            slice_max(Medallas, n = 30)

aa <- aa %>% mutate(Name = forcats::as_factor(Name)) %>%
             mutate(Name = forcats::fct_reorder(Name,Medallas))

ggplot(aa,aes(Name,Medallas,color = Name,fill= Name)) +
  geom_bar(position = "stack",  width =.6,stat="identity") +
  coord_flip()+
  geom_text(aes(label= Medallas ,hjust=-.03,  colour="black"),size=3) +
  geom_text(aes(label= region), position = position_stack(vjust= 0.5),
            colour = "grey30", size = 3) +
  theme(axis.line = element_line(color = "green",size=1))+
      theme(panel.background=element_blank())+
      scale_x_discrete() +
    xlab("Atleta")+ylab("Medallas")+
  theme(legend.position = "none",
                     axis.text = element_text(size = 8,face="bold"),
        plot.title = element_text(size=16,face = "bold")) +
  ggtitle("Atletas con más medallas olímpicas " ,subtitle = "Juegos Olímpicos de verano de 1896 a 2016")

Cargamos dataframe con los tiempos

Para ver los tiempos utilizamos los datos de Olympic Track & Field Results que con la ayuda de nuestro profesor Pedro J. Pérez pudimos limpiarlos y utilizarlos en el análisis.

#realizado por Pedro J. Pérez
df_json <- jsonlite::fromJSON("./datos/results.json")
zz1 <- unnest_longer(df_json, col = games) #- con esto debería bastar pero ....

#------------- a mano
zz1 <- zz1 %>% rename(prueba = name) #- xq luego aparecerá otra variable llamada name

 ii <- 1
 location <- zz1[[1]][[1]][ii]
 year <- zz1[[1]][[3]][ii]
 gender <- zz1[[2]][ii]
 prueba <- zz1[[3]][ii]
 resultaditos <- zz1[[1]][[2]][ii]
 re <- as.data.frame(resultaditos)
 re <- re %>% add_column(location, year, gender, prueba)
 df <- re
 for (ii in 2:nrow(zz1)) {
   location <- zz1[[1]][[1]][ii]
   year <- zz1[[1]][[3]][ii]
   gender <- zz1[[2]][ii]
   prueba <- zz1[[3]][ii]
   resultaditos <- zz1[[1]][[2]][ii]
   re <- as.data.frame(resultaditos)
   re <- re %>% mutate(result = as.character(result))
   re <- re %>% add_column(location, year, gender, prueba)
   df <- bind_rows(df, re)
 }

#- df tiene 2.396 filas y 8 columnas
#- arreglar algunas cosas

df <- df %>% mutate(prueba = stringr::str_remove(prueba, " Men$") )     #- quitar Men de prueba
df <- df %>% mutate(prueba = stringr::str_remove(prueba, " Women$") )   #- quitar Women de prueba


#- arreglar el resltado (result)
#- hay distintos tipos de pruebas: carreras, lanzamientos y concursos(decathlon, heptalon).
df <- df %>% rename(mark = result) %>% relocate(mark, .after = last_col())


 #- la mark de las carreras quiero q este medido en segundos, pero esta en formato texto y no estandar: ARREGLARLO:
#- el código de bajo lo hice para un trabajo mio y estaba adaptado a los pb's de codificación de mis datos, no está adaptado a vuestros datos. Vuestros datos he visto que tienen pbs de codificacion  especificicos; por ejemplo en la marathon y supongo que en mas sitios, asi que lo de abajo funcionara hasta cierto punto
 library(stringr)
 #- 1) quitar letras
 df <- df %>% mutate(mark_x = ifelse(str_detect(mark, "[[:alpha:]]"), str_replace_all(mark, "[[:alpha:]]", "0"), mark))
  #- 3) si el tiempo es 11, pasarlo a 11.00
 df <- df %>% mutate(mark_x = ifelse( str_detect(mark_x, "^[[:digit:]]{2}$"), paste0(mark_x, ".00"), mark_x) )
  #- 4) si el tiempo es 12.1 le he de poner un 0 al final
 df <- df %>% mutate(mark_x = ifelse( str_detect(mark_x, "^[[:digit:]]{2}.[[:digit:]]{1}$"), paste0(mark_x, "0"), mark_x) )
 #- 5) si el tiempo empieza con 9.91 pues ponerle 09.91
 df <- df %>% mutate(mark_x = ifelse( str_detect(mark_x, "^[[:digit:]]{1}.[[:digit:]]{2}"), paste0("0", mark_x), mark_x) )
 #- 6) si el tiempo esta x debajo del minuto, entonces:
 df <- df   %>% mutate(mark_x = ifelse( str_detect(mark_x, "^[[:digit:]]{2}.[[:digit:]]{2}$"), paste0("00:00:", mark_x), mark_x) )
 #- 7) si el tiempo son minutos (forzarles a que tenga 2 digitos de minutos). P.ej: 7:22.44  pasarlo a 07:22.44
 df <- df %>% mutate(mark_x = ifelse( str_detect(mark_x, "^[[:digit:]]{1}:[[:digit:]]{2}.[[:digit:]]{2}$"), paste0("0", mark_x), mark_x) )
 #- 8) 44:44.44 pasa a 00:44:44.44
 df <- df %>% mutate(mark_x = ifelse( str_detect(mark_x, "^[[:digit:]]{2}:[[:digit:]]{2}.[[:digit:]]{2}$"), paste0("00:", mark_x), mark_x) )
 #- 8) 44:44.44 pasa a 00:44:44.44
 df <- df %>% mutate(mark_x = ifelse( str_detect(mark, "^[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2}$"), paste0(mark, ".00"), mark_x) )


#- funcion para pasar "02:44:33.22" a segundos ----
 my_f_tt_to_seconds <- function(xx) {
   #- meto un character con formato hh::mm:ss.dd
   aa <- stringr::str_extract(xx, "^..:..") #- extraigo las horas y minutos
   aa_1 <- stringr::str_extract(aa, "^..") %>% as.numeric(.)*60*60  #- extraigo las horas
   aa_2 <- stringr::str_extract(aa, "..$") %>% as.numeric(.)*60     #- extraigo las minutos
   cc <- stringr::str_extract(xx, "..\\...$")  #- estrae 22.55
   dd <- as.numeric(cc)
   ee <- aa_1 + aa_2 + dd
   ee
 }

 #- usamos la f. para  poner en segundo la marca de las carreras (faltaria arreglar los lanzamientos y concursos)
 #- en realidad esto solo habria que hacerlo para las carreras, no para lanzamientos, saltos y concursos
 df <- df %>% mutate(mark_xx = my_f_tt_to_seconds(mark_x))
 df <- df %>% mutate(mark_unidades = "segundos")

 rm(list = setdiff(ls(), "df"))
 #- Ademas... los datos parecen q tienen fallos. Al menos la primera fila. No puede ser que en la carrera de 10.000 en Rio FARAH le sacase dos minutos al segundo. Igual solo es ese fallo, pero ...

df_results <- rio::import(here::here("datos", "df_results.csv"))

100 metros

Puede que esta sea la disciplina olímpica más conocida, pero desgraciadamente, también la más corta.

Distribución

df_100M <- df_results%>% filter(prueba == "100M", gender == "M") %>% arrange(year)

df_100M_muj_y_hom <- df_results %>% filter(prueba == "100M")

ggplot(df_100M_muj_y_hom, aes(x = mark_xx, fill = gender)) +
        geom_histogram(aes(y = ..count..), position="identity", alpha=0.6) + scale_x_continuous(name = "Tiempo") +
  scale_y_continuous(name = "Número de atletas") +
  ggtitle("Distribución de los tiempos en 100 metros") +
  theme_bw() +
  theme(axis.line = element_line(size=1, colour = "black"),
              panel.grid.major = element_line(colour = "#d3d3d3"),
              panel.grid.minor = element_blank(),
              panel.border = element_blank(), panel.background = element_blank(),
              plot.title = element_text(size = 14, family = "Tahoma", face = "bold"),
              text=element_text(family="Tahoma"),
              axis.text.x=element_text(colour="black", size = 9),
              axis.text.y=element_text(colour="black", size = 9)) +
        scale_fill_brewer(palette="Accent") + labs(color = "Género")

Evolución de los atletas que han ganado oro

df_100M_oro <- df_100M_muj_y_hom %>% filter(medal == "G") %>% mutate(gender = case_when(
  gender == "M" ~ "Hombre",
  gender == "W" ~ "Mujer"))

p1 <- ggplot(df_100M_oro, aes(year, mark_xx, color = gender)) + geom_line() + geom_point(aes (color = name)) + theme_light() +
labs(title = "Evolución de los tiempos de los ganadores de 100 metros",
    subtitle = "Juegos Olímpicos de verano de 1896 a 2016",
    caption = "Fuente:Olympic Track & Field Results",
    x = "Año",
    y = "Tiempo",
    color = "Género y Atleta",
    tag = "Plot 1") +
  scale_fill_distiller(palette = "RdYlBu") + theme(axis.line = element_line(colour = "blue4"),
    axis.ticks = element_line(colour = "blue4"),
    panel.grid.major = element_line(colour = "ivory1"),
    legend.title = element_text(colour = "brown"),
    panel.background = element_rect(fill = "antiquewhite",
        colour = "antiquewhite1"), plot.background = element_rect(fill = "wheat2"),
    legend.background = element_rect(colour = "antiquewhite1"))


ggplotly(p1)

Gracias a estos gráficos observamos como en un siglo, los tiempos han ido cayendo en picado, además de la superioridad de los atletas hombres en esta disciplina. De momento el record olímpico lo tiene el bueno de Usain Bolt.

Peso y martillo y disco

Otra de las disciplinas más antiguas y características de esta competición deportiva, es el lanzamiento de disco y de martillo.

Cuando pensamos en lanzadores de disco y de martillo normalemente nos imaginamos personas muy fuertes y grandes, por ese motivo nos pareció interesante comprobar cuál es la relación entre el peso y las marcas en estas disciplinas.

Lanzamiento de Disco

#fusionando para ver peso en pruebas de disco
df_summer_medals <- rio::import(here::here("datos", "df_summer_medals.csv"))

aa_1 <- df_results %>% filter(prueba %in% c("Discus Throw"), gender == "M") %>% arrange(year) %>%
                       mutate(medal = case_when(
  medal == "G" ~ "Gold",
  medal == "S" ~ "Silver",
  medal == "B" ~ "Bronze",
  TRUE  ~  name ))

bb_1 <- df_summer_medals %>% filter(Event %in% c("Athletics Men's Discus Throw"))%>% arrange(Year)

df_disco <- left_join(aa_1, bb_1, by = c("nationality" = "NOC", "medal" = "Medal", "year" = "Year"))


p_2 <- ggplot(df_disco, aes(x = mark_xx, y = Weight, color = year )) +
  geom_point() +
  geom_smooth(color = "cyan4") +
  theme_bw() +
  labs(title = "Peso y Lanzamiento de Disco",
    subtitle = "Juegos Olímpicos de verano de 1896 a 2016",
    caption = "Fuente: Olympic Track & Field Results",
    x = "Marca",
    y = "Peso",
    color = "Año") + scale_color_gradient(low = "yellow", high = "red", na.value = NA) + theme(axis.line = element_line(colour = "blue4"),
    axis.ticks = element_line(colour = "blue4"),
    panel.grid.major = element_line(colour = "ivory1"),
    legend.title = element_text(colour = "brown"),
    panel.background = element_rect(fill = "antiquewhite",
        colour = "antiquewhite1"), plot.background = element_rect(fill = "wheat2"),
    legend.background = element_rect(colour = "antiquewhite1"))


ggplotly(p_2)

Lanzamiento de Martillo

#fusionando para ver peso y martillo

aa_2 <- df_results %>% filter(prueba %in% c("Hammer Throw"), gender == "M") %>% arrange(year) %>%
                       mutate(medal = case_when(
  medal == "G" ~ "Gold",
  medal == "S" ~ "Silver",
  medal == "B" ~ "Bronze",
  TRUE  ~  name ))

bb_2 <- df_summer_medals %>% filter(Event %in% c("Athletics Men's Hammer Throw"))%>% arrange(Year)

df_mart <- left_join(aa_2, bb_2, by = c("nationality" = "NOC", "medal" = "Medal", "year" = "Year"))


df_mart <- df_mart[-c(39), ]

p_3 <- ggplot(df_mart, aes(x = mark_xx, y = Weight, color = year )) +
  geom_point() +
  geom_smooth(color = "cyan4") +
  theme_bw() +
  labs(title = "Peso y Lanzamiento de Martillo",
    subtitle = "Juegos Olímpicos de verano de 1896 a 2016",
    caption = "Fuente: Olympic Track & Field Results",
    x = "Marca",
    y = "Peso",
    color = "Año") + scale_color_gradient(low = "yellow", high = "red", na.value = NA) + theme(axis.line = element_line(colour = "blue4"),
    axis.ticks = element_line(colour = "blue4"),
    panel.grid.major = element_line(colour = "ivory1"),
    legend.title = element_text(colour = "brown"),
    panel.background = element_rect(fill = "antiquewhite",
        colour = "antiquewhite1"), plot.background = element_rect(fill = "wheat2"),
    legend.background = element_rect(colour = "antiquewhite1")) + annotate(geom = "text", x = 82.91, y = 98, label = "record", hjust = "up") 

ggplotly(p_3)

Combinando gráficos

#combinando gráficos disco y martillo
p_2 + p_3 + plot_layout(ncol = 2)

Podemos observar como en el caso de lanzamiento de disco ha habido una correlación más fuerte a través de los años entre el peso y las marcas. En el caso del lanzamiento de martillo es menos obvia esa realación. Cabe destacar que el record mundial olímpico que está en 82.91 metros y que fue realizado por el japonés Koji Murofushi en 2004 cuando él pesaba menos de 100 kg, siendo de los lanzadores de martillo con menor peso.

4. URSS: Antes y después

Ya que este trabajo pretende destacar aspectos interesantes y curiosos de los Juegos Olímpicos, teníamos la necesidad de hacer algún gráfico a la otra superpotencia, a la URSS. Estábamos interesados en averiguar, que era más “rentable” deportivamente hablando, que los territorios fueran juntos y cada uno por su cuenta. Ahí está el gráfico.

#URSS BUENA

df_summer_medals <- rio::import(here::here("datos", "df_summer_medals.csv"))

df_urss <- df_summer_medals %>% filter(NOC %in% c("URS","EUN")) %>%
  arrange(Year) %>%
  group_by(Year) %>%
  summarise(nn = n())

p <- ggplot(df_urss, aes(x =Year, y= nn, fill= "red")) + geom_col() + ylim(c(NA, 500))+ labs(title = "Gráfico URSS: Medallas totales de la URSS",
       subtitle = "(antes de su disolución en 1992)",
       x = "Años",
       y = "Medallas totales")

df_urss_post <- df_summer_medals %>% filter(NOC %in% c("EST", "RUS", "UKR", "GEO", "BLR", "AZE", "UZB", "TJK", "POL", "LTU", "ROU", "ARM" )) %>%
  filter(Year > 1992) %>%
  arrange(Year) %>%
  group_by(Year, NOC) %>%
  summarise(n = n()) %>%
  group_by(Year) %>%
  mutate(nn = sum(n))

p2 <- ggplot(df_urss_post, aes(x =Year, y= nn, fill = "red")) + stat_summary(geom="bar", position=position_stack()) + ylim(c(NA, 500)) +
  labs(title = "Gráfico URSS: Medallas totales de la URSS",
       subtitle = "(antes de su disolución en 1992)",
       x = "Años",
       y = "Medallas totales")

#fusionando dataframes
df_urss_tot <- full_join(df_urss, df_urss_post)

p3 <- ggplot(df_urss_tot, aes(x =Year, y= nn, fill = "red")) + stat_summary(geom="bar", position=position_stack())

p3 +  ylim(c(NA, 500)) + labs(title = "Gráfico URSS: Medallas totales de la URSS", subtitle = "Año 1900 hasta 2016", x = "Años",
                              y = "Medallas totales")+ theme(axis.line = element_line(color = "orange",size=1))+ theme(legend.position = "none")+ theme_solarized()+ theme(legend.position = "none") + geom_vline(xintercept = 1994)

5.Mujeres

Participación

El siglo XXI es sin duda el siglo de las mujeres, y es por esto por lo que pretendíamos en esta parte, observar como su participación ha ido creciendo. Nosotros creemos que lo seguirá haciendo mucho más. También hemos intentado mostrar, como esa participación no está distribuida de igual manera entre los continentes.


library(ggthemes)

athletes <- rio::import(here::here("datos", "ath.csv"))

df_mujeres <- athletes %>% 
  filter(Sex=="F")%>%
  group_by(Season, Year) %>%
  summarise(nn = n())

p <- ggplot(df_mujeres, aes(Year,nn, color= Season))+ geom_point()+ geom_line()

  
p + labs(title = "Participación mujeres atletas en JJOO",
       subtitle = "Desde 1990 hasta 2016" ,
       x = "Años",
       y = "Participación")+ theme(axis.line = element_line(color = "orange",size=1))+ theme(panel.background=element_blank())+ 
  theme(legend.position = "none",
        axis.text = element_text(size = 8,face="bold"),
        plot.title = element_text(size=16,face = "bold"))+ theme_solarized()

Comparación continentes

athletes <- rio::import(here::here("datos", "ath.csv"))

df_mujeres <- athletes %>% 
  filter(Sex=="F")%>%
  select(Sex, Year, Team, Season)

df_mujeres2 <- athletes %>% 
  filter(Sex=="F")%>%
  group_by(Season, Year,Team) %>%
  summarise(nn = n())


df_mujeres3 <- df_mujeres2 %>% filter(Team %in% c("Spain", "Netherlands", "Finland", "Italy", "Portugal","Canada","Cuba","Brazil","United States","Colombia","China","India","Japon","South Korea","North Korea","Australia","New Zealand","Fiji","Papua New Guinea","Samoa","Egypt","South Africa", "Nigeria", "   
Kenya","Cameroon"))

df_mujeres4 <- df_mujeres3 %>%  mutate(CONTINENTES= case_when(
  Team == "Spain" ~ "Europa",
  Team == "Netherlands" ~ "Europa",
  Team == "Finland" ~ "Europa",
  Team == "Italy" ~ "Europa",
  Team =="Portugal"~ "Europa",
  Team == "Canada" ~ "America",
  Team == "Cuba" ~ "America",
  Team == "Brazil" ~ "America",
  Team == "United States"~ "America",
  Team == "Colombia"~ "America",
  Team == "India" ~ "Asia",
  Team == "Japon" ~ "Asia",
  Team == "South Korea" ~ "Asia",
  Team == "North Korea" ~ "Asia",
  Team == "China" ~ "Asia",
  Team == "Australia"  ~ "Oceanía",
  Team == "New Zealand"~ "Oceanía",
  Team == "Fiji"~ "Oceanía",
  Team == "Papua New Guinea"~ "Oceanía",
  Team == "Samoa" ~ "Oceanía",
  Team == "Cameroon" ~ "Africa",
  Team == "Kenya" ~ "Africa",
  Team == "Egypt"~ "Africa", 
  Team == "South Africa"~ "Africa",
  Team == "Nigeria"~ "Africa"))


library(gghighlight)

ggplot(df_mujeres4 , aes(x = Year,  y = nn, color= CONTINENTES))+ geom_point() + ylim(c(NA, 500)) + 
  labs(title = "Participacion de la mujer por continentes", subtitle = "Año 1900 hasta 2016", x = "Años",
       y = "Atletas")+ theme(axis.line = element_line(color = "orange",size=1))+
  theme(panel.background=element_blank())+
  theme(axis.text = element_text(size = 8,face="bold"),
        plot.title = element_text(size=16,face = "bold"))+  gghighlight::gghighlight() + 
  facet_wrap(vars(CONTINENTES))+ theme_solarized()

6.Curiosidades

Paises organizadores

Cuando estábamos haciendo el trabajo leímos un artículo que comentaba que los países organizadores de los Juegos Olímpicos, a parte de que cuando compiten en casa obtienen sus mejores resultados, provocan la visibilización de ciertos deportes minoritarios, haciendo que los resultados olímpicos posteriores continúen siendo buenos.

Esto hemos intentado mostrar en este gráfico, con resultados dispares.

df_2 <- df_summer_medals %>%
  filter(Year > 1948) %>% mutate(M = case_when(
  is.na(Medal) ~ 0,
  TRUE ~ 1)) %>%
  select(Year, M, region) %>%
  group_by(region, Year) %>%
  summarise(Medallas_anyo = sum(M))%>%
  arrange(region)

Mediterráneo <- df_2 %>% filter(region %in% c("Spain", "Portugal", "Italy", "Greece"))


mediterrania <- ggplot(Mediterráneo, aes(x=Year, y=Medallas_anyo, group=region, color=region)) +
  geom_point() +
  geom_line() +
  scale_color_manual(values=c("darkblue","red", "gold", "green"))  +
  theme(plot.title = element_text(hjust = 0.5)) +
  labs(title="Como han crecido nuestro compañeros")

mediterrania + geom_vline(aes(xintercept=1960), color="#990000", linetype="dashed")+ geom_vline(aes(xintercept=1992), color="brown", linetype="dashed") + geom_vline(aes(xintercept=2004), color="brown", linetype="dashed")

Korea

No sé si sabrán que el gobierno norcoreano le suele decir a sus compatriotas que siempre obtienen más medallas que sus vecinos del sur. Pero, nada más lejos de la realidad. Desde que se separaron, a Corea del Sur cada vez le va mejor, mientras que a Corea del Norte, peor.

korea <- df_summer_medals %>%
  filter(Year > 1970) %>% mutate(M = case_when(
  is.na(Medal) ~ 0,
  TRUE ~ 1)) %>%
  group_by(region, Year) %>%
  summarise(Medallas_anyo = sum(M))%>%
  arrange(region)

koreas <- korea %>% filter(region %in% c("North Korea","South Korea"))

ggplot(koreas, aes(x=Year, y=Medallas_anyo, group=region, color=region)) +
  geom_point(alpha=0.6) +
  geom_abline(intercept=0, slope=1, linetype="dashed") +
  geom_smooth(method="lm", se=FALSE) +
  labs(title = "Crecimiento medallero de las dos Coreas") +
  theme(plot.title = element_text(hjust = 0.5)) +
  guides(color=guide_legend(reverse=TRUE))

Distribucion por edad y olimpiada

Para ir acabando el trabajo, nos apetecía observar los cambios en las edades de los participantes. En muchas otras disciplinas ocurre que precocidad está a la orden del día. Queríamos verlo si aquí también.

athletes <- rio::import(here::here("datos", "ath.csv"))

age_1896 <- athletes%>%filter(Sex=="M",Season=='Summer',Year==1896)%>%group_by(Sport)%>%summarize(avg=round(mean(Age,na.rm = TRUE),1))

age_1936 <- athletes%>%filter(Sex=="M",Season=='Summer',Year==1936)%>%group_by(Sport)%>%summarize(avg=round(mean(Age,na.rm = TRUE),1))

age_1972 <- athletes%>%filter(Sex=="M",Season=='Summer',Year==1972)%>%group_by(Sport)%>%summarize(avg=round(mean(Age,na.rm = TRUE),1))

age_1992 <- athletes%>%filter(Sex=="M",Season=='Summer',Year == 1992)%>%group_by(Sport)%>%summarize(avg=round(mean(Age,na.rm = TRUE),1))

age_2016 <- athletes%>%filter(Sex=="M",Season=='Summer',Year == 2016)%>%group_by(Sport)%>%summarize(avg=round(mean(Age,na.rm = TRUE),1))


age_y = athletes%>%filter(Season=='Summer')%>%group_by(Sport)%>%summarize(Y=unique(Sport))



highchart(height = "700px") %>%
  hc_title(text = "Media de Edad por Deporte en distintas Olimpiada") %>%
  hc_subtitle(text = "Juegos Olímpicos de verano de 1896 a 2016") %>%
  hc_credits(enabled = TRUE, text = "Fuente: 120 years of Olympic history: athletes and results",
             style = list(fontSize = "10px")) %>%
  hc_add_theme(hc_theme_ft()) %>%
  hc_xAxis(categories = age_y$Y,title = list(text = "Deporte")) %>%
  hc_add_series(name = "1896", data = age_1896$avg)%>%
  hc_add_series(name = "1936",data = age_1936$avg)%>%
  hc_add_series(name = "1972",data = age_1972$avg)%>%
  hc_add_series(name = "1992", data = age_1992$avg) %>%
  hc_add_series(name = "2016",data = age_2016$avg)%>%

 hc_yAxis(title = list(text = "Media de edad"),
           labels = list(format = "{value}"), max = 50) %>%
   hc_legend(enabled = T, align= "left", verticalAlign = "bottom")

Es interesante observar como la media de edad en Alpinismo en los Juegos de 1936 estaba en 49 años o como en el caso de Badminton en 1896 o Patinaje Artístico en 1972 sobrepasan por poco la mayoría de edad.

7.Conclusión

A modo de conclusión, destacar, como hemos dicho al comienzo, que sin ningún tipo de duda, los Juegos Olímpicos son el mayor evento deportivo del mundo. Es más, creemos que este acontecimiento trasciende lo puramente deportivo, llegando a convertirse en un evento tanto social como cultural y por supuesto político. Para finalizar consideramos que los Juegos Olímpicos tanto en la Antigua Grecia como en la actualidad, son un instrumento que transcurren en paralelo con la historia de la humanidad y, a través de ellos, podemos aprender y entender todo lo sucedido en el último siglo.

Bibliografía

De aquí sacamos los datos de 120 years of Olympic history: athletes and results.

Trabajos que nos han inspirado:

De aquí sacamos los datos de Olympic Track & Field Results

De aquí sacamos el diseño del histograma de 100 metros.

LS0tDQp0aXRsZTogIkV2b2x1Y2nDs24geSBjdXJpb3NpZGFkZXMgZGUgbG9zIEp1ZWdvcyBPbMOtbXBpY29zIg0KYXV0aG9yOiAiQW50b25pbyBMYW5nYSBMYWhveihhbmxhbmxhQGFsdW1uaS51di5lcykgIFxuXG4gTWFudWVsIFJvam8gTMOzcGV6KHJvbG9tYTZAYWx1bW5pLnV2LmVzKSAgXG4gXG4gTWFudWVsIEppbcOpbmV6IEhhcm8obWFqaWhhQGFsdW1uaS51di5lcykuIFxuXG4gVW5pdmVyc2l0YXQgZGUgVmFsw6huY2lhIg0KZGF0ZTogIkRpY2llbWJyZSBkZSAyMDIwIChhY3R1YWxpemFkbyBlbCBgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkLSVtLSVZJylgKSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0aGVtZTogcGFwZXINCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlIA0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMyANCiAgICB0b2NfZmxvYXQ6IA0KICAgICAgY29sbGFwc2VkOiB0cnVlDQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlDQogICAgZGZfcHJpbnQ6IGthYmxlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KLS0tDQoNCmBgYHtyIHBhY2thZ2VzLXNldHVwLCBpbmNsdWRlID0gRkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoa2xpcHB5KSAgIy0gcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInJsZXN1ci9rbGlwcHkiKQ0KbGlicmFyeShrbml0cikNCmBgYA0KDQpgYGB7ciBjaHVuay1zZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBldmFsID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgICAgICNyZXN1bHRzID0gImhvbGQiLA0KICAgICAgICAgICAgICAgICAgICAgIGNhY2hlID0gRkFMU0UsIGNhY2hlLnBhdGggPSAiL2NhY2hlcy8iLCBjb21tZW50ID0gIiM+IiwNCiAgICAgICAgICAgICAgICAgICAgICAjZmlnLndpZHRoID0gNywgI2ZpZy5oZWlnaHQ9IDcsICAgDQogICAgICAgICAgICAgICAgICAgICAgI291dC53aWR0aCA9IDcsIG91dC5oZWlnaHQgPSA3LA0KICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlID0gVFJVRSwgIGZpZy5zaG93ID0gImhvbGQiLA0KICAgICAgICAgICAgICAgICAgICAgIGZpZy5hc3AgPSA3LzksIG91dC53aWR0aCA9ICI2MCUiLCBmaWcuYWxpZ24gPSAiY2VudGVyIikNCmtuaXRyOjpvcHRzX2NodW5rJHNldChkZXYgPSAicG5nIiwgZGV2LmFyZ3MgPSBsaXN0KHR5cGUgPSAiY2Fpcm8tcG5nIikpDQpgYGANCg0KYGBge3Igb3B0aW9ucy1zZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICMtIHBhcmEgcXVpdGFyIGxhIG5vdGFjacOzbiBjaWVudMOtZmljYQ0Kb3B0aW9ucygieWFtbC5ldmFsLmV4cHIiID0gVFJVRSkgDQpgYGANCg0KDQpgYGB7ciBrbGlwcHksIGVjaG8gPSBGQUxTRX0NCmtsaXBweTo6a2xpcHB5KHBvc2l0aW9uID0gYygidG9wIiwgInJpZ2h0IikpICMtIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJybGVzdXIva2xpcHB5IikNCmBgYA0KDQotLS0tLS0tLS0tLS0tLS0tLQ0KDQpUcmFiYWpvICBlbGFib3JhZG8gcGFyYSBsYSBhc2lnbmF0dXJhICJQcm9ncmFtYWNpw7NuIHkgbWFuZWpvIGRlIGRhdG9zIGVuIGxhIGVyYSBkZWwgQmlnIERhdGEiIGRlIGxhIFVuaXZlcnNpdGF0IGRlIFZhbMOobmNpYSBkdXJhbnRlIGVsIGN1cnNvIDIwMjAtMjAyMS4gTGEgcMOhZ2luYSB3ZWIgZGUgbGEgYXNpZ25hdHVyYSBwdWVkZSB2ZXJzZSBhcXXDrTogPGh0dHBzOi8vcGVyZXpwNDQuZ2l0aHViLmlvL2ludHJvLWRzLTIwLTIxLXdlYi8+LiBMb3MgdHJhYmFqb3MgZGUgbWlzIGNvbXBhw7Flcm9zIGRlIGN1cnNvIHB1ZWRlbiB2ZXJzZSBbYXF1w61dKGh0dHBzOi8vcGVyZXpwNDQuZ2l0aHViLmlvL2ludHJvLWRzLTIwLTIxLXdlYi8wNy10cmFiYWpvcy5odG1sKS4NCg0KLS0tLS0tLS0tLS0tLS0tDQoNCjxicj4NCg0KIyAxLiBJbnRyb2R1Y2Npw7NuDQoNCmBgYHtyIGV2YWwgPSBUUlVFLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWFnZW5lcyIsICJhcm9zLmpwZyIpKQ0KYGBgDQoNCkxvcyBKdWVnb3MgT2zDrW1waWNvcywgc29uIGVsIG1heW9yIGV2ZW50byBkZXBvcnRpdm8gZGVsIG11bmRvLiBFbiDDqWwgcGFydGljaXBhbiBhdGxldGFzIGRlIGRpdmVyc2FzIHBhcnRlcyBkZWwgbXVuZG8geSBzb24gY29uc2lkZXJhZG9zIGNvbW8gZWwgZXZlbnRvIGRlcG9ydGl2byBjb24gbcOhcyBwYXJ0aWNpcGFudGVzLCBjb24gbcOhcyBkZSBkb3NjaWVudGFzIG5hY2lvbmVzIHBhcnRpY2lwYW50ZXMuIEV4aXN0ZW4gZG9zIHRpcG9zLCBsb3MgZGUgdmVyYW5vIHkgbG9zIGRlIGludmllcm5vLCBzaW4gZW1iYXJnbywgbm9zb3Ryb3MgdmFtb3MgYSBjZW50cmFybm9zIGVuIGxvcyBkZSB2ZXJhbm8uIA0KDQpMYSBwcmltZXJhIGVkaWNpw7NuIGRlIGxvcyBsbGFtYWRvcyBKdWVnb3MgT2zDrW1waWNvcyBkZSBsYSBlcmEgbW9kZXJuYSBzZSBsbGV2w7MgYSBjYWJvIGVuIEF0ZW5hcywgY2FwaXRhbCBkZSBHcmVjaWEgZW4gMTg5Ni4gRGVzZGUgZW50b25jZXMgc2UgaGFuIHJlYWxpemFkbyBjYWRhIDQgYcOxb3MgZXhjZXB0byBsYXMgZWRpY2lvbmVzIGRlIDE5MTYsIDE5NDAgeSAxOTQ0LCBkZWJpZG8gYWwgZXN0YWxsaWRvIGRlIGxhIFByaW1lcmEgeSBTZWd1bmRhIEd1ZXJyYSBNdW5kaWFsOyB5IGxhIGRlIDIwMjAgcXVlIGhhIHNpZG8gcG9zdGVyZ2FkYSBhIDIwMjEsIHBvciBsYSBwYW5kZW1pYSBkZSBDT1ZJRC0xOS4NCg0KIyMgQ2FyZ2FyIHBhcXVldGVzDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShoaWdoY2hhcnRlcikNCmxpYnJhcnkoZ2dhbmltYXRlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQpsaWJyYXJ5KHBhdGNod29yaykNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShyb2JzZXJ2YWJsZSkNCmxpYnJhcnkoZ3QpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KbGlicmFyeShnZ2hpZ2hsaWdodCkNCmBgYA0KDQoNCiMjIExpbXBpZXphIGRlIGxvcyBkYXRvcw0KDQpQcmltZXJvIHBhcmEgYnVzY2FyIGlkZWFzIGRlIHRyYWJham9zIG1pcmFtb3MgZW4gPGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vPiBkb25kZSBub3MgdG9wYW1vcyBjb24gZG9zIGRhdGFzZXRzIG11eSBpbnRlcmVzYW50ZXMsIGxvcyBjdWFsZXMgaGVtb3MgdXRpbGl6YWRvIHBhcmEgZWwgdHJhYmFqby4gU29uIFsxMjAgeWVhcnMgb2YgT2x5bXBpYyBoaXN0b3J5OiBhdGhsZXRlcyBhbmQgcmVzdWx0c10oaHR0cDovL2h0dHBzOi8vd3d3LmthZ2dsZS5jb20vaGVlc29vMzcvMTIwLXllYXJzLW9mLW9seW1waWMtaGlzdG9yeS1hdGhsZXRlcy1hbmQtcmVzdWx0cykgeSBbT2x5bXBpYyBUcmFjayAmIEZpZWxkIFJlc3VsdHNdKGh0dHA6Ly9odHRwczovL3d3dy5rYWdnbGUuY29tL2pheXJhdjEzL29seW1waWMtdHJhY2stZmllbGQtcmVzdWx0cykuIEVuIGVsIHByaW1lcm8gdGVuZW1vcyBkYXRvcyBkZSBsb3MgYXRsZXRhcyBxdWUgaGFuIHBhcnRpY2lwYWRvIGVuIGxvcyBvbGltcGlhZGFzIGRlc2RlIDE4OTYgeSBlbiBlbCBzZWd1bmRvIHRlbmVtb3MgbG9zIHRpZW1wb3MgeSBtYXJjYXMgZW4gYWxndW5hcyBkZSBsYXMgcHJ1ZWJhcyBwYXJhIGxvcyB0cmVzIHByaW1lcm9zIGNsYXNpZmljYWRvcy4NCg0KQSBjb250aW51YWNpw7NuIHByb2NlZGVtb3MgYSBsYSBsaW1waWV6YSBkZWwgZGF0YXNldCBbMTIwIHllYXJzIG9mIE9seW1waWMgaGlzdG9yeTogYXRobGV0ZXMgYW5kIHJlc3VsdHNdKGh0dHA6Ly9odHRwczovL3d3dy5rYWdnbGUuY29tL2hlZXNvbzM3LzEyMC15ZWFycy1vZi1vbHltcGljLWhpc3RvcnktYXRobGV0ZXMtYW5kLXJlc3VsdHMpLiANCmBgYHtyfQ0KDQojUGVzYWJhbiBkZW1hc2lhZG8gbG9zIGRhdG9zIG9yaWdpbmFsZXMgY29tbyBwYXJhIHN1YmlybG8gYWwgR2l0SHViDQoNCiMgYXRobGV0ZXMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAiYXRobGV0ZV9ldmVudHMuY3N2IikpDQojIHJlZ2lvbnMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAibm9jX3JlZ2lvbnMuY3N2IikpDQoNCiN1bmltb3MgbG9zIGRhdGFzZXRzDQoNCiNkZiA8LSBsZWZ0X2pvaW4oYXRobGV0ZXMsIHJlZ2lvbnMpDQoNCiN0cmF0YW1vcyBsb3MgZGF0b3MNCg0KIyBkZl9zdW1tZXJfbWVkYWxzIDwtIGRmICU+JSBmaWx0ZXIoIWlzLm5hKE1lZGFsKSkgJT4lIGZpbHRlcihTZWFzb24gPT0gIlN1bW1lciIpDQoNCiN5YSBsbyB0ZW5lbW9zIHBhcmEgbcOhcyB0YXJkZQ0KDQojIHJpbzo6ZXhwb3J0KGRmX3N1bW1lcl9tZWRhbHMsICIuL2RhdG9zL2RmX3N1bW1lcl9tZWRhbHMuY3N2IikNCg0KIyBhdGggPC0gYXRobGV0ZXMgJT4lIHNlbGVjdChJRCwgTmFtZSwgU2V4LCBBZ2UsIFdlaWdodCwgTk9DLCBZZWFyLCBTZWFzb24sIFNwb3J0LCBNZWRhbCwgVGVhbSkNCg0KIyByaW86OmV4cG9ydChhdGgsICIuL2RhdG9zL2F0aC5jc3YiKQ0KDQojaW1wb3J0YW1vcyANCmF0aGxldGVzIDwtIHJpbzo6aW1wb3J0KCIuL2RhdG9zL2F0aC5jc3YiKQ0KDQojaW1wb3J0YW1vcyBkaXJlY3RhbWVudGUgZWwgZGF0YXNldCBjb24gZGF0b3MgZGUgdmVyYW5vIHkgbWVkYWxsYXMNCmRmX3N1bW1lcl9tZWRhbHMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAiZGZfc3VtbWVyX21lZGFscy5jc3YiKSkNCg0Kc3RyKGRmX3N1bW1lcl9tZWRhbHMpDQoNCmBgYA0KDQojIDIuIEV2b2x1Y2nDs24gZGUgbGFzIG1lZGFsbGFzIHBvciBwYcOtcw0KDQpQYXJhIGVtcGV6YXIgdmFtb3MgYSBvYnNlcnZhciBsYSBldm9sdWNpw7NuIGRlIGxhcyBtZWRhbGxhcyBnYW5hZGFzIHBvciBwYcOtcyBhIGxvIGxhcmdvIGRlbCB0aWVtcG8uDQoNCkR1cmFudGUgdG9kYSBsYSBoaXN0b3JpYSwgZWwgZGVwb3J0ZSBoYSBzaWRvIGVsIGVqw6lyY2l0byBzaW1iw7NsaWNvIGRlIGxvcyBwYcOtc2VzLiBFcyBwb3IgZXN0bywgcG9yIGxvIHF1ZSBlc3RhciBhbHRvIGVuIGVsIG1lZGFsbGVybyBvbMOtbXBpY28gZXMgdW5hIG11ZXN0cmEgZGUgcG9kZXIuIA0KDQpgYGB7cn0NCmRmXzEgPC0gZGZfc3VtbWVyX21lZGFscyAlPiUgbXV0YXRlKE0gPSBjYXNlX3doZW4oDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMubmEoTWVkYWwpIH4gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gMSkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KFllYXIsIE0sIHJlZ2lvbikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShyZWdpb24sIFllYXIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKE1lZGFsbGFzX2FueW8gPSBzdW0oTSkpJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKHJlZ2lvbikNCg0KDQojZ3JhZmljYSBjb24gcm9ic2VydmFibGUgZGUgaHR0cHM6Ly9vYnNlcnZhYmxlaHEuY29tL0BqdWJhL2Jhci1jaGFydC1yYWNlDQoNCmRmX3JhY2UgPC0gZGZfMSAgJT4lIG11dGF0ZSh2YWx1ZSA9IGN1bXN1bShNZWRhbGxhc19hbnlvKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICByZW5hbWUoaWQgPSByZWdpb24sIGRhdGUgPSBZZWFyKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGF0ZSkgJT4lDQogICAgICAgICAgICAgICAgICAgICBzZWxlY3QoLU1lZGFsbGFzX2FueW8pDQoNCiNhw7FhZGltb3MgYcOxb3MgZGVsIGJvaWNvdCB5IGFsZW1hbmlhDQp6IDwtIGRhdGEuZnJhbWUoaWQgPSBjKCJVU0EiLCJSdXNzaWEiLCJHZXJtYW55IiwgIkdlcm1hbnkiLCAiR2VybWFueSIpLA0KICAgICAgICAgICAgICBkYXRlID0gYygxOTgwLCAxOTg0LCAxOTIwLCAxOTI0LCAxOTQ4KSwNCiAgICAgICAgICAgICAgdmFsdWUgPSBjKDI2MjYsMTc4MCwgMTk3LCAxOTcsIDU0MSkpDQoNCmRhdG9zIDwtIHJiaW5kKGRmX3JhY2UseikNCg0KZGZfcmFjZV8xIDwtIGRhdG9zICU+JSBhcnJhbmdlKGRhdGUpDQoNCg0Kcm9ic2VydmFibGUoDQogICJodHRwczovL29ic2VydmFibGVocS5jb20vQGp1YmEvYmFyLWNoYXJ0LXJhY2UiLA0KICBpbmNsdWRlID0gYygidmlld29mIGRhdGUiLCAiY2hhcnQiLCAiZHJhdyIsICJzdHlsZXMiKSwNCiAgaGlkZSA9ICJkcmF3IiwNCiAgaW5wdXQgPSBsaXN0KA0KICAgIGRhdGEgPSBkZl9yYWNlXzEsIA0KICAgIHRpdGxlID0gIkV2b2x1Y2nDs24gZGUgbGFzIG1lZGFsbGFzIiwNCiAgICBzdWJ0aXRsZSA9ICJKdWVnb3MgT2zDrW1waWNvcyBkZSB2ZXJhbm8gZGUgMTg5NiBhIDIwMTYiLA0KICAgIHNvdXJjZSA9ICJGdWVudGU6IDEyMCB5ZWFycyBvZiBPbHltcGljIGhpc3Rvcnk6IGF0aGxldGVzIGFuZCByZXN1bHRzIg0KICApLA0KICB3aWR0aCA9IDcwMCwNCiAgaGVpZ2h0ID0gNzEwDQopDQpgYGANCg0KUG9kZW1vcyBvYnNlcnZhciBjb21vIGRlc2RlIDE5MjAgbmluZ8O6biBwYcOtcyBoYSBsb2dyYWRvIHF1aXRhcmxlIGxhIGRlbGFudGVyYSBhIEVzdGFkb3MgVW5pZG9zIGVuIGVsIHRvdGFsIGRlIG1lZGFsbGFzLiBQYXJhIG9ic2VydmFyIGVzdGUgZmVuw7NtZW5vIG3DoXMgZGUgY2VyY2EgcG9kZW1vcyBtaXJhciBsYSBldm9sdWNpw7NuIGRlIGxvcyA1IHBhw61zZXMgY29uIG3DoXMgbWVkYWxsYXMuDQoNCiMjIEV2b2x1Y2nDs24gdG9wIDUgcGFpc2VzDQoNCmBgYHtyfQ0KDQphX3RvcDwtIGRmXzElPiUgZ3JvdXBfYnkocmVnaW9uKSAlPiUgc3VtbWFyaXNlKG4gPSBzdW0oTWVkYWxsYXNfYW55bykpICU+JSBhcnJhbmdlKGRlc2MobikpICU+JSB1bmdyb3VwKCkgJT4lIHNsaWNlX21heChuLCBuPTUpDQoNCmRmX3RvcCA8LSBkZl8xICU+JSBmaWx0ZXIocmVnaW9uICVpbiUgYygiVVNBIiwiUnVzc2lhIiwiVUsiLCAiRnJhbmNlIiwgIkdlcm1hbnkiKSkNCg0KDQoNCnAgPC0gZ2dwbG90KGRmX3RvcCwgYWVzKFllYXIsIE1lZGFsbGFzX2FueW8sIGNvbG9yID0gcmVnaW9uKSkgKyBnZW9tX2xpbmUoKSArIHRoZW1lX3NvbGFyaXplZCgpICsgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhyZWdpb24pKSArDQpsYWJzKHRpdGxlID0gIkV2b2x1Y2nDs24gZGUgbG9zIHRvcCA1IFBhw61zZXMgY29uIG3DoXMgbWVkYWxsYXMiLA0KICAgIHN1YnRpdGxlID0gIkp1ZWdvcyBPbMOtbXBpY29zIGRlIHZlcmFubyBkZSAxODk2IGEgMjAxNiIsDQogICAgY2FwdGlvbiA9ICJGdWVudGU6IDEyMCB5ZWFycyBvZiBPbHltcGljIGhpc3Rvcnk6IGF0aGxldGVzIGFuZCByZXN1bHRzIiwNCiAgICB4ID0gIkHDsW9zIiwNCiAgICB5ID0gIk7Dum1lcm8gZGUgTWVkYWxsYXMgcG9yIGHDsW8iKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KcA0KDQoNCmBgYA0KDQoNClBvZGVtb3Mgb2JzZXJ2YXIgY29tbyBGcmFuY2lhIHkgUmVpbm8gVW5pZG8sIGEgcGVzYXIgZGUgaGFiZXIgZW1wZXphZG8gY29uIGJ1ZW4gcGllIGVuIGFsZ3VuYXMgZGUgbGFzIHByaW1lcmFzIE9saW1waWFkYXMsIGRlc2RlIGVudG9uY2VzIGhhbiBzZWd1aWRvIHVuIHJpdG1vIGNvbnN0YW50ZSwgbWllbnRyYXMgcXVlIGxvcyBjYXNvcyBkZSBFc3RhZG8gVW5pZG9zLCBSdXNpYSB5IEFsZW1hbmlhIHNlIGNhcmFjdGVyaXphbiBwb3IgcGVyaW9kb3MgZGUgY3JlY2ltaWVudG8gbcOhcyBlbGV2YWRvcy4gQWxndW5vcyBlamVtcGxvcyBzb24gbGFzIE9saW1waWFkYXMgZGUgZGUgMTkzNiBxdWUgc2UgY2VsZWJyYXJvbiBlbiBCZXJsaW4gY3VhbmRvIEhpdGxlciBlc3RhYmEgZW4gZWwgcG9kZXIuDQoNCiMjIyBKdWVnb3MgT2zDrW1waWNvcyBCZXJsw61uIDE5MzYNCmBgYHtyfQ0KZGZfbmF6aXMgPC0gZGZfc3VtbWVyX21lZGFscyAlPiUgZmlsdGVyKFllYXIgPT0gMTkzNiwgcmVnaW9uID09ICJHZXJtYW55IikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoVG90YWwgPSBuKCkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KFRvdGFsLFllYXIsIHJlZ2lvbiwgTWVkYWwpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKEJyb25jZSA9IGNhc2Vfd2hlbigNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNZWRhbCA9PSAiQnJvbnplIiB+IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IDApKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKFBsYXRhID0gY2FzZV93aGVuKA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1lZGFsID09ICJTaWx2ZXIiIH4gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gMCkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoT3JvID0gY2FzZV93aGVuKA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1lZGFsID09ICJHb2xkIiB+IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IDApKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKFRvdGFsX29ybyA9IHN1bShPcm8pKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKFRvdGFsX3BsYXRhID0gc3VtKFBsYXRhKSklPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKFRvdGFsX2Jyb25jZSA9IHN1bShCcm9uY2UpKSU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0aW5jdChyZWdpb24sIC5rZWVwX2FsbCA9IFRSVUUpJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6cmVsb2NhdGUoVG90YWwsIC5hZnRlciA9IFRvdGFsX2Jyb25jZSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCgtYyhNZWRhbCwgQnJvbmNlLCBQbGF0YSwgT3JvKSkNCg0KDQoNCnVybHNfbmF6aXMgPC0gImh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvNy83ZS9GbGFnX3ZhcmlhbnRfb2ZfTmF6aV9QYXJ0eV8lMjgxOTIzJTI5LnN2ZyINCm5hemlzX2Nvbl91cmxzIDwtIGRmX25hemlzICU+JSBhZGRfY29sdW1uKHVybHNfbmF6aXMpDQoNCm5hemlzX2Nvbl91cmxzICU+JSBndCgpICU+JQ0KICBndDo6dGV4dF90cmFuc2Zvcm0obG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gdmFycyh1cmxzX25hemlzKSksDQogICAgICAgICAgICAgICAgICAgICBmbiA9IGZ1bmN0aW9uKHgpIHtndDo6d2ViX2ltYWdlKHgsIGhlaWdodCA9IDUwKX0pICU+JQ0KICBkYXRhX2NvbG9yKGNvbHVtbnMgPSB2YXJzKFRvdGFsX29ybyksDQogICAgY29sb3JzID0gInllbGxvdyIpJT4lDQogICBkYXRhX2NvbG9yKGNvbHVtbnMgPSB2YXJzKFRvdGFsX3BsYXRhKSwNCiAgICBjb2xvcnMgPSAiZ3JleSIpJT4lDQogICBkYXRhX2NvbG9yKGNvbHVtbnMgPSB2YXJzKFRvdGFsX2Jyb25jZSksDQogICAgY29sb3JzID0gInNpZW5uYSIpDQoNCmBgYA0KDQoNCiMjIyBCb2ljb3QgRUVVVSAtIFVSU1MNCg0KRHVyYW50ZSBsYSBHdWVycmEgRnLDrWEgbGFzIGRvcyBzdXBlcnBvdGVuY2lhcywgZGVjaWRpZXJvbiBib2ljb3RlYXJzZS4gRnVlIGVuIDE5ODAgZW4gbG9zIEp1ZWdvcyBPbMOtbXBpY29zIGRlIE1vc2PDuiwgY3VhbmRvIEVzdGFkb3MgVW5pZG9zIGRlY2lkacOzIG5vIGFzaXN0aXIuIEN1YXRybyBhw7FvcyBtw6FzIHRhcmRlLCBlbiAxOTg0IGZ1ZSBsYSBVUlNTIHF1aWVuIGRlY2lkacOzIG5vIGFjdWRpciBhIGxhcyBPbGltcGlhZGFzIGRlIExvcyDDgW5nZWxlcy5FbiBlbCBzaWd1aWVudGUgbWFwYSBwb2RlbW9zIHZlciBjb21vIGZ1ZSBsYSBkaXN0cmlidWNpw7NuIGRlIGxhcyBtZWRhbGxhcyBkdXJhbnRlIGVzb3MgSnVlZ29zIE9sw61tcGljb3MuDQoNCmBgYHtyIGV2YWwgPSBUUlVFLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWFnZW5lcyIsICJmcmlhLmpwZyIpKQ0KYGBgDQoNCg0KYGBge3J9DQojbWFwYSBib2ljb3QgMTk4MCB5IDE5ODQNCndvcmxkIDwtIHJuYXR1cmFsZWFydGg6Om5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpDQoNCiMtIHF1aXRvIEFudGFyY3RpY2EgeSBHcm9lbmxhbmRpYQ0Kd29ybGQgPC0gd29ybGQgJT4lIGZpbHRlcihzdWJyZWdpb24gIT0gIkFudGFyY3RpY2EiKSAlPiUgZmlsdGVyKGFkbWluICE9ICJHcmVlbmxhbmQiKQ0KDQoNCmRmX21hcGFfYm9pY290IDwtIGRmX3N1bW1lcl9tZWRhbHMgJT4lIGZpbHRlcihZZWFyICVpbiUgYygiMTk4MCIsICIxOTg0IikpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShyZWdpb24sIFllYXIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UobiA9IG4oKSkNCg0Kd29ybGRfMyA8LSB3b3JsZCAlPiUgbXV0YXRlKGFkbWluID0gY2FzZV93aGVuKA0KICBhZG1pbiA9PSAiVGhlIEJhaGFtYXMiIH4gIkJhaGFtYXMiLA0KICBhZG1pbiA9PSAiUmVwdWJsaWMgb2YgU2VyYmlhIiB+ICJTZXJiaWEiLA0KICBhZG1pbiA9PSAiVHJpbmlkYWQgYW5kIFRvYmFnbyIgfiAiVHJpbmlkYWQiLA0KICBhZG1pbiA9PSAiVW5pdGVkIEtpbmdkb20iIH4gIlVLIiwNCiAgYWRtaW4gPT0gIlVuaXRlZCBTdGF0ZXMgb2YgQW1lcmljYSIgfiAiVVNBIiwNCiAgVFJVRSAgfiAgYWRtaW4gKSkNCg0KZGZfam9pbl8yIDwtIGxlZnRfam9pbihkZl9tYXBhX2JvaWNvdCAsIHdvcmxkXzMsIGJ5ID0gYygicmVnaW9uIiA9ICJhZG1pbiIpKQ0KDQpkZl93b3JsZF8zIDwtIGRmX2pvaW5fMiAlPiUgc2VsZWN0KHJlZ2lvbiwgbiwgWWVhciwgZ2VvbWV0cnkpDQoNCmdncGxvdCgpICsgZ2VvbV9zZihkYXRhID0gd29ybGQsIG1hcHBpbmcgPSBhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSkpICsgZ2VvbV9zZihkZl93b3JsZF8zLCBtYXBwaW5nID0gYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnksIGZpbGwgPSBuKSkgKyBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKFllYXIpKSAgKyB0aGVtZV9saWdodCgpICsgdGhlbWUoIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJhbGljZWJsdWUiKSkgKw0KICBsYWJzKHRpdGxlID0gIk1lZGFsbGFzIGNvbnNlZ3VpZGFzIGR1cmFudGUgZWwgQm9pY290IEFtZXJpY2FubyB5IGVsIFJ1c28iLA0KICAgIHN1YnRpdGxlID0gIkp1ZWdvcyBPbMOtbXBpY29zIGRlIHZlcmFubyBkZSAxODk2IGEgMjAxNiIsDQogICAgY2FwdGlvbiA9ICJGdWVudGU6IDEyMCB5ZWFycyBvZiBPbHltcGljIGhpc3Rvcnk6IGF0aGxldGVzIGFuZCByZXN1bHRzIiwNCiAgICBjb2xvciA9ICJNZWRhbGxhcyIpICsgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uPSJwbGFzbWEiKQ0KYGBgDQoNClBvZGVtb3Mgb2JzZXJ2YXIgY29tbyBlbiBhbWJvcyBKdWVnb3MgT2zDrW1waWNvcyBlbCBwYcOtcyBhbmZpdHJpw7NuIGZ1ZSBlbCBjbGFybyB2ZW5jZWRvci4gTcOhcyB0YXJkZSB2ZXJlbW9zIGxhcyBjb25zZWN1ZW5jaWFzIGRlIGFsYmVyZ2FyIHVub3MgSnVlZ29zIE9sw61tcGljb3MuDQoNCg0KIyAzLiBBdGxldGFzIHkgcmVzdWx0YWRvcw0KDQojIyBBdGxldGFzIGNvbiBtw6FzIG1lZGFsbGFzDQoNCmBgYHtyIGV2YWwgPSBUUlVFLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWFnZW5lcyIsICJwaGVscHMuanBnIikpDQpgYGANCg0KU2kgZ2FuYXIgdW5hIG1lZGFsbGEgb2zDrW1waWNhIGVzIGNvbXBsaWNhZG8sIG5vIG1lIHF1aWVybyBpbWFnaW5hciB0ZW5lcmxhcyBhIG1vbnRvbmVzLiBFc3RvIGVzIGxvIHF1ZSBsZSBzdWNlZGUgYSBsb3Mgc2lndWllbnRlcyBkZXBvcnRpc3Rhcy4gDQpMYSBzaWd1aWVudGUgbGlzdGEgc29uIGxvcyAzMCBhdGxldGFzIGNvbiBtw6FzIG1lZGFsbGFzLiBTb24gdW5vcyBleHRyZXRlcnJlc3RyZXMgZW4gbG8gc3V5byENCg0KYGBge3J9DQoNCiNhdGxldGFzIG3DoXMgbWVkYWxsYXMNCmFhIDwtIGRmX3N1bW1lcl9tZWRhbHMgJT4lIHNlbGVjdCgtYyggV2VpZ2h0LCBUZWFtLCBOT0MsIFNlYXNvbiwgbm90ZXMpKSAlPiUgICAgICAgICAgZ3JvdXBfYnkoSUQpJT4lDQogICAgICAgICAgICBtdXRhdGUoTWVkYWxsYXMgPSBuKCkpJT4lDQogICAgICAgICAgICBhcnJhbmdlKGRlc2MoTWVkYWxsYXMpKSU+JQ0KICAgICAgICAgICAgZGlzdGluY3QoTmFtZSwgLmtlZXBfYWxsID0gVFJVRSklPiUNCiAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUNCiAgICAgICAgICAgIHNsaWNlX21heChNZWRhbGxhcywgbiA9IDMwKQ0KDQphYSA8LSBhYSAlPiUgbXV0YXRlKE5hbWUgPSBmb3JjYXRzOjphc19mYWN0b3IoTmFtZSkpICU+JQ0KICAgICAgICAgICAgIG11dGF0ZShOYW1lID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoTmFtZSxNZWRhbGxhcykpDQoNCmdncGxvdChhYSxhZXMoTmFtZSxNZWRhbGxhcyxjb2xvciA9IE5hbWUsZmlsbD0gTmFtZSkpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCAgd2lkdGggPS42LHN0YXQ9ImlkZW50aXR5IikgKw0KICBjb29yZF9mbGlwKCkrDQogIGdlb21fdGV4dChhZXMobGFiZWw9IE1lZGFsbGFzICxoanVzdD0tLjAzLCAgY29sb3VyPSJibGFjayIpLHNpemU9MykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPSByZWdpb24pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0PSAwLjUpLA0KICAgICAgICAgICAgY29sb3VyID0gImdyZXkzMCIsIHNpemUgPSAzKSArDQogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmVlbiIsc2l6ZT0xKSkrDQogICAgICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSkrDQogICAgICBzY2FsZV94X2Rpc2NyZXRlKCkgKw0KICAgIHhsYWIoIkF0bGV0YSIpK3lsYWIoIk1lZGFsbGFzIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCxmYWNlPSJib2xkIiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNixmYWNlID0gImJvbGQiKSkgKw0KICBnZ3RpdGxlKCJBdGxldGFzIGNvbiBtw6FzIG1lZGFsbGFzIG9sw61tcGljYXMgIiAsc3VidGl0bGUgPSAiSnVlZ29zIE9sw61tcGljb3MgZGUgdmVyYW5vIGRlIDE4OTYgYSAyMDE2IikNCg0KYGBgDQoNCg0KDQoNCiAgICANCiMjIyBDYXJnYW1vcyBkYXRhZnJhbWUgY29uIGxvcyB0aWVtcG9zIA0KDQpQYXJhIHZlciBsb3MgdGllbXBvcyB1dGlsaXphbW9zIGxvcyBkYXRvcyBkZSBbT2x5bXBpYyBUcmFjayAmIEZpZWxkIFJlc3VsdHNdKGh0dHA6Ly9odHRwczovL3d3dy5rYWdnbGUuY29tL2pheXJhdjEzL29seW1waWMtdHJhY2stZmllbGQtcmVzdWx0cykgcXVlIGNvbiBsYSBheXVkYSBkZSBudWVzdHJvIHByb2Zlc29yIFBlZHJvIEouIFDDqXJleiBwdWRpbW9zIGxpbXBpYXJsb3MgeSB1dGlsaXphcmxvcyBlbiBlbCBhbsOhbGlzaXMuDQpgYGB7cn0NCiNyZWFsaXphZG8gcG9yIFBlZHJvIEouIFDDqXJleg0KZGZfanNvbiA8LSBqc29ubGl0ZTo6ZnJvbUpTT04oIi4vZGF0b3MvcmVzdWx0cy5qc29uIikNCnp6MSA8LSB1bm5lc3RfbG9uZ2VyKGRmX2pzb24sIGNvbCA9IGdhbWVzKSAjLSBjb24gZXN0byBkZWJlcsOtYSBiYXN0YXIgcGVybyAuLi4uDQoNCiMtLS0tLS0tLS0tLS0tIGEgbWFubw0KenoxIDwtIHp6MSAlPiUgcmVuYW1lKHBydWViYSA9IG5hbWUpICMtIHhxIGx1ZWdvIGFwYXJlY2Vyw6Egb3RyYSB2YXJpYWJsZSBsbGFtYWRhIG5hbWUNCg0KIGlpIDwtIDENCiBsb2NhdGlvbiA8LSB6ejFbWzFdXVtbMV1dW2lpXQ0KIHllYXIgPC0genoxW1sxXV1bWzNdXVtpaV0NCiBnZW5kZXIgPC0genoxW1syXV1baWldDQogcHJ1ZWJhIDwtIHp6MVtbM11dW2lpXQ0KIHJlc3VsdGFkaXRvcyA8LSB6ejFbWzFdXVtbMl1dW2lpXQ0KIHJlIDwtIGFzLmRhdGEuZnJhbWUocmVzdWx0YWRpdG9zKQ0KIHJlIDwtIHJlICU+JSBhZGRfY29sdW1uKGxvY2F0aW9uLCB5ZWFyLCBnZW5kZXIsIHBydWViYSkNCiBkZiA8LSByZQ0KIGZvciAoaWkgaW4gMjpucm93KHp6MSkpIHsNCiAgIGxvY2F0aW9uIDwtIHp6MVtbMV1dW1sxXV1baWldDQogICB5ZWFyIDwtIHp6MVtbMV1dW1szXV1baWldDQogICBnZW5kZXIgPC0genoxW1syXV1baWldDQogICBwcnVlYmEgPC0genoxW1szXV1baWldDQogICByZXN1bHRhZGl0b3MgPC0genoxW1sxXV1bWzJdXVtpaV0NCiAgIHJlIDwtIGFzLmRhdGEuZnJhbWUocmVzdWx0YWRpdG9zKQ0KICAgcmUgPC0gcmUgJT4lIG11dGF0ZShyZXN1bHQgPSBhcy5jaGFyYWN0ZXIocmVzdWx0KSkNCiAgIHJlIDwtIHJlICU+JSBhZGRfY29sdW1uKGxvY2F0aW9uLCB5ZWFyLCBnZW5kZXIsIHBydWViYSkNCiAgIGRmIDwtIGJpbmRfcm93cyhkZiwgcmUpDQogfQ0KDQojLSBkZiB0aWVuZSAyLjM5NiBmaWxhcyB5IDggY29sdW1uYXMNCiMtIGFycmVnbGFyIGFsZ3VuYXMgY29zYXMNCg0KZGYgPC0gZGYgJT4lIG11dGF0ZShwcnVlYmEgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlKHBydWViYSwgIiBNZW4kIikgKSAgICAgIy0gcXVpdGFyIE1lbiBkZSBwcnVlYmENCmRmIDwtIGRmICU+JSBtdXRhdGUocHJ1ZWJhID0gc3RyaW5ncjo6c3RyX3JlbW92ZShwcnVlYmEsICIgV29tZW4kIikgKSAgICMtIHF1aXRhciBXb21lbiBkZSBwcnVlYmENCg0KDQojLSBhcnJlZ2xhciBlbCByZXNsdGFkbyAocmVzdWx0KQ0KIy0gaGF5IGRpc3RpbnRvcyB0aXBvcyBkZSBwcnVlYmFzOiBjYXJyZXJhcywgbGFuemFtaWVudG9zIHkgY29uY3Vyc29zKGRlY2F0aGxvbiwgaGVwdGFsb24pLg0KZGYgPC0gZGYgJT4lIHJlbmFtZShtYXJrID0gcmVzdWx0KSAlPiUgcmVsb2NhdGUobWFyaywgLmFmdGVyID0gbGFzdF9jb2woKSkNCg0KDQogIy0gbGEgbWFyayBkZSBsYXMgY2FycmVyYXMgcXVpZXJvIHEgZXN0ZSBtZWRpZG8gZW4gc2VndW5kb3MsIHBlcm8gZXN0YSBlbiBmb3JtYXRvIHRleHRvIHkgbm8gZXN0YW5kYXI6IEFSUkVHTEFSTE86DQojLSBlbCBjw7NkaWdvIGRlIGJham8gbG8gaGljZSBwYXJhIHVuIHRyYWJham8gbWlvIHkgZXN0YWJhIGFkYXB0YWRvIGEgbG9zIHBiJ3MgZGUgY29kaWZpY2FjacOzbiBkZSBtaXMgZGF0b3MsIG5vIGVzdMOhIGFkYXB0YWRvIGEgdnVlc3Ryb3MgZGF0b3MuIFZ1ZXN0cm9zIGRhdG9zIGhlIHZpc3RvIHF1ZSB0aWVuZW4gcGJzIGRlIGNvZGlmaWNhY2lvbiAgZXNwZWNpZmljaWNvczsgcG9yIGVqZW1wbG8gZW4gbGEgbWFyYXRob24geSBzdXBvbmdvIHF1ZSBlbiBtYXMgc2l0aW9zLCBhc2kgcXVlIGxvIGRlIGFiYWpvIGZ1bmNpb25hcmEgaGFzdGEgY2llcnRvIHB1bnRvDQogbGlicmFyeShzdHJpbmdyKQ0KICMtIDEpIHF1aXRhciBsZXRyYXMNCiBkZiA8LSBkZiAlPiUgbXV0YXRlKG1hcmtfeCA9IGlmZWxzZShzdHJfZGV0ZWN0KG1hcmssICJbWzphbHBoYTpdXSIpLCBzdHJfcmVwbGFjZV9hbGwobWFyaywgIltbOmFscGhhOl1dIiwgIjAiKSwgbWFyaykpDQogICMtIDMpIHNpIGVsIHRpZW1wbyBlcyAxMSwgcGFzYXJsbyBhIDExLjAwDQogZGYgPC0gZGYgJT4lIG11dGF0ZShtYXJrX3ggPSBpZmVsc2UoIHN0cl9kZXRlY3QobWFya194LCAiXltbOmRpZ2l0Ol1dezJ9JCIpLCBwYXN0ZTAobWFya194LCAiLjAwIiksIG1hcmtfeCkgKQ0KICAjLSA0KSBzaSBlbCB0aWVtcG8gZXMgMTIuMSBsZSBoZSBkZSBwb25lciB1biAwIGFsIGZpbmFsDQogZGYgPC0gZGYgJT4lIG11dGF0ZShtYXJrX3ggPSBpZmVsc2UoIHN0cl9kZXRlY3QobWFya194LCAiXltbOmRpZ2l0Ol1dezJ9LltbOmRpZ2l0Ol1dezF9JCIpLCBwYXN0ZTAobWFya194LCAiMCIpLCBtYXJrX3gpICkNCiAjLSA1KSBzaSBlbCB0aWVtcG8gZW1waWV6YSBjb24gOS45MSBwdWVzIHBvbmVybGUgMDkuOTENCiBkZiA8LSBkZiAlPiUgbXV0YXRlKG1hcmtfeCA9IGlmZWxzZSggc3RyX2RldGVjdChtYXJrX3gsICJeW1s6ZGlnaXQ6XV17MX0uW1s6ZGlnaXQ6XV17Mn0iKSwgcGFzdGUwKCIwIiwgbWFya194KSwgbWFya194KSApDQogIy0gNikgc2kgZWwgdGllbXBvIGVzdGEgeCBkZWJham8gZGVsIG1pbnV0bywgZW50b25jZXM6DQogZGYgPC0gZGYgICAlPiUgbXV0YXRlKG1hcmtfeCA9IGlmZWxzZSggc3RyX2RldGVjdChtYXJrX3gsICJeW1s6ZGlnaXQ6XV17Mn0uW1s6ZGlnaXQ6XV17Mn0kIiksIHBhc3RlMCgiMDA6MDA6IiwgbWFya194KSwgbWFya194KSApDQogIy0gNykgc2kgZWwgdGllbXBvIHNvbiBtaW51dG9zIChmb3J6YXJsZXMgYSBxdWUgdGVuZ2EgMiBkaWdpdG9zIGRlIG1pbnV0b3MpLiBQLmVqOiA3OjIyLjQ0ICBwYXNhcmxvIGEgMDc6MjIuNDQNCiBkZiA8LSBkZiAlPiUgbXV0YXRlKG1hcmtfeCA9IGlmZWxzZSggc3RyX2RldGVjdChtYXJrX3gsICJeW1s6ZGlnaXQ6XV17MX06W1s6ZGlnaXQ6XV17Mn0uW1s6ZGlnaXQ6XV17Mn0kIiksIHBhc3RlMCgiMCIsIG1hcmtfeCksIG1hcmtfeCkgKQ0KICMtIDgpIDQ0OjQ0LjQ0IHBhc2EgYSAwMDo0NDo0NC40NA0KIGRmIDwtIGRmICU+JSBtdXRhdGUobWFya194ID0gaWZlbHNlKCBzdHJfZGV0ZWN0KG1hcmtfeCwgIl5bWzpkaWdpdDpdXXsyfTpbWzpkaWdpdDpdXXsyfS5bWzpkaWdpdDpdXXsyfSQiKSwgcGFzdGUwKCIwMDoiLCBtYXJrX3gpLCBtYXJrX3gpICkNCiAjLSA4KSA0NDo0NC40NCBwYXNhIGEgMDA6NDQ6NDQuNDQNCiBkZiA8LSBkZiAlPiUgbXV0YXRlKG1hcmtfeCA9IGlmZWxzZSggc3RyX2RldGVjdChtYXJrLCAiXltbOmRpZ2l0Ol1dezJ9OltbOmRpZ2l0Ol1dezJ9OltbOmRpZ2l0Ol1dezJ9JCIpLCBwYXN0ZTAobWFyaywgIi4wMCIpLCBtYXJrX3gpICkNCg0KDQojLSBmdW5jaW9uIHBhcmEgcGFzYXIgIjAyOjQ0OjMzLjIyIiBhIHNlZ3VuZG9zIC0tLS0NCiBteV9mX3R0X3RvX3NlY29uZHMgPC0gZnVuY3Rpb24oeHgpIHsNCiAgICMtIG1ldG8gdW4gY2hhcmFjdGVyIGNvbiBmb3JtYXRvIGhoOjptbTpzcy5kZA0KICAgYWEgPC0gc3RyaW5ncjo6c3RyX2V4dHJhY3QoeHgsICJeLi46Li4iKSAjLSBleHRyYWlnbyBsYXMgaG9yYXMgeSBtaW51dG9zDQogICBhYV8xIDwtIHN0cmluZ3I6OnN0cl9leHRyYWN0KGFhLCAiXi4uIikgJT4lIGFzLm51bWVyaWMoLikqNjAqNjAgICMtIGV4dHJhaWdvIGxhcyBob3Jhcw0KICAgYWFfMiA8LSBzdHJpbmdyOjpzdHJfZXh0cmFjdChhYSwgIi4uJCIpICU+JSBhcy5udW1lcmljKC4pKjYwICAgICAjLSBleHRyYWlnbyBsYXMgbWludXRvcw0KICAgY2MgPC0gc3RyaW5ncjo6c3RyX2V4dHJhY3QoeHgsICIuLlxcLi4uJCIpICAjLSBlc3RyYWUgMjIuNTUNCiAgIGRkIDwtIGFzLm51bWVyaWMoY2MpDQogICBlZSA8LSBhYV8xICsgYWFfMiArIGRkDQogICBlZQ0KIH0NCg0KICMtIHVzYW1vcyBsYSBmLiBwYXJhICBwb25lciBlbiBzZWd1bmRvIGxhIG1hcmNhIGRlIGxhcyBjYXJyZXJhcyAoZmFsdGFyaWEgYXJyZWdsYXIgbG9zIGxhbnphbWllbnRvcyB5IGNvbmN1cnNvcykNCiAjLSBlbiByZWFsaWRhZCBlc3RvIHNvbG8gaGFicmlhIHF1ZSBoYWNlcmxvIHBhcmEgbGFzIGNhcnJlcmFzLCBubyBwYXJhIGxhbnphbWllbnRvcywgc2FsdG9zIHkgY29uY3Vyc29zDQogZGYgPC0gZGYgJT4lIG11dGF0ZShtYXJrX3h4ID0gbXlfZl90dF90b19zZWNvbmRzKG1hcmtfeCkpDQogZGYgPC0gZGYgJT4lIG11dGF0ZShtYXJrX3VuaWRhZGVzID0gInNlZ3VuZG9zIikNCg0KIHJtKGxpc3QgPSBzZXRkaWZmKGxzKCksICJkZiIpKQ0KICMtIEFkZW1hcy4uLiBsb3MgZGF0b3MgcGFyZWNlbiBxIHRpZW5lbiBmYWxsb3MuIEFsIG1lbm9zIGxhIHByaW1lcmEgZmlsYS4gTm8gcHVlZGUgc2VyIHF1ZSBlbiBsYSBjYXJyZXJhIGRlIDEwLjAwMCBlbiBSaW8gRkFSQUggbGUgc2FjYXNlIGRvcyBtaW51dG9zIGFsIHNlZ3VuZG8uIElndWFsIHNvbG8gZXMgZXNlIGZhbGxvLCBwZXJvIC4uLg0KDQpkZl9yZXN1bHRzIDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoImRhdG9zIiwgImRmX3Jlc3VsdHMuY3N2IikpDQoNCmBgYA0KICAgIA0KDQojIyAxMDAgbWV0cm9zIA0KDQpgYGB7ciBldmFsID0gVFJVRSwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1hZ2VuZXMiLCAiYm9sdC5qcGciKSkNCmBgYA0KDQpQdWVkZSBxdWUgZXN0YSBzZWEgbGEgZGlzY2lwbGluYSBvbMOtbXBpY2EgbcOhcyBjb25vY2lkYSwgcGVybyBkZXNncmFjaWFkYW1lbnRlLCB0YW1iacOpbiBsYSBtw6FzIGNvcnRhLiANCg0KIyMjIERpc3RyaWJ1Y2nDs24NCmBgYHtyfQ0KZGZfMTAwTSA8LSBkZl9yZXN1bHRzJT4lIGZpbHRlcihwcnVlYmEgPT0gIjEwME0iLCBnZW5kZXIgPT0gIk0iKSAlPiUgYXJyYW5nZSh5ZWFyKQ0KDQpkZl8xMDBNX211al95X2hvbSA8LSBkZl9yZXN1bHRzICU+JSBmaWx0ZXIocHJ1ZWJhID09ICIxMDBNIikNCg0KZ2dwbG90KGRmXzEwME1fbXVqX3lfaG9tLCBhZXMoeCA9IG1hcmtfeHgsIGZpbGwgPSBnZW5kZXIpKSArDQogICAgICAgIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gLi5jb3VudC4uKSwgcG9zaXRpb249ImlkZW50aXR5IiwgYWxwaGE9MC42KSArIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gIlRpZW1wbyIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiTsO6bWVybyBkZSBhdGxldGFzIikgKw0KICBnZ3RpdGxlKCJEaXN0cmlidWNpw7NuIGRlIGxvcyB0aWVtcG9zIGVuIDEwMCBtZXRyb3MiKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoc2l6ZT0xLCBjb2xvdXIgPSAiYmxhY2siKSwNCiAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiI2QzZDNkMyIpLA0KICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYW1pbHkgPSAiVGFob21hIiwgZmFjZSA9ICJib2xkIiksDQogICAgICAgICAgICAgIHRleHQ9ZWxlbWVudF90ZXh0KGZhbWlseT0iVGFob21hIiksDQogICAgICAgICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChjb2xvdXI9ImJsYWNrIiwgc2l6ZSA9IDkpLA0KICAgICAgICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoY29sb3VyPSJibGFjayIsIHNpemUgPSA5KSkgKw0KICAgICAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJBY2NlbnQiKSArIGxhYnMoY29sb3IgPSAiR8OpbmVybyIpDQoNCmBgYA0KDQoNCg0KIyMjIEV2b2x1Y2nDs24gZGUgbG9zIGF0bGV0YXMgcXVlIGhhbiBnYW5hZG8gb3JvIA0KYGBge3J9DQpkZl8xMDBNX29ybyA8LSBkZl8xMDBNX211al95X2hvbSAlPiUgZmlsdGVyKG1lZGFsID09ICJHIikgJT4lIG11dGF0ZShnZW5kZXIgPSBjYXNlX3doZW4oDQogIGdlbmRlciA9PSAiTSIgfiAiSG9tYnJlIiwNCiAgZ2VuZGVyID09ICJXIiB+ICJNdWplciIpKQ0KDQpwMSA8LSBnZ3Bsb3QoZGZfMTAwTV9vcm8sIGFlcyh5ZWFyLCBtYXJrX3h4LCBjb2xvciA9IGdlbmRlcikpICsgZ2VvbV9saW5lKCkgKyBnZW9tX3BvaW50KGFlcyAoY29sb3IgPSBuYW1lKSkgKyB0aGVtZV9saWdodCgpICsNCmxhYnModGl0bGUgPSAiRXZvbHVjacOzbiBkZSBsb3MgdGllbXBvcyBkZSBsb3MgZ2FuYWRvcmVzIGRlIDEwMCBtZXRyb3MiLA0KICAgIHN1YnRpdGxlID0gIkp1ZWdvcyBPbMOtbXBpY29zIGRlIHZlcmFubyBkZSAxODk2IGEgMjAxNiIsDQogICAgY2FwdGlvbiA9ICJGdWVudGU6T2x5bXBpYyBUcmFjayAmIEZpZWxkIFJlc3VsdHMiLA0KICAgIHggPSAiQcOxbyIsDQogICAgeSA9ICJUaWVtcG8iLA0KICAgIGNvbG9yID0gIkfDqW5lcm8geSBBdGxldGEiLA0KICAgIHRhZyA9ICJQbG90IDEiKSArDQogIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKHBhbGV0dGUgPSAiUmRZbEJ1IikgKyB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsdWU0IiksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmx1ZTQiKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJpdm9yeTEiKSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJyb3duIiksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImFudGlxdWV3aGl0ZSIsDQogICAgICAgIGNvbG91ciA9ICJhbnRpcXVld2hpdGUxIiksIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoZWF0MiIpLA0KICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJhbnRpcXVld2hpdGUxIikpDQoNCg0KZ2dwbG90bHkocDEpDQpgYGANCg0KR3JhY2lhcyBhIGVzdG9zIGdyw6FmaWNvcyBvYnNlcnZhbW9zIGNvbW8gZW4gdW4gc2lnbG8sIGxvcyB0aWVtcG9zIGhhbiBpZG8gY2F5ZW5kbyBlbiBwaWNhZG8sIGFkZW3DoXMgZGUgbGEgc3VwZXJpb3JpZGFkIGRlIGxvcyBhdGxldGFzIGhvbWJyZXMgZW4gZXN0YSBkaXNjaXBsaW5hLiBEZSBtb21lbnRvIGVsIHJlY29yZCBvbMOtbXBpY28gbG8gdGllbmUgZWwgYnVlbm8gZGUgVXNhaW4gQm9sdC4NCg0KIyMgUGVzbyB5IG1hcnRpbGxvIHkgZGlzY28NCg0KT3RyYSBkZSBsYXMgZGlzY2lwbGluYXMgbcOhcyBhbnRpZ3VhcyB5IGNhcmFjdGVyw61zdGljYXMgZGUgZXN0YSBjb21wZXRpY2nDs24gZGVwb3J0aXZhLCBlcyBlbCBsYW56YW1pZW50byBkZSBkaXNjbyB5IGRlIG1hcnRpbGxvLiANCg0KYGBge3IgZXZhbCA9IFRSVUUsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImltYWdlbmVzIiwgImxhbnphbWllbnRvLmpwZyIpKQ0KYGBgDQoNCkN1YW5kbyBwZW5zYW1vcyBlbiBsYW56YWRvcmVzIGRlIGRpc2NvIHkgZGUgbWFydGlsbG8gbm9ybWFsZW1lbnRlIG5vcyBpbWFnaW5hbW9zIHBlcnNvbmFzIG11eSBmdWVydGVzIHkgZ3JhbmRlcywgcG9yIGVzZSBtb3Rpdm8gbm9zIHBhcmVjacOzIGludGVyZXNhbnRlIGNvbXByb2JhciBjdcOhbCBlcyBsYSByZWxhY2nDs24gZW50cmUgZWwgcGVzbyB5IGxhcyBtYXJjYXMgZW4gZXN0YXMgZGlzY2lwbGluYXMuDQoNCiMjIyBMYW56YW1pZW50byBkZSBEaXNjbw0KYGBge3J9DQojZnVzaW9uYW5kbyBwYXJhIHZlciBwZXNvIGVuIHBydWViYXMgZGUgZGlzY28NCmRmX3N1bW1lcl9tZWRhbHMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAiZGZfc3VtbWVyX21lZGFscy5jc3YiKSkNCg0KYWFfMSA8LSBkZl9yZXN1bHRzICU+JSBmaWx0ZXIocHJ1ZWJhICVpbiUgYygiRGlzY3VzIFRocm93IiksIGdlbmRlciA9PSAiTSIpICU+JSBhcnJhbmdlKHllYXIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUobWVkYWwgPSBjYXNlX3doZW4oDQogIG1lZGFsID09ICJHIiB+ICJHb2xkIiwNCiAgbWVkYWwgPT0gIlMiIH4gIlNpbHZlciIsDQogIG1lZGFsID09ICJCIiB+ICJCcm9uemUiLA0KICBUUlVFICB+ICBuYW1lICkpDQoNCmJiXzEgPC0gZGZfc3VtbWVyX21lZGFscyAlPiUgZmlsdGVyKEV2ZW50ICVpbiUgYygiQXRobGV0aWNzIE1lbidzIERpc2N1cyBUaHJvdyIpKSU+JSBhcnJhbmdlKFllYXIpDQoNCmRmX2Rpc2NvIDwtIGxlZnRfam9pbihhYV8xLCBiYl8xLCBieSA9IGMoIm5hdGlvbmFsaXR5IiA9ICJOT0MiLCAibWVkYWwiID0gIk1lZGFsIiwgInllYXIiID0gIlllYXIiKSkNCg0KDQpwXzIgPC0gZ2dwbG90KGRmX2Rpc2NvLCBhZXMoeCA9IG1hcmtfeHgsIHkgPSBXZWlnaHQsIGNvbG9yID0geWVhciApKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKGNvbG9yID0gImN5YW40IikgKw0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZSA9ICJQZXNvIHkgTGFuemFtaWVudG8gZGUgRGlzY28iLA0KICAgIHN1YnRpdGxlID0gIkp1ZWdvcyBPbMOtbXBpY29zIGRlIHZlcmFubyBkZSAxODk2IGEgMjAxNiIsDQogICAgY2FwdGlvbiA9ICJGdWVudGU6IE9seW1waWMgVHJhY2sgJiBGaWVsZCBSZXN1bHRzIiwNCiAgICB4ID0gIk1hcmNhIiwNCiAgICB5ID0gIlBlc28iLA0KICAgIGNvbG9yID0gIkHDsW8iKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJ5ZWxsb3ciLCBoaWdoID0gInJlZCIsIG5hLnZhbHVlID0gTkEpICsgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibHVlNCIpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsdWU0IiksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiaXZvcnkxIiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJicm93biIpLA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJhbnRpcXVld2hpdGUiLA0KICAgICAgICBjb2xvdXIgPSAiYW50aXF1ZXdoaXRlMSIpLCBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGVhdDIiKSwNCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYW50aXF1ZXdoaXRlMSIpKQ0KDQoNCmdncGxvdGx5KHBfMikNCg0KYGBgDQoNCiMjIyBMYW56YW1pZW50byBkZSBNYXJ0aWxsbw0KYGBge3J9DQojZnVzaW9uYW5kbyBwYXJhIHZlciBwZXNvIHkgbWFydGlsbG8NCg0KYWFfMiA8LSBkZl9yZXN1bHRzICU+JSBmaWx0ZXIocHJ1ZWJhICVpbiUgYygiSGFtbWVyIFRocm93IiksIGdlbmRlciA9PSAiTSIpICU+JSBhcnJhbmdlKHllYXIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUobWVkYWwgPSBjYXNlX3doZW4oDQogIG1lZGFsID09ICJHIiB+ICJHb2xkIiwNCiAgbWVkYWwgPT0gIlMiIH4gIlNpbHZlciIsDQogIG1lZGFsID09ICJCIiB+ICJCcm9uemUiLA0KICBUUlVFICB+ICBuYW1lICkpDQoNCmJiXzIgPC0gZGZfc3VtbWVyX21lZGFscyAlPiUgZmlsdGVyKEV2ZW50ICVpbiUgYygiQXRobGV0aWNzIE1lbidzIEhhbW1lciBUaHJvdyIpKSU+JSBhcnJhbmdlKFllYXIpDQoNCmRmX21hcnQgPC0gbGVmdF9qb2luKGFhXzIsIGJiXzIsIGJ5ID0gYygibmF0aW9uYWxpdHkiID0gIk5PQyIsICJtZWRhbCIgPSAiTWVkYWwiLCAieWVhciIgPSAiWWVhciIpKQ0KDQoNCmRmX21hcnQgPC0gZGZfbWFydFstYygzOSksIF0NCg0KcF8zIDwtIGdncGxvdChkZl9tYXJ0LCBhZXMoeCA9IG1hcmtfeHgsIHkgPSBXZWlnaHQsIGNvbG9yID0geWVhciApKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKGNvbG9yID0gImN5YW40IikgKw0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZSA9ICJQZXNvIHkgTGFuemFtaWVudG8gZGUgTWFydGlsbG8iLA0KICAgIHN1YnRpdGxlID0gIkp1ZWdvcyBPbMOtbXBpY29zIGRlIHZlcmFubyBkZSAxODk2IGEgMjAxNiIsDQogICAgY2FwdGlvbiA9ICJGdWVudGU6IE9seW1waWMgVHJhY2sgJiBGaWVsZCBSZXN1bHRzIiwNCiAgICB4ID0gIk1hcmNhIiwNCiAgICB5ID0gIlBlc28iLA0KICAgIGNvbG9yID0gIkHDsW8iKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJ5ZWxsb3ciLCBoaWdoID0gInJlZCIsIG5hLnZhbHVlID0gTkEpICsgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibHVlNCIpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsdWU0IiksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiaXZvcnkxIiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJicm93biIpLA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJhbnRpcXVld2hpdGUiLA0KICAgICAgICBjb2xvdXIgPSAiYW50aXF1ZXdoaXRlMSIpLCBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGVhdDIiKSwNCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYW50aXF1ZXdoaXRlMSIpKSArIGFubm90YXRlKGdlb20gPSAidGV4dCIsIHggPSA4Mi45MSwgeSA9IDk4LCBsYWJlbCA9ICJyZWNvcmQiLCBoanVzdCA9ICJ1cCIpIA0KDQpnZ3Bsb3RseShwXzMpDQoNCg0KYGBgDQoNCiMjIyBDb21iaW5hbmRvIGdyw6FmaWNvcw0KYGBge3J9DQojY29tYmluYW5kbyBncsOhZmljb3MgZGlzY28geSBtYXJ0aWxsbw0KcF8yICsgcF8zICsgcGxvdF9sYXlvdXQobmNvbCA9IDIpDQoNCmBgYA0KDQpQb2RlbW9zIG9ic2VydmFyIGNvbW8gZW4gZWwgY2FzbyBkZSBsYW56YW1pZW50byBkZSBkaXNjbyBoYSBoYWJpZG8gdW5hIGNvcnJlbGFjacOzbiBtw6FzIGZ1ZXJ0ZSBhIHRyYXbDqXMgZGUgbG9zIGHDsW9zIGVudHJlIGVsIHBlc28geSBsYXMgbWFyY2FzLiBFbiBlbCBjYXNvIGRlbCBsYW56YW1pZW50byBkZSBtYXJ0aWxsbyBlcyBtZW5vcyBvYnZpYSBlc2EgcmVhbGFjacOzbi4gQ2FiZSBkZXN0YWNhciBxdWUgZWwgcmVjb3JkIG11bmRpYWwgb2zDrW1waWNvIHF1ZSBlc3TDoSBlbiA4Mi45MSBtZXRyb3MgeSBxdWUgZnVlIHJlYWxpemFkbyBwb3IgZWwgamFwb27DqXMgS29qaSBNdXJvZnVzaGkgZW4gMjAwNCBjdWFuZG8gw6lsIHBlc2FiYSBtZW5vcyBkZSAxMDAga2csIHNpZW5kbyBkZSBsb3MgbGFuemFkb3JlcyBkZSBtYXJ0aWxsbyBjb24gbWVub3IgcGVzby4gDQoNCiMgNC4gVVJTUzogQW50ZXMgeSBkZXNwdcOpcw0KDQpZYSBxdWUgZXN0ZSB0cmFiYWpvIHByZXRlbmRlIGRlc3RhY2FyIGFzcGVjdG9zIGludGVyZXNhbnRlcyB5IGN1cmlvc29zIGRlIGxvcyBKdWVnb3MgT2zDrW1waWNvcywgdGVuw61hbW9zIGxhIG5lY2VzaWRhZCBkZSBoYWNlciBhbGfDum4gZ3LDoWZpY28gYSBsYSBvdHJhIHN1cGVycG90ZW5jaWEsIGEgbGEgVVJTUy4gRXN0w6FiYW1vcyBpbnRlcmVzYWRvcyBlbiBhdmVyaWd1YXIsIHF1ZSBlcmEgbcOhcyAicmVudGFibGUiIGRlcG9ydGl2YW1lbnRlIGhhYmxhbmRvLCBxdWUgbG9zIHRlcnJpdG9yaW9zIGZ1ZXJhbiBqdW50b3MgeSBjYWRhIHVubyBwb3Igc3UgY3VlbnRhLiBBaMOtIGVzdMOhIGVsIGdyw6FmaWNvLiAgDQpgYGB7cn0NCiNVUlNTIEJVRU5BDQoNCmRmX3N1bW1lcl9tZWRhbHMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAiZGZfc3VtbWVyX21lZGFscy5jc3YiKSkNCg0KZGZfdXJzcyA8LSBkZl9zdW1tZXJfbWVkYWxzICU+JSBmaWx0ZXIoTk9DICVpbiUgYygiVVJTIiwiRVVOIikpICU+JQ0KICBhcnJhbmdlKFllYXIpICU+JQ0KICBncm91cF9ieShZZWFyKSAlPiUNCiAgc3VtbWFyaXNlKG5uID0gbigpKQ0KDQpwIDwtIGdncGxvdChkZl91cnNzLCBhZXMoeCA9WWVhciwgeT0gbm4sIGZpbGw9ICJyZWQiKSkgKyBnZW9tX2NvbCgpICsgeWxpbShjKE5BLCA1MDApKSsgbGFicyh0aXRsZSA9ICJHcsOhZmljbyBVUlNTOiBNZWRhbGxhcyB0b3RhbGVzIGRlIGxhIFVSU1MiLA0KICAgICAgIHN1YnRpdGxlID0gIihhbnRlcyBkZSBzdSBkaXNvbHVjacOzbiBlbiAxOTkyKSIsDQogICAgICAgeCA9ICJBw7FvcyIsDQogICAgICAgeSA9ICJNZWRhbGxhcyB0b3RhbGVzIikNCg0KZGZfdXJzc19wb3N0IDwtIGRmX3N1bW1lcl9tZWRhbHMgJT4lIGZpbHRlcihOT0MgJWluJSBjKCJFU1QiLCAiUlVTIiwgIlVLUiIsICJHRU8iLCAiQkxSIiwgIkFaRSIsICJVWkIiLCAiVEpLIiwgIlBPTCIsICJMVFUiLCAiUk9VIiwgIkFSTSIgKSkgJT4lDQogIGZpbHRlcihZZWFyID4gMTk5MikgJT4lDQogIGFycmFuZ2UoWWVhcikgJT4lDQogIGdyb3VwX2J5KFllYXIsIE5PQykgJT4lDQogIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgZ3JvdXBfYnkoWWVhcikgJT4lDQogIG11dGF0ZShubiA9IHN1bShuKSkNCg0KcDIgPC0gZ2dwbG90KGRmX3Vyc3NfcG9zdCwgYWVzKHggPVllYXIsIHk9IG5uLCBmaWxsID0gInJlZCIpKSArIHN0YXRfc3VtbWFyeShnZW9tPSJiYXIiLCBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjaygpKSArIHlsaW0oYyhOQSwgNTAwKSkgKw0KICBsYWJzKHRpdGxlID0gIkdyw6FmaWNvIFVSU1M6IE1lZGFsbGFzIHRvdGFsZXMgZGUgbGEgVVJTUyIsDQogICAgICAgc3VidGl0bGUgPSAiKGFudGVzIGRlIHN1IGRpc29sdWNpw7NuIGVuIDE5OTIpIiwNCiAgICAgICB4ID0gIkHDsW9zIiwNCiAgICAgICB5ID0gIk1lZGFsbGFzIHRvdGFsZXMiKQ0KDQojZnVzaW9uYW5kbyBkYXRhZnJhbWVzDQpkZl91cnNzX3RvdCA8LSBmdWxsX2pvaW4oZGZfdXJzcywgZGZfdXJzc19wb3N0KQ0KDQpwMyA8LSBnZ3Bsb3QoZGZfdXJzc190b3QsIGFlcyh4ID1ZZWFyLCB5PSBubiwgZmlsbCA9ICJyZWQiKSkgKyBzdGF0X3N1bW1hcnkoZ2VvbT0iYmFyIiwgcG9zaXRpb249cG9zaXRpb25fc3RhY2soKSkNCg0KcDMgKyAgeWxpbShjKE5BLCA1MDApKSArIGxhYnModGl0bGUgPSAiR3LDoWZpY28gVVJTUzogTWVkYWxsYXMgdG90YWxlcyBkZSBsYSBVUlNTIiwgc3VidGl0bGUgPSAiQcOxbyAxOTAwIGhhc3RhIDIwMTYiLCB4ID0gIkHDsW9zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSAiTWVkYWxsYXMgdG90YWxlcyIpKyB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAib3JhbmdlIixzaXplPTEpKSsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsgdGhlbWVfc29sYXJpemVkKCkrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxOTk0KQ0KDQoNCmBgYA0KDQojIDUuTXVqZXJlcw0KDQojIyBQYXJ0aWNpcGFjacOzbg0KDQpFbCBzaWdsbyBYWEkgZXMgc2luIGR1ZGEgZWwgc2lnbG8gZGUgbGFzIG11amVyZXMsIHkgZXMgcG9yIGVzdG8gcG9yIGxvIHF1ZSBwcmV0ZW5kw61hbW9zIGVuIGVzdGEgcGFydGUsIG9ic2VydmFyIGNvbW8gc3UgcGFydGljaXBhY2nDs24gaGEgaWRvIGNyZWNpZW5kby4gTm9zb3Ryb3MgY3JlZW1vcyBxdWUgbG8gc2VndWlyw6EgaGFjaWVuZG8gbXVjaG8gbcOhcy4gVGFtYmnDqW4gaGVtb3MgaW50ZW50YWRvIG1vc3RyYXIsIGNvbW8gZXNhIHBhcnRpY2lwYWNpw7NuIG5vIGVzdMOhIGRpc3RyaWJ1aWRhIGRlIGlndWFsIG1hbmVyYSBlbnRyZSBsb3MgY29udGluZW50ZXMuIA0KDQpgYGB7cn0NCg0KbGlicmFyeShnZ3RoZW1lcykNCg0KYXRobGV0ZXMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAiYXRoLmNzdiIpKQ0KDQpkZl9tdWplcmVzIDwtIGF0aGxldGVzICU+JSANCiAgZmlsdGVyKFNleD09IkYiKSU+JQ0KICBncm91cF9ieShTZWFzb24sIFllYXIpICU+JQ0KICBzdW1tYXJpc2Uobm4gPSBuKCkpDQoNCnAgPC0gZ2dwbG90KGRmX211amVyZXMsIGFlcyhZZWFyLG5uLCBjb2xvcj0gU2Vhc29uKSkrIGdlb21fcG9pbnQoKSsgZ2VvbV9saW5lKCkNCg0KICANCnAgKyBsYWJzKHRpdGxlID0gIlBhcnRpY2lwYWNpw7NuIG11amVyZXMgYXRsZXRhcyBlbiBKSk9PIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJEZXNkZSAxOTkwIGhhc3RhIDIwMTYiICwNCiAgICAgICB4ID0gIkHDsW9zIiwNCiAgICAgICB5ID0gIlBhcnRpY2lwYWNpw7NuIikrIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJvcmFuZ2UiLHNpemU9MSkpKyB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kPWVsZW1lbnRfYmxhbmsoKSkrIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCxmYWNlPSJib2xkIiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNixmYWNlID0gImJvbGQiKSkrIHRoZW1lX3NvbGFyaXplZCgpDQpgYGANCg0KDQoNCiMjIENvbXBhcmFjacOzbiBjb250aW5lbnRlcw0KDQpgYGB7cn0NCmF0aGxldGVzIDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoImRhdG9zIiwgImF0aC5jc3YiKSkNCg0KZGZfbXVqZXJlcyA8LSBhdGhsZXRlcyAlPiUgDQogIGZpbHRlcihTZXg9PSJGIiklPiUNCiAgc2VsZWN0KFNleCwgWWVhciwgVGVhbSwgU2Vhc29uKQ0KDQpkZl9tdWplcmVzMiA8LSBhdGhsZXRlcyAlPiUgDQogIGZpbHRlcihTZXg9PSJGIiklPiUNCiAgZ3JvdXBfYnkoU2Vhc29uLCBZZWFyLFRlYW0pICU+JQ0KICBzdW1tYXJpc2Uobm4gPSBuKCkpDQoNCg0KZGZfbXVqZXJlczMgPC0gZGZfbXVqZXJlczIgJT4lIGZpbHRlcihUZWFtICVpbiUgYygiU3BhaW4iLCAiTmV0aGVybGFuZHMiLCAiRmlubGFuZCIsICJJdGFseSIsICJQb3J0dWdhbCIsIkNhbmFkYSIsIkN1YmEiLCJCcmF6aWwiLCJVbml0ZWQgU3RhdGVzIiwiQ29sb21iaWEiLCJDaGluYSIsIkluZGlhIiwiSmFwb24iLCJTb3V0aCBLb3JlYSIsIk5vcnRoIEtvcmVhIiwiQXVzdHJhbGlhIiwiTmV3IFplYWxhbmQiLCJGaWppIiwiUGFwdWEgTmV3IEd1aW5lYSIsIlNhbW9hIiwiRWd5cHQiLCJTb3V0aCBBZnJpY2EiLCAiTmlnZXJpYSIsICIJDQpLZW55YSIsIkNhbWVyb29uIikpDQoNCmRmX211amVyZXM0IDwtIGRmX211amVyZXMzICU+JSAgbXV0YXRlKENPTlRJTkVOVEVTPSBjYXNlX3doZW4oDQogIFRlYW0gPT0gIlNwYWluIiB+ICJFdXJvcGEiLA0KICBUZWFtID09ICJOZXRoZXJsYW5kcyIgfiAiRXVyb3BhIiwNCiAgVGVhbSA9PSAiRmlubGFuZCIgfiAiRXVyb3BhIiwNCiAgVGVhbSA9PSAiSXRhbHkiIH4gIkV1cm9wYSIsDQogIFRlYW0gPT0iUG9ydHVnYWwifiAiRXVyb3BhIiwNCiAgVGVhbSA9PSAiQ2FuYWRhIiB+ICJBbWVyaWNhIiwNCiAgVGVhbSA9PSAiQ3ViYSIgfiAiQW1lcmljYSIsDQogIFRlYW0gPT0gIkJyYXppbCIgfiAiQW1lcmljYSIsDQogIFRlYW0gPT0gIlVuaXRlZCBTdGF0ZXMifiAiQW1lcmljYSIsDQogIFRlYW0gPT0gIkNvbG9tYmlhIn4gIkFtZXJpY2EiLA0KICBUZWFtID09ICJJbmRpYSIgfiAiQXNpYSIsDQogIFRlYW0gPT0gIkphcG9uIiB+ICJBc2lhIiwNCiAgVGVhbSA9PSAiU291dGggS29yZWEiIH4gIkFzaWEiLA0KICBUZWFtID09ICJOb3J0aCBLb3JlYSIgfiAiQXNpYSIsDQogIFRlYW0gPT0gIkNoaW5hIiB+ICJBc2lhIiwNCiAgVGVhbSA9PSAiQXVzdHJhbGlhIiAgfiAiT2NlYW7DrWEiLA0KICBUZWFtID09ICJOZXcgWmVhbGFuZCJ+ICJPY2VhbsOtYSIsDQogIFRlYW0gPT0gIkZpamkifiAiT2NlYW7DrWEiLA0KICBUZWFtID09ICJQYXB1YSBOZXcgR3VpbmVhIn4gIk9jZWFuw61hIiwNCiAgVGVhbSA9PSAiU2Ftb2EiIH4gIk9jZWFuw61hIiwNCiAgVGVhbSA9PSAiQ2FtZXJvb24iIH4gIkFmcmljYSIsDQogIFRlYW0gPT0gIktlbnlhIiB+ICJBZnJpY2EiLA0KICBUZWFtID09ICJFZ3lwdCJ+ICJBZnJpY2EiLCANCiAgVGVhbSA9PSAiU291dGggQWZyaWNhIn4gIkFmcmljYSIsDQogIFRlYW0gPT0gIk5pZ2VyaWEifiAiQWZyaWNhIikpDQoNCg0KbGlicmFyeShnZ2hpZ2hsaWdodCkNCg0KZ2dwbG90KGRmX211amVyZXM0ICwgYWVzKHggPSBZZWFyLCAgeSA9IG5uLCBjb2xvcj0gQ09OVElORU5URVMpKSsgZ2VvbV9wb2ludCgpICsgeWxpbShjKE5BLCA1MDApKSArIA0KICBsYWJzKHRpdGxlID0gIlBhcnRpY2lwYWNpb24gZGUgbGEgbXVqZXIgcG9yIGNvbnRpbmVudGVzIiwgc3VidGl0bGUgPSAiQcOxbyAxOTAwIGhhc3RhIDIwMTYiLCB4ID0gIkHDsW9zIiwNCiAgICAgICB5ID0gIkF0bGV0YXMiKSsgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG9yID0gIm9yYW5nZSIsc2l6ZT0xKSkrDQogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpKSsNCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LGZhY2U9ImJvbGQiKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE2LGZhY2UgPSAiYm9sZCIpKSsgIGdnaGlnaGxpZ2h0OjpnZ2hpZ2hsaWdodCgpICsgDQogIGZhY2V0X3dyYXAodmFycyhDT05USU5FTlRFUykpKyB0aGVtZV9zb2xhcml6ZWQoKQ0KYGBgDQoNCg0KIyA2LkN1cmlvc2lkYWRlcyANCg0KIyMgUGFpc2VzIG9yZ2FuaXphZG9yZXMNCg0KQ3VhbmRvIGVzdMOhYmFtb3MgaGFjaWVuZG8gZWwgdHJhYmFqbyBsZcOtbW9zIHVuIGFydMOtY3VsbyBxdWUgY29tZW50YWJhIHF1ZSBsb3MgcGHDrXNlcyBvcmdhbml6YWRvcmVzIGRlIGxvcyBKdWVnb3MgT2zDrW1waWNvcywgYSBwYXJ0ZSBkZSBxdWUgY3VhbmRvIGNvbXBpdGVuIGVuIGNhc2Egb2J0aWVuZW4gc3VzIG1lam9yZXMgcmVzdWx0YWRvcywgcHJvdm9jYW4gbGEgdmlzaWJpbGl6YWNpw7NuIGRlIGNpZXJ0b3MgZGVwb3J0ZXMgbWlub3JpdGFyaW9zLCBoYWNpZW5kbyBxdWUgbG9zIHJlc3VsdGFkb3Mgb2zDrW1waWNvcyBwb3N0ZXJpb3JlcyBjb250aW7DumVuIHNpZW5kbyBidWVub3MuIA0KDQpFc3RvIGhlbW9zIGludGVudGFkbyBtb3N0cmFyIGVuIGVzdGUgZ3LDoWZpY28sIGNvbiByZXN1bHRhZG9zIGRpc3BhcmVzLiANCg0KDQpgYGB7ciBldmFsID0gVFJVRSwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiaW1hZ2VuZXMiLCAiZXNwYcOxYS5qcGciKSkNCmBgYA0KDQpgYGB7cn0NCmRmXzIgPC0gZGZfc3VtbWVyX21lZGFscyAlPiUNCiAgZmlsdGVyKFllYXIgPiAxOTQ4KSAlPiUgbXV0YXRlKE0gPSBjYXNlX3doZW4oDQogIGlzLm5hKE1lZGFsKSB+IDAsDQogIFRSVUUgfiAxKSkgJT4lDQogIHNlbGVjdChZZWFyLCBNLCByZWdpb24pICU+JQ0KICBncm91cF9ieShyZWdpb24sIFllYXIpICU+JQ0KICBzdW1tYXJpc2UoTWVkYWxsYXNfYW55byA9IHN1bShNKSklPiUNCiAgYXJyYW5nZShyZWdpb24pDQoNCk1lZGl0ZXJyw6FuZW8gPC0gZGZfMiAlPiUgZmlsdGVyKHJlZ2lvbiAlaW4lIGMoIlNwYWluIiwgIlBvcnR1Z2FsIiwgIkl0YWx5IiwgIkdyZWVjZSIpKQ0KDQoNCm1lZGl0ZXJyYW5pYSA8LSBnZ3Bsb3QoTWVkaXRlcnLDoW5lbywgYWVzKHg9WWVhciwgeT1NZWRhbGxhc19hbnlvLCBncm91cD1yZWdpb24sIGNvbG9yPXJlZ2lvbikpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImRhcmtibHVlIiwicmVkIiwgImdvbGQiLCAiZ3JlZW4iKSkgICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgbGFicyh0aXRsZT0iQ29tbyBoYW4gY3JlY2lkbyBudWVzdHJvIGNvbXBhw7Flcm9zIikNCg0KbWVkaXRlcnJhbmlhICsgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD0xOTYwKSwgY29sb3I9IiM5OTAwMDAiLCBsaW5ldHlwZT0iZGFzaGVkIikrIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9MTk5MiksIGNvbG9yPSJicm93biIsIGxpbmV0eXBlPSJkYXNoZWQiKSArIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9MjAwNCksIGNvbG9yPSJicm93biIsIGxpbmV0eXBlPSJkYXNoZWQiKQ0KDQpgYGANCg0KDQojIyBLb3JlYQ0KDQpObyBzw6kgc2kgc2FicsOhbiBxdWUgZWwgZ29iaWVybm8gbm9yY29yZWFubyBsZSBzdWVsZSBkZWNpciBhIHN1cyBjb21wYXRyaW90YXMgcXVlIHNpZW1wcmUgb2J0aWVuZW4gbcOhcyBtZWRhbGxhcyBxdWUgc3VzIHZlY2lub3MgZGVsIHN1ci4gUGVybywgbmFkYSBtw6FzIGxlam9zIGRlIGxhIHJlYWxpZGFkLiBEZXNkZSBxdWUgc2Ugc2VwYXJhcm9uLCBhIENvcmVhIGRlbCBTdXIgY2FkYSB2ZXogbGUgdmEgbWVqb3IsIG1pZW50cmFzIHF1ZSBhIENvcmVhIGRlbCBOb3J0ZSwgcGVvci4gDQoNCmBgYHtyIGV2YWwgPSBUUlVFLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWFnZW5lcyIsICJjb3JlYS5qcGciKSkNCmBgYA0KDQpgYGB7cn0NCmtvcmVhIDwtIGRmX3N1bW1lcl9tZWRhbHMgJT4lDQogIGZpbHRlcihZZWFyID4gMTk3MCkgJT4lIG11dGF0ZShNID0gY2FzZV93aGVuKA0KICBpcy5uYShNZWRhbCkgfiAwLA0KICBUUlVFIH4gMSkpICU+JQ0KICBncm91cF9ieShyZWdpb24sIFllYXIpICU+JQ0KICBzdW1tYXJpc2UoTWVkYWxsYXNfYW55byA9IHN1bShNKSklPiUNCiAgYXJyYW5nZShyZWdpb24pDQoNCmtvcmVhcyA8LSBrb3JlYSAlPiUgZmlsdGVyKHJlZ2lvbiAlaW4lIGMoIk5vcnRoIEtvcmVhIiwiU291dGggS29yZWEiKSkNCg0KZ2dwbG90KGtvcmVhcywgYWVzKHg9WWVhciwgeT1NZWRhbGxhc19hbnlvLCBncm91cD1yZWdpb24sIGNvbG9yPXJlZ2lvbikpICsNCiAgZ2VvbV9wb2ludChhbHBoYT0wLjYpICsNCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0PTAsIHNsb3BlPTEsIGxpbmV0eXBlPSJkYXNoZWQiKSArDQogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLCBzZT1GQUxTRSkgKw0KICBsYWJzKHRpdGxlID0gIkNyZWNpbWllbnRvIG1lZGFsbGVybyBkZSBsYXMgZG9zIENvcmVhcyIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChyZXZlcnNlPVRSVUUpKQ0KDQpgYGANCg0KDQojIyBEaXN0cmlidWNpb24gcG9yIGVkYWQgeSBvbGltcGlhZGENCg0KUGFyYSBpciBhY2FiYW5kbyBlbCB0cmFiYWpvLCBub3MgYXBldGVjw61hIG9ic2VydmFyIGxvcyBjYW1iaW9zIGVuIGxhcyBlZGFkZXMgZGUgbG9zIHBhcnRpY2lwYW50ZXMuIEVuIG11Y2hhcyBvdHJhcyBkaXNjaXBsaW5hcyBvY3VycmUgcXVlIHByZWNvY2lkYWQgZXN0w6EgYSBsYSBvcmRlbiBkZWwgZMOtYS4gUXVlcsOtYW1vcyB2ZXJsbyBzaSBhcXXDrSB0YW1iacOpbi4gDQpgYGB7cn0NCmF0aGxldGVzIDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoImRhdG9zIiwgImF0aC5jc3YiKSkNCg0KYWdlXzE4OTYgPC0gYXRobGV0ZXMlPiVmaWx0ZXIoU2V4PT0iTSIsU2Vhc29uPT0nU3VtbWVyJyxZZWFyPT0xODk2KSU+JWdyb3VwX2J5KFNwb3J0KSU+JXN1bW1hcml6ZShhdmc9cm91bmQobWVhbihBZ2UsbmEucm0gPSBUUlVFKSwxKSkNCg0KYWdlXzE5MzYgPC0gYXRobGV0ZXMlPiVmaWx0ZXIoU2V4PT0iTSIsU2Vhc29uPT0nU3VtbWVyJyxZZWFyPT0xOTM2KSU+JWdyb3VwX2J5KFNwb3J0KSU+JXN1bW1hcml6ZShhdmc9cm91bmQobWVhbihBZ2UsbmEucm0gPSBUUlVFKSwxKSkNCg0KYWdlXzE5NzIgPC0gYXRobGV0ZXMlPiVmaWx0ZXIoU2V4PT0iTSIsU2Vhc29uPT0nU3VtbWVyJyxZZWFyPT0xOTcyKSU+JWdyb3VwX2J5KFNwb3J0KSU+JXN1bW1hcml6ZShhdmc9cm91bmQobWVhbihBZ2UsbmEucm0gPSBUUlVFKSwxKSkNCg0KYWdlXzE5OTIgPC0gYXRobGV0ZXMlPiVmaWx0ZXIoU2V4PT0iTSIsU2Vhc29uPT0nU3VtbWVyJyxZZWFyID09IDE5OTIpJT4lZ3JvdXBfYnkoU3BvcnQpJT4lc3VtbWFyaXplKGF2Zz1yb3VuZChtZWFuKEFnZSxuYS5ybSA9IFRSVUUpLDEpKQ0KDQphZ2VfMjAxNiA8LSBhdGhsZXRlcyU+JWZpbHRlcihTZXg9PSJNIixTZWFzb249PSdTdW1tZXInLFllYXIgPT0gMjAxNiklPiVncm91cF9ieShTcG9ydCklPiVzdW1tYXJpemUoYXZnPXJvdW5kKG1lYW4oQWdlLG5hLnJtID0gVFJVRSksMSkpDQoNCg0KYWdlX3kgPSBhdGhsZXRlcyU+JWZpbHRlcihTZWFzb249PSdTdW1tZXInKSU+JWdyb3VwX2J5KFNwb3J0KSU+JXN1bW1hcml6ZShZPXVuaXF1ZShTcG9ydCkpDQoNCg0KDQpoaWdoY2hhcnQoaGVpZ2h0ID0gIjcwMHB4IikgJT4lDQogIGhjX3RpdGxlKHRleHQgPSAiTWVkaWEgZGUgRWRhZCBwb3IgRGVwb3J0ZSBlbiBkaXN0aW50YXMgT2xpbXBpYWRhIikgJT4lDQogIGhjX3N1YnRpdGxlKHRleHQgPSAiSnVlZ29zIE9sw61tcGljb3MgZGUgdmVyYW5vIGRlIDE4OTYgYSAyMDE2IikgJT4lDQogIGhjX2NyZWRpdHMoZW5hYmxlZCA9IFRSVUUsIHRleHQgPSAiRnVlbnRlOiAxMjAgeWVhcnMgb2YgT2x5bXBpYyBoaXN0b3J5OiBhdGhsZXRlcyBhbmQgcmVzdWx0cyIsDQogICAgICAgICAgICAgc3R5bGUgPSBsaXN0KGZvbnRTaXplID0gIjEwcHgiKSkgJT4lDQogIGhjX2FkZF90aGVtZShoY190aGVtZV9mdCgpKSAlPiUNCiAgaGNfeEF4aXMoY2F0ZWdvcmllcyA9IGFnZV95JFksdGl0bGUgPSBsaXN0KHRleHQgPSAiRGVwb3J0ZSIpKSAlPiUNCiAgaGNfYWRkX3NlcmllcyhuYW1lID0gIjE4OTYiLCBkYXRhID0gYWdlXzE4OTYkYXZnKSU+JQ0KICBoY19hZGRfc2VyaWVzKG5hbWUgPSAiMTkzNiIsZGF0YSA9IGFnZV8xOTM2JGF2ZyklPiUNCiAgaGNfYWRkX3NlcmllcyhuYW1lID0gIjE5NzIiLGRhdGEgPSBhZ2VfMTk3MiRhdmcpJT4lDQogIGhjX2FkZF9zZXJpZXMobmFtZSA9ICIxOTkyIiwgZGF0YSA9IGFnZV8xOTkyJGF2ZykgJT4lDQogIGhjX2FkZF9zZXJpZXMobmFtZSA9ICIyMDE2IixkYXRhID0gYWdlXzIwMTYkYXZnKSU+JQ0KDQogaGNfeUF4aXModGl0bGUgPSBsaXN0KHRleHQgPSAiTWVkaWEgZGUgZWRhZCIpLA0KICAgICAgICAgICBsYWJlbHMgPSBsaXN0KGZvcm1hdCA9ICJ7dmFsdWV9IiksIG1heCA9IDUwKSAlPiUNCiAgIGhjX2xlZ2VuZChlbmFibGVkID0gVCwgYWxpZ249ICJsZWZ0IiwgdmVydGljYWxBbGlnbiA9ICJib3R0b20iKQ0KDQpgYGANCg0KRXMgaW50ZXJlc2FudGUgb2JzZXJ2YXIgY29tbyBsYSBtZWRpYSBkZSBlZGFkIGVuIEFscGluaXNtbyBlbiBsb3MgSnVlZ29zIGRlIDE5MzYgZXN0YWJhIGVuIDQ5IGHDsW9zIG8gY29tbyBlbiBlbCBjYXNvIGRlIEJhZG1pbnRvbiBlbiAxODk2IG8gUGF0aW5hamUgQXJ0w61zdGljbyBlbiAxOTcyIHNvYnJlcGFzYW4gcG9yIHBvY28gbGEgbWF5b3LDrWEgZGUgZWRhZC4NCg0KIyA3LkNvbmNsdXNpw7NuDQoNCkEgbW9kbyBkZSBjb25jbHVzacOzbiwgZGVzdGFjYXIsIGNvbW8gaGVtb3MgZGljaG8gYWwgY29taWVuem8sIHF1ZSBzaW4gbmluZ8O6biB0aXBvIGRlIGR1ZGEsIGxvcyBKdWVnb3MgT2zDrW1waWNvcyBzb24gZWwgbWF5b3IgZXZlbnRvIGRlcG9ydGl2byBkZWwgbXVuZG8uIEVzIG3DoXMsIGNyZWVtb3MgcXVlIGVzdGUgYWNvbnRlY2ltaWVudG8gdHJhc2NpZW5kZSBsbyBwdXJhbWVudGUgZGVwb3J0aXZvLCBsbGVnYW5kbyBhIGNvbnZlcnRpcnNlIGVuIHVuIGV2ZW50byB0YW50byBzb2NpYWwgY29tbyBjdWx0dXJhbCB5IHBvciBzdXB1ZXN0byBwb2zDrXRpY28uIFBhcmEgZmluYWxpemFyIGNvbnNpZGVyYW1vcyBxdWUgbG9zIEp1ZWdvcyBPbMOtbXBpY29zIHRhbnRvIGVuIGxhIEFudGlndWEgR3JlY2lhIGNvbW8gZW4gbGEgYWN0dWFsaWRhZCwgc29uIHVuIGluc3RydW1lbnRvIHF1ZSB0cmFuc2N1cnJlbiBlbiBwYXJhbGVsbyBjb24gbGEgaGlzdG9yaWEgZGUgbGEgaHVtYW5pZGFkIHksIGEgdHJhdsOpcyBkZSBlbGxvcywgcG9kZW1vcyBhcHJlbmRlciB5IGVudGVuZGVyIHRvZG8gbG8gc3VjZWRpZG8gZW4gZWwgw7psdGltbyBzaWdsby4gDQoNCmBgYHtyIGV2YWwgPSBUUlVFLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJpbWFnZW5lcyIsICJibGFja19wb3dlci5qcGciKSkNCmBgYA0KDQojIEJpYmxpb2dyYWbDrWEgDQoNCkRlIGFxdcOtIHNhY2Ftb3MgbG9zIGRhdG9zIGRlIFsxMjAgeWVhcnMgb2YgT2x5bXBpYyBoaXN0b3J5OiBhdGhsZXRlcyBhbmQgcmVzdWx0c10oaHR0cDovL2h0dHBzOi8vd3d3LmthZ2dsZS5jb20vaGVlc29vMzcvMTIwLXllYXJzLW9mLW9seW1waWMtaGlzdG9yeS1hdGhsZXRlcy1hbmQtcmVzdWx0cykuDQoNClRyYWJham9zIHF1ZSBub3MgaGFuIGluc3BpcmFkbzoNCg0KLSBbT2x5bXBpYyBoaXN0b3J5IGRhdGE6IHRob3JvdWdoIGFuYWx5c2lzXShodHRwczovL3d3dy5rYWdnbGUuY29tL2hlZXNvbzM3L29seW1waWMtaGlzdG9yeS1kYXRhLWEtdGhvcm91Z2gtYW5hbHlzaXMpDQoNCi0gW0hvbGRpbmcgYW4gT2x5bXBpYyBHYW1lcyBtZWFucyBldm9raW5nIGhpc3RvcnldKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vam9zZXBoZ3BpbnRvL2hvbGRpbmctYW4tb2x5bXBpYy1nYW1lcy1tZWFucy1ldm9raW5nLWhpc3RvcnkpDQoNCkRlIGFxdcOtIHNhY2Ftb3MgbG9zIGRhdG9zIGRlIFtPbHltcGljIFRyYWNrICYgRmllbGQgUmVzdWx0c10oaHR0cDovL2h0dHBzOi8vd3d3LmthZ2dsZS5jb20vamF5cmF2MTMvb2x5bXBpYy10cmFjay1maWVsZC1yZXN1bHRzKQ0KDQpEZSBhcXXDrSBzYWNhbW9zIGVsIGRpc2XDsW8gZGVsIFtoaXN0b2dyYW1hXSgjaHR0cHM6Ly90LXJlZGFjdHlsLmlvL2Jsb2cvMjAxNi8wMi9jcmVhdGluZy1wbG90cy1pbi1yLXVzaW5nLWdncGxvdDItcGFydC03LWhpc3RvZ3JhbXMuaHRtbCkgZGUgMTAwIG1ldHJvcy4NCg0K