library(tidyverse)
library(DT)
library(tidytext)        # package for text analysis
library(readxl)          # reads excel files, the format I used for the data

Reading and tidying the text

suicide_notes <- read_excel("suicide_notes.xlsx")

suicide_notes

Notice that when you first read these documents, they’re just a long string of text. We need to separate the words so they can be analyzed.

The tidytext command unnest_tokens() will separate (or unnest) the words, so that there is one word per row. This command will also remove all punctuation and make everything lower case. In unnest_tokens(word, text), ‘text’ is the name of the original column with the text in it, and ‘word’ is what we want the new column to be named.

suicide_words <- suicide_notes %>%
  unnest_tokens(word, text)

suicide_words
NA

Measures of text complexity

The number of words used in a text can be calculated with a simple n() function that counts the number of words.

But many of the words we use are repetitions: Words like ‘the’ and ‘a’ are used over and over. So the number of distinct words is less than the total number of words. We can calculate the number of distinct words with n_distinct().

Both of these measures are calculated below:

suicide_words %>% 
  group_by(author) %>% 
  summarize(num_words = n(), lex_diversity = n_distinct(word))
NA

The number of distinct words is a measure of lexical diversity. It is one measure of an individual’s vocabulary.

Measures like this have been used to determine authorship (e.g., in cases where a suicide note is suspected of being fake and having been written by someone else), and some well-known studies have shown that low linguistic diversity at a young age has been found to predict dementia in old age.

In general, it’s apparent that longer notes have more distinct words, which makes sense. The following is a measure of lexical density, which is the number of distinct words divided by the total number of words. The higher the number, the higher proportion of distinct words are being used. The smaller the number, the more repeat words are used.

suicide_words %>% 
  group_by(author) %>% 
  summarise(num_words = n(),
            lex_diversity = n_distinct(word), 
            lex_density = n_distinct(word)/n())

Another measure related to verbal complexity is the length of the words, i.e., the number of characters in each word. That can be calculated with nchar().

Here is a table with the length of words, with the longest words at the top of the table.

suicide_words %>%
  mutate(word_length = nchar(word)) %>% 
  distinct(word, word_length, author) %>% 
  arrange(-word_length)
NA

We can get the average word length for each author by using mean() on word_length:

suicide_words %>%
  group_by(author) %>% 
  mutate(word_length = nchar(word)) %>% 
  summarize(mean_word_length = mean(word_length)) %>% 
  arrange(-mean_word_length)

Graph word length distributions for all notes.

suicide_words %>%
  mutate(word_length = nchar(word)) %>% 
  ggplot(aes(word_length)) +
  geom_histogram(binwidth = 1) 

Recreate the above graph, but make two additions:
1. Add the following line: facet_wrap(vars(author), scales = “free_y”). This will create mini graphs for each author.
2. Add a line with labs(title = "") and then put a title in the quotes.

Basic word counts

To get a sense of the content of suicide notes, we could look at the most common words used.

suicide_words %>% 
  count(word, sort = T) 
NA

Copy-paste the above code below, and then separate the word counts by author by adding the following line between the two lines above: group_by(author) %>% .

suicide_words %>% 
  group_by(author) %>%
  count(word, sort = T) 
NA

Graph the most common words for each author by copy-pasting the above code on top of the following. Make sure to connect it with the pipe.

suicide_words %>% 
  group_by(author) %>%
  count(word, sort = T) %>% 
  top_n(5) %>%
  ungroup() %>% 
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(word, n, fill = author)) +
  geom_col(show.legend = FALSE) +
  coord_flip() +
  facet_wrap(~author, scales = "free") +           # creates separate graphs for each author
  scale_fill_viridis_d() +                         # uses a nicer color scheme
  theme_minimal() +                                # removes the gray background
  labs(x = NULL, y = "Most common words")
Selecting by n

Remove stop words

The problem is that the most common words are not very interesting: the, of, and, etc. These are called stop words, and tidytext includes a file with them so you can remove them. Load them and view them:

stop_words <- get_stopwords()
stop_words$word
  [1] "i"          "me"         "my"         "myself"     "we"         "our"        "ours"       "ourselves" 
  [9] "you"        "your"       "yours"      "yourself"   "yourselves" "he"         "him"        "his"       
 [17] "himself"    "she"        "her"        "hers"       "herself"    "it"         "its"        "itself"    
 [25] "they"       "them"       "their"      "theirs"     "themselves" "what"       "which"      "who"       
 [33] "whom"       "this"       "that"       "these"      "those"      "am"         "is"         "are"       
 [41] "was"        "were"       "be"         "been"       "being"      "have"       "has"        "had"       
 [49] "having"     "do"         "does"       "did"        "doing"      "would"      "should"     "could"     
 [57] "ought"      "i'm"        "you're"     "he's"       "she's"      "it's"       "we're"      "they're"   
 [65] "i've"       "you've"     "we've"      "they've"    "i'd"        "you'd"      "he'd"       "she'd"     
 [73] "we'd"       "they'd"     "i'll"       "you'll"     "he'll"      "she'll"     "we'll"      "they'll"   
 [81] "isn't"      "aren't"     "wasn't"     "weren't"    "hasn't"     "haven't"    "hadn't"     "doesn't"   
 [89] "don't"      "didn't"     "won't"      "wouldn't"   "shan't"     "shouldn't"  "can't"      "cannot"    
 [97] "couldn't"   "mustn't"    "let's"      "that's"     "who's"      "what's"     "here's"     "there's"   
[105] "when's"     "where's"    "why's"      "how's"      "a"          "an"         "the"        "and"       
[113] "but"        "if"         "or"         "because"    "as"         "until"      "while"      "of"        
[121] "at"         "by"         "for"        "with"       "about"      "against"    "between"    "into"      
[129] "through"    "during"     "before"     "after"      "above"      "below"      "to"         "from"      
[137] "up"         "down"       "in"         "out"        "on"         "off"        "over"       "under"     
[145] "again"      "further"    "then"       "once"       "here"       "there"      "when"       "where"     
[153] "why"        "how"        "all"        "any"        "both"       "each"       "few"        "more"      
[161] "most"       "other"      "some"       "such"       "no"         "nor"        "not"        "only"      
[169] "own"        "same"       "so"         "than"       "too"        "very"       "will"      

Use anti_join to remove all stopwords. anti_join() is the opposite of join: it will find the words in common between the two data frames (words and stop_words in this case), remove them, and leave all other words.

suicide_words %>%
  anti_join(stop_words)
Joining, by = "word"

To count these words, copy-paste the above code below, and pipe it to the following line: count(word, sort = T)

Separated by author.

suicide_words %>%
  anti_join(stop_words) %>% 
  group_by(author) %>% 
  count(word, sort = T) 
Joining, by = "word"

Copy the code above and pipe it into the following, which creates a graph of the most common words in each note, but now with the stop words removed:

suicide_words %>%
  anti_join(stop_words) %>% 
  group_by(author) %>% 
  count(word, sort = T) %>% 

  top_n(5) %>% 
  ungroup() %>% 
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(word, n, fill = author)) +
  geom_col(show.legend = FALSE) +
  labs(x = NULL, y = "Most common words") +
  facet_wrap(vars(author), scales = "free") +
  scale_fill_viridis_d() +
  theme_minimal() +
  coord_flip()
Joining, by = "word"
Selecting by n

TF-IDF

Term frequency-Inverse Document Frequency (TF-IDF) is a measure of the importance of a word in one document relative to other documents. It finds the words that are unique to one document or author. It’s a mouthful so let’s break it down:

Term frequency (TF) = the number of times a term appears in a document Document frequency (DF) = the number of other documents that contain the word Inverse document frequency = 1/DF.

TF-IDF = TF * IDF

So it’s a measure of how often a word appears in one document, divided by how often it appears in other documents.

For example, say we have 10 web pages. If the word ‘the’ appears in one web page 12 times, its TF = 12. If ‘the’ appears in all 10 of the web pages, its DF = 10 and its IDF = 1/10. That makes its TF-IDF = 12 * 1/10 or 1.2.
But if the word ‘love’ appears 8 times on one web page, but appears in just 3 of the web pages total, its TF-IDF would be 8 * 1/3 = 8/3 or 2.7.
Notice that the word ‘love’ has a higher TF-IDF than the common word ‘the’. ‘Love’ appears often on that page and doesn’t appear in all of the other pages, which makes it important for that particular page.

The math is actually a little more complicated than that, and there are variations on the basic formulas, but that’s the principle.

See the chapter on TF-IDF in Text Mining with R for more information: https://www.tidytextmining.com/tfidf.html.

The following large code chunk does all of the calculations for TF-IDF in a couple of steps, and then shows a table of them.

suicide_word_counts <- suicide_notes %>%             # This counts each word per author
  unnest_tokens(word, text) %>%
  count(author, word, sort = TRUE) 

total_words <- suicide_word_counts %>%               # This counts total words per author
  group_by(author) %>% 
  summarize(total = sum(n))

suicide_word_counts <- left_join(suicide_word_counts, total_words)    # Joins the two
Joining, by = "author"
suicide_tf_idf <- suicide_word_counts %>%             # Calculates tf-idf
  bind_tf_idf(word, author, n)

suicide_tf_idf %>%                                   # Displays it
  arrange(-tf_idf)                          
NA

Graph it.

suicide_tf_idf %>%
  arrange(-tf_idf) %>%
  mutate(word = factor(word, levels = rev(unique(word)))) %>% 
  group_by(author) %>% 
  top_n(5) %>% 
  ggplot(aes(word, tf_idf, fill = author)) +
  geom_col(show.legend = FALSE) +
  labs(x = NULL, y = "tf-idf") +
  facet_wrap(~author, scales = "free") +
  coord_flip()
Selecting by tf_idf

Notice that, although we did not remove the stopwords for this, tf-idf automatically excludes most stop words because they will appear in all of the notes.

To clean this graph up a little, add the following lines:
1. theme_minimal(), which will get rid of the grey background,
2. scale_fill_viridis_d(), which will use an improved color palette 3. labs(title = “Most distinctive words in each suicide note”)

suicide_tf_idf %>%
  arrange(-tf_idf) %>%
  mutate(word = factor(word, levels = rev(unique(word)))) %>% 
  group_by(author) %>% 
  top_n(5) %>% 
  ggplot(aes(word, tf_idf, fill = author)) +
  geom_col(show.legend = FALSE) +
  labs(x = NULL, y = "tf-idf") +
  facet_wrap(~author, scales = "free") +
  coord_flip()
Selecting by tf_idf

  theme_minimal()
List of 59
 $ line                 :List of 6
  ..$ colour       : chr "black"
  ..$ size         : num 0.5
  ..$ linetype     : num 1
  ..$ lineend      : chr "butt"
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ rect                 :List of 5
  ..$ fill         : chr "white"
  ..$ colour       : chr "black"
  ..$ size         : num 0.5
  ..$ linetype     : num 1
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ text                 :List of 11
  ..$ family       : chr ""
  ..$ face         : chr "plain"
  ..$ colour       : chr "black"
  ..$ size         : num 11
  ..$ hjust        : num 0.5
  ..$ vjust        : num 0.5
  ..$ angle        : num 0
  ..$ lineheight   : num 0.9
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.x         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 2.75pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.x.top     :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 2.75pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.y         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : num 90
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 2.75pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.y.right   :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : num -90
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 2.75pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text            :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : chr "grey30"
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.x          :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 2.2pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.x.top      :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 2.2pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.y          :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 2.2pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.y.right    :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 2.2pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.ticks           : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ axis.ticks.length    : 'unit' num 2.75pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ axis.line            : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ axis.line.x          : NULL
 $ axis.line.y          : NULL
 $ legend.background    : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ legend.margin        : 'margin' num [1:4] 5.5pt 5.5pt 5.5pt 5.5pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ legend.spacing       : 'unit' num 11pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ legend.spacing.x     : NULL
 $ legend.spacing.y     : NULL
 $ legend.key           : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ legend.key.size      : 'unit' num 1.2lines
  ..- attr(*, "valid.unit")= int 3
  ..- attr(*, "unit")= chr "lines"
 $ legend.key.height    : NULL
 $ legend.key.width     : NULL
 $ legend.text          :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ legend.text.align    : NULL
 $ legend.title         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ legend.title.align   : NULL
 $ legend.position      : chr "right"
 $ legend.direction     : NULL
 $ legend.justification : chr "center"
 $ legend.box           : NULL
 $ legend.box.margin    : 'margin' num [1:4] 0cm 0cm 0cm 0cm
  ..- attr(*, "valid.unit")= int 1
  ..- attr(*, "unit")= chr "cm"
 $ legend.box.background: list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ legend.box.spacing   : 'unit' num 11pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ panel.background     : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ panel.border         : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ panel.spacing        : 'unit' num 5.5pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ panel.spacing.x      : NULL
 $ panel.spacing.y      : NULL
 $ panel.grid           :List of 6
  ..$ colour       : chr "grey92"
  ..$ size         : NULL
  ..$ linetype     : NULL
  ..$ lineend      : NULL
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ panel.grid.minor     :List of 6
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.5
  ..$ linetype     : NULL
  ..$ lineend      : NULL
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ panel.ontop          : logi FALSE
 $ plot.background      : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ plot.title           :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 1.2
  ..$ hjust        : num 0
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 5.5pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.subtitle        :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 5.5pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.caption         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : num 1
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 5.5pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.tag             :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 1.2
  ..$ hjust        : num 0.5
  ..$ vjust        : num 0.5
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.tag.position    : chr "topleft"
 $ plot.margin          : 'margin' num [1:4] 5.5pt 5.5pt 5.5pt 5.5pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ strip.background     : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ strip.placement      : chr "inside"
 $ strip.text           :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : chr "grey10"
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 4.4pt 4.4pt 4.4pt 4.4pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ strip.text.x         : NULL
 $ strip.text.y         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : num -90
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ strip.switch.pad.grid: 'unit' num 2.75pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ strip.switch.pad.wrap: 'unit' num 2.75pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi TRUE
 - attr(*, "validate")= logi TRUE
  scale_fill_viridis_d()
<ggproto object: Class ScaleDiscrete, Scale, gg>
    aesthetics: fill
    axis_order: function
    break_info: function
    break_positions: function
    breaks: waiver
    call: call
    clone: function
    dimension: function
    drop: TRUE
    expand: waiver
    get_breaks: function
    get_breaks_minor: function
    get_labels: function
    get_limits: function
    guide: legend
    is_discrete: function
    is_empty: function
    labels: waiver
    limits: NULL
    make_sec_title: function
    make_title: function
    map: function
    map_df: function
    n.breaks.cache: NULL
    na.translate: TRUE
    na.value: NA
    name: waiver
    palette: function
    palette.cache: NULL
    position: left
    range: <ggproto object: Class RangeDiscrete, Range, gg>
        range: NULL
        reset: function
        train: function
        super:  <ggproto object: Class RangeDiscrete, Range, gg>
    reset: function
    scale_name: viridis_d
    train: function
    train_df: function
    transform: function
    transform_df: function
    super:  <ggproto object: Class ScaleDiscrete, Scale, gg>
  labs(title = "Most distinctive words in each suicide note")
$title
[1] "Most distinctive words in each suicide note"

attr(,"class")
[1] "labels"

Assignment: Read in the file called manifestos.xslx. It contains the writings of several mass killers, incuding the Unabomber, Anders Breivik who killed 70+ people in Norway, Pekka-Eric Auvinen a school shooter from Finland, Elliot Rodger who killed people in California, Seung-Hui Cho who killed people at Virginia Tech, and Chris Harper-Mercer who killed people at a college in Oregon. (I collected these writings and put them into an excel file. Breivik wrote the most by far; I took only a small portion of his writings.)

  1. Read in the text and unnest the words.
  2. Generate a table that includes both lexical diversity and density, and the total number of words, of each document.
  3. Generate a table with the mean word length of each document.
  4. Genernate a graph with mini histograms of each document’s word lengths.
  5. Remove stop words and then create a graph with the most common words in each document.
  6. Calculate tf-idfs and create a graph of the words with the highest tf-idfs in each document.
terror_notes <- read_excel("manifestos.xlsx")

terror_notes
terror_words <- terror_notes %>%
  unnest_tokens(word, text)

terror_words

step 1

terror_words %>% 
  group_by(author) %>% 
  summarise(num_words = n(),
            lex_diversity = n_distinct(word), 
            lex_density = n_distinct(word)/n())
terror_words %>%
  group_by(author) %>% 
  mutate(word_length = nchar(word)) %>% 
  summarize(mean_word_length = mean(word_length)) %>% 
  arrange(-mean_word_length)
terror_words %>% 
  group_by(author) %>%
  count(word, sort = T) %>% 
  top_n(5) %>%
  ungroup() %>% 
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(word, n, fill = author)) +
  geom_col(show.legend = FALSE) +
  coord_flip() +
  facet_wrap(~author, scales = "free") +           # creates separate graphs for each author
  scale_fill_viridis_d() +                         # uses a nicer color scheme
  theme_minimal() +                                # removes the gray background
  labs(x = NULL, y = "Most common words")
Selecting by n

terror_word_counts <- terror_notes %>%             # This counts each word per author
  unnest_tokens(word, text) %>%
  count(author, word, sort = TRUE) 

total_words <- terror_word_counts %>%               # This counts total words per author
  group_by(author) %>% 
  summarize(total = sum(n))

terror_word_counts <- left_join(terror_word_counts, total_words)    # Joins the two
Joining, by = "author"
terror_tf_idf <- terror_word_counts %>%             # Calculates tf-idf
  bind_tf_idf(word, author, n)

terror_tf_idf %>%                                   # Displays it
  arrange(-tf_idf)                          
NA
terror_tf_idf %>%
  arrange(-tf_idf) %>%
  mutate(word = factor(word, levels = rev(unique(word)))) %>% 
  group_by(author) %>% 
  top_n(5) %>% 
  ggplot(aes(word, tf_idf, fill = author)) +
  geom_col(show.legend = FALSE) +
  labs(x = NULL, y = "tf-idf") +
  facet_wrap(~author, scales = "free") +
  coord_flip()
Selecting by tf_idf

  theme_minimal()
List of 59
 $ line                 :List of 6
  ..$ colour       : chr "black"
  ..$ size         : num 0.5
  ..$ linetype     : num 1
  ..$ lineend      : chr "butt"
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ rect                 :List of 5
  ..$ fill         : chr "white"
  ..$ colour       : chr "black"
  ..$ size         : num 0.5
  ..$ linetype     : num 1
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_rect" "element"
 $ text                 :List of 11
  ..$ family       : chr ""
  ..$ face         : chr "plain"
  ..$ colour       : chr "black"
  ..$ size         : num 11
  ..$ hjust        : num 0.5
  ..$ vjust        : num 0.5
  ..$ angle        : num 0
  ..$ lineheight   : num 0.9
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.x         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 2.75pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.x.top     :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 2.75pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.y         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : num 90
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 2.75pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.title.y.right   :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : num -90
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 2.75pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text            :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : chr "grey30"
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.x          :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 2.2pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.x.top      :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : num 0
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 2.2pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.y          :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 2.2pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.text.y.right    :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 0pt 2.2pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ axis.ticks           : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ axis.ticks.length    : 'unit' num 2.75pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ axis.line            : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ axis.line.x          : NULL
 $ axis.line.y          : NULL
 $ legend.background    : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ legend.margin        : 'margin' num [1:4] 5.5pt 5.5pt 5.5pt 5.5pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ legend.spacing       : 'unit' num 11pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ legend.spacing.x     : NULL
 $ legend.spacing.y     : NULL
 $ legend.key           : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ legend.key.size      : 'unit' num 1.2lines
  ..- attr(*, "valid.unit")= int 3
  ..- attr(*, "unit")= chr "lines"
 $ legend.key.height    : NULL
 $ legend.key.width     : NULL
 $ legend.text          :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ legend.text.align    : NULL
 $ legend.title         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ legend.title.align   : NULL
 $ legend.position      : chr "right"
 $ legend.direction     : NULL
 $ legend.justification : chr "center"
 $ legend.box           : NULL
 $ legend.box.margin    : 'margin' num [1:4] 0cm 0cm 0cm 0cm
  ..- attr(*, "valid.unit")= int 1
  ..- attr(*, "unit")= chr "cm"
 $ legend.box.background: list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ legend.box.spacing   : 'unit' num 11pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ panel.background     : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ panel.border         : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ panel.spacing        : 'unit' num 5.5pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ panel.spacing.x      : NULL
 $ panel.spacing.y      : NULL
 $ panel.grid           :List of 6
  ..$ colour       : chr "grey92"
  ..$ size         : NULL
  ..$ linetype     : NULL
  ..$ lineend      : NULL
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ panel.grid.minor     :List of 6
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.5
  ..$ linetype     : NULL
  ..$ lineend      : NULL
  ..$ arrow        : logi FALSE
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_line" "element"
 $ panel.ontop          : logi FALSE
 $ plot.background      : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ plot.title           :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 1.2
  ..$ hjust        : num 0
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 5.5pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.subtitle        :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 0
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 0pt 0pt 5.5pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.caption         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : num 1
  ..$ vjust        : num 1
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 5.5pt 0pt 0pt 0pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.tag             :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : 'rel' num 1.2
  ..$ hjust        : num 0.5
  ..$ vjust        : num 0.5
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ plot.tag.position    : chr "topleft"
 $ plot.margin          : 'margin' num [1:4] 5.5pt 5.5pt 5.5pt 5.5pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ strip.background     : list()
  ..- attr(*, "class")= chr [1:2] "element_blank" "element"
 $ strip.placement      : chr "inside"
 $ strip.text           :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : chr "grey10"
  ..$ size         : 'rel' num 0.8
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : NULL
  ..$ lineheight   : NULL
  ..$ margin       : 'margin' num [1:4] 4.4pt 4.4pt 4.4pt 4.4pt
  .. ..- attr(*, "valid.unit")= int 8
  .. ..- attr(*, "unit")= chr "pt"
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ strip.text.x         : NULL
 $ strip.text.y         :List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : NULL
  ..$ vjust        : NULL
  ..$ angle        : num -90
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi TRUE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 $ strip.switch.pad.grid: 'unit' num 2.75pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 $ strip.switch.pad.wrap: 'unit' num 2.75pt
  ..- attr(*, "valid.unit")= int 8
  ..- attr(*, "unit")= chr "pt"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi TRUE
 - attr(*, "validate")= logi TRUE
  scale_fill_viridis_d()
<ggproto object: Class ScaleDiscrete, Scale, gg>
    aesthetics: fill
    axis_order: function
    break_info: function
    break_positions: function
    breaks: waiver
    call: call
    clone: function
    dimension: function
    drop: TRUE
    expand: waiver
    get_breaks: function
    get_breaks_minor: function
    get_labels: function
    get_limits: function
    guide: legend
    is_discrete: function
    is_empty: function
    labels: waiver
    limits: NULL
    make_sec_title: function
    make_title: function
    map: function
    map_df: function
    n.breaks.cache: NULL
    na.translate: TRUE
    na.value: NA
    name: waiver
    palette: function
    palette.cache: NULL
    position: left
    range: <ggproto object: Class RangeDiscrete, Range, gg>
        range: NULL
        reset: function
        train: function
        super:  <ggproto object: Class RangeDiscrete, Range, gg>
    reset: function
    scale_name: viridis_d
    train: function
    train_df: function
    transform: function
    transform_df: function
    super:  <ggproto object: Class ScaleDiscrete, Scale, gg>
  labs(title = "Most distinctive words in each terror note")
$title
[1] "Most distinctive words in each terror note"

attr(,"class")
[1] "labels"
LS0tCnRpdGxlOiAiSW50cm8gdG8gVGV4dCBBbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KERUKQpsaWJyYXJ5KHRpZHl0ZXh0KSAgICAgICAgIyBwYWNrYWdlIGZvciB0ZXh0IGFuYWx5c2lzCmxpYnJhcnkocmVhZHhsKSAgICAgICAgICAjIHJlYWRzIGV4Y2VsIGZpbGVzLCB0aGUgZm9ybWF0IEkgdXNlZCBmb3IgdGhlIGRhdGEKCmBgYAoKCiMjIyBSZWFkaW5nIGFuZCB0aWR5aW5nIHRoZSB0ZXh0CgpgYGB7cn0Kc3VpY2lkZV9ub3RlcyA8LSByZWFkX2V4Y2VsKCJzdWljaWRlX25vdGVzLnhsc3giKQoKc3VpY2lkZV9ub3RlcwpgYGAKCk5vdGljZSB0aGF0IHdoZW4geW91IGZpcnN0IHJlYWQgdGhlc2UgZG9jdW1lbnRzLCB0aGV5J3JlIGp1c3QgYSBsb25nIHN0cmluZyBvZiB0ZXh0LiBXZSBuZWVkIHRvIHNlcGFyYXRlIHRoZSB3b3JkcyBzbyB0aGV5IGNhbiBiZSBhbmFseXplZC4KClRoZSB0aWR5dGV4dCBjb21tYW5kIHVubmVzdF90b2tlbnMoKSB3aWxsIHNlcGFyYXRlIChvciB1bm5lc3QpIHRoZSB3b3Jkcywgc28gdGhhdCB0aGVyZSBpcyBvbmUgd29yZCBwZXIgcm93LiBUaGlzIGNvbW1hbmQgd2lsbCBhbHNvIHJlbW92ZSBhbGwgcHVuY3R1YXRpb24gYW5kIG1ha2UgZXZlcnl0aGluZyBsb3dlciBjYXNlLiBJbiB1bm5lc3RfdG9rZW5zKHdvcmQsIHRleHQpLCAndGV4dCcgaXMgdGhlIG5hbWUgb2YgdGhlIG9yaWdpbmFsIGNvbHVtbiB3aXRoIHRoZSB0ZXh0IGluIGl0LCBhbmQgJ3dvcmQnIGlzIHdoYXQgd2Ugd2FudCB0aGUgbmV3IGNvbHVtbiB0byBiZSBuYW1lZC4KCmBgYHtyfQpzdWljaWRlX3dvcmRzIDwtIHN1aWNpZGVfbm90ZXMgJT4lCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB0ZXh0KQoKc3VpY2lkZV93b3JkcwoKYGBgCgoKIyMjIE1lYXN1cmVzIG9mIHRleHQgY29tcGxleGl0eQoKVGhlIG51bWJlciBvZiB3b3JkcyB1c2VkIGluIGEgdGV4dCBjYW4gYmUgY2FsY3VsYXRlZCB3aXRoIGEgc2ltcGxlIG4oKSBmdW5jdGlvbiB0aGF0IGNvdW50cyB0aGUgbnVtYmVyIG9mIHdvcmRzLiAKCkJ1dCBtYW55IG9mIHRoZSB3b3JkcyB3ZSB1c2UgYXJlIHJlcGV0aXRpb25zOiBXb3JkcyBsaWtlICd0aGUnIGFuZCAnYScgYXJlIHVzZWQgb3ZlciBhbmQgb3Zlci4gU28gdGhlIG51bWJlciBvZiBkaXN0aW5jdCB3b3JkcyBpcyBsZXNzIHRoYW4gdGhlIHRvdGFsIG51bWJlciBvZiB3b3Jkcy4gV2UgY2FuIGNhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIGRpc3RpbmN0IHdvcmRzIHdpdGggbl9kaXN0aW5jdCgpLgoKQm90aCBvZiB0aGVzZSBtZWFzdXJlcyBhcmUgY2FsY3VsYXRlZCBiZWxvdzoKCmBgYHtyfQpzdWljaWRlX3dvcmRzICU+JSAKICBncm91cF9ieShhdXRob3IpICU+JSAKICBzdW1tYXJpemUobnVtX3dvcmRzID0gbigpLCBsZXhfZGl2ZXJzaXR5ID0gbl9kaXN0aW5jdCh3b3JkKSkKCmBgYAoKVGhlIG51bWJlciBvZiBkaXN0aW5jdCB3b3JkcyBpcyBhIG1lYXN1cmUgb2YgKmxleGljYWwgZGl2ZXJzaXR5Ki4gSXQgaXMgb25lIG1lYXN1cmUgb2YgYW4gaW5kaXZpZHVhbCdzIHZvY2FidWxhcnkuIAoKTWVhc3VyZXMgbGlrZSB0aGlzIGhhdmUgYmVlbiB1c2VkIHRvIGRldGVybWluZSBhdXRob3JzaGlwIChlLmcuLCBpbiBjYXNlcyB3aGVyZSBhIHN1aWNpZGUgbm90ZSBpcyBzdXNwZWN0ZWQgb2YgYmVpbmcgZmFrZSBhbmQgaGF2aW5nIGJlZW4gd3JpdHRlbiBieSBzb21lb25lIGVsc2UpLCBhbmQgc29tZSB3ZWxsLWtub3duIHN0dWRpZXMgaGF2ZSBzaG93biB0aGF0IGxvdyBsaW5ndWlzdGljIGRpdmVyc2l0eSBhdCBhIHlvdW5nIGFnZSBoYXMgYmVlbiBmb3VuZCB0byBwcmVkaWN0IGRlbWVudGlhIGluIG9sZCBhZ2UuCgpJbiBnZW5lcmFsLCBpdCdzIGFwcGFyZW50IHRoYXQgbG9uZ2VyIG5vdGVzIGhhdmUgbW9yZSBkaXN0aW5jdCB3b3Jkcywgd2hpY2ggbWFrZXMgc2Vuc2UuIFRoZSBmb2xsb3dpbmcgaXMgYSBtZWFzdXJlIG9mICpsZXhpY2FsIGRlbnNpdHkqLCB3aGljaCBpcyB0aGUgbnVtYmVyIG9mIGRpc3RpbmN0IHdvcmRzIGRpdmlkZWQgYnkgdGhlIHRvdGFsIG51bWJlciBvZiB3b3Jkcy4gVGhlIGhpZ2hlciB0aGUgbnVtYmVyLCB0aGUgaGlnaGVyIHByb3BvcnRpb24gb2YgZGlzdGluY3Qgd29yZHMgYXJlIGJlaW5nIHVzZWQuIFRoZSBzbWFsbGVyIHRoZSBudW1iZXIsIHRoZSBtb3JlIHJlcGVhdCB3b3JkcyBhcmUgdXNlZC4KCmBgYHtyfQpzdWljaWRlX3dvcmRzICU+JSAKICBncm91cF9ieShhdXRob3IpICU+JSAKICBzdW1tYXJpc2UobnVtX3dvcmRzID0gbigpLAogICAgICAgICAgICBsZXhfZGl2ZXJzaXR5ID0gbl9kaXN0aW5jdCh3b3JkKSwgCiAgICAgICAgICAgIGxleF9kZW5zaXR5ID0gbl9kaXN0aW5jdCh3b3JkKS9uKCkpCmBgYAoKCgpBbm90aGVyIG1lYXN1cmUgcmVsYXRlZCB0byB2ZXJiYWwgY29tcGxleGl0eSBpcyB0aGUgbGVuZ3RoIG9mIHRoZSB3b3JkcywgaS5lLiwgdGhlIG51bWJlciBvZiBjaGFyYWN0ZXJzIGluIGVhY2ggd29yZC4gVGhhdCBjYW4gYmUgY2FsY3VsYXRlZCB3aXRoIG5jaGFyKCkuCgpIZXJlIGlzIGEgdGFibGUgd2l0aCB0aGUgbGVuZ3RoIG9mIHdvcmRzLCB3aXRoIHRoZSBsb25nZXN0IHdvcmRzIGF0IHRoZSB0b3Agb2YgdGhlIHRhYmxlLgoKYGBge3J9CnN1aWNpZGVfd29yZHMgJT4lCiAgbXV0YXRlKHdvcmRfbGVuZ3RoID0gbmNoYXIod29yZCkpICU+JSAKICBkaXN0aW5jdCh3b3JkLCB3b3JkX2xlbmd0aCwgYXV0aG9yKSAlPiUgCiAgYXJyYW5nZSgtd29yZF9sZW5ndGgpCgpgYGAKCgpXZSBjYW4gZ2V0IHRoZSBhdmVyYWdlIHdvcmQgbGVuZ3RoIGZvciBlYWNoIGF1dGhvciBieSB1c2luZyBtZWFuKCkgb24gd29yZF9sZW5ndGg6CgpgYGB7cn0Kc3VpY2lkZV93b3JkcyAlPiUKICBncm91cF9ieShhdXRob3IpICU+JSAKICBtdXRhdGUod29yZF9sZW5ndGggPSBuY2hhcih3b3JkKSkgJT4lIAogIHN1bW1hcml6ZShtZWFuX3dvcmRfbGVuZ3RoID0gbWVhbih3b3JkX2xlbmd0aCkpICU+JSAKICBhcnJhbmdlKC1tZWFuX3dvcmRfbGVuZ3RoKQpgYGAKCgpHcmFwaCB3b3JkIGxlbmd0aCBkaXN0cmlidXRpb25zIGZvciBhbGwgbm90ZXMuCiAgCmBgYHtyfQpzdWljaWRlX3dvcmRzICU+JQogIG11dGF0ZSh3b3JkX2xlbmd0aCA9IG5jaGFyKHdvcmQpKSAlPiUgCiAgZ2dwbG90KGFlcyh3b3JkX2xlbmd0aCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpIApgYGAKClJlY3JlYXRlIHRoZSBhYm92ZSBncmFwaCwgYnV0IG1ha2UgdHdvIGFkZGl0aW9uczogIAoxLiBBZGQgdGhlIGZvbGxvd2luZyBsaW5lOiBmYWNldF93cmFwKHZhcnMoYXV0aG9yKSwgc2NhbGVzID0gImZyZWVfeSIpLiBUaGlzIHdpbGwgY3JlYXRlIG1pbmkgZ3JhcGhzIGZvciBlYWNoIGF1dGhvci4gIAoyLiBBZGQgYSBsaW5lIHdpdGggbGFicyh0aXRsZSA9ICIiKSBhbmQgdGhlbiBwdXQgYSB0aXRsZSBpbiB0aGUgcXVvdGVzLgoKCgoKCgoKCiMjIyBCYXNpYyB3b3JkIGNvdW50cwoKVG8gZ2V0IGEgc2Vuc2Ugb2YgdGhlIGNvbnRlbnQgb2Ygc3VpY2lkZSBub3Rlcywgd2UgY291bGQgbG9vayBhdCB0aGUgbW9zdCBjb21tb24gd29yZHMgdXNlZC4KCmBgYHtyfQpzdWljaWRlX3dvcmRzICU+JSAKICBjb3VudCh3b3JkLCBzb3J0ID0gVCkgCgpgYGAKCgpDb3B5LXBhc3RlIHRoZSBhYm92ZSBjb2RlIGJlbG93LCBhbmQgdGhlbiBzZXBhcmF0ZSB0aGUgd29yZCBjb3VudHMgYnkgYXV0aG9yIGJ5IGFkZGluZyB0aGUgZm9sbG93aW5nIGxpbmUgYmV0d2VlbiB0aGUgdHdvIGxpbmVzIGFib3ZlOiBncm91cF9ieShhdXRob3IpICU+JSAuCgpgYGB7cn0Kc3VpY2lkZV93b3JkcyAlPiUgCiAgZ3JvdXBfYnkoYXV0aG9yKSAlPiUKICBjb3VudCh3b3JkLCBzb3J0ID0gVCkgCgpgYGAKCgoKCgpHcmFwaCB0aGUgbW9zdCBjb21tb24gd29yZHMgZm9yIGVhY2ggYXV0aG9yIGJ5IGNvcHktcGFzdGluZyB0aGUgYWJvdmUgY29kZSBvbiB0b3Agb2YgdGhlIGZvbGxvd2luZy4gTWFrZSBzdXJlIHRvIGNvbm5lY3QgaXQgd2l0aCB0aGUgcGlwZS4KCmBgYHtyfQpzdWljaWRlX3dvcmRzICU+JSAKICBncm91cF9ieShhdXRob3IpICU+JQogIGNvdW50KHdvcmQsIHNvcnQgPSBUKSAlPiUgCiAgdG9wX24oNSkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUod29yZCA9IHJlb3JkZXIod29yZCwgbikpICU+JQogIGdncGxvdChhZXMod29yZCwgbiwgZmlsbCA9IGF1dGhvcikpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgY29vcmRfZmxpcCgpICsKICBmYWNldF93cmFwKH5hdXRob3IsIHNjYWxlcyA9ICJmcmVlIikgKyAgICAgICAgICAgIyBjcmVhdGVzIHNlcGFyYXRlIGdyYXBocyBmb3IgZWFjaCBhdXRob3IKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpICsgICAgICAgICAgICAgICAgICAgICAgICAgIyB1c2VzIGEgbmljZXIgY29sb3Igc2NoZW1lCiAgdGhlbWVfbWluaW1hbCgpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcmVtb3ZlcyB0aGUgZ3JheSBiYWNrZ3JvdW5kCiAgbGFicyh4ID0gTlVMTCwgeSA9ICJNb3N0IGNvbW1vbiB3b3JkcyIpCgoKYGBgCgoKCgojIyMgUmVtb3ZlIHN0b3Agd29yZHMKClRoZSBwcm9ibGVtIGlzIHRoYXQgdGhlIG1vc3QgY29tbW9uIHdvcmRzIGFyZSBub3QgdmVyeSBpbnRlcmVzdGluZzogdGhlLCBvZiwgYW5kLCBldGMuIFRoZXNlIGFyZSBjYWxsZWQgc3RvcCB3b3JkcywgYW5kIHRpZHl0ZXh0IGluY2x1ZGVzIGEgZmlsZSB3aXRoIHRoZW0gc28geW91IGNhbiByZW1vdmUgdGhlbS4gTG9hZCB0aGVtIGFuZCB2aWV3IHRoZW06CgpgYGB7cn0Kc3RvcF93b3JkcyA8LSBnZXRfc3RvcHdvcmRzKCkKc3RvcF93b3JkcyR3b3JkCmBgYAoKVXNlIGFudGlfam9pbiB0byByZW1vdmUgYWxsIHN0b3B3b3Jkcy4gYW50aV9qb2luKCkgaXMgdGhlIG9wcG9zaXRlIG9mIGpvaW46IGl0IHdpbGwgZmluZCB0aGUgd29yZHMgaW4gY29tbW9uIGJldHdlZW4gdGhlIHR3byBkYXRhIGZyYW1lcyAod29yZHMgYW5kIHN0b3Bfd29yZHMgaW4gdGhpcyBjYXNlKSwgcmVtb3ZlIHRoZW0sIGFuZCBsZWF2ZSBhbGwgb3RoZXIgd29yZHMuCgpgYGB7cn0Kc3VpY2lkZV93b3JkcyAlPiUKICBhbnRpX2pvaW4oc3RvcF93b3JkcykKYGBgCgoKVG8gY291bnQgdGhlc2Ugd29yZHMsIGNvcHktcGFzdGUgdGhlIGFib3ZlIGNvZGUgYmVsb3csIGFuZCBwaXBlIGl0IHRvIHRoZSBmb2xsb3dpbmcgbGluZTogY291bnQod29yZCwgc29ydCA9IFQpCgoKCgpTZXBhcmF0ZWQgYnkgYXV0aG9yLgoKYGBge3J9CnN1aWNpZGVfd29yZHMgJT4lCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JSAKICBncm91cF9ieShhdXRob3IpICU+JSAKICBjb3VudCh3b3JkLCBzb3J0ID0gVCkgCgpgYGAKCgpDb3B5IHRoZSBjb2RlIGFib3ZlIGFuZCBwaXBlIGl0IGludG8gdGhlIGZvbGxvd2luZywgd2hpY2ggY3JlYXRlcyBhIGdyYXBoIG9mIHRoZSBtb3N0IGNvbW1vbiB3b3JkcyBpbiBlYWNoIG5vdGUsIGJ1dCBub3cgd2l0aCB0aGUgc3RvcCB3b3JkcyByZW1vdmVkOgoKCmBgYHtyfQpzdWljaWRlX3dvcmRzICU+JQogIGFudGlfam9pbihzdG9wX3dvcmRzKSAlPiUgCiAgZ3JvdXBfYnkoYXV0aG9yKSAlPiUgCiAgY291bnQod29yZCwgc29ydCA9IFQpICU+JSAKCiAgdG9wX24oNSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUKICBnZ3Bsb3QoYWVzKHdvcmQsIG4sIGZpbGwgPSBhdXRob3IpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSAiTW9zdCBjb21tb24gd29yZHMiKSArCiAgZmFjZXRfd3JhcCh2YXJzKGF1dGhvciksIHNjYWxlcyA9ICJmcmVlIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgY29vcmRfZmxpcCgpCgpgYGAKCgoKCgoKCgoKCgojIyBURi1JREYKClRlcm0gZnJlcXVlbmN5LUludmVyc2UgRG9jdW1lbnQgRnJlcXVlbmN5IChURi1JREYpIGlzIGEgbWVhc3VyZSBvZiB0aGUgaW1wb3J0YW5jZSBvZiBhIHdvcmQgaW4gb25lIGRvY3VtZW50IHJlbGF0aXZlIHRvIG90aGVyIGRvY3VtZW50cy4gSXQgZmluZHMgdGhlIHdvcmRzIHRoYXQgYXJlIHVuaXF1ZSB0byBvbmUgZG9jdW1lbnQgb3IgYXV0aG9yLiBJdCdzIGEgbW91dGhmdWwgc28gbGV0J3MgYnJlYWsgaXQgZG93bjogIAoKVGVybSBmcmVxdWVuY3kgKFRGKSA9IHRoZSBudW1iZXIgb2YgdGltZXMgYSB0ZXJtIGFwcGVhcnMgaW4gYSBkb2N1bWVudApEb2N1bWVudCBmcmVxdWVuY3kgKERGKSA9IHRoZSBudW1iZXIgb2Ygb3RoZXIgZG9jdW1lbnRzIHRoYXQgY29udGFpbiB0aGUgd29yZApJbnZlcnNlIGRvY3VtZW50IGZyZXF1ZW5jeSA9IDEvREYuIAoKVEYtSURGID0gVEYgKiBJREYKClNvIGl0J3MgYSBtZWFzdXJlIG9mIGhvdyBvZnRlbiBhIHdvcmQgYXBwZWFycyBpbiBvbmUgZG9jdW1lbnQsIGRpdmlkZWQgYnkgaG93IG9mdGVuIGl0IGFwcGVhcnMgaW4gb3RoZXIgZG9jdW1lbnRzLiAgCgpGb3IgZXhhbXBsZSwgc2F5IHdlIGhhdmUgMTAgd2ViIHBhZ2VzLiBJZiB0aGUgd29yZCAndGhlJyBhcHBlYXJzIGluIG9uZSB3ZWIgcGFnZSAxMiB0aW1lcywgaXRzIFRGID0gMTIuIElmICd0aGUnIGFwcGVhcnMgaW4gYWxsIDEwIG9mIHRoZSB3ZWIgcGFnZXMsIGl0cyBERiA9IDEwIGFuZCBpdHMgSURGID0gMS8xMC4gVGhhdCBtYWtlcyBpdHMgVEYtSURGID0gMTIgKiAxLzEwIG9yIDEuMi4gIApCdXQgaWYgdGhlIHdvcmQgJ2xvdmUnIGFwcGVhcnMgOCB0aW1lcyBvbiBvbmUgd2ViIHBhZ2UsIGJ1dCBhcHBlYXJzIGluIGp1c3QgMyBvZiB0aGUgd2ViIHBhZ2VzIHRvdGFsLCBpdHMgVEYtSURGIHdvdWxkIGJlIDggKiAxLzMgPSA4LzMgb3IgMi43LiAgCk5vdGljZSB0aGF0IHRoZSB3b3JkICdsb3ZlJyBoYXMgYSBoaWdoZXIgVEYtSURGIHRoYW4gdGhlIGNvbW1vbiB3b3JkICd0aGUnLiAnTG92ZScgYXBwZWFycyBvZnRlbiBvbiB0aGF0IHBhZ2UgYW5kIGRvZXNuJ3QgYXBwZWFyIGluIGFsbCBvZiB0aGUgb3RoZXIgcGFnZXMsIHdoaWNoIG1ha2VzIGl0IGltcG9ydGFudCBmb3IgdGhhdCBwYXJ0aWN1bGFyIHBhZ2UuCgpUaGUgbWF0aCBpcyBhY3R1YWxseSBhIGxpdHRsZSBtb3JlIGNvbXBsaWNhdGVkIHRoYW4gdGhhdCwgYW5kIHRoZXJlIGFyZSB2YXJpYXRpb25zIG9uIHRoZSBiYXNpYyBmb3JtdWxhcywgYnV0IHRoYXQncyB0aGUgcHJpbmNpcGxlLgoKU2VlIHRoZSBjaGFwdGVyIG9uIFRGLUlERiBpbiBUZXh0IE1pbmluZyB3aXRoIFIgZm9yIG1vcmUgaW5mb3JtYXRpb246IGh0dHBzOi8vd3d3LnRpZHl0ZXh0bWluaW5nLmNvbS90ZmlkZi5odG1sLgoKCgpUaGUgZm9sbG93aW5nIGxhcmdlIGNvZGUgY2h1bmsgZG9lcyBhbGwgb2YgdGhlIGNhbGN1bGF0aW9ucyBmb3IgVEYtSURGIGluIGEgY291cGxlIG9mIHN0ZXBzLCBhbmQgdGhlbiBzaG93cyBhIHRhYmxlIG9mIHRoZW0uCgpgYGB7cn0Kc3VpY2lkZV93b3JkX2NvdW50cyA8LSBzdWljaWRlX25vdGVzICU+JSAgICAgICAgICAgICAjIFRoaXMgY291bnRzIGVhY2ggd29yZCBwZXIgYXV0aG9yCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB0ZXh0KSAlPiUKICBjb3VudChhdXRob3IsIHdvcmQsIHNvcnQgPSBUUlVFKSAKCnRvdGFsX3dvcmRzIDwtIHN1aWNpZGVfd29yZF9jb3VudHMgJT4lICAgICAgICAgICAgICAgIyBUaGlzIGNvdW50cyB0b3RhbCB3b3JkcyBwZXIgYXV0aG9yCiAgZ3JvdXBfYnkoYXV0aG9yKSAlPiUgCiAgc3VtbWFyaXplKHRvdGFsID0gc3VtKG4pKQoKc3VpY2lkZV93b3JkX2NvdW50cyA8LSBsZWZ0X2pvaW4oc3VpY2lkZV93b3JkX2NvdW50cywgdG90YWxfd29yZHMpICAgICMgSm9pbnMgdGhlIHR3bwoKc3VpY2lkZV90Zl9pZGYgPC0gc3VpY2lkZV93b3JkX2NvdW50cyAlPiUgICAgICAgICAgICAgIyBDYWxjdWxhdGVzIHRmLWlkZgogIGJpbmRfdGZfaWRmKHdvcmQsIGF1dGhvciwgbikKCnN1aWNpZGVfdGZfaWRmICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBEaXNwbGF5cyBpdAogIGFycmFuZ2UoLXRmX2lkZikgICAgICAgICAgICAgICAgICAgICAgICAgIAoKYGBgCgoKCkdyYXBoIGl0LgoKYGBge3J9CnN1aWNpZGVfdGZfaWRmICU+JQogIGFycmFuZ2UoLXRmX2lkZikgJT4lCiAgbXV0YXRlKHdvcmQgPSBmYWN0b3Iod29yZCwgbGV2ZWxzID0gcmV2KHVuaXF1ZSh3b3JkKSkpKSAlPiUgCiAgZ3JvdXBfYnkoYXV0aG9yKSAlPiUgCiAgdG9wX24oNSkgJT4lIAogIGdncGxvdChhZXMod29yZCwgdGZfaWRmLCBmaWxsID0gYXV0aG9yKSkgKwogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gInRmLWlkZiIpICsKICBmYWNldF93cmFwKH5hdXRob3IsIHNjYWxlcyA9ICJmcmVlIikgKwogIGNvb3JkX2ZsaXAoKQoKYGBgCgoKTm90aWNlIHRoYXQsIGFsdGhvdWdoIHdlIGRpZCBub3QgcmVtb3ZlIHRoZSBzdG9wd29yZHMgZm9yIHRoaXMsIHRmLWlkZiBhdXRvbWF0aWNhbGx5IGV4Y2x1ZGVzIG1vc3Qgc3RvcCB3b3JkcyBiZWNhdXNlIHRoZXkgd2lsbCBhcHBlYXIgaW4gYWxsIG9mIHRoZSBub3Rlcy4KCgpUbyBjbGVhbiB0aGlzIGdyYXBoIHVwIGEgbGl0dGxlLCBhZGQgdGhlIGZvbGxvd2luZyBsaW5lczogIAoxLiB0aGVtZV9taW5pbWFsKCksIHdoaWNoIHdpbGwgZ2V0IHJpZCBvZiB0aGUgZ3JleSBiYWNrZ3JvdW5kLCAgIAoyLiBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpLCB3aGljaCB3aWxsIHVzZSBhbiBpbXByb3ZlZCBjb2xvciBwYWxldHRlCjMuIGxhYnModGl0bGUgPSAiTW9zdCBkaXN0aW5jdGl2ZSB3b3JkcyBpbiBlYWNoIHN1aWNpZGUgbm90ZSIpCgpgYGB7cn0Kc3VpY2lkZV90Zl9pZGYgJT4lCiAgYXJyYW5nZSgtdGZfaWRmKSAlPiUKICBtdXRhdGUod29yZCA9IGZhY3Rvcih3b3JkLCBsZXZlbHMgPSByZXYodW5pcXVlKHdvcmQpKSkpICU+JSAKICBncm91cF9ieShhdXRob3IpICU+JSAKICB0b3Bfbig1KSAlPiUgCiAgZ2dwbG90KGFlcyh3b3JkLCB0Zl9pZGYsIGZpbGwgPSBhdXRob3IpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSAidGYtaWRmIikgKwogIGZhY2V0X3dyYXAofmF1dGhvciwgc2NhbGVzID0gImZyZWUiKSArCiAgY29vcmRfZmxpcCgpCiAgdGhlbWVfbWluaW1hbCgpCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKQogIGxhYnModGl0bGUgPSAiTW9zdCBkaXN0aW5jdGl2ZSB3b3JkcyBpbiBlYWNoIHN1aWNpZGUgbm90ZSIpCgpgYGAKCgoKCgoKCkFzc2lnbm1lbnQ6ClJlYWQgaW4gdGhlIGZpbGUgY2FsbGVkIG1hbmlmZXN0b3MueHNseC4gSXQgY29udGFpbnMgdGhlIHdyaXRpbmdzIG9mIHNldmVyYWwgbWFzcyBraWxsZXJzLCBpbmN1ZGluZyB0aGUgVW5hYm9tYmVyLCBBbmRlcnMgQnJlaXZpayB3aG8ga2lsbGVkIDcwKyBwZW9wbGUgaW4gTm9yd2F5LCBQZWtrYS1FcmljIEF1dmluZW4gYSBzY2hvb2wgc2hvb3RlciBmcm9tIEZpbmxhbmQsIEVsbGlvdCBSb2RnZXIgd2hvIGtpbGxlZCBwZW9wbGUgaW4gQ2FsaWZvcm5pYSwgU2V1bmctSHVpIENobyB3aG8ga2lsbGVkIHBlb3BsZSBhdCBWaXJnaW5pYSBUZWNoLCBhbmQgQ2hyaXMgSGFycGVyLU1lcmNlciB3aG8ga2lsbGVkIHBlb3BsZSBhdCBhIGNvbGxlZ2UgaW4gT3JlZ29uLiAoSSBjb2xsZWN0ZWQgdGhlc2Ugd3JpdGluZ3MgYW5kIHB1dCB0aGVtIGludG8gYW4gZXhjZWwgZmlsZS4gQnJlaXZpayB3cm90ZSB0aGUgbW9zdCBieSBmYXI7IEkgdG9vayBvbmx5IGEgc21hbGwgcG9ydGlvbiBvZiBoaXMgd3JpdGluZ3MuKQoKMS4gUmVhZCBpbiB0aGUgdGV4dCBhbmQgdW5uZXN0IHRoZSB3b3Jkcy4gIAoyLiBHZW5lcmF0ZSBhIHRhYmxlIHRoYXQgaW5jbHVkZXMgYm90aCBsZXhpY2FsIGRpdmVyc2l0eSBhbmQgZGVuc2l0eSwgYW5kIHRoZSB0b3RhbCBudW1iZXIgb2Ygd29yZHMsIG9mIGVhY2ggZG9jdW1lbnQuICAKMy4gR2VuZXJhdGUgYSB0YWJsZSB3aXRoIHRoZSBtZWFuIHdvcmQgbGVuZ3RoIG9mIGVhY2ggZG9jdW1lbnQuICAKNC4gR2VuZXJuYXRlIGEgZ3JhcGggd2l0aCBtaW5pIGhpc3RvZ3JhbXMgb2YgZWFjaCBkb2N1bWVudCdzIHdvcmQgbGVuZ3Rocy4gIAo1LiBSZW1vdmUgc3RvcCB3b3JkcyBhbmQgdGhlbiBjcmVhdGUgYSBncmFwaCB3aXRoIHRoZSBtb3N0IGNvbW1vbiB3b3JkcyBpbiBlYWNoIGRvY3VtZW50LiAgCjYuIENhbGN1bGF0ZSB0Zi1pZGZzIGFuZCBjcmVhdGUgYSBncmFwaCBvZiB0aGUgd29yZHMgd2l0aCB0aGUgaGlnaGVzdCB0Zi1pZGZzIGluIGVhY2ggZG9jdW1lbnQuICAKCmBgYHtyfQp0ZXJyb3Jfbm90ZXMgPC0gcmVhZF9leGNlbCgibWFuaWZlc3Rvcy54bHN4IikKCnRlcnJvcl9ub3Rlcwp0ZXJyb3Jfd29yZHMgPC0gdGVycm9yX25vdGVzICU+JQogIHVubmVzdF90b2tlbnMod29yZCwgdGV4dCkKCnRlcnJvcl93b3JkcwpgYGAKc3RlcCAxCgpgYGB7cn0KdGVycm9yX3dvcmRzICU+JSAKICBncm91cF9ieShhdXRob3IpICU+JSAKICBzdW1tYXJpc2UobnVtX3dvcmRzID0gbigpLAogICAgICAgICAgICBsZXhfZGl2ZXJzaXR5ID0gbl9kaXN0aW5jdCh3b3JkKSwgCiAgICAgICAgICAgIGxleF9kZW5zaXR5ID0gbl9kaXN0aW5jdCh3b3JkKS9uKCkpCmBgYAoKYGBge3J9CnRlcnJvcl93b3JkcyAlPiUKICBncm91cF9ieShhdXRob3IpICU+JSAKICBtdXRhdGUod29yZF9sZW5ndGggPSBuY2hhcih3b3JkKSkgJT4lIAogIHN1bW1hcml6ZShtZWFuX3dvcmRfbGVuZ3RoID0gbWVhbih3b3JkX2xlbmd0aCkpICU+JSAKICBhcnJhbmdlKC1tZWFuX3dvcmRfbGVuZ3RoKQpgYGAKCmBgYHtyfQp0ZXJyb3Jfd29yZHMgJT4lIAogIGdyb3VwX2J5KGF1dGhvcikgJT4lCiAgY291bnQod29yZCwgc29ydCA9IFQpICU+JSAKICB0b3Bfbig1KSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBuKSkgJT4lCiAgZ2dwbG90KGFlcyh3b3JkLCBuLCBmaWxsID0gYXV0aG9yKSkgKwogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBjb29yZF9mbGlwKCkgKwogIGZhY2V0X3dyYXAofmF1dGhvciwgc2NhbGVzID0gImZyZWUiKSArICAgICAgICAgICAjIGNyZWF0ZXMgc2VwYXJhdGUgZ3JhcGhzIGZvciBlYWNoIGF1dGhvcgogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKyAgICAgICAgICAgICAgICAgICAgICAgICAjIHVzZXMgYSBuaWNlciBjb2xvciBzY2hlbWUKICB0aGVtZV9taW5pbWFsKCkgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByZW1vdmVzIHRoZSBncmF5IGJhY2tncm91bmQKICBsYWJzKHggPSBOVUxMLCB5ID0gIk1vc3QgY29tbW9uIHdvcmRzIikKCgpgYGAKYGBge3J9CnRlcnJvcl93b3JkX2NvdW50cyA8LSB0ZXJyb3Jfbm90ZXMgJT4lICAgICAgICAgICAgICMgVGhpcyBjb3VudHMgZWFjaCB3b3JkIHBlciBhdXRob3IKICB1bm5lc3RfdG9rZW5zKHdvcmQsIHRleHQpICU+JQogIGNvdW50KGF1dGhvciwgd29yZCwgc29ydCA9IFRSVUUpIAoKdG90YWxfd29yZHMgPC0gdGVycm9yX3dvcmRfY291bnRzICU+JSAgICAgICAgICAgICAgICMgVGhpcyBjb3VudHMgdG90YWwgd29yZHMgcGVyIGF1dGhvcgogIGdyb3VwX2J5KGF1dGhvcikgJT4lIAogIHN1bW1hcml6ZSh0b3RhbCA9IHN1bShuKSkKCnRlcnJvcl93b3JkX2NvdW50cyA8LSBsZWZ0X2pvaW4odGVycm9yX3dvcmRfY291bnRzLCB0b3RhbF93b3JkcykgICAgIyBKb2lucyB0aGUgdHdvCgp0ZXJyb3JfdGZfaWRmIDwtIHRlcnJvcl93b3JkX2NvdW50cyAlPiUgICAgICAgICAgICAgIyBDYWxjdWxhdGVzIHRmLWlkZgogIGJpbmRfdGZfaWRmKHdvcmQsIGF1dGhvciwgbikKCnRlcnJvcl90Zl9pZGYgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIERpc3BsYXlzIGl0CiAgYXJyYW5nZSgtdGZfaWRmKSAgICAgICAgICAgICAgICAgICAgICAgICAgCgpgYGAKYGBge3J9CnRlcnJvcl90Zl9pZGYgJT4lCiAgYXJyYW5nZSgtdGZfaWRmKSAlPiUKICBtdXRhdGUod29yZCA9IGZhY3Rvcih3b3JkLCBsZXZlbHMgPSByZXYodW5pcXVlKHdvcmQpKSkpICU+JSAKICBncm91cF9ieShhdXRob3IpICU+JSAKICB0b3Bfbig1KSAlPiUgCiAgZ2dwbG90KGFlcyh3b3JkLCB0Zl9pZGYsIGZpbGwgPSBhdXRob3IpKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSAidGYtaWRmIikgKwogIGZhY2V0X3dyYXAofmF1dGhvciwgc2NhbGVzID0gImZyZWUiKSArCiAgY29vcmRfZmxpcCgpCiAgdGhlbWVfbWluaW1hbCgpCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKQogIGxhYnModGl0bGUgPSAiTW9zdCBkaXN0aW5jdGl2ZSB3b3JkcyBpbiBlYWNoIHRlcnJvciBub3RlIikKCmBgYA==