About this Notebook



Analytics Toolkit: Require Packages


# Here we are checking if the package is installed
if(!require("tidyverse")){
  install.packages("tidyverse", dependencies = TRUE)
  library("tidyverse")
}
if(!require("syuzhet")){
  install.packages("syuzhet", dependencies = TRUE)
  library("syuzhet")
}
package <U+393C><U+3E31>syuzhet<U+393C><U+3E32> was built under R version 3.4.4
if(!require("cleanNLP")){
  install.packages("cleanNLP", dependencies = TRUE)
  library("cleanNLP")
}
package <U+393C><U+3E31>cleanNLP<U+393C><U+3E32> was built under R version 3.4.4
if(!require("magrittr")){
  install.packages("magrittr", dependencies = TRUE)
  library("magrittr")
}
if(!require("wordcloud")){
  install.packages("wordcloud", dependencies = TRUE)
  library("wordcloud")
}

Data Preparation: Cleaning tweets using regular expressions


Reading and inspecting the dataset

tweets <- read_csv("data/sentiment_march_madness.csv")
# Change the tweets IDs from longe integer to characters
tweets$tweet_id <- as.character(tweets$tweet_id)
# Extract and delete the links variable to add it at the end
links <- tweets$links
tweets$links <- NULL
# Inspects the first 10 rows
head(tweets)

Now first we need to extract the text from the raw tweets and clean it using regular expressions

replace_reg <- 'https://t.co/[A-Za-z\\d]+|http://[A-Za-z\\d]+|(pic.twitter.com/[A-Za-z\\d]+)|&amp;|&lt;|&gt;|RT|(.*.)\\.com(.*.)\\S+\\s|[^[:alnum:]]|(http|https)\\S+\\s*|(#|@)\\S+\\s*|\\n|\\"'
tweets <- tweets %>% 
  mutate(text = str_replace_all(text, replace_reg, " ")) %>% 
  mutate(text = iconv(text, from = "ASCII", to = "UTF-8", sub = " "))
Error in mutate_impl(.data, dots) : 
  Evaluation error: embedded nul in string: 'How to draw  kawaii  step by step leassons on Google Play   animejapan  KAWAIIcollection  FinalFour  SisterJean  ORLvUTA  c\003\tc\003)c\0024c\0033c\003\034c\003<c\003+h6\005  nitiasa  precure  d;.i\035"c\003)c\002$c\003\0c\003<c\003\023c\003+c\003\t  c\0025c\0033c\003\ac\003<c\003"c\003<c\003\vc\0033c\0020  CBX SomeoneLikeYou  l\v m\031\024l\025< l\n$k,4l\0024l\035\004 l6\025m\025\030m\0254 l5\034j0\025l0=k/< '.

Here we are going to use the Saif Mohammad’s NRC Emotion lexicon toextract the sentiment of the tweet. The NRC emotion lexicon is a list of words and their associations with eight emotions (anger, fear, anticipation, trust, surprise, sadness, joy, and disgust) and two sentiments (negative and positive).

nrc_data <- get_nrc_sentiment(tweets$text)
nrc_data <- as_tibble(nrc_data)

head(nrc_data)

Here we are going to merge the NRC Emotion results with the original data to create a complete dataset.

tweets <- bind_cols(tweets, nrc_data)

To have another metrics for semtiment we are going to use another lexicon developed by Professor Minqing Hu and Professor Bing Liu, from University of Illinois at Chicago.

tweets$sentiment_bing <- get_sentiment(char_v = tweets$text, method="bing", language = "english")

Sentiment Analysis: Natural Language Processing


First lets read the dataset and inspect the first 10 rows

tweets <- read_csv("data/sentiment_march_madness.csv")
tweets$tweet_id <- as.character(tweets$tweet_id)
head(tweets[12:21])

For sentiment analysis we are going to use the cleanNLP package that uses Stanford CoreNLP – Natural language software int he backend. First we need to initialize the CoreNLP engine and create an annotation object using the text column, tweet_id and the other columns are given as metadata

cnlp_init_udpipe()

doc <- cnlp_annotate(input = tweets$text, as_strings = TRUE, doc_ids = tweets$tweet_id, meta = tweets[-c(1,2)])

Distribution of tweet/sentence length, max number of works in a tweet 280

tokens <- cnlp_get_token(doc) %>%
  group_by(id, sid) %>%
  summarize(sent_len = n())

quantile(tokens$sent_len, seq(0,1,0.1))

Here we can see the change of sentiment in the tweets

qplot(x = 1:length(tweets$sentiment_bing), 
      y = tweets$sentiment_bing, 
      geom = "line", 
      xlab = "Narrative Time", 
      ylab = "Emotional Valence", 
      main = "Tweets Sentiment Trajectory")

Here we can find the most used entities from the tweets entity table. The document corpus yields an alternative way to see the underlying topics.

tweets_entities <- cnlp_get_token(doc) %>%
  filter(upos == "NOUN") %>%
  group_by(lemma) %>%
  summarize(count = n()) %>%
  top_n(n = 80, count) %>%
  arrange(desc(count)) %>%
  use_series(lemma)

data_frame(tweets_entities)

Here we creating a high-level summary of the tweets text by extracting all direct object object-dependencies.

tweets_summary <- cnlp_get_dependency(doc, get_token = TRUE) %>%
  left_join(cnlp_get_document(doc)) %>%
  select(id = id, start = word, word = lemma_target) %>%
  left_join(word_frequency) %>%
  filter(frequency < 0.0001) %>%
  select(id, start, word) %$%
  sprintf("%s => %s", start, word)

data_frame(tweets_summary)

Look at the tweets with negative sentiment


angry_tweets <- which(tweets$anger > 0)
data_frame(tweet = tweets$text[angry_tweets][1:2])

Look a tweets with positive sentiment

joy_tweets <- which(tweets$joy > 0)
data_frame(tweet = tweets$text[joy_tweets][5:7])

Lets explore the emotions in the tweets more in-depth. Here we are going to extract the variables regarding emotions and create a subset.

value <- as.double(colSums(prop.table(tweets[, 11:18])))
emotion <- names(tweets)[11:18]
emotion <- factor(emotion, levels = names(tweets)[11:18][order(value, decreasing = FALSE)])
emotions <- data_frame(emotion, percent = value * 100)

head(emotions)

Now we can create a plot of the emotions in the march madness tweets

ggplot(data = emotions, aes(x = emotion, y = percent)) + 
  geom_bar(stat = "identity", aes(fill = emotion)) + 
  scale_fill_brewer(palette="RdYlGn") + 
  coord_flip() +
  xlab("Emotion") +
  ylab("Percentage")

Reporting: A Wordcloud from March Madness Tweets


Wordclouds are always a fun and engaging way to display data. Here we are going to set some stop words that we dont want in the plot.

remove_words <- c( "twitter", "chicago", "loyola", "ramblers", "loyolaramblers","school", "gonna",
                   "university", "luc", "loyolachicago" , "ramblersmbb", "ncaa","ve","basketball" ,
                   "umichbball", "marchmadness2018", "marchmadness", "final", "marchmaddness",
                   "goblue", "finalfour", "sisterjean", "ncaatournament", "ncaatournament2018",
                   "didn","city", "hey", "day", "college", "games", "tourney", "march", "game")

my_stop_words <- bind_rows(data_frame(word = remove_words, lexicon = c("SMART")), stop_words)

Now lets create a dataframe of words and filter using predefined stop words

twt_text <- tibble(text = tweets$text) %>% 
  unnest_tokens(word, text) %>%
  filter(!word %in% my_stop_words$word, str_detect(word, "[a-z]"))

Set a threshold for the min/max frequency of words and scale of the wordcloud

min_freq = 80
max_words = 100
fig_scale = c(3 , 0.5)

The last step is to create the wordcloud by counting the frequency of the words

twt_text %>%
  anti_join(my_stop_words) %>%
  count(word) %>%
  with(wordcloud(word, n, 
                 scale = fig_scale,
                 min.freq = min_freq,
                 max.words = max_words))

Task 1: Data Exploration - Tableau


1A) Generally describe the data (summary)

summary(tweets)
   tweet_id             text             username           fullname        
 Length:20187       Length:20187       Length:20187       Length:20187      
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
      date               datetime                      verified      
 Min.   :2011-02-09   Min.   :2011-02-09 19:42:51   Min.   :0.00000  
 1st Qu.:2018-03-24   1st Qu.:2018-03-24 11:03:02   1st Qu.:0.00000  
 Median :2018-03-25   Median :2018-03-25 00:22:38   Median :0.00000  
 Mean   :2018-03-18   Mean   :2018-03-18 10:40:33   Mean   :0.06192  
 3rd Qu.:2018-03-25   3rd Qu.:2018-03-25 03:08:07   3rd Qu.:0.00000  
 Max.   :2018-04-06   Max.   :2018-04-06 21:24:17   Max.   :1.00000  
     reply             retweets           favorite           anger       
 Min.   :  0.0000   Min.   :   0.000   Min.   :    0.0   Min.   :0.0000  
 1st Qu.:  0.0000   1st Qu.:   0.000   1st Qu.:    0.0   1st Qu.:0.0000  
 Median :  0.0000   Median :   0.000   Median :    1.0   Median :0.0000  
 Mean   :  0.3467   Mean   :   3.146   Mean   :   15.8   Mean   :0.1342  
 3rd Qu.:  0.0000   3rd Qu.:   0.000   3rd Qu.:    3.0   3rd Qu.:0.0000  
 Max.   :591.0000   Max.   :5143.000   Max.   :32180.0   Max.   :4.0000  
  anticipation       disgust             fear             joy       
 Min.   :0.0000   Min.   :0.00000   Min.   :0.0000   Min.   :0.000  
 1st Qu.:0.0000   1st Qu.:0.00000   1st Qu.:0.0000   1st Qu.:0.000  
 Median :0.0000   Median :0.00000   Median :0.0000   Median :0.000  
 Mean   :0.4359   Mean   :0.07143   Mean   :0.1612   Mean   :0.421  
 3rd Qu.:1.0000   3rd Qu.:0.00000   3rd Qu.:0.0000   3rd Qu.:1.000  
 Max.   :7.0000   Max.   :3.00000   Max.   :6.0000   Max.   :8.000  
    sadness          surprise          trust           negative     
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000  
 Median :0.0000   Median :0.0000   Median :0.0000   Median :0.0000  
 Mean   :0.1122   Mean   :0.1798   Mean   :0.4806   Mean   :0.2395  
 3rd Qu.:0.0000   3rd Qu.:0.0000   3rd Qu.:1.0000   3rd Qu.:0.0000  
 Max.   :5.0000   Max.   :4.0000   Max.   :7.0000   Max.   :6.0000  
    positive      sentiment_bing   
 Min.   :0.0000   Min.   :-5.0000  
 1st Qu.:0.0000   1st Qu.: 0.0000  
 Median :0.0000   Median : 0.0000  
 Mean   :0.6676   Mean   : 0.5141  
 3rd Qu.:1.0000   3rd Qu.: 1.0000  
 Max.   :9.0000   Max.   :11.0000  

This summary shows the different types of sentiments in the tweets such as anger, anticipation, disgust, fear, joy, sadness, surprise, and trust. It shows how many verified people tweeted about Loyola - which was only one. It shows how many retweets, favorites, and replies there were for the tweets. It also shows how many could seem positive or negative.

1B) Use tableau to create at least 5 plots

knitr::include_graphics("imgs/tweets1.png")

This graph shows which tweets were retweeted, favorited, or replied on.

knitr::include_graphics("imgs/tweets2.png")

This plot shows which accounts had the most retweets. @RamblersMBB had the most followed by @marchmadness. The rest of the accounts had way less retweets than these two accounts.

knitr::include_graphics("imgs/tweets3.png")

This shows how many tweets there were for each measure. There were more favorites than were retweets. More tweets were aksi more positive than negative.

knitr::include_graphics("imgs/tweets4.png")

This graph shows that most of the tweets were in 2018 but some date back to 2011.

knitr::include_graphics("imgs/tweets5.png")

This shows that more tweets were positive rather than negative.

1C) Explain each plot make a relation to date of the tweets/time

## done under each graph.

Task 3: Data Analysis


2A)Based on your plots and data description make give a general narrative for the image of loyola in twitter

Loyola received more of a positive image on twitter than a negative one. We can see that the account for the Men’s basketball team had the biggest impact on twitter users as it had the most retweets out of any account looked at. People were happy that we were winning and were anxious for each game. This all points toward a positive image for Loyola.

2B) Use descriptive statistics to backup your arguments

summary(tweets)
   tweet_id             text             username           fullname        
 Length:20187       Length:20187       Length:20187       Length:20187      
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
      date               datetime                      verified      
 Min.   :2011-02-09   Min.   :2011-02-09 19:42:51   Min.   :0.00000  
 1st Qu.:2018-03-24   1st Qu.:2018-03-24 11:03:02   1st Qu.:0.00000  
 Median :2018-03-25   Median :2018-03-25 00:22:38   Median :0.00000  
 Mean   :2018-03-18   Mean   :2018-03-18 10:40:33   Mean   :0.06192  
 3rd Qu.:2018-03-25   3rd Qu.:2018-03-25 03:08:07   3rd Qu.:0.00000  
 Max.   :2018-04-06   Max.   :2018-04-06 21:24:17   Max.   :1.00000  
     reply             retweets           favorite           anger       
 Min.   :  0.0000   Min.   :   0.000   Min.   :    0.0   Min.   :0.0000  
 1st Qu.:  0.0000   1st Qu.:   0.000   1st Qu.:    0.0   1st Qu.:0.0000  
 Median :  0.0000   Median :   0.000   Median :    1.0   Median :0.0000  
 Mean   :  0.3467   Mean   :   3.146   Mean   :   15.8   Mean   :0.1342  
 3rd Qu.:  0.0000   3rd Qu.:   0.000   3rd Qu.:    3.0   3rd Qu.:0.0000  
 Max.   :591.0000   Max.   :5143.000   Max.   :32180.0   Max.   :4.0000  
  anticipation       disgust             fear             joy       
 Min.   :0.0000   Min.   :0.00000   Min.   :0.0000   Min.   :0.000  
 1st Qu.:0.0000   1st Qu.:0.00000   1st Qu.:0.0000   1st Qu.:0.000  
 Median :0.0000   Median :0.00000   Median :0.0000   Median :0.000  
 Mean   :0.4359   Mean   :0.07143   Mean   :0.1612   Mean   :0.421  
 3rd Qu.:1.0000   3rd Qu.:0.00000   3rd Qu.:0.0000   3rd Qu.:1.000  
 Max.   :7.0000   Max.   :3.00000   Max.   :6.0000   Max.   :8.000  
    sadness          surprise          trust           negative     
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000  
 Median :0.0000   Median :0.0000   Median :0.0000   Median :0.0000  
 Mean   :0.1122   Mean   :0.1798   Mean   :0.4806   Mean   :0.2395  
 3rd Qu.:0.0000   3rd Qu.:0.0000   3rd Qu.:1.0000   3rd Qu.:0.0000  
 Max.   :5.0000   Max.   :4.0000   Max.   :7.0000   Max.   :6.0000  
    positive      sentiment_bing   
 Min.   :0.0000   Min.   :-5.0000  
 1st Qu.:0.0000   1st Qu.: 0.0000  
 Median :0.0000   Median : 0.0000  
 Mean   :0.6676   Mean   : 0.5141  
 3rd Qu.:1.0000   3rd Qu.: 1.0000  
 Max.   :9.0000   Max.   :11.0000  

This summary shows that the max was 9 for positive which was higher than negative which was 6. It also showed there was more for joy than anger. This shows that the school had more of a positive image than a negative one at this time.

2C)Any recommendations to Loyola’s marketing team

## Loyola’s marketing team can use their Cinderella Story to paint Loyola in a positive image. There was constant talk about this school doing everything right. They can use that narrative to bring in more students to make this school prosperous.

Task 3: Watson Analysis


3A)Use watson analytics to explore the data

3B)Give at least 3 plots or discoveries using watson. Explain your findings.

knitr::include_graphics("imgs/tweets6.png")

This shows what drove trust for the team. Positive, joy, and anticipation fostered trust in the team. This means they were trusting the team to win which gave a positive response of happiness.

knitr::include_graphics("imgs/tweets7.png")

Most of the tweets about joy were towards the end of the month around the time of the elite 8 which lead to the final four. This shows the positive image loyola had at the time.

knitr::include_graphics("imgs/tweets8.png")

This shows there were tweets about trust for years, but most were about the team in 2018. It seems like most were before the tournament started probably talking about what may happen.

LS0tDQp0aXRsZTogIk1hcmNoIE1hZG5lc3MgQW5hbHlzaXMiDQphdXRob3I6IA0KLSAiUXVpbmxhbiBTY2hvb2wgb2YgQnVzaW5lc3MgLSBMb3lvbGEgVW5pdmVyc2l0eSBDaGljYWdvIg0KLSAiQXNobGV5IEtyZW56Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQNCmRhdGU6ICJBcHJpbCAyNCwgMjAxOCINCnN1YnRpdGxlOiAiQ01FIEdyb3VwIEZvdW5kYXRpb24gQnVzaW5lc3MgQW5hbHl0aWNzIExhYiINCi0tLQ0KDQoNCg0KLS0tLS0tLS0tLS0tLS0NCg0KIyMgQWJvdXQgdGhpcyBOb3RlYm9vaw0KDQotLS0tLS0tLS0tLS0tLQ0KDQoqIE9uIHRoaXMgbm90ZWJvb2sgd2UgYXJlIGdvaW5nIHRvIGFuYWx5c2lzIHR3ZWV0cyBmcm9tIG1hcmNoIG1hZG5lc3MgMjAxOA0KDQoqIFVzZSByZWd1bGFyIGV4cHJlc3Npb24gdG8gY2xlYW4gdGhlIHR3ZWV0cyB0ZXh0DQoNCiogRmFtaWxpYXJpemUgd2l0aCBzb21lIG5hdHVyYWwgbGFuZ3VhZ2UgcHJvY2Vzc2luZyB0b29scw0KDQoNCg0KLS0tLS0tLS0tLS0tLS0NCg0KIyMgQW5hbHl0aWNzIFRvb2xraXQ6IFJlcXVpcmUgUGFja2FnZXMNCg0KLS0tLS0tLS0tLS0tLS0NCg0KDQoNCiogdGlkeXZlcnNlOiBodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLw0KKiBzeXV6aGV0OiBodHRwczovL2dpdGh1Yi5jb20vbWpvY2tlcnMvc3l1emhldA0KKiBjbGVhbk5MUDogaHR0cHM6Ly9naXRodWIuY29tL3N0YXRzbWF0aHMvY2xlYW5OTFANCiogd29yZGNsb3VkOiBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvd29yZGNsb3VkL3dvcmRjbG91ZC5wZGYNCg0KYGBge3IgLCBtZXNzYWdlPUZBTFNFfQ0KDQojIEhlcmUgd2UgYXJlIGNoZWNraW5nIGlmIHRoZSBwYWNrYWdlIGlzIGluc3RhbGxlZA0KaWYoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKXsNCiAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgbGlicmFyeSgidGlkeXZlcnNlIikNCn0NCg0KaWYoIXJlcXVpcmUoInN5dXpoZXQiKSl7DQogIGluc3RhbGwucGFja2FnZXMoInN5dXpoZXQiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICBsaWJyYXJ5KCJzeXV6aGV0IikNCn0NCg0KaWYoIXJlcXVpcmUoImNsZWFuTkxQIikpew0KICBpbnN0YWxsLnBhY2thZ2VzKCJjbGVhbk5MUCIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogIGxpYnJhcnkoImNsZWFuTkxQIikNCn0NCg0KaWYoIXJlcXVpcmUoIm1hZ3JpdHRyIikpew0KICBpbnN0YWxsLnBhY2thZ2VzKCJtYWdyaXR0ciIsIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogIGxpYnJhcnkoIm1hZ3JpdHRyIikNCn0NCg0KaWYoIXJlcXVpcmUoIndvcmRjbG91ZCIpKXsNCiAgaW5zdGFsbC5wYWNrYWdlcygid29yZGNsb3VkIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgbGlicmFyeSgid29yZGNsb3VkIikNCn0NCg0KYGBgDQoNCg0KDQotLS0tLS0tLS0tLS0tLQ0KDQojIyBEYXRhIFByZXBhcmF0aW9uOiBDbGVhbmluZyB0d2VldHMgdXNpbmcgcmVndWxhciBleHByZXNzaW9ucw0KDQotLS0tLS0tLS0tLS0tLQ0KDQoNCg0KIyMjIyBSZWFkaW5nIGFuZCBpbnNwZWN0aW5nIHRoZSBkYXRhc2V0DQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCnR3ZWV0cyA8LSByZWFkX2NzdigiZGF0YS9zZW50aW1lbnRfbWFyY2hfbWFkbmVzcy5jc3YiKQ0KDQojIENoYW5nZSB0aGUgdHdlZXRzIElEcyBmcm9tIGxvbmdlIGludGVnZXIgdG8gY2hhcmFjdGVycw0KdHdlZXRzJHR3ZWV0X2lkIDwtIGFzLmNoYXJhY3Rlcih0d2VldHMkdHdlZXRfaWQpDQoNCiMgRXh0cmFjdCBhbmQgZGVsZXRlIHRoZSBsaW5rcyB2YXJpYWJsZSB0byBhZGQgaXQgYXQgdGhlIGVuZA0KbGlua3MgPC0gdHdlZXRzJGxpbmtzDQp0d2VldHMkbGlua3MgPC0gTlVMTA0KDQojIEluc3BlY3RzIHRoZSBmaXJzdCAxMCByb3dzDQpoZWFkKHR3ZWV0cykNCmBgYA0KDQoNCg0KIyMjIyBOb3cgZmlyc3Qgd2UgbmVlZCB0byBleHRyYWN0IHRoZSB0ZXh0IGZyb20gdGhlIHJhdyB0d2VldHMgYW5kIGNsZWFuIGl0IHVzaW5nIHJlZ3VsYXIgZXhwcmVzc2lvbnMNCmBgYHtyfQ0KcmVwbGFjZV9yZWcgPC0gJ2h0dHBzOi8vdC5jby9bQS1aYS16XFxkXSt8aHR0cDovL1tBLVphLXpcXGRdK3wocGljLnR3aXR0ZXIuY29tL1tBLVphLXpcXGRdKyl8JmFtcDt8Jmx0O3wmZ3Q7fFJUfCguKi4pXFwuY29tKC4qLilcXFMrXFxzfFteWzphbG51bTpdXXwoaHR0cHxodHRwcylcXFMrXFxzKnwoI3xAKVxcUytcXHMqfFxcbnxcXCInDQoNCnR3ZWV0cyA8LSB0d2VldHMgJT4lIA0KICBtdXRhdGUodGV4dCA9IHN0cl9yZXBsYWNlX2FsbCh0ZXh0LCByZXBsYWNlX3JlZywgIiAiKSkgJT4lIA0KICBtdXRhdGUodGV4dCA9IGljb252KHRleHQsIGZyb20gPSAiQVNDSUkiLCB0byA9ICJVVEYtOCIsIHN1YiA9ICIgIikpDQoNCmhlYWQodHdlZXRzWyd0ZXh0J10pDQpgYGANCg0KDQoNCiMjIyMgSGVyZSB3ZSBhcmUgZ29pbmcgdG8gdXNlIHRoZSBTYWlmIE1vaGFtbWFk4oCZcyBOUkMgRW1vdGlvbiBsZXhpY29uIHRvZXh0cmFjdCB0aGUgc2VudGltZW50IG9mIHRoZSB0d2VldC4gVGhlIE5SQyBlbW90aW9uIGxleGljb24gaXMgYSBsaXN0IG9mIHdvcmRzIGFuZCB0aGVpciBhc3NvY2lhdGlvbnMgd2l0aCBlaWdodCBlbW90aW9ucyAoYW5nZXIsIGZlYXIsIGFudGljaXBhdGlvbiwgdHJ1c3QsIHN1cnByaXNlLCBzYWRuZXNzLCBqb3ksIGFuZCBkaXNndXN0KSBhbmQgdHdvIHNlbnRpbWVudHMgKG5lZ2F0aXZlIGFuZCBwb3NpdGl2ZSkuDQoNCiogU291cmNlOiBodHRwOi8vc2FpZm1vaGFtbWFkLmNvbS9XZWJQYWdlcy9OUkMtRW1vdGlvbi1MZXhpY29uLmh0bQ0KDQpgYGB7cn0NCm5yY19kYXRhIDwtIGdldF9ucmNfc2VudGltZW50KHR3ZWV0cyR0ZXh0KQ0KbnJjX2RhdGEgPC0gYXNfdGliYmxlKG5yY19kYXRhKQ0KDQpoZWFkKG5yY19kYXRhKQ0KYGBgDQoNCg0KDQojIyMjIEhlcmUgd2UgYXJlIGdvaW5nIHRvIG1lcmdlIHRoZSBOUkMgRW1vdGlvbiByZXN1bHRzIHdpdGggdGhlIG9yaWdpbmFsIGRhdGEgdG8gY3JlYXRlIGEgY29tcGxldGUgZGF0YXNldC4NCmBgYHtyfQ0KdHdlZXRzIDwtIGJpbmRfY29scyh0d2VldHMsIG5yY19kYXRhKQ0KDQpgYGANCg0KDQoNCiMjIyMgVG8gaGF2ZSBhbm90aGVyIG1ldHJpY3MgZm9yIHNlbXRpbWVudCB3ZSBhcmUgZ29pbmcgdG8gdXNlIGFub3RoZXIgbGV4aWNvbiBkZXZlbG9wZWQgYnkgUHJvZmVzc29yIE1pbnFpbmcgSHUgYW5kIFByb2Zlc3NvciBCaW5nIExpdSwgZnJvbSBVbml2ZXJzaXR5IG9mIElsbGlub2lzIGF0IENoaWNhZ28uDQoqIFNvdXJjZTogaHR0cDovL3d3dy5jcy51aWMuZWR1L35saXViL0ZCUy9zZW50aW1lbnQtYW5hbHlzaXMuaHRtbA0KDQpgYGB7cn0NCnR3ZWV0cyRzZW50aW1lbnRfYmluZyA8LSBnZXRfc2VudGltZW50KGNoYXJfdiA9IHR3ZWV0cyR0ZXh0LCBtZXRob2Q9ImJpbmciLCBsYW5ndWFnZSA9ICJlbmdsaXNoIikNCg0KYGBgDQoNCg0KDQojIyMjIEZpbmFsbHkgYWRkIHRoZSBsaW5rcyB2YXJpYWJsZSBhbmQgc2F2ZSB0aGUgbmV3IGNvbXBsZXRlIGRhdGFzZXQgDQpgYGB7cn0NCnR3ZWV0cyRsaW5rcyA8LSBsaW5rcw0KDQp3cml0ZV9jc3YodHdlZXRzLCAiZGF0YS9tYXJjaF9tYWRuZXNzX3NlbnQuY3N2IikNCg0KaGVhZCh0d2VldHNbMzoxMF0pDQpgYGANCg0KDQoNCi0tLS0tLS0tLS0tLS0tDQoNCiMjIFNlbnRpbWVudCBBbmFseXNpczogTmF0dXJhbCBMYW5ndWFnZSBQcm9jZXNzaW5nDQoNCi0tLS0tLS0tLS0tLS0tDQoNCg0KDQojIyMjIEZpcnN0IGxldHMgcmVhZCB0aGUgZGF0YXNldCBhbmQgaW5zcGVjdCB0aGUgZmlyc3QgMTAgcm93cw0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQp0d2VldHMgPC0gcmVhZF9jc3YoImRhdGEvc2VudGltZW50X21hcmNoX21hZG5lc3MuY3N2IikNCnR3ZWV0cyR0d2VldF9pZCA8LSBhcy5jaGFyYWN0ZXIodHdlZXRzJHR3ZWV0X2lkKQ0KaGVhZCh0d2VldHNbMTI6MjFdKQ0KYGBgDQoNCg0KDQojIyMjIEZvciBzZW50aW1lbnQgYW5hbHlzaXMgd2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgY2xlYW5OTFAgcGFja2FnZSB0aGF0IHVzZXMgU3RhbmZvcmQgQ29yZU5MUCDigJMgTmF0dXJhbCBsYW5ndWFnZSBzb2Z0d2FyZSBpbnQgaGUgYmFja2VuZC4gRmlyc3Qgd2UgbmVlZCB0byBpbml0aWFsaXplIHRoZSBDb3JlTkxQIGVuZ2luZSBhbmQgY3JlYXRlIGFuIGFubm90YXRpb24gb2JqZWN0IHVzaW5nIHRoZSB0ZXh0IGNvbHVtbiwgdHdlZXRfaWQgYW5kIHRoZSBvdGhlciBjb2x1bW5zIGFyZSBnaXZlbiBhcyBtZXRhZGF0YQ0KYGBge3J9DQpjbmxwX2luaXRfdWRwaXBlKCkNCg0KZG9jIDwtIGNubHBfYW5ub3RhdGUoaW5wdXQgPSB0d2VldHMkdGV4dCwgYXNfc3RyaW5ncyA9IFRSVUUsIGRvY19pZHMgPSB0d2VldHMkdHdlZXRfaWQsIG1ldGEgPSB0d2VldHNbLWMoMSwyKV0pDQoNCmBgYA0KDQoNCg0KIyMjIyBEaXN0cmlidXRpb24gb2YgdHdlZXQvc2VudGVuY2UgbGVuZ3RoLCBtYXggbnVtYmVyIG9mIHdvcmtzIGluIGEgdHdlZXQgMjgwDQpgYGB7cn0NCnRva2VucyA8LSBjbmxwX2dldF90b2tlbihkb2MpICU+JQ0KICBncm91cF9ieShpZCwgc2lkKSAlPiUNCiAgc3VtbWFyaXplKHNlbnRfbGVuID0gbigpKQ0KDQpxdWFudGlsZSh0b2tlbnMkc2VudF9sZW4sIHNlcSgwLDEsMC4xKSkNCg0KYGBgDQoNCg0KDQojIyMjIEhlcmUgd2UgY2FuIHNlZSB0aGUgY2hhbmdlIG9mIHNlbnRpbWVudCBpbiB0aGUgdHdlZXRzIA0KYGBge3J9DQpxcGxvdCh4ID0gMTpsZW5ndGgodHdlZXRzJHNlbnRpbWVudF9iaW5nKSwgDQogICAgICB5ID0gdHdlZXRzJHNlbnRpbWVudF9iaW5nLCANCiAgICAgIGdlb20gPSAibGluZSIsIA0KICAgICAgeGxhYiA9ICJOYXJyYXRpdmUgVGltZSIsIA0KICAgICAgeWxhYiA9ICJFbW90aW9uYWwgVmFsZW5jZSIsIA0KICAgICAgbWFpbiA9ICJUd2VldHMgU2VudGltZW50IFRyYWplY3RvcnkiKQ0KDQpgYGANCg0KDQoNCiMjIyMgSGVyZSB3ZSBjYW4gZmluZCB0aGUgbW9zdCB1c2VkIGVudGl0aWVzIGZyb20gdGhlIHR3ZWV0cyBlbnRpdHkgdGFibGUuIFRoZSBkb2N1bWVudCBjb3JwdXMgeWllbGRzIGFuIGFsdGVybmF0aXZlIHdheSB0byBzZWUgdGhlIHVuZGVybHlpbmcgdG9waWNzLg0KYGBge3J9DQp0d2VldHNfZW50aXRpZXMgPC0gY25scF9nZXRfdG9rZW4oZG9jKSAlPiUNCiAgZmlsdGVyKHVwb3MgPT0gIk5PVU4iKSAlPiUNCiAgZ3JvdXBfYnkobGVtbWEpICU+JQ0KICBzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JQ0KICB0b3BfbihuID0gODAsIGNvdW50KSAlPiUNCiAgYXJyYW5nZShkZXNjKGNvdW50KSkgJT4lDQogIHVzZV9zZXJpZXMobGVtbWEpDQoNCmRhdGFfZnJhbWUodHdlZXRzX2VudGl0aWVzKQ0KDQpgYGANCg0KDQoNCiMjIyMgSGVyZSB3ZSBjcmVhdGluZyBhIGhpZ2gtbGV2ZWwgc3VtbWFyeSBvZiB0aGUgdHdlZXRzIHRleHQgYnkgZXh0cmFjdGluZyBhbGwgZGlyZWN0IG9iamVjdCBvYmplY3QtZGVwZW5kZW5jaWVzLg0KYGBge3J9DQp0d2VldHNfc3VtbWFyeSA8LSBjbmxwX2dldF9kZXBlbmRlbmN5KGRvYywgZ2V0X3Rva2VuID0gVFJVRSkgJT4lDQogIGxlZnRfam9pbihjbmxwX2dldF9kb2N1bWVudChkb2MpKSAlPiUNCiAgc2VsZWN0KGlkID0gaWQsIHN0YXJ0ID0gd29yZCwgd29yZCA9IGxlbW1hX3RhcmdldCkgJT4lDQogIGxlZnRfam9pbih3b3JkX2ZyZXF1ZW5jeSkgJT4lDQogIGZpbHRlcihmcmVxdWVuY3kgPCAwLjAwMDEpICU+JQ0KICBzZWxlY3QoaWQsIHN0YXJ0LCB3b3JkKSAlJCUNCiAgc3ByaW50ZigiJXMgPT4gJXMiLCBzdGFydCwgd29yZCkNCg0KZGF0YV9mcmFtZSh0d2VldHNfc3VtbWFyeSkNCg0KYGBgDQoNCg0KDQojIyMjIExvb2sgYXQgdGhlIHR3ZWV0cyB3aXRoIG5lZ2F0aXZlIHNlbnRpbWVudCANCmBgYHtyfQ0KDQphbmdyeV90d2VldHMgPC0gd2hpY2godHdlZXRzJGFuZ2VyID4gMCkNCmRhdGFfZnJhbWUodHdlZXQgPSB0d2VldHMkdGV4dFthbmdyeV90d2VldHNdWzE6Ml0pDQoNCmBgYA0KDQoNCg0KIyMjIyBMb29rIGEgdHdlZXRzIHdpdGggcG9zaXRpdmUgc2VudGltZW50DQpgYGB7cn0NCmpveV90d2VldHMgPC0gd2hpY2godHdlZXRzJGpveSA+IDApDQpkYXRhX2ZyYW1lKHR3ZWV0ID0gdHdlZXRzJHRleHRbam95X3R3ZWV0c11bNTo3XSkNCg0KYGBgDQoNCg0KDQojIyMjIExldHMgZXhwbG9yZSB0aGUgZW1vdGlvbnMgaW4gdGhlIHR3ZWV0cyBtb3JlIGluLWRlcHRoLiBIZXJlIHdlIGFyZSBnb2luZyB0byBleHRyYWN0IHRoZSB2YXJpYWJsZXMgcmVnYXJkaW5nIGVtb3Rpb25zIGFuZCBjcmVhdGUgYSBzdWJzZXQuDQpgYGB7cn0NCnZhbHVlIDwtIGFzLmRvdWJsZShjb2xTdW1zKHByb3AudGFibGUodHdlZXRzWywgMTE6MThdKSkpDQplbW90aW9uIDwtIG5hbWVzKHR3ZWV0cylbMTE6MThdDQplbW90aW9uIDwtIGZhY3RvcihlbW90aW9uLCBsZXZlbHMgPSBuYW1lcyh0d2VldHMpWzExOjE4XVtvcmRlcih2YWx1ZSwgZGVjcmVhc2luZyA9IEZBTFNFKV0pDQplbW90aW9ucyA8LSBkYXRhX2ZyYW1lKGVtb3Rpb24sIHBlcmNlbnQgPSB2YWx1ZSAqIDEwMCkNCg0KaGVhZChlbW90aW9ucykNCmBgYA0KDQoNCg0KIyMjIyBOb3cgd2UgY2FuIGNyZWF0ZSBhIHBsb3Qgb2YgdGhlIGVtb3Rpb25zIGluIHRoZSBtYXJjaCBtYWRuZXNzIHR3ZWV0cw0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGVtb3Rpb25zLCBhZXMoeCA9IGVtb3Rpb24sIHkgPSBwZXJjZW50KSkgKyANCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGFlcyhmaWxsID0gZW1vdGlvbikpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlJkWWxHbiIpICsgDQogIGNvb3JkX2ZsaXAoKSArDQogIHhsYWIoIkVtb3Rpb24iKSArDQogIHlsYWIoIlBlcmNlbnRhZ2UiKQ0KDQpgYGANCg0KDQoNCi0tLS0tLS0tLS0tLS0tDQoNCiMjIFJlcG9ydGluZzogQSBXb3JkY2xvdWQgZnJvbSBNYXJjaCBNYWRuZXNzIFR3ZWV0cw0KDQotLS0tLS0tLS0tLS0tLQ0KDQoNCg0KIyMjIyBXb3JkY2xvdWRzIGFyZSBhbHdheXMgYSBmdW4gYW5kIGVuZ2FnaW5nIHdheSB0byBkaXNwbGF5IGRhdGEuIEhlcmUgd2UgYXJlIGdvaW5nIHRvIHNldCBzb21lIHN0b3Agd29yZHMgdGhhdCB3ZSBkb250IHdhbnQgaW4gdGhlIHBsb3QuDQpgYGB7cn0NCnJlbW92ZV93b3JkcyA8LSBjKCAidHdpdHRlciIsICJjaGljYWdvIiwgImxveW9sYSIsICJyYW1ibGVycyIsICJsb3lvbGFyYW1ibGVycyIsInNjaG9vbCIsICJnb25uYSIsDQogICAgICAgICAgICAgICAgICAgInVuaXZlcnNpdHkiLCAibHVjIiwgImxveW9sYWNoaWNhZ28iICwgInJhbWJsZXJzbWJiIiwgIm5jYWEiLCJ2ZSIsImJhc2tldGJhbGwiICwNCiAgICAgICAgICAgICAgICAgICAidW1pY2hiYmFsbCIsICJtYXJjaG1hZG5lc3MyMDE4IiwgIm1hcmNobWFkbmVzcyIsICJmaW5hbCIsICJtYXJjaG1hZGRuZXNzIiwNCiAgICAgICAgICAgICAgICAgICAiZ29ibHVlIiwgImZpbmFsZm91ciIsICJzaXN0ZXJqZWFuIiwgIm5jYWF0b3VybmFtZW50IiwgIm5jYWF0b3VybmFtZW50MjAxOCIsDQogICAgICAgICAgICAgICAgICAgImRpZG4iLCJjaXR5IiwgImhleSIsICJkYXkiLCAiY29sbGVnZSIsICJnYW1lcyIsICJ0b3VybmV5IiwgIm1hcmNoIiwgImdhbWUiKQ0KDQpteV9zdG9wX3dvcmRzIDwtIGJpbmRfcm93cyhkYXRhX2ZyYW1lKHdvcmQgPSByZW1vdmVfd29yZHMsIGxleGljb24gPSBjKCJTTUFSVCIpKSwgc3RvcF93b3JkcykNCg0KYGBgDQoNCg0KDQojIyMjIE5vdyBsZXRzIGNyZWF0ZSBhIGRhdGFmcmFtZSBvZiB3b3JkcyBhbmQgZmlsdGVyIHVzaW5nIHByZWRlZmluZWQgc3RvcCB3b3JkcyANCmBgYHtyfQ0KdHd0X3RleHQgPC0gdGliYmxlKHRleHQgPSB0d2VldHMkdGV4dCkgJT4lIA0KICB1bm5lc3RfdG9rZW5zKHdvcmQsIHRleHQpICU+JQ0KICBmaWx0ZXIoIXdvcmQgJWluJSBteV9zdG9wX3dvcmRzJHdvcmQsIHN0cl9kZXRlY3Qod29yZCwgIlthLXpdIikpDQoNCmBgYA0KDQoNCg0KIyMjIyBTZXQgYSB0aHJlc2hvbGQgZm9yIHRoZSBtaW4vbWF4IGZyZXF1ZW5jeSBvZiB3b3JkcyBhbmQgc2NhbGUgb2YgdGhlIHdvcmRjbG91ZA0KYGBge3J9DQptaW5fZnJlcSA9IDgwDQptYXhfd29yZHMgPSAxMDANCmZpZ19zY2FsZSA9IGMoMyAsIDAuNSkNCmBgYA0KDQoNCg0KIyMjIyBUaGUgbGFzdCBzdGVwIGlzIHRvIGNyZWF0ZSB0aGUgd29yZGNsb3VkIGJ5IGNvdW50aW5nIHRoZSBmcmVxdWVuY3kgb2YgdGhlIHdvcmRzDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCnR3dF90ZXh0ICU+JQ0KICBhbnRpX2pvaW4obXlfc3RvcF93b3JkcykgJT4lDQogIGNvdW50KHdvcmQpICU+JQ0KICB3aXRoKHdvcmRjbG91ZCh3b3JkLCBuLCANCiAgICAgICAgICAgICAgICAgc2NhbGUgPSBmaWdfc2NhbGUsDQogICAgICAgICAgICAgICAgIG1pbi5mcmVxID0gbWluX2ZyZXEsDQogICAgICAgICAgICAgICAgIG1heC53b3JkcyA9IG1heF93b3JkcykpDQoNCmBgYA0KDQoNCi0tLS0tLS0tLS0tLS0NCg0KIyMgVGFzayAxOiBEYXRhIEV4cGxvcmF0aW9uIC0gVGFibGVhdQ0KDQotLS0tLS0tLS0tLS0tDQoNCiMjIyAxQSkgR2VuZXJhbGx5IGRlc2NyaWJlIHRoZSBkYXRhIChzdW1tYXJ5KQ0KDQpgYGB7cn0NCnN1bW1hcnkodHdlZXRzKQ0KYGBgDQojIyBUaGlzIHN1bW1hcnkgc2hvd3MgdGhlIGRpZmZlcmVudCB0eXBlcyBvZiBzZW50aW1lbnRzIGluIHRoZSB0d2VldHMgc3VjaCBhcyBhbmdlciwgYW50aWNpcGF0aW9uLCBkaXNndXN0LCBmZWFyLCBqb3ksIHNhZG5lc3MsIHN1cnByaXNlLCBhbmQgdHJ1c3QuIEl0IHNob3dzIGhvdyBtYW55IHZlcmlmaWVkIHBlb3BsZSB0d2VldGVkIGFib3V0IExveW9sYSAtIHdoaWNoIHdhcyBvbmx5IG9uZS4gSXQgc2hvd3MgaG93IG1hbnkgcmV0d2VldHMsIGZhdm9yaXRlcywgYW5kIHJlcGxpZXMgdGhlcmUgd2VyZSBmb3IgdGhlIHR3ZWV0cy4gSXQgYWxzbyBzaG93cyBob3cgbWFueSBjb3VsZCBzZWVtIHBvc2l0aXZlIG9yIG5lZ2F0aXZlLg0KDQojIyMgMUIpIFVzZSB0YWJsZWF1IHRvIGNyZWF0ZSBhdCBsZWFzdCA1IHBsb3RzDQoNCmBgYHtyfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZ3MvdHdlZXRzMS5wbmciKQ0KYGBgDQojIyBUaGlzIGdyYXBoIHNob3dzIHdoaWNoIHR3ZWV0cyB3ZXJlIHJldHdlZXRlZCwgZmF2b3JpdGVkLCBvciByZXBsaWVkIG9uLg0KDQpgYGB7cn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJpbWdzL3R3ZWV0czIucG5nIikNCmBgYA0KIyMgVGhpcyBwbG90IHNob3dzIHdoaWNoIGFjY291bnRzIGhhZCB0aGUgbW9zdCByZXR3ZWV0cy4gQFJhbWJsZXJzTUJCIGhhZCB0aGUgbW9zdCBmb2xsb3dlZCBieSBAbWFyY2htYWRuZXNzLiBUaGUgcmVzdCBvZiB0aGUgYWNjb3VudHMgaGFkIHdheSBsZXNzIHJldHdlZXRzIHRoYW4gdGhlc2UgdHdvIGFjY291bnRzLiANCg0KYGBge3J9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy90d2VldHMzLnBuZyIpDQpgYGANCiMjIFRoaXMgc2hvd3MgaG93IG1hbnkgdHdlZXRzIHRoZXJlIHdlcmUgZm9yIGVhY2ggbWVhc3VyZS4gVGhlcmUgd2VyZSBtb3JlIGZhdm9yaXRlcyB0aGFuIHdlcmUgcmV0d2VldHMuIE1vcmUgdHdlZXRzIHdlcmUgYWtzaSBtb3JlIHBvc2l0aXZlIHRoYW4gbmVnYXRpdmUuIA0KDQpgYGB7cn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJpbWdzL3R3ZWV0czQucG5nIikNCmBgYA0KIyMgVGhpcyBncmFwaCBzaG93cyB0aGF0IG1vc3Qgb2YgdGhlIHR3ZWV0cyB3ZXJlIGluIDIwMTggYnV0IHNvbWUgZGF0ZSBiYWNrIHRvIDIwMTEuIA0KDQoNCg0KYGBge3J9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy90d2VldHM1LnBuZyIpDQpgYGANCiMjIFRoaXMgc2hvd3MgdGhhdCBtb3JlIHR3ZWV0cyB3ZXJlIHBvc2l0aXZlIHJhdGhlciB0aGFuIG5lZ2F0aXZlLiANCg0KIyMjIDFDKSBFeHBsYWluIGVhY2ggcGxvdCBtYWtlIGEgcmVsYXRpb24gdG8gZGF0ZSBvZiB0aGUgdHdlZXRzL3RpbWUNCiMjIGRvbmUgdW5kZXIgZWFjaCBncmFwaC4gDQotLS0tLS0tLS0tLS0tDQoNCiMjIFRhc2sgMzogRGF0YSBBbmFseXNpcw0KDQotLS0tLS0tLS0tLS0tDQoNCiMjIyAyQSlCYXNlZCBvbiB5b3VyIHBsb3RzIGFuZCBkYXRhIGRlc2NyaXB0aW9uIG1ha2UgZ2l2ZSBhIGdlbmVyYWwgbmFycmF0aXZlIGZvciB0aGUgaW1hZ2Ugb2YgbG95b2xhIGluIHR3aXR0ZXINCg0KIyMgTG95b2xhIHJlY2VpdmVkIG1vcmUgb2YgYSBwb3NpdGl2ZSBpbWFnZSBvbiB0d2l0dGVyIHRoYW4gYSBuZWdhdGl2ZSBvbmUuIFdlIGNhbiBzZWUgdGhhdCB0aGUgYWNjb3VudCBmb3IgdGhlIE1lbidzIGJhc2tldGJhbGwgdGVhbSBoYWQgdGhlIGJpZ2dlc3QgaW1wYWN0IG9uIHR3aXR0ZXIgdXNlcnMgYXMgaXQgaGFkIHRoZSBtb3N0IHJldHdlZXRzIG91dCBvZiBhbnkgYWNjb3VudCBsb29rZWQgYXQuIFBlb3BsZSB3ZXJlIGhhcHB5IHRoYXQgd2Ugd2VyZSB3aW5uaW5nIGFuZCB3ZXJlIGFueGlvdXMgZm9yIGVhY2ggZ2FtZS4gVGhpcyBhbGwgcG9pbnRzIHRvd2FyZCBhIHBvc2l0aXZlIGltYWdlIGZvciBMb3lvbGEuIA0KDQojIyMgMkIpIFVzZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHRvIGJhY2t1cCB5b3VyIGFyZ3VtZW50cw0KDQpgYGB7cn0NCnN1bW1hcnkodHdlZXRzKQ0KYGBgDQojIyBUaGlzIHN1bW1hcnkgc2hvd3MgdGhhdCB0aGUgbWF4IHdhcyA5IGZvciBwb3NpdGl2ZSB3aGljaCB3YXMgaGlnaGVyIHRoYW4gbmVnYXRpdmUgd2hpY2ggd2FzIDYuIEl0IGFsc28gc2hvd2VkIHRoZXJlIHdhcyBtb3JlIGZvciBqb3kgdGhhbiBhbmdlci4gVGhpcyBzaG93cyB0aGF0IHRoZSBzY2hvb2wgaGFkIG1vcmUgb2YgYSBwb3NpdGl2ZSBpbWFnZSB0aGFuIGEgbmVnYXRpdmUgb25lIGF0IHRoaXMgdGltZS4gIA0KDQojIyMgMkMpQW55IHJlY29tbWVuZGF0aW9ucyB0byBMb3lvbGEncyBtYXJrZXRpbmcgdGVhbQ0KIyMgTG95b2xhJ3MgbWFya2V0aW5nIHRlYW0gY2FuIHVzZSB0aGVpciBDaW5kZXJlbGxhIFN0b3J5IHRvIHBhaW50IExveW9sYSBpbiBhIHBvc2l0aXZlIGltYWdlLiBUaGVyZSB3YXMgY29uc3RhbnQgdGFsayBhYm91dCB0aGlzIHNjaG9vbCBkb2luZyBldmVyeXRoaW5nIHJpZ2h0LiBUaGV5IGNhbiB1c2UgdGhhdCBuYXJyYXRpdmUgdG8gYnJpbmcgaW4gbW9yZSBzdHVkZW50cyB0byBtYWtlIHRoaXMgc2Nob29sIHByb3NwZXJvdXMuIA0KLS0tLS0tLS0tLS0tLQ0KDQojIyBUYXNrIDM6IFdhdHNvbiBBbmFseXNpcw0KDQotLS0tLS0tLS0tLS0tDQoNCiMjIyAzQSlVc2Ugd2F0c29uIGFuYWx5dGljcyB0byBleHBsb3JlIHRoZSBkYXRhDQoNCiMjIyAzQilHaXZlIGF0IGxlYXN0IDMgcGxvdHMgb3IgZGlzY292ZXJpZXMgdXNpbmcgd2F0c29uLiBFeHBsYWluIHlvdXIgZmluZGluZ3MuDQoNCg0KYGBge3J9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy90d2VldHM2LnBuZyIpDQpgYGANCiMjIFRoaXMgc2hvd3Mgd2hhdCBkcm92ZSB0cnVzdCBmb3IgdGhlIHRlYW0uIFBvc2l0aXZlLCBqb3ksIGFuZCBhbnRpY2lwYXRpb24gZm9zdGVyZWQgdHJ1c3QgaW4gdGhlIHRlYW0uIFRoaXMgbWVhbnMgdGhleSB3ZXJlIHRydXN0aW5nIHRoZSB0ZWFtIHRvIHdpbiB3aGljaCBnYXZlIGEgcG9zaXRpdmUgcmVzcG9uc2Ugb2YgaGFwcGluZXNzLiANCg0KYGBge3J9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy90d2VldHM3LnBuZyIpDQpgYGANCiMjIE1vc3Qgb2YgdGhlIHR3ZWV0cyBhYm91dCBqb3kgd2VyZSB0b3dhcmRzIHRoZSBlbmQgb2YgdGhlIG1vbnRoIGFyb3VuZCB0aGUgdGltZSBvZiB0aGUgZWxpdGUgOCB3aGljaCBsZWFkIHRvIHRoZSBmaW5hbCBmb3VyLiBUaGlzIHNob3dzIHRoZSBwb3NpdGl2ZSBpbWFnZSBsb3lvbGEgaGFkIGF0IHRoZSB0aW1lLiANCg0KYGBge3J9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy90d2VldHM4LnBuZyIpDQpgYGANCiMjIFRoaXMgc2hvd3MgdGhlcmUgd2VyZSB0d2VldHMgYWJvdXQgdHJ1c3QgZm9yIHllYXJzLCBidXQgbW9zdCB3ZXJlIGFib3V0IHRoZSB0ZWFtIGluIDIwMTguIEl0IHNlZW1zIGxpa2UgbW9zdCB3ZXJlIGJlZm9yZSB0aGUgdG91cm5hbWVudCBzdGFydGVkIHByb2JhYmx5IHRhbGtpbmcgYWJvdXQgd2hhdCBtYXkgaGFwcGVuLiA=