Introduction
- In this notebook, we present the first results of an analysis of
green development paths of Nordic regions
- It is based on patent data from 1990-2015 (PATSTAT, Autumn 2021
Edition)
- Analysis is done on all Nordic NUTS 2 regions (fractionalized patent
allocation by inventor location, DOCDB family level)
- Industries are captured by NACE2 codes of patents according to the
OECD IPC-NACE2 concordance table.
- Green patents are identified using the Y02 tag in the CPC
classification
Preprocessing
### general options
Sys.setenv(LANG = "en")
options("scipen" = 100, "digits" = 4) # override R's tendency to use scientific notation
### Clean workspace
rm(list=ls())
graphics.off()
### Load packages (maybe need to be installed first)
# Standard
library(tidyverse) # General DS toolkit
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ─────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.2 ──✔ ggplot2 3.4.0 ✔ purrr 1.0.1
✔ tibble 3.1.8 ✔ dplyr 1.0.10
✔ tidyr 1.2.1 ✔ stringr 1.5.0
✔ readr 2.1.3 ✔ forcats 0.5.2 ── Conflicts ────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
library(magrittr) # For advanced piping
Attaching package: ‘magrittr’
The following object is masked from ‘package:purrr’:
set_names
The following object is masked from ‘package:tidyr’:
extract
# Databases
library(DBI) # GEneral R database interface
library(RPostgres) # PostgreSQL interface driver
library(dbplyr) # for dplyr with databases
Attaching package: ‘dbplyr’
The following objects are masked from ‘package:dplyr’:
ident, sql
# networks
library(tidygraph)
Attaching package: ‘tidygraph’
The following object is masked from ‘package:stats’:
filter
library(ggraph)
library(ggrepel)
# GEoplot
library(giscoR)
library(sf)
Linking to GEOS 3.10.2, GDAL 3.4.2, PROJ 8.2.1; sf_use_s2() is TRUE
## LOAD DATA
# Regular tables
data_appln <- read_rds('../temp/data_appln.rds')
data_pers_appln <- read_rds('../temp/data_pers_appln.rds')
data_nace2 <- read_rds('../temp/data_nace2.rds')
data_docdb_fam_cpc <- read_rds('../temp/data_docdb_fam_cpc.rds')
#data_person <- read_rds('../temp/data_person.rds')
# Regional specialization
region_RTA <- read_rds('../temp/region_RTA.rds') %>%
mutate(country = nuts %>% str_sub(1,2),
nuts_period = paste(nuts, 'P', period))
region_tech <- read_rds('../temp/region_tech.rds') %>%
mutate(country = nuts %>% str_sub(1,2),
nuts_period = paste(nuts, 'P', period))
# Technology space
g_tech <- read_rds('../temp/g_tech.rds')
# Lists
list_nace2 <- read_rds('../temp/list_nace2.rds')
# Applicants
region_applt_appln <- read_rds('../temp/tbl_region_applt_appln.rds') %>% select(-applt_seq_nr, -invt_seq_nr)
region_applt <- read_rds('../temp/tbl_region_applt.rds')
## Defining parameters
n_cutoff = 50
n_cutoff_green = 25
## SELECT FOCUS REGIONS
reg_in = '' # c('SE232', 'NO043', 'DK012')
n_regions = 4
# Restrict to top N regions
select_region <- region_tech %>%
group_by(country, nuts) %>%
summarise(n = sum(weight_frac, na.rm = TRUE),
n_Y = sum(weight_frac * Y_tag, na.rm = TRUE)) %>%
ungroup() %>%
group_by(country) %>%
arrange(desc(n_Y)) %>%
mutate(index = 1:n()) %>%
ungroup() %>%
filter(index <= n_regions | nuts %in% reg_in) %>%
distinct(nuts) %>%
pull(nuts)
`summarise()` has grouped output by 'country'. You can override using the `.groups` argument.
rm(reg_in)
# Createdataframe with technology relatedness edgelist
tech_rel <- g_tech %E>%
mutate(from_nace = .N()$name[from],
to_nace = .N()$name[to]) %>%
as_tibble() %>%
mutate(from = from_nace %>% as.character(),
to = to_nace %>% as.character()) %>%
arrange(from, to) %>%
select(from, to, weight)
tech_rel %<>%
# Add opposite direction
bind_rows(tech_rel %>%
rename(from_new = to, to_new = from) %>%
rename(from = from_new, to = to_new) %>%
relocate(from, to)) %>%
# Add self loops
bind_rows(tech_rel %>%
distinct(from) %>%
mutate(to = from,
weight = 1)) %>%
distinct(from, to, .keep_all = TRUE)
# Summarize Regions
region_RTA_agg <- region_RTA %>%
group_by(country, nuts, period, nuts_period, Y_tag) %>%
summarise(n_spec = rta_bin %>% sum(na.rm = TRUE),
n_spec_count = (n_tech_region * rta_bin) %>% sum(na.rm = TRUE),
HHI = sum((n_tech_region/sum(n_tech_region) * 100)^2) ) %>%
ungroup()
`summarise()` has grouped output by 'country', 'nuts', 'period', 'nuts_period'. You can override using the `.groups` argument.
Patent application
development
- In the following, a brief descriptive analysis of the development of
green and non-green patent application in the Nordics
- In addition, a breackdown of green patents by top green patenting
reagions
# Dataframe with regions and technology fields
tech_dev <- region_RTA %>%
select(country, period, nuts, nuts_period, nace_group, Y_tag, n_tech_region, rta, rta_bin) %>%
arrange(country, nuts, nace_group, Y_tag, period) %>%
group_by(country, nuts, nace_group, Y_tag) %>%
mutate(n_tech_region_lag = lag(n_tech_region, 1),
n_tech_region_delta = n_tech_region - n_tech_region_lag,
pct_tech_region_delta = (n_tech_region - n_tech_region_lag) / ( n_tech_region_lag + 1),
rta_lag = lag(rta, 1),
rta_delta = rta - rta_lag,
rta_bin_lag = lag(rta_bin, 1),
rta_bin_delta = rta_bin - rta_bin_lag) %>%
ungroup() %>%
arrange(country, nuts, nace_group, Y_tag, period)
data_appln %>%
mutate(Y_tag = ifelse(Y_tag == TRUE, 'Green', 'Non-Green')) %>%
filter(appln_filing_year <= 2015, appln_filing_year >= 1985) %>%
count(appln_filing_year, Y_tag) %>%
ggplot(aes(x = appln_filing_year, y = n, col = Y_tag)) +
geom_line(key_glyph = "timeseries") +
labs(#title = 'Patent applications: Development',
#subtitle = 'All Nordic contries, by Y tag',
x = 'Year',
y = 'Number applications',
col = 'Green')
data_pers_appln %>%
mutate(Y_tag = ifelse(Y_tag == TRUE, 'Green', 'Non-Green')) %>%
filter(appln_filing_year <= 2015, appln_filing_year >= 1985) %>%
filter(nuts %in% select_region) %>%
count(appln_filing_year, nuts, Y_tag, wt = weight_frac) %>%
ggplot(aes(x = appln_filing_year, y = n, col = nuts)) +
geom_line(key_glyph = "timeseries") +
facet_wrap(vars(Y_tag), scales = 'free') +
labs(#title = 'Patent applications: Development',
#subtitle = 'All Nordic contries',
x = 'Year',
y = 'Number applications, by region and Y tag',
col = 'Nuts3')
Applicants
- Applicants of patents filed by inventors in the Nordics
- That can be domestic or foreign applicants
data_pers_appln %>%
mutate(Y_tag = ifelse(Y_tag == TRUE, 'Green', 'Non-Green')) %>%
filter(appln_filing_year <= 2015, appln_filing_year >= 1985) %>%
count(appln_filing_year, person_ctry_code, Y_tag, wt = weight_frac) %>%
ggplot(aes(x = appln_filing_year, y = n, col = person_ctry_code)) +
geom_line(key_glyph = "timeseries") +
facet_wrap(vars(Y_tag), scales = 'free') +
theme(legend.position = 'bottom') +
labs(#title = 'Patent applications: Development by country',
#subtitle = 'All Nordic contries',
x = 'Year',
y = 'Number applications, by region and Y tag',
col = 'Country')
ggsave("../output/paper_figs/fig_3.jpeg", dpi = 300)
Saving 7.29 x 4.51 in image
ggsave("../output/paper_figs/fig_3.eps")
Saving 7.29 x 4.51 in image
region_applt_appln %<>%
group_by(appln_id) %>%
mutate(n_frac = 1 / n()) %>%
ungroup() %>%
left_join(region_applt %>% select(person_id, han_id, han_name, person_ctry_code, nuts), by = 'person_id') %>%
left_join(data_appln %>% select(appln_id, docdb_family_id, appln_filing_year, period, Y_tag), by = 'appln_id') %>%
left_join(data_nace2 %>% select(appln_id, nace_group) %>% group_by(appln_id) %>% mutate(nace_share = 1 / n()) %>% ungroup() %>% nest(nace = c(nace_group, nace_share)), by = 'appln_id') %>%
drop_na()
# List main applicants
applt_stats <- region_applt_appln %>%
group_by(han_id, han_name) %>%
summarise(
n_pat = sum(n_frac),
n_Y = sum(n_frac * Y_tag),
first_pat = min(appln_filing_year)
) %>%
mutate(share_Y = n_Y / n_pat,
age = 2016 - first_pat,
incumbant = age >= 10 & n_pat >= 10) %>%
ungroup() %>%
arrange(desc(n_pat))
`summarise()` has grouped output by 'han_id'. You can override using the `.groups` argument.
applt_stats %>% head(200)
applt_stats %>% arrange(desc(n_Y)) %>% head(100)
Technology space
general
- We calculate the relatedness of industries by co-occurence pattern
following Hidalgo & Hausmann (2007)
- Revealed technological advantage (RTA) Is sepperatedly calculated
for Y-tag and non-Y-tag patents.
data_docdb_fam_cpc %>%
filter(Y_tag == TRUE) %>%
mutate(cpc_class_symbol = cpc_class_symbol %>% str_sub(1,4)) %>%
count(cpc_class_symbol, sort = TRUE)
set.seed(1337)
coords_tech <- g_tech %>% igraph::layout.fruchterman.reingold() %>% as_tibble()
Warning: The `x` argument of `as_tibble.matrix()` must have unique column names if `.name_repair` is omitted as of tibble 2.0.0.
Using compatibility `.name_repair`.
colnames(coords_tech) <- c("x", "y")
Regional specialization
(RTA) development
- Comparison of specialization provides in period 1 and 2
g_tech %N>%
mutate(nace_group_name = nace_group_name %>% str_trunc(50, side = 'right')) %>%
ggraph(layout = coords_tech) +
geom_edge_link(aes(width = weight, alpha = weight), colour = "grey") +
geom_node_point(aes(colour = nace_sec_name, size = dgr)) +
geom_node_text(aes(label = nace_group_name, size = dgr, filter = percent_rank(dgr) >= 0.75 ), repel = TRUE) +
theme_void() +
theme(legend.position = 'bottom',
legend.box = "vertical") +
labs(#title = 'Industry Space (all Nordics)',
#subtitle = 'Nodes = NACE 2 Industries. Edges: Relatedness'
)
ggsave("../output/paper_figs/fig_9.jpeg", dpi = 300)
Saving 10 x 10 in image
ggsave("../output/paper_figs/fig_9.eps")
Saving 10 x 10 in image
p1 <- region_RTA_agg %>%
filter(nuts %in% select_region) %>%
pivot_wider(names_from = Y_tag, values_from = c(n_spec, n_spec_count, HHI), values_fill = 0, names_prefix = 'Y_tag_')
p2 <- p1 %>%
select(period, nuts, n_spec_Y_tag_FALSE, n_spec_Y_tag_TRUE) %>%
pivot_wider(names_from = period, values_from = c(n_spec_Y_tag_FALSE, n_spec_Y_tag_TRUE))
Analysis for existing
green paths:
NOTE: new patentds in specializations?
p1 %>%
ggplot(aes(x = n_spec_Y_tag_FALSE, y = n_spec_Y_tag_TRUE)) +
geom_segment(data = p2,
aes(x = n_spec_Y_tag_FALSE_1,
y = n_spec_Y_tag_TRUE_1,
xend = n_spec_Y_tag_FALSE_2,
yend = n_spec_Y_tag_TRUE_2,
size = 0.75),
alpha = 0.15,
arrow = arrow(length = unit(0.5, "cm"), type = "closed"),
show.legend = FALSE) +
geom_point(aes(size = n_spec_count_Y_tag_TRUE, col = HHI_Y_tag_TRUE)) +
geom_text_repel(aes(label = nuts), box.padding = 0.5, max.overlaps = Inf) +
scale_color_gradient2(low = "skyblue", mid = 'yellow', high = "red", midpoint = 1) +
scale_size(range = c(2, 10)) +
theme(legend.position = 'bottom') +
labs(#title = 'Development of new regional specializations',
#subtitle = 'By number of green and non green specializations in period 1 and 2',
x = 'N non-green specializations',
y = 'N green specializations',
size = 'N green patents',
col = 'HHI green patents')
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.
ggsave("../output/paper_figs/fig_4.jpeg", dpi = 300)
Saving 7.5 x 7.5 in image
ggsave("../output/paper_figs/fig_4.eps")
Saving 7.5 x 7.5 in image
rm(p1, p2)
tech_rel_dev <- tech_rel %>%
select(from, to, weight) %>%
left_join(tech_dev %>% distinct(nace_group, nuts), by = c('from' = 'nace_group')) %>%
# filter for rta in period 1
inner_join(tech_dev %>% filter(period == '1', rta_bin == 1) %>% select(nace_group, nuts, Y_tag), by = c('to' = 'nace_group', 'nuts')) %>%
# filter for new green specialization in period 2
semi_join(tech_dev %>% filter(period == '2', rta_bin == 1, rta_bin_delta == 1, Y_tag == TRUE), by = c('from' = 'nace_group', 'nuts')) %>%
rename(nace_group = from, related_techn = to)
p1 <- tech_rel_dev %>%
group_by(nuts, nace_group, Y_tag) %>%
summarise(rel_max = weight %>% max(),
rel_sum = weight %>% sum(),
rel_mean = weight %>% mean()) %>%
ungroup() %>%
#
group_by(nuts, Y_tag) %>%
summarise(rel = rel_max %>% mean()) %>%
ungroup() %>%
#
pivot_wider(names_from = Y_tag, values_from = rel, names_prefix = 'Y_', values_fill = 0) %>%
left_join(tech_dev %>% filter(Y_tag == TRUE, period == '2', rta_bin_delta == 1) %>% select(nuts , n_tech_region) %>% count(nuts, wt = n_tech_region), by = c('nuts')) %>%
mutate(country = nuts %>% str_sub(1,2))
`summarise()` has grouped output by 'nuts', 'nace_group'. You can override using the `.groups` argument.`summarise()` has grouped output by 'nuts'. You can override using the `.groups` argument.
x_mid <- mean(p1$Y_FALSE, na.rm = TRUE)
y_mid <- mean(p1$Y_TRUE, na.rm = TRUE)
p1 %>%
filter(0.5 <= percent_rank(n)) %>%
ggplot(aes(x = Y_FALSE, y = Y_TRUE, size = n)) +
geom_vline(xintercept = x_mid, linetype = "dashed", color = 'grey') +
geom_hline(yintercept = y_mid, linetype = "dashed", color = 'grey') +
geom_point(aes(col = country)) +
geom_text_repel(aes(label = nuts), box.padding = 0.5, max.overlaps = Inf) +
theme(legend.position="bottom") +
labs(#title = 'New green specialization period 2',
#subtitle = 'By nuts regions',
#note = 'Relatedness is the mean over all new green specializations, per green specialization largest relatedness to former specialization counted',
x = 'Relatedness non-green',
y = 'Relatedness green',
size = 'N green patents')
ggsave("../output/paper_figs/fig_5.jpeg", dpi = 300)
Saving 7.5 x 7.5 in image
ggsave("../output/paper_figs/fig_5.eps")
Saving 7.5 x 7.5 in image
rm(p1, x_mid, y_mid)
library(regions)
data(nuts_changes)
list_nuts <- nuts_changes %>% select(code_2021, geo_name_2021)
colnames(list_nuts) <- c('nuts', 'nuts_name')
list_nuts_add <- tibble(
nuts = c('NO011', 'NO012', 'NO021', 'NO022', 'NO031', 'NO032', 'NO033', 'NO034', 'NO041', 'NO042', 'NO043', 'NO051', 'NO052', 'NO053', 'NO061', 'NO062', 'NO071', 'NO072', 'NO073'),
nuts_name = c('Oslo', 'Akershus', 'Hedmark', 'Oppland', 'Østfold', 'Buskerud', 'Vestfold', 'Telemark', 'Aust-Agder', 'Vest-Agder', 'Rogaland', 'Hordaland', 'Sogn og Fjordane', 'Møre og Romsdal', 'Sør-Trøndelag', 'Nord-Trøndelag', 'Nordland', 'Troms', 'Finnmark')
)
list_nuts %<>% bind_rows(list_nuts_add)
!!! MAke additio nal ploty including old green specializations
Profiling regions
p1 <- tech_rel_dev %>%
filter(nuts %in% select_region) %>%
group_by(nuts, nace_group, Y_tag) %>%
summarise(rel = weight %>% max()) %>%
ungroup() %>%
pivot_wider(names_from = Y_tag, values_from = rel, names_prefix = 'Y_', values_fill = 0) %>%
left_join(tech_dev %>%
filter(Y_tag == TRUE, period == '2', rta_bin_delta == 1) %>%
count(nuts, nace_group, wt = n_tech_region),
by = c('nuts', 'nace_group')) %>%
mutate(country = nuts %>% str_sub(1,2)) %>%
left_join(list_nace2 %>%select(nace_group, nace_sec_name) %>% distinct(), by = 'nace_group') %>%
left_join(list_nuts %>% distinct(), by = 'nuts') %>% mutate(nuts_name = paste(nuts, nuts_name, sep = ': ') )
`summarise()` has grouped output by 'nuts', 'nace_group'. You can override using the `.groups` argument.
x_mid <- mean(p1$Y_FALSE, na.rm = TRUE)
y_mid <- mean(p1$Y_TRUE, na.rm = TRUE)
# plotting
p1 %>%
ggplot(aes(x = Y_FALSE, y = Y_TRUE, size = n, col = nace_sec_name)) +
geom_point() +
geom_text_repel(aes(label = nace_group), box.padding = 0.5) +
geom_vline(xintercept = x_mid, linetype = "dashed", color = 'grey') +
geom_hline(yintercept = y_mid, linetype = "dashed", color = 'grey') +
facet_wrap(vars(nuts_name), ncol = n_regions) +
theme(legend.position = 'bottom',
legend.box = "vertical") +
labs(#title = 'New green specialization period 2',
#subtitle = 'By nuts regions',
#note = 'Relatedness is the mean over all new green specializations, per green specialization largest relatedness to former specialization counted',
x = 'Relatedness non-green',
y = 'Relatedness green',
col = 'NACE',
size = 'N green patents')
ggsave("../output/paper_figs/fig_6.jpeg", dpi = 300)
Saving 10 x 10 in image
ggsave("../output/paper_figs/fig_6.eps")
Saving 10 x 10 in image
rm(p1, x_mid, y_mid)
path_green_new <- tech_rel_dev %>%
group_by(nuts, nace_group, Y_tag) %>%
summarise(rel = weight %>% max()) %>%
ungroup() %>%
pivot_wider(names_from = Y_tag, values_from = rel, names_prefix = 'Y_', values_fill = 0) %>%
left_join(tech_dev %>%
filter(Y_tag == TRUE, period == '2', rta_bin_delta == 1) %>%
select(nuts, nace_group, n_tech_region) %>%
count(nuts, nace_group, wt = n_tech_region),
by = c('nuts', 'nace_group')) %>%
mutate(green_path = case_when(
Y_FALSE <= mean(Y_FALSE) & Y_TRUE <= mean(Y_TRUE) ~ 'creation',
Y_FALSE <= mean(Y_FALSE) & Y_TRUE > mean(Y_TRUE) ~ 'diversification',
Y_FALSE > mean(Y_FALSE) & Y_TRUE <= mean(Y_TRUE) ~ 'renewal',
Y_FALSE > mean(Y_FALSE) & Y_TRUE > mean(Y_TRUE) ~ 'renewal'
) ) %>%
select(-Y_FALSE, - Y_TRUE)
`summarise()` has grouped output by 'nuts', 'nace_group'. You can override using the `.groups` argument.
- Below a radar plot summing all up.
- It includes the share of green patents in nace groups folllowing a
particular green path (within a nuts region)
- Color indicates the share of incumbents (+5 years, +50 patents) in
the path.
- Can be used to identify a regions main path and overal profile.
TODO: Increase text size
path_green <- tech_dev %>%
mutate(green_path = case_when(
Y_tag == TRUE & period == '2' & rta_bin == 1 & rta_bin_delta == 0 & pct_tech_region_delta < 0.1 ~ 'stagnation',
Y_tag == TRUE & period == '2' & rta_bin == 1 & rta_bin_delta == 0 & pct_tech_region_delta >= 0.1 ~ 'extension',
Y_tag == TRUE & period == '2' & rta_bin == 0 & rta_bin_delta == -1 ~ 'extinction'
)) %>%
drop_na(green_path) %>%
select(nuts, nace_group, n_tech_region_delta, green_path) %>%
rename(n = n_tech_region_delta) %>%
# add existing green paths
bind_rows(path_green_new) %>%
mutate(n = n %>% abs()) %>%
# add incumbant measures
left_join(region_techn_incumb %>% filter(period == '2', Y_tag == TRUE) %>% select(nuts, nace_group, share_inc), by = c('nuts', 'nace_group')) %>%
mutate(n_new = n * (1 - share_inc),
n_inc = n * share_inc)
Break down main path industry
Geoplotting
- I also added a first plotting of main green paths
- Works well, so we can adds furthr geoplots if necessary.
path_green %>%
filter(nuts %in% select_region) %>% #, green_path != 'stagnation') %>%
# split by inc and non_incumbents
pivot_longer(c(n_new, n_inc), names_to = 'applt_type') %>%
# Aggregate
count(nuts, green_path, applt_type, wt = value) %>%
complete(nuts, green_path, applt_type, fill = list('n' = 0)) %>%
# Add overall patents andf make share
left_join(region_RTA %>%filter(period == '2') %>% count(nuts, wt = n_region, name = 'n_reg'), by = 'nuts') %>%
mutate(n_share = n ) %>% #/ n_reg) %>%
left_join(list_nuts %>% distinct(), by = 'nuts') %>% mutate(nuts_name = paste(nuts, nuts_name, sep = ': ') ) %>%
# plotting
ggplot() +
geom_col(aes(x = green_path, y = n_share, fill = applt_type), alpha = 0.8, position= "stack") +
# Lollipop shaft
#geom_segment( aes(x = green_path, y = 0, xend = green_path, yend = 0.002), linetype = "dashed", color = "gray12") +
# coord_polar() +
# coord_flip() +
facet_wrap(vars(nuts_name), ncol = n_regions, scales = 'free') +
theme(axis.text.x = element_text(angle = 60, vjust = 1, hjust=1)) +
theme(legend.position = 'bottom',
legend.box = "vertical") +
labs(#title = 'Regional green paths',
#subtitle = 'By nuts regions',
x = NULL,
y = NULL,
size = 'Share green patents',
col = 'Green path type',
fill = 'Applicant type')
ggsave("../output/paper_figs/fig_7.jpeg", dpi = 300)
Saving 10 x 12.5 in image
ggsave("../output/paper_figs/fig_7.eps")
Saving 10 x 12.5 in image
# See: https://ropengov.github.io/giscoR/
# Get map of nordics
map_nordic <- gisco_get_nuts(country = c('DNK', 'SWE', 'NOR', 'FIN'), nuts_level = 3, year = '2016')
# filter out Svalbart etc
map_nordic %<>%
filter(!(NUTS_ID %in% c('NO0B1', 'NO0B2')))
# Group by NUTS by country and convert to lines
country_lines <- map_nordic %>%
group_by(CNTR_CODE) %>%
summarise(n = n()) %>%
ungroup() %>%
st_cast("MULTILINESTRING")
Tables
map_nordic %>%
# enter main green path
left_join(path_green %>% count(nuts, green_path, wt = n) %>% group_by(nuts) %>% slice_max(order_by = n, n = 1, with_ties = FALSE) %>% ungroup(), by = c('NUTS_ID' = 'nuts')) %>%
# plot
ggplot() +
geom_sf(aes(fill = green_path)) +
geom_sf(data = country_lines, col = "blue", linewidth = 0.1) +
theme_void() +
labs(#title = 'Map: Nordic main green paths',
#subtitle = 'By nuts regions',
#note = 'Excluding NO0B1,NO0B2',
x = NULL,
y = NULL,
fill = 'Main green path') #+ theme(legend.position = 'bottom')
ggsave("../output/paper_figs/fig_8.jpeg", dpi = 300)
Saving 8.5 x 7.5 in image
ggsave("../output/paper_figs/fig_8.eps")
Saving 8.5 x 7.5 in image
# Basics Nr patents
tab_basic <- tech_dev %>%
filter(period == 2) %>%
count(nuts, Y_tag, wt = n_tech_region) %>%
pivot_wider(names_from = Y_tag, values_from = n, values_fill = 0, names_prefix = 'Y_') %>%
mutate(Y_FALSE = round(Y_FALSE), Y_TRUE = round(Y_TRUE),
Y_share = (Y_TRUE / (Y_FALSE + Y_TRUE) ) %>% round(2) ) %>%
left_join(list_nuts %>% distinct(), by = 'nuts') %>% mutate(nuts_name = paste(nuts, nuts_name, sep = ': ') ) %>%
relocate(nuts_name)
# Applicant
tab_applt <- region_applt_appln %>%
rename(weight_applt = weight_frac) %>%
filter(period == 2) %>%
left_join(region_tech %>% select(appln_id, nuts, weight) %>% rename(weight_invt = weight), by = c('appln_id', 'nuts')) %>%
mutate(weight_all = weight_applt * weight_invt) %>%
count(nuts, han_name, han_id, Y_tag, wt = weight_all) %>%
pivot_wider(names_from = Y_tag, values_from = n, values_fill = 0, names_prefix = 'Y_') %>%
mutate(Y_FALSE = round(Y_FALSE), Y_TRUE = round(Y_TRUE),
Y_share = (Y_TRUE / (Y_FALSE + Y_TRUE) ) %>% round(2)) %>%
group_by(nuts) %>%
slice_max(order_by = Y_TRUE, n = 1, with_ties = FALSE) %>%
ungroup() %>%
left_join(applt_stats %>% select(han_id, incumbant) %>% mutate(incumbant = ifelse(incumbant == TRUE, 'incumb.', 'entrant')), by = 'han_id') %>%
mutate(applicant = paste0(han_name, ' (',incumbant ,', n green: ', Y_TRUE, ', share:', Y_share, ')')) %>%
select(nuts, applicant)
tab_nace <- tech_dev %>%
filter(period == 2, Y_tag == TRUE) %>%
group_by(nuts) %>%
slice_max(order_by = n_tech_region, n = 1, with_ties = FALSE) %>%
ungroup() %>%
mutate(top_Y_nace = paste0(nace_group, ' (n ', n_tech_region %>% round(), ')')) %>%
select(nuts, top_Y_nace)
tab_cpc_Y <- data_docdb_fam_cpc %>%
mutate(cpc_Y = cpc_class_symbol %>% str_sub(1,4)) %>%
distinct(docdb_family_id, cpc_Y, .keep_all = TRUE) %>%
group_by(docdb_family_id) %>%
mutate(weight_frac = 1 / n()) %>%
ungroup() %>%
filter(cpc_Y %>% str_starts('Y02') | cpc_Y %>% str_starts('Y04')) %>%
count(docdb_family_id, cpc_Y, wt = weight_frac, name = 'weight_cpc') %>%
inner_join(data_appln %>% filter(period == '2') %>% distinct(appln_id, docdb_family_id), by = 'docdb_family_id') %>%
left_join(data_pers_appln %>% select(appln_id, nuts,weight_frac) %>% rename(weight_nuts = weight_frac), by = 'appln_id') %>%
mutate(weight_frac = weight_cpc * weight_nuts) %>%
count(cpc_Y, nuts, wt = weight_frac) %>%
group_by(nuts) %>%
slice_max(order_by = n, n = 1, with_ties = FALSE) %>%
ungroup() %>%
mutate(top_Y_cpc = paste0(cpc_Y, ' (n ', n %>% round(), ')')) %>%
select(nuts, top_Y_cpc)
# Note: Its silly that not all is indexed by docdb family.... change for next version
tab_path_rel <- path_green %>%
count(nuts, green_path, wt = n) %>%
group_by(nuts) %>%
mutate(share = (n / sum(n)) %>% round(2) ) %>%
ungroup() %>%
select(-n) %>%
pivot_wider(names_from = green_path, values_from = share, names_prefix= '% path ', values_fill = 0) %>%
arrange(nuts)
tab_path_total <- path_green %>%
count(nuts, green_path, wt = n) %>%
mutate(n = n %>% round()) %>%
pivot_wider(names_from = green_path, values_from = n, names_prefix= 'n path ', values_fill = 0) %>%
arrange(nuts)
tab_all <- tab_basic %>%
left_join(tab_cpc_Y, by = 'nuts') %>%
left_join(tab_nace, by = 'nuts') %>%
left_join(tab_applt, by = 'nuts') %>%
left_join(tab_path_rel, by = 'nuts') %>%
left_join(tab_path_total, by = 'nuts') %>%
select(-nuts)
tab_all
tab_all %>% write_csv2('../output/table_regions_all.csv')
Endnotes
#library(stargazer)
#tab_all %>% stargazer(summary = FALSE, type = 'html')
sessionInfo()
R version 4.2.1 (2022-06-23)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Ventura 13.2.1
Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.2/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] regions_0.1.8 sf_1.0-9 giscoR_0.3.2 ggrepel_0.9.1 ggraph_2.1.0 tidygraph_1.2.2 dbplyr_2.2.1 RPostgres_1.4.4 DBI_1.1.3 magrittr_2.0.3
[11] forcats_0.5.2 stringr_1.5.0 dplyr_1.0.10 purrr_1.0.1 readr_2.1.3 tidyr_1.2.1 tibble_3.1.8 ggplot2_3.4.0 tidyverse_1.3.2
loaded via a namespace (and not attached):
[1] fs_1.6.1 lubridate_1.8.0 bit64_4.0.5 httr_1.4.4 rprojroot_2.0.3 bslib_0.4.2 tools_4.2.1 backports_1.4.1
[9] utf8_1.2.2 R6_2.5.1 KernSmooth_2.23-20 colorspace_2.1-0 withr_2.5.0 tidyselect_1.2.0 gridExtra_2.3 bit_4.0.5
[17] compiler_4.2.1 cli_3.6.0 rvest_1.0.3 xml2_1.3.3 sass_0.4.5 labeling_0.4.2 scales_1.2.1 classInt_0.4-8
[25] proxy_0.4-27 digest_0.6.31 rmarkdown_2.20 pkgconfig_2.0.3 htmltools_0.5.4 fastmap_1.1.0 rlang_1.0.6 readxl_1.4.1
[33] rstudioapi_0.14 jquerylib_0.1.4 farver_2.1.1 generics_0.1.3 jsonlite_1.8.4 vroom_1.6.0 googlesheets4_1.0.1 s2_1.1.1
[41] Rcpp_1.0.10 munsell_0.5.0 fansi_1.0.3 viridis_0.6.2 lifecycle_1.0.3 stringi_1.7.12 yaml_2.3.7 MASS_7.3-57
[49] grid_4.2.1 blob_1.2.3 parallel_4.2.1 crayon_1.5.2 graphlayouts_0.8.3 haven_2.5.1 hms_1.1.2 knitr_1.42
[57] pillar_1.8.1 igraph_1.3.5 wk_0.7.1 reprex_2.0.2 glue_1.6.2 evaluate_0.20 modelr_0.1.9 vctrs_0.5.2
[65] tzdb_0.3.0 tweenr_2.0.2 cellranger_1.1.0 gtable_0.3.1 polyclip_1.10-4 assertthat_0.2.1 cachem_1.0.6 xfun_0.37
[73] ggforce_0.4.1 countrycode_1.4.0 broom_1.0.1 e1071_1.7-12 class_7.3-20 googledrive_2.0.0 viridisLite_0.4.1 gargle_1.2.1
[81] units_0.8-1 ellipsis_0.3.2 here_1.0.1
# plot_techspace_dev(g = g_tech, rta_df = tech_dev, region = 'DK013', layout_nw = coords_tech)
TODO: GO ON HERE AND DO BETTER DATAVIZ
# TEst for function development
g = g_tech
rta_df = tech_dev
dev_df = tech_rel_dev
region = 'DK013'
time = '2'
layout_nw = coords_tech
rta_df %<>%
filter(nuts == region, period == time, Y_tag == TRUE) %>%
select(nace_group, rta, n_tech_region)
dev_df %<>%
filter(nuts == region) %>%
group_by(nace_group) %>%
summarise(prev_nongreen = max(nace_group == related_techn, na.rm = TRUE) %>% as.logical()) %>%
ungroup() %>%
replace_na(list(prev_nongreen = FALSE)) %>%
select(nace_group, prev_nongreen)
g <- g %N>%
mutate(label = nace_group_name %>% str_trunc(50, side = 'right')) %>%
left_join(rta_df, by = c("name" = "nace_group")) %N>%
left_join(dev_df, by = c("name" = "nace_group"))
g %>%
ggraph(layout = coords_tech) +
geom_edge_link(aes(width = weight, alpha = weight), colour = "grey") +
geom_node_point(aes(colour = rta, shape = prev_nongreen, size = n_tech_region, filter = rta >= 1)) +
geom_node_text(aes(label = label, size = n_tech_region, filter = rta >= 1), repel = TRUE) +
scale_color_gradient2(low = "skyblue", mid = 'yellow', high = "red", midpoint = 1) +
theme_void() +
theme(legend.position="bottom") +
labs(title = paste("Industry Space:", region, sep = " "),
subtitle = 'Nodes = NACE 2 Industries. Edges: Relatedness',
caption = '')
—>
LS0tCnRpdGxlOiAnR3JlZW4gUmVnaW9uYWwgUGF0aCBwYXBlcjogRmlyc3QgcmVzdWx0cycKYXV0aG9yOiAiRGFuaWVsIFMuIEhhaW4iCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICczJwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKYGBge3IsIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIyMgZ2VuZXJhbCBvcHRpb25zClN5cy5zZXRlbnYoTEFORyA9ICJlbiIpCm9wdGlvbnMoInNjaXBlbiIgPSAxMDAsICJkaWdpdHMiID0gNCkgIyBvdmVycmlkZSBSJ3MgdGVuZGVuY3kgdG8gdXNlIHNjaWVudGlmaWMgbm90YXRpb24KCiMjIyBDbGVhbiB3b3Jrc3BhY2UKcm0obGlzdD1scygpKQpncmFwaGljcy5vZmYoKQoKIyMjIExvYWQgcGFja2FnZXMgKG1heWJlIG5lZWQgdG8gYmUgaW5zdGFsbGVkIGZpcnN0KQojIFN0YW5kYXJkCmxpYnJhcnkodGlkeXZlcnNlKSAjIEdlbmVyYWwgRFMgdG9vbGtpdApsaWJyYXJ5KG1hZ3JpdHRyKSAjIEZvciBhZHZhbmNlZCBwaXBpbmcKCiMgRGF0YWJhc2VzCmxpYnJhcnkoREJJKSAjIEdFbmVyYWwgUiBkYXRhYmFzZSBpbnRlcmZhY2UKbGlicmFyeShSUG9zdGdyZXMpICMgUG9zdGdyZVNRTCBpbnRlcmZhY2UgZHJpdmVyIApsaWJyYXJ5KGRicGx5cikgIyBmb3IgZHBseXIgd2l0aCBkYXRhYmFzZXMKCiMgbmV0d29ya3MKbGlicmFyeSh0aWR5Z3JhcGgpCmxpYnJhcnkoZ2dyYXBoKQpsaWJyYXJ5KGdncmVwZWwpCgojIEdFb3Bsb3QKbGlicmFyeShnaXNjb1IpCmxpYnJhcnkoc2YpCmBgYAoKCiMgSW50cm9kdWN0aW9uCgoqIEluIHRoaXMgbm90ZWJvb2ssIHdlIHByZXNlbnQgdGhlIGZpcnN0IHJlc3VsdHMgb2YgYW4gYW5hbHlzaXMgb2YgZ3JlZW4gZGV2ZWxvcG1lbnQgcGF0aHMgb2YgTm9yZGljIHJlZ2lvbnMKKiBJdCBpcyBiYXNlZCBvbiBwYXRlbnQgZGF0YSBmcm9tIDE5OTAtMjAxNSAoUEFUU1RBVCwgQXV0dW1uIDIwMjEgRWRpdGlvbikKKiBBbmFseXNpcyBpcyBkb25lIG9uIGFsbCBOb3JkaWMgTlVUUyAyIHJlZ2lvbnMgKGZyYWN0aW9uYWxpemVkIHBhdGVudCBhbGxvY2F0aW9uIGJ5IGludmVudG9yIGxvY2F0aW9uLCBET0NEQiBmYW1pbHkgbGV2ZWwpCiogSW5kdXN0cmllcyBhcmUgY2FwdHVyZWQgYnkgTkFDRTIgY29kZXMgb2YgcGF0ZW50cyBhY2NvcmRpbmcgdG8gdGhlIE9FQ0QgSVBDLU5BQ0UyIGNvbmNvcmRhbmNlIHRhYmxlLgoqIEdyZWVuIHBhdGVudHMgYXJlIGlkZW50aWZpZWQgdXNpbmcgdGhlIFkwMiB0YWcgaW4gdGhlIENQQyBjbGFzc2lmaWNhdGlvbgoKIyMgUHJlcHJvY2Vzc2luZyAKCmBgYHtyfQojIyBMT0FEIERBVEEKCiMgUmVndWxhciB0YWJsZXMKZGF0YV9hcHBsbiA8LSByZWFkX3JkcygnLi4vdGVtcC9kYXRhX2FwcGxuLnJkcycpCmRhdGFfcGVyc19hcHBsbiAgPC0gcmVhZF9yZHMoJy4uL3RlbXAvZGF0YV9wZXJzX2FwcGxuLnJkcycpCmRhdGFfbmFjZTIgPC0gcmVhZF9yZHMoJy4uL3RlbXAvZGF0YV9uYWNlMi5yZHMnKQpkYXRhX2RvY2RiX2ZhbV9jcGMgPC0gcmVhZF9yZHMoJy4uL3RlbXAvZGF0YV9kb2NkYl9mYW1fY3BjLnJkcycpCiNkYXRhX3BlcnNvbiA8LSByZWFkX3JkcygnLi4vdGVtcC9kYXRhX3BlcnNvbi5yZHMnKQoKCiMgUmVnaW9uYWwgc3BlY2lhbGl6YXRpb24KcmVnaW9uX1JUQSA8LSByZWFkX3JkcygnLi4vdGVtcC9yZWdpb25fUlRBLnJkcycpICU+JSAKICBtdXRhdGUoY291bnRyeSA9IG51dHMgJT4lIHN0cl9zdWIoMSwyKSwKICAgICAgICAgbnV0c19wZXJpb2QgPSBwYXN0ZShudXRzLCAnUCcsIHBlcmlvZCkpIAoKcmVnaW9uX3RlY2ggPC0gcmVhZF9yZHMoJy4uL3RlbXAvcmVnaW9uX3RlY2gucmRzJykgJT4lIAogIG11dGF0ZShjb3VudHJ5ID0gbnV0cyAlPiUgc3RyX3N1YigxLDIpLAogICAgICAgICBudXRzX3BlcmlvZCA9IHBhc3RlKG51dHMsICdQJywgcGVyaW9kKSkgCgojIFRlY2hub2xvZ3kgc3BhY2UKZ190ZWNoIDwtIHJlYWRfcmRzKCcuLi90ZW1wL2dfdGVjaC5yZHMnKQoKIyBMaXN0cwpsaXN0X25hY2UyIDwtIHJlYWRfcmRzKCcuLi90ZW1wL2xpc3RfbmFjZTIucmRzJykKCiMgQXBwbGljYW50cwpyZWdpb25fYXBwbHRfYXBwbG4gPC0gcmVhZF9yZHMoJy4uL3RlbXAvdGJsX3JlZ2lvbl9hcHBsdF9hcHBsbi5yZHMnKSAlPiUgc2VsZWN0KC1hcHBsdF9zZXFfbnIsIC1pbnZ0X3NlcV9ucikKcmVnaW9uX2FwcGx0IDwtIHJlYWRfcmRzKCcuLi90ZW1wL3RibF9yZWdpb25fYXBwbHQucmRzJykKYGBgCgpgYGB7cn0KIyMgRGVmaW5pbmcgcGFyYW1ldGVycwpuX2N1dG9mZiA9IDUwCm5fY3V0b2ZmX2dyZWVuID0gMjUKYGBgCgpgYGB7cn0KIyMgU0VMRUNUIEZPQ1VTIFJFR0lPTlMKcmVnX2luID0gJycgIyBjKCdTRTIzMicsICdOTzA0MycsICdESzAxMicpCm5fcmVnaW9ucyA9IDQgICAgIAoKIyBSZXN0cmljdCB0byB0b3AgTiByZWdpb25zCnNlbGVjdF9yZWdpb24gPC0gcmVnaW9uX3RlY2ggJT4lCiAgZ3JvdXBfYnkoY291bnRyeSwgbnV0cykgJT4lCiAgc3VtbWFyaXNlKG4gPSBzdW0od2VpZ2h0X2ZyYWMsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG5fWSA9IHN1bSh3ZWlnaHRfZnJhYyAqIFlfdGFnLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSkgJT4lCiAgYXJyYW5nZShkZXNjKG5fWSkpICU+JQogIG11dGF0ZShpbmRleCA9IDE6bigpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKGluZGV4IDw9IG5fcmVnaW9ucyB8IG51dHMgJWluJSByZWdfaW4pICU+JQogIGRpc3RpbmN0KG51dHMpICU+JQogIHB1bGwobnV0cykKCnJtKHJlZ19pbikKYGBgCgpgYGB7cn0KIyBDcmVhdGVkYXRhZnJhbWUgd2l0aCB0ZWNobm9sb2d5IHJlbGF0ZWRuZXNzIGVkZ2VsaXN0CnRlY2hfcmVsIDwtIGdfdGVjaCAlRT4lCiAgbXV0YXRlKGZyb21fbmFjZSA9IC5OKCkkbmFtZVtmcm9tXSwKICAgICAgICAgdG9fbmFjZSA9IC5OKCkkbmFtZVt0b10pICU+JQogIGFzX3RpYmJsZSgpICU+JQogIG11dGF0ZShmcm9tID0gZnJvbV9uYWNlICU+JSBhcy5jaGFyYWN0ZXIoKSwKICAgICAgICAgdG8gPSB0b19uYWNlICU+JSBhcy5jaGFyYWN0ZXIoKSkgJT4lCiAgYXJyYW5nZShmcm9tLCB0bykgJT4lCiAgc2VsZWN0KGZyb20sIHRvLCB3ZWlnaHQpCgp0ZWNoX3JlbCAlPD4lCiAgIyBBZGQgb3Bwb3NpdGUgZGlyZWN0aW9uCiAgYmluZF9yb3dzKHRlY2hfcmVsICU+JSAKICAgICAgICAgICAgICByZW5hbWUoZnJvbV9uZXcgPSB0bywgdG9fbmV3ID0gZnJvbSkgJT4lIAogICAgICAgICAgICAgIHJlbmFtZShmcm9tID0gZnJvbV9uZXcsIHRvID0gdG9fbmV3KSAlPiUKICAgICAgICAgICAgICByZWxvY2F0ZShmcm9tLCB0bykpICU+JQogICMgQWRkIHNlbGYgbG9vcHMKICBiaW5kX3Jvd3ModGVjaF9yZWwgJT4lCiAgICAgICAgICAgICAgZGlzdGluY3QoZnJvbSkgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHRvID0gZnJvbSwKICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMSkpICU+JQogIGRpc3RpbmN0KGZyb20sIHRvLCAua2VlcF9hbGwgPSBUUlVFKQpgYGAKCgpgYGB7cn0KIyBTdW1tYXJpemUgUmVnaW9ucwpyZWdpb25fUlRBX2FnZyA8LSByZWdpb25fUlRBICU+JQogIGdyb3VwX2J5KGNvdW50cnksIG51dHMsIHBlcmlvZCwgbnV0c19wZXJpb2QsIFlfdGFnKSAlPiUKICBzdW1tYXJpc2Uobl9zcGVjID0gcnRhX2JpbiAlPiUgc3VtKG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG5fc3BlY19jb3VudCA9IChuX3RlY2hfcmVnaW9uICogcnRhX2JpbikgJT4lIHN1bShuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBISEkgPSBzdW0oKG5fdGVjaF9yZWdpb24vc3VtKG5fdGVjaF9yZWdpb24pICogMTAwKV4yKSApICU+JQogIHVuZ3JvdXAoKSAKYGBgCgpgYGB7cn0KIyBEYXRhZnJhbWUgd2l0aCByZWdpb25zIGFuZCB0ZWNobm9sb2d5IGZpZWxkcwp0ZWNoX2RldiA8LSByZWdpb25fUlRBICU+JQogIHNlbGVjdChjb3VudHJ5LCBwZXJpb2QsIG51dHMsIG51dHNfcGVyaW9kLCBuYWNlX2dyb3VwLCBZX3RhZywgbl90ZWNoX3JlZ2lvbiwgcnRhLCBydGFfYmluKSAlPiUKICBhcnJhbmdlKGNvdW50cnksIG51dHMsIG5hY2VfZ3JvdXAsIFlfdGFnLCBwZXJpb2QpICU+JQogIGdyb3VwX2J5KGNvdW50cnksIG51dHMsIG5hY2VfZ3JvdXAsIFlfdGFnKSAlPiUKICBtdXRhdGUobl90ZWNoX3JlZ2lvbl9sYWcgPSBsYWcobl90ZWNoX3JlZ2lvbiwgMSksCiAgICAgICAgIG5fdGVjaF9yZWdpb25fZGVsdGEgPSBuX3RlY2hfcmVnaW9uIC0gbl90ZWNoX3JlZ2lvbl9sYWcsCiAgICAgICAgIHBjdF90ZWNoX3JlZ2lvbl9kZWx0YSA9IChuX3RlY2hfcmVnaW9uIC0gbl90ZWNoX3JlZ2lvbl9sYWcpIC8gKCBuX3RlY2hfcmVnaW9uX2xhZyArIDEpLAogICAgICAgICBydGFfbGFnID0gbGFnKHJ0YSwgMSksCiAgICAgICAgIHJ0YV9kZWx0YSA9IHJ0YSAtIHJ0YV9sYWcsCiAgICAgICAgIHJ0YV9iaW5fbGFnID0gbGFnKHJ0YV9iaW4sIDEpLAogICAgICAgICBydGFfYmluX2RlbHRhID0gcnRhX2JpbiAtIHJ0YV9iaW5fbGFnKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZShjb3VudHJ5LCBudXRzLCBuYWNlX2dyb3VwLCBZX3RhZywgcGVyaW9kKSAKYGBgCgojIFBhdGVudCBhcHBsaWNhdGlvbiBkZXZlbG9wbWVudAoKKiBJbiB0aGUgZm9sbG93aW5nLCBhIGJyaWVmIGRlc2NyaXB0aXZlIGFuYWx5c2lzIG9mIHRoZSBkZXZlbG9wbWVudCBvZiBncmVlbiBhbmQgbm9uLWdyZWVuIHBhdGVudCBhcHBsaWNhdGlvbiBpbiB0aGUgTm9yZGljcwoqIEluIGFkZGl0aW9uLCBhIGJyZWFja2Rvd24gb2YgZ3JlZW4gcGF0ZW50cyBieSB0b3AgZ3JlZW4gcGF0ZW50aW5nIHJlYWdpb25zCgpgYGB7cn0KZGF0YV9hcHBsbiAlPiUKICBtdXRhdGUoWV90YWcgPSBpZmVsc2UoWV90YWcgPT0gVFJVRSwgJ0dyZWVuJywgJ05vbi1HcmVlbicpKSAlPiUKICBmaWx0ZXIoYXBwbG5fZmlsaW5nX3llYXIgPD0gMjAxNSwgYXBwbG5fZmlsaW5nX3llYXIgPj0gMTk4NSkgJT4lCiAgY291bnQoYXBwbG5fZmlsaW5nX3llYXIsIFlfdGFnKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhcHBsbl9maWxpbmdfeWVhciwgeSA9IG4sIGNvbCA9IFlfdGFnKSkgKyAKICBnZW9tX2xpbmUoa2V5X2dseXBoID0gInRpbWVzZXJpZXMiKSArCiAgbGFicygjdGl0bGUgPSAnUGF0ZW50IGFwcGxpY2F0aW9uczogRGV2ZWxvcG1lbnQnLAogICAgICAgI3N1YnRpdGxlID0gJ0FsbCBOb3JkaWMgY29udHJpZXMsIGJ5IFkgdGFnJywKICAgICAgIHggPSAnWWVhcicsCiAgICAgICB5ID0gJ051bWJlciBhcHBsaWNhdGlvbnMnLAogICAgICAgY29sID0gJ0dyZWVuJykKYGBgCgoKYGBge3J9CmRhdGFfcGVyc19hcHBsbiAlPiUKICBtdXRhdGUoWV90YWcgPSBpZmVsc2UoWV90YWcgPT0gVFJVRSwgJ0dyZWVuJywgJ05vbi1HcmVlbicpKSAlPiUKICBmaWx0ZXIoYXBwbG5fZmlsaW5nX3llYXIgPD0gMjAxNSwgYXBwbG5fZmlsaW5nX3llYXIgPj0gMTk4NSkgJT4lCiAgZmlsdGVyKG51dHMgJWluJSBzZWxlY3RfcmVnaW9uKSAlPiUKICBjb3VudChhcHBsbl9maWxpbmdfeWVhciwgbnV0cywgWV90YWcsIHd0ID0gd2VpZ2h0X2ZyYWMpICU+JQogIGdncGxvdChhZXMoeCA9IGFwcGxuX2ZpbGluZ195ZWFyLCB5ID0gbiwgY29sID0gbnV0cykpICsgCiAgZ2VvbV9saW5lKGtleV9nbHlwaCA9ICJ0aW1lc2VyaWVzIikgKwogIGZhY2V0X3dyYXAodmFycyhZX3RhZyksIHNjYWxlcyA9ICdmcmVlJykgKwogIGxhYnMoI3RpdGxlID0gJ1BhdGVudCBhcHBsaWNhdGlvbnM6IERldmVsb3BtZW50JywKICAgICAgICNzdWJ0aXRsZSA9ICdBbGwgTm9yZGljIGNvbnRyaWVzJywKICAgICAgIHggPSAnWWVhcicsCiAgICAgICB5ID0gJ051bWJlciBhcHBsaWNhdGlvbnMsIGJ5IHJlZ2lvbiBhbmQgWSB0YWcnLAogICAgICAgY29sID0gJ051dHMzJykKYGBgCgoKYGBge3J9CmRhdGFfcGVyc19hcHBsbiAlPiUKICBtdXRhdGUoWV90YWcgPSBpZmVsc2UoWV90YWcgPT0gVFJVRSwgJ0dyZWVuJywgJ05vbi1HcmVlbicpKSAlPiUKICBmaWx0ZXIoYXBwbG5fZmlsaW5nX3llYXIgPD0gMjAxNSwgYXBwbG5fZmlsaW5nX3llYXIgPj0gMTk4NSkgJT4lCiAgY291bnQoYXBwbG5fZmlsaW5nX3llYXIsIHBlcnNvbl9jdHJ5X2NvZGUsIFlfdGFnLCB3dCA9IHdlaWdodF9mcmFjKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhcHBsbl9maWxpbmdfeWVhciwgeSA9IG4sIGNvbCA9IHBlcnNvbl9jdHJ5X2NvZGUpKSArIAogIGdlb21fbGluZShrZXlfZ2x5cGggPSAidGltZXNlcmllcyIpICsKICBmYWNldF93cmFwKHZhcnMoWV90YWcpLCBzY2FsZXMgPSAnZnJlZScpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nKSArIAogIGxhYnMoI3RpdGxlID0gJ1BhdGVudCBhcHBsaWNhdGlvbnM6IERldmVsb3BtZW50IGJ5IGNvdW50cnknLAogICAgICAgI3N1YnRpdGxlID0gJ0FsbCBOb3JkaWMgY29udHJpZXMnLAogICAgICAgeCA9ICdZZWFyJywKICAgICAgIHkgPSAnTnVtYmVyIGFwcGxpY2F0aW9ucywgYnkgcmVnaW9uIGFuZCBZIHRhZycsCiAgICAgICBjb2wgPSAnQ291bnRyeScpCgpnZ3NhdmUoIi4uL291dHB1dC9wYXBlcl9maWdzL2ZpZ18zLmpwZWciLCBkcGkgPSAzMDApCmdnc2F2ZSgiLi4vb3V0cHV0L3BhcGVyX2ZpZ3MvZmlnXzMuZXBzIikKYGBgCgojIEFwcGxpY2FudHMKCiogQXBwbGljYW50cyBvZiBwYXRlbnRzIGZpbGVkIGJ5IGludmVudG9ycyBpbiB0aGUgTm9yZGljcwoqIFRoYXQgY2FuIGJlIGRvbWVzdGljIG9yIGZvcmVpZ24gYXBwbGljYW50cwoKYGBge3J9CgpyZWdpb25fYXBwbHRfYXBwbG4gJTw+JQogIGdyb3VwX2J5KGFwcGxuX2lkKSAlPiUKICBtdXRhdGUobl9mcmFjID0gMSAvIG4oKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGxlZnRfam9pbihyZWdpb25fYXBwbHQgJT4lIHNlbGVjdChwZXJzb25faWQsIGhhbl9pZCwgaGFuX25hbWUsIHBlcnNvbl9jdHJ5X2NvZGUsIG51dHMpLCBieSA9ICdwZXJzb25faWQnKSAlPiUKICBsZWZ0X2pvaW4oZGF0YV9hcHBsbiAlPiUgc2VsZWN0KGFwcGxuX2lkLCBkb2NkYl9mYW1pbHlfaWQsIGFwcGxuX2ZpbGluZ195ZWFyLCBwZXJpb2QsIFlfdGFnKSwgYnkgPSAnYXBwbG5faWQnKSAlPiUKICBsZWZ0X2pvaW4oZGF0YV9uYWNlMiAlPiUgc2VsZWN0KGFwcGxuX2lkLCBuYWNlX2dyb3VwKSAlPiUgZ3JvdXBfYnkoYXBwbG5faWQpICU+JSBtdXRhdGUobmFjZV9zaGFyZSA9IDEgLyBuKCkpICU+JSB1bmdyb3VwKCkgJT4lIG5lc3QobmFjZSA9IGMobmFjZV9ncm91cCwgbmFjZV9zaGFyZSkpLCBieSA9ICdhcHBsbl9pZCcpICU+JQogIGRyb3BfbmEoKQpgYGAKCgpgYGB7cn0KIyBMaXN0IG1haW4gYXBwbGljYW50cwphcHBsdF9zdGF0cyA8LSByZWdpb25fYXBwbHRfYXBwbG4gJT4lCiAgZ3JvdXBfYnkoaGFuX2lkLCBoYW5fbmFtZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgbl9wYXQgPSBzdW0obl9mcmFjKSwKICAgIG5fWSA9IHN1bShuX2ZyYWMgKiBZX3RhZyksCiAgICBmaXJzdF9wYXQgPSBtaW4oYXBwbG5fZmlsaW5nX3llYXIpCiAgICApICU+JQogIG11dGF0ZShzaGFyZV9ZID0gbl9ZIC8gbl9wYXQsCiAgICAgICAgIGFnZSA9IDIwMTYgLSBmaXJzdF9wYXQsCiAgICAgICAgIGluY3VtYmFudCA9IGFnZSA+PSAxMCAmIG5fcGF0ID49IDEwKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZShkZXNjKG5fcGF0KSkKYGBgCgpgYGB7cn0KYXBwbHRfc3RhdHMgJT4lIGhlYWQoMjAwKQpgYGAKCmBgYHtyfQphcHBsdF9zdGF0cyAlPiUgYXJyYW5nZShkZXNjKG5fWSkpICU+JSBoZWFkKDEwMCkKYGBgCgpgYGB7cn0KIyBTaGFyZSBvZiBpbmN1bWJhbnRzIGJ5IHRlY2hub2xvZ3kKcmVnaW9uX3RlY2huX2luY3VtYiA8LSByZWdpb25fYXBwbHRfYXBwbG4gJT4lIAogIGxlZnRfam9pbihhcHBsdF9zdGF0cyAlPiUgc2VsZWN0KGhhbl9pZCwgaW5jdW1iYW50KSwgYnkgPSAnaGFuX2lkJykgJT4lCiAgdW5uZXN0KG5hY2UpICU+JQogIG11dGF0ZShuX3dlaWdodCA9IG5fZnJhYyAqIG5hY2Vfc2hhcmUpICU+JQogIGdyb3VwX2J5KG51dHMsIG5hY2VfZ3JvdXAsIHBlcmlvZCwgWV90YWcpICU+JQogIHN1bW1hcmlzZShuID0gc3VtKG5fd2VpZ2h0KSwKICAgICAgICAgICAgbl9pbmMgPSBzdW0obl93ZWlnaHQgKiBpbmN1bWJhbnQpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHNoYXJlX2luYyA9IG5faW5jIC8gbikKYGBgCgojIFkgVEFncwoKYGBge3J9CmRhdGFfZG9jZGJfZmFtX2NwYyAlPiUgCiAgZmlsdGVyKFlfdGFnID09IFRSVUUpICU+JQogIG11dGF0ZShjcGNfY2xhc3Nfc3ltYm9sID0gY3BjX2NsYXNzX3N5bWJvbCAlPiUgc3RyX3N1YigxLDQpKSAlPiUKICBjb3VudChjcGNfY2xhc3Nfc3ltYm9sLCBzb3J0ID0gVFJVRSkKYGBgCgoKCiMgVGVjaG5vbG9neSBzcGFjZSBnZW5lcmFsCgoqIFdlIGNhbGN1bGF0ZSB0aGUgcmVsYXRlZG5lc3Mgb2YgaW5kdXN0cmllcyBieSBjby1vY2N1cmVuY2UgcGF0dGVybiBmb2xsb3dpbmcgSGlkYWxnbyAmIEhhdXNtYW5uICgyMDA3KQoqIFJldmVhbGVkIHRlY2hub2xvZ2ljYWwgYWR2YW50YWdlIChSVEEpIElzIHNlcHBlcmF0ZWRseSBjYWxjdWxhdGVkIGZvciBZLXRhZyBhbmQgbm9uLVktdGFnIHBhdGVudHMuCgpgYGB7cn0Kc2V0LnNlZWQoMTMzNykKY29vcmRzX3RlY2ggPC0gZ190ZWNoICU+JSBpZ3JhcGg6OmxheW91dC5mcnVjaHRlcm1hbi5yZWluZ29sZCgpICU+JSBhc190aWJibGUoKQpjb2xuYW1lcyhjb29yZHNfdGVjaCkgPC0gYygieCIsICJ5IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PSAxMH0KZ190ZWNoICVOPiUKICBtdXRhdGUobmFjZV9ncm91cF9uYW1lID0gbmFjZV9ncm91cF9uYW1lICU+JSBzdHJfdHJ1bmMoNTAsIHNpZGUgPSAncmlnaHQnKSkgJT4lCiAgZ2dyYXBoKGxheW91dCA9ICBjb29yZHNfdGVjaCkgKyAKICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSB3ZWlnaHQsIGFscGhhID0gd2VpZ2h0KSwgY29sb3VyID0gImdyZXkiKSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3VyID0gbmFjZV9zZWNfbmFtZSwgc2l6ZSA9IGRncikpICsgCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFjZV9ncm91cF9uYW1lLCBzaXplID0gZGdyLCBmaWx0ZXIgPSBwZXJjZW50X3JhbmsoZGdyKSA+PSAwLjc1ICksIHJlcGVsID0gVFJVRSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsCiAgICAgICAgbGVnZW5kLmJveCA9ICJ2ZXJ0aWNhbCIpICsKICBsYWJzKCN0aXRsZSA9ICdJbmR1c3RyeSBTcGFjZSAoYWxsIE5vcmRpY3MpJywKICAgICAgICNzdWJ0aXRsZSA9ICdOb2RlcyA9IE5BQ0UgMiBJbmR1c3RyaWVzLiBFZGdlczogUmVsYXRlZG5lc3MnCiAgICApCgpnZ3NhdmUoIi4uL291dHB1dC9wYXBlcl9maWdzL2ZpZ185LmpwZWciLCBkcGkgPSAzMDApCmdnc2F2ZSgiLi4vb3V0cHV0L3BhcGVyX2ZpZ3MvZmlnXzkuZXBzIikKYGBgCgojIFJlZ2lvbmFsIHNwZWNpYWxpemF0aW9uIChSVEEpIGRldmVsb3BtZW50CgoqIENvbXBhcmlzb24gb2Ygc3BlY2lhbGl6YXRpb24gcHJvdmlkZXMgaW4gcGVyaW9kIDEgYW5kIDIKCmBgYHtyfQpwMSA8LSByZWdpb25fUlRBX2FnZyAgJT4lCiAgZmlsdGVyKG51dHMgJWluJSBzZWxlY3RfcmVnaW9uKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWV90YWcsIHZhbHVlc19mcm9tID0gYyhuX3NwZWMsIG5fc3BlY19jb3VudCwgSEhJKSwgdmFsdWVzX2ZpbGwgPSAwLCBuYW1lc19wcmVmaXggPSAnWV90YWdfJykgCgpwMiA8LSBwMSAlPiUgCiAgc2VsZWN0KHBlcmlvZCwgbnV0cywgbl9zcGVjX1lfdGFnX0ZBTFNFLCBuX3NwZWNfWV90YWdfVFJVRSkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHBlcmlvZCwgdmFsdWVzX2Zyb20gPSBjKG5fc3BlY19ZX3RhZ19GQUxTRSwgbl9zcGVjX1lfdGFnX1RSVUUpKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9IDcuNSwgZmlnLmhlaWdodD03LjV9CnAxICU+JQogIGdncGxvdChhZXMoeCA9IG5fc3BlY19ZX3RhZ19GQUxTRSwgeSA9IG5fc3BlY19ZX3RhZ19UUlVFKSkgKwogIGdlb21fc2VnbWVudChkYXRhID0gcDIsIAogICAgICAgICAgICAgICBhZXMoeCA9IG5fc3BlY19ZX3RhZ19GQUxTRV8xLAogICAgICAgICAgICAgICAgICAgeSA9IG5fc3BlY19ZX3RhZ19UUlVFXzEsCiAgICAgICAgICAgICAgICAgICB4ZW5kID0gbl9zcGVjX1lfdGFnX0ZBTFNFXzIsCiAgICAgICAgICAgICAgICAgICB5ZW5kID0gbl9zcGVjX1lfdGFnX1RSVUVfMiwKICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjc1KSwKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjE1LAogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC41LCAiY20iKSwgdHlwZSA9ICJjbG9zZWQiKSwKICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fcG9pbnQoYWVzKHNpemUgPSBuX3NwZWNfY291bnRfWV90YWdfVFJVRSwgY29sID0gSEhJX1lfdGFnX1RSVUUpKSArCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IG51dHMpLCBib3gucGFkZGluZyA9IDAuNSwgbWF4Lm92ZXJsYXBzID0gSW5mKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJza3libHVlIiwgbWlkID0gJ3llbGxvdycsIGhpZ2ggPSAicmVkIiwgbWlkcG9pbnQgPSAxKSArCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMiwgMTApKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nKSArIAogIGxhYnMoI3RpdGxlID0gJ0RldmVsb3BtZW50IG9mIG5ldyByZWdpb25hbCBzcGVjaWFsaXphdGlvbnMnLCAKICAgICAgICNzdWJ0aXRsZSA9ICdCeSBudW1iZXIgb2YgZ3JlZW4gYW5kIG5vbiBncmVlbiBzcGVjaWFsaXphdGlvbnMgaW4gcGVyaW9kIDEgYW5kIDInLAogICAgICAgeCA9ICdOIG5vbi1ncmVlbiBzcGVjaWFsaXphdGlvbnMnLAogICAgICAgeSA9ICdOIGdyZWVuIHNwZWNpYWxpemF0aW9ucycsCiAgICAgICBzaXplID0gJ04gZ3JlZW4gcGF0ZW50cycsCiAgICAgICBjb2wgPSAnSEhJIGdyZWVuIHBhdGVudHMnKSAKCmdnc2F2ZSgiLi4vb3V0cHV0L3BhcGVyX2ZpZ3MvZmlnXzQuanBlZyIsIGRwaSA9IDMwMCkKZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfNC5lcHMiKQoKcm0ocDEsIHAyKQpgYGAKCgojIEFuYWx5c2lzIGZvciBleGlzdGluZyBncmVlbiBwYXRoczoKCk5PVEU6IG5ldyBwYXRlbnRkcyBpbiBzcGVjaWFsaXphdGlvbnM/IAoKYGBge3J9CnRlY2hfcmVsX2RldiA8LSB0ZWNoX3JlbCAlPiUgCiAgc2VsZWN0KGZyb20sIHRvLCB3ZWlnaHQpICU+JQogIGxlZnRfam9pbih0ZWNoX2RldiAlPiUgZGlzdGluY3QobmFjZV9ncm91cCwgbnV0cyksIGJ5ID0gYygnZnJvbScgPSAnbmFjZV9ncm91cCcpKSAlPiUKICAjIGZpbHRlciBmb3IgcnRhIGluIHBlcmlvZCAxCiAgaW5uZXJfam9pbih0ZWNoX2RldiAlPiUgZmlsdGVyKHBlcmlvZCA9PSAnMScsIHJ0YV9iaW4gPT0gMSkgJT4lIHNlbGVjdChuYWNlX2dyb3VwLCBudXRzLCBZX3RhZyksIGJ5ID0gYygndG8nID0gJ25hY2VfZ3JvdXAnLCAnbnV0cycpKSAlPiUKICAjIGZpbHRlciBmb3IgbmV3IGdyZWVuIHNwZWNpYWxpemF0aW9uIGluIHBlcmlvZCAyCiAgc2VtaV9qb2luKHRlY2hfZGV2ICU+JSBmaWx0ZXIocGVyaW9kID09ICcyJywgcnRhX2JpbiA9PSAxLCBydGFfYmluX2RlbHRhID09IDEsIFlfdGFnID09IFRSVUUpLCBieSA9IGMoJ2Zyb20nID0gJ25hY2VfZ3JvdXAnLCAnbnV0cycpKSAlPiUKICByZW5hbWUobmFjZV9ncm91cCA9IGZyb20sIHJlbGF0ZWRfdGVjaG4gPSB0bykgCmBgYAoKYGBge3IsIGZpZy53aWR0aD0gNy41LCBmaWcuaGVpZ2h0PTcuNX0KcDEgPC0gdGVjaF9yZWxfZGV2ICU+JQogIGdyb3VwX2J5KG51dHMsIG5hY2VfZ3JvdXAsIFlfdGFnKSAlPiUKICBzdW1tYXJpc2UocmVsX21heCA9IHdlaWdodCAlPiUgbWF4KCksCiAgICAgICAgICAgIHJlbF9zdW0gPSB3ZWlnaHQgJT4lIHN1bSgpLAogICAgICAgICAgICByZWxfbWVhbiA9IHdlaWdodCAlPiUgbWVhbigpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIwogIGdyb3VwX2J5KG51dHMsIFlfdGFnKSAlPiUKICBzdW1tYXJpc2UocmVsID0gcmVsX21heCAlPiUgbWVhbigpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIwogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZX3RhZywgdmFsdWVzX2Zyb20gPSByZWwsIG5hbWVzX3ByZWZpeCA9ICdZXycsIHZhbHVlc19maWxsID0gMCkgJT4lCiAgbGVmdF9qb2luKHRlY2hfZGV2ICU+JSBmaWx0ZXIoWV90YWcgPT0gVFJVRSwgcGVyaW9kID09ICcyJywgcnRhX2Jpbl9kZWx0YSA9PSAxKSAlPiUgc2VsZWN0KG51dHMgLCBuX3RlY2hfcmVnaW9uKSAlPiUgY291bnQobnV0cywgd3QgPSBuX3RlY2hfcmVnaW9uKSwgYnkgPSBjKCdudXRzJykpICU+JQogIG11dGF0ZShjb3VudHJ5ID0gbnV0cyAlPiUgc3RyX3N1YigxLDIpKSAKCnhfbWlkIDwtIG1lYW4ocDEkWV9GQUxTRSwgbmEucm0gPSBUUlVFKQp5X21pZCA8LSBtZWFuKHAxJFlfVFJVRSwgbmEucm0gPSBUUlVFKQoKcDEgJT4lCiAgZmlsdGVyKDAuNSA8PSBwZXJjZW50X3JhbmsobikpICU+JQogIGdncGxvdChhZXMoeCA9IFlfRkFMU0UsIHkgPSBZX1RSVUUsIHNpemUgPSBuKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHhfbWlkLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICdncmV5JykgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSB5X21pZCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAnZ3JleScpICsKICBnZW9tX3BvaW50KGFlcyhjb2wgPSBjb3VudHJ5KSkgKwogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBudXRzKSwgYm94LnBhZGRpbmcgPSAwLjUsIG1heC5vdmVybGFwcyA9IEluZikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKyAKICAgIGxhYnMoI3RpdGxlID0gJ05ldyBncmVlbiBzcGVjaWFsaXphdGlvbiBwZXJpb2QgMicsIAogICAgICAgI3N1YnRpdGxlID0gJ0J5IG51dHMgcmVnaW9ucycsCiAgICAgICAjbm90ZSA9ICdSZWxhdGVkbmVzcyBpcyB0aGUgbWVhbiBvdmVyIGFsbCBuZXcgZ3JlZW4gc3BlY2lhbGl6YXRpb25zLCBwZXIgZ3JlZW4gc3BlY2lhbGl6YXRpb24gbGFyZ2VzdCByZWxhdGVkbmVzcyB0byBmb3JtZXIgc3BlY2lhbGl6YXRpb24gY291bnRlZCcsCiAgICAgICB4ID0gJ1JlbGF0ZWRuZXNzIG5vbi1ncmVlbicsCiAgICAgICB5ID0gJ1JlbGF0ZWRuZXNzIGdyZWVuJywKICAgICAgIHNpemUgPSAnTiBncmVlbiBwYXRlbnRzJykgCgpnZ3NhdmUoIi4uL291dHB1dC9wYXBlcl9maWdzL2ZpZ181LmpwZWciLCBkcGkgPSAzMDApCmdnc2F2ZSgiLi4vb3V0cHV0L3BhcGVyX2ZpZ3MvZmlnXzUuZXBzIikKCnJtKHAxLCB4X21pZCwgeV9taWQpCmBgYAoKCmBgYHtyfQpsaWJyYXJ5KHJlZ2lvbnMpCmRhdGEobnV0c19jaGFuZ2VzKQpsaXN0X251dHMgPC0gbnV0c19jaGFuZ2VzICU+JSBzZWxlY3QoY29kZV8yMDIxLCBnZW9fbmFtZV8yMDIxKSAKY29sbmFtZXMobGlzdF9udXRzKSA8LSBjKCdudXRzJywgJ251dHNfbmFtZScpCgpsaXN0X251dHNfYWRkIDwtIHRpYmJsZSgKICBudXRzID0gYygnTk8wMTEnLCAnTk8wMTInLCAnTk8wMjEnLCAnTk8wMjInLCAnTk8wMzEnLCAnTk8wMzInLCAnTk8wMzMnLCAnTk8wMzQnLCAnTk8wNDEnLCAnTk8wNDInLCAnTk8wNDMnLCAnTk8wNTEnLCAnTk8wNTInLCAnTk8wNTMnLCAnTk8wNjEnLCAnTk8wNjInLCAnTk8wNzEnLCAnTk8wNzInLCAnTk8wNzMnKSwKICBudXRzX25hbWUgPSBjKCdPc2xvJywgJ0FrZXJzaHVzJywgJ0hlZG1hcmsnLCAnT3BwbGFuZCcsICfDmHN0Zm9sZCcsICdCdXNrZXJ1ZCcsICdWZXN0Zm9sZCcsICdUZWxlbWFyaycsICdBdXN0LUFnZGVyJywgJ1Zlc3QtQWdkZXInLCAnUm9nYWxhbmQnLCAnSG9yZGFsYW5kJywgJ1NvZ24gb2cgRmpvcmRhbmUnLCAnTcO4cmUgb2cgUm9tc2RhbCcsICdTw7hyLVRyw7huZGVsYWcnLCAnTm9yZC1UcsO4bmRlbGFnJywgJ05vcmRsYW5kJywgJ1Ryb21zJywgJ0Zpbm5tYXJrJykKKQoKbGlzdF9udXRzICU8PiUgYmluZF9yb3dzKGxpc3RfbnV0c19hZGQpCmBgYAoKCgoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KcDEgPC0gdGVjaF9yZWxfZGV2ICU+JQogIGZpbHRlcihudXRzICVpbiUgc2VsZWN0X3JlZ2lvbikgJT4lCiAgZ3JvdXBfYnkobnV0cywgbmFjZV9ncm91cCwgWV90YWcpICU+JQogIHN1bW1hcmlzZShyZWwgPSB3ZWlnaHQgJT4lIG1heCgpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFlfdGFnLCB2YWx1ZXNfZnJvbSA9IHJlbCwgbmFtZXNfcHJlZml4ID0gJ1lfJywgdmFsdWVzX2ZpbGwgPSAwKSAlPiUKICBsZWZ0X2pvaW4odGVjaF9kZXYgJT4lIAogICAgICAgICAgICAgIGZpbHRlcihZX3RhZyA9PSBUUlVFLCBwZXJpb2QgPT0gJzInLCBydGFfYmluX2RlbHRhID09IDEpICU+JSAKICAgICAgICAgICAgICBjb3VudChudXRzLCBuYWNlX2dyb3VwLCB3dCA9IG5fdGVjaF9yZWdpb24pLCAKICAgICAgICAgICAgYnkgPSBjKCdudXRzJywgJ25hY2VfZ3JvdXAnKSkgJT4lCiAgbXV0YXRlKGNvdW50cnkgPSBudXRzICU+JSBzdHJfc3ViKDEsMikpICU+JQogIGxlZnRfam9pbihsaXN0X25hY2UyICU+JXNlbGVjdChuYWNlX2dyb3VwLCBuYWNlX3NlY19uYW1lKSAlPiUgZGlzdGluY3QoKSwgYnkgPSAnbmFjZV9ncm91cCcpICU+JQogIGxlZnRfam9pbihsaXN0X251dHMgJT4lIGRpc3RpbmN0KCksIGJ5ID0gJ251dHMnKSAlPiUgbXV0YXRlKG51dHNfbmFtZSA9IHBhc3RlKG51dHMsIG51dHNfbmFtZSwgc2VwID0gJzogJykgKQoKeF9taWQgPC0gbWVhbihwMSRZX0ZBTFNFLCBuYS5ybSA9IFRSVUUpCnlfbWlkIDwtIG1lYW4ocDEkWV9UUlVFLCBuYS5ybSA9IFRSVUUpCgojIHBsb3R0aW5nCnAxICU+JQogIGdncGxvdChhZXMoeCA9IFlfRkFMU0UsIHkgPSBZX1RSVUUsIHNpemUgPSBuLCBjb2wgPSBuYWNlX3NlY19uYW1lKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IG5hY2VfZ3JvdXApLCBib3gucGFkZGluZyA9IDAuNSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHhfbWlkLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICdncmV5JykgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSB5X21pZCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAnZ3JleScpICsKICBmYWNldF93cmFwKHZhcnMobnV0c19uYW1lKSwgbmNvbCA9IG5fcmVnaW9ucykgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nLAogICAgICAgIGxlZ2VuZC5ib3ggPSAidmVydGljYWwiKSArCiAgbGFicygjdGl0bGUgPSAnTmV3IGdyZWVuIHNwZWNpYWxpemF0aW9uIHBlcmlvZCAyJywgCiAgICAgICAjc3VidGl0bGUgPSAnQnkgbnV0cyByZWdpb25zJywKICAgICAgICNub3RlID0gJ1JlbGF0ZWRuZXNzIGlzIHRoZSBtZWFuIG92ZXIgYWxsIG5ldyBncmVlbiBzcGVjaWFsaXphdGlvbnMsIHBlciBncmVlbiBzcGVjaWFsaXphdGlvbiBsYXJnZXN0IHJlbGF0ZWRuZXNzIHRvIGZvcm1lciBzcGVjaWFsaXphdGlvbiBjb3VudGVkJywKICAgICAgIHggPSAnUmVsYXRlZG5lc3Mgbm9uLWdyZWVuJywKICAgICAgIHkgPSAnUmVsYXRlZG5lc3MgZ3JlZW4nLAogICAgICAgY29sID0gJ05BQ0UnLAogICAgICAgc2l6ZSA9ICdOIGdyZWVuIHBhdGVudHMnKSAKCmdnc2F2ZSgiLi4vb3V0cHV0L3BhcGVyX2ZpZ3MvZmlnXzYuanBlZyIsIGRwaSA9IDMwMCkKZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfNi5lcHMiKQoKcm0ocDEsIHhfbWlkLCB5X21pZCkKYGBgCgohISEgTUFrZSBhZGRpdGlvIG5hbCBwbG90eSBpbmNsdWRpbmcgb2xkIGdyZWVuIHNwZWNpYWxpemF0aW9ucwoKIyBQcm9maWxpbmcgcmVnaW9ucwoKYGBge3J9CnBhdGhfZ3JlZW5fbmV3IDwtIHRlY2hfcmVsX2RldiAlPiUKICBncm91cF9ieShudXRzLCBuYWNlX2dyb3VwLCBZX3RhZykgJT4lCiAgc3VtbWFyaXNlKHJlbCA9IHdlaWdodCAlPiUgbWF4KCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWV90YWcsIHZhbHVlc19mcm9tID0gcmVsLCBuYW1lc19wcmVmaXggPSAnWV8nLCB2YWx1ZXNfZmlsbCA9IDApICU+JQogIGxlZnRfam9pbih0ZWNoX2RldiAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKFlfdGFnID09IFRSVUUsIHBlcmlvZCA9PSAnMicsIHJ0YV9iaW5fZGVsdGEgPT0gMSkgJT4lIAogICAgICAgICAgICAgIHNlbGVjdChudXRzLCBuYWNlX2dyb3VwLCBuX3RlY2hfcmVnaW9uKSAlPiUgCiAgICAgICAgICAgICAgY291bnQobnV0cywgbmFjZV9ncm91cCwgd3QgPSBuX3RlY2hfcmVnaW9uKSwgCiAgICAgICAgICAgIGJ5ID0gYygnbnV0cycsICduYWNlX2dyb3VwJykpICU+JQogIG11dGF0ZShncmVlbl9wYXRoID0gY2FzZV93aGVuKCAKICAgIFlfRkFMU0UgPD0gbWVhbihZX0ZBTFNFKSAmIFlfVFJVRSA8PSBtZWFuKFlfVFJVRSkgfiAnY3JlYXRpb24nLAogICAgWV9GQUxTRSA8PSBtZWFuKFlfRkFMU0UpICYgWV9UUlVFID4gbWVhbihZX1RSVUUpIH4gJ2RpdmVyc2lmaWNhdGlvbicsCiAgICBZX0ZBTFNFID4gbWVhbihZX0ZBTFNFKSAmIFlfVFJVRSA8PSBtZWFuKFlfVFJVRSkgfiAncmVuZXdhbCcsCiAgICBZX0ZBTFNFID4gbWVhbihZX0ZBTFNFKSAmIFlfVFJVRSA+IG1lYW4oWV9UUlVFKSB+ICdyZW5ld2FsJwogICAgKSApICU+JQogIHNlbGVjdCgtWV9GQUxTRSwgLSBZX1RSVUUpCmBgYAoKYGBge3J9CnBhdGhfZ3JlZW4gPC0gdGVjaF9kZXYgJT4lIAogIG11dGF0ZShncmVlbl9wYXRoID0gY2FzZV93aGVuKCAKICAgIFlfdGFnID09IFRSVUUgJiBwZXJpb2QgPT0gJzInICYgcnRhX2JpbiA9PSAxICYgcnRhX2Jpbl9kZWx0YSA9PSAwICYgcGN0X3RlY2hfcmVnaW9uX2RlbHRhIDwgMC4xIH4gJ3N0YWduYXRpb24nLAogICAgWV90YWcgPT0gVFJVRSAmIHBlcmlvZCA9PSAnMicgJiBydGFfYmluID09IDEgJiBydGFfYmluX2RlbHRhID09IDAgJiBwY3RfdGVjaF9yZWdpb25fZGVsdGEgPj0gMC4xIH4gJ2V4dGVuc2lvbicsCiAgICBZX3RhZyA9PSBUUlVFICYgcGVyaW9kID09ICcyJyAmIHJ0YV9iaW4gPT0gMCAmIHJ0YV9iaW5fZGVsdGEgPT0gLTEgfiAnZXh0aW5jdGlvbicKICApKSAlPiUKICBkcm9wX25hKGdyZWVuX3BhdGgpICU+JQogIHNlbGVjdChudXRzLCBuYWNlX2dyb3VwLCBuX3RlY2hfcmVnaW9uX2RlbHRhLCBncmVlbl9wYXRoKSAlPiUKICByZW5hbWUobiA9IG5fdGVjaF9yZWdpb25fZGVsdGEpICU+JQogICMgYWRkIGV4aXN0aW5nIGdyZWVuIHBhdGhzCiAgYmluZF9yb3dzKHBhdGhfZ3JlZW5fbmV3KSAlPiUKICBtdXRhdGUobiA9IG4gJT4lIGFicygpKSAlPiUKICAjIGFkZCBpbmN1bWJhbnQgbWVhc3VyZXMKICBsZWZ0X2pvaW4ocmVnaW9uX3RlY2huX2luY3VtYiAlPiUgZmlsdGVyKHBlcmlvZCA9PSAnMicsIFlfdGFnID09IFRSVUUpICU+JSBzZWxlY3QobnV0cywgbmFjZV9ncm91cCwgc2hhcmVfaW5jKSwgYnkgPSBjKCdudXRzJywgJ25hY2VfZ3JvdXAnKSkgJT4lCiAgbXV0YXRlKG5fbmV3ID0gbiAqICgxIC0gc2hhcmVfaW5jKSwKICAgICAgICAgbl9pbmMgPSBuICogc2hhcmVfaW5jKQpgYGAKCiogQmVsb3cgYSByYWRhciBwbG90IHN1bW1pbmcgYWxsIHVwLgoqIEl0IGluY2x1ZGVzIHRoZSBzaGFyZSBvZiBncmVlbiBwYXRlbnRzIGluIG5hY2UgZ3JvdXBzIGZvbGxsb3dpbmcgYSBwYXJ0aWN1bGFyIGdyZWVuIHBhdGggKHdpdGhpbiBhIG51dHMgcmVnaW9uKQoqIENvbG9yIGluZGljYXRlcyB0aGUgc2hhcmUgb2YgaW5jdW1iZW50cyAoKzUgeWVhcnMsICs1MCBwYXRlbnRzKSBpbiB0aGUgcGF0aC4KKiBDYW4gYmUgdXNlZCB0byBpZGVudGlmeSBhIHJlZ2lvbnMgbWFpbiBwYXRoIGFuZCBvdmVyYWwgcHJvZmlsZS4KClRPRE86IEluY3JlYXNlIHRleHQgc2l6ZQoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMi41fQpwYXRoX2dyZWVuICU+JQogIGZpbHRlcihudXRzICVpbiUgc2VsZWN0X3JlZ2lvbikgJT4lICMsIGdyZWVuX3BhdGggIT0gJ3N0YWduYXRpb24nKSAlPiUKICAjIHNwbGl0IGJ5IGluYyBhbmQgbm9uX2luY3VtYmVudHMKICBwaXZvdF9sb25nZXIoYyhuX25ldywgbl9pbmMpLCBuYW1lc190byA9ICdhcHBsdF90eXBlJykgJT4lIAogICMgQWdncmVnYXRlCiAgY291bnQobnV0cywgZ3JlZW5fcGF0aCwgYXBwbHRfdHlwZSwgd3QgPSB2YWx1ZSkgJT4lCiAgY29tcGxldGUobnV0cywgZ3JlZW5fcGF0aCwgYXBwbHRfdHlwZSwgZmlsbCA9IGxpc3QoJ24nID0gIDApKSAlPiUKICAjIEFkZCBvdmVyYWxsIHBhdGVudHMgYW5kZiBtYWtlIHNoYXJlCiAgbGVmdF9qb2luKHJlZ2lvbl9SVEEgJT4lZmlsdGVyKHBlcmlvZCA9PSAnMicpICU+JSAgY291bnQobnV0cywgd3QgPSBuX3JlZ2lvbiwgbmFtZSA9ICduX3JlZycpLCBieSA9ICdudXRzJykgJT4lCiAgbXV0YXRlKG5fc2hhcmUgPSBuICkgJT4lICMvIG5fcmVnKSAlPiUKICBsZWZ0X2pvaW4obGlzdF9udXRzICU+JSBkaXN0aW5jdCgpLCBieSA9ICdudXRzJykgJT4lIG11dGF0ZShudXRzX25hbWUgPSBwYXN0ZShudXRzLCBudXRzX25hbWUsIHNlcCA9ICc6ICcpICkgJT4lCiAgIyBwbG90dGluZwogIGdncGxvdCgpICsKICBnZW9tX2NvbChhZXMoeCA9IGdyZWVuX3BhdGgsIHkgPSBuX3NoYXJlLCBmaWxsID0gYXBwbHRfdHlwZSksIGFscGhhID0gMC44LCBwb3NpdGlvbj0gInN0YWNrIikgICsgCiAgIyBMb2xsaXBvcCBzaGFmdCAKICAjZ2VvbV9zZWdtZW50KCBhZXMoeCA9IGdyZWVuX3BhdGgsIHkgPSAwLCB4ZW5kID0gZ3JlZW5fcGF0aCwgeWVuZCA9IDAuMDAyKSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiZ3JheTEyIikgKyAKICAjIGNvb3JkX3BvbGFyKCkgKwogICMgY29vcmRfZmxpcCgpICsgCiAgZmFjZXRfd3JhcCh2YXJzKG51dHNfbmFtZSksIG5jb2wgPSBuX3JlZ2lvbnMsIHNjYWxlcyA9ICdmcmVlJykgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNjAsIHZqdXN0ID0gMSwgaGp1c3Q9MSkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsCiAgICAgICAgbGVnZW5kLmJveCA9ICJ2ZXJ0aWNhbCIpICsKICBsYWJzKCN0aXRsZSA9ICdSZWdpb25hbCBncmVlbiBwYXRocycsIAogICAgICAgI3N1YnRpdGxlID0gJ0J5IG51dHMgcmVnaW9ucycsCiAgICAgICB4ID0gTlVMTCwKICAgICAgIHkgPSBOVUxMLAogICAgICAgc2l6ZSA9ICdTaGFyZSBncmVlbiBwYXRlbnRzJywKICAgICAgIGNvbCA9ICdHcmVlbiBwYXRoIHR5cGUnLAogICAgICAgZmlsbCA9ICdBcHBsaWNhbnQgdHlwZScpIAoKZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfNy5qcGVnIiwgZHBpID0gMzAwKQpnZ3NhdmUoIi4uL291dHB1dC9wYXBlcl9maWdzL2ZpZ183LmVwcyIpCmBgYAoKQnJlYWsgZG93biBtYWluIHBhdGggaW5kdXN0cnkKCiMgR2VvcGxvdHRpbmcKCiogSSBhbHNvIGFkZGVkIGEgZmlyc3QgcGxvdHRpbmcgb2YgbWFpbiBncmVlbiBwYXRocwoqIFdvcmtzIHdlbGwsIHNvIHdlIGNhbiBhZGRzIGZ1cnRociBnZW9wbG90cyBpZiBuZWNlc3NhcnkuCgpgYGB7cn0KIyBTZWU6IGh0dHBzOi8vcm9wZW5nb3YuZ2l0aHViLmlvL2dpc2NvUi8gCgojIEdldCBtYXAgb2Ygbm9yZGljcwptYXBfbm9yZGljIDwtIGdpc2NvX2dldF9udXRzKGNvdW50cnkgPSBjKCdETksnLCAnU1dFJywgJ05PUicsICdGSU4nKSwgbnV0c19sZXZlbCA9IDMsIHllYXIgPSAnMjAxNicpCgojIGZpbHRlciBvdXQgU3ZhbGJhcnQgZXRjCm1hcF9ub3JkaWMgJTw+JQogIGZpbHRlcighKE5VVFNfSUQgJWluJSBjKCdOTzBCMScsICdOTzBCMicpKSkKCiMgR3JvdXAgYnkgTlVUUyBieSBjb3VudHJ5IGFuZCBjb252ZXJ0IHRvIGxpbmVzCmNvdW50cnlfbGluZXMgPC0gbWFwX25vcmRpYyAlPiUKICBncm91cF9ieShDTlRSX0NPREUpICU+JQogIHN1bW1hcmlzZShuID0gbigpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc3RfY2FzdCgiTVVMVElMSU5FU1RSSU5HIikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTguNSwgZmlnLmhlaWdodD03LjV9Cm1hcF9ub3JkaWMgJT4lCiAgIyBlbnRlciBtYWluIGdyZWVuIHBhdGgKICBsZWZ0X2pvaW4ocGF0aF9ncmVlbiAlPiUgY291bnQobnV0cywgZ3JlZW5fcGF0aCwgd3QgPSBuKSAlPiUgZ3JvdXBfYnkobnV0cykgJT4lIHNsaWNlX21heChvcmRlcl9ieSA9IG4sIG4gPSAxLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lIHVuZ3JvdXAoKSwgYnkgPSBjKCdOVVRTX0lEJyA9ICdudXRzJykpICU+JQogICMgcGxvdAogIGdncGxvdCgpICsgCiAgZ2VvbV9zZihhZXMoZmlsbCA9IGdyZWVuX3BhdGgpKSArCiAgZ2VvbV9zZihkYXRhID0gY291bnRyeV9saW5lcywgY29sID0gImJsdWUiLCBsaW5ld2lkdGggPSAwLjEpICsgCiAgdGhlbWVfdm9pZCgpICsKICBsYWJzKCN0aXRsZSA9ICdNYXA6IE5vcmRpYyBtYWluIGdyZWVuIHBhdGhzJywgCiAgICAgICAjc3VidGl0bGUgPSAnQnkgbnV0cyByZWdpb25zJywKICAgICAgICNub3RlID0gJ0V4Y2x1ZGluZyBOTzBCMSxOTzBCMicsCiAgICAgICB4ID0gTlVMTCwKICAgICAgIHkgPSBOVUxMLAogICAgICAgZmlsbCA9ICdNYWluIGdyZWVuIHBhdGgnKSAjKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJykKCmdnc2F2ZSgiLi4vb3V0cHV0L3BhcGVyX2ZpZ3MvZmlnXzguanBlZyIsIGRwaSA9IDMwMCkKZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfOC5lcHMiKQpgYGAKCiMgVGFibGVzCgpgYGB7cn0KIyBCYXNpY3MgTnIgcGF0ZW50cwp0YWJfYmFzaWMgPC0gdGVjaF9kZXYgJT4lCiAgZmlsdGVyKHBlcmlvZCA9PSAyKSAlPiUgCiAgY291bnQobnV0cywgWV90YWcsIHd0ID0gbl90ZWNoX3JlZ2lvbikgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFlfdGFnLCB2YWx1ZXNfZnJvbSA9IG4sIHZhbHVlc19maWxsID0gMCwgbmFtZXNfcHJlZml4ID0gJ1lfJykgJT4lCiAgbXV0YXRlKFlfRkFMU0UgPSByb3VuZChZX0ZBTFNFKSwgWV9UUlVFID0gcm91bmQoWV9UUlVFKSwKICAgICAgICAgWV9zaGFyZSA9IChZX1RSVUUgLyAoWV9GQUxTRSArIFlfVFJVRSkgICkgJT4lIHJvdW5kKDIpICApICU+JQogIGxlZnRfam9pbihsaXN0X251dHMgJT4lIGRpc3RpbmN0KCksIGJ5ID0gJ251dHMnKSAlPiUgbXV0YXRlKG51dHNfbmFtZSA9IHBhc3RlKG51dHMsIG51dHNfbmFtZSwgc2VwID0gJzogJykgKSAlPiUKICByZWxvY2F0ZShudXRzX25hbWUpCgojIEFwcGxpY2FudCAKdGFiX2FwcGx0IDwtIHJlZ2lvbl9hcHBsdF9hcHBsbiAlPiUKICByZW5hbWUod2VpZ2h0X2FwcGx0ID0gd2VpZ2h0X2ZyYWMpICU+JQogIGZpbHRlcihwZXJpb2QgPT0gMikgJT4lCiAgbGVmdF9qb2luKHJlZ2lvbl90ZWNoICU+JSBzZWxlY3QoYXBwbG5faWQsIG51dHMsIHdlaWdodCkgJT4lIHJlbmFtZSh3ZWlnaHRfaW52dCA9IHdlaWdodCksIGJ5ID0gYygnYXBwbG5faWQnLCAnbnV0cycpKSAlPiUKICBtdXRhdGUod2VpZ2h0X2FsbCA9IHdlaWdodF9hcHBsdCAqIHdlaWdodF9pbnZ0KSAlPiUKICBjb3VudChudXRzLCBoYW5fbmFtZSwgaGFuX2lkLCBZX3RhZywgd3QgPSB3ZWlnaHRfYWxsKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWV90YWcsIHZhbHVlc19mcm9tID0gbiwgdmFsdWVzX2ZpbGwgPSAwLCBuYW1lc19wcmVmaXggPSAnWV8nKSAlPiUKICBtdXRhdGUoWV9GQUxTRSA9IHJvdW5kKFlfRkFMU0UpLCBZX1RSVUUgPSByb3VuZChZX1RSVUUpLAogICAgICAgICBZX3NoYXJlID0gKFlfVFJVRSAvIChZX0ZBTFNFICsgWV9UUlVFKSAgKSAlPiUgcm91bmQoMikpICU+JSAKICBncm91cF9ieShudXRzKSAlPiUKICBzbGljZV9tYXgob3JkZXJfYnkgPSBZX1RSVUUsIG4gPSAxLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGxlZnRfam9pbihhcHBsdF9zdGF0cyAlPiUgc2VsZWN0KGhhbl9pZCwgaW5jdW1iYW50KSAlPiUgbXV0YXRlKGluY3VtYmFudCA9IGlmZWxzZShpbmN1bWJhbnQgPT0gVFJVRSwgJ2luY3VtYi4nLCAnZW50cmFudCcpKSwgYnkgPSAnaGFuX2lkJykgJT4lCiAgbXV0YXRlKGFwcGxpY2FudCA9IHBhc3RlMChoYW5fbmFtZSwgJyAoJyxpbmN1bWJhbnQgLCcsIG4gZ3JlZW46ICcsIFlfVFJVRSwgJywgc2hhcmU6JywgWV9zaGFyZSwgJyknKSkgJT4lCiAgc2VsZWN0KG51dHMsIGFwcGxpY2FudCkKCnRhYl9uYWNlIDwtIHRlY2hfZGV2ICU+JSAKICBmaWx0ZXIocGVyaW9kID09IDIsIFlfdGFnID09IFRSVUUpICU+JQogIGdyb3VwX2J5KG51dHMpICU+JQogIHNsaWNlX21heChvcmRlcl9ieSA9IG5fdGVjaF9yZWdpb24sIG4gPSAxLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZSh0b3BfWV9uYWNlID0gcGFzdGUwKG5hY2VfZ3JvdXAsICcgKG4gJywgbl90ZWNoX3JlZ2lvbiAlPiUgcm91bmQoKSwgJyknKSkgJT4lCiAgc2VsZWN0KG51dHMsIHRvcF9ZX25hY2UpCgp0YWJfY3BjX1kgPC0gZGF0YV9kb2NkYl9mYW1fY3BjICU+JQogIG11dGF0ZShjcGNfWSA9IGNwY19jbGFzc19zeW1ib2wgJT4lIHN0cl9zdWIoMSw0KSkgJT4lCiAgZGlzdGluY3QoZG9jZGJfZmFtaWx5X2lkLCBjcGNfWSwgLmtlZXBfYWxsID0gVFJVRSkgJT4lCiAgZ3JvdXBfYnkoZG9jZGJfZmFtaWx5X2lkKSAlPiUKICBtdXRhdGUod2VpZ2h0X2ZyYWMgPSAxIC8gbigpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKGNwY19ZICU+JSBzdHJfc3RhcnRzKCdZMDInKSB8IGNwY19ZICU+JSBzdHJfc3RhcnRzKCdZMDQnKSkgJT4lCiAgY291bnQoZG9jZGJfZmFtaWx5X2lkLCBjcGNfWSwgd3QgPSB3ZWlnaHRfZnJhYywgbmFtZSA9ICd3ZWlnaHRfY3BjJykgJT4lCiAgaW5uZXJfam9pbihkYXRhX2FwcGxuICU+JSBmaWx0ZXIocGVyaW9kID09ICcyJykgJT4lIGRpc3RpbmN0KGFwcGxuX2lkLCBkb2NkYl9mYW1pbHlfaWQpLCBieSA9ICdkb2NkYl9mYW1pbHlfaWQnKSAlPiUKICBsZWZ0X2pvaW4oZGF0YV9wZXJzX2FwcGxuICU+JSBzZWxlY3QoYXBwbG5faWQsIG51dHMsd2VpZ2h0X2ZyYWMpICU+JSByZW5hbWUod2VpZ2h0X251dHMgPSB3ZWlnaHRfZnJhYyksIGJ5ID0gJ2FwcGxuX2lkJykgJT4lCiAgbXV0YXRlKHdlaWdodF9mcmFjID0gd2VpZ2h0X2NwYyAqIHdlaWdodF9udXRzKSAlPiUKICBjb3VudChjcGNfWSwgbnV0cywgd3QgPSB3ZWlnaHRfZnJhYykgJT4lCiAgZ3JvdXBfYnkobnV0cykgJT4lCiAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbiA9IDEsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHRvcF9ZX2NwYyA9IHBhc3RlMChjcGNfWSwgJyAobiAnLCBuICU+JSByb3VuZCgpLCAnKScpKSAlPiUKICBzZWxlY3QobnV0cywgdG9wX1lfY3BjKQogIAojIE5vdGU6IEl0cyBzaWxseSB0aGF0IG5vdCBhbGwgaXMgaW5kZXhlZCBieSBkb2NkYiBmYW1pbHkuLi4uIGNoYW5nZSBmb3IgbmV4dCB2ZXJzaW9uCiAgICAgICAgICAKdGFiX3BhdGhfcmVsIDwtIHBhdGhfZ3JlZW4gJT4lCiAgY291bnQobnV0cywgZ3JlZW5fcGF0aCwgd3QgPSBuKSAlPiUKICBncm91cF9ieShudXRzKSAlPiUKICBtdXRhdGUoc2hhcmUgPSAobiAvIHN1bShuKSkgJT4lIHJvdW5kKDIpICkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdCgtbikgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGdyZWVuX3BhdGgsIHZhbHVlc19mcm9tID0gc2hhcmUsIG5hbWVzX3ByZWZpeD0gJyUgcGF0aCAnLCB2YWx1ZXNfZmlsbCA9IDApICU+JQogIGFycmFuZ2UobnV0cykKCnRhYl9wYXRoX3RvdGFsIDwtIHBhdGhfZ3JlZW4gJT4lCiAgY291bnQobnV0cywgZ3JlZW5fcGF0aCwgd3QgPSBuKSAlPiUKICBtdXRhdGUobiA9IG4gJT4lIHJvdW5kKCkpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBncmVlbl9wYXRoLCB2YWx1ZXNfZnJvbSA9IG4sIG5hbWVzX3ByZWZpeD0gJ24gcGF0aCAnLCB2YWx1ZXNfZmlsbCA9IDApICU+JQogIGFycmFuZ2UobnV0cykKYGBgCgpgYGB7cn0KdGFiX2FsbCA8LSB0YWJfYmFzaWMgJT4lCiAgbGVmdF9qb2luKHRhYl9jcGNfWSwgYnkgPSAnbnV0cycpICU+JSAgCiAgbGVmdF9qb2luKHRhYl9uYWNlLCBieSA9ICdudXRzJykgJT4lICAKICBsZWZ0X2pvaW4odGFiX2FwcGx0LCBieSA9ICdudXRzJykgJT4lCiAgbGVmdF9qb2luKHRhYl9wYXRoX3JlbCwgYnkgPSAnbnV0cycpICU+JQogIGxlZnRfam9pbih0YWJfcGF0aF90b3RhbCwgYnkgPSAnbnV0cycpICU+JQogIHNlbGVjdCgtbnV0cykKCnRhYl9hbGwKYGBgCgoKYGBge3J9CnRhYl9hbGwgJT4lIHdyaXRlX2NzdjIoJy4uL291dHB1dC90YWJsZV9yZWdpb25zX2FsbC5jc3YnKQpgYGAKCgpgYGB7ciwgcmVzdWx0cz0nYXNpcyd9CiNsaWJyYXJ5KHN0YXJnYXplcikKI3RhYl9hbGwgJT4lIHN0YXJnYXplcihzdW1tYXJ5ID0gRkFMU0UsIHR5cGUgPSAnaHRtbCcpCmBgYAoKCiMgRW5kbm90ZXMKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoKCjwhLS0tCgpEUk9QUEVEIEZPUiBOT1cKCiMgVGVjaCBTcGFjZSBjaGFuZ2VzCgpgYGB7cn0KcGxvdF90ZWNoc3BhY2VfZGV2IDwtIGZ1bmN0aW9uKGcsIHJ0YV9kZiwgZGV2X2RmLCByZWdpb24sIHRpbWUgPSAnMicsIGxheW91dF9udyA9ICduaWNlbHknKXsKICAjIFRPRE8sIEMmUCBmdW5jdGlvbiBmcm9tIGJlbG93IG9uY2UgZmluaXNoZWQKfQpgYGAKCmBgYHtyfQojIHBsb3RfdGVjaHNwYWNlX2RldihnID0gZ190ZWNoLCBydGFfZGYgPSB0ZWNoX2RldiwgcmVnaW9uID0gJ0RLMDEzJywgbGF5b3V0X253ID0gY29vcmRzX3RlY2gpIApgYGAKCgpUT0RPOiBHTyBPTiBIRVJFIEFORCBETyBCRVRURVIgREFUQVZJWgoKYGBge3J9CiMgVEVzdCBmb3IgZnVuY3Rpb24gZGV2ZWxvcG1lbnQKZyA9IGdfdGVjaApydGFfZGYgPSB0ZWNoX2RldgpkZXZfZGYgPSB0ZWNoX3JlbF9kZXYgCnJlZ2lvbiA9ICdESzAxMycKdGltZSA9ICcyJwpsYXlvdXRfbncgPSBjb29yZHNfdGVjaAoKcnRhX2RmICU8PiUgCiAgZmlsdGVyKG51dHMgPT0gcmVnaW9uLCBwZXJpb2QgPT0gdGltZSwgWV90YWcgPT0gVFJVRSkgJT4lIAogIHNlbGVjdChuYWNlX2dyb3VwLCBydGEsIG5fdGVjaF9yZWdpb24pCiAgCmRldl9kZiAlPD4lCiAgZmlsdGVyKG51dHMgPT0gcmVnaW9uKSAlPiUgCiAgZ3JvdXBfYnkobmFjZV9ncm91cCkgJT4lCiAgc3VtbWFyaXNlKHByZXZfbm9uZ3JlZW4gPSBtYXgobmFjZV9ncm91cCA9PSByZWxhdGVkX3RlY2huLCBuYS5ybSA9IFRSVUUpICU+JSBhcy5sb2dpY2FsKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICByZXBsYWNlX25hKGxpc3QocHJldl9ub25ncmVlbiA9IEZBTFNFKSkgJT4lCiAgc2VsZWN0KG5hY2VfZ3JvdXAsIHByZXZfbm9uZ3JlZW4pCgpnIDwtIGcgJU4+JQogIG11dGF0ZShsYWJlbCA9IG5hY2VfZ3JvdXBfbmFtZSAlPiUgc3RyX3RydW5jKDUwLCBzaWRlID0gJ3JpZ2h0JykpICU+JQogIGxlZnRfam9pbihydGFfZGYsIGJ5ID0gYygibmFtZSIgPSAibmFjZV9ncm91cCIpKSAlTj4lCiAgbGVmdF9qb2luKGRldl9kZiwgYnkgPSBjKCJuYW1lIiA9ICJuYWNlX2dyb3VwIikpIAoKZyAlPiUKICBnZ3JhcGgobGF5b3V0ID0gIGNvb3Jkc190ZWNoKSArIAogIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IHdlaWdodCwgYWxwaGEgPSB3ZWlnaHQpLCBjb2xvdXIgPSAiZ3JleSIpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhjb2xvdXIgPSBydGEsIHNoYXBlID0gcHJldl9ub25ncmVlbiwgc2l6ZSA9IG5fdGVjaF9yZWdpb24sIGZpbHRlciA9IHJ0YSA+PSAxKSkgKyAKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBsYWJlbCwgc2l6ZSA9IG5fdGVjaF9yZWdpb24sIGZpbHRlciA9IHJ0YSA+PSAxKSwgcmVwZWwgPSBUUlVFKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJza3libHVlIiwgbWlkID0gJ3llbGxvdycsIGhpZ2ggPSAicmVkIiwgbWlkcG9pbnQgPSAxKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJJbmR1c3RyeSBTcGFjZToiLCByZWdpb24sIHNlcCA9ICIgIiksCiAgICAgICBzdWJ0aXRsZSA9ICdOb2RlcyA9IE5BQ0UgMiBJbmR1c3RyaWVzLiBFZGdlczogUmVsYXRlZG5lc3MnLAogICAgICAgY2FwdGlvbiA9ICcnKQpgYGAKCi0tLT4=