• 1 Getting started
    • 1.1 clean up
    • 1.2 general custom functions
    • 1.3 necessary packages
  • 2 Import
  • 3 Descriptives
  • 4 Observed segregation in neighborhoods and civic organizations
  • 5 LISS Neighborhood/organization choice experiment
    • 5.1 Marginal means
    • 5.2 Subgroup marginal means
      • 5.2.1 Sensitivity checks
        • 5.2.1.1 excluding religious organizations
        • 5.2.1.2 restrict sample to resemble that of experiment 3
        • 5.2.1.3 more fine-grained subgroups
    • 5.3 controlling for measurement error
    • 5.4 is the composition of one’s current setting predictive of choice behavior?
    • 5.5 additional analyses
      • 5.5.1 only the first setting
        • 5.5.2 subgroup specific travel time estimates
  • 6 TRIAL sports club choice experiment
    • 6.1 Subgroup marginal means
    • 6.2 use LISS-based bias correction
    • 6.3 sensitivity checks
      • 6.3.1 focus only on those with non-western migration background
      • 6.3.2 currently (not) involved in a sports club
  • References

1 Getting started

To copy the code, click the button in the upper right corner of the code-chunks.

1.1 clean up

rm(list = ls())
gc()


1.2 general custom functions

  • fpackage.check: Check if packages are installed (and install if not) in R
  • fsave: Function to save data with time stamp in correct directory
  • fload: Function to load R-objects under new names
  • fshowdf: Print objects (tibble / data.frame) nicely on screen in .Rmd
  • fcreate_exposure_means: Calculate isolation/exposure indices for the main analysis and for the robustness check
  • fcreate_exposure_means_robust
  • fcustom_legend: Create a custom legend
fpackage.check <- function(packages) {
    lapply(packages, FUN = function(x) {
        if (!require(x, character.only = TRUE)) {
            install.packages(x, dependencies = TRUE)
            library(x, character.only = TRUE)
        }
    })
}

fsave <- function(x, location = "./data/processed/") {
    if (location == "./data/processed/") {
        ifelse(!dir.exists("data"), dir.create("data"), FALSE)
        ifelse(!dir.exists("data/processed"), dir.create("data/processed"), FALSE)
    }

    object = deparse(substitute(x))
    datename <- substr(gsub("[:-]", "", Sys.time()), 1, 8)
    totalname <- paste(location, object, "_", datename, ".rda", sep = "")
    assign(eval(object), x, envir = .GlobalEnv)
    print(paste("SAVED: ", totalname, sep = ""))
    save(list = object, file = totalname)
}

fload <- function(fileName) {
    load(fileName)
    get(ls()[ls() != "fileName"])
}

fshowdf <- function(x, caption = NULL, digits = 2, footnote = NULL, ...) {
    knitr::kable(x, digits = digits, "html", caption = caption, ...) %>%
        kableExtra::footnote(general = footnote) %>%
        kableExtra::kable_styling(bootstrap_options = c("striped", "hover")) %>%
        kableExtra::scroll_box(width = "100%", height = "300px")
}

fcreate_exposure_means <- function(dat, dim_var, comp_var, cont_var, g1, g2, setting, datasource) {
    ii_dim_mean <- dat %>%
        filter(!is.na({
            {
                comp_var
            }
        }) & !is.na({
            {
                cont_var
            }
        })) %>%
        summarize(ii_comp_mean = mean({
            {
                comp_var
            }
        }) * 0.01, ii_cont_mean = mean({
            {
                cont_var
            }
        }) * 0.01)
    ii_dim_g1 <- dat %>%
        filter(!is.na({
            {
                comp_var
            }
        }) & !is.na({
            {
                cont_var
            }
        }) & {
            {
                dim_var
            }
        } == g1) %>%
        summarize(ii_comp_g1 = mean({
            {
                comp_var
            }
        }) * 0.01, ii_cont_g1 = mean({
            {
                cont_var
            }
        }) * 0.01)
    ii_dim_g2 <- dat %>%
        filter(!is.na({
            {
                comp_var
            }
        }) & !is.na({
            {
                cont_var
            }
        }) & {
            {
                dim_var
            }
        } == g2) %>%
        summarize(ii_comp_g2 = mean({
            {
                comp_var
            }
        }) * 0.01, ii_cont_g2 = mean({
            {
                cont_var
            }
        }) * 0.01)
    ii_setting <- paste0(setting)
    ii_dimension <- paste0("Share ", g1)
    ii_datatype <- paste0(datasource)
    ii <- cbind(ii_dimension, ii_setting, ii_datatype, ii_dim_mean, ii_dim_g1, ii_dim_g2)
}

fcreate_exposure_means_robust <- function(dat, dim_var, comp_var, comp_buurt, cont_var, g1, g2, setting) {
    ii_dim_mean <- dat %>%
        filter(!is.na({
            {
                comp_var
            }
        }) & !is.na({
            {
                cont_var
            }
        }) & !is.na({
            {
                comp_buurt
            }
        })) %>%
        summarize(ii_comp_mean = mean({
            {
                comp_var
            }
        }) * 0.01, ii_compbuurt_mean = mean({
            {
                comp_buurt
            }
        }) * 0.01)
    ii_dim_g1 <- dat %>%
        filter(!is.na({
            {
                comp_var
            }
        }) & !is.na({
            {
                cont_var
            }
        }) & !is.na({
            {
                comp_buurt
            }
        }) & {
            {
                dim_var
            }
        } == g1) %>%
        summarize(ii_comp_g1 = mean({
            {
                comp_var
            }
        }) * 0.01, ii_compbuurt_g1 = mean({
            {
                comp_buurt
            }
        }) * 0.01)
    ii_dim_g2 <- dat %>%
        filter(!is.na({
            {
                comp_var
            }
        }) & !is.na({
            {
                cont_var
            }
        }) & !is.na({
            {
                comp_buurt
            }
        }) & {
            {
                dim_var
            }
        } == g2) %>%
        summarize(ii_comp_g2 = mean({
            {
                comp_var
            }
        }) * 0.01, ii_compbuurt_g2 = mean({
            {
                comp_buurt
            }
        }) * 0.01)
    ii_setting <- paste0(setting)
    ii_dimension <- paste0("Share ", g1)
    ii <- cbind(ii_dimension, ii_setting, ii_dim_mean, ii_dim_g1, ii_dim_g2)
}

fcustom_legend <- function(text_entry1, text_entry2) {
    legend <- grobTree(pointsGrob(x = unit(c(0.02, 0.07), "npc"), y = unit(c(0.8, 0.8), "npc"), pch = c(22,
        19), gp = gpar(col = "#56B4E9", fill = "#56B4E9")), textGrob(text_entry1, x = unit(0.11, "npc"),
        y = unit(0.8, "npc"), just = "left", gp = gpar(fontsize = 11)), pointsGrob(x = unit(0.02, "npc"),
        y = unit(0.5, "npc"), pch = 22, gp = gpar(col = "#999999", fill = "#999999")), textGrob("Average intra-setting exposure among\nall respondents",
        x = unit(0.11, "npc"), y = unit(0.5, "npc"), just = "left", gp = gpar(fontsize = 11)), pointsGrob(x = unit(c(0.02,
        0.07), "npc"), y = unit(c(0.2, 0.2), "npc"), pch = c(22, 19), gp = gpar(col = "#E69F00", fill = "#E69F00")),
        textGrob(text_entry2, x = unit(0.11, "npc"), y = unit(0.2, "npc"), just = "left", gp = gpar(fontsize = 11)))
    return(legend)
}


1.3 necessary packages

  • tidyverse: data wrangling
  • cregg: calculate marginal means and average marginal component effects
  • ggplot2, ggtext, cowplot, patchwork, ggpubr, ggh4x, gridtext, grid: data visualization
packages = c("tidyverse", "cregg", "ggplot2", "ggtext", "cowplot", "patchwork", "ggpubr", "ggh4x", "gridtext",
    "grid")
fpackage.check(packages)
rm(packages)



2 Import

Import data-sets, created for the LISS and TRIAL choice experiments.

You may obtain it by downloading:

# list.files('./data/processed')
today <- gsub("-", "", Sys.Date())
today <- "20250530"  #latest updated dataset

fload(paste0("./data/processed/", today, "conjoint_liss.Rda")) %>%
    sjlabelled::unlabel(.) -> df

fload(paste0("./data/processed/", today, "conjoint_trial.Rda")) %>%
    sjlabelled::unlabel(.) -> df2



3 Descriptives

# first get the respondents who were involved in the choice tasks
# experiment 1 (nbh)
test <- df[, c("id", "enbh_chosen", "enbh_set")] #subset id, set and choice
test$id_set <- paste0(test$id, "x", test$enbh_set) #combine id and set
test <- test[!is.na(test$enbh_chosen),] #remove choice tasks not fulfilled
ids1 <- unique(test$id) # get ids of respondents in experiment 1
#length(ids1) # N=2733

# experiment 2 (orgs)
test <- df[, c("id", "eciv_chosen", "eciv_set")] #subset id, set and choice
test$id_set <- paste0(test$id, "x", test$eciv_set) #combine id and set
test <- test[!is.na(test$eciv_chosen),] #remove choice tasks not fulfilled
ids2 <- unique(test$id) # get ids of respondents in experiment 2
#length(ids2) # N=2743

ids <- unique(c(ids1, ids2))
#length(ids) #N_total = 2750.

# subset
df %>%
  select(id, sex, edu, age, eth_dtm, ociv_mostimp_type) %>%
  filter(id %in% ids) %>%
  mutate(
    # ethnicity dummies
    tm = ifelse(eth_dtm == "Turkish/Moroccan", 1, 0),
    dutch = ifelse(eth_dtm == "Dutch", 1, 0),
    e_other = ifelse(is.na(eth_dtm), 1, 0),

    # gender dummies
    male = ifelse(sex == "male", 1, 0),
    female = ifelse(sex == "female", 1, 0),
    g_other = ifelse(is.na(sex), 1, 0),

    # education dummies
    college = ifelse(edu == "college degree", 1, 0),
    no_college = ifelse(!is.na(edu) & edu != "college degree", 1, 0),
    educ_missing = ifelse(is.na(edu), 1, 0),

    # age dummies
    age50plus = ifelse(age == "50 or older", 1, 0),
    agebelow50 = ifelse(age == "under 50", 1, 0),

    # organization type dummies
    religious = ifelse(ociv_mostimp_type == "Religious", 1, 0),
    union = ifelse(ociv_mostimp_type == "Union", 1, 0),
    sports = ifelse(ociv_mostimp_type == "Sports", 1, 0),
    environmental = ifelse(ociv_mostimp_type == "Environmental", 1, 0),
    consumer = ifelse(ociv_mostimp_type == "Consumer", 1, 0),
    cultural = ifelse(ociv_mostimp_type == "Cultural", 1, 0),
    professional = ifelse(ociv_mostimp_type == "Professional", 1, 0),
    social = ifelse(ociv_mostimp_type == "Social", 1, 0),
    political = ifelse(ociv_mostimp_type == "Political", 1, 0),
    humanitarian = ifelse(ociv_mostimp_type == "Humanitarian", 1, 0),
    educational = ifelse(ociv_mostimp_type == "Educational", 1, 0),
    migrants = ifelse(ociv_mostimp_type == "Migrants", 1, 0),
    other_org = ifelse(ociv_mostimp_type == "Other", 1, 0),
    org_missing = ifelse(is.na(ociv_mostimp_type), 1, 0)
  ) %>%
  # replace NAs in dummy variables
  mutate(across(
    c(tm, dutch, e_other, male, female, g_other, college, no_college,
      educ_missing,
      age50plus, agebelow50, educ_missing,
      religious, other_org, union, sports, environmental, consumer,
      cultural, professional, social, political, humanitarian,
      educational, migrants, org_missing),
    ~replace_na(., 0)
  )) %>%
  distinct(id, .keep_all = TRUE) %>%
  select(-c(id, sex, edu, age, eth_dtm, ociv_mostimp_type)) -> test

test %>%
  psych::describe() %>%
  .[, c(2, 3, 4, 8, 9)] %>%
  `rownames<-`(c(
    "Turkish or Moroccan migration background", "Dutch background", "Other migration background", 
    "Male", "Female", "Other / missing gender",
    "College degree", "No college degree", "Education missing",
    "Aged 50+", "Aged under 50",
    "Religious org", "Union", "Sports", "Environmental",
    "Consumer", "Cultural", "Professional", "Social", "Political",
    "Humanitarian", "Educational", "Migrants", "Other type", "Missing"
  )) -> des1

des1 %>%
  fshowdf(caption = "Summary of background and organization type variables") 
Summary of background and organization type variables
n mean sd min max
Turkish or Moroccan migration background 2750 0.02 0.14 0 1
Dutch background 2750 0.83 0.38 0 1
Other migration background 2750 0.15 0.36 0 1
Male 2750 0.51 0.50 0 1
Female 2750 0.49 0.50 0 1
Other / missing gender 2750 0.00 0.04 0 1
College degree 2750 0.46 0.50 0 1
No college degree 2750 0.53 0.50 0 1
Education missing 2750 0.01 0.11 0 1
Aged 50+ 2750 0.68 0.47 0 1
Aged under 50 2750 0.32 0.47 0 1
Religious org 2750 0.13 0.33 0 1
Union 2750 0.06 0.23 0 1
Sports 2750 0.45 0.50 0 1
Environmental 2750 0.03 0.17 0 1
Consumer 2750 0.06 0.23 0 1
Cultural 2750 0.11 0.31 0 1
Professional 2750 0.02 0.14 0 1
Social 2750 0.04 0.20 0 1
Political 2750 0.02 0.13 0 1
Humanitarian 2750 0.02 0.14 0 1
Educational 2750 0.02 0.14 0 1
Migrants 2750 0.00 0.07 0 1
Other type 2750 0.04 0.21 0 1
Missing 2750 0.00 0.03 0 1
#str(des1)
#write.csv(des1, "descriptives_liss.csv", row.names = TRUE)
df2 %>%
    select(id, GESLACHT2, LEEFTIJD, tert_educ, migration) %>%
    mutate(male = ifelse(GESLACHT2 == 1, 1, 0), female = ifelse(GESLACHT2 == 2, 1, 0), g_other = ifelse(GESLACHT2 ==
        3 | is.na(GESLACHT2), 1, 0), dutch = ifelse(migration == 0, 1, 0), non_dutch = ifelse(migration ==
        1, 1, 0), no_tert_educ = ifelse(tert_educ == 0, 1, 0)) %>%
    mutate(across(c(male, female), ~replace_na(., 0))) %>%
    distinct(id, .keep_all = TRUE) %>%
    select(male, female, g_other, LEEFTIJD, tert_educ, no_tert_educ, dutch, non_dutch) %>%
    psych::describe() %>%
    .[, c(2, 3, 4, 8, 9)] %>%
    `rownames<-`(c("Male", "Female", "Other / missing gender", "Age", "College degree", "No college degree",
        "Dutch background", "Migration background")) -> des2

des2 %>%
    fshowdf(caption = "Summary of background variables")
Summary of background variables
n mean sd min max
Male 2707 0.33 0.47 0 1
Female 2707 0.66 0.47 0 1
Other / missing gender 2707 0.01 0.07 0 1
Age 2707 31.37 5.61 18 41
College degree 2707 0.76 0.42 0 1
No college degree 2707 0.24 0.42 0 1
Dutch background 2707 0.89 0.31 0 1
Migration background 2707 0.11 0.31 0 1
# str(des2) write.csv(des2, 'descriptives_trial.csv', row.names = TRUE)



4 Observed segregation in neighborhoods and civic organizations

df <- df %>%
    mutate(edu_f = factor(edu, levels = c("no college degree", "college degree")), sex_f = factor(sex,
        levels = c("male", "female")), age_f = factor(age, levels = c("under 50", "50 or older")), eth_dtm_f = factor(eth_dtm,
        levels = c("Dutch", "Turkish/Moroccan")))

# Isolation and Exposure indices for different dimensions across different settings #### Calculate
# Isolation and Exposure indices for all org types pooled:
ei_age_nbh <- fcreate_exposure_means(dat = df, dim_var = age, g1 = "50 or older", g2 = "under 50", comp_var = onbh_comp_age,
    cont_var = onbh_cont_age, setting = "neighborhoods", datasource = "subjective")
ei_age_civ <- fcreate_exposure_means(dat = df, dim_var = age, g1 = "50 or older", g2 = "under 50", comp_var = ociv_comp_age,
    cont_var = ociv_cont_age, setting = "civic organizations", datasource = "subjective")
ei_edu_nbh <- fcreate_exposure_means(dat = df, dim_var = edu, g1 = "college degree", g2 = "no college degree",
    comp_var = onbh_comp_edu, cont_var = onbh_cont_edu, setting = "neighborhoods", datasource = "subjective")
ei_edu_civ <- fcreate_exposure_means(dat = df, dim_var = edu, g1 = "college degree", g2 = "no college degree",
    comp_var = ociv_comp_edu, cont_var = ociv_cont_edu, setting = "civic organizations", datasource = "subjective")
ei_eth_nbh <- fcreate_exposure_means(dat = df, dim_var = eth_dtm, g1 = "Turkish/Moroccan", g2 = "Dutch",
    comp_var = onbh_comp_eth, cont_var = onbh_cont_eth, setting = "neighborhoods", datasource = "subjective")
ei_eth_civ <- fcreate_exposure_means(dat = df, dim_var = eth_dtm, g1 = "Turkish/Moroccan", g2 = "Dutch",
    comp_var = ociv_comp_eth, cont_var = ociv_cont_eth, setting = "civic organizations", datasource = "subjective")

ei <- rbind(ei_age_nbh, ei_age_civ, ei_edu_nbh, ei_edu_civ, ei_eth_nbh, ei_eth_civ) %>%
    mutate(ii_setting = factor(ii_setting, levels = c("neighborhoods", "civic organizations")))

# Observational Data - Figures #### needed for all observational figures ----
data <- data.frame(x = c(1, 2, 3), y = c(1, 2, 3))  # Create dummy data

legend_grob_edu <- fcustom_legend(text_entry1 = "Intra-setting exposure / contacts among\nthose with a college degree",
    text_entry2 = "Intra-setting exposure / contacts among\nthose without a college degree")
legend_grob_eth <- fcustom_legend(text_entry1 = "Intra-setting exposure / contacts among\nthose with a Turkish/Moroccan background",
    text_entry2 = "Intra-setting exposure / contacts among\nthose with no migration background")
legend_grob_age <- fcustom_legend(text_entry1 = "Intra-setting exposure / contacts among\nthose 50 years or older",
    text_entry2 = "Intra-setting exposure / contacts among\nthose below 50 years")

# Create a blank plot to hold the legend
legend_plot_edu <- ggplot() + annotation_custom(legend_grob_edu) + theme_void() + theme(plot.margin = margin(0,
    0, 0, 0, "cm"))
legend_plot_eth <- ggplot() + annotation_custom(legend_grob_eth) + theme_void() + theme(plot.margin = margin(0,
    0, 0, 0, "cm"))
legend_plot_age <- ggplot() + annotation_custom(legend_grob_age) + theme_void() + theme(plot.margin = margin(0,
    0, 0, 0, "cm"))

# arrangement of figure panels
fig1design <- "ABC
               ABC
               ABC
               DEF"

## Figure 1 - Main text ----
fig1_v4_age <- ggplot(ei[ei$ii_dimension == "Share 50 or older", ]) + geom_segment(aes(y = ii_cont_g2,
    yend = ii_cont_g1, x = ii_setting, xend = ii_setting), color = "grey") + geom_segment(aes(y = ii_cont_g2,
    yend = ii_comp_g1, x = ii_setting, xend = ii_setting), color = "grey") + geom_point(aes(y = ii_comp_mean,
    x = ii_setting), color = "#999999", shape = "square", size = 3) + geom_point(aes(y = ii_comp_g1,
    x = ii_setting), color = "#56B4E9", shape = "square", size = 3) + geom_point(aes(y = ii_comp_g2,
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + x
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + ii_setting),
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + color
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + "#E69F00",
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + shape
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + "square",
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + size
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + 3)
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + +
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + #geom_point(aes(x=ii_setting,
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + y=ii_cont_mean),
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + color='red',
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + shape
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + 'circle',
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + size=4)
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + +
geom_point(aes(y = ii_cont_g1, x = ii_setting), color = "#56B4E9", shape = "circle", size = 3.2) + geom_point(aes(y = ii_cont_g2,
    x = ii_setting), color = "#E69F00", shape = "circle", size = 3.2) + scale_y_continuous(breaks = seq(0.2,
    0.7, 0.1), limits = c(0.2, 0.7), labels = scales::percent) + facet_wrap(~ii_dimension, labeller = labeller(ii_dimension = c(`Share 50 or older` = "Share of people aged 50 years or older"))) +
    theme(axis.ticks.x = element_blank(), axis.text = element_text(size = 12), panel.background = element_rect(fill = "white",
        color = "black"), panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
        panel.grid.major.y = element_line(color = "black"), plot.title = element_text(size = 12)) + ylab("") +
    xlab("")

fig1_v4_eth <- ggplot(ei[ei$ii_dimension == "Share Turkish/Moroccan", ]) + geom_segment(aes(y = ii_cont_g2,
    yend = ii_cont_g1, x = ii_setting, xend = ii_setting), color = "grey") + geom_segment(aes(y = ii_cont_g2,
    yend = ii_comp_g1, x = ii_setting, xend = ii_setting), color = "grey") + geom_point(aes(y = ii_comp_mean,
    x = ii_setting), color = "#999999", shape = "square", size = 3) + geom_point(aes(y = ii_comp_g1,
    x = ii_setting), color = "#56B4E9", shape = "square", size = 3) + geom_point(aes(y = ii_comp_g2,
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + x
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + ii_setting),
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + color
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + "#E69F00",
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + shape
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + "square",
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + size
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + 3)
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + +
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + #geom_point(aes(x=ii_setting,
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + y=ii_cont_mean),
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + color='red',
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + shape
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + 'circle',
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + size=4)
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + +
geom_point(aes(y = ii_cont_g1, x = ii_setting), color = "#56B4E9", shape = "circle", size = 3.2) + geom_point(aes(y = ii_cont_g2,
    x = ii_setting), color = "#E69F00", shape = "circle", size = 3.2) + scale_y_continuous(breaks = seq(0,
    0.5, 0.1), limits = c(0, 0.5), labels = scales::percent) + facet_wrap(~ii_dimension, labeller = labeller(ii_dimension = c(`Share Turkish/Moroccan` = "Share of people with a Turkish/Moroccan background"))) +
    theme(axis.ticks.x = element_blank(), axis.text = element_text(size = 12), panel.background = element_rect(fill = "white",
        color = "black"), panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
        panel.grid.major.y = element_line(color = "black"), plot.title = element_text(size = 12)) + ylab("") +
    xlab("")

fig1_v4_edu <- ggplot(ei[ei$ii_dimension == "Share college degree", ]) + geom_segment(aes(y = ii_cont_g2,
    yend = ii_cont_g1, x = ii_setting, xend = ii_setting), color = "grey") + geom_segment(aes(y = ii_cont_g2,
    yend = ii_comp_g1, x = ii_setting, xend = ii_setting), color = "grey") + geom_point(aes(y = ii_comp_mean,
    x = ii_setting), color = "#999999", shape = "square", size = 3) + geom_point(aes(y = ii_comp_g1,
    x = ii_setting), color = "#56B4E9", shape = "square", size = 3) + geom_point(aes(y = ii_comp_g2,
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + x
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + ii_setting),
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + color
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + "#E69F00",
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + shape
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + "square",
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + size
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + 3)
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + +
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + #geom_point(aes(x=ii_setting,
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + y=ii_cont_mean),
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + color='red',
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + shape
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + =
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + 'circle',
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + size=4)
    x = ii_setting), color = "#E69F00", shape = "square", size = 3) + #geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) + +
geom_point(aes(y = ii_cont_g1, x = ii_setting), color = "#56B4E9", shape = "circle", size = 3.2) + geom_point(aes(y = ii_cont_g2,
    x = ii_setting), color = "#E69F00", shape = "circle", size = 3.2) + scale_y_continuous(breaks = seq(0.2,
    0.7, 0.1), limits = c(0.2, 0.7), labels = scales::percent) + facet_wrap(~ii_dimension, labeller = labeller(ii_dimension = c(`Share college degree` = "Share of people with a college degree"))) +
    theme(axis.ticks.x = element_blank(), axis.text = element_text(size = 12), panel.background = element_rect(fill = "white",
        color = "black"), panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
        panel.grid.major.y = element_line(color = "black"), plot.title = element_text(size = 12)) + ylab("") +
    xlab("")

figure_1 <- wrap_plots(fig1_v4_age, fig1_v4_eth, fig1_v4_edu, legend_plot_age, legend_plot_eth, legend_plot_edu,
    byrow = T, design = fig1design) + plot_annotation(tag_levels = list(c("a", "b", "c", "", "", ""))) &
    theme(plot.tag = element_text(face = "bold"))
# plot(figure_1)

# ggsave(figure_1, file = './figures/figure01_main.png', height = 7, width = 12.5)

## Figure 1 - Robustness check: sports clubs vs other civic organizations ----
liss_sport <- df %>%
    filter(ociv_mostimp_type == "Sports")
liss_civoth <- df %>%
    filter(ociv_mostimp_type != "Sports")

ei_age_sport <- fcreate_exposure_means(dat = liss_sport, dim_var = age, g1 = "50 or older", g2 = "under 50",
    comp_var = ociv_comp_age, cont_var = ociv_cont_age, setting = "sport clubs", datasource = "subjective")
ei_age_civoth <- fcreate_exposure_means(dat = liss_civoth, dim_var = age, g1 = "50 or older", g2 = "under 50",
    comp_var = ociv_comp_age, cont_var = ociv_cont_age, setting = "other civic organizations", datasource = "subjective")
ei_edu_sport <- fcreate_exposure_means(dat = liss_sport, dim_var = edu, g1 = "college degree", g2 = "no college degree",
    comp_var = ociv_comp_edu, cont_var = ociv_cont_edu, setting = "sport clubs", datasource = "subjective")
ei_edu_civoth <- fcreate_exposure_means(dat = liss_civoth, dim_var = edu, g1 = "college degree", g2 = "no college degree",
    comp_var = ociv_comp_edu, cont_var = ociv_cont_edu, setting = "other civic organizations", datasource = "subjective")
ei_eth_sport <- fcreate_exposure_means(dat = liss_sport, dim_var = eth_dtm, g1 = "Turkish/Moroccan",
    g2 = "Dutch", comp_var = ociv_comp_eth, cont_var = ociv_cont_eth, setting = "sport clubs", datasource = "subjective")
ei_eth_civoth <- fcreate_exposure_means(dat = liss_civoth, dim_var = eth_dtm, g1 = "Turkish/Moroccan",
    g2 = "Dutch", comp_var = ociv_comp_eth, cont_var = ociv_cont_eth, setting = "other civic organizations",
    datasource = "subjective")
ei_sport_civoth <- rbind(ei_age_sport, ei_age_civoth, ei_edu_sport, ei_edu_civoth, ei_eth_sport, ei_eth_civoth)

ei_sport_civoth <- ei_sport_civoth %>%
    mutate(ii_setting = factor(ii_setting, levels = c("sport clubs", "other civic organizations")))  #get order of setting variable right. 

fig1_v4_age_sport_civoth <- ggplot(ei_sport_civoth[ei_sport_civoth$ii_dimension == "Share 50 or older",
    ]) + geom_segment(aes(y = ii_cont_g2, yend = ii_cont_g1, x = ii_setting, xend = ii_setting), color = "grey") +
    geom_segment(aes(y = ii_cont_g2, yend = ii_comp_g1, x = ii_setting, xend = ii_setting), color = "grey") +
    geom_point(aes(y = ii_comp_mean, x = ii_setting), color = "#999999", shape = "square", size = 3) +
    geom_point(aes(y = ii_comp_g1, x = ii_setting), color = "#56B4E9", shape = "square", size = 3) +
    geom_point(aes(y = ii_comp_g2, x = ii_setting), color = "#E69F00", shape = "square", size = 3) +
    # geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) +
geom_point(aes(y = ii_cont_g1, x = ii_setting), color = "#56B4E9", shape = "circle", size = 3.2) + geom_point(aes(y = ii_cont_g2,
    x = ii_setting), color = "#E69F00", shape = "circle", size = 3.2) + scale_y_continuous(breaks = seq(0.2,
    0.71, 0.1), limits = c(0.2, 0.71), labels = scales::percent) + facet_wrap(~ii_dimension, labeller = labeller(ii_dimension = c(`Share 50 or older` = "Share of people aged 50 years or older"))) +
    theme(axis.ticks.x = element_blank(), axis.text = element_text(size = 12), panel.background = element_rect(fill = "white",
        color = "black"), panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
        panel.grid.major.y = element_line(color = "black"), plot.title = element_text(size = 12)) + ylab("") +
    xlab("")

fig1_v4_eth_sport_civoth <- ggplot(ei_sport_civoth[ei_sport_civoth$ii_dimension == "Share Turkish/Moroccan",
    ]) + geom_segment(aes(y = ii_cont_g2, yend = ii_cont_g1, x = ii_setting, xend = ii_setting), color = "grey") +
    geom_segment(aes(y = ii_cont_g2, yend = ii_comp_g1, x = ii_setting, xend = ii_setting), color = "grey") +
    geom_point(aes(y = ii_comp_mean, x = ii_setting), color = "#999999", shape = "square", size = 3) +
    geom_point(aes(y = ii_comp_g1, x = ii_setting), color = "#56B4E9", shape = "square", size = 3) +
    geom_point(aes(y = ii_comp_g2, x = ii_setting), color = "#E69F00", shape = "square", size = 3) +
    # geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) +
geom_point(aes(y = ii_cont_g1, x = ii_setting), color = "#56B4E9", shape = "circle", size = 3.2) + geom_point(aes(y = ii_cont_g2,
    x = ii_setting), color = "#E69F00", shape = "circle", size = 3.2) + scale_y_continuous(breaks = seq(0,
    0.51, 0.1), limits = c(0, 0.51), labels = scales::percent) + facet_wrap(~ii_dimension, labeller = labeller(ii_dimension = c(`Share Turkish/Moroccan` = "Share of people with a Turkish/Moroccan background"))) +
    theme(axis.ticks.x = element_blank(), axis.text = element_text(size = 12), panel.background = element_rect(fill = "white",
        color = "black"), panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
        panel.grid.major.y = element_line(color = "black"), plot.title = element_text(size = 12)) + ylab("") +
    xlab("")

fig1_v4_edu_sport_civoth <- ggplot(ei_sport_civoth[ei_sport_civoth$ii_dimension == "Share college degree",
    ]) + geom_segment(aes(y = ii_cont_g2, yend = ii_cont_g1, x = ii_setting, xend = ii_setting), color = "grey") +
    geom_segment(aes(y = ii_cont_g2, yend = ii_comp_g1, x = ii_setting, xend = ii_setting), color = "grey") +
    geom_point(aes(y = ii_comp_mean, x = ii_setting), color = "#999999", shape = "square", size = 3) +
    geom_point(aes(y = ii_comp_g1, x = ii_setting), color = "#56B4E9", shape = "square", size = 3) +
    geom_point(aes(y = ii_comp_g2, x = ii_setting), color = "#E69F00", shape = "square", size = 3) +
    # geom_point(aes(x=ii_setting, y=ii_cont_mean), color='red', shape = 'circle', size=4) +
geom_point(aes(y = ii_cont_g1, x = ii_setting), color = "#56B4E9", shape = "circle", size = 3.2) + geom_point(aes(y = ii_cont_g2,
    x = ii_setting), color = "#E69F00", shape = "circle", size = 3.2) + scale_y_continuous(breaks = seq(0.2,
    0.71, 0.1), limits = c(0.2, 0.71), labels = scales::percent) + facet_wrap(~ii_dimension, labeller = labeller(ii_dimension = c(`Share college degree` = "Share of people with a college degree"))) +
    theme(axis.ticks.x = element_blank(), axis.text = element_text(size = 12), panel.background = element_rect(fill = "white",
        color = "black"), panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank(),
        panel.grid.major.y = element_line(color = "black"), plot.title = element_text(size = 12)) + ylab("") +
    xlab("")

figure_1_sport_civoth <- wrap_plots(fig1_v4_age_sport_civoth, fig1_v4_eth_sport_civoth, fig1_v4_edu_sport_civoth,
    legend_plot_age, legend_plot_eth, legend_plot_edu, byrow = T, design = fig1design) + plot_annotation(tag_levels = list(c("a",
    "b", "c", "", "", ""))) & theme(plot.tag = element_text(face = "bold"))
# plot(figure_1_sport_civoth)

# ggsave(figure_1_sport_civoth, file = './figures/figure01_sport_civoth.png', height = 7, width =
# 12.5)
Figure 1A (Main): Segregation across and within neighborhoods and civic organizations
Figure 1A (Main): Segregation across and within neighborhoods and civic organizations
Figure 1B (Supplement): Differences between sports clubs and other organization types
Figure 1B (Supplement): Differences between sports clubs and other organization types

5 LISS Neighborhood/organization choice experiment

5.1 Marginal means

We use the R-package cregg developed by Leeper (2020) to calculate marginal means.

# clean environment, but keep functions and datasets
rm(list = setdiff(ls(), c(lsf.str(), "df", "df2")))

# formula specifying outcome and conjoint features
fciv <- eciv_choice ~ eciv_time + eciv_cost + eciv_cohesion + eciv_acquaintances + eciv_comp_educ + eciv_comp_age +
    eciv_comp_eth
fnbh <- enbh_choice ~ enbh_time + enbh_cost + enbh_cohesion + enbh_acquaintances + enbh_comp_educ + enbh_comp_age +
    enbh_comp_eth

# calculate marginal means
mmciv <- cregg::mm(df, fciv, id = ~id)
mmnbh <- cregg::mm(df, fnbh, id = ~id)

# plot(mmciv) plot(mmnbh)
# 1 fit linear model
linmodel <- lm(eciv_choice ~ (1 | id) + eciv_time + eciv_cost + eciv_cohesion + eciv_acquaintances +
    eciv_comp_educ + eciv_comp_age + eciv_comp_eth, data = df)
summary(linmodel)

# 2 get predicted probabilities remove missings values
df_nm <- df[complete.cases(df[c("eciv_choice", "eciv_time", "eciv_cost", "eciv_cohesion", "eciv_acquaintances",
    "eciv_comp_educ", "eciv_comp_age", "eciv_comp_eth")]), ]
predprob <- predict(linmodel)

# marginal mean == average predicted probability
mean(predprob[df_nm$eciv_time == "travel time: 20 minutes"])
mean(predprob[df_nm$eciv_time == "travel time: 15 minutes"])
mean(predprob[df_nm$eciv_time == "travel time: 10 minutes"])


fshowdf(mmnbh)
outcome statistic feature level estimate std.error z p lower upper
enbh_choice mm enbh_time travel time to facilities: 20 minutes 0.41 0.00 83.28 0 0.40 0.42
enbh_choice mm enbh_time travel time to facilities: 15 minutes 0.50 0.00 102.62 0 0.49 0.51
enbh_choice mm enbh_time travel time to facilities: 10 minutes 0.59 0.00 119.38 0 0.58 0.60
enbh_choice mm enbh_cost costs: 110% of current housing expenses 0.37 0.01 52.72 0 0.36 0.39
enbh_choice mm enbh_cost costs: 105% of current housing expenses 0.46 0.01 68.24 0 0.44 0.47
enbh_choice mm enbh_cost costs: 100% of current housing expenses 0.51 0.01 76.06 0 0.50 0.53
enbh_choice mm enbh_cost costs: 95% of current housing expenses 0.55 0.01 79.12 0 0.53 0.56
enbh_choice mm enbh_cost costs: 90% of current housing expenses 0.61 0.01 89.01 0 0.59 0.62
enbh_choice mm enbh_cohesion cohesion: neighbors know each other only by sight 0.45 0.00 93.41 0 0.44 0.46
enbh_choice mm enbh_cohesion cohesion: some know each other well, others only by sight 0.52 0.00 106.87 0 0.51 0.53
enbh_choice mm enbh_cohesion cohesion: neighbors know each other well 0.53 0.00 110.16 0 0.52 0.54
enbh_choice mm enbh_acquaintances acquaintances: multiple 0.55 0.01 108.67 0 0.54 0.56
enbh_choice mm enbh_acquaintances acquaintances: one person 0.50 0.00 107.10 0 0.49 0.51
enbh_choice mm enbh_acquaintances acquaintances: no one 0.45 0.00 92.79 0 0.44 0.46
enbh_choice mm enbh_comp_educ education: three quarters (75%) 0.53 0.01 104.16 0 0.52 0.54
enbh_choice mm enbh_comp_educ education: half (50%) 0.51 0.00 103.05 0 0.50 0.52
enbh_choice mm enbh_comp_educ education: a quarter (25%) 0.46 0.00 92.84 0 0.45 0.47
enbh_choice mm enbh_comp_age age: half (50%) 0.51 0.00 103.61 0 0.50 0.52
enbh_choice mm enbh_comp_age age: just under half (40%) 0.50 0.00 103.90 0 0.49 0.51
enbh_choice mm enbh_comp_age age: a quarter (25%) 0.48 0.00 100.16 0 0.47 0.49
enbh_choice mm enbh_comp_eth migration: a quarter (25%) 0.40 0.01 77.69 0 0.39 0.41
enbh_choice mm enbh_comp_eth migration: minority (10%) 0.54 0.00 109.79 0 0.54 0.55
enbh_choice mm enbh_comp_eth migration: none (0%) 0.55 0.01 105.91 0 0.54 0.56
fshowdf(mmciv)
outcome statistic feature level estimate std.error z p lower upper
eciv_choice mm eciv_time travel time: 20 minutes 0.43 0.00 85.67 0 0.42 0.44
eciv_choice mm eciv_time travel time: 15 minutes 0.50 0.00 104.99 0 0.49 0.51
eciv_choice mm eciv_time travel time: 10 minutes 0.57 0.00 116.59 0 0.56 0.58
eciv_choice mm eciv_cost costs: 130% of current contribution 0.38 0.01 54.28 0 0.36 0.39
eciv_choice mm eciv_cost costs: 110% of current contribution 0.46 0.01 66.23 0 0.44 0.47
eciv_choice mm eciv_cost costs: 100% of current contribution 0.52 0.01 76.05 0 0.50 0.53
eciv_choice mm eciv_cost costs: 90% of current contribution 0.55 0.01 80.74 0 0.54 0.56
eciv_choice mm eciv_cost costs: 70% of current contribution 0.60 0.01 86.22 0 0.59 0.61
eciv_choice mm eciv_cohesion cohesion: people know each other only by sight 0.45 0.00 90.50 0 0.44 0.46
eciv_choice mm eciv_cohesion cohesion: some know each other well, others only by sight 0.52 0.00 110.67 0 0.51 0.53
eciv_choice mm eciv_cohesion cohesion: people know each other well 0.53 0.00 106.67 0 0.52 0.54
eciv_choice mm eciv_acquaintances acquaintances: multiple 0.58 0.01 116.42 0 0.57 0.59
eciv_choice mm eciv_acquaintances acquaintances: one person 0.50 0.00 103.05 0 0.49 0.51
eciv_choice mm eciv_acquaintances acquaintances: no one 0.42 0.00 83.76 0 0.41 0.43
eciv_choice mm eciv_comp_educ education: three quarters (75%) 0.51 0.01 98.91 0 0.50 0.52
eciv_choice mm eciv_comp_educ education: half (50%) 0.51 0.00 107.38 0 0.51 0.52
eciv_choice mm eciv_comp_educ education: a quarter (25%) 0.48 0.00 96.48 0 0.47 0.49
eciv_choice mm eciv_comp_age age: half (50%) 0.51 0.00 106.40 0 0.50 0.52
eciv_choice mm eciv_comp_age age: just under half (40%) 0.50 0.00 103.68 0 0.49 0.51
eciv_choice mm eciv_comp_age age: a quarter (25%) 0.49 0.00 100.03 0 0.48 0.50
eciv_choice mm eciv_comp_eth migration: a quarter (25%) 0.46 0.01 87.42 0 0.44 0.47
eciv_choice mm eciv_comp_eth migration: minority (10%) 0.53 0.00 110.74 0 0.52 0.54
eciv_choice mm eciv_comp_eth migration: none (0%) 0.51 0.01 98.79 0 0.50 0.52


5.2 Subgroup marginal means

We estimate conditional marginal means and differences between conditional marginal means to describe differences in preference level between subgroups. To formally test for groups differences in preferences toward particular features, we use omnibus nested model comparisons.

#create subgroups
df$Tert <- NA_real_
df$Tert[df$edu == "college degree"] <- 1L
df$Tert[df$edu == "no college degree"] <- 2L
df$Tert <- factor(df$Tert, 1:2, c("With college degree", "Without college degree"))

df$Age <- NA_real_
df$Age[df$age == "50 or older"] <- 1L
df$Age[df$age == "under 50" ] <- 2L
df$Age <- factor(df$Age, 1:2, c("50 years or older", "Below 50 years"))

df$TM <- NA_real_
df$TM[df$eth_dtm == "Dutch"] <- 1L
df$TM[df$eth_dtm == "Turkish/Moroccan"] <- 2L
df$TM <- factor(df$TM, 1:2, c("No migration background", "Turkish/Moroccan background" ))
df$TM <- factor(df$TM, levels = c( "Turkish/Moroccan background", "No migration background"))

#outcome and conjoint features, including only composition features we are interested in;
#and the subgrouping variable

#conditional marginal means (composition dimension; disaggregated by respondent value for this dimension)

#1. nbh
nmmeduc <- cregg::cj(df[!is.na(df$Tert), ], enbh_choice ~ enbh_comp_educ, id = ~id, estimate = "mm", by = ~Tert)
nmmage <- cregg::cj(df[!is.na(df$Age), ], enbh_choice ~ enbh_comp_age, id = ~id, estimate = "mm", by = ~Age)
nmmeth <- cregg::cj(df[!is.na(df$TM), ], enbh_choice ~ enbh_comp_eth, id = ~id, estimate = "mm", by = ~TM)

#2. org
cmmeduc <- cregg::cj(df[!is.na(df$Tert), ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by = ~Tert)
cmmage <- cregg::cj(df[!is.na(df$Age), ], eciv_choice ~ eciv_comp_age, id = ~id, estimate = "mm", by = ~Age)
cmmeth <- cregg::cj(df[!is.na(df$TM), ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by = ~TM)

#rowbind the dataframes
#leave out last column, reflecting the subgrouping variable
mms <- rbind(nmmage[-12],nmmeth[-12],nmmeduc[-12],
             cmmage[-12],cmmeth[-12],cmmeduc[-12])

#rename labels
#1. of outcome (setting)
mms$Outcome <- factor(ifelse(mms$outcome == "eciv_choice", "Civic organizations", "Neighborhoods"),
                       levels = c("Neighborhoods", "Civic organizations"))

#2. of (demographic composition) features
mms$Feature <- factor(sub(".*_", "", mms$feature), 
                        levels = c("age", "eth", "educ"),
                        labels = c("Share of people aged 50 years or older", "Share of people with Turk/Moroc background",  "Share of people with a college degree"))

mms$Subgroup <- mms$BY
mms$Subgroup <- factor(mms$Subgroup, levels = c("50 years or older", "Below 50 years", "Turkish/Moroccan background",   "No migration background" , "With college degree","Without college degree"  )) 

# nice color palette
cbPalette <- c("#999999","#E69F00","#56B4E9","#D55E00","#F0E442","#0072B2")

p2 <- plot(mms, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup", xlab = "Marginal mean") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette) +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people with a college degree" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      Feature == "Share of people aged 50 years or older" ~ scale_y_discrete(
        labels = c("half (50%)", "just under half (40%)", "a quarter (25%)")),
      Feature == "Share of people with Turk/Moroc background" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "none (0%)"))
      ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.40,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people aged 50 years or older" ~ scale_x_continuous(
        limits = c(.45,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with Turk/Moroc background" ~ scale_x_continuous(
        limits = c(.30,.70), labels = scales::number_format(accuracy = 0.01))
      )) +
  theme(legend.position = "none",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

#split legend into multiple parts
split1 <- mms[mms$Subgroup %in% c("50 years or older", "Below 50 years"), ]
split2 <- mms[mms$Subgroup %in% c("Turkish/Moroccan background", "No migration background"), ]
split3 <- mms[mms$Subgroup %in% c("With college degree", "Without college degree"), ]

#reverse order factor.... bug in ggplot2 makes the order of the subgroups in the plot and the legend reversed
split1$Subgroup <- factor(split1$Subgroup, levels = rev(levels(split1$Subgroup)))
split2$Subgroup <- factor(split2$Subgroup, levels = rev(levels(split2$Subgroup)))
split3$Subgroup <- factor(split3$Subgroup, levels = rev(levels(split3$Subgroup)))

#plot legends
split1p <- ggplot(split1, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Respondent subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(2,1)]) 
split2p <- ggplot(split2, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Respondent subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(4,3)])
split3p <- ggplot(split3, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Respondent subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(6,5)])

#get legends
leg1 <- get_legend(split1p)
leg2 <- get_legend(split2p)
leg3 <- get_legend(split3p)

#combine legends
leg123 <- plot_grid(leg1,leg2,leg3, nrow=1, align="h")

#create a blank plot for legend alignment
blank_p <- plot_spacer()

#combine all in one
p3 <- plot_grid(p2, leg123, align = "h", nrow=2, rel_heights = c(7,1))
plot(p3)

#ggsave("./figures/cmms_liss.png", p3, width=13) 

#test of preference heterogeneity (nested model comparison test
cregg::cj_anova(df[!is.na(df$Tert), ], eciv_choice ~ eciv_comp_educ, by = ~Tert)
#> Analysis of Deviance Table
#> 
#> Model 1: eciv_choice ~ eciv_comp_educ
#> Model 2: eciv_choice ~ eciv_comp_educ + Tert + eciv_comp_educ:Tert
#>   Resid. Df Resid. Dev Df Deviance      F    Pr(>F)    
#> 1     21611     5398.7                                 
#> 2     21608     5384.8  3   13.919 18.618 4.674e-12 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
cregg::cj_anova(df[!is.na(df$Tert), ], eciv_choice ~ eciv_comp_eth, by = ~Tert)
#> Analysis of Deviance Table
#> 
#> Model 1: eciv_choice ~ eciv_comp_eth
#> Model 2: eciv_choice ~ eciv_comp_eth + Tert + eciv_comp_eth:Tert
#>   Resid. Df Resid. Dev Df Deviance      F    Pr(>F)    
#> 1     21611     5381.2                                 
#> 2     21608     5376.5  3   4.6392 6.2149 0.0003249 ***
#> ---
#> Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
cregg::cj_anova(df[!is.na(df$Tert), ], eciv_choice ~ eciv_comp_age, by = ~Tert)
#> Analysis of Deviance Table
#> 
#> Model 1: eciv_choice ~ eciv_comp_age
#> Model 2: eciv_choice ~ eciv_comp_age + Tert + eciv_comp_age:Tert
#>   Resid. Df Resid. Dev Df Deviance      F Pr(>F)
#> 1     21611     5402.9                          
#> 2     21608     5402.5  3  0.39704 0.5293 0.6621


5.2.1 Sensitivity checks

5.2.1.1 excluding religious organizations

We redo the organization choice analyses, now excluding those whose (most important) organization is a religious organization

dfnorel <- df[df$ociv_mostimp_type != "Religious",]

#conditional marginal means (composition dimension; disaggregated by respondent value for this dimension)
#org
cmmeduc <- cregg::cj(dfnorel[!is.na(dfnorel$Tert), ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by = ~Tert)
cmmage <- cregg::cj(dfnorel[!is.na(dfnorel$Age), ], eciv_choice ~ eciv_comp_age, id = ~id, estimate = "mm", by = ~Age)
cmmeth <- cregg::cj(dfnorel[!is.na(dfnorel$TM), ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by = ~TM)

#rowbind the dataframes
#leave out last column, reflecting the subgrouping variable
mms_ <- rbind(cmmage[-12],cmmeth[-12],cmmeduc[-12])

#rename labels
#1. of outcome (setting)
mms_$Outcome <- "Civic organizations (excl. religious org.)"

#2. of (demographic composition) features
mms_$Feature <- factor(sub(".*_", "", mms_$feature), 
                        levels = c("age", "eth", "educ"),
                        labels = c("Share of people aged 50 years or older", "Share of people with Turk/Moroc background",  "Share of people with a college degree"))

mms_$Subgroup <- mms_$BY
mms_$Subgroup <- factor(mms_$Subgroup, levels = c("50 years or older", "Below 50 years", "Turkish/Moroccan background",   "No migration background" , "With college degree","Without college degree"  )) 

p2 <- plot(mms_, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup", xlab = "Marginal mean") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette) +
  labs(title = "Excluding religious organizations") +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people with a college degree" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      Feature == "Share of people aged 50 years or older" ~ scale_y_discrete(
        labels = c("half (50%)", "just under half (40%)", "a quarter (25%)")),
      Feature == "Share of people with Turk/Moroc background" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "none (0%)"))
      ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.40,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people aged 50 years or older" ~ scale_x_continuous(
        limits = c(.45,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with Turk/Moroc background" ~ scale_x_continuous(
        limits = c(.30,.70), labels = scales::number_format(accuracy = 0.01))
      )) +
  theme(legend.position = "none",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

#create a blank plot for legend alignment
blank_p <- plot_spacer()

#combine all in one
p3 <- plot_grid(p2, leg123, align = "h", nrow=2, rel_heights = c(4,1))
plot(p3)

5.2.1.2 restrict sample to resemble that of experiment 3

5.2.1.2.1 sports clubs vs. other organization types

We redo the organization choice analyses, including only people whose (most important) organization is a sports clubs (versus other organisations).

dfsports <- df[df$ociv_mostimp_type == "Sports", ]
dfnonsports <- df[!df$ociv_mostimp_type == "Sports",]

#sports org
cmmeducsport <- cregg::cj(dfsports[!is.na(dfsports$Tert), ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by = ~Tert)
cmmagesport <- cregg::cj(dfsports[!is.na(dfsports$Age), ], eciv_choice ~ eciv_comp_age, id = ~id, estimate = "mm", by = ~Age)
cmmethsport <- cregg::cj(dfsports[!is.na(dfsports$TM), ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by = ~TM)

#non sports org
cmmeducnosport <- cregg::cj(dfnonsports[!is.na(dfnonsports$Tert), ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by = ~Tert)
cmmagenosport <- cregg::cj(dfnonsports[!is.na(dfnonsports$Age), ], eciv_choice ~ eciv_comp_age, id = ~id, estimate = "mm", by = ~Age)
cmmethnosport <- cregg::cj(dfnonsports[!is.na(dfnonsports$TM), ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by = ~TM)

cmmeducsport$Outcome <- cmmagesport$Outcome <- cmmethsport$Outcome <- "Sports clubs"
cmmeducnosport$Outcome <- cmmagenosport$Outcome <- cmmethnosport$Outcome <- "Other types of organizations"

#rowbind the dataframes
mms_ <- rbind(cmmeducsport[,-12],cmmeducnosport[,-12],cmmagesport[,-12],cmmagenosport[,-12],cmmethsport[,-12],cmmethnosport[,-12])

#rename/reorder labels
mms_$Outcome <- factor(mms_$Outcome, levels = c("Sports clubs", "Other types of organizations"))
mms_$Feature <- factor(sub(".*_", "", mms_$feature), 
                      levels = c("age", "eth", "educ"),
                      labels = c("Share of people aged 50 years or older", "Share of people with Turk/Moroc background",  "Share of people with a college degree"))

mms_$Subgroup <- mms_$BY
mms_$Subgroup <- factor(mms_$Subgroup, levels = c("50 years or older", "Below 50 years", "Turkish/Moroccan background", "No migration background" , "With college degree","Without college degree"  )) 

p4 <- plot(mms_, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup", xlab = "Marginal mean") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette) +
  labs(title = "Sports clubs vs. other types of organizations") +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people with a college degree" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      Feature == "Share of people aged 50 years or older" ~ scale_y_discrete(
        labels = c("half (50%)", "just under half (40%)", "a quarter (25%)")),
      Feature == "Share of people with Turk/Moroc background" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "none (0%)"))
    ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.4,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people aged 50 years or older" ~ scale_x_continuous(
        limits = c(.43,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with Turk/Moroc background" ~ scale_x_continuous(
        limits = c(.30,.70), labels = scales::number_format(accuracy = 0.01))
    )) +
  theme(legend.position = "none",
        #strip.text.x = element_markdown(),
        strip.placement = "outside")

p5 <- plot_grid(p4, leg123, align = "h", nrow=2, rel_heights = c(7,1))
print(p5)

#ggsave(p5, file = './figures/figure02_sports_versus_other.png', height = 7, width = 12.5)
5.2.1.2.2 only respondents within TRIAL age range

We redo the analyses, now including only respondents within the TRIAL (experiment 3) age range:

agecapmin <- min(df2$LEEFTIJD) #18
agecapmax <- max(df2$LEEFTIJD) #41

#prop.table(table(df$age_continuous)) #relatively many 'older' respondents
#sum(prop.table(table(df$age_continuous))[3:26]) #22% falls within TRIAL range

dfagecap <- df[df$age_continuous >= agecapmin & df$age_continuous <= agecapmax, ]
#length(unique(df$nomem_encr)) #2761 respondents
#length(unique(dfagecap$nomem_encr)) #604 within TRIAL age-range

#also 'increment' restrictions (sports clubs only; restricted age range)
dfsportsagecap <- dfsports[dfsports$age_continuous >= agecapmin & dfsports$age_continuous <= agecapmax, ]
dfnonsportsagecap <- dfnonsports[dfnonsports$age_continuous >= agecapmin & dfnonsports$age_continuous <= agecapmax, ]

#redo the analyses; naturally now we don't estimate subgroup differences in the age composition dimensions; as in our subset of respondents, all respondents are younger than 50 y/o.

#conditional marginal means (composition dimension; disaggregated by respondent value for this dimension)
#1. nbh
nmmeduc <- cregg::cj(dfagecap[!is.na(dfagecap$Tert), ], enbh_choice ~ enbh_comp_educ, id = ~id, estimate = "mm", by = ~Tert)
nmmeth <- cregg::cj(dfagecap[!is.na(dfagecap$TM), ], enbh_choice ~ enbh_comp_eth, id = ~id, estimate = "mm", by = ~TM)

#2. org (sport)
smmeduc <- cregg::cj(dfsportsagecap[!is.na(dfsportsagecap$Tert), ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by = ~Tert)
smmeth <- cregg::cj(dfsportsagecap[!is.na(dfsportsagecap$TM), ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by = ~TM)

#3. org (no sport)
cmmeduc <- cregg::cj(dfnonsportsagecap[!is.na(dfnonsportsagecap$Tert), ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by = ~Tert)
cmmeth <- cregg::cj(dfnonsportsagecap[!is.na(dfnonsportsagecap$TM), ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by = ~TM)

#rowbind the dataframes
#leave out last column, reflecting the subgrouping variable
mms_ <- rbind(nmmeth[-12],nmmeduc[-12],
              smmeth[-12],smmeduc[-12],
             cmmeth[-12],cmmeduc[-12])
#rename labels
#1. of outcome (setting)
mms_$Outcome <- factor(c(rep("Neighborhoods", 6), rep("Sports clubs", 6), rep("Other types of organizations", 6)), levels = c("Neighborhoods", "Sports clubs", "Other types of organizations"))

#2. of (demographic composition) features
mms_$Feature <- factor(sub(".*_", "", mms_$feature), 
                        levels = c("eth", "educ"),
                        labels = c("Share of people with Turk/Moroc background",  "Share of people with a college degree"))

mms_$Subgroup <- mms_$BY
mms_$Subgroup <- factor(mms_$Subgroup, levels = c("Turkish/Moroccan background",   "No migration background" , "With college degree","Without college degree"  )) 

#only focus on eth dimensions
mms_2 <- mms_[mms_$feature %in% c("enbh_comp_eth", "eciv_comp_eth"),]
#and leave out nbh
mms_2 <- mms_2[mms_2$outcome == "eciv_choice",]


p2 <- plot(mms_2, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup", xlab = "Marginal mean") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[3:6]) +
  #labs(title = "Neighborhoods, sports clubs vs. other types of organizations: restricted to the TRIAL age range (18-41 years)") +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people with a college degree" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      Feature == "Share of people with Turk/Moroc background" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "none (0%)"))
      ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.40,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with Turk/Moroc background" ~ scale_x_continuous(
        limits = c(.30,.70), labels = scales::number_format(accuracy = 0.01))
      )) +
  theme(legend.position = "none",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")
 
#combine legends
#leg_age <- plot_grid(leg2,leg3, nrow=1, align="h")

#create a blank plot for legend alignment
blank_p <- plot_spacer()

#combine all in one
p3 <- plot_grid(p2, leg2, align = "h", nrow=2, rel_heights = c(7,1))
plot(p3)

#ggsave("./figures/figureS4d.png", p3, width=6, height=6)

5.2.1.3 more fine-grained subgroups

5.2.1.3.1 research university vs. university of applied science
#create subgroups
df$Uni <- NA_real_
df$Uni[df$edu_unihbo == "research university"] <- 1L
df$Uni[df$edu_unihbo == "university of applied sciences"] <- 2L
df$Uni <- factor(df$Uni, 1:2, c("Research university", "University of applied sciences"))

#outcome and conjoint features, including only composition features we are interested in;
#and the subgrouping variable

#conditional marginal means (composition dimension; disaggregated by respondent value for this dimension)
#1. nbh
nmmeth <- cregg::cj(df[!is.na(df$Uni), ], enbh_choice ~ enbh_comp_eth, id = ~id, estimate = "mm", by = ~Uni)
nmmeduc <- cregg::cj(df[!is.na(df$Uni), ], enbh_choice ~ enbh_comp_educ, id = ~id, estimate = "mm", by = ~Uni)

#2. org
cmmeth <- cregg::cj(df[!is.na(df$Uni), ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by = ~Uni)
cmmeduc <- cregg::cj(df[!is.na(df$Uni), ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by = ~Uni)

#rowbind the dataframes
#leave out last column, reflecting the subgrouping variable
mms_ <- rbind(nmmeth[-12], nmmeduc[-12], cmmeth[-12], cmmeduc[-12])

#rename labels
#1. of outcome (setting)
mms_$Outcome <- factor(ifelse(mms_$outcome == "eciv_choice", "Civic organizations", "Neighborhoods"),
                       levels = c("Neighborhoods", "Civic organizations"))

#2. of (demographic composition) features
mms_$Feature <- factor(sub(".*_", "", mms_$feature), 
                        levels = c("eth", "educ"),
                        labels = c("Share of people with Turk/Moroc background", "Share of people with a college degree"))
mms_$Subgroup <- mms_$BY
mms_$Subgroup <- factor(mms_$Subgroup, levels = c("Research university", "University of applied sciences")) 

p <- plot(mms_, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup", xlab = "Marginal mean") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(5:6)]) +
  facetted_pos_scales(
     y = list(
      Feature == "Share of people with a college degree" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      Feature == "Share of people with Turk/Moroc background" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "none (0%)"))
      ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.40,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with Turk/Moroc background" ~ scale_x_continuous(
        limits = c(.30,.70), labels = scales::number_format(accuracy = 0.01))
      )) +
  theme(legend.position = "none",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

#split legend into multiple parts
split1 <- mms_[mms_$Subgroup %in% c("Research university", "University of applied sciences"), ]

#reverse order factor.... bug in ggplot2 makes the order of the subgroups in the plot and the legend reversed
split1$Subgroup <- factor(split1$Subgroup, levels = rev(levels(split1$Subgroup)))

#plot legends
split1p <- ggplot(split1, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Respondent subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(6,5)])

#get legends
leg_uni <- get_legend(split1p)

#create a blank plot for legend alignment
blank_p <- plot_spacer()

#combine all in one
p <- plot_grid(p, leg_uni, align = "h", nrow=2, rel_heights = c(7,2))
plot(p)

5.2.1.3.2 more age groups
#create subgroups
df$AgeG <- NA_real_
df$AgeG[df$age_continuous > 64] <- 1L
df$AgeG[df$age_continuous > 49 & df$age_continuous < 65] <- 2L
df$AgeG[df$age_continuous > 34 & df$age_continuous < 50] <- 3L
df$AgeG[df$age_continuous > 17 & df$age_continuous < 35] <- 4L

df$AgeG <- factor(df$AgeG, 1:4, c("65+ years old", "Between 50-65", "Between 35-50", "Between 18-35"))

#1. nbh
nmmage <- cregg::cj(df[!is.na(df$AgeG), ], enbh_choice ~ enbh_comp_age, id = ~id, estimate = "mm", by = ~AgeG)
#2. org
cmmage <- cregg::cj(df[!is.na(df$AgeG), ], eciv_choice ~ eciv_comp_age, id = ~id, estimate = "mm", by = ~AgeG)

#rowbind the dataframes
#leave out last column, reflecting the subgrouping variable
mms_ <- rbind(nmmage[-12],
             cmmage[-12])

#rename labels
#1. of outcome (setting)
mms_$Outcome <- factor(ifelse(mms_$outcome == "eciv_choice", "Civic organizations", "Neighborhoods"),
                       levels = c("Neighborhoods", "Civic organizations"))

#2. of (demographic composition) features
mms_$Feature <- factor(sub(".*_", "", mms_$feature), 
                        levels = c("age"),
                        labels = c("Share of people aged 50 years or older"))

mms_$Subgroup <- mms_$BY
mms_$Subgroup <- factor(mms_$Subgroup, levels = c("65+ years old", "Between 50-65", "Between 35-50", "Between 18-35")) 

p <- plot(mms_, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup", xlab = "Marginal mean") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = rainbow(4)) +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people aged 50 years or older" ~ scale_y_discrete(
        labels = c("half (50%)", "just under half (40%)", "a quarter (25%)"))
      ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people aged 50 years or older" ~ scale_x_continuous(
        limits = c(.40,.60), labels = scales::number_format(accuracy = 0.01))
      )) +
  theme(legend.position = "none",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

#split legend into multiple parts
split1 <- mms_[mms_$Subgroup %in% c("65+ years old", "Between 50-65", "Between 35-50", "Between 18-35"), ]

#reverse order factor.... bug in ggplot2 makes the order of the subgroups in the plot and the legend reversed
split1$Subgroup <- factor(split1$Subgroup, levels = rev(levels(split1$Subgroup)))

#plot legends
split1p <- ggplot(split1, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Respondent subgroups:") + theme_bw() + scale_color_manual(values = rev(rainbow(4))) 

#get legends
leg_age <- get_legend(split1p)

#create a blank plot for legend alignment
blank_p <- plot_spacer()

#combine all in one
p <- plot_grid(p, leg_age, align = "h", nrow=2, rel_heights = c(7,2))
plot(p)


5.3 controlling for measurement error

Our design included a fifth choice task for one of the experiments that is identical to respondents’ first choice task except for switching around organization / neighborhood 1 and organization / neighborhood 2. Whether respondents receive such an additional choice task for the civic or neighborhood experiment was randomly determined, with half of the sample receiving an additional task for each experiment.

We calculate the proportion of same responses across the first and fifth choice tasks (by subgroup), and we compute the (subgroup) swapping error (Clayton et al. 2023).

# function to calculate (subgroup) IRR
f_irr <- function(df) {
    irr_cd <- 1 - mean(df$repchoice[df$Tert == "With college degree"], na.rm = TRUE)  #college degree
    irr_ncd <- 1 - mean(df$repchoice[df$Tert == "Without college degree"], na.rm = TRUE)  #no college degree
    irr_50 <- 1 - mean(df$repchoice[df$Age == "50 years or older"], na.rm = TRUE)  #50 plus
    irr_n50 <- 1 - mean(df$repchoice[df$Age == "Below 50 years"], na.rm = TRUE)  #under 50
    irr_d <- 1 - mean(df$repchoice[df$TM == "No migration background"], na.rm = TRUE)  #dutch
    irr_tm <- 1 - mean(df$repchoice[df$TM == "Turkish/Moroccan background"], na.rm = TRUE)  #turk/moroc

    return(list(`With college degree` = irr_cd, `Without college degree` = irr_ncd, `50 years or older` = irr_50,
        `Below 50 years` = irr_n50, `No migration background` = irr_d, `Turkish/Moroccan background` = irr_tm))
}

# function to calculate swapping error
f_tau <- function(irr_list) {
    sapply(irr_list, function(irr) (1 - sqrt(1 - 2 * (1 - irr)))/2)
}

# define data-sets and (repeated) choice tasks
datasets <- list(df[!is.na(df$rep_org_choice), ], df[!is.na(df$rep_nbh_choice), ])
tasks <- list(c("first_org_choice", "rep_org_choice"), c("first_nbh_choice", "rep_nbh_choice"))
labels <- c("organizations", "neighborhoods")

# use a loop to store swapping errors per subgroup, disaggregated by setting (org/nbh)
swapping <- list()
for (i in 1:length(datasets)) {
    # select dataset
    dataset <- datasets[[i]]

    # check whether repeated choicetasks were answered the same by the respondent
    dataset$repchoice <- ifelse(dataset[[tasks[[i]][1]]] == dataset[[tasks[[i]][2]]], 1, 0)

    # calculate IRR (note that the options/alternatives were reversed! that's why we subtract the
    # IRR from 1)
    irr_list <- f_irr(dataset)

    # calculate tau
    tau_list <- f_tau(irr_list)

    # store results in the list
    swapping[[labels[i]]] <- list(irr = irr_list, tau = tau_list)
}

# store this, as we need it later:
swappingList <- swapping

print(swapping)
#> $organizations
#> $organizations$irr
#> $organizations$irr$`With college degree`
#> [1] 0.7749196
#> 
#> $organizations$irr$`Without college degree`
#> [1] 0.7299465
#> 
#> $organizations$irr$`50 years or older`
#> [1] 0.7281553
#> 
#> $organizations$irr$`Below 50 years`
#> [1] 0.7913043
#> 
#> $organizations$irr$`No migration background`
#> [1] 0.7547993
#> 
#> $organizations$irr$`Turkish/Moroccan background`
#> [1] 0.5172414
#> 
#> 
#> $organizations$tau
#>         With college degree      Without college degree           50 years or older 
#>                   0.1292443                   0.1609229                   0.1622461 
#>              Below 50 years     No migration background Turkish/Moroccan background 
#>                   0.1183560                   0.1430691                   0.4071523 
#> 
#> 
#> $neighborhoods
#> $neighborhoods$irr
#> $neighborhoods$irr$`With college degree`
#> [1] 0.7946708
#> 
#> $neighborhoods$irr$`Without college degree`
#> [1] 0.7292576
#> 
#> $neighborhoods$irr$`50 years or older`
#> [1] 0.745614
#> 
#> $neighborhoods$irr$`Below 50 years`
#> [1] 0.7883721
#> 
#> $neighborhoods$irr$`No migration background`
#> [1] 0.7569757
#> 
#> $neighborhoods$irr$`Turkish/Moroccan background`
#> [1] 0.7037037
#> 
#> 
#> $neighborhoods$tau
#>         With college degree      Without college degree           50 years or older 
#>                   0.1161570                   0.1614312                   0.1495617 
#>              Below 50 years     No migration background Turkish/Moroccan background 
#>                   0.1202816                   0.1415480                   0.1808576


In line with prior studies, when faced with two identical conjoint tasks, respondents choose the same profile about 75% of the time… But we do see differences per subgroup (especially respondents with a Turkish/Moroccan background have unreliable choice behavior).

We can now define a bias-controlled estimator for the marginal mean and compute standard errors via (block) bootstrapping (Cameron, Gelbach, and Miller 2008).

# necessary packages
library(parallel)
library(boot)

#set.seed(52235235) #seed for replication

fboot <- function(data, i) { 
  # sample respondent IDs with replacement
  ids <- sample(unique(data$id), length(unique(data$id)), replace = TRUE)
  
  # create a new dataset by iterating over each sampled id and binding the matching rows
  d <- map_dfr(ids, ~ data %>% filter(id == .x)) 

  # make two datasets, for both experiments
  datasets <- list(d[!is.na(d$rep_org_choice), ], d[!is.na(d$rep_nbh_choice), ])
  
  # get the repeated tasks in both experiments
  tasks <- list(c("first_org_choice", "rep_org_choice"), c("first_nbh_choice", "rep_nbh_choice"))
  
  # label the experiments
  labels <- c("organizations", "neighborhoods")
  
  swapping <- list()
  for (i in 1:length(datasets)) { # for experiment i
    # get the dataset 
    dataset <- datasets[[i]]
    
    # identify whether in the repeated choice task, a different (1) or similar (0) choice was made
    dataset$repchoice <- ifelse(dataset[[tasks[[i]][1]]] == dataset[[tasks[[i]][2]]], 1, 0)

    #calculate IRR and swapping error
    irr_list <- f_irr(dataset)
    tau_list <- f_tau(irr_list)
  
    swapping[[labels[i]]] <- list("irr" = irr_list, "tau" = tau_list)
    }
     
  # calculate conditional marginal means:
  x_vars <- cbind(c("Age", "TM", "Tert"), c("age", "eth", "educ"))
  y_vars <- c("enbh", "eciv")
    
  results <- data.frame()
  
  for(x in 1:nrow(x_vars)) {
    for(y in y_vars) {
      # formula  
      f <- as.formula( paste0(y, "_choice ~ ", y, "_comp_", x_vars[x,2]))
      by <- as.formula(paste0("~", x_vars[x,1]))
      cmms <- cregg::cj( d[!is.na(d[x_vars[x,1]]), ], #exclude missings on the subgrouping variable
                           formula = f, id = ~id, estimate = "mm", by = by)
      #bind results
      results <- rbind(results, cmms[,-12])
      }
  }
 
  #calculate corrected conditional marginal mean (for subgroups)
  results$estimate_corr <- NA
    
  for (i in 1:nrow(results)) { 
    #retrieve setting and subgroup
    setting <- ifelse(results$outcome[i] == "enbh_choice", "neighborhoods", "organizations")
    subgroup <- as.character(results$BY[i])

    tau <- swapping[[setting]]$tau[subgroup]
    
    #define bias corrected MM (eq. 11 of Clayton et al.)
    results$estimate_corr[i] <- (results$estimate[i] - tau) / (1 - 2*tau)
  }
   
  #save rownames
  #rnames <- paste0( results$outcome, "-", results$level, "-", results$BY)
  #save(rnames, file = "./data/rownames.Rda")
  
  return(results$estimate_corr)  
}
#fboot(df)#test

nCore <- detectCores() - 1 #detect number of cores (keep one for other tasks)
nIter <- 1000 #number of bootstrap iterations

#set up cluster
mycl <- makeCluster(rep("localhost", nCore)) 

#load necessary library on each cluster node
clusterEvalQ(mycl, {
  library(cregg)
  library(purrr)
  library(dplyr)
})

#copy data and custom functions to each node's workspace
clusterExport(mycl, varlist=c("df", "f_tau", "f_irr", "fboot")) 

#perform bootstrap (takes very long!!!)
system.time(test <- boot(df, fboot, R=nIter, parallel = "snow", ncpus = nCore, cl = mycl)) #about 2 hours on my pc

#save(test, file = "./results/boot.Rda")
stopCluster(mycl)
load("./results/boot.Rda")
load("./data/rownames.Rda")
nIter = 1000

# Some NA values may occur because, in certain bootstrap iterations, no individuals from minority groups are sampled due to their small sample size. replace these NA values with the mean of the corresponding bootstrapped CMM estimates, ignoring any NAs during the calculation.
for (i in 1:length(test$t0)) {
  if(is.na(test$t0[i])) {
    test$t0[i] <- mean(test$t[,i][is.finite(test$t[, i])], na.rm=TRUE)
  }
}

test1 <- summary(test)

#add rownames
rownames(test1) <- rnames
#str(test)
 
#first add the original bias corrected CMMs to the dataframe (instead of the bootstrap estimates):
#create a merge variable in the original CMM dataframe
mms$BY2 <- paste0(mms$outcome, "-", mms$level, "-", mms$BY)
#reorder
mms <- mms[match(rownames(test1), mms$BY2),]

#now calculate the corrected CMMS
for (i in 1:nrow(mms)) { # for each CMM
    #retrieve setting and subgroup
    setting <- ifelse(mms$outcome[i] == "enbh_choice", "neighborhoods", "organizations")
    subgroup <- as.character(mms$BY[i])
    
    #get tau from our saved list
    tau <- swappingList[[setting]]$tau[subgroup]
    #define bias corrected MM (eq. 11 of Clayton et al.)
    mms$estimate_corr[i] <- (mms$estimate[i] - tau) / (1 - 2*tau)
}

#cor(cbind(mms$estimate_corr, test1$original)) # bias is negligible

# i also calculate the difference in the bootstrapped CMM estimates for each composition attribute level, between (1) subgroups (e.g., college/no college degree); and (2) settigns (i.e., nbh vs org)

# create an empty list to store comparison pairs
comparisons <- list()

# loop through each element in rnames
for (i in rnames) {
  # extract relevant components
  components <- unlist(strsplit(i, "-"))
  demo_trait <- components[2] #e.g., age: half (50%)
  choice_type <- components[1] # e.g., enbh_choice-age
  group <- components[3] # e.g., 50 years or older

  # compare with other groups
  for (j in rnames) {
    if (i != j) { 
      other_components <- unlist(strsplit(j, "-"))
      other_choice_type <- other_components[1]
      other_demo_trait <- other_components[2]
      other_group <- other_components[3]
      # compare subgroups (within setting)
      if( group != other_group & demo_trait == other_demo_trait & choice_type == other_choice_type ) {
        comparisons[[length(comparisons) + 1]] <- data.frame(
          focal = i, other = j, comparison = "subgroup", stringsAsFactors = FALSE
        )
      }
      # compare settings (within subgroup)
        if( group == other_group & demo_trait == other_demo_trait & choice_type != other_choice_type ) {
        comparisons[[length(comparisons) + 1]] <- data.frame(
          focal = i, other = j, comparison = "setting", stringsAsFactors = FALSE
        )
      }
    }
  }
}
      
# convert list into dataframe
comparison_df <- do.call(rbind, comparisons)

#now, for each comparison-pair, get the bootstrapped (error-adjusted) CMMs, and calculate the mean and CI of the difference to assess whether the difference is significant (indicating interaction)
comparison_df$mean_dif <- NA
comparison_df$CI <- NA
comparison_df$sig <- NA

for (i in 1:nrow(comparison_df)) {
  #get bootstrapped CMMs 
  focal = comparison_df$focal[i] 
  other = comparison_df$other[i]
  
  #calculate difference between bootstrap estimates of groups (i.e., subgroups/settings)
  cmm_difs <- test$t[, which(rnames == focal)] - test$t[, which(rnames == other)]
  
  #exclude missings and infinite values
  cmm_difs <- cmm_difs[!is.na(cmm_difs) & is.finite(cmm_difs)]
  
  #get the mean difference
  mean_cmm_dif <- mean(cmm_difs)
  
  #standard error
  se_cmm_dif <- sd(cmm_difs) / sqrt(length(cmm_difs))
  
  #critical t value
  t_value <- qt(0.975, df = length(cmm_difs) - 1)
  
  #margin of error
  margin_error <- se_cmm_dif * t_value
  
  #95% CI
  lower_bound <- mean_cmm_dif - margin_error
  upper_bound <- mean_cmm_dif + margin_error
  
  #add to df
  comparison_df$mean_dif[i] <- mean_cmm_dif
  comparison_df$CI[i] <- paste0("[",round(lower_bound,3), ", ", round(upper_bound,3),"]")
  comparison_df$sig[i] <- ifelse((lower_bound <= 0) & (upper_bound >= 0), FALSE, TRUE)
  }

#calculate standard deviation of bootstrap statistics
for (i in 1:nrow(test1)) {
  if(test1$R[i] < nIter) {
    stat <- test$t[,i]
    test1$bootSE[i] <- sd(stat[!is.na(stat) & is.finite(stat)])
  }
}

test1$dif_subgr_CI <- test1$dif_sett_CI <- NA

for (i in 1:nrow(test1)) { 
  focal = rownames(test1)[i]
  test1$dif_subgr_CI[i] <- comparison_df$CI[comparison_df$focal == focal & comparison_df$comparison == "subgroup"]
  test1$dif_sett_CI[i] <- comparison_df$CI[comparison_df$focal == focal & comparison_df$comparison == "setting"]
}

fshowdf(test1, caption = "bootstrap results", footnote = "For each bootstrap iteration, we calculated the difference in estimated conditional marginal means for composition attribute levels (e.g., 25% college educated) *across* subgroups (e.g., with vs. without college degree) within the same setting (e.g., neighborhood). The 95% confidence interval (`dif_subgr_CI`) indicates whether the subgroup differences were significant. Additionally, we tested whether preferences for composition attribute levles *within* subgroups differed significantly between settings (`dif_sett_CI`).")
bootstrap results
R original bootBias bootSE bootMed dif_sett_CI dif_subgr_CI
enbh_choice-age: half (50%)-50 years or older 1000 0.56 -0.01 0.01 0.54 [0.001, 0.003] [0.076, 0.078]
enbh_choice-age: just under half (40%)-50 years or older 1000 0.51 0.00 0.01 0.51 [-0.001, 0.001] [0.008, 0.01]
enbh_choice-age: a quarter (25%)-50 years or older 1000 0.44 0.01 0.01 0.45 [-0.001, 0] [-0.085, -0.084]
enbh_choice-age: half (50%)-Below 50 years 1000 0.47 0.00 0.01 0.47 [0.019, 0.021] [-0.078, -0.076]
enbh_choice-age: just under half (40%)-Below 50 years 1000 0.50 0.00 0.01 0.50 [0.019, 0.021] [-0.01, -0.008]
enbh_choice-age: a quarter (25%)-Below 50 years 1000 0.53 0.00 0.01 0.53 [-0.041, -0.039] [0.084, 0.085]
eciv_choice-age: half (50%)-50 years or older 1000 0.54 0.00 0.01 0.54 [-0.003, -0.001] [0.094, 0.096]
eciv_choice-age: just under half (40%)-50 years or older 1000 0.51 -0.01 0.01 0.51 [-0.001, 0.001] [0.028, 0.03]
eciv_choice-age: a quarter (25%)-50 years or older 1000 0.44 0.01 0.01 0.45 [0, 0.001] [-0.125, -0.123]
eciv_choice-age: half (50%)-Below 50 years 1000 0.43 0.02 0.01 0.45 [-0.021, -0.019] [-0.096, -0.094]
eciv_choice-age: just under half (40%)-Below 50 years 1000 0.48 0.00 0.01 0.48 [-0.021, -0.019] [-0.03, -0.028]
eciv_choice-age: a quarter (25%)-Below 50 years 1000 0.58 -0.01 0.01 0.57 [0.039, 0.041] [0.123, 0.125]
enbh_choice-migration: a quarter (25%)-Turkish/Moroccan background 991 0.58 Inf 0.06 0.58 [-0.165, -0.137] [0.23, 0.237]
enbh_choice-migration: minority (10%)-Turkish/Moroccan background 991 0.56 Inf 0.08 0.58 [-0.01, 0.013] [0.011, 0.021]
enbh_choice-migration: none (0%)-Turkish/Moroccan background 991 0.38 -Inf 0.09 0.34 [0.107, 0.136] [-0.261, -0.25]
enbh_choice-migration: a quarter (25%)-No migration background 1000 0.35 0.01 0.01 0.35 [-0.079, -0.077] [-0.237, -0.23]
enbh_choice-migration: minority (10%)-No migration background 1000 0.56 0.01 0.01 0.57 [0.018, 0.019] [-0.021, -0.011]
enbh_choice-migration: none (0%)-No migration background 1000 0.59 -0.01 0.01 0.58 [0.061, 0.063] [0.25, 0.261]
eciv_choice-migration: a quarter (25%)-Turkish/Moroccan background 576 0.74 NaN 0.16 0.71 [0.137, 0.165] [0.282, 0.309]
eciv_choice-migration: minority (10%)-Turkish/Moroccan background 576 0.71 NaN 0.12 0.58 [-0.013, 0.01] [0.023, 0.044]
eciv_choice-migration: none (0%)-Turkish/Moroccan background 576 0.09 -Inf 0.16 0.23 [-0.136, -0.107] [-0.319, -0.291]
eciv_choice-migration: a quarter (25%)-No migration background 1000 0.42 0.01 0.01 0.43 [0.077, 0.079] [-0.309, -0.282]
eciv_choice-migration: minority (10%)-No migration background 1000 0.55 0.00 0.01 0.55 [-0.019, -0.018] [-0.044, -0.023]
eciv_choice-migration: none (0%)-No migration background 1000 0.53 -0.01 0.01 0.52 [-0.063, -0.061] [0.291, 0.319]
enbh_choice-education: three quarters (75%)-With college degree 1000 0.58 0.00 0.01 0.58 [0.029, 0.031] [0.073, 0.074]
enbh_choice-education: half (50%)-With college degree 1000 0.53 -0.02 0.01 0.51 [-0.014, -0.012] [0.004, 0.005]
enbh_choice-education: a quarter (25%)-With college degree 1000 0.39 0.01 0.01 0.41 [-0.018, -0.016] [-0.077, -0.075]
enbh_choice-education: three quarters (75%)-Without college degree 1000 0.50 0.01 0.01 0.51 [0.037, 0.038] [-0.074, -0.073]
enbh_choice-education: half (50%)-Without college degree 1000 0.51 0.00 0.01 0.51 [-0.008, -0.006] [-0.005, -0.004]
enbh_choice-education: a quarter (25%)-Without college degree 1000 0.49 -0.01 0.01 0.49 [-0.031, -0.029] [0.075, 0.077]
eciv_choice-education: three quarters (75%)-With college degree 1000 0.54 0.01 0.01 0.55 [-0.031, -0.029] [0.08, 0.082]
eciv_choice-education: half (50%)-With college degree 1000 0.54 -0.01 0.01 0.53 [0.012, 0.014] [0.009, 0.011]
eciv_choice-education: a quarter (25%)-With college degree 1000 0.42 0.00 0.01 0.43 [0.016, 0.018] [-0.09, -0.088]
eciv_choice-education: three quarters (75%)-Without college degree 1000 0.48 -0.01 0.01 0.47 [-0.038, -0.037] [-0.082, -0.08]
eciv_choice-education: half (50%)-Without college degree 1000 0.51 0.01 0.01 0.52 [0.006, 0.008] [-0.011, -0.009]
eciv_choice-education: a quarter (25%)-Without college degree 1000 0.51 0.00 0.01 0.52 [0.029, 0.031] [0.088, 0.09]
Note:
For each bootstrap iteration, we calculated the difference in estimated conditional marginal means for composition attribute levels (e.g., 25% college educated) across subgroups (e.g., with vs. without college degree) within the same setting (e.g., neighborhood). The 95% confidence interval (dif_subgr_CI) indicates whether the subgroup differences were significant. Additionally, we tested whether preferences for composition attribute levles within subgroups differed significantly between settings (dif_sett_CI).
#add these statistics to plotting data
#create copy of mms
mms_corr <- mms
#use corrected estimates
mms_corr$estimate <- mms_corr$estimate_corr

#with bootstrapped standard errors
mms_corr$std.error <- test1$bootSE
#and confidence intervals
mms_corr$upper <- mms_corr$estimate + 1.96*mms_corr$std.error
mms_corr$lower <- mms_corr$estimate - 1.96*mms_corr$std.error

mms_corr$estimate[mms_corr$estimate<0] <- 0

p <- plot(mms_corr, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup", xlab = "Marginal mean") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette) +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people with a college degree" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      Feature == "Share of people aged 50 years or older" ~ scale_y_discrete(
        labels = c("half (50%)", "just under half (40%)", "a quarter (25%)")),
      Feature == "Share of people with Turk/Moroc background" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "none (0%)"))
      ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.35,.65), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people aged 50 years or older" ~ scale_x_continuous(
        limits = c(.40,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with Turk/Moroc background" ~ scale_x_continuous(
        limits = c(-0.09,1), labels = scales::number_format(accuracy = 0.01))
      )) +
  theme(legend.position = "none",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")
 
p <- plot_grid(p, leg123, align = "h", nrow=2, rel_heights = c(7,1))

fshowdf(mms_corr[,-c(14, 15,16)], caption = "Measurement error bias corrected conditional marginal means", digits=3)
Measurement error bias corrected conditional marginal means
BY outcome statistic feature level estimate std.error z p lower upper Outcome Feature
1 50 years or older enbh_choice mm enbh_comp_age age: half (50%) 0.545 0.009 88.792 0 0.528 0.562 Neighborhoods Share of people aged 50 years or older
2 50 years or older enbh_choice mm enbh_comp_age age: just under half (40%) 0.509 0.008 85.504 0 0.492 0.525 Neighborhoods Share of people aged 50 years or older
3 50 years or older enbh_choice mm enbh_comp_age age: a quarter (25%) 0.447 0.009 81.025 0 0.430 0.464 Neighborhoods Share of people aged 50 years or older
4 Below 50 years enbh_choice mm enbh_comp_age age: half (50%) 0.469 0.011 54.617 0 0.447 0.491 Neighborhoods Share of people aged 50 years or older
5 Below 50 years enbh_choice mm enbh_comp_age age: just under half (40%) 0.496 0.011 58.909 0 0.474 0.518 Neighborhoods Share of people aged 50 years or older
6 Below 50 years enbh_choice mm enbh_comp_age age: a quarter (25%) 0.535 0.012 59.797 0 0.511 0.558 Neighborhoods Share of people aged 50 years or older
19 50 years or older eciv_choice mm eciv_comp_age age: half (50%) 0.542 0.009 92.398 0 0.525 0.559 Civic organizations Share of people aged 50 years or older
20 50 years or older eciv_choice mm eciv_comp_age age: just under half (40%) 0.510 0.009 87.112 0 0.493 0.527 Civic organizations Share of people aged 50 years or older
21 50 years or older eciv_choice mm eciv_comp_age age: a quarter (25%) 0.447 0.009 78.760 0 0.430 0.465 Civic organizations Share of people aged 50 years or older
22 Below 50 years eciv_choice mm eciv_comp_age age: half (50%) 0.452 0.011 54.756 0 0.429 0.474 Civic organizations Share of people aged 50 years or older
23 Below 50 years eciv_choice mm eciv_comp_age age: just under half (40%) 0.476 0.011 56.356 0 0.453 0.498 Civic organizations Share of people aged 50 years or older
24 Below 50 years eciv_choice mm eciv_comp_age age: a quarter (25%) 0.572 0.012 64.409 0 0.549 0.595 Civic organizations Share of people aged 50 years or older
7 Turkish/Moroccan background enbh_choice mm enbh_comp_eth migration: a quarter (25%) 0.581 0.057 17.186 0 0.470 0.693 Neighborhoods Share of people with Turk/Moroc background
8 Turkish/Moroccan background enbh_choice mm enbh_comp_eth migration: minority (10%) 0.575 0.079 14.570 0 0.420 0.730 Neighborhoods Share of people with Turk/Moroc background
9 Turkish/Moroccan background enbh_choice mm enbh_comp_eth migration: none (0%) 0.341 0.086 10.127 0 0.173 0.509 Neighborhoods Share of people with Turk/Moroc background
10 No migration background enbh_choice mm enbh_comp_eth migration: a quarter (25%) 0.351 0.008 70.017 0 0.335 0.368 Neighborhoods Share of people with Turk/Moroc background
11 No migration background enbh_choice mm enbh_comp_eth migration: minority (10%) 0.567 0.008 100.905 0 0.552 0.582 Neighborhoods Share of people with Turk/Moroc background
12 No migration background enbh_choice mm enbh_comp_eth migration: none (0%) 0.585 0.008 97.705 0 0.569 0.601 Neighborhoods Share of people with Turk/Moroc background
25 Turkish/Moroccan background eciv_choice mm eciv_comp_eth migration: a quarter (25%) 0.910 0.158 14.930 0 0.600 1.220 Civic organizations Share of people with Turk/Moroc background
26 Turkish/Moroccan background eciv_choice mm eciv_comp_eth migration: minority (10%) 0.638 0.123 15.320 0 0.397 0.878 Civic organizations Share of people with Turk/Moroc background
27 Turkish/Moroccan background eciv_choice mm eciv_comp_eth migration: none (0%) 0.000 0.159 11.528 0 -0.316 0.306 Civic organizations Share of people with Turk/Moroc background
28 No migration background eciv_choice mm eciv_comp_eth migration: a quarter (25%) 0.429 0.008 79.151 0 0.413 0.446 Civic organizations Share of people with Turk/Moroc background
29 No migration background eciv_choice mm eciv_comp_eth migration: minority (10%) 0.548 0.008 101.667 0 0.533 0.563 Civic organizations Share of people with Turk/Moroc background
30 No migration background eciv_choice mm eciv_comp_eth migration: none (0%) 0.522 0.008 91.075 0 0.507 0.538 Civic organizations Share of people with Turk/Moroc background
13 With college degree enbh_choice mm enbh_comp_educ education: three quarters (75%) 0.579 0.010 74.555 0 0.560 0.599 Neighborhoods Share of people with a college degree
14 With college degree enbh_choice mm enbh_comp_educ education: half (50%) 0.513 0.010 70.273 0 0.494 0.532 Neighborhoods Share of people with a college degree
15 With college degree enbh_choice mm enbh_comp_educ education: a quarter (25%) 0.410 0.010 59.343 0 0.390 0.429 Neighborhoods Share of people with a college degree
16 Without college degree enbh_choice mm enbh_comp_educ education: three quarters (75%) 0.506 0.010 72.872 0 0.486 0.526 Neighborhoods Share of people with a college degree
17 Without college degree enbh_choice mm enbh_comp_educ education: half (50%) 0.507 0.010 74.544 0 0.488 0.526 Neighborhoods Share of people with a college degree
18 Without college degree enbh_choice mm enbh_comp_educ education: a quarter (25%) 0.486 0.010 71.550 0 0.466 0.506 Neighborhoods Share of people with a college degree
31 With college degree eciv_choice mm eciv_comp_educ education: three quarters (75%) 0.551 0.010 71.825 0 0.531 0.571 Civic organizations Share of people with a college degree
32 With college degree eciv_choice mm eciv_comp_educ education: half (50%) 0.525 0.010 71.960 0 0.506 0.544 Civic organizations Share of people with a college degree
33 With college degree eciv_choice mm eciv_comp_educ education: a quarter (25%) 0.426 0.010 61.334 0 0.407 0.445 Civic organizations Share of people with a college degree
34 Without college degree eciv_choice mm eciv_comp_educ education: three quarters (75%) 0.469 0.011 68.041 0 0.449 0.490 Civic organizations Share of people with a college degree
35 Without college degree eciv_choice mm eciv_comp_educ education: half (50%) 0.515 0.010 78.739 0 0.496 0.534 Civic organizations Share of people with a college degree
36 Without college degree eciv_choice mm eciv_comp_educ education: a quarter (25%) 0.515 0.010 74.649 0 0.496 0.534 Civic organizations Share of people with a college degree
plot(p)

#ggsave("./figures/cmms_liss_corrected.png", p, width=13) 
#ggsave("./figures/figure02_subgroup_mm.png", p, width=13)

### Table for supplement
mms_corr2 <- mms_corr[, c("Subgroup", "Feature", "Outcome", "level", "estimate" )]
mms_corr2$level <- sub(".*: ", "", mms_corr2$level)

#to wide:
mms_corr_wide <- mms_corr2 %>%
  pivot_wider(
    names_from = Outcome,
    values_from = estimate
  )
names(mms_corr_wide)[4:5] <- c("nbh_estimate", "civ_estimate")

# calculate difference
mms_corr_wide$dif_estimate <- mms_corr_wide$nbh_estimate -  mms_corr_wide$civ_estimate
# calculate ratio
mms_corr_wide$ratio <- (mms_corr_wide$nbh_estimate - 0.5) / (mms_corr_wide$civ_estimate - 0.5)

#to 3 digits
mms_corr_wide_d <- mms_corr_wide %>%
  mutate(across(4:7, round, digits = 3))

#write.csv(mms_corr_wide_d, file = "tab.csv", row.names = FALSE)
#write.csv(comparison_df, file = "comp.csv", row.names=FALSE)

5.4 is the composition of one’s current setting predictive of choice behavior?

#additional disaggregation by whether current nbh/org has high/low representation of group x, for subgroup:

#education composition
#split by lower and upper quartile in distribution
df$educnbh <- NA_real_

#hist(df$onbh_comp_edu[df$Tert == "With college degree"])
#hist(df$onbh_comp_edu[df$Tert == "Without college degree"])

#define the quartiles for each subgroup
college_q25 <- quantile(df$onbh_comp_edu[df$Tert == "With college degree"], 0.25, na.rm = TRUE)
college_q75 <- quantile(df$onbh_comp_edu[df$Tert == "With college degree"], 0.75, na.rm = TRUE)
no_college_q25 <- quantile(df$onbh_comp_edu[df$Tert == "Without college degree"], 0.25, na.rm = TRUE)
no_college_q75 <- quantile(df$onbh_comp_edu[df$Tert == "Without college degree"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
df$educnbh <- ifelse(df$Tert == "With college degree", 
                     ifelse(df$onbh_comp_edu <= college_q25, 1,
                            ifelse(df$onbh_comp_edu >= college_q75, 2, NA)),
                     
              ifelse(df$Tert == "Without college degree", 
                     ifelse(df$onbh_comp_edu <= no_college_q25, 1,
                            ifelse(df$onbh_comp_edu >= no_college_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$educnbhTert <- ifelse(df$Tert == "With college degree" & df$educnbh == 1, "With college degree, few with college degree",
                         ifelse(df$Tert == "With college degree" & df$educnbh == 2, "With college degree, many with college degree",
                                
                                ifelse(df$Tert == "Without college degree" & df$educnbh == 1, "Without college degree, few with college degree",
                                       ifelse(df$Tert == "Without college degree" & df$educnbh == 2, "Without college degree, many with college degree", NA))))
#reorder levels
df$educnbhTert <- factor(df$educnbhTert, levels = c("With college degree, few with college degree",  "With college degree, many with college degree", 
                                                     "Without college degree, few with college degree", "Without college degree, many with college degree"))

#also for organizations
df$educciv <- NA_real_

#hist(df$ociv_comp_edu[df$Tert == "With college degree"])
#hist(df$ociv_comp_edu[df$Tert == "Without college degree"])

#define the quartiles for each group
college_q25 <- quantile(df$ociv_comp_edu[df$Tert == "With college degree"], 0.25, na.rm = TRUE)
college_q75 <- quantile(df$ociv_comp_edu[df$Tert == "With college degree"], 0.75, na.rm = TRUE)
no_college_q25 <- quantile(df$ociv_comp_edu[df$Tert == "Without college degree"], 0.25, na.rm = TRUE)
no_college_q75 <- quantile(df$ociv_comp_edu[df$Tert == "Without college degree"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
df$educciv <- ifelse(df$Tert == "With college degree", 
                     ifelse(df$ociv_comp_edu <= college_q25, 1,
                            ifelse(df$ociv_comp_edu >= college_q75, 2, NA)),
                     
              ifelse(df$Tert == "Without college degree", 
                     ifelse(df$ociv_comp_edu <= no_college_q25, 1,
                            ifelse(df$ociv_comp_edu >= no_college_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$educcivTert <- ifelse(df$Tert == "With college degree" & df$educciv == 1, "With college degree, few with college degree",
                         ifelse(df$Tert == "With college degree" & df$educciv == 2, "With college degree, many with college degree",
                                
                                ifelse(df$Tert == "Without college degree" & df$educciv == 1, "Without college degree, few with college degree",
                                       ifelse(df$Tert == "Without college degree" & df$educciv == 2, "Without college degree, many with college degree", NA))))
#reorder levels
df$educcivTert <- factor(df$educcivTert, levels = c("With college degree, few with college degree",  "With college degree, many with college degree", 
                                                     "Without college degree, few with college degree", "Without college degree, many with college degree"))
 #age
df$agenbh <- NA_real_
#hist(df$onbh_comp_age[df$Age == "50 years or older"])
#hist(df$onbh_comp_age[df$Age == "Below 50 years"])

#define the quartiles for each group
age_q25 <- quantile(df$onbh_comp_age[df$Age == "50 years or older"], 0.25, na.rm = TRUE)
age_q75 <- quantile(df$onbh_comp_age[df$Age == "50 years or older"], 0.75, na.rm = TRUE)
nage_q25 <- quantile(df$onbh_comp_age[df$Age == "Below 50 years"], 0.25, na.rm = TRUE)
nage_q75 <- quantile(df$onbh_comp_age[df$Age == "Below 50 years"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
df$agenbh <- ifelse(df$Age == "50 years or older", 
                     ifelse(df$onbh_comp_age <= age_q25, 1,
                            ifelse(df$onbh_comp_age >= age_q75, 2, NA)),
                     
              ifelse(df$Age == "Below 50 years", 
                     ifelse(df$onbh_comp_age <= nage_q25, 1,
                            ifelse(df$onbh_comp_age >= nage_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$agenbhAge <- ifelse(df$Age ==  "50 years or older" & df$agenbh == 1, "50 years or older, few 50 years or older",
                         ifelse(df$Age == "50 years or older" & df$agenbh == 2, "50 years or older, many 50 years or older",
                                
                                ifelse(df$Age ==  "Below 50 years" & df$agenbh == 1, "Below 50 years, few 50 years or older",
                                       ifelse(df$Age ==  "Below 50 years" & df$agenbh == 2, "Below 50 years, many 50 years or older", NA))))

#reorder levels
df$agenbhAge <- factor(df$agenbhAge, levels = c("50 years or older, few 50 years or older", "50 years or older, many 50 years or older", "Below 50 years, few 50 years or older", 
                                               "Below 50 years, many 50 years or older"))

#also for organizations
df$ageciv <- NA_real_
#hist(df$ociv_comp_age[df$Age == "50 years or older"])
#hist(df$ociv_comp_age[df$Age == "Below 50 years"])

#define the quartiles for each group
age_q25 <- quantile(df$ociv_comp_age[df$Age == "50 years or older"], 0.25, na.rm = TRUE)
age_q75 <- quantile(df$ociv_comp_age[df$Age == "50 years or older"], 0.75, na.rm = TRUE)
nage_q25 <- quantile(df$ociv_comp_age[df$Age == "Below 50 years"], 0.25, na.rm = TRUE)
nage_q75 <- quantile(df$ociv_comp_age[df$Age == "Below 50 years"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
df$ageciv <- ifelse(df$Age == "50 years or older", 
                     ifelse(df$ociv_comp_age <= age_q25, 1,
                            ifelse(df$ociv_comp_age >= age_q75, 2, NA)),
                     
              ifelse(df$Age == "Below 50 years", 
                     ifelse(df$ociv_comp_age <= nage_q25, 1,
                            ifelse(df$ociv_comp_age >= nage_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$agecivAge <- ifelse(df$Age ==  "50 years or older" & df$ageciv == 1, "50 years or older, few 50 years or older",
                         ifelse(df$Age == "50 years or older" & df$ageciv == 2, "50 years or older, many 50 years or older",
                                
                                ifelse(df$Age ==  "Below 50 years" & df$ageciv == 1, "Below 50 years, few 50 years or older",
                                       ifelse(df$Age ==  "Below 50 years" & df$ageciv == 2, "Below 50 years, many 50 years or older", NA))))

#reorder levels
df$agecivAge <- factor(df$agecivAge, levels = c("50 years or older, few 50 years or older", "50 years or older, many 50 years or older", "Below 50 years, few 50 years or older", 
                                               "Below 50 years, many 50 years or older"))

#ethnicity
df$TMnbh <- NA_real_
#hist(df$onbh_comp_eth[df$TM == "No migration background"])
#hist(df$onbh_comp_eth[df$TM == "Turkish/Moroccan background"])

#for ethnicity (% turks/moroccans), use mean split (given highly skewed distribution)
df$TMnbh <- NA_real_

#define means for each group
nm_m <- mean(df$onbh_comp_eth[df$TM == "No migration background"], na.rm = TRUE)
m_m <- mean(df$onbh_comp_eth[df$TM == "Turkish/Moroccan background"], na.rm = TRUE)

#apply  conditions for subgroups
df$TMnbh <- ifelse(df$TM == "Turkish/Moroccan background", 
                     ifelse(df$onbh_comp_eth < m_m, 1,
                            ifelse(df$onbh_comp_eth >= m_m, 2, NA)),
                     
              ifelse(df$TM == "No migration background", 
                     ifelse(df$onbh_comp_eth < nm_m, 1,
                            ifelse(df$onbh_comp_eth >= nm_m, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$ethnbhTM <- ifelse(df$TM ==  "Turkish/Moroccan background" & df$TMnbh == 1, "Turkish/Moroccan background, few Turkish/Moroccan background",
                         ifelse(df$TM == "Turkish/Moroccan background" & df$TMnbh == 2, "Turkish/Moroccan background, many Turkish/Moroccan background",
                                
                                ifelse(df$TM ==  "No migration background" & df$TMnbh == 1, "No migration background, few Turkish/Moroccan background",
                                       ifelse(df$TM ==  "No migration background" & df$TMnbh == 2, "No migration background, many Turkish/Moroccan background", NA))))

#reorder levels
df$ethnbhTM <- factor(df$ethnbhTM, levels = c("Turkish/Moroccan background, few Turkish/Moroccan background", "Turkish/Moroccan background, many Turkish/Moroccan background", "No migration background, few Turkish/Moroccan background", "No migration background, many Turkish/Moroccan background"))

#also for organizations
df$TMciv <- NA_real_
#hist(df$ociv_comp_eth[df$TM == "No migration background"])
#hist(df$ociv_comp_eth[df$TM == "Turkish/Moroccan background"])

#for ethnicity (% turks/moroccans), use mean split (given highly skewed distribution)
df$TMciv <- NA_real_

#define means for each group
nm_m <- mean(df$ociv_comp_eth[df$TM == "No migration background"], na.rm = TRUE)
m_m <- mean(df$ociv_comp_eth[df$TM == "Turkish/Moroccan background"], na.rm = TRUE)

#apply  conditions for subgroups
df$TMciv <- ifelse(df$TM == "Turkish/Moroccan background", 
                     ifelse(df$ociv_comp_eth < m_m, 1,
                            ifelse(df$ociv_comp_eth >= m_m, 2, NA)),
                     
              ifelse(df$TM == "No migration background", 
                     ifelse(df$ociv_comp_eth < nm_m, 1,
                            ifelse(df$ociv_comp_eth >= nm_m, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$ethcivTM <- ifelse(df$TM ==  "Turkish/Moroccan background" & df$TMciv == 1, "Turkish/Moroccan background, few Turkish/Moroccan background",
                         ifelse(df$TM == "Turkish/Moroccan background" & df$TMciv == 2, "Turkish/Moroccan background, many Turkish/Moroccan background",
                                
                                ifelse(df$TM ==  "No migration background" & df$TMciv == 1, "No migration background, few Turkish/Moroccan background",
                                       ifelse(df$TM ==  "No migration background" & df$TMciv == 2, "No migration background, many Turkish/Moroccan background", NA))))

#reorder levels
df$ethcivTM <- factor(df$ethcivTM, levels = c("Turkish/Moroccan background, few Turkish/Moroccan background", "Turkish/Moroccan background, many Turkish/Moroccan background", "No migration background, few Turkish/Moroccan background", "No migration background, many Turkish/Moroccan background"))

#age
nmmagecomp <- cregg::cj(df[!is.na(df$agenbhAge), ], enbh_choice ~ enbh_comp_age, id = ~id, estimate = "mm", by =  ~ agenbhAge)
cmmagecomp <- cregg::cj(df[!is.na(df$agecivAge), ], eciv_choice ~ eciv_comp_age, id = ~id, estimate = "mm", by =  ~ agecivAge)
nmmagecomp$setting <- "Neighborhoods"
cmmagecomp$setting <- "Civic organizations"
age <- rbind(nmmagecomp[-12], cmmagecomp[-12])
age$setting <- factor(age$setting, levels = c("Neighborhoods", "Civic organizations"))

page <- plot(age, vline = 1/2, feature_headers = NA, size = 2, group = "BY", xlab = "  ") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people aged 50 years or older") +
    scale_y_discrete(labels = sub(".*: ", "", levels(age$level))) +
  scale_color_manual(values = c("#CCCCCC", "#666666", "#F0B33C", "#A67600")) + 
  theme(
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))

#eth
nmmethcomp <- cregg::cj(df[!is.na(df$ethnbhTM), ], enbh_choice ~ enbh_comp_eth, id = ~id, estimate = "mm", by =  ~ ethnbhTM)
cmmethcomp <- cregg::cj(df[!is.na(df$ethcivTM), ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by =  ~ ethcivTM)
nmmethcomp$setting <- "Neighborhoods"
cmmethcomp$setting <- "Civic organizations"
eth <- rbind(nmmethcomp[-12], cmmethcomp[-12])
eth$setting <- factor(eth$setting, levels = c("Neighborhoods", "Civic organizations"))

#for some reason i need to reverse the levels again...
eth$BY <- factor(eth$BY, levels = c("Turkish/Moroccan background, few Turkish/Moroccan background",  "Turkish/Moroccan background, many Turkish/Moroccan background", "No migration background, few Turkish/Moroccan background", "No migration background, many Turkish/Moroccan background")) 

peth <- plot(eth, vline = 1/2, feature_headers = NA, size = 2, group = "BY", xlab = "Marginal mean") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people with Turk/Moroc background") +
  scale_y_discrete(labels = sub(".*: ", "", levels(eth$level))) +
  scale_color_manual(values = c("#A2D4F7", "#1E80C0", "#F2A066", "#A43D00")) + 
  theme( 
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))

#educ
nmmeduccomp <- cregg::cj(df[!is.na(df$educnbhTert), ], enbh_choice ~ enbh_comp_educ, id = ~id, estimate = "mm", by =  ~ educnbhTert)
cmmeduccomp <- cregg::cj(df[!is.na(df$educcivTert), ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by =  ~ educcivTert)
nmmeduccomp$setting <- "Neighborhoods"
cmmeduccomp$setting <- "Civic organizations"
educ <- rbind(nmmeduccomp[-12], cmmeduccomp[-12])
educ$setting <- factor(educ$setting, levels = c("Neighborhoods", "Civic organizations"))

peduc <- plot(educ, vline = 1/2, feature_headers = NA, size = 2, group = "BY", xlab = "  ") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people with a college degree") +
  scale_y_discrete(labels = sub(".*: ", "", levels(educ$level))) +
  scale_color_manual(values = c("#D1CE8F", "#A9A011", "#3399CC", "#004C8C")) + 
  theme(
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))

#combine plots
combiplot <- ggpubr::ggarrange(page,peth,peduc, ncol = 3, vjust = .9)

#split legend into multiple parts
#first, reverse order subgrouping factor variable ...
age$Subgroup <- factor(age$BY, levels = rev(levels(age$BY)))
eth$Subgroup <- factor(eth$BY, levels = rev(levels(eth$BY)))
educ$Subgroup <- factor(educ$BY, levels = rev(levels(educ$BY)))
 
#plot legends
split1p <- ggplot(age, aes(x = estimate, y = level, color = Subgroup )) + geom_point() + labs(color = "Subgroup, current setting:") + scale_color_manual(values = rev(c("#CCCCCC", "#666666", "#F0B33C", "#A67600"))) + theme_bw()
split2p <- ggplot(eth, aes(x = estimate, y = level, color = Subgroup )) + geom_point() + labs(color = "Subgroup, current setting:") + scale_color_manual(values = rev(c("#A2D4F7", "#1E80C0", "#F2A066", "#A43D00"))) + theme_bw()
split3p <- ggplot(educ, aes(x = estimate, y = level, color = Subgroup )) + geom_point() + labs(color = "Subgroup, current setting:") + scale_color_manual(values = rev(c("#D1CE8F", "#A9A011", "#3399CC", "#004C8C"))) + theme_bw()

#get legends
leg1 <- get_legend(split1p)
leg2 <- get_legend(split2p)
leg3 <- get_legend(split3p)

#combine legends
leg123a <- plot_grid(leg1,leg2,leg3, nrow=1, align="h")

#create a blank plot for legend alignment
blank_p <- plot_spacer()

#combine all in one
p <- plot_grid(combiplot, leg123a, align = "h", nrow=2, rel_heights = c(4.5,1))

#save
#ggsave("./figures/cmms_liss_current.png", p, width=13) 
print(p)

5.4.1.1.1 control for urban-rural divide

We re-do the analyses, now only focusing on respondents who live in urban areas (and thus drop those in rural areas). We do this to check whether our finding that greater exposure to (e.g., ethnic) outgroups reduces ingroup preferences is not confounded by urban-rural divide in ingroup preferences (due to, e.g., traditionalism, educational attainment, …).

attr(df$sted, "labels") #see https://www.cbs.nl/nl-nl/nieuws/2022/49/regionale-brede-welvaart-hier-en-nu-ten-koste-van-later-/stedelijkheidsgraad
#>  Extremely urban       Very urban Moderately urban   Slightly urban        Not urban 
#>                1                2                3                4                5
#let's subset respondents who live in at least a moderately urbanized area:
dfurban <- df[df$sted < 4, ]
#sum(prop.table(table(df$sted))[2:4]) #amounting to 67% of respondents.

#additional disaggregation by whether current nbh/org has high/low representation of group x, for subgroup:

#education composition
#split by lower and upper quartile in distribution
df$educnbh <- NA_real_

#define the quartiles for each subgroup
college_q25 <- quantile(dfurban$onbh_comp_edu[dfurban$Tert == "With college degree"], 0.25, na.rm = TRUE)
college_q75 <- quantile(dfurban$onbh_comp_edu[dfurban$Tert == "With college degree"], 0.75, na.rm = TRUE)
no_college_q25 <- quantile(dfurban$onbh_comp_edu[dfurban$Tert == "Without college degree"], 0.25, na.rm = TRUE)
no_college_q75 <- quantile(dfurban$onbh_comp_edu[dfurban$Tert == "Without college degree"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
dfurban$educnbh <- ifelse(dfurban$Tert == "With college degree", 
                     ifelse(dfurban$onbh_comp_edu <= college_q25, 1,
                            ifelse(dfurban$onbh_comp_edu >= college_q75, 2, NA)),
                     
              ifelse(dfurban$Tert == "Without college degree", 
                     ifelse(dfurban$onbh_comp_edu <= no_college_q25, 1,
                            ifelse(dfurban$onbh_comp_edu >= no_college_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
dfurban$educnbhTert <- ifelse(dfurban$Tert == "With college degree" & dfurban$educnbh == 1, "With college degree, few with college degree",
                         ifelse(dfurban$Tert == "With college degree" & dfurban$educnbh == 2, "With college degree, many with college degree",
                                
                                ifelse(dfurban$Tert == "Without college degree" & dfurban$educnbh == 1, "Without college degree, few with college degree",
                                       ifelse(dfurban$Tert == "Without college degree" & dfurban$educnbh == 2, "Without college degree, many with college degree", NA))))
#reorder levels
dfurban$educnbhTert <- factor(dfurban$educnbhTert, levels = c("With college degree, few with college degree",  "With college degree, many with college degree", 
                                                     "Without college degree, few with college degree", "Without college degree, many with college degree"))

#also for organizations
dfurban$educciv <- NA_real_

#define the quartiles for each group
college_q25 <- quantile(dfurban$ociv_comp_edu[dfurban$Tert == "With college degree"], 0.25, na.rm = TRUE)
college_q75 <- quantile(dfurban$ociv_comp_edu[dfurban$Tert == "With college degree"], 0.75, na.rm = TRUE)
no_college_q25 <- quantile(dfurban$ociv_comp_edu[dfurban$Tert == "Without college degree"], 0.25, na.rm = TRUE)
no_college_q75 <- quantile(dfurban$ociv_comp_edu[dfurban$Tert == "Without college degree"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
dfurban$educciv <- ifelse(dfurban$Tert == "With college degree", 
                     ifelse(dfurban$ociv_comp_edu <= college_q25, 1,
                            ifelse(dfurban$ociv_comp_edu >= college_q75, 2, NA)),
                     
              ifelse(dfurban$Tert == "Without college degree", 
                     ifelse(dfurban$ociv_comp_edu <= no_college_q25, 1,
                            ifelse(dfurban$ociv_comp_edu >= no_college_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
dfurban$educcivTert <- ifelse(dfurban$Tert == "With college degree" & dfurban$educciv == 1, "With college degree, few with college degree",
                         ifelse(dfurban$Tert == "With college degree" & dfurban$educciv == 2, "With college degree, many with college degree",
                                
                                ifelse(dfurban$Tert == "Without college degree" & dfurban$educciv == 1, "Without college degree, few with college degree",
                                       ifelse(dfurban$Tert == "Without college degree" & dfurban$educciv == 2, "Without college degree, many with college degree", NA))))
#reorder levels
dfurban$educcivTert <- factor(dfurban$educcivTert, levels = c("With college degree, few with college degree",  "With college degree, many with college degree", 
                                                     "Without college degree, few with college degree", "Without college degree, many with college degree"))
#age
dfurban$agenbh <- NA_real_

#define the quartiles for each group
age_q25 <- quantile(dfurban$onbh_comp_age[dfurban$Age == "50 years or older"], 0.25, na.rm = TRUE)
age_q75 <- quantile(dfurban$onbh_comp_age[dfurban$Age == "50 years or older"], 0.75, na.rm = TRUE)
nage_q25 <- quantile(dfurban$onbh_comp_age[dfurban$Age == "Below 50 years"], 0.25, na.rm = TRUE)
nage_q75 <- quantile(dfurban$onbh_comp_age[dfurban$Age == "Below 50 years"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
dfurban$agenbh <- ifelse(dfurban$Age == "50 years or older", 
                     ifelse(dfurban$onbh_comp_age <= age_q25, 1,
                            ifelse(dfurban$onbh_comp_age >= age_q75, 2, NA)),
                     
              ifelse(dfurban$Age == "Below 50 years", 
                     ifelse(dfurban$onbh_comp_age <= nage_q25, 1,
                            ifelse(dfurban$onbh_comp_age >= nage_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
dfurban$agenbhAge <- ifelse(dfurban$Age ==  "50 years or older" & dfurban$agenbh == 1, "50 years or older, few 50 years or older",
                         ifelse(dfurban$Age == "50 years or older" & dfurban$agenbh == 2, "50 years or older, many 50 years or older",
                                
                                ifelse(dfurban$Age ==  "Below 50 years" & dfurban$agenbh == 1, "Below 50 years, few 50 years or older",
                                       ifelse(dfurban$Age ==  "Below 50 years" & dfurban$agenbh == 2, "Below 50 years, many 50 years or older", NA))))

#reorder levels
dfurban$agenbhAge <- factor(dfurban$agenbhAge, levels = c("50 years or older, few 50 years or older", "50 years or older, many 50 years or older", "Below 50 years, few 50 years or older", 
                                               "Below 50 years, many 50 years or older"))

#also for organizations
dfurban$ageciv <- NA_real_

#define the quartiles for each group
age_q25 <- quantile(dfurban$ociv_comp_age[dfurban$Age == "50 years or older"], 0.25, na.rm = TRUE)
age_q75 <- quantile(dfurban$ociv_comp_age[dfurban$Age == "50 years or older"], 0.75, na.rm = TRUE)
nage_q25 <- quantile(dfurban$ociv_comp_age[dfurban$Age == "Below 50 years"], 0.25, na.rm = TRUE)
nage_q75 <- quantile(dfurban$ociv_comp_age[dfurban$Age == "Below 50 years"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
dfurban$ageciv <- ifelse(dfurban$Age == "50 years or older", 
                     ifelse(dfurban$ociv_comp_age <= age_q25, 1,
                            ifelse(dfurban$ociv_comp_age >= age_q75, 2, NA)),
                     
              ifelse(dfurban$Age == "Below 50 years", 
                     ifelse(dfurban$ociv_comp_age <= nage_q25, 1,
                            ifelse(dfurban$ociv_comp_age >= nage_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
dfurban$agecivAge <- ifelse(dfurban$Age ==  "50 years or older" & dfurban$ageciv == 1, "50 years or older, few 50 years or older",
                         ifelse(dfurban$Age == "50 years or older" & dfurban$ageciv == 2, "50 years or older, many 50 years or older",
                                
                                ifelse(dfurban$Age ==  "Below 50 years" & dfurban$ageciv == 1, "Below 50 years, few 50 years or older",
                                       ifelse(dfurban$Age ==  "Below 50 years" & dfurban$ageciv == 2, "Below 50 years, many 50 years or older", NA))))

#reorder levels
dfurban$agecivAge <- factor(dfurban$agecivAge, levels = c("50 years or older, few 50 years or older", "50 years or older, many 50 years or older", "Below 50 years, few 50 years or older", 
                                               "Below 50 years, many 50 years or older"))

#ethnicity
dfurban$TMnbh <- NA_real_

#for ethnicity (% turks/moroccans), use mean split (given highly skewed distribution)
dfurban$TMnbh <- NA_real_

#define means for each group
nm_m <- mean(dfurban$onbh_comp_eth[dfurban$TM == "No migration background"], na.rm = TRUE)
m_m <- mean(dfurban$onbh_comp_eth[dfurban$TM == "Turkish/Moroccan background"], na.rm = TRUE)

#apply  conditions for subgroups
dfurban$TMnbh <- ifelse(dfurban$TM == "Turkish/Moroccan background", 
                     ifelse(dfurban$onbh_comp_eth < m_m, 1,
                            ifelse(dfurban$onbh_comp_eth >= m_m, 2, NA)),
                     
              ifelse(dfurban$TM == "No migration background", 
                     ifelse(dfurban$onbh_comp_eth < nm_m, 1,
                            ifelse(dfurban$onbh_comp_eth >= nm_m, 2, NA)), NA))

#make categories (combination of subgroup and composition)
dfurban$ethnbhTM <- ifelse(dfurban$TM ==  "Turkish/Moroccan background" & dfurban$TMnbh == 1, "Turkish/Moroccan background, few Turkish/Moroccan background",
                         ifelse(dfurban$TM == "Turkish/Moroccan background" & dfurban$TMnbh == 2, "Turkish/Moroccan background, many Turkish/Moroccan background",
                                
                                ifelse(dfurban$TM ==  "No migration background" & dfurban$TMnbh == 1, "No migration background, few Turkish/Moroccan background",
                                       ifelse(df$TM ==  "No migration background" & dfurban$TMnbh == 2, "No migration background, many Turkish/Moroccan background", NA))))

#reorder levels
dfurban$ethnbhTM <- factor(dfurban$ethnbhTM, levels = c("Turkish/Moroccan background, few Turkish/Moroccan background", "Turkish/Moroccan background, many Turkish/Moroccan background", "No migration background, few Turkish/Moroccan background", "No migration background, many Turkish/Moroccan background"))

#also for organizations
dfurban$TMciv <- NA_real_

#for ethnicity (% turks/moroccans), use mean split (given highly skewed distribution)
dfurban$TMciv <- NA_real_

#define means for each group
nm_m <- mean(dfurban$ociv_comp_eth[dfurban$TM == "No migration background"], na.rm = TRUE)
m_m <- mean(dfurban$ociv_comp_eth[dfurban$TM == "Turkish/Moroccan background"], na.rm = TRUE)

#apply  conditions for subgroups
dfurban$TMciv <- ifelse(dfurban$TM == "Turkish/Moroccan background", 
                     ifelse(dfurban$ociv_comp_eth < m_m, 1,
                            ifelse(dfurban$ociv_comp_eth >= m_m, 2, NA)),
                     
              ifelse(dfurban$TM == "No migration background", 
                     ifelse(dfurban$ociv_comp_eth < nm_m, 1,
                            ifelse(dfurban$ociv_comp_eth >= nm_m, 2, NA)), NA))

#make categories (combination of subgroup and composition)
dfurban$ethcivTM <- ifelse(dfurban$TM ==  "Turkish/Moroccan background" & dfurban$TMciv == 1, "Turkish/Moroccan background, few Turkish/Moroccan background",
                         ifelse(dfurban$TM == "Turkish/Moroccan background" & dfurban$TMciv == 2, "Turkish/Moroccan background, many Turkish/Moroccan background",
                                
                                ifelse(dfurban$TM ==  "No migration background" & dfurban$TMciv == 1, "No migration background, few Turkish/Moroccan background",
                                       ifelse(dfurban$TM ==  "No migration background" & dfurban$TMciv == 2, "No migration background, many Turkish/Moroccan background", NA))))

#reorder levels
dfurban$ethcivTM <- factor(dfurban$ethcivTM, levels = c("Turkish/Moroccan background, few Turkish/Moroccan background", "Turkish/Moroccan background, many Turkish/Moroccan background", "No migration background, few Turkish/Moroccan background", "No migration background, many Turkish/Moroccan background"))

#age
nmmagecomp <- cregg::cj(dfurban[!is.na(dfurban$agenbhAge), ], enbh_choice ~ enbh_comp_age, id = ~id, estimate = "mm", by =  ~ agenbhAge)
cmmagecomp <- cregg::cj(dfurban[!is.na(dfurban$agecivAge), ], eciv_choice ~ eciv_comp_age, id = ~id, estimate = "mm", by =  ~ agecivAge)
nmmagecomp$setting <- "Neighborhoods"
cmmagecomp$setting <- "Civic organizations"
age2 <- rbind(nmmagecomp[-12], cmmagecomp[-12])
age2$setting <- factor(age2$setting, levels = c("Neighborhoods", "Civic organizations"))

page <- plot(age2, vline = 1/2, feature_headers = NA, size = 2, group = "BY", xlab = "  ") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people aged 50 years or older") +
    scale_y_discrete(labels = sub(".*: ", "", levels(age$level))) +
  scale_color_manual(values = c("#CCCCCC", "#666666", "#F0B33C", "#A67600")) + 
  theme(
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))

#eth
nmmethcomp <- cregg::cj(dfurban[!is.na(dfurban$ethnbhTM), ], enbh_choice ~ enbh_comp_eth, id = ~id, estimate = "mm", by =  ~ ethnbhTM)
cmmethcomp <- cregg::cj(dfurban[!is.na(dfurban$ethcivTM), ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by =  ~ ethcivTM)
nmmethcomp$setting <- "Neighborhoods"
cmmethcomp$setting <- "Civic organizations"
eth2 <- rbind(nmmethcomp[-12], cmmethcomp[-12])
eth2$setting <- factor(eth2$setting, levels = c("Neighborhoods", "Civic organizations"))

#for some reason i need to reverse the levels again...
eth2$BY <- factor(eth2$BY, levels = c("Turkish/Moroccan background, few Turkish/Moroccan background",  "Turkish/Moroccan background, many Turkish/Moroccan background", "No migration background, few Turkish/Moroccan background", "No migration background, many Turkish/Moroccan background")) 

peth <- plot(eth2, vline = 1/2, feature_headers = NA, size = 2, group = "BY", xlab = "Marginal mean") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people with Turk/Moroc background") +
  scale_y_discrete(labels = sub(".*: ", "", levels(eth$level))) +
  scale_color_manual(values = c("#A2D4F7", "#1E80C0", "#F2A066", "#A43D00")) + 
  theme( 
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))

#educ
nmmeduccomp <- cregg::cj(dfurban[!is.na(dfurban$educnbhTert), ], enbh_choice ~ enbh_comp_educ, id = ~id, estimate = "mm", by =  ~ educnbhTert)
cmmeduccomp <- cregg::cj(dfurban[!is.na(dfurban$educcivTert), ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by =  ~ educcivTert)
nmmeduccomp$setting <- "Neighborhoods"
cmmeduccomp$setting <- "Civic organizations"
educ2 <- rbind(nmmeduccomp[-12], cmmeduccomp[-12])
educ2$setting <- factor(educ2$setting, levels = c("Neighborhoods", "Civic organizations"))

peduc <- plot(educ2, vline = 1/2, feature_headers = NA, size = 2, group = "BY", xlab = "  ") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people with a college degree") +
  scale_y_discrete(labels = sub(".*: ", "", levels(educ$level))) +
  scale_color_manual(values = c("#D1CE8F", "#A9A011", "#3399CC", "#004C8C")) + 
  theme(
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))

#combine plots
combiplot <- ggpubr::ggarrange(page,peth,peduc, ncol = 3, vjust = .9)

#combine all in one
p <- plot_grid(combiplot, leg123a, align = "h", nrow=2, rel_heights = c(4.5,1))

print(p)

fboot2 <- function(data, i) {
  # sample respondent IDs with replacement
  ids <- sample(unique(data$id), length(unique(data$id)), replace = TRUE)
  
  # create a new dataset by iterating over each sampled id and binding the matching rows
  d <- map_dfr(ids, ~ data %>% filter(id == .x)) 

  datasets <- list(df[!is.na(df$rep_org_choice), ], df[!is.na(df$rep_nbh_choice), ])
  tasks <- list(c("first_org_choice", "rep_org_choice"), c("first_nbh_choice", "rep_nbh_choice"))
  labels <- c("organizations", "neighborhoods")
  
  swapping <- list()
  for (i in 1:length(datasets)) {
    dataset <- datasets[[i]]
    dataset$repchoice <- ifelse(dataset[[tasks[[i]][1]]] == dataset[[tasks[[i]][2]]], 1, 0)

    irr_list <- f_irr(dataset)
    tau_list <- f_tau(irr_list)

    swapping[[labels[i]]] <- list("irr" = irr_list, "tau" = tau_list)
  }
  
  # calculate conditional marginal means (now for combination subgroup and composition current setting):
  x_vars <- cbind(c("age_Age", "eth_TM", "educ_Tert"), c("age", "eth", "educ"))
  y_vars <- c("enbh", "eciv")
  
  results <- data.frame()

  for(x in 1:nrow(x_vars)) {
    for(y in y_vars) {
      
      # formula  
      f <- as.formula( paste0(y, "_choice ~ ", y, "_comp_", x_vars[x,2]))
     
      #specify the correct "BY" / subgrouping variable (depending on Y)
      byy <- ifelse(y == "enbh", sub("_", "nbh", x_vars[x,1]),
                   sub("_", "civ", x_vars[x,1]))
      by <- as.formula(paste0("~", byy))
 
      cmms <- cregg::cj( d[!is.na(d[byy]), ], #exclude missings on the subgrouping variable
                           formula = f, id = ~id, estimate = "mm", by = by)
      #bind results
      results <- rbind(results, cmms[,-12])
      }
    }
  
  #calculate corrected conditional marginal mean (for subgroups)
  results$estimate_corr <- NA
    
  for (i in 1:nrow(results)) {  
    
    #retrieve setting and subgroup
    setting <- ifelse(results$outcome[i] == "enbh_choice", "neighborhoods", "organizations")
    subgroup <- as.character(results$BY[i])

    #we did not estimate swapping errors for combinations of subgroup + composition current setting, but only for the (demographic) subgroup ...
    #so retrieve this:
    subgroup <- sub(",.*", "", subgroup)

    #get tau
    tau <- swapping[[setting]]$tau[subgroup]
    
    #define bias corrected MM (eq. 11 of Clayton et al.)
    results$estimate_corr[i] <- (results$estimate[i] - tau) / (1 - 2*tau)
  }
  
  #save rownames
  #rnames2 <- paste0( results$outcome, "-", results$level, "-", results$BY)
  #save(rnames2, file = "./data/rownames2.Rda")
  
  return(results$estimate_corr)  
}

#fboot2(df)#test iteration

nCore <- detectCores() - 1 #detect number of cores (keep one for other tasks)
nIter <- 1000 #number of bootstrap iterations

#set up cluster
mycl <- makeCluster(rep("localhost", nCore))

#load necessary library on each cluster node
clusterEvalQ(mycl, {
  library(cregg)
  library(purrr)
  library(dplyr)
})

#copy data and custom functions to each node's workspace
clusterExport(mycl, varlist=c("df", "f_tau", "f_irr", "fboot")) 

#perform bootstrap:
system.time(test <- boot(df, fboot2, R=nIter, parallel = "snow", ncpus = nCore, cl = mycl)) #about 3 hours on my pc

#save(test, file = "./results/boot2.Rda")
stopCluster(mycl)
load("./results/boot2.Rda")
load("./data/rownames2.Rda")

test1 <- summary(test)
rownames(test1) <- rnames2
#print(test1)

#first add the original bias corrected CMMs to the dataframe:
#create a merge variable in the original CMM dataframe
mms <- rbind(age, eth, educ)
mms$BY2 <- paste0(mms$outcome, "-", mms$level, "-", mms$BY)

#reorder
mms <- mms[match(rownames(test1), mms$BY2),]

#now calculate the corrected CMMS
for (i in 1:nrow(mms)) { # for each CMM
    #retrieve setting and subgroup
    setting <- ifelse(mms$outcome[i] == "enbh_choice", "neighborhoods", "organizations")
    subgroup <- as.character(mms$BY[i])
    subgroup <- sub(",.*", "", subgroup)
    
    #get tau from our saved list
    tau <- swappingList[[setting]]$tau[subgroup]
    #define bias corrected MM (eq. 11 of Clayton et al.)
    mms$estimate_corr[i] <- (mms$estimate[i] - tau) / (1 - 2*tau)
}

#calculate standard deviation of bootstrap statistics
for (i in 1:nrow(test1)) {
  if(test1$R[i] < nIter) {
    stat <- test$t[,i]
    test1$bootSE[i] <- sd(stat[!is.na(stat) & is.finite(stat)])
  }
}

#add these statistics to plotting data
#create copy of mms
mms_corr <- mms
#use corrected estimates
mms_corr$estimate <- mms_corr$estimate_corr
#with bootstrapped standard errors
mms_corr$std.error <- test1$bootSE
#and confidence intervals
mms_corr$upper <- mms_corr$estimate + 1.96*mms_corr$std.error
mms_corr$lower <- mms_corr$estimate - 1.96*mms_corr$std.error

#redo the plots:
page <- plot(mms_corr[grep("age", mms_corr$feature ), ], vline = 1/2, feature_headers = NA, size = 2, group = "BY", xlab = " ") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people aged 50 years or older") +
  scale_y_discrete(labels = sub(".*: ", "", mms_corr$level[grep("age", mms$feature ) ])) +
  scale_color_manual(values = c("#CCCCCC", "#666666", "#F0B33C", "#A67600")) + 
  theme(legend.position = "none", 
        strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))

# here, leave out TM, because of large uncertainty
peth <- plot(mms_corr[grep("eth", mms_corr$feature)[c(7:12, 19:24)],], vline = 1/2, feature_headers = NA, size = 2, group = "BY", xlab = "Marginal mean") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people with Turk/Moroc background") +
  scale_y_discrete(labels = sub(".*: ", "", mms_corr$level[grep("eth", mms$feature ) ])) +
  scale_color_manual(values = c( "#F2A066", "#A43D00")) +
  theme(
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))

peduc <- plot(mms_corr[grep("educ", mms_corr$feature ), ], vline = 1/2, feature_headers = NA, size = 2, group = "BY", xlab = " ") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people with a college degree") +
  scale_y_discrete(labels = sub(".*: ", "", mms_corr$level[grep("educ", mms$feature ) ])) +
  scale_color_manual(values = c("#D1CE8F", "#A9A011", "#3399CC", "#004C8C")) + 
  theme(
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))


#combine with custom legends:

#first, remove ethnic minority for custom legend (because we removed estimates from the plot)
split2p.nTM <- ggplot(eth[-grep("Turkish/Moroccan background,", eth$BY),], aes(x = estimate, y = level, color = Subgroup )) + geom_point() + labs(color = "Subgroup, current setting:") + scale_color_manual(values = rev(c("#F2A066", "#A43D00"))) + theme_bw()

#retrieve legend
leg2.nTM <- get_legend(split2p.nTM)

#create new combined legend
leg123.nTM <- plot_grid(leg1,leg2.nTM,leg3, nrow=1, align="h")

#combine all in one
combiplot <- ggpubr::ggarrange(page,peth,peduc, ncol = 3, vjust = .9)
 
#and add custom legend
p <- plot_grid(combiplot, leg123.nTM, align = "h", nrow=2, rel_heights = c(4.5,1))

#save
#ggsave("./figures/cmms_liss_current_corrected.png", p, width=13) 

#plot(p)

### ALTERNATIVE PRESENTATION ###
mms_corr$Subgroup  <- sub(",.*", "", mms_corr$Subgroup)

mms_corr$Current <- NA
mms_corr$Current[mms_corr$Subgroup %in% c("50 years or older", "Below 50 years")] <- ifelse(grepl("few", mms_corr$BY[mms_corr$Subgroup %in% c("50 years or older", "Below 50 years")]), "Few people aged 50 years or older", "Many people aged 50 years or older" )

mms_corr$Current[mms_corr$Subgroup %in% c("Turkish/Moroccan background", "No migration background")] <- ifelse(grepl("few", mms_corr$BY[mms_corr$Subgroup %in% c("Turkish/Moroccan background", "No migration background")]), "Few people with Turk/Moroc background", "Many people with Turk/Moroc background") 

mms_corr$Current[mms_corr$Subgroup %in% c("With college degree", "Without college degree")] <- ifelse(grepl("few", mms_corr$BY[mms_corr$Subgroup %in% c("With college degree", "Without college degree")]), "Few people with college degree", "Many people with college degree")

mms_corr$Outcome <- factor(ifelse(mms_corr$outcome == "eciv_choice", "Civic organizations", "Neighborhoods"),
                       levels = c("Neighborhoods", "Civic organizations"))

#subset datasets for each dimensions
age <- mms_corr[grep("age", mms_corr$feature ), ]
eth <- mms_corr[grep("eth", mms_corr$feature ), ]
edu <- mms_corr[grep("edu", mms_corr$feature ), ]

#specify feature
age$Feature <- "Share of people aged 50 years or older"
eth$Feature <- "Share of people with Turk/Moroc background"
edu$Feature <- "Share of people with a college degree"

plot_age <- plot(age, vline = 1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  facet_nested(Outcome + Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +  
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
  scale_x_continuous( limits = c(.3,.7), labels = scales::number_format(accuracy = 0.01)) +
  scale_y_discrete(labels = c("half (50%)", "just under half (40%)", "a quarter (25%)")) +
  theme(
    legend.position = "none",
    legend.direction = "vertical",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

plot_eth <- plot(eth, vline = 1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  facet_nested(Outcome + Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +  
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
  scale_x_continuous( limits = c(-0.2,1), labels = scales::number_format(accuracy = 0.01)) +
  scale_y_discrete(labels = c("a quarter (25%)", "minority (10%)", "none (0%)")) +
  theme(
    legend.position = "none",
    legend.direction = "vertical",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

plot_educ <- plot(edu, vline = 1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  facet_nested(Outcome + Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +  
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
  scale_x_continuous( limits = c(0.25,.7), labels = scales::number_format(accuracy = 0.01)) +
  scale_y_discrete(labels =  c("three quarters (75%)", "half (50%)", "a quarter (25%)")) +
  theme(
    legend.position = "none",
    legend.direction = "vertical",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

#combine all in one
combiplot <- ggpubr::ggarrange(plot_age, plot_eth, plot_educ, ncol=3)
 
#add legend
#first reorder group factor
age$Current <- factor(age$Current, levels = c("Many people aged 50 years or older", "Few people aged 50 years or older"))
eth$Current <- factor(eth$Current, levels = c("Many people with Turk/Moroc background", "Few people with Turk/Moroc background"))
edu$Current <- factor(edu$Current, levels = c("Many people with college degree", "Few people with college degree"))

leg1 <- get_legend(ggplot(age, aes(x = estimate, y = level, color = Current)) + 
  geom_point() + 
  labs(color = "Current setting:") + 
  scale_color_manual(values = cbPalette[c(2,1)]) +
  theme_bw())

leg2 <- get_legend(ggplot(eth, aes(x = estimate, y = level, color = Current)) + 
  geom_point() + 
  labs(color = "Current setting:") + 
  scale_color_manual(values = cbPalette[c(2,1)]) +
  theme_bw())

leg3 <- get_legend(ggplot(edu, aes(x = estimate, y = level, color = Current)) + 
  geom_point() + 
  labs(color = "Current setting:") + 
  scale_color_manual(values = cbPalette[c(2,1)]) +
  theme_bw())

leg123 <- plot_grid(leg1,leg2,leg3, nrow=1, align="h")

p <- plot_grid(combiplot, leg123, align = "h", nrow=2, rel_heights = c(10,1))
#plot(p)

#ggsave("./figures/cmms_current_corr_alternative.png", p, width=14, height=10) 
ggsave("./figures/figure03_supplement.png", p, width=14, height=10) 
Figure 3 (Supplement): Marginal means of neighborhoods’ and organizations’ social composition attributes by respondents’ age, ethnicity, and education level and the composition of their current neighborhoods and civic organizations (Experiments 1 and 2).
Figure 3 (Supplement): Marginal means of neighborhoods’ and organizations’ social composition attributes by respondents’ age, ethnicity, and education level and the composition of their current neighborhoods and civic organizations (Experiments 1 and 2).
### NOW ONLY 'TOP ROW in each row'; for the MAIN TEXT ###
age_sub <- age[age$Subgroup == "50 years or older", ]
age_sub$Current <- factor(age_sub$Current, levels = rev(levels(age_sub$Current)) )

plot_age_sub <- plot(age_sub, vline = 1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -2, position = position_dodge(width = 0.9)) +
  facet_wrap(~Outcome, nrow = 2, scales = "free_y", switch = "y") +
  scale_color_manual(values = cbPalette[c(1,2)]) + 
  scale_y_discrete(labels = c("half (50%)", "just under half (40%)", "a quarter (25%)")) +
  scale_x_continuous(limits = c(.33,.62), labels = scales::number_format(accuracy = 0.01)) +
  labs(title = "Share of people aged 50 years or older", subtitle = "**Respondents aged 50 years or older**") +
  theme(
    legend.position = "none", 
    strip.placement = "outside", 
    plot.title = element_textbox_simple(
      padding = margin(5.5, 5.5, 5.5, 5.5), 
      margin = margin(0, 0, 5.5, 0), 
      fill = "lightgrey", 
      linetype = 1,
      r = grid::unit(0, "pt"), 
      size = 8),
    plot.subtitle = element_textbox_simple(
      padding = margin(5.5, 5.5, 5.5, 5.5), 
      margin = margin(0, 0, 5.5, 0), 
      fill = "lightgrey", 
      linetype = 1,
      r = grid::unit(0, "pt"), 
      size = 8
    )
  )

eth_sub <- eth[ eth$Subgroup == "No migration background",]
eth_sub$Current <- factor(eth_sub$Current, levels = rev(levels(eth_sub$Current)) )

plot_eth_sub <- plot(eth_sub, vline = 1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -2, position = position_dodge(width = 0.9)) +
    facet_wrap(~Outcome, nrow = 2, scales = "free_y", switch = "y") +
  scale_color_manual(values = cbPalette[c(2,1)]) + #here switch the colors! (yellow == little outgroup exposure) 
  scale_y_discrete(labels = c("a quarter (25%)", "minority (10%)", "none (0%)")) +
  scale_x_continuous(limits = c(.27,.65), labels = scales::number_format(accuracy = 0.01)) +
  labs(title = "Share of people with Turk/Moroc background", subtitle = "**Respondents with no migration background**") +
  theme(
    legend.position = "none", 
    strip.placement = "outside", 
    plot.title = element_textbox_simple(
      padding = margin(5.5, 5.5, 5.5, 5.5), 
      margin = margin(0, 0, 5.5, 0), 
      fill = "lightgrey", 
      linetype = 1,
      r = grid::unit(0, "pt"), 
      size = 8),
    plot.subtitle = element_textbox_simple(
      padding = margin(5.5, 5.5, 5.5, 5.5), 
      margin = margin(0, 0, 5.5, 0), 
      fill = "lightgrey", 
      linetype = 1,
      r = grid::unit(0, "pt"), 
      size = 8
    )
  )

edu_sub <- edu[edu$Subgroup == "With college degree",]
edu_sub$Current <- factor(edu_sub$Current, levels = rev(levels(edu_sub$Current)) )

plot_edu_sub <- plot(edu_sub, vline = 1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -2, position = position_dodge(width = 0.9)) +
  facet_wrap(~Outcome, nrow = 2, scales = "free_y", switch = "y") +
  scale_color_manual(values = cbPalette[c(1,2)]) + 
   scale_y_discrete(labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")) +
  scale_x_continuous(limits = c(.25,.7), labels = scales::number_format(accuracy = 0.01)) +
  labs(title = "Share of people with college degree", subtitle = "**Respondents with college degree**") +
  theme(
    legend.position = "none", 
    strip.placement = "outside", 
    plot.title = element_textbox_simple(
      padding = margin(5.5, 5.5, 5.5, 5.5), 
      margin = margin(0, 0, 5.5, 0), 
      fill = "lightgrey", 
      linetype = 1,
      r = grid::unit(0, "pt"), 
      size = 8),
    plot.subtitle = element_textbox_simple(
      padding = margin(5.5, 5.5, 5.5, 5.5), 
      margin = margin(0, 0, 5.5, 0), 
      fill = "lightgrey", 
      linetype = 1,
      r = grid::unit(0, "pt"), 
      size = 8
    )
  )

#combine all in one
combiplot <- ggpubr::ggarrange(plot_age_sub, plot_eth_sub, plot_edu_sub, ncol=3)

# make a new 'legends' object, now with for the middle (ethnic) panel the colors reversed
# such that yellow indicates little outgroup exposure (here for native dutch respondents)

leg2reversed <- get_legend(ggplot(eth, aes(x = estimate, y = level, color = Current)) + 
  geom_point() + 
  labs(color = "Current setting:") + 
  scale_color_manual(values = cbPalette[c(1,2)]) +
  theme_bw())

leg12reversed3 <- plot_grid(leg1,leg2reversed,leg3, nrow=1, align="h")

p <- plot_grid(combiplot, leg12reversed3, align = "h", nrow=2, rel_heights = c(6,1))
#plot(p)
#ggsave("./figures/cmms_current_corr_main.png", p, width=12, height=6) 
ggsave("./figures/figure03_main.png", p, width=12, height=7) 
Figure 3 (Main): Marginal means of neighborhoods’ social composition attributes for specific subgroups, disaggregated by the composition of their current neighborhoods (Experiments 1 and 2).
Figure 3 (Main): Marginal means of neighborhoods’ social composition attributes for specific subgroups, disaggregated by the composition of their current neighborhoods (Experiments 1 and 2).
#additional disaggregation by whether ego has much/little contact with group x, for subgroup:

#education composition
#split by lower and upper quartile in distribution
df$educnbh <- NA_real_

#hist(df$onbh_cont_edu[df$Tert == "With college degree"])
#hist(df$onbh_cont_edu[df$Tert == "Without college degree"])

#define the quartiles for each subgroup
college_q25 <- quantile(df$onbh_cont_edu[df$Tert == "With college degree"], 0.25, na.rm = TRUE)
college_q75 <- quantile(df$onbh_cont_edu[df$Tert == "With college degree"], 0.75, na.rm = TRUE)
no_college_q25 <- quantile(df$onbh_cont_edu[df$Tert == "Without college degree"], 0.25, na.rm = TRUE)
no_college_q75 <- quantile(df$onbh_cont_edu[df$Tert == "Without college degree"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
df$educnbh <- ifelse(df$Tert == "With college degree", 
                     ifelse(df$onbh_cont_edu <= college_q25, 1,
                            ifelse(df$onbh_cont_edu >= college_q75, 2, NA)),
                     ifelse(df$Tert == "Without college degree", 
                            ifelse(df$onbh_cont_edu <= no_college_q25, 1,
                                   ifelse(df$onbh_cont_edu >= no_college_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$educnbhTert <- ifelse(df$Tert == "With college degree" & df$educnbh == 1, "With college degree, few with college degree",
                         ifelse(df$Tert == "With college degree" & df$educnbh == 2, "With college degree, many with college degree",
                                
                                ifelse(df$Tert == "Without college degree" & df$educnbh == 1, "Without college degree, few with college degree",
                                       ifelse(df$Tert == "Without college degree" & df$educnbh == 2, "Without college degree, many with college degree", NA))))
#reorder levels
df$educnbhTert <- factor(df$educnbhTert, levels = c("With college degree, few with college degree",  "With college degree, many with college degree", 
                                                    "Without college degree, few with college degree", "Without college degree, many with college degree"))

#also for organizations
df$educciv <- NA_real_

#hist(df$ociv_cont_edu[df$Tert == "With college degree"])
#hist(df$ociv_cont_edu[df$Tert == "Without college degree"])

#define the quartiles for each group
college_q25 <- quantile(df$ociv_cont_edu[df$Tert == "With college degree"], 0.25, na.rm = TRUE)
college_q75 <- quantile(df$ociv_cont_edu[df$Tert == "With college degree"], 0.75, na.rm = TRUE)
no_college_q25 <- quantile(df$ociv_cont_edu[df$Tert == "Without college degree"], 0.25, na.rm = TRUE)
no_college_q75 <- quantile(df$ociv_cont_edu[df$Tert == "Without college degree"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
df$educciv <- ifelse(df$Tert == "With college degree", 
                     ifelse(df$ociv_cont_edu <= college_q25, 1,
                            ifelse(df$ociv_cont_edu >= college_q75, 2, NA)),
                     
                     ifelse(df$Tert == "Without college degree", 
                            ifelse(df$ociv_cont_edu <= no_college_q25, 1,
                                   ifelse(df$ociv_cont_edu >= no_college_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$educcivTert <- ifelse(df$Tert == "With college degree" & df$educciv == 1, "With college degree, few with college degree",
                         ifelse(df$Tert == "With college degree" & df$educciv == 2, "With college degree, many with college degree",
                                
                                ifelse(df$Tert == "Without college degree" & df$educciv == 1, "Without college degree, few with college degree",
                                       ifelse(df$Tert == "Without college degree" & df$educciv == 2, "Without college degree, many with college degree", NA))))
#reorder levels
df$educcivTert <- factor(df$educcivTert, levels = c("With college degree, few with college degree",  "With college degree, many with college degree", 
                                                    "Without college degree, few with college degree", "Without college degree, many with college degree"))
#age
df$agenbh <- NA_real_
#hist(df$onbh_cont_age[df$Age == "50 years or older"])
#hist(df$onbh_cont_age[df$Age == "Below 50 years"])

#define the quartiles for each group
age_q25 <- quantile(df$onbh_cont_age[df$Age == "50 years or older"], 0.25, na.rm = TRUE)
age_q75 <- quantile(df$onbh_cont_age[df$Age == "50 years or older"], 0.75, na.rm = TRUE)
nage_q25 <- quantile(df$onbh_cont_age[df$Age == "Below 50 years"], 0.25, na.rm = TRUE)
nage_q75 <- quantile(df$onbh_cont_age[df$Age == "Below 50 years"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
df$agenbh <- ifelse(df$Age == "50 years or older", 
                    ifelse(df$onbh_cont_age <= age_q25, 1,
                           ifelse(df$onbh_cont_age >= age_q75, 2, NA)),
                    
                    ifelse(df$Age == "Below 50 years", 
                           ifelse(df$onbh_cont_age <= nage_q25, 1,
                                  ifelse(df$onbh_cont_age >= nage_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$agenbhAge <- ifelse(df$Age ==  "50 years or older" & df$agenbh == 1, "50 years or older, few 50 years or older",
                       ifelse(df$Age == "50 years or older" & df$agenbh == 2, "50 years or older, many 50 years or older",
                              
                              ifelse(df$Age ==  "Below 50 years" & df$agenbh == 1, "Below 50 years, few 50 years or older",
                                     ifelse(df$Age ==  "Below 50 years" & df$agenbh == 2, "Below 50 years, many 50 years or older", NA))))

#reorder levels
df$agenbhAge <- factor(df$agenbhAge, levels = c("50 years or older, few 50 years or older", "50 years or older, many 50 years or older", "Below 50 years, few 50 years or older", 
                                                "Below 50 years, many 50 years or older"))

#also for organizations
df$ageciv <- NA_real_
#hist(df$ociv_cont_age[df$Age == "50 years or older"])
#hist(df$ociv_cont_age[df$Age == "Below 50 years"])

#define the quartiles for each group
age_q25 <- quantile(df$ociv_cont_age[df$Age == "50 years or older"], 0.25, na.rm = TRUE)
age_q75 <- quantile(df$ociv_cont_age[df$Age == "50 years or older"], 0.75, na.rm = TRUE)
nage_q25 <- quantile(df$ociv_cont_age[df$Age == "Below 50 years"], 0.25, na.rm = TRUE)
nage_q75 <- quantile(df$ociv_cont_age[df$Age == "Below 50 years"], 0.75, na.rm = TRUE)

#apply  conditions for subgroups
df$ageciv <- ifelse(df$Age == "50 years or older", 
                    ifelse(df$ociv_cont_age <= age_q25, 1,
                           ifelse(df$ociv_cont_age >= age_q75, 2, NA)),
                    
                    ifelse(df$Age == "Below 50 years", 
                           ifelse(df$ociv_cont_age <= nage_q25, 1,
                                  ifelse(df$ociv_cont_age >= nage_q75, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$agecivAge <- ifelse(df$Age ==  "50 years or older" & df$ageciv == 1, "50 years or older, few 50 years or older",
                       ifelse(df$Age == "50 years or older" & df$ageciv == 2, "50 years or older, many 50 years or older",
                              
                              ifelse(df$Age ==  "Below 50 years" & df$ageciv == 1, "Below 50 years, few 50 years or older",
                                     ifelse(df$Age ==  "Below 50 years" & df$ageciv == 2, "Below 50 years, many 50 years or older", NA))))

#reorder levels
df$agecivAge <- factor(df$agecivAge, levels = c("50 years or older, few 50 years or older", "50 years or older, many 50 years or older", "Below 50 years, few 50 years or older", 
                                                "Below 50 years, many 50 years or older"))

#ethnicity
df$TMnbh <- NA_real_
#hist(df$onbh_cont_eth[df$TM == "No migration background"])
#hist(df$onbh_cont_eth[df$TM == "Turkish/Moroccan background"])

#for ethnicity (% turks/moroccans), use mean split (given highly skewed distribution)
df$TMnbh <- NA_real_

#define means for each group
nm_m <- mean(df$onbh_cont_eth[df$TM == "No migration background"], na.rm = TRUE)
m_m <- mean(df$onbh_cont_eth[df$TM == "Turkish/Moroccan background"], na.rm = TRUE)

#apply  conditions for subgroups
df$TMnbh <- ifelse(df$TM == "Turkish/Moroccan background", 
                   ifelse(df$onbh_cont_eth < m_m, 1,
                          ifelse(df$onbh_cont_eth >= m_m, 2, NA)),
                   
                   ifelse(df$TM == "No migration background", 
                          ifelse(df$onbh_cont_eth < nm_m, 1,
                                 ifelse(df$onbh_cont_eth >= nm_m, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$ethnbhTM <- ifelse(df$TM ==  "Turkish/Moroccan background" & df$TMnbh == 1, "Turkish/Moroccan background, few Turkish/Moroccan background",
                      ifelse(df$TM == "Turkish/Moroccan background" & df$TMnbh == 2, "Turkish/Moroccan background, many Turkish/Moroccan background",
                             
                             ifelse(df$TM ==  "No migration background" & df$TMnbh == 1, "No migration background, few Turkish/Moroccan background",
                                    ifelse(df$TM ==  "No migration background" & df$TMnbh == 2, "No migration background, many Turkish/Moroccan background", NA))))

#reorder levels
df$ethnbhTM <- factor(df$ethnbhTM, levels = c("Turkish/Moroccan background, few Turkish/Moroccan background", "Turkish/Moroccan background, many Turkish/Moroccan background", "No migration background, few Turkish/Moroccan background", "No migration background, many Turkish/Moroccan background"))

#also for organizations
df$TMciv <- NA_real_
#hist(df$ociv_cont_eth[df$TM == "No migration background"])
#hist(df$ociv_cont_eth[df$TM == "Turkish/Moroccan background"])

#for ethnicity (% turks/moroccans), use mean split (given highly skewed distribution)
df$TMciv <- NA_real_

#define means for each group
nm_m <- mean(df$ociv_cont_eth[df$TM == "No migration background"], na.rm = TRUE)
m_m <- mean(df$ociv_cont_eth[df$TM == "Turkish/Moroccan background"], na.rm = TRUE)

#apply  conditions for subgroups
df$TMciv <- ifelse(df$TM == "Turkish/Moroccan background", 
                   ifelse(df$ociv_cont_eth < m_m, 1,
                          ifelse(df$ociv_cont_eth >= m_m, 2, NA)),
                   
                   ifelse(df$TM == "No migration background", 
                          ifelse(df$ociv_cont_eth < nm_m, 1,
                                 ifelse(df$ociv_cont_eth >= nm_m, 2, NA)), NA))

#make categories (combination of subgroup and composition)
df$ethcivTM <- ifelse(df$TM ==  "Turkish/Moroccan background" & df$TMciv == 1, "Turkish/Moroccan background, few Turkish/Moroccan background",
                      ifelse(df$TM == "Turkish/Moroccan background" & df$TMciv == 2, "Turkish/Moroccan background, many Turkish/Moroccan background",
                             
                             ifelse(df$TM ==  "No migration background" & df$TMciv == 1, "No migration background, few Turkish/Moroccan background",
                                    ifelse(df$TM ==  "No migration background" & df$TMciv == 2, "No migration background, many Turkish/Moroccan background", NA))))

#reorder levels
df$ethcivTM <- factor(df$ethcivTM, levels = c("Turkish/Moroccan background, few Turkish/Moroccan background", "Turkish/Moroccan background, many Turkish/Moroccan background", "No migration background, few Turkish/Moroccan background", "No migration background, many Turkish/Moroccan background"))

#age
nmmagecomp <- cregg::cj(df[!is.na(df$agenbhAge), ], enbh_choice ~ enbh_comp_age, id = ~id, estimate = "mm", by =  ~ agenbhAge)
cmmagecomp <- cregg::cj(df[!is.na(df$agecivAge), ], eciv_choice ~ eciv_comp_age, id = ~id, estimate = "mm", by =  ~ agecivAge)
nmmagecomp$setting <- "Neighborhoods"
cmmagecomp$setting <- "Civic organizations"
age <- rbind(nmmagecomp[-12], cmmagecomp[-12])
age$setting <- factor(age$setting, levels = c("Neighborhoods", "Civic organizations"))

page <- plot(age, vline = 1/2, feature_headers = NA, size = 2, group = "BY") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people aged 50 years or older") +
  scale_y_discrete(labels = sub(".*: ", "", levels(age$level))) +
  scale_color_manual(values = c("#CCCCCC", "#666666", "#F0B33C", "#A67600")) + 
  theme(
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))

#eth
nmmethcomp <- cregg::cj(df[!is.na(df$ethnbhTM), ], enbh_choice ~ enbh_comp_eth, id = ~id, estimate = "mm", by =  ~ ethnbhTM)
cmmethcomp <- cregg::cj(df[!is.na(df$ethcivTM), ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by =  ~ ethcivTM)
nmmethcomp$setting <- "Neighborhoods"
cmmethcomp$setting <- "Civic organizations"
eth <- rbind(nmmethcomp[-12], cmmethcomp[-12])
eth$setting <- factor(eth$setting, levels = c("Neighborhoods", "Civic organizations"))

#for some reason i need to reverse the levels again...
eth$BY <- factor(eth$BY, levels = c("Turkish/Moroccan background, few Turkish/Moroccan background",  "Turkish/Moroccan background, many Turkish/Moroccan background", "No migration background, few Turkish/Moroccan background", "No migration background, many Turkish/Moroccan background")) 

peth <- plot(eth, vline = 1/2, feature_headers = NA, size = 2, group = "BY") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people with Turk/Moroc background") +
  scale_y_discrete(labels = sub(".*: ", "", levels(eth$level))) +
  scale_color_manual(values = c("#A2D4F7", "#1E80C0", "#F2A066", "#A43D00")) + 
  theme( 
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))

#educ
nmmeduccomp <- cregg::cj(df[!is.na(df$educnbhTert), ], enbh_choice ~ enbh_comp_educ, id = ~id, estimate = "mm", by =  ~ educnbhTert)
cmmeduccomp <- cregg::cj(df[!is.na(df$educcivTert), ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by =  ~ educcivTert)
nmmeduccomp$setting <- "Neighborhoods"
cmmeduccomp$setting <- "Civic organizations"
educ <- rbind(nmmeduccomp[-12], cmmeduccomp[-12])
educ$setting <- factor(educ$setting, levels = c("Neighborhoods", "Civic organizations"))

peduc <- plot(educ, vline = 1/2, feature_headers = NA, size = 2, group = "BY") +
  facet_grid2(setting~., switch = "y") +
  labs(title = "Share of people with a college degree") +
  scale_y_discrete(labels = sub(".*: ", "", levels(educ$level))) +
  scale_color_manual(values = c("#D1CE8F", "#A9A011", "#3399CC", "#004C8C")) + 
  theme(
    legend.position = "none", 
    strip.placement = "outside", plot.title = element_textbox_simple(padding = margin(5.5, 5.5, 5.5, 5.5), margin = margin(0, 0, 5.5, 0), fill = "lightgrey", linetype = 1, r = grid::unit(0, "pt"), size = 8))


#combine plots
combiplot <- ggpubr::ggarrange(page,peth,peduc, ncol = 3, vjust = .9)

#split legend into multiple parts
#first, reverse order subgrouping factor variable ...
age$Subgroup <- factor(age$BY, levels = rev(levels(age$BY)))
eth$Subgroup <- factor(eth$BY, levels = rev(levels(eth$BY)))
educ$Subgroup <- factor(educ$BY, levels = rev(levels(educ$BY)))

#combine all in one
p <- plot_grid(combiplot, leg123a, align = "h", nrow=2, rel_heights = c(4.5,1))

#save
#ggsave("./figures/cmms_liss_current_contacts.png", p, width=13) 

print(p)

#1. age:
#respondents aged 50+ vs those below 50
#and for each, whether they have relatively many/few neighbors aged 45+ (based on upper/lower quartile)

#oops, here I used "under" instead of "below" 50...
df$agenbh_obj_Age <- as.factor(gsub("Under 50.*?", "Below 50", df$agenbh_obj_Age))
nmmagecomp <- cregg::cj(df[!is.na(df$agenbh_obj_Age), ], enbh_choice ~ enbh_comp_age, id = ~id, estimate = "mm", by = ~ agenbh_obj_Age)

#retrieve subgroup and exposure
nmmagecomp$Subgroup <- ifelse(grepl("50 years or older", nmmagecomp$BY), "50 years or older", "Below 50 years")
nmmagecomp$Current <- ifelse(grepl("many", nmmagecomp$BY), "Many people aged 45+", "Few people aged 45+")
nmmagecomp$Feature <- "Share of people aged 50 years or older"

page <- plot(nmmagecomp, vline = 1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  facet_nested(Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +  
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
  scale_x_continuous( limits = c(.4,.6), labels = scales::number_format(accuracy = 0.01)) +
  scale_y_discrete(labels = c("half (50%)", "just under half (40%)", "a quarter (25%)")) +
  scale_color_manual(values = cbPalette) + 
  
  theme(
    legend.position = "none",
    legend.direction = "vertical",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

#2. ethnicity
#here, use a (subgroup specific) mean split
df$ethnbh_obj_TM <- as.factor(df$ethnbh_obj_TM)
nmmethcomp <- cregg::cj(df[!is.na(df$ethnbh_obj_TM), ], enbh_choice ~ enbh_comp_eth, id = ~id, estimate = "mm", by = ~ ethnbh_obj_TM)

#retrieve subgroup and exposure
nmmethcomp$Subgroup <- ifelse(grepl("No migration", nmmethcomp$BY), "No migration background", "Turkish/Moroccan background")
nmmethcomp$Current <- ifelse(grepl("many", nmmethcomp$BY), "Many people with Turk/Moroc background", "Few people with Turk/Moroc background")
nmmethcomp$Feature <- "Share of people with Turk/Moroc background"

peth <- plot(nmmethcomp, vline = 1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  facet_nested(Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +  
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
  scale_x_continuous( limits = c(0.05,.8), labels = scales::number_format(accuracy = 0.01)) +
  scale_y_discrete(labels = c("a quarter (25%)", "minority (10%)", "none (0%)")) +
  theme(
    legend.position = "none",
    legend.direction = "vertical",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

#3. education
#for college/non college educated, whether they have relatively many/few high income households in the neighborhoods (based on u/l quartile)
df$hinbh_obj_Educ <- as.factor(df$hinbh_obj_Educ)
nmmeduccomp <- cregg::cj(df[!is.na(df$hinbh_obj_Educ), ], enbh_choice ~ enbh_comp_educ, id = ~id, estimate = "mm", by = ~ hinbh_obj_Educ)

#retrieve subgroup and exposure
nmmeduccomp$Subgroup <- ifelse(grepl("With college", nmmeduccomp$BY), "With college degree", "Without college degree")
nmmeduccomp$Current <- ifelse(grepl("many", nmmeduccomp$BY), "Many high income households", "Few high income households")
nmmeduccomp$Feature <- "Share of people with a college degree"

peduc <-plot(nmmeduccomp, vline = 1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  facet_nested(Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +  
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
  scale_x_continuous( limits = c(.35,.6), labels = scales::number_format(accuracy = 0.01)) +
  scale_y_discrete(labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")) +
  theme(
    legend.position = "none",
    legend.direction = "vertical",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

#combine all in one
combiplot <- ggpubr::ggarrange(page, peth, peduc, ncol=3)

#add legend
#first reorder group factor
nmmagecomp$Current <- factor(nmmagecomp$Current, levels = c("Many people aged 45+", "Few people aged 45+"))
nmmethcomp$Current <- factor(nmmethcomp$Current, levels = c("Many people with Turk/Moroc background", "Few people with Turk/Moroc background"))
nmmeduccomp$Current <- factor(nmmeduccomp$Current, levels = c("Many high income households", "Few high income households"))

leg1 <- get_legend(ggplot(nmmagecomp, aes(x = estimate, y = level, color = Current)) + 
  geom_point() + 
  labs(color = "Current setting:") + 
  scale_color_manual(values = cbPalette[c(2,1)]) +
  theme_bw())

leg2 <- get_legend(ggplot(nmmethcomp, aes(x = estimate, y = level, color = Current)) + 
  geom_point() + 
  labs(color = "Current setting:") + 
  scale_color_manual(values = cbPalette[c(2,1)]) +
  theme_bw())

leg3 <- get_legend(ggplot(nmmeduccomp, aes(x = estimate, y = level, color = Current)) + 
  geom_point() + 
  labs(color = "Current setting:") + 
  scale_color_manual(values = cbPalette[c(2,1)]) +
  theme_bw())

legs <- plot_grid(leg1,leg2,leg3, nrow=1, align="h")

p <- plot_grid(combiplot, legs, align = "h", nrow=2, rel_heights = c(10,1))
plot(p)

fboot <- function(data, i) {
  # sample respondent IDs with replacement
  ids <- sample(unique(data$id), length(unique(data$id)), replace = TRUE)
  
  # create a new dataset by iterating over each sampled id and binding the matching rows
  d <- map_dfr(ids, ~ data %>% filter(id == .x)) 

  datasets <- list(df[!is.na(df$rep_org_choice), ], df[!is.na(df$rep_nbh_choice), ])
  tasks <- list(c("first_org_choice", "rep_org_choice"), c("first_nbh_choice", "rep_nbh_choice"))
  labels <- c("organizations", "neighborhoods")
  
  swapping <- list()
  for (i in 1:length(datasets)) {
    dataset <- datasets[[i]]
    dataset$repchoice <- ifelse(dataset[[tasks[[i]][1]]] == dataset[[tasks[[i]][2]]], 1, 0)

    irr_list <- f_irr(dataset)
    tau_list <- f_tau(irr_list)

    swapping[[labels[i]]] <- list("irr" = irr_list, "tau" = tau_list)
  }
  
  # calculate conditional marginal means (now for combination subgroup and composition current setting):
  x_vars <- cbind(c("agenbh_obj_Age", "ethnbh_obj_TM", "hinbh_obj_Educ"), c("age", "eth", "educ"))
  y_vars <- c("enbh")

  results <- data.frame()

  for(x in 1:nrow(x_vars)) {
    for(y in y_vars) {
      # formula  
      f <- as.formula( paste0(y, "_choice ~ ", y, "_comp_", x_vars[x,2]))
     
      #specify the correct "BY" / subgrouping variable
      byy <- x_vars[x,1]
      by <- as.formula(paste0("~", byy))
 
      cmms <- cregg::cj( d[!is.na(d[byy]), ], #exclude missings on the subgrouping variable
                           formula = f, id = ~id, estimate = "mm", by = by)
      #bind results
      results <- rbind(results, cmms[,-12])
      }
    }
  
  #calculate corrected conditional marginal mean (for subgroups)
  results$estimate_corr <- NA
  
  for (i in 1:nrow(results)) {  
    
    #retrieve setting and subgroup
    setting <- ifelse(results$outcome[i] == "enbh_choice", "neighborhoods", "organizations")
    subgroup <- as.character(results$BY[i])

    #we did not estimate swapping errors for combinations of subgroup + composition current setting, but only for the (demographic) subgroup ...
    #so retrieve this:
    subgroup <- sub(",.*", "", subgroup)

    #get tau
    tau <- swapping[[setting]]$tau[subgroup]
    
    #define bias corrected MM (eq. 11 of Clayton et al.)
    results$estimate_corr[i] <- (results$estimate[i] - tau) / (1 - 2*tau)
  }
  
  #save rownames
  #rnames10 <- paste0( results$outcome, "-", results$level, "-", results$BY)
  #save(rnames10, file = "./data/rownames10.Rda")
  
  return(results$estimate_corr)  
}

#fboot(df)#test iteration
nCore <- detectCores() - 1 #detect number of cores (keep one for other tasks)
nIter <- 1000 #number of bootstrap iterations

#set up cluster
mycl <- makeCluster(rep("localhost", nCore))

#load necessary library on each cluster node
clusterEvalQ(mycl, {
  library(cregg)
  library(purrr)
  library(dplyr)
})

#copy data and custom functions to each node's workspace
clusterExport(mycl, varlist=c("df", "f_tau", "f_irr", "fboot")) 

#perform bootstrap:
system.time(test <- boot(df, fboot, R=nIter, parallel = "snow", ncpus = nCore, cl = mycl)) 

save(test, file = "./results/boot10.Rda")
stopCluster(mycl)
load("./results/boot10.Rda")
load("./data/rownames10.Rda")

test1 <- summary(test)
rownames(test1) <- rnames10
#print(test1)
 
#first add the original bias corrected CMMs to the dataframe:
mms <- rbind(nmmagecomp[,-12], nmmethcomp[,-12], nmmeduccomp[,-12])
#create a merge variable in the original CMM dataframe
mms$BY2 <- paste0(mms$outcome, "-", mms$level, "-", mms$BY)

#reorder
mms <- mms[match(rownames(test1), mms$BY2),]

#now calculate the corrected CMMS
for (i in 1:nrow(mms)) { # for each CMM
    #retrieve setting and subgroup
    setting <- ifelse(mms$outcome[i] == "enbh_choice", "neighborhoods", "organizations")
    subgroup <- as.character(mms$BY[i])
    subgroup <- sub(",.*", "", subgroup)
    
    #get tau from our saved list
    tau <- swappingList[[setting]]$tau[subgroup]
    #define bias corrected MM (eq. 11 of Clayton et al.)
    mms$estimate_corr[i] <- (mms$estimate[i] - tau) / (1 - 2*tau)
}

#calculate standard deviation of bootstrap statistics
for (i in 1:nrow(test1)) {
  if(test1$R[i] < nIter) {
    stat <- test$t[,i]
    test1$bootSE[i] <- sd(stat[!is.na(stat) & is.finite(stat)])
  }
}

#add these statistics to plotting data
#create copy of mms
mms_corr <- mms
#use corrected estimates
mms_corr$estimate <- mms_corr$estimate_corr
#with bootstrapped standard errors
mms_corr$std.error <- test1$bootSE
#and confidence intervals
mms_corr$upper <- mms_corr$estimate + 1.96*mms_corr$std.error
mms_corr$lower <- mms_corr$estimate - 1.96*mms_corr$std.error

# redo the plots:
age <- mms_corr[grep("age", mms_corr$feature), ]
age$Current <- factor(age$Current, levels = c("Few people aged 45+", "Many people aged 45+"))

page <- plot(age, vline =1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  facet_nested(Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
  scale_x_continuous( limits = c(.38,.62), labels = scales::number_format(accuracy = 0.01)) +
  scale_y_discrete(labels = c("half (50%)", "just under half (40%)", "a quarter (25%)")) +
    theme(
    legend.position = "none",
    legend.direction = "vertical",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

eth <- mms_corr[grep("eth", mms_corr$feature), ]
eth$Current <- factor(eth$Current, levels = c("Few people with Turk/Moroc background", "Many people with Turk/Moroc background"))

peth <- plot(eth, vline =1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  facet_nested(Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
  scale_x_continuous( limits = c(0,0.99), labels = scales::number_format(accuracy = 0.01)) +
  scale_y_discrete(labels = c("a quarter (25%)", "minority (10%)", "none (0%)")) +
    theme(
    legend.position = "none",
    legend.direction = "vertical",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

educ <- mms_corr[grep("educ", mms_corr$feature), ]
educ$Current <- factor(educ$Current, levels = c("Few high income households", "Many high income households"))

peduc <- plot(educ, vline =1/2, feature_headers = NA, size = 2, group = "Current", xlab = "Marginal mean") +
  facet_nested(Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
  scale_x_continuous( limits = c(0.35,0.64), labels = scales::number_format(accuracy = 0.01)) +
  scale_y_discrete(labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")) +
    theme(
    legend.position = "none",
    legend.direction = "vertical",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

#combine all in one
combiplot <- ggpubr::ggarrange(page,peth,peduc, ncol = 3, vjust = .9)
 
#and add custom legend
p <- plot_grid(combiplot, legs, align = "h", nrow=2, rel_heights = c(4.5,1))
plot(p)

ggsave("./figures/cmms_liss_current_obj_corr.png", p, width=13) 


5.5 additional analyses

5.5.1 only the first setting

Respondents performed choice tasks for neighborhoods and civic organizations in a random order. Let’s redo the analysis, including for each setting only the responses from those whose first task was that particular setting.

#1. nbh
nmmeduc <- cregg::cj(df[!is.na(df$Tert) & df$block_order == 2, ], enbh_choice ~ enbh_comp_educ, id = ~id, estimate = "mm", by = ~Tert)
nmmage <- cregg::cj(df[!is.na(df$Age) & df$block_order == 2, ], enbh_choice ~ enbh_comp_age, id = ~id, estimate = "mm", by = ~Age)
nmmeth <- cregg::cj(df[!is.na(df$TM) & df$block_order == 2, ], enbh_choice ~ enbh_comp_eth, id = ~id, estimate = "mm", by = ~TM)

#2. org
cmmeduc <- cregg::cj(df[!is.na(df$Tert) & df$block_order == 1, ], eciv_choice ~ eciv_comp_educ, id = ~id, estimate = "mm", by = ~Tert)
cmmage <- cregg::cj(df[!is.na(df$Age) & df$block_order == 1, ], eciv_choice ~ eciv_comp_age, id = ~id, estimate = "mm", by = ~Age)
cmmeth <- cregg::cj(df[!is.na(df$TM) & df$block_order == 1, ], eciv_choice ~ eciv_comp_eth, id = ~id, estimate = "mm", by = ~TM)

#rowbind the dataframes
#leave out last column, reflecting the subgrouping variable
mms <- rbind(nmmage[-12],nmmeth[-12],nmmeduc[-12],
             cmmage[-12],cmmeth[-12],cmmeduc[-12])

#rename labels
#1. of outcome (setting)
mms$Outcome <- factor(ifelse(mms$outcome == "eciv_choice", "Civic organizations", "Neighborhoods"),
                       levels = c("Neighborhoods", "Civic organizations"))

#2. of (demographic composition) features
mms$Feature <- factor(sub(".*_", "", mms$feature), 
                        levels = c("age", "eth", "educ"),
                        labels = c("Share of people aged 50 years or older", "Share of people with Turk/Moroc background",  "Share of people with a college degree"))

mms$Subgroup <- mms$BY
mms$Subgroup <- factor(mms$Subgroup, levels = c("50 years or older", "Below 50 years", "Turkish/Moroccan background", "No migration background" , "With college degree","Without college degree"  )) 

# nice color palette
cbPalette <- c("#999999","#E69F00","#56B4E9","#D55E00","#F0E442","#0072B2")

p2 <- plot(mms, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette) +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people with a college degree" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      Feature == "Share of people aged 50 years or older" ~ scale_y_discrete(
        labels = c("half (50%)", "just under half (40%)", "a quarter (25%)")),
      Feature == "Share of people with Turk/Moroc background" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "none (0%)"))
      ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.4,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people aged 50 years or older" ~ scale_x_continuous(
        limits = c(.43,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with Turk/Moroc background" ~ scale_x_continuous(
        limits = c(.30,.70), labels = scales::number_format(accuracy = 0.01))
      )) +
  theme(legend.position = "none",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")

#split legend into multiple parts
split1 <- mms[mms$Subgroup %in% c("50 years or older", "Below 50 years"), ]
split2 <- mms[mms$Subgroup %in% c("Turkish/Moroccan background", "No migration background"), ]
split3 <- mms[mms$Subgroup %in% c("With college degree", "Without college degree"), ]

#reverse order factor.... bug in ggplot2 makes the order of the subgroups in the plot and the legend reversed
split1$Subgroup <- factor(split1$Subgroup, levels = rev(levels(split1$Subgroup)))
split2$Subgroup <- factor(split2$Subgroup, levels = rev(levels(split2$Subgroup)))
split3$Subgroup <- factor(split3$Subgroup, levels = rev(levels(split3$Subgroup)))

#plot legends
split1p <- ggplot(split1, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(2,1)]) 
split2p <- ggplot(split2, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(4,3)])
split3p <- ggplot(split3, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(6,5)])

#get legends
leg1 <- get_legend(split1p)
leg2 <- get_legend(split2p)
leg3 <- get_legend(split3p)

#combine legends
leg123 <- plot_grid(leg1,leg2,leg3, nrow=1, align="h")

#create a blank plot for legend alignment
blank_p <- plot_spacer()

#combine all in one
p3 <- plot_grid(p2, leg123, align = "h", nrow=2, rel_heights = c(7,1))
#ggsave("./figures/cmms_liss_onlyfirst.png", p, width=13) 
plot(p3)

fbootf <- function(data, i) {
   # sample respondent IDs with replacement
  ids <- sample(unique(data$id), length(unique(data$id)), replace = TRUE)

  # create a new dataset by iterating over each sampled id and binding the matching rows
  d <- map_dfr(ids, ~ data %>% filter(id == .x)) 
  
  datasets <- list(df[!is.na(df$rep_org_choice), ], df[!is.na(df$rep_nbh_choice), ])
  tasks <- list(c("first_org_choice", "rep_org_choice"), c("first_nbh_choice", "rep_nbh_choice"))
  labels <- c("organizations", "neighborhoods")

  swapping <- list()
  for (i in 1:length(datasets)) {
    dataset <- datasets[[i]]
    dataset$repchoice <- ifelse(dataset[[tasks[[i]][1]]] == dataset[[tasks[[i]][2]]], 1, 0)

    irr_list <- f_irr(dataset)
    tau_list <- f_tau(irr_list)

    swapping[[labels[i]]] <- list("irr" = irr_list, "tau" = tau_list)
  }
  
  # calculate conditional marginal means:
  x_vars <- cbind(c("Age", "TM", "Tert"), c("age", "eth", "educ"))
  y_vars <- c("enbh", "eciv")
    
  results <- data.frame()

  for(x in 1:nrow(x_vars)) {
    for(y in y_vars) {
      
      # formula  
      f <- as.formula( paste0(y, "_choice ~ ", y, "_comp_", x_vars[x,2]))
      by <- as.formula(paste0("~", x_vars[x,1]))
        
      # importantly! filter data based on block_order (i.e., include only responses of respondents whose first choice experiments was in setting y)
  
      if (y == "enbh") {
        dd <- d[d$block_order == 2, ]
      } else if (y == "eciv") {
        dd <- d[d$block_order == 1, ]
      }
      
      #estimate marginal means
      cmms <- cregg::cj( dd[!is.na(dd[x_vars[x,1]]), ], 
                         #exclude missings on the subgrouping variable
                           formula = f, id = ~id, estimate = "mm", by = by)
      
      #bind results
      results <- rbind(results, cmms[,-12])
      }
    }
  
  #calculate corrected conditional marginal mean (for subgroups)
  results$estimate_corr <- NA
    
  for (i in 1:nrow(results)) { 
    #retrieve setting and subgroup
    setting <- ifelse(results$outcome[i] == "enbh_choice", "neighborhoods", "organizations")
    subgroup <- as.character(results$BY[i])

    tau <- swapping[[setting]]$tau[subgroup]
    
    #define bias corrected MM (eq. 11 of Clayton et al.)
    results$estimate_corr[i] <- (results$estimate[i] - tau) / (1 - 2*tau)

  }
  return(results$estimate_corr)  
}
#fbootf(df)#test

nCore <- detectCores() - 1 #detect number of cores (keep one for other tasks)
nIter <- 1000 #number of bootstrap iterations

mycl <- makeCluster(rep("localhost", nCore)) #set up cluster
#load necessary library on each cluster node
clusterEvalQ(mycl, {
  library(cregg)
  library(purrr)
  library(dplyr)
})

#copy data and custom functions to each node's workspace
clusterExport(mycl, varlist=c("df", "f_tau", "f_irr", "fbootf")) 

#perform bootstrap:
system.time(test <- boot(df, fbootf, R=nIter, parallel = "snow", ncpus = nCore, cl = mycl)) 
save(test, file = "./results/boot4.Rda")
stopCluster(mycl)
load("./results/boot4.Rda")
load("./data/rownames.Rda")
nIter = 1000

# Some NA values may occur because, in certain bootstrap iterations, no individuals from minority groups are sampled due to their small sample size. replace these NA values with the mean of the corresponding bootstrapped CMM estimates, ignoring any NAs during the calculation.
for (i in 1:length(test$t0)) {
  if(is.na(test$t0[i])) {
    test$t0[i] <- mean(test$t[,i][is.finite(test$t[, i])], na.rm=TRUE)
  }
}

test1 <- summary(test)

#add rownames
rownames(test1) <- rnames
#str(test)

#first add the original bias corrected CMMs to the dataframe (instead of the bootstrap estimates):
#create a merge variable in the original CMM dataframe
mms$BY2 <- paste0(mms$outcome, "-", mms$level, "-", mms$BY)
#reorder
mms <- mms[match(rownames(test1), mms$BY2),]

#now calculate the corrected CMMS
for (i in 1:nrow(mms)) { # for each CMM
    #retrieve setting and subgroup
    setting <- ifelse(mms$outcome[i] == "enbh_choice", "neighborhoods", "organizations")
    subgroup <- as.character(mms$BY[i])
    
    #get tau from our saved list
    tau <- swappingList[[setting]]$tau[subgroup]
    #define bias corrected MM (eq. 11 of Clayton et al.)
    mms$estimate_corr[i] <- (mms$estimate[i] - tau) / (1 - 2*tau)
}

#calculate standard deviation of bootstrap statistics
for (i in 1:nrow(test1)) {
  if(test1$R[i] < nIter) {
    stat <- test$t[,i]
    test1$bootSE[i] <- sd(stat[!is.na(stat) & is.finite(stat)])
  }
}

#corr(cbind(mms$estimate_corr, test1$original))

#add these statistics to plotting data
#create copy of mms
mms_corr <- mms
#use corrected estimates
mms_corr$estimate <- mms_corr$estimate_corr
#with bootstrapped standard errors
mms_corr$std.error <- test1$bootSE
#and confidence intervals
mms_corr$upper <- mms_corr$estimate + 1.96*mms_corr$std.error
mms_corr$lower <- mms_corr$estimate - 1.96*mms_corr$std.error

p <- plot(mms_corr, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup", xlab = "Marginal mean") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette) +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people with a college degree" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      Feature == "Share of people aged 50 years or older" ~ scale_y_discrete(
        labels = c("half (50%)", "just under half (40%)", "a quarter (25%)")),
      Feature == "Share of people with Turk/Moroc background" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "none (0%)"))
      ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.35,.65), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people aged 50 years or older" ~ scale_x_continuous(
        limits = c(.40,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with Turk/Moroc background" ~ scale_x_continuous(
        limits = c(0,.95), labels = scales::number_format(accuracy = 0.01))
      )) +
  theme(legend.position = "none",
       # strip.text.x = element_markdown(),
        strip.placement = "outside")
 
p <- plot_grid(p, leg123, align = "h", nrow=2, rel_heights = c(7,1))

#fshowdf(mms_corr[,-c(14, 15,16)], caption = "Measurement error bias corrected conditional marginal means")

#plot(p)
ggsave("./figures/cmms_liss_onlyfirst_corrected.png", p, width=13) 
Subgroup marginal means, only considering the first choice task presented to respondents
Subgroup marginal means, only considering the first choice task presented to respondents

5.5.2 subgroup specific travel time estimates

# get full solution for subgroups
nbhTert <- cregg::cj(df[!is.na(df$Tert), ], fnbh, id = ~id, estimate = "mm", by = ~Tert)
civTert <- cregg::cj(df[!is.na(df$Tert), ], fciv, id = ~id, estimate = "mm", by = ~Tert)
nbhAge <- cregg::cj(df[!is.na(df$Age), ], fnbh, id = ~id, estimate = "mm", by = ~Age)
civAge <- cregg::cj(df[!is.na(df$Age), ], fciv, id = ~id, estimate = "mm", by = ~Age)
nbhEth <- cregg::cj(df[!is.na(df$TM), ], fnbh, id = ~id, estimate = "mm", by = ~TM)
civEth <- cregg::cj(df[!is.na(df$TM), ], fciv, id = ~id, estimate = "mm", by = ~TM)

# filter on travel time attributes
nbh_timeTert <- nbhTert[grep("time", nbhTert$feature), ]
civ_timeTert <- civTert[grep("time", civTert$feature), ]
nbh_timeAge <- nbhAge[grep("time", nbhAge$feature), ]
civ_timeAge <- civAge[grep("time", civAge$feature), ]
nbh_timeEth <- nbhEth[grep("time", nbhEth$feature), ]
civ_timeEth <- civEth[grep("time", civEth$feature), ]

# now adjust the estimates for measurement error
nbh_timeTert$estimate[nbh_timeTert$BY == "With college degree"] <- (nbh_timeTert$estimate[nbh_timeTert$BY ==
    "With college degree"] - swappingList$neighborhoods$tau["With college degree"])/(1 - 2 * swappingList$neighborhoods$tau["With college degree"])
nbh_timeTert$estimate[nbh_timeTert$BY == "Without college degree"] <- (nbh_timeTert$estimate[nbh_timeTert$BY ==
    "Without college degree"] - swappingList$neighborhoods$tau["Without college degree"])/(1 - 2 * swappingList$neighborhoods$tau["Without college degree"])
civ_timeTert$estimate[civ_timeTert$BY == "With college degree"] <- (civ_timeTert$estimate[civ_timeTert$BY ==
    "With college degree"] - swappingList$neighborhoods$tau["With college degree"])/(1 - 2 * swappingList$neighborhoods$tau["With college degree"])
civ_timeTert$estimate[civ_timeTert$BY == "Without college degree"] <- (civ_timeTert$estimate[civ_timeTert$BY ==
    "Without college degree"] - swappingList$neighborhoods$tau["Without college degree"])/(1 - 2 * swappingList$neighborhoods$tau["Without college degree"])

nbh_timeAge$estimate[nbh_timeAge$BY == "50 years or older"] <- (nbh_timeAge$estimate[nbh_timeAge$BY ==
    "50 years or older"] - swappingList$neighborhoods$tau["50 years or older"])/(1 - 2 * swappingList$neighborhoods$tau["50 years or older"])
nbh_timeAge$estimate[nbh_timeAge$BY == "Below 50 years"] <- (nbh_timeAge$estimate[nbh_timeAge$BY == "Below 50 years"] -
    swappingList$neighborhoods$tau["Below 50 years"])/(1 - 2 * swappingList$neighborhoods$tau["Below 50 years"])
civ_timeAge$estimate[civ_timeAge$BY == "50 years or older"] <- (civ_timeAge$estimate[civ_timeAge$BY ==
    "50 years or older"] - swappingList$neighborhoods$tau["50 years or older"])/(1 - 2 * swappingList$neighborhoods$tau["50 years or older"])
civ_timeAge$estimate[civ_timeAge$BY == "Below 50 years"] <- (civ_timeAge$estimate[civ_timeAge$BY == "Below 50 years"] -
    swappingList$neighborhoods$tau["Below 50 years"])/(1 - 2 * swappingList$neighborhoods$tau["Below 50 years"])

nbh_timeEth$estimate[nbh_timeEth$BY == "Turkish/Moroccan background"] <- (nbh_timeEth$estimate[nbh_timeEth$BY ==
    "Turkish/Moroccan background"] - swappingList$neighborhoods$tau["Turkish/Moroccan background"])/(1 -
    2 * swappingList$neighborhoods$tau["Turkish/Moroccan background"])
nbh_timeEth$estimate[nbh_timeEth$BY == "No migration background"] <- (nbh_timeEth$estimate[nbh_timeEth$BY ==
    "No migration background"] - swappingList$neighborhoods$tau["No migration background"])/(1 - 2 *
    swappingList$neighborhoods$tau["No migration background"])
civ_timeEth$estimate[civ_timeEth$BY == "Turkish/Moroccan background"] <- (civ_timeEth$estimate[civ_timeEth$BY ==
    "Turkish/Moroccan background"] - swappingList$neighborhoods$tau["Turkish/Moroccan background"])/(1 -
    2 * swappingList$neighborhoods$tau["Turkish/Moroccan background"])
civ_timeEth$estimate[civ_timeEth$BY == "No migration background"] <- (civ_timeEth$estimate[civ_timeEth$BY ==
    "No migration background"] - swappingList$neighborhoods$tau["No migration background"])/(1 - 2 *
    swappingList$neighborhoods$tau["No migration background"])

time_estimates <- rbind(civ_timeTert[, c(1, 2, 5, 6)], nbh_timeTert[, c(1, 2, 5, 6)], civ_timeAge[, c(1,
    2, 5, 6)], nbh_timeAge[, c(1, 2, 5, 6)], civ_timeEth[, c(1, 2, 5, 6)], nbh_timeEth[, c(1, 2, 5, 6)])

colnames(time_estimates) <- c("Respondent_subgroup", "Setting", "Level", "Estimate")
time_estimates$Setting <- ifelse(time_estimates$Setting == "eciv_choice", "Civic organizations", "Neighborhoods")
time_estimates$Setting <- factor(time_estimates$Setting, levels = c("Neighborhoods", "Civic organizations"))
time_estimates$Level <- gsub("travel time to facilities: ", "", gsub("travel time: ", "", time_estimates$Level))

ggplot(time_estimates, aes(x = Level, y = Estimate, color = Setting, group = interaction(Setting, Respondent_subgroup))) +
    geom_point(size = 3) + geom_line() + geom_smooth(method = "lm", se = FALSE, linetype = "dashed",
    size = 0.8) + facet_grid(Setting ~ Respondent_subgroup, scales = "free_x") + labs(title = "Corrected subgroup marginal means for travel time levels",
    subtitle = "Dashed lines represent linear effects", x = "Travel time (to key amenities / from home)",
    y = "Marginal mean", color = "Setting") + theme_minimal() + theme(axis.text.x = element_text(angle = 45,
    hjust = 1), strip.text.y = element_blank(), legend.position = "top", legend.title = element_text(size = 12,
    face = "bold"), legend.text = element_text(size = 10))

fshowdf(time_estimates, caption = "Corrected subgroup marginal means for travel time levels", digit = 3)
Corrected subgroup marginal means for travel time levels
Respondent_subgroup Setting Level Estimate
1 With college degree Civic organizations 20 minutes 0.395
2 With college degree Civic organizations 15 minutes 0.503
3 With college degree Civic organizations 10 minutes 0.599
24 Without college degree Civic organizations 20 minutes 0.403
25 Without college degree Civic organizations 15 minutes 0.501
26 Without college degree Civic organizations 10 minutes 0.597
11 With college degree Neighborhoods 20 minutes 0.368
21 With college degree Neighborhoods 15 minutes 0.497
31 With college degree Neighborhoods 10 minutes 0.632
241 Without college degree Neighborhoods 20 minutes 0.397
251 Without college degree Neighborhoods 15 minutes 0.493
261 Without college degree Neighborhoods 10 minutes 0.611
12 50 years or older Civic organizations 20 minutes 0.415
22 50 years or older Civic organizations 15 minutes 0.496
32 50 years or older Civic organizations 10 minutes 0.589
242 Below 50 years Civic organizations 20 minutes 0.369
252 Below 50 years Civic organizations 15 minutes 0.514
262 Below 50 years Civic organizations 10 minutes 0.613
13 50 years or older Neighborhoods 20 minutes 0.376
23 50 years or older Neighborhoods 15 minutes 0.497
33 50 years or older Neighborhoods 10 minutes 0.626
243 Below 50 years Neighborhoods 20 minutes 0.393
253 Below 50 years Neighborhoods 15 minutes 0.491
263 Below 50 years Neighborhoods 10 minutes 0.617
14 Turkish/Moroccan background Civic organizations 20 minutes 0.390
27 Turkish/Moroccan background Civic organizations 15 minutes 0.555
34 Turkish/Moroccan background Civic organizations 10 minutes 0.555
244 No migration background Civic organizations 20 minutes 0.400
254 No migration background Civic organizations 15 minutes 0.502
264 No migration background Civic organizations 10 minutes 0.598
15 Turkish/Moroccan background Neighborhoods 20 minutes 0.436
28 Turkish/Moroccan background Neighborhoods 15 minutes 0.474
35 Turkish/Moroccan background Neighborhoods 10 minutes 0.588
245 No migration background Neighborhoods 20 minutes 0.384
255 No migration background Neighborhoods 15 minutes 0.493
265 No migration background Neighborhoods 10 minutes 0.622

6 TRIAL sports club choice experiment

6.1 Subgroup marginal means

#create subgroups

df2$Tert <- NA_real_
df2$Tert[df2$tert_educ == 1] <- 1L
df2$Tert[df2$tert_educ == 0] <- 2L
df2$Tert <- factor(df2$Tert, 1:2, c("With college degree", "Without college degree"))

df2$Migr <- NA_real_
df2$Migr[df2$migration == 1] <- 1L
df2$Migr[df2$migration == 0] <- 2L
df2$Migr <- factor(df2$Migr, 1:2, c( "Migration background","No migration background"))

#outcome and conjoint features, including only composition features we are interested in;
#and the subgrouping variable

#conditional marginal means (composition dimension; disaggregated by respondent value for this dimension)

#1. club
cmmeduc <- cregg::cj(df2[!is.na(df2$Tert), ], choice ~ educ_club, id = ~id, estimate = "mm", by = ~Tert)
cmmeth <- cregg::cj(df2[!is.na(df2$Migr), ], choice ~ migrant_club, id ~id, estimate = "mm", by = ~Migr)

#2. team
tmmeduc <- cregg::cj(df2[!is.na(df2$Tert), ], choice ~ educ_team, id = ~id, estimate = "mm", by = ~Tert)
tmmeth <- cregg::cj(df2[!is.na(df2$Migr), ], choice ~ migrant_team, id ~id, estimate = "mm", by = ~Migr)

#rowbind the dataframes
#leave out last column, reflecting the subgrouping variable
mms <- rbind(cmmeduc[-12],tmmeduc[-12],
             cmmeth[-12],tmmeth[-12])

#rename labels
#1. of outcome (setting)
mms$Outcome <- factor(ifelse( grepl("club", mms$feature), "Club", "Team / training group"), levels = c("Club", "Team / training group"))

#2. of (demographic composition) features
mms$Feature <- factor(sub("_.+", "", mms$feature), levels = c("migrant", "educ"),
                      labels = c("Share of people with a migration background", "Share of people with a college degree"))

mms$Subgroup <- mms$BY

# nice color palette
cbPalette <- c("#F0E442","#0072B2", "#56B4E9","#D55E00")

p <- plot(mms, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette) +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people with a college degree" & Outcome == "Club" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      
      Feature == "Share of people with a college degree"  & Outcome == "Team / training group" ~ scale_y_discrete(
        labels = c("majority (90%)", "three quarters (75%)", "half (50%)", "a quarter (25%)", "minority (10%)")),
      
      Feature == "Share of people with a migration background" & Outcome == "Club" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "a few (5%)")),
      
      Feature == "Share of people with a migration background" & Outcome == "Team / training group" ~ scale_y_discrete(
        labels = c("half (50%)", "a quarter (25%)", "minority (10%)", "a few (5%)", "none (0%)"))
    ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.42,.58), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with a migration background" ~ scale_x_continuous(
        limits = c(.42,.58), labels = scales::number_format(accuracy = 0.01))
    )
  ) +
  theme(legend.position = "none",
        #strip.text.x = element_markdown(),
        strip.placement = "outside")

#split legend into multiple parts
split1 <- mms[mms$Subgroup %in% c("Migration background", "No migration background"), ]
split2 <- mms[mms$Subgroup %in% c("With college degree", "Without college degree"), ]

#reverse order factor.... bug in ggplot2 makes the order of the subgroups in the plot and the legend reversed
split1$Subgroup <- factor(split1$Subgroup, levels = rev(levels(split1$Subgroup)))
split2$Subgroup <- factor(split2$Subgroup, levels = rev(levels(split2$Subgroup)))

#plot legends
split1p <- ggplot(split1, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Respondent subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(4,3)]) 
split2p <- ggplot(split2, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Respondent subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(2,1)])

#get legends
leg1 <- get_legend(split1p)
leg2 <- get_legend(split2p)

#combine legends
leg12 <- plot_grid(leg1,leg2, nrow=1, align="h")

#create a blank plot for legend alignment
blank_p <- plot_spacer()

#combine all in one
p <- plot_grid(p, leg12, align = "h", nrow=2, rel_heights = c(9,1))

print(p)

#ggsave("./figures/cmms_trial.png", p, width=9) 

6.2 use LISS-based bias correction

# create dataframe
swapping2 <- data.frame(x = c("With college degree", "Without college degree", "Migration background",
    "No migration background"), tau = NA)

# we retrieve LISS-based swapping errors
swapping2$tau <- ifelse(swapping2$x == "With college degree", swapping$organizations$tau[["With college degree"]],
    ifelse(swapping2$x == "Without college degree", swapping$organizations$tau[["Without college degree"]],
        ifelse(swapping2$x == "No migration background", swapping$organizations$tau[["No migration background"]],
            ifelse(swapping2$x == "Migration background", swapping$organizations$tau[["Turkish/Moroccan background"]],
                NA))))

fboot <- function(data, i) {
    # sample respondent IDs with replacement
    ids <- sample(unique(data$id), length(unique(data$id)), replace = TRUE)

    # create a new dataset by iterating over each sampled id and binding the matching rows
    d <- map_dfr(ids, ~data %>%
        filter(id == .x))

    # calculate conditional marginal means:
    x_vars <- cbind(c("Migr", "Tert"), c("migrant", "educ"))
    y_vars <- c("club", "team")

    results <- data.frame()

    for (x in 1:nrow(x_vars)) {
        for (y in y_vars) {

            # formula
            f <- as.formula(paste0("choice ~ ", x_vars[x, 2], "_", y))
            by <- as.formula(paste0("~", x_vars[x, 1]))

            cmms <- cregg::cj(d[!is.na(d[x_vars[x, 1]]), ], formula = f, id = ~id, estimate = "mm", by = by)

            # bind results
            results <- rbind(results, cmms[, -12])
        }
    }

    # calculate corrected conditional marginal mean (for subgroups)
    results$estimate_corr <- NA

    for (i in 1:nrow(results)) {
        # retrieve subgroup
        subgroup <- as.character(results$BY[i])
        tau <- swapping2$tau[swapping2$x == subgroup]

        # define bias corrected MM (eq. 11 of Clayton et al.)
        results$estimate_corr[i] <- (results$estimate[i] - tau)/(1 - 2 * tau)

    }
    # save rownames rnames3 <- paste0( results$outcome, '-', results$level, '-', results$BY)
    # save(rnames3, file = './data/rownames3.Rda')

    return(results$estimate_corr)
}
# fboot(df2)#test

nCore <- detectCores() - 1  #detect number of cores (keep one for other tasks)
nIter <- 1000  #number of bootstrap iterations

# set up cluster
mycl <- makeCluster(rep("localhost", nCore))

# load necessary library on each cluster node
clusterEvalQ(mycl, {
    library(cregg)
    library(purrr)
    library(dplyr)
})

# copy data and custom functions to each node's workspace
clusterExport(mycl, varlist = c("df2", "f_tau", "f_irr", "fboot", "swapping2"))

# perform bootstrap:
system.time(test <- boot(df2, fboot, R = nIter, parallel = "snow", ncpus = nCore, cl = mycl))  #about 30 min on my pc
# save(test, file = './results/boot5.Rda')
stopCluster(mycl)
load("./results/boot5.Rda")
load("./data/rownames3.Rda")
nIter = 1000

test1 <- summary(test)
#add rownames
rownames(test1) <- rnames3

#print(test1)

#first add the original bias corrected CMMs to the dataframe:
#create a merge variable in the original CMM dataframe
mms$BY2 <- paste0(mms$outcome, "-", mms$level, "-", mms$BY)
#reorder
mms <- mms[match(rownames(test1), mms$BY2),]

#now calculate the corrected CMMS
for (i in 1:nrow(mms)) { # for each CMM
    #retrieve setting and subgroup
    setting <- "organizations" #use LISS-based swapping error for organizations experiment
    subgroup <- as.character(mms$BY[i])
    subgroup <- ifelse(subgroup == "Migration background", "Turkish/Moroccan background", subgroup) # if migration background, use swapping error of TM
    #get tau from our saved list
    tau <- swappingList[[setting]]$tau[subgroup]
    #define bias corrected MM (eq. 11 of Clayton et al.)
    mms$estimate_corr[i] <- (mms$estimate[i] - tau) / (1 - 2*tau)
}

#add these statistics to plotting data

#create copy of mms
mms_corr <- mms

#use corrected estimates
mms_corr$estimate <- mms_corr$estimate_corr

#with bootstrapped standard errors
mms_corr$std.error <- test1$bootSE
#and confidence intervals
mms_corr$upper <- mms_corr$estimate + 1.96*mms_corr$std.error
mms_corr$lower <- mms_corr$estimate - 1.96*mms_corr$std.error

#plot
p <- plot(mms_corr, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup", xlab = "Marginal mean") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette) +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people with a college degree" & Outcome == "Club" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      
      Feature == "Share of people with a college degree"  & Outcome == "Team / training group" ~ scale_y_discrete(
        labels = c("majority (90%)", "three quarters (75%)", "half (50%)", "a quarter (25%)", "minority (10%)")),
        
      Feature == "Share of people with a migration background" & Outcome == "Club" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "a few (5%)")),
      
      Feature == "Share of people with a migration background" & Outcome == "Team / training group" ~ scale_y_discrete(
        labels = c("half (50%)", "a quarter (25%)", "minority (10%)", "a few (5%)", "none (0%)"))
      ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.38,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with a migration background" ~ scale_x_continuous(
        limits = c(.28,.70), labels = scales::number_format(accuracy = 0.01))
    )
    ) +
  theme(legend.position = "none",
        #strip.text.x = element_markdown(),
        strip.placement = "outside")

p <- plot_grid(p, leg12, align = "h", nrow=2, rel_heights = c(9,1))
fshowdf(mms_corr[,-c(15,16)], caption = "Measurement error bias corrected conditional marginal means")
Measurement error bias corrected conditional marginal means
BY outcome statistic feature level estimate std.error z p lower upper Outcome Feature Subgroup
17 Migration background choice mm migrant_club club members with migration background: a quarter (25%) 0.44 0.04 30.00 0 0.36 0.53 Club Share of people with a migration background Migration background
18 Migration background choice mm migrant_club club members with migration background: minority (10%) 0.60 0.05 29.54 0 0.50 0.69 Club Share of people with a migration background Migration background
19 Migration background choice mm migrant_club club members with migration background: a few (5%) 0.46 0.05 28.88 0 0.37 0.55 Club Share of people with a migration background Migration background
20 No migration background choice mm migrant_club club members with migration background: a quarter (25%) 0.49 0.01 84.21 0 0.47 0.50 Club Share of people with a migration background No migration background
21 No migration background choice mm migrant_club club members with migration background: minority (10%) 0.51 0.01 84.08 0 0.49 0.53 Club Share of people with a migration background No migration background
22 No migration background choice mm migrant_club club members with migration background: a few (5%) 0.51 0.01 82.18 0 0.49 0.52 Club Share of people with a migration background No migration background
23 Migration background choice mm migrant_team contacts with migration background: half (50%) 0.65 0.06 25.56 0 0.53 0.76 Team / training group Share of people with a migration background Migration background
24 Migration background choice mm migrant_team contacts with migration background: a quarter (25%) 0.35 0.07 19.41 0 0.22 0.47 Team / training group Share of people with a migration background Migration background
25 Migration background choice mm migrant_team contacts with migration background: minority (10%) 0.65 0.07 22.60 0 0.52 0.78 Team / training group Share of people with a migration background Migration background
26 Migration background choice mm migrant_team contacts with migration background: a few (5%) 0.54 0.06 23.72 0 0.43 0.66 Team / training group Share of people with a migration background Migration background
27 Migration background choice mm migrant_team contacts with migration background: none (0%) 0.28 0.07 18.78 0 0.15 0.42 Team / training group Share of people with a migration background Migration background
28 No migration background choice mm migrant_team contacts with migration background: half (50%) 0.47 0.01 56.78 0 0.45 0.50 Team / training group Share of people with a migration background No migration background
29 No migration background choice mm migrant_team contacts with migration background: a quarter (25%) 0.50 0.01 61.31 0 0.47 0.52 Team / training group Share of people with a migration background No migration background
30 No migration background choice mm migrant_team contacts with migration background: minority (10%) 0.51 0.01 60.64 0 0.49 0.53 Team / training group Share of people with a migration background No migration background
31 No migration background choice mm migrant_team contacts with migration background: a few (5%) 0.51 0.01 62.53 0 0.49 0.53 Team / training group Share of people with a migration background No migration background
32 No migration background choice mm migrant_team contacts with migration background: none (0%) 0.51 0.01 59.94 0 0.48 0.53 Team / training group Share of people with a migration background No migration background
1 With college degree choice mm educ_club club members with tertiary education: three quarters (75%) 0.55 0.01 85.48 0 0.53 0.57 Club Share of people with a college degree With college degree
2 With college degree choice mm educ_club club members with tertiary education: half (50%) 0.48 0.01 76.92 0 0.46 0.50 Club Share of people with a college degree With college degree
3 With college degree choice mm educ_club club members with tertiary education: a quarter (25%) 0.47 0.01 74.11 0 0.45 0.49 Club Share of people with a college degree With college degree
4 Without college degree choice mm educ_club club members with tertiary education: three quarters (75%) 0.50 0.02 42.96 0 0.46 0.53 Club Share of people with a college degree Without college degree
5 Without college degree choice mm educ_club club members with tertiary education: half (50%) 0.50 0.02 45.72 0 0.47 0.54 Club Share of people with a college degree Without college degree
6 Without college degree choice mm educ_club club members with tertiary education: a quarter (25%) 0.50 0.02 41.21 0 0.46 0.53 Club Share of people with a college degree Without college degree
7 With college degree choice mm educ_team contacts with tertiary education: majority (90%) 0.58 0.01 60.93 0 0.56 0.61 Team / training group Share of people with a college degree With college degree
8 With college degree choice mm educ_team contacts with tertiary education: three quarters (75%) 0.56 0.01 60.92 0 0.54 0.58 Team / training group Share of people with a college degree With college degree
9 With college degree choice mm educ_team contacts with tertiary education: half (50%) 0.52 0.01 57.75 0 0.50 0.55 Team / training group Share of people with a college degree With college degree
10 With college degree choice mm educ_team contacts with tertiary education: a quarter (25%) 0.44 0.01 49.99 0 0.41 0.46 Team / training group Share of people with a college degree With college degree
11 With college degree choice mm educ_team contacts with tertiary education: minority (10%) 0.40 0.01 48.52 0 0.38 0.43 Team / training group Share of people with a college degree With college degree
12 Without college degree choice mm educ_team contacts with tertiary education: majority (90%) 0.52 0.02 31.82 0 0.48 0.57 Team / training group Share of people with a college degree Without college degree
13 Without college degree choice mm educ_team contacts with tertiary education: three quarters (75%) 0.48 0.02 29.37 0 0.43 0.53 Team / training group Share of people with a college degree Without college degree
14 Without college degree choice mm educ_team contacts with tertiary education: half (50%) 0.51 0.02 32.42 0 0.46 0.56 Team / training group Share of people with a college degree Without college degree
15 Without college degree choice mm educ_team contacts with tertiary education: a quarter (25%) 0.48 0.03 28.51 0 0.43 0.53 Team / training group Share of people with a college degree Without college degree
16 Without college degree choice mm educ_team contacts with tertiary education: minority (10%) 0.51 0.02 30.96 0 0.46 0.55 Team / training group Share of people with a college degree Without college degree
plot(p)

#ggsave("./figures/cmms_trial_corrected.png", p, width=9) 
#ggsave("./figures/figure04_subgroup_mm.png", p, width=9) 


6.3 sensitivity checks

6.3.1 focus only on those with non-western migration background

#create new subgroup (nw vs no migration background)
df2$Migr2 <- NA_real_
df2$Migr2[df2$migration_nw == 1] <- 1L
df2$Migr2[df2$migration_nw == 0] <- 2L
df2$Migr2 <- factor(df2$Migr2, 1:2, c( "Non-western migration background","No migration background"))

#outcome and conjoint features, including only composition features we are interested in;
#and the subgrouping variable

#conditional marginal means (composition dimension; disaggregated by respondent value for this dimension)

#1. club
cmmeduc <- cregg::cj(df2[!is.na(df2$Tert), ], choice ~ educ_club, id = ~id, estimate = "mm", by = ~Tert)
cmmeth <- cregg::cj(df2[!is.na(df2$Migr2), ], choice ~ migrant_club, id ~id, estimate = "mm", by = ~Migr2)

#2. team
tmmeduc <- cregg::cj(df2[!is.na(df2$Tert), ], choice ~ educ_team, id = ~id, estimate = "mm", by = ~Tert)
tmmeth <- cregg::cj(df2[!is.na(df2$Migr2), ], choice ~ migrant_team, id ~id, estimate = "mm", by = ~Migr2)

#rowbind the dataframes
#leave out last column, reflecting the subgrouping variable
mms <- rbind(cmmeduc[-12],tmmeduc[-12],
             cmmeth[-12],tmmeth[-12])

#rename labels
#1. of outcome (setting)
mms$Outcome <- factor(ifelse( grepl("club", mms$feature), "Club", "Team / training group"), levels = c("Club", "Team / training group"))

#2. of (demographic composition) features
mms$Feature <- factor(sub("_.+", "", mms$feature), levels = c("migrant", "educ"),
                      labels = c("Share of people with a migration background", "Share of people with a college degree"))

mms$Subgroup <- mms$BY

p <- plot(mms, vline=1/2, feature_headers = NA, size = 2, group = "Subgroup") +
  facet_grid2( Outcome ~ Feature, scales = "free", independent = "y", switch = "y") +
  geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette) +
  facetted_pos_scales(
    y = list(
      Feature == "Share of people with a college degree" & Outcome == "Club" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      
      Feature == "Share of people with a college degree"  & Outcome == "Team / training group" ~ scale_y_discrete(
        labels = c("majority (90%)", "three quarters (75%)", "half (50%)", "a quarter (25%)", "minority (10%)")),
      
      Feature == "Share of people with a migration background" & Outcome == "Club" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "a few (5%)")),
      
      Feature == "Share of people with a migration background" & Outcome == "Team / training group" ~ scale_y_discrete(
        labels = c("half (50%)", "a quarter (25%)", "minority (10%)", "a few (5%)", "none (0%)"))
    ),
    #freeing up the x scales does not work for some reason... so i set them manually:
    x = list(
      Feature == "Share of people with a college degree" ~ scale_x_continuous(
        limits = c(.42,.58), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of people with a migration background" ~ scale_x_continuous(
        limits = c(.38,.58), labels = scales::number_format(accuracy = 0.01))
    )
  ) +
  theme(legend.position = "none",
        #strip.text.x = element_markdown(),
        strip.placement = "outside")

#split legend into multiple parts
split1 <- mms[mms$Subgroup %in% c("Non-western migration background", "No migration background"), ]
split2 <- mms[mms$Subgroup %in% c("With college degree", "Without college degree"), ]

#reverse order factor.... bug in ggplot2 makes the order of the subgroups in the plot and the legend reversed
split1$Subgroup <- factor(split1$Subgroup, levels = rev(levels(split1$Subgroup)))
split2$Subgroup <- factor(split2$Subgroup, levels = rev(levels(split2$Subgroup)))

#plot legends
split1p <- ggplot(split1, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(4,3)]) 
split2p <- ggplot(split2, aes(x = estimate, y = level, color=Subgroup)) + geom_point() + labs(color = "Subgroups:") + theme_bw() + scale_color_manual(values = cbPalette[c(2,1)])

#get legends
leg1 <- get_legend(split1p)
leg2 <- get_legend(split2p)

#combine legends
leg12 <- plot_grid(leg1,leg2, nrow=1, align="h")

#create a blank plot for legend alignment
blank_p <- plot_spacer()

#combine all in one
p <- plot_grid(p, leg12, align = "h", nrow=2, rel_heights = c(9,1))

print(p)

#ggsave("./figures/cmms_trial.png", p, width=9) 

6.3.2 currently (not) involved in a sports club

check whether choice homophily depends on whether people are currently involved in a sports club.

#additional disaggregation by whether people are currently involved in sports club
df2$inv_sportclub[is.na(df2$inv_sportclub)] <- 0 #those that do not do sports, naturally are no member of a sports club...

df2$Tert <- NA_real_
df2$Tert[df2$tert_educ == 1] <- 1L
df2$Tert[df2$tert_educ == 0] <- 2L
df2$Tert <- factor(df2$Tert, 1:2, c("College degree", "No college degree"))

df2$Migr <- NA_real_
df2$Migr[df2$migration == 1] <- 1L
df2$Migr[df2$migration == 0] <- 2L
df2$Migr <- factor(df2$Migr, 1:2, c("Migration background",  "Dutch background"))

#cmms, including only composition measure of interest, the (demographic) subgrouping variable, and further the current involvement

#1.club
cmmeduccur <- cregg::cj(df2[!is.na(df2$Tert), ], choice ~ educ_club, id = ~id, estimate = "mm", by = inv_sportclub ~ Tert )
cmmethcur <- cregg::cj(df2[!is.na(df2$Tert), ], choice ~ migrant_club, id = ~id, estimate = "mm", by = inv_sportclub ~ Migr )

#2.team
tmmeduccur <- cregg::cj(df2[!is.na(df2$Tert), ], choice ~ educ_team, id = ~id, estimate = "mm", by = inv_sportclub ~ Tert )
tmmethcur <- cregg::cj(df2[!is.na(df2$Tert), ], choice ~ migrant_team, id = ~id, estimate = "mm", by = inv_sportclub ~ Migr )

cmmeduccur$Subgroup <- ifelse(grepl("No college degree", cmmeduccur$BY), "No college degree", "College degree")
cmmeduccur$Current <- ifelse(grepl("0", cmmeduccur$BY), "No member of sports club", "Member of sports club")
tmmeduccur$Subgroup <- ifelse(grepl("No college degree", tmmeduccur$BY), "No college degree", "College degree")
tmmeduccur$Current <- ifelse(grepl("0", tmmeduccur$BY), "No member of sports club", "Member of sports club")

cmmethcur$Subgroup <- ifelse(grepl("Migration", cmmethcur$BY), "Migration background", "Dutch background")
cmmethcur$Current <- ifelse(grepl("0", cmmethcur$BY), "No member of sports club", "Member of sports club")
tmmethcur$Subgroup <- ifelse(grepl("Migration", tmmethcur$BY), "Migration background", "Dutch background")
tmmethcur$Current <- ifelse(grepl("0", tmmethcur$BY), "No member of sports club", "Member of sports club")

#combine
cmms <- rbind(cmmeduccur[,-12], tmmeduccur[,-12], cmmethcur[,-12], tmmethcur[, -12])

#rename labels
#outcome (setting)
cmms$Outcome <- factor(ifelse( grepl("club", cmms$feature), "Club", "Team / training group"))

#demographic features
cmms$Feature <- factor(sub("_.*", "", cmms$feature), 
                        levels = c("educ", "migrant"),
                        labels = c("Share of members with a college degree", "Share of members with a migration background"))

ploteduc <- plot(cmms[cmms$Feature == "Share of members with a college degree",],
     vline = 1/2, feature_headers = NA, size = 2, group = "Current") +
   geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  facet_nested( Outcome + Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +
  #geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
    facetted_pos_scales(
           y = list(
      Feature == "Share of members with a college degree" & Outcome == "Club" ~ scale_y_discrete(
        labels = c("three quarters (75%)", "half (50%)", "a quarter (25%)")),
      
      Feature == "Share of members with a college degree" & Outcome == "Team / training group" ~ scale_y_discrete(
        labels = c("majority (90%)", "three quarters (75%)", "half (50%)", "a quarter (25%)", "minority (10%)"))
      ),
          x = list(
      Feature == "Share of members with a college degree" ~ scale_x_continuous(
        limits = c(.40,.60), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of members with a migration background" ~ scale_x_continuous(
        limits = c(.40,.60), labels = scales::number_format(accuracy = 0.01))
    )
      )+
  theme(legend.position = "none",
        #strip.text.x = element_markdown(),
        strip.placement = "outside")

ploteth <- plot(cmms[cmms$Feature == "Share of members with a migration background",],
     vline = 1/2, feature_headers = NA, size = 2, group = "Current") +
   geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  facet_nested( Outcome + Subgroup ~ Feature, scales = "free_y", independent = "y", switch = "y") +
  #geom_text( aes(label = sprintf("%0.2f (%0.2f)", estimate, std.error)), size = 3, colour = "black", vjust = -1, position = position_dodge(width = 0.9)) +
  scale_color_manual(values = cbPalette[c(1,2)]) +
    facetted_pos_scales(
           y = list(
      Feature == "Share of members with a migration background" & Outcome == "Club" ~ scale_y_discrete(
        labels = c("a quarter (25%)", "minority (10%)", "a few (5%)")),
      
      Feature == "Share of members with a migration background" & Outcome == "Team / training group" ~ scale_y_discrete(
        labels = c("half (50%)", "a quarter (25%)", "minority (10%)", "a few (5%)", "none (0%)"))
      ),
      
       x = list(
      Feature == "Share of members with a college degree" ~ scale_x_continuous(
        limits = c(.30,.70), labels = scales::number_format(accuracy = 0.01)),
      Feature == "Share of members with a migration background" ~ scale_x_continuous(
        limits = c(.30,.70), labels = scales::number_format(accuracy = 0.01))
    )
      ) +
  theme(legend.position = "none",
        #strip.text.x = element_markdown(),
        strip.placement = "outside")

combined_plot <- plot_grid(ploteth, ploteduc, align = "h", nrow=1)

#legend
split1 <-  cmms[ grepl("background", cmms$BY), ]

#reverse order factor.... bug in ggplot2 makes the order of the subgroups in the plot and the legend reversed
split1$Current <- factor(split1$Current, levels = rev(levels(as.factor(split1$Current))))

#plot legend
split1p <- ggplot(split1, aes(x = estimate, y = level, color=Current)) + geom_point() + labs(color = "Current involvement:") + theme_bw() + scale_color_manual(values = cbPalette[c(2,1)]) + theme(legend.title = element_markdown())

#get legends
leg1 <- get_legend(split1p)

p6 <- plot_grid(combined_plot,leg1, nrow=2, rel_heights = c(11,1))
plot(p6)

#ggsave("./figures/cmms_trial_current2.png", p6, width=12, height=12) 

References

Cameron, Colin, Jonah Gelbach, and Douglas Miller. 2008. “Bootstrap-Based Improvements for Inference with Clustered Errors.” The Review of Economics and Statistics 90 (3): 414–27. https://doi.org/10.1162/rest.90.3.414.
Clayton, Katherine, Yasuka Horiuchi, Aaron R. Kaufman, Gary King, and Mayya Komisarchick. 2023. “Correcting Measurement Error Bias in Conjoint Survey Experiments.” American Journal of Political Science, 1–11. https://scholar.harvard.edu/sites/scholar.harvard.edu/files/gking/files/conerr.pdf.
Leeper, Thomas J. 2020. Cregg: Simple Conjoint Analyses and Visualization. https://thomasleeper.com/cregg/index.html.
LS0tDQp0aXRsZTogIkFuYWx5c2VzIg0KYmlibGlvZ3JhcGh5OiByZWZlcmVuY2VzLmJpYg0KbGluay1jaXRhdGlvbnM6IHRydWUNCmRhdGU6ICJMYXN0IGNvbXBpbGVkIG9uIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQtJW0tJVknKWAiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIGNzczogdHdlYWtzLmNzcw0KICAgIHRvYzogIHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCi0tLQ0KDQpgYGB7ciwgZ2xvYmFsc2V0dGluZ3MsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkodGlkeXZlcnNlKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0Kb3B0c19jaHVuayRzZXQodGlkeS5vcHRzPWxpc3Qod2lkdGguY3V0b2ZmPTEwMCksdGlkeT1UUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSxjb21tZW50ID0gIiM+IiwgY2FjaGU9VFJVRSwgY2xhc3Muc291cmNlPWMoInRlc3QiKSwgY2xhc3Mub3V0cHV0PWMoInRlc3QzIikpDQpvcHRpb25zKHdpZHRoID0gMTAwKQ0KcmdsOjpzZXR1cEtuaXRyKCkNCg0KY29sb3JpemUgPC0gZnVuY3Rpb24oeCwgY29sb3IpIHtzcHJpbnRmKCI8c3BhbiBzdHlsZT0nY29sb3I6ICVzOyc+JXM8L3NwYW4+IiwgY29sb3IsIHgpIH0NCmBgYA0KDQoNCmBgYHtyIGtsaXBweSwgZWNobz1GQUxTRSwgaW5jbHVkZT1UUlVFfQ0Ka2xpcHB5OjprbGlwcHkocG9zaXRpb24gPSBjKCd0b3AnLCAncmlnaHQnKSkNCiNrbGlwcHk6OmtsaXBweShjb2xvciA9ICdkYXJrcmVkJykNCiNrbGlwcHk6OmtsaXBweSh0b29sdGlwX21lc3NhZ2UgPSAnQ2xpY2sgdG8gY29weScsIHRvb2x0aXBfc3VjY2VzcyA9ICdEb25lJykNCmBgYA0KDQotLS0gIA0KDQoNCiMgR2V0dGluZyBzdGFydGVkDQoNCg0KVG8gY29weSB0aGUgY29kZSwgY2xpY2sgdGhlIGJ1dHRvbiBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyIG9mIHRoZSBjb2RlLWNodW5rcy4NCg0KDQojIyBjbGVhbiB1cA0KDQpgYGB7ciwgY2xlYW4sIHJlc3VsdHM9J2hpZGUnfQ0Kcm0obGlzdD1scygpKQ0KZ2MoKQ0KYGBgDQoNCjxicj4NCg0KIyMgZ2VuZXJhbCBjdXN0b20gZnVuY3Rpb25zDQoNCi0gYGZwYWNrYWdlLmNoZWNrYDogQ2hlY2sgaWYgcGFja2FnZXMgYXJlIGluc3RhbGxlZCAoYW5kIGluc3RhbGwgaWYgbm90KSBpbiBSDQotIGBmc2F2ZWA6IEZ1bmN0aW9uIHRvIHNhdmUgZGF0YSB3aXRoIHRpbWUgc3RhbXAgaW4gY29ycmVjdCBkaXJlY3RvcnkNCi0gYGZsb2FkYDogRnVuY3Rpb24gdG8gbG9hZCBSLW9iamVjdHMgdW5kZXIgbmV3IG5hbWVzDQotIGBmc2hvd2RmYDogUHJpbnQgb2JqZWN0cyAoYHRpYmJsZWAgLyBgZGF0YS5mcmFtZWApIG5pY2VseSBvbiBzY3JlZW4gaW4gYC5SbWRgDQotIGBmY3JlYXRlX2V4cG9zdXJlX21lYW5zYDogQ2FsY3VsYXRlIGlzb2xhdGlvbi9leHBvc3VyZSBpbmRpY2VzIGZvciB0aGUgbWFpbiBhbmFseXNpcyBhbmQgZm9yIHRoZSByb2J1c3RuZXNzIGNoZWNrDQotIGBmY3JlYXRlX2V4cG9zdXJlX21lYW5zX3JvYnVzdGANCi0gYGZjdXN0b21fbGVnZW5kYDogQ3JlYXRlIGEgY3VzdG9tIGxlZ2VuZA0KDQpgYGB7ciwgZnVufQ0KZnBhY2thZ2UuY2hlY2sgPC0gZnVuY3Rpb24ocGFja2FnZXMpIHsNCiAgICBsYXBwbHkocGFja2FnZXMsIEZVTiA9IGZ1bmN0aW9uKHgpIHsNCiAgICAgICAgaWYgKCFyZXF1aXJlKHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsNCiAgICAgICAgICAgIGluc3RhbGwucGFja2FnZXMoeCwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgICAgICAgICAgIGxpYnJhcnkoeCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQ0KICAgICAgICB9DQogICAgfSkNCn0NCg0KZnNhdmUgPC0gZnVuY3Rpb24oeCwgbG9jYXRpb24gPSAiLi9kYXRhL3Byb2Nlc3NlZC8iKSB7DQogIGlmIChsb2NhdGlvbiA9PSAiLi9kYXRhL3Byb2Nlc3NlZC8iKSB7DQogIGlmZWxzZSghZGlyLmV4aXN0cygiZGF0YSIpLCBkaXIuY3JlYXRlKCJkYXRhIiksIEZBTFNFKQ0KICBpZmVsc2UoIWRpci5leGlzdHMoImRhdGEvcHJvY2Vzc2VkIiksIGRpci5jcmVhdGUoImRhdGEvcHJvY2Vzc2VkIiksIEZBTFNFKQ0KICB9DQoNCiAgb2JqZWN0ID0gZGVwYXJzZShzdWJzdGl0dXRlKHgpKQ0KICBkYXRlbmFtZSA8LSBzdWJzdHIoZ3N1YigiWzotXSIsICIiLCBTeXMudGltZSgpKSwgMSwgOCkNCiAgdG90YWxuYW1lIDwtIHBhc3RlKGxvY2F0aW9uLCBvYmplY3QsICJfIiwgZGF0ZW5hbWUsICAiLnJkYSIsIHNlcCA9ICIiKQ0KICBhc3NpZ24oZXZhbChvYmplY3QpLCB4LCBlbnZpciA9IC5HbG9iYWxFbnYpDQogIHByaW50KHBhc3RlKCJTQVZFRDogIiwgdG90YWxuYW1lLCBzZXAgPSAiIikpDQogIHNhdmUobGlzdCA9IG9iamVjdCwgZmlsZSA9IHRvdGFsbmFtZSkgIA0KfQ0KDQpmbG9hZCAgPC0gZnVuY3Rpb24oZmlsZU5hbWUpew0KICBsb2FkKGZpbGVOYW1lKQ0KICBnZXQobHMoKVtscygpICE9ICJmaWxlTmFtZSJdKQ0KfQ0KDQpmc2hvd2RmIDwtIGZ1bmN0aW9uKHgsIGNhcHRpb24gPSBOVUxMLCBkaWdpdHMgPSAyLCBmb290bm90ZSA9IE5VTEwsIC4uLikgew0KICAgIGtuaXRyOjprYWJsZSh4LCBkaWdpdHMgPSBkaWdpdHMsICJodG1sIiwgY2FwdGlvbiA9IGNhcHRpb24sIC4uLikgJT4lDQogICAgICAgIGthYmxlRXh0cmE6OmZvb3Rub3RlKGdlbmVyYWwgPSBmb290bm90ZSkgJT4lDQogICAgICAgIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQ0KICAgICAgICBrYWJsZUV4dHJhOjpzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiLCBoZWlnaHQgPSAiMzAwcHgiKQ0KfQ0KDQpmY3JlYXRlX2V4cG9zdXJlX21lYW5zIDwtIGZ1bmN0aW9uKGRhdCwgZGltX3ZhciwgY29tcF92YXIsIGNvbnRfdmFyLCBnMSwgZzIsIHNldHRpbmcsIGRhdGFzb3VyY2Upew0KICBpaV9kaW1fbWVhbiA8LSBkYXQgJT4lDQogICAgZmlsdGVyKCFpcy5uYSh7e2NvbXBfdmFyfX0pICYgIWlzLm5hKHt7Y29udF92YXJ9fSkpICU+JSANCiAgICBzdW1tYXJpemUoaWlfY29tcF9tZWFuID0gbWVhbih7e2NvbXBfdmFyfX0pKjAuMDEsDQogICAgICAgICAgICAgIGlpX2NvbnRfbWVhbiA9IG1lYW4oe3tjb250X3Zhcn19KSowLjAxKQ0KICBpaV9kaW1fZzEgPC0gZGF0ICU+JQ0KICAgIGZpbHRlcighaXMubmEoe3tjb21wX3Zhcn19KSAmICFpcy5uYSh7e2NvbnRfdmFyfX0pICYge3tkaW1fdmFyfX0gPT0gZzEpICU+JQ0KICAgIHN1bW1hcml6ZShpaV9jb21wX2cxID0gbWVhbih7e2NvbXBfdmFyfX0pKjAuMDEsDQogICAgICAgICAgICAgIGlpX2NvbnRfZzEgPSBtZWFuKHt7Y29udF92YXJ9fSkqMC4wMSkNCiAgaWlfZGltX2cyIDwtIGRhdCAlPiUNCiAgICBmaWx0ZXIoIWlzLm5hKHt7Y29tcF92YXJ9fSkgJiAhaXMubmEoe3tjb250X3Zhcn19KSAmIHt7ZGltX3Zhcn19ID09IGcyKSAlPiUNCiAgICBzdW1tYXJpemUoaWlfY29tcF9nMiA9IG1lYW4oe3tjb21wX3Zhcn19KSowLjAxLA0KICAgICAgICAgICAgICBpaV9jb250X2cyID0gbWVhbih7e2NvbnRfdmFyfX0pKjAuMDEpDQogIGlpX3NldHRpbmcgPC0gcGFzdGUwKHNldHRpbmcpDQogIGlpX2RpbWVuc2lvbiA8LSBwYXN0ZTAoJ1NoYXJlICcsIGcxKQ0KICBpaV9kYXRhdHlwZSA8LSBwYXN0ZTAoZGF0YXNvdXJjZSkNCiAgaWkgPC0gY2JpbmQoaWlfZGltZW5zaW9uLCBpaV9zZXR0aW5nLCBpaV9kYXRhdHlwZSwgaWlfZGltX21lYW4sIGlpX2RpbV9nMSwgaWlfZGltX2cyKQ0KfQ0KDQpmY3JlYXRlX2V4cG9zdXJlX21lYW5zX3JvYnVzdCA8LSBmdW5jdGlvbihkYXQsIGRpbV92YXIsIGNvbXBfdmFyLCBjb21wX2J1dXJ0LCBjb250X3ZhciwgZzEsIGcyLCBzZXR0aW5nKXsNCiAgaWlfZGltX21lYW4gPC0gZGF0ICU+JQ0KICAgIGZpbHRlcighaXMubmEoe3tjb21wX3Zhcn19KSAmICFpcy5uYSh7e2NvbnRfdmFyfX0pICYgIWlzLm5hKHt7Y29tcF9idXVydH19KSkgJT4lIA0KICAgIHN1bW1hcml6ZShpaV9jb21wX21lYW4gPSBtZWFuKHt7Y29tcF92YXJ9fSkqMC4wMSwNCiAgICAgICAgICAgICAgaWlfY29tcGJ1dXJ0X21lYW4gPSBtZWFuKHt7Y29tcF9idXVydH19KSowLjAxKQ0KICBpaV9kaW1fZzEgPC0gZGF0ICU+JQ0KICAgIGZpbHRlcighaXMubmEoe3tjb21wX3Zhcn19KSAmICFpcy5uYSh7e2NvbnRfdmFyfX0pICYgIWlzLm5hKHt7Y29tcF9idXVydH19KSAmIHt7ZGltX3Zhcn19ID09IGcxKSAlPiUNCiAgICBzdW1tYXJpemUoaWlfY29tcF9nMSA9IG1lYW4oe3tjb21wX3Zhcn19KSowLjAxLA0KICAgICAgICAgICAgICBpaV9jb21wYnV1cnRfZzEgPSBtZWFuKHt7Y29tcF9idXVydH19KSowLjAxKQ0KICBpaV9kaW1fZzIgPC0gZGF0ICU+JQ0KICAgIGZpbHRlcighaXMubmEoe3tjb21wX3Zhcn19KSAmICFpcy5uYSh7e2NvbnRfdmFyfX0pICYgIWlzLm5hKHt7Y29tcF9idXVydH19KSAmIHt7ZGltX3Zhcn19ID09IGcyKSAlPiUNCiAgICBzdW1tYXJpemUoaWlfY29tcF9nMiA9IG1lYW4oe3tjb21wX3Zhcn19KSowLjAxLA0KICAgICAgICAgICAgICBpaV9jb21wYnV1cnRfZzIgPSBtZWFuKHt7Y29tcF9idXVydH19KSowLjAxKQ0KICBpaV9zZXR0aW5nIDwtIHBhc3RlMChzZXR0aW5nKQ0KICBpaV9kaW1lbnNpb24gPC0gcGFzdGUwKCdTaGFyZSAnLCBnMSkNCiAgaWkgPC0gY2JpbmQoaWlfZGltZW5zaW9uLCBpaV9zZXR0aW5nLCBpaV9kaW1fbWVhbiwgaWlfZGltX2cxLCBpaV9kaW1fZzIpDQp9DQoNCmZjdXN0b21fbGVnZW5kIDwtIGZ1bmN0aW9uKHRleHRfZW50cnkxLCB0ZXh0X2VudHJ5Mikgew0KICBsZWdlbmQgPC0gZ3JvYlRyZWUoDQogICAgcG9pbnRzR3JvYih4ID0gdW5pdChjKDAuMDIsIDAuMDcpLCAibnBjIiksIHkgPSB1bml0KGMoMC44LCAwLjgpLCAibnBjIiksIHBjaCA9IGMoMjIsIDE5KSwgZ3AgPSBncGFyKGNvbCA9ICIjNTZCNEU5IiwgZmlsbCA9ICIjNTZCNEU5IikpLA0KICAgIHRleHRHcm9iKHRleHRfZW50cnkxLCB4ID0gdW5pdCgwLjExLCAibnBjIiksIHkgPSB1bml0KDAuOCwgIm5wYyIpLCBqdXN0ID0gImxlZnQiLCBncCA9IGdwYXIoZm9udHNpemUgPSAxMSkpLA0KICAgIHBvaW50c0dyb2IoeCA9IHVuaXQoMC4wMiwgIm5wYyIpLCB5ID0gdW5pdCgwLjUsICJucGMiKSwgcGNoID0gMjIsIGdwID0gZ3Bhcihjb2wgPSAiIzk5OTk5OSIsIGZpbGwgPSAiIzk5OTk5OSIpKSwNCiAgICB0ZXh0R3JvYigiQXZlcmFnZSBpbnRyYS1zZXR0aW5nIGV4cG9zdXJlIGFtb25nXG5hbGwgcmVzcG9uZGVudHMiLCB4ID0gdW5pdCgwLjExLCAibnBjIiksIHkgPSB1bml0KDAuNSwgIm5wYyIpLCBqdXN0ID0gImxlZnQiLCBncCA9IGdwYXIoZm9udHNpemUgPSAxMSkpLA0KICAgIHBvaW50c0dyb2IoeCA9IHVuaXQoYygwLjAyLCAwLjA3KSwgIm5wYyIpLCB5ID0gdW5pdChjKDAuMiwgMC4yKSwgIm5wYyIpLCBwY2ggPSBjKDIyLCAxOSksIGdwID0gZ3Bhcihjb2wgPSAiI0U2OUYwMCIsIGZpbGwgPSAiI0U2OUYwMCIpKSwNCiAgICB0ZXh0R3JvYih0ZXh0X2VudHJ5MiwgeCA9IHVuaXQoMC4xMSwgIm5wYyIpLCB5ID0gdW5pdCgwLjIsICJucGMiKSwganVzdCA9ICJsZWZ0IiwgZ3AgPSBncGFyKGZvbnRzaXplID0gMTEpKSkNCiAgcmV0dXJuKGxlZ2VuZCkNCn0NCmBgYA0KDQo8YnI+DQoNCiMjIG5lY2Vzc2FyeSBwYWNrYWdlcw0KDQotIGB0aWR5dmVyc2VgOiBkYXRhIHdyYW5nbGluZw0KLSBgY3JlZ2dgOiBjYWxjdWxhdGUgbWFyZ2luYWwgbWVhbnMgYW5kIGF2ZXJhZ2UgbWFyZ2luYWwgY29tcG9uZW50IGVmZmVjdHMNCi0gYGdncGxvdDJgLCBgZ2d0ZXh0YCwgYGNvd3Bsb3RgLCBgcGF0Y2h3b3JrYCwgYGdncHVicmAsIGBnZ2g0eGAsIGBncmlkdGV4dGAsIGBncmlkYDogZGF0YSB2aXN1YWxpemF0aW9uIA0KDQoNCmBgYHtyLCBwYWNrYWdlcywgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQpwYWNrYWdlcyA9IGMoInRpZHl2ZXJzZSIsICJjcmVnZyIsICJnZ3Bsb3QyIiwgImdndGV4dCIsICJjb3dwbG90IiwgInBhdGNod29yayIsICJnZ3B1YnIiLCAiZ2doNHgiLCAiZ3JpZHRleHQiLCAiZ3JpZCIpDQpmcGFja2FnZS5jaGVjayhwYWNrYWdlcykNCnJtKHBhY2thZ2VzKQ0KYGBgDQoNCg0KPGJyPg0KDQotLS0NCg0KIyBJbXBvcnQNCg0KSW1wb3J0IGRhdGEtc2V0cywgY3JlYXRlZCBmb3IgdGhlIFtMSVNTXShwcmVwX2xpc3MuaHRtbCkgYW5kIFtUUklBTF0ocHJlcF90cmlhbC5odG1sKSBjaG9pY2UgZXhwZXJpbWVudHMuDQoNCllvdSBtYXkgb2J0YWluIGl0IGJ5IGRvd25sb2FkaW5nOiANCg0KLSBgciB4ZnVuOjplbWJlZF9maWxlKCIuL2RhdGFfc2hhcmVkL2NvbmpvaW50X2xpc3MuUmRhIilgDQotIGByIHhmdW46OmVtYmVkX2ZpbGUoIi4vZGF0YV9zaGFyZWQvY29uam9pbnRfdHJpYWwuUmRhIilgDQoNCmBgYHtyLCBkYXRhfQ0KI2xpc3QuZmlsZXMoIi4vZGF0YS9wcm9jZXNzZWQiKQ0KdG9kYXkgPC0gZ3N1YigiLSIsICIiLCBTeXMuRGF0ZSgpKQ0KdG9kYXkgPC0gIjIwMjUwNTMwIiAjbGF0ZXN0IHVwZGF0ZWQgZGF0YXNldA0KDQpmbG9hZChwYXN0ZTAoIi4vZGF0YS9wcm9jZXNzZWQvIiwgdG9kYXksICJjb25qb2ludF9saXNzLlJkYSIpKSAlPiUNCiAgc2psYWJlbGxlZDo6dW5sYWJlbCguKSAtPiBkZg0KDQpmbG9hZChwYXN0ZTAoIi4vZGF0YS9wcm9jZXNzZWQvIiwgdG9kYXksICJjb25qb2ludF90cmlhbC5SZGEiKSkgJT4lDQogIHNqbGFiZWxsZWQ6OnVubGFiZWwoLikgLT4gZGYyDQpgYGANCg0KPGJyPg0KDQotLS0NCg0KIyBEZXNjcmlwdGl2ZXMgey50YWJzZXQgLnRhYnNldC1mYWRlfQ0KDQojIyBFeHBlcmltZW50cyAxIGFuZCAyDQoNCmBgYHtyLCBkZXMxLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30NCiMgZmlyc3QgZ2V0IHRoZSByZXNwb25kZW50cyB3aG8gd2VyZSBpbnZvbHZlZCBpbiB0aGUgY2hvaWNlIHRhc2tzDQojIGV4cGVyaW1lbnQgMSAobmJoKQ0KdGVzdCA8LSBkZlssIGMoImlkIiwgImVuYmhfY2hvc2VuIiwgImVuYmhfc2V0IildICNzdWJzZXQgaWQsIHNldCBhbmQgY2hvaWNlDQp0ZXN0JGlkX3NldCA8LSBwYXN0ZTAodGVzdCRpZCwgIngiLCB0ZXN0JGVuYmhfc2V0KSAjY29tYmluZSBpZCBhbmQgc2V0DQp0ZXN0IDwtIHRlc3RbIWlzLm5hKHRlc3QkZW5iaF9jaG9zZW4pLF0gI3JlbW92ZSBjaG9pY2UgdGFza3Mgbm90IGZ1bGZpbGxlZA0KaWRzMSA8LSB1bmlxdWUodGVzdCRpZCkgIyBnZXQgaWRzIG9mIHJlc3BvbmRlbnRzIGluIGV4cGVyaW1lbnQgMQ0KI2xlbmd0aChpZHMxKSAjIE49MjczMw0KDQojIGV4cGVyaW1lbnQgMiAob3JncykNCnRlc3QgPC0gZGZbLCBjKCJpZCIsICJlY2l2X2Nob3NlbiIsICJlY2l2X3NldCIpXSAjc3Vic2V0IGlkLCBzZXQgYW5kIGNob2ljZQ0KdGVzdCRpZF9zZXQgPC0gcGFzdGUwKHRlc3QkaWQsICJ4IiwgdGVzdCRlY2l2X3NldCkgI2NvbWJpbmUgaWQgYW5kIHNldA0KdGVzdCA8LSB0ZXN0WyFpcy5uYSh0ZXN0JGVjaXZfY2hvc2VuKSxdICNyZW1vdmUgY2hvaWNlIHRhc2tzIG5vdCBmdWxmaWxsZWQNCmlkczIgPC0gdW5pcXVlKHRlc3QkaWQpICMgZ2V0IGlkcyBvZiByZXNwb25kZW50cyBpbiBleHBlcmltZW50IDINCiNsZW5ndGgoaWRzMikgIyBOPTI3NDMNCg0KaWRzIDwtIHVuaXF1ZShjKGlkczEsIGlkczIpKQ0KI2xlbmd0aChpZHMpICNOX3RvdGFsID0gMjc1MC4NCg0KIyBzdWJzZXQNCmRmICU+JQ0KICBzZWxlY3QoaWQsIHNleCwgZWR1LCBhZ2UsIGV0aF9kdG0sIG9jaXZfbW9zdGltcF90eXBlKSAlPiUNCiAgZmlsdGVyKGlkICVpbiUgaWRzKSAlPiUNCiAgbXV0YXRlKA0KICAgICMgZXRobmljaXR5IGR1bW1pZXMNCiAgICB0bSA9IGlmZWxzZShldGhfZHRtID09ICJUdXJraXNoL01vcm9jY2FuIiwgMSwgMCksDQogICAgZHV0Y2ggPSBpZmVsc2UoZXRoX2R0bSA9PSAiRHV0Y2giLCAxLCAwKSwNCiAgICBlX290aGVyID0gaWZlbHNlKGlzLm5hKGV0aF9kdG0pLCAxLCAwKSwNCg0KICAgICMgZ2VuZGVyIGR1bW1pZXMNCiAgICBtYWxlID0gaWZlbHNlKHNleCA9PSAibWFsZSIsIDEsIDApLA0KICAgIGZlbWFsZSA9IGlmZWxzZShzZXggPT0gImZlbWFsZSIsIDEsIDApLA0KICAgIGdfb3RoZXIgPSBpZmVsc2UoaXMubmEoc2V4KSwgMSwgMCksDQoNCiAgICAjIGVkdWNhdGlvbiBkdW1taWVzDQogICAgY29sbGVnZSA9IGlmZWxzZShlZHUgPT0gImNvbGxlZ2UgZGVncmVlIiwgMSwgMCksDQogICAgbm9fY29sbGVnZSA9IGlmZWxzZSghaXMubmEoZWR1KSAmIGVkdSAhPSAiY29sbGVnZSBkZWdyZWUiLCAxLCAwKSwNCiAgICBlZHVjX21pc3NpbmcgPSBpZmVsc2UoaXMubmEoZWR1KSwgMSwgMCksDQoNCiAgICAjIGFnZSBkdW1taWVzDQogICAgYWdlNTBwbHVzID0gaWZlbHNlKGFnZSA9PSAiNTAgb3Igb2xkZXIiLCAxLCAwKSwNCiAgICBhZ2ViZWxvdzUwID0gaWZlbHNlKGFnZSA9PSAidW5kZXIgNTAiLCAxLCAwKSwNCg0KICAgICMgb3JnYW5pemF0aW9uIHR5cGUgZHVtbWllcw0KICAgIHJlbGlnaW91cyA9IGlmZWxzZShvY2l2X21vc3RpbXBfdHlwZSA9PSAiUmVsaWdpb3VzIiwgMSwgMCksDQogICAgdW5pb24gPSBpZmVsc2Uob2Npdl9tb3N0aW1wX3R5cGUgPT0gIlVuaW9uIiwgMSwgMCksDQogICAgc3BvcnRzID0gaWZlbHNlKG9jaXZfbW9zdGltcF90eXBlID09ICJTcG9ydHMiLCAxLCAwKSwNCiAgICBlbnZpcm9ubWVudGFsID0gaWZlbHNlKG9jaXZfbW9zdGltcF90eXBlID09ICJFbnZpcm9ubWVudGFsIiwgMSwgMCksDQogICAgY29uc3VtZXIgPSBpZmVsc2Uob2Npdl9tb3N0aW1wX3R5cGUgPT0gIkNvbnN1bWVyIiwgMSwgMCksDQogICAgY3VsdHVyYWwgPSBpZmVsc2Uob2Npdl9tb3N0aW1wX3R5cGUgPT0gIkN1bHR1cmFsIiwgMSwgMCksDQogICAgcHJvZmVzc2lvbmFsID0gaWZlbHNlKG9jaXZfbW9zdGltcF90eXBlID09ICJQcm9mZXNzaW9uYWwiLCAxLCAwKSwNCiAgICBzb2NpYWwgPSBpZmVsc2Uob2Npdl9tb3N0aW1wX3R5cGUgPT0gIlNvY2lhbCIsIDEsIDApLA0KICAgIHBvbGl0aWNhbCA9IGlmZWxzZShvY2l2X21vc3RpbXBfdHlwZSA9PSAiUG9saXRpY2FsIiwgMSwgMCksDQogICAgaHVtYW5pdGFyaWFuID0gaWZlbHNlKG9jaXZfbW9zdGltcF90eXBlID09ICJIdW1hbml0YXJpYW4iLCAxLCAwKSwNCiAgICBlZHVjYXRpb25hbCA9IGlmZWxzZShvY2l2X21vc3RpbXBfdHlwZSA9PSAiRWR1Y2F0aW9uYWwiLCAxLCAwKSwNCiAgICBtaWdyYW50cyA9IGlmZWxzZShvY2l2X21vc3RpbXBfdHlwZSA9PSAiTWlncmFudHMiLCAxLCAwKSwNCiAgICBvdGhlcl9vcmcgPSBpZmVsc2Uob2Npdl9tb3N0aW1wX3R5cGUgPT0gIk90aGVyIiwgMSwgMCksDQogICAgb3JnX21pc3NpbmcgPSBpZmVsc2UoaXMubmEob2Npdl9tb3N0aW1wX3R5cGUpLCAxLCAwKQ0KICApICU+JQ0KICAjIHJlcGxhY2UgTkFzIGluIGR1bW15IHZhcmlhYmxlcw0KICBtdXRhdGUoYWNyb3NzKA0KICAgIGModG0sIGR1dGNoLCBlX290aGVyLCBtYWxlLCBmZW1hbGUsIGdfb3RoZXIsIGNvbGxlZ2UsIG5vX2NvbGxlZ2UsDQogICAgICBlZHVjX21pc3NpbmcsDQogICAgICBhZ2U1MHBsdXMsIGFnZWJlbG93NTAsIGVkdWNfbWlzc2luZywNCiAgICAgIHJlbGlnaW91cywgb3RoZXJfb3JnLCB1bmlvbiwgc3BvcnRzLCBlbnZpcm9ubWVudGFsLCBjb25zdW1lciwNCiAgICAgIGN1bHR1cmFsLCBwcm9mZXNzaW9uYWwsIHNvY2lhbCwgcG9saXRpY2FsLCBodW1hbml0YXJpYW4sDQogICAgICBlZHVjYXRpb25hbCwgbWlncmFudHMsIG9yZ19taXNzaW5nKSwNCiAgICB+cmVwbGFjZV9uYSguLCAwKQ0KICApKSAlPiUNCiAgZGlzdGluY3QoaWQsIC5rZWVwX2FsbCA9IFRSVUUpICU+JQ0KICBzZWxlY3QoLWMoaWQsIHNleCwgZWR1LCBhZ2UsIGV0aF9kdG0sIG9jaXZfbW9zdGltcF90eXBlKSkgLT4gdGVzdA0KDQp0ZXN0ICU+JQ0KICBwc3ljaDo6ZGVzY3JpYmUoKSAlPiUNCiAgLlssIGMoMiwgMywgNCwgOCwgOSldICU+JQ0KICBgcm93bmFtZXM8LWAoYygNCiAgICAiVHVya2lzaCBvciBNb3JvY2NhbiBtaWdyYXRpb24gYmFja2dyb3VuZCIsICJEdXRjaCBiYWNrZ3JvdW5kIiwgIk90aGVyIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiwgDQogICAgIk1hbGUiLCAiRmVtYWxlIiwgIk90aGVyIC8gbWlzc2luZyBnZW5kZXIiLA0KICAgICJDb2xsZWdlIGRlZ3JlZSIsICJObyBjb2xsZWdlIGRlZ3JlZSIsICJFZHVjYXRpb24gbWlzc2luZyIsDQogICAgIkFnZWQgNTArIiwgIkFnZWQgdW5kZXIgNTAiLA0KICAgICJSZWxpZ2lvdXMgb3JnIiwgIlVuaW9uIiwgIlNwb3J0cyIsICJFbnZpcm9ubWVudGFsIiwNCiAgICAiQ29uc3VtZXIiLCAiQ3VsdHVyYWwiLCAiUHJvZmVzc2lvbmFsIiwgIlNvY2lhbCIsICJQb2xpdGljYWwiLA0KICAgICJIdW1hbml0YXJpYW4iLCAiRWR1Y2F0aW9uYWwiLCAiTWlncmFudHMiLCAiT3RoZXIgdHlwZSIsICJNaXNzaW5nIg0KICApKSAtPiBkZXMxDQoNCmRlczEgJT4lDQogIGZzaG93ZGYoY2FwdGlvbiA9ICJTdW1tYXJ5IG9mIGJhY2tncm91bmQgYW5kIG9yZ2FuaXphdGlvbiB0eXBlIHZhcmlhYmxlcyIpIA0KDQojc3RyKGRlczEpDQojd3JpdGUuY3N2KGRlczEsICJkZXNjcmlwdGl2ZXNfbGlzcy5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQ0KYGBgDQoNCiMjIEV4cGVyaW1lbnQgMw0KDQpgYGB7ciwgZGVzMiwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZSd9DQpkZjIgJT4lDQogIHNlbGVjdChpZCwgR0VTTEFDSFQyLCBMRUVGVElKRCwgdGVydF9lZHVjLCBtaWdyYXRpb24pICU+JQ0KICBtdXRhdGUoDQogICAgbWFsZSA9IGlmZWxzZShHRVNMQUNIVDIgPT0gMSwgMSwgMCksDQogICAgZmVtYWxlID0gaWZlbHNlKEdFU0xBQ0hUMiA9PSAyLCAxLCAwKSwNCiAgICBnX290aGVyID0gaWZlbHNlKEdFU0xBQ0hUMiA9PSAzIHwgaXMubmEoR0VTTEFDSFQyKSwgMSwgMCksDQogICAgZHV0Y2ggPSBpZmVsc2UobWlncmF0aW9uID09IDAsIDEsIDApLA0KICAgIG5vbl9kdXRjaCA9IGlmZWxzZShtaWdyYXRpb24gPT0gMSwgMSwgMCksDQogICAgbm9fdGVydF9lZHVjID0gaWZlbHNlKHRlcnRfZWR1YyA9PSAwLCAxLCAwKQ0KICApICU+JQ0KICBtdXRhdGUoYWNyb3NzKA0KICAgIGMobWFsZSxmZW1hbGUpLA0KICAgIH5yZXBsYWNlX25hKC4sIDApKSkgJT4lDQogIGRpc3RpbmN0KGlkLCAua2VlcF9hbGwgPSBUUlVFKSAlPiUNCiAgc2VsZWN0KG1hbGUsIGZlbWFsZSwgZ19vdGhlciwgTEVFRlRJSkQsIHRlcnRfZWR1Yywgbm9fdGVydF9lZHVjLCBkdXRjaCwgbm9uX2R1dGNoKSAlPiUNCiAgcHN5Y2g6OmRlc2NyaWJlKCkgJT4lDQogIC5bLCBjKDIsIDMsIDQsIDgsIDkpXSAlPiUNCiAgYHJvd25hbWVzPC1gKGMoDQogICAgIk1hbGUiLCAiRmVtYWxlIiwgIk90aGVyIC8gbWlzc2luZyBnZW5kZXIiLA0KICAgICJBZ2UiLCAiQ29sbGVnZSBkZWdyZWUiLCAiTm8gY29sbGVnZSBkZWdyZWUiLA0KICAgICJEdXRjaCBiYWNrZ3JvdW5kIiwgIk1pZ3JhdGlvbiBiYWNrZ3JvdW5kIg0KICApKSAtPiBkZXMyICANCg0KZGVzMiAlPiUNCiAgZnNob3dkZihjYXB0aW9uID0gIlN1bW1hcnkgb2YgYmFja2dyb3VuZCB2YXJpYWJsZXMiKQ0KDQojc3RyKGRlczIpDQojd3JpdGUuY3N2KGRlczIsICJkZXNjcmlwdGl2ZXNfdHJpYWwuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkNCmBgYA0KDQojIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9DQoNCjxicj4NCg0KLS0tDQoNCjwhLS0tLQ0KDQojIE9ic2VydmVkIG9yZ2FuaXphdGlvbnMNCg0KYGBge3IsIGRlc2NyaWJlfQ0KIyB0eXBlcyBvZiBvcmdhbml6YXRpb25zIC8gcHJvcG9ydGlvbg0KcF9vcmdzIDwtIGFzLmRhdGEuZnJhbWUocHJvcC50YWJsZSh0YWJsZShkZiRvY2l2X21vc3RpbXBfdHlwZSkpKQ0KY29sbmFtZXMocF9vcmdzKSA8LSBjKCJUeXBlIiwgIlByb3BvcnRpb24iKQ0KDQojc29ydA0KcF9vcmdzIDwtIHBfb3Jnc1tvcmRlcigtcF9vcmdzJFByb3BvcnRpb24pLF0NCnJvd25hbWVzKHBfb3JncykgPC0gMTpucm93KHBfb3JncykNCmZzaG93ZGYocF9vcmdzLCBjYXB0aW9uID0gIlByb3BvcnRpb25zIG9mIG1vc3QgaW1wb3J0YW50IG9yZ2FuaXphdGlvbiB0eXBlLCBpbiBkZXNjZW5kaW5nIG9yZGVyIikNCg0KZ2dwbG90KHN1YnNldChkZiwgIWlzLm5hKG9jaXZfbW9zdGltcF90eXBlKSksIGFlcyh4ID0gb2Npdl9tb3N0aW1wX3R5cGUpKSArDQogIGdlb21fYmFyKCkgKw0KICBjb29yZF9mbGlwKCkNCmBgYCANCg0KLS0tPg0KDQojIE9ic2VydmVkIHNlZ3JlZ2F0aW9uIGluIG5laWdoYm9yaG9vZHMgYW5kIGNpdmljIG9yZ2FuaXphdGlvbnMNCg0KYGBge3IsIGZpZ3VyZV8xLCBldmFsPUZBTFNFfSANCmRmIDwtIGRmICU+JQ0KICBtdXRhdGUoZWR1X2YgPSBmYWN0b3IoZWR1LCBsZXZlbHMgPSBjKCJubyBjb2xsZWdlIGRlZ3JlZSIsICJjb2xsZWdlIGRlZ3JlZSIpKSwNCiAgICAgICAgIHNleF9mID0gZmFjdG9yKHNleCwgbGV2ZWxzID0gYygibWFsZSIsICJmZW1hbGUiKSksDQogICAgICAgICBhZ2VfZiA9IGZhY3RvcihhZ2UsIGxldmVscyA9IGMoInVuZGVyIDUwIiwgIjUwIG9yIG9sZGVyIikpLA0KICAgICAgICAgZXRoX2R0bV9mID0gZmFjdG9yKGV0aF9kdG0sIGxldmVscyA9IGMoIkR1dGNoIiwgIlR1cmtpc2gvTW9yb2NjYW4iKSkpDQoNCiMgSXNvbGF0aW9uIGFuZCBFeHBvc3VyZSBpbmRpY2VzIGZvciBkaWZmZXJlbnQgZGltZW5zaW9ucyBhY3Jvc3MgZGlmZmVyZW50IHNldHRpbmdzICMjIyMNCiNDYWxjdWxhdGUgSXNvbGF0aW9uIGFuZCBFeHBvc3VyZSBpbmRpY2VzIGZvciBhbGwgb3JnIHR5cGVzIHBvb2xlZDoNCmVpX2FnZV9uYmggPC0gZmNyZWF0ZV9leHBvc3VyZV9tZWFucyhkYXQgPSBkZiwgZGltX3ZhciA9IGFnZSwgZzEgPSAnNTAgb3Igb2xkZXInLCBnMiA9ICd1bmRlciA1MCcsIGNvbXBfdmFyID0gb25iaF9jb21wX2FnZSwgY29udF92YXIgPSBvbmJoX2NvbnRfYWdlLCBzZXR0aW5nID0gJ25laWdoYm9yaG9vZHMnLCBkYXRhc291cmNlID0gJ3N1YmplY3RpdmUnKQ0KZWlfYWdlX2NpdiA8LSBmY3JlYXRlX2V4cG9zdXJlX21lYW5zKGRhdCA9IGRmLCBkaW1fdmFyID0gYWdlLCBnMSA9ICc1MCBvciBvbGRlcicsIGcyID0gJ3VuZGVyIDUwJywgY29tcF92YXIgPSBvY2l2X2NvbXBfYWdlLCBjb250X3ZhciA9IG9jaXZfY29udF9hZ2UsIHNldHRpbmcgPSAnY2l2aWMgb3JnYW5pemF0aW9ucycsIGRhdGFzb3VyY2UgPSAnc3ViamVjdGl2ZScpDQplaV9lZHVfbmJoIDwtIGZjcmVhdGVfZXhwb3N1cmVfbWVhbnMoZGF0ID0gZGYsIGRpbV92YXIgPSBlZHUsIGcxID0gJ2NvbGxlZ2UgZGVncmVlJywgZzIgPSAnbm8gY29sbGVnZSBkZWdyZWUnLCBjb21wX3ZhciA9IG9uYmhfY29tcF9lZHUsIGNvbnRfdmFyID0gb25iaF9jb250X2VkdSwgc2V0dGluZyA9ICduZWlnaGJvcmhvb2RzJywgZGF0YXNvdXJjZSA9ICdzdWJqZWN0aXZlJykNCmVpX2VkdV9jaXYgPC0gZmNyZWF0ZV9leHBvc3VyZV9tZWFucyhkYXQgPSBkZiwgZGltX3ZhciA9IGVkdSwgZzEgPSAnY29sbGVnZSBkZWdyZWUnLCBnMiA9ICdubyBjb2xsZWdlIGRlZ3JlZScsIGNvbXBfdmFyID0gb2Npdl9jb21wX2VkdSwgY29udF92YXIgPSBvY2l2X2NvbnRfZWR1LCBzZXR0aW5nID0gJ2NpdmljIG9yZ2FuaXphdGlvbnMnLCBkYXRhc291cmNlID0gJ3N1YmplY3RpdmUnKQ0KZWlfZXRoX25iaCA8LSBmY3JlYXRlX2V4cG9zdXJlX21lYW5zKGRhdCA9IGRmLCBkaW1fdmFyID0gZXRoX2R0bSwgZzEgPSAnVHVya2lzaC9Nb3JvY2NhbicsIGcyID0gJ0R1dGNoJywgY29tcF92YXIgPSBvbmJoX2NvbXBfZXRoLCBjb250X3ZhciA9IG9uYmhfY29udF9ldGgsIHNldHRpbmcgPSAnbmVpZ2hib3Job29kcycsIGRhdGFzb3VyY2UgPSAnc3ViamVjdGl2ZScpDQplaV9ldGhfY2l2IDwtIGZjcmVhdGVfZXhwb3N1cmVfbWVhbnMoZGF0ID0gZGYsIGRpbV92YXIgPSBldGhfZHRtLCBnMSA9ICdUdXJraXNoL01vcm9jY2FuJywgZzIgPSAnRHV0Y2gnLCBjb21wX3ZhciA9IG9jaXZfY29tcF9ldGgsIGNvbnRfdmFyID0gb2Npdl9jb250X2V0aCwgc2V0dGluZyA9ICdjaXZpYyBvcmdhbml6YXRpb25zJywgZGF0YXNvdXJjZSA9ICdzdWJqZWN0aXZlJykNCg0KZWkgPC0gcmJpbmQoZWlfYWdlX25iaCwgZWlfYWdlX2NpdiwgZWlfZWR1X25iaCwgZWlfZWR1X2NpdiwgZWlfZXRoX25iaCwgZWlfZXRoX2NpdikgJT4lIA0KICBtdXRhdGUoaWlfc2V0dGluZyA9IGZhY3RvcihpaV9zZXR0aW5nLCBsZXZlbHMgPSBjKCduZWlnaGJvcmhvb2RzJywgJ2NpdmljIG9yZ2FuaXphdGlvbnMnKSkpDQoNCiMgT2JzZXJ2YXRpb25hbCBEYXRhIC0gRmlndXJlcyAjIyMjDQojIyBuZWVkZWQgZm9yIGFsbCBvYnNlcnZhdGlvbmFsIGZpZ3VyZXMgLS0tLQ0KZGF0YSA8LSBkYXRhLmZyYW1lKHggPSBjKDEsIDIsIDMpLCB5ID0gYygxLCAyLCAzKSkgIyBDcmVhdGUgZHVtbXkgZGF0YQ0KDQpsZWdlbmRfZ3JvYl9lZHUgPC0gZmN1c3RvbV9sZWdlbmQoDQogIHRleHRfZW50cnkxID0gJ0ludHJhLXNldHRpbmcgZXhwb3N1cmUgLyBjb250YWN0cyBhbW9uZ1xudGhvc2Ugd2l0aCBhIGNvbGxlZ2UgZGVncmVlJywgDQogIHRleHRfZW50cnkyID0gJ0ludHJhLXNldHRpbmcgZXhwb3N1cmUgLyBjb250YWN0cyBhbW9uZ1xudGhvc2Ugd2l0aG91dCBhIGNvbGxlZ2UgZGVncmVlJykNCmxlZ2VuZF9ncm9iX2V0aCA8LSBmY3VzdG9tX2xlZ2VuZCgNCiAgdGV4dF9lbnRyeTEgPSAnSW50cmEtc2V0dGluZyBleHBvc3VyZSAvIGNvbnRhY3RzIGFtb25nXG50aG9zZSB3aXRoIGEgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kJywgIA0KICB0ZXh0X2VudHJ5MiA9ICdJbnRyYS1zZXR0aW5nIGV4cG9zdXJlIC8gY29udGFjdHMgYW1vbmdcbnRob3NlIHdpdGggbm8gbWlncmF0aW9uIGJhY2tncm91bmQnKQ0KbGVnZW5kX2dyb2JfYWdlIDwtIGZjdXN0b21fbGVnZW5kKA0KICB0ZXh0X2VudHJ5MSA9ICdJbnRyYS1zZXR0aW5nIGV4cG9zdXJlIC8gY29udGFjdHMgYW1vbmdcbnRob3NlIDUwIHllYXJzIG9yIG9sZGVyJywgDQogIHRleHRfZW50cnkyID0gJ0ludHJhLXNldHRpbmcgZXhwb3N1cmUgLyBjb250YWN0cyBhbW9uZ1xudGhvc2UgYmVsb3cgNTAgeWVhcnMnKQ0KDQojIENyZWF0ZSBhIGJsYW5rIHBsb3QgdG8gaG9sZCB0aGUgbGVnZW5kDQpsZWdlbmRfcGxvdF9lZHUgPC0gZ2dwbG90KCkgKyBhbm5vdGF0aW9uX2N1c3RvbShsZWdlbmRfZ3JvYl9lZHUpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCwgImNtIikpDQpsZWdlbmRfcGxvdF9ldGggPC0gZ2dwbG90KCkgKyBhbm5vdGF0aW9uX2N1c3RvbShsZWdlbmRfZ3JvYl9ldGgpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCwgImNtIikpDQpsZWdlbmRfcGxvdF9hZ2UgPC0gZ2dwbG90KCkgKyBhbm5vdGF0aW9uX2N1c3RvbShsZWdlbmRfZ3JvYl9hZ2UpICsgdGhlbWVfdm9pZCgpICsgdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4oMCwgMCwgMCwgMCwgImNtIikpDQoNCiNhcnJhbmdlbWVudCBvZiBmaWd1cmUgcGFuZWxzDQpmaWcxZGVzaWduIDwtICJBQkMNCiAgICAgICAgICAgICAgIEFCQw0KICAgICAgICAgICAgICAgQUJDDQogICAgICAgICAgICAgICBERUYiDQoNCiMjIEZpZ3VyZSAxIC0gTWFpbiB0ZXh0IC0tLS0NCmZpZzFfdjRfYWdlIDwtIGdncGxvdChlaVtlaSRpaV9kaW1lbnNpb249PSJTaGFyZSA1MCBvciBvbGRlciIsXSkgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHk9aWlfY29udF9nMiwgeWVuZD1paV9jb250X2cxLCB4PWlpX3NldHRpbmcsIHhlbmQ9aWlfc2V0dGluZyksIGNvbG9yPSJncmV5IikgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHk9aWlfY29udF9nMiwgeWVuZD1paV9jb21wX2cxLCB4PWlpX3NldHRpbmcsIHhlbmQ9aWlfc2V0dGluZyksIGNvbG9yPSJncmV5IikgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbXBfbWVhbiwgeD1paV9zZXR0aW5nKSwgY29sb3I9IiM5OTk5OTkiLCBzaGFwZSA9ICdzcXVhcmUnLCBzaXplPTMpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb21wX2cxLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iIzU2QjRFOSIsIHNoYXBlID0gJ3NxdWFyZScsIHNpemU9MykgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbXBfZzIsIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjRTY5RjAwIiwgc2hhcGUgPSAnc3F1YXJlJywgc2l6ZT0zKSArDQogICNnZW9tX3BvaW50KGFlcyh4PWlpX3NldHRpbmcsIHk9aWlfY29udF9tZWFuKSwgY29sb3I9J3JlZCcsIHNoYXBlID0gJ2NpcmNsZScsIHNpemU9NCkgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbnRfZzEsIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjNTZCNEU5Iiwgc2hhcGUgPSAnY2lyY2xlJywgc2l6ZT0zLjIpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb250X2cyLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iI0U2OUYwMCIsIHNoYXBlID0gJ2NpcmNsZScsIHNpemU9My4yKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMC4yLDAuNywwLjEpLCBsaW1pdHMgPSBjKDAuMiwgMC43KSwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogIGZhY2V0X3dyYXAofmlpX2RpbWVuc2lvbiwgbGFiZWxsZXIgPSANCiAgICAgICAgICAgICAgIGxhYmVsbGVyKGlpX2RpbWVuc2lvbiA9IGMoIlNoYXJlIDUwIG9yIG9sZGVyIiA9ICJTaGFyZSBvZiBwZW9wbGUgYWdlZCA1MCB5ZWFycyBvciBvbGRlciIpKSkgKw0KICB0aGVtZShheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJywgY29sb3IgPSAnYmxhY2snKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsNCiAgeWxhYigiIikgKw0KICB4bGFiKCIiKQ0KDQpmaWcxX3Y0X2V0aCA8LSBnZ3Bsb3QoZWlbZWkkaWlfZGltZW5zaW9uPT0iU2hhcmUgVHVya2lzaC9Nb3JvY2NhbiIsXSkgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHk9aWlfY29udF9nMiwgeWVuZD1paV9jb250X2cxLCB4PWlpX3NldHRpbmcsIHhlbmQ9aWlfc2V0dGluZyksIGNvbG9yPSJncmV5IikgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHk9aWlfY29udF9nMiwgeWVuZD1paV9jb21wX2cxLCB4PWlpX3NldHRpbmcsIHhlbmQ9aWlfc2V0dGluZyksIGNvbG9yPSJncmV5IikgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbXBfbWVhbiwgeD1paV9zZXR0aW5nKSwgY29sb3I9IiM5OTk5OTkiLCBzaGFwZSA9ICdzcXVhcmUnLCBzaXplPTMpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb21wX2cxLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iIzU2QjRFOSIsIHNoYXBlID0gJ3NxdWFyZScsIHNpemU9MykgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbXBfZzIsIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjRTY5RjAwIiwgc2hhcGUgPSAnc3F1YXJlJywgc2l6ZT0zKSArDQogICNnZW9tX3BvaW50KGFlcyh4PWlpX3NldHRpbmcsIHk9aWlfY29udF9tZWFuKSwgY29sb3I9J3JlZCcsIHNoYXBlID0gJ2NpcmNsZScsIHNpemU9NCkgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbnRfZzEsIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjNTZCNEU5Iiwgc2hhcGUgPSAnY2lyY2xlJywgc2l6ZT0zLjIpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb250X2cyLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iI0U2OUYwMCIsIHNoYXBlID0gJ2NpcmNsZScsIHNpemU9My4yKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwwLjUsMC4xKSwgbGltaXRzID0gYygwLDAuNSksIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKw0KICBmYWNldF93cmFwKH5paV9kaW1lbnNpb24sIGxhYmVsbGVyID0gDQogICAgICAgICAgICAgICBsYWJlbGxlcihpaV9kaW1lbnNpb24gPSBjKCJTaGFyZSBUdXJraXNoL01vcm9jY2FuIiA9ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIpKSkgKw0KICB0aGVtZShheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJywgY29sb3IgPSAnYmxhY2snKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsNCiAgeWxhYigiIikgKw0KICB4bGFiKCIiKQ0KDQpmaWcxX3Y0X2VkdSA8LSBnZ3Bsb3QoZWlbZWkkaWlfZGltZW5zaW9uPT0iU2hhcmUgY29sbGVnZSBkZWdyZWUiLF0pICsNCiAgZ2VvbV9zZWdtZW50KGFlcyh5PWlpX2NvbnRfZzIsIHllbmQ9aWlfY29udF9nMSwgeD1paV9zZXR0aW5nLCB4ZW5kPWlpX3NldHRpbmcpLCBjb2xvcj0iZ3JleSIpICsNCiAgZ2VvbV9zZWdtZW50KGFlcyh5PWlpX2NvbnRfZzIsIHllbmQ9aWlfY29tcF9nMSwgeD1paV9zZXR0aW5nLCB4ZW5kPWlpX3NldHRpbmcpLCBjb2xvcj0iZ3JleSIpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb21wX21lYW4sIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjOTk5OTk5Iiwgc2hhcGUgPSAnc3F1YXJlJywgc2l6ZT0zKSArDQogIGdlb21fcG9pbnQoYWVzKHk9aWlfY29tcF9nMSwgeD1paV9zZXR0aW5nKSwgY29sb3I9IiM1NkI0RTkiLCBzaGFwZSA9ICdzcXVhcmUnLCBzaXplPTMpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb21wX2cyLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iI0U2OUYwMCIsIHNoYXBlID0gJ3NxdWFyZScsIHNpemU9MykgKw0KICAjZ2VvbV9wb2ludChhZXMoeD1paV9zZXR0aW5nLCB5PWlpX2NvbnRfbWVhbiksIGNvbG9yPSdyZWQnLCBzaGFwZSA9ICdjaXJjbGUnLCBzaXplPTQpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb250X2cxLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iIzU2QjRFOSIsIHNoYXBlID0gJ2NpcmNsZScsIHNpemU9My4yKSArDQogIGdlb21fcG9pbnQoYWVzKHk9aWlfY29udF9nMiwgeD1paV9zZXR0aW5nKSwgY29sb3I9IiNFNjlGMDAiLCBzaGFwZSA9ICdjaXJjbGUnLCBzaXplPTMuMikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAuMiwwLjcsMC4xKSwgbGltaXRzID0gYygwLjIsIDAuNyksIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKw0KICBmYWNldF93cmFwKH5paV9kaW1lbnNpb24sIGxhYmVsbGVyID0gDQogICAgICAgICAgICAgICBsYWJlbGxlcihpaV9kaW1lbnNpb24gPSBjKCJTaGFyZSBjb2xsZWdlIGRlZ3JlZSIgPSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIpKSkgKw0KICB0aGVtZShheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJywgY29sb3IgPSAnYmxhY2snKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpICsNCiAgeWxhYigiIikgKw0KICB4bGFiKCIiKQ0KDQpmaWd1cmVfMSA8LSB3cmFwX3Bsb3RzKGZpZzFfdjRfYWdlLCBmaWcxX3Y0X2V0aCwgZmlnMV92NF9lZHUsIGxlZ2VuZF9wbG90X2FnZSwgbGVnZW5kX3Bsb3RfZXRoLCBsZWdlbmRfcGxvdF9lZHUsIGJ5cm93PVQsIGRlc2lnbiA9IGZpZzFkZXNpZ24pICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSBsaXN0KGMoJ2EnLCAnYicsICdjJywgJycsICcnLCAnJykpKSAmIHRoZW1lKHBsb3QudGFnID0gZWxlbWVudF90ZXh0KGZhY2UgPSAnYm9sZCcpKQ0KI3Bsb3QoZmlndXJlXzEpDQoNCiNnZ3NhdmUoZmlndXJlXzEsIGZpbGUgPSAnLi9maWd1cmVzL2ZpZ3VyZTAxX21haW4ucG5nJywgaGVpZ2h0ID0gNywgd2lkdGggPSAxMi41KQ0KDQojIyBGaWd1cmUgMSAtIFJvYnVzdG5lc3MgY2hlY2s6IHNwb3J0cyBjbHVicyB2cyBvdGhlciBjaXZpYyBvcmdhbml6YXRpb25zIC0tLS0NCmxpc3Nfc3BvcnQgPC0gZGYgJT4lIGZpbHRlcihvY2l2X21vc3RpbXBfdHlwZT09IlNwb3J0cyIpDQpsaXNzX2Npdm90aCA8LSBkZiAlPiUgZmlsdGVyKG9jaXZfbW9zdGltcF90eXBlIT0iU3BvcnRzIikNCg0KZWlfYWdlX3Nwb3J0IDwtIGZjcmVhdGVfZXhwb3N1cmVfbWVhbnMoZGF0ID0gbGlzc19zcG9ydCwgZGltX3ZhciA9IGFnZSwgZzEgPSAnNTAgb3Igb2xkZXInLCBnMiA9ICd1bmRlciA1MCcsIGNvbXBfdmFyID0gb2Npdl9jb21wX2FnZSwgY29udF92YXIgPSBvY2l2X2NvbnRfYWdlLCBzZXR0aW5nID0gJ3Nwb3J0IGNsdWJzJywgZGF0YXNvdXJjZSA9ICdzdWJqZWN0aXZlJykNCmVpX2FnZV9jaXZvdGggPC0gZmNyZWF0ZV9leHBvc3VyZV9tZWFucyhkYXQgPSBsaXNzX2Npdm90aCwgZGltX3ZhciA9IGFnZSwgZzEgPSAnNTAgb3Igb2xkZXInLCBnMiA9ICd1bmRlciA1MCcsIGNvbXBfdmFyID0gb2Npdl9jb21wX2FnZSwgY29udF92YXIgPSBvY2l2X2NvbnRfYWdlLCBzZXR0aW5nID0gJ290aGVyIGNpdmljIG9yZ2FuaXphdGlvbnMnLCBkYXRhc291cmNlID0gJ3N1YmplY3RpdmUnKQ0KZWlfZWR1X3Nwb3J0IDwtIGZjcmVhdGVfZXhwb3N1cmVfbWVhbnMoZGF0ID0gbGlzc19zcG9ydCwgZGltX3ZhciA9IGVkdSwgZzEgPSAnY29sbGVnZSBkZWdyZWUnLCBnMiA9ICdubyBjb2xsZWdlIGRlZ3JlZScsIGNvbXBfdmFyID0gb2Npdl9jb21wX2VkdSwgY29udF92YXIgPSBvY2l2X2NvbnRfZWR1LCBzZXR0aW5nID0gJ3Nwb3J0IGNsdWJzJywgZGF0YXNvdXJjZSA9ICdzdWJqZWN0aXZlJykNCmVpX2VkdV9jaXZvdGggPC0gZmNyZWF0ZV9leHBvc3VyZV9tZWFucyhkYXQgPSBsaXNzX2Npdm90aCwgZGltX3ZhciA9IGVkdSwgZzEgPSAnY29sbGVnZSBkZWdyZWUnLCBnMiA9ICdubyBjb2xsZWdlIGRlZ3JlZScsIGNvbXBfdmFyID0gb2Npdl9jb21wX2VkdSwgY29udF92YXIgPSBvY2l2X2NvbnRfZWR1LCBzZXR0aW5nID0gJ290aGVyIGNpdmljIG9yZ2FuaXphdGlvbnMnLCBkYXRhc291cmNlID0gJ3N1YmplY3RpdmUnKQ0KZWlfZXRoX3Nwb3J0IDwtIGZjcmVhdGVfZXhwb3N1cmVfbWVhbnMoZGF0ID0gbGlzc19zcG9ydCwgZGltX3ZhciA9IGV0aF9kdG0sIGcxID0gJ1R1cmtpc2gvTW9yb2NjYW4nLCBnMiA9ICdEdXRjaCcsIGNvbXBfdmFyID0gb2Npdl9jb21wX2V0aCwgY29udF92YXIgPSBvY2l2X2NvbnRfZXRoLCBzZXR0aW5nID0gJ3Nwb3J0IGNsdWJzJywgZGF0YXNvdXJjZSA9ICdzdWJqZWN0aXZlJykNCmVpX2V0aF9jaXZvdGggPC0gZmNyZWF0ZV9leHBvc3VyZV9tZWFucyhkYXQgPSBsaXNzX2Npdm90aCwgZGltX3ZhciA9IGV0aF9kdG0sIGcxID0gJ1R1cmtpc2gvTW9yb2NjYW4nLCBnMiA9ICdEdXRjaCcsIGNvbXBfdmFyID0gb2Npdl9jb21wX2V0aCwgY29udF92YXIgPSBvY2l2X2NvbnRfZXRoLCBzZXR0aW5nID0gJ290aGVyIGNpdmljIG9yZ2FuaXphdGlvbnMnLCBkYXRhc291cmNlID0gJ3N1YmplY3RpdmUnKQ0KZWlfc3BvcnRfY2l2b3RoIDwtIHJiaW5kKGVpX2FnZV9zcG9ydCwgZWlfYWdlX2Npdm90aCwgZWlfZWR1X3Nwb3J0LCBlaV9lZHVfY2l2b3RoLCBlaV9ldGhfc3BvcnQsIGVpX2V0aF9jaXZvdGgpDQoNCmVpX3Nwb3J0X2Npdm90aCA8LSBlaV9zcG9ydF9jaXZvdGggJT4lIG11dGF0ZShpaV9zZXR0aW5nID0gZmFjdG9yKGlpX3NldHRpbmcsIGxldmVscyA9IGMoInNwb3J0IGNsdWJzIiwgIm90aGVyIGNpdmljIG9yZ2FuaXphdGlvbnMiKSkpICNnZXQgb3JkZXIgb2Ygc2V0dGluZyB2YXJpYWJsZSByaWdodC4gDQoNCmZpZzFfdjRfYWdlX3Nwb3J0X2Npdm90aCA8LSBnZ3Bsb3QoZWlfc3BvcnRfY2l2b3RoW2VpX3Nwb3J0X2Npdm90aCRpaV9kaW1lbnNpb249PSJTaGFyZSA1MCBvciBvbGRlciIsXSkgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHk9aWlfY29udF9nMiwgeWVuZD1paV9jb250X2cxLCB4PWlpX3NldHRpbmcsIHhlbmQ9aWlfc2V0dGluZyksIGNvbG9yPSJncmV5IikgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHk9aWlfY29udF9nMiwgeWVuZD1paV9jb21wX2cxLCB4PWlpX3NldHRpbmcsIHhlbmQ9aWlfc2V0dGluZyksIGNvbG9yPSJncmV5IikgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbXBfbWVhbiwgeD1paV9zZXR0aW5nKSwgY29sb3I9IiM5OTk5OTkiLCBzaGFwZSA9ICdzcXVhcmUnLCBzaXplPTMpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb21wX2cxLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iIzU2QjRFOSIsIHNoYXBlID0gJ3NxdWFyZScsIHNpemU9MykgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbXBfZzIsIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjRTY5RjAwIiwgc2hhcGUgPSAnc3F1YXJlJywgc2l6ZT0zKSArDQogICNnZW9tX3BvaW50KGFlcyh4PWlpX3NldHRpbmcsIHk9aWlfY29udF9tZWFuKSwgY29sb3I9J3JlZCcsIHNoYXBlID0gJ2NpcmNsZScsIHNpemU9NCkgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbnRfZzEsIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjNTZCNEU5Iiwgc2hhcGUgPSAnY2lyY2xlJywgc2l6ZT0zLjIpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb250X2cyLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iI0U2OUYwMCIsIHNoYXBlID0gJ2NpcmNsZScsIHNpemU9My4yKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMC4yLDAuNzEsMC4xKSwgbGltaXRzID0gYygwLjIsIDAuNzEpLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgZmFjZXRfd3JhcCh+aWlfZGltZW5zaW9uLCBsYWJlbGxlciA9IA0KICAgICAgICAgICAgICAgbGFiZWxsZXIoaWlfZGltZW5zaW9uID0gYygiU2hhcmUgNTAgb3Igb2xkZXIiID0gIlNoYXJlIG9mIHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIikpKSArDQogIHRoZW1lKGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAnd2hpdGUnLCBjb2xvciA9ICdibGFjaycpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKw0KICB5bGFiKCIiKSArDQogIHhsYWIoIiIpDQoNCmZpZzFfdjRfZXRoX3Nwb3J0X2Npdm90aCA8LSBnZ3Bsb3QoZWlfc3BvcnRfY2l2b3RoW2VpX3Nwb3J0X2Npdm90aCRpaV9kaW1lbnNpb249PSJTaGFyZSBUdXJraXNoL01vcm9jY2FuIixdKSArDQogIGdlb21fc2VnbWVudChhZXMoeT1paV9jb250X2cyLCB5ZW5kPWlpX2NvbnRfZzEsIHg9aWlfc2V0dGluZywgeGVuZD1paV9zZXR0aW5nKSwgY29sb3I9ImdyZXkiKSArDQogIGdlb21fc2VnbWVudChhZXMoeT1paV9jb250X2cyLCB5ZW5kPWlpX2NvbXBfZzEsIHg9aWlfc2V0dGluZywgeGVuZD1paV9zZXR0aW5nKSwgY29sb3I9ImdyZXkiKSArDQogIGdlb21fcG9pbnQoYWVzKHk9aWlfY29tcF9tZWFuLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iIzk5OTk5OSIsIHNoYXBlID0gJ3NxdWFyZScsIHNpemU9MykgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbXBfZzEsIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjNTZCNEU5Iiwgc2hhcGUgPSAnc3F1YXJlJywgc2l6ZT0zKSArDQogIGdlb21fcG9pbnQoYWVzKHk9aWlfY29tcF9nMiwgeD1paV9zZXR0aW5nKSwgY29sb3I9IiNFNjlGMDAiLCBzaGFwZSA9ICdzcXVhcmUnLCBzaXplPTMpICsNCiAgI2dlb21fcG9pbnQoYWVzKHg9aWlfc2V0dGluZywgeT1paV9jb250X21lYW4pLCBjb2xvcj0ncmVkJywgc2hhcGUgPSAnY2lyY2xlJywgc2l6ZT00KSArDQogIGdlb21fcG9pbnQoYWVzKHk9aWlfY29udF9nMSwgeD1paV9zZXR0aW5nKSwgY29sb3I9IiM1NkI0RTkiLCBzaGFwZSA9ICdjaXJjbGUnLCBzaXplPTMuMikgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbnRfZzIsIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjRTY5RjAwIiwgc2hhcGUgPSAnY2lyY2xlJywgc2l6ZT0zLjIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDAuNTEsMC4xKSwgbGltaXRzID0gYygwLCAwLjUxKSwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogIGZhY2V0X3dyYXAofmlpX2RpbWVuc2lvbiwgbGFiZWxsZXIgPSANCiAgICAgICAgICAgICAgIGxhYmVsbGVyKGlpX2RpbWVuc2lvbiA9IGMoIlNoYXJlIFR1cmtpc2gvTW9yb2NjYW4iID0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIikpKSArDQogIHRoZW1lKGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAnd2hpdGUnLCBjb2xvciA9ICdibGFjaycpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKw0KICB5bGFiKCIiKSArDQogIHhsYWIoIiIpDQoNCmZpZzFfdjRfZWR1X3Nwb3J0X2Npdm90aCA8LSBnZ3Bsb3QoZWlfc3BvcnRfY2l2b3RoW2VpX3Nwb3J0X2Npdm90aCRpaV9kaW1lbnNpb249PSJTaGFyZSBjb2xsZWdlIGRlZ3JlZSIsXSkgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHk9aWlfY29udF9nMiwgeWVuZD1paV9jb250X2cxLCB4PWlpX3NldHRpbmcsIHhlbmQ9aWlfc2V0dGluZyksIGNvbG9yPSJncmV5IikgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHk9aWlfY29udF9nMiwgeWVuZD1paV9jb21wX2cxLCB4PWlpX3NldHRpbmcsIHhlbmQ9aWlfc2V0dGluZyksIGNvbG9yPSJncmV5IikgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbXBfbWVhbiwgeD1paV9zZXR0aW5nKSwgY29sb3I9IiM5OTk5OTkiLCBzaGFwZSA9ICdzcXVhcmUnLCBzaXplPTMpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb21wX2cxLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iIzU2QjRFOSIsIHNoYXBlID0gJ3NxdWFyZScsIHNpemU9MykgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbXBfZzIsIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjRTY5RjAwIiwgc2hhcGUgPSAnc3F1YXJlJywgc2l6ZT0zKSArDQogICNnZW9tX3BvaW50KGFlcyh4PWlpX3NldHRpbmcsIHk9aWlfY29udF9tZWFuKSwgY29sb3I9J3JlZCcsIHNoYXBlID0gJ2NpcmNsZScsIHNpemU9NCkgKw0KICBnZW9tX3BvaW50KGFlcyh5PWlpX2NvbnRfZzEsIHg9aWlfc2V0dGluZyksIGNvbG9yPSIjNTZCNEU5Iiwgc2hhcGUgPSAnY2lyY2xlJywgc2l6ZT0zLjIpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1paV9jb250X2cyLCB4PWlpX3NldHRpbmcpLCBjb2xvcj0iI0U2OUYwMCIsIHNoYXBlID0gJ2NpcmNsZScsIHNpemU9My4yKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMC4yLDAuNzEsMC4xKSwgbGltaXRzID0gYygwLjIsIDAuNzEpLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsNCiAgZmFjZXRfd3JhcCh+aWlfZGltZW5zaW9uLCBsYWJlbGxlciA9IA0KICAgICAgICAgICAgICAgbGFiZWxsZXIoaWlfZGltZW5zaW9uID0gYygiU2hhcmUgY29sbGVnZSBkZWdyZWUiID0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiKSkpICsNCiAgdGhlbWUoYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICd3aGl0ZScsIGNvbG9yID0gJ2JsYWNrJyksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmxhY2siKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArDQogIHlsYWIoIiIpICsNCiAgeGxhYigiIikNCg0KZmlndXJlXzFfc3BvcnRfY2l2b3RoIDwtIHdyYXBfcGxvdHMoZmlnMV92NF9hZ2Vfc3BvcnRfY2l2b3RoLCBmaWcxX3Y0X2V0aF9zcG9ydF9jaXZvdGgsIGZpZzFfdjRfZWR1X3Nwb3J0X2Npdm90aCwgbGVnZW5kX3Bsb3RfYWdlLCBsZWdlbmRfcGxvdF9ldGgsIGxlZ2VuZF9wbG90X2VkdSwgYnlyb3c9VCwgZGVzaWduID0gZmlnMWRlc2lnbikgKyANCiAgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSBsaXN0KGMoJ2EnLCAnYicsICdjJywgJycsICcnLCAnJykpKSAmIHRoZW1lKHBsb3QudGFnID0gZWxlbWVudF90ZXh0KGZhY2UgPSAnYm9sZCcpKQ0KI3Bsb3QoZmlndXJlXzFfc3BvcnRfY2l2b3RoKQ0KDQojZ2dzYXZlKGZpZ3VyZV8xX3Nwb3J0X2Npdm90aCwgZmlsZSA9ICcuL2ZpZ3VyZXMvZmlndXJlMDFfc3BvcnRfY2l2b3RoLnBuZycsIGhlaWdodCA9IDcsIHdpZHRoID0gMTIuNSkNCmBgYCANCg0KIVsqKkZpZ3VyZSAxQSAoTWFpbik6IFNlZ3JlZ2F0aW9uIGFjcm9zcyBhbmQgd2l0aGluIG5laWdoYm9yaG9vZHMgYW5kIGNpdmljIG9yZ2FuaXphdGlvbnMqKl0oLi9maWd1cmVzL2ZpZ3VyZTAxX21haW4ucG5nKQ0KDQohWyoqRmlndXJlIDFCIChTdXBwbGVtZW50KTogRGlmZmVyZW5jZXMgYmV0d2VlbiBzcG9ydHMgY2x1YnMgYW5kIG90aGVyIG9yZ2FuaXphdGlvbiB0eXBlcyoqXSguL2ZpZ3VyZXMvZmlndXJlMDFfc3BvcnRfY2l2b3RoLnBuZykNCg0KLS0tDQoNCiMgTElTUyBOZWlnaGJvcmhvb2Qvb3JnYW5pemF0aW9uIGNob2ljZSBleHBlcmltZW50DQoNCg0KIyMgTWFyZ2luYWwgbWVhbnMgey50YWJzZXQgLnRhYnNldC1mYWRlfQ0KDQpXZSB1c2UgdGhlIFItcGFja2FnZSBgY3JlZ2dgIGRldmVsb3BlZCBieSBATGVlcGVyMjAyMCB0byBjYWxjdWxhdGUgbWFyZ2luYWwgbWVhbnMuDQoNCmBgYHtyLCBtbXMsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD05LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfSANCiMgY2xlYW4gZW52aXJvbm1lbnQsIGJ1dCBrZWVwIGZ1bmN0aW9ucyBhbmQgZGF0YXNldHMNCnJtKGxpc3QgPSBzZXRkaWZmKGxzKCksIGMobHNmLnN0cigpLCAiZGYiLCAiZGYyIikpKQ0KDQojZm9ybXVsYSBzcGVjaWZ5aW5nIG91dGNvbWUgYW5kIGNvbmpvaW50IGZlYXR1cmVzDQpmY2l2IDwtIGVjaXZfY2hvaWNlIH4gZWNpdl90aW1lICsgZWNpdl9jb3N0ICsgZWNpdl9jb2hlc2lvbiArIGVjaXZfYWNxdWFpbnRhbmNlcyArIGVjaXZfY29tcF9lZHVjICsgZWNpdl9jb21wX2FnZSArIGVjaXZfY29tcF9ldGggDQpmbmJoIDwtIGVuYmhfY2hvaWNlIH4gZW5iaF90aW1lICsgZW5iaF9jb3N0ICsgZW5iaF9jb2hlc2lvbiArIGVuYmhfYWNxdWFpbnRhbmNlcyArIGVuYmhfY29tcF9lZHVjICsgZW5iaF9jb21wX2FnZSArIGVuYmhfY29tcF9ldGgNCg0KI2NhbGN1bGF0ZSBtYXJnaW5hbCBtZWFucw0KbW1jaXYgPC0gY3JlZ2c6Om1tKGRmLCBmY2l2LCBpZCA9IH5pZCkNCm1tbmJoIDwtIGNyZWdnOjptbShkZiwgZm5iaCwgaWQgPSB+aWQpDQoNCiNwbG90KG1tY2l2KQ0KI3Bsb3QobW1uYmgpDQpgYGANCg0KYGBge3IsIHRlc3QsIGV2YWw9RkFMU0V9DQojMSBmaXQgbGluZWFyIG1vZGVsDQpsaW5tb2RlbCA8LSBsbShlY2l2X2Nob2ljZSB+ICgxIHwgaWQpICsgZWNpdl90aW1lICsgZWNpdl9jb3N0ICsgZWNpdl9jb2hlc2lvbiArIGVjaXZfYWNxdWFpbnRhbmNlcyArIGVjaXZfY29tcF9lZHVjICsgZWNpdl9jb21wX2FnZSArIGVjaXZfY29tcF9ldGgsIGRhdGEgPSBkZikNCnN1bW1hcnkobGlubW9kZWwpDQoNCiMyIGdldCBwcmVkaWN0ZWQgcHJvYmFiaWxpdGllcw0KI3JlbW92ZSBtaXNzaW5ncyB2YWx1ZXMNCmRmX25tIDwtIGRmW2NvbXBsZXRlLmNhc2VzKGRmW2MoImVjaXZfY2hvaWNlIiwgImVjaXZfdGltZSIsICJlY2l2X2Nvc3QiLCAiZWNpdl9jb2hlc2lvbiIsICJlY2l2X2FjcXVhaW50YW5jZXMiLCAiZWNpdl9jb21wX2VkdWMiLCAiZWNpdl9jb21wX2FnZSIsICJlY2l2X2NvbXBfZXRoIildKSwgXQ0KcHJlZHByb2IgPC0gcHJlZGljdChsaW5tb2RlbCkNCg0KI21hcmdpbmFsIG1lYW4gPT0gYXZlcmFnZSBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkNCm1lYW4ocHJlZHByb2JbZGZfbm0kZWNpdl90aW1lID09ICJ0cmF2ZWwgdGltZTogMjAgbWludXRlcyJdKQ0KbWVhbihwcmVkcHJvYltkZl9ubSRlY2l2X3RpbWUgPT0gInRyYXZlbCB0aW1lOiAxNSBtaW51dGVzIl0pDQptZWFuKHByZWRwcm9iW2RmX25tJGVjaXZfdGltZSA9PSAidHJhdmVsIHRpbWU6IDEwIG1pbnV0ZXMiXSkNCmBgYA0KDQoNCjxicj4NCg0KIyMjIE5laWdoYm9yaG9vZHMNCg0KYGBge3J9DQpmc2hvd2RmKG1tbmJoKQ0KYGBgDQoNCiMjIyBDaXZpYyBvcmdhbml6YXRpb25zDQoNCmBgYHtyfQ0KZnNob3dkZihtbWNpdikNCmBgYCANCg0KIyMgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KLS0tDQoNCiMjIFN1Ymdyb3VwIG1hcmdpbmFsIG1lYW5zDQoNCldlIGVzdGltYXRlIGNvbmRpdGlvbmFsIG1hcmdpbmFsIG1lYW5zIGFuZCBkaWZmZXJlbmNlcyBiZXR3ZWVuIGNvbmRpdGlvbmFsIG1hcmdpbmFsIG1lYW5zIHRvIGRlc2NyaWJlIGRpZmZlcmVuY2VzIGluIHByZWZlcmVuY2UgbGV2ZWwgYmV0d2VlbiBzdWJncm91cHMuIFRvIGZvcm1hbGx5IHRlc3QgZm9yIGdyb3VwcyBkaWZmZXJlbmNlcyBpbiBwcmVmZXJlbmNlcyB0b3dhcmQgcGFydGljdWxhciBmZWF0dXJlcywgd2UgdXNlIG9tbmlidXMgbmVzdGVkIG1vZGVsIGNvbXBhcmlzb25zLiANCg0KYGBge3IsIGNtbXMsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfSANCiNjcmVhdGUgc3ViZ3JvdXBzDQpkZiRUZXJ0IDwtIE5BX3JlYWxfDQpkZiRUZXJ0W2RmJGVkdSA9PSAiY29sbGVnZSBkZWdyZWUiXSA8LSAxTA0KZGYkVGVydFtkZiRlZHUgPT0gIm5vIGNvbGxlZ2UgZGVncmVlIl0gPC0gMkwNCmRmJFRlcnQgPC0gZmFjdG9yKGRmJFRlcnQsIDE6MiwgYygiV2l0aCBjb2xsZWdlIGRlZ3JlZSIsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIikpDQoNCmRmJEFnZSA8LSBOQV9yZWFsXw0KZGYkQWdlW2RmJGFnZSA9PSAiNTAgb3Igb2xkZXIiXSA8LSAxTA0KZGYkQWdlW2RmJGFnZSA9PSAidW5kZXIgNTAiIF0gPC0gMkwNCmRmJEFnZSA8LSBmYWN0b3IoZGYkQWdlLCAxOjIsIGMoIjUwIHllYXJzIG9yIG9sZGVyIiwgIkJlbG93IDUwIHllYXJzIikpDQoNCmRmJFRNIDwtIE5BX3JlYWxfDQpkZiRUTVtkZiRldGhfZHRtID09ICJEdXRjaCJdIDwtIDFMDQpkZiRUTVtkZiRldGhfZHRtID09ICJUdXJraXNoL01vcm9jY2FuIl0gPC0gMkwNCmRmJFRNIDwtIGZhY3RvcihkZiRUTSwgMToyLCBjKCJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIsICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiICkpDQpkZiRUTSA8LSBmYWN0b3IoZGYkVE0sIGxldmVscyA9IGMoICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiKSkNCg0KI291dGNvbWUgYW5kIGNvbmpvaW50IGZlYXR1cmVzLCBpbmNsdWRpbmcgb25seSBjb21wb3NpdGlvbiBmZWF0dXJlcyB3ZSBhcmUgaW50ZXJlc3RlZCBpbjsNCiNhbmQgdGhlIHN1Ymdyb3VwaW5nIHZhcmlhYmxlDQoNCiNjb25kaXRpb25hbCBtYXJnaW5hbCBtZWFucyAoY29tcG9zaXRpb24gZGltZW5zaW9uOyBkaXNhZ2dyZWdhdGVkIGJ5IHJlc3BvbmRlbnQgdmFsdWUgZm9yIHRoaXMgZGltZW5zaW9uKQ0KDQojMS4gbmJoDQpubW1lZHVjIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkVGVydCksIF0sIGVuYmhfY2hvaWNlIH4gZW5iaF9jb21wX2VkdWMsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflRlcnQpDQpubW1hZ2UgPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRBZ2UpLCBdLCBlbmJoX2Nob2ljZSB+IGVuYmhfY29tcF9hZ2UsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gfkFnZSkNCm5tbWV0aCA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJFRNKSwgXSwgZW5iaF9jaG9pY2UgfiBlbmJoX2NvbXBfZXRoLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5UTSkNCg0KIzIuIG9yZw0KY21tZWR1YyA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJFRlcnQpLCBdLCBlY2l2X2Nob2ljZSB+IGVjaXZfY29tcF9lZHVjLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5UZXJ0KQ0KY21tYWdlIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkQWdlKSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfYWdlLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5BZ2UpDQpjbW1ldGggPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRUTSksIF0sIGVjaXZfY2hvaWNlIH4gZWNpdl9jb21wX2V0aCwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VE0pDQoNCiNyb3diaW5kIHRoZSBkYXRhZnJhbWVzDQojbGVhdmUgb3V0IGxhc3QgY29sdW1uLCByZWZsZWN0aW5nIHRoZSBzdWJncm91cGluZyB2YXJpYWJsZQ0KbW1zIDwtIHJiaW5kKG5tbWFnZVstMTJdLG5tbWV0aFstMTJdLG5tbWVkdWNbLTEyXSwNCiAgICAgICAgICAgICBjbW1hZ2VbLTEyXSxjbW1ldGhbLTEyXSxjbW1lZHVjWy0xMl0pDQoNCiNyZW5hbWUgbGFiZWxzDQojMS4gb2Ygb3V0Y29tZSAoc2V0dGluZykNCm1tcyRPdXRjb21lIDwtIGZhY3RvcihpZmVsc2UobW1zJG91dGNvbWUgPT0gImVjaXZfY2hvaWNlIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiLCAiTmVpZ2hib3Job29kcyIpLA0KICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJOZWlnaGJvcmhvb2RzIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiKSkNCg0KIzIuIG9mIChkZW1vZ3JhcGhpYyBjb21wb3NpdGlvbikgZmVhdHVyZXMNCm1tcyRGZWF0dXJlIDwtIGZhY3RvcihzdWIoIi4qXyIsICIiLCBtbXMkZmVhdHVyZSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiYWdlIiwgImV0aCIsICJlZHVjIiksDQogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJTaGFyZSBvZiBwZW9wbGUgYWdlZCA1MCB5ZWFycyBvciBvbGRlciIsICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiLCAgIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiKSkNCg0KbW1zJFN1Ymdyb3VwIDwtIG1tcyRCWQ0KbW1zJFN1Ymdyb3VwIDwtIGZhY3RvcihtbXMkU3ViZ3JvdXAsIGxldmVscyA9IGMoIjUwIHllYXJzIG9yIG9sZGVyIiwgIkJlbG93IDUwIHllYXJzIiwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICAgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiAsICJXaXRoIGNvbGxlZ2UgZGVncmVlIiwiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIgICkpIA0KDQojIG5pY2UgY29sb3IgcGFsZXR0ZQ0KY2JQYWxldHRlIDwtIGMoIiM5OTk5OTkiLCIjRTY5RjAwIiwiIzU2QjRFOSIsIiNENTVFMDAiLCIjRjBFNDQyIiwiIzAwNzJCMiIpDQoNCnAyIDwtIHBsb3QobW1zLCB2bGluZT0xLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiU3ViZ3JvdXAiLCB4bGFiID0gIk1hcmdpbmFsIG1lYW4iKSArDQogIGZhY2V0X2dyaWQyKCBPdXRjb21lIH4gRmVhdHVyZSwgc2NhbGVzID0gImZyZWUiLCBpbmRlcGVuZGVudCA9ICJ5Iiwgc3dpdGNoID0gInkiKSArDQogIGdlb21fdGV4dCggYWVzKGxhYmVsID0gc3ByaW50ZigiJTAuMmYgKCUwLjJmKSIsIGVzdGltYXRlLCBzdGQuZXJyb3IpKSwgc2l6ZSA9IDMsIGNvbG91ciA9ICJibGFjayIsIHZqdXN0ID0gLTEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGUpICsNCiAgZmFjZXR0ZWRfcG9zX3NjYWxlcygNCiAgICB5ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygidGhyZWUgcXVhcnRlcnMgKDc1JSkiLCAiaGFsZiAoNTAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgYWdlZCA1MCB5ZWFycyBvciBvbGRlciIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJoYWxmICg1MCUpIiwgImp1c3QgdW5kZXIgaGFsZiAoNDAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIiwgIm5vbmUgKDAlKSIpKQ0KICAgICAgKSwNCiAgICAjZnJlZWluZyB1cCB0aGUgeCBzY2FsZXMgZG9lcyBub3Qgd29yayBmb3Igc29tZSByZWFzb24uLi4gc28gaSBzZXQgdGhlbSBtYW51YWxseToNCiAgICB4ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC40MCwuNjApLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgYWdlZCA1MCB5ZWFycyBvciBvbGRlciIgfiBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgICAgIGxpbWl0cyA9IGMoLjQ1LC42MCksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSwNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIgfiBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgICAgIGxpbWl0cyA9IGMoLjMwLC43MCksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKQ0KICAgICAgKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIyBzdHJpcC50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKCksDQogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikNCg0KI3NwbGl0IGxlZ2VuZCBpbnRvIG11bHRpcGxlIHBhcnRzDQpzcGxpdDEgPC0gbW1zW21tcyRTdWJncm91cCAlaW4lIGMoIjUwIHllYXJzIG9yIG9sZGVyIiwgIkJlbG93IDUwIHllYXJzIiksIF0NCnNwbGl0MiA8LSBtbXNbbW1zJFN1Ymdyb3VwICVpbiUgYygiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiksIF0NCnNwbGl0MyA8LSBtbXNbbW1zJFN1Ymdyb3VwICVpbiUgYygiV2l0aCBjb2xsZWdlIGRlZ3JlZSIsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiksIF0NCg0KI3JldmVyc2Ugb3JkZXIgZmFjdG9yLi4uLiBidWcgaW4gZ2dwbG90MiBtYWtlcyB0aGUgb3JkZXIgb2YgdGhlIHN1Ymdyb3VwcyBpbiB0aGUgcGxvdCBhbmQgdGhlIGxlZ2VuZCByZXZlcnNlZA0Kc3BsaXQxJFN1Ymdyb3VwIDwtIGZhY3RvcihzcGxpdDEkU3ViZ3JvdXAsIGxldmVscyA9IHJldihsZXZlbHMoc3BsaXQxJFN1Ymdyb3VwKSkpDQpzcGxpdDIkU3ViZ3JvdXAgPC0gZmFjdG9yKHNwbGl0MiRTdWJncm91cCwgbGV2ZWxzID0gcmV2KGxldmVscyhzcGxpdDIkU3ViZ3JvdXApKSkNCnNwbGl0MyRTdWJncm91cCA8LSBmYWN0b3Ioc3BsaXQzJFN1Ymdyb3VwLCBsZXZlbHMgPSByZXYobGV2ZWxzKHNwbGl0MyRTdWJncm91cCkpKQ0KDQojcGxvdCBsZWdlbmRzDQpzcGxpdDFwIDwtIGdncGxvdChzcGxpdDEsIGFlcyh4ID0gZXN0aW1hdGUsIHkgPSBsZXZlbCwgY29sb3I9U3ViZ3JvdXApKSArIGdlb21fcG9pbnQoKSArIGxhYnMoY29sb3IgPSAiUmVzcG9uZGVudCBzdWJncm91cHM6IikgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZVtjKDIsMSldKSANCnNwbGl0MnAgPC0gZ2dwbG90KHNwbGl0MiwgYWVzKHggPSBlc3RpbWF0ZSwgeSA9IGxldmVsLCBjb2xvcj1TdWJncm91cCkpICsgZ2VvbV9wb2ludCgpICsgbGFicyhjb2xvciA9ICJSZXNwb25kZW50IHN1Ymdyb3VwczoiKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoNCwzKV0pDQpzcGxpdDNwIDwtIGdncGxvdChzcGxpdDMsIGFlcyh4ID0gZXN0aW1hdGUsIHkgPSBsZXZlbCwgY29sb3I9U3ViZ3JvdXApKSArIGdlb21fcG9pbnQoKSArIGxhYnMoY29sb3IgPSAiUmVzcG9uZGVudCBzdWJncm91cHM6IikgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZVtjKDYsNSldKQ0KDQojZ2V0IGxlZ2VuZHMNCmxlZzEgPC0gZ2V0X2xlZ2VuZChzcGxpdDFwKQ0KbGVnMiA8LSBnZXRfbGVnZW5kKHNwbGl0MnApDQpsZWczIDwtIGdldF9sZWdlbmQoc3BsaXQzcCkNCg0KI2NvbWJpbmUgbGVnZW5kcw0KbGVnMTIzIDwtIHBsb3RfZ3JpZChsZWcxLGxlZzIsbGVnMywgbnJvdz0xLCBhbGlnbj0iaCIpDQoNCiNjcmVhdGUgYSBibGFuayBwbG90IGZvciBsZWdlbmQgYWxpZ25tZW50DQpibGFua19wIDwtIHBsb3Rfc3BhY2VyKCkNCg0KI2NvbWJpbmUgYWxsIGluIG9uZQ0KcDMgPC0gcGxvdF9ncmlkKHAyLCBsZWcxMjMsIGFsaWduID0gImgiLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYyg3LDEpKQ0KcGxvdChwMykNCg0KI2dnc2F2ZSgiLi9maWd1cmVzL2NtbXNfbGlzcy5wbmciLCBwMywgd2lkdGg9MTMpIA0KDQojdGVzdCBvZiBwcmVmZXJlbmNlIGhldGVyb2dlbmVpdHkgKG5lc3RlZCBtb2RlbCBjb21wYXJpc29uIHRlc3QNCmNyZWdnOjpjal9hbm92YShkZlshaXMubmEoZGYkVGVydCksIF0sIGVjaXZfY2hvaWNlIH4gZWNpdl9jb21wX2VkdWMsIGJ5ID0gflRlcnQpDQpjcmVnZzo6Y2pfYW5vdmEoZGZbIWlzLm5hKGRmJFRlcnQpLCBdLCBlY2l2X2Nob2ljZSB+IGVjaXZfY29tcF9ldGgsIGJ5ID0gflRlcnQpDQpjcmVnZzo6Y2pfYW5vdmEoZGZbIWlzLm5hKGRmJFRlcnQpLCBdLCBlY2l2X2Nob2ljZSB+IGVjaXZfY29tcF9hZ2UsIGJ5ID0gflRlcnQpDQpgYGAgDQoNCjxicj4NCg0KIyMjIFNlbnNpdGl2aXR5IGNoZWNrcw0KDQojIyMjIGV4Y2x1ZGluZyByZWxpZ2lvdXMgb3JnYW5pemF0aW9ucw0KDQpXZSByZWRvIHRoZSBvcmdhbml6YXRpb24gY2hvaWNlIGFuYWx5c2VzLCBub3cgZXhjbHVkaW5nIHRob3NlIHdob3NlIChtb3N0IGltcG9ydGFudCkgb3JnYW5pemF0aW9uIGlzIGEgcmVsaWdpb3VzIG9yZ2FuaXphdGlvbg0KDQpgYGB7ciwgY21tc19leGNscmVsLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJywgZmlnLndpZHRoPTEyfSANCmRmbm9yZWwgPC0gZGZbZGYkb2Npdl9tb3N0aW1wX3R5cGUgIT0gIlJlbGlnaW91cyIsXQ0KDQojY29uZGl0aW9uYWwgbWFyZ2luYWwgbWVhbnMgKGNvbXBvc2l0aW9uIGRpbWVuc2lvbjsgZGlzYWdncmVnYXRlZCBieSByZXNwb25kZW50IHZhbHVlIGZvciB0aGlzIGRpbWVuc2lvbikNCiNvcmcNCmNtbWVkdWMgPC0gY3JlZ2c6OmNqKGRmbm9yZWxbIWlzLm5hKGRmbm9yZWwkVGVydCksIF0sIGVjaXZfY2hvaWNlIH4gZWNpdl9jb21wX2VkdWMsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflRlcnQpDQpjbW1hZ2UgPC0gY3JlZ2c6OmNqKGRmbm9yZWxbIWlzLm5hKGRmbm9yZWwkQWdlKSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfYWdlLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5BZ2UpDQpjbW1ldGggPC0gY3JlZ2c6OmNqKGRmbm9yZWxbIWlzLm5hKGRmbm9yZWwkVE0pLCBdLCBlY2l2X2Nob2ljZSB+IGVjaXZfY29tcF9ldGgsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflRNKQ0KDQojcm93YmluZCB0aGUgZGF0YWZyYW1lcw0KI2xlYXZlIG91dCBsYXN0IGNvbHVtbiwgcmVmbGVjdGluZyB0aGUgc3ViZ3JvdXBpbmcgdmFyaWFibGUNCm1tc18gPC0gcmJpbmQoY21tYWdlWy0xMl0sY21tZXRoWy0xMl0sY21tZWR1Y1stMTJdKQ0KDQojcmVuYW1lIGxhYmVscw0KIzEuIG9mIG91dGNvbWUgKHNldHRpbmcpDQptbXNfJE91dGNvbWUgPC0gIkNpdmljIG9yZ2FuaXphdGlvbnMgKGV4Y2wuIHJlbGlnaW91cyBvcmcuKSINCg0KIzIuIG9mIChkZW1vZ3JhcGhpYyBjb21wb3NpdGlvbikgZmVhdHVyZXMNCm1tc18kRmVhdHVyZSA8LSBmYWN0b3Ioc3ViKCIuKl8iLCAiIiwgbW1zXyRmZWF0dXJlKSwgDQogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJhZ2UiLCAiZXRoIiwgImVkdWMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlNoYXJlIG9mIHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIiwgIlNoYXJlIG9mIHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIsICAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIpKQ0KDQptbXNfJFN1Ymdyb3VwIDwtIG1tc18kQlkNCm1tc18kU3ViZ3JvdXAgPC0gZmFjdG9yKG1tc18kU3ViZ3JvdXAsIGxldmVscyA9IGMoIjUwIHllYXJzIG9yIG9sZGVyIiwgIkJlbG93IDUwIHllYXJzIiwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICAgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiAsICJXaXRoIGNvbGxlZ2UgZGVncmVlIiwiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIgICkpIA0KDQpwMiA8LSBwbG90KG1tc18sIHZsaW5lPTEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJTdWJncm91cCIsIHhsYWIgPSAiTWFyZ2luYWwgbWVhbiIpICsNCiAgZmFjZXRfZ3JpZDIoIE91dGNvbWUgfiBGZWF0dXJlLCBzY2FsZXMgPSAiZnJlZSIsIGluZGVwZW5kZW50ID0gInkiLCBzd2l0Y2ggPSAieSIpICsNCiAgZ2VvbV90ZXh0KCBhZXMobGFiZWwgPSBzcHJpbnRmKCIlMC4yZiAoJTAuMmYpIiwgZXN0aW1hdGUsIHN0ZC5lcnJvcikpLCBzaXplID0gMywgY29sb3VyID0gImJsYWNrIiwgdmp1c3QgPSAtMSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZSkgKw0KICBsYWJzKHRpdGxlID0gIkV4Y2x1ZGluZyByZWxpZ2lvdXMgb3JnYW5pemF0aW9ucyIpICsNCiAgZmFjZXR0ZWRfcG9zX3NjYWxlcygNCiAgICB5ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygidGhyZWUgcXVhcnRlcnMgKDc1JSkiLCAiaGFsZiAoNTAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgYWdlZCA1MCB5ZWFycyBvciBvbGRlciIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJoYWxmICg1MCUpIiwgImp1c3QgdW5kZXIgaGFsZiAoNDAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIiwgIm5vbmUgKDAlKSIpKQ0KICAgICAgKSwNCiAgICAjZnJlZWluZyB1cCB0aGUgeCBzY2FsZXMgZG9lcyBub3Qgd29yayBmb3Igc29tZSByZWFzb24uLi4gc28gaSBzZXQgdGhlbSBtYW51YWxseToNCiAgICB4ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC40MCwuNjApLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgYWdlZCA1MCB5ZWFycyBvciBvbGRlciIgfiBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgICAgIGxpbWl0cyA9IGMoLjQ1LC42MCksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSwNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIgfiBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgICAgIGxpbWl0cyA9IGMoLjMwLC43MCksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKQ0KICAgICAgKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIyBzdHJpcC50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKCksDQogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikNCg0KI2NyZWF0ZSBhIGJsYW5rIHBsb3QgZm9yIGxlZ2VuZCBhbGlnbm1lbnQNCmJsYW5rX3AgPC0gcGxvdF9zcGFjZXIoKQ0KDQojY29tYmluZSBhbGwgaW4gb25lDQpwMyA8LSBwbG90X2dyaWQocDIsIGxlZzEyMywgYWxpZ24gPSAiaCIsIG5yb3c9MiwgcmVsX2hlaWdodHMgPSBjKDQsMSkpDQpwbG90KHAzKQ0KYGBgDQoNCg0KIyMjIyByZXN0cmljdCBzYW1wbGUgdG8gcmVzZW1ibGUgdGhhdCBvZiBleHBlcmltZW50IDMNCg0KIyMjIyMgc3BvcnRzIGNsdWJzIHZzLiBvdGhlciBvcmdhbml6YXRpb24gdHlwZXMNCiAgDQpXZSByZWRvIHRoZSBvcmdhbml6YXRpb24gY2hvaWNlIGFuYWx5c2VzLCBpbmNsdWRpbmcgb25seSBwZW9wbGUgd2hvc2UgKG1vc3QgaW1wb3J0YW50KSBvcmdhbml6YXRpb24gaXMgYSBzcG9ydHMgY2x1YnMgKHZlcnN1cyBvdGhlciBvcmdhbmlzYXRpb25zKS4NCg0KYGBge3IsIGNtbXNfc3BvcnQsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnLCBmaWcud2lkdGg9MTJ9IA0KZGZzcG9ydHMgPC0gZGZbZGYkb2Npdl9tb3N0aW1wX3R5cGUgPT0gIlNwb3J0cyIsIF0NCmRmbm9uc3BvcnRzIDwtIGRmWyFkZiRvY2l2X21vc3RpbXBfdHlwZSA9PSAiU3BvcnRzIixdDQoNCiNzcG9ydHMgb3JnDQpjbW1lZHVjc3BvcnQgPC0gY3JlZ2c6OmNqKGRmc3BvcnRzWyFpcy5uYShkZnNwb3J0cyRUZXJ0KSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfZWR1YywgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VGVydCkNCmNtbWFnZXNwb3J0IDwtIGNyZWdnOjpjaihkZnNwb3J0c1shaXMubmEoZGZzcG9ydHMkQWdlKSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfYWdlLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5BZ2UpDQpjbW1ldGhzcG9ydCA8LSBjcmVnZzo6Y2ooZGZzcG9ydHNbIWlzLm5hKGRmc3BvcnRzJFRNKSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfZXRoLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5UTSkNCg0KI25vbiBzcG9ydHMgb3JnDQpjbW1lZHVjbm9zcG9ydCA8LSBjcmVnZzo6Y2ooZGZub25zcG9ydHNbIWlzLm5hKGRmbm9uc3BvcnRzJFRlcnQpLCBdLCBlY2l2X2Nob2ljZSB+IGVjaXZfY29tcF9lZHVjLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5UZXJ0KQ0KY21tYWdlbm9zcG9ydCA8LSBjcmVnZzo6Y2ooZGZub25zcG9ydHNbIWlzLm5hKGRmbm9uc3BvcnRzJEFnZSksIF0sIGVjaXZfY2hvaWNlIH4gZWNpdl9jb21wX2FnZSwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+QWdlKQ0KY21tZXRobm9zcG9ydCA8LSBjcmVnZzo6Y2ooZGZub25zcG9ydHNbIWlzLm5hKGRmbm9uc3BvcnRzJFRNKSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfZXRoLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5UTSkNCg0KY21tZWR1Y3Nwb3J0JE91dGNvbWUgPC0gY21tYWdlc3BvcnQkT3V0Y29tZSA8LSBjbW1ldGhzcG9ydCRPdXRjb21lIDwtICJTcG9ydHMgY2x1YnMiDQpjbW1lZHVjbm9zcG9ydCRPdXRjb21lIDwtIGNtbWFnZW5vc3BvcnQkT3V0Y29tZSA8LSBjbW1ldGhub3Nwb3J0JE91dGNvbWUgPC0gIk90aGVyIHR5cGVzIG9mIG9yZ2FuaXphdGlvbnMiDQoNCiNyb3diaW5kIHRoZSBkYXRhZnJhbWVzDQptbXNfIDwtIHJiaW5kKGNtbWVkdWNzcG9ydFssLTEyXSxjbW1lZHVjbm9zcG9ydFssLTEyXSxjbW1hZ2VzcG9ydFssLTEyXSxjbW1hZ2Vub3Nwb3J0WywtMTJdLGNtbWV0aHNwb3J0WywtMTJdLGNtbWV0aG5vc3BvcnRbLC0xMl0pDQoNCiNyZW5hbWUvcmVvcmRlciBsYWJlbHMNCm1tc18kT3V0Y29tZSA8LSBmYWN0b3IobW1zXyRPdXRjb21lLCBsZXZlbHMgPSBjKCJTcG9ydHMgY2x1YnMiLCAiT3RoZXIgdHlwZXMgb2Ygb3JnYW5pemF0aW9ucyIpKQ0KbW1zXyRGZWF0dXJlIDwtIGZhY3RvcihzdWIoIi4qXyIsICIiLCBtbXNfJGZlYXR1cmUpLCANCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJhZ2UiLCAiZXRoIiwgImVkdWMiKSwNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJTaGFyZSBvZiBwZW9wbGUgYWdlZCA1MCB5ZWFycyBvciBvbGRlciIsICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiLCAgIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiKSkNCg0KbW1zXyRTdWJncm91cCA8LSBtbXNfJEJZDQptbXNfJFN1Ymdyb3VwIDwtIGZhY3RvcihtbXNfJFN1Ymdyb3VwLCBsZXZlbHMgPSBjKCI1MCB5ZWFycyBvciBvbGRlciIsICJCZWxvdyA1MCB5ZWFycyIsICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiICwgIldpdGggY29sbGVnZSBkZWdyZWUiLCJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiAgKSkgDQoNCnA0IDwtIHBsb3QobW1zXywgdmxpbmU9MS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIlN1Ymdyb3VwIiwgeGxhYiA9ICJNYXJnaW5hbCBtZWFuIikgKw0KICBmYWNldF9ncmlkMiggT3V0Y29tZSB+IEZlYXR1cmUsIHNjYWxlcyA9ICJmcmVlIiwgaW5kZXBlbmRlbnQgPSAieSIsIHN3aXRjaCA9ICJ5IikgKw0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlKSArDQogIGxhYnModGl0bGUgPSAiU3BvcnRzIGNsdWJzIHZzLiBvdGhlciB0eXBlcyBvZiBvcmdhbml6YXRpb25zIikgKw0KICBmYWNldHRlZF9wb3Nfc2NhbGVzKA0KICAgIHkgPSBsaXN0KA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJ0aHJlZSBxdWFydGVycyAoNzUlKSIsICJoYWxmICg1MCUpIiwgImEgcXVhcnRlciAoMjUlKSIpKSwNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoImhhbGYgKDUwJSkiLCAianVzdCB1bmRlciBoYWxmICg0MCUpIiwgImEgcXVhcnRlciAoMjUlKSIpKSwNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJhIHF1YXJ0ZXIgKDI1JSkiLCAibWlub3JpdHkgKDEwJSkiLCAibm9uZSAoMCUpIikpDQogICAgKSwNCiAgICAjZnJlZWluZyB1cCB0aGUgeCBzY2FsZXMgZG9lcyBub3Qgd29yayBmb3Igc29tZSByZWFzb24uLi4gc28gaSBzZXQgdGhlbSBtYW51YWxseToNCiAgICB4ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC40LC42MCksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSwNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIiB+IHNjYWxlX3hfY29udGludW91cygNCiAgICAgICAgbGltaXRzID0gYyguNDMsLjYwKSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggVHVyay9Nb3JvYyBiYWNrZ3JvdW5kIiB+IHNjYWxlX3hfY29udGludW91cygNCiAgICAgICAgbGltaXRzID0gYyguMzAsLjcwKSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpDQogICAgKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICNzdHJpcC50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKCksDQogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikNCg0KcDUgPC0gcGxvdF9ncmlkKHA0LCBsZWcxMjMsIGFsaWduID0gImgiLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYyg3LDEpKQ0KcHJpbnQocDUpDQoNCiNnZ3NhdmUocDUsIGZpbGUgPSAnLi9maWd1cmVzL2ZpZ3VyZTAyX3Nwb3J0c192ZXJzdXNfb3RoZXIucG5nJywgaGVpZ2h0ID0gNywgd2lkdGggPSAxMi41KQ0KYGBgIA0KDQoNCiMjIyMjIG9ubHkgcmVzcG9uZGVudHMgd2l0aGluIFRSSUFMIGFnZSByYW5nZQ0KDQpXZSByZWRvIHRoZSBhbmFseXNlcywgbm93IGluY2x1ZGluZyBvbmx5IHJlc3BvbmRlbnRzIHdpdGhpbiB0aGUgVFJJQUwgKGV4cGVyaW1lbnQgMykgYWdlIHJhbmdlOg0KDQpgYGB7ciwgY21tc19hZ2VjYXAsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD04fSANCmFnZWNhcG1pbiA8LSBtaW4oZGYyJExFRUZUSUpEKSAjMTgNCmFnZWNhcG1heCA8LSBtYXgoZGYyJExFRUZUSUpEKSAjNDENCg0KI3Byb3AudGFibGUodGFibGUoZGYkYWdlX2NvbnRpbnVvdXMpKSAjcmVsYXRpdmVseSBtYW55ICdvbGRlcicgcmVzcG9uZGVudHMNCiNzdW0ocHJvcC50YWJsZSh0YWJsZShkZiRhZ2VfY29udGludW91cykpWzM6MjZdKSAjMjIlIGZhbGxzIHdpdGhpbiBUUklBTCByYW5nZQ0KDQpkZmFnZWNhcCA8LSBkZltkZiRhZ2VfY29udGludW91cyA+PSBhZ2VjYXBtaW4gJiBkZiRhZ2VfY29udGludW91cyA8PSBhZ2VjYXBtYXgsIF0NCiNsZW5ndGgodW5pcXVlKGRmJG5vbWVtX2VuY3IpKSAjMjc2MSByZXNwb25kZW50cw0KI2xlbmd0aCh1bmlxdWUoZGZhZ2VjYXAkbm9tZW1fZW5jcikpICM2MDQgd2l0aGluIFRSSUFMIGFnZS1yYW5nZQ0KDQojYWxzbyAnaW5jcmVtZW50JyByZXN0cmljdGlvbnMgKHNwb3J0cyBjbHVicyBvbmx5OyByZXN0cmljdGVkIGFnZSByYW5nZSkNCmRmc3BvcnRzYWdlY2FwIDwtIGRmc3BvcnRzW2Rmc3BvcnRzJGFnZV9jb250aW51b3VzID49IGFnZWNhcG1pbiAmIGRmc3BvcnRzJGFnZV9jb250aW51b3VzIDw9IGFnZWNhcG1heCwgXQ0KZGZub25zcG9ydHNhZ2VjYXAgPC0gZGZub25zcG9ydHNbZGZub25zcG9ydHMkYWdlX2NvbnRpbnVvdXMgPj0gYWdlY2FwbWluICYgZGZub25zcG9ydHMkYWdlX2NvbnRpbnVvdXMgPD0gYWdlY2FwbWF4LCBdDQoNCiNyZWRvIHRoZSBhbmFseXNlczsgbmF0dXJhbGx5IG5vdyB3ZSBkb24ndCBlc3RpbWF0ZSBzdWJncm91cCBkaWZmZXJlbmNlcyBpbiB0aGUgYWdlIGNvbXBvc2l0aW9uIGRpbWVuc2lvbnM7IGFzIGluIG91ciBzdWJzZXQgb2YgcmVzcG9uZGVudHMsIGFsbCByZXNwb25kZW50cyBhcmUgeW91bmdlciB0aGFuIDUwIHkvby4NCg0KI2NvbmRpdGlvbmFsIG1hcmdpbmFsIG1lYW5zIChjb21wb3NpdGlvbiBkaW1lbnNpb247IGRpc2FnZ3JlZ2F0ZWQgYnkgcmVzcG9uZGVudCB2YWx1ZSBmb3IgdGhpcyBkaW1lbnNpb24pDQojMS4gbmJoDQpubW1lZHVjIDwtIGNyZWdnOjpjaihkZmFnZWNhcFshaXMubmEoZGZhZ2VjYXAkVGVydCksIF0sIGVuYmhfY2hvaWNlIH4gZW5iaF9jb21wX2VkdWMsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflRlcnQpDQpubW1ldGggPC0gY3JlZ2c6OmNqKGRmYWdlY2FwWyFpcy5uYShkZmFnZWNhcCRUTSksIF0sIGVuYmhfY2hvaWNlIH4gZW5iaF9jb21wX2V0aCwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VE0pDQoNCiMyLiBvcmcgKHNwb3J0KQ0Kc21tZWR1YyA8LSBjcmVnZzo6Y2ooZGZzcG9ydHNhZ2VjYXBbIWlzLm5hKGRmc3BvcnRzYWdlY2FwJFRlcnQpLCBdLCBlY2l2X2Nob2ljZSB+IGVjaXZfY29tcF9lZHVjLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5UZXJ0KQ0Kc21tZXRoIDwtIGNyZWdnOjpjaihkZnNwb3J0c2FnZWNhcFshaXMubmEoZGZzcG9ydHNhZ2VjYXAkVE0pLCBdLCBlY2l2X2Nob2ljZSB+IGVjaXZfY29tcF9ldGgsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflRNKQ0KDQojMy4gb3JnIChubyBzcG9ydCkNCmNtbWVkdWMgPC0gY3JlZ2c6OmNqKGRmbm9uc3BvcnRzYWdlY2FwWyFpcy5uYShkZm5vbnNwb3J0c2FnZWNhcCRUZXJ0KSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfZWR1YywgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VGVydCkNCmNtbWV0aCA8LSBjcmVnZzo6Y2ooZGZub25zcG9ydHNhZ2VjYXBbIWlzLm5hKGRmbm9uc3BvcnRzYWdlY2FwJFRNKSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfZXRoLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5UTSkNCg0KI3Jvd2JpbmQgdGhlIGRhdGFmcmFtZXMNCiNsZWF2ZSBvdXQgbGFzdCBjb2x1bW4sIHJlZmxlY3RpbmcgdGhlIHN1Ymdyb3VwaW5nIHZhcmlhYmxlDQptbXNfIDwtIHJiaW5kKG5tbWV0aFstMTJdLG5tbWVkdWNbLTEyXSwNCiAgICAgICAgICAgICAgc21tZXRoWy0xMl0sc21tZWR1Y1stMTJdLA0KICAgICAgICAgICAgIGNtbWV0aFstMTJdLGNtbWVkdWNbLTEyXSkNCiNyZW5hbWUgbGFiZWxzDQojMS4gb2Ygb3V0Y29tZSAoc2V0dGluZykNCm1tc18kT3V0Y29tZSA8LSBmYWN0b3IoYyhyZXAoIk5laWdoYm9yaG9vZHMiLCA2KSwgcmVwKCJTcG9ydHMgY2x1YnMiLCA2KSwgcmVwKCJPdGhlciB0eXBlcyBvZiBvcmdhbml6YXRpb25zIiwgNikpLCBsZXZlbHMgPSBjKCJOZWlnaGJvcmhvb2RzIiwgIlNwb3J0cyBjbHVicyIsICJPdGhlciB0eXBlcyBvZiBvcmdhbml6YXRpb25zIikpDQoNCiMyLiBvZiAoZGVtb2dyYXBoaWMgY29tcG9zaXRpb24pIGZlYXR1cmVzDQptbXNfJEZlYXR1cmUgPC0gZmFjdG9yKHN1YigiLipfIiwgIiIsIG1tc18kZmVhdHVyZSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiZXRoIiwgImVkdWMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlNoYXJlIG9mIHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIsICAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIpKQ0KDQptbXNfJFN1Ymdyb3VwIDwtIG1tc18kQlkNCm1tc18kU3ViZ3JvdXAgPC0gZmFjdG9yKG1tc18kU3ViZ3JvdXAsIGxldmVscyA9IGMoIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICAgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiAsICJXaXRoIGNvbGxlZ2UgZGVncmVlIiwiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIgICkpIA0KDQojb25seSBmb2N1cyBvbiBldGggZGltZW5zaW9ucw0KbW1zXzIgPC0gbW1zX1ttbXNfJGZlYXR1cmUgJWluJSBjKCJlbmJoX2NvbXBfZXRoIiwgImVjaXZfY29tcF9ldGgiKSxdDQojYW5kIGxlYXZlIG91dCBuYmgNCm1tc18yIDwtIG1tc18yW21tc18yJG91dGNvbWUgPT0gImVjaXZfY2hvaWNlIixdDQoNCg0KcDIgPC0gcGxvdChtbXNfMiwgdmxpbmU9MS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIlN1Ymdyb3VwIiwgeGxhYiA9ICJNYXJnaW5hbCBtZWFuIikgKw0KICBmYWNldF9ncmlkMiggT3V0Y29tZSB+IEZlYXR1cmUsIHNjYWxlcyA9ICJmcmVlIiwgaW5kZXBlbmRlbnQgPSAieSIsIHN3aXRjaCA9ICJ5IikgKw0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlWzM6Nl0pICsNCiAgI2xhYnModGl0bGUgPSAiTmVpZ2hib3Job29kcywgc3BvcnRzIGNsdWJzIHZzLiBvdGhlciB0eXBlcyBvZiBvcmdhbml6YXRpb25zOiByZXN0cmljdGVkIHRvIHRoZSBUUklBTCBhZ2UgcmFuZ2UgKDE4LTQxIHllYXJzKSIpICsNCiAgZmFjZXR0ZWRfcG9zX3NjYWxlcygNCiAgICB5ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygidGhyZWUgcXVhcnRlcnMgKDc1JSkiLCAiaGFsZiAoNTAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIiwgIm5vbmUgKDAlKSIpKQ0KICAgICAgKSwNCiAgICAjZnJlZWluZyB1cCB0aGUgeCBzY2FsZXMgZG9lcyBub3Qgd29yayBmb3Igc29tZSByZWFzb24uLi4gc28gaSBzZXQgdGhlbSBtYW51YWxseToNCiAgICB4ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC40MCwuNjApLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC4zMCwuNzApLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkNCiAgICAgICkpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICMgc3RyaXAudGV4dC54ID0gZWxlbWVudF9tYXJrZG93bigpLA0KICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpDQogDQojY29tYmluZSBsZWdlbmRzDQojbGVnX2FnZSA8LSBwbG90X2dyaWQobGVnMixsZWczLCBucm93PTEsIGFsaWduPSJoIikNCg0KI2NyZWF0ZSBhIGJsYW5rIHBsb3QgZm9yIGxlZ2VuZCBhbGlnbm1lbnQNCmJsYW5rX3AgPC0gcGxvdF9zcGFjZXIoKQ0KDQojY29tYmluZSBhbGwgaW4gb25lDQpwMyA8LSBwbG90X2dyaWQocDIsIGxlZzIsIGFsaWduID0gImgiLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYyg3LDEpKQ0KcGxvdChwMykNCg0KI2dnc2F2ZSgiLi9maWd1cmVzL2ZpZ3VyZVM0ZC5wbmciLCBwMywgd2lkdGg9NiwgaGVpZ2h0PTYpDQpgYGAgDQoNCg0KIyMjIyBtb3JlIGZpbmUtZ3JhaW5lZCBzdWJncm91cHMNCg0KIyMjIyMgcmVzZWFyY2ggdW5pdmVyc2l0eSB2cy4gdW5pdmVyc2l0eSBvZiBhcHBsaWVkIHNjaWVuY2UNCg0KYGBge3IsIGNtbXNfdGVydCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZScsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9DQojY3JlYXRlIHN1Ymdyb3Vwcw0KZGYkVW5pIDwtIE5BX3JlYWxfDQpkZiRVbmlbZGYkZWR1X3VuaWhibyA9PSAicmVzZWFyY2ggdW5pdmVyc2l0eSJdIDwtIDFMDQpkZiRVbmlbZGYkZWR1X3VuaWhibyA9PSAidW5pdmVyc2l0eSBvZiBhcHBsaWVkIHNjaWVuY2VzIl0gPC0gMkwNCmRmJFVuaSA8LSBmYWN0b3IoZGYkVW5pLCAxOjIsIGMoIlJlc2VhcmNoIHVuaXZlcnNpdHkiLCAiVW5pdmVyc2l0eSBvZiBhcHBsaWVkIHNjaWVuY2VzIikpDQoNCiNvdXRjb21lIGFuZCBjb25qb2ludCBmZWF0dXJlcywgaW5jbHVkaW5nIG9ubHkgY29tcG9zaXRpb24gZmVhdHVyZXMgd2UgYXJlIGludGVyZXN0ZWQgaW47DQojYW5kIHRoZSBzdWJncm91cGluZyB2YXJpYWJsZQ0KDQojY29uZGl0aW9uYWwgbWFyZ2luYWwgbWVhbnMgKGNvbXBvc2l0aW9uIGRpbWVuc2lvbjsgZGlzYWdncmVnYXRlZCBieSByZXNwb25kZW50IHZhbHVlIGZvciB0aGlzIGRpbWVuc2lvbikNCiMxLiBuYmgNCm5tbWV0aCA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJFVuaSksIF0sIGVuYmhfY2hvaWNlIH4gZW5iaF9jb21wX2V0aCwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VW5pKQ0Kbm1tZWR1YyA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJFVuaSksIF0sIGVuYmhfY2hvaWNlIH4gZW5iaF9jb21wX2VkdWMsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflVuaSkNCg0KIzIuIG9yZw0KY21tZXRoIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkVW5pKSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfZXRoLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5VbmkpDQpjbW1lZHVjIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkVW5pKSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfZWR1YywgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VW5pKQ0KDQojcm93YmluZCB0aGUgZGF0YWZyYW1lcw0KI2xlYXZlIG91dCBsYXN0IGNvbHVtbiwgcmVmbGVjdGluZyB0aGUgc3ViZ3JvdXBpbmcgdmFyaWFibGUNCm1tc18gPC0gcmJpbmQobm1tZXRoWy0xMl0sIG5tbWVkdWNbLTEyXSwgY21tZXRoWy0xMl0sIGNtbWVkdWNbLTEyXSkNCg0KI3JlbmFtZSBsYWJlbHMNCiMxLiBvZiBvdXRjb21lIChzZXR0aW5nKQ0KbW1zXyRPdXRjb21lIDwtIGZhY3RvcihpZmVsc2UobW1zXyRvdXRjb21lID09ICJlY2l2X2Nob2ljZSIsICJDaXZpYyBvcmdhbml6YXRpb25zIiwgIk5laWdoYm9yaG9vZHMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiTmVpZ2hib3Job29kcyIsICJDaXZpYyBvcmdhbml6YXRpb25zIikpDQoNCiMyLiBvZiAoZGVtb2dyYXBoaWMgY29tcG9zaXRpb24pIGZlYXR1cmVzDQptbXNfJEZlYXR1cmUgPC0gZmFjdG9yKHN1YigiLipfIiwgIiIsIG1tc18kZmVhdHVyZSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiZXRoIiwgImVkdWMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlNoYXJlIG9mIHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIsICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIikpDQptbXNfJFN1Ymdyb3VwIDwtIG1tc18kQlkNCm1tc18kU3ViZ3JvdXAgPC0gZmFjdG9yKG1tc18kU3ViZ3JvdXAsIGxldmVscyA9IGMoIlJlc2VhcmNoIHVuaXZlcnNpdHkiLCAiVW5pdmVyc2l0eSBvZiBhcHBsaWVkIHNjaWVuY2VzIikpIA0KDQpwIDwtIHBsb3QobW1zXywgdmxpbmU9MS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIlN1Ymdyb3VwIiwgeGxhYiA9ICJNYXJnaW5hbCBtZWFuIikgKw0KICBmYWNldF9ncmlkMiggT3V0Y29tZSB+IEZlYXR1cmUsIHNjYWxlcyA9ICJmcmVlIiwgaW5kZXBlbmRlbnQgPSAieSIsIHN3aXRjaCA9ICJ5IikgKw0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoNTo2KV0pICsNCiAgZmFjZXR0ZWRfcG9zX3NjYWxlcygNCiAgICAgeSA9IGxpc3QoDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoInRocmVlIHF1YXJ0ZXJzICg3NSUpIiwgImhhbGYgKDUwJSkiLCAiYSBxdWFydGVyICgyNSUpIikpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggVHVyay9Nb3JvYyBiYWNrZ3JvdW5kIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoImEgcXVhcnRlciAoMjUlKSIsICJtaW5vcml0eSAoMTAlKSIsICJub25lICgwJSkiKSkNCiAgICAgICksDQogICAgI2ZyZWVpbmcgdXAgdGhlIHggc2NhbGVzIGRvZXMgbm90IHdvcmsgZm9yIHNvbWUgcmVhc29uLi4uIHNvIGkgc2V0IHRoZW0gbWFudWFsbHk6DQogICAgeCA9IGxpc3QoDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiB+IHNjYWxlX3hfY29udGludW91cygNCiAgICAgICAgbGltaXRzID0gYyguNDAsLjYwKSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggVHVyay9Nb3JvYyBiYWNrZ3JvdW5kIiB+IHNjYWxlX3hfY29udGludW91cygNCiAgICAgICAgbGltaXRzID0gYyguMzAsLjcwKSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpDQogICAgICApKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAjIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfbWFya2Rvd24oKSwNCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQ0KDQojc3BsaXQgbGVnZW5kIGludG8gbXVsdGlwbGUgcGFydHMNCnNwbGl0MSA8LSBtbXNfW21tc18kU3ViZ3JvdXAgJWluJSBjKCJSZXNlYXJjaCB1bml2ZXJzaXR5IiwgIlVuaXZlcnNpdHkgb2YgYXBwbGllZCBzY2llbmNlcyIpLCBdDQoNCiNyZXZlcnNlIG9yZGVyIGZhY3Rvci4uLi4gYnVnIGluIGdncGxvdDIgbWFrZXMgdGhlIG9yZGVyIG9mIHRoZSBzdWJncm91cHMgaW4gdGhlIHBsb3QgYW5kIHRoZSBsZWdlbmQgcmV2ZXJzZWQNCnNwbGl0MSRTdWJncm91cCA8LSBmYWN0b3Ioc3BsaXQxJFN1Ymdyb3VwLCBsZXZlbHMgPSByZXYobGV2ZWxzKHNwbGl0MSRTdWJncm91cCkpKQ0KDQojcGxvdCBsZWdlbmRzDQpzcGxpdDFwIDwtIGdncGxvdChzcGxpdDEsIGFlcyh4ID0gZXN0aW1hdGUsIHkgPSBsZXZlbCwgY29sb3I9U3ViZ3JvdXApKSArIGdlb21fcG9pbnQoKSArIGxhYnMoY29sb3IgPSAiUmVzcG9uZGVudCBzdWJncm91cHM6IikgKyB0aGVtZV9idygpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZVtjKDYsNSldKQ0KDQojZ2V0IGxlZ2VuZHMNCmxlZ191bmkgPC0gZ2V0X2xlZ2VuZChzcGxpdDFwKQ0KDQojY3JlYXRlIGEgYmxhbmsgcGxvdCBmb3IgbGVnZW5kIGFsaWdubWVudA0KYmxhbmtfcCA8LSBwbG90X3NwYWNlcigpDQoNCiNjb21iaW5lIGFsbCBpbiBvbmUNCnAgPC0gcGxvdF9ncmlkKHAsIGxlZ191bmksIGFsaWduID0gImgiLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYyg3LDIpKQ0KcGxvdChwKQ0KYGBgIA0KDQoNCiMjIyMjIG1vcmUgYWdlIGdyb3Vwcw0KDQpgYGB7ciwgY21tc19hZ2Vncm91cHMsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD02fSANCiNjcmVhdGUgc3ViZ3JvdXBzDQpkZiRBZ2VHIDwtIE5BX3JlYWxfDQpkZiRBZ2VHW2RmJGFnZV9jb250aW51b3VzID4gNjRdIDwtIDFMDQpkZiRBZ2VHW2RmJGFnZV9jb250aW51b3VzID4gNDkgJiBkZiRhZ2VfY29udGludW91cyA8IDY1XSA8LSAyTA0KZGYkQWdlR1tkZiRhZ2VfY29udGludW91cyA+IDM0ICYgZGYkYWdlX2NvbnRpbnVvdXMgPCA1MF0gPC0gM0wNCmRmJEFnZUdbZGYkYWdlX2NvbnRpbnVvdXMgPiAxNyAmIGRmJGFnZV9jb250aW51b3VzIDwgMzVdIDwtIDRMDQoNCmRmJEFnZUcgPC0gZmFjdG9yKGRmJEFnZUcsIDE6NCwgYygiNjUrIHllYXJzIG9sZCIsICJCZXR3ZWVuIDUwLTY1IiwgIkJldHdlZW4gMzUtNTAiLCAiQmV0d2VlbiAxOC0zNSIpKQ0KDQojMS4gbmJoDQpubW1hZ2UgPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRBZ2VHKSwgXSwgZW5iaF9jaG9pY2UgfiBlbmJoX2NvbXBfYWdlLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5BZ2VHKQ0KIzIuIG9yZw0KY21tYWdlIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkQWdlRyksIF0sIGVjaXZfY2hvaWNlIH4gZWNpdl9jb21wX2FnZSwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+QWdlRykNCg0KI3Jvd2JpbmQgdGhlIGRhdGFmcmFtZXMNCiNsZWF2ZSBvdXQgbGFzdCBjb2x1bW4sIHJlZmxlY3RpbmcgdGhlIHN1Ymdyb3VwaW5nIHZhcmlhYmxlDQptbXNfIDwtIHJiaW5kKG5tbWFnZVstMTJdLA0KICAgICAgICAgICAgIGNtbWFnZVstMTJdKQ0KDQojcmVuYW1lIGxhYmVscw0KIzEuIG9mIG91dGNvbWUgKHNldHRpbmcpDQptbXNfJE91dGNvbWUgPC0gZmFjdG9yKGlmZWxzZShtbXNfJG91dGNvbWUgPT0gImVjaXZfY2hvaWNlIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiLCAiTmVpZ2hib3Job29kcyIpLA0KICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJOZWlnaGJvcmhvb2RzIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiKSkNCg0KIzIuIG9mIChkZW1vZ3JhcGhpYyBjb21wb3NpdGlvbikgZmVhdHVyZXMNCm1tc18kRmVhdHVyZSA8LSBmYWN0b3Ioc3ViKCIuKl8iLCAiIiwgbW1zXyRmZWF0dXJlKSwgDQogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJhZ2UiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlNoYXJlIG9mIHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIikpDQoNCm1tc18kU3ViZ3JvdXAgPC0gbW1zXyRCWQ0KbW1zXyRTdWJncm91cCA8LSBmYWN0b3IobW1zXyRTdWJncm91cCwgbGV2ZWxzID0gYygiNjUrIHllYXJzIG9sZCIsICJCZXR3ZWVuIDUwLTY1IiwgIkJldHdlZW4gMzUtNTAiLCAiQmV0d2VlbiAxOC0zNSIpKSANCg0KcCA8LSBwbG90KG1tc18sIHZsaW5lPTEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJTdWJncm91cCIsIHhsYWIgPSAiTWFyZ2luYWwgbWVhbiIpICsNCiAgZmFjZXRfZ3JpZDIoIE91dGNvbWUgfiBGZWF0dXJlLCBzY2FsZXMgPSAiZnJlZSIsIGluZGVwZW5kZW50ID0gInkiLCBzd2l0Y2ggPSAieSIpICsNCiAgZ2VvbV90ZXh0KCBhZXMobGFiZWwgPSBzcHJpbnRmKCIlMC4yZiAoJTAuMmYpIiwgZXN0aW1hdGUsIHN0ZC5lcnJvcikpLCBzaXplID0gMywgY29sb3VyID0gImJsYWNrIiwgdmp1c3QgPSAtMSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJhaW5ib3coNCkpICsNCiAgZmFjZXR0ZWRfcG9zX3NjYWxlcygNCiAgICB5ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoImhhbGYgKDUwJSkiLCAianVzdCB1bmRlciBoYWxmICg0MCUpIiwgImEgcXVhcnRlciAoMjUlKSIpKQ0KICAgICAgKSwNCiAgICAjZnJlZWluZyB1cCB0aGUgeCBzY2FsZXMgZG9lcyBub3Qgd29yayBmb3Igc29tZSByZWFzb24uLi4gc28gaSBzZXQgdGhlbSBtYW51YWxseToNCiAgICB4ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIiB+IHNjYWxlX3hfY29udGludW91cygNCiAgICAgICAgbGltaXRzID0gYyguNDAsLjYwKSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpDQogICAgICApKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAjIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfbWFya2Rvd24oKSwNCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQ0KDQojc3BsaXQgbGVnZW5kIGludG8gbXVsdGlwbGUgcGFydHMNCnNwbGl0MSA8LSBtbXNfW21tc18kU3ViZ3JvdXAgJWluJSBjKCI2NSsgeWVhcnMgb2xkIiwgIkJldHdlZW4gNTAtNjUiLCAiQmV0d2VlbiAzNS01MCIsICJCZXR3ZWVuIDE4LTM1IiksIF0NCg0KI3JldmVyc2Ugb3JkZXIgZmFjdG9yLi4uLiBidWcgaW4gZ2dwbG90MiBtYWtlcyB0aGUgb3JkZXIgb2YgdGhlIHN1Ymdyb3VwcyBpbiB0aGUgcGxvdCBhbmQgdGhlIGxlZ2VuZCByZXZlcnNlZA0Kc3BsaXQxJFN1Ymdyb3VwIDwtIGZhY3RvcihzcGxpdDEkU3ViZ3JvdXAsIGxldmVscyA9IHJldihsZXZlbHMoc3BsaXQxJFN1Ymdyb3VwKSkpDQoNCiNwbG90IGxlZ2VuZHMNCnNwbGl0MXAgPC0gZ2dwbG90KHNwbGl0MSwgYWVzKHggPSBlc3RpbWF0ZSwgeSA9IGxldmVsLCBjb2xvcj1TdWJncm91cCkpICsgZ2VvbV9wb2ludCgpICsgbGFicyhjb2xvciA9ICJSZXNwb25kZW50IHN1Ymdyb3VwczoiKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcmV2KHJhaW5ib3coNCkpKSANCg0KI2dldCBsZWdlbmRzDQpsZWdfYWdlIDwtIGdldF9sZWdlbmQoc3BsaXQxcCkNCg0KI2NyZWF0ZSBhIGJsYW5rIHBsb3QgZm9yIGxlZ2VuZCBhbGlnbm1lbnQNCmJsYW5rX3AgPC0gcGxvdF9zcGFjZXIoKQ0KDQojY29tYmluZSBhbGwgaW4gb25lDQpwIDwtIHBsb3RfZ3JpZChwLCBsZWdfYWdlLCBhbGlnbiA9ICJoIiwgbnJvdz0yLCByZWxfaGVpZ2h0cyA9IGMoNywyKSkNCnBsb3QocCkNCmBgYCANCg0KDQotLS0NCg0KIyMgY29udHJvbGxpbmcgZm9yIG1lYXN1cmVtZW50IGVycm9yDQoNCk91ciBkZXNpZ24gaW5jbHVkZWQgYSBmaWZ0aCBjaG9pY2UgdGFzayBmb3Igb25lIG9mIHRoZSBleHBlcmltZW50cyB0aGF0IGlzIGlkZW50aWNhbCB0byByZXNwb25kZW50c+KAmSBmaXJzdCBjaG9pY2UgdGFzayBleGNlcHQgZm9yIHN3aXRjaGluZyBhcm91bmQgb3JnYW5pemF0aW9uIC8gbmVpZ2hib3Job29kIDEgYW5kIG9yZ2FuaXphdGlvbiAvIG5laWdoYm9yaG9vZCAyLiBXaGV0aGVyIHJlc3BvbmRlbnRzIHJlY2VpdmUgc3VjaCBhbiBhZGRpdGlvbmFsIGNob2ljZSB0YXNrIGZvciB0aGUgY2l2aWMgb3IgbmVpZ2hib3Job29kIGV4cGVyaW1lbnQgd2FzIHJhbmRvbWx5IGRldGVybWluZWQsIHdpdGggaGFsZiBvZiB0aGUgc2FtcGxlIHJlY2VpdmluZyBhbiBhZGRpdGlvbmFsIHRhc2sgZm9yIGVhY2ggZXhwZXJpbWVudC4NCg0KV2UgY2FsY3VsYXRlIHRoZSBwcm9wb3J0aW9uIG9mIHNhbWUgcmVzcG9uc2VzIGFjcm9zcyB0aGUgZmlyc3QgYW5kIGZpZnRoIGNob2ljZSB0YXNrcyAoYnkgc3ViZ3JvdXApLCBhbmQgd2UgY29tcHV0ZSB0aGUgKHN1Ymdyb3VwKSBzd2FwcGluZyBlcnJvciBbQENsYXl0b24yMDIzXS4NCg0KYGBge3IsIHN3YXBwaW5nfQ0KIyBmdW5jdGlvbiB0byBjYWxjdWxhdGUgKHN1Ymdyb3VwKSBJUlINCmZfaXJyIDwtIGZ1bmN0aW9uKGRmKSB7DQogIGlycl9jZCA8LSAxIC0gbWVhbihkZiRyZXBjaG9pY2VbZGYkVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSJdLCBuYS5ybT1UUlVFKSAjY29sbGVnZSBkZWdyZWUNCiAgaXJyX25jZCA8LSAxIC0gbWVhbihkZiRyZXBjaG9pY2VbZGYkVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSJdLCBuYS5ybT1UUlVFKSAjbm8gY29sbGVnZSBkZWdyZWUNCiAgaXJyXzUwIDwtIDEgLSBtZWFuKGRmJHJlcGNob2ljZVtkZiRBZ2UgPT0gIjUwIHllYXJzIG9yIG9sZGVyIl0sIG5hLnJtPVRSVUUpICM1MCBwbHVzDQogIGlycl9uNTAgPC0gMSAtIG1lYW4oZGYkcmVwY2hvaWNlW2RmJEFnZSA9PSAiQmVsb3cgNTAgeWVhcnMiXSwgbmEucm09VFJVRSkgI3VuZGVyIDUwDQogIGlycl9kIDwtIDEgLSBtZWFuKGRmJHJlcGNob2ljZVtkZiRUTSA9PSAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiXSwgbmEucm09VFJVRSkgI2R1dGNoDQogIGlycl90bSA8LSAxIC0gbWVhbihkZiRyZXBjaG9pY2VbZGYkVE0gPT0gIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCJdLCBuYS5ybT1UUlVFKSAjdHVyay9tb3JvYw0KICANCiAgIHJldHVybihsaXN0KCJXaXRoIGNvbGxlZ2UgZGVncmVlIiA9IGlycl9jZCwgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUiID0gaXJyX25jZCwgIjUwIHllYXJzIG9yIG9sZGVyIiA9IGlycl81MCwgDQogICAgICAgICAgICAgICJCZWxvdyA1MCB5ZWFycyIgPSBpcnJfbjUwLCAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiID0gaXJyX2QsIA0KICAgICAgICAgICAgICAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiA9IGlycl90bSkpDQp9DQoNCiMgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHN3YXBwaW5nIGVycm9yDQpmX3RhdSA8LSBmdW5jdGlvbihpcnJfbGlzdCkgew0KICBzYXBwbHkoaXJyX2xpc3QsIGZ1bmN0aW9uKGlycikgKDEgLSBzcXJ0KDEgLSAyICogKDEgLSBpcnIpKSkgLyAyKQ0KfQ0KDQojZGVmaW5lIGRhdGEtc2V0cyBhbmQgKHJlcGVhdGVkKSBjaG9pY2UgdGFza3MNCmRhdGFzZXRzIDwtIGxpc3QoZGZbIWlzLm5hKGRmJHJlcF9vcmdfY2hvaWNlKSwgXSwgZGZbIWlzLm5hKGRmJHJlcF9uYmhfY2hvaWNlKSwgXSkNCnRhc2tzIDwtIGxpc3QoYygiZmlyc3Rfb3JnX2Nob2ljZSIsICJyZXBfb3JnX2Nob2ljZSIpLCBjKCJmaXJzdF9uYmhfY2hvaWNlIiwgInJlcF9uYmhfY2hvaWNlIikpDQpsYWJlbHMgPC0gYygib3JnYW5pemF0aW9ucyIsICJuZWlnaGJvcmhvb2RzIikNCg0KI3VzZSBhIGxvb3AgdG8gc3RvcmUgc3dhcHBpbmcgZXJyb3JzIHBlciBzdWJncm91cCwgZGlzYWdncmVnYXRlZCBieSBzZXR0aW5nIChvcmcvbmJoKQ0Kc3dhcHBpbmcgPC0gbGlzdCgpDQpmb3IgKGkgaW4gMTpsZW5ndGgoZGF0YXNldHMpKSB7DQogICNzZWxlY3QgZGF0YXNldA0KICBkYXRhc2V0IDwtIGRhdGFzZXRzW1tpXV0NCiAgDQogICNjaGVjayB3aGV0aGVyIHJlcGVhdGVkIGNob2ljZXRhc2tzIHdlcmUgYW5zd2VyZWQgdGhlIHNhbWUgYnkgdGhlIHJlc3BvbmRlbnQNCiAgZGF0YXNldCRyZXBjaG9pY2UgPC0gaWZlbHNlKGRhdGFzZXRbW3Rhc2tzW1tpXV1bMV1dXSA9PSBkYXRhc2V0W1t0YXNrc1tbaV1dWzJdXV0sIDEsIDApIA0KDQogICMgY2FsY3VsYXRlIElSUiAobm90ZSB0aGF0IHRoZSBvcHRpb25zL2FsdGVybmF0aXZlcyB3ZXJlIHJldmVyc2VkISB0aGF0J3Mgd2h5IHdlIHN1YnRyYWN0IHRoZSBJUlIgZnJvbSAxKQ0KICBpcnJfbGlzdCA8LSBmX2lycihkYXRhc2V0KQ0KDQogICMgY2FsY3VsYXRlIHRhdQ0KICB0YXVfbGlzdCA8LSBmX3RhdShpcnJfbGlzdCkNCiAgDQogICMgc3RvcmUgcmVzdWx0cyBpbiB0aGUgbGlzdA0KICBzd2FwcGluZ1tbbGFiZWxzW2ldXV0gPC0gbGlzdCgiaXJyIiA9IGlycl9saXN0LCAidGF1IiA9IHRhdV9saXN0KQ0KfQ0KDQojc3RvcmUgdGhpcywgYXMgd2UgbmVlZCBpdCBsYXRlcjoNCnN3YXBwaW5nTGlzdCA8LSBzd2FwcGluZw0KDQpwcmludChzd2FwcGluZykNCmBgYCANCg0KPGJyPg0KDQpJbiBsaW5lIHdpdGggcHJpb3Igc3R1ZGllcywgd2hlbiBmYWNlZCB3aXRoIHR3byBpZGVudGljYWwgY29uam9pbnQgdGFza3MsIHJlc3BvbmRlbnRzIGNob29zZSB0aGUgc2FtZSBwcm9maWxlIGFib3V0IDc1JSBvZiB0aGUgdGltZS4uLiBCdXQgd2UgZG8gc2VlIGRpZmZlcmVuY2VzIHBlciBzdWJncm91cCAoZXNwZWNpYWxseSByZXNwb25kZW50cyB3aXRoIGEgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIGhhdmUgdW5yZWxpYWJsZSBjaG9pY2UgYmVoYXZpb3IpLg0KDQpXZSBjYW4gbm93IGRlZmluZSBhIGJpYXMtY29udHJvbGxlZCBlc3RpbWF0b3IgZm9yIHRoZSBtYXJnaW5hbCBtZWFuIGFuZCBjb21wdXRlIHN0YW5kYXJkIGVycm9ycyB2aWEgKGJsb2NrKSBib290c3RyYXBwaW5nIFtAQ2FtZXJvbjIwMDhdLg0KDQpgYGB7ciwgY29yciwgZXZhbD1GQUxTRX0gDQojIG5lY2Vzc2FyeSBwYWNrYWdlcw0KbGlicmFyeShwYXJhbGxlbCkNCmxpYnJhcnkoYm9vdCkNCg0KI3NldC5zZWVkKDUyMjM1MjM1KSAjc2VlZCBmb3IgcmVwbGljYXRpb24NCg0KZmJvb3QgPC0gZnVuY3Rpb24oZGF0YSwgaSkgeyANCiAgIyBzYW1wbGUgcmVzcG9uZGVudCBJRHMgd2l0aCByZXBsYWNlbWVudA0KICBpZHMgPC0gc2FtcGxlKHVuaXF1ZShkYXRhJGlkKSwgbGVuZ3RoKHVuaXF1ZShkYXRhJGlkKSksIHJlcGxhY2UgPSBUUlVFKQ0KICANCiAgIyBjcmVhdGUgYSBuZXcgZGF0YXNldCBieSBpdGVyYXRpbmcgb3ZlciBlYWNoIHNhbXBsZWQgaWQgYW5kIGJpbmRpbmcgdGhlIG1hdGNoaW5nIHJvd3MNCiAgZCA8LSBtYXBfZGZyKGlkcywgfiBkYXRhICU+JSBmaWx0ZXIoaWQgPT0gLngpKSANCg0KICAjIG1ha2UgdHdvIGRhdGFzZXRzLCBmb3IgYm90aCBleHBlcmltZW50cw0KICBkYXRhc2V0cyA8LSBsaXN0KGRbIWlzLm5hKGQkcmVwX29yZ19jaG9pY2UpLCBdLCBkWyFpcy5uYShkJHJlcF9uYmhfY2hvaWNlKSwgXSkNCiAgDQogICMgZ2V0IHRoZSByZXBlYXRlZCB0YXNrcyBpbiBib3RoIGV4cGVyaW1lbnRzDQogIHRhc2tzIDwtIGxpc3QoYygiZmlyc3Rfb3JnX2Nob2ljZSIsICJyZXBfb3JnX2Nob2ljZSIpLCBjKCJmaXJzdF9uYmhfY2hvaWNlIiwgInJlcF9uYmhfY2hvaWNlIikpDQogIA0KICAjIGxhYmVsIHRoZSBleHBlcmltZW50cw0KICBsYWJlbHMgPC0gYygib3JnYW5pemF0aW9ucyIsICJuZWlnaGJvcmhvb2RzIikNCiAgDQogIHN3YXBwaW5nIDwtIGxpc3QoKQ0KICBmb3IgKGkgaW4gMTpsZW5ndGgoZGF0YXNldHMpKSB7ICMgZm9yIGV4cGVyaW1lbnQgaQ0KICAgICMgZ2V0IHRoZSBkYXRhc2V0IA0KICAgIGRhdGFzZXQgPC0gZGF0YXNldHNbW2ldXQ0KICAgIA0KICAgICMgaWRlbnRpZnkgd2hldGhlciBpbiB0aGUgcmVwZWF0ZWQgY2hvaWNlIHRhc2ssIGEgZGlmZmVyZW50ICgxKSBvciBzaW1pbGFyICgwKSBjaG9pY2Ugd2FzIG1hZGUNCiAgICBkYXRhc2V0JHJlcGNob2ljZSA8LSBpZmVsc2UoZGF0YXNldFtbdGFza3NbW2ldXVsxXV1dID09IGRhdGFzZXRbW3Rhc2tzW1tpXV1bMl1dXSwgMSwgMCkNCg0KICAgICNjYWxjdWxhdGUgSVJSIGFuZCBzd2FwcGluZyBlcnJvcg0KICAgIGlycl9saXN0IDwtIGZfaXJyKGRhdGFzZXQpDQogICAgdGF1X2xpc3QgPC0gZl90YXUoaXJyX2xpc3QpDQogIA0KICAgIHN3YXBwaW5nW1tsYWJlbHNbaV1dXSA8LSBsaXN0KCJpcnIiID0gaXJyX2xpc3QsICJ0YXUiID0gdGF1X2xpc3QpDQogICAgfQ0KICAgICANCiAgIyBjYWxjdWxhdGUgY29uZGl0aW9uYWwgbWFyZ2luYWwgbWVhbnM6DQogIHhfdmFycyA8LSBjYmluZChjKCJBZ2UiLCAiVE0iLCAiVGVydCIpLCBjKCJhZ2UiLCAiZXRoIiwgImVkdWMiKSkNCiAgeV92YXJzIDwtIGMoImVuYmgiLCAiZWNpdiIpDQogICAgDQogIHJlc3VsdHMgPC0gZGF0YS5mcmFtZSgpDQogIA0KICBmb3IoeCBpbiAxOm5yb3coeF92YXJzKSkgew0KICAgIGZvcih5IGluIHlfdmFycykgew0KICAgICAgIyBmb3JtdWxhICANCiAgICAgIGYgPC0gYXMuZm9ybXVsYSggcGFzdGUwKHksICJfY2hvaWNlIH4gIiwgeSwgIl9jb21wXyIsIHhfdmFyc1t4LDJdKSkNCiAgICAgIGJ5IDwtIGFzLmZvcm11bGEocGFzdGUwKCJ+IiwgeF92YXJzW3gsMV0pKQ0KICAgICAgY21tcyA8LSBjcmVnZzo6Y2ooIGRbIWlzLm5hKGRbeF92YXJzW3gsMV1dKSwgXSwgI2V4Y2x1ZGUgbWlzc2luZ3Mgb24gdGhlIHN1Ymdyb3VwaW5nIHZhcmlhYmxlDQogICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtdWxhID0gZiwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSBieSkNCiAgICAgICNiaW5kIHJlc3VsdHMNCiAgICAgIHJlc3VsdHMgPC0gcmJpbmQocmVzdWx0cywgY21tc1ssLTEyXSkNCiAgICAgIH0NCiAgfQ0KIA0KICAjY2FsY3VsYXRlIGNvcnJlY3RlZCBjb25kaXRpb25hbCBtYXJnaW5hbCBtZWFuIChmb3Igc3ViZ3JvdXBzKQ0KICByZXN1bHRzJGVzdGltYXRlX2NvcnIgPC0gTkENCiAgICANCiAgZm9yIChpIGluIDE6bnJvdyhyZXN1bHRzKSkgeyANCiAgICAjcmV0cmlldmUgc2V0dGluZyBhbmQgc3ViZ3JvdXANCiAgICBzZXR0aW5nIDwtIGlmZWxzZShyZXN1bHRzJG91dGNvbWVbaV0gPT0gImVuYmhfY2hvaWNlIiwgIm5laWdoYm9yaG9vZHMiLCAib3JnYW5pemF0aW9ucyIpDQogICAgc3ViZ3JvdXAgPC0gYXMuY2hhcmFjdGVyKHJlc3VsdHMkQllbaV0pDQoNCiAgICB0YXUgPC0gc3dhcHBpbmdbW3NldHRpbmddXSR0YXVbc3ViZ3JvdXBdDQogICAgDQogICAgI2RlZmluZSBiaWFzIGNvcnJlY3RlZCBNTSAoZXEuIDExIG9mIENsYXl0b24gZXQgYWwuKQ0KICAgIHJlc3VsdHMkZXN0aW1hdGVfY29ycltpXSA8LSAocmVzdWx0cyRlc3RpbWF0ZVtpXSAtIHRhdSkgLyAoMSAtIDIqdGF1KQ0KICB9DQogICANCiAgI3NhdmUgcm93bmFtZXMNCiAgI3JuYW1lcyA8LSBwYXN0ZTAoIHJlc3VsdHMkb3V0Y29tZSwgIi0iLCByZXN1bHRzJGxldmVsLCAiLSIsIHJlc3VsdHMkQlkpDQogICNzYXZlKHJuYW1lcywgZmlsZSA9ICIuL2RhdGEvcm93bmFtZXMuUmRhIikNCiAgDQogIHJldHVybihyZXN1bHRzJGVzdGltYXRlX2NvcnIpICANCn0NCiNmYm9vdChkZikjdGVzdA0KDQpuQ29yZSA8LSBkZXRlY3RDb3JlcygpIC0gMSAjZGV0ZWN0IG51bWJlciBvZiBjb3JlcyAoa2VlcCBvbmUgZm9yIG90aGVyIHRhc2tzKQ0Kbkl0ZXIgPC0gMTAwMCAjbnVtYmVyIG9mIGJvb3RzdHJhcCBpdGVyYXRpb25zDQoNCiNzZXQgdXAgY2x1c3Rlcg0KbXljbCA8LSBtYWtlQ2x1c3RlcihyZXAoImxvY2FsaG9zdCIsIG5Db3JlKSkgDQoNCiNsb2FkIG5lY2Vzc2FyeSBsaWJyYXJ5IG9uIGVhY2ggY2x1c3RlciBub2RlDQpjbHVzdGVyRXZhbFEobXljbCwgew0KICBsaWJyYXJ5KGNyZWdnKQ0KICBsaWJyYXJ5KHB1cnJyKQ0KICBsaWJyYXJ5KGRwbHlyKQ0KfSkNCg0KI2NvcHkgZGF0YSBhbmQgY3VzdG9tIGZ1bmN0aW9ucyB0byBlYWNoIG5vZGUncyB3b3Jrc3BhY2UNCmNsdXN0ZXJFeHBvcnQobXljbCwgdmFybGlzdD1jKCJkZiIsICJmX3RhdSIsICJmX2lyciIsICJmYm9vdCIpKSANCg0KI3BlcmZvcm0gYm9vdHN0cmFwICh0YWtlcyB2ZXJ5IGxvbmchISEpDQpzeXN0ZW0udGltZSh0ZXN0IDwtIGJvb3QoZGYsIGZib290LCBSPW5JdGVyLCBwYXJhbGxlbCA9ICJzbm93IiwgbmNwdXMgPSBuQ29yZSwgY2wgPSBteWNsKSkgI2Fib3V0IDIgaG91cnMgb24gbXkgcGMNCg0KI3NhdmUodGVzdCwgZmlsZSA9ICIuL3Jlc3VsdHMvYm9vdC5SZGEiKQ0Kc3RvcENsdXN0ZXIobXljbCkNCmBgYA0KDQpgYGB7ciwgY29ycnBsb3QsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfSANCmxvYWQoIi4vcmVzdWx0cy9ib290LlJkYSIpDQpsb2FkKCIuL2RhdGEvcm93bmFtZXMuUmRhIikNCm5JdGVyID0gMTAwMA0KDQojIFNvbWUgTkEgdmFsdWVzIG1heSBvY2N1ciBiZWNhdXNlLCBpbiBjZXJ0YWluIGJvb3RzdHJhcCBpdGVyYXRpb25zLCBubyBpbmRpdmlkdWFscyBmcm9tIG1pbm9yaXR5IGdyb3VwcyBhcmUgc2FtcGxlZCBkdWUgdG8gdGhlaXIgc21hbGwgc2FtcGxlIHNpemUuIHJlcGxhY2UgdGhlc2UgTkEgdmFsdWVzIHdpdGggdGhlIG1lYW4gb2YgdGhlIGNvcnJlc3BvbmRpbmcgYm9vdHN0cmFwcGVkIENNTSBlc3RpbWF0ZXMsIGlnbm9yaW5nIGFueSBOQXMgZHVyaW5nIHRoZSBjYWxjdWxhdGlvbi4NCmZvciAoaSBpbiAxOmxlbmd0aCh0ZXN0JHQwKSkgew0KICBpZihpcy5uYSh0ZXN0JHQwW2ldKSkgew0KICAgIHRlc3QkdDBbaV0gPC0gbWVhbih0ZXN0JHRbLGldW2lzLmZpbml0ZSh0ZXN0JHRbLCBpXSldLCBuYS5ybT1UUlVFKQ0KICB9DQp9DQoNCnRlc3QxIDwtIHN1bW1hcnkodGVzdCkNCg0KI2FkZCByb3duYW1lcw0Kcm93bmFtZXModGVzdDEpIDwtIHJuYW1lcw0KI3N0cih0ZXN0KQ0KIA0KI2ZpcnN0IGFkZCB0aGUgb3JpZ2luYWwgYmlhcyBjb3JyZWN0ZWQgQ01NcyB0byB0aGUgZGF0YWZyYW1lIChpbnN0ZWFkIG9mIHRoZSBib290c3RyYXAgZXN0aW1hdGVzKToNCiNjcmVhdGUgYSBtZXJnZSB2YXJpYWJsZSBpbiB0aGUgb3JpZ2luYWwgQ01NIGRhdGFmcmFtZQ0KbW1zJEJZMiA8LSBwYXN0ZTAobW1zJG91dGNvbWUsICItIiwgbW1zJGxldmVsLCAiLSIsIG1tcyRCWSkNCiNyZW9yZGVyDQptbXMgPC0gbW1zW21hdGNoKHJvd25hbWVzKHRlc3QxKSwgbW1zJEJZMiksXQ0KDQojbm93IGNhbGN1bGF0ZSB0aGUgY29ycmVjdGVkIENNTVMNCmZvciAoaSBpbiAxOm5yb3cobW1zKSkgeyAjIGZvciBlYWNoIENNTQ0KICAgICNyZXRyaWV2ZSBzZXR0aW5nIGFuZCBzdWJncm91cA0KICAgIHNldHRpbmcgPC0gaWZlbHNlKG1tcyRvdXRjb21lW2ldID09ICJlbmJoX2Nob2ljZSIsICJuZWlnaGJvcmhvb2RzIiwgIm9yZ2FuaXphdGlvbnMiKQ0KICAgIHN1Ymdyb3VwIDwtIGFzLmNoYXJhY3RlcihtbXMkQllbaV0pDQogICAgDQogICAgI2dldCB0YXUgZnJvbSBvdXIgc2F2ZWQgbGlzdA0KICAgIHRhdSA8LSBzd2FwcGluZ0xpc3RbW3NldHRpbmddXSR0YXVbc3ViZ3JvdXBdDQogICAgI2RlZmluZSBiaWFzIGNvcnJlY3RlZCBNTSAoZXEuIDExIG9mIENsYXl0b24gZXQgYWwuKQ0KICAgIG1tcyRlc3RpbWF0ZV9jb3JyW2ldIDwtIChtbXMkZXN0aW1hdGVbaV0gLSB0YXUpIC8gKDEgLSAyKnRhdSkNCn0NCg0KI2NvcihjYmluZChtbXMkZXN0aW1hdGVfY29yciwgdGVzdDEkb3JpZ2luYWwpKSAjIGJpYXMgaXMgbmVnbGlnaWJsZQ0KDQojIGkgYWxzbyBjYWxjdWxhdGUgdGhlIGRpZmZlcmVuY2UgaW4gdGhlIGJvb3RzdHJhcHBlZCBDTU0gZXN0aW1hdGVzIGZvciBlYWNoIGNvbXBvc2l0aW9uIGF0dHJpYnV0ZSBsZXZlbCwgYmV0d2VlbiAoMSkgc3ViZ3JvdXBzIChlLmcuLCBjb2xsZWdlL25vIGNvbGxlZ2UgZGVncmVlKTsgYW5kICgyKSBzZXR0aWducyAoaS5lLiwgbmJoIHZzIG9yZykNCg0KIyBjcmVhdGUgYW4gZW1wdHkgbGlzdCB0byBzdG9yZSBjb21wYXJpc29uIHBhaXJzDQpjb21wYXJpc29ucyA8LSBsaXN0KCkNCg0KIyBsb29wIHRocm91Z2ggZWFjaCBlbGVtZW50IGluIHJuYW1lcw0KZm9yIChpIGluIHJuYW1lcykgew0KICAjIGV4dHJhY3QgcmVsZXZhbnQgY29tcG9uZW50cw0KICBjb21wb25lbnRzIDwtIHVubGlzdChzdHJzcGxpdChpLCAiLSIpKQ0KICBkZW1vX3RyYWl0IDwtIGNvbXBvbmVudHNbMl0gI2UuZy4sIGFnZTogaGFsZiAoNTAlKQ0KICBjaG9pY2VfdHlwZSA8LSBjb21wb25lbnRzWzFdICMgZS5nLiwgZW5iaF9jaG9pY2UtYWdlDQogIGdyb3VwIDwtIGNvbXBvbmVudHNbM10gIyBlLmcuLCA1MCB5ZWFycyBvciBvbGRlcg0KDQogICMgY29tcGFyZSB3aXRoIG90aGVyIGdyb3Vwcw0KICBmb3IgKGogaW4gcm5hbWVzKSB7DQogICAgaWYgKGkgIT0gaikgeyANCiAgICAgIG90aGVyX2NvbXBvbmVudHMgPC0gdW5saXN0KHN0cnNwbGl0KGosICItIikpDQogICAgICBvdGhlcl9jaG9pY2VfdHlwZSA8LSBvdGhlcl9jb21wb25lbnRzWzFdDQogICAgICBvdGhlcl9kZW1vX3RyYWl0IDwtIG90aGVyX2NvbXBvbmVudHNbMl0NCiAgICAgIG90aGVyX2dyb3VwIDwtIG90aGVyX2NvbXBvbmVudHNbM10NCiAgICAgICMgY29tcGFyZSBzdWJncm91cHMgKHdpdGhpbiBzZXR0aW5nKQ0KICAgICAgaWYoIGdyb3VwICE9IG90aGVyX2dyb3VwICYgZGVtb190cmFpdCA9PSBvdGhlcl9kZW1vX3RyYWl0ICYgY2hvaWNlX3R5cGUgPT0gb3RoZXJfY2hvaWNlX3R5cGUgKSB7DQogICAgICAgIGNvbXBhcmlzb25zW1tsZW5ndGgoY29tcGFyaXNvbnMpICsgMV1dIDwtIGRhdGEuZnJhbWUoDQogICAgICAgICAgZm9jYWwgPSBpLCBvdGhlciA9IGosIGNvbXBhcmlzb24gPSAic3ViZ3JvdXAiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCiAgICAgICAgKQ0KICAgICAgfQ0KICAgICAgIyBjb21wYXJlIHNldHRpbmdzICh3aXRoaW4gc3ViZ3JvdXApDQogICAgICAgIGlmKCBncm91cCA9PSBvdGhlcl9ncm91cCAmIGRlbW9fdHJhaXQgPT0gb3RoZXJfZGVtb190cmFpdCAmIGNob2ljZV90eXBlICE9IG90aGVyX2Nob2ljZV90eXBlICkgew0KICAgICAgICBjb21wYXJpc29uc1tbbGVuZ3RoKGNvbXBhcmlzb25zKSArIDFdXSA8LSBkYXRhLmZyYW1lKA0KICAgICAgICAgIGZvY2FsID0gaSwgb3RoZXIgPSBqLCBjb21wYXJpc29uID0gInNldHRpbmciLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCiAgICAgICAgKQ0KICAgICAgfQ0KICAgIH0NCiAgfQ0KfQ0KICAgICAgDQojIGNvbnZlcnQgbGlzdCBpbnRvIGRhdGFmcmFtZQ0KY29tcGFyaXNvbl9kZiA8LSBkby5jYWxsKHJiaW5kLCBjb21wYXJpc29ucykNCg0KI25vdywgZm9yIGVhY2ggY29tcGFyaXNvbi1wYWlyLCBnZXQgdGhlIGJvb3RzdHJhcHBlZCAoZXJyb3ItYWRqdXN0ZWQpIENNTXMsIGFuZCBjYWxjdWxhdGUgdGhlIG1lYW4gYW5kIENJIG9mIHRoZSBkaWZmZXJlbmNlIHRvIGFzc2VzcyB3aGV0aGVyIHRoZSBkaWZmZXJlbmNlIGlzIHNpZ25pZmljYW50IChpbmRpY2F0aW5nIGludGVyYWN0aW9uKQ0KY29tcGFyaXNvbl9kZiRtZWFuX2RpZiA8LSBOQQ0KY29tcGFyaXNvbl9kZiRDSSA8LSBOQQ0KY29tcGFyaXNvbl9kZiRzaWcgPC0gTkENCg0KZm9yIChpIGluIDE6bnJvdyhjb21wYXJpc29uX2RmKSkgew0KICAjZ2V0IGJvb3RzdHJhcHBlZCBDTU1zIA0KICBmb2NhbCA9IGNvbXBhcmlzb25fZGYkZm9jYWxbaV0gDQogIG90aGVyID0gY29tcGFyaXNvbl9kZiRvdGhlcltpXQ0KICANCiAgI2NhbGN1bGF0ZSBkaWZmZXJlbmNlIGJldHdlZW4gYm9vdHN0cmFwIGVzdGltYXRlcyBvZiBncm91cHMgKGkuZS4sIHN1Ymdyb3Vwcy9zZXR0aW5ncykNCiAgY21tX2RpZnMgPC0gdGVzdCR0Wywgd2hpY2gocm5hbWVzID09IGZvY2FsKV0gLSB0ZXN0JHRbLCB3aGljaChybmFtZXMgPT0gb3RoZXIpXQ0KICANCiAgI2V4Y2x1ZGUgbWlzc2luZ3MgYW5kIGluZmluaXRlIHZhbHVlcw0KICBjbW1fZGlmcyA8LSBjbW1fZGlmc1shaXMubmEoY21tX2RpZnMpICYgaXMuZmluaXRlKGNtbV9kaWZzKV0NCiAgDQogICNnZXQgdGhlIG1lYW4gZGlmZmVyZW5jZQ0KICBtZWFuX2NtbV9kaWYgPC0gbWVhbihjbW1fZGlmcykNCiAgDQogICNzdGFuZGFyZCBlcnJvcg0KICBzZV9jbW1fZGlmIDwtIHNkKGNtbV9kaWZzKSAvIHNxcnQobGVuZ3RoKGNtbV9kaWZzKSkNCiAgDQogICNjcml0aWNhbCB0IHZhbHVlDQogIHRfdmFsdWUgPC0gcXQoMC45NzUsIGRmID0gbGVuZ3RoKGNtbV9kaWZzKSAtIDEpDQogIA0KICAjbWFyZ2luIG9mIGVycm9yDQogIG1hcmdpbl9lcnJvciA8LSBzZV9jbW1fZGlmICogdF92YWx1ZQ0KICANCiAgIzk1JSBDSQ0KICBsb3dlcl9ib3VuZCA8LSBtZWFuX2NtbV9kaWYgLSBtYXJnaW5fZXJyb3INCiAgdXBwZXJfYm91bmQgPC0gbWVhbl9jbW1fZGlmICsgbWFyZ2luX2Vycm9yDQogIA0KICAjYWRkIHRvIGRmDQogIGNvbXBhcmlzb25fZGYkbWVhbl9kaWZbaV0gPC0gbWVhbl9jbW1fZGlmDQogIGNvbXBhcmlzb25fZGYkQ0lbaV0gPC0gcGFzdGUwKCJbIixyb3VuZChsb3dlcl9ib3VuZCwzKSwgIiwgIiwgcm91bmQodXBwZXJfYm91bmQsMyksIl0iKQ0KICBjb21wYXJpc29uX2RmJHNpZ1tpXSA8LSBpZmVsc2UoKGxvd2VyX2JvdW5kIDw9IDApICYgKHVwcGVyX2JvdW5kID49IDApLCBGQUxTRSwgVFJVRSkNCiAgfQ0KDQojY2FsY3VsYXRlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBib290c3RyYXAgc3RhdGlzdGljcw0KZm9yIChpIGluIDE6bnJvdyh0ZXN0MSkpIHsNCiAgaWYodGVzdDEkUltpXSA8IG5JdGVyKSB7DQogICAgc3RhdCA8LSB0ZXN0JHRbLGldDQogICAgdGVzdDEkYm9vdFNFW2ldIDwtIHNkKHN0YXRbIWlzLm5hKHN0YXQpICYgaXMuZmluaXRlKHN0YXQpXSkNCiAgfQ0KfQ0KDQp0ZXN0MSRkaWZfc3ViZ3JfQ0kgPC0gdGVzdDEkZGlmX3NldHRfQ0kgPC0gTkENCg0KZm9yIChpIGluIDE6bnJvdyh0ZXN0MSkpIHsgDQogIGZvY2FsID0gcm93bmFtZXModGVzdDEpW2ldDQogIHRlc3QxJGRpZl9zdWJncl9DSVtpXSA8LSBjb21wYXJpc29uX2RmJENJW2NvbXBhcmlzb25fZGYkZm9jYWwgPT0gZm9jYWwgJiBjb21wYXJpc29uX2RmJGNvbXBhcmlzb24gPT0gInN1Ymdyb3VwIl0NCiAgdGVzdDEkZGlmX3NldHRfQ0lbaV0gPC0gY29tcGFyaXNvbl9kZiRDSVtjb21wYXJpc29uX2RmJGZvY2FsID09IGZvY2FsICYgY29tcGFyaXNvbl9kZiRjb21wYXJpc29uID09ICJzZXR0aW5nIl0NCn0NCg0KZnNob3dkZih0ZXN0MSwgY2FwdGlvbiA9ICJib290c3RyYXAgcmVzdWx0cyIsIGZvb3Rub3RlID0gIkZvciBlYWNoIGJvb3RzdHJhcCBpdGVyYXRpb24sIHdlIGNhbGN1bGF0ZWQgdGhlIGRpZmZlcmVuY2UgaW4gZXN0aW1hdGVkIGNvbmRpdGlvbmFsIG1hcmdpbmFsIG1lYW5zIGZvciBjb21wb3NpdGlvbiBhdHRyaWJ1dGUgbGV2ZWxzIChlLmcuLCAyNSUgY29sbGVnZSBlZHVjYXRlZCkgKmFjcm9zcyogc3ViZ3JvdXBzIChlLmcuLCB3aXRoIHZzLiB3aXRob3V0IGNvbGxlZ2UgZGVncmVlKSB3aXRoaW4gdGhlIHNhbWUgc2V0dGluZyAoZS5nLiwgbmVpZ2hib3Job29kKS4gVGhlIDk1JSBjb25maWRlbmNlIGludGVydmFsIChgZGlmX3N1YmdyX0NJYCkgaW5kaWNhdGVzIHdoZXRoZXIgdGhlIHN1Ymdyb3VwIGRpZmZlcmVuY2VzIHdlcmUgc2lnbmlmaWNhbnQuIEFkZGl0aW9uYWxseSwgd2UgdGVzdGVkIHdoZXRoZXIgcHJlZmVyZW5jZXMgZm9yIGNvbXBvc2l0aW9uIGF0dHJpYnV0ZSBsZXZsZXMgKndpdGhpbiogc3ViZ3JvdXBzIGRpZmZlcmVkIHNpZ25pZmljYW50bHkgYmV0d2VlbiBzZXR0aW5ncyAoYGRpZl9zZXR0X0NJYCkuIikNCiAgICAgICAgDQojYWRkIHRoZXNlIHN0YXRpc3RpY3MgdG8gcGxvdHRpbmcgZGF0YQ0KI2NyZWF0ZSBjb3B5IG9mIG1tcw0KbW1zX2NvcnIgPC0gbW1zDQojdXNlIGNvcnJlY3RlZCBlc3RpbWF0ZXMNCm1tc19jb3JyJGVzdGltYXRlIDwtIG1tc19jb3JyJGVzdGltYXRlX2NvcnINCg0KI3dpdGggYm9vdHN0cmFwcGVkIHN0YW5kYXJkIGVycm9ycw0KbW1zX2NvcnIkc3RkLmVycm9yIDwtIHRlc3QxJGJvb3RTRQ0KI2FuZCBjb25maWRlbmNlIGludGVydmFscw0KbW1zX2NvcnIkdXBwZXIgPC0gbW1zX2NvcnIkZXN0aW1hdGUgKyAxLjk2Km1tc19jb3JyJHN0ZC5lcnJvcg0KbW1zX2NvcnIkbG93ZXIgPC0gbW1zX2NvcnIkZXN0aW1hdGUgLSAxLjk2Km1tc19jb3JyJHN0ZC5lcnJvcg0KDQptbXNfY29yciRlc3RpbWF0ZVttbXNfY29yciRlc3RpbWF0ZTwwXSA8LSAwDQoNCnAgPC0gcGxvdChtbXNfY29yciwgdmxpbmU9MS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIlN1Ymdyb3VwIiwgeGxhYiA9ICJNYXJnaW5hbCBtZWFuIikgKw0KICBmYWNldF9ncmlkMiggT3V0Y29tZSB+IEZlYXR1cmUsIHNjYWxlcyA9ICJmcmVlIiwgaW5kZXBlbmRlbnQgPSAieSIsIHN3aXRjaCA9ICJ5IikgKw0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlKSArDQogIGZhY2V0dGVkX3Bvc19zY2FsZXMoDQogICAgeSA9IGxpc3QoDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoInRocmVlIHF1YXJ0ZXJzICg3NSUpIiwgImhhbGYgKDUwJSkiLCAiYSBxdWFydGVyICgyNSUpIikpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygiaGFsZiAoNTAlKSIsICJqdXN0IHVuZGVyIGhhbGYgKDQwJSkiLCAiYSBxdWFydGVyICgyNSUpIikpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggVHVyay9Nb3JvYyBiYWNrZ3JvdW5kIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoImEgcXVhcnRlciAoMjUlKSIsICJtaW5vcml0eSAoMTAlKSIsICJub25lICgwJSkiKSkNCiAgICAgICksDQogICAgI2ZyZWVpbmcgdXAgdGhlIHggc2NhbGVzIGRvZXMgbm90IHdvcmsgZm9yIHNvbWUgcmVhc29uLi4uIHNvIGkgc2V0IHRoZW0gbWFudWFsbHk6DQogICAgeCA9IGxpc3QoDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiB+IHNjYWxlX3hfY29udGludW91cygNCiAgICAgICAgbGltaXRzID0gYyguMzUsLjY1KSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC40MCwuNjApLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC0wLjA5LDEpLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkNCiAgICAgICkpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICMgc3RyaXAudGV4dC54ID0gZWxlbWVudF9tYXJrZG93bigpLA0KICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpDQogDQpwIDwtIHBsb3RfZ3JpZChwLCBsZWcxMjMsIGFsaWduID0gImgiLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYyg3LDEpKQ0KDQpmc2hvd2RmKG1tc19jb3JyWywtYygxNCwgMTUsMTYpXSwgY2FwdGlvbiA9ICJNZWFzdXJlbWVudCBlcnJvciBiaWFzIGNvcnJlY3RlZCBjb25kaXRpb25hbCBtYXJnaW5hbCBtZWFucyIsIGRpZ2l0cz0zKQ0KDQpwbG90KHApDQoNCiNnZ3NhdmUoIi4vZmlndXJlcy9jbW1zX2xpc3NfY29ycmVjdGVkLnBuZyIsIHAsIHdpZHRoPTEzKSANCiNnZ3NhdmUoIi4vZmlndXJlcy9maWd1cmUwMl9zdWJncm91cF9tbS5wbmciLCBwLCB3aWR0aD0xMykNCg0KIyMjIFRhYmxlIGZvciBzdXBwbGVtZW50DQptbXNfY29ycjIgPC0gbW1zX2NvcnJbLCBjKCJTdWJncm91cCIsICJGZWF0dXJlIiwgIk91dGNvbWUiLCAibGV2ZWwiLCAiZXN0aW1hdGUiICldDQptbXNfY29ycjIkbGV2ZWwgPC0gc3ViKCIuKjogIiwgIiIsIG1tc19jb3JyMiRsZXZlbCkNCg0KI3RvIHdpZGU6DQptbXNfY29ycl93aWRlIDwtIG1tc19jb3JyMiAlPiUNCiAgcGl2b3Rfd2lkZXIoDQogICAgbmFtZXNfZnJvbSA9IE91dGNvbWUsDQogICAgdmFsdWVzX2Zyb20gPSBlc3RpbWF0ZQ0KICApDQpuYW1lcyhtbXNfY29ycl93aWRlKVs0OjVdIDwtIGMoIm5iaF9lc3RpbWF0ZSIsICJjaXZfZXN0aW1hdGUiKQ0KDQojIGNhbGN1bGF0ZSBkaWZmZXJlbmNlDQptbXNfY29ycl93aWRlJGRpZl9lc3RpbWF0ZSA8LSBtbXNfY29ycl93aWRlJG5iaF9lc3RpbWF0ZSAtICBtbXNfY29ycl93aWRlJGNpdl9lc3RpbWF0ZQ0KIyBjYWxjdWxhdGUgcmF0aW8NCm1tc19jb3JyX3dpZGUkcmF0aW8gPC0gKG1tc19jb3JyX3dpZGUkbmJoX2VzdGltYXRlIC0gMC41KSAvIChtbXNfY29ycl93aWRlJGNpdl9lc3RpbWF0ZSAtIDAuNSkNCg0KI3RvIDMgZGlnaXRzDQptbXNfY29ycl93aWRlX2QgPC0gbW1zX2NvcnJfd2lkZSAlPiUNCiAgbXV0YXRlKGFjcm9zcyg0OjcsIHJvdW5kLCBkaWdpdHMgPSAzKSkNCg0KI3dyaXRlLmNzdihtbXNfY29ycl93aWRlX2QsIGZpbGUgPSAidGFiLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KI3dyaXRlLmNzdihjb21wYXJpc29uX2RmLCBmaWxlID0gImNvbXAuY3N2Iiwgcm93Lm5hbWVzPUZBTFNFKQ0KYGBgIA0KDQoNCi0tLS0NCg0KIyMgaXMgdGhlIGNvbXBvc2l0aW9uIG9mIG9uZSdzIGN1cnJlbnQgc2V0dGluZyBwcmVkaWN0aXZlIG9mIGNob2ljZSBiZWhhdmlvcj8gey50YWJzZXQgLnRhYnNldC1mYWRlfQ0KDQojIyMgY29tcG9zaXRpb24gaW4gdGVybXMgb2Ygc2V0dGluZyAqKm1lbWJlcnMqKiB7LnRhYnNldCAudGFic2V0LWZhZGV9DQoNCiMjIyMgdW5jb3JyZWN0ZWQNCg0KYGBge3IsIGNtbXNfY3VyaW52LCBmaWcud2lkdGg9MTQsIGZpZy5oZWlnaHQ9OSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiNhZGRpdGlvbmFsIGRpc2FnZ3JlZ2F0aW9uIGJ5IHdoZXRoZXIgY3VycmVudCBuYmgvb3JnIGhhcyBoaWdoL2xvdyByZXByZXNlbnRhdGlvbiBvZiBncm91cCB4LCBmb3Igc3ViZ3JvdXA6DQoNCiNlZHVjYXRpb24gY29tcG9zaXRpb24NCiNzcGxpdCBieSBsb3dlciBhbmQgdXBwZXIgcXVhcnRpbGUgaW4gZGlzdHJpYnV0aW9uDQpkZiRlZHVjbmJoIDwtIE5BX3JlYWxfDQoNCiNoaXN0KGRmJG9uYmhfY29tcF9lZHVbZGYkVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSJdKQ0KI2hpc3QoZGYkb25iaF9jb21wX2VkdVtkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIl0pDQoNCiNkZWZpbmUgdGhlIHF1YXJ0aWxlcyBmb3IgZWFjaCBzdWJncm91cA0KY29sbGVnZV9xMjUgPC0gcXVhbnRpbGUoZGYkb25iaF9jb21wX2VkdVtkZiRUZXJ0ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIl0sIDAuMjUsIG5hLnJtID0gVFJVRSkNCmNvbGxlZ2VfcTc1IDwtIHF1YW50aWxlKGRmJG9uYmhfY29tcF9lZHVbZGYkVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSJdLCAwLjc1LCBuYS5ybSA9IFRSVUUpDQpub19jb2xsZWdlX3EyNSA8LSBxdWFudGlsZShkZiRvbmJoX2NvbXBfZWR1W2RmJFRlcnQgPT0gIldpdGhvdXQgY29sbGVnZSBkZWdyZWUiXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0Kbm9fY29sbGVnZV9xNzUgPC0gcXVhbnRpbGUoZGYkb25iaF9jb21wX2VkdVtkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIl0sIDAuNzUsIG5hLnJtID0gVFJVRSkNCg0KI2FwcGx5ICBjb25kaXRpb25zIGZvciBzdWJncm91cHMNCmRmJGVkdWNuYmggPC0gaWZlbHNlKGRmJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiLCANCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvbmJoX2NvbXBfZWR1IDw9IGNvbGxlZ2VfcTI1LCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvbmJoX2NvbXBfZWR1ID49IGNvbGxlZ2VfcTc1LCAyLCBOQSkpLA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgIGlmZWxzZShkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiwgDQogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb25iaF9jb21wX2VkdSA8PSBub19jb2xsZWdlX3EyNSwgMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb25iaF9jb21wX2VkdSA+PSBub19jb2xsZWdlX3E3NSwgMiwgTkEpKSwgTkEpKQ0KDQojbWFrZSBjYXRlZ29yaWVzIChjb21iaW5hdGlvbiBvZiBzdWJncm91cCBhbmQgY29tcG9zaXRpb24pDQpkZiRlZHVjbmJoVGVydCA8LSBpZmVsc2UoZGYkVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSIgJiBkZiRlZHVjbmJoID09IDEsICJXaXRoIGNvbGxlZ2UgZGVncmVlLCBmZXcgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiICYgZGYkZWR1Y25iaCA9PSAyLCAiV2l0aCBjb2xsZWdlIGRlZ3JlZSwgbWFueSB3aXRoIGNvbGxlZ2UgZGVncmVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiAmIGRmJGVkdWNuYmggPT0gMSwgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIGZldyB3aXRoIGNvbGxlZ2UgZGVncmVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiAmIGRmJGVkdWNuYmggPT0gMiwgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIG1hbnkgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsIE5BKSkpKQ0KI3Jlb3JkZXIgbGV2ZWxzDQpkZiRlZHVjbmJoVGVydCA8LSBmYWN0b3IoZGYkZWR1Y25iaFRlcnQsIGxldmVscyA9IGMoIldpdGggY29sbGVnZSBkZWdyZWUsIGZldyB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgICJXaXRoIGNvbGxlZ2UgZGVncmVlLCBtYW55IHdpdGggY29sbGVnZSBkZWdyZWUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIGZldyB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIG1hbnkgd2l0aCBjb2xsZWdlIGRlZ3JlZSIpKQ0KDQojYWxzbyBmb3Igb3JnYW5pemF0aW9ucw0KZGYkZWR1Y2NpdiA8LSBOQV9yZWFsXw0KDQojaGlzdChkZiRvY2l2X2NvbXBfZWR1W2RmJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiXSkNCiNoaXN0KGRmJG9jaXZfY29tcF9lZHVbZGYkVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSJdKQ0KDQojZGVmaW5lIHRoZSBxdWFydGlsZXMgZm9yIGVhY2ggZ3JvdXANCmNvbGxlZ2VfcTI1IDwtIHF1YW50aWxlKGRmJG9jaXZfY29tcF9lZHVbZGYkVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSJdLCAwLjI1LCBuYS5ybSA9IFRSVUUpDQpjb2xsZWdlX3E3NSA8LSBxdWFudGlsZShkZiRvY2l2X2NvbXBfZWR1W2RmJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiXSwgMC43NSwgbmEucm0gPSBUUlVFKQ0Kbm9fY29sbGVnZV9xMjUgPC0gcXVhbnRpbGUoZGYkb2Npdl9jb21wX2VkdVtkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIl0sIDAuMjUsIG5hLnJtID0gVFJVRSkNCm5vX2NvbGxlZ2VfcTc1IDwtIHF1YW50aWxlKGRmJG9jaXZfY29tcF9lZHVbZGYkVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSJdLCAwLjc1LCBuYS5ybSA9IFRSVUUpDQoNCiNhcHBseSAgY29uZGl0aW9ucyBmb3Igc3ViZ3JvdXBzDQpkZiRlZHVjY2l2IDwtIGlmZWxzZShkZiRUZXJ0ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIiwgDQogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb2Npdl9jb21wX2VkdSA8PSBjb2xsZWdlX3EyNSwgMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb2Npdl9jb21wX2VkdSA+PSBjb2xsZWdlX3E3NSwgMiwgTkEpKSwNCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICBpZmVsc2UoZGYkVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIsIA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29tcF9lZHUgPD0gbm9fY29sbGVnZV9xMjUsIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29tcF9lZHUgPj0gbm9fY29sbGVnZV9xNzUsIDIsIE5BKSksIE5BKSkNCg0KI21ha2UgY2F0ZWdvcmllcyAoY29tYmluYXRpb24gb2Ygc3ViZ3JvdXAgYW5kIGNvbXBvc2l0aW9uKQ0KZGYkZWR1Y2NpdlRlcnQgPC0gaWZlbHNlKGRmJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiICYgZGYkZWR1Y2NpdiA9PSAxLCAiV2l0aCBjb2xsZWdlIGRlZ3JlZSwgZmV3IHdpdGggY29sbGVnZSBkZWdyZWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUZXJ0ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIiAmIGRmJGVkdWNjaXYgPT0gMiwgIldpdGggY29sbGVnZSBkZWdyZWUsIG1hbnkgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIgJiBkZiRlZHVjY2l2ID09IDEsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlLCBmZXcgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIgJiBkZiRlZHVjY2l2ID09IDIsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlLCBtYW55IHdpdGggY29sbGVnZSBkZWdyZWUiLCBOQSkpKSkNCiNyZW9yZGVyIGxldmVscw0KZGYkZWR1Y2NpdlRlcnQgPC0gZmFjdG9yKGRmJGVkdWNjaXZUZXJ0LCBsZXZlbHMgPSBjKCJXaXRoIGNvbGxlZ2UgZGVncmVlLCBmZXcgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsICAiV2l0aCBjb2xsZWdlIGRlZ3JlZSwgbWFueSB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlLCBmZXcgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlLCBtYW55IHdpdGggY29sbGVnZSBkZWdyZWUiKSkNCiAjYWdlDQpkZiRhZ2VuYmggPC0gTkFfcmVhbF8NCiNoaXN0KGRmJG9uYmhfY29tcF9hZ2VbZGYkQWdlID09ICI1MCB5ZWFycyBvciBvbGRlciJdKQ0KI2hpc3QoZGYkb25iaF9jb21wX2FnZVtkZiRBZ2UgPT0gIkJlbG93IDUwIHllYXJzIl0pDQoNCiNkZWZpbmUgdGhlIHF1YXJ0aWxlcyBmb3IgZWFjaCBncm91cA0KYWdlX3EyNSA8LSBxdWFudGlsZShkZiRvbmJoX2NvbXBfYWdlW2RmJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0KYWdlX3E3NSA8LSBxdWFudGlsZShkZiRvbmJoX2NvbXBfYWdlW2RmJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiXSwgMC43NSwgbmEucm0gPSBUUlVFKQ0KbmFnZV9xMjUgPC0gcXVhbnRpbGUoZGYkb25iaF9jb21wX2FnZVtkZiRBZ2UgPT0gIkJlbG93IDUwIHllYXJzIl0sIDAuMjUsIG5hLnJtID0gVFJVRSkNCm5hZ2VfcTc1IDwtIHF1YW50aWxlKGRmJG9uYmhfY29tcF9hZ2VbZGYkQWdlID09ICJCZWxvdyA1MCB5ZWFycyJdLCAwLjc1LCBuYS5ybSA9IFRSVUUpDQoNCiNhcHBseSAgY29uZGl0aW9ucyBmb3Igc3ViZ3JvdXBzDQpkZiRhZ2VuYmggPC0gaWZlbHNlKGRmJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiLCANCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvbmJoX2NvbXBfYWdlIDw9IGFnZV9xMjUsIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9uYmhfY29tcF9hZ2UgPj0gYWdlX3E3NSwgMiwgTkEpKSwNCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICBpZmVsc2UoZGYkQWdlID09ICJCZWxvdyA1MCB5ZWFycyIsIA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9uYmhfY29tcF9hZ2UgPD0gbmFnZV9xMjUsIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9uYmhfY29tcF9hZ2UgPj0gbmFnZV9xNzUsIDIsIE5BKSksIE5BKSkNCg0KI21ha2UgY2F0ZWdvcmllcyAoY29tYmluYXRpb24gb2Ygc3ViZ3JvdXAgYW5kIGNvbXBvc2l0aW9uKQ0KZGYkYWdlbmJoQWdlIDwtIGlmZWxzZShkZiRBZ2UgPT0gICI1MCB5ZWFycyBvciBvbGRlciIgJiBkZiRhZ2VuYmggPT0gMSwgIjUwIHllYXJzIG9yIG9sZGVyLCBmZXcgNTAgeWVhcnMgb3Igb2xkZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRBZ2UgPT0gIjUwIHllYXJzIG9yIG9sZGVyIiAmIGRmJGFnZW5iaCA9PSAyLCAiNTAgeWVhcnMgb3Igb2xkZXIsIG1hbnkgNTAgeWVhcnMgb3Igb2xkZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJEFnZSA9PSAgIkJlbG93IDUwIHllYXJzIiAmIGRmJGFnZW5iaCA9PSAxLCAiQmVsb3cgNTAgeWVhcnMsIGZldyA1MCB5ZWFycyBvciBvbGRlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkQWdlID09ICAiQmVsb3cgNTAgeWVhcnMiICYgZGYkYWdlbmJoID09IDIsICJCZWxvdyA1MCB5ZWFycywgbWFueSA1MCB5ZWFycyBvciBvbGRlciIsIE5BKSkpKQ0KDQojcmVvcmRlciBsZXZlbHMNCmRmJGFnZW5iaEFnZSA8LSBmYWN0b3IoZGYkYWdlbmJoQWdlLCBsZXZlbHMgPSBjKCI1MCB5ZWFycyBvciBvbGRlciwgZmV3IDUwIHllYXJzIG9yIG9sZGVyIiwgIjUwIHllYXJzIG9yIG9sZGVyLCBtYW55IDUwIHllYXJzIG9yIG9sZGVyIiwgIkJlbG93IDUwIHllYXJzLCBmZXcgNTAgeWVhcnMgb3Igb2xkZXIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJlbG93IDUwIHllYXJzLCBtYW55IDUwIHllYXJzIG9yIG9sZGVyIikpDQoNCiNhbHNvIGZvciBvcmdhbml6YXRpb25zDQpkZiRhZ2VjaXYgPC0gTkFfcmVhbF8NCiNoaXN0KGRmJG9jaXZfY29tcF9hZ2VbZGYkQWdlID09ICI1MCB5ZWFycyBvciBvbGRlciJdKQ0KI2hpc3QoZGYkb2Npdl9jb21wX2FnZVtkZiRBZ2UgPT0gIkJlbG93IDUwIHllYXJzIl0pDQoNCiNkZWZpbmUgdGhlIHF1YXJ0aWxlcyBmb3IgZWFjaCBncm91cA0KYWdlX3EyNSA8LSBxdWFudGlsZShkZiRvY2l2X2NvbXBfYWdlW2RmJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0KYWdlX3E3NSA8LSBxdWFudGlsZShkZiRvY2l2X2NvbXBfYWdlW2RmJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiXSwgMC43NSwgbmEucm0gPSBUUlVFKQ0KbmFnZV9xMjUgPC0gcXVhbnRpbGUoZGYkb2Npdl9jb21wX2FnZVtkZiRBZ2UgPT0gIkJlbG93IDUwIHllYXJzIl0sIDAuMjUsIG5hLnJtID0gVFJVRSkNCm5hZ2VfcTc1IDwtIHF1YW50aWxlKGRmJG9jaXZfY29tcF9hZ2VbZGYkQWdlID09ICJCZWxvdyA1MCB5ZWFycyJdLCAwLjc1LCBuYS5ybSA9IFRSVUUpDQoNCiNhcHBseSAgY29uZGl0aW9ucyBmb3Igc3ViZ3JvdXBzDQpkZiRhZ2VjaXYgPC0gaWZlbHNlKGRmJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiLCANCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvY2l2X2NvbXBfYWdlIDw9IGFnZV9xMjUsIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29tcF9hZ2UgPj0gYWdlX3E3NSwgMiwgTkEpKSwNCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICBpZmVsc2UoZGYkQWdlID09ICJCZWxvdyA1MCB5ZWFycyIsIA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29tcF9hZ2UgPD0gbmFnZV9xMjUsIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29tcF9hZ2UgPj0gbmFnZV9xNzUsIDIsIE5BKSksIE5BKSkNCg0KI21ha2UgY2F0ZWdvcmllcyAoY29tYmluYXRpb24gb2Ygc3ViZ3JvdXAgYW5kIGNvbXBvc2l0aW9uKQ0KZGYkYWdlY2l2QWdlIDwtIGlmZWxzZShkZiRBZ2UgPT0gICI1MCB5ZWFycyBvciBvbGRlciIgJiBkZiRhZ2VjaXYgPT0gMSwgIjUwIHllYXJzIG9yIG9sZGVyLCBmZXcgNTAgeWVhcnMgb3Igb2xkZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRBZ2UgPT0gIjUwIHllYXJzIG9yIG9sZGVyIiAmIGRmJGFnZWNpdiA9PSAyLCAiNTAgeWVhcnMgb3Igb2xkZXIsIG1hbnkgNTAgeWVhcnMgb3Igb2xkZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJEFnZSA9PSAgIkJlbG93IDUwIHllYXJzIiAmIGRmJGFnZWNpdiA9PSAxLCAiQmVsb3cgNTAgeWVhcnMsIGZldyA1MCB5ZWFycyBvciBvbGRlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkQWdlID09ICAiQmVsb3cgNTAgeWVhcnMiICYgZGYkYWdlY2l2ID09IDIsICJCZWxvdyA1MCB5ZWFycywgbWFueSA1MCB5ZWFycyBvciBvbGRlciIsIE5BKSkpKQ0KDQojcmVvcmRlciBsZXZlbHMNCmRmJGFnZWNpdkFnZSA8LSBmYWN0b3IoZGYkYWdlY2l2QWdlLCBsZXZlbHMgPSBjKCI1MCB5ZWFycyBvciBvbGRlciwgZmV3IDUwIHllYXJzIG9yIG9sZGVyIiwgIjUwIHllYXJzIG9yIG9sZGVyLCBtYW55IDUwIHllYXJzIG9yIG9sZGVyIiwgIkJlbG93IDUwIHllYXJzLCBmZXcgNTAgeWVhcnMgb3Igb2xkZXIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJlbG93IDUwIHllYXJzLCBtYW55IDUwIHllYXJzIG9yIG9sZGVyIikpDQoNCiNldGhuaWNpdHkNCmRmJFRNbmJoIDwtIE5BX3JlYWxfDQojaGlzdChkZiRvbmJoX2NvbXBfZXRoW2RmJFRNID09ICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCJdKQ0KI2hpc3QoZGYkb25iaF9jb21wX2V0aFtkZiRUTSA9PSAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIl0pDQoNCiNmb3IgZXRobmljaXR5ICglIHR1cmtzL21vcm9jY2FucyksIHVzZSBtZWFuIHNwbGl0IChnaXZlbiBoaWdobHkgc2tld2VkIGRpc3RyaWJ1dGlvbikNCmRmJFRNbmJoIDwtIE5BX3JlYWxfDQoNCiNkZWZpbmUgbWVhbnMgZm9yIGVhY2ggZ3JvdXANCm5tX20gPC0gbWVhbihkZiRvbmJoX2NvbXBfZXRoW2RmJFRNID09ICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCJdLCBuYS5ybSA9IFRSVUUpDQptX20gPC0gbWVhbihkZiRvbmJoX2NvbXBfZXRoW2RmJFRNID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiXSwgbmEucm0gPSBUUlVFKQ0KDQojYXBwbHkgIGNvbmRpdGlvbnMgZm9yIHN1Ymdyb3Vwcw0KZGYkVE1uYmggPC0gaWZlbHNlKGRmJFRNID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCANCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvbmJoX2NvbXBfZXRoIDwgbV9tLCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvbmJoX2NvbXBfZXRoID49IG1fbSwgMiwgTkEpKSwNCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICBpZmVsc2UoZGYkVE0gPT0gIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiwgDQogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb25iaF9jb21wX2V0aCA8IG5tX20sIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9uYmhfY29tcF9ldGggPj0gbm1fbSwgMiwgTkEpKSwgTkEpKQ0KDQojbWFrZSBjYXRlZ29yaWVzIChjb21iaW5hdGlvbiBvZiBzdWJncm91cCBhbmQgY29tcG9zaXRpb24pDQpkZiRldGhuYmhUTSA8LSBpZmVsc2UoZGYkVE0gPT0gICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiICYgZGYkVE1uYmggPT0gMSwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJFRNID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiICYgZGYkVE1uYmggPT0gMiwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJFRNID09ICAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiICYgZGYkVE1uYmggPT0gMSwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUTSA9PSAgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiAmIGRmJFRNbmJoID09IDIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCBOQSkpKSkNCg0KI3Jlb3JkZXIgbGV2ZWxzDQpkZiRldGhuYmhUTSA8LSBmYWN0b3IoZGYkZXRobmJoVE0sIGxldmVscyA9IGMoIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQsIG1hbnkgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBtYW55IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIpKQ0KDQojYWxzbyBmb3Igb3JnYW5pemF0aW9ucw0KZGYkVE1jaXYgPC0gTkFfcmVhbF8NCiNoaXN0KGRmJG9jaXZfY29tcF9ldGhbZGYkVE0gPT0gIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIl0pDQojaGlzdChkZiRvY2l2X2NvbXBfZXRoW2RmJFRNID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiXSkNCg0KI2ZvciBldGhuaWNpdHkgKCUgdHVya3MvbW9yb2NjYW5zKSwgdXNlIG1lYW4gc3BsaXQgKGdpdmVuIGhpZ2hseSBza2V3ZWQgZGlzdHJpYnV0aW9uKQ0KZGYkVE1jaXYgPC0gTkFfcmVhbF8NCg0KI2RlZmluZSBtZWFucyBmb3IgZWFjaCBncm91cA0Kbm1fbSA8LSBtZWFuKGRmJG9jaXZfY29tcF9ldGhbZGYkVE0gPT0gIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIl0sIG5hLnJtID0gVFJVRSkNCm1fbSA8LSBtZWFuKGRmJG9jaXZfY29tcF9ldGhbZGYkVE0gPT0gIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCJdLCBuYS5ybSA9IFRSVUUpDQoNCiNhcHBseSAgY29uZGl0aW9ucyBmb3Igc3ViZ3JvdXBzDQpkZiRUTWNpdiA8LSBpZmVsc2UoZGYkVE0gPT0gIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsIA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29tcF9ldGggPCBtX20sIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29tcF9ldGggPj0gbV9tLCAyLCBOQSkpLA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgIGlmZWxzZShkZiRUTSA9PSAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiLCANCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvY2l2X2NvbXBfZXRoIDwgbm1fbSwgMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb2Npdl9jb21wX2V0aCA+PSBubV9tLCAyLCBOQSkpLCBOQSkpDQoNCiNtYWtlIGNhdGVnb3JpZXMgKGNvbWJpbmF0aW9uIG9mIHN1Ymdyb3VwIGFuZCBjb21wb3NpdGlvbikNCmRmJGV0aGNpdlRNIDwtIGlmZWxzZShkZiRUTSA9PSAgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIgJiBkZiRUTWNpdiA9PSAxLCAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkVE0gPT0gIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIgJiBkZiRUTWNpdiA9PSAyLCAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kLCBtYW55IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkVE0gPT0gICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIgJiBkZiRUTWNpdiA9PSAxLCAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQsIGZldyBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJFRNID09ICAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiICYgZGYkVE1jaXYgPT0gMiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBtYW55IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsIE5BKSkpKQ0KDQojcmVvcmRlciBsZXZlbHMNCmRmJGV0aGNpdlRNIDwtIGZhY3RvcihkZiRldGhjaXZUTSwgbGV2ZWxzID0gYygiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQsIGZldyBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQsIG1hbnkgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIikpDQoNCiNhZ2UNCm5tbWFnZWNvbXAgPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRhZ2VuYmhBZ2UpLCBdLCBlbmJoX2Nob2ljZSB+IGVuYmhfY29tcF9hZ2UsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gIH4gYWdlbmJoQWdlKQ0KY21tYWdlY29tcCA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJGFnZWNpdkFnZSksIF0sIGVjaXZfY2hvaWNlIH4gZWNpdl9jb21wX2FnZSwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSAgfiBhZ2VjaXZBZ2UpDQpubW1hZ2Vjb21wJHNldHRpbmcgPC0gIk5laWdoYm9yaG9vZHMiDQpjbW1hZ2Vjb21wJHNldHRpbmcgPC0gIkNpdmljIG9yZ2FuaXphdGlvbnMiDQphZ2UgPC0gcmJpbmQobm1tYWdlY29tcFstMTJdLCBjbW1hZ2Vjb21wWy0xMl0pDQphZ2Ukc2V0dGluZyA8LSBmYWN0b3IoYWdlJHNldHRpbmcsIGxldmVscyA9IGMoIk5laWdoYm9yaG9vZHMiLCAiQ2l2aWMgb3JnYW5pemF0aW9ucyIpKQ0KDQpwYWdlIDwtIHBsb3QoYWdlLCB2bGluZSA9IDEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJCWSIsIHhsYWIgPSAiICAiKSArDQogIGZhY2V0X2dyaWQyKHNldHRpbmd+Liwgc3dpdGNoID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiU2hhcmUgb2YgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiKSArDQogICAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBzdWIoIi4qOiAiLCAiIiwgbGV2ZWxzKGFnZSRsZXZlbCkpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjQ0NDQ0NDIiwgIiM2NjY2NjYiLCAiI0YwQjMzQyIsICIjQTY3NjAwIikpICsgDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0Ym94X3NpbXBsZShwYWRkaW5nID0gbWFyZ2luKDUuNSwgNS41LCA1LjUsIDUuNSksIG1hcmdpbiA9IG1hcmdpbigwLCAwLCA1LjUsIDApLCBmaWxsID0gImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMSwgciA9IGdyaWQ6OnVuaXQoMCwgInB0IiksIHNpemUgPSA4KSkNCg0KI2V0aA0Kbm1tZXRoY29tcCA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJGV0aG5iaFRNKSwgXSwgZW5iaF9jaG9pY2UgfiBlbmJoX2NvbXBfZXRoLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9ICB+IGV0aG5iaFRNKQ0KY21tZXRoY29tcCA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJGV0aGNpdlRNKSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfZXRoLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9ICB+IGV0aGNpdlRNKQ0Kbm1tZXRoY29tcCRzZXR0aW5nIDwtICJOZWlnaGJvcmhvb2RzIg0KY21tZXRoY29tcCRzZXR0aW5nIDwtICJDaXZpYyBvcmdhbml6YXRpb25zIg0KZXRoIDwtIHJiaW5kKG5tbWV0aGNvbXBbLTEyXSwgY21tZXRoY29tcFstMTJdKQ0KZXRoJHNldHRpbmcgPC0gZmFjdG9yKGV0aCRzZXR0aW5nLCBsZXZlbHMgPSBjKCJOZWlnaGJvcmhvb2RzIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiKSkNCg0KI2ZvciBzb21lIHJlYXNvbiBpIG5lZWQgdG8gcmV2ZXJzZSB0aGUgbGV2ZWxzIGFnYWluLi4uDQpldGgkQlkgPC0gZmFjdG9yKGV0aCRCWSwgbGV2ZWxzID0gYygiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQsIG1hbnkgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBtYW55IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIpKSANCg0KcGV0aCA8LSBwbG90KGV0aCwgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQlkiLCB4bGFiID0gIk1hcmdpbmFsIG1lYW4iKSArDQogIGZhY2V0X2dyaWQyKHNldHRpbmd+Liwgc3dpdGNoID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggVHVyay9Nb3JvYyBiYWNrZ3JvdW5kIikgKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IHN1YigiLio6ICIsICIiLCBsZXZlbHMoZXRoJGxldmVsKSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiNBMkQ0RjciLCAiIzFFODBDMCIsICIjRjJBMDY2IiwgIiNBNDNEMDAiKSkgKyANCiAgdGhlbWUoIA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0Ym94X3NpbXBsZShwYWRkaW5nID0gbWFyZ2luKDUuNSwgNS41LCA1LjUsIDUuNSksIG1hcmdpbiA9IG1hcmdpbigwLCAwLCA1LjUsIDApLCBmaWxsID0gImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMSwgciA9IGdyaWQ6OnVuaXQoMCwgInB0IiksIHNpemUgPSA4KSkNCg0KI2VkdWMNCm5tbWVkdWNjb21wIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkZWR1Y25iaFRlcnQpLCBdLCBlbmJoX2Nob2ljZSB+IGVuYmhfY29tcF9lZHVjLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9ICB+IGVkdWNuYmhUZXJ0KQ0KY21tZWR1Y2NvbXAgPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRlZHVjY2l2VGVydCksIF0sIGVjaXZfY2hvaWNlIH4gZWNpdl9jb21wX2VkdWMsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gIH4gZWR1Y2NpdlRlcnQpDQpubW1lZHVjY29tcCRzZXR0aW5nIDwtICJOZWlnaGJvcmhvb2RzIg0KY21tZWR1Y2NvbXAkc2V0dGluZyA8LSAiQ2l2aWMgb3JnYW5pemF0aW9ucyINCmVkdWMgPC0gcmJpbmQobm1tZWR1Y2NvbXBbLTEyXSwgY21tZWR1Y2NvbXBbLTEyXSkNCmVkdWMkc2V0dGluZyA8LSBmYWN0b3IoZWR1YyRzZXR0aW5nLCBsZXZlbHMgPSBjKCJOZWlnaGJvcmhvb2RzIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiKSkNCg0KcGVkdWMgPC0gcGxvdChlZHVjLCB2bGluZSA9IDEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJCWSIsIHhsYWIgPSAiICAiKSArDQogIGZhY2V0X2dyaWQyKHNldHRpbmd+Liwgc3dpdGNoID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBzdWIoIi4qOiAiLCAiIiwgbGV2ZWxzKGVkdWMkbGV2ZWwpKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI0QxQ0U4RiIsICIjQTlBMDExIiwgIiMzMzk5Q0MiLCAiIzAwNEM4QyIpKSArIA0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dGJveF9zaW1wbGUocGFkZGluZyA9IG1hcmdpbig1LjUsIDUuNSwgNS41LCA1LjUpLCBtYXJnaW4gPSBtYXJnaW4oMCwgMCwgNS41LCAwKSwgZmlsbCA9ICJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDEsIHIgPSBncmlkOjp1bml0KDAsICJwdCIpLCBzaXplID0gOCkpDQoNCiNjb21iaW5lIHBsb3RzDQpjb21iaXBsb3QgPC0gZ2dwdWJyOjpnZ2FycmFuZ2UocGFnZSxwZXRoLHBlZHVjLCBuY29sID0gMywgdmp1c3QgPSAuOSkNCg0KI3NwbGl0IGxlZ2VuZCBpbnRvIG11bHRpcGxlIHBhcnRzDQojZmlyc3QsIHJldmVyc2Ugb3JkZXIgc3ViZ3JvdXBpbmcgZmFjdG9yIHZhcmlhYmxlIC4uLg0KYWdlJFN1Ymdyb3VwIDwtIGZhY3RvcihhZ2UkQlksIGxldmVscyA9IHJldihsZXZlbHMoYWdlJEJZKSkpDQpldGgkU3ViZ3JvdXAgPC0gZmFjdG9yKGV0aCRCWSwgbGV2ZWxzID0gcmV2KGxldmVscyhldGgkQlkpKSkNCmVkdWMkU3ViZ3JvdXAgPC0gZmFjdG9yKGVkdWMkQlksIGxldmVscyA9IHJldihsZXZlbHMoZWR1YyRCWSkpKQ0KIA0KI3Bsb3QgbGVnZW5kcw0Kc3BsaXQxcCA8LSBnZ3Bsb3QoYWdlLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gbGV2ZWwsIGNvbG9yID0gU3ViZ3JvdXAgKSkgKyBnZW9tX3BvaW50KCkgKyBsYWJzKGNvbG9yID0gIlN1Ymdyb3VwLCBjdXJyZW50IHNldHRpbmc6IikgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcmV2KGMoIiNDQ0NDQ0MiLCAiIzY2NjY2NiIsICIjRjBCMzNDIiwgIiNBNjc2MDAiKSkpICsgdGhlbWVfYncoKQ0Kc3BsaXQycCA8LSBnZ3Bsb3QoZXRoLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gbGV2ZWwsIGNvbG9yID0gU3ViZ3JvdXAgKSkgKyBnZW9tX3BvaW50KCkgKyBsYWJzKGNvbG9yID0gIlN1Ymdyb3VwLCBjdXJyZW50IHNldHRpbmc6IikgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcmV2KGMoIiNBMkQ0RjciLCAiIzFFODBDMCIsICIjRjJBMDY2IiwgIiNBNDNEMDAiKSkpICsgdGhlbWVfYncoKQ0Kc3BsaXQzcCA8LSBnZ3Bsb3QoZWR1YywgYWVzKHggPSBlc3RpbWF0ZSwgeSA9IGxldmVsLCBjb2xvciA9IFN1Ymdyb3VwICkpICsgZ2VvbV9wb2ludCgpICsgbGFicyhjb2xvciA9ICJTdWJncm91cCwgY3VycmVudCBzZXR0aW5nOiIpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJldihjKCIjRDFDRThGIiwgIiNBOUEwMTEiLCAiIzMzOTlDQyIsICIjMDA0QzhDIikpKSArIHRoZW1lX2J3KCkNCg0KI2dldCBsZWdlbmRzDQpsZWcxIDwtIGdldF9sZWdlbmQoc3BsaXQxcCkNCmxlZzIgPC0gZ2V0X2xlZ2VuZChzcGxpdDJwKQ0KbGVnMyA8LSBnZXRfbGVnZW5kKHNwbGl0M3ApDQoNCiNjb21iaW5lIGxlZ2VuZHMNCmxlZzEyM2EgPC0gcGxvdF9ncmlkKGxlZzEsbGVnMixsZWczLCBucm93PTEsIGFsaWduPSJoIikNCg0KI2NyZWF0ZSBhIGJsYW5rIHBsb3QgZm9yIGxlZ2VuZCBhbGlnbm1lbnQNCmJsYW5rX3AgPC0gcGxvdF9zcGFjZXIoKQ0KDQojY29tYmluZSBhbGwgaW4gb25lDQpwIDwtIHBsb3RfZ3JpZChjb21iaXBsb3QsIGxlZzEyM2EsIGFsaWduID0gImgiLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYyg0LjUsMSkpDQoNCiNzYXZlDQojZ2dzYXZlKCIuL2ZpZ3VyZXMvY21tc19saXNzX2N1cnJlbnQucG5nIiwgcCwgd2lkdGg9MTMpIA0KcHJpbnQocCkNCmBgYCANCg0KIyMjIyMgY29udHJvbCBmb3IgdXJiYW4tcnVyYWwgZGl2aWRlDQoNCldlIHJlLWRvIHRoZSBhbmFseXNlcywgbm93IG9ubHkgZm9jdXNpbmcgb24gcmVzcG9uZGVudHMgd2hvIGxpdmUgaW4gdXJiYW4gYXJlYXMgKGFuZCB0aHVzIGRyb3AgdGhvc2UgaW4gcnVyYWwgYXJlYXMpLiBXZSBkbyB0aGlzIHRvIGNoZWNrIHdoZXRoZXIgb3VyIGZpbmRpbmcgdGhhdCBncmVhdGVyIGV4cG9zdXJlIHRvIChlLmcuLCBldGhuaWMpIG91dGdyb3VwcyByZWR1Y2VzIGluZ3JvdXAgcHJlZmVyZW5jZXMgaXMgbm90IGNvbmZvdW5kZWQgYnkgdXJiYW4tcnVyYWwgZGl2aWRlIGluIGluZ3JvdXAgcHJlZmVyZW5jZXMgKGR1ZSB0bywgZS5nLiwgdHJhZGl0aW9uYWxpc20sIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQsIC4uLikuDQoNCmBgYHtyLCBjbW1zX2N1cmludl91cmJhbiwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTksIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQphdHRyKGRmJHN0ZWQsICJsYWJlbHMiKSAjc2VlIGh0dHBzOi8vd3d3LmNicy5ubC9ubC1ubC9uaWV1d3MvMjAyMi80OS9yZWdpb25hbGUtYnJlZGUtd2VsdmFhcnQtaGllci1lbi1udS10ZW4ta29zdGUtdmFuLWxhdGVyLS9zdGVkZWxpamtoZWlkc2dyYWFkDQoNCiNsZXQncyBzdWJzZXQgcmVzcG9uZGVudHMgd2hvIGxpdmUgaW4gYXQgbGVhc3QgYSBtb2RlcmF0ZWx5IHVyYmFuaXplZCBhcmVhOg0KZGZ1cmJhbiA8LSBkZltkZiRzdGVkIDwgNCwgXQ0KI3N1bShwcm9wLnRhYmxlKHRhYmxlKGRmJHN0ZWQpKVsyOjRdKSAjYW1vdW50aW5nIHRvIDY3JSBvZiByZXNwb25kZW50cy4NCg0KI2FkZGl0aW9uYWwgZGlzYWdncmVnYXRpb24gYnkgd2hldGhlciBjdXJyZW50IG5iaC9vcmcgaGFzIGhpZ2gvbG93IHJlcHJlc2VudGF0aW9uIG9mIGdyb3VwIHgsIGZvciBzdWJncm91cDoNCg0KI2VkdWNhdGlvbiBjb21wb3NpdGlvbg0KI3NwbGl0IGJ5IGxvd2VyIGFuZCB1cHBlciBxdWFydGlsZSBpbiBkaXN0cmlidXRpb24NCmRmJGVkdWNuYmggPC0gTkFfcmVhbF8NCg0KI2RlZmluZSB0aGUgcXVhcnRpbGVzIGZvciBlYWNoIHN1Ymdyb3VwDQpjb2xsZWdlX3EyNSA8LSBxdWFudGlsZShkZnVyYmFuJG9uYmhfY29tcF9lZHVbZGZ1cmJhbiRUZXJ0ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIl0sIDAuMjUsIG5hLnJtID0gVFJVRSkNCmNvbGxlZ2VfcTc1IDwtIHF1YW50aWxlKGRmdXJiYW4kb25iaF9jb21wX2VkdVtkZnVyYmFuJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiXSwgMC43NSwgbmEucm0gPSBUUlVFKQ0Kbm9fY29sbGVnZV9xMjUgPC0gcXVhbnRpbGUoZGZ1cmJhbiRvbmJoX2NvbXBfZWR1W2RmdXJiYW4kVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSJdLCAwLjI1LCBuYS5ybSA9IFRSVUUpDQpub19jb2xsZWdlX3E3NSA8LSBxdWFudGlsZShkZnVyYmFuJG9uYmhfY29tcF9lZHVbZGZ1cmJhbiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIl0sIDAuNzUsIG5hLnJtID0gVFJVRSkNCg0KI2FwcGx5ICBjb25kaXRpb25zIGZvciBzdWJncm91cHMNCmRmdXJiYW4kZWR1Y25iaCA8LSBpZmVsc2UoZGZ1cmJhbiRUZXJ0ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIiwgDQogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRvbmJoX2NvbXBfZWR1IDw9IGNvbGxlZ2VfcTI1LCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJG9uYmhfY29tcF9lZHUgPj0gY29sbGVnZV9xNzUsIDIsIE5BKSksDQogICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIsIA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kb25iaF9jb21wX2VkdSA8PSBub19jb2xsZWdlX3EyNSwgMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRvbmJoX2NvbXBfZWR1ID49IG5vX2NvbGxlZ2VfcTc1LCAyLCBOQSkpLCBOQSkpDQoNCiNtYWtlIGNhdGVnb3JpZXMgKGNvbWJpbmF0aW9uIG9mIHN1Ymdyb3VwIGFuZCBjb21wb3NpdGlvbikNCmRmdXJiYW4kZWR1Y25iaFRlcnQgPC0gaWZlbHNlKGRmdXJiYW4kVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSIgJiBkZnVyYmFuJGVkdWNuYmggPT0gMSwgIldpdGggY29sbGVnZSBkZWdyZWUsIGZldyB3aXRoIGNvbGxlZ2UgZGVncmVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRUZXJ0ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIiAmIGRmdXJiYW4kZWR1Y25iaCA9PSAyLCAiV2l0aCBjb2xsZWdlIGRlZ3JlZSwgbWFueSB3aXRoIGNvbGxlZ2UgZGVncmVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJFRlcnQgPT0gIldpdGhvdXQgY29sbGVnZSBkZWdyZWUiICYgZGZ1cmJhbiRlZHVjbmJoID09IDEsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlLCBmZXcgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiAmIGRmdXJiYW4kZWR1Y25iaCA9PSAyLCAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSwgbWFueSB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgTkEpKSkpDQojcmVvcmRlciBsZXZlbHMNCmRmdXJiYW4kZWR1Y25iaFRlcnQgPC0gZmFjdG9yKGRmdXJiYW4kZWR1Y25iaFRlcnQsIGxldmVscyA9IGMoIldpdGggY29sbGVnZSBkZWdyZWUsIGZldyB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgICJXaXRoIGNvbGxlZ2UgZGVncmVlLCBtYW55IHdpdGggY29sbGVnZSBkZWdyZWUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIGZldyB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIG1hbnkgd2l0aCBjb2xsZWdlIGRlZ3JlZSIpKQ0KDQojYWxzbyBmb3Igb3JnYW5pemF0aW9ucw0KZGZ1cmJhbiRlZHVjY2l2IDwtIE5BX3JlYWxfDQoNCiNkZWZpbmUgdGhlIHF1YXJ0aWxlcyBmb3IgZWFjaCBncm91cA0KY29sbGVnZV9xMjUgPC0gcXVhbnRpbGUoZGZ1cmJhbiRvY2l2X2NvbXBfZWR1W2RmdXJiYW4kVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSJdLCAwLjI1LCBuYS5ybSA9IFRSVUUpDQpjb2xsZWdlX3E3NSA8LSBxdWFudGlsZShkZnVyYmFuJG9jaXZfY29tcF9lZHVbZGZ1cmJhbiRUZXJ0ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIl0sIDAuNzUsIG5hLnJtID0gVFJVRSkNCm5vX2NvbGxlZ2VfcTI1IDwtIHF1YW50aWxlKGRmdXJiYW4kb2Npdl9jb21wX2VkdVtkZnVyYmFuJFRlcnQgPT0gIldpdGhvdXQgY29sbGVnZSBkZWdyZWUiXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0Kbm9fY29sbGVnZV9xNzUgPC0gcXVhbnRpbGUoZGZ1cmJhbiRvY2l2X2NvbXBfZWR1W2RmdXJiYW4kVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSJdLCAwLjc1LCBuYS5ybSA9IFRSVUUpDQoNCiNhcHBseSAgY29uZGl0aW9ucyBmb3Igc3ViZ3JvdXBzDQpkZnVyYmFuJGVkdWNjaXYgPC0gaWZlbHNlKGRmdXJiYW4kVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSIsIA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kb2Npdl9jb21wX2VkdSA8PSBjb2xsZWdlX3EyNSwgMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRvY2l2X2NvbXBfZWR1ID49IGNvbGxlZ2VfcTc1LCAyLCBOQSkpLA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJFRlcnQgPT0gIldpdGhvdXQgY29sbGVnZSBkZWdyZWUiLCANCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJG9jaXZfY29tcF9lZHUgPD0gbm9fY29sbGVnZV9xMjUsIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kb2Npdl9jb21wX2VkdSA+PSBub19jb2xsZWdlX3E3NSwgMiwgTkEpKSwgTkEpKQ0KDQojbWFrZSBjYXRlZ29yaWVzIChjb21iaW5hdGlvbiBvZiBzdWJncm91cCBhbmQgY29tcG9zaXRpb24pDQpkZnVyYmFuJGVkdWNjaXZUZXJ0IDwtIGlmZWxzZShkZnVyYmFuJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiICYgZGZ1cmJhbiRlZHVjY2l2ID09IDEsICJXaXRoIGNvbGxlZ2UgZGVncmVlLCBmZXcgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSIgJiBkZnVyYmFuJGVkdWNjaXYgPT0gMiwgIldpdGggY29sbGVnZSBkZWdyZWUsIG1hbnkgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiAmIGRmdXJiYW4kZWR1Y2NpdiA9PSAxLCAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSwgZmV3IHdpdGggY29sbGVnZSBkZWdyZWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIgJiBkZnVyYmFuJGVkdWNjaXYgPT0gMiwgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIG1hbnkgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsIE5BKSkpKQ0KI3Jlb3JkZXIgbGV2ZWxzDQpkZnVyYmFuJGVkdWNjaXZUZXJ0IDwtIGZhY3RvcihkZnVyYmFuJGVkdWNjaXZUZXJ0LCBsZXZlbHMgPSBjKCJXaXRoIGNvbGxlZ2UgZGVncmVlLCBmZXcgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsICAiV2l0aCBjb2xsZWdlIGRlZ3JlZSwgbWFueSB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlLCBmZXcgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlLCBtYW55IHdpdGggY29sbGVnZSBkZWdyZWUiKSkNCiNhZ2UNCmRmdXJiYW4kYWdlbmJoIDwtIE5BX3JlYWxfDQoNCiNkZWZpbmUgdGhlIHF1YXJ0aWxlcyBmb3IgZWFjaCBncm91cA0KYWdlX3EyNSA8LSBxdWFudGlsZShkZnVyYmFuJG9uYmhfY29tcF9hZ2VbZGZ1cmJhbiRBZ2UgPT0gIjUwIHllYXJzIG9yIG9sZGVyIl0sIDAuMjUsIG5hLnJtID0gVFJVRSkNCmFnZV9xNzUgPC0gcXVhbnRpbGUoZGZ1cmJhbiRvbmJoX2NvbXBfYWdlW2RmdXJiYW4kQWdlID09ICI1MCB5ZWFycyBvciBvbGRlciJdLCAwLjc1LCBuYS5ybSA9IFRSVUUpDQpuYWdlX3EyNSA8LSBxdWFudGlsZShkZnVyYmFuJG9uYmhfY29tcF9hZ2VbZGZ1cmJhbiRBZ2UgPT0gIkJlbG93IDUwIHllYXJzIl0sIDAuMjUsIG5hLnJtID0gVFJVRSkNCm5hZ2VfcTc1IDwtIHF1YW50aWxlKGRmdXJiYW4kb25iaF9jb21wX2FnZVtkZnVyYmFuJEFnZSA9PSAiQmVsb3cgNTAgeWVhcnMiXSwgMC43NSwgbmEucm0gPSBUUlVFKQ0KDQojYXBwbHkgIGNvbmRpdGlvbnMgZm9yIHN1Ymdyb3Vwcw0KZGZ1cmJhbiRhZ2VuYmggPC0gaWZlbHNlKGRmdXJiYW4kQWdlID09ICI1MCB5ZWFycyBvciBvbGRlciIsIA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kb25iaF9jb21wX2FnZSA8PSBhZ2VfcTI1LCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJG9uYmhfY29tcF9hZ2UgPj0gYWdlX3E3NSwgMiwgTkEpKSwNCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRBZ2UgPT0gIkJlbG93IDUwIHllYXJzIiwgDQogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRvbmJoX2NvbXBfYWdlIDw9IG5hZ2VfcTI1LCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJG9uYmhfY29tcF9hZ2UgPj0gbmFnZV9xNzUsIDIsIE5BKSksIE5BKSkNCg0KI21ha2UgY2F0ZWdvcmllcyAoY29tYmluYXRpb24gb2Ygc3ViZ3JvdXAgYW5kIGNvbXBvc2l0aW9uKQ0KZGZ1cmJhbiRhZ2VuYmhBZ2UgPC0gaWZlbHNlKGRmdXJiYW4kQWdlID09ICAiNTAgeWVhcnMgb3Igb2xkZXIiICYgZGZ1cmJhbiRhZ2VuYmggPT0gMSwgIjUwIHllYXJzIG9yIG9sZGVyLCBmZXcgNTAgeWVhcnMgb3Igb2xkZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiICYgZGZ1cmJhbiRhZ2VuYmggPT0gMiwgIjUwIHllYXJzIG9yIG9sZGVyLCBtYW55IDUwIHllYXJzIG9yIG9sZGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJEFnZSA9PSAgIkJlbG93IDUwIHllYXJzIiAmIGRmdXJiYW4kYWdlbmJoID09IDEsICJCZWxvdyA1MCB5ZWFycywgZmV3IDUwIHllYXJzIG9yIG9sZGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJEFnZSA9PSAgIkJlbG93IDUwIHllYXJzIiAmIGRmdXJiYW4kYWdlbmJoID09IDIsICJCZWxvdyA1MCB5ZWFycywgbWFueSA1MCB5ZWFycyBvciBvbGRlciIsIE5BKSkpKQ0KDQojcmVvcmRlciBsZXZlbHMNCmRmdXJiYW4kYWdlbmJoQWdlIDwtIGZhY3RvcihkZnVyYmFuJGFnZW5iaEFnZSwgbGV2ZWxzID0gYygiNTAgeWVhcnMgb3Igb2xkZXIsIGZldyA1MCB5ZWFycyBvciBvbGRlciIsICI1MCB5ZWFycyBvciBvbGRlciwgbWFueSA1MCB5ZWFycyBvciBvbGRlciIsICJCZWxvdyA1MCB5ZWFycywgZmV3IDUwIHllYXJzIG9yIG9sZGVyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCZWxvdyA1MCB5ZWFycywgbWFueSA1MCB5ZWFycyBvciBvbGRlciIpKQ0KDQojYWxzbyBmb3Igb3JnYW5pemF0aW9ucw0KZGZ1cmJhbiRhZ2VjaXYgPC0gTkFfcmVhbF8NCg0KI2RlZmluZSB0aGUgcXVhcnRpbGVzIGZvciBlYWNoIGdyb3VwDQphZ2VfcTI1IDwtIHF1YW50aWxlKGRmdXJiYW4kb2Npdl9jb21wX2FnZVtkZnVyYmFuJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0KYWdlX3E3NSA8LSBxdWFudGlsZShkZnVyYmFuJG9jaXZfY29tcF9hZ2VbZGZ1cmJhbiRBZ2UgPT0gIjUwIHllYXJzIG9yIG9sZGVyIl0sIDAuNzUsIG5hLnJtID0gVFJVRSkNCm5hZ2VfcTI1IDwtIHF1YW50aWxlKGRmdXJiYW4kb2Npdl9jb21wX2FnZVtkZnVyYmFuJEFnZSA9PSAiQmVsb3cgNTAgeWVhcnMiXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0KbmFnZV9xNzUgPC0gcXVhbnRpbGUoZGZ1cmJhbiRvY2l2X2NvbXBfYWdlW2RmdXJiYW4kQWdlID09ICJCZWxvdyA1MCB5ZWFycyJdLCAwLjc1LCBuYS5ybSA9IFRSVUUpDQoNCiNhcHBseSAgY29uZGl0aW9ucyBmb3Igc3ViZ3JvdXBzDQpkZnVyYmFuJGFnZWNpdiA8LSBpZmVsc2UoZGZ1cmJhbiRBZ2UgPT0gIjUwIHllYXJzIG9yIG9sZGVyIiwgDQogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRvY2l2X2NvbXBfYWdlIDw9IGFnZV9xMjUsIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kb2Npdl9jb21wX2FnZSA+PSBhZ2VfcTc1LCAyLCBOQSkpLA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJEFnZSA9PSAiQmVsb3cgNTAgeWVhcnMiLCANCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJG9jaXZfY29tcF9hZ2UgPD0gbmFnZV9xMjUsIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kb2Npdl9jb21wX2FnZSA+PSBuYWdlX3E3NSwgMiwgTkEpKSwgTkEpKQ0KDQojbWFrZSBjYXRlZ29yaWVzIChjb21iaW5hdGlvbiBvZiBzdWJncm91cCBhbmQgY29tcG9zaXRpb24pDQpkZnVyYmFuJGFnZWNpdkFnZSA8LSBpZmVsc2UoZGZ1cmJhbiRBZ2UgPT0gICI1MCB5ZWFycyBvciBvbGRlciIgJiBkZnVyYmFuJGFnZWNpdiA9PSAxLCAiNTAgeWVhcnMgb3Igb2xkZXIsIGZldyA1MCB5ZWFycyBvciBvbGRlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kQWdlID09ICI1MCB5ZWFycyBvciBvbGRlciIgJiBkZnVyYmFuJGFnZWNpdiA9PSAyLCAiNTAgeWVhcnMgb3Igb2xkZXIsIG1hbnkgNTAgeWVhcnMgb3Igb2xkZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kQWdlID09ICAiQmVsb3cgNTAgeWVhcnMiICYgZGZ1cmJhbiRhZ2VjaXYgPT0gMSwgIkJlbG93IDUwIHllYXJzLCBmZXcgNTAgeWVhcnMgb3Igb2xkZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kQWdlID09ICAiQmVsb3cgNTAgeWVhcnMiICYgZGZ1cmJhbiRhZ2VjaXYgPT0gMiwgIkJlbG93IDUwIHllYXJzLCBtYW55IDUwIHllYXJzIG9yIG9sZGVyIiwgTkEpKSkpDQoNCiNyZW9yZGVyIGxldmVscw0KZGZ1cmJhbiRhZ2VjaXZBZ2UgPC0gZmFjdG9yKGRmdXJiYW4kYWdlY2l2QWdlLCBsZXZlbHMgPSBjKCI1MCB5ZWFycyBvciBvbGRlciwgZmV3IDUwIHllYXJzIG9yIG9sZGVyIiwgIjUwIHllYXJzIG9yIG9sZGVyLCBtYW55IDUwIHllYXJzIG9yIG9sZGVyIiwgIkJlbG93IDUwIHllYXJzLCBmZXcgNTAgeWVhcnMgb3Igb2xkZXIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJlbG93IDUwIHllYXJzLCBtYW55IDUwIHllYXJzIG9yIG9sZGVyIikpDQoNCiNldGhuaWNpdHkNCmRmdXJiYW4kVE1uYmggPC0gTkFfcmVhbF8NCg0KI2ZvciBldGhuaWNpdHkgKCUgdHVya3MvbW9yb2NjYW5zKSwgdXNlIG1lYW4gc3BsaXQgKGdpdmVuIGhpZ2hseSBza2V3ZWQgZGlzdHJpYnV0aW9uKQ0KZGZ1cmJhbiRUTW5iaCA8LSBOQV9yZWFsXw0KDQojZGVmaW5lIG1lYW5zIGZvciBlYWNoIGdyb3VwDQpubV9tIDwtIG1lYW4oZGZ1cmJhbiRvbmJoX2NvbXBfZXRoW2RmdXJiYW4kVE0gPT0gIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIl0sIG5hLnJtID0gVFJVRSkNCm1fbSA8LSBtZWFuKGRmdXJiYW4kb25iaF9jb21wX2V0aFtkZnVyYmFuJFRNID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiXSwgbmEucm0gPSBUUlVFKQ0KDQojYXBwbHkgIGNvbmRpdGlvbnMgZm9yIHN1Ymdyb3Vwcw0KZGZ1cmJhbiRUTW5iaCA8LSBpZmVsc2UoZGZ1cmJhbiRUTSA9PSAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgDQogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRvbmJoX2NvbXBfZXRoIDwgbV9tLCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJG9uYmhfY29tcF9ldGggPj0gbV9tLCAyLCBOQSkpLA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJFRNID09ICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIsIA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kb25iaF9jb21wX2V0aCA8IG5tX20sIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kb25iaF9jb21wX2V0aCA+PSBubV9tLCAyLCBOQSkpLCBOQSkpDQoNCiNtYWtlIGNhdGVnb3JpZXMgKGNvbWJpbmF0aW9uIG9mIHN1Ymdyb3VwIGFuZCBjb21wb3NpdGlvbikNCmRmdXJiYW4kZXRobmJoVE0gPC0gaWZlbHNlKGRmdXJiYW4kVE0gPT0gICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiICYgZGZ1cmJhbiRUTW5iaCA9PSAxLCAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRUTSA9PSAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiAmIGRmdXJiYW4kVE1uYmggPT0gMiwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kVE0gPT0gICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIgJiBkZnVyYmFuJFRNbmJoID09IDEsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkVE0gPT0gICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIgJiBkZnVyYmFuJFRNbmJoID09IDIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCBOQSkpKSkNCg0KI3Jlb3JkZXIgbGV2ZWxzDQpkZnVyYmFuJGV0aG5iaFRNIDwtIGZhY3RvcihkZnVyYmFuJGV0aG5iaFRNLCBsZXZlbHMgPSBjKCJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQsIGZldyBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kLCBtYW55IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiKSkNCg0KI2Fsc28gZm9yIG9yZ2FuaXphdGlvbnMNCmRmdXJiYW4kVE1jaXYgPC0gTkFfcmVhbF8NCg0KI2ZvciBldGhuaWNpdHkgKCUgdHVya3MvbW9yb2NjYW5zKSwgdXNlIG1lYW4gc3BsaXQgKGdpdmVuIGhpZ2hseSBza2V3ZWQgZGlzdHJpYnV0aW9uKQ0KZGZ1cmJhbiRUTWNpdiA8LSBOQV9yZWFsXw0KDQojZGVmaW5lIG1lYW5zIGZvciBlYWNoIGdyb3VwDQpubV9tIDwtIG1lYW4oZGZ1cmJhbiRvY2l2X2NvbXBfZXRoW2RmdXJiYW4kVE0gPT0gIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIl0sIG5hLnJtID0gVFJVRSkNCm1fbSA8LSBtZWFuKGRmdXJiYW4kb2Npdl9jb21wX2V0aFtkZnVyYmFuJFRNID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiXSwgbmEucm0gPSBUUlVFKQ0KDQojYXBwbHkgIGNvbmRpdGlvbnMgZm9yIHN1Ymdyb3Vwcw0KZGZ1cmJhbiRUTWNpdiA8LSBpZmVsc2UoZGZ1cmJhbiRUTSA9PSAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgDQogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRvY2l2X2NvbXBfZXRoIDwgbV9tLCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJG9jaXZfY29tcF9ldGggPj0gbV9tLCAyLCBOQSkpLA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgIGlmZWxzZShkZnVyYmFuJFRNID09ICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIsIA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kb2Npdl9jb21wX2V0aCA8IG5tX20sIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kb2Npdl9jb21wX2V0aCA+PSBubV9tLCAyLCBOQSkpLCBOQSkpDQoNCiNtYWtlIGNhdGVnb3JpZXMgKGNvbWJpbmF0aW9uIG9mIHN1Ymdyb3VwIGFuZCBjb21wb3NpdGlvbikNCmRmdXJiYW4kZXRoY2l2VE0gPC0gaWZlbHNlKGRmdXJiYW4kVE0gPT0gICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiICYgZGZ1cmJhbiRUTWNpdiA9PSAxLCAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRUTSA9PSAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiAmIGRmdXJiYW4kVE1jaXYgPT0gMiwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmdXJiYW4kVE0gPT0gICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIgJiBkZnVyYmFuJFRNY2l2ID09IDEsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGZ1cmJhbiRUTSA9PSAgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiAmIGRmdXJiYW4kVE1jaXYgPT0gMiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBtYW55IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsIE5BKSkpKQ0KDQojcmVvcmRlciBsZXZlbHMNCmRmdXJiYW4kZXRoY2l2VE0gPC0gZmFjdG9yKGRmdXJiYW4kZXRoY2l2VE0sIGxldmVscyA9IGMoIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQsIG1hbnkgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBtYW55IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIpKQ0KDQojYWdlDQpubW1hZ2Vjb21wIDwtIGNyZWdnOjpjaihkZnVyYmFuWyFpcy5uYShkZnVyYmFuJGFnZW5iaEFnZSksIF0sIGVuYmhfY2hvaWNlIH4gZW5iaF9jb21wX2FnZSwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSAgfiBhZ2VuYmhBZ2UpDQpjbW1hZ2Vjb21wIDwtIGNyZWdnOjpjaihkZnVyYmFuWyFpcy5uYShkZnVyYmFuJGFnZWNpdkFnZSksIF0sIGVjaXZfY2hvaWNlIH4gZWNpdl9jb21wX2FnZSwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSAgfiBhZ2VjaXZBZ2UpDQpubW1hZ2Vjb21wJHNldHRpbmcgPC0gIk5laWdoYm9yaG9vZHMiDQpjbW1hZ2Vjb21wJHNldHRpbmcgPC0gIkNpdmljIG9yZ2FuaXphdGlvbnMiDQphZ2UyIDwtIHJiaW5kKG5tbWFnZWNvbXBbLTEyXSwgY21tYWdlY29tcFstMTJdKQ0KYWdlMiRzZXR0aW5nIDwtIGZhY3RvcihhZ2UyJHNldHRpbmcsIGxldmVscyA9IGMoIk5laWdoYm9yaG9vZHMiLCAiQ2l2aWMgb3JnYW5pemF0aW9ucyIpKQ0KDQpwYWdlIDwtIHBsb3QoYWdlMiwgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQlkiLCB4bGFiID0gIiAgIikgKw0KICBmYWNldF9ncmlkMihzZXR0aW5nfi4sIHN3aXRjaCA9ICJ5IikgKw0KICBsYWJzKHRpdGxlID0gIlNoYXJlIG9mIHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIikgKw0KICAgIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gc3ViKCIuKjogIiwgIiIsIGxldmVscyhhZ2UkbGV2ZWwpKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI0NDQ0NDQyIsICIjNjY2NjY2IiwgIiNGMEIzM0MiLCAiI0E2NzYwMCIpKSArIA0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dGJveF9zaW1wbGUocGFkZGluZyA9IG1hcmdpbig1LjUsIDUuNSwgNS41LCA1LjUpLCBtYXJnaW4gPSBtYXJnaW4oMCwgMCwgNS41LCAwKSwgZmlsbCA9ICJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDEsIHIgPSBncmlkOjp1bml0KDAsICJwdCIpLCBzaXplID0gOCkpDQoNCiNldGgNCm5tbWV0aGNvbXAgPC0gY3JlZ2c6OmNqKGRmdXJiYW5bIWlzLm5hKGRmdXJiYW4kZXRobmJoVE0pLCBdLCBlbmJoX2Nob2ljZSB+IGVuYmhfY29tcF9ldGgsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gIH4gZXRobmJoVE0pDQpjbW1ldGhjb21wIDwtIGNyZWdnOjpjaihkZnVyYmFuWyFpcy5uYShkZnVyYmFuJGV0aGNpdlRNKSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfZXRoLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9ICB+IGV0aGNpdlRNKQ0Kbm1tZXRoY29tcCRzZXR0aW5nIDwtICJOZWlnaGJvcmhvb2RzIg0KY21tZXRoY29tcCRzZXR0aW5nIDwtICJDaXZpYyBvcmdhbml6YXRpb25zIg0KZXRoMiA8LSByYmluZChubW1ldGhjb21wWy0xMl0sIGNtbWV0aGNvbXBbLTEyXSkNCmV0aDIkc2V0dGluZyA8LSBmYWN0b3IoZXRoMiRzZXR0aW5nLCBsZXZlbHMgPSBjKCJOZWlnaGJvcmhvb2RzIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiKSkNCg0KI2ZvciBzb21lIHJlYXNvbiBpIG5lZWQgdG8gcmV2ZXJzZSB0aGUgbGV2ZWxzIGFnYWluLi4uDQpldGgyJEJZIDwtIGZhY3RvcihldGgyJEJZLCBsZXZlbHMgPSBjKCJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQsIGZldyBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCAgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQsIGZldyBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQsIG1hbnkgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIikpIA0KDQpwZXRoIDwtIHBsb3QoZXRoMiwgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQlkiLCB4bGFiID0gIk1hcmdpbmFsIG1lYW4iKSArDQogIGZhY2V0X2dyaWQyKHNldHRpbmd+Liwgc3dpdGNoID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggVHVyay9Nb3JvYyBiYWNrZ3JvdW5kIikgKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IHN1YigiLio6ICIsICIiLCBsZXZlbHMoZXRoJGxldmVsKSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiNBMkQ0RjciLCAiIzFFODBDMCIsICIjRjJBMDY2IiwgIiNBNDNEMDAiKSkgKyANCiAgdGhlbWUoIA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0Ym94X3NpbXBsZShwYWRkaW5nID0gbWFyZ2luKDUuNSwgNS41LCA1LjUsIDUuNSksIG1hcmdpbiA9IG1hcmdpbigwLCAwLCA1LjUsIDApLCBmaWxsID0gImxpZ2h0Z3JleSIsIGxpbmV0eXBlID0gMSwgciA9IGdyaWQ6OnVuaXQoMCwgInB0IiksIHNpemUgPSA4KSkNCg0KI2VkdWMNCm5tbWVkdWNjb21wIDwtIGNyZWdnOjpjaihkZnVyYmFuWyFpcy5uYShkZnVyYmFuJGVkdWNuYmhUZXJ0KSwgXSwgZW5iaF9jaG9pY2UgfiBlbmJoX2NvbXBfZWR1YywgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSAgfiBlZHVjbmJoVGVydCkNCmNtbWVkdWNjb21wIDwtIGNyZWdnOjpjaihkZnVyYmFuWyFpcy5uYShkZnVyYmFuJGVkdWNjaXZUZXJ0KSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfZWR1YywgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSAgfiBlZHVjY2l2VGVydCkNCm5tbWVkdWNjb21wJHNldHRpbmcgPC0gIk5laWdoYm9yaG9vZHMiDQpjbW1lZHVjY29tcCRzZXR0aW5nIDwtICJDaXZpYyBvcmdhbml6YXRpb25zIg0KZWR1YzIgPC0gcmJpbmQobm1tZWR1Y2NvbXBbLTEyXSwgY21tZWR1Y2NvbXBbLTEyXSkNCmVkdWMyJHNldHRpbmcgPC0gZmFjdG9yKGVkdWMyJHNldHRpbmcsIGxldmVscyA9IGMoIk5laWdoYm9yaG9vZHMiLCAiQ2l2aWMgb3JnYW5pemF0aW9ucyIpKQ0KDQpwZWR1YyA8LSBwbG90KGVkdWMyLCB2bGluZSA9IDEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJCWSIsIHhsYWIgPSAiICAiKSArDQogIGZhY2V0X2dyaWQyKHNldHRpbmd+Liwgc3dpdGNoID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBzdWIoIi4qOiAiLCAiIiwgbGV2ZWxzKGVkdWMkbGV2ZWwpKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI0QxQ0U4RiIsICIjQTlBMDExIiwgIiMzMzk5Q0MiLCAiIzAwNEM4QyIpKSArIA0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dGJveF9zaW1wbGUocGFkZGluZyA9IG1hcmdpbig1LjUsIDUuNSwgNS41LCA1LjUpLCBtYXJnaW4gPSBtYXJnaW4oMCwgMCwgNS41LCAwKSwgZmlsbCA9ICJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDEsIHIgPSBncmlkOjp1bml0KDAsICJwdCIpLCBzaXplID0gOCkpDQoNCiNjb21iaW5lIHBsb3RzDQpjb21iaXBsb3QgPC0gZ2dwdWJyOjpnZ2FycmFuZ2UocGFnZSxwZXRoLHBlZHVjLCBuY29sID0gMywgdmp1c3QgPSAuOSkNCg0KI2NvbWJpbmUgYWxsIGluIG9uZQ0KcCA8LSBwbG90X2dyaWQoY29tYmlwbG90LCBsZWcxMjNhLCBhbGlnbiA9ICJoIiwgbnJvdz0yLCByZWxfaGVpZ2h0cyA9IGMoNC41LDEpKQ0KDQpwcmludChwKQ0KYGBgIA0KDQoNCiMjIyMgY29ycmVjdGVkDQoNCmBgYHtyLCBjbW1zX2N1cmludl9jb3JyLCBldmFsID0gRkFMU0V9IA0KZmJvb3QyIDwtIGZ1bmN0aW9uKGRhdGEsIGkpIHsNCiAgIyBzYW1wbGUgcmVzcG9uZGVudCBJRHMgd2l0aCByZXBsYWNlbWVudA0KICBpZHMgPC0gc2FtcGxlKHVuaXF1ZShkYXRhJGlkKSwgbGVuZ3RoKHVuaXF1ZShkYXRhJGlkKSksIHJlcGxhY2UgPSBUUlVFKQ0KICANCiAgIyBjcmVhdGUgYSBuZXcgZGF0YXNldCBieSBpdGVyYXRpbmcgb3ZlciBlYWNoIHNhbXBsZWQgaWQgYW5kIGJpbmRpbmcgdGhlIG1hdGNoaW5nIHJvd3MNCiAgZCA8LSBtYXBfZGZyKGlkcywgfiBkYXRhICU+JSBmaWx0ZXIoaWQgPT0gLngpKSANCg0KICBkYXRhc2V0cyA8LSBsaXN0KGRmWyFpcy5uYShkZiRyZXBfb3JnX2Nob2ljZSksIF0sIGRmWyFpcy5uYShkZiRyZXBfbmJoX2Nob2ljZSksIF0pDQogIHRhc2tzIDwtIGxpc3QoYygiZmlyc3Rfb3JnX2Nob2ljZSIsICJyZXBfb3JnX2Nob2ljZSIpLCBjKCJmaXJzdF9uYmhfY2hvaWNlIiwgInJlcF9uYmhfY2hvaWNlIikpDQogIGxhYmVscyA8LSBjKCJvcmdhbml6YXRpb25zIiwgIm5laWdoYm9yaG9vZHMiKQ0KICANCiAgc3dhcHBpbmcgPC0gbGlzdCgpDQogIGZvciAoaSBpbiAxOmxlbmd0aChkYXRhc2V0cykpIHsNCiAgICBkYXRhc2V0IDwtIGRhdGFzZXRzW1tpXV0NCiAgICBkYXRhc2V0JHJlcGNob2ljZSA8LSBpZmVsc2UoZGF0YXNldFtbdGFza3NbW2ldXVsxXV1dID09IGRhdGFzZXRbW3Rhc2tzW1tpXV1bMl1dXSwgMSwgMCkNCg0KICAgIGlycl9saXN0IDwtIGZfaXJyKGRhdGFzZXQpDQogICAgdGF1X2xpc3QgPC0gZl90YXUoaXJyX2xpc3QpDQoNCiAgICBzd2FwcGluZ1tbbGFiZWxzW2ldXV0gPC0gbGlzdCgiaXJyIiA9IGlycl9saXN0LCAidGF1IiA9IHRhdV9saXN0KQ0KICB9DQogIA0KICAjIGNhbGN1bGF0ZSBjb25kaXRpb25hbCBtYXJnaW5hbCBtZWFucyAobm93IGZvciBjb21iaW5hdGlvbiBzdWJncm91cCBhbmQgY29tcG9zaXRpb24gY3VycmVudCBzZXR0aW5nKToNCiAgeF92YXJzIDwtIGNiaW5kKGMoImFnZV9BZ2UiLCAiZXRoX1RNIiwgImVkdWNfVGVydCIpLCBjKCJhZ2UiLCAiZXRoIiwgImVkdWMiKSkNCiAgeV92YXJzIDwtIGMoImVuYmgiLCAiZWNpdiIpDQogIA0KICByZXN1bHRzIDwtIGRhdGEuZnJhbWUoKQ0KDQogIGZvcih4IGluIDE6bnJvdyh4X3ZhcnMpKSB7DQogICAgZm9yKHkgaW4geV92YXJzKSB7DQogICAgICANCiAgICAgICMgZm9ybXVsYSAgDQogICAgICBmIDwtIGFzLmZvcm11bGEoIHBhc3RlMCh5LCAiX2Nob2ljZSB+ICIsIHksICJfY29tcF8iLCB4X3ZhcnNbeCwyXSkpDQogICAgIA0KICAgICAgI3NwZWNpZnkgdGhlIGNvcnJlY3QgIkJZIiAvIHN1Ymdyb3VwaW5nIHZhcmlhYmxlIChkZXBlbmRpbmcgb24gWSkNCiAgICAgIGJ5eSA8LSBpZmVsc2UoeSA9PSAiZW5iaCIsIHN1YigiXyIsICJuYmgiLCB4X3ZhcnNbeCwxXSksDQogICAgICAgICAgICAgICAgICAgc3ViKCJfIiwgImNpdiIsIHhfdmFyc1t4LDFdKSkNCiAgICAgIGJ5IDwtIGFzLmZvcm11bGEocGFzdGUwKCJ+IiwgYnl5KSkNCiANCiAgICAgIGNtbXMgPC0gY3JlZ2c6OmNqKCBkWyFpcy5uYShkW2J5eV0pLCBdLCAjZXhjbHVkZSBtaXNzaW5ncyBvbiB0aGUgc3ViZ3JvdXBpbmcgdmFyaWFibGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm11bGEgPSBmLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IGJ5KQ0KICAgICAgI2JpbmQgcmVzdWx0cw0KICAgICAgcmVzdWx0cyA8LSByYmluZChyZXN1bHRzLCBjbW1zWywtMTJdKQ0KICAgICAgfQ0KICAgIH0NCiAgDQogICNjYWxjdWxhdGUgY29ycmVjdGVkIGNvbmRpdGlvbmFsIG1hcmdpbmFsIG1lYW4gKGZvciBzdWJncm91cHMpDQogIHJlc3VsdHMkZXN0aW1hdGVfY29yciA8LSBOQQ0KICAgIA0KICBmb3IgKGkgaW4gMTpucm93KHJlc3VsdHMpKSB7ICANCiAgICANCiAgICAjcmV0cmlldmUgc2V0dGluZyBhbmQgc3ViZ3JvdXANCiAgICBzZXR0aW5nIDwtIGlmZWxzZShyZXN1bHRzJG91dGNvbWVbaV0gPT0gImVuYmhfY2hvaWNlIiwgIm5laWdoYm9yaG9vZHMiLCAib3JnYW5pemF0aW9ucyIpDQogICAgc3ViZ3JvdXAgPC0gYXMuY2hhcmFjdGVyKHJlc3VsdHMkQllbaV0pDQoNCiAgICAjd2UgZGlkIG5vdCBlc3RpbWF0ZSBzd2FwcGluZyBlcnJvcnMgZm9yIGNvbWJpbmF0aW9ucyBvZiBzdWJncm91cCArIGNvbXBvc2l0aW9uIGN1cnJlbnQgc2V0dGluZywgYnV0IG9ubHkgZm9yIHRoZSAoZGVtb2dyYXBoaWMpIHN1Ymdyb3VwIC4uLg0KICAgICNzbyByZXRyaWV2ZSB0aGlzOg0KICAgIHN1Ymdyb3VwIDwtIHN1YigiLC4qIiwgIiIsIHN1Ymdyb3VwKQ0KDQogICAgI2dldCB0YXUNCiAgICB0YXUgPC0gc3dhcHBpbmdbW3NldHRpbmddXSR0YXVbc3ViZ3JvdXBdDQogICAgDQogICAgI2RlZmluZSBiaWFzIGNvcnJlY3RlZCBNTSAoZXEuIDExIG9mIENsYXl0b24gZXQgYWwuKQ0KICAgIHJlc3VsdHMkZXN0aW1hdGVfY29ycltpXSA8LSAocmVzdWx0cyRlc3RpbWF0ZVtpXSAtIHRhdSkgLyAoMSAtIDIqdGF1KQ0KICB9DQogIA0KICAjc2F2ZSByb3duYW1lcw0KICAjcm5hbWVzMiA8LSBwYXN0ZTAoIHJlc3VsdHMkb3V0Y29tZSwgIi0iLCByZXN1bHRzJGxldmVsLCAiLSIsIHJlc3VsdHMkQlkpDQogICNzYXZlKHJuYW1lczIsIGZpbGUgPSAiLi9kYXRhL3Jvd25hbWVzMi5SZGEiKQ0KICANCiAgcmV0dXJuKHJlc3VsdHMkZXN0aW1hdGVfY29ycikgIA0KfQ0KDQojZmJvb3QyKGRmKSN0ZXN0IGl0ZXJhdGlvbg0KDQpuQ29yZSA8LSBkZXRlY3RDb3JlcygpIC0gMSAjZGV0ZWN0IG51bWJlciBvZiBjb3JlcyAoa2VlcCBvbmUgZm9yIG90aGVyIHRhc2tzKQ0Kbkl0ZXIgPC0gMTAwMCAjbnVtYmVyIG9mIGJvb3RzdHJhcCBpdGVyYXRpb25zDQoNCiNzZXQgdXAgY2x1c3Rlcg0KbXljbCA8LSBtYWtlQ2x1c3RlcihyZXAoImxvY2FsaG9zdCIsIG5Db3JlKSkNCg0KI2xvYWQgbmVjZXNzYXJ5IGxpYnJhcnkgb24gZWFjaCBjbHVzdGVyIG5vZGUNCmNsdXN0ZXJFdmFsUShteWNsLCB7DQogIGxpYnJhcnkoY3JlZ2cpDQogIGxpYnJhcnkocHVycnIpDQogIGxpYnJhcnkoZHBseXIpDQp9KQ0KDQojY29weSBkYXRhIGFuZCBjdXN0b20gZnVuY3Rpb25zIHRvIGVhY2ggbm9kZSdzIHdvcmtzcGFjZQ0KY2x1c3RlckV4cG9ydChteWNsLCB2YXJsaXN0PWMoImRmIiwgImZfdGF1IiwgImZfaXJyIiwgImZib290IikpIA0KDQojcGVyZm9ybSBib290c3RyYXA6DQpzeXN0ZW0udGltZSh0ZXN0IDwtIGJvb3QoZGYsIGZib290MiwgUj1uSXRlciwgcGFyYWxsZWwgPSAic25vdyIsIG5jcHVzID0gbkNvcmUsIGNsID0gbXljbCkpICNhYm91dCAzIGhvdXJzIG9uIG15IHBjDQoNCiNzYXZlKHRlc3QsIGZpbGUgPSAiLi9yZXN1bHRzL2Jvb3QyLlJkYSIpDQpzdG9wQ2x1c3RlcihteWNsKQ0KYGBgIA0KDQpgYGB7ciwgY21tc19jdXJpbnZfY29ycl9wbG90LCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0gDQpsb2FkKCIuL3Jlc3VsdHMvYm9vdDIuUmRhIikNCmxvYWQoIi4vZGF0YS9yb3duYW1lczIuUmRhIikNCg0KdGVzdDEgPC0gc3VtbWFyeSh0ZXN0KQ0Kcm93bmFtZXModGVzdDEpIDwtIHJuYW1lczINCiNwcmludCh0ZXN0MSkNCg0KI2ZpcnN0IGFkZCB0aGUgb3JpZ2luYWwgYmlhcyBjb3JyZWN0ZWQgQ01NcyB0byB0aGUgZGF0YWZyYW1lOg0KI2NyZWF0ZSBhIG1lcmdlIHZhcmlhYmxlIGluIHRoZSBvcmlnaW5hbCBDTU0gZGF0YWZyYW1lDQptbXMgPC0gcmJpbmQoYWdlLCBldGgsIGVkdWMpDQptbXMkQlkyIDwtIHBhc3RlMChtbXMkb3V0Y29tZSwgIi0iLCBtbXMkbGV2ZWwsICItIiwgbW1zJEJZKQ0KDQojcmVvcmRlcg0KbW1zIDwtIG1tc1ttYXRjaChyb3duYW1lcyh0ZXN0MSksIG1tcyRCWTIpLF0NCg0KI25vdyBjYWxjdWxhdGUgdGhlIGNvcnJlY3RlZCBDTU1TDQpmb3IgKGkgaW4gMTpucm93KG1tcykpIHsgIyBmb3IgZWFjaCBDTU0NCiAgICAjcmV0cmlldmUgc2V0dGluZyBhbmQgc3ViZ3JvdXANCiAgICBzZXR0aW5nIDwtIGlmZWxzZShtbXMkb3V0Y29tZVtpXSA9PSAiZW5iaF9jaG9pY2UiLCAibmVpZ2hib3Job29kcyIsICJvcmdhbml6YXRpb25zIikNCiAgICBzdWJncm91cCA8LSBhcy5jaGFyYWN0ZXIobW1zJEJZW2ldKQ0KICAgIHN1Ymdyb3VwIDwtIHN1YigiLC4qIiwgIiIsIHN1Ymdyb3VwKQ0KICAgIA0KICAgICNnZXQgdGF1IGZyb20gb3VyIHNhdmVkIGxpc3QNCiAgICB0YXUgPC0gc3dhcHBpbmdMaXN0W1tzZXR0aW5nXV0kdGF1W3N1Ymdyb3VwXQ0KICAgICNkZWZpbmUgYmlhcyBjb3JyZWN0ZWQgTU0gKGVxLiAxMSBvZiBDbGF5dG9uIGV0IGFsLikNCiAgICBtbXMkZXN0aW1hdGVfY29ycltpXSA8LSAobW1zJGVzdGltYXRlW2ldIC0gdGF1KSAvICgxIC0gMip0YXUpDQp9DQoNCiNjYWxjdWxhdGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIGJvb3RzdHJhcCBzdGF0aXN0aWNzDQpmb3IgKGkgaW4gMTpucm93KHRlc3QxKSkgew0KICBpZih0ZXN0MSRSW2ldIDwgbkl0ZXIpIHsNCiAgICBzdGF0IDwtIHRlc3QkdFssaV0NCiAgICB0ZXN0MSRib290U0VbaV0gPC0gc2Qoc3RhdFshaXMubmEoc3RhdCkgJiBpcy5maW5pdGUoc3RhdCldKQ0KICB9DQp9DQoNCiNhZGQgdGhlc2Ugc3RhdGlzdGljcyB0byBwbG90dGluZyBkYXRhDQojY3JlYXRlIGNvcHkgb2YgbW1zDQptbXNfY29yciA8LSBtbXMNCiN1c2UgY29ycmVjdGVkIGVzdGltYXRlcw0KbW1zX2NvcnIkZXN0aW1hdGUgPC0gbW1zX2NvcnIkZXN0aW1hdGVfY29ycg0KI3dpdGggYm9vdHN0cmFwcGVkIHN0YW5kYXJkIGVycm9ycw0KbW1zX2NvcnIkc3RkLmVycm9yIDwtIHRlc3QxJGJvb3RTRQ0KI2FuZCBjb25maWRlbmNlIGludGVydmFscw0KbW1zX2NvcnIkdXBwZXIgPC0gbW1zX2NvcnIkZXN0aW1hdGUgKyAxLjk2Km1tc19jb3JyJHN0ZC5lcnJvcg0KbW1zX2NvcnIkbG93ZXIgPC0gbW1zX2NvcnIkZXN0aW1hdGUgLSAxLjk2Km1tc19jb3JyJHN0ZC5lcnJvcg0KDQojcmVkbyB0aGUgcGxvdHM6DQpwYWdlIDwtIHBsb3QobW1zX2NvcnJbZ3JlcCgiYWdlIiwgbW1zX2NvcnIkZmVhdHVyZSApLCBdLCB2bGluZSA9IDEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJCWSIsIHhsYWIgPSAiICIpICsNCiAgZmFjZXRfZ3JpZDIoc2V0dGluZ34uLCBzd2l0Y2ggPSAieSIpICsNCiAgbGFicyh0aXRsZSA9ICJTaGFyZSBvZiBwZW9wbGUgYWdlZCA1MCB5ZWFycyBvciBvbGRlciIpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBzdWIoIi4qOiAiLCAiIiwgbW1zX2NvcnIkbGV2ZWxbZ3JlcCgiYWdlIiwgbW1zJGZlYXR1cmUgKSBdKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI0NDQ0NDQyIsICIjNjY2NjY2IiwgIiNGMEIzM0MiLCAiI0E2NzYwMCIpKSArIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIsIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHRib3hfc2ltcGxlKHBhZGRpbmcgPSBtYXJnaW4oNS41LCA1LjUsIDUuNSwgNS41KSwgbWFyZ2luID0gbWFyZ2luKDAsIDAsIDUuNSwgMCksIGZpbGwgPSAibGlnaHRncmV5IiwgbGluZXR5cGUgPSAxLCByID0gZ3JpZDo6dW5pdCgwLCAicHQiKSwgc2l6ZSA9IDgpKQ0KDQojIGhlcmUsIGxlYXZlIG91dCBUTSwgYmVjYXVzZSBvZiBsYXJnZSB1bmNlcnRhaW50eQ0KcGV0aCA8LSBwbG90KG1tc19jb3JyW2dyZXAoImV0aCIsIG1tc19jb3JyJGZlYXR1cmUpW2MoNzoxMiwgMTk6MjQpXSxdLCB2bGluZSA9IDEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJCWSIsIHhsYWIgPSAiTWFyZ2luYWwgbWVhbiIpICsNCiAgZmFjZXRfZ3JpZDIoc2V0dGluZ34uLCBzd2l0Y2ggPSAieSIpICsNCiAgbGFicyh0aXRsZSA9ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiKSArDQogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gc3ViKCIuKjogIiwgIiIsIG1tc19jb3JyJGxldmVsW2dyZXAoImV0aCIsIG1tcyRmZWF0dXJlICkgXSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoICIjRjJBMDY2IiwgIiNBNDNEMDAiKSkgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dGJveF9zaW1wbGUocGFkZGluZyA9IG1hcmdpbig1LjUsIDUuNSwgNS41LCA1LjUpLCBtYXJnaW4gPSBtYXJnaW4oMCwgMCwgNS41LCAwKSwgZmlsbCA9ICJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDEsIHIgPSBncmlkOjp1bml0KDAsICJwdCIpLCBzaXplID0gOCkpDQoNCnBlZHVjIDwtIHBsb3QobW1zX2NvcnJbZ3JlcCgiZWR1YyIsIG1tc19jb3JyJGZlYXR1cmUgKSwgXSwgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQlkiLCB4bGFiID0gIiAiKSArDQogIGZhY2V0X2dyaWQyKHNldHRpbmd+Liwgc3dpdGNoID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBzdWIoIi4qOiAiLCAiIiwgbW1zX2NvcnIkbGV2ZWxbZ3JlcCgiZWR1YyIsIG1tcyRmZWF0dXJlICkgXSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiNEMUNFOEYiLCAiI0E5QTAxMSIsICIjMzM5OUNDIiwgIiMwMDRDOEMiKSkgKyANCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIsIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHRib3hfc2ltcGxlKHBhZGRpbmcgPSBtYXJnaW4oNS41LCA1LjUsIDUuNSwgNS41KSwgbWFyZ2luID0gbWFyZ2luKDAsIDAsIDUuNSwgMCksIGZpbGwgPSAibGlnaHRncmV5IiwgbGluZXR5cGUgPSAxLCByID0gZ3JpZDo6dW5pdCgwLCAicHQiKSwgc2l6ZSA9IDgpKQ0KDQoNCiNjb21iaW5lIHdpdGggY3VzdG9tIGxlZ2VuZHM6DQoNCiNmaXJzdCwgcmVtb3ZlIGV0aG5pYyBtaW5vcml0eSBmb3IgY3VzdG9tIGxlZ2VuZCAoYmVjYXVzZSB3ZSByZW1vdmVkIGVzdGltYXRlcyBmcm9tIHRoZSBwbG90KQ0Kc3BsaXQycC5uVE0gPC0gZ2dwbG90KGV0aFstZ3JlcCgiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kLCIsIGV0aCRCWSksXSwgYWVzKHggPSBlc3RpbWF0ZSwgeSA9IGxldmVsLCBjb2xvciA9IFN1Ymdyb3VwICkpICsgZ2VvbV9wb2ludCgpICsgbGFicyhjb2xvciA9ICJTdWJncm91cCwgY3VycmVudCBzZXR0aW5nOiIpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJldihjKCIjRjJBMDY2IiwgIiNBNDNEMDAiKSkpICsgdGhlbWVfYncoKQ0KDQojcmV0cmlldmUgbGVnZW5kDQpsZWcyLm5UTSA8LSBnZXRfbGVnZW5kKHNwbGl0MnAublRNKQ0KDQojY3JlYXRlIG5ldyBjb21iaW5lZCBsZWdlbmQNCmxlZzEyMy5uVE0gPC0gcGxvdF9ncmlkKGxlZzEsbGVnMi5uVE0sbGVnMywgbnJvdz0xLCBhbGlnbj0iaCIpDQoNCiNjb21iaW5lIGFsbCBpbiBvbmUNCmNvbWJpcGxvdCA8LSBnZ3B1YnI6OmdnYXJyYW5nZShwYWdlLHBldGgscGVkdWMsIG5jb2wgPSAzLCB2anVzdCA9IC45KQ0KIA0KI2FuZCBhZGQgY3VzdG9tIGxlZ2VuZA0KcCA8LSBwbG90X2dyaWQoY29tYmlwbG90LCBsZWcxMjMublRNLCBhbGlnbiA9ICJoIiwgbnJvdz0yLCByZWxfaGVpZ2h0cyA9IGMoNC41LDEpKQ0KDQojc2F2ZQ0KI2dnc2F2ZSgiLi9maWd1cmVzL2NtbXNfbGlzc19jdXJyZW50X2NvcnJlY3RlZC5wbmciLCBwLCB3aWR0aD0xMykgDQoNCiNwbG90KHApDQoNCiMjIyBBTFRFUk5BVElWRSBQUkVTRU5UQVRJT04gIyMjDQptbXNfY29yciRTdWJncm91cCAgPC0gc3ViKCIsLioiLCAiIiwgbW1zX2NvcnIkU3ViZ3JvdXApDQoNCm1tc19jb3JyJEN1cnJlbnQgPC0gTkENCm1tc19jb3JyJEN1cnJlbnRbbW1zX2NvcnIkU3ViZ3JvdXAgJWluJSBjKCI1MCB5ZWFycyBvciBvbGRlciIsICJCZWxvdyA1MCB5ZWFycyIpXSA8LSBpZmVsc2UoZ3JlcGwoImZldyIsIG1tc19jb3JyJEJZW21tc19jb3JyJFN1Ymdyb3VwICVpbiUgYygiNTAgeWVhcnMgb3Igb2xkZXIiLCAiQmVsb3cgNTAgeWVhcnMiKV0pLCAiRmV3IHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIiwgIk1hbnkgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiICkNCg0KbW1zX2NvcnIkQ3VycmVudFttbXNfY29yciRTdWJncm91cCAlaW4lIGMoIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIpXSA8LSBpZmVsc2UoZ3JlcGwoImZldyIsIG1tc19jb3JyJEJZW21tc19jb3JyJFN1Ymdyb3VwICVpbiUgYygiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIildKSwgIkZldyBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiLCAiTWFueSBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiKSANCg0KbW1zX2NvcnIkQ3VycmVudFttbXNfY29yciRTdWJncm91cCAlaW4lIGMoIldpdGggY29sbGVnZSBkZWdyZWUiLCAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIpXSA8LSBpZmVsc2UoZ3JlcGwoImZldyIsIG1tc19jb3JyJEJZW21tc19jb3JyJFN1Ymdyb3VwICVpbiUgYygiV2l0aCBjb2xsZWdlIGRlZ3JlZSIsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIildKSwgIkZldyBwZW9wbGUgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsICJNYW55IHBlb3BsZSB3aXRoIGNvbGxlZ2UgZGVncmVlIikNCg0KbW1zX2NvcnIkT3V0Y29tZSA8LSBmYWN0b3IoaWZlbHNlKG1tc19jb3JyJG91dGNvbWUgPT0gImVjaXZfY2hvaWNlIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiLCAiTmVpZ2hib3Job29kcyIpLA0KICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJOZWlnaGJvcmhvb2RzIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiKSkNCg0KI3N1YnNldCBkYXRhc2V0cyBmb3IgZWFjaCBkaW1lbnNpb25zDQphZ2UgPC0gbW1zX2NvcnJbZ3JlcCgiYWdlIiwgbW1zX2NvcnIkZmVhdHVyZSApLCBdDQpldGggPC0gbW1zX2NvcnJbZ3JlcCgiZXRoIiwgbW1zX2NvcnIkZmVhdHVyZSApLCBdDQplZHUgPC0gbW1zX2NvcnJbZ3JlcCgiZWR1IiwgbW1zX2NvcnIkZmVhdHVyZSApLCBdDQoNCiNzcGVjaWZ5IGZlYXR1cmUNCmFnZSRGZWF0dXJlIDwtICJTaGFyZSBvZiBwZW9wbGUgYWdlZCA1MCB5ZWFycyBvciBvbGRlciINCmV0aCRGZWF0dXJlIDwtICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiDQplZHUkRmVhdHVyZSA8LSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSINCg0KcGxvdF9hZ2UgPC0gcGxvdChhZ2UsIHZsaW5lID0gMS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIkN1cnJlbnQiLCB4bGFiID0gIk1hcmdpbmFsIG1lYW4iKSArDQogIGZhY2V0X25lc3RlZChPdXRjb21lICsgU3ViZ3JvdXAgfiBGZWF0dXJlLCBzY2FsZXMgPSAiZnJlZV95IiwgaW5kZXBlbmRlbnQgPSAieSIsIHN3aXRjaCA9ICJ5IikgKyAgDQogIGdlb21fdGV4dCggYWVzKGxhYmVsID0gc3ByaW50ZigiJTAuMmYgKCUwLjJmKSIsIGVzdGltYXRlLCBzdGQuZXJyb3IpKSwgc2l6ZSA9IDMsIGNvbG91ciA9ICJibGFjayIsIHZqdXN0ID0gLTEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGVbYygxLDIpXSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIGxpbWl0cyA9IGMoLjMsLjcpLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkgKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IGMoImhhbGYgKDUwJSkiLCAianVzdCB1bmRlciBoYWxmICg0MCUpIiwgImEgcXVhcnRlciAoMjUlKSIpKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwNCiAgICAgICAjIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfbWFya2Rvd24oKSwNCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQ0KDQpwbG90X2V0aCA8LSBwbG90KGV0aCwgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQ3VycmVudCIsIHhsYWIgPSAiTWFyZ2luYWwgbWVhbiIpICsNCiAgZmFjZXRfbmVzdGVkKE91dGNvbWUgKyBTdWJncm91cCB+IEZlYXR1cmUsIHNjYWxlcyA9ICJmcmVlX3kiLCBpbmRlcGVuZGVudCA9ICJ5Iiwgc3dpdGNoID0gInkiKSArICANCiAgZ2VvbV90ZXh0KCBhZXMobGFiZWwgPSBzcHJpbnRmKCIlMC4yZiAoJTAuMmYpIiwgZXN0aW1hdGUsIHN0ZC5lcnJvcikpLCBzaXplID0gMywgY29sb3VyID0gImJsYWNrIiwgdmp1c3QgPSAtMSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZVtjKDEsMildKSArDQogIHNjYWxlX3hfY29udGludW91cyggbGltaXRzID0gYygtMC4yLDEpLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkgKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IGMoImEgcXVhcnRlciAoMjUlKSIsICJtaW5vcml0eSAoMTAlKSIsICJub25lICgwJSkiKSkgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIsDQogICAgICAgIyBzdHJpcC50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKCksDQogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikNCg0KcGxvdF9lZHVjIDwtIHBsb3QoZWR1LCB2bGluZSA9IDEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJDdXJyZW50IiwgeGxhYiA9ICJNYXJnaW5hbCBtZWFuIikgKw0KICBmYWNldF9uZXN0ZWQoT3V0Y29tZSArIFN1Ymdyb3VwIH4gRmVhdHVyZSwgc2NhbGVzID0gImZyZWVfeSIsIGluZGVwZW5kZW50ID0gInkiLCBzd2l0Y2ggPSAieSIpICsgIA0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMSwyKV0pICsNCiAgc2NhbGVfeF9jb250aW51b3VzKCBsaW1pdHMgPSBjKDAuMjUsLjcpLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkgKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9ICBjKCJ0aHJlZSBxdWFydGVycyAoNzUlKSIsICJoYWxmICg1MCUpIiwgImEgcXVhcnRlciAoMjUlKSIpKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwNCiAgICAgICAjIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfbWFya2Rvd24oKSwNCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQ0KDQojY29tYmluZSBhbGwgaW4gb25lDQpjb21iaXBsb3QgPC0gZ2dwdWJyOjpnZ2FycmFuZ2UocGxvdF9hZ2UsIHBsb3RfZXRoLCBwbG90X2VkdWMsIG5jb2w9MykNCiANCiNhZGQgbGVnZW5kDQojZmlyc3QgcmVvcmRlciBncm91cCBmYWN0b3INCmFnZSRDdXJyZW50IDwtIGZhY3RvcihhZ2UkQ3VycmVudCwgbGV2ZWxzID0gYygiTWFueSBwZW9wbGUgYWdlZCA1MCB5ZWFycyBvciBvbGRlciIsICJGZXcgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiKSkNCmV0aCRDdXJyZW50IDwtIGZhY3RvcihldGgkQ3VycmVudCwgbGV2ZWxzID0gYygiTWFueSBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiLCAiRmV3IHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIpKQ0KZWR1JEN1cnJlbnQgPC0gZmFjdG9yKGVkdSRDdXJyZW50LCBsZXZlbHMgPSBjKCJNYW55IHBlb3BsZSB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgIkZldyBwZW9wbGUgd2l0aCBjb2xsZWdlIGRlZ3JlZSIpKQ0KDQpsZWcxIDwtIGdldF9sZWdlbmQoZ2dwbG90KGFnZSwgYWVzKHggPSBlc3RpbWF0ZSwgeSA9IGxldmVsLCBjb2xvciA9IEN1cnJlbnQpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgbGFicyhjb2xvciA9ICJDdXJyZW50IHNldHRpbmc6IikgKyANCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZVtjKDIsMSldKSArDQogIHRoZW1lX2J3KCkpDQoNCmxlZzIgPC0gZ2V0X2xlZ2VuZChnZ3Bsb3QoZXRoLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gbGV2ZWwsIGNvbG9yID0gQ3VycmVudCkpICsgDQogIGdlb21fcG9pbnQoKSArIA0KICBsYWJzKGNvbG9yID0gIkN1cnJlbnQgc2V0dGluZzoiKSArIA0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMiwxKV0pICsNCiAgdGhlbWVfYncoKSkNCg0KbGVnMyA8LSBnZXRfbGVnZW5kKGdncGxvdChlZHUsIGFlcyh4ID0gZXN0aW1hdGUsIHkgPSBsZXZlbCwgY29sb3IgPSBDdXJyZW50KSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGxhYnMoY29sb3IgPSAiQ3VycmVudCBzZXR0aW5nOiIpICsgDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGVbYygyLDEpXSkgKw0KICB0aGVtZV9idygpKQ0KDQpsZWcxMjMgPC0gcGxvdF9ncmlkKGxlZzEsbGVnMixsZWczLCBucm93PTEsIGFsaWduPSJoIikNCg0KcCA8LSBwbG90X2dyaWQoY29tYmlwbG90LCBsZWcxMjMsIGFsaWduID0gImgiLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYygxMCwxKSkNCiNwbG90KHApDQoNCiNnZ3NhdmUoIi4vZmlndXJlcy9jbW1zX2N1cnJlbnRfY29ycl9hbHRlcm5hdGl2ZS5wbmciLCBwLCB3aWR0aD0xNCwgaGVpZ2h0PTEwKSANCmdnc2F2ZSgiLi9maWd1cmVzL2ZpZ3VyZTAzX3N1cHBsZW1lbnQucG5nIiwgcCwgd2lkdGg9MTQsIGhlaWdodD0xMCkgDQpgYGAgICANCg0KIVsqKkZpZ3VyZSAzIChTdXBwbGVtZW50KTogTWFyZ2luYWwgbWVhbnMgb2YgbmVpZ2hib3Job29kc+KAmSBhbmQgb3JnYW5pemF0aW9uc+KAmSBzb2NpYWwgY29tcG9zaXRpb24gYXR0cmlidXRlcyBieSByZXNwb25kZW50c+KAmSBhZ2UsIGV0aG5pY2l0eSwgYW5kIGVkdWNhdGlvbiBsZXZlbCBhbmQgdGhlIGNvbXBvc2l0aW9uIG9mIHRoZWlyIGN1cnJlbnQgbmVpZ2hib3Job29kcyBhbmQgY2l2aWMgb3JnYW5pemF0aW9ucyAoRXhwZXJpbWVudHMgMSBhbmQgMikuKipdKC4vZmlndXJlcy9maWd1cmUwM19zdXBwbGVtZW50LnBuZykNCg0KYGBge3IsIGNtbXNfY3VyaW52X2NvcnJfcGxvdDIsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KIyMjIE5PVyBPTkxZICdUT1AgUk9XIGluIGVhY2ggcm93JzsgZm9yIHRoZSBNQUlOIFRFWFQgIyMjDQphZ2Vfc3ViIDwtIGFnZVthZ2UkU3ViZ3JvdXAgPT0gIjUwIHllYXJzIG9yIG9sZGVyIiwgXQ0KYWdlX3N1YiRDdXJyZW50IDwtIGZhY3RvcihhZ2Vfc3ViJEN1cnJlbnQsIGxldmVscyA9IHJldihsZXZlbHMoYWdlX3N1YiRDdXJyZW50KSkgKQ0KDQpwbG90X2FnZV9zdWIgPC0gcGxvdChhZ2Vfc3ViLCB2bGluZSA9IDEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJDdXJyZW50IiwgeGxhYiA9ICJNYXJnaW5hbCBtZWFuIikgKw0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0yLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBmYWNldF93cmFwKH5PdXRjb21lLCBucm93ID0gMiwgc2NhbGVzID0gImZyZWVfeSIsIHN3aXRjaCA9ICJ5IikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMSwyKV0pICsgDQogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gYygiaGFsZiAoNTAlKSIsICJqdXN0IHVuZGVyIGhhbGYgKDQwJSkiLCAiYSBxdWFydGVyICgyNSUpIikpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLjMzLC42MiksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSArDQogIGxhYnModGl0bGUgPSAiU2hhcmUgb2YgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiLCBzdWJ0aXRsZSA9ICIqKlJlc3BvbmRlbnRzIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIqKiIpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIsIA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHRib3hfc2ltcGxlKA0KICAgICAgcGFkZGluZyA9IG1hcmdpbig1LjUsIDUuNSwgNS41LCA1LjUpLCANCiAgICAgIG1hcmdpbiA9IG1hcmdpbigwLCAwLCA1LjUsIDApLCANCiAgICAgIGZpbGwgPSAibGlnaHRncmV5IiwgDQogICAgICBsaW5ldHlwZSA9IDEsDQogICAgICByID0gZ3JpZDo6dW5pdCgwLCAicHQiKSwgDQogICAgICBzaXplID0gOCksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dGJveF9zaW1wbGUoDQogICAgICBwYWRkaW5nID0gbWFyZ2luKDUuNSwgNS41LCA1LjUsIDUuNSksIA0KICAgICAgbWFyZ2luID0gbWFyZ2luKDAsIDAsIDUuNSwgMCksIA0KICAgICAgZmlsbCA9ICJsaWdodGdyZXkiLCANCiAgICAgIGxpbmV0eXBlID0gMSwNCiAgICAgIHIgPSBncmlkOjp1bml0KDAsICJwdCIpLCANCiAgICAgIHNpemUgPSA4DQogICAgKQ0KICApDQoNCmV0aF9zdWIgPC0gZXRoWyBldGgkU3ViZ3JvdXAgPT0gIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIixdDQpldGhfc3ViJEN1cnJlbnQgPC0gZmFjdG9yKGV0aF9zdWIkQ3VycmVudCwgbGV2ZWxzID0gcmV2KGxldmVscyhldGhfc3ViJEN1cnJlbnQpKSApDQoNCnBsb3RfZXRoX3N1YiA8LSBwbG90KGV0aF9zdWIsIHZsaW5lID0gMS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIkN1cnJlbnQiLCB4bGFiID0gIk1hcmdpbmFsIG1lYW4iKSArDQogIGdlb21fdGV4dCggYWVzKGxhYmVsID0gc3ByaW50ZigiJTAuMmYgKCUwLjJmKSIsIGVzdGltYXRlLCBzdGQuZXJyb3IpKSwgc2l6ZSA9IDMsIGNvbG91ciA9ICJibGFjayIsIHZqdXN0ID0gLTIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArDQogICAgZmFjZXRfd3JhcCh+T3V0Y29tZSwgbnJvdyA9IDIsIHNjYWxlcyA9ICJmcmVlX3kiLCBzd2l0Y2ggPSAieSIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZVtjKDIsMSldKSArICNoZXJlIHN3aXRjaCB0aGUgY29sb3JzISAoeWVsbG93ID09IGxpdHRsZSBvdXRncm91cCBleHBvc3VyZSkgDQogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gYygiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIiwgIm5vbmUgKDAlKSIpKSArDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC4yNywuNjUpLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkgKw0KICBsYWJzKHRpdGxlID0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIsIHN1YnRpdGxlID0gIioqUmVzcG9uZGVudHMgd2l0aCBubyBtaWdyYXRpb24gYmFja2dyb3VuZCoqIikgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwgDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dGJveF9zaW1wbGUoDQogICAgICBwYWRkaW5nID0gbWFyZ2luKDUuNSwgNS41LCA1LjUsIDUuNSksIA0KICAgICAgbWFyZ2luID0gbWFyZ2luKDAsIDAsIDUuNSwgMCksIA0KICAgICAgZmlsbCA9ICJsaWdodGdyZXkiLCANCiAgICAgIGxpbmV0eXBlID0gMSwNCiAgICAgIHIgPSBncmlkOjp1bml0KDAsICJwdCIpLCANCiAgICAgIHNpemUgPSA4KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0Ym94X3NpbXBsZSgNCiAgICAgIHBhZGRpbmcgPSBtYXJnaW4oNS41LCA1LjUsIDUuNSwgNS41KSwgDQogICAgICBtYXJnaW4gPSBtYXJnaW4oMCwgMCwgNS41LCAwKSwgDQogICAgICBmaWxsID0gImxpZ2h0Z3JleSIsIA0KICAgICAgbGluZXR5cGUgPSAxLA0KICAgICAgciA9IGdyaWQ6OnVuaXQoMCwgInB0IiksIA0KICAgICAgc2l6ZSA9IDgNCiAgICApDQogICkNCg0KZWR1X3N1YiA8LSBlZHVbZWR1JFN1Ymdyb3VwID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIixdDQplZHVfc3ViJEN1cnJlbnQgPC0gZmFjdG9yKGVkdV9zdWIkQ3VycmVudCwgbGV2ZWxzID0gcmV2KGxldmVscyhlZHVfc3ViJEN1cnJlbnQpKSApDQoNCnBsb3RfZWR1X3N1YiA8LSBwbG90KGVkdV9zdWIsIHZsaW5lID0gMS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIkN1cnJlbnQiLCB4bGFiID0gIk1hcmdpbmFsIG1lYW4iKSArDQogIGdlb21fdGV4dCggYWVzKGxhYmVsID0gc3ByaW50ZigiJTAuMmYgKCUwLjJmKSIsIGVzdGltYXRlLCBzdGQuZXJyb3IpKSwgc2l6ZSA9IDMsIGNvbG91ciA9ICJibGFjayIsIHZqdXN0ID0gLTIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArDQogIGZhY2V0X3dyYXAofk91dGNvbWUsIG5yb3cgPSAyLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3dpdGNoID0gInkiKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGVbYygxLDIpXSkgKyANCiAgIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gYygidGhyZWUgcXVhcnRlcnMgKDc1JSkiLCAiaGFsZiAoNTAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYyguMjUsLjcpLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkgKw0KICBsYWJzKHRpdGxlID0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgc3VidGl0bGUgPSAiKipSZXNwb25kZW50cyB3aXRoIGNvbGxlZ2UgZGVncmVlKioiKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiLCANCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0Ym94X3NpbXBsZSgNCiAgICAgIHBhZGRpbmcgPSBtYXJnaW4oNS41LCA1LjUsIDUuNSwgNS41KSwgDQogICAgICBtYXJnaW4gPSBtYXJnaW4oMCwgMCwgNS41LCAwKSwgDQogICAgICBmaWxsID0gImxpZ2h0Z3JleSIsIA0KICAgICAgbGluZXR5cGUgPSAxLA0KICAgICAgciA9IGdyaWQ6OnVuaXQoMCwgInB0IiksIA0KICAgICAgc2l6ZSA9IDgpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHRib3hfc2ltcGxlKA0KICAgICAgcGFkZGluZyA9IG1hcmdpbig1LjUsIDUuNSwgNS41LCA1LjUpLCANCiAgICAgIG1hcmdpbiA9IG1hcmdpbigwLCAwLCA1LjUsIDApLCANCiAgICAgIGZpbGwgPSAibGlnaHRncmV5IiwgDQogICAgICBsaW5ldHlwZSA9IDEsDQogICAgICByID0gZ3JpZDo6dW5pdCgwLCAicHQiKSwgDQogICAgICBzaXplID0gOA0KICAgICkNCiAgKQ0KDQojY29tYmluZSBhbGwgaW4gb25lDQpjb21iaXBsb3QgPC0gZ2dwdWJyOjpnZ2FycmFuZ2UocGxvdF9hZ2Vfc3ViLCBwbG90X2V0aF9zdWIsIHBsb3RfZWR1X3N1YiwgbmNvbD0zKQ0KDQojIG1ha2UgYSBuZXcgJ2xlZ2VuZHMnIG9iamVjdCwgbm93IHdpdGggZm9yIHRoZSBtaWRkbGUgKGV0aG5pYykgcGFuZWwgdGhlIGNvbG9ycyByZXZlcnNlZA0KIyBzdWNoIHRoYXQgeWVsbG93IGluZGljYXRlcyBsaXR0bGUgb3V0Z3JvdXAgZXhwb3N1cmUgKGhlcmUgZm9yIG5hdGl2ZSBkdXRjaCByZXNwb25kZW50cykNCg0KbGVnMnJldmVyc2VkIDwtIGdldF9sZWdlbmQoZ2dwbG90KGV0aCwgYWVzKHggPSBlc3RpbWF0ZSwgeSA9IGxldmVsLCBjb2xvciA9IEN1cnJlbnQpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgbGFicyhjb2xvciA9ICJDdXJyZW50IHNldHRpbmc6IikgKyANCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZVtjKDEsMildKSArDQogIHRoZW1lX2J3KCkpDQoNCmxlZzEycmV2ZXJzZWQzIDwtIHBsb3RfZ3JpZChsZWcxLGxlZzJyZXZlcnNlZCxsZWczLCBucm93PTEsIGFsaWduPSJoIikNCg0KcCA8LSBwbG90X2dyaWQoY29tYmlwbG90LCBsZWcxMnJldmVyc2VkMywgYWxpZ24gPSAiaCIsIG5yb3c9MiwgcmVsX2hlaWdodHMgPSBjKDYsMSkpDQojcGxvdChwKQ0KI2dnc2F2ZSgiLi9maWd1cmVzL2NtbXNfY3VycmVudF9jb3JyX21haW4ucG5nIiwgcCwgd2lkdGg9MTIsIGhlaWdodD02KSANCmdnc2F2ZSgiLi9maWd1cmVzL2ZpZ3VyZTAzX21haW4ucG5nIiwgcCwgd2lkdGg9MTIsIGhlaWdodD03KSANCmBgYCANCg0KIVsqKkZpZ3VyZSAzIChNYWluKTogTWFyZ2luYWwgbWVhbnMgb2YgbmVpZ2hib3Job29kc+KAmSBzb2NpYWwgY29tcG9zaXRpb24gYXR0cmlidXRlcyBmb3Igc3BlY2lmaWMgc3ViZ3JvdXBzLCBkaXNhZ2dyZWdhdGVkIGJ5IHRoZSBjb21wb3NpdGlvbiBvZiB0aGVpciBjdXJyZW50IG5laWdoYm9yaG9vZHMgKEV4cGVyaW1lbnRzIDEgYW5kIDIpLioqXSguL2ZpZ3VyZXMvZmlndXJlMDNfbWFpbi5wbmcpDQoNCiMjIyBjb21wb3NpdGlvbiBpbiB0ZXJtcyBvZiBzZXR0aW5nICoqY29udGFjdHMqKg0KDQpgYGB7ciwgY21tc19jdXJpbnZfY29udCwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTksIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojYWRkaXRpb25hbCBkaXNhZ2dyZWdhdGlvbiBieSB3aGV0aGVyIGVnbyBoYXMgbXVjaC9saXR0bGUgY29udGFjdCB3aXRoIGdyb3VwIHgsIGZvciBzdWJncm91cDoNCg0KI2VkdWNhdGlvbiBjb21wb3NpdGlvbg0KI3NwbGl0IGJ5IGxvd2VyIGFuZCB1cHBlciBxdWFydGlsZSBpbiBkaXN0cmlidXRpb24NCmRmJGVkdWNuYmggPC0gTkFfcmVhbF8NCg0KI2hpc3QoZGYkb25iaF9jb250X2VkdVtkZiRUZXJ0ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIl0pDQojaGlzdChkZiRvbmJoX2NvbnRfZWR1W2RmJFRlcnQgPT0gIldpdGhvdXQgY29sbGVnZSBkZWdyZWUiXSkNCg0KI2RlZmluZSB0aGUgcXVhcnRpbGVzIGZvciBlYWNoIHN1Ymdyb3VwDQpjb2xsZWdlX3EyNSA8LSBxdWFudGlsZShkZiRvbmJoX2NvbnRfZWR1W2RmJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0KY29sbGVnZV9xNzUgPC0gcXVhbnRpbGUoZGYkb25iaF9jb250X2VkdVtkZiRUZXJ0ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIl0sIDAuNzUsIG5hLnJtID0gVFJVRSkNCm5vX2NvbGxlZ2VfcTI1IDwtIHF1YW50aWxlKGRmJG9uYmhfY29udF9lZHVbZGYkVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSJdLCAwLjI1LCBuYS5ybSA9IFRSVUUpDQpub19jb2xsZWdlX3E3NSA8LSBxdWFudGlsZShkZiRvbmJoX2NvbnRfZWR1W2RmJFRlcnQgPT0gIldpdGhvdXQgY29sbGVnZSBkZWdyZWUiXSwgMC43NSwgbmEucm0gPSBUUlVFKQ0KDQojYXBwbHkgIGNvbmRpdGlvbnMgZm9yIHN1Ymdyb3Vwcw0KZGYkZWR1Y25iaCA8LSBpZmVsc2UoZGYkVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSIsIA0KICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9uYmhfY29udF9lZHUgPD0gY29sbGVnZV9xMjUsIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9uYmhfY29udF9lZHUgPj0gY29sbGVnZV9xNzUsIDIsIE5BKSksDQogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvbmJoX2NvbnRfZWR1IDw9IG5vX2NvbGxlZ2VfcTI1LCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb25iaF9jb250X2VkdSA+PSBub19jb2xsZWdlX3E3NSwgMiwgTkEpKSwgTkEpKQ0KDQojbWFrZSBjYXRlZ29yaWVzIChjb21iaW5hdGlvbiBvZiBzdWJncm91cCBhbmQgY29tcG9zaXRpb24pDQpkZiRlZHVjbmJoVGVydCA8LSBpZmVsc2UoZGYkVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSIgJiBkZiRlZHVjbmJoID09IDEsICJXaXRoIGNvbGxlZ2UgZGVncmVlLCBmZXcgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiICYgZGYkZWR1Y25iaCA9PSAyLCAiV2l0aCBjb2xsZWdlIGRlZ3JlZSwgbWFueSB3aXRoIGNvbGxlZ2UgZGVncmVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiAmIGRmJGVkdWNuYmggPT0gMSwgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIGZldyB3aXRoIGNvbGxlZ2UgZGVncmVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiAmIGRmJGVkdWNuYmggPT0gMiwgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIG1hbnkgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsIE5BKSkpKQ0KI3Jlb3JkZXIgbGV2ZWxzDQpkZiRlZHVjbmJoVGVydCA8LSBmYWN0b3IoZGYkZWR1Y25iaFRlcnQsIGxldmVscyA9IGMoIldpdGggY29sbGVnZSBkZWdyZWUsIGZldyB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgICJXaXRoIGNvbGxlZ2UgZGVncmVlLCBtYW55IHdpdGggY29sbGVnZSBkZWdyZWUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSwgZmV3IHdpdGggY29sbGVnZSBkZWdyZWUiLCAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSwgbWFueSB3aXRoIGNvbGxlZ2UgZGVncmVlIikpDQoNCiNhbHNvIGZvciBvcmdhbml6YXRpb25zDQpkZiRlZHVjY2l2IDwtIE5BX3JlYWxfDQoNCiNoaXN0KGRmJG9jaXZfY29udF9lZHVbZGYkVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSJdKQ0KI2hpc3QoZGYkb2Npdl9jb250X2VkdVtkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIl0pDQoNCiNkZWZpbmUgdGhlIHF1YXJ0aWxlcyBmb3IgZWFjaCBncm91cA0KY29sbGVnZV9xMjUgPC0gcXVhbnRpbGUoZGYkb2Npdl9jb250X2VkdVtkZiRUZXJ0ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIl0sIDAuMjUsIG5hLnJtID0gVFJVRSkNCmNvbGxlZ2VfcTc1IDwtIHF1YW50aWxlKGRmJG9jaXZfY29udF9lZHVbZGYkVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSJdLCAwLjc1LCBuYS5ybSA9IFRSVUUpDQpub19jb2xsZWdlX3EyNSA8LSBxdWFudGlsZShkZiRvY2l2X2NvbnRfZWR1W2RmJFRlcnQgPT0gIldpdGhvdXQgY29sbGVnZSBkZWdyZWUiXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0Kbm9fY29sbGVnZV9xNzUgPC0gcXVhbnRpbGUoZGYkb2Npdl9jb250X2VkdVtkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIl0sIDAuNzUsIG5hLnJtID0gVFJVRSkNCg0KI2FwcGx5ICBjb25kaXRpb25zIGZvciBzdWJncm91cHMNCmRmJGVkdWNjaXYgPC0gaWZlbHNlKGRmJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiLCANCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvY2l2X2NvbnRfZWR1IDw9IGNvbGxlZ2VfcTI1LCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvY2l2X2NvbnRfZWR1ID49IGNvbGxlZ2VfcTc1LCAyLCBOQSkpLA0KICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkVGVydCA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvY2l2X2NvbnRfZWR1IDw9IG5vX2NvbGxlZ2VfcTI1LCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb2Npdl9jb250X2VkdSA+PSBub19jb2xsZWdlX3E3NSwgMiwgTkEpKSwgTkEpKQ0KDQojbWFrZSBjYXRlZ29yaWVzIChjb21iaW5hdGlvbiBvZiBzdWJncm91cCBhbmQgY29tcG9zaXRpb24pDQpkZiRlZHVjY2l2VGVydCA8LSBpZmVsc2UoZGYkVGVydCA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSIgJiBkZiRlZHVjY2l2ID09IDEsICJXaXRoIGNvbGxlZ2UgZGVncmVlLCBmZXcgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJFRlcnQgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiICYgZGYkZWR1Y2NpdiA9PSAyLCAiV2l0aCBjb2xsZWdlIGRlZ3JlZSwgbWFueSB3aXRoIGNvbGxlZ2UgZGVncmVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiAmIGRmJGVkdWNjaXYgPT0gMSwgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIGZldyB3aXRoIGNvbGxlZ2UgZGVncmVlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUZXJ0ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiAmIGRmJGVkdWNjaXYgPT0gMiwgIldpdGhvdXQgY29sbGVnZSBkZWdyZWUsIG1hbnkgd2l0aCBjb2xsZWdlIGRlZ3JlZSIsIE5BKSkpKQ0KI3Jlb3JkZXIgbGV2ZWxzDQpkZiRlZHVjY2l2VGVydCA8LSBmYWN0b3IoZGYkZWR1Y2NpdlRlcnQsIGxldmVscyA9IGMoIldpdGggY29sbGVnZSBkZWdyZWUsIGZldyB3aXRoIGNvbGxlZ2UgZGVncmVlIiwgICJXaXRoIGNvbGxlZ2UgZGVncmVlLCBtYW55IHdpdGggY29sbGVnZSBkZWdyZWUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSwgZmV3IHdpdGggY29sbGVnZSBkZWdyZWUiLCAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSwgbWFueSB3aXRoIGNvbGxlZ2UgZGVncmVlIikpDQojYWdlDQpkZiRhZ2VuYmggPC0gTkFfcmVhbF8NCiNoaXN0KGRmJG9uYmhfY29udF9hZ2VbZGYkQWdlID09ICI1MCB5ZWFycyBvciBvbGRlciJdKQ0KI2hpc3QoZGYkb25iaF9jb250X2FnZVtkZiRBZ2UgPT0gIkJlbG93IDUwIHllYXJzIl0pDQoNCiNkZWZpbmUgdGhlIHF1YXJ0aWxlcyBmb3IgZWFjaCBncm91cA0KYWdlX3EyNSA8LSBxdWFudGlsZShkZiRvbmJoX2NvbnRfYWdlW2RmJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0KYWdlX3E3NSA8LSBxdWFudGlsZShkZiRvbmJoX2NvbnRfYWdlW2RmJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiXSwgMC43NSwgbmEucm0gPSBUUlVFKQ0KbmFnZV9xMjUgPC0gcXVhbnRpbGUoZGYkb25iaF9jb250X2FnZVtkZiRBZ2UgPT0gIkJlbG93IDUwIHllYXJzIl0sIDAuMjUsIG5hLnJtID0gVFJVRSkNCm5hZ2VfcTc1IDwtIHF1YW50aWxlKGRmJG9uYmhfY29udF9hZ2VbZGYkQWdlID09ICJCZWxvdyA1MCB5ZWFycyJdLCAwLjc1LCBuYS5ybSA9IFRSVUUpDQoNCiNhcHBseSAgY29uZGl0aW9ucyBmb3Igc3ViZ3JvdXBzDQpkZiRhZ2VuYmggPC0gaWZlbHNlKGRmJEFnZSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiLCANCiAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9uYmhfY29udF9hZ2UgPD0gYWdlX3EyNSwgMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvbmJoX2NvbnRfYWdlID49IGFnZV9xNzUsIDIsIE5BKSksDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkQWdlID09ICJCZWxvdyA1MCB5ZWFycyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9uYmhfY29udF9hZ2UgPD0gbmFnZV9xMjUsIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9uYmhfY29udF9hZ2UgPj0gbmFnZV9xNzUsIDIsIE5BKSksIE5BKSkNCg0KI21ha2UgY2F0ZWdvcmllcyAoY29tYmluYXRpb24gb2Ygc3ViZ3JvdXAgYW5kIGNvbXBvc2l0aW9uKQ0KZGYkYWdlbmJoQWdlIDwtIGlmZWxzZShkZiRBZ2UgPT0gICI1MCB5ZWFycyBvciBvbGRlciIgJiBkZiRhZ2VuYmggPT0gMSwgIjUwIHllYXJzIG9yIG9sZGVyLCBmZXcgNTAgeWVhcnMgb3Igb2xkZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkQWdlID09ICI1MCB5ZWFycyBvciBvbGRlciIgJiBkZiRhZ2VuYmggPT0gMiwgIjUwIHllYXJzIG9yIG9sZGVyLCBtYW55IDUwIHllYXJzIG9yIG9sZGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJEFnZSA9PSAgIkJlbG93IDUwIHllYXJzIiAmIGRmJGFnZW5iaCA9PSAxLCAiQmVsb3cgNTAgeWVhcnMsIGZldyA1MCB5ZWFycyBvciBvbGRlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJEFnZSA9PSAgIkJlbG93IDUwIHllYXJzIiAmIGRmJGFnZW5iaCA9PSAyLCAiQmVsb3cgNTAgeWVhcnMsIG1hbnkgNTAgeWVhcnMgb3Igb2xkZXIiLCBOQSkpKSkNCg0KI3Jlb3JkZXIgbGV2ZWxzDQpkZiRhZ2VuYmhBZ2UgPC0gZmFjdG9yKGRmJGFnZW5iaEFnZSwgbGV2ZWxzID0gYygiNTAgeWVhcnMgb3Igb2xkZXIsIGZldyA1MCB5ZWFycyBvciBvbGRlciIsICI1MCB5ZWFycyBvciBvbGRlciwgbWFueSA1MCB5ZWFycyBvciBvbGRlciIsICJCZWxvdyA1MCB5ZWFycywgZmV3IDUwIHllYXJzIG9yIG9sZGVyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmVsb3cgNTAgeWVhcnMsIG1hbnkgNTAgeWVhcnMgb3Igb2xkZXIiKSkNCg0KI2Fsc28gZm9yIG9yZ2FuaXphdGlvbnMNCmRmJGFnZWNpdiA8LSBOQV9yZWFsXw0KI2hpc3QoZGYkb2Npdl9jb250X2FnZVtkZiRBZ2UgPT0gIjUwIHllYXJzIG9yIG9sZGVyIl0pDQojaGlzdChkZiRvY2l2X2NvbnRfYWdlW2RmJEFnZSA9PSAiQmVsb3cgNTAgeWVhcnMiXSkNCg0KI2RlZmluZSB0aGUgcXVhcnRpbGVzIGZvciBlYWNoIGdyb3VwDQphZ2VfcTI1IDwtIHF1YW50aWxlKGRmJG9jaXZfY29udF9hZ2VbZGYkQWdlID09ICI1MCB5ZWFycyBvciBvbGRlciJdLCAwLjI1LCBuYS5ybSA9IFRSVUUpDQphZ2VfcTc1IDwtIHF1YW50aWxlKGRmJG9jaXZfY29udF9hZ2VbZGYkQWdlID09ICI1MCB5ZWFycyBvciBvbGRlciJdLCAwLjc1LCBuYS5ybSA9IFRSVUUpDQpuYWdlX3EyNSA8LSBxdWFudGlsZShkZiRvY2l2X2NvbnRfYWdlW2RmJEFnZSA9PSAiQmVsb3cgNTAgeWVhcnMiXSwgMC4yNSwgbmEucm0gPSBUUlVFKQ0KbmFnZV9xNzUgPC0gcXVhbnRpbGUoZGYkb2Npdl9jb250X2FnZVtkZiRBZ2UgPT0gIkJlbG93IDUwIHllYXJzIl0sIDAuNzUsIG5hLnJtID0gVFJVRSkNCg0KI2FwcGx5ICBjb25kaXRpb25zIGZvciBzdWJncm91cHMNCmRmJGFnZWNpdiA8LSBpZmVsc2UoZGYkQWdlID09ICI1MCB5ZWFycyBvciBvbGRlciIsIA0KICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb2Npdl9jb250X2FnZSA8PSBhZ2VfcTI1LCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29udF9hZ2UgPj0gYWdlX3E3NSwgMiwgTkEpKSwNCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRBZ2UgPT0gIkJlbG93IDUwIHllYXJzIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb2Npdl9jb250X2FnZSA8PSBuYWdlX3EyNSwgMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb2Npdl9jb250X2FnZSA+PSBuYWdlX3E3NSwgMiwgTkEpKSwgTkEpKQ0KDQojbWFrZSBjYXRlZ29yaWVzIChjb21iaW5hdGlvbiBvZiBzdWJncm91cCBhbmQgY29tcG9zaXRpb24pDQpkZiRhZ2VjaXZBZ2UgPC0gaWZlbHNlKGRmJEFnZSA9PSAgIjUwIHllYXJzIG9yIG9sZGVyIiAmIGRmJGFnZWNpdiA9PSAxLCAiNTAgeWVhcnMgb3Igb2xkZXIsIGZldyA1MCB5ZWFycyBvciBvbGRlciIsDQogICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRBZ2UgPT0gIjUwIHllYXJzIG9yIG9sZGVyIiAmIGRmJGFnZWNpdiA9PSAyLCAiNTAgeWVhcnMgb3Igb2xkZXIsIG1hbnkgNTAgeWVhcnMgb3Igb2xkZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkQWdlID09ICAiQmVsb3cgNTAgeWVhcnMiICYgZGYkYWdlY2l2ID09IDEsICJCZWxvdyA1MCB5ZWFycywgZmV3IDUwIHllYXJzIG9yIG9sZGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkQWdlID09ICAiQmVsb3cgNTAgeWVhcnMiICYgZGYkYWdlY2l2ID09IDIsICJCZWxvdyA1MCB5ZWFycywgbWFueSA1MCB5ZWFycyBvciBvbGRlciIsIE5BKSkpKQ0KDQojcmVvcmRlciBsZXZlbHMNCmRmJGFnZWNpdkFnZSA8LSBmYWN0b3IoZGYkYWdlY2l2QWdlLCBsZXZlbHMgPSBjKCI1MCB5ZWFycyBvciBvbGRlciwgZmV3IDUwIHllYXJzIG9yIG9sZGVyIiwgIjUwIHllYXJzIG9yIG9sZGVyLCBtYW55IDUwIHllYXJzIG9yIG9sZGVyIiwgIkJlbG93IDUwIHllYXJzLCBmZXcgNTAgeWVhcnMgb3Igb2xkZXIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCZWxvdyA1MCB5ZWFycywgbWFueSA1MCB5ZWFycyBvciBvbGRlciIpKQ0KDQojZXRobmljaXR5DQpkZiRUTW5iaCA8LSBOQV9yZWFsXw0KI2hpc3QoZGYkb25iaF9jb250X2V0aFtkZiRUTSA9PSAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiXSkNCiNoaXN0KGRmJG9uYmhfY29udF9ldGhbZGYkVE0gPT0gIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCJdKQ0KDQojZm9yIGV0aG5pY2l0eSAoJSB0dXJrcy9tb3JvY2NhbnMpLCB1c2UgbWVhbiBzcGxpdCAoZ2l2ZW4gaGlnaGx5IHNrZXdlZCBkaXN0cmlidXRpb24pDQpkZiRUTW5iaCA8LSBOQV9yZWFsXw0KDQojZGVmaW5lIG1lYW5zIGZvciBlYWNoIGdyb3VwDQpubV9tIDwtIG1lYW4oZGYkb25iaF9jb250X2V0aFtkZiRUTSA9PSAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiXSwgbmEucm0gPSBUUlVFKQ0KbV9tIDwtIG1lYW4oZGYkb25iaF9jb250X2V0aFtkZiRUTSA9PSAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIl0sIG5hLnJtID0gVFJVRSkNCg0KI2FwcGx5ICBjb25kaXRpb25zIGZvciBzdWJncm91cHMNCmRmJFRNbmJoIDwtIGlmZWxzZShkZiRUTSA9PSAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgDQogICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9uYmhfY29udF9ldGggPCBtX20sIDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvbmJoX2NvbnRfZXRoID49IG1fbSwgMiwgTkEpKSwNCiAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkVE0gPT0gIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvbmJoX2NvbnRfZXRoIDwgbm1fbSwgMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRvbmJoX2NvbnRfZXRoID49IG5tX20sIDIsIE5BKSksIE5BKSkNCg0KI21ha2UgY2F0ZWdvcmllcyAoY29tYmluYXRpb24gb2Ygc3ViZ3JvdXAgYW5kIGNvbXBvc2l0aW9uKQ0KZGYkZXRobmJoVE0gPC0gaWZlbHNlKGRmJFRNID09ICAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiAmIGRmJFRNbmJoID09IDEsICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQsIGZldyBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLA0KICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUTSA9PSAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiAmIGRmJFRNbmJoID09IDIsICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQsIG1hbnkgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUTSA9PSAgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiAmIGRmJFRNbmJoID09IDEsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkVE0gPT0gICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIgJiBkZiRUTW5iaCA9PSAyLCAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQsIG1hbnkgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgTkEpKSkpDQoNCiNyZW9yZGVyIGxldmVscw0KZGYkZXRobmJoVE0gPC0gZmFjdG9yKGRmJGV0aG5iaFRNLCBsZXZlbHMgPSBjKCJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQsIGZldyBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kLCBtYW55IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiKSkNCg0KI2Fsc28gZm9yIG9yZ2FuaXphdGlvbnMNCmRmJFRNY2l2IDwtIE5BX3JlYWxfDQojaGlzdChkZiRvY2l2X2NvbnRfZXRoW2RmJFRNID09ICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCJdKQ0KI2hpc3QoZGYkb2Npdl9jb250X2V0aFtkZiRUTSA9PSAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIl0pDQoNCiNmb3IgZXRobmljaXR5ICglIHR1cmtzL21vcm9jY2FucyksIHVzZSBtZWFuIHNwbGl0IChnaXZlbiBoaWdobHkgc2tld2VkIGRpc3RyaWJ1dGlvbikNCmRmJFRNY2l2IDwtIE5BX3JlYWxfDQoNCiNkZWZpbmUgbWVhbnMgZm9yIGVhY2ggZ3JvdXANCm5tX20gPC0gbWVhbihkZiRvY2l2X2NvbnRfZXRoW2RmJFRNID09ICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCJdLCBuYS5ybSA9IFRSVUUpDQptX20gPC0gbWVhbihkZiRvY2l2X2NvbnRfZXRoW2RmJFRNID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiXSwgbmEucm0gPSBUUlVFKQ0KDQojYXBwbHkgIGNvbmRpdGlvbnMgZm9yIHN1Ymdyb3Vwcw0KZGYkVE1jaXYgPC0gaWZlbHNlKGRmJFRNID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCANCiAgICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkb2Npdl9jb250X2V0aCA8IG1fbSwgMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29udF9ldGggPj0gbV9tLCAyLCBOQSkpLA0KICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUTSA9PSAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29udF9ldGggPCBubV9tLCAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJG9jaXZfY29udF9ldGggPj0gbm1fbSwgMiwgTkEpKSwgTkEpKQ0KDQojbWFrZSBjYXRlZ29yaWVzIChjb21iaW5hdGlvbiBvZiBzdWJncm91cCBhbmQgY29tcG9zaXRpb24pDQpkZiRldGhjaXZUTSA8LSBpZmVsc2UoZGYkVE0gPT0gICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiICYgZGYkVE1jaXYgPT0gMSwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsDQogICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJFRNID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiICYgZGYkVE1jaXYgPT0gMiwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGRmJFRNID09ICAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiICYgZGYkVE1jaXYgPT0gMSwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiRUTSA9PSAgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiAmIGRmJFRNY2l2ID09IDIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCBOQSkpKSkNCg0KI3Jlb3JkZXIgbGV2ZWxzDQpkZiRldGhjaXZUTSA8LSBmYWN0b3IoZGYkZXRoY2l2VE0sIGxldmVscyA9IGMoIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQsIG1hbnkgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBmZXcgVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCBtYW55IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIpKQ0KDQojYWdlDQpubW1hZ2Vjb21wIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkYWdlbmJoQWdlKSwgXSwgZW5iaF9jaG9pY2UgfiBlbmJoX2NvbXBfYWdlLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9ICB+IGFnZW5iaEFnZSkNCmNtbWFnZWNvbXAgPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRhZ2VjaXZBZ2UpLCBdLCBlY2l2X2Nob2ljZSB+IGVjaXZfY29tcF9hZ2UsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gIH4gYWdlY2l2QWdlKQ0Kbm1tYWdlY29tcCRzZXR0aW5nIDwtICJOZWlnaGJvcmhvb2RzIg0KY21tYWdlY29tcCRzZXR0aW5nIDwtICJDaXZpYyBvcmdhbml6YXRpb25zIg0KYWdlIDwtIHJiaW5kKG5tbWFnZWNvbXBbLTEyXSwgY21tYWdlY29tcFstMTJdKQ0KYWdlJHNldHRpbmcgPC0gZmFjdG9yKGFnZSRzZXR0aW5nLCBsZXZlbHMgPSBjKCJOZWlnaGJvcmhvb2RzIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiKSkNCg0KcGFnZSA8LSBwbG90KGFnZSwgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQlkiKSArDQogIGZhY2V0X2dyaWQyKHNldHRpbmd+Liwgc3dpdGNoID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiU2hhcmUgb2YgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiKSArDQogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gc3ViKCIuKjogIiwgIiIsIGxldmVscyhhZ2UkbGV2ZWwpKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI0NDQ0NDQyIsICIjNjY2NjY2IiwgIiNGMEIzM0MiLCAiI0E2NzYwMCIpKSArIA0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dGJveF9zaW1wbGUocGFkZGluZyA9IG1hcmdpbig1LjUsIDUuNSwgNS41LCA1LjUpLCBtYXJnaW4gPSBtYXJnaW4oMCwgMCwgNS41LCAwKSwgZmlsbCA9ICJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDEsIHIgPSBncmlkOjp1bml0KDAsICJwdCIpLCBzaXplID0gOCkpDQoNCiNldGgNCm5tbWV0aGNvbXAgPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRldGhuYmhUTSksIF0sIGVuYmhfY2hvaWNlIH4gZW5iaF9jb21wX2V0aCwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSAgfiBldGhuYmhUTSkNCmNtbWV0aGNvbXAgPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRldGhjaXZUTSksIF0sIGVjaXZfY2hvaWNlIH4gZWNpdl9jb21wX2V0aCwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSAgfiBldGhjaXZUTSkNCm5tbWV0aGNvbXAkc2V0dGluZyA8LSAiTmVpZ2hib3Job29kcyINCmNtbWV0aGNvbXAkc2V0dGluZyA8LSAiQ2l2aWMgb3JnYW5pemF0aW9ucyINCmV0aCA8LSByYmluZChubW1ldGhjb21wWy0xMl0sIGNtbWV0aGNvbXBbLTEyXSkNCmV0aCRzZXR0aW5nIDwtIGZhY3RvcihldGgkc2V0dGluZywgbGV2ZWxzID0gYygiTmVpZ2hib3Job29kcyIsICJDaXZpYyBvcmdhbml6YXRpb25zIikpDQoNCiNmb3Igc29tZSByZWFzb24gaSBuZWVkIHRvIHJldmVyc2UgdGhlIGxldmVscyBhZ2Fpbi4uLg0KZXRoJEJZIDwtIGZhY3RvcihldGgkQlksIGxldmVscyA9IGMoIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICAiVHVya2lzaC9Nb3JvY2NhbiBiYWNrZ3JvdW5kLCBtYW55IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgZmV3IFR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCwgbWFueSBUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiKSkgDQoNCnBldGggPC0gcGxvdChldGgsIHZsaW5lID0gMS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIkJZIikgKw0KICBmYWNldF9ncmlkMihzZXR0aW5nfi4sIHN3aXRjaCA9ICJ5IikgKw0KICBsYWJzKHRpdGxlID0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBzdWIoIi4qOiAiLCAiIiwgbGV2ZWxzKGV0aCRsZXZlbCkpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjQTJENEY3IiwgIiMxRTgwQzAiLCAiI0YyQTA2NiIsICIjQTQzRDAwIikpICsgDQogIHRoZW1lKCANCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dGJveF9zaW1wbGUocGFkZGluZyA9IG1hcmdpbig1LjUsIDUuNSwgNS41LCA1LjUpLCBtYXJnaW4gPSBtYXJnaW4oMCwgMCwgNS41LCAwKSwgZmlsbCA9ICJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDEsIHIgPSBncmlkOjp1bml0KDAsICJwdCIpLCBzaXplID0gOCkpDQoNCiNlZHVjDQpubW1lZHVjY29tcCA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJGVkdWNuYmhUZXJ0KSwgXSwgZW5iaF9jaG9pY2UgfiBlbmJoX2NvbXBfZWR1YywgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSAgfiBlZHVjbmJoVGVydCkNCmNtbWVkdWNjb21wIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkZWR1Y2NpdlRlcnQpLCBdLCBlY2l2X2Nob2ljZSB+IGVjaXZfY29tcF9lZHVjLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9ICB+IGVkdWNjaXZUZXJ0KQ0Kbm1tZWR1Y2NvbXAkc2V0dGluZyA8LSAiTmVpZ2hib3Job29kcyINCmNtbWVkdWNjb21wJHNldHRpbmcgPC0gIkNpdmljIG9yZ2FuaXphdGlvbnMiDQplZHVjIDwtIHJiaW5kKG5tbWVkdWNjb21wWy0xMl0sIGNtbWVkdWNjb21wWy0xMl0pDQplZHVjJHNldHRpbmcgPC0gZmFjdG9yKGVkdWMkc2V0dGluZywgbGV2ZWxzID0gYygiTmVpZ2hib3Job29kcyIsICJDaXZpYyBvcmdhbml6YXRpb25zIikpDQoNCnBlZHVjIDwtIHBsb3QoZWR1YywgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQlkiKSArDQogIGZhY2V0X2dyaWQyKHNldHRpbmd+Liwgc3dpdGNoID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBzdWIoIi4qOiAiLCAiIiwgbGV2ZWxzKGVkdWMkbGV2ZWwpKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiI0QxQ0U4RiIsICIjQTlBMDExIiwgIiMzMzk5Q0MiLCAiIzAwNEM4QyIpKSArIA0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIA0KICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dGJveF9zaW1wbGUocGFkZGluZyA9IG1hcmdpbig1LjUsIDUuNSwgNS41LCA1LjUpLCBtYXJnaW4gPSBtYXJnaW4oMCwgMCwgNS41LCAwKSwgZmlsbCA9ICJsaWdodGdyZXkiLCBsaW5ldHlwZSA9IDEsIHIgPSBncmlkOjp1bml0KDAsICJwdCIpLCBzaXplID0gOCkpDQoNCg0KI2NvbWJpbmUgcGxvdHMNCmNvbWJpcGxvdCA8LSBnZ3B1YnI6OmdnYXJyYW5nZShwYWdlLHBldGgscGVkdWMsIG5jb2wgPSAzLCB2anVzdCA9IC45KQ0KDQojc3BsaXQgbGVnZW5kIGludG8gbXVsdGlwbGUgcGFydHMNCiNmaXJzdCwgcmV2ZXJzZSBvcmRlciBzdWJncm91cGluZyBmYWN0b3IgdmFyaWFibGUgLi4uDQphZ2UkU3ViZ3JvdXAgPC0gZmFjdG9yKGFnZSRCWSwgbGV2ZWxzID0gcmV2KGxldmVscyhhZ2UkQlkpKSkNCmV0aCRTdWJncm91cCA8LSBmYWN0b3IoZXRoJEJZLCBsZXZlbHMgPSByZXYobGV2ZWxzKGV0aCRCWSkpKQ0KZWR1YyRTdWJncm91cCA8LSBmYWN0b3IoZWR1YyRCWSwgbGV2ZWxzID0gcmV2KGxldmVscyhlZHVjJEJZKSkpDQoNCiNjb21iaW5lIGFsbCBpbiBvbmUNCnAgPC0gcGxvdF9ncmlkKGNvbWJpcGxvdCwgbGVnMTIzYSwgYWxpZ24gPSAiaCIsIG5yb3c9MiwgcmVsX2hlaWdodHMgPSBjKDQuNSwxKSkNCg0KI3NhdmUNCiNnZ3NhdmUoIi4vZmlndXJlcy9jbW1zX2xpc3NfY3VycmVudF9jb250YWN0cy5wbmciLCBwLCB3aWR0aD0xMykgDQoNCnByaW50KHApDQpgYGAgDQoNCiMjIyBvYmplY3RpdmUgY29tcG9zaXRpb24gZGF0YSAoQ0JTKSB7LnRhYnNldCAudGFic2V0LWZhZGV9DQoNCiMjIyMgdW5jb3JyZWN0ZWQNCg0KYGBge3IsIGNtbXNfY3VyaW52X29iaiwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTksIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQojMS4gYWdlOg0KI3Jlc3BvbmRlbnRzIGFnZWQgNTArIHZzIHRob3NlIGJlbG93IDUwDQojYW5kIGZvciBlYWNoLCB3aGV0aGVyIHRoZXkgaGF2ZSByZWxhdGl2ZWx5IG1hbnkvZmV3IG5laWdoYm9ycyBhZ2VkIDQ1KyAoYmFzZWQgb24gdXBwZXIvbG93ZXIgcXVhcnRpbGUpDQoNCiNvb3BzLCBoZXJlIEkgdXNlZCAidW5kZXIiIGluc3RlYWQgb2YgImJlbG93IiA1MC4uLg0KZGYkYWdlbmJoX29ial9BZ2UgPC0gYXMuZmFjdG9yKGdzdWIoIlVuZGVyIDUwLio/IiwgIkJlbG93IDUwIiwgZGYkYWdlbmJoX29ial9BZ2UpKQ0Kbm1tYWdlY29tcCA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJGFnZW5iaF9vYmpfQWdlKSwgXSwgZW5iaF9jaG9pY2UgfiBlbmJoX2NvbXBfYWdlLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH4gYWdlbmJoX29ial9BZ2UpDQoNCiNyZXRyaWV2ZSBzdWJncm91cCBhbmQgZXhwb3N1cmUNCm5tbWFnZWNvbXAkU3ViZ3JvdXAgPC0gaWZlbHNlKGdyZXBsKCI1MCB5ZWFycyBvciBvbGRlciIsIG5tbWFnZWNvbXAkQlkpLCAiNTAgeWVhcnMgb3Igb2xkZXIiLCAiQmVsb3cgNTAgeWVhcnMiKQ0Kbm1tYWdlY29tcCRDdXJyZW50IDwtIGlmZWxzZShncmVwbCgibWFueSIsIG5tbWFnZWNvbXAkQlkpLCAiTWFueSBwZW9wbGUgYWdlZCA0NSsiLCAiRmV3IHBlb3BsZSBhZ2VkIDQ1KyIpDQpubW1hZ2Vjb21wJEZlYXR1cmUgPC0gIlNoYXJlIG9mIHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIg0KDQpwYWdlIDwtIHBsb3Qobm1tYWdlY29tcCwgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQ3VycmVudCIsIHhsYWIgPSAiTWFyZ2luYWwgbWVhbiIpICsNCiAgZmFjZXRfbmVzdGVkKFN1Ymdyb3VwIH4gRmVhdHVyZSwgc2NhbGVzID0gImZyZWVfeSIsIGluZGVwZW5kZW50ID0gInkiLCBzd2l0Y2ggPSAieSIpICsgIA0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMSwyKV0pICsNCiAgc2NhbGVfeF9jb250aW51b3VzKCBsaW1pdHMgPSBjKC40LC42KSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBjKCJoYWxmICg1MCUpIiwgImp1c3QgdW5kZXIgaGFsZiAoNDAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlKSArIA0KICANCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAidmVydGljYWwiLA0KICAgICAgICMgc3RyaXAudGV4dC54ID0gZWxlbWVudF9tYXJrZG93bigpLA0KICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpDQoNCiMyLiBldGhuaWNpdHkNCiNoZXJlLCB1c2UgYSAoc3ViZ3JvdXAgc3BlY2lmaWMpIG1lYW4gc3BsaXQNCmRmJGV0aG5iaF9vYmpfVE0gPC0gYXMuZmFjdG9yKGRmJGV0aG5iaF9vYmpfVE0pDQpubW1ldGhjb21wIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkZXRobmJoX29ial9UTSksIF0sIGVuYmhfY2hvaWNlIH4gZW5iaF9jb21wX2V0aCwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+IGV0aG5iaF9vYmpfVE0pDQoNCiNyZXRyaWV2ZSBzdWJncm91cCBhbmQgZXhwb3N1cmUNCm5tbWV0aGNvbXAkU3ViZ3JvdXAgPC0gaWZlbHNlKGdyZXBsKCJObyBtaWdyYXRpb24iLCBubW1ldGhjb21wJEJZKSwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIpDQpubW1ldGhjb21wJEN1cnJlbnQgPC0gaWZlbHNlKGdyZXBsKCJtYW55Iiwgbm1tZXRoY29tcCRCWSksICJNYW55IHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIsICJGZXcgcGVvcGxlIHdpdGggVHVyay9Nb3JvYyBiYWNrZ3JvdW5kIikNCm5tbWV0aGNvbXAkRmVhdHVyZSA8LSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggVHVyay9Nb3JvYyBiYWNrZ3JvdW5kIg0KDQpwZXRoIDwtIHBsb3Qobm1tZXRoY29tcCwgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQ3VycmVudCIsIHhsYWIgPSAiTWFyZ2luYWwgbWVhbiIpICsNCiAgZmFjZXRfbmVzdGVkKFN1Ymdyb3VwIH4gRmVhdHVyZSwgc2NhbGVzID0gImZyZWVfeSIsIGluZGVwZW5kZW50ID0gInkiLCBzd2l0Y2ggPSAieSIpICsgIA0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMSwyKV0pICsNCiAgc2NhbGVfeF9jb250aW51b3VzKCBsaW1pdHMgPSBjKDAuMDUsLjgpLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkgKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IGMoImEgcXVhcnRlciAoMjUlKSIsICJtaW5vcml0eSAoMTAlKSIsICJub25lICgwJSkiKSkgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIsDQogICAgICAgIyBzdHJpcC50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKCksDQogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikNCg0KIzMuIGVkdWNhdGlvbg0KI2ZvciBjb2xsZWdlL25vbiBjb2xsZWdlIGVkdWNhdGVkLCB3aGV0aGVyIHRoZXkgaGF2ZSByZWxhdGl2ZWx5IG1hbnkvZmV3IGhpZ2ggaW5jb21lIGhvdXNlaG9sZHMgaW4gdGhlIG5laWdoYm9yaG9vZHMgKGJhc2VkIG9uIHUvbCBxdWFydGlsZSkNCmRmJGhpbmJoX29ial9FZHVjIDwtIGFzLmZhY3RvcihkZiRoaW5iaF9vYmpfRWR1YykNCm5tbWVkdWNjb21wIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkaGluYmhfb2JqX0VkdWMpLCBdLCBlbmJoX2Nob2ljZSB+IGVuYmhfY29tcF9lZHVjLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH4gaGluYmhfb2JqX0VkdWMpDQoNCiNyZXRyaWV2ZSBzdWJncm91cCBhbmQgZXhwb3N1cmUNCm5tbWVkdWNjb21wJFN1Ymdyb3VwIDwtIGlmZWxzZShncmVwbCgiV2l0aCBjb2xsZWdlIiwgbm1tZWR1Y2NvbXAkQlkpLCAiV2l0aCBjb2xsZWdlIGRlZ3JlZSIsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIikNCm5tbWVkdWNjb21wJEN1cnJlbnQgPC0gaWZlbHNlKGdyZXBsKCJtYW55Iiwgbm1tZWR1Y2NvbXAkQlkpLCAiTWFueSBoaWdoIGluY29tZSBob3VzZWhvbGRzIiwgIkZldyBoaWdoIGluY29tZSBob3VzZWhvbGRzIikNCm5tbWVkdWNjb21wJEZlYXR1cmUgPC0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiDQoNCnBlZHVjIDwtcGxvdChubW1lZHVjY29tcCwgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQ3VycmVudCIsIHhsYWIgPSAiTWFyZ2luYWwgbWVhbiIpICsNCiAgZmFjZXRfbmVzdGVkKFN1Ymdyb3VwIH4gRmVhdHVyZSwgc2NhbGVzID0gImZyZWVfeSIsIGluZGVwZW5kZW50ID0gInkiLCBzd2l0Y2ggPSAieSIpICsgIA0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMSwyKV0pICsNCiAgc2NhbGVfeF9jb250aW51b3VzKCBsaW1pdHMgPSBjKC4zNSwuNiksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSArDQogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gYygidGhyZWUgcXVhcnRlcnMgKDc1JSkiLCAiaGFsZiAoNTAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSkgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIsDQogICAgICAgIyBzdHJpcC50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKCksDQogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikNCg0KI2NvbWJpbmUgYWxsIGluIG9uZQ0KY29tYmlwbG90IDwtIGdncHVicjo6Z2dhcnJhbmdlKHBhZ2UsIHBldGgsIHBlZHVjLCBuY29sPTMpDQoNCiNhZGQgbGVnZW5kDQojZmlyc3QgcmVvcmRlciBncm91cCBmYWN0b3INCm5tbWFnZWNvbXAkQ3VycmVudCA8LSBmYWN0b3Iobm1tYWdlY29tcCRDdXJyZW50LCBsZXZlbHMgPSBjKCJNYW55IHBlb3BsZSBhZ2VkIDQ1KyIsICJGZXcgcGVvcGxlIGFnZWQgNDUrIikpDQpubW1ldGhjb21wJEN1cnJlbnQgPC0gZmFjdG9yKG5tbWV0aGNvbXAkQ3VycmVudCwgbGV2ZWxzID0gYygiTWFueSBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiLCAiRmV3IHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIpKQ0Kbm1tZWR1Y2NvbXAkQ3VycmVudCA8LSBmYWN0b3Iobm1tZWR1Y2NvbXAkQ3VycmVudCwgbGV2ZWxzID0gYygiTWFueSBoaWdoIGluY29tZSBob3VzZWhvbGRzIiwgIkZldyBoaWdoIGluY29tZSBob3VzZWhvbGRzIikpDQoNCmxlZzEgPC0gZ2V0X2xlZ2VuZChnZ3Bsb3Qobm1tYWdlY29tcCwgYWVzKHggPSBlc3RpbWF0ZSwgeSA9IGxldmVsLCBjb2xvciA9IEN1cnJlbnQpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgbGFicyhjb2xvciA9ICJDdXJyZW50IHNldHRpbmc6IikgKyANCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZVtjKDIsMSldKSArDQogIHRoZW1lX2J3KCkpDQoNCmxlZzIgPC0gZ2V0X2xlZ2VuZChnZ3Bsb3Qobm1tZXRoY29tcCwgYWVzKHggPSBlc3RpbWF0ZSwgeSA9IGxldmVsLCBjb2xvciA9IEN1cnJlbnQpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgbGFicyhjb2xvciA9ICJDdXJyZW50IHNldHRpbmc6IikgKyANCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZVtjKDIsMSldKSArDQogIHRoZW1lX2J3KCkpDQoNCmxlZzMgPC0gZ2V0X2xlZ2VuZChnZ3Bsb3Qobm1tZWR1Y2NvbXAsIGFlcyh4ID0gZXN0aW1hdGUsIHkgPSBsZXZlbCwgY29sb3IgPSBDdXJyZW50KSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGxhYnMoY29sb3IgPSAiQ3VycmVudCBzZXR0aW5nOiIpICsgDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGVbYygyLDEpXSkgKw0KICB0aGVtZV9idygpKQ0KDQpsZWdzIDwtIHBsb3RfZ3JpZChsZWcxLGxlZzIsbGVnMywgbnJvdz0xLCBhbGlnbj0iaCIpDQoNCnAgPC0gcGxvdF9ncmlkKGNvbWJpcGxvdCwgbGVncywgYWxpZ24gPSAiaCIsIG5yb3c9MiwgcmVsX2hlaWdodHMgPSBjKDEwLDEpKQ0KcGxvdChwKQ0KYGBgDQoNCg0KIyMjIyBjb3JyZWN0ZWQNCg0KYGBge3IsIGNtbXNfY3VyaW52X29ial9jb3JyLCBldmFsPUZBTFNFfSANCmZib290IDwtIGZ1bmN0aW9uKGRhdGEsIGkpIHsNCiAgIyBzYW1wbGUgcmVzcG9uZGVudCBJRHMgd2l0aCByZXBsYWNlbWVudA0KICBpZHMgPC0gc2FtcGxlKHVuaXF1ZShkYXRhJGlkKSwgbGVuZ3RoKHVuaXF1ZShkYXRhJGlkKSksIHJlcGxhY2UgPSBUUlVFKQ0KICANCiAgIyBjcmVhdGUgYSBuZXcgZGF0YXNldCBieSBpdGVyYXRpbmcgb3ZlciBlYWNoIHNhbXBsZWQgaWQgYW5kIGJpbmRpbmcgdGhlIG1hdGNoaW5nIHJvd3MNCiAgZCA8LSBtYXBfZGZyKGlkcywgfiBkYXRhICU+JSBmaWx0ZXIoaWQgPT0gLngpKSANCg0KICBkYXRhc2V0cyA8LSBsaXN0KGRmWyFpcy5uYShkZiRyZXBfb3JnX2Nob2ljZSksIF0sIGRmWyFpcy5uYShkZiRyZXBfbmJoX2Nob2ljZSksIF0pDQogIHRhc2tzIDwtIGxpc3QoYygiZmlyc3Rfb3JnX2Nob2ljZSIsICJyZXBfb3JnX2Nob2ljZSIpLCBjKCJmaXJzdF9uYmhfY2hvaWNlIiwgInJlcF9uYmhfY2hvaWNlIikpDQogIGxhYmVscyA8LSBjKCJvcmdhbml6YXRpb25zIiwgIm5laWdoYm9yaG9vZHMiKQ0KICANCiAgc3dhcHBpbmcgPC0gbGlzdCgpDQogIGZvciAoaSBpbiAxOmxlbmd0aChkYXRhc2V0cykpIHsNCiAgICBkYXRhc2V0IDwtIGRhdGFzZXRzW1tpXV0NCiAgICBkYXRhc2V0JHJlcGNob2ljZSA8LSBpZmVsc2UoZGF0YXNldFtbdGFza3NbW2ldXVsxXV1dID09IGRhdGFzZXRbW3Rhc2tzW1tpXV1bMl1dXSwgMSwgMCkNCg0KICAgIGlycl9saXN0IDwtIGZfaXJyKGRhdGFzZXQpDQogICAgdGF1X2xpc3QgPC0gZl90YXUoaXJyX2xpc3QpDQoNCiAgICBzd2FwcGluZ1tbbGFiZWxzW2ldXV0gPC0gbGlzdCgiaXJyIiA9IGlycl9saXN0LCAidGF1IiA9IHRhdV9saXN0KQ0KICB9DQogIA0KICAjIGNhbGN1bGF0ZSBjb25kaXRpb25hbCBtYXJnaW5hbCBtZWFucyAobm93IGZvciBjb21iaW5hdGlvbiBzdWJncm91cCBhbmQgY29tcG9zaXRpb24gY3VycmVudCBzZXR0aW5nKToNCiAgeF92YXJzIDwtIGNiaW5kKGMoImFnZW5iaF9vYmpfQWdlIiwgImV0aG5iaF9vYmpfVE0iLCAiaGluYmhfb2JqX0VkdWMiKSwgYygiYWdlIiwgImV0aCIsICJlZHVjIikpDQogIHlfdmFycyA8LSBjKCJlbmJoIikNCg0KICByZXN1bHRzIDwtIGRhdGEuZnJhbWUoKQ0KDQogIGZvcih4IGluIDE6bnJvdyh4X3ZhcnMpKSB7DQogICAgZm9yKHkgaW4geV92YXJzKSB7DQogICAgICAjIGZvcm11bGEgIA0KICAgICAgZiA8LSBhcy5mb3JtdWxhKCBwYXN0ZTAoeSwgIl9jaG9pY2UgfiAiLCB5LCAiX2NvbXBfIiwgeF92YXJzW3gsMl0pKQ0KICAgICANCiAgICAgICNzcGVjaWZ5IHRoZSBjb3JyZWN0ICJCWSIgLyBzdWJncm91cGluZyB2YXJpYWJsZQ0KICAgICAgYnl5IDwtIHhfdmFyc1t4LDFdDQogICAgICBieSA8LSBhcy5mb3JtdWxhKHBhc3RlMCgifiIsIGJ5eSkpDQogDQogICAgICBjbW1zIDwtIGNyZWdnOjpjaiggZFshaXMubmEoZFtieXldKSwgXSwgI2V4Y2x1ZGUgbWlzc2luZ3Mgb24gdGhlIHN1Ymdyb3VwaW5nIHZhcmlhYmxlDQogICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtdWxhID0gZiwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSBieSkNCiAgICAgICNiaW5kIHJlc3VsdHMNCiAgICAgIHJlc3VsdHMgPC0gcmJpbmQocmVzdWx0cywgY21tc1ssLTEyXSkNCiAgICAgIH0NCiAgICB9DQogIA0KICAjY2FsY3VsYXRlIGNvcnJlY3RlZCBjb25kaXRpb25hbCBtYXJnaW5hbCBtZWFuIChmb3Igc3ViZ3JvdXBzKQ0KICByZXN1bHRzJGVzdGltYXRlX2NvcnIgPC0gTkENCiAgDQogIGZvciAoaSBpbiAxOm5yb3cocmVzdWx0cykpIHsgIA0KICAgIA0KICAgICNyZXRyaWV2ZSBzZXR0aW5nIGFuZCBzdWJncm91cA0KICAgIHNldHRpbmcgPC0gaWZlbHNlKHJlc3VsdHMkb3V0Y29tZVtpXSA9PSAiZW5iaF9jaG9pY2UiLCAibmVpZ2hib3Job29kcyIsICJvcmdhbml6YXRpb25zIikNCiAgICBzdWJncm91cCA8LSBhcy5jaGFyYWN0ZXIocmVzdWx0cyRCWVtpXSkNCg0KICAgICN3ZSBkaWQgbm90IGVzdGltYXRlIHN3YXBwaW5nIGVycm9ycyBmb3IgY29tYmluYXRpb25zIG9mIHN1Ymdyb3VwICsgY29tcG9zaXRpb24gY3VycmVudCBzZXR0aW5nLCBidXQgb25seSBmb3IgdGhlIChkZW1vZ3JhcGhpYykgc3ViZ3JvdXAgLi4uDQogICAgI3NvIHJldHJpZXZlIHRoaXM6DQogICAgc3ViZ3JvdXAgPC0gc3ViKCIsLioiLCAiIiwgc3ViZ3JvdXApDQoNCiAgICAjZ2V0IHRhdQ0KICAgIHRhdSA8LSBzd2FwcGluZ1tbc2V0dGluZ11dJHRhdVtzdWJncm91cF0NCiAgICANCiAgICAjZGVmaW5lIGJpYXMgY29ycmVjdGVkIE1NIChlcS4gMTEgb2YgQ2xheXRvbiBldCBhbC4pDQogICAgcmVzdWx0cyRlc3RpbWF0ZV9jb3JyW2ldIDwtIChyZXN1bHRzJGVzdGltYXRlW2ldIC0gdGF1KSAvICgxIC0gMip0YXUpDQogIH0NCiAgDQogICNzYXZlIHJvd25hbWVzDQogICNybmFtZXMxMCA8LSBwYXN0ZTAoIHJlc3VsdHMkb3V0Y29tZSwgIi0iLCByZXN1bHRzJGxldmVsLCAiLSIsIHJlc3VsdHMkQlkpDQogICNzYXZlKHJuYW1lczEwLCBmaWxlID0gIi4vZGF0YS9yb3duYW1lczEwLlJkYSIpDQogIA0KICByZXR1cm4ocmVzdWx0cyRlc3RpbWF0ZV9jb3JyKSAgDQp9DQoNCiNmYm9vdChkZikjdGVzdCBpdGVyYXRpb24NCm5Db3JlIDwtIGRldGVjdENvcmVzKCkgLSAxICNkZXRlY3QgbnVtYmVyIG9mIGNvcmVzIChrZWVwIG9uZSBmb3Igb3RoZXIgdGFza3MpDQpuSXRlciA8LSAxMDAwICNudW1iZXIgb2YgYm9vdHN0cmFwIGl0ZXJhdGlvbnMNCg0KI3NldCB1cCBjbHVzdGVyDQpteWNsIDwtIG1ha2VDbHVzdGVyKHJlcCgibG9jYWxob3N0IiwgbkNvcmUpKQ0KDQojbG9hZCBuZWNlc3NhcnkgbGlicmFyeSBvbiBlYWNoIGNsdXN0ZXIgbm9kZQ0KY2x1c3RlckV2YWxRKG15Y2wsIHsNCiAgbGlicmFyeShjcmVnZykNCiAgbGlicmFyeShwdXJycikNCiAgbGlicmFyeShkcGx5cikNCn0pDQoNCiNjb3B5IGRhdGEgYW5kIGN1c3RvbSBmdW5jdGlvbnMgdG8gZWFjaCBub2RlJ3Mgd29ya3NwYWNlDQpjbHVzdGVyRXhwb3J0KG15Y2wsIHZhcmxpc3Q9YygiZGYiLCAiZl90YXUiLCAiZl9pcnIiLCAiZmJvb3QiKSkgDQoNCiNwZXJmb3JtIGJvb3RzdHJhcDoNCnN5c3RlbS50aW1lKHRlc3QgPC0gYm9vdChkZiwgZmJvb3QsIFI9bkl0ZXIsIHBhcmFsbGVsID0gInNub3ciLCBuY3B1cyA9IG5Db3JlLCBjbCA9IG15Y2wpKSANCg0Kc2F2ZSh0ZXN0LCBmaWxlID0gIi4vcmVzdWx0cy9ib290MTAuUmRhIikNCnN0b3BDbHVzdGVyKG15Y2wpDQpgYGAgDQoNCg0KYGBge3IsIGNtbXNfY3VyaW52X29ial9jb3JyX3Bsb3QsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD05LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KbG9hZCgiLi9yZXN1bHRzL2Jvb3QxMC5SZGEiKQ0KbG9hZCgiLi9kYXRhL3Jvd25hbWVzMTAuUmRhIikNCg0KdGVzdDEgPC0gc3VtbWFyeSh0ZXN0KQ0Kcm93bmFtZXModGVzdDEpIDwtIHJuYW1lczEwDQojcHJpbnQodGVzdDEpDQogDQojZmlyc3QgYWRkIHRoZSBvcmlnaW5hbCBiaWFzIGNvcnJlY3RlZCBDTU1zIHRvIHRoZSBkYXRhZnJhbWU6DQptbXMgPC0gcmJpbmQobm1tYWdlY29tcFssLTEyXSwgbm1tZXRoY29tcFssLTEyXSwgbm1tZWR1Y2NvbXBbLC0xMl0pDQojY3JlYXRlIGEgbWVyZ2UgdmFyaWFibGUgaW4gdGhlIG9yaWdpbmFsIENNTSBkYXRhZnJhbWUNCm1tcyRCWTIgPC0gcGFzdGUwKG1tcyRvdXRjb21lLCAiLSIsIG1tcyRsZXZlbCwgIi0iLCBtbXMkQlkpDQoNCiNyZW9yZGVyDQptbXMgPC0gbW1zW21hdGNoKHJvd25hbWVzKHRlc3QxKSwgbW1zJEJZMiksXQ0KDQojbm93IGNhbGN1bGF0ZSB0aGUgY29ycmVjdGVkIENNTVMNCmZvciAoaSBpbiAxOm5yb3cobW1zKSkgeyAjIGZvciBlYWNoIENNTQ0KICAgICNyZXRyaWV2ZSBzZXR0aW5nIGFuZCBzdWJncm91cA0KICAgIHNldHRpbmcgPC0gaWZlbHNlKG1tcyRvdXRjb21lW2ldID09ICJlbmJoX2Nob2ljZSIsICJuZWlnaGJvcmhvb2RzIiwgIm9yZ2FuaXphdGlvbnMiKQ0KICAgIHN1Ymdyb3VwIDwtIGFzLmNoYXJhY3RlcihtbXMkQllbaV0pDQogICAgc3ViZ3JvdXAgPC0gc3ViKCIsLioiLCAiIiwgc3ViZ3JvdXApDQogICAgDQogICAgI2dldCB0YXUgZnJvbSBvdXIgc2F2ZWQgbGlzdA0KICAgIHRhdSA8LSBzd2FwcGluZ0xpc3RbW3NldHRpbmddXSR0YXVbc3ViZ3JvdXBdDQogICAgI2RlZmluZSBiaWFzIGNvcnJlY3RlZCBNTSAoZXEuIDExIG9mIENsYXl0b24gZXQgYWwuKQ0KICAgIG1tcyRlc3RpbWF0ZV9jb3JyW2ldIDwtIChtbXMkZXN0aW1hdGVbaV0gLSB0YXUpIC8gKDEgLSAyKnRhdSkNCn0NCg0KI2NhbGN1bGF0ZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgYm9vdHN0cmFwIHN0YXRpc3RpY3MNCmZvciAoaSBpbiAxOm5yb3codGVzdDEpKSB7DQogIGlmKHRlc3QxJFJbaV0gPCBuSXRlcikgew0KICAgIHN0YXQgPC0gdGVzdCR0WyxpXQ0KICAgIHRlc3QxJGJvb3RTRVtpXSA8LSBzZChzdGF0WyFpcy5uYShzdGF0KSAmIGlzLmZpbml0ZShzdGF0KV0pDQogIH0NCn0NCg0KI2FkZCB0aGVzZSBzdGF0aXN0aWNzIHRvIHBsb3R0aW5nIGRhdGENCiNjcmVhdGUgY29weSBvZiBtbXMNCm1tc19jb3JyIDwtIG1tcw0KI3VzZSBjb3JyZWN0ZWQgZXN0aW1hdGVzDQptbXNfY29yciRlc3RpbWF0ZSA8LSBtbXNfY29yciRlc3RpbWF0ZV9jb3JyDQojd2l0aCBib290c3RyYXBwZWQgc3RhbmRhcmQgZXJyb3JzDQptbXNfY29yciRzdGQuZXJyb3IgPC0gdGVzdDEkYm9vdFNFDQojYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzDQptbXNfY29yciR1cHBlciA8LSBtbXNfY29yciRlc3RpbWF0ZSArIDEuOTYqbW1zX2NvcnIkc3RkLmVycm9yDQptbXNfY29yciRsb3dlciA8LSBtbXNfY29yciRlc3RpbWF0ZSAtIDEuOTYqbW1zX2NvcnIkc3RkLmVycm9yDQoNCiMgcmVkbyB0aGUgcGxvdHM6DQphZ2UgPC0gbW1zX2NvcnJbZ3JlcCgiYWdlIiwgbW1zX2NvcnIkZmVhdHVyZSksIF0NCmFnZSRDdXJyZW50IDwtIGZhY3RvcihhZ2UkQ3VycmVudCwgbGV2ZWxzID0gYygiRmV3IHBlb3BsZSBhZ2VkIDQ1KyIsICJNYW55IHBlb3BsZSBhZ2VkIDQ1KyIpKQ0KDQpwYWdlIDwtIHBsb3QoYWdlLCB2bGluZSA9MS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIkN1cnJlbnQiLCB4bGFiID0gIk1hcmdpbmFsIG1lYW4iKSArDQogIGZhY2V0X25lc3RlZChTdWJncm91cCB+IEZlYXR1cmUsIHNjYWxlcyA9ICJmcmVlX3kiLCBpbmRlcGVuZGVudCA9ICJ5Iiwgc3dpdGNoID0gInkiKSArDQogIGdlb21fdGV4dCggYWVzKGxhYmVsID0gc3ByaW50ZigiJTAuMmYgKCUwLjJmKSIsIGVzdGltYXRlLCBzdGQuZXJyb3IpKSwgc2l6ZSA9IDMsIGNvbG91ciA9ICJibGFjayIsIHZqdXN0ID0gLTEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGVbYygxLDIpXSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoIGxpbWl0cyA9IGMoLjM4LC42MiksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSArDQogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gYygiaGFsZiAoNTAlKSIsICJqdXN0IHVuZGVyIGhhbGYgKDQwJSkiLCAiYSBxdWFydGVyICgyNSUpIikpICsNCiAgICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIsDQogICAgICAgIyBzdHJpcC50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKCksDQogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikNCg0KZXRoIDwtIG1tc19jb3JyW2dyZXAoImV0aCIsIG1tc19jb3JyJGZlYXR1cmUpLCBdDQpldGgkQ3VycmVudCA8LSBmYWN0b3IoZXRoJEN1cnJlbnQsIGxldmVscyA9IGMoIkZldyBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiLCAiTWFueSBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiKSkNCg0KcGV0aCA8LSBwbG90KGV0aCwgdmxpbmUgPTEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJDdXJyZW50IiwgeGxhYiA9ICJNYXJnaW5hbCBtZWFuIikgKw0KICBmYWNldF9uZXN0ZWQoU3ViZ3JvdXAgfiBGZWF0dXJlLCBzY2FsZXMgPSAiZnJlZV95IiwgaW5kZXBlbmRlbnQgPSAieSIsIHN3aXRjaCA9ICJ5IikgKw0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMSwyKV0pICsNCiAgc2NhbGVfeF9jb250aW51b3VzKCBsaW1pdHMgPSBjKDAsMC45OSksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSArDQogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gYygiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIiwgIm5vbmUgKDAlKSIpKSArDQogICAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAidmVydGljYWwiLA0KICAgICAgICMgc3RyaXAudGV4dC54ID0gZWxlbWVudF9tYXJrZG93bigpLA0KICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpDQoNCmVkdWMgPC0gbW1zX2NvcnJbZ3JlcCgiZWR1YyIsIG1tc19jb3JyJGZlYXR1cmUpLCBdDQplZHVjJEN1cnJlbnQgPC0gZmFjdG9yKGVkdWMkQ3VycmVudCwgbGV2ZWxzID0gYygiRmV3IGhpZ2ggaW5jb21lIGhvdXNlaG9sZHMiLCAiTWFueSBoaWdoIGluY29tZSBob3VzZWhvbGRzIikpDQoNCnBlZHVjIDwtIHBsb3QoZWR1YywgdmxpbmUgPTEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJDdXJyZW50IiwgeGxhYiA9ICJNYXJnaW5hbCBtZWFuIikgKw0KICBmYWNldF9uZXN0ZWQoU3ViZ3JvdXAgfiBGZWF0dXJlLCBzY2FsZXMgPSAiZnJlZV95IiwgaW5kZXBlbmRlbnQgPSAieSIsIHN3aXRjaCA9ICJ5IikgKw0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMSwyKV0pICsNCiAgc2NhbGVfeF9jb250aW51b3VzKCBsaW1pdHMgPSBjKDAuMzUsMC42NCksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSArDQogIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gYygidGhyZWUgcXVhcnRlcnMgKDc1JSkiLCAiaGFsZiAoNTAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSkgKw0KICAgIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwNCiAgICAgICAjIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfbWFya2Rvd24oKSwNCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQ0KDQojY29tYmluZSBhbGwgaW4gb25lDQpjb21iaXBsb3QgPC0gZ2dwdWJyOjpnZ2FycmFuZ2UocGFnZSxwZXRoLHBlZHVjLCBuY29sID0gMywgdmp1c3QgPSAuOSkNCiANCiNhbmQgYWRkIGN1c3RvbSBsZWdlbmQNCnAgPC0gcGxvdF9ncmlkKGNvbWJpcGxvdCwgbGVncywgYWxpZ24gPSAiaCIsIG5yb3c9MiwgcmVsX2hlaWdodHMgPSBjKDQuNSwxKSkNCnBsb3QocCkNCg0KZ2dzYXZlKCIuL2ZpZ3VyZXMvY21tc19saXNzX2N1cnJlbnRfb2JqX2NvcnIucG5nIiwgcCwgd2lkdGg9MTMpIA0KYGBgIA0KDQoNCiMjIyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQ0KDQojIyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQ0KDQotLS0tDQoNCiMjIGFkZGl0aW9uYWwgYW5hbHlzZXMNCiAgDQojIyMgb25seSB0aGUgZmlyc3Qgc2V0dGluZyB7LnRhYnNldCAudGFic2V0LWZhZGV9DQogIA0KUmVzcG9uZGVudHMgcGVyZm9ybWVkIGNob2ljZSB0YXNrcyBmb3IgbmVpZ2hib3Job29kcyBhbmQgY2l2aWMgb3JnYW5pemF0aW9ucyBpbiBhIHJhbmRvbSBvcmRlci4gTGV0J3MgcmVkbyB0aGUgYW5hbHlzaXMsIGluY2x1ZGluZyBmb3IgZWFjaCBzZXR0aW5nIG9ubHkgdGhlIHJlc3BvbnNlcyBmcm9tIHRob3NlIHdob3NlIGZpcnN0IHRhc2sgd2FzIHRoYXQgcGFydGljdWxhciBzZXR0aW5nLg0KDQojIyMjIHVuY29ycmVjdGVkDQoNCmBgYHtyLCBjbW1zX2ZpcnN0b25seSwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTYsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9IA0KIzEuIG5iaA0Kbm1tZWR1YyA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJFRlcnQpICYgZGYkYmxvY2tfb3JkZXIgPT0gMiwgXSwgZW5iaF9jaG9pY2UgfiBlbmJoX2NvbXBfZWR1YywgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VGVydCkNCm5tbWFnZSA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJEFnZSkgJiBkZiRibG9ja19vcmRlciA9PSAyLCBdLCBlbmJoX2Nob2ljZSB+IGVuYmhfY29tcF9hZ2UsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gfkFnZSkNCm5tbWV0aCA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJFRNKSAmIGRmJGJsb2NrX29yZGVyID09IDIsIF0sIGVuYmhfY2hvaWNlIH4gZW5iaF9jb21wX2V0aCwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VE0pDQoNCiMyLiBvcmcNCmNtbWVkdWMgPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRUZXJ0KSAmIGRmJGJsb2NrX29yZGVyID09IDEsIF0sIGVjaXZfY2hvaWNlIH4gZWNpdl9jb21wX2VkdWMsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflRlcnQpDQpjbW1hZ2UgPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRBZ2UpICYgZGYkYmxvY2tfb3JkZXIgPT0gMSwgXSwgZWNpdl9jaG9pY2UgfiBlY2l2X2NvbXBfYWdlLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5BZ2UpDQpjbW1ldGggPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRUTSkgJiBkZiRibG9ja19vcmRlciA9PSAxLCBdLCBlY2l2X2Nob2ljZSB+IGVjaXZfY29tcF9ldGgsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflRNKQ0KDQojcm93YmluZCB0aGUgZGF0YWZyYW1lcw0KI2xlYXZlIG91dCBsYXN0IGNvbHVtbiwgcmVmbGVjdGluZyB0aGUgc3ViZ3JvdXBpbmcgdmFyaWFibGUNCm1tcyA8LSByYmluZChubW1hZ2VbLTEyXSxubW1ldGhbLTEyXSxubW1lZHVjWy0xMl0sDQogICAgICAgICAgICAgY21tYWdlWy0xMl0sY21tZXRoWy0xMl0sY21tZWR1Y1stMTJdKQ0KDQojcmVuYW1lIGxhYmVscw0KIzEuIG9mIG91dGNvbWUgKHNldHRpbmcpDQptbXMkT3V0Y29tZSA8LSBmYWN0b3IoaWZlbHNlKG1tcyRvdXRjb21lID09ICJlY2l2X2Nob2ljZSIsICJDaXZpYyBvcmdhbml6YXRpb25zIiwgIk5laWdoYm9yaG9vZHMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiTmVpZ2hib3Job29kcyIsICJDaXZpYyBvcmdhbml6YXRpb25zIikpDQoNCiMyLiBvZiAoZGVtb2dyYXBoaWMgY29tcG9zaXRpb24pIGZlYXR1cmVzDQptbXMkRmVhdHVyZSA8LSBmYWN0b3Ioc3ViKCIuKl8iLCAiIiwgbW1zJGZlYXR1cmUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImFnZSIsICJldGgiLCAiZWR1YyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiU2hhcmUgb2YgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiLCAiU2hhcmUgb2YgcGVvcGxlIHdpdGggVHVyay9Nb3JvYyBiYWNrZ3JvdW5kIiwgICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIikpDQoNCm1tcyRTdWJncm91cCA8LSBtbXMkQlkNCm1tcyRTdWJncm91cCA8LSBmYWN0b3IobW1zJFN1Ymdyb3VwLCBsZXZlbHMgPSBjKCI1MCB5ZWFycyBvciBvbGRlciIsICJCZWxvdyA1MCB5ZWFycyIsICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiLCAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiICwgIldpdGggY29sbGVnZSBkZWdyZWUiLCJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiAgKSkgDQoNCiMgbmljZSBjb2xvciBwYWxldHRlDQpjYlBhbGV0dGUgPC0gYygiIzk5OTk5OSIsIiNFNjlGMDAiLCIjNTZCNEU5IiwiI0Q1NUUwMCIsIiNGMEU0NDIiLCIjMDA3MkIyIikNCg0KcDIgPC0gcGxvdChtbXMsIHZsaW5lPTEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJTdWJncm91cCIpICsNCiAgZmFjZXRfZ3JpZDIoIE91dGNvbWUgfiBGZWF0dXJlLCBzY2FsZXMgPSAiZnJlZSIsIGluZGVwZW5kZW50ID0gInkiLCBzd2l0Y2ggPSAieSIpICsNCiAgZ2VvbV90ZXh0KCBhZXMobGFiZWwgPSBzcHJpbnRmKCIlMC4yZiAoJTAuMmYpIiwgZXN0aW1hdGUsIHN0ZC5lcnJvcikpLCBzaXplID0gMywgY29sb3VyID0gImJsYWNrIiwgdmp1c3QgPSAtMSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZSkgKw0KICBmYWNldHRlZF9wb3Nfc2NhbGVzKA0KICAgIHkgPSBsaXN0KA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJ0aHJlZSBxdWFydGVycyAoNzUlKSIsICJoYWxmICg1MCUpIiwgImEgcXVhcnRlciAoMjUlKSIpKSwNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSBhZ2VkIDUwIHllYXJzIG9yIG9sZGVyIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoImhhbGYgKDUwJSkiLCAianVzdCB1bmRlciBoYWxmICg0MCUpIiwgImEgcXVhcnRlciAoMjUlKSIpKSwNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIFR1cmsvTW9yb2MgYmFja2dyb3VuZCIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJhIHF1YXJ0ZXIgKDI1JSkiLCAibWlub3JpdHkgKDEwJSkiLCAibm9uZSAoMCUpIikpDQogICAgICApLA0KICAgICNmcmVlaW5nIHVwIHRoZSB4IHNjYWxlcyBkb2VzIG5vdCB3b3JrIGZvciBzb21lIHJlYXNvbi4uLiBzbyBpIHNldCB0aGVtIG1hbnVhbGx5Og0KICAgIHggPSBsaXN0KA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIgfiBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgICAgIGxpbWl0cyA9IGMoLjQsLjYwKSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC40MywuNjApLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC4zMCwuNzApLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkNCiAgICAgICkpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICMgc3RyaXAudGV4dC54ID0gZWxlbWVudF9tYXJrZG93bigpLA0KICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpDQoNCiNzcGxpdCBsZWdlbmQgaW50byBtdWx0aXBsZSBwYXJ0cw0Kc3BsaXQxIDwtIG1tc1ttbXMkU3ViZ3JvdXAgJWluJSBjKCI1MCB5ZWFycyBvciBvbGRlciIsICJCZWxvdyA1MCB5ZWFycyIpLCBdDQpzcGxpdDIgPC0gbW1zW21tcyRTdWJncm91cCAlaW4lIGMoIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIpLCBdDQpzcGxpdDMgPC0gbW1zW21tcyRTdWJncm91cCAlaW4lIGMoIldpdGggY29sbGVnZSBkZWdyZWUiLCAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIpLCBdDQoNCiNyZXZlcnNlIG9yZGVyIGZhY3Rvci4uLi4gYnVnIGluIGdncGxvdDIgbWFrZXMgdGhlIG9yZGVyIG9mIHRoZSBzdWJncm91cHMgaW4gdGhlIHBsb3QgYW5kIHRoZSBsZWdlbmQgcmV2ZXJzZWQNCnNwbGl0MSRTdWJncm91cCA8LSBmYWN0b3Ioc3BsaXQxJFN1Ymdyb3VwLCBsZXZlbHMgPSByZXYobGV2ZWxzKHNwbGl0MSRTdWJncm91cCkpKQ0Kc3BsaXQyJFN1Ymdyb3VwIDwtIGZhY3RvcihzcGxpdDIkU3ViZ3JvdXAsIGxldmVscyA9IHJldihsZXZlbHMoc3BsaXQyJFN1Ymdyb3VwKSkpDQpzcGxpdDMkU3ViZ3JvdXAgPC0gZmFjdG9yKHNwbGl0MyRTdWJncm91cCwgbGV2ZWxzID0gcmV2KGxldmVscyhzcGxpdDMkU3ViZ3JvdXApKSkNCg0KI3Bsb3QgbGVnZW5kcw0Kc3BsaXQxcCA8LSBnZ3Bsb3Qoc3BsaXQxLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gbGV2ZWwsIGNvbG9yPVN1Ymdyb3VwKSkgKyBnZW9tX3BvaW50KCkgKyBsYWJzKGNvbG9yID0gIlN1Ymdyb3VwczoiKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMiwxKV0pIA0Kc3BsaXQycCA8LSBnZ3Bsb3Qoc3BsaXQyLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gbGV2ZWwsIGNvbG9yPVN1Ymdyb3VwKSkgKyBnZW9tX3BvaW50KCkgKyBsYWJzKGNvbG9yID0gIlN1Ymdyb3VwczoiKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoNCwzKV0pDQpzcGxpdDNwIDwtIGdncGxvdChzcGxpdDMsIGFlcyh4ID0gZXN0aW1hdGUsIHkgPSBsZXZlbCwgY29sb3I9U3ViZ3JvdXApKSArIGdlb21fcG9pbnQoKSArIGxhYnMoY29sb3IgPSAiU3ViZ3JvdXBzOiIpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGVbYyg2LDUpXSkNCg0KI2dldCBsZWdlbmRzDQpsZWcxIDwtIGdldF9sZWdlbmQoc3BsaXQxcCkNCmxlZzIgPC0gZ2V0X2xlZ2VuZChzcGxpdDJwKQ0KbGVnMyA8LSBnZXRfbGVnZW5kKHNwbGl0M3ApDQoNCiNjb21iaW5lIGxlZ2VuZHMNCmxlZzEyMyA8LSBwbG90X2dyaWQobGVnMSxsZWcyLGxlZzMsIG5yb3c9MSwgYWxpZ249ImgiKQ0KDQojY3JlYXRlIGEgYmxhbmsgcGxvdCBmb3IgbGVnZW5kIGFsaWdubWVudA0KYmxhbmtfcCA8LSBwbG90X3NwYWNlcigpDQoNCiNjb21iaW5lIGFsbCBpbiBvbmUNCnAzIDwtIHBsb3RfZ3JpZChwMiwgbGVnMTIzLCBhbGlnbiA9ICJoIiwgbnJvdz0yLCByZWxfaGVpZ2h0cyA9IGMoNywxKSkNCiNnZ3NhdmUoIi4vZmlndXJlcy9jbW1zX2xpc3Nfb25seWZpcnN0LnBuZyIsIHAsIHdpZHRoPTEzKSANCnBsb3QocDMpDQpgYGAgDQoNCiMjIyMgY29ycmVjdGVkDQoNCmBgYHtyLCBjbW1zX2ZpcnN0b25seV9jb3JyLCBldmFsPUZBTFNFfSANCmZib290ZiA8LSBmdW5jdGlvbihkYXRhLCBpKSB7DQogICAjIHNhbXBsZSByZXNwb25kZW50IElEcyB3aXRoIHJlcGxhY2VtZW50DQogIGlkcyA8LSBzYW1wbGUodW5pcXVlKGRhdGEkaWQpLCBsZW5ndGgodW5pcXVlKGRhdGEkaWQpKSwgcmVwbGFjZSA9IFRSVUUpDQoNCiAgIyBjcmVhdGUgYSBuZXcgZGF0YXNldCBieSBpdGVyYXRpbmcgb3ZlciBlYWNoIHNhbXBsZWQgaWQgYW5kIGJpbmRpbmcgdGhlIG1hdGNoaW5nIHJvd3MNCiAgZCA8LSBtYXBfZGZyKGlkcywgfiBkYXRhICU+JSBmaWx0ZXIoaWQgPT0gLngpKSANCiAgDQogIGRhdGFzZXRzIDwtIGxpc3QoZGZbIWlzLm5hKGRmJHJlcF9vcmdfY2hvaWNlKSwgXSwgZGZbIWlzLm5hKGRmJHJlcF9uYmhfY2hvaWNlKSwgXSkNCiAgdGFza3MgPC0gbGlzdChjKCJmaXJzdF9vcmdfY2hvaWNlIiwgInJlcF9vcmdfY2hvaWNlIiksIGMoImZpcnN0X25iaF9jaG9pY2UiLCAicmVwX25iaF9jaG9pY2UiKSkNCiAgbGFiZWxzIDwtIGMoIm9yZ2FuaXphdGlvbnMiLCAibmVpZ2hib3Job29kcyIpDQoNCiAgc3dhcHBpbmcgPC0gbGlzdCgpDQogIGZvciAoaSBpbiAxOmxlbmd0aChkYXRhc2V0cykpIHsNCiAgICBkYXRhc2V0IDwtIGRhdGFzZXRzW1tpXV0NCiAgICBkYXRhc2V0JHJlcGNob2ljZSA8LSBpZmVsc2UoZGF0YXNldFtbdGFza3NbW2ldXVsxXV1dID09IGRhdGFzZXRbW3Rhc2tzW1tpXV1bMl1dXSwgMSwgMCkNCg0KICAgIGlycl9saXN0IDwtIGZfaXJyKGRhdGFzZXQpDQogICAgdGF1X2xpc3QgPC0gZl90YXUoaXJyX2xpc3QpDQoNCiAgICBzd2FwcGluZ1tbbGFiZWxzW2ldXV0gPC0gbGlzdCgiaXJyIiA9IGlycl9saXN0LCAidGF1IiA9IHRhdV9saXN0KQ0KICB9DQogIA0KICAjIGNhbGN1bGF0ZSBjb25kaXRpb25hbCBtYXJnaW5hbCBtZWFuczoNCiAgeF92YXJzIDwtIGNiaW5kKGMoIkFnZSIsICJUTSIsICJUZXJ0IiksIGMoImFnZSIsICJldGgiLCAiZWR1YyIpKQ0KICB5X3ZhcnMgPC0gYygiZW5iaCIsICJlY2l2IikNCiAgICANCiAgcmVzdWx0cyA8LSBkYXRhLmZyYW1lKCkNCg0KICBmb3IoeCBpbiAxOm5yb3coeF92YXJzKSkgew0KICAgIGZvcih5IGluIHlfdmFycykgew0KICAgICAgDQogICAgICAjIGZvcm11bGEgIA0KICAgICAgZiA8LSBhcy5mb3JtdWxhKCBwYXN0ZTAoeSwgIl9jaG9pY2UgfiAiLCB5LCAiX2NvbXBfIiwgeF92YXJzW3gsMl0pKQ0KICAgICAgYnkgPC0gYXMuZm9ybXVsYShwYXN0ZTAoIn4iLCB4X3ZhcnNbeCwxXSkpDQogICAgICAgIA0KICAgICAgIyBpbXBvcnRhbnRseSEgZmlsdGVyIGRhdGEgYmFzZWQgb24gYmxvY2tfb3JkZXIgKGkuZS4sIGluY2x1ZGUgb25seSByZXNwb25zZXMgb2YgcmVzcG9uZGVudHMgd2hvc2UgZmlyc3QgY2hvaWNlIGV4cGVyaW1lbnRzIHdhcyBpbiBzZXR0aW5nIHkpDQogIA0KICAgICAgaWYgKHkgPT0gImVuYmgiKSB7DQogICAgICAgIGRkIDwtIGRbZCRibG9ja19vcmRlciA9PSAyLCBdDQogICAgICB9IGVsc2UgaWYgKHkgPT0gImVjaXYiKSB7DQogICAgICAgIGRkIDwtIGRbZCRibG9ja19vcmRlciA9PSAxLCBdDQogICAgICB9DQogICAgICANCiAgICAgICNlc3RpbWF0ZSBtYXJnaW5hbCBtZWFucw0KICAgICAgY21tcyA8LSBjcmVnZzo6Y2ooIGRkWyFpcy5uYShkZFt4X3ZhcnNbeCwxXV0pLCBdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAjZXhjbHVkZSBtaXNzaW5ncyBvbiB0aGUgc3ViZ3JvdXBpbmcgdmFyaWFibGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm11bGEgPSBmLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IGJ5KQ0KICAgICAgDQogICAgICAjYmluZCByZXN1bHRzDQogICAgICByZXN1bHRzIDwtIHJiaW5kKHJlc3VsdHMsIGNtbXNbLC0xMl0pDQogICAgICB9DQogICAgfQ0KICANCiAgI2NhbGN1bGF0ZSBjb3JyZWN0ZWQgY29uZGl0aW9uYWwgbWFyZ2luYWwgbWVhbiAoZm9yIHN1Ymdyb3VwcykNCiAgcmVzdWx0cyRlc3RpbWF0ZV9jb3JyIDwtIE5BDQogICAgDQogIGZvciAoaSBpbiAxOm5yb3cocmVzdWx0cykpIHsgDQogICAgI3JldHJpZXZlIHNldHRpbmcgYW5kIHN1Ymdyb3VwDQogICAgc2V0dGluZyA8LSBpZmVsc2UocmVzdWx0cyRvdXRjb21lW2ldID09ICJlbmJoX2Nob2ljZSIsICJuZWlnaGJvcmhvb2RzIiwgIm9yZ2FuaXphdGlvbnMiKQ0KICAgIHN1Ymdyb3VwIDwtIGFzLmNoYXJhY3RlcihyZXN1bHRzJEJZW2ldKQ0KDQogICAgdGF1IDwtIHN3YXBwaW5nW1tzZXR0aW5nXV0kdGF1W3N1Ymdyb3VwXQ0KICAgIA0KICAgICNkZWZpbmUgYmlhcyBjb3JyZWN0ZWQgTU0gKGVxLiAxMSBvZiBDbGF5dG9uIGV0IGFsLikNCiAgICByZXN1bHRzJGVzdGltYXRlX2NvcnJbaV0gPC0gKHJlc3VsdHMkZXN0aW1hdGVbaV0gLSB0YXUpIC8gKDEgLSAyKnRhdSkNCg0KICB9DQogIHJldHVybihyZXN1bHRzJGVzdGltYXRlX2NvcnIpICANCn0NCiNmYm9vdGYoZGYpI3Rlc3QNCg0KbkNvcmUgPC0gZGV0ZWN0Q29yZXMoKSAtIDEgI2RldGVjdCBudW1iZXIgb2YgY29yZXMgKGtlZXAgb25lIGZvciBvdGhlciB0YXNrcykNCm5JdGVyIDwtIDEwMDAgI251bWJlciBvZiBib290c3RyYXAgaXRlcmF0aW9ucw0KDQpteWNsIDwtIG1ha2VDbHVzdGVyKHJlcCgibG9jYWxob3N0IiwgbkNvcmUpKSAjc2V0IHVwIGNsdXN0ZXINCiNsb2FkIG5lY2Vzc2FyeSBsaWJyYXJ5IG9uIGVhY2ggY2x1c3RlciBub2RlDQpjbHVzdGVyRXZhbFEobXljbCwgew0KICBsaWJyYXJ5KGNyZWdnKQ0KICBsaWJyYXJ5KHB1cnJyKQ0KICBsaWJyYXJ5KGRwbHlyKQ0KfSkNCg0KI2NvcHkgZGF0YSBhbmQgY3VzdG9tIGZ1bmN0aW9ucyB0byBlYWNoIG5vZGUncyB3b3Jrc3BhY2UNCmNsdXN0ZXJFeHBvcnQobXljbCwgdmFybGlzdD1jKCJkZiIsICJmX3RhdSIsICJmX2lyciIsICJmYm9vdGYiKSkgDQoNCiNwZXJmb3JtIGJvb3RzdHJhcDoNCnN5c3RlbS50aW1lKHRlc3QgPC0gYm9vdChkZiwgZmJvb3RmLCBSPW5JdGVyLCBwYXJhbGxlbCA9ICJzbm93IiwgbmNwdXMgPSBuQ29yZSwgY2wgPSBteWNsKSkgDQpzYXZlKHRlc3QsIGZpbGUgPSAiLi9yZXN1bHRzL2Jvb3Q0LlJkYSIpDQpzdG9wQ2x1c3RlcihteWNsKQ0KYGBgIA0KDQoNCmBgYHtyLCBjbW1zX2ZpcnN0b25seV9jb3JyX3Bsb3QsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD02LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfSANCmxvYWQoIi4vcmVzdWx0cy9ib290NC5SZGEiKQ0KbG9hZCgiLi9kYXRhL3Jvd25hbWVzLlJkYSIpDQpuSXRlciA9IDEwMDANCg0KIyBTb21lIE5BIHZhbHVlcyBtYXkgb2NjdXIgYmVjYXVzZSwgaW4gY2VydGFpbiBib290c3RyYXAgaXRlcmF0aW9ucywgbm8gaW5kaXZpZHVhbHMgZnJvbSBtaW5vcml0eSBncm91cHMgYXJlIHNhbXBsZWQgZHVlIHRvIHRoZWlyIHNtYWxsIHNhbXBsZSBzaXplLiByZXBsYWNlIHRoZXNlIE5BIHZhbHVlcyB3aXRoIHRoZSBtZWFuIG9mIHRoZSBjb3JyZXNwb25kaW5nIGJvb3RzdHJhcHBlZCBDTU0gZXN0aW1hdGVzLCBpZ25vcmluZyBhbnkgTkFzIGR1cmluZyB0aGUgY2FsY3VsYXRpb24uDQpmb3IgKGkgaW4gMTpsZW5ndGgodGVzdCR0MCkpIHsNCiAgaWYoaXMubmEodGVzdCR0MFtpXSkpIHsNCiAgICB0ZXN0JHQwW2ldIDwtIG1lYW4odGVzdCR0WyxpXVtpcy5maW5pdGUodGVzdCR0WywgaV0pXSwgbmEucm09VFJVRSkNCiAgfQ0KfQ0KDQp0ZXN0MSA8LSBzdW1tYXJ5KHRlc3QpDQoNCiNhZGQgcm93bmFtZXMNCnJvd25hbWVzKHRlc3QxKSA8LSBybmFtZXMNCiNzdHIodGVzdCkNCg0KI2ZpcnN0IGFkZCB0aGUgb3JpZ2luYWwgYmlhcyBjb3JyZWN0ZWQgQ01NcyB0byB0aGUgZGF0YWZyYW1lIChpbnN0ZWFkIG9mIHRoZSBib290c3RyYXAgZXN0aW1hdGVzKToNCiNjcmVhdGUgYSBtZXJnZSB2YXJpYWJsZSBpbiB0aGUgb3JpZ2luYWwgQ01NIGRhdGFmcmFtZQ0KbW1zJEJZMiA8LSBwYXN0ZTAobW1zJG91dGNvbWUsICItIiwgbW1zJGxldmVsLCAiLSIsIG1tcyRCWSkNCiNyZW9yZGVyDQptbXMgPC0gbW1zW21hdGNoKHJvd25hbWVzKHRlc3QxKSwgbW1zJEJZMiksXQ0KDQojbm93IGNhbGN1bGF0ZSB0aGUgY29ycmVjdGVkIENNTVMNCmZvciAoaSBpbiAxOm5yb3cobW1zKSkgeyAjIGZvciBlYWNoIENNTQ0KICAgICNyZXRyaWV2ZSBzZXR0aW5nIGFuZCBzdWJncm91cA0KICAgIHNldHRpbmcgPC0gaWZlbHNlKG1tcyRvdXRjb21lW2ldID09ICJlbmJoX2Nob2ljZSIsICJuZWlnaGJvcmhvb2RzIiwgIm9yZ2FuaXphdGlvbnMiKQ0KICAgIHN1Ymdyb3VwIDwtIGFzLmNoYXJhY3RlcihtbXMkQllbaV0pDQogICAgDQogICAgI2dldCB0YXUgZnJvbSBvdXIgc2F2ZWQgbGlzdA0KICAgIHRhdSA8LSBzd2FwcGluZ0xpc3RbW3NldHRpbmddXSR0YXVbc3ViZ3JvdXBdDQogICAgI2RlZmluZSBiaWFzIGNvcnJlY3RlZCBNTSAoZXEuIDExIG9mIENsYXl0b24gZXQgYWwuKQ0KICAgIG1tcyRlc3RpbWF0ZV9jb3JyW2ldIDwtIChtbXMkZXN0aW1hdGVbaV0gLSB0YXUpIC8gKDEgLSAyKnRhdSkNCn0NCg0KI2NhbGN1bGF0ZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgYm9vdHN0cmFwIHN0YXRpc3RpY3MNCmZvciAoaSBpbiAxOm5yb3codGVzdDEpKSB7DQogIGlmKHRlc3QxJFJbaV0gPCBuSXRlcikgew0KICAgIHN0YXQgPC0gdGVzdCR0WyxpXQ0KICAgIHRlc3QxJGJvb3RTRVtpXSA8LSBzZChzdGF0WyFpcy5uYShzdGF0KSAmIGlzLmZpbml0ZShzdGF0KV0pDQogIH0NCn0NCg0KI2NvcnIoY2JpbmQobW1zJGVzdGltYXRlX2NvcnIsIHRlc3QxJG9yaWdpbmFsKSkNCg0KI2FkZCB0aGVzZSBzdGF0aXN0aWNzIHRvIHBsb3R0aW5nIGRhdGENCiNjcmVhdGUgY29weSBvZiBtbXMNCm1tc19jb3JyIDwtIG1tcw0KI3VzZSBjb3JyZWN0ZWQgZXN0aW1hdGVzDQptbXNfY29yciRlc3RpbWF0ZSA8LSBtbXNfY29yciRlc3RpbWF0ZV9jb3JyDQojd2l0aCBib290c3RyYXBwZWQgc3RhbmRhcmQgZXJyb3JzDQptbXNfY29yciRzdGQuZXJyb3IgPC0gdGVzdDEkYm9vdFNFDQojYW5kIGNvbmZpZGVuY2UgaW50ZXJ2YWxzDQptbXNfY29yciR1cHBlciA8LSBtbXNfY29yciRlc3RpbWF0ZSArIDEuOTYqbW1zX2NvcnIkc3RkLmVycm9yDQptbXNfY29yciRsb3dlciA8LSBtbXNfY29yciRlc3RpbWF0ZSAtIDEuOTYqbW1zX2NvcnIkc3RkLmVycm9yDQoNCnAgPC0gcGxvdChtbXNfY29yciwgdmxpbmU9MS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIlN1Ymdyb3VwIiwgeGxhYiA9ICJNYXJnaW5hbCBtZWFuIikgKw0KICBmYWNldF9ncmlkMiggT3V0Y29tZSB+IEZlYXR1cmUsIHNjYWxlcyA9ICJmcmVlIiwgaW5kZXBlbmRlbnQgPSAieSIsIHN3aXRjaCA9ICJ5IikgKw0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlKSArDQogIGZhY2V0dGVkX3Bvc19zY2FsZXMoDQogICAgeSA9IGxpc3QoDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoInRocmVlIHF1YXJ0ZXJzICg3NSUpIiwgImhhbGYgKDUwJSkiLCAiYSBxdWFydGVyICgyNSUpIikpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygiaGFsZiAoNTAlKSIsICJqdXN0IHVuZGVyIGhhbGYgKDQwJSkiLCAiYSBxdWFydGVyICgyNSUpIikpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggVHVyay9Nb3JvYyBiYWNrZ3JvdW5kIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoImEgcXVhcnRlciAoMjUlKSIsICJtaW5vcml0eSAoMTAlKSIsICJub25lICgwJSkiKSkNCiAgICAgICksDQogICAgI2ZyZWVpbmcgdXAgdGhlIHggc2NhbGVzIGRvZXMgbm90IHdvcmsgZm9yIHNvbWUgcmVhc29uLi4uIHNvIGkgc2V0IHRoZW0gbWFudWFsbHk6DQogICAgeCA9IGxpc3QoDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiB+IHNjYWxlX3hfY29udGludW91cygNCiAgICAgICAgbGltaXRzID0gYyguMzUsLjY1KSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIGFnZWQgNTAgeWVhcnMgb3Igb2xkZXIiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC40MCwuNjApLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBUdXJrL01vcm9jIGJhY2tncm91bmQiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKDAsLjk1KSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpDQogICAgICApKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAjIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfbWFya2Rvd24oKSwNCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQ0KIA0KcCA8LSBwbG90X2dyaWQocCwgbGVnMTIzLCBhbGlnbiA9ICJoIiwgbnJvdz0yLCByZWxfaGVpZ2h0cyA9IGMoNywxKSkNCg0KI2ZzaG93ZGYobW1zX2NvcnJbLC1jKDE0LCAxNSwxNildLCBjYXB0aW9uID0gIk1lYXN1cmVtZW50IGVycm9yIGJpYXMgY29ycmVjdGVkIGNvbmRpdGlvbmFsIG1hcmdpbmFsIG1lYW5zIikNCg0KI3Bsb3QocCkNCmdnc2F2ZSgiLi9maWd1cmVzL2NtbXNfbGlzc19vbmx5Zmlyc3RfY29ycmVjdGVkLnBuZyIsIHAsIHdpZHRoPTEzKSANCmBgYCAgIA0KDQohWyoqU3ViZ3JvdXAgbWFyZ2luYWwgbWVhbnMsIG9ubHkgY29uc2lkZXJpbmcgdGhlIGZpcnN0IGNob2ljZSB0YXNrIHByZXNlbnRlZCB0byByZXNwb25kZW50cyoqXSguL2ZpZ3VyZXMvY21tc19saXNzX29ubHlmaXJzdF9jb3JyZWN0ZWQucG5nKQ0KDQoNCiMjIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9DQoNCiMjIyBzdWJncm91cCBzcGVjaWZpYyB0cmF2ZWwgdGltZSBlc3RpbWF0ZXMNCg0KYGBge3IsIHRyYXZlbHRpbWVfc3ViZ3JvdXAsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Nn0NCiMgZ2V0IGZ1bGwgc29sdXRpb24gZm9yIHN1Ymdyb3Vwcw0KbmJoVGVydCA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJFRlcnQpLF0sIGZuYmgsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflRlcnQpDQpjaXZUZXJ0IDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkVGVydCksXSwgZmNpdiwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VGVydCkNCm5iaEFnZSA8LSBjcmVnZzo6Y2ooZGZbIWlzLm5hKGRmJEFnZSksXSwgZm5iaCwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+QWdlKQ0KY2l2QWdlIDwtIGNyZWdnOjpjaihkZlshaXMubmEoZGYkQWdlKSxdLCBmY2l2LCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5BZ2UpDQpuYmhFdGggPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRUTSksXSwgZm5iaCwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VE0pDQpjaXZFdGggPC0gY3JlZ2c6OmNqKGRmWyFpcy5uYShkZiRUTSksXSwgZmNpdiwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VE0pDQoNCiMgZmlsdGVyIG9uIHRyYXZlbCB0aW1lIGF0dHJpYnV0ZXMNCm5iaF90aW1lVGVydCA8LSBuYmhUZXJ0W2dyZXAoInRpbWUiLCBuYmhUZXJ0JGZlYXR1cmUpLCBdDQpjaXZfdGltZVRlcnQgPC0gY2l2VGVydFtncmVwKCJ0aW1lIiwgY2l2VGVydCRmZWF0dXJlKSwgXQ0KbmJoX3RpbWVBZ2UgPC0gbmJoQWdlW2dyZXAoInRpbWUiLCBuYmhBZ2UkZmVhdHVyZSksIF0NCmNpdl90aW1lQWdlIDwtIGNpdkFnZVtncmVwKCJ0aW1lIiwgY2l2QWdlJGZlYXR1cmUpLCBdDQpuYmhfdGltZUV0aCA8LSBuYmhFdGhbZ3JlcCgidGltZSIsIG5iaEV0aCRmZWF0dXJlKSwgXQ0KY2l2X3RpbWVFdGggPC0gY2l2RXRoW2dyZXAoInRpbWUiLCBjaXZFdGgkZmVhdHVyZSksIF0NCg0KI25vdyBhZGp1c3QgdGhlIGVzdGltYXRlcyBmb3IgbWVhc3VyZW1lbnQgZXJyb3INCm5iaF90aW1lVGVydCRlc3RpbWF0ZVtuYmhfdGltZVRlcnQkQlkgPT0gIldpdGggY29sbGVnZSBkZWdyZWUiXSA8LSAobmJoX3RpbWVUZXJ0JGVzdGltYXRlW25iaF90aW1lVGVydCRCWSA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSJdIC0gc3dhcHBpbmdMaXN0JG5laWdoYm9yaG9vZHMkdGF1WyJXaXRoIGNvbGxlZ2UgZGVncmVlIl0pIC8gKDEgLSAyICogc3dhcHBpbmdMaXN0JG5laWdoYm9yaG9vZHMkdGF1WyJXaXRoIGNvbGxlZ2UgZGVncmVlIl0pDQpuYmhfdGltZVRlcnQkZXN0aW1hdGVbbmJoX3RpbWVUZXJ0JEJZID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIl0gPC0gKG5iaF90aW1lVGVydCRlc3RpbWF0ZVtuYmhfdGltZVRlcnQkQlkgPT0gIldpdGhvdXQgY29sbGVnZSBkZWdyZWUiXSAtIHN3YXBwaW5nTGlzdCRuZWlnaGJvcmhvb2RzJHRhdVsiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSJdKSAvICgxIC0gMiAqIHN3YXBwaW5nTGlzdCRuZWlnaGJvcmhvb2RzJHRhdVsiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSJdKQ0KY2l2X3RpbWVUZXJ0JGVzdGltYXRlW2Npdl90aW1lVGVydCRCWSA9PSAiV2l0aCBjb2xsZWdlIGRlZ3JlZSJdIDwtIChjaXZfdGltZVRlcnQkZXN0aW1hdGVbY2l2X3RpbWVUZXJ0JEJZID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIl0gLSBzd2FwcGluZ0xpc3QkbmVpZ2hib3Job29kcyR0YXVbIldpdGggY29sbGVnZSBkZWdyZWUiXSkgLyAoMSAtIDIgKiBzd2FwcGluZ0xpc3QkbmVpZ2hib3Job29kcyR0YXVbIldpdGggY29sbGVnZSBkZWdyZWUiXSkNCmNpdl90aW1lVGVydCRlc3RpbWF0ZVtjaXZfdGltZVRlcnQkQlkgPT0gIldpdGhvdXQgY29sbGVnZSBkZWdyZWUiXSA8LSAoY2l2X3RpbWVUZXJ0JGVzdGltYXRlW2Npdl90aW1lVGVydCRCWSA9PSAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSJdIC0gc3dhcHBpbmdMaXN0JG5laWdoYm9yaG9vZHMkdGF1WyJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIl0pIC8gKDEgLSAyICogc3dhcHBpbmdMaXN0JG5laWdoYm9yaG9vZHMkdGF1WyJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIl0pDQoNCm5iaF90aW1lQWdlJGVzdGltYXRlW25iaF90aW1lQWdlJEJZID09ICI1MCB5ZWFycyBvciBvbGRlciJdIDwtIChuYmhfdGltZUFnZSRlc3RpbWF0ZVtuYmhfdGltZUFnZSRCWSA9PSAiNTAgeWVhcnMgb3Igb2xkZXIiXSAtIHN3YXBwaW5nTGlzdCRuZWlnaGJvcmhvb2RzJHRhdVsiNTAgeWVhcnMgb3Igb2xkZXIiXSkgLyAoMSAtIDIgKiBzd2FwcGluZ0xpc3QkbmVpZ2hib3Job29kcyR0YXVbIjUwIHllYXJzIG9yIG9sZGVyIl0pDQpuYmhfdGltZUFnZSRlc3RpbWF0ZVtuYmhfdGltZUFnZSRCWSA9PSAiQmVsb3cgNTAgeWVhcnMiXSA8LSAobmJoX3RpbWVBZ2UkZXN0aW1hdGVbbmJoX3RpbWVBZ2UkQlkgPT0gIkJlbG93IDUwIHllYXJzIl0gLSBzd2FwcGluZ0xpc3QkbmVpZ2hib3Job29kcyR0YXVbIkJlbG93IDUwIHllYXJzIl0pIC8gKDEgLSAyICogc3dhcHBpbmdMaXN0JG5laWdoYm9yaG9vZHMkdGF1WyJCZWxvdyA1MCB5ZWFycyJdKQ0KY2l2X3RpbWVBZ2UkZXN0aW1hdGVbY2l2X3RpbWVBZ2UkQlkgPT0gIjUwIHllYXJzIG9yIG9sZGVyIl0gPC0gKGNpdl90aW1lQWdlJGVzdGltYXRlW2Npdl90aW1lQWdlJEJZID09ICI1MCB5ZWFycyBvciBvbGRlciJdIC0gc3dhcHBpbmdMaXN0JG5laWdoYm9yaG9vZHMkdGF1WyI1MCB5ZWFycyBvciBvbGRlciJdKSAvICgxIC0gMiAqIHN3YXBwaW5nTGlzdCRuZWlnaGJvcmhvb2RzJHRhdVsiNTAgeWVhcnMgb3Igb2xkZXIiXSkNCmNpdl90aW1lQWdlJGVzdGltYXRlW2Npdl90aW1lQWdlJEJZID09ICJCZWxvdyA1MCB5ZWFycyJdIDwtIChjaXZfdGltZUFnZSRlc3RpbWF0ZVtjaXZfdGltZUFnZSRCWSA9PSAiQmVsb3cgNTAgeWVhcnMiXSAtIHN3YXBwaW5nTGlzdCRuZWlnaGJvcmhvb2RzJHRhdVsiQmVsb3cgNTAgeWVhcnMiXSkgLyAoMSAtIDIgKiBzd2FwcGluZ0xpc3QkbmVpZ2hib3Job29kcyR0YXVbIkJlbG93IDUwIHllYXJzIl0pDQoNCm5iaF90aW1lRXRoJGVzdGltYXRlW25iaF90aW1lRXRoJEJZID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiXSA8LSAobmJoX3RpbWVFdGgkZXN0aW1hdGVbbmJoX3RpbWVFdGgkQlkgPT0gIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCJdIC0gc3dhcHBpbmdMaXN0JG5laWdoYm9yaG9vZHMkdGF1WyJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiXSkgLyAoMSAtIDIgKiBzd2FwcGluZ0xpc3QkbmVpZ2hib3Job29kcyR0YXVbIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCJdKQ0KbmJoX3RpbWVFdGgkZXN0aW1hdGVbbmJoX3RpbWVFdGgkQlkgPT0gIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIl0gPC0gKG5iaF90aW1lRXRoJGVzdGltYXRlW25iaF90aW1lRXRoJEJZID09ICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCJdIC0gc3dhcHBpbmdMaXN0JG5laWdoYm9yaG9vZHMkdGF1WyJObyBtaWdyYXRpb24gYmFja2dyb3VuZCJdKSAvICgxIC0gMiAqIHN3YXBwaW5nTGlzdCRuZWlnaGJvcmhvb2RzJHRhdVsiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiXSkNCmNpdl90aW1lRXRoJGVzdGltYXRlW2Npdl90aW1lRXRoJEJZID09ICJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiXSA8LSAoY2l2X3RpbWVFdGgkZXN0aW1hdGVbY2l2X3RpbWVFdGgkQlkgPT0gIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCJdIC0gc3dhcHBpbmdMaXN0JG5laWdoYm9yaG9vZHMkdGF1WyJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiXSkgLyAoMSAtIDIgKiBzd2FwcGluZ0xpc3QkbmVpZ2hib3Job29kcyR0YXVbIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCJdKQ0KY2l2X3RpbWVFdGgkZXN0aW1hdGVbY2l2X3RpbWVFdGgkQlkgPT0gIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIl0gPC0gKGNpdl90aW1lRXRoJGVzdGltYXRlW2Npdl90aW1lRXRoJEJZID09ICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCJdIC0gc3dhcHBpbmdMaXN0JG5laWdoYm9yaG9vZHMkdGF1WyJObyBtaWdyYXRpb24gYmFja2dyb3VuZCJdKSAvICgxIC0gMiAqIHN3YXBwaW5nTGlzdCRuZWlnaGJvcmhvb2RzJHRhdVsiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiXSkNCg0KdGltZV9lc3RpbWF0ZXMgPC0gcmJpbmQoDQogIGNpdl90aW1lVGVydFssIGMoMSwgMiwgNSw2KV0sDQogIG5iaF90aW1lVGVydFssIGMoMSwgMiwgNSw2KV0sDQogIGNpdl90aW1lQWdlWywgYygxLCAyLCA1LDYpXSwNCiAgbmJoX3RpbWVBZ2VbLCBjKDEsIDIsIDUsNildLA0KICBjaXZfdGltZUV0aFssIGMoMSwgMiwgNSw2KV0sDQogIG5iaF90aW1lRXRoWywgYygxLCAyLCA1LDYpXQ0KKQ0KDQpjb2xuYW1lcyh0aW1lX2VzdGltYXRlcykgPC0gYygiUmVzcG9uZGVudF9zdWJncm91cCIsICJTZXR0aW5nIiwgIkxldmVsIiwgIkVzdGltYXRlIikNCnRpbWVfZXN0aW1hdGVzJFNldHRpbmcgPC0gaWZlbHNlKHRpbWVfZXN0aW1hdGVzJFNldHRpbmcgPT0gImVjaXZfY2hvaWNlIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiLCAiTmVpZ2hib3Job29kcyIpDQp0aW1lX2VzdGltYXRlcyRTZXR0aW5nIDwtIGZhY3Rvcih0aW1lX2VzdGltYXRlcyRTZXR0aW5nLCBsZXZlbHMgPSBjKCJOZWlnaGJvcmhvb2RzIiwgIkNpdmljIG9yZ2FuaXphdGlvbnMiKSkNCnRpbWVfZXN0aW1hdGVzJExldmVsIDwtIGdzdWIoInRyYXZlbCB0aW1lIHRvIGZhY2lsaXRpZXM6ICIsICIiLCBnc3ViKCJ0cmF2ZWwgdGltZTogIiwgIiIsIHRpbWVfZXN0aW1hdGVzJExldmVsKSkNCg0KZ2dwbG90KHRpbWVfZXN0aW1hdGVzLCBhZXMoeCA9IExldmVsLCB5ID0gRXN0aW1hdGUsIGNvbG9yID0gU2V0dGluZywgZ3JvdXAgPSBpbnRlcmFjdGlvbihTZXR0aW5nLCBSZXNwb25kZW50X3N1Ymdyb3VwKSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMykgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAwLjgpICsNCiAgZmFjZXRfZ3JpZChTZXR0aW5nIH4gUmVzcG9uZGVudF9zdWJncm91cCwgc2NhbGVzID0gImZyZWVfeCIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJDb3JyZWN0ZWQgc3ViZ3JvdXAgbWFyZ2luYWwgbWVhbnMgZm9yIHRyYXZlbCB0aW1lIGxldmVscyIsDQogICAgc3VidGl0bGUgPSAiRGFzaGVkIGxpbmVzIHJlcHJlc2VudCBsaW5lYXIgZWZmZWN0cyIsDQogICAgeCA9ICJUcmF2ZWwgdGltZSAodG8ga2V5IGFtZW5pdGllcyAvIGZyb20gaG9tZSkiLA0KICAgIHkgPSAiTWFyZ2luYWwgbWVhbiIsDQogICAgY29sb3IgPSAiU2V0dGluZyINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCANCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgICAgICANCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApDQogICkNCg0KZnNob3dkZih0aW1lX2VzdGltYXRlcywgY2FwdGlvbiA9ICJDb3JyZWN0ZWQgc3ViZ3JvdXAgbWFyZ2luYWwgbWVhbnMgZm9yIHRyYXZlbCB0aW1lIGxldmVscyIsIGRpZ2l0PTMpDQpgYGANCg0KDQoNCi0tLQ0KDQojIFRSSUFMIHNwb3J0cyBjbHViIGNob2ljZSBleHBlcmltZW50DQoNCiMjIFN1Ymdyb3VwIG1hcmdpbmFsIG1lYW5zDQogIA0KYGBge3IsIGNtbXMyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0gDQojY3JlYXRlIHN1Ymdyb3Vwcw0KDQpkZjIkVGVydCA8LSBOQV9yZWFsXw0KZGYyJFRlcnRbZGYyJHRlcnRfZWR1YyA9PSAxXSA8LSAxTA0KZGYyJFRlcnRbZGYyJHRlcnRfZWR1YyA9PSAwXSA8LSAyTA0KZGYyJFRlcnQgPC0gZmFjdG9yKGRmMiRUZXJ0LCAxOjIsIGMoIldpdGggY29sbGVnZSBkZWdyZWUiLCAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIpKQ0KDQpkZjIkTWlnciA8LSBOQV9yZWFsXw0KZGYyJE1pZ3JbZGYyJG1pZ3JhdGlvbiA9PSAxXSA8LSAxTA0KZGYyJE1pZ3JbZGYyJG1pZ3JhdGlvbiA9PSAwXSA8LSAyTA0KZGYyJE1pZ3IgPC0gZmFjdG9yKGRmMiRNaWdyLCAxOjIsIGMoICJNaWdyYXRpb24gYmFja2dyb3VuZCIsIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIikpDQoNCiNvdXRjb21lIGFuZCBjb25qb2ludCBmZWF0dXJlcywgaW5jbHVkaW5nIG9ubHkgY29tcG9zaXRpb24gZmVhdHVyZXMgd2UgYXJlIGludGVyZXN0ZWQgaW47DQojYW5kIHRoZSBzdWJncm91cGluZyB2YXJpYWJsZQ0KDQojY29uZGl0aW9uYWwgbWFyZ2luYWwgbWVhbnMgKGNvbXBvc2l0aW9uIGRpbWVuc2lvbjsgZGlzYWdncmVnYXRlZCBieSByZXNwb25kZW50IHZhbHVlIGZvciB0aGlzIGRpbWVuc2lvbikNCg0KIzEuIGNsdWINCmNtbWVkdWMgPC0gY3JlZ2c6OmNqKGRmMlshaXMubmEoZGYyJFRlcnQpLCBdLCBjaG9pY2UgfiBlZHVjX2NsdWIsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflRlcnQpDQpjbW1ldGggPC0gY3JlZ2c6OmNqKGRmMlshaXMubmEoZGYyJE1pZ3IpLCBdLCBjaG9pY2UgfiBtaWdyYW50X2NsdWIsIGlkIH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5NaWdyKQ0KDQojMi4gdGVhbQ0KdG1tZWR1YyA8LSBjcmVnZzo6Y2ooZGYyWyFpcy5uYShkZjIkVGVydCksIF0sIGNob2ljZSB+IGVkdWNfdGVhbSwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VGVydCkNCnRtbWV0aCA8LSBjcmVnZzo6Y2ooZGYyWyFpcy5uYShkZjIkTWlnciksIF0sIGNob2ljZSB+IG1pZ3JhbnRfdGVhbSwgaWQgfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gfk1pZ3IpDQoNCiNyb3diaW5kIHRoZSBkYXRhZnJhbWVzDQojbGVhdmUgb3V0IGxhc3QgY29sdW1uLCByZWZsZWN0aW5nIHRoZSBzdWJncm91cGluZyB2YXJpYWJsZQ0KbW1zIDwtIHJiaW5kKGNtbWVkdWNbLTEyXSx0bW1lZHVjWy0xMl0sDQogICAgICAgICAgICAgY21tZXRoWy0xMl0sdG1tZXRoWy0xMl0pDQoNCiNyZW5hbWUgbGFiZWxzDQojMS4gb2Ygb3V0Y29tZSAoc2V0dGluZykNCm1tcyRPdXRjb21lIDwtIGZhY3RvcihpZmVsc2UoIGdyZXBsKCJjbHViIiwgbW1zJGZlYXR1cmUpLCAiQ2x1YiIsICJUZWFtIC8gdHJhaW5pbmcgZ3JvdXAiKSwgbGV2ZWxzID0gYygiQ2x1YiIsICJUZWFtIC8gdHJhaW5pbmcgZ3JvdXAiKSkNCg0KIzIuIG9mIChkZW1vZ3JhcGhpYyBjb21wb3NpdGlvbikgZmVhdHVyZXMNCm1tcyRGZWF0dXJlIDwtIGZhY3RvcihzdWIoIl8uKyIsICIiLCBtbXMkZmVhdHVyZSksIGxldmVscyA9IGMoIm1pZ3JhbnQiLCAiZWR1YyIpLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiLCAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIpKQ0KDQptbXMkU3ViZ3JvdXAgPC0gbW1zJEJZDQoNCiMgbmljZSBjb2xvciBwYWxldHRlDQpjYlBhbGV0dGUgPC0gYygiI0YwRTQ0MiIsIiMwMDcyQjIiLCAiIzU2QjRFOSIsIiNENTVFMDAiKQ0KDQpwIDwtIHBsb3QobW1zLCB2bGluZT0xLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiU3ViZ3JvdXAiKSArDQogIGZhY2V0X2dyaWQyKCBPdXRjb21lIH4gRmVhdHVyZSwgc2NhbGVzID0gImZyZWUiLCBpbmRlcGVuZGVudCA9ICJ5Iiwgc3dpdGNoID0gInkiKSArDQogIGdlb21fdGV4dCggYWVzKGxhYmVsID0gc3ByaW50ZigiJTAuMmYgKCUwLjJmKSIsIGVzdGltYXRlLCBzdGQuZXJyb3IpKSwgc2l6ZSA9IDMsIGNvbG91ciA9ICJibGFjayIsIHZqdXN0ID0gLTEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGUpICsNCiAgZmFjZXR0ZWRfcG9zX3NjYWxlcygNCiAgICB5ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiICYgT3V0Y29tZSA9PSAiQ2x1YiIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJ0aHJlZSBxdWFydGVycyAoNzUlKSIsICJoYWxmICg1MCUpIiwgImEgcXVhcnRlciAoMjUlKSIpKSwNCiAgICAgIA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIgICYgT3V0Y29tZSA9PSAiVGVhbSAvIHRyYWluaW5nIGdyb3VwIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoIm1ham9yaXR5ICg5MCUpIiwgInRocmVlIHF1YXJ0ZXJzICg3NSUpIiwgImhhbGYgKDUwJSkiLCAiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIikpLA0KICAgICAgDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiAmIE91dGNvbWUgPT0gIkNsdWIiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIiwgImEgZmV3ICg1JSkiKSksDQogICAgICANCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiICYgT3V0Y29tZSA9PSAiVGVhbSAvIHRyYWluaW5nIGdyb3VwIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoImhhbGYgKDUwJSkiLCAiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIiwgImEgZmV3ICg1JSkiLCAibm9uZSAoMCUpIikpDQogICAgKSwNCiAgICAjZnJlZWluZyB1cCB0aGUgeCBzY2FsZXMgZG9lcyBub3Qgd29yayBmb3Igc29tZSByZWFzb24uLi4gc28gaSBzZXQgdGhlbSBtYW51YWxseToNCiAgICB4ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC40MiwuNTgpLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSksDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiB+IHNjYWxlX3hfY29udGludW91cygNCiAgICAgICAgbGltaXRzID0gYyguNDIsLjU4KSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpDQogICAgKQ0KICApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAjc3RyaXAudGV4dC54ID0gZWxlbWVudF9tYXJrZG93bigpLA0KICAgICAgICBzdHJpcC5wbGFjZW1lbnQgPSAib3V0c2lkZSIpDQoNCiNzcGxpdCBsZWdlbmQgaW50byBtdWx0aXBsZSBwYXJ0cw0Kc3BsaXQxIDwtIG1tc1ttbXMkU3ViZ3JvdXAgJWluJSBjKCJNaWdyYXRpb24gYmFja2dyb3VuZCIsICJObyBtaWdyYXRpb24gYmFja2dyb3VuZCIpLCBdDQpzcGxpdDIgPC0gbW1zW21tcyRTdWJncm91cCAlaW4lIGMoIldpdGggY29sbGVnZSBkZWdyZWUiLCAiV2l0aG91dCBjb2xsZWdlIGRlZ3JlZSIpLCBdDQoNCiNyZXZlcnNlIG9yZGVyIGZhY3Rvci4uLi4gYnVnIGluIGdncGxvdDIgbWFrZXMgdGhlIG9yZGVyIG9mIHRoZSBzdWJncm91cHMgaW4gdGhlIHBsb3QgYW5kIHRoZSBsZWdlbmQgcmV2ZXJzZWQNCnNwbGl0MSRTdWJncm91cCA8LSBmYWN0b3Ioc3BsaXQxJFN1Ymdyb3VwLCBsZXZlbHMgPSByZXYobGV2ZWxzKHNwbGl0MSRTdWJncm91cCkpKQ0Kc3BsaXQyJFN1Ymdyb3VwIDwtIGZhY3RvcihzcGxpdDIkU3ViZ3JvdXAsIGxldmVscyA9IHJldihsZXZlbHMoc3BsaXQyJFN1Ymdyb3VwKSkpDQoNCiNwbG90IGxlZ2VuZHMNCnNwbGl0MXAgPC0gZ2dwbG90KHNwbGl0MSwgYWVzKHggPSBlc3RpbWF0ZSwgeSA9IGxldmVsLCBjb2xvcj1TdWJncm91cCkpICsgZ2VvbV9wb2ludCgpICsgbGFicyhjb2xvciA9ICJSZXNwb25kZW50IHN1Ymdyb3VwczoiKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoNCwzKV0pIA0Kc3BsaXQycCA8LSBnZ3Bsb3Qoc3BsaXQyLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gbGV2ZWwsIGNvbG9yPVN1Ymdyb3VwKSkgKyBnZW9tX3BvaW50KCkgKyBsYWJzKGNvbG9yID0gIlJlc3BvbmRlbnQgc3ViZ3JvdXBzOiIpICsgdGhlbWVfYncoKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGVbYygyLDEpXSkNCg0KI2dldCBsZWdlbmRzDQpsZWcxIDwtIGdldF9sZWdlbmQoc3BsaXQxcCkNCmxlZzIgPC0gZ2V0X2xlZ2VuZChzcGxpdDJwKQ0KDQojY29tYmluZSBsZWdlbmRzDQpsZWcxMiA8LSBwbG90X2dyaWQobGVnMSxsZWcyLCBucm93PTEsIGFsaWduPSJoIikNCg0KI2NyZWF0ZSBhIGJsYW5rIHBsb3QgZm9yIGxlZ2VuZCBhbGlnbm1lbnQNCmJsYW5rX3AgPC0gcGxvdF9zcGFjZXIoKQ0KDQojY29tYmluZSBhbGwgaW4gb25lDQpwIDwtIHBsb3RfZ3JpZChwLCBsZWcxMiwgYWxpZ24gPSAiaCIsIG5yb3c9MiwgcmVsX2hlaWdodHMgPSBjKDksMSkpDQoNCnByaW50KHApDQojZ2dzYXZlKCIuL2ZpZ3VyZXMvY21tc190cmlhbC5wbmciLCBwLCB3aWR0aD05KSANCmBgYCAgICAgICAgICAgDQoNCg0KLS0tDQoNCg0KIyMgdXNlIExJU1MtYmFzZWQgYmlhcyBjb3JyZWN0aW9uDQoNCmBgYHtyLCBzd2FwcGluZzIsIGV2YWwgPSBGQUxTRX0NCiNjcmVhdGUgZGF0YWZyYW1lDQpzd2FwcGluZzIgPC0gZGF0YS5mcmFtZSh4ID0gYygiV2l0aCBjb2xsZWdlIGRlZ3JlZSIsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiwgIk1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiksIHRhdSA9IE5BKQ0KDQojd2UgcmV0cmlldmUgTElTUy1iYXNlZCBzd2FwcGluZyBlcnJvcnMNCnN3YXBwaW5nMiR0YXUgPC0gaWZlbHNlKHN3YXBwaW5nMiR4ID09ICJXaXRoIGNvbGxlZ2UgZGVncmVlIiwgc3dhcHBpbmckb3JnYW5pemF0aW9ucyR0YXVbWyJXaXRoIGNvbGxlZ2UgZGVncmVlIl1dLA0KICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHN3YXBwaW5nMiR4ID09ICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiwgc3dhcHBpbmckb3JnYW5pemF0aW9ucyR0YXVbWyJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIl1dLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzd2FwcGluZzIkeCA9PSAiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiLCBzd2FwcGluZyRvcmdhbml6YXRpb25zJHRhdVtbIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIl1dLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc3dhcHBpbmcyJHggPT0gIk1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiwgc3dhcHBpbmckb3JnYW5pemF0aW9ucyR0YXVbWyJUdXJraXNoL01vcm9jY2FuIGJhY2tncm91bmQiXV0sIE5BKSkpKQ0KDQpmYm9vdCA8LSBmdW5jdGlvbihkYXRhLCBpKSB7DQogICMgc2FtcGxlIHJlc3BvbmRlbnQgSURzIHdpdGggcmVwbGFjZW1lbnQNCiAgaWRzIDwtIHNhbXBsZSh1bmlxdWUoZGF0YSRpZCksIGxlbmd0aCh1bmlxdWUoZGF0YSRpZCkpLCByZXBsYWNlID0gVFJVRSkNCiAgDQogICMgY3JlYXRlIGEgbmV3IGRhdGFzZXQgYnkgaXRlcmF0aW5nIG92ZXIgZWFjaCBzYW1wbGVkIGlkIGFuZCBiaW5kaW5nIHRoZSBtYXRjaGluZyByb3dzDQogIGQgPC0gbWFwX2RmcihpZHMsIH4gZGF0YSAlPiUgZmlsdGVyKGlkID09IC54KSkgDQoNCiAgIyBjYWxjdWxhdGUgY29uZGl0aW9uYWwgbWFyZ2luYWwgbWVhbnM6DQogIHhfdmFycyA8LSBjYmluZChjKCJNaWdyIiwgIlRlcnQiKSwgYygibWlncmFudCIsICJlZHVjIikpDQogIHlfdmFycyA8LSBjKCJjbHViIiwgInRlYW0iKQ0KICAgIA0KICByZXN1bHRzIDwtIGRhdGEuZnJhbWUoKQ0KDQogIGZvcih4IGluIDE6bnJvdyh4X3ZhcnMpKSB7DQogICAgZm9yKHkgaW4geV92YXJzKSB7DQogICAgICANCiAgICAgICMgZm9ybXVsYSAgDQogICAgICBmIDwtIGFzLmZvcm11bGEocGFzdGUwKCJjaG9pY2UgfiAiLCB4X3ZhcnNbeCwyXSwgIl8iLCB5KSkNCiAgICAgIGJ5IDwtIGFzLmZvcm11bGEocGFzdGUwKCJ+IiwgeF92YXJzW3gsMV0pKQ0KICAgICAgDQogICAgICBjbW1zIDwtIGNyZWdnOjpjaiggZFshaXMubmEoZFt4X3ZhcnNbeCwxXV0pLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm11bGEgPSBmLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IGJ5KQ0KICAgICAgDQogICAgICAjYmluZCByZXN1bHRzDQogICAgICByZXN1bHRzIDwtIHJiaW5kKHJlc3VsdHMsIGNtbXNbLC0xMl0pDQogICAgICB9DQogICAgfQ0KDQogICNjYWxjdWxhdGUgY29ycmVjdGVkIGNvbmRpdGlvbmFsIG1hcmdpbmFsIG1lYW4gKGZvciBzdWJncm91cHMpDQogIHJlc3VsdHMkZXN0aW1hdGVfY29yciA8LSBOQQ0KICAgIA0KICBmb3IgKGkgaW4gMTpucm93KHJlc3VsdHMpKSB7IA0KICAgICNyZXRyaWV2ZSBzdWJncm91cA0KICAgIHN1Ymdyb3VwIDwtIGFzLmNoYXJhY3RlcihyZXN1bHRzJEJZW2ldKQ0KICAgIHRhdSA8LSBzd2FwcGluZzIkdGF1W3N3YXBwaW5nMiR4ID09IHN1Ymdyb3VwXQ0KICAgIA0KICAgICNkZWZpbmUgYmlhcyBjb3JyZWN0ZWQgTU0gKGVxLiAxMSBvZiBDbGF5dG9uIGV0IGFsLikNCiAgICByZXN1bHRzJGVzdGltYXRlX2NvcnJbaV0gPC0gKHJlc3VsdHMkZXN0aW1hdGVbaV0gLSB0YXUpIC8gKDEgLSAyKnRhdSkNCg0KICB9DQogICNzYXZlIHJvd25hbWVzDQogICNybmFtZXMzIDwtIHBhc3RlMCggcmVzdWx0cyRvdXRjb21lLCAiLSIsIHJlc3VsdHMkbGV2ZWwsICItIiwgcmVzdWx0cyRCWSkNCiAgI3NhdmUocm5hbWVzMywgZmlsZSA9ICIuL2RhdGEvcm93bmFtZXMzLlJkYSIpDQogICANCiAgcmV0dXJuKHJlc3VsdHMkZXN0aW1hdGVfY29ycikgIA0KfQ0KI2Zib290KGRmMikjdGVzdA0KDQpuQ29yZSA8LSBkZXRlY3RDb3JlcygpIC0gMSAjZGV0ZWN0IG51bWJlciBvZiBjb3JlcyAoa2VlcCBvbmUgZm9yIG90aGVyIHRhc2tzKQ0Kbkl0ZXIgPC0gMTAwMCAjbnVtYmVyIG9mIGJvb3RzdHJhcCBpdGVyYXRpb25zDQoNCiNzZXQgdXAgY2x1c3Rlcg0KbXljbCA8LSBtYWtlQ2x1c3RlcihyZXAoImxvY2FsaG9zdCIsIG5Db3JlKSkgDQoNCiNsb2FkIG5lY2Vzc2FyeSBsaWJyYXJ5IG9uIGVhY2ggY2x1c3RlciBub2RlDQpjbHVzdGVyRXZhbFEobXljbCwgew0KICBsaWJyYXJ5KGNyZWdnKQ0KICBsaWJyYXJ5KHB1cnJyKQ0KICBsaWJyYXJ5KGRwbHlyKQ0KfSkNCg0KI2NvcHkgZGF0YSBhbmQgY3VzdG9tIGZ1bmN0aW9ucyB0byBlYWNoIG5vZGUncyB3b3Jrc3BhY2UNCmNsdXN0ZXJFeHBvcnQobXljbCwgdmFybGlzdD1jKCJkZjIiLCAiZl90YXUiLCAiZl9pcnIiLCAiZmJvb3QiLCAic3dhcHBpbmcyIikpIA0KDQojcGVyZm9ybSBib290c3RyYXA6DQpzeXN0ZW0udGltZSh0ZXN0IDwtIGJvb3QoZGYyLCBmYm9vdCwgUj1uSXRlciwgcGFyYWxsZWwgPSAic25vdyIsIG5jcHVzID0gbkNvcmUsIGNsID0gbXljbCkpICNhYm91dCAzMCBtaW4gb24gbXkgcGMNCiNzYXZlKHRlc3QsIGZpbGUgPSAiLi9yZXN1bHRzL2Jvb3Q1LlJkYSIpDQpzdG9wQ2x1c3RlcihteWNsKQ0KYGBgIA0KDQpgYGB7ciwgY29ycnBsb3QyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9OSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0gDQpsb2FkKCIuL3Jlc3VsdHMvYm9vdDUuUmRhIikNCmxvYWQoIi4vZGF0YS9yb3duYW1lczMuUmRhIikNCm5JdGVyID0gMTAwMA0KDQp0ZXN0MSA8LSBzdW1tYXJ5KHRlc3QpDQojYWRkIHJvd25hbWVzDQpyb3duYW1lcyh0ZXN0MSkgPC0gcm5hbWVzMw0KDQojcHJpbnQodGVzdDEpDQoNCiNmaXJzdCBhZGQgdGhlIG9yaWdpbmFsIGJpYXMgY29ycmVjdGVkIENNTXMgdG8gdGhlIGRhdGFmcmFtZToNCiNjcmVhdGUgYSBtZXJnZSB2YXJpYWJsZSBpbiB0aGUgb3JpZ2luYWwgQ01NIGRhdGFmcmFtZQ0KbW1zJEJZMiA8LSBwYXN0ZTAobW1zJG91dGNvbWUsICItIiwgbW1zJGxldmVsLCAiLSIsIG1tcyRCWSkNCiNyZW9yZGVyDQptbXMgPC0gbW1zW21hdGNoKHJvd25hbWVzKHRlc3QxKSwgbW1zJEJZMiksXQ0KDQojbm93IGNhbGN1bGF0ZSB0aGUgY29ycmVjdGVkIENNTVMNCmZvciAoaSBpbiAxOm5yb3cobW1zKSkgeyAjIGZvciBlYWNoIENNTQ0KICAgICNyZXRyaWV2ZSBzZXR0aW5nIGFuZCBzdWJncm91cA0KICAgIHNldHRpbmcgPC0gIm9yZ2FuaXphdGlvbnMiICN1c2UgTElTUy1iYXNlZCBzd2FwcGluZyBlcnJvciBmb3Igb3JnYW5pemF0aW9ucyBleHBlcmltZW50DQogICAgc3ViZ3JvdXAgPC0gYXMuY2hhcmFjdGVyKG1tcyRCWVtpXSkNCiAgICBzdWJncm91cCA8LSBpZmVsc2Uoc3ViZ3JvdXAgPT0gIk1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiwgIlR1cmtpc2gvTW9yb2NjYW4gYmFja2dyb3VuZCIsIHN1Ymdyb3VwKSAjIGlmIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kLCB1c2Ugc3dhcHBpbmcgZXJyb3Igb2YgVE0NCiAgICAjZ2V0IHRhdSBmcm9tIG91ciBzYXZlZCBsaXN0DQogICAgdGF1IDwtIHN3YXBwaW5nTGlzdFtbc2V0dGluZ11dJHRhdVtzdWJncm91cF0NCiAgICAjZGVmaW5lIGJpYXMgY29ycmVjdGVkIE1NIChlcS4gMTEgb2YgQ2xheXRvbiBldCBhbC4pDQogICAgbW1zJGVzdGltYXRlX2NvcnJbaV0gPC0gKG1tcyRlc3RpbWF0ZVtpXSAtIHRhdSkgLyAoMSAtIDIqdGF1KQ0KfQ0KDQojYWRkIHRoZXNlIHN0YXRpc3RpY3MgdG8gcGxvdHRpbmcgZGF0YQ0KDQojY3JlYXRlIGNvcHkgb2YgbW1zDQptbXNfY29yciA8LSBtbXMNCg0KI3VzZSBjb3JyZWN0ZWQgZXN0aW1hdGVzDQptbXNfY29yciRlc3RpbWF0ZSA8LSBtbXNfY29yciRlc3RpbWF0ZV9jb3JyDQoNCiN3aXRoIGJvb3RzdHJhcHBlZCBzdGFuZGFyZCBlcnJvcnMNCm1tc19jb3JyJHN0ZC5lcnJvciA8LSB0ZXN0MSRib290U0UNCiNhbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMNCm1tc19jb3JyJHVwcGVyIDwtIG1tc19jb3JyJGVzdGltYXRlICsgMS45NiptbXNfY29yciRzdGQuZXJyb3INCm1tc19jb3JyJGxvd2VyIDwtIG1tc19jb3JyJGVzdGltYXRlIC0gMS45NiptbXNfY29yciRzdGQuZXJyb3INCg0KI3Bsb3QNCnAgPC0gcGxvdChtbXNfY29yciwgdmxpbmU9MS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIlN1Ymdyb3VwIiwgeGxhYiA9ICJNYXJnaW5hbCBtZWFuIikgKw0KICBmYWNldF9ncmlkMiggT3V0Y29tZSB+IEZlYXR1cmUsIHNjYWxlcyA9ICJmcmVlIiwgaW5kZXBlbmRlbnQgPSAieSIsIHN3aXRjaCA9ICJ5IikgKw0KICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlKSArDQogIGZhY2V0dGVkX3Bvc19zY2FsZXMoDQogICAgeSA9IGxpc3QoDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiAmIE91dGNvbWUgPT0gIkNsdWIiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygidGhyZWUgcXVhcnRlcnMgKDc1JSkiLCAiaGFsZiAoNTAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSksDQogICAgICANCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgY29sbGVnZSBkZWdyZWUiICAmIE91dGNvbWUgPT0gIlRlYW0gLyB0cmFpbmluZyBncm91cCIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJtYWpvcml0eSAoOTAlKSIsICJ0aHJlZSBxdWFydGVycyAoNzUlKSIsICJoYWxmICg1MCUpIiwgImEgcXVhcnRlciAoMjUlKSIsICJtaW5vcml0eSAoMTAlKSIpKSwNCiAgICAgICAgDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiAmIE91dGNvbWUgPT0gIkNsdWIiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIiwgImEgZmV3ICg1JSkiKSksDQogICAgICANCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiICYgT3V0Y29tZSA9PSAiVGVhbSAvIHRyYWluaW5nIGdyb3VwIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoImhhbGYgKDUwJSkiLCAiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIiwgImEgZmV3ICg1JSkiLCAibm9uZSAoMCUpIikpDQogICAgICApLA0KICAgICNmcmVlaW5nIHVwIHRoZSB4IHNjYWxlcyBkb2VzIG5vdCB3b3JrIGZvciBzb21lIHJlYXNvbi4uLiBzbyBpIHNldCB0aGVtIG1hbnVhbGx5Og0KICAgIHggPSBsaXN0KA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIgfiBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgICAgIGxpbWl0cyA9IGMoLjM4LC42MCksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSwNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC4yOCwuNzApLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkNCiAgICApDQogICAgKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgI3N0cmlwLnRleHQueCA9IGVsZW1lbnRfbWFya2Rvd24oKSwNCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQ0KDQpwIDwtIHBsb3RfZ3JpZChwLCBsZWcxMiwgYWxpZ24gPSAiaCIsIG5yb3c9MiwgcmVsX2hlaWdodHMgPSBjKDksMSkpDQpmc2hvd2RmKG1tc19jb3JyWywtYygxNSwxNildLCBjYXB0aW9uID0gIk1lYXN1cmVtZW50IGVycm9yIGJpYXMgY29ycmVjdGVkIGNvbmRpdGlvbmFsIG1hcmdpbmFsIG1lYW5zIikNCg0KcGxvdChwKQ0KI2dnc2F2ZSgiLi9maWd1cmVzL2NtbXNfdHJpYWxfY29ycmVjdGVkLnBuZyIsIHAsIHdpZHRoPTkpIA0KI2dnc2F2ZSgiLi9maWd1cmVzL2ZpZ3VyZTA0X3N1Ymdyb3VwX21tLnBuZyIsIHAsIHdpZHRoPTkpIA0KYGBgICAgDQoNCjxicj4NCg0KIyMgc2Vuc2l0aXZpdHkgY2hlY2tzDQoNCiMjIyBmb2N1cyBvbmx5IG9uIHRob3NlIHdpdGggbm9uLXdlc3Rlcm4gbWlncmF0aW9uIGJhY2tncm91bmQNCg0KYGBge3IsIGNtbXNfbncsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD05LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30gDQojY3JlYXRlIG5ldyBzdWJncm91cCAobncgdnMgbm8gbWlncmF0aW9uIGJhY2tncm91bmQpDQpkZjIkTWlncjIgPC0gTkFfcmVhbF8NCmRmMiRNaWdyMltkZjIkbWlncmF0aW9uX253ID09IDFdIDwtIDFMDQpkZjIkTWlncjJbZGYyJG1pZ3JhdGlvbl9udyA9PSAwXSA8LSAyTA0KZGYyJE1pZ3IyIDwtIGZhY3RvcihkZjIkTWlncjIsIDE6MiwgYyggIk5vbi13ZXN0ZXJuIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiwiTm8gbWlncmF0aW9uIGJhY2tncm91bmQiKSkNCg0KI291dGNvbWUgYW5kIGNvbmpvaW50IGZlYXR1cmVzLCBpbmNsdWRpbmcgb25seSBjb21wb3NpdGlvbiBmZWF0dXJlcyB3ZSBhcmUgaW50ZXJlc3RlZCBpbjsNCiNhbmQgdGhlIHN1Ymdyb3VwaW5nIHZhcmlhYmxlDQoNCiNjb25kaXRpb25hbCBtYXJnaW5hbCBtZWFucyAoY29tcG9zaXRpb24gZGltZW5zaW9uOyBkaXNhZ2dyZWdhdGVkIGJ5IHJlc3BvbmRlbnQgdmFsdWUgZm9yIHRoaXMgZGltZW5zaW9uKQ0KDQojMS4gY2x1Yg0KY21tZWR1YyA8LSBjcmVnZzo6Y2ooZGYyWyFpcy5uYShkZjIkVGVydCksIF0sIGNob2ljZSB+IGVkdWNfY2x1YiwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+VGVydCkNCmNtbWV0aCA8LSBjcmVnZzo6Y2ooZGYyWyFpcy5uYShkZjIkTWlncjIpLCBdLCBjaG9pY2UgfiBtaWdyYW50X2NsdWIsIGlkIH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IH5NaWdyMikNCg0KIzIuIHRlYW0NCnRtbWVkdWMgPC0gY3JlZ2c6OmNqKGRmMlshaXMubmEoZGYyJFRlcnQpLCBdLCBjaG9pY2UgfiBlZHVjX3RlYW0sIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gflRlcnQpDQp0bW1ldGggPC0gY3JlZ2c6OmNqKGRmMlshaXMubmEoZGYyJE1pZ3IyKSwgXSwgY2hvaWNlIH4gbWlncmFudF90ZWFtLCBpZCB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSB+TWlncjIpDQoNCiNyb3diaW5kIHRoZSBkYXRhZnJhbWVzDQojbGVhdmUgb3V0IGxhc3QgY29sdW1uLCByZWZsZWN0aW5nIHRoZSBzdWJncm91cGluZyB2YXJpYWJsZQ0KbW1zIDwtIHJiaW5kKGNtbWVkdWNbLTEyXSx0bW1lZHVjWy0xMl0sDQogICAgICAgICAgICAgY21tZXRoWy0xMl0sdG1tZXRoWy0xMl0pDQoNCiNyZW5hbWUgbGFiZWxzDQojMS4gb2Ygb3V0Y29tZSAoc2V0dGluZykNCm1tcyRPdXRjb21lIDwtIGZhY3RvcihpZmVsc2UoIGdyZXBsKCJjbHViIiwgbW1zJGZlYXR1cmUpLCAiQ2x1YiIsICJUZWFtIC8gdHJhaW5pbmcgZ3JvdXAiKSwgbGV2ZWxzID0gYygiQ2x1YiIsICJUZWFtIC8gdHJhaW5pbmcgZ3JvdXAiKSkNCg0KIzIuIG9mIChkZW1vZ3JhcGhpYyBjb21wb3NpdGlvbikgZmVhdHVyZXMNCm1tcyRGZWF0dXJlIDwtIGZhY3RvcihzdWIoIl8uKyIsICIiLCBtbXMkZmVhdHVyZSksIGxldmVscyA9IGMoIm1pZ3JhbnQiLCAiZWR1YyIpLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiLCAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIpKQ0KDQptbXMkU3ViZ3JvdXAgPC0gbW1zJEJZDQoNCnAgPC0gcGxvdChtbXMsIHZsaW5lPTEvMiwgZmVhdHVyZV9oZWFkZXJzID0gTkEsIHNpemUgPSAyLCBncm91cCA9ICJTdWJncm91cCIpICsNCiAgZmFjZXRfZ3JpZDIoIE91dGNvbWUgfiBGZWF0dXJlLCBzY2FsZXMgPSAiZnJlZSIsIGluZGVwZW5kZW50ID0gInkiLCBzd2l0Y2ggPSAieSIpICsNCiAgZ2VvbV90ZXh0KCBhZXMobGFiZWwgPSBzcHJpbnRmKCIlMC4yZiAoJTAuMmYpIiwgZXN0aW1hdGUsIHN0ZC5lcnJvcikpLCBzaXplID0gMywgY29sb3VyID0gImJsYWNrIiwgdmp1c3QgPSAtMSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZSkgKw0KICBmYWNldHRlZF9wb3Nfc2NhbGVzKA0KICAgIHkgPSBsaXN0KA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIgJiBPdXRjb21lID09ICJDbHViIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoInRocmVlIHF1YXJ0ZXJzICg3NSUpIiwgImhhbGYgKDUwJSkiLCAiYSBxdWFydGVyICgyNSUpIikpLA0KICAgICAgDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBwZW9wbGUgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiAgJiBPdXRjb21lID09ICJUZWFtIC8gdHJhaW5pbmcgZ3JvdXAiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygibWFqb3JpdHkgKDkwJSkiLCAidGhyZWUgcXVhcnRlcnMgKDc1JSkiLCAiaGFsZiAoNTAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiLCAibWlub3JpdHkgKDEwJSkiKSksDQogICAgICANCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiICYgT3V0Y29tZSA9PSAiQ2x1YiIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJhIHF1YXJ0ZXIgKDI1JSkiLCAibWlub3JpdHkgKDEwJSkiLCAiYSBmZXcgKDUlKSIpKSwNCiAgICAgIA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBtaWdyYXRpb24gYmFja2dyb3VuZCIgJiBPdXRjb21lID09ICJUZWFtIC8gdHJhaW5pbmcgZ3JvdXAiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygiaGFsZiAoNTAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiLCAibWlub3JpdHkgKDEwJSkiLCAiYSBmZXcgKDUlKSIsICJub25lICgwJSkiKSkNCiAgICApLA0KICAgICNmcmVlaW5nIHVwIHRoZSB4IHNjYWxlcyBkb2VzIG5vdCB3b3JrIGZvciBzb21lIHJlYXNvbi4uLiBzbyBpIHNldCB0aGVtIG1hbnVhbGx5Og0KICAgIHggPSBsaXN0KA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgcGVvcGxlIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIgfiBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgICAgIGxpbWl0cyA9IGMoLjQyLC41OCksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSwNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIHBlb3BsZSB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC4zOCwuNTgpLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkNCiAgICApDQogICkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICNzdHJpcC50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKCksDQogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikNCg0KI3NwbGl0IGxlZ2VuZCBpbnRvIG11bHRpcGxlIHBhcnRzDQpzcGxpdDEgPC0gbW1zW21tcyRTdWJncm91cCAlaW4lIGMoIk5vbi13ZXN0ZXJuIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiwgIk5vIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiksIF0NCnNwbGl0MiA8LSBtbXNbbW1zJFN1Ymdyb3VwICVpbiUgYygiV2l0aCBjb2xsZWdlIGRlZ3JlZSIsICJXaXRob3V0IGNvbGxlZ2UgZGVncmVlIiksIF0NCg0KI3JldmVyc2Ugb3JkZXIgZmFjdG9yLi4uLiBidWcgaW4gZ2dwbG90MiBtYWtlcyB0aGUgb3JkZXIgb2YgdGhlIHN1Ymdyb3VwcyBpbiB0aGUgcGxvdCBhbmQgdGhlIGxlZ2VuZCByZXZlcnNlZA0Kc3BsaXQxJFN1Ymdyb3VwIDwtIGZhY3RvcihzcGxpdDEkU3ViZ3JvdXAsIGxldmVscyA9IHJldihsZXZlbHMoc3BsaXQxJFN1Ymdyb3VwKSkpDQpzcGxpdDIkU3ViZ3JvdXAgPC0gZmFjdG9yKHNwbGl0MiRTdWJncm91cCwgbGV2ZWxzID0gcmV2KGxldmVscyhzcGxpdDIkU3ViZ3JvdXApKSkNCg0KI3Bsb3QgbGVnZW5kcw0Kc3BsaXQxcCA8LSBnZ3Bsb3Qoc3BsaXQxLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gbGV2ZWwsIGNvbG9yPVN1Ymdyb3VwKSkgKyBnZW9tX3BvaW50KCkgKyBsYWJzKGNvbG9yID0gIlN1Ymdyb3VwczoiKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoNCwzKV0pIA0Kc3BsaXQycCA8LSBnZ3Bsb3Qoc3BsaXQyLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gbGV2ZWwsIGNvbG9yPVN1Ymdyb3VwKSkgKyBnZW9tX3BvaW50KCkgKyBsYWJzKGNvbG9yID0gIlN1Ymdyb3VwczoiKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMiwxKV0pDQoNCiNnZXQgbGVnZW5kcw0KbGVnMSA8LSBnZXRfbGVnZW5kKHNwbGl0MXApDQpsZWcyIDwtIGdldF9sZWdlbmQoc3BsaXQycCkNCg0KI2NvbWJpbmUgbGVnZW5kcw0KbGVnMTIgPC0gcGxvdF9ncmlkKGxlZzEsbGVnMiwgbnJvdz0xLCBhbGlnbj0iaCIpDQoNCiNjcmVhdGUgYSBibGFuayBwbG90IGZvciBsZWdlbmQgYWxpZ25tZW50DQpibGFua19wIDwtIHBsb3Rfc3BhY2VyKCkNCg0KI2NvbWJpbmUgYWxsIGluIG9uZQ0KcCA8LSBwbG90X2dyaWQocCwgbGVnMTIsIGFsaWduID0gImgiLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYyg5LDEpKQ0KDQpwcmludChwKQ0KI2dnc2F2ZSgiLi9maWd1cmVzL2NtbXNfdHJpYWwucG5nIiwgcCwgd2lkdGg9OSkgDQoNCmBgYA0KDQojIyMgY3VycmVudGx5IChub3QpIGludm9sdmVkIGluIGEgc3BvcnRzIGNsdWINCg0KY2hlY2sgd2hldGhlciBjaG9pY2UgaG9tb3BoaWx5IGRlcGVuZHMgb24gd2hldGhlciBwZW9wbGUgYXJlIGN1cnJlbnRseSBpbnZvbHZlZCBpbiBhIHNwb3J0cyBjbHViLg0KDQpgYGB7ciwgY21tc19zcG9ydF9pbnYsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMiwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnfQ0KI2FkZGl0aW9uYWwgZGlzYWdncmVnYXRpb24gYnkgd2hldGhlciBwZW9wbGUgYXJlIGN1cnJlbnRseSBpbnZvbHZlZCBpbiBzcG9ydHMgY2x1Yg0KZGYyJGludl9zcG9ydGNsdWJbaXMubmEoZGYyJGludl9zcG9ydGNsdWIpXSA8LSAwICN0aG9zZSB0aGF0IGRvIG5vdCBkbyBzcG9ydHMsIG5hdHVyYWxseSBhcmUgbm8gbWVtYmVyIG9mIGEgc3BvcnRzIGNsdWIuLi4NCg0KZGYyJFRlcnQgPC0gTkFfcmVhbF8NCmRmMiRUZXJ0W2RmMiR0ZXJ0X2VkdWMgPT0gMV0gPC0gMUwNCmRmMiRUZXJ0W2RmMiR0ZXJ0X2VkdWMgPT0gMF0gPC0gMkwNCmRmMiRUZXJ0IDwtIGZhY3RvcihkZjIkVGVydCwgMToyLCBjKCJDb2xsZWdlIGRlZ3JlZSIsICJObyBjb2xsZWdlIGRlZ3JlZSIpKQ0KDQpkZjIkTWlnciA8LSBOQV9yZWFsXw0KZGYyJE1pZ3JbZGYyJG1pZ3JhdGlvbiA9PSAxXSA8LSAxTA0KZGYyJE1pZ3JbZGYyJG1pZ3JhdGlvbiA9PSAwXSA8LSAyTA0KZGYyJE1pZ3IgPC0gZmFjdG9yKGRmMiRNaWdyLCAxOjIsIGMoIk1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiwgICJEdXRjaCBiYWNrZ3JvdW5kIikpDQoNCiNjbW1zLCBpbmNsdWRpbmcgb25seSBjb21wb3NpdGlvbiBtZWFzdXJlIG9mIGludGVyZXN0LCB0aGUgKGRlbW9ncmFwaGljKSBzdWJncm91cGluZyB2YXJpYWJsZSwgYW5kIGZ1cnRoZXIgdGhlIGN1cnJlbnQgaW52b2x2ZW1lbnQNCg0KIzEuY2x1Yg0KY21tZWR1Y2N1ciA8LSBjcmVnZzo6Y2ooZGYyWyFpcy5uYShkZjIkVGVydCksIF0sIGNob2ljZSB+IGVkdWNfY2x1YiwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSBpbnZfc3BvcnRjbHViIH4gVGVydCApDQpjbW1ldGhjdXIgPC0gY3JlZ2c6OmNqKGRmMlshaXMubmEoZGYyJFRlcnQpLCBdLCBjaG9pY2UgfiBtaWdyYW50X2NsdWIsIGlkID0gfmlkLCBlc3RpbWF0ZSA9ICJtbSIsIGJ5ID0gaW52X3Nwb3J0Y2x1YiB+IE1pZ3IgKQ0KDQojMi50ZWFtDQp0bW1lZHVjY3VyIDwtIGNyZWdnOjpjaihkZjJbIWlzLm5hKGRmMiRUZXJ0KSwgXSwgY2hvaWNlIH4gZWR1Y190ZWFtLCBpZCA9IH5pZCwgZXN0aW1hdGUgPSAibW0iLCBieSA9IGludl9zcG9ydGNsdWIgfiBUZXJ0ICkNCnRtbWV0aGN1ciA8LSBjcmVnZzo6Y2ooZGYyWyFpcy5uYShkZjIkVGVydCksIF0sIGNob2ljZSB+IG1pZ3JhbnRfdGVhbSwgaWQgPSB+aWQsIGVzdGltYXRlID0gIm1tIiwgYnkgPSBpbnZfc3BvcnRjbHViIH4gTWlnciApDQoNCmNtbWVkdWNjdXIkU3ViZ3JvdXAgPC0gaWZlbHNlKGdyZXBsKCJObyBjb2xsZWdlIGRlZ3JlZSIsIGNtbWVkdWNjdXIkQlkpLCAiTm8gY29sbGVnZSBkZWdyZWUiLCAiQ29sbGVnZSBkZWdyZWUiKQ0KY21tZWR1Y2N1ciRDdXJyZW50IDwtIGlmZWxzZShncmVwbCgiMCIsIGNtbWVkdWNjdXIkQlkpLCAiTm8gbWVtYmVyIG9mIHNwb3J0cyBjbHViIiwgIk1lbWJlciBvZiBzcG9ydHMgY2x1YiIpDQp0bW1lZHVjY3VyJFN1Ymdyb3VwIDwtIGlmZWxzZShncmVwbCgiTm8gY29sbGVnZSBkZWdyZWUiLCB0bW1lZHVjY3VyJEJZKSwgIk5vIGNvbGxlZ2UgZGVncmVlIiwgIkNvbGxlZ2UgZGVncmVlIikNCnRtbWVkdWNjdXIkQ3VycmVudCA8LSBpZmVsc2UoZ3JlcGwoIjAiLCB0bW1lZHVjY3VyJEJZKSwgIk5vIG1lbWJlciBvZiBzcG9ydHMgY2x1YiIsICJNZW1iZXIgb2Ygc3BvcnRzIGNsdWIiKQ0KDQpjbW1ldGhjdXIkU3ViZ3JvdXAgPC0gaWZlbHNlKGdyZXBsKCJNaWdyYXRpb24iLCBjbW1ldGhjdXIkQlkpLCAiTWlncmF0aW9uIGJhY2tncm91bmQiLCAiRHV0Y2ggYmFja2dyb3VuZCIpDQpjbW1ldGhjdXIkQ3VycmVudCA8LSBpZmVsc2UoZ3JlcGwoIjAiLCBjbW1ldGhjdXIkQlkpLCAiTm8gbWVtYmVyIG9mIHNwb3J0cyBjbHViIiwgIk1lbWJlciBvZiBzcG9ydHMgY2x1YiIpDQp0bW1ldGhjdXIkU3ViZ3JvdXAgPC0gaWZlbHNlKGdyZXBsKCJNaWdyYXRpb24iLCB0bW1ldGhjdXIkQlkpLCAiTWlncmF0aW9uIGJhY2tncm91bmQiLCAiRHV0Y2ggYmFja2dyb3VuZCIpDQp0bW1ldGhjdXIkQ3VycmVudCA8LSBpZmVsc2UoZ3JlcGwoIjAiLCB0bW1ldGhjdXIkQlkpLCAiTm8gbWVtYmVyIG9mIHNwb3J0cyBjbHViIiwgIk1lbWJlciBvZiBzcG9ydHMgY2x1YiIpDQoNCiNjb21iaW5lDQpjbW1zIDwtIHJiaW5kKGNtbWVkdWNjdXJbLC0xMl0sIHRtbWVkdWNjdXJbLC0xMl0sIGNtbWV0aGN1clssLTEyXSwgdG1tZXRoY3VyWywgLTEyXSkNCg0KI3JlbmFtZSBsYWJlbHMNCiNvdXRjb21lIChzZXR0aW5nKQ0KY21tcyRPdXRjb21lIDwtIGZhY3RvcihpZmVsc2UoIGdyZXBsKCJjbHViIiwgY21tcyRmZWF0dXJlKSwgIkNsdWIiLCAiVGVhbSAvIHRyYWluaW5nIGdyb3VwIikpDQoNCiNkZW1vZ3JhcGhpYyBmZWF0dXJlcw0KY21tcyRGZWF0dXJlIDwtIGZhY3RvcihzdWIoIl8uKiIsICIiLCBjbW1zJGZlYXR1cmUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImVkdWMiLCAibWlncmFudCIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiU2hhcmUgb2YgbWVtYmVycyB3aXRoIGEgY29sbGVnZSBkZWdyZWUiLCAiU2hhcmUgb2YgbWVtYmVycyB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiKSkNCg0KcGxvdGVkdWMgPC0gcGxvdChjbW1zW2NtbXMkRmVhdHVyZSA9PSAiU2hhcmUgb2YgbWVtYmVycyB3aXRoIGEgY29sbGVnZSBkZWdyZWUiLF0sDQogICAgIHZsaW5lID0gMS8yLCBmZWF0dXJlX2hlYWRlcnMgPSBOQSwgc2l6ZSA9IDIsIGdyb3VwID0gIkN1cnJlbnQiKSArDQogICBnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBmYWNldF9uZXN0ZWQoIE91dGNvbWUgKyBTdWJncm91cCB+IEZlYXR1cmUsIHNjYWxlcyA9ICJmcmVlX3kiLCBpbmRlcGVuZGVudCA9ICJ5Iiwgc3dpdGNoID0gInkiKSArDQogICNnZW9tX3RleHQoIGFlcyhsYWJlbCA9IHNwcmludGYoIiUwLjJmICglMC4yZikiLCBlc3RpbWF0ZSwgc3RkLmVycm9yKSksIHNpemUgPSAzLCBjb2xvdXIgPSAiYmxhY2siLCB2anVzdCA9IC0xLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMSwyKV0pICsNCiAgICBmYWNldHRlZF9wb3Nfc2NhbGVzKA0KICAgICAgICAgICB5ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIG1lbWJlcnMgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiAmIE91dGNvbWUgPT0gIkNsdWIiIH4gc2NhbGVfeV9kaXNjcmV0ZSgNCiAgICAgICAgbGFiZWxzID0gYygidGhyZWUgcXVhcnRlcnMgKDc1JSkiLCAiaGFsZiAoNTAlKSIsICJhIHF1YXJ0ZXIgKDI1JSkiKSksDQogICAgICANCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIG1lbWJlcnMgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiAmIE91dGNvbWUgPT0gIlRlYW0gLyB0cmFpbmluZyBncm91cCIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJtYWpvcml0eSAoOTAlKSIsICJ0aHJlZSBxdWFydGVycyAoNzUlKSIsICJoYWxmICg1MCUpIiwgImEgcXVhcnRlciAoMjUlKSIsICJtaW5vcml0eSAoMTAlKSIpKQ0KICAgICAgKSwNCiAgICAgICAgICB4ID0gbGlzdCgNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIG1lbWJlcnMgd2l0aCBhIGNvbGxlZ2UgZGVncmVlIiB+IHNjYWxlX3hfY29udGludW91cygNCiAgICAgICAgbGltaXRzID0gYyguNDAsLjYwKSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpLA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgbWVtYmVycyB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiIH4gc2NhbGVfeF9jb250aW51b3VzKA0KICAgICAgICBsaW1pdHMgPSBjKC40MCwuNjApLCBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkNCiAgICApDQogICAgICApKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICNzdHJpcC50ZXh0LnggPSBlbGVtZW50X21hcmtkb3duKCksDQogICAgICAgIHN0cmlwLnBsYWNlbWVudCA9ICJvdXRzaWRlIikNCg0KcGxvdGV0aCA8LSBwbG90KGNtbXNbY21tcyRGZWF0dXJlID09ICJTaGFyZSBvZiBtZW1iZXJzIHdpdGggYSBtaWdyYXRpb24gYmFja2dyb3VuZCIsXSwNCiAgICAgdmxpbmUgPSAxLzIsIGZlYXR1cmVfaGVhZGVycyA9IE5BLCBzaXplID0gMiwgZ3JvdXAgPSAiQ3VycmVudCIpICsNCiAgIGdlb21fdGV4dCggYWVzKGxhYmVsID0gc3ByaW50ZigiJTAuMmYgKCUwLjJmKSIsIGVzdGltYXRlLCBzdGQuZXJyb3IpKSwgc2l6ZSA9IDMsIGNvbG91ciA9ICJibGFjayIsIHZqdXN0ID0gLTEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArDQogIGZhY2V0X25lc3RlZCggT3V0Y29tZSArIFN1Ymdyb3VwIH4gRmVhdHVyZSwgc2NhbGVzID0gImZyZWVfeSIsIGluZGVwZW5kZW50ID0gInkiLCBzd2l0Y2ggPSAieSIpICsNCiAgI2dlb21fdGV4dCggYWVzKGxhYmVsID0gc3ByaW50ZigiJTAuMmYgKCUwLjJmKSIsIGVzdGltYXRlLCBzdGQuZXJyb3IpKSwgc2l6ZSA9IDMsIGNvbG91ciA9ICJibGFjayIsIHZqdXN0ID0gLTEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjYlBhbGV0dGVbYygxLDIpXSkgKw0KICAgIGZhY2V0dGVkX3Bvc19zY2FsZXMoDQogICAgICAgICAgIHkgPSBsaXN0KA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgbWVtYmVycyB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiICYgT3V0Y29tZSA9PSAiQ2x1YiIgfiBzY2FsZV95X2Rpc2NyZXRlKA0KICAgICAgICBsYWJlbHMgPSBjKCJhIHF1YXJ0ZXIgKDI1JSkiLCAibWlub3JpdHkgKDEwJSkiLCAiYSBmZXcgKDUlKSIpKSwNCiAgICAgIA0KICAgICAgRmVhdHVyZSA9PSAiU2hhcmUgb2YgbWVtYmVycyB3aXRoIGEgbWlncmF0aW9uIGJhY2tncm91bmQiICYgT3V0Y29tZSA9PSAiVGVhbSAvIHRyYWluaW5nIGdyb3VwIiB+IHNjYWxlX3lfZGlzY3JldGUoDQogICAgICAgIGxhYmVscyA9IGMoImhhbGYgKDUwJSkiLCAiYSBxdWFydGVyICgyNSUpIiwgIm1pbm9yaXR5ICgxMCUpIiwgImEgZmV3ICg1JSkiLCAibm9uZSAoMCUpIikpDQogICAgICApLA0KICAgICAgDQogICAgICAgeCA9IGxpc3QoDQogICAgICBGZWF0dXJlID09ICJTaGFyZSBvZiBtZW1iZXJzIHdpdGggYSBjb2xsZWdlIGRlZ3JlZSIgfiBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgICAgIGxpbWl0cyA9IGMoLjMwLC43MCksIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSwNCiAgICAgIEZlYXR1cmUgPT0gIlNoYXJlIG9mIG1lbWJlcnMgd2l0aCBhIG1pZ3JhdGlvbiBiYWNrZ3JvdW5kIiB+IHNjYWxlX3hfY29udGludW91cygNCiAgICAgICAgbGltaXRzID0gYyguMzAsLjcwKSwgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpDQogICAgKQ0KICAgICAgKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgI3N0cmlwLnRleHQueCA9IGVsZW1lbnRfbWFya2Rvd24oKSwNCiAgICAgICAgc3RyaXAucGxhY2VtZW50ID0gIm91dHNpZGUiKQ0KDQpjb21iaW5lZF9wbG90IDwtIHBsb3RfZ3JpZChwbG90ZXRoLCBwbG90ZWR1YywgYWxpZ24gPSAiaCIsIG5yb3c9MSkNCg0KI2xlZ2VuZA0Kc3BsaXQxIDwtICBjbW1zWyBncmVwbCgiYmFja2dyb3VuZCIsIGNtbXMkQlkpLCBdDQoNCiNyZXZlcnNlIG9yZGVyIGZhY3Rvci4uLi4gYnVnIGluIGdncGxvdDIgbWFrZXMgdGhlIG9yZGVyIG9mIHRoZSBzdWJncm91cHMgaW4gdGhlIHBsb3QgYW5kIHRoZSBsZWdlbmQgcmV2ZXJzZWQNCnNwbGl0MSRDdXJyZW50IDwtIGZhY3RvcihzcGxpdDEkQ3VycmVudCwgbGV2ZWxzID0gcmV2KGxldmVscyhhcy5mYWN0b3Ioc3BsaXQxJEN1cnJlbnQpKSkpDQoNCiNwbG90IGxlZ2VuZA0Kc3BsaXQxcCA8LSBnZ3Bsb3Qoc3BsaXQxLCBhZXMoeCA9IGVzdGltYXRlLCB5ID0gbGV2ZWwsIGNvbG9yPUN1cnJlbnQpKSArIGdlb21fcG9pbnQoKSArIGxhYnMoY29sb3IgPSAiQ3VycmVudCBpbnZvbHZlbWVudDoiKSArIHRoZW1lX2J3KCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY2JQYWxldHRlW2MoMiwxKV0pICsgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9tYXJrZG93bigpKQ0KDQojZ2V0IGxlZ2VuZHMNCmxlZzEgPC0gZ2V0X2xlZ2VuZChzcGxpdDFwKQ0KDQpwNiA8LSBwbG90X2dyaWQoY29tYmluZWRfcGxvdCxsZWcxLCBucm93PTIsIHJlbF9oZWlnaHRzID0gYygxMSwxKSkNCnBsb3QocDYpDQojZ2dzYXZlKCIuL2ZpZ3VyZXMvY21tc190cmlhbF9jdXJyZW50Mi5wbmciLCBwNiwgd2lkdGg9MTIsIGhlaWdodD0xMikgDQpgYGAgDQoNCg0KLS0tLQ0KDQojIFJlZmVyZW5jZXMNCg==


Copyright © 2025 Rob Franken / Kasimir Dederichs / Dingeman Wiertz / Jochem Tolsma