Ansgar Wolsing’s contribution to 30 Day Chart Challenge, 2022 Edition.
Code on GitHub (very slightly modified).
## remotes::install_github("davidsjoberg/ggstream")
library(ggstream)
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✔ ggplot2 3.3.5 ✔ purrr 0.3.4
## ✔ tibble 3.1.6 ✔ dplyr 1.0.8
## ✔ tidyr 1.2.0 ✔ stringr 1.4.0
## ✔ readr 2.1.2 ✔ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
library(tidytext)
library(ggtext)
## download text from Project Gutenberg
if (! file.exists("macbeth.txt")) {
macbeth_url <- "https://www.gutenberg.org/cache/epub/1129/pg1129.txt"
download.file(macbeth_url, "macbeth.txt")
}
macbeth_lines <- read_lines("macbeth.txt")
## Lines where the manuscript starts and ends
start_line <- 282
end_line <- 2899
exclude_lines <- 2358:2365
text_df <- tibble(line = macbeth_lines[start_line:end_line]) %>%
mutate(line = str_squish(line),
line_id = row_number()) %>%
## remove empty or irrelevant lines
filter(line != "" | line_id %in% exclude_lines) %>%
filter(!str_detect(line, "SERVICE THAT CHARGES|WITH PERMISSION|COMMERCIALLY")) %>%
## extract the act and scene
mutate(act = str_extract(line, "^ACT\\b.+?\\."),
scene = str_extract(line, "SCENE\\b.+?\\.")) %>%
fill(act, scene, .direction = "down") %>%
## extract the character name who speaks
mutate(speaker = str_extract(line, "^[A-Z\\s]+\\."),
speaker = str_remove(speaker, "\\.$"),
speaker = ifelse(str_detect(speaker, "^ACT|SCENE\\b"),
NA_character_, speaker),
speaker = str_to_title(speaker)) %>%
## manage the switch of speakers from scene to scene
group_by(act, scene) %>%
fill(speaker, .direction = "down") %>%
ungroup() %>%
## remove lines without a speaker
filter(!is.na(speaker)) %>%
## remove speaker names from the lines
mutate(line = str_remove(line, paste0(speaker, ". ")))
## count the number of words per speaker in each act and scene
word_count_speakers <- text_df %>%
## recode the witches and murderers into one category
mutate(speaker_grp = ifelse(str_detect(speaker, "Witch$"),
"Three Witches", speaker),
speaker_grp = ifelse(str_detect(speaker_grp, "Mutherers?$"),
"Mutherers", speaker_grp)) %>%
unnest_tokens(word, line, token = "words", drop = TRUE) %>%
count(act, scene, speaker_grp, speaker, name = "word_count")
## identify character with only a few appearances
few_appearances_speakers <- word_count_speakers %>%
group_by(speaker_grp) %>%
summarize(scenes_count = n_distinct(act, scene),
word_count_total = sum(word_count)) %>%
filter(scenes_count <= 3, word_count_total < 500) %>%
pull(speaker_grp)
## Custom color palette by character affiliation
speaker_grp_levels = c(
"Macbeth", "Lady Macbeth",
"Duncan", "Malcolm", "Macduff", "Ross",
"Banquo", "Lennox",
"Three Witches",
"Other")
color_palette <- paletteer::paletteer_d(
"palettetown::pidgey")[c(9, 8,
2, 5, 4, 6,
12, 6,
3,
11 )]
## Annotations
plot_titles <- list(
title = "Who speaks when in Shakespeare's MACBETH?",
subtitle = "Distribution of speech share (number of words) per character in
each scene. Acts are separated with vertical lines.",
caption = "Project Gutenberg. Visualization: Ansgar Wolsing"
)
## highlight key events - used for text and lines
story_annotations <- tibble(
x = c(13.5, 1.2, 7, 5, 14, 22),
xend = c(19, 1.2, 7, 5, 14, 22),
y = c(-5000, -4200, -4500, 5000, 5000, 3000),
yend = c(-5000, -200, 400, 800, 1000, 500),
vjust = c( 0, 0.25, 0.3, 0.85, 0.9, 0.8),
label = c(
"Macduff & Malcolm decide to go to war against Macbeth",
"Three Witches<br>appear",
"Macbeth kills King Duncan",
"Lady Macbeth & Macbeth<br>plan the murder of King Duncan",
"Murder of Banquo reported to Macbeth,<br>Ghost of Banquo appears",
"Macduff<br>kills<br>Macbeth"))
word_count_speakers %>%
mutate(speaker_grp =
ifelse(speaker_grp %in% c("All", few_appearances_speakers),
"Other", speaker_grp),
speaker_grp = factor(speaker_grp, levels = speaker_grp_levels)) %>%
count(act, scene, speaker_grp, wt = word_count, name = "word_count") %>%
## increment counter across act and scene
group_by(act, scene) %>%
mutate(act_scene_id = cur_group_id()) %>%
ungroup() %>%
ggplot(aes(act_scene_id, word_count, fill = speaker_grp)) +
## vertical lines for the acts
geom_vline(
data = . %>% filter(scene == "SCENE I."),
aes(xintercept = act_scene_id),
color = "grey50", size = 0.2, lty = "dotted") +
geom_stream(type = "mirror", bw = 0.5, extra_span = 0.1) +
## annotations for key events (text + segment)
geom_textbox(
data = story_annotations,
aes(x - 0.08, y, label = label, vjust = vjust),
inherit.aes = FALSE,
color = "grey90", family = "Forum", hjust = 0, fill = NA,
box.size = 0,
width = unit(3.5, "cm")) +
geom_segment(
data = story_annotations,
aes(x = x, xend = xend, y = y, yend = yend), inherit.aes = FALSE,
color = "grey90", size = 0.3) +
## text labels for the acts
geom_text(
data = . %>% group_by(act) %>%
summarize(x = min(act_scene_id) + n_distinct(scene) / 2),
aes(x, y = -Inf, label = act), inherit.aes = FALSE,
vjust = -1, hjust = 0.5, color = "grey60", family = "Forum") +
scale_fill_manual(values = color_palette) +
labs(
title = plot_titles$title,
subtitle = plot_titles$subtitle,
caption = plot_titles$caption,
fill = NULL) +
theme_void(base_family = "Forum", base_size = 10) +
theme(
plot.background = element_rect(color = NA, fill = "grey8"),
plot.margin = margin(10, 10, 10, 10),
legend.position = "bottom",
legend.direction = "horizontal",
legend.key.height = unit(3, "mm"),
legend.spacing.y = unit(4, "cm"),
legend.text = element_text(size = 9.5),
text = element_text(color = "white"),
plot.title = element_text(size = 24, family = "Forum"),
plot.subtitle = element_markdown(),
plot.caption = element_markdown(hjust = 1))

LS0tCnRpdGxlOiAiV2hvIFNwZWFrcyBXaGVuIGluIFNoYWtlc3BlYXJlJ3MgTUFDQkVUSD8iCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVkgJUg6JU0nKWAiCi0tLQoKYGBge3IgZ2xvYmFsX29wdGlvbnMsIGluY2x1ZGUgPSBGQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGNvbGxhcHNlID0gVFJVRSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIikKYGBgCkFuc2dhciBXb2xzaW5nJ3MKW2NvbnRyaWJ1dGlvbl0oaHR0cHM6Ly90d2l0dGVyLmNvbS9fYW5zZ2FyL3N0YXR1cy8xNTEzMDg0NjU5MDEzNTA1MDI4KSB0bwpbMzAgRGF5IENoYXJ0IENoYWxsZW5nZSwgMjAyMiBFZGl0aW9uXShodHRwczovL3R3aXR0ZXIuY29tLzMwRGF5Q2hhcnRDaGFsbCkuCgpbQ29kZSBvbiBHaXRIdWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9ieWRhdGEvMzBEYXlDaGFydENoYWxsZW5nZS9ibG9iL21haW4vMjAyMi8xMC8xMC1leHBlcmltZW50YWwtbWFjYmV0aC5SKSAodmVyeSBzbGlnaHRseSBtb2RpZmllZCkuCgpgYGB7ciwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA4fQojIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiZGF2aWRzam9iZXJnL2dnc3RyZWFtIikKbGlicmFyeShnZ3N0cmVhbSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkodGlkeXRleHQpCmxpYnJhcnkoZ2d0ZXh0KQoKIyMgZG93bmxvYWQgdGV4dCBmcm9tIFByb2plY3QgR3V0ZW5iZXJnCmlmICghIGZpbGUuZXhpc3RzKCJtYWNiZXRoLnR4dCIpKSB7CiAgICBtYWNiZXRoX3VybCA8LSAiaHR0cHM6Ly93d3cuZ3V0ZW5iZXJnLm9yZy9jYWNoZS9lcHViLzExMjkvcGcxMTI5LnR4dCIKICAgIGRvd25sb2FkLmZpbGUobWFjYmV0aF91cmwsICJtYWNiZXRoLnR4dCIpCn0KbWFjYmV0aF9saW5lcyA8LSByZWFkX2xpbmVzKCJtYWNiZXRoLnR4dCIpCgojIyBMaW5lcyB3aGVyZSB0aGUgbWFudXNjcmlwdCBzdGFydHMgYW5kIGVuZHMKc3RhcnRfbGluZSA8LSAyODIKZW5kX2xpbmUgPC0gMjg5OQpleGNsdWRlX2xpbmVzIDwtIDIzNTg6MjM2NQoKdGV4dF9kZiA8LSB0aWJibGUobGluZSA9IG1hY2JldGhfbGluZXNbc3RhcnRfbGluZTplbmRfbGluZV0pICU+JSAKICAgIG11dGF0ZShsaW5lID0gc3RyX3NxdWlzaChsaW5lKSwKICAgICAgICAgICBsaW5lX2lkID0gcm93X251bWJlcigpKSAlPiUgCiAgICAjIyByZW1vdmUgZW1wdHkgb3IgaXJyZWxldmFudCBsaW5lcwogICAgZmlsdGVyKGxpbmUgIT0gIiIgfCBsaW5lX2lkICVpbiUgZXhjbHVkZV9saW5lcykgJT4lIAogICAgZmlsdGVyKCFzdHJfZGV0ZWN0KGxpbmUsICJTRVJWSUNFIFRIQVQgQ0hBUkdFU3xXSVRIIFBFUk1JU1NJT058Q09NTUVSQ0lBTExZIikpICU+JSAKICAgICMjIGV4dHJhY3QgdGhlIGFjdCBhbmQgc2NlbmUKICAgIG11dGF0ZShhY3QgPSBzdHJfZXh0cmFjdChsaW5lLCAiXkFDVFxcYi4rP1xcLiIpLAogICAgICAgICAgIHNjZW5lID0gc3RyX2V4dHJhY3QobGluZSwgIlNDRU5FXFxiLis/XFwuIikpICU+JSAKICAgIGZpbGwoYWN0LCBzY2VuZSwgLmRpcmVjdGlvbiA9ICJkb3duIikgJT4lIAogICAgIyMgZXh0cmFjdCB0aGUgY2hhcmFjdGVyIG5hbWUgd2hvIHNwZWFrcwogICAgbXV0YXRlKHNwZWFrZXIgPSBzdHJfZXh0cmFjdChsaW5lLCAiXltBLVpcXHNdK1xcLiIpLAogICAgICAgICAgIHNwZWFrZXIgPSBzdHJfcmVtb3ZlKHNwZWFrZXIsICJcXC4kIiksCiAgICAgICAgICAgc3BlYWtlciA9IGlmZWxzZShzdHJfZGV0ZWN0KHNwZWFrZXIsICJeQUNUfFNDRU5FXFxiIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFfY2hhcmFjdGVyXywgc3BlYWtlciksCiAgICAgICAgICAgc3BlYWtlciA9IHN0cl90b190aXRsZShzcGVha2VyKSkgJT4lIAogICAgIyMgbWFuYWdlIHRoZSBzd2l0Y2ggb2Ygc3BlYWtlcnMgZnJvbSBzY2VuZSB0byBzY2VuZQogICAgZ3JvdXBfYnkoYWN0LCBzY2VuZSkgJT4lIAogICAgZmlsbChzcGVha2VyLCAuZGlyZWN0aW9uID0gImRvd24iKSAlPiUgCiAgICB1bmdyb3VwKCkgJT4lIAogICAgIyMgcmVtb3ZlIGxpbmVzIHdpdGhvdXQgYSBzcGVha2VyCiAgICBmaWx0ZXIoIWlzLm5hKHNwZWFrZXIpKSAlPiUKICAgICMjIHJlbW92ZSBzcGVha2VyIG5hbWVzIGZyb20gdGhlIGxpbmVzCiAgICBtdXRhdGUobGluZSA9IHN0cl9yZW1vdmUobGluZSwgcGFzdGUwKHNwZWFrZXIsICIuICIpKSkgCgojIyBjb3VudCB0aGUgbnVtYmVyIG9mIHdvcmRzIHBlciBzcGVha2VyIGluIGVhY2ggYWN0IGFuZCBzY2VuZQp3b3JkX2NvdW50X3NwZWFrZXJzIDwtIHRleHRfZGYgJT4lIAogICAgIyMgcmVjb2RlIHRoZSB3aXRjaGVzIGFuZCBtdXJkZXJlcnMgaW50byBvbmUgY2F0ZWdvcnkKICAgIG11dGF0ZShzcGVha2VyX2dycCA9IGlmZWxzZShzdHJfZGV0ZWN0KHNwZWFrZXIsICJXaXRjaCQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGhyZWUgV2l0Y2hlcyIsIHNwZWFrZXIpLAogICAgICAgICAgIHNwZWFrZXJfZ3JwID0gaWZlbHNlKHN0cl9kZXRlY3Qoc3BlYWtlcl9ncnAsICJNdXRoZXJlcnM/JCIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNdXRoZXJlcnMiLCBzcGVha2VyX2dycCkpICU+JSAKICAgIHVubmVzdF90b2tlbnMod29yZCwgbGluZSwgdG9rZW4gPSAid29yZHMiLCBkcm9wID0gVFJVRSkgJT4lIAogICAgY291bnQoYWN0LCBzY2VuZSwgc3BlYWtlcl9ncnAsIHNwZWFrZXIsIG5hbWUgPSAid29yZF9jb3VudCIpCgojIyBpZGVudGlmeSBjaGFyYWN0ZXIgd2l0aCBvbmx5IGEgZmV3IGFwcGVhcmFuY2VzCmZld19hcHBlYXJhbmNlc19zcGVha2VycyA8LSB3b3JkX2NvdW50X3NwZWFrZXJzICU+JSAKICAgIGdyb3VwX2J5KHNwZWFrZXJfZ3JwKSAlPiUgCiAgICBzdW1tYXJpemUoc2NlbmVzX2NvdW50ID0gbl9kaXN0aW5jdChhY3QsIHNjZW5lKSwKICAgICAgICAgICAgICB3b3JkX2NvdW50X3RvdGFsID0gc3VtKHdvcmRfY291bnQpKSAlPiUgCiAgICBmaWx0ZXIoc2NlbmVzX2NvdW50IDw9IDMsIHdvcmRfY291bnRfdG90YWwgPCA1MDApICU+JSAKICAgIHB1bGwoc3BlYWtlcl9ncnApCgojIyBDdXN0b20gY29sb3IgcGFsZXR0ZSBieSBjaGFyYWN0ZXIgYWZmaWxpYXRpb24Kc3BlYWtlcl9ncnBfbGV2ZWxzID0gYygKICAiTWFjYmV0aCIsICJMYWR5IE1hY2JldGgiLCAKICAiRHVuY2FuIiwgIk1hbGNvbG0iLCAiTWFjZHVmZiIsICJSb3NzIiwKICAiQmFucXVvIiwgIkxlbm5veCIsCiAgIlRocmVlIFdpdGNoZXMiLAogICJPdGhlciIpCmNvbG9yX3BhbGV0dGUgPC0gcGFsZXR0ZWVyOjpwYWxldHRlZXJfZCgKICAicGFsZXR0ZXRvd246OnBpZGdleSIpW2MoOSwgOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgMiwgNSwgNCwgNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgMTIsIDYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIDExICldCgojIyBBbm5vdGF0aW9ucwpwbG90X3RpdGxlcyA8LSBsaXN0KAogICAgdGl0bGUgPSAiV2hvIHNwZWFrcyB3aGVuIGluIFNoYWtlc3BlYXJlJ3MgTUFDQkVUSD8iLAogICAgc3VidGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIHNwZWVjaCBzaGFyZSAobnVtYmVyIG9mIHdvcmRzKSBwZXIgY2hhcmFjdGVyIGluIAogIGVhY2ggc2NlbmUuIEFjdHMgYXJlIHNlcGFyYXRlZCB3aXRoIHZlcnRpY2FsIGxpbmVzLiIsCiAgY2FwdGlvbiA9ICJQcm9qZWN0IEd1dGVuYmVyZy4gVmlzdWFsaXphdGlvbjogQW5zZ2FyIFdvbHNpbmciCikKCiMjIGhpZ2hsaWdodCBrZXkgZXZlbnRzIC0gdXNlZCBmb3IgdGV4dCBhbmQgbGluZXMKc3RvcnlfYW5ub3RhdGlvbnMgPC0gdGliYmxlKAogICAgeCAgICA9IGMoMTMuNSwgMS4yLCA3LCA1LCAxNCwgMjIpLAogICAgeGVuZCA9IGMoMTksICAgMS4yLCA3LCA1LCAxNCwgMjIpLAogICAgeSAgICA9IGMoLTUwMDAsIC00MjAwLCAtNDUwMCwgNTAwMCwgNTAwMCwgMzAwMCksCiAgICB5ZW5kID0gYygtNTAwMCwgIC0yMDAsICAgNDAwLCAgODAwLCAxMDAwLCAgNTAwKSwKICAgIHZqdXN0ID0gYyggICAwLCAgMC4yNSwgICAwLjMsICAwLjg1LCAgMC45LCAgMC44KSwKICAgIGxhYmVsID0gYygKICAgICAgICAiTWFjZHVmZiAmIE1hbGNvbG0gZGVjaWRlIHRvIGdvIHRvIHdhciBhZ2FpbnN0IE1hY2JldGgiLAogICAgICAgICJUaHJlZSBXaXRjaGVzPGJyPmFwcGVhciIsCiAgICAgICAgIk1hY2JldGgga2lsbHMgS2luZyBEdW5jYW4iLAogICAgICAgICJMYWR5IE1hY2JldGggJiBNYWNiZXRoPGJyPnBsYW4gdGhlIG11cmRlciBvZiBLaW5nIER1bmNhbiIsCiAgICAgICAgIk11cmRlciBvZiBCYW5xdW8gcmVwb3J0ZWQgdG8gTWFjYmV0aCw8YnI+R2hvc3Qgb2YgQmFucXVvIGFwcGVhcnMiLAogICAgICAgICJNYWNkdWZmPGJyPmtpbGxzPGJyPk1hY2JldGgiKSkKCndvcmRfY291bnRfc3BlYWtlcnMgJT4lIAogICAgbXV0YXRlKHNwZWFrZXJfZ3JwID0KICAgICAgICAgICAgICAgaWZlbHNlKHNwZWFrZXJfZ3JwICVpbiUgYygiQWxsIiwgZmV3X2FwcGVhcmFuY2VzX3NwZWFrZXJzKSwKICAgICAgICAgICAgICAgICAgICAgICJPdGhlciIsIHNwZWFrZXJfZ3JwKSwKICAgICAgICAgICBzcGVha2VyX2dycCA9IGZhY3RvcihzcGVha2VyX2dycCwgbGV2ZWxzID0gc3BlYWtlcl9ncnBfbGV2ZWxzKSkgJT4lIAogICAgY291bnQoYWN0LCBzY2VuZSwgc3BlYWtlcl9ncnAsIHd0ID0gd29yZF9jb3VudCwgbmFtZSA9ICJ3b3JkX2NvdW50IikgJT4lIAogICAgIyMgaW5jcmVtZW50IGNvdW50ZXIgYWNyb3NzIGFjdCBhbmQgc2NlbmUKICAgIGdyb3VwX2J5KGFjdCwgc2NlbmUpICU+JSAKICAgIG11dGF0ZShhY3Rfc2NlbmVfaWQgPSBjdXJfZ3JvdXBfaWQoKSkgJT4lIAogICAgdW5ncm91cCgpICU+JSAKICAgIGdncGxvdChhZXMoYWN0X3NjZW5lX2lkLCB3b3JkX2NvdW50LCBmaWxsID0gc3BlYWtlcl9ncnApKSArCiAgICAjIyB2ZXJ0aWNhbCBsaW5lcyBmb3IgdGhlIGFjdHMKICAgIGdlb21fdmxpbmUoCiAgICAgICAgZGF0YSA9IC4gJT4lIGZpbHRlcihzY2VuZSA9PSAiU0NFTkUgSS4iKSwKICAgICAgICBhZXMoeGludGVyY2VwdCA9IGFjdF9zY2VuZV9pZCksIAogICAgICAgIGNvbG9yID0gImdyZXk1MCIsIHNpemUgPSAwLjIsIGx0eSA9ICJkb3R0ZWQiKSArCiAgICBnZW9tX3N0cmVhbSh0eXBlID0gIm1pcnJvciIsIGJ3ID0gMC41LCAgZXh0cmFfc3BhbiA9IDAuMSkgKwogICAgIyMgYW5ub3RhdGlvbnMgZm9yIGtleSBldmVudHMgKHRleHQgKyBzZWdtZW50KQogICAgZ2VvbV90ZXh0Ym94KAogICAgICAgIGRhdGEgPSBzdG9yeV9hbm5vdGF0aW9ucywKICAgICAgICBhZXMoeCAtIDAuMDgsIHksIGxhYmVsID0gbGFiZWwsIHZqdXN0ID0gdmp1c3QpLAogICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsCiAgICAgICAgY29sb3IgPSAiZ3JleTkwIiwgZmFtaWx5ID0gIkZvcnVtIiwgaGp1c3QgPSAwLCBmaWxsID0gTkEsCiAgICAgICAgYm94LnNpemUgPSAwLAogICAgICAgIHdpZHRoID0gdW5pdCgzLjUsICJjbSIpKSArCiAgICBnZW9tX3NlZ21lbnQoCiAgICAgICAgZGF0YSA9IHN0b3J5X2Fubm90YXRpb25zLAogICAgICAgIGFlcyh4ID0geCwgeGVuZCA9IHhlbmQsIHkgPSB5LCB5ZW5kID0geWVuZCksIGluaGVyaXQuYWVzID0gRkFMU0UsCiAgICAgICAgY29sb3IgPSAiZ3JleTkwIiwgc2l6ZSA9IDAuMykgKwogICAgIyMgdGV4dCBsYWJlbHMgZm9yIHRoZSBhY3RzCiAgICBnZW9tX3RleHQoCiAgICAgICAgZGF0YSA9IC4gJT4lIGdyb3VwX2J5KGFjdCkgJT4lCiAgICAgICAgICAgIHN1bW1hcml6ZSh4ID0gbWluKGFjdF9zY2VuZV9pZCkgKyBuX2Rpc3RpbmN0KHNjZW5lKSAvIDIpLAogICAgICAgIGFlcyh4LCB5ID0gLUluZiwgbGFiZWwgPSBhY3QpLCBpbmhlcml0LmFlcyA9IEZBTFNFLCAKICAgICAgICB2anVzdCA9IC0xLCBoanVzdCA9IDAuNSwgY29sb3IgPSAiZ3JleTYwIiwgZmFtaWx5ID0gIkZvcnVtIikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JfcGFsZXR0ZSkgKwogICAgbGFicygKICAgICAgICB0aXRsZSA9IHBsb3RfdGl0bGVzJHRpdGxlLAogICAgICAgIHN1YnRpdGxlID0gcGxvdF90aXRsZXMkc3VidGl0bGUsCiAgICAgICAgY2FwdGlvbiA9IHBsb3RfdGl0bGVzJGNhcHRpb24sCiAgICAgICAgZmlsbCA9IE5VTEwpICsKICAgIHRoZW1lX3ZvaWQoYmFzZV9mYW1pbHkgPSAiRm9ydW0iLCBiYXNlX3NpemUgPSAxMCkgKwogICAgdGhlbWUoCiAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gTkEsIGZpbGwgPSAiZ3JleTgiKSwKICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbigxMCwgMTAsIDEwLCAxMCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIAogICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsCiAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDMsICJtbSIpLAogICAgICAgIGxlZ2VuZC5zcGFjaW5nLnkgPSB1bml0KDQsICJjbSIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LjUpLAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAid2hpdGUiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNCwgZmFtaWx5ID0gIkZvcnVtIiksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfbWFya2Rvd24oKSwKICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X21hcmtkb3duKGhqdXN0ID0gMSkpCmBgYAo=