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 2021-2022. 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

El debate acerca de quién es el GOAT del tenis (el mejor jugador de todos los tiempos) se encuentra en su punto más álgido. Hasta mediados de 2008 no existía argumento que pudiese desbancar a Roger Federer de esta posición. Sin embargo, en la actualidad hay otros dos jugadores con méritos suficientes para disputar este título honorífico a Su Majestad Roger Federer. Ellos son Rafael Nadal y Novak Djokovic.

“Si alguien dice que soy mejor que Roger, creo que no sabe nada sobre el tenis” Rafael Nadal

No resulta tarea sencilla establecer qué jugador es el mejor de todos los tiempos. Lo logrado por parte de Federer, Nadal y Djokovic durante estos últimos 20 años es un hito que difícilmente se volverá a repetir. La hegemonía de estos tres deportistas apenas ha podido ser quebrada por unos pocos, creando una de las rivalidades más apasionantes de la historia de este deporte.


Djokovic, Nadal y Federer junto al trofeo al número 1 del año.

A lo largo del documento trataremos de analizar cuál de estos grandes tenistas merece ser el GOAT del tenis. Para la realización de esta tarea, estableceremos una serie de criterios lo más objetivos posibles. No obstante, ante la posibilidad de no poder clarificar quién ha hecho más méritos debido a la grandeza de estos deportistas, al menos trataremos de aportar una visión más objetiva de en qué aspectos cada jugador ha sobresalido respecto al resto.

2. Datos

Para poder lograr obtener alguna conclusión, necesitamos datos a través de los cuáles obtener información. A lo largo del documento, haremos uso principalmente de tres datasets, los cuáles se muestran a continuación.

Dataset Grand Slams

Uno de los criterios más usados para afirmar si un jugador ha logrado mayores éxitos que otro, es el número de Grand Slams que ha obtenido. Toda la información acerca de los campeones y subcampeones de Grand Slam se muestra a continuación.

grand_slams <- rio::import(here::here("datos", "grand_slam_tidy.xlsx"))

grand_slams <- SharedData$new(grand_slams)

bscols(widths = c(3,NA,NA),
       list(filter_slider("Año", "Año", grand_slams, ~Año, width = "100%"),
            filter_checkbox("Major", "Major", grand_slams, ~Major, columns =1),
            filter_select("Campeón", "Campeón", grand_slams, ~Campeón),
            filter_select("Subcampeón", "Subcampeón", grand_slams, ~Subcampeón)),
       reactable(grand_slams, minRows = 10, defaultPageSize =  10, 
                 paginationType = "jump",  showPageSizeOptions =  TRUE , 
                 pageSizeOptions =  c ( 10 , 50 , 100 ),defaultColDef = colDef(
                   align = "center",
                   minWidth = 70,
                   headerStyle = list(background = "lightgreen"),
                   filterable = FALSE), highlight = TRUE,
                 outlined = TRUE))

Dataset Temporadas

Las temporadas de tenis constan de numerosos torneos a lo largo y ancho del planeta desde enero hasta mediados/finales de noviembre. Gracias al dataset siguiente, tenemos los datos más relevantes de todos los partidos desde el año 2000 hasta el 2021. No obstante, para una mejor visualización de los datos, hemos juntado las distintas temporadas en un solo dataset y se han elegido las variables más relevantes entre las más de 30 de las que disponemos.

temporadas <- SharedData$new(temporadas)

bscols(widths = c(3,NA,NA),
       list( filter_checkbox("Series", "Series", temporadas, ~Series, columns =1), 
             filter_slider("Date", "Date",
                           temporadas, ~Date, width = "100%"),
             filter_checkbox("Surface", "Surface", temporadas, ~Surface, columns =1),
             filter_select("Winner", "Winner", temporadas, ~Winner),
             filter_select("Loser", "Loser", temporadas, ~Loser)),
       reactable(temporadas, minRows = 10, defaultPageSize =  10, 
                 paginationType = "jump",  showPageSizeOptions =  TRUE , 
                 pageSizeOptions =  c ( 10 , 50 , 100 ),defaultColDef = colDef(
                   align = "center",
                   minWidth = 70,
                   headerStyle = list(background = "lightgreen"),
                   filterable = FALSE), highlight = TRUE,
                 outlined = TRUE))

Dataset Ranking

El ranking ATP se forma a través de los puntos que otorgan los torneos a los jugadores según su resultado en el mismo. En el dataset siguiente se muestra el top 1000 del ranking ATP desde enero del 2000 hasta la actualidad. Cabe destacar que, por motivos de simplicidad, se ha reducido su dimensión y solo se mostrará el top 10 semanal.

ranking <- SharedData$new(ranking)

bscols(widths = c(3,NA,NA),
       list(filter_select("ranking_date", "ranking_date",
                           ranking, ~ranking_date),
            filter_select("name", "name", ranking, ~name),
            filter_slider("rank", "rank", ranking, ~rank, width = "100%")),
       reactable(ranking, minRows = 10, defaultPageSize =  10, 
                 paginationType = "jump",  showPageSizeOptions =  TRUE , 
                 pageSizeOptions =  c ( 10 , 50 , 100 ),defaultColDef = colDef(
                   align = "center",
                   minWidth = 70,
                   headerStyle = list(background = "lightgreen"),
                   filterable = FALSE), highlight = TRUE,
                 outlined = TRUE))

3. Criterio 1: Mayor cantidad de títulos por categoría

Los fanáticos del tenis sabrán que los torneos profesionales se dividen en cuatro categorías más la Copa de Maestros y los JJOO. En este apartado trataremos de analizar qué jugador han ganado más torneos según la categoría.

3.1 Torneos de Grand Slam

Grand Slams

Los Grand Slams son los torneos más importantes y prestigiosos del tenis. Esta categoría está formada por cuatro torneos (Australian Open, Roland Garros, Wimbledon y el US Open) y se celebran una vez cada uno a lo largo del año. Los jugadores que logran ganar alguno de estos torneos obtienen 2000 puntos para el ránking más el prestigio de ganar uno de los grandes del tenis.

En este último año, la prensa se ha hecho eco de la hazaña lograda por Djokovic, ganando tres de los cuatro Grand Slams del año y empatando de esta forma a 20 torneos major ganados con Federer y Nadal. En el gráfico que se muestra a continuación, se observa la evolución de Grand Slams ganados por parte de estos tres jugadores.

grand_slams <- rio::import(here::here("datos",
                                      "grand_slam_tidy.xlsx"))

big3 <- grand_slams %>% 
  filter(Campeón %in% c("Rafael Nadal", "Novak Djokovic", 
                        "Roger Federer")) %>% 
  select(Año, Campeón) %>% group_by(Año, Campeón) %>%
  summarise(por_año = n()) %>% ungroup() %>% group_by(Campeón) %>%
  mutate(n_grand_slam = cumsum(por_año)) %>%
  mutate(n_grand_slam = as.numeric(n_grand_slam)) %>% ungroup()

big3 %>% ggplot(aes(x= Año, y= n_grand_slam)) + 
  labs(title = "Evolución Grand Slams ganados\npor el Big 3",
       x= "Año",
       y= "Número de Grand Slams",
       color = "Jugador") +
  geom_point(aes(color= Campeón), size= 3) +
  geom_line(aes(color= Campeón), size= 1.5) + 
  scale_color_manual(values = c("midnightblue", "darkgreen",
                                "sienna"), 
                     breaks = c("Roger Federer", "Rafael Nadal",
                                "Novak Djokovic")) +
  theme_minimal() +
  theme(plot.title = element_text(size = 20, face = "bold", 
                                  hjust = 0.5),
        axis.title.x = element_text(size = 13, hjust = 1, vjust = 0),
        axis.title.y = element_text(size = 13, hjust = 1, vjust = 1),
        legend.title = element_text(face = "bold")) +
  geom_text(aes(x = min(Año), y = min(n_grand_slam), 
                label = as.factor(Año)) , hjust= 0, vjust = -6.2,
            alpha = 1,  col = "gray", size = 20) +
  transition_reveal(Año) + 
  view_follow()

El primer jugador en alcanzar los 20 Grand Slams ganados fue Roger Federer, seguido de Rafael Nadal y, finalmente este año, Djokovic alcanzó esta cifra. Es difícil decir qué jugador terminará con un mayor número de Grand Slams. Por el momento la tendencia favorece a Djokovic, ya que en este año ha logrado ganar tres de estos torneos, mientras que ni Nadal ni Federer se han conseguido hacer con uno.

Curiosidad

Siempre que llega un Grand Slam las casas de apuestas se llenan de predicciones sobre quién será la sorpresa del torneo. Ver ganar un Grand Slam a un jugador de fuera del Top 5 es algo bastante extraño en el tenis masculino. No tanto en el tenis femenino, donde este tipo de sorpresas son más habituales. El último caso fue el de la tenista británica Raducanu, quién en el pasado US Open ganó su primer grande siendo la número 150 del ranking WTA.

No obstante, volviendo al tenis masculino, ¿en qué torneo de Grand Slam se han dado más sorpresas?

no_serie <- grand_slams %>% group_by(Major) %>% summarise(`No cabeza de serie` = sum(is.na(Cabeza_serie_campeón))) %>% arrange(desc(`No cabeza de serie`))

serie1 <- grand_slams %>% group_by(Major) %>% filter(Cabeza_serie_campeón == 1) %>% summarise(`Cabeza de serie 1` = n()) %>% arrange(desc(`Cabeza de serie 1`))

serie_menor_4 <- grand_slams %>% group_by(Major) %>% filter(Cabeza_serie_campeón <= 4) %>% summarise(`Cabeza de serie < 4` = n()) %>% arrange(desc(`Cabeza de serie < 4`))

serie_entre_4_y_10 <- grand_slams %>% group_by(Major) %>% filter(Cabeza_serie_campeón > 4 & Cabeza_serie_campeón <= 10) %>% summarise(`Cabeza de serie entre 4 y 10` = n()) %>% arrange(desc(`Cabeza de serie entre 4 y 10`))

serie_entre_10_y_32 <- grand_slams %>% group_by(Major) %>% filter(Cabeza_serie_campeón > 10 & Cabeza_serie_campeón <= 32) %>% summarise(`Cabeza de serie > 10` = n()) %>% arrange(desc(`Cabeza de serie > 10`))

a1 <- full_join(serie_menor_4, serie_entre_4_y_10, by= c("Major" = "Major"))  

a2 <- full_join(a1, serie_entre_10_y_32, by= c("Major" = "Major"))  

a3 <- full_join(a2, no_serie, by= c("Major" = "Major"))

a4 <- a3 %>% pivot_longer(cols = 2:5, names_to = "Cabeza de serie", values_to = "Ganadores", values_transform = list(Ganadores = as.numeric))

a5 <- a4 %>% mutate(`Cabeza de serie` = forcats::as_factor(`Cabeza de serie`))

ggplot(a5, aes(x=Major, y= Ganadores, fill= `Cabeza de serie`)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Número de ganadores por cabeza de serie") +
  scale_x_discrete(labels = c("Australian\nOpen", "Roland\nGarros", "US\nOpen", "Wimbledon")) +
  theme_ipsum() +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        legend.title = element_text(face = "bold"),
        axis.title.x = element_text(size = 13, face = "bold"),
        axis.title.y = element_text(size = 13, face = "bold"))

La gráfica anterior nos muestra que el torneo dónde más sorpresas se han producido es Roland Garros. Históricamente es el torneo en el que menos veces ha ganado un jugador del Top 4 y en que más veces ha ganado un jugador que llegaba al torneo sin ser ser cabeza de serie (jugador dentro de los 32 jugadores con mejor ranking inscritos al torneo). Por otra parte, Wimbledon es el torneo en el que más veces ha ganado un cabeza de serie menor al 4 y el US Open el torneo en el que es menos probable que un jugador sin ser cabeza de serie gane.

Estos datos resultarán de gran interés para quién desee apostar esta temporada que empieza. Pero cuidado, desde que Rafael Nadal impuso su ley en Roland Garros, en 13 de las últimas 17 ediciones del torneo el ganador ha sido el tenista español. Sin duda, la mejor opción para la victoria.

3.2 Resto de torneos

Continuando con el análisis, prestaremos atención a los resultados obtenidos en el resto de torneos profesionales por parte de estos tenistas.

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

m1000 <- a %>% filter(Series %in% c("Masters 1000", "Masters"), Round == "The Final", Winner %in% c("Nadal R.", "Federer R.", "Djokovic N.")) %>% group_by(Winner) %>% summarise(total_masters_1000 = n())

masters <- a %>% filter(Series %in% c("Masters Cup"), Round == "The Final", Winner %in% c("Nadal R.", "Federer R.", "Djokovic N.")) %>% group_by(Winner) %>% summarise(total_masters_cup = n())

atp500 <- a %>% filter(Series %in% c("ATP500", "International Gold"), Round == "The Final", Winner %in% c("Nadal R.", "Federer R.", "Djokovic N.")) %>% group_by(Winner) %>% summarise(total_atp_500 = n())

atp250 <- a %>% filter(Series %in% c("ATP250", "International"), Round == "The Final", Winner %in% c("Nadal R.", "Federer R.", "Djokovic N.")) %>% group_by(Winner) %>% summarise(total_atp_250 = n())

total<- full_join(masters, m1000, by= c("Winner" = "Winner"))
jjoo <- c(0,0,1)
total <- cbind(total, jjoo)
total <- full_join(total, atp500, by= c("Winner" = "Winner"))
total <- full_join(total, atp250, by= c("Winner" = "Winner"))
total <- total %>% 
  select(Winner, total_masters_cup, jjoo, total_masters_1000,
         total_atp_500, total_atp_250) %>% 
  mutate(total_masters_cup = 
           ifelse(is.na(total_masters_cup), 0, total_masters_cup)) %>%
  pivot_longer(cols = 2:6, names_to = "Categoría", values_to = "Número") 

total <- total %>% pivot_wider(names_from = "Winner", values_from = "Número") %>% mutate(Categoría = case_when(
  Categoría == "total_masters_cup" ~ "Copa de Maestros",
  Categoría == "jjoo" ~ "Juegos Olímpicos",
  Categoría == "total_masters_1000" ~ "Masters 1000",
  Categoría == "total_atp_500" ~ "ATP 500",
  Categoría == "total_atp_250" ~ "ATP 250",
  TRUE ~ Categoría))

total %>% gt(rowname_col = "Categoría") %>% 
  tab_header(title = "Número de torneos por categoría",
             subtitle = "Excluyendo torneos de Grand Slam") %>% 
  tab_options(heading.background.color = "#D4AF37") %>% tab_options(heading.title.font.size = 22, heading.subtitle.font.size = 15,  column_labels.font.weight =  "bold") %>% 
  cols_align(align = "center") %>% 
  cols_label(
    `Djokovic N.` = "Novak Djokovic",
    `Federer R.` = "Roger Federer",
    `Nadal R.` = "Rafael Nadal") %>% 
  cols_move_to_start(
    columns = c(`Federer R.`, `Nadal R.`, `Djokovic N.`)) %>% 
  tab_footnote(
    footnote = "Medalla de oro en individuales",
    locations = cells_stub(rows = 2)) %>% 
  tab_footnote(
    footnote = "Previo a 2009 llamados International Gold",
    locations = cells_stub(rows = 4)) %>% 
  tab_footnote(
    footnote = "Previo a 2009 llamados International",
    locations = cells_stub(rows = 5)) %>% 
  tab_style(style = list(cell_fill(color = "green")),
            locations = cells_body(columns = `Federer R.`,
      rows = c(1, 4, 5))) %>% 
  tab_style(style = list(cell_fill(color = "green")),
            locations = cells_body(columns = `Nadal R.`,
                                   rows = 2))  %>% 
  tab_style(style = list(cell_fill(color = "green")),
            locations = cells_body(columns = `Djokovic N.`,
                                   rows = 3)) 
Número de torneos por categoría
Excluyendo torneos de Grand Slam
Roger Federer Rafael Nadal Novak Djokovic
Copa de Maestros 6 0 5
Juegos Olímpicos1 0 1 0
Masters 1000 28 36 37
ATP 5002 24 21 14
ATP 2503 25 10 10

1 Medalla de oro en individuales

2 Previo a 2009 llamados International Gold

3 Previo a 2009 llamados International

Se torna complicado concluir qué jugador presenta mejores cifras. Entre los tres se reparten el liderato en las tres categorías de importancia restantes. Federer es el jugador que mayor número de Copas de Maestro tiene. Por otro lado, Nadal es el único de los tres en obtener una medalla de oro en individuales en unos Juegos Olímpicos. Y en cuanto a Masters 1000 se refiere, es Djokovic el que lidera esta clasificación con 37, uno más que los ganados por Nadal. Finalmente, es lógico que Federer sea el jugador que mayor cantidad de torneos ATP 500 y ATP 250 ha ganado, puesto que es 5 y 6 años mayor que Nadal y Djokovic, respectivamente.

De esta forma, no es posible concluir qué jugador del Big 3 tiene mejores números en cuanto a torneos ganados a día de hoy. Esto se debe a que las actuaciones de estos tres jugadores es sobresaliente en cada categoría. Deberemos seguir repasando distintos criterios para tratar de dar respueta a nuestra cuestión.

4. Criterio 2: Ranking ATP

La importancia entre ganar un torneo u otro se define, entre otros aspectos como el prestigio, por la cantidad de puntos que reparte. En este apartado analizaremos cómo ha sido en rendimiento de estos tres jugadores a lo largo del tiempo.

jugadores <- jugadores %>% mutate(name = paste(name_first, name_last, sep = " "), .after = player_id) %>% select(player_id, name, ioc)

### Evolución puntos ATP

dd <- left_join(ranking, jugadores, by = c("player" = "player_id")) %>% filter(name %in% c("Rafael Nadal", "Roger Federer", "Novak Djokovic")) %>% mutate(ranking_date = ymd(ranking_date)) %>% mutate(points = as.numeric(points), rank = as.numeric(rank)) %>% select(ranking_date, points, name) %>% pivot_wider(names_from = "name", values_from = "points")

Federer <- xts(dd$`Roger Federer`, order.by = dd$ranking_date)

Nadal <- xts(dd$`Rafael Nadal`, order.by = dd$ranking_date)

Djokovic <- xts(dd$`Novak Djokovic`, order.by = dd$ranking_date)

p <- cbind(Federer, Nadal, Djokovic) 

dygraph(p, ylab= "Puntos ATP",
        main = "Evolución puntos ATP del Big 3") %>% 
  dyOptions(colors = c("blue", "green", "brown")) %>% 
  dyRangeSelector() 

Con el fin de observar el rendimiento del Big 3, hemos calculado la cantidad de puntos de cada jugador durante cada semana del año desde la temporada del año 2000, motivo por el cuál Federer empieza el periodo con alrededor de 900 puntos. Es increíble observar la regularidad de estos tres jugadores a lo largo de los años, siempre muy por encima de los 2000 puntos. Para que nos hagamos una idea, alrededor de 2000 puntos son los que necesita conseguir un jugador en un año para estar dentro del Top 20…

Sin embargo, podemos apreciar que el rendimiento y regularidad es algo mayor en Djokovic que en el resto, a excepción del periodo que abarca desde mediados de 2017 hasta finales de 2018 en el que el tenista balcánico sufrió problemas de espalda.

ranking2 <- ranking

Top_1 <- left_join(ranking2, jugadores, by = c("player" = "player_id")) %>% filter(name %in% c("Rafael Nadal", "Roger Federer", "Novak Djokovic")) %>% mutate(ranking_date = ymd(ranking_date)) %>% mutate(points = as.numeric(points), rank = as.numeric(rank)) %>% select(ranking_date, rank, name) %>% filter(rank == 1) %>% group_by(name) %>% summarise(Top1 = n()) 

Tot <- left_join(ranking2, jugadores, by = c("player" = "player_id")) %>% filter(name %in% c("Rafael Nadal", "Roger Federer", "Novak Djokovic")) %>% mutate(ranking_date = ymd(ranking_date)) %>% mutate(points = as.numeric(points), rank = as.numeric(rank)) %>% select(ranking_date, rank, name) %>% drop_na() %>%  group_by(name) %>% summarise(Tot = n())

Top_3 <- left_join(ranking2, jugadores, by = c("player" = "player_id")) %>% filter(name %in% c("Rafael Nadal", "Roger Federer", "Novak Djokovic")) %>% mutate(ranking_date = ymd(ranking_date)) %>% mutate(points = as.numeric(points), rank = as.numeric(rank)) %>% select(ranking_date, rank, name) %>% filter(rank <= 3) %>% group_by(name) %>% summarise(Top3 = n())

Top_10 <- left_join(ranking2, jugadores, by = c("player" = "player_id")) %>% filter(name %in% c("Rafael Nadal", "Roger Federer", "Novak Djokovic")) %>% mutate(ranking_date = ymd(ranking_date)) %>% mutate(points = as.numeric(points), rank = as.numeric(rank)) %>% select(ranking_date, rank, name) %>% filter(rank <= 10) %>% group_by(name) %>% summarise(Top10 = n())

tabla <- left_join(Top_1, Top_3, by = c("name" = "name"))

tabla <- left_join(tabla, Top_10, by = c("name" = "name"))

tabla <- left_join(tabla, Tot, by = c("name" = "name"))

tabla <- tabla %>% mutate(Top1_porc = Top1/Tot, .after = Top1) %>% mutate(Top3_porc = Top3/Tot, .after = Top3) %>% mutate(Top10_porc = Top10/Tot, .after = Top10) 
  
tabla %>% gt(rowname_col = "name") %>% 
  tab_header(title = "Numero de semanas top del ranking ATP",
                      subtitle = "Jugadores del Big3") %>% 
  tab_options(heading.background.color = "#CD7F32") %>% tab_options(heading.title.font.size = 22, heading.subtitle.font.size = 15,  column_labels.font.weight =  "bold") %>% 
  cols_align(align = "center") %>% 
  cols_label(
    Top1 = "Top 1",
    Top1_porc = "Porcentaje",
    Top3 = "Top 3",
    Top3_porc = "Porcentaje",
    Top10 = "Top 10",
    Top10_porc = "Porcentaje",
    Tot = "Total") %>% 
  fmt_percent(columns= c(3, 5, 7), 
              decimals = 2) %>% 
  tab_style(style = list(cell_fill(color = "green")),
            locations = cells_body(columns = Top1,
                                   rows = 1)) %>% 
  tab_style(style = list(cell_fill(color = "green")),
            locations = cells_body(columns = Top1_porc,
                                   rows = 1))  %>% 
  tab_style(style = list(cell_fill(color = "green")),
            locations = cells_body(columns = Top3,
                                   rows = 3))  %>% 
  tab_style(style = list(cell_fill(color = "green")),
            locations = cells_body(columns = Top3_porc,
                                   rows = 1))  %>% 
  tab_style(style = list(cell_fill(color = "green")),
            locations = cells_body(columns = Top10,
                                   rows = 3)) %>% 
  tab_style(style = list(cell_fill(color = "green")),
            locations = cells_body(columns = Top10_porc,
                                   rows = 2)) 
Numero de semanas top del ranking ATP
Jugadores del Big3
Top 1 Porcentaje Top 3 Porcentaje Top 10 Porcentaje Total
Novak Djokovic 314 35.64% 590 66.97% 657 74.57% 881
Rafael Nadal 193 19.82% 614 63.04% 787 80.80% 974
Roger Federer 307 28.88% 709 66.70% 908 85.42% 1063

La tabla anterior nos termina de dar un visión acerca de los increíbles números de Novak Djokovic. El tenista serbio es el jugador de la historia que más semanas ha estado al frente del ranking mundial, seguido de Federer. Además, este récord se sigue ampliando semana tras semana, puesto que Djokovic es el actual número 1 del mundo. Además, es el jugador que más porcentaje de semanas ha estado en el Top 3. El único aspecto en el que no es el líder, es en el porcentaje de semanas dentro del Top 10. En este aspecto Nadal es el número 1, con más del 80% del tiempo que lleva como profesional dentro de los 10 mejores del mundo. Una muestra más de la precocidad y la regularidad del tenista español.

En este apartado, podemos concluir que Novak Djokovic es el mejor de todos los tiempos. Su récord al frente del ranking es, sin duda alguna, uno de los más dominantes del deporte mundial. Un récord difícilmente de superar y del que solo podemos sentir orgullo por haber podido vivirlo.

5. Criterio 3: Superficie de juego

El tenis es sin lugar a dudas uno de los deportes en los que existe una mayor diversidad de estilos y formas de juego. Esto, sumado a la existencia de las diferentes superficies de juego en las que se disputan los torneos, crean la combinación perfecta para que dependiendo de en la parte de la temporada en la que nos encontremos, las condiciones climáticas y la superficie de juego unos jugadores destaquen más sobre el resto que otros.

Históricamente existían 4 superficies de juego:

  • Tierra batida: pistas creadas en base a polvo de ladrillo que destacan por ser las más lentas y por un bote de bola alto.

  • Superficie dura: pistas de cemento cuya rapidez varía según el tipo de material con que se fabriquen.

  • Hierba: destacan por su rapidez y por su bajo bote de bola.

  • Moqueta: destacan por su alta velocidad de bola y por jugarse bajo techo.

Sin embargo, desde la temporada 2009, la ATP decidió eliminar los torneos que se disputaban sobre moqueta, remplazándolos por superficie dura. De esta forma, los distintos torneos disputados a lo largo del año se disputan o bien el tierra, dura o hierba y o bien al aire libre o bajo techo. Dependiendo la combinación de estos dos aspectos, las condiciones de juego cambian drásticamente.

De esta forma, se podría decir que existen distintos tipos de tenis. Por ello, a continuación trataremos de analizar el rendimiento del Big 3 de acuerdo al tipo de pista.

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

aa <- temporadas %>% filter(Winner %in% c("Federer R.", "Nadal R.", "Djokovic N."), Round == "The Final") %>% group_by(Surface, Court, Winner) %>% summarise(títulos = n()) %>% ungroup() %>% 
  mutate(Surface = case_when(
    Surface =="Carpet" ~  "Moqueta",
    Surface =="Clay" ~  "Tierra batida",
    Surface =="Grass" ~  "Hierba",
    Surface =="Hard" ~  "Dura")) %>% 
  mutate(Court = case_when(
    Court =="Indoor" ~  "Bajo techo",
    Court =="Outdoor" ~  "Aire libre")) %>% 
  mutate(Winner = case_when(
    Winner =="Federer R." ~  "Federer",
    Winner =="Nadal R." ~  "Nadal",
    Winner =="Djokovic N." ~  "Djokovic"))

ggplot(aa, aes(x = Winner, y = títulos, fill = Court)) +
  geom_bar(stat = "identity") +
  labs(title = "Número de títulos por superficie", 
       subtitle = "Superficie: {closest_state}",
       fill= "Tipo de pista") +
  geom_text(aes(label = títulos),
            position =  position_stack(vjust = 0.8),
            fontface= "bold",
            size = 5) +
  scale_fill_manual(values = c("grey", "yellow")) +
  theme_classic() +
  theme(axis.ticks.y=element_blank(), 
        axis.text.y=element_blank(),
        axis.text.x = element_text(size = 15),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        plot.title = element_text(size = 20, hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(size = 15, hjust = 0.5),
        legend.title = element_text(face = "bold", size = 15),
        legend.text = element_text(size = 12)) +
  transition_states(states = Surface, transition_length = 2, state_length = 1) + 
  enter_fade() + 
  exit_shrink() +
  ease_aes('sine-in-out')

Del gráfico anterior extraemos distintas conclusiones.

La primera, Rafael Nadal es el mejor jugador de la historia en tierra batida. Esta afirmación no es discutida por nadie hoy en día. Sus resultados sobre esta superficie son superlativos. Además, los ha conseguido en una de las eras más competitivas de la historia. Simplemente, no hay palabras para describir lo logrado por este jugador. Muy probablemente nadie más sea capaz de igualarle.

La segunda es acerca de la regularidad y versatilidad de Novak Djokovic. Sin duda, el jugador más versátil de la historia. Capaz de jugar rozando la perfección en el tipo de pista en la que juegue.

Y a tercera, Federer es el mejor en pistas de alta velocidad. Cuanto más rápida es una pista de tenis, la perfección suiza es capaz de mostrar al mundo el porqué de que la definición de tenis perfecto sea Federer.

6. Criterio 4: Mayor número de victorias ante jugadores Top

Seguimos tratando de dar una respuesta a ¿Quién es el GOAT del tenis?. Y para tratar de obtener una respuesta, es necesario realizar una parada para analizar cuál ha sido el rendimiento del Big 3 frente a otros grandes jugadores del circuito.

El gráfico que se muestra a continuación nos muestra las victorias y derrotas del Big 3 frente a jugadores cuyo ránking era:

  • Número 1 del mundo.

  • Entre el 2 y el 5 del mundo.

  • Entre el 6 y el 10 del mundo.

  • Entre el 11 y el 20 del mundo.

tt <- temporadas %>% filter(Winner %in% c("Federer R.", "Nadal R.", "Djokovic N.") | Loser %in% c("Federer R.", "Nadal R.", "Djokovic N.")) %>% mutate(WRank = as.numeric(WRank), LRank = as.numeric(LRank))

#Top 20
v_top20 <- tt %>% filter(Winner %in% c("Federer R.", "Nadal R.", "Djokovic N.") & LRank <= 20 & LRank > 10) %>% group_by(Winner) %>% summarise(Victorias = n())

d_top20 <- tt %>% filter(Loser %in% c("Federer R.", "Nadal R.", "Djokovic N.") & WRank <= 20 & WRank > 10) %>% group_by(Loser) %>% summarise(Derrotas = n())

Top20 <- full_join(v_top20, d_top20, by = c("Winner" = "Loser")) %>% pivot_longer(cols = 2:3, names_to = "V/D", values_to = "Número")

d <- c("Top 20", "Top 20", "Top 20", "Top 20", "Top 20", "Top 20")

Top20 <- cbind(Top20, d)


#Top 10
v_top10 <- tt %>% filter(Winner %in% c("Federer R.", "Nadal R.", "Djokovic N.") & LRank <= 10 & LRank > 5) %>% group_by(Winner) %>% summarise(Victorias = n())

d_top10 <- tt %>% filter(Loser %in% c("Federer R.", "Nadal R.", "Djokovic N.") & WRank <= 10 & WRank > 5) %>% group_by(Loser) %>% summarise(Derrotas = n())

Top10 <- full_join(v_top10, d_top10, by = c("Winner" = "Loser")) %>% pivot_longer(cols = 2:3, names_to = "V/D", values_to = "Número")

d <- c("Top 10", "Top 10", "Top 10", "Top 10", "Top 10", "Top 10")

Top10 <- cbind(Top10, d)

#Top 5
v_top5 <- tt %>% filter(Winner %in% c("Federer R.", "Nadal R.", "Djokovic N.") & LRank <= 5 & LRank > 1) %>% group_by(Winner) %>% summarise(Victorias = n())

d_top5 <- tt %>% filter(Loser %in% c("Federer R.", "Nadal R.", "Djokovic N.") & WRank <= 5 & WRank > 1) %>% group_by(Loser) %>% summarise(Derrotas = n())

Top5 <- full_join(v_top5, d_top5, by = c("Winner" = "Loser")) %>% pivot_longer(cols = 2:3, names_to = "V/D", values_to = "Número")

d <- c("Top 5", "Top 5", "Top 5", "Top 5", "Top 5", "Top 5")

Top5 <- cbind(Top5, d)

#Top 1
v_top1 <- tt %>% filter(Winner %in% c("Federer R.", "Nadal R.", "Djokovic N.") & LRank == 1) %>% group_by(Winner) %>% summarise(Victorias = n())

d_top1 <- tt %>% filter(Loser %in% c("Federer R.", "Nadal R.", "Djokovic N.") & WRank == 1) %>% group_by(Loser) %>% summarise(Derrotas = n())

Top1 <- full_join(v_top1, d_top1, by = c("Winner" = "Loser")) %>% pivot_longer(cols = 2:3, names_to = "V/D", values_to = "Número")

d <- c("Top 1", "Top 1", "Top 1", "Top 1", "Top 1", "Top 1")

Top1 <- cbind(Top1, d)

### Gráfico
Top <- rbind(Top1, Top5, Top10, Top20) %>% 
  mutate(Winner = case_when(
  Winner =="Federer R." ~  "Federer",
  Winner =="Nadal R." ~  "Nadal",
  Winner =="Djokovic N." ~  "Djokovic")) %>% 
  mutate(`V/D` = forcats::as_factor(`V/D`)) %>% 
  mutate(`V/D` = forcats::fct_reorder(`V/D`, Número, .desc = TRUE)) %>% 
  mutate(d = forcats::as_factor(d)) %>% 
  mutate(d = forcats::fct_reorder(d, Número, .desc = FALSE))

Top %>% ggplot() +
  geom_bar(aes(x= Winner, y= Número, fill= `V/D`), stat = "identity",
           position = "dodge") +
  scale_fill_viridis_d() +
  facet_wrap(vars(d)) +
  theme_test() +
  labs(title = "Estadísticas Victorias/Derrotas Big 3",
       subtitle = "Clasificación por ranking") +
  theme(plot.title = element_text(size = 20, hjust = 0.5),
        plot.subtitle = element_text(size = 15, hjust = 0.5),
        legend.title = element_blank(),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.x = element_text(size = 11),
        strip.text = element_text(face = "bold"))

Realizaremos este análisis dedicando a cada jugador su propio párrafo en relación al resto.

Empezaremos por Novak Djokovic. Aun siendo el más joven de los tres, es el que presenta mejores cifras entre victorias y derrotas frente a jugadores entre el 2 y 10 del mundo. Además, tiene un muy buen ratio cuando a enfrentado al número 1 del mundo.

Seguidamente tenemos a Roger Federer. Al ser el más veterano, es el jugador con más victorias frente a jugadores desde el 2 al 20 del ranking. No obstante, también el que más derrotas ha acumulado. Por otro lado, su rendimiento frente a números 1 del mundo es el más pobre de los tres. Un mayor y mejor análisis sería necesario para determinar los motivos detrás de este pobre rendimiento frente a números 1. Sin embargo, lo cierto es que es ampliamente superado por Djokovic y especialmente por Nadal en este aspecto.

Finalmente, Nadal. Su rendimiento frente a jugadores entre el 2 y 20 del ránking es el peor de los tres. Sin embargo, Nadal se lleva el título de mata gigantes. Es el único de los tres que tiene más victorias que derrotas ante números 1. Un logro al alcance únicamente del jugador español. Su pundonor y su tenis le llevan a ser el tenista más temido por los mejores.

7. Criterio 5: Temporada de inicio en la élite

El quinto de los criterios del que haremos uso es el rendimiento de estos tres jugadores en su temporada de inicio en la élite. Para poder utilizar este criterio, primero debemos determinar qué temporada consideramos que fue la primera en la que cada jugador comenzó a competir en la élite de este deporte. Esta no es una elección sencilla. No obstante, consideraremos la temporada en la que ganaron su primer Grand Slam como la temporada en la que cada miembro del Big 3 comenzó a ser considerado como un jugador de élite.

Estadísticas generales

En anteriores apartados pudimos desgranar los títulos ganados por cada jugador. De este análisis obtenemos tres años de especial relevancia: 2003, 2005 y 2008, los años en los que Roger Federer, Rafael Nadal y Novak Djokovic ganaron su primer Grand Slam, respectivamente. De esta forma, analizaremos como fue el rendimiento de cada jugador en su correspondiente año, el cuál pasaremos a considerar su temporada de inicio en la élite.

gan_fed <- temporada_03 %>% filter(Winner == "Federer R.") %>% group_by(Winner) %>% summarise(Ganados =n())

per_fed <- temporada_03 %>% filter(Loser == "Federer R.") %>% group_by(Loser) %>% summarise(Perdidos =n())

part_fed <- left_join(gan_fed, per_fed, by = c("Winner" = "Loser"))

## Nadal
gan_nad <- temporada_05 %>% filter(Winner == "Nadal R.") %>% group_by(Winner) %>% summarise(Ganados =n())

per_nad <- temporada_05 %>% filter(Loser == "Nadal R.") %>% group_by(Loser) %>% summarise(Perdidos =n())

part_nad <- left_join(gan_nad, per_nad, by = c("Winner" = "Loser"))

## Djokovic
gan_djo <- temporada_08 %>% filter(Winner == "Djokovic N.") %>% group_by(Winner) %>% summarise(Ganados =n())

per_djo <- temporada_08 %>% filter(Loser == "Djokovic N.") %>% group_by(Loser) %>% summarise(Perdidos =n())

part_djo <- left_join(gan_djo, per_djo, by = c("Winner" = "Loser"))

Foto <- c("https://www.atptour.com/-/media/tennis/players/head-shot/2020/federer_head_ao20.png", "https://www.atptour.com/-/media/tennis/players/head-shot/2020/nadal_head_ao20.png", "https://www.atptour.com/es/players/novak-djokovic/d643/www.atptour.com/-/media/tennis/players/head-shot/2019/djokovic_head_ao19.png")

Nacionalidad <- c("https://www.ecured.cu/images/2/20/Bandera_suiza.JPG", "https://upload.wikimedia.org/wikipedia/commons/thumb/8/89/Bandera_de_Espa%C3%B1a.svg/1200px-Bandera_de_Espa%C3%B1a.svg.png", "https://upload.wikimedia.org/wikipedia/commons/thumb/f/ff/Flag_of_Serbia.svg/1200px-Flag_of_Serbia.svg.png")

part <- rbind(part_fed, part_nad, part_djo) %>% mutate(Porcentaje = Ganados/(Ganados + Perdidos))

tabla <- cbind(Foto, part, Nacionalidad, Edad, Temporada, Títulos) %>%  
  mutate(Winner = case_when(
    Winner =="Federer R." ~  "Roger Federer",
    Winner =="Nadal R." ~  "Rafael Nadal",
    Winner =="Djokovic N." ~  "Novak Djokovic"))

tabla %>% gt(rowname_col = "Foto", groupname_col = "Winner") %>% 
  text_transform(locations = cells_stub(rows = 1:3), fn = function(x) {gt::web_image(x, height = 50)}) %>%
  text_transform(locations = cells_body(columns = vars(Nacionalidad)), fn = function(x) {gt::web_image(x, height = 50)}) %>% 
  cols_align(align = "center") %>% 
  cols_move_to_start(columns = "Edad") %>% 
  cols_move(columns = "Temporada",
            after = "Edad") %>% 
  cols_move(columns = "Títulos",
            after = "Temporada") %>% 
  tab_header(title = "Estadíticas Big 3",
             subtitle = "Temporada inicio en la élite") %>%
  tab_spanner(label = "Partidos",
              columns = c("Ganados", "Perdidos", "Porcentaje")) %>% 
  tab_options(heading.background.color = "#DAA520") %>% tab_options(heading.title.font.size = 30, heading.subtitle.font.size = 25,  column_labels.font.weight =  "bold") %>% 
  fmt_percent(columns = "Porcentaje", 
              decimals = 2)
Estadíticas Big 3
Temporada inicio en la élite
Edad Temporada Títulos Partidos Nacionalidad
Ganados Perdidos Porcentaje
Roger Federer
22 2003 7 74 16 82.22%
Rafael Nadal
19 2005 11 77 10 88.51%
Novak Djokovic
21 2008 4 58 15 79.45%

Al estar comparando diferentes años para cada jugador, la edad que cada jugador tenía en ese año varía. El jugador más joven en diputar su primera temporada en la élite fue Rafael Nadal. Con 19 años, el jugador español ganó en la temporada 2005 su primer Grand Slam. Además de ser el más joven, también fue el que mayor porcentaje de victorias tuvo en su temporada, ganando 77 de 87 partidos y obteniendo de esta forma 11 títulos ATP. Por su parte, Federer fue el más tardío en explotar, llegando a sus 22 años el primero de su Grand Slams en 2003. Finalmente, Djokovic es el menos laureado en su temporada de debut en la élite, sumando 3 títulos más a su primer Grand Slam.

No es descarado decir que la temporada de debut de Nadal fue la que más sobresalió. Ya no solo por el asombroso número de títulos, sino también por su corta edad. A continuación, podemos observar la distribución geográfica de los títulos de cada jugador.

## Federer
titulos_fed <- temporada_03 %>% filter(Winner == "Federer R.") %>% filter(Round == "The Final") %>% select(Location, Winner)

## Nadal
titulos_nad <- temporada_05 %>% filter(Winner == "Nadal R.") %>% filter(Round == "The Final") %>% select(Location, Winner)


## Djokovic
titulos_djo <- temporada_08 %>% filter(Winner == "Djokovic N.") %>% filter(Round == "The Final") %>% select(Location, Winner)


titulos <-rbind(titulos_fed, titulos_nad, titulos_djo)

iso2 <- c("FR", "AE", "DE", "DE", "GB", "AT", "US", "BR", "MX", "MC", "ES", "IT", "FR", "SE", "DE", "CA", "CN", "ES", "AU", "US", "IT", "CN" )

total <- cbind(iso2, titulos) %>%  
  mutate(Winner = case_when(
    Winner =="Federer R." ~  "Federer",
    Winner =="Nadal R." ~  "Nadal",
    Winner =="Djokovic N." ~  "Djokovic"))

long <- c(5.37639, 55.3077, 11.5753, 11.97, -0.1275, 16.3728, -95.3863, -37.9224, -99.8816, 7.41284, 2.16992, 12.4942, 2.3486000, 12.8529, 9.18278, -73.58781, 116.39723, -3.70325, 144.96332, -116.341, 12.4942, 121.469)

lat <- c(43.2967, 25.2646, 48.1369, 51.4828, 51.5072, 48.2092, 29.7805, -12.4319, 16.8638, 43.7503, 41.3879, 41.8905, 48.8534000, 56.4267, 48.7756, 45.50884, 39.9075, 40.4167, -37.814, 33.7052, 41.8905, 31.2323)

num <- c(1, 2, 1, 1, 1, 1, 3, 3, 3, 1, 1, 1, 1, 1, 1, 3, 2, 1, 2, 3, 1, 2)

torneos <- cbind(total, long, lat, num)

torneos1 <- torneos %>% filter(num == 1)

torneos2 <- torneos %>% filter(num == 2)

torneos3 <- torneos %>% filter(num == 3)

mapa_mundo <- map_data("world") %>% mutate(iso2 = countrycode::countrycode(sourcevar = region, origin = "country.name",destination =  "iso2c", warn = FALSE), .after = region) %>% select(long, lat, group, iso2)

mapa_mundo %>%
  ggplot() +
  geom_polygon(aes(x= long, y = lat, group = group), fill = "grey",
               color = "black", na.rm = FALSE) +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5, size = 18, face = "bold", vjust = 2),
        plot.subtitle = element_text(hjust = 0.5, size= 12, vjust = 2),
    axis.line = element_blank(),
    axis.text = element_blank(),
    axis.title = element_blank(),
    axis.ticks = element_blank(),
    panel.background = element_rect(colour= "black", size= 1, fill = "#9fd5d1"),
    legend.text = element_text(face = "bold"),
    legend.title = element_text(face = "bold")) +
  geom_point(data = torneos, mapping = aes(x= long, y= lat, color= Winner), size= 2.2) +
  coord_fixed (xlim= c(-200,200),
               ylim= c(-58,90),
               ratio = 2.2) +
  scale_color_manual(values = c("midnightblue", "seagreen", "yellow")) + 
  labs(title = "Distribución geográfica títulos Big 3",
       subtitle = "Representación temporada inicio élite",
       color = "Jugador")

En el mapa anterior no se aprecia fácilmente las conquistas de cada jugador. Por ello, dividiremos el mapa en tres zonas para poder observarlo con mayor precisión.

mapa_mundo %>%
  ggplot() +
  geom_polygon(aes(x= long, y = lat, group = group), fill = "grey",
               color = "black", na.rm = FALSE) +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5, size = 18, face = "bold", vjust = 2),
        plot.subtitle = element_text(hjust = 0.5, size= 12, vjust = 2),
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        panel.background = element_rect(colour= "black", size= 1, fill = "#9fd5d1"),
        legend.text = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) +
  geom_point(data = torneos3, mapping = aes(x= long, y= lat), color= "red", size= 2) +
  coord_fixed (xlim= c(-140,-35),
               ylim= c(-60,80))+
  geom_text_repel(data = torneos3, aes(x= long, y= lat, label = Location, color = Winner), fontface = "bold")  +
  scale_color_manual(values = c("midnightblue", "seagreen", "yellow")) + 
  labs(title = "Títulos continente americano del Big 3",
       subtitle = "Representación temporada inicio élite",
       color = "Jugador")

En cuanto a los títulos en suelo americano. Tanto Federer como Djokovic tan solo se pudieron hacer con uno de los torneos jugados en esta zona del planeta, mientras Nadal se hizo con 3 títulos, destacándose el Másters Series de Montreal.

mapa_mundo %>%
  ggplot() +
  geom_polygon(aes(x= long, y = lat, group = group), fill = "grey",
               color = "black", na.rm = FALSE) +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5, size = 18, face = "bold", vjust = 2),
        plot.subtitle = element_text(hjust = 0.5, size= 12, vjust = 2),
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        panel.background = element_rect(colour= "black", size= 1, fill = "#9fd5d1"),
        legend.text = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) +
  geom_point(data = torneos1, mapping = aes(x= long, y= lat), color="red", size= 2) +
  coord_fixed (x= c(-10,20),
               y= c(35, 70))+
  geom_text_repel(data = torneos1, aes(x= long, y= lat, label = Location, color = Winner), fontface = "bold") +
  scale_color_manual(values = c("midnightblue", "seagreen", "yellow")) + 
  labs(title = "Títulos continente europeo del Big 3",
       subtitle = "Representación temporada inicio élite",
       color = "Jugador")

En el continente europeo fue donde Federer logró 5 de sus 7 títulos del año. Nadal por su parte ganaría 7, siendo 2 de ellos en España. En la otra cara de la moneda, Djokovic a penas lograría uno en el Másters Series de Roma.

mapa_mundo %>%
  ggplot() +
  geom_polygon(aes(x= long, y = lat, group = group), fill = "grey",
               color = "black", na.rm = FALSE) +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5, size = 18, face = "bold", vjust = 2),
        plot.subtitle = element_text(hjust = 0.5, size= 12, vjust = 2),
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        panel.background = element_rect(colour= "black", size= 1, fill = "#9fd5d1"),
        legend.text = element_text(face = "bold"),
        legend.title = element_text(face = "bold")) +
  geom_point(data = torneos2, mapping = aes(x= long, y= lat), color="red", size= 2) +
  coord_fixed (x= c(50,150),
               y= c(-40, 50))+
  geom_text_repel(data = torneos2, aes(x= long, y= lat, label = Location, color = Winner), fontface = "bold") +
  scale_color_manual(values = c("midnightblue", "seagreen", "yellow")) + 
  labs(title = "Títulos en Asia y Oceanía del Big 3",
       subtitle = "Representación temporada inicio élite",
       color = "Jugador")

Finalmente nos centramos en Asia y Oceanía. En esta parte del globo, el tenista serbio obtuvo la mitad de sus títulos ese año. Nadal y Federer tan solo conquistarían uno cada uno, siendo la parte del mundo en la que menos títulos logró Nadal.

Evolución del ránking

Continuando con el análisis, otro aspecto a considerar es la evolución en el ránking de cada jugador a lo largo de su temporada de inicio.

# Evolución del ranking

## Federer
temporada_03 <- rio::import(here::here("datos", "atp_2003.xls")) %>% mutate(WRank = as.numeric(WRank), LRank = as.numeric(LRank))

rank_ini <- temporada_03 %>% filter(Winner == "Federer R." | Loser == "Federer R.") %>% slice(1) %>% select(Winner, WRank) %>% rename(`2003-01-01` = WRank)

rank_fin <- temporada_03 %>% filter(Winner == "Federer R." | Loser == "Federer R.") %>% slice(n()) %>% select(Winner, WRank) %>% rename(`2003-12-31` = WRank)

rank_fed <- full_join(rank_ini, rank_fin, by = c("Winner" = "Winner"))

## Nadal
temporada_05 <- rio::import(here::here("datos", "atp_2005.xls")) %>% mutate(WRank = as.numeric(WRank), LRank = as.numeric(LRank))

rank_ini <- temporada_05 %>% filter(Winner == "Nadal R." | Loser == "Nadal R.") %>% slice(1) %>% select(Winner, WRank) %>% rename(`2003-01-01` = WRank)

rank_fin <- temporada_05 %>% filter(Winner == "Nadal R." | Loser == "Nadal R.") %>% slice(n()) %>% select(Winner, WRank) %>% rename(`2003-12-31` = WRank)

rank_nad <- full_join(rank_ini, rank_fin, by = c("Winner" = "Winner"))

## Djokovic
temporada_08 <- rio::import(here::here("datos", "atp_2008.xls")) %>% mutate(WRank = as.numeric(WRank), LRank = as.numeric(LRank))

rank_ini <- temporada_08 %>% filter(Winner == "Djokovic N." | Loser == "Djokovic N.") %>% slice(1) %>% select(Winner, WRank) %>% rename(`2003-01-01` = WRank)

rank_fin <- temporada_08 %>% filter(Winner == "Djokovic N." | Loser == "Djokovic N.") %>% slice(n()) %>% select(Winner, WRank) %>% rename(`2003-12-31` = WRank)

rank_djo <- full_join(rank_ini, rank_fin, by = c("Winner" = "Winner"))


rank <- rbind(rank_fed, rank_nad, rank_djo) %>% 
  mutate(Winner = case_when(
    Winner =="Federer R." ~  "Federer",
    Winner =="Nadal R." ~  "Nadal",
    Winner =="Djokovic N." ~  "Djokovic")) %>% 
  pivot_longer(cols = 2:3, names_to = "Periodo", values_to =  "Ranking") %>% 
  mutate(Periodo = month(Periodo)) %>% 
  mutate(Ranking = as.integer(Ranking)) %>% 
  rename(Jugador = Winner)

ggplot(rank, aes(Periodo, Ranking, group = Jugador, color=Jugador)) +
  geom_line(size  = 1.2) + 
  geom_point(size= 2.5) + 
  scale_y_reverse(breaks = seq(1, 55, 10)) +
  scale_x_continuous(breaks = seq(1, 12, 11), labels = c("Inicio", "Final")) +
  scale_color_viridis_d() +
  labs(title = "Evolución del ránking en la temporada\nde inicio élite"
  ) +
  theme(plot.title = element_text(hjust = 0.5)) + 
  theme_classic() +
  theme(plot.title = element_text(size = 20, hjust = 0.5),
        legend.title = element_blank(),
        legend.text = element_text(size = 15),
        axis.text = element_text(size = 15),
        axis.title = element_blank()) +
  transition_reveal(Periodo) 

La gráfica anterior es muy ilustrativa del gran salto en el ránking de Rafael Nadal en su temporada 2005. Avanzó 49 puestos, acabando el año como el segundo mejor jugador del planeta. En el caso de Federer y Djokovic, al tratarse de jugadores algo más mayores, ya se encontraban consolidados entre los 10 mejores. Ambos acabaron en el número 3 del ránking.

Tops ganados

Por último, es de gran interés conocer el desempeño de estos jugadores frente a los grandes tenistas de su temporada de inicio. En este apartado, Federer es el que mejor ratio victorias/derrotas tiene. Djokovic fue el jugador que más partidos de alto nivel disputó, con un total de 10 victorias en 19 enfrentamientos. Nadal tuvo un notorio desempeño con 5 victorias y 3 derrotas. Sin embargo, al ser el jugador que más atrás en el ránking empezó el año, disputó menos partidos ante jugadores Top.

#Federer
v_top10_fed <- temporada_03 %>% filter(Winner %in% c("Federer R.") & LRank <= 10) %>% group_by(Winner) %>% summarise(Victorias = n())

d_top10_fed <- temporada_03 %>% filter(Loser %in% c("Federer R.") & WRank <= 10) %>% group_by(Loser) %>% summarise(Derrotas = n())

Top10_fed <- full_join(v_top10_fed, d_top10_fed, by = c("Winner" = "Loser")) %>% pivot_longer(cols = 2:3, names_to = "V/D", values_to = "Número")

#Nadal
v_top10_nad <- temporada_05 %>% filter(Winner %in% c("Nadal R.") & LRank <= 10) %>% group_by(Winner) %>% summarise(Victorias = n())

d_top10_nad <- temporada_05 %>% filter(Loser %in% c("Nadal R.") & WRank <= 10) %>% group_by(Loser) %>% summarise(Derrotas = n())

Top10_nad <- full_join(v_top10_nad, d_top10_nad, by = c("Winner" = "Loser")) %>% pivot_longer(cols = 2:3, names_to = "V/D", values_to = "Número")

#Djokovic
v_top10_djo <- temporada_08 %>% filter(Winner %in% c("Djokovic N.") & LRank <= 10) %>% group_by(Winner) %>% summarise(Victorias = n())

d_top10_djo <- temporada_08 %>% filter(Loser %in% c("Djokovic N.") & WRank <= 10) %>% group_by(Loser) %>% summarise(Derrotas = n())

Top10_djo <- full_join(v_top10_djo, d_top10_djo, by = c("Winner" = "Loser")) %>% pivot_longer(cols = 2:3, names_to = "V/D", values_to = "Número") 


Top10 <- rbind(Top10_fed, Top10_nad, Top10_djo) %>% mutate(`V/D` = forcats::as_factor(`V/D`)) %>% mutate(`V/D` = forcats::fct_reorder(`V/D`, Número, .desc = TRUE)) %>% mutate(Winner = case_when(
  Winner =="Federer R." ~  "Federer",
  Winner =="Nadal R." ~  "Nadal",
  Winner =="Djokovic N." ~  "Djokovic"))

Top10 %>% ggplot(aes(x= Winner, y= Número, fill= `V/D`)) +
  geom_bar(stat = "identity",
           position = "dodge") +
  scale_y_continuous(breaks = seq(0, 10, 2)) +
  scale_fill_viridis_d() +
  geom_text(aes(y=Número, label = Número), 
            position = position_dodge(width = 0.9), size = 5, 
            vjust=1.5, col = "White", fontface = "bold") +
  labs(title = "Partidos frente a Top 10 temporada\ninicio en la élite",
       fill= "Resultado") +
  theme_ipsum() +
  theme(axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        plot.title = element_text(hjust = 0.5),
        legend.title = element_text(face = "bold"))

De este modo, en este apartado podemos afirmar que Nadal es el jugador que explotó su tenis con mayor precocidad, además de ser el que obtuvo mayores éxitos en su primera temporada en la élite del tenis mundial.

8. Criterio 6: Confianza del público

El último de los criterios que utilizaremos es la confianza que los fanáticos del tenis han depositado en cada uno de estos jugadores a lo largo del tiempo. Para ello, utilizaremos el índice de ganancia por euro jugado de la casa de apuestas Bet365 desde el año 2002 hasta la actualidad. Estos índices son más pequeños cuánto más gente apuesta por la victoria de un jugador. Por ello, consideraremos que el jugador que tenga un índice medio más bajo que el resto es el jugador en que más confianza depositan los apostantes.

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

zz <- temporadas2 %>%  filter(Winner %in% c("Federer R.", "Nadal R.", "Djokovic N.")) %>% drop_na(B365W) %>% 
  mutate(Date = year(Date)) %>% 
  group_by(Winner, Date) %>% 
  summarise(B365W = mean(B365W)) %>% ungroup() %>% 
  arrange(Date) %>% 
  mutate(Winner = case_when(
    Winner =="Federer R." ~  "Federer",
    Winner =="Nadal R." ~  "Nadal",
    Winner =="Djokovic N." ~  "Djokovic")) %>% 
  select(id = Winner, date = Date, value = B365W)

robservable(
  "https://observablehq.com/@juba/bar-chart-race",
  include = c("viewof date", "chart", "draw", "styles"),
  hide = "draw",
  input = list(
    data = zz, 
    title = "Confianza del público en el Big 3",
    subtitle = "Evolución apuestas en B365",
    source = "",
    tickDuration = 1000),
  width = 1000,
  height = 700)

Gracias a la gráfica anterior, podemos observar que no existe ningún periodo en el que alguno de los jugadores haya sido tan superior al resto como para que los apostantes depositarán mayor confianza en él año tras año. Dependiendo del año que analicemos, la confianza en estos jugadores varía. Por lo tanto, este criterio no es determinante para responder a la cuestión ante la que nos encontramos.

9. Conclusión

Una vez analizada y clasificada la información anterior, nos encontramos en una mejor posición para concluir quién es el mejor jugador de tenis de todos los tiempos. Mi respuesta es clara: a día de hoy no es posible decir qué jugador de los tres es superior.

Cada uno de los miembros del Big 3 destacan en unos aspectos. En el caso de Roger Federer, el tenista suizo es de lo más brillante que ha dado el deporte mundial. Su clase, su talento y lo que ha reprensentado para el tenis es inigualable. Además, estadísticamente ha sido el dominador del circuito durante alrededor de 4 años, de 2004 a 2008. Un récord al alcance de muy pocos.

Para hablar de Rafael Nadal faltan calificativos en el diccionario. De él sí que podemos decir que es el mejor jugador de la historia en tierra batida. Su récord sobre esta superficie es de otro planeta. Por otro lado, los valores que Nadal representa destacan por encima de sus éxitos. Sin duda, un deportista ejemplar. Por último, para hablar de Novak Djokovic es necesario hacerlo en el más actual de los tiempos verbales. Djokovic es y sigue siendo el dominador más arrollador de la última década, además de un luchador incansable.

Terminaremos este documento rindiéndonos una vez más ante las palabras de Rafael Nadal que se destacaron en la introducción de este trabajo: Si alguien dice que soy mejor que Roger, creo que no sabe nada sobre el tenis. Y es que si lo dice Rafael Nadal, tiene que ser cierto.

Disfrutemos de estos grandes jugadores mientras estén en activo. Si alguna vez las comparaciones fueron odiosas, este es el ejemplo que mejor lo ilustra…

10. Bibliografía

Los datos acerca de las estadísticas de Grand Slams, se han obtenido de aquí

Los datos acerca de las estadísticas de los partidos de cada temporada desde el año 2000, se han obtenido de aquí

Datos y estadísticas sobre los tenistas profesionales, se han obtenido de aquí

El ranking ATP desde 1990, se ha obtenido descargándolo de:

Artículo sobre el día que el tenis pasó a ser abierto.

La fuente oficial de la ATP para la comprobación de los resultados, se puede visitar aquí



Información de mi R-sesión:

- Session info ---------------------------------------------------------------
 setting  value                       
 version  R version 4.1.1 (2021-08-10)
 os       Windows 10 x64              
 system   x86_64, mingw32             
 ui       RTerm                       
 language (EN)                        
 collate  Spanish_Spain.1252          
 ctype    Spanish_Spain.1252          
 tz       Europe/Paris                
 date     2022-01-02                  

- Packages -------------------------------------------------------------------
 package     * version    date       lib source                        
 assertthat    0.2.1      2019-03-21 [1] CRAN (R 4.1.1)                
 backports     1.2.1      2020-12-09 [1] CRAN (R 4.1.0)                
 broom         0.7.9      2021-07-27 [1] CRAN (R 4.1.1)                
 bslib         0.3.1      2021-10-06 [1] CRAN (R 4.1.1)                
 cellranger    1.1.0      2016-07-27 [1] CRAN (R 4.1.1)                
 checkmate     2.0.0      2020-02-06 [1] CRAN (R 4.1.1)                
 cli           3.1.0      2021-10-27 [1] CRAN (R 4.1.1)                
 clipr         0.7.1      2020-10-08 [1] CRAN (R 4.1.1)                
 colorspace    2.0-2      2021-06-24 [1] CRAN (R 4.1.1)                
 countrycode   1.3.0      2021-07-15 [1] CRAN (R 4.1.1)                
 crayon        1.4.2      2021-10-29 [1] CRAN (R 4.1.1)                
 crosstalk   * 1.1.1      2021-01-12 [1] CRAN (R 4.1.1)                
 curl          4.3.2      2021-06-23 [1] CRAN (R 4.1.1)                
 data.table    1.14.0     2021-02-21 [1] CRAN (R 4.1.1)                
 DBI           1.1.1      2021-01-15 [1] CRAN (R 4.1.1)                
 dbplyr        2.1.1      2021-04-06 [1] CRAN (R 4.1.1)                
 desc          1.3.0      2021-03-05 [1] CRAN (R 4.1.1)                
 details       0.2.1      2020-01-12 [1] CRAN (R 4.1.1)                
 digest        0.6.28     2021-09-23 [1] CRAN (R 4.1.1)                
 dplyr       * 1.0.7      2021-06-18 [1] CRAN (R 4.1.1)                
 dygraphs    * 1.1.1.6    2018-07-11 [1] CRAN (R 4.1.2)                
 ellipsis      0.3.2      2021-04-29 [1] CRAN (R 4.1.1)                
 evaluate      0.14       2019-05-28 [1] CRAN (R 4.1.1)                
 extrafont     0.17       2014-12-08 [1] CRAN (R 4.1.1)                
 extrafontdb   1.0        2012-06-11 [1] CRAN (R 4.1.1)                
 fansi         0.5.0      2021-05-25 [1] CRAN (R 4.1.1)                
 farver        2.1.0      2021-02-28 [1] CRAN (R 4.1.1)                
 fastmap       1.1.0      2021-01-25 [1] CRAN (R 4.1.1)                
 forcats     * 0.5.1      2021-01-27 [1] CRAN (R 4.1.1)                
 foreign       0.8-81     2020-12-22 [2] CRAN (R 4.1.1)                
 fs            1.5.0      2020-07-31 [1] CRAN (R 4.1.1)                
 gdtools       0.2.3      2021-01-06 [1] CRAN (R 4.1.1)                
 generics      0.1.1      2021-10-25 [1] CRAN (R 4.1.1)                
 gganimate   * 1.0.7      2020-10-15 [1] CRAN (R 4.1.1)                
 ggplot2     * 3.3.5      2021-06-25 [1] CRAN (R 4.1.1)                
 ggrepel     * 0.9.1      2021-01-15 [1] CRAN (R 4.1.1)                
 gifski        1.4.3-1    2021-05-02 [1] CRAN (R 4.1.1)                
 glue          1.5.0      2021-11-07 [1] CRAN (R 4.1.2)                
 gt          * 0.3.1.9000 2021-11-26 [1] Github (rstudio/gt@e441737)   
 gtable        0.3.0      2019-03-25 [1] CRAN (R 4.1.1)                
 haven         2.4.3      2021-08-04 [1] CRAN (R 4.1.1)                
 here          1.0.1      2020-12-13 [1] CRAN (R 4.1.1)                
 highr         0.9        2021-04-16 [1] CRAN (R 4.1.1)                
 hms           1.1.1      2021-09-26 [1] CRAN (R 4.1.1)                
 hrbrthemes  * 0.8.0      2020-03-06 [1] CRAN (R 4.1.1)                
 htmltools     0.5.2      2021-08-25 [1] CRAN (R 4.1.1)                
 htmlwidgets   1.5.4      2021-09-08 [1] CRAN (R 4.1.1)                
 httpuv        1.6.3      2021-09-09 [1] CRAN (R 4.1.1)                
 httr          1.4.2      2020-07-20 [1] CRAN (R 4.1.1)                
 jquerylib     0.1.4      2021-04-26 [1] CRAN (R 4.1.1)                
 jsonlite      1.7.2      2020-12-09 [1] CRAN (R 4.1.1)                
 klippy      * 0.0.0.9500 2021-11-16 [1] Github (rlesur/klippy@378c247)
 knitr       * 1.36       2021-09-29 [1] CRAN (R 4.1.1)                
 labeling      0.4.2      2020-10-20 [1] CRAN (R 4.1.0)                
 later         1.3.0      2021-08-18 [1] CRAN (R 4.1.1)                
 lattice       0.20-44    2021-05-02 [1] CRAN (R 4.1.1)                
 lazyeval      0.2.2      2019-03-15 [1] CRAN (R 4.1.1)                
 lifecycle     1.0.1      2021-09-24 [1] CRAN (R 4.1.1)                
 lubridate   * 1.7.10     2021-02-26 [1] CRAN (R 4.1.1)                
 magrittr      2.0.1      2020-11-17 [1] CRAN (R 4.1.1)                
 maps          3.3.0      2018-04-03 [1] CRAN (R 4.1.1)                
 mime          0.12       2021-09-28 [1] CRAN (R 4.1.1)                
 modelr        0.1.8      2020-05-19 [1] CRAN (R 4.1.1)                
 munsell       0.5.0      2018-06-12 [1] CRAN (R 4.1.1)                
 openxlsx      4.2.4      2021-06-16 [1] CRAN (R 4.1.1)                
 patchwork   * 1.1.1      2020-12-17 [1] CRAN (R 4.1.1)                
 pillar        1.6.4      2021-10-18 [1] CRAN (R 4.1.1)                
 pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 4.1.1)                
 plotly      * 4.9.4.1    2021-06-18 [1] CRAN (R 4.1.1)                
 plyr          1.8.6      2020-03-03 [1] CRAN (R 4.1.1)                
 png           0.1-7      2013-12-03 [1] CRAN (R 4.1.0)                
 prettyunits   1.1.1      2020-01-24 [1] CRAN (R 4.1.1)                
 progress      1.2.2      2019-05-16 [1] CRAN (R 4.1.1)                
 promises      1.2.0.1    2021-02-11 [1] CRAN (R 4.1.1)                
 purrr       * 0.3.4      2020-04-17 [1] CRAN (R 4.1.1)                
 R6            2.5.1      2021-08-19 [1] CRAN (R 4.1.1)                
 Rcpp          1.0.7      2021-07-07 [1] CRAN (R 4.1.1)                
 reactable   * 0.2.3      2020-10-04 [1] CRAN (R 4.1.1)                
 reactR        0.4.4      2021-02-22 [1] CRAN (R 4.1.1)                
 readr       * 2.0.1      2021-08-10 [1] CRAN (R 4.1.1)                
 readxl        1.3.1      2019-03-13 [1] CRAN (R 4.1.1)                
 reprex        2.0.1      2021-08-05 [1] CRAN (R 4.1.1)                
 rio           0.5.27     2021-06-21 [1] CRAN (R 4.1.1)                
 rlang         0.4.12     2021-10-18 [1] CRAN (R 4.1.1)                
 rmarkdown     2.11       2021-09-14 [1] CRAN (R 4.1.1)                
 robservable * 0.2.1      2021-10-06 [1] CRAN (R 4.1.1)                
 rprojroot     2.0.2      2020-11-15 [1] CRAN (R 4.1.1)                
 rstudioapi    0.13       2020-11-12 [1] CRAN (R 4.1.1)                
 Rttf2pt1      1.3.9      2021-07-22 [1] CRAN (R 4.1.1)                
 rvest         1.0.1      2021-07-26 [1] CRAN (R 4.1.1)                
 sass          0.4.0      2021-05-12 [1] CRAN (R 4.1.1)                
 scales        1.1.1      2020-05-11 [1] CRAN (R 4.1.1)                
 sessioninfo   1.1.1      2018-11-05 [1] CRAN (R 4.1.1)                
 shiny         1.7.1      2021-10-02 [1] CRAN (R 4.1.1)                
 stringi       1.7.5      2021-10-04 [1] CRAN (R 4.1.1)                
 stringr     * 1.4.0      2019-02-10 [1] CRAN (R 4.1.1)                
 systemfonts   1.0.3      2021-10-13 [1] CRAN (R 4.1.1)                
 tibble      * 3.1.5      2021-09-30 [1] CRAN (R 4.1.1)                
 tidyr       * 1.1.4      2021-09-27 [1] CRAN (R 4.1.1)                
 tidyselect    1.1.1      2021-04-30 [1] CRAN (R 4.1.1)                
 tidyverse   * 1.3.1      2021-04-15 [1] CRAN (R 4.1.1)                
 tweenr        1.0.2      2021-03-23 [1] CRAN (R 4.1.1)                
 tzdb          0.1.2      2021-07-20 [1] CRAN (R 4.1.1)                
 utf8          1.2.2      2021-07-24 [1] CRAN (R 4.1.1)                
 vctrs         0.3.8      2021-04-29 [1] CRAN (R 4.1.1)                
 viridisLite   0.4.0      2021-04-13 [1] CRAN (R 4.1.1)                
 withr         2.4.2      2021-04-18 [1] CRAN (R 4.1.1)                
 xfun          0.26       2021-09-14 [1] CRAN (R 4.1.1)                
 xml2          1.3.2      2020-04-23 [1] CRAN (R 4.1.1)                
 xtable        1.8-4      2019-04-21 [1] CRAN (R 4.1.1)                
 xts         * 0.12.1     2020-09-09 [1] CRAN (R 4.1.2)                
 yaml          2.2.1      2020-02-01 [1] CRAN (R 4.1.0)                
 zip           2.2.0      2021-05-31 [1] CRAN (R 4.1.1)                
 zoo         * 1.8-9      2021-03-09 [1] CRAN (R 4.1.1)                

[1] C:/Users/Usuario/Documents/R/win-library/4.1
[2] C:/Program Files/R/R-4.1.1/library






LS0tDQp0aXRsZTogIsK/UVVJw4lOIEVTIEVMIEdPQVQgREVMIFRFTklTPyINCnN1YnRpdGxlOiAiSm9yZ2UgR29uesOhbGV6IEFuZHLDqXMoam9yZ29uYW5AYWx1bW5pLnV2LmVzKSIgIy0gcG9uZ28gdMO6IG5vbWJyZSBhaMOtIHBhcmEgcSBhcGFyZXpjYSBtw6FzIGdyYW5kZSBxIGVsIGRlIGxhIFVWDQphdXRob3I6ICJVbml2ZXJzaXRhdCBkZSBWYWzDqG5jaWEiDQpkYXRlOiAiRGljaWVtYnJlIGRlIDIwMjEgKGFjdHVhbGl6YWRvIGVsIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVknKWApIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNzczogIi4vYXNzZXRzL215X2Nzc19maWxlLmNzcyINCiAgICB0aGVtZTogY29zbW8NCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlIA0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMyANCiAgICB0b2NfZmxvYXQ6IA0KICAgICAgY29sbGFwc2VkOiB0cnVlDQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlDQogICAgZGZfcHJpbnQ6IGthYmxlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogImhpZGUiDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlDQotLS0NCg0KYGBge3IgcGFja2FnZXMtc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShrbGlwcHkpICAjLSByZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigicmxlc3VyL2tsaXBweSIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGhyYnJ0aGVtZXMpDQpsaWJyYXJ5KHBhdGNod29yaykgDQpsaWJyYXJ5KGdnYW5pbWF0ZSkNCmxpYnJhcnkoZ3QpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeSh4dHMpDQpsaWJyYXJ5KGR5Z3JhcGhzKQ0KbGlicmFyeShyb2JzZXJ2YWJsZSkNCmxpYnJhcnkoY3Jvc3N0YWxrKQ0KbGlicmFyeShyZWFjdGFibGUpDQpsaWJyYXJ5KGdncmVwZWwpDQpgYGANCg0KYGBge3IgY2h1bmstc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZXZhbCA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICAjcmVzdWx0cyA9ICJob2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICBjYWNoZSA9IEZBTFNFLCBjYWNoZS5wYXRoID0gIi9jYWNoZXMvIiwgY29tbWVudCA9ICIjPiIsDQogICAgICAgICAgICAgICAgICAgICAgI2ZpZy53aWR0aCA9IDcsICNmaWcuaGVpZ2h0PSA3LCAgIA0KICAgICAgICAgICAgICAgICAgICAgICNvdXQud2lkdGggPSA3LCBvdXQuaGVpZ2h0ID0gNywNCiAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZSA9IFRSVUUsICBmaWcuc2hvdyA9ICJob2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYXNwID0gMC44MjgsIG91dC53aWR0aCA9ICI3NSUiLCBmaWcuYWxpZ24gPSAiY2VudGVyIikNCmtuaXRyOjpvcHRzX2NodW5rJHNldChkZXYgPSAicG5nIiwgZGV2LmFyZ3MgPSBsaXN0KHR5cGUgPSAiY2Fpcm8tcG5nIikpDQpgYGANCg0KYGBge3Igb3B0aW9ucy1zZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICMtIHBhcmEgcXVpdGFyIGxhIG5vdGFjacOzbiBjaWVudMOtZmljYQ0Kb3B0aW9ucygieWFtbC5ldmFsLmV4cHIiID0gVFJVRSkgDQpgYGANCg0KYGBge3Iga2xpcHB5LCBlY2hvID0gRkFMU0V9DQprbGlwcHk6OmtsaXBweShwb3NpdGlvbiA9IGMoInRvcCIsICJyaWdodCIpKSAjLSByZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigicmxlc3VyL2tsaXBweSIpDQpgYGANCg0KPGhyIGNsYXNzPSJsaW5lYS1ibGFjayI+DQoNCjwhLS0gRWwgcMOhcnJhZm8gZGUgYWJham8gaGFzIGRlIGRlamFybG8gY2FzaSBpZ3VhbCwgc29sbyBIQVMgZGUgU1VTVElUVUlSICJwZXJlenA0NCIgcG9yIHR1IHVzdWFyaW8gZGUgR2l0aHViLS0+DQoNClRyYWJham8gZWxhYm9yYWRvIHBhcmEgbGEgYXNpZ25hdHVyYSAiUHJvZ3JhbWFjacOzbiB5IG1hbmVqbyBkZSBkYXRvcyBlbiBsYSBlcmEgZGVsIEJpZyBEYXRhIiBkZSBsYSBVbml2ZXJzaXRhdCBkZSBWYWzDqG5jaWEgZHVyYW50ZSBlbCBjdXJzbyAyMDIxLTIwMjIuIEVsIHJlcG8gZGVsIHRyYWJham8gZXN0w6EgW2FxdcOtXShodHRwczovL2dpdGh1Yi5jb20vam9vcmdlMDYwMy90cmFiYWpvX0JpZ0RhdGEpe3RhcmdldD0iX2JsYW5rIn0uDQoNCjwhLS0gRWwgcMOhcnJhZm8gZGUgYWJham8gaGFzIGRlIGRlamFybG8gZXhhY3RhbWVudGUgaWd1YWwsIE5PIEhBUyBERSBDQU1CSUFSIE5BREEtLT4NCg0KTGEgcMOhZ2luYSB3ZWIgZGUgbGEgYXNpZ25hdHVyYSB5IGxvcyB0cmFiYWpvcyBkZSBtaXMgY29tcGHDsWVyb3MgcHVlZGVuIHZlcnNlIFthcXXDrV0oaHR0cHM6Ly9wZXJlenA0NC5naXRodWIuaW8vaW50cm8tZHMtMjEtMjItd2ViLzA3LXRyYWJham9zLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uDQoNCjxociBjbGFzcz0ibGluZWEtYmxhY2siPg0KDQojIDEuIEludHJvZHVjY2nDs24NCg0KRWwgZGViYXRlIGFjZXJjYSBkZSBxdWnDqW4gZXMgZWwgR09BVCBkZWwgdGVuaXMgKGVsIG1lam9yIGp1Z2Fkb3IgZGUgdG9kb3MgbG9zIHRpZW1wb3MpIHNlIGVuY3VlbnRyYSBlbiBzdSBwdW50byBtw6FzIMOhbGdpZG8uIEhhc3RhIG1lZGlhZG9zIGRlIDIwMDggbm8gZXhpc3TDrWEgYXJndW1lbnRvIHF1ZSBwdWRpZXNlIGRlc2JhbmNhciBhIFJvZ2VyIEZlZGVyZXIgZGUgZXN0YSBwb3NpY2nDs24uIFNpbiBlbWJhcmdvLCBlbiBsYSBhY3R1YWxpZGFkIGhheSBvdHJvcyBkb3MganVnYWRvcmVzIGNvbiBtw6lyaXRvcyBzdWZpY2llbnRlcyBwYXJhIGRpc3B1dGFyIGVzdGUgdMOtdHVsbyBob25vcsOtZmljbyBhICpTdSBNYWplc3RhZCogUm9nZXIgRmVkZXJlci4gRWxsb3Mgc29uIFJhZmFlbCBOYWRhbCB5IE5vdmFrIERqb2tvdmljLg0KDQo+ICJTaSBhbGd1aWVuIGRpY2UgcXVlIHNveSBtZWpvciBxdWUgUm9nZXIsIGNyZW8gcXVlIG5vIHNhYmUgbmFkYSBzb2JyZSBlbCB0ZW5pcyIgUmFmYWVsIE5hZGFsDQoNCk5vIHJlc3VsdGEgdGFyZWEgc2VuY2lsbGEgZXN0YWJsZWNlciBxdcOpIGp1Z2Fkb3IgZXMgZWwgbWVqb3IgZGUgdG9kb3MgbG9zIHRpZW1wb3MuIExvIGxvZ3JhZG8gcG9yIHBhcnRlIGRlIEZlZGVyZXIsIE5hZGFsIHkgRGpva292aWMgZHVyYW50ZSBlc3RvcyDDumx0aW1vcyAyMCBhw7FvcyBlcyB1biBoaXRvIHF1ZSBkaWbDrWNpbG1lbnRlIHNlIHZvbHZlcsOhIGEgcmVwZXRpci4gTGEgaGVnZW1vbsOtYSBkZSBlc3RvcyB0cmVzIGRlcG9ydGlzdGFzIGFwZW5hcyBoYSBwb2RpZG8gc2VyIHF1ZWJyYWRhIHBvciB1bm9zIHBvY29zLCBjcmVhbmRvIHVuYSBkZSBsYXMgcml2YWxpZGFkZXMgbcOhcyBhcGFzaW9uYW50ZXMgZGUgbGEgaGlzdG9yaWEgZGUgZXN0ZSBkZXBvcnRlLg0KDQo8YnI+DQoNCjxjZW50ZXI+DQoNCiFbKkRqb2tvdmljLCBOYWRhbCB5IEZlZGVyZXIganVudG8gYWwgdHJvZmVvIGFsIG7Dum1lcm8gMSBkZWwgYcOxby4qXShpbWFnZW5lcy90cmVzLmpwZyl7d2lkdGg9IndpZHRoIiBoZWlnaHQ9ImhlaWdodCJ9DQoNCjxjZW50ZXI+DQoNCkEgbG8gbGFyZ28gZGVsIGRvY3VtZW50byB0cmF0YXJlbW9zIGRlIGFuYWxpemFyIGN1w6FsIGRlIGVzdG9zIGdyYW5kZXMgdGVuaXN0YXMgbWVyZWNlIHNlciBlbCBHT0FUIGRlbCB0ZW5pcy4gUGFyYSBsYSByZWFsaXphY2nDs24gZGUgZXN0YSB0YXJlYSwgZXN0YWJsZWNlcmVtb3MgdW5hIHNlcmllIGRlIGNyaXRlcmlvcyBsbyBtw6FzIG9iamV0aXZvcyBwb3NpYmxlcy4gTm8gb2JzdGFudGUsIGFudGUgbGEgcG9zaWJpbGlkYWQgZGUgbm8gcG9kZXIgY2xhcmlmaWNhciBxdWnDqW4gaGEgaGVjaG8gbcOhcyBtw6lyaXRvcyBkZWJpZG8gYSBsYSBncmFuZGV6YSBkZSBlc3RvcyBkZXBvcnRpc3RhcywgYWwgbWVub3MgdHJhdGFyZW1vcyBkZSBhcG9ydGFyIHVuYSB2aXNpw7NuIG3DoXMgb2JqZXRpdmEgZGUgZW4gcXXDqSBhc3BlY3RvcyBjYWRhIGp1Z2Fkb3IgaGEgc29icmVzYWxpZG8gcmVzcGVjdG8gYWwgcmVzdG8uDQoNCiMgMi4gRGF0b3Mgey50YWJzZXR9DQoNClBhcmEgcG9kZXIgbG9ncmFyIG9idGVuZXIgYWxndW5hIGNvbmNsdXNpw7NuLCBuZWNlc2l0YW1vcyBkYXRvcyBhIHRyYXbDqXMgZGUgbG9zIGN1w6FsZXMgb2J0ZW5lciBpbmZvcm1hY2nDs24uIEEgbG8gbGFyZ28gZGVsIGRvY3VtZW50bywgaGFyZW1vcyB1c28gcHJpbmNpcGFsbWVudGUgZGUgdHJlcyBkYXRhc2V0cywgbG9zIGN1w6FsZXMgc2UgbXVlc3RyYW4gYSBjb250aW51YWNpw7NuLg0KDQojIyBEYXRhc2V0ICpHcmFuZCBTbGFtcyoNCg0KVW5vIGRlIGxvcyBjcml0ZXJpb3MgbcOhcyB1c2Fkb3MgcGFyYSBhZmlybWFyIHNpIHVuIGp1Z2Fkb3IgaGEgbG9ncmFkbyBtYXlvcmVzIMOpeGl0b3MgcXVlIG90cm8sIGVzIGVsIG7Dum1lcm8gZGUgR3JhbmQgU2xhbXMgcXVlIGhhIG9idGVuaWRvLiBUb2RhIGxhIGluZm9ybWFjacOzbiBhY2VyY2EgZGUgbG9zIGNhbXBlb25lcyB5IHN1YmNhbXBlb25lcyBkZSBHcmFuZCBTbGFtIHNlIG11ZXN0cmEgYSBjb250aW51YWNpw7NuLg0KDQpgYGB7cn0NCmdyYW5kX3NsYW1zIDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoImRhdG9zIiwgImdyYW5kX3NsYW1fdGlkeS54bHN4IikpDQoNCmdyYW5kX3NsYW1zIDwtIFNoYXJlZERhdGEkbmV3KGdyYW5kX3NsYW1zKQ0KDQpic2NvbHMod2lkdGhzID0gYygzLE5BLE5BKSwNCiAgICAgICBsaXN0KGZpbHRlcl9zbGlkZXIoIkHDsW8iLCAiQcOxbyIsIGdyYW5kX3NsYW1zLCB+QcOxbywgd2lkdGggPSAiMTAwJSIpLA0KICAgICAgICAgICAgZmlsdGVyX2NoZWNrYm94KCJNYWpvciIsICJNYWpvciIsIGdyYW5kX3NsYW1zLCB+TWFqb3IsIGNvbHVtbnMgPTEpLA0KICAgICAgICAgICAgZmlsdGVyX3NlbGVjdCgiQ2FtcGXDs24iLCAiQ2FtcGXDs24iLCBncmFuZF9zbGFtcywgfkNhbXBlw7NuKSwNCiAgICAgICAgICAgIGZpbHRlcl9zZWxlY3QoIlN1YmNhbXBlw7NuIiwgIlN1YmNhbXBlw7NuIiwgZ3JhbmRfc2xhbXMsIH5TdWJjYW1wZcOzbikpLA0KICAgICAgIHJlYWN0YWJsZShncmFuZF9zbGFtcywgbWluUm93cyA9IDEwLCBkZWZhdWx0UGFnZVNpemUgPSAgMTAsIA0KICAgICAgICAgICAgICAgICBwYWdpbmF0aW9uVHlwZSA9ICJqdW1wIiwgIHNob3dQYWdlU2l6ZU9wdGlvbnMgPSAgVFJVRSAsIA0KICAgICAgICAgICAgICAgICBwYWdlU2l6ZU9wdGlvbnMgPSAgYyAoIDEwICwgNTAgLCAxMDAgKSxkZWZhdWx0Q29sRGVmID0gY29sRGVmKA0KICAgICAgICAgICAgICAgICAgIGFsaWduID0gImNlbnRlciIsDQogICAgICAgICAgICAgICAgICAgbWluV2lkdGggPSA3MCwNCiAgICAgICAgICAgICAgICAgICBoZWFkZXJTdHlsZSA9IGxpc3QoYmFja2dyb3VuZCA9ICJsaWdodGdyZWVuIiksDQogICAgICAgICAgICAgICAgICAgZmlsdGVyYWJsZSA9IEZBTFNFKSwgaGlnaGxpZ2h0ID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgb3V0bGluZWQgPSBUUlVFKSkNCmBgYA0KDQojIyBEYXRhc2V0ICpUZW1wb3JhZGFzKg0KDQpMYXMgdGVtcG9yYWRhcyBkZSB0ZW5pcyBjb25zdGFuIGRlIG51bWVyb3NvcyB0b3JuZW9zIGEgbG8gbGFyZ28geSBhbmNobyBkZWwgcGxhbmV0YSBkZXNkZSBlbmVybyBoYXN0YSBtZWRpYWRvcy9maW5hbGVzIGRlIG5vdmllbWJyZS4gR3JhY2lhcyBhbCBkYXRhc2V0IHNpZ3VpZW50ZSwgdGVuZW1vcyBsb3MgZGF0b3MgbcOhcyByZWxldmFudGVzIGRlIHRvZG9zIGxvcyBwYXJ0aWRvcyBkZXNkZSBlbCBhw7FvIDIwMDAgaGFzdGEgZWwgMjAyMS4gTm8gb2JzdGFudGUsIHBhcmEgdW5hIG1lam9yIHZpc3VhbGl6YWNpw7NuIGRlIGxvcyBkYXRvcywgaGVtb3MganVudGFkbyBsYXMgZGlzdGludGFzIHRlbXBvcmFkYXMgZW4gdW4gc29sbyBkYXRhc2V0IHkgc2UgaGFuIGVsZWdpZG8gbGFzIHZhcmlhYmxlcyBtw6FzIHJlbGV2YW50ZXMgZW50cmUgbGFzIG3DoXMgZGUgMzAgZGUgbGFzIHF1ZSBkaXNwb25lbW9zLg0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCnRlbXBvcmFkYXMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAidGVtcG9yYWRhcy5jc3YiKSkNCmBgYA0KDQpgYGB7ciwgZXZhbCA9IFRSVUV9DQp0ZW1wb3JhZGFzIDwtIFNoYXJlZERhdGEkbmV3KHRlbXBvcmFkYXMpDQoNCmJzY29scyh3aWR0aHMgPSBjKDMsTkEsTkEpLA0KICAgICAgIGxpc3QoIGZpbHRlcl9jaGVja2JveCgiU2VyaWVzIiwgIlNlcmllcyIsIHRlbXBvcmFkYXMsIH5TZXJpZXMsIGNvbHVtbnMgPTEpLCANCiAgICAgICAgICAgICBmaWx0ZXJfc2xpZGVyKCJEYXRlIiwgIkRhdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVtcG9yYWRhcywgfkRhdGUsIHdpZHRoID0gIjEwMCUiKSwNCiAgICAgICAgICAgICBmaWx0ZXJfY2hlY2tib3goIlN1cmZhY2UiLCAiU3VyZmFjZSIsIHRlbXBvcmFkYXMsIH5TdXJmYWNlLCBjb2x1bW5zID0xKSwNCiAgICAgICAgICAgICBmaWx0ZXJfc2VsZWN0KCJXaW5uZXIiLCAiV2lubmVyIiwgdGVtcG9yYWRhcywgfldpbm5lciksDQogICAgICAgICAgICAgZmlsdGVyX3NlbGVjdCgiTG9zZXIiLCAiTG9zZXIiLCB0ZW1wb3JhZGFzLCB+TG9zZXIpKSwNCiAgICAgICByZWFjdGFibGUodGVtcG9yYWRhcywgbWluUm93cyA9IDEwLCBkZWZhdWx0UGFnZVNpemUgPSAgMTAsIA0KICAgICAgICAgICAgICAgICBwYWdpbmF0aW9uVHlwZSA9ICJqdW1wIiwgIHNob3dQYWdlU2l6ZU9wdGlvbnMgPSAgVFJVRSAsIA0KICAgICAgICAgICAgICAgICBwYWdlU2l6ZU9wdGlvbnMgPSAgYyAoIDEwICwgNTAgLCAxMDAgKSxkZWZhdWx0Q29sRGVmID0gY29sRGVmKA0KICAgICAgICAgICAgICAgICAgIGFsaWduID0gImNlbnRlciIsDQogICAgICAgICAgICAgICAgICAgbWluV2lkdGggPSA3MCwNCiAgICAgICAgICAgICAgICAgICBoZWFkZXJTdHlsZSA9IGxpc3QoYmFja2dyb3VuZCA9ICJsaWdodGdyZWVuIiksDQogICAgICAgICAgICAgICAgICAgZmlsdGVyYWJsZSA9IEZBTFNFKSwgaGlnaGxpZ2h0ID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgb3V0bGluZWQgPSBUUlVFKSkNCmBgYA0KDQojIyBEYXRhc2V0ICpSYW5raW5nKg0KDQpFbCByYW5raW5nIEFUUCBzZSBmb3JtYSBhIHRyYXbDqXMgZGUgbG9zIHB1bnRvcyBxdWUgb3RvcmdhbiBsb3MgdG9ybmVvcyBhIGxvcyBqdWdhZG9yZXMgc2Vnw7puIHN1IHJlc3VsdGFkbyBlbiBlbCBtaXNtby4gRW4gZWwgZGF0YXNldCBzaWd1aWVudGUgc2UgbXVlc3RyYSBlbCB0b3AgMTAwMCBkZWwgcmFua2luZyBBVFAgZGVzZGUgZW5lcm8gZGVsIDIwMDAgaGFzdGEgbGEgYWN0dWFsaWRhZC4gQ2FiZSBkZXN0YWNhciBxdWUsIHBvciBtb3Rpdm9zIGRlIHNpbXBsaWNpZGFkLCBzZSBoYSByZWR1Y2lkbyBzdSBkaW1lbnNpw7NuIHkgc29sbyBzZSBtb3N0cmFyw6EgZWwgdG9wIDEwIHNlbWFuYWwuDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KcmFua2luZyA8LSByaW86OjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAicmFua2luZy5yZHMiKSkNCmBgYA0KDQpgYGB7cn0NCnJhbmtpbmcgPC0gU2hhcmVkRGF0YSRuZXcocmFua2luZykNCg0KYnNjb2xzKHdpZHRocyA9IGMoMyxOQSxOQSksDQogICAgICAgbGlzdChmaWx0ZXJfc2VsZWN0KCJyYW5raW5nX2RhdGUiLCAicmFua2luZ19kYXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhbmtpbmcsIH5yYW5raW5nX2RhdGUpLA0KICAgICAgICAgICAgZmlsdGVyX3NlbGVjdCgibmFtZSIsICJuYW1lIiwgcmFua2luZywgfm5hbWUpLA0KICAgICAgICAgICAgZmlsdGVyX3NsaWRlcigicmFuayIsICJyYW5rIiwgcmFua2luZywgfnJhbmssIHdpZHRoID0gIjEwMCUiKSksDQogICAgICAgcmVhY3RhYmxlKHJhbmtpbmcsIG1pblJvd3MgPSAxMCwgZGVmYXVsdFBhZ2VTaXplID0gIDEwLCANCiAgICAgICAgICAgICAgICAgcGFnaW5hdGlvblR5cGUgPSAianVtcCIsICBzaG93UGFnZVNpemVPcHRpb25zID0gIFRSVUUgLCANCiAgICAgICAgICAgICAgICAgcGFnZVNpemVPcHRpb25zID0gIGMgKCAxMCAsIDUwICwgMTAwICksZGVmYXVsdENvbERlZiA9IGNvbERlZigNCiAgICAgICAgICAgICAgICAgICBhbGlnbiA9ICJjZW50ZXIiLA0KICAgICAgICAgICAgICAgICAgIG1pbldpZHRoID0gNzAsDQogICAgICAgICAgICAgICAgICAgaGVhZGVyU3R5bGUgPSBsaXN0KGJhY2tncm91bmQgPSAibGlnaHRncmVlbiIpLA0KICAgICAgICAgICAgICAgICAgIGZpbHRlcmFibGUgPSBGQUxTRSksIGhpZ2hsaWdodCA9IFRSVUUsDQogICAgICAgICAgICAgICAgIG91dGxpbmVkID0gVFJVRSkpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpncmFuZF9zbGFtcyA8LSByaW86OmltcG9ydChoZXJlOjpoZXJlKCJkYXRvcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJncmFuZF9zbGFtX3RpZHkueGxzeCIpKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KanVnYWRvcmVzIDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoImRhdG9zIiwgImp1Z2Fkb3Jlcy5jc3YiKSkNCg0KcmFua2luZyA8LSByaW86OmltcG9ydChoZXJlOjpoZXJlKCJkYXRvcyIsICJyYW5raW5nX3RvdC5yZHMiKSkNCmBgYA0KDQojIDMuIENyaXRlcmlvIDE6IE1heW9yIGNhbnRpZGFkIGRlIHTDrXR1bG9zIHBvciBjYXRlZ29yw61hDQoNCkxvcyBmYW7DoXRpY29zIGRlbCB0ZW5pcyBzYWJyw6FuIHF1ZSBsb3MgdG9ybmVvcyBwcm9mZXNpb25hbGVzIHNlIGRpdmlkZW4gZW4gKipjdWF0cm8gY2F0ZWdvcsOtYXMgbcOhcyBsYSBDb3BhIGRlIE1hZXN0cm9zIHkgbG9zIEpKT08qKi4gRW4gZXN0ZSBhcGFydGFkbyB0cmF0YXJlbW9zIGRlIGFuYWxpemFyIHF1w6kganVnYWRvciBoYW4gZ2FuYWRvIG3DoXMgdG9ybmVvcyBzZWfDum4gbGEgY2F0ZWdvcsOtYS4NCg0KIyMgMy4xIFRvcm5lb3MgZGUgR3JhbmQgU2xhbSB7LnRhYnNldH0NCg0KIyMjIEdyYW5kIFNsYW1zDQoNCkxvcyBHcmFuZCBTbGFtcyBzb24gbG9zIHRvcm5lb3MgbcOhcyBpbXBvcnRhbnRlcyB5IHByZXN0aWdpb3NvcyBkZWwgdGVuaXMuIEVzdGEgY2F0ZWdvcsOtYSBlc3TDoSBmb3JtYWRhIHBvciBjdWF0cm8gdG9ybmVvcyAoQXVzdHJhbGlhbiBPcGVuLCBSb2xhbmQgR2Fycm9zLCBXaW1ibGVkb24geSBlbCBVUyBPcGVuKSB5IHNlIGNlbGVicmFuIHVuYSB2ZXogY2FkYSB1bm8gYSBsbyBsYXJnbyBkZWwgYcOxby4gTG9zIGp1Z2Fkb3JlcyBxdWUgbG9ncmFuIGdhbmFyIGFsZ3VubyBkZSBlc3RvcyB0b3JuZW9zIG9idGllbmVuIDIwMDAgcHVudG9zIHBhcmEgZWwgcsOhbmtpbmcgbcOhcyBlbCBwcmVzdGlnaW8gZGUgZ2FuYXIgdW5vIGRlIGxvcyAqZ3JhbmRlcyogZGVsIHRlbmlzLg0KDQpFbiBlc3RlIMO6bHRpbW8gYcOxbywgbGEgcHJlbnNhIHNlIGhhIGhlY2hvIGVjbyBkZSBsYSBoYXphw7FhIGxvZ3JhZGEgcG9yIERqb2tvdmljLCBnYW5hbmRvIHRyZXMgZGUgbG9zIGN1YXRybyBHcmFuZCBTbGFtcyBkZWwgYcOxbyB5IGVtcGF0YW5kbyBkZSBlc3RhIGZvcm1hIGEgMjAgdG9ybmVvcyAqbWFqb3IqIGdhbmFkb3MgY29uIEZlZGVyZXIgeSBOYWRhbC4gRW4gZWwgZ3LDoWZpY28gcXVlIHNlIG11ZXN0cmEgYSBjb250aW51YWNpw7NuLCBzZSBvYnNlcnZhIGxhIGV2b2x1Y2nDs24gZGUgR3JhbmQgU2xhbXMgZ2FuYWRvcyBwb3IgcGFydGUgZGUgZXN0b3MgdHJlcyBqdWdhZG9yZXMuDQoNCmBgYHtyfQ0KZ3JhbmRfc2xhbXMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZ3JhbmRfc2xhbV90aWR5Lnhsc3giKSkNCg0KYmlnMyA8LSBncmFuZF9zbGFtcyAlPiUgDQogIGZpbHRlcihDYW1wZcOzbiAlaW4lIGMoIlJhZmFlbCBOYWRhbCIsICJOb3ZhayBEam9rb3ZpYyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIlJvZ2VyIEZlZGVyZXIiKSkgJT4lIA0KICBzZWxlY3QoQcOxbywgQ2FtcGXDs24pICU+JSBncm91cF9ieShBw7FvLCBDYW1wZcOzbikgJT4lDQogIHN1bW1hcmlzZShwb3JfYcOxbyA9IG4oKSkgJT4lIHVuZ3JvdXAoKSAlPiUgZ3JvdXBfYnkoQ2FtcGXDs24pICU+JQ0KICBtdXRhdGUobl9ncmFuZF9zbGFtID0gY3Vtc3VtKHBvcl9hw7FvKSkgJT4lDQogIG11dGF0ZShuX2dyYW5kX3NsYW0gPSBhcy5udW1lcmljKG5fZ3JhbmRfc2xhbSkpICU+JSB1bmdyb3VwKCkNCg0KYmlnMyAlPiUgZ2dwbG90KGFlcyh4PSBBw7FvLCB5PSBuX2dyYW5kX3NsYW0pKSArIA0KICBsYWJzKHRpdGxlID0gIkV2b2x1Y2nDs24gR3JhbmQgU2xhbXMgZ2FuYWRvc1xucG9yIGVsIEJpZyAzIiwNCiAgICAgICB4PSAiQcOxbyIsDQogICAgICAgeT0gIk7Dum1lcm8gZGUgR3JhbmQgU2xhbXMiLA0KICAgICAgIGNvbG9yID0gIkp1Z2Fkb3IiKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yPSBDYW1wZcOzbiksIHNpemU9IDMpICsNCiAgZ2VvbV9saW5lKGFlcyhjb2xvcj0gQ2FtcGXDs24pLCBzaXplPSAxLjUpICsgDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJtaWRuaWdodGJsdWUiLCAiZGFya2dyZWVuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNpZW5uYSIpLCANCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoIlJvZ2VyIEZlZGVyZXIiLCAiUmFmYWVsIE5hZGFsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vdmFrIERqb2tvdmljIikpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMC41KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMywgaGp1c3QgPSAxLCB2anVzdCA9IDApLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLCBoanVzdCA9IDEsIHZqdXN0ID0gMSksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSkgKw0KICBnZW9tX3RleHQoYWVzKHggPSBtaW4oQcOxbyksIHkgPSBtaW4obl9ncmFuZF9zbGFtKSwgDQogICAgICAgICAgICAgICAgbGFiZWwgPSBhcy5mYWN0b3IoQcOxbykpICwgaGp1c3Q9IDAsIHZqdXN0ID0gLTYuMiwNCiAgICAgICAgICAgIGFscGhhID0gMSwgIGNvbCA9ICJncmF5Iiwgc2l6ZSA9IDIwKSArDQogIHRyYW5zaXRpb25fcmV2ZWFsKEHDsW8pICsgDQogIHZpZXdfZm9sbG93KCkNCmBgYA0KDQpFbCBwcmltZXIganVnYWRvciBlbiBhbGNhbnphciBsb3MgMjAgR3JhbmQgU2xhbXMgZ2FuYWRvcyBmdWUgUm9nZXIgRmVkZXJlciwgc2VndWlkbyBkZSBSYWZhZWwgTmFkYWwgeSwgZmluYWxtZW50ZSBlc3RlIGHDsW8sIERqb2tvdmljIGFsY2FuesOzIGVzdGEgY2lmcmEuIEVzIGRpZsOtY2lsIGRlY2lyIHF1w6kganVnYWRvciB0ZXJtaW5hcsOhIGNvbiB1biBtYXlvciBuw7ptZXJvIGRlIEdyYW5kIFNsYW1zLiBQb3IgZWwgbW9tZW50byBsYSB0ZW5kZW5jaWEgZmF2b3JlY2UgYSBEam9rb3ZpYywgeWEgcXVlIGVuIGVzdGUgYcOxbyBoYSBsb2dyYWRvIGdhbmFyIHRyZXMgZGUgZXN0b3MgdG9ybmVvcywgbWllbnRyYXMgcXVlIG5pIE5hZGFsIG5pIEZlZGVyZXIgc2UgaGFuIGNvbnNlZ3VpZG8gaGFjZXIgY29uIHVuby4NCg0KIyMjIEN1cmlvc2lkYWQNCg0KU2llbXByZSBxdWUgbGxlZ2EgdW4gR3JhbmQgU2xhbSBsYXMgY2FzYXMgZGUgYXB1ZXN0YXMgc2UgbGxlbmFuIGRlIHByZWRpY2Npb25lcyBzb2JyZSBxdWnDqW4gc2Vyw6EgbGEgc29ycHJlc2EgZGVsIHRvcm5lby4gVmVyIGdhbmFyIHVuIEdyYW5kIFNsYW0gYSB1biBqdWdhZG9yIGRlIGZ1ZXJhIGRlbCBUb3AgNSBlcyBhbGdvIGJhc3RhbnRlIGV4dHJhw7FvIGVuIGVsIHRlbmlzIG1hc2N1bGluby4gTm8gdGFudG8gZW4gZWwgdGVuaXMgZmVtZW5pbm8sIGRvbmRlIGVzdGUgdGlwbyBkZSBzb3JwcmVzYXMgc29uIG3DoXMgaGFiaXR1YWxlcy4gRWwgw7psdGltbyBjYXNvIGZ1ZSBlbCBkZSBsYSB0ZW5pc3RhIGJyaXTDoW5pY2EgUmFkdWNhbnUsIHF1acOpbiBlbiBlbCBwYXNhZG8gVVMgT3BlbiBnYW7DsyBzdSBwcmltZXIgZ3JhbmRlIHNpZW5kbyBsYSBuw7ptZXJvIDE1MCBkZWwgcmFua2luZyBXVEEuDQoNCk5vIG9ic3RhbnRlLCB2b2x2aWVuZG8gYWwgdGVuaXMgbWFzY3VsaW5vLCDCv2VuIHF1w6kgdG9ybmVvIGRlIEdyYW5kIFNsYW0gc2UgaGFuIGRhZG8gbcOhcyBzb3JwcmVzYXM/DQoNCmBgYHtyfQ0Kbm9fc2VyaWUgPC0gZ3JhbmRfc2xhbXMgJT4lIGdyb3VwX2J5KE1ham9yKSAlPiUgc3VtbWFyaXNlKGBObyBjYWJlemEgZGUgc2VyaWVgID0gc3VtKGlzLm5hKENhYmV6YV9zZXJpZV9jYW1wZcOzbikpKSAlPiUgYXJyYW5nZShkZXNjKGBObyBjYWJlemEgZGUgc2VyaWVgKSkNCg0Kc2VyaWUxIDwtIGdyYW5kX3NsYW1zICU+JSBncm91cF9ieShNYWpvcikgJT4lIGZpbHRlcihDYWJlemFfc2VyaWVfY2FtcGXDs24gPT0gMSkgJT4lIHN1bW1hcmlzZShgQ2FiZXphIGRlIHNlcmllIDFgID0gbigpKSAlPiUgYXJyYW5nZShkZXNjKGBDYWJlemEgZGUgc2VyaWUgMWApKQ0KDQpzZXJpZV9tZW5vcl80IDwtIGdyYW5kX3NsYW1zICU+JSBncm91cF9ieShNYWpvcikgJT4lIGZpbHRlcihDYWJlemFfc2VyaWVfY2FtcGXDs24gPD0gNCkgJT4lIHN1bW1hcmlzZShgQ2FiZXphIGRlIHNlcmllIDwgNGAgPSBuKCkpICU+JSBhcnJhbmdlKGRlc2MoYENhYmV6YSBkZSBzZXJpZSA8IDRgKSkNCg0Kc2VyaWVfZW50cmVfNF95XzEwIDwtIGdyYW5kX3NsYW1zICU+JSBncm91cF9ieShNYWpvcikgJT4lIGZpbHRlcihDYWJlemFfc2VyaWVfY2FtcGXDs24gPiA0ICYgQ2FiZXphX3NlcmllX2NhbXBlw7NuIDw9IDEwKSAlPiUgc3VtbWFyaXNlKGBDYWJlemEgZGUgc2VyaWUgZW50cmUgNCB5IDEwYCA9IG4oKSkgJT4lIGFycmFuZ2UoZGVzYyhgQ2FiZXphIGRlIHNlcmllIGVudHJlIDQgeSAxMGApKQ0KDQpzZXJpZV9lbnRyZV8xMF95XzMyIDwtIGdyYW5kX3NsYW1zICU+JSBncm91cF9ieShNYWpvcikgJT4lIGZpbHRlcihDYWJlemFfc2VyaWVfY2FtcGXDs24gPiAxMCAmIENhYmV6YV9zZXJpZV9jYW1wZcOzbiA8PSAzMikgJT4lIHN1bW1hcmlzZShgQ2FiZXphIGRlIHNlcmllID4gMTBgID0gbigpKSAlPiUgYXJyYW5nZShkZXNjKGBDYWJlemEgZGUgc2VyaWUgPiAxMGApKQ0KDQphMSA8LSBmdWxsX2pvaW4oc2VyaWVfbWVub3JfNCwgc2VyaWVfZW50cmVfNF95XzEwLCBieT0gYygiTWFqb3IiID0gIk1ham9yIikpICANCg0KYTIgPC0gZnVsbF9qb2luKGExLCBzZXJpZV9lbnRyZV8xMF95XzMyLCBieT0gYygiTWFqb3IiID0gIk1ham9yIikpICANCg0KYTMgPC0gZnVsbF9qb2luKGEyLCBub19zZXJpZSwgYnk9IGMoIk1ham9yIiA9ICJNYWpvciIpKQ0KDQphNCA8LSBhMyAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSAyOjUsIG5hbWVzX3RvID0gIkNhYmV6YSBkZSBzZXJpZSIsIHZhbHVlc190byA9ICJHYW5hZG9yZXMiLCB2YWx1ZXNfdHJhbnNmb3JtID0gbGlzdChHYW5hZG9yZXMgPSBhcy5udW1lcmljKSkNCg0KYTUgPC0gYTQgJT4lIG11dGF0ZShgQ2FiZXphIGRlIHNlcmllYCA9IGZvcmNhdHM6OmFzX2ZhY3RvcihgQ2FiZXphIGRlIHNlcmllYCkpDQoNCmdncGxvdChhNSwgYWVzKHg9TWFqb3IsIHk9IEdhbmFkb3JlcywgZmlsbD0gYENhYmV6YSBkZSBzZXJpZWApKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgbGFicyh0aXRsZSA9ICJOw7ptZXJvIGRlIGdhbmFkb3JlcyBwb3IgY2FiZXphIGRlIHNlcmllIikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIkF1c3RyYWxpYW5cbk9wZW4iLCAiUm9sYW5kXG5HYXJyb3MiLCAiVVNcbk9wZW4iLCAiV2ltYmxlZG9uIikpICsNCiAgdGhlbWVfaXBzdW0oKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLCBmYWNlID0gImJvbGQiKSkNCmBgYA0KDQpMYSBncsOhZmljYSBhbnRlcmlvciBub3MgbXVlc3RyYSBxdWUgZWwgdG9ybmVvIGTDs25kZSBtw6FzIHNvcnByZXNhcyBzZSBoYW4gcHJvZHVjaWRvIGVzIFJvbGFuZCBHYXJyb3MuIEhpc3TDs3JpY2FtZW50ZSBlcyBlbCB0b3JuZW8gZW4gZWwgcXVlIG1lbm9zIHZlY2VzIGhhIGdhbmFkbyB1biBqdWdhZG9yIGRlbCBUb3AgNCB5IGVuIHF1ZSBtw6FzIHZlY2VzIGhhIGdhbmFkbyB1biBqdWdhZG9yIHF1ZSBsbGVnYWJhIGFsIHRvcm5lbyBzaW4gc2VyIHNlciBjYWJlemEgZGUgc2VyaWUgKGp1Z2Fkb3IgZGVudHJvIGRlIGxvcyAzMiBqdWdhZG9yZXMgY29uIG1lam9yIHJhbmtpbmcgaW5zY3JpdG9zIGFsIHRvcm5lbykuIFBvciBvdHJhIHBhcnRlLCBXaW1ibGVkb24gZXMgZWwgdG9ybmVvIGVuIGVsIHF1ZSBtw6FzIHZlY2VzIGhhIGdhbmFkbyB1biBjYWJlemEgZGUgc2VyaWUgbWVub3IgYWwgNCB5IGVsIFVTIE9wZW4gZWwgdG9ybmVvIGVuIGVsIHF1ZSBlcyBtZW5vcyBwcm9iYWJsZSBxdWUgdW4ganVnYWRvciBzaW4gc2VyIGNhYmV6YSBkZSBzZXJpZSBnYW5lLg0KDQpFc3RvcyBkYXRvcyByZXN1bHRhcsOhbiBkZSBncmFuIGludGVyw6lzIHBhcmEgcXVpw6luIGRlc2VlIGFwb3N0YXIgZXN0YSB0ZW1wb3JhZGEgcXVlIGVtcGllemEuIFBlcm8gY3VpZGFkbywgZGVzZGUgcXVlIFJhZmFlbCBOYWRhbCBpbXB1c28gc3UgbGV5IGVuIFJvbGFuZCBHYXJyb3MsIGVuIDEzIGRlIGxhcyDDumx0aW1hcyAxNyBlZGljaW9uZXMgZGVsIHRvcm5lbyBlbCBnYW5hZG9yIGhhIHNpZG8gZWwgdGVuaXN0YSBlc3Bhw7FvbC4gU2luIGR1ZGEsIGxhIG1lam9yIG9wY2nDs24gcGFyYSBsYSB2aWN0b3JpYS4NCg0KIyMgMy4yIFJlc3RvIGRlIHRvcm5lb3MNCg0KQ29udGludWFuZG8gY29uIGVsIGFuw6FsaXNpcywgcHJlc3RhcmVtb3MgYXRlbmNpw7NuIGEgbG9zIHJlc3VsdGFkb3Mgb2J0ZW5pZG9zIGVuIGVsIHJlc3RvIGRlIHRvcm5lb3MgcHJvZmVzaW9uYWxlcyBwb3IgcGFydGUgZGUgZXN0b3MgdGVuaXN0YXMuDQoNCmBgYHtyfQ0KYSA8LSByaW86OmltcG9ydChoZXJlOjpoZXJlKCJkYXRvcyIsICJ0ZW1wb3JhZGFzLmNzdiIpKQ0KDQptMTAwMCA8LSBhICU+JSBmaWx0ZXIoU2VyaWVzICVpbiUgYygiTWFzdGVycyAxMDAwIiwgIk1hc3RlcnMiKSwgUm91bmQgPT0gIlRoZSBGaW5hbCIsIFdpbm5lciAlaW4lIGMoIk5hZGFsIFIuIiwgIkZlZGVyZXIgUi4iLCAiRGpva292aWMgTi4iKSkgJT4lIGdyb3VwX2J5KFdpbm5lcikgJT4lIHN1bW1hcmlzZSh0b3RhbF9tYXN0ZXJzXzEwMDAgPSBuKCkpDQoNCm1hc3RlcnMgPC0gYSAlPiUgZmlsdGVyKFNlcmllcyAlaW4lIGMoIk1hc3RlcnMgQ3VwIiksIFJvdW5kID09ICJUaGUgRmluYWwiLCBXaW5uZXIgJWluJSBjKCJOYWRhbCBSLiIsICJGZWRlcmVyIFIuIiwgIkRqb2tvdmljIE4uIikpICU+JSBncm91cF9ieShXaW5uZXIpICU+JSBzdW1tYXJpc2UodG90YWxfbWFzdGVyc19jdXAgPSBuKCkpDQoNCmF0cDUwMCA8LSBhICU+JSBmaWx0ZXIoU2VyaWVzICVpbiUgYygiQVRQNTAwIiwgIkludGVybmF0aW9uYWwgR29sZCIpLCBSb3VuZCA9PSAiVGhlIEZpbmFsIiwgV2lubmVyICVpbiUgYygiTmFkYWwgUi4iLCAiRmVkZXJlciBSLiIsICJEam9rb3ZpYyBOLiIpKSAlPiUgZ3JvdXBfYnkoV2lubmVyKSAlPiUgc3VtbWFyaXNlKHRvdGFsX2F0cF81MDAgPSBuKCkpDQoNCmF0cDI1MCA8LSBhICU+JSBmaWx0ZXIoU2VyaWVzICVpbiUgYygiQVRQMjUwIiwgIkludGVybmF0aW9uYWwiKSwgUm91bmQgPT0gIlRoZSBGaW5hbCIsIFdpbm5lciAlaW4lIGMoIk5hZGFsIFIuIiwgIkZlZGVyZXIgUi4iLCAiRGpva292aWMgTi4iKSkgJT4lIGdyb3VwX2J5KFdpbm5lcikgJT4lIHN1bW1hcmlzZSh0b3RhbF9hdHBfMjUwID0gbigpKQ0KDQp0b3RhbDwtIGZ1bGxfam9pbihtYXN0ZXJzLCBtMTAwMCwgYnk9IGMoIldpbm5lciIgPSAiV2lubmVyIikpDQpqam9vIDwtIGMoMCwwLDEpDQp0b3RhbCA8LSBjYmluZCh0b3RhbCwgampvbykNCnRvdGFsIDwtIGZ1bGxfam9pbih0b3RhbCwgYXRwNTAwLCBieT0gYygiV2lubmVyIiA9ICJXaW5uZXIiKSkNCnRvdGFsIDwtIGZ1bGxfam9pbih0b3RhbCwgYXRwMjUwLCBieT0gYygiV2lubmVyIiA9ICJXaW5uZXIiKSkNCnRvdGFsIDwtIHRvdGFsICU+JSANCiAgc2VsZWN0KFdpbm5lciwgdG90YWxfbWFzdGVyc19jdXAsIGpqb28sIHRvdGFsX21hc3RlcnNfMTAwMCwNCiAgICAgICAgIHRvdGFsX2F0cF81MDAsIHRvdGFsX2F0cF8yNTApICU+JSANCiAgbXV0YXRlKHRvdGFsX21hc3RlcnNfY3VwID0gDQogICAgICAgICAgIGlmZWxzZShpcy5uYSh0b3RhbF9tYXN0ZXJzX2N1cCksIDAsIHRvdGFsX21hc3RlcnNfY3VwKSkgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gMjo2LCBuYW1lc190byA9ICJDYXRlZ29yw61hIiwgdmFsdWVzX3RvID0gIk7Dum1lcm8iKSANCg0KdG90YWwgPC0gdG90YWwgJT4lIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAiV2lubmVyIiwgdmFsdWVzX2Zyb20gPSAiTsO6bWVybyIpICU+JSBtdXRhdGUoQ2F0ZWdvcsOtYSA9IGNhc2Vfd2hlbigNCiAgQ2F0ZWdvcsOtYSA9PSAidG90YWxfbWFzdGVyc19jdXAiIH4gIkNvcGEgZGUgTWFlc3Ryb3MiLA0KICBDYXRlZ29yw61hID09ICJqam9vIiB+ICJKdWVnb3MgT2zDrW1waWNvcyIsDQogIENhdGVnb3LDrWEgPT0gInRvdGFsX21hc3RlcnNfMTAwMCIgfiAiTWFzdGVycyAxMDAwIiwNCiAgQ2F0ZWdvcsOtYSA9PSAidG90YWxfYXRwXzUwMCIgfiAiQVRQIDUwMCIsDQogIENhdGVnb3LDrWEgPT0gInRvdGFsX2F0cF8yNTAiIH4gIkFUUCAyNTAiLA0KICBUUlVFIH4gQ2F0ZWdvcsOtYSkpDQoNCnRvdGFsICU+JSBndChyb3duYW1lX2NvbCA9ICJDYXRlZ29yw61hIikgJT4lIA0KICB0YWJfaGVhZGVyKHRpdGxlID0gIk7Dum1lcm8gZGUgdG9ybmVvcyBwb3IgY2F0ZWdvcsOtYSIsDQogICAgICAgICAgICAgc3VidGl0bGUgPSAiRXhjbHV5ZW5kbyB0b3JuZW9zIGRlIEdyYW5kIFNsYW0iKSAlPiUgDQogIHRhYl9vcHRpb25zKGhlYWRpbmcuYmFja2dyb3VuZC5jb2xvciA9ICIjRDRBRjM3IikgJT4lIHRhYl9vcHRpb25zKGhlYWRpbmcudGl0bGUuZm9udC5zaXplID0gMjIsIGhlYWRpbmcuc3VidGl0bGUuZm9udC5zaXplID0gMTUsICBjb2x1bW5fbGFiZWxzLmZvbnQud2VpZ2h0ID0gICJib2xkIikgJT4lIA0KICBjb2xzX2FsaWduKGFsaWduID0gImNlbnRlciIpICU+JSANCiAgY29sc19sYWJlbCgNCiAgICBgRGpva292aWMgTi5gID0gIk5vdmFrIERqb2tvdmljIiwNCiAgICBgRmVkZXJlciBSLmAgPSAiUm9nZXIgRmVkZXJlciIsDQogICAgYE5hZGFsIFIuYCA9ICJSYWZhZWwgTmFkYWwiKSAlPiUgDQogIGNvbHNfbW92ZV90b19zdGFydCgNCiAgICBjb2x1bW5zID0gYyhgRmVkZXJlciBSLmAsIGBOYWRhbCBSLmAsIGBEam9rb3ZpYyBOLmApKSAlPiUgDQogIHRhYl9mb290bm90ZSgNCiAgICBmb290bm90ZSA9ICJNZWRhbGxhIGRlIG9ybyBlbiBpbmRpdmlkdWFsZXMiLA0KICAgIGxvY2F0aW9ucyA9IGNlbGxzX3N0dWIocm93cyA9IDIpKSAlPiUgDQogIHRhYl9mb290bm90ZSgNCiAgICBmb290bm90ZSA9ICJQcmV2aW8gYSAyMDA5IGxsYW1hZG9zIEludGVybmF0aW9uYWwgR29sZCIsDQogICAgbG9jYXRpb25zID0gY2VsbHNfc3R1Yihyb3dzID0gNCkpICU+JSANCiAgdGFiX2Zvb3Rub3RlKA0KICAgIGZvb3Rub3RlID0gIlByZXZpbyBhIDIwMDkgbGxhbWFkb3MgSW50ZXJuYXRpb25hbCIsDQogICAgbG9jYXRpb25zID0gY2VsbHNfc3R1Yihyb3dzID0gNSkpICU+JSANCiAgdGFiX3N0eWxlKHN0eWxlID0gbGlzdChjZWxsX2ZpbGwoY29sb3IgPSAiZ3JlZW4iKSksDQogICAgICAgICAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBgRmVkZXJlciBSLmAsDQogICAgICByb3dzID0gYygxLCA0LCA1KSkpICU+JSANCiAgdGFiX3N0eWxlKHN0eWxlID0gbGlzdChjZWxsX2ZpbGwoY29sb3IgPSAiZ3JlZW4iKSksDQogICAgICAgICAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBgTmFkYWwgUi5gLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dzID0gMikpICAlPiUgDQogIHRhYl9zdHlsZShzdHlsZSA9IGxpc3QoY2VsbF9maWxsKGNvbG9yID0gImdyZWVuIikpLA0KICAgICAgICAgICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gYERqb2tvdmljIE4uYCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93cyA9IDMpKSANCg0KYGBgDQoNClNlIHRvcm5hIGNvbXBsaWNhZG8gY29uY2x1aXIgcXXDqSBqdWdhZG9yIHByZXNlbnRhIG1lam9yZXMgY2lmcmFzLiBFbnRyZSBsb3MgdHJlcyBzZSByZXBhcnRlbiBlbCBsaWRlcmF0byBlbiBsYXMgdHJlcyBjYXRlZ29yw61hcyBkZSBpbXBvcnRhbmNpYSByZXN0YW50ZXMuIEZlZGVyZXIgZXMgZWwganVnYWRvciBxdWUgbWF5b3IgbsO6bWVybyBkZSBDb3BhcyBkZSBNYWVzdHJvIHRpZW5lLiBQb3Igb3RybyBsYWRvLCBOYWRhbCBlcyBlbCDDum5pY28gZGUgbG9zIHRyZXMgZW4gb2J0ZW5lciB1bmEgbWVkYWxsYSBkZSBvcm8gZW4gaW5kaXZpZHVhbGVzIGVuIHVub3MgSnVlZ29zIE9sw61tcGljb3MuIFkgZW4gY3VhbnRvIGEgTWFzdGVycyAxMDAwIHNlIHJlZmllcmUsIGVzIERqb2tvdmljIGVsIHF1ZSBsaWRlcmEgZXN0YSBjbGFzaWZpY2FjacOzbiBjb24gMzcsIHVubyBtw6FzIHF1ZSBsb3MgZ2FuYWRvcyBwb3IgTmFkYWwuIEZpbmFsbWVudGUsIGVzIGzDs2dpY28gcXVlIEZlZGVyZXIgc2VhIGVsIGp1Z2Fkb3IgcXVlIG1heW9yIGNhbnRpZGFkIGRlIHRvcm5lb3MgQVRQIDUwMCB5IEFUUCAyNTAgaGEgZ2FuYWRvLCBwdWVzdG8gcXVlIGVzIDUgeSA2IGHDsW9zIG1heW9yIHF1ZSBOYWRhbCB5IERqb2tvdmljLCByZXNwZWN0aXZhbWVudGUuDQoNCkRlIGVzdGEgZm9ybWEsIG5vIGVzIHBvc2libGUgY29uY2x1aXIgcXXDqSBqdWdhZG9yIGRlbCBCaWcgMyB0aWVuZSBtZWpvcmVzIG7Dum1lcm9zIGVuIGN1YW50byBhIHRvcm5lb3MgZ2FuYWRvcyBhIGTDrWEgZGUgaG95LiBFc3RvIHNlIGRlYmUgYSBxdWUgbGFzIGFjdHVhY2lvbmVzIGRlIGVzdG9zIHRyZXMganVnYWRvcmVzIGVzIHNvYnJlc2FsaWVudGUgZW4gY2FkYSBjYXRlZ29yw61hLiBEZWJlcmVtb3Mgc2VndWlyIHJlcGFzYW5kbyBkaXN0aW50b3MgY3JpdGVyaW9zIHBhcmEgdHJhdGFyIGRlIGRhciByZXNwdWV0YSBhIG51ZXN0cmEgY3Vlc3Rpw7NuLg0KDQojIDQuIENyaXRlcmlvIDI6IFJhbmtpbmcgQVRQDQoNCkxhIGltcG9ydGFuY2lhIGVudHJlIGdhbmFyIHVuIHRvcm5lbyB1IG90cm8gc2UgZGVmaW5lLCBlbnRyZSBvdHJvcyBhc3BlY3RvcyBjb21vIGVsIHByZXN0aWdpbywgcG9yIGxhIGNhbnRpZGFkIGRlIHB1bnRvcyBxdWUgcmVwYXJ0ZS4gRW4gZXN0ZSBhcGFydGFkbyBhbmFsaXphcmVtb3MgY8OzbW8gaGEgc2lkbyBlbiByZW5kaW1pZW50byBkZSBlc3RvcyB0cmVzIGp1Z2Fkb3JlcyBhIGxvIGxhcmdvIGRlbCB0aWVtcG8uDQoNCmBgYHtyLCBvdXQud2lkdGg9ICIxMDAlIn0NCmp1Z2Fkb3JlcyA8LSBqdWdhZG9yZXMgJT4lIG11dGF0ZShuYW1lID0gcGFzdGUobmFtZV9maXJzdCwgbmFtZV9sYXN0LCBzZXAgPSAiICIpLCAuYWZ0ZXIgPSBwbGF5ZXJfaWQpICU+JSBzZWxlY3QocGxheWVyX2lkLCBuYW1lLCBpb2MpDQoNCiMjIyBFdm9sdWNpw7NuIHB1bnRvcyBBVFANCg0KZGQgPC0gbGVmdF9qb2luKHJhbmtpbmcsIGp1Z2Fkb3JlcywgYnkgPSBjKCJwbGF5ZXIiID0gInBsYXllcl9pZCIpKSAlPiUgZmlsdGVyKG5hbWUgJWluJSBjKCJSYWZhZWwgTmFkYWwiLCAiUm9nZXIgRmVkZXJlciIsICJOb3ZhayBEam9rb3ZpYyIpKSAlPiUgbXV0YXRlKHJhbmtpbmdfZGF0ZSA9IHltZChyYW5raW5nX2RhdGUpKSAlPiUgbXV0YXRlKHBvaW50cyA9IGFzLm51bWVyaWMocG9pbnRzKSwgcmFuayA9IGFzLm51bWVyaWMocmFuaykpICU+JSBzZWxlY3QocmFua2luZ19kYXRlLCBwb2ludHMsIG5hbWUpICU+JSBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gIm5hbWUiLCB2YWx1ZXNfZnJvbSA9ICJwb2ludHMiKQ0KDQpGZWRlcmVyIDwtIHh0cyhkZCRgUm9nZXIgRmVkZXJlcmAsIG9yZGVyLmJ5ID0gZGQkcmFua2luZ19kYXRlKQ0KDQpOYWRhbCA8LSB4dHMoZGQkYFJhZmFlbCBOYWRhbGAsIG9yZGVyLmJ5ID0gZGQkcmFua2luZ19kYXRlKQ0KDQpEam9rb3ZpYyA8LSB4dHMoZGQkYE5vdmFrIERqb2tvdmljYCwgb3JkZXIuYnkgPSBkZCRyYW5raW5nX2RhdGUpDQoNCnAgPC0gY2JpbmQoRmVkZXJlciwgTmFkYWwsIERqb2tvdmljKSANCg0KZHlncmFwaChwLCB5bGFiPSAiUHVudG9zIEFUUCIsDQogICAgICAgIG1haW4gPSAiRXZvbHVjacOzbiBwdW50b3MgQVRQIGRlbCBCaWcgMyIpICU+JSANCiAgZHlPcHRpb25zKGNvbG9ycyA9IGMoImJsdWUiLCAiZ3JlZW4iLCAiYnJvd24iKSkgJT4lIA0KICBkeVJhbmdlU2VsZWN0b3IoKSANCmBgYA0KDQpDb24gZWwgZmluIGRlIG9ic2VydmFyIGVsIHJlbmRpbWllbnRvIGRlbCBCaWcgMywgaGVtb3MgY2FsY3VsYWRvIGxhIGNhbnRpZGFkIGRlIHB1bnRvcyBkZSBjYWRhIGp1Z2Fkb3IgZHVyYW50ZSBjYWRhIHNlbWFuYSBkZWwgYcOxbyBkZXNkZSBsYSB0ZW1wb3JhZGEgZGVsIGHDsW8gMjAwMCwgbW90aXZvIHBvciBlbCBjdcOhbCBGZWRlcmVyIGVtcGllemEgZWwgcGVyaW9kbyBjb24gYWxyZWRlZG9yIGRlIDkwMCBwdW50b3MuIEVzIGluY3Jlw61ibGUgb2JzZXJ2YXIgbGEgcmVndWxhcmlkYWQgZGUgZXN0b3MgdHJlcyBqdWdhZG9yZXMgYSBsbyBsYXJnbyBkZSBsb3MgYcOxb3MsIHNpZW1wcmUgbXV5IHBvciBlbmNpbWEgZGUgbG9zIDIwMDAgcHVudG9zLiBQYXJhIHF1ZSBub3MgaGFnYW1vcyB1bmEgaWRlYSwgYWxyZWRlZG9yIGRlIDIwMDAgcHVudG9zIHNvbiBsb3MgcXVlIG5lY2VzaXRhIGNvbnNlZ3VpciB1biBqdWdhZG9yIGVuIHVuIGHDsW8gcGFyYSBlc3RhciBkZW50cm8gZGVsIFRvcCAyMC4uLg0KDQpTaW4gZW1iYXJnbywgcG9kZW1vcyBhcHJlY2lhciBxdWUgZWwgcmVuZGltaWVudG8geSByZWd1bGFyaWRhZCBlcyBhbGdvIG1heW9yIGVuIERqb2tvdmljIHF1ZSBlbiBlbCByZXN0bywgYSBleGNlcGNpw7NuIGRlbCBwZXJpb2RvIHF1ZSBhYmFyY2EgZGVzZGUgbWVkaWFkb3MgZGUgMjAxNyBoYXN0YSBmaW5hbGVzIGRlIDIwMTggZW4gZWwgcXVlIGVsIHRlbmlzdGEgYmFsY8OhbmljbyBzdWZyacOzIHByb2JsZW1hcyBkZSBlc3BhbGRhLg0KDQpgYGB7cn0NCnJhbmtpbmcyIDwtIHJhbmtpbmcNCg0KVG9wXzEgPC0gbGVmdF9qb2luKHJhbmtpbmcyLCBqdWdhZG9yZXMsIGJ5ID0gYygicGxheWVyIiA9ICJwbGF5ZXJfaWQiKSkgJT4lIGZpbHRlcihuYW1lICVpbiUgYygiUmFmYWVsIE5hZGFsIiwgIlJvZ2VyIEZlZGVyZXIiLCAiTm92YWsgRGpva292aWMiKSkgJT4lIG11dGF0ZShyYW5raW5nX2RhdGUgPSB5bWQocmFua2luZ19kYXRlKSkgJT4lIG11dGF0ZShwb2ludHMgPSBhcy5udW1lcmljKHBvaW50cyksIHJhbmsgPSBhcy5udW1lcmljKHJhbmspKSAlPiUgc2VsZWN0KHJhbmtpbmdfZGF0ZSwgcmFuaywgbmFtZSkgJT4lIGZpbHRlcihyYW5rID09IDEpICU+JSBncm91cF9ieShuYW1lKSAlPiUgc3VtbWFyaXNlKFRvcDEgPSBuKCkpIA0KDQpUb3QgPC0gbGVmdF9qb2luKHJhbmtpbmcyLCBqdWdhZG9yZXMsIGJ5ID0gYygicGxheWVyIiA9ICJwbGF5ZXJfaWQiKSkgJT4lIGZpbHRlcihuYW1lICVpbiUgYygiUmFmYWVsIE5hZGFsIiwgIlJvZ2VyIEZlZGVyZXIiLCAiTm92YWsgRGpva292aWMiKSkgJT4lIG11dGF0ZShyYW5raW5nX2RhdGUgPSB5bWQocmFua2luZ19kYXRlKSkgJT4lIG11dGF0ZShwb2ludHMgPSBhcy5udW1lcmljKHBvaW50cyksIHJhbmsgPSBhcy5udW1lcmljKHJhbmspKSAlPiUgc2VsZWN0KHJhbmtpbmdfZGF0ZSwgcmFuaywgbmFtZSkgJT4lIGRyb3BfbmEoKSAlPiUgIGdyb3VwX2J5KG5hbWUpICU+JSBzdW1tYXJpc2UoVG90ID0gbigpKQ0KDQpUb3BfMyA8LSBsZWZ0X2pvaW4ocmFua2luZzIsIGp1Z2Fkb3JlcywgYnkgPSBjKCJwbGF5ZXIiID0gInBsYXllcl9pZCIpKSAlPiUgZmlsdGVyKG5hbWUgJWluJSBjKCJSYWZhZWwgTmFkYWwiLCAiUm9nZXIgRmVkZXJlciIsICJOb3ZhayBEam9rb3ZpYyIpKSAlPiUgbXV0YXRlKHJhbmtpbmdfZGF0ZSA9IHltZChyYW5raW5nX2RhdGUpKSAlPiUgbXV0YXRlKHBvaW50cyA9IGFzLm51bWVyaWMocG9pbnRzKSwgcmFuayA9IGFzLm51bWVyaWMocmFuaykpICU+JSBzZWxlY3QocmFua2luZ19kYXRlLCByYW5rLCBuYW1lKSAlPiUgZmlsdGVyKHJhbmsgPD0gMykgJT4lIGdyb3VwX2J5KG5hbWUpICU+JSBzdW1tYXJpc2UoVG9wMyA9IG4oKSkNCg0KVG9wXzEwIDwtIGxlZnRfam9pbihyYW5raW5nMiwganVnYWRvcmVzLCBieSA9IGMoInBsYXllciIgPSAicGxheWVyX2lkIikpICU+JSBmaWx0ZXIobmFtZSAlaW4lIGMoIlJhZmFlbCBOYWRhbCIsICJSb2dlciBGZWRlcmVyIiwgIk5vdmFrIERqb2tvdmljIikpICU+JSBtdXRhdGUocmFua2luZ19kYXRlID0geW1kKHJhbmtpbmdfZGF0ZSkpICU+JSBtdXRhdGUocG9pbnRzID0gYXMubnVtZXJpYyhwb2ludHMpLCByYW5rID0gYXMubnVtZXJpYyhyYW5rKSkgJT4lIHNlbGVjdChyYW5raW5nX2RhdGUsIHJhbmssIG5hbWUpICU+JSBmaWx0ZXIocmFuayA8PSAxMCkgJT4lIGdyb3VwX2J5KG5hbWUpICU+JSBzdW1tYXJpc2UoVG9wMTAgPSBuKCkpDQoNCnRhYmxhIDwtIGxlZnRfam9pbihUb3BfMSwgVG9wXzMsIGJ5ID0gYygibmFtZSIgPSAibmFtZSIpKQ0KDQp0YWJsYSA8LSBsZWZ0X2pvaW4odGFibGEsIFRvcF8xMCwgYnkgPSBjKCJuYW1lIiA9ICJuYW1lIikpDQoNCnRhYmxhIDwtIGxlZnRfam9pbih0YWJsYSwgVG90LCBieSA9IGMoIm5hbWUiID0gIm5hbWUiKSkNCg0KdGFibGEgPC0gdGFibGEgJT4lIG11dGF0ZShUb3AxX3BvcmMgPSBUb3AxL1RvdCwgLmFmdGVyID0gVG9wMSkgJT4lIG11dGF0ZShUb3AzX3BvcmMgPSBUb3AzL1RvdCwgLmFmdGVyID0gVG9wMykgJT4lIG11dGF0ZShUb3AxMF9wb3JjID0gVG9wMTAvVG90LCAuYWZ0ZXIgPSBUb3AxMCkgDQogIA0KdGFibGEgJT4lIGd0KHJvd25hbWVfY29sID0gIm5hbWUiKSAlPiUgDQogIHRhYl9oZWFkZXIodGl0bGUgPSAiTnVtZXJvIGRlIHNlbWFuYXMgdG9wIGRlbCByYW5raW5nIEFUUCIsDQogICAgICAgICAgICAgICAgICAgICAgc3VidGl0bGUgPSAiSnVnYWRvcmVzIGRlbCBCaWczIikgJT4lIA0KICB0YWJfb3B0aW9ucyhoZWFkaW5nLmJhY2tncm91bmQuY29sb3IgPSAiI0NEN0YzMiIpICU+JSB0YWJfb3B0aW9ucyhoZWFkaW5nLnRpdGxlLmZvbnQuc2l6ZSA9IDIyLCBoZWFkaW5nLnN1YnRpdGxlLmZvbnQuc2l6ZSA9IDE1LCAgY29sdW1uX2xhYmVscy5mb250LndlaWdodCA9ICAiYm9sZCIpICU+JSANCiAgY29sc19hbGlnbihhbGlnbiA9ICJjZW50ZXIiKSAlPiUgDQogIGNvbHNfbGFiZWwoDQogICAgVG9wMSA9ICJUb3AgMSIsDQogICAgVG9wMV9wb3JjID0gIlBvcmNlbnRhamUiLA0KICAgIFRvcDMgPSAiVG9wIDMiLA0KICAgIFRvcDNfcG9yYyA9ICJQb3JjZW50YWplIiwNCiAgICBUb3AxMCA9ICJUb3AgMTAiLA0KICAgIFRvcDEwX3BvcmMgPSAiUG9yY2VudGFqZSIsDQogICAgVG90ID0gIlRvdGFsIikgJT4lIA0KICBmbXRfcGVyY2VudChjb2x1bW5zPSBjKDMsIDUsIDcpLCANCiAgICAgICAgICAgICAgZGVjaW1hbHMgPSAyKSAlPiUgDQogIHRhYl9zdHlsZShzdHlsZSA9IGxpc3QoY2VsbF9maWxsKGNvbG9yID0gImdyZWVuIikpLA0KICAgICAgICAgICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gVG9wMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93cyA9IDEpKSAlPiUgDQogIHRhYl9zdHlsZShzdHlsZSA9IGxpc3QoY2VsbF9maWxsKGNvbG9yID0gImdyZWVuIikpLA0KICAgICAgICAgICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gVG9wMV9wb3JjLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dzID0gMSkpICAlPiUgDQogIHRhYl9zdHlsZShzdHlsZSA9IGxpc3QoY2VsbF9maWxsKGNvbG9yID0gImdyZWVuIikpLA0KICAgICAgICAgICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gVG9wMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93cyA9IDMpKSAgJT4lIA0KICB0YWJfc3R5bGUoc3R5bGUgPSBsaXN0KGNlbGxfZmlsbChjb2xvciA9ICJncmVlbiIpKSwNCiAgICAgICAgICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IFRvcDNfcG9yYywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93cyA9IDEpKSAgJT4lIA0KICB0YWJfc3R5bGUoc3R5bGUgPSBsaXN0KGNlbGxfZmlsbChjb2xvciA9ICJncmVlbiIpKSwNCiAgICAgICAgICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IFRvcDEwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dzID0gMykpICU+JSANCiAgdGFiX3N0eWxlKHN0eWxlID0gbGlzdChjZWxsX2ZpbGwoY29sb3IgPSAiZ3JlZW4iKSksDQogICAgICAgICAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBUb3AxMF9wb3JjLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dzID0gMikpIA0KYGBgDQoNCkxhIHRhYmxhIGFudGVyaW9yIG5vcyB0ZXJtaW5hIGRlIGRhciB1biB2aXNpw7NuIGFjZXJjYSBkZSBsb3MgaW5jcmXDrWJsZXMgbsO6bWVyb3MgZGUgTm92YWsgRGpva292aWMuIEVsIHRlbmlzdGEgc2VyYmlvIGVzIGVsIGp1Z2Fkb3IgZGUgbGEgaGlzdG9yaWEgcXVlIG3DoXMgc2VtYW5hcyBoYSBlc3RhZG8gYWwgZnJlbnRlIGRlbCByYW5raW5nIG11bmRpYWwsIHNlZ3VpZG8gZGUgRmVkZXJlci4gQWRlbcOhcywgZXN0ZSByw6ljb3JkIHNlIHNpZ3VlIGFtcGxpYW5kbyBzZW1hbmEgdHJhcyBzZW1hbmEsIHB1ZXN0byBxdWUgRGpva292aWMgZXMgZWwgYWN0dWFsIG7Dum1lcm8gMSBkZWwgbXVuZG8uIEFkZW3DoXMsIGVzIGVsIGp1Z2Fkb3IgcXVlIG3DoXMgcG9yY2VudGFqZSBkZSBzZW1hbmFzIGhhIGVzdGFkbyBlbiBlbCBUb3AgMy4gRWwgw7puaWNvIGFzcGVjdG8gZW4gZWwgcXVlIG5vIGVzIGVsIGzDrWRlciwgZXMgZW4gZWwgcG9yY2VudGFqZSBkZSBzZW1hbmFzIGRlbnRybyBkZWwgVG9wIDEwLiBFbiBlc3RlIGFzcGVjdG8gTmFkYWwgZXMgZWwgbsO6bWVybyAxLCBjb24gbcOhcyBkZWwgODAlIGRlbCB0aWVtcG8gcXVlIGxsZXZhIGNvbW8gcHJvZmVzaW9uYWwgZGVudHJvIGRlIGxvcyAxMCBtZWpvcmVzIGRlbCBtdW5kby4gVW5hIG11ZXN0cmEgbcOhcyBkZSBsYSBwcmVjb2NpZGFkIHkgbGEgcmVndWxhcmlkYWQgZGVsIHRlbmlzdGEgZXNwYcOxb2wuDQoNCkVuIGVzdGUgYXBhcnRhZG8sIHBvZGVtb3MgY29uY2x1aXIgcXVlIE5vdmFrIERqb2tvdmljIGVzIGVsIG1lam9yIGRlIHRvZG9zIGxvcyB0aWVtcG9zLiBTdSByw6ljb3JkIGFsIGZyZW50ZSBkZWwgcmFua2luZyBlcywgc2luIGR1ZGEgYWxndW5hLCB1bm8gZGUgbG9zIG3DoXMgZG9taW5hbnRlcyBkZWwgZGVwb3J0ZSBtdW5kaWFsLiBVbiByw6ljb3JkIGRpZsOtY2lsbWVudGUgZGUgc3VwZXJhciB5IGRlbCBxdWUgc29sbyBwb2RlbW9zIHNlbnRpciBvcmd1bGxvIHBvciBoYWJlciBwb2RpZG8gdml2aXJsby4NCg0KIyA1LiBDcml0ZXJpbyAzOiBTdXBlcmZpY2llIGRlIGp1ZWdvDQoNCkVsIHRlbmlzIGVzIHNpbiBsdWdhciBhIGR1ZGFzIHVubyBkZSBsb3MgZGVwb3J0ZXMgZW4gbG9zIHF1ZSBleGlzdGUgdW5hIG1heW9yIGRpdmVyc2lkYWQgZGUgZXN0aWxvcyB5IGZvcm1hcyBkZSBqdWVnby4gRXN0bywgc3VtYWRvIGEgbGEgZXhpc3RlbmNpYSBkZSBsYXMgZGlmZXJlbnRlcyBzdXBlcmZpY2llcyBkZSBqdWVnbyBlbiBsYXMgcXVlIHNlIGRpc3B1dGFuIGxvcyB0b3JuZW9zLCBjcmVhbiBsYSBjb21iaW5hY2nDs24gcGVyZmVjdGEgcGFyYSBxdWUgZGVwZW5kaWVuZG8gZGUgZW4gbGEgcGFydGUgZGUgbGEgdGVtcG9yYWRhIGVuIGxhIHF1ZSBub3MgZW5jb250cmVtb3MsIGxhcyBjb25kaWNpb25lcyBjbGltw6F0aWNhcyB5IGxhIHN1cGVyZmljaWUgZGUganVlZ28gdW5vcyBqdWdhZG9yZXMgZGVzdGFxdWVuIG3DoXMgc29icmUgZWwgcmVzdG8gcXVlIG90cm9zLg0KDQpIaXN0w7NyaWNhbWVudGUgZXhpc3TDrWFuIDQgc3VwZXJmaWNpZXMgZGUganVlZ286DQoNCi0gICBUaWVycmEgYmF0aWRhOiBwaXN0YXMgY3JlYWRhcyBlbiBiYXNlIGEgcG9sdm8gZGUgbGFkcmlsbG8gcXVlIGRlc3RhY2FuIHBvciBzZXIgbGFzIG3DoXMgbGVudGFzIHkgcG9yIHVuIGJvdGUgZGUgYm9sYSBhbHRvLg0KDQotICAgU3VwZXJmaWNpZSBkdXJhOiBwaXN0YXMgZGUgY2VtZW50byBjdXlhIHJhcGlkZXogdmFyw61hIHNlZ8O6biBlbCB0aXBvIGRlIG1hdGVyaWFsIGNvbiBxdWUgc2UgZmFicmlxdWVuLg0KDQotICAgSGllcmJhOiBkZXN0YWNhbiBwb3Igc3UgcmFwaWRleiB5IHBvciBzdSBiYWpvIGJvdGUgZGUgYm9sYS4NCg0KLSAgIE1vcXVldGE6IGRlc3RhY2FuIHBvciBzdSBhbHRhIHZlbG9jaWRhZCBkZSBib2xhIHkgcG9yIGp1Z2Fyc2UgYmFqbyB0ZWNoby4NCg0KU2luIGVtYmFyZ28sIGRlc2RlIGxhIHRlbXBvcmFkYSAyMDA5LCBsYSBBVFAgZGVjaWRpw7MgZWxpbWluYXIgbG9zIHRvcm5lb3MgcXVlIHNlIGRpc3B1dGFiYW4gc29icmUgbW9xdWV0YSwgcmVtcGxhesOhbmRvbG9zIHBvciBzdXBlcmZpY2llIGR1cmEuIERlIGVzdGEgZm9ybWEsIGxvcyBkaXN0aW50b3MgdG9ybmVvcyBkaXNwdXRhZG9zIGEgbG8gbGFyZ28gZGVsIGHDsW8gc2UgZGlzcHV0YW4gbyBiaWVuIGVsIHRpZXJyYSwgZHVyYSBvIGhpZXJiYSB5IG8gYmllbiBhbCBhaXJlIGxpYnJlIG8gYmFqbyB0ZWNoby4gRGVwZW5kaWVuZG8gbGEgY29tYmluYWNpw7NuIGRlIGVzdG9zIGRvcyBhc3BlY3RvcywgbGFzIGNvbmRpY2lvbmVzIGRlIGp1ZWdvIGNhbWJpYW4gZHLDoXN0aWNhbWVudGUuDQoNCkRlIGVzdGEgZm9ybWEsIHNlIHBvZHLDrWEgZGVjaXIgcXVlIGV4aXN0ZW4gKmRpc3RpbnRvcyB0aXBvcyBkZSB0ZW5pcyouIFBvciBlbGxvLCBhIGNvbnRpbnVhY2nDs24gdHJhdGFyZW1vcyBkZSBhbmFsaXphciBlbCByZW5kaW1pZW50byBkZWwgQmlnIDMgZGUgYWN1ZXJkbyBhbCB0aXBvIGRlIHBpc3RhLg0KDQpgYGB7cn0NCnRlbXBvcmFkYXMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAidGVtcG9yYWRhcy5jc3YiKSkNCg0KYWEgPC0gdGVtcG9yYWRhcyAlPiUgZmlsdGVyKFdpbm5lciAlaW4lIGMoIkZlZGVyZXIgUi4iLCAiTmFkYWwgUi4iLCAiRGpva292aWMgTi4iKSwgUm91bmQgPT0gIlRoZSBGaW5hbCIpICU+JSBncm91cF9ieShTdXJmYWNlLCBDb3VydCwgV2lubmVyKSAlPiUgc3VtbWFyaXNlKHTDrXR1bG9zID0gbigpKSAlPiUgdW5ncm91cCgpICU+JSANCiAgbXV0YXRlKFN1cmZhY2UgPSBjYXNlX3doZW4oDQogICAgU3VyZmFjZSA9PSJDYXJwZXQiIH4gICJNb3F1ZXRhIiwNCiAgICBTdXJmYWNlID09IkNsYXkiIH4gICJUaWVycmEgYmF0aWRhIiwNCiAgICBTdXJmYWNlID09IkdyYXNzIiB+ICAiSGllcmJhIiwNCiAgICBTdXJmYWNlID09IkhhcmQiIH4gICJEdXJhIikpICU+JSANCiAgbXV0YXRlKENvdXJ0ID0gY2FzZV93aGVuKA0KICAgIENvdXJ0ID09IkluZG9vciIgfiAgIkJham8gdGVjaG8iLA0KICAgIENvdXJ0ID09Ik91dGRvb3IiIH4gICJBaXJlIGxpYnJlIikpICU+JSANCiAgbXV0YXRlKFdpbm5lciA9IGNhc2Vfd2hlbigNCiAgICBXaW5uZXIgPT0iRmVkZXJlciBSLiIgfiAgIkZlZGVyZXIiLA0KICAgIFdpbm5lciA9PSJOYWRhbCBSLiIgfiAgIk5hZGFsIiwNCiAgICBXaW5uZXIgPT0iRGpva292aWMgTi4iIH4gICJEam9rb3ZpYyIpKQ0KDQpnZ3Bsb3QoYWEsIGFlcyh4ID0gV2lubmVyLCB5ID0gdMOtdHVsb3MsIGZpbGwgPSBDb3VydCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJOw7ptZXJvIGRlIHTDrXR1bG9zIHBvciBzdXBlcmZpY2llIiwgDQogICAgICAgc3VidGl0bGUgPSAiU3VwZXJmaWNpZToge2Nsb3Nlc3Rfc3RhdGV9IiwNCiAgICAgICBmaWxsPSAiVGlwbyBkZSBwaXN0YSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHTDrXR1bG9zKSwNCiAgICAgICAgICAgIHBvc2l0aW9uID0gIHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC44KSwNCiAgICAgICAgICAgIGZvbnRmYWNlPSAiYm9sZCIsDQogICAgICAgICAgICBzaXplID0gNSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJncmV5IiwgInllbGxvdyIpKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgaGp1c3QgPSAwLjUpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE1KSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKw0KICB0cmFuc2l0aW9uX3N0YXRlcyhzdGF0ZXMgPSBTdXJmYWNlLCB0cmFuc2l0aW9uX2xlbmd0aCA9IDIsIHN0YXRlX2xlbmd0aCA9IDEpICsgDQogIGVudGVyX2ZhZGUoKSArIA0KICBleGl0X3NocmluaygpICsNCiAgZWFzZV9hZXMoJ3NpbmUtaW4tb3V0JykNCmBgYA0KDQpEZWwgZ3LDoWZpY28gYW50ZXJpb3IgZXh0cmFlbW9zIGRpc3RpbnRhcyBjb25jbHVzaW9uZXMuDQoNCkxhIHByaW1lcmEsICoqUmFmYWVsIE5hZGFsIGVzIGVsIG1lam9yIGp1Z2Fkb3IgZGUgbGEgaGlzdG9yaWEgZW4gdGllcnJhIGJhdGlkYSoqLiBFc3RhIGFmaXJtYWNpw7NuIG5vIGVzIGRpc2N1dGlkYSBwb3IgbmFkaWUgaG95IGVuIGTDrWEuIFN1cyByZXN1bHRhZG9zIHNvYnJlIGVzdGEgc3VwZXJmaWNpZSBzb24gc3VwZXJsYXRpdm9zLiBBZGVtw6FzLCBsb3MgaGEgY29uc2VndWlkbyBlbiB1bmEgZGUgbGFzIGVyYXMgbcOhcyBjb21wZXRpdGl2YXMgZGUgbGEgaGlzdG9yaWEuIFNpbXBsZW1lbnRlLCBubyBoYXkgcGFsYWJyYXMgcGFyYSBkZXNjcmliaXIgbG8gbG9ncmFkbyBwb3IgZXN0ZSBqdWdhZG9yLiBNdXkgcHJvYmFibGVtZW50ZSBuYWRpZSBtw6FzIHNlYSBjYXBheiBkZSBpZ3VhbGFybGUuDQoNCkxhIHNlZ3VuZGEgZXMgYWNlcmNhIGRlIGxhIHJlZ3VsYXJpZGFkIHkgdmVyc2F0aWxpZGFkIGRlICoqTm92YWsgRGpva292aWMqKi4gU2luIGR1ZGEsICoqZWwganVnYWRvciBtw6FzIHZlcnPDoXRpbCBkZSBsYSBoaXN0b3JpYSoqLiBDYXBheiBkZSBqdWdhciByb3phbmRvIGxhIHBlcmZlY2Npw7NuIGVuIGVsIHRpcG8gZGUgcGlzdGEgZW4gbGEgcXVlIGp1ZWd1ZS4NCg0KWSBhIHRlcmNlcmEsICoqRmVkZXJlciBlcyBlbCBtZWpvciBlbiBwaXN0YXMgZGUgYWx0YSB2ZWxvY2lkYWQqKi4gQ3VhbnRvIG3DoXMgcsOhcGlkYSBlcyB1bmEgcGlzdGEgZGUgdGVuaXMsIGxhIHBlcmZlY2Npw7NuIHN1aXphIGVzIGNhcGF6IGRlIG1vc3RyYXIgYWwgbXVuZG8gZWwgcG9ycXXDqSBkZSBxdWUgbGEgZGVmaW5pY2nDs24gZGUgdGVuaXMgcGVyZmVjdG8gc2VhIEZlZGVyZXIuDQoNCiMgNi4gQ3JpdGVyaW8gNDogTWF5b3IgbsO6bWVybyBkZSB2aWN0b3JpYXMgYW50ZSBqdWdhZG9yZXMgVG9wDQoNClNlZ3VpbW9zIHRyYXRhbmRvIGRlIGRhciB1bmEgcmVzcHVlc3RhIGEgKsK/UXVpw6luIGVzIGVsIEdPQVQgZGVsIHRlbmlzPyouIFkgcGFyYSB0cmF0YXIgZGUgb2J0ZW5lciB1bmEgcmVzcHVlc3RhLCBlcyBuZWNlc2FyaW8gcmVhbGl6YXIgdW5hIHBhcmFkYSBwYXJhIGFuYWxpemFyIGN1w6FsIGhhIHNpZG8gZWwgcmVuZGltaWVudG8gZGVsIEJpZyAzIGZyZW50ZSBhIG90cm9zIGdyYW5kZXMganVnYWRvcmVzIGRlbCBjaXJjdWl0by4NCg0KRWwgZ3LDoWZpY28gcXVlIHNlIG11ZXN0cmEgYSBjb250aW51YWNpw7NuIG5vcyBtdWVzdHJhIGxhcyB2aWN0b3JpYXMgeSBkZXJyb3RhcyBkZWwgQmlnIDMgZnJlbnRlIGEganVnYWRvcmVzIGN1eW8gcsOhbmtpbmcgZXJhOg0KDQotICAgTsO6bWVybyAxIGRlbCBtdW5kby4NCg0KLSAgIEVudHJlIGVsIDIgeSBlbCA1IGRlbCBtdW5kby4NCg0KLSAgIEVudHJlIGVsIDYgeSBlbCAxMCBkZWwgbXVuZG8uDQoNCi0gICBFbnRyZSBlbCAxMSB5IGVsIDIwIGRlbCBtdW5kby4NCg0KYGBge3J9DQp0dCA8LSB0ZW1wb3JhZGFzICU+JSBmaWx0ZXIoV2lubmVyICVpbiUgYygiRmVkZXJlciBSLiIsICJOYWRhbCBSLiIsICJEam9rb3ZpYyBOLiIpIHwgTG9zZXIgJWluJSBjKCJGZWRlcmVyIFIuIiwgIk5hZGFsIFIuIiwgIkRqb2tvdmljIE4uIikpICU+JSBtdXRhdGUoV1JhbmsgPSBhcy5udW1lcmljKFdSYW5rKSwgTFJhbmsgPSBhcy5udW1lcmljKExSYW5rKSkNCg0KI1RvcCAyMA0Kdl90b3AyMCA8LSB0dCAlPiUgZmlsdGVyKFdpbm5lciAlaW4lIGMoIkZlZGVyZXIgUi4iLCAiTmFkYWwgUi4iLCAiRGpva292aWMgTi4iKSAmIExSYW5rIDw9IDIwICYgTFJhbmsgPiAxMCkgJT4lIGdyb3VwX2J5KFdpbm5lcikgJT4lIHN1bW1hcmlzZShWaWN0b3JpYXMgPSBuKCkpDQoNCmRfdG9wMjAgPC0gdHQgJT4lIGZpbHRlcihMb3NlciAlaW4lIGMoIkZlZGVyZXIgUi4iLCAiTmFkYWwgUi4iLCAiRGpva292aWMgTi4iKSAmIFdSYW5rIDw9IDIwICYgV1JhbmsgPiAxMCkgJT4lIGdyb3VwX2J5KExvc2VyKSAlPiUgc3VtbWFyaXNlKERlcnJvdGFzID0gbigpKQ0KDQpUb3AyMCA8LSBmdWxsX2pvaW4odl90b3AyMCwgZF90b3AyMCwgYnkgPSBjKCJXaW5uZXIiID0gIkxvc2VyIikpICU+JSBwaXZvdF9sb25nZXIoY29scyA9IDI6MywgbmFtZXNfdG8gPSAiVi9EIiwgdmFsdWVzX3RvID0gIk7Dum1lcm8iKQ0KDQpkIDwtIGMoIlRvcCAyMCIsICJUb3AgMjAiLCAiVG9wIDIwIiwgIlRvcCAyMCIsICJUb3AgMjAiLCAiVG9wIDIwIikNCg0KVG9wMjAgPC0gY2JpbmQoVG9wMjAsIGQpDQoNCg0KI1RvcCAxMA0Kdl90b3AxMCA8LSB0dCAlPiUgZmlsdGVyKFdpbm5lciAlaW4lIGMoIkZlZGVyZXIgUi4iLCAiTmFkYWwgUi4iLCAiRGpva292aWMgTi4iKSAmIExSYW5rIDw9IDEwICYgTFJhbmsgPiA1KSAlPiUgZ3JvdXBfYnkoV2lubmVyKSAlPiUgc3VtbWFyaXNlKFZpY3RvcmlhcyA9IG4oKSkNCg0KZF90b3AxMCA8LSB0dCAlPiUgZmlsdGVyKExvc2VyICVpbiUgYygiRmVkZXJlciBSLiIsICJOYWRhbCBSLiIsICJEam9rb3ZpYyBOLiIpICYgV1JhbmsgPD0gMTAgJiBXUmFuayA+IDUpICU+JSBncm91cF9ieShMb3NlcikgJT4lIHN1bW1hcmlzZShEZXJyb3RhcyA9IG4oKSkNCg0KVG9wMTAgPC0gZnVsbF9qb2luKHZfdG9wMTAsIGRfdG9wMTAsIGJ5ID0gYygiV2lubmVyIiA9ICJMb3NlciIpKSAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSAyOjMsIG5hbWVzX3RvID0gIlYvRCIsIHZhbHVlc190byA9ICJOw7ptZXJvIikNCg0KZCA8LSBjKCJUb3AgMTAiLCAiVG9wIDEwIiwgIlRvcCAxMCIsICJUb3AgMTAiLCAiVG9wIDEwIiwgIlRvcCAxMCIpDQoNClRvcDEwIDwtIGNiaW5kKFRvcDEwLCBkKQ0KDQojVG9wIDUNCnZfdG9wNSA8LSB0dCAlPiUgZmlsdGVyKFdpbm5lciAlaW4lIGMoIkZlZGVyZXIgUi4iLCAiTmFkYWwgUi4iLCAiRGpva292aWMgTi4iKSAmIExSYW5rIDw9IDUgJiBMUmFuayA+IDEpICU+JSBncm91cF9ieShXaW5uZXIpICU+JSBzdW1tYXJpc2UoVmljdG9yaWFzID0gbigpKQ0KDQpkX3RvcDUgPC0gdHQgJT4lIGZpbHRlcihMb3NlciAlaW4lIGMoIkZlZGVyZXIgUi4iLCAiTmFkYWwgUi4iLCAiRGpva292aWMgTi4iKSAmIFdSYW5rIDw9IDUgJiBXUmFuayA+IDEpICU+JSBncm91cF9ieShMb3NlcikgJT4lIHN1bW1hcmlzZShEZXJyb3RhcyA9IG4oKSkNCg0KVG9wNSA8LSBmdWxsX2pvaW4odl90b3A1LCBkX3RvcDUsIGJ5ID0gYygiV2lubmVyIiA9ICJMb3NlciIpKSAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSAyOjMsIG5hbWVzX3RvID0gIlYvRCIsIHZhbHVlc190byA9ICJOw7ptZXJvIikNCg0KZCA8LSBjKCJUb3AgNSIsICJUb3AgNSIsICJUb3AgNSIsICJUb3AgNSIsICJUb3AgNSIsICJUb3AgNSIpDQoNClRvcDUgPC0gY2JpbmQoVG9wNSwgZCkNCg0KI1RvcCAxDQp2X3RvcDEgPC0gdHQgJT4lIGZpbHRlcihXaW5uZXIgJWluJSBjKCJGZWRlcmVyIFIuIiwgIk5hZGFsIFIuIiwgIkRqb2tvdmljIE4uIikgJiBMUmFuayA9PSAxKSAlPiUgZ3JvdXBfYnkoV2lubmVyKSAlPiUgc3VtbWFyaXNlKFZpY3RvcmlhcyA9IG4oKSkNCg0KZF90b3AxIDwtIHR0ICU+JSBmaWx0ZXIoTG9zZXIgJWluJSBjKCJGZWRlcmVyIFIuIiwgIk5hZGFsIFIuIiwgIkRqb2tvdmljIE4uIikgJiBXUmFuayA9PSAxKSAlPiUgZ3JvdXBfYnkoTG9zZXIpICU+JSBzdW1tYXJpc2UoRGVycm90YXMgPSBuKCkpDQoNClRvcDEgPC0gZnVsbF9qb2luKHZfdG9wMSwgZF90b3AxLCBieSA9IGMoIldpbm5lciIgPSAiTG9zZXIiKSkgJT4lIHBpdm90X2xvbmdlcihjb2xzID0gMjozLCBuYW1lc190byA9ICJWL0QiLCB2YWx1ZXNfdG8gPSAiTsO6bWVybyIpDQoNCmQgPC0gYygiVG9wIDEiLCAiVG9wIDEiLCAiVG9wIDEiLCAiVG9wIDEiLCAiVG9wIDEiLCAiVG9wIDEiKQ0KDQpUb3AxIDwtIGNiaW5kKFRvcDEsIGQpDQoNCiMjIyBHcsOhZmljbw0KVG9wIDwtIHJiaW5kKFRvcDEsIFRvcDUsIFRvcDEwLCBUb3AyMCkgJT4lIA0KICBtdXRhdGUoV2lubmVyID0gY2FzZV93aGVuKA0KICBXaW5uZXIgPT0iRmVkZXJlciBSLiIgfiAgIkZlZGVyZXIiLA0KICBXaW5uZXIgPT0iTmFkYWwgUi4iIH4gICJOYWRhbCIsDQogIFdpbm5lciA9PSJEam9rb3ZpYyBOLiIgfiAgIkRqb2tvdmljIikpICU+JSANCiAgbXV0YXRlKGBWL0RgID0gZm9yY2F0czo6YXNfZmFjdG9yKGBWL0RgKSkgJT4lIA0KICBtdXRhdGUoYFYvRGAgPSBmb3JjYXRzOjpmY3RfcmVvcmRlcihgVi9EYCwgTsO6bWVybywgLmRlc2MgPSBUUlVFKSkgJT4lIA0KICBtdXRhdGUoZCA9IGZvcmNhdHM6OmFzX2ZhY3RvcihkKSkgJT4lIA0KICBtdXRhdGUoZCA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGQsIE7Dum1lcm8sIC5kZXNjID0gRkFMU0UpKQ0KDQpUb3AgJT4lIGdncGxvdCgpICsNCiAgZ2VvbV9iYXIoYWVzKHg9IFdpbm5lciwgeT0gTsO6bWVybywgZmlsbD0gYFYvRGApLCBzdGF0ID0gImlkZW50aXR5IiwNCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKw0KICBmYWNldF93cmFwKHZhcnMoZCkpICsNCiAgdGhlbWVfdGVzdCgpICsNCiAgbGFicyh0aXRsZSA9ICJFc3RhZMOtc3RpY2FzIFZpY3Rvcmlhcy9EZXJyb3RhcyBCaWcgMyIsDQogICAgICAgc3VidGl0bGUgPSAiQ2xhc2lmaWNhY2nDs24gcG9yIHJhbmtpbmciKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBoanVzdCA9IDAuNSksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSksDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikpDQpgYGANCg0KUmVhbGl6YXJlbW9zIGVzdGUgYW7DoWxpc2lzIGRlZGljYW5kbyBhIGNhZGEganVnYWRvciBzdSBwcm9waW8gcMOhcnJhZm8gZW4gcmVsYWNpw7NuIGFsIHJlc3RvLg0KDQpFbXBlemFyZW1vcyBwb3IgKipOb3ZhayBEam9rb3ZpYyoqLiBBdW4gc2llbmRvIGVsIG3DoXMgam92ZW4gZGUgbG9zIHRyZXMsIGVzIGVsIHF1ZSBwcmVzZW50YSBtZWpvcmVzIGNpZnJhcyBlbnRyZSB2aWN0b3JpYXMgeSBkZXJyb3RhcyBmcmVudGUgYSBqdWdhZG9yZXMgZW50cmUgZWwgMiB5IDEwIGRlbCBtdW5kby4gQWRlbcOhcywgdGllbmUgdW4gbXV5IGJ1ZW4gcmF0aW8gY3VhbmRvIGEgZW5mcmVudGFkbyBhbCBuw7ptZXJvIDEgZGVsIG11bmRvLg0KDQpTZWd1aWRhbWVudGUgdGVuZW1vcyBhICoqUm9nZXIgRmVkZXJlcioqLiBBbCBzZXIgZWwgbcOhcyB2ZXRlcmFubywgZXMgZWwganVnYWRvciBjb24gbcOhcyB2aWN0b3JpYXMgZnJlbnRlIGEganVnYWRvcmVzIGRlc2RlIGVsIDIgYWwgMjAgZGVsIHJhbmtpbmcuIE5vIG9ic3RhbnRlLCB0YW1iacOpbiBlbCBxdWUgbcOhcyBkZXJyb3RhcyBoYSBhY3VtdWxhZG8uIFBvciBvdHJvIGxhZG8sIHN1IHJlbmRpbWllbnRvIGZyZW50ZSBhIG7Dum1lcm9zIDEgZGVsIG11bmRvIGVzIGVsIG3DoXMgcG9icmUgZGUgbG9zIHRyZXMuIFVuIG1heW9yIHkgbWVqb3IgYW7DoWxpc2lzIHNlcsOtYSBuZWNlc2FyaW8gcGFyYSBkZXRlcm1pbmFyIGxvcyBtb3Rpdm9zIGRldHLDoXMgZGUgZXN0ZSBwb2JyZSByZW5kaW1pZW50byBmcmVudGUgYSBuw7ptZXJvcyAxLiBTaW4gZW1iYXJnbywgbG8gY2llcnRvIGVzIHF1ZSBlcyBhbXBsaWFtZW50ZSBzdXBlcmFkbyBwb3IgRGpva292aWMgeSBlc3BlY2lhbG1lbnRlIHBvciBOYWRhbCBlbiBlc3RlIGFzcGVjdG8uDQoNCkZpbmFsbWVudGUsICoqTmFkYWwqKi4gU3UgcmVuZGltaWVudG8gZnJlbnRlIGEganVnYWRvcmVzIGVudHJlIGVsIDIgeSAyMCBkZWwgcsOhbmtpbmcgZXMgZWwgcGVvciBkZSBsb3MgdHJlcy4gU2luIGVtYmFyZ28sIE5hZGFsIHNlIGxsZXZhIGVsIHTDrXR1bG8gZGUgKm1hdGEgZ2lnYW50ZXMqLiBFcyBlbCDDum5pY28gZGUgbG9zIHRyZXMgcXVlIHRpZW5lIG3DoXMgdmljdG9yaWFzIHF1ZSBkZXJyb3RhcyBhbnRlIG7Dum1lcm9zIDEuIFVuIGxvZ3JvIGFsIGFsY2FuY2Ugw7puaWNhbWVudGUgZGVsIGp1Z2Fkb3IgZXNwYcOxb2wuIFN1IHB1bmRvbm9yIHkgc3UgdGVuaXMgbGUgbGxldmFuIGEgc2VyIGVsIHRlbmlzdGEgbcOhcyB0ZW1pZG8gcG9yIGxvcyBtZWpvcmVzLg0KDQojIDcuIENyaXRlcmlvIDU6IFRlbXBvcmFkYSBkZSBpbmljaW8gZW4gbGEgw6lsaXRlDQoNCkVsIHF1aW50byBkZSBsb3MgY3JpdGVyaW9zIGRlbCBxdWUgaGFyZW1vcyB1c28gZXMgZWwgcmVuZGltaWVudG8gZGUgZXN0b3MgdHJlcyBqdWdhZG9yZXMgZW4gc3UgdGVtcG9yYWRhIGRlIGluaWNpbyBlbiBsYSDDqWxpdGUuIFBhcmEgcG9kZXIgdXRpbGl6YXIgZXN0ZSBjcml0ZXJpbywgcHJpbWVybyBkZWJlbW9zIGRldGVybWluYXIgcXXDqSB0ZW1wb3JhZGEgY29uc2lkZXJhbW9zIHF1ZSBmdWUgbGEgcHJpbWVyYSBlbiBsYSBxdWUgY2FkYSBqdWdhZG9yIGNvbWVuesOzIGEgY29tcGV0aXIgZW4gbGEgw6lsaXRlIGRlIGVzdGUgZGVwb3J0ZS4gRXN0YSBubyBlcyB1bmEgZWxlY2Npw7NuIHNlbmNpbGxhLiBObyBvYnN0YW50ZSwgY29uc2lkZXJhcmVtb3MgbGEgdGVtcG9yYWRhIGVuIGxhIHF1ZSBnYW5hcm9uIHN1IHByaW1lciBHcmFuZCBTbGFtIGNvbW8gbGEgdGVtcG9yYWRhIGVuIGxhIHF1ZSBjYWRhIG1pZW1icm8gZGVsIEJpZyAzIGNvbWVuesOzIGEgc2VyIGNvbnNpZGVyYWRvIGNvbW8gdW4gKmp1Z2Fkb3IgZGUgw6lsaXRlKi4NCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQp0ZW1wb3JhZGFfMDggPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAiYXRwXzIwMDgueGxzIikpDQp0ZW1wb3JhZGFfMDUgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAiYXRwXzIwMDUueGxzIikpDQp0ZW1wb3JhZGFfMDMgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAiYXRwXzIwMDMueGxzIikpDQpgYGANCg0KIyMgRXN0YWTDrXN0aWNhcyBnZW5lcmFsZXMNCg0KRW4gYW50ZXJpb3JlcyBhcGFydGFkb3MgcHVkaW1vcyBkZXNncmFuYXIgbG9zIHTDrXR1bG9zIGdhbmFkb3MgcG9yIGNhZGEganVnYWRvci4gRGUgZXN0ZSBhbsOhbGlzaXMgb2J0ZW5lbW9zIHRyZXMgYcOxb3MgZGUgZXNwZWNpYWwgcmVsZXZhbmNpYTogMjAwMywgMjAwNSB5IDIwMDgsIGxvcyBhw7FvcyBlbiBsb3MgcXVlIFJvZ2VyIEZlZGVyZXIsIFJhZmFlbCBOYWRhbCB5IE5vdmFrIERqb2tvdmljIGdhbmFyb24gc3UgcHJpbWVyIEdyYW5kIFNsYW0sIHJlc3BlY3RpdmFtZW50ZS4gRGUgZXN0YSBmb3JtYSwgYW5hbGl6YXJlbW9zIGNvbW8gZnVlIGVsIHJlbmRpbWllbnRvIGRlIGNhZGEganVnYWRvciBlbiBzdSBjb3JyZXNwb25kaWVudGUgYcOxbywgZWwgY3XDoWwgcGFzYXJlbW9zIGEgY29uc2lkZXJhciBzdSAqKnRlbXBvcmFkYSBkZSBpbmljaW8gZW4gbGEgw6lsaXRlKiouDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KRWRhZCA8LSBjKDIyLCAxOSwgMjEpDQpUw610dWxvcyA8LSBjKDcsIDExLCA0KQ0KVGVtcG9yYWRhIDwtIGMoMjAwMywgMjAwNSwgMjAwOCkNCmBgYA0KDQpgYGB7cn0NCmdhbl9mZWQgPC0gdGVtcG9yYWRhXzAzICU+JSBmaWx0ZXIoV2lubmVyID09ICJGZWRlcmVyIFIuIikgJT4lIGdyb3VwX2J5KFdpbm5lcikgJT4lIHN1bW1hcmlzZShHYW5hZG9zID1uKCkpDQoNCnBlcl9mZWQgPC0gdGVtcG9yYWRhXzAzICU+JSBmaWx0ZXIoTG9zZXIgPT0gIkZlZGVyZXIgUi4iKSAlPiUgZ3JvdXBfYnkoTG9zZXIpICU+JSBzdW1tYXJpc2UoUGVyZGlkb3MgPW4oKSkNCg0KcGFydF9mZWQgPC0gbGVmdF9qb2luKGdhbl9mZWQsIHBlcl9mZWQsIGJ5ID0gYygiV2lubmVyIiA9ICJMb3NlciIpKQ0KDQojIyBOYWRhbA0KZ2FuX25hZCA8LSB0ZW1wb3JhZGFfMDUgJT4lIGZpbHRlcihXaW5uZXIgPT0gIk5hZGFsIFIuIikgJT4lIGdyb3VwX2J5KFdpbm5lcikgJT4lIHN1bW1hcmlzZShHYW5hZG9zID1uKCkpDQoNCnBlcl9uYWQgPC0gdGVtcG9yYWRhXzA1ICU+JSBmaWx0ZXIoTG9zZXIgPT0gIk5hZGFsIFIuIikgJT4lIGdyb3VwX2J5KExvc2VyKSAlPiUgc3VtbWFyaXNlKFBlcmRpZG9zID1uKCkpDQoNCnBhcnRfbmFkIDwtIGxlZnRfam9pbihnYW5fbmFkLCBwZXJfbmFkLCBieSA9IGMoIldpbm5lciIgPSAiTG9zZXIiKSkNCg0KIyMgRGpva292aWMNCmdhbl9kam8gPC0gdGVtcG9yYWRhXzA4ICU+JSBmaWx0ZXIoV2lubmVyID09ICJEam9rb3ZpYyBOLiIpICU+JSBncm91cF9ieShXaW5uZXIpICU+JSBzdW1tYXJpc2UoR2FuYWRvcyA9bigpKQ0KDQpwZXJfZGpvIDwtIHRlbXBvcmFkYV8wOCAlPiUgZmlsdGVyKExvc2VyID09ICJEam9rb3ZpYyBOLiIpICU+JSBncm91cF9ieShMb3NlcikgJT4lIHN1bW1hcmlzZShQZXJkaWRvcyA9bigpKQ0KDQpwYXJ0X2RqbyA8LSBsZWZ0X2pvaW4oZ2FuX2RqbywgcGVyX2RqbywgYnkgPSBjKCJXaW5uZXIiID0gIkxvc2VyIikpDQoNCkZvdG8gPC0gYygiaHR0cHM6Ly93d3cuYXRwdG91ci5jb20vLS9tZWRpYS90ZW5uaXMvcGxheWVycy9oZWFkLXNob3QvMjAyMC9mZWRlcmVyX2hlYWRfYW8yMC5wbmciLCAiaHR0cHM6Ly93d3cuYXRwdG91ci5jb20vLS9tZWRpYS90ZW5uaXMvcGxheWVycy9oZWFkLXNob3QvMjAyMC9uYWRhbF9oZWFkX2FvMjAucG5nIiwgImh0dHBzOi8vd3d3LmF0cHRvdXIuY29tL2VzL3BsYXllcnMvbm92YWstZGpva292aWMvZDY0My93d3cuYXRwdG91ci5jb20vLS9tZWRpYS90ZW5uaXMvcGxheWVycy9oZWFkLXNob3QvMjAxOS9kam9rb3ZpY19oZWFkX2FvMTkucG5nIikNCg0KTmFjaW9uYWxpZGFkIDwtIGMoImh0dHBzOi8vd3d3LmVjdXJlZC5jdS9pbWFnZXMvMi8yMC9CYW5kZXJhX3N1aXphLkpQRyIsICJodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9jb21tb25zL3RodW1iLzgvODkvQmFuZGVyYV9kZV9Fc3BhJUMzJUIxYS5zdmcvMTIwMHB4LUJhbmRlcmFfZGVfRXNwYSVDMyVCMWEuc3ZnLnBuZyIsICJodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9jb21tb25zL3RodW1iL2YvZmYvRmxhZ19vZl9TZXJiaWEuc3ZnLzEyMDBweC1GbGFnX29mX1NlcmJpYS5zdmcucG5nIikNCg0KcGFydCA8LSByYmluZChwYXJ0X2ZlZCwgcGFydF9uYWQsIHBhcnRfZGpvKSAlPiUgbXV0YXRlKFBvcmNlbnRhamUgPSBHYW5hZG9zLyhHYW5hZG9zICsgUGVyZGlkb3MpKQ0KDQp0YWJsYSA8LSBjYmluZChGb3RvLCBwYXJ0LCBOYWNpb25hbGlkYWQsIEVkYWQsIFRlbXBvcmFkYSwgVMOtdHVsb3MpICU+JSAgDQogIG11dGF0ZShXaW5uZXIgPSBjYXNlX3doZW4oDQogICAgV2lubmVyID09IkZlZGVyZXIgUi4iIH4gICJSb2dlciBGZWRlcmVyIiwNCiAgICBXaW5uZXIgPT0iTmFkYWwgUi4iIH4gICJSYWZhZWwgTmFkYWwiLA0KICAgIFdpbm5lciA9PSJEam9rb3ZpYyBOLiIgfiAgIk5vdmFrIERqb2tvdmljIikpDQoNCnRhYmxhICU+JSBndChyb3duYW1lX2NvbCA9ICJGb3RvIiwgZ3JvdXBuYW1lX2NvbCA9ICJXaW5uZXIiKSAlPiUgDQogIHRleHRfdHJhbnNmb3JtKGxvY2F0aW9ucyA9IGNlbGxzX3N0dWIocm93cyA9IDE6MyksIGZuID0gZnVuY3Rpb24oeCkge2d0Ojp3ZWJfaW1hZ2UoeCwgaGVpZ2h0ID0gNTApfSkgJT4lDQogIHRleHRfdHJhbnNmb3JtKGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IHZhcnMoTmFjaW9uYWxpZGFkKSksIGZuID0gZnVuY3Rpb24oeCkge2d0Ojp3ZWJfaW1hZ2UoeCwgaGVpZ2h0ID0gNTApfSkgJT4lIA0KICBjb2xzX2FsaWduKGFsaWduID0gImNlbnRlciIpICU+JSANCiAgY29sc19tb3ZlX3RvX3N0YXJ0KGNvbHVtbnMgPSAiRWRhZCIpICU+JSANCiAgY29sc19tb3ZlKGNvbHVtbnMgPSAiVGVtcG9yYWRhIiwNCiAgICAgICAgICAgIGFmdGVyID0gIkVkYWQiKSAlPiUgDQogIGNvbHNfbW92ZShjb2x1bW5zID0gIlTDrXR1bG9zIiwNCiAgICAgICAgICAgIGFmdGVyID0gIlRlbXBvcmFkYSIpICU+JSANCiAgdGFiX2hlYWRlcih0aXRsZSA9ICJFc3RhZMOtdGljYXMgQmlnIDMiLA0KICAgICAgICAgICAgIHN1YnRpdGxlID0gIlRlbXBvcmFkYSBpbmljaW8gZW4gbGEgw6lsaXRlIikgJT4lDQogIHRhYl9zcGFubmVyKGxhYmVsID0gIlBhcnRpZG9zIiwNCiAgICAgICAgICAgICAgY29sdW1ucyA9IGMoIkdhbmFkb3MiLCAiUGVyZGlkb3MiLCAiUG9yY2VudGFqZSIpKSAlPiUgDQogIHRhYl9vcHRpb25zKGhlYWRpbmcuYmFja2dyb3VuZC5jb2xvciA9ICIjREFBNTIwIikgJT4lIHRhYl9vcHRpb25zKGhlYWRpbmcudGl0bGUuZm9udC5zaXplID0gMzAsIGhlYWRpbmcuc3VidGl0bGUuZm9udC5zaXplID0gMjUsICBjb2x1bW5fbGFiZWxzLmZvbnQud2VpZ2h0ID0gICJib2xkIikgJT4lIA0KICBmbXRfcGVyY2VudChjb2x1bW5zID0gIlBvcmNlbnRhamUiLCANCiAgICAgICAgICAgICAgZGVjaW1hbHMgPSAyKQ0KYGBgDQoNCkFsIGVzdGFyIGNvbXBhcmFuZG8gZGlmZXJlbnRlcyBhw7FvcyBwYXJhIGNhZGEganVnYWRvciwgbGEgZWRhZCBxdWUgY2FkYSBqdWdhZG9yIHRlbsOtYSBlbiBlc2UgYcOxbyB2YXLDrWEuIEVsIGp1Z2Fkb3IgbcOhcyBqb3ZlbiBlbiBkaXB1dGFyIHN1IHByaW1lcmEgdGVtcG9yYWRhIGVuIGxhIMOpbGl0ZSBmdWUgUmFmYWVsIE5hZGFsLiBDb24gMTkgYcOxb3MsIGVsIGp1Z2Fkb3IgZXNwYcOxb2wgZ2Fuw7MgZW4gbGEgdGVtcG9yYWRhIDIwMDUgc3UgcHJpbWVyIEdyYW5kIFNsYW0uIEFkZW3DoXMgZGUgc2VyIGVsIG3DoXMgam92ZW4sIHRhbWJpw6luIGZ1ZSBlbCBxdWUgbWF5b3IgcG9yY2VudGFqZSBkZSB2aWN0b3JpYXMgdHV2byBlbiBzdSB0ZW1wb3JhZGEsIGdhbmFuZG8gNzcgZGUgODcgcGFydGlkb3MgeSBvYnRlbmllbmRvIGRlIGVzdGEgZm9ybWEgMTEgdMOtdHVsb3MgQVRQLiBQb3Igc3UgcGFydGUsIEZlZGVyZXIgZnVlIGVsIG3DoXMgdGFyZMOtbyBlbiBleHBsb3RhciwgbGxlZ2FuZG8gYSBzdXMgMjIgYcOxb3MgZWwgcHJpbWVybyBkZSBzdSBHcmFuZCBTbGFtcyBlbiAyMDAzLiBGaW5hbG1lbnRlLCBEam9rb3ZpYyBlcyBlbCBtZW5vcyBsYXVyZWFkbyBlbiBzdSB0ZW1wb3JhZGEgZGUgZGVidXQgZW4gbGEgw6lsaXRlLCBzdW1hbmRvIDMgdMOtdHVsb3MgbcOhcyBhIHN1IHByaW1lciBHcmFuZCBTbGFtLg0KDQpObyBlcyBkZXNjYXJhZG8gZGVjaXIgcXVlIGxhIHRlbXBvcmFkYSBkZSBkZWJ1dCBkZSBOYWRhbCBmdWUgbGEgcXVlIG3DoXMgc29icmVzYWxpw7MuIFlhIG5vIHNvbG8gcG9yIGVsIGFzb21icm9zbyBuw7ptZXJvIGRlIHTDrXR1bG9zLCBzaW5vIHRhbWJpw6luIHBvciBzdSBjb3J0YSBlZGFkLiBBIGNvbnRpbnVhY2nDs24sIHBvZGVtb3Mgb2JzZXJ2YXIgbGEgZGlzdHJpYnVjacOzbiBnZW9ncsOhZmljYSBkZSBsb3MgdMOtdHVsb3MgZGUgY2FkYSBqdWdhZG9yLg0KDQpgYGB7cn0NCiMjIEZlZGVyZXINCnRpdHVsb3NfZmVkIDwtIHRlbXBvcmFkYV8wMyAlPiUgZmlsdGVyKFdpbm5lciA9PSAiRmVkZXJlciBSLiIpICU+JSBmaWx0ZXIoUm91bmQgPT0gIlRoZSBGaW5hbCIpICU+JSBzZWxlY3QoTG9jYXRpb24sIFdpbm5lcikNCg0KIyMgTmFkYWwNCnRpdHVsb3NfbmFkIDwtIHRlbXBvcmFkYV8wNSAlPiUgZmlsdGVyKFdpbm5lciA9PSAiTmFkYWwgUi4iKSAlPiUgZmlsdGVyKFJvdW5kID09ICJUaGUgRmluYWwiKSAlPiUgc2VsZWN0KExvY2F0aW9uLCBXaW5uZXIpDQoNCg0KIyMgRGpva292aWMNCnRpdHVsb3NfZGpvIDwtIHRlbXBvcmFkYV8wOCAlPiUgZmlsdGVyKFdpbm5lciA9PSAiRGpva292aWMgTi4iKSAlPiUgZmlsdGVyKFJvdW5kID09ICJUaGUgRmluYWwiKSAlPiUgc2VsZWN0KExvY2F0aW9uLCBXaW5uZXIpDQoNCg0KdGl0dWxvcyA8LXJiaW5kKHRpdHVsb3NfZmVkLCB0aXR1bG9zX25hZCwgdGl0dWxvc19kam8pDQoNCmlzbzIgPC0gYygiRlIiLCAiQUUiLCAiREUiLCAiREUiLCAiR0IiLCAiQVQiLCAiVVMiLCAiQlIiLCAiTVgiLCAiTUMiLCAiRVMiLCAiSVQiLCAiRlIiLCAiU0UiLCAiREUiLCAiQ0EiLCAiQ04iLCAiRVMiLCAiQVUiLCAiVVMiLCAiSVQiLCAiQ04iICkNCg0KdG90YWwgPC0gY2JpbmQoaXNvMiwgdGl0dWxvcykgJT4lICANCiAgbXV0YXRlKFdpbm5lciA9IGNhc2Vfd2hlbigNCiAgICBXaW5uZXIgPT0iRmVkZXJlciBSLiIgfiAgIkZlZGVyZXIiLA0KICAgIFdpbm5lciA9PSJOYWRhbCBSLiIgfiAgIk5hZGFsIiwNCiAgICBXaW5uZXIgPT0iRGpva292aWMgTi4iIH4gICJEam9rb3ZpYyIpKQ0KDQpsb25nIDwtIGMoNS4zNzYzOSwgNTUuMzA3NywgMTEuNTc1MywgMTEuOTcsIC0wLjEyNzUsIDE2LjM3MjgsIC05NS4zODYzLCAtMzcuOTIyNCwgLTk5Ljg4MTYsIDcuNDEyODQsIDIuMTY5OTIsIDEyLjQ5NDIsIDIuMzQ4NjAwMCwgMTIuODUyOSwgOS4xODI3OCwgLTczLjU4NzgxLCAxMTYuMzk3MjMsIC0zLjcwMzI1LCAxNDQuOTYzMzIsIC0xMTYuMzQxLCAxMi40OTQyLCAxMjEuNDY5KQ0KDQpsYXQgPC0gYyg0My4yOTY3LCAyNS4yNjQ2LCA0OC4xMzY5LCA1MS40ODI4LCA1MS41MDcyLCA0OC4yMDkyLCAyOS43ODA1LCAtMTIuNDMxOSwgMTYuODYzOCwgNDMuNzUwMywgNDEuMzg3OSwgNDEuODkwNSwgNDguODUzNDAwMCwgNTYuNDI2NywgNDguNzc1NiwgNDUuNTA4ODQsIDM5LjkwNzUsIDQwLjQxNjcsIC0zNy44MTQsIDMzLjcwNTIsIDQxLjg5MDUsIDMxLjIzMjMpDQoNCm51bSA8LSBjKDEsIDIsIDEsIDEsIDEsIDEsIDMsIDMsIDMsIDEsIDEsIDEsIDEsIDEsIDEsIDMsIDIsIDEsIDIsIDMsIDEsIDIpDQoNCnRvcm5lb3MgPC0gY2JpbmQodG90YWwsIGxvbmcsIGxhdCwgbnVtKQ0KDQp0b3JuZW9zMSA8LSB0b3JuZW9zICU+JSBmaWx0ZXIobnVtID09IDEpDQoNCnRvcm5lb3MyIDwtIHRvcm5lb3MgJT4lIGZpbHRlcihudW0gPT0gMikNCg0KdG9ybmVvczMgPC0gdG9ybmVvcyAlPiUgZmlsdGVyKG51bSA9PSAzKQ0KDQptYXBhX211bmRvIDwtIG1hcF9kYXRhKCJ3b3JsZCIpICU+JSBtdXRhdGUoaXNvMiA9IGNvdW50cnljb2RlOjpjb3VudHJ5Y29kZShzb3VyY2V2YXIgPSByZWdpb24sIG9yaWdpbiA9ICJjb3VudHJ5Lm5hbWUiLGRlc3RpbmF0aW9uID0gICJpc28yYyIsIHdhcm4gPSBGQUxTRSksIC5hZnRlciA9IHJlZ2lvbikgJT4lIHNlbGVjdChsb25nLCBsYXQsIGdyb3VwLCBpc28yKQ0KDQptYXBhX211bmRvICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fcG9seWdvbihhZXMoeD0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCksIGZpbGwgPSAiZ3JleSIsDQogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIG5hLnJtID0gRkFMU0UpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE4LCBmYWNlID0gImJvbGQiLCB2anVzdCA9IDIpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplPSAxMiwgdmp1c3QgPSAyKSwNCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91cj0gImJsYWNrIiwgc2l6ZT0gMSwgZmlsbCA9ICIjOWZkNWQxIiksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IHRvcm5lb3MsIG1hcHBpbmcgPSBhZXMoeD0gbG9uZywgeT0gbGF0LCBjb2xvcj0gV2lubmVyKSwgc2l6ZT0gMi4yKSArDQogIGNvb3JkX2ZpeGVkICh4bGltPSBjKC0yMDAsMjAwKSwNCiAgICAgICAgICAgICAgIHlsaW09IGMoLTU4LDkwKSwNCiAgICAgICAgICAgICAgIHJhdGlvID0gMi4yKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJtaWRuaWdodGJsdWUiLCAic2VhZ3JlZW4iLCAieWVsbG93IikpICsgDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnVjacOzbiBnZW9ncsOhZmljYSB0w610dWxvcyBCaWcgMyIsDQogICAgICAgc3VidGl0bGUgPSAiUmVwcmVzZW50YWNpw7NuIHRlbXBvcmFkYSBpbmljaW8gw6lsaXRlIiwNCiAgICAgICBjb2xvciA9ICJKdWdhZG9yIikNCmBgYA0KDQpFbiBlbCBtYXBhIGFudGVyaW9yIG5vIHNlIGFwcmVjaWEgZsOhY2lsbWVudGUgbGFzIGNvbnF1aXN0YXMgZGUgY2FkYSBqdWdhZG9yLiBQb3IgZWxsbywgZGl2aWRpcmVtb3MgZWwgbWFwYSBlbiB0cmVzIHpvbmFzIHBhcmEgcG9kZXIgb2JzZXJ2YXJsbyBjb24gbWF5b3IgcHJlY2lzacOzbi4NCg0KYGBge3J9DQptYXBhX211bmRvICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fcG9seWdvbihhZXMoeD0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCksIGZpbGwgPSAiZ3JleSIsDQogICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIG5hLnJtID0gRkFMU0UpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE4LCBmYWNlID0gImJvbGQiLCB2anVzdCA9IDIpLA0KICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplPSAxMiwgdmp1c3QgPSAyKSwNCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyPSAiYmxhY2siLCBzaXplPSAxLCBmaWxsID0gIiM5ZmQ1ZDEiKSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSkgKw0KICBnZW9tX3BvaW50KGRhdGEgPSB0b3JuZW9zMywgbWFwcGluZyA9IGFlcyh4PSBsb25nLCB5PSBsYXQpLCBjb2xvcj0gInJlZCIsIHNpemU9IDIpICsNCiAgY29vcmRfZml4ZWQgKHhsaW09IGMoLTE0MCwtMzUpLA0KICAgICAgICAgICAgICAgeWxpbT0gYygtNjAsODApKSsNCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSB0b3JuZW9zMywgYWVzKHg9IGxvbmcsIHk9IGxhdCwgbGFiZWwgPSBMb2NhdGlvbiwgY29sb3IgPSBXaW5uZXIpLCBmb250ZmFjZSA9ICJib2xkIikgICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIm1pZG5pZ2h0Ymx1ZSIsICJzZWFncmVlbiIsICJ5ZWxsb3ciKSkgKyANCiAgbGFicyh0aXRsZSA9ICJUw610dWxvcyBjb250aW5lbnRlIGFtZXJpY2FubyBkZWwgQmlnIDMiLA0KICAgICAgIHN1YnRpdGxlID0gIlJlcHJlc2VudGFjacOzbiB0ZW1wb3JhZGEgaW5pY2lvIMOpbGl0ZSIsDQogICAgICAgY29sb3IgPSAiSnVnYWRvciIpDQpgYGANCg0KRW4gY3VhbnRvIGEgbG9zIHTDrXR1bG9zIGVuIHN1ZWxvIGFtZXJpY2Fuby4gVGFudG8gRmVkZXJlciBjb21vIERqb2tvdmljIHRhbiBzb2xvIHNlIHB1ZGllcm9uIGhhY2VyIGNvbiB1bm8gZGUgbG9zIHRvcm5lb3MganVnYWRvcyBlbiBlc3RhIHpvbmEgZGVsIHBsYW5ldGEsIG1pZW50cmFzIE5hZGFsIHNlIGhpem8gY29uIDMgdMOtdHVsb3MsIGRlc3RhY8OhbmRvc2UgZWwgTcOhc3RlcnMgU2VyaWVzIGRlIE1vbnRyZWFsLg0KDQpgYGB7cn0NCm1hcGFfbXVuZG8gJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9wb2x5Z29uKGFlcyh4PSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgZmlsbCA9ICJncmV5IiwNCiAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgbmEucm0gPSBGQUxTRSkgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTgsIGZhY2UgPSAiYm9sZCIsIHZqdXN0ID0gMiksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemU9IDEyLCB2anVzdCA9IDIpLA0KICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXI9ICJibGFjayIsIHNpemU9IDEsIGZpbGwgPSAiIzlmZDVkMSIpLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKSArDQogIGdlb21fcG9pbnQoZGF0YSA9IHRvcm5lb3MxLCBtYXBwaW5nID0gYWVzKHg9IGxvbmcsIHk9IGxhdCksIGNvbG9yPSJyZWQiLCBzaXplPSAyKSArDQogIGNvb3JkX2ZpeGVkICh4PSBjKC0xMCwyMCksDQogICAgICAgICAgICAgICB5PSBjKDM1LCA3MCkpKw0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IHRvcm5lb3MxLCBhZXMoeD0gbG9uZywgeT0gbGF0LCBsYWJlbCA9IExvY2F0aW9uLCBjb2xvciA9IFdpbm5lciksIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJtaWRuaWdodGJsdWUiLCAic2VhZ3JlZW4iLCAieWVsbG93IikpICsgDQogIGxhYnModGl0bGUgPSAiVMOtdHVsb3MgY29udGluZW50ZSBldXJvcGVvIGRlbCBCaWcgMyIsDQogICAgICAgc3VidGl0bGUgPSAiUmVwcmVzZW50YWNpw7NuIHRlbXBvcmFkYSBpbmljaW8gw6lsaXRlIiwNCiAgICAgICBjb2xvciA9ICJKdWdhZG9yIikNCmBgYA0KDQpFbiBlbCBjb250aW5lbnRlIGV1cm9wZW8gZnVlIGRvbmRlIEZlZGVyZXIgbG9ncsOzIDUgZGUgc3VzIDcgdMOtdHVsb3MgZGVsIGHDsW8uIE5hZGFsIHBvciBzdSBwYXJ0ZSBnYW5hcsOtYSA3LCBzaWVuZG8gMiBkZSBlbGxvcyBlbiBFc3Bhw7FhLiBFbiBsYSBvdHJhIGNhcmEgZGUgbGEgbW9uZWRhLCBEam9rb3ZpYyBhIHBlbmFzIGxvZ3JhcsOtYSB1bm8gZW4gZWwgTcOhc3RlcnMgU2VyaWVzIGRlIFJvbWEuDQoNCmBgYHtyfQ0KbWFwYV9tdW5kbyAlPiUNCiAgZ2dwbG90KCkgKw0KICBnZW9tX3BvbHlnb24oYWVzKHg9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXApLCBmaWxsID0gImdyZXkiLA0KICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBuYS5ybSA9IEZBTFNFKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxOCwgZmFjZSA9ICJib2xkIiwgdmp1c3QgPSAyKSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZT0gMTIsIHZqdXN0ID0gMiksDQogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91cj0gImJsYWNrIiwgc2l6ZT0gMSwgZmlsbCA9ICIjOWZkNWQxIiksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikpICsNCiAgZ2VvbV9wb2ludChkYXRhID0gdG9ybmVvczIsIG1hcHBpbmcgPSBhZXMoeD0gbG9uZywgeT0gbGF0KSwgY29sb3I9InJlZCIsIHNpemU9IDIpICsNCiAgY29vcmRfZml4ZWQgKHg9IGMoNTAsMTUwKSwNCiAgICAgICAgICAgICAgIHk9IGMoLTQwLCA1MCkpKw0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IHRvcm5lb3MyLCBhZXMoeD0gbG9uZywgeT0gbGF0LCBsYWJlbCA9IExvY2F0aW9uLCBjb2xvciA9IFdpbm5lciksIGZvbnRmYWNlID0gImJvbGQiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJtaWRuaWdodGJsdWUiLCAic2VhZ3JlZW4iLCAieWVsbG93IikpICsgDQogIGxhYnModGl0bGUgPSAiVMOtdHVsb3MgZW4gQXNpYSB5IE9jZWFuw61hIGRlbCBCaWcgMyIsDQogICAgICAgc3VidGl0bGUgPSAiUmVwcmVzZW50YWNpw7NuIHRlbXBvcmFkYSBpbmljaW8gw6lsaXRlIiwNCiAgICAgICBjb2xvciA9ICJKdWdhZG9yIikNCmBgYA0KDQpGaW5hbG1lbnRlIG5vcyBjZW50cmFtb3MgZW4gQXNpYSB5IE9jZWFuw61hLiBFbiBlc3RhIHBhcnRlIGRlbCBnbG9ibywgZWwgdGVuaXN0YSBzZXJiaW8gb2J0dXZvIGxhIG1pdGFkIGRlIHN1cyB0w610dWxvcyBlc2UgYcOxby4gTmFkYWwgeSBGZWRlcmVyIHRhbiBzb2xvIGNvbnF1aXN0YXLDrWFuIHVubyBjYWRhIHVubywgc2llbmRvIGxhIHBhcnRlIGRlbCBtdW5kbyBlbiBsYSBxdWUgbWVub3MgdMOtdHVsb3MgbG9ncsOzIE5hZGFsLg0KDQojIyBFdm9sdWNpw7NuIGRlbCByw6Fua2luZw0KDQpDb250aW51YW5kbyBjb24gZWwgYW7DoWxpc2lzLCBvdHJvIGFzcGVjdG8gYSBjb25zaWRlcmFyIGVzIGxhIGV2b2x1Y2nDs24gZW4gZWwgcsOhbmtpbmcgZGUgY2FkYSBqdWdhZG9yIGEgbG8gbGFyZ28gZGUgc3UgdGVtcG9yYWRhIGRlIGluaWNpby4NCg0KYGBge3J9DQojIEV2b2x1Y2nDs24gZGVsIHJhbmtpbmcNCg0KIyMgRmVkZXJlcg0KdGVtcG9yYWRhXzAzIDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoImRhdG9zIiwgImF0cF8yMDAzLnhscyIpKSAlPiUgbXV0YXRlKFdSYW5rID0gYXMubnVtZXJpYyhXUmFuayksIExSYW5rID0gYXMubnVtZXJpYyhMUmFuaykpDQoNCnJhbmtfaW5pIDwtIHRlbXBvcmFkYV8wMyAlPiUgZmlsdGVyKFdpbm5lciA9PSAiRmVkZXJlciBSLiIgfCBMb3NlciA9PSAiRmVkZXJlciBSLiIpICU+JSBzbGljZSgxKSAlPiUgc2VsZWN0KFdpbm5lciwgV1JhbmspICU+JSByZW5hbWUoYDIwMDMtMDEtMDFgID0gV1JhbmspDQoNCnJhbmtfZmluIDwtIHRlbXBvcmFkYV8wMyAlPiUgZmlsdGVyKFdpbm5lciA9PSAiRmVkZXJlciBSLiIgfCBMb3NlciA9PSAiRmVkZXJlciBSLiIpICU+JSBzbGljZShuKCkpICU+JSBzZWxlY3QoV2lubmVyLCBXUmFuaykgJT4lIHJlbmFtZShgMjAwMy0xMi0zMWAgPSBXUmFuaykNCg0KcmFua19mZWQgPC0gZnVsbF9qb2luKHJhbmtfaW5pLCByYW5rX2ZpbiwgYnkgPSBjKCJXaW5uZXIiID0gIldpbm5lciIpKQ0KDQojIyBOYWRhbA0KdGVtcG9yYWRhXzA1IDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoImRhdG9zIiwgImF0cF8yMDA1LnhscyIpKSAlPiUgbXV0YXRlKFdSYW5rID0gYXMubnVtZXJpYyhXUmFuayksIExSYW5rID0gYXMubnVtZXJpYyhMUmFuaykpDQoNCnJhbmtfaW5pIDwtIHRlbXBvcmFkYV8wNSAlPiUgZmlsdGVyKFdpbm5lciA9PSAiTmFkYWwgUi4iIHwgTG9zZXIgPT0gIk5hZGFsIFIuIikgJT4lIHNsaWNlKDEpICU+JSBzZWxlY3QoV2lubmVyLCBXUmFuaykgJT4lIHJlbmFtZShgMjAwMy0wMS0wMWAgPSBXUmFuaykNCg0KcmFua19maW4gPC0gdGVtcG9yYWRhXzA1ICU+JSBmaWx0ZXIoV2lubmVyID09ICJOYWRhbCBSLiIgfCBMb3NlciA9PSAiTmFkYWwgUi4iKSAlPiUgc2xpY2UobigpKSAlPiUgc2VsZWN0KFdpbm5lciwgV1JhbmspICU+JSByZW5hbWUoYDIwMDMtMTItMzFgID0gV1JhbmspDQoNCnJhbmtfbmFkIDwtIGZ1bGxfam9pbihyYW5rX2luaSwgcmFua19maW4sIGJ5ID0gYygiV2lubmVyIiA9ICJXaW5uZXIiKSkNCg0KIyMgRGpva292aWMNCnRlbXBvcmFkYV8wOCA8LSByaW86OmltcG9ydChoZXJlOjpoZXJlKCJkYXRvcyIsICJhdHBfMjAwOC54bHMiKSkgJT4lIG11dGF0ZShXUmFuayA9IGFzLm51bWVyaWMoV1JhbmspLCBMUmFuayA9IGFzLm51bWVyaWMoTFJhbmspKQ0KDQpyYW5rX2luaSA8LSB0ZW1wb3JhZGFfMDggJT4lIGZpbHRlcihXaW5uZXIgPT0gIkRqb2tvdmljIE4uIiB8IExvc2VyID09ICJEam9rb3ZpYyBOLiIpICU+JSBzbGljZSgxKSAlPiUgc2VsZWN0KFdpbm5lciwgV1JhbmspICU+JSByZW5hbWUoYDIwMDMtMDEtMDFgID0gV1JhbmspDQoNCnJhbmtfZmluIDwtIHRlbXBvcmFkYV8wOCAlPiUgZmlsdGVyKFdpbm5lciA9PSAiRGpva292aWMgTi4iIHwgTG9zZXIgPT0gIkRqb2tvdmljIE4uIikgJT4lIHNsaWNlKG4oKSkgJT4lIHNlbGVjdChXaW5uZXIsIFdSYW5rKSAlPiUgcmVuYW1lKGAyMDAzLTEyLTMxYCA9IFdSYW5rKQ0KDQpyYW5rX2RqbyA8LSBmdWxsX2pvaW4ocmFua19pbmksIHJhbmtfZmluLCBieSA9IGMoIldpbm5lciIgPSAiV2lubmVyIikpDQoNCg0KcmFuayA8LSByYmluZChyYW5rX2ZlZCwgcmFua19uYWQsIHJhbmtfZGpvKSAlPiUgDQogIG11dGF0ZShXaW5uZXIgPSBjYXNlX3doZW4oDQogICAgV2lubmVyID09IkZlZGVyZXIgUi4iIH4gICJGZWRlcmVyIiwNCiAgICBXaW5uZXIgPT0iTmFkYWwgUi4iIH4gICJOYWRhbCIsDQogICAgV2lubmVyID09IkRqb2tvdmljIE4uIiB+ICAiRGpva292aWMiKSkgJT4lIA0KICBwaXZvdF9sb25nZXIoY29scyA9IDI6MywgbmFtZXNfdG8gPSAiUGVyaW9kbyIsIHZhbHVlc190byA9ICAiUmFua2luZyIpICU+JSANCiAgbXV0YXRlKFBlcmlvZG8gPSBtb250aChQZXJpb2RvKSkgJT4lIA0KICBtdXRhdGUoUmFua2luZyA9IGFzLmludGVnZXIoUmFua2luZykpICU+JSANCiAgcmVuYW1lKEp1Z2Fkb3IgPSBXaW5uZXIpDQoNCmdncGxvdChyYW5rLCBhZXMoUGVyaW9kbywgUmFua2luZywgZ3JvdXAgPSBKdWdhZG9yLCBjb2xvcj1KdWdhZG9yKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSAgPSAxLjIpICsgDQogIGdlb21fcG9pbnQoc2l6ZT0gMi41KSArIA0KICBzY2FsZV95X3JldmVyc2UoYnJlYWtzID0gc2VxKDEsIDU1LCAxMCkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxLCAxMiwgMTEpLCBsYWJlbHMgPSBjKCJJbmljaW8iLCAiRmluYWwiKSkgKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2QoKSArDQogIGxhYnModGl0bGUgPSAiRXZvbHVjacOzbiBkZWwgcsOhbmtpbmcgZW4gbGEgdGVtcG9yYWRhXG5kZSBpbmljaW8gw6lsaXRlIg0KICApICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsgDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBoanVzdCA9IDAuNSksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgdHJhbnNpdGlvbl9yZXZlYWwoUGVyaW9kbykgDQoNCmBgYA0KDQpMYSBncsOhZmljYSBhbnRlcmlvciBlcyBtdXkgaWx1c3RyYXRpdmEgZGVsIGdyYW4gc2FsdG8gZW4gZWwgcsOhbmtpbmcgZGUgUmFmYWVsIE5hZGFsIGVuIHN1IHRlbXBvcmFkYSAyMDA1LiBBdmFuesOzIDQ5IHB1ZXN0b3MsIGFjYWJhbmRvIGVsIGHDsW8gY29tbyBlbCBzZWd1bmRvIG1lam9yIGp1Z2Fkb3IgZGVsIHBsYW5ldGEuIEVuIGVsIGNhc28gZGUgRmVkZXJlciB5IERqb2tvdmljLCBhbCB0cmF0YXJzZSBkZSBqdWdhZG9yZXMgYWxnbyBtw6FzIG1heW9yZXMsIHlhIHNlIGVuY29udHJhYmFuIGNvbnNvbGlkYWRvcyBlbnRyZSBsb3MgMTAgbWVqb3Jlcy4gQW1ib3MgYWNhYmFyb24gZW4gZWwgbsO6bWVybyAzIGRlbCByw6Fua2luZy4NCg0KIyMgVG9wcyBnYW5hZG9zDQoNClBvciDDumx0aW1vLCBlcyBkZSBncmFuIGludGVyw6lzIGNvbm9jZXIgZWwgZGVzZW1wZcOxbyBkZSBlc3RvcyBqdWdhZG9yZXMgZnJlbnRlIGEgbG9zIGdyYW5kZXMgdGVuaXN0YXMgZGUgc3UgdGVtcG9yYWRhIGRlIGluaWNpby4gRW4gZXN0ZSBhcGFydGFkbywgRmVkZXJlciBlcyBlbCBxdWUgbWVqb3IgcmF0aW8gdmljdG9yaWFzL2RlcnJvdGFzIHRpZW5lLiBEam9rb3ZpYyBmdWUgZWwganVnYWRvciBxdWUgbcOhcyBwYXJ0aWRvcyBkZSBhbHRvIG5pdmVsIGRpc3B1dMOzLCBjb24gdW4gdG90YWwgZGUgMTAgdmljdG9yaWFzIGVuIDE5IGVuZnJlbnRhbWllbnRvcy4gTmFkYWwgdHV2byB1biBub3RvcmlvIGRlc2VtcGXDsW8gY29uIDUgdmljdG9yaWFzIHkgMyBkZXJyb3Rhcy4gU2luIGVtYmFyZ28sIGFsIHNlciBlbCBqdWdhZG9yIHF1ZSBtw6FzIGF0csOhcyBlbiBlbCByw6Fua2luZyBlbXBlesOzIGVsIGHDsW8sIGRpc3B1dMOzIG1lbm9zIHBhcnRpZG9zIGFudGUganVnYWRvcmVzIFRvcC4NCg0KYGBge3J9DQojRmVkZXJlcg0Kdl90b3AxMF9mZWQgPC0gdGVtcG9yYWRhXzAzICU+JSBmaWx0ZXIoV2lubmVyICVpbiUgYygiRmVkZXJlciBSLiIpICYgTFJhbmsgPD0gMTApICU+JSBncm91cF9ieShXaW5uZXIpICU+JSBzdW1tYXJpc2UoVmljdG9yaWFzID0gbigpKQ0KDQpkX3RvcDEwX2ZlZCA8LSB0ZW1wb3JhZGFfMDMgJT4lIGZpbHRlcihMb3NlciAlaW4lIGMoIkZlZGVyZXIgUi4iKSAmIFdSYW5rIDw9IDEwKSAlPiUgZ3JvdXBfYnkoTG9zZXIpICU+JSBzdW1tYXJpc2UoRGVycm90YXMgPSBuKCkpDQoNClRvcDEwX2ZlZCA8LSBmdWxsX2pvaW4odl90b3AxMF9mZWQsIGRfdG9wMTBfZmVkLCBieSA9IGMoIldpbm5lciIgPSAiTG9zZXIiKSkgJT4lIHBpdm90X2xvbmdlcihjb2xzID0gMjozLCBuYW1lc190byA9ICJWL0QiLCB2YWx1ZXNfdG8gPSAiTsO6bWVybyIpDQoNCiNOYWRhbA0Kdl90b3AxMF9uYWQgPC0gdGVtcG9yYWRhXzA1ICU+JSBmaWx0ZXIoV2lubmVyICVpbiUgYygiTmFkYWwgUi4iKSAmIExSYW5rIDw9IDEwKSAlPiUgZ3JvdXBfYnkoV2lubmVyKSAlPiUgc3VtbWFyaXNlKFZpY3RvcmlhcyA9IG4oKSkNCg0KZF90b3AxMF9uYWQgPC0gdGVtcG9yYWRhXzA1ICU+JSBmaWx0ZXIoTG9zZXIgJWluJSBjKCJOYWRhbCBSLiIpICYgV1JhbmsgPD0gMTApICU+JSBncm91cF9ieShMb3NlcikgJT4lIHN1bW1hcmlzZShEZXJyb3RhcyA9IG4oKSkNCg0KVG9wMTBfbmFkIDwtIGZ1bGxfam9pbih2X3RvcDEwX25hZCwgZF90b3AxMF9uYWQsIGJ5ID0gYygiV2lubmVyIiA9ICJMb3NlciIpKSAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSAyOjMsIG5hbWVzX3RvID0gIlYvRCIsIHZhbHVlc190byA9ICJOw7ptZXJvIikNCg0KI0Rqb2tvdmljDQp2X3RvcDEwX2RqbyA8LSB0ZW1wb3JhZGFfMDggJT4lIGZpbHRlcihXaW5uZXIgJWluJSBjKCJEam9rb3ZpYyBOLiIpICYgTFJhbmsgPD0gMTApICU+JSBncm91cF9ieShXaW5uZXIpICU+JSBzdW1tYXJpc2UoVmljdG9yaWFzID0gbigpKQ0KDQpkX3RvcDEwX2RqbyA8LSB0ZW1wb3JhZGFfMDggJT4lIGZpbHRlcihMb3NlciAlaW4lIGMoIkRqb2tvdmljIE4uIikgJiBXUmFuayA8PSAxMCkgJT4lIGdyb3VwX2J5KExvc2VyKSAlPiUgc3VtbWFyaXNlKERlcnJvdGFzID0gbigpKQ0KDQpUb3AxMF9kam8gPC0gZnVsbF9qb2luKHZfdG9wMTBfZGpvLCBkX3RvcDEwX2RqbywgYnkgPSBjKCJXaW5uZXIiID0gIkxvc2VyIikpICU+JSBwaXZvdF9sb25nZXIoY29scyA9IDI6MywgbmFtZXNfdG8gPSAiVi9EIiwgdmFsdWVzX3RvID0gIk7Dum1lcm8iKSANCg0KDQpUb3AxMCA8LSByYmluZChUb3AxMF9mZWQsIFRvcDEwX25hZCwgVG9wMTBfZGpvKSAlPiUgbXV0YXRlKGBWL0RgID0gZm9yY2F0czo6YXNfZmFjdG9yKGBWL0RgKSkgJT4lIG11dGF0ZShgVi9EYCA9IGZvcmNhdHM6OmZjdF9yZW9yZGVyKGBWL0RgLCBOw7ptZXJvLCAuZGVzYyA9IFRSVUUpKSAlPiUgbXV0YXRlKFdpbm5lciA9IGNhc2Vfd2hlbigNCiAgV2lubmVyID09IkZlZGVyZXIgUi4iIH4gICJGZWRlcmVyIiwNCiAgV2lubmVyID09Ik5hZGFsIFIuIiB+ICAiTmFkYWwiLA0KICBXaW5uZXIgPT0iRGpva292aWMgTi4iIH4gICJEam9rb3ZpYyIpKQ0KDQpUb3AxMCAlPiUgZ2dwbG90KGFlcyh4PSBXaW5uZXIsIHk9IE7Dum1lcm8sIGZpbGw9IGBWL0RgKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwNCiAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTAsIDIpKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKw0KICBnZW9tX3RleHQoYWVzKHk9TsO6bWVybywgbGFiZWwgPSBOw7ptZXJvKSwgDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwgc2l6ZSA9IDUsIA0KICAgICAgICAgICAgdmp1c3Q9MS41LCBjb2wgPSAiV2hpdGUiLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBsYWJzKHRpdGxlID0gIlBhcnRpZG9zIGZyZW50ZSBhIFRvcCAxMCB0ZW1wb3JhZGFcbmluaWNpbyBlbiBsYSDDqWxpdGUiLA0KICAgICAgIGZpbGw9ICJSZXN1bHRhZG8iKSArDQogIHRoZW1lX2lwc3VtKCkgKw0KICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSkNCg0KYGBgDQoNCkRlIGVzdGUgbW9kbywgZW4gZXN0ZSBhcGFydGFkbyBwb2RlbW9zIGFmaXJtYXIgcXVlIE5hZGFsIGVzIGVsIGp1Z2Fkb3IgcXVlIGV4cGxvdMOzIHN1IHRlbmlzIGNvbiBtYXlvciBwcmVjb2NpZGFkLCBhZGVtw6FzIGRlIHNlciBlbCBxdWUgb2J0dXZvIG1heW9yZXMgw6l4aXRvcyBlbiBzdSBwcmltZXJhIHRlbXBvcmFkYSBlbiBsYSDDqWxpdGUgZGVsIHRlbmlzIG11bmRpYWwuDQoNCiMgOC4gQ3JpdGVyaW8gNjogQ29uZmlhbnphIGRlbCBww7pibGljbw0KDQpFbCDDumx0aW1vIGRlIGxvcyBjcml0ZXJpb3MgcXVlIHV0aWxpemFyZW1vcyBlcyBsYSBjb25maWFuemEgcXVlIGxvcyBmYW7DoXRpY29zIGRlbCB0ZW5pcyBoYW4gZGVwb3NpdGFkbyBlbiBjYWRhIHVubyBkZSBlc3RvcyBqdWdhZG9yZXMgYSBsbyBsYXJnbyBkZWwgdGllbXBvLiBQYXJhIGVsbG8sIHV0aWxpemFyZW1vcyBlbCDDrW5kaWNlIGRlIGdhbmFuY2lhIHBvciBldXJvIGp1Z2FkbyBkZSBsYSBjYXNhIGRlIGFwdWVzdGFzIEJldDM2NSBkZXNkZSBlbCBhw7FvIDIwMDIgaGFzdGEgbGEgYWN0dWFsaWRhZC4gRXN0b3Mgw61uZGljZXMgc29uIG3DoXMgcGVxdWXDsW9zIGN1w6FudG8gbcOhcyBnZW50ZSBhcHVlc3RhIHBvciBsYSB2aWN0b3JpYSBkZSB1biBqdWdhZG9yLiBQb3IgZWxsbywgY29uc2lkZXJhcmVtb3MgcXVlIGVsIGp1Z2Fkb3IgcXVlIHRlbmdhIHVuIMOtbmRpY2UgbWVkaW8gbcOhcyBiYWpvIHF1ZSBlbCByZXN0byBlcyBlbCBqdWdhZG9yIGVuIHF1ZSBtw6FzIGNvbmZpYW56YSBkZXBvc2l0YW4gbG9zIGFwb3N0YW50ZXMuDQoNCmBgYHtyfQ0KdGVtcG9yYWRhczIgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiZGF0b3MiLCAidGVtcG9yYWRhczIuY3N2IikpDQoNCnp6IDwtIHRlbXBvcmFkYXMyICU+JSAgZmlsdGVyKFdpbm5lciAlaW4lIGMoIkZlZGVyZXIgUi4iLCAiTmFkYWwgUi4iLCAiRGpva292aWMgTi4iKSkgJT4lIGRyb3BfbmEoQjM2NVcpICU+JSANCiAgbXV0YXRlKERhdGUgPSB5ZWFyKERhdGUpKSAlPiUgDQogIGdyb3VwX2J5KFdpbm5lciwgRGF0ZSkgJT4lIA0KICBzdW1tYXJpc2UoQjM2NVcgPSBtZWFuKEIzNjVXKSkgJT4lIHVuZ3JvdXAoKSAlPiUgDQogIGFycmFuZ2UoRGF0ZSkgJT4lIA0KICBtdXRhdGUoV2lubmVyID0gY2FzZV93aGVuKA0KICAgIFdpbm5lciA9PSJGZWRlcmVyIFIuIiB+ICAiRmVkZXJlciIsDQogICAgV2lubmVyID09Ik5hZGFsIFIuIiB+ICAiTmFkYWwiLA0KICAgIFdpbm5lciA9PSJEam9rb3ZpYyBOLiIgfiAgIkRqb2tvdmljIikpICU+JSANCiAgc2VsZWN0KGlkID0gV2lubmVyLCBkYXRlID0gRGF0ZSwgdmFsdWUgPSBCMzY1VykNCg0Kcm9ic2VydmFibGUoDQogICJodHRwczovL29ic2VydmFibGVocS5jb20vQGp1YmEvYmFyLWNoYXJ0LXJhY2UiLA0KICBpbmNsdWRlID0gYygidmlld29mIGRhdGUiLCAiY2hhcnQiLCAiZHJhdyIsICJzdHlsZXMiKSwNCiAgaGlkZSA9ICJkcmF3IiwNCiAgaW5wdXQgPSBsaXN0KA0KICAgIGRhdGEgPSB6eiwgDQogICAgdGl0bGUgPSAiQ29uZmlhbnphIGRlbCBww7pibGljbyBlbiBlbCBCaWcgMyIsDQogICAgc3VidGl0bGUgPSAiRXZvbHVjacOzbiBhcHVlc3RhcyBlbiBCMzY1IiwNCiAgICBzb3VyY2UgPSAiIiwNCiAgICB0aWNrRHVyYXRpb24gPSAxMDAwKSwNCiAgd2lkdGggPSAxMDAwLA0KICBoZWlnaHQgPSA3MDApDQpgYGANCg0KR3JhY2lhcyBhIGxhIGdyw6FmaWNhIGFudGVyaW9yLCBwb2RlbW9zIG9ic2VydmFyIHF1ZSBubyBleGlzdGUgbmluZ8O6biBwZXJpb2RvIGVuIGVsIHF1ZSBhbGd1bm8gZGUgbG9zIGp1Z2Fkb3JlcyBoYXlhIHNpZG8gdGFuIHN1cGVyaW9yIGFsIHJlc3RvIGNvbW8gcGFyYSBxdWUgbG9zIGFwb3N0YW50ZXMgZGVwb3NpdGFyw6FuIG1heW9yIGNvbmZpYW56YSBlbiDDqWwgYcOxbyB0cmFzIGHDsW8uIERlcGVuZGllbmRvIGRlbCBhw7FvIHF1ZSBhbmFsaWNlbW9zLCBsYSBjb25maWFuemEgZW4gZXN0b3MganVnYWRvcmVzIHZhcsOtYS4gUG9yIGxvIHRhbnRvLCBlc3RlIGNyaXRlcmlvIG5vIGVzIGRldGVybWluYW50ZSBwYXJhIHJlc3BvbmRlciBhIGxhIGN1ZXN0acOzbiBhbnRlIGxhIHF1ZSBub3MgZW5jb250cmFtb3MuDQoNCiMgOS4gQ29uY2x1c2nDs24NCg0KVW5hIHZleiBhbmFsaXphZGEgeSBjbGFzaWZpY2FkYSBsYSBpbmZvcm1hY2nDs24gYW50ZXJpb3IsIG5vcyBlbmNvbnRyYW1vcyBlbiB1bmEgbWVqb3IgcG9zaWNpw7NuIHBhcmEgY29uY2x1aXIgcXVpw6luIGVzIGVsIG1lam9yIGp1Z2Fkb3IgZGUgdGVuaXMgZGUgdG9kb3MgbG9zIHRpZW1wb3MuIE1pIHJlc3B1ZXN0YSBlcyBjbGFyYTogKiphIGTDrWEgZGUgaG95IG5vIGVzIHBvc2libGUgZGVjaXIgcXXDqSBqdWdhZG9yIGRlIGxvcyB0cmVzIGVzIHN1cGVyaW9yKiouDQoNCkNhZGEgdW5vIGRlIGxvcyBtaWVtYnJvcyBkZWwgQmlnIDMgZGVzdGFjYW4gZW4gdW5vcyBhc3BlY3Rvcy4gRW4gZWwgY2FzbyBkZSAqKlJvZ2VyIEZlZGVyZXIqKiwgZWwgdGVuaXN0YSBzdWl6byBlcyBkZSBsbyBtw6FzIGJyaWxsYW50ZSBxdWUgaGEgZGFkbyBlbCBkZXBvcnRlIG11bmRpYWwuIFN1IGNsYXNlLCBzdSB0YWxlbnRvIHkgbG8gcXVlIGhhIHJlcHJlbnNlbnRhZG8gcGFyYSBlbCB0ZW5pcyBlcyBpbmlndWFsYWJsZS4gQWRlbcOhcywgZXN0YWTDrXN0aWNhbWVudGUgaGEgc2lkbyBlbCBkb21pbmFkb3IgZGVsIGNpcmN1aXRvIGR1cmFudGUgYWxyZWRlZG9yIGRlIDQgYcOxb3MsIGRlIDIwMDQgYSAyMDA4LiBVbiByw6ljb3JkIGFsIGFsY2FuY2UgZGUgbXV5IHBvY29zLiANCg0KUGFyYSBoYWJsYXIgZGUgKipSYWZhZWwgTmFkYWwqKiBmYWx0YW4gY2FsaWZpY2F0aXZvcyBlbiBlbCBkaWNjaW9uYXJpby4gRGUgw6lsIHPDrSBxdWUgcG9kZW1vcyBkZWNpciBxdWUgZXMgZWwgbWVqb3IganVnYWRvciBkZSBsYSBoaXN0b3JpYSBlbiB0aWVycmEgYmF0aWRhLiBTdSByw6ljb3JkIHNvYnJlIGVzdGEgc3VwZXJmaWNpZSBlcyBkZSBvdHJvIHBsYW5ldGEuIFBvciBvdHJvIGxhZG8sIGxvcyB2YWxvcmVzIHF1ZSBOYWRhbCByZXByZXNlbnRhIGRlc3RhY2FuIHBvciBlbmNpbWEgZGUgc3VzIMOpeGl0b3MuIFNpbiBkdWRhLCB1biBkZXBvcnRpc3RhIGVqZW1wbGFyLiANClBvciDDumx0aW1vLCBwYXJhIGhhYmxhciBkZSAqKk5vdmFrIERqb2tvdmljKiogZXMgbmVjZXNhcmlvIGhhY2VybG8gZW4gZWwgbcOhcyBhY3R1YWwgZGUgbG9zIHRpZW1wb3MgdmVyYmFsZXMuIERqb2tvdmljIGVzIHkgc2lndWUgc2llbmRvIGVsIGRvbWluYWRvciBtw6FzIGFycm9sbGFkb3IgZGUgbGEgw7psdGltYSBkw6ljYWRhLCBhZGVtw6FzIGRlIHVuIGx1Y2hhZG9yIGluY2Fuc2FibGUuDQoNClRlcm1pbmFyZW1vcyBlc3RlIGRvY3VtZW50byByaW5kacOpbmRvbm9zIHVuYSB2ZXogbcOhcyBhbnRlIGxhcyBwYWxhYnJhcyBkZSBSYWZhZWwgTmFkYWwgcXVlIHNlIGRlc3RhY2Fyb24gZW4gbGEgaW50cm9kdWNjacOzbiBkZSBlc3RlIHRyYWJham86ICpTaSBhbGd1aWVuIGRpY2UgcXVlIHNveSBtZWpvciBxdWUgUm9nZXIsIGNyZW8gcXVlIG5vIHNhYmUgbmFkYSBzb2JyZSBlbCB0ZW5pcyouIFkgZXMgcXVlIHNpIGxvIGRpY2UgUmFmYWVsIE5hZGFsLCB0aWVuZSBxdWUgc2VyIGNpZXJ0by4NCg0KRGlzZnJ1dGVtb3MgZGUgZXN0b3MgZ3JhbmRlcyBqdWdhZG9yZXMgbWllbnRyYXMgZXN0w6luIGVuIGFjdGl2by4gU2kgYWxndW5hIHZleiBsYXMgY29tcGFyYWNpb25lcyBmdWVyb24gb2Rpb3NhcywgZXN0ZSBlcyBlbCBlamVtcGxvIHF1ZSBtZWpvciBsbyBpbHVzdHJhLi4uDQoNCiMgMTAuIEJpYmxpb2dyYWbDrWENCg0KTG9zIGRhdG9zIGFjZXJjYSBkZSBsYXMgZXN0YWTDrXN0aWNhcyBkZSBHcmFuZCBTbGFtcywgc2UgaGFuIG9idGVuaWRvIGRlIFthcXXDrV0oaHR0cHM6Ly9kYXRhLndvcmxkL2ZzZDAxL3Rlbm5pcy1ncmFuZC1zbGFtLWNoYW1waW9uc2hpcHMtY2hhbXBpb24tdnMtcnVubmVyLXVwLW1lbikNCg0KTG9zIGRhdG9zIGFjZXJjYSBkZSBsYXMgZXN0YWTDrXN0aWNhcyBkZSBsb3MgcGFydGlkb3MgZGUgY2FkYSB0ZW1wb3JhZGEgZGVzZGUgZWwgYcOxbyAyMDAwLCBzZSBoYW4gb2J0ZW5pZG8gZGUgW2FxdcOtXShodHRwczovL2RhdGEud29ybGQvdHlsZXJ1ZGl0ZS9hdHAtbWF0Y2gtZGF0YSkNCg0KRGF0b3MgeSBlc3RhZMOtc3RpY2FzIHNvYnJlIGxvcyB0ZW5pc3RhcyBwcm9mZXNpb25hbGVzLCBzZSBoYW4gb2J0ZW5pZG8gZGUgW2FxdcOtXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vSmVmZlNhY2ttYW5uL3Rlbm5pc19hdHAvbWFzdGVyL2F0cF9wbGF5ZXJzLmNzdikNCg0KRWwgcmFua2luZyBBVFAgZGVzZGUgMTk5MCwgc2UgaGEgb2J0ZW5pZG8gZGVzY2FyZ8OhbmRvbG8gZGU6DQoNCi0gICBbUsOhbmtpbmcgOTBzXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vSmVmZlNhY2ttYW5uL3Rlbm5pc19hdHAvbWFzdGVyL2F0cF9yYW5raW5nc185MHMuY3N2KQ0KLSAgIFtSw6Fua2luZyAyMDAwc10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0plZmZTYWNrbWFubi90ZW5uaXNfYXRwL21hc3Rlci9hdHBfcmFua2luZ3NfMDBzLmNzdikNCi0gICBbUsOhbmtpbmcgMjAxMHNdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9KZWZmU2Fja21hbm4vdGVubmlzX2F0cC9tYXN0ZXIvYXRwX3JhbmtpbmdzXzEwcy5jc3YpDQotICAgW1LDoW5raW5nIDIwMjBdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9KZWZmU2Fja21hbm4vdGVubmlzX2F0cC9tYXN0ZXIvYXRwX3JhbmtpbmdzXzIwcy5jc3YpDQotICAgW1LDoW5raW5nIDIwMjFdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9KZWZmU2Fja21hbm4vdGVubmlzX2F0cC9tYXN0ZXIvYXRwX3JhbmtpbmdzX2N1cnJlbnQuY3N2KQ0KDQpbQXJ0w61jdWxvXShodHRwczovL3d3dy5wdW50b2RlYnJlYWsuY29tLzIwMTUvMDQvMjIvZGlhLXRlbmlzLXBhc28tYWJpZXJ0bykgc29icmUgZWwgZMOtYSBxdWUgZWwgdGVuaXMgcGFzw7MgYSBzZXIgKmFiaWVydG8uKg0KDQpMYSBmdWVudGUgb2ZpY2lhbCBkZSBsYSBBVFAgcGFyYSBsYSBjb21wcm9iYWNpw7NuIGRlIGxvcyByZXN1bHRhZG9zLCBzZSBwdWVkZSB2aXNpdGFyIFthcXXDrV0oaHR0cHM6Ly93d3cuYXRwdG91ci5jb20vZXMvKQ0KDQo8YnI+PGJyPg0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0Kc2Vzc2lvbmluZm86OnNlc3Npb25faW5mbygpICU+JSBkZXRhaWxzOjpkZXRhaWxzKHN1bW1hcnkgPSAnSW5mb3JtYWNpw7NuIGRlIG1pIFItc2VzacOzbjonKSANCmBgYA0KDQo8YnI+PGJyPg0KDQo6Ojogey50b2NpZnktZXh0ZW5kLXBhZ2UgZGF0YS11bmlxdWU9InRvY2lmeS1leHRlbmQtcGFnZSIgc3R5bGU9ImhlaWdodDogMDsifQ0KOjo6DQoNCjxicj48YnI+DQoNCjo6OiB7LnRvY2lmeS1leHRlbmQtcGFnZSBkYXRhLXVuaXF1ZT0idG9jaWZ5LWV4dGVuZC1wYWdlIiBzdHlsZT0iaGVpZ2h0OiAwOyJ9DQo6OjoNCg==