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. El repo del trabajo está aquí. La página web de la asignatura y los trabajos de mis compañeros pueden verse aquí.


1. Introducción

Antes de elegir estos datos estuve viendo datos de la web de imdb (pesaban demasiado) y de otro dataset de kaggle de la web tmdb. Finalemente me he decantado por estos porque tienen los principales datos que quiero analizar de 220 películas por cada año desde 1986 hasta 2016. También he utilizado un df de los nominados y los ganadores de los Oscar, sacado de kaggle también.

La intención principal de este trabajo es ver si existe relación entre el éxito tanto comercial (en cuanto a recaudación en USA) como de popularidad (puntuación media de los usuarios de IMDB) como de reconocimiento (premios Oscars) y el actor/actriz principal, el director o la productora.

2. Datos

Primero cargamos los paquetes

library(tidyverse)
library(plotly)
library(DT)
library(gridExtra)
library(formattable)
library(cowplot)
library(ggplot2)
library("wesanderson")
library(ggthemr)
library(gt)

Cargamos los datos

movies <- rio::import(here::here("datos", "movie_industry", "movies.csv"))
oscars <- rio::import(here::here("datos","oscars", "the_oscar_award.csv"))

Tuve la suerte de que los datos de los dos dataframes que utilicé ya estaban bastante limpios y los pocos cambios que tuve que hacer los hice sobre la marcha.

Primero vamos a observar quienes son los actores/actrices, directores y productoras que más recaudan, mejor valoración tienen por el público y mejor valoración tienen por la Academia de las Oscars.

Para calcular la nota media he tenido que escoger actores/directores/productoras que tengan más de 5 películas, ya que sino era más difícil encontrar una relación. Por ejemplo la película brasileña “Ciudad de Dios” tiene una de las notas más altas (8.7), pero es la única película en la lista del actor principal y de la productora.

Después en el apartado “Resultados” observaremos los actores/directores/productoras que se encuentran tanto en el Top 30 de los que más recaudan, en el Top 30 de los que mejor nota tienen sus películas y tienen por lo menos un Oscar.

3. Actores

Actores que más recaudan

#actores que más recaudan

#top 30
star_gross <- movies %>% group_by(star) %>%
                         summarise(recaudacion = sum(gross)) %>%
                         arrange(desc(recaudacion)) %>%
                         mutate(recaudacion = recaudacion/1000000)

DT::datatable(star_gross, caption = 'Recaudación en millones de dólares')

Comprueba lo que recuada tu actor/actriz favorito.

star_gross_10 <- star_gross %>% head(10)

star_gross_10 <- star_gross_10 %>% mutate(star = forcats::as_factor(star)) %>%
             mutate(star = forcats::fct_reorder(star,recaudacion))

#Fijamos el tema para el resto de gráficos
ggthemr("solarized")

ggplot(star_gross_10, aes(star, recaudacion, fill = star)) + geom_col() + coord_flip() + theme(legend.position = "none") +
labs(title = "Top 10 actores/actrices con más recaudación",
    subtitle = "En millones de dólares",
    x = NULL, y = NULL)+
  geom_text(aes(label= recaudacion), position = position_stack(vjust= 0.5),
            colour = "grey30", size = 3) + scale_fill_manual(values = wes_palette("Zissou1", n = 10, type = "continuous"))

Actores mejor valorados en imdb

Para hacer esto he calculado la media de la puntuación de las películas que han hecho cada actor(he escogido actores que hayan hecho más de 5 películas).

#vamos a observar qué pasa si escogemos actores que hayan hecho más de 5 películas como protagonistas.

star_score_5 <- movies %>% group_by(star) %>%
                           mutate(NN = n()) %>%
                           filter(NN > 5) %>%
                           summarise(nota_media = mean(score)) %>%
                           arrange(desc(nota_media)) 

DT::datatable(star_score_5)

¡Busca a tu intérprete favorito!

Actores con Oscar

#actores con oscar
oscars <- rio::import(here::here("datos","oscars", "the_oscar_award.csv"))

oscars_1 <- oscars  %>% filter(category %in% c("ACTOR", "ACTRESS", "ACTOR IN A SUPPORTING ROLE", "ACTRESS IN A SUPPORTING ROLE", "ACTOR IN A LEADING ROLE", "ACTRESS IN A LEADING ROLE")) %>% filter(winner == TRUE) %>%
                      group_by(name) %>%
                      mutate(wins = n()) %>%
                      distinct(name,.keep_all = TRUE)

osc_act <- left_join(movies, oscars_1, by = c("star" = "name"))

osc_act_un <- osc_act %>% filter(complete.cases(.)) %>% distinct(star, .keep_all = TRUE)

#actores con oscar

act_osc <- osc_act_un %>% select(star, wins)%>%
                          arrange(desc(wins))

#actores con más de un oscar

act_mas_osc <- act_osc %>% slice_max(wins, n = 10) #usar head(10) para los 10 primeros resultados

library(DT)

datatable(act_osc) %>% formatStyle(
  'wins',target = 'row',
  backgroundColor = styleEqual(c(1, 2, 3), c('khaki', 'lightblue', 'pink'))
)

Resultados

Ahora vamos a comprobar qué actores están entre los 30 con más recaudación, los 30 con mejor nota media de sus películas y además tienen un Oscar.

#Resultados

star_gross_30 <- star_gross %>% head(30) %>%
                         mutate(rank_rec = c(1:30))

star_score_30 <- star_score_5 %>% head(30)

actores <- merge(merge(
  star_gross_30,
  star_score_30, all = TRUE),
  act_osc, all = TRUE)

aa <- actores %>% filter(complete.cases(.)) %>% arrange(desc(recaudacion))

customGreen0 = "#DeF7E9"

customGreen = "#71CA97"

aa %>% formattable(list(
 nota_media = formatter("span",
    style = x ~ style(color = ifelse(rank(-x) <= 1, "blue", "gray")),
    x ~ sprintf("%.2f (rank: %02d)", x, rank(-x))),
   area(col = recaudacion) ~ normalize_bar("pink", 0.2),
  `rank_rec`= color_tile(customGreen, customGreen0),
   wins = color_tile("khaki", "lightblue")))
star recaudacion rank_rec nota_media wins
Tom Hanks 3973.406 1 7.07 (rank: 04) 2
Leonardo DiCaprio 2304.909 9 7.51 (rank: 01) 1
Christian Bale 1817.915 16 7.39 (rank: 02) 1
Brad Pitt 1486.238 28 7.13 (rank: 03) 1

Tenemos a Tom Hanks, Leonardo DiCaprio, Brad Pitt y a Christian Bale. Siendo Tom Hanks el que más dinero recauda de todos y el que más oscars tiene (de los cuatro), aunque DiCaprio participa en películas mejor valoradas.

4. Directores

Directores que más recuadan

#Directores más taquilleros

dir_gross <- movies %>% group_by(director) %>%
                         summarise(recaudacion = sum(gross)) %>%
                         arrange(desc(recaudacion)) %>%
                         mutate(recaudacion = recaudacion/1000000)

DT::datatable(dir_gross, caption = 'Recaudación en millones de dólares')

¡Encuentra a tu director favorito!

dir_gross_10 <- dir_gross %>% head(10) %>% mutate(director = forcats::as_factor(director)) %>%
             mutate(director = forcats::fct_reorder(director,recaudacion))

ggplot(dir_gross_10, aes(director, recaudacion, fill = director)) + geom_col() + coord_flip() + theme(legend.position = "none") +
labs(title = "Top 10 Directores con más recaudación",
    subtitle = "En millones de dólares",
    x = NULL, y = NULL) +
  geom_text(aes(label= recaudacion), position = position_stack(vjust= 0.5),
            colour = "grey30", size = 3) + scale_fill_manual(values = wes_palette("Zissou1", n = 10, type = "continuous"))

Directores mejor valorados en imdb

En este caso he hecho como con los actores y he escogido solo a directores con más de 5 películas

#que hayan dirigido más de 5 películas
dir_score_5 <- movies %>% group_by(director) %>%
                           mutate(NN = n()) %>%
                           filter(NN > 5) %>%
                           summarise(nota_media = mean(score)) %>%
                           arrange(desc(nota_media)) 

DT::datatable(dir_score_5)

Directores con Oscar


oscars_2 <- oscars  %>% filter(category %in% c("DIRECTING (Comedy Picture)", "DIRECTING (Dramatic Picture)", "DIRECTING")) %>% filter(winner == TRUE) %>%
                      group_by(name) %>%
                      mutate(wins = n()) %>%
                      distinct(name,.keep_all = TRUE)

osc_dir <- left_join(movies, oscars_2, by = c("director" = "name"))

osc_dir_un <- osc_dir %>% filter(complete.cases(.)) %>% distinct(director, .keep_all = TRUE)

#directores con oscar

dir_osc <- osc_dir_un %>% select(director, wins)%>%
                          arrange(desc(wins))

datatable(dir_osc) %>% formatStyle(
  'wins',target = 'row',
  backgroundColor = styleEqual(c(1, 2, 3), c('khaki', 'lightblue', 'pink'))
)

Resultados


dir_gross_30 <- dir_gross %>% head(30) %>%
                         mutate(rank_rec = c(1:30))

dir_score_30 <- dir_score_5 %>% head(30)

directores <- merge(merge(
  dir_gross_30,
  dir_score_30, all = TRUE),
  dir_osc, all = TRUE)

bb <- directores %>% filter(complete.cases(.)) %>% arrange(desc(recaudacion))

bb %>% formattable(list(
 nota_media = formatter("span",
    style = x ~ style(color = ifelse(rank(-x) <= 1, "blue", "gray")),
    x ~ sprintf("%.2f (rank: %02d)", x, rank(-x))),
   area(col = recaudacion) ~ normalize_bar("pink", 0.2),
  `rank_rec`= color_tile(customGreen, customGreen0),
   wins = color_tile("khaki", "lightblue")))
director recaudacion rank_rec nota_media wins
Steven Spielberg 2890.693 1 7.39 (rank: 03) 2
Peter Jackson 2134.382 3 7.78 (rank: 02) 1
James Cameron 1909.927 4 7.88 (rank: 01) 1

Podemos ver que los tres directores que han ganado un Oscar y están en el top 30 de los que más recaudan y en el de la nota media de sus películas son Steven Spielberg, Peter Jackson y James Cameron. A pesar de tener las peliculas peor valoradas de media de los tres directores, Spielberg es el director que más recauda de todos y es el director con más Oscars (empatado con otros).

5. Productoras

Productoras con más recaudación

prod_gross <- movies %>% group_by(company) %>%
                         summarise(recaudacion = sum(gross)) %>%
                         arrange(desc(recaudacion))  %>%
                         mutate(recaudacion = recaudacion/1000000)

DT::datatable(prod_gross)
prod_gross_10 <- prod_gross %>% head(10) %>% mutate(company = forcats::as_factor(company)) %>%
             mutate(company = forcats::fct_reorder(company,recaudacion))

ggplot(prod_gross_10, aes(company, recaudacion, fill = company)) + geom_col() + coord_flip() + theme(legend.position = "none") +
labs(title = "Top 10 Productoras con más recaudación",
    subtitle = "En millones de dólares",
    x = NULL, y = NULL)+
  geom_text(aes(label= recaudacion), position = position_stack(vjust= 0.5),
            colour = "grey30", size = 3) + scale_y_continuous(labels=scales::comma) + scale_fill_manual(values = wes_palette("Zissou1", n = 10, type = "continuous"))

5 Majors

En la indutria del cine hoy en día se puede destacar el papel de 5 productoras que manejan gran parte del mercado, son conocidas como las 5 majors y a estas pertenecen muchas de las productoras más pequeñas.


tot_gross <- movies %>% mutate(total = sum(gross))#total de la recaudación de las películas

columbia_gross <- tot_gross  %>% filter(company %in% c("Columbia Pictures", "Columbia Pictures Corporation", "Columbia Pictures Film Production Asia", "Columbia Pictures Industries", "Columbia TriStar Home Video" ,"TriStar Television", "TriStar Pictures", "Columbia TriStar Home Video", "Sony Pictures Classics", "Sony Pictures Entertainment (SPE)", "Affirm Films", "Screen Gems", "Stage 6 Films", "Destination Films")) %>%
                         mutate(rec = sum(gross)) %>%
                         filter(company == "Columbia Pictures") %>%
                         distinct(company, .keep_all = TRUE)

warner_gross <- tot_gross %>% filter(company %in% c( "Warner Bros.", "Warner Bros. Animation", "Warner Bros. Digital Distribution", "Warner Bros. Family Entertainment", "Warner Bros. Pictures", "Warner Independent Pictures (WIP)", "New Line Cinema", "DC Entertainment", "Castle Rock Entertainment", "HBO Films", "Home Box Office (HBO)", "Spyglass Entertainment", "Turner Pictures (I)")) %>%
                         mutate(rec = sum(gross)) %>%
                         filter(company == "Warner Bros.") %>%
                         distinct(company, .keep_all = TRUE)


universal_gross <- tot_gross %>% filter(company %in% c( "Universal Pictures", "Universal Pictures International (UPI)", "Universal City Studios", "NBC Productions", "National Broadcasting Company (NBC)", "Focus Features", "Working Title Films", "DreamWorks", "DreamWorks Animation", "Illumination Entertainment", "Amblin Partners", "Carnival Film & Television", "WT2 Productions"))%>%
                         mutate(rec = sum(gross)) %>%
                         filter(company == "Universal Pictures") %>%
                         distinct(company, .keep_all = TRUE)

paramount_gross <- tot_gross %>% filter(company %in% c( "Paramount Pictures", "Paramount Classics", "Paramount Animation", "Paramount Vantage", "Viacom18 Motion Pictures", "CBS Entertainment Production", "CBS Films", "Miramax", "BET Pictures", "Comedy Central Films", "MTV Films", "Nickelodeon Movies"))%>%
                         mutate(rec = sum(gross)) %>%
                         filter(company == "Paramount Pictures") %>%
                         distinct(company, .keep_all = TRUE)



disney_20th_gross <- tot_gross %>% filter(company %in% c( "Walt Disney Pictures", "Walt Disney Feature Animation Florida", "Walt Disney Feature Animation", "Walt Disney Animation Studios", "Disneytoon Studios", "Disney Television Animation" , "20th Century Fox", "Twentieth Century Fox Film Corporation", "Twentieth Century Fox Animation", "Fox Searchlight Pictures", "Lucasfilm", "Lucasfilm Animation", "Marvel Studios", "Marvel Entertainment", "Marvel Enterprises", "Blue Sky Studios", "Pixar Animation Studios", "", ""))%>%
                         mutate(rec = sum(gross)) %>%
                         filter(company == "Walt Disney Pictures") %>%
                         distinct(company, .keep_all = TRUE)


prod <- rbind(columbia_gross, warner_gross, universal_gross, paramount_gross, disney_20th_gross)


prod_1 <- prod %>% select(company,rec, total) %>% arrange(desc(rec)) %>% mutate(porc = rec/total*100) %>% add_row(company = "Otros", porc = 37.05033)%>% relocate(total, .after = porc)

prod_1 <- prod_1 %>%
  arrange(desc(company)) %>%
 mutate(lab.ypos = cumsum(porc) - 0.5*porc)


p2 <-ggplot(prod_1, aes(x = "", y = porc, fill = company)) +
  geom_bar(width = 1, stat = "identity", color = "white") +
  coord_polar("y", start = 0)+
  geom_text(aes(y = lab.ypos, label = scales::percent(porc/100)), color = "black", size = 5.5)+
 theme_void() + scale_fill_manual(values = wes_palette("FantasticFox1", n = 6, type = "continuous"))

ggdraw(p2) + draw_image("https://www.ecured.cu/images/9/9d/Columbia_pictures.jpg",x= 0.29, y = 0.75, width = 0.1, height = 0.1) + draw_image("https://www.cinemascomics.com/wp-content/uploads/2019/11/WarnerMedia_Warner_Bros.jpg",x= 0.47, y = 0.75, width = 0.1, height = 0.1) + draw_image("https://1.bp.blogspot.com/--Gh5dYahIco/XIMJmYmWw6I/AAAAAAAALRI/fXrve6ZPlqQWGpWRJ9eCip6KHO4Nxf_SgCLcBGAs/s1600/disney_pocahontas.png",x= 0.63, y = 0.48, width = 0.1, height = 0.1) + draw_image("https://static.wikia.nocookie.net/disneyypixar/images/9/95/Universal_Studios.jpg/revision/latest/scale-to-width-down/340?cb=20180920175301&path-prefix=es",x= 0.54, y = 0.2, width = 0.1, height = 0.1) + draw_image("https://www.creativosonline.org/blog/wp-content/uploads/2015/08/paramount-majestic-mountain-logo.jpg",x= 0.36, y = 0.13, width = 0.1, height = 0.1)

Vemos que Walt Disney Pictures, que empezó como una productora de animación, hoy en día ha conseguido diversificar consolidándose como la productora más rentable.

Productoras y la nota media de sus peliculas en imdb

Productoras con más de 5 películas

#más de 5 peliculas
prod_score_5 <- movies %>% group_by(company) %>%
                           mutate(NN = n()) %>%
                           filter(NN > 5) %>%
                           summarise(nota_media = mean(score)) %>%
                           arrange(desc(nota_media))


DT::datatable(prod_score_5)

Productoras y oscars

oscars_3 <- oscars %>% filter(winner == TRUE, film != "") %>%
                      group_by(film) %>%
                      mutate(wins = n()) %>%
                      distinct(film, .keep_all = TRUE)


osc_prod <- left_join(movies, oscars_3, by = c("name" = "film"))

osc_prod_un <- osc_prod %>% filter(complete.cases(.)) %>% distinct(name, .keep_all = TRUE)

#productoras con más oscars
prod_osc <- osc_prod_un %>% group_by(company) %>%
                            mutate(tot_wins = sum(wins)) %>%
                            distinct(company, .keep_all = TRUE) %>%
                            select(company, tot_wins)%>%
                            arrange(desc(tot_wins))

prod_osc_10 <- prod_osc %>% head(10)

ggplot(prod_osc_10, aes(factor(company,levels = company), tot_wins, fill = company)) + geom_col() + coord_flip() + theme(legend.position = "none") +
  geom_text(aes(label= tot_wins ,hjust=-.03),size=4) +
labs(title = "Productoras con más Oscars",
    subtitle = "Todas las categorías",
    x = NULL , y = "número de Oscars") + scale_fill_manual(values = wes_palette("Zissou1", n = 10, type = "continuous"))

Productoras con más oscars a mejor película

(tambien mejor produccion, mejor pelicula extranjera, mejor documental y mejor `pelicUla de animacion)


oscars_4 <- oscars %>% filter(winner == TRUE, film != "", category %in% c("OUTSTANDING PICTURE", "UNIQUE AND ARTISTIC PICTURE", "OUTSTANDING PRODUCTION", "OUTSTANDING MOTION PICTURE", "DOCUMENTARY", "DOCUMENTARY (Feature)", "BEST MOTION PICTURE", "SPECIAL FOREIGN LANGUAGE FILM AWARD", "HONORARY FOREIGN LANGUAGE FILM AWARD", "FOREIGN LANGUAGE FILM", "BEST PICTURE", "ANIMATED FEATURE FILM", "INTERNATIONAL FEATURE FILM")) %>%
                      group_by(film) %>%
                      mutate(wins = n()) %>%
                      distinct(film, .keep_all = TRUE)


osc_prod_1 <- left_join(movies, oscars_4, by = c("name" = "film"))

osc_prod_dos <- osc_prod_1 %>% filter(complete.cases(.)) %>% distinct(name, .keep_all = TRUE)

prod_osc_peli <- osc_prod_dos %>% group_by(company) %>%
                            mutate(tot_wins = sum(wins)) %>%
                            distinct(company, .keep_all = TRUE) %>%
                            select(company, tot_wins)%>%
                            arrange(desc(tot_wins)) 


datatable(prod_osc_peli) %>% formatStyle(
  'tot_wins',target = 'row',
  backgroundColor = styleEqual(c(1, 2, 3, 5, 6), c('khaki', 'lightblue', 'pink', 'orange', 'palegreen'))
)

Resultados

Vamos a coger las productoras con oscar a mejor película.

prod_gross_30 <- prod_gross %>% head(30) %>%
                         mutate(rank_rec = c(1:30))

prod_score_30 <- prod_score_5 %>% head(30)


productoras_1 <- merge(merge(
  prod_gross_30,
  prod_score_30, all = TRUE),
  prod_osc_peli, all = TRUE)

hh <- productoras_1 %>% filter(complete.cases(.)) %>% arrange(desc(tot_wins))

hh %>% formattable(list(
 nota_media = formatter("span",
    style = x ~ style(color = ifelse(rank(-x) <= 1, "blue", "gray")),
    x ~ sprintf("%.2f (rank: %02d)", x, rank(-x))),
   area(col = recaudacion) ~ normalize_bar("pink", 0.2),
  `rank_rec`= color_tile(customGreen, customGreen0),
   tot_wins = color_tile("khaki", "orange")))
company recaudacion rank_rec nota_media tot_wins
Pixar Animation Studios 3242.025 13 7.78 (rank: 01) 5
DreamWorks Animation 4143.974 11 6.92 (rank: 02) 1

Curiosamente vemos que las dos únicas productoras en el top de recaudación, nota media de sus películas y que han ganado un Oscar son ambas de animación: Pixar Animation Studios y DreamWorks Animation. Siendo Pixar la que mejor nota media tiene y más Oscars, aunque menos recaudación que Dreamworks Animation.

6. Comparaciones

Peliculas con actor, director y productora más rentables

Para esta comparación vamos a coger a las 10 estrellas, los 10 directores y las 10 productoras que más recaudan para ver qué peliculas han hecho y si estas han tenido el éxito comercial que se espera de ellas.

#filtrando TOP 10 actores, dir, y prod

pelis_gross <- movies %>% filter(star %in% c("Tom Hanks", "Tom Cruise", "Robert Downey Jr.", "Will Smith", "Johnny Depp", "Adam Sandler", "Daniel Radcliffe", "Ben Stiller", "Leonardo DiCaprio", "Jim Carrey")) %>%
                          filter(director %in% c("Steven Spielberg", "Michael Bay", "Peter Jackson", "James Cameron", "Christopher Nolan", "Tim Burton", "Robert Zemeckis", "Chris Columbus", "Ron Howard", "J.J. Abrams"))%>%
                          filter(company %in% c("Warner Bros.", "Universal Pictures", "Paramount Pictures", "Twentieth Century Fox Film Corporation", "Walt Disney Pictures", "Columbia Pictures", "New Line Cinema", "Columbia Pictures Corporation", "Touchstone Pictures", "DreamWorks")) %>%
                          arrange(desc(gross)) %>%
                          mutate(act_dir_prod = "si") %>%
                          mutate(gross = gross/1000000)


pelis_gross <- pelis_gross %>% mutate(name = forcats::as_factor(name)) %>%
             mutate(name = forcats::fct_reorder(name,gross))

ggplot(pelis_gross, aes(name, gross, fill = name)) + geom_col() + coord_flip() + theme(legend.position = "none") +
labs(subtitle = "Recaudación en millones de dólares",
    x = NULL, y = NULL)+
  geom_text(aes(label= gross), position = position_stack(vjust= 0.5),
            colour = "grey30", size = 3) + scale_fill_manual(values = wes_palette("Zissou1", n = 27, type = "continuous"))

Comparación con las peliculas que más han recaudado

Comparamos si la fórmula director + actor + productora rentables de verdad crea películas rentables. Comparamos con el top de peliculas con más recaudación (desde 1986 y en la lista).

pelis_max_gross <- movies %>% arrange(desc(gross)) %>% head(50) %>% mutate(act_dir_prod = "top_50")%>%
                          mutate(gross = gross/1000000)

pelis_rec <- union(pelis_gross, pelis_max_gross)

# pelis_rec <- pelis_rec[-c(30), ]

pelis_rec_1 <- pelis_rec %>% arrange(desc(gross)) %>% head(53)

pelis_rec_2 <- pelis_rec_1[-c(4, 47, 53), ]

pelis_rec_2 <- pelis_rec_2 %>% mutate(name = forcats::as_factor(name)) %>%
             mutate(name = forcats::fct_reorder(name,gross))



ggplot(pelis_rec_2, aes(name, gross, fill = act_dir_prod)) + geom_col() + scale_y_continuous(labels=scales::comma) + coord_flip() +
labs(subtitle = "Recaudación en millones de dólares",
    x = NULL, y = NULL) + scale_fill_manual(values = wes_palette("Moonrise3", n = 2, type = "continuous"))


pelis_list <- pelis_rec_2 %>% mutate(ranking = c(1:50)) %>% 
                              filter(act_dir_prod == "si") %>%
                              select(ranking, name, director, star, company, gross)

pelis_list %>% formattable(list(
  `ranking`= color_tile(customGreen, customGreen0),
   area(col = gross) ~ normalize_bar("pink", 0.2)))
ranking name director star company gross
3 Titanic James Cameron Leonardo DiCaprio Twentieth Century Fox Film Corporation 658.6723
45 Forrest Gump Robert Zemeckis Tom Hanks Paramount Pictures 330.2522
50 Harry Potter and the Sorcerer’s Stone Chris Columbus Daniel Radcliffe Warner Bros.  317.5756

En el Top 50 películas más taquilleras de la historia podemos encontrar tres de las películas que cumplen la hipótesis de director + productora + actor/actriz. Estas son Titanic, Forrest Gump y Harry Potter, siendo Titanic la tercera con más recaudación desde 1986. Cabe destacar que en el año de su estreno se convirtió en la película más taquillera hasta ese momento.


#boxplot medias
movies_box <- movies %>% mutate(gross = gross/1000000) %>% mutate(act_dir_prod = "Todas")

box_pelis_gross <- union(movies_box, pelis_rec)

library("wesanderson")

p <- ggplot(box_pelis_gross, aes(x = reorder(act_dir_prod, gross, mean),  y = gross, fill = act_dir_prod )) + geom_boxplot() + scale_y_continuous(breaks = seq(0, 500, 50), limits = c(NA, 500)) + scale_fill_manual(values = wes_palette("Darjeeling1", n = 3, type = "discrete")) + labs(subtitle = "Recaudación en millones de dólares", x = NULL) + theme(legend.position = "none")

library(plotly)

ggplotly(p)

Podemos ver como, teniendo en cuenta que la mediana de todas las películas de la lista es de poco más de 12 millones de dólares , contratar un actor + director + productora rentable (el boxplot “si”) sube la mediana de ingresos a más de 135 millones de dólares. Sin embargo queda lejos de la mediana de las 50 películas que más han recaudado de la lista, 368 milliones de dólares.

Recaudación, nota y Oscars

#scatterplot con nota media y oscars
oscars_pelis <- oscars %>% filter(winner == "TRUE", year_film > 1986) %>% 
                           group_by(film) %>% 
                           mutate(wins = n())%>% 
                           distinct(film,.keep_all = TRUE) %>%
                           mutate(film = case_when(
                            film == "Dr. Seuss' How the Grinch Stole Christmas" ~ "How the Grinch Stole Christmas",
                            film == "Sweeney Todd The Demon Barber of Fleet Street" ~ "Sweeney Todd: The Demon Barber of Fleet Street",
                            TRUE  ~  film ))

oscars_pelis_gross <- left_join(pelis_gross, oscars_pelis, by = c("name" = "film"))

oscars_pelis_gross$wins[is.na(oscars_pelis_gross$wins)] <- 0

library(ggrepel)
p1 <- ggplot(oscars_pelis_gross, aes(gross, score, size = wins , color = name)) + geom_point()  + theme(legend.position = "none") + scale_x_continuous(labels=scales::dollar, breaks = seq(0, 700, 100)) + scale_color_manual(values = wes_palette("Zissou1", n = 27, type = "continuous"))


library(plotly)

ggplotly(p1)

En esta gráfica vemos cómo estas películas con act + dir + prod más rentables, han sido luego recibidas por los usuarios de imdb (score) y además según su tamaño cuántos Oscars ganaron.

Vemos en el caso de Titanic como a parte de convertirse en la película más taquillera, se llevó la mayor cantidad de Óscars (record que sigue vigente, solo igualado por el Señor de los Anillos 3) en su momento. También cabe destacar las películas Salvar al soldado Ryan, Inception y Forrest Gump, que aparte de llevarse entre 4 y 6 Oscars, están valoradas por los usuarios con más de un 8.5.

Peliculas con actor, director y productora con MEJOR NOTA


#filtrando TOP 10 actores, dir, y prod

pelis_score_5 <- movies %>% filter(star %in% c("Aamir Khan", "Ricardo Darín","Leonardo DiCaprio", "Shah Rukh Khan", "Takeshi Kitano", "Christian Bale", "Andrew Garfield", "Ian McKellen", "Tom Hardy",  "Javier Bardem")) %>%
                          filter(director %in% c("Christopher Nolan", "Quentin Tarantino","James Cameron","Giuseppe Tornatore", "Peter Jackson", "Alejandro González Iñárritu", "David Fincher", "Éric Rohmer", "Denis Villeneuve", "Chan-wook Park"))%>%
                          filter(company %in% c("Pixar Animation Studios", "Marvel Studios", "Warner Independent Pictures (WIP)", "MK2 Productions", "Bandai Visual Company", "Walt Disney Animation Studios", "Lucasfilm", "Zentropa Entertainments", "Canal+ España", "Good Machine")) %>%
                          arrange(desc(score)) %>%
                          mutate(act_dir_prod = "si")

No se han encontrado películas con los actores + directores + productoras mejor valorados.

Peliculas con actor, director y productora con MAS DE UN OSCAR

(tomando los datos de act_osc, dir_osc y prod_osc_peli <- oscar a MEJOR PELICULA)


pelis_oscar <- movies %>% filter(star %in% c("Meryl Streep", "Jack Nicholson","Robert De Niro", "Tom Hanks", "Gene Hackman", "Sean Penn", "Jane Fonda", "Jack Lemmon", "Michael Caine",  "Denzel Washington", "Bette Davis", "Jason Robards", "Jodie Foster", "Sally Field", "Dustin Hoffman","Daniel Day-Lewis", "Peter Ustinov", "Jessica Lange","Glenda Jackson", "Marlon Brando","Frances McDormand", "Kevin Spacey", "Cate Blanchett","Hilary Swank", "Maggie Smith", "Christoph Waltz", "Mahershala Ali")) %>%
                          filter(director %in% c("Oliver Stone", "Clint Eastwood","Steven Spielberg","Milos Forman", "Ang Lee"))%>%
                          filter(company %in% c("Warner Bros.", "Pixar Animation Studios", "Universal Pictures", "Walt Disney Pictures", "Recorded Picture Company (RPC)", "Columbia Pictures Corporation", "Paramount Pictures", "Miramax")) %>%
                          arrange(desc(gross)) %>%
                          mutate(act_dir_prod = "si")

peliculas_oscar <- pelis_oscar %>% select(name, director, star, company, gross)
#Mystic River y Million Dollar Baby

ee <- oscars %>% filter(film %in% c("Mystic River", "Million Dollar Baby"), winner == TRUE) %>% select(film, category, name, winner)

datatable(ee) %>% formatStyle(
  'film',target = 'row',
  backgroundColor = styleEqual(c("Mystic River", "Million Dollar Baby"), c('pink', 'lightblue'))) %>% formatStyle('name',
  backgroundColor = styleEqual(c("Sean Penn", "Hilary Swank", "Clint Eastwood"), c('khaki', 'khaki', 'khaki'))) %>% formatStyle('category',
  backgroundColor = styleEqual(c("ACTOR IN A LEADING ROLE", "ACTRESS IN A LEADING ROLE", "DIRECTING", "BEST PICTURE"), c('khaki', 'khaki', 'khaki', 'khaki'))) %>% formatStyle('name', target = 'row',
  backgroundColor = styleEqual(c("Clint Eastwood, Albert S. Ruddy and Tom Rosenberg, Producers"), c('khaki'))) %>% formatStyle('name', target = "row",
  fontWeight = styleEqual("Clint Eastwood, Albert S. Ruddy and Tom Rosenberg, Producers", "bold"))

Podemos ver como la combinación de productora ganadora de Oscar, actor ganador de Oscar y director ganador de Oscar fue fructífera en estas dos películas. Mirando los datos con detenimiento vemos como Sean Penn ganó su primer Oscar con Mystic River (con lo cual cuando se le escogió para la pelicula todavía no era ganador de Oscar).

En el caso de Million Dollar Baby, Clint Eastwood, Hilary Swank y Warner Bros ya habían ganado un oscar (casualmente con Clint Eastwood en Unforgiven), y el resultado fue el Oscar a Mejor Película, el Oscar a Mejor Actriz para Hillary Swank y el Oscar a Mejor Director para Clint Eastwood, con lo cual en este caso les salió bien la estrategia de escoger a ganadores de oscar.

7. Relaciones

Todas las productoras

Actor, director y productora

Primero probamos a ver si hay películas que cuenten con actor, director y productora que cumplen los 3 criterios (más taquilleros, mejor nota y ganadores de óscar; es decir los que salen en Resultados)

#todo: nada
df <- movies %>% filter(star %in% c( "Brad Pitt", "Christian Bale", "Leonardo DiCaprio", "Tom Hanks")) %>% filter(director %in% c("Steven Spielberg", "Peter Jackson", "James Cameron")) %>% filter(company %in% c("Pixar Animation Studios", "DreamWorks Animation"))

No sale ningún resultado, vamos a probar con actor y director:

Actor y director

df_1 <- movies %>% filter(star %in% c( "Brad Pitt", "Christian Bale", "Leonardo DiCaprio", "Tom Hanks")) %>% filter(director %in% c("Steven Spielberg", "Peter Jackson", "James Cameron"))#6 resultados

df_1 %>% select(name, director, star, company, gross, score)
name director star company gross score
Empire of the Sun Steven Spielberg Christian Bale Amblin Entertainment 22238696 7.8
Titanic James Cameron Leonardo DiCaprio Twentieth Century Fox Film Corporation 658672302 7.8
Saving Private Ryan Steven Spielberg Tom Hanks DreamWorks 216540909 8.6
Catch Me If You Can Steven Spielberg Leonardo DiCaprio DreamWorks 164615351 8.1
The Terminal Steven Spielberg Tom Hanks DreamWorks 77872883 7.3
Bridge of Spies Steven Spielberg Tom Hanks DreamWorks 72313754 7.6

Tenemos 6 películas. Vamos a ver con actor y productora:

Actor y productora

df_2 <- movies %>% filter(star %in% c( "Brad Pitt", "Christian Bale", "Leonardo DiCaprio", "Tom Hanks")) %>% filter(company %in% c("Pixar Animation Studios", "DreamWorks Animation"))#Toy Story 1 y 2

df_2 %>% select(name, director, star, company, gross, score)
name director star company gross score
Toy Story John Lasseter Tom Hanks Pixar Animation Studios 191796233 8.3
Toy Story 2 John Lasseter Tom Hanks Pixar Animation Studios 245852179 7.9

Tenemos dos resultados.

Director y productora

df_3 <- movies %>% filter(director %in% c("Steven Spielberg", "Peter Jackson", "James Cameron")) %>% filter(company %in% c("Pixar Animation Studios", "DreamWorks Animation"))#nada

Ningún resultado, ahora vamos a quitar a las productoras de animación, ya que podían estar entorpeciendo la relación entre actores o directores que no suelen dedicarse al ámbito de la animación.

Sin animación

sin_anim <- movies %>% filter(genre != "Animation")

prod_gross_1 <- sin_anim %>% group_by(company) %>%
                         summarise(recaudacion = sum(gross)) %>%
                         arrange(desc(recaudacion)) %>%
                         head(30)

prod_score_1 <- sin_anim %>% group_by(company) %>%
                         summarise(nota_media = mean(score)) %>%
                         arrange(desc(nota_media)) %>%
                         head(30)

#más de 5 peliculas
prod_score_5_1 <- sin_anim %>% group_by(company) %>%
                           mutate(NN = n()) %>%
                           filter(NN > 5) %>%
                           summarise(nota_media = mean(score)) %>%
                           arrange(desc(nota_media)) %>%
                           head(30)

productoras_1 <- merge(merge(
  prod_gross_1,
  prod_score_5_1, all = TRUE),
  prod_osc, all = TRUE)

dd <- productoras_1 %>% filter(complete.cases(.)) %>% arrange(desc(tot_wins))

dd
company recaudacion nota_media tot_wins
Focus Features 811903004 6.802857 8

Vemos que la única productora que cumple ahora los tres criterios es Focus Features.

Actor, director y productora

#SIN ANIMACION
df_rel_1 <- movies %>% filter(star %in% c( "Brad Pitt", "Christian Bale", "Leonardo DiCaprio", "Tom Hanks")) %>% filter(director %in% c("Steven Spielberg", "Peter Jackson", "James Cameron")) %>% filter(company == "Focus Features")#nada

Incorporando la productora Focus Features sigue sin haber ninguna pelicula que cumpla los tres criterios. Vamos a ver actor y productora que hayan trabajado juntos.

Actor y productora

df_rel_2 <- movies %>% filter(star %in% c( "Brad Pitt", "Christian Bale", "Leonardo DiCaprio", "Tom Hanks")) %>% filter(company == "Focus Features")
#Burn After Reading
df_rel_2
budget company country director genre gross name rating released runtime score star votes writer year
37000000 Focus Features USA Ethan Coen Comedy 60355347 Burn After Reading R 2008-09-12 96 7 Brad Pitt 264758 Joel Coen 2008

Tenemos un resultado. Nos saltamos Actor y director porque es el mismo resultado de antes.

Director y productora

df_rel_4 <- movies %>%  filter(director %in% c("Steven Spielberg", "Peter Jackson", "James Cameron")) %>% filter(company == "Focus Features")#nada

Nada, ahora vamos a comparar todas estas películas.

8. Conclusiones


qq <- Reduce(union, list(df_1, df_2, df_rel_2))

qq <- qq %>% mutate(gross = gross/1000000)

#scatterplot con nota media y oscars

oscars_pelis_df <- left_join(qq, oscars_pelis, by = c("name" = "film"))

oscars_pelis_df$wins[is.na(oscars_pelis_df$wins)] <- 0

library(ggrepel)
p3 <- ggplot(oscars_pelis_df, aes(gross, score, label = name, color = name, size = wins)) + geom_point() + theme(legend.position = "none") + geom_label_repel(size = 3) + scale_color_manual(values = wes_palette("FantasticFox1", n = 10, type = "continuous")) + scale_x_continuous( breaks = seq(0, 700, 100))

#con los nombres
p3

Se puede apreciar una ligera correlación entre recaudación y nota media. También vemos que las dos películas con más Oscars son la película con mejor nota y la más taquillera.

Vemos que las notas de los usuarios de imdb no son malas, todas por encima de un 7 y destacando la película Salvar al soldado Ryan con un 8,6 de nota. En temas de taquilla, vemos que todas superan la mediana de 12 millones de dólares, destaca Titanic, que durante muchos años fue la película que más había recaudado en USA (hasta 2009 que ese récord fue superado por Avatar, otra película del mismo director, James Cameron)

Ahora vamos a ver su éxito en comparación con el Top 30 películas con más recaudación, mejor nota y más Oscars.

Comparación con las películas con más recaudación

#top50 pelis con más recaudación ya tenemos -> pelis_max_gross
qq <- qq %>% mutate(act_dir_prod = "final")

pelis_rec_fin <- union(qq, pelis_max_gross)

pelis_rec_fin <- pelis_rec_fin %>% arrange(desc(gross)) %>% head(31)

pelis_rec_fin <- pelis_rec_fin[-c(4), ]

pelis_rec_fin <- pelis_rec_fin %>% mutate(name = forcats::as_factor(name)) %>%
             mutate(name = forcats::fct_reorder(name,gross))

pelis_list_1 <- pelis_rec_fin %>% mutate(ranking = c(1:30)) %>% 
                              filter(act_dir_prod == "final") %>%
                              select(ranking, name, director, star, company, gross)

urls_tit <- "https://upload.wikimedia.org/wikipedia/en/1/19/Titanic_%28Official_Film_Poster%29.png"
tit_urls <- pelis_list_1 %>% add_column(urls_tit)

tit_urls %>% gt() %>%
  gt::text_transform(locations = cells_body(columns = vars(urls_tit)),
                     fn = function(x) {gt::web_image(x, height = 100)}) %>%  tab_style(
    style = cell_fill(color = "pink"),
    locations = cells_body(columns = vars(gross),
      rows = gross > 1 )) %>% tab_style(
    style = cell_fill(color = "lightgreen"),
    locations = cells_body(columns = vars(ranking),
      rows = ranking > 2 )) %>%  data_color(columns = vars(name),
    colors = "lightblue")
ranking name director star company gross urls_tit
3 Titanic James Cameron Leonardo DiCaprio Twentieth Century Fox Film Corporation 658.6723

Comparación con las películas con mejor nota media

#top30 pelis con mejor nota
pelis_max_score <- movies %>% arrange(desc(score))%>% ungroup() %>% head(30) %>% mutate(act_dir_prod = "top_30")

pelis_score_fin <- union(qq, pelis_max_score)

pelis_score_fin <- pelis_score_fin %>% arrange(desc(score)) %>% head(31)

pelis_score_fin <- pelis_score_fin[-c(21), ]


pelis_list_2 <- pelis_score_fin %>% mutate(ranking = c(1:30)) %>% 
                              filter(act_dir_prod == "final") %>%
                              select(ranking, name, director, star, company, score)



urls_sav <- "https://es.web.img3.acsta.net/pictures/14/03/05/09/42/163621.jpg"
sav_urls <- pelis_list_2 %>% add_column(urls_sav)

sav_urls %>% gt() %>%
  gt::text_transform(locations = cells_body(columns = vars(urls_sav)),
                     fn = function(x) {gt::web_image(x, height = 100)}) %>%  tab_style(
    style = cell_fill(color = "pink"),
    locations = cells_body(columns = vars(score),
      rows = score > 5 )) %>% tab_style(
    style = cell_fill(color = "lightgreen"),
    locations = cells_body(columns = vars(ranking),
      rows = ranking > 2 )) %>%  data_color(columns = vars(name),
    colors = "lightblue")
ranking name director star company score urls_sav
15 Saving Private Ryan Steven Spielberg Tom Hanks DreamWorks 8.6

Comparación con las películas con más Oscars

#top30 pelis con más oscars
pelis_max_oscars <- oscars_pelis %>% filter(year_film > 1986) %>% arrange(desc(wins)) %>% head(31) %>% mutate(act_dir_prod = "top_30")

pelis_max_oscars <- pelis_max_oscars[-c(1), ]

pelis_osc_fin <- left_join(oscars_pelis_df, pelis_max_oscars, by = c("name" = "film"))

pelis_osc_fin <- pelis_osc_fin %>% select(year_film = year_film.x, year_ceremony = year_ceremony.y, ceremony = ceremony.y, category = category.y, name = name.y, film = name, winner = winner.y, wins = wins.y) %>% mutate(act_dir_prod = "final")

pelis_oscars_fin <- union(pelis_osc_fin, pelis_max_oscars)

pelis_oscars_fin <- pelis_oscars_fin %>% arrange(desc(wins)) %>% head(32)

pelis_oscars_fin <- pelis_oscars_fin[-c(2, 19), ]


pelis_list_3 <- pelis_oscars_fin %>% mutate(ranking = case_when(
                                         film == "Titanic" ~ 1,
                                         film == "Saving Private Ryan" ~ 15,
                                         TRUE  ~  0 ))%>%
                                      filter(act_dir_prod == "final") %>%
                                     select(film, ranking, wins)
#en el ultimo momento me daba error lo de mutate(ranking = c(1:30)) habiéndome funcionado antes, y tuve que hacer la chapuza con el case_when.

urls_osc <- c("https://upload.wikimedia.org/wikipedia/en/1/19/Titanic_%28Official_Film_Poster%29.png",  "https://es.web.img3.acsta.net/pictures/14/03/05/09/42/163621.jpg")
osc_urls <- pelis_list_3 %>% add_column(urls_osc)

osc_urls %>% gt() %>%
  gt::text_transform(locations = cells_body(columns = vars(urls_osc)),
                     fn = function(x) {gt::web_image(x, height = 100)})%>%
   data_color(columns = vars(film),
    colors = "lightblue") %>%
  data_color(columns = vars(ranking),
    colors = "pink")%>%
   data_color(columns = vars(wins),
    colors = "khaki") %>% tab_style(
    style = cell_fill(color = "orange"),
    locations = cells_body(columns = vars(wins),
      rows = wins > 5 )) %>% tab_style(
    style = cell_fill(color = "lightgreen"),
    locations = cells_body(columns = vars(ranking),
      rows = ranking < 2 )
  )
ranking wins urls_osc
Titanic
1 11
Saving Private Ryan
15 5

Para concluir tenemos que destacar las películas Titanic y Salvar al soldado Ryan, ambas con protagonista y director que cumplían los 3 requisitos y el resultado ha dado sus frutos.

Titanic fue en su momento la película más taquillera de historia (ahora la número 3) y la que más Óscars se llevó. Salvar al soldado Ryan se encuentra en el puesto 15 de las películas mejor valoradas por los usuarios de imdb y además se encuentra también en el puesto 15 de las películas con más Oscars (con 5 galardones).

Sobre si el éxito de estas películas es debido a la elección del actor principal, director o productora no se puede decir con total precisión.

En el caso de Titanic es difícil de decir, ya que se puede discutir si las figuras de James Cameron y Leonardo Dicaprio estaban tan consolidadas como hoy en día.

En el caso de Salvar al soldado Ryan sí que se podría decir con más seguridad que tanto Steven Spielberg como Tom Hanks estaban más consolidados, puesto que Spielberg ya tenía un Oscar (ganó el segundo precisamente con esta película) y Hanks tenía dos. También hemos visto que ambos son los que más recaudan en su oficio.

LS0tDQp0aXRsZTogIkPDs21vIGluZmx1eWVuIGVsIGFjdG9yL2FjdHJpeiBwcmluY2lwYWwsIGRpcmVjdG9yIHkgcHJvZHVjdG9yYSBlbiBlbCDDqXhpdG8gZGUgdW5hIHBlbMOtY3VsYSINCnN1YnRpdGxlOiAiTWFudWVsIEppbcOpbmV6IEhhcm8obWFqaWhhQGFsdW1uaS51di5lcykiICMtIHBvbmdvIHTDuiBub21icmUgYWjDrSBwYXJhIHEgYXBhcmV6Y2EgbcOhcyBncmFuZGUgcSBlbCBkZSBsYSBVVg0KYXV0aG9yOiAiVW5pdmVyc2l0YXQgZGUgVmFsw6huY2lhIg0KZGF0ZTogIkVuZXJvIGRlIDIwMjEgKGFjdHVhbGl6YWRvIGVsIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVknKWApIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgICNjc3M6ICIuL2Fzc2V0cy9teV9jc3NfZmlsZS5jc3MiDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGhpZ2hsaWdodDogdGV4dG1hdGUgDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiAzIA0KICAgIHRvY19mbG9hdDogDQogICAgICBjb2xsYXBzZWQ6IHRydWUNCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICBkZl9wcmludDoga2FibGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlDQotLS0NCg0KYGBge3IgcGFja2FnZXMtc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShrbGlwcHkpICAjLSByZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigicmxlc3VyL2tsaXBweSIpDQpsaWJyYXJ5KGtuaXRyKQ0KYGBgDQoNCmBgYHtyIGNodW5rLXNldHVwLCBpbmNsdWRlID0gRkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGV2YWwgPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgICAgI3Jlc3VsdHMgPSAiaG9sZCIsDQogICAgICAgICAgICAgICAgICAgICAgY2FjaGUgPSBGQUxTRSwgY2FjaGUucGF0aCA9ICIvY2FjaGVzLyIsIGNvbW1lbnQgPSAiIz4iLA0KICAgICAgICAgICAgICAgICAgICAgICNmaWcud2lkdGggPSA3LCAjZmlnLmhlaWdodD0gNywgICANCiAgICAgICAgICAgICAgICAgICAgICAjb3V0LndpZHRoID0gNywgb3V0LmhlaWdodCA9IDcsDQogICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2UgPSBUUlVFLCAgZmlnLnNob3cgPSAiaG9sZCIsDQogICAgICAgICAgICAgICAgICAgICAgZmlnLmFzcCA9IDcvOSwgb3V0LndpZHRoID0gIjYwJSIsIGZpZy5hbGlnbiA9ICJjZW50ZXIiKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGRldiA9ICJwbmciLCBkZXYuYXJncyA9IGxpc3QodHlwZSA9ICJjYWlyby1wbmciKSkNCmBgYA0KDQpgYGB7ciBvcHRpb25zLXNldHVwLCBpbmNsdWRlID0gRkFMU0V9DQpvcHRpb25zKHNjaXBlbiA9IDk5OSkgIy0gcGFyYSBxdWl0YXIgbGEgbm90YWNpw7NuIGNpZW50w61maWNhDQpvcHRpb25zKCJ5YW1sLmV2YWwuZXhwciIgPSBUUlVFKSANCmBgYA0KDQoNCmBgYHtyIGtsaXBweSwgZWNobyA9IEZBTFNFfQ0Ka2xpcHB5OjprbGlwcHkocG9zaXRpb24gPSBjKCJ0b3AiLCAicmlnaHQiKSkgIy0gcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInJsZXN1ci9rbGlwcHkiKQ0KYGBgDQoNCjxociBjbGFzcz0ibGluZWEtYmxhY2siPg0KDQpUcmFiYWpvIGVsYWJvcmFkbyBwYXJhIGxhIGFzaWduYXR1cmEgIlByb2dyYW1hY2nDs24geSBtYW5lam8gZGUgZGF0b3MgZW4gbGEgZXJhIGRlbCBCaWcgRGF0YSIgZGUgbGEgVW5pdmVyc2l0YXQgZGUgVmFsw6huY2lhIGR1cmFudGUgZWwgY3Vyc28gMjAyMC0yMDIxLiBFbCByZXBvIGRlbCB0cmFiYWpvIGVzdMOhIFthcXXDrV0oaHR0cHM6Ly9naXRodWIuY29tL21hbnVqaW1lbmV6NjIvdHJhYmFqb19CaWdEYXRhKXt0YXJnZXQ9Il9ibGFuayJ9LiBMYSBww6FnaW5hIHdlYiBkZSBsYSBhc2lnbmF0dXJhIHkgbG9zIHRyYWJham9zIGRlIG1pcyBjb21wYcOxZXJvcyBwdWVkZW4gdmVyc2UgW2FxdcOtXShodHRwczovL3BlcmV6cDQ0LmdpdGh1Yi5pby9pbnRyby1kcy0yMC0yMS13ZWIvMDctdHJhYmFqb3MuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifS4NCg0KPCEtLSBFbCBww6FycmFmbyBkZSBhcnJpYmEgaGFzIGRlIGRlamFybG8gY2FzaSBpZ3VhbCwgDQogICAgICAgIHNvbG8gSEFTIGRlIFNVU1RJVFVJUiBsYXMgMiB2ZWNlcyBxdWUgYXBhcmVjZSAicGVyZXpwNDQiIHBvciB0dSB1c3VhcmlvIGRlIEdpdGh1Yi0tPg0KDQo8aHIgY2xhc3M9ImxpbmVhLXJlZCI+DQoNCiMgMS4gSW50cm9kdWNjacOzbg0KDQpBbnRlcyBkZSBlbGVnaXIgZXN0b3MgZGF0b3MgZXN0dXZlIHZpZW5kbyBkYXRvcyBkZSBsYSB3ZWIgZGUgW2ltZGJdKGh0dHBzOi8vd3d3LmltZGIuY29tL2ludGVyZmFjZXMvKSAocGVzYWJhbiBkZW1hc2lhZG8pIHkgZGUgb3RybyBkYXRhc2V0IGRlIGthZ2dsZSBkZSBsYSB3ZWIgdG1kYi4gRmluYWxlbWVudGUgbWUgaGUgZGVjYW50YWRvIHBvciBbZXN0b3NdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGFuaWVsZ3JpamFsdmFzL21vdmllcykgcG9ycXVlIHRpZW5lbiBsb3MgcHJpbmNpcGFsZXMgZGF0b3MgcXVlIHF1aWVybyBhbmFsaXphciBkZSAyMjAgcGVsw61jdWxhcyBwb3IgY2FkYSBhw7FvIGRlc2RlIDE5ODYgaGFzdGEgMjAxNi4gVGFtYmnDqW4gaGUgdXRpbGl6YWRvIHVuIGRmIGRlIGxvcyBub21pbmFkb3MgeSBsb3MgZ2FuYWRvcmVzIGRlIGxvcyBbT3NjYXJdKHNodHRwczovL3d3dy5rYWdnbGUuY29tL3VuYW5pbWFkL3RoZS1vc2Nhci1hd2FyZCksIHNhY2FkbyBkZSBrYWdnbGUgdGFtYmnDqW4uDQoNCkxhIGludGVuY2nDs24gcHJpbmNpcGFsIGRlIGVzdGUgdHJhYmFqbyBlcyB2ZXIgc2kgZXhpc3RlIHJlbGFjacOzbiBlbnRyZSBlbCDDqXhpdG8gdGFudG8gY29tZXJjaWFsIChlbiBjdWFudG8gYSByZWNhdWRhY2nDs24gKiplbiBVU0EqKikgY29tbyBkZSBwb3B1bGFyaWRhZCAocHVudHVhY2nDs24gbWVkaWEgZGUgbG9zIHVzdWFyaW9zIGRlIElNREIpIGNvbW8gZGUgcmVjb25vY2ltaWVudG8gKHByZW1pb3MgT3NjYXJzKSB5IGVsIGFjdG9yL2FjdHJpeiBwcmluY2lwYWwsIGVsIGRpcmVjdG9yIG8gbGEgcHJvZHVjdG9yYS4NCg0KIyAyLiBEYXRvcw0KDQpQcmltZXJvIGNhcmdhbW9zIGxvcyBwYXF1ZXRlcw0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KERUKQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KGZvcm1hdHRhYmxlKQ0KbGlicmFyeShjb3dwbG90KQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSgid2VzYW5kZXJzb24iKQ0KbGlicmFyeShnZ3RoZW1yKQ0KbGlicmFyeShndCkNCmBgYA0KDQpDYXJnYW1vcyBsb3MgZGF0b3MNCg0KYGBge3J9DQptb3ZpZXMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAibW92aWVfaW5kdXN0cnkiLCAibW92aWVzLmNzdiIpKQ0Kb3NjYXJzIDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoImRhdG9zIiwib3NjYXJzIiwgInRoZV9vc2Nhcl9hd2FyZC5jc3YiKSkNCmBgYA0KDQpUdXZlIGxhIHN1ZXJ0ZSBkZSBxdWUgbG9zIGRhdG9zIGRlIGxvcyBkb3MgZGF0YWZyYW1lcyBxdWUgdXRpbGljw6kgeWEgZXN0YWJhbiBiYXN0YW50ZSBsaW1waW9zIHkgbG9zIHBvY29zIGNhbWJpb3MgcXVlIHR1dmUgcXVlIGhhY2VyIGxvcyBoaWNlIHNvYnJlIGxhIG1hcmNoYS4NCg0KUHJpbWVybyB2YW1vcyBhIG9ic2VydmFyIHF1aWVuZXMgc29uIGxvcyBhY3RvcmVzL2FjdHJpY2VzLCBkaXJlY3RvcmVzIHkgcHJvZHVjdG9yYXMgcXVlIG3DoXMgcmVjYXVkYW4sIG1lam9yIHZhbG9yYWNpw7NuIHRpZW5lbiBwb3IgZWwgcMO6YmxpY28geSBtZWpvciB2YWxvcmFjacOzbiB0aWVuZW4gcG9yIGxhIEFjYWRlbWlhIGRlIGxhcyBPc2NhcnMuDQoNClBhcmEgY2FsY3VsYXIgbGEgbm90YSBtZWRpYSBoZSB0ZW5pZG8gcXVlIGVzY29nZXIgYWN0b3Jlcy9kaXJlY3RvcmVzL3Byb2R1Y3RvcmFzIHF1ZSB0ZW5nYW4gbcOhcyBkZSA1IHBlbMOtY3VsYXMsIHlhIHF1ZSBzaW5vIGVyYSBtw6FzIGRpZsOtY2lsIGVuY29udHJhciB1bmEgcmVsYWNpw7NuLiBQb3IgZWplbXBsbyBsYSBwZWzDrWN1bGEgYnJhc2lsZcOxYSAiQ2l1ZGFkIGRlIERpb3MiIHRpZW5lIHVuYSBkZSBsYXMgbm90YXMgbcOhcyBhbHRhcyAoOC43KSwgcGVybyBlcyBsYSDDum5pY2EgcGVsw61jdWxhIGVuIGxhIGxpc3RhIGRlbCBhY3RvciBwcmluY2lwYWwgeSBkZSBsYSBwcm9kdWN0b3JhLg0KDQpEZXNwdcOpcyBlbiBlbCBhcGFydGFkbyAiUmVzdWx0YWRvcyIgb2JzZXJ2YXJlbW9zIGxvcyBhY3RvcmVzL2RpcmVjdG9yZXMvcHJvZHVjdG9yYXMgcXVlIHNlIGVuY3VlbnRyYW4gdGFudG8gZW4gZWwgKipUb3AgMzAqKiBkZSBsb3MgcXVlIG3DoXMgcmVjYXVkYW4sIGVuIGVsICoqVG9wIDMwKiogZGUgbG9zIHF1ZSBtZWpvciBub3RhIHRpZW5lbiBzdXMgcGVsw61jdWxhcyB5IHRpZW5lbiBwb3IgbG8gbWVub3MgKip1biBPc2NhcioqLg0KDQojIDMuIEFjdG9yZXMgey50YWJzZXQgLnRhYnNldC1waWxsfQ0KDQojIyBBY3RvcmVzIHF1ZSBtw6FzIHJlY2F1ZGFuDQoNCmBgYHtyfQ0KI2FjdG9yZXMgcXVlIG3DoXMgcmVjYXVkYW4NCg0KI3RvcCAzMA0Kc3Rhcl9ncm9zcyA8LSBtb3ZpZXMgJT4lIGdyb3VwX2J5KHN0YXIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShyZWNhdWRhY2lvbiA9IHN1bShncm9zcykpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhyZWNhdWRhY2lvbikpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShyZWNhdWRhY2lvbiA9IHJlY2F1ZGFjaW9uLzEwMDAwMDApDQoNCkRUOjpkYXRhdGFibGUoc3Rhcl9ncm9zcywgY2FwdGlvbiA9ICdSZWNhdWRhY2nDs24gZW4gbWlsbG9uZXMgZGUgZMOzbGFyZXMnKQ0KDQpgYGANCg0KQ29tcHJ1ZWJhIGxvIHF1ZSByZWN1YWRhIHR1IGFjdG9yL2FjdHJpeiBmYXZvcml0by4NCg0KYGBge3J9DQpzdGFyX2dyb3NzXzEwIDwtIHN0YXJfZ3Jvc3MgJT4lIGhlYWQoMTApDQoNCnN0YXJfZ3Jvc3NfMTAgPC0gc3Rhcl9ncm9zc18xMCAlPiUgbXV0YXRlKHN0YXIgPSBmb3JjYXRzOjphc19mYWN0b3Ioc3RhcikpICU+JQ0KICAgICAgICAgICAgIG11dGF0ZShzdGFyID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoc3RhcixyZWNhdWRhY2lvbikpDQoNCiNGaWphbW9zIGVsIHRlbWEgcGFyYSBlbCByZXN0byBkZSBncsOhZmljb3MNCmdndGhlbXIoInNvbGFyaXplZCIpDQoNCmdncGxvdChzdGFyX2dyb3NzXzEwLCBhZXMoc3RhciwgcmVjYXVkYWNpb24sIGZpbGwgPSBzdGFyKSkgKyBnZW9tX2NvbCgpICsgY29vcmRfZmxpcCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQpsYWJzKHRpdGxlID0gIlRvcCAxMCBhY3RvcmVzL2FjdHJpY2VzIGNvbiBtw6FzIHJlY2F1ZGFjacOzbiIsDQogICAgc3VidGl0bGUgPSAiRW4gbWlsbG9uZXMgZGUgZMOzbGFyZXMiLA0KICAgIHggPSBOVUxMLCB5ID0gTlVMTCkrDQogIGdlb21fdGV4dChhZXMobGFiZWw9IHJlY2F1ZGFjaW9uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdD0gMC41KSwNCiAgICAgICAgICAgIGNvbG91ciA9ICJncmV5MzAiLCBzaXplID0gMykgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiWmlzc291MSIsIG4gPSAxMCwgdHlwZSA9ICJjb250aW51b3VzIikpDQoNCg0KDQpgYGANCg0KDQojIyBBY3RvcmVzIG1lam9yIHZhbG9yYWRvcyBlbiBpbWRiDQoNClBhcmEgaGFjZXIgZXN0byBoZSBjYWxjdWxhZG8gbGEgbWVkaWEgZGUgbGEgcHVudHVhY2nDs24gZGUgbGFzIHBlbMOtY3VsYXMgcXVlIGhhbiBoZWNobyBjYWRhIGFjdG9yKGhlIGVzY29naWRvIGFjdG9yZXMgcXVlIGhheWFuIGhlY2hvICoqbcOhcyBkZSA1IHBlbMOtY3VsYXMqKikuDQoNCmBgYHtyfQ0KI3ZhbW9zIGEgb2JzZXJ2YXIgcXXDqSBwYXNhIHNpIGVzY29nZW1vcyBhY3RvcmVzIHF1ZSBoYXlhbiBoZWNobyBtw6FzIGRlIDUgcGVsw61jdWxhcyBjb21vIHByb3RhZ29uaXN0YXMuDQoNCnN0YXJfc2NvcmVfNSA8LSBtb3ZpZXMgJT4lIGdyb3VwX2J5KHN0YXIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKE5OID0gbigpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihOTiA+IDUpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKG5vdGFfbWVkaWEgPSBtZWFuKHNjb3JlKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2Mobm90YV9tZWRpYSkpIA0KDQpEVDo6ZGF0YXRhYmxlKHN0YXJfc2NvcmVfNSkNCmBgYA0KDQrCoUJ1c2NhIGEgdHUgaW50w6lycHJldGUgZmF2b3JpdG8hDQoNCiMjIEFjdG9yZXMgY29uIE9zY2FyDQoNCmBgYHtyfQ0KI2FjdG9yZXMgY29uIG9zY2FyDQpvc2NhcnMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCJvc2NhcnMiLCAidGhlX29zY2FyX2F3YXJkLmNzdiIpKQ0KDQpvc2NhcnNfMSA8LSBvc2NhcnMgICU+JSBmaWx0ZXIoY2F0ZWdvcnkgJWluJSBjKCJBQ1RPUiIsICJBQ1RSRVNTIiwgIkFDVE9SIElOIEEgU1VQUE9SVElORyBST0xFIiwgIkFDVFJFU1MgSU4gQSBTVVBQT1JUSU5HIFJPTEUiLCAiQUNUT1IgSU4gQSBMRUFESU5HIFJPTEUiLCAiQUNUUkVTUyBJTiBBIExFQURJTkcgUk9MRSIpKSAlPiUgZmlsdGVyKHdpbm5lciA9PSBUUlVFKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShuYW1lKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUod2lucyA9IG4oKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgZGlzdGluY3QobmFtZSwua2VlcF9hbGwgPSBUUlVFKQ0KDQpvc2NfYWN0IDwtIGxlZnRfam9pbihtb3ZpZXMsIG9zY2Fyc18xLCBieSA9IGMoInN0YXIiID0gIm5hbWUiKSkNCg0Kb3NjX2FjdF91biA8LSBvc2NfYWN0ICU+JSBmaWx0ZXIoY29tcGxldGUuY2FzZXMoLikpICU+JSBkaXN0aW5jdChzdGFyLCAua2VlcF9hbGwgPSBUUlVFKQ0KDQojYWN0b3JlcyBjb24gb3NjYXINCg0KYWN0X29zYyA8LSBvc2NfYWN0X3VuICU+JSBzZWxlY3Qoc3Rhciwgd2lucyklPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKHdpbnMpKQ0KDQojYWN0b3JlcyBjb24gbcOhcyBkZSB1biBvc2Nhcg0KDQphY3RfbWFzX29zYyA8LSBhY3Rfb3NjICU+JSBzbGljZV9tYXgod2lucywgbiA9IDEwKSAjdXNhciBoZWFkKDEwKSBwYXJhIGxvcyAxMCBwcmltZXJvcyByZXN1bHRhZG9zDQoNCmxpYnJhcnkoRFQpDQoNCmRhdGF0YWJsZShhY3Rfb3NjKSAlPiUgZm9ybWF0U3R5bGUoDQogICd3aW5zJyx0YXJnZXQgPSAncm93JywNCiAgYmFja2dyb3VuZENvbG9yID0gc3R5bGVFcXVhbChjKDEsIDIsIDMpLCBjKCdraGFraScsICdsaWdodGJsdWUnLCAncGluaycpKQ0KKQ0KYGBgDQoNCmBgYHtyIGV2YWwgPSBUUlVFLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly9lbmZpbG1lLmNvbS9pbWcvY29udGVudC82N2FkYjA0ZGQyNmE5ZmQzN2EyYTI0YWYwMjZmM2U1YTczXzY3NV80ODkuanBnIikNCmBgYA0KDQojIyBSZXN1bHRhZG9zDQoNCkFob3JhIHZhbW9zIGEgY29tcHJvYmFyIHF1w6kgYWN0b3JlcyBlc3TDoW4gZW50cmUgbG9zIDMwIGNvbiBtw6FzIHJlY2F1ZGFjacOzbiwgbG9zIDMwIGNvbiBtZWpvciBub3RhIG1lZGlhIGRlIHN1cyBwZWzDrWN1bGFzIHkgYWRlbcOhcyB0aWVuZW4gdW4gT3NjYXIuDQoNCmBgYHtyfQ0KI1Jlc3VsdGFkb3MNCg0Kc3Rhcl9ncm9zc18zMCA8LSBzdGFyX2dyb3NzICU+JSBoZWFkKDMwKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocmFua19yZWMgPSBjKDE6MzApKQ0KDQpzdGFyX3Njb3JlXzMwIDwtIHN0YXJfc2NvcmVfNSAlPiUgaGVhZCgzMCkNCg0KYWN0b3JlcyA8LSBtZXJnZShtZXJnZSgNCiAgc3Rhcl9ncm9zc18zMCwNCiAgc3Rhcl9zY29yZV8zMCwgYWxsID0gVFJVRSksDQogIGFjdF9vc2MsIGFsbCA9IFRSVUUpDQoNCmFhIDwtIGFjdG9yZXMgJT4lIGZpbHRlcihjb21wbGV0ZS5jYXNlcyguKSkgJT4lIGFycmFuZ2UoZGVzYyhyZWNhdWRhY2lvbikpDQoNCmN1c3RvbUdyZWVuMCA9ICIjRGVGN0U5Ig0KDQpjdXN0b21HcmVlbiA9ICIjNzFDQTk3Ig0KDQphYSAlPiUgZm9ybWF0dGFibGUobGlzdCgNCiBub3RhX21lZGlhID0gZm9ybWF0dGVyKCJzcGFuIiwNCiAgICBzdHlsZSA9IHggfiBzdHlsZShjb2xvciA9IGlmZWxzZShyYW5rKC14KSA8PSAxLCAiYmx1ZSIsICJncmF5IikpLA0KICAgIHggfiBzcHJpbnRmKCIlLjJmIChyYW5rOiAlMDJkKSIsIHgsIHJhbmsoLXgpKSksDQogICBhcmVhKGNvbCA9IHJlY2F1ZGFjaW9uKSB+IG5vcm1hbGl6ZV9iYXIoInBpbmsiLCAwLjIpLA0KICBgcmFua19yZWNgPSBjb2xvcl90aWxlKGN1c3RvbUdyZWVuLCBjdXN0b21HcmVlbjApLA0KICAgd2lucyA9IGNvbG9yX3RpbGUoImtoYWtpIiwgImxpZ2h0Ymx1ZSIpKSkNCg0KYGBgDQoNCmBgYHtyIGV2YWwgPSBUUlVFLCBlY2hvID0gRkFMU0V9DQoNCnRvbSA8LSBnZ2RyYXcoKSArIGRyYXdfaW1hZ2UoImh0dHBzOi8vYWtucy1pbWFnZXMuZW9ubGluZS5jb20vZW9sX2ltYWdlcy9FbnRpcmVfU2l0ZS8yMDIwMDIxL3JzXzYwMHg2MDAtMjAwMTIxMTEzOTUwLTYwMC50b20taGFua3MuY3QuMDEyMTIwLmpwZz9maXQ9YXJvdW5kfDEwODA6MTA4MCZvdXRwdXQtcXVhbGl0eT05MCZjcm9wPTEwODA6MTA4MDtjZW50ZXIsdG9wIiwgc2NhbGUgPSAwLjkpDQpsZW8gPC0gZ2dkcmF3KCkgKyBkcmF3X2ltYWdlKCJodHRwczovL3d3dy5sYXZhbmd1YXJkaWEuY29tL2ZpbGVzL2NvbnRlbnRfaW1hZ2VfbW9iaWxlX2ZpbHRlci91cGxvYWRzLzIwMjAvMDEvMDkvNWZhOTAyNjc0YThmZC5qcGVnIiwgc2NhbGUgPSAwLjkpDQpjaHJpcyA8LSBnZ2RyYXcoKSArIGRyYXdfaW1hZ2UoImh0dHBzOi8vc3RhdGljLndpa2lhLm5vY29va2llLm5ldC90ZXJtaW5hdG9yL2ltYWdlcy80LzQ5L0NocmlzdGlhbl9CYWxlLmpwZy9yZXZpc2lvbi9sYXRlc3Qvc2NhbGUtdG8td2lkdGgtZG93bi8zNDA/Y2I9MjAxNTA3MTUxMDAzNDgmcGF0aC1wcmVmaXg9ZXMiLCBzY2FsZSA9IDAuOSkNCmJyYWQgPC0gZ2dkcmF3KCkgKyBkcmF3X2ltYWdlKCJodHRwczovL21lZGlhcy5mYXNoaW9ubmV0d29yay5jb20vaW1hZ2UvdXBsb2FkL3YxL21lZGlhcy9hYjRhMTBmNzY3OWVhMmMzODgxOWM4YzkwMDkwNGYyYjI5NDM3NDUuanBnIiwgc2NhbGUgPSAwLjkpDQoNCnBsb3RfZ3JpZCh0b20sIGxlbywgY2hyaXMsIGJyYWQpDQoNCmBgYA0KDQpUZW5lbW9zIGEgVG9tIEhhbmtzLCBMZW9uYXJkbyBEaUNhcHJpbywgQnJhZCBQaXR0IHkgYSBDaHJpc3RpYW4gQmFsZS4gU2llbmRvIFRvbSBIYW5rcyBlbCBxdWUgbcOhcyBkaW5lcm8gcmVjYXVkYSBkZSB0b2RvcyB5IGVsIHF1ZSBtw6FzIG9zY2FycyB0aWVuZSAoZGUgbG9zIGN1YXRybyksIGF1bnF1ZSBEaUNhcHJpbyBwYXJ0aWNpcGEgZW4gcGVsw61jdWxhcyBtZWpvciB2YWxvcmFkYXMuDQoNCg0KIyA0LiBEaXJlY3RvcmVzICB7LnRhYnNldCAudGFic2V0LXBpbGx9DQoNCiMjIERpcmVjdG9yZXMgcXVlIG3DoXMgcmVjdWFkYW4NCmBgYHtyfQ0KI0RpcmVjdG9yZXMgbcOhcyB0YXF1aWxsZXJvcw0KDQpkaXJfZ3Jvc3MgPC0gbW92aWVzICU+JSBncm91cF9ieShkaXJlY3RvcikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKHJlY2F1ZGFjaW9uID0gc3VtKGdyb3NzKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKHJlY2F1ZGFjaW9uKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHJlY2F1ZGFjaW9uID0gcmVjYXVkYWNpb24vMTAwMDAwMCkNCg0KRFQ6OmRhdGF0YWJsZShkaXJfZ3Jvc3MsIGNhcHRpb24gPSAnUmVjYXVkYWNpw7NuIGVuIG1pbGxvbmVzIGRlIGTDs2xhcmVzJykNCg0KYGBgDQoNCsKhRW5jdWVudHJhIGEgdHUgZGlyZWN0b3IgZmF2b3JpdG8hDQoNCmBgYHtyfQ0KZGlyX2dyb3NzXzEwIDwtIGRpcl9ncm9zcyAlPiUgaGVhZCgxMCkgJT4lIG11dGF0ZShkaXJlY3RvciA9IGZvcmNhdHM6OmFzX2ZhY3RvcihkaXJlY3RvcikpICU+JQ0KICAgICAgICAgICAgIG11dGF0ZShkaXJlY3RvciA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGRpcmVjdG9yLHJlY2F1ZGFjaW9uKSkNCg0KZ2dwbG90KGRpcl9ncm9zc18xMCwgYWVzKGRpcmVjdG9yLCByZWNhdWRhY2lvbiwgZmlsbCA9IGRpcmVjdG9yKSkgKyBnZW9tX2NvbCgpICsgY29vcmRfZmxpcCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQpsYWJzKHRpdGxlID0gIlRvcCAxMCBEaXJlY3RvcmVzIGNvbiBtw6FzIHJlY2F1ZGFjacOzbiIsDQogICAgc3VidGl0bGUgPSAiRW4gbWlsbG9uZXMgZGUgZMOzbGFyZXMiLA0KICAgIHggPSBOVUxMLCB5ID0gTlVMTCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPSByZWNhdWRhY2lvbiksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3Q9IDAuNSksDQogICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTMwIiwgc2l6ZSA9IDMpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlppc3NvdTEiLCBuID0gMTAsIHR5cGUgPSAiY29udGludW91cyIpKQ0KDQpgYGANCg0KIyMgRGlyZWN0b3JlcyBtZWpvciB2YWxvcmFkb3MgZW4gaW1kYg0KDQpFbiBlc3RlIGNhc28gaGUgaGVjaG8gY29tbyBjb24gbG9zIGFjdG9yZXMgeSBoZSBlc2NvZ2lkbyBzb2xvIGEgZGlyZWN0b3JlcyBjb24gbcOhcyBkZSA1IHBlbMOtY3VsYXMNCg0KYGBge3J9DQojcXVlIGhheWFuIGRpcmlnaWRvIG3DoXMgZGUgNSBwZWzDrWN1bGFzDQpkaXJfc2NvcmVfNSA8LSBtb3ZpZXMgJT4lIGdyb3VwX2J5KGRpcmVjdG9yKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShOTiA9IG4oKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoTk4gPiA1KSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShub3RhX21lZGlhID0gbWVhbihzY29yZSkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKG5vdGFfbWVkaWEpKSANCg0KRFQ6OmRhdGF0YWJsZShkaXJfc2NvcmVfNSkNCmBgYA0KDQojIyBEaXJlY3RvcmVzIGNvbiBPc2Nhcg0KDQpgYGB7cn0NCg0Kb3NjYXJzXzIgPC0gb3NjYXJzICAlPiUgZmlsdGVyKGNhdGVnb3J5ICVpbiUgYygiRElSRUNUSU5HIChDb21lZHkgUGljdHVyZSkiLCAiRElSRUNUSU5HIChEcmFtYXRpYyBQaWN0dXJlKSIsICJESVJFQ1RJTkciKSkgJT4lIGZpbHRlcih3aW5uZXIgPT0gVFJVRSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkobmFtZSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHdpbnMgPSBuKCkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgIGRpc3RpbmN0KG5hbWUsLmtlZXBfYWxsID0gVFJVRSkNCg0Kb3NjX2RpciA8LSBsZWZ0X2pvaW4obW92aWVzLCBvc2NhcnNfMiwgYnkgPSBjKCJkaXJlY3RvciIgPSAibmFtZSIpKQ0KDQpvc2NfZGlyX3VuIDwtIG9zY19kaXIgJT4lIGZpbHRlcihjb21wbGV0ZS5jYXNlcyguKSkgJT4lIGRpc3RpbmN0KGRpcmVjdG9yLCAua2VlcF9hbGwgPSBUUlVFKQ0KDQojZGlyZWN0b3JlcyBjb24gb3NjYXINCg0KZGlyX29zYyA8LSBvc2NfZGlyX3VuICU+JSBzZWxlY3QoZGlyZWN0b3IsIHdpbnMpJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyh3aW5zKSkNCg0KZGF0YXRhYmxlKGRpcl9vc2MpICU+JSBmb3JtYXRTdHlsZSgNCiAgJ3dpbnMnLHRhcmdldCA9ICdyb3cnLA0KICBiYWNrZ3JvdW5kQ29sb3IgPSBzdHlsZUVxdWFsKGMoMSwgMiwgMyksIGMoJ2toYWtpJywgJ2xpZ2h0Ymx1ZScsICdwaW5rJykpDQopDQpgYGANCg0KIyMgUmVzdWx0YWRvcw0KDQpgYGB7cn0NCg0KZGlyX2dyb3NzXzMwIDwtIGRpcl9ncm9zcyAlPiUgaGVhZCgzMCkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHJhbmtfcmVjID0gYygxOjMwKSkNCg0KZGlyX3Njb3JlXzMwIDwtIGRpcl9zY29yZV81ICU+JSBoZWFkKDMwKQ0KDQpkaXJlY3RvcmVzIDwtIG1lcmdlKG1lcmdlKA0KICBkaXJfZ3Jvc3NfMzAsDQogIGRpcl9zY29yZV8zMCwgYWxsID0gVFJVRSksDQogIGRpcl9vc2MsIGFsbCA9IFRSVUUpDQoNCmJiIDwtIGRpcmVjdG9yZXMgJT4lIGZpbHRlcihjb21wbGV0ZS5jYXNlcyguKSkgJT4lIGFycmFuZ2UoZGVzYyhyZWNhdWRhY2lvbikpDQoNCmJiICU+JSBmb3JtYXR0YWJsZShsaXN0KA0KIG5vdGFfbWVkaWEgPSBmb3JtYXR0ZXIoInNwYW4iLA0KICAgIHN0eWxlID0geCB+IHN0eWxlKGNvbG9yID0gaWZlbHNlKHJhbmsoLXgpIDw9IDEsICJibHVlIiwgImdyYXkiKSksDQogICAgeCB+IHNwcmludGYoIiUuMmYgKHJhbms6ICUwMmQpIiwgeCwgcmFuaygteCkpKSwNCiAgIGFyZWEoY29sID0gcmVjYXVkYWNpb24pIH4gbm9ybWFsaXplX2JhcigicGluayIsIDAuMiksDQogIGByYW5rX3JlY2A9IGNvbG9yX3RpbGUoY3VzdG9tR3JlZW4sIGN1c3RvbUdyZWVuMCksDQogICB3aW5zID0gY29sb3JfdGlsZSgia2hha2kiLCAibGlnaHRibHVlIikpKQ0KDQoNCmBgYA0KDQpgYGB7ciBldmFsID0gVFJVRSwgZWNobyA9IEZBTFNFfQ0KDQpzdGUgPC0gZ2dkcmF3KCkgKyBkcmF3X2ltYWdlKCJodHRwczovL2VzLndlYi5pbWcyLmFjc3RhLm5ldC9waWN0dXJlcy8xNi8wNS8xNy8xMS8zOS80NTM2MDkuanBnIiwgc2NhbGUgPSAwLjkpDQpwZXQgPC0gZ2dkcmF3KCkgKyBkcmF3X2ltYWdlKCJodHRwczovL20ubWVkaWEtYW1hem9uLmNvbS9pbWFnZXMvTS9NVjVCTVRZMU16UTNOakEyT1Y1Qk1sNUJhbkJuWGtGdFpUY3dOVEV4T1RBNU9BQEAuX1YxXy5qcGciLCBzY2FsZSA9IDAuOSkNCmphbSA8LSBnZ2RyYXcoKSArIGRyYXdfaW1hZ2UoImh0dHBzOi8vZW5jcnlwdGVkLXRibjAuZ3N0YXRpYy5jb20vaW1hZ2VzP3E9dGJuOkFOZDlHY1M1OS1qanBvRnEyeW4wWlVUUUhjTXFnWGd5bzJCWUJ5a2JxQSZ1c3FwPUNBVSIsIHNjYWxlID0gMC45KQ0KDQpwbG90X2dyaWQoc3RlLCBwZXQsIGphbSkNCg0KYGBgDQoNClBvZGVtb3MgdmVyIHF1ZSBsb3MgdHJlcyBkaXJlY3RvcmVzIHF1ZSBoYW4gZ2FuYWRvIHVuIE9zY2FyIHkgZXN0w6FuIGVuIGVsIHRvcCAzMCBkZSBsb3MgcXVlIG3DoXMgcmVjYXVkYW4geSBlbiBlbCBkZSBsYSBub3RhIG1lZGlhIGRlIHN1cyBwZWzDrWN1bGFzIHNvbiBTdGV2ZW4gU3BpZWxiZXJnLCBQZXRlciBKYWNrc29uIHkgSmFtZXMgQ2FtZXJvbi4gQSBwZXNhciBkZSB0ZW5lciBsYXMgIHBlbGljdWxhcyBwZW9yIHZhbG9yYWRhcyBkZSBtZWRpYSBkZSBsb3MgdHJlcyBkaXJlY3RvcmVzLCBTcGllbGJlcmcgZXMgZWwgZGlyZWN0b3IgcXVlIG3DoXMgcmVjYXVkYSBkZSB0b2RvcyB5IGVzIGVsIGRpcmVjdG9yIGNvbiBtw6FzIE9zY2FycyAoZW1wYXRhZG8gY29uIG90cm9zKS4gDQoNCiMgNS4gUHJvZHVjdG9yYXMgIHsudGFic2V0IC50YWJzZXQtcGlsbH0NCg0KIyMgUHJvZHVjdG9yYXMgY29uIG3DoXMgcmVjYXVkYWNpw7NuDQoNCmBgYHtyfQ0KcHJvZF9ncm9zcyA8LSBtb3ZpZXMgJT4lIGdyb3VwX2J5KGNvbXBhbnkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShyZWNhdWRhY2lvbiA9IHN1bShncm9zcykpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhyZWNhdWRhY2lvbikpICAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocmVjYXVkYWNpb24gPSByZWNhdWRhY2lvbi8xMDAwMDAwKQ0KDQpEVDo6ZGF0YXRhYmxlKHByb2RfZ3Jvc3MpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KcHJvZF9ncm9zc18xMCA8LSBwcm9kX2dyb3NzICU+JSBoZWFkKDEwKSAlPiUgbXV0YXRlKGNvbXBhbnkgPSBmb3JjYXRzOjphc19mYWN0b3IoY29tcGFueSkpICU+JQ0KICAgICAgICAgICAgIG11dGF0ZShjb21wYW55ID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIoY29tcGFueSxyZWNhdWRhY2lvbikpDQoNCmdncGxvdChwcm9kX2dyb3NzXzEwLCBhZXMoY29tcGFueSwgcmVjYXVkYWNpb24sIGZpbGwgPSBjb21wYW55KSkgKyBnZW9tX2NvbCgpICsgY29vcmRfZmxpcCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQpsYWJzKHRpdGxlID0gIlRvcCAxMCBQcm9kdWN0b3JhcyBjb24gbcOhcyByZWNhdWRhY2nDs24iLA0KICAgIHN1YnRpdGxlID0gIkVuIG1pbGxvbmVzIGRlIGTDs2xhcmVzIiwNCiAgICB4ID0gTlVMTCwgeSA9IE5VTEwpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPSByZWNhdWRhY2lvbiksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3Q9IDAuNSksDQogICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTMwIiwgc2l6ZSA9IDMpICsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1zY2FsZXM6OmNvbW1hKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJaaXNzb3UxIiwgbiA9IDEwLCB0eXBlID0gImNvbnRpbnVvdXMiKSkNCg0KYGBgDQoNCjxGT05UIENPTE9SPSJPcmFuZ2UiPioqNSBNYWpvcnMqKjwvRk9OVD4NCg0KRW4gbGEgaW5kdXRyaWEgZGVsIGNpbmUgaG95IGVuIGTDrWEgc2UgcHVlZGUgZGVzdGFjYXIgZWwgcGFwZWwgZGUgNSBwcm9kdWN0b3JhcyBxdWUgbWFuZWphbiBncmFuIHBhcnRlIGRlbCBtZXJjYWRvLCBzb24gY29ub2NpZGFzIGNvbW8gbGFzIDUgbWFqb3JzIHkgYSBlc3RhcyBwZXJ0ZW5lY2VuIG11Y2hhcyBkZSBsYXMgcHJvZHVjdG9yYXMgbcOhcyBwZXF1ZcOxYXMuDQoNCmBgYHtyfQ0KDQp0b3RfZ3Jvc3MgPC0gbW92aWVzICU+JSBtdXRhdGUodG90YWwgPSBzdW0oZ3Jvc3MpKSN0b3RhbCBkZSBsYSByZWNhdWRhY2nDs24gZGUgbGFzIHBlbMOtY3VsYXMNCg0KY29sdW1iaWFfZ3Jvc3MgPC0gdG90X2dyb3NzICAlPiUgZmlsdGVyKGNvbXBhbnkgJWluJSBjKCJDb2x1bWJpYSBQaWN0dXJlcyIsICJDb2x1bWJpYSBQaWN0dXJlcyBDb3Jwb3JhdGlvbiIsICJDb2x1bWJpYSBQaWN0dXJlcyBGaWxtIFByb2R1Y3Rpb24gQXNpYSIsICJDb2x1bWJpYSBQaWN0dXJlcyBJbmR1c3RyaWVzIiwgIkNvbHVtYmlhIFRyaVN0YXIgSG9tZSBWaWRlbyIgLCJUcmlTdGFyIFRlbGV2aXNpb24iLCAiVHJpU3RhciBQaWN0dXJlcyIsICJDb2x1bWJpYSBUcmlTdGFyIEhvbWUgVmlkZW8iLCAiU29ueSBQaWN0dXJlcyBDbGFzc2ljcyIsICJTb255IFBpY3R1cmVzIEVudGVydGFpbm1lbnQgKFNQRSkiLCAiQWZmaXJtIEZpbG1zIiwgIlNjcmVlbiBHZW1zIiwgIlN0YWdlIDYgRmlsbXMiLCAiRGVzdGluYXRpb24gRmlsbXMiKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHJlYyA9IHN1bShncm9zcykpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihjb21wYW55ID09ICJDb2x1bWJpYSBQaWN0dXJlcyIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3RpbmN0KGNvbXBhbnksIC5rZWVwX2FsbCA9IFRSVUUpDQoNCndhcm5lcl9ncm9zcyA8LSB0b3RfZ3Jvc3MgJT4lIGZpbHRlcihjb21wYW55ICVpbiUgYyggIldhcm5lciBCcm9zLiIsICJXYXJuZXIgQnJvcy4gQW5pbWF0aW9uIiwgIldhcm5lciBCcm9zLiBEaWdpdGFsIERpc3RyaWJ1dGlvbiIsICJXYXJuZXIgQnJvcy4gRmFtaWx5IEVudGVydGFpbm1lbnQiLCAiV2FybmVyIEJyb3MuIFBpY3R1cmVzIiwgIldhcm5lciBJbmRlcGVuZGVudCBQaWN0dXJlcyAoV0lQKSIsICJOZXcgTGluZSBDaW5lbWEiLCAiREMgRW50ZXJ0YWlubWVudCIsICJDYXN0bGUgUm9jayBFbnRlcnRhaW5tZW50IiwgIkhCTyBGaWxtcyIsICJIb21lIEJveCBPZmZpY2UgKEhCTykiLCAiU3B5Z2xhc3MgRW50ZXJ0YWlubWVudCIsICJUdXJuZXIgUGljdHVyZXMgKEkpIikpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShyZWMgPSBzdW0oZ3Jvc3MpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoY29tcGFueSA9PSAiV2FybmVyIEJyb3MuIikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgZGlzdGluY3QoY29tcGFueSwgLmtlZXBfYWxsID0gVFJVRSkNCg0KDQp1bml2ZXJzYWxfZ3Jvc3MgPC0gdG90X2dyb3NzICU+JSBmaWx0ZXIoY29tcGFueSAlaW4lIGMoICJVbml2ZXJzYWwgUGljdHVyZXMiLCAiVW5pdmVyc2FsIFBpY3R1cmVzIEludGVybmF0aW9uYWwgKFVQSSkiLCAiVW5pdmVyc2FsIENpdHkgU3R1ZGlvcyIsICJOQkMgUHJvZHVjdGlvbnMiLCAiTmF0aW9uYWwgQnJvYWRjYXN0aW5nIENvbXBhbnkgKE5CQykiLCAiRm9jdXMgRmVhdHVyZXMiLCAiV29ya2luZyBUaXRsZSBGaWxtcyIsICJEcmVhbVdvcmtzIiwgIkRyZWFtV29ya3MgQW5pbWF0aW9uIiwgIklsbHVtaW5hdGlvbiBFbnRlcnRhaW5tZW50IiwgIkFtYmxpbiBQYXJ0bmVycyIsICJDYXJuaXZhbCBGaWxtICYgVGVsZXZpc2lvbiIsICJXVDIgUHJvZHVjdGlvbnMiKSklPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocmVjID0gc3VtKGdyb3NzKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGNvbXBhbnkgPT0gIlVuaXZlcnNhbCBQaWN0dXJlcyIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3RpbmN0KGNvbXBhbnksIC5rZWVwX2FsbCA9IFRSVUUpDQoNCnBhcmFtb3VudF9ncm9zcyA8LSB0b3RfZ3Jvc3MgJT4lIGZpbHRlcihjb21wYW55ICVpbiUgYyggIlBhcmFtb3VudCBQaWN0dXJlcyIsICJQYXJhbW91bnQgQ2xhc3NpY3MiLCAiUGFyYW1vdW50IEFuaW1hdGlvbiIsICJQYXJhbW91bnQgVmFudGFnZSIsICJWaWFjb20xOCBNb3Rpb24gUGljdHVyZXMiLCAiQ0JTIEVudGVydGFpbm1lbnQgUHJvZHVjdGlvbiIsICJDQlMgRmlsbXMiLCAiTWlyYW1heCIsICJCRVQgUGljdHVyZXMiLCAiQ29tZWR5IENlbnRyYWwgRmlsbXMiLCAiTVRWIEZpbG1zIiwgIk5pY2tlbG9kZW9uIE1vdmllcyIpKSU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShyZWMgPSBzdW0oZ3Jvc3MpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoY29tcGFueSA9PSAiUGFyYW1vdW50IFBpY3R1cmVzIikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgZGlzdGluY3QoY29tcGFueSwgLmtlZXBfYWxsID0gVFJVRSkNCg0KDQoNCmRpc25leV8yMHRoX2dyb3NzIDwtIHRvdF9ncm9zcyAlPiUgZmlsdGVyKGNvbXBhbnkgJWluJSBjKCAiV2FsdCBEaXNuZXkgUGljdHVyZXMiLCAiV2FsdCBEaXNuZXkgRmVhdHVyZSBBbmltYXRpb24gRmxvcmlkYSIsICJXYWx0IERpc25leSBGZWF0dXJlIEFuaW1hdGlvbiIsICJXYWx0IERpc25leSBBbmltYXRpb24gU3R1ZGlvcyIsICJEaXNuZXl0b29uIFN0dWRpb3MiLCAiRGlzbmV5IFRlbGV2aXNpb24gQW5pbWF0aW9uIiAsICIyMHRoIENlbnR1cnkgRm94IiwgIlR3ZW50aWV0aCBDZW50dXJ5IEZveCBGaWxtIENvcnBvcmF0aW9uIiwgIlR3ZW50aWV0aCBDZW50dXJ5IEZveCBBbmltYXRpb24iLCAiRm94IFNlYXJjaGxpZ2h0IFBpY3R1cmVzIiwgIkx1Y2FzZmlsbSIsICJMdWNhc2ZpbG0gQW5pbWF0aW9uIiwgIk1hcnZlbCBTdHVkaW9zIiwgIk1hcnZlbCBFbnRlcnRhaW5tZW50IiwgIk1hcnZlbCBFbnRlcnByaXNlcyIsICJCbHVlIFNreSBTdHVkaW9zIiwgIlBpeGFyIEFuaW1hdGlvbiBTdHVkaW9zIiwgIiIsICIiKSklPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUocmVjID0gc3VtKGdyb3NzKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGNvbXBhbnkgPT0gIldhbHQgRGlzbmV5IFBpY3R1cmVzIikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgZGlzdGluY3QoY29tcGFueSwgLmtlZXBfYWxsID0gVFJVRSkNCg0KDQpwcm9kIDwtIHJiaW5kKGNvbHVtYmlhX2dyb3NzLCB3YXJuZXJfZ3Jvc3MsIHVuaXZlcnNhbF9ncm9zcywgcGFyYW1vdW50X2dyb3NzLCBkaXNuZXlfMjB0aF9ncm9zcykNCg0KDQpwcm9kXzEgPC0gcHJvZCAlPiUgc2VsZWN0KGNvbXBhbnkscmVjLCB0b3RhbCkgJT4lIGFycmFuZ2UoZGVzYyhyZWMpKSAlPiUgbXV0YXRlKHBvcmMgPSByZWMvdG90YWwqMTAwKSAlPiUgYWRkX3Jvdyhjb21wYW55ID0gIk90cm9zIiwgcG9yYyA9IDM3LjA1MDMzKSU+JSByZWxvY2F0ZSh0b3RhbCwgLmFmdGVyID0gcG9yYykNCg0KcHJvZF8xIDwtIHByb2RfMSAlPiUNCiAgYXJyYW5nZShkZXNjKGNvbXBhbnkpKSAlPiUNCiBtdXRhdGUobGFiLnlwb3MgPSBjdW1zdW0ocG9yYykgLSAwLjUqcG9yYykNCg0KDQpwMiA8LWdncGxvdChwcm9kXzEsIGFlcyh4ID0gIiIsIHkgPSBwb3JjLCBmaWxsID0gY29tcGFueSkpICsNCiAgZ2VvbV9iYXIod2lkdGggPSAxLCBzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAid2hpdGUiKSArDQogIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQgPSAwKSsNCiAgZ2VvbV90ZXh0KGFlcyh5ID0gbGFiLnlwb3MsIGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KHBvcmMvMTAwKSksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDUuNSkrDQogdGhlbWVfdm9pZCgpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIkZhbnRhc3RpY0ZveDEiLCBuID0gNiwgdHlwZSA9ICJjb250aW51b3VzIikpDQoNCmdnZHJhdyhwMikgKyBkcmF3X2ltYWdlKCJodHRwczovL3d3dy5lY3VyZWQuY3UvaW1hZ2VzLzkvOWQvQ29sdW1iaWFfcGljdHVyZXMuanBnIix4PSAwLjI5LCB5ID0gMC43NSwgd2lkdGggPSAwLjEsIGhlaWdodCA9IDAuMSkgKyBkcmF3X2ltYWdlKCJodHRwczovL3d3dy5jaW5lbWFzY29taWNzLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxOS8xMS9XYXJuZXJNZWRpYV9XYXJuZXJfQnJvcy5qcGciLHg9IDAuNDcsIHkgPSAwLjc1LCB3aWR0aCA9IDAuMSwgaGVpZ2h0ID0gMC4xKSArIGRyYXdfaW1hZ2UoImh0dHBzOi8vMS5icC5ibG9nc3BvdC5jb20vLS1HaDVkWWFoSWNvL1hJTUptWW1XdzZJL0FBQUFBQUFBTFJJL2ZYcnZlNlpQbHFRV0dwV1JKOWVDaXA2S0hPNE54Zl9TZ0NMY0JHQXMvczE2MDAvZGlzbmV5X3BvY2Fob250YXMucG5nIix4PSAwLjYzLCB5ID0gMC40OCwgd2lkdGggPSAwLjEsIGhlaWdodCA9IDAuMSkgKyBkcmF3X2ltYWdlKCJodHRwczovL3N0YXRpYy53aWtpYS5ub2Nvb2tpZS5uZXQvZGlzbmV5eXBpeGFyL2ltYWdlcy85Lzk1L1VuaXZlcnNhbF9TdHVkaW9zLmpwZy9yZXZpc2lvbi9sYXRlc3Qvc2NhbGUtdG8td2lkdGgtZG93bi8zNDA/Y2I9MjAxODA5MjAxNzUzMDEmcGF0aC1wcmVmaXg9ZXMiLHg9IDAuNTQsIHkgPSAwLjIsIHdpZHRoID0gMC4xLCBoZWlnaHQgPSAwLjEpICsgZHJhd19pbWFnZSgiaHR0cHM6Ly93d3cuY3JlYXRpdm9zb25saW5lLm9yZy9ibG9nL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE1LzA4L3BhcmFtb3VudC1tYWplc3RpYy1tb3VudGFpbi1sb2dvLmpwZyIseD0gMC4zNiwgeSA9IDAuMTMsIHdpZHRoID0gMC4xLCBoZWlnaHQgPSAwLjEpDQoNCmBgYA0KDQpWZW1vcyBxdWUgV2FsdCBEaXNuZXkgUGljdHVyZXMsIHF1ZSBlbXBlesOzIGNvbW8gdW5hIHByb2R1Y3RvcmEgZGUgYW5pbWFjacOzbiwgaG95IGVuIGTDrWEgaGEgY29uc2VndWlkbyBkaXZlcnNpZmljYXIgY29uc29saWTDoW5kb3NlIGNvbW8gbGEgcHJvZHVjdG9yYSBtw6FzIHJlbnRhYmxlLg0KDQojIyBQcm9kdWN0b3JhcyB5IGxhIG5vdGEgbWVkaWEgZGUgc3VzIHBlbGljdWxhcyBlbiBpbWRiDQoNClByb2R1Y3RvcmFzIGNvbiBtw6FzIGRlIDUgcGVsw61jdWxhcw0KYGBge3J9DQojbcOhcyBkZSA1IHBlbGljdWxhcw0KcHJvZF9zY29yZV81IDwtIG1vdmllcyAlPiUgZ3JvdXBfYnkoY29tcGFueSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoTk4gPSBuKCkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKE5OID4gNSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2Uobm90YV9tZWRpYSA9IG1lYW4oc2NvcmUpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhub3RhX21lZGlhKSkNCg0KDQpEVDo6ZGF0YXRhYmxlKHByb2Rfc2NvcmVfNSkNCmBgYA0KDQojIyBQcm9kdWN0b3JhcyB5IG9zY2Fycw0KDQpgYGB7cn0NCm9zY2Fyc18zIDwtIG9zY2FycyAlPiUgZmlsdGVyKHdpbm5lciA9PSBUUlVFLCBmaWxtICE9ICIiKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShmaWxtKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUod2lucyA9IG4oKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgZGlzdGluY3QoZmlsbSwgLmtlZXBfYWxsID0gVFJVRSkNCg0KDQpvc2NfcHJvZCA8LSBsZWZ0X2pvaW4obW92aWVzLCBvc2NhcnNfMywgYnkgPSBjKCJuYW1lIiA9ICJmaWxtIikpDQoNCm9zY19wcm9kX3VuIDwtIG9zY19wcm9kICU+JSBmaWx0ZXIoY29tcGxldGUuY2FzZXMoLikpICU+JSBkaXN0aW5jdChuYW1lLCAua2VlcF9hbGwgPSBUUlVFKQ0KDQojcHJvZHVjdG9yYXMgY29uIG3DoXMgb3NjYXJzDQpwcm9kX29zYyA8LSBvc2NfcHJvZF91biAlPiUgZ3JvdXBfYnkoY29tcGFueSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHRvdF93aW5zID0gc3VtKHdpbnMpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0aW5jdChjb21wYW55LCAua2VlcF9hbGwgPSBUUlVFKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoY29tcGFueSwgdG90X3dpbnMpJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKHRvdF93aW5zKSkNCg0KcHJvZF9vc2NfMTAgPC0gcHJvZF9vc2MgJT4lIGhlYWQoMTApDQoNCmdncGxvdChwcm9kX29zY18xMCwgYWVzKGZhY3Rvcihjb21wYW55LGxldmVscyA9IGNvbXBhbnkpLCB0b3Rfd2lucywgZmlsbCA9IGNvbXBhbnkpKSArIGdlb21fY29sKCkgKyBjb29yZF9mbGlwKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD0gdG90X3dpbnMgLGhqdXN0PS0uMDMpLHNpemU9NCkgKw0KbGFicyh0aXRsZSA9ICJQcm9kdWN0b3JhcyBjb24gbcOhcyBPc2NhcnMiLA0KICAgIHN1YnRpdGxlID0gIlRvZGFzIGxhcyBjYXRlZ29yw61hcyIsDQogICAgeCA9IE5VTEwgLCB5ID0gIm7Dum1lcm8gZGUgT3NjYXJzIikgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiWmlzc291MSIsIG4gPSAxMCwgdHlwZSA9ICJjb250aW51b3VzIikpDQoNCmBgYA0KDQo8Rk9OVCBDT0xPUj0iT3JhbmdlIj4qKlByb2R1Y3RvcmFzIGNvbiBtw6FzIG9zY2FycyBhIG1lam9yIHBlbMOtY3VsYSoqPC9GT05UPg0KDQoodGFtYmllbiBtZWpvciBwcm9kdWNjaW9uLCBtZWpvciBwZWxpY3VsYSBleHRyYW5qZXJhLCBtZWpvciBkb2N1bWVudGFsIHkgbWVqb3IgYHBlbGljVWxhIGRlIGFuaW1hY2lvbikNCg0KYGBge3J9DQoNCm9zY2Fyc180IDwtIG9zY2FycyAlPiUgZmlsdGVyKHdpbm5lciA9PSBUUlVFLCBmaWxtICE9ICIiLCBjYXRlZ29yeSAlaW4lIGMoIk9VVFNUQU5ESU5HIFBJQ1RVUkUiLCAiVU5JUVVFIEFORCBBUlRJU1RJQyBQSUNUVVJFIiwgIk9VVFNUQU5ESU5HIFBST0RVQ1RJT04iLCAiT1VUU1RBTkRJTkcgTU9USU9OIFBJQ1RVUkUiLCAiRE9DVU1FTlRBUlkiLCAiRE9DVU1FTlRBUlkgKEZlYXR1cmUpIiwgIkJFU1QgTU9USU9OIFBJQ1RVUkUiLCAiU1BFQ0lBTCBGT1JFSUdOIExBTkdVQUdFIEZJTE0gQVdBUkQiLCAiSE9OT1JBUlkgRk9SRUlHTiBMQU5HVUFHRSBGSUxNIEFXQVJEIiwgIkZPUkVJR04gTEFOR1VBR0UgRklMTSIsICJCRVNUIFBJQ1RVUkUiLCAiQU5JTUFURUQgRkVBVFVSRSBGSUxNIiwgIklOVEVSTkFUSU9OQUwgRkVBVFVSRSBGSUxNIikpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGZpbG0pICU+JQ0KICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZSh3aW5zID0gbigpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICBkaXN0aW5jdChmaWxtLCAua2VlcF9hbGwgPSBUUlVFKQ0KDQoNCm9zY19wcm9kXzEgPC0gbGVmdF9qb2luKG1vdmllcywgb3NjYXJzXzQsIGJ5ID0gYygibmFtZSIgPSAiZmlsbSIpKQ0KDQpvc2NfcHJvZF9kb3MgPC0gb3NjX3Byb2RfMSAlPiUgZmlsdGVyKGNvbXBsZXRlLmNhc2VzKC4pKSAlPiUgZGlzdGluY3QobmFtZSwgLmtlZXBfYWxsID0gVFJVRSkNCg0KcHJvZF9vc2NfcGVsaSA8LSBvc2NfcHJvZF9kb3MgJT4lIGdyb3VwX2J5KGNvbXBhbnkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZSh0b3Rfd2lucyA9IHN1bSh3aW5zKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzdGluY3QoY29tcGFueSwgLmtlZXBfYWxsID0gVFJVRSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGNvbXBhbnksIHRvdF93aW5zKSU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyh0b3Rfd2lucykpIA0KDQoNCmRhdGF0YWJsZShwcm9kX29zY19wZWxpKSAlPiUgZm9ybWF0U3R5bGUoDQogICd0b3Rfd2lucycsdGFyZ2V0ID0gJ3JvdycsDQogIGJhY2tncm91bmRDb2xvciA9IHN0eWxlRXF1YWwoYygxLCAyLCAzLCA1LCA2KSwgYygna2hha2knLCAnbGlnaHRibHVlJywgJ3BpbmsnLCAnb3JhbmdlJywgJ3BhbGVncmVlbicpKQ0KKQ0KYGBgDQoNCiMjIFJlc3VsdGFkb3MNCg0KVmFtb3MgYSBjb2dlciBsYXMgcHJvZHVjdG9yYXMgY29uIG9zY2FyIGEgbWVqb3IgcGVsw61jdWxhLg0KYGBge3J9DQpwcm9kX2dyb3NzXzMwIDwtIHByb2RfZ3Jvc3MgJT4lIGhlYWQoMzApICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShyYW5rX3JlYyA9IGMoMTozMCkpDQoNCnByb2Rfc2NvcmVfMzAgPC0gcHJvZF9zY29yZV81ICU+JSBoZWFkKDMwKQ0KDQoNCnByb2R1Y3RvcmFzXzEgPC0gbWVyZ2UobWVyZ2UoDQogIHByb2RfZ3Jvc3NfMzAsDQogIHByb2Rfc2NvcmVfMzAsIGFsbCA9IFRSVUUpLA0KICBwcm9kX29zY19wZWxpLCBhbGwgPSBUUlVFKQ0KDQpoaCA8LSBwcm9kdWN0b3Jhc18xICU+JSBmaWx0ZXIoY29tcGxldGUuY2FzZXMoLikpICU+JSBhcnJhbmdlKGRlc2ModG90X3dpbnMpKQ0KDQpoaCAlPiUgZm9ybWF0dGFibGUobGlzdCgNCiBub3RhX21lZGlhID0gZm9ybWF0dGVyKCJzcGFuIiwNCiAgICBzdHlsZSA9IHggfiBzdHlsZShjb2xvciA9IGlmZWxzZShyYW5rKC14KSA8PSAxLCAiYmx1ZSIsICJncmF5IikpLA0KICAgIHggfiBzcHJpbnRmKCIlLjJmIChyYW5rOiAlMDJkKSIsIHgsIHJhbmsoLXgpKSksDQogICBhcmVhKGNvbCA9IHJlY2F1ZGFjaW9uKSB+IG5vcm1hbGl6ZV9iYXIoInBpbmsiLCAwLjIpLA0KICBgcmFua19yZWNgPSBjb2xvcl90aWxlKGN1c3RvbUdyZWVuLCBjdXN0b21HcmVlbjApLA0KICAgdG90X3dpbnMgPSBjb2xvcl90aWxlKCJraGFraSIsICJvcmFuZ2UiKSkpDQoNCmBgYA0KDQpgYGB7ciBldmFsID0gVFJVRSwgZWNobyA9IEZBTFNFfQ0KDQpwaXggPC0gZ2dkcmF3KCkgKyBkcmF3X2ltYWdlKCJodHRwczovL2kwLndwLmNvbS90aGVkaXNpbnNpZGVyLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAyMC8wNi9pbWdfNjg0MS5qcGc/Zml0PTEyODAlMkM3MjAmc3NsPTEiLCBzY2FsZSA9IDAuOSkNCmRyZSA8LSBnZ2RyYXcoKSArIGRyYXdfaW1hZ2UoImh0dHBzOi8vZ3JhZmZpY2EuaW5mby93cC1jb250ZW50L3VwbG9hZHMvMjAxNS8wNC9kcmVhbXdvcmtzbG9nbzEucG5nIiwgc2NhbGUgPSAwLjkpDQoNCnBsb3RfZ3JpZChwaXgsIGRyZSkNCg0KYGBgDQoNCkN1cmlvc2FtZW50ZSB2ZW1vcyBxdWUgbGFzIGRvcyDDum5pY2FzIHByb2R1Y3RvcmFzIGVuIGVsIHRvcCBkZSByZWNhdWRhY2nDs24sIG5vdGEgbWVkaWEgZGUgc3VzIHBlbMOtY3VsYXMgeSBxdWUgaGFuIGdhbmFkbyB1biBPc2NhciBzb24gYW1iYXMgZGUgYW5pbWFjacOzbjogUGl4YXIgQW5pbWF0aW9uIFN0dWRpb3MgeSBEcmVhbVdvcmtzIEFuaW1hdGlvbi4gU2llbmRvIFBpeGFyIGxhIHF1ZSBtZWpvciBub3RhIG1lZGlhIHRpZW5lIHkgbcOhcyBPc2NhcnMsIGF1bnF1ZSBtZW5vcyByZWNhdWRhY2nDs24gcXVlIERyZWFtd29ya3MgQW5pbWF0aW9uLg0KDQojIDYuIENvbXBhcmFjaW9uZXMgIHsudGFic2V0IC50YWJzZXQtcGlsbH0NCg0KIyMgUGVsaWN1bGFzIGNvbiBhY3RvciwgZGlyZWN0b3IgeSBwcm9kdWN0b3JhIG3DoXMgcmVudGFibGVzDQoNClBhcmEgZXN0YSBjb21wYXJhY2nDs24gdmFtb3MgYSBjb2dlciBhIGxhcyAqKjEwIGVzdHJlbGxhcywgbG9zIDEwIGRpcmVjdG9yZXMgeSBsYXMgMTAgcHJvZHVjdG9yYXMgcXVlIG3DoXMgcmVjYXVkYW4qKiBwYXJhIHZlciBxdcOpIHBlbGljdWxhcyBoYW4gaGVjaG8geSBzaSBlc3RhcyBoYW4gdGVuaWRvIGVsIMOpeGl0byBjb21lcmNpYWwgcXVlIHNlIGVzcGVyYSBkZSBlbGxhcy4NCg0KYGBge3J9DQojZmlsdHJhbmRvIFRPUCAxMCBhY3RvcmVzLCBkaXIsIHkgcHJvZA0KDQpwZWxpc19ncm9zcyA8LSBtb3ZpZXMgJT4lIGZpbHRlcihzdGFyICVpbiUgYygiVG9tIEhhbmtzIiwgIlRvbSBDcnVpc2UiLCAiUm9iZXJ0IERvd25leSBKci4iLCAiV2lsbCBTbWl0aCIsICJKb2hubnkgRGVwcCIsICJBZGFtIFNhbmRsZXIiLCAiRGFuaWVsIFJhZGNsaWZmZSIsICJCZW4gU3RpbGxlciIsICJMZW9uYXJkbyBEaUNhcHJpbyIsICJKaW0gQ2FycmV5IikpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoZGlyZWN0b3IgJWluJSBjKCJTdGV2ZW4gU3BpZWxiZXJnIiwgIk1pY2hhZWwgQmF5IiwgIlBldGVyIEphY2tzb24iLCAiSmFtZXMgQ2FtZXJvbiIsICJDaHJpc3RvcGhlciBOb2xhbiIsICJUaW0gQnVydG9uIiwgIlJvYmVydCBaZW1lY2tpcyIsICJDaHJpcyBDb2x1bWJ1cyIsICJSb24gSG93YXJkIiwgIkouSi4gQWJyYW1zIikpJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihjb21wYW55ICVpbiUgYygiV2FybmVyIEJyb3MuIiwgIlVuaXZlcnNhbCBQaWN0dXJlcyIsICJQYXJhbW91bnQgUGljdHVyZXMiLCAiVHdlbnRpZXRoIENlbnR1cnkgRm94IEZpbG0gQ29ycG9yYXRpb24iLCAiV2FsdCBEaXNuZXkgUGljdHVyZXMiLCAiQ29sdW1iaWEgUGljdHVyZXMiLCAiTmV3IExpbmUgQ2luZW1hIiwgIkNvbHVtYmlhIFBpY3R1cmVzIENvcnBvcmF0aW9uIiwgIlRvdWNoc3RvbmUgUGljdHVyZXMiLCAiRHJlYW1Xb3JrcyIpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKGdyb3NzKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY3RfZGlyX3Byb2QgPSAic2kiKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGdyb3NzID0gZ3Jvc3MvMTAwMDAwMCkNCg0KDQpwZWxpc19ncm9zcyA8LSBwZWxpc19ncm9zcyAlPiUgbXV0YXRlKG5hbWUgPSBmb3JjYXRzOjphc19mYWN0b3IobmFtZSkpICU+JQ0KICAgICAgICAgICAgIG11dGF0ZShuYW1lID0gZm9yY2F0czo6ZmN0X3Jlb3JkZXIobmFtZSxncm9zcykpDQoNCmdncGxvdChwZWxpc19ncm9zcywgYWVzKG5hbWUsIGdyb3NzLCBmaWxsID0gbmFtZSkpICsgZ2VvbV9jb2woKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KbGFicyhzdWJ0aXRsZSA9ICJSZWNhdWRhY2nDs24gZW4gbWlsbG9uZXMgZGUgZMOzbGFyZXMiLA0KICAgIHggPSBOVUxMLCB5ID0gTlVMTCkrDQogIGdlb21fdGV4dChhZXMobGFiZWw9IGdyb3NzKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdD0gMC41KSwNCiAgICAgICAgICAgIGNvbG91ciA9ICJncmV5MzAiLCBzaXplID0gMykgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiWmlzc291MSIsIG4gPSAyNywgdHlwZSA9ICJjb250aW51b3VzIikpDQoNCmBgYA0KDQo8Rk9OVCBDT0xPUj0iT3JhbmdlIj4qKkNvbXBhcmFjacOzbiBjb24gbGFzIHBlbGljdWxhcyBxdWUgbcOhcyBoYW4gcmVjYXVkYWRvKio8L0ZPTlQ+DQoNCkNvbXBhcmFtb3Mgc2kgbGEgZsOzcm11bGEgZGlyZWN0b3IgKyBhY3RvciArIHByb2R1Y3RvcmEgcmVudGFibGVzIGRlIHZlcmRhZCBjcmVhIHBlbMOtY3VsYXMgcmVudGFibGVzLiBDb21wYXJhbW9zIGNvbiBlbCB0b3AgZGUgcGVsaWN1bGFzIGNvbiBtw6FzIHJlY2F1ZGFjacOzbiAoZGVzZGUgMTk4NiB5IGVuIGxhIGxpc3RhKS4NCmBgYHtyfQ0KcGVsaXNfbWF4X2dyb3NzIDwtIG1vdmllcyAlPiUgYXJyYW5nZShkZXNjKGdyb3NzKSkgJT4lIGhlYWQoNTApICU+JSBtdXRhdGUoYWN0X2Rpcl9wcm9kID0gInRvcF81MCIpJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShncm9zcyA9IGdyb3NzLzEwMDAwMDApDQoNCnBlbGlzX3JlYyA8LSB1bmlvbihwZWxpc19ncm9zcywgcGVsaXNfbWF4X2dyb3NzKQ0KDQojIHBlbGlzX3JlYyA8LSBwZWxpc19yZWNbLWMoMzApLCBdDQoNCnBlbGlzX3JlY18xIDwtIHBlbGlzX3JlYyAlPiUgYXJyYW5nZShkZXNjKGdyb3NzKSkgJT4lIGhlYWQoNTMpDQoNCnBlbGlzX3JlY18yIDwtIHBlbGlzX3JlY18xWy1jKDQsIDQ3LCA1MyksIF0NCg0KcGVsaXNfcmVjXzIgPC0gcGVsaXNfcmVjXzIgJT4lIG11dGF0ZShuYW1lID0gZm9yY2F0czo6YXNfZmFjdG9yKG5hbWUpKSAlPiUNCiAgICAgICAgICAgICBtdXRhdGUobmFtZSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKG5hbWUsZ3Jvc3MpKQ0KDQoNCg0KZ2dwbG90KHBlbGlzX3JlY18yLCBhZXMobmFtZSwgZ3Jvc3MsIGZpbGwgPSBhY3RfZGlyX3Byb2QpKSArIGdlb21fY29sKCkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXNjYWxlczo6Y29tbWEpICsgY29vcmRfZmxpcCgpICsNCmxhYnMoc3VidGl0bGUgPSAiUmVjYXVkYWNpw7NuIGVuIG1pbGxvbmVzIGRlIGTDs2xhcmVzIiwNCiAgICB4ID0gTlVMTCwgeSA9IE5VTEwpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIk1vb25yaXNlMyIsIG4gPSAyLCB0eXBlID0gImNvbnRpbnVvdXMiKSkNCg0KDQpwZWxpc19saXN0IDwtIHBlbGlzX3JlY18yICU+JSBtdXRhdGUocmFua2luZyA9IGMoMTo1MCkpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihhY3RfZGlyX3Byb2QgPT0gInNpIikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QocmFua2luZywgbmFtZSwgZGlyZWN0b3IsIHN0YXIsIGNvbXBhbnksIGdyb3NzKQ0KDQpwZWxpc19saXN0ICU+JSBmb3JtYXR0YWJsZShsaXN0KA0KICBgcmFua2luZ2A9IGNvbG9yX3RpbGUoY3VzdG9tR3JlZW4sIGN1c3RvbUdyZWVuMCksDQogICBhcmVhKGNvbCA9IGdyb3NzKSB+IG5vcm1hbGl6ZV9iYXIoInBpbmsiLCAwLjIpKSkNCmBgYA0KDQoNCkVuIGVsIFRvcCA1MCBwZWzDrWN1bGFzIG3DoXMgdGFxdWlsbGVyYXMgZGUgbGEgaGlzdG9yaWEgcG9kZW1vcyBlbmNvbnRyYXIgdHJlcyBkZSBsYXMgcGVsw61jdWxhcyBxdWUgY3VtcGxlbiBsYSBoaXDDs3Rlc2lzIGRlIGRpcmVjdG9yICsgcHJvZHVjdG9yYSArIGFjdG9yL2FjdHJpei4gRXN0YXMgc29uIFRpdGFuaWMsIEZvcnJlc3QgR3VtcCB5IEhhcnJ5IFBvdHRlciwgc2llbmRvIFRpdGFuaWMgbGEgdGVyY2VyYSBjb24gbcOhcyByZWNhdWRhY2nDs24gZGVzZGUgMTk4Ni4gQ2FiZSBkZXN0YWNhciBxdWUgZW4gZWwgYcOxbyBkZSBzdSBlc3RyZW5vIHNlIGNvbnZpcnRpw7MgZW4gbGEgcGVsw61jdWxhIG3DoXMgdGFxdWlsbGVyYSBoYXN0YSBlc2UgbW9tZW50by4NCg0KYGBge3IgZXZhbCA9IFRSVUUsIGVjaG8gPSBGQUxTRX0NCnRpdCA8LSBnZ2RyYXcoKSArIGRyYXdfaW1hZ2UoImh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2VuLzEvMTkvVGl0YW5pY18lMjhPZmZpY2lhbF9GaWxtX1Bvc3RlciUyOS5wbmciLCBzY2FsZSA9IDAuOSkNCmZvcnIgPC0gZ2dkcmF3KCkgKyBkcmF3X2ltYWdlKCJodHRwczovL3BpY3MuZmlsbWFmZmluaXR5LmNvbS9Gb3JyZXN0X0d1bXAtMjEyNzY1ODI3LW1tZWQuanBnIiwgc2NhbGUgPSAwLjkpDQpoYXIgPC0gZ2dkcmF3KCkgKyBkcmF3X2ltYWdlKCJodHRwczovL2kuZXRzeXN0YXRpYy5jb20vMTYzNTUzMjEvci9pbC8yM2JkYTEvMTQyNzA2NTc2Mi9pbF81NzB4Ti4xNDI3MDY1NzYyX2oyY3kuanBnIiwgc2NhbGUgPSAwLjkpDQoNCnBsb3RfZ3JpZCh0aXQsIGZvcnIsIGhhcikNCmBgYA0KDQoNCmBgYHtyfQ0KDQojYm94cGxvdCBtZWRpYXMNCm1vdmllc19ib3ggPC0gbW92aWVzICU+JSBtdXRhdGUoZ3Jvc3MgPSBncm9zcy8xMDAwMDAwKSAlPiUgbXV0YXRlKGFjdF9kaXJfcHJvZCA9ICJUb2RhcyIpDQoNCmJveF9wZWxpc19ncm9zcyA8LSB1bmlvbihtb3ZpZXNfYm94LCBwZWxpc19yZWMpDQoNCmxpYnJhcnkoIndlc2FuZGVyc29uIikNCg0KcCA8LSBnZ3Bsb3QoYm94X3BlbGlzX2dyb3NzLCBhZXMoeCA9IHJlb3JkZXIoYWN0X2Rpcl9wcm9kLCBncm9zcywgbWVhbiksICB5ID0gZ3Jvc3MsIGZpbGwgPSBhY3RfZGlyX3Byb2QgKSkgKyBnZW9tX2JveHBsb3QoKSArIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNTAwLCA1MCksIGxpbWl0cyA9IGMoTkEsIDUwMCkpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIkRhcmplZWxpbmcxIiwgbiA9IDMsIHR5cGUgPSAiZGlzY3JldGUiKSkgKyBsYWJzKHN1YnRpdGxlID0gIlJlY2F1ZGFjacOzbiBlbiBtaWxsb25lcyBkZSBkw7NsYXJlcyIsIHggPSBOVUxMKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KbGlicmFyeShwbG90bHkpDQoNCmdncGxvdGx5KHApDQoNCmBgYA0KDQpQb2RlbW9zIHZlciBjb21vLCB0ZW5pZW5kbyBlbiBjdWVudGEgcXVlIGxhIG1lZGlhbmEgZGUgdG9kYXMgbGFzIHBlbMOtY3VsYXMgZGUgbGEgbGlzdGEgZXMgZGUgcG9jbyBtw6FzIGRlIDEyIG1pbGxvbmVzIGRlIGTDs2xhcmVzICwgY29udHJhdGFyIHVuIGFjdG9yICsgZGlyZWN0b3IgKyBwcm9kdWN0b3JhIHJlbnRhYmxlIChlbCBib3hwbG90ICJzaSIpIHN1YmUgbGEgbWVkaWFuYSBkZSBpbmdyZXNvcyBhIG3DoXMgZGUgMTM1IG1pbGxvbmVzIGRlICBkw7NsYXJlcy4gU2luIGVtYmFyZ28gcXVlZGEgbGVqb3MgZGUgbGEgbWVkaWFuYSBkZSBsYXMgNTAgcGVsw61jdWxhcyBxdWUgbcOhcyBoYW4gcmVjYXVkYWRvIGRlIGxhIGxpc3RhLCAzNjggbWlsbGlvbmVzIGRlIGTDs2xhcmVzLg0KDQo8Rk9OVCBDT0xPUj0iT3JhbmdlIj4qKlJlY2F1ZGFjacOzbiwgbm90YSB5IE9zY2FycyoqPC9GT05UPg0KDQpgYGB7cn0NCiNzY2F0dGVycGxvdCBjb24gbm90YSBtZWRpYSB5IG9zY2Fycw0Kb3NjYXJzX3BlbGlzIDwtIG9zY2FycyAlPiUgZmlsdGVyKHdpbm5lciA9PSAiVFJVRSIsIHllYXJfZmlsbSA+IDE5ODYpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwX2J5KGZpbG0pICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZSh3aW5zID0gbigpKSU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpc3RpbmN0KGZpbG0sLmtlZXBfYWxsID0gVFJVRSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoZmlsbSA9IGNhc2Vfd2hlbigNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxtID09ICJEci4gU2V1c3MnIEhvdyB0aGUgR3JpbmNoIFN0b2xlIENocmlzdG1hcyIgfiAiSG93IHRoZSBHcmluY2ggU3RvbGUgQ2hyaXN0bWFzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxtID09ICJTd2VlbmV5IFRvZGQgVGhlIERlbW9uIEJhcmJlciBvZiBGbGVldCBTdHJlZXQiIH4gIlN3ZWVuZXkgVG9kZDogVGhlIERlbW9uIEJhcmJlciBvZiBGbGVldCBTdHJlZXQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgIH4gIGZpbG0gKSkNCg0Kb3NjYXJzX3BlbGlzX2dyb3NzIDwtIGxlZnRfam9pbihwZWxpc19ncm9zcywgb3NjYXJzX3BlbGlzLCBieSA9IGMoIm5hbWUiID0gImZpbG0iKSkNCg0Kb3NjYXJzX3BlbGlzX2dyb3NzJHdpbnNbaXMubmEob3NjYXJzX3BlbGlzX2dyb3NzJHdpbnMpXSA8LSAwDQoNCmxpYnJhcnkoZ2dyZXBlbCkNCnAxIDwtIGdncGxvdChvc2NhcnNfcGVsaXNfZ3Jvc3MsIGFlcyhncm9zcywgc2NvcmUsIHNpemUgPSB3aW5zICwgY29sb3IgPSBuYW1lKSkgKyBnZW9tX3BvaW50KCkgICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIHNjYWxlX3hfY29udGludW91cyhsYWJlbHM9c2NhbGVzOjpkb2xsYXIsIGJyZWFrcyA9IHNlcSgwLCA3MDAsIDEwMCkpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJaaXNzb3UxIiwgbiA9IDI3LCB0eXBlID0gImNvbnRpbnVvdXMiKSkNCg0KDQpsaWJyYXJ5KHBsb3RseSkNCg0KZ2dwbG90bHkocDEpDQpgYGANCg0KRW4gZXN0YSBncsOhZmljYSB2ZW1vcyBjw7NtbyBlc3RhcyBwZWzDrWN1bGFzIGNvbiBhY3QgKyBkaXIgKyBwcm9kIG3DoXMgcmVudGFibGVzLCBoYW4gc2lkbyBsdWVnbyByZWNpYmlkYXMgcG9yIGxvcyB1c3VhcmlvcyBkZSBpbWRiIChzY29yZSkgeSBhZGVtw6FzIHNlZ8O6biBzdSB0YW1hw7FvIGN1w6FudG9zIE9zY2FycyBnYW5hcm9uLg0KDQpWZW1vcyBlbiBlbCBjYXNvIGRlIFRpdGFuaWMgY29tbyBhIHBhcnRlIGRlIGNvbnZlcnRpcnNlIGVuIGxhIHBlbMOtY3VsYSBtw6FzIHRhcXVpbGxlcmEsIHNlIGxsZXbDsyBsYSBtYXlvciBjYW50aWRhZCBkZSDDk3NjYXJzIChyZWNvcmQgcXVlIHNpZ3VlIHZpZ2VudGUsIHNvbG8gaWd1YWxhZG8gcG9yIGVsIFNlw7FvciBkZSBsb3MgQW5pbGxvcyAzKSBlbiBzdSBtb21lbnRvLiBUYW1iacOpbiBjYWJlIGRlc3RhY2FyIGxhcyBwZWzDrWN1bGFzIFNhbHZhciBhbCBzb2xkYWRvIFJ5YW4sIEluY2VwdGlvbiB5IEZvcnJlc3QgR3VtcCwgcXVlIGFwYXJ0ZSBkZSBsbGV2YXJzZSBlbnRyZSA0IHkgNiBPc2NhcnMsIGVzdMOhbiB2YWxvcmFkYXMgcG9yIGxvcyB1c3VhcmlvcyBjb24gbcOhcyBkZSB1biA4LjUuDQoNCiMjIFBlbGljdWxhcyBjb24gYWN0b3IsIGRpcmVjdG9yIHkgcHJvZHVjdG9yYSBjb24gTUVKT1IgTk9UQQ0KDQpgYGB7cn0NCg0KI2ZpbHRyYW5kbyBUT1AgMTAgYWN0b3JlcywgZGlyLCB5IHByb2QNCg0KcGVsaXNfc2NvcmVfNSA8LSBtb3ZpZXMgJT4lIGZpbHRlcihzdGFyICVpbiUgYygiQWFtaXIgS2hhbiIsICJSaWNhcmRvIERhcsOtbiIsIkxlb25hcmRvIERpQ2FwcmlvIiwgIlNoYWggUnVraCBLaGFuIiwgIlRha2VzaGkgS2l0YW5vIiwgIkNocmlzdGlhbiBCYWxlIiwgIkFuZHJldyBHYXJmaWVsZCIsICJJYW4gTWNLZWxsZW4iLCAiVG9tIEhhcmR5IiwgICJKYXZpZXIgQmFyZGVtIikpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoZGlyZWN0b3IgJWluJSBjKCJDaHJpc3RvcGhlciBOb2xhbiIsICJRdWVudGluIFRhcmFudGlubyIsIkphbWVzIENhbWVyb24iLCJHaXVzZXBwZSBUb3JuYXRvcmUiLCAiUGV0ZXIgSmFja3NvbiIsICJBbGVqYW5kcm8gR29uesOhbGV6IEnDscOhcnJpdHUiLCAiRGF2aWQgRmluY2hlciIsICLDiXJpYyBSb2htZXIiLCAiRGVuaXMgVmlsbGVuZXV2ZSIsICJDaGFuLXdvb2sgUGFyayIpKSU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoY29tcGFueSAlaW4lIGMoIlBpeGFyIEFuaW1hdGlvbiBTdHVkaW9zIiwgIk1hcnZlbCBTdHVkaW9zIiwgIldhcm5lciBJbmRlcGVuZGVudCBQaWN0dXJlcyAoV0lQKSIsICJNSzIgUHJvZHVjdGlvbnMiLCAiQmFuZGFpIFZpc3VhbCBDb21wYW55IiwgIldhbHQgRGlzbmV5IEFuaW1hdGlvbiBTdHVkaW9zIiwgIkx1Y2FzZmlsbSIsICJaZW50cm9wYSBFbnRlcnRhaW5tZW50cyIsICJDYW5hbCsgRXNwYcOxYSIsICJHb29kIE1hY2hpbmUiKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhzY29yZSkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWN0X2Rpcl9wcm9kID0gInNpIikNCg0KYGBgDQoNCioqTm8gc2UgaGFuIGVuY29udHJhZG8gcGVsw61jdWxhcyBjb24gbG9zIGFjdG9yZXMgKyBkaXJlY3RvcmVzICsgcHJvZHVjdG9yYXMgbWVqb3IgdmFsb3JhZG9zLioqDQoNCiMjIFBlbGljdWxhcyBjb24gYWN0b3IsIGRpcmVjdG9yIHkgcHJvZHVjdG9yYSBjb24gTUFTIERFIFVOIE9TQ0FSIA0KDQoodG9tYW5kbyBsb3MgZGF0b3MgZGUgYWN0X29zYywgZGlyX29zYyB5IHByb2Rfb3NjX3BlbGkgPC0gb3NjYXIgYSBNRUpPUiBQRUxJQ1VMQSkNCg0KYGBge3J9DQoNCnBlbGlzX29zY2FyIDwtIG1vdmllcyAlPiUgZmlsdGVyKHN0YXIgJWluJSBjKCJNZXJ5bCBTdHJlZXAiLCAiSmFjayBOaWNob2xzb24iLCJSb2JlcnQgRGUgTmlybyIsICJUb20gSGFua3MiLCAiR2VuZSBIYWNrbWFuIiwgIlNlYW4gUGVubiIsICJKYW5lIEZvbmRhIiwgIkphY2sgTGVtbW9uIiwgIk1pY2hhZWwgQ2FpbmUiLCAgIkRlbnplbCBXYXNoaW5ndG9uIiwgIkJldHRlIERhdmlzIiwgIkphc29uIFJvYmFyZHMiLCAiSm9kaWUgRm9zdGVyIiwgIlNhbGx5IEZpZWxkIiwgIkR1c3RpbiBIb2ZmbWFuIiwiRGFuaWVsIERheS1MZXdpcyIsICJQZXRlciBVc3Rpbm92IiwgIkplc3NpY2EgTGFuZ2UiLCJHbGVuZGEgSmFja3NvbiIsICJNYXJsb24gQnJhbmRvIiwiRnJhbmNlcyBNY0Rvcm1hbmQiLCAiS2V2aW4gU3BhY2V5IiwgIkNhdGUgQmxhbmNoZXR0IiwiSGlsYXJ5IFN3YW5rIiwgIk1hZ2dpZSBTbWl0aCIsICJDaHJpc3RvcGggV2FsdHoiLCAiTWFoZXJzaGFsYSBBbGkiKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihkaXJlY3RvciAlaW4lIGMoIk9saXZlciBTdG9uZSIsICJDbGludCBFYXN0d29vZCIsIlN0ZXZlbiBTcGllbGJlcmciLCJNaWxvcyBGb3JtYW4iLCAiQW5nIExlZSIpKSU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoY29tcGFueSAlaW4lIGMoIldhcm5lciBCcm9zLiIsICJQaXhhciBBbmltYXRpb24gU3R1ZGlvcyIsICJVbml2ZXJzYWwgUGljdHVyZXMiLCAiV2FsdCBEaXNuZXkgUGljdHVyZXMiLCAiUmVjb3JkZWQgUGljdHVyZSBDb21wYW55IChSUEMpIiwgIkNvbHVtYmlhIFBpY3R1cmVzIENvcnBvcmF0aW9uIiwgIlBhcmFtb3VudCBQaWN0dXJlcyIsICJNaXJhbWF4IikpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoZ3Jvc3MpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGFjdF9kaXJfcHJvZCA9ICJzaSIpDQoNCnBlbGljdWxhc19vc2NhciA8LSBwZWxpc19vc2NhciAlPiUgc2VsZWN0KG5hbWUsIGRpcmVjdG9yLCBzdGFyLCBjb21wYW55LCBncm9zcykNCiNNeXN0aWMgUml2ZXIgeSBNaWxsaW9uIERvbGxhciBCYWJ5DQoNCmVlIDwtIG9zY2FycyAlPiUgZmlsdGVyKGZpbG0gJWluJSBjKCJNeXN0aWMgUml2ZXIiLCAiTWlsbGlvbiBEb2xsYXIgQmFieSIpLCB3aW5uZXIgPT0gVFJVRSkgJT4lIHNlbGVjdChmaWxtLCBjYXRlZ29yeSwgbmFtZSwgd2lubmVyKQ0KDQpkYXRhdGFibGUoZWUpICU+JSBmb3JtYXRTdHlsZSgNCiAgJ2ZpbG0nLHRhcmdldCA9ICdyb3cnLA0KICBiYWNrZ3JvdW5kQ29sb3IgPSBzdHlsZUVxdWFsKGMoIk15c3RpYyBSaXZlciIsICJNaWxsaW9uIERvbGxhciBCYWJ5IiksIGMoJ3BpbmsnLCAnbGlnaHRibHVlJykpKSAlPiUgZm9ybWF0U3R5bGUoJ25hbWUnLA0KICBiYWNrZ3JvdW5kQ29sb3IgPSBzdHlsZUVxdWFsKGMoIlNlYW4gUGVubiIsICJIaWxhcnkgU3dhbmsiLCAiQ2xpbnQgRWFzdHdvb2QiKSwgYygna2hha2knLCAna2hha2knLCAna2hha2knKSkpICU+JSBmb3JtYXRTdHlsZSgnY2F0ZWdvcnknLA0KICBiYWNrZ3JvdW5kQ29sb3IgPSBzdHlsZUVxdWFsKGMoIkFDVE9SIElOIEEgTEVBRElORyBST0xFIiwgIkFDVFJFU1MgSU4gQSBMRUFESU5HIFJPTEUiLCAiRElSRUNUSU5HIiwgIkJFU1QgUElDVFVSRSIpLCBjKCdraGFraScsICdraGFraScsICdraGFraScsICdraGFraScpKSkgJT4lIGZvcm1hdFN0eWxlKCduYW1lJywgdGFyZ2V0ID0gJ3JvdycsDQogIGJhY2tncm91bmRDb2xvciA9IHN0eWxlRXF1YWwoYygiQ2xpbnQgRWFzdHdvb2QsIEFsYmVydCBTLiBSdWRkeSBhbmQgVG9tIFJvc2VuYmVyZywgUHJvZHVjZXJzIiksIGMoJ2toYWtpJykpKSAlPiUgZm9ybWF0U3R5bGUoJ25hbWUnLCB0YXJnZXQgPSAicm93IiwNCiAgZm9udFdlaWdodCA9IHN0eWxlRXF1YWwoIkNsaW50IEVhc3R3b29kLCBBbGJlcnQgUy4gUnVkZHkgYW5kIFRvbSBSb3NlbmJlcmcsIFByb2R1Y2VycyIsICJib2xkIikpDQoNCmBgYA0KDQpgYGB7ciBldmFsID0gVFJVRSwgZWNobyA9IEZBTFNFfQ0KDQpteXMgPC0gZ2dkcmF3KCkgKyBkcmF3X2ltYWdlKCJodHRwczovL3BpY3MuZmlsbWFmZmluaXR5LmNvbS9NeXN0aWNfUml2ZXItOTc2NjM4NTI1LWxhcmdlLmpwZyIsIHNjYWxlID0gMC45KQ0KbWlsbCA8LSBnZ2RyYXcoKSArIGRyYXdfaW1hZ2UoImh0dHBzOi8vcGljcy5maWxtYWZmaW5pdHkuY29tL01pbGxpb25fRG9sbGFyX0JhYnktMzQyMTU0NDEzLW1tZWQuanBnIiwgc2NhbGUgPSAwLjkpDQoNCnBsb3RfZ3JpZChteXMsIG1pbGwpDQpgYGANCg0KDQpQb2RlbW9zIHZlciBjb21vIGxhIGNvbWJpbmFjacOzbiBkZSBwcm9kdWN0b3JhIGdhbmFkb3JhIGRlIE9zY2FyLCBhY3RvciBnYW5hZG9yIGRlIE9zY2FyIHkgZGlyZWN0b3IgZ2FuYWRvciBkZSBPc2NhciBmdWUgZnJ1Y3TDrWZlcmEgZW4gZXN0YXMgZG9zIHBlbMOtY3VsYXMuIE1pcmFuZG8gbG9zIGRhdG9zIGNvbiBkZXRlbmltaWVudG8gdmVtb3MgY29tbyBTZWFuIFBlbm4gZ2Fuw7Mgc3UgcHJpbWVyIE9zY2FyIGNvbiBNeXN0aWMgUml2ZXIgKGNvbiBsbyBjdWFsIGN1YW5kbyBzZSBsZSBlc2NvZ2nDsyBwYXJhIGxhIHBlbGljdWxhIHRvZGF2w61hIG5vIGVyYSBnYW5hZG9yIGRlIE9zY2FyKS4gDQoNCkVuIGVsIGNhc28gZGUgTWlsbGlvbiBEb2xsYXIgQmFieSwgQ2xpbnQgRWFzdHdvb2QsIEhpbGFyeSBTd2FuayB5IFdhcm5lciBCcm9zIHlhIGhhYsOtYW4gZ2FuYWRvIHVuIG9zY2FyIChjYXN1YWxtZW50ZSBjb24gQ2xpbnQgRWFzdHdvb2QgZW4gVW5mb3JnaXZlbiksIHkgZWwgcmVzdWx0YWRvIGZ1ZSBlbCBPc2NhciBhIE1lam9yIFBlbMOtY3VsYSwgZWwgT3NjYXIgYSBNZWpvciBBY3RyaXogcGFyYSBIaWxsYXJ5IFN3YW5rIHkgZWwgT3NjYXIgYSBNZWpvciBEaXJlY3RvciBwYXJhIENsaW50IEVhc3R3b29kLCBjb24gbG8gY3VhbCBlbiBlc3RlIGNhc28gbGVzIHNhbGnDsyBiaWVuIGxhIGVzdHJhdGVnaWEgZGUgZXNjb2dlciBhIGdhbmFkb3JlcyBkZSBvc2Nhci4NCg0KIyA3LiBSZWxhY2lvbmVzICB7LnRhYnNldCAudGFic2V0LXBpbGx9DQoNCiMjIFRvZGFzIGxhcyBwcm9kdWN0b3Jhcw0KDQo8Rk9OVCBDT0xPUj0iT3JhbmdlIj4qKkFjdG9yLCBkaXJlY3RvciB5IHByb2R1Y3RvcmEqKjwvRk9OVD4NCg0KUHJpbWVybyBwcm9iYW1vcyBhIHZlciBzaSBoYXkgcGVsw61jdWxhcyBxdWUgY3VlbnRlbiBjb24gYWN0b3IsIGRpcmVjdG9yIHkgcHJvZHVjdG9yYSBxdWUgY3VtcGxlbiBsb3MgMyBjcml0ZXJpb3MgKG3DoXMgdGFxdWlsbGVyb3MsIG1lam9yIG5vdGEgeSBnYW5hZG9yZXMgZGUgw7NzY2FyOyBlcyBkZWNpciBsb3MgcXVlIHNhbGVuIGVuIFJlc3VsdGFkb3MpDQoNCmBgYHtyfQ0KI3RvZG86IG5hZGENCmRmIDwtIG1vdmllcyAlPiUgZmlsdGVyKHN0YXIgJWluJSBjKCAiQnJhZCBQaXR0IiwgIkNocmlzdGlhbiBCYWxlIiwgIkxlb25hcmRvIERpQ2FwcmlvIiwgIlRvbSBIYW5rcyIpKSAlPiUgZmlsdGVyKGRpcmVjdG9yICVpbiUgYygiU3RldmVuIFNwaWVsYmVyZyIsICJQZXRlciBKYWNrc29uIiwgIkphbWVzIENhbWVyb24iKSkgJT4lIGZpbHRlcihjb21wYW55ICVpbiUgYygiUGl4YXIgQW5pbWF0aW9uIFN0dWRpb3MiLCAiRHJlYW1Xb3JrcyBBbmltYXRpb24iKSkNCmBgYA0KDQpObyBzYWxlIG5pbmfDum4gcmVzdWx0YWRvLCB2YW1vcyBhIHByb2JhciBjb24gYWN0b3IgeSBkaXJlY3RvcjoNCg0KPEZPTlQgQ09MT1I9Ik9yYW5nZSI+KipBY3RvciB5IGRpcmVjdG9yKio8L0ZPTlQ+DQoNCmBgYHtyfQ0KZGZfMSA8LSBtb3ZpZXMgJT4lIGZpbHRlcihzdGFyICVpbiUgYyggIkJyYWQgUGl0dCIsICJDaHJpc3RpYW4gQmFsZSIsICJMZW9uYXJkbyBEaUNhcHJpbyIsICJUb20gSGFua3MiKSkgJT4lIGZpbHRlcihkaXJlY3RvciAlaW4lIGMoIlN0ZXZlbiBTcGllbGJlcmciLCAiUGV0ZXIgSmFja3NvbiIsICJKYW1lcyBDYW1lcm9uIikpIzYgcmVzdWx0YWRvcw0KDQpkZl8xICU+JSBzZWxlY3QobmFtZSwgZGlyZWN0b3IsIHN0YXIsIGNvbXBhbnksIGdyb3NzLCBzY29yZSkNCmBgYA0KDQpUZW5lbW9zIDYgcGVsw61jdWxhcy4gVmFtb3MgYSB2ZXIgY29uIGFjdG9yIHkgcHJvZHVjdG9yYToNCg0KPEZPTlQgQ09MT1I9Ik9yYW5nZSI+KipBY3RvciB5IHByb2R1Y3RvcmEqKjwvRk9OVD4NCmBgYHtyfQ0KZGZfMiA8LSBtb3ZpZXMgJT4lIGZpbHRlcihzdGFyICVpbiUgYyggIkJyYWQgUGl0dCIsICJDaHJpc3RpYW4gQmFsZSIsICJMZW9uYXJkbyBEaUNhcHJpbyIsICJUb20gSGFua3MiKSkgJT4lIGZpbHRlcihjb21wYW55ICVpbiUgYygiUGl4YXIgQW5pbWF0aW9uIFN0dWRpb3MiLCAiRHJlYW1Xb3JrcyBBbmltYXRpb24iKSkjVG95IFN0b3J5IDEgeSAyDQoNCmRmXzIgJT4lIHNlbGVjdChuYW1lLCBkaXJlY3Rvciwgc3RhciwgY29tcGFueSwgZ3Jvc3MsIHNjb3JlKQ0KYGBgDQoNClRlbmVtb3MgZG9zIHJlc3VsdGFkb3MuDQoNCjxGT05UIENPTE9SPSJPcmFuZ2UiPioqRGlyZWN0b3IgeSBwcm9kdWN0b3JhKio8L0ZPTlQ+DQpgYGB7cn0NCmRmXzMgPC0gbW92aWVzICU+JSBmaWx0ZXIoZGlyZWN0b3IgJWluJSBjKCJTdGV2ZW4gU3BpZWxiZXJnIiwgIlBldGVyIEphY2tzb24iLCAiSmFtZXMgQ2FtZXJvbiIpKSAlPiUgZmlsdGVyKGNvbXBhbnkgJWluJSBjKCJQaXhhciBBbmltYXRpb24gU3R1ZGlvcyIsICJEcmVhbVdvcmtzIEFuaW1hdGlvbiIpKSNuYWRhDQoNCmBgYA0KDQpOaW5nw7puIHJlc3VsdGFkbywgYWhvcmEgKip2YW1vcyBhIHF1aXRhciBhIGxhcyBwcm9kdWN0b3JhcyBkZSBhbmltYWNpw7NuKiosIHlhIHF1ZSBwb2TDrWFuIGVzdGFyIGVudG9ycGVjaWVuZG8gbGEgcmVsYWNpw7NuIGVudHJlIGFjdG9yZXMgbyBkaXJlY3RvcmVzIHF1ZSBubyBzdWVsZW4gZGVkaWNhcnNlIGFsIMOhbWJpdG8gZGUgbGEgYW5pbWFjacOzbi4NCg0KIyMgU2luIGFuaW1hY2nDs24NCg0KYGBge3J9DQpzaW5fYW5pbSA8LSBtb3ZpZXMgJT4lIGZpbHRlcihnZW5yZSAhPSAiQW5pbWF0aW9uIikNCg0KcHJvZF9ncm9zc18xIDwtIHNpbl9hbmltICU+JSBncm91cF9ieShjb21wYW55KSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UocmVjYXVkYWNpb24gPSBzdW0oZ3Jvc3MpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MocmVjYXVkYWNpb24pKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkKDMwKQ0KDQpwcm9kX3Njb3JlXzEgPC0gc2luX2FuaW0gJT4lIGdyb3VwX2J5KGNvbXBhbnkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShub3RhX21lZGlhID0gbWVhbihzY29yZSkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyhub3RhX21lZGlhKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgaGVhZCgzMCkNCg0KI23DoXMgZGUgNSBwZWxpY3VsYXMNCnByb2Rfc2NvcmVfNV8xIDwtIHNpbl9hbmltICU+JSBncm91cF9ieShjb21wYW55KSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShOTiA9IG4oKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoTk4gPiA1KSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShub3RhX21lZGlhID0gbWVhbihzY29yZSkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKG5vdGFfbWVkaWEpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWQoMzApDQoNCnByb2R1Y3RvcmFzXzEgPC0gbWVyZ2UobWVyZ2UoDQogIHByb2RfZ3Jvc3NfMSwNCiAgcHJvZF9zY29yZV81XzEsIGFsbCA9IFRSVUUpLA0KICBwcm9kX29zYywgYWxsID0gVFJVRSkNCg0KZGQgPC0gcHJvZHVjdG9yYXNfMSAlPiUgZmlsdGVyKGNvbXBsZXRlLmNhc2VzKC4pKSAlPiUgYXJyYW5nZShkZXNjKHRvdF93aW5zKSkNCg0KZGQNCmBgYA0KDQpWZW1vcyBxdWUgbGEgw7puaWNhIHByb2R1Y3RvcmEgcXVlIGN1bXBsZSBhaG9yYSBsb3MgdHJlcyBjcml0ZXJpb3MgZXMgRm9jdXMgRmVhdHVyZXMuDQoNCmBgYHtyIGV2YWwgPSBUUlVFLCBlY2hvID0gRkFMU0V9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly9lbmNyeXB0ZWQtdGJuMC5nc3RhdGljLmNvbS9pbWFnZXM/cT10Ym46QU5kOUdjUTI5S09NcE90VXh6bDNfZ3d2bnhzTDlRUXFUaXJBWmxtNlVnJnVzcXA9Q0FVIikNCmBgYA0KDQo8Rk9OVCBDT0xPUj0iT3JhbmdlIj4qKkFjdG9yLCBkaXJlY3RvciB5IHByb2R1Y3RvcmEqKjwvRk9OVD4NCg0KYGBge3J9DQojU0lOIEFOSU1BQ0lPTg0KZGZfcmVsXzEgPC0gbW92aWVzICU+JSBmaWx0ZXIoc3RhciAlaW4lIGMoICJCcmFkIFBpdHQiLCAiQ2hyaXN0aWFuIEJhbGUiLCAiTGVvbmFyZG8gRGlDYXByaW8iLCAiVG9tIEhhbmtzIikpICU+JSBmaWx0ZXIoZGlyZWN0b3IgJWluJSBjKCJTdGV2ZW4gU3BpZWxiZXJnIiwgIlBldGVyIEphY2tzb24iLCAiSmFtZXMgQ2FtZXJvbiIpKSAlPiUgZmlsdGVyKGNvbXBhbnkgPT0gIkZvY3VzIEZlYXR1cmVzIikjbmFkYQ0KDQpgYGANCg0KSW5jb3Jwb3JhbmRvIGxhIHByb2R1Y3RvcmEgRm9jdXMgRmVhdHVyZXMgc2lndWUgc2luIGhhYmVyIG5pbmd1bmEgcGVsaWN1bGEgcXVlIGN1bXBsYSBsb3MgdHJlcyBjcml0ZXJpb3MuIFZhbW9zIGEgdmVyIGFjdG9yIHkgcHJvZHVjdG9yYSBxdWUgaGF5YW4gdHJhYmFqYWRvIGp1bnRvcy4NCg0KPEZPTlQgQ09MT1I9Ik9yYW5nZSI+KipBY3RvciB5IHByb2R1Y3RvcmEqKjwvRk9OVD4NCmBgYHtyfQ0KZGZfcmVsXzIgPC0gbW92aWVzICU+JSBmaWx0ZXIoc3RhciAlaW4lIGMoICJCcmFkIFBpdHQiLCAiQ2hyaXN0aWFuIEJhbGUiLCAiTGVvbmFyZG8gRGlDYXByaW8iLCAiVG9tIEhhbmtzIikpICU+JSBmaWx0ZXIoY29tcGFueSA9PSAiRm9jdXMgRmVhdHVyZXMiKQ0KI0J1cm4gQWZ0ZXIgUmVhZGluZw0KZGZfcmVsXzINCmBgYA0KDQpUZW5lbW9zIHVuIHJlc3VsdGFkby4gTm9zIHNhbHRhbW9zIEFjdG9yIHkgZGlyZWN0b3IgcG9ycXVlIGVzIGVsIG1pc21vIHJlc3VsdGFkbyBkZSBhbnRlcy4NCg0KPEZPTlQgQ09MT1I9Ik9yYW5nZSI+KipEaXJlY3RvciB5IHByb2R1Y3RvcmEqKjwvRk9OVD4NCmBgYHtyfQ0KZGZfcmVsXzQgPC0gbW92aWVzICU+JSAgZmlsdGVyKGRpcmVjdG9yICVpbiUgYygiU3RldmVuIFNwaWVsYmVyZyIsICJQZXRlciBKYWNrc29uIiwgIkphbWVzIENhbWVyb24iKSkgJT4lIGZpbHRlcihjb21wYW55ID09ICJGb2N1cyBGZWF0dXJlcyIpI25hZGENCg0KYGBgDQoNCk5hZGEsIGFob3JhIHZhbW9zIGEgY29tcGFyYXIgdG9kYXMgZXN0YXMgcGVsw61jdWxhcy4NCg0KIyA4LiBDb25jbHVzaW9uZXMNCg0KYGBge3J9DQoNCnFxIDwtIFJlZHVjZSh1bmlvbiwgbGlzdChkZl8xLCBkZl8yLCBkZl9yZWxfMikpDQoNCnFxIDwtIHFxICU+JSBtdXRhdGUoZ3Jvc3MgPSBncm9zcy8xMDAwMDAwKQ0KDQojc2NhdHRlcnBsb3QgY29uIG5vdGEgbWVkaWEgeSBvc2NhcnMNCg0Kb3NjYXJzX3BlbGlzX2RmIDwtIGxlZnRfam9pbihxcSwgb3NjYXJzX3BlbGlzLCBieSA9IGMoIm5hbWUiID0gImZpbG0iKSkNCg0Kb3NjYXJzX3BlbGlzX2RmJHdpbnNbaXMubmEob3NjYXJzX3BlbGlzX2RmJHdpbnMpXSA8LSAwDQoNCmxpYnJhcnkoZ2dyZXBlbCkNCnAzIDwtIGdncGxvdChvc2NhcnNfcGVsaXNfZGYsIGFlcyhncm9zcywgc2NvcmUsIGxhYmVsID0gbmFtZSwgY29sb3IgPSBuYW1lLCBzaXplID0gd2lucykpICsgZ2VvbV9wb2ludCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIGdlb21fbGFiZWxfcmVwZWwoc2l6ZSA9IDMpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJGYW50YXN0aWNGb3gxIiwgbiA9IDEwLCB0eXBlID0gImNvbnRpbnVvdXMiKSkgKyBzY2FsZV94X2NvbnRpbnVvdXMoIGJyZWFrcyA9IHNlcSgwLCA3MDAsIDEwMCkpDQoNCiNjb24gbG9zIG5vbWJyZXMNCnAzDQoNCmBgYA0KDQpTZSBwdWVkZSBhcHJlY2lhciB1bmEgbGlnZXJhIGNvcnJlbGFjacOzbiBlbnRyZSByZWNhdWRhY2nDs24geSBub3RhIG1lZGlhLiBUYW1iacOpbiB2ZW1vcyBxdWUgbGFzIGRvcyBwZWzDrWN1bGFzIGNvbiBtw6FzIE9zY2FycyBzb24gbGEgcGVsw61jdWxhIGNvbiBtZWpvciBub3RhIHkgbGEgbcOhcyB0YXF1aWxsZXJhLg0KDQpWZW1vcyBxdWUgbGFzIG5vdGFzIGRlIGxvcyB1c3VhcmlvcyBkZSBpbWRiIG5vIHNvbiBtYWxhcywgdG9kYXMgcG9yIGVuY2ltYSBkZSB1biA3IHkgZGVzdGFjYW5kbyBsYSBwZWzDrWN1bGEgU2FsdmFyIGFsIHNvbGRhZG8gUnlhbiBjb24gdW4gOCw2IGRlIG5vdGEuIEVuIHRlbWFzIGRlIHRhcXVpbGxhLCB2ZW1vcyBxdWUgdG9kYXMgc3VwZXJhbiBsYSBtZWRpYW5hIGRlIDEyIG1pbGxvbmVzIGRlIGTDs2xhcmVzLCBkZXN0YWNhIFRpdGFuaWMsIHF1ZSBkdXJhbnRlIG11Y2hvcyBhw7FvcyBmdWUgbGEgcGVsw61jdWxhIHF1ZSBtw6FzIGhhYsOtYSByZWNhdWRhZG8gZW4gVVNBIChoYXN0YSAyMDA5IHF1ZSBlc2UgcsOpY29yZCBmdWUgc3VwZXJhZG8gcG9yIEF2YXRhciwgb3RyYSBwZWzDrWN1bGEgZGVsIG1pc21vIGRpcmVjdG9yLCBKYW1lcyBDYW1lcm9uKQ0KDQpBaG9yYSB2YW1vcyBhIHZlciBzdSDDqXhpdG8gZW4gY29tcGFyYWNpw7NuIGNvbiBlbCBUb3AgMzAgcGVsw61jdWxhcyBjb24gbcOhcyByZWNhdWRhY2nDs24sIG1lam9yIG5vdGEgeSBtw6FzIE9zY2Fycy4NCg0KIyMgQ29tcGFyYWNpw7NuIGNvbiBsYXMgcGVsw61jdWxhcyBjb24gbcOhcyByZWNhdWRhY2nDs24NCmBgYHtyfQ0KI3RvcDUwIHBlbGlzIGNvbiBtw6FzIHJlY2F1ZGFjacOzbiB5YSB0ZW5lbW9zIC0+IHBlbGlzX21heF9ncm9zcw0KcXEgPC0gcXEgJT4lIG11dGF0ZShhY3RfZGlyX3Byb2QgPSAiZmluYWwiKQ0KDQpwZWxpc19yZWNfZmluIDwtIHVuaW9uKHFxLCBwZWxpc19tYXhfZ3Jvc3MpDQoNCnBlbGlzX3JlY19maW4gPC0gcGVsaXNfcmVjX2ZpbiAlPiUgYXJyYW5nZShkZXNjKGdyb3NzKSkgJT4lIGhlYWQoMzEpDQoNCnBlbGlzX3JlY19maW4gPC0gcGVsaXNfcmVjX2ZpblstYyg0KSwgXQ0KDQpwZWxpc19yZWNfZmluIDwtIHBlbGlzX3JlY19maW4gJT4lIG11dGF0ZShuYW1lID0gZm9yY2F0czo6YXNfZmFjdG9yKG5hbWUpKSAlPiUNCiAgICAgICAgICAgICBtdXRhdGUobmFtZSA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKG5hbWUsZ3Jvc3MpKQ0KDQpwZWxpc19saXN0XzEgPC0gcGVsaXNfcmVjX2ZpbiAlPiUgbXV0YXRlKHJhbmtpbmcgPSBjKDE6MzApKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoYWN0X2Rpcl9wcm9kID09ICJmaW5hbCIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHJhbmtpbmcsIG5hbWUsIGRpcmVjdG9yLCBzdGFyLCBjb21wYW55LCBncm9zcykNCg0KdXJsc190aXQgPC0gImh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2VuLzEvMTkvVGl0YW5pY18lMjhPZmZpY2lhbF9GaWxtX1Bvc3RlciUyOS5wbmciDQp0aXRfdXJscyA8LSBwZWxpc19saXN0XzEgJT4lIGFkZF9jb2x1bW4odXJsc190aXQpDQoNCnRpdF91cmxzICU+JSBndCgpICU+JQ0KICBndDo6dGV4dF90cmFuc2Zvcm0obG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gdmFycyh1cmxzX3RpdCkpLA0KICAgICAgICAgICAgICAgICAgICAgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OndlYl9pbWFnZSh4LCBoZWlnaHQgPSAxMDApfSkgJT4lICB0YWJfc3R5bGUoDQogICAgc3R5bGUgPSBjZWxsX2ZpbGwoY29sb3IgPSAicGluayIpLA0KICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IHZhcnMoZ3Jvc3MpLA0KICAgICAgcm93cyA9IGdyb3NzID4gMSApKSAlPiUgdGFiX3N0eWxlKA0KICAgIHN0eWxlID0gY2VsbF9maWxsKGNvbG9yID0gImxpZ2h0Z3JlZW4iKSwNCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSB2YXJzKHJhbmtpbmcpLA0KICAgICAgcm93cyA9IHJhbmtpbmcgPiAyICkpICU+JSAgZGF0YV9jb2xvcihjb2x1bW5zID0gdmFycyhuYW1lKSwNCiAgICBjb2xvcnMgPSAibGlnaHRibHVlIikNCmBgYA0KDQoNCiMjIENvbXBhcmFjacOzbiBjb24gbGFzIHBlbMOtY3VsYXMgY29uIG1lam9yIG5vdGEgbWVkaWENCmBgYHtyfQ0KI3RvcDMwIHBlbGlzIGNvbiBtZWpvciBub3RhDQpwZWxpc19tYXhfc2NvcmUgPC0gbW92aWVzICU+JSBhcnJhbmdlKGRlc2Moc2NvcmUpKSU+JSB1bmdyb3VwKCkgJT4lIGhlYWQoMzApICU+JSBtdXRhdGUoYWN0X2Rpcl9wcm9kID0gInRvcF8zMCIpDQoNCnBlbGlzX3Njb3JlX2ZpbiA8LSB1bmlvbihxcSwgcGVsaXNfbWF4X3Njb3JlKQ0KDQpwZWxpc19zY29yZV9maW4gPC0gcGVsaXNfc2NvcmVfZmluICU+JSBhcnJhbmdlKGRlc2Moc2NvcmUpKSAlPiUgaGVhZCgzMSkNCg0KcGVsaXNfc2NvcmVfZmluIDwtIHBlbGlzX3Njb3JlX2ZpblstYygyMSksIF0NCg0KDQpwZWxpc19saXN0XzIgPC0gcGVsaXNfc2NvcmVfZmluICU+JSBtdXRhdGUocmFua2luZyA9IGMoMTozMCkpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihhY3RfZGlyX3Byb2QgPT0gImZpbmFsIikgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QocmFua2luZywgbmFtZSwgZGlyZWN0b3IsIHN0YXIsIGNvbXBhbnksIHNjb3JlKQ0KDQoNCg0KdXJsc19zYXYgPC0gImh0dHBzOi8vZXMud2ViLmltZzMuYWNzdGEubmV0L3BpY3R1cmVzLzE0LzAzLzA1LzA5LzQyLzE2MzYyMS5qcGciDQpzYXZfdXJscyA8LSBwZWxpc19saXN0XzIgJT4lIGFkZF9jb2x1bW4odXJsc19zYXYpDQoNCnNhdl91cmxzICU+JSBndCgpICU+JQ0KICBndDo6dGV4dF90cmFuc2Zvcm0obG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gdmFycyh1cmxzX3NhdikpLA0KICAgICAgICAgICAgICAgICAgICAgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OndlYl9pbWFnZSh4LCBoZWlnaHQgPSAxMDApfSkgJT4lICB0YWJfc3R5bGUoDQogICAgc3R5bGUgPSBjZWxsX2ZpbGwoY29sb3IgPSAicGluayIpLA0KICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IHZhcnMoc2NvcmUpLA0KICAgICAgcm93cyA9IHNjb3JlID4gNSApKSAlPiUgdGFiX3N0eWxlKA0KICAgIHN0eWxlID0gY2VsbF9maWxsKGNvbG9yID0gImxpZ2h0Z3JlZW4iKSwNCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSB2YXJzKHJhbmtpbmcpLA0KICAgICAgcm93cyA9IHJhbmtpbmcgPiAyICkpICU+JSAgZGF0YV9jb2xvcihjb2x1bW5zID0gdmFycyhuYW1lKSwNCiAgICBjb2xvcnMgPSAibGlnaHRibHVlIikNCiAgICAgICAgDQpgYGANCg0KIyMgQ29tcGFyYWNpw7NuIGNvbiBsYXMgcGVsw61jdWxhcyBjb24gbcOhcyBPc2NhcnMNCmBgYHtyfQ0KI3RvcDMwIHBlbGlzIGNvbiBtw6FzIG9zY2Fycw0KcGVsaXNfbWF4X29zY2FycyA8LSBvc2NhcnNfcGVsaXMgJT4lIGZpbHRlcih5ZWFyX2ZpbG0gPiAxOTg2KSAlPiUgYXJyYW5nZShkZXNjKHdpbnMpKSAlPiUgaGVhZCgzMSkgJT4lIG11dGF0ZShhY3RfZGlyX3Byb2QgPSAidG9wXzMwIikNCg0KcGVsaXNfbWF4X29zY2FycyA8LSBwZWxpc19tYXhfb3NjYXJzWy1jKDEpLCBdDQoNCnBlbGlzX29zY19maW4gPC0gbGVmdF9qb2luKG9zY2Fyc19wZWxpc19kZiwgcGVsaXNfbWF4X29zY2FycywgYnkgPSBjKCJuYW1lIiA9ICJmaWxtIikpDQoNCnBlbGlzX29zY19maW4gPC0gcGVsaXNfb3NjX2ZpbiAlPiUgc2VsZWN0KHllYXJfZmlsbSA9IHllYXJfZmlsbS54LCB5ZWFyX2NlcmVtb255ID0geWVhcl9jZXJlbW9ueS55LCBjZXJlbW9ueSA9IGNlcmVtb255LnksIGNhdGVnb3J5ID0gY2F0ZWdvcnkueSwgbmFtZSA9IG5hbWUueSwgZmlsbSA9IG5hbWUsIHdpbm5lciA9IHdpbm5lci55LCB3aW5zID0gd2lucy55KSAlPiUgbXV0YXRlKGFjdF9kaXJfcHJvZCA9ICJmaW5hbCIpDQoNCnBlbGlzX29zY2Fyc19maW4gPC0gdW5pb24ocGVsaXNfb3NjX2ZpbiwgcGVsaXNfbWF4X29zY2FycykNCg0KcGVsaXNfb3NjYXJzX2ZpbiA8LSBwZWxpc19vc2NhcnNfZmluICU+JSBhcnJhbmdlKGRlc2Mod2lucykpICU+JSBoZWFkKDMyKQ0KDQpwZWxpc19vc2NhcnNfZmluIDwtIHBlbGlzX29zY2Fyc19maW5bLWMoMiwgMTkpLCBdDQoNCg0KcGVsaXNfbGlzdF8zIDwtIHBlbGlzX29zY2Fyc19maW4gJT4lIG11dGF0ZShyYW5raW5nID0gY2FzZV93aGVuKA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxtID09ICJUaXRhbmljIiB+IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbG0gPT0gIlNhdmluZyBQcml2YXRlIFJ5YW4iIH4gMTUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgIH4gIDAgKSklPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGFjdF9kaXJfcHJvZCA9PSAiZmluYWwiKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoZmlsbSwgcmFua2luZywgd2lucykNCiNlbiBlbCB1bHRpbW8gbW9tZW50byBtZSBkYWJhIGVycm9yIGxvIGRlIG11dGF0ZShyYW5raW5nID0gYygxOjMwKSkgaGFiacOpbmRvbWUgZnVuY2lvbmFkbyBhbnRlcywgeSB0dXZlIHF1ZSBoYWNlciBsYSBjaGFwdXphIGNvbiBlbCBjYXNlX3doZW4uDQoNCnVybHNfb3NjIDwtIGMoImh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2VuLzEvMTkvVGl0YW5pY18lMjhPZmZpY2lhbF9GaWxtX1Bvc3RlciUyOS5wbmciLCAgImh0dHBzOi8vZXMud2ViLmltZzMuYWNzdGEubmV0L3BpY3R1cmVzLzE0LzAzLzA1LzA5LzQyLzE2MzYyMS5qcGciKQ0Kb3NjX3VybHMgPC0gcGVsaXNfbGlzdF8zICU+JSBhZGRfY29sdW1uKHVybHNfb3NjKQ0KDQpvc2NfdXJscyAlPiUgZ3QoKSAlPiUNCiAgZ3Q6OnRleHRfdHJhbnNmb3JtKGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IHZhcnModXJsc19vc2MpKSwNCiAgICAgICAgICAgICAgICAgICAgIGZuID0gZnVuY3Rpb24oeCkge2d0Ojp3ZWJfaW1hZ2UoeCwgaGVpZ2h0ID0gMTAwKX0pJT4lDQogICBkYXRhX2NvbG9yKGNvbHVtbnMgPSB2YXJzKGZpbG0pLA0KICAgIGNvbG9ycyA9ICJsaWdodGJsdWUiKSAlPiUNCiAgZGF0YV9jb2xvcihjb2x1bW5zID0gdmFycyhyYW5raW5nKSwNCiAgICBjb2xvcnMgPSAicGluayIpJT4lDQogICBkYXRhX2NvbG9yKGNvbHVtbnMgPSB2YXJzKHdpbnMpLA0KICAgIGNvbG9ycyA9ICJraGFraSIpICU+JSB0YWJfc3R5bGUoDQogICAgc3R5bGUgPSBjZWxsX2ZpbGwoY29sb3IgPSAib3JhbmdlIiksDQogICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gdmFycyh3aW5zKSwNCiAgICAgIHJvd3MgPSB3aW5zID4gNSApKSAlPiUgdGFiX3N0eWxlKA0KICAgIHN0eWxlID0gY2VsbF9maWxsKGNvbG9yID0gImxpZ2h0Z3JlZW4iKSwNCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSB2YXJzKHJhbmtpbmcpLA0KICAgICAgcm93cyA9IHJhbmtpbmcgPCAyICkNCiAgKQ0KDQpgYGANCg0KUGFyYSBjb25jbHVpciB0ZW5lbW9zIHF1ZSBkZXN0YWNhciBsYXMgcGVsw61jdWxhcyBUaXRhbmljIHkgU2FsdmFyIGFsIHNvbGRhZG8gUnlhbiwgYW1iYXMgY29uIHByb3RhZ29uaXN0YSB5IGRpcmVjdG9yIHF1ZSBjdW1wbMOtYW4gbG9zIDMgcmVxdWlzaXRvcyB5IGVsIHJlc3VsdGFkbyBoYSBkYWRvIHN1cyBmcnV0b3MuDQoNClRpdGFuaWMgZnVlIGVuIHN1IG1vbWVudG8gbGEgcGVsw61jdWxhIG3DoXMgdGFxdWlsbGVyYSBkZSBoaXN0b3JpYSAoYWhvcmEgbGEgbsO6bWVybyAzKSB5IGxhIHF1ZSBtw6FzIMOTc2NhcnMgc2UgbGxldsOzLiBTYWx2YXIgYWwgc29sZGFkbyBSeWFuIHNlIGVuY3VlbnRyYSBlbiBlbCBwdWVzdG8gMTUgZGUgbGFzIHBlbMOtY3VsYXMgbWVqb3IgdmFsb3JhZGFzIHBvciBsb3MgdXN1YXJpb3MgZGUgaW1kYiB5IGFkZW3DoXMgc2UgZW5jdWVudHJhIHRhbWJpw6luIGVuIGVsIHB1ZXN0byAxNSBkZSBsYXMgcGVsw61jdWxhcyBjb24gbcOhcyBPc2NhcnMgKGNvbiA1IGdhbGFyZG9uZXMpLg0KDQpTb2JyZSBzaSBlbCDDqXhpdG8gZGUgZXN0YXMgcGVsw61jdWxhcyBlcyBkZWJpZG8gYSBsYSBlbGVjY2nDs24gZGVsIGFjdG9yIHByaW5jaXBhbCwgZGlyZWN0b3IgbyBwcm9kdWN0b3JhIG5vIHNlIHB1ZWRlIGRlY2lyIGNvbiB0b3RhbCBwcmVjaXNpw7NuLiANCg0KRW4gZWwgY2FzbyBkZSBUaXRhbmljIGVzIGRpZsOtY2lsIGRlIGRlY2lyLCB5YSBxdWUgc2UgcHVlZGUgZGlzY3V0aXIgc2kgbGFzIGZpZ3VyYXMgZGUgSmFtZXMgQ2FtZXJvbiB5IExlb25hcmRvIERpY2FwcmlvIGVzdGFiYW4gdGFuIGNvbnNvbGlkYWRhcyBjb21vIGhveSBlbiBkw61hLiANCg0KRW4gZWwgY2FzbyBkZSBTYWx2YXIgYWwgc29sZGFkbyBSeWFuIHPDrSBxdWUgc2UgcG9kcsOtYSBkZWNpciBjb24gbcOhcyBzZWd1cmlkYWQgcXVlIHRhbnRvIFN0ZXZlbiBTcGllbGJlcmcgY29tbyBUb20gSGFua3MgZXN0YWJhbiBtw6FzIGNvbnNvbGlkYWRvcywgcHVlc3RvIHF1ZSBTcGllbGJlcmcgeWEgdGVuw61hIHVuIE9zY2FyIChnYW7DsyBlbCBzZWd1bmRvIHByZWNpc2FtZW50ZSBjb24gZXN0YSBwZWzDrWN1bGEpIHkgSGFua3MgdGVuw61hIGRvcy4gVGFtYmnDqW4gaGVtb3MgdmlzdG8gcXVlIGFtYm9zIHNvbiBsb3MgcXVlIG3DoXMgcmVjYXVkYW4gZW4gc3Ugb2ZpY2lvLg0KDQojIEJpYmxpb2dyYWbDrWENCg0KSW5mb3JtYWNpw7NuIHNvYnJlIGxvcyBbNSBNYWpvcnNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01ham9yX2ZpbG1fc3R1ZGlvcykNCg0KRWRpY2nDs24gZGUgdGFibGFzOg0KDQotIDxodHRwczovL3d3dy5saXR0bGVtaXNzZGF0YS5jb20vYmxvZy9wcmV0dHl0YWJsZXM+DQotIDxodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL0RULzAxMC1zdHlsZS5odG1sPg0KDQpUZW1hIHkgY29sb3JlcyBkZSBsb3MgZ3LDoWZpY29zOg0KDQotIDxodHRwczovL3d3dy5kYXRhbm92aWEuY29tL2VuL2Jsb2cvdG9wLXItY29sb3ItcGFsZXR0ZXMtdG8ta25vdy1mb3ItZ3JlYXQtZGF0YS12aXN1YWxpemF0aW9uLz4NCg0KLSA8aHR0cHM6Ly93d3cuc2hhbmVseW5uLmllL3RoZW1lcy1hbmQtY29sb3Vycy1mb3Itci1nZ3Bsb3RzLXdpdGgtZ2d0aGVtci8+