Today we will take a look at the first part of Chapter 4, about n-grams and the Case Study in Chapter 8, mining NASA metadata. NASA data is available online in JSON format.

Chapter 4

Consecutive sequence of words.

library(dplyr)
library(tidytext)
library(janeaustenr)
austen_bigrams <- austen_books() %>%
  unnest_tokens(bigram, text, token = "ngrams", n = 2)
austen_bigrams
austen_bigrams %>%
  count(bigram, sort = TRUE)
library(tidyr)
bigrams_separated <- austen_bigrams %>%
  separate(bigram, c("word1", "word2"), sep = " ")
bigrams_filtered <- bigrams_separated %>%
  filter(!word1 %in% stop_words$word) %>%
  filter(!word2 %in% stop_words$word)
# new bigram counts:
bigram_counts <- bigrams_filtered %>% 
  count(word1, word2, sort = TRUE)
bigram_counts
bigrams_united <- bigrams_filtered %>%
  unite(bigram, word1, word2, sep = " ")
bigrams_united
austen_books() %>%
  unnest_tokens(trigram, text, token = "ngrams", n = 3) %>%
  separate(trigram, c("word1", "word2", "word3"), sep = " ") %>%
  filter(!word1 %in% stop_words$word,
         !word2 %in% stop_words$word,
         !word3 %in% stop_words$word) %>%
  count(word1, word2, word3, sort = TRUE)
bigrams_filtered %>%
  filter(word2 == "street") %>%
  count(book, word1, sort = TRUE)
bigram_tf_idf <- bigrams_united %>%
  count(book, bigram) %>%
  bind_tf_idf(bigram, book, n) %>%
  arrange(desc(tf_idf))
bigram_tf_idf
bigrams_separated %>%
  filter(word1 == "not") %>%
  count(word1, word2, sort = TRUE)
AFINN <- get_sentiments("afinn")
AFINN
not_words <- bigrams_separated %>%
  filter(word1 == "not") %>%
  inner_join(AFINN, by = c(word2 = "word")) %>%
  count(word2, score, sort = TRUE) %>%
  ungroup()
not_words
not_words %>%
  mutate(contribution = n * score) %>%
  arrange(desc(abs(contribution))) %>%
  head(20) %>%
  mutate(word2 = reorder(word2, contribution)) %>%
  ggplot(aes(word2, n * score, fill = n * score > 0)) +
  geom_col(show.legend = FALSE) +
  xlab("Words preceded by \"not\"") +
  ylab("Sentiment score * number of occurrences") +
  coord_flip()

negation_words <- c("not", "no", "never", "without")
negated_words <- bigrams_separated %>%
  filter(word1 %in% negation_words) %>%
  inner_join(AFINN, by = c(word2 = "word")) %>%
  count(word1, word2, score, sort = TRUE) %>%
  ungroup()
library(igraph)
# original counts
bigram_counts
# filter for only relatively common combinations
bigram_graph <- bigram_counts %>%
  filter(n > 20) %>%
  graph_from_data_frame()
bigram_graph
IGRAPH e854329 DN-- 91 77 -- 
+ attr: name (v/c), n (e/n)
+ edges from e854329 (vertex names):
 [1] sir     ->thomas     miss    ->crawford   captain ->wentworth 
 [4] miss    ->woodhouse  frank   ->churchill  lady    ->russell   
 [7] lady    ->bertram    sir     ->walter     miss    ->fairfax   
[10] colonel ->brandon    miss    ->bates      lady    ->catherine 
[13] sir     ->john       jane    ->fairfax    miss    ->tilney    
[16] lady    ->middleton  miss    ->bingley    thousand->pounds    
[19] miss    ->dashwood   miss    ->bennet     john    ->knightley 
[22] miss    ->morland    captain ->benwick    dear    ->miss      
+ ... omitted several edges
library(ggraph)
set.seed(2017)
ggraph(bigram_graph, layout = "fr") +
  geom_edge_link() +
  geom_node_point() +
  geom_node_text(aes(label = name), vjust = 1, hjust = 1)

Chapter 8

Get the metadata about the datasets and variables.

library(jsonlite)
metadata <- fromJSON("https://data.nasa.gov/data.json")
names(metadata$dataset)
 [1] "_id"                "@type"              "accessLevel"       
 [4] "accrualPeriodicity" "bureauCode"         "contactPoint"      
 [7] "description"        "distribution"       "identifier"        
[10] "issued"             "keyword"            "landingPage"       
[13] "language"           "modified"           "programCode"       
[16] "publisher"          "spatial"            "temporal"          
[19] "theme"              "title"              "license"           
[22] "references"         "rights"             "describedBy"       
class(metadata$dataset$title)
[1] "character"
class(metadata$dataset$description)
[1] "character"
class(metadata$dataset$keyword)
[1] "list"

Title, description, and keywords.

library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
nasa_title <- data_frame(id = metadata$dataset$`_id`$`$oid`, 
                         title = metadata$dataset$title)
nasa_title
nasa_desc <- data_frame(id = metadata$dataset$`_id`$`$oid`, 
                        desc = metadata$dataset$description)
nasa_desc %>% 
  select(desc) %>% 
  sample_n(5)
library(tidyr)
nasa_keyword <- data_frame(id = metadata$dataset$`_id`$`$oid`, 
                           keyword = metadata$dataset$keyword) %>%
  unnest(keyword)
nasa_keyword
library(tidytext)
nasa_title <- nasa_title %>% 
  unnest_tokens(word, title) %>% 
  anti_join(stop_words)
Joining, by = "word"
nasa_desc <- nasa_desc %>% 
  unnest_tokens(word, desc) %>% 
  anti_join(stop_words)
Joining, by = "word"
nasa_title
nasa_desc

Word counts.

nasa_title %>%
  count(word, sort = TRUE)
nasa_desc %>% 
  count(word, sort = TRUE)
my_stopwords <- data_frame(word = c(as.character(1:10), 
                                    "v1", "v03", "l2", "l3", "l4", "v5.2.0", 
                                    "v003", "v004", "v005", "v006", "v7"))
nasa_title <- nasa_title %>% 
  anti_join(my_stopwords)
Joining, by = "word"
nasa_desc <- nasa_desc %>% 
  anti_join(my_stopwords)
Joining, by = "word"
nasa_keyword %>% 
  group_by(keyword) %>% 
  count(sort = TRUE)
nasa_keyword <- nasa_keyword %>% 
  mutate(keyword = toupper(keyword))

Word co-occurences and correlations from Chapter 4

library(widyr)
title_word_pairs <- nasa_title %>% 
  pairwise_count(word, id, sort = TRUE, upper = FALSE)
title_word_pairs

Plot co-occuring words. In the description field.

library(ggplot2)
library(igraph)

Attaching package: ‘igraph’

The following object is masked from ‘package:tidyr’:

    crossing

The following objects are masked from ‘package:dplyr’:

    as_data_frame, groups, union

The following objects are masked from ‘package:stats’:

    decompose, spectrum

The following object is masked from ‘package:base’:

    union
library(ggraph)
set.seed(1234)
title_word_pairs %>%
  filter(n >= 250) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
  geom_edge_link(aes(edge_alpha = n, edge_width = n), edge_colour = "cyan4") +
  geom_node_point(size = 5) +
  geom_node_text(aes(label = name), repel = TRUE, 
                 point.padding = unit(0.2, "lines")) +
  theme_void()

Network of Kewords.

keyword_pairs <- nasa_keyword %>% 
  pairwise_count(keyword, id, sort = TRUE, upper = FALSE)
keyword_pairs
set.seed(1234)
keyword_pairs %>%
  filter(n >= 700) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
  geom_edge_link(aes(edge_alpha = n, edge_width = n), edge_colour = "royalblue") +
  geom_node_point(size = 5) +
  geom_node_text(aes(label = name), repel = TRUE,
                 point.padding = unit(0.2, "lines")) +
  theme_void()

LS0tCnRpdGxlOiAiQ2hhcHRlciA0ICYgOCAtIG4tZ3JhbXMsIG5hc2EgZGF0YSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKClRvZGF5IHdlIHdpbGwgdGFrZSBhIGxvb2sgYXQgdGhlIGZpcnN0IHBhcnQgb2YgQ2hhcHRlciA0LCBhYm91dCBuLWdyYW1zIGFuZCB0aGUgQ2FzZSBTdHVkeSBpbiBDaGFwdGVyIDgsIG1pbmluZyBOQVNBIG1ldGFkYXRhLiAgTkFTQSBkYXRhIGlzIGF2YWlsYWJsZSBvbmxpbmUgaW4gSlNPTiBmb3JtYXQuCgojIENoYXB0ZXIgNAoKQ29uc2VjdXRpdmUgc2VxdWVuY2Ugb2Ygd29yZHMuCgpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeShqYW5lYXVzdGVucikKCmF1c3Rlbl9iaWdyYW1zIDwtIGF1c3Rlbl9ib29rcygpICU+JQogIHVubmVzdF90b2tlbnMoYmlncmFtLCB0ZXh0LCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikKCmF1c3Rlbl9iaWdyYW1zCmBgYAoKYGBge3J9CmF1c3Rlbl9iaWdyYW1zICU+JQogIGNvdW50KGJpZ3JhbSwgc29ydCA9IFRSVUUpCmBgYAoKYGBge3J9CmxpYnJhcnkodGlkeXIpCgpiaWdyYW1zX3NlcGFyYXRlZCA8LSBhdXN0ZW5fYmlncmFtcyAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikKCmJpZ3JhbXNfZmlsdGVyZWQgPC0gYmlncmFtc19zZXBhcmF0ZWQgJT4lCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHN0b3Bfd29yZHMkd29yZCkgJT4lCiAgZmlsdGVyKCF3b3JkMiAlaW4lIHN0b3Bfd29yZHMkd29yZCkKCiMgbmV3IGJpZ3JhbSBjb3VudHM6CmJpZ3JhbV9jb3VudHMgPC0gYmlncmFtc19maWx0ZXJlZCAlPiUgCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkKCmJpZ3JhbV9jb3VudHMKYGBgCgpgYGB7cn0KYmlncmFtc191bml0ZWQgPC0gYmlncmFtc19maWx0ZXJlZCAlPiUKICB1bml0ZShiaWdyYW0sIHdvcmQxLCB3b3JkMiwgc2VwID0gIiAiKQoKYmlncmFtc191bml0ZWQKYGBgCgpgYGB7cn0KYXVzdGVuX2Jvb2tzKCkgJT4lCiAgdW5uZXN0X3Rva2Vucyh0cmlncmFtLCB0ZXh0LCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMykgJT4lCiAgc2VwYXJhdGUodHJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiLCAid29yZDMiKSwgc2VwID0gIiAiKSAlPiUKICBmaWx0ZXIoIXdvcmQxICVpbiUgc3RvcF93b3JkcyR3b3JkLAogICAgICAgICAhd29yZDIgJWluJSBzdG9wX3dvcmRzJHdvcmQsCiAgICAgICAgICF3b3JkMyAlaW4lIHN0b3Bfd29yZHMkd29yZCkgJT4lCiAgY291bnQod29yZDEsIHdvcmQyLCB3b3JkMywgc29ydCA9IFRSVUUpCmBgYAoKYGBge3J9CmJpZ3JhbXNfZmlsdGVyZWQgJT4lCiAgZmlsdGVyKHdvcmQyID09ICJzdHJlZXQiKSAlPiUKICBjb3VudChib29rLCB3b3JkMSwgc29ydCA9IFRSVUUpCmBgYAoKYGBge3J9CmJpZ3JhbV90Zl9pZGYgPC0gYmlncmFtc191bml0ZWQgJT4lCiAgY291bnQoYm9vaywgYmlncmFtKSAlPiUKICBiaW5kX3RmX2lkZihiaWdyYW0sIGJvb2ssIG4pICU+JQogIGFycmFuZ2UoZGVzYyh0Zl9pZGYpKQoKYmlncmFtX3RmX2lkZgpgYGAKCmBgYHtyfQpiaWdyYW1zX3NlcGFyYXRlZCAlPiUKICBmaWx0ZXIod29yZDEgPT0gIm5vdCIpICU+JQogIGNvdW50KHdvcmQxLCB3b3JkMiwgc29ydCA9IFRSVUUpCmBgYAoKYGBge3J9CkFGSU5OIDwtIGdldF9zZW50aW1lbnRzKCJhZmlubiIpCgpBRklOTgpgYGAKCmBgYHtyfQpub3Rfd29yZHMgPC0gYmlncmFtc19zZXBhcmF0ZWQgJT4lCiAgZmlsdGVyKHdvcmQxID09ICJub3QiKSAlPiUKICBpbm5lcl9qb2luKEFGSU5OLCBieSA9IGMod29yZDIgPSAid29yZCIpKSAlPiUKICBjb3VudCh3b3JkMiwgc2NvcmUsIHNvcnQgPSBUUlVFKSAlPiUKICB1bmdyb3VwKCkKCm5vdF93b3JkcwpgYGAKCmBgYHtyfQpub3Rfd29yZHMgJT4lCiAgbXV0YXRlKGNvbnRyaWJ1dGlvbiA9IG4gKiBzY29yZSkgJT4lCiAgYXJyYW5nZShkZXNjKGFicyhjb250cmlidXRpb24pKSkgJT4lCiAgaGVhZCgyMCkgJT4lCiAgbXV0YXRlKHdvcmQyID0gcmVvcmRlcih3b3JkMiwgY29udHJpYnV0aW9uKSkgJT4lCiAgZ2dwbG90KGFlcyh3b3JkMiwgbiAqIHNjb3JlLCBmaWxsID0gbiAqIHNjb3JlID4gMCkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgeGxhYigiV29yZHMgcHJlY2VkZWQgYnkgXCJub3RcIiIpICsKICB5bGFiKCJTZW50aW1lbnQgc2NvcmUgKiBudW1iZXIgb2Ygb2NjdXJyZW5jZXMiKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKYGBge3J9Cm5lZ2F0aW9uX3dvcmRzIDwtIGMoIm5vdCIsICJubyIsICJuZXZlciIsICJ3aXRob3V0IikKCm5lZ2F0ZWRfd29yZHMgPC0gYmlncmFtc19zZXBhcmF0ZWQgJT4lCiAgZmlsdGVyKHdvcmQxICVpbiUgbmVnYXRpb25fd29yZHMpICU+JQogIGlubmVyX2pvaW4oQUZJTk4sIGJ5ID0gYyh3b3JkMiA9ICJ3b3JkIikpICU+JQogIGNvdW50KHdvcmQxLCB3b3JkMiwgc2NvcmUsIHNvcnQgPSBUUlVFKSAlPiUKICB1bmdyb3VwKCkKYGBgCgpgYGB7cn0KbGlicmFyeShpZ3JhcGgpCgojIG9yaWdpbmFsIGNvdW50cwpiaWdyYW1fY291bnRzCmBgYAoKYGBge3J9CiMgZmlsdGVyIGZvciBvbmx5IHJlbGF0aXZlbHkgY29tbW9uIGNvbWJpbmF0aW9ucwpiaWdyYW1fZ3JhcGggPC0gYmlncmFtX2NvdW50cyAlPiUKICBmaWx0ZXIobiA+IDIwKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKQoKYmlncmFtX2dyYXBoCmBgYAoKYGBge3J9CmxpYnJhcnkoZ2dyYXBoKQpzZXQuc2VlZCgyMDE3KQoKZ2dyYXBoKGJpZ3JhbV9ncmFwaCwgbGF5b3V0ID0gImZyIikgKwogIGdlb21fZWRnZV9saW5rKCkgKwogIGdlb21fbm9kZV9wb2ludCgpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgdmp1c3QgPSAxLCBoanVzdCA9IDEpCmBgYAoKCgoKIyBDaGFwdGVyIDgKCkdldCB0aGUgbWV0YWRhdGEgYWJvdXQgdGhlIGRhdGFzZXRzIGFuZCB2YXJpYWJsZXMuCgpgYGB7cn0KbGlicmFyeShqc29ubGl0ZSkKbWV0YWRhdGEgPC0gZnJvbUpTT04oImh0dHBzOi8vZGF0YS5uYXNhLmdvdi9kYXRhLmpzb24iKQpuYW1lcyhtZXRhZGF0YSRkYXRhc2V0KQpgYGAKCmBgYHtyfQpjbGFzcyhtZXRhZGF0YSRkYXRhc2V0JHRpdGxlKQpgYGAKCmBgYHtyfQpjbGFzcyhtZXRhZGF0YSRkYXRhc2V0JGRlc2NyaXB0aW9uKQpgYGAKCmBgYHtyfQpjbGFzcyhtZXRhZGF0YSRkYXRhc2V0JGtleXdvcmQpCmBgYAoKVGl0bGUsIGRlc2NyaXB0aW9uLCBhbmQga2V5d29yZHMuCgpgYGB7cn0KbGlicmFyeShkcGx5cikKCm5hc2FfdGl0bGUgPC0gZGF0YV9mcmFtZShpZCA9IG1ldGFkYXRhJGRhdGFzZXQkYF9pZGAkYCRvaWRgLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gbWV0YWRhdGEkZGF0YXNldCR0aXRsZSkKbmFzYV90aXRsZQpgYGAKCgpgYGB7cn0KbmFzYV9kZXNjIDwtIGRhdGFfZnJhbWUoaWQgPSBtZXRhZGF0YSRkYXRhc2V0JGBfaWRgJGAkb2lkYCwgCiAgICAgICAgICAgICAgICAgICAgICAgIGRlc2MgPSBtZXRhZGF0YSRkYXRhc2V0JGRlc2NyaXB0aW9uKQoKbmFzYV9kZXNjICU+JSAKICBzZWxlY3QoZGVzYykgJT4lIAogIHNhbXBsZV9uKDUpCmBgYAoKYGBge3J9CmxpYnJhcnkodGlkeXIpCgpuYXNhX2tleXdvcmQgPC0gZGF0YV9mcmFtZShpZCA9IG1ldGFkYXRhJGRhdGFzZXQkYF9pZGAkYCRvaWRgLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5d29yZCA9IG1ldGFkYXRhJGRhdGFzZXQka2V5d29yZCkgJT4lCiAgdW5uZXN0KGtleXdvcmQpCgpuYXNhX2tleXdvcmQKYGBgCgpgYGB7cn0KbGlicmFyeSh0aWR5dGV4dCkKCm5hc2FfdGl0bGUgPC0gbmFzYV90aXRsZSAlPiUgCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB0aXRsZSkgJT4lIAogIGFudGlfam9pbihzdG9wX3dvcmRzKQoKbmFzYV9kZXNjIDwtIG5hc2FfZGVzYyAlPiUgCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCBkZXNjKSAlPiUgCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpCmBgYAoKYGBge3J9Cm5hc2FfdGl0bGUKYGBgCgpgYGB7cn0KbmFzYV9kZXNjCmBgYAoKV29yZCBjb3VudHMuCgpgYGB7cn0KbmFzYV90aXRsZSAlPiUKICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkKYGBgCgoKYGBge3J9Cm5hc2FfZGVzYyAlPiUgCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpCmBgYAoKYGBge3J9Cm15X3N0b3B3b3JkcyA8LSBkYXRhX2ZyYW1lKHdvcmQgPSBjKGFzLmNoYXJhY3RlcigxOjEwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ2MSIsICJ2MDMiLCAibDIiLCAibDMiLCAibDQiLCAidjUuMi4wIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ2MDAzIiwgInYwMDQiLCAidjAwNSIsICJ2MDA2IiwgInY3IikpCm5hc2FfdGl0bGUgPC0gbmFzYV90aXRsZSAlPiUgCiAgYW50aV9qb2luKG15X3N0b3B3b3JkcykKbmFzYV9kZXNjIDwtIG5hc2FfZGVzYyAlPiUgCiAgYW50aV9qb2luKG15X3N0b3B3b3JkcykKYGBgCgpgYGB7cn0KbmFzYV9rZXl3b3JkICU+JSAKICBncm91cF9ieShrZXl3b3JkKSAlPiUgCiAgY291bnQoc29ydCA9IFRSVUUpCmBgYAoKYGBge3J9Cm5hc2Ffa2V5d29yZCA8LSBuYXNhX2tleXdvcmQgJT4lIAogIG11dGF0ZShrZXl3b3JkID0gdG91cHBlcihrZXl3b3JkKSkKYGBgCgojIFdvcmQgY28tb2NjdXJlbmNlcyBhbmQgY29ycmVsYXRpb25zIGZyb20gQ2hhcHRlciA0CgpgYGB7cn0KbGlicmFyeSh3aWR5cikKCnRpdGxlX3dvcmRfcGFpcnMgPC0gbmFzYV90aXRsZSAlPiUgCiAgcGFpcndpc2VfY291bnQod29yZCwgaWQsIHNvcnQgPSBUUlVFLCB1cHBlciA9IEZBTFNFKQoKdGl0bGVfd29yZF9wYWlycwpgYGAKCgoKUGxvdCBjby1vY2N1cmluZyB3b3Jkcy4gIEluIHRoZSBkZXNjcmlwdGlvbiBmaWVsZC4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KGdncmFwaCkKCnNldC5zZWVkKDEyMzQpCnRpdGxlX3dvcmRfcGFpcnMgJT4lCiAgZmlsdGVyKG4gPj0gMjUwKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogIGdlb21fZWRnZV9saW5rKGFlcyhlZGdlX2FscGhhID0gbiwgZWRnZV93aWR0aCA9IG4pLCBlZGdlX2NvbG91ciA9ICJjeWFuNCIpICsKICBnZW9tX25vZGVfcG9pbnQoc2l6ZSA9IDUpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWwgPSBUUlVFLCAKICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gdW5pdCgwLjIsICJsaW5lcyIpKSArCiAgdGhlbWVfdm9pZCgpCmBgYAoKTmV0d29yayBvZiBLZXdvcmRzLgoKYGBge3J9CmtleXdvcmRfcGFpcnMgPC0gbmFzYV9rZXl3b3JkICU+JSAKICBwYWlyd2lzZV9jb3VudChrZXl3b3JkLCBpZCwgc29ydCA9IFRSVUUsIHVwcGVyID0gRkFMU0UpCgprZXl3b3JkX3BhaXJzCmBgYAoKYGBge3J9CnNldC5zZWVkKDEyMzQpCmtleXdvcmRfcGFpcnMgJT4lCiAgZmlsdGVyKG4gPj0gNzAwKSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogIGdlb21fZWRnZV9saW5rKGFlcyhlZGdlX2FscGhhID0gbiwgZWRnZV93aWR0aCA9IG4pLCBlZGdlX2NvbG91ciA9ICJyb3lhbGJsdWUiKSArCiAgZ2VvbV9ub2RlX3BvaW50KHNpemUgPSA1KSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsID0gVFJVRSwKICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gdW5pdCgwLjIsICJsaW5lcyIpKSArCiAgdGhlbWVfdm9pZCgpCmBgYAoKCgoKCgo=