Sigur Ros- The Reynes of Castamere
Following on from yesterday’s post, I wanted to create some static graphs that were easier on my PC of the A Song of Ice and Fire books, using the network and ggnet packages
library(network)
library(ggnet)
library(ggplot2)
I’m using the same data I scraped in the previous post but instead of going through all that again, I’ll load it from my GitHub. The only change I think I’ve made is to add the links from the Characters df sheet to the Nodes df to tidy the environment a bit
Github <- "https://raw.githubusercontent.com/RobWHickman/"
Project <- "Databases-and-Files/master/GoT-Network/"
Matrix_file <- paste0(Github, Project, "GoT-Matrix.csv")
Network_file <- paste0(Github, Project, "GoT-Network.csv")
Nodes_file <- paste0(Github, Project, "GoT-Nodes.csv")
Books_file <- paste0(Github, Project, "GoT-Books.csv")
chapter_df <- read.csv(Matrix_file, stringsAsFactors = FALSE)
names(chapter_df)[1] <- "name"
Links <- read.csv(Network_file, stringsAsFactors = FALSE)
Nodes <- read.csv(Nodes_file, stringsAsFactors = FALSE)
books <- read.csv(Books_file, stringsAsFactors = FALSE)
I also wanted to colour each network by the book cover. This basically copies the Sigil colouring function from the previous post. I also lightened the colours for the area in the main plot so the nodes/vertexes could still be seen
library(jpeg)
library(RImagePalette)
#function to get the colour of each book cover
cover_func <- function(book_cover){
download.file(book_cover, "cover.jpg", mode = "wb", quiet = TRUE)
img <- readJPEG("cover.jpg")
cover_colour <- image_palette(img, n=1)
return(cover_colour)
}
books$cover_colours <- unlist(lapply(books$cover, cover_func))
#make the colours a bit lighter so they don't interfere with the plot
for (cover in 1:nrow(books)){
ifelse(cover < 2, light_covers <- colorRampPalette(c(books$cover_colours[cover], "white"))(100)[75], light_covers <- append(light_covers, colorRampPalette(c(books$cover_colours[cover], "white"))(100)[75]))}
books$light_covers <- light_covers
I also scraped the point-of-view of the chapter (i.e. the character who is the main focus of each chapter) using the chapter_urls from the previous post and running them in this function. I’ve commented it out and added the download fo the Git file below to save scraping on re-running my own script
#pov_func <- function(chapter_url){
# read <- read_html(chapter_url)
# nodes <- read %>% html_nodes("#content > div > div > div > div > ul > li:nth-child(1) > a")
# pov <- nodes %>% html_text()
# return(pov)
#}
#povs <- lapply(chapter_urls, pov_func)
#chapters <- data.frame(pov = unlist(povs), book = rep(books$book, books$chapters))
Chapters_file <- paste0(Github, Project, "GoT-Chapters.csv")
chapters <- read.csv(Chapters_file, stringsAsFactors = FALSE)
To plot each book separately (my computer can’t handle running network() on the 22k edges between all the characters in every book) I’ll use this massive loop which will spit out a lattice of all 5 network plots at the end. Hopefully it should be commented enough that it won’t get too confusing
#get the chapter numbers cumulatively for each book
books$cumsum <- cumsum(books$chapters)
#make the chapter_df for just chapters in 1 book + the name column
for (book in 1:5){
lower <- sum(books$cumsum[book-1]) + 2
upper <- sum(books$cumsum[book])
book_df <- chapter_df[c(1, lower:upper)]
Nodes <- Nodes[order(Nodes$order),]
book_df$name <- Nodes$name[which(Nodes$links %in% book_df$name)]
pov_chapters <- chapters[c((lower-1):upper),]
#remove characters that don't appear in that book
rm(to_delete)
for (character in 1:nrow(book_df)){
if(sum(book_df[character, c(2:ncol(book_df))]) < 1){
ifelse(!exists("to_delete"),
to_delete <- c(character),
to_delete <- append(to_delete, character)
)
}}
book_df <- book_df[-c(to_delete),]
#prepare a matrix of interactions between each character
#a df of n(characters) x n(characters) where the value is the connections
#between character[row] and character[column]
rm(Book_Matrix)
for (protag in 1:nrow(book_df)){
for (other in 1:nrow(book_df)){
if(protag == other){
ifelse(other == 1,
newrow <- 0,
newrow <- append(newrow, 0))
} else{
connection <- length(which(
book_df[protag,] == 1 &
book_df[other,] == 1))
ifelse(other == 1,
newrow <- connection,
newrow <- append(newrow, connection))
}
}
newrow <- data.frame(newrow)
names(newrow) <- book_df$name[protag]
ifelse(!exists("Book_Matrix"),
Book_Matrix <- newrow,
Book_Matrix <- cbind(Book_Matrix, newrow))
}
#make network object of the matrix using network()
rownames(Book_Matrix) <- colnames(Book_Matrix)
net <- network(Book_Matrix)
#prepare the nodes df by deleting unused nodes
#i.e. the characters that don't appear in this book
NodesBook <- Nodes[which(Nodes$name %in% book_df$name),]
#add rownames so we can find each node from the network object
rownames(NodesBook) <- NodesBook$order
#Also change the size variable to be the number of chapters each
#character appears in in just this one book
NodesBook$size <- rowSums(book_df[2:ncol(book_df)])
#bind aethetics to the network object
net %v% "region" = as.character(NodesBook$region)
net %v% "colour" = as.character(NodesBook$colour)
net %v% "size" = (as.numeric(NodesBook$size) ^ 0.25) * 2.5
net %v% "nodesize" = log(as.numeric(NodesBook$size)) * 3
#set up which labels to show
#(i.e. only "recurring" characters who are in more than 3 chapters)
povs <- unique(pov_chapters$pov)
extralabels <- book_df$name[which(rowSums(book_df[2:ncol(book_df)]) > 10)]
labels <- append(unique(povs), extralabels)
#set up colours for each region
y <- c(Dorne. = "Orange", Vale. = "Skyblue", Westerlands. = "Red",
Stormlands. = "Yellow", Riverlands. = "Darkblue",
Crownlands. = "Goldenrod", North. = "White", Islands. = "Grey30",
Reach. = "Darkgreen", none = "Grey70", Westeros. = "Purple")
#plot the ggnet
plot <- ggnet2(net, label = labels, node.color = "region", palette = y,
label.size = "size", node.size = "nodesize",
alpha = 0.75, edge.color = "grey75") +
ggtitle(paste0("Book ", book, ": ", books$title[book])) +
theme(legend.position = "none",
title = element_text(size = 20),
plot.background = element_rect(fill = books$cover_colours[book]),
panel.background = element_rect(fill = books$light_covers[book]))
#assign the plot to the book number
assign(paste0("book", book), plot)
#close up the loop per book
}
Then make the final lattice plot of all five books together using grid.arrange()
library(gridExtra)
#plot all five books
grid.arrange(book1, book2, book3, book4, book5)
LS0tCnRpdGxlOiAiQSBQbG90IG9mIE5ldHdvcmtzIChwYXJ0IDIpIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCltTaWd1ciBSb3MtIFRoZSBSZXluZXMgb2YgQ2FzdGFtZXJlXShodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PXczUVc4UFZ5eU5NKQoKRm9sbG93aW5nIG9uIGZyb20geWVzdGVyZGF5J3MgcG9zdCwgSSB3YW50ZWQgdG8gY3JlYXRlIHNvbWUgc3RhdGljIGdyYXBocyB0aGF0IHdlcmUgZWFzaWVyIG9uIG15IFBDIG9mIHRoZSBBIFNvbmcgb2YgSWNlIGFuZCBGaXJlIGJvb2tzLCB1c2luZyB0aGUgW25ldHdvcmtdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9uZXR3b3JrL2luZGV4Lmh0bWwpIGFuZCBbZ2duZXRdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9HR2FsbHkvaW5kZXguaHRtbCkgcGFja2FnZXMKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KG5ldHdvcmspCmxpYnJhcnkoZ2duZXQpCmxpYnJhcnkoZ2dwbG90MikKYGBgCgpJJ20gdXNpbmcgdGhlIHNhbWUgZGF0YSBJIHNjcmFwZWQgaW4gdGhlIHByZXZpb3VzIHBvc3QgYnV0IGluc3RlYWQgb2YgZ29pbmcgdGhyb3VnaCBhbGwgdGhhdCBhZ2FpbiwgSSdsbCBsb2FkIGl0IGZyb20gbXkgR2l0SHViLiBUaGUgb25seSBjaGFuZ2UgSSB0aGluayBJJ3ZlIG1hZGUgaXMgdG8gYWRkIHRoZSBsaW5rcyBmcm9tIHRoZSBDaGFyYWN0ZXJzIGRmIHNoZWV0IHRvIHRoZSBOb2RlcyBkZiB0byB0aWR5IHRoZSBlbnZpcm9ubWVudCBhIGJpdAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CkdpdGh1YiA8LSAiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1JvYldIaWNrbWFuLyIKUHJvamVjdCA8LSAiRGF0YWJhc2VzLWFuZC1GaWxlcy9tYXN0ZXIvR29ULU5ldHdvcmsvIgoKTWF0cml4X2ZpbGUgPC0gcGFzdGUwKEdpdGh1YiwgUHJvamVjdCwgIkdvVC1NYXRyaXguY3N2IikKTmV0d29ya19maWxlIDwtIHBhc3RlMChHaXRodWIsIFByb2plY3QsICJHb1QtTmV0d29yay5jc3YiKQpOb2Rlc19maWxlIDwtIHBhc3RlMChHaXRodWIsIFByb2plY3QsICJHb1QtTm9kZXMuY3N2IikKQm9va3NfZmlsZSA8LSBwYXN0ZTAoR2l0aHViLCBQcm9qZWN0LCAiR29ULUJvb2tzLmNzdiIpCgpjaGFwdGVyX2RmIDwtIHJlYWQuY3N2KE1hdHJpeF9maWxlLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCiAgbmFtZXMoY2hhcHRlcl9kZilbMV0gPC0gIm5hbWUiCkxpbmtzIDwtIHJlYWQuY3N2KE5ldHdvcmtfZmlsZSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQpOb2RlcyA8LSByZWFkLmNzdihOb2Rlc19maWxlLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCmJvb2tzIDwtIHJlYWQuY3N2KEJvb2tzX2ZpbGUsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKYGBgCgpJIGFsc28gd2FudGVkIHRvIGNvbG91ciBlYWNoIG5ldHdvcmsgYnkgdGhlIGJvb2sgY292ZXIuIFRoaXMgYmFzaWNhbGx5IGNvcGllcyB0aGUgU2lnaWwgY29sb3VyaW5nIGZ1bmN0aW9uIGZyb20gdGhlIHByZXZpb3VzIHBvc3QuIEkgYWxzbyBsaWdodGVuZWQgdGhlIGNvbG91cnMgZm9yIHRoZSBhcmVhIGluIHRoZSBtYWluIHBsb3Qgc28gdGhlIG5vZGVzL3ZlcnRleGVzIGNvdWxkIHN0aWxsIGJlIHNlZW4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoanBlZykKbGlicmFyeShSSW1hZ2VQYWxldHRlKQoKI2Z1bmN0aW9uIHRvIGdldCB0aGUgY29sb3VyIG9mIGVhY2ggYm9vayBjb3Zlcgpjb3Zlcl9mdW5jIDwtIGZ1bmN0aW9uKGJvb2tfY292ZXIpewogIGRvd25sb2FkLmZpbGUoYm9va19jb3ZlciwgImNvdmVyLmpwZyIsIG1vZGUgPSAid2IiLCBxdWlldCA9IFRSVUUpCglpbWcgPC0gcmVhZEpQRUcoImNvdmVyLmpwZyIpCgljb3Zlcl9jb2xvdXIgPC0gaW1hZ2VfcGFsZXR0ZShpbWcsIG49MSkKcmV0dXJuKGNvdmVyX2NvbG91cikKfQoKYm9va3MkY292ZXJfY29sb3VycyA8LSB1bmxpc3QobGFwcGx5KGJvb2tzJGNvdmVyLCBjb3Zlcl9mdW5jKSkKCiNtYWtlIHRoZSBjb2xvdXJzIGEgYml0IGxpZ2h0ZXIgc28gdGhleSBkb24ndCBpbnRlcmZlcmUgd2l0aCB0aGUgcGxvdApmb3IgKGNvdmVyIGluIDE6bnJvdyhib29rcykpewogICAgaWZlbHNlKGNvdmVyIDwgMiwgbGlnaHRfY292ZXJzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYyhib29rcyRjb3Zlcl9jb2xvdXJzW2NvdmVyXSwgIndoaXRlIikpKDEwMClbNzVdLCBsaWdodF9jb3ZlcnMgPC0gYXBwZW5kKGxpZ2h0X2NvdmVycywgY29sb3JSYW1wUGFsZXR0ZShjKGJvb2tzJGNvdmVyX2NvbG91cnNbY292ZXJdLCAid2hpdGUiKSkoMTAwKVs3NV0pKX0KYm9va3MkbGlnaHRfY292ZXJzIDwtIGxpZ2h0X2NvdmVycwpgYGAKCkkgYWxzbyBzY3JhcGVkIHRoZSBwb2ludC1vZi12aWV3IG9mIHRoZSBjaGFwdGVyIChpLmUuIHRoZSBjaGFyYWN0ZXIgd2hvIGlzIHRoZSBtYWluIGZvY3VzIG9mIGVhY2ggY2hhcHRlcikgdXNpbmcgdGhlIGNoYXB0ZXJfdXJscyBmcm9tIHRoZSBwcmV2aW91cyBwb3N0IGFuZCBydW5uaW5nIHRoZW0gaW4gdGhpcyBmdW5jdGlvbi4gSSd2ZSBjb21tZW50ZWQgaXQgb3V0IGFuZCBhZGRlZCB0aGUgZG93bmxvYWQgZm8gdGhlIEdpdCBmaWxlIGJlbG93IHRvIHNhdmUgc2NyYXBpbmcgb24gcmUtcnVubmluZyBteSBvd24gc2NyaXB0CgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI3Bvdl9mdW5jIDwtIGZ1bmN0aW9uKGNoYXB0ZXJfdXJsKXsKIwlyZWFkIDwtIHJlYWRfaHRtbChjaGFwdGVyX3VybCkKIwlub2RlcyA8LSByZWFkICU+JSBodG1sX25vZGVzKCIjY29udGVudCA+IGRpdiA+IGRpdiA+IGRpdiA+IGRpdiA+IHVsID4gbGk6bnRoLWNoaWxkKDEpID4gYSIpCiMJcG92IDwtIG5vZGVzICU+JSBodG1sX3RleHQoKQojCXJldHVybihwb3YpCiN9CgojcG92cyA8LSBsYXBwbHkoY2hhcHRlcl91cmxzLCBwb3ZfZnVuYykKCiNjaGFwdGVycyA8LSBkYXRhLmZyYW1lKHBvdiA9IHVubGlzdChwb3ZzKSwgYm9vayA9IHJlcChib29rcyRib29rLCBib29rcyRjaGFwdGVycykpCgpDaGFwdGVyc19maWxlIDwtIHBhc3RlMChHaXRodWIsIFByb2plY3QsICJHb1QtQ2hhcHRlcnMuY3N2IikKY2hhcHRlcnMgPC0gcmVhZC5jc3YoQ2hhcHRlcnNfZmlsZSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQpgYGAKCgpUbyBwbG90IGVhY2ggYm9vayBzZXBhcmF0ZWx5IChteSBjb21wdXRlciBjYW4ndCBoYW5kbGUgcnVubmluZyBuZXR3b3JrKCkgb24gdGhlIDIyayBlZGdlcyBiZXR3ZWVuIGFsbCB0aGUgY2hhcmFjdGVycyBpbiBldmVyeSBib29rKSBJJ2xsIHVzZSB0aGlzIG1hc3NpdmUgbG9vcCB3aGljaCB3aWxsIHNwaXQgb3V0IGEgbGF0dGljZSBvZiBhbGwgNSBuZXR3b3JrIHBsb3RzIGF0IHRoZSBlbmQuIEhvcGVmdWxseSBpdCBzaG91bGQgYmUgY29tbWVudGVkIGVub3VnaCB0aGF0IGl0IHdvbid0IGdldCB0b28gY29uZnVzaW5nCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2dldCB0aGUgY2hhcHRlciBudW1iZXJzIGN1bXVsYXRpdmVseSBmb3IgZWFjaCBib29rCmJvb2tzJGN1bXN1bSA8LSBjdW1zdW0oYm9va3MkY2hhcHRlcnMpCgojbWFrZSB0aGUgY2hhcHRlcl9kZiBmb3IganVzdCBjaGFwdGVycyBpbiAxIGJvb2sgKyB0aGUgbmFtZSBjb2x1bW4KZm9yIChib29rIGluIDE6NSl7CiAgbG93ZXIgPC0gc3VtKGJvb2tzJGN1bXN1bVtib29rLTFdKSArIDIKICB1cHBlciA8LSBzdW0oYm9va3MkY3Vtc3VtW2Jvb2tdKQogIGJvb2tfZGYgPC0gY2hhcHRlcl9kZltjKDEsIGxvd2VyOnVwcGVyKV0KICBOb2RlcyA8LSBOb2Rlc1tvcmRlcihOb2RlcyRvcmRlciksXQogIGJvb2tfZGYkbmFtZSA8LSBOb2RlcyRuYW1lW3doaWNoKE5vZGVzJGxpbmtzICVpbiUgYm9va19kZiRuYW1lKV0KICAKcG92X2NoYXB0ZXJzIDwtIGNoYXB0ZXJzW2MoKGxvd2VyLTEpOnVwcGVyKSxdCgojcmVtb3ZlIGNoYXJhY3RlcnMgdGhhdCBkb24ndCBhcHBlYXIgaW4gdGhhdCBib29rCnJtKHRvX2RlbGV0ZSkKZm9yIChjaGFyYWN0ZXIgaW4gMTpucm93KGJvb2tfZGYpKXsKICBpZihzdW0oYm9va19kZltjaGFyYWN0ZXIsIGMoMjpuY29sKGJvb2tfZGYpKV0pIDwgMSl7CiAgICBpZmVsc2UoIWV4aXN0cygidG9fZGVsZXRlIiksIAogICAgICAgICAgIHRvX2RlbGV0ZSA8LSBjKGNoYXJhY3RlciksCiAgICAgICAgICAgdG9fZGVsZXRlIDwtIGFwcGVuZCh0b19kZWxldGUsIGNoYXJhY3RlcikKICAgICkKICB9fQpib29rX2RmIDwtIGJvb2tfZGZbLWModG9fZGVsZXRlKSxdCgojcHJlcGFyZSBhIG1hdHJpeCBvZiBpbnRlcmFjdGlvbnMgYmV0d2VlbiBlYWNoIGNoYXJhY3RlcgojYSBkZiBvZiBuKGNoYXJhY3RlcnMpIHggbihjaGFyYWN0ZXJzKSB3aGVyZSB0aGUgdmFsdWUgaXMgdGhlIGNvbm5lY3Rpb25zCiNiZXR3ZWVuIGNoYXJhY3Rlcltyb3ddIGFuZCBjaGFyYWN0ZXJbY29sdW1uXQpybShCb29rX01hdHJpeCkKZm9yIChwcm90YWcgaW4gMTpucm93KGJvb2tfZGYpKXsKICBmb3IgKG90aGVyIGluIDE6bnJvdyhib29rX2RmKSl7CiAgICBpZihwcm90YWcgPT0gb3RoZXIpewogICAgICBpZmVsc2Uob3RoZXIgPT0gMSwgCiAgICAgICAgICAgICBuZXdyb3cgPC0gMCwKICAgICAgICAgICAgIG5ld3JvdyA8LSBhcHBlbmQobmV3cm93LCAwKSkKICAgIH0gZWxzZXsKICAgIGNvbm5lY3Rpb24gPC0gbGVuZ3RoKHdoaWNoKAogCQkJCWJvb2tfZGZbcHJvdGFnLF0gPT0gMSAmCiAJCQkJYm9va19kZltvdGhlcixdID09IDEpKQogICAgICBpZmVsc2Uob3RoZXIgPT0gMSwgCiAgICAgICAgICAgICBuZXdyb3cgPC0gY29ubmVjdGlvbiwKICAgICAgICAgICAgIG5ld3JvdyA8LSBhcHBlbmQobmV3cm93LCBjb25uZWN0aW9uKSkKICAgIH0KICB9CiAgbmV3cm93IDwtIGRhdGEuZnJhbWUobmV3cm93KQogICAgbmFtZXMobmV3cm93KSA8LSBib29rX2RmJG5hbWVbcHJvdGFnXQogICAgaWZlbHNlKCFleGlzdHMoIkJvb2tfTWF0cml4IiksIAogICAgICAgICBCb29rX01hdHJpeCA8LSBuZXdyb3csCiAgICAgICAgIEJvb2tfTWF0cml4IDwtIGNiaW5kKEJvb2tfTWF0cml4LCBuZXdyb3cpKQogIH0KCiNtYWtlIG5ldHdvcmsgb2JqZWN0IG9mIHRoZSBtYXRyaXggdXNpbmcgbmV0d29yaygpCnJvd25hbWVzKEJvb2tfTWF0cml4KSA8LSBjb2xuYW1lcyhCb29rX01hdHJpeCkKbmV0IDwtIG5ldHdvcmsoQm9va19NYXRyaXgpCgojcHJlcGFyZSB0aGUgbm9kZXMgZGYgYnkgZGVsZXRpbmcgdW51c2VkIG5vZGVzCiNpLmUuIHRoZSBjaGFyYWN0ZXJzIHRoYXQgZG9uJ3QgYXBwZWFyIGluIHRoaXMgYm9vawpOb2Rlc0Jvb2sgPC0gTm9kZXNbd2hpY2goTm9kZXMkbmFtZSAlaW4lIGJvb2tfZGYkbmFtZSksXQoKI2FkZCByb3duYW1lcyBzbyB3ZSBjYW4gZmluZCBlYWNoIG5vZGUgZnJvbSB0aGUgbmV0d29yayBvYmplY3QKcm93bmFtZXMoTm9kZXNCb29rKSA8LSBOb2Rlc0Jvb2skb3JkZXIKI0Fsc28gY2hhbmdlIHRoZSBzaXplIHZhcmlhYmxlIHRvIGJlIHRoZSBudW1iZXIgb2YgY2hhcHRlcnMgZWFjaAojY2hhcmFjdGVyIGFwcGVhcnMgaW4gaW4ganVzdCB0aGlzIG9uZSBib29rCk5vZGVzQm9vayRzaXplIDwtIHJvd1N1bXMoYm9va19kZlsyOm5jb2woYm9va19kZildKQoKI2JpbmQgYWV0aGV0aWNzIHRvIHRoZSBuZXR3b3JrIG9iamVjdApuZXQgJXYlICJyZWdpb24iID0gYXMuY2hhcmFjdGVyKE5vZGVzQm9vayRyZWdpb24pCm5ldCAldiUgImNvbG91ciIgPSBhcy5jaGFyYWN0ZXIoTm9kZXNCb29rJGNvbG91cikKbmV0ICV2JSAic2l6ZSIgPSAoYXMubnVtZXJpYyhOb2Rlc0Jvb2skc2l6ZSkgXiAwLjI1KSAqIDIuNQpuZXQgJXYlICJub2Rlc2l6ZSIgPSBsb2coYXMubnVtZXJpYyhOb2Rlc0Jvb2skc2l6ZSkpICogMwoKI3NldCB1cCB3aGljaCBsYWJlbHMgdG8gc2hvdwojKGkuZS4gb25seSAicmVjdXJyaW5nIiBjaGFyYWN0ZXJzIHdobyBhcmUgaW4gbW9yZSB0aGFuIDMgY2hhcHRlcnMpCnBvdnMgPC0gdW5pcXVlKHBvdl9jaGFwdGVycyRwb3YpCmV4dHJhbGFiZWxzIDwtIGJvb2tfZGYkbmFtZVt3aGljaChyb3dTdW1zKGJvb2tfZGZbMjpuY29sKGJvb2tfZGYpXSkgPiAxMCldCmxhYmVscyA8LSBhcHBlbmQodW5pcXVlKHBvdnMpLCBleHRyYWxhYmVscykKI3NldCB1cCBjb2xvdXJzIGZvciBlYWNoIHJlZ2lvbgp5IDwtIGMoRG9ybmUuID0gIk9yYW5nZSIsIFZhbGUuID0gIlNreWJsdWUiLCBXZXN0ZXJsYW5kcy4gPSAiUmVkIiwKICAgICAgIFN0b3JtbGFuZHMuID0gIlllbGxvdyIsIFJpdmVybGFuZHMuID0gIkRhcmtibHVlIiwgCiAgICAgICBDcm93bmxhbmRzLiA9ICJHb2xkZW5yb2QiLCBOb3J0aC4gPSAiV2hpdGUiLCBJc2xhbmRzLiA9ICJHcmV5MzAiLAogICAgICAgUmVhY2guID0gIkRhcmtncmVlbiIsIG5vbmUgPSAiR3JleTcwIiwgV2VzdGVyb3MuID0gIlB1cnBsZSIpCgojcGxvdCB0aGUgZ2duZXQKcGxvdCA8LSBnZ25ldDIobmV0LCBsYWJlbCA9IGxhYmVscywgbm9kZS5jb2xvciA9ICJyZWdpb24iLCBwYWxldHRlID0geSwKICAgICAgICAgICAgICAgbGFiZWwuc2l6ZSA9ICJzaXplIiwgbm9kZS5zaXplID0gIm5vZGVzaXplIiwKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjc1LCBlZGdlLmNvbG9yID0gImdyZXk3NSIpICsKICAgIGdndGl0bGUocGFzdGUwKCJCb29rICIsIGJvb2ssICI6ICIsIGJvb2tzJHRpdGxlW2Jvb2tdKSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwKICAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYm9va3MkY292ZXJfY29sb3Vyc1tib29rXSksCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBib29rcyRsaWdodF9jb3ZlcnNbYm9va10pKQoKI2Fzc2lnbiB0aGUgcGxvdCB0byB0aGUgYm9vayBudW1iZXIKYXNzaWduKHBhc3RlMCgiYm9vayIsIGJvb2spLCBwbG90KQoKI2Nsb3NlIHVwIHRoZSBsb29wIHBlciBib29rCn0KYGBgCgpUaGVuIG1ha2UgdGhlIGZpbmFsIGxhdHRpY2UgcGxvdCBvZiBhbGwgZml2ZSBib29rcyB0b2dldGhlciB1c2luZyBncmlkLmFycmFuZ2UoKQoKYGBge3J9CmxpYnJhcnkoZ3JpZEV4dHJhKQoKI3Bsb3QgYWxsIGZpdmUgYm9va3MKZ3JpZC5hcnJhbmdlKGJvb2sxLCBib29rMiwgYm9vazMsIGJvb2s0LCBib29rNSkKYGBgCg==