Introducción

El Metro de Madrid sufrió una pérdida de calidad como consecuencia de la crisis económica del 2008. La frecuencia de trenes se redujo dando lugar a frecuentes aglomeraciones, sobre todo en hora punta. La falta de inversión afectó a escaleras mecánicas y ascensores que frecuentemente estaban averiados y a los servicios de limpieza.

Como consecuencia, los viajeros se quejaban frecuentemente del servicio en Twitter y aparecieron perfiles como @SufridoresMetro que denunciaban el mal estado de este transporte público. Pensé que cuantificar estas quejas de los viajeros del metro podrían convertir a sus usuarios en un sensor de la calidad del servicio.

Mapa Metroaverías

Mapa Metroaverías

Metro averías es un proyecto que arranqué en el 2014 mientras estaba realizando mi tesis sobre Caracterización de usuarios y propagación de mensajes en Twitter en el entorno de temas sociales. En 2015 publiqué un artículo en el IEEE Internet Computing titulado Microbloggers as sensors for public transport breakdowns.

Desde marzo de 2014 hasta la fecha se han recogido todos los tweets que mencionan al Metro de Madrid o a su perfil en @metro_madrid en Twitter, salvo un periodo entre septiembre de 2017 a agosto de 2018 que no se descargaron datos por problemas de infraestructura.

Los datos se obtienen con t-hoarder y se procesan de forma especial para detectar las averías del Metro de Madrid con esta metodología. Los resultados se depositan en este repositorio y están abiertos al que los quiera utilizar.

library(readr)
library(dplyr)
library(tidyr)
library(ggplot2)
library(stringr)
library(lubridate)
require(RCurl)
locale(date_names = "es", date_format = "%AD", time_format = "%AT",
       decimal_mark = ",", grouping_mark = ".", tz = "UTC",
       encoding = "UTF-8", asciify = FALSE)
<locale>
Numbers:  123.456,78
Formats:  %AD / %AT
Timezone: UTC
Encoding: UTF-8
<date_names>
Days:   domingo (dom.), lunes (lun.), martes (mar.), miércoles (mié.), jueves (jue.), viernes (vie.),
        sábado (sáb.)
Months: enero (ene.), febrero (feb.), marzo (mar.), abril (abr.), mayo (may.), junio (jun.), julio (jul.),
        agosto (ago.), septiembre (sept.), octubre (oct.), noviembre (nov.), diciembre (dic.)
AM/PM:  a. m./p. m.

Descarga y preparación de datos para las gráficas

urlfile_complaints<-"https://raw.githubusercontent.com/congosto/metroaverias/master/data/metro_madrid_topics.csv"
urlfile_lines<-"https://raw.githubusercontent.com/congosto/metroaverias/master/data/metro_madrid_lines.csv"
DiaSemana <- c('domingo','lunes','martes','miércoles','jueves','viernes','sábado')
Meses <- c ("Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dic")
complaints<-read.csv2( urlfile_complaints,encoding = "UTF-8")

df_complaints_ancha <- data.frame(complaints)
df_complaints_ancha$Date <- as.Date(df_complaints_ancha$Date,format="%Y-%m-%d")
df_complaints_larga <- gather(df_complaints_ancha,"complaint", "Count", -"Date") 
df_complaints_larga <- mutate (df_complaints_larga, Year = as.numeric(format(Date,'%Y')))
df_complaints_larga <- mutate (df_complaints_larga, Month = as.numeric(format(Date,'%m')))
df_complaints_larga <- mutate (df_complaints_larga, DiaSem=wday(Date))

lines<-read.csv2( urlfile_lines,encoding = "UTF-8")

df_lines_ancha <- data.frame(lines)
df_lines_ancha$Date <- as.Date(df_lines_ancha$Date,format="%Y-%m-%d")
df_lines_larga <- gather(df_lines_ancha,"Line", "Count", -"Date") 
df_lines_larga <- mutate (df_lines_larga, Year = as.numeric(format(Date,'%Y')))

Quejas más frecuentes

Las quejas analizadas fueron: slowness (lentitud), entrance (accesos), breakdown (avería), heat (calor), odor (olor), overcrowding (aglomeración), dirtiness (suciedad), control(control de billetes), price (precio), flood (inundación), covid-19 (posibles quejas por covid-19).

Se ha utilizado la mediana en vez de la media porque había valores atípicos (picos de quejas) que podrían distorsionar la comparación.

De todas estas quejas, las más frecuentes por este orden han sido: slowness, entrance, heat y overcrowding.

Destaca sobre todas slowness que tiene una mediana más de tres veces superior a la siguiente queja

df_complaints_larga  %>%  select (complaint,Count) %>%
                     group_by(complaint) %>%  
                     summarise ( Mediana=median(Count), .groups = 'drop')  %>%
  ggplot (aes(x =  reorder(complaint,Mediana), y = Mediana)) +
  geom_col(color = "white",
           fill = "cornflowerblue" )+
  coord_flip() + 
  guides(color = FALSE)+
  geom_text( aes(label= round(Mediana,2)),colour="white",size=3,
           position=position_stack(vjust = 0.5))+
  theme(text=element_text(size=9))+
  theme(plot.title=element_text(size=10,face="bold"))+
  labs(x = "Quejas", y = "Mediana de quejas/día",
       title = "Mediana del número de quejas diarias")+
ggsave("../images/mediana_quejas_diarias.jpg")

Quejas más frecuentes por año

Si miramos la mediana de quejas diarias por año, se observa que de slowness va descendiendo en los años 2015, 2016 y 2017 para aumentar fuertemente en los años 2018 y 2019, volviendo a descender en el 2020. y que la mediana de covid-19 es la mayor en el año 2020.

df_complaints_larga  %>%  select (complaint,Count,Year) %>%
                     group_by(complaint,Year) %>% 
                     summarise ( Mediana=median(Count), .groups = 'drop')  %>%
  ggplot (aes(x =  reorder(complaint,Mediana), y = Mediana)) +
  geom_col(color = "white",
           fill = "cornflowerblue" )+
  coord_flip() + 
  guides(color = FALSE)+
  theme(text=element_text(size=9))+
  theme(plot.title=element_text(size=10,face="bold"))+
  labs(x = "Quejas", y = "Mediana de quejas/día",
       title = "Mediana del número de quejas diarias por año")+
  facet_wrap(~ Year) 
ggsave("../images/mediana_quejas_diarias_year.jpg")

Mediana del múmero de quejas por mes

En los meses de verano es cuando hay más quejas de lentitud, posiblemente porque se reduce la frecuencia de los trenes por las vacaciones.

df_complaints_larga  %>%  select (Count,Month,complaint)  %>%
                     group_by(Month,complaint) %>%  
                     summarise ( Mediana=median(Count), .groups = 'drop')  %>% 
  ggplot () +
  geom_step(aes(x =  Month, y = Mediana, color=reorder(complaint,-Mediana)) )+
  guides(title = "")+

  theme(text=element_text(size=9))+
         theme(plot.title=element_text(size=10,face="bold"))+
  scale_x_continuous(breaks=c(1,2,3,4,5,6,7,8,9,10,11,12), 
                              labels=Meses)+  
  labs(x = "Meses", y = "Mediana de quejas/día",
       title = "Mediana del múmero de quejas por mes")+
ggsave("../images/mediana_quejas_mes.jpg") 

Mediana del múmero de quejas por mes y año

Desglosándolo por años, persiste el aumento de quejas en los meses de verano. En el año 2020 la quejas por covid-19 desbancan a las de slowness.

df_complaints_larga  %>%  select (Count,Month,complaint,Year)  %>%
                     group_by(Month,complaint,Year) %>%  
                     summarise ( Mediana=median(Count), .groups = 'drop')  %>% 
  ggplot () +
  geom_step(aes(x =  Month, y = Mediana, color=reorder(complaint,-Mediana)) )+
  guides(title = "")+

  theme(text=element_text(size=9))+
         theme(plot.title=element_text(size=10,face="bold"))+
  scale_x_continuous(breaks=c(1,2,3,4,5,6,7,8,9,10,11,12))+  
  labs(x = "Meses", y = "Mediana de quejas/día",
       title = "Mediana del múmero de quejas por mes y año")+
  facet_wrap(~ Year)
ggsave("../images/mediana_quejas_mes_year.jpg") 

Mediana del múmero de quejas por dia de la semana

La mitad de la semana, el miércoles, es cuando se producen más quejas. Bajan significativamente los fines de semana

df_complaints_larga  %>%  select (Count,DiaSem,complaint)  %>%
                     group_by(DiaSem,complaint) %>%  
                     summarise ( Mediana=median(Count), .groups = 'drop')  %>% 
  ggplot () +
  geom_step(aes(x =  DiaSem, y = Mediana, color=reorder(complaint,-Mediana)) )+
  guides(title = "")+

  theme(text=element_text(size=9))+
         theme(plot.title=element_text(size=10,face="bold"))+
  scale_x_continuous(breaks=c(1,2,3,4,5,6,7), 
                              labels=DiaSemana)+  
  labs(x = "Días de la semana", y = "Mediana de quejas/día",
       title = "Mediana del múmero de quejas por día de la semana")+
ggsave("../images/mediana_quejas_dia_sem.jpg") 

Mediana del número de quejas diarias por línea

Las líneas con más quejas son la L1, L6 y L5, posiblemente por ser las más largas y concurridas

df_lines_larga  %>%  select (Line,Count) %>%
                     group_by(Line) %>% 
                     summarise ( Mediana=median(Count), .groups = 'drop')  %>%
  ggplot (aes(x =  reorder(Line,Mediana), y = Mediana,color = Line)) +
  geom_col(color = "white",
           fill = "cornflowerblue" )+
  coord_flip() + 
  guides(color = FALSE)+
  geom_text( aes(label= round(Mediana,2)),colour="white",size=3,
           position=position_stack(vjust = 0.5))+
  theme(text=element_text(size=9))+
  theme(plot.title=element_text(size=10,face="bold"))+
  labs(x = "Líneas", y = "Mediana de quejas/día",
       title = "Mediana del número de quejas diarias por línea")+
ggsave("../images/mediana_quejas_diarias_linea.jpg") 

Mediana del número de quejas diarias por línea y año

Salvo en el año 2015, la línea con más quejas fue la L1. En todos los años las líneas L1,L6 y L5 estuvieron en el top de quejas.

df_lines_larga  %>%  select (Line,Count,Year) %>%
                     group_by(Line,Year) %>% 
                     summarise ( Mediana=median(Count), .groups = 'drop')  %>%
  ggplot (aes(x =  reorder(Line,Mediana), y = Mediana,color = Line)) +
  geom_col(color = "white",
           fill = "cornflowerblue" )+
  coord_flip() + 
  guides(color = FALSE)+
  theme(text=element_text(size=9))+
  theme(plot.title=element_text(size=10,face="bold"))+
  labs(x = "Líneas", y = "Mediana de quejas/día",
       title = "Mediana del número de quejas diarias por línea")+
  facet_wrap(~ Year)
ggsave("../images/mediana_quejas_diarias_linea_year.jpg") 

Evolución de las quejas Lentitud (Slowness) y Aglomeración (Overcrowding) durante el periodo 2014- 2020

Para analizar la evolución de las quejas se han seleccionado las quejas slowness y Overcrowding que son las que más preocupan por su relación con posibles contagios en el Metro de Madrid.

En la gráfica se puede observar los picos de actividad y una ausencia de datos, por problemas de infraestructura, entre septiembre de 2017 a agosto de 2018.

df_complaints_larga  %>%  filter(complaint == "Slowness" | complaint == "Overcrowding" ) %>%
  ggplot () +
  geom_step(  aes(x = Date, y = Count, color=complaint))+
  scale_colour_manual('', values = c('#B40F20','#46ACC8')) +
  theme(text=element_text(size=9))+
  theme(plot.title=element_text(size=9,face="bold"))+
  labs(x = "Tiempo en días", y = "Núnero de quejas",
       title = "Evolución de las quejas del metro de Madrid 2014-2020")+
  annotate(geom="text",x=as.Date("2017-09-09"),y=600,
           label="Stop datos\n2017-09-09",size=2.5,color="red",
           hjust = 1,fontface = 'italic')+
  annotate(geom="text",x=as.Date("2018-06-11"),y=1000,
           label="reanudar datos\n2018-06-11",size=2.5,color="red",hjust = 1,
           fontface = 'italic')+
  annotate(geom="text",x=as.Date("2020-03-16"),y=3000,
           label="confinamiento\n2020-03-16",size=2.5,color="red",
           hjust = 1,fontface = 'italic')

ggsave("../images/complaint_2014_2020.jpg") 

Evolución de las quejas Lentitud (Slowness) y Aglomeración (Overcrowding) durante el periodo 2019-2020

Seleccionando sólo los años 2019 y 2020 se puede comparar las quejas del año 2020, un año atípico por el covid-19, respecto a las del 2019.

df_complaints_larga  %>%  filter(complaint == "Slowness" | complaint == "Overcrowding",
                                 Year == "2020" | Year == "2019" ) %>%
  ggplot () +
  geom_step(  aes(x = Date, y = Count, color=complaint))+
  scale_colour_manual('', values = c('#B40F20','#46ACC8')) +
  theme(text=element_text(size=9))+
  theme(plot.title=element_text(size=9,face="bold"))+
  labs(x = "Tiempo en días", y = "Núnero de quejas",
       title = "Evolución de las quejas del metro de Madrid 2019-2020")+
  annotate(geom="text",x=as.Date("2020-03-16"),y=3000,
           label="confinamiento\n2020-03-16",size=2.5,color="red",
           hjust = 1,fontface = 'italic')

ggsave("../images/complaint_2019_2020.jpg") 

Evolución de las quejas Lentitud (Slowness), Aglomeración (Overcrowding) y COVID-19 durante el año 2020

Seleccionando sólo el año 2020 e incluyendo la queja de covid-19 se observa como las quejas de covid-19 han superado ampliamente a las otras dos, tanto en momentos puntuales como continuos.

df_complaints_larga  %>%  filter(complaint == "Slowness" | complaint == "Overcrowding" | complaint == "COVID.19" ,
                                Year == "2020" ) %>%
  ggplot () +
  geom_step(  aes(x = Date, y = Count, color=complaint))+
  scale_colour_manual('', values = c('#EC33FF','#B40F20','#46ACC8')) +
  theme(text=element_text(size=9))+
  theme(plot.title=element_text(size=10,face="bold"))+
  labs(x = "Tiempo en días", y = "Núnero de quejas",
       title = "Evolución de las quejas del metro de Madrid en 2020")+
  annotate(geom="text",x=as.Date("2020-03-16"),y=20000,
           label="confinamiento\n2020-03-16",size=2.5,color="red",
           hjust = 1,fontface = 'italic')
ggsave("../images/complaint_2020.jpg") 

LS0tDQp0aXRsZTogIlF1ZWphcyBkZWwgTWV0cm8gZGUgTWFkcmlkIGVuIFR3aXR0ZXIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyBJbnRyb2R1Y2Npw7NuDQoNCkVsIE1ldHJvIGRlIE1hZHJpZCBzdWZyacOzIHVuYSBww6lyZGlkYSBkZSBjYWxpZGFkIGNvbW8gY29uc2VjdWVuY2lhIGRlIGxhIGNyaXNpcyBlY29uw7NtaWNhIGRlbCAyMDA4LiBMYSBmcmVjdWVuY2lhIGRlIHRyZW5lcyBzZSByZWR1am8gZGFuZG8gbHVnYXIgYSBmcmVjdWVudGVzIGFnbG9tZXJhY2lvbmVzLCBzb2JyZSB0b2RvIGVuIGhvcmEgcHVudGEuIExhIGZhbHRhIGRlIGludmVyc2nDs24gYWZlY3TDsyBhIGVzY2FsZXJhcyBtZWPDoW5pY2FzIHkgYXNjZW5zb3JlcyBxdWUgZnJlY3VlbnRlbWVudGUgZXN0YWJhbiBhdmVyaWFkb3MgeSBhIGxvcyBzZXJ2aWNpb3MgZGUgbGltcGllemEuIA0KDQpDb21vIGNvbnNlY3VlbmNpYSwgbG9zIHZpYWplcm9zIHNlIHF1ZWphYmFuIGZyZWN1ZW50ZW1lbnRlIGRlbCBzZXJ2aWNpbyBlbiBUd2l0dGVyIHkgYXBhcmVjaWVyb24gcGVyZmlsZXMgY29tbyBAU3Vmcmlkb3Jlc01ldHJvIHF1ZSBkZW51bmNpYWJhbiBlbCBtYWwgZXN0YWRvIGRlIGVzdGUgdHJhbnNwb3J0ZSBww7pibGljby4gUGVuc8OpIHF1ZSBjdWFudGlmaWNhciBlc3RhcyBxdWVqYXMgZGUgbG9zIHZpYWplcm9zIGRlbCBtZXRybyBwb2Ryw61hbiBjb252ZXJ0aXIgYSBzdXMgdXN1YXJpb3MgZW4gdW4gc2Vuc29yIGRlIGxhIGNhbGlkYWQgZGVsIHNlcnZpY2lvLg0KDQo8Y2VudGVyPg0KIVtNYXBhIE1ldHJvYXZlcsOtYXNdKC4uL2ltYWdlcy9tZXRyb2F2ZXJpYXNfbWFwYS5wbmcpe3dpdGhkPTkwfQ0KDQo8L2NlbnRlcj4NCg0KTWV0cm8gYXZlcsOtYXMgZXMgdW4gcHJveWVjdG8gcXVlIGFycmFucXXDqSBlbiBlbCAyMDE0IG1pZW50cmFzIGVzdGFiYSByZWFsaXphbmRvIG1pIHRlc2lzIHNvYnJlIFtDYXJhY3Rlcml6YWNpw7NuIGRlIHVzdWFyaW9zIHkgcHJvcGFnYWNpw7NuIGRlIG1lbnNhamVzIGVuIFR3aXR0ZXIgZW4gZWwgZW50b3JubyBkZSB0ZW1hcyBzb2NpYWxlc10oaHR0cHM6Ly9lLWFyY2hpdm8udWMzbS5lcy9oYW5kbGUvMTAwMTYvMjI4MjYpLiBFbiAyMDE1IHB1YmxpcXXDqSB1biBhcnTDrWN1bG8gZW4gZWwgSUVFRSBJbnRlcm5ldCBDb21wdXRpbmcgIHRpdHVsYWRvIFtNaWNyb2Jsb2dnZXJzIGFzIHNlbnNvcnMgZm9yIHB1YmxpYyB0cmFuc3BvcnQgYnJlYWtkb3duc10oaHR0cHM6Ly9pZWVleHBsb3JlLmllZWUub3JnL2RvY3VtZW50LzcyMzk1MTQpLg0KDQoNCkRlc2RlIG1hcnpvIGRlIDIwMTQgaGFzdGEgbGEgZmVjaGEgc2UgaGFuIHJlY29naWRvIHRvZG9zIGxvcyB0d2VldHMgcXVlIG1lbmNpb25hbiBhbCBNZXRybyBkZSBNYWRyaWQgbyBhIHN1IHBlcmZpbCBlbiBAbWV0cm9fbWFkcmlkIGVuIFR3aXR0ZXIsIHNhbHZvIHVuIHBlcmlvZG8gZW50cmUgc2VwdGllbWJyZSBkZSAyMDE3IGEgYWdvc3RvIGRlIDIwMTggcXVlIG5vIHNlIGRlc2Nhcmdhcm9uIGRhdG9zIHBvciBwcm9ibGVtYXMgZGUgaW5mcmFlc3RydWN0dXJhLg0KDQoNCkxvcyBkYXRvcyBzZSBvYnRpZW5lbiBjb24gW3QtaG9hcmRlcl0oaHR0cHM6Ly9naXRodWIuY29tL2Nvbmdvc3RvL3QtaG9hcmRlciApIHkgc2UgcHJvY2VzYW4gZGUgZm9ybWEgZXNwZWNpYWwgcGFyYSBkZXRlY3RhciBsYXMgYXZlcsOtYXMgZGVsIE1ldHJvIGRlIE1hZHJpZCBbY29uIGVzdGEgbWV0b2RvbG9nw61hXShodHRwOi8vdC1ob2FyZGVyLmNvbS9tZXRyb19tYWRyaWQvbWV0cm9hdmVyaWFzX21ldGhvZG9sb2d5Lmh0bWwpLiBMb3MgcmVzdWx0YWRvcyBzZSBkZXBvc2l0YW4gZW4gW2VzdGUgcmVwb3NpdG9yaW9dKGh0dHBzOi8vZ2l0aHViLmNvbS9jb25nb3N0by9tZXRyb2F2ZXJpYXMvdHJlZS9tYXN0ZXIvZGF0YSApIHkgZXN0w6FuIGFiaWVydG9zIGFsIHF1ZSBsb3MgcXVpZXJhIHV0aWxpemFyLg0KDQoNCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkobHVicmlkYXRlKQ0KcmVxdWlyZShSQ3VybCkNCmxvY2FsZShkYXRlX25hbWVzID0gImVzIiwgZGF0ZV9mb3JtYXQgPSAiJUFEIiwgdGltZV9mb3JtYXQgPSAiJUFUIiwNCiAgICAgICBkZWNpbWFsX21hcmsgPSAiLCIsIGdyb3VwaW5nX21hcmsgPSAiLiIsIHR6ID0gIlVUQyIsDQogICAgICAgZW5jb2RpbmcgPSAiVVRGLTgiLCBhc2NpaWZ5ID0gRkFMU0UpDQpgYGANCg0KIyMjIERlc2NhcmdhIHkgcHJlcGFyYWNpw7NuIGRlIGRhdG9zIHBhcmEgbGFzIGdyw6FmaWNhcw0KDQoNCg0KDQpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KdXJsZmlsZV9jb21wbGFpbnRzPC0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2Nvbmdvc3RvL21ldHJvYXZlcmlhcy9tYXN0ZXIvZGF0YS9tZXRyb19tYWRyaWRfdG9waWNzLmNzdiINCnVybGZpbGVfbGluZXM8LSJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vY29uZ29zdG8vbWV0cm9hdmVyaWFzL21hc3Rlci9kYXRhL21ldHJvX21hZHJpZF9saW5lcy5jc3YiDQpEaWFTZW1hbmEgPC0gYygnZG9taW5nbycsJ2x1bmVzJywnbWFydGVzJywnbWnDqXJjb2xlcycsJ2p1ZXZlcycsJ3ZpZXJuZXMnLCdzw6FiYWRvJykNCk1lc2VzIDwtIGMgKCJFbmUiLCJGZWIiLCJNYXIiLCJBYnIiLCJNYXkiLCJKdW4iLCJKdWwiLCJBZ28iLCJTZXAiLCJPY3QiLCJOb3YiLCJEaWMiKQ0KY29tcGxhaW50czwtcmVhZC5jc3YyKCB1cmxmaWxlX2NvbXBsYWludHMsZW5jb2RpbmcgPSAiVVRGLTgiKQ0KDQpkZl9jb21wbGFpbnRzX2FuY2hhIDwtIGRhdGEuZnJhbWUoY29tcGxhaW50cykNCmRmX2NvbXBsYWludHNfYW5jaGEkRGF0ZSA8LSBhcy5EYXRlKGRmX2NvbXBsYWludHNfYW5jaGEkRGF0ZSxmb3JtYXQ9IiVZLSVtLSVkIikNCmRmX2NvbXBsYWludHNfbGFyZ2EgPC0gZ2F0aGVyKGRmX2NvbXBsYWludHNfYW5jaGEsImNvbXBsYWludCIsICJDb3VudCIsIC0iRGF0ZSIpIA0KZGZfY29tcGxhaW50c19sYXJnYSA8LSBtdXRhdGUgKGRmX2NvbXBsYWludHNfbGFyZ2EsIFllYXIgPSBhcy5udW1lcmljKGZvcm1hdChEYXRlLCclWScpKSkNCmRmX2NvbXBsYWludHNfbGFyZ2EgPC0gbXV0YXRlIChkZl9jb21wbGFpbnRzX2xhcmdhLCBNb250aCA9IGFzLm51bWVyaWMoZm9ybWF0KERhdGUsJyVtJykpKQ0KZGZfY29tcGxhaW50c19sYXJnYSA8LSBtdXRhdGUgKGRmX2NvbXBsYWludHNfbGFyZ2EsIERpYVNlbT13ZGF5KERhdGUpKQ0KDQpsaW5lczwtcmVhZC5jc3YyKCB1cmxmaWxlX2xpbmVzLGVuY29kaW5nID0gIlVURi04IikNCg0KZGZfbGluZXNfYW5jaGEgPC0gZGF0YS5mcmFtZShsaW5lcykNCmRmX2xpbmVzX2FuY2hhJERhdGUgPC0gYXMuRGF0ZShkZl9saW5lc19hbmNoYSREYXRlLGZvcm1hdD0iJVktJW0tJWQiKQ0KZGZfbGluZXNfbGFyZ2EgPC0gZ2F0aGVyKGRmX2xpbmVzX2FuY2hhLCJMaW5lIiwgIkNvdW50IiwgLSJEYXRlIikgDQpkZl9saW5lc19sYXJnYSA8LSBtdXRhdGUgKGRmX2xpbmVzX2xhcmdhLCBZZWFyID0gYXMubnVtZXJpYyhmb3JtYXQoRGF0ZSwnJVknKSkpDQoNCg0KYGBgDQojIyMgUXVlamFzIG3DoXMgZnJlY3VlbnRlcyANCg0KTGFzIHF1ZWphcyBhbmFsaXphZGFzIGZ1ZXJvbjogc2xvd25lc3MgKGxlbnRpdHVkKSwgZW50cmFuY2UgKGFjY2Vzb3MpLCBicmVha2Rvd24gKGF2ZXLDrWEpLCBoZWF0IChjYWxvciksIG9kb3IgKG9sb3IpLCBvdmVyY3Jvd2RpbmcgKGFnbG9tZXJhY2nDs24pLCBkaXJ0aW5lc3MgKHN1Y2llZGFkKSwgY29udHJvbChjb250cm9sIGRlIGJpbGxldGVzKSwgcHJpY2UgKHByZWNpbyksIGZsb29kIChpbnVuZGFjacOzbiksIGNvdmlkLTE5IChwb3NpYmxlcyBxdWVqYXMgcG9yIGNvdmlkLTE5KS4NCg0KU2UgaGEgdXRpbGl6YWRvIGxhIG1lZGlhbmEgZW4gdmV6IGRlIGxhIG1lZGlhIHBvcnF1ZSBoYWLDrWEgdmFsb3JlcyBhdMOtcGljb3MgKHBpY29zIGRlIHF1ZWphcykgcXVlIHBvZHLDrWFuIGRpc3RvcnNpb25hciBsYSBjb21wYXJhY2nDs24uDQoNCkRlIHRvZGFzIGVzdGFzIHF1ZWphcywgbGFzIG3DoXMgZnJlY3VlbnRlcyBwb3IgZXN0ZSBvcmRlbiBoYW4gc2lkbzogc2xvd25lc3MsIGVudHJhbmNlLCBoZWF0IHkgb3ZlcmNyb3dkaW5nLg0KDQpEZXN0YWNhIHNvYnJlIHRvZGFzIHNsb3duZXNzIHF1ZSB0aWVuZSB1bmEgbWVkaWFuYSBtw6FzIGRlIHRyZXMgdmVjZXMgc3VwZXJpb3IgYSBsYSBzaWd1aWVudGUgcXVlamENCg0KDQoNCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCmRmX2NvbXBsYWludHNfbGFyZ2EgICU+JSAgc2VsZWN0IChjb21wbGFpbnQsQ291bnQpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY29tcGxhaW50KSAlPiUgIA0KICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlICggTWVkaWFuYT1tZWRpYW4oQ291bnQpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAgJT4lDQogIGdncGxvdCAoYWVzKHggPSAgcmVvcmRlcihjb21wbGFpbnQsTWVkaWFuYSksIHkgPSBNZWRpYW5hKSkgKw0KICBnZW9tX2NvbChjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgIGZpbGwgPSAiY29ybmZsb3dlcmJsdWUiICkrDQogIGNvb3JkX2ZsaXAoKSArIA0KICBndWlkZXMoY29sb3IgPSBGQUxTRSkrDQogIGdlb21fdGV4dCggYWVzKGxhYmVsPSByb3VuZChNZWRpYW5hLDIpKSxjb2xvdXI9IndoaXRlIixzaXplPTMsDQogICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkrDQogIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OSkpKw0KICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwLGZhY2U9ImJvbGQiKSkrDQogIGxhYnMoeCA9ICJRdWVqYXMiLCB5ID0gIk1lZGlhbmEgZGUgcXVlamFzL2TDrWEiLA0KICAgICAgIHRpdGxlID0gIk1lZGlhbmEgZGVsIG7Dum1lcm8gZGUgcXVlamFzIGRpYXJpYXMiKSsNCmdnc2F2ZSgiLi4vaW1hZ2VzL21lZGlhbmFfcXVlamFzX2RpYXJpYXMuanBnIikNCmBgYA0KDQojIyMgUXVlamFzIG3DoXMgZnJlY3VlbnRlcyBwb3IgYcOxbw0KDQpTaSBtaXJhbW9zIGxhIG1lZGlhbmEgZGUgcXVlamFzIGRpYXJpYXMgcG9yIGHDsW8sIHNlIG9ic2VydmEgcXVlIGRlIHNsb3duZXNzIHZhIGRlc2NlbmRpZW5kbyBlbiBsb3MgYcOxb3MgMjAxNSwgMjAxNiB5IDIwMTcgcGFyYSBhdW1lbnRhciBmdWVydGVtZW50ZSBlbiBsb3MgYcOxb3MgMjAxOCB5IDIwMTksIHZvbHZpZW5kbyBhIGRlc2NlbmRlciBlbiBlbCAyMDIwLiB5IHF1ZSBsYSBtZWRpYW5hIGRlIGNvdmlkLTE5IGVzIGxhIG1heW9yIGVuIGVsIGHDsW8gMjAyMC4NCg0KDQoNCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9RkFMU0V9DQpkZl9jb21wbGFpbnRzX2xhcmdhICAlPiUgIHNlbGVjdCAoY29tcGxhaW50LENvdW50LFllYXIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoY29tcGxhaW50LFllYXIpICU+JSANCiAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSAoIE1lZGlhbmE9bWVkaWFuKENvdW50KSwgLmdyb3VwcyA9ICdkcm9wJykgICU+JQ0KICBnZ3Bsb3QgKGFlcyh4ID0gIHJlb3JkZXIoY29tcGxhaW50LE1lZGlhbmEpLCB5ID0gTWVkaWFuYSkpICsNCiAgZ2VvbV9jb2woY29sb3IgPSAid2hpdGUiLA0KICAgICAgICAgICBmaWxsID0gImNvcm5mbG93ZXJibHVlIiApKw0KICBjb29yZF9mbGlwKCkgKyANCiAgZ3VpZGVzKGNvbG9yID0gRkFMU0UpKw0KICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTkpKSsNCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCxmYWNlPSJib2xkIikpKw0KICBsYWJzKHggPSAiUXVlamFzIiwgeSA9ICJNZWRpYW5hIGRlIHF1ZWphcy9kw61hIiwNCiAgICAgICB0aXRsZSA9ICJNZWRpYW5hIGRlbCBuw7ptZXJvIGRlIHF1ZWphcyBkaWFyaWFzIHBvciBhw7FvIikrDQogIGZhY2V0X3dyYXAofiBZZWFyKSANCmdnc2F2ZSgiLi4vaW1hZ2VzL21lZGlhbmFfcXVlamFzX2RpYXJpYXNfeWVhci5qcGciKQ0KDQpgYGANCiMjIyBNZWRpYW5hIGRlbCBtw7ptZXJvIGRlIHF1ZWphcyBwb3IgbWVzDQoNCkVuIGxvcyBtZXNlcyBkZSB2ZXJhbm8gZXMgY3VhbmRvIGhheSBtw6FzIHF1ZWphcyBkZSBsZW50aXR1ZCwgcG9zaWJsZW1lbnRlIHBvcnF1ZSBzZSByZWR1Y2UgbGEgZnJlY3VlbmNpYSBkZSBsb3MgdHJlbmVzIHBvciBsYXMgdmFjYWNpb25lcy4NCg0KDQpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KZGZfY29tcGxhaW50c19sYXJnYSAgJT4lICBzZWxlY3QgKENvdW50LE1vbnRoLGNvbXBsYWludCkgICU+JQ0KICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoTW9udGgsY29tcGxhaW50KSAlPiUgIA0KICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlICggTWVkaWFuYT1tZWRpYW4oQ291bnQpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAgJT4lIA0KICBnZ3Bsb3QgKCkgKw0KICBnZW9tX3N0ZXAoYWVzKHggPSAgTW9udGgsIHkgPSBNZWRpYW5hLCBjb2xvcj1yZW9yZGVyKGNvbXBsYWludCwtTWVkaWFuYSkpICkrDQogIGd1aWRlcyh0aXRsZSA9ICIiKSsNCg0KICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTkpKSsNCiAgICAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTAsZmFjZT0iYm9sZCIpKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9TWVzZXMpKyAgDQogIGxhYnMoeCA9ICJNZXNlcyIsIHkgPSAiTWVkaWFuYSBkZSBxdWVqYXMvZMOtYSIsDQogICAgICAgdGl0bGUgPSAiTWVkaWFuYSBkZWwgbcO6bWVybyBkZSBxdWVqYXMgcG9yIG1lcyIpKw0KZ2dzYXZlKCIuLi9pbWFnZXMvbWVkaWFuYV9xdWVqYXNfbWVzLmpwZyIpIA0KDQpgYGANCiMjIyBNZWRpYW5hIGRlbCBtw7ptZXJvIGRlIHF1ZWphcyBwb3IgbWVzIHkgYcOxbw0KDQpEZXNnbG9zw6FuZG9sbyBwb3IgYcOxb3MsIHBlcnNpc3RlIGVsIGF1bWVudG8gZGUgcXVlamFzIGVuIGxvcyBtZXNlcyBkZSB2ZXJhbm8uIEVuIGVsIGHDsW8gMjAyMCBsYSBxdWVqYXMgcG9yIGNvdmlkLTE5IGRlc2JhbmNhbiBhIGxhcyBkZSBzbG93bmVzcy4NCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCmRmX2NvbXBsYWludHNfbGFyZ2EgICU+JSAgc2VsZWN0IChDb3VudCxNb250aCxjb21wbGFpbnQsWWVhcikgICU+JQ0KICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoTW9udGgsY29tcGxhaW50LFllYXIpICU+JSAgDQogICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UgKCBNZWRpYW5hPW1lZGlhbihDb3VudCksIC5ncm91cHMgPSAnZHJvcCcpICAlPiUgDQogIGdncGxvdCAoKSArDQogIGdlb21fc3RlcChhZXMoeCA9ICBNb250aCwgeSA9IE1lZGlhbmEsIGNvbG9yPXJlb3JkZXIoY29tcGxhaW50LC1NZWRpYW5hKSkgKSsNCiAgZ3VpZGVzKHRpdGxlID0gIiIpKw0KDQogIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9OSkpKw0KICAgICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCxmYWNlPSJib2xkIikpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIpKSsgIA0KICBsYWJzKHggPSAiTWVzZXMiLCB5ID0gIk1lZGlhbmEgZGUgcXVlamFzL2TDrWEiLA0KICAgICAgIHRpdGxlID0gIk1lZGlhbmEgZGVsIG3Dum1lcm8gZGUgcXVlamFzIHBvciBtZXMgeSBhw7FvIikrDQogIGZhY2V0X3dyYXAofiBZZWFyKQ0KZ2dzYXZlKCIuLi9pbWFnZXMvbWVkaWFuYV9xdWVqYXNfbWVzX3llYXIuanBnIikgDQpgYGANCg0KDQoNCiMjIyBNZWRpYW5hIGRlbCBtw7ptZXJvIGRlIHF1ZWphcyBwb3IgZGlhIGRlIGxhIHNlbWFuYQ0KDQpMYSBtaXRhZCBkZSBsYSBzZW1hbmEsIGVsIG1pw6lyY29sZXMsIGVzIGN1YW5kbyBzZSBwcm9kdWNlbiBtw6FzIHF1ZWphcy4gQmFqYW4gc2lnbmlmaWNhdGl2YW1lbnRlIGxvcyBmaW5lcyBkZSBzZW1hbmENCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCmRmX2NvbXBsYWludHNfbGFyZ2EgICU+JSAgc2VsZWN0IChDb3VudCxEaWFTZW0sY29tcGxhaW50KSAgJT4lDQogICAgICAgICAgICAgICAgICAgICBncm91cF9ieShEaWFTZW0sY29tcGxhaW50KSAlPiUgIA0KICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlICggTWVkaWFuYT1tZWRpYW4oQ291bnQpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAgJT4lIA0KICBnZ3Bsb3QgKCkgKw0KICBnZW9tX3N0ZXAoYWVzKHggPSAgRGlhU2VtLCB5ID0gTWVkaWFuYSwgY29sb3I9cmVvcmRlcihjb21wbGFpbnQsLU1lZGlhbmEpKSApKw0KICBndWlkZXModGl0bGUgPSAiIikrDQoNCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT05KSkrDQogICAgICAgICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwLGZhY2U9ImJvbGQiKSkrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxLDIsMyw0LDUsNiw3KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9RGlhU2VtYW5hKSsgIA0KICBsYWJzKHggPSAiRMOtYXMgZGUgbGEgc2VtYW5hIiwgeSA9ICJNZWRpYW5hIGRlIHF1ZWphcy9kw61hIiwNCiAgICAgICB0aXRsZSA9ICJNZWRpYW5hIGRlbCBtw7ptZXJvIGRlIHF1ZWphcyBwb3IgZMOtYSBkZSBsYSBzZW1hbmEiKSsNCmdnc2F2ZSgiLi4vaW1hZ2VzL21lZGlhbmFfcXVlamFzX2RpYV9zZW0uanBnIikgDQpgYGANCiMjIyBNZWRpYW5hIGRlbCBuw7ptZXJvIGRlIHF1ZWphcyBkaWFyaWFzIHBvciBsw61uZWENCg0KTGFzIGzDrW5lYXMgY29uIG3DoXMgcXVlamFzIHNvbiBsYSBMMSwgTDYgeSBMNSwgcG9zaWJsZW1lbnRlIHBvciBzZXIgbGFzIG3DoXMgbGFyZ2FzIHkgY29uY3VycmlkYXMNCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCmRmX2xpbmVzX2xhcmdhICAlPiUgIHNlbGVjdCAoTGluZSxDb3VudCkgJT4lDQogICAgICAgICAgICAgICAgICAgICBncm91cF9ieShMaW5lKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UgKCBNZWRpYW5hPW1lZGlhbihDb3VudCksIC5ncm91cHMgPSAnZHJvcCcpICAlPiUNCiAgZ2dwbG90IChhZXMoeCA9ICByZW9yZGVyKExpbmUsTWVkaWFuYSksIHkgPSBNZWRpYW5hLGNvbG9yID0gTGluZSkpICsNCiAgZ2VvbV9jb2woY29sb3IgPSAid2hpdGUiLA0KICAgICAgICAgICBmaWxsID0gImNvcm5mbG93ZXJibHVlIiApKw0KICBjb29yZF9mbGlwKCkgKyANCiAgZ3VpZGVzKGNvbG9yID0gRkFMU0UpKw0KICBnZW9tX3RleHQoIGFlcyhsYWJlbD0gcm91bmQoTWVkaWFuYSwyKSksY29sb3VyPSJ3aGl0ZSIsc2l6ZT0zLA0KICAgICAgICAgICBwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpKw0KICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTkpKSsNCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCxmYWNlPSJib2xkIikpKw0KICBsYWJzKHggPSAiTMOtbmVhcyIsIHkgPSAiTWVkaWFuYSBkZSBxdWVqYXMvZMOtYSIsDQogICAgICAgdGl0bGUgPSAiTWVkaWFuYSBkZWwgbsO6bWVybyBkZSBxdWVqYXMgZGlhcmlhcyBwb3IgbMOtbmVhIikrDQpnZ3NhdmUoIi4uL2ltYWdlcy9tZWRpYW5hX3F1ZWphc19kaWFyaWFzX2xpbmVhLmpwZyIpIA0KYGBgDQojIyMgTWVkaWFuYSBkZWwgbsO6bWVybyBkZSBxdWVqYXMgZGlhcmlhcyBwb3IgbMOtbmVhIHkgYcOxbw0KDQpTYWx2byBlbiBlbCBhw7FvIDIwMTUsIGxhIGzDrW5lYSBjb24gbcOhcyBxdWVqYXMgZnVlIGxhIEwxLiBFbiB0b2RvcyBsb3MgYcOxb3MgbGFzIGzDrW5lYXMgTDEsTDYgeSBMNSBlc3R1dmllcm9uIGVuIGVsIHRvcCBkZSBxdWVqYXMuIA0KDQpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KZGZfbGluZXNfbGFyZ2EgICU+JSAgc2VsZWN0IChMaW5lLENvdW50LFllYXIpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoTGluZSxZZWFyKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UgKCBNZWRpYW5hPW1lZGlhbihDb3VudCksIC5ncm91cHMgPSAnZHJvcCcpICAlPiUNCiAgZ2dwbG90IChhZXMoeCA9ICByZW9yZGVyKExpbmUsTWVkaWFuYSksIHkgPSBNZWRpYW5hLGNvbG9yID0gTGluZSkpICsNCiAgZ2VvbV9jb2woY29sb3IgPSAid2hpdGUiLA0KICAgICAgICAgICBmaWxsID0gImNvcm5mbG93ZXJibHVlIiApKw0KICBjb29yZF9mbGlwKCkgKyANCiAgZ3VpZGVzKGNvbG9yID0gRkFMU0UpKw0KICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTkpKSsNCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCxmYWNlPSJib2xkIikpKw0KICBsYWJzKHggPSAiTMOtbmVhcyIsIHkgPSAiTWVkaWFuYSBkZSBxdWVqYXMvZMOtYSIsDQogICAgICAgdGl0bGUgPSAiTWVkaWFuYSBkZWwgbsO6bWVybyBkZSBxdWVqYXMgZGlhcmlhcyBwb3IgbMOtbmVhIikrDQogIGZhY2V0X3dyYXAofiBZZWFyKQ0KZ2dzYXZlKCIuLi9pbWFnZXMvbWVkaWFuYV9xdWVqYXNfZGlhcmlhc19saW5lYV95ZWFyLmpwZyIpIA0KYGBgDQoNCg0KIyMjIEV2b2x1Y2nDs24gZGUgbGFzIHF1ZWphcyBMZW50aXR1ZCAoU2xvd25lc3MpIHkgQWdsb21lcmFjacOzbiAoT3ZlcmNyb3dkaW5nKSBkdXJhbnRlIGVsIHBlcmlvZG8gMjAxNC0gMjAyMA0KDQpQYXJhIGFuYWxpemFyIGxhIGV2b2x1Y2nDs24gZGUgbGFzIHF1ZWphcyBzZSBoYW4gc2VsZWNjaW9uYWRvIGxhcyBxdWVqYXMgc2xvd25lc3MgeSBPdmVyY3Jvd2RpbmcgcXVlIHNvbiBsYXMgcXVlIG3DoXMgcHJlb2N1cGFuIHBvciBzdSByZWxhY2nDs24gY29uIHBvc2libGVzIGNvbnRhZ2lvcyBlbiBlbCBNZXRybyBkZSBNYWRyaWQuDQoNCkVuIGxhIGdyw6FmaWNhIHNlIHB1ZWRlIG9ic2VydmFyIGxvcyBwaWNvcyBkZSBhY3RpdmlkYWQgeSB1bmEgYXVzZW5jaWEgZGUgZGF0b3MsIHBvciBwcm9ibGVtYXMgZGUgaW5mcmFlc3RydWN0dXJhLCBlbnRyZSBzZXB0aWVtYnJlIGRlIDIwMTcgYSBhZ29zdG8gZGUgMjAxOC4NCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCmRmX2NvbXBsYWludHNfbGFyZ2EgICU+JSAgZmlsdGVyKGNvbXBsYWludCA9PSAiU2xvd25lc3MiIHwgY29tcGxhaW50ID09ICJPdmVyY3Jvd2RpbmciICkgJT4lDQogIGdncGxvdCAoKSArDQogIGdlb21fc3RlcCggIGFlcyh4ID0gRGF0ZSwgeSA9IENvdW50LCBjb2xvcj1jb21wbGFpbnQpKSsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCgnJywgdmFsdWVzID0gYygnI0I0MEYyMCcsJyM0NkFDQzgnKSkgKw0KICB0aGVtZSh0ZXh0PWVsZW1lbnRfdGV4dChzaXplPTkpKSsNCiAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT05LGZhY2U9ImJvbGQiKSkrDQogIGxhYnMoeCA9ICJUaWVtcG8gZW4gZMOtYXMiLCB5ID0gIk7Dum5lcm8gZGUgcXVlamFzIiwNCiAgICAgICB0aXRsZSA9ICJFdm9sdWNpw7NuIGRlIGxhcyBxdWVqYXMgZGVsIG1ldHJvIGRlIE1hZHJpZCAyMDE0LTIwMjAiKSsNCiAgYW5ub3RhdGUoZ2VvbT0idGV4dCIseD1hcy5EYXRlKCIyMDE3LTA5LTA5IikseT02MDAsDQogICAgICAgICAgIGxhYmVsPSJTdG9wIGRhdG9zXG4yMDE3LTA5LTA5IixzaXplPTIuNSxjb2xvcj0icmVkIiwNCiAgICAgICAgICAgaGp1c3QgPSAxLGZvbnRmYWNlID0gJ2l0YWxpYycpKw0KICBhbm5vdGF0ZShnZW9tPSJ0ZXh0Iix4PWFzLkRhdGUoIjIwMTgtMDYtMTEiKSx5PTEwMDAsDQogICAgICAgICAgIGxhYmVsPSJyZWFudWRhciBkYXRvc1xuMjAxOC0wNi0xMSIsc2l6ZT0yLjUsY29sb3I9InJlZCIsaGp1c3QgPSAxLA0KICAgICAgICAgICBmb250ZmFjZSA9ICdpdGFsaWMnKSsNCiAgYW5ub3RhdGUoZ2VvbT0idGV4dCIseD1hcy5EYXRlKCIyMDIwLTAzLTE2IikseT0zMDAwLA0KICAgICAgICAgICBsYWJlbD0iY29uZmluYW1pZW50b1xuMjAyMC0wMy0xNiIsc2l6ZT0yLjUsY29sb3I9InJlZCIsDQogICAgICAgICAgIGhqdXN0ID0gMSxmb250ZmFjZSA9ICdpdGFsaWMnKQ0KDQpnZ3NhdmUoIi4uL2ltYWdlcy9jb21wbGFpbnRfMjAxNF8yMDIwLmpwZyIpIA0KYGBgDQojIyMgRXZvbHVjacOzbiBkZSBsYXMgcXVlamFzIExlbnRpdHVkIChTbG93bmVzcykgeSBBZ2xvbWVyYWNpw7NuIChPdmVyY3Jvd2RpbmcpIGR1cmFudGUgZWwgcGVyaW9kbyAyMDE5LTIwMjANCg0KU2VsZWNjaW9uYW5kbyBzw7NsbyBsb3MgYcOxb3MgMjAxOSB5IDIwMjAgc2UgcHVlZGUgY29tcGFyYXIgbGFzIHF1ZWphcyBkZWwgYcOxbyAyMDIwLCB1biBhw7FvIGF0w61waWNvIHBvciBlbCBjb3ZpZC0xOSwgcmVzcGVjdG8gYSBsYXMgZGVsIDIwMTkuIA0KDQoNCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0NCmRmX2NvbXBsYWludHNfbGFyZ2EgICU+JSAgZmlsdGVyKGNvbXBsYWludCA9PSAiU2xvd25lc3MiIHwgY29tcGxhaW50ID09ICJPdmVyY3Jvd2RpbmciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWWVhciA9PSAiMjAyMCIgfCBZZWFyID09ICIyMDE5IiApICU+JQ0KICBnZ3Bsb3QgKCkgKw0KICBnZW9tX3N0ZXAoICBhZXMoeCA9IERhdGUsIHkgPSBDb3VudCwgY29sb3I9Y29tcGxhaW50KSkrDQogIHNjYWxlX2NvbG91cl9tYW51YWwoJycsIHZhbHVlcyA9IGMoJyNCNDBGMjAnLCcjNDZBQ0M4JykpICsNCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT05KSkrDQogIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OSxmYWNlPSJib2xkIikpKw0KICBsYWJzKHggPSAiVGllbXBvIGVuIGTDrWFzIiwgeSA9ICJOw7puZXJvIGRlIHF1ZWphcyIsDQogICAgICAgdGl0bGUgPSAiRXZvbHVjacOzbiBkZSBsYXMgcXVlamFzIGRlbCBtZXRybyBkZSBNYWRyaWQgMjAxOS0yMDIwIikrDQogIGFubm90YXRlKGdlb209InRleHQiLHg9YXMuRGF0ZSgiMjAyMC0wMy0xNiIpLHk9MzAwMCwNCiAgICAgICAgICAgbGFiZWw9ImNvbmZpbmFtaWVudG9cbjIwMjAtMDMtMTYiLHNpemU9Mi41LGNvbG9yPSJyZWQiLA0KICAgICAgICAgICBoanVzdCA9IDEsZm9udGZhY2UgPSAnaXRhbGljJykNCg0KZ2dzYXZlKCIuLi9pbWFnZXMvY29tcGxhaW50XzIwMTlfMjAyMC5qcGciKSANCg0KYGBgDQoNCiMjIyBFdm9sdWNpw7NuIGRlIGxhcyBxdWVqYXMgTGVudGl0dWQgKFNsb3duZXNzKSwgQWdsb21lcmFjacOzbiAoT3ZlcmNyb3dkaW5nKSB5IENPVklELTE5IGR1cmFudGUgZWwgYcOxbyAyMDIwDQoNClNlbGVjY2lvbmFuZG8gc8OzbG8gZWwgYcOxbyAyMDIwIGUgaW5jbHV5ZW5kbyBsYSBxdWVqYSBkZSBjb3ZpZC0xOSAgc2Ugb2JzZXJ2YSBjb21vIGxhcyBxdWVqYXMgZGUgY292aWQtMTkgaGFuIHN1cGVyYWRvIGFtcGxpYW1lbnRlIGEgbGFzIG90cmFzIGRvcywgdGFudG8gZW4gbW9tZW50b3MgcHVudHVhbGVzIGNvbW8gY29udGludW9zLg0KDQpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KZGZfY29tcGxhaW50c19sYXJnYSAgJT4lICBmaWx0ZXIoY29tcGxhaW50ID09ICJTbG93bmVzcyIgfCBjb21wbGFpbnQgPT0gIk92ZXJjcm93ZGluZyIgfCBjb21wbGFpbnQgPT0gIkNPVklELjE5IiAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFllYXIgPT0gIjIwMjAiICkgJT4lDQogIGdncGxvdCAoKSArDQogIGdlb21fc3RlcCggIGFlcyh4ID0gRGF0ZSwgeSA9IENvdW50LCBjb2xvcj1jb21wbGFpbnQpKSsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCgnJywgdmFsdWVzID0gYygnI0VDMzNGRicsJyNCNDBGMjAnLCcjNDZBQ0M4JykpICsNCiAgdGhlbWUodGV4dD1lbGVtZW50X3RleHQoc2l6ZT05KSkrDQogIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTAsZmFjZT0iYm9sZCIpKSsNCiAgbGFicyh4ID0gIlRpZW1wbyBlbiBkw61hcyIsIHkgPSAiTsO6bmVybyBkZSBxdWVqYXMiLA0KICAgICAgIHRpdGxlID0gIkV2b2x1Y2nDs24gZGUgbGFzIHF1ZWphcyBkZWwgbWV0cm8gZGUgTWFkcmlkIGVuIDIwMjAiKSsNCiAgYW5ub3RhdGUoZ2VvbT0idGV4dCIseD1hcy5EYXRlKCIyMDIwLTAzLTE2IikseT0yMDAwMCwNCiAgICAgICAgICAgbGFiZWw9ImNvbmZpbmFtaWVudG9cbjIwMjAtMDMtMTYiLHNpemU9Mi41LGNvbG9yPSJyZWQiLA0KICAgICAgICAgICBoanVzdCA9IDEsZm9udGZhY2UgPSAnaXRhbGljJykNCmdnc2F2ZSgiLi4vaW1hZ2VzL2NvbXBsYWludF8yMDIwLmpwZyIpIA0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==