Analisis sobre el timeline
3- Unimos los dataframes
Vamos a usar un solo Dataframe que llamaremos Tweets_Club y lo vamos a hacer con la funcion rbind de R base
El nuevo Dataframe va a contar con 3200*5 filas = 16000 y contiene 3200 tweets de cada una de las cuentas
Tweets_Club <- rbind(Tweets_BocaJrs, Tweets_Racing, Tweets_SanLorenzo, Tweets_RiverPlate, Tweets_Independiente)
4- Comenzamos el proceso de limpieza
Vamos a crear algunas columnas extras para obtener mas información y también vamos a filtrar datos, para quedarnos solo con los que nos interesa
Tweets_Club <- Tweets_Club%>%
tbl_df %>%
mutate(text = gsub("[^[:graph:]]", " ", text)) %>% #Sin graficos
mutate(text = tolower(text)) %>% #Todo el texto a minuscula
mutate(created_at = with_tz(created_at, "America/Argentina/Buenos_Aires"))%>% #Cambiamos a la zona horaria correspondiente
separate(created_at, into = c("date", "hour"), sep = " ")%>% #Separamos en dia y hora el campo created_at
separate(hour, into = c("hour", "minutes","seconds"), sep = ":")%>% #Separamos la hora en hora,minutos y segundos
rename(Club = screen_name) %>% #Cambiamos la columna con el nombre del club
mutate(periodo = year(date),
mes = month(date, label = T, abbr = F),
dia = as.numeric(day(date)),
dia_sem = wday(date, label = T, abbr = F, week_start = 1),
dia_per = yday(date),
date = as.Date(date) #Creamos una columna con el numero de año, mes, dia, nombre de dia y de mes.
)%>%
filter(periodo == 2020) #Solo vamos a utilizar info de 2020
El nuevo DataFrame sera de 9660 observaciones
5- Creamos ciertos temas graficos
Para tener una mejor visualizacion, precargamos algunos temas y le damos el color a cada club
tema_plot <-
theme(text = element_text(family = "sans", size = 10),
panel.border = element_rect(color = "#cccccc", fill = NA),
panel.background = element_rect(fill = "white"),
panel.grid.major = element_line(color = "#dddddd"),
panel.grid.minor = element_line(color = "#eeeeee"),
axis.ticks = element_line(colour = "#cccccc"),
strip.background = element_rect(color = "#cccccc", fill = "#eeeeee"),
legend.position = "top")
tema_graf <- theme_minimal() +
theme(text = element_text(family = "serif"),
panel.grid.minor = element_blank(),
strip.background = element_rect(fill = "#EBEBEB", colour = NA),
legend.position = "none",
legend.box.background = element_rect(fill = "#EBEBEB", colour = NA))
colours <- c(
"#1746f8", # BocaJrsOficial
"#cd0000", # Independiente
"#13e4fc", # RacingClub
"#9b5b53", # River Plate
"#001256" # SanLorenzo
)
9- Cantidad de interacciones
Creamos un pequeño DF para sumarizar todas las iteracciones que tienen los distintos clubes, y le agregamos su cantidad de followers (dividido 1000)
Interacciones = Tweets_Club %>%
group_by(Club)%>%
summarise(PromedioRT = mean(retweet_count),
TotalRT = sum(retweet_count),
PromedioFAV = mean(favorite_count),
TotalFAV = sum(favorite_count),
TotalInteracciones = TotalFAV + TotalRT,
PromedioInteracciones = PromedioRT + PromedioFAV
) %>%
mutate(followers = ifelse (Club == "BocaJrsOficial", 3800,
ifelse (Club == "Independiente", 454.4,
ifelse (Club == "RacingClub", 330.5,
ifelse (Club == "RiverPlate", 3400,
753.4
)
)
)
)
)
`summarise()` ungrouping output (override with `.groups` argument)
print(Interacciones)
11- Favoritos a la cuenta
Medimos los FAV que tuvo cada uno de los clubes, tanto en cantidad total que va de la mano de las publicaciones, así como tambien el promedio.
Se nota una clara diferencia entre River, que ademas se asentua contra Boca, mientras que los otros clubes están muy por debajo en cuanto a FAVs recibidos
Interacciones %>%
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
ggplot()+
aes(x=reorder(Club, -TotalFAV), y= TotalFAV, fill= Club) +
geom_col() +
labs(title = "Cantidad total de FAV", x = "Club", y = "Cantidad") +
scale_fill_manual(values= colours) +
tema_graf

Interacciones %>%
ggplot()+
aes(x=reorder(Club, -PromedioFAV), y= PromedioFAV, fill= Club) +
geom_col() +
labs(title = "Cantidad promedio de FAV", x = "Club", y = "Cantidad") +
scale_fill_manual(values= colours) +
tema_plot

12- Cantidad promedio de interacciones
Sumamos lo visto anteriormente, tomando un solo campo “Interaccion” como la suma de los promedios de FAVs y de RTs, las diferencias que se notan son las mismas que en los anteriores gráficos.

13- Cantidad promedio de interacciones
Normalizamos la cantidad de interacciones que tuvieron por cada 1000 seguidores, ahí se nota que Racing e Independiente si bien sus interacciones son menor, se debe a la cantidad de followers que tiene cada uno, cuando normalizamos quedan en un primer nivel junto a River.
Mientras que Boca no logra llegar a 1 interacción por cada mil followers, estando en un segundo pelotón, mientras que San Lorenzo es el que menos interacciones recibe con su gente.
Interacciones %>%
ggplot()+
aes(x=reorder(Club, (PromedioInteracciones/followers)), y= (PromedioInteracciones/followers), color= Club) +
geom_point(shape=23, fill=colours, color=colours, size=5) +
labs(title = "Cantidad promedio de interacciones x 1000 followers", x = "Club", y = "Cantidad") +
scale_fill_manual(values= colours) +
tema_plot

Analisis sobre followers
1 - Descargamos los followers
Con la funcion “get_followers” del paquete “rtweet” podemos descargar el ID de todos los seguidores de una cuenta y luego con la “funcion lookup_users” obtenemos la información más precisa de los seguidores.
n = “all” es el máximo de cantidad de seguidores que podes descargar de una cuenta, en este caso es 75 mil usuarios, que se tomara como Muestra aleatoria simple
2 - Agregamos una identificación de cada club
Le ponemos una identificación a cada usuario, de que club sigue, y luego unimos nuevamente con la función Rbind para tener un DataFrame único
for(i in 1:nrow(Followers_Independiente)) {
Followers_Independiente$Sigue <- c ("Independiente")
}
for(i in 1:nrow(Followers_BocaJrs)) {
Followers_BocaJrs$Sigue <- c ("Boca")
}
for(i in 1:nrow(Followers_SanLorenzo)) {
Followers_SanLorenzo$Sigue <- c ("San Lorenzo")
}
for(i in 1:nrow(Followers_RacingClub)) {
Followers_RacingClub$Sigue <- c ("Racing")
}
for(i in 1:nrow(Followers_RiverPlate)) {
Followers_RiverPlate$Sigue <- c ("River Plate")
}
Followers_Club <- rbind(Followers_BocaJrs, Followers_RacingClub, Followers_SanLorenzo, Followers_RiverPlate, Followers_Independiente)
3- Cantidad seguidores
El club con mas seguidores es Boca, que cuenta con casi 3.8 MM, en un segundo nivel River con casi 3.5 MM de seguidores, y luego el resto de los clubes en torno a los 500K de seguidores
Interacciones %>%
ggplot()+
aes(x=reorder(Club, -followers), y= (followers*1000), fill= Club) +
geom_col() +
labs(title = "Cantidad followers", x = "Club", y = "Cantidad") +
scale_fill_manual(values= colours) +
tema_plot

4- Desde que interfaz lo siguen
El comportamiento desde donde lo siguen los usuarios es parecida en todos los clubes, predonima Android, luego Iphone y web en un nivel parecido, y un grupo pequeño desde Instagram y la Web Client de twitter.
Se filtra en un mínimo de 300 los seguidores que usen esa plataforma, para evitar que sea infinita la cantidad de variables.

5- Idioma de los followers
Se saca proporcionalmente la cantidad de idiomas que son hablados por los seguidores que tiene cada una de las cuentas.
Como corresponde, la mayoria habla en español, la cantidad de seguidores en ingles es parecida entre todas las cuentas.
El portugues es el otro idioma importante entre los clubes.
Followers_Club %>%
group_by(Sigue) %>%
count(lang) %>%
filter(n > 300) %>%
filter(!is.na(lang)) %>%
filter(lang != "und") %>%
filter(lang != "ar")%>%
mutate(Proporcion = n / sum(n)) %>%
ggplot() +
aes(Sigue, Proporcion, fill = lang) +
geom_col() +
scale_y_continuous(labels = percent_format()) +
tema_plot

7- Actividad de los seguidores
Primero creamos los campos para la fecha created_at como hicimos con el DF de tweets, y adjuntamos un campo de actividad, para saber cual es la relación del usuario con Twitter.
Los clubes con menos seguidores son los que tienen seguidores con más tiempo sin actividad, mientras que los siguen a clubes grandes estan mayormente en actividad.

LS0tDQp0aXRsZTogIkFuYWxpc2lzIDUgZ3JhbmRlcyBlbiBUd2l0dGVyIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyBBbmFsaXNpcyBzb2JyZSBlbCB0aW1lbGluZQ0KDQojIyAxLSBDb21wbGV0YW1vcyBsYSBhdXRvcml6YWNpw7NuIHBhcmEgdHdpdHRlcg0KQ3JlYW1vcyB1biB0b2tlbiBwYXJhIGVudHJhciBhIHR3aXR0ZXIgeSB1c2FyIGxhIEFQSSwgeSBsYXMgbGlicmVyaWFzIFJ0d2VldCB5IFR3aXR0ZVINCmBgYHtyfQ0KdHdpdHRlcl90b2tlbiA8LSBjcmVhdGVfdG9rZW4oDQogIGFwcCA9IGFwcG5hbWUsDQogIGNvbnN1bWVyX2tleSA9IGNvbnN1bWVyX2tleSwNCiAgY29uc3VtZXJfc2VjcmV0ID0gY29uc3VtZXJfc2VjcmV0LA0KICBhY2Nlc3NfdG9rZW4gPSBhY2Nlc3NfdG9rZW4sIA0KICBhY2Nlc3Nfc2VjcmV0ID0gYWNjZXNzX3NlY3JldCkNCmBgYA0KDQojIyAyLSBEZXNjYXJnYW1vcyBsb3MgdHdlZXRzDQpEZXNjYXJnYW1vcyBsb3MgdHdlZXRzIGRlIGN1YWxxdWllciB1c3VhcmlvIGNvbiBsYSBmdW5jaW9uICJnZXRfdGltZWxpbmUiIGRlIHJ0d2VldA0KVXNlciA9IEAgZGVsIHVzdWFyaW8NCm49IENhbnRpZGFkIGRlIHR3ZWV0cyBhIGJhamFyDQppbmNsdWRlUnRzID0gRiBwYXJhIGVsaW1pbmFyIGxvcyBwb3NpYmxlcyBSVCBkZSBsYSBjdWVudGENCmV4Y2x1ZGVSZXBsaWVzID0gRiB2YW1vcyBhIGRlc2NhcmdhciBsYSBzZWNjacOzbiAiVHdlZXRzIHkgcmVzcHVlc3RhcyINCg0KYGBge3J9DQpUd2VldHNfQm9jYUpycyA8LSBnZXRfdGltZWxpbmUodXNlciA9ICJCb2NhSnJzT2ZpY2lhbCIsIG4gPSAzMjAwLCBpbmNsdWRlUnRzID0gRiwgZXhjbHVkZVJlcGxpZXMgPSBGKQ0KVHdlZXRzX1JpdmVyUGxhdGUgPC0gZ2V0X3RpbWVsaW5lKHVzZXIgPSAiUml2ZXJQbGF0ZSIsIG4gPSAzMjAwLCBpbmNsdWRlUnRzID0gRiwgZXhjbHVkZVJlcGxpZXMgPSBGKQ0KVHdlZXRzX1NhbkxvcmVuem8gPC0gZ2V0X3RpbWVsaW5lKHVzZXIgPSAiU2FuTG9yZW56byIsIG4gPSAzMjAwLCBpbmNsdWRlUnRzID0gRiwgZXhjbHVkZVJlcGxpZXMgPSBGKQ0KVHdlZXRzX1JhY2luZyA8LSBnZXRfdGltZWxpbmUodXNlciA9ICJSYWNpbmdDbHViIiwgbiA9IDMyMDAsIGluY2x1ZGVSdHMgPSBGLCBleGNsdWRlUmVwbGllcyA9IEYpDQpUd2VldHNfSW5kZXBlbmRpZW50ZSA8LSBnZXRfdGltZWxpbmUodXNlciA9ICJJbmRlcGVuZGllbnRlIiwgbiA9IDMyMDAsIGluY2x1ZGVSdHMgPSBGLCBleGNsdWRlUmVwbGllcyA9IEYpDQpgYGANCg0KIyMgMy0gVW5pbW9zIGxvcyBkYXRhZnJhbWVzDQpWYW1vcyBhIHVzYXIgdW4gc29sbyBEYXRhZnJhbWUgcXVlIGxsYW1hcmVtb3MgVHdlZXRzX0NsdWIgeSBsbyB2YW1vcyBhIGhhY2VyIGNvbiBsYSBmdW5jaW9uIHJiaW5kIGRlIFIgYmFzZQ0KDQpFbCBudWV2byBEYXRhZnJhbWUgdmEgYSBjb250YXIgY29uIDMyMDAqNSBmaWxhcyA9IDE2MDAwIHkgY29udGllbmUgMzIwMCB0d2VldHMgZGUgY2FkYSB1bmEgZGUgbGFzIGN1ZW50YXMNCmBgYHtyfQ0KVHdlZXRzX0NsdWIgPC0gcmJpbmQoVHdlZXRzX0JvY2FKcnMsIFR3ZWV0c19SYWNpbmcsIFR3ZWV0c19TYW5Mb3JlbnpvLCBUd2VldHNfUml2ZXJQbGF0ZSwgVHdlZXRzX0luZGVwZW5kaWVudGUpDQpgYGANCg0KIyMgNC0gQ29tZW56YW1vcyBlbCBwcm9jZXNvIGRlIGxpbXBpZXphDQpWYW1vcyBhIGNyZWFyIGFsZ3VuYXMgY29sdW1uYXMgZXh0cmFzIHBhcmEgb2J0ZW5lciBtYXMgaW5mb3JtYWNpw7NuIHkgdGFtYmnDqW4gdmFtb3MgYSBmaWx0cmFyIGRhdG9zLCBwYXJhIHF1ZWRhcm5vcyBzb2xvIGNvbiBsb3MgcXVlIG5vcyBpbnRlcmVzYQ0KYGBge3J9DQpUd2VldHNfQ2x1YiA8LSBUd2VldHNfQ2x1YiU+JQ0KICB0YmxfZGYgJT4lDQogIG11dGF0ZSh0ZXh0ID0gZ3N1YigiW15bOmdyYXBoOl1dIiwgIiAiLCB0ZXh0KSkgJT4lICNTaW4gZ3JhZmljb3MNCiAgbXV0YXRlKHRleHQgPSB0b2xvd2VyKHRleHQpKSAlPiUgI1RvZG8gZWwgdGV4dG8gYSBtaW51c2N1bGENCiAgbXV0YXRlKGNyZWF0ZWRfYXQgPSB3aXRoX3R6KGNyZWF0ZWRfYXQsICJBbWVyaWNhL0FyZ2VudGluYS9CdWVub3NfQWlyZXMiKSklPiUgI0NhbWJpYW1vcyBhIGxhIHpvbmEgaG9yYXJpYSBjb3JyZXNwb25kaWVudGUNCiAgc2VwYXJhdGUoY3JlYXRlZF9hdCwgaW50byA9IGMoImRhdGUiLCAiaG91ciIpLCBzZXAgPSAiICIpJT4lICNTZXBhcmFtb3MgZW4gZGlhIHkgaG9yYSBlbCBjYW1wbyBjcmVhdGVkX2F0DQogICAgc2VwYXJhdGUoaG91ciwgaW50byA9IGMoImhvdXIiLCAibWludXRlcyIsInNlY29uZHMiKSwgc2VwID0gIjoiKSU+JSAjU2VwYXJhbW9zIGxhIGhvcmEgZW4gaG9yYSxtaW51dG9zIHkgc2VndW5kb3MNCiAgIHJlbmFtZShDbHViID0gc2NyZWVuX25hbWUpICU+JSAjQ2FtYmlhbW9zIGxhIGNvbHVtbmEgY29uIGVsIG5vbWJyZSBkZWwgY2x1Yg0KbXV0YXRlKHBlcmlvZG8gPSB5ZWFyKGRhdGUpLCANCiAgICAgICAgIG1lcyA9IG1vbnRoKGRhdGUsIGxhYmVsID0gVCwgYWJiciA9IEYpLA0KICAgICAgICAgZGlhID0gYXMubnVtZXJpYyhkYXkoZGF0ZSkpLA0KICAgICAgICAgZGlhX3NlbSA9IHdkYXkoZGF0ZSwgbGFiZWwgPSBULCBhYmJyID0gRiwgd2Vla19zdGFydCA9IDEpLA0KICAgICAgICAgZGlhX3BlciA9IHlkYXkoZGF0ZSksDQogICAgICAgICBkYXRlID0gYXMuRGF0ZShkYXRlKSAjQ3JlYW1vcyB1bmEgY29sdW1uYSBjb24gZWwgbnVtZXJvIGRlIGHDsW8sIG1lcywgZGlhLCBub21icmUgZGUgZGlhIHkgZGUgbWVzLg0KICApJT4lDQogIGZpbHRlcihwZXJpb2RvID09IDIwMjApICNTb2xvIHZhbW9zIGEgdXRpbGl6YXIgaW5mbyAgZGUgMjAyMA0KYGBgDQpFbCBudWV2byBEYXRhRnJhbWUgc2VyYSBkZSA5NjYwIG9ic2VydmFjaW9uZXMNCg0KDQojIyA1LSBDcmVhbW9zIGNpZXJ0b3MgdGVtYXMgZ3JhZmljb3MNCg0KUGFyYSB0ZW5lciB1bmEgbWVqb3IgdmlzdWFsaXphY2lvbiwgcHJlY2FyZ2Ftb3MgYWxndW5vcyB0ZW1hcyB5IGxlIGRhbW9zIGVsIGNvbG9yIGEgY2FkYSBjbHViDQpgYGB7cn0NCnRlbWFfcGxvdCA8LQ0KICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzYW5zIiwgc2l6ZSA9IDEwKSwNCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gIiNjY2NjY2MiLCBmaWxsID0gTkEpLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9ICBlbGVtZW50X2xpbmUoY29sb3IgPSAiI2RkZGRkZCIpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gIGVsZW1lbnRfbGluZShjb2xvciA9ICIjZWVlZWVlIiksDQogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gIiNjY2NjY2MiKSwNCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICIjY2NjY2NjIiwgZmlsbCA9ICIjZWVlZWVlIiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KDQp0ZW1hX2dyYWYgPC0gdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2VyaWYiKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFQkVCRUIiLCBjb2xvdXIgPSBOQSksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0VCRUJFQiIsIGNvbG91ciA9IE5BKSkNCg0KY29sb3VycyA8LSBjKA0KICAiIzE3NDZmOCIsICMgQm9jYUpyc09maWNpYWwNCiAgIiNjZDAwMDAiLCAjIEluZGVwZW5kaWVudGUNCiAgIiMxM2U0ZmMiLCAjIFJhY2luZ0NsdWINCiAgIiM5YjViNTMiLCAjIFJpdmVyIFBsYXRlDQogICIjMDAxMjU2IiAgIyBTYW5Mb3JlbnpvDQopDQpgYGANCg0KIyMgNi0gQ2FudGlkYWQgZGUgdHdlZXRzIGVuIGVsIGHDsW8NCg0KVmVtb3MgcXVlIGVsIGNsdWIgcXVlIG1hcyB0d2l0dGVvIGVuIGxvIHF1ZSB2YSBkZWwgYcOxbyBlcyBSYWNpbmcgY29uIGNhc2kgMjUwMCwgcGFyZWNpZG8gYSBsbyBxdWUgaGl6byBTYW4gTG9yZW56byB5IHRhbWJpw6luIGEgUml2ZXIuIA0KDQpCb2NhIGUgSW5kZXBlbmRpZW50ZSBlc3RhbiBlbiB1biBuaXZlbCBtw6FzIGJham8sIGNlcmNhIGRlIGxvcyAxNTAwIHR3ZWV0cyBlbiBsbyBxdWUgdmEgZGVsIGHDsW8NCmBgYHtyfQ0KDQpUd2VldHNfQ2x1YiAlPiUgDQogIGdyb3VwX2J5KENsdWIpJT4lDQogIGNvdW50KENsdWIpICU+JQ0KZ2dwbG90KCkrDQogIGFlcyh4PXJlb3JkZXIoQ2x1YiwgbiksIHk9IG4sIGZpbGw9IENsdWIpICsNCiAgZ2VvbV9jb2woKSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICBsYWJzKHRpdGxlID0gIkNhbnRpZGFkIFR3ZWV0cyIsIHggPSAiQ2x1YiIsIFkgPSAiQ2FudGlkYWQiKSArDQogICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGNvbG91cnMpICsNCiAgICB0ZW1hX2dyYWYNCmBgYA0KDQojIyA3LSBDYW50aWRhZCBkZSB0d2VldHMgcG9yIG1lcw0KYGBge3J9DQpUd2VldHNfQ2x1YiAlPiUgDQogIGdyb3VwX2J5KENsdWIsIG1lcyklPiUNCiAgY291bnQoQ2x1YikgJT4lDQpnZ3Bsb3QoKSsNCiAgYWVzKHg9cmVvcmRlcihDbHViLCBuKSwgeT0gbiwgZmlsbD0gQ2x1YikgKw0KICBnZW9tX2NvbCgpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiQ2FudGlkYWQgVHdlZXRzIiwgeCA9ICJDbHViIiwgWSA9ICJDYW50aWRhZCIpICsNCiAgZmFjZXRfd3JhcCh+bWVzLCBzY2FsZXMgPSAiZnJlZSIsIG5yb3cgPSAzKSsNCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sb3VycykgKw0KICAgIHRlbWFfZ3JhZg0KYGBgDQoNCg0KIyMgOC0gVHdlZXRzIHBvciBob3JhDQoNClZlbW9zIGNvbW8gZXMgbGEgZGlzdHJpYnVjacOzbiBkZSBsb3MgdHdlZXRzIHBvciBob3JhcmlvLiANCg0KQm9jYSBlcyBlbCBjbHViIGNvbiBtYXlvciBhY3RpdmlkYWQgYSBsYSBtZWRpYW5vY2hlLCBhIGxhIG1hZHJ1Z2FkYSBsYSBhY3RpdmlkYWQgZXMgY2FzaSBudWxhIHkgY29taWVuemEgbnVldmFtZW50ZSBhIGxhcyA4YW0uDQoNClRhbWLDrWVuIHBvZGVtb3Mgbm90YXIgcXVlIGxhIG1heW9yIGRpZmVyZW5jaWEgZW4gbG9zIHR3ZWV0cyBzZSBkYW4gYWxyZWRlZG9yIGRlbCBtZWRpb2RpYSB5IGEgbWVkaWEgdGFyZGUsIHZvbHZpZW5kbyBhIHR3aXR0ZWFyIGRlIG1hbmVyYSBwYXJlY2lkYSBkdXJhbnRlIGxhIG5vY2hlLg0KDQpgYGB7cn0NClR3ZWV0c19DbHViICU+JSANCiAgZ3JvdXBfYnkoQ2x1YiwgaG91ciklPiUNCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQ0KZ2dwbG90IChhZXMoeD0gaG91ciwgeSA9IG4sIGdyb3VwPSBDbHViLCBjb2xvciA9IENsdWIpKSArDQogIGdlb21fbGluZSgpKw0KICAgIGxhYnModGl0bGUgPSAiVHdlZXRzIHBvciBob3JhIiwgeCA9ICJIb3JhIiwgeSA9ICJDYW50aWRhZCIpICsNCiAgdGVtYV9wbG90DQpgYGANCg0KIyMgOS0gQ2FudGlkYWQgZGUgaW50ZXJhY2Npb25lcw0KDQpDcmVhbW9zIHVuIHBlcXVlw7FvIERGIHBhcmEgc3VtYXJpemFyIHRvZGFzIGxhcyBpdGVyYWNjaW9uZXMgcXVlIHRpZW5lbiBsb3MgZGlzdGludG9zIGNsdWJlcywgeSBsZSBhZ3JlZ2Ftb3Mgc3UgY2FudGlkYWQgZGUgZm9sbG93ZXJzIChkaXZpZGlkbyAxMDAwKQ0KYGBge3J9DQpJbnRlcmFjY2lvbmVzID0gVHdlZXRzX0NsdWIgJT4lIA0KICBncm91cF9ieShDbHViKSU+JQ0KICBzdW1tYXJpc2UoUHJvbWVkaW9SVCA9IG1lYW4ocmV0d2VldF9jb3VudCksIA0KICAgICAgICAgICAgVG90YWxSVCA9ICBzdW0ocmV0d2VldF9jb3VudCksDQogICAgICAgICAgICBQcm9tZWRpb0ZBViA9IG1lYW4oZmF2b3JpdGVfY291bnQpLCANCiAgICAgICAgICAgIFRvdGFsRkFWID0gIHN1bShmYXZvcml0ZV9jb3VudCksDQogICAgICAgICAgICBUb3RhbEludGVyYWNjaW9uZXMgPSBUb3RhbEZBViArIFRvdGFsUlQsDQogICAgICAgICAgICBQcm9tZWRpb0ludGVyYWNjaW9uZXMgPSBQcm9tZWRpb1JUICsgUHJvbWVkaW9GQVYNCiAgKSAlPiUNCiAgICBtdXRhdGUoZm9sbG93ZXJzID0gaWZlbHNlIChDbHViID09ICJCb2NhSnJzT2ZpY2lhbCIsIDM4MDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChDbHViID09ICJJbmRlcGVuZGllbnRlIiwgNDU0LjQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoQ2x1YiA9PSAiUmFjaW5nQ2x1YiIsIDMzMC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoQ2x1YiA9PSAiUml2ZXJQbGF0ZSIsIDM0MDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA3NTMuNA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQogICAgKQ0KICApDQoNCnByaW50KEludGVyYWNjaW9uZXMpDQpgYGANCg0KIyMgMTAtIFJldHdlZXRzIGEgbGEgY3VlbnRhDQoNCk1lZGltb3MgbG9zIFJUIHF1ZSB0dXZvIGNhZGEgdW5vIGRlIGxvcyBjbHViZXMsIHRhbnRvIGVuIGNhbnRpZGFkIHRvdGFsIHF1ZSB2YSBkZSBsYSBtYW5vIGRlIGxhcyBwdWJsaWNhY2lvbmVzLCBhc8OtIGNvbW8gdGFtYmllbiBlbCBwcm9tZWRpby4NCg0KU2Ugbm90YSB1bmEgY2xhcmEgZGlmZXJlbmNpYSBlbnRyZSBSaXZlciB5IEJvY2EgY29uIGxvcyBvdHJvcyAzIGNsdWJlcyBhIGxhIGhvcmEgZGUgcXVlIHN1cyB0d2VldHMgc2VhbiByZXR3aXR0ZWFkb3MuDQpgYGB7cn0NCkludGVyYWNjaW9uZXMgJT4lIA0KZ2dwbG90KCkrDQogIGFlcyh4PXJlb3JkZXIoQ2x1YiwgVG90YWxSVCksIHk9IFRvdGFsUlQsIGZpbGw9IENsdWIpICsNCiAgZ2VvbV9jb2woKSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICBsYWJzKHRpdGxlID0gIkNhbnRpZGFkIHRvdGFsIGRlIFJUIiwgeCA9ICJDbHViIiwgeSA9ICJDYW50aWRhZCIpICsNCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sb3VycykgKw0KICAgIHRlbWFfZ3JhZg0KDQpJbnRlcmFjY2lvbmVzICU+JSANCmdncGxvdCgpKw0KICBhZXMoeD1yZW9yZGVyKENsdWIsIFByb21lZGlvUlQpLCB5PSBQcm9tZWRpb1JULCBmaWxsPSBDbHViKSArDQogIGdlb21fY29sKCkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh0aXRsZSA9ICJDYW50aWRhZCBwcm9tZWRpbyBkZSBSVCIsIHggPSAiQ2x1YiIsIHkgPSAiQ2FudGlkYWQiKSArDQogICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGNvbG91cnMpICsNCiAgICB0ZW1hX3Bsb3QNCmBgYA0KDQojIyAxMS0gRmF2b3JpdG9zIGEgbGEgY3VlbnRhDQoNCk1lZGltb3MgbG9zIEZBViBxdWUgdHV2byBjYWRhIHVubyBkZSBsb3MgY2x1YmVzLCB0YW50byBlbiBjYW50aWRhZCB0b3RhbCBxdWUgdmEgZGUgbGEgbWFubyBkZSBsYXMgcHVibGljYWNpb25lcywgYXPDrSBjb21vIHRhbWJpZW4gZWwgcHJvbWVkaW8uDQoNClNlIG5vdGEgdW5hIGNsYXJhIGRpZmVyZW5jaWEgZW50cmUgUml2ZXIsIHF1ZSBhZGVtYXMgc2UgYXNlbnR1YSBjb250cmEgQm9jYSwgbWllbnRyYXMgcXVlIGxvcyBvdHJvcyBjbHViZXMgZXN0w6FuIG11eSBwb3IgZGViYWpvIGVuIGN1YW50byBhIEZBVnMgcmVjaWJpZG9zDQoNCmBgYHtyfQ0KSW50ZXJhY2Npb25lcyAlPiUgDQpnZ3Bsb3QoKSsNCiAgYWVzKHg9cmVvcmRlcihDbHViLCAtVG90YWxGQVYpLCB5PSBUb3RhbEZBViwgZmlsbD0gQ2x1YikgKw0KICBnZW9tX2NvbCgpICsNCiAgbGFicyh0aXRsZSA9ICJDYW50aWRhZCB0b3RhbCBkZSBGQVYiLCB4ID0gIkNsdWIiLCB5ID0gIkNhbnRpZGFkIikgKw0KICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjb2xvdXJzKSArDQogICAgdGVtYV9ncmFmDQoNCkludGVyYWNjaW9uZXMgJT4lIA0KZ2dwbG90KCkrDQogIGFlcyh4PXJlb3JkZXIoQ2x1YiwgLVByb21lZGlvRkFWKSwgeT0gUHJvbWVkaW9GQVYsIGZpbGw9IENsdWIpICsNCiAgZ2VvbV9jb2woKSArDQogICAgbGFicyh0aXRsZSA9ICJDYW50aWRhZCBwcm9tZWRpbyBkZSBGQVYiLCB4ID0gIkNsdWIiLCB5ID0gIkNhbnRpZGFkIikgKw0KICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjb2xvdXJzKSArDQogICAgdGVtYV9wbG90DQpgYGANCg0KDQojIyAxMi0gQ2FudGlkYWQgcHJvbWVkaW8gZGUgaW50ZXJhY2Npb25lcw0KDQpTdW1hbW9zIGxvIHZpc3RvIGFudGVyaW9ybWVudGUsIHRvbWFuZG8gdW4gc29sbyBjYW1wbyAiSW50ZXJhY2Npb24iIGNvbW8gbGEgc3VtYSBkZSBsb3MgcHJvbWVkaW9zIGRlIEZBVnMgeSBkZSBSVHMsIGxhcyBkaWZlcmVuY2lhcyBxdWUgc2Ugbm90YW4gc29uIGxhcyBtaXNtYXMgcXVlIGVuIGxvcyBhbnRlcmlvcmVzIGdyw6FmaWNvcy4NCg0KYGBge3J9DQpJbnRlcmFjY2lvbmVzICU+JSANCmdncGxvdCgpKw0KICBhZXMoeD1yZW9yZGVyKENsdWIsIFByb21lZGlvSW50ZXJhY2Npb25lcyksIHk9IFByb21lZGlvSW50ZXJhY2Npb25lcywgY29sb3I9IENsdWIpICsNCiAgZ2VvbV9wb2ludChzaGFwZT0yMywgZmlsbD1jb2xvdXJzLCBjb2xvcj1jb2xvdXJzLCBzaXplPTUpICsNCiAgICBsYWJzKHRpdGxlID0gIkNhbnRpZGFkIHByb21lZGlvIGRlIGludGVyYWNjaW9uZXMiLCB4ID0gIkNsdWIiLCB5ID0gIkNhbnRpZGFkIikgKw0KICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjb2xvdXJzKSArDQogICAgdGVtYV9wbG90DQpgYGANCg0KIyMgMTMtIENhbnRpZGFkIHByb21lZGlvIGRlIGludGVyYWNjaW9uZXMNCg0KTm9ybWFsaXphbW9zIGxhIGNhbnRpZGFkIGRlIGludGVyYWNjaW9uZXMgcXVlIHR1dmllcm9uIHBvciBjYWRhIDEwMDAgc2VndWlkb3JlcywgYWjDrSBzZSBub3RhIHF1ZSBSYWNpbmcgZSBJbmRlcGVuZGllbnRlIHNpIGJpZW4gc3VzIGludGVyYWNjaW9uZXMgc29uIG1lbm9yLCBzZSBkZWJlIGEgbGEgY2FudGlkYWQgZGUgZm9sbG93ZXJzIHF1ZSB0aWVuZSBjYWRhIHVubywgY3VhbmRvIG5vcm1hbGl6YW1vcyBxdWVkYW4gZW4gdW4gcHJpbWVyIG5pdmVsIGp1bnRvIGEgUml2ZXIuDQoNCk1pZW50cmFzIHF1ZSBCb2NhIG5vIGxvZ3JhIGxsZWdhciBhIDEgaW50ZXJhY2Npw7NuIHBvciBjYWRhIG1pbCBmb2xsb3dlcnMsIGVzdGFuZG8gZW4gdW4gc2VndW5kbyBwZWxvdMOzbiwgbWllbnRyYXMgcXVlIFNhbiBMb3JlbnpvIGVzIGVsIHF1ZSBtZW5vcyBpbnRlcmFjY2lvbmVzIHJlY2liZSBjb24gc3UgZ2VudGUuDQoNCmBgYHtyfQ0KSW50ZXJhY2Npb25lcyAlPiUgDQpnZ3Bsb3QoKSsNCiAgYWVzKHg9cmVvcmRlcihDbHViLCAoUHJvbWVkaW9JbnRlcmFjY2lvbmVzL2ZvbGxvd2VycykpLCB5PSAoUHJvbWVkaW9JbnRlcmFjY2lvbmVzL2ZvbGxvd2VycyksIGNvbG9yPSBDbHViKSArDQogIGdlb21fcG9pbnQoc2hhcGU9MjMsIGZpbGw9Y29sb3VycywgY29sb3I9Y29sb3Vycywgc2l6ZT01KSArDQogICAgbGFicyh0aXRsZSA9ICJDYW50aWRhZCBwcm9tZWRpbyBkZSBpbnRlcmFjY2lvbmVzIHggMTAwMCBmb2xsb3dlcnMiLCB4ID0gIkNsdWIiLCB5ID0gIkNhbnRpZGFkIikgKw0KICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPSBjb2xvdXJzKSArDQogICAgdGVtYV9wbG90DQpgYGANCg0KIyMgMTQtIE1lZGlhIGRlIGludGVyYWNjaW9uZXMNCg0KQSB0cmF2ZXMgZGUgdW4gYm94cGxvdCBidXNjYW1vcyBsYXMgbWVkaWFzLCB5IGxvcyBvdXRsaWVycyBxdWUgdHV2aWVyb24gbGFzIGludGVyYWNjaW9uZXMgYSBsb3MgZGlzdGludG9zIHR3ZWV0cyBkZSBsb3MgY2x1YmVzLCBzaWVtcHJlIHkgY3VhbmRvIGxvcyB0d2VldHMgaGF5YW4gdGVuaWRvIGFsIG1lbm9zIDEwMDAgaW50ZXJhY2Npb25lcy4NCg0KU2kgYmllbiBlcyB1biBncsOhZmljbyBxdWUgbm8gbm9zIGRpY2UgbXVjaG8sIHNpcnZlIHBhcmEgaWRlbnRpZmljYXIgMiBvdXRsaWVycyBjbGF2ZXMsIHF1ZSBzb24gZWwgZMOtYSBxdWUgQm9jYSBzYWxpbyBjYW1wZW9uIHkgdHV2byBjYXNpIDEwMGsgZGUgaW50ZXJhY2Npb25lcyB5IGVsIGRpYSBxdWUgUmFjaW5nIHByb3B1c28gbGxlZ2FyIGEgMTAwIG1pbCBmYXZvcml0b3MsIHF1ZSBsbyBzdXBlcm8gYW1wbGlhbWVudGUuDQoNCmBgYHtyfQ0KVHdlZXRzX0NsdWIgJT4lIA0KICBtdXRhdGUoaW50ZXJhY2Npb25lcyA9IGZhdm9yaXRlX2NvdW50ICsgcmV0d2VldF9jb3VudCklPiUNCiAgZmlsdGVyKGludGVyYWNjaW9uZXMgPiAxMDAwKSAlPiUNCmdncGxvdCgpKw0KICBhZXMoeD0gQ2x1YiwgeT0gaW50ZXJhY2Npb25lcywgY29sb3I9IENsdWIpICsNCiAgZ2VvbV9ib3hwbG90ICgpICsNCiAgICBsYWJzKHRpdGxlID0gIkJveHBsb3QgZGUgaW50ZXJhY2Npb25lcyIsIHggPSAiQ2x1YiIsIHkgPSAiQ2FudGlkYWQiKSArDQogICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGNvbG91cnMpICsNCiAgICB0ZW1hX3Bsb3QNCmBgYA0KDQojIyAxNS0gTGFyZ28gZGVsIHR3ZWV0DQoNCkNvbiBlbCBjYW1wbyAiZGlzcGxheV90ZXh0X3dpZHRoIiBxdWUgbWlkZSBsYSBjYW50aWRhZCBkZSBjYXJhY3RlcmVzIHF1ZSB0aWVuZSB1biB0d2VldCBzYWNhbW9zIGxhIG1lZGlhIGRlbCBsYXJnbyBxdWUgdGllbmUgY2FkYSB0d2VldC4NCg0KU2FuIExvcmVuem8gZXMgZWwgcXVlIHByb2R1Y2UgbG9zIHR3ZWV0cyBjb24gbcOhcyB0ZXh0bywgbHVlZ28gZWwgcmVzdG8gZGUgbG9zIGNsdWJlcyBlc3TDoW4gZW4gdW5hIG1lZGlhbmlhIGJhc3RhbnRlIHBhcmVjaWRhLg0KDQpgYGB7cn0NClR3ZWV0c19DbHViICU+JSANCmdncGxvdCgpKw0KICBhZXMoeD0gQ2x1YiwgeT0gZGlzcGxheV90ZXh0X3dpZHRoLCBjb2xvcj0gQ2x1YikgKw0KICBnZW9tX2JveHBsb3QgKCkgKw0KICAgIGxhYnModGl0bGUgPSAiQ2FudGlkYWQgcHJvbWVkaW8gZGUgaW50ZXJhY2Npb25lcyB4IDEwMDAgZm9sbG93ZXJzIiwgeCA9ICJDbHViIiwgeSA9ICJMYXJnbyBwcm9tZWRpbyB0d2VldCIpICsNCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sb3VycykgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgIHRlbWFfcGxvdA0KYGBgDQoNCiMjIDE2LSBUd2VldHMgc29icmUgY292aWQNCg0KRWwgY292aWQgZXMgZWwgdGVtYSBtw6FzIGltcG9ydGFudGUgZGVsIGHDsW8gMjAyMCwgY29uIGxhIGZ1bmNpb24gZ3JlcGwgYnVzY2Ftb3MgdHdlZXRzIHF1ZSBjb250ZW5nYW4gcGFsYWJyYXMgcXVlIHNlIHJlbGFjaW9uYW4gY29uIGVsIHZpcnVzLCB5IGNvbnRhYmlsaXphbW9zIGN1YWxlcyBzb24gbG9zIGNsdWJlcyBxdWUgbcOhcyBoYWJsYXJvbiBzb2JyZSBlbCBtaXNtbw0KYGBge3J9DQojQnVzY2Ftb3MgdHdlZXRzIGNvbiBsYSBwYWxhYnJhIGNvdmlkDQpQYWxhYnJhc19jb3ZpZCA8LSAiY292aWR8Y292aWQtMTl8Y292aWQxOXxjb3JvbmF2aXJ1c3wjY292aWR8I2NvdmlkLTE5fCNjb3ZpZDE5fCNjb3JvbmF2aXJ1c3x0ZXN0fHRlc3Rlb3x0ZXN0ZW9zfHBjcnxzZXJvbG9naWNvfGhpc29wYWRvIg0KVHdlZXRzX0NsdWIkQ292aWQgPC0gZ3JlcGwoUGFsYWJyYXNfY292aWQsIFR3ZWV0c19DbHViJHRleHQsIGlnbm9yZS5jYXNlID0iVHJ1ZSIpDQoNClR3ZWV0c19DbHViICU+JSANCiAgZ3JvdXBfYnkoQ2x1YiwgQ292aWQpJT4lDQogIGZpbHRlcihDb3ZpZCA9PSBUKSAlPiUNCiAgY291bnQoQ2x1YikgJT4lDQpnZ3Bsb3QoKSsNCiAgYWVzKHg9cmVvcmRlcihDbHViLCBuKSwgeT0gbiwgZmlsbD0gQ2x1YikgKw0KICBnZW9tX2NvbCgpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiQ2FudGlkYWQgVHdlZXRzIHNvYnJlIENvcm9uYXZpcnVzIiwgeCA9ICJDbHViIiwgeSA9ICJDYW50aWRhZCIpICsNCiAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sb3VycykgKw0KICAgIHRlbWFfZ3JhZg0KYGBgDQoNCg0KDQojIEFuYWxpc2lzIHNvYnJlIGZvbGxvd2Vycw0KDQojIyAxIC0gRGVzY2FyZ2Ftb3MgbG9zIGZvbGxvd2Vycw0KDQpDb24gbGEgZnVuY2lvbiAiZ2V0X2ZvbGxvd2VycyIgZGVsIHBhcXVldGUgInJ0d2VldCIgcG9kZW1vcyBkZXNjYXJnYXIgZWwgSUQgZGUgdG9kb3MgbG9zIHNlZ3VpZG9yZXMgZGUgdW5hIGN1ZW50YSB5IGx1ZWdvIGNvbiBsYSAiZnVuY2lvbiBsb29rdXBfdXNlcnMiIG9idGVuZW1vcyBsYSBpbmZvcm1hY2nDs24gbcOhcyBwcmVjaXNhIGRlIGxvcyBzZWd1aWRvcmVzLg0KDQpuID0gImFsbCIgZXMgZWwgbcOheGltbyBkZSBjYW50aWRhZCBkZSBzZWd1aWRvcmVzIHF1ZSBwb2RlcyBkZXNjYXJnYXIgZGUgdW5hIGN1ZW50YSwgZW4gZXN0ZSBjYXNvIGVzIDc1IG1pbCB1c3VhcmlvcywgcXVlIHNlIHRvbWFyYSBjb21vIE11ZXN0cmEgYWxlYXRvcmlhIHNpbXBsZQ0KDQpgYGB7cn0NCkZvbGxvd2Vyc19Cb2NhSnJzX2lkIDwtIGdldF9mb2xsb3dlcnMoIkJvY2FKcnNPZmljaWFsIiwgbiA9ICJhbGwiKSAjRGVzY2FyZ2FyIGZvbGxvd2VycyBJZA0KRm9sbG93ZXJzX0JvY2FKcnMgPC0gbG9va3VwX3VzZXJzKEZvbGxvd2Vyc19Cb2NhSnJzX2lkJHVzZXJfaWQpICNEZXNjYXJnYXIgdGhlIGZvbGxvd2VycyBpbmZvDQoNCiNSZXBldGlyIHBhcmEgdG9kb3MgbG9zIHVzdWFyaW9zDQoNCkZvbGxvd2Vyc19SaXZlclBsYXRlX2lkIDwtIGdldF9mb2xsb3dlcnMoIlJpdmVyUGxhdGUiLCBuID0gImFsbCIpDQpGb2xsb3dlcnNfUml2ZXJQbGF0ZSA8LSBsb29rdXBfdXNlcnMoRm9sbG93ZXJzX1JpdmVyUGxhdGVfaWQkdXNlcl9pZCkNCg0KRm9sbG93ZXJzX1NhbkxvcmVuem9faWQgPC0gZ2V0X2ZvbGxvd2VycygiU2FuTG9yZW56byIsIG4gPSAiYWxsIikNCkZvbGxvd2Vyc19TYW5Mb3JlbnpvIDwtIGxvb2t1cF91c2VycyhGb2xsb3dlcnNfU2FuTG9yZW56b19pZCR1c2VyX2lkKQ0KDQpGb2xsb3dlcnNfUmFjaW5nQ2x1Yl9pZCA8LSBnZXRfZm9sbG93ZXJzKCJSYWNpbmdDbHViIiwgbiA9ICJhbGwiKQ0KRm9sbG93ZXJzX1JhY2luZ0NsdWIgPC0gbG9va3VwX3VzZXJzKEZvbGxvd2Vyc19SYWNpbmdDbHViX2lkJHVzZXJfaWQpDQoNCkZvbGxvd2Vyc19JbmRlcGVuZGllbnRlX2lkIDwtIGdldF9mb2xsb3dlcnMoIkluZGVwZW5kaWVudGUiLCBuID0gImFsbCIpDQpGb2xsb3dlcnNfSW5kZXBlbmRpZW50ZSA8LSBsb29rdXBfdXNlcnMoRm9sbG93ZXJzX0luZGVwZW5kaWVudGVfaWQkdXNlcl9pZCkNCg0KcHJpbnQoRm9sbG93ZXJzX1JhY2luZ0NsdWIpDQpgYGANCg0KIyMgMiAtIEFncmVnYW1vcyB1bmEgaWRlbnRpZmljYWNpw7NuIGRlIGNhZGEgY2x1YiANCg0KTGUgcG9uZW1vcyB1bmEgaWRlbnRpZmljYWNpw7NuIGEgY2FkYSB1c3VhcmlvLCBkZSBxdWUgY2x1YiBzaWd1ZSwgeSBsdWVnbyB1bmltb3MgbnVldmFtZW50ZSBjb24gbGEgZnVuY2nDs24gUmJpbmQgcGFyYSB0ZW5lciB1biBEYXRhRnJhbWUgw7puaWNvDQoNCmBgYHtyfQ0KZm9yKGkgaW4gMTpucm93KEZvbGxvd2Vyc19JbmRlcGVuZGllbnRlKSkgew0KRm9sbG93ZXJzX0luZGVwZW5kaWVudGUkU2lndWUgIDwtIGMgKCJJbmRlcGVuZGllbnRlIikNCn0NCg0KZm9yKGkgaW4gMTpucm93KEZvbGxvd2Vyc19Cb2NhSnJzKSkgew0KRm9sbG93ZXJzX0JvY2FKcnMkU2lndWUgIDwtIGMgKCJCb2NhIikNCn0NCg0KZm9yKGkgaW4gMTpucm93KEZvbGxvd2Vyc19TYW5Mb3JlbnpvKSkgew0KRm9sbG93ZXJzX1NhbkxvcmVuem8kU2lndWUgIDwtIGMgKCJTYW4gTG9yZW56byIpDQp9DQoNCmZvcihpIGluIDE6bnJvdyhGb2xsb3dlcnNfUmFjaW5nQ2x1YikpIHsNCkZvbGxvd2Vyc19SYWNpbmdDbHViJFNpZ3VlICA8LSBjICgiUmFjaW5nIikNCn0NCg0KZm9yKGkgaW4gMTpucm93KEZvbGxvd2Vyc19SaXZlclBsYXRlKSkgew0KRm9sbG93ZXJzX1JpdmVyUGxhdGUkU2lndWUgIDwtIGMgKCJSaXZlciBQbGF0ZSIpDQp9DQoNCkZvbGxvd2Vyc19DbHViIDwtIHJiaW5kKEZvbGxvd2Vyc19Cb2NhSnJzLCBGb2xsb3dlcnNfUmFjaW5nQ2x1YiwgRm9sbG93ZXJzX1NhbkxvcmVuem8sIEZvbGxvd2Vyc19SaXZlclBsYXRlLCBGb2xsb3dlcnNfSW5kZXBlbmRpZW50ZSkNCg0KYGBgDQoNCiMjIDMtIENhbnRpZGFkIHNlZ3VpZG9yZXMNCg0KRWwgY2x1YiBjb24gbWFzIHNlZ3VpZG9yZXMgZXMgQm9jYSwgcXVlIGN1ZW50YSBjb24gY2FzaSAzLjggTU0sIGVuIHVuIHNlZ3VuZG8gbml2ZWwgUml2ZXIgY29uIGNhc2kgMy41IE1NIGRlIHNlZ3VpZG9yZXMsIHkgbHVlZ28gZWwgcmVzdG8gZGUgbG9zIGNsdWJlcyBlbiB0b3JubyBhIGxvcyA1MDBLIGRlIHNlZ3VpZG9yZXMNCmBgYHtyfQ0KSW50ZXJhY2Npb25lcyAlPiUgDQpnZ3Bsb3QoKSsNCiAgYWVzKHg9cmVvcmRlcihDbHViLCAtZm9sbG93ZXJzKSwgeT0gKGZvbGxvd2VycyoxMDAwKSwgZmlsbD0gQ2x1YikgKw0KICBnZW9tX2NvbCgpICsNCiAgICBsYWJzKHRpdGxlID0gIkNhbnRpZGFkIGZvbGxvd2VycyIsIHggPSAiQ2x1YiIsIHkgPSAiQ2FudGlkYWQiKSArDQogICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9IGNvbG91cnMpICsNCiAgICB0ZW1hX3Bsb3QNCmBgYA0KDQoNCiMjIDQtIERlc2RlIHF1ZSBpbnRlcmZheiBsbyBzaWd1ZW4NCg0KRWwgY29tcG9ydGFtaWVudG8gZGVzZGUgZG9uZGUgbG8gc2lndWVuIGxvcyB1c3VhcmlvcyBlcyBwYXJlY2lkYSBlbiB0b2RvcyBsb3MgY2x1YmVzLCBwcmVkb25pbWEgQW5kcm9pZCwgbHVlZ28gSXBob25lIHkgd2ViIGVuIHVuIG5pdmVsIHBhcmVjaWRvLCB5IHVuIGdydXBvIHBlcXVlw7FvIGRlc2RlIEluc3RhZ3JhbSB5IGxhIFdlYiBDbGllbnQgZGUgdHdpdHRlci4NCg0KU2UgZmlsdHJhIGVuIHVuIG3DrW5pbW8gZGUgMzAwIGxvcyBzZWd1aWRvcmVzIHF1ZSB1c2VuIGVzYSBwbGF0YWZvcm1hLCBwYXJhIGV2aXRhciBxdWUgc2VhIGluZmluaXRhIGxhIGNhbnRpZGFkIGRlIHZhcmlhYmxlcy4NCmBgYHtyfQ0KRm9sbG93ZXJzX0NsdWIgJT4lDQogIGdyb3VwX2J5KFNpZ3VlKSAlPiUNCiAgY291bnQoc291cmNlKSAlPiUNCiAgZmlsdGVyKG4gPiAzMDApICU+JQ0KICBmaWx0ZXIoIWlzLm5hKHNvdXJjZSkpICU+JQ0KICBtdXRhdGUoUHJvcG9yY2lvbiA9IG4gLyBzdW0obikpICU+JQ0KICBnZ3Bsb3QoKSArDQogICAgICBhZXMoU2lndWUsIFByb3BvcmNpb24sIGZpbGwgPSBzb3VyY2UpICsNCiAgICAgIGdlb21fY29sKCkgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz0gY29sb3VycykgKw0KICAgICAgdGVtYV9wbG90DQpgYGANCg0KIyMgNS0gSWRpb21hIGRlIGxvcyBmb2xsb3dlcnMgDQoNClNlIHNhY2EgcHJvcG9yY2lvbmFsbWVudGUgbGEgY2FudGlkYWQgZGUgaWRpb21hcyBxdWUgc29uIGhhYmxhZG9zIHBvciBsb3Mgc2VndWlkb3JlcyBxdWUgdGllbmUgY2FkYSB1bmEgZGUgbGFzIGN1ZW50YXMuDQoNCkNvbW8gY29ycmVzcG9uZGUsIGxhIG1heW9yaWEgaGFibGEgZW4gZXNwYcOxb2wsIGxhIGNhbnRpZGFkIGRlIHNlZ3VpZG9yZXMgZW4gaW5nbGVzIGVzIHBhcmVjaWRhIGVudHJlIHRvZGFzIGxhcyBjdWVudGFzLiANCg0KRWwgcG9ydHVndWVzIGVzIGVsIG90cm8gaWRpb21hIGltcG9ydGFudGUgZW50cmUgbG9zIGNsdWJlcy4NCmBgYHtyfQ0KRm9sbG93ZXJzX0NsdWIgJT4lDQogIGdyb3VwX2J5KFNpZ3VlKSAlPiUNCiAgY291bnQobGFuZykgJT4lDQogIGZpbHRlcihuID4gMzAwKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShsYW5nKSkgJT4lDQogICAgZmlsdGVyKGxhbmcgIT0gInVuZCIpICU+JQ0KICAgZmlsdGVyKGxhbmcgIT0gImFyIiklPiUNCiAgbXV0YXRlKFByb3BvcmNpb24gPSBuIC8gc3VtKG4pKSAlPiUNCiAgZ2dwbG90KCkgKw0KICAgICAgYWVzKFNpZ3VlLCBQcm9wb3JjaW9uLCBmaWxsID0gbGFuZykgKw0KICAgICAgZ2VvbV9jb2woKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgICAgIHRlbWFfcGxvdA0KYGBgDQoNCiMjIDYtIEV4dHJhbmplcm9zIHF1ZSBsbyBzaWd1ZW4NCg0KQnVzY2Ftb3MgbmFkYSBtYXMgcXVlIGxvcyBleHRyYW5qZXJvcyBxdWUgc2lndWVuIGEgbGEgY3VlbnRhLCBlbCBwYcOtcyBxdWUgbcOhcyBzZSBkZXN0YWNhIGVzIEJyYXNpbCwgc2VndWlkbyBwb3IgQ29sb21iaWEgeSBVcnVndWF5Lg0KDQpgYGB7cn0NCkZvbGxvd2Vyc19DbHViICU+JQ0KICBncm91cF9ieShTaWd1ZSkgJT4lDQogIGNvdW50KGNvdW50cnlfY29kZSkgJT4lDQogIGZpbHRlcihjb3VudHJ5X2NvZGUgIT0gIiIpICU+JQ0KICBmaWx0ZXIoY291bnRyeV9jb2RlICE9ICJBUiIpJT4lDQogIGZpbHRlcighaXMubmEoY291bnRyeV9jb2RlKSkgJT4lDQogIGZpbHRlcihuID4gMTApICU+JQ0KICBtdXRhdGUoUHJvcG9yY2lvbiA9IG4gLyBzdW0obikpICU+JQ0KICBnZ3Bsb3QoKSArDQogICAgICBhZXMoU2lndWUsIFByb3BvcmNpb24sIGZpbGwgPSBjb3VudHJ5X2NvZGUpICsNCiAgICAgIGdlb21fY29sKCkgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpKSArDQogICAgICB0ZW1hX3Bsb3QNCmBgYA0KDQoNCiMjIDctIEFjdGl2aWRhZCBkZSBsb3Mgc2VndWlkb3Jlcw0KDQpQcmltZXJvIGNyZWFtb3MgbG9zIGNhbXBvcyBwYXJhIGxhIGZlY2hhIGNyZWF0ZWRfYXQgY29tbyBoaWNpbW9zIGNvbiBlbCBERiBkZSB0d2VldHMsIHkgYWRqdW50YW1vcyB1biBjYW1wbyBkZSBhY3RpdmlkYWQsIHBhcmEgc2FiZXIgY3VhbCBlcyBsYSByZWxhY2nDs24gZGVsIHVzdWFyaW8gY29uIFR3aXR0ZXIuDQoNCkxvcyBjbHViZXMgY29uIG1lbm9zIHNlZ3VpZG9yZXMgc29uIGxvcyBxdWUgdGllbmVuIHNlZ3VpZG9yZXMgY29uIG3DoXMgdGllbXBvIHNpbiBhY3RpdmlkYWQsIG1pZW50cmFzIHF1ZSBsb3Mgc2lndWVuIGEgY2x1YmVzIGdyYW5kZXMgZXN0YW4gbWF5b3JtZW50ZSBlbiBhY3RpdmlkYWQuDQoNCmBgYHtyfQ0KRm9sbG93ZXJzX0NsdWIgPC0gRm9sbG93ZXJzX0NsdWIlPiUNCiAgbXV0YXRlKGNyZWF0ZWRfYXQgPSB3aXRoX3R6KGNyZWF0ZWRfYXQsICJBbWVyaWNhL0FyZ2VudGluYS9CdWVub3NfQWlyZXMiKSklPiUgI0NoYW5nZSB0aGUgdGltZV96b25lDQogIHNlcGFyYXRlKGNyZWF0ZWRfYXQsIGludG8gPSBjKCJkYXRlIiwgImhvdXIiKSwgc2VwID0gIiAiKSU+JSAjU2VwYXJhdGVkIHRoZSBkYXRlIGluIGRhdGUgYW5kIGhvdXINCiAgICBzZXBhcmF0ZShob3VyLCBpbnRvID0gYygiaG91ciIsICJtaW51dGVzIiwic2Vjb25kcyIpLCBzZXAgPSAiOiIpJT4lICNTZXBhcmF0ZWQgdGhlIGhvdXIgaW50byBob3VyLCBtaW51dGVzIGFuZCANCm11dGF0ZShwZXJpb2RvID0geWVhcihkYXRlKSwgDQogICAgICAgICBtZXMgPSBtb250aChkYXRlLCBsYWJlbCA9IFQsIGFiYnIgPSBGKSwNCiAgICAgICAgIGRpYSA9IGFzLm51bWVyaWMoZGF5KGRhdGUpKSwNCiAgICAgICAgIGRpYV9zZW0gPSB3ZGF5KGRhdGUsIGxhYmVsID0gVCwgYWJiciA9IEYsIHdlZWtfc3RhcnQgPSAxKSwNCiAgICAgICAgIGRpYV9wZXIgPSB5ZGF5KGRhdGUpLA0KICAgICAgICAgZGF0ZSA9IGFzLkRhdGUoZGF0ZSkgI0NyZWF0ZWQgY29sdW1ucyB3aXRoIG51bWJlciBvZiB5ZWFyLCBtb250aCwgZGF5LCBuYW1lIG9mIGRheS4NCiAgKSU+JQ0KbXV0YXRlKEFjdGl2aWRhZCA9IGlmZWxzZShwZXJpb2RvIDwgMjAxNiwgIjUrIGHDsW9zIHNpbiB0d2l0dGVhciIsDQogICAgICAgICAgICAgICAgICAgaWZlbHNlKHBlcmlvZG8gPCAyMDE4LCAiMyBhIDUgYcOxb3Mgc2luIHR3aXR0ZWFyIiwNCiAgICAgICAgICAgICAgICAgICBpZmVsc2UocGVyaW9kbyA8IDIwMjAsICIxIGEgMiBhw7FvcyBzaW4gdHdpdHRlYXIiLCAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJUd2l0dGVvIGVuIDIwMjAiKQ0KICAgICAgICAgICAgICAgICAgICkNCiAgICAgICkNCikNCg0KRm9sbG93ZXJzX0NsdWIgJT4lDQogIGdyb3VwX2J5KFNpZ3VlKSAlPiUNCiAgY291bnQoQWN0aXZpZGFkKSAlPiUNCiAgZmlsdGVyKCFpcy5uYShBY3RpdmlkYWQpKSAlPiUNCiAgbXV0YXRlKFByb3BvcmNpb24gPSBuIC8gc3VtKG4pKSAlPiUNCiAgZ2dwbG90KCkgKw0KICAgICAgYWVzKFNpZ3VlLCBQcm9wb3JjaW9uLCBmaWxsID0gQWN0aXZpZGFkKSArDQogICAgICBnZW9tX2NvbCgpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSkgKw0KICAgICAgdGVtYV9wbG90DQpgYGANCg==