1 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

1.1 Preprocessing

2 Defining parameters

### 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
library(magrittr) # For advanced piping

# Databases
library(DBI) # GEneral R database interface
library(RPostgres) # PostgreSQL interface driver 
library(dbplyr) # for dplyr with databases

# networks
library(tidygraph)
library(ggraph)
library(ggrepel)

# GEoplot
library(giscoR)
library(sf)
var_t_start <- 1985
var_t_end <- 2015
var_t_break <- 2000
## LOAD DATA

# Regular tables
data_appln <- read_rds('../temp/tbl_region_appln.rds') %>% mutate(period = ((appln_filing_year >= var_t_break) + 1) %>% as.numeric() %>% as.character()) 
data_docdb_fam_cpc <- read_rds('../temp/tbl_region_docdb_fam_cpc.rds')
data_appln_isic <- read_rds('../temp/tbl_appln_isic.rds')
data_pers_appln <- read_rds('../temp/tbl_region_pers_appln.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')

# 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')

# Lists
list_isic  <- read_csv('../input/list_isic4_cleaned.csv') 
Rows: 766 Columns: 9── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (8): isic4_l1, isic4_l2, isic4_l3, isic4_l4, isic4_l4_name, isic4_l3_name, isic4_l2_name, isic4_l1_name
dbl (1): level
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Defining parameters
n_cutoff = 50
n_cutoff_green = 25
## SELECT FOCUS REGIONS
select_country = c('SE', 'NO','DK', 'FI')

reg_in = '' # c('SE232', 'NO043', 'DK012')
n_regions = 4     

# Restrict to top N regions
select_region <- region_tech %>%
  filter(country %in% select_country) %>%
  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)
appln_invt_nordic <- data_pers_appln %>% filter(person_ctry_code %in% select_country) %>%
  distinct(appln_id) %>%
  left_join(data_appln %>% select(appln_id, docdb_family_id) , by = 'appln_id') %>%
  distinct(appln_id, docdb_family_id)
# 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.

3 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 regions
# Dataframe with regions and technology fields
tech_dev <- region_RTA %>%
  select(country, period, nuts, nuts_period, isic4_l3, Y_tag, n_tech_region, rta, rta_bin) %>%
  arrange(country, nuts, isic4_l3, Y_tag, period) %>%
  group_by(country, nuts, isic4_l3, 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, isic4_l3, Y_tag, period) 

!! TODO ADJUST FOR COUNRTY!

data_appln %>%
  semi_join(appln_invt_nordic, by = 'appln_id') %>%
  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 %<>%
  inner_join(data_appln %>% select(appln_id, appln_filing_year), by = 'appln_id')
data_pers_appln %>%
  filter(nuts %in% select_region) %>%
  mutate(Y_tag = ifelse(Y_tag == TRUE, 'Green', 'Non-Green')) %>%
  filter(appln_filing_year <= 2015, appln_filing_year >= 1985) %>%
  count(appln_filing_year, nuts, Y_tag, wt = pers_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 countries',
       x = 'Year',
       y = 'Number applications, by region and Y tag',
       col = 'Nuts3')

4 Applicants

  • Applicants of patents filed by inventors in the Nordics
  • That can be domestic or foreign applicants
data_pers_appln %>%
  filter(person_ctry_code %in% select_country) %>%
  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 = pers_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)
#ggsave("../output/paper_figs/fig_3.eps")
region_applt_appln %<>%
  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), by = 'appln_id') %>%
  left_join(data_appln_isic %>% select(docdb_family_id, isic4_l3, isic_frac) %>% nest(isic = c(isic4_l3, isic_frac)), by = 'docdb_family_id') %>%
  drop_na()
# List main applicants
applt_stats <- region_applt_appln %>%
  filter(person_ctry_code %in% select_country) %>%
  group_by(han_id, han_name) %>%
  summarise(
    n_pat = sum(applt_frac),
    n_Y = sum(applt_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)

5 Y TAgs

# Share of incumbants by technology
region_techn_incumb <- region_applt_appln %>% 
  filter(person_ctry_code %in% select_country) %>%
  left_join(applt_stats %>% select(han_id, incumbant), by = 'han_id') %>%
  unnest(isic) %>%
  mutate(n_weight = isic_frac * applt_frac) %>%
  group_by(nuts, isic4_l3, period, Y_tag) %>%
  summarise(n = sum(n_weight),
            n_inc = sum(n_weight * incumbant)) %>%
  ungroup() %>%
  mutate(share_inc = n_inc / n)
`summarise()` has grouped output by 'nuts', 'isic4_l3', 'period'. You can override using the `.groups` argument.

6 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 %>% 
  semi_join(appln_invt_nordic, by = 'docdb_family_id') %>%
  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()
colnames(coords_tech) <- c("x", "y")

7 Regional specialization (RTA) development

  • Comparison of specialization provides in period 1 and 2
g_tech %N>%
  mutate(isic4_l3_name = isic4_l3_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 = isic4_l1_name, size = dgr)) + 
  geom_node_text(aes(label = isic4_l3_name, size = dgr, filter = percent_rank(dgr) >= 0.90 ), repel = TRUE) +
  theme_void() +
  theme(legend.position = 'bottom',
        legend.box = "vertical") +
  labs(col = 'ISIC Rev.4 group'
         #title = 'Industry Space (all Nordics)',
       #subtitle = 'Nodes = NACE 2 Industries. Edges: Relatedness'
    )


#ggsave("../output/paper_figs/fig_9.jpeg", dpi = 300)
#ggsave("../output/paper_figs/fig_9.eps")
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))

8 Analysis for existing green paths:

NOTE: new patents in specializations?

p1 %>%
  ggplot(aes(x = n_spec_Y_tag_FALSE, y = n_spec_Y_tag_TRUE)) +
  geom_point(aes(size = n_spec_count_Y_tag_TRUE, col = HHI_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_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') 


# ggsave("../output/paper_figs/fig_4.jpeg", dpi = 300)
#ggsave("../output/paper_figs/fig_4.eps")

rm(p1, p2)
tech_rel_dev <- tech_rel %>% 
  select(from, to, weight) %>%
  inner_join(tech_dev %>% distinct(isic4_l3, nuts), by = c('from' = 'isic4_l3')) %>%
  # filter for rta in period 1
  inner_join(tech_dev %>% filter(period == '1', rta_bin == 1) %>% distinct(isic4_l3, nuts, Y_tag), by = c('to' = 'isic4_l3', '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' = 'isic4_l3', 'nuts')) %>%
  rename(isic4_l3= from, related_techn = to) 
Warning: Detected an unexpected many-to-many relationship between `x` and `y`.Warning: Detected an unexpected many-to-many relationship between `x` and `y`.
p1 <- tech_rel_dev %>%
  group_by(nuts, isic4_l3, 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', 'isic4_l3'. 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(country %in% select_country,
         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)
#ggsave("../output/paper_figs/fig_5.eps")

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)
list_isic %>%
  filter(level ==3) %>%
    select(isic4_l1, isic4_l3, isic4_l4_name, isic4_l1_name) 

!!! Make additio nal ploty including old green specializations

9 Profiling regions

p1 <- tech_rel_dev %>%
  group_by(nuts, isic4_l3, 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, isic4_l3, wt = n_tech_region), 
            by = c('nuts', 'isic4_l3')) %>%
  mutate(country = nuts %>% str_sub(1,2)) %>%
  left_join(list_isic  %>%select(isic4_l3, isic4_l3_name, isic4_l1_name) %>% distinct(), by = 'isic4_l3') %>%
  left_join(list_nuts %>% distinct(), by = 'nuts') %>% 
  mutate(nuts_name = paste(nuts, nuts_name, sep = ': ') )
`summarise()` has grouped output by 'nuts', 'isic4_l3'. 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 %>%
  filter(nuts %in% select_region) %>%
  ggplot(aes(x = Y_FALSE, y = Y_TRUE, size = n, col = isic4_l1_name)) +
  geom_point() +
  geom_text_repel(aes(label = isic4_l3), 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 = 'ISIC Rev.4',
       size = 'N green patents') 


# ggsave("../output/paper_figs/fig_6.jpeg", dpi = 300)
# ggsave("../output/paper_figs/fig_6.eps")

rm(p1, x_mid, y_mid)
path_green_new <- tech_rel_dev %>%
  group_by(nuts, isic4_l3, 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, isic4_l3, n_tech_region) %>% 
              count(nuts, isic4_l3, wt = n_tech_region), 
            by = c('nuts', 'isic4_l3')) %>%
  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', 'isic4_l3'. 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, isic4_l3, 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, isic4_l3, share_inc), by = c('nuts', 'isic4_l3')) %>%
  mutate(n_new = n * (1 - share_inc),
         n_inc = n * share_inc)

Break down main path industry

10 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)
# ggsave("../output/paper_figs/fig_7.eps")
# 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")

11 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)
# ggsave("../output/paper_figs/fig_8.eps")
# Basics Nr patents
tab_basic <- tech_dev %>%
  filter(country %in% select_country, 
         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 %>%
  filter(person_ctry_code %in% select_country,
         period == 2) %>%
  left_join(region_tech %>% select(appln_id, nuts, weight_frac), by = c('appln_id', 'nuts')) %>%
  count(nuts, han_name, han_id, Y_tag, wt = weight_frac) %>%
  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)
Warning: Detected an unexpected many-to-many relationship between `x` and `y`.
tab_isic <- tech_dev %>% 
  filter(country %in% select_country,
         period == 2, 
         Y_tag == TRUE) %>%
  group_by(nuts) %>%
  slice_max(order_by = n_tech_region, n = 1, with_ties = FALSE) %>%
  ungroup() %>%
  mutate(top_Y_isic = paste0(isic4_l3, ' (n ', n_tech_region %>% round(), ')')) %>%
  select(nuts, top_Y_isic)

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) %>%
  filter(cpc_Y %>% str_starts('Y02') | cpc_Y %>% str_starts('Y04')) %>%
  count(docdb_family_id, cpc_Y, wt = cpc_frac, name = 'weight_cpc') %>%
  inner_join(data_appln %>% distinct(appln_id, docdb_family_id), by = 'docdb_family_id') %>%
  inner_join(data_pers_appln %>% filter(person_ctry_code %in% select_country) %>% select(appln_id, nuts), by = 'appln_id') %>% 
  count(cpc_Y, nuts, wt = weight_cpc) %>%
  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)
Warning: Detected an unexpected many-to-many relationship between `x` and `y`.
  
# Note: Its silly that not all is indexed by docdb family.... change for next version
          
tab_path_rel <- path_green %>%
  filter(str_sub(nuts, 1,2) %in% select_country) %>%
  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 %>%
  filter(str_sub(nuts, 1,2) %in% select_country) %>%
  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_isic, 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')

12 Endnotes

#library(stargazer)
#tab_all %>% stargazer(summary = FALSE, type = 'html')
sessionInfo()
R version 4.3.1 (2023-06-16)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Ventura 13.5

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: Europe/Copenhagen
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] regions_0.1.8   sf_1.0-14       giscoR_0.3.5    ggrepel_0.9.3   ggraph_2.1.0    tidygraph_1.2.3 Matrix_1.5-4.1  EconGeo_2.0     dbplyr_2.3.3    RPostgres_1.4.5 DBI_1.1.3      
[12] magrittr_2.0.3  lubridate_1.9.2 forcats_1.0.0   stringr_1.5.0   dplyr_1.1.2     purrr_1.0.2     readr_2.1.4     tidyr_1.3.0     tibble_3.2.1    ggplot2_3.4.3   tidyverse_2.0.0

loaded via a namespace (and not attached):
 [1] tidyselect_1.2.0   viridisLite_0.4.2  farver_2.1.1       blob_1.2.4         viridis_0.6.4      fastmap_1.1.1      reshape_0.8.9      tweenr_2.0.2       digest_0.6.33     
[10] timechange_0.2.0   lifecycle_1.0.3    compiler_4.3.1     rlang_1.1.1        sass_0.4.7         tools_4.3.1        igraph_1.5.1       utf8_1.2.3         yaml_2.3.7        
[19] knitr_1.43         labeling_0.4.2     graphlayouts_1.0.0 bit_4.0.5          classInt_0.4-9     here_1.0.1         plyr_1.8.8         KernSmooth_2.23-21 withr_2.5.0       
[28] grid_4.3.1         polyclip_1.10-4    fansi_1.0.4        e1071_1.7-13       colorspace_2.1-0   scales_1.2.1       MASS_7.3-60        cli_3.6.1          rmarkdown_2.24    
[37] crayon_1.5.2       ragg_1.2.5         generics_0.1.3     rstudioapi_0.15.0  tzdb_0.4.0         readxl_1.4.3       cachem_1.0.8       ggforce_0.4.1      proxy_0.4-27      
[46] assertthat_0.2.1   parallel_4.3.1     s2_1.1.4           cellranger_1.1.0   vctrs_0.6.3        jsonlite_1.8.7     hms_1.1.3          bit64_4.0.5        systemfonts_1.0.4 
[55] jquerylib_0.1.4    units_0.8-3        glue_1.6.2         stringi_1.7.12     countrycode_1.5.0  gtable_0.3.3       munsell_0.5.0      pillar_1.9.0       htmltools_0.5.6   
[64] R6_2.5.1           wk_0.7.3           textshaping_0.3.6  rprojroot_2.0.3    vroom_1.6.3        evaluate_0.21      lattice_0.21-8     bslib_0.5.1        class_7.3-22      
[73] Rcpp_1.0.11        gridExtra_2.3      xfun_0.40          pkgconfig_2.0.3   
# 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 = '')

—>

LS0tCnRpdGxlOiAnR3JlZW4gUmVnaW9uYWwgUGF0aCBwYXBlcjogRmlyc3QgcmVzdWx0cycKYXV0aG9yOiAiRGFuaWVsIFMuIEhhaW4iCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICczJwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKYGBge3IsIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIyMgZ2VuZXJhbCBvcHRpb25zClN5cy5zZXRlbnYoTEFORyA9ICJlbiIpCm9wdGlvbnMoInNjaXBlbiIgPSAxMDAsICJkaWdpdHMiID0gNCkgIyBvdmVycmlkZSBSJ3MgdGVuZGVuY3kgdG8gdXNlIHNjaWVudGlmaWMgbm90YXRpb24KCiMjIyBDbGVhbiB3b3Jrc3BhY2UKcm0obGlzdD1scygpKQpncmFwaGljcy5vZmYoKQoKIyMjIExvYWQgcGFja2FnZXMgKG1heWJlIG5lZWQgdG8gYmUgaW5zdGFsbGVkIGZpcnN0KQojIFN0YW5kYXJkCmxpYnJhcnkodGlkeXZlcnNlKSAjIEdlbmVyYWwgRFMgdG9vbGtpdApsaWJyYXJ5KG1hZ3JpdHRyKSAjIEZvciBhZHZhbmNlZCBwaXBpbmcKCiMgRGF0YWJhc2VzCmxpYnJhcnkoREJJKSAjIEdFbmVyYWwgUiBkYXRhYmFzZSBpbnRlcmZhY2UKbGlicmFyeShSUG9zdGdyZXMpICMgUG9zdGdyZVNRTCBpbnRlcmZhY2UgZHJpdmVyIApsaWJyYXJ5KGRicGx5cikgIyBmb3IgZHBseXIgd2l0aCBkYXRhYmFzZXMKCiMgbmV0d29ya3MKbGlicmFyeSh0aWR5Z3JhcGgpCmxpYnJhcnkoZ2dyYXBoKQpsaWJyYXJ5KGdncmVwZWwpCgojIEdFb3Bsb3QKbGlicmFyeShnaXNjb1IpCmxpYnJhcnkoc2YpCmBgYAoKCiMgSW50cm9kdWN0aW9uCgoqIEluIHRoaXMgbm90ZWJvb2ssIHdlIHByZXNlbnQgdGhlIGZpcnN0IHJlc3VsdHMgb2YgYW4gYW5hbHlzaXMgb2YgZ3JlZW4gZGV2ZWxvcG1lbnQgcGF0aHMgb2YgTm9yZGljIHJlZ2lvbnMKKiBJdCBpcyBiYXNlZCBvbiBwYXRlbnQgZGF0YSBmcm9tIDE5OTAtMjAxNSAoUEFUU1RBVCwgQXV0dW1uIDIwMjEgRWRpdGlvbikKKiBBbmFseXNpcyBpcyBkb25lIG9uIGFsbCBOb3JkaWMgTlVUUyAyIHJlZ2lvbnMgKGZyYWN0aW9uYWxpemVkIHBhdGVudCBhbGxvY2F0aW9uIGJ5IGludmVudG9yIGxvY2F0aW9uLCBET0NEQiBmYW1pbHkgbGV2ZWwpCiogSW5kdXN0cmllcyBhcmUgY2FwdHVyZWQgYnkgTkFDRTIgY29kZXMgb2YgcGF0ZW50cyBhY2NvcmRpbmcgdG8gdGhlIE9FQ0QgSVBDLU5BQ0UyIGNvbmNvcmRhbmNlIHRhYmxlLgoqIEdyZWVuIHBhdGVudHMgYXJlIGlkZW50aWZpZWQgdXNpbmcgdGhlIFkwMiB0YWcgaW4gdGhlIENQQyBjbGFzc2lmaWNhdGlvbgoKIyMgUHJlcHJvY2Vzc2luZyAKCiMgRGVmaW5pbmcgcGFyYW1ldGVycwoKYGBge3J9CnZhcl90X3N0YXJ0IDwtIDE5ODUKdmFyX3RfZW5kIDwtIDIwMTUKdmFyX3RfYnJlYWsgPC0gMjAwMApgYGAKCmBgYHtyfQojIyBMT0FEIERBVEEKCiMgUmVndWxhciB0YWJsZXMKZGF0YV9hcHBsbiA8LSByZWFkX3JkcygnLi4vdGVtcC90YmxfcmVnaW9uX2FwcGxuLnJkcycpICU+JSBtdXRhdGUocGVyaW9kID0gKChhcHBsbl9maWxpbmdfeWVhciA+PSB2YXJfdF9icmVhaykgKyAxKSAlPiUgYXMubnVtZXJpYygpICU+JSBhcy5jaGFyYWN0ZXIoKSkgCmRhdGFfZG9jZGJfZmFtX2NwYyA8LSByZWFkX3JkcygnLi4vdGVtcC90YmxfcmVnaW9uX2RvY2RiX2ZhbV9jcGMucmRzJykKZGF0YV9hcHBsbl9pc2ljIDwtIHJlYWRfcmRzKCcuLi90ZW1wL3RibF9hcHBsbl9pc2ljLnJkcycpCmRhdGFfcGVyc19hcHBsbiA8LSByZWFkX3JkcygnLi4vdGVtcC90YmxfcmVnaW9uX3BlcnNfYXBwbG4ucmRzJykKCiMgUmVnaW9uYWwgc3BlY2lhbGl6YXRpb24KcmVnaW9uX1JUQSA8LSByZWFkX3JkcygnLi4vdGVtcC9yZWdpb25fUlRBLnJkcycpICU+JSAKICBtdXRhdGUoY291bnRyeSA9IG51dHMgJT4lIHN0cl9zdWIoMSwyKSwKICAgICAgICAgbnV0c19wZXJpb2QgPSBwYXN0ZShudXRzLCAnUCcsIHBlcmlvZCkpIAoKcmVnaW9uX3RlY2ggPC0gcmVhZF9yZHMoJy4uL3RlbXAvcmVnaW9uX3RlY2gucmRzJykgJT4lIAogIG11dGF0ZShjb3VudHJ5ID0gbnV0cyAlPiUgc3RyX3N1YigxLDIpLAogICAgICAgICBudXRzX3BlcmlvZCA9IHBhc3RlKG51dHMsICdQJywgcGVyaW9kKSkgCgojIFRlY2hub2xvZ3kgc3BhY2UKZ190ZWNoIDwtIHJlYWRfcmRzKCcuLi90ZW1wL2dfdGVjaC5yZHMnKQoKIyBBcHBsaWNhbnRzCnJlZ2lvbl9hcHBsdF9hcHBsbiA8LSByZWFkX3JkcygnLi4vdGVtcC90YmxfcmVnaW9uX2FwcGx0X2FwcGxuLnJkcycpICU+JSBzZWxlY3QoLWFwcGx0X3NlcV9uciwgLWludnRfc2VxX25yKQpyZWdpb25fYXBwbHQgPC0gcmVhZF9yZHMoJy4uL3RlbXAvdGJsX3JlZ2lvbl9hcHBsdC5yZHMnKQoKIyBMaXN0cwpsaXN0X2lzaWMgIDwtIHJlYWRfY3N2KCcuLi9pbnB1dC9saXN0X2lzaWM0X2NsZWFuZWQuY3N2JykgCmBgYAoKYGBge3J9CiMjIERlZmluaW5nIHBhcmFtZXRlcnMKbl9jdXRvZmYgPSA1MApuX2N1dG9mZl9ncmVlbiA9IDI1CmBgYAoKYGBge3J9CiMjIFNFTEVDVCBGT0NVUyBSRUdJT05TCnNlbGVjdF9jb3VudHJ5ID0gYygnU0UnLCAnTk8nLCdESycsICdGSScpCgpyZWdfaW4gPSAnJyAjIGMoJ1NFMjMyJywgJ05PMDQzJywgJ0RLMDEyJykKbl9yZWdpb25zID0gNCAgICAgCgojIFJlc3RyaWN0IHRvIHRvcCBOIHJlZ2lvbnMKc2VsZWN0X3JlZ2lvbiA8LSByZWdpb25fdGVjaCAlPiUKICBmaWx0ZXIoY291bnRyeSAlaW4lIHNlbGVjdF9jb3VudHJ5KSAlPiUKICBncm91cF9ieShjb3VudHJ5LCBudXRzKSAlPiUKICBzdW1tYXJpc2UobiA9IHN1bSh3ZWlnaHRfZnJhYywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbl9ZID0gc3VtKHdlaWdodF9mcmFjICogWV90YWcsIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBhcnJhbmdlKGRlc2Mobl9ZKSkgJT4lCiAgbXV0YXRlKGluZGV4ID0gMTpuKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIoaW5kZXggPD0gbl9yZWdpb25zIHwgbnV0cyAlaW4lIHJlZ19pbikgJT4lCiAgZGlzdGluY3QobnV0cykgJT4lCiAgcHVsbChudXRzKQoKcm0ocmVnX2luKQpgYGAKCmBgYHtyfQphcHBsbl9pbnZ0X25vcmRpYyA8LSBkYXRhX3BlcnNfYXBwbG4gJT4lIGZpbHRlcihwZXJzb25fY3RyeV9jb2RlICVpbiUgc2VsZWN0X2NvdW50cnkpICU+JQogIGRpc3RpbmN0KGFwcGxuX2lkKSAlPiUKICBsZWZ0X2pvaW4oZGF0YV9hcHBsbiAlPiUgc2VsZWN0KGFwcGxuX2lkLCBkb2NkYl9mYW1pbHlfaWQpICwgYnkgPSAnYXBwbG5faWQnKSAlPiUKICBkaXN0aW5jdChhcHBsbl9pZCwgZG9jZGJfZmFtaWx5X2lkKQpgYGAKCgpgYGB7cn0KIyBDcmVhdGVkYXRhZnJhbWUgd2l0aCB0ZWNobm9sb2d5IHJlbGF0ZWRuZXNzIGVkZ2VsaXN0CnRlY2hfcmVsIDwtIGdfdGVjaCAlRT4lCiAgbXV0YXRlKGZyb21fbmFjZSA9IC5OKCkkbmFtZVtmcm9tXSwKICAgICAgICAgdG9fbmFjZSA9IC5OKCkkbmFtZVt0b10pICU+JQogIGFzX3RpYmJsZSgpICU+JQogIG11dGF0ZShmcm9tID0gZnJvbV9uYWNlICU+JSBhcy5jaGFyYWN0ZXIoKSwKICAgICAgICAgdG8gPSB0b19uYWNlICU+JSBhcy5jaGFyYWN0ZXIoKSkgJT4lCiAgYXJyYW5nZShmcm9tLCB0bykgJT4lCiAgc2VsZWN0KGZyb20sIHRvLCB3ZWlnaHQpCgp0ZWNoX3JlbCAlPD4lCiAgIyBBZGQgb3Bwb3NpdGUgZGlyZWN0aW9uCiAgYmluZF9yb3dzKHRlY2hfcmVsICU+JSAKICAgICAgICAgICAgICByZW5hbWUoZnJvbV9uZXcgPSB0bywgdG9fbmV3ID0gZnJvbSkgJT4lIAogICAgICAgICAgICAgIHJlbmFtZShmcm9tID0gZnJvbV9uZXcsIHRvID0gdG9fbmV3KSAlPiUKICAgICAgICAgICAgICByZWxvY2F0ZShmcm9tLCB0bykpICU+JQogICMgQWRkIHNlbGYgbG9vcHMKICBiaW5kX3Jvd3ModGVjaF9yZWwgJT4lCiAgICAgICAgICAgICAgZGlzdGluY3QoZnJvbSkgJT4lCiAgICAgICAgICAgICAgbXV0YXRlKHRvID0gZnJvbSwKICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gMSkpICU+JQogIGRpc3RpbmN0KGZyb20sIHRvLCAua2VlcF9hbGwgPSBUUlVFKQpgYGAKCgpgYGB7cn0KIyBTdW1tYXJpemUgUmVnaW9ucwpyZWdpb25fUlRBX2FnZyA8LSByZWdpb25fUlRBICU+JQogIGdyb3VwX2J5KGNvdW50cnksIG51dHMsIHBlcmlvZCwgbnV0c19wZXJpb2QsIFlfdGFnKSAlPiUKICBzdW1tYXJpc2Uobl9zcGVjID0gcnRhX2JpbiAlPiUgc3VtKG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG5fc3BlY19jb3VudCA9IChuX3RlY2hfcmVnaW9uICogcnRhX2JpbikgJT4lIHN1bShuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBISEkgPSBzdW0oKG5fdGVjaF9yZWdpb24vc3VtKG5fdGVjaF9yZWdpb24pICogMTAwKV4yKSApICU+JQogIHVuZ3JvdXAoKSAKYGBgCgpgYGB7cn0KIyBEYXRhZnJhbWUgd2l0aCByZWdpb25zIGFuZCB0ZWNobm9sb2d5IGZpZWxkcwp0ZWNoX2RldiA8LSByZWdpb25fUlRBICU+JQogIHNlbGVjdChjb3VudHJ5LCBwZXJpb2QsIG51dHMsIG51dHNfcGVyaW9kLCBpc2ljNF9sMywgWV90YWcsIG5fdGVjaF9yZWdpb24sIHJ0YSwgcnRhX2JpbikgJT4lCiAgYXJyYW5nZShjb3VudHJ5LCBudXRzLCBpc2ljNF9sMywgWV90YWcsIHBlcmlvZCkgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSwgbnV0cywgaXNpYzRfbDMsIFlfdGFnKSAlPiUKICBtdXRhdGUobl90ZWNoX3JlZ2lvbl9sYWcgPSBsYWcobl90ZWNoX3JlZ2lvbiwgMSksCiAgICAgICAgIG5fdGVjaF9yZWdpb25fZGVsdGEgPSBuX3RlY2hfcmVnaW9uIC0gbl90ZWNoX3JlZ2lvbl9sYWcsCiAgICAgICAgIHBjdF90ZWNoX3JlZ2lvbl9kZWx0YSA9IChuX3RlY2hfcmVnaW9uIC0gbl90ZWNoX3JlZ2lvbl9sYWcpIC8gKCBuX3RlY2hfcmVnaW9uX2xhZyArIDEpLAogICAgICAgICBydGFfbGFnID0gbGFnKHJ0YSwgMSksCiAgICAgICAgIHJ0YV9kZWx0YSA9IHJ0YSAtIHJ0YV9sYWcsCiAgICAgICAgIHJ0YV9iaW5fbGFnID0gbGFnKHJ0YV9iaW4sIDEpLAogICAgICAgICBydGFfYmluX2RlbHRhID0gcnRhX2JpbiAtIHJ0YV9iaW5fbGFnKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZShjb3VudHJ5LCBudXRzLCBpc2ljNF9sMywgWV90YWcsIHBlcmlvZCkgCmBgYAoKIyBQYXRlbnQgYXBwbGljYXRpb24gZGV2ZWxvcG1lbnQKCiogSW4gdGhlIGZvbGxvd2luZywgYSBicmllZiBkZXNjcmlwdGl2ZSBhbmFseXNpcyBvZiB0aGUgZGV2ZWxvcG1lbnQgb2YgZ3JlZW4gYW5kIG5vbi1ncmVlbiBwYXRlbnQgYXBwbGljYXRpb24gaW4gdGhlIE5vcmRpY3MKKiBJbiBhZGRpdGlvbiwgYSBicmVhY2tkb3duIG9mIGdyZWVuIHBhdGVudHMgYnkgdG9wIGdyZWVuIHBhdGVudGluZyByZWdpb25zCgpgYGB7cn0KZGF0YV9hcHBsbiAlPiUKICBzZW1pX2pvaW4oYXBwbG5faW52dF9ub3JkaWMsIGJ5ID0gJ2FwcGxuX2lkJykgJT4lCiAgbXV0YXRlKFlfdGFnID0gaWZlbHNlKFlfdGFnID09IFRSVUUsICdHcmVlbicsICdOb24tR3JlZW4nKSkgJT4lCiAgZmlsdGVyKGFwcGxuX2ZpbGluZ195ZWFyIDw9IDIwMTUsIGFwcGxuX2ZpbGluZ195ZWFyID49IDE5ODUpICU+JQogIGNvdW50KGFwcGxuX2ZpbGluZ195ZWFyLCBZX3RhZykgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYXBwbG5fZmlsaW5nX3llYXIsIHkgPSBuLCBjb2wgPSBZX3RhZykpICsgCiAgZ2VvbV9saW5lKGtleV9nbHlwaCA9ICJ0aW1lc2VyaWVzIikgKwogIGxhYnMoI3RpdGxlID0gJ1BhdGVudCBhcHBsaWNhdGlvbnM6IERldmVsb3BtZW50JywKICAgICAgICNzdWJ0aXRsZSA9ICdBbGwgTm9yZGljIGNvbnRyaWVzLCBieSBZIHRhZycsCiAgICAgICB4ID0gJ1llYXInLAogICAgICAgeSA9ICdOdW1iZXIgYXBwbGljYXRpb25zJywKICAgICAgIGNvbCA9ICdHcmVlbicpCmBgYAohISBUT0RPIEFESlVTVCBGT1IgQ09VTlJUWSEKCmBgYHtyfQpkYXRhX3BlcnNfYXBwbG4gJTw+JQogIGlubmVyX2pvaW4oZGF0YV9hcHBsbiAlPiUgc2VsZWN0KGFwcGxuX2lkLCBhcHBsbl9maWxpbmdfeWVhciksIGJ5ID0gJ2FwcGxuX2lkJykKYGBgCgoKYGBge3J9CmRhdGFfcGVyc19hcHBsbiAlPiUKICBmaWx0ZXIobnV0cyAlaW4lIHNlbGVjdF9yZWdpb24pICU+JQogIG11dGF0ZShZX3RhZyA9IGlmZWxzZShZX3RhZyA9PSBUUlVFLCAnR3JlZW4nLCAnTm9uLUdyZWVuJykpICU+JQogIGZpbHRlcihhcHBsbl9maWxpbmdfeWVhciA8PSAyMDE1LCBhcHBsbl9maWxpbmdfeWVhciA+PSAxOTg1KSAlPiUKICBjb3VudChhcHBsbl9maWxpbmdfeWVhciwgbnV0cywgWV90YWcsIHd0ID0gcGVyc19mcmFjKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhcHBsbl9maWxpbmdfeWVhciwgeSA9IG4sIGNvbCA9IG51dHMpKSArIAogIGdlb21fbGluZShrZXlfZ2x5cGggPSAidGltZXNlcmllcyIpICsKICBmYWNldF93cmFwKHZhcnMoWV90YWcpLCBzY2FsZXMgPSAnZnJlZScpICsKICBsYWJzKCN0aXRsZSA9ICdQYXRlbnQgYXBwbGljYXRpb25zOiBEZXZlbG9wbWVudCcsCiAgICAgICAjc3VidGl0bGUgPSAnQWxsIE5vcmRpYyBjb3VudHJpZXMnLAogICAgICAgeCA9ICdZZWFyJywKICAgICAgIHkgPSAnTnVtYmVyIGFwcGxpY2F0aW9ucywgYnkgcmVnaW9uIGFuZCBZIHRhZycsCiAgICAgICBjb2wgPSAnTnV0czMnKQpgYGAKCgpgYGB7cn0KZGF0YV9wZXJzX2FwcGxuICU+JQogIGZpbHRlcihwZXJzb25fY3RyeV9jb2RlICVpbiUgc2VsZWN0X2NvdW50cnkpICU+JQogIG11dGF0ZShZX3RhZyA9IGlmZWxzZShZX3RhZyA9PSBUUlVFLCAnR3JlZW4nLCAnTm9uLUdyZWVuJykpICU+JQogIGZpbHRlcihhcHBsbl9maWxpbmdfeWVhciA8PSAyMDE1LCBhcHBsbl9maWxpbmdfeWVhciA+PSAxOTg1KSAlPiUKICBjb3VudChhcHBsbl9maWxpbmdfeWVhciwgcGVyc29uX2N0cnlfY29kZSwgWV90YWcsIHd0ID0gcGVyc19mcmFjKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBhcHBsbl9maWxpbmdfeWVhciwgeSA9IG4sIGNvbCA9IHBlcnNvbl9jdHJ5X2NvZGUpKSArIAogIGdlb21fbGluZShrZXlfZ2x5cGggPSAidGltZXNlcmllcyIpICsKICBmYWNldF93cmFwKHZhcnMoWV90YWcpLCBzY2FsZXMgPSAnZnJlZScpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nKSArIAogIGxhYnMoI3RpdGxlID0gJ1BhdGVudCBhcHBsaWNhdGlvbnM6IERldmVsb3BtZW50IGJ5IGNvdW50cnknLAogICAgICAgI3N1YnRpdGxlID0gJ0FsbCBOb3JkaWMgY29udHJpZXMnLAogICAgICAgeCA9ICdZZWFyJywKICAgICAgIHkgPSAnTnVtYmVyIGFwcGxpY2F0aW9ucywgYnkgcmVnaW9uIGFuZCBZIHRhZycsCiAgICAgICBjb2wgPSAnQ291bnRyeScpCgojZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfMy5qcGVnIiwgZHBpID0gMzAwKQojZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfMy5lcHMiKQpgYGAKCiMgQXBwbGljYW50cwoKKiBBcHBsaWNhbnRzIG9mIHBhdGVudHMgZmlsZWQgYnkgaW52ZW50b3JzIGluIHRoZSBOb3JkaWNzCiogVGhhdCBjYW4gYmUgZG9tZXN0aWMgb3IgZm9yZWlnbiBhcHBsaWNhbnRzCgpgYGB7cn0KcmVnaW9uX2FwcGx0X2FwcGxuICU8PiUKICBsZWZ0X2pvaW4ocmVnaW9uX2FwcGx0ICU+JSBzZWxlY3QocGVyc29uX2lkLCBoYW5faWQsIGhhbl9uYW1lLCBwZXJzb25fY3RyeV9jb2RlLCBudXRzKSwgYnkgPSAncGVyc29uX2lkJykgJT4lCiAgbGVmdF9qb2luKGRhdGFfYXBwbG4gJT4lIHNlbGVjdChhcHBsbl9pZCwgZG9jZGJfZmFtaWx5X2lkLCBhcHBsbl9maWxpbmdfeWVhciwgcGVyaW9kKSwgYnkgPSAnYXBwbG5faWQnKSAlPiUKICBsZWZ0X2pvaW4oZGF0YV9hcHBsbl9pc2ljICU+JSBzZWxlY3QoZG9jZGJfZmFtaWx5X2lkLCBpc2ljNF9sMywgaXNpY19mcmFjKSAlPiUgbmVzdChpc2ljID0gYyhpc2ljNF9sMywgaXNpY19mcmFjKSksIGJ5ID0gJ2RvY2RiX2ZhbWlseV9pZCcpICU+JQogIGRyb3BfbmEoKQpgYGAKCgpgYGB7cn0KIyBMaXN0IG1haW4gYXBwbGljYW50cwphcHBsdF9zdGF0cyA8LSByZWdpb25fYXBwbHRfYXBwbG4gJT4lCiAgZmlsdGVyKHBlcnNvbl9jdHJ5X2NvZGUgJWluJSBzZWxlY3RfY291bnRyeSkgJT4lCiAgZ3JvdXBfYnkoaGFuX2lkLCBoYW5fbmFtZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgbl9wYXQgPSBzdW0oYXBwbHRfZnJhYyksCiAgICBuX1kgPSBzdW0oYXBwbHRfZnJhYyAqIFlfdGFnKSwKICAgIGZpcnN0X3BhdCA9IG1pbihhcHBsbl9maWxpbmdfeWVhcikKICAgICkgJT4lCiAgbXV0YXRlKHNoYXJlX1kgPSBuX1kgLyBuX3BhdCwKICAgICAgICAgYWdlID0gMjAxNiAtIGZpcnN0X3BhdCwKICAgICAgICAgaW5jdW1iYW50ID0gYWdlID49IDEwICYgbl9wYXQgPj0gMTApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBhcnJhbmdlKGRlc2Mobl9wYXQpKQpgYGAKCmBgYHtyfQphcHBsdF9zdGF0cyAlPiUgaGVhZCgyMDApCmBgYAoKYGBge3J9CmFwcGx0X3N0YXRzICU+JSBhcnJhbmdlKGRlc2Mobl9ZKSkgJT4lIGhlYWQoMTAwKQpgYGAKCmBgYHtyfQojIFNoYXJlIG9mIGluY3VtYmFudHMgYnkgdGVjaG5vbG9neQpyZWdpb25fdGVjaG5faW5jdW1iIDwtIHJlZ2lvbl9hcHBsdF9hcHBsbiAlPiUgCiAgZmlsdGVyKHBlcnNvbl9jdHJ5X2NvZGUgJWluJSBzZWxlY3RfY291bnRyeSkgJT4lCiAgbGVmdF9qb2luKGFwcGx0X3N0YXRzICU+JSBzZWxlY3QoaGFuX2lkLCBpbmN1bWJhbnQpLCBieSA9ICdoYW5faWQnKSAlPiUKICB1bm5lc3QoaXNpYykgJT4lCiAgbXV0YXRlKG5fd2VpZ2h0ID0gaXNpY19mcmFjICogYXBwbHRfZnJhYykgJT4lCiAgZ3JvdXBfYnkobnV0cywgaXNpYzRfbDMsIHBlcmlvZCwgWV90YWcpICU+JQogIHN1bW1hcmlzZShuID0gc3VtKG5fd2VpZ2h0KSwKICAgICAgICAgICAgbl9pbmMgPSBzdW0obl93ZWlnaHQgKiBpbmN1bWJhbnQpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHNoYXJlX2luYyA9IG5faW5jIC8gbikKYGBgCgojIFkgVEFncwoKYGBge3J9CmRhdGFfZG9jZGJfZmFtX2NwYyAlPiUgCiAgc2VtaV9qb2luKGFwcGxuX2ludnRfbm9yZGljLCBieSA9ICdkb2NkYl9mYW1pbHlfaWQnKSAlPiUKICBmaWx0ZXIoWV90YWcgPT0gVFJVRSkgJT4lCiAgbXV0YXRlKGNwY19jbGFzc19zeW1ib2wgPSBjcGNfY2xhc3Nfc3ltYm9sICU+JSBzdHJfc3ViKDEsNCkpICU+JQogIGNvdW50KGNwY19jbGFzc19zeW1ib2wsIHNvcnQgPSBUUlVFKQpgYGAKCgoKIyBUZWNobm9sb2d5IHNwYWNlIGdlbmVyYWwKCiogV2UgY2FsY3VsYXRlIHRoZSByZWxhdGVkbmVzcyBvZiBpbmR1c3RyaWVzIGJ5IGNvLW9jY3VyZW5jZSBwYXR0ZXJuIGZvbGxvd2luZyBIaWRhbGdvICYgSGF1c21hbm4gKDIwMDcpCiogUmV2ZWFsZWQgdGVjaG5vbG9naWNhbCBhZHZhbnRhZ2UgKFJUQSkgSXMgc2VwcGVyYXRlZGx5IGNhbGN1bGF0ZWQgZm9yIFktdGFnIGFuZCBub24tWS10YWcgcGF0ZW50cy4KCmBgYHtyfQpzZXQuc2VlZCgxMzM3KQpjb29yZHNfdGVjaCA8LSBnX3RlY2ggJT4lIGlncmFwaDo6bGF5b3V0LmZydWNodGVybWFuLnJlaW5nb2xkKCkgJT4lIGFzX3RpYmJsZSgpCmNvbG5hbWVzKGNvb3Jkc190ZWNoKSA8LSBjKCJ4IiwgInkiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9IDE1fQpnX3RlY2ggJU4+JQogIG11dGF0ZShpc2ljNF9sM19uYW1lID0gaXNpYzRfbDNfbmFtZSAlPiUgc3RyX3RydW5jKDUwLCBzaWRlID0gJ3JpZ2h0JykpICU+JQogIGdncmFwaChsYXlvdXQgPSAgY29vcmRzX3RlY2gpICsgCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKHdpZHRoID0gd2VpZ2h0LCBhbHBoYSA9IHdlaWdodCksIGNvbG91ciA9ICJncmV5IikgKyAKICBnZW9tX25vZGVfcG9pbnQoYWVzKGNvbG91ciA9IGlzaWM0X2wxX25hbWUsIHNpemUgPSBkZ3IpKSArIAogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IGlzaWM0X2wzX25hbWUsIHNpemUgPSBkZ3IsIGZpbHRlciA9IHBlcmNlbnRfcmFuayhkZ3IpID49IDAuOTAgKSwgcmVwZWwgPSBUUlVFKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnYm90dG9tJywKICAgICAgICBsZWdlbmQuYm94ID0gInZlcnRpY2FsIikgKwogIGxhYnMoY29sID0gJ0lTSUMgUmV2LjQgZ3JvdXAnCiAgICAgICAgICN0aXRsZSA9ICdJbmR1c3RyeSBTcGFjZSAoYWxsIE5vcmRpY3MpJywKICAgICAgICNzdWJ0aXRsZSA9ICdOb2RlcyA9IE5BQ0UgMiBJbmR1c3RyaWVzLiBFZGdlczogUmVsYXRlZG5lc3MnCiAgICApCgojZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfOS5qcGVnIiwgZHBpID0gMzAwKQojZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfOS5lcHMiKQpgYGAKCiMgUmVnaW9uYWwgc3BlY2lhbGl6YXRpb24gKFJUQSkgZGV2ZWxvcG1lbnQKCiogQ29tcGFyaXNvbiBvZiBzcGVjaWFsaXphdGlvbiBwcm92aWRlcyBpbiBwZXJpb2QgMSBhbmQgMgoKYGBge3J9CnAxIDwtIHJlZ2lvbl9SVEFfYWdnICAlPiUKICBmaWx0ZXIobnV0cyAlaW4lIHNlbGVjdF9yZWdpb24pICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZX3RhZywgdmFsdWVzX2Zyb20gPSBjKG5fc3BlYywgbl9zcGVjX2NvdW50LCBISEkpLCB2YWx1ZXNfZmlsbCA9IDAsIG5hbWVzX3ByZWZpeCA9ICdZX3RhZ18nKSAKCnAyIDwtIHAxICU+JSAKICBzZWxlY3QocGVyaW9kLCBudXRzLCBuX3NwZWNfWV90YWdfRkFMU0UsIG5fc3BlY19ZX3RhZ19UUlVFKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcGVyaW9kLCB2YWx1ZXNfZnJvbSA9IGMobl9zcGVjX1lfdGFnX0ZBTFNFLCBuX3NwZWNfWV90YWdfVFJVRSkpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0gNy41LCBmaWcuaGVpZ2h0PTcuNX0KcDEgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbl9zcGVjX1lfdGFnX0ZBTFNFLCB5ID0gbl9zcGVjX1lfdGFnX1RSVUUpKSArCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IG5fc3BlY19jb3VudF9ZX3RhZ19UUlVFLCBjb2wgPSBISElfWV90YWdfVFJVRSkpICsKICBnZW9tX3NlZ21lbnQoZGF0YSA9IHAyLCAKICAgICAgICAgICAgICAgYWVzKHggPSBuX3NwZWNfWV90YWdfRkFMU0VfMSwKICAgICAgICAgICAgICAgICAgIHkgPSBuX3NwZWNfWV90YWdfVFJVRV8xLAogICAgICAgICAgICAgICAgICAgeGVuZCA9IG5fc3BlY19ZX3RhZ19GQUxTRV8yLAogICAgICAgICAgICAgICAgICAgeWVuZCA9IG5fc3BlY19ZX3RhZ19UUlVFXzIsCiAgICAgICAgICAgICAgICAgICBzaXplID0gMC43NSksCiAgICAgICAgICAgICAgIGFscGhhID0gMC4xNSwKICAgICAgICAgICAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuNSwgImNtIiksIHR5cGUgPSAiY2xvc2VkIiksCiAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gbnV0cyksIGJveC5wYWRkaW5nID0gMC41LCBtYXgub3ZlcmxhcHMgPSBJbmYpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gInNreWJsdWUiLCBtaWQgPSAneWVsbG93JywgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDEpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygyLCAxMCkpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScpICsgCiAgbGFicygjdGl0bGUgPSAnRGV2ZWxvcG1lbnQgb2YgbmV3IHJlZ2lvbmFsIHNwZWNpYWxpemF0aW9ucycsIAogICAgICAgI3N1YnRpdGxlID0gJ0J5IG51bWJlciBvZiBncmVlbiBhbmQgbm9uIGdyZWVuIHNwZWNpYWxpemF0aW9ucyBpbiBwZXJpb2QgMSBhbmQgMicsCiAgICAgICB4ID0gJ04gbm9uLWdyZWVuIHNwZWNpYWxpemF0aW9ucycsCiAgICAgICB5ID0gJ04gZ3JlZW4gc3BlY2lhbGl6YXRpb25zJywKICAgICAgIHNpemUgPSAnTiBncmVlbiBwYXRlbnRzJywKICAgICAgIGNvbCA9ICdISEkgZ3JlZW4gcGF0ZW50cycpIAoKIyBnZ3NhdmUoIi4uL291dHB1dC9wYXBlcl9maWdzL2ZpZ180LmpwZWciLCBkcGkgPSAzMDApCiNnZ3NhdmUoIi4uL291dHB1dC9wYXBlcl9maWdzL2ZpZ180LmVwcyIpCgpybShwMSwgcDIpCmBgYAoKCiMgQW5hbHlzaXMgZm9yIGV4aXN0aW5nIGdyZWVuIHBhdGhzOgoKTk9URTogbmV3IHBhdGVudHMgaW4gc3BlY2lhbGl6YXRpb25zPyAKCmBgYHtyfQp0ZWNoX3JlbF9kZXYgPC0gdGVjaF9yZWwgJT4lIAogIHNlbGVjdChmcm9tLCB0bywgd2VpZ2h0KSAlPiUKICBpbm5lcl9qb2luKHRlY2hfZGV2ICU+JSBkaXN0aW5jdChpc2ljNF9sMywgbnV0cyksIGJ5ID0gYygnZnJvbScgPSAnaXNpYzRfbDMnKSkgJT4lCiAgIyBmaWx0ZXIgZm9yIHJ0YSBpbiBwZXJpb2QgMQogIGlubmVyX2pvaW4odGVjaF9kZXYgJT4lIGZpbHRlcihwZXJpb2QgPT0gJzEnLCBydGFfYmluID09IDEpICU+JSBkaXN0aW5jdChpc2ljNF9sMywgbnV0cywgWV90YWcpLCBieSA9IGMoJ3RvJyA9ICdpc2ljNF9sMycsICdudXRzJykpICU+JQogICMgZmlsdGVyIGZvciBuZXcgZ3JlZW4gc3BlY2lhbGl6YXRpb24gaW4gcGVyaW9kIDIKICBzZW1pX2pvaW4odGVjaF9kZXYgJT4lIGZpbHRlcihwZXJpb2QgPT0gJzInLCBydGFfYmluID09IDEsIHJ0YV9iaW5fZGVsdGEgPT0gMSwgWV90YWcgPT0gVFJVRSksIGJ5ID0gYygnZnJvbScgPSAnaXNpYzRfbDMnLCAnbnV0cycpKSAlPiUKICByZW5hbWUoaXNpYzRfbDM9IGZyb20sIHJlbGF0ZWRfdGVjaG4gPSB0bykgCmBgYAoKYGBge3IsIGZpZy53aWR0aD0gNy41LCBmaWcuaGVpZ2h0PTcuNX0KcDEgPC0gdGVjaF9yZWxfZGV2ICU+JQogIGdyb3VwX2J5KG51dHMsIGlzaWM0X2wzLCBZX3RhZykgJT4lCiAgc3VtbWFyaXNlKHJlbF9tYXggPSB3ZWlnaHQgJT4lIG1heCgpLAogICAgICAgICAgICByZWxfc3VtID0gd2VpZ2h0ICU+JSBzdW0oKSwKICAgICAgICAgICAgcmVsX21lYW4gPSB3ZWlnaHQgJT4lIG1lYW4oKSkgJT4lCiAgdW5ncm91cCgpICU+JQogICMKICBncm91cF9ieShudXRzLCBZX3RhZykgJT4lCiAgc3VtbWFyaXNlKHJlbCA9IHJlbF9tYXggJT4lIG1lYW4oKSkgJT4lCiAgdW5ncm91cCgpICU+JQogICMKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWV90YWcsIHZhbHVlc19mcm9tID0gcmVsLCBuYW1lc19wcmVmaXggPSAnWV8nLCB2YWx1ZXNfZmlsbCA9IDApICU+JQogIGxlZnRfam9pbih0ZWNoX2RldiAlPiUgZmlsdGVyKFlfdGFnID09IFRSVUUsIHBlcmlvZCA9PSAnMicsIHJ0YV9iaW5fZGVsdGEgPT0gMSkgJT4lIHNlbGVjdChudXRzICwgbl90ZWNoX3JlZ2lvbikgJT4lIGNvdW50KG51dHMsIHd0ID0gbl90ZWNoX3JlZ2lvbiksIGJ5ID0gYygnbnV0cycpKSAlPiUKICBtdXRhdGUoY291bnRyeSA9IG51dHMgJT4lIHN0cl9zdWIoMSwyKSkgCgp4X21pZCA8LSBtZWFuKHAxJFlfRkFMU0UsIG5hLnJtID0gVFJVRSkKeV9taWQgPC0gbWVhbihwMSRZX1RSVUUsIG5hLnJtID0gVFJVRSkKCnAxICU+JQogIGZpbHRlcihjb3VudHJ5ICVpbiUgc2VsZWN0X2NvdW50cnksCiAgICAgICAgIDAuNSA8PSBwZXJjZW50X3JhbmsobikpICU+JQogIGdncGxvdChhZXMoeCA9IFlfRkFMU0UsIHkgPSBZX1RSVUUsIHNpemUgPSBuKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHhfbWlkLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICdncmV5JykgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSB5X21pZCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAnZ3JleScpICsKICBnZW9tX3BvaW50KGFlcyhjb2wgPSBjb3VudHJ5KSkgKwogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBudXRzKSwgYm94LnBhZGRpbmcgPSAwLjUsIG1heC5vdmVybGFwcyA9IEluZikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikgKyAKICAgIGxhYnMoI3RpdGxlID0gJ05ldyBncmVlbiBzcGVjaWFsaXphdGlvbiBwZXJpb2QgMicsIAogICAgICAgI3N1YnRpdGxlID0gJ0J5IG51dHMgcmVnaW9ucycsCiAgICAgICAjbm90ZSA9ICdSZWxhdGVkbmVzcyBpcyB0aGUgbWVhbiBvdmVyIGFsbCBuZXcgZ3JlZW4gc3BlY2lhbGl6YXRpb25zLCBwZXIgZ3JlZW4gc3BlY2lhbGl6YXRpb24gbGFyZ2VzdCByZWxhdGVkbmVzcyB0byBmb3JtZXIgc3BlY2lhbGl6YXRpb24gY291bnRlZCcsCiAgICAgICB4ID0gJ1JlbGF0ZWRuZXNzIG5vbi1ncmVlbicsCiAgICAgICB5ID0gJ1JlbGF0ZWRuZXNzIGdyZWVuJywKICAgICAgIHNpemUgPSAnTiBncmVlbiBwYXRlbnRzJykgCgojZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfNS5qcGVnIiwgZHBpID0gMzAwKQojZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfNS5lcHMiKQoKcm0ocDEsIHhfbWlkLCB5X21pZCkKYGBgCgoKYGBge3J9CmxpYnJhcnkocmVnaW9ucykKZGF0YShudXRzX2NoYW5nZXMpCmxpc3RfbnV0cyA8LSBudXRzX2NoYW5nZXMgJT4lIHNlbGVjdChjb2RlXzIwMjEsIGdlb19uYW1lXzIwMjEpIApjb2xuYW1lcyhsaXN0X251dHMpIDwtIGMoJ251dHMnLCAnbnV0c19uYW1lJykKCmxpc3RfbnV0c19hZGQgPC0gdGliYmxlKAogIG51dHMgPSBjKCdOTzAxMScsICdOTzAxMicsICdOTzAyMScsICdOTzAyMicsICdOTzAzMScsICdOTzAzMicsICdOTzAzMycsICdOTzAzNCcsICdOTzA0MScsICdOTzA0MicsICdOTzA0MycsICdOTzA1MScsICdOTzA1MicsICdOTzA1MycsICdOTzA2MScsICdOTzA2MicsICdOTzA3MScsICdOTzA3MicsICdOTzA3MycpLAogIG51dHNfbmFtZSA9IGMoJ09zbG8nLCAnQWtlcnNodXMnLCAnSGVkbWFyaycsICdPcHBsYW5kJywgJ8OYc3Rmb2xkJywgJ0J1c2tlcnVkJywgJ1Zlc3Rmb2xkJywgJ1RlbGVtYXJrJywgJ0F1c3QtQWdkZXInLCAnVmVzdC1BZ2RlcicsICdSb2dhbGFuZCcsICdIb3JkYWxhbmQnLCAnU29nbiBvZyBGam9yZGFuZScsICdNw7hyZSBvZyBSb21zZGFsJywgJ1PDuHItVHLDuG5kZWxhZycsICdOb3JkLVRyw7huZGVsYWcnLCAnTm9yZGxhbmQnLCAnVHJvbXMnLCAnRmlubm1hcmsnKQopCgpsaXN0X251dHMgJTw+JSBiaW5kX3Jvd3MobGlzdF9udXRzX2FkZCkKYGBgCgoKYGBge3J9Cmxpc3RfaXNpYyAlPiUKICBmaWx0ZXIobGV2ZWwgPT0zKSAlPiUKICAgIHNlbGVjdChpc2ljNF9sMSwgaXNpYzRfbDMsIGlzaWM0X2w0X25hbWUsIGlzaWM0X2wxX25hbWUpIApgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwfQpwMSA8LSB0ZWNoX3JlbF9kZXYgJT4lCiAgZ3JvdXBfYnkobnV0cywgaXNpYzRfbDMsIFlfdGFnKSAlPiUKICBzdW1tYXJpc2UocmVsID0gd2VpZ2h0ICU+JSBtYXgoKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZX3RhZywgdmFsdWVzX2Zyb20gPSByZWwsIG5hbWVzX3ByZWZpeCA9ICdZXycsIHZhbHVlc19maWxsID0gMCkgJT4lCiAgbGVmdF9qb2luKHRlY2hfZGV2ICU+JSAKICAgICAgICAgICAgICBmaWx0ZXIoWV90YWcgPT0gVFJVRSwgcGVyaW9kID09ICcyJywgcnRhX2Jpbl9kZWx0YSA9PSAxKSAlPiUgCiAgICAgICAgICAgICAgY291bnQobnV0cywgaXNpYzRfbDMsIHd0ID0gbl90ZWNoX3JlZ2lvbiksIAogICAgICAgICAgICBieSA9IGMoJ251dHMnLCAnaXNpYzRfbDMnKSkgJT4lCiAgbXV0YXRlKGNvdW50cnkgPSBudXRzICU+JSBzdHJfc3ViKDEsMikpICU+JQogIGxlZnRfam9pbihsaXN0X2lzaWMgICU+JXNlbGVjdChpc2ljNF9sMywgaXNpYzRfbDNfbmFtZSwgaXNpYzRfbDFfbmFtZSkgJT4lIGRpc3RpbmN0KCksIGJ5ID0gJ2lzaWM0X2wzJykgJT4lCiAgbGVmdF9qb2luKGxpc3RfbnV0cyAlPiUgZGlzdGluY3QoKSwgYnkgPSAnbnV0cycpICU+JSAKICBtdXRhdGUobnV0c19uYW1lID0gcGFzdGUobnV0cywgbnV0c19uYW1lLCBzZXAgPSAnOiAnKSApCgp4X21pZCA8LSBtZWFuKHAxJFlfRkFMU0UsIG5hLnJtID0gVFJVRSkKeV9taWQgPC0gbWVhbihwMSRZX1RSVUUsIG5hLnJtID0gVFJVRSkKCiMgcGxvdHRpbmcKcDEgJT4lCiAgZmlsdGVyKG51dHMgJWluJSBzZWxlY3RfcmVnaW9uKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBZX0ZBTFNFLCB5ID0gWV9UUlVFLCBzaXplID0gbiwgY29sID0gaXNpYzRfbDFfbmFtZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBpc2ljNF9sMyksIGJveC5wYWRkaW5nID0gMC41KSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0geF9taWQsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gJ2dyZXknKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IHlfbWlkLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICdncmV5JykgKwogIGZhY2V0X3dyYXAodmFycyhudXRzX25hbWUpLCBuY29sID0gbl9yZWdpb25zKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScsCiAgICAgICAgbGVnZW5kLmJveCA9ICJ2ZXJ0aWNhbCIpICsKICBsYWJzKCN0aXRsZSA9ICdOZXcgZ3JlZW4gc3BlY2lhbGl6YXRpb24gcGVyaW9kIDInLCAKICAgICAgICNzdWJ0aXRsZSA9ICdCeSBudXRzIHJlZ2lvbnMnLAogICAgICAgI25vdGUgPSAnUmVsYXRlZG5lc3MgaXMgdGhlIG1lYW4gb3ZlciBhbGwgbmV3IGdyZWVuIHNwZWNpYWxpemF0aW9ucywgcGVyIGdyZWVuIHNwZWNpYWxpemF0aW9uIGxhcmdlc3QgcmVsYXRlZG5lc3MgdG8gZm9ybWVyIHNwZWNpYWxpemF0aW9uIGNvdW50ZWQnLAogICAgICAgeCA9ICdSZWxhdGVkbmVzcyBub24tZ3JlZW4nLAogICAgICAgeSA9ICdSZWxhdGVkbmVzcyBncmVlbicsCiAgICAgICBjb2wgPSAnSVNJQyBSZXYuNCcsCiAgICAgICBzaXplID0gJ04gZ3JlZW4gcGF0ZW50cycpIAoKIyBnZ3NhdmUoIi4uL291dHB1dC9wYXBlcl9maWdzL2ZpZ182LmpwZWciLCBkcGkgPSAzMDApCiMgZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfNi5lcHMiKQoKcm0ocDEsIHhfbWlkLCB5X21pZCkKYGBgCgohISEgTWFrZSBhZGRpdGlvIG5hbCBwbG90eSBpbmNsdWRpbmcgb2xkIGdyZWVuIHNwZWNpYWxpemF0aW9ucwoKIyBQcm9maWxpbmcgcmVnaW9ucwoKYGBge3J9CnBhdGhfZ3JlZW5fbmV3IDwtIHRlY2hfcmVsX2RldiAlPiUKICBncm91cF9ieShudXRzLCBpc2ljNF9sMywgWV90YWcpICU+JQogIHN1bW1hcmlzZShyZWwgPSB3ZWlnaHQgJT4lIG1heCgpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFlfdGFnLCB2YWx1ZXNfZnJvbSA9IHJlbCwgbmFtZXNfcHJlZml4ID0gJ1lfJywgdmFsdWVzX2ZpbGwgPSAwKSAlPiUKICBsZWZ0X2pvaW4odGVjaF9kZXYgJT4lIAogICAgICAgICAgICAgIGZpbHRlcihZX3RhZyA9PSBUUlVFLCBwZXJpb2QgPT0gJzInLCBydGFfYmluX2RlbHRhID09IDEpICU+JSAKICAgICAgICAgICAgICBzZWxlY3QobnV0cywgaXNpYzRfbDMsIG5fdGVjaF9yZWdpb24pICU+JSAKICAgICAgICAgICAgICBjb3VudChudXRzLCBpc2ljNF9sMywgd3QgPSBuX3RlY2hfcmVnaW9uKSwgCiAgICAgICAgICAgIGJ5ID0gYygnbnV0cycsICdpc2ljNF9sMycpKSAlPiUKICBtdXRhdGUoZ3JlZW5fcGF0aCA9IGNhc2Vfd2hlbiggCiAgICBZX0ZBTFNFIDw9IG1lYW4oWV9GQUxTRSkgJiBZX1RSVUUgPD0gbWVhbihZX1RSVUUpIH4gJ2NyZWF0aW9uJywKICAgIFlfRkFMU0UgPD0gbWVhbihZX0ZBTFNFKSAmIFlfVFJVRSA+IG1lYW4oWV9UUlVFKSB+ICdkaXZlcnNpZmljYXRpb24nLAogICAgWV9GQUxTRSA+IG1lYW4oWV9GQUxTRSkgJiBZX1RSVUUgPD0gbWVhbihZX1RSVUUpIH4gJ3JlbmV3YWwnLAogICAgWV9GQUxTRSA+IG1lYW4oWV9GQUxTRSkgJiBZX1RSVUUgPiBtZWFuKFlfVFJVRSkgfiAncmVuZXdhbCcKICAgICkgKSAlPiUKICBzZWxlY3QoLVlfRkFMU0UsIC0gWV9UUlVFKQpgYGAKCmBgYHtyfQpwYXRoX2dyZWVuIDwtIHRlY2hfZGV2ICU+JSAKICBtdXRhdGUoZ3JlZW5fcGF0aCA9IGNhc2Vfd2hlbiggCiAgICBZX3RhZyA9PSBUUlVFICYgcGVyaW9kID09ICcyJyAmIHJ0YV9iaW4gPT0gMSAmIHJ0YV9iaW5fZGVsdGEgPT0gMCAmIHBjdF90ZWNoX3JlZ2lvbl9kZWx0YSA8IDAuMSB+ICdzdGFnbmF0aW9uJywKICAgIFlfdGFnID09IFRSVUUgJiBwZXJpb2QgPT0gJzInICYgcnRhX2JpbiA9PSAxICYgcnRhX2Jpbl9kZWx0YSA9PSAwICYgcGN0X3RlY2hfcmVnaW9uX2RlbHRhID49IDAuMSB+ICdleHRlbnNpb24nLAogICAgWV90YWcgPT0gVFJVRSAmIHBlcmlvZCA9PSAnMicgJiBydGFfYmluID09IDAgJiBydGFfYmluX2RlbHRhID09IC0xIH4gJ2V4dGluY3Rpb24nCiAgKSkgJT4lCiAgZHJvcF9uYShncmVlbl9wYXRoKSAlPiUKICBzZWxlY3QobnV0cywgaXNpYzRfbDMsIG5fdGVjaF9yZWdpb25fZGVsdGEsIGdyZWVuX3BhdGgpICU+JQogIHJlbmFtZShuID0gbl90ZWNoX3JlZ2lvbl9kZWx0YSkgJT4lCiAgIyBhZGQgZXhpc3RpbmcgZ3JlZW4gcGF0aHMKICBiaW5kX3Jvd3MocGF0aF9ncmVlbl9uZXcpICU+JQogIG11dGF0ZShuID0gbiAlPiUgYWJzKCkpICU+JQogICMgYWRkIGluY3VtYmFudCBtZWFzdXJlcwogIGxlZnRfam9pbihyZWdpb25fdGVjaG5faW5jdW1iICU+JSBmaWx0ZXIocGVyaW9kID09ICcyJywgWV90YWcgPT0gVFJVRSkgJT4lIHNlbGVjdChudXRzLCBpc2ljNF9sMywgc2hhcmVfaW5jKSwgYnkgPSBjKCdudXRzJywgJ2lzaWM0X2wzJykpICU+JQogIG11dGF0ZShuX25ldyA9IG4gKiAoMSAtIHNoYXJlX2luYyksCiAgICAgICAgIG5faW5jID0gbiAqIHNoYXJlX2luYykKYGBgCgoqIEJlbG93IGEgcmFkYXIgcGxvdCBzdW1taW5nIGFsbCB1cC4KKiBJdCBpbmNsdWRlcyB0aGUgc2hhcmUgb2YgZ3JlZW4gcGF0ZW50cyBpbiBuYWNlIGdyb3VwcyBmb2xsbG93aW5nIGEgcGFydGljdWxhciBncmVlbiBwYXRoICh3aXRoaW4gYSBudXRzIHJlZ2lvbikKKiBDb2xvciBpbmRpY2F0ZXMgdGhlIHNoYXJlIG9mIGluY3VtYmVudHMgKCs1IHllYXJzLCArNTAgcGF0ZW50cykgaW4gdGhlIHBhdGguCiogQ2FuIGJlIHVzZWQgdG8gaWRlbnRpZnkgYSByZWdpb25zIG1haW4gcGF0aCBhbmQgb3ZlcmFsIHByb2ZpbGUuCgpUT0RPOiBJbmNyZWFzZSB0ZXh0IHNpemUKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTIuNX0KcGF0aF9ncmVlbiAlPiUKICBmaWx0ZXIobnV0cyAlaW4lIHNlbGVjdF9yZWdpb24pICU+JSAjLCBncmVlbl9wYXRoICE9ICdzdGFnbmF0aW9uJykgJT4lCiAgIyBzcGxpdCBieSBpbmMgYW5kIG5vbl9pbmN1bWJlbnRzCiAgcGl2b3RfbG9uZ2VyKGMobl9uZXcsIG5faW5jKSwgbmFtZXNfdG8gPSAnYXBwbHRfdHlwZScpICU+JSAKICAjIEFnZ3JlZ2F0ZQogIGNvdW50KG51dHMsIGdyZWVuX3BhdGgsIGFwcGx0X3R5cGUsIHd0ID0gdmFsdWUpICU+JQogIGNvbXBsZXRlKG51dHMsIGdyZWVuX3BhdGgsIGFwcGx0X3R5cGUsIGZpbGwgPSBsaXN0KCduJyA9ICAwKSkgJT4lCiAgIyBBZGQgb3ZlcmFsbCBwYXRlbnRzIGFuZGYgbWFrZSBzaGFyZQogIGxlZnRfam9pbihyZWdpb25fUlRBICU+JWZpbHRlcihwZXJpb2QgPT0gJzInKSAlPiUgIGNvdW50KG51dHMsIHd0ID0gbl9yZWdpb24sIG5hbWUgPSAnbl9yZWcnKSwgYnkgPSAnbnV0cycpICU+JQogIG11dGF0ZShuX3NoYXJlID0gbiApICU+JSAjLyBuX3JlZykgJT4lCiAgbGVmdF9qb2luKGxpc3RfbnV0cyAlPiUgZGlzdGluY3QoKSwgYnkgPSAnbnV0cycpICU+JSBtdXRhdGUobnV0c19uYW1lID0gcGFzdGUobnV0cywgbnV0c19uYW1lLCBzZXAgPSAnOiAnKSApICU+JQogICMgcGxvdHRpbmcKICBnZ3Bsb3QoKSArCiAgZ2VvbV9jb2woYWVzKHggPSBncmVlbl9wYXRoLCB5ID0gbl9zaGFyZSwgZmlsbCA9IGFwcGx0X3R5cGUpLCBhbHBoYSA9IDAuOCwgcG9zaXRpb249ICJzdGFjayIpICArIAogICMgTG9sbGlwb3Agc2hhZnQgCiAgI2dlb21fc2VnbWVudCggYWVzKHggPSBncmVlbl9wYXRoLCB5ID0gMCwgeGVuZCA9IGdyZWVuX3BhdGgsIHllbmQgPSAwLjAwMiksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImdyYXkxMiIpICsgCiAgIyBjb29yZF9wb2xhcigpICsKICAjIGNvb3JkX2ZsaXAoKSArIAogIGZhY2V0X3dyYXAodmFycyhudXRzX25hbWUpLCBuY29sID0gbl9yZWdpb25zLCBzY2FsZXMgPSAnZnJlZScpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCB2anVzdCA9IDEsIGhqdXN0PTEpKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nLAogICAgICAgIGxlZ2VuZC5ib3ggPSAidmVydGljYWwiKSArCiAgbGFicygjdGl0bGUgPSAnUmVnaW9uYWwgZ3JlZW4gcGF0aHMnLCAKICAgICAgICNzdWJ0aXRsZSA9ICdCeSBudXRzIHJlZ2lvbnMnLAogICAgICAgeCA9IE5VTEwsCiAgICAgICB5ID0gTlVMTCwKICAgICAgIHNpemUgPSAnU2hhcmUgZ3JlZW4gcGF0ZW50cycsCiAgICAgICBjb2wgPSAnR3JlZW4gcGF0aCB0eXBlJywKICAgICAgIGZpbGwgPSAnQXBwbGljYW50IHR5cGUnKSAKCiMjZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfNy5qcGVnIiwgZHBpID0gMzAwKQojIGdnc2F2ZSgiLi4vb3V0cHV0L3BhcGVyX2ZpZ3MvZmlnXzcuZXBzIikKYGBgCgpCcmVhayBkb3duIG1haW4gcGF0aCBpbmR1c3RyeQoKIyBHZW9wbG90dGluZwoKKiBJIGFsc28gYWRkZWQgYSBmaXJzdCBwbG90dGluZyBvZiBtYWluIGdyZWVuIHBhdGhzCiogV29ya3Mgd2VsbCwgc28gd2UgY2FuIGFkZHMgZnVydGhyIGdlb3Bsb3RzIGlmIG5lY2Vzc2FyeS4KCmBgYHtyfQojIFNlZTogaHR0cHM6Ly9yb3Blbmdvdi5naXRodWIuaW8vZ2lzY29SLyAKCiMgR2V0IG1hcCBvZiBub3JkaWNzCm1hcF9ub3JkaWMgPC0gZ2lzY29fZ2V0X251dHMoY291bnRyeSA9IGMoJ0ROSycsICdTV0UnLCAnTk9SJywgJ0ZJTicpLCBudXRzX2xldmVsID0gMywgeWVhciA9ICcyMDE2JykKCiMgZmlsdGVyIG91dCBTdmFsYmFydCBldGMKbWFwX25vcmRpYyAlPD4lCiAgZmlsdGVyKCEoTlVUU19JRCAlaW4lIGMoJ05PMEIxJywgJ05PMEIyJykpKQoKIyBHcm91cCBieSBOVVRTIGJ5IGNvdW50cnkgYW5kIGNvbnZlcnQgdG8gbGluZXMKY291bnRyeV9saW5lcyA8LSBtYXBfbm9yZGljICU+JQogIGdyb3VwX2J5KENOVFJfQ09ERSkgJT4lCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzdF9jYXN0KCJNVUxUSUxJTkVTVFJJTkciKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9OC41LCBmaWcuaGVpZ2h0PTcuNX0KbWFwX25vcmRpYyAlPiUKICAjIGVudGVyIG1haW4gZ3JlZW4gcGF0aAogIGxlZnRfam9pbihwYXRoX2dyZWVuICU+JSBjb3VudChudXRzLCBncmVlbl9wYXRoLCB3dCA9IG4pICU+JSBncm91cF9ieShudXRzKSAlPiUgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbiA9IDEsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUgdW5ncm91cCgpLCBieSA9IGMoJ05VVFNfSUQnID0gJ251dHMnKSkgJT4lCiAgIyBwbG90CiAgZ2dwbG90KCkgKyAKICBnZW9tX3NmKGFlcyhmaWxsID0gZ3JlZW5fcGF0aCkpICsKICBnZW9tX3NmKGRhdGEgPSBjb3VudHJ5X2xpbmVzLCBjb2wgPSAiYmx1ZSIsIGxpbmV3aWR0aCA9IDAuMSkgKyAKICB0aGVtZV92b2lkKCkgKwogIGxhYnMoI3RpdGxlID0gJ01hcDogTm9yZGljIG1haW4gZ3JlZW4gcGF0aHMnLCAKICAgICAgICNzdWJ0aXRsZSA9ICdCeSBudXRzIHJlZ2lvbnMnLAogICAgICAgI25vdGUgPSAnRXhjbHVkaW5nIE5PMEIxLE5PMEIyJywKICAgICAgIHggPSBOVUxMLAogICAgICAgeSA9IE5VTEwsCiAgICAgICBmaWxsID0gJ01haW4gZ3JlZW4gcGF0aCcpICMrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nKQoKIyBnZ3NhdmUoIi4uL291dHB1dC9wYXBlcl9maWdzL2ZpZ184LmpwZWciLCBkcGkgPSAzMDApCiMgZ2dzYXZlKCIuLi9vdXRwdXQvcGFwZXJfZmlncy9maWdfOC5lcHMiKQpgYGAKCiMgVGFibGVzCgpgYGB7cn0KIyBCYXNpY3MgTnIgcGF0ZW50cwp0YWJfYmFzaWMgPC0gdGVjaF9kZXYgJT4lCiAgZmlsdGVyKGNvdW50cnkgJWluJSBzZWxlY3RfY291bnRyeSwgCiAgICAgICAgIHBlcmlvZCA9PSAyKSAlPiUgCiAgY291bnQobnV0cywgWV90YWcsIHd0ID0gbl90ZWNoX3JlZ2lvbikgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFlfdGFnLCB2YWx1ZXNfZnJvbSA9IG4sIHZhbHVlc19maWxsID0gMCwgbmFtZXNfcHJlZml4ID0gJ1lfJykgJT4lCiAgbXV0YXRlKFlfRkFMU0UgPSByb3VuZChZX0ZBTFNFKSwgWV9UUlVFID0gcm91bmQoWV9UUlVFKSwKICAgICAgICAgWV9zaGFyZSA9IChZX1RSVUUgLyAoWV9GQUxTRSArIFlfVFJVRSkgICkgJT4lIHJvdW5kKDIpICApICU+JQogIGxlZnRfam9pbihsaXN0X251dHMgJT4lIGRpc3RpbmN0KCksIGJ5ID0gJ251dHMnKSAlPiUgbXV0YXRlKG51dHNfbmFtZSA9IHBhc3RlKG51dHMsIG51dHNfbmFtZSwgc2VwID0gJzogJykgKSAlPiUKICByZWxvY2F0ZShudXRzX25hbWUpCgojIEFwcGxpY2FudCAKdGFiX2FwcGx0IDwtIHJlZ2lvbl9hcHBsdF9hcHBsbiAlPiUKICBmaWx0ZXIocGVyc29uX2N0cnlfY29kZSAlaW4lIHNlbGVjdF9jb3VudHJ5LAogICAgICAgICBwZXJpb2QgPT0gMikgJT4lCiAgbGVmdF9qb2luKHJlZ2lvbl90ZWNoICU+JSBzZWxlY3QoYXBwbG5faWQsIG51dHMsIHdlaWdodF9mcmFjKSwgYnkgPSBjKCdhcHBsbl9pZCcsICdudXRzJykpICU+JQogIGNvdW50KG51dHMsIGhhbl9uYW1lLCBoYW5faWQsIFlfdGFnLCB3dCA9IHdlaWdodF9mcmFjKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWV90YWcsIHZhbHVlc19mcm9tID0gbiwgdmFsdWVzX2ZpbGwgPSAwLCBuYW1lc19wcmVmaXggPSAnWV8nKSAlPiUKICBtdXRhdGUoWV9GQUxTRSA9IHJvdW5kKFlfRkFMU0UpLCBZX1RSVUUgPSByb3VuZChZX1RSVUUpLAogICAgICAgICBZX3NoYXJlID0gKFlfVFJVRSAvIChZX0ZBTFNFICsgWV9UUlVFKSAgKSAlPiUgcm91bmQoMikpICU+JSAKICBncm91cF9ieShudXRzKSAlPiUKICBzbGljZV9tYXgob3JkZXJfYnkgPSBZX1RSVUUsIG4gPSAxLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGxlZnRfam9pbihhcHBsdF9zdGF0cyAlPiUgc2VsZWN0KGhhbl9pZCwgaW5jdW1iYW50KSAlPiUgbXV0YXRlKGluY3VtYmFudCA9IGlmZWxzZShpbmN1bWJhbnQgPT0gVFJVRSwgJ2luY3VtYi4nLCAnZW50cmFudCcpKSwgYnkgPSAnaGFuX2lkJykgJT4lCiAgbXV0YXRlKGFwcGxpY2FudCA9IHBhc3RlMChoYW5fbmFtZSwgJyAoJyxpbmN1bWJhbnQgLCcsIG4gZ3JlZW46ICcsIFlfVFJVRSwgJywgc2hhcmU6JywgWV9zaGFyZSwgJyknKSkgJT4lCiAgc2VsZWN0KG51dHMsIGFwcGxpY2FudCkKCnRhYl9pc2ljIDwtIHRlY2hfZGV2ICU+JSAKICBmaWx0ZXIoY291bnRyeSAlaW4lIHNlbGVjdF9jb3VudHJ5LAogICAgICAgICBwZXJpb2QgPT0gMiwgCiAgICAgICAgIFlfdGFnID09IFRSVUUpICU+JQogIGdyb3VwX2J5KG51dHMpICU+JQogIHNsaWNlX21heChvcmRlcl9ieSA9IG5fdGVjaF9yZWdpb24sIG4gPSAxLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZSh0b3BfWV9pc2ljID0gcGFzdGUwKGlzaWM0X2wzLCAnIChuICcsIG5fdGVjaF9yZWdpb24gJT4lIHJvdW5kKCksICcpJykpICU+JQogIHNlbGVjdChudXRzLCB0b3BfWV9pc2ljKQoKdGFiX2NwY19ZIDwtIGRhdGFfZG9jZGJfZmFtX2NwYyAlPiUKICBtdXRhdGUoY3BjX1kgPSBjcGNfY2xhc3Nfc3ltYm9sICU+JSBzdHJfc3ViKDEsNCkpICU+JQogIGRpc3RpbmN0KGRvY2RiX2ZhbWlseV9pZCwgY3BjX1ksIC5rZWVwX2FsbCA9IFRSVUUpICU+JQogIGZpbHRlcihjcGNfWSAlPiUgc3RyX3N0YXJ0cygnWTAyJykgfCBjcGNfWSAlPiUgc3RyX3N0YXJ0cygnWTA0JykpICU+JQogIGNvdW50KGRvY2RiX2ZhbWlseV9pZCwgY3BjX1ksIHd0ID0gY3BjX2ZyYWMsIG5hbWUgPSAnd2VpZ2h0X2NwYycpICU+JQogIGlubmVyX2pvaW4oZGF0YV9hcHBsbiAlPiUgZGlzdGluY3QoYXBwbG5faWQsIGRvY2RiX2ZhbWlseV9pZCksIGJ5ID0gJ2RvY2RiX2ZhbWlseV9pZCcpICU+JQogIGlubmVyX2pvaW4oZGF0YV9wZXJzX2FwcGxuICU+JSBmaWx0ZXIocGVyc29uX2N0cnlfY29kZSAlaW4lIHNlbGVjdF9jb3VudHJ5KSAlPiUgc2VsZWN0KGFwcGxuX2lkLCBudXRzKSwgYnkgPSAnYXBwbG5faWQnKSAlPiUgCiAgY291bnQoY3BjX1ksIG51dHMsIHd0ID0gd2VpZ2h0X2NwYykgJT4lCiAgZ3JvdXBfYnkobnV0cykgJT4lCiAgc2xpY2VfbWF4KG9yZGVyX2J5ID0gbiwgbiA9IDEsIHdpdGhfdGllcyA9IEZBTFNFKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKHRvcF9ZX2NwYyA9IHBhc3RlMChjcGNfWSwgJyAobiAnLCBuICU+JSByb3VuZCgpLCAnKScpKSAlPiUKICBzZWxlY3QobnV0cywgdG9wX1lfY3BjKQogIAojIE5vdGU6IEl0cyBzaWxseSB0aGF0IG5vdCBhbGwgaXMgaW5kZXhlZCBieSBkb2NkYiBmYW1pbHkuLi4uIGNoYW5nZSBmb3IgbmV4dCB2ZXJzaW9uCiAgICAgICAgICAKdGFiX3BhdGhfcmVsIDwtIHBhdGhfZ3JlZW4gJT4lCiAgZmlsdGVyKHN0cl9zdWIobnV0cywgMSwyKSAlaW4lIHNlbGVjdF9jb3VudHJ5KSAlPiUKICBjb3VudChudXRzLCBncmVlbl9wYXRoLCB3dCA9IG4pICU+JQogIGdyb3VwX2J5KG51dHMpICU+JQogIG11dGF0ZShzaGFyZSA9IChuIC8gc3VtKG4pKSAlPiUgcm91bmQoMikgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KC1uKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gZ3JlZW5fcGF0aCwgdmFsdWVzX2Zyb20gPSBzaGFyZSwgbmFtZXNfcHJlZml4PSAnJSBwYXRoICcsIHZhbHVlc19maWxsID0gMCkgJT4lCiAgYXJyYW5nZShudXRzKQoKdGFiX3BhdGhfdG90YWwgPC0gcGF0aF9ncmVlbiAlPiUKICBmaWx0ZXIoc3RyX3N1YihudXRzLCAxLDIpICVpbiUgc2VsZWN0X2NvdW50cnkpICU+JQogIGNvdW50KG51dHMsIGdyZWVuX3BhdGgsIHd0ID0gbikgJT4lCiAgbXV0YXRlKG4gPSBuICU+JSByb3VuZCgpKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gZ3JlZW5fcGF0aCwgdmFsdWVzX2Zyb20gPSBuLCBuYW1lc19wcmVmaXg9ICduIHBhdGggJywgdmFsdWVzX2ZpbGwgPSAwKSAlPiUKICBhcnJhbmdlKG51dHMpCmBgYAoKYGBge3J9CnRhYl9hbGwgPC0gdGFiX2Jhc2ljICU+JQogIGxlZnRfam9pbih0YWJfY3BjX1ksIGJ5ID0gJ251dHMnKSAlPiUgIAogIGxlZnRfam9pbih0YWJfaXNpYywgYnkgPSAnbnV0cycpICU+JSAgCiAgbGVmdF9qb2luKHRhYl9hcHBsdCwgYnkgPSAnbnV0cycpICU+JQogIGxlZnRfam9pbih0YWJfcGF0aF9yZWwsIGJ5ID0gJ251dHMnKSAlPiUKICBsZWZ0X2pvaW4odGFiX3BhdGhfdG90YWwsIGJ5ID0gJ251dHMnKSAlPiUKICBzZWxlY3QoLW51dHMpCgp0YWJfYWxsCmBgYAoKCmBgYHtyfQp0YWJfYWxsICU+JSB3cml0ZV9jc3YyKCcuLi9vdXRwdXQvdGFibGVfcmVnaW9uc19hbGwuY3N2JykKYGBgCgoKYGBge3IsIHJlc3VsdHM9J2FzaXMnfQojbGlicmFyeShzdGFyZ2F6ZXIpCiN0YWJfYWxsICU+JSBzdGFyZ2F6ZXIoc3VtbWFyeSA9IEZBTFNFLCB0eXBlID0gJ2h0bWwnKQpgYGAKCgojIEVuZG5vdGVzCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKCgo8IS0tLQoKRFJPUFBFRCBGT1IgTk9XCgojIFRlY2ggU3BhY2UgY2hhbmdlcwoKYGBge3J9CnBsb3RfdGVjaHNwYWNlX2RldiA8LSBmdW5jdGlvbihnLCBydGFfZGYsIGRldl9kZiwgcmVnaW9uLCB0aW1lID0gJzInLCBsYXlvdXRfbncgPSAnbmljZWx5Jyl7CiAgIyBUT0RPLCBDJlAgZnVuY3Rpb24gZnJvbSBiZWxvdyBvbmNlIGZpbmlzaGVkCn0KYGBgCgpgYGB7cn0KIyBwbG90X3RlY2hzcGFjZV9kZXYoZyA9IGdfdGVjaCwgcnRhX2RmID0gdGVjaF9kZXYsIHJlZ2lvbiA9ICdESzAxMycsIGxheW91dF9udyA9IGNvb3Jkc190ZWNoKSAKYGBgCgoKVE9ETzogR08gT04gSEVSRSBBTkQgRE8gQkVUVEVSIERBVEFWSVoKCmBgYHtyfQojIFRFc3QgZm9yIGZ1bmN0aW9uIGRldmVsb3BtZW50CmcgPSBnX3RlY2gKcnRhX2RmID0gdGVjaF9kZXYKZGV2X2RmID0gdGVjaF9yZWxfZGV2IApyZWdpb24gPSAnREswMTMnCnRpbWUgPSAnMicKbGF5b3V0X253ID0gY29vcmRzX3RlY2gKCnJ0YV9kZiAlPD4lIAogIGZpbHRlcihudXRzID09IHJlZ2lvbiwgcGVyaW9kID09IHRpbWUsIFlfdGFnID09IFRSVUUpICU+JSAKICBzZWxlY3QobmFjZV9ncm91cCwgcnRhLCBuX3RlY2hfcmVnaW9uKQogIApkZXZfZGYgJTw+JQogIGZpbHRlcihudXRzID09IHJlZ2lvbikgJT4lIAogIGdyb3VwX2J5KG5hY2VfZ3JvdXApICU+JQogIHN1bW1hcmlzZShwcmV2X25vbmdyZWVuID0gbWF4KG5hY2VfZ3JvdXAgPT0gcmVsYXRlZF90ZWNobiwgbmEucm0gPSBUUlVFKSAlPiUgYXMubG9naWNhbCgpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgcmVwbGFjZV9uYShsaXN0KHByZXZfbm9uZ3JlZW4gPSBGQUxTRSkpICU+JQogIHNlbGVjdChuYWNlX2dyb3VwLCBwcmV2X25vbmdyZWVuKQoKZyA8LSBnICVOPiUKICBtdXRhdGUobGFiZWwgPSBuYWNlX2dyb3VwX25hbWUgJT4lIHN0cl90cnVuYyg1MCwgc2lkZSA9ICdyaWdodCcpKSAlPiUKICBsZWZ0X2pvaW4ocnRhX2RmLCBieSA9IGMoIm5hbWUiID0gIm5hY2VfZ3JvdXAiKSkgJU4+JQogIGxlZnRfam9pbihkZXZfZGYsIGJ5ID0gYygibmFtZSIgPSAibmFjZV9ncm91cCIpKSAKCmcgJT4lCiAgZ2dyYXBoKGxheW91dCA9ICBjb29yZHNfdGVjaCkgKyAKICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSB3ZWlnaHQsIGFscGhhID0gd2VpZ2h0KSwgY29sb3VyID0gImdyZXkiKSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3VyID0gcnRhLCBzaGFwZSA9IHByZXZfbm9uZ3JlZW4sIHNpemUgPSBuX3RlY2hfcmVnaW9uLCBmaWx0ZXIgPSBydGEgPj0gMSkpICsgCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbGFiZWwsIHNpemUgPSBuX3RlY2hfcmVnaW9uLCBmaWx0ZXIgPSBydGEgPj0gMSksIHJlcGVsID0gVFJVRSkgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAic2t5Ymx1ZSIsIG1pZCA9ICd5ZWxsb3cnLCBoaWdoID0gInJlZCIsIG1pZHBvaW50ID0gMSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiSW5kdXN0cnkgU3BhY2U6IiwgcmVnaW9uLCBzZXAgPSAiICIpLAogICAgICAgc3VidGl0bGUgPSAnTm9kZXMgPSBOQUNFIDIgSW5kdXN0cmllcy4gRWRnZXM6IFJlbGF0ZWRuZXNzJywKICAgICAgIGNhcHRpb24gPSAnJykKYGBgCgotLS0+