Politician analysis

1- Download tweets

I create a list of accounts from which I am going to download their tweets, and also an assignment to know to which political party each account.

The original idea is to have 4 members from each of the two main parties, the last 4 candidates in the 2019 elections and also the 4 party accounts on Twitter.

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

2-ETL process

We are going to clean up certain elements that can complicate the analysis of the text, such as links, numbers, graphics and turn everything to lowercase.

In addition, we create several fields for what the date is, disaggregating the field into several different ones, which will be used in the future, and the time is also updated to the time zone where the tweet (Argentina) was made.

Finally we filter by date, the idea is to have only tweets from the period 1/3/2020 until the publication date (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-Normalization

We normalize some fields, to help the analysis and also the visualization.

We add the match to each of those analyzed, and also change their name from the @ we see on Twitter, to a name easy for everyone to understand

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-Number of tweets

The first approximation that we are going to have is the number of times each tweeted from March 2020 to the date of publication of the report.

There are considerable differences between all, you should normalize or use proportions more than once

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-Date of tweets

We see when each of the analyzed tweets have been published, in order to show when they had more or less action.

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-Number of tweets about COVID

The most important topic of the year is the coronavirus, the idea is to see what percentage of the tweets made these months deal with the coronavirus, for that they will look for keywords that determine that the tweet is about the pandemic.

#We look for tweets with the word 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

The idea of ​​the word cloud is to know which are the 200 words that were used the most by those analyzed these months, as expected they stand out “coronavirus”, “covid”, “pandemia” or “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-Download a dictionary

We download a dictionary that has the words in Spanish, and assigns it a value between -5 to 5, showing the positivity or negativity of the word.

We eliminate the word “No” that takes it as negative, when in Spanish it is a connector sometimes, and the word “Negro” (Nigga) that takes it with the maximum negative value

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()
`tbl_df()` is deprecated as of dplyr 1.0.0.
Please use `tibble::as_tibble()` instead.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.
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- Word separation

We separated the different words that each of the politicians used in their tweets, and we eliminated some of Twitter’s own words and the so-called stopwords that are the most frequent words in the Spanish language.

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

10- We value words

We join the scoring dictionary with the words that each of those analyzed used, so that each word has a value, and it helps us to analyze what each politician wrote.

The words will be:

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- Who uses most characters?

The idea is to find what is the average length (number of characters) of the tweets made by each of those analyzed.

The further to the right the box is, the longer the tweets they write, in that aspect they stand out:

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- Who uses most words?

The idea is to analyze who is the one who used the most different words on average during this time, in this case we are going to divide by the number of tweets he made, so it is normalized for all those analyzed.

Common connectors such as “on”, “to”, “from”, etc. are not counted

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- Who uses the different words?

We seek to see the distinctive lexicon that is in each of the accounts, counting their unique words and it shows:

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- Most used words

Now that we know with what variety of words, we can analyze which ones they used the most

In this case, each graph has a different scale so that it is not lost due to the number of tweets made.

The most used words were:

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- Most used positive words

By having a score for each word given by the lexicon dictionary, we can also look for the positive words that each of the politicians use the most.

In this case:

 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- Most used negative words

By having a score for each word given by the lexicon dictionary, we can also look for the negative words that each of the politicians use the most.

 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- Feelings in the tweet

Using the afinn dictionary punctuation again, we rejoin the words to the tweets and averaged the points of all the words, moving from the unit word value to a unit value for each tweet posted.

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- Feelings in the PRO vs Peronismo tweet

We take the 4 members that we have already analyzed from each of the parties (PRO and TODOS), and we unite it in a single graph per party, we see that the distribution is something similar, although Peronism had a little more positive tweets and fewer negative tweets, but not at significant levels.

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- Feeling month by month

The idea is to analyze if there are fluctuations in what they have been tweeting over time and their feelings.

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- Feeling Boxplot

The distribution of feelings among all the tweets, those that are enclosed in the boxes are the normal ones, while the loose points are isolated tweets to what they usually write.

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

21- Correlation between PRO vs Peronismo tweeted

It is searched through the words that they used what is the correlation between the different politicians and their tweets, and several observations can be made:

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- Correlation between the tweeted candidates for president.

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- Correlation between what was tweeted between party accounts

This can be an interesting analysis, since the number of tweets is significant for everyone.

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- Macri vs Fernandez word use comparison

The idea of this graph is to show which words are the most different in their use, in this case between Mauricio Macri and 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- Larreta vs Kicillof word use comparison

The idea of this graph is to show which words are the most different in their use, in this case between Horacio Larreta and 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-Gines vs Quirós word use comparison

The idea of this graph is to show which words are the most different in their use, in this case between Gines Gonzalez and 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- Bullrich vs Cristina word use comparison

The idea of this graph is to show which words are the most different in their use, in this case between Cristina Kirchner and 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- Emotions in tweets

Now we analyze a broader field of emotions that were used by the different politicians among all the tweets that have been published in this period.

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, sentiment) %>%
  filter(Partido ==  "cuenta partidaria")%>%
  filter(sentiment != "negative" & sentiment !="positive")%>%
    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 != "negative" & sentiment !="positive")%>%
    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 != "negative" & sentiment !="positive")%>%
    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 != "negative" & sentiment !="positive")%>%
    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- Emotions month by month

Although there are no major changes when it comes to doing sentiment analysis from month to month, there are some details:

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, mes, sentiment) %>%
  filter(Partido ==  "cuenta partidaria")%>%
  filter(sentiment != "negative" & sentiment !="positive")%>%
    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 != "negative" & sentiment !="positive")%>%
    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 != "negative" & sentiment !="positive")%>%
    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 != "negative" & sentiment !="positive")%>%
    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- Comparison of emotions

The idea of ​​comparing everyone’s emotions on a graph helps for a general visualization (eliminating party accounts):

gather(Tweets_DF_sentimiento, "sentiment", "values", 103:112) %>%
  group_by(Politico, Partido, sentiment) %>%
  filter(sentiment != "negative" & sentiment !="positive" & 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 != "positive" & sentiment !="negative" & sentiment !="joy" & sentiment !="surprise" & 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)

LS0tDQp0aXRsZTogIkFuYWxpc2lzIGRlIHR3aXR0ZXI6IFBvbMOtdGljb3MgZW4gY3VhcmVudGVuYSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KYWJzdHJhY3Q6IFRoZSBpZGVhIG9mIHRoaXMgZG9jdW1lbnQgaXMgdG8gc2VlIGhvdyBzb21lIHBvbGl0aWNpYW5zIGludGVyYWN0ZWQgb24gVHdpdHRlcg0KICBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHBhbmRlbWljIHVudGlsIFNlcHRlbWJlciAxMC4gRm9yDQogIGRvd25sb2FkIHRoZSB0d2VldHMgdXNpbmcgdGhlIFR3aXR0ZXIgQVBJIGFuZCB0aGUgcnR3ZWV0IGxpYnJhcnkNCi0tLQ0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMDIxODJCOyI+IDxoMj4gUG9saXRpY2lhbiBhbmFseXNpcyA8L2gyPiA8L3NwYW4+IDwvY2VudGVyPg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAxLSBEb3dubG9hZCB0d2VldHMgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KSSBjcmVhdGUgYSBsaXN0IG9mIGFjY291bnRzIGZyb20gd2hpY2ggSSBhbSBnb2luZyB0byBkb3dubG9hZCB0aGVpciB0d2VldHMsIGFuZCBhbHNvIGFuIGFzc2lnbm1lbnQgdG8ga25vdyB0byB3aGljaCBwb2xpdGljYWwgcGFydHkgZWFjaCBhY2NvdW50Lg0KDQpUaGUgb3JpZ2luYWwgaWRlYSBpcyB0byBoYXZlIDQgbWVtYmVycyBmcm9tIGVhY2ggb2YgdGhlIHR3byBtYWluIHBhcnRpZXMsIHRoZSBsYXN0IDQgY2FuZGlkYXRlcyBpbiB0aGUgMjAxOSBlbGVjdGlvbnMgYW5kIGFsc28gdGhlIDQgcGFydHkgYWNjb3VudHMgb24gVHdpdHRlci4NCg0KICAtICAqKkZyZW50ZSBkZSB0b2RvcyoqOiAqQWxiZXJ0byBGZXJuw6FuZGV6LCBDcmlzdGluYSBLaXJjaG5lciwgR2luZXMgR29uesOhbGV6IEdhcmPDrWEgeSBBeGVsIEtpY2lsbG9mKg0KICAtICAqKlBSTyoqOiAqTWF1cmljaW8gTWFjcmksIEhvcmFjaW8gUm9kcsOtZ3VleiBMYXJyZXRhLCBGZXJuw6FuIFF1aXJveiB5IFBhdHJpY2lhIEJ1bGxyaWNoKg0KICAtICAqKk90cm9zIGNhbmRpZGF0b3MqKjogKkpvc8OpIEx1aXMgRXNwZXJ0LCBSb2JlcnRvIExhdmFnbmEsIEp1YW4gSm9zw6kgR8OzbWV6IENlbnR1cmnDs24geSBOaWNvbGFzIGRlbCBDYcOxbyoNCiAgLSAgKipQYXJ0aWRhcmlhcyoqOiAqRnJlbnRlIGRlIFRvZG9zLCBQUk8sIEdFTiB5IFVuacOzbiBDw612aWNhIFJhZGljYWwqDQoNCmBgYHtyfQ0KY2FuZGlkYXRvcyA8LSBsaXN0KCJhbGZlcmRleiIsIA0KICAgICAgICAgICAgICAgICAgICJDRktBcmdlbnRpbmEiLCANCiAgICAgICAgICAgICAgICAgICAiZ2luZXNnZ2FyY2lhIiwNCiAgICAgICAgICAgICAgICAgICAiS2ljaWxsb2ZvayIsDQogICAgICAgICAgICAgICAgICAgIlBhcnRpZG9HRU4iLCANCiAgICAgICAgICAgICAgICAgICAiRnJlbnRlRGVUb2RvcyIsDQogICAgICAgICAgICAgICAgICAgICJtYXVyaWNpb21hY3JpIiwNCiAgICAgICAgICAgICAgICAgICAiUGF0b0J1bGxyaWNoIiwNCiAgICAgICAgICAgICAgICAgICAiaG9yYWNpb3JsYXJyZXRhIiwNCiAgICAgICAgICAgICAgICAgICAiRmVybmFuUXVpcm9zQkEiLA0KICAgICAgICAgICAgICAgICAgICJwcm9hcmdlbnRpbmEiLA0KICAgICAgICAgICAgICAgICAgICJVQ1JOYWNpb25hbCIsDQogICAgICAgICAgICAgICAgICAgImpsZXNwZXJ0IiwNCiAgICAgICAgICAgICAgICAgICAiTmljb2xhc2RlbENhbm8iLA0KICAgICAgICAgICAgICAgICAgICJSTGF2YWduYSIsDQogICAgICAgICAgICAgICAgICAgImp1YW5qb21hbHZpbmFzIikNCg0KdGlwb2N1ZW50YSA8LSBsaXN0ICgiUGVyb25pc21vIiwiY3VlbnRhIHBhcnRpZGFyaWEiLCAiUFJPIiwib3Ryb3MgY2FuZGlkYXRvcyIgKQ0KDQogVHdlZXRzPC1tYXAoY2FuZGlkYXRvcywgZnVuY3Rpb24oeCl7DQogICAgZ2V0X3RpbWVsaW5lKHVzZXIgPSB4LCBuID0gMzIwMCwgaW5jbHVkZVJ0cyA9IEYsIGV4Y2x1ZGVSZXBsaWVzID0gRikNCiAgICAgfSApDQogDQpUd2VldHNfREY8LSBkb19jYWxsX3JiaW5kKFR3ZWV0cykNCg0KcHJpbnQoIk11ZXN0cmEiKQ0KcHJpbnQoVHdlZXRzX0RGICU+JSANCiAgc2VsZWN0KHRleHQpJT4lIA0KICAgIGhlYWQoNSkpDQoNCmBgYA0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDItRVRMIHByb2Nlc3MgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpXZSBhcmUgZ29pbmcgdG8gY2xlYW4gdXAgY2VydGFpbiBlbGVtZW50cyB0aGF0IGNhbiBjb21wbGljYXRlIHRoZSBhbmFseXNpcyBvZiB0aGUgdGV4dCwgc3VjaCBhcyBsaW5rcywgbnVtYmVycywgZ3JhcGhpY3MgYW5kIHR1cm4gZXZlcnl0aGluZyB0byBsb3dlcmNhc2UuDQoNCkluIGFkZGl0aW9uLCB3ZSBjcmVhdGUgc2V2ZXJhbCBmaWVsZHMgZm9yIHdoYXQgdGhlIGRhdGUgaXMsIGRpc2FnZ3JlZ2F0aW5nIHRoZSBmaWVsZCBpbnRvIHNldmVyYWwgZGlmZmVyZW50IG9uZXMsIHdoaWNoIHdpbGwgYmUgdXNlZCBpbiB0aGUgZnV0dXJlLCBhbmQgdGhlIHRpbWUgaXMgYWxzbyB1cGRhdGVkIHRvIHRoZSB0aW1lIHpvbmUgd2hlcmUgdGhlIHR3ZWV0ICooQXJnZW50aW5hKSogd2FzIG1hZGUuDQoNCkZpbmFsbHkgd2UgZmlsdGVyIGJ5IGRhdGUsIHRoZSBpZGVhIGlzIHRvIGhhdmUgb25seSB0d2VldHMgZnJvbSB0aGUgcGVyaW9kIDEvMy8yMDIwIHVudGlsIHRoZSBwdWJsaWNhdGlvbiBkYXRlICooU2VwIC8gMjAyMCkqDQoNCmBgYHtyfQ0KVHdlZXRzX0RGIDwtDQogIFR3ZWV0c19ERiAlPiUNCiAgIyNBbGwgdGV4dCBpbiBsb3dlcmNhc2UjIw0KICBtdXRhdGUodGV4dCA9IHRvbG93ZXIodGV4dCkpICU+JSANCiAgIyNObyBncmFwaHMjIw0KICBtdXRhdGUodGV4dCA9IGdzdWIoIlteWzpncmFwaDpdXSIsICIgIiwgdGV4dCkpICU+JSANCiAgIyNObyBsaW5rcyMjDQogIG11dGF0ZSh0ZXh0ID0gZ3N1YigiaHR0cC8vUyIsICIgIiwgdGV4dCkpICU+JSANCiAgIyNObyBudW1iZXJzIyMNCiAgbXV0YXRlKHRleHQgPSBnc3ViKCJbWzpkaWdpdDpdXSIsICIgIiwgdGV4dCkpICU+JSANCiAgIyNObyBhY2NlbnQgbWFyayMjDQogIG11dGF0ZSh0ZXh0ID0gY2hhcnRyKCfDocOpw63Ds8O6w7EnLCdhZWlvdW4nLHRleHQpKSAlPiUNCiAgIyNXZSBjaGFuZ2UgdG8gdGhlIGNvcnJlc3BvbmRpbmcgdGltZSB6b25lIyMNCiAgbXV0YXRlKGNyZWF0ZWRfYXQgPSB3aXRoX3R6KGNyZWF0ZWRfYXQsICJBbWVyaWNhL0FyZ2VudGluYS9CdWVub3NfQWlyZXMiKSklPiUgDQogICMjV2Ugc2VwYXJhdGUgdGhlIGNyZWF0ZWRfYSBmaWVsZCBpbnRvIGRheSBhbmQgdGltZXQjIw0KICBzZXBhcmF0ZShjcmVhdGVkX2F0LCBpbnRvID0gYygiZGF0ZSIsICJob3VyIiksIHNlcCA9ICIgIiklPiUgDQogICMjV2Ugc2VwYXJhdGUgdGhlIHRpbWUgaW50byBob3VycywgbWludXRlcyBhbmQgc2Vjb25kcyMjDQogICAgc2VwYXJhdGUoaG91ciwgaW50byA9IGMoImhvdXIiLCAibWludXRlcyIsInNlY29uZHMiKSwgc2VwID0gIjoiKSU+JSANCiAgIyNXZSBjaGFuZ2UgdGhlIGNvbHVtbiB3aXRoIHRoZSBuYW1lIG9mIHRoZSBwb2xpdGljaWFuIyMNCiAgIHJlbmFtZShQb2xpdGljbyA9IHNjcmVlbl9uYW1lKSAlPiUgDQogICMjV2UgY3JlYXRlIGEgY29sdW1uIHdpdGggdGhlIG51bWJlciBvZiB5ZWFyLCBtb250aCwgZGF5LCBuYW1lIG9mIGRheSBhbmQgbW9udGguIyMNCm11dGF0ZShwZXJpb2RvID0geWVhcihkYXRlKSwgDQogICAgICAgICBtZXMgPSBtb250aChkYXRlLCBsYWJlbCA9IEYsIGFiYnIgPSBGKSwNCiAgICAgICAgIGRpYSA9IGFzLm51bWVyaWMoZGF5KGRhdGUpKSwNCiAgICAgICAgIGRpYV9zZW0gPSB3ZGF5KGRhdGUsIGxhYmVsID0gVCwgYWJiciA9IEYsIHdlZWtfc3RhcnQgPSAxKSwNCiAgICAgICAgIGRpYV9wZXIgPSB5ZGF5KGRhdGUpLA0KICAgICAgICAgZGF0ZSA9IGFzLkRhdGUoZGF0ZSkgDQogICkgJT4lDQogICMjV2Ugd2lsbCBvbmx5IHVzZSBpbmZvIGZyb20gTWFyY2ggMjAyMCBvbndhcmRzIyMNCiAgZmlsdGVyKHBlcmlvZG8gPT0gMjAyMCAmIG1lcyA+IDIpIA0KDQpwcmludCgiTXVlc3RyYSIpDQpwcmludChUd2VldHNfREYgJT4lIA0KICBzZWxlY3QoUG9saXRpY28sIHN0YXR1c19pZCwgcGVyaW9kbywgbWVzLCBkaWEpJT4lIA0KICAgIGhlYWQoMTApKQ0KDQpgYGANCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMy1Ob3JtYWxpemF0aW9uIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KV2Ugbm9ybWFsaXplIHNvbWUgZmllbGRzLCB0byBoZWxwIHRoZSBhbmFseXNpcyBhbmQgYWxzbyB0aGUgdmlzdWFsaXphdGlvbi4NCg0KV2UgYWRkIHRoZSBtYXRjaCB0byBlYWNoIG9mIHRob3NlIGFuYWx5emVkLCBhbmQgYWxzbyBjaGFuZ2UgdGhlaXIgbmFtZSBmcm9tIHRoZSBAIHdlIHNlZSBvbiBUd2l0dGVyLCB0byBhIG5hbWUgZWFzeSBmb3IgZXZlcnlvbmUgdG8gdW5kZXJzdGFuZA0KDQoNCmBgYHtyfQ0KVHdlZXRzX0RGIDwtDQogIFR3ZWV0c19ERiAlPiUNCiAgbXV0YXRlIChQYXJ0aWRvID0gaWZlbHNlIChQb2xpdGljbyA9PSAiYWxmZXJkZXoiLCAiUGVyb25pc21vIiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiQ0ZLQXJnZW50aW5hIiwgIlBlcm9uaXNtbyIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gImdpbmVzZ2dhcmNpYSIsICJQZXJvbmlzbW8iLCANCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiS2ljaWxsb2ZvayIsICJQZXJvbmlzbW8iLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJVQ1JOYWNpb25hbCIsICJjdWVudGEgcGFydGlkYXJpYSIsICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiRnJlbnRlRGVUb2RvcyIsICJjdWVudGEgcGFydGlkYXJpYSIsIA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJwcm9hcmdlbnRpbmEiLCAiY3VlbnRhIHBhcnRpZGFyaWEiLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJQYXJ0aWRvR0VOIiwgImN1ZW50YSBwYXJ0aWRhcmlhIiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAibWF1cmljaW9tYWNyaSIsICJQUk8iLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJQYXRvQnVsbHJpY2giLCAiUFJPIiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiaG9yYWNpb3JsYXJyZXRhIiwgIlBSTyIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIkZlcm5hblF1aXJvc0JBIiwgIlBSTyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJvdHJvcyBjYW5kaWRhdG9zIikpKSkpKSkpKSkpKSkNCg0KVHdlZXRzX0RGIDwtDQogIFR3ZWV0c19ERiAlPiUNCiAgbXV0YXRlIChQb2xpdGljbyA9IGlmZWxzZSAoUG9saXRpY28gPT0gImFsZmVyZGV6IiwgIkEuRmVybmFuZGV6IiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiQ0ZLQXJnZW50aW5hIiwgIkMuS2lyY2huZXIiLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJnaW5lc2dnYXJjaWEiLCAiR2luZXMuR0ciLCANCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiS2ljaWxsb2ZvayIsICJBLktpY2lsbG9mIiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiVUNSTmFjaW9uYWwiLCAiVUNSIiwgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJGcmVudGVEZVRvZG9zIiwgIlRPRE9TIiwgDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gInByb2FyZ2VudGluYSIsICJQUk8iLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJQYXJ0aWRvR0VOIiwgIkdFTiIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIm1hdXJpY2lvbWFjcmkiLCAiTS5NYWNyaSIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIlBhdG9CdWxscmljaCIsICJQLkJ1bGxyaWNoIiwNCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlIChQb2xpdGljbyA9PSAiaG9yYWNpb3JsYXJyZXRhIiwgIkguTGFycmV0YSIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIkZlcm5hblF1aXJvc0JBIiwgIkYuUXVpcm9zIiwgDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIk5pY29sYXNkZWxDYW5vIiwgIk4uRGVsQ2HDsW8iLA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UgKFBvbGl0aWNvID09ICJqbGVzcGVydCIsICJKLkVzcGVydCIsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZSAoUG9saXRpY28gPT0gIlJMYXZhZ25hIiwgIlIuTGF2YWduYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdvbWV6Q2VudHVyaW9uIg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpKSkpKSkpKSkpKSkpKSkNCg0KcHJpbnQoIk11ZXN0cmEiKQ0KcHJpbnQoVHdlZXRzX0RGICU+JSANCiAgc2VsZWN0KFBvbGl0aWNvLCBQYXJ0aWRvLCBzb3VyY2UpJT4lIA0KICAgIHRhaWwoMTApKQ0KYGBgDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gNC1OdW1iZXIgb2YgdHdlZXRzIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KVGhlIGZpcnN0IGFwcHJveGltYXRpb24gdGhhdCB3ZSBhcmUgZ29pbmcgdG8gaGF2ZSBpcyB0aGUgbnVtYmVyIG9mIHRpbWVzIGVhY2ggdHdlZXRlZCBmcm9tIE1hcmNoIDIwMjAgdG8gdGhlIGRhdGUgb2YgcHVibGljYXRpb24gb2YgdGhlIHJlcG9ydC4NCg0KVGhlcmUgYXJlIGNvbnNpZGVyYWJsZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIGFsbCwgeW91IHNob3VsZCBub3JtYWxpemUgb3IgdXNlIHByb3BvcnRpb25zIG1vcmUgdGhhbiBvbmNlDQoNCiAgLSAqTWFjcmkgYW5kIExhdmFnbmEgaGF2ZSBmZXdlciB0d2VldHMgdGhhbiB0aGUgcmVzdCoNCiAgLSAqQ3Jpc3RpbmEgS2lyY2huZXIgaXMgYWxzbyBvZiBsaXR0bGUgcGFydGljaXBhdGlvbioNCiAgLSAqVGhlIGFjY291bnRzIG9mIEZyZW50ZSBkZSBUb2RvcywgRXNwZXJ0LCBEZWwgQ2HDsW8gYW5kIHRoZSBVQ1IgYXJlIHRoZSBtb3N0IHVzZWQqDQoNCg0KICANCmBgYHtyfQ0KQ2FudGlkYWRfdHdlZXRzID0gVHdlZXRzX0RGICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbykgJT4lDQogIGNvdW50KFBvbGl0aWNvKQ0KICANCkNhbnRpZGFkX3R3ZWV0cyU+JSAgDQogIGdncGxvdCgpKw0KICBhZXMoeD1yZW9yZGVyKFBvbGl0aWNvLCBuKSwgeT0gbiwgZmlsbD0gUG9saXRpY28pICsNCiAgZ2VvbV9jb2woKSArDQogIGZhY2V0X3dyYXAoIlBhcnRpZG8iLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHRpdGxlID0gIkNhbnRpZGFkIHRvdGFsIGRlIHR3ZWV0cyIsIHggPSAidHdlZXRzIiwgeSA9ICJDYW50aWRhZCIpICsNCiAgICB0ZW1hMQ0KYGBgDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gNS1EYXRlIG9mIHR3ZWV0cyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNCldlIHNlZSB3aGVuIGVhY2ggb2YgdGhlIGFuYWx5emVkIHR3ZWV0cyBoYXZlIGJlZW4gcHVibGlzaGVkLCBpbiBvcmRlciB0byBzaG93IHdoZW4gdGhleSBoYWQgbW9yZSBvciBsZXNzIGFjdGlvbi4NCg0KICAtICpJbiB0aGUgY2FzZSBvZiB0aGUgRnJlbnRlIGRlIHRvZG9zIGFjY291bnQsIGFzIGl0IGhhZCBtb3JlIHRoYW4gMywyMDAgdHdlZXRzLCB0aGUgYW5hbHlzaXMgc3RhcnRzIGZyb20gdGhlIGZpcnN0IGRheXMgb2YgQXByaWwqDQoNCmBgYHtyfQ0KVHdlZXRzX0RGICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAiUFJPIikgJT4lDQogIGdncGxvdChhZXMoeCA9IGFzLkRhdGUoZGF0ZSksIGZpbGwgPSBQb2xpdGljbykpICsNCiAgICAgIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImlkZW50aXR5IiwgYmlucyA9IDIwLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJWQtJW0iLCBkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIikgKw0KICAgICAgbGFicyh4ID0gImZlY2hhIGRlIHB1YmxpY2FjacOzbiIsIHkgPSAibsO6bWVybyBkZSB0d2VldHMiKSArDQogICAgICBmYWNldF93cmFwKH4gUG9saXRpY28sIG5jb2wgPSAxKSArDQogICAgICB0ZW1hMiArDQogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkNCg0KVHdlZXRzX0RGICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAiUGVyb25pc21vIikgJT4lDQogIGdncGxvdChhZXMoeCA9IGFzLkRhdGUoZGF0ZSksIGZpbGwgPSBQb2xpdGljbykpICsNCiAgICAgIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImlkZW50aXR5IiwgYmlucyA9IDIwLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJWQtJW0iLCBkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIikgKw0KICAgICAgbGFicyh4ID0gImZlY2hhIGRlIHB1YmxpY2FjacOzbiIsIHkgPSAibsO6bWVybyBkZSB0d2VldHMiKSArDQogICAgICBmYWNldF93cmFwKH4gUG9saXRpY28sIG5jb2wgPSAxKSArDQogICAgICB0ZW1hMSArDQogICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkNCg0KVHdlZXRzX0RGICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAib3Ryb3MgY2FuZGlkYXRvcyIpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBhcy5EYXRlKGRhdGUpLCBmaWxsID0gUG9saXRpY28pKSArDQogICAgICBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGJpbnMgPSAyMCwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICAgICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzID0gIiVkLSVtIiwgZGF0ZV9icmVha3MgPSAiMSBtb250aCIpICsNCiAgICAgIGxhYnMoeCA9ICJmZWNoYSBkZSBwdWJsaWNhY2nDs24iLCB5ID0gIm7Dum1lcm8gZGUgdHdlZXRzIikgKw0KICAgICAgZmFjZXRfd3JhcCh+IFBvbGl0aWNvLCBuY29sID0gMSkgKw0KICAgICAgdGVtYTEgKw0KICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpDQoNClR3ZWV0c19ERiAlPiUNCiAgZmlsdGVyKFBhcnRpZG8gPT0gImN1ZW50YSBwYXJ0aWRhcmlhIikgJT4lDQogIGdncGxvdChhZXMoeCA9IGFzLkRhdGUoZGF0ZSksIGZpbGwgPSBQb2xpdGljbykpICsNCiAgICAgIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImlkZW50aXR5IiwgYmlucyA9IDIwLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogICAgICBzY2FsZV94X2RhdGUoZGF0ZV9sYWJlbHMgPSAiJWQtJW0iLCBkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIikgKw0KICAgICAgbGFicyh4ID0gImZlY2hhIGRlIHB1YmxpY2FjacOzbiIsIHkgPSAibsO6bWVybyBkZSB0d2VldHMiKSArDQogICAgICBmYWNldF93cmFwKH4gUG9saXRpY28sIG5jb2wgPSAxKSArDQogICAgICB0ZW1hMiAgKw0KICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpDQpgYGANCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDYtTnVtYmVyIG9mIHR3ZWV0cyBhYm91dCBDT1ZJRCA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNClRoZSBtb3N0IGltcG9ydGFudCB0b3BpYyBvZiB0aGUgeWVhciBpcyB0aGUgY29yb25hdmlydXMsIHRoZSBpZGVhIGlzIHRvIHNlZSB3aGF0IHBlcmNlbnRhZ2Ugb2YgdGhlIHR3ZWV0cyBtYWRlIHRoZXNlIG1vbnRocyBkZWFsIHdpdGggdGhlIGNvcm9uYXZpcnVzLCBmb3IgdGhhdCB0aGV5IHdpbGwgbG9vayBmb3Iga2V5d29yZHMgdGhhdCBkZXRlcm1pbmUgdGhhdCB0aGUgdHdlZXQgaXMgYWJvdXQgdGhlIHBhbmRlbWljLg0KDQogIC0gKkNsZWFybHkgdGhlIG1pbmlzdGVycyBhcmUgdGhlIG9uZXMgd2hvIHNwb2tlIHRoZSBtb3N0IGFib3V0IHRoZSBDb3JvbmF2aXJ1cywgd2l0aCA3NSUgb2YgdGhlaXIgdHdlZXRzLioNCiAgDQogIC0gKkdvdmVybm9ycyBLaWNpbG9mZiBhbmQgTGFycmV0YSBjb250aW51ZSwgd2hvIGRpc2N1c3NlZCB0aGUgZXZvbHV0aW9uIG9mIHRoZSBwYW5kZW1pYyBpbiB0aGVpciBkaXN0cmljdHMuKg0KDQogIC0gKlRvIGEgbGVzc2VyIGV4dGVudCB0aGUgbGVhZGVycyBvZiB0aGUgdHdvIG1haW4gcGFydGllcyBzcG9rZS4qDQoNCiAgLSAqRGVsIENhw7FvIGlzIHRoZSBvbmUgd2hvIHNwb2tlIHRoZSBtb3N0IGFtb25nIHRoZSBvdGhlciBjYW5kaWRhdGVzLCBmb2xsb3dlZCBieSBFc3BlcnQsIHdoaWxlIExhdmFnbmEgYW5kIEfDs21leiBDZW50dXJpw7NuIHNwb2tlIHZlcnkgbGl0dGxlLioNCg0KICAtICpQYXJ0eSBhY2NvdW50cywgZXhjZXB0IHRob3NlIG9mIHRoZSBVQ1IsIHdlcmUgbm90IHdpZGVseSB1c2VkIHRvIHRhbGsgYWJvdXQgdGhlIENvcm9uYXZpcnVzKg0KDQoNCg0KYGBge3J9DQojV2UgbG9vayBmb3IgdHdlZXRzIHdpdGggdGhlIHdvcmQgY292aWQNClBhbGFicmFzX2NvdmlkIDwtICJjb3ZpZHxjb3ZpZC0xOXxjb3ZpZDE5fGNvcm9uYXZpcnVzfCNjb3ZpZHwjY292aWQtMTl8I2NvdmlkMTl8I2Nvcm9uYXZpcnVzfHRlc3R8dGVzdGVvfHRlc3Rlb3N8cGNyfHNlcm9sb2dpY298aGlzb3BhZG98YW50aWJpb3RpY29zfGFwbGFuYXJ8Y3VydmF8Y3VhcmVudGVuYXxjb250YWdpb3xlbmZlcm1lZGFkfGVwaWRlbWlhfHBhbmRlbWlhfGFsYXJtYXxnZWx8Y3VpZGFkb3N8aW5jdWJhY2lvbnxqYWJvbnxiYXJiaWpvfGJhcmJpam9zfG1hc2NhcmlsbGF8bWFzY2FyaWxsYXN8bWVyc3xzYXJzfHZhY3VuYXx3dWhhbnxveGZvcmR8YXN0cmF8emVuZWNhfHRyYW5zbWlzaW9ufGV4cG9uZW5jaWFsfGNhc29zfGR1cGxpY2FjaW9ufGRpc3RhbmNpYW1pZW50b3xjb2xhcHNvfHNhbHVkfGxldGFsaWRhZHxtb3J0YWxpZGFkfHZlbnRpbGFkb3J8aWN1fHVjaXx1dGl8aW5tdW5pZGFkfHNlcm9sb2dpY2F8ZGlzdGFuY2lhbWllbnRvfHZpcnVzfGFzaW50b21hdGljb3xjYXNvIHNvc3BlY2hvc298b2xmYXRvfGd1c3RvfHRlcmFwaWF8c2F0dXJhY2lvbnxjbGluaWNhfHBvc2l0aXZpZGFkfHBvc2l0aXZpb3N8cmViYcOxb3xpbm11bmlkYWR8aG9zcGl0YWx8aG9zcGl0YWxlc3xhc3BvfGFpc2xhbWllbnRvIg0KVHdlZXRzX0RGJENvdmlkIDwtIGdyZXBsKFBhbGFicmFzX2NvdmlkLCBUd2VldHNfREYkdGV4dCwgaWdub3JlLmNhc2UgPSJUcnVlIikNCg0KVHdlZXRzX0RGICU+JSANCmNvdW50KFBvbGl0aWNvLCBQYXJ0aWRvLENvdmlkKSAlPiUNCiAgZ3JvdXBfYnkoUG9saXRpY28pICU+JQ0KICBtdXRhdGUoUHJvcG9yY2lvbiA9IG4gLyBzdW0obikpICU+JQ0KICBtdXRhdGUoQ292aWQgPSBpZmVsc2UoQ292aWQgPT0gVCwgIlNvYnJlIENPVklEIiwgIk90cm8gdGVtYSIpKSU+JQ0KZ2dwbG90KCkgKw0KICBhZXMoUG9saXRpY28sIFByb3BvcmNpb24sIGZpbGwgPSBDb3ZpZCkgKw0KICBnZW9tX2NvbCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgICAgIGZhY2V0X3dyYXAoIlBhcnRpZG8iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpDQpgYGANCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+ICA3LSBXb3JkY2xvdWQgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpUaGUgaWRlYSBvZiDigIvigIt0aGUgd29yZCBjbG91ZCBpcyB0byBrbm93IHdoaWNoIGFyZSB0aGUgMjAwIHdvcmRzIHRoYXQgd2VyZSB1c2VkIHRoZSBtb3N0IGJ5IHRob3NlIGFuYWx5emVkIHRoZXNlIG1vbnRocywgYXMgZXhwZWN0ZWQgdGhleSBzdGFuZCBvdXQgKioiY29yb25hdmlydXMiKiosICoqImNvdmlkIioqLCAqKiJwYW5kZW1pYSIqKiBvciAqKiJjdWFyZW50ZW5hIioqDQoNCg0KYGBge3J9DQp0dWl0c190b2tlbnMgPC0NCiAgVHdlZXRzX0RGICU+JQ0KICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gdGV4dCwgb3V0cHV0ID0gUGFsYWJyYSwgdG9rZW4gPSAid29yZHMiKSAlPiUNCiAgc2VsZWN0KFBvbGl0aWNvLCBQYWxhYnJhLCBzdGF0dXNfaWQsIHBlcmlvZG8sIG1lcywgaG91ciwgUGFydGlkbykgJT4lDQogIG11dGF0ZShzdGF0dXNfaWQgPSBnc3ViKCI8KC4qKT4rPyIsICIiLCBzdGF0dXNfaWQpKSAlPiUNCiAgZmlsdGVyKCFQYWxhYnJhICVpbiUgc3RvcHdvcmRzKCJlcyIpKSAlPiUNCiAgZmlsdGVyKCFQYWxhYnJhICVpbiUgYygidC5jbyIsICJodHRwcyIsICJ2w4PCrWEiLCAieW91dHViZSIsICJhbXAiKSkNCg0KUGFsYWJyYXNfc2luaG95bWFzID0gdHVpdHNfdG9rZW5zICAlPiUNCiAgZmlsdGVyKFBhbGFicmEgIT0gIm1hcyIgJiBQYWxhYnJhICE9ICJob3kiKSANCg0Kd29yZGNsb3VkKHdvcmRzID0gUGFsYWJyYXNfc2luaG95bWFzJFBhbGFicmEsIA0KICAgICAgICAgIHNjYWxlPWMoMiwuMiksIA0KICAgICAgICAgIG1heC53b3Jkcz0yMDAsIHJhbmRvbS5vcmRlcj1GQUxTRSwgcm90LnBlcj0wLjM1LCANCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg4LCAiRGFyazIiKSwNCiAgICAgICAgICApDQoNCg0KYGBgDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiA4LURvd25sb2FkIGEgZGljdGlvbmFyeSA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNCldlIGRvd25sb2FkIGEgZGljdGlvbmFyeSB0aGF0IGhhcyB0aGUgd29yZHMgaW4gU3BhbmlzaCwgYW5kIGFzc2lnbnMgaXQgYSB2YWx1ZSBiZXR3ZWVuIC01IHRvIDUsIHNob3dpbmcgdGhlIHBvc2l0aXZpdHkgb3IgbmVnYXRpdml0eSBvZiB0aGUgd29yZC4NCg0KV2UgZWxpbWluYXRlIHRoZSB3b3JkICoiTm8iKiB0aGF0IHRha2VzIGl0IGFzIG5lZ2F0aXZlLCB3aGVuIGluIFNwYW5pc2ggaXQgaXMgYSBjb25uZWN0b3Igc29tZXRpbWVzLCBhbmQgdGhlIHdvcmQgKuKAnE5lZ3Jv4oCdKiAoTmlnZ2EpIHRoYXQgdGFrZXMgaXQgd2l0aCB0aGUgbWF4aW11bSBuZWdhdGl2ZSB2YWx1ZQ0KDQoNCmBgYHtyfQ0KZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2pib3Njb21lbmRvemEvcnB1YnMvbWFzdGVyL3NlbnRpbWllbnRvc19hZmlubi9sZXhpY29fYWZpbm4uZW4uZXMuY3N2IiwNCiAgICAgICAgICAgICAgImxleGljb19hZmlubi5lbi5lcy5jc3YiKQ0KDQphZmlubiA8LSByZWFkLmNzdigibGV4aWNvX2FmaW5uLmVuLmVzLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGLCBmaWxlRW5jb2RpbmcgPSAibGF0aW4xIikgJT4lIA0KICB0YmxfZGYoKQ0KDQphZmlubiRQdW50dWFjaW9uIDwtIGlmZWxzZShhZmlubiRQYWxhYnJhID09ICJubyIsIDAsIGFmaW5uJFB1bnR1YWNpb24pDQphZmlubiRQdW50dWFjaW9uIDwtIGlmZWxzZShhZmlubiRQYWxhYnJhID09ICJuZWdybyIsIDAsIGFmaW5uJFB1bnR1YWNpb24pDQoNCnByaW50KCJNdWVzdHJhIikNCmFmaW5uICU+JQ0KICBzZWxlY3QoUGFsYWJyYSwgUHVudHVhY2lvbikgJT4lDQogICAgYXJyYW5nZShQdW50dWFjaW9uKSAlPiUNCiAgcHJpbnQoaGVhZCgxMCkpDQoNCmFmaW5uICU+JQ0KICBzZWxlY3QoUGFsYWJyYSwgUHVudHVhY2lvbikgJT4lDQogICAgYXJyYW5nZSgtUHVudHVhY2lvbikgJT4lDQogIHByaW50KHRhaWwoMTApKQ0KYGBgDQoNCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDktIFdvcmQgc2VwYXJhdGlvbiA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNCldlIHNlcGFyYXRlZCB0aGUgZGlmZmVyZW50IHdvcmRzIHRoYXQgZWFjaCBvZiB0aGUgcG9saXRpY2lhbnMgdXNlZCBpbiB0aGVpciB0d2VldHMsIGFuZCB3ZSBlbGltaW5hdGVkIHNvbWUgb2YgVHdpdHRlcidzIG93biB3b3JkcyBhbmQgdGhlIHNvLWNhbGxlZCBzdG9wd29yZHMgdGhhdCBhcmUgdGhlIG1vc3QgZnJlcXVlbnQgd29yZHMgaW4gdGhlIFNwYW5pc2ggbGFuZ3VhZ2UuDQoNCg0KYGBge3J9DQpwcmludCAoIk11ZXN0cmEiKQ0KcHJpbnQgKHR1aXRzX3Rva2VucyAlPiUNCiAgICBzZWxlY3QoUG9saXRpY28sIFBhbGFicmEpICU+JSAgICANCiAgICAgICAgIGhlYWQgKDEwKSkNCmBgYA0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAxMC0gV2UgdmFsdWUgd29yZHMgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpXZSBqb2luIHRoZSBzY29yaW5nIGRpY3Rpb25hcnkgd2l0aCB0aGUgd29yZHMgdGhhdCBlYWNoIG9mIHRob3NlIGFuYWx5emVkIHVzZWQsIHNvIHRoYXQgZWFjaCB3b3JkIGhhcyBhIHZhbHVlLCBhbmQgaXQgaGVscHMgdXMgdG8gYW5hbHl6ZSB3aGF0IGVhY2ggcG9saXRpY2lhbiB3cm90ZS4NCg0KVGhlIHdvcmRzIHdpbGwgYmU6DQoNCiAgLSBJZiB0aGV5IGhhdmUgYSB2YWx1ZSBncmVhdGVyIHRoYW4gMCAqKlBvc2l0aXZlKioNCiAgDQogIC0gSWYgdGhleSBhcmUgbGVzcyB0aGFuIDAgKipOZWdhdGl2ZSoqDQogIA0KICAtIEluIGNhc2UgdGhlIHdvcmQgZG9lcyBub3QgaGF2ZSBhIGxvYWQgb2YgZmVlbGluZ3MgKipOZXV0cmFsKioNCg0KDQpgYGB7cn0NCnR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgPC0gICANCiB0dWl0c190b2tlbnMgJT4lDQppbm5lcl9qb2luKGFmaW5uLCAuLCBieSA9ICJQYWxhYnJhIikgJT4lDQogIG11dGF0ZShDYWxpZmljYWNpb24gPSBpZmVsc2UoUHVudHVhY2lvbiA+IDAsICJQb3NpdGl2YSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFB1bnR1YWNpb24gPT0gMCwgIk5ldXRyYWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5lZ2F0aXZhIikNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQogICkgICAgICANCg0KcHJpbnQgKCJNdWVzdHJhIikNCnByaW50ICh0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIHNlbGVjdChQb2xpdGljbywgUGFsYWJyYSwgUHVudHVhY2lvbiwgQ2FsaWZpY2FjaW9uKSAlPiUgICAgDQogICAgICAgICB0YWlsICgxMCkpDQpgYGANCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDExLSBXaG8gdXNlcyBtb3N0IGNoYXJhY3RlcnM/IDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KVGhlIGlkZWEgaXMgdG8gZmluZCB3aGF0IGlzIHRoZSBhdmVyYWdlIGxlbmd0aCAobnVtYmVyIG9mIGNoYXJhY3RlcnMpIG9mIHRoZSB0d2VldHMgbWFkZSBieSBlYWNoIG9mIHRob3NlIGFuYWx5emVkLg0KDQpUaGUgZnVydGhlciB0byB0aGUgcmlnaHQgdGhlIGJveCBpcywgdGhlIGxvbmdlciB0aGUgdHdlZXRzIHRoZXkgd3JpdGUsIGluIHRoYXQgYXNwZWN0IHRoZXkgc3RhbmQgb3V0Og0KDQogIC0gKkxhdmFnbmEsIFBhdHJpY2lhIEJ1bGxyaWNoLCBMYXJyZXRhIGFuZCBGZXJuw6FuIFF1aXLDs3MgYXJlIHRoZSBvbmVzIHdobyB3cml0ZSB0aGUgbG9uZ2VzdCB0d2VldHMuKg0KICANCiAgLSAqVGhvc2UgcmVsYXRlZCB0byB0aGUgUFJPIGFyZSB0byB3cml0ZSBsb25nZXIgdHdlZXRzKg0KDQoNCmBgYHtyfQ0KVHdlZXRzX0RGICU+JSANCmdncGxvdCgpKw0KICBhZXMoeD0gUG9saXRpY28sIHk9IGRpc3BsYXlfdGV4dF93aWR0aCwgY29sb3I9IFBvbGl0aWNvKSArDQogIGdlb21fYm94cGxvdCAoKSArDQogICAgbGFicyh0aXRsZSA9ICJMYXJnbyBwcm9tZWRpbyBkZWwgdHdlZXQiLCB4ID0gIlBvbGl0aWNvIiwgeSA9ICJDYW50aWRhZCBjYXJhY3RlcmVzIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgIHRlbWExDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMTItIFdobyB1c2VzIG1vc3Qgd29yZHM/IDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KVGhlIGlkZWEgaXMgdG8gYW5hbHl6ZSB3aG8gaXMgdGhlIG9uZSB3aG8gdXNlZCB0aGUgbW9zdCBkaWZmZXJlbnQgd29yZHMgb24gYXZlcmFnZSBkdXJpbmcgdGhpcyB0aW1lLCBpbiB0aGlzIGNhc2Ugd2UgYXJlIGdvaW5nIHRvIGRpdmlkZSBieSB0aGUgbnVtYmVyIG9mIHR3ZWV0cyBoZSBtYWRlLCBzbyBpdCBpcyBub3JtYWxpemVkIGZvciBhbGwgdGhvc2UgYW5hbHl6ZWQuDQoNCipDb21tb24gY29ubmVjdG9ycyBzdWNoIGFzICJvbiIsICJ0byIsICJmcm9tIiwgZXRjLiBhcmUgbm90IGNvdW50ZWQqDQoNCiAgLSAqRXNwZXJ0IGlzIGJlbG93IDE1IHdvcmRzIHBlciB0d2VldCwgaXQgaXMgdGhlIGxlYXN0IHVzZWQuKg0KICAtICpUaGUgcmVzdCBpcyBpbiBhIHNpbWlsYXIgYW1vdW50IG9mIGJldHdlZW4gMTUgYW5kIDIwIHdvcmRzLioNCg0KDQoNCmBgYHtyfQ0KQ2FudGlkYWRfcGFsYWJyYXM9IHR1aXRzX3Rva2VucyU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbyklPiUNCiAgY291bnQoUG9saXRpY28pJT4lDQppbm5lcl9qb2luKENhbnRpZGFkX3R3ZWV0cywgLiwgYnkgPSAiUG9saXRpY28iKSU+JQ0KICBtdXRhdGUoY2FudGlkYWRfcHJvbWVkaW8gPSBuLnkgLyBuLngpDQoNCg0KQ2FudGlkYWRfcGFsYWJyYXMlPiUgZ2dwbG90KCkrDQogIGFlcyh4PXJlb3JkZXIoUG9saXRpY28sIC1jYW50aWRhZF9wcm9tZWRpbyksIHk9IGNhbnRpZGFkX3Byb21lZGlvLCBmaWxsPSBQb2xpdGljbykgKw0KICBnZW9tX2NvbCgpICsNCiAgZmFjZXRfd3JhcCgiUGFydGlkby54Iiwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgbGFicyh0aXRsZSA9ICJVc28gZGUgcGFsYWJyYXMiLCB4ID0gInR3ZWV0cyIsIHkgPSAiQ2FudGlkYWQiKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICAgdGVtYTENCg0KDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gIDEzLSBXaG8gdXNlcyB0aGUgZGlmZmVyZW50IHdvcmRzPyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQpXZSBzZWVrIHRvIHNlZSB0aGUgZGlzdGluY3RpdmUgbGV4aWNvbiB0aGF0IGlzIGluIGVhY2ggb2YgdGhlIGFjY291bnRzLCBjb3VudGluZyB0aGVpciB1bmlxdWUgd29yZHMgYW5kIGl0IHNob3dzOg0KDQotICpEaWZmZXJlbmNlcyBiZXR3ZWVuIExhdmFnbmEsIE1hY3JpLCBDcmlzdGluYSB3aXRoIHRoZSByZXN0IG9mIHRob3NlIHdobyB3cml0ZSoNCg0KLSAqRXNwZXJ0IHRoYXQgaXMgdGhlIG9uZSB3aXRoIHRoZSBsZWFzdCB2YXJpZWQgbGV4aWNvbioNCg0KDQpgYGB7cn0NCnR1aXRzX3Rva2VucyU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbyklPiUNCiAgZGlzdGluY3QoUGFsYWJyYSklPiUNCiAgY291bnQoUG9saXRpY28pJT4lDQppbm5lcl9qb2luKENhbnRpZGFkX3R3ZWV0cywgLiwgYnkgPSAiUG9saXRpY28iKSAgJT4lDQogIG11dGF0ZShjYW50aWRhZF9wcm9tZWRpbyA9IG4ueSAvIG4ueCkgJT4lIA0KICBnZ3Bsb3QoKSsNCiAgYWVzKHg9cmVvcmRlcihQb2xpdGljbywgY2FudGlkYWRfcHJvbWVkaW8pLCB5PSBjYW50aWRhZF9wcm9tZWRpbywgZmlsbD0gUG9saXRpY28pICsNCiAgZ2VvbV9jb2woKSArDQogIGZhY2V0X3dyYXAoIlBhcnRpZG8ueCIsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnModGl0bGUgPSAiUGFsYWJyYXMgZGlzdGludGFzIiwgeCA9ICJ0d2VldHMiLCB5ID0gIkNhbnRpZGFkIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgIHRlbWExDQogIA0KYGBgDQoNCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDE0LSBNb3N0IHVzZWQgd29yZHMgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KTm93IHRoYXQgd2Uga25vdyB3aXRoIHdoYXQgdmFyaWV0eSBvZiB3b3Jkcywgd2UgY2FuIGFuYWx5emUgd2hpY2ggb25lcyB0aGV5IHVzZWQgdGhlIG1vc3QNCg0KSW4gdGhpcyBjYXNlLCBlYWNoIGdyYXBoIGhhcyBhIGRpZmZlcmVudCBzY2FsZSBzbyB0aGF0IGl0IGlzIG5vdCBsb3N0IGR1ZSB0byB0aGUgbnVtYmVyIG9mIHR3ZWV0cyBtYWRlLg0KDQpUaGUgbW9zdCB1c2VkIHdvcmRzIHdlcmU6DQoNCi0gIiphdm9pZCoiDQotICIqZGVidCoiDQotICIqSnVzdGljZSoiDQotICIqZnJlZWRvbSoiIG1haW5seSB1c2VkIGJ5IEVzcGVydC4NCg0KDQpgYGB7cn0NCnR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgJT4lDQogICAgZ3JvdXBfYnkoUGFydGlkbywgUG9saXRpY28pICU+JQ0KICAgIGNvdW50KFBhbGFicmEsIHNvcnQgPSBUKSAlPiUNCiAgICAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbj0gMTApICU+JQ0KICAgICAgZmlsdGVyKFBhcnRpZG8gPT0gICJQUk8iKSAlPiUNCiAgICBnZ3Bsb3QoKSArDQogICAgYWVzKFBhbGFicmEsIG4sIGZpbGwgPSBQb2xpdGljbykgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGZhY2V0X3dyYXAoIlBvbGl0aWNvIiwgc2NhbGVzID0gImZyZWUiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiUGFsYWJyYXMgbcOhcyB1c2FkYXMiKSArDQogICAgIHRlbWExDQoNCiB0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIGdyb3VwX2J5KFBhcnRpZG8sIFBvbGl0aWNvKSAlPiUNCiAgICBjb3VudChQYWxhYnJhLCBzb3J0ID0gVCkgJT4lDQogICAgIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG49IDEwKSAlPiUNCiAgICAgIGZpbHRlcihQYXJ0aWRvID09ICAiUGVyb25pc21vIikgJT4lDQogICAgZ2dwbG90KCkgKw0KICAgIGFlcyhQYWxhYnJhLCBuLCBmaWxsID0gUG9saXRpY28pICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICBmYWNldF93cmFwKCJQb2xpdGljbyIsIHNjYWxlcyA9ICJmcmVlIikgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApKSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICBsYWJzKHRpdGxlID0gIlBhbGFicmFzIG3DoXMgdXNhZGFzIikgKw0KICAgICB0ZW1hMQ0KIA0KICB0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIGdyb3VwX2J5KFBhcnRpZG8sIFBvbGl0aWNvKSAlPiUNCiAgICBjb3VudChQYWxhYnJhLCBzb3J0ID0gVCkgJT4lDQogICAgIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG49IDEwKSAlPiUNCiAgICAgIGZpbHRlcihQYXJ0aWRvID09ICAib3Ryb3MgY2FuZGlkYXRvcyIpICU+JQ0KICAgIGdncGxvdCgpICsNCiAgICBhZXMoUGFsYWJyYSwgbiwgZmlsbCA9IFBvbGl0aWNvKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgZmFjZXRfd3JhcCgiUG9saXRpY28iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh0aXRsZSA9ICJQYWxhYnJhcyBtw6FzIHVzYWRhcyIpICsNCiAgICAgdGVtYTENCiAgDQogICB0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIGdyb3VwX2J5KFBhcnRpZG8sIFBvbGl0aWNvKSAlPiUNCiAgICBjb3VudChQYWxhYnJhLCBzb3J0ID0gVCkgJT4lDQogICAgIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG49IDEwKSAlPiUNCiAgICAgIGZpbHRlcihQYXJ0aWRvID09ICAiY3VlbnRhIHBhcnRpZGFyaWEiKSAlPiUNCiAgICBnZ3Bsb3QoKSArDQogICAgYWVzKFBhbGFicmEsIG4sIGZpbGwgPSBQb2xpdGljbykgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGZhY2V0X3dyYXAoIlBvbGl0aWNvIiwgc2NhbGVzID0gImZyZWUiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiUGFsYWJyYXMgbcOhcyB1c2FkYXMiKSArDQogICAgIHRlbWExDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMTUtIE1vc3QgdXNlZCBwb3NpdGl2ZSB3b3JkcyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQpCeSBoYXZpbmcgYSBzY29yZSBmb3IgZWFjaCB3b3JkIGdpdmVuIGJ5IHRoZSBsZXhpY29uIGRpY3Rpb25hcnksIHdlIGNhbiBhbHNvIGxvb2sgZm9yIHRoZSBwb3NpdGl2ZSB3b3JkcyB0aGF0IGVhY2ggb2YgdGhlIHBvbGl0aWNpYW5zIHVzZSB0aGUgbW9zdC4NCg0KSW4gdGhpcyBjYXNlOg0KDQotIE5vdGUgdGhlIHVzZSBvZiB0aGUgd29yZHMgKioiZnJlZWRvbSIqKiBhbmQgKioianVzdGljZSIqKiB3aGljaCBhcmUgY29uc2lkZXJlZCBwb3NpdGl2ZQ0KDQotIFRoZSB1c2Ugb2YgdGhlIHdvcmQgKioidGhhbmsgeW91IioqIGFwcGVhcnMgcXVpdGUgYSBsb3QsIG1haW5seSBmcm9tIHRob3NlIGFjY291bnRzIHJlbGF0ZWQgdG8gaGVhbHRoICoqKEdpbmVzIEdvbnrDoWxleiBHYXJjw61hIGFuZCBGZXJuw6FuIFF1aXLDs3MpKioNCg0KDQpgYGB7cn0NCiB0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIGZpbHRlcihDYWxpZmljYWNpb24gPT0gICJQb3NpdGl2YSIpICU+JQ0KICAgIGdyb3VwX2J5KFBhcnRpZG8sIFBvbGl0aWNvKSAlPiUNCiAgICBjb3VudChQYWxhYnJhLCBzb3J0ID0gVCkgJT4lDQogICAgIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG49IDEwKSAlPiUNCiAgICAgIGZpbHRlcihQYXJ0aWRvID09ICAiUFJPIikgJT4lDQogICAgZ2dwbG90KCkgKw0KICAgIGFlcyhQYWxhYnJhLCBuLCBmaWxsID0gUG9saXRpY28pICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICBmYWNldF93cmFwKCJQb2xpdGljbyIsIHNjYWxlcyA9ICJmcmVlIikgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApKSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICBsYWJzKHRpdGxlID0gIlBhbGFicmFzIFBvc2l0aXZhcyBtw6FzIHVzYWRhcyIpIA0KDQogdHVpdHNfdG9rZW5zX2Vtb2Npb25lcyAlPiUNCiAgICBmaWx0ZXIoQ2FsaWZpY2FjaW9uID09ICAiUG9zaXRpdmEiKSAlPiUNCiAgICBncm91cF9ieShQYXJ0aWRvLCBQb2xpdGljbykgJT4lDQogICAgY291bnQoUGFsYWJyYSwgc29ydCA9IFQpICU+JQ0KICAgICBzbGljZV9tYXgob3JkZXJfYnkgPSBuLCBuPSAxMCkgJT4lDQogICAgICBmaWx0ZXIoUGFydGlkbyA9PSAgIlBlcm9uaXNtbyIpICU+JQ0KICAgIGdncGxvdCgpICsNCiAgICBhZXMoUGFsYWJyYSwgbiwgZmlsbCA9IFBvbGl0aWNvKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgZmFjZXRfd3JhcCgiUG9saXRpY28iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh0aXRsZSA9ICJQYWxhYnJhcyBQb3NpdGl2YXMgbcOhcyB1c2FkYXMiKSANCiANCiAgdHVpdHNfdG9rZW5zX2Vtb2Npb25lcyAlPiUNCiAgICBmaWx0ZXIoQ2FsaWZpY2FjaW9uID09ICAiUG9zaXRpdmEiKSAlPiUNCiAgICBncm91cF9ieShQYXJ0aWRvLCBQb2xpdGljbykgJT4lDQogICAgY291bnQoUGFsYWJyYSwgc29ydCA9IFQpICU+JQ0KICAgICBzbGljZV9tYXgob3JkZXJfYnkgPSBuLCBuPSAxMCkgJT4lDQogICAgICBmaWx0ZXIoUGFydGlkbyA9PSAgIm90cm9zIGNhbmRpZGF0b3MiKSAlPiUNCiAgICBnZ3Bsb3QoKSArDQogICAgYWVzKFBhbGFicmEsIG4sIGZpbGwgPSBQb2xpdGljbykgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGZhY2V0X3dyYXAoIlBvbGl0aWNvIiwgc2NhbGVzID0gImZyZWUiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiUGFsYWJyYXMgUG9zaXRpdmFzIG3DoXMgdXNhZGFzIikgDQogIA0KICAgdHVpdHNfdG9rZW5zX2Vtb2Npb25lcyAlPiUNCiAgICBmaWx0ZXIoQ2FsaWZpY2FjaW9uID09ICAiUG9zaXRpdmEiKSAlPiUNCiAgICBncm91cF9ieShQYXJ0aWRvLCBQb2xpdGljbykgJT4lDQogICAgY291bnQoUGFsYWJyYSwgc29ydCA9IFQpICU+JQ0KICAgICBzbGljZV9tYXgob3JkZXJfYnkgPSBuLCBuPSAxMCkgJT4lDQogICAgICBmaWx0ZXIoUGFydGlkbyA9PSAgImN1ZW50YSBwYXJ0aWRhcmlhIikgJT4lDQogICAgZ2dwbG90KCkgKw0KICAgIGFlcyhQYWxhYnJhLCBuLCBmaWxsID0gUG9saXRpY28pICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICBmYWNldF93cmFwKCJQb2xpdGljbyIsIHNjYWxlcyA9ICJmcmVlIikgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApKSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICBsYWJzKHRpdGxlID0gIlBhbGFicmFzIFBvc2l0aXZhcyBtw6FzIHVzYWRhcyIpIA0KYGBgDQoNCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDE2LSBNb3N0IHVzZWQgbmVnYXRpdmUgd29yZHMgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpCeSBoYXZpbmcgYSBzY29yZSBmb3IgZWFjaCB3b3JkIGdpdmVuIGJ5IHRoZSBsZXhpY29uIGRpY3Rpb25hcnksIHdlIGNhbiBhbHNvIGxvb2sgZm9yIHRoZSBuZWdhdGl2ZSB3b3JkcyB0aGF0IGVhY2ggb2YgdGhlIHBvbGl0aWNpYW5zIHVzZSB0aGUgbW9zdC4NCg0KICAtICpBdm9pZCosICpFbWVyZ2VuY3kqIG9yICpQcm9ibGVtKiBhcmUgdGhlIHdvcmRzIHRoYXQgYXBwZWFyIHRoZSBtb3N0LCB3aXRoaW4gdGhlIG1haW4gdG9waWMgb2Ygc3BlZWNoLCB3aGljaCBpcyB0aGUgcGFuZGVtaWMuDQoNCiAgLSAqRGVidCogaXMgYW5vdGhlciB3aWRlbHkgdXNlZCB3b3JkLCBhIGRpZmZpY3VsdCBzdWJqZWN0IHRvIGF2b2lkIHRoaXMgeWVhci4NCg0KDQoNCmBgYHtyfQ0KIHR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgJT4lDQogICAgZmlsdGVyKENhbGlmaWNhY2lvbiA9PSAgIk5lZ2F0aXZhIikgJT4lDQogICAgZ3JvdXBfYnkoUGFydGlkbywgUG9saXRpY28pICU+JQ0KICAgIGNvdW50KFBhbGFicmEsIHNvcnQgPSBUKSAlPiUNCiAgICAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbj0gMTApICU+JQ0KICAgICAgZmlsdGVyKFBhcnRpZG8gPT0gICJQUk8iKSAlPiUNCiAgICBnZ3Bsb3QoKSArDQogICAgYWVzKFBhbGFicmEsIG4sIGZpbGwgPSBQb2xpdGljbykgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGZhY2V0X3dyYXAoIlBvbGl0aWNvIiwgc2NhbGVzID0gImZyZWUiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiUGFsYWJyYXMgTmVnYXRpdmFzIG3DoXMgdXNhZGFzIikgDQoNCiB0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIGZpbHRlcihDYWxpZmljYWNpb24gPT0gICJOZWdhdGl2YSIpICU+JQ0KICAgIGdyb3VwX2J5KFBhcnRpZG8sIFBvbGl0aWNvKSAlPiUNCiAgICBjb3VudChQYWxhYnJhLCBzb3J0ID0gVCkgJT4lDQogICAgIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG49IDEwKSAlPiUNCiAgICAgIGZpbHRlcihQYXJ0aWRvID09ICAiUGVyb25pc21vIikgJT4lDQogICAgZ2dwbG90KCkgKw0KICAgIGFlcyhQYWxhYnJhLCBuLCBmaWxsID0gUG9saXRpY28pICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICBmYWNldF93cmFwKCJQb2xpdGljbyIsIHNjYWxlcyA9ICJmcmVlIikgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApKSArDQogICAgY29vcmRfZmxpcCgpICsNCiAgICBsYWJzKHRpdGxlID0gIlBhbGFicmFzIE5lZ2F0aXZhcyBtw6FzIHVzYWRhcyIpIA0KIA0KICB0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIGZpbHRlcihDYWxpZmljYWNpb24gPT0gICJOZWdhdGl2YSIpICU+JQ0KICAgIGdyb3VwX2J5KFBhcnRpZG8sIFBvbGl0aWNvKSAlPiUNCiAgICBjb3VudChQYWxhYnJhLCBzb3J0ID0gVCkgJT4lDQogICAgIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG49IDEwKSAlPiUNCiAgICAgIGZpbHRlcihQYXJ0aWRvID09ICAib3Ryb3MgY2FuZGlkYXRvcyIpICU+JQ0KICAgIGdncGxvdCgpICsNCiAgICBhZXMoUGFsYWJyYSwgbiwgZmlsbCA9IFBvbGl0aWNvKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgZmFjZXRfd3JhcCgiUG9saXRpY28iLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwKSkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgbGFicyh0aXRsZSA9ICJQYWxhYnJhcyBOZWdhdGl2YXMgbcOhcyB1c2FkYXMiKSANCiAgDQogICB0dWl0c190b2tlbnNfZW1vY2lvbmVzICU+JQ0KICAgIGZpbHRlcihDYWxpZmljYWNpb24gPT0gICJOZWdhdGl2YSIpICU+JQ0KICAgIGdyb3VwX2J5KFBhcnRpZG8sIFBvbGl0aWNvKSAlPiUNCiAgICBjb3VudChQYWxhYnJhLCBzb3J0ID0gVCkgJT4lDQogICAgIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG49IDEwKSAlPiUNCiAgICAgIGZpbHRlcihQYXJ0aWRvID09ICAiY3VlbnRhIHBhcnRpZGFyaWEiKSAlPiUNCiAgICBnZ3Bsb3QoKSArDQogICAgYWVzKFBhbGFicmEsIG4sIGZpbGwgPSBQb2xpdGljbykgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGZhY2V0X3dyYXAoIlBvbGl0aWNvIiwgc2NhbGVzID0gImZyZWUiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIGxhYnModGl0bGUgPSAiUGFsYWJyYXMgTmVnYXRpdmFzIG3DoXMgdXNhZGFzIikgDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gIDE3LSBGZWVsaW5ncyBpbiB0aGUgdHdlZXQgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpVc2luZyB0aGUgYWZpbm4gZGljdGlvbmFyeSBwdW5jdHVhdGlvbiBhZ2Fpbiwgd2UgcmVqb2luIHRoZSB3b3JkcyB0byB0aGUgdHdlZXRzIGFuZCBhdmVyYWdlZCB0aGUgcG9pbnRzIG9mIGFsbCB0aGUgd29yZHMsIG1vdmluZyBmcm9tIHRoZSB1bml0IHdvcmQgdmFsdWUgdG8gYSB1bml0IHZhbHVlIGZvciBlYWNoIHR3ZWV0IHBvc3RlZC4NCg0KICAtICpNb3N0IHR3ZWV0cyB3ZXJlIG5ldXRyYWwuKg0KICANCiAgLSAqVGhlIG1vc3QgcG9zaXRpdmUgaW4gdGhpcyBjb3Vyc2Ugd2VyZSBNLiBNYWNyaSwgQS4gRmVybmFuZGV6IGFuZCBSLiBMYXZhZ25hLioNCiAgDQogIC0gKlRoZSBtb3N0IG5lZ2F0aXZlIHdlcmUgTi4gRGVsIENhw7FvIGFuZCB0aGUgb2ZmaWNpYWwgUFJPIGFjY291bnQuKg0KDQoNCmBgYHtyfQ0KVHdlZXRzX0RGIDwtDQogIHR1aXRzX3Rva2Vuc19lbW9jaW9uZXMgJT4lDQogIGdyb3VwX2J5KHN0YXR1c19pZCkgJT4lDQogIHN1bW1hcmlzZShQdW50dWFjaW9uX3R3ZWV0LnggPSBtZWFuKFB1bnR1YWNpb24pKSAlPiUNCiAgbGVmdF9qb2luKFR3ZWV0c19ERiwgLiwgYnkgPSAic3RhdHVzX2lkIikNCg0KDQpUd2VldHNfREYgPC0gIFR3ZWV0c19ERiAlPiUNCiAgbXV0YXRlKFB1bnR1YWNpb25fdHdlZXQueF9sZXRyYSA9IGlmZWxzZShpcy5uYShQdW50dWFjaW9uX3R3ZWV0LngpLCAiTmV1dHJhbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQdW50dWFjaW9uX3R3ZWV0LnggPiAwLCAiUG9zaXRpdmEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShQdW50dWFjaW9uX3R3ZWV0LnggPT0gMCwgIk5ldXRyYWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5lZ2F0aXZhIikNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICApDQogICkgICAgICANCikNCg0KVHdlZXRzX0RGICU+JQ0KICBjb3VudChQb2xpdGljbywgUGFydGlkbywgUHVudHVhY2lvbl90d2VldC54X2xldHJhKSAlPiUNCiAgZ3JvdXBfYnkoUG9saXRpY28pICU+JQ0KICBtdXRhdGUoUHJvcG9yY2lvbiA9IG4gLyBzdW0obikpICU+JQ0KZ2dwbG90KCkgKw0KICBhZXMoUG9saXRpY28sIFByb3BvcmNpb24sIGZpbGwgPSBQdW50dWFjaW9uX3R3ZWV0LnhfbGV0cmEpICsNCiAgZ2VvbV9jb2woKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpKSArDQogICAgICBmYWNldF93cmFwKCJQYXJ0aWRvIiwgc2NhbGVzID0gImZyZWUiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KDQoNCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAxOC0gRmVlbGluZ3MgaW4gdGhlIFBSTyB2cyBQZXJvbmlzbW8gdHdlZXQgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpXZSB0YWtlIHRoZSA0IG1lbWJlcnMgdGhhdCB3ZSBoYXZlIGFscmVhZHkgYW5hbHl6ZWQgZnJvbSBlYWNoIG9mIHRoZSBwYXJ0aWVzICooUFJPIGFuZCBUT0RPUykqLCBhbmQgd2UgdW5pdGUgaXQgaW4gYSBzaW5nbGUgZ3JhcGggcGVyIHBhcnR5LCB3ZSBzZWUgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIGlzIHNvbWV0aGluZyBzaW1pbGFyLCBhbHRob3VnaCBQZXJvbmlzbSBoYWQgYSBsaXR0bGUgbW9yZSBwb3NpdGl2ZSB0d2VldHMgYW5kIGZld2VyIG5lZ2F0aXZlIHR3ZWV0cywgYnV0IG5vdCBhdCBzaWduaWZpY2FudCBsZXZlbHMuDQoNCg0KDQpgYGB7cn0NClR3ZWV0c19ERiAlPiUNCiAgY291bnQoUGFydGlkbywgUHVudHVhY2lvbl90d2VldC54X2xldHJhKSAlPiUNCiAgZ3JvdXBfYnkoUGFydGlkbykgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICJQUk8iIHxQYXJ0aWRvID09ICJQZXJvbmlzbW8iKSU+JQ0KICBtdXRhdGUoUHJvcG9yY2lvbiA9IG4gLyBzdW0obikpICU+JQ0KZ2dwbG90KCkgKw0KICBhZXMoUGFydGlkbywgUHJvcG9yY2lvbiwgZmlsbCA9IFB1bnR1YWNpb25fdHdlZXQueF9sZXRyYSkgKw0KICBnZW9tX2NvbCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gIDE5LSBGZWVsaW5nIG1vbnRoIGJ5IG1vbnRoIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KVGhlIGlkZWEgaXMgdG8gYW5hbHl6ZSBpZiB0aGVyZSBhcmUgZmx1Y3R1YXRpb25zIGluIHdoYXQgdGhleSBoYXZlIGJlZW4gdHdlZXRpbmcgb3ZlciB0aW1lIGFuZCB0aGVpciBmZWVsaW5ncy4NCg0KICAtIEluIHRoZSAqKlBSTyoqIHRoZXJlIHdlcmUgbm8gYmlnIGNoYW5nZXMsIHRoZSBsYXN0IHR3ZWV0cyBvZiBCdWxscmljaCBhcmUgbW9yZSBwb3NpdGl2ZS4NCiAgDQogIC0gQW1vbmcgdGhlIG90aGVyIGNhbmRpZGF0ZXMgKipOaWNvbGFzIERlbCBDYcOxbyoqIGlzIGFsd2F5cyBuZWdhdGl2ZSwgYnV0IGhhcyBiZWVuIGxlc3MgbmVnYXRpdmUgbGF0ZWx5Lg0KICANCiAgLSBBbW9uZyB0aGUgKipGcmVudGUgZGUgVG9kb3MqKiB0aGVyZSBpcyBhIGxvdCBvZiBmbHVjdHVhdGlvbiwgdGhlIFByZXNpZGVudCBzZWVtcyB0byBiZSBvbiBhIHBhdGggdG93YXJkcyBuZWdhdGl2aXR5Lg0KICANCg0KYGBge3J9DQpUd2VldHNfREYkUHVudHVhY2lvbl90d2VldC54ID0gaWZlbHNlKGlzLm5hKFR3ZWV0c19ERiRQdW50dWFjaW9uX3R3ZWV0LngpLCAwLCBUd2VldHNfREYkUHVudHVhY2lvbl90d2VldC54KQ0KDQpUd2VldHNfREYgJT4lDQpncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgbWVzKSAlPiUNCiAgZmlsdGVyKFBhcnRpZG8gPT0gIlBSTyIpJT4lDQogIHN1bW1hcmlzZShzZW50aW1pZW50byA9IG1lYW4oUHVudHVhY2lvbl90d2VldC54KSkgJT4lDQpnZ3Bsb3QoKSArDQogIGFlcyhtZXMsIHNlbnRpbWllbnRvLCBjb2xvciA9IFBvbGl0aWNvKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gLjM1KSArDQogIGdlb21fbGluZSgpICsNCiAgZmFjZXRfZ3JpZChQb2xpdGljb34uKSArDQogIHRlbWExICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpUd2VldHNfREYgJT4lDQpncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgbWVzKSAlPiUNCiAgZmlsdGVyKFBhcnRpZG8gPT0gIm90cm9zIGNhbmRpZGF0b3MiKSU+JQ0KICBzdW1tYXJpc2Uoc2VudGltaWVudG8gPSBtZWFuKFB1bnR1YWNpb25fdHdlZXQueCkpICU+JQ0KZ2dwbG90KCkgKw0KICBhZXMobWVzLCBzZW50aW1pZW50bywgY29sb3IgPSBQb2xpdGljbykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IC4zNSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGZhY2V0X2dyaWQoUG9saXRpY29+LikgKw0KICB0ZW1hMSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KVHdlZXRzX0RGICU+JQ0KZ3JvdXBfYnkoUG9saXRpY28sIFBhcnRpZG8sIG1lcykgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICJQZXJvbmlzbW8iKSU+JQ0KICBzdW1tYXJpc2Uoc2VudGltaWVudG8gPSBtZWFuKFB1bnR1YWNpb25fdHdlZXQueCkpICU+JQ0KZ2dwbG90KCkgKw0KICBhZXMobWVzLCBzZW50aW1pZW50bywgY29sb3IgPSBQb2xpdGljbykgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBhbHBoYSA9IC4zNSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGZhY2V0X2dyaWQoUG9saXRpY29+LikgKw0KICB0ZW1hMSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KVHdlZXRzX0RGICU+JQ0KZ3JvdXBfYnkoUG9saXRpY28sIFBhcnRpZG8sIG1lcykgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICJjdWVudGEgcGFydGlkYXJpYSIpJT4lDQogIHN1bW1hcmlzZShzZW50aW1pZW50byA9IG1lYW4oUHVudHVhY2lvbl90d2VldC54KSkgJT4lDQpnZ3Bsb3QoKSArDQogIGFlcyhtZXMsIHNlbnRpbWllbnRvLCBjb2xvciA9IFBvbGl0aWNvKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGFscGhhID0gLjM1KSArDQogIGdlb21fbGluZSgpICsNCiAgZmFjZXRfZ3JpZChQb2xpdGljb34uKSArDQogIHRlbWExICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+ICAyMC0gRmVlbGluZyBCb3hwbG90IDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KDQpUaGUgZGlzdHJpYnV0aW9uIG9mIGZlZWxpbmdzIGFtb25nIGFsbCB0aGUgdHdlZXRzLCB0aG9zZSB0aGF0IGFyZSBlbmNsb3NlZCBpbiB0aGUgYm94ZXMgYXJlIHRoZSBub3JtYWwgb25lcywgd2hpbGUgdGhlIGxvb3NlIHBvaW50cyBhcmUgaXNvbGF0ZWQgdHdlZXRzIHRvIHdoYXQgdGhleSB1c3VhbGx5IHdyaXRlLg0KDQogIC0gKkVzcGVydCBkb2VzIG5vdCBwcmVzZW50IGFueSBraW5kIG9mIHBhdHRlcm4gb2YgZmVlbGluZ3MqDQoNCg0KYGBge3J9DQpUd2VldHNfREYgJT4lDQogIGdncGxvdCgpICsNCiAgYWVzKFBvbGl0aWNvLCBQdW50dWFjaW9uX3R3ZWV0LngsIGZpbGwgPSBQb2xpdGljbykgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGNvb3JkX2ZsaXAoKSArIA0KICBsYWJzKHk9ICJTZW50aW1pZW50byIpICsNCiAgdGVtYTENCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAyMS0gQ29ycmVsYXRpb24gYmV0d2VlbiBQUk8gdnMgUGVyb25pc21vIHR3ZWV0ZWQ8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQpJdCBpcyBzZWFyY2hlZCB0aHJvdWdoIHRoZSB3b3JkcyB0aGF0IHRoZXkgdXNlZCB3aGF0IGlzIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgcG9saXRpY2lhbnMgYW5kIHRoZWlyIHR3ZWV0cywgYW5kIHNldmVyYWwgb2JzZXJ2YXRpb25zIGNhbiBiZSBtYWRlOg0KDQogIC0gKlF1aXLDs3MgYW5kIExhcnJldGEgYXJlIHRoZSBvbmVzIHdpdGggdGhlIGhpZ2hlc3QgY29ycmVsYXRpb24sIGRlbW9uc3RyYXRpbmcgZ29vZCBtYW5hZ2VtZW50IG9mIEJ1ZW5vcyBBaXJlcyBjb21tdW5pY2F0aW9uLCB3aGVyZSBib3RoIGNvbnRpbnVlIGluIHRoZSBzYW1lIGRpcmVjdGlvbi4gKg0KDQogIC0gKk1hY3JpIGlzIHRoZSBvbmUgd2l0aCB0aGUgbG93ZXN0IGNvcnJlbGF0aW9uIHdpdGggdGhlIHJlc3Qgb2YgdGhlIHBhcnRpY2lwYW50cywgYnV0IGl0IGFsc28gbWFrZXMgc2Vuc2UgdGhhdCBoaXMgaGlnaGVzdCBsZXZlbCBvZiByZWxhdGlvbnNoaXAgaXMgd2l0aCBCdWxscmljaC4gKg0KDQogIC0gKkJldHdlZW4gS2ljaWxvZmYgYW5kIEdpbmVzLCB0aGVyZSBpcyBhbiBpbXBvcnRhbnQgcmVsYXRpb25zaGlwLCBhcyB3ZWxsIGFzIHRoZSB0d28gb2YgdGhlbSB3aXRoIHRoZWlyIHNpbWlsYXIgcG9ydGXDsW9zIChRdWlyw7NzIGFuZCBMYXJyZXRhKS4gKg0KDQogIC0gKkNyaXN0aW5hIEtpcmNobmVyIGlzIGFub3RoZXIgd2hvIGRvZXMgbm90IGhhdmUgYSBoaWdoIGxldmVsIG9mIHJlbGF0aW9uc2hpcCBpbiBoZXIgdHdlZXRzIHdpdGggb3RoZXIgcG9saXRpY2lhbnMuICoNCg0KICAtICpJdCBpcyBzdXJwcmlzaW5nIHRoYXQgb25lIG9mIHRoZSBoaWdoZXN0IGxldmVscyBvZiByZWxhdGlvbnNoaXAgaW4gdGVybXMgb2Ygd2hhdCBpcyBjb21tdW5pY2F0ZWQgaXMgYmV0d2VlbiBBbGJlcnRvIEZlcm7DoW5kZXogYW5kIFBhdHJpY2lhIEJ1bGxyaWNoLiAqDQoNCg0KDQpgYGB7cn0NCnR3ZWV0c19zcHJlYWQyIDwtIHR1aXRzX3Rva2VucyAlPiUgDQogZmlsdGVyKFBhcnRpZG8gPT0gICJQUk8iIHwgUGFydGlkbyA9PSAiUGVyb25pc21vIiklPiUgDQogIGdyb3VwX2J5KFBvbGl0aWNvLCBQYWxhYnJhKSAlPiUgDQogIGNvdW50KFBhbGFicmEpICU+JQ0KICAgICAgc3ByZWFkKGtleSA9IFBvbGl0aWNvLCB2YWx1ZSA9IG4sIGZpbGwgPSBOQSwgZHJvcCA9IFRSVUUpDQp0d2VldHNfc3ByZWFkMltpcy5uYSh0d2VldHNfc3ByZWFkMildIDwtIDANCg0KbmFtZXModHdlZXRzX3NwcmVhZDIpIDwtIGMoIlBhbGFicmEiLCAiQS5GZXJuYW5kZXoiLCAiQS5LaWNpbGxvZiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiQy5LaXJjaG5lciIsICJGLlF1aXJvcyIsICJHaW5lcy5HRyIsIkguTGFycmV0YSIsICJNLk1hY3JpIiwgIlAuQnVsbHJpY2giICkNCg0KbWV0aG9kIDwtICJwZWFyc29uIg0KbV9jb3IgPC0gbWF0cml4KG5yb3cgPSA4LCBuY29sID0gOCkNCmZvciAoaSBpbiAxOmRpbShtX2NvcilbMV0pIHsNCiAgICAgIGZvciAoaiBpbiAxOmRpbShtX2NvcilbMl0pIHsNCiAgICAgICAgICAgIGZvcm0gPC0gYXMuZm9ybXVsYShwYXN0ZSgifiIsIG5hbWVzKHR3ZWV0c19zcHJlYWQyKVtpKzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIisiLCBuYW1lcyh0d2VldHNfc3ByZWFkMilbaisxXSkpDQogICAgICAgICAgICBpZihpIT1qKXsNCiAgICAgICAgICAgICAgICAgIG1fY29yW2ksal0gPC0gY29yLnRlc3QoZm9ybSwgbWV0aG9kID0gbWV0aG9kLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHR3ZWV0c19zcHJlYWQyKSRlc3RpbWF0ZQ0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgaWYoaT09ail7bV9jb3JbaSxqXSA8LSAxfQ0KICAgICAgfQ0KfQ0KY29sbmFtZXMobV9jb3IpIDwtIG5hbWVzKHR3ZWV0c19zcHJlYWQyKVsyOjldDQpyb3duYW1lcyhtX2NvcikgPC0gbmFtZXModHdlZXRzX3NwcmVhZDIpWzI6OV0NCmNvcnJwbG90KG1fY29yLCBtZXRob2Q9ImNvbG9yIiwgdHlwZT0idXBwZXIiLCBvcmRlcj0iaGNsdXN0IiwgDQogICAgICAgICBhZGRDb2VmLmNvbCA9ICJibGFjayIsIHRsLmNvbD0iYmxhY2siLCB0bC5zcnQ9NDUsDQogICAgICAgICBzaWcubGV2ZWwgPSAwLjAxLCBpbnNpZyA9ICJibGFuayIsIGRpYWc9RkFMU0UpDQoNCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAyMi0gQ29ycmVsYXRpb24gYmV0d2VlbiB0aGUgdHdlZXRlZCBjYW5kaWRhdGVzIGZvciBwcmVzaWRlbnQuIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KLSBUaGUgcmVsYXRpb25zaGlwIGJldHdlZW4gd2hhdCB0aGUgY2FuZGlkYXRlcyB3cml0ZSBoYXMgYSBjbHVzdGVyIHRoYXQgc3RhbmRzIG91dCBhYm92ZSB0aGUgcmVzdCwgd2hpY2ggaXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIEVzcGVydCwgR8OzbWV6IENlbnR1cmnDs24gYW5kIEFsYmVydG8gRmVybsOhbmRlei4NCg0KLSBOaWNvbGFzIERlbCBDYcOxbyBoYXMgYSBoaWdoIGxldmVsIG9mIHJlbGF0aW9uc2hpcCB3aXRoIEfDs21leiBDZW50dXJpw7NuLCBhbmQgdG8gYSBtZWRpdW0gZXh0ZW50IHdpdGggQWxiZXJ0byBGZXJuw6FuZGV6IGFuZCBFc3BlcnQuDQoNCi0gTGF2YWduYSBhbmQgTWFjcmkgZG8gbm90IHByZXNlbnQgYSBncmVhdCBjb3JyZWxhdGlvbiB3aXRoIHRoZSByZXN0IG9mIHRoZSBwb2xpdGljaWFucy4NCg0KDQpgYGB7cn0NCnR3ZWV0c19zcHJlYWQyIDwtIHR1aXRzX3Rva2VucyAlPiUgDQogIGZpbHRlcihQYXJ0aWRvID09ICAib3Ryb3MgY2FuZGlkYXRvcyIgfCBQb2xpdGljbyA9PSAiQS5GZXJuYW5kZXoifCBQb2xpdGljbyA9PSAiTS5NYWNyaSIpJT4lIA0KICBncm91cF9ieShQb2xpdGljbywgUGFsYWJyYSkgJT4lIA0KICBjb3VudChQYWxhYnJhKSAlPiUNCiAgICAgIHNwcmVhZChrZXkgPSBQb2xpdGljbywgdmFsdWUgPSBuLCBmaWxsID0gTkEsIGRyb3AgPSBUUlVFKQ0KdHdlZXRzX3NwcmVhZDJbaXMubmEodHdlZXRzX3NwcmVhZDIpXSA8LSAwDQoNCm5hbWVzKHR3ZWV0c19zcHJlYWQyKSA8LSBjKCJQYWxhYnJhIiwgIkEuRmVybmFuZGV6IiwgIkouRXNwZXJ0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICJHb21lekNlbnR1cmlvbiIsICJNLk1hY3JpIiwgIk4uRGVsQ2HDsW8iLCJSLkxhdmFnbmEiKQ0KDQptZXRob2QgPC0gInBlYXJzb24iDQptX2NvciA8LSBtYXRyaXgobnJvdyA9IDYsIG5jb2wgPSA2KQ0KZm9yIChpIGluIDE6ZGltKG1fY29yKVsxXSkgew0KICAgICAgZm9yIChqIGluIDE6ZGltKG1fY29yKVsyXSkgew0KICAgICAgICAgICAgZm9ybSA8LSBhcy5mb3JtdWxhKHBhc3RlKCJ+IiwgbmFtZXModHdlZXRzX3NwcmVhZDIpW2krMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKyIsIG5hbWVzKHR3ZWV0c19zcHJlYWQyKVtqKzFdKSkNCiAgICAgICAgICAgIGlmKGkhPWopew0KICAgICAgICAgICAgICAgICAgbV9jb3JbaSxqXSA8LSBjb3IudGVzdChmb3JtLCBtZXRob2QgPSBtZXRob2QsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gdHdlZXRzX3NwcmVhZDIpJGVzdGltYXRlDQogICAgICAgICAgICB9DQogICAgICAgICAgICBpZihpPT1qKXttX2NvcltpLGpdIDwtIDF9DQogICAgICB9DQp9DQpjb2xuYW1lcyhtX2NvcikgPC0gbmFtZXModHdlZXRzX3NwcmVhZDIpWzI6N10NCnJvd25hbWVzKG1fY29yKSA8LSBuYW1lcyh0d2VldHNfc3ByZWFkMilbMjo3XQ0KY29ycnBsb3QobV9jb3IsIG1ldGhvZD0iY29sb3IiLCB0eXBlPSJ1cHBlciIsIG9yZGVyPSJoY2x1c3QiLCANCiAgICAgICAgIGFkZENvZWYuY29sID0gImJsYWNrIiwgdGwuY29sPSJibGFjayIsIHRsLnNydD00NSwNCiAgICAgICAgIHNpZy5sZXZlbCA9IDAuMDEsIGluc2lnID0gImJsYW5rIiwgZGlhZz1GQUxTRSkNCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAyMy0gQ29ycmVsYXRpb24gYmV0d2VlbiB3aGF0IHdhcyB0d2VldGVkIGJldHdlZW4gcGFydHkgYWNjb3VudHM8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNClRoaXMgY2FuIGJlIGFuIGludGVyZXN0aW5nIGFuYWx5c2lzLCBzaW5jZSB0aGUgbnVtYmVyIG9mIHR3ZWV0cyBpcyBzaWduaWZpY2FudCBmb3IgZXZlcnlvbmUuDQoNCi0gU3VycHJpc2luZ2x5LCB0aGUgbWF4aW11bSBsZXZlbCBvZiByZWxhdGlvbnNoaXAgb2NjdXJzIGJldHdlZW4gdGhlIFVDUiBhbmQgVE9ET1MsIHR3byBwYXJ0aWVzIHRoYXQgdG9kYXkgYXJlIHByZXNlbnRlZCBhcyBvcHBvc2l0ZQ0KDQotIFRoZSBoaWdoIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBQUk8gYW5kIHRoZSBVQ1IgbWFrZXMgbW9yZSBzZW5zZS4NCg0KLSBUaGUgR0VOIHNlZW1zIHRvIGJlIHRoZSBwYXJ0eSB0aGF0IHdyaXRlcyBtb3JlIGRpZmZlcmVudGx5IGZyb20gdGhlIHJlc3QuDQoNCi0gSG93ZXZlciwgd2UgY2FuIG5vdGUgdGhhdCwgdW5saWtlIHRoZSBpbmRpdmlkdWFsIGFjY291bnRzLCB0aGUgc3VwcG9ydGVycyBoYXZlIG1vcmUgcmVsYXRpb25zaGlwLCBkdWUgdG8gdGhlaXIgbW9yZSBuZXV0cmFsIGxhbmd1YWdlIGFuZCBvcmdhbmljIGNvbW11bmljYXRpb24uDQoNCg0KYGBge3J9DQp0d2VldHNfc3ByZWFkMiA8LSB0dWl0c190b2tlbnMgJT4lIA0KICBmaWx0ZXIoUGFydGlkbyA9PSAgImN1ZW50YSBwYXJ0aWRhcmlhIiklPiUgDQogIGdyb3VwX2J5KFBvbGl0aWNvLCBQYWxhYnJhKSAlPiUgDQogIGNvdW50KFBhbGFicmEpICU+JQ0KICAgICAgc3ByZWFkKGtleSA9IFBvbGl0aWNvLCB2YWx1ZSA9IG4sIGZpbGwgPSBOQSwgZHJvcCA9IFRSVUUpDQp0d2VldHNfc3ByZWFkMltpcy5uYSh0d2VldHNfc3ByZWFkMildIDwtIDANCg0KbmFtZXModHdlZXRzX3NwcmVhZDIpIDwtIGMoIlBhbGFicmEiLCAiR0VOIiwgIlBSTyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiVE9ET1MiLCAiVUNSIikNCg0KbWV0aG9kIDwtICJwZWFyc29uIg0KbV9jb3IgPC0gbWF0cml4KG5yb3cgPSA0LCBuY29sID0gNCkNCmZvciAoaSBpbiAxOmRpbShtX2NvcilbMV0pIHsNCiAgICAgIGZvciAoaiBpbiAxOmRpbShtX2NvcilbMl0pIHsNCiAgICAgICAgICAgIGZvcm0gPC0gYXMuZm9ybXVsYShwYXN0ZSgifiIsIG5hbWVzKHR3ZWV0c19zcHJlYWQyKVtpKzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIisiLCBuYW1lcyh0d2VldHNfc3ByZWFkMilbaisxXSkpDQogICAgICAgICAgICBpZihpIT1qKXsNCiAgICAgICAgICAgICAgICAgIG1fY29yW2ksal0gPC0gY29yLnRlc3QoZm9ybSwgbWV0aG9kID0gbWV0aG9kLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHR3ZWV0c19zcHJlYWQyKSRlc3RpbWF0ZQ0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgaWYoaT09ail7bV9jb3JbaSxqXSA8LSAxfQ0KICAgICAgfQ0KfQ0KY29sbmFtZXMobV9jb3IpIDwtIG5hbWVzKHR3ZWV0c19zcHJlYWQyKVsyOjVdDQpyb3duYW1lcyhtX2NvcikgPC0gbmFtZXModHdlZXRzX3NwcmVhZDIpWzI6NV0NCmNvcnJwbG90KG1fY29yLCBtZXRob2Q9ImNvbG9yIiwgdHlwZT0idXBwZXIiLCBvcmRlcj0iaGNsdXN0IiwgDQogICAgICAgICBhZGRDb2VmLmNvbCA9ICJibGFjayIsIHRsLmNvbD0iYmxhY2siLCB0bC5zcnQ9NDUsDQogICAgICAgICBzaWcubGV2ZWwgPSAwLjAxLCBpbnNpZyA9ICJibGFuayIsIGRpYWc9RkFMU0UpDQpgYGANCg0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAyNC0gTWFjcmkgdnMgRmVybmFuZGV6IHdvcmQgdXNlIGNvbXBhcmlzb24gPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KDQpUaGUgaWRlYSBvZiB0aGlzIGdyYXBoIGlzIHRvIHNob3cgd2hpY2ggd29yZHMgYXJlIHRoZSBtb3N0IGRpZmZlcmVudCBpbiB0aGVpciB1c2UsIGluIHRoaXMgY2FzZSBiZXR3ZWVuICpNYXVyaWNpbyBNYWNyaSogYW5kICpBbGJlcnRvIEZlcm7DoW5kZXoqDQoNCg0KDQpgYGB7cn0NCg0KIyBQaXZvdGFqZSB5IGRlc3Bpdm90YWplDQp0d2VldHNfdW5waXZvdCA8LSB0dWl0c190b2tlbnMgJT4lIGdyb3VwX2J5KFBvbGl0aWNvLCBQYWxhYnJhKSAlPiUNCiAgICAgIGNvdW50KFBhbGFicmEpICU+JQ0KICAgICAgc3ByZWFkKGtleSA9IFBvbGl0aWNvLCB2YWx1ZSA9IG4sIGZpbGwgPSAwLCBkcm9wID0gVFJVRSkgJT4lIA0KICAgICAgZ2F0aGVyKGtleSA9ICJQb2xpdGljbyIsIHZhbHVlID0gIm4iLCAtUGFsYWJyYSkNCg0KDQogICAgICAgICAgICAgICAgICAjIFNlbGVjY2nDs24gZGUgbG9zIGF1dG9yZXMNCiAgICAgICAgICAgICAgICAgIHR3ZWV0c191bnBpdm90MiA8LSB0d2VldHNfdW5waXZvdCAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoUG9saXRpY28gJWluJSBjKCJNLk1hY3JpIiwgIkEuRmVybmFuZGV6IikpDQogICAgICAgICAgICAgICAgICAjIFNlIGHDsWFkZSBlbCB0b3RhbCBkZSBwYWxhYnJhcyBkZSBjYWRhIGF1dG9yDQogICAgICAgICAgICAgICAgICB0d2VldHNfdW5waXZvdDIgPC0gdHdlZXRzX3VucGl2b3QyICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKFR3ZWV0c19ERiAlPiUgZ3JvdXBfYnkoUG9saXRpY28pICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShOID0gbigpKSwgYnkgPSAiUG9saXRpY28iKQ0KICAgICAgICAgICAgICAgICAgIyBDw6FsY3VsbyBkZSBvZGRzIHkgbG9nIG9mIG9kZHMgZGUgY2FkYSBwYWxhYnJhDQogICAgICAgICAgICAgICAgICB0d2VldHNfbG9nT2RkcyA8LSB0d2VldHNfdW5waXZvdDIgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKG9kZHMgPSAobiArIDEpIC8gKE4gKyAxKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoUG9saXRpY28sIFBhbGFicmEsIG9kZHMpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNwcmVhZChrZXkgPSBQb2xpdGljbywgdmFsdWUgPSBvZGRzKQ0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHNbLDRdIDwtIGxvZyh0d2VldHNfbG9nT2Rkc1ssMl0vdHdlZXRzX2xvZ09kZHNbLDNdKQ0KICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzRdIDwtICJsb2dfb2RkcyINCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzWyw1XSA8LSBhYnModHdlZXRzX2xvZ09kZHMkbG9nX29kZHMpDQogICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbNV0gPC0gImFic19sb2dfb2RkcyINCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzIDwtIHR3ZWV0c19sb2dPZGRzICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGF1dG9yX2ZyZWN1ZW50ZSA9IGlmX2Vsc2UobG9nX29kZHMgPiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzNdKSkNCg0KRGlmZXJlbmNpYV9BRiA8LSB0d2VldHNfbG9nT2RkcyAlPiUgDQogIGFycmFuZ2UoLWFic19sb2dfb2RkcywgYnlncm91cCA9IEZBTFNFKSU+JSANCiAgZmlsdGVyKGF1dG9yX2ZyZWN1ZW50ZSA9PSAiQS5GZXJuYW5kZXoiKSU+JSANCiAgaGVhZCgxNSkNCg0KRGlmZXJlbmNpYV9NTSA8LSB0d2VldHNfbG9nT2RkcyAlPiUgDQogIGFycmFuZ2UobG9nX29kZHMsIGJ5Z3JvdXAgPSBGQUxTRSklPiUgDQogIGZpbHRlcihhdXRvcl9mcmVjdWVudGUgPT0gIk0uTWFjcmkiKSU+JSANCiAgaGVhZCgxNSkNCg0KRGlmZXJlbmNpYV9BRl9NTSA8LSByYmluZChEaWZlcmVuY2lhX0FGLERpZmVyZW5jaWFfTU0pDQoNCkRpZmVyZW5jaWFfQUZfTU0lPiUgDQogICAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihQYWxhYnJhLCBsb2dfb2RkcyksIHk9IGxvZ19vZGRzLCBmaWxsID0gYXV0b3JfZnJlY3VlbnRlKSkgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGxhYnMoeCA9ICItcGFsYWJyYSIsIHkgPSAiVXNvIiwgdGl0bGUgPSAiRmVybmFuZGV6IHZzIE1hY3JpIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0ZW1hMg0KDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMjUtIExhcnJldGEgdnMgS2ljaWxsb2Ygd29yZCB1c2UgY29tcGFyaXNvbjwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KVGhlIGlkZWEgb2YgdGhpcyBncmFwaCBpcyB0byBzaG93IHdoaWNoIHdvcmRzIGFyZSB0aGUgbW9zdCBkaWZmZXJlbnQgaW4gdGhlaXIgdXNlLCBpbiB0aGlzIGNhc2UgYmV0d2VlbiAqSG9yYWNpbyBMYXJyZXRhKiBhbmQgKkF4ZWwgS2ljaWxsb2YqDQoNCg0KDQpgYGB7cn0NCg0KDQojIFBpdm90YWplIHkgZGVzcGl2b3RhamUNCnR3ZWV0c191bnBpdm90IDwtIHR1aXRzX3Rva2VucyAlPiUgZ3JvdXBfYnkoUG9saXRpY28sIFBhbGFicmEpICU+JQ0KICAgICAgY291bnQoUGFsYWJyYSkgJT4lDQogICAgICBzcHJlYWQoa2V5ID0gUG9saXRpY28sIHZhbHVlID0gbiwgZmlsbCA9IDAsIGRyb3AgPSBUUlVFKSAlPiUgDQogICAgICBnYXRoZXIoa2V5ID0gIlBvbGl0aWNvIiwgdmFsdWUgPSAibiIsIC1QYWxhYnJhKQ0KDQoNCiAgICAgICAgICAgICAgICAgICMgU2VsZWNjacOzbiBkZSBsb3MgYXV0b3Jlcw0KICAgICAgICAgICAgICAgICAgdHdlZXRzX3VucGl2b3QyIDwtIHR3ZWV0c191bnBpdm90ICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihQb2xpdGljbyAlaW4lIGMoIkguTGFycmV0YSIsICJBLktpY2lsbG9mIikpDQogICAgICAgICAgICAgICAgICAjIFNlIGHDsWFkZSBlbCB0b3RhbCBkZSBwYWxhYnJhcyBkZSBjYWRhIGF1dG9yDQogICAgICAgICAgICAgICAgICB0d2VldHNfdW5waXZvdDIgPC0gdHdlZXRzX3VucGl2b3QyICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKFR3ZWV0c19ERiAlPiUgZ3JvdXBfYnkoUG9saXRpY28pICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShOID0gbigpKSwgYnkgPSAiUG9saXRpY28iKQ0KICAgICAgICAgICAgICAgICAgIyBDw6FsY3VsbyBkZSBvZGRzIHkgbG9nIG9mIG9kZHMgZGUgY2FkYSBwYWxhYnJhDQogICAgICAgICAgICAgICAgICB0d2VldHNfbG9nT2RkcyA8LSB0d2VldHNfdW5waXZvdDIgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKG9kZHMgPSAobiArIDEpIC8gKE4gKyAxKSkgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoUG9saXRpY28sIFBhbGFicmEsIG9kZHMpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIHNwcmVhZChrZXkgPSBQb2xpdGljbywgdmFsdWUgPSBvZGRzKSANCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzWyw0XSA8LSBsb2codHdlZXRzX2xvZ09kZHNbLDJdL3R3ZWV0c19sb2dPZGRzWywzXSkNCiAgICAgICAgICAgICAgICAgIG5hbWVzKHR3ZWV0c19sb2dPZGRzKVs0XSA8LSAibG9nX29kZHMiDQogICAgICAgICAgICAgICAgICB0d2VldHNfbG9nT2Rkc1ssNV0gPC0gYWJzKHR3ZWV0c19sb2dPZGRzJGxvZ19vZGRzKQ0KICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzVdIDwtICJhYnNfbG9nX29kZHMiDQogICAgICAgICAgICAgICAgICB0d2VldHNfbG9nT2RkcyA8LSB0d2VldHNfbG9nT2RkcyAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhdXRvcl9mcmVjdWVudGUgPSBpZl9lbHNlKGxvZ19vZGRzID4gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzKHR3ZWV0c19sb2dPZGRzKVsyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzKHR3ZWV0c19sb2dPZGRzKVszXSkpDQoNCkRpZmVyZW5jaWFfQUsgPC0gdHdlZXRzX2xvZ09kZHMgJT4lIA0KICBhcnJhbmdlKC1sb2dfb2RkcywgYnlncm91cCA9IEZBTFNFKSU+JSANCiAgZmlsdGVyKGF1dG9yX2ZyZWN1ZW50ZSA9PSAiQS5LaWNpbGxvZiIpJT4lIA0KICBoZWFkKDE1KQ0KDQpEaWZlcmVuY2lhX0hMIDwtIHR3ZWV0c19sb2dPZGRzICU+JSANCiAgYXJyYW5nZShhYnNfbG9nX29kZHMsIGJ5Z3JvdXAgPSBGQUxTRSklPiUgDQogIGZpbHRlcihhdXRvcl9mcmVjdWVudGUgPT0gIkguTGFycmV0YSIpJT4lIA0KICB0YWlsKDE1KQ0KDQpEaWZlcmVuY2lhX0FLX0hMIDwtIHJiaW5kKERpZmVyZW5jaWFfQUssRGlmZXJlbmNpYV9ITCkNCg0KRGlmZXJlbmNpYV9BS19ITCU+JSANCiAgICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKFBhbGFicmEsIGxvZ19vZGRzKSwgeT0gbG9nX29kZHMsIGZpbGwgPSBhdXRvcl9mcmVjdWVudGUpKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgbGFicyh4ID0gIi1wYWxhYnJhIiwgeSA9ICJVc28iLCB0aXRsZSA9ICJLaWNpbGxvZiB2cyBMYXJyZXRhIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0ZW1hMg0KDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gMjYtR2luZXMgdnMgUXVpcsOzcyB3b3JkIHVzZSBjb21wYXJpc29uIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KVGhlIGlkZWEgb2YgdGhpcyBncmFwaCBpcyB0byBzaG93IHdoaWNoIHdvcmRzIGFyZSB0aGUgbW9zdCBkaWZmZXJlbnQgaW4gdGhlaXIgdXNlLCBpbiB0aGlzIGNhc2UgYmV0d2VlbiAqR2luZXMgR29uemFsZXoqIGFuZCAqRmVybsOhbiBRdWlyw7NzKg0KDQoNCmBgYHtyfQ0KdHdlZXRzX3VucGl2b3QgPC0gdHVpdHNfdG9rZW5zICU+JSBncm91cF9ieShQb2xpdGljbywgUGFsYWJyYSkgJT4lDQogICAgICBjb3VudChQYWxhYnJhKSAlPiUNCiAgICAgIHNwcmVhZChrZXkgPSBQb2xpdGljbywgdmFsdWUgPSBuLCBmaWxsID0gMCwgZHJvcCA9IFRSVUUpICU+JSANCiAgICAgIGdhdGhlcihrZXkgPSAiUG9saXRpY28iLCB2YWx1ZSA9ICJuIiwgLVBhbGFicmEpDQoNCg0KICAgICAgICAgICAgICAgICAgIyBTZWxlY2Npw7NuIGRlIGxvcyBhdXRvcmVzDQogICAgICAgICAgICAgICAgICB0d2VldHNfdW5waXZvdDIgPC0gdHdlZXRzX3VucGl2b3QgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKFBvbGl0aWNvICVpbiUgYygiR2luZXMuR0ciLCAiRi5RdWlyb3MiKSkNCiAgICAgICAgICAgICAgICAgICMgU2UgYcOxYWRlIGVsIHRvdGFsIGRlIHBhbGFicmFzIGRlIGNhZGEgYXV0b3INCiAgICAgICAgICAgICAgICAgIHR3ZWV0c191bnBpdm90MiA8LSB0d2VldHNfdW5waXZvdDIgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBsZWZ0X2pvaW4oVHdlZXRzX0RGICU+JSBncm91cF9ieShQb2xpdGljbykgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKE4gPSBuKCkpLCBieSA9ICJQb2xpdGljbyIpDQogICAgICAgICAgICAgICAgICAjIEPDoWxjdWxvIGRlIG9kZHMgeSBsb2cgb2Ygb2RkcyBkZSBjYWRhIHBhbGFicmENCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzIDwtIHR3ZWV0c191bnBpdm90MiAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUob2RkcyA9IChuICsgMSkgLyAoTiArIDEpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChQb2xpdGljbywgUGFsYWJyYSwgb2RkcykgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgc3ByZWFkKGtleSA9IFBvbGl0aWNvLCB2YWx1ZSA9IG9kZHMpIA0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHNbLDRdIDwtIGxvZyh0d2VldHNfbG9nT2Rkc1ssMl0vdHdlZXRzX2xvZ09kZHNbLDNdKQ0KICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzRdIDwtICJsb2dfb2RkcyINCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzWyw1XSA8LSBhYnModHdlZXRzX2xvZ09kZHMkbG9nX29kZHMpDQogICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbNV0gPC0gImFic19sb2dfb2RkcyINCiAgICAgICAgICAgICAgICAgIHR3ZWV0c19sb2dPZGRzIDwtIHR3ZWV0c19sb2dPZGRzICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGF1dG9yX2ZyZWN1ZW50ZSA9IGlmX2Vsc2UobG9nX29kZHMgPiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXModHdlZXRzX2xvZ09kZHMpWzNdKSkNCg0KRGlmZXJlbmNpYV9HRyA8LSB0d2VldHNfbG9nT2RkcyAlPiUgDQogIGFycmFuZ2UoLWxvZ19vZGRzLCBieWdyb3VwID0gRkFMU0UpJT4lIA0KICBmaWx0ZXIoYXV0b3JfZnJlY3VlbnRlID09ICJHaW5lcy5HRyIpJT4lIA0KICB0YWlsKDE1KQ0KDQpEaWZlcmVuY2lhX0ZRIDwtIHR3ZWV0c19sb2dPZGRzICU+JSANCiAgYXJyYW5nZSgtYWJzX2xvZ19vZGRzLCBieWdyb3VwID0gRkFMU0UpJT4lIA0KICBmaWx0ZXIoYXV0b3JfZnJlY3VlbnRlID09ICJGLlF1aXJvcyIpJT4lIA0KICBoZWFkKDE1KQ0KDQpEaWZlcmVuY2lhX0dHX0ZRIDwtIHJiaW5kKERpZmVyZW5jaWFfR0csRGlmZXJlbmNpYV9GUSkNCg0KRGlmZXJlbmNpYV9HR19GUSU+JSANCiAgICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKFBhbGFicmEsIGxvZ19vZGRzKSwgeT0gbG9nX29kZHMsIGZpbGwgPSBhdXRvcl9mcmVjdWVudGUpKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgbGFicyh4ID0gIi1wYWxhYnJhIiwgeSA9ICJVc28iLCB0aXRsZSA9ICJRdWlyw7NzIHZzIEdpbmVzIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0ZW1hMg0KYGBgDQoNCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+IDI3LSBCdWxscmljaCB2cyBDcmlzdGluYSB3b3JkIHVzZSBjb21wYXJpc29uIDwvaDM+IDwvc3Bhbj4gPC9jZW50ZXI+DQoNCg0KVGhlIGlkZWEgb2YgdGhpcyBncmFwaCBpcyB0byBzaG93IHdoaWNoIHdvcmRzIGFyZSB0aGUgbW9zdCBkaWZmZXJlbnQgaW4gdGhlaXIgdXNlLCBpbiB0aGlzIGNhc2UgYmV0d2Vlbg0KICpDcmlzdGluYSBLaXJjaG5lciogYW5kICpQYXRyaWNpYSBCdWxscmljaCoNCg0KDQpgYGB7cn0NCnR3ZWV0c191bnBpdm90IDwtIHR1aXRzX3Rva2VucyAlPiUgZ3JvdXBfYnkoUG9saXRpY28sIFBhbGFicmEpICU+JQ0KICAgICAgY291bnQoUGFsYWJyYSkgJT4lDQogICAgICBzcHJlYWQoa2V5ID0gUG9saXRpY28sIHZhbHVlID0gbiwgZmlsbCA9IDAsIGRyb3AgPSBUUlVFKSAlPiUgDQogICAgICBnYXRoZXIoa2V5ID0gIlBvbGl0aWNvIiwgdmFsdWUgPSAibiIsIC1QYWxhYnJhKQ0KDQoNCiAgICAgICAgICAgICAgICAgICMgU2VsZWNjacOzbiBkZSBsb3MgYXV0b3Jlcw0KICAgICAgICAgICAgICAgICAgdHdlZXRzX3VucGl2b3QyIDwtIHR3ZWV0c191bnBpdm90ICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihQb2xpdGljbyAlaW4lIGMoIlAuQnVsbHJpY2giLCAiQy5LaXJjaG5lciIpKQ0KICAgICAgICAgICAgICAgICAgIyBTZSBhw7FhZGUgZWwgdG90YWwgZGUgcGFsYWJyYXMgZGUgY2FkYSBhdXRvcg0KICAgICAgICAgICAgICAgICAgdHdlZXRzX3VucGl2b3QyIDwtIHR3ZWV0c191bnBpdm90MiAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgIGxlZnRfam9pbihUd2VldHNfREYgJT4lIGdyb3VwX2J5KFBvbGl0aWNvKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoTiA9IG4oKSksIGJ5ID0gIlBvbGl0aWNvIikNCiAgICAgICAgICAgICAgICAgICMgQ8OhbGN1bG8gZGUgb2RkcyB5IGxvZyBvZiBvZGRzIGRlIGNhZGEgcGFsYWJyYQ0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHMgPC0gdHdlZXRzX3VucGl2b3QyICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShvZGRzID0gKG4gKyAxKSAvIChOICsgMSkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KFBvbGl0aWNvLCBQYWxhYnJhLCBvZGRzKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBzcHJlYWQoa2V5ID0gUG9saXRpY28sIHZhbHVlID0gb2RkcykgDQogICAgICAgICAgICAgICAgICB0d2VldHNfbG9nT2Rkc1ssNF0gPC0gbG9nKHR3ZWV0c19sb2dPZGRzWywyXS90d2VldHNfbG9nT2Rkc1ssM10pDQogICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbNF0gPC0gImxvZ19vZGRzIg0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHNbLDVdIDwtIGFicyh0d2VldHNfbG9nT2RkcyRsb2dfb2RkcykNCiAgICAgICAgICAgICAgICAgIG5hbWVzKHR3ZWV0c19sb2dPZGRzKVs1XSA8LSAiYWJzX2xvZ19vZGRzIg0KICAgICAgICAgICAgICAgICAgdHdlZXRzX2xvZ09kZHMgPC0gdHdlZXRzX2xvZ09kZHMgJT4lDQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYXV0b3JfZnJlY3VlbnRlID0gaWZfZWxzZShsb2dfb2RkcyA+IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbMl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyh0d2VldHNfbG9nT2RkcylbM10pKQ0KDQpEaWZlcmVuY2lhX1BCIDwtIHR3ZWV0c19sb2dPZGRzICU+JSANCiAgYXJyYW5nZSgtbG9nX29kZHMsIGJ5Z3JvdXAgPSBGQUxTRSklPiUgDQogIGZpbHRlcihhdXRvcl9mcmVjdWVudGUgPT0gIlAuQnVsbHJpY2giKSU+JSANCiAgdGFpbCgxNSkNCg0KRGlmZXJlbmNpYV9DRksgPC0gdHdlZXRzX2xvZ09kZHMgJT4lIA0KICBhcnJhbmdlKC1hYnNfbG9nX29kZHMsIGJ5Z3JvdXAgPSBGQUxTRSklPiUgDQogIGZpbHRlcihhdXRvcl9mcmVjdWVudGUgPT0gIkMuS2lyY2huZXIiKSU+JSANCiAgaGVhZCgxNSkNCg0KRGlmZXJlbmNpYV9QQl9DRksgPC0gcmJpbmQoRGlmZXJlbmNpYV9QQixEaWZlcmVuY2lhX0NGSykNCg0KRGlmZXJlbmNpYV9QQl9DRkslPiUgDQogICAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihQYWxhYnJhLCBsb2dfb2RkcyksIHk9IGxvZ19vZGRzLCBmaWxsID0gYXV0b3JfZnJlY3VlbnRlKSkgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIGxhYnMoeCA9ICItcGFsYWJyYSIsIHkgPSAiVXNvIiwgdGl0bGUgPSAiQ3Jpc3RpbmEgdnMgQnVsbHJpY2giKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRlbWEyDQpgYGANCg0KDQoNCg0KPGNlbnRlcj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjMjgyRjQ0OyI+IDxoMz4gIDI4LSBFbW90aW9ucyBpbiB0d2VldHMgPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KTm93IHdlIGFuYWx5emUgYSBicm9hZGVyIGZpZWxkIG9mIGVtb3Rpb25zIHRoYXQgd2VyZSB1c2VkIGJ5IHRoZSBkaWZmZXJlbnQgcG9saXRpY2lhbnMgYW1vbmcgYWxsIHRoZSB0d2VldHMgdGhhdCBoYXZlIGJlZW4gcHVibGlzaGVkIGluIHRoaXMgcGVyaW9kLg0KDQogIC0gQW1vbmcgdGhlIG1lbWJlcnMgb2YgKipQUk8qKiBhbmQgKipQZXJvbmlzbSoqLCAqdHJ1c3QqIHN0YW5kcyBvdXQgYXMgdGhlIG1haW4gc2VudGltZW50IGV4cHJlc3NlZA0KDQogIC0gSW4gYWNjb3VudHMgbGlrZSAqKkVzcGVydCoqIG9yICoqRGVsIENhw7FvKiogd2hhdCB0aGVpciB0d2VldHMgc2hvdyB0aGUgbW9zdCBpcyAqZmVhciouDQoNCiAgLSBUaGUgKipQUk8qKiBhbmQgKipQZXJvbmlzbSoqIGFjY291bnRzLCBtYWlubHkgYnkgdGhlIG1pbmlzdGVycyBhbmQgaGVhZHMgb2YgZ292ZXJubWVudHMsIHNlZWsgYSBmZWVsaW5nIG9mICogYW50aWNpcGF0aW9uICoNCg0KICAtIE90aGVyIGFjY291bnRzIGFyZSBoaWdoZXIgdG9uZSAqYW5ndWlzaCogb3ZlciB0aW1lLg0KDQogIC0gKlNhZG5lc3MqIGlzIGEgZ2VuZXJhbCBmZWVsaW5nIHRoYXQgaXMgaW5jb3Jwb3JhdGVkIGluIGFsbCB0d2VldHMsIGFuZCBpcyB1bmRlcnN0b29kIGJ5IHRoZSBjb21wbGV4IHNpdHVhdGlvbiB0aGF0IGEgcGFuZGVtaWMgbWVhbnMuDQoNCg0KDQoNCmBgYHtyfQ0KVGV4dFNlbnRpbWVudCA8LSBnZXRfbnJjX3NlbnRpbWVudChUd2VldHNfREYkdGV4dCkNCg0KDQpUd2VldHNfREZfc2VudGltaWVudG8gPC0gY2JpbmQoVHdlZXRzX0RGLCBUZXh0U2VudGltZW50KQ0KDQoNCmdhdGhlcihUd2VldHNfREZfc2VudGltaWVudG8sICJzZW50aW1lbnQiLCAidmFsdWVzIiwgMTAzOjExMikgJT4lDQogIGdyb3VwX2J5KFBvbGl0aWNvLCBQYXJ0aWRvLCBzZW50aW1lbnQpICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAgImN1ZW50YSBwYXJ0aWRhcmlhIiklPiUNCiAgZmlsdGVyKHNlbnRpbWVudCAhPSAibmVnYXRpdmUiICYgc2VudGltZW50ICE9InBvc2l0aXZlIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQpnZ3Bsb3QoKSArDQogIGFlcyhQb2xpdGljbywgUHJvcG9yY2lvbiwgZmlsbCA9IHNlbnRpbWVudCkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJzdGFjayIsIGNvbG9yID0gImJsYWNrIikgKw0KICBjb29yZF9mbGlwKCkgICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKw0KICBsYWJzKHkgPSAiUGFsYWJyYXMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpnYXRoZXIoVHdlZXRzX0RGX3NlbnRpbWllbnRvLCAic2VudGltZW50IiwgInZhbHVlcyIsIDEwMzoxMTIpICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgc2VudGltZW50KSAlPiUNCiAgZmlsdGVyKFBhcnRpZG8gPT0gICJQUk8iKSU+JQ0KICAgIGZpbHRlcihzZW50aW1lbnQgIT0gIm5lZ2F0aXZlIiAmIHNlbnRpbWVudCAhPSJwb3NpdGl2ZSIpJT4lDQogICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKHZhbHVlcykpICU+JQ0KICAgICAgbXV0YXRlKFByb3BvcmNpb24gPSBUb3RhbCAvIHN1bShUb3RhbCkpICU+JQ0KZ2dwbG90KCkgKw0KICBhZXMoUG9saXRpY28sIFByb3BvcmNpb24sIGZpbGwgPSBzZW50aW1lbnQpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAic3RhY2siLCBjb2xvciA9ICJibGFjayIpICsNCiAgY29vcmRfZmxpcCgpICArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpICsNCiAgbGFicyh5ID0gIlBhbGFicmFzIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KZ2F0aGVyKFR3ZWV0c19ERl9zZW50aW1pZW50bywgInNlbnRpbWVudCIsICJ2YWx1ZXMiLCAxMDM6MTEyKSAlPiUNCiAgZ3JvdXBfYnkoUG9saXRpY28sIFBhcnRpZG8sIHNlbnRpbWVudCkgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICAiUGVyb25pc21vIiklPiUNCiAgICBmaWx0ZXIoc2VudGltZW50ICE9ICJuZWdhdGl2ZSIgJiBzZW50aW1lbnQgIT0icG9zaXRpdmUiKSU+JQ0KICAgIHN1bW1hcmlzZShUb3RhbCA9IHN1bSh2YWx1ZXMpKSAlPiUNCiAgICAgIG11dGF0ZShQcm9wb3JjaW9uID0gVG90YWwgLyBzdW0oVG90YWwpKSAlPiUNCmdncGxvdCgpICsNCiAgYWVzKFBvbGl0aWNvLCBQcm9wb3JjaW9uLCBmaWxsID0gc2VudGltZW50KSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gInN0YWNrIiwgY29sb3IgPSAiYmxhY2siKSArDQogIGNvb3JkX2ZsaXAoKSAgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSArDQogIGxhYnMoeSA9ICJQYWxhYnJhcyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmdhdGhlcihUd2VldHNfREZfc2VudGltaWVudG8sICJzZW50aW1lbnQiLCAidmFsdWVzIiwgMTAzOjExMikgJT4lDQogIGdyb3VwX2J5KFBvbGl0aWNvLCBQYXJ0aWRvLCBzZW50aW1lbnQpICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAgIm90cm9zIGNhbmRpZGF0b3MiKSU+JQ0KICAgZmlsdGVyKHNlbnRpbWVudCAhPSAibmVnYXRpdmUiICYgc2VudGltZW50ICE9InBvc2l0aXZlIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQpnZ3Bsb3QoKSArDQogIGFlcyhQb2xpdGljbywgUHJvcG9yY2lvbiwgZmlsbCA9IHNlbnRpbWVudCkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJzdGFjayIsIGNvbG9yID0gImJsYWNrIikgKw0KICBjb29yZF9mbGlwKCkgICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKw0KICBsYWJzKHkgPSAiUGFsYWJyYXMiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCg0KDQoNCjxjZW50ZXI+IDxzcGFuIHN0eWxlPSJjb2xvcjogIzI4MkY0NDsiPiA8aDM+ICAyOS0gRW1vdGlvbnMgbW9udGggYnkgbW9udGggPC9oMz4gPC9zcGFuPiA8L2NlbnRlcj4NCg0KQWx0aG91Z2ggdGhlcmUgYXJlIG5vIG1ham9yIGNoYW5nZXMgd2hlbiBpdCBjb21lcyB0byBkb2luZyBzZW50aW1lbnQgYW5hbHlzaXMgZnJvbSBtb250aCB0byBtb250aCwgdGhlcmUgYXJlIHNvbWUgZGV0YWlsczoNCg0KLSBIZWFsdGggbWluaXN0ZXJzIHRyYW5zbWl0IG1vcmUgYW5kIG1vcmUgKmNvbmZpZGVuY2UqLg0KDQotIFRoZSBzby1jYWxsZWQgb3RoZXIgY2FuZGlkYXRlcyBpcyBkZWNsaW5pbmcgdGhlIHRyYW5zbWlzc2lvbiBvZiAqY29uZmlkZW5jZSouDQoNCi0gKipMYXJyZXRhKiogYWx0aG91Z2ggaXQgaGFzIGxvdyBpbiB0aGUgZmVlbGluZyBvZiAqY29uZmlkZW5jZSosIGNvbnRpbnVlcyB0byBleHBvc2Ugb25lIG9mICogYW50aWNpcGF0aW9uICouDQoNCi0gKipLaWNpbGxvZioqIGhhcyBhbiBpbmNyZWFzaW5nIG1lc3NhZ2Ugb2YgKmFuZ3Vpc2gqLg0KDQoNCg0KYGBge3J9DQpnYXRoZXIoVHdlZXRzX0RGX3NlbnRpbWllbnRvLCAic2VudGltZW50IiwgInZhbHVlcyIsIDEwMzoxMTIpICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgbWVzLCBzZW50aW1lbnQpICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAgImN1ZW50YSBwYXJ0aWRhcmlhIiklPiUNCiAgZmlsdGVyKHNlbnRpbWVudCAhPSAibmVnYXRpdmUiICYgc2VudGltZW50ICE9InBvc2l0aXZlIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQpnZ3Bsb3QoKSArDQphZXMoeCA9IG1lcywgeSA9UHJvcG9yY2lvbiwgY29sb3IgPSBzZW50aW1lbnQpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHNlbnRpbWVudCkpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IC40KSwgDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIikpICsNCiAgdGVtYTIgKw0KICBmYWNldF93cmFwKH4gUG9saXRpY28pICsNCiAgbGFicyh0aXRsZSA9ICJDYW1iaW8gZGUgbG9zIHNlbnRpbWllbnRvcyBlbiBlbCB0aWVtcG8iLCANCiAgICAgICB4ID0gIk1lcyIsIHkgPSAiUG9ycG9yY2nDs24iLCBjb2xvciA9ICJTZW50aW1pZW50byIpIA0KDQpnYXRoZXIoVHdlZXRzX0RGX3NlbnRpbWllbnRvLCAic2VudGltZW50IiwgInZhbHVlcyIsIDEwMzoxMTIpICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgbWVzLCBzZW50aW1lbnQpICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAgIm90cm9zIGNhbmRpZGF0b3MiKSU+JQ0KICAgZmlsdGVyKHNlbnRpbWVudCAhPSAibmVnYXRpdmUiICYgc2VudGltZW50ICE9InBvc2l0aXZlIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQpnZ3Bsb3QoKSArDQphZXMoeCA9IG1lcywgeSA9UHJvcG9yY2lvbiwgY29sb3IgPSBzZW50aW1lbnQpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHNlbnRpbWVudCkpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IC40KSwgDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIikpICsNCiAgdGVtYTIgKw0KICBmYWNldF93cmFwKH4gUG9saXRpY28pICsNCiAgbGFicyh0aXRsZSA9ICJDYW1iaW8gZGUgbG9zIHNlbnRpbWllbnRvcyBlbiBlbCB0aWVtcG8iLCANCiAgICAgICB4ID0gIk1lcyIsIHkgPSAiUG9ycG9yY2nDs24iLCBjb2xvciA9ICJTZW50aW1pZW50byIpIA0KDQoNCmdhdGhlcihUd2VldHNfREZfc2VudGltaWVudG8sICJzZW50aW1lbnQiLCAidmFsdWVzIiwgMTAzOjExMikgJT4lDQogIGdyb3VwX2J5KFBvbGl0aWNvLCBQYXJ0aWRvLCBtZXMsIHNlbnRpbWVudCkgJT4lDQogIGZpbHRlcihQYXJ0aWRvID09ICAiUGVyb25pc21vIiklPiUNCiAgZmlsdGVyKHNlbnRpbWVudCAhPSAibmVnYXRpdmUiICYgc2VudGltZW50ICE9InBvc2l0aXZlIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQpnZ3Bsb3QoKSArDQphZXMoeCA9IG1lcywgeSA9UHJvcG9yY2lvbiwgY29sb3IgPSBzZW50aW1lbnQpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHNlbnRpbWVudCkpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IC40KSwgDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIikpICsNCiAgdGVtYTIgKw0KICBmYWNldF93cmFwKH4gUG9saXRpY28pICsNCiAgbGFicyh0aXRsZSA9ICJDYW1iaW8gZGUgbG9zIHNlbnRpbWllbnRvcyBlbiBlbCB0aWVtcG8iLCANCiAgICAgICB4ID0gIk1lcyIsIHkgPSAiUG9ycG9yY2nDs24iLCBjb2xvciA9ICJTZW50aW1pZW50byIpIA0KDQpnYXRoZXIoVHdlZXRzX0RGX3NlbnRpbWllbnRvLCAic2VudGltZW50IiwgInZhbHVlcyIsIDEwMzoxMTIpICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgbWVzLCBzZW50aW1lbnQpICU+JQ0KICBmaWx0ZXIoUGFydGlkbyA9PSAgIlBSTyIpJT4lDQogIGZpbHRlcihzZW50aW1lbnQgIT0gIm5lZ2F0aXZlIiAmIHNlbnRpbWVudCAhPSJwb3NpdGl2ZSIpJT4lDQogICAgc3VtbWFyaXNlKFRvdGFsID0gc3VtKHZhbHVlcykpICU+JQ0KICAgICAgbXV0YXRlKFByb3BvcmNpb24gPSBUb3RhbCAvIHN1bShUb3RhbCkpICU+JQ0KZ2dwbG90KCkgKw0KYWVzKHggPSBtZXMsIHkgPVByb3BvcmNpb24sIGNvbG9yID0gc2VudGltZW50KSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzZW50aW1lbnQpKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgdmp1c3QgPSAuNCksIA0KICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzZXJpZiIpKSArDQogIHRlbWEyICsNCiAgZmFjZXRfd3JhcCh+IFBvbGl0aWNvKSArDQogIGxhYnModGl0bGUgPSAiQ2FtYmlvIGRlIGxvcyBzZW50aW1pZW50b3MgZW4gZWwgdGllbXBvIiwgDQogICAgICAgeCA9ICJNZXMiLCB5ID0gIlBvcnBvcmNpw7NuIiwgY29sb3IgPSAiU2VudGltaWVudG8iKSANCmBgYA0KDQoNCg0KDQo8Y2VudGVyPiA8c3BhbiBzdHlsZT0iY29sb3I6ICMyODJGNDQ7Ij4gPGgzPiAzMC0gQ29tcGFyaXNvbiBvZiBlbW90aW9ucyA8L2gzPiA8L3NwYW4+IDwvY2VudGVyPg0KDQoNClRoZSBpZGVhIG9mIOKAi+KAi2NvbXBhcmluZyBldmVyeW9uZSdzIGVtb3Rpb25zIG9uIGEgZ3JhcGggaGVscHMgZm9yIGEgZ2VuZXJhbCB2aXN1YWxpemF0aW9uIChlbGltaW5hdGluZyBwYXJ0eSBhY2NvdW50cyk6DQoNCi0gQWx0aG91Z2ggdGhlIG51bWJlciBvZiB0d2VldHMgZnJvbSAqKk1hY3JpKiogYXJlIGZldywgaXQgaXMgdGhlIG9uZSB0aGF0IHRyYW5zbWl0cyB0aGUgbW9zdCAqY29uZmlkZW5jZSouDQoNCi0gVGhvc2Ugd2hvIGhhdmUgZWxlY3RlZCBwb3dlciBhcmUgdGhlIG9uZXMgd2hvIG1vc3QgKnRydXN0KiBzZWVrIGluIHRoZWlyIHR3ZWV0cy4NCg0KLSBDYW5kaWRhdGVzIHdobyBoYXZlIGxvc3QgaGF2ZSBtaXhlZCBmZWVsaW5ncywgd2l0aCBhIGhpZ2ggbGV2ZWwgb2YgKmZlYXIqIGFuZCAqYW5ndWlzaCogaW4gdGhlaXIgd3JpdGluZy4NCg0KLSAqRmVlbGluZ3MgdGhhdCByZXByZXNlbnQgbGVzcyB0aGFuIDEwJSBvZiB0d2VldHMgYXJlIGRpc2NhcmRlZC4qDQoNCg0KDQoNCg0KYGBge3J9DQpnYXRoZXIoVHdlZXRzX0RGX3NlbnRpbWllbnRvLCAic2VudGltZW50IiwgInZhbHVlcyIsIDEwMzoxMTIpICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgc2VudGltZW50KSAlPiUNCiAgZmlsdGVyKHNlbnRpbWVudCAhPSAibmVnYXRpdmUiICYgc2VudGltZW50ICE9InBvc2l0aXZlIiAmIFBhcnRpZG8gIT0gImN1ZW50YSBwYXJ0aWRhcmlhIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQogICAgZ2dwbG90KCkgKw0KICBhZXMoUG9saXRpY28sIFByb3BvcmNpb24sIGNvbG9yID0gc2VudGltZW50LCBhbHBoYSA9IFByb3BvcmNpb24pICsNCiAgZ2VvbV9wb2ludChmaWxsID0gIndoaXRlIiwgc3Ryb2tlID0gMSwgc2hhcGUgPSAyMSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc2VudGltZW50KSwgdmp1c3QgPSAtLjksIGZhbWlseSA9ICJzZXJpZiIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0ICgpKSArDQogIHRlbWExICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgdGV4dCA9ICBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNlcmlmIikpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh0aXRsZSA9ICJTZW50aW1pZW50b3MgdG90YWxlcyBjb21wYXJhdGl2byIsDQogICAgICAgeCA9ICJQb2xpdGljbyIsDQogICAgICAgeSA9ICJQcm9wb3JjacOzbiBkZWwgc2VudGltaWVudG8iKQ0KDQpnYXRoZXIoVHdlZXRzX0RGX3NlbnRpbWllbnRvLCAic2VudGltZW50IiwgInZhbHVlcyIsIDEwMzoxMTIpICU+JQ0KICBncm91cF9ieShQb2xpdGljbywgUGFydGlkbywgc2VudGltZW50KSAlPiUNCiAgZmlsdGVyKHNlbnRpbWVudCAhPSAicG9zaXRpdmUiICYgc2VudGltZW50ICE9Im5lZ2F0aXZlIiAmIHNlbnRpbWVudCAhPSJqb3kiICYgc2VudGltZW50ICE9InN1cnByaXNlIiAmIFBhcnRpZG8gIT0gImN1ZW50YSBwYXJ0aWRhcmlhIiklPiUNCiAgICBzdW1tYXJpc2UoVG90YWwgPSBzdW0odmFsdWVzKSkgJT4lDQogICAgICBtdXRhdGUoUHJvcG9yY2lvbiA9IFRvdGFsIC8gc3VtKFRvdGFsKSkgJT4lDQogIGdncGxvdCgpICsNCiAgYWVzKHNlbnRpbWVudCwgUHJvcG9yY2lvbiwgY29sb3IgPSBzZW50aW1lbnQpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IFBvbGl0aWNvKSAsdmp1c3QgPSAtLjMsIHNpemUgPSAzKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAuMTUsIDAuNDcpKSArDQogICBsYWJzKHRpdGxlID0gIlNlbnRpbWllbnRvcyB0b3RhbGVzIGNvbXBhcmF0aXZvIiwNCiAgICAgICB4ID0gIlBvbGl0aWNvIiwNCiAgICAgICB5ID0gIlByb3BvcmNpw7NuIGRlbCBzZW50aW1pZW50byIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQoNCmBgYA0K