Data getting
wos_scopus_tos <-
tosr::tosr_load("Scopus ecohydrology sustainability 178.bib",
"WoS ecohydrology sustainability 88.txt")
[1] 2
Converting your scopus collection into a bibliographic dataframe
Done!
Generating affiliation field tag AU_UN from C1: Done!
Converting your wos collection into a bibliographic dataframe
Done!
Generating affiliation field tag AU_UN from C1: Done!
66 duplicated documents have been removed
tree_of_science <-
tosr::tosR("Scopus ecohydrology sustainability 178.bib",
"WoS ecohydrology sustainability 88.txt")
[1] 2
Converting your scopus collection into a bibliographic dataframe
Done!
Generating affiliation field tag AU_UN from C1: Done!
Converting your wos collection into a bibliographic dataframe
Done!
Generating affiliation field tag AU_UN from C1: Done!
66 duplicated documents have been removed
Computing TOS SAP
Computing TOS subfields
wos <-
bibliometrix::convert2df("WoS ecohydrology sustainability 88.txt") # create dataframe from wos file
Converting your wos collection into a bibliographic dataframe
Done!
Generating affiliation field tag AU_UN from C1: Done!
scopus <-
bibliometrix::convert2df("Scopus ecohydrology sustainability 178.bib", # Create dataframe from scopus file
dbsource = "scopus",
format = "bibtex")
Converting your scopus collection into a bibliographic dataframe
Done!
Generating affiliation field tag AU_UN from C1: Done!
Table 1. Search Criteria
table_1 <-
tibble(wos = length(wos$SR), # Create a dataframe with the values.
scopus = length(scopus$SR),
total = length(wos_scopus_tos$df$SR))
table_1
Figure 1. Languages
main_languages <-
wos_scopus_tos$df |>
select(LA) |>
separate_rows(LA, sep = "; ") |>
count(LA, sort = TRUE) |>
slice(1:5)
other_languages <-
wos_scopus_tos$df |>
separate_rows(LA, sep = "; ") |>
select(LA) |>
count(LA, sort = TRUE) |>
slice(6:n) |>
summarise(n = sum(n)) |>
mutate(LA = "OTHERS") |>
select(LA, n)
Warning in 6:n :
numerical expression has 4 elements: only the first used
languages <-
main_languages |>
bind_rows(other_languages) |>
mutate(percentage = n / sum(n),
percentage = round(percentage,
digits = 2) ) |>
rename(language = LA) |>
select(language, percentage, count = n)
languages
df <- languages |>
rename(value = percentage, group = language) |>
mutate(value = value * 100) |>
select(value, group)
df2 <- df %>%
mutate(csum = rev(cumsum(rev(value))),
pos = value/2 + lead(csum, 1),
pos = if_else(is.na(pos), value/2, pos))
ggplot(df, aes(x = 2 , y = value, fill = fct_inorder(group))) +
geom_col(width = 1, color = 1) +
coord_polar(theta = "y") +
geom_label_repel(data = df2,
aes(y = pos, label = paste0(value, "%")),
size = 4.5, nudge_x = 1, show.legend = FALSE) +
theme(panel.background = element_blank(),
axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
plot.title = element_text(hjust = 0.5, size = 18)) +
labs(title = "Languages") +
guides(fill = guide_legend(title = "")) +
theme_void() +
xlim(0.5, 2.5)

Table 2. Country production
data_biblio_wos <- biblioAnalysis(wos)
wos_country <-
data_biblio_wos$Countries |>
data.frame() |>
mutate(database = "wos") |>
select(country = Tab, papers = Freq, database ) |>
arrange(desc(papers))
data_biblio_scopus <- biblioAnalysis(scopus)
scopus_country <-
data_biblio_scopus$Countries |>
data.frame() |>
mutate(database = "scopus") |>
select(country = Tab, papers = Freq, database ) |>
arrange(desc(papers))
data_biblio_total <- biblioAnalysis(wos_scopus_tos$df)
total_country <-
data_biblio_total$Countries |>
data.frame() |>
mutate(database = "total") |>
select(country = Tab, papers = Freq, database ) |>
arrange(desc(papers))
wos_scopus_total_country <-
wos_country |>
bind_rows(scopus_country,
total_country) |>
mutate(country = as.character(country)) |>
pivot_wider(names_from = database,
values_from = papers) |>
arrange(desc(total)) |>
slice(1:10) |>
mutate(percentage = total / (table_1 |> pull(total)),
percentage = round(percentage, digits = 2))
wos_scopus_total_country
Table 3. Author production
wos_authors <-
data_biblio_wos$Authors |>
data.frame() |>
rename(authors_wos = AU, papers_wos = Freq) |>
arrange(desc(papers_wos)) |>
slice(1:10) |>
mutate(database_wos = "wos")
scopus_authors <-
data_biblio_scopus$Authors |>
data.frame() |>
rename(authors_scopus = AU, papers_scopus = Freq) |>
arrange(desc(papers_scopus)) |>
slice(1:10) |>
mutate(database_scopus = "scopus")
total_authors <-
data_biblio_total$Authors |>
data.frame() |>
rename(authors_total = AU,
papers_total = Freq) |>
arrange(desc(papers_total)) |>
slice(1:10) |>
mutate(database_total = "total")
wos_scopus_authors <-
wos_authors |>
bind_cols(scopus_authors,
total_authors)
wos_scopus_authors
Table 4. Journal production
wos_journal <-
wos |>
select(journal = SO) |>
na.omit() |>
count(journal, sort = TRUE) |>
slice(1:20) |>
rename(publications = n) |>
mutate(database = "wos")
scopus_journal <-
scopus |>
select(journal = SO) |>
na.omit() |>
count(journal, sort = TRUE) |>
slice(1:20) |>
rename(publications = n) |>
mutate(database = "scopus")
total_journal <-
wos_scopus_tos$df |>
select(journal = SO) |>
na.omit() |>
count(journal, sort = TRUE) |>
slice(1:20) |>
rename(publications = n) |>
mutate(database = "total")
wos_scopus_total_journal <-
wos_journal |>
bind_rows(scopus_journal,
total_journal) |>
pivot_wider(names_from = database,
values_from = publications) |>
arrange(desc(total)) |>
slice(1:10) |>
mutate(percentage = total / table_1 |> pull(total),
percentage = round(percentage, digits = 2))
wos_scopus_total_journal
Figure 3. Co-citation network
Author co-citation network
wos_scopus_author_metatag <-
metaTagExtraction(wos_scopus_tos$df, Field = "CR_AU")
wos_scopus_author_co_citation_matrix <-
biblioNetwork(M = wos_scopus_author_metatag,
analysis = "co-citation",
network = "authors")
aca_tbl_graph <-
graph_from_adjacency_matrix(wos_scopus_author_co_citation_matrix ,
mode = "undirected",
weighted = TRUE,
diag = FALSE) |>
as_tbl_graph(aca_igraph, directed = FALSE ) |>
activate(nodes) |>
mutate(degree = centrality_degree()) |>
arrange(desc(degree)) |>
slice(1:30)
weight_tbl <-
aca_tbl_graph |>
activate(edges) |>
select(weight) |>
as.data.frame()
threshold <-
quantile(weight_tbl |>
select(weight) |>
pull(),
probs = 0.80)
aca_tbl_graph_filtered <-
aca_tbl_graph |>
activate(edges) |>
filter(weight >= threshold) |>
activate(nodes) |>
mutate(components = group_components(type = "weak")) |>
filter(components == 1) |>
mutate(degree = centrality_degree(),
community = as.factor(group_louvain()) )
aca_tbl_graph_filtered |>
ggraph(layout = "kk") +
geom_edge_link(alpha = .25,
aes(width = weight)) +
geom_node_point(aes(colour = community,
size = degree)) +
geom_node_text(aes(label = name), repel = TRUE) +
theme_graph()

Author Collaboration network
wos_scopus_author_collab_matrix <-
biblioNetwork(M = wos_scopus_tos$df,
analysis = "collaboration",
network = "authors")
plot_author_collab <-
networkPlot(NetMatrix = wos_scopus_author_collab_matrix,
weighted=T, n = 30,
Title = "Author Collaboration Network",
type = "fruchterman",
size=T,
edgesize = 5,
labelsize=0.7)

author_collab_tbl_graph <-
graph_from_adjacency_matrix(wos_scopus_author_collab_matrix ,
mode = "undirected",
weighted = TRUE,
diag = FALSE) |>
as_tbl_graph(aca_igraph, directed = FALSE ) |>
activate(nodes) |>
mutate(degree = centrality_degree()) |>
arrange(desc(degree)) |>
slice(1:30)
author_collab_tbl_graph_filtered <-
author_collab_tbl_graph |>
activate(edges) |>
filter(weight > 1) |>
activate(nodes) |>
mutate(components = group_components(type = "weak")) |>
filter(components == 1) |>
mutate(degree = centrality_degree(),
community = as.factor(group_louvain()) )
author_collab_tbl_graph_filtered |>
ggraph(layout = "kk") +
geom_edge_link(alpha = .25,
aes(width = weight)) +
geom_node_point(aes(colour = community,
size = degree)) +
geom_node_text(aes(label = name), repel = TRUE) +
theme_graph()

Country Collaboration Network
wos_scopus_country_collab_matrix <-
biblioNetwork(M = wos_scopus_tos$df,
analysis = "collaboration",
network = "countries")
plot_country_collab <-
networkPlot(wos_scopus_country_collab_matrix,
weighted=T, n = 30,
Title = "Country Collaboration Network",
type = "fruchterman",
size=T,
edgesize = 5,
labelsize=0.7)

country_collab_tbl_graph <-
graph_from_adjacency_matrix(wos_scopus_country_collab_matrix ,
mode = "undirected",
weighted = TRUE,
diag = FALSE) |>
as_tbl_graph(aca_igraph, directed = FALSE ) |>
activate(nodes) |>
mutate(degree = centrality_degree()) |>
arrange(desc(degree)) |>
slice(1:30)
country_collab_tbl_graph_filtered <-
country_collab_tbl_graph |>
activate(nodes) |>
mutate(components = group_components(type = "weak")) |>
filter(components == 1) |>
mutate(degree = centrality_degree(),
community = as.factor(group_louvain()) )
country_collab_tbl_graph_filtered |>
ggraph(layout = "kk") +
geom_edge_link(alpha = .25,
aes(width = weight)) +
geom_node_point(aes(colour = community,
size = degree)) +
geom_node_text(aes(label = name), repel = TRUE) +
theme_graph()

Keyword co-occurrence network
wos_scopus_keyword_co_occurrence_matrix <-
biblioNetwork(M = wos_scopus_tos$df,
analysis = "co-occurrences",
network = "keywords",
sep = ";")
plot_net_co_occurrence <-
networkPlot(wos_scopus_keyword_co_occurrence_matrix,
weighted=T, n = 30,
Title = "Keyword Co-occurrence Network",
type = "fruchterman",
size=T,
edgesize = 5,
labelsize=0.7)

keyword_co_occurrence_tbl_graph <-
graph_from_adjacency_matrix(wos_scopus_keyword_co_occurrence_matrix ,
mode = "undirected",
weighted = TRUE,
diag = FALSE) |>
as_tbl_graph(aca_igraph, directed = FALSE ) |>
activate(nodes) |>
mutate(degree = centrality_degree()) |>
arrange(desc(degree)) |>
slice(1:30)
keyword_co_occurrence_weight_tbl <-
keyword_co_occurrence_tbl_graph |>
activate(edges) |>
select(weight) |>
as.data.frame()
threshold <-
quantile(keyword_co_occurrence_weight_tbl |>
select(weight) |>
pull(),
probs = 0.80)
keyword_co_occurrence_tbl_graph_filtered <-
keyword_co_occurrence_tbl_graph |>
activate(edges) |>
filter(weight >= threshold) |>
activate(nodes) |>
mutate(components = group_components(type = "weak")) |>
filter(components == 1) |>
mutate(degree = centrality_degree(),
community = as.factor(group_louvain()) )
keyword_co_occurrence_tbl_graph_filtered |>
ggraph(layout = "kk") +
geom_edge_link(alpha = .25,
aes(width = weight)) +
geom_node_point(aes(colour = community,
size = degree)) +
geom_node_text(aes(label = name), repel = TRUE) +
theme_graph()

Figure 4. Tree of Science
Tree of Science
tree_of_science
Clustering analysis
Finding the clusters
nodes <- # Create a dataframe with the fullname of articles
tibble(name = V(wos_scopus_tos$graph)$name) |>
left_join(wos_scopus_tos$nodes,
by = c("name" = "ID_TOS"))
wos_scopus_citation_network_1 <- # Add the article names to the citation network
wos_scopus_tos$graph |>
igraph::set.vertex.attribute(name = "full_name",
index = V(wos_scopus_tos$graph)$name,
value = nodes$CITE)
nodes_1 <- # Create a dataframe with subfields (clusters)
tibble(name = V(wos_scopus_citation_network_1)$name,
cluster = V(wos_scopus_citation_network_1)$subfield,
full_name = V(wos_scopus_citation_network_1)$full_name)
nodes_2 <- # Count the number of articles per cluster
nodes_1 |>
count(cluster, sort = TRUE) |>
mutate(cluster_1 = row_number()) |>
select(cluster, cluster_1)
nodes_3 <-
nodes_1 |>
left_join(nodes_2) |>
rename(subfield = cluster_1) |>
select(name, full_name, subfield)
Joining, by = "cluster"
edge_list <-
get.edgelist(wos_scopus_citation_network_1) |>
data.frame() |>
rename(Source = X1, Target = X2)
wos_scopus_citation_network <-
graph.data.frame(d = edge_list,
directed = TRUE,
vertices = nodes_3)
wos_scopus_citation_network |>
summary()
IGRAPH 8632aca DN-- 901 1932 --
+ attr: name (v/c), full_name (v/c), subfield (v/n)
Choosing clusters
We proposed the tipping point option to choose the number of clusters. See this paper:
https://www.nature.com/articles/s41598-021-85041-8
clusters <-
tibble(cluster = V(wos_scopus_citation_network)$subfield) |>
count(cluster, sort = TRUE)
clusters |>
ggplot(aes(x = reorder(cluster, n), y = n)) +
geom_point()

Removing not chosen clusters
wos_scopus_citation_network_clusters <-
wos_scopus_citation_network |>
delete.vertices(which(V(wos_scopus_citation_network)$subfield != 1 & # filter clusters
V(wos_scopus_citation_network)$subfield != 2 &
V(wos_scopus_citation_network)$subfield != 3 &
V(wos_scopus_citation_network)$subfield != 4))
wos_scopus_citation_network_clusters |>
summary()
IGRAPH e1d2ab5 DN-- 485 982 --
+ attr: name (v/c), full_name (v/c), subfield (v/n)
Cluster 1
pal <- brewer.pal(8,"Dark2")
nodes_full_data <-
tibble(name = V(wos_scopus_citation_network)$name,
cluster = V(wos_scopus_citation_network)$subfield,
full_name = V(wos_scopus_citation_network)$full_name)
cluster_1 <-
wos_scopus_citation_network |>
delete.vertices(which(V(wos_scopus_citation_network)$subfield != 1))
cluster_1_page_rank <-
cluster_1 |>
set.vertex.attribute(name = "page_rank",
value = page_rank(cluster_1)$vector)
cluster_1_df <-
tibble(name = V(cluster_1_page_rank)$name,
full_name = V(cluster_1_page_rank)$full_name,
page_rank = V(cluster_1_page_rank)$page_rank,
cluster = V(cluster_1_page_rank)$subfield,)
nodes_full_data |>
filter(cluster == 1) |>
select(full_name) |>
mutate(full_name = str_extract(full_name, SPC %R% # Regular expressions
one_or_more(WRD) %R%
SPC %R%
one_or_more(or(WRD, ANY_CHAR))),
full_name = str_remove(full_name, OPEN_PAREN %R%
repeated(DGT, 4) %R%
CLOSE_PAREN %R%
one_or_more(or(WRD,ANY_CHAR))),
full_name = str_trim(full_name)) |>
unnest_tokens(output = word, input = full_name) |> # Tokenization
anti_join(stop_words) |> # Removing stop words
filter(word != "doi",
!str_detect(word, "[0-9]")) |> # WoS data
filter(word == str_remove(word, pattern = "citation"),
word == str_remove(word, pattern = "research"), # Words removed
word == str_remove(word, pattern = "analysis"),
word == str_remove(word, pattern = "science"),
word == str_remove(word, pattern = "scientometric"),
word == str_remove(word, pattern = "vulnerability")) |>
count(word, sort = TRUE) |>
with(wordcloud(word,
n,
random.order = FALSE,
max.words = 50,
colors=pal))
Joining, by = "word"

Cluster 2
cluster_2 <-
wos_scopus_citation_network |>
delete.vertices(which(V(wos_scopus_citation_network)$subfield != 2))
cluster_2_page_rank <-
cluster_2 |>
set.vertex.attribute(name = "page_rank",
value = page_rank(cluster_2)$vector)
cluster_2_df <-
tibble(name = V(cluster_2_page_rank)$name,
full_name = V(cluster_2_page_rank)$full_name,
page_rank = V(cluster_2_page_rank)$page_rank,
cluster = V(cluster_2_page_rank)$subfield,)
nodes_full_data |>
filter(cluster == 2) |>
select(full_name) |>
mutate(full_name = str_extract(full_name, SPC %R% # Regular expressions
one_or_more(WRD) %R%
SPC %R%
one_or_more(or(WRD, ANY_CHAR))),
full_name = str_remove(full_name, OPEN_PAREN %R%
repeated(DGT, 4) %R%
CLOSE_PAREN %R%
one_or_more(or(WRD,ANY_CHAR))),
full_name = str_trim(full_name)) |>
unnest_tokens(output = word, input = full_name) |>
anti_join(stop_words) |>
filter(word != "doi",
!str_detect(word, "[0-9]")) |> # WoS data
filter(word == str_remove(word, pattern = "citation"),
word == str_remove(word, pattern = "research"),
word == str_remove(word, pattern = "analysis"),
word == str_remove(word, pattern = "science"),
word == str_remove(word, pattern = "scientometric"),
word == str_remove(word, pattern = "vulnerability")) |>
count(word, sort = TRUE) |>
with(wordcloud(word,
n,
random.order = FALSE,
max.words = 50,
colors=pal))
Joining, by = "word"

Cluster 3
cluster_3 <-
wos_scopus_citation_network |>
delete.vertices(which(V(wos_scopus_citation_network)$subfield != 3))
cluster_3_page_rank <-
cluster_3 |>
set.vertex.attribute(name = "page_rank",
value = page_rank(cluster_3)$vector)
cluster_3_df <-
tibble(name = V(cluster_3_page_rank)$name,
full_name = V(cluster_3_page_rank)$full_name,
page_rank = V(cluster_3_page_rank)$page_rank,
cluster = V(cluster_3_page_rank)$subfield,)
nodes_full_data |>
filter(cluster == 3) |>
select(full_name) |>
mutate(full_name = str_extract(full_name, SPC %R% # Regular expressions
one_or_more(WRD) %R%
SPC %R%
one_or_more(or(WRD, ANY_CHAR))),
full_name = str_remove(full_name, OPEN_PAREN %R%
repeated(DGT, 4) %R%
CLOSE_PAREN %R%
one_or_more(or(WRD,ANY_CHAR))),
full_name = str_trim(full_name)) |>
unnest_tokens(output = word, input = full_name) |>
anti_join(stop_words) |>
filter(word != "doi",
!str_detect(word, "[0-9]")) |> # WoS data
filter(word == str_remove(word, pattern = "citation"),
word == str_remove(word, pattern = "research"),
word == str_remove(word, pattern = "analysis"),
word == str_remove(word, pattern = "science"),
word == str_remove(word, pattern = "scientometric"),
word == str_remove(word, pattern = "vulnerability")) |>
count(word, sort = TRUE) |>
with(wordcloud(word,
n,
random.order = FALSE,
max.words = 50,
colors=pal))
Joining, by = "word"

Cluster 4
cluster_4 <-
wos_scopus_citation_network |>
delete.vertices(which(V(wos_scopus_citation_network)$subfield != 4))
cluster_4_page_rank <-
cluster_4 |>
set.vertex.attribute(name = "page_rank",
value = page_rank(cluster_4)$vector)
cluster_4_df <-
tibble(name = V(cluster_4_page_rank)$name,
full_name = V(cluster_4_page_rank)$full_name,
page_rank = V(cluster_4_page_rank)$page_rank,
cluster = V(cluster_4_page_rank)$subfield,)
nodes_full_data |>
filter(cluster == 4) |>
select(full_name) |>
mutate(full_name = str_extract(full_name, SPC %R% # Regular expressions
one_or_more(WRD) %R%
SPC %R%
one_or_more(or(WRD, ANY_CHAR))),
full_name = str_remove(full_name, OPEN_PAREN %R%
repeated(DGT, 4) %R%
CLOSE_PAREN %R%
one_or_more(or(WRD,ANY_CHAR))),
full_name = str_trim(full_name)) |>
unnest_tokens(output = word, input = full_name) |>
anti_join(stop_words) |>
filter(word != "doi",
!str_detect(word, "[0-9]")) |> # WoS data
filter(word == str_remove(word, pattern = "citation"),
word == str_remove(word, pattern = "research"),
word == str_remove(word, pattern = "analysis"),
word == str_remove(word, pattern = "science"),
word == str_remove(word, pattern = "scientometric"),
word == str_remove(word, pattern = "vulnerability")) |>
count(word, sort = TRUE) |>
with(wordcloud(word,
n,
random.order = FALSE,
max.words = 50,
colors=pal))
Joining, by = "word"

Exporting files
write_csv(wos_scopus_tos$df, "wos_scopus_tos.csv") # Exporting all data merged
write_csv(table_1, "table_1.csv") # Exporting table 1
write_csv(wos_scopus_total_country, "table_2_.csv") # Exporting table 2
write_csv(wos_scopus_authors, "table_3.csv") # Exporting table 3
write_csv(wos_scopus_total_journal, "table_4.csv") # Exporting table 4
write_csv(languages, "figure_1.csv") # Exporting data figure 1
write_csv(figure_2_data, "figure_2.csv") # Exporting data figure 2
write.graph(wos_scopus_citation_network, "citation_network_full.graphml", "graphml") # Exporting graph
write.graph(wos_scopus_citation_network_clusters,
"wos_scopus_citation_network_clusters.graphml",
"graphml")
aca_graphml_nodes <-
aca_tbl_graph_filtered |>
activate(nodes) |>
as_tibble() |>
rename(author = name) |>
rownames_to_column("name")
aca_graphml_edges <-
aca_tbl_graph_filtered |>
activate(edges) |>
as_tibble()
aca_graphml <-
graph_from_data_frame(d = aca_graphml_edges,
directed = FALSE,
vertices = aca_graphml_nodes)
write_graph(aca_graphml, "aca_graph.graphml", "graphml") # Export author co-citation graph
author_collab_graphml_nodes <-
author_collab_tbl_graph_filtered |>
activate(nodes) |>
as_tibble() |>
rename(author = name) |>
rownames_to_column("name")
author_collab_graphml_edges <-
author_collab_tbl_graph_filtered |>
activate(edges) |>
as_tibble()
author_collab_graphml <-
graph_from_data_frame(d = author_collab_graphml_edges,
directed = FALSE,
vertices = author_collab_graphml_nodes)
write_graph(author_collab_graphml, "author_collab_graphml.graphml", "graphml") # Export author co-citation graph
country_collab_graphml_nodes <-
country_collab_tbl_graph_filtered |>
activate(nodes) |>
as_tibble() |>
rename(author = name) |>
rownames_to_column("name")
country_collab_graphml_edges <-
country_collab_tbl_graph_filtered |>
activate(edges) |>
as_tibble()
country_collab_graphml <-
graph_from_data_frame(d = country_collab_graphml_edges,
directed = FALSE,
vertices = country_collab_graphml_nodes)
write_graph(country_collab_graphml, "country_collab_graphml.graphml", "graphml") # Export author co-citation graph
keyword_co_occurrence_graphml_nodes <-
keyword_co_occurrence_tbl_graph_filtered |>
activate(nodes) |>
as_tibble() |>
rename(author = name) |>
rownames_to_column("name")
keyword_co_occurrence_graphml_edges <-
keyword_co_occurrence_tbl_graph_filtered |>
activate(edges) |>
as_tibble()
keyword_co_occurrence_graphml <-
graph_from_data_frame(d = keyword_co_occurrence_graphml_edges,
directed = FALSE,
vertices = keyword_co_occurrence_graphml_nodes)
write_graph(keyword_co_occurrence_graphml, "keyword_co_occurrence_graphml.graphml", "graphml") # Export author co-citation graph
write.csv(tree_of_science, "tree_of_science.csv") # Exporting Tree of Science
write.csv(cluster_1_df, "cluster_1.csv") # Exporting cluster 1
write.csv(cluster_2_df, "cluster_2.csv") # Exporting cluster 2
write.csv(cluster_3_df, "cluster_3.csv") # Exporting cluster 3
write.csv(cluster_4_df, "cluster_4.csv") # Exporting cluster 4
write.csv(nodes_full_data, "nodes_full_data.csv") # Exporting all nodes
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKIyBDcmVhdGluZyB0aGUgZW52aXJvbm1lbnQKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0b3NyKQpsaWJyYXJ5KGJpYmxpb21ldHJpeCkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoaWdyYXBoKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHdvcmRjbG91ZCkKbGlicmFyeShyZWJ1cykKbGlicmFyeShnZ3JlcGVsKSAjIGltcHJvdmUgZG9udXQgdmlzdWFsaXphdGlvbgpsaWJyYXJ5KGdncmFwaCkKbGlicmFyeSh2aXNOZXR3b3JrKSAKbGlicmFyeSh0aWR5Z3JhcGgpCmBgYAoKVGhpcyB0ZW1wbGF0ZSBpcyBiYXNlZCBpbiB0aGlzIHBhcGVyCgpodHRwczovL3JldmlzdGFzLnVjbS5lcy9pbmRleC5waHAvUkVWRS9hcnRpY2xlL3ZpZXcvNzU1NjYvNDU2NDQ1NjU1NzQ2NwoKRm9yIGEgZGV0YWlsIGV4cGxhbmF0aW9uIG9mIGhvdyB0byB1c2UgaXQsIHBsZWFzZSB3YXRjaCB0aGlzIHZpZGVvIAoKaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1qdEtTaWZ2TnZUTQoKIyBEYXRhIGdldHRpbmcKCmBgYHtyfQp3b3Nfc2NvcHVzX3RvcyA8LSAKICB0b3NyOjp0b3NyX2xvYWQoIlNjb3B1cyBlY29oeWRyb2xvZ3kgc3VzdGFpbmFiaWxpdHkgMTc4LmJpYiIsCiAgICAgICAgICAgICAgICAgICJXb1MgZWNvaHlkcm9sb2d5IHN1c3RhaW5hYmlsaXR5IDg4LnR4dCIpCgp0cmVlX29mX3NjaWVuY2UgPC0gCiAgdG9zcjo6dG9zUigiU2NvcHVzIGVjb2h5ZHJvbG9neSBzdXN0YWluYWJpbGl0eSAxNzguYmliIiwKICAgICAgICAgICAgICJXb1MgZWNvaHlkcm9sb2d5IHN1c3RhaW5hYmlsaXR5IDg4LnR4dCIpCgp3b3MgPC0gCiAgYmlibGlvbWV0cml4Ojpjb252ZXJ0MmRmKCJXb1MgZWNvaHlkcm9sb2d5IHN1c3RhaW5hYmlsaXR5IDg4LnR4dCIpICAjIGNyZWF0ZSBkYXRhZnJhbWUgZnJvbSB3b3MgZmlsZQoKc2NvcHVzIDwtIAogIGJpYmxpb21ldHJpeDo6Y29udmVydDJkZigiU2NvcHVzIGVjb2h5ZHJvbG9neSBzdXN0YWluYWJpbGl0eSAxNzguYmliIiwgIyBDcmVhdGUgZGF0YWZyYW1lIGZyb20gc2NvcHVzIGZpbGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGJzb3VyY2UgPSAic2NvcHVzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdCA9ICJiaWJ0ZXgiKQpgYGAKCiMjIFRhYmxlIDEuIFNlYXJjaCBDcml0ZXJpYQoKYGBge3J9CnRhYmxlXzEgPC0gCiAgdGliYmxlKHdvcyA9IGxlbmd0aCh3b3MkU1IpLCAjIENyZWF0ZSBhIGRhdGFmcmFtZSB3aXRoIHRoZSB2YWx1ZXMuCiAgICAgICAgIHNjb3B1cyA9IGxlbmd0aChzY29wdXMkU1IpLCAKICAgICAgICAgdG90YWwgPSBsZW5ndGgod29zX3Njb3B1c190b3MkZGYkU1IpKQp0YWJsZV8xCmBgYAoKIyMgRmlndXJlIDEuIExhbmd1YWdlcwoKYGBge3J9Cm1haW5fbGFuZ3VhZ2VzIDwtIAogIHdvc19zY29wdXNfdG9zJGRmIHw+IAogIHNlbGVjdChMQSkgfD4gCiAgc2VwYXJhdGVfcm93cyhMQSwgc2VwID0gIjsgIikgfD4gCiAgY291bnQoTEEsIHNvcnQgPSBUUlVFKSB8PiAKICBzbGljZSgxOjUpCgpvdGhlcl9sYW5ndWFnZXMgPC0gCiAgd29zX3Njb3B1c190b3MkZGYgfD4gCiAgc2VwYXJhdGVfcm93cyhMQSwgc2VwID0gIjsgIikgfD4gCiAgc2VsZWN0KExBKSB8PiAKICBjb3VudChMQSwgc29ydCA9IFRSVUUpIHw+IAogIHNsaWNlKDY6bikgfD4gCiAgc3VtbWFyaXNlKG4gPSBzdW0obikpIHw+IAogIG11dGF0ZShMQSA9ICJPVEhFUlMiKSB8PiAKICBzZWxlY3QoTEEsIG4pCgpsYW5ndWFnZXMgPC0gCiAgbWFpbl9sYW5ndWFnZXMgfD4gCiAgYmluZF9yb3dzKG90aGVyX2xhbmd1YWdlcykgfD4gCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSBuIC8gc3VtKG4pLAogICAgICAgICBwZXJjZW50YWdlID0gcm91bmQocGVyY2VudGFnZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWdpdHMgPSAyKSApIHw+IAogIHJlbmFtZShsYW5ndWFnZSA9IExBKSB8PgogIHNlbGVjdChsYW5ndWFnZSwgcGVyY2VudGFnZSwgY291bnQgPSBuKQoKbGFuZ3VhZ2VzCmBgYAoKCmBgYHtyfQpkZiA8LSBsYW5ndWFnZXMgfD4gCiAgcmVuYW1lKHZhbHVlID0gcGVyY2VudGFnZSwgZ3JvdXAgPSBsYW5ndWFnZSkgfD4KICBtdXRhdGUodmFsdWUgPSB2YWx1ZSAqIDEwMCkgfD4gCiAgc2VsZWN0KHZhbHVlLCBncm91cCkKCmRmMiA8LSBkZiAlPiUgCiAgbXV0YXRlKGNzdW0gPSByZXYoY3Vtc3VtKHJldih2YWx1ZSkpKSwgCiAgICAgICAgIHBvcyA9IHZhbHVlLzIgKyBsZWFkKGNzdW0sIDEpLAogICAgICAgICBwb3MgPSBpZl9lbHNlKGlzLm5hKHBvcyksIHZhbHVlLzIsIHBvcykpCgpnZ3Bsb3QoZGYsIGFlcyh4ID0gMiAsIHkgPSB2YWx1ZSwgZmlsbCA9IGZjdF9pbm9yZGVyKGdyb3VwKSkpICsKICBnZW9tX2NvbCh3aWR0aCA9IDEsIGNvbG9yID0gMSkgKwogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArCiAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID0gZGYyLAogICAgICAgICAgICAgICAgICAgYWVzKHkgPSBwb3MsIGxhYmVsID0gcGFzdGUwKHZhbHVlLCAiJSIpKSwKICAgICAgICAgICAgICAgICAgIHNpemUgPSA0LjUsIG51ZGdlX3ggPSAxLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE4KSkgKwogIGxhYnModGl0bGUgPSAiTGFuZ3VhZ2VzIikgKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIiIpKSArCiAgdGhlbWVfdm9pZCgpICsKICB4bGltKDAuNSwgMi41KQpgYGAKCiMjIEZpZ3VyZSAyLiBTY2llbnRpZmljIFByb2R1Y3Rpb24KCmBgYHtyfQp3b3NfYW51YWxfcHJvZHVjdGlvbiA8LSAKICB3b3MgfD4gCiAgc2VsZWN0KFBZKSB8PiAKICBjb3VudChQWSwgc29ydCA9IFRSVUUpIHw+IAogIG5hLm9taXQoKSB8PiAKICBmaWx0ZXIoUFkgPj0gMjAwMCwKICAgICAgICAgUFkgPCB5ZWFyKHRvZGF5KCkpKSB8PiAKICBtdXRhdGUocmVmX3R5cGUgPSAid29zIikKCnNjb3B1c19hbnVhbF9wcm9kdWN0aW9uICA8LSAKICBzY29wdXMgfD4gCiAgc2VsZWN0KFBZKSB8PiAKICBjb3VudChQWSwgc29ydCA9IFRSVUUpIHw+IAogIG5hLm9taXQoKSB8PiAKICBmaWx0ZXIoUFkgPj0gMjAwMCwKICAgICAgICAgUFkgPCB5ZWFyKHRvZGF5KCkpKSB8PgogIG11dGF0ZShyZWZfdHlwZSA9ICJzY29wdXMiKQoKdG90YWxfYW51YWxfcHJvZHVjdGlvbiA8LSAKICB3b3Nfc2NvcHVzX3RvcyRkZiB8PiAKICBzZWxlY3QoUFkpIHw+IAogIGNvdW50KFBZLCBzb3J0ID0gVFJVRSkgfD4gCiAgbmEub21pdCgpIHw+IAogIGZpbHRlcihQWSA+PSAyMDAwLAogICAgICAgICBQWSA8IHllYXIodG9kYXkoKSkpIHw+CiAgbXV0YXRlKHJlZl90eXBlID0gInRvdGFsIikKCndvc19zY29wdXNfdG90YWxfYW5udWFsX3Byb2R1Y3Rpb24gPC0gCiAgd29zX2FudWFsX3Byb2R1Y3Rpb24gfD4gCiAgYmluZF9yb3dzKHNjb3B1c19hbnVhbF9wcm9kdWN0aW9uLAogICAgICAgICAgICB0b3RhbF9hbnVhbF9wcm9kdWN0aW9uKSAKCmZpZ3VyZV8yX2RhdGEgPC0gCiAgd29zX3Njb3B1c190b3RhbF9hbm51YWxfcHJvZHVjdGlvbiB8PiAKICBtdXRhdGUoUFkgPSByZXBsYWNlX25hKFBZLCByZXBsYWNlID0gMCkpIHw+IAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSByZWZfdHlwZSwgCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBuKSB8PiAKICBhcnJhbmdlKGRlc2MoUFkpKQoKZmlndXJlXzJfZGF0YSAKYGBgCgpgYGB7cn0Kd29zX3Njb3B1c190b3RhbF9hbm51YWxfcHJvZHVjdGlvbiB8PiAKICBnZ3Bsb3QoYWVzKHggPSBQWSwgeSA9IG4sIGNvbG9yID0gcmVmX3R5cGUpKSArCiAgZ2VvbV9saW5lKCkgKwogIGxhYnModGl0bGUgPSAiQW5udWFsIFNjaWVudGlmaWMgUHJvZHVjdGlvbiIsIAogICAgICAgeCA9ICJ5ZWFycyIsCiAgICAgICB5ID0gInBhcGVycyIpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgCmBgYAoKIyMgVGFibGUgMi4gQ291bnRyeSBwcm9kdWN0aW9uCgpgYGB7cn0KZGF0YV9iaWJsaW9fd29zIDwtIGJpYmxpb0FuYWx5c2lzKHdvcykKCndvc19jb3VudHJ5IDwtIAogIGRhdGFfYmlibGlvX3dvcyRDb3VudHJpZXMgfD4gCiAgZGF0YS5mcmFtZSgpIHw+IAogIG11dGF0ZShkYXRhYmFzZSA9ICJ3b3MiKSB8PiAKICBzZWxlY3QoY291bnRyeSA9IFRhYiwgcGFwZXJzID0gRnJlcSwgZGF0YWJhc2UgKSB8PiAKICBhcnJhbmdlKGRlc2MocGFwZXJzKSkgCgpkYXRhX2JpYmxpb19zY29wdXMgPC0gYmlibGlvQW5hbHlzaXMoc2NvcHVzKQoKc2NvcHVzX2NvdW50cnkgPC0gCiAgZGF0YV9iaWJsaW9fc2NvcHVzJENvdW50cmllcyB8PiAKICBkYXRhLmZyYW1lKCkgfD4gCiAgbXV0YXRlKGRhdGFiYXNlID0gInNjb3B1cyIpIHw+IAogIHNlbGVjdChjb3VudHJ5ID0gVGFiLCBwYXBlcnMgPSBGcmVxLCBkYXRhYmFzZSApIHw+IAogIGFycmFuZ2UoZGVzYyhwYXBlcnMpKSAKCmRhdGFfYmlibGlvX3RvdGFsIDwtIGJpYmxpb0FuYWx5c2lzKHdvc19zY29wdXNfdG9zJGRmKQoKdG90YWxfY291bnRyeSA8LSAKICBkYXRhX2JpYmxpb190b3RhbCRDb3VudHJpZXMgfD4gCiAgZGF0YS5mcmFtZSgpIHw+IAogIG11dGF0ZShkYXRhYmFzZSA9ICJ0b3RhbCIpIHw+IAogIHNlbGVjdChjb3VudHJ5ID0gVGFiLCBwYXBlcnMgPSBGcmVxLCBkYXRhYmFzZSApIHw+IAogIGFycmFuZ2UoZGVzYyhwYXBlcnMpKSAKCndvc19zY29wdXNfdG90YWxfY291bnRyeSA8LSAKICB3b3NfY291bnRyeSB8PiAKICBiaW5kX3Jvd3Moc2NvcHVzX2NvdW50cnksIAogICAgICAgICAgICB0b3RhbF9jb3VudHJ5KSB8PiAKICBtdXRhdGUoY291bnRyeSA9IGFzLmNoYXJhY3Rlcihjb3VudHJ5KSkgfD4gCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGRhdGFiYXNlLCAKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IHBhcGVycykgfD4gCiAgYXJyYW5nZShkZXNjKHRvdGFsKSkgfD4gCiAgc2xpY2UoMToxMCkgfD4gCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSB0b3RhbCAvICh0YWJsZV8xIHw+IHB1bGwodG90YWwpKSwKICAgICAgICAgcGVyY2VudGFnZSA9IHJvdW5kKHBlcmNlbnRhZ2UsIGRpZ2l0cyA9IDIpKQoKd29zX3Njb3B1c190b3RhbF9jb3VudHJ5CmBgYAoKIyMgVGFibGUgMy4gQXV0aG9yIHByb2R1Y3Rpb24KCmBgYHtyfQp3b3NfYXV0aG9ycyA8LSAKICBkYXRhX2JpYmxpb193b3MkQXV0aG9ycyB8PiAKICBkYXRhLmZyYW1lKCkgfD4gCiAgcmVuYW1lKGF1dGhvcnNfd29zID0gQVUsIHBhcGVyc193b3MgPSBGcmVxKSB8PiAKICBhcnJhbmdlKGRlc2MocGFwZXJzX3dvcykpIHw+IAogIHNsaWNlKDE6MTApIHw+IAogIG11dGF0ZShkYXRhYmFzZV93b3MgPSAid29zIikKCgpzY29wdXNfYXV0aG9ycyA8LSAKICBkYXRhX2JpYmxpb19zY29wdXMkQXV0aG9ycyB8PiAKICBkYXRhLmZyYW1lKCkgfD4gCiAgcmVuYW1lKGF1dGhvcnNfc2NvcHVzID0gQVUsIHBhcGVyc19zY29wdXMgPSBGcmVxKSB8PiAKICBhcnJhbmdlKGRlc2MocGFwZXJzX3Njb3B1cykpIHw+IAogIHNsaWNlKDE6MTApIHw+IAogIG11dGF0ZShkYXRhYmFzZV9zY29wdXMgPSAic2NvcHVzIikKCnRvdGFsX2F1dGhvcnMgPC0gCiAgZGF0YV9iaWJsaW9fdG90YWwkQXV0aG9ycyB8PiAKICBkYXRhLmZyYW1lKCkgfD4gCiAgcmVuYW1lKGF1dGhvcnNfdG90YWwgPSBBVSwgCiAgICAgICAgIHBhcGVyc190b3RhbCA9IEZyZXEpIHw+IAogIGFycmFuZ2UoZGVzYyhwYXBlcnNfdG90YWwpKSB8PiAKICBzbGljZSgxOjEwKSB8PiAKICBtdXRhdGUoZGF0YWJhc2VfdG90YWwgPSAidG90YWwiKQoKd29zX3Njb3B1c19hdXRob3JzIDwtIAogIHdvc19hdXRob3JzIHw+IAogIGJpbmRfY29scyhzY29wdXNfYXV0aG9ycywKICAgICAgICAgICAgdG90YWxfYXV0aG9ycykKCndvc19zY29wdXNfYXV0aG9ycwpgYGAKCiMjIFRhYmxlIDQuIEpvdXJuYWwgcHJvZHVjdGlvbgoKYGBge3J9Cndvc19qb3VybmFsIDwtIAogIHdvcyB8PiAKICBzZWxlY3Qoam91cm5hbCA9IFNPKSB8PiAKICBuYS5vbWl0KCkgfD4gCiAgY291bnQoam91cm5hbCwgc29ydCA9IFRSVUUpIHw+IAogIHNsaWNlKDE6MjApIHw+IAogIHJlbmFtZShwdWJsaWNhdGlvbnMgPSBuKSB8PiAKICBtdXRhdGUoZGF0YWJhc2UgPSAid29zIikKCnNjb3B1c19qb3VybmFsIDwtIAogIHNjb3B1cyB8PiAKICBzZWxlY3Qoam91cm5hbCA9IFNPKSB8PiAKICBuYS5vbWl0KCkgfD4gCiAgY291bnQoam91cm5hbCwgc29ydCA9IFRSVUUpIHw+IAogIHNsaWNlKDE6MjApIHw+IAogIHJlbmFtZShwdWJsaWNhdGlvbnMgPSBuKSB8PiAKICBtdXRhdGUoZGF0YWJhc2UgPSAic2NvcHVzIikKCnRvdGFsX2pvdXJuYWwgPC0gCiAgd29zX3Njb3B1c190b3MkZGYgfD4gCiAgc2VsZWN0KGpvdXJuYWwgPSBTTykgfD4gCiAgbmEub21pdCgpIHw+IAogIGNvdW50KGpvdXJuYWwsIHNvcnQgPSBUUlVFKSB8PiAKICBzbGljZSgxOjIwKSB8PiAKICByZW5hbWUocHVibGljYXRpb25zID0gbikgfD4gCiAgbXV0YXRlKGRhdGFiYXNlID0gInRvdGFsIikKCndvc19zY29wdXNfdG90YWxfam91cm5hbCA8LSAKICB3b3Nfam91cm5hbCB8PiAKICBiaW5kX3Jvd3Moc2NvcHVzX2pvdXJuYWwsIAogICAgICAgICAgICB0b3RhbF9qb3VybmFsKSB8PiAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gZGF0YWJhc2UsIAogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gcHVibGljYXRpb25zKSB8PiAKICBhcnJhbmdlKGRlc2ModG90YWwpKSB8PiAKICBzbGljZSgxOjEwKSB8PiAKICBtdXRhdGUocGVyY2VudGFnZSA9IHRvdGFsIC8gdGFibGVfMSB8PiBwdWxsKHRvdGFsKSwKICAgICAgICAgcGVyY2VudGFnZSA9IHJvdW5kKHBlcmNlbnRhZ2UsIGRpZ2l0cyA9IDIpKQoKCndvc19zY29wdXNfdG90YWxfam91cm5hbApgYGAKCiMjIEZpZ3VyZSAzLiBDby1jaXRhdGlvbiBuZXR3b3JrCgojIyMgQXV0aG9yIGNvLWNpdGF0aW9uIG5ldHdvcmsKCmBgYHtyfQp3b3Nfc2NvcHVzX2F1dGhvcl9tZXRhdGFnIDwtIAogIG1ldGFUYWdFeHRyYWN0aW9uKHdvc19zY29wdXNfdG9zJGRmLCBGaWVsZCA9ICJDUl9BVSIpCgp3b3Nfc2NvcHVzX2F1dGhvcl9jb19jaXRhdGlvbl9tYXRyaXggPC0gCiAgYmlibGlvTmV0d29yayhNID0gd29zX3Njb3B1c19hdXRob3JfbWV0YXRhZywgCiAgICAgICAgICAgICAgICBhbmFseXNpcyA9ICJjby1jaXRhdGlvbiIsIAogICAgICAgICAgICAgICAgbmV0d29yayA9ICJhdXRob3JzIikKCmFjYV90YmxfZ3JhcGggPC0gCiAgZ3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KHdvc19zY29wdXNfYXV0aG9yX2NvX2NpdGF0aW9uX21hdHJpeCAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlID0gInVuZGlyZWN0ZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0ZWQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlhZyA9IEZBTFNFKSB8PiAKICBhc190YmxfZ3JhcGgoYWNhX2lncmFwaCwgZGlyZWN0ZWQgPSBGQUxTRSApIHw+IAogIGFjdGl2YXRlKG5vZGVzKSB8PiAKICBtdXRhdGUoZGVncmVlID0gY2VudHJhbGl0eV9kZWdyZWUoKSkgfD4gCiAgYXJyYW5nZShkZXNjKGRlZ3JlZSkpIHw+IAogIHNsaWNlKDE6MzApCgp3ZWlnaHRfdGJsIDwtIAogIGFjYV90YmxfZ3JhcGggfD4gCiAgYWN0aXZhdGUoZWRnZXMpIHw+IAogIHNlbGVjdCh3ZWlnaHQpIHw+IAogIGFzLmRhdGEuZnJhbWUoKQoKdGhyZXNob2xkIDwtIAogIHF1YW50aWxlKHdlaWdodF90YmwgfD4gCiAgICAgICAgICAgICBzZWxlY3Qod2VpZ2h0KSB8PiAKICAgICAgICAgICAgIHB1bGwoKSwgCiAgICAgICAgICAgcHJvYnMgPSAwLjgwKQoKYWNhX3RibF9ncmFwaF9maWx0ZXJlZCA8LSAKICBhY2FfdGJsX2dyYXBoIHw+IAogIGFjdGl2YXRlKGVkZ2VzKSB8PiAKICBmaWx0ZXIod2VpZ2h0ID49IHRocmVzaG9sZCkgfD4gCiAgYWN0aXZhdGUobm9kZXMpIHw+IAogIG11dGF0ZShjb21wb25lbnRzID0gZ3JvdXBfY29tcG9uZW50cyh0eXBlID0gIndlYWsiKSkgfD4gCiAgZmlsdGVyKGNvbXBvbmVudHMgPT0gMSkgfD4gCiAgbXV0YXRlKGRlZ3JlZSA9IGNlbnRyYWxpdHlfZGVncmVlKCksCiAgICAgICAgIGNvbW11bml0eSA9IGFzLmZhY3Rvcihncm91cF9sb3V2YWluKCkpICkKCmFjYV90YmxfZ3JhcGhfZmlsdGVyZWQgfD4gCiAgZ2dyYXBoKGxheW91dCA9ICJrayIpICsgCiAgZ2VvbV9lZGdlX2xpbmsoYWxwaGEgPSAuMjUsIAogICAgICAgICAgICAgICAgIGFlcyh3aWR0aCA9IHdlaWdodCkpICsKICBnZW9tX25vZGVfcG9pbnQoYWVzKGNvbG91ciA9IGNvbW11bml0eSwgCiAgICAgICAgICAgICAgICAgICAgICBzaXplID0gZGVncmVlKSkgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCByZXBlbCA9IFRSVUUpICsKICB0aGVtZV9ncmFwaCgpCmBgYAoKIyMjIEF1dGhvciBDb2xsYWJvcmF0aW9uIG5ldHdvcmsKCmBgYHtyfQp3b3Nfc2NvcHVzX2F1dGhvcl9jb2xsYWJfbWF0cml4IDwtIAogIGJpYmxpb05ldHdvcmsoTSA9IHdvc19zY29wdXNfdG9zJGRmLCAKICAgICAgICAgICAgICAgIGFuYWx5c2lzID0gImNvbGxhYm9yYXRpb24iLCAKICAgICAgICAgICAgICAgIG5ldHdvcmsgPSAiYXV0aG9ycyIpCgpwbG90X2F1dGhvcl9jb2xsYWIgPC0gCiAgbmV0d29ya1Bsb3QoTmV0TWF0cml4ID0gd29zX3Njb3B1c19hdXRob3JfY29sbGFiX21hdHJpeCwgCiAgICAgICAgICAgICAgd2VpZ2h0ZWQ9VCwgbiA9IDMwLCAKICAgICAgICAgICAgICBUaXRsZSA9ICJBdXRob3IgQ29sbGFib3JhdGlvbiBOZXR3b3JrIiwgCiAgICAgICAgICAgICAgdHlwZSA9ICJmcnVjaHRlcm1hbiIsIAogICAgICAgICAgICAgIHNpemU9VCwKICAgICAgICAgICAgICBlZGdlc2l6ZSA9IDUsCiAgICAgICAgICAgICAgbGFiZWxzaXplPTAuNykKCmF1dGhvcl9jb2xsYWJfdGJsX2dyYXBoIDwtIAogIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeCh3b3Nfc2NvcHVzX2F1dGhvcl9jb2xsYWJfbWF0cml4ICwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGUgPSAidW5kaXJlY3RlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHRlZCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWFnID0gRkFMU0UpIHw+IAogIGFzX3RibF9ncmFwaChhY2FfaWdyYXBoLCBkaXJlY3RlZCA9IEZBTFNFICkgfD4gCiAgYWN0aXZhdGUobm9kZXMpIHw+IAogIG11dGF0ZShkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZSgpKSB8PiAKICBhcnJhbmdlKGRlc2MoZGVncmVlKSkgfD4gCiAgc2xpY2UoMTozMCkKCmF1dGhvcl9jb2xsYWJfdGJsX2dyYXBoX2ZpbHRlcmVkIDwtIAogIGF1dGhvcl9jb2xsYWJfdGJsX2dyYXBoIHw+IAogIGFjdGl2YXRlKGVkZ2VzKSB8PiAKICBmaWx0ZXIod2VpZ2h0ID4gMSkgfD4gCiAgYWN0aXZhdGUobm9kZXMpIHw+IAogIG11dGF0ZShjb21wb25lbnRzID0gZ3JvdXBfY29tcG9uZW50cyh0eXBlID0gIndlYWsiKSkgfD4KICBmaWx0ZXIoY29tcG9uZW50cyA9PSAxKSB8PgogIG11dGF0ZShkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZSgpLAogICAgICAgICBjb21tdW5pdHkgPSBhcy5mYWN0b3IoZ3JvdXBfbG91dmFpbigpKSApCgphdXRob3JfY29sbGFiX3RibF9ncmFwaF9maWx0ZXJlZCB8PiAKICBnZ3JhcGgobGF5b3V0ID0gImtrIikgKyAKICBnZW9tX2VkZ2VfbGluayhhbHBoYSA9IC4yNSwgCiAgICAgICAgICAgICAgICAgYWVzKHdpZHRoID0gd2VpZ2h0KSkgKwogIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3VyID0gY29tbXVuaXR5LCAKICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBkZWdyZWUpKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsID0gVFJVRSkgKwogIHRoZW1lX2dyYXBoKCkKYGBgCgojIyMgQ291bnRyeSBDb2xsYWJvcmF0aW9uIE5ldHdvcmsKCmBgYHtyfQp3b3Nfc2NvcHVzX2NvdW50cnlfY29sbGFiX21hdHJpeCA8LSAKICBiaWJsaW9OZXR3b3JrKE0gPSB3b3Nfc2NvcHVzX3RvcyRkZiwgCiAgICAgICAgICAgICAgICBhbmFseXNpcyA9ICJjb2xsYWJvcmF0aW9uIiwgCiAgICAgICAgICAgICAgICBuZXR3b3JrID0gImNvdW50cmllcyIpCgpwbG90X2NvdW50cnlfY29sbGFiIDwtIAogIG5ldHdvcmtQbG90KHdvc19zY29wdXNfY291bnRyeV9jb2xsYWJfbWF0cml4LCAKICAgICAgICAgICAgICB3ZWlnaHRlZD1ULCBuID0gMzAsIAogICAgICAgICAgICAgIFRpdGxlID0gIkNvdW50cnkgQ29sbGFib3JhdGlvbiBOZXR3b3JrIiwgCiAgICAgICAgICAgICAgdHlwZSA9ICJmcnVjaHRlcm1hbiIsIAogICAgICAgICAgICAgIHNpemU9VCwKICAgICAgICAgICAgICBlZGdlc2l6ZSA9IDUsCiAgICAgICAgICAgICAgbGFiZWxzaXplPTAuNykKCmNvdW50cnlfY29sbGFiX3RibF9ncmFwaCA8LSAKICBncmFwaF9mcm9tX2FkamFjZW5jeV9tYXRyaXgod29zX3Njb3B1c19jb3VudHJ5X2NvbGxhYl9tYXRyaXggLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZSA9ICJ1bmRpcmVjdGVkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlaWdodGVkID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpYWcgPSBGQUxTRSkgfD4gCiAgYXNfdGJsX2dyYXBoKGFjYV9pZ3JhcGgsIGRpcmVjdGVkID0gRkFMU0UgKSB8PiAKICBhY3RpdmF0ZShub2RlcykgfD4gCiAgbXV0YXRlKGRlZ3JlZSA9IGNlbnRyYWxpdHlfZGVncmVlKCkpIHw+IAogIGFycmFuZ2UoZGVzYyhkZWdyZWUpKSB8PiAKICBzbGljZSgxOjMwKQoKY291bnRyeV9jb2xsYWJfdGJsX2dyYXBoX2ZpbHRlcmVkIDwtIAogIGNvdW50cnlfY29sbGFiX3RibF9ncmFwaCB8PiAKICBhY3RpdmF0ZShub2RlcykgfD4gCiAgbXV0YXRlKGNvbXBvbmVudHMgPSBncm91cF9jb21wb25lbnRzKHR5cGUgPSAid2VhayIpKSB8PgogIGZpbHRlcihjb21wb25lbnRzID09IDEpIHw+CiAgbXV0YXRlKGRlZ3JlZSA9IGNlbnRyYWxpdHlfZGVncmVlKCksCiAgICAgICAgIGNvbW11bml0eSA9IGFzLmZhY3Rvcihncm91cF9sb3V2YWluKCkpICkKCmNvdW50cnlfY29sbGFiX3RibF9ncmFwaF9maWx0ZXJlZCB8PiAKICBnZ3JhcGgobGF5b3V0ID0gImtrIikgKyAKICBnZW9tX2VkZ2VfbGluayhhbHBoYSA9IC4yNSwgCiAgICAgICAgICAgICAgICAgYWVzKHdpZHRoID0gd2VpZ2h0KSkgKwogIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3VyID0gY29tbXVuaXR5LCAKICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBkZWdyZWUpKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsID0gVFJVRSkgKwogIHRoZW1lX2dyYXBoKCkKYGBgCgojIyMgS2V5d29yZCBjby1vY2N1cnJlbmNlIG5ldHdvcmsKCmBgYHtyfQp3b3Nfc2NvcHVzX2tleXdvcmRfY29fb2NjdXJyZW5jZV9tYXRyaXggPC0gCiAgYmlibGlvTmV0d29yayhNID0gd29zX3Njb3B1c190b3MkZGYsIAogICAgICAgICAgICAgICAgYW5hbHlzaXMgPSAiY28tb2NjdXJyZW5jZXMiLCAKICAgICAgICAgICAgICAgIG5ldHdvcmsgPSAia2V5d29yZHMiLCAKICAgICAgICAgICAgICAgIHNlcCA9ICI7IikKCnBsb3RfbmV0X2NvX29jY3VycmVuY2UgPC0gCiAgbmV0d29ya1Bsb3Qod29zX3Njb3B1c19rZXl3b3JkX2NvX29jY3VycmVuY2VfbWF0cml4LCAKICAgICAgICAgICAgICB3ZWlnaHRlZD1ULCBuID0gMzAsIAogICAgICAgICAgICAgIFRpdGxlID0gIktleXdvcmQgQ28tb2NjdXJyZW5jZSBOZXR3b3JrIiwgCiAgICAgICAgICAgICAgdHlwZSA9ICJmcnVjaHRlcm1hbiIsIAogICAgICAgICAgICAgIHNpemU9VCwKICAgICAgICAgICAgICBlZGdlc2l6ZSA9IDUsCiAgICAgICAgICAgICAgbGFiZWxzaXplPTAuNykKCmtleXdvcmRfY29fb2NjdXJyZW5jZV90YmxfZ3JhcGggPC0gCiAgZ3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KHdvc19zY29wdXNfa2V5d29yZF9jb19vY2N1cnJlbmNlX21hdHJpeCAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlID0gInVuZGlyZWN0ZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0ZWQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlhZyA9IEZBTFNFKSB8PiAKICBhc190YmxfZ3JhcGgoYWNhX2lncmFwaCwgZGlyZWN0ZWQgPSBGQUxTRSApIHw+IAogIGFjdGl2YXRlKG5vZGVzKSB8PiAKICBtdXRhdGUoZGVncmVlID0gY2VudHJhbGl0eV9kZWdyZWUoKSkgfD4gCiAgYXJyYW5nZShkZXNjKGRlZ3JlZSkpIHw+IAogIHNsaWNlKDE6MzApCgprZXl3b3JkX2NvX29jY3VycmVuY2Vfd2VpZ2h0X3RibCA8LSAKICBrZXl3b3JkX2NvX29jY3VycmVuY2VfdGJsX2dyYXBoIHw+IAogIGFjdGl2YXRlKGVkZ2VzKSB8PiAKICBzZWxlY3Qod2VpZ2h0KSB8PiAKICBhcy5kYXRhLmZyYW1lKCkKCnRocmVzaG9sZCA8LSAKICBxdWFudGlsZShrZXl3b3JkX2NvX29jY3VycmVuY2Vfd2VpZ2h0X3RibCB8PiAKICAgICAgICAgICAgIHNlbGVjdCh3ZWlnaHQpIHw+IAogICAgICAgICAgICAgcHVsbCgpLCAKICAgICAgICAgICBwcm9icyA9IDAuODApCgprZXl3b3JkX2NvX29jY3VycmVuY2VfdGJsX2dyYXBoX2ZpbHRlcmVkIDwtIAogIGtleXdvcmRfY29fb2NjdXJyZW5jZV90YmxfZ3JhcGggfD4gCiAgYWN0aXZhdGUoZWRnZXMpIHw+IAogIGZpbHRlcih3ZWlnaHQgPj0gdGhyZXNob2xkKSB8PiAKICBhY3RpdmF0ZShub2RlcykgfD4gCiAgbXV0YXRlKGNvbXBvbmVudHMgPSBncm91cF9jb21wb25lbnRzKHR5cGUgPSAid2VhayIpKSB8PiAKICBmaWx0ZXIoY29tcG9uZW50cyA9PSAxKSB8PiAKICBtdXRhdGUoZGVncmVlID0gY2VudHJhbGl0eV9kZWdyZWUoKSwKICAgICAgICAgY29tbXVuaXR5ID0gYXMuZmFjdG9yKGdyb3VwX2xvdXZhaW4oKSkgKQoKa2V5d29yZF9jb19vY2N1cnJlbmNlX3RibF9ncmFwaF9maWx0ZXJlZCB8PiAKICBnZ3JhcGgobGF5b3V0ID0gImtrIikgKyAKICBnZW9tX2VkZ2VfbGluayhhbHBoYSA9IC4yNSwgCiAgICAgICAgICAgICAgICAgYWVzKHdpZHRoID0gd2VpZ2h0KSkgKwogIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3VyID0gY29tbXVuaXR5LCAKICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBkZWdyZWUpKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsID0gVFJVRSkgKwogIHRoZW1lX2dyYXBoKCkKYGBgCgojIyBGaWd1cmUgNC4gVHJlZSBvZiBTY2llbmNlCgojIyMgVHJlZSBvZiBTY2llbmNlCgpgYGB7cn0KdHJlZV9vZl9zY2llbmNlCmBgYAoKIyMjIENsdXN0ZXJpbmcgYW5hbHlzaXMKCkZpbmRpbmcgdGhlIGNsdXN0ZXJzCgpgYGB7cn0Kbm9kZXMgPC0gICMgQ3JlYXRlIGEgZGF0YWZyYW1lIHdpdGggdGhlIGZ1bGxuYW1lIG9mIGFydGljbGVzIAogIHRpYmJsZShuYW1lID0gVih3b3Nfc2NvcHVzX3RvcyRncmFwaCkkbmFtZSkgfD4gCiAgbGVmdF9qb2luKHdvc19zY29wdXNfdG9zJG5vZGVzLCAKICAgICAgICAgICAgYnkgPSBjKCJuYW1lIiA9ICJJRF9UT1MiKSkKCndvc19zY29wdXNfY2l0YXRpb25fbmV0d29ya18xIDwtICMgQWRkIHRoZSBhcnRpY2xlIG5hbWVzIHRvIHRoZSBjaXRhdGlvbiBuZXR3b3JrCiAgd29zX3Njb3B1c190b3MkZ3JhcGggfD4gCiAgaWdyYXBoOjpzZXQudmVydGV4LmF0dHJpYnV0ZShuYW1lID0gImZ1bGxfbmFtZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSBWKHdvc19zY29wdXNfdG9zJGdyYXBoKSRuYW1lLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gbm9kZXMkQ0lURSkKCm5vZGVzXzEgPC0gIyBDcmVhdGUgYSBkYXRhZnJhbWUgd2l0aCBzdWJmaWVsZHMgKGNsdXN0ZXJzKQogIHRpYmJsZShuYW1lID0gVih3b3Nfc2NvcHVzX2NpdGF0aW9uX25ldHdvcmtfMSkkbmFtZSwKICAgICAgICAgY2x1c3RlciA9IFYod29zX3Njb3B1c19jaXRhdGlvbl9uZXR3b3JrXzEpJHN1YmZpZWxkLAogICAgICAgICBmdWxsX25hbWUgPSBWKHdvc19zY29wdXNfY2l0YXRpb25fbmV0d29ya18xKSRmdWxsX25hbWUpCgpub2Rlc18yIDwtICMgQ291bnQgdGhlIG51bWJlciBvZiBhcnRpY2xlcyBwZXIgY2x1c3RlcgogIG5vZGVzXzEgfD4gCiAgY291bnQoY2x1c3Rlciwgc29ydCA9IFRSVUUpIHw+IAogIG11dGF0ZShjbHVzdGVyXzEgPSByb3dfbnVtYmVyKCkpIHw+IAogIHNlbGVjdChjbHVzdGVyLCBjbHVzdGVyXzEpCgpub2Rlc18zIDwtIAogIG5vZGVzXzEgfD4gCiAgbGVmdF9qb2luKG5vZGVzXzIpIHw+IAogIHJlbmFtZShzdWJmaWVsZCA9IGNsdXN0ZXJfMSkgfD4gCiAgc2VsZWN0KG5hbWUsIGZ1bGxfbmFtZSwgc3ViZmllbGQpCgplZGdlX2xpc3QgPC0gCiAgZ2V0LmVkZ2VsaXN0KHdvc19zY29wdXNfY2l0YXRpb25fbmV0d29ya18xKSB8PiAKICBkYXRhLmZyYW1lKCkgfD4gCiAgcmVuYW1lKFNvdXJjZSA9IFgxLCBUYXJnZXQgPSBYMikKCndvc19zY29wdXNfY2l0YXRpb25fbmV0d29yayA8LSAKICBncmFwaC5kYXRhLmZyYW1lKGQgPSBlZGdlX2xpc3QsIAogICAgICAgICAgICAgICAgICAgZGlyZWN0ZWQgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgIHZlcnRpY2VzID0gbm9kZXNfMykKCndvc19zY29wdXNfY2l0YXRpb25fbmV0d29yayB8PiAKICBzdW1tYXJ5KCkKYGBgCgpDaG9vc2luZyBjbHVzdGVycwoKV2UgcHJvcG9zZWQgdGhlIHRpcHBpbmcgcG9pbnQgb3B0aW9uIHRvIGNob29zZSB0aGUgbnVtYmVyIG9mIGNsdXN0ZXJzLiBTZWUgdGhpcyBwYXBlcjoKCmh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNTk4LTAyMS04NTA0MS04CgpgYGB7cn0KY2x1c3RlcnMgPC0gCiAgdGliYmxlKGNsdXN0ZXIgPSBWKHdvc19zY29wdXNfY2l0YXRpb25fbmV0d29yaykkc3ViZmllbGQpIHw+IAogIGNvdW50KGNsdXN0ZXIsIHNvcnQgPSBUUlVFKQoKY2x1c3RlcnMgfD4gCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjbHVzdGVyLCBuKSwgeSA9IG4pKSArCiAgZ2VvbV9wb2ludCgpIApgYGAKClJlbW92aW5nIG5vdCBjaG9zZW4gY2x1c3RlcnMKCmBgYHtyfQp3b3Nfc2NvcHVzX2NpdGF0aW9uX25ldHdvcmtfY2x1c3RlcnMgPC0gCiAgd29zX3Njb3B1c19jaXRhdGlvbl9uZXR3b3JrIHw+IAogIGRlbGV0ZS52ZXJ0aWNlcyh3aGljaChWKHdvc19zY29wdXNfY2l0YXRpb25fbmV0d29yaykkc3ViZmllbGQgIT0gMSAmICMgZmlsdGVyIGNsdXN0ZXJzIAogICAgICAgICAgICAgICAgICAgICAgICAgIFYod29zX3Njb3B1c19jaXRhdGlvbl9uZXR3b3JrKSRzdWJmaWVsZCAhPSAyICYKICAgICAgICAgICAgICAgICAgICAgICAgICBWKHdvc19zY29wdXNfY2l0YXRpb25fbmV0d29yaykkc3ViZmllbGQgIT0gMyAgJgogICAgICAgICAgICAgICAgICAgICAgICAgIFYod29zX3Njb3B1c19jaXRhdGlvbl9uZXR3b3JrKSRzdWJmaWVsZCAhPSA0KSkKCndvc19zY29wdXNfY2l0YXRpb25fbmV0d29ya19jbHVzdGVycyB8PiAKICBzdW1tYXJ5KCkKYGBgCgojIyMgQ2x1c3RlciAxCgpgYGB7cn0KcGFsIDwtIGJyZXdlci5wYWwoOCwiRGFyazIiKQoKbm9kZXNfZnVsbF9kYXRhIDwtIAogIHRpYmJsZShuYW1lID0gVih3b3Nfc2NvcHVzX2NpdGF0aW9uX25ldHdvcmspJG5hbWUsCiAgICAgICAgIGNsdXN0ZXIgPSBWKHdvc19zY29wdXNfY2l0YXRpb25fbmV0d29yaykkc3ViZmllbGQsCiAgICAgICAgIGZ1bGxfbmFtZSA9IFYod29zX3Njb3B1c19jaXRhdGlvbl9uZXR3b3JrKSRmdWxsX25hbWUpCgpjbHVzdGVyXzEgPC0gCiAgd29zX3Njb3B1c19jaXRhdGlvbl9uZXR3b3JrIHw+IAogIGRlbGV0ZS52ZXJ0aWNlcyh3aGljaChWKHdvc19zY29wdXNfY2l0YXRpb25fbmV0d29yaykkc3ViZmllbGQgIT0gMSkpCgpjbHVzdGVyXzFfcGFnZV9yYW5rIDwtIAogIGNsdXN0ZXJfMSB8PiAKICBzZXQudmVydGV4LmF0dHJpYnV0ZShuYW1lID0gInBhZ2VfcmFuayIsIAogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gcGFnZV9yYW5rKGNsdXN0ZXJfMSkkdmVjdG9yKQoKY2x1c3Rlcl8xX2RmIDwtIAogIHRpYmJsZShuYW1lID0gVihjbHVzdGVyXzFfcGFnZV9yYW5rKSRuYW1lLAogICAgICAgICBmdWxsX25hbWUgPSBWKGNsdXN0ZXJfMV9wYWdlX3JhbmspJGZ1bGxfbmFtZSwKICAgICAgICAgcGFnZV9yYW5rID0gVihjbHVzdGVyXzFfcGFnZV9yYW5rKSRwYWdlX3JhbmssCiAgICAgICAgIGNsdXN0ZXIgPSBWKGNsdXN0ZXJfMV9wYWdlX3JhbmspJHN1YmZpZWxkLCkKCm5vZGVzX2Z1bGxfZGF0YSB8PiAKICBmaWx0ZXIoY2x1c3RlciA9PSAxKSB8PiAKICBzZWxlY3QoZnVsbF9uYW1lKSB8PiAKICBtdXRhdGUoZnVsbF9uYW1lID0gc3RyX2V4dHJhY3QoZnVsbF9uYW1lLCBTUEMgJVIlICAjIFJlZ3VsYXIgZXhwcmVzc2lvbnMgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25lX29yX21vcmUoV1JEKSAlUiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU1BDICVSJSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmVfb3JfbW9yZShvcihXUkQsIEFOWV9DSEFSKSkpLAogICAgICAgICBmdWxsX25hbWUgPSBzdHJfcmVtb3ZlKGZ1bGxfbmFtZSwgT1BFTl9QQVJFTiAlUiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBlYXRlZChER1QsIDQpICVSJSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENMT1NFX1BBUkVOICVSJQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25lX29yX21vcmUob3IoV1JELEFOWV9DSEFSKSkpLAogICAgICAgICBmdWxsX25hbWUgPSBzdHJfdHJpbShmdWxsX25hbWUpKSAgfD4gCiAgdW5uZXN0X3Rva2VucyhvdXRwdXQgPSB3b3JkLCBpbnB1dCA9IGZ1bGxfbmFtZSkgfD4gIyBUb2tlbml6YXRpb24KICBhbnRpX2pvaW4oc3RvcF93b3JkcykgfD4gICMgUmVtb3Zpbmcgc3RvcCB3b3JkcwogIGZpbHRlcih3b3JkICE9ICJkb2kiLAogICAgICAgICAhc3RyX2RldGVjdCh3b3JkLCAiWzAtOV0iKSkgfD4gICMgV29TIGRhdGEKICBmaWx0ZXIod29yZCA9PSBzdHJfcmVtb3ZlKHdvcmQsIHBhdHRlcm4gPSAiY2l0YXRpb24iKSwKICAgICAgICAgd29yZCA9PSBzdHJfcmVtb3ZlKHdvcmQsIHBhdHRlcm4gPSAicmVzZWFyY2giKSwgICMgV29yZHMgcmVtb3ZlZAogICAgICAgICB3b3JkID09IHN0cl9yZW1vdmUod29yZCwgcGF0dGVybiA9ICJhbmFseXNpcyIpLCAKICAgICAgICAgd29yZCA9PSBzdHJfcmVtb3ZlKHdvcmQsIHBhdHRlcm4gPSAic2NpZW5jZSIpLAogICAgICAgICB3b3JkID09IHN0cl9yZW1vdmUod29yZCwgcGF0dGVybiA9ICJzY2llbnRvbWV0cmljIiksCiAgICAgICAgIHdvcmQgPT0gc3RyX3JlbW92ZSh3b3JkLCBwYXR0ZXJuID0gInZ1bG5lcmFiaWxpdHkiKSkgfD4KICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkgfD4gCiAgd2l0aCh3b3JkY2xvdWQod29yZCwgCiAgICAgICAgICAgICAgICAgbiwgCiAgICAgICAgICAgICAgICAgcmFuZG9tLm9yZGVyID0gRkFMU0UsIAogICAgICAgICAgICAgICAgIG1heC53b3JkcyA9IDUwLCAKICAgICAgICAgICAgICAgICBjb2xvcnM9cGFsKSkKYGBgCgojIyMgQ2x1c3RlciAyCgpgYGB7cn0KY2x1c3Rlcl8yIDwtIAogIHdvc19zY29wdXNfY2l0YXRpb25fbmV0d29yayB8PiAKICBkZWxldGUudmVydGljZXMod2hpY2goVih3b3Nfc2NvcHVzX2NpdGF0aW9uX25ldHdvcmspJHN1YmZpZWxkICE9IDIpKQoKY2x1c3Rlcl8yX3BhZ2VfcmFuayA8LSAKICBjbHVzdGVyXzIgfD4gCiAgc2V0LnZlcnRleC5hdHRyaWJ1dGUobmFtZSA9ICJwYWdlX3JhbmsiLCAKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHBhZ2VfcmFuayhjbHVzdGVyXzIpJHZlY3RvcikKCmNsdXN0ZXJfMl9kZiA8LSAKICB0aWJibGUobmFtZSA9IFYoY2x1c3Rlcl8yX3BhZ2VfcmFuaykkbmFtZSwKICAgICAgICAgZnVsbF9uYW1lID0gVihjbHVzdGVyXzJfcGFnZV9yYW5rKSRmdWxsX25hbWUsCiAgICAgICAgIHBhZ2VfcmFuayA9IFYoY2x1c3Rlcl8yX3BhZ2VfcmFuaykkcGFnZV9yYW5rLAogICAgICAgICBjbHVzdGVyID0gVihjbHVzdGVyXzJfcGFnZV9yYW5rKSRzdWJmaWVsZCwpCgpub2Rlc19mdWxsX2RhdGEgfD4gCiAgZmlsdGVyKGNsdXN0ZXIgPT0gMikgfD4gCiAgc2VsZWN0KGZ1bGxfbmFtZSkgfD4gCiAgbXV0YXRlKGZ1bGxfbmFtZSA9IHN0cl9leHRyYWN0KGZ1bGxfbmFtZSwgU1BDICVSJSAgIyBSZWd1bGFyIGV4cHJlc3Npb25zIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZV9vcl9tb3JlKFdSRCkgJVIlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNQQyAlUiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25lX29yX21vcmUob3IoV1JELCBBTllfQ0hBUikpKSwKICAgICAgICAgZnVsbF9uYW1lID0gc3RyX3JlbW92ZShmdWxsX25hbWUsIE9QRU5fUEFSRU4gJVIlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwZWF0ZWQoREdULCA0KSAlUiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDTE9TRV9QQVJFTiAlUiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZV9vcl9tb3JlKG9yKFdSRCxBTllfQ0hBUikpKSwKICAgICAgICAgZnVsbF9uYW1lID0gc3RyX3RyaW0oZnVsbF9uYW1lKSkgIHw+IAogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gd29yZCwgaW5wdXQgPSBmdWxsX25hbWUpIHw+IAogIGFudGlfam9pbihzdG9wX3dvcmRzKSB8PgogIGZpbHRlcih3b3JkICE9ICJkb2kiLAogICAgICAgICAhc3RyX2RldGVjdCh3b3JkLCAiWzAtOV0iKSkgfD4gICMgV29TIGRhdGEKICBmaWx0ZXIod29yZCA9PSBzdHJfcmVtb3ZlKHdvcmQsIHBhdHRlcm4gPSAiY2l0YXRpb24iKSwKICAgICAgICAgd29yZCA9PSBzdHJfcmVtb3ZlKHdvcmQsIHBhdHRlcm4gPSAicmVzZWFyY2giKSwgCiAgICAgICAgIHdvcmQgPT0gc3RyX3JlbW92ZSh3b3JkLCBwYXR0ZXJuID0gImFuYWx5c2lzIiksIAogICAgICAgICB3b3JkID09IHN0cl9yZW1vdmUod29yZCwgcGF0dGVybiA9ICJzY2llbmNlIiksCiAgICAgICAgIHdvcmQgPT0gc3RyX3JlbW92ZSh3b3JkLCBwYXR0ZXJuID0gInNjaWVudG9tZXRyaWMiKSwKICAgICAgICAgd29yZCA9PSBzdHJfcmVtb3ZlKHdvcmQsIHBhdHRlcm4gPSAidnVsbmVyYWJpbGl0eSIpKSB8PgogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSB8PiAKICB3aXRoKHdvcmRjbG91ZCh3b3JkLCAKICAgICAgICAgICAgICAgICBuLCAKICAgICAgICAgICAgICAgICByYW5kb20ub3JkZXIgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgbWF4LndvcmRzID0gNTAsIAogICAgICAgICAgICAgICAgIGNvbG9ycz1wYWwpKQpgYGAKCiMjIyBDbHVzdGVyIDMKCmBgYHtyfQoKY2x1c3Rlcl8zIDwtIAogIHdvc19zY29wdXNfY2l0YXRpb25fbmV0d29yayB8PiAKICBkZWxldGUudmVydGljZXMod2hpY2goVih3b3Nfc2NvcHVzX2NpdGF0aW9uX25ldHdvcmspJHN1YmZpZWxkICE9IDMpKQoKY2x1c3Rlcl8zX3BhZ2VfcmFuayA8LSAKICBjbHVzdGVyXzMgfD4gCiAgc2V0LnZlcnRleC5hdHRyaWJ1dGUobmFtZSA9ICJwYWdlX3JhbmsiLCAKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHBhZ2VfcmFuayhjbHVzdGVyXzMpJHZlY3RvcikKCmNsdXN0ZXJfM19kZiA8LSAKICB0aWJibGUobmFtZSA9IFYoY2x1c3Rlcl8zX3BhZ2VfcmFuaykkbmFtZSwKICAgICAgICAgZnVsbF9uYW1lID0gVihjbHVzdGVyXzNfcGFnZV9yYW5rKSRmdWxsX25hbWUsCiAgICAgICAgIHBhZ2VfcmFuayA9IFYoY2x1c3Rlcl8zX3BhZ2VfcmFuaykkcGFnZV9yYW5rLAogICAgICAgICBjbHVzdGVyID0gVihjbHVzdGVyXzNfcGFnZV9yYW5rKSRzdWJmaWVsZCwpCgpub2Rlc19mdWxsX2RhdGEgfD4gCiAgZmlsdGVyKGNsdXN0ZXIgPT0gMykgfD4gCiAgc2VsZWN0KGZ1bGxfbmFtZSkgfD4gCiAgbXV0YXRlKGZ1bGxfbmFtZSA9IHN0cl9leHRyYWN0KGZ1bGxfbmFtZSwgU1BDICVSJSAgIyBSZWd1bGFyIGV4cHJlc3Npb25zIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZV9vcl9tb3JlKFdSRCkgJVIlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNQQyAlUiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25lX29yX21vcmUob3IoV1JELCBBTllfQ0hBUikpKSwKICAgICAgICAgZnVsbF9uYW1lID0gc3RyX3JlbW92ZShmdWxsX25hbWUsIE9QRU5fUEFSRU4gJVIlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwZWF0ZWQoREdULCA0KSAlUiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDTE9TRV9QQVJFTiAlUiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZV9vcl9tb3JlKG9yKFdSRCxBTllfQ0hBUikpKSwKICAgICAgICAgZnVsbF9uYW1lID0gc3RyX3RyaW0oZnVsbF9uYW1lKSkgIHw+IAogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gd29yZCwgaW5wdXQgPSBmdWxsX25hbWUpIHw+IAogIGFudGlfam9pbihzdG9wX3dvcmRzKSB8PgogIGZpbHRlcih3b3JkICE9ICJkb2kiLAogICAgICAgICAhc3RyX2RldGVjdCh3b3JkLCAiWzAtOV0iKSkgfD4gICMgV29TIGRhdGEgCiAgZmlsdGVyKHdvcmQgPT0gc3RyX3JlbW92ZSh3b3JkLCBwYXR0ZXJuID0gImNpdGF0aW9uIiksCiAgICAgICAgIHdvcmQgPT0gc3RyX3JlbW92ZSh3b3JkLCBwYXR0ZXJuID0gInJlc2VhcmNoIiksIAogICAgICAgICB3b3JkID09IHN0cl9yZW1vdmUod29yZCwgcGF0dGVybiA9ICJhbmFseXNpcyIpLCAKICAgICAgICAgd29yZCA9PSBzdHJfcmVtb3ZlKHdvcmQsIHBhdHRlcm4gPSAic2NpZW5jZSIpLAogICAgICAgICB3b3JkID09IHN0cl9yZW1vdmUod29yZCwgcGF0dGVybiA9ICJzY2llbnRvbWV0cmljIiksCiAgICAgICAgIHdvcmQgPT0gc3RyX3JlbW92ZSh3b3JkLCBwYXR0ZXJuID0gInZ1bG5lcmFiaWxpdHkiKSkgfD4KICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkgfD4gCiAgd2l0aCh3b3JkY2xvdWQod29yZCwgCiAgICAgICAgICAgICAgICAgbiwgCiAgICAgICAgICAgICAgICAgcmFuZG9tLm9yZGVyID0gRkFMU0UsIAogICAgICAgICAgICAgICAgIG1heC53b3JkcyA9IDUwLCAKICAgICAgICAgICAgICAgICBjb2xvcnM9cGFsKSkKYGBgCiMjIyBDbHVzdGVyIDQKCmBgYHtyfQoKY2x1c3Rlcl80IDwtIAogIHdvc19zY29wdXNfY2l0YXRpb25fbmV0d29yayB8PiAKICBkZWxldGUudmVydGljZXMod2hpY2goVih3b3Nfc2NvcHVzX2NpdGF0aW9uX25ldHdvcmspJHN1YmZpZWxkICE9IDQpKQoKY2x1c3Rlcl80X3BhZ2VfcmFuayA8LSAKICBjbHVzdGVyXzQgfD4gCiAgc2V0LnZlcnRleC5hdHRyaWJ1dGUobmFtZSA9ICJwYWdlX3JhbmsiLCAKICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IHBhZ2VfcmFuayhjbHVzdGVyXzQpJHZlY3RvcikKCmNsdXN0ZXJfNF9kZiA8LSAKICB0aWJibGUobmFtZSA9IFYoY2x1c3Rlcl80X3BhZ2VfcmFuaykkbmFtZSwKICAgICAgICAgZnVsbF9uYW1lID0gVihjbHVzdGVyXzRfcGFnZV9yYW5rKSRmdWxsX25hbWUsCiAgICAgICAgIHBhZ2VfcmFuayA9IFYoY2x1c3Rlcl80X3BhZ2VfcmFuaykkcGFnZV9yYW5rLAogICAgICAgICBjbHVzdGVyID0gVihjbHVzdGVyXzRfcGFnZV9yYW5rKSRzdWJmaWVsZCwpCgpub2Rlc19mdWxsX2RhdGEgfD4gCiAgZmlsdGVyKGNsdXN0ZXIgPT0gNCkgfD4gCiAgc2VsZWN0KGZ1bGxfbmFtZSkgfD4gCiAgbXV0YXRlKGZ1bGxfbmFtZSA9IHN0cl9leHRyYWN0KGZ1bGxfbmFtZSwgU1BDICVSJSAgIyBSZWd1bGFyIGV4cHJlc3Npb25zIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZV9vcl9tb3JlKFdSRCkgJVIlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNQQyAlUiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25lX29yX21vcmUob3IoV1JELCBBTllfQ0hBUikpKSwKICAgICAgICAgZnVsbF9uYW1lID0gc3RyX3JlbW92ZShmdWxsX25hbWUsIE9QRU5fUEFSRU4gJVIlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwZWF0ZWQoREdULCA0KSAlUiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDTE9TRV9QQVJFTiAlUiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uZV9vcl9tb3JlKG9yKFdSRCxBTllfQ0hBUikpKSwKICAgICAgICAgZnVsbF9uYW1lID0gc3RyX3RyaW0oZnVsbF9uYW1lKSkgIHw+IAogIHVubmVzdF90b2tlbnMob3V0cHV0ID0gd29yZCwgaW5wdXQgPSBmdWxsX25hbWUpIHw+IAogIGFudGlfam9pbihzdG9wX3dvcmRzKSB8PiAKICBmaWx0ZXIod29yZCAhPSAiZG9pIiwKICAgICAgICAgIXN0cl9kZXRlY3Qod29yZCwgIlswLTldIikpIHw+ICAjIFdvUyBkYXRhCiAgZmlsdGVyKHdvcmQgPT0gc3RyX3JlbW92ZSh3b3JkLCBwYXR0ZXJuID0gImNpdGF0aW9uIiksCiAgICAgICAgIHdvcmQgPT0gc3RyX3JlbW92ZSh3b3JkLCBwYXR0ZXJuID0gInJlc2VhcmNoIiksIAogICAgICAgICB3b3JkID09IHN0cl9yZW1vdmUod29yZCwgcGF0dGVybiA9ICJhbmFseXNpcyIpLCAKICAgICAgICAgd29yZCA9PSBzdHJfcmVtb3ZlKHdvcmQsIHBhdHRlcm4gPSAic2NpZW5jZSIpLAogICAgICAgICB3b3JkID09IHN0cl9yZW1vdmUod29yZCwgcGF0dGVybiA9ICJzY2llbnRvbWV0cmljIiksCiAgICAgICAgIHdvcmQgPT0gc3RyX3JlbW92ZSh3b3JkLCBwYXR0ZXJuID0gInZ1bG5lcmFiaWxpdHkiKSkgfD4KICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkgfD4gCiAgd2l0aCh3b3JkY2xvdWQod29yZCwgCiAgICAgICAgICAgICAgICAgbiwgCiAgICAgICAgICAgICAgICAgcmFuZG9tLm9yZGVyID0gRkFMU0UsIAogICAgICAgICAgICAgICAgIG1heC53b3JkcyA9IDUwLCAKICAgICAgICAgICAgICAgICBjb2xvcnM9cGFsKSkKYGBgCgojIEV4cG9ydGluZyBmaWxlcwoKYGBge3J9Cgp3cml0ZV9jc3Yod29zX3Njb3B1c190b3MkZGYsICJ3b3Nfc2NvcHVzX3Rvcy5jc3YiKSAjIEV4cG9ydGluZyBhbGwgZGF0YSBtZXJnZWQKCndyaXRlX2Nzdih0YWJsZV8xLCAidGFibGVfMS5jc3YiKSAjIEV4cG9ydGluZyB0YWJsZSAxCndyaXRlX2Nzdih3b3Nfc2NvcHVzX3RvdGFsX2NvdW50cnksICJ0YWJsZV8yXy5jc3YiKSAgIyBFeHBvcnRpbmcgdGFibGUgMgp3cml0ZV9jc3Yod29zX3Njb3B1c19hdXRob3JzLCAidGFibGVfMy5jc3YiKSAjIEV4cG9ydGluZyB0YWJsZSAzCndyaXRlX2Nzdih3b3Nfc2NvcHVzX3RvdGFsX2pvdXJuYWwsICJ0YWJsZV80LmNzdiIpICMgRXhwb3J0aW5nIHRhYmxlIDQKCgp3cml0ZV9jc3YobGFuZ3VhZ2VzLCAiZmlndXJlXzEuY3N2IikgIyBFeHBvcnRpbmcgZGF0YSBmaWd1cmUgMSAKd3JpdGVfY3N2KGZpZ3VyZV8yX2RhdGEsICJmaWd1cmVfMi5jc3YiKSAjIEV4cG9ydGluZyBkYXRhIGZpZ3VyZSAyCgp3cml0ZS5ncmFwaCh3b3Nfc2NvcHVzX2NpdGF0aW9uX25ldHdvcmssICJjaXRhdGlvbl9uZXR3b3JrX2Z1bGwuZ3JhcGhtbCIsICJncmFwaG1sIikgIyBFeHBvcnRpbmcgZ3JhcGgKd3JpdGUuZ3JhcGgod29zX3Njb3B1c19jaXRhdGlvbl9uZXR3b3JrX2NsdXN0ZXJzLCAKICAgICAgICAgICAgIndvc19zY29wdXNfY2l0YXRpb25fbmV0d29ya19jbHVzdGVycy5ncmFwaG1sIiwgCiAgICAgICAgICAgICJncmFwaG1sIikKCmFjYV9ncmFwaG1sX25vZGVzIDwtIAogIGFjYV90YmxfZ3JhcGhfZmlsdGVyZWQgfD4gCiAgYWN0aXZhdGUobm9kZXMpIHw+IAogIGFzX3RpYmJsZSgpIHw+IAogIHJlbmFtZShhdXRob3IgPSBuYW1lKSB8PiAKICByb3duYW1lc190b19jb2x1bW4oIm5hbWUiKQoKYWNhX2dyYXBobWxfZWRnZXMgPC0gCiAgYWNhX3RibF9ncmFwaF9maWx0ZXJlZCB8PiAKICBhY3RpdmF0ZShlZGdlcykgfD4gCiAgYXNfdGliYmxlKCkgCgphY2FfZ3JhcGhtbCA8LSAKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZCA9IGFjYV9ncmFwaG1sX2VkZ2VzLCAKICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0ZWQgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnRpY2VzID0gYWNhX2dyYXBobWxfbm9kZXMpCgp3cml0ZV9ncmFwaChhY2FfZ3JhcGhtbCwgImFjYV9ncmFwaC5ncmFwaG1sIiwgImdyYXBobWwiKSAjIEV4cG9ydCBhdXRob3IgY28tY2l0YXRpb24gZ3JhcGgKCmF1dGhvcl9jb2xsYWJfZ3JhcGhtbF9ub2RlcyA8LSAKICBhdXRob3JfY29sbGFiX3RibF9ncmFwaF9maWx0ZXJlZCB8PiAKICBhY3RpdmF0ZShub2RlcykgfD4gCiAgYXNfdGliYmxlKCkgfD4gCiAgcmVuYW1lKGF1dGhvciA9IG5hbWUpIHw+IAogIHJvd25hbWVzX3RvX2NvbHVtbigibmFtZSIpCgphdXRob3JfY29sbGFiX2dyYXBobWxfZWRnZXMgPC0gCiAgYXV0aG9yX2NvbGxhYl90YmxfZ3JhcGhfZmlsdGVyZWQgfD4gCiAgYWN0aXZhdGUoZWRnZXMpIHw+IAogIGFzX3RpYmJsZSgpIAoKYXV0aG9yX2NvbGxhYl9ncmFwaG1sIDwtIAogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkID0gYXV0aG9yX2NvbGxhYl9ncmFwaG1sX2VkZ2VzLCAKICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0ZWQgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgIHZlcnRpY2VzID0gYXV0aG9yX2NvbGxhYl9ncmFwaG1sX25vZGVzKQoKd3JpdGVfZ3JhcGgoYXV0aG9yX2NvbGxhYl9ncmFwaG1sLCAiYXV0aG9yX2NvbGxhYl9ncmFwaG1sLmdyYXBobWwiLCAiZ3JhcGhtbCIpICMgRXhwb3J0IGF1dGhvciBjby1jaXRhdGlvbiBncmFwaAoKY291bnRyeV9jb2xsYWJfZ3JhcGhtbF9ub2RlcyA8LSAKICBjb3VudHJ5X2NvbGxhYl90YmxfZ3JhcGhfZmlsdGVyZWQgfD4gCiAgYWN0aXZhdGUobm9kZXMpIHw+IAogIGFzX3RpYmJsZSgpIHw+IAogIHJlbmFtZShhdXRob3IgPSBuYW1lKSB8PiAKICByb3duYW1lc190b19jb2x1bW4oIm5hbWUiKQoKY291bnRyeV9jb2xsYWJfZ3JhcGhtbF9lZGdlcyA8LSAKICBjb3VudHJ5X2NvbGxhYl90YmxfZ3JhcGhfZmlsdGVyZWQgfD4gCiAgYWN0aXZhdGUoZWRnZXMpIHw+IAogIGFzX3RpYmJsZSgpIAoKY291bnRyeV9jb2xsYWJfZ3JhcGhtbCA8LSAKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoZCA9IGNvdW50cnlfY29sbGFiX2dyYXBobWxfZWRnZXMsIAogICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3RlZCA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgdmVydGljZXMgPSBjb3VudHJ5X2NvbGxhYl9ncmFwaG1sX25vZGVzKQoKd3JpdGVfZ3JhcGgoY291bnRyeV9jb2xsYWJfZ3JhcGhtbCwgImNvdW50cnlfY29sbGFiX2dyYXBobWwuZ3JhcGhtbCIsICJncmFwaG1sIikgIyBFeHBvcnQgYXV0aG9yIGNvLWNpdGF0aW9uIGdyYXBoCgprZXl3b3JkX2NvX29jY3VycmVuY2VfZ3JhcGhtbF9ub2RlcyA8LSAKICBrZXl3b3JkX2NvX29jY3VycmVuY2VfdGJsX2dyYXBoX2ZpbHRlcmVkIHw+IAogIGFjdGl2YXRlKG5vZGVzKSB8PiAKICBhc190aWJibGUoKSB8PiAKICByZW5hbWUoYXV0aG9yID0gbmFtZSkgfD4gCiAgcm93bmFtZXNfdG9fY29sdW1uKCJuYW1lIikKCmtleXdvcmRfY29fb2NjdXJyZW5jZV9ncmFwaG1sX2VkZ2VzIDwtIAogIGtleXdvcmRfY29fb2NjdXJyZW5jZV90YmxfZ3JhcGhfZmlsdGVyZWQgfD4gCiAgYWN0aXZhdGUoZWRnZXMpIHw+IAogIGFzX3RpYmJsZSgpICAKCmtleXdvcmRfY29fb2NjdXJyZW5jZV9ncmFwaG1sIDwtIAogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShkID0ga2V5d29yZF9jb19vY2N1cnJlbmNlX2dyYXBobWxfZWRnZXMsIAogICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3RlZCA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgICAgdmVydGljZXMgPSBrZXl3b3JkX2NvX29jY3VycmVuY2VfZ3JhcGhtbF9ub2RlcykKCndyaXRlX2dyYXBoKGtleXdvcmRfY29fb2NjdXJyZW5jZV9ncmFwaG1sLCAia2V5d29yZF9jb19vY2N1cnJlbmNlX2dyYXBobWwuZ3JhcGhtbCIsICJncmFwaG1sIikgIyBFeHBvcnQgYXV0aG9yIGNvLWNpdGF0aW9uIGdyYXBoCgp3cml0ZS5jc3YodHJlZV9vZl9zY2llbmNlLCAidHJlZV9vZl9zY2llbmNlLmNzdiIpICMgRXhwb3J0aW5nIFRyZWUgb2YgU2NpZW5jZQoKd3JpdGUuY3N2KGNsdXN0ZXJfMV9kZiwgImNsdXN0ZXJfMS5jc3YiKSAjIEV4cG9ydGluZyBjbHVzdGVyIDEKd3JpdGUuY3N2KGNsdXN0ZXJfMl9kZiwgImNsdXN0ZXJfMi5jc3YiKSAjIEV4cG9ydGluZyBjbHVzdGVyIDIKd3JpdGUuY3N2KGNsdXN0ZXJfM19kZiwgImNsdXN0ZXJfMy5jc3YiKSAjIEV4cG9ydGluZyBjbHVzdGVyIDMKd3JpdGUuY3N2KGNsdXN0ZXJfNF9kZiwgImNsdXN0ZXJfNC5jc3YiKSAjIEV4cG9ydGluZyBjbHVzdGVyIDQKCndyaXRlLmNzdihub2Rlc19mdWxsX2RhdGEsICJub2Rlc19mdWxsX2RhdGEuY3N2IikgIyBFeHBvcnRpbmcgYWxsIG5vZGVzCmBgYAoK