Goal

Recreate the descriptive analysis and plots used in the published research paper.

Preparing data

Libraries

fpackage.check <- function(packages) { # (c) Jochem Tolsma
  lapply(packages, FUN = function(x) {
    if (!require(x, character.only = TRUE)) {
      install.packages(x, dependencies = TRUE)
      library(x, character.only = TRUE)
    }
  })
}
packages = c("tidyverse","kableExtra", "ggplot2", "patchwork", "foreach", "ggpattern")
fpackage.check(packages)

Import results and data

Import the NSUM data and recreate the NSUM module.

#import nells file.
load(file = "data_analysis/data/data_processed/nells_data/2022-11-09_nells-nsum-prepped-data.rds")

Import the model estimates from the estimated NSUM models. I have chosen the model which uses Ibrahim for the ethnic names.

if (file.exists(
  "data_analysis/results/nsum_output/main/combined_data/df_models_nsum_long.rds"
)) {
  load(file = "data_analysis/results/nsum_output/main/combined_data/df_models_nsum_long.rds")
} else {
  list_files <-
    as.list(
      dir(
        "data_analysis/results/nsum_output/main/model/",
        full.names = T
      )
    )
  #create loop lists
  kds <- list()
  kdssd <- list()
  data <- list()
  list_df <- list()
  
  #loop to extract information
  for (i in 1:length(list_files)) {
    #i = 1
    print(paste0("Number ", i, " of ", length(list_files)))
    load(list_files[[i]])
    kds[[i]] <-
      rowMeans(degree$d.values, na.rm = TRUE) # calculate rowmean of netsize iterations: so the retained chains
    kdssd[[i]] <-
      matrixStats::rowSds(degree$d.values) # calculate sd of 4k estimates per row: sd for those values
    data[[i]] <- cbind(kds[[i]], kdssd[[i]]) # combine them
    list_df[[i]] <-
      cbind(as_tibble(data[[i]]), nells_nsum$id) # add NELLS id variable
    strings <-
      str_split(str_extract(list_files[[i]][1], pattern = "estimates.+"),
                pattern = "_")  # add holdout number
    list_df[[i]] <- list_df[[i]] %>%
      mutate(
        holdout = as.numeric(str_extract(strings[[1]][2], pattern = "[[:digit:]]{1,}")))
  }
    #combine results and save
    df_models_nsum_long <- list_df %>%
      bind_rows() %>%
      rename(mean = V1,
             sd = V2,
             id = 3)
    #save image
    save(df_models_nsum_long, file = "data_analysis/results/nsum_output/main/combined_data/df_models_nsum_long.rds")
}

We use Ibrahim as population for the size estimates, so let’s combine the size estimates from holdout 10 with the other NSUM information.

#select holdout ten 10
size_selection <- df_models_nsum_long %>% 
  dplyr::filter(holdout == 10) 

#add netsize data to NELLS data
nells_df <- size_selection %>% 
  left_join(nells_nsum, by = "id")

Selection of respondents

We remove 32 observations as they deviate more than 3 SD from the mean.

nells_df <- nells_df %>% 
    mutate(mean_size = mean(mean, na.rm = T),
         sd_size = sd(mean, na.rm = T),
         z = (mean - mean_size)/sd_size) %>% 
  filter(z < 3) 

#filter out other
nells_df <- nells_df %>% 
  filter(migration_background_fac != "Other")

Describing network size

First of all, we want to show the density distribution of extended network size. We also show the median size of extended networks. These estimates are in line with previous estimates that have been found of extended network size.

options(scipen = 999)

size_density_plot <- nells_df %>%
  ggplot(aes(x = mean)) +
  geom_density(alpha = 0.4,
               colour = "black",
               fill = "grey") +
  geom_vline(xintercept = median(nells_df$mean, na.rm = T),
             colour = "red") +
  annotate(
    "text",
    x = 1500,
    y = 0.0008,
    label = paste("Median:", as.character(round(
      median(nells_df$mean, na.rm = T), 3
    ))),
    colour = "black"
  ) +
  #facet_wrap(vars(migration_background_fac)) +
  scale_fill_viridis_d() +
  scale_color_viridis_d() +
  theme(
    panel.background = element_rect(fill = "#FFFFFF"),
    plot.background = element_rect(fill = "#FFFFFF"),
    panel.grid = element_line(colour = "grey"),
    text = element_text(family = "sans", size = 12),
    axis.title.x = element_text(hjust = 0.9, face = "bold"),
    axis.text.x = element_text(),
    axis.line = element_blank(),
    axis.title.y = element_text(hjust = 0.9, face = "bold"),
    axis.ticks = element_blank(),
    strip.background = element_rect(fill = "#A9A9A9"),
    panel.grid.minor = element_blank(),
    panel.grid.major.x = element_blank(),
    legend.position = "right",
    legend.title = element_blank(),
    legend.background = element_rect(fill = "#FFFFFF"),
    legend.key = element_rect(fill = "#FFFFFF")
  ) +
  labs(x = "Extended social network size", y = "Density")

#show plot
size_density_plot

#export plot
ggsave(size_density_plot,
       file = "data_analysis/plots/descriptive/density_network_size.jpg",
       width = 5,
       height = 4,
       dpi = 320)

Group comparison

To present differences in network size

Extended groups boxplot

nells_df <- nells_df %>%
  mutate(
    migration_background_fac = fct_relevel(migration_background_fac,
                                                "Dutch",
                                                "1st gen Turkish",
                                                "2nd gen Turkish",
                                                "1st gen Moroccan",
                                                "2nd gen Moroccan"),
         migration_background_fac = factor(as.numeric(migration_background_fac),
         levels = 1:5,
         labels = c("Dutch Majority",
                                                "1st gen Turkish-Dutch",
                                                "2nd gen Turkish-Dutch",
                                                "1st gen Moroccan-Dutch",
                                                "2nd gen Moroccan-Dutch")),
    migration_background_simple_fac = case_when(
      migration_background_fac == "1st gen Turkish-Dutch" ~ 2,
      migration_background_fac == "2nd gen Turkish-Dutch" ~ 2,
      migration_background_fac == "1st gen Moroccan-Dutch" ~ 3,
      migration_background_fac == "2nd gen Moroccan-Dutch" ~ 3,
      migration_background_fac == "Dutch Majority" ~ 1
    ),
    migration_background_simple_fac = factor(
      migration_background_simple_fac,
      levels = 1:3,
      labels = c("Dutch Majority", "Turkish-Dutch", "Moroccan-Dutch")
    ),
    migrant_generation = case_when(
      str_detect(migration_background_fac, "1st") ~ 1,
      str_detect(migration_background_fac, "2nd") ~ 2
    )
  )

Boxplot

Create panel with complete groups (no generation distinction).

#set custom pallet
pal <- c("#66c2a5",
         "#fc8d62",
         "#8da0cb")

#create simple boxplot
boxplot_size_simple_groups <- nells_df %>%
  ggplot(aes(x = fct_rev(migration_background_simple_fac),
             y = mean,
             fill = migration_background_simple_fac,
             colour = migration_background_simple_fac
             )) +
  geom_boxplot(alpha = 0.6) +
  coord_flip() +
  scale_colour_manual(
    values = pal,
    aesthetics = c("colour", "fill")
  ) +
   theme(
    panel.background = element_rect(fill = "#FFFFFF"),
    plot.background = element_rect(fill = "#FFFFFF"),
    panel.grid = element_line(colour = "grey"),
    text = element_text(family = "sans", size = 12),
    axis.title.x = element_text(hjust = 0.9, face = "bold"),
    axis.text.x = element_text(),
    axis.line = element_blank(),
    axis.title.y = element_text(hjust = 0.9, face = "bold"),
    axis.ticks = element_blank(),
    strip.background = element_rect(fill = "#A9A9A9"),
    panel.grid.minor = element_blank(),
    panel.grid.major.y = element_blank(),
    legend.position = "none",
    legend.title = element_blank(),
    legend.background = element_rect(fill = "#FFFFFF"),
    legend.key = element_rect(fill = "#FFFFFF")
  ) +
  labs(y  = "",
       x = "")

Create panel with generation distinction.

#set custom pallet
pal <- c("#fc8d62",
         "#fc8d62",
         "#8da0cb",
         "#8da0cb")

#create extended boplot
boxplot_size_extended_groups <- nells_df %>%
  filter(migration_background_fac != "Dutch Majority") %>% 
  ggplot(aes(x = fct_rev(migration_background_fac),
             y = mean,
             fill = migration_background_fac,
             colour = migration_background_fac
             )) +
  geom_boxplot_pattern(aes(pattern_density = as.factor(migrant_generation)),
                       alpha = 0.6,
                       pattern = "circle"
                       ) +
  coord_flip() +
  scale_colour_manual(
    values = pal,
    aesthetics = c("colour", "fill")
  )  +
  scale_pattern_density_manual(values = c("1" = 0, "2"=0.1)) +
   theme(
    panel.background = element_rect(fill = "#FFFFFF"),
    plot.background = element_rect(fill = "#FFFFFF"),
    panel.grid = element_line(colour = "grey"),
    text = element_text(family = "sans", size = 12),
    axis.title.x = element_text(hjust = 0.9, face = "bold"),
    axis.text.x = element_text(),
    axis.line = element_blank(),
    axis.title.y = element_text(hjust = 0.9, face = "bold"),
    axis.ticks = element_blank(),
    strip.background = element_rect(fill = "#A9A9A9"),
    panel.grid.minor = element_blank(),
    panel.grid.major.y = element_blank(),
    legend.position = "none",
    legend.title = element_blank(),
    legend.background = element_rect(fill = "#FFFFFF"),
    legend.key = element_rect(fill = "#FFFFFF")
  ) +
  labs(y  = "",
       x = "")

Combine panels in multipanel plot.

## Panel plot
hom_size_panel <- boxplot_size_simple_groups + 
  boxplot_size_extended_groups + 
  plot_annotation(tag_levels ='a',
                  tag_prefix = '(',
                  tag_suffix = ')') +
  plot_layout(ncol = 1,
              guides = "collect",
              heights = c(1,2)) & 
  theme(legend.position='none')


hom_size_panel

ggsave(hom_size_panel,
       file = "data_analysis/plots/descriptive/size_plot_panel.jpg",
       width = 8,
       height = 5,
       dpi = 320)

Ethnic Homogeneity

Multipanel boxplot

Prepare data for ethnic homogeneity plot.

#weighted by name frequency.
nells_df <- nells_df %>%
  mutate(
    sum_dutch_w = knows_daan_boundary/22704 + 
      knows_kevin_boundary/23167 +
      knows_emma_boundary/18730 + 
      knows_linda_boundary/29955 + 
      knows_albert_boundary/31767 + 
      knows_edwin_boundary/21866 + 
      knows_willemina_boundary/17133 + 
      knows_ingrid_boundary/31323,
    sum_turkish_w = knows_ibrahim_boundary/2099 + 
      knows_esra_boundary/1878,
    sum_moroccan_w = knows_mohammed_boundary/13448 + 
      knows_fatima_boundary/2808,
    sum_total_w = sum_dutch_w + sum_turkish_w + sum_moroccan_w,
    per_dutch_w = (sum_dutch_w / sum_total_w) * 100,
    per_turkish_w = (sum_turkish_w / sum_total_w) * 100,
    per_moroccan_w = (sum_moroccan_w / sum_total_w) * 100
  )

#assign correct percentage co-ethnic to each group
nells_df <- nells_df %>% 
  mutate(per_ingroup_w = case_when(
    str_detect(migration_background_fac, "kish") ~ per_turkish_w,
    str_detect(migration_background_fac, "occan") ~ per_moroccan_w,
    migration_background_fac == "Dutch Majority" ~ per_dutch_w,
    migration_background_fac == "Other" ~ per_dutch_w
  ))

Create panel with complete groups (no generation distinction).

#set custom pallet
pal <- c("#66c2a5",
         "#fc8d62",
         "#8da0cb")

#create graph for simple groups
boxplot_hom_simple_groups <- nells_df %>%
  ggplot(aes(x = fct_rev(migration_background_simple_fac),
             y = per_ingroup_w,
             fill = migration_background_simple_fac,
             colour = migration_background_simple_fac
             )) +
  geom_boxplot(alpha = 0.6) +
  coord_flip() +
  scale_colour_manual(
    values = pal,
    aesthetics = c("colour", "fill")
  ) +
   theme(
    panel.background = element_rect(fill = "#FFFFFF"),
    plot.background = element_rect(fill = "#FFFFFF"),
    panel.grid = element_line(colour = "grey"),
    text = element_text(family = "sans", size = 12),
    axis.title.x = element_text(hjust = 0.9, face = "bold"),
    axis.text.x = element_text(),
    axis.line = element_blank(),
    axis.title.y = element_text(hjust = 0.9, face = "bold"),
    axis.ticks = element_blank(),
    strip.background = element_rect(fill = "#A9A9A9"),
    panel.grid.minor = element_blank(),
    panel.grid.major.y = element_blank(),
    legend.position = "none",
    legend.title = element_blank(),
    legend.background = element_rect(fill = "#FFFFFF"),
    legend.key = element_rect(fill = "#FFFFFF")
  ) +
  labs(y  = "",
       x = "")

Create panel with generation distinction.

#set custom pallet
pal <- c("#fc8d62",
         "#fc8d62",
         "#8da0cb",
         "#8da0cb")

#create boxplot for extended groups
boxplot_hom_extended_groups <- nells_df %>%
  filter(migration_background_fac != "Dutch Majority") %>% 
  ggplot(aes(x = fct_rev(migration_background_fac),
             y = per_ingroup_w,
             colour = migration_background_fac,
             fill = migration_background_fac,
             )) +
    geom_boxplot_pattern(aes(pattern_density = as.factor(migrant_generation)),
                       alpha = 0.6,
                       pattern = "circle"
                       ) +
  coord_flip() +
  scale_colour_manual(
    values = pal,
    aesthetics = c("colour", "fill")
  )  +
  scale_pattern_density_manual(values = c("1" = 0, "2"=0.1)) +
   theme(
    panel.background = element_rect(fill = "#FFFFFF"),
    plot.background = element_rect(fill = "#FFFFFF"),
    panel.grid = element_line(colour = "grey"),
    text = element_text(family = "sans", size = 12),
    axis.title.x = element_text(hjust = 0.9, face = "bold"),
    axis.text.x = element_text(),
    axis.line = element_blank(),
    axis.title.y = element_text(hjust = 0.9, face = "bold"),
    axis.ticks = element_blank(),
    strip.background = element_rect(fill = "#A9A9A9"),
    panel.grid.minor = element_blank(),
    panel.grid.major.y = element_blank(),
    legend.position = "none",
    legend.title = element_blank(),
    legend.background = element_rect(fill = "#FFFFFF"),
    legend.key = element_rect(fill = "#FFFFFF")
  ) +
  labs(y  = "",
       x = "")

Create multipanel plot.

## Panel plot
hom_plot_panel <- boxplot_hom_simple_groups + 
  boxplot_hom_extended_groups + 
  plot_annotation(tag_levels ='a',
                  tag_prefix = '(',
                  tag_suffix = ')') +
  plot_layout(ncol = 1,
              guides = "collect",
              heights = c(1,2)) & 
  theme(legend.position='none')

#show plot
hom_plot_panel

#save plor
ggsave(hom_plot_panel,
       file = "data_analysis/plots/descriptive/hom_plot_panel.jpg",
       width = 8,
       height = 5,
       dpi = 320)

Name differences

For every x (for now names) we can estimate an NB regression to see differences between migration backgrounds. Please note: this does not take into account naming frequency in the population. Differences between different ethnic groups may indeed be larger or smaller for different names.

# use a loop.
#set var_names to use in loop. 
variable_names_model <- c("knows_daan",
  "knows_kevin", 
  "knows_edwin",
  "knows_albert",
  "knows_emma",
  "knows_linda",
  "knows_ingrid",
  "knows_willemina",
  "knows_mohammed",
  "knows_fatima",
  "knows_ibrahim",
  "knows_esra")

#start analysis loop
model_results <- list()

for(i in 1:length(variable_names_model)) {#i = 1
  fm <- as.formula(paste(variable_names_model[[i]], "~", "migration_background_fac"))
  model_results[[i]] <- MASS::glm.nb(fm,
     data = nells_df)
}

#clean output with tidy r
model_results_df_list <- model_results %>% 
  purrr::map(.x =., 
             .f = ~ broom::tidy(.x))

#add var_names to model_results
for(i in 1:length(model_results_df_list)){
  model_results_df_list[[i]] <- model_results_df_list[[i]] %>% 
    mutate(dep_var = variable_names_model[i])
}

#combine model dfs.
model_results_df <- model_results_df_list %>%
  bind_rows() 

#set correct variable names
model_results_df <- model_results_df %>%
  mutate(
    term = case_when(
      str_detect(term, "2nd gen Moroccan") ~ "2nd gen Moroccan-Dutch",
      str_detect(term, "2nd gen Turkish") ~ "2nd gen Turkish-Dutch",
      str_detect(term, "1st gen Moroccan") ~ "1st gen Moroccan-Dutch",
      str_detect(term, "1st gen Turkish") ~ "1st gen Turkish-Dutch",
      term == "(Intercept)" ~ "Intercept"
    )
  )

#Set correct names
correct_names <- model_results_df %>% 
  pull(dep_var) %>% 
  str_replace(., pattern = "knows_", replacement = "") %>% 
  str_to_title()

#drop old names and add the correct names
model_results_df <- model_results_df %>% 
  select(-dep_var) %>% 
  mutate(dep_var = correct_names)

Predicted counts plot for names and ethnicity

pred_nb_f <- function(nb_model, names){#nb_model = model_results[[1]], names = variable_names_model[[1]]
pred <- predict(object = nb_model,
                type = "response",
                se.fit = T
        )

plot_df <- nells_df %>% 
  select(id, migration_background_fac) %>% 
  bind_cols(pred) %>% 
  mutate(dep_var = names)

return(plot_df)
}

model_pred_list <- map2(.x = model_results,
     .y = variable_names_model,
     .f = ~pred_nb_f(nb_model = .x,
                     names = .y))

model_pred_df <- model_pred_list %>% 
  bind_rows()


#Set correct names
correct_names <- model_pred_df %>% 
  pull(dep_var) %>% 
  str_replace(., pattern = "knows_", replacement = "") %>% 
  str_to_title()


#drop old names and add the correct names
model_pred_df <- model_pred_df %>% 
  select(-dep_var) %>% 
  mutate(dep_var = correct_names)
#set custom pallet
pal <- c("#66c2a5",
         "#fc8d62",
         "#fc8d62",
         "#8da0cb",
         "#8da0cb")

#crete plot with minority names
ethnic_names_pred_plot <- model_pred_df %>% 
  filter(dep_var %in% c("Mohammed",
  "Fatima",
  "Ibrahim",
  "Esra")) %>% 
  ggplot(aes(x = dep_var,
             y = fit,
             shape = migration_background_fac)) +
  geom_linerange(aes(ymin = fit - (se.fit *1.96),
                      ymax =  fit + (se.fit *1.96)),
                  position = position_dodge(width = 1)) +
  geom_point(aes(colour = migration_background_fac,
                 fill = migration_background_fac),
            position = position_dodge(width = 1)) +
  facet_wrap(vars(dep_var),
             scales = "free",
             ncol = 2) +
  scale_colour_manual(
    values = pal,
    aesthetics = c("colour", "fill")
  ) +
  scale_shape_manual(values = c(21,22,24,22,24)) +
  theme(
    panel.background = element_rect(fill = "#FFFFFF",
                                    colour = "black"),
    plot.background = element_rect(fill = "#FFFFFF"),
    panel.grid = element_line(colour = "grey"),
    text = element_text(family = "sans", size = 12),
    axis.title.x = element_text(hjust = 0.9, face = "bold"),
    axis.text.x = element_blank(),
    axis.line = element_blank(),
    axis.title.y = element_text(hjust = 0.9, face = "bold"),
    axis.ticks = element_blank(),
    strip.background = element_rect(fill = "#FFFFFF"),
    panel.grid.minor = element_blank(),
    panel.grid.major.x = element_blank(),
    legend.position = "none",
    legend.title = element_blank(),
    legend.background = element_rect(fill = "#FFFFFF"),
    legend.key = element_rect(fill = "#FFFFFF")
  ) +
    labs(x = "", 
       y = "",
       colour = "",
       shape = "",
       fill = ""
       )
#set custom pallet
pal <- c("#66c2a5",
         "#fc8d62",
         "#fc8d62",
         "#8da0cb",
         "#8da0cb")

#create plot for majority names
non_ethnic_names_pred_plot <- model_pred_df %>% 
  filter(!dep_var %in% c("Mohammed",
  "Fatima",
  "Ibrahim",
  "Esra")) %>% 
  ggplot(aes(x = dep_var,
             y = fit,
             shape = migration_background_fac)) +
  geom_linerange(aes(ymin = fit - (se.fit *1.96),
                      ymax =  fit + (se.fit *1.96)),
                  position = position_dodge(width = 1)) +
  geom_point(aes(colour = migration_background_fac,
                 fill = migration_background_fac),
            position = position_dodge(width = 1)) +
  facet_wrap(vars(dep_var),
             scales = "free_x",
             ncol = 2) +
  scale_colour_manual(
    values = pal,
    aesthetics = c("colour", "fill")
  ) +
  scale_shape_manual(values = c(21,22,24,22,24)) +
  theme(
    panel.background = element_rect(fill = "#FFFFFF",
                                    colour = "black"),
    plot.background = element_rect(fill = "#FFFFFF"),
    panel.grid = element_line(colour = "grey"),
    text = element_text(family = "sans", size = 12),
    axis.title.x = element_text(hjust = 0.9, face = "bold"),
    axis.text.x = element_blank(),
    axis.line = element_blank(),
    axis.title.y = element_text(hjust = 0.9, face = "bold"),
    axis.ticks = element_blank(),
    strip.background = element_rect(fill = "#FFFFFF"),
    panel.grid.minor = element_blank(),
    panel.grid.major.x = element_blank(),
    legend.position = "none",
    legend.title = element_blank(),
    legend.background = element_rect(fill = "#FFFFFF"),
    legend.key = element_rect(fill = "#FFFFFF")
  ) +
    labs(x = "", 
       y = "",
       colour = "",
       shape = "",
       fill = ""
       )
#Combine plots in multipanel plot
names_pred_het_panel <- ethnic_names_pred_plot +
  non_ethnic_names_pred_plot + 
  plot_annotation(
    tag_levels = 'a',
    tag_prefix = '(',
    tag_suffix = ')'
  ) +
  plot_layout(ncol = 1,
              heights = c(1, 3),
              guides = 'collect',
  ) &
  theme(legend.position = c(-2,-5),
        legend.direction = 'vertical')

#preview plot
names_pred_het_panel

#save plot
ggsave(names_pred_het_panel,
        file = "data_analysis/plots/descriptive/names_het_pred_panel.jpg",
       width = 6,
       height = 8,
       dpi = 320)
LS0tDQp0aXRsZTogIkRlc2NyaWJpbmcgZXh0ZW5kZWQgbmV0d29yayBzaXplIGFuZCBldGhuaWMgY29tcG9zaXRpb24iDQphdXRob3I6ICJUaGlqbWVuIEplcm9lbnNlIg0KZGF0ZTogIkxhc3QgY29tcGlsZWQgb24gYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2RlcHRoOiAzDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGNhY2hlID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHMgPSAiYXNpcyIsDQogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gImNlbnRlciIpDQpgYGANCg0KIyBHb2FsDQpSZWNyZWF0ZSB0aGUgZGVzY3JpcHRpdmUgYW5hbHlzaXMgYW5kIHBsb3RzIHVzZWQgaW4gdGhlIHB1Ymxpc2hlZCByZXNlYXJjaCBwYXBlci4NCg0KIyBQcmVwYXJpbmcgZGF0YQ0KDQojIyBMaWJyYXJpZXMNCg0KYGBge3IgbGlicmFyaWVzIGFuZCBmaWxlcywgcmVzdWx0cyA9ICdoaWRlJ30NCmZwYWNrYWdlLmNoZWNrIDwtIGZ1bmN0aW9uKHBhY2thZ2VzKSB7ICMgKGMpIEpvY2hlbSBUb2xzbWENCiAgbGFwcGx5KHBhY2thZ2VzLCBGVU4gPSBmdW5jdGlvbih4KSB7DQogICAgaWYgKCFyZXF1aXJlKHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsNCiAgICAgIGluc3RhbGwucGFja2FnZXMoeCwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgICAgIGxpYnJhcnkoeCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQ0KICAgIH0NCiAgfSkNCn0NCnBhY2thZ2VzID0gYygidGlkeXZlcnNlIiwia2FibGVFeHRyYSIsICJnZ3Bsb3QyIiwgInBhdGNod29yayIsICJmb3JlYWNoIiwgImdncGF0dGVybiIpDQpmcGFja2FnZS5jaGVjayhwYWNrYWdlcykNCg0KYGBgDQoNCiMjIEltcG9ydCByZXN1bHRzIGFuZCBkYXRhDQoNCkltcG9ydCB0aGUgTlNVTSBkYXRhIGFuZCByZWNyZWF0ZSB0aGUgTlNVTSBtb2R1bGUuIA0KDQpgYGB7ciBmaWxlc30NCiNpbXBvcnQgbmVsbHMgZmlsZS4NCmxvYWQoZmlsZSA9ICJkYXRhX2FuYWx5c2lzL2RhdGEvZGF0YV9wcm9jZXNzZWQvbmVsbHNfZGF0YS8yMDIyLTExLTA5X25lbGxzLW5zdW0tcHJlcHBlZC1kYXRhLnJkcyIpDQoNCmBgYA0KDQpJbXBvcnQgdGhlIG1vZGVsIGVzdGltYXRlcyBmcm9tIHRoZSBlc3RpbWF0ZWQgTlNVTSBtb2RlbHMuIEkgaGF2ZSBjaG9zZW4gdGhlIG1vZGVsIHdoaWNoIHVzZXMgSWJyYWhpbSBmb3IgdGhlIGV0aG5pYyBuYW1lcy4NCg0KYGBge3IgaW1wb3J0IHJlc3VsdHN9DQoNCmlmIChmaWxlLmV4aXN0cygNCiAgImRhdGFfYW5hbHlzaXMvcmVzdWx0cy9uc3VtX291dHB1dC9tYWluL2NvbWJpbmVkX2RhdGEvZGZfbW9kZWxzX25zdW1fbG9uZy5yZHMiDQopKSB7DQogIGxvYWQoZmlsZSA9ICJkYXRhX2FuYWx5c2lzL3Jlc3VsdHMvbnN1bV9vdXRwdXQvbWFpbi9jb21iaW5lZF9kYXRhL2RmX21vZGVsc19uc3VtX2xvbmcucmRzIikNCn0gZWxzZSB7DQogIGxpc3RfZmlsZXMgPC0NCiAgICBhcy5saXN0KA0KICAgICAgZGlyKA0KICAgICAgICAiZGF0YV9hbmFseXNpcy9yZXN1bHRzL25zdW1fb3V0cHV0L21haW4vbW9kZWwvIiwNCiAgICAgICAgZnVsbC5uYW1lcyA9IFQNCiAgICAgICkNCiAgICApDQogICNjcmVhdGUgbG9vcCBsaXN0cw0KICBrZHMgPC0gbGlzdCgpDQogIGtkc3NkIDwtIGxpc3QoKQ0KICBkYXRhIDwtIGxpc3QoKQ0KICBsaXN0X2RmIDwtIGxpc3QoKQ0KICANCiAgI2xvb3AgdG8gZXh0cmFjdCBpbmZvcm1hdGlvbg0KICBmb3IgKGkgaW4gMTpsZW5ndGgobGlzdF9maWxlcykpIHsNCiAgICAjaSA9IDENCiAgICBwcmludChwYXN0ZTAoIk51bWJlciAiLCBpLCAiIG9mICIsIGxlbmd0aChsaXN0X2ZpbGVzKSkpDQogICAgbG9hZChsaXN0X2ZpbGVzW1tpXV0pDQogICAga2RzW1tpXV0gPC0NCiAgICAgIHJvd01lYW5zKGRlZ3JlZSRkLnZhbHVlcywgbmEucm0gPSBUUlVFKSAjIGNhbGN1bGF0ZSByb3dtZWFuIG9mIG5ldHNpemUgaXRlcmF0aW9uczogc28gdGhlIHJldGFpbmVkIGNoYWlucw0KICAgIGtkc3NkW1tpXV0gPC0NCiAgICAgIG1hdHJpeFN0YXRzOjpyb3dTZHMoZGVncmVlJGQudmFsdWVzKSAjIGNhbGN1bGF0ZSBzZCBvZiA0ayBlc3RpbWF0ZXMgcGVyIHJvdzogc2QgZm9yIHRob3NlIHZhbHVlcw0KICAgIGRhdGFbW2ldXSA8LSBjYmluZChrZHNbW2ldXSwga2Rzc2RbW2ldXSkgIyBjb21iaW5lIHRoZW0NCiAgICBsaXN0X2RmW1tpXV0gPC0NCiAgICAgIGNiaW5kKGFzX3RpYmJsZShkYXRhW1tpXV0pLCBuZWxsc19uc3VtJGlkKSAjIGFkZCBORUxMUyBpZCB2YXJpYWJsZQ0KICAgIHN0cmluZ3MgPC0NCiAgICAgIHN0cl9zcGxpdChzdHJfZXh0cmFjdChsaXN0X2ZpbGVzW1tpXV1bMV0sIHBhdHRlcm4gPSAiZXN0aW1hdGVzLisiKSwNCiAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIl8iKSAgIyBhZGQgaG9sZG91dCBudW1iZXINCiAgICBsaXN0X2RmW1tpXV0gPC0gbGlzdF9kZltbaV1dICU+JQ0KICAgICAgbXV0YXRlKA0KICAgICAgICBob2xkb3V0ID0gYXMubnVtZXJpYyhzdHJfZXh0cmFjdChzdHJpbmdzW1sxXV1bMl0sIHBhdHRlcm4gPSAiW1s6ZGlnaXQ6XV17MSx9IikpKQ0KICB9DQogICAgI2NvbWJpbmUgcmVzdWx0cyBhbmQgc2F2ZQ0KICAgIGRmX21vZGVsc19uc3VtX2xvbmcgPC0gbGlzdF9kZiAlPiUNCiAgICAgIGJpbmRfcm93cygpICU+JQ0KICAgICAgcmVuYW1lKG1lYW4gPSBWMSwNCiAgICAgICAgICAgICBzZCA9IFYyLA0KICAgICAgICAgICAgIGlkID0gMykNCiAgICAjc2F2ZSBpbWFnZQ0KICAgIHNhdmUoZGZfbW9kZWxzX25zdW1fbG9uZywgZmlsZSA9ICJkYXRhX2FuYWx5c2lzL3Jlc3VsdHMvbnN1bV9vdXRwdXQvbWFpbi9jb21iaW5lZF9kYXRhL2RmX21vZGVsc19uc3VtX2xvbmcucmRzIikNCn0NCmBgYA0KDQpXZSB1c2UgSWJyYWhpbSBhcyBwb3B1bGF0aW9uIGZvciB0aGUgc2l6ZSBlc3RpbWF0ZXMsIHNvIGxldCdzIGNvbWJpbmUgdGhlIHNpemUgZXN0aW1hdGVzIGZyb20gaG9sZG91dCAxMCB3aXRoIHRoZSBvdGhlciBOU1VNIGluZm9ybWF0aW9uLiANCg0KYGBge3IgaG9sZG91dCAyLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD03fQ0KI3NlbGVjdCBob2xkb3V0IHRlbiAxMA0Kc2l6ZV9zZWxlY3Rpb24gPC0gZGZfbW9kZWxzX25zdW1fbG9uZyAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoaG9sZG91dCA9PSAxMCkgDQoNCiNhZGQgbmV0c2l6ZSBkYXRhIHRvIE5FTExTIGRhdGENCm5lbGxzX2RmIDwtIHNpemVfc2VsZWN0aW9uICU+JSANCiAgbGVmdF9qb2luKG5lbGxzX25zdW0sIGJ5ID0gImlkIikNCg0KYGBgDQoNCiMjIFNlbGVjdGlvbiBvZiByZXNwb25kZW50cw0KDQpXZSByZW1vdmUgMzIgb2JzZXJ2YXRpb25zIGFzIHRoZXkgZGV2aWF0ZSBtb3JlIHRoYW4gMyBTRCBmcm9tIHRoZSBtZWFuLiANCg0KYGBge3IgZGVsZXRlIG91dGxpZXJzfQ0KbmVsbHNfZGYgPC0gbmVsbHNfZGYgJT4lIA0KICAgIG11dGF0ZShtZWFuX3NpemUgPSBtZWFuKG1lYW4sIG5hLnJtID0gVCksDQogICAgICAgICBzZF9zaXplID0gc2QobWVhbiwgbmEucm0gPSBUKSwNCiAgICAgICAgIHogPSAobWVhbiAtIG1lYW5fc2l6ZSkvc2Rfc2l6ZSkgJT4lIA0KICBmaWx0ZXIoeiA8IDMpIA0KDQojZmlsdGVyIG91dCBvdGhlcg0KbmVsbHNfZGYgPC0gbmVsbHNfZGYgJT4lIA0KICBmaWx0ZXIobWlncmF0aW9uX2JhY2tncm91bmRfZmFjICE9ICJPdGhlciIpDQoNCg0KYGBgDQoNCiMgRGVzY3JpYmluZyBuZXR3b3JrIHNpemUgDQoNCkZpcnN0IG9mIGFsbCwgd2Ugd2FudCB0byBzaG93IHRoZSBkZW5zaXR5IGRpc3RyaWJ1dGlvbiBvZiBleHRlbmRlZCBuZXR3b3JrIHNpemUuIFdlIGFsc28gc2hvdyB0aGUgbWVkaWFuIHNpemUgb2YgZXh0ZW5kZWQgbmV0d29ya3MuIFRoZXNlIGVzdGltYXRlcyBhcmUgaW4gbGluZSB3aXRoIHByZXZpb3VzIGVzdGltYXRlcyB0aGF0IGhhdmUgYmVlbiBmb3VuZCBvZiBleHRlbmRlZCBuZXR3b3JrIHNpemUuIA0KDQpgYGB7ciBkZW5zaXR5IHBsb3Qgc2FtcGxlLCB3aWR0aCA9IDQsIGhlaWd0aCA9IDR9DQpvcHRpb25zKHNjaXBlbiA9IDk5OSkNCg0Kc2l6ZV9kZW5zaXR5X3Bsb3QgPC0gbmVsbHNfZGYgJT4lDQogIGdncGxvdChhZXMoeCA9IG1lYW4pKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCwNCiAgICAgICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsDQogICAgICAgICAgICAgICBmaWxsID0gImdyZXkiKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lZGlhbihuZWxsc19kZiRtZWFuLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgIGNvbG91ciA9ICJyZWQiKSArDQogIGFubm90YXRlKA0KICAgICJ0ZXh0IiwNCiAgICB4ID0gMTUwMCwNCiAgICB5ID0gMC4wMDA4LA0KICAgIGxhYmVsID0gcGFzdGUoIk1lZGlhbjoiLCBhcy5jaGFyYWN0ZXIocm91bmQoDQogICAgICBtZWRpYW4obmVsbHNfZGYkbWVhbiwgbmEucm0gPSBUKSwgMw0KICAgICkpKSwNCiAgICBjb2xvdXIgPSAiYmxhY2siDQogICkgKw0KICAjZmFjZXRfd3JhcCh2YXJzKG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYykpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKSArDQogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsNCiAgdGhlbWUoDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkZGRkYiKSwNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkZGRkZGIiksDQogICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleSIpLA0KICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNhbnMiLCBzaXplID0gMTIpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuOSwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoKSwNCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC45LCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjQTlBOUE5IiksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkZGRkZGIiksDQogICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkZGRkYiKQ0KICApICsNCiAgbGFicyh4ID0gIkV4dGVuZGVkIHNvY2lhbCBuZXR3b3JrIHNpemUiLCB5ID0gIkRlbnNpdHkiKQ0KDQojc2hvdyBwbG90DQpzaXplX2RlbnNpdHlfcGxvdA0KDQojZXhwb3J0IHBsb3QNCmdnc2F2ZShzaXplX2RlbnNpdHlfcGxvdCwNCiAgICAgICBmaWxlID0gImRhdGFfYW5hbHlzaXMvcGxvdHMvZGVzY3JpcHRpdmUvZGVuc2l0eV9uZXR3b3JrX3NpemUuanBnIiwNCiAgICAgICB3aWR0aCA9IDUsDQogICAgICAgaGVpZ2h0ID0gNCwNCiAgICAgICBkcGkgPSAzMjApDQoNCg0KYGBgDQoNCiMjIEdyb3VwIGNvbXBhcmlzb24NCg0KVG8gcHJlc2VudCBkaWZmZXJlbmNlcyBpbiBuZXR3b3JrIHNpemUNCg0KIyMjIEV4dGVuZGVkIGdyb3VwcyBib3hwbG90DQoNCmBgYHtyIHByZXBhcmUgZmFjdG9yIGxhYmVsc30NCm5lbGxzX2RmIDwtIG5lbGxzX2RmICU+JQ0KICBtdXRhdGUoDQogICAgbWlncmF0aW9uX2JhY2tncm91bmRfZmFjID0gZmN0X3JlbGV2ZWwobWlncmF0aW9uX2JhY2tncm91bmRfZmFjLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkR1dGNoIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxc3QgZ2VuIFR1cmtpc2giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjJuZCBnZW4gVHVya2lzaCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMXN0IGdlbiBNb3JvY2NhbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMm5kIGdlbiBNb3JvY2NhbiIpLA0KICAgICAgICAgbWlncmF0aW9uX2JhY2tncm91bmRfZmFjID0gZmFjdG9yKGFzLm51bWVyaWMobWlncmF0aW9uX2JhY2tncm91bmRfZmFjKSwNCiAgICAgICAgIGxldmVscyA9IDE6NSwNCiAgICAgICAgIGxhYmVscyA9IGMoIkR1dGNoIE1ham9yaXR5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxc3QgZ2VuIFR1cmtpc2gtRHV0Y2giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjJuZCBnZW4gVHVya2lzaC1EdXRjaCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMXN0IGdlbiBNb3JvY2Nhbi1EdXRjaCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMm5kIGdlbiBNb3JvY2Nhbi1EdXRjaCIpKSwNCiAgICBtaWdyYXRpb25fYmFja2dyb3VuZF9zaW1wbGVfZmFjID0gY2FzZV93aGVuKA0KICAgICAgbWlncmF0aW9uX2JhY2tncm91bmRfZmFjID09ICIxc3QgZ2VuIFR1cmtpc2gtRHV0Y2giIH4gMiwNCiAgICAgIG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYyA9PSAiMm5kIGdlbiBUdXJraXNoLUR1dGNoIiB+IDIsDQogICAgICBtaWdyYXRpb25fYmFja2dyb3VuZF9mYWMgPT0gIjFzdCBnZW4gTW9yb2NjYW4tRHV0Y2giIH4gMywNCiAgICAgIG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYyA9PSAiMm5kIGdlbiBNb3JvY2Nhbi1EdXRjaCIgfiAzLA0KICAgICAgbWlncmF0aW9uX2JhY2tncm91bmRfZmFjID09ICJEdXRjaCBNYWpvcml0eSIgfiAxDQogICAgKSwNCiAgICBtaWdyYXRpb25fYmFja2dyb3VuZF9zaW1wbGVfZmFjID0gZmFjdG9yKA0KICAgICAgbWlncmF0aW9uX2JhY2tncm91bmRfc2ltcGxlX2ZhYywNCiAgICAgIGxldmVscyA9IDE6MywNCiAgICAgIGxhYmVscyA9IGMoIkR1dGNoIE1ham9yaXR5IiwgIlR1cmtpc2gtRHV0Y2giLCAiTW9yb2NjYW4tRHV0Y2giKQ0KICAgICksDQogICAgbWlncmFudF9nZW5lcmF0aW9uID0gY2FzZV93aGVuKA0KICAgICAgc3RyX2RldGVjdChtaWdyYXRpb25fYmFja2dyb3VuZF9mYWMsICIxc3QiKSB+IDEsDQogICAgICBzdHJfZGV0ZWN0KG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYywgIjJuZCIpIH4gMg0KICAgICkNCiAgKQ0KDQpgYGANCg0KIyMjIyBCb3hwbG90IA0KDQpDcmVhdGUgcGFuZWwgd2l0aCBjb21wbGV0ZSBncm91cHMgKG5vIGdlbmVyYXRpb24gZGlzdGluY3Rpb24pLg0KDQpgYGB7ciBjb21wYXJlIHNpbXBsZSBncm91cHMgc2l6ZX0NCiNzZXQgY3VzdG9tIHBhbGxldA0KcGFsIDwtIGMoIiM2NmMyYTUiLA0KICAgICAgICAgIiNmYzhkNjIiLA0KICAgICAgICAgIiM4ZGEwY2IiKQ0KDQojY3JlYXRlIHNpbXBsZSBib3hwbG90DQpib3hwbG90X3NpemVfc2ltcGxlX2dyb3VwcyA8LSBuZWxsc19kZiAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3JldihtaWdyYXRpb25fYmFja2dyb3VuZF9zaW1wbGVfZmFjKSwNCiAgICAgICAgICAgICB5ID0gbWVhbiwNCiAgICAgICAgICAgICBmaWxsID0gbWlncmF0aW9uX2JhY2tncm91bmRfc2ltcGxlX2ZhYywNCiAgICAgICAgICAgICBjb2xvdXIgPSBtaWdyYXRpb25fYmFja2dyb3VuZF9zaW1wbGVfZmFjDQogICAgICAgICAgICAgKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjYpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCgNCiAgICB2YWx1ZXMgPSBwYWwsDQogICAgYWVzdGhldGljcyA9IGMoImNvbG91ciIsICJmaWxsIikNCiAgKSArDQogICB0aGVtZSgNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0ZGRkZGRiIpLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkZGRkYiKSwNCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5IiksDQogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2FucyIsIHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC45LCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgpLA0KICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjksIGZhY2UgPSAiYm9sZCIpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksDQogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNBOUE5QTkiKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0ZGRkZGRiIpLA0KICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkZGRkZGIikNCiAgKSArDQogIGxhYnMoeSAgPSAiIiwNCiAgICAgICB4ID0gIiIpDQpgYGANCg0KQ3JlYXRlIHBhbmVsIHdpdGggZ2VuZXJhdGlvbiBkaXN0aW5jdGlvbi4NCg0KYGBge3IgY29tcGFyZSBldGhuaWMgc2l6ZSBib3hwbG90IGV4dGVuZGVkLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQ0KI3NldCBjdXN0b20gcGFsbGV0DQpwYWwgPC0gYygiI2ZjOGQ2MiIsDQogICAgICAgICAiI2ZjOGQ2MiIsDQogICAgICAgICAiIzhkYTBjYiIsDQogICAgICAgICAiIzhkYTBjYiIpDQoNCiNjcmVhdGUgZXh0ZW5kZWQgYm9wbG90DQpib3hwbG90X3NpemVfZXh0ZW5kZWRfZ3JvdXBzIDwtIG5lbGxzX2RmICU+JQ0KICBmaWx0ZXIobWlncmF0aW9uX2JhY2tncm91bmRfZmFjICE9ICJEdXRjaCBNYWpvcml0eSIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3JldihtaWdyYXRpb25fYmFja2dyb3VuZF9mYWMpLA0KICAgICAgICAgICAgIHkgPSBtZWFuLA0KICAgICAgICAgICAgIGZpbGwgPSBtaWdyYXRpb25fYmFja2dyb3VuZF9mYWMsDQogICAgICAgICAgICAgY29sb3VyID0gbWlncmF0aW9uX2JhY2tncm91bmRfZmFjDQogICAgICAgICAgICAgKSkgKw0KICBnZW9tX2JveHBsb3RfcGF0dGVybihhZXMocGF0dGVybl9kZW5zaXR5ID0gYXMuZmFjdG9yKG1pZ3JhbnRfZ2VuZXJhdGlvbikpLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNiwNCiAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJjaXJjbGUiDQogICAgICAgICAgICAgICAgICAgICAgICkgKw0KICBjb29yZF9mbGlwKCkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKA0KICAgIHZhbHVlcyA9IHBhbCwNCiAgICBhZXN0aGV0aWNzID0gYygiY29sb3VyIiwgImZpbGwiKQ0KICApICArDQogIHNjYWxlX3BhdHRlcm5fZGVuc2l0eV9tYW51YWwodmFsdWVzID0gYygiMSIgPSAwLCAiMiI9MC4xKSkgKw0KICAgdGhlbWUoDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkZGRkYiKSwNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkZGRkZGIiksDQogICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleSIpLA0KICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNhbnMiLCBzaXplID0gMTIpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuOSwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoKSwNCiAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC45LCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjQTlBOUE5IiksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkZGRkYiKSwNCiAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0ZGRkZGRiIpDQogICkgKw0KICBsYWJzKHkgID0gIiIsDQogICAgICAgeCA9ICIiKQ0KYGBgDQoNCkNvbWJpbmUgcGFuZWxzIGluIG11bHRpcGFuZWwgcGxvdC4NCg0KYGBge3IgY29tcGFyZSBzaXplIHBsb3RzfQ0KDQojIyBQYW5lbCBwbG90DQpob21fc2l6ZV9wYW5lbCA8LSBib3hwbG90X3NpemVfc2ltcGxlX2dyb3VwcyArIA0KICBib3hwbG90X3NpemVfZXh0ZW5kZWRfZ3JvdXBzICsgDQogIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0nYScsDQogICAgICAgICAgICAgICAgICB0YWdfcHJlZml4ID0gJygnLA0KICAgICAgICAgICAgICAgICAgdGFnX3N1ZmZpeCA9ICcpJykgKw0KICBwbG90X2xheW91dChuY29sID0gMSwNCiAgICAgICAgICAgICAgZ3VpZGVzID0gImNvbGxlY3QiLA0KICAgICAgICAgICAgICBoZWlnaHRzID0gYygxLDIpKSAmIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb249J25vbmUnKQ0KDQoNCmhvbV9zaXplX3BhbmVsDQoNCmdnc2F2ZShob21fc2l6ZV9wYW5lbCwNCiAgICAgICBmaWxlID0gImRhdGFfYW5hbHlzaXMvcGxvdHMvZGVzY3JpcHRpdmUvc2l6ZV9wbG90X3BhbmVsLmpwZyIsDQogICAgICAgd2lkdGggPSA4LA0KICAgICAgIGhlaWdodCA9IDUsDQogICAgICAgZHBpID0gMzIwKQ0KDQpgYGANCg0KIyBFdGhuaWMgSG9tb2dlbmVpdHkNCg0KIyMgTXVsdGlwYW5lbCBib3hwbG90DQoNClByZXBhcmUgZGF0YSBmb3IgZXRobmljIGhvbW9nZW5laXR5IHBsb3QuDQoNCmBgYHtyIGNyZWF0ZSBldGhuaWMgaG9tb2dlbmVpdHl9DQojd2VpZ2h0ZWQgYnkgbmFtZSBmcmVxdWVuY3kuDQpuZWxsc19kZiA8LSBuZWxsc19kZiAlPiUNCiAgbXV0YXRlKA0KICAgIHN1bV9kdXRjaF93ID0ga25vd3NfZGFhbl9ib3VuZGFyeS8yMjcwNCArIA0KICAgICAga25vd3Nfa2V2aW5fYm91bmRhcnkvMjMxNjcgKw0KICAgICAga25vd3NfZW1tYV9ib3VuZGFyeS8xODczMCArIA0KICAgICAga25vd3NfbGluZGFfYm91bmRhcnkvMjk5NTUgKyANCiAgICAgIGtub3dzX2FsYmVydF9ib3VuZGFyeS8zMTc2NyArIA0KICAgICAga25vd3NfZWR3aW5fYm91bmRhcnkvMjE4NjYgKyANCiAgICAgIGtub3dzX3dpbGxlbWluYV9ib3VuZGFyeS8xNzEzMyArIA0KICAgICAga25vd3NfaW5ncmlkX2JvdW5kYXJ5LzMxMzIzLA0KICAgIHN1bV90dXJraXNoX3cgPSBrbm93c19pYnJhaGltX2JvdW5kYXJ5LzIwOTkgKyANCiAgICAgIGtub3dzX2VzcmFfYm91bmRhcnkvMTg3OCwNCiAgICBzdW1fbW9yb2NjYW5fdyA9IGtub3dzX21vaGFtbWVkX2JvdW5kYXJ5LzEzNDQ4ICsgDQogICAgICBrbm93c19mYXRpbWFfYm91bmRhcnkvMjgwOCwNCiAgICBzdW1fdG90YWxfdyA9IHN1bV9kdXRjaF93ICsgc3VtX3R1cmtpc2hfdyArIHN1bV9tb3JvY2Nhbl93LA0KICAgIHBlcl9kdXRjaF93ID0gKHN1bV9kdXRjaF93IC8gc3VtX3RvdGFsX3cpICogMTAwLA0KICAgIHBlcl90dXJraXNoX3cgPSAoc3VtX3R1cmtpc2hfdyAvIHN1bV90b3RhbF93KSAqIDEwMCwNCiAgICBwZXJfbW9yb2NjYW5fdyA9IChzdW1fbW9yb2NjYW5fdyAvIHN1bV90b3RhbF93KSAqIDEwMA0KICApDQoNCiNhc3NpZ24gY29ycmVjdCBwZXJjZW50YWdlIGNvLWV0aG5pYyB0byBlYWNoIGdyb3VwDQpuZWxsc19kZiA8LSBuZWxsc19kZiAlPiUgDQogIG11dGF0ZShwZXJfaW5ncm91cF93ID0gY2FzZV93aGVuKA0KICAgIHN0cl9kZXRlY3QobWlncmF0aW9uX2JhY2tncm91bmRfZmFjLCAia2lzaCIpIH4gcGVyX3R1cmtpc2hfdywNCiAgICBzdHJfZGV0ZWN0KG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYywgIm9jY2FuIikgfiBwZXJfbW9yb2NjYW5fdywNCiAgICBtaWdyYXRpb25fYmFja2dyb3VuZF9mYWMgPT0gIkR1dGNoIE1ham9yaXR5IiB+IHBlcl9kdXRjaF93LA0KICAgIG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYyA9PSAiT3RoZXIiIH4gcGVyX2R1dGNoX3cNCiAgKSkNCg0KYGBgDQoNCkNyZWF0ZSBwYW5lbCB3aXRoIGNvbXBsZXRlIGdyb3VwcyAobm8gZ2VuZXJhdGlvbiBkaXN0aW5jdGlvbikuDQoNCmBgYHtyIGNvbXBhcmUgc2ltcGxlIGdyb3VwcyBob219DQojc2V0IGN1c3RvbSBwYWxsZXQNCnBhbCA8LSBjKCIjNjZjMmE1IiwNCiAgICAgICAgICIjZmM4ZDYyIiwNCiAgICAgICAgICIjOGRhMGNiIikNCg0KI2NyZWF0ZSBncmFwaCBmb3Igc2ltcGxlIGdyb3Vwcw0KYm94cGxvdF9ob21fc2ltcGxlX2dyb3VwcyA8LSBuZWxsc19kZiAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3JldihtaWdyYXRpb25fYmFja2dyb3VuZF9zaW1wbGVfZmFjKSwNCiAgICAgICAgICAgICB5ID0gcGVyX2luZ3JvdXBfdywNCiAgICAgICAgICAgICBmaWxsID0gbWlncmF0aW9uX2JhY2tncm91bmRfc2ltcGxlX2ZhYywNCiAgICAgICAgICAgICBjb2xvdXIgPSBtaWdyYXRpb25fYmFja2dyb3VuZF9zaW1wbGVfZmFjDQogICAgICAgICAgICAgKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjYpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCgNCiAgICB2YWx1ZXMgPSBwYWwsDQogICAgYWVzdGhldGljcyA9IGMoImNvbG91ciIsICJmaWxsIikNCiAgKSArDQogICB0aGVtZSgNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0ZGRkZGRiIpLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkZGRkYiKSwNCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5IiksDQogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2FucyIsIHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC45LCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dCgpLA0KICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjksIGZhY2UgPSAiYm9sZCIpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksDQogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNBOUE5QTkiKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0ZGRkZGRiIpLA0KICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkZGRkZGIikNCiAgKSArDQogIGxhYnMoeSAgPSAiIiwNCiAgICAgICB4ID0gIiIpDQpgYGANCg0KQ3JlYXRlIHBhbmVsIHdpdGggZ2VuZXJhdGlvbiBkaXN0aW5jdGlvbi4NCg0KYGBge3IgY29tcGFyZSBldGhuaWMgaG9tIGJveHBsb3QgZXh0ZW5kZWQsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTV9DQojc2V0IGN1c3RvbSBwYWxsZXQNCnBhbCA8LSBjKCIjZmM4ZDYyIiwNCiAgICAgICAgICIjZmM4ZDYyIiwNCiAgICAgICAgICIjOGRhMGNiIiwNCiAgICAgICAgICIjOGRhMGNiIikNCg0KI2NyZWF0ZSBib3hwbG90IGZvciBleHRlbmRlZCBncm91cHMNCmJveHBsb3RfaG9tX2V4dGVuZGVkX2dyb3VwcyA8LSBuZWxsc19kZiAlPiUNCiAgZmlsdGVyKG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYyAhPSAiRHV0Y2ggTWFqb3JpdHkiKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGZjdF9yZXYobWlncmF0aW9uX2JhY2tncm91bmRfZmFjKSwNCiAgICAgICAgICAgICB5ID0gcGVyX2luZ3JvdXBfdywNCiAgICAgICAgICAgICBjb2xvdXIgPSBtaWdyYXRpb25fYmFja2dyb3VuZF9mYWMsDQogICAgICAgICAgICAgZmlsbCA9IG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYywNCiAgICAgICAgICAgICApKSArDQogICAgZ2VvbV9ib3hwbG90X3BhdHRlcm4oYWVzKHBhdHRlcm5fZGVuc2l0eSA9IGFzLmZhY3RvcihtaWdyYW50X2dlbmVyYXRpb24pKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjYsDQogICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiY2lyY2xlIg0KICAgICAgICAgICAgICAgICAgICAgICApICsNCiAgY29vcmRfZmxpcCgpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCgNCiAgICB2YWx1ZXMgPSBwYWwsDQogICAgYWVzdGhldGljcyA9IGMoImNvbG91ciIsICJmaWxsIikNCiAgKSAgKw0KICBzY2FsZV9wYXR0ZXJuX2RlbnNpdHlfbWFudWFsKHZhbHVlcyA9IGMoIjEiID0gMCwgIjIiPTAuMSkpICsNCiAgIHRoZW1lKA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkZGRkZGIiksDQogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0ZGRkZGRiIpLA0KICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXkiKSwNCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzYW5zIiwgc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjksIGZhY2UgPSAiYm9sZCIpLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KCksDQogICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuOSwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0E5QTlBOSIpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkZGRkZGIiksDQogICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkZGRkYiKQ0KICApICsNCiAgbGFicyh5ICA9ICIiLA0KICAgICAgIHggPSAiIikNCmBgYA0KDQpDcmVhdGUgbXVsdGlwYW5lbCBwbG90Lg0KDQpgYGB7ciBjb21wYXJlIHBsb3RzIGhvbX0NCg0KIyMgUGFuZWwgcGxvdA0KaG9tX3Bsb3RfcGFuZWwgPC0gYm94cGxvdF9ob21fc2ltcGxlX2dyb3VwcyArIA0KICBib3hwbG90X2hvbV9leHRlbmRlZF9ncm91cHMgKyANCiAgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSdhJywNCiAgICAgICAgICAgICAgICAgIHRhZ19wcmVmaXggPSAnKCcsDQogICAgICAgICAgICAgICAgICB0YWdfc3VmZml4ID0gJyknKSArDQogIHBsb3RfbGF5b3V0KG5jb2wgPSAxLA0KICAgICAgICAgICAgICBndWlkZXMgPSAiY29sbGVjdCIsDQogICAgICAgICAgICAgIGhlaWdodHMgPSBjKDEsMikpICYgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpDQoNCiNzaG93IHBsb3QNCmhvbV9wbG90X3BhbmVsDQoNCiNzYXZlIHBsb3INCmdnc2F2ZShob21fcGxvdF9wYW5lbCwNCiAgICAgICBmaWxlID0gImRhdGFfYW5hbHlzaXMvcGxvdHMvZGVzY3JpcHRpdmUvaG9tX3Bsb3RfcGFuZWwuanBnIiwNCiAgICAgICB3aWR0aCA9IDgsDQogICAgICAgaGVpZ2h0ID0gNSwNCiAgICAgICBkcGkgPSAzMjApDQoNCmBgYA0KDQoNCiMjIE5hbWUgZGlmZmVyZW5jZXMNCg0KRm9yIGV2ZXJ5IHggKGZvciBub3cgbmFtZXMpIHdlIGNhbiBlc3RpbWF0ZSBhbiBOQiByZWdyZXNzaW9uIHRvIHNlZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kcy4gUGxlYXNlIG5vdGU6IHRoaXMgZG9lcyBub3QgdGFrZSBpbnRvIGFjY291bnQgbmFtaW5nIGZyZXF1ZW5jeSBpbiB0aGUgcG9wdWxhdGlvbi4gRGlmZmVyZW5jZXMgYmV0d2VlbiBkaWZmZXJlbnQgZXRobmljIGdyb3VwcyBtYXkgaW5kZWVkIGJlIGxhcmdlciBvciBzbWFsbGVyIGZvciBkaWZmZXJlbnQgbmFtZXMuIA0KDQoNCmBgYHtyIGFuYWx5c2lzIG9mIHggY2F0ZWdvcmllc30NCiMgdXNlIGEgbG9vcC4NCiNzZXQgdmFyX25hbWVzIHRvIHVzZSBpbiBsb29wLiANCnZhcmlhYmxlX25hbWVzX21vZGVsIDwtIGMoImtub3dzX2RhYW4iLA0KICAia25vd3Nfa2V2aW4iLCANCiAgImtub3dzX2Vkd2luIiwNCiAgImtub3dzX2FsYmVydCIsDQogICJrbm93c19lbW1hIiwNCiAgImtub3dzX2xpbmRhIiwNCiAgImtub3dzX2luZ3JpZCIsDQogICJrbm93c193aWxsZW1pbmEiLA0KICAia25vd3NfbW9oYW1tZWQiLA0KICAia25vd3NfZmF0aW1hIiwNCiAgImtub3dzX2licmFoaW0iLA0KICAia25vd3NfZXNyYSIpDQoNCiNzdGFydCBhbmFseXNpcyBsb29wDQptb2RlbF9yZXN1bHRzIDwtIGxpc3QoKQ0KDQpmb3IoaSBpbiAxOmxlbmd0aCh2YXJpYWJsZV9uYW1lc19tb2RlbCkpIHsjaSA9IDENCiAgZm0gPC0gYXMuZm9ybXVsYShwYXN0ZSh2YXJpYWJsZV9uYW1lc19tb2RlbFtbaV1dLCAifiIsICJtaWdyYXRpb25fYmFja2dyb3VuZF9mYWMiKSkNCiAgbW9kZWxfcmVzdWx0c1tbaV1dIDwtIE1BU1M6OmdsbS5uYihmbSwNCiAgICAgZGF0YSA9IG5lbGxzX2RmKQ0KfQ0KDQojY2xlYW4gb3V0cHV0IHdpdGggdGlkeSByDQptb2RlbF9yZXN1bHRzX2RmX2xpc3QgPC0gbW9kZWxfcmVzdWx0cyAlPiUgDQogIHB1cnJyOjptYXAoLnggPS4sIA0KICAgICAgICAgICAgIC5mID0gfiBicm9vbTo6dGlkeSgueCkpDQoNCiNhZGQgdmFyX25hbWVzIHRvIG1vZGVsX3Jlc3VsdHMNCmZvcihpIGluIDE6bGVuZ3RoKG1vZGVsX3Jlc3VsdHNfZGZfbGlzdCkpew0KICBtb2RlbF9yZXN1bHRzX2RmX2xpc3RbW2ldXSA8LSBtb2RlbF9yZXN1bHRzX2RmX2xpc3RbW2ldXSAlPiUgDQogICAgbXV0YXRlKGRlcF92YXIgPSB2YXJpYWJsZV9uYW1lc19tb2RlbFtpXSkNCn0NCg0KI2NvbWJpbmUgbW9kZWwgZGZzLg0KbW9kZWxfcmVzdWx0c19kZiA8LSBtb2RlbF9yZXN1bHRzX2RmX2xpc3QgJT4lDQogIGJpbmRfcm93cygpIA0KDQojc2V0IGNvcnJlY3QgdmFyaWFibGUgbmFtZXMNCm1vZGVsX3Jlc3VsdHNfZGYgPC0gbW9kZWxfcmVzdWx0c19kZiAlPiUNCiAgbXV0YXRlKA0KICAgIHRlcm0gPSBjYXNlX3doZW4oDQogICAgICBzdHJfZGV0ZWN0KHRlcm0sICIybmQgZ2VuIE1vcm9jY2FuIikgfiAiMm5kIGdlbiBNb3JvY2Nhbi1EdXRjaCIsDQogICAgICBzdHJfZGV0ZWN0KHRlcm0sICIybmQgZ2VuIFR1cmtpc2giKSB+ICIybmQgZ2VuIFR1cmtpc2gtRHV0Y2giLA0KICAgICAgc3RyX2RldGVjdCh0ZXJtLCAiMXN0IGdlbiBNb3JvY2NhbiIpIH4gIjFzdCBnZW4gTW9yb2NjYW4tRHV0Y2giLA0KICAgICAgc3RyX2RldGVjdCh0ZXJtLCAiMXN0IGdlbiBUdXJraXNoIikgfiAiMXN0IGdlbiBUdXJraXNoLUR1dGNoIiwNCiAgICAgIHRlcm0gPT0gIihJbnRlcmNlcHQpIiB+ICJJbnRlcmNlcHQiDQogICAgKQ0KICApDQoNCiNTZXQgY29ycmVjdCBuYW1lcw0KY29ycmVjdF9uYW1lcyA8LSBtb2RlbF9yZXN1bHRzX2RmICU+JSANCiAgcHVsbChkZXBfdmFyKSAlPiUgDQogIHN0cl9yZXBsYWNlKC4sIHBhdHRlcm4gPSAia25vd3NfIiwgcmVwbGFjZW1lbnQgPSAiIikgJT4lIA0KICBzdHJfdG9fdGl0bGUoKQ0KDQojZHJvcCBvbGQgbmFtZXMgYW5kIGFkZCB0aGUgY29ycmVjdCBuYW1lcw0KbW9kZWxfcmVzdWx0c19kZiA8LSBtb2RlbF9yZXN1bHRzX2RmICU+JSANCiAgc2VsZWN0KC1kZXBfdmFyKSAlPiUgDQogIG11dGF0ZShkZXBfdmFyID0gY29ycmVjdF9uYW1lcykNCg0KYGBgDQoNCiMjIFByZWRpY3RlZCBjb3VudHMgcGxvdCBmb3IgbmFtZXMgYW5kIGV0aG5pY2l0eQ0KDQpgYGB7ciBwcmVkIGNvdW50IG5hbWVzIH0NCnByZWRfbmJfZiA8LSBmdW5jdGlvbihuYl9tb2RlbCwgbmFtZXMpeyNuYl9tb2RlbCA9IG1vZGVsX3Jlc3VsdHNbWzFdXSwgbmFtZXMgPSB2YXJpYWJsZV9uYW1lc19tb2RlbFtbMV1dDQpwcmVkIDwtIHByZWRpY3Qob2JqZWN0ID0gbmJfbW9kZWwsDQogICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIsDQogICAgICAgICAgICAgICAgc2UuZml0ID0gVA0KICAgICAgICApDQoNCnBsb3RfZGYgPC0gbmVsbHNfZGYgJT4lIA0KICBzZWxlY3QoaWQsIG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYykgJT4lIA0KICBiaW5kX2NvbHMocHJlZCkgJT4lIA0KICBtdXRhdGUoZGVwX3ZhciA9IG5hbWVzKQ0KDQpyZXR1cm4ocGxvdF9kZikNCn0NCg0KbW9kZWxfcHJlZF9saXN0IDwtIG1hcDIoLnggPSBtb2RlbF9yZXN1bHRzLA0KICAgICAueSA9IHZhcmlhYmxlX25hbWVzX21vZGVsLA0KICAgICAuZiA9IH5wcmVkX25iX2YobmJfbW9kZWwgPSAueCwNCiAgICAgICAgICAgICAgICAgICAgIG5hbWVzID0gLnkpKQ0KDQptb2RlbF9wcmVkX2RmIDwtIG1vZGVsX3ByZWRfbGlzdCAlPiUgDQogIGJpbmRfcm93cygpDQoNCg0KI1NldCBjb3JyZWN0IG5hbWVzDQpjb3JyZWN0X25hbWVzIDwtIG1vZGVsX3ByZWRfZGYgJT4lIA0KICBwdWxsKGRlcF92YXIpICU+JSANCiAgc3RyX3JlcGxhY2UoLiwgcGF0dGVybiA9ICJrbm93c18iLCByZXBsYWNlbWVudCA9ICIiKSAlPiUgDQogIHN0cl90b190aXRsZSgpDQoNCg0KI2Ryb3Agb2xkIG5hbWVzIGFuZCBhZGQgdGhlIGNvcnJlY3QgbmFtZXMNCm1vZGVsX3ByZWRfZGYgPC0gbW9kZWxfcHJlZF9kZiAlPiUgDQogIHNlbGVjdCgtZGVwX3ZhcikgJT4lIA0KICBtdXRhdGUoZGVwX3ZhciA9IGNvcnJlY3RfbmFtZXMpDQpgYGANCg0KDQpgYGB7ciBldGhuaWMgbmFtZXMgcGxvdCBwcmVkfQ0KI3NldCBjdXN0b20gcGFsbGV0DQpwYWwgPC0gYygiIzY2YzJhNSIsDQogICAgICAgICAiI2ZjOGQ2MiIsDQogICAgICAgICAiI2ZjOGQ2MiIsDQogICAgICAgICAiIzhkYTBjYiIsDQogICAgICAgICAiIzhkYTBjYiIpDQoNCiNjcmV0ZSBwbG90IHdpdGggbWlub3JpdHkgbmFtZXMNCmV0aG5pY19uYW1lc19wcmVkX3Bsb3QgPC0gbW9kZWxfcHJlZF9kZiAlPiUgDQogIGZpbHRlcihkZXBfdmFyICVpbiUgYygiTW9oYW1tZWQiLA0KICAiRmF0aW1hIiwNCiAgIklicmFoaW0iLA0KICAiRXNyYSIpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGRlcF92YXIsDQogICAgICAgICAgICAgeSA9IGZpdCwNCiAgICAgICAgICAgICBzaGFwZSA9IG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYykpICsNCiAgZ2VvbV9saW5lcmFuZ2UoYWVzKHltaW4gPSBmaXQgLSAoc2UuZml0ICoxLjk2KSwNCiAgICAgICAgICAgICAgICAgICAgICB5bWF4ID0gIGZpdCArIChzZS5maXQgKjEuOTYpKSwNCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBtaWdyYXRpb25fYmFja2dyb3VuZF9mYWMsDQogICAgICAgICAgICAgICAgIGZpbGwgPSBtaWdyYXRpb25fYmFja2dyb3VuZF9mYWMpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKSArDQogIGZhY2V0X3dyYXAodmFycyhkZXBfdmFyKSwNCiAgICAgICAgICAgICBzY2FsZXMgPSAiZnJlZSIsDQogICAgICAgICAgICAgbmNvbCA9IDIpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCgNCiAgICB2YWx1ZXMgPSBwYWwsDQogICAgYWVzdGhldGljcyA9IGMoImNvbG91ciIsICJmaWxsIikNCiAgKSArDQogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIxLDIyLDI0LDIyLDI0KSkgKw0KICB0aGVtZSgNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0ZGRkZGRiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiYmxhY2siKSwNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkZGRkZGIiksDQogICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleSIpLA0KICAgIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gInNhbnMiLCBzaXplID0gMTIpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuOSwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuOSwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0ZGRkZGRiIpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkZGRkZGIiksDQogICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkZGRkYiKQ0KICApICsNCiAgICBsYWJzKHggPSAiIiwgDQogICAgICAgeSA9ICIiLA0KICAgICAgIGNvbG91ciA9ICIiLA0KICAgICAgIHNoYXBlID0gIiIsDQogICAgICAgZmlsbCA9ICIiDQogICAgICAgKQ0KYGBgDQoNCmBgYHtyIG5vbiBldGhuaWMgbmFtZXMgcGxvdCBwcmVkfQ0KI3NldCBjdXN0b20gcGFsbGV0DQpwYWwgPC0gYygiIzY2YzJhNSIsDQogICAgICAgICAiI2ZjOGQ2MiIsDQogICAgICAgICAiI2ZjOGQ2MiIsDQogICAgICAgICAiIzhkYTBjYiIsDQogICAgICAgICAiIzhkYTBjYiIpDQoNCiNjcmVhdGUgcGxvdCBmb3IgbWFqb3JpdHkgbmFtZXMNCm5vbl9ldGhuaWNfbmFtZXNfcHJlZF9wbG90IDwtIG1vZGVsX3ByZWRfZGYgJT4lIA0KICBmaWx0ZXIoIWRlcF92YXIgJWluJSBjKCJNb2hhbW1lZCIsDQogICJGYXRpbWEiLA0KICAiSWJyYWhpbSIsDQogICJFc3JhIikpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZGVwX3ZhciwNCiAgICAgICAgICAgICB5ID0gZml0LA0KICAgICAgICAgICAgIHNoYXBlID0gbWlncmF0aW9uX2JhY2tncm91bmRfZmFjKSkgKw0KICBnZW9tX2xpbmVyYW5nZShhZXMoeW1pbiA9IGZpdCAtIChzZS5maXQgKjEuOTYpLA0KICAgICAgICAgICAgICAgICAgICAgIHltYXggPSAgZml0ICsgKHNlLmZpdCAqMS45NikpLA0KICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYywNCiAgICAgICAgICAgICAgICAgZmlsbCA9IG1pZ3JhdGlvbl9iYWNrZ3JvdW5kX2ZhYyksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSkpICsNCiAgZmFjZXRfd3JhcCh2YXJzKGRlcF92YXIpLA0KICAgICAgICAgICAgIHNjYWxlcyA9ICJmcmVlX3giLA0KICAgICAgICAgICAgIG5jb2wgPSAyKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwoDQogICAgdmFsdWVzID0gcGFsLA0KICAgIGFlc3RoZXRpY3MgPSBjKCJjb2xvdXIiLCAiZmlsbCIpDQogICkgKw0KICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygyMSwyMiwyNCwyMiwyNCkpICsNCiAgdGhlbWUoDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkZGRkYiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIiksDQogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0ZGRkZGRiIpLA0KICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXkiKSwNCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzYW5zIiwgc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjksIGZhY2UgPSAiYm9sZCIpLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjksIGZhY2UgPSAiYm9sZCIpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksDQogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNGRkZGRkYiKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0ZGRkZGRiIpLA0KICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRkZGRkZGIikNCiAgKSArDQogICAgbGFicyh4ID0gIiIsIA0KICAgICAgIHkgPSAiIiwNCiAgICAgICBjb2xvdXIgPSAiIiwNCiAgICAgICBzaGFwZSA9ICIiLA0KICAgICAgIGZpbGwgPSAiIg0KICAgICAgICkNCg0KYGBgDQoNCmBgYHtyIHByZWQgbmFtZXMgcGFuZWwgcGxvdCwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9OH0NCiNDb21iaW5lIHBsb3RzIGluIG11bHRpcGFuZWwgcGxvdA0KbmFtZXNfcHJlZF9oZXRfcGFuZWwgPC0gZXRobmljX25hbWVzX3ByZWRfcGxvdCArDQogIG5vbl9ldGhuaWNfbmFtZXNfcHJlZF9wbG90ICsgDQogIHBsb3RfYW5ub3RhdGlvbigNCiAgICB0YWdfbGV2ZWxzID0gJ2EnLA0KICAgIHRhZ19wcmVmaXggPSAnKCcsDQogICAgdGFnX3N1ZmZpeCA9ICcpJw0KICApICsNCiAgcGxvdF9sYXlvdXQobmNvbCA9IDEsDQogICAgICAgICAgICAgIGhlaWdodHMgPSBjKDEsIDMpLA0KICAgICAgICAgICAgICBndWlkZXMgPSAnY29sbGVjdCcsDQogICkgJg0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC0yLC01KSwNCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICd2ZXJ0aWNhbCcpDQoNCiNwcmV2aWV3IHBsb3QNCm5hbWVzX3ByZWRfaGV0X3BhbmVsDQoNCiNzYXZlIHBsb3QNCmdnc2F2ZShuYW1lc19wcmVkX2hldF9wYW5lbCwNCiAgICAgICAgZmlsZSA9ICJkYXRhX2FuYWx5c2lzL3Bsb3RzL2Rlc2NyaXB0aXZlL25hbWVzX2hldF9wcmVkX3BhbmVsLmpwZyIsDQogICAgICAgd2lkdGggPSA2LA0KICAgICAgIGhlaWdodCA9IDgsDQogICAgICAgZHBpID0gMzIwKQ0KYGBgDQoNCg0KDQoNCg==


Copyright © 2024 Jeroense Thijmen