# Load libraries
library(tidyverse)
library(crackdownsphilanthropy)
library(magrittr)
library(rstan)
library(rstanarm)
library(broom)
library(broom.mixed)
library(glue)
library(grid)
library(gridExtra)
library(Gmisc)  # For the CONSORT diagram
library(pander)
library(scales)
library(ipumsr)
library(huxtable)
library(here)

source(here("analysis", "options.R"))

# Print correct huxtable table depending on the type of output.
#
# Technically this isn't completely necessary, since huxtable can output a
# markdown table, which is ostensibly universal for all output types. However,
# markdown tables are inherently limited in how fancy they can be (e.g. they
# don't support column spans), so I instead let the regression table use
# huxtable's fancy formatting for html and PDF and markdown everywhere else.
if (isTRUE(getOption('knitr.in.progress'))) {
  file_format <- rmarkdown::all_output_formats(knitr::current_input())
} else {
  file_format <- ""
}

print_hux <- function(x) {
  if ("html_document" %in% file_format) {
    print_html(x)
  } else if ("pdf_document" %in% file_format) {
    print_latex(x)
  } else if ("word_document" %in% file_format) {
    print_md(x)
  } else {
    print(x)
  }
}

# Load data
results <- readRDS(here("data", "derived_data", "results_clean.rds"))

CONSORT flow

consort <- readRDS(here("data", "derived_data", "completion_summary.rds")) %>% 
  pivot_wider(names_from = reason, values_from = n) %>% 
  mutate(group = 1:n(),
         assigned = Approved + `Failed first attention check`,
         issue = str_replace_all(issue, "assistance", "assist.")) %>% 
  mutate(assigned_label = glue("Allocated to Group {group}\n{crackdown}\n{issue}\n{funding} funding\n\nN = {assigned}"),
         completed_label = glue("Completed\nN = {Approved}\n\n{`Failed first attention check`} failed\nattention check"))

assessed_eligibility_n <- sum(consort$Approved, consort$`Failed first attention check`, 
                              consort$`Took survey outisde of MTurk`)
ineligible_n <- sum(consort$`Took survey outisde of MTurk`)
randomized_n <- sum(consort$Approved, consort$`Failed first attention check`)


# https://aghaynes.wordpress.com/2018/05/09/flow-charts-in-r/
# set some parameters to use repeatedly
width <- 0.1
xs <- seq(0.1, 0.9, length.out = 8)
allocated_y <- 0.375
completed_y <- 0.125

box_gp_grey <- gpar(fill = ngo_cols("light grey"))
box_gp_blue_dk <- gpar(fill = ngo_cols("blue"), alpha = 0.75)
box_gp_blue_lt <- gpar(fill = ngo_cols("blue"), alpha = 0.35)
box_gp_green <- gpar(fill = ngo_cols("green"), alpha = 0.65)
box_gp_yellow <- gpar(fill = ngo_cols("yellow"))
box_gp_orange <- gpar(fill = ngo_cols("orange"), alpha = 0.65)

txt_gp <- gpar(fontfamily = "Roboto Condensed", 
               fontface = "plain", fontsize = 8)

# Create boxes
total <- boxGrob(glue("Assessed for eligibility\n N = {assessed_eligibility_n}"), 
                 x = 0.5, y = 0.9, width = 2 * width,
                 box_gp = box_gp_blue_lt, txt_gp = txt_gp)
randomized <- boxGrob(glue("Randomized\n N = {randomized_n}"), 
                      x = 0.5, y = 0.65, width = 2 * width,
                      box_gp = box_gp_blue_dk, txt_gp = txt_gp)
ineligible <- boxGrob(glue("Participants excluded for\ncompleting Qualtrics survey\noutside of MTurk\n N = {ineligible_n}"), 
                      x = xs[7], y = 0.775, #width = 0.25,
                      box_gp = box_gp_yellow, txt_gp = txt_gp)

group1 <- boxGrob(filter(consort, group == 1)$assigned_label,
                  x = xs[1], y = allocated_y, width = width, 
                  box_gp = box_gp_orange, txt_gp = txt_gp)
group2 <- boxGrob(filter(consort, group == 2)$assigned_label,
                  x = xs[2], y = allocated_y, width = width, 
                  box_gp = box_gp_orange, txt_gp = txt_gp)
group3 <- boxGrob(filter(consort, group == 3)$assigned_label,
                  x = xs[3], y = allocated_y, width = width, 
                  box_gp = box_gp_orange, txt_gp = txt_gp)
group4 <- boxGrob(filter(consort, group == 4)$assigned_label,
                  x = xs[4], y = allocated_y, width = width, 
                  box_gp = box_gp_orange, txt_gp = txt_gp)
group5 <- boxGrob(filter(consort, group == 5)$assigned_label,
                  x = xs[5], y = allocated_y, width = width, 
                  box_gp = box_gp_orange, txt_gp = txt_gp)
group6 <- boxGrob(filter(consort, group == 6)$assigned_label,
                  x = xs[6], y = allocated_y, width = width, 
                  box_gp = box_gp_orange, txt_gp = txt_gp)
group7 <- boxGrob(filter(consort, group == 7)$assigned_label,
                  x = xs[7], y = allocated_y, width = width, 
                  box_gp = box_gp_orange, txt_gp = txt_gp)
group8 <- boxGrob(filter(consort, group == 8)$assigned_label,
                  x = xs[8], y = allocated_y, width = width, 
                  box_gp = box_gp_orange, txt_gp = txt_gp)

group1_completed <- boxGrob(filter(consort, group == 1)$completed_label, 
                            x = xs[1], y = completed_y, width = width,
                            box_gp = box_gp_green, txt_gp = txt_gp)
group2_completed <- boxGrob(filter(consort, group == 2)$completed_label, 
                            x = xs[2], y = completed_y, width = width,
                            box_gp = box_gp_green, txt_gp = txt_gp)
group3_completed <- boxGrob(filter(consort, group == 3)$completed_label, 
                            x = xs[3], y = completed_y, width = width,
                            box_gp = box_gp_green, txt_gp = txt_gp)
group4_completed <- boxGrob(filter(consort, group == 4)$completed_label, 
                            x = xs[4], y = completed_y, width = width,
                            box_gp = box_gp_green, txt_gp = txt_gp)
group5_completed <- boxGrob(filter(consort, group == 5)$completed_label, 
                            x = xs[5], y = completed_y, width = width,
                            box_gp = box_gp_green, txt_gp = txt_gp)
group6_completed <- boxGrob(filter(consort, group == 6)$completed_label, 
                            x = xs[6], y = completed_y, width = width,
                            box_gp = box_gp_green, txt_gp = txt_gp)
group7_completed <- boxGrob(filter(consort, group == 7)$completed_label, 
                            x = xs[7], y = completed_y, width = width,
                            box_gp = box_gp_green, txt_gp = txt_gp)
group8_completed <- boxGrob(filter(consort, group == 8)$completed_label, 
                            x = xs[8], y = completed_y, width = width,
                            box_gp = box_gp_green, txt_gp = txt_gp)

total_random_connect <- connectGrob(total, randomized, "v")
total_ineligible_connect <- connectGrob(total, ineligible, "-")

rand_connect1 <- connectGrob(randomized, group1, "N")
rand_connect2 <- connectGrob(randomized, group2, "N")
rand_connect3 <- connectGrob(randomized, group3, "N")
rand_connect4 <- connectGrob(randomized, group4, "N")
rand_connect5 <- connectGrob(randomized, group5, "N")
rand_connect6 <- connectGrob(randomized, group6, "N")
rand_connect7 <- connectGrob(randomized, group7, "N")
rand_connect8 <- connectGrob(randomized, group8, "N")

complete_connect1 <- connectGrob(group1, group1_completed, "N")
complete_connect2 <- connectGrob(group2, group2_completed, "N")
complete_connect3 <- connectGrob(group3, group3_completed, "N")
complete_connect4 <- connectGrob(group4, group4_completed, "N")
complete_connect5 <- connectGrob(group5, group5_completed, "N")
complete_connect6 <- connectGrob(group6, group6_completed, "N")
complete_connect7 <- connectGrob(group7, group7_completed, "N")
complete_connect8 <- connectGrob(group8, group8_completed, "N")

full_chart <- list(total, randomized, ineligible, total_random_connect, total_ineligible_connect,
                   group1, group2, group3, group4, group5, group6, group7, group8,
                   rand_connect1, rand_connect2, rand_connect3, rand_connect4, 
                   rand_connect5, rand_connect6, rand_connect7, rand_connect8,
                   group1_completed, group2_completed, group3_completed, group4_completed, 
                   group5_completed, group6_completed, group7_completed, group8_completed,
                   complete_connect1, complete_connect2, complete_connect3, complete_connect4, 
                   complete_connect5, complete_connect6, complete_connect7, complete_connect8) 
# Ordinarily, you can use grid.grab() to save the output of a grid figure into
# an object and then use that in ggsave(). However, when knitting, this creates
# a duplicate plot, which is frustrating. So instead, we use walk() to reprint
# all the grobs within specific pdf and png devices
#
# See https://stackoverflow.com/a/17509770/120898 for a similar issue

# Save as PDF
cairo_pdf(filename = here("analysis", "output", "figures", "consort.pdf"),
          width = 10, height = 6)
grid.newpage()
walk(full_chart, ~ print(.))
invisible(dev.off())

# Save as PNG
png(filename = here("analysis", "output", "figures", "consort.png"), 
    width = 10, height = 6, units = "in",
    bg = "white", res = 300, type = "cairo")
grid.newpage()
walk(full_chart, ~ print(.))
invisible(dev.off())

# Show in knitted document
grid.newpage()
walk(full_chart, ~ print(.))

Characteristics of experiment samples

We compare our sample with demographic characteristics of the general population. Since there is no nationally representative sample for each of our demographic variables, we use two waves of the US Census’s Current Population Survey (CPS), with data from the Minnesota Population Center’s Integrated Public Use Microdata Series (IPUMS).

For general demographic information, we use data from the 2017 Annual Social and Economic Supplement (ASEC) for the CPS. From 2002–2015, the CPS included a Volunteer Supplement every September, so we use 2015 data for data on volunteering and donating to charity.

IPUMS requires that you manually generate a data extract through their website, so downloading data from them is not entirely automated or reproducible. We created two extracts (though this could have been combined into one), with the following variables

  • "data/raw_data/ipums-cps/cps_2017.dat.gz": 2017 ASEC, with the following variables selected (in addition to whatever IPUMS preselects by default) (and weighted by ASECWT):
    • AGE
    • SEX
    • EDUC
    • INCTOT
  • "data/raw_data/ipums-cps/cps_09_2015.dat.gz": September 2015 basic monthly CPS (which includes the Volunteer Supplement), with the following variables selected (and weighted by VLSUPPWT):
    • VLSTATUS
    • VLDONATE

We do not show other respondent demographic details because we don’t have good population-level data to compare our sample with. We could theoretically use Pew data for political preferences, but they collect data on party affiliation, while we collected data about respondent positions along a conservative–liberal spectrum, so the two variables aren’t comparable.

cps_2015_ddi_file <- here("data", "raw_data", "ipums-cps", "cps_09_2015.xml")
cps_2015_data_file <- here("data", "raw_data", "ipums-cps", "cps_09_2015.dat.gz")

cps_2015_ddi <- read_ipums_ddi(cps_2015_ddi_file)
cps_2015_data <- read_ipums_micro(cps_2015_ddi_file, data_file = cps_2015_data_file, verbose = FALSE)

cps_2017_ddi_file <- here("data", "raw_data", "ipums-cps", "cps_2017.xml")
cps_2017_data_file <- here("data", "raw_data", "ipums-cps", "cps_2017.dat.gz")

cps_2017_ddi <- read_ipums_ddi(cps_2017_ddi_file)
cps_2017_data <- read_ipums_micro(cps_2017_ddi_file, data_file = cps_2017_data_file, verbose = FALSE)

# Volunteering data from September 2015 only
df_volunteering <- cps_2015_data %>% 
  # Remove values not in the universe
  mutate_at(vars(VLSTATUS, VLDONATE), list(~ifelse(. == 99, NA, .)))

# All other data from annual March 2017 survey
df_demographics <- cps_2017_data %>% 
  # Remove values not in the universe
  mutate(SEX = ifelse(SEX == 9, NA, SEX),
         EDUC = ifelse(EDUC <= 1 | EDUC == 999, NA, EDUC),
         INCTOT = ifelse(INCTOT == 99999999, NA, INCTOT))
global_demographics <- df_demographics %>% 
  summarize(age = weighted.mean(AGE >= 35, ASECWT), 
            female = weighted.mean(SEX == 2, ASECWT),
            college = weighted.mean(EDUC >= 111, ASECWT, na.rm = TRUE),
            income = weighted.mean(INCTOT >= 50000, ASECWT, na.rm = TRUE)) %>% 
  c()

global_vol <- df_volunteering %>% 
  summarize(volunteering = weighted.mean(VLSTATUS == 2, VLSUPPWT, na.rm = TRUE),
            donating = weighted.mean(VLDONATE == 2, VLSUPPWT, na.rm = TRUE)) %>% 
  c()

global_stats <- c(global_vol, global_demographics)
compare_sample_to_pop <- function(sample_value, population_value) {
  mcmc_samples <- pop_prop_stan(
    x = table(sample_value)[1],
    n_total = length(sample_value),
    pop_prop = population_value,
    chains = CHAINS, iter = ITER, warmup = WARMUP, seed = BAYES_SEED)

  tidied <- tidy(mcmc_samples, conf.int = TRUE, conf.level = 0.95, 
                 estimate.method = "median", conf.method = "HPDinterval") %>%
    mutate(in_hpdi = (population_value >= conf.low & population_value <= conf.high))
  
  thetas <- unlist(extract(mcmc_samples, "theta"))
  pop_quantile_in_sample <- ecdf(thetas)(population_value)
  
  in_hpdi <- (population_value >= tidied[1,]$conf.low & 
                population_value <= tidied[1,]$conf.high)
  
  return(list(mcmc_samples = mcmc_samples, tidied = tidied, theta_in_hpdi = in_hpdi,
              pop_quantile_in_sample = pop_quantile_in_sample))
}

calc_sample_pop <- tribble(
  ~Variable, ~sample_value, ~National,
  "Female (%)^a^", results$gender_bin, global_stats$female,
  "Age (% 35+)^a^", results$age_bin, global_stats$age,
  "Income (% $50,000+)^a^", results$income_bin, global_stats$income,
  "Education (% BA+)^a^", results$education_bin, global_stats$college,
  "Donated in past year (%)^b^", results$give_charity_2, global_stats$donating,
  "Volunteered in past year (%)^b^", results$volunteer, global_stats$volunteering
) %>% 
  mutate(Sample = sample_value %>% map_dbl(~ prop.table(table(.))[1]),
         prop_test_bayes = map2(.x = sample_value, .y = National, 
                                .f = ~ compare_sample_to_pop(.x, .y))) 
format_hpdi <- function(post_lower, post_upper, star, digits = 1) {
  glue("({lower}%, {upper}%){star}",
       lower = round(100 * post_lower, digits),
       upper = round(100 * post_upper, digits))
}

tbl_sample_pop <- calc_sample_pop %>% 
  mutate(in_hpdi = prop_test_bayes %>% map_lgl(~ .$theta_in_hpdi),
         not_hpdi_symbol = ifelse(in_hpdi, "", "^†^"),
         diffs_tidy = prop_test_bayes %>% map(~ .$tidied[2,]),
         diffs_median = diffs_tidy %>% map_dbl(~ .$estimate),
         diffs_hpdi_fancy = diffs_tidy %>%
           map2_chr(.x = diffs_tidy, .y = not_hpdi_symbol, 
                    .f = ~ format_hpdi(.x$conf.low, .x$conf.high, .y))) %>% 
  mutate_at(vars(National, Sample, diffs_median), list(percent)) %>% 
  select(Variable, Sample, National, 
         `∆~median~` = diffs_median,
         `95% HPDI` = diffs_hpdi_fancy)

note_row <- tibble(Variable = c("*^a^Annual CPS, March 2017*",
                                "*^b^Monthly CPS, September 2015*",
                                "*^†^National value is outside the sample highest posterior density interval (HPDI)*"))

bind_rows(tbl_sample_pop, note_row) %>% 
  pandoc.table.return(keep.line.breaks = TRUE, style = "multiline", justify = "lcccc", 
                      caption = "Characteristics of experimental sample {#tbl:exp-sample}") %T>% 
  cat(file = here("analysis", "output", "tables", "tbl-exp-sample.md")) %>% 
  cat()
Characteristics of experimental sample {#tbl:exp-sample}
Variable Sample National median 95% HPDI
Female (%)a 54.80% 51.0% 3.7% (-0.7%, 7.7%)
Age (% 35+)a 47.27% 53.9% -6.6% (-10.7%, -2.2%)
Income (% $50,000+)a 50.39% 27.4% 21.7% (17.3%, 26%)
Education (% BA+)a 46.14% 29.9% 16.2% (11.9%, 20.2%)
Donated in past year (%)b 82.49% 48.8% 33.6% (30.3%, 36.8%)
Volunteered in past year (%)b 54.24% 75.1% -20.9% (-25%, -16.7%)
aAnnual CPS, March 2017
bMonthly CPS, September 2015
National value is outside the sample highest posterior density interval (HPDI)

Results using interaction terms

In our preregistration protocol, we said we’d calculate the differences in group means using a regression model with 3-way interaction terms. This was mostly for the sake of simplicity—running one model is easier than running multiple individual tests—but the interpretation is a complicated mess. So instead, we ran individual difference in mean tests for the actual paper. For the sake of transparency, though, here are the results from the fully interacted regression models.

Interpreting interactions in models

Ordinarily, people use ANOVA to analyze 3-way, 2 × 2 × 2 factorial designs, like this. A more flexible (yet identical!) way to do this is to use a regular regression model with interaction terms for each of the conditions, like so (here we use three, since we can use simper models to get averages for the larger umbrella groups, like just crackdowns and crackdown + issue):

  • Model 1:

    \[ y = \beta_0 + \beta_1 \text{Crackdown} \]

  • Model 2:

    \[ \begin{aligned} y =& \beta_0 + \beta_1 \text{Crackdown} + \beta_2 \text{Issue } + \\ & \beta_3 \text{Crackdown} \times \text{Issue} \end{aligned} \]

  • Model 3:

    \[ \begin{aligned} y =& \beta_0 + \beta_1 \text{Crackdown} + \beta_2 \text{Issue} + \beta_3 \text{Funding } + \\ & \beta_4 \text{Crackdown} \times \text{Issue } + \\ & \beta_5 \text{Crackdown} \times \text{Funding } + \\ & \beta_6 \text{Issue} \times \text{Funding } + \\ & \beta_7 \text{Crackdown} \times \text{Issue} \times \text{Funding} \end{aligned} \]

Adding different combinations of the coefficients provides the average values for each combination of factors, which corresponds to the average likelihood and amount donated.

model1 <- "1"
model2 <- "2"
model3 <- "3"

interpretation <- tribble(
  ~Model, ~`Coefficients to add together`,
  model3, "Intercept",
  model3, "Intercept + Funding",
  model2, "Intercept",
  model3, "Intercept + Issue",
  model3, "Intercept + Issue + Funding + (Issue × Funding)",
  model2, "Intercept + Issue",
  model1, "Intercept",
  model3, "Intercept + Crackdown",
  model3, "Intercept + Crackdown + Funding + (Crackdown × Funding)",
  model2, "Intercept + Crackdown",
  model3, "Intercept + Crackdown + Issue + (Crackdown × Issue)",
  model3, "Intercept + Crackdown + Issue + Funding + (Crackdown × Issue) + (Crackdown × Funding) + (Issue × Funding) + (Crackdown × Issue × Funding)",
  model2, "Intercept + Crackdown + Issue + (Crackdown × Issue)",
  model1, "Intercept + Crackdown"
)

conditions_summary <- bind_rows(group_by(results, crackdown, issue, funding) %>% nest(),
                                group_by(results, crackdown, issue) %>% nest(),
                                group_by(results, crackdown) %>% nest(),
                                results %>% nest(data = everything())) %>% 
  arrange(crackdown, issue, funding) %>% 
  select(-data) %>% ungroup() %>% 
  mutate(funding = ifelse(is.na(funding) & !is.na(issue) , "*Total*", as.character(funding)),
         issue = ifelse(is.na(issue) & !is.na(crackdown), "*Total*", as.character(issue)),
         crackdown = ifelse(is.na(crackdown), "*Total*", as.character(crackdown))) %>% 
  group_by(crackdown) %>% 
  mutate(issue = replace(issue, duplicated(issue), NA)) %>% 
  ungroup() %>% 
  mutate(crackdown = replace(crackdown, duplicated(crackdown), NA)) %>% 
  rename(`Crackdown condition` = crackdown, `Issue condition` = issue,
         `Funding condition` = funding)

conditions_summary %>% 
  slice(-n()) %>% 
  bind_cols(interpretation) %>% 
  pandoc.table()
Crackdown condition Issue condition Funding condition Model Coefficients to add together
No crackdown Human rights Government 3 Intercept
Private 3 Intercept + Funding
Total 2 Intercept
Humanitarian assistance Government 3 Intercept + Issue
Private 3 Intercept + Issue + Funding + (Issue × Funding)
Total 2 Intercept + Issue
Total 1 Intercept
Crackdown Human rights Government 3 Intercept + Crackdown
Private 3 Intercept + Crackdown + Funding + (Crackdown × Funding)
Total 2 Intercept + Crackdown
Humanitarian assistance Government 3 Intercept + Crackdown + Issue + (Crackdown × Issue)
Private 3 Intercept + Crackdown + Issue + Funding + (Crackdown × Issue) + (Crackdown × Funding) + (Issue × Funding) + (Crackdown × Issue × Funding)
Total 2 Intercept + Crackdown + Issue + (Crackdown × Issue)
Total 1 Intercept + Crackdown

Amount donated

# Basic interaction models
m_amount_c <- stan_glm(amount_donate ~ crackdown,
                       data = results, family = gaussian(),
                       prior = cauchy(location = 0, scale = 2.5),
                       prior_intercept = cauchy(location = 0, scale = 10),
                       chains = CHAINS, iter = ITER, warmup = WARMUP, seed = BAYES_SEED)

m_amount_ci <- update(m_amount_c, . ~ . + issue + crackdown * issue)
m_amount_cif <- update(m_amount_c, . ~ . + 
                         issue + funding + crackdown * issue + crackdown * funding + 
                         issue * funding + crackdown * issue * funding)
# Models with just issue and just funding
m_amount_i <- update(m_amount_c, . ~ issue)
m_amount_f <- update(m_amount_c, . ~ funding)
# Get subset of coefficients
coefs_to_include <- list(m_amount_c, m_amount_ci, m_amount_cif) %>% 
  map(~ tidy(.)) %>% bind_rows() %>% distinct(term) %>% pull(term)

huxreg(m_amount_c, m_amount_ci, m_amount_cif, 
       coefs = coefs_to_include,
       statistics = c(Observations = "nobs",
                       `Posterior sample size` = "pss",
                       Sigma = "sigma"),
       stars = NULL) %T>% 
  print_hux() %>% 
  to_md(max_width = 100) %>% 
  cat(file = here("analysis", "output", "tables", "tbl-interactions-amount.md"))
(1) (2) (3)
(Intercept) 21.045  20.978  20.698 
(1.490) (1.707) (1.977)
crackdownCrackdown 2.502  2.053  1.801 
(2.061) (2.019) (2.251)
issueHumanitarian assistance       -0.241  0.177 
      (1.692) (1.844)
crackdownCrackdown:issueHumanitarian assistance       1.126  2.717 
      (2.209) (3.231)
fundingPrivate             0.377 
            (1.858)
crackdownCrackdown:fundingPrivate             1.078 
            (2.436)
issueHumanitarian assistance:fundingPrivate             -0.645 
            (2.242)
crackdownCrackdown:issueHumanitarian assistance:fundingPrivate             -4.638 
            (5.222)
Observations 531      531      531     
Posterior sample size 8000.000  8000.000  8000.000 
Sigma 25.653  25.640  25.589 

Likelihood of donation

# Basic interaction models
# Weakly informative student t priors, since these coefficients are log-odds
# See https://github.com/stan-dev/stan/wiki/Prior-Choice-Recommendations#prior-for-the-regression-coefficients-in-logistic-regression-non-sparse-case and https://arxiv.org/abs/1507.07170
m_likely_c <- stan_glm(donate_likely_bin ~ crackdown,
                       data = results, family = binomial(link = "logit"),
                       prior = student_t(3, 0, 2.5),
                       prior_intercept = student_t(3, 0, 10),
                       chains = CHAINS, iter = ITER, warmup = WARMUP, seed = BAYES_SEED)

m_likely_ci <- update(m_likely_c, . ~ . + issue + crackdown * issue)

m_likely_cif <- update(m_likely_c, . ~ . + 
                         issue + funding + crackdown * issue + crackdown * funding + 
                         issue * funding + crackdown * issue * funding)

# Models with just issue and just funding
m_likely_i <- update(m_likely_c, . ~ issue)
m_likely_f <- update(m_likely_c, . ~ funding)
# Get subset of coefficients
coefs_to_include <- list(m_likely_c, m_likely_ci, m_likely_cif) %>% 
  map(~ tidy(.)) %>% bind_rows() %>% distinct(term) %>% pull(term)

huxreg(m_likely_c, m_likely_ci, m_likely_cif, 
       coefs = coefs_to_include,
       statistics = c(Observations = "nobs",
                       `Posterior sample size` = "pss",
                       Sigma = "sigma"),
       stars = NULL) %T>% 
  print_hux() %>% 
  to_md(max_width = 100) %>% 
  cat(file = here("analysis", "output", "tables", "tbl-interactions-likelihood.md"))
(1) (2) (3)
(Intercept) -0.298  -0.275  -0.175 
(0.123) (0.173) (0.235)
crackdownCrackdown 0.161  0.028  -0.666 
(0.169) (0.247) (0.346)
issueHumanitarian assistance       -0.044  -0.040 
      (0.242) (0.319)
crackdownCrackdown:issueHumanitarian assistance       0.261  0.910 
      (0.336) (0.483)
fundingPrivate             -0.245 
            (0.336)
crackdownCrackdown:fundingPrivate             1.389 
            (0.471)
issueHumanitarian assistance:fundingPrivate             0.025 
            (0.473)
crackdownCrackdown:issueHumanitarian assistance:fundingPrivate             -1.300 
            (0.657)
Observations 531      531      531     
Posterior sample size 8000.000  8000.000  8000.000 
Sigma 1.000  1.000  1.000 

Collapsing likelihood variable

To simplify our analysis, we collapse our likelihood scale from a 1-5 Likert scale to a binary variable:

collapsed_likelihood <- tribble(
  ~`Original answer`, ~`Collapsed answer`,
  "Extremely likely", "Likely",
  "Somewhat likely", "Likely",
  "Neither likely nor unlikely", "Unlikely",
  "Somewhat unlikely", "Unlikely",
  "Extremely unlikely", "Unlikely"
)
    
collapsed_likelihood %>% 
  pandoc.table.return(justify = "ll") %T>%
  cat(file = here("analysis", "output", "tables", "tbl-collapsed-likelihood.md")) %>% 
  cat()
Original answer Collapsed answer
Extremely likely Likely
Somewhat likely Likely
Neither likely nor unlikely Unlikely
Somewhat unlikely Unlikely
Extremely unlikely Unlikely

To check that the results are internally consistent when collapsed, we ran an ordered probit model (using Stan) to see if the cutpoints follow the distribution of answers, and they do. “Somewhat likely” and above has a cutpoint of > 0.18, meaning that the likelihood is positive on average for both “Somewhat likely” and “Extremely likely.”

collapsed_oprobit <- stan_polr(donate_likely ~ crackdown, data = results,
                               prior = R2(0.25, what = "mean"), prior_counts = dirichlet(1),
                               method = "probit",
                               chains = CHAINS, iter = ITER, warmup = WARMUP, seed = BAYES_SEED)
huxreg(collapsed_oprobit,
       coefs = c("Crackdown" = "crackdownCrackdown",
                 "Cutpoint: Extremely unlikely|Somewhat unlikely" = 
                   "Extremely unlikely|Somewhat unlikely",
                 "Cutpoint: Somewhat unlikely|Neither likely nor unlikely" = 
                   "Somewhat unlikely|Neither likely nor unlikely",
                 "Cutpoint: Neither likely nor unlikely|Somewhat likely" = 
                   "Neither likely nor unlikely|Somewhat likely",
                 "Cutpoint: Somewhat likely|Extremely likely" = 
                   "Somewhat likely|Extremely likely"),
       statistics = c(Observations = "nobs",
                       `Posterior sample size` = "pss"),
       stars = NULL) %>%
  set_align(everywhere, 1, "left") %>% 
  set_align(everywhere, 2, "center") %>% 
  set_position("left") %>% 
  set_caption("Ordered probit regression with donation likelihood as outcome variable {#tbl:probit-likelihood}") %T>% 
  print_hux() %>% 
  to_md(max_width = 140) %>% 
  cat(file = here("analysis", "output", "tables", "tbl-probit-likelihood.md"))
Ordered probit regression with donation likelihood as outcome variable {#tbl:probit-likelihood}
(1)
Crackdown 0.089
(0.091)
Cutpoint: Extremely unlikely|Somewhat unlikely -1.314
(0.091)
Cutpoint: Somewhat unlikely|Neither likely nor unlikely -0.496
(0.075)
Cutpoint: Neither likely nor unlikely|Somewhat likely 0.181
(0.072)
Cutpoint: Somewhat likely|Extremely likely 1.416
(0.093)
Observations 531
Posterior sample size 8000.000

Miscellaneous survey details

Average time to complete survey

time_summary <- results %>% 
  summarize_at(vars(duration), list(Minimum = min, Maximum = max, Mean = mean, 
                                    `Standard deviation` = sd, Median = median)) %>% 
  pivot_longer(everything(), names_to = "Statistic", values_to = "value") %>% 
  mutate(Minutes = fmt_seconds(value)) %>% 
  select(-value) 

pandoc.table(time_summary)
Statistic Minutes
Minimum 00:49
Maximum 17:34
Mean 03:23
Standard deviation 02:05
Median 02:48
summary_stats <- tableGrob(time_summary, rows = NULL, theme = theme_ngos_table) %>% 
  gtable::gtable_add_grob(., grobs = rectGrob(gp = gpar(fill = NA, lwd = 1)),
                          t = 1, b = nrow(.), l = 1, r = ncol(.))

plot_avg_time <- ggplot(results, aes(x = duration)) +
  geom_histogram(bins = 50, fill = ngo_cols("blue")) +
  scale_x_time(labels = fmt_seconds) +
  annotation_custom(summary_stats, xmin = 700, xmax = 900, ymin = 30, ymax = 60) +
  labs(x = "Minutes spent on experiment", y = "Count") +
  theme_ngos(base_size = 9.5) +
  theme(panel.grid.minor = element_blank())

plot_avg_time %T>% 
  print() %T>%
  ggsave(., filename = here("analysis", "output", "figures", "avg-time.pdf"),
         width = 4, height = 2.25, units = "in", device = cairo_pdf) %>% 
  ggsave(., filename = here("analysis", "output", "figures", "avg-time.png"),
         width = 4, height = 2.25, units = "in", type = "cairo", dpi = 300)


Original computing environment

writeLines(readLines(file.path(Sys.getenv("HOME"), ".R/Makevars")))
## # http://dirk.eddelbuettel.com/blog/2017/11/27/#011_faster_package_installation_one
## VER=
## CCACHE=ccache
## CC=$(CCACHE) gcc$(VER)
## CXX=$(CCACHE) g++$(VER)
## CXX11=$(CCACHE) g++$(VER)
## CXX14=$(CCACHE) g++$(VER)
## FC=$(CCACHE) gfortran$(VER)
## F77=$(CCACHE) gfortran$(VER)
## 
## CXX14FLAGS=-O3 -march=native -mtune=native -fPIC
devtools::session_info()
## ─ Session info ───────────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 4.0.2 (2020-06-22)
##  os       macOS Catalina 10.15.6      
##  system   x86_64, darwin17.0          
##  ui       X11                         
##  language (EN)                        
##  collate  en_US.UTF-8                 
##  ctype    en_US.UTF-8                 
##  tz       America/New_York            
##  date     2020-10-01                  
## 
## ─ Packages ───────────────────────────────────────────────────────────────────
##  package                * version  date       lib
##  abind                    1.4-5    2016-07-21 [1]
##  assertthat               0.2.1    2019-03-21 [1]
##  backports                1.1.9    2020-08-24 [1]
##  base64enc                0.1-3    2015-07-28 [1]
##  bayesplot                1.7.2    2020-05-28 [1]
##  blob                     1.2.1    2020-01-20 [1]
##  boot                     1.3-25   2020-04-26 [1]
##  broom                  * 0.7.0    2020-07-09 [1]
##  broom.mixed            * 0.2.7    2020-09-05 [1]
##  callr                    3.4.3    2020-03-28 [1]
##  cellranger               1.1.0    2016-07-27 [1]
##  checkmate                2.0.0    2020-02-06 [1]
##  cli                      2.0.2    2020-02-28 [1]
##  cluster                  2.1.0    2019-06-19 [1]
##  coda                     0.19-3   2019-07-05 [1]
##  codetools                0.2-16   2018-12-24 [1]
##  colorspace               1.4-1    2019-03-18 [1]
##  colourpicker             1.0      2017-09-27 [1]
##  commonmark               1.7      2018-12-01 [1]
##  crackdownsphilanthropy * 0.9      2020-10-01 [1]
##  crayon                   1.3.4    2017-09-16 [1]
##  crosstalk                1.1.0.1  2020-03-13 [1]
##  curl                     4.3      2019-12-02 [1]
##  data.table               1.13.0   2020-07-24 [1]
##  DBI                      1.1.0    2019-12-15 [1]
##  dbplyr                   1.4.4    2020-05-27 [1]
##  desc                     1.2.0    2018-05-01 [1]
##  devtools                 2.3.1    2020-07-21 [1]
##  digest                   0.6.25   2020-02-23 [1]
##  dplyr                  * 1.0.2    2020-08-18 [1]
##  DT                       0.15     2020-08-05 [1]
##  dygraphs                 1.1.1.6  2018-07-11 [1]
##  ellipsis                 0.3.1    2020-05-15 [1]
##  evaluate                 0.14     2019-05-28 [1]
##  fansi                    0.4.1    2020-01-08 [1]
##  farver                   2.0.3    2020-01-16 [1]
##  fastmap                  1.0.1    2019-10-08 [1]
##  forcats                * 0.5.0    2020-03-01 [1]
##  foreign                  0.8-80   2020-05-24 [1]
##  forestplot               1.10     2020-07-16 [1]
##  Formula                  1.2-3    2018-05-03 [1]
##  fs                       1.5.0    2020-07-31 [1]
##  generics                 0.0.2    2018-11-29 [1]
##  ggplot2                * 3.3.2    2020-06-19 [1]
##  ggridges                 0.5.2    2020-01-12 [1]
##  glue                   * 1.4.2    2020-08-27 [1]
##  Gmisc                  * 1.11.0   2020-07-03 [1]
##  gridExtra              * 2.3      2017-09-09 [1]
##  gtable                   0.3.0    2019-03-25 [1]
##  gtools                   3.8.2    2020-03-31 [1]
##  haven                    2.3.1    2020-06-01 [1]
##  here                   * 0.1      2017-05-28 [1]
##  hipread                  0.2.2    2020-04-29 [1]
##  Hmisc                    4.4-1    2020-08-10 [1]
##  hms                      0.5.3    2020-01-08 [1]
##  htmlTable              * 2.0.1    2020-07-05 [1]
##  htmltools                0.5.0    2020-06-16 [1]
##  htmlwidgets              1.5.1    2019-10-08 [1]
##  httpuv                   1.5.4    2020-06-06 [1]
##  httr                     1.4.2    2020-07-20 [1]
##  huxtable               * 5.0.0    2020-06-15 [1]
##  igraph                   1.2.5    2020-03-19 [1]
##  inline                   0.3.15   2018-05-18 [1]
##  ipumsr                 * 0.4.5    2020-07-21 [1]
##  jpeg                     0.1-8.1  2019-10-24 [1]
##  jsonlite                 1.7.0    2020-06-25 [1]
##  knitr                    1.29     2020-06-23 [1]
##  labeling                 0.3      2014-08-23 [1]
##  later                    1.1.0.1  2020-06-05 [1]
##  lattice                  0.20-41  2020-04-02 [1]
##  latticeExtra             0.6-29   2019-12-19 [1]
##  lifecycle                0.2.0    2020-03-06 [1]
##  lme4                     1.1-23   2020-04-07 [1]
##  loo                      2.3.1    2020-07-14 [1]
##  lubridate                1.7.9    2020-06-08 [1]
##  magrittr               * 1.5      2014-11-22 [1]
##  markdown                 1.1      2019-08-07 [1]
##  MASS                     7.3-52   2020-08-18 [1]
##  Matrix                   1.2-18   2019-11-27 [1]
##  matrixStats              0.56.0   2020-03-13 [1]
##  memoise                  1.1.0    2017-04-21 [1]
##  mime                     0.9      2020-02-04 [1]
##  miniUI                   0.1.1.1  2018-05-18 [1]
##  minqa                    1.2.4    2014-10-09 [1]
##  modelr                   0.1.8    2020-05-19 [1]
##  munsell                  0.5.0    2018-06-12 [1]
##  nlme                     3.1-149  2020-08-23 [1]
##  nloptr                   1.2.2.2  2020-07-02 [1]
##  nnet                     7.3-14   2020-04-26 [1]
##  pander                 * 0.6.3    2018-11-06 [1]
##  pillar                   1.4.6    2020-07-10 [1]
##  pkgbuild                 1.1.0    2020-07-13 [1]
##  pkgconfig                2.0.3    2019-09-22 [1]
##  pkgload                  1.1.0    2020-05-29 [1]
##  plyr                     1.8.6    2020-03-03 [1]
##  png                      0.1-7    2013-12-03 [1]
##  prettyunits              1.1.1    2020-01-24 [1]
##  processx                 3.4.3    2020-07-05 [1]
##  promises                 1.1.1    2020-06-09 [1]
##  ps                       1.3.4    2020-08-11 [1]
##  purrr                  * 0.3.4    2020-04-17 [1]
##  R6                       2.4.1    2019-11-12 [1]
##  RColorBrewer             1.1-2    2014-12-07 [1]
##  Rcpp                   * 1.0.5    2020-07-06 [1]
##  RcppParallel             5.0.2    2020-06-24 [1]
##  readr                  * 1.3.1    2018-12-21 [1]
##  readxl                   1.3.1    2019-03-13 [1]
##  remotes                  2.2.0    2020-07-21 [1]
##  reprex                   0.3.0    2019-05-16 [1]
##  reshape2                 1.4.4    2020-04-09 [1]
##  rlang                    0.4.7    2020-07-09 [1]
##  rmarkdown                2.3      2020-06-18 [1]
##  rpart                    4.1-15   2019-04-12 [1]
##  rprojroot                1.3-2    2018-01-03 [1]
##  rsconnect                0.8.16   2019-12-13 [1]
##  rstan                  * 2.21.2   2020-07-27 [1]
##  rstanarm               * 2.21.1   2020-07-20 [1]
##  rstantools               2.1.1    2020-07-06 [1]
##  rstudioapi               0.11     2020-02-07 [1]
##  rvest                    0.3.6    2020-07-25 [1]
##  scales                 * 1.1.1    2020-05-11 [1]
##  sessioninfo              1.1.1    2018-11-05 [1]
##  shiny                    1.5.0    2020-06-23 [1]
##  shinyjs                  1.1      2020-01-13 [1]
##  shinystan                2.5.0    2018-05-01 [1]
##  shinythemes              1.1.2    2018-11-06 [1]
##  StanHeaders            * 2.21.0-6 2020-08-16 [1]
##  statmod                  1.4.34   2020-02-17 [1]
##  stringi                  1.4.6    2020-02-17 [1]
##  stringr                * 1.4.0    2019-02-10 [1]
##  survival                 3.2-3    2020-06-13 [1]
##  testthat                 2.3.2    2020-03-02 [1]
##  threejs                  0.3.3    2020-01-21 [1]
##  tibble                 * 3.0.3    2020-07-10 [1]
##  tidyr                  * 1.1.2    2020-08-27 [1]
##  tidyselect               1.1.0    2020-05-11 [1]
##  tidyverse              * 1.3.0    2019-11-21 [1]
##  TMB                      1.7.18   2020-07-27 [1]
##  usethis                  1.6.1    2020-04-29 [1]
##  V8                       3.2.0    2020-06-19 [1]
##  vctrs                    0.3.4    2020-08-29 [1]
##  withr                    2.2.0    2020-04-20 [1]
##  xfun                     0.16     2020-07-24 [1]
##  XML                      3.99-0.5 2020-07-23 [1]
##  xml2                     1.3.2    2020-04-23 [1]
##  xtable                   1.8-4    2019-04-21 [1]
##  xts                      0.12-0   2020-01-19 [1]
##  yaml                     2.2.1    2020-02-01 [1]
##  zeallot                  0.1.0    2018-01-28 [1]
##  zoo                      1.8-8    2020-05-02 [1]
##  source                              
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  Github (bbolker/broom.mixed@3d12088)
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  local                               
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.0)                      
##  CRAN (R 4.0.2)                      
##  CRAN (R 4.0.0)                      
## 
## [1] /Library/Frameworks/R.framework/Versions/4.0/Resources/library
LS0tCnRpdGxlOiAiQWRkaXRpb25hbCBhbmFseXNpcyIKYXV0aG9yOiAiU3VwYXJuYSBDaGF1ZGhyeSBhbmQgQW5kcmV3IEhlaXNzIgpkYXRlOiAiTGFzdCBydW46IGByIGZvcm1hdChTeXMudGltZSgpLCAnJUYnKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZm9sZGluZzogaGlkZQplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5yZXRpbmEgPSAzLCBmaWcuYWxpZ24gPSAiY2VudGVyIikKYGBgCgpgYGB7ciBsb2FkLWxpYnJhcmllcy1kYXRhLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIExvYWQgbGlicmFyaWVzCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGNyYWNrZG93bnNwaGlsYW50aHJvcHkpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkocnN0YW4pCmxpYnJhcnkocnN0YW5hcm0pCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoYnJvb20ubWl4ZWQpCmxpYnJhcnkoZ2x1ZSkKbGlicmFyeShncmlkKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShHbWlzYykgICMgRm9yIHRoZSBDT05TT1JUIGRpYWdyYW0KbGlicmFyeShwYW5kZXIpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGlwdW1zcikKbGlicmFyeShodXh0YWJsZSkKbGlicmFyeShoZXJlKQoKc291cmNlKGhlcmUoImFuYWx5c2lzIiwgIm9wdGlvbnMuUiIpKQoKIyBQcmludCBjb3JyZWN0IGh1eHRhYmxlIHRhYmxlIGRlcGVuZGluZyBvbiB0aGUgdHlwZSBvZiBvdXRwdXQuCiMKIyBUZWNobmljYWxseSB0aGlzIGlzbid0IGNvbXBsZXRlbHkgbmVjZXNzYXJ5LCBzaW5jZSBodXh0YWJsZSBjYW4gb3V0cHV0IGEKIyBtYXJrZG93biB0YWJsZSwgd2hpY2ggaXMgb3N0ZW5zaWJseSB1bml2ZXJzYWwgZm9yIGFsbCBvdXRwdXQgdHlwZXMuIEhvd2V2ZXIsCiMgbWFya2Rvd24gdGFibGVzIGFyZSBpbmhlcmVudGx5IGxpbWl0ZWQgaW4gaG93IGZhbmN5IHRoZXkgY2FuIGJlIChlLmcuIHRoZXkKIyBkb24ndCBzdXBwb3J0IGNvbHVtbiBzcGFucyksIHNvIEkgaW5zdGVhZCBsZXQgdGhlIHJlZ3Jlc3Npb24gdGFibGUgdXNlCiMgaHV4dGFibGUncyBmYW5jeSBmb3JtYXR0aW5nIGZvciBodG1sIGFuZCBQREYgYW5kIG1hcmtkb3duIGV2ZXJ5d2hlcmUgZWxzZS4KaWYgKGlzVFJVRShnZXRPcHRpb24oJ2tuaXRyLmluLnByb2dyZXNzJykpKSB7CiAgZmlsZV9mb3JtYXQgPC0gcm1hcmtkb3duOjphbGxfb3V0cHV0X2Zvcm1hdHMoa25pdHI6OmN1cnJlbnRfaW5wdXQoKSkKfSBlbHNlIHsKICBmaWxlX2Zvcm1hdCA8LSAiIgp9CgpwcmludF9odXggPC0gZnVuY3Rpb24oeCkgewogIGlmICgiaHRtbF9kb2N1bWVudCIgJWluJSBmaWxlX2Zvcm1hdCkgewogICAgcHJpbnRfaHRtbCh4KQogIH0gZWxzZSBpZiAoInBkZl9kb2N1bWVudCIgJWluJSBmaWxlX2Zvcm1hdCkgewogICAgcHJpbnRfbGF0ZXgoeCkKICB9IGVsc2UgaWYgKCJ3b3JkX2RvY3VtZW50IiAlaW4lIGZpbGVfZm9ybWF0KSB7CiAgICBwcmludF9tZCh4KQogIH0gZWxzZSB7CiAgICBwcmludCh4KQogIH0KfQoKIyBMb2FkIGRhdGEKcmVzdWx0cyA8LSByZWFkUkRTKGhlcmUoImRhdGEiLCAiZGVyaXZlZF9kYXRhIiwgInJlc3VsdHNfY2xlYW4ucmRzIikpCmBgYAoKIyBDT05TT1JUIGZsb3cKCmBgYHtyIGJ1aWxkLWNvbnNvcnR9CmNvbnNvcnQgPC0gcmVhZFJEUyhoZXJlKCJkYXRhIiwgImRlcml2ZWRfZGF0YSIsICJjb21wbGV0aW9uX3N1bW1hcnkucmRzIikpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcmVhc29uLCB2YWx1ZXNfZnJvbSA9IG4pICU+JSAKICBtdXRhdGUoZ3JvdXAgPSAxOm4oKSwKICAgICAgICAgYXNzaWduZWQgPSBBcHByb3ZlZCArIGBGYWlsZWQgZmlyc3QgYXR0ZW50aW9uIGNoZWNrYCwKICAgICAgICAgaXNzdWUgPSBzdHJfcmVwbGFjZV9hbGwoaXNzdWUsICJhc3Npc3RhbmNlIiwgImFzc2lzdC4iKSkgJT4lIAogIG11dGF0ZShhc3NpZ25lZF9sYWJlbCA9IGdsdWUoIkFsbG9jYXRlZCB0byBHcm91cCB7Z3JvdXB9XG57Y3JhY2tkb3dufVxue2lzc3VlfVxue2Z1bmRpbmd9IGZ1bmRpbmdcblxuTiA9IHthc3NpZ25lZH0iKSwKICAgICAgICAgY29tcGxldGVkX2xhYmVsID0gZ2x1ZSgiQ29tcGxldGVkXG5OID0ge0FwcHJvdmVkfVxuXG57YEZhaWxlZCBmaXJzdCBhdHRlbnRpb24gY2hlY2tgfSBmYWlsZWRcbmF0dGVudGlvbiBjaGVjayIpKQoKYXNzZXNzZWRfZWxpZ2liaWxpdHlfbiA8LSBzdW0oY29uc29ydCRBcHByb3ZlZCwgY29uc29ydCRgRmFpbGVkIGZpcnN0IGF0dGVudGlvbiBjaGVja2AsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb3J0JGBUb29rIHN1cnZleSBvdXRpc2RlIG9mIE1UdXJrYCkKaW5lbGlnaWJsZV9uIDwtIHN1bShjb25zb3J0JGBUb29rIHN1cnZleSBvdXRpc2RlIG9mIE1UdXJrYCkKcmFuZG9taXplZF9uIDwtIHN1bShjb25zb3J0JEFwcHJvdmVkLCBjb25zb3J0JGBGYWlsZWQgZmlyc3QgYXR0ZW50aW9uIGNoZWNrYCkKCgojIGh0dHBzOi8vYWdoYXluZXMud29yZHByZXNzLmNvbS8yMDE4LzA1LzA5L2Zsb3ctY2hhcnRzLWluLXIvCiMgc2V0IHNvbWUgcGFyYW1ldGVycyB0byB1c2UgcmVwZWF0ZWRseQp3aWR0aCA8LSAwLjEKeHMgPC0gc2VxKDAuMSwgMC45LCBsZW5ndGgub3V0ID0gOCkKYWxsb2NhdGVkX3kgPC0gMC4zNzUKY29tcGxldGVkX3kgPC0gMC4xMjUKCmJveF9ncF9ncmV5IDwtIGdwYXIoZmlsbCA9IG5nb19jb2xzKCJsaWdodCBncmV5IikpCmJveF9ncF9ibHVlX2RrIDwtIGdwYXIoZmlsbCA9IG5nb19jb2xzKCJibHVlIiksIGFscGhhID0gMC43NSkKYm94X2dwX2JsdWVfbHQgPC0gZ3BhcihmaWxsID0gbmdvX2NvbHMoImJsdWUiKSwgYWxwaGEgPSAwLjM1KQpib3hfZ3BfZ3JlZW4gPC0gZ3BhcihmaWxsID0gbmdvX2NvbHMoImdyZWVuIiksIGFscGhhID0gMC42NSkKYm94X2dwX3llbGxvdyA8LSBncGFyKGZpbGwgPSBuZ29fY29scygieWVsbG93IikpCmJveF9ncF9vcmFuZ2UgPC0gZ3BhcihmaWxsID0gbmdvX2NvbHMoIm9yYW5nZSIpLCBhbHBoYSA9IDAuNjUpCgp0eHRfZ3AgPC0gZ3Bhcihmb250ZmFtaWx5ID0gIlJvYm90byBDb25kZW5zZWQiLCAKICAgICAgICAgICAgICAgZm9udGZhY2UgPSAicGxhaW4iLCBmb250c2l6ZSA9IDgpCgojIENyZWF0ZSBib3hlcwp0b3RhbCA8LSBib3hHcm9iKGdsdWUoIkFzc2Vzc2VkIGZvciBlbGlnaWJpbGl0eVxuIE4gPSB7YXNzZXNzZWRfZWxpZ2liaWxpdHlfbn0iKSwgCiAgICAgICAgICAgICAgICAgeCA9IDAuNSwgeSA9IDAuOSwgd2lkdGggPSAyICogd2lkdGgsCiAgICAgICAgICAgICAgICAgYm94X2dwID0gYm94X2dwX2JsdWVfbHQsIHR4dF9ncCA9IHR4dF9ncCkKcmFuZG9taXplZCA8LSBib3hHcm9iKGdsdWUoIlJhbmRvbWl6ZWRcbiBOID0ge3JhbmRvbWl6ZWRfbn0iKSwgCiAgICAgICAgICAgICAgICAgICAgICB4ID0gMC41LCB5ID0gMC42NSwgd2lkdGggPSAyICogd2lkdGgsCiAgICAgICAgICAgICAgICAgICAgICBib3hfZ3AgPSBib3hfZ3BfYmx1ZV9kaywgdHh0X2dwID0gdHh0X2dwKQppbmVsaWdpYmxlIDwtIGJveEdyb2IoZ2x1ZSgiUGFydGljaXBhbnRzIGV4Y2x1ZGVkIGZvclxuY29tcGxldGluZyBRdWFsdHJpY3Mgc3VydmV5XG5vdXRzaWRlIG9mIE1UdXJrXG4gTiA9IHtpbmVsaWdpYmxlX259IiksIAogICAgICAgICAgICAgICAgICAgICAgeCA9IHhzWzddLCB5ID0gMC43NzUsICN3aWR0aCA9IDAuMjUsCiAgICAgICAgICAgICAgICAgICAgICBib3hfZ3AgPSBib3hfZ3BfeWVsbG93LCB0eHRfZ3AgPSB0eHRfZ3ApCgpncm91cDEgPC0gYm94R3JvYihmaWx0ZXIoY29uc29ydCwgZ3JvdXAgPT0gMSkkYXNzaWduZWRfbGFiZWwsCiAgICAgICAgICAgICAgICAgIHggPSB4c1sxXSwgeSA9IGFsbG9jYXRlZF95LCB3aWR0aCA9IHdpZHRoLCAKICAgICAgICAgICAgICAgICAgYm94X2dwID0gYm94X2dwX29yYW5nZSwgdHh0X2dwID0gdHh0X2dwKQpncm91cDIgPC0gYm94R3JvYihmaWx0ZXIoY29uc29ydCwgZ3JvdXAgPT0gMikkYXNzaWduZWRfbGFiZWwsCiAgICAgICAgICAgICAgICAgIHggPSB4c1syXSwgeSA9IGFsbG9jYXRlZF95LCB3aWR0aCA9IHdpZHRoLCAKICAgICAgICAgICAgICAgICAgYm94X2dwID0gYm94X2dwX29yYW5nZSwgdHh0X2dwID0gdHh0X2dwKQpncm91cDMgPC0gYm94R3JvYihmaWx0ZXIoY29uc29ydCwgZ3JvdXAgPT0gMykkYXNzaWduZWRfbGFiZWwsCiAgICAgICAgICAgICAgICAgIHggPSB4c1szXSwgeSA9IGFsbG9jYXRlZF95LCB3aWR0aCA9IHdpZHRoLCAKICAgICAgICAgICAgICAgICAgYm94X2dwID0gYm94X2dwX29yYW5nZSwgdHh0X2dwID0gdHh0X2dwKQpncm91cDQgPC0gYm94R3JvYihmaWx0ZXIoY29uc29ydCwgZ3JvdXAgPT0gNCkkYXNzaWduZWRfbGFiZWwsCiAgICAgICAgICAgICAgICAgIHggPSB4c1s0XSwgeSA9IGFsbG9jYXRlZF95LCB3aWR0aCA9IHdpZHRoLCAKICAgICAgICAgICAgICAgICAgYm94X2dwID0gYm94X2dwX29yYW5nZSwgdHh0X2dwID0gdHh0X2dwKQpncm91cDUgPC0gYm94R3JvYihmaWx0ZXIoY29uc29ydCwgZ3JvdXAgPT0gNSkkYXNzaWduZWRfbGFiZWwsCiAgICAgICAgICAgICAgICAgIHggPSB4c1s1XSwgeSA9IGFsbG9jYXRlZF95LCB3aWR0aCA9IHdpZHRoLCAKICAgICAgICAgICAgICAgICAgYm94X2dwID0gYm94X2dwX29yYW5nZSwgdHh0X2dwID0gdHh0X2dwKQpncm91cDYgPC0gYm94R3JvYihmaWx0ZXIoY29uc29ydCwgZ3JvdXAgPT0gNikkYXNzaWduZWRfbGFiZWwsCiAgICAgICAgICAgICAgICAgIHggPSB4c1s2XSwgeSA9IGFsbG9jYXRlZF95LCB3aWR0aCA9IHdpZHRoLCAKICAgICAgICAgICAgICAgICAgYm94X2dwID0gYm94X2dwX29yYW5nZSwgdHh0X2dwID0gdHh0X2dwKQpncm91cDcgPC0gYm94R3JvYihmaWx0ZXIoY29uc29ydCwgZ3JvdXAgPT0gNykkYXNzaWduZWRfbGFiZWwsCiAgICAgICAgICAgICAgICAgIHggPSB4c1s3XSwgeSA9IGFsbG9jYXRlZF95LCB3aWR0aCA9IHdpZHRoLCAKICAgICAgICAgICAgICAgICAgYm94X2dwID0gYm94X2dwX29yYW5nZSwgdHh0X2dwID0gdHh0X2dwKQpncm91cDggPC0gYm94R3JvYihmaWx0ZXIoY29uc29ydCwgZ3JvdXAgPT0gOCkkYXNzaWduZWRfbGFiZWwsCiAgICAgICAgICAgICAgICAgIHggPSB4c1s4XSwgeSA9IGFsbG9jYXRlZF95LCB3aWR0aCA9IHdpZHRoLCAKICAgICAgICAgICAgICAgICAgYm94X2dwID0gYm94X2dwX29yYW5nZSwgdHh0X2dwID0gdHh0X2dwKQoKZ3JvdXAxX2NvbXBsZXRlZCA8LSBib3hHcm9iKGZpbHRlcihjb25zb3J0LCBncm91cCA9PSAxKSRjb21wbGV0ZWRfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHhzWzFdLCB5ID0gY29tcGxldGVkX3ksIHdpZHRoID0gd2lkdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3hfZ3AgPSBib3hfZ3BfZ3JlZW4sIHR4dF9ncCA9IHR4dF9ncCkKZ3JvdXAyX2NvbXBsZXRlZCA8LSBib3hHcm9iKGZpbHRlcihjb25zb3J0LCBncm91cCA9PSAyKSRjb21wbGV0ZWRfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHhzWzJdLCB5ID0gY29tcGxldGVkX3ksIHdpZHRoID0gd2lkdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3hfZ3AgPSBib3hfZ3BfZ3JlZW4sIHR4dF9ncCA9IHR4dF9ncCkKZ3JvdXAzX2NvbXBsZXRlZCA8LSBib3hHcm9iKGZpbHRlcihjb25zb3J0LCBncm91cCA9PSAzKSRjb21wbGV0ZWRfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHhzWzNdLCB5ID0gY29tcGxldGVkX3ksIHdpZHRoID0gd2lkdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3hfZ3AgPSBib3hfZ3BfZ3JlZW4sIHR4dF9ncCA9IHR4dF9ncCkKZ3JvdXA0X2NvbXBsZXRlZCA8LSBib3hHcm9iKGZpbHRlcihjb25zb3J0LCBncm91cCA9PSA0KSRjb21wbGV0ZWRfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHhzWzRdLCB5ID0gY29tcGxldGVkX3ksIHdpZHRoID0gd2lkdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3hfZ3AgPSBib3hfZ3BfZ3JlZW4sIHR4dF9ncCA9IHR4dF9ncCkKZ3JvdXA1X2NvbXBsZXRlZCA8LSBib3hHcm9iKGZpbHRlcihjb25zb3J0LCBncm91cCA9PSA1KSRjb21wbGV0ZWRfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHhzWzVdLCB5ID0gY29tcGxldGVkX3ksIHdpZHRoID0gd2lkdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3hfZ3AgPSBib3hfZ3BfZ3JlZW4sIHR4dF9ncCA9IHR4dF9ncCkKZ3JvdXA2X2NvbXBsZXRlZCA8LSBib3hHcm9iKGZpbHRlcihjb25zb3J0LCBncm91cCA9PSA2KSRjb21wbGV0ZWRfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHhzWzZdLCB5ID0gY29tcGxldGVkX3ksIHdpZHRoID0gd2lkdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3hfZ3AgPSBib3hfZ3BfZ3JlZW4sIHR4dF9ncCA9IHR4dF9ncCkKZ3JvdXA3X2NvbXBsZXRlZCA8LSBib3hHcm9iKGZpbHRlcihjb25zb3J0LCBncm91cCA9PSA3KSRjb21wbGV0ZWRfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHhzWzddLCB5ID0gY29tcGxldGVkX3ksIHdpZHRoID0gd2lkdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3hfZ3AgPSBib3hfZ3BfZ3JlZW4sIHR4dF9ncCA9IHR4dF9ncCkKZ3JvdXA4X2NvbXBsZXRlZCA8LSBib3hHcm9iKGZpbHRlcihjb25zb3J0LCBncm91cCA9PSA4KSRjb21wbGV0ZWRfbGFiZWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IHhzWzhdLCB5ID0gY29tcGxldGVkX3ksIHdpZHRoID0gd2lkdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3hfZ3AgPSBib3hfZ3BfZ3JlZW4sIHR4dF9ncCA9IHR4dF9ncCkKCnRvdGFsX3JhbmRvbV9jb25uZWN0IDwtIGNvbm5lY3RHcm9iKHRvdGFsLCByYW5kb21pemVkLCAidiIpCnRvdGFsX2luZWxpZ2libGVfY29ubmVjdCA8LSBjb25uZWN0R3JvYih0b3RhbCwgaW5lbGlnaWJsZSwgIi0iKQoKcmFuZF9jb25uZWN0MSA8LSBjb25uZWN0R3JvYihyYW5kb21pemVkLCBncm91cDEsICJOIikKcmFuZF9jb25uZWN0MiA8LSBjb25uZWN0R3JvYihyYW5kb21pemVkLCBncm91cDIsICJOIikKcmFuZF9jb25uZWN0MyA8LSBjb25uZWN0R3JvYihyYW5kb21pemVkLCBncm91cDMsICJOIikKcmFuZF9jb25uZWN0NCA8LSBjb25uZWN0R3JvYihyYW5kb21pemVkLCBncm91cDQsICJOIikKcmFuZF9jb25uZWN0NSA8LSBjb25uZWN0R3JvYihyYW5kb21pemVkLCBncm91cDUsICJOIikKcmFuZF9jb25uZWN0NiA8LSBjb25uZWN0R3JvYihyYW5kb21pemVkLCBncm91cDYsICJOIikKcmFuZF9jb25uZWN0NyA8LSBjb25uZWN0R3JvYihyYW5kb21pemVkLCBncm91cDcsICJOIikKcmFuZF9jb25uZWN0OCA8LSBjb25uZWN0R3JvYihyYW5kb21pemVkLCBncm91cDgsICJOIikKCmNvbXBsZXRlX2Nvbm5lY3QxIDwtIGNvbm5lY3RHcm9iKGdyb3VwMSwgZ3JvdXAxX2NvbXBsZXRlZCwgIk4iKQpjb21wbGV0ZV9jb25uZWN0MiA8LSBjb25uZWN0R3JvYihncm91cDIsIGdyb3VwMl9jb21wbGV0ZWQsICJOIikKY29tcGxldGVfY29ubmVjdDMgPC0gY29ubmVjdEdyb2IoZ3JvdXAzLCBncm91cDNfY29tcGxldGVkLCAiTiIpCmNvbXBsZXRlX2Nvbm5lY3Q0IDwtIGNvbm5lY3RHcm9iKGdyb3VwNCwgZ3JvdXA0X2NvbXBsZXRlZCwgIk4iKQpjb21wbGV0ZV9jb25uZWN0NSA8LSBjb25uZWN0R3JvYihncm91cDUsIGdyb3VwNV9jb21wbGV0ZWQsICJOIikKY29tcGxldGVfY29ubmVjdDYgPC0gY29ubmVjdEdyb2IoZ3JvdXA2LCBncm91cDZfY29tcGxldGVkLCAiTiIpCmNvbXBsZXRlX2Nvbm5lY3Q3IDwtIGNvbm5lY3RHcm9iKGdyb3VwNywgZ3JvdXA3X2NvbXBsZXRlZCwgIk4iKQpjb21wbGV0ZV9jb25uZWN0OCA8LSBjb25uZWN0R3JvYihncm91cDgsIGdyb3VwOF9jb21wbGV0ZWQsICJOIikKCmZ1bGxfY2hhcnQgPC0gbGlzdCh0b3RhbCwgcmFuZG9taXplZCwgaW5lbGlnaWJsZSwgdG90YWxfcmFuZG9tX2Nvbm5lY3QsIHRvdGFsX2luZWxpZ2libGVfY29ubmVjdCwKICAgICAgICAgICAgICAgICAgIGdyb3VwMSwgZ3JvdXAyLCBncm91cDMsIGdyb3VwNCwgZ3JvdXA1LCBncm91cDYsIGdyb3VwNywgZ3JvdXA4LAogICAgICAgICAgICAgICAgICAgcmFuZF9jb25uZWN0MSwgcmFuZF9jb25uZWN0MiwgcmFuZF9jb25uZWN0MywgcmFuZF9jb25uZWN0NCwgCiAgICAgICAgICAgICAgICAgICByYW5kX2Nvbm5lY3Q1LCByYW5kX2Nvbm5lY3Q2LCByYW5kX2Nvbm5lY3Q3LCByYW5kX2Nvbm5lY3Q4LAogICAgICAgICAgICAgICAgICAgZ3JvdXAxX2NvbXBsZXRlZCwgZ3JvdXAyX2NvbXBsZXRlZCwgZ3JvdXAzX2NvbXBsZXRlZCwgZ3JvdXA0X2NvbXBsZXRlZCwgCiAgICAgICAgICAgICAgICAgICBncm91cDVfY29tcGxldGVkLCBncm91cDZfY29tcGxldGVkLCBncm91cDdfY29tcGxldGVkLCBncm91cDhfY29tcGxldGVkLAogICAgICAgICAgICAgICAgICAgY29tcGxldGVfY29ubmVjdDEsIGNvbXBsZXRlX2Nvbm5lY3QyLCBjb21wbGV0ZV9jb25uZWN0MywgY29tcGxldGVfY29ubmVjdDQsIAogICAgICAgICAgICAgICAgICAgY29tcGxldGVfY29ubmVjdDUsIGNvbXBsZXRlX2Nvbm5lY3Q2LCBjb21wbGV0ZV9jb25uZWN0NywgY29tcGxldGVfY29ubmVjdDgpIApgYGAKCmBgYHtyIHNob3ctc2F2ZS1jb25zb3J0LCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9Niwgb3V0LndpZHRoPSIxMDAlIn0KIyBPcmRpbmFyaWx5LCB5b3UgY2FuIHVzZSBncmlkLmdyYWIoKSB0byBzYXZlIHRoZSBvdXRwdXQgb2YgYSBncmlkIGZpZ3VyZSBpbnRvCiMgYW4gb2JqZWN0IGFuZCB0aGVuIHVzZSB0aGF0IGluIGdnc2F2ZSgpLiBIb3dldmVyLCB3aGVuIGtuaXR0aW5nLCB0aGlzIGNyZWF0ZXMKIyBhIGR1cGxpY2F0ZSBwbG90LCB3aGljaCBpcyBmcnVzdHJhdGluZy4gU28gaW5zdGVhZCwgd2UgdXNlIHdhbGsoKSB0byByZXByaW50CiMgYWxsIHRoZSBncm9icyB3aXRoaW4gc3BlY2lmaWMgcGRmIGFuZCBwbmcgZGV2aWNlcwojCiMgU2VlIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8xNzUwOTc3MC8xMjA4OTggZm9yIGEgc2ltaWxhciBpc3N1ZQoKIyBTYXZlIGFzIFBERgpjYWlyb19wZGYoZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZmlndXJlcyIsICJjb25zb3J0LnBkZiIpLAogICAgICAgICAgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKZ3JpZC5uZXdwYWdlKCkKd2FsayhmdWxsX2NoYXJ0LCB+IHByaW50KC4pKQppbnZpc2libGUoZGV2Lm9mZigpKQoKIyBTYXZlIGFzIFBORwpwbmcoZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZmlndXJlcyIsICJjb25zb3J0LnBuZyIpLCAKICAgIHdpZHRoID0gMTAsIGhlaWdodCA9IDYsIHVuaXRzID0gImluIiwKICAgIGJnID0gIndoaXRlIiwgcmVzID0gMzAwLCB0eXBlID0gImNhaXJvIikKZ3JpZC5uZXdwYWdlKCkKd2FsayhmdWxsX2NoYXJ0LCB+IHByaW50KC4pKQppbnZpc2libGUoZGV2Lm9mZigpKQoKIyBTaG93IGluIGtuaXR0ZWQgZG9jdW1lbnQKZ3JpZC5uZXdwYWdlKCkKd2FsayhmdWxsX2NoYXJ0LCB+IHByaW50KC4pKQpgYGAKCgojIENoYXJhY3RlcmlzdGljcyBvZiBleHBlcmltZW50IHNhbXBsZXMKCldlIGNvbXBhcmUgb3VyIHNhbXBsZSB3aXRoIGRlbW9ncmFwaGljIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgZ2VuZXJhbCBwb3B1bGF0aW9uLiBTaW5jZSB0aGVyZSBpcyBubyBuYXRpb25hbGx5IHJlcHJlc2VudGF0aXZlIHNhbXBsZSBmb3IgZWFjaCBvZiBvdXIgZGVtb2dyYXBoaWMgdmFyaWFibGVzLCB3ZSB1c2UgdHdvIHdhdmVzIG9mIHRoZSBVUyBDZW5zdXMncyBDdXJyZW50IFBvcHVsYXRpb24gU3VydmV5IChDUFMpLCB3aXRoIGRhdGEgZnJvbSB0aGUgW01pbm5lc290YSBQb3B1bGF0aW9uIENlbnRlcidzIEludGVncmF0ZWQgUHVibGljIFVzZSBNaWNyb2RhdGEgU2VyaWVzIChJUFVNUyldKGh0dHBzOi8vY3BzLmlwdW1zLm9yZy9jcHMvKS4KCkZvciBnZW5lcmFsIGRlbW9ncmFwaGljIGluZm9ybWF0aW9uLCB3ZSB1c2UgZGF0YSBmcm9tIHRoZSAyMDE3IFtBbm51YWwgU29jaWFsIGFuZCBFY29ub21pYyBTdXBwbGVtZW50IChBU0VDKV0oaHR0cHM6Ly9jcHMuaXB1bXMub3JnL2Nwcy9hc2VjX3NhbXBsZV9ub3Rlcy5zaHRtbCkgZm9yIHRoZSBDUFMuIEZyb20gMjAwMuKAkzIwMTUsIHRoZSBDUFMgaW5jbHVkZWQgYSBbVm9sdW50ZWVyIFN1cHBsZW1lbnRdKGh0dHBzOi8vY3BzLmlwdW1zLm9yZy9jcHMvdm9sdW50ZWVyX3NhbXBsZV9ub3Rlcy5zaHRtbCkgZXZlcnkgU2VwdGVtYmVyLCBzbyB3ZSB1c2UgMjAxNSBkYXRhIGZvciBkYXRhIG9uIHZvbHVudGVlcmluZyBhbmQgZG9uYXRpbmcgdG8gY2hhcml0eS4KCklQVU1TIHJlcXVpcmVzIHRoYXQgeW91IG1hbnVhbGx5IGdlbmVyYXRlIGEgZGF0YSBleHRyYWN0IHRocm91Z2ggdGhlaXIgd2Vic2l0ZSwgc28gZG93bmxvYWRpbmcgZGF0YSBmcm9tIHRoZW0gaXMgbm90IGVudGlyZWx5IGF1dG9tYXRlZCBvciByZXByb2R1Y2libGUuIFdlIGNyZWF0ZWQgdHdvIGV4dHJhY3RzICh0aG91Z2ggdGhpcyBjb3VsZCBoYXZlIGJlZW4gY29tYmluZWQgaW50byBvbmUpLCB3aXRoIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzCgotICBgImRhdGEvcmF3X2RhdGEvaXB1bXMtY3BzL2Nwc18yMDE3LmRhdC5neiJgOiAyMDE3IEFTRUMsIHdpdGggdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMgc2VsZWN0ZWQgKGluIGFkZGl0aW9uIHRvIHdoYXRldmVyIElQVU1TIHByZXNlbGVjdHMgYnkgZGVmYXVsdCkgKGFuZCB3ZWlnaHRlZCBieSBgQVNFQ1dUYCk6CiAgICAtIGBBR0VgCiAgICAtIGBTRVhgCiAgICAtIGBFRFVDYAogICAgLSBgSU5DVE9UYAotICBgImRhdGEvcmF3X2RhdGEvaXB1bXMtY3BzL2Nwc18wOV8yMDE1LmRhdC5neiJgOiBTZXB0ZW1iZXIgMjAxNSBiYXNpYyBtb250aGx5IENQUyAod2hpY2ggaW5jbHVkZXMgdGhlIFZvbHVudGVlciBTdXBwbGVtZW50KSwgd2l0aCB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcyBzZWxlY3RlZCAoYW5kIHdlaWdodGVkIGJ5IGBWTFNVUFBXVGApOgogICAgLSBgVkxTVEFUVVNgCiAgICAtIGBWTERPTkFURWAKCldlIGRvIG5vdCBzaG93IG90aGVyIHJlc3BvbmRlbnQgZGVtb2dyYXBoaWMgZGV0YWlscyBiZWNhdXNlIHdlIGRvbid0IGhhdmUgZ29vZCBwb3B1bGF0aW9uLWxldmVsIGRhdGEgdG8gY29tcGFyZSBvdXIgc2FtcGxlIHdpdGguIFdlIGNvdWxkIHRoZW9yZXRpY2FsbHkgdXNlIFBldyBkYXRhIGZvciBwb2xpdGljYWwgcHJlZmVyZW5jZXMsIGJ1dCB0aGV5IGNvbGxlY3QgZGF0YSBvbiBwYXJ0eSBhZmZpbGlhdGlvbiwgd2hpbGUgd2UgY29sbGVjdGVkIGRhdGEgYWJvdXQgcmVzcG9uZGVudCBwb3NpdGlvbnMgYWxvbmcgYSBjb25zZXJ2YXRpdmXigJNsaWJlcmFsIHNwZWN0cnVtLCBzbyB0aGUgdHdvIHZhcmlhYmxlcyBhcmVuJ3QgY29tcGFyYWJsZS4KCmBgYHtyIGxvYWQtY2xlYW4tY3BzLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpjcHNfMjAxNV9kZGlfZmlsZSA8LSBoZXJlKCJkYXRhIiwgInJhd19kYXRhIiwgImlwdW1zLWNwcyIsICJjcHNfMDlfMjAxNS54bWwiKQpjcHNfMjAxNV9kYXRhX2ZpbGUgPC0gaGVyZSgiZGF0YSIsICJyYXdfZGF0YSIsICJpcHVtcy1jcHMiLCAiY3BzXzA5XzIwMTUuZGF0Lmd6IikKCmNwc18yMDE1X2RkaSA8LSByZWFkX2lwdW1zX2RkaShjcHNfMjAxNV9kZGlfZmlsZSkKY3BzXzIwMTVfZGF0YSA8LSByZWFkX2lwdW1zX21pY3JvKGNwc18yMDE1X2RkaV9maWxlLCBkYXRhX2ZpbGUgPSBjcHNfMjAxNV9kYXRhX2ZpbGUsIHZlcmJvc2UgPSBGQUxTRSkKCmNwc18yMDE3X2RkaV9maWxlIDwtIGhlcmUoImRhdGEiLCAicmF3X2RhdGEiLCAiaXB1bXMtY3BzIiwgImNwc18yMDE3LnhtbCIpCmNwc18yMDE3X2RhdGFfZmlsZSA8LSBoZXJlKCJkYXRhIiwgInJhd19kYXRhIiwgImlwdW1zLWNwcyIsICJjcHNfMjAxNy5kYXQuZ3oiKQoKY3BzXzIwMTdfZGRpIDwtIHJlYWRfaXB1bXNfZGRpKGNwc18yMDE3X2RkaV9maWxlKQpjcHNfMjAxN19kYXRhIDwtIHJlYWRfaXB1bXNfbWljcm8oY3BzXzIwMTdfZGRpX2ZpbGUsIGRhdGFfZmlsZSA9IGNwc18yMDE3X2RhdGFfZmlsZSwgdmVyYm9zZSA9IEZBTFNFKQoKIyBWb2x1bnRlZXJpbmcgZGF0YSBmcm9tIFNlcHRlbWJlciAyMDE1IG9ubHkKZGZfdm9sdW50ZWVyaW5nIDwtIGNwc18yMDE1X2RhdGEgJT4lIAogICMgUmVtb3ZlIHZhbHVlcyBub3QgaW4gdGhlIHVuaXZlcnNlCiAgbXV0YXRlX2F0KHZhcnMoVkxTVEFUVVMsIFZMRE9OQVRFKSwgbGlzdCh+aWZlbHNlKC4gPT0gOTksIE5BLCAuKSkpCgojIEFsbCBvdGhlciBkYXRhIGZyb20gYW5udWFsIE1hcmNoIDIwMTcgc3VydmV5CmRmX2RlbW9ncmFwaGljcyA8LSBjcHNfMjAxN19kYXRhICU+JSAKICAjIFJlbW92ZSB2YWx1ZXMgbm90IGluIHRoZSB1bml2ZXJzZQogIG11dGF0ZShTRVggPSBpZmVsc2UoU0VYID09IDksIE5BLCBTRVgpLAogICAgICAgICBFRFVDID0gaWZlbHNlKEVEVUMgPD0gMSB8IEVEVUMgPT0gOTk5LCBOQSwgRURVQyksCiAgICAgICAgIElOQ1RPVCA9IGlmZWxzZShJTkNUT1QgPT0gOTk5OTk5OTksIE5BLCBJTkNUT1QpKQpgYGAKCmBgYHtyIHBvcHVsYXRpb24tdmFsdWVzfQpnbG9iYWxfZGVtb2dyYXBoaWNzIDwtIGRmX2RlbW9ncmFwaGljcyAlPiUgCiAgc3VtbWFyaXplKGFnZSA9IHdlaWdodGVkLm1lYW4oQUdFID49IDM1LCBBU0VDV1QpLCAKICAgICAgICAgICAgZmVtYWxlID0gd2VpZ2h0ZWQubWVhbihTRVggPT0gMiwgQVNFQ1dUKSwKICAgICAgICAgICAgY29sbGVnZSA9IHdlaWdodGVkLm1lYW4oRURVQyA+PSAxMTEsIEFTRUNXVCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgaW5jb21lID0gd2VpZ2h0ZWQubWVhbihJTkNUT1QgPj0gNTAwMDAsIEFTRUNXVCwgbmEucm0gPSBUUlVFKSkgJT4lIAogIGMoKQoKZ2xvYmFsX3ZvbCA8LSBkZl92b2x1bnRlZXJpbmcgJT4lIAogIHN1bW1hcml6ZSh2b2x1bnRlZXJpbmcgPSB3ZWlnaHRlZC5tZWFuKFZMU1RBVFVTID09IDIsIFZMU1VQUFdULCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBkb25hdGluZyA9IHdlaWdodGVkLm1lYW4oVkxET05BVEUgPT0gMiwgVkxTVVBQV1QsIG5hLnJtID0gVFJVRSkpICU+JSAKICBjKCkKCmdsb2JhbF9zdGF0cyA8LSBjKGdsb2JhbF92b2wsIGdsb2JhbF9kZW1vZ3JhcGhpY3MpCmBgYAoKYGBge3Igc2FtcGxlLXBvcHVsYXRpb24tY2hhcmFjdGVyaXN0aWNzLCBjYWNoZT1UUlVFfQpjb21wYXJlX3NhbXBsZV90b19wb3AgPC0gZnVuY3Rpb24oc2FtcGxlX3ZhbHVlLCBwb3B1bGF0aW9uX3ZhbHVlKSB7CiAgbWNtY19zYW1wbGVzIDwtIHBvcF9wcm9wX3N0YW4oCiAgICB4ID0gdGFibGUoc2FtcGxlX3ZhbHVlKVsxXSwKICAgIG5fdG90YWwgPSBsZW5ndGgoc2FtcGxlX3ZhbHVlKSwKICAgIHBvcF9wcm9wID0gcG9wdWxhdGlvbl92YWx1ZSwKICAgIGNoYWlucyA9IENIQUlOUywgaXRlciA9IElURVIsIHdhcm11cCA9IFdBUk1VUCwgc2VlZCA9IEJBWUVTX1NFRUQpCgogIHRpZGllZCA8LSB0aWR5KG1jbWNfc2FtcGxlcywgY29uZi5pbnQgPSBUUlVFLCBjb25mLmxldmVsID0gMC45NSwgCiAgICAgICAgICAgICAgICAgZXN0aW1hdGUubWV0aG9kID0gIm1lZGlhbiIsIGNvbmYubWV0aG9kID0gIkhQRGludGVydmFsIikgJT4lCiAgICBtdXRhdGUoaW5faHBkaSA9IChwb3B1bGF0aW9uX3ZhbHVlID49IGNvbmYubG93ICYgcG9wdWxhdGlvbl92YWx1ZSA8PSBjb25mLmhpZ2gpKQogIAogIHRoZXRhcyA8LSB1bmxpc3QoZXh0cmFjdChtY21jX3NhbXBsZXMsICJ0aGV0YSIpKQogIHBvcF9xdWFudGlsZV9pbl9zYW1wbGUgPC0gZWNkZih0aGV0YXMpKHBvcHVsYXRpb25fdmFsdWUpCiAgCiAgaW5faHBkaSA8LSAocG9wdWxhdGlvbl92YWx1ZSA+PSB0aWRpZWRbMSxdJGNvbmYubG93ICYgCiAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX3ZhbHVlIDw9IHRpZGllZFsxLF0kY29uZi5oaWdoKQogIAogIHJldHVybihsaXN0KG1jbWNfc2FtcGxlcyA9IG1jbWNfc2FtcGxlcywgdGlkaWVkID0gdGlkaWVkLCB0aGV0YV9pbl9ocGRpID0gaW5faHBkaSwKICAgICAgICAgICAgICBwb3BfcXVhbnRpbGVfaW5fc2FtcGxlID0gcG9wX3F1YW50aWxlX2luX3NhbXBsZSkpCn0KCmNhbGNfc2FtcGxlX3BvcCA8LSB0cmliYmxlKAogIH5WYXJpYWJsZSwgfnNhbXBsZV92YWx1ZSwgfk5hdGlvbmFsLAogICJGZW1hbGUgKCUpXmFeIiwgcmVzdWx0cyRnZW5kZXJfYmluLCBnbG9iYWxfc3RhdHMkZmVtYWxlLAogICJBZ2UgKCUgMzUrKV5hXiIsIHJlc3VsdHMkYWdlX2JpbiwgZ2xvYmFsX3N0YXRzJGFnZSwKICAiSW5jb21lICglICQ1MCwwMDArKV5hXiIsIHJlc3VsdHMkaW5jb21lX2JpbiwgZ2xvYmFsX3N0YXRzJGluY29tZSwKICAiRWR1Y2F0aW9uICglIEJBKyleYV4iLCByZXN1bHRzJGVkdWNhdGlvbl9iaW4sIGdsb2JhbF9zdGF0cyRjb2xsZWdlLAogICJEb25hdGVkIGluIHBhc3QgeWVhciAoJSleYl4iLCByZXN1bHRzJGdpdmVfY2hhcml0eV8yLCBnbG9iYWxfc3RhdHMkZG9uYXRpbmcsCiAgIlZvbHVudGVlcmVkIGluIHBhc3QgeWVhciAoJSleYl4iLCByZXN1bHRzJHZvbHVudGVlciwgZ2xvYmFsX3N0YXRzJHZvbHVudGVlcmluZwopICU+JSAKICBtdXRhdGUoU2FtcGxlID0gc2FtcGxlX3ZhbHVlICU+JSBtYXBfZGJsKH4gcHJvcC50YWJsZSh0YWJsZSguKSlbMV0pLAogICAgICAgICBwcm9wX3Rlc3RfYmF5ZXMgPSBtYXAyKC54ID0gc2FtcGxlX3ZhbHVlLCAueSA9IE5hdGlvbmFsLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZiA9IH4gY29tcGFyZV9zYW1wbGVfdG9fcG9wKC54LCAueSkpKSAKYGBgCgpgYGB7ciB0Ymwtc2FtcGxlLWNoYXJhY3RlcmlzdGljcywgcmVzdWx0cz0iYXNpcyJ9CmZvcm1hdF9ocGRpIDwtIGZ1bmN0aW9uKHBvc3RfbG93ZXIsIHBvc3RfdXBwZXIsIHN0YXIsIGRpZ2l0cyA9IDEpIHsKICBnbHVlKCIoe2xvd2VyfSUsIHt1cHBlcn0lKXtzdGFyfSIsCiAgICAgICBsb3dlciA9IHJvdW5kKDEwMCAqIHBvc3RfbG93ZXIsIGRpZ2l0cyksCiAgICAgICB1cHBlciA9IHJvdW5kKDEwMCAqIHBvc3RfdXBwZXIsIGRpZ2l0cykpCn0KCnRibF9zYW1wbGVfcG9wIDwtIGNhbGNfc2FtcGxlX3BvcCAlPiUgCiAgbXV0YXRlKGluX2hwZGkgPSBwcm9wX3Rlc3RfYmF5ZXMgJT4lIG1hcF9sZ2wofiAuJHRoZXRhX2luX2hwZGkpLAogICAgICAgICBub3RfaHBkaV9zeW1ib2wgPSBpZmVsc2UoaW5faHBkaSwgIiIsICJe4oCgXiIpLAogICAgICAgICBkaWZmc190aWR5ID0gcHJvcF90ZXN0X2JheWVzICU+JSBtYXAofiAuJHRpZGllZFsyLF0pLAogICAgICAgICBkaWZmc19tZWRpYW4gPSBkaWZmc190aWR5ICU+JSBtYXBfZGJsKH4gLiRlc3RpbWF0ZSksCiAgICAgICAgIGRpZmZzX2hwZGlfZmFuY3kgPSBkaWZmc190aWR5ICU+JQogICAgICAgICAgIG1hcDJfY2hyKC54ID0gZGlmZnNfdGlkeSwgLnkgPSBub3RfaHBkaV9zeW1ib2wsIAogICAgICAgICAgICAgICAgICAgIC5mID0gfiBmb3JtYXRfaHBkaSgueCRjb25mLmxvdywgLngkY29uZi5oaWdoLCAueSkpKSAlPiUgCiAgbXV0YXRlX2F0KHZhcnMoTmF0aW9uYWwsIFNhbXBsZSwgZGlmZnNfbWVkaWFuKSwgbGlzdChwZXJjZW50KSkgJT4lIAogIHNlbGVjdChWYXJpYWJsZSwgU2FtcGxlLCBOYXRpb25hbCwgCiAgICAgICAgIGDiiIZ+bWVkaWFufmAgPSBkaWZmc19tZWRpYW4sCiAgICAgICAgIGA5NSUgSFBESWAgPSBkaWZmc19ocGRpX2ZhbmN5KQoKbm90ZV9yb3cgPC0gdGliYmxlKFZhcmlhYmxlID0gYygiKl5hXkFubnVhbCBDUFMsIE1hcmNoIDIwMTcqIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiKl5iXk1vbnRobHkgQ1BTLCBTZXB0ZW1iZXIgMjAxNSoiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIqXuKAoF5OYXRpb25hbCB2YWx1ZSBpcyBvdXRzaWRlIHRoZSBzYW1wbGUgaGlnaGVzdCBwb3N0ZXJpb3IgZGVuc2l0eSBpbnRlcnZhbCAoSFBESSkqIikpCgpiaW5kX3Jvd3ModGJsX3NhbXBsZV9wb3AsIG5vdGVfcm93KSAlPiUgCiAgcGFuZG9jLnRhYmxlLnJldHVybihrZWVwLmxpbmUuYnJlYWtzID0gVFJVRSwgc3R5bGUgPSAibXVsdGlsaW5lIiwganVzdGlmeSA9ICJsY2NjYyIsIAogICAgICAgICAgICAgICAgICAgICAgY2FwdGlvbiA9ICJDaGFyYWN0ZXJpc3RpY3Mgb2YgZXhwZXJpbWVudGFsIHNhbXBsZSB7I3RibDpleHAtc2FtcGxlfSIpICVUPiUgCiAgY2F0KGZpbGUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidGFibGVzIiwgInRibC1leHAtc2FtcGxlLm1kIikpICU+JSAKICBjYXQoKQpgYGAKCiMgUmVzdWx0cyB1c2luZyBpbnRlcmFjdGlvbiB0ZXJtcwoKSW4gb3VyIHByZXJlZ2lzdHJhdGlvbiBwcm90b2NvbCwgd2Ugc2FpZCB3ZSdkIGNhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZXMgaW4gZ3JvdXAgbWVhbnMgdXNpbmcgYSByZWdyZXNzaW9uIG1vZGVsIHdpdGggMy13YXkgaW50ZXJhY3Rpb24gdGVybXMuIFRoaXMgd2FzIG1vc3RseSBmb3IgdGhlIHNha2Ugb2Ygc2ltcGxpY2l0eeKAlHJ1bm5pbmcgb25lIG1vZGVsIGlzIGVhc2llciB0aGFuIHJ1bm5pbmcgbXVsdGlwbGUgaW5kaXZpZHVhbCB0ZXN0c+KAlGJ1dCB0aGUgaW50ZXJwcmV0YXRpb24gaXMgYSBjb21wbGljYXRlZCBtZXNzLiBTbyBpbnN0ZWFkLCB3ZSByYW4gaW5kaXZpZHVhbCBkaWZmZXJlbmNlIGluIG1lYW4gdGVzdHMgZm9yIHRoZSBhY3R1YWwgcGFwZXIuIEZvciB0aGUgc2FrZSBvZiB0cmFuc3BhcmVuY3ksIHRob3VnaCwgaGVyZSBhcmUgdGhlIHJlc3VsdHMgZnJvbSB0aGUgZnVsbHkgaW50ZXJhY3RlZCByZWdyZXNzaW9uIG1vZGVscy4KCiMjIEludGVycHJldGluZyBpbnRlcmFjdGlvbnMgaW4gbW9kZWxzCgpPcmRpbmFyaWx5LCBwZW9wbGUgdXNlIEFOT1ZBIHRvIGFuYWx5emUgMy13YXksIDIgw5cgMiDDlyAyIGZhY3RvcmlhbCBkZXNpZ25zLCBbbGlrZSB0aGlzXShodHRwczovL215cGFnZXMudmFsZG9zdGEuZWR1L213aGF0bGV5LzM2MDAvMngyeDIuaHRtKS4gQSBtb3JlIGZsZXhpYmxlIChbeWV0IGlkZW50aWNhbCFdKGh0dHBzOi8vd3d3LnRoZWFuYWx5c2lzZmFjdG9yLmNvbS93aHktYW5vdmEtYW5kLWxpbmVhci1yZWdyZXNzaW9uLWFyZS10aGUtc2FtZS1hbmFseXNpcy8pKSB3YXkgdG8gZG8gdGhpcyBpcyB0byB1c2UgYSByZWd1bGFyIHJlZ3Jlc3Npb24gbW9kZWwgd2l0aCBpbnRlcmFjdGlvbiB0ZXJtcyBmb3IgZWFjaCBvZiB0aGUgY29uZGl0aW9ucywgbGlrZSBzbyAoaGVyZSB3ZSB1c2UgdGhyZWUsIHNpbmNlIHdlIGNhbiB1c2Ugc2ltcGVyIG1vZGVscyB0byBnZXQgYXZlcmFnZXMgZm9yIHRoZSBsYXJnZXIgdW1icmVsbGEgZ3JvdXBzLCBsaWtlIGp1c3QgY3JhY2tkb3ducyBhbmQgY3JhY2tkb3duICsgaXNzdWUpOgoKLSBNb2RlbCAxOiAKCiAgICAkJAogICAgeSA9IFxiZXRhXzAgKyBcYmV0YV8xIFx0ZXh0e0NyYWNrZG93bn0KICAgICQkCgotIE1vZGVsIDI6IAoKICAgICQkCiAgICBcYmVnaW57YWxpZ25lZH0KICAgIHkgPSYgXGJldGFfMCArIFxiZXRhXzEgXHRleHR7Q3JhY2tkb3dufSArIFxiZXRhXzIgXHRleHR7SXNzdWUgfSArIFxcCiAgICAmIFxiZXRhXzMgXHRleHR7Q3JhY2tkb3dufSBcdGltZXMgXHRleHR7SXNzdWV9CiAgICBcZW5ke2FsaWduZWR9CiAgICAkJAoKLSBNb2RlbCAzOiAKCiAgICAkJAogICAgXGJlZ2lue2FsaWduZWR9CiAgICB5ID0mIFxiZXRhXzAgKyBcYmV0YV8xIFx0ZXh0e0NyYWNrZG93bn0gKyBcYmV0YV8yIFx0ZXh0e0lzc3VlfSArIFxiZXRhXzMgXHRleHR7RnVuZGluZyB9ICsgXFwKICAgICYgXGJldGFfNCBcdGV4dHtDcmFja2Rvd259IFx0aW1lcyBcdGV4dHtJc3N1ZSB9ICsgXFwKICAgICYgXGJldGFfNSBcdGV4dHtDcmFja2Rvd259IFx0aW1lcyBcdGV4dHtGdW5kaW5nIH0gKyBcXAogICAgJiBcYmV0YV82IFx0ZXh0e0lzc3VlfSBcdGltZXMgXHRleHR7RnVuZGluZyB9ICsgXFwKICAgICYgXGJldGFfNyBcdGV4dHtDcmFja2Rvd259IFx0aW1lcyBcdGV4dHtJc3N1ZX0gXHRpbWVzIFx0ZXh0e0Z1bmRpbmd9CiAgICBcZW5ke2FsaWduZWR9CiAgICAkJAoKQWRkaW5nIGRpZmZlcmVudCBjb21iaW5hdGlvbnMgb2YgdGhlIGNvZWZmaWNpZW50cyBwcm92aWRlcyB0aGUgYXZlcmFnZSB2YWx1ZXMgZm9yIGVhY2ggY29tYmluYXRpb24gb2YgZmFjdG9ycywgd2hpY2ggY29ycmVzcG9uZHMgdG8gdGhlIGF2ZXJhZ2UgbGlrZWxpaG9vZCBhbmQgYW1vdW50IGRvbmF0ZWQuIAoKYGBge3IgaW50ZXJhY3Rpb24taW50ZXJwcmV0YXRpb24sIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9ImFzaXMifQptb2RlbDEgPC0gIjEiCm1vZGVsMiA8LSAiMiIKbW9kZWwzIDwtICIzIgoKaW50ZXJwcmV0YXRpb24gPC0gdHJpYmJsZSgKICB+TW9kZWwsIH5gQ29lZmZpY2llbnRzIHRvIGFkZCB0b2dldGhlcmAsCiAgbW9kZWwzLCAiSW50ZXJjZXB0IiwKICBtb2RlbDMsICJJbnRlcmNlcHQgKyBGdW5kaW5nIiwKICBtb2RlbDIsICJJbnRlcmNlcHQiLAogIG1vZGVsMywgIkludGVyY2VwdCArIElzc3VlIiwKICBtb2RlbDMsICJJbnRlcmNlcHQgKyBJc3N1ZSArIEZ1bmRpbmcgKyAoSXNzdWUgw5cgRnVuZGluZykiLAogIG1vZGVsMiwgIkludGVyY2VwdCArIElzc3VlIiwKICBtb2RlbDEsICJJbnRlcmNlcHQiLAogIG1vZGVsMywgIkludGVyY2VwdCArIENyYWNrZG93biIsCiAgbW9kZWwzLCAiSW50ZXJjZXB0ICsgQ3JhY2tkb3duICsgRnVuZGluZyArIChDcmFja2Rvd24gw5cgRnVuZGluZykiLAogIG1vZGVsMiwgIkludGVyY2VwdCArIENyYWNrZG93biIsCiAgbW9kZWwzLCAiSW50ZXJjZXB0ICsgQ3JhY2tkb3duICsgSXNzdWUgKyAoQ3JhY2tkb3duIMOXIElzc3VlKSIsCiAgbW9kZWwzLCAiSW50ZXJjZXB0ICsgQ3JhY2tkb3duICsgSXNzdWUgKyBGdW5kaW5nICsgKENyYWNrZG93biDDlyBJc3N1ZSkgKyAoQ3JhY2tkb3duIMOXIEZ1bmRpbmcpICsgKElzc3VlIMOXIEZ1bmRpbmcpICsgKENyYWNrZG93biDDlyBJc3N1ZSDDlyBGdW5kaW5nKSIsCiAgbW9kZWwyLCAiSW50ZXJjZXB0ICsgQ3JhY2tkb3duICsgSXNzdWUgKyAoQ3JhY2tkb3duIMOXIElzc3VlKSIsCiAgbW9kZWwxLCAiSW50ZXJjZXB0ICsgQ3JhY2tkb3duIgopCgpjb25kaXRpb25zX3N1bW1hcnkgPC0gYmluZF9yb3dzKGdyb3VwX2J5KHJlc3VsdHMsIGNyYWNrZG93biwgaXNzdWUsIGZ1bmRpbmcpICU+JSBuZXN0KCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkocmVzdWx0cywgY3JhY2tkb3duLCBpc3N1ZSkgJT4lIG5lc3QoKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShyZXN1bHRzLCBjcmFja2Rvd24pICU+JSBuZXN0KCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyAlPiUgbmVzdChkYXRhID0gZXZlcnl0aGluZygpKSkgJT4lIAogIGFycmFuZ2UoY3JhY2tkb3duLCBpc3N1ZSwgZnVuZGluZykgJT4lIAogIHNlbGVjdCgtZGF0YSkgJT4lIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKGZ1bmRpbmcgPSBpZmVsc2UoaXMubmEoZnVuZGluZykgJiAhaXMubmEoaXNzdWUpICwgIipUb3RhbCoiLCBhcy5jaGFyYWN0ZXIoZnVuZGluZykpLAogICAgICAgICBpc3N1ZSA9IGlmZWxzZShpcy5uYShpc3N1ZSkgJiAhaXMubmEoY3JhY2tkb3duKSwgIipUb3RhbCoiLCBhcy5jaGFyYWN0ZXIoaXNzdWUpKSwKICAgICAgICAgY3JhY2tkb3duID0gaWZlbHNlKGlzLm5hKGNyYWNrZG93biksICIqVG90YWwqIiwgYXMuY2hhcmFjdGVyKGNyYWNrZG93bikpKSAlPiUgCiAgZ3JvdXBfYnkoY3JhY2tkb3duKSAlPiUgCiAgbXV0YXRlKGlzc3VlID0gcmVwbGFjZShpc3N1ZSwgZHVwbGljYXRlZChpc3N1ZSksIE5BKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgbXV0YXRlKGNyYWNrZG93biA9IHJlcGxhY2UoY3JhY2tkb3duLCBkdXBsaWNhdGVkKGNyYWNrZG93biksIE5BKSkgJT4lIAogIHJlbmFtZShgQ3JhY2tkb3duIGNvbmRpdGlvbmAgPSBjcmFja2Rvd24sIGBJc3N1ZSBjb25kaXRpb25gID0gaXNzdWUsCiAgICAgICAgIGBGdW5kaW5nIGNvbmRpdGlvbmAgPSBmdW5kaW5nKQoKY29uZGl0aW9uc19zdW1tYXJ5ICU+JSAKICBzbGljZSgtbigpKSAlPiUgCiAgYmluZF9jb2xzKGludGVycHJldGF0aW9uKSAlPiUgCiAgcGFuZG9jLnRhYmxlKCkKYGBgCgojIyBBbW91bnQgZG9uYXRlZAoKYGBge3IgYnVpbGQtbW9kZWxzLWFtb3VudCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0iaGlkZSIsIGNhY2hlPVRSVUV9CiMgQmFzaWMgaW50ZXJhY3Rpb24gbW9kZWxzCm1fYW1vdW50X2MgPC0gc3Rhbl9nbG0oYW1vdW50X2RvbmF0ZSB+IGNyYWNrZG93biwKICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gcmVzdWx0cywgZmFtaWx5ID0gZ2F1c3NpYW4oKSwKICAgICAgICAgICAgICAgICAgICAgICBwcmlvciA9IGNhdWNoeShsb2NhdGlvbiA9IDAsIHNjYWxlID0gMi41KSwKICAgICAgICAgICAgICAgICAgICAgICBwcmlvcl9pbnRlcmNlcHQgPSBjYXVjaHkobG9jYXRpb24gPSAwLCBzY2FsZSA9IDEwKSwKICAgICAgICAgICAgICAgICAgICAgICBjaGFpbnMgPSBDSEFJTlMsIGl0ZXIgPSBJVEVSLCB3YXJtdXAgPSBXQVJNVVAsIHNlZWQgPSBCQVlFU19TRUVEKQoKbV9hbW91bnRfY2kgPC0gdXBkYXRlKG1fYW1vdW50X2MsIC4gfiAuICsgaXNzdWUgKyBjcmFja2Rvd24gKiBpc3N1ZSkKbV9hbW91bnRfY2lmIDwtIHVwZGF0ZShtX2Ftb3VudF9jLCAuIH4gLiArIAogICAgICAgICAgICAgICAgICAgICAgICAgaXNzdWUgKyBmdW5kaW5nICsgY3JhY2tkb3duICogaXNzdWUgKyBjcmFja2Rvd24gKiBmdW5kaW5nICsgCiAgICAgICAgICAgICAgICAgICAgICAgICBpc3N1ZSAqIGZ1bmRpbmcgKyBjcmFja2Rvd24gKiBpc3N1ZSAqIGZ1bmRpbmcpCiMgTW9kZWxzIHdpdGgganVzdCBpc3N1ZSBhbmQganVzdCBmdW5kaW5nCm1fYW1vdW50X2kgPC0gdXBkYXRlKG1fYW1vdW50X2MsIC4gfiBpc3N1ZSkKbV9hbW91bnRfZiA8LSB1cGRhdGUobV9hbW91bnRfYywgLiB+IGZ1bmRpbmcpCmBgYAoKYGBge3IgdGJsLW1vZGVscy1hbW91bnQsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9ImFzaXMifQojIEdldCBzdWJzZXQgb2YgY29lZmZpY2llbnRzCmNvZWZzX3RvX2luY2x1ZGUgPC0gbGlzdChtX2Ftb3VudF9jLCBtX2Ftb3VudF9jaSwgbV9hbW91bnRfY2lmKSAlPiUgCiAgbWFwKH4gdGlkeSguKSkgJT4lIGJpbmRfcm93cygpICU+JSBkaXN0aW5jdCh0ZXJtKSAlPiUgcHVsbCh0ZXJtKQoKaHV4cmVnKG1fYW1vdW50X2MsIG1fYW1vdW50X2NpLCBtX2Ftb3VudF9jaWYsIAogICAgICAgY29lZnMgPSBjb2Vmc190b19pbmNsdWRlLAogICAgICAgc3RhdGlzdGljcyA9IGMoT2JzZXJ2YXRpb25zID0gIm5vYnMiLAogICAgICAgICAgICAgICAgICAgICAgIGBQb3N0ZXJpb3Igc2FtcGxlIHNpemVgID0gInBzcyIsCiAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAic2lnbWEiKSwKICAgICAgIHN0YXJzID0gTlVMTCkgJVQ+JSAKICBwcmludF9odXgoKSAlPiUgCiAgdG9fbWQobWF4X3dpZHRoID0gMTAwKSAlPiUgCiAgY2F0KGZpbGUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidGFibGVzIiwgInRibC1pbnRlcmFjdGlvbnMtYW1vdW50Lm1kIikpCmBgYAoKIyMgTGlrZWxpaG9vZCBvZiBkb25hdGlvbgoKYGBge3IgYnVpbGQtbW9kZWxzLWxpa2VseSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgcmV1c2x0cz0iaGlkZSIsIGNhY2hlPVRSVUV9CiMgQmFzaWMgaW50ZXJhY3Rpb24gbW9kZWxzCiMgV2Vha2x5IGluZm9ybWF0aXZlIHN0dWRlbnQgdCBwcmlvcnMsIHNpbmNlIHRoZXNlIGNvZWZmaWNpZW50cyBhcmUgbG9nLW9kZHMKIyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3N0YW4tZGV2L3N0YW4vd2lraS9Qcmlvci1DaG9pY2UtUmVjb21tZW5kYXRpb25zI3ByaW9yLWZvci10aGUtcmVncmVzc2lvbi1jb2VmZmljaWVudHMtaW4tbG9naXN0aWMtcmVncmVzc2lvbi1ub24tc3BhcnNlLWNhc2UgYW5kIGh0dHBzOi8vYXJ4aXYub3JnL2Ficy8xNTA3LjA3MTcwCm1fbGlrZWx5X2MgPC0gc3Rhbl9nbG0oZG9uYXRlX2xpa2VseV9iaW4gfiBjcmFja2Rvd24sCiAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHJlc3VsdHMsIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwKICAgICAgICAgICAgICAgICAgICAgICBwcmlvciA9IHN0dWRlbnRfdCgzLCAwLCAyLjUpLAogICAgICAgICAgICAgICAgICAgICAgIHByaW9yX2ludGVyY2VwdCA9IHN0dWRlbnRfdCgzLCAwLCAxMCksCiAgICAgICAgICAgICAgICAgICAgICAgY2hhaW5zID0gQ0hBSU5TLCBpdGVyID0gSVRFUiwgd2FybXVwID0gV0FSTVVQLCBzZWVkID0gQkFZRVNfU0VFRCkKCm1fbGlrZWx5X2NpIDwtIHVwZGF0ZShtX2xpa2VseV9jLCAuIH4gLiArIGlzc3VlICsgY3JhY2tkb3duICogaXNzdWUpCgptX2xpa2VseV9jaWYgPC0gdXBkYXRlKG1fbGlrZWx5X2MsIC4gfiAuICsgCiAgICAgICAgICAgICAgICAgICAgICAgICBpc3N1ZSArIGZ1bmRpbmcgKyBjcmFja2Rvd24gKiBpc3N1ZSArIGNyYWNrZG93biAqIGZ1bmRpbmcgKyAKICAgICAgICAgICAgICAgICAgICAgICAgIGlzc3VlICogZnVuZGluZyArIGNyYWNrZG93biAqIGlzc3VlICogZnVuZGluZykKCiMgTW9kZWxzIHdpdGgganVzdCBpc3N1ZSBhbmQganVzdCBmdW5kaW5nCm1fbGlrZWx5X2kgPC0gdXBkYXRlKG1fbGlrZWx5X2MsIC4gfiBpc3N1ZSkKbV9saWtlbHlfZiA8LSB1cGRhdGUobV9saWtlbHlfYywgLiB+IGZ1bmRpbmcpCmBgYAoKYGBge3IgdGJsLW1vZGVscy1saWtlbHksIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9ImFzaXMifQojIEdldCBzdWJzZXQgb2YgY29lZmZpY2llbnRzCmNvZWZzX3RvX2luY2x1ZGUgPC0gbGlzdChtX2xpa2VseV9jLCBtX2xpa2VseV9jaSwgbV9saWtlbHlfY2lmKSAlPiUgCiAgbWFwKH4gdGlkeSguKSkgJT4lIGJpbmRfcm93cygpICU+JSBkaXN0aW5jdCh0ZXJtKSAlPiUgcHVsbCh0ZXJtKQoKaHV4cmVnKG1fbGlrZWx5X2MsIG1fbGlrZWx5X2NpLCBtX2xpa2VseV9jaWYsIAogICAgICAgY29lZnMgPSBjb2Vmc190b19pbmNsdWRlLAogICAgICAgc3RhdGlzdGljcyA9IGMoT2JzZXJ2YXRpb25zID0gIm5vYnMiLAogICAgICAgICAgICAgICAgICAgICAgIGBQb3N0ZXJpb3Igc2FtcGxlIHNpemVgID0gInBzcyIsCiAgICAgICAgICAgICAgICAgICAgICAgU2lnbWEgPSAic2lnbWEiKSwKICAgICAgIHN0YXJzID0gTlVMTCkgJVQ+JSAKICBwcmludF9odXgoKSAlPiUgCiAgdG9fbWQobWF4X3dpZHRoID0gMTAwKSAlPiUgCiAgY2F0KGZpbGUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidGFibGVzIiwgInRibC1pbnRlcmFjdGlvbnMtbGlrZWxpaG9vZC5tZCIpKQpgYGAKCgojIENvbGxhcHNpbmcgbGlrZWxpaG9vZCB2YXJpYWJsZQoKVG8gc2ltcGxpZnkgb3VyIGFuYWx5c2lzLCB3ZSBjb2xsYXBzZSBvdXIgbGlrZWxpaG9vZCBzY2FsZSBmcm9tIGEgMS01IExpa2VydCBzY2FsZSB0byBhIGJpbmFyeSB2YXJpYWJsZToKCmBgYHtyIHNob3ctY29sbGFwc2VkLWxldmVscywgcmVzdWx0cz0iYXNpcyJ9CmNvbGxhcHNlZF9saWtlbGlob29kIDwtIHRyaWJibGUoCiAgfmBPcmlnaW5hbCBhbnN3ZXJgLCB+YENvbGxhcHNlZCBhbnN3ZXJgLAogICJFeHRyZW1lbHkgbGlrZWx5IiwgIkxpa2VseSIsCiAgIlNvbWV3aGF0IGxpa2VseSIsICJMaWtlbHkiLAogICJOZWl0aGVyIGxpa2VseSBub3IgdW5saWtlbHkiLCAiVW5saWtlbHkiLAogICJTb21ld2hhdCB1bmxpa2VseSIsICJVbmxpa2VseSIsCiAgIkV4dHJlbWVseSB1bmxpa2VseSIsICJVbmxpa2VseSIKKQogICAgCmNvbGxhcHNlZF9saWtlbGlob29kICU+JSAKICBwYW5kb2MudGFibGUucmV0dXJuKGp1c3RpZnkgPSAibGwiKSAlVD4lCiAgY2F0KGZpbGUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAidGFibGVzIiwgInRibC1jb2xsYXBzZWQtbGlrZWxpaG9vZC5tZCIpKSAlPiUgCiAgY2F0KCkKYGBgCgpUbyBjaGVjayB0aGF0IHRoZSByZXN1bHRzIGFyZSBpbnRlcm5hbGx5IGNvbnNpc3RlbnQgd2hlbiBjb2xsYXBzZWQsIHdlIHJhbiBhbiBvcmRlcmVkIHByb2JpdCBtb2RlbCAKKHVzaW5nIFN0YW4pIHRvIHNlZSBpZiB0aGUgY3V0cG9pbnRzIGZvbGxvdyB0aGUgZGlzdHJpYnV0aW9uIG9mIGFuc3dlcnMsIGFuZCB0aGV5IGRvLiAiU29tZXdoYXQgbGlrZWx5IiBhbmQgYWJvdmUgaGFzIGEgY3V0cG9pbnQgb2YgPiAwLjE4LCBtZWFuaW5nIHRoYXQgdGhlIGxpa2VsaWhvb2QgaXMgcG9zaXRpdmUgb24gYXZlcmFnZSBmb3IgYm90aCAiU29tZXdoYXQgbGlrZWx5IiBhbmQgIkV4dHJlbWVseSBsaWtlbHkuIgoKYGBge3IgY29sbGFwc2VkLXByb2JpdCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0iaGlkZSIsIGNhY2hlPVRSVUV9CmNvbGxhcHNlZF9vcHJvYml0IDwtIHN0YW5fcG9scihkb25hdGVfbGlrZWx5IH4gY3JhY2tkb3duLCBkYXRhID0gcmVzdWx0cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yID0gUjIoMC4yNSwgd2hhdCA9ICJtZWFuIiksIHByaW9yX2NvdW50cyA9IGRpcmljaGxldCgxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJwcm9iaXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hhaW5zID0gQ0hBSU5TLCBpdGVyID0gSVRFUiwgd2FybXVwID0gV0FSTVVQLCBzZWVkID0gQkFZRVNfU0VFRCkKYGBgCgpgYGB7ciBzaG93LWNvbGxhcHNlZC1wcm9iaXQsIHJlc3VsdHM9ImFzaXMifQpodXhyZWcoY29sbGFwc2VkX29wcm9iaXQsCiAgICAgICBjb2VmcyA9IGMoIkNyYWNrZG93biIgPSAiY3JhY2tkb3duQ3JhY2tkb3duIiwKICAgICAgICAgICAgICAgICAiQ3V0cG9pbnQ6IEV4dHJlbWVseSB1bmxpa2VseXxTb21ld2hhdCB1bmxpa2VseSIgPSAKICAgICAgICAgICAgICAgICAgICJFeHRyZW1lbHkgdW5saWtlbHl8U29tZXdoYXQgdW5saWtlbHkiLAogICAgICAgICAgICAgICAgICJDdXRwb2ludDogU29tZXdoYXQgdW5saWtlbHl8TmVpdGhlciBsaWtlbHkgbm9yIHVubGlrZWx5IiA9IAogICAgICAgICAgICAgICAgICAgIlNvbWV3aGF0IHVubGlrZWx5fE5laXRoZXIgbGlrZWx5IG5vciB1bmxpa2VseSIsCiAgICAgICAgICAgICAgICAgIkN1dHBvaW50OiBOZWl0aGVyIGxpa2VseSBub3IgdW5saWtlbHl8U29tZXdoYXQgbGlrZWx5IiA9IAogICAgICAgICAgICAgICAgICAgIk5laXRoZXIgbGlrZWx5IG5vciB1bmxpa2VseXxTb21ld2hhdCBsaWtlbHkiLAogICAgICAgICAgICAgICAgICJDdXRwb2ludDogU29tZXdoYXQgbGlrZWx5fEV4dHJlbWVseSBsaWtlbHkiID0gCiAgICAgICAgICAgICAgICAgICAiU29tZXdoYXQgbGlrZWx5fEV4dHJlbWVseSBsaWtlbHkiKSwKICAgICAgIHN0YXRpc3RpY3MgPSBjKE9ic2VydmF0aW9ucyA9ICJub2JzIiwKICAgICAgICAgICAgICAgICAgICAgICBgUG9zdGVyaW9yIHNhbXBsZSBzaXplYCA9ICJwc3MiKSwKICAgICAgIHN0YXJzID0gTlVMTCkgJT4lCiAgc2V0X2FsaWduKGV2ZXJ5d2hlcmUsIDEsICJsZWZ0IikgJT4lIAogIHNldF9hbGlnbihldmVyeXdoZXJlLCAyLCAiY2VudGVyIikgJT4lIAogIHNldF9wb3NpdGlvbigibGVmdCIpICU+JSAKICBzZXRfY2FwdGlvbigiT3JkZXJlZCBwcm9iaXQgcmVncmVzc2lvbiB3aXRoIGRvbmF0aW9uIGxpa2VsaWhvb2QgYXMgb3V0Y29tZSB2YXJpYWJsZSB7I3RibDpwcm9iaXQtbGlrZWxpaG9vZH0iKSAlVD4lIAogIHByaW50X2h1eCgpICU+JSAKICB0b19tZChtYXhfd2lkdGggPSAxNDApICU+JSAKICBjYXQoZmlsZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJ0YWJsZXMiLCAidGJsLXByb2JpdC1saWtlbGlob29kLm1kIikpCmBgYAoKCiMgTWlzY2VsbGFuZW91cyBzdXJ2ZXkgZGV0YWlscwoKIyMgQXZlcmFnZSB0aW1lIHRvIGNvbXBsZXRlIHN1cnZleQoKYGBge3IgYXZnLXRpbWUsIHJlc3VsdHM9ImFzaXMifQp0aW1lX3N1bW1hcnkgPC0gcmVzdWx0cyAlPiUgCiAgc3VtbWFyaXplX2F0KHZhcnMoZHVyYXRpb24pLCBsaXN0KE1pbmltdW0gPSBtaW4sIE1heGltdW0gPSBtYXgsIE1lYW4gPSBtZWFuLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFN0YW5kYXJkIGRldmlhdGlvbmAgPSBzZCwgTWVkaWFuID0gbWVkaWFuKSkgJT4lIAogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKCksIG5hbWVzX3RvID0gIlN0YXRpc3RpYyIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JSAKICBtdXRhdGUoTWludXRlcyA9IGZtdF9zZWNvbmRzKHZhbHVlKSkgJT4lIAogIHNlbGVjdCgtdmFsdWUpIAoKcGFuZG9jLnRhYmxlKHRpbWVfc3VtbWFyeSkKYGBgCgpgYGB7ciBhdmctdGltZS1wbG90LCBmaWcuaGVpZ2h0PTIuNSwgZmlnLndpZHRoPTQsIG91dC53aWR0aD0iODAlIn0Kc3VtbWFyeV9zdGF0cyA8LSB0YWJsZUdyb2IodGltZV9zdW1tYXJ5LCByb3dzID0gTlVMTCwgdGhlbWUgPSB0aGVtZV9uZ29zX3RhYmxlKSAlPiUgCiAgZ3RhYmxlOjpndGFibGVfYWRkX2dyb2IoLiwgZ3JvYnMgPSByZWN0R3JvYihncCA9IGdwYXIoZmlsbCA9IE5BLCBsd2QgPSAxKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgdCA9IDEsIGIgPSBucm93KC4pLCBsID0gMSwgciA9IG5jb2woLikpCgpwbG90X2F2Z190aW1lIDwtIGdncGxvdChyZXN1bHRzLCBhZXMoeCA9IGR1cmF0aW9uKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSA1MCwgZmlsbCA9IG5nb19jb2xzKCJibHVlIikpICsKICBzY2FsZV94X3RpbWUobGFiZWxzID0gZm10X3NlY29uZHMpICsKICBhbm5vdGF0aW9uX2N1c3RvbShzdW1tYXJ5X3N0YXRzLCB4bWluID0gNzAwLCB4bWF4ID0gOTAwLCB5bWluID0gMzAsIHltYXggPSA2MCkgKwogIGxhYnMoeCA9ICJNaW51dGVzIHNwZW50IG9uIGV4cGVyaW1lbnQiLCB5ID0gIkNvdW50IikgKwogIHRoZW1lX25nb3MoYmFzZV9zaXplID0gOS41KSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkKCnBsb3RfYXZnX3RpbWUgJVQ+JSAKICBwcmludCgpICVUPiUKICBnZ3NhdmUoLiwgZmlsZW5hbWUgPSBoZXJlKCJhbmFseXNpcyIsICJvdXRwdXQiLCAiZmlndXJlcyIsICJhdmctdGltZS5wZGYiKSwKICAgICAgICAgd2lkdGggPSA0LCBoZWlnaHQgPSAyLjI1LCB1bml0cyA9ICJpbiIsIGRldmljZSA9IGNhaXJvX3BkZikgJT4lIAogIGdnc2F2ZSguLCBmaWxlbmFtZSA9IGhlcmUoImFuYWx5c2lzIiwgIm91dHB1dCIsICJmaWd1cmVzIiwgImF2Zy10aW1lLnBuZyIpLAogICAgICAgICB3aWR0aCA9IDQsIGhlaWdodCA9IDIuMjUsIHVuaXRzID0gImluIiwgdHlwZSA9ICJjYWlybyIsIGRwaSA9IDMwMCkKYGBgCgpcCgojIE9yaWdpbmFsIGNvbXB1dGluZyBlbnZpcm9ubWVudAoKPGJ1dHRvbiBkYXRhLXRvZ2dsZT0iY29sbGFwc2UiIGRhdGEtdGFyZ2V0PSIjc2Vzc2lvbmluZm8iIGNsYXNzPSJidG4gYnRuLXByaW1hcnkgYnRuLW1kIGJ0bi1pbmZvIj5IZXJlJ3Mgd2hhdCB3ZSB1c2VkIHRoZSBsYXN0IHRpbWUgd2UgYnVpbHQgdGhpcyBwYWdlPC9idXR0b24+Cgo8ZGl2IGlkPSJzZXNzaW9uaW5mbyIgY2xhc3M9ImNvbGxhcHNlIj4KCmBgYHtyIHNob3ctc2Vzc2lvbi1pbmZvLCBlY2hvPVRSVUUsIHdpZHRoPTEwMH0Kd3JpdGVMaW5lcyhyZWFkTGluZXMoZmlsZS5wYXRoKFN5cy5nZXRlbnYoIkhPTUUiKSwgIi5SL01ha2V2YXJzIikpKQoKZGV2dG9vbHM6OnNlc3Npb25faW5mbygpCmBgYAoKPC9kaXY+IAo=