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 tour de Francia es el evento anual más importante del ciclismo y en gran medida también del deporte internacional, este reúne a los mejores ciclistas del pelotón en la que se verán las caras durante 21 Etapas por las carreteras de Francia, recorriendo el país desde la Bretaña Francesa, pasando por los emblemáticos Pirineos y Alpes hasta llegar a los famosos Campos Elíseos de Paris, donde solo un corredor podrá alcanzar la gloria y cruzar la línea de meta vistiendo el Maillot amarillo de líder. Muchos han sido los que han fracasado en su intento por conseguirlo, pero es que este espacio está reservado para muy pocas leyendas tales como: Gino Bartali, Fausto Coppi, Jaques Anquetil, Eddy Merckx, Miguel Indurain, etc.



El funcionamiento de la carrera es bastante curioso, esta se divide en 21 etapas, que pueden ser llanas, de contrarreloj, de montaña, entre otros tipos. En cada etapa abra un ganador que recibirá el premio por ganar ese día, pero realmente el ganador del Tour es quien ha conseguido finalizar las 21 etapas con el menor tiempo posible, lo que se conoce como la clasificación general, cada corredor tendrá un tiempo que ira deteniendo cada vez que cruce la línea de meta de una etapa y se le irán sumando los tiempos día tras día, por lo tanto puede darse el caso que alguien gane la clasificación general sin haber ganado una etapa. La clasificación general es la más importante pero no la única, existen otro tipo de clasificaciones como: la clasificación por puntos, la clasificación de puertos de montaña y la clasificación de los menores de 25 años, cada una de ellas otorga el derecho a portar un maillot especial.

Trabajo: La idea de este proyecto, por una parte, es analizar cómo ha ido evolucionando la carrera desde sus inicios hasta la actualidad, aspectos relevantes como: distancias, velocidades, diferencias entre corredores, países participantes, etc. También destacar aquellos corredores que más han triunfado pasando desde vencedores de la general hasta ganadores de etapa, en esta segunda parte del trabajo no se trata de volcar los resultados obtenidos en conclusiones sino más bien dar al lector una visión sobre aquellos corredores que más han triunfador en el Tour.


2. Motivaciones

Personalmente he de decir que me declaro un amante incondicional del ciclismo por lo tanto he querido plasmar esta pasión en el trabajo individual, creo que el conocer mucho del mundillo me ayudara por una parte a entender mejor la información obtenida así como expresarla, y por otra parte me resultara mucho más ameno a la hora de estar trabajando.

3. Datos utilizados

Comentarios

Para la realización del trabajo he utilizado los dataframes que se utilizaron en el tidytuesday del 2020-04-07 dedicado al Tour de Francia, el origen de los datos proviene del usuario alastairrushworth y consta de 3 dataframes que contienen información desde los ganadores del tour, de etapas, edades, nacionalidades, pesos, edad, etc. La verdad que los datos están muy bien cuidados y refinados, además al tratarse de un evento del tidytuesday me he podido ayudar e inspirar en algunas de las gráficas realizadas por genios como: André Waage, Ariane Aumaitre, Jake Lawlor, entre otros.


Mencionar que en la mayoría de observaciones solo se tienen datos hasta 2017, está bastante actualizada, pero estamos en 2021 por lo tanto a lo largo del trabajo realizare algún inciso con tal de actualizar la información, pero en líneas generales toda la información es hasta el 2017. Por último, la gran mayoría conocemos el caso de dopaje de Lance Armstrong es por eso que he considerado oportuno eliminar su nombre en aquellas graficas de títulos individuales.



Datos


# Esta lineas de codigo han sido necessarias para poder descargar los dataframe, una vez cargados han sido exportados a un fichero csv por lo tanto estas lineas estan comentadas porque no es necesario ejecutarlas cada vez.

#tdf_winners <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-04-07/tdf_winners.csv')

# Install via devtools::install_github("thebioengineer/tidytuesdayR")

#tuesdata <- tidytuesdayR::tt_load('2020-04-07')
#tuesdata <- tidytuesdayR::tt_load(2020, week = 15)


#tdf_winners <- tuesdata$tdf_winners
#stage_data <- tuesdata$stage_data
#tdf_stages <- tuesdata$tdf_stages

#str(tdf_winners)
#str(stage_data)
#str(tdf_stages)

#tdf_winners %>% 
  #write_csv(here::here("datos", "tdf_winners.csv"))

#stage_data %>% 
  #write_csv(here::here("datos", "stage_data.csv"))

#tdf_stages %>% 
  #write_csv(here::here("datos","tdf_stages.csv"))


stage_data <- read_csv("datos/stage_data.csv")
tdf_winners <- read_csv("datos/tdf_winners.csv")
tdf_stages <- read_excel("datos/tdf_stages.xlsx")

Paquetes

  • library(readr)
  • library(readxl)
  • library(tidyverse)
  • library(ggplot2)
  • library(lubridate)
  • library(ggforce)
  • library(rio)
  • library(ggrepel)
  • library(gt)
  • library(png)
  • library(grid)
  • library(countrycode)
  • library(ggflags)
  • library(hrbrthemes)
  • library(DT)


4. DESARROLLO DEL TOUR

En este primer apartado la idea es analizar cómo ha ido desarrollándose la carrera, desde aquellos desconocidos héroes que decidirían cruzar aquellos puertos de los Alpes, encima de su bicicleta, la mayoría sin asfaltar, prácticamente eran carreteras de barro, hasta la época del ciclismo de épica con Bartali y Coppi, pasando por la década de los 70 con la gran dominación del caníbal Eddy Merckx, los noventa como referente Induráin, hasta la actualidad. Los resultados obtenidos a través de la graficas arrojan una tendencia clara: La carrera cada vez se ha profesionalizado e internacionalizado más.

Vamos a comentar las gráficas apartado por apartado.

4.1. Cada vez más rápido

4.1.1. Evolución de la velocidad media


#Grafica p1 velocidad media

velocidad_media <- tdf_winners 

velocidad_media <- tdf_winners %>%
  mutate(year= year(start_date)) %>%
  mutate(velocidad = distance / time_overall)

                             
p1 <- ggplot(velocidad_media, aes(year, velocidad)) +
  geom_point(color =  "black") +
  geom_smooth(span = 0.2, color = "black" , fill= "#ede657") + theme(panel.grid.major = element_line(colour = "white"),
    panel.background = element_rect(fill = NA)) +labs(x = NULL, y = "velocidad en Km/H") +
  geom_label_repel(data = velocidad_media %>% sample_n(20), 
                   aes(label = winner_name), size = 2.3,  
                   nudge_y = -9, na.rm = TRUE,
                   segment.alpha = 0.2)
 
p1


Como podemos observar la tendencia es muy clara la velocidad media ha ido aumentado como norma general edición tras edición, esto es debido en parte a 3 factores:

  • Mejoras de los componentes.
  • Mejor estado de las carreteras.
  • Profesionalización de la carrera.

A destacar el periodo entre los finales de los 90 y la entrada del nuevo siglo, donde la carrera se vio manchada por numerosos escándalos de dopping, esto explicaría ese fuerte aumento de la velocidad media y su posterior caída una vez erradicado el problema.


4.2. Recorridos cada vez más cortos

4.2.1. Evolución de las distancias


#Grafica p3 evolucion distancias

distancia_ediciones <- tdf_winners %>%
  tidyr::drop_na(distance) %>%
  mutate(year= year(start_date))


p3 <- ggplot(distancia_ediciones, aes(year, distance)) +
  
  geom_line(color="#ede657") +
  geom_area( fill="#ede657") +
  geom_smooth(span = 0.2, color = "#ede657", alpha = 0.2) +
  
  scale_y_continuous( 
                      breaks = seq(0, 6000, 1000),
                      limits = c(0,6000)) +
  
  annotate(
  geom = "curve", x = 1926, y = 5800, xend = 1945, yend = 6000, curvature = .3, arrow = arrow(length = unit(2, "mm"))) +
  
  annotate(geom = "text", x = 1946, y = 6000, label = "En 1926 fue la edición mas larga con un total de 5745 km", hjust = "left") + 
  theme(panel.background = element_rect(fill = NA)) + 
  labs(x = NULL, y = "Distancia en km")
  

p3   


De aquellos recorridos de infarto de etapas que duraban días enteros se ha ido recortando el recorrido de cada etapa y con ello el kilometraje total de cada edición como muestra la tendencia, hasta la actualidad donde parece que la tendencia se ha estabilizado con los recorridos actuales más cortos y explosivos.


El año 1926 fue la edición más larga de todas con un total de 5745 km, aquella edición se dividió en 15 etapas lo que nos da una media de 383 km, me tiemblan las piernas solo de pensar en hacer esa cantidad de kilómetros durante 15 días seguidos.


4.3. Establecimiento de las 21 Etapas

Tipos de etapa

4.3.1. Evolución del numero y tipos de etapa.


#Grafica p4 Tipos de etapa

tipos_etapa <- tdf_stages %>%
  mutate(year= year(Date)) %>%
  group_by(Type,year) %>%
  summarise(total_categoria=n())

  
p4 <- ggplot(tipos_etapa, aes(year, total_categoria, fill = Type)) +
  geom_col() + 
  coord_flip() +
  scale_fill_viridis_d() +
  labs(x = NULL) + theme(panel.background = element_rect(fill = NA),
    legend.position = "right", legend.direction = "vertical") +labs(y = "Numero de etapas", fill = "Tipo de Etapa")
  
p4 


Como hemos mencionado al principio en la introducción el número de etapas en las que se divide la competición es en 21, pero como vemos en el grafico no siempre ha sido así, podemos diferenciar 3 etapas: inicios hasta los años 50, de los 50 los hasta los 90 y de los 90 a la actualidad.


La primera etapa se caracteriza por una primera fase con muy pocas etapas y una segunda fase con un incremento considerable, además esta etapa se caracteriza por los suspensiones del tour durante las dos guerras mundial de ahí los espacios en blanco.La segunda parece un poco caótica cada edición tenía un numero distinto de etapas y no será hasta llegar a los 90 donde se oficialice y acuerde las 21 etapas por edición, una vez más reafirmado la tendencia de la profesionalización.



Tabla


#tabla etapas

etapas_espanol <- tdf_stages %>%
  rename(etapa = "Stage" ,
         fecha = "Date" ,
         distancia = "Distance" ,
         origen = "Origin" ,
         final = "Destination" ,
         tipo = "Type" ,
         ganador = "Winner" ,
         nacionalidad = "Winner_Country" ,) %>%
  select(etapa, fecha, distancia, origen, final, tipo, ganador, nacionalidad)

datatable(etapas_espanol, class ="stripe hover compact row-border" , filter = 'top')


4.3. Hacia la internalización del Tour

4.3.1. Nacionalidades distintas en ganar una etapa por edición



#Grafica p5 nacionalidades en ganar etapa por edicion

nacionalidades <- tdf_stages %>%
  mutate(year = year(Date)) %>%
  group_by(year, Winner_Country) %>%
  summarise(total= n_distinct(Winner_Country)) %>%
  group_by(year) %>%
  summarise(total_nacionalidades= n()) 
  


p5 <- ggplot(nacionalidades, aes(year, total_nacionalidades)) +
  geom_col(aes(fill=total_nacionalidades)) +
  scale_fill_continuous(low="#9e9e9e",high="#282828") + 
  geom_smooth(color = "#ede657", alpha = 0.3) +
  scale_y_continuous(
    breaks = seq(0, 15, 5),
    limits = c(0, 15)) +
  annotate("rect",
           xmin = 1900,
           xmax = 1950,
           ymin = 0,
           ymax = Inf,
           alpha = 0.3,
           fill = "pink") +
  annotate("rect",
           xmin = 1950,
           xmax = 1985,
           ymin = 0,
           ymax = Inf,
           alpha = 0.3,
           fill = "#b2ebf2") +
  annotate("rect",
           xmin = 1985,
           xmax = 2018,
           ymin = 0,
           ymax = Inf,
           alpha = 0.3,
           fill = "#a5d6a7") +
  theme(axis.ticks = element_line(linetype = "blank"),
        axis.text.y = element_text(colour = "white"),
        panel.background = element_rect(fill = NA),
        legend.position = "none") +labs(x = NULL, y = NULL, fill = NULL)+
  theme(axis.ticks = element_line(linetype = "solid"),
    axis.text.y = element_text(colour = "black"))

p5


En esta grafica podemos observar cuantas nacionalidades distintas fueron capaces de ganar una o más etapas en cada edición, una vez más la tendencia es muy clara, el tour se ha ido internalizando, ha pasado de ser una carrera reservada para franceses, belgas, italianos hasta los años 50, a dar pasar a una competición más internacional primero con fuerte dominio europeo para en los 80 y 90 abrir sus puertas a todo el mundo. Una vez más las 3 etapas mencionada anteriormente se ven reflejadas claramente en el gráfico.


4.5. Mayor rivalidad entre ciclistas

4.5.1. Ventaja del ganador respecto del subcampeón



#Grafica p2 Diferencia entre el ganador y subcampeon

tiempo_vencedor <- tdf_winners %>%
  tidyr::drop_na(time_margin) %>%
  mutate(year= year(start_date))

  
p2 <-  ggplot(tiempo_vencedor, aes(x=year,y=time_margin)) +
    geom_point() +
    geom_smooth( formula = y~x,method="loess",
                 color="grey30",fill="#ede657")  +
    scale_y_continuous(breaks = c(0,0.16,1,2,3),
                       labels = c(0,"10 Min","1 Hr","2 Hrs","3 Hrs"),
                       name="Venteja del ganador")+
    scale_x_continuous(name=NULL) +
    coord_cartesian(ylim=c(-.1,3.1),
                    xlim=c(1899,2020),expand=F) + 
  theme(panel.background = element_rect(fill = NA))

p2


Como consecuencia de los dos fenómenos mencionados anteriormente la profesionalización e internalización, la ventaja entre el ganador de la clasificación general y el subcampeón se ha ido reduciendo fuertemente hasta llegar a los tiempos del ciclismo actual donde el vencedor no suele sacar más de 3 o 4 minutos al segundo clasificad, como podemos observar en la gráfica.


5. LOS CICLISTAS

Llegados a este punto y una vez analizado el desarrollo histórico del Tour vamos a enseñar quienes han sido y son los mejores ciclistas que han pasado por las carreteras de Francia, desde los que más clasificaciones generales han ganado hasta los que más etapas se han llevado y también algunos datos curiosos como nacionalidades, edades, etc.


5.1. Ciclistas más laureados

#Tabla 1 corredores mas laureados
#Realmente esta tabla no tiene mucho merito porque ha sido reproducir literalmente el codigo de un usuario por internet pero me ha parecido tan bonita y elegante que me he visto casi forzado a ponerla...

most_wins<-tdf_winners%>%
  # Lo primero es borrar a Armstrong por tramposo
  filter(winner_name!="Lance Armstrong")%>%
  mutate(winner_name=case_when(
    winner_name=='Miguel Induráin'~'Miguel Indurain',
    TRUE~winner_name
  ))%>%
  # Crear la variable para contar titulos
  mutate(ct=1)%>%
  group_by(winner_name)%>%
  summarize(
    # Contamos Titulos
    Titulos=sum(ct),
    # Añadimos nacionalidad
    Nacionalidad=nationality[1],
    # Añadimos el apodo
    Nickname=nickname[1])%>%
  filter(Titulos>2)%>%
  arrange(-Titulos)

# Data preparation:
most_wins<-most_wins%>%
  #  ordenando las columna
  select(
    Corredor=winner_name,
    Nickname,Nacionalidad,Titulos)%>%
  # Limpiando los apodos
  mutate(Nickname=case_when(
    str_detect(Corredor,'Hinault')~'The Badger',
    str_detect(Corredor,'Anquetil')~'Maître Jacques',
    str_detect(Corredor,'Indurain')~'Miguelón',
    str_detect(Corredor,'LeMond')~"The American",
    str_detect(Corredor,'Bobet')~'Zonzon',
    str_detect(Corredor,'Thys')~'The Basset Hound',
    TRUE~Nickname
  ))

most_wins <- most_wins%>%
  mutate(Nacionalidad = case_when(
    str_detect(Nacionalidad,'France') ~ 'https://raw.githubusercontent.com/BjnNowak/TdF/main/fr.png',
    str_detect(Nacionalidad,'Belgium') ~ 'https://raw.githubusercontent.com/BjnNowak/TdF/main/be.png',
    str_detect(Nacionalidad,'Great Britain') ~ 'https://raw.githubusercontent.com/BjnNowak/TdF/main/uk.png',
    str_detect(Nacionalidad,'Spain') ~ 'https://raw.githubusercontent.com/BjnNowak/TdF/main/sp.png',
    str_detect(Nacionalidad,'United States') ~ 'https://raw.githubusercontent.com/BjnNowak/TdF/main/us.png'
  ))

tabla <- most_wins%>%
  gt()%>%
  tab_header(
    title = "Corredores con más victorias en el Tour de Francia"
  )%>%
  gtExtras::gt_theme_nytimes()%>%
  gtExtras::gt_merge_stack(col1 = Corredor, col2 = Nickname)%>%
  # añadimos las banderas
  gtExtras::gt_img_rows(columns = Nacionalidad, height = 20)

tabla%>%
  gtExtras::gt_fa_repeats(
    column=Titulos,
    palette = "orange",
    name = "tshirt",
    align='left'
  )
Corredores con más victorias en el Tour de Francia
Corredor Nacionalidad Titulos
Bernard Hinault
The Badger
T-Shirt T-Shirt T-Shirt T-Shirt T-Shirt
Eddy Merckx
The Cannibal
T-Shirt T-Shirt T-Shirt T-Shirt T-Shirt
Jacques Anquetil
Maître Jacques
T-Shirt T-Shirt T-Shirt T-Shirt T-Shirt
Miguel Indurain
Miguelón
T-Shirt T-Shirt T-Shirt T-Shirt T-Shirt
Chris Froome
Froomey
T-Shirt T-Shirt T-Shirt T-Shirt
Greg LeMond
The American
T-Shirt T-Shirt T-Shirt
Louison Bobet
Zonzon
T-Shirt T-Shirt T-Shirt
Philippe Thys
The Basset Hound
T-Shirt T-Shirt T-Shirt


Este “salón de la fama” por decirlo de alguna manera está reservado a muy pocos, hablar del tour es hablar de aquellas grandes cronos de Bernard Hinault, es de aquellas tardes en el salón disfrutando con Induráin y sin duda de aquella dominación imparable de Eddy Merckx al que solo el difunto Luis Ocaña pudo plantarle cara al caníbal. El ultimo en entrar en este Ranking es Froome corredor que sigue en activo y quién sabe si será capaz de alcanzar los 5 tours, en la actualidad está complicado pero la esperanza es lo último que se pierde. Se puede llegar a quedar corto este ranking porque no aparecen nombres como el de Bartali, Contador, Perico, Poulidor, entre otros, pero es que el nivel ofrecido por estos 8 ciclistas ha sido muy alto.


5.1.1. Consulta quien gano cada edición del Tour


library(DT)

tdf_espanol <- tdf_winners %>% 
  rename(edicion = "edition" ,
         inicio = "start_date" ,
         ganador = "winner_name" ,
         equipo = "winner_team" ,
         distancia = "distance" ,
         tiempo = "time_overall" ,
         nacionalidad = "nationality" ,
         `etapas ganadas` = "stage_wins" ,
         `estapas de lider` = "stages_led") %>%
  select(edicion, inicio, ganador, nacionalidad, equipo, distancia, `etapas ganadas`, `estapas de lider` )
  
  
  
  
datatable(tdf_espanol, class ="stripe hover compact row-border" , filter = 'top')

5.2. Ciclistas destacados

Etapas

5.2.1. Corredores que mas estapas han ganado del Tour


#Maximos ganadores de etapas

ganadores_etapa <- tdf_stages %>%
  filter(Winner!="Lance Armstrong[n 1]")%>%
  group_by(Winner) %>%
  mutate(etapas_ganas = n()) %>%
  ungroup() %>%
  count(Winner, Type, etapas_ganas, sort = TRUE) %>%
  filter(etapas_ganas>= 10)
  
  
p6 <- ggplot(ganadores_etapa, aes(reorder(Winner, etapas_ganas), n, fill= Type)) +
  geom_col() +
  scale_fill_viridis_d() +
  coord_flip() + theme(panel.background = element_rect(fill = NA),
    legend.position = c(0.7, 0.4)) +labs(x = NULL, y = "Etapas totales", fill = "Tipo de etapa")


p6


Como podemos ver Merckx es máximo ganador de etapas, pero sería injusto no mencionar que en la última edición el sprinter Mark Cavendish que hasta entonces ocupaba la segunda posición con 30 victorias, ha conseguido igualar al caníbal con 34 victorias, gracias a las 4 etapas ganadas en 2021 y de no haber sido por un ajustado sprint y victoria final en los campos Elíseos de Wout van Aert, este hubiera conseguido superar a Merckx .


Como podemos ver los sprinters son los que suelen copar el ranking de corredores con mayores etapas, esto es debido a su facilidad por ganar etapas. Si estáis interesado en ver quienes han ganado más etapas de montaña o de contrarreloj podéis hacer clic en las pestañas de sus apartados.



Etapas Llanas

5.2.2. Mejores sprinters del Tour
#Mejores ciclistas sprinters 

mejores_sprinters <- tdf_stages %>%
  filter(Winner!="Lance Armstrong[n 1]")%>%
  group_by(Winner) %>%
  mutate(etapas_ganas = n()) %>%
  ungroup() %>%
  count(Winner, Type, etapas_ganas, sort = TRUE) %>%
  filter(Type == "Etapa llana") %>%
  filter(n>= 6)

p7 <-  ggplot(mejores_sprinters, aes(reorder(Winner, n), n)) +
  geom_col(fill = "#fde725") +
  coord_flip() + theme(panel.background = element_rect(fill = NA)) +
  labs(x = NULL, y = "Victorias ")
  
img1 <- readPNG("imagenes/tarmac.png")
marca1 <- rasterGrob(img1, interpolate=F,height=unit(4, "cm"),hjust= -0.2, vjust=1.3)
p7 + annotation_custom(marca1,xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf)



Etapas Montaña

5.2.3. Mejores escaladores del tour

#Mejores ciclistas escaladores

mejores_escaladores <- tdf_stages %>%
  filter(Winner!="Lance Armstrong[n 1]")%>%
  group_by(Winner) %>%
  mutate(etapas_ganas = n()) %>%
  ungroup() %>%
  count(Winner, Type, etapas_ganas, sort = TRUE) %>%
  filter(Type == "Etapa de montaña") %>%
  filter(n>= 4)


p8 <- ggplot(mejores_escaladores, aes(reorder(Winner, n), n)) +
  geom_col(fill = "#8fd744") +
  coord_flip() + theme(panel.background = element_rect(fill = NA)) +
  labs(x = NULL, y = "Victorias ")

img2 <- readPNG("imagenes/mountain.png")
marca2 <- rasterGrob(img2, interpolate=F,height=unit(4, "cm"),hjust= -0.2, vjust=1.3)
p8 + annotation_custom(marca2,xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf)



Etapas Crono

5.2.4. Mejores ciclistas contra el crono

#Mejores ciclistas contra el crono  

mejores_cronos <- tdf_stages %>%
  filter(Winner!="Lance Armstrong[n 1]")%>%
  group_by(Winner) %>%
  mutate(etapas_ganas = n()) %>%
  ungroup() %>%
  count(Winner, Type, etapas_ganas, sort = TRUE) %>%
  filter(Type == "Contrarreloj individual") %>%
  filter(n>= 2)


p9 <- ggplot(mejores_cronos, aes(reorder(Winner, n), n)) +
  geom_col(fill = "#443a83") +
  coord_flip() + theme(panel.background = element_rect(fill = NA)) +
  labs(x = NULL, y = "Victorias ")

img3 <- readPNG("imagenes/crono.png")
marca3 <- rasterGrob(img3, interpolate=F,height=unit(4, "cm"),hjust= -0.2, vjust=1.15)
p9 + annotation_custom(marca3,xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf)



5.3. Francia la gran dominadora

5.3.1. Paises ganadores del Tour


#Grafica p10  ganadores por paises


tdf_winners$code<-tolower(countrycode(tdf_winners$nationality,origin = 'country.name', destination = 'iso2c'))

victorias_pais <- tdf_winners %>%
  filter(winner_name!="Lance Armstrong")%>%
  group_by(nationality,code) %>%
  summarise(victorias = n())

p10 <- ggplot(victorias_pais, aes(reorder(nationality, - victorias), victorias)) +
  geom_col(aes(fill= victorias)) +
  scale_fill_continuous(low="#9e9e9e",high="#282828") +
  geom_flag(aes(nationality, victorias, country = code), y=-1 ,size = 10) + 
  geom_text(aes(nationality,victorias, label = victorias), vjust = -0.8, size = 5) +
  
  annotate(geom = "curve", x = 1.5, y = 36, xend = 5, yend = 36, curvature = .3, arrow = arrow(length = unit(2, "mm"))) +
  annotate(geom = "text", x = 5, y = 37, label = "La última victoria francesa fue en 1985.", hjust = "left") +
  
  lims(y=c(-2,38)) +
theme(panel.background = element_rect(fill = NA)) +
  labs(x = NULL) + theme(legend.position = "none") + 
  theme(axis.ticks = element_line(linetype = "blank"),
  axis.text.y = element_text(colour = "white")) +
  labs(y = NULL)  + 
  theme(axis.text.x = element_text(angle = 90))

p10


Como no podía ser de otra manera el dominio Francés seguido muy de lejos por los Belgas y Españoles, en la carrera es aplastante pero no debemos dejarnos llevar por las apariencias, si analizamos mejor los datos podemos decir que este dominio como tal no existe en la actualidad, muchas de las victorias son de la primera etapa mencionada anteriormente donde la mayoría de los corredores eran franceses, es mas, desde el año 1985 cuando Bernad Hinault conquisto el último Tour ningún otro Francés ha vuelto a ganar la carrera, es decir, han pasado 36 años desde la última victoria Francesa.


5.4. Los ciclistas alcanzan su madurez a los 30 años

5.4.1. Densidad de victorias por edad



p11 <- ggplot(tdf_winners, aes(age)) +
  geom_density(fill="#ede657", color="#ede657", alpha=0.9) +
  theme_ipsum() + theme(plot.subtitle = element_text(family = "serif"),
    plot.caption = element_text(family = "serif"),
    axis.title = element_text(family = "serif"),
    plot.title = element_text(family = "serif")) +labs(x = "Edad", y = "Densidad")
  
p11


El objetivo de esta gráfica era ver donde se encuentra la edad de maduración o en otras palabras cuando un ciclista desarrolla todo su potencial, observando la gráfica podríamos decir que está entre los 28 a 30 años.


5.5. Trayectoria de ciclistas destacados

Alberto Contador

5.5.1. Trayectoria de Alberto Contador en el Tour de Francia
# Grafico p11 analisi de Alberto Contador

carrera_corredor1 <- stage_data %>%
  filter(rider == "Contador Alberto") %>% 
  mutate(posicion = as.numeric(rank)) %>%
  mutate(etapa = factor(as.numeric(str_remove(stage_results_id, "stage-")))) %>%
  mutate(year = factor(year)) 
  
 p11 <- ggplot(carrera_corredor1, aes(year, etapa, fill = posicion)) +
  geom_tile() +
  scale_fill_viridis_c() +
  geom_text(aes(label = rank), size = 2, color = "white") +
  theme(panel.background = element_rect(fill = NA),
  legend.position = "none") +
   labs(title = NULL, x = "Edición", y = "Etapa")

plotly::ggplotly(p11, tooltip = c("y", "x", "fill"))


5.5.1. Victorias de Alberto Contador en el Tour de Francia

#Tabla p15 victoria contador

p15 <- tdf_stages %>% 
  
  rename(Etapa = "Stage",
         Distancia = "Distance",
         Fecha = "Date",
         Origen = "Origin",
         Destino = "Destination",
         Tipo = "Type") %>%
  filter(Winner == "Alberto Contador") %>% 
  select(- Winner, - Winner_Country, - Etapa) 

knitr::kable(p15)
Fecha Distancia Origen Destino Tipo
2009-07-23 40.5 Annecy Annecy Contrarreloj individual
2009-07-19 207.5 Pontarlier Verbier Etapa de montaña
2007-07-22 197.0 Mazamet Plateau-de-Beille Etapa de montaña


Fabian Cancellara

5.5.2. Trayectoria de Fabian Cancellara en el Tour de Francia

carrera_corredor2 <- stage_data %>%
  filter(rider == "Cancellara Fabian") %>% 
  mutate(posicion = as.numeric(rank)) %>%
  mutate(etapa = factor(as.numeric(str_remove(stage_results_id, "stage-")))) %>%
  mutate(year = factor(year)) 

p12 <- ggplot(carrera_corredor2, aes(year, etapa, fill = posicion)) +
  geom_tile() +
  scale_fill_viridis_c() +
  geom_text(aes(label = rank), size = 2, color = "white") +
  theme(panel.background = element_rect(fill = NA),
        legend.position = "none") +
  labs(title = NULL, x = "Edición", y = "Etapa")

plotly::ggplotly(p12, tooltip = c("y", "x", "fill"))


5.5.1. Victorias de Fabian Cancellara en el Tour de Francia

#Tabla p16 victoris Cancellara

p16 <- tdf_stages %>% 
  
  rename(Etapa = "Stage",
         Distancia = "Distance",
         Fecha = "Date",
         Origen = "Origin",
         Destino = "Destination",
         Tipo = "Type") %>%
  filter(Winner == "Fabian Cancellara") %>% 
  select(- Winner, - Winner_Country, - Etapa) 

knitr::kable(p16)
Fecha Distancia Origen Destino Tipo
2007-07-10 236.5 Waregem - Compiègne Waregem - Compiègne Etapa llana
2012-06-30 6.4 Liège Liège Contrarreloj individual
2010-07-03 8.9 Rotterdam Rotterdam Contrarreloj individual
2010-07-24 52.0 Bordeaux Pauillac Contrarreloj individual
2009-07-04 15.5 Monaco Monaco Contrarreloj individual
2008-07-26 53.0 Cérilly Saint-Amand-Montrond Contrarreloj individual
2007-07-07 7.9 London London Contrarreloj individual
2004-07-03 6.1 Liège Liège Contrarreloj individual


Óscar Freire

5.5.1. Trayectoria de Óscar Freire en el Tour de Francia

# Grafico p13 analisi de Oscar Freire

carrera_corredor3 <- stage_data %>%
  filter(rider == "Freire Óscar") %>% 
  mutate(posicion = as.numeric(rank)) %>%
  mutate(etapa = factor(as.numeric(str_remove(stage_results_id, "stage-")))) %>%
  mutate(year = factor(year)) 

p13 <- ggplot(carrera_corredor3, aes(year, etapa, fill = posicion)) +
  geom_tile() +
  scale_fill_viridis_c() +
  geom_text(aes(label = rank), size = 2, color = "white") +
  theme(panel.background = element_rect(fill = NA),
  legend.position = "none") +
  labs(title = NULL, x = "Edición", y = "Etapa")

plotly::ggplotly(p13, tooltip = c("y", "x", "fill"))


5.5.3. Victorias de Óscar Freire en el Tour de Francia

#Tabla p17 victoria Oscar Freire

p17 <- tdf_stages %>% 
  
  rename(Etapa = "Stage",
         Distancia = "Distance",
         Fecha = "Date",
         Origen = "Origin",
         Destino = "Destination",
         Tipo = "Type") %>%
  filter(Winner == "Óscar Freire") %>% 
  select(- Winner, - Winner_Country, - Etapa) 

knitr::kable(p17)
Fecha Distancia Origen Destino Tipo
2008-07-19 194.5 Nîmes Digne-les-Bains Etapa llana
2006-07-06 225.0 Beauvais Caen Etapa llana
2006-07-11 169.5 Bordeaux Dax Etapa llana
2002-07-08 181.0 Luxembourg City Saarbrücken Etapa llana


Tom Boonem

5.5.1. Trayectoria de Tom Boonem en el Tour de Francia

# Grafico p14 analisi de Tom Boonem

carrera_corredor <- stage_data %>%
  filter(rider == "Boonen Tom") %>% 
  mutate(posicion = as.numeric(rank)) %>%
  mutate(etapa = factor(as.numeric(str_remove(stage_results_id, "stage-")))) %>%
  mutate(year = factor(year)) 

p14 <- ggplot(carrera_corredor, aes(year, etapa, fill = posicion)) +
  geom_tile() +
  scale_fill_viridis_c() +
  geom_text(aes(label = rank), size = 2, color = "white") +
  theme(panel.background = element_rect(fill = NA),
        legend.position = "none") +
  labs(title = NULL, x = "Edición", y = "Etapa")

plotly::ggplotly(p14, tooltip = c("y", "x", "fill"))


5.5.4. Victorias de Tom Boonem en el Tour de Francia

#Tabla p18 victoria Tom Boonem

p18 <- tdf_stages %>% 
  
  rename(Etapa = "Stage",
         Distancia = "Distance",
         Fecha = "Date",
         Origen = "Origin",
         Destino = "Destination",
         Tipo = "Type") %>%
  filter(Winner == "Tom Boonen") %>% 
  select(- Winner, - Winner_Country, - Etapa) 

knitr::kable(p18)
Fecha Distancia Origen Destino Tipo
2007-07-13 199.5 Semur-en-Auxois Bourg-en-Bresse Etapa llana
2005-07-03 181.5 Challans Les Essarts Etapa llana
2005-07-04 212.5 La Châtaigneraie Tours Etapa llana
2004-07-09 196.0 Bonneval Angers Etapa llana
2004-07-25 163.0 Montereau-Fault-Yonne Paris Etapa llana
2007-07-20 178.5 Montpellier Castres Etapa llana


6.DATOS CURIOSOS

Para finalizar el trabajo en este último apartado me gustaría realizar una serie de tablas con información sobre equipos, corredores y ciudades que forman parte habitual de la carrera.


Me gustaría aclarar que realizar una clasificación por equipos resulta un poco complicada, ya que en el ciclismo es muy habitual el cambio de nombres de equipos dependiendo de su patrocinador, pero el equipo sigue siendo el mismo pues lo importante es la estructura, un ejemplo de esto sería el Banesto, actualmente conocido como Movistar team, o el Team Sky que ha pasado a llamarse Ineos. Por lo tanto, los datos que se observan en la primera tabla pueden no ser exactos del todo pero mi finalidad en esta ha sido remarcar aquellos equipos que marcaron una época y son muy recordados por los aficionados.

6.1. El Team Sky el equipo con más victorias

6.1.1. Equipos con más victorias del tour


equipo_victoria <- tdf_winners %>%
  group_by(winner_team) %>%
  summarise(n = n()) %>%
  ungroup() %>%
  filter(winner_team!= "France") %>%
  filter(winner_team!="Italy") %>%
  filter(winner_team!="Belgium") %>%
  filter(winner_team!="U.S. Postal Service") %>%
  filter(winner_team!="La Sportive") %>%
  filter(winner_team!="Switzerland") %>%
  filter(winner_team!="Peugeot–BP–Michelin") %>%
  filter(winner_team!="Renault–Elf–Gitane") %>%
  filter(winner_team!="Alcyon–Dunlop") %>%
  filter(winner_team!="Peugeot–Wolber") %>%
  filter(winner_team!="Automoto–Hutchinson") %>%
  filter(winner_team!="Alcyon–Dunlop") %>%
  filter(n>=2)%>%
  arrange(desc(n))



fotos_equipo <- c("imagenes/sky.png", "imagenes/banesto.png", "imagenes/molteni.png", "imagenes/astana.png", "imagenes/discovery.png", "imagenes/claire.png", "imagenes/renault.png", "imagenes/telekom.png")


fotos_pais <- c("imagenes/uk.png", "imagenes/espanya.png", "imagenes/italia.png", "imagenes/caza.png", "imagenes/usa.png", "imagenes/francia.png", "imagenes/francia.png", "imagenes/alemania.png")


equipo_victorias_fotos <- equipo_victoria %>%
  group_by(winner_team) %>%
  add_column(fotos_equipo) %>%
  add_column(fotos_pais) %>%
  ungroup() %>%
  rename(Equipo = "winner_team" , 
         Tours = "n" , 
         Maillot = "fotos_equipo" , 
         Pais = "fotos_pais")

library(gt)

equipo_victorias_fotos %>% gt() %>% 
  gt::text_transform(locations = cells_body(columns = c(Maillot)),
                     fn = function(x) {gt::web_image(x, height = 70 )}) %>%
  gt::text_transform(locations = cells_body(columns = c(Pais)),
                     fn = function(x) {gt::web_image(x, height = 35 )}) 
Equipo Tours Maillot Pais
Team Sky 6
Banesto 5
Molteni 3
Astana 2
Discovery Channel 2
La Vie Claire 2
Renault–Elf 2
Team Telekom 2


6.2. Ciclistas más joven y mayores

En esta ocasión también me ha gustado separar entre corredores de un ciclismo actual más moderno a aquellos primeros ciclistas, no por desmerecer las actuaciones de Henri Cornet o Firmin Lambot pero eran otros tiempos y creo que tampoco sería justo no reconocer el trabajo de Bernal o Cadel Evans.



#Grafica p20 Ganador mas Joven del tour de francia

nacionalidad1 <- ("imagenes/francia.png")
equipo1 <- ("imagenes/conte.png")


ganador_joven <- tdf_winners %>%
  slice_min(age, n=1) %>%
  mutate(year= year(start_date)) %>%
  select(edition, year, winner_name, age) %>%
  add_column(nacionalidad1) %>%
  add_column(equipo1) %>%
  rename(Edicion = "edition" ,
         Año = "year" ,
         Nombre = "winner_name" ,
         Nacionalidad = "nacionalidad1" ,
         Edad = "age" ,
         Equipo = "equipo1" )
  

ganador_joven %>% gt() %>% 
  gt::tab_header(title = md("**Corredor más joven en ganar el Tour**"), subtitle = md("Ciclismo histórico")) %>%
  gt::tab_options(heading.background.color = "#e2282e") %>%
  gt::text_transform(locations = cells_body(columns = c(Nacionalidad)),
                     fn = function(x) {gt::web_image(x, height = 35 )}) %>%
  gt::text_transform(locations = cells_body(columns = c(Equipo)),
                     fn = function(x) {gt::web_image(x, height = 70 )})
Corredor más joven en ganar el Tour
Ciclismo histórico
Edicion Año Nombre Edad Nacionalidad Equipo
2 1904 Henri Cornet 19

#Grafica p21 Ganador mas mayor tour de Francia


nacionalidad1 <- ("imagenes/belgium.png")
equipo1 <- ("imagenes/peugeot.png")


ganador_mayor <- tdf_winners %>%
  slice_max(age, n=1) %>%
  mutate(year= year(start_date)) %>%
  select(edition, year, winner_name, age) %>%
  add_column(nacionalidad1) %>%
  add_column(equipo1) %>%
  rename(Edicion = "edition" ,
         Año = "year" ,
         Nombre = "winner_name" ,
         Nacionalidad = "nacionalidad1" ,
         Edad = "age" ,
         Equipo = "equipo1" )

ganador_mayor %>% gt() %>% 
  gt::tab_header(title = md("**Corredor más mayor en ganar el Tour**"), subtitle = md("Ciclismo histórico")) %>%
  gt::tab_options(heading.background.color = "#e2282e") %>%
  gt::text_transform(locations = cells_body(columns = c(Nacionalidad)),
                     fn = function(x) {gt::web_image(x, height = 35 )}) %>%
  gt::text_transform(locations = cells_body(columns = c(Equipo)),
                     fn = function(x) {gt::web_image(x, height = 70 )})
Corredor más mayor en ganar el Tour
Ciclismo histórico
Edicion Año Nombre Edad Nacionalidad Equipo
16 1922 Firmin Lambot 36




#Grafica p22 Ganador mas Joven del tour de francia moderno

nacionalidad1 <- ("imagenes/colombia.png")
equipo1 <- ("imagenes/ineos.png")


ganador_joven_actual <- tdf_winners %>%
  filter(edition >= 57) %>%
  filter(winner_name !="Laurent Fignon") %>%
  slice_min(age, n=1) %>%
  mutate(year= year(start_date)) %>%
  select(edition, year, winner_name, age) %>%
  add_column(nacionalidad1) %>%
  add_column(equipo1) %>%
  rename(Edicion = "edition" ,
         Año = "year" ,
         Nombre = "winner_name" ,
         Nacionalidad = "nacionalidad1" ,
         Edad = "age" ,
         Equipo = "equipo1" )


ganador_joven_actual %>% gt() %>% 
  gt::tab_header(title = md("**Corredor más joven en ganar el Tour**"), subtitle = md("Ciclismo moderno")) %>%
  gt::tab_options(heading.background.color = "#e2282e") %>%
  gt::text_transform(locations = cells_body(columns = c(Nacionalidad)),
                     fn = function(x) {gt::web_image(x, height = 35 )}) %>%
  gt::text_transform(locations = cells_body(columns = c(Equipo)),
                     fn = function(x) {gt::web_image(x, height = 70 )})
Corredor más joven en ganar el Tour
Ciclismo moderno
Edicion Año Nombre Edad Nacionalidad Equipo
106 2019 Egan Bernal 22

#Grafica p23 Ganador mas mayor tour de Francia moderno

nacionalidad1 <- ("imagenes/australia.png")
equipo1 <- ("imagenes/bmc.png")



ganador_mayor_actual <- tdf_winners %>%
  filter(edition >= 57) %>%
  slice_max(age, n=1) %>%
  mutate(year= year(start_date)) %>%
  select(edition, year, winner_name, age) %>%
  add_column(nacionalidad1) %>%
  add_column(equipo1) %>%
  rename(Edicion = "edition" ,
         Año = "year" ,
         Nombre = "winner_name" ,
         Nacionalidad = "nacionalidad1" ,
         Edad = "age" ,
         Equipo = "equipo1" )


ganador_mayor_actual %>% gt() %>% 
  gt::tab_header(title = md("**Corredor más mayor en ganar el Tour**"), subtitle = md("Ciclismo moderno")) %>%
  gt::tab_options(heading.background.color = "#e2282e") %>%
  gt::text_transform(locations = cells_body(columns = c(Nacionalidad)),
                     fn = function(x) {gt::web_image(x, height = 35 )}) %>%
  gt::text_transform(locations = cells_body(columns = c(Equipo)),
                     fn = function(x) {gt::web_image(x, height = 70 )})
Corredor más mayor en ganar el Tour
Ciclismo moderno
Edicion Año Nombre Edad Nacionalidad Equipo
98 2011 Cadel Evans 34


6.3. París nunca falta a la cita


# tabla ciudadades salidas


etapas_espanol <- tdf_stages %>%
  rename(etapa = "Stage" ,
         fecha = "Date" ,
         distancia = "Distance" ,
         origen = "Origin" ,
         final = "Destination" ,
         tipo = "Type" ,
         ganador = "Winner" ,
         nacionalidad = "Winner_Country" ,) %>%
  select(etapa, fecha, distancia, origen, final, tipo, ganador, nacionalidad)



tabla_origen <- etapas_espanol %>%
  group_by(origen) %>%
  summarise(salidas = n()) %>%
  slice_max(salidas, n = 10) %>%
  rename(ciudad = "origen")



tabla_origen %>% gt() %>% 
  gt::tab_header(title = md("**Ciudades que más han sido inicio de etapa**"), subtitle = md("")) %>%
  gt::tab_options(heading.background.color = "#e0e0e0", column_labels.font.weight = "bold", column_labels.background.color = "#eeeeee")
Ciudades que más han sido inicio de etapa
ciudad salidas
Pau 62
Bordeaux 56
Luchon 51
Paris 44
Grenoble 40
Metz 39
Nice 37
Perpignan 34
Briançon 33
Marseille 33

#tablas ciudad finales


etapas_espanol <- tdf_stages %>%
  rename(etapa = "Stage" ,
         fecha = "Date" ,
         distancia = "Distance" ,
         origen = "Origin" ,
         final = "Destination" ,
         tipo = "Type" ,
         ganador = "Winner" ,
         nacionalidad = "Winner_Country" ,) %>%
  select(etapa, fecha, distancia, origen, final, tipo, ganador, nacionalidad)



tabla_final <- etapas_espanol %>%
  group_by(final) %>%
  summarise(finales = n())%>%
  slice_max(finales, n = 10)%>%
  rename(ciudad = "final" ) %>%
  filter(ciudad != "Caen")


tabla_final %>% gt() %>% 
  gt::tab_header(title = md("**Ciudades que más han sido final de etapa**"), subtitle = md("")) %>%
  gt::tab_options(heading.background.color = "#e0e0e0", column_labels.font.weight = "bold", column_labels.background.color = "#eeeeee")
Ciudades que más han sido final de etapa
ciudad finales
Paris 108
Bordeaux 79
Pau 60
Luchon 43
Metz 38
Grenoble 35
Marseille 35
Nice 35
Perpignan 35
Briançon 33


7. Conclusiones

Al tratarse del trabajo individual y ya haber realizado anteriormente el grupal he podido poner en practica muchas de las cosas que he aprendido en este, por una parte me ha permitido ser mucho más ágil y rápido a la hora de elaborar gráficas, manipular datos con dplyr, entre otros aspectos y por otro lado me ha servido para afianzar conceptos como la creación de tablas. A diferencia del anterior trabajo esta vez me he basado en 3 dataframes sobre el tour de Francia que estaban muy completos, esto me ha permitido agilizar el proceso de trabajo con los datos y ha sido de muy gran ayuda porque en algunas ocasiones me ha permitido inspirarme en trabajos ya realizados por la comunidad R, siempre he intentado añadir un plus a esos gráficos aportando mi granito de arena, así que me siento muy contento con el resultado obtenido.


En cuanto al tema me ha resultado muy ameno ya que me he entretenido mucho observando datos de corredores, es cierto que muchas de las cosas ya las conocía, pero algunas otras cosas no y por lo tanto estoy satisfecho de haber elegido este tema. Como conclusión a este poco tengo que añadir o valorar a raíz de los resultados obtenidos, solo como valoración final me gustaría mencionar que ojalá en unos años pueda realizar el mismo trabajo, pero hablando de ciclismo femenino ya que este está empezando a explotar y promete mucho, pero es una pena que a día de hoy me haya resultado muy difícil sino imposible encontrar datos o información sobre este. Esto es todo y espero que os haya gustado y quién sabe si a partir de ahora os aficionáis al ciclismo sino lo estabais ya.


8. Referencias

En la mayoría de ocasiones todos los comentarios realizados al respecto han sido por mi propia experiencia, pero en alguna ocasión he buscado información en algún blog o página oficial como por ejemplo:

Para la realización del trabajo he utilizados los dataframes del usuario alastairrushworth, que ha sido el encargado de recopilar los datos para el tidytuesday del 2020-04-07 dedicado al Tour de Francia.

En la realización de la tabla de máximos ganadores he utilizado el blog del usuario Benjamin Nowak sobre las tablas {gt} y {gtExtras}.

Además, a la hora de realizar algunos gráficos me he inspirado en algunos ya existentes como por ejemplo los de André Waage Rivenæs, o los de los usuarios de twitter [@ariamsita](https://twitter.com/ariamsita) y [@Jake_Lawlor1](https://twitter.com/Jake_Lawlor1)

Y como no podía ser de otra forma la página The R Graph Gallery ha sido una vez más una gran fuente de inspiración

Por último, También me he consultado algunos aspectos de los trabajos grupales de este año. Estos últimos los podemos encontrar aqui



LS0tDQp0aXRsZTogIkVsIHRvdXIgZGUgRnJhbmNpYSBlbiBkYXRvcyINCmF1dGhvcjogIkplc3VzIExsb3JldCBRdWVybyAoamVsbG9xdWVAYWx1bW5pLnV2LmVzKS4gXG5cbiBVbml2ZXJzaXRhdCBkZSBWYWzDqG5jaWEiDQpkYXRlOiAiRGljaWVtYnJlIGRlIDIwMjEgKGFjdHVhbGl6YWRvIGVsIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVknKWApIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBjc3M6ICIuL2Fzc2V0cy9lc3RpbG9fMi5jc3MiDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiAiaGlkZSINCiAgICB0aGVtZTogZGFyaw0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB5ZXMNCiAgICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIGRmX3ByaW50OiBrYWJsZQ0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KLS0tDQoNCmBgYHtyIHBhY2thZ2VzLXNldHVwLCBpbmNsdWRlID0gRkFMU0V9DQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShnZ2ZvcmNlKQ0KbGlicmFyeShyaW8pDQpsaWJyYXJ5KGdncmVwZWwpDQpsaWJyYXJ5KGd0KQ0KbGlicmFyeShwbmcpDQpsaWJyYXJ5KGdyaWQpDQpsaWJyYXJ5KGNvdW50cnljb2RlKQ0KbGlicmFyeShnZ2ZsYWdzKQ0KbGlicmFyeShocmJydGhlbWVzKQ0KbGlicmFyeShEVCkNCg0KDQpgYGANCg0KDQoNCg0KYGBge3IgY2h1bmstc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZXZhbCA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICAjcmVzdWx0cyA9ICJob2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICBjYWNoZSA9IEZBTFNFLCBjYWNoZS5wYXRoID0gIi9jYWNoZXMvIiwgY29tbWVudCA9ICIjPiIsDQogICAgICAgICAgICAgICAgICAgICAgI2ZpZy53aWR0aCA9IDcsICNmaWcuaGVpZ2h0PSA3LCAgIA0KICAgICAgICAgICAgICAgICAgICAgICNvdXQud2lkdGggPSA3LCBvdXQuaGVpZ2h0ID0gNywNCiAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZSA9IFRSVUUsICBmaWcuc2hvdyA9ICJob2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYXNwID0gMC42MjgsIG91dC53aWR0aCA9ICI5NSUiLCBmaWcuYWxpZ24gPSAiY2VudGVyIikNCmtuaXRyOjpvcHRzX2NodW5rJHNldChkZXYgPSAicG5nIiwgZGV2LmFyZ3MgPSBsaXN0KHR5cGUgPSAiY2Fpcm8tcG5nIikpDQpgYGANCg0KYGBge3Igb3B0aW9ucy1zZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICMtIHBhcmEgcXVpdGFyIGxhIG5vdGFjacOzbiBjaWVudMOtZmljYQ0Kb3B0aW9ucygieWFtbC5ldmFsLmV4cHIiID0gVFJVRSkgDQpgYGANCg0KDQpgYGB7ciBrbGlwcHksIGVjaG8gPSBGQUxTRX0NCmtsaXBweTo6a2xpcHB5KHBvc2l0aW9uID0gYygidG9wIiwgInJpZ2h0IikpICMtIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJybGVzdXIva2xpcHB5IikNCmBgYA0KDQo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5Ij48ZGl2Lz4NCg0KPGhyIGNsYXNzPSJsaW5lYS1ibGFjayI+DQoNCjwhLS0gRWwgcMOhcnJhZm8gZGUgYWJham8gaGFzIGRlIGRlamFybG8gY2FzaSBpZ3VhbCwgc29sbyBIQVMgZGUgU1VTVElUVUlSICJwZXJlenA0NCIgcG9yIHR1IHVzdWFyaW8gZGUgR2l0aHViLS0+DQpUcmFiYWpvIGVsYWJvcmFkbyBwYXJhIGxhIGFzaWduYXR1cmEgIlByb2dyYW1hY2nDs24geSBtYW5lam8gZGUgZGF0b3MgZW4gbGEgZXJhIGRlbCBCaWcgRGF0YSIgZGUgbGEgVW5pdmVyc2l0YXQgZGUgVmFsw6huY2lhIGR1cmFudGUgZWwgY3Vyc28gMjAyMS0yMDIyLiBFbCByZXBvIGRlbCB0cmFiYWpvIGVzdMOhIFthcXXDrV0oaHR0cHM6Ly9naXRodWIuY29tL0plbGxvcXVlL3RyYWJham9fQmlnRGF0YSl7dGFyZ2V0PSJfYmxhbmsifS4gDQoNCjwhLS0gRWwgcMOhcnJhZm8gZGUgYWJham8gaGFzIGRlIGRlamFybG8gZXhhY3RhbWVudGUgaWd1YWwsIE5PIGhhcyBkZSBjYW1iaWFyIG5hZGEtLT4NCg0KTGEgcMOhZ2luYSB3ZWIgZGUgbGEgYXNpZ25hdHVyYSB5IGxvcyB0cmFiYWpvcyBkZSBtaXMgY29tcGHDsWVyb3MgcHVlZGVuIHZlcnNlIFthcXXDrV0oaHR0cHM6Ly9wZXJlenA0NC5naXRodWIuaW8vaW50cm8tZHMtMjEtMjItd2ViLzA3LXRyYWJham9zLmh0bWwpe3RhcmdldD0iX2JsYW5rIn0uDQoNCjxociBjbGFzcz0ibGluZWEtcmVkIj4NCg0KDQojIyAxLiBJbnRyb2R1Y2Npw7NuDQoNCkVsIHRvdXIgZGUgRnJhbmNpYSBlcyBlbCBldmVudG8gYW51YWwgbcOhcyBpbXBvcnRhbnRlIGRlbCBjaWNsaXNtbyB5IGVuIGdyYW4gbWVkaWRhIHRhbWJpw6luIGRlbCBkZXBvcnRlIGludGVybmFjaW9uYWwsIGVzdGUgcmXDum5lIGEgbG9zIG1lam9yZXMgY2ljbGlzdGFzIGRlbCBwZWxvdMOzbiBlbiBsYSBxdWUgc2UgdmVyw6FuIGxhcyBjYXJhcyBkdXJhbnRlIDIxIEV0YXBhcyBwb3IgbGFzIGNhcnJldGVyYXMgZGUgRnJhbmNpYSwgcmVjb3JyaWVuZG8gZWwgcGHDrXMgZGVzZGUgbGEgQnJldGHDsWEgRnJhbmNlc2EsIHBhc2FuZG8gcG9yIGxvcyBlbWJsZW3DoXRpY29zIFBpcmluZW9zIHkgQWxwZXMgaGFzdGEgbGxlZ2FyIGEgbG9zIGZhbW9zb3MgQ2FtcG9zIEVsw61zZW9zIGRlIFBhcmlzLCBkb25kZSBzb2xvIHVuIGNvcnJlZG9yIHBvZHLDoSBhbGNhbnphciBsYSBnbG9yaWEgeSBjcnV6YXIgbGEgbMOtbmVhIGRlIG1ldGEgdmlzdGllbmRvIGVsIE1haWxsb3QgYW1hcmlsbG8gZGUgbMOtZGVyLiBNdWNob3MgaGFuIHNpZG8gbG9zIHF1ZSBoYW4gZnJhY2FzYWRvIGVuIHN1IGludGVudG8gcG9yIGNvbnNlZ3VpcmxvLCBwZXJvIGVzIHF1ZSBlc3RlIGVzcGFjaW8gZXN0w6EgcmVzZXJ2YWRvIHBhcmEgbXV5IHBvY2FzIGxleWVuZGFzIHRhbGVzIGNvbW86ICBHaW5vIEJhcnRhbGksIEZhdXN0byBDb3BwaSwgSmFxdWVzIEFucXVldGlsLCBFZGR5IE1lcmNreCwgTWlndWVsIEluZHVyYWluLCBldGMuDQoNCjxicj4NCg0KPGNlbnRlcj48aW1nIHNyYz0iaW1hZ2VuZXMvbG9nby5wbmciIHdpZHRoID0gIjQwMHB4IiAvPjwvY2VudGVyPg0KDQo8YnI+DQoNCkVsIGZ1bmNpb25hbWllbnRvIGRlIGxhIGNhcnJlcmEgZXMgYmFzdGFudGUgY3VyaW9zbywgZXN0YSBzZSBkaXZpZGUgZW4gMjEgZXRhcGFzLCBxdWUgcHVlZGVuIHNlciBsbGFuYXMsIGRlIGNvbnRyYXJyZWxvaiwgZGUgbW9udGHDsWEsIGVudHJlIG90cm9zIHRpcG9zLiBFbiBjYWRhIGV0YXBhIGFicmEgdW4gZ2FuYWRvciBxdWUgcmVjaWJpcsOhIGVsIHByZW1pbyBwb3IgZ2FuYXIgZXNlIGTDrWEsIHBlcm8gcmVhbG1lbnRlIGVsIGdhbmFkb3IgZGVsIFRvdXIgIGVzIHF1aWVuIGhhIGNvbnNlZ3VpZG8gZmluYWxpemFyIGxhcyAyMSBldGFwYXMgY29uIGVsIG1lbm9yIHRpZW1wbyBwb3NpYmxlLCBsbyBxdWUgc2UgY29ub2NlIGNvbW8gbGEgY2xhc2lmaWNhY2nDs24gZ2VuZXJhbCwgY2FkYSBjb3JyZWRvciB0ZW5kcsOhIHVuIHRpZW1wbyBxdWUgaXJhIGRldGVuaWVuZG8gY2FkYSB2ZXogcXVlIGNydWNlIGxhIGzDrW5lYSBkZSBtZXRhIGRlIHVuYSBldGFwYSB5IHNlIGxlIGlyw6FuIHN1bWFuZG8gbG9zIHRpZW1wb3MgZMOtYSB0cmFzIGTDrWEsIHBvciBsbyB0YW50byBwdWVkZSBkYXJzZSBlbCBjYXNvIHF1ZSBhbGd1aWVuIGdhbmUgbGEgY2xhc2lmaWNhY2nDs24gZ2VuZXJhbCBzaW4gaGFiZXIgZ2FuYWRvIHVuYSBldGFwYS4gDQpMYSBjbGFzaWZpY2FjacOzbiBnZW5lcmFsIGVzIGxhIG3DoXMgaW1wb3J0YW50ZSBwZXJvIG5vIGxhIMO6bmljYSwgZXhpc3RlbiBvdHJvIHRpcG8gZGUgY2xhc2lmaWNhY2lvbmVzIGNvbW86IGxhIGNsYXNpZmljYWNpw7NuIHBvciBwdW50b3MsIGxhIGNsYXNpZmljYWNpw7NuIGRlIHB1ZXJ0b3MgZGUgbW9udGHDsWEgeSBsYSBjbGFzaWZpY2FjacOzbiBkZSBsb3MgbWVub3JlcyBkZSAyNSBhw7FvcywgY2FkYSB1bmEgZGUgZWxsYXMgb3RvcmdhIGVsIGRlcmVjaG8gYSBwb3J0YXIgdW4gbWFpbGxvdCBlc3BlY2lhbC4NCg0KDQoqKlRyYWJham86KiogTGEgaWRlYSBkZSBlc3RlIHByb3llY3RvLCBwb3IgdW5hIHBhcnRlLCBlcyBhbmFsaXphciBjw7NtbyBoYSBpZG8gZXZvbHVjaW9uYW5kbyBsYSBjYXJyZXJhIGRlc2RlIHN1cyBpbmljaW9zIGhhc3RhIGxhIGFjdHVhbGlkYWQsIGFzcGVjdG9zIHJlbGV2YW50ZXMgY29tbzogZGlzdGFuY2lhcywgdmVsb2NpZGFkZXMsIGRpZmVyZW5jaWFzIGVudHJlIGNvcnJlZG9yZXMsIHBhw61zZXMgcGFydGljaXBhbnRlcywgZXRjLiBUYW1iacOpbiBkZXN0YWNhciBhcXVlbGxvcyBjb3JyZWRvcmVzIHF1ZSBtw6FzIGhhbiB0cml1bmZhZG8gcGFzYW5kbyBkZXNkZSB2ZW5jZWRvcmVzIGRlIGxhIGdlbmVyYWwgaGFzdGEgZ2FuYWRvcmVzIGRlIGV0YXBhLCBlbiBlc3RhIHNlZ3VuZGEgcGFydGUgZGVsIHRyYWJham8gbm8gc2UgdHJhdGEgZGUgdm9sY2FyIGxvcyByZXN1bHRhZG9zIG9idGVuaWRvcyBlbiBjb25jbHVzaW9uZXMgc2lubyBtw6FzIGJpZW4gZGFyIGFsIGxlY3RvciB1bmEgdmlzacOzbiBzb2JyZSBhcXVlbGxvcyBjb3JyZWRvcmVzIHF1ZSBtw6FzIGhhbiB0cml1bmZhZG9yIGVuIGVsIFRvdXIuDQoNCjxicj4NCg0KIyMgMi4gTW90aXZhY2lvbmVzDQoNClBlcnNvbmFsbWVudGUgaGUgZGUgZGVjaXIgcXVlIG1lIGRlY2xhcm8gdW4gYW1hbnRlIGluY29uZGljaW9uYWwgZGVsIGNpY2xpc21vIHBvciBsbyB0YW50byBoZSBxdWVyaWRvIHBsYXNtYXIgZXN0YSBwYXNpw7NuIGVuIGVsIHRyYWJham8gaW5kaXZpZHVhbCwgY3JlbyBxdWUgZWwgY29ub2NlciBtdWNobyBkZWwgbXVuZGlsbG8gbWUgYXl1ZGFyYSBwb3IgdW5hIHBhcnRlIGEgZW50ZW5kZXIgbWVqb3IgbGEgaW5mb3JtYWNpw7NuIG9idGVuaWRhIGFzw60gY29tbyBleHByZXNhcmxhLCB5IHBvciBvdHJhIHBhcnRlIG1lIHJlc3VsdGFyYSBtdWNobyBtw6FzIGFtZW5vIGEgbGEgaG9yYSBkZSBlc3RhciB0cmFiYWphbmRvLg0KDQojIyAzLiBEYXRvcyB1dGlsaXphZG9zey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KDQojIyMgQ29tZW50YXJpb3MNCg0KUGFyYSBsYSByZWFsaXphY2nDs24gZGVsIHRyYWJham8gaGUgdXRpbGl6YWRvIGxvcyBkYXRhZnJhbWVzIHF1ZSBzZSB1dGlsaXphcm9uIGVuIGVsIHRpZHl0dWVzZGF5IGRlbCAyMDIwLTA0LTA3IGRlZGljYWRvIGFsIFRvdXIgZGUgRnJhbmNpYSwgZWwgb3JpZ2VuIGRlIGxvcyBkYXRvcyBwcm92aWVuZSBkZWwgdXN1YXJpbyAqKmFsYXN0YWlycnVzaHdvcnRoKiogeSBjb25zdGEgZGUgMyBkYXRhZnJhbWVzIHF1ZSBjb250aWVuZW4gaW5mb3JtYWNpw7NuIGRlc2RlIGxvcyBnYW5hZG9yZXMgZGVsIHRvdXIsIGRlIGV0YXBhcywgZWRhZGVzLCBuYWNpb25hbGlkYWRlcywgcGVzb3MsIGVkYWQsIGV0Yy4gTGEgdmVyZGFkIHF1ZSBsb3MgZGF0b3MgZXN0w6FuIG11eSBiaWVuIGN1aWRhZG9zIHkgcmVmaW5hZG9zLCBhZGVtw6FzIGFsIHRyYXRhcnNlIGRlIHVuIGV2ZW50byBkZWwgdGlkeXR1ZXNkYXkgbWUgaGUgcG9kaWRvIGF5dWRhciBlIGluc3BpcmFyIGVuIGFsZ3VuYXMgZGUgbGFzIGdyw6FmaWNhcyByZWFsaXphZGFzIHBvciBnZW5pb3MgY29tbzogQW5kcsOpIFdhYWdlLCBBcmlhbmUgQXVtYWl0cmUsIEpha2UgTGF3bG9yLCBlbnRyZSBvdHJvcy4gDQoNCjxicj4NCg0KTWVuY2lvbmFyIHF1ZSBlbiBsYSBtYXlvcsOtYSBkZSBvYnNlcnZhY2lvbmVzIHNvbG8gc2UgdGllbmVuIGRhdG9zIGhhc3RhIDIwMTcsIGVzdMOhIGJhc3RhbnRlIGFjdHVhbGl6YWRhLCBwZXJvIGVzdGFtb3MgZW4gMjAyMSBwb3IgbG8gdGFudG8gYSBsbyBsYXJnbyBkZWwgdHJhYmFqbyByZWFsaXphcmUgYWxnw7puIGluY2lzbyBjb24gdGFsIGRlIGFjdHVhbGl6YXIgbGEgaW5mb3JtYWNpw7NuLCBwZXJvIGVuIGzDrW5lYXMgZ2VuZXJhbGVzIHRvZGEgbGEgaW5mb3JtYWNpw7NuIGVzIGhhc3RhIGVsIDIwMTcuDQpQb3Igw7psdGltbywgbGEgZ3JhbiBtYXlvcsOtYSBjb25vY2Vtb3MgZWwgY2FzbyBkZSBkb3BhamUgZGUgTGFuY2UgQXJtc3Ryb25nIGVzIHBvciBlc28gcXVlIGhlIGNvbnNpZGVyYWRvIG9wb3J0dW5vIGVsaW1pbmFyIHN1IG5vbWJyZSBlbiBhcXVlbGxhcyBncmFmaWNhcyBkZSB0w610dWxvcyBpbmRpdmlkdWFsZXMuDQoNCg0KDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCjxicj4NCg0KIyMjIERhdG9zDQoNCmBgYHtyIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRSB9DQoNCiMgRXN0YSBsaW5lYXMgZGUgY29kaWdvIGhhbiBzaWRvIG5lY2Vzc2FyaWFzIHBhcmEgcG9kZXIgZGVzY2FyZ2FyIGxvcyBkYXRhZnJhbWUsIHVuYSB2ZXogY2FyZ2Fkb3MgaGFuIHNpZG8gZXhwb3J0YWRvcyBhIHVuIGZpY2hlcm8gY3N2IHBvciBsbyB0YW50byBlc3RhcyBsaW5lYXMgZXN0YW4gY29tZW50YWRhcyBwb3JxdWUgbm8gZXMgbmVjZXNhcmlvIGVqZWN1dGFybGFzIGNhZGEgdmV6Lg0KDQojdGRmX3dpbm5lcnMgPC0gcmVhZHI6OnJlYWRfY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L21hc3Rlci9kYXRhLzIwMjAvMjAyMC0wNC0wNy90ZGZfd2lubmVycy5jc3YnKQ0KDQojIEluc3RhbGwgdmlhIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigidGhlYmlvZW5naW5lZXIvdGlkeXR1ZXNkYXlSIikNCg0KI3R1ZXNkYXRhIDwtIHRpZHl0dWVzZGF5Ujo6dHRfbG9hZCgnMjAyMC0wNC0wNycpDQojdHVlc2RhdGEgPC0gdGlkeXR1ZXNkYXlSOjp0dF9sb2FkKDIwMjAsIHdlZWsgPSAxNSkNCg0KDQojdGRmX3dpbm5lcnMgPC0gdHVlc2RhdGEkdGRmX3dpbm5lcnMNCiNzdGFnZV9kYXRhIDwtIHR1ZXNkYXRhJHN0YWdlX2RhdGENCiN0ZGZfc3RhZ2VzIDwtIHR1ZXNkYXRhJHRkZl9zdGFnZXMNCg0KI3N0cih0ZGZfd2lubmVycykNCiNzdHIoc3RhZ2VfZGF0YSkNCiNzdHIodGRmX3N0YWdlcykNCg0KI3RkZl93aW5uZXJzICU+JSANCiAgI3dyaXRlX2NzdihoZXJlOjpoZXJlKCJkYXRvcyIsICJ0ZGZfd2lubmVycy5jc3YiKSkNCg0KI3N0YWdlX2RhdGEgJT4lIA0KICAjd3JpdGVfY3N2KGhlcmU6OmhlcmUoImRhdG9zIiwgInN0YWdlX2RhdGEuY3N2IikpDQoNCiN0ZGZfc3RhZ2VzICU+JSANCiAgI3dyaXRlX2NzdihoZXJlOjpoZXJlKCJkYXRvcyIsInRkZl9zdGFnZXMuY3N2IikpDQoNCg0Kc3RhZ2VfZGF0YSA8LSByZWFkX2NzdigiZGF0b3Mvc3RhZ2VfZGF0YS5jc3YiKQ0KdGRmX3dpbm5lcnMgPC0gcmVhZF9jc3YoImRhdG9zL3RkZl93aW5uZXJzLmNzdiIpDQp0ZGZfc3RhZ2VzIDwtIHJlYWRfZXhjZWwoImRhdG9zL3RkZl9zdGFnZXMueGxzeCIpDQoNCmBgYA0KDQojIyMgUGFxdWV0ZXMNCg0KDQotIGxpYnJhcnkocmVhZHIpDQotIGxpYnJhcnkocmVhZHhsKQ0KLSBsaWJyYXJ5KHRpZHl2ZXJzZSkNCi0gbGlicmFyeShnZ3Bsb3QyKQ0KLSBsaWJyYXJ5KGx1YnJpZGF0ZSkNCi0gbGlicmFyeShnZ2ZvcmNlKQ0KLSBsaWJyYXJ5KHJpbykNCi0gbGlicmFyeShnZ3JlcGVsKQ0KLSBsaWJyYXJ5KGd0KQ0KLSBsaWJyYXJ5KHBuZykNCi0gbGlicmFyeShncmlkKQ0KLSBsaWJyYXJ5KGNvdW50cnljb2RlKQ0KLSBsaWJyYXJ5KGdnZmxhZ3MpDQotIGxpYnJhcnkoaHJicnRoZW1lcykNCi0gbGlicmFyeShEVCkNCg0KDQoNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KPGJyPg0KDQoNCg0KIyMgNC4gREVTQVJST0xMTyBERUwgVE9VUg0KDQpFbiBlc3RlIHByaW1lciBhcGFydGFkbyBsYSBpZGVhIGVzIGFuYWxpemFyIGPDs21vIGhhIGlkbyBkZXNhcnJvbGzDoW5kb3NlIGxhIGNhcnJlcmEsIGRlc2RlIGFxdWVsbG9zIGRlc2Nvbm9jaWRvcyBow6lyb2VzIHF1ZSBkZWNpZGlyw61hbiBjcnV6YXIgYXF1ZWxsb3MgcHVlcnRvcyBkZSBsb3MgQWxwZXMsIGVuY2ltYSBkZSBzdSBiaWNpY2xldGEsIGxhIG1heW9yw61hIHNpbiBhc2ZhbHRhciwgcHLDoWN0aWNhbWVudGUgZXJhbiBjYXJyZXRlcmFzIGRlIGJhcnJvLCBoYXN0YSBsYSDDqXBvY2EgZGVsIGNpY2xpc21vIGRlIMOpcGljYSBjb24gQmFydGFsaSB5IENvcHBpLCBwYXNhbmRvIHBvciBsYSBkw6ljYWRhIGRlIGxvcyA3MCBjb24gbGEgZ3JhbiBkb21pbmFjacOzbiBkZWwgY2Fuw61iYWwgRWRkeSBNZXJja3gsIGxvcyBub3ZlbnRhIGNvbW8gcmVmZXJlbnRlIEluZHVyw6FpbiwgaGFzdGEgbGEgYWN0dWFsaWRhZC4NCkxvcyByZXN1bHRhZG9zIG9idGVuaWRvcyBhIHRyYXbDqXMgZGUgbGEgZ3JhZmljYXMgYXJyb2phbiB1bmEgKip0ZW5kZW5jaWEqKiBjbGFyYTogTGEgY2FycmVyYSBjYWRhIHZleiBzZSBoYSAqKnByb2Zlc2lvbmFsaXphZG8qKiBlICoqaW50ZXJuYWNpb25hbGl6YWRvKiogbcOhcy4NCg0KVmFtb3MgYSBjb21lbnRhciBsYXMgZ3LDoWZpY2FzIGFwYXJ0YWRvIHBvciBhcGFydGFkby4NCg0KDQoNCiMjIyA0LjEuIENhZGEgdmV6IG3DoXMgcsOhcGlkbw0KDQojIyMjIDQuMS4xLiBFdm9sdWNpw7NuIGRlIGxhIHZlbG9jaWRhZCBtZWRpYQ0KDQpgYGB7cn0NCg0KI0dyYWZpY2EgcDEgdmVsb2NpZGFkIG1lZGlhDQoNCnZlbG9jaWRhZF9tZWRpYSA8LSB0ZGZfd2lubmVycyANCg0KdmVsb2NpZGFkX21lZGlhIDwtIHRkZl93aW5uZXJzICU+JQ0KICBtdXRhdGUoeWVhcj0geWVhcihzdGFydF9kYXRlKSkgJT4lDQogIG11dGF0ZSh2ZWxvY2lkYWQgPSBkaXN0YW5jZSAvIHRpbWVfb3ZlcmFsbCkNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCnAxIDwtIGdncGxvdCh2ZWxvY2lkYWRfbWVkaWEsIGFlcyh5ZWFyLCB2ZWxvY2lkYWQpKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAgImJsYWNrIikgKw0KICBnZW9tX3Ntb290aChzcGFuID0gMC4yLCBjb2xvciA9ICJibGFjayIgLCBmaWxsPSAiI2VkZTY1NyIpICsgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAid2hpdGUiKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpICtsYWJzKHggPSBOVUxMLCB5ID0gInZlbG9jaWRhZCBlbiBLbS9IIikgKw0KICBnZW9tX2xhYmVsX3JlcGVsKGRhdGEgPSB2ZWxvY2lkYWRfbWVkaWEgJT4lIHNhbXBsZV9uKDIwKSwgDQogICAgICAgICAgICAgICAgICAgYWVzKGxhYmVsID0gd2lubmVyX25hbWUpLCBzaXplID0gMi4zLCAgDQogICAgICAgICAgICAgICAgICAgbnVkZ2VfeSA9IC05LCBuYS5ybSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgc2VnbWVudC5hbHBoYSA9IDAuMikNCiANCnAxDQpgYGANCg0KPGJyPg0KDQpDb21vIHBvZGVtb3Mgb2JzZXJ2YXIgbGEgdGVuZGVuY2lhIGVzIG11eSBjbGFyYSBsYSB2ZWxvY2lkYWQgbWVkaWEgaGEgaWRvICoqYXVtZW50YWRvKiogY29tbyBub3JtYSBnZW5lcmFsIGVkaWNpw7NuIHRyYXMgZWRpY2nDs24sIGVzdG8gZXMgZGViaWRvIGVuIHBhcnRlIGEgMyBmYWN0b3JlczoNCg0KDQotIE1lam9yYXMgZGUgbG9zIGNvbXBvbmVudGVzLg0KLSBNZWpvciBlc3RhZG8gZGUgbGFzIGNhcnJldGVyYXMuDQotIFByb2Zlc2lvbmFsaXphY2nDs24gZGUgbGEgY2FycmVyYS4NCg0KDQpBIGRlc3RhY2FyIGVsIHBlcmlvZG8gZW50cmUgbG9zIGZpbmFsZXMgZGUgbG9zIDkwIHkgbGEgZW50cmFkYSBkZWwgbnVldm8gc2lnbG8sIGRvbmRlIGxhIGNhcnJlcmEgc2UgdmlvIG1hbmNoYWRhIHBvciBudW1lcm9zb3MgKiplc2PDoW5kYWxvcyBkZSBkb3BwaW5nKiosIGVzdG8gZXhwbGljYXLDrWEgZXNlIGZ1ZXJ0ZSBhdW1lbnRvIGRlIGxhIHZlbG9jaWRhZCBtZWRpYSB5IHN1IHBvc3RlcmlvciBjYcOtZGEgdW5hIHZleiBlcnJhZGljYWRvIGVsIHByb2JsZW1hLg0KDQoNCjxicj4NCg0KIyMjIDQuMi4gUmVjb3JyaWRvcyBjYWRhIHZleiBtw6FzIGNvcnRvcw0KDQojIyMjIDQuMi4xLiBFdm9sdWNpw7NuIGRlIGxhcyBkaXN0YW5jaWFzDQoNCmBgYHtyfQ0KDQojR3JhZmljYSBwMyBldm9sdWNpb24gZGlzdGFuY2lhcw0KDQpkaXN0YW5jaWFfZWRpY2lvbmVzIDwtIHRkZl93aW5uZXJzICU+JQ0KICB0aWR5cjo6ZHJvcF9uYShkaXN0YW5jZSkgJT4lDQogIG11dGF0ZSh5ZWFyPSB5ZWFyKHN0YXJ0X2RhdGUpKQ0KDQoNCnAzIDwtIGdncGxvdChkaXN0YW5jaWFfZWRpY2lvbmVzLCBhZXMoeWVhciwgZGlzdGFuY2UpKSArDQogIA0KICBnZW9tX2xpbmUoY29sb3I9IiNlZGU2NTciKSArDQogIGdlb21fYXJlYSggZmlsbD0iI2VkZTY1NyIpICsNCiAgZ2VvbV9zbW9vdGgoc3BhbiA9IDAuMiwgY29sb3IgPSAiI2VkZTY1NyIsIGFscGhhID0gMC4yKSArDQogIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoIA0KICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCA2MDAwLCAxMDAwKSwNCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsNjAwMCkpICsNCiAgDQogIGFubm90YXRlKA0KICBnZW9tID0gImN1cnZlIiwgeCA9IDE5MjYsIHkgPSA1ODAwLCB4ZW5kID0gMTk0NSwgeWVuZCA9IDYwMDAsIGN1cnZhdHVyZSA9IC4zLCBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMiwgIm1tIikpKSArDQogIA0KICBhbm5vdGF0ZShnZW9tID0gInRleHQiLCB4ID0gMTk0NiwgeSA9IDYwMDAsIGxhYmVsID0gIkVuIDE5MjYgZnVlIGxhIGVkaWNpw7NuIG1hcyBsYXJnYSBjb24gdW4gdG90YWwgZGUgNTc0NSBrbSIsIGhqdXN0ID0gImxlZnQiKSArIA0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpICsgDQogIGxhYnMoeCA9IE5VTEwsIHkgPSAiRGlzdGFuY2lhIGVuIGttIikNCiAgDQoNCnAzICAgDQpgYGANCg0KPGJyPg0KDQpEZSBhcXVlbGxvcyByZWNvcnJpZG9zIGRlIGluZmFydG8gZGUgZXRhcGFzIHF1ZSBkdXJhYmFuIGTDrWFzIGVudGVyb3Mgc2UgaGEgaWRvIHJlY29ydGFuZG8gZWwgcmVjb3JyaWRvIGRlIGNhZGEgZXRhcGEgeSBjb24gZWxsbyBlbCBraWxvbWV0cmFqZSB0b3RhbCBkZSBjYWRhIGVkaWNpw7NuIGNvbW8gbXVlc3RyYSBsYSB0ZW5kZW5jaWEsIGhhc3RhIGxhIGFjdHVhbGlkYWQgZG9uZGUgcGFyZWNlIHF1ZSBsYSB0ZW5kZW5jaWEgc2UgaGEgZXN0YWJpbGl6YWRvIGNvbiBsb3MgcmVjb3JyaWRvcyBhY3R1YWxlcyBtw6FzIGNvcnRvcyB5IGV4cGxvc2l2b3MuDQoNCjxicj4NCg0KRWwgYcOxbyAxOTI2IGZ1ZSBsYSBlZGljacOzbiBtw6FzIGxhcmdhIGRlIHRvZGFzIGNvbiB1biB0b3RhbCBkZSA1NzQ1IGttLCBhcXVlbGxhIGVkaWNpw7NuIHNlIGRpdmlkacOzIGVuIDE1IGV0YXBhcyBsbyBxdWUgbm9zIGRhIHVuYSBtZWRpYSBkZSAzODMga20sIG1lIHRpZW1ibGFuIGxhcyBwaWVybmFzIHNvbG8gZGUgcGVuc2FyIGVuIGhhY2VyIGVzYSBjYW50aWRhZCBkZSBraWzDs21ldHJvcyBkdXJhbnRlIDE1IGTDrWFzIHNlZ3VpZG9zLg0KDQoNCjxicj4NCg0KIyMjIDQuMy4gRXN0YWJsZWNpbWllbnRvIGRlIGxhcyAyMSBFdGFwYXN7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQojIyMjIFRpcG9zIGRlIGV0YXBhDQoNCiMjIyMjIDQuMy4xLiBFdm9sdWNpw7NuIGRlbCBudW1lcm8geSB0aXBvcyBkZSBldGFwYS4NCg0KDQpgYGB7cn0NCg0KDQojR3JhZmljYSBwNCBUaXBvcyBkZSBldGFwYQ0KDQp0aXBvc19ldGFwYSA8LSB0ZGZfc3RhZ2VzICU+JQ0KICBtdXRhdGUoeWVhcj0geWVhcihEYXRlKSkgJT4lDQogIGdyb3VwX2J5KFR5cGUseWVhcikgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF9jYXRlZ29yaWE9bigpKQ0KDQogIA0KcDQgPC0gZ2dwbG90KHRpcG9zX2V0YXBhLCBhZXMoeWVhciwgdG90YWxfY2F0ZWdvcmlhLCBmaWxsID0gVHlwZSkpICsNCiAgZ2VvbV9jb2woKSArIA0KICBjb29yZF9mbGlwKCkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpICsNCiAgbGFicyh4ID0gTlVMTCkgKyB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpICtsYWJzKHkgPSAiTnVtZXJvIGRlIGV0YXBhcyIsIGZpbGwgPSAiVGlwbyBkZSBFdGFwYSIpDQogIA0KcDQgDQpgYGANCg0KDQo8YnI+DQoNCkNvbW8gaGVtb3MgbWVuY2lvbmFkbyBhbCBwcmluY2lwaW8gZW4gbGEgaW50cm9kdWNjacOzbiBlbCBuw7ptZXJvIGRlIGV0YXBhcyBlbiBsYXMgcXVlIHNlIGRpdmlkZSBsYSBjb21wZXRpY2nDs24gZXMgZW4gMjEsIHBlcm8gY29tbyB2ZW1vcyBlbiBlbCBncmFmaWNvIG5vIHNpZW1wcmUgaGEgc2lkbyBhc8OtLCBwb2RlbW9zIGRpZmVyZW5jaWFyIDMgZXRhcGFzOiBpbmljaW9zIGhhc3RhIGxvcyBhw7FvcyA1MCwgZGUgbG9zIDUwIGxvcyBoYXN0YSBsb3MgOTAgeSBkZSBsb3MgOTAgYSBsYSBhY3R1YWxpZGFkLg0KDQo8YnI+DQoNCkxhIHByaW1lcmEgZXRhcGEgc2UgY2FyYWN0ZXJpemEgcG9yIHVuYSBwcmltZXJhIGZhc2UgY29uIG11eSBwb2NhcyBldGFwYXMgeSB1bmEgc2VndW5kYSBmYXNlIGNvbiB1biBpbmNyZW1lbnRvIGNvbnNpZGVyYWJsZSwgYWRlbcOhcyBlc3RhIGV0YXBhIHNlIGNhcmFjdGVyaXphIHBvciBsb3Mgc3VzcGVuc2lvbmVzIGRlbCB0b3VyIGR1cmFudGUgbGFzIGRvcyBndWVycmFzIG11bmRpYWwgZGUgYWjDrSBsb3MgZXNwYWNpb3MgZW4gYmxhbmNvLkxhIHNlZ3VuZGEgcGFyZWNlIHVuIHBvY28gY2HDs3RpY2EgY2FkYSBlZGljacOzbiB0ZW7DrWEgdW4gbnVtZXJvIGRpc3RpbnRvIGRlIGV0YXBhcyB5IG5vIHNlcsOhIGhhc3RhIGxsZWdhciBhIGxvcyA5MCBkb25kZSBzZSBvZmljaWFsaWNlIHkgYWN1ZXJkZSBsYXMgMjEgZXRhcGFzIHBvciBlZGljacOzbiwgdW5hIHZleiBtw6FzIHJlYWZpcm1hZG8gbGEgdGVuZGVuY2lhIGRlIGxhIHByb2Zlc2lvbmFsaXphY2nDs24uDQoNCg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQo8YnI+DQoNCiMjIyMgVGFibGEgDQoNCmBgYHtyfQ0KDQojdGFibGEgZXRhcGFzDQoNCmV0YXBhc19lc3Bhbm9sIDwtIHRkZl9zdGFnZXMgJT4lDQogIHJlbmFtZShldGFwYSA9ICJTdGFnZSIgLA0KICAgICAgICAgZmVjaGEgPSAiRGF0ZSIgLA0KICAgICAgICAgZGlzdGFuY2lhID0gIkRpc3RhbmNlIiAsDQogICAgICAgICBvcmlnZW4gPSAiT3JpZ2luIiAsDQogICAgICAgICBmaW5hbCA9ICJEZXN0aW5hdGlvbiIgLA0KICAgICAgICAgdGlwbyA9ICJUeXBlIiAsDQogICAgICAgICBnYW5hZG9yID0gIldpbm5lciIgLA0KICAgICAgICAgbmFjaW9uYWxpZGFkID0gIldpbm5lcl9Db3VudHJ5IiAsKSAlPiUNCiAgc2VsZWN0KGV0YXBhLCBmZWNoYSwgZGlzdGFuY2lhLCBvcmlnZW4sIGZpbmFsLCB0aXBvLCBnYW5hZG9yLCBuYWNpb25hbGlkYWQpDQoNCmRhdGF0YWJsZShldGFwYXNfZXNwYW5vbCwgY2xhc3MgPSJzdHJpcGUgaG92ZXIgY29tcGFjdCByb3ctYm9yZGVyIiAsIGZpbHRlciA9ICd0b3AnKQ0KDQpgYGANCg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQo8YnI+DQoNCiMjIyA0LjMuIEhhY2lhIGxhIGludGVybmFsaXphY2nDs24gZGVsIFRvdXINCg0KIyMjIyA0LjMuMS4gTmFjaW9uYWxpZGFkZXMgZGlzdGludGFzIGVuIGdhbmFyIHVuYSBldGFwYSBwb3IgZWRpY2nDs24NCg0KYGBge3J9DQoNCg0KI0dyYWZpY2EgcDUgbmFjaW9uYWxpZGFkZXMgZW4gZ2FuYXIgZXRhcGEgcG9yIGVkaWNpb24NCg0KbmFjaW9uYWxpZGFkZXMgPC0gdGRmX3N0YWdlcyAlPiUNCiAgbXV0YXRlKHllYXIgPSB5ZWFyKERhdGUpKSAlPiUNCiAgZ3JvdXBfYnkoeWVhciwgV2lubmVyX0NvdW50cnkpICU+JQ0KICBzdW1tYXJpc2UodG90YWw9IG5fZGlzdGluY3QoV2lubmVyX0NvdW50cnkpKSAlPiUNCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF9uYWNpb25hbGlkYWRlcz0gbigpKSANCiAgDQoNCg0KcDUgPC0gZ2dwbG90KG5hY2lvbmFsaWRhZGVzLCBhZXMoeWVhciwgdG90YWxfbmFjaW9uYWxpZGFkZXMpKSArDQogIGdlb21fY29sKGFlcyhmaWxsPXRvdGFsX25hY2lvbmFsaWRhZGVzKSkgKw0KICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93PSIjOWU5ZTllIixoaWdoPSIjMjgyODI4IikgKyANCiAgZ2VvbV9zbW9vdGgoY29sb3IgPSAiI2VkZTY1NyIsIGFscGhhID0gMC4zKSArDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBicmVha3MgPSBzZXEoMCwgMTUsIDUpLA0KICAgIGxpbWl0cyA9IGMoMCwgMTUpKSArDQogIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgeG1pbiA9IDE5MDAsDQogICAgICAgICAgIHhtYXggPSAxOTUwLA0KICAgICAgICAgICB5bWluID0gMCwNCiAgICAgICAgICAgeW1heCA9IEluZiwNCiAgICAgICAgICAgYWxwaGEgPSAwLjMsDQogICAgICAgICAgIGZpbGwgPSAicGluayIpICsNCiAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICB4bWluID0gMTk1MCwNCiAgICAgICAgICAgeG1heCA9IDE5ODUsDQogICAgICAgICAgIHltaW4gPSAwLA0KICAgICAgICAgICB5bWF4ID0gSW5mLA0KICAgICAgICAgICBhbHBoYSA9IDAuMywNCiAgICAgICAgICAgZmlsbCA9ICIjYjJlYmYyIikgKw0KICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgIHhtaW4gPSAxOTg1LA0KICAgICAgICAgICB4bWF4ID0gMjAxOCwNCiAgICAgICAgICAgeW1pbiA9IDAsDQogICAgICAgICAgIHltYXggPSBJbmYsDQogICAgICAgICAgIGFscGhhID0gMC4zLA0KICAgICAgICAgICBmaWxsID0gIiNhNWQ2YTciKSArDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAiYmxhbmsiKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3VyID0gIndoaXRlIiksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIGZpbGwgPSBOVUxMKSsNCiAgdGhlbWUoYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZShsaW5ldHlwZSA9ICJzb2xpZCIpLA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIpKQ0KDQpwNQ0KDQoNCg0KYGBgDQo8YnI+DQoNCkVuIGVzdGEgZ3JhZmljYSBwb2RlbW9zIG9ic2VydmFyIGN1YW50YXMgbmFjaW9uYWxpZGFkZXMgZGlzdGludGFzIGZ1ZXJvbiBjYXBhY2VzIGRlIGdhbmFyIHVuYSBvIG3DoXMgZXRhcGFzIGVuIGNhZGEgZWRpY2nDs24sIHVuYSB2ZXogbcOhcyBsYSB0ZW5kZW5jaWEgZXMgbXV5IGNsYXJhLCBlbCB0b3VyIHNlIGhhIGlkbyBpbnRlcm5hbGl6YW5kbywgaGEgcGFzYWRvIGRlIHNlciB1bmEgY2FycmVyYSByZXNlcnZhZGEgcGFyYSBmcmFuY2VzZXMsIGJlbGdhcywgaXRhbGlhbm9zIGhhc3RhIGxvcyBhw7FvcyA1MCwgYSBkYXIgcGFzYXIgYSB1bmEgY29tcGV0aWNpw7NuIG3DoXMgaW50ZXJuYWNpb25hbCBwcmltZXJvIGNvbiBmdWVydGUgZG9taW5pbyBldXJvcGVvIHBhcmEgZW4gbG9zIDgwIHkgOTAgYWJyaXIgc3VzIHB1ZXJ0YXMgYSB0b2RvIGVsIG11bmRvLiBVbmEgdmV6IG3DoXMgbGFzIDMgZXRhcGFzIG1lbmNpb25hZGEgYW50ZXJpb3JtZW50ZSBzZSB2ZW4gcmVmbGVqYWRhcyBjbGFyYW1lbnRlIGVuIGVsIGdyw6FmaWNvLiANCg0KPGJyPg0KDQoNCiMjIyA0LjUuIE1heW9yIHJpdmFsaWRhZCBlbnRyZSBjaWNsaXN0YXMNCg0KIyMjIyA0LjUuMS4gVmVudGFqYSBkZWwgZ2FuYWRvciByZXNwZWN0byBkZWwgc3ViY2FtcGXDs24NCg0KDQpgYGB7cn0NCg0KDQojR3JhZmljYSBwMiBEaWZlcmVuY2lhIGVudHJlIGVsIGdhbmFkb3IgeSBzdWJjYW1wZW9uDQoNCnRpZW1wb192ZW5jZWRvciA8LSB0ZGZfd2lubmVycyAlPiUNCiAgdGlkeXI6OmRyb3BfbmEodGltZV9tYXJnaW4pICU+JQ0KICBtdXRhdGUoeWVhcj0geWVhcihzdGFydF9kYXRlKSkNCg0KICANCnAyIDwtICBnZ3Bsb3QodGllbXBvX3ZlbmNlZG9yLCBhZXMoeD15ZWFyLHk9dGltZV9tYXJnaW4pKSArDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBnZW9tX3Ntb290aCggZm9ybXVsYSA9IHl+eCxtZXRob2Q9ImxvZXNzIiwNCiAgICAgICAgICAgICAgICAgY29sb3I9ImdyZXkzMCIsZmlsbD0iI2VkZTY1NyIpICArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoMCwwLjE2LDEsMiwzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygwLCIxMCBNaW4iLCIxIEhyIiwiMiBIcnMiLCIzIEhycyIpLA0KICAgICAgICAgICAgICAgICAgICAgICBuYW1lPSJWZW50ZWphIGRlbCBnYW5hZG9yIikrDQogICAgc2NhbGVfeF9jb250aW51b3VzKG5hbWU9TlVMTCkgKw0KICAgIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoLS4xLDMuMSksDQogICAgICAgICAgICAgICAgICAgIHhsaW09YygxODk5LDIwMjApLGV4cGFuZD1GKSArIA0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpDQoNCnAyDQoNCmBgYA0KPGJyPg0KDQpDb21vIGNvbnNlY3VlbmNpYSBkZSBsb3MgZG9zIGZlbsOzbWVub3MgbWVuY2lvbmFkb3MgYW50ZXJpb3JtZW50ZSBsYSBwcm9mZXNpb25hbGl6YWNpw7NuIGUgaW50ZXJuYWxpemFjacOzbiwgbGEgdmVudGFqYSBlbnRyZSBlbCBnYW5hZG9yIGRlIGxhIGNsYXNpZmljYWNpw7NuIGdlbmVyYWwgeSBlbCBzdWJjYW1wZcOzbiBzZSBoYSBpZG8gcmVkdWNpZW5kbyBmdWVydGVtZW50ZSBoYXN0YSBsbGVnYXIgYSBsb3MgdGllbXBvcyBkZWwgY2ljbGlzbW8gYWN0dWFsIGRvbmRlIGVsIHZlbmNlZG9yIG5vIHN1ZWxlIHNhY2FyIG3DoXMgZGUgMyBvIDQgbWludXRvcyBhbCBzZWd1bmRvIGNsYXNpZmljYWQsIGNvbW8gcG9kZW1vcyBvYnNlcnZhciBlbiBsYSBncsOhZmljYS4gDQoNCjxicj4NCg0KDQoNCiMjIDUuIExPUyBDSUNMSVNUQVMNCg0KTGxlZ2Fkb3MgYSBlc3RlIHB1bnRvIHkgdW5hIHZleiBhbmFsaXphZG8gZWwgZGVzYXJyb2xsbyBoaXN0w7NyaWNvIGRlbCBUb3VyIHZhbW9zIGEgZW5zZcOxYXIgcXVpZW5lcyBoYW4gc2lkbyB5IHNvbiBsb3MgbWVqb3JlcyBjaWNsaXN0YXMgcXVlIGhhbiBwYXNhZG8gcG9yIGxhcyBjYXJyZXRlcmFzIGRlIEZyYW5jaWEsIGRlc2RlIGxvcyBxdWUgbcOhcyBjbGFzaWZpY2FjaW9uZXMgZ2VuZXJhbGVzIGhhbiBnYW5hZG8gaGFzdGEgbG9zIHF1ZSBtw6FzIGV0YXBhcyBzZSBoYW4gbGxldmFkbyB5IHRhbWJpw6luIGFsZ3Vub3MgZGF0b3MgY3VyaW9zb3MgY29tbyBuYWNpb25hbGlkYWRlcywgZWRhZGVzLCBldGMuDQoNCjxicj4NCg0KIyMjIDUuMS4gQ2ljbGlzdGFzIG3DoXMgbGF1cmVhZG9zDQoNCmBgYHtyfQ0KI1RhYmxhIDEgY29ycmVkb3JlcyBtYXMgbGF1cmVhZG9zDQojUmVhbG1lbnRlIGVzdGEgdGFibGEgbm8gdGllbmUgbXVjaG8gbWVyaXRvIHBvcnF1ZSBoYSBzaWRvIHJlcHJvZHVjaXIgbGl0ZXJhbG1lbnRlIGVsIGNvZGlnbyBkZSB1biB1c3VhcmlvIHBvciBpbnRlcm5ldCBwZXJvIG1lIGhhIHBhcmVjaWRvIHRhbiBib25pdGEgeSBlbGVnYW50ZSBxdWUgbWUgaGUgdmlzdG8gY2FzaSBmb3J6YWRvIGEgcG9uZXJsYS4uLg0KDQptb3N0X3dpbnM8LXRkZl93aW5uZXJzJT4lDQogICMgTG8gcHJpbWVybyBlcyBib3JyYXIgYSBBcm1zdHJvbmcgcG9yIHRyYW1wb3NvDQogIGZpbHRlcih3aW5uZXJfbmFtZSE9IkxhbmNlIEFybXN0cm9uZyIpJT4lDQogIG11dGF0ZSh3aW5uZXJfbmFtZT1jYXNlX3doZW4oDQogICAgd2lubmVyX25hbWU9PSdNaWd1ZWwgSW5kdXLDoWluJ34nTWlndWVsIEluZHVyYWluJywNCiAgICBUUlVFfndpbm5lcl9uYW1lDQogICkpJT4lDQogICMgQ3JlYXIgbGEgdmFyaWFibGUgcGFyYSBjb250YXIgdGl0dWxvcw0KICBtdXRhdGUoY3Q9MSklPiUNCiAgZ3JvdXBfYnkod2lubmVyX25hbWUpJT4lDQogIHN1bW1hcml6ZSgNCiAgICAjIENvbnRhbW9zIFRpdHVsb3MNCiAgICBUaXR1bG9zPXN1bShjdCksDQogICAgIyBBw7FhZGltb3MgbmFjaW9uYWxpZGFkDQogICAgTmFjaW9uYWxpZGFkPW5hdGlvbmFsaXR5WzFdLA0KICAgICMgQcOxYWRpbW9zIGVsIGFwb2RvDQogICAgTmlja25hbWU9bmlja25hbWVbMV0pJT4lDQogIGZpbHRlcihUaXR1bG9zPjIpJT4lDQogIGFycmFuZ2UoLVRpdHVsb3MpDQoNCiMgRGF0YSBwcmVwYXJhdGlvbjoNCm1vc3Rfd2luczwtbW9zdF93aW5zJT4lDQogICMgIG9yZGVuYW5kbyBsYXMgY29sdW1uYQ0KICBzZWxlY3QoDQogICAgQ29ycmVkb3I9d2lubmVyX25hbWUsDQogICAgTmlja25hbWUsTmFjaW9uYWxpZGFkLFRpdHVsb3MpJT4lDQogICMgTGltcGlhbmRvIGxvcyBhcG9kb3MNCiAgbXV0YXRlKE5pY2tuYW1lPWNhc2Vfd2hlbigNCiAgICBzdHJfZGV0ZWN0KENvcnJlZG9yLCdIaW5hdWx0Jyl+J1RoZSBCYWRnZXInLA0KICAgIHN0cl9kZXRlY3QoQ29ycmVkb3IsJ0FucXVldGlsJyl+J01hw650cmUgSmFjcXVlcycsDQogICAgc3RyX2RldGVjdChDb3JyZWRvciwnSW5kdXJhaW4nKX4nTWlndWVsw7NuJywNCiAgICBzdHJfZGV0ZWN0KENvcnJlZG9yLCdMZU1vbmQnKX4iVGhlIEFtZXJpY2FuIiwNCiAgICBzdHJfZGV0ZWN0KENvcnJlZG9yLCdCb2JldCcpfidab256b24nLA0KICAgIHN0cl9kZXRlY3QoQ29ycmVkb3IsJ1RoeXMnKX4nVGhlIEJhc3NldCBIb3VuZCcsDQogICAgVFJVRX5OaWNrbmFtZQ0KICApKQ0KDQptb3N0X3dpbnMgPC0gbW9zdF93aW5zJT4lDQogIG11dGF0ZShOYWNpb25hbGlkYWQgPSBjYXNlX3doZW4oDQogICAgc3RyX2RldGVjdChOYWNpb25hbGlkYWQsJ0ZyYW5jZScpIH4gJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9Cam5Ob3dhay9UZEYvbWFpbi9mci5wbmcnLA0KICAgIHN0cl9kZXRlY3QoTmFjaW9uYWxpZGFkLCdCZWxnaXVtJykgfiAnaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0Jqbk5vd2FrL1RkRi9tYWluL2JlLnBuZycsDQogICAgc3RyX2RldGVjdChOYWNpb25hbGlkYWQsJ0dyZWF0IEJyaXRhaW4nKSB+ICdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQmpuTm93YWsvVGRGL21haW4vdWsucG5nJywNCiAgICBzdHJfZGV0ZWN0KE5hY2lvbmFsaWRhZCwnU3BhaW4nKSB+ICdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQmpuTm93YWsvVGRGL21haW4vc3AucG5nJywNCiAgICBzdHJfZGV0ZWN0KE5hY2lvbmFsaWRhZCwnVW5pdGVkIFN0YXRlcycpIH4gJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9Cam5Ob3dhay9UZEYvbWFpbi91cy5wbmcnDQogICkpDQoNCnRhYmxhIDwtIG1vc3Rfd2lucyU+JQ0KICBndCgpJT4lDQogIHRhYl9oZWFkZXIoDQogICAgdGl0bGUgPSAiQ29ycmVkb3JlcyBjb24gbcOhcyB2aWN0b3JpYXMgZW4gZWwgVG91ciBkZSBGcmFuY2lhIg0KICApJT4lDQogIGd0RXh0cmFzOjpndF90aGVtZV9ueXRpbWVzKCklPiUNCiAgZ3RFeHRyYXM6Omd0X21lcmdlX3N0YWNrKGNvbDEgPSBDb3JyZWRvciwgY29sMiA9IE5pY2tuYW1lKSU+JQ0KICAjIGHDsWFkaW1vcyBsYXMgYmFuZGVyYXMNCiAgZ3RFeHRyYXM6Omd0X2ltZ19yb3dzKGNvbHVtbnMgPSBOYWNpb25hbGlkYWQsIGhlaWdodCA9IDIwKQ0KDQp0YWJsYSU+JQ0KICBndEV4dHJhczo6Z3RfZmFfcmVwZWF0cygNCiAgICBjb2x1bW49VGl0dWxvcywNCiAgICBwYWxldHRlID0gIm9yYW5nZSIsDQogICAgbmFtZSA9ICJ0c2hpcnQiLA0KICAgIGFsaWduPSdsZWZ0Jw0KICApDQoNCmBgYA0KDQo8YnI+DQoNCkVzdGUg4oCcc2Fsw7NuIGRlIGxhIGZhbWHigJ0gcG9yIGRlY2lybG8gZGUgYWxndW5hIG1hbmVyYSBlc3TDoSByZXNlcnZhZG8gYSBtdXkgcG9jb3MsIGhhYmxhciBkZWwgdG91ciBlcyBoYWJsYXIgZGUgYXF1ZWxsYXMgZ3JhbmRlcyBjcm9ub3MgZGUgQmVybmFyZCBIaW5hdWx0LCBlcyBkZSBhcXVlbGxhcyB0YXJkZXMgZW4gZWwgc2Fsw7NuIGRpc2ZydXRhbmRvIGNvbiBJbmR1csOhaW4geSBzaW4gZHVkYSBkZSBhcXVlbGxhIGRvbWluYWNpw7NuIGltcGFyYWJsZSBkZSBFZGR5IE1lcmNreCBhbCBxdWUgc29sbyBlbCBkaWZ1bnRvIEx1aXMgT2Nhw7FhIHB1ZG8gcGxhbnRhcmxlIGNhcmEgYWwgY2Fuw61iYWwuDQpFbCB1bHRpbW8gZW4gZW50cmFyIGVuIGVzdGUgUmFua2luZyBlcyBGcm9vbWUgY29ycmVkb3IgcXVlIHNpZ3VlIGVuIGFjdGl2byB5IHF1acOpbiBzYWJlIHNpIHNlcsOhIGNhcGF6IGRlIGFsY2FuemFyIGxvcyA1IHRvdXJzLCBlbiBsYSBhY3R1YWxpZGFkIGVzdMOhIGNvbXBsaWNhZG8gcGVybyBsYSBlc3BlcmFuemEgZXMgbG8gw7psdGltbyBxdWUgc2UgcGllcmRlLg0KU2UgcHVlZGUgbGxlZ2FyIGEgcXVlZGFyIGNvcnRvIGVzdGUgcmFua2luZyBwb3JxdWUgbm8gYXBhcmVjZW4gbm9tYnJlcyBjb21vIGVsIGRlIEJhcnRhbGksIENvbnRhZG9yLCBQZXJpY28sIFBvdWxpZG9yLCBlbnRyZSBvdHJvcywgcGVybyBlcyBxdWUgZWwgbml2ZWwgb2ZyZWNpZG8gcG9yIGVzdG9zIDggY2ljbGlzdGFzIGhhIHNpZG8gbXV5IGFsdG8uDQoNCg0KPGJyPg0KDQojIyMjIDUuMS4xLiBDb25zdWx0YSBxdWllbiBnYW5vIGNhZGEgZWRpY2nDs24gZGVsIFRvdXINCg0KYGBge3J9DQoNCmxpYnJhcnkoRFQpDQoNCnRkZl9lc3Bhbm9sIDwtIHRkZl93aW5uZXJzICU+JSANCiAgcmVuYW1lKGVkaWNpb24gPSAiZWRpdGlvbiIgLA0KICAgICAgICAgaW5pY2lvID0gInN0YXJ0X2RhdGUiICwNCiAgICAgICAgIGdhbmFkb3IgPSAid2lubmVyX25hbWUiICwNCiAgICAgICAgIGVxdWlwbyA9ICJ3aW5uZXJfdGVhbSIgLA0KICAgICAgICAgZGlzdGFuY2lhID0gImRpc3RhbmNlIiAsDQogICAgICAgICB0aWVtcG8gPSAidGltZV9vdmVyYWxsIiAsDQogICAgICAgICBuYWNpb25hbGlkYWQgPSAibmF0aW9uYWxpdHkiICwNCiAgICAgICAgIGBldGFwYXMgZ2FuYWRhc2AgPSAic3RhZ2Vfd2lucyIgLA0KICAgICAgICAgYGVzdGFwYXMgZGUgbGlkZXJgID0gInN0YWdlc19sZWQiKSAlPiUNCiAgc2VsZWN0KGVkaWNpb24sIGluaWNpbywgZ2FuYWRvciwgbmFjaW9uYWxpZGFkLCBlcXVpcG8sIGRpc3RhbmNpYSwgYGV0YXBhcyBnYW5hZGFzYCwgYGVzdGFwYXMgZGUgbGlkZXJgICkNCiAgDQogIA0KICANCiAgDQpkYXRhdGFibGUodGRmX2VzcGFub2wsIGNsYXNzID0ic3RyaXBlIGhvdmVyIGNvbXBhY3Qgcm93LWJvcmRlciIgLCBmaWx0ZXIgPSAndG9wJykNCg0KYGBgDQoNCg0KIyMjIDUuMi4gQ2ljbGlzdGFzIGRlc3RhY2Fkb3Mgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KDQojIyMjIEV0YXBhcyANCg0KIyMjIyMgNS4yLjEuIENvcnJlZG9yZXMgcXVlIG1hcyBlc3RhcGFzIGhhbiBnYW5hZG8gZGVsIFRvdXINCg0KYGBge3J9DQoNCg0KI01heGltb3MgZ2FuYWRvcmVzIGRlIGV0YXBhcw0KDQpnYW5hZG9yZXNfZXRhcGEgPC0gdGRmX3N0YWdlcyAlPiUNCiAgZmlsdGVyKFdpbm5lciE9IkxhbmNlIEFybXN0cm9uZ1tuIDFdIiklPiUNCiAgZ3JvdXBfYnkoV2lubmVyKSAlPiUNCiAgbXV0YXRlKGV0YXBhc19nYW5hcyA9IG4oKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgY291bnQoV2lubmVyLCBUeXBlLCBldGFwYXNfZ2FuYXMsIHNvcnQgPSBUUlVFKSAlPiUNCiAgZmlsdGVyKGV0YXBhc19nYW5hcz49IDEwKQ0KICANCiAgDQpwNiA8LSBnZ3Bsb3QoZ2FuYWRvcmVzX2V0YXBhLCBhZXMocmVvcmRlcihXaW5uZXIsIGV0YXBhc19nYW5hcyksIG4sIGZpbGw9IFR5cGUpKSArDQogIGdlb21fY29sKCkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpICsNCiAgY29vcmRfZmxpcCgpICsgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC43LCAwLjQpKSArbGFicyh4ID0gTlVMTCwgeSA9ICJFdGFwYXMgdG90YWxlcyIsIGZpbGwgPSAiVGlwbyBkZSBldGFwYSIpDQoNCg0KcDYNCg0KYGBgDQo8YnI+DQoNCkNvbW8gcG9kZW1vcyB2ZXIgKipNZXJja3gqKiBlcyBtw6F4aW1vIGdhbmFkb3IgZGUgZXRhcGFzLCBwZXJvIHNlcsOtYSBpbmp1c3RvIG5vIG1lbmNpb25hciBxdWUgZW4gbGEgw7psdGltYSBlZGljacOzbiBlbCBzcHJpbnRlciBNYXJrIENhdmVuZGlzaCBxdWUgaGFzdGEgZW50b25jZXMgb2N1cGFiYSBsYSBzZWd1bmRhIHBvc2ljacOzbiBjb24gMzAgdmljdG9yaWFzLCBoYSBjb25zZWd1aWRvIGlndWFsYXIgYWwgY2Fuw61iYWwgY29uIDM0IHZpY3RvcmlhcywgZ3JhY2lhcyBhIGxhcyA0IGV0YXBhcyBnYW5hZGFzIGVuIDIwMjEgeSBkZSBubyBoYWJlciBzaWRvIHBvciB1biBhanVzdGFkbyBzcHJpbnQgeSB2aWN0b3JpYSBmaW5hbCBlbiBsb3MgY2FtcG9zIEVsw61zZW9zIGRlIFdvdXQgdmFuIEFlcnQsIGVzdGUgaHViaWVyYSBjb25zZWd1aWRvIHN1cGVyYXIgYSBNZXJja3ggLg0KDQo8YnI+DQoNCkNvbW8gcG9kZW1vcyB2ZXIgbG9zICoqc3ByaW50ZXJzKiogc29uIGxvcyBxdWUgc3VlbGVuIGNvcGFyIGVsIHJhbmtpbmcgZGUgY29ycmVkb3JlcyBjb24gbWF5b3JlcyBldGFwYXMsIGVzdG8gZXMgZGViaWRvIGEgc3UgZmFjaWxpZGFkIHBvciBnYW5hciBldGFwYXMuIFNpIGVzdMOhaXMgaW50ZXJlc2FkbyBlbiB2ZXIgcXVpZW5lcyBoYW4gZ2FuYWRvIG3DoXMgZXRhcGFzIGRlIG1vbnRhw7FhIG8gZGUgY29udHJhcnJlbG9qIHBvZMOpaXMgaGFjZXIgY2xpYyBlbiBsYXMgcGVzdGHDsWFzIGRlIHN1cyBhcGFydGFkb3MuDQoNCg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQo8YnI+DQoNCiMjIyMgIEV0YXBhcyBMbGFuYXMNCg0KIyMjIyMgNS4yLjIuIE1lam9yZXMgc3ByaW50ZXJzIGRlbCBUb3VyDQoNCmBgYHtyfQ0KI01lam9yZXMgY2ljbGlzdGFzIHNwcmludGVycyANCg0KbWVqb3Jlc19zcHJpbnRlcnMgPC0gdGRmX3N0YWdlcyAlPiUNCiAgZmlsdGVyKFdpbm5lciE9IkxhbmNlIEFybXN0cm9uZ1tuIDFdIiklPiUNCiAgZ3JvdXBfYnkoV2lubmVyKSAlPiUNCiAgbXV0YXRlKGV0YXBhc19nYW5hcyA9IG4oKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgY291bnQoV2lubmVyLCBUeXBlLCBldGFwYXNfZ2FuYXMsIHNvcnQgPSBUUlVFKSAlPiUNCiAgZmlsdGVyKFR5cGUgPT0gIkV0YXBhIGxsYW5hIikgJT4lDQogIGZpbHRlcihuPj0gNikNCg0KcDcgPC0gIGdncGxvdChtZWpvcmVzX3NwcmludGVycywgYWVzKHJlb3JkZXIoV2lubmVyLCBuKSwgbikpICsNCiAgZ2VvbV9jb2woZmlsbCA9ICIjZmRlNzI1IikgKw0KICBjb29yZF9mbGlwKCkgKyB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpICsNCiAgbGFicyh4ID0gTlVMTCwgeSA9ICJWaWN0b3JpYXMgIikNCiAgDQppbWcxIDwtIHJlYWRQTkcoImltYWdlbmVzL3Rhcm1hYy5wbmciKQ0KbWFyY2ExIDwtIHJhc3Rlckdyb2IoaW1nMSwgaW50ZXJwb2xhdGU9RixoZWlnaHQ9dW5pdCg0LCAiY20iKSxoanVzdD0gLTAuMiwgdmp1c3Q9MS4zKQ0KcDcgKyBhbm5vdGF0aW9uX2N1c3RvbShtYXJjYTEseG1pbj0tSW5mLCB4bWF4PUluZiwgeW1pbj0tSW5mLCB5bWF4PUluZikNCmBgYA0KDQoNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KPGJyPg0KDQojIyMjIEV0YXBhcyBNb250YcOxYQ0KIyMjIyMgNS4yLjMuIE1lam9yZXMgZXNjYWxhZG9yZXMgZGVsIHRvdXINCg0KYGBge3J9DQoNCiNNZWpvcmVzIGNpY2xpc3RhcyBlc2NhbGFkb3Jlcw0KDQptZWpvcmVzX2VzY2FsYWRvcmVzIDwtIHRkZl9zdGFnZXMgJT4lDQogIGZpbHRlcihXaW5uZXIhPSJMYW5jZSBBcm1zdHJvbmdbbiAxXSIpJT4lDQogIGdyb3VwX2J5KFdpbm5lcikgJT4lDQogIG11dGF0ZShldGFwYXNfZ2FuYXMgPSBuKCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGNvdW50KFdpbm5lciwgVHlwZSwgZXRhcGFzX2dhbmFzLCBzb3J0ID0gVFJVRSkgJT4lDQogIGZpbHRlcihUeXBlID09ICJFdGFwYSBkZSBtb250YcOxYSIpICU+JQ0KICBmaWx0ZXIobj49IDQpDQoNCg0KcDggPC0gZ2dwbG90KG1lam9yZXNfZXNjYWxhZG9yZXMsIGFlcyhyZW9yZGVyKFdpbm5lciwgbiksIG4pKSArDQogIGdlb21fY29sKGZpbGwgPSAiIzhmZDc0NCIpICsNCiAgY29vcmRfZmxpcCgpICsgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpKSArDQogIGxhYnMoeCA9IE5VTEwsIHkgPSAiVmljdG9yaWFzICIpDQoNCmltZzIgPC0gcmVhZFBORygiaW1hZ2VuZXMvbW91bnRhaW4ucG5nIikNCm1hcmNhMiA8LSByYXN0ZXJHcm9iKGltZzIsIGludGVycG9sYXRlPUYsaGVpZ2h0PXVuaXQoNCwgImNtIiksaGp1c3Q9IC0wLjIsIHZqdXN0PTEuMykNCnA4ICsgYW5ub3RhdGlvbl9jdXN0b20obWFyY2EyLHhtaW49LUluZiwgeG1heD1JbmYsIHltaW49LUluZiwgeW1heD1JbmYpDQoNCmBgYA0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQo8YnI+DQoNCiMjIyMgIEV0YXBhcyBDcm9ubw0KDQojIyMjIyA1LjIuNC4gTWVqb3JlcyBjaWNsaXN0YXMgY29udHJhIGVsIGNyb25vDQoNCmBgYHtyfQ0KDQojTWVqb3JlcyBjaWNsaXN0YXMgY29udHJhIGVsIGNyb25vICANCg0KbWVqb3Jlc19jcm9ub3MgPC0gdGRmX3N0YWdlcyAlPiUNCiAgZmlsdGVyKFdpbm5lciE9IkxhbmNlIEFybXN0cm9uZ1tuIDFdIiklPiUNCiAgZ3JvdXBfYnkoV2lubmVyKSAlPiUNCiAgbXV0YXRlKGV0YXBhc19nYW5hcyA9IG4oKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgY291bnQoV2lubmVyLCBUeXBlLCBldGFwYXNfZ2FuYXMsIHNvcnQgPSBUUlVFKSAlPiUNCiAgZmlsdGVyKFR5cGUgPT0gIkNvbnRyYXJyZWxvaiBpbmRpdmlkdWFsIikgJT4lDQogIGZpbHRlcihuPj0gMikNCg0KDQpwOSA8LSBnZ3Bsb3QobWVqb3Jlc19jcm9ub3MsIGFlcyhyZW9yZGVyKFdpbm5lciwgbiksIG4pKSArDQogIGdlb21fY29sKGZpbGwgPSAiIzQ0M2E4MyIpICsNCiAgY29vcmRfZmxpcCgpICsgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpKSArDQogIGxhYnMoeCA9IE5VTEwsIHkgPSAiVmljdG9yaWFzICIpDQoNCmltZzMgPC0gcmVhZFBORygiaW1hZ2VuZXMvY3Jvbm8ucG5nIikNCm1hcmNhMyA8LSByYXN0ZXJHcm9iKGltZzMsIGludGVycG9sYXRlPUYsaGVpZ2h0PXVuaXQoNCwgImNtIiksaGp1c3Q9IC0wLjIsIHZqdXN0PTEuMTUpDQpwOSArIGFubm90YXRpb25fY3VzdG9tKG1hcmNhMyx4bWluPS1JbmYsIHhtYXg9SW5mLCB5bWluPS1JbmYsIHltYXg9SW5mKQ0KDQoNCmBgYA0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQo8YnI+DQoNCg0KDQoNCiMjIyA1LjMuIEZyYW5jaWEgbGEgZ3JhbiBkb21pbmFkb3JhDQoNCiMjIyMgNS4zLjEuIFBhaXNlcyBnYW5hZG9yZXMgZGVsIFRvdXINCg0KYGBge3J9DQoNCiNHcmFmaWNhIHAxMCAgZ2FuYWRvcmVzIHBvciBwYWlzZXMNCg0KDQp0ZGZfd2lubmVycyRjb2RlPC10b2xvd2VyKGNvdW50cnljb2RlKHRkZl93aW5uZXJzJG5hdGlvbmFsaXR5LG9yaWdpbiA9ICdjb3VudHJ5Lm5hbWUnLCBkZXN0aW5hdGlvbiA9ICdpc28yYycpKQ0KDQp2aWN0b3JpYXNfcGFpcyA8LSB0ZGZfd2lubmVycyAlPiUNCiAgZmlsdGVyKHdpbm5lcl9uYW1lIT0iTGFuY2UgQXJtc3Ryb25nIiklPiUNCiAgZ3JvdXBfYnkobmF0aW9uYWxpdHksY29kZSkgJT4lDQogIHN1bW1hcmlzZSh2aWN0b3JpYXMgPSBuKCkpDQoNCnAxMCA8LSBnZ3Bsb3QodmljdG9yaWFzX3BhaXMsIGFlcyhyZW9yZGVyKG5hdGlvbmFsaXR5LCAtIHZpY3RvcmlhcyksIHZpY3RvcmlhcykpICsNCiAgZ2VvbV9jb2woYWVzKGZpbGw9IHZpY3RvcmlhcykpICsNCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdz0iIzllOWU5ZSIsaGlnaD0iIzI4MjgyOCIpICsNCiAgZ2VvbV9mbGFnKGFlcyhuYXRpb25hbGl0eSwgdmljdG9yaWFzLCBjb3VudHJ5ID0gY29kZSksIHk9LTEgLHNpemUgPSAxMCkgKyANCiAgZ2VvbV90ZXh0KGFlcyhuYXRpb25hbGl0eSx2aWN0b3JpYXMsIGxhYmVsID0gdmljdG9yaWFzKSwgdmp1c3QgPSAtMC44LCBzaXplID0gNSkgKw0KICANCiAgYW5ub3RhdGUoZ2VvbSA9ICJjdXJ2ZSIsIHggPSAxLjUsIHkgPSAzNiwgeGVuZCA9IDUsIHllbmQgPSAzNiwgY3VydmF0dXJlID0gLjMsIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgyLCAibW0iKSkpICsNCiAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwgeCA9IDUsIHkgPSAzNywgbGFiZWwgPSAiTGEgw7psdGltYSB2aWN0b3JpYSBmcmFuY2VzYSBmdWUgZW4gMTk4NS4iLCBoanVzdCA9ICJsZWZ0IikgKw0KICANCiAgbGltcyh5PWMoLTIsMzgpKSArDQp0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSkpICsNCiAgbGFicyh4ID0gTlVMTCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgDQogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAiYmxhbmsiKSwNCiAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3VyID0gIndoaXRlIikpICsNCiAgbGFicyh5ID0gTlVMTCkgICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQ0KDQpwMTANCg0KYGBgDQo8YnI+DQoNCkNvbW8gbm8gcG9kw61hIHNlciBkZSBvdHJhIG1hbmVyYSBlbCBkb21pbmlvIEZyYW5jw6lzIHNlZ3VpZG8gbXV5IGRlIGxlam9zIHBvciBsb3MgQmVsZ2FzIHkgRXNwYcOxb2xlcywgZW4gbGEgY2FycmVyYSBlcyBhcGxhc3RhbnRlIHBlcm8gbm8gZGViZW1vcyBkZWphcm5vcyBsbGV2YXIgcG9yIGxhcyBhcGFyaWVuY2lhcywgc2kgYW5hbGl6YW1vcyBtZWpvciBsb3MgZGF0b3MgcG9kZW1vcyBkZWNpciBxdWUgZXN0ZSBkb21pbmlvIGNvbW8gdGFsIG5vIGV4aXN0ZSBlbiBsYSBhY3R1YWxpZGFkLCBtdWNoYXMgZGUgbGFzIHZpY3RvcmlhcyBzb24gZGUgbGEgcHJpbWVyYSBldGFwYSBtZW5jaW9uYWRhIGFudGVyaW9ybWVudGUgZG9uZGUgbGEgbWF5b3LDrWEgZGUgbG9zIGNvcnJlZG9yZXMgZXJhbiBmcmFuY2VzZXMsIGVzIG1hcywgZGVzZGUgZWwgYcOxbyAxOTg1IGN1YW5kbyBCZXJuYWQgSGluYXVsdCBjb25xdWlzdG8gZWwgw7psdGltbyBUb3VyIG5pbmfDum4gb3RybyBGcmFuY8OpcyBoYSB2dWVsdG8gYSBnYW5hciBsYSBjYXJyZXJhLCBlcyBkZWNpciwgaGFuIHBhc2FkbyAzNiBhw7FvcyBkZXNkZSBsYSDDumx0aW1hIHZpY3RvcmlhIEZyYW5jZXNhLg0KDQo8YnI+DQoNCiMjIyA1LjQuIExvcyBjaWNsaXN0YXMgYWxjYW56YW4gc3UgbWFkdXJleiBhIGxvcyAzMCBhw7Fvcw0KDQojIyMjIDUuNC4xLiBEZW5zaWRhZCBkZSB2aWN0b3JpYXMgcG9yIGVkYWQNCg0KYGBge3J9DQoNCg0KcDExIDwtIGdncGxvdCh0ZGZfd2lubmVycywgYWVzKGFnZSkpICsNCiAgZ2VvbV9kZW5zaXR5KGZpbGw9IiNlZGU2NTciLCBjb2xvcj0iI2VkZTY1NyIsIGFscGhhPTAuOSkgKw0KICB0aGVtZV9pcHN1bSgpICsgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwNCiAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIiksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpKSArbGFicyh4ID0gIkVkYWQiLCB5ID0gIkRlbnNpZGFkIikNCiAgDQpwMTENCg0KYGBgDQo8YnI+DQoNCkVsIG9iamV0aXZvIGRlIGVzdGEgZ3LDoWZpY2EgZXJhIHZlciBkb25kZSBzZSBlbmN1ZW50cmEgbGEgZWRhZCBkZSBtYWR1cmFjacOzbiBvIGVuIG90cmFzIHBhbGFicmFzIGN1YW5kbyB1biBjaWNsaXN0YSBkZXNhcnJvbGxhIHRvZG8gc3UgcG90ZW5jaWFsLCBvYnNlcnZhbmRvIGxhIGdyw6FmaWNhIHBvZHLDrWFtb3MgZGVjaXIgcXVlIGVzdMOhIGVudHJlIGxvcyAyOCBhIDMwIGHDsW9zLg0KDQo8YnI+DQoNCiMjIyA1LjUuIFRyYXllY3RvcmlhIGRlIGNpY2xpc3RhcyBkZXN0YWNhZG9zIHsudGFic2V0IC50YWJzZXQtcGlsbHN9IA0KDQojIyMjIEFsYmVydG8gQ29udGFkb3INCg0KIyMjIyMgNS41LjEuIFRyYXllY3RvcmlhIGRlIEFsYmVydG8gQ29udGFkb3IgZW4gZWwgVG91ciBkZSBGcmFuY2lhDQoNCmBgYHtyfQ0KIyBHcmFmaWNvIHAxMSBhbmFsaXNpIGRlIEFsYmVydG8gQ29udGFkb3INCg0KY2FycmVyYV9jb3JyZWRvcjEgPC0gc3RhZ2VfZGF0YSAlPiUNCiAgZmlsdGVyKHJpZGVyID09ICJDb250YWRvciBBbGJlcnRvIikgJT4lIA0KICBtdXRhdGUocG9zaWNpb24gPSBhcy5udW1lcmljKHJhbmspKSAlPiUNCiAgbXV0YXRlKGV0YXBhID0gZmFjdG9yKGFzLm51bWVyaWMoc3RyX3JlbW92ZShzdGFnZV9yZXN1bHRzX2lkLCAic3RhZ2UtIikpKSkgJT4lDQogIG11dGF0ZSh5ZWFyID0gZmFjdG9yKHllYXIpKSANCiAgDQogcDExIDwtIGdncGxvdChjYXJyZXJhX2NvcnJlZG9yMSwgYWVzKHllYXIsIGV0YXBhLCBmaWxsID0gcG9zaWNpb24pKSArDQogIGdlb21fdGlsZSgpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByYW5rKSwgc2l6ZSA9IDIsIGNvbG9yID0gIndoaXRlIikgKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksDQogIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICAgbGFicyh0aXRsZSA9IE5VTEwsIHggPSAiRWRpY2nDs24iLCB5ID0gIkV0YXBhIikNCg0KcGxvdGx5OjpnZ3Bsb3RseShwMTEsIHRvb2x0aXAgPSBjKCJ5IiwgIngiLCAiZmlsbCIpKQ0KDQpgYGANCjxicj4NCg0KIyMjIyMgNS41LjEuIFZpY3RvcmlhcyBkZSBBbGJlcnRvIENvbnRhZG9yIGVuIGVsIFRvdXIgZGUgRnJhbmNpYQ0KDQpgYGB7cn0NCg0KI1RhYmxhIHAxNSB2aWN0b3JpYSBjb250YWRvcg0KDQpwMTUgPC0gdGRmX3N0YWdlcyAlPiUgDQogIA0KICByZW5hbWUoRXRhcGEgPSAiU3RhZ2UiLA0KICAgICAgICAgRGlzdGFuY2lhID0gIkRpc3RhbmNlIiwNCiAgICAgICAgIEZlY2hhID0gIkRhdGUiLA0KICAgICAgICAgT3JpZ2VuID0gIk9yaWdpbiIsDQogICAgICAgICBEZXN0aW5vID0gIkRlc3RpbmF0aW9uIiwNCiAgICAgICAgIFRpcG8gPSAiVHlwZSIpICU+JQ0KICBmaWx0ZXIoV2lubmVyID09ICJBbGJlcnRvIENvbnRhZG9yIikgJT4lIA0KICBzZWxlY3QoLSBXaW5uZXIsIC0gV2lubmVyX0NvdW50cnksIC0gRXRhcGEpIA0KDQprbml0cjo6a2FibGUocDE1KQ0KDQpgYGANCg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoNCjxicj4NCg0KDQojIyMjIEZhYmlhbiBDYW5jZWxsYXJhDQoNCiMjIyMjIDUuNS4yLiBUcmF5ZWN0b3JpYSBkZSBGYWJpYW4gQ2FuY2VsbGFyYSBlbiBlbCBUb3VyIGRlIEZyYW5jaWENCg0KYGBge3J9DQoNCmNhcnJlcmFfY29ycmVkb3IyIDwtIHN0YWdlX2RhdGEgJT4lDQogIGZpbHRlcihyaWRlciA9PSAiQ2FuY2VsbGFyYSBGYWJpYW4iKSAlPiUgDQogIG11dGF0ZShwb3NpY2lvbiA9IGFzLm51bWVyaWMocmFuaykpICU+JQ0KICBtdXRhdGUoZXRhcGEgPSBmYWN0b3IoYXMubnVtZXJpYyhzdHJfcmVtb3ZlKHN0YWdlX3Jlc3VsdHNfaWQsICJzdGFnZS0iKSkpKSAlPiUNCiAgbXV0YXRlKHllYXIgPSBmYWN0b3IoeWVhcikpIA0KDQpwMTIgPC0gZ2dwbG90KGNhcnJlcmFfY29ycmVkb3IyLCBhZXMoeWVhciwgZXRhcGEsIGZpbGwgPSBwb3NpY2lvbikpICsNCiAgZ2VvbV90aWxlKCkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJhbmspLCBzaXplID0gMiwgY29sb3IgPSAid2hpdGUiKSArDQogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIGxhYnModGl0bGUgPSBOVUxMLCB4ID0gIkVkaWNpw7NuIiwgeSA9ICJFdGFwYSIpDQoNCnBsb3RseTo6Z2dwbG90bHkocDEyLCB0b29sdGlwID0gYygieSIsICJ4IiwgImZpbGwiKSkNCg0KYGBgDQo8YnI+DQoNCiMjIyMjIDUuNS4xLiBWaWN0b3JpYXMgZGUgRmFiaWFuIENhbmNlbGxhcmEgZW4gZWwgVG91ciBkZSBGcmFuY2lhDQoNCmBgYHtyfQ0KDQojVGFibGEgcDE2IHZpY3RvcmlzIENhbmNlbGxhcmENCg0KcDE2IDwtIHRkZl9zdGFnZXMgJT4lIA0KICANCiAgcmVuYW1lKEV0YXBhID0gIlN0YWdlIiwNCiAgICAgICAgIERpc3RhbmNpYSA9ICJEaXN0YW5jZSIsDQogICAgICAgICBGZWNoYSA9ICJEYXRlIiwNCiAgICAgICAgIE9yaWdlbiA9ICJPcmlnaW4iLA0KICAgICAgICAgRGVzdGlubyA9ICJEZXN0aW5hdGlvbiIsDQogICAgICAgICBUaXBvID0gIlR5cGUiKSAlPiUNCiAgZmlsdGVyKFdpbm5lciA9PSAiRmFiaWFuIENhbmNlbGxhcmEiKSAlPiUgDQogIHNlbGVjdCgtIFdpbm5lciwgLSBXaW5uZXJfQ291bnRyeSwgLSBFdGFwYSkgDQoNCmtuaXRyOjprYWJsZShwMTYpDQoNCmBgYA0KDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCjxicj4NCg0KIyMjIyDDk3NjYXIgRnJlaXJlDQoNCiMjIyMjIDUuNS4xLiBUcmF5ZWN0b3JpYSBkZSDDk3NjYXIgRnJlaXJlIGVuIGVsIFRvdXIgZGUgRnJhbmNpYQ0KDQpgYGB7cn0NCg0KIyBHcmFmaWNvIHAxMyBhbmFsaXNpIGRlIE9zY2FyIEZyZWlyZQ0KDQpjYXJyZXJhX2NvcnJlZG9yMyA8LSBzdGFnZV9kYXRhICU+JQ0KICBmaWx0ZXIocmlkZXIgPT0gIkZyZWlyZSDDk3NjYXIiKSAlPiUgDQogIG11dGF0ZShwb3NpY2lvbiA9IGFzLm51bWVyaWMocmFuaykpICU+JQ0KICBtdXRhdGUoZXRhcGEgPSBmYWN0b3IoYXMubnVtZXJpYyhzdHJfcmVtb3ZlKHN0YWdlX3Jlc3VsdHNfaWQsICJzdGFnZS0iKSkpKSAlPiUNCiAgbXV0YXRlKHllYXIgPSBmYWN0b3IoeWVhcikpIA0KDQpwMTMgPC0gZ2dwbG90KGNhcnJlcmFfY29ycmVkb3IzLCBhZXMoeWVhciwgZXRhcGEsIGZpbGwgPSBwb3NpY2lvbikpICsNCiAgZ2VvbV90aWxlKCkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJhbmspLCBzaXplID0gMiwgY29sb3IgPSAid2hpdGUiKSArDQogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwNCiAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIGxhYnModGl0bGUgPSBOVUxMLCB4ID0gIkVkaWNpw7NuIiwgeSA9ICJFdGFwYSIpDQoNCnBsb3RseTo6Z2dwbG90bHkocDEzLCB0b29sdGlwID0gYygieSIsICJ4IiwgImZpbGwiKSkNCg0KDQpgYGANCg0KPGJyPg0KDQojIyMjIyA1LjUuMy4gVmljdG9yaWFzIGRlIMOTc2NhciBGcmVpcmUgZW4gZWwgVG91ciBkZSBGcmFuY2lhDQoNCmBgYHtyfQ0KDQojVGFibGEgcDE3IHZpY3RvcmlhIE9zY2FyIEZyZWlyZQ0KDQpwMTcgPC0gdGRmX3N0YWdlcyAlPiUgDQogIA0KICByZW5hbWUoRXRhcGEgPSAiU3RhZ2UiLA0KICAgICAgICAgRGlzdGFuY2lhID0gIkRpc3RhbmNlIiwNCiAgICAgICAgIEZlY2hhID0gIkRhdGUiLA0KICAgICAgICAgT3JpZ2VuID0gIk9yaWdpbiIsDQogICAgICAgICBEZXN0aW5vID0gIkRlc3RpbmF0aW9uIiwNCiAgICAgICAgIFRpcG8gPSAiVHlwZSIpICU+JQ0KICBmaWx0ZXIoV2lubmVyID09ICLDk3NjYXIgRnJlaXJlIikgJT4lIA0KICBzZWxlY3QoLSBXaW5uZXIsIC0gV2lubmVyX0NvdW50cnksIC0gRXRhcGEpIA0KDQprbml0cjo6a2FibGUocDE3KQ0KDQpgYGANCg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQo8YnI+DQoNCiMjIyMgVG9tIEJvb25lbQ0KDQojIyMjIyA1LjUuMS4gVHJheWVjdG9yaWEgZGUgVG9tIEJvb25lbSBlbiBlbCBUb3VyIGRlIEZyYW5jaWENCg0KYGBge3J9DQoNCiMgR3JhZmljbyBwMTQgYW5hbGlzaSBkZSBUb20gQm9vbmVtDQoNCmNhcnJlcmFfY29ycmVkb3IgPC0gc3RhZ2VfZGF0YSAlPiUNCiAgZmlsdGVyKHJpZGVyID09ICJCb29uZW4gVG9tIikgJT4lIA0KICBtdXRhdGUocG9zaWNpb24gPSBhcy5udW1lcmljKHJhbmspKSAlPiUNCiAgbXV0YXRlKGV0YXBhID0gZmFjdG9yKGFzLm51bWVyaWMoc3RyX3JlbW92ZShzdGFnZV9yZXN1bHRzX2lkLCAic3RhZ2UtIikpKSkgJT4lDQogIG11dGF0ZSh5ZWFyID0gZmFjdG9yKHllYXIpKSANCg0KcDE0IDwtIGdncGxvdChjYXJyZXJhX2NvcnJlZG9yLCBhZXMoeWVhciwgZXRhcGEsIGZpbGwgPSBwb3NpY2lvbikpICsNCiAgZ2VvbV90aWxlKCkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJhbmspLCBzaXplID0gMiwgY29sb3IgPSAid2hpdGUiKSArDQogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIGxhYnModGl0bGUgPSBOVUxMLCB4ID0gIkVkaWNpw7NuIiwgeSA9ICJFdGFwYSIpDQoNCnBsb3RseTo6Z2dwbG90bHkocDE0LCB0b29sdGlwID0gYygieSIsICJ4IiwgImZpbGwiKSkNCg0KDQpgYGANCg0KPGJyPg0KDQojIyMjIyA1LjUuNC4gVmljdG9yaWFzIGRlIFRvbSBCb29uZW0gZW4gZWwgVG91ciBkZSBGcmFuY2lhDQoNCmBgYHtyfQ0KDQojVGFibGEgcDE4IHZpY3RvcmlhIFRvbSBCb29uZW0NCg0KcDE4IDwtIHRkZl9zdGFnZXMgJT4lIA0KICANCiAgcmVuYW1lKEV0YXBhID0gIlN0YWdlIiwNCiAgICAgICAgIERpc3RhbmNpYSA9ICJEaXN0YW5jZSIsDQogICAgICAgICBGZWNoYSA9ICJEYXRlIiwNCiAgICAgICAgIE9yaWdlbiA9ICJPcmlnaW4iLA0KICAgICAgICAgRGVzdGlubyA9ICJEZXN0aW5hdGlvbiIsDQogICAgICAgICBUaXBvID0gIlR5cGUiKSAlPiUNCiAgZmlsdGVyKFdpbm5lciA9PSAiVG9tIEJvb25lbiIpICU+JSANCiAgc2VsZWN0KC0gV2lubmVyLCAtIFdpbm5lcl9Db3VudHJ5LCAtIEV0YXBhKSANCg0Ka25pdHI6OmthYmxlKHAxOCkNCg0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCjxicj4NCg0KIyMgNi5EQVRPUyBDVVJJT1NPUw0KDQpQYXJhIGZpbmFsaXphciBlbCB0cmFiYWpvIGVuIGVzdGUgw7psdGltbyBhcGFydGFkbyBtZSBndXN0YXLDrWEgcmVhbGl6YXIgdW5hIHNlcmllIGRlIHRhYmxhcyBjb24gaW5mb3JtYWNpw7NuIHNvYnJlIGVxdWlwb3MsIGNvcnJlZG9yZXMgeSBjaXVkYWRlcyBxdWUgZm9ybWFuIHBhcnRlIGhhYml0dWFsIGRlIGxhIGNhcnJlcmEuDQoNCjxicj4NCg0KTWUgZ3VzdGFyw61hIGFjbGFyYXIgcXVlIHJlYWxpemFyIHVuYSBjbGFzaWZpY2FjacOzbiBwb3IgZXF1aXBvcyByZXN1bHRhIHVuIHBvY28gY29tcGxpY2FkYSwgeWEgcXVlIGVuIGVsIGNpY2xpc21vIGVzIG11eSBoYWJpdHVhbCBlbCBjYW1iaW8gZGUgbm9tYnJlcyBkZSBlcXVpcG9zIGRlcGVuZGllbmRvIGRlIHN1IHBhdHJvY2luYWRvciwgcGVybyBlbCBlcXVpcG8gc2lndWUgc2llbmRvIGVsIG1pc21vIHB1ZXMgbG8gaW1wb3J0YW50ZSBlcyBsYSBlc3RydWN0dXJhLCB1biBlamVtcGxvIGRlIGVzdG8gc2Vyw61hIGVsIEJhbmVzdG8sIGFjdHVhbG1lbnRlIGNvbm9jaWRvIGNvbW8gTW92aXN0YXIgdGVhbSwgbyBlbCBUZWFtIFNreSBxdWUgaGEgcGFzYWRvIGEgbGxhbWFyc2UgSW5lb3MuIFBvciBsbyB0YW50bywgbG9zIGRhdG9zIHF1ZSBzZSBvYnNlcnZhbiBlbiBsYSBwcmltZXJhIHRhYmxhIHB1ZWRlbiBubyBzZXIgZXhhY3RvcyBkZWwgdG9kbyBwZXJvIG1pIGZpbmFsaWRhZCBlbiBlc3RhIGhhIHNpZG8gcmVtYXJjYXIgYXF1ZWxsb3MgZXF1aXBvcyBxdWUgbWFyY2Fyb24gdW5hIMOpcG9jYSB5IHNvbiBtdXkgcmVjb3JkYWRvcyBwb3IgbG9zIGFmaWNpb25hZG9zLg0KDQojIyMgNi4xLiAgRWwgVGVhbSBTa3kgZWwgZXF1aXBvIGNvbiBtw6FzIHZpY3Rvcmlhcw0KDQojIyMjIDYuMS4xLiBFcXVpcG9zIGNvbiBtw6FzIHZpY3RvcmlhcyBkZWwgdG91cg0KDQpgYGB7cn0NCg0KZXF1aXBvX3ZpY3RvcmlhIDwtIHRkZl93aW5uZXJzICU+JQ0KICBncm91cF9ieSh3aW5uZXJfdGVhbSkgJT4lDQogIHN1bW1hcmlzZShuID0gbigpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBmaWx0ZXIod2lubmVyX3RlYW0hPSAiRnJhbmNlIikgJT4lDQogIGZpbHRlcih3aW5uZXJfdGVhbSE9Ikl0YWx5IikgJT4lDQogIGZpbHRlcih3aW5uZXJfdGVhbSE9IkJlbGdpdW0iKSAlPiUNCiAgZmlsdGVyKHdpbm5lcl90ZWFtIT0iVS5TLiBQb3N0YWwgU2VydmljZSIpICU+JQ0KICBmaWx0ZXIod2lubmVyX3RlYW0hPSJMYSBTcG9ydGl2ZSIpICU+JQ0KICBmaWx0ZXIod2lubmVyX3RlYW0hPSJTd2l0emVybGFuZCIpICU+JQ0KICBmaWx0ZXIod2lubmVyX3RlYW0hPSJQZXVnZW904oCTQlDigJNNaWNoZWxpbiIpICU+JQ0KICBmaWx0ZXIod2lubmVyX3RlYW0hPSJSZW5hdWx04oCTRWxm4oCTR2l0YW5lIikgJT4lDQogIGZpbHRlcih3aW5uZXJfdGVhbSE9IkFsY3lvbuKAk0R1bmxvcCIpICU+JQ0KICBmaWx0ZXIod2lubmVyX3RlYW0hPSJQZXVnZW904oCTV29sYmVyIikgJT4lDQogIGZpbHRlcih3aW5uZXJfdGVhbSE9IkF1dG9tb3Rv4oCTSHV0Y2hpbnNvbiIpICU+JQ0KICBmaWx0ZXIod2lubmVyX3RlYW0hPSJBbGN5b27igJNEdW5sb3AiKSAlPiUNCiAgZmlsdGVyKG4+PTIpJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkNCg0KDQoNCmZvdG9zX2VxdWlwbyA8LSBjKCJpbWFnZW5lcy9za3kucG5nIiwgImltYWdlbmVzL2JhbmVzdG8ucG5nIiwgImltYWdlbmVzL21vbHRlbmkucG5nIiwgImltYWdlbmVzL2FzdGFuYS5wbmciLCAiaW1hZ2VuZXMvZGlzY292ZXJ5LnBuZyIsICJpbWFnZW5lcy9jbGFpcmUucG5nIiwgImltYWdlbmVzL3JlbmF1bHQucG5nIiwgImltYWdlbmVzL3RlbGVrb20ucG5nIikNCg0KDQpmb3Rvc19wYWlzIDwtIGMoImltYWdlbmVzL3VrLnBuZyIsICJpbWFnZW5lcy9lc3BhbnlhLnBuZyIsICJpbWFnZW5lcy9pdGFsaWEucG5nIiwgImltYWdlbmVzL2NhemEucG5nIiwgImltYWdlbmVzL3VzYS5wbmciLCAiaW1hZ2VuZXMvZnJhbmNpYS5wbmciLCAiaW1hZ2VuZXMvZnJhbmNpYS5wbmciLCAiaW1hZ2VuZXMvYWxlbWFuaWEucG5nIikNCg0KDQplcXVpcG9fdmljdG9yaWFzX2ZvdG9zIDwtIGVxdWlwb192aWN0b3JpYSAlPiUNCiAgZ3JvdXBfYnkod2lubmVyX3RlYW0pICU+JQ0KICBhZGRfY29sdW1uKGZvdG9zX2VxdWlwbykgJT4lDQogIGFkZF9jb2x1bW4oZm90b3NfcGFpcykgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgcmVuYW1lKEVxdWlwbyA9ICJ3aW5uZXJfdGVhbSIgLCANCiAgICAgICAgIFRvdXJzID0gIm4iICwgDQogICAgICAgICBNYWlsbG90ID0gImZvdG9zX2VxdWlwbyIgLCANCiAgICAgICAgIFBhaXMgPSAiZm90b3NfcGFpcyIpDQoNCmxpYnJhcnkoZ3QpDQoNCmVxdWlwb192aWN0b3JpYXNfZm90b3MgJT4lIGd0KCkgJT4lIA0KICBndDo6dGV4dF90cmFuc2Zvcm0obG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gYyhNYWlsbG90KSksDQogICAgICAgICAgICAgICAgICAgICBmbiA9IGZ1bmN0aW9uKHgpIHtndDo6d2ViX2ltYWdlKHgsIGhlaWdodCA9IDcwICl9KSAlPiUNCiAgZ3Q6OnRleHRfdHJhbnNmb3JtKGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoUGFpcykpLA0KICAgICAgICAgICAgICAgICAgICAgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OndlYl9pbWFnZSh4LCBoZWlnaHQgPSAzNSApfSkgDQoNCmBgYA0KDQoNCg0KPGJyPg0KDQojIyMgNi4yLiBDaWNsaXN0YXMgbcOhcyBqb3ZlbiB5IG1heW9yZXMgDQoNCkVuIGVzdGEgb2Nhc2nDs24gdGFtYmnDqW4gbWUgaGEgZ3VzdGFkbyBzZXBhcmFyIGVudHJlIGNvcnJlZG9yZXMgZGUgdW4gY2ljbGlzbW8gYWN0dWFsIG3DoXMgbW9kZXJubyBhIGFxdWVsbG9zIHByaW1lcm9zIGNpY2xpc3Rhcywgbm8gcG9yIGRlc21lcmVjZXIgbGFzIGFjdHVhY2lvbmVzIGRlIEhlbnJpIENvcm5ldCBvIEZpcm1pbiBMYW1ib3QgcGVybyBlcmFuIG90cm9zIHRpZW1wb3MgeSBjcmVvIHF1ZSB0YW1wb2NvIHNlcsOtYSBqdXN0byBubyByZWNvbm9jZXIgZWwgdHJhYmFqbyBkZSBCZXJuYWwgbyBDYWRlbCBFdmFucy4gDQoNCjxicj4NCg0KOjo6IHsuY29sdW1uIHdpZHRoPSI0NyUifQ0KDQoNCmBgYHtyfQ0KDQojR3JhZmljYSBwMjAgR2FuYWRvciBtYXMgSm92ZW4gZGVsIHRvdXIgZGUgZnJhbmNpYQ0KDQpuYWNpb25hbGlkYWQxIDwtICgiaW1hZ2VuZXMvZnJhbmNpYS5wbmciKQ0KZXF1aXBvMSA8LSAoImltYWdlbmVzL2NvbnRlLnBuZyIpDQoNCg0KZ2FuYWRvcl9qb3ZlbiA8LSB0ZGZfd2lubmVycyAlPiUNCiAgc2xpY2VfbWluKGFnZSwgbj0xKSAlPiUNCiAgbXV0YXRlKHllYXI9IHllYXIoc3RhcnRfZGF0ZSkpICU+JQ0KICBzZWxlY3QoZWRpdGlvbiwgeWVhciwgd2lubmVyX25hbWUsIGFnZSkgJT4lDQogIGFkZF9jb2x1bW4obmFjaW9uYWxpZGFkMSkgJT4lDQogIGFkZF9jb2x1bW4oZXF1aXBvMSkgJT4lDQogIHJlbmFtZShFZGljaW9uID0gImVkaXRpb24iICwNCiAgICAgICAgIEHDsW8gPSAieWVhciIgLA0KICAgICAgICAgTm9tYnJlID0gIndpbm5lcl9uYW1lIiAsDQogICAgICAgICBOYWNpb25hbGlkYWQgPSAibmFjaW9uYWxpZGFkMSIgLA0KICAgICAgICAgRWRhZCA9ICJhZ2UiICwNCiAgICAgICAgIEVxdWlwbyA9ICJlcXVpcG8xIiApDQogIA0KDQpnYW5hZG9yX2pvdmVuICU+JSBndCgpICU+JSANCiAgZ3Q6OnRhYl9oZWFkZXIodGl0bGUgPSBtZCgiKipDb3JyZWRvciBtw6FzIGpvdmVuIGVuIGdhbmFyIGVsIFRvdXIqKiIpLCBzdWJ0aXRsZSA9IG1kKCJDaWNsaXNtbyBoaXN0w7NyaWNvIikpICU+JQ0KICBndDo6dGFiX29wdGlvbnMoaGVhZGluZy5iYWNrZ3JvdW5kLmNvbG9yID0gIiNlMjI4MmUiKSAlPiUNCiAgZ3Q6OnRleHRfdHJhbnNmb3JtKGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoTmFjaW9uYWxpZGFkKSksDQogICAgICAgICAgICAgICAgICAgICBmbiA9IGZ1bmN0aW9uKHgpIHtndDo6d2ViX2ltYWdlKHgsIGhlaWdodCA9IDM1ICl9KSAlPiUNCiAgZ3Q6OnRleHRfdHJhbnNmb3JtKGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoRXF1aXBvKSksDQogICAgICAgICAgICAgICAgICAgICBmbiA9IGZ1bmN0aW9uKHgpIHtndDo6d2ViX2ltYWdlKHgsIGhlaWdodCA9IDcwICl9KQ0KDQpgYGANCg0KOjo6DQoNCjo6OiB7LmNvbHVtbiB3aWR0aD0iMSUifQ0KPCEtLSBhbiBlbXB0eSBEaXYgKHdpdGggYSB3aGl0ZSBzcGFjZSkgaGFjaWVuZG8gZGUgc2VwYXJhZG9yIC0tPg0KOjo6DQoNCjo6OiB7LmNvbHVtbiB3aWR0aD0iNDclIn0NCg0KDQpgYGB7cn0NCg0KI0dyYWZpY2EgcDIxIEdhbmFkb3IgbWFzIG1heW9yIHRvdXIgZGUgRnJhbmNpYQ0KDQoNCm5hY2lvbmFsaWRhZDEgPC0gKCJpbWFnZW5lcy9iZWxnaXVtLnBuZyIpDQplcXVpcG8xIDwtICgiaW1hZ2VuZXMvcGV1Z2VvdC5wbmciKQ0KDQoNCmdhbmFkb3JfbWF5b3IgPC0gdGRmX3dpbm5lcnMgJT4lDQogIHNsaWNlX21heChhZ2UsIG49MSkgJT4lDQogIG11dGF0ZSh5ZWFyPSB5ZWFyKHN0YXJ0X2RhdGUpKSAlPiUNCiAgc2VsZWN0KGVkaXRpb24sIHllYXIsIHdpbm5lcl9uYW1lLCBhZ2UpICU+JQ0KICBhZGRfY29sdW1uKG5hY2lvbmFsaWRhZDEpICU+JQ0KICBhZGRfY29sdW1uKGVxdWlwbzEpICU+JQ0KICByZW5hbWUoRWRpY2lvbiA9ICJlZGl0aW9uIiAsDQogICAgICAgICBBw7FvID0gInllYXIiICwNCiAgICAgICAgIE5vbWJyZSA9ICJ3aW5uZXJfbmFtZSIgLA0KICAgICAgICAgTmFjaW9uYWxpZGFkID0gIm5hY2lvbmFsaWRhZDEiICwNCiAgICAgICAgIEVkYWQgPSAiYWdlIiAsDQogICAgICAgICBFcXVpcG8gPSAiZXF1aXBvMSIgKQ0KDQpnYW5hZG9yX21heW9yICU+JSBndCgpICU+JSANCiAgZ3Q6OnRhYl9oZWFkZXIodGl0bGUgPSBtZCgiKipDb3JyZWRvciBtw6FzIG1heW9yIGVuIGdhbmFyIGVsIFRvdXIqKiIpLCBzdWJ0aXRsZSA9IG1kKCJDaWNsaXNtbyBoaXN0w7NyaWNvIikpICU+JQ0KICBndDo6dGFiX29wdGlvbnMoaGVhZGluZy5iYWNrZ3JvdW5kLmNvbG9yID0gIiNlMjI4MmUiKSAlPiUNCiAgZ3Q6OnRleHRfdHJhbnNmb3JtKGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoTmFjaW9uYWxpZGFkKSksDQogICAgICAgICAgICAgICAgICAgICBmbiA9IGZ1bmN0aW9uKHgpIHtndDo6d2ViX2ltYWdlKHgsIGhlaWdodCA9IDM1ICl9KSAlPiUNCiAgZ3Q6OnRleHRfdHJhbnNmb3JtKGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoRXF1aXBvKSksDQogICAgICAgICAgICAgICAgICAgICBmbiA9IGZ1bmN0aW9uKHgpIHtndDo6d2ViX2ltYWdlKHgsIGhlaWdodCA9IDcwICl9KQ0KDQoNCmBgYA0KDQo6OjoNCg0KPGJyPg0KDQo6Ojogey5jb2x1bW4gd2lkdGg9IjQ3JSJ9DQoNCg0KYGBge3J9DQoNCg0KI0dyYWZpY2EgcDIyIEdhbmFkb3IgbWFzIEpvdmVuIGRlbCB0b3VyIGRlIGZyYW5jaWEgbW9kZXJubw0KDQpuYWNpb25hbGlkYWQxIDwtICgiaW1hZ2VuZXMvY29sb21iaWEucG5nIikNCmVxdWlwbzEgPC0gKCJpbWFnZW5lcy9pbmVvcy5wbmciKQ0KDQoNCmdhbmFkb3Jfam92ZW5fYWN0dWFsIDwtIHRkZl93aW5uZXJzICU+JQ0KICBmaWx0ZXIoZWRpdGlvbiA+PSA1NykgJT4lDQogIGZpbHRlcih3aW5uZXJfbmFtZSAhPSJMYXVyZW50IEZpZ25vbiIpICU+JQ0KICBzbGljZV9taW4oYWdlLCBuPTEpICU+JQ0KICBtdXRhdGUoeWVhcj0geWVhcihzdGFydF9kYXRlKSkgJT4lDQogIHNlbGVjdChlZGl0aW9uLCB5ZWFyLCB3aW5uZXJfbmFtZSwgYWdlKSAlPiUNCiAgYWRkX2NvbHVtbihuYWNpb25hbGlkYWQxKSAlPiUNCiAgYWRkX2NvbHVtbihlcXVpcG8xKSAlPiUNCiAgcmVuYW1lKEVkaWNpb24gPSAiZWRpdGlvbiIgLA0KICAgICAgICAgQcOxbyA9ICJ5ZWFyIiAsDQogICAgICAgICBOb21icmUgPSAid2lubmVyX25hbWUiICwNCiAgICAgICAgIE5hY2lvbmFsaWRhZCA9ICJuYWNpb25hbGlkYWQxIiAsDQogICAgICAgICBFZGFkID0gImFnZSIgLA0KICAgICAgICAgRXF1aXBvID0gImVxdWlwbzEiICkNCg0KDQpnYW5hZG9yX2pvdmVuX2FjdHVhbCAlPiUgZ3QoKSAlPiUgDQogIGd0Ojp0YWJfaGVhZGVyKHRpdGxlID0gbWQoIioqQ29ycmVkb3IgbcOhcyBqb3ZlbiBlbiBnYW5hciBlbCBUb3VyKioiKSwgc3VidGl0bGUgPSBtZCgiQ2ljbGlzbW8gbW9kZXJubyIpKSAlPiUNCiAgZ3Q6OnRhYl9vcHRpb25zKGhlYWRpbmcuYmFja2dyb3VuZC5jb2xvciA9ICIjZTIyODJlIikgJT4lDQogIGd0Ojp0ZXh0X3RyYW5zZm9ybShsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBjKE5hY2lvbmFsaWRhZCkpLA0KICAgICAgICAgICAgICAgICAgICAgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OndlYl9pbWFnZSh4LCBoZWlnaHQgPSAzNSApfSkgJT4lDQogIGd0Ojp0ZXh0X3RyYW5zZm9ybShsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBjKEVxdWlwbykpLA0KICAgICAgICAgICAgICAgICAgICAgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OndlYl9pbWFnZSh4LCBoZWlnaHQgPSA3MCApfSkNCg0KDQpgYGANCg0KOjo6DQoNCjo6OiB7LmNvbHVtbiB3aWR0aD0iMSUifQ0KPCEtLSBhbiBlbXB0eSBEaXYgKHdpdGggYSB3aGl0ZSBzcGFjZSkgaGFjaWVuZG8gZGUgc2VwYXJhZG9yIC0tPg0KOjo6DQoNCjo6OiB7LmNvbHVtbiB3aWR0aD0iNDclIn0NCg0KYGBge3J9DQoNCiNHcmFmaWNhIHAyMyBHYW5hZG9yIG1hcyBtYXlvciB0b3VyIGRlIEZyYW5jaWEgbW9kZXJubw0KDQpuYWNpb25hbGlkYWQxIDwtICgiaW1hZ2VuZXMvYXVzdHJhbGlhLnBuZyIpDQplcXVpcG8xIDwtICgiaW1hZ2VuZXMvYm1jLnBuZyIpDQoNCg0KDQpnYW5hZG9yX21heW9yX2FjdHVhbCA8LSB0ZGZfd2lubmVycyAlPiUNCiAgZmlsdGVyKGVkaXRpb24gPj0gNTcpICU+JQ0KICBzbGljZV9tYXgoYWdlLCBuPTEpICU+JQ0KICBtdXRhdGUoeWVhcj0geWVhcihzdGFydF9kYXRlKSkgJT4lDQogIHNlbGVjdChlZGl0aW9uLCB5ZWFyLCB3aW5uZXJfbmFtZSwgYWdlKSAlPiUNCiAgYWRkX2NvbHVtbihuYWNpb25hbGlkYWQxKSAlPiUNCiAgYWRkX2NvbHVtbihlcXVpcG8xKSAlPiUNCiAgcmVuYW1lKEVkaWNpb24gPSAiZWRpdGlvbiIgLA0KICAgICAgICAgQcOxbyA9ICJ5ZWFyIiAsDQogICAgICAgICBOb21icmUgPSAid2lubmVyX25hbWUiICwNCiAgICAgICAgIE5hY2lvbmFsaWRhZCA9ICJuYWNpb25hbGlkYWQxIiAsDQogICAgICAgICBFZGFkID0gImFnZSIgLA0KICAgICAgICAgRXF1aXBvID0gImVxdWlwbzEiICkNCg0KDQpnYW5hZG9yX21heW9yX2FjdHVhbCAlPiUgZ3QoKSAlPiUgDQogIGd0Ojp0YWJfaGVhZGVyKHRpdGxlID0gbWQoIioqQ29ycmVkb3IgbcOhcyBtYXlvciBlbiBnYW5hciBlbCBUb3VyKioiKSwgc3VidGl0bGUgPSBtZCgiQ2ljbGlzbW8gbW9kZXJubyIpKSAlPiUNCiAgZ3Q6OnRhYl9vcHRpb25zKGhlYWRpbmcuYmFja2dyb3VuZC5jb2xvciA9ICIjZTIyODJlIikgJT4lDQogIGd0Ojp0ZXh0X3RyYW5zZm9ybShsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBjKE5hY2lvbmFsaWRhZCkpLA0KICAgICAgICAgICAgICAgICAgICAgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OndlYl9pbWFnZSh4LCBoZWlnaHQgPSAzNSApfSkgJT4lDQogIGd0Ojp0ZXh0X3RyYW5zZm9ybShsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBjKEVxdWlwbykpLA0KICAgICAgICAgICAgICAgICAgICAgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OndlYl9pbWFnZSh4LCBoZWlnaHQgPSA3MCApfSkNCg0KYGBgDQoNCjo6Og0KDQoNCjxicj4NCg0KIyMjIDYuMy4gUGFyw61zIG51bmNhIGZhbHRhIGEgbGEgY2l0YQ0KDQoNCjo6OiB7LmNvbHVtbiB3aWR0aD0iNDclIn0NCg0KYGBge3J9DQoNCiMgdGFibGEgY2l1ZGFkYWRlcyBzYWxpZGFzDQoNCg0KZXRhcGFzX2VzcGFub2wgPC0gdGRmX3N0YWdlcyAlPiUNCiAgcmVuYW1lKGV0YXBhID0gIlN0YWdlIiAsDQogICAgICAgICBmZWNoYSA9ICJEYXRlIiAsDQogICAgICAgICBkaXN0YW5jaWEgPSAiRGlzdGFuY2UiICwNCiAgICAgICAgIG9yaWdlbiA9ICJPcmlnaW4iICwNCiAgICAgICAgIGZpbmFsID0gIkRlc3RpbmF0aW9uIiAsDQogICAgICAgICB0aXBvID0gIlR5cGUiICwNCiAgICAgICAgIGdhbmFkb3IgPSAiV2lubmVyIiAsDQogICAgICAgICBuYWNpb25hbGlkYWQgPSAiV2lubmVyX0NvdW50cnkiICwpICU+JQ0KICBzZWxlY3QoZXRhcGEsIGZlY2hhLCBkaXN0YW5jaWEsIG9yaWdlbiwgZmluYWwsIHRpcG8sIGdhbmFkb3IsIG5hY2lvbmFsaWRhZCkNCg0KDQoNCnRhYmxhX29yaWdlbiA8LSBldGFwYXNfZXNwYW5vbCAlPiUNCiAgZ3JvdXBfYnkob3JpZ2VuKSAlPiUNCiAgc3VtbWFyaXNlKHNhbGlkYXMgPSBuKCkpICU+JQ0KICBzbGljZV9tYXgoc2FsaWRhcywgbiA9IDEwKSAlPiUNCiAgcmVuYW1lKGNpdWRhZCA9ICJvcmlnZW4iKQ0KDQoNCg0KdGFibGFfb3JpZ2VuICU+JSBndCgpICU+JSANCiAgZ3Q6OnRhYl9oZWFkZXIodGl0bGUgPSBtZCgiKipDaXVkYWRlcyBxdWUgbcOhcyBoYW4gc2lkbyBpbmljaW8gZGUgZXRhcGEqKiIpLCBzdWJ0aXRsZSA9IG1kKCIiKSkgJT4lDQogIGd0Ojp0YWJfb3B0aW9ucyhoZWFkaW5nLmJhY2tncm91bmQuY29sb3IgPSAiI2UwZTBlMCIsIGNvbHVtbl9sYWJlbHMuZm9udC53ZWlnaHQgPSAiYm9sZCIsIGNvbHVtbl9sYWJlbHMuYmFja2dyb3VuZC5jb2xvciA9ICIjZWVlZWVlIikNCg0KYGBgDQoNCg0KOjo6DQoNCjo6OiB7LmNvbHVtbiB3aWR0aD0iMSUifQ0KPCEtLSBhbiBlbXB0eSBEaXYgKHdpdGggYSB3aGl0ZSBzcGFjZSkgaGFjaWVuZG8gZGUgc2VwYXJhZG9yIC0tPg0KOjo6DQoNCjo6OiB7LmNvbHVtbiB3aWR0aD0iNDclIn0NCg0KYGBge3J9DQoNCiN0YWJsYXMgY2l1ZGFkIGZpbmFsZXMNCg0KDQpldGFwYXNfZXNwYW5vbCA8LSB0ZGZfc3RhZ2VzICU+JQ0KICByZW5hbWUoZXRhcGEgPSAiU3RhZ2UiICwNCiAgICAgICAgIGZlY2hhID0gIkRhdGUiICwNCiAgICAgICAgIGRpc3RhbmNpYSA9ICJEaXN0YW5jZSIgLA0KICAgICAgICAgb3JpZ2VuID0gIk9yaWdpbiIgLA0KICAgICAgICAgZmluYWwgPSAiRGVzdGluYXRpb24iICwNCiAgICAgICAgIHRpcG8gPSAiVHlwZSIgLA0KICAgICAgICAgZ2FuYWRvciA9ICJXaW5uZXIiICwNCiAgICAgICAgIG5hY2lvbmFsaWRhZCA9ICJXaW5uZXJfQ291bnRyeSIgLCkgJT4lDQogIHNlbGVjdChldGFwYSwgZmVjaGEsIGRpc3RhbmNpYSwgb3JpZ2VuLCBmaW5hbCwgdGlwbywgZ2FuYWRvciwgbmFjaW9uYWxpZGFkKQ0KDQoNCg0KdGFibGFfZmluYWwgPC0gZXRhcGFzX2VzcGFub2wgJT4lDQogIGdyb3VwX2J5KGZpbmFsKSAlPiUNCiAgc3VtbWFyaXNlKGZpbmFsZXMgPSBuKCkpJT4lDQogIHNsaWNlX21heChmaW5hbGVzLCBuID0gMTApJT4lDQogIHJlbmFtZShjaXVkYWQgPSAiZmluYWwiICkgJT4lDQogIGZpbHRlcihjaXVkYWQgIT0gIkNhZW4iKQ0KDQoNCnRhYmxhX2ZpbmFsICU+JSBndCgpICU+JSANCiAgZ3Q6OnRhYl9oZWFkZXIodGl0bGUgPSBtZCgiKipDaXVkYWRlcyBxdWUgbcOhcyBoYW4gc2lkbyBmaW5hbCBkZSBldGFwYSoqIiksIHN1YnRpdGxlID0gbWQoIiIpKSAlPiUNCiAgZ3Q6OnRhYl9vcHRpb25zKGhlYWRpbmcuYmFja2dyb3VuZC5jb2xvciA9ICIjZTBlMGUwIiwgY29sdW1uX2xhYmVscy5mb250LndlaWdodCA9ICJib2xkIiwgY29sdW1uX2xhYmVscy5iYWNrZ3JvdW5kLmNvbG9yID0gIiNlZWVlZWUiKQ0KDQpgYGANCg0KDQo6OjoNCg0KPGJyPg0KDQoNCiMjIDcuIENvbmNsdXNpb25lcw0KDQpBbCB0cmF0YXJzZSBkZWwgdHJhYmFqbyBpbmRpdmlkdWFsIHkgeWEgaGFiZXIgcmVhbGl6YWRvIGFudGVyaW9ybWVudGUgZWwgZ3J1cGFsIGhlIHBvZGlkbyBwb25lciBlbiBwcmFjdGljYSBtdWNoYXMgZGUgbGFzIGNvc2FzIHF1ZSBoZSBhcHJlbmRpZG8gZW4gZXN0ZSwgcG9yIHVuYSBwYXJ0ZSBtZSBoYSBwZXJtaXRpZG8gc2VyIG11Y2hvIG3DoXMgw6FnaWwgeSByw6FwaWRvIGEgbGEgaG9yYSBkZSBlbGFib3JhciBncsOhZmljYXMsIG1hbmlwdWxhciBkYXRvcyBjb24gZHBseXIsIGVudHJlIG90cm9zIGFzcGVjdG9zIHkgcG9yIG90cm8gbGFkbyBtZSBoYSBzZXJ2aWRvIHBhcmEgYWZpYW56YXIgY29uY2VwdG9zIGNvbW8gbGEgY3JlYWNpw7NuIGRlIHRhYmxhcy4NCkEgZGlmZXJlbmNpYSBkZWwgYW50ZXJpb3IgdHJhYmFqbyBlc3RhIHZleiBtZSBoZSBiYXNhZG8gZW4gMyBkYXRhZnJhbWVzIHNvYnJlIGVsIHRvdXIgZGUgRnJhbmNpYSBxdWUgZXN0YWJhbiBtdXkgY29tcGxldG9zLCBlc3RvIG1lIGhhIHBlcm1pdGlkbyBhZ2lsaXphciBlbCBwcm9jZXNvIGRlIHRyYWJham8gY29uIGxvcyBkYXRvcyB5IGhhIHNpZG8gZGUgbXV5IGdyYW4gYXl1ZGEgcG9ycXVlIGVuIGFsZ3VuYXMgb2Nhc2lvbmVzIG1lIGhhIHBlcm1pdGlkbyBpbnNwaXJhcm1lIGVuIHRyYWJham9zIHlhIHJlYWxpemFkb3MgcG9yIGxhIGNvbXVuaWRhZCBSLCBzaWVtcHJlIGhlIGludGVudGFkbyBhw7FhZGlyIHVuIHBsdXMgYSBlc29zIGdyw6FmaWNvcyBhcG9ydGFuZG8gbWkgZ3Jhbml0byBkZSBhcmVuYSwgYXPDrSBxdWUgbWUgc2llbnRvIG11eSBjb250ZW50byBjb24gZWwgcmVzdWx0YWRvIG9idGVuaWRvLg0KDQo8YnI+DQoNCkVuIGN1YW50byBhbCB0ZW1hIG1lIGhhIHJlc3VsdGFkbyBtdXkgYW1lbm8geWEgcXVlIG1lIGhlIGVudHJldGVuaWRvIG11Y2hvIG9ic2VydmFuZG8gZGF0b3MgZGUgY29ycmVkb3JlcywgZXMgY2llcnRvIHF1ZSBtdWNoYXMgZGUgbGFzIGNvc2FzIHlhIGxhcyBjb25vY8OtYSwgcGVybyBhbGd1bmFzIG90cmFzIGNvc2FzIG5vIHkgcG9yIGxvIHRhbnRvIGVzdG95IHNhdGlzZmVjaG8gZGUgaGFiZXIgZWxlZ2lkbyBlc3RlIHRlbWEuIENvbW8gY29uY2x1c2nDs24gYSBlc3RlIHBvY28gdGVuZ28gcXVlIGHDsWFkaXIgbyB2YWxvcmFyIGEgcmHDrXogZGUgbG9zIHJlc3VsdGFkb3Mgb2J0ZW5pZG9zLCBzb2xvIGNvbW8gdmFsb3JhY2nDs24gZmluYWwgbWUgZ3VzdGFyw61hIG1lbmNpb25hciBxdWUgb2phbMOhIGVuIHVub3MgYcOxb3MgcHVlZGEgcmVhbGl6YXIgZWwgbWlzbW8gdHJhYmFqbywgcGVybyBoYWJsYW5kbyBkZSBjaWNsaXNtbyBmZW1lbmlubyB5YSBxdWUgZXN0ZSBlc3TDoSBlbXBlemFuZG8gYSBleHBsb3RhciB5IHByb21ldGUgbXVjaG8sIHBlcm8gZXMgdW5hIHBlbmEgcXVlIGEgZMOtYSBkZSBob3kgbWUgaGF5YSByZXN1bHRhZG8gbXV5IGRpZsOtY2lsIHNpbm8gaW1wb3NpYmxlIGVuY29udHJhciBkYXRvcyBvIGluZm9ybWFjacOzbiBzb2JyZSBlc3RlLiBFc3RvIGVzIHRvZG8geSBlc3Blcm8gcXVlIG9zIGhheWEgZ3VzdGFkbyB5IHF1acOpbiBzYWJlIHNpIGEgcGFydGlyIGRlIGFob3JhIG9zIGFmaWNpb27DoWlzIGFsIGNpY2xpc21vIHNpbm8gbG8gZXN0YWJhaXMgeWEuDQoNCjxicj4NCg0KIyMgOC4gUmVmZXJlbmNpYXMNCg0KRW4gbGEgbWF5b3LDrWEgZGUgb2Nhc2lvbmVzIHRvZG9zIGxvcyBjb21lbnRhcmlvcyByZWFsaXphZG9zIGFsIHJlc3BlY3RvIGhhbiBzaWRvIHBvciBtaSBwcm9waWEgZXhwZXJpZW5jaWEsIHBlcm8gZW4gYWxndW5hIG9jYXNpw7NuIGhlIGJ1c2NhZG8gaW5mb3JtYWNpw7NuIGVuIGFsZ8O6biBibG9nIG8gcMOhZ2luYSBvZmljaWFsIGNvbW8gcG9yIGVqZW1wbG86DQoNCi0gPGEgaHJlZj0iaHR0cHM6Ly93d3cucHJvY3ljbGluZ3N0YXRzLmNvbSI+d3d3LnByb2N5Y2xpbmdzdGF0cy5jb208L2E+DQoNCi0gPGEgaHJlZj0iaHR0cHM6Ly93d3cubGV0b3VyLmZyL2VzLyI+d3d3LmxldG91ci5mci9lcy88L2E+DQoNCi0gPGEgaHJlZj0iaHR0cHM6Ly93d3cud2Vsb3ZlY3ljbGluZy5jb20vZXMvIj53d3cud2Vsb3ZlY3ljbGluZy5jb20vZXMvPC9hPg0KDQotIDxhIGhyZWY9Imh0dHBzOi8vd3d3LmNpY2xpc21vYWZvbmRvLmVzLyI+d3d3LmNpY2xpc21vYWZvbmRvLmVzLzwvYT4NCg0KUGFyYSBsYSByZWFsaXphY2nDs24gZGVsIHRyYWJham8gaGUgdXRpbGl6YWRvcyBsb3MgZGF0YWZyYW1lcyBkZWwgdXN1YXJpbyBbYWxhc3RhaXJydXNod29ydGhdKGh0dHBzOi8vZ2l0aHViLmNvbS9hbGFzdGFpcnJ1c2h3b3J0aC90ZGYpLCBxdWUgaGEgc2lkbyBlbCBlbmNhcmdhZG8gZGUgcmVjb3BpbGFyIGxvcyBkYXRvcyBwYXJhIGVsIFt0aWR5dHVlc2RheV0oaHR0cHM6Ly9naXRodWIuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9ibG9iL21hc3Rlci9kYXRhLzIwMjAvMjAyMC0wNC0wNy9yZWFkbWUubWQpIGRlbCAyMDIwLTA0LTA3IGRlZGljYWRvIGFsIFRvdXIgZGUgRnJhbmNpYS4NCg0KRW4gbGEgcmVhbGl6YWNpw7NuIGRlIGxhIHRhYmxhIGRlIFttw6F4aW1vcyBnYW5hZG9yZXNdKGh0dHBzOi8vYmpubm93YWsubmV0bGlmeS5hcHAvMjAyMS8xMC8wNC9yLWJlYXV0aWZ1bC10YWJsZXMtd2l0aC1ndC1hbmQtZ3RleHRyYXMvKSBoZSB1dGlsaXphZG8gZWwgYmxvZyBkZWwgdXN1YXJpbyBCZW5qYW1pbiBOb3dhayBzb2JyZSBsYXMgdGFibGFzIHtndH0geSB7Z3RFeHRyYXN9Lg0KDQpBZGVtw6FzLCBhIGxhIGhvcmEgZGUgcmVhbGl6YXIgYWxndW5vcyBncsOhZmljb3MgbWUgaGUgaW5zcGlyYWRvIGVuIGFsZ3Vub3MgeWEgZXhpc3RlbnRlcyBjb21vIHBvciBlamVtcGxvIGxvcyBkZSBbQW5kcsOpIFdhYWdlIFJpdmVuw6ZzXShodHRwczovL3d3dy5hbmRyZXdhYWdlLmNvbS9wb3N0L2FuYWx5emluZy10b3VyLWRlLWZyYW5jZS1kYXRhLyksIG8gbG9zIGRlIGxvcyB1c3VhcmlvcyBkZSB0d2l0dGVyIFtAYXJpYW1zaXRhXShodHRwczovL3R3aXR0ZXIuY29tL2FyaWFtc2l0YSkgeSBbQEpha2VfTGF3bG9yMV0oaHR0cHM6Ly90d2l0dGVyLmNvbS9KYWtlX0xhd2xvcjEpDQoNClkgY29tbyBubyBwb2TDrWEgc2VyIGRlIG90cmEgZm9ybWEgbGEgcMOhZ2luYSBbVGhlIFIgR3JhcGggR2FsbGVyeV0oaHR0cHM6Ly93d3cuci1ncmFwaC1nYWxsZXJ5LmNvbS9pbmRleC5odG1sKSBoYSBzaWRvIHVuYSB2ZXogbcOhcyB1bmEgZ3JhbiBmdWVudGUgZGUgaW5zcGlyYWNpw7NuIA0KDQpQb3Igw7psdGltbywgVGFtYmnDqW4gbWUgaGUgY29uc3VsdGFkbyBhbGd1bm9zIGFzcGVjdG9zIGRlIGxvcyB0cmFiYWpvcyBncnVwYWxlcyBkZSBlc3RlIGHDsW8uIEVzdG9zIMO6bHRpbW9zIGxvcyBwb2RlbW9zIGVuY29udHJhciBbYXF1aV0oaHR0cHM6Ly9wZXJlenA0NC5naXRodWIuaW8vaW50cm8tZHMtMjEtMjItd2ViLzA3LXRyYWJham9zLmh0bWwpIA0KDQotLS0tLS0tLS0tLS0tLS0tDQoNCjxicj4=