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

Spotify es el servicio digital de música, podcasts y vídeos, más utilizado actualmente a nivel mundial.En esta aplicación podras encontrar millones de canciones para todos los gustos, al igual que podcasts, ya que hay de todo tipo, de política, de economía de deportes, etc. En este trabajo, vamos a tratar varios temas sobre esta aplicación, en primer lugar, haremos un repaso sobre la evolución de Spotify a lo largo de los años, después nos adentraremos más en lo que más se ha escuchado en 2021 y comparaciones entre los distintos generos, y por último, nos referiremos más a aspectos musicales de las canciones, como la bailabilidad, la popularidad, los acordes… Al final de año, Spotify, muestra a sus usuarios un resumen de lo que mas ha escuchado durante ese año,de una forma interactiva y divertida, y de aqui es de donde me surgió la idea de realizar el trabajo sobre esta plataforma, a continuación podeis observar cual ha sido mi resumen de 2021

Wrapped

2. Datos

Los datos que he utilizado en este trabajo, han sido extraidos de kaggle en esta web he obtenido los datos sobre las canciones más escuhadas este 2021, de la propia web de Spotify aquí he extraido la información sobre los seguidores de los artistas y de Statista de esta web he sacado los datos sobre la evolución de los ingresos y de los oyentes.

2.1. Procesando los datos

En este apartado voy a mostrar como he manipulado los 4 dataframes, y que acciones he realizado en cada uno de ellos para eliminar fallos y dejarlos más organizados y con la información que me interesa.El df principal es el llamado spotify_dataset ya que este ha sido el que mas he manipulado, el que mas he utilizado y el que más in formación tiene.Los otros 3 df, **evolucion_usuarios, evolucion_ingresos, mas_seguidores* han sido más complementarios, ya que solo me han servido para hacer 2-3 gráficos.

#cambio estos nombres aqui debajo pq si no da error luego

spotify_dataset <- rio::import(file = "./datos/spotify_dataset.csv")

names(spotify_dataset)[names(spotify_dataset) == 'Artist Followers'] <- 'artist_followers'
names(spotify_dataset)[names(spotify_dataset) == 'Song Name'] <- 'song_name'

spotify_dataset$song_name <- iconv(spotify_dataset$song_name, from="UTF-8", to="LATIN1")
spotify_dataset$Artist <- iconv(spotify_dataset$Artist, from="UTF-8", to="LATIN1")

spotify_dataset$Streams <- as.numeric(gsub(",","",spotify_dataset$Streams))


spotify_dataset[is.na(spotify_dataset)] <- 0



evolucion_usuarios <- read_excel("datos/evolucion_usuarios.xlsx")

evolucion_ingresos <- read_excel("datos/evolucion_ingresos.xlsx")

mas_seguidores <- read_excel("datos/followers_artists_2021.xlsx") 

3. La evolución de Spotify

Spotify es una aplicación que permite la reproducción de audio y video por medio del streaming, es decir, la transmisión en continuo de música o listas de música de distintos artistas alrededor del mundo.Este software multiplataforma, de origen sueco, cuenta con una versión gratuita que permite escuchar música de forma gratuita, con algunas limitaciones y publicidades. También, cuenta con otra modalidad Premium que ofrece mejor calidad de audio y otras funciones adicionales que funcionan con una suscripción de paga.

En este apartado, vamos a observar su evolución en distintos aspectos.

3.1 Evolución de los usuarios por año y trimestre

Conforme ha ido avanzando los smartphones y la tecnología,Spotify ha ido aumentando sus usuarios, ya que unicamente teniendo conexión a internet, te permite acceso ilimitado a miles de canciones.


evolucion_usuarios <- read_excel("datos/evolucion_usuarios.xlsx")

gg_usuarios <- ggplot(evolucion_usuarios, aes(x = year_trimester, y = usuarios )) +
  geom_segment( aes(x=year_trimester, xend=year_trimester, y=0, yend=usuarios), size=0.5, 
                color="black", linetype="dotdash") +
  geom_point( color="chartreuse3", size=3.5) +
  theme_light() +
  theme(
    panel.grid.major.x = element_blank(),
    panel.border = element_blank(),
    axis.ticks.x = element_blank()) +
  xlab("Año y trimestre ") +
  ylab("Numero de Usuarios en millones")
  

ggplotly(gg_usuarios)   

3.2 Evolución de los ingresos por año

Conforme Spotify ha ido aumentando los usuarios, también ha ido aumentando sus ingresos, ya que gran parte de estos nuevos usuarios se han unido de forma premium, lo que conlleva un pago mensual o anual a la plataforma, por ello, contra más usuarios nuevos, mayores ingresos.



evolucion_ingresos <- read_excel("datos/evolucion_ingresos.xlsx")


gg_ingresos <- ggplot(evolucion_ingresos, aes(x=year, y= ingresos)) +
  geom_area() +
  geom_point( size=1.5, color="chartreuse3", fill=alpha("chartreuse3", 8), shape=21, stroke=2) +  
  geom_line(color="chartreuse3", size=1.5) +
  scale_x_continuous(
    breaks = seq(2009, 2020, 1),
    limits = c(2009, 2020)) + labs(x = "Año", y = "Ingresos en millones de €" ) + theme(panel.grid.major = element_line(colour = "white"),
    panel.grid.minor = element_line(colour = "white"),
    panel.background = element_rect(fill = "white"))


ggplotly(gg_ingresos)

3.2 Los logos de spotify a lo largo de su historia

Aunque no sea algo de vital importancia, Spotify a lo largo de los años, como cualquier marca, ha realizado modificaciones en el logo, haciendo cada vez más simples y menos recargados


logo2008 <- image_read("./imagenes/spotify-logo2008.png") %>% image_scale(., "500") %>%  image_annotate(., "2008", size = 40, gravity = "southeast", color = "black")

logo2013 <- image_read("./imagenes/spotify_logo_2013.png") %>% image_scale(., "900") %>%  image_annotate(., "2013", size = 80, gravity = "southeast", color = "black")

logo2015 <- image_read("./imagenes/spotify_logo_actual.png") %>% image_scale(., "500") %>%  image_annotate(., "Actual", size = 40, gravity = "southeast", color = "black")

logos <- c(logo2008, logo2013, logo2015)

image_animate(image_scale(logos), fps = 0.5)

4. La música del 2021

En esta sección hablaré de lo que más se ha escuchado en el último año, los artistas más sonados, los más seguidos y las canciones más famosas.

4.1 TOP 30 Artistas del 2021

Como podemos observar, la artista más escuchada, en este 2021 ha sido la cantante estadounidense, Taylor Swift, con un total de 381480455 reproducciones.Por detrás, tenemos a la banda surcoreana de K-Pop, BTS con 238400020 reproducciones, y en tercer lugar, podemos encontrar al canadiense Justin Bieber con 225842427 reproducciones.

GRÁFICO DE BARRAS


total_streams_art <- spotify_dataset %>% 
  group_by(Artist) %>% 
  mutate(streams_totales = sum(Streams)) %>% 
  select(Artist, streams_totales, Genre)

total_streams_art_nodup <- total_streams_art[!duplicated(total_streams_art), ] %>% 
  group_by(streams_totales) %>% 
  arrange(desc(streams_totales)) %>% 
  filter(streams_totales > 46346067)


treinta_mas_escuchados <- total_streams_art_nodup[-c(4, 15, 19, 21, 23
                                                     , 25, 27, 33, 41), ]

treinta_mas_escuchados_no_dup <- treinta_mas_escuchados[-c(27, 32 ,33 ,34), ]


gg_masescuchados <- ggplot(treinta_mas_escuchados_no_dup, aes(x= Artist, 
                                                              y= streams_totales, fill=Artist)) +
  geom_bar(stat = "identity") +
  coord_flip() +
  theme(legend.position="none") + theme(panel.background = element_rect(fill = "white")) +labs(y = "Streams Totales")
  
ggplotly(gg_masescuchados)

GRÁFICO CIRCULAR



# Set highcharter options
options(highcharter.theme = hc_theme_smpl(tooltip = list(valueDecimals = 2)))

gg_masescuchados_circ <- treinta_mas_escuchados_no_dup %>%
  hchart(
    "pie", hcaes(x = Artist, y = streams_totales),
    name = "Nº de reproducciones"
  )

gg_masescuchados_circ

4.2 TOP 30 Artistas con más seguidores en spotify del 2021

En este gráfico de tarta, se puede ver que los artistas más seguidos, NO son los más escuchados, ya que los 3 con más fans en esta plataforma, son Ed Sheeran, Ariana Grande y Drake. Cuando Taylor Swift ha sido la más escuchada, pero la 7 más seguida, lo mismo pasa con BTS que ha pasado de ser el segundo a el décimo primero.Esto es porque el hecho de que sean más escuchados no significa que sean los más famosos, solo significa que han sacado más canciones en 2021 o mejor contenido.


mas_seguidores <- read_excel("datos/followers_artists_2021.xlsx") 


# Set highcharter options
options(highcharter.theme = hc_theme_smpl(tooltip = list(valueDecimals = 2)))

gg_masseguidores <- mas_seguidores %>%
  hchart(
    "pie", hcaes(x = Artist, y = artist_followers),
    name = "Nº de seguidores"
  )

gg_masseguidores

4.3 TOP 30 canciones más sonadas en este 2021 ¨

Como podemos observar en este gráfico de caja las canciones más escuchadas en 2021 han sido, en primer lugar, Beggin’ del grupo italiano Måneskin con 48633449 reproducciones, esta canción fue la ganadora de Eurovision.En segundo lugar, esta STAY (with Justin Bieber) del rapero australiano The Kid LAROI y este tema, acumula 47248719 reproducciones en Spotify. Y en tercer lugar, la canción, good 4 u de la americana Olivia Rodrigo que tiene 40162559 reproducciones.

POR CANCIONES DENTRO DEL TOP 30


#top10 <- spotify_dataset %>% select(song_name, Artist, Streams) %>% 
 # filter(Streams > 14174752)

#library(treemap)

#gg_top_10 <- treemap(top10,
 #       index="group",
  #      vSize="value",
   #     type="index")


#gg_top10 <- treemap(top10,
                            #index=c("Artist","song_name"),
                            #vSize="Streams",
                            #type="index",
                            #vColor = "Artist",
                            #fontsize.labels=c(15,20),
                            #bg.labels=c("transparent"),
                            #palette = "Set1",
                            #align.labels=list(
                             # c("center", "center"), 
                            #  c("center", "bottom")),
                            #title = "TOP 10 2021",
                            #title.legend = "Artistas") 

#gg_top10

inter_top10 <- d3tree2(gg_top10 ,  rootname = "TOP 30 Canciones más escuchadas del 2021 y sus Artistas")
inter_top10

TABLA RANKING TOP 30


knitr::kable(top10, caption = "TOP 30 2021") %>% 
  kableExtra::kable_styling(bootstrap_options = c("striped", "hover"))  %>% 
  kableExtra::kable_styling(fixed_thead = list(enabled = T, background = "chartreuse"))
TOP 30 2021
song_name Artist Streams
Beggin’ Måneskin 48633449
STAY (with Justin Bieber) The Kid LAROI 47248719
good 4 u Olivia Rodrigo 40162559
Bad Habits Ed Sheeran 37799456
INDUSTRY BABY (feat. Jack Harlow) Lil Nas X 33948454
MONTERO (Call Me By Your Name) Lil Nas X 30071134
Kiss Me More (feat. SZA) Doja Cat 29356736
Intentions Justin Bieber, Quavo 28509534
Todo De Ti Rauw Alejandro 26951613
Yonaguni Bad Bunny 25030128
I WANNA BE YOUR SLAVE Måneskin 24551591
Levitating (feat. DaBaby) Dua Lipa 23518010
All I Want for Christmas Is You Mariah Carey 23235257
Qué Más Pues? J Balvin, Maria Becerra 22405111
Permission to Dance BTS 22062812
Last Christmas Wham! 20709328
Peaches (feat. Daniel Caesar & Giveon) Justin Bieber 20294457
Butter BTS 19985713
traitor Olivia Rodrigo 19480679
deja vu Olivia Rodrigo 18571755
Save Your Tears (with Ariana Grande) (Remix) The Weeknd 18053141
AM Remix Nio Garcia, J Balvin, Bad Bunny 17617965
Need To Know Doja Cat 16908917
Santa Tell Me Ariana Grande 16657592
Rockin’ Around The Christmas Tree Brenda Lee 16613649
Volando - Remix Mora, Bad Bunny, Sech 16606925
Jingle Bell Rock Bobby Helms 16527404
happiness Taylor Swift 16213589
Ain’t Shit Doja Cat 16126897
a p p l y i n g . p r e s s u r e J. Cole 15967986

5. Reggaeton vs POP

Según varias fuentes de información, los dos generos más escuchados en la actualidad son el pop y el reggaeton.En este apartado vamos a comparar los dos generos mediante distintos aspectos, la suma de todas las reproducciones de cada género en 2021, la bailabilidad de cada género y la popularidad.

5.1 Que género ha tenido más reproducciones en 2021

Para comparar hemos sumado todas las reproducciones de las canciones de pop en 2021.En este gráfico de barras podemos ver, que el pop se ha escuchado mucho más que el reggaeton durante este año.

reggaeton <- spotify_dataset %>% 
  select(Artist, song_name, Streams, Genre, Popularity, Danceability, Energy) %>%
  filter(stringr::str_detect(Genre, 'reggaeton') ) %>% 
  mutate(streams_totales = sum(Streams)) 


pop <- spotify_dataset %>% 
  select(Artist, song_name, Streams, Genre, Popularity, Danceability, Energy) %>%
  filter(stringr::str_detect(Genre, 'pop') ) %>% 
  mutate(streams_totales = sum(Streams))


reggaeton_vs_pop <- rbind(reggaeton, pop) %>% 
  select(Genre, streams_totales)

reggaeton_vs_pop_solo_streams <- reggaeton_vs_pop[c(29,185), ]


gg_vs_streams <- ggplot(reggaeton_vs_pop_solo_streams, aes(x=Genre, y=streams_totales, 
                                                           fill = streams_totales)) + 
  geom_bar(stat = "identity") +
  theme(panel.background = element_rect(fill = "white")) +labs(x = "Genero", y = "Streams Totales")


ggplotly(gg_vs_streams)

5.2 Que género ha sido más bailable en 2021

Para llevar a cabo esta comparación, he realizado la media de la bailabilidad de todas las canciones de cada género, es decir, he sumado la bailabilidad de todas las canciones de pop y de reggaeton, y lo he dividido entre el nº de temas de cada uno .Y como podemos observar, las canciones de reggaeton han sido más bailables que las de pop en un 8%.


reggaeton_baila <- reggaeton %>% summarise(media_bailabilidad = mean(Danceability))

pop_baila <- pop %>% summarise(media_bailabilidad = mean(Danceability))

reggaeton_vs_pop_baila <- rbind(reggaeton_baila, pop_baila)

reggaeton_vs_pop_baila_bien <- cbind(reggaeton_vs_pop_baila, Genre=c("reggaeton","pop"))

gg_vs_baila <- ggplot(reggaeton_vs_pop_baila_bien, aes(x=Genre, y=media_bailabilidad, 
                                                           fill = media_bailabilidad)) + 
  geom_bar(stat = "identity")  + theme(panel.background = element_rect(fill = "white")) +labs(x = "Genero", y = "Media de Bailabilidad")



ggplotly(gg_vs_baila)

6. Aspectos musicales del 2021

En este apartado observaremos varias características que tienen que ver con la música, como es el tempo, los acordes, la energía y la bailabilidad

6.1 Que tempo deben tener las canciones para ser bailables?

Como podemos observar en este gráfico de dispersión, las canciones para ser bailables (danceability>= 0,75), han de tener un tempo entre 100 y 150, si tienen un tempo mayor son demasiado rápidas para ser bailadas por tanto su bailabilidad cae, y si tienen un tempo menor que 100, son demasiado lentas.



gg_1 <- ggplot(spotify_dataset) + geom_point(mapping = aes(x=Tempo, y=Danceability), colour = "chartreuse3") + 
  geom_smooth(mapping = aes(x=Tempo, y=Danceability), color = "black") + 
  labs(title="Tempo de la canción vs Bailabilidad") +
  theme(panel.background = element_rect(fill = "white")) +labs(y = "Bailabilidad")
ggplotly(gg_1)

6.2 Que energia suelen tener las canciones más bailables?

Las canciones más bailables, según el gráfico de dispersion, suelen tener unas energía entre 0,60 y 0,75. Si las canciones tienen una energía menor, no incitan al movimiento y por tanto, tienen una bailabilidad muy baja


gg_2 <- ggplot(spotify_dataset) + geom_point(mapping = aes(x=Energy, y=Danceability), colour = "chartreuse3") + 
  geom_smooth(mapping = aes(x=Energy, y=Danceability), color = "black") + 
  labs(title="Energía de la canción vs Bailabilidad") +
  theme(panel.background = element_rect(fill = "white")) +labs(x = "Energía de la Canción", y = "Bailabilidad")
ggplotly(gg_2)

6.3 Las canciones más populares son las más bailables?

La respuesta a esta pregunta es si, ya que como podemos ver, las canciones con una popularidad por encima de 75, que esto significa que son canciones populares a nivel mundial y que han estado en los tops varias veces, tienen una bailabilidad por encima de 0,65, es decir, que si son populares son bastante bailables, ya que estos significa que su ritmo, su letra y su melodia son más pegadizas.


gg_3 <- ggplot(spotify_dataset) + geom_point(mapping = aes(x=Danceability, y=Popularity), colour = "chartreuse3") + 
  geom_smooth(mapping = aes(x=Danceability, y=Popularity), color = "black") + 
  labs(title="Popularidad vs Bailabilidad") +
  theme(panel.background = element_rect(fill = "white")) +labs(x = "Bailabilidad", y = "Popularidad")
ggplotly(gg_3)

6.4 Que acorde usan las canciones más populares?

En este gráfico de barras se puede observar que, las canciones con mayor popularidad son las que utilizan el acorde C#/Db, y las que menos populares son las que utilizan el acorde D#/Eb.



gg_4 <- ggplot(spotify_dataset, aes(x=Chord, y=Popularity)) + 
  geom_bar(stat = "identity", color ="black" ,fill = "chartreuse3") +

 theme(panel.background = element_rect(fill = "white")) +labs(title = "Popularidad vs Acorde", x = "Acorde",
    y = "Popularidad")
gg_4

7. Reggaeton en el 2021

En los ultimos años, este género musical ha ido aumentando su popularidad a niveles estratosféricos, ha pasado de ser solo escuchado en paises latinos, ha ser uno de los más famosos a nivel mundial.Este año, los 3 artistas de reggaeton más importantes han sido Bad Bunny, Rauw Alejandro y J Balvin.


bb_ra_j <- spotify_dataset %>% 
  select(Artist, Streams, artist_followers, song_name, `Number of Times Charted`) %>% 
  filter(Artist %in% c("Bad Bunny", "Rauw Alejandro","J Balvin"))

total_streams_bb_ra_j <- treinta_mas_escuchados[c(5,31,32), ] %>% 
  select(Artist, streams_totales)

comparacion_reggaeton <- full_join(bb_ra_j,total_streams_bb_ra_j, c("Artist" = "Artist")) %>% 
  select(Artist,streams_totales,artist_followers) 

comparacion_reggaeton_3 <- comparacion_reggaeton[c(1,2,7), ]

comparacion_reggaeton_edad <- cbind(comparacion_reggaeton_3, Edad=c("27","28", "36"))



fotos_reggaeton_artistas <- c("./imagenes/bad_bunny.png", "./imagenes/rauw_alejandro.png","./imagenes/j_balvin.png")

fotos_pr_col <- c("./imagenes/Puerto_Rico.png","./imagenes/Puerto_Rico.png", "./imagenes/Colombia.png")

comparacion_reggaeton_bien <- comparacion_reggaeton_edad %>% add_column(fotos_reggaeton_artistas, fotos_pr_col)

library(gt)

reggaeton_tabla <- comparacion_reggaeton_bien %>% gt() %>% 
  text_transform( locations = cells_body(columns = c(fotos_reggaeton_artistas)), fn = function(x) {gt::local_image(x, height = 80)}) %>% 
  text_transform( locations = cells_body(columns = c(fotos_pr_col)), fn = function(x) {gt::local_image(x, height = 80)}) %>% tab_header(title = md("**TOP ARTISTAS REGGAETON 2021**"), subtitle = md("Comparación")) %>%   cols_label(
    Artist = html("Artista"),
    streams_totales = html("Total Reproducciones"),
    artist_followers = html("Seguidores Spotify"),
    fotos_reggaeton_artistas = html(""),
    fotos_pr_col = html("")) %>%  
  tab_options(table.background.color = "white",   table.font.color.light = "chartreuse") %>% 
  cols_align(align = "center",
  columns = everything())

reggaeton_tabla
TOP ARTISTAS REGGAETON 2021
Comparación
Artista Total Reproducciones Seguidores Spotify Edad
Rauw Alejandro 52301649 6080597 27
Bad Bunny 203813133 36142273 28
J Balvin 50589690 29067437 36
LS0tDQp0aXRsZTogIkxBIEJBTkRBIFNPTk9SQSBERUwgMjAyMSINCnN1YnRpdGxlOiAiQ2FybG9zIEdhcmPDrWEgQ2FzdGlsbGEoZ2FyY2FzOEBhbHVtbmkudXYuZXMpIiAjLSBwb25nbyB0w7ogbm9tYnJlIGFow60gcGFyYSBxIGFwYXJlemNhIG3DoXMgZ3JhbmRlIHEgZWwgZGUgbGEgVVYNCmF1dGhvcjogIlVuaXZlcnNpdGF0IGRlIFZhbMOobmNpYSINCmRhdGU6ICJEaWNpZW1icmUgZGUgMjAyMSAoYWN0dWFsaXphZG8gZWwgYHIgZm9ybWF0KFN5cy50aW1lKCksICclZC0lbS0lWScpYCkiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY3NzOiAiLi9hc3NldHMvbXlfY3NzX2ZpbGUuY3NzIg0KICAgIHRoZW1lOiBwYXBlcg0KICAgIGhpZ2hsaWdodDogdGV4dG1hdGUgDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiAzIA0KICAgIHRvY19mbG9hdDogDQogICAgICBjb2xsYXBzZWQ6IHRydWUNCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICBkZl9wcmludDoga2FibGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlDQotLS0NCg0KYGBge3IgcGFja2FnZXMtc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShrbGlwcHkpICAjLSByZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigicmxlc3VyL2tsaXBweSIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHJpbykNCmxpYnJhcnkoa2xpcHB5KQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGhlcmUpDQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KHNraW1yKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShnYXBtaW5kZXIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkod29yZGNsb3VkMikNCmxpYnJhcnkoaGlnaGNoYXJ0ZXIpDQpsaWJyYXJ5KGQzdHJlZVIpDQpsaWJyYXJ5KG1hZ2ljaykNCmxpYnJhcnkoZ3QpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpgYGANCg0KYGBge3IgY2h1bmstc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZXZhbCA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICAjcmVzdWx0cyA9ICJob2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICBjYWNoZSA9IEZBTFNFLCBjYWNoZS5wYXRoID0gIi9jYWNoZXMvIiwgY29tbWVudCA9ICIjPiIsDQogICAgICAgICAgICAgICAgICAgICAgI2ZpZy53aWR0aCA9IDcsICNmaWcuaGVpZ2h0PSA3LCAgIA0KICAgICAgICAgICAgICAgICAgICAgICNvdXQud2lkdGggPSA3LCBvdXQuaGVpZ2h0ID0gNywNCiAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZSA9IFRSVUUsICBmaWcuc2hvdyA9ICJob2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYXNwID0gMC42MjgsIG91dC53aWR0aCA9ICI3NSUiLCBmaWcuYWxpZ24gPSAiY2VudGVyIikNCmtuaXRyOjpvcHRzX2NodW5rJHNldChkZXYgPSAicG5nIiwgZGV2LmFyZ3MgPSBsaXN0KHR5cGUgPSAiY2Fpcm8tcG5nIikpDQpgYGANCg0KDQpgYGB7ciBvcHRpb25zLXNldHVwLCBpbmNsdWRlID0gRkFMU0V9DQpvcHRpb25zKHNjaXBlbiA9IDk5OSkgIy0gcGFyYSBxdWl0YXIgbGEgbm90YWNpw7NuIGNpZW50w61maWNhDQpvcHRpb25zKCJ5YW1sLmV2YWwuZXhwciIgPSBUUlVFKSANCmBgYA0KDQoNCmBgYHtyIGtsaXBweSwgZWNobyA9IEZBTFNFfQ0Ka2xpcHB5OjprbGlwcHkocG9zaXRpb24gPSBjKCJ0b3AiLCAicmlnaHQiKSkgIy0gcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoInJsZXN1ci9rbGlwcHkiKQ0KYGBgDQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnkiPjxkaXYvPg0KDQo8aHIgY2xhc3M9ImxpbmVhLWJsYWNrIj4NCg0KPCEtLSBFbCBww6FycmFmbyBkZSBhYmFqbyBoYXMgZGUgZGVqYXJsbyBjYXNpIGlndWFsLCBzb2xvIEhBUyBkZSBTVVNUSVRVSVIgInBlcmV6cDQ0IiBwb3IgdHUgdXN1YXJpbyBkZSBHaXRodWItLT4NClRyYWJham8gZWxhYm9yYWRvIHBhcmEgbGEgYXNpZ25hdHVyYSAiUHJvZ3JhbWFjacOzbiB5IG1hbmVqbyBkZSBkYXRvcyBlbiBsYSBlcmEgZGVsIEJpZyBEYXRhIiBkZSBsYSBVbml2ZXJzaXRhdCBkZSBWYWzDqG5jaWEgZHVyYW50ZSBlbCBjdXJzbyAyMDIxLTIwMjIuIEVsIHJlcG8gZGVsIHRyYWJham8gZXN0w6EgW2FxdcOtXShodHRwczovL2dpdGh1Yi5jb20vZ2FyY2FzOC90cmFiYWpvX0JpZ0RhdGEpe3RhcmdldD0iX2JsYW5rIn0uIA0KDQo8IS0tIEVsIHDDoXJyYWZvIGRlIGFiYWpvIGhhcyBkZSBkZWphcmxvIGV4YWN0YW1lbnRlIGlndWFsLCBOTyBIQVMgREUgQ0FNQklBUiBOQURBLS0+DQoNCkxhIHDDoWdpbmEgd2ViIGRlIGxhIGFzaWduYXR1cmEgeSBsb3MgdHJhYmFqb3MgZGUgbWlzIGNvbXBhw7Flcm9zIHB1ZWRlbiB2ZXJzZSBbYXF1w61dKGh0dHBzOi8vcGVyZXpwNDQuZ2l0aHViLmlvL2ludHJvLWRzLTIxLTIyLXdlYi8wNy10cmFiYWpvcy5odG1sKXt0YXJnZXQ9Il9ibGFuayJ9Lg0KDQoNCjxociBjbGFzcz0ibGluZWEtcmVkIj4NCg0KIyBbMS4gSW50cm9kdWNjacOzbl17LnZlcmRlY2l0b30NCg0KKipTcG90aWZ5KiogZXMgZWwgKipzZXJ2aWNpbyBkaWdpdGFsKiogZGUgbcO6c2ljYSwgcG9kY2FzdHMgeSB2w61kZW9zLCBtw6FzIHV0aWxpemFkbyBhY3R1YWxtZW50ZSBhIG5pdmVsIG11bmRpYWwuRW4gZXN0YSBhcGxpY2FjacOzbiBwb2RyYXMgZW5jb250cmFyIG1pbGxvbmVzIGRlIGNhbmNpb25lcyBwYXJhIHRvZG9zIGxvcyBndXN0b3MsIGFsIGlndWFsIHF1ZSBwb2RjYXN0cywgeWEgcXVlIGhheSBkZSB0b2RvIHRpcG8sIGRlIHBvbMOtdGljYSwgZGUgZWNvbm9tw61hIGRlIGRlcG9ydGVzLCBldGMuIEVuIGVzdGUgdHJhYmFqbywgdmFtb3MgYSB0cmF0YXIgdmFyaW9zIHRlbWFzIHNvYnJlIGVzdGEgYXBsaWNhY2nDs24sIGVuIHByaW1lciBsdWdhciwgaGFyZW1vcyB1biByZXBhc28gc29icmUgbGEgZXZvbHVjacOzbiBkZSBTcG90aWZ5IGEgbG8gbGFyZ28gZGUgbG9zIGHDsW9zLCBkZXNwdcOpcyBub3MgYWRlbnRyYXJlbW9zIG3DoXMgZW4gbG8gcXVlIG3DoXMgc2UgaGEgZXNjdWNoYWRvIGVuIDIwMjEgeSBjb21wYXJhY2lvbmVzIGVudHJlIGxvcyBkaXN0aW50b3MgZ2VuZXJvcywgeSBwb3Igw7psdGltbywgbm9zIHJlZmVyaXJlbW9zIG3DoXMgYSBhc3BlY3RvcyBtdXNpY2FsZXMgZGUgbGFzIGNhbmNpb25lcywgY29tbyBsYSBiYWlsYWJpbGlkYWQsIGxhIHBvcHVsYXJpZGFkLCBsb3MgYWNvcmRlcy4uLg0KQWwgZmluYWwgZGUgYcOxbywgU3BvdGlmeSwgbXVlc3RyYSBhIHN1cyB1c3VhcmlvcyB1biByZXN1bWVuIGRlIGxvIHF1ZSBtYXMgaGEgZXNjdWNoYWRvIGR1cmFudGUgZXNlIGHDsW8sZGUgdW5hIGZvcm1hIGludGVyYWN0aXZhIHkgZGl2ZXJ0aWRhLCB5IGRlIGFxdWkgZXMgZGUgZG9uZGUgbWUgc3VyZ2nDsyBsYSBpZGVhIGRlIHJlYWxpemFyIGVsIHRyYWJham8gc29icmUgZXN0YSBwbGF0YWZvcm1hLCBhIGNvbnRpbnVhY2nDs24gcG9kZWlzIG9ic2VydmFyIGN1YWwgaGEgc2lkbyBtaSByZXN1bWVuIGRlIDIwMjENCg0KPGNlbnRlcj4NCg0KIVtXcmFwcGVkXSguL2ltYWdlbmVzL3dyYXBwZWQuanBlZyl7d2lkdGg9MzAwIGhlaWdodD01MDB9DQoNCjwvY2VudGVyPg0KDQoNCg0KDQojIDIuIERhdG9zDQoNCkxvcyBkYXRvcyBxdWUgaGUgdXRpbGl6YWRvIGVuIGVzdGUgdHJhYmFqbywgaGFuIHNpZG8gZXh0cmFpZG9zIGRlIFtrYWdnbGVdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vKSBlbiBlc3RhIHdlYiBoZSBvYnRlbmlkbyBsb3MgZGF0b3Mgc29icmUgbGFzIGNhbmNpb25lcyBtw6FzIGVzY3VoYWRhcyBlc3RlIDIwMjEsIGRlIGxhIHByb3BpYSB3ZWIgZGUgW1Nwb3RpZnldKGh0dHBzOi8vd3d3LnNwb3RpZnkuY29tL2VzLykgYXF1w60gaGUgZXh0cmFpZG8gbGEgaW5mb3JtYWNpw7NuIHNvYnJlIGxvcyBzZWd1aWRvcmVzIGRlIGxvcyBhcnRpc3RhcyB5IGRlIFtTdGF0aXN0YV0oaHR0cHM6Ly93d3cuc3RhdGlzdGEuY29tL3RvcGljcy8yMDc1L3Nwb3RpZnkvI2Rvc3NpZXJLZXlmaWd1cmVzKSBkZSBlc3RhIHdlYiBoZSBzYWNhZG8gbG9zIGRhdG9zIHNvYnJlIGxhIGV2b2x1Y2nDs24gZGUgbG9zIGluZ3Jlc29zIHkgZGUgbG9zIG95ZW50ZXMuDQoNCg0KIyMgMi4xLiBQcm9jZXNhbmRvIGxvcyBkYXRvcw0KDQpFbiBlc3RlIGFwYXJ0YWRvIHZveSBhIG1vc3RyYXIgY29tbyBoZSBtYW5pcHVsYWRvIGxvcyA0IGRhdGFmcmFtZXMsIHkgcXVlIGFjY2lvbmVzIGhlIHJlYWxpemFkbyBlbiBjYWRhIHVubyBkZSBlbGxvcyBwYXJhIGVsaW1pbmFyIGZhbGxvcyB5IGRlamFybG9zIG3DoXMgb3JnYW5pemFkb3MgeSBjb24gbGEgaW5mb3JtYWNpw7NuIHF1ZSBtZSBpbnRlcmVzYS5FbCBkZiBwcmluY2lwYWwgZXMgZWwgbGxhbWFkbyAqKnNwb3RpZnlfZGF0YXNldCoqIHlhIHF1ZSBlc3RlIGhhIHNpZG8gZWwgcXVlIG1hcyBoZSBtYW5pcHVsYWRvLCBlbCBxdWUgbWFzIGhlIHV0aWxpemFkbyB5IGVsIHF1ZSBtw6FzIGluIGZvcm1hY2nDs24gdGllbmUuTG9zIG90cm9zIDMgZGYsICoqZXZvbHVjaW9uX3VzdWFyaW9zLCBldm9sdWNpb25faW5ncmVzb3MsIG1hc19zZWd1aWRvcmVzKiBoYW4gc2lkbyBtw6FzIGNvbXBsZW1lbnRhcmlvcywgeWEgcXVlIHNvbG8gbWUgaGFuIHNlcnZpZG8gcGFyYSBoYWNlciAyLTMgZ3LDoWZpY29zLg0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KI2NhbWJpbyBlc3RvcyBub21icmVzIGFxdWkgZGViYWpvIHBxIHNpIG5vIGRhIGVycm9yIGx1ZWdvDQoNCnNwb3RpZnlfZGF0YXNldCA8LSByaW86OmltcG9ydChmaWxlID0gIi4vZGF0b3Mvc3BvdGlmeV9kYXRhc2V0LmNzdiIpDQoNCm5hbWVzKHNwb3RpZnlfZGF0YXNldClbbmFtZXMoc3BvdGlmeV9kYXRhc2V0KSA9PSAnQXJ0aXN0IEZvbGxvd2VycyddIDwtICdhcnRpc3RfZm9sbG93ZXJzJw0KbmFtZXMoc3BvdGlmeV9kYXRhc2V0KVtuYW1lcyhzcG90aWZ5X2RhdGFzZXQpID09ICdTb25nIE5hbWUnXSA8LSAnc29uZ19uYW1lJw0KDQpzcG90aWZ5X2RhdGFzZXQkc29uZ19uYW1lIDwtIGljb252KHNwb3RpZnlfZGF0YXNldCRzb25nX25hbWUsIGZyb209IlVURi04IiwgdG89IkxBVElOMSIpDQpzcG90aWZ5X2RhdGFzZXQkQXJ0aXN0IDwtIGljb252KHNwb3RpZnlfZGF0YXNldCRBcnRpc3QsIGZyb209IlVURi04IiwgdG89IkxBVElOMSIpDQoNCnNwb3RpZnlfZGF0YXNldCRTdHJlYW1zIDwtIGFzLm51bWVyaWMoZ3N1YigiLCIsIiIsc3BvdGlmeV9kYXRhc2V0JFN0cmVhbXMpKQ0KDQoNCnNwb3RpZnlfZGF0YXNldFtpcy5uYShzcG90aWZ5X2RhdGFzZXQpXSA8LSAwDQoNCg0KDQpldm9sdWNpb25fdXN1YXJpb3MgPC0gcmVhZF9leGNlbCgiZGF0b3MvZXZvbHVjaW9uX3VzdWFyaW9zLnhsc3giKQ0KDQpldm9sdWNpb25faW5ncmVzb3MgPC0gcmVhZF9leGNlbCgiZGF0b3MvZXZvbHVjaW9uX2luZ3Jlc29zLnhsc3giKQ0KDQptYXNfc2VndWlkb3JlcyA8LSByZWFkX2V4Y2VsKCJkYXRvcy9mb2xsb3dlcnNfYXJ0aXN0c18yMDIxLnhsc3giKSANCmBgYA0KDQojIDMuIExhIGV2b2x1Y2nDs24gZGUgU3BvdGlmeQ0KDQoqKlNwb3RpZnkqKiBlcyB1bmEgYXBsaWNhY2nDs24gcXVlIHBlcm1pdGUgbGEgcmVwcm9kdWNjacOzbiBkZSBhdWRpbyB5IHZpZGVvIHBvciBtZWRpbyBkZWwgc3RyZWFtaW5nLCBlcyBkZWNpciwgbGEgdHJhbnNtaXNpw7NuIGVuIGNvbnRpbnVvIGRlIG3DunNpY2EgbyBsaXN0YXMgZGUgbcO6c2ljYSBkZSBkaXN0aW50b3MgYXJ0aXN0YXMgYWxyZWRlZG9yIGRlbCBtdW5kby5Fc3RlIHNvZnR3YXJlIG11bHRpcGxhdGFmb3JtYSwgZGUgb3JpZ2VuIHN1ZWNvLCBjdWVudGEgY29uIHVuYSB2ZXJzacOzbiBncmF0dWl0YSBxdWUgcGVybWl0ZSBlc2N1Y2hhciBtw7pzaWNhIGRlIGZvcm1hIGdyYXR1aXRhLCBjb24gYWxndW5hcyBsaW1pdGFjaW9uZXMgeSBwdWJsaWNpZGFkZXMuIFRhbWJpw6luLCBjdWVudGEgY29uIG90cmEgbW9kYWxpZGFkIFByZW1pdW0gcXVlIG9mcmVjZSBtZWpvciBjYWxpZGFkIGRlIGF1ZGlvIHkgb3RyYXMgZnVuY2lvbmVzIGFkaWNpb25hbGVzIHF1ZSBmdW5jaW9uYW4gY29uIHVuYSBzdXNjcmlwY2nDs24gZGUgcGFnYS4NCg0KRW4gZXN0ZSBhcGFydGFkbywgdmFtb3MgYSBvYnNlcnZhciBzdSBldm9sdWNpw7NuIGVuIGRpc3RpbnRvcyBhc3BlY3Rvcy4NCg0KDQojIyAzLjEgRXZvbHVjacOzbiBkZSBsb3MgdXN1YXJpb3MgcG9yIGHDsW8geSB0cmltZXN0cmUNCg0KQ29uZm9ybWUgaGEgaWRvIGF2YW56YW5kbyBsb3Mgc21hcnRwaG9uZXMgeSBsYSB0ZWNub2xvZ8OtYSwqKlNwb3RpZnkqKiBoYSBpZG8gYXVtZW50YW5kbyBzdXMgdXN1YXJpb3MsIHlhIHF1ZSB1bmljYW1lbnRlIHRlbmllbmRvIGNvbmV4acOzbiBhIGludGVybmV0LCB0ZSBwZXJtaXRlIGFjY2VzbyBpbGltaXRhZG8gYSBtaWxlcyBkZSBjYW5jaW9uZXMuDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCmV2b2x1Y2lvbl91c3VhcmlvcyA8LSByZWFkX2V4Y2VsKCJkYXRvcy9ldm9sdWNpb25fdXN1YXJpb3MueGxzeCIpDQoNCmdnX3VzdWFyaW9zIDwtIGdncGxvdChldm9sdWNpb25fdXN1YXJpb3MsIGFlcyh4ID0geWVhcl90cmltZXN0ZXIsIHkgPSB1c3VhcmlvcyApKSArDQogIGdlb21fc2VnbWVudCggYWVzKHg9eWVhcl90cmltZXN0ZXIsIHhlbmQ9eWVhcl90cmltZXN0ZXIsIHk9MCwgeWVuZD11c3VhcmlvcyksIHNpemU9MC41LCANCiAgICAgICAgICAgICAgICBjb2xvcj0iYmxhY2siLCBsaW5ldHlwZT0iZG90ZGFzaCIpICsNCiAgZ2VvbV9wb2ludCggY29sb3I9ImNoYXJ0cmV1c2UzIiwgc2l6ZT0zLjUpICsNCiAgdGhlbWVfbGlnaHQoKSArDQogIHRoZW1lKA0KICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIHhsYWIoIkHDsW8geSB0cmltZXN0cmUgIikgKw0KICB5bGFiKCJOdW1lcm8gZGUgVXN1YXJpb3MgZW4gbWlsbG9uZXMiKQ0KICANCg0KZ2dwbG90bHkoZ2dfdXN1YXJpb3MpICAgDQoNCg0KDQoNCmBgYA0KDQojIyAzLjIgRXZvbHVjacOzbiBkZSBsb3MgaW5ncmVzb3MgcG9yIGHDsW8gDQoNCkNvbmZvcm1lICoqU3BvdGlmeSoqIGhhIGlkbyBhdW1lbnRhbmRvIGxvcyB1c3VhcmlvcywgdGFtYmnDqW4gaGEgaWRvIGF1bWVudGFuZG8gc3VzIGluZ3Jlc29zLCB5YSBxdWUgZ3JhbiBwYXJ0ZSBkZSBlc3RvcyBudWV2b3MgdXN1YXJpb3Mgc2UgaGFuIHVuaWRvIGRlIGZvcm1hIHByZW1pdW0sIGxvIHF1ZSBjb25sbGV2YSB1biBwYWdvIG1lbnN1YWwgbyBhbnVhbCBhIGxhIHBsYXRhZm9ybWEsIHBvciBlbGxvLCBjb250cmEgbcOhcyB1c3VhcmlvcyBudWV2b3MsIG1heW9yZXMgaW5ncmVzb3MuDQoNCg0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0NCg0KDQpldm9sdWNpb25faW5ncmVzb3MgPC0gcmVhZF9leGNlbCgiZGF0b3MvZXZvbHVjaW9uX2luZ3Jlc29zLnhsc3giKQ0KDQoNCmdnX2luZ3Jlc29zIDwtIGdncGxvdChldm9sdWNpb25faW5ncmVzb3MsIGFlcyh4PXllYXIsIHk9IGluZ3Jlc29zKSkgKw0KICBnZW9tX2FyZWEoKSArDQogIGdlb21fcG9pbnQoIHNpemU9MS41LCBjb2xvcj0iY2hhcnRyZXVzZTMiLCBmaWxsPWFscGhhKCJjaGFydHJldXNlMyIsIDgpLCBzaGFwZT0yMSwgc3Ryb2tlPTIpICsgIA0KICBnZW9tX2xpbmUoY29sb3I9ImNoYXJ0cmV1c2UzIiwgc2l6ZT0xLjUpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKA0KICAgIGJyZWFrcyA9IHNlcSgyMDA5LCAyMDIwLCAxKSwNCiAgICBsaW1pdHMgPSBjKDIwMDksIDIwMjApKSArIGxhYnMoeCA9ICJBw7FvIiwgeSA9ICJJbmdyZXNvcyBlbiBtaWxsb25lcyBkZSDigqwiICkgKyB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJ3aGl0ZSIpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gIndoaXRlIiksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikpDQoNCg0KZ2dwbG90bHkoZ2dfaW5ncmVzb3MpDQoNCmBgYA0KDQoNCg0KIyMgMy4yIExvcyBsb2dvcyBkZSBzcG90aWZ5IGEgbG8gbGFyZ28gZGUgc3UgaGlzdG9yaWENCg0KQXVucXVlIG5vIHNlYSBhbGdvIGRlIHZpdGFsIGltcG9ydGFuY2lhLCAqKlNwb3RpZnkqKiBhIGxvIGxhcmdvIGRlIGxvcyBhw7FvcywgY29tbyBjdWFscXVpZXIgbWFyY2EsIGhhIHJlYWxpemFkbyBtb2RpZmljYWNpb25lcyBlbiBlbCBsb2dvLCBoYWNpZW5kbyBjYWRhIHZleiBtw6FzIHNpbXBsZXMgeSBtZW5vcyByZWNhcmdhZG9zDQoNCg0KYGBge3J9DQoNCmxvZ28yMDA4IDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvc3BvdGlmeS1sb2dvMjAwOC5wbmciKSAlPiUgaW1hZ2Vfc2NhbGUoLiwgIjUwMCIpICU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIjIwMDgiLCBzaXplID0gNDAsIGdyYXZpdHkgPSAic291dGhlYXN0IiwgY29sb3IgPSAiYmxhY2siKQ0KDQpsb2dvMjAxMyA8LSBpbWFnZV9yZWFkKCIuL2ltYWdlbmVzL3Nwb3RpZnlfbG9nb18yMDEzLnBuZyIpICU+JSBpbWFnZV9zY2FsZSguLCAiOTAwIikgJT4lICBpbWFnZV9hbm5vdGF0ZSguLCAiMjAxMyIsIHNpemUgPSA4MCwgZ3Jhdml0eSA9ICJzb3V0aGVhc3QiLCBjb2xvciA9ICJibGFjayIpDQoNCmxvZ28yMDE1IDwtIGltYWdlX3JlYWQoIi4vaW1hZ2VuZXMvc3BvdGlmeV9sb2dvX2FjdHVhbC5wbmciKSAlPiUgaW1hZ2Vfc2NhbGUoLiwgIjUwMCIpICU+JSAgaW1hZ2VfYW5ub3RhdGUoLiwgIkFjdHVhbCIsIHNpemUgPSA0MCwgZ3Jhdml0eSA9ICJzb3V0aGVhc3QiLCBjb2xvciA9ICJibGFjayIpDQoNCmxvZ29zIDwtIGMobG9nbzIwMDgsIGxvZ28yMDEzLCBsb2dvMjAxNSkNCg0KaW1hZ2VfYW5pbWF0ZShpbWFnZV9zY2FsZShsb2dvcyksIGZwcyA9IDAuNSkNCmBgYA0KDQojIDQuIExhIG3DunNpY2EgZGVsIDIwMjENCg0KRW4gZXN0YSBzZWNjacOzbiBoYWJsYXLDqSBkZSBsbyBxdWUgbcOhcyBzZSBoYSBlc2N1Y2hhZG8gZW4gZWwgw7psdGltbyBhw7FvLCBsb3MgYXJ0aXN0YXMgbcOhcyBzb25hZG9zLCBsb3MgbcOhcyBzZWd1aWRvcyB5IGxhcyBjYW5jaW9uZXMgbcOhcyBmYW1vc2FzLg0KDQoNCiMjIDQuMSBUT1AgMzAgQXJ0aXN0YXMgZGVsIDIwMjEgey50YWJzZXR9DQoNCkNvbW8gcG9kZW1vcyBvYnNlcnZhciwgbGEgYXJ0aXN0YSBtw6FzIGVzY3VjaGFkYSwgZW4gZXN0ZSAyMDIxIGhhIHNpZG8gbGEgY2FudGFudGUgZXN0YWRvdW5pZGVuc2UsICoqVGF5bG9yIFN3aWZ0KiosIGNvbiB1biB0b3RhbCBkZSAzODE0ODA0NTUgcmVwcm9kdWNjaW9uZXMuUG9yIGRldHLDoXMsIHRlbmVtb3MgYSBsYSBiYW5kYSBzdXJjb3JlYW5hIGRlIEstUG9wLCAqKkJUUyoqIGNvbiAyMzg0MDAwMjAgcmVwcm9kdWNjaW9uZXMsIHkgZW4gdGVyY2VyIGx1Z2FyLCBwb2RlbW9zIGVuY29udHJhciBhbCBjYW5hZGllbnNlICoqSnVzdGluIEJpZWJlcioqIGNvbiAyMjU4NDI0MjcgcmVwcm9kdWNjaW9uZXMuDQoNCiMjIyBHUsOBRklDTyBERSBCQVJSQVMNCg0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0NCg0KdG90YWxfc3RyZWFtc19hcnQgPC0gc3BvdGlmeV9kYXRhc2V0ICU+JSANCiAgZ3JvdXBfYnkoQXJ0aXN0KSAlPiUgDQogIG11dGF0ZShzdHJlYW1zX3RvdGFsZXMgPSBzdW0oU3RyZWFtcykpICU+JSANCiAgc2VsZWN0KEFydGlzdCwgc3RyZWFtc190b3RhbGVzLCBHZW5yZSkNCg0KdG90YWxfc3RyZWFtc19hcnRfbm9kdXAgPC0gdG90YWxfc3RyZWFtc19hcnRbIWR1cGxpY2F0ZWQodG90YWxfc3RyZWFtc19hcnQpLCBdICU+JSANCiAgZ3JvdXBfYnkoc3RyZWFtc190b3RhbGVzKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhzdHJlYW1zX3RvdGFsZXMpKSAlPiUgDQogIGZpbHRlcihzdHJlYW1zX3RvdGFsZXMgPiA0NjM0NjA2NykNCg0KDQp0cmVpbnRhX21hc19lc2N1Y2hhZG9zIDwtIHRvdGFsX3N0cmVhbXNfYXJ0X25vZHVwWy1jKDQsIDE1LCAxOSwgMjEsIDIzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICwgMjUsIDI3LCAzMywgNDEpLCBdDQoNCnRyZWludGFfbWFzX2VzY3VjaGFkb3Nfbm9fZHVwIDwtIHRyZWludGFfbWFzX2VzY3VjaGFkb3NbLWMoMjcsIDMyICwzMyAsMzQpLCBdDQoNCg0KZ2dfbWFzZXNjdWNoYWRvcyA8LSBnZ3Bsb3QodHJlaW50YV9tYXNfZXNjdWNoYWRvc19ub19kdXAsIGFlcyh4PSBBcnRpc3QsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PSBzdHJlYW1zX3RvdGFsZXMsIGZpbGw9QXJ0aXN0KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpKSArbGFicyh5ID0gIlN0cmVhbXMgVG90YWxlcyIpDQogIA0KZ2dwbG90bHkoZ2dfbWFzZXNjdWNoYWRvcykNCg0KDQoNCg0KDQoNCmBgYA0KDQojIyMgR1LDgUZJQ08gQ0lSQ1VMQVINCg0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0NCg0KDQojIFNldCBoaWdoY2hhcnRlciBvcHRpb25zDQpvcHRpb25zKGhpZ2hjaGFydGVyLnRoZW1lID0gaGNfdGhlbWVfc21wbCh0b29sdGlwID0gbGlzdCh2YWx1ZURlY2ltYWxzID0gMikpKQ0KDQpnZ19tYXNlc2N1Y2hhZG9zX2NpcmMgPC0gdHJlaW50YV9tYXNfZXNjdWNoYWRvc19ub19kdXAgJT4lDQogIGhjaGFydCgNCiAgICAicGllIiwgaGNhZXMoeCA9IEFydGlzdCwgeSA9IHN0cmVhbXNfdG90YWxlcyksDQogICAgbmFtZSA9ICJOwrogZGUgcmVwcm9kdWNjaW9uZXMiDQogICkNCg0KZ2dfbWFzZXNjdWNoYWRvc19jaXJjDQoNCg0KDQoNCmBgYA0KDQoNCg0KDQoNCg0KIyMgNC4yIFRPUCAzMCBBcnRpc3RhcyBjb24gbcOhcyBzZWd1aWRvcmVzIGVuIHNwb3RpZnkgZGVsIDIwMjENCg0KRW4gZXN0ZSBncsOhZmljbyBkZSB0YXJ0YSwgc2UgcHVlZGUgdmVyIHF1ZSBsb3MgYXJ0aXN0YXMgbcOhcyBzZWd1aWRvcywgKipOTyoqIHNvbiBsb3MgbcOhcyBlc2N1Y2hhZG9zLCB5YSBxdWUgbG9zIDMgY29uIG3DoXMgZmFucyBlbiBlc3RhIHBsYXRhZm9ybWEsIHNvbiBFZCBTaGVlcmFuLCBBcmlhbmEgR3JhbmRlIHkgRHJha2UuIEN1YW5kbyBUYXlsb3IgU3dpZnQgaGEgc2lkbyBsYSBtw6FzIGVzY3VjaGFkYSwgcGVybyBsYSA3IG3DoXMgc2VndWlkYSwgbG8gbWlzbW8gcGFzYSBjb24gQlRTIHF1ZSBoYSBwYXNhZG8gZGUgc2VyIGVsIHNlZ3VuZG8gYSBlbCBkw6ljaW1vIHByaW1lcm8uRXN0byBlcyBwb3JxdWUgZWwgaGVjaG8gZGUgcXVlIHNlYW4gbcOhcyBlc2N1Y2hhZG9zIG5vIHNpZ25pZmljYSBxdWUgc2VhbiBsb3MgbcOhcyBmYW1vc29zLCBzb2xvIHNpZ25pZmljYSBxdWUgaGFuIHNhY2FkbyBtw6FzIGNhbmNpb25lcyBlbiAyMDIxIG8gbWVqb3IgY29udGVuaWRvLg0KDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCm1hc19zZWd1aWRvcmVzIDwtIHJlYWRfZXhjZWwoImRhdG9zL2ZvbGxvd2Vyc19hcnRpc3RzXzIwMjEueGxzeCIpIA0KDQoNCiMgU2V0IGhpZ2hjaGFydGVyIG9wdGlvbnMNCm9wdGlvbnMoaGlnaGNoYXJ0ZXIudGhlbWUgPSBoY190aGVtZV9zbXBsKHRvb2x0aXAgPSBsaXN0KHZhbHVlRGVjaW1hbHMgPSAyKSkpDQoNCmdnX21hc3NlZ3VpZG9yZXMgPC0gbWFzX3NlZ3VpZG9yZXMgJT4lDQogIGhjaGFydCgNCiAgICAicGllIiwgaGNhZXMoeCA9IEFydGlzdCwgeSA9IGFydGlzdF9mb2xsb3dlcnMpLA0KICAgIG5hbWUgPSAiTsK6IGRlIHNlZ3VpZG9yZXMiDQogICkNCg0KZ2dfbWFzc2VndWlkb3Jlcw0KDQoNCg0KYGBgDQoNCg0KDQojIyA0LjMgVE9QIDMwIGNhbmNpb25lcyBtw6FzIHNvbmFkYXMgZW4gZXN0ZSAyMDIxIMKoey50YWJzZXR9DQoNCkNvbW8gcG9kZW1vcyBvYnNlcnZhciBlbiBlc3RlIGdyw6FmaWNvIGRlIGNhamEgbGFzIGNhbmNpb25lcyBtw6FzIGVzY3VjaGFkYXMgZW4gMjAyMSBoYW4gc2lkbywgZW4gcHJpbWVyIGx1Z2FyLCAqKkJlZ2dpbicqKiBkZWwgZ3J1cG8gaXRhbGlhbm8gTcOlbmVza2luIGNvbiA0ODYzMzQ0OSByZXByb2R1Y2Npb25lcywgZXN0YSBjYW5jacOzbiBmdWUgbGEgZ2FuYWRvcmEgZGUgRXVyb3Zpc2lvbi5FbiBzZWd1bmRvIGx1Z2FyLCBlc3RhICoqU1RBWSAod2l0aCBKdXN0aW4gQmllYmVyKSoqIGRlbCByYXBlcm8gYXVzdHJhbGlhbm8gVGhlIEtpZCBMQVJPSSB5IGVzdGUgdGVtYSwgYWN1bXVsYSA0NzI0ODcxOSByZXByb2R1Y2Npb25lcyBlbiBTcG90aWZ5LiBZIGVuIHRlcmNlciBsdWdhciwgbGEgY2FuY2nDs24sICoqZ29vZCA0IHUqKiBkZSBsYSBhbWVyaWNhbmEgT2xpdmlhIFJvZHJpZ28gcXVlIHRpZW5lIDQwMTYyNTU5IHJlcHJvZHVjY2lvbmVzLg0KDQojIyMgUE9SIENBTkNJT05FUyBERU5UUk8gREVMIFRPUCAzMA0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFLCBpbmNsdWRlID0gRkFMU0V9DQp0b3AxMCA8LSBzcG90aWZ5X2RhdGFzZXQgJT4lIHNlbGVjdChzb25nX25hbWUsIEFydGlzdCwgU3RyZWFtcykgJT4lIA0KIGFycmFuZ2UoZGVzYyhTdHJlYW1zKSkgJT4lIGZpbHRlcihTdHJlYW1zID4gMTU5Njc5ODUpDQoNCmxpYnJhcnkodHJlZW1hcCkNCg0KDQoNCg0KZ2dfdG9wMTAgPC0gdHJlZW1hcCh0b3AxMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmRleD1jKCJBcnRpc3QiLCJzb25nX25hbWUiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2U2l6ZT0iU3RyZWFtcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT0iaW5kZXgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZDb2xvciA9ICJBcnRpc3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplLmxhYmVscz1jKDE1LDIwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZy5sYWJlbHM9YygidHJhbnNwYXJlbnQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYWxldHRlID0gIlNldDEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFsaWduLmxhYmVscz1saXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiY2VudGVyIiwgImNlbnRlciIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoImNlbnRlciIsICJib3R0b20iKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiVE9QIDEwIDIwMjEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLmxlZ2VuZCA9ICJBcnRpc3RhcyIpIA0KDQpnZ190b3AxMA0KDQpgYGANCg0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0NCg0KI3RvcDEwIDwtIHNwb3RpZnlfZGF0YXNldCAlPiUgc2VsZWN0KHNvbmdfbmFtZSwgQXJ0aXN0LCBTdHJlYW1zKSAlPiUgDQogIyBmaWx0ZXIoU3RyZWFtcyA+IDE0MTc0NzUyKQ0KDQojbGlicmFyeSh0cmVlbWFwKQ0KDQojZ2dfdG9wXzEwIDwtIHRyZWVtYXAodG9wMTAsDQogIyAgICAgICBpbmRleD0iZ3JvdXAiLA0KICAjICAgICAgdlNpemU9InZhbHVlIiwNCiAgICMgICAgIHR5cGU9ImluZGV4IikNCg0KDQojZ2dfdG9wMTAgPC0gdHJlZW1hcCh0b3AxMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjaW5kZXg9YygiQXJ0aXN0Iiwic29uZ19uYW1lIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgI3ZTaXplPSJTdHJlYW1zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjdHlwZT0iaW5kZXgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICN2Q29sb3IgPSAiQXJ0aXN0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjZm9udHNpemUubGFiZWxzPWMoMTUsMjApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICNiZy5sYWJlbHM9YygidHJhbnNwYXJlbnQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjcGFsZXR0ZSA9ICJTZXQxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjYWxpZ24ubGFiZWxzPWxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYygiY2VudGVyIiwgImNlbnRlciIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjICBjKCJjZW50ZXIiLCAiYm90dG9tIikpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICN0aXRsZSA9ICJUT1AgMTAgMjAyMSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgI3RpdGxlLmxlZ2VuZCA9ICJBcnRpc3RhcyIpIA0KDQojZ2dfdG9wMTANCg0KDQoNCmBgYA0KDQpgYGB7ciwgZmlnLmFsaWduPSdjZW50ZXInLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCmludGVyX3RvcDEwIDwtIGQzdHJlZTIoZ2dfdG9wMTAgLCAgcm9vdG5hbWUgPSAiVE9QIDMwIENhbmNpb25lcyBtw6FzIGVzY3VjaGFkYXMgZGVsIDIwMjEgeSBzdXMgQXJ0aXN0YXMiKQ0KaW50ZXJfdG9wMTANCg0KDQpgYGANCg0KIyMjIFRBQkxBIFJBTktJTkcgVE9QIDMwDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCmtuaXRyOjprYWJsZSh0b3AxMCwgY2FwdGlvbiA9ICJUT1AgMzAgMjAyMSIpICU+JSANCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkgICU+JSANCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhmaXhlZF90aGVhZCA9IGxpc3QoZW5hYmxlZCA9IFQsIGJhY2tncm91bmQgPSAiY2hhcnRyZXVzZSIpKQ0KDQpgYGANCg0KIyA1LiBSZWdnYWV0b24gdnMgUE9QDQoNClNlZ8O6biB2YXJpYXMgZnVlbnRlcyBkZSBpbmZvcm1hY2nDs24sIGxvcyBkb3MgZ2VuZXJvcyBtw6FzIGVzY3VjaGFkb3MgZW4gbGEgYWN0dWFsaWRhZCBzb24gZWwgcG9wIHkgZWwgcmVnZ2FldG9uLkVuIGVzdGUgYXBhcnRhZG8gdmFtb3MgYSBjb21wYXJhciBsb3MgZG9zIGdlbmVyb3MgbWVkaWFudGUgZGlzdGludG9zIGFzcGVjdG9zLCBsYSBzdW1hIGRlIHRvZGFzIGxhcyByZXByb2R1Y2Npb25lcyBkZSBjYWRhIGfDqW5lcm8gZW4gMjAyMSwgbGEgYmFpbGFiaWxpZGFkIGRlIGNhZGEgZ8OpbmVybyB5IGxhIHBvcHVsYXJpZGFkLg0KDQojIyA1LjEgUXVlIGfDqW5lcm8gaGEgdGVuaWRvIG3DoXMgcmVwcm9kdWNjaW9uZXMgZW4gMjAyMQ0KDQpQYXJhIGNvbXBhcmFyIGhlbW9zIHN1bWFkbyB0b2RhcyBsYXMgcmVwcm9kdWNjaW9uZXMgZGUgbGFzIGNhbmNpb25lcyBkZSBwb3AgZW4gMjAyMS5FbiBlc3RlIGdyw6FmaWNvIGRlIGJhcnJhcyBwb2RlbW9zIHZlciwgcXVlIGVsIHBvcCBzZSBoYSBlc2N1Y2hhZG8gbXVjaG8gbcOhcyBxdWUgZWwgcmVnZ2FldG9uIGR1cmFudGUgZXN0ZSBhw7FvLg0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KcmVnZ2FldG9uIDwtIHNwb3RpZnlfZGF0YXNldCAlPiUgDQogIHNlbGVjdChBcnRpc3QsIHNvbmdfbmFtZSwgU3RyZWFtcywgR2VucmUsIFBvcHVsYXJpdHksIERhbmNlYWJpbGl0eSwgRW5lcmd5KSAlPiUNCiAgZmlsdGVyKHN0cmluZ3I6OnN0cl9kZXRlY3QoR2VucmUsICdyZWdnYWV0b24nKSApICU+JSANCiAgbXV0YXRlKHN0cmVhbXNfdG90YWxlcyA9IHN1bShTdHJlYW1zKSkgDQoNCg0KcG9wIDwtIHNwb3RpZnlfZGF0YXNldCAlPiUgDQogIHNlbGVjdChBcnRpc3QsIHNvbmdfbmFtZSwgU3RyZWFtcywgR2VucmUsIFBvcHVsYXJpdHksIERhbmNlYWJpbGl0eSwgRW5lcmd5KSAlPiUNCiAgZmlsdGVyKHN0cmluZ3I6OnN0cl9kZXRlY3QoR2VucmUsICdwb3AnKSApICU+JSANCiAgbXV0YXRlKHN0cmVhbXNfdG90YWxlcyA9IHN1bShTdHJlYW1zKSkNCg0KDQpyZWdnYWV0b25fdnNfcG9wIDwtIHJiaW5kKHJlZ2dhZXRvbiwgcG9wKSAlPiUgDQogIHNlbGVjdChHZW5yZSwgc3RyZWFtc190b3RhbGVzKQ0KDQpyZWdnYWV0b25fdnNfcG9wX3NvbG9fc3RyZWFtcyA8LSByZWdnYWV0b25fdnNfcG9wW2MoMjksMTg1KSwgXQ0KDQoNCmdnX3ZzX3N0cmVhbXMgPC0gZ2dwbG90KHJlZ2dhZXRvbl92c19wb3Bfc29sb19zdHJlYW1zLCBhZXMoeD1HZW5yZSwgeT1zdHJlYW1zX3RvdGFsZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gc3RyZWFtc190b3RhbGVzKSkgKyANCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikpICtsYWJzKHggPSAiR2VuZXJvIiwgeSA9ICJTdHJlYW1zIFRvdGFsZXMiKQ0KDQoNCmdncGxvdGx5KGdnX3ZzX3N0cmVhbXMpDQoNCmBgYA0KDQoNCiMjIDUuMiBRdWUgZ8OpbmVybyBoYSBzaWRvIG3DoXMgYmFpbGFibGUgZW4gMjAyMQ0KDQpQYXJhIGxsZXZhciBhIGNhYm8gZXN0YSBjb21wYXJhY2nDs24sIGhlIHJlYWxpemFkbyBsYSBtZWRpYSBkZSBsYSBiYWlsYWJpbGlkYWQgZGUgdG9kYXMgbGFzIGNhbmNpb25lcyBkZSBjYWRhIGfDqW5lcm8sIGVzIGRlY2lyLCBoZSBzdW1hZG8gbGEgYmFpbGFiaWxpZGFkIGRlIHRvZGFzIGxhcyBjYW5jaW9uZXMgZGUgcG9wIHkgZGUgcmVnZ2FldG9uLCB5IGxvIGhlIGRpdmlkaWRvIGVudHJlIGVsIG7CuiBkZSB0ZW1hcyBkZSBjYWRhIHVubyAuWSBjb21vIHBvZGVtb3Mgb2JzZXJ2YXIsIGxhcyBjYW5jaW9uZXMgZGUgcmVnZ2FldG9uIGhhbiBzaWRvIG3DoXMgYmFpbGFibGVzIHF1ZSBsYXMgZGUgcG9wIGVuIHVuIDglLg0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KDQpyZWdnYWV0b25fYmFpbGEgPC0gcmVnZ2FldG9uICU+JSBzdW1tYXJpc2UobWVkaWFfYmFpbGFiaWxpZGFkID0gbWVhbihEYW5jZWFiaWxpdHkpKQ0KDQpwb3BfYmFpbGEgPC0gcG9wICU+JSBzdW1tYXJpc2UobWVkaWFfYmFpbGFiaWxpZGFkID0gbWVhbihEYW5jZWFiaWxpdHkpKQ0KDQpyZWdnYWV0b25fdnNfcG9wX2JhaWxhIDwtIHJiaW5kKHJlZ2dhZXRvbl9iYWlsYSwgcG9wX2JhaWxhKQ0KDQpyZWdnYWV0b25fdnNfcG9wX2JhaWxhX2JpZW4gPC0gY2JpbmQocmVnZ2FldG9uX3ZzX3BvcF9iYWlsYSwgR2VucmU9YygicmVnZ2FldG9uIiwicG9wIikpDQoNCmdnX3ZzX2JhaWxhIDwtIGdncGxvdChyZWdnYWV0b25fdnNfcG9wX2JhaWxhX2JpZW4sIGFlcyh4PUdlbnJlLCB5PW1lZGlhX2JhaWxhYmlsaWRhZCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBtZWRpYV9iYWlsYWJpbGlkYWQpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgICsgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikpICtsYWJzKHggPSAiR2VuZXJvIiwgeSA9ICJNZWRpYSBkZSBCYWlsYWJpbGlkYWQiKQ0KDQoNCg0KZ2dwbG90bHkoZ2dfdnNfYmFpbGEpDQoNCg0KYGBgDQoNCg0KIyMgNS4zIFF1ZSBnw6luZXJvIGhhIHNpZG8gbcOhcyBwb3B1bGFyIGVuIDIwMjENCg0KUGFyYSByZWFsaXphciBlc3RhIGNvbXBhcmFjacOzbiwgaGVtb3Mgc3VtYWRvIGxhIHBvcHVsYXJpZGFkIGRlIHRvZGFzIGxhcyBjYW5jaW9uZXMgZGUgY2FkYSBnw6luZXJvIHkgbG8gaGVtb3MgZGl2aWRpZG8gZW50cmUgZWwgbsK6IGRlIGNhbmNpb25lcyBkZSBjYWRhIHVuby5UcmFzIG9ic2VydmFyIGVsIGdyw6FmaWNvLCBwb2RlbW9zIG9idGVuZXIgdW5hIGNvbmNsdXNpw7NuLCBsYXMgY2FuY2lvbmVzIGRlIHJlZ2dhZXRvbiBzb24gbcOhcyBwb3B1bGFyZXMgcXVlIGxhcyBkZSBwb3Agbm9ybWFsbWVudGUuDQoNCg0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0NCg0KcmVnZ2FldG9uX3BvcHUgPC0gcmVnZ2FldG9uICU+JSBzdW1tYXJpc2UobWVkaWFfcG9wdWxhcmlkYWQgPSBtZWFuKFBvcHVsYXJpdHkpKQ0KDQpwb3BfcG9wdSA8LSBwb3AgJT4lIHN1bW1hcmlzZShtZWRpYV9wb3B1bGFyaWRhZCA9IG1lYW4oUG9wdWxhcml0eSkpDQoNCnJlZ2dhZXRvbl92c19wb3BfcG9wdSA8LSByYmluZChyZWdnYWV0b25fcG9wdSwgcG9wX3BvcHUpDQoNCnJlZ2dhZXRvbl92c19wb3BfcG9wdV9iaWVuIDwtIGNiaW5kKHJlZ2dhZXRvbl92c19wb3BfcG9wdSwgR2VucmU9YygicmVnZ2FldG9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3AiKSkNCg0KZ2dfdnNfcG9wdSA8LSBnZ3Bsb3QocmVnZ2FldG9uX3ZzX3BvcF9wb3B1X2JpZW4sIGFlcyh4PUdlbnJlLCB5PW1lZGlhX3BvcHVsYXJpZGFkLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gbWVkaWFfcG9wdWxhcmlkYWQpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkgK2xhYnMoeCA9ICJHZW5lcm8iLCB5ID0gIk1lZGlhIGRlIGxhIFBvcHVsYXJpZGFkIikNCg0KDQpnZ3Bsb3RseShnZ192c19wb3B1KQ0KDQpgYGANCg0KDQojIDYuIEFzcGVjdG9zIG11c2ljYWxlcyBkZWwgMjAyMQ0KDQpFbiBlc3RlIGFwYXJ0YWRvIG9ic2VydmFyZW1vcyB2YXJpYXMgY2FyYWN0ZXLDrXN0aWNhcyBxdWUgdGllbmVuIHF1ZSB2ZXIgY29uIGxhIG3DunNpY2EsIGNvbW8gZXMgZWwgKip0ZW1wbyoqLCBsb3MgKiphY29yZGVzKiosIGxhICoqZW5lcmfDrWEqKiB5IGxhICoqYmFpbGFiaWxpZGFkKioNCg0KIyMgNi4xIFF1ZSB0ZW1wbyBkZWJlbiB0ZW5lciBsYXMgY2FuY2lvbmVzIHBhcmEgc2VyIGJhaWxhYmxlcz8NCg0KQ29tbyBwb2RlbW9zIG9ic2VydmFyIGVuIGVzdGUgZ3LDoWZpY28gZGUgZGlzcGVyc2nDs24sIGxhcyBjYW5jaW9uZXMgcGFyYSBzZXIgYmFpbGFibGVzIChkYW5jZWFiaWxpdHk+PSAwLDc1KSwgaGFuIGRlIHRlbmVyIHVuIHRlbXBvIGVudHJlIDEwMCB5IDE1MCwgc2kgdGllbmVuIHVuIHRlbXBvIG1heW9yIHNvbiBkZW1hc2lhZG8gcsOhcGlkYXMgcGFyYSBzZXIgYmFpbGFkYXMgcG9yIHRhbnRvIHN1IGJhaWxhYmlsaWRhZCBjYWUsIHkgc2kgdGllbmVuIHVuIHRlbXBvIG1lbm9yIHF1ZSAxMDAsIHNvbiBkZW1hc2lhZG8gbGVudGFzLg0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KDQoNCmdnXzEgPC0gZ2dwbG90KHNwb3RpZnlfZGF0YXNldCkgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1UZW1wbywgeT1EYW5jZWFiaWxpdHkpLCBjb2xvdXIgPSAiY2hhcnRyZXVzZTMiKSArIA0KICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKHg9VGVtcG8sIHk9RGFuY2VhYmlsaXR5KSwgY29sb3IgPSAiYmxhY2siKSArIA0KICBsYWJzKHRpdGxlPSJUZW1wbyBkZSBsYSBjYW5jacOzbiB2cyBCYWlsYWJpbGlkYWQiKSArDQogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpKSArbGFicyh5ID0gIkJhaWxhYmlsaWRhZCIpDQpnZ3Bsb3RseShnZ18xKQ0KDQoNCg0KYGBgDQoNCg0KIyMgNi4yIFF1ZSBlbmVyZ2lhIHN1ZWxlbiB0ZW5lciBsYXMgY2FuY2lvbmVzIG3DoXMgYmFpbGFibGVzPw0KDQpMYXMgY2FuY2lvbmVzIG3DoXMgYmFpbGFibGVzLCBzZWfDum4gZWwgZ3LDoWZpY28gZGUgZGlzcGVyc2lvbiwgc3VlbGVuIHRlbmVyIHVuYXMgZW5lcmfDrWEgZW50cmUgMCw2MCB5IDAsNzUuIFNpIGxhcyBjYW5jaW9uZXMgdGllbmVuIHVuYSBlbmVyZ8OtYSBtZW5vciwgbm8gaW5jaXRhbiBhbCBtb3ZpbWllbnRvIHkgcG9yIHRhbnRvLCB0aWVuZW4gdW5hIGJhaWxhYmlsaWRhZCBtdXkgYmFqYQ0KDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCmdnXzIgPC0gZ2dwbG90KHNwb3RpZnlfZGF0YXNldCkgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1FbmVyZ3ksIHk9RGFuY2VhYmlsaXR5KSwgY29sb3VyID0gImNoYXJ0cmV1c2UzIikgKyANCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyh4PUVuZXJneSwgeT1EYW5jZWFiaWxpdHkpLCBjb2xvciA9ICJibGFjayIpICsgDQogIGxhYnModGl0bGU9IkVuZXJnw61hIGRlIGxhIGNhbmNpw7NuIHZzIEJhaWxhYmlsaWRhZCIpICsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikpICtsYWJzKHggPSAiRW5lcmfDrWEgZGUgbGEgQ2FuY2nDs24iLCB5ID0gIkJhaWxhYmlsaWRhZCIpDQpnZ3Bsb3RseShnZ18yKQ0KDQoNCg0KYGBgDQoNCg0KIyMgNi4zIExhcyBjYW5jaW9uZXMgbcOhcyBwb3B1bGFyZXMgc29uIGxhcyBtw6FzIGJhaWxhYmxlcz8NCg0KTGEgcmVzcHVlc3RhIGEgZXN0YSBwcmVndW50YSBlcyBzaSwgeWEgcXVlIGNvbW8gcG9kZW1vcyB2ZXIsIGxhcyBjYW5jaW9uZXMgY29uIHVuYSBwb3B1bGFyaWRhZCBwb3IgZW5jaW1hIGRlIDc1LCBxdWUgZXN0byBzaWduaWZpY2EgcXVlIHNvbiBjYW5jaW9uZXMgcG9wdWxhcmVzIGEgbml2ZWwgbXVuZGlhbCB5IHF1ZSBoYW4gZXN0YWRvIGVuIGxvcyB0b3BzIHZhcmlhcyB2ZWNlcywgdGllbmVuIHVuYSBiYWlsYWJpbGlkYWQgcG9yIGVuY2ltYSBkZSAwLDY1LCBlcyBkZWNpciwgcXVlIHNpIHNvbiBwb3B1bGFyZXMgc29uIGJhc3RhbnRlIGJhaWxhYmxlcywgeWEgcXVlIGVzdG9zIHNpZ25pZmljYSBxdWUgc3Ugcml0bW8sIHN1IGxldHJhIHkgc3UgbWVsb2RpYSBzb24gbcOhcyBwZWdhZGl6YXMuDQoNCmBgYHtyLCBldmFsID0gVFJVRSwgZWNobyA9IFRSVUV9DQoNCmdnXzMgPC0gZ2dwbG90KHNwb3RpZnlfZGF0YXNldCkgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1EYW5jZWFiaWxpdHksIHk9UG9wdWxhcml0eSksIGNvbG91ciA9ICJjaGFydHJldXNlMyIpICsgDQogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoeD1EYW5jZWFiaWxpdHksIHk9UG9wdWxhcml0eSksIGNvbG9yID0gImJsYWNrIikgKyANCiAgbGFicyh0aXRsZT0iUG9wdWxhcmlkYWQgdnMgQmFpbGFiaWxpZGFkIikgKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkgK2xhYnMoeCA9ICJCYWlsYWJpbGlkYWQiLCB5ID0gIlBvcHVsYXJpZGFkIikNCmdncGxvdGx5KGdnXzMpDQoNCg0KYGBgDQoNCg0KIyMgNi40IFF1ZSBhY29yZGUgdXNhbiBsYXMgY2FuY2lvbmVzIG3DoXMgcG9wdWxhcmVzPw0KDQpFbiBlc3RlIGdyw6FmaWNvIGRlIGJhcnJhcyBzZSBwdWVkZSBvYnNlcnZhciBxdWUsIGxhcyBjYW5jaW9uZXMgY29uIG1heW9yIHBvcHVsYXJpZGFkIHNvbiBsYXMgcXVlIHV0aWxpemFuIGVsIGFjb3JkZSAqKkMjL0RiKiosIHkgbGFzIHF1ZSBtZW5vcyBwb3B1bGFyZXMgc29uIGxhcyBxdWUgdXRpbGl6YW4gZWwgYWNvcmRlICoqRCMvRWIqKi4NCg0KYGBge3IsIGV2YWwgPSBUUlVFLCBlY2hvID0gVFJVRX0NCg0KDQpnZ180IDwtIGdncGxvdChzcG90aWZ5X2RhdGFzZXQsIGFlcyh4PUNob3JkLCB5PVBvcHVsYXJpdHkpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSJibGFjayIgLGZpbGwgPSAiY2hhcnRyZXVzZTMiKSArDQoNCiB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkgK2xhYnModGl0bGUgPSAiUG9wdWxhcmlkYWQgdnMgQWNvcmRlIiwgeCA9ICJBY29yZGUiLA0KICAgIHkgPSAiUG9wdWxhcmlkYWQiKQ0KZ2dfNA0KDQoNCmBgYA0KDQoNCiMgNy4gUmVnZ2FldG9uIGVuIGVsIDIwMjENCg0KRW4gbG9zIHVsdGltb3MgYcOxb3MsIGVzdGUgZ8OpbmVybyBtdXNpY2FsIGhhIGlkbyBhdW1lbnRhbmRvIHN1IHBvcHVsYXJpZGFkIGEgbml2ZWxlcyBlc3RyYXRvc2bDqXJpY29zLCBoYSBwYXNhZG8gZGUgc2VyIHNvbG8gZXNjdWNoYWRvIGVuIHBhaXNlcyBsYXRpbm9zLCBoYSBzZXIgdW5vIGRlIGxvcyBtw6FzIGZhbW9zb3MgYSBuaXZlbCBtdW5kaWFsLkVzdGUgYcOxbywgbG9zIDMgYXJ0aXN0YXMgZGUgcmVnZ2FldG9uIG3DoXMgaW1wb3J0YW50ZXMgaGFuIHNpZG8gQmFkIEJ1bm55LCBSYXV3IEFsZWphbmRybyB5IEogQmFsdmluLg0KDQpgYGB7ciwgZXZhbCA9IFRSVUUsIGVjaG8gPSBUUlVFfQ0KDQpiYl9yYV9qIDwtIHNwb3RpZnlfZGF0YXNldCAlPiUgDQogIHNlbGVjdChBcnRpc3QsIFN0cmVhbXMsIGFydGlzdF9mb2xsb3dlcnMsIHNvbmdfbmFtZSwgYE51bWJlciBvZiBUaW1lcyBDaGFydGVkYCkgJT4lIA0KICBmaWx0ZXIoQXJ0aXN0ICVpbiUgYygiQmFkIEJ1bm55IiwgIlJhdXcgQWxlamFuZHJvIiwiSiBCYWx2aW4iKSkNCg0KdG90YWxfc3RyZWFtc19iYl9yYV9qIDwtIHRyZWludGFfbWFzX2VzY3VjaGFkb3NbYyg1LDMxLDMyKSwgXSAlPiUgDQogIHNlbGVjdChBcnRpc3QsIHN0cmVhbXNfdG90YWxlcykNCg0KY29tcGFyYWNpb25fcmVnZ2FldG9uIDwtIGZ1bGxfam9pbihiYl9yYV9qLHRvdGFsX3N0cmVhbXNfYmJfcmFfaiwgYygiQXJ0aXN0IiA9ICJBcnRpc3QiKSkgJT4lIA0KICBzZWxlY3QoQXJ0aXN0LHN0cmVhbXNfdG90YWxlcyxhcnRpc3RfZm9sbG93ZXJzKSANCg0KY29tcGFyYWNpb25fcmVnZ2FldG9uXzMgPC0gY29tcGFyYWNpb25fcmVnZ2FldG9uW2MoMSwyLDcpLCBdDQoNCmNvbXBhcmFjaW9uX3JlZ2dhZXRvbl9lZGFkIDwtIGNiaW5kKGNvbXBhcmFjaW9uX3JlZ2dhZXRvbl8zLCBFZGFkPWMoIjI3IiwiMjgiLCAiMzYiKSkNCg0KDQoNCmZvdG9zX3JlZ2dhZXRvbl9hcnRpc3RhcyA8LSBjKCIuL2ltYWdlbmVzL2JhZF9idW5ueS5wbmciLCAiLi9pbWFnZW5lcy9yYXV3X2FsZWphbmRyby5wbmciLCIuL2ltYWdlbmVzL2pfYmFsdmluLnBuZyIpDQoNCmZvdG9zX3ByX2NvbCA8LSBjKCIuL2ltYWdlbmVzL1B1ZXJ0b19SaWNvLnBuZyIsIi4vaW1hZ2VuZXMvUHVlcnRvX1JpY28ucG5nIiwgIi4vaW1hZ2VuZXMvQ29sb21iaWEucG5nIikNCg0KY29tcGFyYWNpb25fcmVnZ2FldG9uX2JpZW4gPC0gY29tcGFyYWNpb25fcmVnZ2FldG9uX2VkYWQgJT4lIGFkZF9jb2x1bW4oZm90b3NfcmVnZ2FldG9uX2FydGlzdGFzLCBmb3Rvc19wcl9jb2wpDQoNCmxpYnJhcnkoZ3QpDQoNCnJlZ2dhZXRvbl90YWJsYSA8LSBjb21wYXJhY2lvbl9yZWdnYWV0b25fYmllbiAlPiUgZ3QoKSAlPiUgDQogIHRleHRfdHJhbnNmb3JtKCBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBjKGZvdG9zX3JlZ2dhZXRvbl9hcnRpc3RhcykpLCBmbiA9IGZ1bmN0aW9uKHgpIHtndDo6bG9jYWxfaW1hZ2UoeCwgaGVpZ2h0ID0gODApfSkgJT4lIA0KICB0ZXh0X3RyYW5zZm9ybSggbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gYyhmb3Rvc19wcl9jb2wpKSwgZm4gPSBmdW5jdGlvbih4KSB7Z3Q6OmxvY2FsX2ltYWdlKHgsIGhlaWdodCA9IDgwKX0pICU+JSB0YWJfaGVhZGVyKHRpdGxlID0gbWQoIioqVE9QIEFSVElTVEFTIFJFR0dBRVRPTiAyMDIxKioiKSwgc3VidGl0bGUgPSBtZCgiQ29tcGFyYWNpw7NuIikpICU+JSAgIGNvbHNfbGFiZWwoDQogICAgQXJ0aXN0ID0gaHRtbCgiQXJ0aXN0YSIpLA0KICAgIHN0cmVhbXNfdG90YWxlcyA9IGh0bWwoIlRvdGFsIFJlcHJvZHVjY2lvbmVzIiksDQogICAgYXJ0aXN0X2ZvbGxvd2VycyA9IGh0bWwoIlNlZ3VpZG9yZXMgU3BvdGlmeSIpLA0KICAgIGZvdG9zX3JlZ2dhZXRvbl9hcnRpc3RhcyA9IGh0bWwoIiIpLA0KICAgIGZvdG9zX3ByX2NvbCA9IGh0bWwoIiIpKSAlPiUgIA0KICB0YWJfb3B0aW9ucyh0YWJsZS5iYWNrZ3JvdW5kLmNvbG9yID0gIndoaXRlIiwgICB0YWJsZS5mb250LmNvbG9yLmxpZ2h0ID0gImNoYXJ0cmV1c2UiKSAlPiUgDQogIGNvbHNfYWxpZ24oYWxpZ24gPSAiY2VudGVyIiwNCiAgY29sdW1ucyA9IGV2ZXJ5dGhpbmcoKSkNCg0KcmVnZ2FldG9uX3RhYmxhDQoNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCiMgNC4gQmlibGlvZ3JhZsOtYQ0KDQotIFtQw6FnaW5hIHdlYiBkZSBsYSBhc2lnbmF0dXJhLl0oaHR0cHM6Ly9wZXJlenA0NC5naXRodWIuaW8vaW50cm8tZHMtMjEtMjItd2ViLzA0LXR1dG9yaWFsZXMuaHRtbCkNCg0KLSBbS2FnZ2xlIHNvYnJlIFNwb3RpZnkuXShodHRwczovL3d3dy5rYWdnbGUuY29tL3Nhc2hhbmtwaWxsYWkvc3BvdGlmeS10b3AtMjAwLWNoYXJ0cy0yMDIwMjAyMSkNCg0KLSBbU3RhdGlzdGEuXShodHRwczovL3d3dy5zdGF0aXN0YS5jb20vdG9waWNzLzIwNzUvc3BvdGlmeS8jZG9zc2llcktleWZpZ3VyZXMpDQoNCi0gW0RhdG9zIFNwb3RpZnkgU2VtYW5hbGVzLl0oaHR0cHM6Ly9zcG90aWZ5Y2hhcnRzLmNvbS9yZWdpb25hbCkNCg0KPGJyPjxicj4NCg0KPGhyIGNsYXNzPSJsaW5lYS1yZWQiPg0KPGhyIGNsYXNzPSJsaW5lYS1yZWQiPg0KDQoNCg0KDQo8YnI+PGJyPg0KDQo8ZGl2IGNsYXNzPSJ0b2NpZnktZXh0ZW5kLXBhZ2UiIGRhdGEtdW5pcXVlPSJ0b2NpZnktZXh0ZW5kLXBhZ2UiIHN0eWxlPSJoZWlnaHQ6IDA7Ij48L2Rpdj4NCjxicj48YnI+DQoNCjxkaXYgY2xhc3M9InRvY2lmeS1leHRlbmQtcGFnZSIgZGF0YS11bmlxdWU9InRvY2lmeS1leHRlbmQtcGFnZSIgc3R5bGU9ImhlaWdodDogMDsiPjwvZGl2Pg0K