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")
}
if(!require("cleanNLP")){
  install.packages("cleanNLP", dependencies = TRUE)
  library("cleanNLP")
}
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/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 = " "))
head(tweets['text'])

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)

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)
Error in bind_rows(data_frame(word = remove_words, lexicon = c("SMART")),  : 
  could not find function "bind_rows"

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))
Error in twt_text %>% anti_join(my_stop_words) %>% count(word) %>% with(wordcloud(word,  : 
  could not find function "%>%"

Task 1: Data Exploration - Tableau


1A) Generally describe the data (summary)

mydata = read.csv("~/Dropbox/Cameron/college 2017-2018/Semester Two/BSAD- Business Analytics/BSAD Labs/09-notebook-lab/data/sentiment_march_madness.csv")
summary(mydata)
    tweet_id                   text                   username    
 Min.   :3.542e+16               : 1273   @LALATE         :   81  
 1st Qu.:9.774e+17               : 1245   @RamblersMBB    :   30  
 Median :9.777e+17               :  197   @SkywayChicago  :   27  
 Mean   :9.753e+17               :   51   @chicagomargaret:   21  
 3rd Qu.:9.777e+17               :   35   @sschrimp       :   18  
 Max.   :9.824e+17     SisterJean:   15   @loyolaforus    :   16  
                     (Other)     :17371   (Other)         :19994  
              fullname             date                       datetime    
 LALATE           :   81   2018-03-25:10708   2018-03-25T00:21:10Z:   16  
 Loyola Basketball:   31   2018-03-23: 2976   2018-03-25T00:21:31Z:   16  
 Steve Timble     :   27   2018-03-24: 2274   2018-03-25T00:21:09Z:   15  
 Margaret Holt    :   21   2018-03-26: 1504   2018-03-25T00:21:35Z:   15  
 Mark             :   21   2018-03-18: 1099   2018-03-25T00:21:08Z:   14  
 Steve            :   19   2018-03-27:  241   2018-03-25T00:21:11Z:   14  
 (Other)          :19987   (Other)   : 1385   (Other)             :20097  
    verified           reply             retweets           favorite      
 Min.   :0.00000   Min.   :  0.0000   Min.   :   0.000   Min.   :    0.0  
 1st Qu.:0.00000   1st Qu.:  0.0000   1st Qu.:   0.000   1st Qu.:    0.0  
 Median :0.00000   Median :  0.0000   Median :   0.000   Median :    1.0  
 Mean   :0.06192   Mean   :  0.3467   Mean   :   3.146   Mean   :   15.8  
 3rd Qu.:0.00000   3rd Qu.:  0.0000   3rd Qu.:   0.000   3rd Qu.:    3.0  
 Max.   :1.00000   Max.   :591.0000   Max.   :5143.000   Max.   :32180.0  
                                                                          
     anger         anticipation       disgust             fear             joy       
 Min.   :0.0000   Min.   :0.0000   Min.   :0.00000   Min.   :0.0000   Min.   :0.000  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.00000   1st Qu.:0.0000   1st Qu.:0.000  
 Median :0.0000   Median :0.0000   Median :0.00000   Median :0.0000   Median :0.000  
 Mean   :0.1342   Mean   :0.4359   Mean   :0.07143   Mean   :0.1612   Mean   :0.421  
 3rd Qu.:0.0000   3rd Qu.:1.0000   3rd Qu.:0.00000   3rd Qu.:0.0000   3rd Qu.:1.000  
 Max.   :4.0000   Max.   :7.0000   Max.   :3.00000   Max.   :6.0000   Max.   :8.000  
                                                                                     
    sadness          surprise          trust           negative         positive     
 Min.   :0.0000   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   1st Qu.:0.0000  
 Median :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   Mean   :0.6676  
 3rd Qu.:0.0000   3rd Qu.:0.0000   3rd Qu.:1.0000   3rd Qu.:0.0000   3rd Qu.:1.0000  
 Max.   :5.0000   Max.   :4.0000   Max.   :7.0000   Max.   :6.0000   Max.   :9.0000  
                                                                                     
 sentiment_bing                               links      
 Min.   :-5.0000   @RamblersMBB                  : 1139  
 1st Qu.: 0.0000   #LoyolaChicago                : 1027  
 Median : 0.0000   #SisterJean                   :  778  
 Mean   : 0.5141   https://twitter.com#SisterJean:  231  
 3rd Qu.: 1.0000   #LoyolaChicago; #MarchMadness :  208  
 Max.   :11.0000   (Other)                       :16117  
                   NA's                          :  687  

This dataset is a compilation of tweets that werer collected during March Madness. The dataset looks at the number of tweets as well as the number of favorites, replies, and retweets. Additionally, this dataset looks at the different sentiments included in the tweets, which resemebles some of the feelings people were having while tweeting about Loyola and the games.

1B) Use tableau to create at least 5 plots

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

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

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

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

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

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

The first plot shows the accounts with the greatest number of retweets while the second plot shows the top five accounts with the most tweets overall. The third plot shows the number of tweets per day. The line on this plot obviously peaks on the days that the March Madness games were played. The fourth plot the number of tweets by datetime, and again there is a peak during the time in which the game was played. Finally, the fifth plot shows the number of tweets by different sentiments. Overall, most of the tweets had a good sentiment, whether it was positive, anticipation, or joy. There were far fewer tweets with a bad sentiment, such as anger or disgust. There are also a significant amount of tweets that contained a fearful or sad sentiment, which makes sense for those fans that were afraid the team would not win a game, and then the ones that were obviously sad when the team did lose in the Final Four.


Task 3: Data Analysis


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

Overall, there was a very positive image of Loyola on twitter during March Madess. Many of the tweets had an overall positive sentiment, which makes it easy to assume that the majority of people tweeting about Loyola were supporting the team. Additionally, due to the sheet number of tweets, it is safe to say that Loyola had a significant presence on Twitter during March Madness. This makes sense because Loyola did make it into the Final Four, and they were one of the favorite teams considering nobody really expected them to even be in the tournament, so naturally it seems logical that there are so many tweets about Loyola.

2B) Use descriptive statistics to backup your arguments

summary(mydata)
    tweet_id                   text                   username    
 Min.   :3.542e+16               : 1273   @LALATE         :   81  
 1st Qu.:9.774e+17               : 1245   @RamblersMBB    :   30  
 Median :9.777e+17               :  197   @SkywayChicago  :   27  
 Mean   :9.753e+17               :   51   @chicagomargaret:   21  
 3rd Qu.:9.777e+17               :   35   @sschrimp       :   18  
 Max.   :9.824e+17     SisterJean:   15   @loyolaforus    :   16  
                     (Other)     :17371   (Other)         :19994  
              fullname             date                       datetime    
 LALATE           :   81   2018-03-25:10708   2018-03-25T00:21:10Z:   16  
 Loyola Basketball:   31   2018-03-23: 2976   2018-03-25T00:21:31Z:   16  
 Steve Timble     :   27   2018-03-24: 2274   2018-03-25T00:21:09Z:   15  
 Margaret Holt    :   21   2018-03-26: 1504   2018-03-25T00:21:35Z:   15  
 Mark             :   21   2018-03-18: 1099   2018-03-25T00:21:08Z:   14  
 Steve            :   19   2018-03-27:  241   2018-03-25T00:21:11Z:   14  
 (Other)          :19987   (Other)   : 1385   (Other)             :20097  
    verified           reply             retweets           favorite      
 Min.   :0.00000   Min.   :  0.0000   Min.   :   0.000   Min.   :    0.0  
 1st Qu.:0.00000   1st Qu.:  0.0000   1st Qu.:   0.000   1st Qu.:    0.0  
 Median :0.00000   Median :  0.0000   Median :   0.000   Median :    1.0  
 Mean   :0.06192   Mean   :  0.3467   Mean   :   3.146   Mean   :   15.8  
 3rd Qu.:0.00000   3rd Qu.:  0.0000   3rd Qu.:   0.000   3rd Qu.:    3.0  
 Max.   :1.00000   Max.   :591.0000   Max.   :5143.000   Max.   :32180.0  
                                                                          
     anger         anticipation       disgust             fear             joy       
 Min.   :0.0000   Min.   :0.0000   Min.   :0.00000   Min.   :0.0000   Min.   :0.000  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.00000   1st Qu.:0.0000   1st Qu.:0.000  
 Median :0.0000   Median :0.0000   Median :0.00000   Median :0.0000   Median :0.000  
 Mean   :0.1342   Mean   :0.4359   Mean   :0.07143   Mean   :0.1612   Mean   :0.421  
 3rd Qu.:0.0000   3rd Qu.:1.0000   3rd Qu.:0.00000   3rd Qu.:0.0000   3rd Qu.:1.000  
 Max.   :4.0000   Max.   :7.0000   Max.   :3.00000   Max.   :6.0000   Max.   :8.000  
                                                                                     
    sadness          surprise          trust           negative         positive     
 Min.   :0.0000   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   1st Qu.:0.0000  
 Median :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   Mean   :0.6676  
 3rd Qu.:0.0000   3rd Qu.:0.0000   3rd Qu.:1.0000   3rd Qu.:0.0000   3rd Qu.:1.0000  
 Max.   :5.0000   Max.   :4.0000   Max.   :7.0000   Max.   :6.0000   Max.   :9.0000  
                                                                                     
 sentiment_bing                               links      
 Min.   :-5.0000   @RamblersMBB                  : 1139  
 1st Qu.: 0.0000   #LoyolaChicago                : 1027  
 Median : 0.0000   #SisterJean                   :  778  
 Mean   : 0.5141   https://twitter.com#SisterJean:  231  
 3rd Qu.: 1.0000   #LoyolaChicago; #MarchMadness :  208  
 Max.   :11.0000   (Other)                       :16117  
                   NA's                          :  687  

This shows that the maximum value for positive is 9, which is the highest among all of the sentiments. Joy and trust are also quite high at 8 and 7 respectively. Seeing that these are all good sentiments, it is safe to say that these helped to create a positive image of Loyola on twitter.

2C)Any recommendations to Loyola’s marketing team

I would say that Loyola’s marketing team should continue to use some of the hashtags that were created in relation to Loyola’s March Madness run. Furthermore, they should pick two or three specific hashtags and encourage students to use those when tweeting about Loyola. This could help consildate many of their marketing efforts into one. Also, I would recommend that the marketing team turn some of the most popular tweets or hashtags into a new marketing campaign and make promotional materials inclduing them. Since many people now know Loyola through the basketball program, it would be wise to use these tweets to catch the attention of non-Loyola people and then once they have their attention, they can share more information about things other than basketball with them.


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/screenshot6.png")

This graph depicts what the top drivers of joy are. According to this graph, the top driver is potisitve and anticipation. This makes sense because those who were tweeting with either or both a postitive or anticipatory sentiment would also have had a joyful sentiment. All of these emotions seem to go together, so it seems accurate that this is the top predictor of joy.

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

This graph shows how the number of tweets that were favorited and the number of replies compare in relation to the date. The two highest peaks were on March 28 and April 1, which were both game days for Loyola. This makes compelte sense, because people would obviously be more likely to tweet either during the games or immediately after they won.

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

This wordcloud displays what the most common hashtags were that were used in the tweets from the dataset. The most popular hashtags included #FinalFour and #LoyolaChicago. Obviously, the greatest number of tweets came during the Final Four game that Loyola played in so it makes sense that #FinalFour is one of the most common hashtags in addition to #LoyolaChicago.

LS0tCnRpdGxlOiAiTWFyY2ggTWFkbmVzcyBBbmFseXNpcyIKYXV0aG9yOiAKLSAiUXVpbmxhbiBTY2hvb2wgb2YgQnVzaW5lc3MgLSBMb3lvbGEgVW5pdmVyc2l0eSBDaGljYWdvIgotICJDYW1lcm9uIEdlcmhhcnQiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdApkYXRlOiAiQXByaWwgMjQsIDIwMTgiCnN1YnRpdGxlOiAiQ01FIEdyb3VwIEZvdW5kYXRpb24gQnVzaW5lc3MgQW5hbHl0aWNzIExhYiIKLS0tCgoKCi0tLS0tLS0tLS0tLS0tCgojIyBBYm91dCB0aGlzIE5vdGVib29rCgotLS0tLS0tLS0tLS0tLQoKKiBPbiB0aGlzIG5vdGVib29rIHdlIGFyZSBnb2luZyB0byBhbmFseXNpcyB0d2VldHMgZnJvbSBtYXJjaCBtYWRuZXNzIDIwMTgKCiogVXNlIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBjbGVhbiB0aGUgdHdlZXRzIHRleHQKCiogRmFtaWxpYXJpemUgd2l0aCBzb21lIG5hdHVyYWwgbGFuZ3VhZ2UgcHJvY2Vzc2luZyB0b29scwoKCgotLS0tLS0tLS0tLS0tLQoKIyMgQW5hbHl0aWNzIFRvb2xraXQ6IFJlcXVpcmUgUGFja2FnZXMKCi0tLS0tLS0tLS0tLS0tCgoKCiogdGlkeXZlcnNlOiBodHRwczovL3d3dy50aWR5dmVyc2Uub3JnLwoqIHN5dXpoZXQ6IGh0dHBzOi8vZ2l0aHViLmNvbS9tam9ja2Vycy9zeXV6aGV0CiogY2xlYW5OTFA6IGh0dHBzOi8vZ2l0aHViLmNvbS9zdGF0c21hdGhzL2NsZWFuTkxQCiogd29yZGNsb3VkOiBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvd29yZGNsb3VkL3dvcmRjbG91ZC5wZGYKCmBgYHtyICwgbWVzc2FnZT1GQUxTRX0KCiMgSGVyZSB3ZSBhcmUgY2hlY2tpbmcgaWYgdGhlIHBhY2thZ2UgaXMgaW5zdGFsbGVkCmlmKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSl7CiAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkKICBsaWJyYXJ5KCJ0aWR5dmVyc2UiKQp9CgppZighcmVxdWlyZSgic3l1emhldCIpKXsKICBpbnN0YWxsLnBhY2thZ2VzKCJzeXV6aGV0IiwgZGVwZW5kZW5jaWVzID0gVFJVRSkKICBsaWJyYXJ5KCJzeXV6aGV0IikKfQoKaWYoIXJlcXVpcmUoImNsZWFuTkxQIikpewogIGluc3RhbGwucGFja2FnZXMoImNsZWFuTkxQIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkKICBsaWJyYXJ5KCJjbGVhbk5MUCIpCn0KCmlmKCFyZXF1aXJlKCJtYWdyaXR0ciIpKXsKICBpbnN0YWxsLnBhY2thZ2VzKCJtYWdyaXR0ciIsIGRlcGVuZGVuY2llcyA9IFRSVUUpCiAgbGlicmFyeSgibWFncml0dHIiKQp9CgppZighcmVxdWlyZSgid29yZGNsb3VkIikpewogIGluc3RhbGwucGFja2FnZXMoIndvcmRjbG91ZCIsIGRlcGVuZGVuY2llcyA9IFRSVUUpCiAgbGlicmFyeSgid29yZGNsb3VkIikKfQoKYGBgCgoKCi0tLS0tLS0tLS0tLS0tCgojIyBEYXRhIFByZXBhcmF0aW9uOiBDbGVhbmluZyB0d2VldHMgdXNpbmcgcmVndWxhciBleHByZXNzaW9ucwoKLS0tLS0tLS0tLS0tLS0KCgoKIyMjIyBSZWFkaW5nIGFuZCBpbnNwZWN0aW5nIHRoZSBkYXRhc2V0CmBgYHtyLCBtZXNzYWdlPUZBTFNFfQp0d2VldHMgPC0gcmVhZF9jc3YoImRhdGEvbWFyY2hfbWFkbmVzcy5jc3YiKQoKIyBDaGFuZ2UgdGhlIHR3ZWV0cyBJRHMgZnJvbSBsb25nZSBpbnRlZ2VyIHRvIGNoYXJhY3RlcnMKdHdlZXRzJHR3ZWV0X2lkIDwtIGFzLmNoYXJhY3Rlcih0d2VldHMkdHdlZXRfaWQpCgojIEV4dHJhY3QgYW5kIGRlbGV0ZSB0aGUgbGlua3MgdmFyaWFibGUgdG8gYWRkIGl0IGF0IHRoZSBlbmQKbGlua3MgPC0gdHdlZXRzJGxpbmtzCnR3ZWV0cyRsaW5rcyA8LSBOVUxMCgojIEluc3BlY3RzIHRoZSBmaXJzdCAxMCByb3dzCmhlYWQodHdlZXRzKQpgYGAKCgoKIyMjIyBOb3cgZmlyc3Qgd2UgbmVlZCB0byBleHRyYWN0IHRoZSB0ZXh0IGZyb20gdGhlIHJhdyB0d2VldHMgYW5kIGNsZWFuIGl0IHVzaW5nIHJlZ3VsYXIgZXhwcmVzc2lvbnMKYGBge3J9CnJlcGxhY2VfcmVnIDwtICdodHRwczovL3QuY28vW0EtWmEtelxcZF0rfGh0dHA6Ly9bQS1aYS16XFxkXSt8KHBpYy50d2l0dGVyLmNvbS9bQS1aYS16XFxkXSspfCZhbXA7fCZsdDt8Jmd0O3xSVHwoLiouKVxcLmNvbSguKi4pXFxTK1xcc3xbXls6YWxudW06XV18KGh0dHB8aHR0cHMpXFxTK1xccyp8KCN8QClcXFMrXFxzKnxcXG58XFwiJwoKdHdlZXRzIDwtIHR3ZWV0cyAlPiUgCiAgbXV0YXRlKHRleHQgPSBzdHJfcmVwbGFjZV9hbGwodGV4dCwgcmVwbGFjZV9yZWcsICIgIikpICU+JSAKICBtdXRhdGUodGV4dCA9IGljb252KHRleHQsIGZyb20gPSAiQVNDSUkiLCB0byA9ICJVVEYtOCIsIHN1YiA9ICIgIikpCgpoZWFkKHR3ZWV0c1sndGV4dCddKQpgYGAKCgoKIyMjIyBIZXJlIHdlIGFyZSBnb2luZyB0byB1c2UgdGhlIFNhaWYgTW9oYW1tYWTigJlzIE5SQyBFbW90aW9uIGxleGljb24gdG9leHRyYWN0IHRoZSBzZW50aW1lbnQgb2YgdGhlIHR3ZWV0LiBUaGUgTlJDIGVtb3Rpb24gbGV4aWNvbiBpcyBhIGxpc3Qgb2Ygd29yZHMgYW5kIHRoZWlyIGFzc29jaWF0aW9ucyB3aXRoIGVpZ2h0IGVtb3Rpb25zIChhbmdlciwgZmVhciwgYW50aWNpcGF0aW9uLCB0cnVzdCwgc3VycHJpc2UsIHNhZG5lc3MsIGpveSwgYW5kIGRpc2d1c3QpIGFuZCB0d28gc2VudGltZW50cyAobmVnYXRpdmUgYW5kIHBvc2l0aXZlKS4KCiogU291cmNlOiBodHRwOi8vc2FpZm1vaGFtbWFkLmNvbS9XZWJQYWdlcy9OUkMtRW1vdGlvbi1MZXhpY29uLmh0bQoKYGBge3J9Cm5yY19kYXRhIDwtIGdldF9ucmNfc2VudGltZW50KHR3ZWV0cyR0ZXh0KQpucmNfZGF0YSA8LSBhc190aWJibGUobnJjX2RhdGEpCgpoZWFkKG5yY19kYXRhKQpgYGAKCgoKIyMjIyBIZXJlIHdlIGFyZSBnb2luZyB0byBtZXJnZSB0aGUgTlJDIEVtb3Rpb24gcmVzdWx0cyB3aXRoIHRoZSBvcmlnaW5hbCBkYXRhIHRvIGNyZWF0ZSBhIGNvbXBsZXRlIGRhdGFzZXQuCmBgYHtyfQp0d2VldHMgPC0gYmluZF9jb2xzKHR3ZWV0cywgbnJjX2RhdGEpCgpgYGAKCgoKIyMjIyBUbyBoYXZlIGFub3RoZXIgbWV0cmljcyBmb3Igc2VtdGltZW50IHdlIGFyZSBnb2luZyB0byB1c2UgYW5vdGhlciBsZXhpY29uIGRldmVsb3BlZCBieSBQcm9mZXNzb3IgTWlucWluZyBIdSBhbmQgUHJvZmVzc29yIEJpbmcgTGl1LCBmcm9tIFVuaXZlcnNpdHkgb2YgSWxsaW5vaXMgYXQgQ2hpY2Fnby4KKiBTb3VyY2U6IGh0dHA6Ly93d3cuY3MudWljLmVkdS9+bGl1Yi9GQlMvc2VudGltZW50LWFuYWx5c2lzLmh0bWwKCmBgYHtyfQp0d2VldHMkc2VudGltZW50X2JpbmcgPC0gZ2V0X3NlbnRpbWVudChjaGFyX3YgPSB0d2VldHMkdGV4dCwgbWV0aG9kPSJiaW5nIiwgbGFuZ3VhZ2UgPSAiZW5nbGlzaCIpCgpgYGAKCgoKIyMjIyBGaW5hbGx5IGFkZCB0aGUgbGlua3MgdmFyaWFibGUgYW5kIHNhdmUgdGhlIG5ldyBjb21wbGV0ZSBkYXRhc2V0IApgYGB7cn0KdHdlZXRzJGxpbmtzIDwtIGxpbmtzCgp3cml0ZV9jc3YodHdlZXRzLCAiZGF0YS9tYXJjaF9tYWRuZXNzX3NlbnQuY3N2IikKCmhlYWQodHdlZXRzWzM6MTBdKQpgYGAKCgoKLS0tLS0tLS0tLS0tLS0KCiMjIFNlbnRpbWVudCBBbmFseXNpczogTmF0dXJhbCBMYW5ndWFnZSBQcm9jZXNzaW5nCgotLS0tLS0tLS0tLS0tLQoKCgojIyMjIEZpcnN0IGxldHMgcmVhZCB0aGUgZGF0YXNldCBhbmQgaW5zcGVjdCB0aGUgZmlyc3QgMTAgcm93cwpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KdHdlZXRzIDwtIHJlYWRfY3N2KCJkYXRhL3NlbnRpbWVudF9tYXJjaF9tYWRuZXNzLmNzdiIpCnR3ZWV0cyR0d2VldF9pZCA8LSBhcy5jaGFyYWN0ZXIodHdlZXRzJHR3ZWV0X2lkKQpoZWFkKHR3ZWV0c1sxMjoyMV0pCmBgYAoKCgojIyMjIEZvciBzZW50aW1lbnQgYW5hbHlzaXMgd2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgY2xlYW5OTFAgcGFja2FnZSB0aGF0IHVzZXMgU3RhbmZvcmQgQ29yZU5MUCDigJMgTmF0dXJhbCBsYW5ndWFnZSBzb2Z0d2FyZSBpbnQgaGUgYmFja2VuZC4gRmlyc3Qgd2UgbmVlZCB0byBpbml0aWFsaXplIHRoZSBDb3JlTkxQIGVuZ2luZSBhbmQgY3JlYXRlIGFuIGFubm90YXRpb24gb2JqZWN0IHVzaW5nIHRoZSB0ZXh0IGNvbHVtbiwgdHdlZXRfaWQgYW5kIHRoZSBvdGhlciBjb2x1bW5zIGFyZSBnaXZlbiBhcyBtZXRhZGF0YQpgYGB7cn0KY25scF9pbml0X3VkcGlwZSgpCgpkb2MgPC0gY25scF9hbm5vdGF0ZShpbnB1dCA9IHR3ZWV0cyR0ZXh0LCBhc19zdHJpbmdzID0gVFJVRSwgZG9jX2lkcyA9IHR3ZWV0cyR0d2VldF9pZCwgbWV0YSA9IHR3ZWV0c1stYygxLDIpXSkKCmBgYAoKCgojIyMjIERpc3RyaWJ1dGlvbiBvZiB0d2VldC9zZW50ZW5jZSBsZW5ndGgsIG1heCBudW1iZXIgb2Ygd29ya3MgaW4gYSB0d2VldCAyODAKYGBge3J9CnRva2VucyA8LSBjbmxwX2dldF90b2tlbihkb2MpICU+JQogIGdyb3VwX2J5KGlkLCBzaWQpICU+JQogIHN1bW1hcml6ZShzZW50X2xlbiA9IG4oKSkKCnF1YW50aWxlKHRva2VucyRzZW50X2xlbiwgc2VxKDAsMSwwLjEpKQoKYGBgCgoKCiMjIyMgSGVyZSB3ZSBjYW4gc2VlIHRoZSBjaGFuZ2Ugb2Ygc2VudGltZW50IGluIHRoZSB0d2VldHMgCmBgYHtyfQpxcGxvdCh4ID0gMTpsZW5ndGgodHdlZXRzJHNlbnRpbWVudF9iaW5nKSwgCiAgICAgIHkgPSB0d2VldHMkc2VudGltZW50X2JpbmcsIAogICAgICBnZW9tID0gImxpbmUiLCAKICAgICAgeGxhYiA9ICJOYXJyYXRpdmUgVGltZSIsIAogICAgICB5bGFiID0gIkVtb3Rpb25hbCBWYWxlbmNlIiwgCiAgICAgIG1haW4gPSAiVHdlZXRzIFNlbnRpbWVudCBUcmFqZWN0b3J5IikKCmBgYAoKCgojIyMjIEhlcmUgd2UgY2FuIGZpbmQgdGhlIG1vc3QgdXNlZCBlbnRpdGllcyBmcm9tIHRoZSB0d2VldHMgZW50aXR5IHRhYmxlLiBUaGUgZG9jdW1lbnQgY29ycHVzIHlpZWxkcyBhbiBhbHRlcm5hdGl2ZSB3YXkgdG8gc2VlIHRoZSB1bmRlcmx5aW5nIHRvcGljcy4KYGBge3J9CnR3ZWV0c19lbnRpdGllcyA8LSBjbmxwX2dldF90b2tlbihkb2MpICU+JQogIGZpbHRlcih1cG9zID09ICJOT1VOIikgJT4lCiAgZ3JvdXBfYnkobGVtbWEpICU+JQogIHN1bW1hcml6ZShjb3VudCA9IG4oKSkgJT4lCiAgdG9wX24obiA9IDgwLCBjb3VudCkgJT4lCiAgYXJyYW5nZShkZXNjKGNvdW50KSkgJT4lCiAgdXNlX3NlcmllcyhsZW1tYSkKCmRhdGFfZnJhbWUodHdlZXRzX2VudGl0aWVzKQoKYGBgCgoKCiMjIyMgSGVyZSB3ZSBjcmVhdGluZyBhIGhpZ2gtbGV2ZWwgc3VtbWFyeSBvZiB0aGUgdHdlZXRzIHRleHQgYnkgZXh0cmFjdGluZyBhbGwgZGlyZWN0IG9iamVjdCBvYmplY3QtZGVwZW5kZW5jaWVzLgpgYGB7cn0KdHdlZXRzX3N1bW1hcnkgPC0gY25scF9nZXRfZGVwZW5kZW5jeShkb2MsIGdldF90b2tlbiA9IFRSVUUpICU+JQogIGxlZnRfam9pbihjbmxwX2dldF9kb2N1bWVudChkb2MpKSAlPiUKICBzZWxlY3QoaWQgPSBpZCwgc3RhcnQgPSB3b3JkLCB3b3JkID0gbGVtbWFfdGFyZ2V0KSAlPiUKICBsZWZ0X2pvaW4od29yZF9mcmVxdWVuY3kpICU+JQogIGZpbHRlcihmcmVxdWVuY3kgPCAwLjAwMDEpICU+JQogIHNlbGVjdChpZCwgc3RhcnQsIHdvcmQpICUkJQogIHNwcmludGYoIiVzID0+ICVzIiwgc3RhcnQsIHdvcmQpCgpkYXRhX2ZyYW1lKHR3ZWV0c19zdW1tYXJ5KQoKYGBgCgoKCiMjIyMgTG9vayBhdCB0aGUgdHdlZXRzIHdpdGggbmVnYXRpdmUgc2VudGltZW50IApgYGB7cn0KCmFuZ3J5X3R3ZWV0cyA8LSB3aGljaCh0d2VldHMkYW5nZXIgPiAwKQpkYXRhX2ZyYW1lKHR3ZWV0ID0gdHdlZXRzJHRleHRbYW5ncnlfdHdlZXRzXVsxOjJdKQoKYGBgCgoKCiMjIyMgTG9vayBhIHR3ZWV0cyB3aXRoIHBvc2l0aXZlIHNlbnRpbWVudApgYGB7cn0Kam95X3R3ZWV0cyA8LSB3aGljaCh0d2VldHMkam95ID4gMCkKZGF0YV9mcmFtZSh0d2VldCA9IHR3ZWV0cyR0ZXh0W2pveV90d2VldHNdWzU6N10pCgpgYGAKCgoKIyMjIyBMZXRzIGV4cGxvcmUgdGhlIGVtb3Rpb25zIGluIHRoZSB0d2VldHMgbW9yZSBpbi1kZXB0aC4gSGVyZSB3ZSBhcmUgZ29pbmcgdG8gZXh0cmFjdCB0aGUgdmFyaWFibGVzIHJlZ2FyZGluZyBlbW90aW9ucyBhbmQgY3JlYXRlIGEgc3Vic2V0LgpgYGB7cn0KdmFsdWUgPC0gYXMuZG91YmxlKGNvbFN1bXMocHJvcC50YWJsZSh0d2VldHNbLCAxMToxOF0pKSkKZW1vdGlvbiA8LSBuYW1lcyh0d2VldHMpWzExOjE4XQplbW90aW9uIDwtIGZhY3RvcihlbW90aW9uLCBsZXZlbHMgPSBuYW1lcyh0d2VldHMpWzExOjE4XVtvcmRlcih2YWx1ZSwgZGVjcmVhc2luZyA9IEZBTFNFKV0pCmVtb3Rpb25zIDwtIGRhdGFfZnJhbWUoZW1vdGlvbiwgcGVyY2VudCA9IHZhbHVlICogMTAwKQoKaGVhZChlbW90aW9ucykKYGBgCgoKCiMjIyMgTm93IHdlIGNhbiBjcmVhdGUgYSBwbG90IG9mIHRoZSBlbW90aW9ucyBpbiB0aGUgbWFyY2ggbWFkbmVzcyB0d2VldHMKYGBge3J9CmdncGxvdChkYXRhID0gZW1vdGlvbnMsIGFlcyh4ID0gZW1vdGlvbiwgeSA9IHBlcmNlbnQpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBhZXMoZmlsbCA9IGVtb3Rpb24pKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlJkWWxHbiIpICsgCiAgY29vcmRfZmxpcCgpICsKICB4bGFiKCJFbW90aW9uIikgKwogIHlsYWIoIlBlcmNlbnRhZ2UiKQoKYGBgCgoKCi0tLS0tLS0tLS0tLS0tCgojIyBSZXBvcnRpbmc6IEEgV29yZGNsb3VkIGZyb20gTWFyY2ggTWFkbmVzcyBUd2VldHMKCi0tLS0tLS0tLS0tLS0tCgoKCiMjIyMgV29yZGNsb3VkcyBhcmUgYWx3YXlzIGEgZnVuIGFuZCBlbmdhZ2luZyB3YXkgdG8gZGlzcGxheSBkYXRhLiBIZXJlIHdlIGFyZSBnb2luZyB0byBzZXQgc29tZSBzdG9wIHdvcmRzIHRoYXQgd2UgZG9udCB3YW50IGluIHRoZSBwbG90LgpgYGB7cn0KcmVtb3ZlX3dvcmRzIDwtIGMoICJ0d2l0dGVyIiwgImNoaWNhZ28iLCAibG95b2xhIiwgInJhbWJsZXJzIiwgImxveW9sYXJhbWJsZXJzIiwic2Nob29sIiwgImdvbm5hIiwKICAgICAgICAgICAgICAgICAgICJ1bml2ZXJzaXR5IiwgImx1YyIsICJsb3lvbGFjaGljYWdvIiAsICJyYW1ibGVyc21iYiIsICJuY2FhIiwidmUiLCJiYXNrZXRiYWxsIiAsCiAgICAgICAgICAgICAgICAgICAidW1pY2hiYmFsbCIsICJtYXJjaG1hZG5lc3MyMDE4IiwgIm1hcmNobWFkbmVzcyIsICJmaW5hbCIsICJtYXJjaG1hZGRuZXNzIiwKICAgICAgICAgICAgICAgICAgICJnb2JsdWUiLCAiZmluYWxmb3VyIiwgInNpc3RlcmplYW4iLCAibmNhYXRvdXJuYW1lbnQiLCAibmNhYXRvdXJuYW1lbnQyMDE4IiwKICAgICAgICAgICAgICAgICAgICJkaWRuIiwiY2l0eSIsICJoZXkiLCAiZGF5IiwgImNvbGxlZ2UiLCAiZ2FtZXMiLCAidG91cm5leSIsICJtYXJjaCIsICJnYW1lIikKCm15X3N0b3Bfd29yZHMgPC0gYmluZF9yb3dzKGRhdGFfZnJhbWUod29yZCA9IHJlbW92ZV93b3JkcywgbGV4aWNvbiA9IGMoIlNNQVJUIikpLCBzdG9wX3dvcmRzKQoKYGBgCgoKCiMjIyMgTm93IGxldHMgY3JlYXRlIGEgZGF0YWZyYW1lIG9mIHdvcmRzIGFuZCBmaWx0ZXIgdXNpbmcgcHJlZGVmaW5lZCBzdG9wIHdvcmRzIApgYGB7cn0KdHd0X3RleHQgPC0gdGliYmxlKHRleHQgPSB0d2VldHMkdGV4dCkgJT4lIAogIHVubmVzdF90b2tlbnMod29yZCwgdGV4dCkgJT4lCiAgZmlsdGVyKCF3b3JkICVpbiUgbXlfc3RvcF93b3JkcyR3b3JkLCBzdHJfZGV0ZWN0KHdvcmQsICJbYS16XSIpKQoKYGBgCgoKCiMjIyMgU2V0IGEgdGhyZXNob2xkIGZvciB0aGUgbWluL21heCBmcmVxdWVuY3kgb2Ygd29yZHMgYW5kIHNjYWxlIG9mIHRoZSB3b3JkY2xvdWQKYGBge3J9Cm1pbl9mcmVxID0gODAKbWF4X3dvcmRzID0gMTAwCmZpZ19zY2FsZSA9IGMoMyAsIDAuNSkKYGBgCgoKCiMjIyMgVGhlIGxhc3Qgc3RlcCBpcyB0byBjcmVhdGUgdGhlIHdvcmRjbG91ZCBieSBjb3VudGluZyB0aGUgZnJlcXVlbmN5IG9mIHRoZSB3b3JkcwpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KdHd0X3RleHQgJT4lCiAgYW50aV9qb2luKG15X3N0b3Bfd29yZHMpICU+JQogIGNvdW50KHdvcmQpICU+JQogIHdpdGgod29yZGNsb3VkKHdvcmQsIG4sIAogICAgICAgICAgICAgICAgIHNjYWxlID0gZmlnX3NjYWxlLAogICAgICAgICAgICAgICAgIG1pbi5mcmVxID0gbWluX2ZyZXEsCiAgICAgICAgICAgICAgICAgbWF4LndvcmRzID0gbWF4X3dvcmRzKSkKCmBgYAoKCi0tLS0tLS0tLS0tLS0KCiMjIFRhc2sgMTogRGF0YSBFeHBsb3JhdGlvbiAtIFRhYmxlYXUKCi0tLS0tLS0tLS0tLS0KCiMjIyAxQSkgR2VuZXJhbGx5IGRlc2NyaWJlIHRoZSBkYXRhIChzdW1tYXJ5KQpgYGB7cn0KbXlkYXRhID0gcmVhZC5jc3YoIn4vRHJvcGJveC9DYW1lcm9uL2NvbGxlZ2UgMjAxNy0yMDE4L1NlbWVzdGVyIFR3by9CU0FELSBCdXNpbmVzcyBBbmFseXRpY3MvQlNBRCBMYWJzLzA5LW5vdGVib29rLWxhYi9kYXRhL3NlbnRpbWVudF9tYXJjaF9tYWRuZXNzLmNzdiIpCnN1bW1hcnkobXlkYXRhKQpgYGAKVGhpcyBkYXRhc2V0IGlzIGEgY29tcGlsYXRpb24gb2YgdHdlZXRzIHRoYXQgd2VyZXIgY29sbGVjdGVkIGR1cmluZyBNYXJjaCBNYWRuZXNzLiBUaGUgZGF0YXNldCBsb29rcyBhdCB0aGUgbnVtYmVyIG9mIHR3ZWV0cyBhcyB3ZWxsIGFzIHRoZSBudW1iZXIgb2YgZmF2b3JpdGVzLCByZXBsaWVzLCBhbmQgcmV0d2VldHMuIEFkZGl0aW9uYWxseSwgdGhpcyBkYXRhc2V0IGxvb2tzIGF0IHRoZSBkaWZmZXJlbnQgc2VudGltZW50cyBpbmNsdWRlZCBpbiB0aGUgdHdlZXRzLCB3aGljaCByZXNlbWVibGVzIHNvbWUgb2YgdGhlIGZlZWxpbmdzIHBlb3BsZSB3ZXJlIGhhdmluZyB3aGlsZSB0d2VldGluZyBhYm91dCBMb3lvbGEgYW5kIHRoZSBnYW1lcy4gCgojIyMgMUIpIFVzZSB0YWJsZWF1IHRvIGNyZWF0ZSBhdCBsZWFzdCA1IHBsb3RzCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy9zY3JlZW5zaG90MS5wbmciKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy9zY3JlZW5zaG90Mi5wbmciKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy9zY3JlZW5zaG90My5wbmciKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy9zY3JlZW5zaG90NC5wbmciKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy9zY3JlZW5zaG90NS5wbmciKQpgYGAKCiMjIyAxQykgRXhwbGFpbiBlYWNoIHBsb3QgbWFrZSBhIHJlbGF0aW9uIHRvIGRhdGUgb2YgdGhlIHR3ZWV0cy90aW1lClRoZSBmaXJzdCBwbG90IHNob3dzIHRoZSBhY2NvdW50cyB3aXRoIHRoZSBncmVhdGVzdCBudW1iZXIgb2YgcmV0d2VldHMgd2hpbGUgdGhlIHNlY29uZCBwbG90IHNob3dzIHRoZSB0b3AgZml2ZSBhY2NvdW50cyB3aXRoIHRoZSBtb3N0IHR3ZWV0cyBvdmVyYWxsLiBUaGUgdGhpcmQgcGxvdCBzaG93cyB0aGUgbnVtYmVyIG9mIHR3ZWV0cyBwZXIgZGF5LiBUaGUgbGluZSBvbiB0aGlzIHBsb3Qgb2J2aW91c2x5IHBlYWtzIG9uIHRoZSBkYXlzIHRoYXQgdGhlIE1hcmNoIE1hZG5lc3MgZ2FtZXMgd2VyZSBwbGF5ZWQuIFRoZSBmb3VydGggcGxvdCB0aGUgbnVtYmVyIG9mIHR3ZWV0cyBieSBkYXRldGltZSwgYW5kIGFnYWluIHRoZXJlIGlzIGEgcGVhayBkdXJpbmcgdGhlIHRpbWUgaW4gd2hpY2ggdGhlIGdhbWUgd2FzIHBsYXllZC4gRmluYWxseSwgdGhlIGZpZnRoIHBsb3Qgc2hvd3MgdGhlIG51bWJlciBvZiB0d2VldHMgYnkgZGlmZmVyZW50IHNlbnRpbWVudHMuIE92ZXJhbGwsIG1vc3Qgb2YgdGhlIHR3ZWV0cyBoYWQgYSBnb29kIHNlbnRpbWVudCwgd2hldGhlciBpdCB3YXMgcG9zaXRpdmUsIGFudGljaXBhdGlvbiwgb3Igam95LiBUaGVyZSB3ZXJlIGZhciBmZXdlciB0d2VldHMgd2l0aCBhIGJhZCBzZW50aW1lbnQsIHN1Y2ggYXMgYW5nZXIgb3IgZGlzZ3VzdC4gVGhlcmUgYXJlIGFsc28gYSBzaWduaWZpY2FudCBhbW91bnQgb2YgdHdlZXRzIHRoYXQgY29udGFpbmVkIGEgZmVhcmZ1bCBvciBzYWQgc2VudGltZW50LCB3aGljaCBtYWtlcyBzZW5zZSBmb3IgdGhvc2UgZmFucyB0aGF0IHdlcmUgYWZyYWlkIHRoZSB0ZWFtIHdvdWxkIG5vdCB3aW4gYSBnYW1lLCBhbmQgdGhlbiB0aGUgb25lcyB0aGF0IHdlcmUgb2J2aW91c2x5IHNhZCB3aGVuIHRoZSB0ZWFtIGRpZCBsb3NlIGluIHRoZSBGaW5hbCBGb3VyLiAKCi0tLS0tLS0tLS0tLS0KCiMjIFRhc2sgMzogRGF0YSBBbmFseXNpcwoKLS0tLS0tLS0tLS0tLQoKIyMjIDJBKUJhc2VkIG9uIHlvdXIgcGxvdHMgYW5kIGRhdGEgZGVzY3JpcHRpb24gbWFrZSBnaXZlIGEgZ2VuZXJhbCBuYXJyYXRpdmUgZm9yIHRoZSBpbWFnZSBvZiBsb3lvbGEgaW4gdHdpdHRlcgpPdmVyYWxsLCB0aGVyZSB3YXMgYSB2ZXJ5IHBvc2l0aXZlIGltYWdlIG9mIExveW9sYSBvbiB0d2l0dGVyIGR1cmluZyBNYXJjaCBNYWRlc3MuIE1hbnkgb2YgdGhlIHR3ZWV0cyBoYWQgYW4gb3ZlcmFsbCBwb3NpdGl2ZSBzZW50aW1lbnQsIHdoaWNoIG1ha2VzIGl0IGVhc3kgdG8gYXNzdW1lIHRoYXQgdGhlIG1ham9yaXR5IG9mIHBlb3BsZSB0d2VldGluZyBhYm91dCBMb3lvbGEgd2VyZSBzdXBwb3J0aW5nIHRoZSB0ZWFtLiBBZGRpdGlvbmFsbHksIGR1ZSB0byB0aGUgc2hlZXQgbnVtYmVyIG9mIHR3ZWV0cywgaXQgaXMgc2FmZSB0byBzYXkgdGhhdCBMb3lvbGEgaGFkIGEgc2lnbmlmaWNhbnQgcHJlc2VuY2Ugb24gVHdpdHRlciBkdXJpbmcgTWFyY2ggTWFkbmVzcy4gVGhpcyBtYWtlcyBzZW5zZSBiZWNhdXNlIExveW9sYSBkaWQgbWFrZSBpdCBpbnRvIHRoZSBGaW5hbCBGb3VyLCBhbmQgdGhleSB3ZXJlIG9uZSBvZiB0aGUgZmF2b3JpdGUgdGVhbXMgY29uc2lkZXJpbmcgbm9ib2R5IHJlYWxseSBleHBlY3RlZCB0aGVtIHRvIGV2ZW4gYmUgaW4gdGhlIHRvdXJuYW1lbnQsIHNvIG5hdHVyYWxseSBpdCBzZWVtcyBsb2dpY2FsIHRoYXQgdGhlcmUgYXJlIHNvIG1hbnkgdHdlZXRzIGFib3V0IExveW9sYS4gCgojIyMgMkIpIFVzZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHRvIGJhY2t1cCB5b3VyIGFyZ3VtZW50cwpgYGB7cn0Kc3VtbWFyeShteWRhdGEpCmBgYApUaGlzIHNob3dzIHRoYXQgdGhlIG1heGltdW0gdmFsdWUgZm9yIHBvc2l0aXZlIGlzIDksIHdoaWNoIGlzIHRoZSBoaWdoZXN0IGFtb25nIGFsbCBvZiB0aGUgc2VudGltZW50cy4gSm95IGFuZCB0cnVzdCBhcmUgYWxzbyBxdWl0ZSBoaWdoIGF0IDggYW5kIDcgcmVzcGVjdGl2ZWx5LiBTZWVpbmcgdGhhdCB0aGVzZSBhcmUgYWxsIGdvb2Qgc2VudGltZW50cywgaXQgaXMgc2FmZSB0byBzYXkgdGhhdCB0aGVzZSBoZWxwZWQgdG8gY3JlYXRlIGEgcG9zaXRpdmUgaW1hZ2Ugb2YgTG95b2xhIG9uIHR3aXR0ZXIuIAoKIyMjIDJDKUFueSByZWNvbW1lbmRhdGlvbnMgdG8gTG95b2xhJ3MgbWFya2V0aW5nIHRlYW0KSSB3b3VsZCBzYXkgdGhhdCBMb3lvbGEncyBtYXJrZXRpbmcgdGVhbSBzaG91bGQgY29udGludWUgdG8gdXNlIHNvbWUgb2YgdGhlIGhhc2h0YWdzIHRoYXQgd2VyZSBjcmVhdGVkIGluIHJlbGF0aW9uIHRvIExveW9sYSdzIE1hcmNoIE1hZG5lc3MgcnVuLiBGdXJ0aGVybW9yZSwgdGhleSBzaG91bGQgcGljayB0d28gb3IgdGhyZWUgc3BlY2lmaWMgaGFzaHRhZ3MgYW5kIGVuY291cmFnZSBzdHVkZW50cyB0byB1c2UgdGhvc2Ugd2hlbiB0d2VldGluZyBhYm91dCBMb3lvbGEuIFRoaXMgY291bGQgaGVscCBjb25zaWxkYXRlIG1hbnkgb2YgdGhlaXIgbWFya2V0aW5nIGVmZm9ydHMgaW50byBvbmUuIEFsc28sIEkgd291bGQgcmVjb21tZW5kIHRoYXQgdGhlIG1hcmtldGluZyB0ZWFtIHR1cm4gc29tZSBvZiB0aGUgbW9zdCBwb3B1bGFyIHR3ZWV0cyBvciBoYXNodGFncyBpbnRvIGEgbmV3IG1hcmtldGluZyBjYW1wYWlnbiBhbmQgbWFrZSBwcm9tb3Rpb25hbCBtYXRlcmlhbHMgaW5jbGR1aW5nIHRoZW0uIFNpbmNlIG1hbnkgcGVvcGxlIG5vdyBrbm93IExveW9sYSB0aHJvdWdoIHRoZSBiYXNrZXRiYWxsIHByb2dyYW0sIGl0IHdvdWxkIGJlIHdpc2UgdG8gdXNlIHRoZXNlIHR3ZWV0cyB0byBjYXRjaCB0aGUgYXR0ZW50aW9uIG9mIG5vbi1Mb3lvbGEgcGVvcGxlIGFuZCB0aGVuIG9uY2UgdGhleSBoYXZlIHRoZWlyIGF0dGVudGlvbiwgdGhleSBjYW4gc2hhcmUgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGluZ3Mgb3RoZXIgdGhhbiBiYXNrZXRiYWxsIHdpdGggdGhlbS4gCgkKLS0tLS0tLS0tLS0tLQoKIyMgVGFzayAzOiBXYXRzb24gQW5hbHlzaXMKCi0tLS0tLS0tLS0tLS0KCiMjIyAzQSlVc2Ugd2F0c29uIGFuYWx5dGljcyB0byBleHBsb3JlIHRoZSBkYXRhCgojIyMgM0IpR2l2ZSBhdCBsZWFzdCAzIHBsb3RzIG9yIGRpc2NvdmVyaWVzIHVzaW5nIHdhdHNvbi4gRXhwbGFpbiB5b3VyIGZpbmRpbmdzLgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZ3Mvc2NyZWVuc2hvdDYucG5nIikKYGBgClRoaXMgZ3JhcGggZGVwaWN0cyB3aGF0IHRoZSB0b3AgZHJpdmVycyBvZiBqb3kgYXJlLiBBY2NvcmRpbmcgdG8gdGhpcyBncmFwaCwgdGhlIHRvcCBkcml2ZXIgaXMgcG90aXNpdHZlIGFuZCBhbnRpY2lwYXRpb24uIFRoaXMgbWFrZXMgc2Vuc2UgYmVjYXVzZSB0aG9zZSB3aG8gd2VyZSB0d2VldGluZyB3aXRoIGVpdGhlciBvciBib3RoIGEgcG9zdGl0aXZlIG9yIGFudGljaXBhdG9yeSBzZW50aW1lbnQgd291bGQgYWxzbyBoYXZlIGhhZCBhIGpveWZ1bCBzZW50aW1lbnQuIEFsbCBvZiB0aGVzZSBlbW90aW9ucyBzZWVtIHRvIGdvIHRvZ2V0aGVyLCBzbyBpdCBzZWVtcyBhY2N1cmF0ZSB0aGF0IHRoaXMgaXMgdGhlIHRvcCBwcmVkaWN0b3Igb2Ygam95LiAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1ncy9zY3JlZW5zaG90Ny5wbmciKQpgYGAKVGhpcyBncmFwaCBzaG93cyBob3cgdGhlIG51bWJlciBvZiB0d2VldHMgdGhhdCB3ZXJlIGZhdm9yaXRlZCBhbmQgdGhlIG51bWJlciBvZiByZXBsaWVzIGNvbXBhcmUgaW4gcmVsYXRpb24gdG8gdGhlIGRhdGUuIFRoZSB0d28gaGlnaGVzdCBwZWFrcyB3ZXJlIG9uIE1hcmNoIDI4IGFuZCBBcHJpbCAxLCB3aGljaCB3ZXJlIGJvdGggZ2FtZSBkYXlzIGZvciBMb3lvbGEuIFRoaXMgbWFrZXMgY29tcGVsdGUgc2Vuc2UsIGJlY2F1c2UgcGVvcGxlIHdvdWxkIG9idmlvdXNseSBiZSBtb3JlIGxpa2VseSB0byB0d2VldCBlaXRoZXIgZHVyaW5nIHRoZSBnYW1lcyBvciBpbW1lZGlhdGVseSBhZnRlciB0aGV5IHdvbi4gCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZ3Mvc2NyZWVuc2hvdDgucG5nIikKYGBgClRoaXMgd29yZGNsb3VkIGRpc3BsYXlzIHdoYXQgdGhlIG1vc3QgY29tbW9uIGhhc2h0YWdzIHdlcmUgdGhhdCB3ZXJlIHVzZWQgaW4gdGhlIHR3ZWV0cyBmcm9tIHRoZSBkYXRhc2V0LiBUaGUgbW9zdCBwb3B1bGFyIGhhc2h0YWdzIGluY2x1ZGVkICNGaW5hbEZvdXIgYW5kICNMb3lvbGFDaGljYWdvLiBPYnZpb3VzbHksIHRoZSBncmVhdGVzdCBudW1iZXIgb2YgdHdlZXRzIGNhbWUgZHVyaW5nIHRoZSBGaW5hbCBGb3VyIGdhbWUgdGhhdCBMb3lvbGEgcGxheWVkIGluIHNvIGl0IG1ha2VzIHNlbnNlIHRoYXQgI0ZpbmFsRm91ciBpcyBvbmUgb2YgdGhlIG1vc3QgY29tbW9uIGhhc2h0YWdzIGluIGFkZGl0aW9uIHRvICNMb3lvbGFDaGljYWdvLgoK