Analysis and other experimentation for my Data Driven Shaw Brothers Analysis.

Follow along here!

library(scales)
library(ggthemes)
library(tidyjson)
library(tidyverse)
Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages ---------------------------------------------------------------------------------
col_factor():  readr, scales
col_numeric(): readr, scales
discard():     purrr, scales
filter():      dplyr, stats
lag():         dplyr, stats
library(forcats)
source("v_theme.R")

Read in Data

First, we need to get the data somehow. Its in JSON format, so let’s read the JSON into a string.

filename = '../scrape/out/shaw.json'
shaw_json <- paste(readLines(filename), collapse="")
incomplete final line found on '../scrape/out/shaw.json'

Then use tidyjson to convert the nested form into a flat data frame (tibble) we can work with.

films <- shaw_json %>% as.tbl_json %>% gather_array %>%
  spread_values(
    title = jstring("title"),
    director = jstring('director'),
    year = jstring('year'),
    avg_rating = jnumber('avg_rating'),
    watches = jnumber("watches"),
    likes = jnumber("likes"),
    time = jnumber("time")
  )
films %>% head(n = 5) %>% select(title, director, year)

The above table has a row for every film.

We can use tidyjson again to create a row for each actor, duplicating the film-specific data for each actor that had a part in it.

cast <- shaw_json  %>% as.tbl_json  %>% gather_array %>%
  spread_values(
    title = jstring("title"),
    director = jstring('director'),
    year = jstring('year'),
    avg_rating = jnumber('avg_rating'),
    watches = jnumber("watches"),
    likes = jnumber("likes"),
    time = jnumber("time")
  ) %>% enter_object("cast") %>% gather_array() %>%
  spread_values(
    name = jstring("name")
  )
cast %>% head(n = 8) %>% select(title, year, name)

Right now characters are a separte array

characters <- shaw_json  %>% as.tbl_json  %>% gather_array %>%
  spread_values(
    title = jstring("title"),
    director = jstring('director'),
    year = jstring('year'),
    avg_rating = jnumber('avg_rating'),
    watches = jnumber("watches"),
    likes = jnumber("likes")
  ) %>% enter_object("characters") %>% gather_array() %>%
  spread_values(
    name = jstring("name")
  )

Real quick, let’s get a sense of the number of films in our data.

nrow(films)
[1] 260

260! That’s a lot of Kung Fu. Let’s take a look at these films from a few different angles. We can start with release year.

Shaw Brothers, Through The Ages

So, I said retro, when exactly were these movies made?

films %>% ggplot(aes(x = year)) +
  geom_bar() +
  labs(title = 'Shaw Bros Films by Year') + 
  theme_fivethirtyeight()
ggsave("imgs/films_by_year.png", width = 8, height = 5)

The first Kung fu Shaw Brothers film in this data set is Temple of the Red Lotus from 1965. From the reviews, it sounds like it was a bit rough around the edges - but thats about what you would expect from this burgeoning genre.

The studio hits its stride in the early 70’s, with a lull in the mid 70’s and another spike in the late 70’s, early 80’s. Keep in mind that even during the lull, the studio is still putting out 10 or more Kung fu movies most years.

Shaw Brothers Directorial Favorites

We have the director for each movie in our dataset, let’s look to see if there are any popular standouts.

by_director <- films %>% group_by(director) %>% summarise(n = n()) %>% arrange(-n)
  by_director %>% filter(n > 1) %>%
  ggplot(aes(x = fct_reorder(director, n), y = n)) + 
  geom_bar(stat = "identity") +
  coord_flip() +
  labs(title = 'Counts of Shaw Bros Films by Director') +
  theme_fivethirtyeight()
ggsave("imgs/director_count.png", width = 8, height = 6)

I’d say! Chang Cheh directed 67 or roughly 26% of all Shaw Brothers Kung fu!

According to his Wikipedia page, he was known as the “The Godfather of Hong Kong cinema”, and rightly so - at least in terms of quantity.

Let’s pull out the top 5 directors, in terms of movie count, and see when they were most active.

# pull out just the top 5 directors
top_directors <- by_director %>% head(n = 5)
# filter films to those directed by these titans of Kung fu
films_top_director <- films %>% filter(director %in% top_directors$director)
#plot bar chart
films_top_director %>%
  ggplot(aes(x = year)) +
  geom_bar(aes(fill = director)) +
  labs(title = 'Shaw Bros Top Director Count by Year') + 
  theme_fivethirtyeight()

# Try Fill Position
films_top_director %>%
  ggplot(aes(x = year)) +
  geom_bar(aes(fill = director), position = "fill") +
  labs(title = 'Shaw Bros Top Director Count by Year') + 
  theme_fivethirtyeight()

That was with filtering to just the top directors. What happens when we put all of them in?

films_top_director_all <- films %>% mutate(director_label = ifelse(director %in% top_directors$director, director, 'Other'))
films_top_director_all %>%
  ggplot(aes(x = year)) +
  geom_bar(aes(fill = director_label)) +
  labs(title = 'Shaw Bros Director Count by Year', fill = '') + 
  theme_fivethirtyeight()
ggsave("imgs/top_directors_by_year.png", width = 8, height = 5)

films_top_director_all %>%
  ggplot(aes(x = year)) +
  geom_bar(aes(fill = director_label), position = 'fill') +
  labs(title = 'Shaw Bros Director Count by Year', fill = '') + 
  theme_fivethirtyeight() +
  scale_y_continuous(labels = percent)
ggsave("imgs/top_directors_by_year_fill.png", width = 8, height = 5)

Other Values over Time

summary(films)
  document.id  array.index        title             director             year             avg_rating   
 Min.   :1    Min.   :  1.00   Length:260         Length:260         Length:260         Min.   :2.900  
 1st Qu.:1    1st Qu.: 65.75   Class :character   Class :character   Class :character   1st Qu.:3.400  
 Median :1    Median :130.50   Mode  :character   Mode  :character   Mode  :character   Median :3.400  
 Mean   :1    Mean   :130.50                                                            Mean   :3.462  
 3rd Qu.:1    3rd Qu.:195.25                                                            3rd Qu.:3.600  
 Max.   :1    Max.   :260.00                                                            Max.   :4.000  
                                                                                        NA's   :187    
    watches           likes             time       
 Min.   :  3.00   Min.   :  0.00   Min.   : 70.00  
 1st Qu.: 12.00   1st Qu.:  2.00   1st Qu.: 88.00  
 Median : 23.50   Median :  6.00   Median : 94.00  
 Mean   : 66.43   Mean   : 18.78   Mean   : 95.13  
 3rd Qu.: 56.00   3rd Qu.: 15.25   3rd Qu.:101.00  
 Max.   :818.00   Max.   :290.00   Max.   :137.00  
                                   NA's   :28      
film_summary <- films %>% group_by(year) %>% summarise(n = n(), mean_time = mean(time, na.rm = TRUE))
film_summary %>%
  ggplot(aes(x = year, y = mean_time)) +
  geom_bar(stat = "identity") +
  labs(title = 'Shaw Bros Length by Year (in mins)') + 
  theme_fivethirtyeight()

#ggsave("imgs/films_by_year.png", width = 8, height = 5)
films %>%
  ggplot(aes(x = year, y = time )) +
  geom_boxplot() +
  labs(title = 'Shaw Bros Length by Year (in mins)') + 
  theme_fivethirtyeight()

films %>%
  ggplot(aes(x = year, y = avg_rating )) +
  geom_boxplot() +
  labs(title = 'Shaw Bros Rating by Year') + 
  theme_fivethirtyeight()

films %>%
  ggplot(aes(x = year, y = watches )) +
  geom_boxplot() +
  labs(title = 'Shaw Bros Watches by Year') + 
  theme_fivethirtyeight()

films %>% filter(watches > 200) %>% select(title, year, watches) %>% arrange(-watches)
films  %>%
  ggplot(aes(x = watches, y = avg_rating)) +
  geom_point()

films  %>%
  ggplot(aes(x = watches, y = likes)) +
  geom_point() + 
  labs(title = "Watches vs Likes of Kung Fu Movies") +
  theme_fivethirtyeight()
ggsave("imgs/watches_vs_likes.png", width = 8, height = 5)

films  %>%
  ggplot(aes(x = avg_rating, y = likes)) +
  geom_point()

films %>%
  ggplot(aes(x = year, y = likes )) +
  geom_boxplot() +
  labs(title = 'Shaw Bros Rating by Year') + 
  theme_fivethirtyeight()

Title Showdown

library(tidytext)
# load stop_words into R environment
data("stop_words")
# saves entire title in `title_all` column, 
# then splits up title column creating the `word` column - 
# with a row for every token (word).
titles <- films %>% mutate(title_all = title) %>% unnest_tokens(word, title)
# filter stopwords
titles_filter <- titles %>% anti_join(stop_words, by = "word")
by_word <- titles_filter %>% count(word, sort = TRUE)
by_word %>%
  filter(n > 3) %>% 
  ggplot(aes(x = fct_reorder(word, n), y = n)) +
  geom_bar(stat = 'identity') +
  coord_flip() + 
  labs(title = 'Top Words Used in Kung Fu Titles') +
  theme_fivethirtyeight()
ggsave("imgs/top_words_in_titles.png",  width = 8, height = 6)

top_word <- by_word %>% head(n = 12)
films_top_word <- titles %>% filter(word %in% top_word$word)
films_top_word %>% 
  ggplot(aes(x = year)) +
  geom_bar() +
  labs(title = 'Titles with Most Common Words by Year') + 
  facet_wrap( ~ fct_relevel(word, top_word$word)) +
  scale_x_discrete(labels = function(x) { return(ifelse(as.numeric(x) %% 2, x, '')) }) +
  theme_fivethirtyeight() + 
  theme(axis.text.x = element_text(angle = 45, hjust = 1), legend.position="none")
ggsave("imgs/top_words_by_time.png", width = 8, height = 6)

Swordsman or Shaolin?

top2_word <- by_word %>% head(n = 2)
films_top2_word <- titles %>% filter(word %in% top2_word$word)
films_top2_word %>% 
  ggplot(aes(x = year, fill = fct_inorder(word))) +
  geom_bar() +
  labs(title = 'Swordsman vs Shaolin by Year', fill = '') + 
  #scale_x_discrete(labels = function(x) { return(ifelse(as.numeric(x) %% 2, x, '')) }) +
  theme_fivethirtyeight() 
  #theme(axis.text.x = element_text(angle = 45, hjust = 1))
ggsave("imgs/shaolin_swordsman.png", width = 8, height = 5)

Swordsman Titles

titles %>% filter(word == 'swordsman') %>% arrange(year) %>% select(title_all, year)

swordsman success: https://en.wikipedia.org/wiki/One-Armed_Swordsman

It was the first of the new style of wuxia films emphasizing male anti-heroes, violent swordplay and heavy bloodletting. It was the first Hong Kong film to make HK$1 million at the local box office, propelling its star Jimmy Wang to super stardom.

Wuxia Films.

30 Essential Wuxia Films

The Chinese martial arts movie is generally split into two primary subgeneres: the kung fu film and the wuxia film. The kung fu film is newer and focuses primarily on hand-to-hand combat, it’s steeped in traditional fighting forms and there’s a general emphasis on the physical skill of the performer: special effects are generally disdained. Bruce Lee and Jackie Chan are its most famous practitioners and Lau Kar-leung its most important director.

Wuxia is a much older form, based ultimately in the long tradition of Chinese adventure literature, in classic novels such as The Water Margin or Journey to the West, or more contemporary works by authors like Louis Cha and Gu Long. Its heroes follow a very specific code of honor as they navigate the jianghu, an underworld of outlaws and bandits outside the normal streams of civilization.

From Wuxia Women Warriors

Less realistic than its cousin, the kung fu film, wuxia often includes gravity-defying stunts where legendary warriors fly through the air or punch holes straight through their enemies’ chests.

Shaolin Titles

titles %>% filter(word == 'shaolin') %>% arrange(year) %>% select(title_all, year)

From History in the Shaw Brothers

These films, focused on the Shaolin Temple as a center for anti-Qing resistance, provide a dizzying metaphorical potential, with the Qing variously standing in for Western imperialists, the Japanese, the Nationalist Kuomingtang, the Communists, or even simply the Manchurians themselves, while the Buddhism of the monks allows for examining of the contradictions at the heart of traditional Chinese belief systems, between the imperatives of social justice and withdrawal from worldly concerns.

Actor Troupes and Groups

Even with my novice-level consuption of Shaw Brothers films, one thing I noticed early on was a lot of familiar faces that showed up in many of the movies. My assumption is just like directors, there are a number of actors that are heavily reused in these films. Let’s see if I am right!

First, just like directors, we can look at counts by actor.

by_actor <- cast %>% group_by(name) %>% summarise(n = n()) %>% arrange(-n)
by_actor %>% filter(n > 20) %>%
  ggplot(aes(x = fct_reorder(name, n), y = n)) +
  geom_bar(stat = "identity") +
  coord_flip() +
  labs(title = 'Counts of Shaw Bros Films by Actor') +
  theme_fivethirtyeight()

ggsave("imgs/actor_counts.png", width = 8, height = 6)

Wow! Ku Feng apparently appeared in 82 Kung Fu movies. That’s a lot of Kung Fu!

His Wikipedia page isn’t as impressed with this feat as I am, providing little information on this Martial Arts Maniac. Apparently his real name is Chan Sze-man, and his first film was in 1959, and apparently he is still acting. The HKMDB, or Hong Kong Movie Database, provides just a bit more info:

In 1965, Ku formally signed an acting contract with Shaw Brothers where he made around 100 films for them and became most notably known as one of their top character actors. He has worked with just about every top Hong Kong director in a variety of films.

Ok then, well props to you Ku.

Did most of the top actors’ carreers span multiple decades, or did actors come and go quickly? Let’s graph the top actor’s movie count by year.

top_actor <- by_actor %>% head(n = 16)
films_top_actor <- cast %>% filter(name %in% top_actor$name)
films_top_actor %>% 
  ggplot(aes(x = year)) +
  geom_bar() +
  labs(title = 'Top Actors Film Count by Year') + 
  facet_wrap( ~ fct_relevel(name, top_actor$name)) +
  # only label half of the years to make things a bit look cleaner
  scale_x_discrete(labels = function(x) { return(ifelse(as.numeric(x) %% 2, x, '')) }) +
  theme_fivethirtyeight() + 
  # angle label text
  theme(axis.text.x = element_text(angle = 45, hjust = 1), legend.position="none")

ggsave("imgs/top_actors_by_year.png", width = 8, height = 10)
year_count <- films %>% select(year) %>% unique() %>% nrow()
actor_active_years <- films_top_actor %>% group_by(name) %>% 
  summarise(active_years = length(unique(year)), 
            percent_active = active_years / year_count, 
            start = min(as.numeric(year)), 
            end = max(as.numeric(year))) %>% 
  arrange(percent_active)
actor_active_years %>% 
  ggplot(aes(x = fct_inorder(name), y = percent_active)) + 
  geom_bar(stat = "identity") +
  coord_flip() + 
  scale_y_continuous(labels = percent) + 
  labs(title = "Percent of Years Active by Actor") +
  theme_fivethirtyeight()
ggsave("imgs/actor_percent_active.png", width = 8, height = 5)

actor_active_years %>% gather(caps, cap_year, start, end) %>%
  ggplot(aes(x = cap_year, y = fct_inorder(name))) +
  geom_point(size = 3) + 
  geom_path(aes(group = name)) +
  labs(title = "Shaw Brother Career Span by Actor") +
  theme_fivethirtyeight()
ggsave("imgs/actor_career_span.png", width = 8, height = 5)    

Finding A Mob of Venoms

Venom Mob

Inspiration from Love Actually Analysis by David Robinson.

Create a matrix of actor co-occurance.

summary(by_actor$n)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    1.0     1.0     2.0     4.6     4.0    84.0 
library(reshape2)

Attaching package: ‘reshape2’

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

    smiths
# filter actors not in many movies
min_movie_actors <- by_actor %>% filter(n > 5)
popular_cast <- cast %>% filter(name %in% min_movie_actors$name) 
cast_movie_matrix <- popular_cast %>%
  acast(name ~ title,  fun.aggregate = length)
Using name as value column: use value.var to override.
dim(cast_movie_matrix)
[1] 125 258

Rows are actors. Columns are movies.

Filter out movies with few co-occuring actors

cast_movie_df_filtered <- cast_movie_matrix %>% colSums(.)
norm <- cast_movie_matrix / rowSums(cast_movie_matrix)
hc_norm_cast <- hclust(dist(norm, method = "manhattan"))

Plot:

library(ggdendro)
ggdendrogram(hc_norm_cast, rotate = TRUE)

See ordering:

ordering <-hc_norm_cast$labels[hc_norm_cast$order]
ordering
  [1] "Chin Ping"             "Jimmy Wang Yu"         "Lisa Chiao Chiao"      "Tien Feng"            
  [5] "Chang Yi"              "Goo Man-Chung"         "Shu Pei-Pei"           "Tang Ti"              
  [9] "Wu Ma"                 "Lee Wan-Chung"         "Chen Hung-Lieh"        "Fang Mian"            
 [13] "Tung Lam"              "Fan Mei-Sheng"         "Lily Ho Li-Li"         "Bolo Yeung"           
 [17] "James Nam Gung-Fan"    "Ku Wen-Chung"          "Bruce Tong Yim-Chaan"  "Dick Wei"             
 [21] "Shih Szu"              "Wai Wang"              "Chan Shen"             "Lily Li Li-Li"        
 [25] "Tung Li"               "Law Hon"               "Lee Pang-Fei"          "Wang Hsieh"           
 [29] "Chiu Hung"             "Wong Chung-Shun"       "Philip Kwok Chun-Fung" "Chiang Sheng"         
 [33] "Lu Feng"               "Lo Meng"               "Sun Chien"             "Candy Wen Xue-Er"     
 [37] "Lung Tien-Hsiang"      "Siao Yuk"              "Chin Siu-Ho"           "Lau Fong-Sai"         
 [41] "Yu Tai-Ping"           "Lam Chi-Tai"           "Wong Lik"              "Chen Ping"            
 [45] "Danny Lee Sau-Yin"     "Wong Chung"            "Yuen Bun"              "Yuen Wah"             
 [49] "Candice Yu On-On"      "Derek Yee Tung-Sing"   "Lau Wai-Ling"          "Ling Yun"             
 [53] "Lau Wing"              "Norman Chu"            "Ku Kuan-Chung"         "Ching Li"             
 [57] "Ngaai Fei"             "Ku Feng"               "Lo Lieh"               "Elliot Ngok"          
 [61] "Cheng Miu"             "Yeung Chi-Hing"        "Wilson Tong"           "Hsiao Ho"             
 [65] "King Lee King-Chu"     "Lam Fai-Wong"          "Wong Ching-Ho"         "Alexander Fu Sheng"   
 [69] "Johnny Wang Lung-Wei"  "Gordon Liu Chia-Hui"   "Kara Hui"              "Cheung Pooi-Saan"     
 [73] "Dean Shek"             "Wang Han-Chen"         "Choh Seung-Wan"        "Helen Poon Bing-Seung"
 [77] "Dang Wai-Ho"           "Jason Pai Piao"        "Kwan Fung"             "Leanne Lau Suet-Wa"   
 [81] "Phillip Ko Fei"        "Chan Sze-Kai"          "Yeung Jing-Jing"       "Keung Hon"            
 [85] "Shum Lo"               "Teresa Ha Ping"        "Ou-Yang Sha-Fei"       "Ivy Ling Po"          
 [89] "Lam Jing"              "Chin Han"              "Chung Wa"              "Wang Ping"            
 [93] "David Chiang"          "Ti Lung"               "Li Ching"              "Tin Ching"            
 [97] "Chiang Nan"            "Fung Ngai"             "Fung Hak-On"           "Lo Dik"               
[101] "Chi Kuan-Chun"         "Leung Kar-Yan"         "Cheng Pei-Pei"         "Lan Wei-Lieh"         
[105] "Lau Kar-Wing"          "Liu Chia-Liang"        "Cliff Lok"             "Cheng Lui"            
[109] "Wang Kuang-Yu"         "Chan Sing"             "Lau Gong"              "Tang Ching"           
[113] "Wong Yung"             "Lo Wei"                "Chiu Sam-Yin"          "Hung Lau"             
[117] "Walter Tso Tat-Wah"    "Austin Wai"            "Wong Mei-Mei"          "Ng Hong-Sang"         
[121] "Yuen Tak"              "Chen Kuan-Tai"         "Chiang Tao"            "Lee Hoi-Sang"         
[125] "Wong Yu"              
# http://stackoverflow.com/questions/13281303/creating-co-occurrence-matrix
cooccur <- cast_movie_matrix %*% t(cast_movie_matrix)
diag(cooccur) <- 0
heatmap(cooccur, symm = TRUE )

cooccur is matrix with rows and columns as actors. The cells for each actor combo indicate the number of movies they have appeared together in.

summary(rowSums(cooccur))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
     39      65      94     125     143     631 
summary(colSums(cooccur))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
     39      65      94     125     143     631 
summary(colSums(cooccur != 0))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  21.00   36.00   46.00   49.94   57.00  119.00 
collab_counts <- as.data.frame(colSums(cooccur != 0))
library(igraph)

Attaching package: ‘igraph’

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

    %>%

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

    %>%, as_data_frame, groups, union

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

    %>%, compose, simplify

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

    %>%, crossing

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

    as_data_frame

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

    decompose, spectrum

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

    union
cooccur <- cast_movie_matrix %*% t(cast_movie_matrix)
#cooccur <- ifelse(cooccur < 4, 0, cooccur)
g <- graph.adjacency(cooccur, weighted = TRUE, mode = "undirected", diag = FALSE)
summary(E(g)$weight)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   1.000   2.000   2.503   3.000  30.000 
summary(degree(g))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  21.00   36.00   46.00   49.94   57.00  119.00 
summary(strength(g))
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
     39      65      94     125     143     631 
library(igraph)
cooccur <- cast_movie_matrix %*% t(cast_movie_matrix)
#cooccur <- ifelse(cooccur < 4, 0, cooccur)
g <- graph.adjacency(cooccur, weighted = TRUE, mode = "undirected", diag = FALSE)
low_degree_v <- V(g)[degree(g) < 10] #identify those vertices part of less than three edges
g <- delete_vertices(g, low_degree_v) #exclude them from the graph
low_weight_e <- E(g)[E(g)$weight < 3]
g <- delete_edges(g, low_weight_e)
low_strength_v <- V(g)[strength(g) < 90]
g <- delete_vertices(g, low_strength_v) #exclude them from the graph
V(g)$betweenness <- strength(g)
plot(g, edge.width = E(g)$weight, 
     #layout=layout.fruchterman.reingold,
     layout=layout_with_fr,
     vertex.label.dist=0.5,
     #vertex.size = V(g)$betweenness,
     vertex.size = 3,
     vertex.color='steelblue',
     vertex.frame.color='white',        #the color of the border of the dots 
     vertex.label.color='black',        #the color of the name labels
     vertex.label.font=2,           #the font of the name labels
     vertex.label.cex=1,            #specifies the size of the font of the labels. can also be made to vary
     edge.color = hsv(0,0.2,0.5,alpha=0.2)
)

chiang_sheng <- V(g)[V(g)$name == "Chiang Sheng"]
chiang_sheng_neighbors <- neighbors(g, chiang_sheng)
neighbor_edges <- incident_edges(g, chiang_sheng_neighbors)
sub_g <- make_empty_graph(n = length(chiang_sheng_neighbors), directed = FALSE)
add_vertices(sub_g, chiang_sheng_neighbors)
IGRAPH U--- 14 0 -- 
+ edges:
#add_edges(sub_g, neighbor_edges)
#E(g)[neighbor_edges]$color = hsv(0,0.2,0.5,alpha=0.5)
V(g)$color = "grey"
V(g)[chiang_sheng]$color = "tomato"
V(g)[chiang_sheng_neighbors]$color = 'tomato'
plot(g, edge.width = E(g)$weight, 
     #layout=layout.fruchterman.reingold,
     layout=layout_with_fr,
     vertex.label.dist=0.5,
     #vertex.size = V(g)$betweenness,
     vertex.size = 5,
     vertex.color=V(g)$color,
     vertex.frame.color='white',        #the color of the border of the dots 
     vertex.label.color='black',        #the color of the name labels
     vertex.label.font=2,           #the font of the name labels
     vertex.label.cex=1,            #specifies the size of the font of the labels. can also be made to vary
     edge.color = hsv(0,0.2,0.5,alpha=0.2)
)

cooccur_df <- data.frame(cooccur, col.names = colnames(cooccur))
cooccur_df$name <- row.names(cooccur) 
cooccur_df <- cooccur_df %>% select(name, everything())
#write_delim(cooccur_df, 'shaw_cooccurance.csv', delim = ';')
LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgU2hhdyBCcm90aGVycyBLdW5nIEZ1IEZpbG1zIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBtYXRoamF4OiBudWxsCiAgICB0aGVtZTogeWV0aQogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCi0tLQoKQW5hbHlzaXMgYW5kIG90aGVyIGV4cGVyaW1lbnRhdGlvbiBmb3IgbXkgW0RhdGEgRHJpdmVuIFNoYXcgQnJvdGhlcnMgQW5hbHlzaXNdKCkuCgpGb2xsb3cgYWxvbmcgaGVyZSEKCmBgYHtyfQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeSh0aWR5anNvbikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZm9yY2F0cykKCmBgYAoKIyMgUmVhZCBpbiBEYXRhCgpGaXJzdCwgd2UgbmVlZCB0byBnZXQgdGhlIGRhdGEgc29tZWhvdy4gSXRzIGluIEpTT04gZm9ybWF0LCBzbyBsZXQncyByZWFkIHRoZSBKU09OIGludG8gYSBzdHJpbmcuCgpgYGB7cn0KZmlsZW5hbWUgPSAnLi4vc2NyYXBlL291dC9zaGF3Lmpzb24nCnNoYXdfanNvbiA8LSBwYXN0ZShyZWFkTGluZXMoZmlsZW5hbWUpLCBjb2xsYXBzZT0iIikKYGBgCgpUaGVuIHVzZSBbdGlkeWpzb25dKGh0dHBzOi8vZ2l0aHViLmNvbS9zYWlsdGhydS90aWR5anNvbikgdG8gY29udmVydCB0aGUgbmVzdGVkIGZvcm0gaW50byBhIGZsYXQgZGF0YSBmcmFtZSAoW3RpYmJsZV0oaHR0cHM6Ly9ibG9nLnJzdHVkaW8ub3JnLzIwMTYvMDMvMjQvdGliYmxlLTEtMC0wLykpIHdlIGNhbiB3b3JrIHdpdGguIAoKYGBge3J9CmZpbG1zIDwtIHNoYXdfanNvbiAlPiUgYXMudGJsX2pzb24gJT4lIGdhdGhlcl9hcnJheSAlPiUKICBzcHJlYWRfdmFsdWVzKAogICAgdGl0bGUgPSBqc3RyaW5nKCJ0aXRsZSIpLAogICAgZGlyZWN0b3IgPSBqc3RyaW5nKCdkaXJlY3RvcicpLAogICAgeWVhciA9IGpzdHJpbmcoJ3llYXInKSwKICAgIGF2Z19yYXRpbmcgPSBqbnVtYmVyKCdhdmdfcmF0aW5nJyksCiAgICB3YXRjaGVzID0gam51bWJlcigid2F0Y2hlcyIpLAogICAgbGlrZXMgPSBqbnVtYmVyKCJsaWtlcyIpLAogICAgdGltZSA9IGpudW1iZXIoInRpbWUiKQogICkKCmZpbG1zICU+JSBoZWFkKG4gPSA1KSAlPiUgc2VsZWN0KHRpdGxlLCBkaXJlY3RvciwgeWVhcikKYGBgCgpUaGUgYWJvdmUgdGFibGUgaGFzIGEgcm93IGZvciBldmVyeSBmaWxtLiAKCldlIGNhbiB1c2UgYHRpZHlqc29uYCBhZ2FpbiB0byBjcmVhdGUgYSByb3cgZm9yIGVhY2ggYWN0b3IsIGR1cGxpY2F0aW5nIHRoZSBmaWxtLXNwZWNpZmljIGRhdGEgZm9yIGVhY2ggYWN0b3IgdGhhdCBoYWQgYSBwYXJ0IGluIGl0LgoKYGBge3J9CmNhc3QgPC0gc2hhd19qc29uICAlPiUgYXMudGJsX2pzb24gICU+JSBnYXRoZXJfYXJyYXkgJT4lCiAgc3ByZWFkX3ZhbHVlcygKICAgIHRpdGxlID0ganN0cmluZygidGl0bGUiKSwKICAgIGRpcmVjdG9yID0ganN0cmluZygnZGlyZWN0b3InKSwKICAgIHllYXIgPSBqc3RyaW5nKCd5ZWFyJyksCiAgICBhdmdfcmF0aW5nID0gam51bWJlcignYXZnX3JhdGluZycpLAogICAgd2F0Y2hlcyA9IGpudW1iZXIoIndhdGNoZXMiKSwKICAgIGxpa2VzID0gam51bWJlcigibGlrZXMiKSwKICAgIHRpbWUgPSBqbnVtYmVyKCJ0aW1lIikKICApICU+JSBlbnRlcl9vYmplY3QoImNhc3QiKSAlPiUgZ2F0aGVyX2FycmF5KCkgJT4lCiAgc3ByZWFkX3ZhbHVlcygKICAgIG5hbWUgPSBqc3RyaW5nKCJuYW1lIikKICApCgpjYXN0ICU+JSBoZWFkKG4gPSA4KSAlPiUgc2VsZWN0KHRpdGxlLCB5ZWFyLCBuYW1lKQpgYGAKClJpZ2h0IG5vdyBjaGFyYWN0ZXJzIGFyZSBhIHNlcGFydGUgYXJyYXkKCmBgYHtyfQpjaGFyYWN0ZXJzIDwtIHNoYXdfanNvbiAgJT4lIGFzLnRibF9qc29uICAlPiUgZ2F0aGVyX2FycmF5ICU+JQogIHNwcmVhZF92YWx1ZXMoCiAgICB0aXRsZSA9IGpzdHJpbmcoInRpdGxlIiksCiAgICBkaXJlY3RvciA9IGpzdHJpbmcoJ2RpcmVjdG9yJyksCiAgICB5ZWFyID0ganN0cmluZygneWVhcicpLAogICAgYXZnX3JhdGluZyA9IGpudW1iZXIoJ2F2Z19yYXRpbmcnKSwKICAgIHdhdGNoZXMgPSBqbnVtYmVyKCJ3YXRjaGVzIiksCiAgICBsaWtlcyA9IGpudW1iZXIoImxpa2VzIikKICApICU+JSBlbnRlcl9vYmplY3QoImNoYXJhY3RlcnMiKSAlPiUgZ2F0aGVyX2FycmF5KCkgJT4lCiAgc3ByZWFkX3ZhbHVlcygKICAgIG5hbWUgPSBqc3RyaW5nKCJuYW1lIikKICApCmBgYAoKUmVhbCBxdWljaywgbGV0J3MgZ2V0IGEgc2Vuc2Ugb2YgdGhlIG51bWJlciBvZiBmaWxtcyBpbiBvdXIgZGF0YS4KCmBgYHtyfQpucm93KGZpbG1zKQpgYGAKCjI2MCEgVGhhdCdzIGEgbG90IG9mIEt1bmcgRnUuIExldCdzIHRha2UgYSBsb29rIGF0IHRoZXNlIGZpbG1zIGZyb20gYSBmZXcgZGlmZmVyZW50IGFuZ2xlcy4gV2UgY2FuIHN0YXJ0IHdpdGggcmVsZWFzZSB5ZWFyLgoKIyMjIFNoYXcgQnJvdGhlcnMsIFRocm91Z2ggVGhlIEFnZXMKClNvLCBJIHNhaWQgcmV0cm8sIHdoZW4gZXhhY3RseSB3ZXJlIHRoZXNlIG1vdmllcyBtYWRlPwoKYGBge3J9CgpmaWxtcyAlPiUgZ2dwbG90KGFlcyh4ID0geWVhcikpICsKICBnZW9tX2JhcigpICsKICBsYWJzKHRpdGxlID0gJ1NoYXcgQnJvcyBGaWxtcyBieSBZZWFyJykgKyAKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKQpnZ3NhdmUoImltZ3MvZmlsbXNfYnlfeWVhci5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYAoKVGhlIGZpcnN0IEt1bmcgZnUgU2hhdyBCcm90aGVycyBmaWxtIGluIHRoaXMgZGF0YSBzZXQgaXMgW1RlbXBsZSBvZiB0aGUgUmVkIExvdHVzXShodHRwczovL2xldHRlcmJveGQuY29tL2ZpbG0vdGVtcGxlLW9mLXRoZS1yZWQtbG90dXMvKSBmcm9tIDE5NjUuIEZyb20gdGhlIHJldmlld3MsIGl0IHNvdW5kcyBsaWtlIGl0IHdhcyBhIGJpdCByb3VnaCBhcm91bmQgdGhlIGVkZ2VzIC0gYnV0IHRoYXRzIGFib3V0IHdoYXQgeW91IHdvdWxkIGV4cGVjdCBmcm9tIHRoaXMgYnVyZ2VvbmluZyBnZW5yZS4KClRoZSBzdHVkaW8gaGl0cyBpdHMgc3RyaWRlIGluIHRoZSBlYXJseSA3MCdzLCB3aXRoIGEgbHVsbCBpbiB0aGUgbWlkIDcwJ3MgYW5kIGFub3RoZXIgc3Bpa2UgaW4gdGhlIGxhdGUgNzAncywgZWFybHkgODAncy4gS2VlcCBpbiBtaW5kIHRoYXQgZXZlbiBkdXJpbmcgdGhlIGx1bGwsIHRoZSBzdHVkaW8gaXMgX3N0aWxsXyBwdXR0aW5nIG91dCAxMCBvciBtb3JlIEt1bmcgZnUgbW92aWVzIG1vc3QgeWVhcnMuIAoKCiMjIyBTaGF3IEJyb3RoZXJzIERpcmVjdG9yaWFsIEZhdm9yaXRlcwoKV2UgaGF2ZSB0aGUgZGlyZWN0b3IgZm9yIGVhY2ggbW92aWUgaW4gb3VyIGRhdGFzZXQsIGxldCdzIGxvb2sgdG8gc2VlIGlmIHRoZXJlIGFyZSBhbnkgcG9wdWxhciBzdGFuZG91dHMuCgoKYGBge3J9CmJ5X2RpcmVjdG9yIDwtIGZpbG1zICU+JSBncm91cF9ieShkaXJlY3RvcikgJT4lIHN1bW1hcmlzZShuID0gbigpKSAlPiUgYXJyYW5nZSgtbikKCiAgYnlfZGlyZWN0b3IgJT4lIGZpbHRlcihuID4gMSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3Jlb3JkZXIoZGlyZWN0b3IsIG4pLCB5ID0gbikpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnModGl0bGUgPSAnQ291bnRzIG9mIFNoYXcgQnJvcyBGaWxtcyBieSBEaXJlY3RvcicpICsKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKQpnZ3NhdmUoImltZ3MvZGlyZWN0b3JfY291bnQucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA2KQpgYGAKCkknZCBzYXkhIFtDaGFuZyBDaGVoXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9DaGFuZ19DaGVoKSBkaXJlY3RlZCA2NyBvciByb3VnaGx5IDI2JSBvZiBhbGwgU2hhdyBCcm90aGVycyBLdW5nIGZ1IQoKQWNjb3JkaW5nIHRvIGhpcyBXaWtpcGVkaWEgcGFnZSwgaGUgd2FzIGtub3duIGFzIHRoZSAiVGhlIEdvZGZhdGhlciBvZiBIb25nIEtvbmcgY2luZW1hIiwgYW5kIHJpZ2h0bHkgc28gLSBhdCBsZWFzdCBpbiB0ZXJtcyBvZiBxdWFudGl0eS4gCgpMZXQncyBwdWxsIG91dCB0aGUgdG9wIDUgZGlyZWN0b3JzLCBpbiB0ZXJtcyBvZiBtb3ZpZSBjb3VudCwgYW5kIHNlZSB3aGVuIHRoZXkgd2VyZSBtb3N0IGFjdGl2ZS4gCgpgYGB7cn0KCiMgcHVsbCBvdXQganVzdCB0aGUgdG9wIDUgZGlyZWN0b3JzCnRvcF9kaXJlY3RvcnMgPC0gYnlfZGlyZWN0b3IgJT4lIGhlYWQobiA9IDUpCiMgZmlsdGVyIGZpbG1zIHRvIHRob3NlIGRpcmVjdGVkIGJ5IHRoZXNlIHRpdGFucyBvZiBLdW5nIGZ1CmZpbG1zX3RvcF9kaXJlY3RvciA8LSBmaWxtcyAlPiUgZmlsdGVyKGRpcmVjdG9yICVpbiUgdG9wX2RpcmVjdG9ycyRkaXJlY3RvcikKCiNwbG90IGJhciBjaGFydApmaWxtc190b3BfZGlyZWN0b3IgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhcikpICsKICBnZW9tX2JhcihhZXMoZmlsbCA9IGRpcmVjdG9yKSkgKwogIGxhYnModGl0bGUgPSAnU2hhdyBCcm9zIFRvcCBEaXJlY3RvciBDb3VudCBieSBZZWFyJykgKyAKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKQoKYGBgCgoKYGBge3J9CiMgVHJ5IEZpbGwgUG9zaXRpb24KZmlsbXNfdG9wX2RpcmVjdG9yICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIpKSArCiAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBkaXJlY3RvciksIHBvc2l0aW9uID0gImZpbGwiKSArCiAgbGFicyh0aXRsZSA9ICdTaGF3IEJyb3MgVG9wIERpcmVjdG9yIENvdW50IGJ5IFllYXInKSArIAogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpCmBgYAoKVGhhdCB3YXMgd2l0aCBmaWx0ZXJpbmcgdG8gX2p1c3RfIHRoZSB0b3AgZGlyZWN0b3JzLiBXaGF0IGhhcHBlbnMgd2hlbiB3ZSBwdXQgYWxsIG9mIHRoZW0gaW4/CgpgYGB7cn0KZmlsbXNfdG9wX2RpcmVjdG9yX2FsbCA8LSBmaWxtcyAlPiUgbXV0YXRlKGRpcmVjdG9yX2xhYmVsID0gaWZlbHNlKGRpcmVjdG9yICVpbiUgdG9wX2RpcmVjdG9ycyRkaXJlY3RvciwgZGlyZWN0b3IsICdPdGhlcicpKQoKZmlsbXNfdG9wX2RpcmVjdG9yX2FsbCAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyKSkgKwogIGdlb21fYmFyKGFlcyhmaWxsID0gZGlyZWN0b3JfbGFiZWwpKSArCiAgbGFicyh0aXRsZSA9ICdTaGF3IEJyb3MgRGlyZWN0b3IgQ291bnQgYnkgWWVhcicsIGZpbGwgPSAnJykgKyAKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKQoKZ2dzYXZlKCJpbWdzL3RvcF9kaXJlY3RvcnNfYnlfeWVhci5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYAoKYGBge3J9CmZpbG1zX3RvcF9kaXJlY3Rvcl9hbGwgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhcikpICsKICBnZW9tX2JhcihhZXMoZmlsbCA9IGRpcmVjdG9yX2xhYmVsKSwgcG9zaXRpb24gPSAnZmlsbCcpICsKICBsYWJzKHRpdGxlID0gJ1NoYXcgQnJvcyBEaXJlY3RvciBDb3VudCBieSBZZWFyJywgZmlsbCA9ICcnKSArIAogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkKZ2dzYXZlKCJpbWdzL3RvcF9kaXJlY3RvcnNfYnlfeWVhcl9maWxsLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNSkKYGBgCgojIyBPdGhlciBWYWx1ZXMgb3ZlciBUaW1lCgpgYGB7cn0Kc3VtbWFyeShmaWxtcykKYGBgCgoKYGBge3J9CmZpbG1fc3VtbWFyeSA8LSBmaWxtcyAlPiUgZ3JvdXBfYnkoeWVhcikgJT4lIHN1bW1hcmlzZShuID0gbigpLCBtZWFuX3RpbWUgPSBtZWFuKHRpbWUsIG5hLnJtID0gVFJVRSkpCmZpbG1fc3VtbWFyeSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gbWVhbl90aW1lKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicyh0aXRsZSA9ICdTaGF3IEJyb3MgTGVuZ3RoIGJ5IFllYXIgKGluIG1pbnMpJykgKyAKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKQojZ2dzYXZlKCJpbWdzL2ZpbG1zX2J5X3llYXIucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA1KQpgYGAKCmBgYHtyfQpmaWxtcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gdGltZSApKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGxhYnModGl0bGUgPSAnU2hhdyBCcm9zIExlbmd0aCBieSBZZWFyIChpbiBtaW5zKScpICsgCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkKCmBgYAoKYGBge3J9CmZpbG1zICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBhdmdfcmF0aW5nICkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicyh0aXRsZSA9ICdTaGF3IEJyb3MgUmF0aW5nIGJ5IFllYXInKSArIAogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpCmBgYAoKCmBgYHtyfQpmaWxtcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gd2F0Y2hlcyApKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGxhYnModGl0bGUgPSAnU2hhdyBCcm9zIFdhdGNoZXMgYnkgWWVhcicpICsgCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkKYGBgCgpgYGB7cn0KZmlsbXMgJT4lIGZpbHRlcih3YXRjaGVzID4gMjAwKSAlPiUgc2VsZWN0KHRpdGxlLCB5ZWFyLCB3YXRjaGVzKSAlPiUgYXJyYW5nZSgtd2F0Y2hlcykKYGBgCgpgYGB7cn0KZmlsbXMgICU+JQogIGdncGxvdChhZXMoeCA9IHdhdGNoZXMsIHkgPSBhdmdfcmF0aW5nKSkgKwogIGdlb21fcG9pbnQoKQoKYGBgCgoKCmBgYHtyfQpmaWxtcyAgJT4lCiAgZ2dwbG90KGFlcyh4ID0gd2F0Y2hlcywgeSA9IGxpa2VzKSkgKwogIGdlb21fcG9pbnQoKSArIAogIGxhYnModGl0bGUgPSAiV2F0Y2hlcyB2cyBMaWtlcyBvZiBLdW5nIEZ1IE1vdmllcyIpICsKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKQoKCmdnc2F2ZSgiaW1ncy93YXRjaGVzX3ZzX2xpa2VzLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNSkKYGBgCgpgYGB7cn0KZmlsbXMgICU+JQogIGdncGxvdChhZXMoeCA9IGF2Z19yYXRpbmcsIHkgPSBsaWtlcykpICsKICBnZW9tX3BvaW50KCkKCmBgYAoKCmBgYHtyfQoKZmlsbXMgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGxpa2VzICkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicyh0aXRsZSA9ICdTaGF3IEJyb3MgUmF0aW5nIGJ5IFllYXInKSArIAogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpCmBgYAoKIyMgVGl0bGUgU2hvd2Rvd24KCmBgYHtyfQpsaWJyYXJ5KHRpZHl0ZXh0KQoKIyBsb2FkIHN0b3Bfd29yZHMgaW50byBSIGVudmlyb25tZW50CmRhdGEoInN0b3Bfd29yZHMiKQpgYGAKCgpgYGB7cn0KIyBzYXZlcyBlbnRpcmUgdGl0bGUgaW4gYHRpdGxlX2FsbGAgY29sdW1uLCAKIyB0aGVuIHNwbGl0cyB1cCB0aXRsZSBjb2x1bW4gY3JlYXRpbmcgdGhlIGB3b3JkYCBjb2x1bW4gLSAKIyB3aXRoIGEgcm93IGZvciBldmVyeSB0b2tlbiAod29yZCkuCnRpdGxlcyA8LSBmaWxtcyAlPiUgbXV0YXRlKHRpdGxlX2FsbCA9IHRpdGxlKSAlPiUgdW5uZXN0X3Rva2Vucyh3b3JkLCB0aXRsZSkKYGBgCgpgYGB7cn0KIyBmaWx0ZXIgc3RvcHdvcmRzCnRpdGxlc19maWx0ZXIgPC0gdGl0bGVzICU+JSBhbnRpX2pvaW4oc3RvcF93b3JkcywgYnkgPSAid29yZCIpCmBgYAoKCmBgYHtyfQpieV93b3JkIDwtIHRpdGxlc19maWx0ZXIgJT4lIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKQpieV93b3JkICU+JQogIGZpbHRlcihuID4gMykgJT4lIAogIGdncGxvdChhZXMoeCA9IGZjdF9yZW9yZGVyKHdvcmQsIG4pLCB5ID0gbikpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKwogIGNvb3JkX2ZsaXAoKSArIAogIGxhYnModGl0bGUgPSAnVG9wIFdvcmRzIFVzZWQgaW4gS3VuZyBGdSBUaXRsZXMnKSArCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkKZ2dzYXZlKCJpbWdzL3RvcF93b3Jkc19pbl90aXRsZXMucG5nIiwgIHdpZHRoID0gOCwgaGVpZ2h0ID0gNikKYGBgCgoKYGBge3J9CnRvcF93b3JkIDwtIGJ5X3dvcmQgJT4lIGhlYWQobiA9IDEyKQpmaWxtc190b3Bfd29yZCA8LSB0aXRsZXMgJT4lIGZpbHRlcih3b3JkICVpbiUgdG9wX3dvcmQkd29yZCkKCmZpbG1zX3RvcF93b3JkICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyKSkgKwogIGdlb21fYmFyKCkgKwogIGxhYnModGl0bGUgPSAnVGl0bGVzIHdpdGggTW9zdCBDb21tb24gV29yZHMgYnkgWWVhcicpICsgCiAgZmFjZXRfd3JhcCggfiBmY3RfcmVsZXZlbCh3b3JkLCB0b3Bfd29yZCR3b3JkKSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gZnVuY3Rpb24oeCkgeyByZXR1cm4oaWZlbHNlKGFzLm51bWVyaWMoeCkgJSUgMiwgeCwgJycpKSB9KSArCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLCBsZWdlbmQucG9zaXRpb249Im5vbmUiKQpnZ3NhdmUoImltZ3MvdG9wX3dvcmRzX2J5X3RpbWUucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA2KQoKYGBgCgpTd29yZHNtYW4gb3IgU2hhb2xpbj8KCmBgYHtyfQp0b3AyX3dvcmQgPC0gYnlfd29yZCAlPiUgaGVhZChuID0gMikKZmlsbXNfdG9wMl93b3JkIDwtIHRpdGxlcyAlPiUgZmlsdGVyKHdvcmQgJWluJSB0b3AyX3dvcmQkd29yZCkKCmZpbG1zX3RvcDJfd29yZCAlPiUgCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgZmlsbCA9IGZjdF9pbm9yZGVyKHdvcmQpKSkgKwogIGdlb21fYmFyKCkgKwogIGxhYnModGl0bGUgPSAnU3dvcmRzbWFuIHZzIFNoYW9saW4gYnkgWWVhcicsIGZpbGwgPSAnJykgKyAKICAjc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSB7IHJldHVybihpZmVsc2UoYXMubnVtZXJpYyh4KSAlJSAyLCB4LCAnJykpIH0pICsKICB0aGVtZV9maXZldGhpcnR5ZWlnaHQoKSAKICAjdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKZ2dzYXZlKCJpbWdzL3NoYW9saW5fc3dvcmRzbWFuLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNSkKYGBgCgoqKlN3b3Jkc21hbiBUaXRsZXMqKgoKYGBge3J9CnRpdGxlcyAlPiUgZmlsdGVyKHdvcmQgPT0gJ3N3b3Jkc21hbicpICU+JSBhcnJhbmdlKHllYXIpICU+JSBzZWxlY3QodGl0bGVfYWxsLCB5ZWFyKQpgYGAKCnN3b3Jkc21hbiBzdWNjZXNzOiBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9PbmUtQXJtZWRfU3dvcmRzbWFuCgo+ICBJdCB3YXMgdGhlIGZpcnN0IG9mIHRoZSBuZXcgc3R5bGUgb2Ygd3V4aWEgZmlsbXMgZW1waGFzaXppbmcgbWFsZSBhbnRpLWhlcm9lcywgdmlvbGVudCBzd29yZHBsYXkgYW5kIGhlYXZ5IGJsb29kbGV0dGluZy4gSXQgd2FzIHRoZSBmaXJzdCBIb25nIEtvbmcgZmlsbSB0byBtYWtlIEhLJDEgbWlsbGlvbiBhdCB0aGUgbG9jYWwgYm94IG9mZmljZSwgcHJvcGVsbGluZyBpdHMgc3RhciBKaW1teSBXYW5nIHRvIHN1cGVyIHN0YXJkb20uCgpXdXhpYSBGaWxtcy4gCgpbMzAgRXNzZW50aWFsIFd1eGlhIEZpbG1zXShodHRwczovL3RoZWVuZG9mY2luZW1hLm5ldC8yMDE2LzAyLzExLzMwLWVzc2VudGlhbC13dXhpYS1maWxtcy8pCgo+IFRoZSBDaGluZXNlIG1hcnRpYWwgYXJ0cyBtb3ZpZSBpcyBnZW5lcmFsbHkgc3BsaXQgaW50byB0d28gcHJpbWFyeSBzdWJnZW5lcmVzOiB0aGUga3VuZyBmdSBmaWxtIGFuZCB0aGUgd3V4aWEgZmlsbS4gVGhlIGt1bmcgZnUgZmlsbSBpcyBuZXdlciBhbmQgZm9jdXNlcyBwcmltYXJpbHkgb24gaGFuZC10by1oYW5kIGNvbWJhdCwgaXTigJlzIHN0ZWVwZWQgaW4gdHJhZGl0aW9uYWwgZmlnaHRpbmcgZm9ybXMgYW5kIHRoZXJl4oCZcyBhIGdlbmVyYWwgZW1waGFzaXMgb24gdGhlIHBoeXNpY2FsIHNraWxsIG9mIHRoZSBwZXJmb3JtZXI6IHNwZWNpYWwgZWZmZWN0cyBhcmUgZ2VuZXJhbGx5IGRpc2RhaW5lZC4gQnJ1Y2UgTGVlIGFuZCBKYWNraWUgQ2hhbiBhcmUgaXRzIG1vc3QgZmFtb3VzIHByYWN0aXRpb25lcnMgYW5kIExhdSBLYXItbGV1bmcgaXRzIG1vc3QgaW1wb3J0YW50IGRpcmVjdG9yLgoKPiBXdXhpYSBpcyBhIG11Y2ggb2xkZXIgZm9ybSwgYmFzZWQgdWx0aW1hdGVseSBpbiB0aGUgbG9uZyB0cmFkaXRpb24gb2YgQ2hpbmVzZSBhZHZlbnR1cmUgbGl0ZXJhdHVyZSwgaW4gY2xhc3NpYyBub3ZlbHMgc3VjaCBhcyBUaGUgV2F0ZXIgTWFyZ2luIG9yIEpvdXJuZXkgdG8gdGhlIFdlc3QsIG9yIG1vcmUgY29udGVtcG9yYXJ5IHdvcmtzIGJ5IGF1dGhvcnMgbGlrZSBMb3VpcyBDaGEgYW5kIEd1IExvbmcuIEl0cyBoZXJvZXMgZm9sbG93IGEgdmVyeSBzcGVjaWZpYyBjb2RlIG9mIGhvbm9yIGFzIHRoZXkgbmF2aWdhdGUgdGhlIGppYW5naHUsIGFuIHVuZGVyd29ybGQgb2Ygb3V0bGF3cyBhbmQgYmFuZGl0cyBvdXRzaWRlIHRoZSBub3JtYWwgc3RyZWFtcyBvZiBjaXZpbGl6YXRpb24uCgoKRnJvbSBbV3V4aWEgV29tZW4gV2FycmlvcnNdKGh0dHA6Ly93d3cuaW5kaWV3aXJlLmNvbS8yMDE1LzEwLzgtZXh0cmFvcmRpbmFyeS13dXhpYS1maWxtcy1wb3dlcmVkLWJ5LXdhcnJpb3Itd29tZW4tNTY1MjcvKQoKPiBMZXNzIHJlYWxpc3RpYyB0aGFuIGl0cyBjb3VzaW4sIHRoZSBrdW5nIGZ1IGZpbG0sIHd1eGlhIG9mdGVuIGluY2x1ZGVzIGdyYXZpdHktZGVmeWluZyBzdHVudHMgd2hlcmUgbGVnZW5kYXJ5IHdhcnJpb3JzIGZseSB0aHJvdWdoIHRoZSBhaXIgb3IgcHVuY2ggaG9sZXMgc3RyYWlnaHQgdGhyb3VnaCB0aGVpciBlbmVtaWVz4oCZIGNoZXN0cy4KCioqU2hhb2xpbiBUaXRsZXMqKgoKYGBge3J9CnRpdGxlcyAlPiUgZmlsdGVyKHdvcmQgPT0gJ3NoYW9saW4nKSAlPiUgYXJyYW5nZSh5ZWFyKSAlPiUgc2VsZWN0KHRpdGxlX2FsbCwgeWVhcikKYGBgCgoKRnJvbSBbSGlzdG9yeSBpbiB0aGUgU2hhdyBCcm90aGVyc10oaHR0cDovL3RoZXZ1bGdhcmNpbmVtYS5jb20vMjAxNS8xMi9oaXN0b3J5LWluLXRoZS1zaGF3LWJyb3RoZXJzLykKCj4gVGhlc2UgZmlsbXMsIGZvY3VzZWQgb24gdGhlIFNoYW9saW4gVGVtcGxlIGFzIGEgY2VudGVyIGZvciBhbnRpLVFpbmcgcmVzaXN0YW5jZSwgcHJvdmlkZSBhIGRpenp5aW5nIG1ldGFwaG9yaWNhbCBwb3RlbnRpYWwsIHdpdGggdGhlIFFpbmcgdmFyaW91c2x5IHN0YW5kaW5nIGluIGZvciBXZXN0ZXJuIGltcGVyaWFsaXN0cywgdGhlIEphcGFuZXNlLCB0aGUgTmF0aW9uYWxpc3QgS3VvbWluZ3RhbmcsIHRoZSBDb21tdW5pc3RzLCBvciBldmVuIHNpbXBseSB0aGUgTWFuY2h1cmlhbnMgdGhlbXNlbHZlcywgd2hpbGUgdGhlIEJ1ZGRoaXNtIG9mIHRoZSBtb25rcyBhbGxvd3MgZm9yIGV4YW1pbmluZyBvZiB0aGUgY29udHJhZGljdGlvbnMgYXQgdGhlIGhlYXJ0IG9mIHRyYWRpdGlvbmFsIENoaW5lc2UgYmVsaWVmIHN5c3RlbXMsIGJldHdlZW4gdGhlIGltcGVyYXRpdmVzIG9mIHNvY2lhbCBqdXN0aWNlIGFuZCB3aXRoZHJhd2FsIGZyb20gd29ybGRseSBjb25jZXJucy4KCiMjIEFjdG9yIFRyb3VwZXMgYW5kIEdyb3VwcwoKRXZlbiB3aXRoIG15IG5vdmljZS1sZXZlbCBjb25zdXB0aW9uIG9mIFNoYXcgQnJvdGhlcnMgZmlsbXMsIG9uZSB0aGluZyBJIG5vdGljZWQgZWFybHkgb24gd2FzIGEgbG90IG9mIGZhbWlsaWFyIGZhY2VzIHRoYXQgc2hvd2VkIHVwIGluIG1hbnkgb2YgdGhlIG1vdmllcy4gTXkgYXNzdW1wdGlvbiBpcyBqdXN0IGxpa2UgZGlyZWN0b3JzLCB0aGVyZSBhcmUgYSBudW1iZXIgb2YgYWN0b3JzIHRoYXQgYXJlIGhlYXZpbHkgcmV1c2VkIGluIHRoZXNlIGZpbG1zLiBMZXQncyBzZWUgaWYgSSBhbSByaWdodCEKCkZpcnN0LCBqdXN0IGxpa2UgZGlyZWN0b3JzLCB3ZSBjYW4gbG9vayBhdCBjb3VudHMgYnkgYWN0b3IuIAoKYGBge3IgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDR9CmJ5X2FjdG9yIDwtIGNhc3QgJT4lIGdyb3VwX2J5KG5hbWUpICU+JSBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIGFycmFuZ2UoLW4pCgpieV9hY3RvciAlPiUgZmlsdGVyKG4gPiAyMCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3Jlb3JkZXIobmFtZSwgbiksIHkgPSBuKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gJ0NvdW50cyBvZiBTaGF3IEJyb3MgRmlsbXMgYnkgQWN0b3InKSArCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkKZ2dzYXZlKCJpbWdzL2FjdG9yX2NvdW50cy5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYpCmBgYAoKV293ISBbS3UgRmVuZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvS3VfRmVuZykgYXBwYXJlbnRseSBhcHBlYXJlZCBpbiA4MiBLdW5nIEZ1IG1vdmllcy4gVGhhdCdzIGEgbG90IG9mIEt1bmcgRnUhCgpIaXMgV2lraXBlZGlhIHBhZ2UgaXNuJ3QgYXMgaW1wcmVzc2VkIHdpdGggdGhpcyBmZWF0IGFzIEkgYW0sIHByb3ZpZGluZyBsaXR0bGUgaW5mb3JtYXRpb24gb24gdGhpcyBNYXJ0aWFsIEFydHMgTWFuaWFjLiBBcHBhcmVudGx5IGhpcyByZWFsIG5hbWUgaXMgQ2hhbiBTemUtbWFuLCBhbmQgaGlzIGZpcnN0IGZpbG0gd2FzIGluIDE5NTksIGFuZCBhcHBhcmVudGx5IGhlIGlzIHN0aWxsIGFjdGluZy4gVGhlIFtIS01EQl0oaHR0cDovL2hrbWRiLmNvbS9kYi9wZW9wbGUvdmlldy5taHRtbD9pZD0zNTc5JmRpc3BsYXlfc2V0PWVuZyksIG9yIEhvbmcgS29uZyBNb3ZpZSBEYXRhYmFzZSwgcHJvdmlkZXMganVzdCBhIGJpdCBtb3JlIGluZm86Cgo+IEluIDE5NjUsIEt1IGZvcm1hbGx5IHNpZ25lZCBhbiBhY3RpbmcgY29udHJhY3Qgd2l0aCBTaGF3IEJyb3RoZXJzIHdoZXJlIGhlIG1hZGUgYXJvdW5kIDEwMCBmaWxtcyBmb3IgdGhlbSBhbmQgYmVjYW1lIG1vc3Qgbm90YWJseSBrbm93biBhcyBvbmUgb2YgdGhlaXIgdG9wIGNoYXJhY3RlciBhY3RvcnMuIEhlIGhhcyB3b3JrZWQgd2l0aCBqdXN0IGFib3V0IGV2ZXJ5IHRvcCBIb25nIEtvbmcgZGlyZWN0b3IgaW4gYSB2YXJpZXR5IG9mIGZpbG1zLgoKT2sgdGhlbiwgd2VsbCBwcm9wcyB0byB5b3UgS3UuCgpEaWQgbW9zdCBvZiB0aGUgdG9wIGFjdG9ycycgY2FycmVlcnMgc3BhbiBtdWx0aXBsZSBkZWNhZGVzLCBvciBkaWQgYWN0b3JzIGNvbWUgYW5kIGdvIHF1aWNrbHk/IExldCdzIGdyYXBoIHRoZSB0b3AgYWN0b3IncyBtb3ZpZSBjb3VudCBieSB5ZWFyLiAKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTV9CnRvcF9hY3RvciA8LSBieV9hY3RvciAlPiUgaGVhZChuID0gMTYpCmZpbG1zX3RvcF9hY3RvciA8LSBjYXN0ICU+JSBmaWx0ZXIobmFtZSAlaW4lIHRvcF9hY3RvciRuYW1lKQoKZmlsbXNfdG9wX2FjdG9yICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyKSkgKwogIGdlb21fYmFyKCkgKwogIGxhYnModGl0bGUgPSAnVG9wIEFjdG9ycyBGaWxtIENvdW50IGJ5IFllYXInKSArIAogIGZhY2V0X3dyYXAoIH4gZmN0X3JlbGV2ZWwobmFtZSwgdG9wX2FjdG9yJG5hbWUpKSArCiAgIyBvbmx5IGxhYmVsIGhhbGYgb2YgdGhlIHllYXJzIHRvIG1ha2UgdGhpbmdzIGEgYml0IGxvb2sgY2xlYW5lcgogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gZnVuY3Rpb24oeCkgeyByZXR1cm4oaWZlbHNlKGFzLm51bWVyaWMoeCkgJSUgMiwgeCwgJycpKSB9KSArCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkgKyAKICAjIGFuZ2xlIGxhYmVsIHRleHQKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLCBsZWdlbmQucG9zaXRpb249Im5vbmUiKQpnZ3NhdmUoImltZ3MvdG9wX2FjdG9yc19ieV95ZWFyLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gMTApCmBgYAoKYGBge3J9CnllYXJfY291bnQgPC0gZmlsbXMgJT4lIHNlbGVjdCh5ZWFyKSAlPiUgdW5pcXVlKCkgJT4lIG5yb3coKQphY3Rvcl9hY3RpdmVfeWVhcnMgPC0gZmlsbXNfdG9wX2FjdG9yICU+JSBncm91cF9ieShuYW1lKSAlPiUgCiAgc3VtbWFyaXNlKGFjdGl2ZV95ZWFycyA9IGxlbmd0aCh1bmlxdWUoeWVhcikpLCAKICAgICAgICAgICAgcGVyY2VudF9hY3RpdmUgPSBhY3RpdmVfeWVhcnMgLyB5ZWFyX2NvdW50LCAKICAgICAgICAgICAgc3RhcnQgPSBtaW4oYXMubnVtZXJpYyh5ZWFyKSksIAogICAgICAgICAgICBlbmQgPSBtYXgoYXMubnVtZXJpYyh5ZWFyKSkpICU+JSAKICBhcnJhbmdlKHBlcmNlbnRfYWN0aXZlKQoKCmFjdG9yX2FjdGl2ZV95ZWFycyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZmN0X2lub3JkZXIobmFtZSksIHkgPSBwZXJjZW50X2FjdGl2ZSkpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBjb29yZF9mbGlwKCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkgKyAKICBsYWJzKHRpdGxlID0gIlBlcmNlbnQgb2YgWWVhcnMgQWN0aXZlIGJ5IEFjdG9yIikgKwogIHRoZW1lX2ZpdmV0aGlydHllaWdodCgpCmdnc2F2ZSgiaW1ncy9hY3Rvcl9wZXJjZW50X2FjdGl2ZS5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYAoKYGBge3J9CmFjdG9yX2FjdGl2ZV95ZWFycyAlPiUgZ2F0aGVyKGNhcHMsIGNhcF95ZWFyLCBzdGFydCwgZW5kKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBjYXBfeWVhciwgeSA9IGZjdF9pbm9yZGVyKG5hbWUpKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsgCiAgZ2VvbV9wYXRoKGFlcyhncm91cCA9IG5hbWUpKSArCiAgbGFicyh0aXRsZSA9ICJTaGF3IEJyb3RoZXIgQ2FyZWVyIFNwYW4gYnkgQWN0b3IiKSArCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkKZ2dzYXZlKCJpbWdzL2FjdG9yX2NhcmVlcl9zcGFuLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNSkgICAgCmBgYAoKCiMjIEZpbmRpbmcgQSBNb2Igb2YgVmVub21zIAoKW1Zlbm9tIE1vYl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVmVub21fTW9iKQoKSW5zcGlyYXRpb24gZnJvbSBbTG92ZSBBY3R1YWxseSBBbmFseXNpc10oaHR0cDovL3ZhcmlhbmNlZXhwbGFpbmVkLm9yZy9yL2xvdmUtYWN0dWFsbHktbmV0d29yay8pIGJ5IERhdmlkIFJvYmluc29uLgoKQ3JlYXRlIGEgbWF0cml4IG9mIGFjdG9yIGNvLW9jY3VyYW5jZS4KCmBgYHtyfQpzdW1tYXJ5KGJ5X2FjdG9yJG4pCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KHJlc2hhcGUyKQoKIyBmaWx0ZXIgYWN0b3JzIG5vdCBpbiBtYW55IG1vdmllcwptaW5fbW92aWVfYWN0b3JzIDwtIGJ5X2FjdG9yICU+JSBmaWx0ZXIobiA+IDUpCnBvcHVsYXJfY2FzdCA8LSBjYXN0ICU+JSBmaWx0ZXIobmFtZSAlaW4lIG1pbl9tb3ZpZV9hY3RvcnMkbmFtZSkgCgpjYXN0X21vdmllX21hdHJpeCA8LSBwb3B1bGFyX2Nhc3QgJT4lCiAgYWNhc3QobmFtZSB+IHRpdGxlLCAgZnVuLmFnZ3JlZ2F0ZSA9IGxlbmd0aCkKZGltKGNhc3RfbW92aWVfbWF0cml4KQpgYGAKClJvd3MgYXJlIGFjdG9ycy4gQ29sdW1ucyBhcmUgbW92aWVzLiAKCgpGaWx0ZXIgb3V0IG1vdmllcyB3aXRoIGZldyBjby1vY2N1cmluZyBhY3RvcnMKCmBgYHtyfQpjYXN0X21vdmllX2RmX2ZpbHRlcmVkIDwtIGNhc3RfbW92aWVfbWF0cml4ICU+JSBjb2xTdW1zKC4pCmBgYAoKCmBgYHtyfQpub3JtIDwtIGNhc3RfbW92aWVfbWF0cml4IC8gcm93U3VtcyhjYXN0X21vdmllX21hdHJpeCkKCmhjX25vcm1fY2FzdCA8LSBoY2x1c3QoZGlzdChub3JtLCBtZXRob2QgPSAibWFuaGF0dGFuIikpCgpgYGAKCgpQbG90OgoKYGBge3IsIGZpZy5oZWlnaHQ9NC44LCBmaWcud2lkdGg9My42fQpsaWJyYXJ5KGdnZGVuZHJvKQoKZ2dkZW5kcm9ncmFtKGhjX25vcm1fY2FzdCwgcm90YXRlID0gVFJVRSkKYGBgCgpTZWUgb3JkZXJpbmc6CgpgYGB7cn0Kb3JkZXJpbmcgPC1oY19ub3JtX2Nhc3QkbGFiZWxzW2hjX25vcm1fY2FzdCRvcmRlcl0Kb3JkZXJpbmcKYGBgCgoKYGBge3J9CiMgaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xMzI4MTMwMy9jcmVhdGluZy1jby1vY2N1cnJlbmNlLW1hdHJpeApjb29jY3VyIDwtIGNhc3RfbW92aWVfbWF0cml4ICUqJSB0KGNhc3RfbW92aWVfbWF0cml4KQoKZGlhZyhjb29jY3VyKSA8LSAwCgpoZWF0bWFwKGNvb2NjdXIsIHN5bW0gPSBUUlVFICkKYGBgCgpjb29jY3VyIGlzIG1hdHJpeCB3aXRoIHJvd3MgYW5kIGNvbHVtbnMgYXMgYWN0b3JzLiBUaGUgY2VsbHMgZm9yIGVhY2ggYWN0b3IgY29tYm8gaW5kaWNhdGUgdGhlIG51bWJlciBvZiBtb3ZpZXMgdGhleSBoYXZlIGFwcGVhcmVkIHRvZ2V0aGVyIGluLgoKYGBge3J9CnN1bW1hcnkocm93U3Vtcyhjb29jY3VyKSkKCnN1bW1hcnkoY29sU3Vtcyhjb29jY3VyKSkKCnN1bW1hcnkoY29sU3Vtcyhjb29jY3VyICE9IDApKQoKY29sbGFiX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKGNvbFN1bXMoY29vY2N1ciAhPSAwKSkKYGBgCgpgYGB7cn0KbGlicmFyeShpZ3JhcGgpCgpjb29jY3VyIDwtIGNhc3RfbW92aWVfbWF0cml4ICUqJSB0KGNhc3RfbW92aWVfbWF0cml4KQojY29vY2N1ciA8LSBpZmVsc2UoY29vY2N1ciA8IDQsIDAsIGNvb2NjdXIpCgpnIDwtIGdyYXBoLmFkamFjZW5jeShjb29jY3VyLCB3ZWlnaHRlZCA9IFRSVUUsIG1vZGUgPSAidW5kaXJlY3RlZCIsIGRpYWcgPSBGQUxTRSkKCnN1bW1hcnkoRShnKSR3ZWlnaHQpCgpzdW1tYXJ5KGRlZ3JlZShnKSkKCnN1bW1hcnkoc3RyZW5ndGgoZykpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD00fQpsaWJyYXJ5KGlncmFwaCkKCmNvb2NjdXIgPC0gY2FzdF9tb3ZpZV9tYXRyaXggJSolIHQoY2FzdF9tb3ZpZV9tYXRyaXgpCiNjb29jY3VyIDwtIGlmZWxzZShjb29jY3VyIDwgNCwgMCwgY29vY2N1cikKCmcgPC0gZ3JhcGguYWRqYWNlbmN5KGNvb2NjdXIsIHdlaWdodGVkID0gVFJVRSwgbW9kZSA9ICJ1bmRpcmVjdGVkIiwgZGlhZyA9IEZBTFNFKQoKbG93X2RlZ3JlZV92IDwtIFYoZylbZGVncmVlKGcpIDwgMTBdICNpZGVudGlmeSB0aG9zZSB2ZXJ0aWNlcyBwYXJ0IG9mIGxlc3MgdGhhbiB0aHJlZSBlZGdlcwpnIDwtIGRlbGV0ZV92ZXJ0aWNlcyhnLCBsb3dfZGVncmVlX3YpICNleGNsdWRlIHRoZW0gZnJvbSB0aGUgZ3JhcGgKCmxvd193ZWlnaHRfZSA8LSBFKGcpW0UoZykkd2VpZ2h0IDwgM10KZyA8LSBkZWxldGVfZWRnZXMoZywgbG93X3dlaWdodF9lKQoKbG93X3N0cmVuZ3RoX3YgPC0gVihnKVtzdHJlbmd0aChnKSA8IDkwXQpnIDwtIGRlbGV0ZV92ZXJ0aWNlcyhnLCBsb3dfc3RyZW5ndGhfdikgI2V4Y2x1ZGUgdGhlbSBmcm9tIHRoZSBncmFwaAoKVihnKSRiZXR3ZWVubmVzcyA8LSBzdHJlbmd0aChnKQoKcGxvdChnLCBlZGdlLndpZHRoID0gRShnKSR3ZWlnaHQsIAogICAgICNsYXlvdXQ9bGF5b3V0LmZydWNodGVybWFuLnJlaW5nb2xkLAogICAgIGxheW91dD1sYXlvdXRfd2l0aF9mciwKICAgICB2ZXJ0ZXgubGFiZWwuZGlzdD0wLjUsCiAgICAgI3ZlcnRleC5zaXplID0gVihnKSRiZXR3ZWVubmVzcywKICAgICB2ZXJ0ZXguc2l6ZSA9IDMsCiAgICAgdmVydGV4LmNvbG9yPSdzdGVlbGJsdWUnLAogICAgIHZlcnRleC5mcmFtZS5jb2xvcj0nd2hpdGUnLCAJCSN0aGUgY29sb3Igb2YgdGhlIGJvcmRlciBvZiB0aGUgZG90cyAKICAgICB2ZXJ0ZXgubGFiZWwuY29sb3I9J2JsYWNrJywJCSN0aGUgY29sb3Igb2YgdGhlIG5hbWUgbGFiZWxzCiAgICAgdmVydGV4LmxhYmVsLmZvbnQ9MiwJCQkjdGhlIGZvbnQgb2YgdGhlIG5hbWUgbGFiZWxzCiAgICAgdmVydGV4LmxhYmVsLmNleD0xLAkJCSNzcGVjaWZpZXMgdGhlIHNpemUgb2YgdGhlIGZvbnQgb2YgdGhlIGxhYmVscy4gY2FuIGFsc28gYmUgbWFkZSB0byB2YXJ5CiAgICAgZWRnZS5jb2xvciA9IGhzdigwLDAuMiwwLjUsYWxwaGE9MC4yKQoKKQoKYGBgCgoKYGBge3J9CmNoaWFuZ19zaGVuZyA8LSBWKGcpW1YoZykkbmFtZSA9PSAiQ2hpYW5nIFNoZW5nIl0KCmNoaWFuZ19zaGVuZ19uZWlnaGJvcnMgPC0gbmVpZ2hib3JzKGcsIGNoaWFuZ19zaGVuZykKbmVpZ2hib3JfZWRnZXMgPC0gaW5jaWRlbnRfZWRnZXMoZywgY2hpYW5nX3NoZW5nX25laWdoYm9ycykKCnN1Yl9nIDwtIG1ha2VfZW1wdHlfZ3JhcGgobiA9IGxlbmd0aChjaGlhbmdfc2hlbmdfbmVpZ2hib3JzKSwgZGlyZWN0ZWQgPSBGQUxTRSkKYWRkX3ZlcnRpY2VzKHN1Yl9nLCBjaGlhbmdfc2hlbmdfbmVpZ2hib3JzKQoKI2FkZF9lZGdlcyhzdWJfZywgbmVpZ2hib3JfZWRnZXMpCiNFKGcpW25laWdoYm9yX2VkZ2VzXSRjb2xvciA9IGhzdigwLDAuMiwwLjUsYWxwaGE9MC41KQpWKGcpJGNvbG9yID0gImdyZXkiClYoZylbY2hpYW5nX3NoZW5nXSRjb2xvciA9ICJ0b21hdG8iClYoZylbY2hpYW5nX3NoZW5nX25laWdoYm9yc10kY29sb3IgPSAndG9tYXRvJwpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD00fQpwbG90KGcsIGVkZ2Uud2lkdGggPSBFKGcpJHdlaWdodCwgCiAgICAgI2xheW91dD1sYXlvdXQuZnJ1Y2h0ZXJtYW4ucmVpbmdvbGQsCiAgICAgbGF5b3V0PWxheW91dF93aXRoX2ZyLAogICAgIHZlcnRleC5sYWJlbC5kaXN0PTAuNSwKICAgICAjdmVydGV4LnNpemUgPSBWKGcpJGJldHdlZW5uZXNzLAogICAgIHZlcnRleC5zaXplID0gNSwKICAgICB2ZXJ0ZXguY29sb3I9VihnKSRjb2xvciwKICAgICB2ZXJ0ZXguZnJhbWUuY29sb3I9J3doaXRlJywgCQkjdGhlIGNvbG9yIG9mIHRoZSBib3JkZXIgb2YgdGhlIGRvdHMgCiAgICAgdmVydGV4LmxhYmVsLmNvbG9yPSdibGFjaycsCQkjdGhlIGNvbG9yIG9mIHRoZSBuYW1lIGxhYmVscwogICAgIHZlcnRleC5sYWJlbC5mb250PTIsCQkJI3RoZSBmb250IG9mIHRoZSBuYW1lIGxhYmVscwogICAgIHZlcnRleC5sYWJlbC5jZXg9MSwJCQkjc3BlY2lmaWVzIHRoZSBzaXplIG9mIHRoZSBmb250IG9mIHRoZSBsYWJlbHMuIGNhbiBhbHNvIGJlIG1hZGUgdG8gdmFyeQogICAgIGVkZ2UuY29sb3IgPSBoc3YoMCwwLjIsMC41LGFscGhhPTAuMikKKQpgYGAKCgpgYGB7cn0KY29vY2N1cl9kZiA8LSBkYXRhLmZyYW1lKGNvb2NjdXIsIGNvbC5uYW1lcyA9IGNvbG5hbWVzKGNvb2NjdXIpKQpjb29jY3VyX2RmJG5hbWUgPC0gcm93Lm5hbWVzKGNvb2NjdXIpIApjb29jY3VyX2RmIDwtIGNvb2NjdXJfZGYgJT4lIHNlbGVjdChuYW1lLCBldmVyeXRoaW5nKCkpCiN3cml0ZV9kZWxpbShjb29jY3VyX2RmLCAnc2hhd19jb29jY3VyYW5jZS5jc3YnLCBkZWxpbSA9ICc7JykKYGBgCgoK