For this assignment, I have chosen one of the most iconic detective novels, “A Study in Scarlet” by Arthur Conan Doyle. First, I downloaded all the necessary packages to work this assignment as shown below:

knitr::opts_chunk$set(echo = TRUE) 
#library(gutenbergr)
#library(tidyverse)
#library(wordcloud)
#library(stringr)
#library(topicmodels)
#library(data.table)
#library(cleanNLP)
#library(tidytext)
#library(textdata)
#cnlp_init_udpipe()
#I chose all of these packages based on the R Tutorial.

Download and Tidy

Now that I have all my packages ready, I can go ahead and use the gutenberg_download function to download “A Study in Scarlet” into my R Studio and start cleaning it up

(doyle<- gutenberg_download(244))
str(doyle) 
tibble [4,759 × 2] (S3: tbl_df/tbl/data.frame)
 $ gutenberg_id: int [1:4759] 244 244 244 244 244 244 244 244 244 244 ...
 $ text        : chr [1:4759] "A STUDY IN SCARLET." "" "By A. Conan Doyle" "" ...

Looking at the internal structure with the str function, I can see that Doyle’s short story is already in a tibble which is the first step in organizing text data with these packages. However, there is a lot of unecessary infromation at the beginning (such as a Gutenberg disclaimer) that is not relevant for my text analysis. In fact, this information that is not part of the original Doyle manuscript could dkew my data analysis. Therefore, I have picked only the rows that have actual valuable data, which start on row 50.

(doyle.df<-doyle[50:4759,])

My next step is to tokenize the information by making every row one word. I can do this with the unnest_tokens function

(doyle.word <- doyle.df%>%
  unnest_tokens(word, text)) #word is the name of the new column I want to create, and text is the column from which the data came from within the doyle data frame

Just looking at the tibble, it is pretty obvious that there are stop words that can affect my analysis of the text, so I will go ahead and remove those using the tidytext stop words’ dictionary. I will also check for any missing values in order to remove those as well.

(tidy.doyle<- doyle.word %>%
  anti_join(stop_words)) #Used anti_join function so all the words in the data frame stop_words would be removed from the data frame doyle.word
Joining, by = "word"
sum(is.na(tidy.doyle$word)) #Using the sum function, I added all the values within the word column in the data set that exhbited NA.
[1] 0

I finally have my data in a tidy format, with no stop words, missing values, or extra characters. I can go ahead and produce a table of the top 50 words.

Analyzing Top 50 Words

tidy.doyle.wordcounts <-tidy.doyle %>% 
  count(word, sort=T)
head(tidy.doyle.wordcounts, 50)

Analysis: Looking at the top 50 words, it makes sense that Holmes, the main characters’ name, is the most used word in the data. However, I can also see that the word Sherlock, the first name, is also used 50 times but it is taking up space in my word analysis. Here, a bigram would be useful to see how these words interact with one another and which bigrams come out on top. My guess would be that Sherlock Holmes as a bigram is going to come up a lot.

Making a Bigram

(bigrams.doyle <- doyle.df %>% unnest_tokens(output = bigrams, input = text, token = "ngrams", 
    n = 2)) #Same formula to unnest tokens except instead of words I am now tokenizing for ngrams with an n of two 

Taking a quick look at the bigram here, I can see that a lot of the stop words create the same issues that they did before. As per recommended by Dr. Brown, the easiest option is to remove bigrams from the list on which there is a stop word as a first or second word in the bigram set. First, I will separate the words in the bigram, and then I will filter the stop words.

separated.words <- bigrams.doyle %>% separate(bigrams, c("firstword", "secondword"), sep = " ") #I copied this code from Dr. Brown's tutorial. Using the bigrams.doyle created before, I used the separate function to divide the bigram column into two columns named first word and second word and separated by a space. 
(doyle.bigram.final <-separated.words %>%
  filter(!firstword %in% stop_words$word) %>% 
  filter(!secondword %in% stop_words$word)) #Using the new data set called separated.words, I filtered not the first word if the word matches any of the ones in the wor column of stop_words. Then, I added the same thing but for the secondword column
NA
(doyle.diagram.wordcount <-doyle.bigram.final %>% count(firstword, secondword, sort=T)) #Doing the same word counting as I did before for the words, except this one is for the bigram counts. 
write_csv(doyle.diagram.wordcount,"/Users/silvanamontanola/Desktop/Quantitative/Code Files/bigram.csv")

After performing the bigram, I can see that there are 991 NAs on the data set since those are the ones who have the removed stop words. I will go ahead and remove those from the data set, so I can continue analyzing the bigram.

na.omit(doyle.diagram.wordcount) #na.omit is a function that easily allows me to eliminate all the NA's from the data set

Analysis: Analyzing this bigram data set, it is not surprising to see that the most common bigram is Sherlock Holmes, the name of the main character and detective of the story. It is also not uncommon that the name of his companion, John Watson, is not as common since Watson is in fact the narrator of this novel. Other information I would have missed without the bigram is the fact that a lot of the most used word are the names of people and places important to the story. For example, the words baker street are used 6 times, which is the home of Sherlock Holmes and John Watson. Similarly, we have the name of Jefferson Hope used 30 times. This would suggest he is also a main character in this novel. In fact, those who have read it know that he is the main villain.

Analyzing Frequencies per Chapter

Another thing I am interested in looking at is how the frequencies of words differ according to chapter. For example, I imagine that the villain’s name probably does not figure as often in the first chapters as it does in the last. “A Study in Scarlet” is divided into fourteen chapters, so I will subdivide the data by chapter to analyze word frequencies across the subsets.

First, I added an id. number to each word so I could filter for the word “chapter” within the data and figure out the cutoff points of each chapter.

(id.doyle <-doyle.word %>% mutate(ID= rownames(doyle.word)))
id.doyle %>% filter(id.doyle$word=="chapter") #filtered the data and realized that the word chapter actually shows up 15 times instead of 14. 

Since the word chapter shows up more times than intended, I had to manually check the wording of the cutoff points to see which sections are not in fact chapters.

id.doyle[2796:2800,]
id.doyle[6374:6380,]
id.doyle[41524:41530,]
id.doyle[43700:43706,]

As seen above, the last two instances of the word chapter are filler words at the end of the book from project Gutenberg. As such, I have removed those, and will subset the data based on the remaining 13 chapter headers (the first chapter does not have a chapter number, hence why it did not show up on the filtered data)

ch1 <- id.doyle[1:2795,]
ch2<- id.doyle[2796:6373,]
ch3<-id.doyle[6374:10243,]
ch4<- id.doyle[10244:12829,]
ch5<- id.doyle [12830:15370,]
ch6 <- id.doyle[15371:18594,]
ch7<- id.doyle[18595:21942,]
ch8 <- id.doyle[21943:25590,]
ch9 <-id.doyle[25591:28196,]
ch10<- id.doyle[28197:30041,]
ch11<- id.doyle[30042:33444,]
ch12 <-id.doyle[33445:36996,]
ch13 <- id.doyle[36997:41523,]
ch14 <- id.doyle[41523:43700,] #Created each chapter individually in order to analyze the difference in word frequencies 

Individual Word Frequencies per Chapter

Now I will repeat the same procedure that I did with the entire text in terms of frequency and bigram counts. Instead of doing it with all the chapters, I have chosen ch1, ch8, and ch14 as samples.

(tidy.doyle.ch1<- ch1 %>%
  anti_join(stop_words))
Joining, by = "word"
(tidy.doyle.ch8<- ch8 %>%
  anti_join(stop_words))
Joining, by = "word"
(tidy.doyle.ch14<- ch14 %>%
  anti_join(stop_words)) #Removed the stop words from all three of the chapters 
Joining, by = "word"
(wordcounts.ch1 <-tidy.doyle.ch1 %>% 
  count(word, sort=T))
(wordcounts.ch8 <-tidy.doyle.ch8 %>% 
  count(word, sort=T))
(wordcounts.ch14 <-tidy.doyle.ch14 %>% 
  count(word, sort=T)) #Counted the most used words in each chapter

Analysis: Looking at the per chapter comparison from the three samples, there are clear differences between the most used words, with ch1 having “Stamford”, a name, most commonly used, while chapter 8 has a common tangible noun, “eyes”, and chapter 14 has an abstract noun “hope”.

##Bigrams for Chapter Frequencies

Now, I will go ahead and create bigrams for the chapter samples and see how these differ from the entire chapter analysis. First, I need to find where the chapters divide in the bigram since the ID will be different in this table. Then, I can create the bigram chapters, remove the stop words, and then look at the count for the most used bigrams in chapter 1, 8, and 14 respectively.

(separated.words.id <-separated.words %>% mutate(ID= rownames(separated.words))) #added an ID number for each row in the bigram
separated.words.id %>% filter(separated.words.id$firstword=="chapter") #Looked for the chapter starts
ch1.bigram <-separated.words.id[1:2624,]
ch8.bigram <-separated.words.id[20580:23984,]
ch14.bigram <-separated.words.id[38860:40890,] #Created the bigrams for each chapter 
(doyle.bigram.ch1 <-ch1.bigram %>%
  filter(!firstword %in% stop_words$word) %>% 
  filter(!secondword %in% stop_words$word))
(doyle.bigram.ch8 <-ch8.bigram %>%
  filter(!firstword %in% stop_words$word) %>% 
  filter(!secondword %in% stop_words$word))
(doyle.bigram.ch14 <-ch.14bigram %>%
  filter(!firstword %in% stop_words$word) %>% 
  filter(!secondword %in% stop_words$word)) #Removed stop words from each of the three bigrams 
(doyle.diagram.ch1.wordcount <-doyle.bigram.ch1 %>% count(firstword, secondword, sort=T))
(doyle.diagram.ch8.wordcount <-doyle.bigram.ch8 %>% count(firstword, secondword, sort=T))
(doyle.diagram.ch14.wordcount <-doyle.bigram.ch14 %>% count(firstword, secondword, sort=T)) #Sorted the most used words for each of the three bigrams in order to compare them.

Analysis Looking at the bigrams, there are some clear differences between which pair of words is most used as the novel unfolds. The first chapter has most instances of the name Sherlock Holmes. This makes sense since “A Study in Scarlet” is the first instance of the famous detective, so Doyle has to give the background information necessary. Chapter 8 has instances of Sierra Blanco which is the setting of the death in “A Study in Scarlet”. Finally, Chapter 14 has more instances of Sherlock Holmes as the most used bigram along with dead man’s. I can also see how looking and analyzing the code is important since there are instances of bigrams that do not make sense, such as “page 23” which I am assuming is a page number that was accidentally not deleted when the manuscript was uploaded to Project Gutenberg.

#Analyzing Parts of Speech Another type of analysis that can be done on this novel is the study of the parts of speech. I was curious to see, given that this is a detective and adventure narration, if the novel would be action packed. The easiest way to do so is to verify the usage of verbs (action) against adjectives (description). First, I annotated the entire novel with the cnlp_annotate function which takes a little bit of time for R to run. Then, I divided the data frame to get only the tibble that has the actual words and the parts of speech.

#tidy.doyle.annotated <-cnlp_annotate(tidy.doyle$word)
tidy.doyle.annotated.full <- data.frame(tidy.doyle.annotated$token)

Here, I checked to see which parts of speech are included in this book.

unique(tidy.doyle.annotated.full$upos)
 [1] "NUM"   "NOUN"  "VERB"  "INTJ"  "ADV"   "ADJ"   "PART"  "PRON"  "X"     "PROPN" "SYM"   "AUX"   "CCONJ" "ADP"   "DET"  

Then, I conducted a test on the most used verbs as well as the number of verbs used. I did the same thing for the adjectives.

(doyle.verbs<-tidy.doyle.annotated.full %>% filter(upos == "VERB") %>% count(token, sort = T) %>% 
    top_n(100))
Selecting by n
tidy.doyle.annotated.full %>% filter(upos == "VERB") %>% count()
(doyle.adj<- tidy.doyle.annotated.full %>% filter(upos == "ADJ") %>% count(token, sort = T) %>% 
    top_n(100))
Selecting by n
tidy.doyle.annotated.full %>% filter(upos == "ADJ") %>% count()

Analysis: Looking at the counts for the parts of speech, there are more than twice as many verbs as there are adjectives in this novel. This would suggest that action moves the plot forward more than heavy description does. This follows the general formatting of detective novels which tend to be active in narration to propel the action. Looking at the specific verbs used, it seems that “answered” and “found” are the two most used verbs. Given that mystery and thriller requires deduction and analysis of evidence, it would be logical to assume that words that describe those actions are most common. Using this analysis also made it easy for me to realize that most of the novel is written in past participle since the most used verbs are conjugated as such. In regards to the use of adjectives, the most used ones allude to ambiance “dark”, “white”, “silent”, as well as emotion “terrible”. Just looking at the word choice, it is easy to assume that the overall writing style of Arthur Conan Doyle relates to creating an environment of intrigue for the reader.

#Word Frequency Figures

Now is the time to showcase this analysis in a graphical manner. For this, I have chosen to do a word cloud for the most used verbs and adjectives in order to showcase them in a digestible manner. For the comparison between chapters, I have chosen a bar graph. First, I needed to download the wordscloud two to create a colorful version of the world cloud.

#library(wordcloud2)
wordcloud.adj<-wordcloud2(doyle.adj)
wordcloud.verbs<-wordcloud2(doyle.verbs)
wordcloud.adj
wordcloud.verbs

This word cloud visually show what the analysis above stated. Now I will do the bar graphs for the word frequencies in the chapters.

ch1plot <- wordcounts.ch1 %>% top_n(20) %>%
    mutate(word = reorder(word, n)) %>% ggplot(aes(x = word, y = n)) + geom_col(fill="#FF2400") + 
    xlab(NULL) + coord_flip() + labs(y = "Count", x = "Most Used Words")
Selecting by n
ch8plot <- wordcounts.ch8 %>% top_n(20) %>%
    mutate(word = reorder(word, n)) %>% ggplot(aes(x = word, y = n)) + geom_col(fill="#660e00") + 
    xlab(NULL) + coord_flip() + labs(y = "Count", x = "Most Used Words")
Selecting by n
ch14plot <- wordcounts.ch14 %>% top_n(20) %>%
    mutate(word = reorder(word, n)) %>% ggplot(aes(x = word, y = n)) + geom_col(fill="#330700") + 
    xlab(NULL) + coord_flip() + labs(y = "Count", x = "Most Used Words")
Selecting by n
combinedplots<- ggarrange(ch1plot, ch8plot, ch14plot, ncol=3, nrow=1)
(finalplots<-annotate_figure(combinedplots, bottom = "Figure 1: Most used words in Chapter 1, 8, and 14, respectively", top= "A Study in Scarlet"))

#Sentiment Analysis

The final part of this problem set was focusing on sentiment analysis. In order to do that, I decided to also use the NRC Emotion Lexicon because I was curious to see how the lexicon used by Conan Doyle relates to “negative” emotions (fear, sadness, anger).

#get_sentiments("nrc")
(sentiment.doyle<- tidy.doyle %>% inner_join(get_sentiments("nrc")))
Joining, by = "word"
(fear.doyle <-sentiment.doyle %>% filter(sentiment == "fear") %>% count(word, sort = T))
(negative.doyle <-sentiment.doyle  %>% filter(sentiment == "negative") %>% count(word, sort = T))
(surprise.doyle<-sentiment.doyle %>% filter(sentiment == "surprise") %>% count(word, sort = T))
(positive.doyle <- sentiment.doyle %>% filter(sentiment == "positive") %>% count(word, sort = T))
NA
(fearplot <- fear.doyle %>% top_n(20) %>%
    mutate(word = reorder(word, n)) %>% ggplot(aes(x = word, y = n)) + geom_col(fill="#03AC13") + 
    xlab(NULL) + coord_flip() + labs(y = "Count", x = "Words Associated to Fear", title = "A Study In Scarlet: Sentiment Analysis of Fear"))
Selecting by n

(surpriseplot <- surprise.doyle %>% top_n(20) %>%
    mutate(word = reorder(word, n)) %>% ggplot(aes(x = word, y = n)) + geom_col(fill="#32612D") + 
    xlab(NULL) + coord_flip() + labs(y = "Count", x = "Words Associated to Surprise", title = "A Study In Scarlet: Sentiment Analysis of Surprise"))
Selecting by n

positiveplot<-positive.doyle %>% top_n(20) %>%
    mutate(word = reorder(word, n)) %>% ggplot(aes(x = word, y = n)) + geom_col(fill="#1338BE") + 
    xlab(NULL) + coord_flip() + labs(y = "Count", x = "Positive Words")
Selecting by n
negativeplot<-negative.doyle %>% top_n(20) %>%
    mutate(word = reorder(word, n)) %>% ggplot(aes(x = word, y = n)) + geom_col(fill="#541E1B") + 
    xlab(NULL) + coord_flip() + labs(y = "Count", x = "Negative Words")
Selecting by n
combinedplots2<- ggarrange(positiveplot, negativeplot, ncol=2, nrow=1)
(finalplots2<-annotate_figure(combinedplots2, bottom = "Figure 4: Comparison of positive and negative words across A Study In Scarlet", top= "Sentiment Analysis: A Study in Scarlet"))

LS0tCnRpdGxlOiAiUHJvYmxlbSBTZXQgMTEgLVNpbHZhbmEgTW9udGFub2xhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpGb3IgdGhpcyBhc3NpZ25tZW50LCBJIGhhdmUgY2hvc2VuIG9uZSBvZiB0aGUgbW9zdCBpY29uaWMgZGV0ZWN0aXZlIG5vdmVscywgIkEgU3R1ZHkgaW4gU2NhcmxldCIgYnkgQXJ0aHVyIENvbmFuIERveWxlLiBGaXJzdCwgSSBkb3dubG9hZGVkIGFsbCB0aGUgbmVjZXNzYXJ5IHBhY2thZ2VzIHRvIHdvcmsgdGhpcyBhc3NpZ25tZW50IGFzIHNob3duIGJlbG93OiAKCmBgYHtyfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpIAojbGlicmFyeShndXRlbmJlcmdyKQojbGlicmFyeSh0aWR5dmVyc2UpCiNsaWJyYXJ5KHdvcmRjbG91ZCkKI2xpYnJhcnkoc3RyaW5ncikKI2xpYnJhcnkodG9waWNtb2RlbHMpCiNsaWJyYXJ5KGRhdGEudGFibGUpCiNsaWJyYXJ5KGNsZWFuTkxQKQojbGlicmFyeSh0aWR5dGV4dCkKI2xpYnJhcnkodGV4dGRhdGEpCiNjbmxwX2luaXRfdWRwaXBlKCkKI0kgY2hvc2UgYWxsIG9mIHRoZXNlIHBhY2thZ2VzIGJhc2VkIG9uIHRoZSBSIFR1dG9yaWFsLgpgYGAKCiMgRG93bmxvYWQgYW5kIFRpZHkgCk5vdyB0aGF0IEkgaGF2ZSBhbGwgbXkgcGFja2FnZXMgcmVhZHksIEkgY2FuIGdvIGFoZWFkIGFuZCB1c2UgdGhlIGd1dGVuYmVyZ19kb3dubG9hZCBmdW5jdGlvbiB0byBkb3dubG9hZCAiQSBTdHVkeSBpbiBTY2FybGV0IiBpbnRvIG15IFIgU3R1ZGlvIGFuZCBzdGFydCBjbGVhbmluZyBpdCB1cCAKYGBge3J9Cihkb3lsZTwtIGd1dGVuYmVyZ19kb3dubG9hZCgyNDQpKQpgYGAKYGBge3J9CnN0cihkb3lsZSkgCmBgYAoKTG9va2luZyBhdCB0aGUgaW50ZXJuYWwgc3RydWN0dXJlIHdpdGggdGhlIHN0ciBmdW5jdGlvbiwgSSBjYW4gc2VlIHRoYXQgRG95bGUncyBzaG9ydCBzdG9yeSBpcyBhbHJlYWR5IGluIGEgdGliYmxlIHdoaWNoIGlzIHRoZSBmaXJzdCBzdGVwIGluIG9yZ2FuaXppbmcgdGV4dCBkYXRhIHdpdGggdGhlc2UgcGFja2FnZXMuIEhvd2V2ZXIsIHRoZXJlIGlzIGEgbG90IG9mIHVuZWNlc3NhcnkgaW5mcm9tYXRpb24gYXQgdGhlIGJlZ2lubmluZyAoc3VjaCBhcyBhIEd1dGVuYmVyZyBkaXNjbGFpbWVyKSB0aGF0IGlzIG5vdCByZWxldmFudCBmb3IgbXkgdGV4dCBhbmFseXNpcy4gSW4gZmFjdCwgdGhpcyBpbmZvcm1hdGlvbiB0aGF0IGlzIG5vdCBwYXJ0IG9mIHRoZSBvcmlnaW5hbCBEb3lsZSBtYW51c2NyaXB0IGNvdWxkIGRrZXcgbXkgZGF0YSBhbmFseXNpcy4gVGhlcmVmb3JlLCBJIGhhdmUgcGlja2VkIG9ubHkgdGhlIHJvd3MgdGhhdCBoYXZlIGFjdHVhbCB2YWx1YWJsZSBkYXRhLCB3aGljaCBzdGFydCBvbiByb3cgNTAuIAoKYGBge3J9Cihkb3lsZS5kZjwtZG95bGVbNTA6NDc1OSxdKQpgYGAKTXkgbmV4dCBzdGVwIGlzIHRvIHRva2VuaXplIHRoZSBpbmZvcm1hdGlvbiBieSBtYWtpbmcgZXZlcnkgcm93IG9uZSB3b3JkLiBJIGNhbiBkbyB0aGlzIHdpdGggdGhlIHVubmVzdF90b2tlbnMgZnVuY3Rpb24KYGBge3J9Cihkb3lsZS53b3JkIDwtIGRveWxlLmRmJT4lCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB0ZXh0KSkgI3dvcmQgaXMgdGhlIG5hbWUgb2YgdGhlIG5ldyBjb2x1bW4gSSB3YW50IHRvIGNyZWF0ZSwgYW5kIHRleHQgaXMgdGhlIGNvbHVtbiBmcm9tIHdoaWNoIHRoZSBkYXRhIGNhbWUgZnJvbSB3aXRoaW4gdGhlIGRveWxlIGRhdGEgZnJhbWUKYGBgCkp1c3QgbG9va2luZyBhdCB0aGUgdGliYmxlLCBpdCBpcyBwcmV0dHkgb2J2aW91cyB0aGF0IHRoZXJlIGFyZSBzdG9wIHdvcmRzIHRoYXQgY2FuIGFmZmVjdCBteSBhbmFseXNpcyBvZiB0aGUgdGV4dCwgc28gSSB3aWxsIGdvIGFoZWFkIGFuZCByZW1vdmUgdGhvc2UgdXNpbmcgdGhlIHRpZHl0ZXh0IHN0b3Agd29yZHMnIGRpY3Rpb25hcnkuIEkgd2lsbCBhbHNvIGNoZWNrIGZvciBhbnkgbWlzc2luZyB2YWx1ZXMgaW4gb3JkZXIgdG8gcmVtb3ZlIHRob3NlIGFzIHdlbGwuIAoKYGBge3J9Cih0aWR5LmRveWxlPC0gZG95bGUud29yZCAlPiUKICBhbnRpX2pvaW4oc3RvcF93b3JkcykpICNVc2VkIGFudGlfam9pbiBmdW5jdGlvbiBzbyBhbGwgdGhlIHdvcmRzIGluIHRoZSBkYXRhIGZyYW1lIHN0b3Bfd29yZHMgd291bGQgYmUgcmVtb3ZlZCBmcm9tIHRoZSBkYXRhIGZyYW1lIGRveWxlLndvcmQKYGBgCmBgYHtyfQpzdW0oaXMubmEodGlkeS5kb3lsZSR3b3JkKSkgI1VzaW5nIHRoZSBzdW0gZnVuY3Rpb24sIEkgYWRkZWQgYWxsIHRoZSB2YWx1ZXMgd2l0aGluIHRoZSB3b3JkIGNvbHVtbiBpbiB0aGUgZGF0YSBzZXQgdGhhdCBleGhiaXRlZCBOQS4KYGBgCgpJIGZpbmFsbHkgaGF2ZSBteSBkYXRhIGluIGEgdGlkeSBmb3JtYXQsIHdpdGggbm8gc3RvcCB3b3JkcywgbWlzc2luZyB2YWx1ZXMsIG9yIGV4dHJhIGNoYXJhY3RlcnMuIEkgY2FuIGdvIGFoZWFkIGFuZCBwcm9kdWNlIGEgdGFibGUgb2YgdGhlIHRvcCA1MCB3b3Jkcy4gCgojIEFuYWx5emluZyBUb3AgNTAgV29yZHMKCmBgYHtyfQp0aWR5LmRveWxlLndvcmRjb3VudHMgPC10aWR5LmRveWxlICU+JSAKICBjb3VudCh3b3JkLCBzb3J0PVQpCmhlYWQodGlkeS5kb3lsZS53b3JkY291bnRzLCA1MCkKYGBgCgoqKkFuYWx5c2lzOioqIExvb2tpbmcgYXQgdGhlIHRvcCA1MCB3b3JkcywgaXQgbWFrZXMgc2Vuc2UgdGhhdCBIb2xtZXMsIHRoZSBtYWluIGNoYXJhY3RlcnMnIG5hbWUsIGlzIHRoZSBtb3N0IHVzZWQgd29yZCBpbiB0aGUgZGF0YS4gSG93ZXZlciwgSSBjYW4gYWxzbyBzZWUgdGhhdCB0aGUgd29yZCBTaGVybG9jaywgdGhlIGZpcnN0IG5hbWUsIGlzIGFsc28gdXNlZCA1MCB0aW1lcyBidXQgaXQgaXMgdGFraW5nIHVwIHNwYWNlIGluIG15IHdvcmQgYW5hbHlzaXMuIEhlcmUsIGEgYmlncmFtIHdvdWxkIGJlIHVzZWZ1bCB0byBzZWUgaG93IHRoZXNlIHdvcmRzIGludGVyYWN0IHdpdGggb25lIGFub3RoZXIgYW5kIHdoaWNoIGJpZ3JhbXMgY29tZSBvdXQgb24gdG9wLiBNeSBndWVzcyB3b3VsZCBiZSB0aGF0IFNoZXJsb2NrIEhvbG1lcyBhcyBhIGJpZ3JhbSBpcyBnb2luZyB0byBjb21lIHVwIGEgbG90LiAKCiMgTWFraW5nIGEgQmlncmFtIAoKYGBge3J9CihiaWdyYW1zLmRveWxlIDwtIGRveWxlLmRmICU+JSB1bm5lc3RfdG9rZW5zKG91dHB1dCA9IGJpZ3JhbXMsIGlucHV0ID0gdGV4dCwgdG9rZW4gPSAibmdyYW1zIiwgCiAgICBuID0gMikpICNTYW1lIGZvcm11bGEgdG8gdW5uZXN0IHRva2VucyBleGNlcHQgaW5zdGVhZCBvZiB3b3JkcyBJIGFtIG5vdyB0b2tlbml6aW5nIGZvciBuZ3JhbXMgd2l0aCBhbiBuIG9mIHR3byAKYGBgClRha2luZyBhIHF1aWNrIGxvb2sgYXQgdGhlIGJpZ3JhbSBoZXJlLCBJIGNhbiBzZWUgdGhhdCBhIGxvdCBvZiB0aGUgc3RvcCB3b3JkcyBjcmVhdGUgdGhlIHNhbWUgaXNzdWVzIHRoYXQgdGhleSBkaWQgYmVmb3JlLiBBcyBwZXIgcmVjb21tZW5kZWQgYnkgRHIuIEJyb3duLCB0aGUgZWFzaWVzdCBvcHRpb24gaXMgdG8gcmVtb3ZlIGJpZ3JhbXMgZnJvbSB0aGUgbGlzdCBvbiB3aGljaCB0aGVyZSBpcyBhIHN0b3Agd29yZCBhcyBhIGZpcnN0IG9yIHNlY29uZCB3b3JkIGluIHRoZSBiaWdyYW0gc2V0LiBGaXJzdCwgSSB3aWxsIHNlcGFyYXRlIHRoZSB3b3JkcyBpbiB0aGUgYmlncmFtLCBhbmQgdGhlbiBJIHdpbGwgZmlsdGVyIHRoZSBzdG9wIHdvcmRzLiAKCmBgYHtyfQpzZXBhcmF0ZWQud29yZHMgPC0gYmlncmFtcy5kb3lsZSAlPiUgc2VwYXJhdGUoYmlncmFtcywgYygiZmlyc3R3b3JkIiwgInNlY29uZHdvcmQiKSwgc2VwID0gIiAiKSAjSSBjb3BpZWQgdGhpcyBjb2RlIGZyb20gRHIuIEJyb3duJ3MgdHV0b3JpYWwuIFVzaW5nIHRoZSBiaWdyYW1zLmRveWxlIGNyZWF0ZWQgYmVmb3JlLCBJIHVzZWQgdGhlIHNlcGFyYXRlIGZ1bmN0aW9uIHRvIGRpdmlkZSB0aGUgYmlncmFtIGNvbHVtbiBpbnRvIHR3byBjb2x1bW5zIG5hbWVkIGZpcnN0IHdvcmQgYW5kIHNlY29uZCB3b3JkIGFuZCBzZXBhcmF0ZWQgYnkgYSBzcGFjZS4gCihkb3lsZS5iaWdyYW0uZmluYWwgPC1zZXBhcmF0ZWQud29yZHMgJT4lCiAgZmlsdGVyKCFmaXJzdHdvcmQgJWluJSBzdG9wX3dvcmRzJHdvcmQpICU+JSAKICBmaWx0ZXIoIXNlY29uZHdvcmQgJWluJSBzdG9wX3dvcmRzJHdvcmQpKSAjVXNpbmcgdGhlIG5ldyBkYXRhIHNldCBjYWxsZWQgc2VwYXJhdGVkLndvcmRzLCBJIGZpbHRlcmVkIG5vdCB0aGUgZmlyc3Qgd29yZCBpZiB0aGUgd29yZCBtYXRjaGVzIGFueSBvZiB0aGUgb25lcyBpbiB0aGUgd29yIGNvbHVtbiBvZiBzdG9wX3dvcmRzLiBUaGVuLCBJIGFkZGVkIHRoZSBzYW1lIHRoaW5nIGJ1dCBmb3IgdGhlIHNlY29uZHdvcmQgY29sdW1uCgpgYGAKCmBgYHtyfQooZG95bGUuZGlhZ3JhbS53b3JkY291bnQgPC1kb3lsZS5iaWdyYW0uZmluYWwgJT4lIGNvdW50KGZpcnN0d29yZCwgc2Vjb25kd29yZCwgc29ydD1UKSkgI0RvaW5nIHRoZSBzYW1lIHdvcmQgY291bnRpbmcgYXMgSSBkaWQgYmVmb3JlIGZvciB0aGUgd29yZHMsIGV4Y2VwdCB0aGlzIG9uZSBpcyBmb3IgdGhlIGJpZ3JhbSBjb3VudHMuIAp3cml0ZV9jc3YoZG95bGUuZGlhZ3JhbS53b3JkY291bnQsIi9Vc2Vycy9zaWx2YW5hbW9udGFub2xhL0Rlc2t0b3AvUXVhbnRpdGF0aXZlL0NvZGUgRmlsZXMvYmlncmFtLmNzdiIpCmBgYAoKQWZ0ZXIgcGVyZm9ybWluZyB0aGUgYmlncmFtLCBJIGNhbiBzZWUgdGhhdCB0aGVyZSBhcmUgOTkxIE5BcyBvbiB0aGUgZGF0YSBzZXQgc2luY2UgdGhvc2UgYXJlIHRoZSBvbmVzIHdobyBoYXZlIHRoZSByZW1vdmVkIHN0b3Agd29yZHMuIEkgd2lsbCBnbyBhaGVhZCBhbmQgcmVtb3ZlIHRob3NlIGZyb20gdGhlIGRhdGEgc2V0LCBzbyBJIGNhbiBjb250aW51ZSBhbmFseXppbmcgdGhlIGJpZ3JhbS4gCgpgYGB7cn0KbmEub21pdChkb3lsZS5kaWFncmFtLndvcmRjb3VudCkgI25hLm9taXQgaXMgYSBmdW5jdGlvbiB0aGF0IGVhc2lseSBhbGxvd3MgbWUgdG8gZWxpbWluYXRlIGFsbCB0aGUgTkEncyBmcm9tIHRoZSBkYXRhIHNldApgYGAKKipBbmFseXNpczoqKiBBbmFseXppbmcgdGhpcyBiaWdyYW0gZGF0YSBzZXQsIGl0IGlzIG5vdCBzdXJwcmlzaW5nIHRvIHNlZSB0aGF0IHRoZSBtb3N0IGNvbW1vbiBiaWdyYW0gaXMgU2hlcmxvY2sgSG9sbWVzLCB0aGUgbmFtZSBvZiB0aGUgbWFpbiBjaGFyYWN0ZXIgYW5kIGRldGVjdGl2ZSBvZiB0aGUgc3RvcnkuIEl0IGlzIGFsc28gbm90IHVuY29tbW9uIHRoYXQgdGhlIG5hbWUgb2YgaGlzIGNvbXBhbmlvbiwgSm9obiBXYXRzb24sIGlzIG5vdCBhcyBjb21tb24gc2luY2UgV2F0c29uIGlzIGluIGZhY3QgdGhlIG5hcnJhdG9yIG9mIHRoaXMgbm92ZWwuIE90aGVyIGluZm9ybWF0aW9uIEkgd291bGQgaGF2ZSBtaXNzZWQgd2l0aG91dCB0aGUgYmlncmFtIGlzIHRoZSBmYWN0IHRoYXQgYSBsb3Qgb2YgdGhlIG1vc3QgdXNlZCB3b3JkIGFyZSB0aGUgbmFtZXMgb2YgcGVvcGxlIGFuZCBwbGFjZXMgaW1wb3J0YW50IHRvIHRoZSBzdG9yeS4gRm9yIGV4YW1wbGUsIHRoZSB3b3JkcyBiYWtlciBzdHJlZXQgYXJlIHVzZWQgNiB0aW1lcywgd2hpY2ggaXMgdGhlIGhvbWUgb2YgU2hlcmxvY2sgSG9sbWVzIGFuZCBKb2huIFdhdHNvbi4gU2ltaWxhcmx5LCB3ZSBoYXZlIHRoZSBuYW1lIG9mIEplZmZlcnNvbiBIb3BlIHVzZWQgMzAgdGltZXMuIFRoaXMgd291bGQgc3VnZ2VzdCBoZSBpcyBhbHNvIGEgbWFpbiBjaGFyYWN0ZXIgaW4gdGhpcyBub3ZlbC4gSW4gZmFjdCwgdGhvc2Ugd2hvIGhhdmUgcmVhZCBpdCBrbm93IHRoYXQgaGUgaXMgdGhlIG1haW4gdmlsbGFpbi4gCgojIEFuYWx5emluZyBGcmVxdWVuY2llcyBwZXIgQ2hhcHRlcgoKQW5vdGhlciB0aGluZyBJIGFtIGludGVyZXN0ZWQgaW4gbG9va2luZyBhdCBpcyBob3cgdGhlIGZyZXF1ZW5jaWVzIG9mIHdvcmRzIGRpZmZlciBhY2NvcmRpbmcgdG8gY2hhcHRlci4gRm9yIGV4YW1wbGUsIEkgaW1hZ2luZSB0aGF0IHRoZSB2aWxsYWluJ3MgbmFtZSBwcm9iYWJseSBkb2VzIG5vdCBmaWd1cmUgYXMgb2Z0ZW4gaW4gdGhlIGZpcnN0IGNoYXB0ZXJzIGFzIGl0IGRvZXMgaW4gdGhlIGxhc3QuICJBIFN0dWR5IGluIFNjYXJsZXQiIGlzIGRpdmlkZWQgaW50byBmb3VydGVlbiBjaGFwdGVycywgc28gSSB3aWxsIHN1YmRpdmlkZSB0aGUgZGF0YSBieSBjaGFwdGVyIHRvIGFuYWx5emUgd29yZCBmcmVxdWVuY2llcyBhY3Jvc3MgdGhlIHN1YnNldHMuIAoKRmlyc3QsIEkgYWRkZWQgYW4gaWQuIG51bWJlciB0byBlYWNoIHdvcmQgc28gSSBjb3VsZCBmaWx0ZXIgZm9yIHRoZSB3b3JkICJjaGFwdGVyIiB3aXRoaW4gdGhlIGRhdGEgYW5kIGZpZ3VyZSBvdXQgdGhlIGN1dG9mZiBwb2ludHMgb2YgZWFjaCBjaGFwdGVyLiAKYGBge3J9CihpZC5kb3lsZSA8LWRveWxlLndvcmQgJT4lIG11dGF0ZShJRD0gcm93bmFtZXMoZG95bGUud29yZCkpKQpgYGAKYGBge3J9CmlkLmRveWxlICU+JSBmaWx0ZXIoaWQuZG95bGUkd29yZD09ImNoYXB0ZXIiKSAjZmlsdGVyZWQgdGhlIGRhdGEgYW5kIHJlYWxpemVkIHRoYXQgdGhlIHdvcmQgY2hhcHRlciBhY3R1YWxseSBzaG93cyB1cCAxNSB0aW1lcyBpbnN0ZWFkIG9mIDE0LiAKYGBgCgpTaW5jZSB0aGUgd29yZCBjaGFwdGVyIHNob3dzIHVwIG1vcmUgdGltZXMgdGhhbiBpbnRlbmRlZCwgSSBoYWQgdG8gbWFudWFsbHkgY2hlY2sgdGhlIHdvcmRpbmcgb2YgdGhlIGN1dG9mZiBwb2ludHMgdG8gc2VlIHdoaWNoIHNlY3Rpb25zIGFyZSBub3QgaW4gZmFjdCBjaGFwdGVycy4gCgpgYGB7cn0KaWQuZG95bGVbMjc5NjoyODAwLF0KaWQuZG95bGVbNjM3NDo2MzgwLF0KaWQuZG95bGVbNDE1MjQ6NDE1MzAsXQppZC5kb3lsZVs0MzcwMDo0MzcwNixdCmBgYApBcyBzZWVuIGFib3ZlLCB0aGUgbGFzdCB0d28gaW5zdGFuY2VzIG9mIHRoZSB3b3JkIGNoYXB0ZXIgYXJlIGZpbGxlciB3b3JkcyBhdCB0aGUgZW5kIG9mIHRoZSBib29rIGZyb20gcHJvamVjdCBHdXRlbmJlcmcuIEFzIHN1Y2gsIEkgaGF2ZSByZW1vdmVkIHRob3NlLCBhbmQgd2lsbCBzdWJzZXQgdGhlIGRhdGEgYmFzZWQgb24gdGhlIHJlbWFpbmluZyAxMyBjaGFwdGVyIGhlYWRlcnMgKHRoZSBmaXJzdCBjaGFwdGVyIGRvZXMgbm90IGhhdmUgYSBjaGFwdGVyIG51bWJlciwgaGVuY2Ugd2h5IGl0IGRpZCBub3Qgc2hvdyB1cCBvbiB0aGUgZmlsdGVyZWQgZGF0YSkKCmBgYHtyfQpjaDEgPC0gaWQuZG95bGVbMToyNzk1LF0KY2gyPC0gaWQuZG95bGVbMjc5Njo2MzczLF0KY2gzPC1pZC5kb3lsZVs2Mzc0OjEwMjQzLF0KY2g0PC0gaWQuZG95bGVbMTAyNDQ6MTI4MjksXQpjaDU8LSBpZC5kb3lsZSBbMTI4MzA6MTUzNzAsXQpjaDYgPC0gaWQuZG95bGVbMTUzNzE6MTg1OTQsXQpjaDc8LSBpZC5kb3lsZVsxODU5NToyMTk0MixdCmNoOCA8LSBpZC5kb3lsZVsyMTk0MzoyNTU5MCxdCmNoOSA8LWlkLmRveWxlWzI1NTkxOjI4MTk2LF0KY2gxMDwtIGlkLmRveWxlWzI4MTk3OjMwMDQxLF0KY2gxMTwtIGlkLmRveWxlWzMwMDQyOjMzNDQ0LF0KY2gxMiA8LWlkLmRveWxlWzMzNDQ1OjM2OTk2LF0KY2gxMyA8LSBpZC5kb3lsZVszNjk5Nzo0MTUyMyxdCmNoMTQgPC0gaWQuZG95bGVbNDE1MjM6NDM3MDAsXSAjQ3JlYXRlZCBlYWNoIGNoYXB0ZXIgaW5kaXZpZHVhbGx5IGluIG9yZGVyIHRvIGFuYWx5emUgdGhlIGRpZmZlcmVuY2UgaW4gd29yZCBmcmVxdWVuY2llcyAKYGBgCgojIyBJbmRpdmlkdWFsIFdvcmQgRnJlcXVlbmNpZXMgcGVyIENoYXB0ZXIKTm93IEkgd2lsbCByZXBlYXQgdGhlIHNhbWUgcHJvY2VkdXJlIHRoYXQgSSBkaWQgd2l0aCB0aGUgZW50aXJlIHRleHQgaW4gdGVybXMgb2YgZnJlcXVlbmN5IGFuZCBiaWdyYW0gY291bnRzLiBJbnN0ZWFkIG9mIGRvaW5nIGl0IHdpdGggYWxsIHRoZSBjaGFwdGVycywgSSBoYXZlIGNob3NlbiBjaDEsIGNoOCwgYW5kIGNoMTQgYXMgc2FtcGxlcy4gCgpgYGB7cn0KKHRpZHkuZG95bGUuY2gxPC0gY2gxICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzKSkKKHRpZHkuZG95bGUuY2g4PC0gY2g4ICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzKSkKKHRpZHkuZG95bGUuY2gxNDwtIGNoMTQgJT4lCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpKSAjUmVtb3ZlZCB0aGUgc3RvcCB3b3JkcyBmcm9tIGFsbCB0aHJlZSBvZiB0aGUgY2hhcHRlcnMgCmBgYAoKYGBge3J9Cih3b3JkY291bnRzLmNoMSA8LXRpZHkuZG95bGUuY2gxICU+JSAKICBjb3VudCh3b3JkLCBzb3J0PVQpKQood29yZGNvdW50cy5jaDggPC10aWR5LmRveWxlLmNoOCAlPiUgCiAgY291bnQod29yZCwgc29ydD1UKSkKKHdvcmRjb3VudHMuY2gxNCA8LXRpZHkuZG95bGUuY2gxNCAlPiUgCiAgY291bnQod29yZCwgc29ydD1UKSkgI0NvdW50ZWQgdGhlIG1vc3QgdXNlZCB3b3JkcyBpbiBlYWNoIGNoYXB0ZXIKYGBgCioqQW5hbHlzaXM6KiogTG9va2luZyBhdCB0aGUgcGVyIGNoYXB0ZXIgY29tcGFyaXNvbiBmcm9tIHRoZSB0aHJlZSBzYW1wbGVzLCB0aGVyZSBhcmUgY2xlYXIgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgbW9zdCB1c2VkIHdvcmRzLCB3aXRoIGNoMSBoYXZpbmcgIlN0YW1mb3JkIiwgYSBuYW1lLCBtb3N0IGNvbW1vbmx5IHVzZWQsIHdoaWxlIGNoYXB0ZXIgOCBoYXMgYSBjb21tb24gdGFuZ2libGUgbm91biwgImV5ZXMiLCBhbmQgY2hhcHRlciAxNCBoYXMgYW4gYWJzdHJhY3Qgbm91biAiaG9wZSIuIAoKIyNCaWdyYW1zIGZvciBDaGFwdGVyIEZyZXF1ZW5jaWVzCgpOb3csIEkgd2lsbCBnbyBhaGVhZCBhbmQgY3JlYXRlIGJpZ3JhbXMgZm9yIHRoZSBjaGFwdGVyIHNhbXBsZXMgYW5kIHNlZSBob3cgdGhlc2UgZGlmZmVyIGZyb20gdGhlIGVudGlyZSBjaGFwdGVyIGFuYWx5c2lzLiBGaXJzdCwgSSBuZWVkIHRvIGZpbmQgd2hlcmUgdGhlIGNoYXB0ZXJzIGRpdmlkZSBpbiB0aGUgYmlncmFtIHNpbmNlIHRoZSBJRCB3aWxsIGJlIGRpZmZlcmVudCBpbiB0aGlzIHRhYmxlLiBUaGVuLCBJIGNhbiBjcmVhdGUgdGhlIGJpZ3JhbSBjaGFwdGVycywgcmVtb3ZlIHRoZSBzdG9wIHdvcmRzLCBhbmQgdGhlbiBsb29rIGF0IHRoZSBjb3VudCBmb3IgdGhlIG1vc3QgdXNlZCBiaWdyYW1zIGluIGNoYXB0ZXIgMSwgOCwgYW5kIDE0IHJlc3BlY3RpdmVseS4gCgpgYGB7cn0KKHNlcGFyYXRlZC53b3Jkcy5pZCA8LXNlcGFyYXRlZC53b3JkcyAlPiUgbXV0YXRlKElEPSByb3duYW1lcyhzZXBhcmF0ZWQud29yZHMpKSkgI2FkZGVkIGFuIElEIG51bWJlciBmb3IgZWFjaCByb3cgaW4gdGhlIGJpZ3JhbQpzZXBhcmF0ZWQud29yZHMuaWQgJT4lIGZpbHRlcihzZXBhcmF0ZWQud29yZHMuaWQkZmlyc3R3b3JkPT0iY2hhcHRlciIpICNMb29rZWQgZm9yIHRoZSBjaGFwdGVyIHN0YXJ0cwpgYGAKCmBgYHtyfQpjaDEuYmlncmFtIDwtc2VwYXJhdGVkLndvcmRzLmlkWzE6MjYyNCxdCmNoOC5iaWdyYW0gPC1zZXBhcmF0ZWQud29yZHMuaWRbMjA1ODA6MjM5ODQsXQpjaDE0LmJpZ3JhbSA8LXNlcGFyYXRlZC53b3Jkcy5pZFszODg2MDo0MDg5MCxdICNDcmVhdGVkIHRoZSBiaWdyYW1zIGZvciBlYWNoIGNoYXB0ZXIgCmBgYAoKYGBge3J9Cihkb3lsZS5iaWdyYW0uY2gxIDwtY2gxLmJpZ3JhbSAlPiUKICBmaWx0ZXIoIWZpcnN0d29yZCAlaW4lIHN0b3Bfd29yZHMkd29yZCkgJT4lIAogIGZpbHRlcighc2Vjb25kd29yZCAlaW4lIHN0b3Bfd29yZHMkd29yZCkpCihkb3lsZS5iaWdyYW0uY2g4IDwtY2g4LmJpZ3JhbSAlPiUKICBmaWx0ZXIoIWZpcnN0d29yZCAlaW4lIHN0b3Bfd29yZHMkd29yZCkgJT4lIAogIGZpbHRlcighc2Vjb25kd29yZCAlaW4lIHN0b3Bfd29yZHMkd29yZCkpCihkb3lsZS5iaWdyYW0uY2gxNCA8LWNoLjE0YmlncmFtICU+JQogIGZpbHRlcighZmlyc3R3b3JkICVpbiUgc3RvcF93b3JkcyR3b3JkKSAlPiUgCiAgZmlsdGVyKCFzZWNvbmR3b3JkICVpbiUgc3RvcF93b3JkcyR3b3JkKSkgI1JlbW92ZWQgc3RvcCB3b3JkcyBmcm9tIGVhY2ggb2YgdGhlIHRocmVlIGJpZ3JhbXMgCmBgYAoKYGBge3J9Cihkb3lsZS5kaWFncmFtLmNoMS53b3JkY291bnQgPC1kb3lsZS5iaWdyYW0uY2gxICU+JSBjb3VudChmaXJzdHdvcmQsIHNlY29uZHdvcmQsIHNvcnQ9VCkpCihkb3lsZS5kaWFncmFtLmNoOC53b3JkY291bnQgPC1kb3lsZS5iaWdyYW0uY2g4ICU+JSBjb3VudChmaXJzdHdvcmQsIHNlY29uZHdvcmQsIHNvcnQ9VCkpCihkb3lsZS5kaWFncmFtLmNoMTQud29yZGNvdW50IDwtZG95bGUuYmlncmFtLmNoMTQgJT4lIGNvdW50KGZpcnN0d29yZCwgc2Vjb25kd29yZCwgc29ydD1UKSkgI1NvcnRlZCB0aGUgbW9zdCB1c2VkIHdvcmRzIGZvciBlYWNoIG9mIHRoZSB0aHJlZSBiaWdyYW1zIGluIG9yZGVyIHRvIGNvbXBhcmUgdGhlbS4KYGBgCgoqKkFuYWx5c2lzKiogTG9va2luZyBhdCB0aGUgYmlncmFtcywgdGhlcmUgYXJlIHNvbWUgY2xlYXIgZGlmZmVyZW5jZXMgYmV0d2VlbiB3aGljaCBwYWlyIG9mIHdvcmRzIGlzIG1vc3QgdXNlZCBhcyB0aGUgbm92ZWwgdW5mb2xkcy4gVGhlIGZpcnN0IGNoYXB0ZXIgaGFzIG1vc3QgaW5zdGFuY2VzIG9mIHRoZSBuYW1lIFNoZXJsb2NrIEhvbG1lcy4gVGhpcyBtYWtlcyBzZW5zZSBzaW5jZSAiQSBTdHVkeSBpbiBTY2FybGV0IiBpcyB0aGUgZmlyc3QgaW5zdGFuY2Ugb2YgdGhlIGZhbW91cyBkZXRlY3RpdmUsIHNvIERveWxlIGhhcyB0byBnaXZlIHRoZSBiYWNrZ3JvdW5kIGluZm9ybWF0aW9uIG5lY2Vzc2FyeS4gQ2hhcHRlciA4IGhhcyBpbnN0YW5jZXMgb2YgU2llcnJhIEJsYW5jbyB3aGljaCBpcyB0aGUgc2V0dGluZyBvZiB0aGUgZGVhdGggaW4gIkEgU3R1ZHkgaW4gU2NhcmxldCIuIEZpbmFsbHksIENoYXB0ZXIgMTQgaGFzIG1vcmUgaW5zdGFuY2VzIG9mIFNoZXJsb2NrIEhvbG1lcyBhcyB0aGUgbW9zdCB1c2VkIGJpZ3JhbSBhbG9uZyB3aXRoIGRlYWQgbWFuJ3MuIEkgY2FuIGFsc28gc2VlIGhvdyBsb29raW5nIGFuZCBhbmFseXppbmcgdGhlIGNvZGUgaXMgaW1wb3J0YW50IHNpbmNlIHRoZXJlIGFyZSBpbnN0YW5jZXMgb2YgYmlncmFtcyB0aGF0IGRvIG5vdCBtYWtlIHNlbnNlLCBzdWNoIGFzICJwYWdlIDIzIiB3aGljaCBJIGFtIGFzc3VtaW5nIGlzIGEgcGFnZSBudW1iZXIgdGhhdCB3YXMgYWNjaWRlbnRhbGx5IG5vdCBkZWxldGVkIHdoZW4gdGhlIG1hbnVzY3JpcHQgd2FzIHVwbG9hZGVkIHRvIFByb2plY3QgR3V0ZW5iZXJnLiAKCgojQW5hbHl6aW5nIFBhcnRzIG9mIFNwZWVjaCAKQW5vdGhlciB0eXBlIG9mIGFuYWx5c2lzIHRoYXQgY2FuIGJlIGRvbmUgb24gdGhpcyBub3ZlbCBpcyB0aGUgc3R1ZHkgb2YgdGhlIHBhcnRzIG9mIHNwZWVjaC4gSSB3YXMgY3VyaW91cyB0byBzZWUsIGdpdmVuIHRoYXQgdGhpcyBpcyBhIGRldGVjdGl2ZSBhbmQgYWR2ZW50dXJlIG5hcnJhdGlvbiwgaWYgdGhlIG5vdmVsIHdvdWxkIGJlIGFjdGlvbiBwYWNrZWQuIFRoZSBlYXNpZXN0IHdheSB0byBkbyBzbyBpcyB0byB2ZXJpZnkgdGhlIHVzYWdlIG9mIHZlcmJzIChhY3Rpb24pIGFnYWluc3QgYWRqZWN0aXZlcyAoZGVzY3JpcHRpb24pLiBGaXJzdCwgSSBhbm5vdGF0ZWQgdGhlIGVudGlyZSBub3ZlbCB3aXRoIHRoZSBjbmxwX2Fubm90YXRlIGZ1bmN0aW9uIHdoaWNoIHRha2VzIGEgbGl0dGxlIGJpdCBvZiB0aW1lIGZvciBSIHRvIHJ1bi4gVGhlbiwgSSBkaXZpZGVkIHRoZSBkYXRhIGZyYW1lIHRvIGdldCBvbmx5IHRoZSB0aWJibGUgdGhhdCBoYXMgdGhlIGFjdHVhbCB3b3JkcyBhbmQgdGhlIHBhcnRzIG9mIHNwZWVjaC4gCgpgYGB7cn0KI3RpZHkuZG95bGUuYW5ub3RhdGVkIDwtY25scF9hbm5vdGF0ZSh0aWR5LmRveWxlJHdvcmQpCmBgYAoKYGBge3J9CnRpZHkuZG95bGUuYW5ub3RhdGVkLmZ1bGwgPC0gZGF0YS5mcmFtZSh0aWR5LmRveWxlLmFubm90YXRlZCR0b2tlbikKYGBgCgpIZXJlLCBJIGNoZWNrZWQgdG8gc2VlIHdoaWNoIHBhcnRzIG9mIHNwZWVjaCBhcmUgaW5jbHVkZWQgaW4gdGhpcyBib29rLgoKYGBge3J9CnVuaXF1ZSh0aWR5LmRveWxlLmFubm90YXRlZC5mdWxsJHVwb3MpCmBgYAoKVGhlbiwgSSBjb25kdWN0ZWQgYSB0ZXN0IG9uIHRoZSBtb3N0IHVzZWQgdmVyYnMgYXMgd2VsbCBhcyB0aGUgbnVtYmVyIG9mIHZlcmJzIHVzZWQuIEkgZGlkIHRoZSBzYW1lIHRoaW5nIGZvciB0aGUgYWRqZWN0aXZlcy4gCmBgYHtyfQooZG95bGUudmVyYnM8LXRpZHkuZG95bGUuYW5ub3RhdGVkLmZ1bGwgJT4lIGZpbHRlcih1cG9zID09ICJWRVJCIikgJT4lIGNvdW50KHRva2VuLCBzb3J0ID0gVCkgJT4lIAogICAgdG9wX24oMTAwKSkKdGlkeS5kb3lsZS5hbm5vdGF0ZWQuZnVsbCAlPiUgZmlsdGVyKHVwb3MgPT0gIlZFUkIiKSAlPiUgY291bnQoKQpgYGAKCgpgYGB7cn0KKGRveWxlLmFkajwtIHRpZHkuZG95bGUuYW5ub3RhdGVkLmZ1bGwgJT4lIGZpbHRlcih1cG9zID09ICJBREoiKSAlPiUgY291bnQodG9rZW4sIHNvcnQgPSBUKSAlPiUgCiAgICB0b3BfbigxMDApKQp0aWR5LmRveWxlLmFubm90YXRlZC5mdWxsICU+JSBmaWx0ZXIodXBvcyA9PSAiQURKIikgJT4lIGNvdW50KCkKYGBgCioqQW5hbHlzaXM6KiogTG9va2luZyBhdCB0aGUgY291bnRzIGZvciB0aGUgcGFydHMgb2Ygc3BlZWNoLCB0aGVyZSBhcmUgbW9yZSB0aGFuIHR3aWNlIGFzIG1hbnkgdmVyYnMgYXMgdGhlcmUgYXJlIGFkamVjdGl2ZXMgaW4gdGhpcyBub3ZlbC4gVGhpcyB3b3VsZCBzdWdnZXN0IHRoYXQgYWN0aW9uIG1vdmVzIHRoZSBwbG90IGZvcndhcmQgbW9yZSB0aGFuIGhlYXZ5IGRlc2NyaXB0aW9uIGRvZXMuIFRoaXMgZm9sbG93cyB0aGUgZ2VuZXJhbCBmb3JtYXR0aW5nIG9mIGRldGVjdGl2ZSBub3ZlbHMgd2hpY2ggdGVuZCB0byBiZSBhY3RpdmUgaW4gbmFycmF0aW9uIHRvIHByb3BlbCB0aGUgYWN0aW9uLiBMb29raW5nIGF0IHRoZSBzcGVjaWZpYyB2ZXJicyB1c2VkLCBpdCBzZWVtcyB0aGF0ICJhbnN3ZXJlZCIgYW5kICJmb3VuZCIgYXJlIHRoZSB0d28gbW9zdCB1c2VkIHZlcmJzLiBHaXZlbiB0aGF0IG15c3RlcnkgYW5kIHRocmlsbGVyIHJlcXVpcmVzIGRlZHVjdGlvbiBhbmQgYW5hbHlzaXMgb2YgZXZpZGVuY2UsIGl0IHdvdWxkIGJlIGxvZ2ljYWwgdG8gYXNzdW1lIHRoYXQgd29yZHMgdGhhdCBkZXNjcmliZSB0aG9zZSBhY3Rpb25zIGFyZSBtb3N0IGNvbW1vbi4gVXNpbmcgdGhpcyBhbmFseXNpcyBhbHNvIG1hZGUgaXQgZWFzeSBmb3IgbWUgdG8gcmVhbGl6ZSB0aGF0IG1vc3Qgb2YgdGhlIG5vdmVsIGlzIHdyaXR0ZW4gaW4gcGFzdCBwYXJ0aWNpcGxlIHNpbmNlIHRoZSBtb3N0IHVzZWQgdmVyYnMgYXJlIGNvbmp1Z2F0ZWQgYXMgc3VjaC4gSW4gcmVnYXJkcyB0byB0aGUgdXNlIG9mIGFkamVjdGl2ZXMsIHRoZSBtb3N0IHVzZWQgb25lcyBhbGx1ZGUgdG8gYW1iaWFuY2UgImRhcmsiLCAid2hpdGUiLCAic2lsZW50IiwgYXMgd2VsbCBhcyBlbW90aW9uICJ0ZXJyaWJsZSIuIEp1c3QgbG9va2luZyBhdCB0aGUgd29yZCBjaG9pY2UsIGl0IGlzIGVhc3kgdG8gYXNzdW1lIHRoYXQgdGhlIG92ZXJhbGwgd3JpdGluZyBzdHlsZSBvZiBBcnRodXIgQ29uYW4gRG95bGUgcmVsYXRlcyB0byBjcmVhdGluZyBhbiBlbnZpcm9ubWVudCBvZiBpbnRyaWd1ZSBmb3IgdGhlIHJlYWRlci4gCgojV29yZCBGcmVxdWVuY3kgRmlndXJlcyAKCk5vdyBpcyB0aGUgdGltZSB0byBzaG93Y2FzZSB0aGlzIGFuYWx5c2lzIGluIGEgZ3JhcGhpY2FsIG1hbm5lci4gRm9yIHRoaXMsIEkgaGF2ZSBjaG9zZW4gdG8gZG8gYSB3b3JkIGNsb3VkIGZvciB0aGUgbW9zdCB1c2VkIHZlcmJzIGFuZCBhZGplY3RpdmVzIGluIG9yZGVyIHRvIHNob3djYXNlIHRoZW0gaW4gYSBkaWdlc3RpYmxlIG1hbm5lci4gRm9yIHRoZSBjb21wYXJpc29uIGJldHdlZW4gY2hhcHRlcnMsIEkgaGF2ZSBjaG9zZW4gYSBiYXIgZ3JhcGguIEZpcnN0LCBJIG5lZWRlZCB0byBkb3dubG9hZCB0aGUgd29yZHNjbG91ZCB0d28gdG8gY3JlYXRlIGEgY29sb3JmdWwgdmVyc2lvbiBvZiB0aGUgd29ybGQgY2xvdWQuIAoKYGBge3J9CiNsaWJyYXJ5KHdvcmRjbG91ZDIpCndvcmRjbG91ZC5hZGo8LXdvcmRjbG91ZDIoZG95bGUuYWRqKQp3b3JkY2xvdWQudmVyYnM8LXdvcmRjbG91ZDIoZG95bGUudmVyYnMpCndvcmRjbG91ZC5hZGoKYGBgCgpgYGB7cn0Kd29yZGNsb3VkLnZlcmJzCmBgYAoKVGhpcyB3b3JkIGNsb3VkIHZpc3VhbGx5IHNob3cgd2hhdCB0aGUgYW5hbHlzaXMgYWJvdmUgc3RhdGVkLiBOb3cgSSB3aWxsIGRvIHRoZSBiYXIgZ3JhcGhzIGZvciB0aGUgd29yZCBmcmVxdWVuY2llcyBpbiB0aGUgY2hhcHRlcnMuIAoKYGBge3J9CmNoMXBsb3QgPC0gd29yZGNvdW50cy5jaDEgJT4lIHRvcF9uKDIwKSAlPiUKICAgIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBuKSkgJT4lIGdncGxvdChhZXMoeCA9IHdvcmQsIHkgPSBuKSkgKyBnZW9tX2NvbChmaWxsPSIjRkYyNDAwIikgKyAKICAgIHhsYWIoTlVMTCkgKyBjb29yZF9mbGlwKCkgKyBsYWJzKHkgPSAiQ291bnQiLCB4ID0gIk1vc3QgVXNlZCBXb3JkcyIpCmNoOHBsb3QgPC0gd29yZGNvdW50cy5jaDggJT4lIHRvcF9uKDIwKSAlPiUKICAgIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBuKSkgJT4lIGdncGxvdChhZXMoeCA9IHdvcmQsIHkgPSBuKSkgKyBnZW9tX2NvbChmaWxsPSIjNjYwZTAwIikgKyAKICAgIHhsYWIoTlVMTCkgKyBjb29yZF9mbGlwKCkgKyBsYWJzKHkgPSAiQ291bnQiLCB4ID0gIk1vc3QgVXNlZCBXb3JkcyIpCmNoMTRwbG90IDwtIHdvcmRjb3VudHMuY2gxNCAlPiUgdG9wX24oMjApICU+JQogICAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUgZ2dwbG90KGFlcyh4ID0gd29yZCwgeSA9IG4pKSArIGdlb21fY29sKGZpbGw9IiMzMzA3MDAiKSArIAogICAgeGxhYihOVUxMKSArIGNvb3JkX2ZsaXAoKSArIGxhYnMoeSA9ICJDb3VudCIsIHggPSAiTW9zdCBVc2VkIFdvcmRzIikKY29tYmluZWRwbG90czwtIGdnYXJyYW5nZShjaDFwbG90LCBjaDhwbG90LCBjaDE0cGxvdCwgbmNvbD0zLCBucm93PTEpCihmaW5hbHBsb3RzPC1hbm5vdGF0ZV9maWd1cmUoY29tYmluZWRwbG90cywgYm90dG9tID0gIkZpZ3VyZSAxOiBNb3N0IHVzZWQgd29yZHMgaW4gQ2hhcHRlciAxLCA4LCBhbmQgMTQsIHJlc3BlY3RpdmVseSIsIHRvcD0gIkEgU3R1ZHkgaW4gU2NhcmxldCIpKQpgYGAKCgojU2VudGltZW50IEFuYWx5c2lzIAoKVGhlIGZpbmFsIHBhcnQgb2YgdGhpcyBwcm9ibGVtIHNldCB3YXMgZm9jdXNpbmcgb24gc2VudGltZW50IGFuYWx5c2lzLiBJbiBvcmRlciB0byBkbyB0aGF0LCBJIGRlY2lkZWQgdG8gYWxzbyB1c2UgdGhlIE5SQyBFbW90aW9uIExleGljb24gYmVjYXVzZSBJIHdhcyBjdXJpb3VzIHRvIHNlZSBob3cgdGhlIGxleGljb24gdXNlZCBieSBDb25hbiBEb3lsZSByZWxhdGVzIHRvICJuZWdhdGl2ZSIgZW1vdGlvbnMgKGZlYXIsIHNhZG5lc3MsIGFuZ2VyKS4gCgpgYGB7cn0KI2dldF9zZW50aW1lbnRzKCJucmMiKQooc2VudGltZW50LmRveWxlPC0gdGlkeS5kb3lsZSAlPiUgaW5uZXJfam9pbihnZXRfc2VudGltZW50cygibnJjIikpKQpgYGAKCmBgYHtyfQooZmVhci5kb3lsZSA8LXNlbnRpbWVudC5kb3lsZSAlPiUgZmlsdGVyKHNlbnRpbWVudCA9PSAiZmVhciIpICU+JSBjb3VudCh3b3JkLCBzb3J0ID0gVCkpCihuZWdhdGl2ZS5kb3lsZSA8LXNlbnRpbWVudC5kb3lsZSAgJT4lIGZpbHRlcihzZW50aW1lbnQgPT0gIm5lZ2F0aXZlIikgJT4lIGNvdW50KHdvcmQsIHNvcnQgPSBUKSkKKHN1cnByaXNlLmRveWxlPC1zZW50aW1lbnQuZG95bGUgJT4lIGZpbHRlcihzZW50aW1lbnQgPT0gInN1cnByaXNlIikgJT4lIGNvdW50KHdvcmQsIHNvcnQgPSBUKSkKKHBvc2l0aXZlLmRveWxlIDwtIHNlbnRpbWVudC5kb3lsZSAlPiUgZmlsdGVyKHNlbnRpbWVudCA9PSAicG9zaXRpdmUiKSAlPiUgY291bnQod29yZCwgc29ydCA9IFQpKQoKYGBgCgpgYGB7cn0KKGZlYXJwbG90IDwtIGZlYXIuZG95bGUgJT4lIHRvcF9uKDIwKSAlPiUKICAgIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBuKSkgJT4lIGdncGxvdChhZXMoeCA9IHdvcmQsIHkgPSBuKSkgKyBnZW9tX2NvbChmaWxsPSIjMDNBQzEzIikgKyAKICAgIHhsYWIoTlVMTCkgKyBjb29yZF9mbGlwKCkgKyBsYWJzKHkgPSAiQ291bnQiLCB4ID0gIldvcmRzIEFzc29jaWF0ZWQgdG8gRmVhciIsIHRpdGxlID0gIkEgU3R1ZHkgSW4gU2NhcmxldDogU2VudGltZW50IEFuYWx5c2lzIG9mIEZlYXIiKSkKKHN1cnByaXNlcGxvdCA8LSBzdXJwcmlzZS5kb3lsZSAlPiUgdG9wX24oMjApICU+JQogICAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUgZ2dwbG90KGFlcyh4ID0gd29yZCwgeSA9IG4pKSArIGdlb21fY29sKGZpbGw9IiMzMjYxMkQiKSArIAogICAgeGxhYihOVUxMKSArIGNvb3JkX2ZsaXAoKSArIGxhYnMoeSA9ICJDb3VudCIsIHggPSAiV29yZHMgQXNzb2NpYXRlZCB0byBTdXJwcmlzZSIsIHRpdGxlID0gIkEgU3R1ZHkgSW4gU2NhcmxldDogU2VudGltZW50IEFuYWx5c2lzIG9mIFN1cnByaXNlIikpCnBvc2l0aXZlcGxvdDwtcG9zaXRpdmUuZG95bGUgJT4lIHRvcF9uKDIwKSAlPiUKICAgIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBuKSkgJT4lIGdncGxvdChhZXMoeCA9IHdvcmQsIHkgPSBuKSkgKyBnZW9tX2NvbChmaWxsPSIjMTMzOEJFIikgKyAKICAgIHhsYWIoTlVMTCkgKyBjb29yZF9mbGlwKCkgKyBsYWJzKHkgPSAiQ291bnQiLCB4ID0gIlBvc2l0aXZlIFdvcmRzIikKbmVnYXRpdmVwbG90PC1uZWdhdGl2ZS5kb3lsZSAlPiUgdG9wX24oMjApICU+JQogICAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUgZ2dwbG90KGFlcyh4ID0gd29yZCwgeSA9IG4pKSArIGdlb21fY29sKGZpbGw9IiM1NDFFMUIiKSArIAogICAgeGxhYihOVUxMKSArIGNvb3JkX2ZsaXAoKSArIGxhYnMoeSA9ICJDb3VudCIsIHggPSAiTmVnYXRpdmUgV29yZHMiKQpjb21iaW5lZHBsb3RzMjwtIGdnYXJyYW5nZShwb3NpdGl2ZXBsb3QsIG5lZ2F0aXZlcGxvdCwgbmNvbD0yLCBucm93PTEpCihmaW5hbHBsb3RzMjwtYW5ub3RhdGVfZmlndXJlKGNvbWJpbmVkcGxvdHMyLCBib3R0b20gPSAiRmlndXJlIDQ6IENvbXBhcmlzb24gb2YgcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIHdvcmRzIGFjcm9zcyBBIFN0dWR5IEluIFNjYXJsZXQiLCB0b3A9ICJTZW50aW1lbnQgQW5hbHlzaXM6IEEgU3R1ZHkgaW4gU2NhcmxldCIpKQpgYGAKCg==