Trabajo elaborado para la asignatura “Programación y manejo de datos en la era del Big Data” de la Universitat de València durante el curso 2020-2021. El repo del trabajo está aquí. La página web de la asignatura y los trabajos de mis compañeros pueden verse aquí.


1. Introducción

Este tabajo me ha ayudado ha conocer algunos datos curiosos osbre mi hobby favorito como es el futbol. Hacer el trabajo sobre este deporte ma ha ayduado a que me interese más la realización del trabajo.

Por una parte, voy a hablar de algunos datos de Laliga centrandome principalmente en los máximos goleadores históricos. Más tarde también me centraré en datos sobre los campeones de liga. Por último, pasaré a datos sobre los goleadores 4 grandes ligas (Laliga, Bundesliga, Premier League y la Serie A).

Copa

2. Datos

Los datos son procedentes de varios repositorios de Github, donde he tenido varios problemas a la hora de seleccionar y trasformar, ya que muchos nombres de los jugadores y equipos no son aceptados correctamente debido a los acentos, diéresis…
Los datos están en formato Excel y he conseguido extraer varios data frames. A parte de estps, había encontrado otros por internet, pero estaban muy mal estructurados y a la hora de manejarlos se me hacía imposible.

goleadores_laliga <- rio::import(here::here("./datos/goles_total_laliga.csv"))
goleadores_ligas_top<- rio::import(here::here("./datos/goles_ligas_top.csv"))
estadisticas_jugadores<- rio::import(here::here("./datos/estadisticas_jugadores.csv"))
clasificacion<- rio::import(here::here("./datos/clasificacion_total.csv"))
campeones<- rio::import(here::here("./datos/La_Liga_Winners.csv"))

#Tabla campeones
campeones <- campeones %>% mutate(Winner = case_when(
Winner==  "Atlético Madrid" ~ "Átletico de Madird",
Winner == "Atlético Aviación[a]" ~ "Átletico de Madrid",
Winner == "Deportivo La Coruña" ~ "Deportivo de La Coruña",
TRUE ~ Winner))
#Tabla goleadores
goleadores_laliga$Total = rowSums (goleadores_laliga[ , 4:32])

3. Goleadores

En esta parte del tabajo voy a tratar de mostrar una serie de datos curiosos de los máximos goleadores de la liga desde el 1990 hasta día de hoy; también dedicaré un tramo para mostrar datos de los máximos goleadores de las grandes ligas europeas.

goleadores_laliga <- rio::import(here::here("./datos/goles_total_laliga.csv"))
goleadores_laliga$Total = rowSums (goleadores_laliga[ , 4:32])

En primer lugar vamos a observar quien es el jugador con más goles en la historia de Laliga:

goleadores_laliga <- rio::import(here::here("./datos/goles_total_laliga.csv"))

library (tidyverse)
library(gganimate)



goleadores_laliga$Total = rowSums (goleadores_laliga[ , 4:32])

goleadores_laliga <- goleadores_laliga %>% mutate(Player = case_when(
  Player==  "Raúl" ~ " Raúl ",
  TRUE ~ Player))

Imagen<-"https://upload.wikimedia.org/wikipedia/commons/b/b8/Messi_vs_Nigeria_2018.jpg"



Messi <- goleadores_laliga  %>% slice_max(Total, n = 1) %>% select(Player|Total)

Messi <- Messi %>% add_column(Imagen)

library(gt)
Messi <- Messi %>% gt()

Messi <- Messi %>%
                   tab_header(title = md("**Jugador con más goles en LaLiga**"), subtitle= md("Hasta la temporada 2018/2019"))
Messi <- Messi %>%
                tab_options(heading.background.color = "black") %>% tab_options(heading.title.font.size = 18, heading.subtitle.font.size = 13,  column_labels.font.weight =  "bold")


Messi <- Messi  %>%
  gt::text_transform(locations = cells_body(columns = vars(Imagen)), fn = function(x) {gt::web_image(x, height = 70)}) %>%  cols_align(
    align = "center")
Jugador con más goles en LaLiga
Hasta la temporada 2018/2019
Player Total Imagen
Lionel Messi 419

Claramente el máximo goleador histórico es Lionel Messi con un total de 419 goles desde su debut en la temporada 2004/2005 hasta la temporada 2018/2019.

library (tidyverse)
library(gganimate)
goleadores_laliga <- rio::import(here::here("./datos/goles_total_laliga.csv"))
goleadores_laliga$Total = rowSums (goleadores_laliga[ , 4:32])

goleadores_laliga <- goleadores_laliga %>% mutate(Player = case_when(
  Player==  "Raúl" ~ " Raúl ",
  TRUE ~ Player))
goleadores_laliga2 <- goleadores_laliga  %>%  slice_max(Total, n = 5) 

topg<- goleadores_laliga2 %>% 
  tidyr::pivot_longer(cols = 4:32, names_to = "Temporada")


a<-ggplot(topg, aes(Temporada , value , color=Player, fill=Player))+ geom_bar(stat = "identity")+  coord_flip()+  labs(title = "Evolución de goles por temporada de los 5 máximos goleadores de España", subtitle = "Desde la temporada 90/91 a la 18/19",  x = "Goles", x = "Año")
a

Este gráfico tendría que ser animado, pero a la hora de knittear no se llega a cargar, en formato.r si que iba sin problema, pero a la hora de pasar a rmd y poner la función transition_states no carga. El gráfico nos muestra la evolución de cantidad de goles de los 5 máximos goleadores históricos de Laliga desde el año 1990 hasta el 2019. Estos son Messi, Cristiano Ronaldo, Raúl, Eto’o y Villa.

El gráfico nos muestra la cantidad de goles que ha maracado cada jugadore en cada año. Esta tabla está animada por el paquete gganimate, a través de la función transition_states.

map<- goleadores_laliga %>% group_by(Country) %>%  summarize(Paises = n()) 


library("rnaturalearth")
library("rnaturalearthdata")
library("rgeos")

world <- ne_countries(scale = "medium", returnclass = "sf")

world <- world %>% filter(subregion != "Antarctica") %>% filter(admin != "Greenland")
x<-ggplot() + geom_sf(data = world) + theme_void()
world <- world %>% select(name, iso_a3, geometry)


df_world <- left_join(map, world, by = c("Country" = "name") ) 

m<-ggplot(df_world) + geom_sf(aes(geometry = geometry, fill = Paises)) + scale_fill_viridis_c(option = "plasma", trans = "sqrt")+ labs(title = "Número de goleadores por cada país de LaLiga", caption = "Datos de Github",subtitle = "Datos desde la temporada 87/88 a la 18/19")

Más tarde, he elaborado un mapa, que nos muestra la cantidad de goleadores de Laliga que ha habido en cada país desde la temporada 1990.
Claramente, el país que más goleadores ha aportado es España, más tarde, destacan otros países como Francia, Brasil o Argentina.
Para la elaboración de este mapa, he cogido los datos de cada temporada, y he agrupado los datos por el país del que viene cada futbolista. Más tarde obtenido los datos espacilaes de la practica 5 de calse, en el que había un mapa del mundo espacial con los paquetes “rnaturalearth”, “rnaturalearthdata” y “rgeos”. Después he unido estas dos tablas y he creado el gráfico.


2.1 Máximos goleadores de las grandes ligas europeas

Esta parte del trabajo la vamos a centrar en los máximos goleadores de fútbol europeo en los últimos 20 años.

goleadores_ligas_top<- rio::import(here::here("./datos/goles_ligas_top.csv"))
library (tidyverse)
library(gganimate)

goleadores_ligas_top <- goleadores_ligas_top %>% mutate(Player = case_when(
  Player==  "Raúl" ~ " Raúl ",
  Player==  "Zlatan Ibrahimović" ~ " Zlatan Ibrahimović ",
  TRUE ~ Player))


goleadores_ligas_top$Total = rowSums (goleadores_ligas_top[ , 2:30])

goleadores_top <- goleadores_ligas_top  %>%  slice_max(Total, n = 6) 

mejor<- goleadores_top %>% 
  tidyr::pivot_longer(cols = 2:30, names_to = "Temporada")


gr<-ggplot(mejor , aes(Temporada , value,  group= Player, color = Player))  + geom_line() + facet_wrap(vars(Player), nrow = 2, ncol = 3)+  labs(title = "Evolución de goles por temporada de los 6 máximos goleadores de Europa", subtitle = "Desde la temporada 90/91 a la 18/19",  x = "Goles", x = "Año") +  theme(legend.position = "none")+ theme( axis.text.x=element_blank()) 




grafico_a <- ggplot(mejor, aes(Player, Total,   fill = Player , color= "blue")) +  scale_fill_brewer(palette="Spectral") + geom_bar(stat = "identity")+ 
  labs(title = "Máximos goleadores Ligas Top", subtitle = "Desde el 1990 hasta el 2019") + theme(legend.position = "none")

grafico_ap <- grafico_a + 
  geom_text(aes(y=Total, 
                label =Total), position = position_dodge(width = 0.8), 
            size = 3.2, vjust=3, col = "Black")

Aquí he recogido los datos y los he agrupado en un sumatorio de todos los goles de las últimas temporadas. Podemos observar que los dos jugadores que destacan por encima del resto son Leo Messi y Cristiano Ronaldo (el cual le cogen los datos de Laliga y de la Serie A (Italia)), estos dos animales han anotado la friolera cantidad de 419 y 416 goles respectivamente en las ligas que han jugado.

El gráfico es de barras pero tiene la diferencia de que he añadido el número de goles que han anotado debajo de las barras con geom_text.

Este, muestra la evolución de goles que han anotado los 6 máximos goleadores de los últimos 20 años en cada temporada.

Es un gráfico de lineas que está unido a través de un facet_wrap diferenciando cada jugador. En este gráfico he tenido la dificultad de ajustar bien el texto del eje x(las difernetes temporadas), finalmente he quitado el número de las temporadas debido a que salía mal.

4. Campeones

En este apartado voy a enseñaros una serie de curiosidades sobre la historia de la liga española.


Aquí se puede observar una tabla que nos muestra todos los campeones de Laliga desde que se creó esta, cabe destacar que del 1936-1939, fue suspendida por la guerra civil. También nos muestra, los segundos y terceros clasificados; así como, el máximo goleador de cada año y cuantos goles hizo este.


equipo<- campeones %>% group_by(Winner)%>%filter(!(Season %in% c("1936/37", "1937/38","1938/39")) ) %>%   summarize(Ligas = n()) %>% 
  arrange(desc(Ligas))
 
rm<- equipo  %>%  slice_max(Ligas, n = 1) 

Escudo<-"https://www.ecured.cu/images/thumb/c/c6/428px-logo_real_madrid_svg1_copia.jpg/260px-428px-logo_real_madrid_svg1_copia.jpg"
rm <- rm %>% add_column(Escudo)

library(gt)
rm <- rm %>% gt()

rm <- rm %>%
                   tab_header(title = md("**Equipo con más Ligas**"), subtitle= md("Hasta la temporada 2019/2020"))
rm <- rm %>%
                tab_options(heading.background.color = "black") %>% tab_options(heading.title.font.size = 18, heading.subtitle.font.size = 13,  column_labels.font.weight =  "bold")


rm <- rm  %>%
  gt::text_transform(locations = cells_body(columns = vars(Escudo)), fn = function(x) {gt::web_image(x, height = 70)}) %>%  cols_align(
    align = "center")

Equipo con más Ligas
Hasta la temporada 2019/2020
Winner Ligas Escudo
Real Madrid 34
Aquí podemos observar que el equipo más laureado de la historia de la liga española es el Real Madrid Club de fútbol con 34 ligas.


equipo<- campeones %>% group_by(Winner)%>%filter(!(Season %in% c("1936/37", "1937/38","1938/39")) ) %>%  
  summarize(Ligas = n()) %>% 
  arrange(desc(Ligas))
 
queso<-ggplot(equipo, aes("", Ligas, fill = Winner)) + geom_bar(stat = "identity", color="white") + geom_text(aes(label=Ligas), position = position_stack(vjust=0.5), color = "white", size = 2) + coord_polar(theta = "y") + theme_void() + labs(title="Número de Ligas por equipo") + theme(plot.title = element_text(hjust = 0.5))
queso

anyox<- campeones %>% group_by(Winner)%>%filter(!(Season %in% c("1936/37", "1937/38","1938/39")) )
anyo<- ggplot(anyox, aes(Season , Goals, group=Goals,fill="red")) + geom_bar(stat = "identity")  + labs(x = "Temporada", y = "Goles", title = "Goles por temporada de cada pichichi de LaLiga", caption = "Datos obtenidos de Github")  + theme_bw()   + theme(plot.title = element_text(hjust = 0.5)) +
  theme(axis.text.x = element_text(angle=60, vjust=0.6), panel.background = NULL)+ theme(legend.position = "none")

Este gráfico nos muestra a través de un gráfico circular, la cantidad de ligas que ha ganado cada club de la liga española. El Real Madird encabeza esta lista, por delante del Barcelona (26) y Atlético de Madrid que tiene 8 más 2 cuando se llamaba Atlético aviación.
Para la elaboración de este gráfico primero he tenido que arreglar los datos de los nombres de cada equipo, y más tarde agrupar los datos por cada primera posición que ha había obtenido. A partir de estos datos, he hecho un gráfico de “quesitos”.


En este gráfico vemos como ha evolucionado la cantidad de goles marcados por cada “pichichi” de la liga en cada temporada que se ha realizado esta, es decir, desde el 1929 hasta el 2020 quitando los años de la guerra civil.
Hay que destacar los años donde tanto Messi, como Cristiano Ronaldo han estado pealndo por ser el máximo goleador y se iban a unas cifras realmente altas, en la temporada 2011/2012 Messi llegó a alcanzar los 50 goles en una temporada.

Es un ggplot de barras donde he tenido que girar el angulo del texto del eje x (las temporadas) para que se pudieran ver de manera adecuada.


5. Clasificación

En este apartado voy a mirar algunos datos relevantes sobre la clasificación de la liga en los últimos 30 años, desde la temporada 1987/1988 hasta la temporada 2018/2019.


library (tidyverse)
library(ggThemeAssist)

clasificacion<- rio::import(here::here("./datos/clasificacion_total.csv"))


#Puntos de cada primer clasificado y más partidos ganados
clasificacion_1<- clasificacion %>% filter(Position == 1) 

clasificacion_1<- clasificacion_1 %>% group_by(Points) %>%   arrange(desc(Points))

primero<-ggplot(clasificacion_1, aes(Season , Points , color=Team, fill=Team))+ geom_bar(stat = "identity")+ labs(x = "Temporada", y = "Puntos obtenidos", title = "Puntos por temporada de cada campeón de la Liga",subtitle = "Desde la temporada 87/88 a la 18/19", caption = "Datos obtenidos de Github")  + theme_bw() + scale_y_continuous(labels=function(n){format(n, scientific = FALSE)})  + theme(plot.title = element_text(hjust = 0.5)) +
  theme(axis.text.x = element_text(angle=60, vjust=0.6), panel.background = NULL)


clasificacion_wins <- clasificacion_1 %>%   arrange(desc(Won))

w<-ggplot(clasificacion_1, aes(Season , Won , color=Team, fill=Team))+ geom_bar(stat = "identity") + labs(x = "Temporada", y = "Nº de Partidos Ganados", title = "Partidos ganados por temporada de cada campeón de la Liga",subtitle = "Desde la temporada 87/88 a la 18/19", caption = "Datos obtenidos de Github")  + theme_bw() + scale_y_continuous(labels=function(n){format(n, scientific = FALSE)})  + theme(plot.title = element_text(hjust = 0.5)) +
  theme(axis.text.x = element_text(angle=60, vjust=0.6), panel.background = NULL)


library(gridExtra)  #- install.packages("gridExtra")

l<-grid.arrange(primero, w, nrow= 2)


#> TableGrob (2 x 1) "arrange": 2 grobs
#>   z     cells    name           grob
#> 1 1 (1-1,1-1) arrange gtable[layout]
#> 2 2 (2-2,1-1) arrange gtable[layout]

Aquí, nos hemos centrado en los datos de los primeros clasificados, y en este gráfico observamos la evolución de los puntos de cada primer clasificado así como la cantidad de partidos que ha ganado cada equipo ganador en cada tmeporada.

El gráfico consta de dos gráficos de barras agrupados por el equipo que ha salido campeón. Más tarde a raíz de estos gráficos, los he unido con la función gird.extra del paquete con el mismo nombre.


#Los peores equipos (menos puntos)
clasificacion_peor <- clasificacion %>% slice_min(Points, n = 10) %>% select(!(Conceded|GoalDifference|Team))

#Los que más goles han marcado
clasificacion_goles <- clasificacion %>%   slice_max(Scored, n = 10)%>% select(!(Conceded|GoalDifference|Team))


Equipos con menos puntos obtenidos en liga
Season Position Crest names City Points Matches Won Draw Lost Scored
1994-95 20 CD Logroñés Logroño 13 38 2 9 27 15
1997-98 20 R. Sporting Gijón 13 38 2 7 29 31
1988-89 20 Elche CF Alicante 15 38 4 7 27 29
1989-90 20 Rayo Vallecano Madrid 19 38 6 7 25 32
2014-15 20 Córdoba CF Córdoba 20 38 3 11 24 22
2016-17 20 Granada CF Granada 20 38 4 8 26 30
2017-18 20 Málaga CF Málaga 20 38 5 5 28 24
1989-90 19 RC Celta Vigo 22 38 5 12 21 24
1992-93 19 Cádiz CF Cádiz 22 38 5 12 21 30
1992-93 20 Real Burgos CF Burgos 22 38 4 14 20 29
2016-17 19 CA Osasuna Pamplona 22 38 4 10 24 40
2017-18 19 UD Las Palmas Las Palmas de Gran Canaria 22 38 5 7 26 24

Esta primera tabla, nos muestra los peores equipos de los últimos 30 años en cuanto datos de la puntuación. Los equipos que menos puntos han logrado ene stos 30 años son el Logroñes de la temporada 94/95 y el Sporting de Gijón de la temporada 97/98. Cabe destacar, que el último en unirse a esta lista en la que nadie quiere aparecer esel Málaga de la temporada 2017/2018, con 20 puntos.
Otro de los datos curisosos es que a pesar de ser los peores equipos, hay varios equipos que aparecen en esta lista sin haber quedado el último clasificado de la liga, como es el caso de Las Palmas en el año 17/18; esto supone que hay años en los que las puntuaciones para salvarse y no descender a segunda son más altos que otros.


Equipos con más goles en liga
Season Position Crest names City Points Matches Won Draw Lost Scored
2011-12 1 Real Madrid Madrid 100 38 32 4 2 121
2014-15 2 Real Madrid Madrid 92 38 30 2 6 118
2016-17 2 FC Barcelona Barcelona 90 38 28 6 4 116
2012-13 1 FC Barcelona Barcelona 100 38 32 4 2 115
2011-12 2 FC Barcelona Barcelona 91 38 28 7 3 114
2015-16 1 FC Barcelona Barcelona 91 38 29 4 5 112
2014-15 1 FC Barcelona Barcelona 94 38 30 4 4 110
2015-16 2 Real Madrid Madrid 90 38 28 6 4 110
1989-90 1 Real Madrid Madrid 62 38 26 10 2 107
2016-17 1 Real Madrid Madrid 93 38 29 6 3 106

Aquí, he adjunto otra tabla, pero no tiene nad auqe ver con la anteror, esta muestra los 10 equipos que más goles han marcado en los últimos años. No obstante, se puede ver que todos pertenecen al Real madrid o al Fútbol Club Barcelona. El record de puntos y goles marcados, lo consiguió el Real Madrid de Mourinho en la temporada 2011/2012 xon 100 puntos y 121 goles favor, una auténtica locura. Este récord a día de hoy sigue vigente y me imagino que aún tardará en batirse.


5.1 Equipos que nunca han descendido

Hay 3 equipos en la historia del fútbol español, que jamás ha descendido a segunda división y siempre han permanecido en la categoría de oro. Estos son,por un lado, los que no podían faltar el Real Madrid y el Barça; y por el otro lado el meritorio Athletic Club de Bilbao. Este apartado se centra en los datos de estos tres equipos en los últimos 30 años.

library(gganimate)

clasificacion_mba<- clasificacion %>% filter(`Crest names` == "Real Madrid"|`Crest names` == "FC Barcelona"| `Crest names` == "Athletic Club") 

graficomba <- ggplot(clasificacion_mba, aes(Season, Points, color = `Crest names`, group = `Crest names`)) + geom_line() + geom_point() + theme_light()  + labs(title = "Evolución de puntos obtenidos",subtitle = "Datos desde la temporada 87/88 a la 18/19", caption = "Datos de Github", x = "Temporada", y = "Nº de puntos") +  theme(plot.title = element_text(hjust = 0.5, face = "bold", color = "Coral")) + theme(axis.text.x = element_text(angle=60, vjust=0.6), panel.background = NULL)+ scale_y_continuous(labels=function(n){format(n, scientific = FALSE)})  


library(plotly)




b <- ggplot(clasificacion_mba, aes(Season, Position, fill = Team)) + geom_col(position = "dodge")+  theme(axis.text.x = element_text(angle=90, vjust=0.6), panel.background = NULL)+ labs(title = "Evolución de la posición en LaLiga ", caption = "Datos de Github",subtitle = "Obtenida por los equipos que nunca han descendido", x = "Temporada", y = "Nº de puntos") +  theme(plot.title = element_text(hjust = 0.5, face = "bold", color = "Coral"))   

Este primer gráfico muestra la evolución de la cantidad de puntos que han obtenido estos tres equipos.

Está elaborado a traves de un gráfico de puntos y lineas.


En este gráfico dinámico vemos la posición que ha logrado estos equipos desde la temporada 87/88.
Vemos que las barras del Atlhetic de Bilbao, son mucho más altas ya que al ser un equipo más modesto, muchas veces están lejos de las posiciones de las posiciones cabeceras, por este motivo tiene tanto mérito que nunca hayan descendido.

Es un gráfico de barras que es dinámico gracias al paquete ploty, por lo tanto, si pasas el puntero por encima de las barras, en cada una de ellas, nos dice que posición obtuvo cada equipo en esa temporada.


bilbao

6. Conclusión

Finalmente quiero decir que este trabajo me ha llevado bastante trabajo, aunque gracias al tema elegido se me ha hecho bastnate más llevadero. No sé si el resultado final muestra todo el tiempo que ha supuesto (espero que sí) y espero que os haya gustado.

También me gustaría decir que el trabajo no está inspirado como tal en ningún otro, pero que me he apoyado y me ha ayudado bastante a la hora de resolver varias dudas, el trabajo de eqipo que hice en su día con mis compañeros Noelia y Andreu sobre el Covid.

fin

LS0tDQp0aXRsZTogIkRhdG9zIGludGVyZXNhbnRlcyBzb2JyZSBsYSBoaXN0b3JpYSBkZWwgZnV0Ym9sIGVzcGHDsW9sIg0Kc3VidGl0bGU6ICJJZ25hY2lvIE1vbnRhdmEgKG1vbnBlaWdAYWx1bW5pLnV2LmVzKSIgIy0gcG9uZ28gdMO6IG5vbWJyZSBhaMOtIHBhcmEgcSBhcGFyZXpjYSBtw6FzIGdyYW5kZSBxIGVsIGRlIGxhIFVWDQphdXRob3I6ICJVbml2ZXJzaXRhdCBkZSBWYWzDqG5jaWEiDQpkYXRlOiAiRGljaWVtYnJlIGRlIDIwMjAgKGFjdHVhbGl6YWRvIGVsIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVknKWApIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgICNjc3M6ICIuL2Fzc2V0cy9teV9jc3NfZmlsZS5jc3MiDQogICAgdGhlbWU6IHBhcGVyDQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZSANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDMgDQogICAgdG9jX2Zsb2F0OiANCiAgICAgIGNvbGxhcHNlZDogdHJ1ZQ0KICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQ0KICAgIGRmX3ByaW50OiBrYWJsZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUNCi0tLQ0KDQpgYGB7ciBwYWNrYWdlcy1zZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGtsaXBweSkgICMtIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJybGVzdXIva2xpcHB5IikNCmxpYnJhcnkoa25pdHIpDQpgYGANCg0KYGBge3IgY2h1bmstc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZXZhbCA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICAjcmVzdWx0cyA9ICJob2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICBjYWNoZSA9IEZBTFNFLCBjYWNoZS5wYXRoID0gIi9jYWNoZXMvIiwgY29tbWVudCA9ICIjPiIsDQogICAgICAgICAgICAgICAgICAgICAgI2ZpZy53aWR0aCA9IDcsICNmaWcuaGVpZ2h0PSA3LCAgIA0KICAgICAgICAgICAgICAgICAgICAgICNvdXQud2lkdGggPSA3LCBvdXQuaGVpZ2h0ID0gNywNCiAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZSA9IFRSVUUsICBmaWcuc2hvdyA9ICJob2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYXNwID0gNy85LCBvdXQud2lkdGggPSAiNjAlIiwgZmlnLmFsaWduID0gImNlbnRlciIpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZGV2ID0gInBuZyIsIGRldi5hcmdzID0gbGlzdCh0eXBlID0gImNhaXJvLXBuZyIpKQ0KYGBgDQoNCmBgYHtyIG9wdGlvbnMtc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCm9wdGlvbnMoc2NpcGVuID0gOTk5KSAjLSBwYXJhIHF1aXRhciBsYSBub3RhY2nDs24gY2llbnTDrWZpY2ENCm9wdGlvbnMoInlhbWwuZXZhbC5leHByIiA9IFRSVUUpIA0KYGBgDQoNCg0KYGBge3Iga2xpcHB5LCBlY2hvID0gRkFMU0V9DQprbGlwcHk6OmtsaXBweShwb3NpdGlvbiA9IGMoInRvcCIsICJyaWdodCIpKSAjLSByZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigicmxlc3VyL2tsaXBweSIpDQpgYGANCg0KPGhyIGNsYXNzPSJsaW5lYS1ibGFjayI+DQoNClRyYWJham8gZWxhYm9yYWRvIHBhcmEgbGEgYXNpZ25hdHVyYSAiUHJvZ3JhbWFjacOzbiB5IG1hbmVqbyBkZSBkYXRvcyBlbiBsYSBlcmEgZGVsIEJpZyBEYXRhIiBkZSBsYSBVbml2ZXJzaXRhdCBkZSBWYWzDqG5jaWEgZHVyYW50ZSBlbCBjdXJzbyAyMDIwLTIwMjEuIEVsIHJlcG8gZGVsIHRyYWJham8gZXN0w6EgW2FxdcOtXShodHRwczovL2dpdGh1Yi5jb20vcGVyZXpwNDQvdHJhYmFqb19CaWdEYXRhKXt0YXJnZXQ9Il9ibGFuayJ9LiBMYSBww6FnaW5hIHdlYiBkZSBsYSBhc2lnbmF0dXJhIHkgbG9zIHRyYWJham9zIGRlIG1pcyBjb21wYcOxZXJvcyBwdWVkZW4gdmVyc2UgW2FxdcOtXShodHRwczovL3BlcmV6cDQ0LmdpdGh1Yi5pby9pbnRyby1kcy0yMC0yMS13ZWIvMDctdHJhYmFqb3MuaHRtbCl7dGFyZ2V0PSJfYmxhbmsifS4NCg0KPCEtLSBFbCBww6FycmFmbyBkZSBhcnJpYmEgaGFzIGRlIGRlamFybG8gY2FzaSBpZ3VhbCwgDQogICAgICAgIHNvbG8gSEFTIGRlIFNVU1RJVFVJUiBsYXMgMiB2ZWNlcyBxdWUgYXBhcmVjZSAicGVyZXpwNDQiIHBvciB0dSB1c3VhcmlvIGRlIEdpdGh1Yi0tPg0KDQo8aHIgY2xhc3M9ImxpbmVhLXJlZCI+DQoNCiMgMS4gSW50cm9kdWNjacOzbg0KDQpFc3RlIHRhYmFqbyBtZSBoYSBheXVkYWRvIGhhIGNvbm9jZXIgYWxndW5vcyBkYXRvcyBjdXJpb3NvcyBvc2JyZSBtaSBob2JieSBmYXZvcml0byBjb21vIGVzIGVsIGZ1dGJvbC4gSGFjZXIgZWwgdHJhYmFqbyBzb2JyZSBlc3RlIGRlcG9ydGUgbWEgaGEgYXlkdWFkbyBhIHF1ZSBtZSBpbnRlcmVzZSBtw6FzIGxhIHJlYWxpemFjacOzbiBkZWwgdHJhYmFqby48YnI+DQoNClBvciB1bmEgcGFydGUsIHZveSBhIGhhYmxhciBkZSBhbGd1bm9zIGRhdG9zIGRlIExhbGlnYSBjZW50cmFuZG9tZSBwcmluY2lwYWxtZW50ZSBlbiBsb3MgbcOheGltb3MgZ29sZWFkb3JlcyBoaXN0w7NyaWNvcy4gTcOhcyB0YXJkZSB0YW1iacOpbiBtZSBjZW50cmFyw6kgZW4gZGF0b3Mgc29icmUgbG9zIGNhbXBlb25lcyBkZSBsaWdhLiBQb3Igw7psdGltbywgcGFzYXLDqSBhIGRhdG9zIHNvYnJlIGxvcyBnb2xlYWRvcmVzIDQgZ3JhbmRlcyBsaWdhcyAoTGFsaWdhLCBCdW5kZXNsaWdhLCBQcmVtaWVyIExlYWd1ZSB5IGxhIFNlcmllIEEpLjxicj4NCg0KIVtDb3BhXSguL2ltYWdlbmVzL2NvcGEuanBnKQ0KDQojIDIuIERhdG9zDQoNCkxvcyBkYXRvcyBzb24gcHJvY2VkZW50ZXMgZGUgdmFyaW9zIHJlcG9zaXRvcmlvcyBkZSBHaXRodWIsIGRvbmRlIGhlIHRlbmlkbyB2YXJpb3MgcHJvYmxlbWFzIGEgbGEgaG9yYSBkZSBzZWxlY2Npb25hciB5IHRyYXNmb3JtYXIsIHlhIHF1ZSBtdWNob3Mgbm9tYnJlcyBkZSBsb3MganVnYWRvcmVzIHkgZXF1aXBvcyBubyBzb24gYWNlcHRhZG9zIGNvcnJlY3RhbWVudGUgZGViaWRvIGEgbG9zIGFjZW50b3MsIGRpw6lyZXNpcy4uLiA8YnI+DQpMb3MgZGF0b3MgZXN0w6FuIGVuIGZvcm1hdG8gRXhjZWwgeSBoZSBjb25zZWd1aWRvIGV4dHJhZXIgdmFyaW9zIGRhdGEgZnJhbWVzLiBBIHBhcnRlIGRlIGVzdHBzLCBoYWLDrWEgZW5jb250cmFkbyBvdHJvcyBwb3IgaW50ZXJuZXQsIHBlcm8gZXN0YWJhbiBtdXkgbWFsIGVzdHJ1Y3R1cmFkb3MgeSBhIGxhIGhvcmEgZGUgbWFuZWphcmxvcyBzZSBtZSBoYWPDrWEgaW1wb3NpYmxlLg0KDQpgYGB7ciwgZXZhbCA9IFRSVUV9DQpnb2xlYWRvcmVzX2xhbGlnYSA8LSByaW86OmltcG9ydChoZXJlOjpoZXJlKCIuL2RhdG9zL2dvbGVzX3RvdGFsX2xhbGlnYS5jc3YiKSkNCmdvbGVhZG9yZXNfbGlnYXNfdG9wPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiLi9kYXRvcy9nb2xlc19saWdhc190b3AuY3N2IikpDQplc3RhZGlzdGljYXNfanVnYWRvcmVzPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiLi9kYXRvcy9lc3RhZGlzdGljYXNfanVnYWRvcmVzLmNzdiIpKQ0KY2xhc2lmaWNhY2lvbjwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoIi4vZGF0b3MvY2xhc2lmaWNhY2lvbl90b3RhbC5jc3YiKSkNCmNhbXBlb25lczwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoIi4vZGF0b3MvTGFfTGlnYV9XaW5uZXJzLmNzdiIpKQ0KDQojVGFibGEgY2FtcGVvbmVzDQpjYW1wZW9uZXMgPC0gY2FtcGVvbmVzICU+JSBtdXRhdGUoV2lubmVyID0gY2FzZV93aGVuKA0KV2lubmVyPT0gICJBdGzDg8KpdGljbyBNYWRyaWQiIH4gIsOBdGxldGljbyBkZSBNYWRpcmQiLA0KV2lubmVyID09ICJBdGzDg8KpdGljbyBBdmlhY2nDg8KzblthXSIgfiAiw4F0bGV0aWNvIGRlIE1hZHJpZCIsDQpXaW5uZXIgPT0gIkRlcG9ydGl2byBMYSBDb3J1w4PCsWEiIH4gIkRlcG9ydGl2byBkZSBMYSBDb3J1w7FhIiwNClRSVUUgfiBXaW5uZXIpKQ0KI1RhYmxhIGdvbGVhZG9yZXMNCmdvbGVhZG9yZXNfbGFsaWdhJFRvdGFsID0gcm93U3VtcyAoZ29sZWFkb3Jlc19sYWxpZ2FbICwgNDozMl0pDQoNCg0KYGBgDQoNCg0KDQojIDMuIEdvbGVhZG9yZXMNCkVuIGVzdGEgcGFydGUgZGVsIHRhYmFqbyB2b3kgYSB0cmF0YXIgZGUgbW9zdHJhciB1bmEgc2VyaWUgZGUgZGF0b3MgY3VyaW9zb3MgZGUgbG9zIG3DoXhpbW9zIGdvbGVhZG9yZXMgZGUgbGEgbGlnYSBkZXNkZSBlbCAxOTkwIGhhc3RhIGTDrWEgZGUgaG95OyB0YW1iacOpbiBkZWRpY2Fyw6kgdW4gdHJhbW8gcGFyYSBtb3N0cmFyIGRhdG9zIGRlIGxvcyBtw6F4aW1vcyBnb2xlYWRvcmVzIGRlIGxhcyBncmFuZGVzIGxpZ2FzIGV1cm9wZWFzLg0KDQoNCmBgYHtyfQ0KZ29sZWFkb3Jlc19sYWxpZ2EgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiLi9kYXRvcy9nb2xlc190b3RhbF9sYWxpZ2EuY3N2IikpDQpnb2xlYWRvcmVzX2xhbGlnYSRUb3RhbCA9IHJvd1N1bXMgKGdvbGVhZG9yZXNfbGFsaWdhWyAsIDQ6MzJdKQ0KDQpgYGANCg0KDQpFbiBwcmltZXIgbHVnYXIgdmFtb3MgYSBvYnNlcnZhciBxdWllbiBlcyBlbCBqdWdhZG9yIGNvbiBtw6FzIGdvbGVzIGVuIGxhIGhpc3RvcmlhIGRlIExhbGlnYToNCg0KYGBge3IsIGV2YWwgPSBUUlVFfQ0KZ29sZWFkb3Jlc19sYWxpZ2EgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiLi9kYXRvcy9nb2xlc190b3RhbF9sYWxpZ2EuY3N2IikpDQoNCmxpYnJhcnkgKHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2dhbmltYXRlKQ0KDQoNCg0KZ29sZWFkb3Jlc19sYWxpZ2EkVG90YWwgPSByb3dTdW1zIChnb2xlYWRvcmVzX2xhbGlnYVsgLCA0OjMyXSkNCg0KZ29sZWFkb3Jlc19sYWxpZ2EgPC0gZ29sZWFkb3Jlc19sYWxpZ2EgJT4lIG11dGF0ZShQbGF5ZXIgPSBjYXNlX3doZW4oDQogIFBsYXllcj09ICAiUmHDg8K6bCIgfiAiIFJhw7psICIsDQogIFRSVUUgfiBQbGF5ZXIpKQ0KDQpJbWFnZW48LSJodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9jb21tb25zL2IvYjgvTWVzc2lfdnNfTmlnZXJpYV8yMDE4LmpwZyINCg0KDQoNCk1lc3NpIDwtIGdvbGVhZG9yZXNfbGFsaWdhICAlPiUgc2xpY2VfbWF4KFRvdGFsLCBuID0gMSkgJT4lIHNlbGVjdChQbGF5ZXJ8VG90YWwpDQoNCk1lc3NpIDwtIE1lc3NpICU+JSBhZGRfY29sdW1uKEltYWdlbikNCg0KbGlicmFyeShndCkNCk1lc3NpIDwtIE1lc3NpICU+JSBndCgpDQoNCk1lc3NpIDwtIE1lc3NpICU+JQ0KICAgICAgICAgICAgICAgICAgIHRhYl9oZWFkZXIodGl0bGUgPSBtZCgiKipKdWdhZG9yIGNvbiBtw6FzIGdvbGVzIGVuIExhTGlnYSoqIiksIHN1YnRpdGxlPSBtZCgiSGFzdGEgbGEgdGVtcG9yYWRhIDIwMTgvMjAxOSIpKQ0KTWVzc2kgPC0gTWVzc2kgJT4lDQogICAgICAgICAgICAgICAgdGFiX29wdGlvbnMoaGVhZGluZy5iYWNrZ3JvdW5kLmNvbG9yID0gImJsYWNrIikgJT4lIHRhYl9vcHRpb25zKGhlYWRpbmcudGl0bGUuZm9udC5zaXplID0gMTgsIGhlYWRpbmcuc3VidGl0bGUuZm9udC5zaXplID0gMTMsICBjb2x1bW5fbGFiZWxzLmZvbnQud2VpZ2h0ID0gICJib2xkIikNCg0KDQpNZXNzaSA8LSBNZXNzaSAgJT4lDQogIGd0Ojp0ZXh0X3RyYW5zZm9ybShsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSB2YXJzKEltYWdlbikpLCBmbiA9IGZ1bmN0aW9uKHgpIHtndDo6d2ViX2ltYWdlKHgsIGhlaWdodCA9IDcwKX0pICU+JSAgY29sc19hbGlnbigNCiAgICBhbGlnbiA9ICJjZW50ZXIiKQ0KDQpgYGANCg0KDQpgYGB7ciBlY2hvID0gRkFMU0UsIGV2YWwgPSBUUlVFfQ0KTWVzc2kNCmBgYA0KDQpDbGFyYW1lbnRlIGVsIG3DoXhpbW8gZ29sZWFkb3IgaGlzdMOzcmljbyBlcyAqKkxpb25lbCBNZXNzaSoqIGNvbiB1biB0b3RhbCBkZSA0MTkgZ29sZXMgZGVzZGUgc3UgZGVidXQgZW4gbGEgdGVtcG9yYWRhIDIwMDQvMjAwNSBoYXN0YSBsYSB0ZW1wb3JhZGEgMjAxOC8yMDE5Lg0KDQpgYGB7cn0NCmxpYnJhcnkgKHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2dhbmltYXRlKQ0KZ29sZWFkb3Jlc19sYWxpZ2EgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiLi9kYXRvcy9nb2xlc190b3RhbF9sYWxpZ2EuY3N2IikpDQpnb2xlYWRvcmVzX2xhbGlnYSRUb3RhbCA9IHJvd1N1bXMgKGdvbGVhZG9yZXNfbGFsaWdhWyAsIDQ6MzJdKQ0KDQpnb2xlYWRvcmVzX2xhbGlnYSA8LSBnb2xlYWRvcmVzX2xhbGlnYSAlPiUgbXV0YXRlKFBsYXllciA9IGNhc2Vfd2hlbigNCiAgUGxheWVyPT0gICJSYcODwrpsIiB+ICIgUmHDumwgIiwNCiAgVFJVRSB+IFBsYXllcikpDQpnb2xlYWRvcmVzX2xhbGlnYTIgPC0gZ29sZWFkb3Jlc19sYWxpZ2EgICU+JSAgc2xpY2VfbWF4KFRvdGFsLCBuID0gNSkgDQoNCnRvcGc8LSBnb2xlYWRvcmVzX2xhbGlnYTIgJT4lIA0KICB0aWR5cjo6cGl2b3RfbG9uZ2VyKGNvbHMgPSA0OjMyLCBuYW1lc190byA9ICJUZW1wb3JhZGEiKQ0KDQoNCmE8LWdncGxvdCh0b3BnLCBhZXMoVGVtcG9yYWRhICwgdmFsdWUgLCBjb2xvcj1QbGF5ZXIsIGZpbGw9UGxheWVyKSkrIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSsgIGNvb3JkX2ZsaXAoKSsgIGxhYnModGl0bGUgPSAiRXZvbHVjacOzbiBkZSBnb2xlcyBwb3IgdGVtcG9yYWRhIGRlIGxvcyA1IG3DoXhpbW9zIGdvbGVhZG9yZXMgZGUgRXNwYcOxYSIsIHN1YnRpdGxlID0gIkRlc2RlIGxhIHRlbXBvcmFkYSA5MC85MSBhIGxhIDE4LzE5IiwgIHggPSAiR29sZXMiLCB4ID0gIkHDsW8iKQ0KYQ0KDQpgYGANCg0KRXN0ZSBncsOhZmljbyB0ZW5kcsOtYSBxdWUgc2VyIGFuaW1hZG8sIHBlcm8gYSBsYSBob3JhIGRlIGtuaXR0ZWFyIG5vIHNlIGxsZWdhIGEgY2FyZ2FyLCBlbiBmb3JtYXRvLnIgc2kgcXVlIGliYSBzaW4gcHJvYmxlbWEsIHBlcm8gYSBsYSBob3JhIGRlIHBhc2FyIGEgcm1kIHkgcG9uZXIgbGEgZnVuY2nDs24gdHJhbnNpdGlvbl9zdGF0ZXMgbm8gY2FyZ2EuIEVsIGdyw6FmaWNvIG5vcyBtdWVzdHJhIGxhIGV2b2x1Y2nDs24gZGUgY2FudGlkYWQgZGUgZ29sZXMgZGUgbG9zIDUgbcOheGltb3MgZ29sZWFkb3JlcyBoaXN0w7NyaWNvcyBkZSBMYWxpZ2EgZGVzZGUgZWwgYcOxbyAxOTkwIGhhc3RhIGVsIDIwMTkuIEVzdG9zIHNvbiBNZXNzaSwgQ3Jpc3RpYW5vIFJvbmFsZG8sIFJhw7psLCBFdG8nbyB5IFZpbGxhLjxicj4NCg0KRWwgZ3LDoWZpY28gbm9zIG11ZXN0cmEgbGEgY2FudGlkYWQgZGUgZ29sZXMgcXVlIGhhIG1hcmFjYWRvIGNhZGEganVnYWRvcmUgZW4gY2FkYSBhw7FvLiBFc3RhIHRhYmxhIGVzdMOhIGFuaW1hZGEgcG9yIGVsIHBhcXVldGUgZ2dhbmltYXRlLCBhIHRyYXbDqXMgZGUgbGEgZnVuY2nDs24gdHJhbnNpdGlvbl9zdGF0ZXMuPGJyPg0KDQoNCmBgYHtyfQ0KbWFwPC0gZ29sZWFkb3Jlc19sYWxpZ2EgJT4lIGdyb3VwX2J5KENvdW50cnkpICU+JSAgc3VtbWFyaXplKFBhaXNlcyA9IG4oKSkgDQoNCg0KbGlicmFyeSgicm5hdHVyYWxlYXJ0aCIpDQpsaWJyYXJ5KCJybmF0dXJhbGVhcnRoZGF0YSIpDQpsaWJyYXJ5KCJyZ2VvcyIpDQoNCndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpDQoNCndvcmxkIDwtIHdvcmxkICU+JSBmaWx0ZXIoc3VicmVnaW9uICE9ICJBbnRhcmN0aWNhIikgJT4lIGZpbHRlcihhZG1pbiAhPSAiR3JlZW5sYW5kIikNCng8LWdncGxvdCgpICsgZ2VvbV9zZihkYXRhID0gd29ybGQpICsgdGhlbWVfdm9pZCgpDQp3b3JsZCA8LSB3b3JsZCAlPiUgc2VsZWN0KG5hbWUsIGlzb19hMywgZ2VvbWV0cnkpDQoNCg0KZGZfd29ybGQgPC0gbGVmdF9qb2luKG1hcCwgd29ybGQsIGJ5ID0gYygiQ291bnRyeSIgPSAibmFtZSIpICkgDQoNCm08LWdncGxvdChkZl93b3JsZCkgKyBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5LCBmaWxsID0gUGFpc2VzKSkgKyBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAicGxhc21hIiwgdHJhbnMgPSAic3FydCIpKyBsYWJzKHRpdGxlID0gIk7Dum1lcm8gZGUgZ29sZWFkb3JlcyBwb3IgY2FkYSBwYcOtcyBkZSBMYUxpZ2EiLCBjYXB0aW9uID0gIkRhdG9zIGRlIEdpdGh1YiIsc3VidGl0bGUgPSAiRGF0b3MgZGVzZGUgbGEgdGVtcG9yYWRhIDg3Lzg4IGEgbGEgMTgvMTkiKQ0KDQoNCmBgYA0KDQoNCmBgYHtyIG91dC53aWR0aD0iMTAwJSIsIG91dC5oZWlnaHQ9IjUwJSIsIGVjaG89RkFMU0UsIGV2YWw9VFJVRX0NCm0NCmBgYA0KDQpNw6FzIHRhcmRlLCBoZSBlbGFib3JhZG8gdW4gbWFwYSwgcXVlIG5vcyBtdWVzdHJhIGxhIGNhbnRpZGFkIGRlIGdvbGVhZG9yZXMgZGUgTGFsaWdhIHF1ZSBoYSBoYWJpZG8gZW4gY2FkYSBwYcOtcyBkZXNkZSBsYSB0ZW1wb3JhZGEgMTk5MC48YnI+DQpDbGFyYW1lbnRlLCBlbCBwYcOtcyBxdWUgbcOhcyBnb2xlYWRvcmVzIGhhIGFwb3J0YWRvIGVzIEVzcGHDsWEsIG3DoXMgdGFyZGUsIGRlc3RhY2FuIG90cm9zIHBhw61zZXMgY29tbyBGcmFuY2lhLCBCcmFzaWwgbyBBcmdlbnRpbmEuDQo8YnI+DQpQYXJhIGxhIGVsYWJvcmFjacOzbiBkZSBlc3RlIG1hcGEsIGhlIGNvZ2lkbyBsb3MgZGF0b3MgZGUgY2FkYSB0ZW1wb3JhZGEsIHkgaGUgYWdydXBhZG8gbG9zIGRhdG9zIHBvciBlbCBwYcOtcyBkZWwgcXVlIHZpZW5lIGNhZGEgZnV0Ym9saXN0YS4gTcOhcyB0YXJkZSBvYnRlbmlkbyBsb3MgZGF0b3MgZXNwYWNpbGFlcyBkZSBsYSBwcmFjdGljYSA1IGRlIGNhbHNlLCBlbiBlbCBxdWUgaGFiw61hIHVuIG1hcGEgZGVsIG11bmRvIGVzcGFjaWFsIGNvbiBsb3MgcGFxdWV0ZXMgInJuYXR1cmFsZWFydGgiLCAicm5hdHVyYWxlYXJ0aGRhdGEiIHkgInJnZW9zIi4gRGVzcHXDqXMgaGUgdW5pZG8gZXN0YXMgZG9zIHRhYmxhcyB5IGhlIGNyZWFkbyBlbCBncsOhZmljby4NCg0KDQo8YnI+DQoNCiMjIDIuMSBNw6F4aW1vcyBnb2xlYWRvcmVzIGRlIGxhcyBncmFuZGVzIGxpZ2FzIGV1cm9wZWFzDQpFc3RhIHBhcnRlIGRlbCB0cmFiYWpvIGxhIHZhbW9zIGEgY2VudHJhciBlbiBsb3MgbcOheGltb3MgZ29sZWFkb3JlcyBkZSBmw7p0Ym9sIGV1cm9wZW8gZW4gbG9zIMO6bHRpbW9zIDIwIGHDsW9zLiANCg0KYGBge3J9DQpnb2xlYWRvcmVzX2xpZ2FzX3RvcDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoIi4vZGF0b3MvZ29sZXNfbGlnYXNfdG9wLmNzdiIpKQ0KbGlicmFyeSAodGlkeXZlcnNlKQ0KbGlicmFyeShnZ2FuaW1hdGUpDQoNCmdvbGVhZG9yZXNfbGlnYXNfdG9wIDwtIGdvbGVhZG9yZXNfbGlnYXNfdG9wICU+JSBtdXRhdGUoUGxheWVyID0gY2FzZV93aGVuKA0KICBQbGF5ZXI9PSAgIlJhw4PCumwiIH4gIiBSYcO6bCAiLA0KICBQbGF5ZXI9PSAgIlpsYXRhbiBJYnJhaGltb3Zpw4TigKEiIH4gIiBabGF0YW4gSWJyYWhpbW92acSHICIsDQogIFRSVUUgfiBQbGF5ZXIpKQ0KDQoNCmdvbGVhZG9yZXNfbGlnYXNfdG9wJFRvdGFsID0gcm93U3VtcyAoZ29sZWFkb3Jlc19saWdhc190b3BbICwgMjozMF0pDQoNCmdvbGVhZG9yZXNfdG9wIDwtIGdvbGVhZG9yZXNfbGlnYXNfdG9wICAlPiUgIHNsaWNlX21heChUb3RhbCwgbiA9IDYpIA0KDQptZWpvcjwtIGdvbGVhZG9yZXNfdG9wICU+JSANCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gMjozMCwgbmFtZXNfdG8gPSAiVGVtcG9yYWRhIikNCg0KDQpncjwtZ2dwbG90KG1lam9yICwgYWVzKFRlbXBvcmFkYSAsIHZhbHVlLCAgZ3JvdXA9IFBsYXllciwgY29sb3IgPSBQbGF5ZXIpKSAgKyBnZW9tX2xpbmUoKSArIGZhY2V0X3dyYXAodmFycyhQbGF5ZXIpLCBucm93ID0gMiwgbmNvbCA9IDMpKyAgbGFicyh0aXRsZSA9ICJFdm9sdWNpw7NuIGRlIGdvbGVzIHBvciB0ZW1wb3JhZGEgZGUgbG9zIDYgbcOheGltb3MgZ29sZWFkb3JlcyBkZSBFdXJvcGEiLCBzdWJ0aXRsZSA9ICJEZXNkZSBsYSB0ZW1wb3JhZGEgOTAvOTEgYSBsYSAxOC8xOSIsICB4ID0gIkdvbGVzIiwgeCA9ICJBw7FvIikgKyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsgdGhlbWUoIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkgDQoNCg0KDQoNCmdyYWZpY29fYSA8LSBnZ3Bsb3QobWVqb3IsIGFlcyhQbGF5ZXIsIFRvdGFsLCAgIGZpbGwgPSBQbGF5ZXIgLCBjb2xvcj0gImJsdWUiKSkgKyAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iU3BlY3RyYWwiKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSsgDQogIGxhYnModGl0bGUgPSAiTcOheGltb3MgZ29sZWFkb3JlcyBMaWdhcyBUb3AiLCBzdWJ0aXRsZSA9ICJEZXNkZSBlbCAxOTkwIGhhc3RhIGVsIDIwMTkiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KZ3JhZmljb19hcCA8LSBncmFmaWNvX2EgKyANCiAgZ2VvbV90ZXh0KGFlcyh5PVRvdGFsLCANCiAgICAgICAgICAgICAgICBsYWJlbCA9VG90YWwpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgDQogICAgICAgICAgICBzaXplID0gMy4yLCB2anVzdD0zLCBjb2wgPSAiQmxhY2siKQ0KDQpgYGANCg0KDQpgYGB7ciBlY2hvID0gRkFMU0UsIGV2YWwgPSBUUlVFfQ0KZ3JhZmljb19hcA0KYGBgDQpBcXXDrSBoZSByZWNvZ2lkbyBsb3MgZGF0b3MgeSBsb3MgaGUgYWdydXBhZG8gZW4gdW4gc3VtYXRvcmlvIGRlIHRvZG9zIGxvcyBnb2xlcyBkZSBsYXMgw7psdGltYXMgdGVtcG9yYWRhcy4gUG9kZW1vcyBvYnNlcnZhciBxdWUgbG9zIGRvcyBqdWdhZG9yZXMgcXVlIGRlc3RhY2FuIHBvciBlbmNpbWEgZGVsIHJlc3RvIHNvbiBMZW8gTWVzc2kgeSBDcmlzdGlhbm8gUm9uYWxkbyAoZWwgY3VhbCBsZSBjb2dlbiBsb3MgZGF0b3MgZGUgTGFsaWdhIHkgZGUgbGEgU2VyaWUgQSAoSXRhbGlhKSksIGVzdG9zIGRvcyBhbmltYWxlcyBoYW4gYW5vdGFkbyBsYSBmcmlvbGVyYSBjYW50aWRhZCBkZSA0MTkgeSA0MTYgZ29sZXMgcmVzcGVjdGl2YW1lbnRlIGVuIGxhcyBsaWdhcyBxdWUgaGFuIGp1Z2Fkby4gPGJyPg0KDQpFbCBncsOhZmljbyBlcyBkZSBiYXJyYXMgcGVybyB0aWVuZSBsYSBkaWZlcmVuY2lhIGRlIHF1ZSBoZSBhw7FhZGlkbyBlbCBuw7ptZXJvIGRlIGdvbGVzIHF1ZSBoYW4gYW5vdGFkbyBkZWJham8gZGUgbGFzIGJhcnJhcyBjb24gZ2VvbV90ZXh0Lg0KDQpgYGB7ciBlY2hvID0gRkFMU0UsIGV2YWwgPSBUUlVFfQ0KZ3INCmBgYA0KDQpFc3RlLCBtdWVzdHJhIGxhIGV2b2x1Y2nDs24gZGUgZ29sZXMgcXVlIGhhbiBhbm90YWRvIGxvcyA2IG3DoXhpbW9zIGdvbGVhZG9yZXMgZGUgbG9zIMO6bHRpbW9zIDIwIGHDsW9zIGVuIGNhZGEgdGVtcG9yYWRhLjxicj4NCg0KRXMgdW4gZ3LDoWZpY28gZGUgbGluZWFzIHF1ZSBlc3TDoSB1bmlkbyBhIHRyYXbDqXMgZGUgdW4gZmFjZXRfd3JhcCBkaWZlcmVuY2lhbmRvIGNhZGEganVnYWRvci4gRW4gZXN0ZSBncsOhZmljbyBoZSB0ZW5pZG8gbGEgZGlmaWN1bHRhZCBkZSBhanVzdGFyIGJpZW4gZWwgdGV4dG8gZGVsIGVqZSB4KGxhcyBkaWZlcm5ldGVzIHRlbXBvcmFkYXMpLCBmaW5hbG1lbnRlIGhlIHF1aXRhZG8gZWwgbsO6bWVybyBkZSBsYXMgdGVtcG9yYWRhcyBkZWJpZG8gYSBxdWUgc2Fsw61hIG1hbC4NCg0KIyA0LiBDYW1wZW9uZXMNCkVuIGVzdGUgYXBhcnRhZG8gdm95IGEgZW5zZcOxYXJvcyB1bmEgc2VyaWUgZGUgY3VyaW9zaWRhZGVzIHNvYnJlIGxhIGhpc3RvcmlhIGRlIGxhIGxpZ2EgZXNwYcOxb2xhLiA8YnI+DQpgYGB7ciBlY2hvID0gRkFMU0UsIGV2YWwgPSBUUlVFfQ0KY2FtcGVvbmVzPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiLi9kYXRvcy9MYV9MaWdhX1dpbm5lcnMuY3N2IikpDQoNCmNhbXBlb25lcyA8LSBjYW1wZW9uZXMgJT4lIG11dGF0ZShXaW5uZXIgPSBjYXNlX3doZW4oDQpXaW5uZXI9PSAgIkF0bMODwql0aWNvIE1hZHJpZCIgfiAiw4F0bGV0aWNvIGRlIE1hZGlyZCIsDQpXaW5uZXIgPT0gIkF0bMODwql0aWNvIEF2aWFjacODwrNuW2FdIiB+ICLDgXRsZXRpY28gZGUgTWFkcmlkIiwNCldpbm5lciA9PSAiRGVwb3J0aXZvIExhIENvcnXDg8KxYSIgfiAiRGVwb3J0aXZvIGRlIExhIENvcnXDsWEiLA0KVFJVRSB+IFdpbm5lcikpDQpgYGANCg0KDQoNCmBgYHtyIGVjaG8gPSBGQUxTRSwgZXZhbCA9IFRSVUV9DQoNCkRUOjpkYXRhdGFibGUoY2FtcGVvbmVzLCBmaWx0ZXIgPSAndG9wJywNCiAgICAgICAgICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwICwgYXV0b1dpZHRoID0gVFJVRSApKQ0KYGBgDQo8YnI+DQpBcXXDrSBzZSBwdWVkZSBvYnNlcnZhciB1bmEgdGFibGEgcXVlIG5vcyBtdWVzdHJhIHRvZG9zIGxvcyBjYW1wZW9uZXMgZGUgTGFsaWdhIGRlc2RlIHF1ZSBzZSBjcmXDsyBlc3RhLCBjYWJlIGRlc3RhY2FyIHF1ZSBkZWwgMTkzNi0xOTM5LCBmdWUgc3VzcGVuZGlkYSBwb3IgbGEgZ3VlcnJhIGNpdmlsLiBUYW1iacOpbiBub3MgbXVlc3RyYSwgbG9zIHNlZ3VuZG9zIHkgdGVyY2Vyb3MgY2xhc2lmaWNhZG9zOyBhc8OtIGNvbW8sIGVsIG3DoXhpbW8gZ29sZWFkb3IgZGUgY2FkYSBhw7FvIHkgY3VhbnRvcyBnb2xlcyBoaXpvIGVzdGUuDQoNCjxicj4NCmBgYHtyfQ0KZXF1aXBvPC0gY2FtcGVvbmVzICU+JSBncm91cF9ieShXaW5uZXIpJT4lZmlsdGVyKCEoU2Vhc29uICVpbiUgYygiMTkzNi8zNyIsICIxOTM3LzM4IiwiMTkzOC8zOSIpKSApICU+JSAgIHN1bW1hcml6ZShMaWdhcyA9IG4oKSkgJT4lIA0KICBhcnJhbmdlKGRlc2MoTGlnYXMpKQ0KIA0Kcm08LSBlcXVpcG8gICU+JSAgc2xpY2VfbWF4KExpZ2FzLCBuID0gMSkgDQoNCkVzY3VkbzwtImh0dHBzOi8vd3d3LmVjdXJlZC5jdS9pbWFnZXMvdGh1bWIvYy9jNi80MjhweC1sb2dvX3JlYWxfbWFkcmlkX3N2ZzFfY29waWEuanBnLzI2MHB4LTQyOHB4LWxvZ29fcmVhbF9tYWRyaWRfc3ZnMV9jb3BpYS5qcGciDQpybSA8LSBybSAlPiUgYWRkX2NvbHVtbihFc2N1ZG8pDQoNCmxpYnJhcnkoZ3QpDQpybSA8LSBybSAlPiUgZ3QoKQ0KDQpybSA8LSBybSAlPiUNCiAgICAgICAgICAgICAgICAgICB0YWJfaGVhZGVyKHRpdGxlID0gbWQoIioqRXF1aXBvIGNvbiBtw6FzIExpZ2FzKioiKSwgc3VidGl0bGU9IG1kKCJIYXN0YSBsYSB0ZW1wb3JhZGEgMjAxOS8yMDIwIikpDQpybSA8LSBybSAlPiUNCiAgICAgICAgICAgICAgICB0YWJfb3B0aW9ucyhoZWFkaW5nLmJhY2tncm91bmQuY29sb3IgPSAiYmxhY2siKSAlPiUgdGFiX29wdGlvbnMoaGVhZGluZy50aXRsZS5mb250LnNpemUgPSAxOCwgaGVhZGluZy5zdWJ0aXRsZS5mb250LnNpemUgPSAxMywgIGNvbHVtbl9sYWJlbHMuZm9udC53ZWlnaHQgPSAgImJvbGQiKQ0KDQoNCnJtIDwtIHJtICAlPiUNCiAgZ3Q6OnRleHRfdHJhbnNmb3JtKGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IHZhcnMoRXNjdWRvKSksIGZuID0gZnVuY3Rpb24oeCkge2d0Ojp3ZWJfaW1hZ2UoeCwgaGVpZ2h0ID0gNzApfSkgJT4lICBjb2xzX2FsaWduKA0KICAgIGFsaWduID0gImNlbnRlciIpDQoNCmBgYA0KDQpgYGB7ciBlY2hvID0gRkFMU0UsIGV2YWwgPSBUUlVFfQ0Kcm0NCmBgYA0KQXF1w60gcG9kZW1vcyBvYnNlcnZhciBxdWUgZWwgZXF1aXBvIG3DoXMgbGF1cmVhZG8gZGUgbGEgaGlzdG9yaWEgZGUgbGEgbGlnYSBlc3Bhw7FvbGEgZXMgZWwgKipSZWFsIE1hZHJpZCoqIENsdWIgZGUgZsO6dGJvbCBjb24gMzQgbGlnYXMuIA0KDQo8YnI+DQpgYGB7ciwgZXZhbCA9IFRSVUV9DQplcXVpcG88LSBjYW1wZW9uZXMgJT4lIGdyb3VwX2J5KFdpbm5lciklPiVmaWx0ZXIoIShTZWFzb24gJWluJSBjKCIxOTM2LzM3IiwgIjE5MzcvMzgiLCIxOTM4LzM5IikpICkgJT4lICANCiAgc3VtbWFyaXplKExpZ2FzID0gbigpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhMaWdhcykpDQogDQpxdWVzbzwtZ2dwbG90KGVxdWlwbywgYWVzKCIiLCBMaWdhcywgZmlsbCA9IFdpbm5lcikpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yPSJ3aGl0ZSIpICsgZ2VvbV90ZXh0KGFlcyhsYWJlbD1MaWdhcyksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMikgKyBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKyB0aGVtZV92b2lkKCkgKyBsYWJzKHRpdGxlPSJOw7ptZXJvIGRlIExpZ2FzIHBvciBlcXVpcG8iKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KcXVlc28NCg0KYW55b3g8LSBjYW1wZW9uZXMgJT4lIGdyb3VwX2J5KFdpbm5lciklPiVmaWx0ZXIoIShTZWFzb24gJWluJSBjKCIxOTM2LzM3IiwgIjE5MzcvMzgiLCIxOTM4LzM5IikpICkNCmFueW88LSBnZ3Bsb3QoYW55b3gsIGFlcyhTZWFzb24gLCBHb2FscywgZ3JvdXA9R29hbHMsZmlsbD0icmVkIikpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICArIGxhYnMoeCA9ICJUZW1wb3JhZGEiLCB5ID0gIkdvbGVzIiwgdGl0bGUgPSAiR29sZXMgcG9yIHRlbXBvcmFkYSBkZSBjYWRhIHBpY2hpY2hpIGRlIExhTGlnYSIsIGNhcHRpb24gPSAiRGF0b3Mgb2J0ZW5pZG9zIGRlIEdpdGh1YiIpICArIHRoZW1lX2J3KCkgICArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTYwLCB2anVzdD0wLjYpLCBwYW5lbC5iYWNrZ3JvdW5kID0gTlVMTCkrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KDQpgYGANCkVzdGUgZ3LDoWZpY28gbm9zIG11ZXN0cmEgYSB0cmF2w6lzIGRlIHVuIGdyw6FmaWNvIGNpcmN1bGFyLCBsYSBjYW50aWRhZCBkZSBsaWdhcyBxdWUgaGEgZ2FuYWRvIGNhZGEgY2x1YiBkZSBsYSBsaWdhIGVzcGHDsW9sYS4gRWwgUmVhbCBNYWRpcmQgZW5jYWJlemEgZXN0YSBsaXN0YSwgcG9yIGRlbGFudGUgZGVsIEJhcmNlbG9uYSAoMjYpIHkgQXRsw6l0aWNvIGRlIE1hZHJpZCBxdWUgdGllbmUgOCBtw6FzIDIgY3VhbmRvIHNlIGxsYW1hYmEgQXRsw6l0aWNvIGF2aWFjacOzbi48YnI+DQpQYXJhIGxhIGVsYWJvcmFjacOzbiBkZSBlc3RlIGdyw6FmaWNvIHByaW1lcm8gaGUgdGVuaWRvIHF1ZSBhcnJlZ2xhciBsb3MgZGF0b3MgZGUgbG9zIG5vbWJyZXMgZGUgY2FkYSBlcXVpcG8sIHkgbcOhcyB0YXJkZSBhZ3J1cGFyIGxvcyBkYXRvcyBwb3IgY2FkYSBwcmltZXJhIHBvc2ljacOzbiBxdWUgaGEgaGFiw61hIG9idGVuaWRvLiBBIHBhcnRpciBkZSBlc3RvcyBkYXRvcywgaGUgaGVjaG8gdW4gZ3LDoWZpY28gZGUgInF1ZXNpdG9zIi4NCg0KPGJyPg0KYGBge3IgZWNobyA9IEZBTFNFLCBldmFsID0gVFJVRX0NCmFueW8NCmBgYA0KRW4gZXN0ZSBncsOhZmljbyB2ZW1vcyBjb21vIGhhIGV2b2x1Y2lvbmFkbyBsYSBjYW50aWRhZCBkZSBnb2xlcyBtYXJjYWRvcyBwb3IgY2FkYSAicGljaGljaGkiIGRlIGxhIGxpZ2EgZW4gY2FkYSB0ZW1wb3JhZGEgcXVlIHNlIGhhIHJlYWxpemFkbyBlc3RhLCBlcyBkZWNpciwgZGVzZGUgZWwgMTkyOSBoYXN0YSBlbCAyMDIwIHF1aXRhbmRvIGxvcyBhw7FvcyBkZSBsYSBndWVycmEgY2l2aWwuPGJyPg0KSGF5IHF1ZSBkZXN0YWNhciBsb3MgYcOxb3MgZG9uZGUgdGFudG8gTWVzc2ksIGNvbW8gQ3Jpc3RpYW5vIFJvbmFsZG8gaGFuIGVzdGFkbyBwZWFsbmRvIHBvciBzZXIgZWwgbcOheGltbyBnb2xlYWRvciB5IHNlIGliYW4gYSB1bmFzIGNpZnJhcyByZWFsbWVudGUgYWx0YXMsICoqZW4gbGEgdGVtcG9yYWRhIDIwMTEvMjAxMiBNZXNzaSBsbGVnw7MgYSBhbGNhbnphciBsb3MgNTAgZ29sZXMgZW4gdW5hIHRlbXBvcmFkYSoqLjxicj4NCg0KRXMgdW4gZ2dwbG90IGRlIGJhcnJhcyBkb25kZSBoZSB0ZW5pZG8gcXVlIGdpcmFyIGVsIGFuZ3VsbyBkZWwgdGV4dG8gZGVsIGVqZSB4IChsYXMgdGVtcG9yYWRhcykgcGFyYSBxdWUgc2UgcHVkaWVyYW4gdmVyIGRlIG1hbmVyYSBhZGVjdWFkYS4NCg0KDQo8YnI+DQoNCg0KDQojIDUuIENsYXNpZmljYWNpw7NuICANCkVuIGVzdGUgYXBhcnRhZG8gdm95IGEgbWlyYXIgYWxndW5vcyBkYXRvcyByZWxldmFudGVzIHNvYnJlIGxhIGNsYXNpZmljYWNpw7NuIGRlIGxhIGxpZ2EgZW4gbG9zIMO6bHRpbW9zIDMwIGHDsW9zLCBkZXNkZSBsYSB0ZW1wb3JhZGEgMTk4Ny8xOTg4IGhhc3RhIGxhIHRlbXBvcmFkYSAyMDE4LzIwMTkuDQoNCjxicj4NCmBgYHtyIGVjaG8gPSBUUlVFLCBldmFsID0gVFJVRX0NCmxpYnJhcnkgKHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2dUaGVtZUFzc2lzdCkNCg0KY2xhc2lmaWNhY2lvbjwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoIi4vZGF0b3MvY2xhc2lmaWNhY2lvbl90b3RhbC5jc3YiKSkNCg0KDQojUHVudG9zIGRlIGNhZGEgcHJpbWVyIGNsYXNpZmljYWRvIHkgbcOhcyBwYXJ0aWRvcyBnYW5hZG9zDQpjbGFzaWZpY2FjaW9uXzE8LSBjbGFzaWZpY2FjaW9uICU+JSBmaWx0ZXIoUG9zaXRpb24gPT0gMSkgDQoNCmNsYXNpZmljYWNpb25fMTwtIGNsYXNpZmljYWNpb25fMSAlPiUgZ3JvdXBfYnkoUG9pbnRzKSAlPiUgICBhcnJhbmdlKGRlc2MoUG9pbnRzKSkNCg0KcHJpbWVybzwtZ2dwbG90KGNsYXNpZmljYWNpb25fMSwgYWVzKFNlYXNvbiAsIFBvaW50cyAsIGNvbG9yPVRlYW0sIGZpbGw9VGVhbSkpKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrIGxhYnMoeCA9ICJUZW1wb3JhZGEiLCB5ID0gIlB1bnRvcyBvYnRlbmlkb3MiLCB0aXRsZSA9ICJQdW50b3MgcG9yIHRlbXBvcmFkYSBkZSBjYWRhIGNhbXBlw7NuIGRlIGxhIExpZ2EiLHN1YnRpdGxlID0gIkRlc2RlIGxhIHRlbXBvcmFkYSA4Ny84OCBhIGxhIDE4LzE5IiwgY2FwdGlvbiA9ICJEYXRvcyBvYnRlbmlkb3MgZGUgR2l0aHViIikgICsgdGhlbWVfYncoKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9ZnVuY3Rpb24obil7Zm9ybWF0KG4sIHNjaWVudGlmaWMgPSBGQUxTRSl9KSAgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02MCwgdmp1c3Q9MC42KSwgcGFuZWwuYmFja2dyb3VuZCA9IE5VTEwpDQoNCg0KY2xhc2lmaWNhY2lvbl93aW5zIDwtIGNsYXNpZmljYWNpb25fMSAlPiUgICBhcnJhbmdlKGRlc2MoV29uKSkNCg0KdzwtZ2dwbG90KGNsYXNpZmljYWNpb25fMSwgYWVzKFNlYXNvbiAsIFdvbiAsIGNvbG9yPVRlYW0sIGZpbGw9VGVhbSkpKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyBsYWJzKHggPSAiVGVtcG9yYWRhIiwgeSA9ICJOwrogZGUgUGFydGlkb3MgR2FuYWRvcyIsIHRpdGxlID0gIlBhcnRpZG9zIGdhbmFkb3MgcG9yIHRlbXBvcmFkYSBkZSBjYWRhIGNhbXBlw7NuIGRlIGxhIExpZ2EiLHN1YnRpdGxlID0gIkRlc2RlIGxhIHRlbXBvcmFkYSA4Ny84OCBhIGxhIDE4LzE5IiwgY2FwdGlvbiA9ICJEYXRvcyBvYnRlbmlkb3MgZGUgR2l0aHViIikgICsgdGhlbWVfYncoKSArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9ZnVuY3Rpb24obil7Zm9ybWF0KG4sIHNjaWVudGlmaWMgPSBGQUxTRSl9KSAgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02MCwgdmp1c3Q9MC42KSwgcGFuZWwuYmFja2dyb3VuZCA9IE5VTEwpDQoNCg0KbGlicmFyeShncmlkRXh0cmEpICAjLSBpbnN0YWxsLnBhY2thZ2VzKCJncmlkRXh0cmEiKQ0KDQpsPC1ncmlkLmFycmFuZ2UocHJpbWVybywgdywgbnJvdz0gMikNCg0KYGBgDQo8YnI+DQpgYGB7ciBlY2hvID0gRkFMU0UsIGV2YWwgPSBUUlVFLHdhcm5pbmcgPSBGQUxTRX0NCmwNCmBgYA0KQXF1w60sIG5vcyBoZW1vcyBjZW50cmFkbyBlbiBsb3MgZGF0b3MgZGUgbG9zIHByaW1lcm9zIGNsYXNpZmljYWRvcywgeSBlbiBlc3RlIGdyw6FmaWNvIG9ic2VydmFtb3MgbGEgZXZvbHVjacOzbiBkZSBsb3MgcHVudG9zIGRlIGNhZGEgcHJpbWVyIGNsYXNpZmljYWRvIGFzw60gY29tbyBsYSBjYW50aWRhZCBkZSBwYXJ0aWRvcyBxdWUgaGEgZ2FuYWRvIGNhZGEgZXF1aXBvIGdhbmFkb3IgZW4gY2FkYSB0bWVwb3JhZGEuPGJyPg0KDQpFbCBncsOhZmljbyBjb25zdGEgZGUgZG9zIGdyw6FmaWNvcyBkZSBiYXJyYXMgYWdydXBhZG9zIHBvciBlbCBlcXVpcG8gcXVlIGhhIHNhbGlkbyBjYW1wZcOzbi4gTcOhcyB0YXJkZSBhIHJhw616IGRlIGVzdG9zIGdyw6FmaWNvcywgbG9zIGhlIHVuaWRvIGNvbiBsYSBmdW5jacOzbiBnaXJkLmV4dHJhIGRlbCBwYXF1ZXRlIGNvbiBlbCBtaXNtbyBub21icmUuDQoNCg0KPGJyPg0KDQoNCmBgYHtyfQ0KI0xvcyBwZW9yZXMgZXF1aXBvcyAobWVub3MgcHVudG9zKQ0KY2xhc2lmaWNhY2lvbl9wZW9yIDwtIGNsYXNpZmljYWNpb24gJT4lIHNsaWNlX21pbihQb2ludHMsIG4gPSAxMCkgJT4lIHNlbGVjdCghKENvbmNlZGVkfEdvYWxEaWZmZXJlbmNlfFRlYW0pKQ0KDQojTG9zIHF1ZSBtw6FzIGdvbGVzIGhhbiBtYXJjYWRvDQpjbGFzaWZpY2FjaW9uX2dvbGVzIDwtIGNsYXNpZmljYWNpb24gJT4lICAgc2xpY2VfbWF4KFNjb3JlZCwgbiA9IDEwKSU+JSBzZWxlY3QoIShDb25jZWRlZHxHb2FsRGlmZmVyZW5jZXxUZWFtKSkNCmBgYA0KDQo8YnI+DQoNCjxjZW50ZXI+PEZPTlQgQ09MT1I9IkJsdWUiPioqRXF1aXBvcyBjb24gbWVub3MgcHVudG9zIG9idGVuaWRvcyBlbiBsaWdhKio8L0ZPTlQ+PC9jZW50ZXI+DQpgYGB7ciBlY2hvPUZBTFNFLCBldmFsPVRSVUUsIG91dC53aWR0aD0iODAlIn0NCmNsYXNpZmljYWNpb25fcGVvcg0KYGBgDQpFc3RhIHByaW1lcmEgdGFibGEsIG5vcyBtdWVzdHJhIGxvcyBwZW9yZXMgZXF1aXBvcyBkZSBsb3Mgw7psdGltb3MgMzAgYcOxb3MgZW4gY3VhbnRvIGRhdG9zIGRlIGxhIHB1bnR1YWNpw7NuLiBMb3MgZXF1aXBvcyBxdWUgbWVub3MgcHVudG9zIGhhbiBsb2dyYWRvIGVuZSBzdG9zIDMwIGHDsW9zIHNvbiBlbCBMb2dyb8OxZXMgZGUgbGEgdGVtcG9yYWRhIDk0Lzk1IHkgZWwgU3BvcnRpbmcgZGUgR2lqw7NuIGRlIGxhIHRlbXBvcmFkYSA5Ny85OC4gQ2FiZSBkZXN0YWNhciwgcXVlIGVsIMO6bHRpbW8gZW4gdW5pcnNlIGEgZXN0YSBsaXN0YSBlbiBsYSBxdWUgbmFkaWUgcXVpZXJlIGFwYXJlY2VyIGVzZWwgTcOhbGFnYSBkZSBsYSB0ZW1wb3JhZGEgMjAxNy8yMDE4LCBjb24gMjAgcHVudG9zLjxicj4NCk90cm8gZGUgbG9zIGRhdG9zIGN1cmlzb3NvcyBlcyBxdWUgYSBwZXNhciBkZSBzZXIgbG9zIHBlb3JlcyBlcXVpcG9zLCBoYXkgdmFyaW9zIGVxdWlwb3MgcXVlIGFwYXJlY2VuIGVuIGVzdGEgbGlzdGEgc2luIGhhYmVyIHF1ZWRhZG8gZWwgw7psdGltbyBjbGFzaWZpY2FkbyBkZSBsYSBsaWdhLCBjb21vIGVzIGVsIGNhc28gZGUgTGFzIFBhbG1hcyBlbiBlbCBhw7FvIDE3LzE4OyBlc3RvIHN1cG9uZSBxdWUgaGF5IGHDsW9zIGVuIGxvcyBxdWUgbGFzIHB1bnR1YWNpb25lcyBwYXJhIHNhbHZhcnNlIHkgbm8gZGVzY2VuZGVyIGEgc2VndW5kYSBzb24gbcOhcyBhbHRvcyBxdWUgb3Ryb3MuDQoNCg0KPGJyPg0KDQo8Y2VudGVyPjxGT05UIENPTE9SPSJCbHVlIj4qKkVxdWlwb3MgY29uIG3DoXMgZ29sZXMgZW4gbGlnYSoqPC9GT05UPjwvY2VudGVyPg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBldmFsPVRSVUUsIG91dC53aWR0aD0iODAlIn0NCmNsYXNpZmljYWNpb25fZ29sZXMNCmBgYA0KQXF1w60sIGhlIGFkanVudG8gb3RyYSB0YWJsYSwgcGVybyBubyB0aWVuZSBuYWQgYXVxZSB2ZXIgY29uIGxhIGFudGVyb3IsIGVzdGEgbXVlc3RyYSBsb3MgMTAgZXF1aXBvcyBxdWUgbcOhcyBnb2xlcyBoYW4gbWFyY2FkbyBlbiBsb3Mgw7psdGltb3MgYcOxb3MuIE5vIG9ic3RhbnRlLCBzZSBwdWVkZSB2ZXIgcXVlIHRvZG9zIHBlcnRlbmVjZW4gYWwgUmVhbCBtYWRyaWQgbyBhbCBGw7p0Ym9sIENsdWIgQmFyY2Vsb25hLiBFbCByZWNvcmQgZGUgcHVudG9zIHkgZ29sZXMgbWFyY2Fkb3MsIGxvIGNvbnNpZ3Vpw7MgZWwgUmVhbCBNYWRyaWQgZGUgTW91cmluaG8gZW4gbGEgdGVtcG9yYWRhIDIwMTEvMjAxMiB4b24gMTAwIHB1bnRvcyB5IDEyMSBnb2xlcyAgZmF2b3IsIHVuYSBhdXTDqW50aWNhIGxvY3VyYS4gRXN0ZSByw6ljb3JkIGEgZMOtYSBkZSBob3kgc2lndWUgdmlnZW50ZSB5IG1lIGltYWdpbm8gcXVlIGHDum4gdGFyZGFyw6EgZW4gYmF0aXJzZS4NCg0KDQo8YnI+DQoNCg0KDQojIyA1LjEgRXF1aXBvcyBxdWUgbnVuY2EgaGFuIGRlc2NlbmRpZG8gICANCg0KSGF5IDMgZXF1aXBvcyBlbiBsYSBoaXN0b3JpYSBkZWwgZsO6dGJvbCBlc3Bhw7FvbCwgcXVlIGphbcOhcyBoYSBkZXNjZW5kaWRvIGEgc2VndW5kYSBkaXZpc2nDs24geSBzaWVtcHJlIGhhbiBwZXJtYW5lY2lkbyBlbiBsYSBjYXRlZ29yw61hIGRlIG9yby4gRXN0b3Mgc29uLHBvciB1biBsYWRvLCBsb3MgcXVlIG5vIHBvZMOtYW4gZmFsdGFyICBlbCBSZWFsIE1hZHJpZCB5IGVsIEJhcsOnYTsgeSBwb3IgZWwgb3RybyBsYWRvIGVsIG1lcml0b3JpbyBBdGhsZXRpYyBDbHViIGRlIEJpbGJhby4gRXN0ZSBhcGFydGFkbyBzZSBjZW50cmEgZW4gbG9zIGRhdG9zIGRlIGVzdG9zIHRyZXMgZXF1aXBvcyBlbiBsb3Mgw7psdGltb3MgMzAgYcOxb3MuDQoNCmBgYHtyfQ0KbGlicmFyeShnZ2FuaW1hdGUpDQoNCmNsYXNpZmljYWNpb25fbWJhPC0gY2xhc2lmaWNhY2lvbiAlPiUgZmlsdGVyKGBDcmVzdCBuYW1lc2AgPT0gIlJlYWwgTWFkcmlkInxgQ3Jlc3QgbmFtZXNgID09ICJGQyBCYXJjZWxvbmEifCBgQ3Jlc3QgbmFtZXNgID09ICJBdGhsZXRpYyBDbHViIikgDQoNCmdyYWZpY29tYmEgPC0gZ2dwbG90KGNsYXNpZmljYWNpb25fbWJhLCBhZXMoU2Vhc29uLCBQb2ludHMsIGNvbG9yID0gYENyZXN0IG5hbWVzYCwgZ3JvdXAgPSBgQ3Jlc3QgbmFtZXNgKSkgKyBnZW9tX2xpbmUoKSArIGdlb21fcG9pbnQoKSArIHRoZW1lX2xpZ2h0KCkgICsgbGFicyh0aXRsZSA9ICJFdm9sdWNpw7NuIGRlIHB1bnRvcyBvYnRlbmlkb3MiLHN1YnRpdGxlID0gIkRhdG9zIGRlc2RlIGxhIHRlbXBvcmFkYSA4Ny84OCBhIGxhIDE4LzE5IiwgY2FwdGlvbiA9ICJEYXRvcyBkZSBHaXRodWIiLCB4ID0gIlRlbXBvcmFkYSIsIHkgPSAiTsK6IGRlIHB1bnRvcyIpICsgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gIkNvcmFsIikpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NjAsIHZqdXN0PTAuNiksIHBhbmVsLmJhY2tncm91bmQgPSBOVUxMKSsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1mdW5jdGlvbihuKXtmb3JtYXQobiwgc2NpZW50aWZpYyA9IEZBTFNFKX0pICANCg0KDQpsaWJyYXJ5KHBsb3RseSkNCg0KDQoNCg0KYiA8LSBnZ3Bsb3QoY2xhc2lmaWNhY2lvbl9tYmEsIGFlcyhTZWFzb24sIFBvc2l0aW9uLCBmaWxsID0gVGVhbSkpICsgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSsgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLCB2anVzdD0wLjYpLCBwYW5lbC5iYWNrZ3JvdW5kID0gTlVMTCkrIGxhYnModGl0bGUgPSAiRXZvbHVjacOzbiBkZSBsYSBwb3NpY2nDs24gZW4gTGFMaWdhICIsIGNhcHRpb24gPSAiRGF0b3MgZGUgR2l0aHViIixzdWJ0aXRsZSA9ICJPYnRlbmlkYSBwb3IgbG9zIGVxdWlwb3MgcXVlIG51bmNhIGhhbiBkZXNjZW5kaWRvIiwgeCA9ICJUZW1wb3JhZGEiLCB5ID0gIk7CuiBkZSBwdW50b3MiKSArICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBjb2xvciA9ICJDb3JhbCIpKSAgIA0KDQoNCg0KYGBgDQoNCg0KYGBge3Igb3V0LndpZHRoPSI4MCUiLCBvdXQuaGVpZ2h0PSI5MCUiLCBlY2hvPUZBTFNFLCBldmFsPVRSVUV9DQpncmFmaWNvbWJhDQoNCmBgYA0KRXN0ZSBwcmltZXIgZ3LDoWZpY28gbXVlc3RyYSBsYSBldm9sdWNpw7NuIGRlIGxhIGNhbnRpZGFkIGRlIHB1bnRvcyBxdWUgaGFuIG9idGVuaWRvIGVzdG9zIHRyZXMgZXF1aXBvcy48YnI+DQoNCkVzdMOhIGVsYWJvcmFkbyBhIHRyYXZlcyBkZSB1biBncsOhZmljbyBkZSBwdW50b3MgeSBsaW5lYXMuDQoNCg0KPGJyPg0KDQpgYGB7ciBvdXQud2lkdGg9IjEwMCUiLCBvdXQuaGVpZ2h0PSI1MCUiLCBlY2hvPUZBTFNFLCBldmFsPVRSVUV9DQpnZ3Bsb3RseShiKQ0KYGBgDQpFbiBlc3RlIGdyw6FmaWNvIGRpbsOhbWljbyB2ZW1vcyBsYSBwb3NpY2nDs24gcXVlIGhhIGxvZ3JhZG8gZXN0b3MgZXF1aXBvcyBkZXNkZSBsYSB0ZW1wb3JhZGEgODcvODguPGJyPg0KVmVtb3MgcXVlIGxhcyBiYXJyYXMgZGVsIEF0bGhldGljIGRlIEJpbGJhbywgc29uIG11Y2hvIG3DoXMgYWx0YXMgeWEgcXVlIGFsIHNlciB1biBlcXVpcG8gbcOhcyBtb2Rlc3RvLCBtdWNoYXMgdmVjZXMgZXN0w6FuIGxlam9zIGRlIGxhcyBwb3NpY2lvbmVzIGRlIGxhcyBwb3NpY2lvbmVzIGNhYmVjZXJhcywgcG9yIGVzdGUgbW90aXZvIHRpZW5lIHRhbnRvIG3DqXJpdG8gcXVlIG51bmNhIGhheWFuIGRlc2NlbmRpZG8uIDxicj4NCg0KRXMgdW4gZ3LDoWZpY28gZGUgYmFycmFzIHF1ZSBlcyBkaW7DoW1pY28gZ3JhY2lhcyBhbCBwYXF1ZXRlIHBsb3R5LCBwb3IgbG8gdGFudG8sIHNpIHBhc2FzIGVsIHB1bnRlcm8gcG9yIGVuY2ltYSBkZSBsYXMgYmFycmFzLCBlbiBjYWRhIHVuYSBkZSBlbGxhcywgbm9zIGRpY2UgcXVlIHBvc2ljacOzbiBvYnR1dm8gY2FkYSBlcXVpcG8gZW4gZXNhIHRlbXBvcmFkYS4NCg0KDQo8YnI+DQoNCiFbYmlsYmFvXSguL2ltYWdlbmVzL2JpbGJhby5qcGcpDQoNCiMgNi4gQ29uY2x1c2nDs24NCkZpbmFsbWVudGUgcXVpZXJvIGRlY2lyIHF1ZSBlc3RlIHRyYWJham8gbWUgaGEgbGxldmFkbyBiYXN0YW50ZSB0cmFiYWpvLCBhdW5xdWUgZ3JhY2lhcyBhbCB0ZW1hIGVsZWdpZG8gc2UgbWUgaGEgaGVjaG8gYmFzdG5hdGUgbcOhcyBsbGV2YWRlcm8uIE5vIHPDqSBzaSBlbCByZXN1bHRhZG8gZmluYWwgbXVlc3RyYSB0b2RvIGVsIHRpZW1wbyBxdWUgaGEgc3VwdWVzdG8gKGVzcGVybyBxdWUgc8OtKSB5IGVzcGVybyBxdWUgb3MgaGF5YSBndXN0YWRvLjxicj4NCg0KVGFtYmnDqW4gbWUgZ3VzdGFyw61hIGRlY2lyIHF1ZSBlbCB0cmFiYWpvIG5vIGVzdMOhIGluc3BpcmFkbyBjb21vIHRhbCBlbiBuaW5nw7puIG90cm8sIHBlcm8gcXVlIG1lIGhlIGFwb3lhZG8geSBtZSBoYSBheXVkYWRvIGJhc3RhbnRlIGEgbGEgaG9yYSBkZSByZXNvbHZlciB2YXJpYXMgZHVkYXMsIGVsIHRyYWJham8gZGUgZXFpcG8gcXVlIGhpY2UgZW4gc3UgZMOtYSBjb24gbWlzIGNvbXBhw7Flcm9zIE5vZWxpYSB5IEFuZHJldSBzb2JyZSBlbCBDb3ZpZC4NCg0KIVtmaW5dKC4vaW1hZ2VuZXMvZmluLmpwZyk8YnI+DQoNCiMgNy4gQmlibGlvZ3JhZsOtYQ0KDQpQYXJhIGxhIHJlYWxpemFjacOzbiBkZWwgdHJhYmFqbyBoZSB1dGlsaXphZG86DQoNCi0gaHR0cHM6Ly9naXRodWIuY29tL3NhbWVlci1tLWRldi93ZWJTY3JhcGluZ1JlcG8vdHJlZS9mNjQwZTNkZDM0YmIwMWQzNDk1OWRmMTM4MjAzMTAwZDBjN2RjYWYxL0Zvb3RiYWxsDQoNCi0gaHR0cHM6Ly9naXRodWIuY29tL2FsdmFyb2JhcnR0L2xhbGlnYS1kYXRhc2V0L3RyZWUvbWFzdGVyL2RhdGFzZXQNCg0KLSBodHRwczovL2dpdGh1Yi5jb20vYXJpYW5uYWx1cGkvbGFsaWdhDQoNCi0gaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9raXNoYW4zMDUvc3BhbmlzaC1mb290YmFsbC1sYS1saWdhLWNoYW1waW9ucw0K