Análisis de políticos

1- Descargar tweets

Creo una lista de cuentas de las cuales voy a descargar sus tweets, y además una asignación para saber a quién representa cada cuenta.

La idea original es tener 4 miembros de cada uno de los dos partidos principales, los últimos 4 candidatos en las elecciones 2019 y también las 4 cuentas partidarias en Twitter.

print("Muestra")
[1] "Muestra"
print(Tweets_DF %>% 
  select(text)%>% 
    head(5))
NA

2-Limpieza

Vamos a limpiar ciertos elementos que pueden complicar el análisis del texto, como son los links, los números, los gráficos y pasar todo a minúscula.

Además, creamos varios campos para lo que es la fecha, desagregando el campo en varios distintos, que se van a utilizar a futuro, y también se actualiza el horario a la zona horaria donde fue realizado el tweet (Argentina).

Finalmente filtramos por fecha, la idea es tener solo tweets del periodo 1/3/2020 hasta la fecha de publicación (Sep/2020)

Tweets_DF <-
  Tweets_DF %>%
  ##Todo el texto a minuscula##
  mutate(text = tolower(text)) %>% 
  ##Sin graficos##
  mutate(text = gsub("[^[:graph:]]", " ", text)) %>% 
  ##Sin links##
  mutate(text = gsub("http//S", " ", text)) %>% 
  ##Sin numeros##
  mutate(text = gsub("[[:digit:]]", " ", text)) %>% 
  ##Sin numeros##
  mutate(text = chartr('áéíóúñ','aeioun',text)) %>%
  ##Cambiamos a la zona horaria correspondiente##
  mutate(created_at = with_tz(created_at, "America/Argentina/Buenos_Aires"))%>% 
  ##Separamos en dia y hora el campo created_at##
  separate(created_at, into = c("date", "hour"), sep = " ")%>% 
  ##Separamos la hora en hora,minutos y segundos##
    separate(hour, into = c("hour", "minutes","seconds"), sep = ":")%>% 
  ##Cambiamos la columna con el nombre del politico##
   rename(Politico = screen_name) %>% 
  ##Creamos una columna con el numero de año, mes, dia, nombre de dia y de mes.##
mutate(periodo = year(date), 
         mes = month(date, label = F, 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) 
  ) %>%
  ##Solo vamos a utilizar info de marzo 2020 en adelante##
  filter(periodo == 2020 & mes > 2) 

print("Muestra")
[1] "Muestra"
print(Tweets_DF %>% 
  select(Politico, status_id, periodo, mes, dia)%>% 
    head(10))
NA

3-Normalización

Normalizamos algunos campos, para ayudar al análisis y también a la visualización.

Le agregamos el partido a cada uno de los analizados, y además cambiamos su nombre del @ que vemos en Twitter, a un nombre fácil de entender para todos

Tweets_DF <-
  Tweets_DF %>%
  mutate (Partido = ifelse (Politico == "alferdez", "Peronismo",
                    ifelse (Politico == "CFKArgentina", "Peronismo",
                    ifelse (Politico == "ginesggarcia", "Peronismo", 
                    ifelse (Politico == "Kicillofok", "Peronismo",
                    ifelse (Politico == "UCRNacional", "cuenta partidaria",        
                    ifelse (Politico == "FrenteDeTodos", "cuenta partidaria", 
                    ifelse (Politico == "proargentina", "cuenta partidaria",
                    ifelse (Politico == "PartidoGEN", "cuenta partidaria",
                    ifelse (Politico == "mauriciomacri", "PRO",
                    ifelse (Politico == "PatoBullrich", "PRO",
                    ifelse (Politico == "horaciorlarreta", "PRO",
                    ifelse (Politico == "FernanQuirosBA", "PRO", 
                            "otros candidatos")))))))))))))

Tweets_DF <-
  Tweets_DF %>%
  mutate (Politico = ifelse (Politico == "alferdez", "A.Fernandez",
                    ifelse (Politico == "CFKArgentina", "C.Kirchner",
                    ifelse (Politico == "ginesggarcia", "Gines.GG", 
                    ifelse (Politico == "Kicillofok", "A.Kicillof",
                    ifelse (Politico == "UCRNacional", "UCR",        
                    ifelse (Politico == "FrenteDeTodos", "TODOS", 
                    ifelse (Politico == "proargentina", "PRO",
                    ifelse (Politico == "PartidoGEN", "GEN",
                    ifelse (Politico == "mauriciomacri", "M.Macri",
                    ifelse (Politico == "PatoBullrich", "P.Bullrich",
                    ifelse (Politico == "horaciorlarreta", "H.Larreta",
                    ifelse (Politico == "FernanQuirosBA", "F.Quiros", 
                    ifelse (Politico == "NicolasdelCano", "N.DelCaño",
                    ifelse (Politico == "jlespert", "J.Espert",
                    ifelse (Politico == "RLavagna", "R.Lavagna",
                            "GomezCenturion"
                            ))))))))))))))))

print("Muestra")
[1] "Muestra"
print(Tweets_DF %>% 
  select(Politico, Partido, source)%>% 
    tail(10))

4-Cantidad de tweets

La primera aproximación que vamos a tener, es la cantidad de veces que twitteo cada uno desde marzo del 2020 hasta la fecha de publicación del informe.

Se presentan diferencias considerables entre todos, se deberá normalizar o utilizar proporciones más de una vez

Cantidad_tweets = Tweets_DF %>%
  group_by(Politico, Partido) %>%
  count(Politico)
  
Cantidad_tweets%>%  
  ggplot()+
  aes(x=reorder(Politico, n), y= n, fill= Politico) +
  geom_col() +
  facet_wrap("Partido", scales = "free_y") +
  coord_flip() +
  labs(title = "Cantidad total de tweets", x = "tweets", y = "Cantidad") +
    tema1

5-Fecha de los tweets

Vemos cuando han ido publicando cada uno de los analizados sus tweets, con el fin de mostrar en que época tuvieron más o menos acción.

Tweets_DF %>%
  filter(Partido == "PRO") %>%
  ggplot(aes(x = as.Date(date), fill = Politico)) +
      geom_histogram(position = "identity", bins = 20, show.legend = FALSE) +
      scale_x_date(date_labels = "%d-%m", date_breaks = "1 month") +
      labs(x = "fecha de publicación", y = "número de tweets") +
      facet_wrap(~ Politico, ncol = 1) +
      tema2 +
      theme(axis.text.x = element_text(angle = 90))


Tweets_DF %>%
  filter(Partido == "Peronismo") %>%
  ggplot(aes(x = as.Date(date), fill = Politico)) +
      geom_histogram(position = "identity", bins = 20, show.legend = FALSE) +
      scale_x_date(date_labels = "%d-%m", date_breaks = "1 month") +
      labs(x = "fecha de publicación", y = "número de tweets") +
      facet_wrap(~ Politico, ncol = 1) +
      tema1 +
      theme(axis.text.x = element_text(angle = 90))


Tweets_DF %>%
  filter(Partido == "otros candidatos") %>%
  ggplot(aes(x = as.Date(date), fill = Politico)) +
      geom_histogram(position = "identity", bins = 20, show.legend = FALSE) +
      scale_x_date(date_labels = "%d-%m", date_breaks = "1 month") +
      labs(x = "fecha de publicación", y = "número de tweets") +
      facet_wrap(~ Politico, ncol = 1) +
      tema1 +
      theme(axis.text.x = element_text(angle = 90))


Tweets_DF %>%
  filter(Partido == "cuenta partidaria") %>%
  ggplot(aes(x = as.Date(date), fill = Politico)) +
      geom_histogram(position = "identity", bins = 20, show.legend = FALSE) +
      scale_x_date(date_labels = "%d-%m", date_breaks = "1 month") +
      labs(x = "fecha de publicación", y = "número de tweets") +
      facet_wrap(~ Politico, ncol = 1) +
      tema2  +
      theme(axis.text.x = element_text(angle = 90))

6-Cantidad de tweets sobre COVID

El tema más importante del año es el coronavirus, la idea es ver qué porcentaje de los tweets realizados estos meses trato sobre el coronavirus, para eso se van a buscar palabras claves que determinen que el tweet trata sobre la pandemia.

#Buscamos tweets con la palabra covid
Palabras_covid <- "covid|covid-19|covid19|coronavirus|#covid|#covid-19|#covid19|#coronavirus|test|testeo|testeos|pcr|serologico|hisopado|antibioticos|aplanar|curva|cuarentena|contagio|enfermedad|epidemia|pandemia|alarma|gel|cuidados|incubacion|jabon|barbijo|barbijos|mascarilla|mascarillas|mers|sars|vacuna|wuhan|oxford|astra|zeneca|transmision|exponencial|casos|duplicacion|distanciamiento|colapso|salud|letalidad|mortalidad|ventilador|icu|uci|uti|inmunidad|serologica|distanciamiento|virus|asintomatico|caso sospechoso|olfato|gusto|terapia|saturacion|clinica|positividad|positivios|rebaño|inmunidad|hospital|hospitales|aspo|aislamiento"
Tweets_DF$Covid <- grepl(Palabras_covid, Tweets_DF$text, ignore.case ="True")

Tweets_DF %>% 
count(Politico, Partido,Covid) %>%
  group_by(Politico) %>%
  mutate(Proporcion = n / sum(n)) %>%
  mutate(Covid = ifelse(Covid == T, "Sobre COVID", "Otro tema"))%>%
ggplot() +
  aes(Politico, Proporcion, fill = Covid) +
  geom_col() +
  scale_y_continuous(labels = percent_format()) +
      facet_wrap("Partido", scales = "free") +
  theme(legend.position = "top")

7- Wordcloud

La idea de la nube de palabras es saber cuáles son las 200 palabras que más se usaron por los analizados estos meses, como era de esperarse sobresalen “coronavirus”, “covid”, “pandemia” o “cuarentena”

tuits_tokens <-
  Tweets_DF %>%
  unnest_tokens(input = text, output = Palabra, token = "words") %>%
  select(Politico, Palabra, status_id, periodo, mes, hour, Partido) %>%
  mutate(status_id = gsub("<(.*)>+?", "", status_id)) %>%
  filter(!Palabra %in% stopwords("es")) %>%
  filter(!Palabra %in% c("t.co", "https", "vía", "youtube", "amp"))

Palabras_sinhoymas = tuits_tokens  %>%
  filter(Palabra != "mas" & Palabra != "hoy") 

wordcloud(words = Palabras_sinhoymas$Palabra, 
          scale=c(2,.2), 
          max.words=200, random.order=FALSE, rot.per=0.35, 
          colors=brewer.pal(8, "Dark2"),
          )
transformation drops documentstransformation drops documents

8-Descargamos un diccionario

Descargamos un diccionario que tiene las palabras en español, y le asigna un valor entre -5 a 5, mostrando la positividad o negatividad de la palabra.

Eliminamos la palabra “No” que la toma como negativa, cuando en español es un conector a veces, y la palabra “Negro” (Nigga) que la toma con el máximo valor negativo

download.file("https://raw.githubusercontent.com/jboscomendoza/rpubs/master/sentimientos_afinn/lexico_afinn.en.es.csv",
              "lexico_afinn.en.es.csv")
probando la URL 'https://raw.githubusercontent.com/jboscomendoza/rpubs/master/sentimientos_afinn/lexico_afinn.en.es.csv'
Content type 'text/plain; charset=utf-8' length 51625 bytes (50 KB)
downloaded 50 KB
afinn <- read.csv("lexico_afinn.en.es.csv", stringsAsFactors = F, fileEncoding = "latin1") %>% 
  tbl_df()

afinn$Puntuacion <- ifelse(afinn$Palabra == "no", 0, afinn$Puntuacion)
afinn$Puntuacion <- ifelse(afinn$Palabra == "negro", 0, afinn$Puntuacion)

print("Muestra")
[1] "Muestra"
afinn %>%
  select(Palabra, Puntuacion) %>%
    arrange(Puntuacion) %>%
  print(head(10))

afinn %>%
  select(Palabra, Puntuacion) %>%
    arrange(-Puntuacion) %>%
  print(tail(10))

9- Separacion de palabras

Separamos las distintas palabras que usaron cada uno de los políticos en sus tweets, y eliminamos algunas palabras propias de Twitter y las llamadas stopwords que son las palabras más frecuentes en el idioma español.

print ("Muestra")
[1] "Muestra"
print (tuits_tokens %>%
    select(Politico, Palabra) %>%    
         head (10))

10- Le damos valor a las palabras

Unimos el diccionario de puntuación con las palabras que uso cada uno de los analizados, con el fin de que cada palabra tenga un valor, y nos sirva para analizar que escribió cada político.

Las palabras serán: - Si tienen valor mayor a 0 Positivas

tuits_tokens_emociones <-   
 tuits_tokens %>%
inner_join(afinn, ., by = "Palabra") %>%
  mutate(Calificacion = ifelse(Puntuacion > 0, "Positiva", 
                              ifelse(Puntuacion == 0, "Neutral",
                              "Negativa")
                            )
  )      

print ("Muestra")
[1] "Muestra"
print (tuits_tokens_emociones %>%
    select(Politico, Palabra, Puntuacion, Calificacion) %>%    
         tail (10))

11- ¿Quién usa más caracteres?

La idea es buscar cual es el promedio del largo (cantidad de caracteres) de los tweets que realiza cada uno de los analizados.

Mientras más a la derecha este la caja, más largo son los tweets que escriben, en ese aspecto se destacan: - Lavagna, Patricia Bullrich, Larreta y Fernán Quirós son los que escriben los tweets más largos. - Aquellos relacionados al PRO son de escribir tweets más largos

Tweets_DF %>% 
ggplot()+
  aes(x= Politico, y= display_text_width, color= Politico) +
  geom_boxplot () +
    labs(title = "Largo promedio del tweet", x = "Politico", y = "Cantidad caracteres") +
  coord_flip() +
    tema1

12- ¿Quién usa más palabras?

La idea es analizar quien es el que uso más palabras distintas en promedio durante este tiempo, en este caso vamos a dividir por la cantidad de tweets que hizo, así queda normalizado para todos los analizados.

No se cuentan los conectores comunes como “en”, “a”, “de”, etc.

Cantidad_palabras= tuits_tokens%>%
  group_by(Politico, Partido)%>%
  count(Politico)%>%
inner_join(Cantidad_tweets, ., by = "Politico")%>%
  mutate(cantidad_promedio = n.y / n.x)


Cantidad_palabras%>% ggplot()+
  aes(x=reorder(Politico, -cantidad_promedio), y= cantidad_promedio, fill= Politico) +
  geom_col() +
  facet_wrap("Partido.x", scales = "free_y") +
  labs(title = "Uso de palabras", x = "tweets", y = "Cantidad") +
  coord_flip() +
    tema1

NA
NA

13- ¿Quien usa mas palabras distintas?

Buscamos ver el léxico distintivo que hay en cada una de las cuentas, contando sus palabras únicas y se nota:

tuits_tokens%>%
  group_by(Politico, Partido)%>%
  distinct(Palabra)%>%
  count(Politico)%>%
inner_join(Cantidad_tweets, ., by = "Politico")  %>%
  mutate(cantidad_promedio = n.y / n.x) %>% 
  ggplot()+
  aes(x=reorder(Politico, cantidad_promedio), y= cantidad_promedio, fill= Politico) +
  geom_col() +
  facet_wrap("Partido.x", scales = "free_y") +
  labs(title = "Palabras distintas", x = "tweets", y = "Cantidad") +
  coord_flip() +
    tema1

NA

14- Palabras más usadas

Ahora que ya sabemos con qué variedad de palabras, podemos analizar cuáles son las que más usaron En este caso, cada grafico tiene una escala distinta para que no se pierda por la cantidad de tweets realizados.

Las palabras más utilizadas fueron:

tuits_tokens_emociones %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "PRO") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras más usadas") +
     tema1


 tuits_tokens_emociones %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "Peronismo") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras más usadas") +
     tema1

 
  tuits_tokens_emociones %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "otros candidatos") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras más usadas") +
     tema1

  
   tuits_tokens_emociones %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "cuenta partidaria") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras más usadas") +
     tema1

15- Palabras positivas más usadas

Al tener una puntuación cada palabra otorgada por el diccionario de léxico, también podemos buscar cuales son las palabras positivas que más uso cada uno de los políticos.

En este caso:

 tuits_tokens_emociones %>%
    filter(Calificacion ==  "Positiva") %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "PRO") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras Positivas más usadas") 


 tuits_tokens_emociones %>%
    filter(Calificacion ==  "Positiva") %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "Peronismo") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras Positivas más usadas") 

 
  tuits_tokens_emociones %>%
    filter(Calificacion ==  "Positiva") %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "otros candidatos") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras Positivas más usadas") 

  
   tuits_tokens_emociones %>%
    filter(Calificacion ==  "Positiva") %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "cuenta partidaria") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras Positivas más usadas") 

16- Palabras negativas más usadas

Al tener una puntuación cada palabra otorgada por el diccionario de léxico, también podemos buscar cuales son las palabras negativas que más uso cada uno de los políticos.

 tuits_tokens_emociones %>%
    filter(Calificacion ==  "Negativa") %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "PRO") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras Negativas más usadas") 


 tuits_tokens_emociones %>%
    filter(Calificacion ==  "Negativa") %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "Peronismo") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras Negativas más usadas") 

 
  tuits_tokens_emociones %>%
    filter(Calificacion ==  "Negativa") %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "otros candidatos") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras Negativas más usadas") 

  
   tuits_tokens_emociones %>%
    filter(Calificacion ==  "Negativa") %>%
    group_by(Partido, Politico) %>%
    count(Palabra, sort = T) %>%
     slice_max(order_by = n, n= 10) %>%
      filter(Partido ==  "cuenta partidaria") %>%
    ggplot() +
    aes(Palabra, n, fill = Politico) +
    geom_col() +
    facet_wrap("Politico", scales = "free") +
    scale_y_continuous(expand = c(0, 0)) +
    coord_flip() +
    labs(title = "Palabras Negativas más usadas") 

17- Sentimientos en el tweet

Volviendo a usar la puntuación del diccionario afinn, volvemos a unir las palabras a los tweets y sacamos el promedio de puntos de todas las palabras, pasando del valor unitario de palabra a un valor unitario por cada tweet publicado.

Tweets_DF <-
  tuits_tokens_emociones %>%
  group_by(status_id) %>%
  summarise(Puntuacion_tweet.x = mean(Puntuacion)) %>%
  left_join(Tweets_DF, ., by = "status_id")
`summarise()` ungrouping output (override with `.groups` argument)
Tweets_DF <-  Tweets_DF %>%
  mutate(Puntuacion_tweet.x_letra = ifelse(is.na(Puntuacion_tweet.x), "Neutral",
                                   ifelse(Puntuacion_tweet.x > 0, "Positiva", 
                                    ifelse(Puntuacion_tweet.x == 0, "Neutral",
                              "Negativa")
                            )
  )      
)

Tweets_DF %>%
  count(Politico, Partido, Puntuacion_tweet.x_letra) %>%
  group_by(Politico) %>%
  mutate(Proporcion = n / sum(n)) %>%
ggplot() +
  aes(Politico, Proporcion, fill = Puntuacion_tweet.x_letra) +
  geom_col() +
  scale_y_continuous(labels = percent_format()) +
      facet_wrap("Partido", scales = "free") +
  theme(legend.position = "top")

NA
NA

18- Sentimientos en el tweet PRO vs Peronismo

Tomamos los 4 miembros que ya analizamos de cada uno de los partidos (PRO y Todos), y lo unimos en un solo gráfico por partido, vemos que la distribución es algo parecido, si bien el Peronismo tuvo un poco más de tweets positivos y menos de tweets negativos, pero no a niveles significativos.

Tweets_DF %>%
  count(Partido, Puntuacion_tweet.x_letra) %>%
  group_by(Partido) %>%
  filter(Partido == "PRO" |Partido == "Peronismo")%>%
  mutate(Proporcion = n / sum(n)) %>%
ggplot() +
  aes(Partido, Proporcion, fill = Puntuacion_tweet.x_letra) +
  geom_col() +
  scale_y_continuous(labels = percent_format()) +
  theme(legend.position = "top")

19- Sentimiento mes a mes

La idea es analizar si hay fluctuaciones en lo que han ido twitteando en el transcurso del tiempo y sus sentimientos.

Tweets_DF$Puntuacion_tweet.x = ifelse(is.na(Tweets_DF$Puntuacion_tweet.x), 0, Tweets_DF$Puntuacion_tweet.x)

Tweets_DF %>%
group_by(Politico, Partido, mes) %>%
  filter(Partido == "PRO")%>%
  summarise(sentimiento = mean(Puntuacion_tweet.x)) %>%
ggplot() +
  aes(mes, sentimiento, color = Politico) +
  geom_hline(yintercept = 0, alpha = .35) +
  geom_line() +
  facet_grid(Politico~.) +
  tema1 +
  theme(legend.position = "none")
`summarise()` regrouping output by 'Politico', 'Partido' (override with `.groups` argument)

Tweets_DF %>%
group_by(Politico, Partido, mes) %>%
  filter(Partido == "otros candidatos")%>%
  summarise(sentimiento = mean(Puntuacion_tweet.x)) %>%
ggplot() +
  aes(mes, sentimiento, color = Politico) +
  geom_hline(yintercept = 0, alpha = .35) +
  geom_line() +
  facet_grid(Politico~.) +
  tema1 +
  theme(legend.position = "none")
`summarise()` regrouping output by 'Politico', 'Partido' (override with `.groups` argument)

Tweets_DF %>%
group_by(Politico, Partido, mes) %>%
  filter(Partido == "Peronismo")%>%
  summarise(sentimiento = mean(Puntuacion_tweet.x)) %>%
ggplot() +
  aes(mes, sentimiento, color = Politico) +
  geom_hline(yintercept = 0, alpha = .35) +
  geom_line() +
  facet_grid(Politico~.) +
  tema1 +
  theme(legend.position = "none")
`summarise()` regrouping output by 'Politico', 'Partido' (override with `.groups` argument)

Tweets_DF %>%
group_by(Politico, Partido, mes) %>%
  filter(Partido == "cuenta partidaria")%>%
  summarise(sentimiento = mean(Puntuacion_tweet.x)) %>%
ggplot() +
  aes(mes, sentimiento, color = Politico) +
  geom_hline(yintercept = 0, alpha = .35) +
  geom_line() +
  facet_grid(Politico~.) +
  tema1 +
  theme(legend.position = "none")
`summarise()` regrouping output by 'Politico', 'Partido' (override with `.groups` argument)

20- Boxplot sentimientos

La distribución de los sentimientos entre todos los tweets, aquellos que están encerrados en las cajas son los normales, mientras que los puntos sueltos son tweets aislados a lo que suelen escribir.

Tweets_DF %>%
  ggplot() +
  aes(Politico, Puntuacion_tweet.x, fill = Politico) +
  geom_boxplot() +
  coord_flip() + 
  labs(y= "Sentimiento") +
  tema1

21- Correlación entre lo twitteado PRO vs Peronismo

Se busca a través de las palabras que utilizaron cual es la correlación que hay entre los distintos políticos y sus tweets, y se pueden realizar varias observaciones:

tweets_spread2 <- tuits_tokens %>% 
 filter(Partido ==  "PRO" | Partido == "Peronismo")%>% 
  group_by(Politico, Palabra) %>% 
  count(Palabra) %>%
      spread(key = Politico, value = n, fill = NA, drop = TRUE)
tweets_spread2[is.na(tweets_spread2)] <- 0

names(tweets_spread2) <- c("Palabra", "A.Fernandez", "A.Kicillof", 
                          "C.Kirchner", "F.Quiros", "Gines.GG","H.Larreta", "M.Macri", "P.Bullrich" )

method <- "pearson"
m_cor <- matrix(nrow = 8, ncol = 8)
for (i in 1:dim(m_cor)[1]) {
      for (j in 1:dim(m_cor)[2]) {
            form <- as.formula(paste("~", names(tweets_spread2)[i+1], 
                                      "+", names(tweets_spread2)[j+1]))
            if(i!=j){
                  m_cor[i,j] <- cor.test(form, method = method, 
                                   data = tweets_spread2)$estimate
            }
            if(i==j){m_cor[i,j] <- 1}
      }
}
colnames(m_cor) <- names(tweets_spread2)[2:9]
rownames(m_cor) <- names(tweets_spread2)[2:9]
corrplot(m_cor, method="color", type="upper", order="hclust", 
         addCoef.col = "black", tl.col="black", tl.srt=45,
         sig.level = 0.01, insig = "blank", diag=FALSE)

22- Correlación entre lo twitteado candidatos a presidente.

tweets_spread2 <- tuits_tokens %>% 
  filter(Partido ==  "otros candidatos" | Politico == "A.Fernandez"| Politico == "M.Macri")%>% 
  group_by(Politico, Palabra) %>% 
  count(Palabra) %>%
      spread(key = Politico, value = n, fill = NA, drop = TRUE)
tweets_spread2[is.na(tweets_spread2)] <- 0

names(tweets_spread2) <- c("Palabra", "A.Fernandez", "J.Espert", 
                          "GomezCenturion", "M.Macri", "N.DelCaño","R.Lavagna")

method <- "pearson"
m_cor <- matrix(nrow = 6, ncol = 6)
for (i in 1:dim(m_cor)[1]) {
      for (j in 1:dim(m_cor)[2]) {
            form <- as.formula(paste("~", names(tweets_spread2)[i+1], 
                                      "+", names(tweets_spread2)[j+1]))
            if(i!=j){
                  m_cor[i,j] <- cor.test(form, method = method, 
                                   data = tweets_spread2)$estimate
            }
            if(i==j){m_cor[i,j] <- 1}
      }
}
colnames(m_cor) <- names(tweets_spread2)[2:7]
rownames(m_cor) <- names(tweets_spread2)[2:7]
corrplot(m_cor, method="color", type="upper", order="hclust", 
         addCoef.col = "black", tl.col="black", tl.srt=45,
         sig.level = 0.01, insig = "blank", diag=FALSE)

23- Correlación entre lo twitteado entre cuentas partidarias

Este puede ser un análisis interesante, ya que la cantidad de tweets es significativa para todos.

tweets_spread2 <- tuits_tokens %>% 
  filter(Partido ==  "cuenta partidaria")%>% 
  group_by(Politico, Palabra) %>% 
  count(Palabra) %>%
      spread(key = Politico, value = n, fill = NA, drop = TRUE)
tweets_spread2[is.na(tweets_spread2)] <- 0

names(tweets_spread2) <- c("Palabra", "GEN", "PRO", 
                          "TODOS", "UCR")

method <- "pearson"
m_cor <- matrix(nrow = 4, ncol = 4)
for (i in 1:dim(m_cor)[1]) {
      for (j in 1:dim(m_cor)[2]) {
            form <- as.formula(paste("~", names(tweets_spread2)[i+1], 
                                      "+", names(tweets_spread2)[j+1]))
            if(i!=j){
                  m_cor[i,j] <- cor.test(form, method = method, 
                                   data = tweets_spread2)$estimate
            }
            if(i==j){m_cor[i,j] <- 1}
      }
}
colnames(m_cor) <- names(tweets_spread2)[2:5]
rownames(m_cor) <- names(tweets_spread2)[2:5]
corrplot(m_cor, method="color", type="upper", order="hclust", 
         addCoef.col = "black", tl.col="black", tl.srt=45,
         sig.level = 0.01, insig = "blank", diag=FALSE)

24- Comparación de uso de palabras Macri vs Fernandez

La idea de este gráfico es de mostrar cuales son las palabras más diferencias en su uso, en este caso entre Mauricio Macri y Alberto Fernández


# Pivotaje y despivotaje
tweets_unpivot <- tuits_tokens %>% group_by(Politico, Palabra) %>%
      count(Palabra) %>%
      spread(key = Politico, value = n, fill = 0, drop = TRUE) %>% 
      gather(key = "Politico", value = "n", -Palabra)

                  # Selección de los autores
                  tweets_unpivot2 <- tweets_unpivot %>% 
                        filter(Politico %in% c("M.Macri", "A.Fernandez"))
                  # Se añade el total de palabras de cada autor
                  tweets_unpivot2 <- tweets_unpivot2 %>%
                        left_join(Tweets_DF %>% group_by(Politico) %>%
                                        summarise(N = n()), by = "Politico")
`summarise()` ungrouping output (override with `.groups` argument)
                  # Cálculo de odds y log of odds de cada palabra
                  tweets_logOdds <- tweets_unpivot2 %>% 
                        mutate(odds = (n + 1) / (N + 1)) %>%
                        select(Politico, Palabra, odds) %>% 
                        spread(key = Politico, value = odds)
                  tweets_logOdds[,4] <- log(tweets_logOdds[,2]/tweets_logOdds[,3])
                  names(tweets_logOdds)[4] <- "log_odds"
                  tweets_logOdds[,5] <- abs(tweets_logOdds$log_odds)
                  names(tweets_logOdds)[5] <- "abs_log_odds"
                  tweets_logOdds <- tweets_logOdds %>%
                        mutate(autor_frecuente = if_else(log_odds > 0,
                                                         names(tweets_logOdds)[2],
                                                         names(tweets_logOdds)[3]))

Diferencia_AF <- tweets_logOdds %>% 
  arrange(-abs_log_odds, bygroup = FALSE)%>% 
  filter(autor_frecuente == "A.Fernandez")%>% 
  head(15)

Diferencia_MM <- tweets_logOdds %>% 
  arrange(log_odds, bygroup = FALSE)%>% 
  filter(autor_frecuente == "M.Macri")%>% 
  head(15)

Diferencia_AF_MM <- rbind(Diferencia_AF,Diferencia_MM)

Diferencia_AF_MM%>% 
    ggplot(aes(x = reorder(Palabra, log_odds), y= log_odds, fill = autor_frecuente)) +
    geom_col() +
    labs(x = "-palabra", y = "Uso", title = "Fernandez vs Macri") +
  coord_flip() +
  tema2

25- Comparación de uso de palabras Larreta vs Kicillof

La idea de este gráfico es de mostrar cuales son las palabras más diferencias en su uso, en este caso entre Horacio Larreta y Axel Kicillof



# Pivotaje y despivotaje
tweets_unpivot <- tuits_tokens %>% group_by(Politico, Palabra) %>%
      count(Palabra) %>%
      spread(key = Politico, value = n, fill = 0, drop = TRUE) %>% 
      gather(key = "Politico", value = "n", -Palabra)

                  # Selección de los autores
                  tweets_unpivot2 <- tweets_unpivot %>% 
                        filter(Politico %in% c("H.Larreta", "A.Kicillof"))
                  # Se añade el total de palabras de cada autor
                  tweets_unpivot2 <- tweets_unpivot2 %>%
                        left_join(Tweets_DF %>% group_by(Politico) %>%
                                        summarise(N = n()), by = "Politico")
`summarise()` ungrouping output (override with `.groups` argument)
                  # Cálculo de odds y log of odds de cada palabra
                  tweets_logOdds <- tweets_unpivot2 %>% 
                        mutate(odds = (n + 1) / (N + 1)) %>%
                        select(Politico, Palabra, odds) %>% 
                        spread(key = Politico, value = odds) 
                  tweets_logOdds[,4] <- log(tweets_logOdds[,2]/tweets_logOdds[,3])
                  names(tweets_logOdds)[4] <- "log_odds"
                  tweets_logOdds[,5] <- abs(tweets_logOdds$log_odds)
                  names(tweets_logOdds)[5] <- "abs_log_odds"
                  tweets_logOdds <- tweets_logOdds %>%
                        mutate(autor_frecuente = if_else(log_odds > 0,
                                                         names(tweets_logOdds)[2],
                                                         names(tweets_logOdds)[3]))

Diferencia_AK <- tweets_logOdds %>% 
  arrange(-log_odds, bygroup = FALSE)%>% 
  filter(autor_frecuente == "A.Kicillof")%>% 
  head(15)

Diferencia_HL <- tweets_logOdds %>% 
  arrange(abs_log_odds, bygroup = FALSE)%>% 
  filter(autor_frecuente == "H.Larreta")%>% 
  tail(15)

Diferencia_AK_HL <- rbind(Diferencia_AK,Diferencia_HL)

Diferencia_AK_HL%>% 
    ggplot(aes(x = reorder(Palabra, log_odds), y= log_odds, fill = autor_frecuente)) +
    geom_col() +
    labs(x = "-palabra", y = "Uso", title = "Kicillof vs Larreta") +
  coord_flip() +
  tema2

26- Comparación de uso de palabras Gines vs Quirós

La idea de este gráfico es de mostrar cuales son las palabras más diferencias en su uso, en este caso entre Gines Gonzalez y Fernán Quirós

tweets_unpivot <- tuits_tokens %>% group_by(Politico, Palabra) %>%
      count(Palabra) %>%
      spread(key = Politico, value = n, fill = 0, drop = TRUE) %>% 
      gather(key = "Politico", value = "n", -Palabra)

                  # Selección de los autores
                  tweets_unpivot2 <- tweets_unpivot %>% 
                        filter(Politico %in% c("Gines.GG", "F.Quiros"))
                  # Se añade el total de palabras de cada autor
                  tweets_unpivot2 <- tweets_unpivot2 %>%
                        left_join(Tweets_DF %>% group_by(Politico) %>%
                                        summarise(N = n()), by = "Politico")
`summarise()` ungrouping output (override with `.groups` argument)
                  # Cálculo de odds y log of odds de cada palabra
                  tweets_logOdds <- tweets_unpivot2 %>% 
                        mutate(odds = (n + 1) / (N + 1)) %>%
                        select(Politico, Palabra, odds) %>% 
                        spread(key = Politico, value = odds) 
                  tweets_logOdds[,4] <- log(tweets_logOdds[,2]/tweets_logOdds[,3])
                  names(tweets_logOdds)[4] <- "log_odds"
                  tweets_logOdds[,5] <- abs(tweets_logOdds$log_odds)
                  names(tweets_logOdds)[5] <- "abs_log_odds"
                  tweets_logOdds <- tweets_logOdds %>%
                        mutate(autor_frecuente = if_else(log_odds > 0,
                                                         names(tweets_logOdds)[2],
                                                         names(tweets_logOdds)[3]))

Diferencia_GG <- tweets_logOdds %>% 
  arrange(-log_odds, bygroup = FALSE)%>% 
  filter(autor_frecuente == "Gines.GG")%>% 
  tail(15)

Diferencia_FQ <- tweets_logOdds %>% 
  arrange(-abs_log_odds, bygroup = FALSE)%>% 
  filter(autor_frecuente == "F.Quiros")%>% 
  head(15)

Diferencia_GG_FQ <- rbind(Diferencia_GG,Diferencia_FQ)

Diferencia_GG_FQ%>% 
    ggplot(aes(x = reorder(Palabra, log_odds), y= log_odds, fill = autor_frecuente)) +
    geom_col() +
    labs(x = "-palabra", y = "Uso", title = "Quirós vs Gines") +
  coord_flip() +
  tema2

27- Comparación de uso de palabras Bullrich vs Cristina

La idea de este gráfico es de mostrar cuales son las palabras más diferencias en su uso, en este caso entre Cristina Kirchner y Patricia Bullrich

tweets_unpivot <- tuits_tokens %>% group_by(Politico, Palabra) %>%
      count(Palabra) %>%
      spread(key = Politico, value = n, fill = 0, drop = TRUE) %>% 
      gather(key = "Politico", value = "n", -Palabra)

                  # Selección de los autores
                  tweets_unpivot2 <- tweets_unpivot %>% 
                        filter(Politico %in% c("P.Bullrich", "C.Kirchner"))
                  # Se añade el total de palabras de cada autor
                  tweets_unpivot2 <- tweets_unpivot2 %>%
                        left_join(Tweets_DF %>% group_by(Politico) %>%
                                        summarise(N = n()), by = "Politico")
`summarise()` ungrouping output (override with `.groups` argument)
                  # Cálculo de odds y log of odds de cada palabra
                  tweets_logOdds <- tweets_unpivot2 %>% 
                        mutate(odds = (n + 1) / (N + 1)) %>%
                        select(Politico, Palabra, odds) %>% 
                        spread(key = Politico, value = odds) 
                  tweets_logOdds[,4] <- log(tweets_logOdds[,2]/tweets_logOdds[,3])
                  names(tweets_logOdds)[4] <- "log_odds"
                  tweets_logOdds[,5] <- abs(tweets_logOdds$log_odds)
                  names(tweets_logOdds)[5] <- "abs_log_odds"
                  tweets_logOdds <- tweets_logOdds %>%
                        mutate(autor_frecuente = if_else(log_odds > 0,
                                                         names(tweets_logOdds)[2],
                                                         names(tweets_logOdds)[3]))

Diferencia_PB <- tweets_logOdds %>% 
  arrange(-log_odds, bygroup = FALSE)%>% 
  filter(autor_frecuente == "P.Bullrich")%>% 
  tail(15)

Diferencia_CFK <- tweets_logOdds %>% 
  arrange(-abs_log_odds, bygroup = FALSE)%>% 
  filter(autor_frecuente == "C.Kirchner")%>% 
  head(15)

Diferencia_PB_CFK <- rbind(Diferencia_PB,Diferencia_CFK)

Diferencia_PB_CFK%>% 
    ggplot(aes(x = reorder(Palabra, log_odds), y= log_odds, fill = autor_frecuente)) +
    geom_col() +
    labs(x = "-palabra", y = "Uso", title = "Cristina vs Bullrich") +
  coord_flip() +
  tema2

28- Emociones en los tweets

Ahora analizamos un campo más amplio de emociones que fueron usado por los distintos políticos entre todos los tweets que han ido publicando en este periodo.

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, sentiment) %>%
  filter(Partido ==  "cuenta partidaria")%>%
  filter(sentiment != "Positivo" & sentiment !="Negativo")%>%
    summarise(Total = sum(values)) %>%
      mutate(Proporcion = Total / sum(Total)) %>%
ggplot() +
  aes(Politico, Proporcion, fill = sentiment) +
  geom_col(position = "stack", color = "black") +
  coord_flip()  +
  scale_y_continuous(expand = c(0,0)) +
  labs(y = "Palabras") +
  theme_minimal()
`summarise()` regrouping output by 'Politico', 'Partido' (override with `.groups` argument)


gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, sentiment) %>%
  filter(Partido ==  "PRO")%>%
  filter(sentiment != "Positivo" & sentiment !="Negativo")%>%
    summarise(Total = sum(values)) %>%
      mutate(Proporcion = Total / sum(Total)) %>%
ggplot() +
  aes(Politico, Proporcion, fill = sentiment) +
  geom_col(position = "stack", color = "black") +
  coord_flip()  +
  scale_y_continuous(expand = c(0,0)) +
  labs(y = "Palabras") +
  theme_minimal()
`summarise()` regrouping output by 'Politico', 'Partido' (override with `.groups` argument)

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, sentiment) %>%
  filter(Partido ==  "Peronismo")%>%
  filter(sentiment != "Positivo" & sentiment !="Negativo")%>%
    summarise(Total = sum(values)) %>%
      mutate(Proporcion = Total / sum(Total)) %>%
ggplot() +
  aes(Politico, Proporcion, fill = sentiment) +
  geom_col(position = "stack", color = "black") +
  coord_flip()  +
  scale_y_continuous(expand = c(0,0)) +
  labs(y = "Palabras") +
  theme_minimal()
`summarise()` regrouping output by 'Politico', 'Partido' (override with `.groups` argument)

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, sentiment) %>%
  filter(Partido ==  "otros candidatos")%>%
  filter(sentiment != "Positivo" & sentiment !="Negativo")%>%
    summarise(Total = sum(values)) %>%
      mutate(Proporcion = Total / sum(Total)) %>%
ggplot() +
  aes(Politico, Proporcion, fill = sentiment) +
  geom_col(position = "stack", color = "black") +
  coord_flip()  +
  scale_y_continuous(expand = c(0,0)) +
  labs(y = "Palabras") +
  theme_minimal()
`summarise()` regrouping output by 'Politico', 'Partido' (override with `.groups` argument)

29- Emociones mes a mes

Si bien no hay grandes cambios a la hora de hacer los análisis de sentimientos mes a mes, se nota algunos detalles:

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, mes, sentiment) %>%
  filter(Partido ==  "cuenta partidaria")%>%
  filter(sentiment != "Positivo" & sentiment !="Negativo")%>%
    summarise(Total = sum(values)) %>%
      mutate(Proporcion = Total / sum(Total)) %>%
ggplot() +
aes(x = mes, y =Proporcion, color = sentiment) +
  geom_point() +
  geom_line(aes(group = sentiment)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = .4), 
        text = element_text(family = "serif")) +
  tema2 +
  facet_wrap(~ Politico) +
  labs(title = "Cambio de los sentimientos en el tiempo", 
       x = "Mes", y = "Porporción", color = "Sentimiento") 
`summarise()` regrouping output by 'Politico', 'Partido', 'mes' (override with `.groups` argument)

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, mes, sentiment) %>%
  filter(Partido ==  "otros candidatos")%>%
  filter(sentiment != "Positivo" & sentiment !="Negativo")%>%
    summarise(Total = sum(values)) %>%
      mutate(Proporcion = Total / sum(Total)) %>%
ggplot() +
aes(x = mes, y =Proporcion, color = sentiment) +
  geom_point() +
  geom_line(aes(group = sentiment)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = .4), 
        text = element_text(family = "serif")) +
  tema2 +
  facet_wrap(~ Politico) +
  labs(title = "Cambio de los sentimientos en el tiempo", 
       x = "Mes", y = "Porporción", color = "Sentimiento") 
`summarise()` regrouping output by 'Politico', 'Partido', 'mes' (override with `.groups` argument)

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, mes, sentiment) %>%
  filter(Partido ==  "Peronismo")%>%
  filter(sentiment != "Positivo" & sentiment !="Negativo")%>%
    summarise(Total = sum(values)) %>%
      mutate(Proporcion = Total / sum(Total)) %>%
ggplot() +
aes(x = mes, y =Proporcion, color = sentiment) +
  geom_point() +
  geom_line(aes(group = sentiment)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = .4), 
        text = element_text(family = "serif")) +
  tema2 +
  facet_wrap(~ Politico) +
  labs(title = "Cambio de los sentimientos en el tiempo", 
       x = "Mes", y = "Porporción", color = "Sentimiento") 
`summarise()` regrouping output by 'Politico', 'Partido', 'mes' (override with `.groups` argument)

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, mes, sentiment) %>%
  filter(Partido ==  "PRO")%>%
  filter(sentiment != "Positivo" & sentiment !="Negativo")%>%
    summarise(Total = sum(values)) %>%
      mutate(Proporcion = Total / sum(Total)) %>%
ggplot() +
aes(x = mes, y =Proporcion, color = sentiment) +
  geom_point() +
  geom_line(aes(group = sentiment)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = .4), 
        text = element_text(family = "serif")) +
  tema2 +
  facet_wrap(~ Politico) +
  labs(title = "Cambio de los sentimientos en el tiempo", 
       x = "Mes", y = "Porporción", color = "Sentimiento") 
`summarise()` regrouping output by 'Politico', 'Partido', 'mes' (override with `.groups` argument)

30- Comparación de emociones

La idea de comparar las emociones de todos en un gráfico ayuda para una visualización general (eliminando las cuentas partidarias):

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, sentiment) %>%
  filter(sentiment != "Positivo" & sentiment !="Negativo" & Partido != "cuenta partidaria")%>%
    summarise(Total = sum(values)) %>%
      mutate(Proporcion = Total / sum(Total)) %>%
    ggplot() +
  aes(Politico, Proporcion, color = sentiment, alpha = Proporcion) +
  geom_point(fill = "white", stroke = 1, shape = 21) +
  geom_text(aes(label = sentiment), vjust = -.9, family = "serif") +
  scale_y_continuous(labels = percent_format ()) +
  tema1 +
  theme(legend.position = "none",
        panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank(),
        text =  element_text(family = "serif")) +
  coord_flip() +
  labs(title = "Sentimientos totales comparativo",
       x = "Politico",
       y = "Proporción del sentimiento")
`summarise()` regrouping output by 'Politico', 'Partido' (override with `.groups` argument)

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, sentiment) %>%
  filter(sentiment != "Positivo" & sentiment !="Negativo" & sentiment !="Alegria" & sentiment !="Sorpresa" & Partido != "cuenta partidaria")%>%
    summarise(Total = sum(values)) %>%
      mutate(Proporcion = Total / sum(Total)) %>%
  ggplot() +
  aes(sentiment, Proporcion, color = sentiment) +
  geom_point() +
  geom_text(aes(label = Politico) ,vjust = -.3, size = 3) +
  scale_y_continuous(limits = c(0.15, 0.47)) +
   labs(title = "Sentimientos totales comparativo",
       x = "Politico",
       y = "Proporción del sentimiento") +
  theme_minimal() +
  theme(legend.position = "none")
`summarise()` regrouping output by 'Politico', 'Partido' (override with `.groups` argument)

LS0tDQp0aXRsZTogIkFuYWxpc2lzIGRlIHR3aXR0ZXI6IFBvbMOtdGljb3MgZW4gY3VhcmVudGVuYSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzAyMTgyQjsiPiA8aDI+IEFuw6FsaXNpcyBkZSBwb2zDrXRpY29zIDwvaDI+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDEtIERlc2NhcmdhciB0d2VldHMgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KQ3JlbyB1bmEgbGlzdGEgZGUgY3VlbnRhcyBkZSBsYXMgY3VhbGVzIHZveSBhIGRlc2NhcmdhciBzdXMgdHdlZXRzLCB5IGFkZW3DoXMgdW5hIGFzaWduYWNpw7NuIHBhcmEgc2FiZXIgYSBxdWnDqW4gcmVwcmVzZW50YSBjYWRhIGN1ZW50YS4NCg0KTGEgaWRlYSBvcmlnaW5hbCBlcyB0ZW5lciA0IG1pZW1icm9zIGRlIGNhZGEgdW5vIGRlIGxvcyBkb3MgcGFydGlkb3MgcHJpbmNpcGFsZXMsIGxvcyDDumx0aW1vcyA0IGNhbmRpZGF0b3MgZW4gbGFzIGVsZWNjaW9uZXMgMjAxOSB5IHRhbWJpw6luIGxhcyA0IGN1ZW50YXMgcGFydGlkYXJpYXMgZW4gVHdpdHRlci4NCg0KICAtICoqRnJlbnRlIGRlIHRvZG9zKio6ICpBbGJlcnRvIEZlcm7DoW5kZXosIENyaXN0aW5hIEtpcmNobmVyLCBHaW5lcyBHb256w6FsZXogR2FyY8OtYSB5IEF4ZWwgS2ljaWxsb2YqDQogIC0gKipQUk8qKjogKk1hdXJpY2lvIE1hY3JpLCBIb3JhY2lvIFJvZHLDrWd1ZXogTGFycmV0YSwgRmVybsOhbiBRdWlyb3ogeSBQYXRyaWNpYSBCdWxscmljaCoNCiAgLSAqKk90cm9zIGNhbmRpZGF0b3MqKjogKkpvc8OpIEx1aXMgRXNwZXJ0LCBSb2JlcnRvIExhdmFnbmEsIEp1YW4gSm9zw6kgR8OzbWV6IENlbnR1cmnDs24geSBOaWNvbGFzIGRlbCBDYcOxbyoNCiAgLSAqKlBhcnRpZGFyaWFzKio6ICpGcmVudGUgZGUgVG9kb3MsIFBSTywgR0VOIHkgVW5pw7NuIEPDrXZpY2EgUmFkaWNhbCoNCg0KYGBge3J9DQpjYW5kaWRhdG9zIDwtIGxpc3QoImFsZmVyZGV6IiwgDQogICAgICAgICAgICAgICAgICAgIkNGS0FyZ2VudGluYSIsIA0KICAgICAgICAgICAgICAgICAgICJnaW5lc2dnYXJjaWEiLA0KICAgICAgICAgICAgICAgICAgICJLaWNpbGxvZm9rIiwNCiAgICAgICAgICAgICAgICAgICAiUGFydGlkb0dFTiIsIA0KICAgICAgICAgICAgICAgICAgICJGcmVudGVEZVRvZG9zIiwNCiAgICAgICAgICAgICAgICAgICAgIm1hdXJpY2lvbWFjcmkiLA0KICAgICAgICAgICAgICAgICAgICJQYXRvQnVsbHJpY2giLA0KICAgICAgICAgICAgICAgICAgICJob3JhY2lvcmxhcnJldGEiLA0KICAgICAgICAgICAgICAgICAgICJGZXJuYW5RdWlyb3NCQSIsDQogICAgICAgICAgICAgICAgICAgInByb2FyZ2VudGluYSIsDQogICAgICAgICAgICAgICAgICAgIlVDUk5hY2lvbmFsIiwNCiAgICAgICAgICAgICAgICAgICAiamxlc3BlcnQiLA0KICAgICAgICAgICAgICAgICAgICJOaWNvbGFzZGVsQ2FubyIsDQogICAgICAgICAgICAgICAgICAgIlJMYXZhZ25hIiwNCiAgICAgICAgICAgICAgICAgICAianVhbmpvbWFsdmluYXMiKQ0KDQp0aXBvY3VlbnRhIDwtIGxpc3QgKCJQZXJvbmlzbW8iLCJjdWVudGEgcGFydGlkYXJpYSIsICJQUk8iLCJvdHJvcyBjYW5kaWRhdG9zIiApDQoNCiBUd2VldHM8LW1hcChjYW5kaWRhdG9zLCBmdW5jdGlvbih4KXsNCiAgICBnZXRfdGltZWxpbmUodXNlciA9IHgsIG4gPSAzMjAwLCBpbmNsdWRlUnRzID0gRiwgZXhjbHVkZVJlcGxpZXMgPSBGKQ0KICAgICB9ICkNCiANClR3ZWV0c19ERjwtIGRvX2NhbGxfcmJpbmQoVHdlZXRzKQ0KDQpwcmludCgiTXVlc3RyYSIpDQpwcmludChUd2VldHNfREYgJT4lIA0KICBzZWxlY3QodGV4dCklPiUgDQogICAgaGVhZCg1KSkNCg0KYGBgDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMi1MaW1waWV6YSA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNClZhbW9zIGEgbGltcGlhciBjaWVydG9zIGVsZW1lbnRvcyBxdWUgcHVlZGVuIGNvbXBsaWNhciBlbCBhbsOhbGlzaXMgZGVsIHRleHRvLCBjb21vIHNvbiBsb3MgbGlua3MsIGxvcyBuw7ptZXJvcywgbG9zIGdyw6FmaWNvcyB5IHBhc2FyIHRvZG8gYSBtaW7DunNjdWxhLg0KDQpBZGVtw6FzLCBjcmVhbW9zIHZhcmlvcyBjYW1wb3MgcGFyYSBsbyBxdWUgZXMgbGEgZmVjaGEsIGRlc2FncmVnYW5kbyBlbCBjYW1wbyBlbiB2YXJpb3MgZGlzdGludG9zLCBxdWUgc2UgdmFuIGEgdXRpbGl6YXIgYSBmdXR1cm8sIHkgdGFtYmnDqW4gc2UgYWN0dWFsaXphIGVsIGhvcmFyaW8gYSBsYSB6b25hIGhvcmFyaWEgZG9uZGUgZnVlIHJlYWxpemFkbyBlbCB0d2VldCAqKEFyZ2VudGluYSkqLg0KDQpGaW5hbG1lbnRlIGZpbHRyYW1vcyBwb3IgZmVjaGEsIGxhIGlkZWEgZXMgdGVuZXIgc29sbyB0d2VldHMgZGVsIHBlcmlvZG8gMS8zLzIwMjAgaGFzdGEgbGEgZmVjaGEgZGUgcHVibGljYWNpw7NuICooU2VwLzIwMjApKg0KDQpgYGB7cn0NClR3ZWV0c19ERiA8LQ0KICBUd2VldHNfREYgJT4lDQogICMjVG9kbyBlbCB0ZXh0byBhIG1pbnVzY3VsYSMjDQogIG11dGF0ZSh0ZXh0ID0gdG9sb3dlcih0ZXh0KSkgJT4lIA0KICAjI1NpbiBncmFmaWNvcyMjDQogIG11dGF0ZSh0ZXh0ID0gZ3N1YigiW15bOmdyYXBoOl1dIiwgIiAiLCB0ZXh0KSkgJT4lIA0KICAjI1NpbiBsaW5rcyMjDQogIG11dGF0ZSh0ZXh0ID0gZ3N1YigiaHR0cC8vUyIsICIgIiwgdGV4dCkpICU+JSANCiAgIyNTaW4gbnVtZXJvcyMjDQogIG11dGF0ZSh0ZXh0ID0gZ3N1YigiW1s6ZGlnaXQ6XV0iLCAiICIsIHRleHQpKSAlPiUgDQogICMjU2luIG51bWVyb3MjIw0KICBtdXRhdGUodGV4dCA9IGNoYXJ0cignw6HDqcOtw7PDusOxJywnYWVpb3VuJyx0ZXh0KSkgJT4lDQogICMjQ2FtYmlhbW9zIGEgbGEgem9uYSBob3JhcmlhIGNvcnJlc3BvbmRpZW50ZSMjDQogIG11dGF0ZShjcmVhdGVkX2F0ID0gd2l0aF90eihjcmVhdGVkX2F0LCAiQW1lcmljYS9BcmdlbnRpbmEvQnVlbm9zX0FpcmVzIikpJT4lIA0KICAjI1NlcGFyYW1vcyBlbiBkaWEgeSBob3JhIGVsIGNhbXBvIGNyZWF0ZWRfYXQjIw0KICBzZXBhcmF0ZShjcmVhdGVkX2F0LCBpbnRvID0gYygiZGF0ZSIsICJob3VyIiksIHNlcCA9ICIgIiklPiUgDQogICMjU2VwYXJhbW9zIGxhIGhvcmEgZW4gaG9yYSxtaW51dG9zIHkgc2VndW5kb3MjIw0KICAgIHNlcGFyYXRlKGhvdXIsIGludG8gPSBjKCJob3VyIiwgIm1pbnV0ZXMiLCJzZWNvbmRzIiksIHNlcCA9ICI6IiklPiUgDQogICMjQ2FtYmlhbW9zIGxhIGNvbHVtbmEgY29uIGVsIG5vbWJyZSBkZWwgcG9saXRpY28jIw0KICAgcmVuYW1lKFBvbGl0aWNvID0gc2NyZWVuX25hbWUpICU+JSANCiAgIyNDcmVhbW9zIHVuYSBjb2x1bW5hIGNvbiBlbCBudW1lcm8gZGUgYcOxbywgbWVzLCBkaWEsIG5vbWJyZSBkZSBkaWEgeSBkZSBtZXMuIyMNCm11dGF0ZShwZXJpb2RvID0geWVhcihkYXRlKSwgDQogICAgICAgICBtZXMgPSBtb250aChkYXRlLCBsYWJlbCA9IEYsIGFiYnIgPSBGKSwNCiAgICAgICAgIGRpYSA9IGFzLm51bWVyaWMoZGF5KGRhdGUpKSwNCiAgICAgICAgIGRpYV9zZW0gPSB3ZGF5KGRhdGUsIGxhYmVsID0gVCwgYWJiciA9IEYsIHdlZWtfc3RhcnQgPSAxKSwNCiAgICAgICAgIGRpYV9wZXIgPSB5ZGF5KGRhdGUpLA0KICAgICAgICAgZGF0ZSA9IGFzLkRhdGUoZGF0ZSkgDQogICkgJT4lDQogICMjU29sbyB2YW1vcyBhIHV0aWxpemFyIGluZm8gZGUgbWFyem8gMjAyMCBlbiBhZGVsYW50ZSMjDQogIGZpbHRlcihwZXJpb2RvID09IDIwMjAgJiBtZXMgPiAyKSANCg0KcHJpbnQoIk11ZXN0cmEiKQ0KcHJpbnQoVHdlZXRzX0RGICU+JSANCiAgc2VsZWN0KFBvbGl0aWNvLCBzdGF0dXNfaWQsIHBlcmlvZG8sIG1lcywgZGlhKSU+JSANCiAgICBoZWFkKDEwKSkNCg0KYGBgDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDMtTm9ybWFsaXphY2nDs24gPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpOb3JtYWxpemFtb3MgYWxndW5vcyBjYW1wb3MsIHBhcmEgYXl1ZGFyIGFsIGFuw6FsaXNpcyB5IHRhbWJpw6luIGEgbGEgdmlzdWFsaXphY2nDs24uDQoNCkxlIGFncmVnYW1vcyBlbCBwYXJ0aWRvIGEgY2FkYSB1bm8gZGUgbG9zIGFuYWxpemFkb3MsIHkgYWRlbcOhcyBjYW1iaWFtb3Mgc3Ugbm9tYnJlIGRlbCBAIHF1ZSB2ZW1vcyBlbiBUd2l0dGVyLCBhIHVuIG5vbWJyZSBmw6FjaWwgZGUgZW50ZW5kZXIgcGFyYSB0b2Rvcw0KDQoNCmBgYHtyfQ0KVHdlZXRzX0RGIDwtDQogIFR3ZWV0c19ERiAlPiUNCiAgbXV0YXRlIChQYXJ0aWRvID0gaWZlbHNlIChQb2xpdGljbyA9PSAiYWxmZXJkZXoiLCAiUGVyb25pc21vIiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiQ0ZLQXJnZW50aW5hIiwgIlBlcm9uaXNtbyIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gImdpbmVzZ2dhcmNpYSIsICJQZXJvbmlzbW8iLCANCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiS2ljaWxsb2ZvayIsICJQZXJvbmlzbW8iLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJVQ1JOYWNpb25hbCIsICJjdWVudGEgcGFydGlkYXJpYSIsICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiRnJlbnRlRGVUb2RvcyIsICJjdWVudGEgcGFydGlkYXJpYSIsIA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJwcm9hcmdlbnRpbmEiLCAiY3VlbnRhIHBhcnRpZGFyaWEiLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJQYXJ0aWRvR0VOIiwgImN1ZW50YSBwYXJ0aWRhcmlhIiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAibWF1cmljaW9tYWNyaSIsICJQUk8iLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJQYXRvQnVsbHJpY2giLCAiUFJPIiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiaG9yYWNpb3JsYXJyZXRhIiwgIlBSTyIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIkZlcm5hblF1aXJvc0JBIiwgIlBSTyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvdHJvcyBjYW5kaWRhdG9zIikpKSkpKSkpKSkpKSkNCg0KVHdlZXRzX0RGIDwtDQogIFR3ZWV0c19ERiAlPiUNCiAgbXV0YXRlIChQb2xpdGljbyA9IGlmZWxzZSAoUG9saXRpY28gPT0gImFsZmVyZGV6IiwgIkEuRmVybmFuZGV6IiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiQ0ZLQXJnZW50aW5hIiwgIkMuS2lyY2huZXIiLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJnaW5lc2dnYXJjaWEiLCAiR2luZXMuR0ciLCANCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiS2ljaWxsb2ZvayIsICJBLktpY2lsbG9mIiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiVUNSTmFjaW9uYWwiLCAiVUNSIiwgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJGcmVudGVEZVRvZG9zIiwgIlRPRE9TIiwgDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gInByb2FyZ2VudGluYSIsICJQUk8iLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJQYXJ0aWRvR0VOIiwgIkdFTiIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIm1hdXJpY2lvbWFjcmkiLCAiTS5NYWNyaSIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIlBhdG9CdWxscmljaCIsICJQLkJ1bGxyaWNoIiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiaG9yYWNpb3JsYXJyZXRhIiwgIkguTGFycmV0YSIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIkZlcm5hblF1aXJvc0JBIiwgIkYuUXVpcm9zIiwgDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIk5pY29sYXNkZWxDYW5vIiwgIk4uRGVsQ2HDsW8iLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJqbGVzcGVydCIsICJKLkVzcGVydCIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIlJMYXZhZ25hIiwgIlIuTGF2YWduYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdvbWV6Q2VudHVyaW9uIg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpKSkpKSkpKSkpKSkpKSkNCg0KcHJpbnQoIk11ZXN0cmEiKQ0KcHJpbnQoVHdlZXRzX0RGICU+JSANCiAgc2VsZWN0KFBvbGl0aWNvLCBQYXJ0aWRvLCBzb3VyY2UpJT4lIA0KICAgIHRhaWwoMTApKQ0KYGBgDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gNC1DYW50aWRhZCBkZSB0d2VldHMgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpMYSBwcmltZXJhIGFwcm94aW1hY2nDs24gcXVlIHZhbW9zIGEgdGVuZXIsIGVzIGxhIGNhbnRpZGFkIGRlIHZlY2VzIHF1ZSB0d2l0dGVvIGNhZGEgdW5vIGRlc2RlIG1hcnpvIGRlbCAyMDIwIGhhc3RhIGxhIGZlY2hhIGRlIHB1YmxpY2FjacOzbiBkZWwgaW5mb3JtZS4NCg0KU2UgcHJlc2VudGFuIGRpZmVyZW5jaWFzIGNvbnNpZGVyYWJsZXMgZW50cmUgdG9kb3MsIHNlIGRlYmVyw6Egbm9ybWFsaXphciBvIHV0aWxpemFyIHByb3BvcmNpb25lcyBtw6FzIGRlIHVuYSB2ZXoNCg0KICAtICpNYWNyaSB5IExhdmFnbmEgdGllbmVuIG1lbm9zIHR3ZWV0cyBxdWUgZWwgcmVzdG8qDQogIC0gKkNyaXN0aW5hIEtpcmNobmVyIGVzIHRhbWJpw6luIGRlIHBvY2EgcGFydGljaXBhY2nDs24qDQogIC0gKkxhcyBjdWVudGFzIGRlIEZyZW50ZSBkZSBUb2RvcywgRXNwZXJ0LCBEZWwgQ2HDsW8geSBsYSBVQ1Igc29uIGxhIGRlIG3DoXMgdXRpbGl6YWNpw7NuKg0KICANCiAgDQpgYGB7cn0NCkNhbnRpZGFkX3R3ZWV0cyA9IFR3ZWV0c19ERiAlPiUNCiAgZ3JvdXBfYnkoUG9saXRpY28sIFBhcnRpZG8pICU+JQ0KICBjb3VudChQb2xpdGljbykNCiAgDQpDYW50aWRhZF90d2VldHMlPiUgIA0KICBnZ3Bsb3QoKSsNCiAgYWVzKHg9cmVvcmRlcihQb2xpdGljbywgbiksIHk9IG4sIGZpbGw9IFBvbGl0aWNvKSArDQogIGdlb21fY29sKCkgKw0KICBmYWNldF93cmFwKCJQYXJ0aWRvIiwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh0aXRsZSA9ICJDYW50aWRhZCB0b3RhbCBkZSB0d2VldHMiLCB4ID0gInR3ZWV0cyIsIHkgPSAiQ2FudGlkYWQiKSArDQogICAgdGVtYTENCmBgYA0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDUtRmVjaGEgZGUgbG9zIHR3ZWV0cyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNClZlbW9zIGN1YW5kbyBoYW4gaWRvIHB1YmxpY2FuZG8gY2FkYSB1bm8gZGUgbG9zIGFuYWxpemFkb3Mgc3VzIHR3ZWV0cywgY29uIGVsIGZpbiBkZSBtb3N0cmFyIGVuIHF1ZSDDqXBvY2EgdHV2aWVyb24gbcOhcyBvIG1lbm9zIGFjY2nDs24uDQoNCiAgLSAqRW4gZWwgY2FzbyBkZSBsYSBjdWVudGEgZGUgRnJlbnRlIGRlIHRvZG9zLCBjb21vIHR1dm8gbcOhcyBkZSAzMjAwIHR3ZWV0cywgZWwgYW7DoWxpc2lzIGFycmFuY2EgZGVzZGUgbG9zICAgICAgICAgICAgcHJpbWVyb3MgZMOtYXMgZGUgYWJyaWwqDQoNCg0KYGBge3J9DQpUd2VldHNfREYgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICJQUk8iKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gYXMuRGF0ZShkYXRlKSwgZmlsbCA9IFBvbGl0aWNvKSkgKw0KICAgICAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAiaWRlbnRpdHkiLCBiaW5zID0gMjAsIHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlZC0lbSIsIGRhdGVfYnJlYWtzID0gIjEgbW9udGgiKSArDQogICAgICBsYWJzKHggPSAiZmVjaGEgZGUgcHVibGljYWNpw7NuIiwgeSA9ICJuw7ptZXJvIGRlIHR3ZWV0cyIpICsNCiAgICAgIGZhY2V0X3dyYXAofiBQb2xpdGljbywgbmNvbCA9IDEpICsNCiAgICAgIHRlbWEyICsNCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQ0KDQpUd2VldHNfREYgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICJQZXJvbmlzbW8iKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gYXMuRGF0ZShkYXRlKSwgZmlsbCA9IFBvbGl0aWNvKSkgKw0KICAgICAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAiaWRlbnRpdHkiLCBiaW5zID0gMjAsIHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlZC0lbSIsIGRhdGVfYnJlYWtzID0gIjEgbW9udGgiKSArDQogICAgICBsYWJzKHggPSAiZmVjaGEgZGUgcHVibGljYWNpw7NuIiwgeSA9ICJuw7ptZXJvIGRlIHR3ZWV0cyIpICsNCiAgICAgIGZhY2V0X3dyYXAofiBQb2xpdGljbywgbmNvbCA9IDEpICsNCiAgICAgIHRlbWExICsNCiAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQ0KDQpUd2VldHNfREYgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICJvdHJvcyBjYW5kaWRhdG9zIikgJT4lDQogIGdncGxvdChhZXMoeCA9IGFzLkRhdGUoZGF0ZSksIGZpbGwgPSBQb2xpdGljbykpICsNCiAgICAgIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImlkZW50aXR5IiwgYmlucyA9IDIwLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJWQtJW0iLCBkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIikgKw0KICAgICAgbGFicyh4ID0gImZlY2hhIGRlIHB1YmxpY2FjacOzbiIsIHkgPSAibsO6bWVybyBkZSB0d2VldHMiKSArDQogICAgICBmYWNldF93cmFwKH4gUG9saXRpY28sIG5jb2wgPSAxKSArDQogICAgICB0ZW1hMSArDQogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkNCg0KVHdlZXRzX0RGICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAiY3VlbnRhIHBhcnRpZGFyaWEiKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gYXMuRGF0ZShkYXRlKSwgZmlsbCA9IFBvbGl0aWNvKSkgKw0KICAgICAgZ2VvbV9oaXN0b2dyYW0ocG9zaXRpb24gPSAiaWRlbnRpdHkiLCBiaW5zID0gMjAsIHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgICAgIHNjYWxlX3hfZGF0ZShkYXRlX2xhYmVscyA9ICIlZC0lbSIsIGRhdGVfYnJlYWtzID0gIjEgbW9udGgiKSArDQogICAgICBsYWJzKHggPSAiZmVjaGEgZGUgcHVibGljYWNpw7NuIiwgeSA9ICJuw7ptZXJvIGRlIHR3ZWV0cyIpICsNCiAgICAgIGZhY2V0X3dyYXAofiBQb2xpdGljbywgbmNvbCA9IDEpICsNCiAgICAgIHRlbWEyICArDQogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkNCmBgYA0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gNi1DYW50aWRhZCBkZSB0d2VldHMgc29icmUgQ09WSUQgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCkVsIHRlbWEgbcOhcyBpbXBvcnRhbnRlIGRlbCBhw7FvIGVzIGVsIGNvcm9uYXZpcnVzLCBsYSBpZGVhIGVzIHZlciBxdcOpIHBvcmNlbnRhamUgZGUgbG9zIHR3ZWV0cyByZWFsaXphZG9zIGVzdG9zIG1lc2VzIHRyYXRvIHNvYnJlIGVsIGNvcm9uYXZpcnVzLCBwYXJhIGVzbyBzZSB2YW4gYSBidXNjYXIgcGFsYWJyYXMgY2xhdmVzIHF1ZSBkZXRlcm1pbmVuIHF1ZSBlbCB0d2VldCB0cmF0YSBzb2JyZSBsYSBwYW5kZW1pYS4NCg0KICAtICpDbGFyYW1lbnRlIGxvcyBtaW5pc3Ryb3Mgc29uIGxvcyBxdWUgbcOhcyBoYWJsYXJvbiBzb2JyZSBlbCBDb3JvbmF2aXJ1cywgY29uIGVsIDc1JSBkZSBzdXMgdHdlZXRzLioNCiAgDQogIC0gKlNpZ3VlbiBsb3MgZ29iZXJuYWRvcmVzIEtpY2lsb2ZmIHkgTGFycmV0YSwgcXVlIHRyYXRhcm9uIHNvYnJlIGxhIGV2b2x1Y2nDs24gZGUgbGEgcGFuZGVtaWEgZW4gc3VzIGRpc3RyaXRvcy4qIA0KDQogIC0gKkVuIG1lbm9yIG1lZGlkYSBoYWJsYXJvbiBsb3MgbMOtZGVyZXMgZGUgbG9zIGRvcyBwcmluY2lwYWxlcyBwYXJ0aWRvcy4qDQoNCiAgLSAqRGVsIENhw7FvIGVzIGVsIHF1ZSBtw6FzIGhhYmxvIGVudHJlIGxvcyBvdHJvcyBjYW5kaWRhdG9zLCBsbyBzaWd1ZSBFc3BlcnQsIG1pZW50cmFzIHF1ZSBMYXZhZ25hIHkgR8OzbWV6IENlbnR1cmnDs24gICAgIGhhYmxhcm9uIG11eSBwb2NvLioNCg0KICAtICpMYXMgY3VlbnRhcyBwYXJ0aWRhcmlhcywgc2Fsdm8gbGFzIGRlIGxhIFVDUiBubyBmdWVyb24gbXV5IHVzYWRhcyBwYXJhIGhhYmxhciBzb2JyZSBlbCBDb3JvbmF2aXJ1cyoNCg0KDQpgYGB7cn0NCiNCdXNjYW1vcyB0d2VldHMgY29uIGxhIHBhbGFicmEgY292aWQNClBhbGFicmFzX2NvdmlkIDwtICJjb3ZpZHxjb3ZpZC0xOXxjb3ZpZDE5fGNvcm9uYXZpcnVzfCNjb3ZpZHwjY292aWQtMTl8I2NvdmlkMTl8I2Nvcm9uYXZpcnVzfHRlc3R8dGVzdGVvfHRlc3Rlb3N8cGNyfHNlcm9sb2dpY298aGlzb3BhZG98YW50aWJpb3RpY29zfGFwbGFuYXJ8Y3VydmF8Y3VhcmVudGVuYXxjb250YWdpb3xlbmZlcm1lZGFkfGVwaWRlbWlhfHBhbmRlbWlhfGFsYXJtYXxnZWx8Y3VpZGFkb3N8aW5jdWJhY2lvbnxqYWJvbnxiYXJiaWpvfGJhcmJpam9zfG1hc2NhcmlsbGF8bWFzY2FyaWxsYXN8bWVyc3xzYXJzfHZhY3VuYXx3dWhhbnxveGZvcmR8YXN0cmF8emVuZWNhfHRyYW5zbWlzaW9ufGV4cG9uZW5jaWFsfGNhc29zfGR1cGxpY2FjaW9ufGRpc3RhbmNpYW1pZW50b3xjb2xhcHNvfHNhbHVkfGxldGFsaWRhZHxtb3J0YWxpZGFkfHZlbnRpbGFkb3J8aWN1fHVjaXx1dGl8aW5tdW5pZGFkfHNlcm9sb2dpY2F8ZGlzdGFuY2lhbWllbnRvfHZpcnVzfGFzaW50b21hdGljb3xjYXNvIHNvc3BlY2hvc298b2xmYXRvfGd1c3RvfHRlcmFwaWF8c2F0dXJhY2lvbnxjbGluaWNhfHBvc2l0aXZpZGFkfHBvc2l0aXZpb3N8cmViYcOxb3xpbm11bmlkYWR8aG9zcGl0YWx8aG9zcGl0YWxlc3xhc3BvfGFpc2xhbWllbnRvIg0KVHdlZXRzX0RGJENvdmlkIDwtIGdyZXBsKFBhbGFicmFzX2NvdmlkLCBUd2VldHNfREYkdGV4dCwgaWdub3JlLmNhc2UgPSJUcnVlIikNCg0KVHdlZXRzX0RGICU+JSANCmNvdW50KFBvbGl0aWNvLCBQYXJ0aWRvLENvdmlkKSAlPiUNCiAgZ3JvdXBfYnkoUG9saXRpY28pICU+JQ0KICBtdXRhdGUoUHJvcG9yY2lvbiA9IG4gLyBzdW0obikpICU+JQ0KICBtdXRhdGUoQ292aWQgPSBpZmVsc2UoQ292aWQgPT0gVCwgIlNvYnJlIENPVklEIiwgIk90cm8gdGVtYSIpKSU+JQ0KZ2dwbG90KCkgKw0KICBhZXMoUG9saXRpY28sIFByb3BvcmNpb24sIGZpbGwgPSBDb3ZpZCkgKw0KICBnZW9tX2NvbCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgICAgIGZhY2V0X3dyYXAoIlBhcnRpZG8iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpDQpgYGANCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+ICA3LSBXb3JkY2xvdWQgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCkxhIGlkZWEgZGUgbGEgbnViZSBkZSBwYWxhYnJhcyBlcyBzYWJlciBjdcOhbGVzIHNvbiBsYXMgMjAwIHBhbGFicmFzIHF1ZSBtw6FzIHNlIHVzYXJvbiBwb3IgbG9zIGFuYWxpemFkb3MgZXN0b3MgbWVzZXMsIGNvbW8gZXJhIGRlIGVzcGVyYXJzZSBzb2JyZXNhbGVuICoqImNvcm9uYXZpcnVzIioqLCAqKiJjb3ZpZCIqKiwgKioicGFuZGVtaWEiKiogbyAqKiJjdWFyZW50ZW5hIioqDQoNCg0KYGBge3J9DQp0dWl0c190b2tlbnMgPC0NCiAgVHdlZXRzX0RGICU+JQ0KICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gdGV4dCwgb3V0cHV0ID0gUGFsYWJyYSwgdG9rZW4gPSAid29yZHMiKSAlPiUNCiAgc2VsZWN0KFBvbGl0aWNvLCBQYWxhYnJhLCBzdGF0dXNfaWQsIHBlcmlvZG8sIG1lcywgaG91ciwgUGFydGlkbykgJT4lDQogIG11dGF0ZShzdGF0dXNfaWQgPSBnc3ViKCI8KC4qKT4rPyIsICIiLCBzdGF0dXNfaWQpKSAlPiUNCiAgZmlsdGVyKCFQYWxhYnJhICVpbiUgc3RvcHdvcmRzKCJlcyIpKSAlPiUNCiAgZmlsdGVyKCFQYWxhYnJhICVpbiUgYygidC5jbyIsICJodHRwcyIsICJ2w4PCrWEiLCAieW91dHViZSIsICJhbXAiKSkNCg0KUGFsYWJyYXNfc2luaG95bWFzID0gdHVpdHNfdG9rZW5zICAlPiUNCiAgZmlsdGVyKFBhbGFicmEgIT0gIm1hcyIgJiBQYWxhYnJhICE9ICJob3kiKSANCg0Kd29yZGNsb3VkKHdvcmRzID0gUGFsYWJyYXNfc2luaG95bWFzJFBhbGFicmEsIA0KICAgICAgICAgIHNjYWxlPWMoMiwuMiksIA0KICAgICAgICAgIG1heC53b3Jkcz0yMDAsIHJhbmRvbS5vcmRlcj1GQUxTRSwgcm90LnBlcj0wLjM1LCANCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg4LCAiRGFyazIiKSwNCiAgICAgICAgICApDQoNCg0KYGBgDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiA4LURlc2NhcmdhbW9zIHVuIGRpY2Npb25hcmlvIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KRGVzY2FyZ2Ftb3MgdW4gZGljY2lvbmFyaW8gcXVlIHRpZW5lIGxhcyBwYWxhYnJhcyBlbiBlc3Bhw7FvbCwgeSBsZSBhc2lnbmEgdW4gdmFsb3IgZW50cmUgLTUgYSA1LCBtb3N0cmFuZG8gbGEgcG9zaXRpdmlkYWQgbyBuZWdhdGl2aWRhZCBkZSBsYSBwYWxhYnJhLg0KDQpFbGltaW5hbW9zIGxhIHBhbGFicmEgKiJObyIqIHF1ZSBsYSB0b21hIGNvbW8gbmVnYXRpdmEsIGN1YW5kbyBlbiBlc3Bhw7FvbCBlcyB1biBjb25lY3RvciBhIHZlY2VzLCB5IGxhIHBhbGFicmEgKuKAnE5lZ3Jv4oCdKiAoTmlnZ2EpIHF1ZSBsYSB0b21hIGNvbiBlbCBtw6F4aW1vIHZhbG9yIG5lZ2F0aXZvDQoNCg0KYGBge3J9DQpkb3dubG9hZC5maWxlKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vamJvc2NvbWVuZG96YS9ycHVicy9tYXN0ZXIvc2VudGltaWVudG9zX2FmaW5uL2xleGljb19hZmlubi5lbi5lcy5jc3YiLA0KICAgICAgICAgICAgICAibGV4aWNvX2FmaW5uLmVuLmVzLmNzdiIpDQoNCmFmaW5uIDwtIHJlYWQuY3N2KCJsZXhpY29fYWZpbm4uZW4uZXMuY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYsIGZpbGVFbmNvZGluZyA9ICJsYXRpbjEiKSAlPiUgDQogIHRibF9kZigpDQoNCmFmaW5uJFB1bnR1YWNpb24gPC0gaWZlbHNlKGFmaW5uJFBhbGFicmEgPT0gIm5vIiwgMCwgYWZpbm4kUHVudHVhY2lvbikNCmFmaW5uJFB1bnR1YWNpb24gPC0gaWZlbHNlKGFmaW5uJFBhbGFicmEgPT0gIm5lZ3JvIiwgMCwgYWZpbm4kUHVudHVhY2lvbikNCg0KcHJpbnQoIk11ZXN0cmEiKQ0KYWZpbm4gJT4lDQogIHNlbGVjdChQYWxhYnJhLCBQdW50dWFjaW9uKSAlPiUNCiAgICBhcnJhbmdlKFB1bnR1YWNpb24pICU+JQ0KICBwcmludChoZWFkKDEwKSkNCg0KYWZpbm4gJT4lDQogIHNlbGVjdChQYWxhYnJhLCBQdW50dWFjaW9uKSAlPiUNCiAgICBhcnJhbmdlKC1QdW50dWFjaW9uKSAlPiUNCiAgcHJpbnQodGFpbCgxMCkpDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gOS0gU2VwYXJhY2lvbiBkZSBwYWxhYnJhcyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNClNlcGFyYW1vcyBsYXMgZGlzdGludGFzIHBhbGFicmFzIHF1ZSB1c2Fyb24gY2FkYSB1bm8gZGUgbG9zIHBvbMOtdGljb3MgZW4gc3VzIHR3ZWV0cywgeSBlbGltaW5hbW9zIGFsZ3VuYXMgcGFsYWJyYXMgcHJvcGlhcyBkZSBUd2l0dGVyIHkgbGFzIGxsYW1hZGFzIHN0b3B3b3JkcyBxdWUgc29uIGxhcyBwYWxhYnJhcyBtw6FzIGZyZWN1ZW50ZXMgZW4gZWwgaWRpb21hIGVzcGHDsW9sLg0KDQoNCmBgYHtyfQ0KcHJpbnQgKCJNdWVzdHJhIikNCnByaW50ICh0dWl0c190b2tlbnMgJT4lDQogICAgc2VsZWN0KFBvbGl0aWNvLCBQYWxhYnJhKSAlPiUgICAgDQogICAgICAgICBoZWFkICgxMCkpDQpgYGANCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMTAtIExlIGRhbW9zIHZhbG9yIGEgbGFzIHBhbGFicmFzIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KVW5pbW9zIGVsIGRpY2Npb25hcmlvIGRlIHB1bnR1YWNpw7NuIGNvbiBsYXMgcGFsYWJyYXMgcXVlIHVzbyBjYWRhIHVubyBkZSBsb3MgYW5hbGl6YWRvcywgY29uIGVsIGZpbiBkZSBxdWUgY2FkYSBwYWxhYnJhIHRlbmdhIHVuIHZhbG9yLCB5IG5vcyBzaXJ2YSBwYXJhIGFuYWxpemFyIHF1ZSBlc2NyaWJpw7MgY2FkYSBwb2zDrXRpY28uDQoNCkxhcyBwYWxhYnJhcyBzZXLDoW46IA0KICAtICBTaSB0aWVuZW4gdmFsb3IgbWF5b3IgYSAwICoqUG9zaXRpdmFzKiogDQogIA0KICAtICBTaSBzb24gbWVub3JlcyBhIDAgKipOZWdhdGl2YXMqKiANCiAgDQogIC0gIEVuIGNhc28gZGUgcXVlIGxhIHBhbGFicmEgbm8gdGVuZ2EgY2FyZ2EgZGUgc2VudGltaWVudG9zKipOZXV0cmFsZXMqKiANCg0KDQpgYGB7cn0NCnR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgPC0gICANCiB0dWl0c190b2tlbnMgJT4lDQppbm5lcl9qb2luKGFmaW5uLCAuLCBieSA9ICJQYWxhYnJhIikgJT4lDQogIG11dGF0ZShDYWxpZmljYWNpb24gPSBpZmVsc2UoUHVudHVhY2lvbiA+IDAsICJQb3NpdGl2YSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFB1bnR1YWNpb24gPT0gMCwgIk5ldXRyYWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5lZ2F0aXZhIikNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQogICkgICAgICANCg0KcHJpbnQgKCJNdWVzdHJhIikNCnByaW50ICh0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIHNlbGVjdChQb2xpdGljbywgUGFsYWJyYSwgUHVudHVhY2lvbiwgQ2FsaWZpY2FjaW9uKSAlPiUgICAgDQogICAgICAgICB0YWlsICgxMCkpDQpgYGANCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDExLSDCv1F1acOpbiB1c2EgbcOhcyBjYXJhY3RlcmVzPyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNCkxhIGlkZWEgZXMgYnVzY2FyIGN1YWwgZXMgZWwgcHJvbWVkaW8gZGVsIGxhcmdvIChjYW50aWRhZCBkZSBjYXJhY3RlcmVzKSBkZSBsb3MgdHdlZXRzIHF1ZSByZWFsaXphIGNhZGEgdW5vIGRlIGxvcyBhbmFsaXphZG9zLg0KDQpNaWVudHJhcyBtw6FzIGEgbGEgZGVyZWNoYSBlc3RlIGxhIGNhamEsIG3DoXMgbGFyZ28gc29uIGxvcyB0d2VldHMgcXVlIGVzY3JpYmVuLCBlbiBlc2UgYXNwZWN0byBzZSBkZXN0YWNhbjogDQogIC0JKkxhdmFnbmEsIFBhdHJpY2lhIEJ1bGxyaWNoLCBMYXJyZXRhIHkgRmVybsOhbiBRdWlyw7NzIHNvbiBsb3MgcXVlIGVzY3JpYmVuIGxvcyB0d2VldHMgbcOhcyBsYXJnb3MuKiANCiAgLQkqQXF1ZWxsb3MgcmVsYWNpb25hZG9zIGFsIFBSTyBzb24gZGUgZXNjcmliaXIgdHdlZXRzIG3DoXMgbGFyZ29zKg0KDQoNCmBgYHtyfQ0KVHdlZXRzX0RGICU+JSANCmdncGxvdCgpKw0KICBhZXMoeD0gUG9saXRpY28sIHk9IGRpc3BsYXlfdGV4dF93aWR0aCwgY29sb3I9IFBvbGl0aWNvKSArDQogIGdlb21fYm94cGxvdCAoKSArDQogICAgbGFicyh0aXRsZSA9ICJMYXJnbyBwcm9tZWRpbyBkZWwgdHdlZXQiLCB4ID0gIlBvbGl0aWNvIiwgeSA9ICJDYW50aWRhZCBjYXJhY3RlcmVzIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgIHRlbWExDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMTItIMK/UXVpw6luIHVzYSBtw6FzIHBhbGFicmFzPyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNCkxhIGlkZWEgZXMgYW5hbGl6YXIgcXVpZW4gZXMgZWwgcXVlIHVzbyBtw6FzIHBhbGFicmFzIGRpc3RpbnRhcyBlbiBwcm9tZWRpbyBkdXJhbnRlIGVzdGUgdGllbXBvLCBlbiBlc3RlIGNhc28gdmFtb3MgYSBkaXZpZGlyIHBvciBsYSBjYW50aWRhZCBkZSB0d2VldHMgcXVlIGhpem8sIGFzw60gcXVlZGEgbm9ybWFsaXphZG8gcGFyYSB0b2RvcyBsb3MgYW5hbGl6YWRvcy4NCg0KKk5vIHNlIGN1ZW50YW4gbG9zIGNvbmVjdG9yZXMgY29tdW5lcyBjb21vICJlbiIsICJhIiwgImRlIiwgZXRjLioNCg0KICAtCSpFc3BlcnQgZXN0YSBhYmFqbyBkZSBsYXMgMTUgcGFsYWJyYXMgcG9yIHR3ZWV0LCBlcyBlbCBkZSBtZW5vciB1c28uKg0KICAtCSpFbCByZXN0byBlc3TDoSBlbiB1bmEgY2FudGlkYWQgc2ltaWxhcmVzIGRlIGVudHJlIDE1IHkgMjAgcGFsYWJyYXMuKg0KDQoNCmBgYHtyfQ0KQ2FudGlkYWRfcGFsYWJyYXM9IHR1aXRzX3Rva2VucyU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbyklPiUNCiAgY291bnQoUG9saXRpY28pJT4lDQppbm5lcl9qb2luKENhbnRpZGFkX3R3ZWV0cywgLiwgYnkgPSAiUG9saXRpY28iKSU+JQ0KICBtdXRhdGUoY2FudGlkYWRfcHJvbWVkaW8gPSBuLnkgLyBuLngpDQoNCg0KQ2FudGlkYWRfcGFsYWJyYXMlPiUgZ2dwbG90KCkrDQogIGFlcyh4PXJlb3JkZXIoUG9saXRpY28sIC1jYW50aWRhZF9wcm9tZWRpbyksIHk9IGNhbnRpZGFkX3Byb21lZGlvLCBmaWxsPSBQb2xpdGljbykgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCgiUGFydGlkby54Iiwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgbGFicyh0aXRsZSA9ICJVc28gZGUgcGFsYWJyYXMiLCB4ID0gInR3ZWV0cyIsIHkgPSAiQ2FudGlkYWQiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICAgdGVtYTENCg0KDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gIDEzLSDCv1F1aWVuIHVzYSBtYXMgcGFsYWJyYXMgZGlzdGludGFzPyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQpCdXNjYW1vcyB2ZXIgZWwgbMOpeGljbyBkaXN0aW50aXZvIHF1ZSBoYXkgZW4gY2FkYSB1bmEgZGUgbGFzIGN1ZW50YXMsIGNvbnRhbmRvIHN1cyBwYWxhYnJhcyDDum5pY2FzIHkgc2Ugbm90YTogDQoNCi0JKkRpZmVyZW5jaWFzIGVudHJlIExhdmFnbmEsIE1hY3JpLCBDcmlzdGluYSBjb24gZWwgcmVzdG8gZGUgbG9zIHF1ZSBlc2NyaWJlbioNCg0KLQkqRXNwZXJ0IHF1ZSBlcyBlbCBkZSBsw6l4aWNvIG1lbm9zIHZhcmlhZG8qDQoNCg0KYGBge3J9DQp0dWl0c190b2tlbnMlPiUNCiAgZ3JvdXBfYnkoUG9saXRpY28sIFBhcnRpZG8pJT4lDQogIGRpc3RpbmN0KFBhbGFicmEpJT4lDQogIGNvdW50KFBvbGl0aWNvKSU+JQ0KaW5uZXJfam9pbihDYW50aWRhZF90d2VldHMsIC4sIGJ5ID0gIlBvbGl0aWNvIikgICU+JQ0KICBtdXRhdGUoY2FudGlkYWRfcHJvbWVkaW8gPSBuLnkgLyBuLngpICU+JSANCiAgZ2dwbG90KCkrDQogIGFlcyh4PXJlb3JkZXIoUG9saXRpY28sIGNhbnRpZGFkX3Byb21lZGlvKSwgeT0gY2FudGlkYWRfcHJvbWVkaW8sIGZpbGw9IFBvbGl0aWNvKSArDQogIGdlb21fY29sKCkgKw0KICBmYWNldF93cmFwKCJQYXJ0aWRvLngiLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICBsYWJzKHRpdGxlID0gIlBhbGFicmFzIGRpc3RpbnRhcyIsIHggPSAidHdlZXRzIiwgeSA9ICJDYW50aWRhZCIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgICB0ZW1hMQ0KICANCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAxNC0gUGFsYWJyYXMgbcOhcyB1c2FkYXMgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KQWhvcmEgcXVlIHlhIHNhYmVtb3MgY29uIHF1w6kgdmFyaWVkYWQgZGUgcGFsYWJyYXMsIHBvZGVtb3MgYW5hbGl6YXIgY3XDoWxlcyBzb24gbGFzIHF1ZSBtw6FzIHVzYXJvbg0KRW4gZXN0ZSBjYXNvLCBjYWRhIGdyYWZpY28gdGllbmUgdW5hIGVzY2FsYSBkaXN0aW50YSBwYXJhIHF1ZSBubyBzZSBwaWVyZGEgcG9yIGxhIGNhbnRpZGFkIGRlIHR3ZWV0cyByZWFsaXphZG9zLg0KDQpMYXMgcGFsYWJyYXMgbcOhcyB1dGlsaXphZGFzIGZ1ZXJvbjogDQoNCi0gIipldml0YXIqIg0KLSAiKmRldWRhKiINCi0gIipqdXN0aWNpYSoiIA0KLSAiKmxpYmVydGFkKiIgdXNhZGEgcHJpbmNpcGFsbWVudGUgcG9yIEVzcGVydC4NCg0KDQpgYGB7cn0NCnR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgJT4lDQogICAgZ3JvdXBfYnkoUGFydGlkbywgUG9saXRpY28pICU+JQ0KICAgIGNvdW50KFBhbGFicmEsIHNvcnQgPSBUKSAlPiUNCiAgICAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbj0gMTApICU+JQ0KICAgICAgZmlsdGVyKFBhcnRpZG8gPT0gICJQUk8iKSAlPiUNCiAgICBnZ3Bsb3QoKSArDQogICAgYWVzKFBhbGFicmEsIG4sIGZpbGwgPSBQb2xpdGljbykgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGZhY2V0X3dyYXAoIlBvbGl0aWNvIiwgc2NhbGVzID0gImZyZWUiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiUGFsYWJyYXMgbcOhcyB1c2FkYXMiKSArDQogICAgIHRlbWExDQoNCiB0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIGdyb3VwX2J5KFBhcnRpZG8sIFBvbGl0aWNvKSAlPiUNCiAgICBjb3VudChQYWxhYnJhLCBzb3J0ID0gVCkgJT4lDQogICAgIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG49IDEwKSAlPiUNCiAgICAgIGZpbHRlcihQYXJ0aWRvID09ICAiUGVyb25pc21vIikgJT4lDQogICAgZ2dwbG90KCkgKw0KICAgIGFlcyhQYWxhYnJhLCBuLCBmaWxsID0gUG9saXRpY28pICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICBmYWNldF93cmFwKCJQb2xpdGljbyIsIHNjYWxlcyA9ICJmcmVlIikgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApKSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICBsYWJzKHRpdGxlID0gIlBhbGFicmFzIG3DoXMgdXNhZGFzIikgKw0KICAgICB0ZW1hMQ0KIA0KICB0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIGdyb3VwX2J5KFBhcnRpZG8sIFBvbGl0aWNvKSAlPiUNCiAgICBjb3VudChQYWxhYnJhLCBzb3J0ID0gVCkgJT4lDQogICAgIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG49IDEwKSAlPiUNCiAgICAgIGZpbHRlcihQYXJ0aWRvID09ICAib3Ryb3MgY2FuZGlkYXRvcyIpICU+JQ0KICAgIGdncGxvdCgpICsNCiAgICBhZXMoUGFsYWJyYSwgbiwgZmlsbCA9IFBvbGl0aWNvKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgZmFjZXRfd3JhcCgiUG9saXRpY28iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh0aXRsZSA9ICJQYWxhYnJhcyBtw6FzIHVzYWRhcyIpICsNCiAgICAgdGVtYTENCiAgDQogICB0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIGdyb3VwX2J5KFBhcnRpZG8sIFBvbGl0aWNvKSAlPiUNCiAgICBjb3VudChQYWxhYnJhLCBzb3J0ID0gVCkgJT4lDQogICAgIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG49IDEwKSAlPiUNCiAgICAgIGZpbHRlcihQYXJ0aWRvID09ICAiY3VlbnRhIHBhcnRpZGFyaWEiKSAlPiUNCiAgICBnZ3Bsb3QoKSArDQogICAgYWVzKFBhbGFicmEsIG4sIGZpbGwgPSBQb2xpdGljbykgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGZhY2V0X3dyYXAoIlBvbGl0aWNvIiwgc2NhbGVzID0gImZyZWUiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiUGFsYWJyYXMgbcOhcyB1c2FkYXMiKSArDQogICAgIHRlbWExDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMTUtIFBhbGFicmFzIHBvc2l0aXZhcyBtw6FzIHVzYWRhcyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQpBbCB0ZW5lciB1bmEgcHVudHVhY2nDs24gY2FkYSBwYWxhYnJhIG90b3JnYWRhIHBvciBlbCBkaWNjaW9uYXJpbyBkZSBsw6l4aWNvLCB0YW1iacOpbiBwb2RlbW9zIGJ1c2NhciBjdWFsZXMgc29uIGxhcyBwYWxhYnJhcyBwb3NpdGl2YXMgcXVlIG3DoXMgdXNvIGNhZGEgdW5vIGRlIGxvcyBwb2zDrXRpY29zLg0KDQpFbiBlc3RlIGNhc286IA0KDQotIFNlIG5vdGEgZWwgdXNvIGRlIGxhcyBwYWxhYnJhcyAqKiJsaWJlcnRhZCIqKiB5ICoqImp1c3RpY2lhIioqIHF1ZSBzb24gY29uc2lkZXJhZGFzIHBvc2l0aXZhcw0KDQotIEFwYXJlY2UgYmFzdGFudGUgZWwgdXNvIGRlIGxhIHBhbGFicmEgKioiZ3JhY2lhcyIqKiwgcHJpbmNpcGFsbWVudGUgZGUgYXF1ZWxsYXMgY3VlbnRhcyByZWxhY2lvbmFkYSBhIGxhIHNhbHVkICoqKEdpbmVzIEdvbnrDoWxleiBHYXJjw61hIHkgRmVybsOhbiBRdWlyw7NzKSoqDQoNCg0KYGBge3J9DQogdHVpdHNfdG9rZW5zX2Vtb2Npb25lcyAlPiUNCiAgICBmaWx0ZXIoQ2FsaWZpY2FjaW9uID09ICAiUG9zaXRpdmEiKSAlPiUNCiAgICBncm91cF9ieShQYXJ0aWRvLCBQb2xpdGljbykgJT4lDQogICAgY291bnQoUGFsYWJyYSwgc29ydCA9IFQpICU+JQ0KICAgICBzbGljZV9tYXgob3JkZXJfYnkgPSBuLCBuPSAxMCkgJT4lDQogICAgICBmaWx0ZXIoUGFydGlkbyA9PSAgIlBSTyIpICU+JQ0KICAgIGdncGxvdCgpICsNCiAgICBhZXMoUGFsYWJyYSwgbiwgZmlsbCA9IFBvbGl0aWNvKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgZmFjZXRfd3JhcCgiUG9saXRpY28iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh0aXRsZSA9ICJQYWxhYnJhcyBQb3NpdGl2YXMgbcOhcyB1c2FkYXMiKSANCg0KIHR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgJT4lDQogICAgZmlsdGVyKENhbGlmaWNhY2lvbiA9PSAgIlBvc2l0aXZhIikgJT4lDQogICAgZ3JvdXBfYnkoUGFydGlkbywgUG9saXRpY28pICU+JQ0KICAgIGNvdW50KFBhbGFicmEsIHNvcnQgPSBUKSAlPiUNCiAgICAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbj0gMTApICU+JQ0KICAgICAgZmlsdGVyKFBhcnRpZG8gPT0gICJQZXJvbmlzbW8iKSAlPiUNCiAgICBnZ3Bsb3QoKSArDQogICAgYWVzKFBhbGFicmEsIG4sIGZpbGwgPSBQb2xpdGljbykgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGZhY2V0X3dyYXAoIlBvbGl0aWNvIiwgc2NhbGVzID0gImZyZWUiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiUGFsYWJyYXMgUG9zaXRpdmFzIG3DoXMgdXNhZGFzIikgDQogDQogIHR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgJT4lDQogICAgZmlsdGVyKENhbGlmaWNhY2lvbiA9PSAgIlBvc2l0aXZhIikgJT4lDQogICAgZ3JvdXBfYnkoUGFydGlkbywgUG9saXRpY28pICU+JQ0KICAgIGNvdW50KFBhbGFicmEsIHNvcnQgPSBUKSAlPiUNCiAgICAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbj0gMTApICU+JQ0KICAgICAgZmlsdGVyKFBhcnRpZG8gPT0gICJvdHJvcyBjYW5kaWRhdG9zIikgJT4lDQogICAgZ2dwbG90KCkgKw0KICAgIGFlcyhQYWxhYnJhLCBuLCBmaWxsID0gUG9saXRpY28pICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICBmYWNldF93cmFwKCJQb2xpdGljbyIsIHNjYWxlcyA9ICJmcmVlIikgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApKSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICBsYWJzKHRpdGxlID0gIlBhbGFicmFzIFBvc2l0aXZhcyBtw6FzIHVzYWRhcyIpIA0KICANCiAgIHR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgJT4lDQogICAgZmlsdGVyKENhbGlmaWNhY2lvbiA9PSAgIlBvc2l0aXZhIikgJT4lDQogICAgZ3JvdXBfYnkoUGFydGlkbywgUG9saXRpY28pICU+JQ0KICAgIGNvdW50KFBhbGFicmEsIHNvcnQgPSBUKSAlPiUNCiAgICAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbj0gMTApICU+JQ0KICAgICAgZmlsdGVyKFBhcnRpZG8gPT0gICJjdWVudGEgcGFydGlkYXJpYSIpICU+JQ0KICAgIGdncGxvdCgpICsNCiAgICBhZXMoUGFsYWJyYSwgbiwgZmlsbCA9IFBvbGl0aWNvKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgZmFjZXRfd3JhcCgiUG9saXRpY28iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh0aXRsZSA9ICJQYWxhYnJhcyBQb3NpdGl2YXMgbcOhcyB1c2FkYXMiKSANCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAxNi0gUGFsYWJyYXMgbmVnYXRpdmFzIG3DoXMgdXNhZGFzIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KQWwgdGVuZXIgdW5hIHB1bnR1YWNpw7NuIGNhZGEgcGFsYWJyYSBvdG9yZ2FkYSBwb3IgZWwgZGljY2lvbmFyaW8gZGUgbMOpeGljbywgdGFtYmnDqW4gcG9kZW1vcyBidXNjYXIgY3VhbGVzIHNvbiBsYXMgcGFsYWJyYXMgbmVnYXRpdmFzIHF1ZSBtw6FzIHVzbyBjYWRhIHVubyBkZSBsb3MgcG9sw610aWNvcy4NCg0KICAtCSpFdml0YXIqLCAqRW1lcmdlbmNpYSogbyAqUHJvYmxlbWEqIHNvbiBsYXMgcGFsYWJyYXMgcXVlIG3DoXMgYXBhcmVjZW4sIGRlbnRybyBkZWwgcHJpbmNpcGFsIHRlbWEgZGUgaGFibGEgcXVlIGVzIGxhIHBhbmRlbWlhLiANCg0KICAtCSpEZXVkYSogZXMgb3RyYSBwYWxhYnJhIG11eSB1dGlsaXphZGEsIHVuIHRlbWEgZGlmw61jaWwgZGUgZXNxdWl2YXIgZXN0ZSBhw7FvLg0KDQoNCg0KYGBge3J9DQogdHVpdHNfdG9rZW5zX2Vtb2Npb25lcyAlPiUNCiAgICBmaWx0ZXIoQ2FsaWZpY2FjaW9uID09ICAiTmVnYXRpdmEiKSAlPiUNCiAgICBncm91cF9ieShQYXJ0aWRvLCBQb2xpdGljbykgJT4lDQogICAgY291bnQoUGFsYWJyYSwgc29ydCA9IFQpICU+JQ0KICAgICBzbGljZV9tYXgob3JkZXJfYnkgPSBuLCBuPSAxMCkgJT4lDQogICAgICBmaWx0ZXIoUGFydGlkbyA9PSAgIlBSTyIpICU+JQ0KICAgIGdncGxvdCgpICsNCiAgICBhZXMoUGFsYWJyYSwgbiwgZmlsbCA9IFBvbGl0aWNvKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgZmFjZXRfd3JhcCgiUG9saXRpY28iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh0aXRsZSA9ICJQYWxhYnJhcyBOZWdhdGl2YXMgbcOhcyB1c2FkYXMiKSANCg0KIHR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgJT4lDQogICAgZmlsdGVyKENhbGlmaWNhY2lvbiA9PSAgIk5lZ2F0aXZhIikgJT4lDQogICAgZ3JvdXBfYnkoUGFydGlkbywgUG9saXRpY28pICU+JQ0KICAgIGNvdW50KFBhbGFicmEsIHNvcnQgPSBUKSAlPiUNCiAgICAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbj0gMTApICU+JQ0KICAgICAgZmlsdGVyKFBhcnRpZG8gPT0gICJQZXJvbmlzbW8iKSAlPiUNCiAgICBnZ3Bsb3QoKSArDQogICAgYWVzKFBhbGFicmEsIG4sIGZpbGwgPSBQb2xpdGljbykgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGZhY2V0X3dyYXAoIlBvbGl0aWNvIiwgc2NhbGVzID0gImZyZWUiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiUGFsYWJyYXMgTmVnYXRpdmFzIG3DoXMgdXNhZGFzIikgDQogDQogIHR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgJT4lDQogICAgZmlsdGVyKENhbGlmaWNhY2lvbiA9PSAgIk5lZ2F0aXZhIikgJT4lDQogICAgZ3JvdXBfYnkoUGFydGlkbywgUG9saXRpY28pICU+JQ0KICAgIGNvdW50KFBhbGFicmEsIHNvcnQgPSBUKSAlPiUNCiAgICAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbj0gMTApICU+JQ0KICAgICAgZmlsdGVyKFBhcnRpZG8gPT0gICJvdHJvcyBjYW5kaWRhdG9zIikgJT4lDQogICAgZ2dwbG90KCkgKw0KICAgIGFlcyhQYWxhYnJhLCBuLCBmaWxsID0gUG9saXRpY28pICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICBmYWNldF93cmFwKCJQb2xpdGljbyIsIHNjYWxlcyA9ICJmcmVlIikgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApKSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICBsYWJzKHRpdGxlID0gIlBhbGFicmFzIE5lZ2F0aXZhcyBtw6FzIHVzYWRhcyIpIA0KICANCiAgIHR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgJT4lDQogICAgZmlsdGVyKENhbGlmaWNhY2lvbiA9PSAgIk5lZ2F0aXZhIikgJT4lDQogICAgZ3JvdXBfYnkoUGFydGlkbywgUG9saXRpY28pICU+JQ0KICAgIGNvdW50KFBhbGFicmEsIHNvcnQgPSBUKSAlPiUNCiAgICAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbj0gMTApICU+JQ0KICAgICAgZmlsdGVyKFBhcnRpZG8gPT0gICJjdWVudGEgcGFydGlkYXJpYSIpICU+JQ0KICAgIGdncGxvdCgpICsNCiAgICBhZXMoUGFsYWJyYSwgbiwgZmlsbCA9IFBvbGl0aWNvKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgZmFjZXRfd3JhcCgiUG9saXRpY28iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh0aXRsZSA9ICJQYWxhYnJhcyBOZWdhdGl2YXMgbcOhcyB1c2FkYXMiKSANCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAgMTctIFNlbnRpbWllbnRvcyBlbiBlbCB0d2VldCA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNClZvbHZpZW5kbyBhIHVzYXIgbGEgcHVudHVhY2nDs24gZGVsIGRpY2Npb25hcmlvIGFmaW5uLCB2b2x2ZW1vcyBhIHVuaXIgbGFzIHBhbGFicmFzIGEgbG9zIHR3ZWV0cyB5IHNhY2Ftb3MgZWwgcHJvbWVkaW8gZGUgcHVudG9zIGRlIHRvZGFzIGxhcyBwYWxhYnJhcywgcGFzYW5kbyBkZWwgdmFsb3IgdW5pdGFyaW8gZGUgcGFsYWJyYSBhIHVuIHZhbG9yIHVuaXRhcmlvIHBvciBjYWRhIHR3ZWV0IHB1YmxpY2Fkby4NCg0KICAtICpMYSBtYXlvcsOtYSBkZSBsb3MgdHdlZXRzIGZ1ZXJvbiBuZXV0cm9zLioNCiAgDQogIC0gKkxvcyBtw6FzIHBvc2l0aXZvcyBlbiBlc3RlIHRyYW5zY3Vyc28gZnVlcm9uIE0uIE1hY3JpLCBBLiBGZXJuYW5kZXogeSBSLiBMYXZhZ25hLioNCiAgDQogIC0gKkxvcyBtw6FzIG5lZ2F0aXZvcyBmdWVyb24gTi4gRGVsIENhw7FvIHkgbGEgY3VlbnRhIG9maWNpYWwgZGVsIFBSTy4qDQoNCg0KYGBge3J9DQpUd2VldHNfREYgPC0NCiAgdHVpdHNfdG9rZW5zX2Vtb2Npb25lcyAlPiUNCiAgZ3JvdXBfYnkoc3RhdHVzX2lkKSAlPiUNCiAgc3VtbWFyaXNlKFB1bnR1YWNpb25fdHdlZXQueCA9IG1lYW4oUHVudHVhY2lvbikpICU+JQ0KICBsZWZ0X2pvaW4oVHdlZXRzX0RGLCAuLCBieSA9ICJzdGF0dXNfaWQiKQ0KDQoNClR3ZWV0c19ERiA8LSAgVHdlZXRzX0RGICU+JQ0KICBtdXRhdGUoUHVudHVhY2lvbl90d2VldC54X2xldHJhID0gaWZlbHNlKGlzLm5hKFB1bnR1YWNpb25fdHdlZXQueCksICJOZXV0cmFsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFB1bnR1YWNpb25fdHdlZXQueCA+IDAsICJQb3NpdGl2YSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFB1bnR1YWNpb25fdHdlZXQueCA9PSAwLCAiTmV1dHJhbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTmVnYXRpdmEiKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICkNCiAgKSAgICAgIA0KKQ0KDQpUd2VldHNfREYgJT4lDQogIGNvdW50KFBvbGl0aWNvLCBQYXJ0aWRvLCBQdW50dWFjaW9uX3R3ZWV0LnhfbGV0cmEpICU+JQ0KICBncm91cF9ieShQb2xpdGljbykgJT4lDQogIG11dGF0ZShQcm9wb3JjaW9uID0gbiAvIHN1bShuKSkgJT4lDQpnZ3Bsb3QoKSArDQogIGFlcyhQb2xpdGljbywgUHJvcG9yY2lvbiwgZmlsbCA9IFB1bnR1YWNpb25fdHdlZXQueF9sZXRyYSkgKw0KICBnZW9tX2NvbCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgICAgIGZhY2V0X3dyYXAoIlBhcnRpZG8iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpDQoNCg0KYGBgDQoNCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDE4LSBTZW50aW1pZW50b3MgZW4gZWwgdHdlZXQgUFJPIHZzIFBlcm9uaXNtbyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNClRvbWFtb3MgbG9zIDQgbWllbWJyb3MgcXVlIHlhIGFuYWxpemFtb3MgZGUgY2FkYSB1bm8gZGUgbG9zIHBhcnRpZG9zICooUFJPIHkgVG9kb3MpKiwgeSBsbyB1bmltb3MgZW4gdW4gc29sbyBncsOhZmljbyBwb3IgcGFydGlkbywgdmVtb3MgcXVlIGxhIGRpc3RyaWJ1Y2nDs24gZXMgYWxnbyBwYXJlY2lkbywgc2kgYmllbiBlbCBQZXJvbmlzbW8gdHV2byB1biBwb2NvIG3DoXMgZGUgdHdlZXRzIHBvc2l0aXZvcyB5IG1lbm9zIGRlIHR3ZWV0cyBuZWdhdGl2b3MsIHBlcm8gbm8gYSBuaXZlbGVzIHNpZ25pZmljYXRpdm9zLg0KDQoNCmBgYHtyfQ0KVHdlZXRzX0RGICU+JQ0KICBjb3VudChQYXJ0aWRvLCBQdW50dWFjaW9uX3R3ZWV0LnhfbGV0cmEpICU+JQ0KICBncm91cF9ieShQYXJ0aWRvKSAlPiUNCiAgZmlsdGVyKFBhcnRpZG8gPT0gIlBSTyIgfFBhcnRpZG8gPT0gIlBlcm9uaXNtbyIpJT4lDQogIG11dGF0ZShQcm9wb3JjaW9uID0gbiAvIHN1bShuKSkgJT4lDQpnZ3Bsb3QoKSArDQogIGFlcyhQYXJ0aWRvLCBQcm9wb3JjaW9uLCBmaWxsID0gUHVudHVhY2lvbl90d2VldC54X2xldHJhKSArDQogIGdlb21fY29sKCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikNCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAgMTktIFNlbnRpbWllbnRvIG1lcyBhIG1lcyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNCkxhIGlkZWEgZXMgYW5hbGl6YXIgc2kgaGF5IGZsdWN0dWFjaW9uZXMgZW4gbG8gcXVlIGhhbiBpZG8gdHdpdHRlYW5kbyBlbiBlbCB0cmFuc2N1cnNvIGRlbCB0aWVtcG8geSBzdXMgc2VudGltaWVudG9zLg0KDQogIC0gRW4gZWwgKipQUk8qKiBubyBodWJvIGdyYW5kZXMgY2FtYmlvcywgbG9zIMO6bHRpbW9zIHR3ZWV0cyBkZSBCdWxscmljaCBzb24gbcOhcyBwb3NpdGl2by4NCiAgDQogIC0gRW50cmUgbG9zIG90cm9zIGNhbmRpZGF0b3MgKipOaWNvbGFzIERlbCBDYcOxbyoqIHNpZW1wcmUgZXMgbmVnYXRpdm8sIHBlcm8gdmllbmUgc2llbmRvIG1lbm9zIG5lZ2F0aXZvIHVsdGltYW1lbnRlLg0KICANCiAgLSBFbnRyZSBlbCAqKkZyZW50ZSBkZSBUb2RvcyoqIGhheSBtdWNoYSBmbHVjdHVhY2nDs24sIGVsIFByZXNpZGVudGUgcGFyZWNlIGVzdGFyIGVuIHVuIGNhbWlubyBoYWNpYSBsYSBuZWdhdGl2aWRhZC4NCiAgDQoNCmBgYHtyfQ0KVHdlZXRzX0RGJFB1bnR1YWNpb25fdHdlZXQueCA9IGlmZWxzZShpcy5uYShUd2VldHNfREYkUHVudHVhY2lvbl90d2VldC54KSwgMCwgVHdlZXRzX0RGJFB1bnR1YWNpb25fdHdlZXQueCkNCg0KVHdlZXRzX0RGICU+JQ0KZ3JvdXBfYnkoUG9saXRpY28sIFBhcnRpZG8sIG1lcykgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICJQUk8iKSU+JQ0KICBzdW1tYXJpc2Uoc2VudGltaWVudG8gPSBtZWFuKFB1bnR1YWNpb25fdHdlZXQueCkpICU+JQ0KZ2dwbG90KCkgKw0KICBhZXMobWVzLCBzZW50aW1pZW50bywgY29sb3IgPSBQb2xpdGljbykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IC4zNSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGZhY2V0X2dyaWQoUG9saXRpY29+LikgKw0KICB0ZW1hMSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KVHdlZXRzX0RGICU+JQ0KZ3JvdXBfYnkoUG9saXRpY28sIFBhcnRpZG8sIG1lcykgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICJvdHJvcyBjYW5kaWRhdG9zIiklPiUNCiAgc3VtbWFyaXNlKHNlbnRpbWllbnRvID0gbWVhbihQdW50dWFjaW9uX3R3ZWV0LngpKSAlPiUNCmdncGxvdCgpICsNCiAgYWVzKG1lcywgc2VudGltaWVudG8sIGNvbG9yID0gUG9saXRpY28pICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAuMzUpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF9ncmlkKFBvbGl0aWNvfi4pICsNCiAgdGVtYTEgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNClR3ZWV0c19ERiAlPiUNCmdyb3VwX2J5KFBvbGl0aWNvLCBQYXJ0aWRvLCBtZXMpICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAiUGVyb25pc21vIiklPiUNCiAgc3VtbWFyaXNlKHNlbnRpbWllbnRvID0gbWVhbihQdW50dWFjaW9uX3R3ZWV0LngpKSAlPiUNCmdncGxvdCgpICsNCiAgYWVzKG1lcywgc2VudGltaWVudG8sIGNvbG9yID0gUG9saXRpY28pICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgYWxwaGEgPSAuMzUpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF9ncmlkKFBvbGl0aWNvfi4pICsNCiAgdGVtYTEgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNClR3ZWV0c19ERiAlPiUNCmdyb3VwX2J5KFBvbGl0aWNvLCBQYXJ0aWRvLCBtZXMpICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAiY3VlbnRhIHBhcnRpZGFyaWEiKSU+JQ0KICBzdW1tYXJpc2Uoc2VudGltaWVudG8gPSBtZWFuKFB1bnR1YWNpb25fdHdlZXQueCkpICU+JQ0KZ2dwbG90KCkgKw0KICBhZXMobWVzLCBzZW50aW1pZW50bywgY29sb3IgPSBQb2xpdGljbykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IC4zNSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGZhY2V0X2dyaWQoUG9saXRpY29+LikgKw0KICB0ZW1hMSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAgMjAtIEJveHBsb3Qgc2VudGltaWVudG9zIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCkxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIHNlbnRpbWllbnRvcyBlbnRyZSB0b2RvcyBsb3MgdHdlZXRzLCBhcXVlbGxvcyBxdWUgZXN0w6FuIGVuY2VycmFkb3MgZW4gbGFzIGNhamFzIHNvbiBsb3Mgbm9ybWFsZXMsIG1pZW50cmFzIHF1ZSBsb3MgcHVudG9zIHN1ZWx0b3Mgc29uIHR3ZWV0cyBhaXNsYWRvcyBhIGxvIHF1ZSBzdWVsZW4gZXNjcmliaXIuDQoNCiAgLSAqRXNwZXJ0IG5vIHByZXNlbnRhIG5pbmd1biB0aXBvIGRlIHBhdHLDs24gZGUgc2VudGltaWVudG9zKg0KDQoNCmBgYHtyfQ0KVHdlZXRzX0RGICU+JQ0KICBnZ3Bsb3QoKSArDQogIGFlcyhQb2xpdGljbywgUHVudHVhY2lvbl90d2VldC54LCBmaWxsID0gUG9saXRpY28pICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBjb29yZF9mbGlwKCkgKyANCiAgbGFicyh5PSAiU2VudGltaWVudG8iKSArDQogIHRlbWExDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMjEtIENvcnJlbGFjacOzbiBlbnRyZSBsbyB0d2l0dGVhZG8gUFJPIHZzIFBlcm9uaXNtbzwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNClNlIGJ1c2NhIGEgdHJhdsOpcyBkZSBsYXMgcGFsYWJyYXMgcXVlIHV0aWxpemFyb24gY3VhbCBlcyBsYSBjb3JyZWxhY2nDs24gcXVlIGhheSBlbnRyZSBsb3MgZGlzdGludG9zIHBvbMOtdGljb3MgeSBzdXMgdHdlZXRzLCB5IHNlIHB1ZWRlbiByZWFsaXphciB2YXJpYXMgb2JzZXJ2YWNpb25lczoNCg0KICAtICpRdWlyw7NzIHkgTGFycmV0YSBzb24gbG9zIGRlIG1heW9yIGNvcnJlbGFjacOzbiwgZGVtb3N0cmFuZG8gdW4gYnVlbiBtYW5lam8gZGUgbGEgY29tdW5pY2FjacOzbiBwb3J0ZcOxYSwgZG9uZGUgYW1ib3Mgc2lndWVuIGVuIG1pc21hIGRpcmVjY2nDs24uKg0KDQogIC0gKk1hY3JpIGVzIGVsIGRlIG1lbm9yIGNvcnJlbGFjacOzbiBjb24gZWwgcmVzdG8gZGUgbG9zIHBhcnRpY2lwYW50ZXMsIHBlcm8gYXPDrSBtaXNtbyB0aWVuZSBsw7NnaWNhIHF1ZSBzdSBtYXlvciBuaXZlbCBkZSByZWxhY2nDs24gbG8gdGVuZ2EgY29uIEJ1bGxyaWNoLioNCg0KICAtICpFbnRyZSBLaWNpbG9mZiB5IEdpbmVzLCBoYXkgdW5hIHJlbGFjacOzbiBpbXBvcnRhbnRlLCBhc8OtIGNvbW8gdGFtYmnDqW4gZGUgZWxsb3MgZG9zIGNvbiBzdXMgc2ltaWxhcmVzIHBvcnRlw7FvcyAoUXVpcsOzcyB5IExhcnJldGEpLioNCg0KICAtICpDcmlzdGluYSBLaXJjaG5lciBlcyBvdHJhIHF1ZSBubyB0aWVuZSB1biBhbHRvIG5pdmVsIGRlIHJlbGFjacOzbiBlbiBzdXMgdHdlZXRzIGNvbiBvdHJvcyBwb2zDrXRpY29zLioNCg0KICAtICpFcyBzb3JwcmVuZGVudGUgcXVlIHVubyBkZSBsb3MgbWF5b3JlcyBuaXZlbGVzIGRlIHJlbGFjacOzbiBlbiBjdWFudG8gbG8gcXVlIHNlIGNvbXVuaWNhIGVzdGUgZW50cmUgQWxiZXJ0byBGZXJuw6FuZGV6IHkgUGF0cmljaWEgQnVsbHJpY2guKg0KDQoNCg0KYGBge3J9DQp0d2VldHNfc3ByZWFkMiA8LSB0dWl0c190b2tlbnMgJT4lIA0KIGZpbHRlcihQYXJ0aWRvID09ICAiUFJPIiB8IFBhcnRpZG8gPT0gIlBlcm9uaXNtbyIpJT4lIA0KICBncm91cF9ieShQb2xpdGljbywgUGFsYWJyYSkgJT4lIA0KICBjb3VudChQYWxhYnJhKSAlPiUNCiAgICAgIHNwcmVhZChrZXkgPSBQb2xpdGljbywgdmFsdWUgPSBuLCBmaWxsID0gTkEsIGRyb3AgPSBUUlVFKQ0KdHdlZXRzX3NwcmVhZDJbaXMubmEodHdlZXRzX3NwcmVhZDIpXSA8LSAwDQoNCm5hbWVzKHR3ZWV0c19zcHJlYWQyKSA8LSBjKCJQYWxhYnJhIiwgIkEuRmVybmFuZGV6IiwgIkEuS2ljaWxsb2YiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIkMuS2lyY2huZXIiLCAiRi5RdWlyb3MiLCAiR2luZXMuR0ciLCJILkxhcnJldGEiLCAiTS5NYWNyaSIsICJQLkJ1bGxyaWNoIiApDQoNCm1ldGhvZCA8LSAicGVhcnNvbiINCm1fY29yIDwtIG1hdHJpeChucm93ID0gOCwgbmNvbCA9IDgpDQpmb3IgKGkgaW4gMTpkaW0obV9jb3IpWzFdKSB7DQogICAgICBmb3IgKGogaW4gMTpkaW0obV9jb3IpWzJdKSB7DQogICAgICAgICAgICBmb3JtIDwtIGFzLmZvcm11bGEocGFzdGUoIn4iLCBuYW1lcyh0d2VldHNfc3ByZWFkMilbaSsxXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIrIiwgbmFtZXModHdlZXRzX3NwcmVhZDIpW2orMV0pKQ0KICAgICAgICAgICAgaWYoaSE9ail7DQogICAgICAgICAgICAgICAgICBtX2NvcltpLGpdIDwtIGNvci50ZXN0KGZvcm0sIG1ldGhvZCA9IG1ldGhvZCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSB0d2VldHNfc3ByZWFkMikkZXN0aW1hdGUNCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgIGlmKGk9PWope21fY29yW2ksal0gPC0gMX0NCiAgICAgIH0NCn0NCmNvbG5hbWVzKG1fY29yKSA8LSBuYW1lcyh0d2VldHNfc3ByZWFkMilbMjo5XQ0Kcm93bmFtZXMobV9jb3IpIDwtIG5hbWVzKHR3ZWV0c19zcHJlYWQyKVsyOjldDQpjb3JycGxvdChtX2NvciwgbWV0aG9kPSJjb2xvciIsIHR5cGU9InVwcGVyIiwgb3JkZXI9ImhjbHVzdCIsIA0KICAgICAgICAgYWRkQ29lZi5jb2wgPSAiYmxhY2siLCB0bC5jb2w9ImJsYWNrIiwgdGwuc3J0PTQ1LA0KICAgICAgICAgc2lnLmxldmVsID0gMC4wMSwgaW5zaWcgPSAiYmxhbmsiLCBkaWFnPUZBTFNFKQ0KDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMjItIENvcnJlbGFjacOzbiBlbnRyZSBsbyB0d2l0dGVhZG8gY2FuZGlkYXRvcyBhIHByZXNpZGVudGUuIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KLQlMYSByZWxhY2nDs24gZW50cmUgbG8gcXVlIGVzY3JpYmVuIGxvcyBjYW5kaWRhdG9zIHRpZW5lIHVuIGNsw7pzdGVyIHF1ZSBzZSBkZXN0YWNhIHNvYnJlIGVsIHJlc3RvIHF1ZSBlcyBsYSByZWxhY2nDs24gZW50cmUgRXNwZXJ0LCBHw7NtZXogQ2VudHVyacOzbiB5IEFsYmVydG8gRmVybsOhbmRlei4NCg0KLQlOaWNvbGFzIERlbCBDYcOxbyB0aWVuZSB1biBhbHRvIG5pdmVsIGRlIHJlbGFjacOzbiBjb24gR8OzbWV6IENlbnR1cmnDs24sIHkgZW4gbWVkaWRhIG1lZGlhbmEgY29uIEFsYmVydG8gRmVybsOhbmRleiB5IEVzcGVydC4NCg0KLQlMYXZhZ25hIHkgTWFjcmkgbm8gcHJlc2VudGFuIHVuYSBncmFuIGNvcnJlbGFjacOzbiBjb24gZWwgcmVzdG8gZGUgbG9zIHBvbMOtdGljb3MuDQoNCg0KYGBge3J9DQp0d2VldHNfc3ByZWFkMiA8LSB0dWl0c190b2tlbnMgJT4lIA0KICBmaWx0ZXIoUGFydGlkbyA9PSAgIm90cm9zIGNhbmRpZGF0b3MiIHwgUG9saXRpY28gPT0gIkEuRmVybmFuZGV6InwgUG9saXRpY28gPT0gIk0uTWFjcmkiKSU+JSANCiAgZ3JvdXBfYnkoUG9saXRpY28sIFBhbGFicmEpICU+JSANCiAgY291bnQoUGFsYWJyYSkgJT4lDQogICAgICBzcHJlYWQoa2V5ID0gUG9saXRpY28sIHZhbHVlID0gbiwgZmlsbCA9IE5BLCBkcm9wID0gVFJVRSkNCnR3ZWV0c19zcHJlYWQyW2lzLm5hKHR3ZWV0c19zcHJlYWQyKV0gPC0gMA0KDQpuYW1lcyh0d2VldHNfc3ByZWFkMikgPC0gYygiUGFsYWJyYSIsICJBLkZlcm5hbmRleiIsICJKLkVzcGVydCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiR29tZXpDZW50dXJpb24iLCAiTS5NYWNyaSIsICJOLkRlbENhw7FvIiwiUi5MYXZhZ25hIikNCg0KbWV0aG9kIDwtICJwZWFyc29uIg0KbV9jb3IgPC0gbWF0cml4KG5yb3cgPSA2LCBuY29sID0gNikNCmZvciAoaSBpbiAxOmRpbShtX2NvcilbMV0pIHsNCiAgICAgIGZvciAoaiBpbiAxOmRpbShtX2NvcilbMl0pIHsNCiAgICAgICAgICAgIGZvcm0gPC0gYXMuZm9ybXVsYShwYXN0ZSgifiIsIG5hbWVzKHR3ZWV0c19zcHJlYWQyKVtpKzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIisiLCBuYW1lcyh0d2VldHNfc3ByZWFkMilbaisxXSkpDQogICAgICAgICAgICBpZihpIT1qKXsNCiAgICAgICAgICAgICAgICAgIG1fY29yW2ksal0gPC0gY29yLnRlc3QoZm9ybSwgbWV0aG9kID0gbWV0aG9kLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHR3ZWV0c19zcHJlYWQyKSRlc3RpbWF0ZQ0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgaWYoaT09ail7bV9jb3JbaSxqXSA8LSAxfQ0KICAgICAgfQ0KfQ0KY29sbmFtZXMobV9jb3IpIDwtIG5hbWVzKHR3ZWV0c19zcHJlYWQyKVsyOjddDQpyb3duYW1lcyhtX2NvcikgPC0gbmFtZXModHdlZXRzX3NwcmVhZDIpWzI6N10NCmNvcnJwbG90KG1fY29yLCBtZXRob2Q9ImNvbG9yIiwgdHlwZT0idXBwZXIiLCBvcmRlcj0iaGNsdXN0IiwgDQogICAgICAgICBhZGRDb2VmLmNvbCA9ICJibGFjayIsIHRsLmNvbD0iYmxhY2siLCB0bC5zcnQ9NDUsDQogICAgICAgICBzaWcubGV2ZWwgPSAwLjAxLCBpbnNpZyA9ICJibGFuayIsIGRpYWc9RkFMU0UpDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMjMtIENvcnJlbGFjacOzbiBlbnRyZSBsbyB0d2l0dGVhZG8gZW50cmUgY3VlbnRhcyBwYXJ0aWRhcmlhczwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KRXN0ZSBwdWVkZSBzZXIgdW4gYW7DoWxpc2lzIGludGVyZXNhbnRlLCB5YSBxdWUgbGEgY2FudGlkYWQgZGUgdHdlZXRzIGVzIHNpZ25pZmljYXRpdmEgcGFyYSB0b2Rvcy4NCg0KLQlTb3JwcmVzaXZhbWVudGUgZWwgbcOheGltbyBuaXZlbCBkZSByZWxhY2nDs24gc2UgZGEgZW50cmUgbGEgVUNSIHkgVE9ET1MsIGRvcyBwYXJ0aWRvcyBxdWUgaG95IHNlIHByZXNlbnRhbiBjb21vIG9wdWVzdG8NCg0KLQlUaWVuZSBtYXlvciBsw7NnaWNhIGxhIGFsdGEgcmVsYWNpw7NuIGVudHJlIGVsIFBSTyB5IGxhIFVDUi4NCg0KLQlFbCBHRU4gcGFyZWNpZXJhIHNlciBlbCBwYXJ0aWRvIHF1ZSBlc2NyaWJlIGRlIG1hbmVyYSBtw6FzIGRpc3RpbnRhIGFsIHJlc3RvLg0KDQotCVNpbiBlbWJhcmdvLCBwb2RlbW9zIG5vdGFyIHF1ZSwgYSBkaWZlcmVuY2lhIGRlIGxhcyBjdWVudGFzIGluZGl2aWR1YWxlcywgbGFzIHBhcnRpZGFyaWFzIHRpZW5lbiBtw6FzIHJlbGFjacOzbiwgcG9yIHN1IGxlbmd1YWplIG3DoXMgbmV1dHJvIHkgY29tdW5pY2FjacOzbiBvcmfDoW5pY2EuDQoNCg0KYGBge3J9DQp0d2VldHNfc3ByZWFkMiA8LSB0dWl0c190b2tlbnMgJT4lIA0KICBmaWx0ZXIoUGFydGlkbyA9PSAgImN1ZW50YSBwYXJ0aWRhcmlhIiklPiUgDQogIGdyb3VwX2J5KFBvbGl0aWNvLCBQYWxhYnJhKSAlPiUgDQogIGNvdW50KFBhbGFicmEpICU+JQ0KICAgICAgc3ByZWFkKGtleSA9IFBvbGl0aWNvLCB2YWx1ZSA9IG4sIGZpbGwgPSBOQSwgZHJvcCA9IFRSVUUpDQp0d2VldHNfc3ByZWFkMltpcy5uYSh0d2VldHNfc3ByZWFkMildIDwtIDANCg0KbmFtZXModHdlZXRzX3NwcmVhZDIpIDwtIGMoIlBhbGFicmEiLCAiR0VOIiwgIlBSTyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiVE9ET1MiLCAiVUNSIikNCg0KbWV0aG9kIDwtICJwZWFyc29uIg0KbV9jb3IgPC0gbWF0cml4KG5yb3cgPSA0LCBuY29sID0gNCkNCmZvciAoaSBpbiAxOmRpbShtX2NvcilbMV0pIHsNCiAgICAgIGZvciAoaiBpbiAxOmRpbShtX2NvcilbMl0pIHsNCiAgICAgICAgICAgIGZvcm0gPC0gYXMuZm9ybXVsYShwYXN0ZSgifiIsIG5hbWVzKHR3ZWV0c19zcHJlYWQyKVtpKzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIisiLCBuYW1lcyh0d2VldHNfc3ByZWFkMilbaisxXSkpDQogICAgICAgICAgICBpZihpIT1qKXsNCiAgICAgICAgICAgICAgICAgIG1fY29yW2ksal0gPC0gY29yLnRlc3QoZm9ybSwgbWV0aG9kID0gbWV0aG9kLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHR3ZWV0c19zcHJlYWQyKSRlc3RpbWF0ZQ0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgaWYoaT09ail7bV9jb3JbaSxqXSA8LSAxfQ0KICAgICAgfQ0KfQ0KY29sbmFtZXMobV9jb3IpIDwtIG5hbWVzKHR3ZWV0c19zcHJlYWQyKVsyOjVdDQpyb3duYW1lcyhtX2NvcikgPC0gbmFtZXModHdlZXRzX3NwcmVhZDIpWzI6NV0NCmNvcnJwbG90KG1fY29yLCBtZXRob2Q9ImNvbG9yIiwgdHlwZT0idXBwZXIiLCBvcmRlcj0iaGNsdXN0IiwgDQogICAgICAgICBhZGRDb2VmLmNvbCA9ICJibGFjayIsIHRsLmNvbD0iYmxhY2siLCB0bC5zcnQ9NDUsDQogICAgICAgICBzaWcubGV2ZWwgPSAwLjAxLCBpbnNpZyA9ICJibGFuayIsIGRpYWc9RkFMU0UpDQpgYGANCg0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAyNC0gQ29tcGFyYWNpw7NuIGRlIHVzbyBkZSBwYWxhYnJhcyBNYWNyaSB2cyBGZXJuYW5kZXogPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpMYSBpZGVhIGRlIGVzdGUgZ3LDoWZpY28gZXMgZGUgbW9zdHJhciBjdWFsZXMgc29uIGxhcyBwYWxhYnJhcyBtw6FzIGRpZmVyZW5jaWFzIGVuIHN1IHVzbywgZW4gZXN0ZSBjYXNvIGVudHJlICpNYXVyaWNpbyBNYWNyaSogeSAqQWxiZXJ0byBGZXJuw6FuZGV6Kg0KDQoNCmBgYHtyfQ0KDQojIFBpdm90YWplIHkgZGVzcGl2b3RhamUNCnR3ZWV0c191bnBpdm90IDwtIHR1aXRzX3Rva2VucyAlPiUgZ3JvdXBfYnkoUG9saXRpY28sIFBhbGFicmEpICU+JQ0KICAgICAgY291bnQoUGFsYWJyYSkgJT4lDQogICAgICBzcHJlYWQoa2V5ID0gUG9saXRpY28sIHZhbHVlID0gbiwgZmlsbCA9IDAsIGRyb3AgPSBUUlVFKSAlPiUgDQogICAgICBnYXRoZXIoa2V5ID0gIlBvbGl0aWNvIiwgdmFsdWUgPSAibiIsIC1QYWxhYnJhKQ0KDQoNCiAgICAgICAgICAgICAgICAgICMgU2VsZWNjacOzbiBkZSBsb3MgYXV0b3Jlcw0KICAgICAgICAgICAgICAgICAgdHdlZXRzX3VucGl2b3QyIDwtIHR3ZWV0c191bnBpdm90ICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihQb2xpdGljbyAlaW4lIGMoIk0uTWFjcmkiLCAiQS5GZXJuYW5kZXoiKSkNCiAgICAgICAgICAgICAgICAgICMgU2UgYcOxYWRlIGVsIHRvdGFsIGRlIHBhbGFicmFzIGRlIGNhZGEgYXV0b3INCiAgICAgICAgICAgICAgICAgIHR3ZWV0c191bnBpdm90MiA8LSB0d2VldHNfdW5waXZvdDIgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oVHdlZXRzX0RGICU+JSBncm91cF9ieShQb2xpdGljbykgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKE4gPSBuKCkpLCBieSA9ICJQb2xpdGljbyIpDQogICAgICAgICAgICAgICAgICAjIEPDoWxjdWxvIGRlIG9kZHMgeSBsb2cgb2Ygb2RkcyBkZSBjYWRhIHBhbGFicmENCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzIDwtIHR3ZWV0c191bnBpdm90MiAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUob2RkcyA9IChuICsgMSkgLyAoTiArIDEpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChQb2xpdGljbywgUGFsYWJyYSwgb2RkcykgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgc3ByZWFkKGtleSA9IFBvbGl0aWNvLCB2YWx1ZSA9IG9kZHMpDQogICAgICAgICAgICAgICAgICB0d2VldHNfbG9nT2Rkc1ssNF0gPC0gbG9nKHR3ZWV0c19sb2dPZGRzWywyXS90d2VldHNfbG9nT2Rkc1ssM10pDQogICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbNF0gPC0gImxvZ19vZGRzIg0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHNbLDVdIDwtIGFicyh0d2VldHNfbG9nT2RkcyRsb2dfb2RkcykNCiAgICAgICAgICAgICAgICAgIG5hbWVzKHR3ZWV0c19sb2dPZGRzKVs1XSA8LSAiYWJzX2xvZ19vZGRzIg0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHMgPC0gdHdlZXRzX2xvZ09kZHMgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYXV0b3JfZnJlY3VlbnRlID0gaWZfZWxzZShsb2dfb2RkcyA+IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbMl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbM10pKQ0KDQpEaWZlcmVuY2lhX0FGIDwtIHR3ZWV0c19sb2dPZGRzICU+JSANCiAgYXJyYW5nZSgtYWJzX2xvZ19vZGRzLCBieWdyb3VwID0gRkFMU0UpJT4lIA0KICBmaWx0ZXIoYXV0b3JfZnJlY3VlbnRlID09ICJBLkZlcm5hbmRleiIpJT4lIA0KICBoZWFkKDE1KQ0KDQpEaWZlcmVuY2lhX01NIDwtIHR3ZWV0c19sb2dPZGRzICU+JSANCiAgYXJyYW5nZShsb2dfb2RkcywgYnlncm91cCA9IEZBTFNFKSU+JSANCiAgZmlsdGVyKGF1dG9yX2ZyZWN1ZW50ZSA9PSAiTS5NYWNyaSIpJT4lIA0KICBoZWFkKDE1KQ0KDQpEaWZlcmVuY2lhX0FGX01NIDwtIHJiaW5kKERpZmVyZW5jaWFfQUYsRGlmZXJlbmNpYV9NTSkNCg0KRGlmZXJlbmNpYV9BRl9NTSU+JSANCiAgICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKFBhbGFicmEsIGxvZ19vZGRzKSwgeT0gbG9nX29kZHMsIGZpbGwgPSBhdXRvcl9mcmVjdWVudGUpKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgbGFicyh4ID0gIi1wYWxhYnJhIiwgeSA9ICJVc28iLCB0aXRsZSA9ICJGZXJuYW5kZXogdnMgTWFjcmkiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRlbWEyDQoNCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAyNS0gQ29tcGFyYWNpw7NuIGRlIHVzbyBkZSBwYWxhYnJhcyBMYXJyZXRhIHZzIEtpY2lsbG9mIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KTGEgaWRlYSBkZSBlc3RlIGdyw6FmaWNvIGVzIGRlIG1vc3RyYXIgY3VhbGVzIHNvbiBsYXMgcGFsYWJyYXMgbcOhcyBkaWZlcmVuY2lhcyBlbiBzdSB1c28sIGVuIGVzdGUgY2FzbyBlbnRyZSAqSG9yYWNpbyBMYXJyZXRhKiB5ICpBeGVsIEtpY2lsbG9mKg0KDQoNCg0KYGBge3J9DQoNCg0KIyBQaXZvdGFqZSB5IGRlc3Bpdm90YWplDQp0d2VldHNfdW5waXZvdCA8LSB0dWl0c190b2tlbnMgJT4lIGdyb3VwX2J5KFBvbGl0aWNvLCBQYWxhYnJhKSAlPiUNCiAgICAgIGNvdW50KFBhbGFicmEpICU+JQ0KICAgICAgc3ByZWFkKGtleSA9IFBvbGl0aWNvLCB2YWx1ZSA9IG4sIGZpbGwgPSAwLCBkcm9wID0gVFJVRSkgJT4lIA0KICAgICAgZ2F0aGVyKGtleSA9ICJQb2xpdGljbyIsIHZhbHVlID0gIm4iLCAtUGFsYWJyYSkNCg0KDQogICAgICAgICAgICAgICAgICAjIFNlbGVjY2nDs24gZGUgbG9zIGF1dG9yZXMNCiAgICAgICAgICAgICAgICAgIHR3ZWV0c191bnBpdm90MiA8LSB0d2VldHNfdW5waXZvdCAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoUG9saXRpY28gJWluJSBjKCJILkxhcnJldGEiLCAiQS5LaWNpbGxvZiIpKQ0KICAgICAgICAgICAgICAgICAgIyBTZSBhw7FhZGUgZWwgdG90YWwgZGUgcGFsYWJyYXMgZGUgY2FkYSBhdXRvcg0KICAgICAgICAgICAgICAgICAgdHdlZXRzX3VucGl2b3QyIDwtIHR3ZWV0c191bnBpdm90MiAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgIGxlZnRfam9pbihUd2VldHNfREYgJT4lIGdyb3VwX2J5KFBvbGl0aWNvKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoTiA9IG4oKSksIGJ5ID0gIlBvbGl0aWNvIikNCiAgICAgICAgICAgICAgICAgICMgQ8OhbGN1bG8gZGUgb2RkcyB5IGxvZyBvZiBvZGRzIGRlIGNhZGEgcGFsYWJyYQ0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHMgPC0gdHdlZXRzX3VucGl2b3QyICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShvZGRzID0gKG4gKyAxKSAvIChOICsgMSkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KFBvbGl0aWNvLCBQYWxhYnJhLCBvZGRzKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBzcHJlYWQoa2V5ID0gUG9saXRpY28sIHZhbHVlID0gb2RkcykgDQogICAgICAgICAgICAgICAgICB0d2VldHNfbG9nT2Rkc1ssNF0gPC0gbG9nKHR3ZWV0c19sb2dPZGRzWywyXS90d2VldHNfbG9nT2Rkc1ssM10pDQogICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbNF0gPC0gImxvZ19vZGRzIg0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHNbLDVdIDwtIGFicyh0d2VldHNfbG9nT2RkcyRsb2dfb2RkcykNCiAgICAgICAgICAgICAgICAgIG5hbWVzKHR3ZWV0c19sb2dPZGRzKVs1XSA8LSAiYWJzX2xvZ19vZGRzIg0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHMgPC0gdHdlZXRzX2xvZ09kZHMgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYXV0b3JfZnJlY3VlbnRlID0gaWZfZWxzZShsb2dfb2RkcyA+IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbMl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbM10pKQ0KDQpEaWZlcmVuY2lhX0FLIDwtIHR3ZWV0c19sb2dPZGRzICU+JSANCiAgYXJyYW5nZSgtbG9nX29kZHMsIGJ5Z3JvdXAgPSBGQUxTRSklPiUgDQogIGZpbHRlcihhdXRvcl9mcmVjdWVudGUgPT0gIkEuS2ljaWxsb2YiKSU+JSANCiAgaGVhZCgxNSkNCg0KRGlmZXJlbmNpYV9ITCA8LSB0d2VldHNfbG9nT2RkcyAlPiUgDQogIGFycmFuZ2UoYWJzX2xvZ19vZGRzLCBieWdyb3VwID0gRkFMU0UpJT4lIA0KICBmaWx0ZXIoYXV0b3JfZnJlY3VlbnRlID09ICJILkxhcnJldGEiKSU+JSANCiAgdGFpbCgxNSkNCg0KRGlmZXJlbmNpYV9BS19ITCA8LSByYmluZChEaWZlcmVuY2lhX0FLLERpZmVyZW5jaWFfSEwpDQoNCkRpZmVyZW5jaWFfQUtfSEwlPiUgDQogICAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihQYWxhYnJhLCBsb2dfb2RkcyksIHk9IGxvZ19vZGRzLCBmaWxsID0gYXV0b3JfZnJlY3VlbnRlKSkgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGxhYnMoeCA9ICItcGFsYWJyYSIsIHkgPSAiVXNvIiwgdGl0bGUgPSAiS2ljaWxsb2YgdnMgTGFycmV0YSIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGVtYTINCg0KYGBgDQoNCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDI2LSBDb21wYXJhY2nDs24gZGUgdXNvIGRlIHBhbGFicmFzIEdpbmVzIHZzIFF1aXLDs3MgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpMYSBpZGVhIGRlIGVzdGUgZ3LDoWZpY28gZXMgZGUgbW9zdHJhciBjdWFsZXMgc29uIGxhcyBwYWxhYnJhcyBtw6FzIGRpZmVyZW5jaWFzIGVuIHN1IHVzbywgZW4gZXN0ZSBjYXNvIGVudHJlICpHaW5lcyBHb256YWxleiogeSAqRmVybsOhbiBRdWlyw7NzKg0KDQoNCmBgYHtyfQ0KdHdlZXRzX3VucGl2b3QgPC0gdHVpdHNfdG9rZW5zICU+JSBncm91cF9ieShQb2xpdGljbywgUGFsYWJyYSkgJT4lDQogICAgICBjb3VudChQYWxhYnJhKSAlPiUNCiAgICAgIHNwcmVhZChrZXkgPSBQb2xpdGljbywgdmFsdWUgPSBuLCBmaWxsID0gMCwgZHJvcCA9IFRSVUUpICU+JSANCiAgICAgIGdhdGhlcihrZXkgPSAiUG9saXRpY28iLCB2YWx1ZSA9ICJuIiwgLVBhbGFicmEpDQoNCg0KICAgICAgICAgICAgICAgICAgIyBTZWxlY2Npw7NuIGRlIGxvcyBhdXRvcmVzDQogICAgICAgICAgICAgICAgICB0d2VldHNfdW5waXZvdDIgPC0gdHdlZXRzX3VucGl2b3QgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKFBvbGl0aWNvICVpbiUgYygiR2luZXMuR0ciLCAiRi5RdWlyb3MiKSkNCiAgICAgICAgICAgICAgICAgICMgU2UgYcOxYWRlIGVsIHRvdGFsIGRlIHBhbGFicmFzIGRlIGNhZGEgYXV0b3INCiAgICAgICAgICAgICAgICAgIHR3ZWV0c191bnBpdm90MiA8LSB0d2VldHNfdW5waXZvdDIgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oVHdlZXRzX0RGICU+JSBncm91cF9ieShQb2xpdGljbykgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKE4gPSBuKCkpLCBieSA9ICJQb2xpdGljbyIpDQogICAgICAgICAgICAgICAgICAjIEPDoWxjdWxvIGRlIG9kZHMgeSBsb2cgb2Ygb2RkcyBkZSBjYWRhIHBhbGFicmENCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzIDwtIHR3ZWV0c191bnBpdm90MiAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUob2RkcyA9IChuICsgMSkgLyAoTiArIDEpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChQb2xpdGljbywgUGFsYWJyYSwgb2RkcykgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgc3ByZWFkKGtleSA9IFBvbGl0aWNvLCB2YWx1ZSA9IG9kZHMpIA0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHNbLDRdIDwtIGxvZyh0d2VldHNfbG9nT2Rkc1ssMl0vdHdlZXRzX2xvZ09kZHNbLDNdKQ0KICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzRdIDwtICJsb2dfb2RkcyINCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzWyw1XSA8LSBhYnModHdlZXRzX2xvZ09kZHMkbG9nX29kZHMpDQogICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbNV0gPC0gImFic19sb2dfb2RkcyINCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzIDwtIHR3ZWV0c19sb2dPZGRzICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGF1dG9yX2ZyZWN1ZW50ZSA9IGlmX2Vsc2UobG9nX29kZHMgPiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzNdKSkNCg0KRGlmZXJlbmNpYV9HRyA8LSB0d2VldHNfbG9nT2RkcyAlPiUgDQogIGFycmFuZ2UoLWxvZ19vZGRzLCBieWdyb3VwID0gRkFMU0UpJT4lIA0KICBmaWx0ZXIoYXV0b3JfZnJlY3VlbnRlID09ICJHaW5lcy5HRyIpJT4lIA0KICB0YWlsKDE1KQ0KDQpEaWZlcmVuY2lhX0ZRIDwtIHR3ZWV0c19sb2dPZGRzICU+JSANCiAgYXJyYW5nZSgtYWJzX2xvZ19vZGRzLCBieWdyb3VwID0gRkFMU0UpJT4lIA0KICBmaWx0ZXIoYXV0b3JfZnJlY3VlbnRlID09ICJGLlF1aXJvcyIpJT4lIA0KICBoZWFkKDE1KQ0KDQpEaWZlcmVuY2lhX0dHX0ZRIDwtIHJiaW5kKERpZmVyZW5jaWFfR0csRGlmZXJlbmNpYV9GUSkNCg0KRGlmZXJlbmNpYV9HR19GUSU+JSANCiAgICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKFBhbGFicmEsIGxvZ19vZGRzKSwgeT0gbG9nX29kZHMsIGZpbGwgPSBhdXRvcl9mcmVjdWVudGUpKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgbGFicyh4ID0gIi1wYWxhYnJhIiwgeSA9ICJVc28iLCB0aXRsZSA9ICJRdWlyw7NzIHZzIEdpbmVzIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0ZW1hMg0KYGBgDQoNCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDI3LSBDb21wYXJhY2nDs24gZGUgdXNvIGRlIHBhbGFicmFzIEJ1bGxyaWNoIHZzIENyaXN0aW5hIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KTGEgaWRlYSBkZSBlc3RlIGdyw6FmaWNvIGVzIGRlIG1vc3RyYXIgY3VhbGVzIHNvbiBsYXMgcGFsYWJyYXMgbcOhcyBkaWZlcmVuY2lhcyBlbiBzdSB1c28sIGVuIGVzdGUgY2FzbyBlbnRyZSAqQ3Jpc3RpbmEgS2lyY2huZXIqIHkgKlBhdHJpY2lhIEJ1bGxyaWNoKg0KDQoNCmBgYHtyfQ0KdHdlZXRzX3VucGl2b3QgPC0gdHVpdHNfdG9rZW5zICU+JSBncm91cF9ieShQb2xpdGljbywgUGFsYWJyYSkgJT4lDQogICAgICBjb3VudChQYWxhYnJhKSAlPiUNCiAgICAgIHNwcmVhZChrZXkgPSBQb2xpdGljbywgdmFsdWUgPSBuLCBmaWxsID0gMCwgZHJvcCA9IFRSVUUpICU+JSANCiAgICAgIGdhdGhlcihrZXkgPSAiUG9saXRpY28iLCB2YWx1ZSA9ICJuIiwgLVBhbGFicmEpDQoNCg0KICAgICAgICAgICAgICAgICAgIyBTZWxlY2Npw7NuIGRlIGxvcyBhdXRvcmVzDQogICAgICAgICAgICAgICAgICB0d2VldHNfdW5waXZvdDIgPC0gdHdlZXRzX3VucGl2b3QgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKFBvbGl0aWNvICVpbiUgYygiUC5CdWxscmljaCIsICJDLktpcmNobmVyIikpDQogICAgICAgICAgICAgICAgICAjIFNlIGHDsWFkZSBlbCB0b3RhbCBkZSBwYWxhYnJhcyBkZSBjYWRhIGF1dG9yDQogICAgICAgICAgICAgICAgICB0d2VldHNfdW5waXZvdDIgPC0gdHdlZXRzX3VucGl2b3QyICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKFR3ZWV0c19ERiAlPiUgZ3JvdXBfYnkoUG9saXRpY28pICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShOID0gbigpKSwgYnkgPSAiUG9saXRpY28iKQ0KICAgICAgICAgICAgICAgICAgIyBDw6FsY3VsbyBkZSBvZGRzIHkgbG9nIG9mIG9kZHMgZGUgY2FkYSBwYWxhYnJhDQogICAgICAgICAgICAgICAgICB0d2VldHNfbG9nT2RkcyA8LSB0d2VldHNfdW5waXZvdDIgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKG9kZHMgPSAobiArIDEpIC8gKE4gKyAxKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoUG9saXRpY28sIFBhbGFicmEsIG9kZHMpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNwcmVhZChrZXkgPSBQb2xpdGljbywgdmFsdWUgPSBvZGRzKSANCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzWyw0XSA8LSBsb2codHdlZXRzX2xvZ09kZHNbLDJdL3R3ZWV0c19sb2dPZGRzWywzXSkNCiAgICAgICAgICAgICAgICAgIG5hbWVzKHR3ZWV0c19sb2dPZGRzKVs0XSA8LSAibG9nX29kZHMiDQogICAgICAgICAgICAgICAgICB0d2VldHNfbG9nT2Rkc1ssNV0gPC0gYWJzKHR3ZWV0c19sb2dPZGRzJGxvZ19vZGRzKQ0KICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzVdIDwtICJhYnNfbG9nX29kZHMiDQogICAgICAgICAgICAgICAgICB0d2VldHNfbG9nT2RkcyA8LSB0d2VldHNfbG9nT2RkcyAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhdXRvcl9mcmVjdWVudGUgPSBpZl9lbHNlKGxvZ19vZGRzID4gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzKHR3ZWV0c19sb2dPZGRzKVsyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzKHR3ZWV0c19sb2dPZGRzKVszXSkpDQoNCkRpZmVyZW5jaWFfUEIgPC0gdHdlZXRzX2xvZ09kZHMgJT4lIA0KICBhcnJhbmdlKC1sb2dfb2RkcywgYnlncm91cCA9IEZBTFNFKSU+JSANCiAgZmlsdGVyKGF1dG9yX2ZyZWN1ZW50ZSA9PSAiUC5CdWxscmljaCIpJT4lIA0KICB0YWlsKDE1KQ0KDQpEaWZlcmVuY2lhX0NGSyA8LSB0d2VldHNfbG9nT2RkcyAlPiUgDQogIGFycmFuZ2UoLWFic19sb2dfb2RkcywgYnlncm91cCA9IEZBTFNFKSU+JSANCiAgZmlsdGVyKGF1dG9yX2ZyZWN1ZW50ZSA9PSAiQy5LaXJjaG5lciIpJT4lIA0KICBoZWFkKDE1KQ0KDQpEaWZlcmVuY2lhX1BCX0NGSyA8LSByYmluZChEaWZlcmVuY2lhX1BCLERpZmVyZW5jaWFfQ0ZLKQ0KDQpEaWZlcmVuY2lhX1BCX0NGSyU+JSANCiAgICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKFBhbGFicmEsIGxvZ19vZGRzKSwgeT0gbG9nX29kZHMsIGZpbGwgPSBhdXRvcl9mcmVjdWVudGUpKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgbGFicyh4ID0gIi1wYWxhYnJhIiwgeSA9ICJVc28iLCB0aXRsZSA9ICJDcmlzdGluYSB2cyBCdWxscmljaCIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGVtYTINCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAgMjgtIEVtb2Npb25lcyBlbiBsb3MgdHdlZXRzIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCkFob3JhIGFuYWxpemFtb3MgdW4gY2FtcG8gbcOhcyBhbXBsaW8gZGUgZW1vY2lvbmVzIHF1ZSBmdWVyb24gdXNhZG8gcG9yIGxvcyBkaXN0aW50b3MgcG9sw610aWNvcyBlbnRyZSB0b2RvcyBsb3MgdHdlZXRzIHF1ZSBoYW4gaWRvIHB1YmxpY2FuZG8gZW4gZXN0ZSBwZXJpb2RvLg0KDQogIC0JRW50cmUgbG9zIG1pZW1icm9zIGRlbCAqKlBSTyoqIHkgZWwgKipQZXJvbmlzbW8qKiBzZSBkZXN0YWNhIGxhICpjb25maWFuemEqIGNvbW8gcHJpbmNpcGFsIHNlbnRpbWllbnRvIGV4cHVlc3RvDQoNCiAgLQlFbiBjdWVudGFzIGNvbW8gbGEgZGUgKipFc3BlcnQqKiBvICoqRGVsIENhw7FvKiogbG8gcXVlIG3DoXMgbXVlc3RyYW4gc3VzIHR3ZWV0cyBlcyBlbCAqbWllZG8qLg0KDQogIC0JTGFzIGN1ZW50YXMgZGVsICoqUFJPKiogeSAqKlBlcm9uaXNtbyoqLCBwcmluY2lwYWxtZW50ZSBwb3IgbG9zIG1pbmlzdHJvcyB5IGplZmVzIGRlIGdvYmllcm5vcyBidXNjYW4gdW4gc2VudGltaWVudG8gZGUgKmFudGljaXBhY2nDs24qDQoNCiAgLQlPdHJhcyBjdWVudGFzIHNvbiBtYXlvcmVzIGVsIHRvbm8gZGUgKmFuZ3VzdGlhKiBzb2JyZSBlbCB0aWVtcG8uDQoNCiAgLQlMYSAqdHJpc3RlemEqIGVzIHVuIHNlbnRpbWllbnRvIGdlbmVyYWwgcXVlIGVzdMOhIGluY29ycG9yYWRvIGVuIHRvZG9zIGxvcyB0d2VldHMsIHkgc2UgZW50aWVuZGUgcG9yIGxhIHNpdHVhY2nDs24gY29tcGxlamEgcXVlIHNpZ25pZmljYSB1bmEgcGFuZGVtaWEuDQoNCg0KYGBge3J9DQpUZXh0U2VudGltZW50IDwtIGdldF9ucmNfc2VudGltZW50KFR3ZWV0c19ERiR0ZXh0KQ0KbmFtZXMoVGV4dFNlbnRpbWVudCkgPC0gYyAoIkFuZ3VzdGlhIiwgIkFudGljaXBhY2lvbiIsICJEaXNndXN0byIsICJNaWVkbyIsICJBbGVncmlhIiwgIlRyaXN0ZXphIiwgIlNvcnByZXNhIiwgIkNvbmZpYW56YSIsICJOZWdhdGl2byIsICJQb3NpdGl2byIgKQ0KDQpUd2VldHNfREZfc2VudGltaWVudG8gPC0gY2JpbmQoVHdlZXRzX0RGLCBUZXh0U2VudGltZW50KQ0KDQoNCmdhdGhlcihUd2VldHNfREZfc2VudGltaWVudG8sICJzZW50aW1lbnQiLCAidmFsdWVzIiwgMTAzOjExMikgJT4lDQogIGdyb3VwX2J5KFBvbGl0aWNvLCBQYXJ0aWRvLCBzZW50aW1lbnQpICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAgImN1ZW50YSBwYXJ0aWRhcmlhIiklPiUNCiAgZmlsdGVyKHNlbnRpbWVudCAhPSAiUG9zaXRpdm8iICYgc2VudGltZW50ICE9Ik5lZ2F0aXZvIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQpnZ3Bsb3QoKSArDQogIGFlcyhQb2xpdGljbywgUHJvcG9yY2lvbiwgZmlsbCA9IHNlbnRpbWVudCkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJzdGFjayIsIGNvbG9yID0gImJsYWNrIikgKw0KICBjb29yZF9mbGlwKCkgICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKw0KICBsYWJzKHkgPSAiUGFsYWJyYXMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpnYXRoZXIoVHdlZXRzX0RGX3NlbnRpbWllbnRvLCAic2VudGltZW50IiwgInZhbHVlcyIsIDEwMzoxMTIpICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgc2VudGltZW50KSAlPiUNCiAgZmlsdGVyKFBhcnRpZG8gPT0gICJQUk8iKSU+JQ0KICBmaWx0ZXIoc2VudGltZW50ICE9ICJQb3NpdGl2byIgJiBzZW50aW1lbnQgIT0iTmVnYXRpdm8iKSU+JQ0KICAgIHN1bW1hcmlzZShUb3RhbCA9IHN1bSh2YWx1ZXMpKSAlPiUNCiAgICAgIG11dGF0ZShQcm9wb3JjaW9uID0gVG90YWwgLyBzdW0oVG90YWwpKSAlPiUNCmdncGxvdCgpICsNCiAgYWVzKFBvbGl0aWNvLCBQcm9wb3JjaW9uLCBmaWxsID0gc2VudGltZW50KSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gInN0YWNrIiwgY29sb3IgPSAiYmxhY2siKSArDQogIGNvb3JkX2ZsaXAoKSAgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSArDQogIGxhYnMoeSA9ICJQYWxhYnJhcyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmdhdGhlcihUd2VldHNfREZfc2VudGltaWVudG8sICJzZW50aW1lbnQiLCAidmFsdWVzIiwgMTAzOjExMikgJT4lDQogIGdyb3VwX2J5KFBvbGl0aWNvLCBQYXJ0aWRvLCBzZW50aW1lbnQpICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAgIlBlcm9uaXNtbyIpJT4lDQogIGZpbHRlcihzZW50aW1lbnQgIT0gIlBvc2l0aXZvIiAmIHNlbnRpbWVudCAhPSJOZWdhdGl2byIpJT4lDQogICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKHZhbHVlcykpICU+JQ0KICAgICAgbXV0YXRlKFByb3BvcmNpb24gPSBUb3RhbCAvIHN1bShUb3RhbCkpICU+JQ0KZ2dwbG90KCkgKw0KICBhZXMoUG9saXRpY28sIFByb3BvcmNpb24sIGZpbGwgPSBzZW50aW1lbnQpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJibGFjayIpICsNCiAgY29vcmRfZmxpcCgpICArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpICsNCiAgbGFicyh5ID0gIlBhbGFicmFzIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KZ2F0aGVyKFR3ZWV0c19ERl9zZW50aW1pZW50bywgInNlbnRpbWVudCIsICJ2YWx1ZXMiLCAxMDM6MTEyKSAlPiUNCiAgZ3JvdXBfYnkoUG9saXRpY28sIFBhcnRpZG8sIHNlbnRpbWVudCkgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICAib3Ryb3MgY2FuZGlkYXRvcyIpJT4lDQogIGZpbHRlcihzZW50aW1lbnQgIT0gIlBvc2l0aXZvIiAmIHNlbnRpbWVudCAhPSJOZWdhdGl2byIpJT4lDQogICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKHZhbHVlcykpICU+JQ0KICAgICAgbXV0YXRlKFByb3BvcmNpb24gPSBUb3RhbCAvIHN1bShUb3RhbCkpICU+JQ0KZ2dwbG90KCkgKw0KICBhZXMoUG9saXRpY28sIFByb3BvcmNpb24sIGZpbGwgPSBzZW50aW1lbnQpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJibGFjayIpICsNCiAgY29vcmRfZmxpcCgpICArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpICsNCiAgbGFicyh5ID0gIlBhbGFicmFzIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAgMjktIEVtb2Npb25lcyBtZXMgYSBtZXMgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KU2kgYmllbiBubyBoYXkgZ3JhbmRlcyBjYW1iaW9zIGEgbGEgaG9yYSBkZSBoYWNlciBsb3MgYW7DoWxpc2lzIGRlIHNlbnRpbWllbnRvcyBtZXMgYSBtZXMsIHNlIG5vdGEgYWxndW5vcyBkZXRhbGxlczoNCg0KLSBMb3MgbWluaXN0cm9zIGRlIHNhbHVkIGNhZGEgdmV6IHRyYW5zbWl0ZW4gbWF5b3IgKmNvbmZpYW56YSouDQoNCi0gTG9zIGxsYW1hZG9zIG90cm9zIGNhbmRpZGF0b3MgdmEgZGVjYXllbmRvIGxhIHRyYW5zbWlzacOzbiBkZSAqY29uZmlhbnphKi4NCg0KLSAqKkxhcnJldGEqKiBzaSBiaWVuIHRpZW5lIGJhamFzIGVuIGVsIHNlbnRpbWllbnRvIGRlICpjb25maWFuemEqLCBzaWd1ZSBleHBvbmllbmRvIHVubyBkZSAqYW50aWNpcGFjacOzbiouDQoNCi0gKipLaWNpbGxvZioqIGNhZGEgdmV6IHRpZW5lIG1heW9yIG1lbnNhamUgZGUgKmFuZ3VzdGlhKi4NCg0KDQoNCmBgYHtyfQ0KZ2F0aGVyKFR3ZWV0c19ERl9zZW50aW1pZW50bywgInNlbnRpbWVudCIsICJ2YWx1ZXMiLCAxMDM6MTEyKSAlPiUNCiAgZ3JvdXBfYnkoUG9saXRpY28sIFBhcnRpZG8sIG1lcywgc2VudGltZW50KSAlPiUNCiAgZmlsdGVyKFBhcnRpZG8gPT0gICJjdWVudGEgcGFydGlkYXJpYSIpJT4lDQogIGZpbHRlcihzZW50aW1lbnQgIT0gIlBvc2l0aXZvIiAmIHNlbnRpbWVudCAhPSJOZWdhdGl2byIpJT4lDQogICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKHZhbHVlcykpICU+JQ0KICAgICAgbXV0YXRlKFByb3BvcmNpb24gPSBUb3RhbCAvIHN1bShUb3RhbCkpICU+JQ0KZ2dwbG90KCkgKw0KYWVzKHggPSBtZXMsIHkgPVByb3BvcmNpb24sIGNvbG9yID0gc2VudGltZW50KSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzZW50aW1lbnQpKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgdmp1c3QgPSAuNCksIA0KICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpKSArDQogIHRlbWEyICsNCiAgZmFjZXRfd3JhcCh+IFBvbGl0aWNvKSArDQogIGxhYnModGl0bGUgPSAiQ2FtYmlvIGRlIGxvcyBzZW50aW1pZW50b3MgZW4gZWwgdGllbXBvIiwgDQogICAgICAgeCA9ICJNZXMiLCB5ID0gIlBvcnBvcmNpw7NuIiwgY29sb3IgPSAiU2VudGltaWVudG8iKSANCg0KZ2F0aGVyKFR3ZWV0c19ERl9zZW50aW1pZW50bywgInNlbnRpbWVudCIsICJ2YWx1ZXMiLCAxMDM6MTEyKSAlPiUNCiAgZ3JvdXBfYnkoUG9saXRpY28sIFBhcnRpZG8sIG1lcywgc2VudGltZW50KSAlPiUNCiAgZmlsdGVyKFBhcnRpZG8gPT0gICJvdHJvcyBjYW5kaWRhdG9zIiklPiUNCiAgZmlsdGVyKHNlbnRpbWVudCAhPSAiUG9zaXRpdm8iICYgc2VudGltZW50ICE9Ik5lZ2F0aXZvIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQpnZ3Bsb3QoKSArDQphZXMoeCA9IG1lcywgeSA9UHJvcG9yY2lvbiwgY29sb3IgPSBzZW50aW1lbnQpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHNlbnRpbWVudCkpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IC40KSwgDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIikpICsNCiAgdGVtYTIgKw0KICBmYWNldF93cmFwKH4gUG9saXRpY28pICsNCiAgbGFicyh0aXRsZSA9ICJDYW1iaW8gZGUgbG9zIHNlbnRpbWllbnRvcyBlbiBlbCB0aWVtcG8iLCANCiAgICAgICB4ID0gIk1lcyIsIHkgPSAiUG9ycG9yY2nDs24iLCBjb2xvciA9ICJTZW50aW1pZW50byIpIA0KDQoNCmdhdGhlcihUd2VldHNfREZfc2VudGltaWVudG8sICJzZW50aW1lbnQiLCAidmFsdWVzIiwgMTAzOjExMikgJT4lDQogIGdyb3VwX2J5KFBvbGl0aWNvLCBQYXJ0aWRvLCBtZXMsIHNlbnRpbWVudCkgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICAiUGVyb25pc21vIiklPiUNCiAgZmlsdGVyKHNlbnRpbWVudCAhPSAiUG9zaXRpdm8iICYgc2VudGltZW50ICE9Ik5lZ2F0aXZvIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQpnZ3Bsb3QoKSArDQphZXMoeCA9IG1lcywgeSA9UHJvcG9yY2lvbiwgY29sb3IgPSBzZW50aW1lbnQpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHNlbnRpbWVudCkpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IC40KSwgDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIikpICsNCiAgdGVtYTIgKw0KICBmYWNldF93cmFwKH4gUG9saXRpY28pICsNCiAgbGFicyh0aXRsZSA9ICJDYW1iaW8gZGUgbG9zIHNlbnRpbWllbnRvcyBlbiBlbCB0aWVtcG8iLCANCiAgICAgICB4ID0gIk1lcyIsIHkgPSAiUG9ycG9yY2nDs24iLCBjb2xvciA9ICJTZW50aW1pZW50byIpIA0KDQpnYXRoZXIoVHdlZXRzX0RGX3NlbnRpbWllbnRvLCAic2VudGltZW50IiwgInZhbHVlcyIsIDEwMzoxMTIpICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgbWVzLCBzZW50aW1lbnQpICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAgIlBSTyIpJT4lDQogIGZpbHRlcihzZW50aW1lbnQgIT0gIlBvc2l0aXZvIiAmIHNlbnRpbWVudCAhPSJOZWdhdGl2byIpJT4lDQogICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKHZhbHVlcykpICU+JQ0KICAgICAgbXV0YXRlKFByb3BvcmNpb24gPSBUb3RhbCAvIHN1bShUb3RhbCkpICU+JQ0KZ2dwbG90KCkgKw0KYWVzKHggPSBtZXMsIHkgPVByb3BvcmNpb24sIGNvbG9yID0gc2VudGltZW50KSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzZW50aW1lbnQpKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgdmp1c3QgPSAuNCksIA0KICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpKSArDQogIHRlbWEyICsNCiAgZmFjZXRfd3JhcCh+IFBvbGl0aWNvKSArDQogIGxhYnModGl0bGUgPSAiQ2FtYmlvIGRlIGxvcyBzZW50aW1pZW50b3MgZW4gZWwgdGllbXBvIiwgDQogICAgICAgeCA9ICJNZXMiLCB5ID0gIlBvcnBvcmNpw7NuIiwgY29sb3IgPSAiU2VudGltaWVudG8iKSANCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAzMC0gQ29tcGFyYWNpw7NuIGRlIGVtb2Npb25lcyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNCkxhIGlkZWEgZGUgY29tcGFyYXIgbGFzIGVtb2Npb25lcyBkZSB0b2RvcyBlbiB1biBncsOhZmljbyBheXVkYSBwYXJhIHVuYSB2aXN1YWxpemFjacOzbiBnZW5lcmFsIChlbGltaW5hbmRvIGxhcyBjdWVudGFzIHBhcnRpZGFyaWFzKToNCg0KLSBTaSBiaWVuIGxhIGNhbnRpZGFkIGRlIHR3ZWV0cyBkZSAqKk1hY3JpKiogc29uIHBvY29zLCBlcyBlbCBxdWUgbWF5b3IgKmNvbmZpYW56YSogdHJhbnNtaXRlLg0KDQotIEFxdWVsbG9zIHF1ZSB0aWVuZW4gcG9kZXIgZWxlY3RvIHNvbiBsb3MgcXVlIG3DoXMgKmNvbmZpYW56YSogYnVzY2FuIGVuIHN1cyB0d2VldHMuDQoNCi0gTG9zIGNhbmRpZGF0b3MgcXVlIGhhbiBwZXJkaWRvLCB0aWVuZW4gbWV6Y2xhIGRlIHNlbnRpbWllbnRvcywgY29uIGFsdG8gbml2ZWwgZGUgKm1pZWRvKiB5ICphbmd1c3RpYSogZW4gc3VzIGVzY3JpdG9zLg0KDQotICpTZSBkZXNjYXJ0YW4gYXF1ZWxsb3Mgc2VudGltaWVudG9zIHF1ZSByZXByZXNlbnRlbiBtZW5vcyBkZWwgMTAlIGRlIGxvcyB0d2VldHMuKg0KDQoNCg0KYGBge3J9DQpnYXRoZXIoVHdlZXRzX0RGX3NlbnRpbWllbnRvLCAic2VudGltZW50IiwgInZhbHVlcyIsIDEwMzoxMTIpICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgc2VudGltZW50KSAlPiUNCiAgZmlsdGVyKHNlbnRpbWVudCAhPSAiUG9zaXRpdm8iICYgc2VudGltZW50ICE9Ik5lZ2F0aXZvIiAmIFBhcnRpZG8gIT0gImN1ZW50YSBwYXJ0aWRhcmlhIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQogICAgZ2dwbG90KCkgKw0KICBhZXMoUG9saXRpY28sIFByb3BvcmNpb24sIGNvbG9yID0gc2VudGltZW50LCBhbHBoYSA9IFByb3BvcmNpb24pICsNCiAgZ2VvbV9wb2ludChmaWxsID0gIndoaXRlIiwgc3Ryb2tlID0gMSwgc2hhcGUgPSAyMSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc2VudGltZW50KSwgdmp1c3QgPSAtLjksIGZhbWlseSA9ICJzZXJpZiIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0ICgpKSArDQogIHRlbWExICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgdGV4dCA9ICBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIikpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh0aXRsZSA9ICJTZW50aW1pZW50b3MgdG90YWxlcyBjb21wYXJhdGl2byIsDQogICAgICAgeCA9ICJQb2xpdGljbyIsDQogICAgICAgeSA9ICJQcm9wb3JjacOzbiBkZWwgc2VudGltaWVudG8iKQ0KDQpnYXRoZXIoVHdlZXRzX0RGX3NlbnRpbWllbnRvLCAic2VudGltZW50IiwgInZhbHVlcyIsIDEwMzoxMTIpICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgc2VudGltZW50KSAlPiUNCiAgZmlsdGVyKHNlbnRpbWVudCAhPSAiUG9zaXRpdm8iICYgc2VudGltZW50ICE9Ik5lZ2F0aXZvIiAmIHNlbnRpbWVudCAhPSJBbGVncmlhIiAmIHNlbnRpbWVudCAhPSJTb3JwcmVzYSIgJiBQYXJ0aWRvICE9ICJjdWVudGEgcGFydGlkYXJpYSIpJT4lDQogICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKHZhbHVlcykpICU+JQ0KICAgICAgbXV0YXRlKFByb3BvcmNpb24gPSBUb3RhbCAvIHN1bShUb3RhbCkpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGFlcyhzZW50aW1lbnQsIFByb3BvcmNpb24sIGNvbG9yID0gc2VudGltZW50KSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBQb2xpdGljbykgLHZqdXN0ID0gLS4zLCBzaXplID0gMykgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLjE1LCAwLjQ3KSkgKw0KICAgbGFicyh0aXRsZSA9ICJTZW50aW1pZW50b3MgdG90YWxlcyBjb21wYXJhdGl2byIsDQogICAgICAgeCA9ICJQb2xpdGljbyIsDQogICAgICAgeSA9ICJQcm9wb3JjacOzbiBkZWwgc2VudGltaWVudG8iKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KDQpgYGANCg==