library(geniusr) # This package gets lyrics
library(tidyverse)
library(tidytext)
library(wordcloud2)
genius_token()
[1] "r6MbEOV_SiYagrS_8dNLGuji0Eh6CPwyYHGYyk7Zn0hlfmkcre6XD8C1C0cDx2A1"
- I want to look at lyrics by The Vines, an Australian rock band that were successful briefly in the early 2000’s, specifically from their debut album Highly Evolved.
To do so, I am using the Genius.com API, which contains a repository of song lyrics.
I remember the name of a song from the album, “Get Free,” and I want to see what other songs might be called by that name first, and make sure I choose the right one.
search_song("get free")
Okay, I see the song ID I want for the correct artists, so I’ll tell R to show me information about this song, including the album ID.
get_song_meta(897254)
Great, now I know the album ID for the album I want to look at, Highly Evolved. So I’ll tell R to “scrape” a track list from that album.
evolved_tracks <- scrape_tracklist(214505)
evolved_tracks
Now that I have the list of all songs from that album, I can tell R to load the lyrics from each of them.
evolved_lyrics <- map_df(evolved_tracks$song_lyrics_url, scrape_lyrics_url)
evolved_lyrics
NA
As we can see, these lyrics are all in fairly long strings. I want to analyze individual words from these lyrics, so I’ll tell R to unnest them.
evolved_words <- evolved_lyrics %>%
unnest_tokens(word, line) %>%
select(song_name, word)
evolved_words
That’s better! But there’s a lot of stopwords in there (so, a, etc.)… therefore I wish to…
- Remove all of the stopwords from these lyrics.
evolved_words %>%
anti_join(get_stopwords()) %>%
count(word, sort = T)
Joining, by = "word"
That looks better! But what would this new list look like in the form of a wordcloud? Let’s tell R to show us…
evolved_words %>%
anti_join(get_stopwords()) %>%
count(word, sort = T) %>%
top_n(200) %>%
wordcloud2(size = .5)
Joining, by = "word"
Selecting by n
- Now I want to use sentiment analysis to see which words, for example, carry positive connotations and which carry negative connotations from these lyrics.
In order to a sentiment analysis, we need a dictionary to inform us what the sentiment of any given word is likely to be (obviously, this is an imperfect art).
First, I will use the bing sentiment dictionary.
bing <- get_sentiments("bing")
bing
Now that I have loaded in the bing sentiment dictionary (which we can see above), I want to apply its contents to the lyrics.
evolved_words %>%
inner_join(bing) %>%
count(word, sentiment, sort = TRUE)
Joining, by = "word"
This looks fairly straight-forward to me. Let’s graph it!
evolved_words %>%
inner_join(bing) %>%
count(word, sentiment, sort = TRUE) %>%
group_by(sentiment) %>%
top_n(10) %>%
ungroup() %>%
mutate(word = reorder(word, n)) %>%
ggplot(aes(word, n, fill = sentiment)) +
geom_col(show.legend = FALSE) +
facet_wrap(vars(sentiment), scales = "free") +
labs(y = "The Vines's Highly Evolved album: Words that contribute the most to each sentiment",
x = NULL) +
scale_fill_viridis_d() +
coord_flip() +
theme_minimal()
Joining, by = "word"
Selecting by n

Now I want to look at sentiments using a different sentiment dictionary, called NRC.
nrc <- get_sentiments("nrc")
nrc
evolved_words %>%
inner_join(nrc) %>%
count(word, sentiment, sort = TRUE)
Joining, by = "word"
evolved_words %>%
inner_join(nrc) %>%
count(word, sentiment, sort = TRUE) %>%
group_by(sentiment) %>%
top_n(3) %>%
ungroup() %>%
mutate(word = reorder(word, n)) %>%
ggplot(aes(word, n, fill = sentiment)) +
geom_col(show.legend = FALSE) +
facet_wrap(vars(sentiment), scales = "free") +
labs(y = "The Vines's Highly Evolved album: Words that contribute the most to each sentiment",
x = NULL) +
scale_fill_viridis_d() +
coord_flip() +
theme_minimal()
Joining, by = "word"
Selecting by n

- Instead of only examining individual words, let’s take a look at lyrics that are paired together.
evolved_lyrics %>%
unnest_tokens(bigram, line, token = "ngrams", n = 2) %>%
select(bigram)
NA
This looks good, except we get stopwords again. Let’s get rid of those.
evolved_lyrics %>%
unnest_tokens(bigram, line, token = "ngrams", n = 2) %>%
select(bigram) -> evolved_bigrams
evolved_bigrams %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% stop_words$word) %>%
filter(!word2 %in% stop_words$word) %>%
unite(bigram, word1, word2, sep = " ")
NA
That looks better! Now we can tell R to count how many times each pairing occurs.
evolved_bigrams %>%
separate(bigram, c("word1", "word2"), sep = " ") %>%
filter(!word1 %in% stop_words$word) %>%
filter(!word2 %in% stop_words$word) %>%
unite(bigram, word1, word2, sep = " ") %>%
count(bigram, sort = T)
NA
As we can see, the word pairs “gonna get” and “get free” are among the most common.
- I would now like to see what word tends to immediately follow the word “I” and what word tends to immediately follow the word “you,” to see if any intersting difference is apparent.
first_word <- c("i", "you") # these need to be lowercase
evolved_bigrams %>%
count(bigram, sort = T) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>% # separate the two words
filter(word1 %in% first_word) %>% # find first words from our list
count(word1, word2, wt = n, sort = TRUE) %>%
rename(total = nn)
Error: Can't rename columns that don't exist.
x The column `nn` doesn't exist.
Finally, I would like to look at that on a graph.
first_word <- c("i", "you") # these need to be lowercase
evolved_bigrams %>%
count(bigram, sort = T) %>%
separate(bigram, c("word1", "word2"), sep = " ") %>% # separate the two words
filter(word1 %in% first_word) %>% # find first words from our list
count(word1, word2, wt = n, sort = TRUE) %>%
rename(total = nn)
mutate(word2 = factor(word2, levels = rev(unique(word2)))) %>% # put the words in order
group_by(word1) %>%
top_n(5) %>%
ggplot(aes(word2, total, fill = word1)) + #
scale_fill_viridis_d() + # set the color palette
geom_col(show.legend = FALSE) +
labs(x = NULL, y = NULL, title = "Word following:") +
facet_wrap(~word1, scales = "free") +
coord_flip() +
theme_minimal()
LS0tCnRpdGxlOiAiZ2VuaXVzIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKLS0tCgpgYGB7cn0KbGlicmFyeShnZW5pdXNyKSAgICAgICAgICAgICAgICAgICAgICAgICAjIFRoaXMgcGFja2FnZSBnZXRzIGx5cmljcwpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0aWR5dGV4dCkKbGlicmFyeSh3b3JkY2xvdWQyKQpgYGAKCmBgYHtyfQpnZW5pdXNfdG9rZW4oKQpgYGAKCgoKMS4gSSB3YW50IHRvIGxvb2sgYXQgbHlyaWNzIGJ5IFRoZSBWaW5lcywgYW4gQXVzdHJhbGlhbiByb2NrIGJhbmQgdGhhdCB3ZXJlIHN1Y2Nlc3NmdWwgYnJpZWZseSBpbiB0aGUgZWFybHkgMjAwMCdzLCBzcGVjaWZpY2FsbHkgZnJvbSB0aGVpciBkZWJ1dCBhbGJ1bSBIaWdobHkgRXZvbHZlZC4gCgpUbyBkbyBzbywgSSBhbSB1c2luZyB0aGUgR2VuaXVzLmNvbSBBUEksIHdoaWNoIGNvbnRhaW5zIGEgcmVwb3NpdG9yeSBvZiBzb25nIGx5cmljcy4gCgpJIHJlbWVtYmVyIHRoZSBuYW1lIG9mIGEgc29uZyBmcm9tIHRoZSBhbGJ1bSwgIkdldCBGcmVlLCIgYW5kIEkgd2FudCB0byBzZWUgd2hhdCBvdGhlciBzb25ncyBtaWdodCBiZSBjYWxsZWQgYnkgdGhhdCBuYW1lIGZpcnN0LCBhbmQgbWFrZSBzdXJlIEkgY2hvb3NlIHRoZSByaWdodCBvbmUuIAoKCmBgYHtyfQpzZWFyY2hfc29uZygiZ2V0IGZyZWUiKQpgYGAKCk9rYXksIEkgc2VlIHRoZSBzb25nIElEIEkgd2FudCBmb3IgdGhlIGNvcnJlY3QgYXJ0aXN0cywgc28gSSdsbCB0ZWxsIFIgdG8gc2hvdyBtZSBpbmZvcm1hdGlvbiBhYm91dCB0aGlzIHNvbmcsIGluY2x1ZGluZyB0aGUgYWxidW0gSUQuIAoKYGBge3J9CmdldF9zb25nX21ldGEoODk3MjU0KQpgYGAKCkdyZWF0LCBub3cgSSBrbm93IHRoZSBhbGJ1bSBJRCBmb3IgdGhlIGFsYnVtIEkgd2FudCB0byBsb29rIGF0LCBIaWdobHkgRXZvbHZlZC4gU28gSSdsbCB0ZWxsIFIgdG8gInNjcmFwZSIgYSB0cmFjayBsaXN0IGZyb20gdGhhdCBhbGJ1bS4gCgpgYGB7cn0KZXZvbHZlZF90cmFja3MgPC0gc2NyYXBlX3RyYWNrbGlzdCgyMTQ1MDUpCmV2b2x2ZWRfdHJhY2tzCmBgYAoKTm93IHRoYXQgSSBoYXZlIHRoZSBsaXN0IG9mIGFsbCBzb25ncyBmcm9tIHRoYXQgYWxidW0sIEkgY2FuIHRlbGwgUiB0byBsb2FkIHRoZSBseXJpY3MgZnJvbSBlYWNoIG9mIHRoZW0uIAoKYGBge3J9CmV2b2x2ZWRfbHlyaWNzIDwtIG1hcF9kZihldm9sdmVkX3RyYWNrcyRzb25nX2x5cmljc191cmwsIHNjcmFwZV9seXJpY3NfdXJsKQpldm9sdmVkX2x5cmljcwoKYGBgCgpBcyB3ZSBjYW4gc2VlLCB0aGVzZSBseXJpY3MgYXJlIGFsbCBpbiBmYWlybHkgbG9uZyBzdHJpbmdzLiBJIHdhbnQgdG8gYW5hbHl6ZSBpbmRpdmlkdWFsIHdvcmRzIGZyb20gdGhlc2UgbHlyaWNzLCBzbyBJJ2xsIHRlbGwgUiB0byB1bm5lc3QgdGhlbS4gCgpgYGB7cn0KZXZvbHZlZF93b3JkcyA8LSBldm9sdmVkX2x5cmljcyAlPiUKICB1bm5lc3RfdG9rZW5zKHdvcmQsIGxpbmUpICU+JSAKICBzZWxlY3Qoc29uZ19uYW1lLCB3b3JkKQoKZXZvbHZlZF93b3JkcwpgYGAKClRoYXQncyBiZXR0ZXIhIEJ1dCB0aGVyZSdzIGEgbG90IG9mIHN0b3B3b3JkcyBpbiB0aGVyZSAoc28sIGEsIGV0Yy4pLi4uIHRoZXJlZm9yZSBJIHdpc2ggdG8uLi4gCgoKMi4gUmVtb3ZlIGFsbCBvZiB0aGUgc3RvcHdvcmRzIGZyb20gdGhlc2UgbHlyaWNzLiAKCmBgYHtyfQpldm9sdmVkX3dvcmRzICU+JSAKICBhbnRpX2pvaW4oZ2V0X3N0b3B3b3JkcygpKSAlPiUgCiAgY291bnQod29yZCwgc29ydCA9IFQpCmBgYApUaGF0IGxvb2tzIGJldHRlciEgQnV0IHdoYXQgd291bGQgdGhpcyBuZXcgbGlzdCBsb29rIGxpa2UgaW4gdGhlIGZvcm0gb2YgYSB3b3JkY2xvdWQ/IExldCdzIHRlbGwgUiB0byBzaG93IHVzLi4uIAoKYGBge3J9CmV2b2x2ZWRfd29yZHMgJT4lIAogIGFudGlfam9pbihnZXRfc3RvcHdvcmRzKCkpICU+JSAKICBjb3VudCh3b3JkLCBzb3J0ID0gVCkgJT4lCiAgdG9wX24oMjAwKSAlPiUKICB3b3JkY2xvdWQyKHNpemUgPSAuNSkKYGBgCgoKMy4gTm93IEkgd2FudCB0byB1c2Ugc2VudGltZW50IGFuYWx5c2lzIHRvIHNlZSB3aGljaCB3b3JkcywgZm9yIGV4YW1wbGUsIGNhcnJ5IHBvc2l0aXZlIGNvbm5vdGF0aW9ucyBhbmQgd2hpY2ggY2FycnkgbmVnYXRpdmUgY29ubm90YXRpb25zIGZyb20gdGhlc2UgbHlyaWNzLgoKSW4gb3JkZXIgdG8gYSBzZW50aW1lbnQgYW5hbHlzaXMsIHdlIG5lZWQgYSBkaWN0aW9uYXJ5IHRvIGluZm9ybSB1cyB3aGF0IHRoZSBzZW50aW1lbnQgb2YgYW55IGdpdmVuIHdvcmQgaXMgbGlrZWx5IHRvIGJlIChvYnZpb3VzbHksIHRoaXMgaXMgYW4gaW1wZXJmZWN0IGFydCkuIAoKRmlyc3QsIEkgd2lsbCB1c2UgdGhlIGJpbmcgc2VudGltZW50IGRpY3Rpb25hcnkuIAoKYGBge3J9CmJpbmcgPC0gZ2V0X3NlbnRpbWVudHMoImJpbmciKQpiaW5nCmBgYAoKTm93IHRoYXQgSSBoYXZlIGxvYWRlZCBpbiB0aGUgYmluZyBzZW50aW1lbnQgZGljdGlvbmFyeSAod2hpY2ggd2UgY2FuIHNlZSBhYm92ZSksIEkgd2FudCB0byBhcHBseSBpdHMgY29udGVudHMgdG8gdGhlIGx5cmljcy4gCgpgYGB7cn0KZXZvbHZlZF93b3JkcyAlPiUgCiAgaW5uZXJfam9pbihiaW5nKSAlPiUgCiAgY291bnQod29yZCwgc2VudGltZW50LCBzb3J0ID0gVFJVRSkKCmBgYAoKVGhpcyBsb29rcyBmYWlybHkgc3RyYWlnaHQtZm9yd2FyZCB0byBtZS4gTGV0J3MgZ3JhcGggaXQhIAoKYGBge3J9CmV2b2x2ZWRfd29yZHMgJT4lIAogIGlubmVyX2pvaW4oYmluZykgJT4lIAogIGNvdW50KHdvcmQsIHNlbnRpbWVudCwgc29ydCA9IFRSVUUpICU+JQogIGdyb3VwX2J5KHNlbnRpbWVudCkgJT4lCiAgdG9wX24oMTApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUod29yZCA9IHJlb3JkZXIod29yZCwgbikpICU+JQogIGdncGxvdChhZXMod29yZCwgbiwgZmlsbCA9IHNlbnRpbWVudCkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh2YXJzKHNlbnRpbWVudCksIHNjYWxlcyA9ICJmcmVlIikgKwogIGxhYnMoeSA9ICJUaGUgVmluZXMncyBIaWdobHkgRXZvbHZlZCBhbGJ1bTogV29yZHMgdGhhdCBjb250cmlidXRlIHRoZSBtb3N0IHRvIGVhY2ggc2VudGltZW50IiwKICAgICAgIHggPSBOVUxMKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCk5vdyBJIHdhbnQgdG8gbG9vayBhdCBzZW50aW1lbnRzIHVzaW5nIGEgZGlmZmVyZW50IHNlbnRpbWVudCBkaWN0aW9uYXJ5LCBjYWxsZWQgTlJDLiAKCmBgYHtyfQpucmMgPC0gZ2V0X3NlbnRpbWVudHMoIm5yYyIpCm5yYwpgYGAKCgpgYGB7cn0KZXZvbHZlZF93b3JkcyAlPiUgCiAgaW5uZXJfam9pbihucmMpICU+JSAKICBjb3VudCh3b3JkLCBzZW50aW1lbnQsIHNvcnQgPSBUUlVFKQoKYGBgCgpgYGB7cn0KZXZvbHZlZF93b3JkcyAlPiUgCiAgaW5uZXJfam9pbihucmMpICU+JSAKICBjb3VudCh3b3JkLCBzZW50aW1lbnQsIHNvcnQgPSBUUlVFKSAlPiUKICBncm91cF9ieShzZW50aW1lbnQpICU+JQogIHRvcF9uKDMpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUod29yZCA9IHJlb3JkZXIod29yZCwgbikpICU+JQogIGdncGxvdChhZXMod29yZCwgbiwgZmlsbCA9IHNlbnRpbWVudCkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh2YXJzKHNlbnRpbWVudCksIHNjYWxlcyA9ICJmcmVlIikgKwogIGxhYnMoeSA9ICJUaGUgVmluZXMncyBIaWdobHkgRXZvbHZlZCBhbGJ1bTogV29yZHMgdGhhdCBjb250cmlidXRlIHRoZSBtb3N0IHRvIGVhY2ggc2VudGltZW50IiwKICAgICAgIHggPSBOVUxMKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgo0LiBJbnN0ZWFkIG9mIG9ubHkgZXhhbWluaW5nIGluZGl2aWR1YWwgd29yZHMsIGxldCdzIHRha2UgYSBsb29rIGF0IGx5cmljcyB0aGF0IGFyZSBwYWlyZWQgdG9nZXRoZXIuIAoKYGBge3J9CmV2b2x2ZWRfbHlyaWNzICU+JQogIHVubmVzdF90b2tlbnMoYmlncmFtLCBsaW5lLCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikgJT4lIAogIHNlbGVjdChiaWdyYW0pCgpgYGAKClRoaXMgbG9va3MgZ29vZCwgZXhjZXB0IHdlIGdldCBzdG9wd29yZHMgYWdhaW4uIExldCdzIGdldCByaWQgb2YgdGhvc2UuIAoKYGBge3J9CmV2b2x2ZWRfbHlyaWNzICU+JQogIHVubmVzdF90b2tlbnMoYmlncmFtLCBsaW5lLCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikgJT4lIAogIHNlbGVjdChiaWdyYW0pIC0+IGV2b2x2ZWRfYmlncmFtcwoKYGBgCgpgYGB7cn0KZXZvbHZlZF9iaWdyYW1zICU+JSAKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lIAogIGZpbHRlcighd29yZDEgJWluJSBzdG9wX3dvcmRzJHdvcmQpICU+JQogIGZpbHRlcighd29yZDIgJWluJSBzdG9wX3dvcmRzJHdvcmQpICU+JSAKICB1bml0ZShiaWdyYW0sIHdvcmQxLCB3b3JkMiwgc2VwID0gIiAiKQoKYGBgCgpUaGF0IGxvb2tzIGJldHRlciEgTm93IHdlIGNhbiB0ZWxsIFIgdG8gY291bnQgaG93IG1hbnkgdGltZXMgZWFjaCBwYWlyaW5nIG9jY3Vycy4gCgpgYGB7cn0KZXZvbHZlZF9iaWdyYW1zICU+JSAKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lIAogIGZpbHRlcighd29yZDEgJWluJSBzdG9wX3dvcmRzJHdvcmQpICU+JQogIGZpbHRlcighd29yZDIgJWluJSBzdG9wX3dvcmRzJHdvcmQpICU+JSAKICB1bml0ZShiaWdyYW0sIHdvcmQxLCB3b3JkMiwgc2VwID0gIiAiKSAlPiUKICBjb3VudChiaWdyYW0sIHNvcnQgPSBUKQoKYGBgCgpBcyB3ZSBjYW4gc2VlLCB0aGUgd29yZCBwYWlycyAiZ29ubmEgZ2V0IiBhbmQgImdldCBmcmVlIiBhcmUgYW1vbmcgdGhlIG1vc3QgY29tbW9uLiAKCgo1LiBJIHdvdWxkIG5vdyBsaWtlIHRvIHNlZSB3aGF0IHdvcmQgdGVuZHMgdG8gaW1tZWRpYXRlbHkgZm9sbG93IHRoZSB3b3JkICJJIiBhbmQgd2hhdCB3b3JkIHRlbmRzIHRvIGltbWVkaWF0ZWx5IGZvbGxvdyB0aGUgd29yZCAieW91LCIgdG8gc2VlIGlmIGFueSBpbnRlcnN0aW5nIGRpZmZlcmVuY2UgaXMgYXBwYXJlbnQuIAoKYGBge3J9CmZpcnN0X3dvcmQgPC0gYygiaSIsICJ5b3UiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZXNlIG5lZWQgdG8gYmUgbG93ZXJjYXNlCgpldm9sdmVkX2JpZ3JhbXMgJT4lIAogIGNvdW50KGJpZ3JhbSwgc29ydCA9IFQpICU+JSAKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgJT4lICAgICAgICMgc2VwYXJhdGUgdGhlIHR3byB3b3JkcwogIGZpbHRlcih3b3JkMSAlaW4lIGZpcnN0X3dvcmQpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgIyBmaW5kIGZpcnN0IHdvcmRzIGZyb20gb3VyIGxpc3QKICBjb3VudCh3b3JkMSwgd29yZDIsIHd0ID0gbiwgc29ydCA9IFRSVUUpICU+JSAKICByZW5hbWUodG90YWwgPSBubikKCmBgYAoKRmluYWxseSwgSSB3b3VsZCBsaWtlIHRvIGxvb2sgYXQgdGhhdCBvbiBhIGdyYXBoLiAKCmBgYHtyfQoKZmlyc3Rfd29yZCA8LSBjKCJpIiwgInlvdSIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlc2UgbmVlZCB0byBiZSBsb3dlcmNhc2UKCmV2b2x2ZWRfYmlncmFtcyAlPiUgCiAgY291bnQoYmlncmFtLCBzb3J0ID0gVCkgJT4lIAogIHNlcGFyYXRlKGJpZ3JhbSwgYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKSAlPiUgICAgICAgIyBzZXBhcmF0ZSB0aGUgdHdvIHdvcmRzCiAgZmlsdGVyKHdvcmQxICVpbiUgZmlyc3Rfd29yZCkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAjIGZpbmQgZmlyc3Qgd29yZHMgZnJvbSBvdXIgbGlzdAogIGNvdW50KHdvcmQxLCB3b3JkMiwgd3QgPSBuLCBzb3J0ID0gVFJVRSkgJT4lIAogIHJlbmFtZSh0b3RhbCA9IG5uKQogIG11dGF0ZSh3b3JkMiA9IGZhY3Rvcih3b3JkMiwgbGV2ZWxzID0gcmV2KHVuaXF1ZSh3b3JkMikpKSkgJT4lICAgICAjIHB1dCB0aGUgd29yZHMgaW4gb3JkZXIKICBncm91cF9ieSh3b3JkMSkgJT4lIAogIHRvcF9uKDUpICU+JSAKICBnZ3Bsb3QoYWVzKHdvcmQyLCB0b3RhbCwgZmlsbCA9IHdvcmQxKSkgKyAgICAgICAgICAgICAgICAgICAgICAgICAgIwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNldCB0aGUgY29sb3IgcGFsZXR0ZQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsKICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgdGl0bGUgPSAiV29yZCBmb2xsb3dpbmc6IikgKwogIGZhY2V0X3dyYXAofndvcmQxLCBzY2FsZXMgPSAiZnJlZSIpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX21pbmltYWwoKQoKYGBg