suppressPackageStartupMessages(require(plotly))
suppressPackageStartupMessages(require(tidyverse))
suppressPackageStartupMessages(require(cowplot))
suppressPackageStartupMessages(require(ggtext))

Background

Emily found out that a number of constructs included in the last batch of experiments had nonsynonymous mutations. To ensure that the results were not due to mutations, she remade those constructs using higher fidelity enzymes.

Goal

  • Quality control for the new batch of repeat experiments. Determine if there is any well position effect and how well the values agree across multiple days of experiments.
  • Once QC is done, merge the new, repeat dataset with the old one, replacing the results for the old constructs with mutations.
  • Implement the idea of separating the basal activity and Pho2-boost traits.

Data

Read the previous merged data

datPre <- read_tsv("../output/20220614-mar22-batch-bg-sub-data.tsv", col_types = "cccfdddddll") %>% 
  mutate(host = ordered(host))

list.mutations <- as.character(c(215, 209, 211, 210, 217, 218, 220, 221, 223, 224, 222, 227, 230, 229, 231, 233, 240, 241, 250:255, 257, 258))

exptPre <- datPre %>% 
  group_by(date, plasmid, host) %>% 
  summarize(n = n(), n_filter = sum(!low_event_count), .groups = "drop") %>% 
  mutate(flag = ifelse(plasmid %in% list.mutations, "mutation", ""))

Read the new batches of data

raw <- list(
  "05/12/22" = read_tsv("../data/20220512-EO-repeat-batch-1/20220512-gated-median-out.txt", show_col_types = FALSE),
  "05/17/22" = read_tsv("../data/20220517-EO-repeat-batch-2/20220517-gated-median-out.txt", show_col_types = FALSE),
  "05/19/22" = read_tsv("../data/20220519-EO-repeat-batch-3/20220519-gated-median-out.txt", show_col_types = FALSE),
  "05/31/22" = read_tsv("../data/20220531-EO-repeat-batch-4/20220531-gated-median-out.txt", show_col_types = FALSE),
  "06/02/22" = read_tsv("../data/20220602-EO-repeat-batch-5/20220602-gated-median-out.txt", show_col_types = FALSE)
)
dat <- bind_rows(raw, .id = "date") %>% 
  #separate(col = well, sep = 1, into = c("row", "col")) %>% 
  separate(col = sample, sep = "-", into = c("plasmid", "host", "rep")) %>% 
  mutate(plasmid = na_if(plasmid, "NA"))

QC

1. Number of events per sample

dat %>% ggplot(aes(x = n_induction/1000)) + geom_histogram(bins = 30, fill = "forestgreen") + 
  xlab("# events x 1000") +
  facet_grid(host~date, scales = "free_y") + theme_bw(base_size = 14) #+ panel_border()

Majority of the experimental wells (not blank) have > 10000 events, with the exception of a few samples

dat %>% filter(host != "blank", n_induction < 10000)

Nearly all samples with a low event count were in the 555 background. Emily repeated many of them. Will remove all samples with lower than 7,000 events in the final gated population from further analysis.

Flag samples that have a low event count, contain mutations or show multiple populations.

event.th <- 7000

dat <- dat %>% 
  mutate(
    low_event_count = n_induction < event.th,
    # Emily labeled the old plasmids with mutations with an "o" in the flow sample name column
    mutation = ifelse(grepl("o$", name), TRUE, FALSE)
  ) %>% 
  filter(host != "blank")

2. Background subtraction

Check the background fluorescence levels across different days.

dat %>% filter(host == "156") %>% 
  mutate(date = gsub("/22", "", date)) %>% 
  pivot_longer(BL1.H:nRFP, names_to = "parameter", values_to = "intensity") %>% 
  mutate(parameter = ordered(parameter, levels = c("BL1.H", "YL2.H", "nGFP", "nRFP"))) %>% 
  ggplot(aes(x = date, y = intensity)) + geom_point(aes(shape = well)) +
  stat_summary(fun.data = "mean_se", geom = "pointrange", color = "red", position = position_nudge(x = 0.1)) +
  facet_wrap(~parameter, scale = "free_y") +
  theme_bw(base_size = 14)

06/02 run had smaller FSC values (~ cell volume) compared with the other days, while the background fluorescence doesn’t appear to be a lot higher, resulting in higher normalized values.

Subtract the background

bg <- dat %>% 
  filter(host == "156") %>% 
  group_by(date) %>% 
  summarize(across(FSC.H:nRFP, ~ round(mean(.x),1))) %>% 
  column_to_rownames(var = "date")

dat1 <- dat %>% 
  filter(host != "blank") %>% 
  select(date:host, FSC.H:nRFP, low_event_count:mutation) %>%
  mutate(
    BL1.H = BL1.H - bg[date, "BL1.H"],
    YL2.H = YL2.H - bg[date, "YL2.H"],
    nGFP = nGFP - bg[date, "nGFP"],
    nRFP = nRFP - bg[date, "nRFP"],
  )

Double check that the subtraction worked correctly

dat1 %>% filter(host == "156") %>% 
  pivot_longer(BL1.H:nRFP, names_to = "parameter", values_to = "intensity") %>% 
  mutate(
    parameter = ordered(parameter, levels = c("BL1.H", "YL2.H", "nGFP", "nRFP")),
    date = gsub("\\/22$", "", date)
  ) %>% 
  ggplot(aes(x = date, y = intensity)) + geom_point(aes(shape = well)) +
  stat_summary(fun.data = "mean_se", geom = "pointrange", color = "red", position = position_nudge(x = 0.1)) +
  facet_wrap(~parameter, scale = "free_y") +
  theme_bw(base_size = 14)


# remove the yH156 samples
dat1 <- dat1 %>% 
  filter(host != "156") %>%
  mutate(host = ordered(host, levels = c("555", "373"), labels = c("PHO2", "pho2∆")))

3. Well position

Rationale

In my plate design, I placed a positive control strain (CgPho4-mNeon in PHO2 background) in the control columns (1, 5, 9) on every other row (A, C, E, G). The rationale for this is to use it to identify any well position effect on the fluorescence readings. In this round of repeat experiments, Emily followed this design and put pH188-yH323 in these wells. Now we can properly assess the well position effect.

For this analysis, we will combine and compare the May/Jun batch with the Mar batch

datM <- bind_rows(datPre, dat1)
datM %>% 
  filter(plasmid == "188", host == "PHO2") %>% 
  separate(well, into = c("row", "col"), sep = 1) %>% 
  pivot_longer(BL1.H:YL2.H, names_to = "parameter", values_to = "intensity") %>% 
  ggplot(aes(x = col, y = intensity, group = date)) + 
  geom_point(aes(color = date), size = 1) + 
  #geom_line(aes(color = date), size = 0.4) +
  stat_summary(aes(color = date), geom = "line", fun = mean) +
  scale_color_brewer(type = "qual", palette = 2) +
  xlab("Column") +
  facet_grid(parameter~row, scales = "free_y") +
  theme_bw(base_size = 14)

  • no obvious trend between the rows or columns
  • a clear correlation between YL2.H and BL1.H.

Same plot for normalized fluorescence

datM %>% 
  filter(plasmid == "188", host == "PHO2") %>% 
  separate(well, into = c("row", "col"), sep = 1) %>% 
  pivot_longer(c(nGFP, nRFP), names_to = "parameter", values_to = "intensity") %>% 
  ggplot(aes(x = col, y = intensity, group = date)) + 
  geom_point(aes(color = date), size = 1) + 
  #geom_line(aes(color = date), size = 0.4) +
  stat_summary(aes(color = date), geom = "line", fun = mean) +
  scale_color_brewer(type = "qual", palette = 2) +
  xlab("Column") +
  facet_grid(parameter~row, scales = "free_y") +
  theme_bw(base_size = 14)

  • What we care about is the ratio between Pho4-mNeon and PHO5pr-mCherry
datM %>% 
  filter(plasmid == "188", host == "PHO2") %>% 
  separate(well, into = c("row", "col"), sep = 1) %>% 
  ggplot(aes(x = BL1.H, y = YL2.H)) + 
  geom_point(aes(color = date, shape = row), size = 3) + 
  stat_smooth(method = "lm", se = FALSE, color = "gray50", size = 0.5) +
  scale_color_brewer(type = "qual", palette = 2) +
  #scale_color_viridis_d() +
  #scale_shape_manual(values = c(15:17, 23, 25)) +
  theme_bw(base_size = 14)
`geom_smooth()` using formula 'y ~ x'

  • There is variation in BL1.H and correspondingly in YL2.H, but the ratio between the two are very consistent

4. Run effect

How does the same control strain behave in different runs (represented as date variable here)? Is there a strong run effect?

Let’s check both ScPho4 (pH194) and CgPho4 (pH188) to see if their behaviors are consistent across days and between this and the last (03/30) batch.

datM %>% 
  filter(plasmid %in% c("188", "194")) %>% 
  mutate(
    date = gsub("/22$", "", date),
    `YL2.H / BL1.H` = YL2.H / BL1.H,
    Pho4 = factor(plasmid, levels = c("194", "188"), labels = c("ScPho4", "CgPho4"))
  ) %>% 
  separate(well, into = c("row", "col"), sep = 1) %>% 
  ggplot(aes(x = date, y = `YL2.H / BL1.H`, group = host)) + 
  geom_point(aes(color = host), position = position_jitter(0.1), alpha = 0.8, size = 1) + 
  scale_color_viridis_d(begin = 0.2, end = 0.6) +
  stat_summary(fun.data = "mean_se", geom = "pointrange", shape = 16, color = "red") +
  ylim(0, 30) + facet_grid(Pho4~.) + theme_bw(base_size = 14)

while the characteristic behaviors of ScPho4 and CgPho4 are consistent across runs, there are also clear variability in the RFP/GFP ratios between plates for the same genotype.

Next we examine the underlying background-subtracted fluorescence values for pH188 and pH194 in the yH555 background, which are present on each plate.

datM %>% 
  filter(plasmid %in% c("188", "194"), host == "PHO2") %>% 
  mutate(
    date = gsub("/22$", "", date),
    plasmid = factor(plasmid, levels = c("188", "194"), labels = c("CgPho4", "ScPho4"))
  ) %>% 
  pivot_longer(BL1.H:YL2.H, names_to = "parameter", values_to = "intensity") %>% 
  ggplot(aes(x = date, y = intensity, group = plasmid)) + 
  geom_point(aes(color = plasmid), alpha = 0.7, size = 1,
             position = position_jitterdodge(jitter.width = 0.1, dodge.width = 0.7)) + 
  scale_color_manual(values = c("ScPho4" = "blue3", "CgPho4" = "forestgreen")) +
  stat_summary(aes(color = plasmid), fun.data = "mean_se", geom = "crossbar", width = 0.4,
               position = position_dodge(0.7)) +
  facet_grid(parameter~., scale = "free_y") +
  expand_limits(y = 0) +
  theme_bw(base_size = 14) + labs(subtitle = "in PHO2 background")# +

  #theme(plot.subtitle = element_markdown())

CgPho4 and ScPho4 values track each other – on days (runs) where one is high, the other one also tends to be high. On the 05/31 run, ScPho4 is significantly higher than CgPho4.

datM %>% 
  filter(plasmid %in% c("188", "194"), host == "PHO2") %>% 
  mutate(
    date = gsub("/22$", "", date),
    plasmid = factor(plasmid, levels = c("188", "194"), labels = c("CgPho4", "ScPho4"))
  ) %>% 
  pivot_longer(nGFP:nRFP, names_to = "parameter", values_to = "intensity") %>% 
  ggplot(aes(x = date, y = intensity, group = plasmid)) + 
  geom_point(aes(color = plasmid), alpha = 0.7, size = 1,
             position = position_jitterdodge(jitter.width = 0.1, dodge.width = 0.7)) + 
  scale_color_manual(values = c("ScPho4" = "blue3", "CgPho4" = "forestgreen")) +
  stat_summary(aes(color = plasmid), fun.data = "mean_se", geom = "crossbar", width = 0.4,
               position = position_dodge(0.7)) +
  facet_grid(parameter~., scale = "free_y") +
  expand_limits(y = 0) +
  theme_bw(base_size = 14) + labs(subtitle = "in PHO2 background")# +

  #theme(plot.subtitle = element_markdown())

The size normalized values show lower variance but a similar correlated pattern. Here, however, ScPho4 overtakes CgPho4 on the 03/22 and 05/17 runs.

How about the RFP/GFP ratios?

datM %>% 
  filter(plasmid %in% c("188", "194"), host == "PHO2") %>% 
  mutate(
    date = gsub("/22$", "", date),
    plasmid = factor(plasmid, levels = c("188", "194"), labels = c("CgPho4", "ScPho4")),
    `YL2 / BL1` = YL2.H / BL1.H,
    `nRFP / nGFP` = nRFP / nGFP
  ) %>% 
  pivot_longer(`YL2 / BL1`:`nRFP / nGFP`, names_to = "parameter", values_to = "ratio") %>% 
  ggplot(aes(x = date, y = ratio, group = plasmid)) + 
  geom_point(aes(color = plasmid), alpha = 0.6, size = 1, 
             position = position_jitterdodge(jitter.width = 0.1, dodge.width = 0.7)) + 
  stat_summary(aes(color = plasmid), fun.data = "mean_se", geom = "crossbar", width = 0.4,
               position = position_dodge(0.7)) +
  scale_color_manual(values = c("ScPho4" = "blue3", "CgPho4" = "forestgreen")) +
  facet_grid(parameter~.) + expand_limits(y = c(0,30)) +
  theme_bw(base_size = 14) + labs(subtitle = "in PHO2 background")# +

  #theme(plot.subtitle = element_markdown())

5. Statistical tests for confounding factors

Testing for run (date) as well as well (block) position effects on fluorescence values. Using the nest-map-unnest workflow

Note that in order to maintain a balanced design (same number of replicates in each group), we will restrict the analysis to batches 1-4 in the May/Jun dataset. The March dataset had a different plate design, while batch 5 of the May/Jun dataset is incomplete w.r.t. the controls (because only half of the plate was used).

tmp <- filter(dat1, plasmid == "188", host == "PHO2", date != "06/02/22") %>%   
  separate(well, into = c("row", "col"), sep = 1, remove = FALSE) %>% 
  select(date, block = well, row, col, BL1.H:nRFP) %>% 
  mutate(RvG = YL2.H / BL1.H, nRvG = nRFP / nGFP)
tmp %>% 
  pivot_longer(cols = BL1.H:nRvG, names_to = "parameter", values_to = "value") %>% 
  nest(data = c(-parameter)) %>% 
  mutate(
    fit = map(data, ~anova(lm(value ~ date + row + col, data = .x))),
    tidied = map(fit, broom::tidy)
  ) %>% 
  unnest(tidied) %>% 
  mutate(
    significant = case_when(
      p.value < 0.001 ~ "***",
      p.value < 0.01  ~ "**",
      p.value < 0.05  ~ "*",
      p.value < 0.1   ~ ".",
      TRUE ~ " "
    )) %>% 
  filter(term != "Residuals") %>% 
  select(parameter, term, df, statistic, p.value, significant)

There is a highly significant run (date) effect for all variables. The R/G and nR/G ratios show significant column effects. I also tried using block (12 blocks on the plate) and most of the block effects are significant.

Use dummy encoding in linear regression to view the effects of run and well position.

tmp %>% 
  mutate(row = factor(row, levels = c("G", "E", "C", "A"))) %>% 
  pivot_longer(cols = BL1.H:nRvG, names_to = "parameter", values_to = "value") %>% 
  nest(data = c(-parameter)) %>% 
  mutate(
    fit = map(data, ~lm(value ~ date + row + col, dat = .x)),
    tidied = map(fit, broom::tidy)
  ) %>% 
  unnest(tidied) %>% 
  mutate(
    term = gsub("/22$", "", term),
    estimate = round(estimate, digits = 2),
    significant = case_when(
      p.value < 0.001 ~ "***",
      p.value < 0.01  ~ "**",
      p.value < 0.05  ~ "*",
      p.value < 0.1   ~ ".",
      TRUE ~ " "
    ),
    eff = paste(estimate, significant, sep = "  ")
  ) %>% 
  select(parameter, term, eff) %>% 
  pivot_wider(names_from = parameter, values_from = eff)# %>% 
  #mutate(across(e_BL1:e_nRFP, ~ round(.x, digits = 0)))
  • There is a significant run (date) effect for all variables. RvG ratio appears to be better than nRvG in terms of being less affected by either run or well positions.
  • Row A has a higher fluorescence values overall. But the RvG ratios are not significantly higher in row A.
  • Column 9 has a significantly higher RvG, because, for some reason, the RFP is higher but not the GFP.

With the above observations, it is yet unclear to me (1) whether it is necessary to account for the run and position effects (if the effect sizes we are interested in are much larger than these, we may not care) and (2) if necessary, what’s the best way to account for it. One idea I have is to use the common strains on each plate, e.g., the host strains (no Pho4) or CgPho4 and ScPho4 with and without Pho2, as normalizing factors. One can think of several ways of normalization, e.g., setting ScPho4 w/ Pho2’s RvG as 100%. Will explore these ideas below.

Main

1. Mutation effects

Here we examine the effects of the mutations on the chimera activity. Emily remade 26 chimeric constructs to correct the non-synonymous mutations in them and reran those constructs in the May/Jun batch. While doing that, she encountered some issues with certain samples not growing well or the flow data showing multiple populations. She repeated some of those strains. As a result, we have more than two measurements for some of the strains. The goal in this analysis is to compare their measurements both with and without mutations, and also across the repeats.

Read in the experimental flags for the May/Jun batch, for the multiple population labels

multipop <- read_tsv("../data/20220614-EO-repeat-experiment-info.tsv", col_types = cols()) %>% 
  filter(flag == "multi pop") %>% select(-flag) %>% 
  separate(sample, into = c("plasmid", "host"), sep = "-") %>% 
  mutate(host = ordered(host, levels = c("555", "373"), labels = c("PHO2", "pho2∆")), multi_pop = TRUE)

Create a flag variable

datN <- datM %>% 
  mutate(multi_pop = FALSE) %>% 
  rows_update(multipop, by = c("date", "plasmid", "host")) %>% 
  mutate(
    RvG = ifelse(BL1.H > 0, YL2.H/BL1.H, NA),
    #RvG = num(RvG, digits = 2),
    flag = factor(mutation + multi_pop*2,
                  levels = as.character(0:3),
                  labels = c("pass", "mutation", "multi_pop", "mutation;multi_pop"))
  ) %>% relocate(RvG, .after = nRFP)

Emily has included two old samples containing mutations (pH209, 210) along with the remade, mutation-free plasmids, in the new batch. Let’s see how they compare with each other and with the March batch (with mutations).

tmp <- filter(datN, plasmid %in% c("209", "210")) %>% 
  mutate(
    month = str_sub(date, 1, 2),
    sample = ifelse(month == "03", "03-old", ifelse(mutation, "05-old", "05-new")),
    sample = factor(sample, levels = c("03-old", "05-old", "05-new"))
  )

First compare the same plasmids (with mutations) measured on different days

tmp %>% 
  select(-FSC.H) %>% 
  pivot_longer(BL1.H:RvG, names_to = "parameter", values_to = "value") %>%
  mutate(parameter = factor(parameter, levels = c("BL1.H", "YL2.H", "nGFP", "nRFP", "RvG"))) %>% 
  ggplot(aes(x = plasmid, y = value, group = sample)) +
  geom_point(aes(color = sample), size = 1, position = position_dodge(0.7)) +
  #stat_summary(aes(color = sample), fun.data = "mean_se", geom = "crossbar", width = 0.1,
  #             position = position_dodge(0.7)) +
  scale_color_manual(values = c("03-old" = "gray50", "05-old" = "gray30", "05-new" = "red2")) +
  scale_y_continuous(n.breaks = 3) + expand_limits(y = 0) +
  facet_grid(parameter~host, scales = "free_y") +
  theme_bw(base_size = 14) + background_grid(major = "y")

tmp %>% 
  select(-FSC.H) %>% 
  pivot_longer(BL1.H:RvG, names_to = "parameter", values_to = "value") %>%
  mutate(parameter = factor(parameter, levels = c("BL1.H", "YL2.H", "nGFP", "nRFP", "RvG"))) %>% 
  nest(data = c(-parameter)) %>% 
  mutate(
    fit = map(data, ~anova(lm(value ~ sample + host, data = .x))),
    tidied = map(fit, broom::tidy)
  ) %>% 
  unnest(tidied) %>% 
  mutate(
    significant = case_when(
      p.value < 0.001 ~ "***",
      p.value < 0.01  ~ "**",
      p.value < 0.05  ~ "*",
      p.value < 0.1   ~ ".",
      TRUE ~ " "
    )) %>% 
  filter(term != "Residuals") %>% 
  select(parameter, term, df, statistic, p.value, significant)

For the RvG ratio, there is no significant difference between the 03-old, 05-old and 05-new. In other words, we don’t have evidence that either the different runs or the correction of mutations impacted the behavior of the chimera in the case of pH209 and pH210.

We will now move on to the rest of the plasmids that have been remade.

pp <- theme(axis.title.x = element_blank(), legend.position = "none")
myPlotMutEffect <- function(l){
  even_numbers <- seq(2, length(l), 2) # used to draw stripes on even numbered x-values
  df_tile <- tibble(plasmid = rep(sort(l)[even_numbers], times = 2),
                    host = factor(rep(c("PHO2", "pho2∆"), each = length(even_numbers))))
  datN %>% 
    #mutate(date = gsub("/22$", "", date)) %>% 
    filter(!low_event_count, plasmid %in% l) %>% 
    select(date:host, RvG, flag) %>%
    ggplot(aes(x = plasmid, y = RvG)) +
    # draw stripes on even columns,
    # from: https://stackoverflow.com/questions/56961744/draw-alternate-rectangles-in-boxplots-with-facets-r-ggplot2'
    geom_tile(aes(x = plasmid, y = 1), height = Inf, width = 1, data = df_tile, alpha = 0.3) +
              #ymin = -Inf, ymax = Inf, fill = "grey80", color = NA, alpha = 0.5) +
    geom_point(aes(color = flag, group = date), size = 1.5, shape = 19,
               position = position_jitterdodge(jitter.width = 0.1, dodge.width = 0.7)) +
    #stat_summary(aes(color = sample), fun.data = "mean_se", geom = "crossbar", width = 0.1,
    #             position = position_dodge(0.7)) +
    scale_color_manual(values = c("pass" = "forestgreen", "mutation" = "purple", "multi_pop" = "steelblue3")) +
    scale_y_continuous(n.breaks = 4) + expand_limits(y = 0) +
    facet_grid(host~., scales = "free_y") +
    theme_cowplot() + panel_border(color = "gray30") + 
    theme(strip.text = element_text(face = 3))
}
lst <- split(list.mutations, f = ceiling(seq_along(list.mutations)/9))
p <- lapply(lst, myPlotMutEffect)
legend_p <- get_legend(p[[1]] + theme(legend.position = "bottom", legend.justification = "center"))
plot_grid(p[[1]] + pp, p[[2]] + pp, p[[3]] + theme(legend.position = "none"), legend_p, ncol = 1, rel_heights = c(1,1,1,.15))

Samples showing multiple populations mostly agree with the latter measurements where the issue was ressolved, with the exception of one of the samples of 231 in PHO2 background.

Here are the ones that show obvious differences between the old and corrected constructs:

ll <- c("215", "218", "227", "233", "241", "252", "257")
myPlotMutEffect(ll) + scale_y_log10()
Scale for 'y' is already present. Adding another scale for 'y', which will replace the existing scale.
Warning: Transformation introduced infinite values in continuous y-axis

2. Summarize results per chimera

We will remove all the measurements made of chimeras with mutations. For the measurements made of remade, corrected chimeras, we will remove one sample for pH231 from the 05/19 batch (well C2, the other 2 replicates of the same strain in that batch were removed due to the presence of multiple populations and low event count in the gated population), as well as one sample for pH233 from the 06/02 batch (well D4, which showed overexpression of the chimera).

Number of replicates measured for each chimera x host combination:

# load genotype information
meta <- read_tsv("../data/20220621-chimera-Pho4-makeup.tsv", col_types = "ccccc") %>% 
  rename(genotype = full) %>% select(-plasmid_wrong)

datN %>% 
  filter(!low_event_count, !mutation) %>% 
  count(plasmid, host) %>% 
  pivot_wider(names_from = host, values_from = n) %>% 
  full_join(meta, by = "plasmid") %>% 
  select(-letter, -genotype)

pH211 was measured 9 times in the PHO2 background. The results were consistent.

For each chimera, we would like to calculate three values:

  1. RvG in pho2∆: this is its base activity without Pho2
  2. RvG in PHO2: this is its full activity with Pho2
  3. RvG_PHO2 / RvG_pho2∆: this is the Pho2 enhancement of activity

The first two values are further normalized against the corresponding ScPho4 measurements on the same plate.

# filter data
tmp <- filter(datN, !low_event_count, !mutation, !is.na(plasmid)) %>% select(date:host, BL1.H:RvG)

# calculate the ScPho4 values per plate
mScPho4 <- tmp %>% filter(plasmid == "194") %>% group_by(date, host) %>% summarize(mean = mean(RvG), .groups = "drop") %>% 
  pivot_wider(names_from = host, values_from = mean) %>% column_to_rownames(var = "date")

# normalize the values for non-ScPho4 with those of ScPho4 per plate
datO <- tmp %>% mutate(sRvG = RvG / mScPho4[cbind(date, as.character(host))])

# summarize
datsum <- datO %>% 
  group_by(plasmid, host) %>% 
  summarize(across(RvG:sRvG, mean), .groups = "drop") %>% 
  pivot_wider(names_from = host, values_from = RvG:sRvG) %>% 
  rename(`A_PHO2` = `RvG_PHO2`, `A_pho2` = `RvG_pho2∆`, full = sRvG_PHO2, base = `sRvG_pho2∆`) %>% 
  mutate(boost = `A_PHO2` / `A_pho2`, across(`A_PHO2`:boost, ~ round(.x, digits = 3))) %>% 
  full_join(meta, by = "plasmid")

Export the summary data

write_tsv(datsum, file = "../output/20220619-chimera-summary-result.tsv")

Here are the chimera that have little full activity (with Pho2):

plasmid A_PHO2 A_pho2 full base boost symbol genotype
229 1.154 1.288 0.045 0.910 0.896 SSSCS Sc(1-176) Cg(283-458) Sc(243-312)
250 1.695 1.873 0.071 1.632 0.905 CSSCS Cg(1-44) Sc(43-176) Cg(283-458) Sc(243-312)
224 2.750 1.473 0.108 1.040 1.868 SCSCS Sc(1-42) Cg(45-112) Sc(100-176) Cg(283-458) Sc(243-312)
235 2.169 2.188 0.109 2.211 0.991 SSCCS Sc(1-99) Cg(113-458) Sc(243-312)
220 2.979 2.839 0.116 2.005 1.049 SCSCC Sc(1-42) Cg(45-112) Sc(100-176) Cg(283-533)
240 3.093 2.582 0.125 2.093 1.198 CCSCS Cg(1-112) Sc(100-176) Cg(283-458) Sc(243-312)
216 3.774 3.704 0.139 2.519 1.019 SCCCS Sc(1-42) Cg(45-458) Sc(243-312)
227 3.722 2.763 0.155 2.409 1.347 SSSCC Sc(1-176) Cg(283-533)
253 3.287 3.396 0.175 3.309 0.968 CSCCS Cg(1-44) Sc(43-99) Cg(113-458) Sc(243-312)

Here are the ones with the highest base activity (without Pho2):

plasmid A_PHO2 A_pho2 full base boost symbol genotype
188 20.771 17.674 0.899 14.709 1.175 CCCCC Cg(1-533)
257 40.497 20.073 1.583 14.174 2.017 CCCscC Cg (1-282) Sc(177-204) Cg(328-533)
213 13.974 11.972 0.700 12.097 1.167 CSCCC Cg(1-44) Sc(43-99) Cg(113-533)
212 17.570 13.155 0.646 8.945 1.336 SCCCC Sc(1-42) Cg(45-533)
209 10.920 8.746 0.456 7.624 1.249 CCSCC Cg(1-112) Sc(100-176) Cg(283-533)
255 18.337 7.505 0.765 6.541 2.443 CSSscC Cg(1-44) Sc(43-204) Cg(328-533)
219 47.187 9.115 1.734 6.198 5.177 CCCSS Cg(1-282) Sc(177-312)
215 8.904 7.686 0.348 5.427 1.159 SSCCC Sc(1-99) Cg(113-533)
210 6.359 5.536 0.265 4.825 1.149 CCCCS Cg(1-458) Sc(243-312)
266 6.546 5.438 0.273 4.740 1.204 SSscCC Sc(1-153) Cg(250-533)

3. Plotting functions

The goal here is to develop a set of plotting functions to visualize the results.

For testing purposes, we will select a set of chimera along with the endogenous ScPho4 and CgPho4.

# extract ximera names
refs <- c("CCCCC","SSSSS")
ximeras <- setdiff(meta$symbol, refs)
# make a test set
test <- c(refs, filter(meta, plasmid %in% c("211", "229", "250", "224", "257", "219", "266")) %>% pull(symbol))
# subset data
datT <- meta %>% 
  filter(symbol %in% test) %>% 
  inner_join(datO, by = "plasmid") %>% 
  mutate(symbol = factor(symbol, levels = test))

Design a set of color palettes:

# for two groups, e.g., with vs w/o Pho2
cols.two <- c("PHO2" = "#457dbc", "pho2∆" = "#ea9e25")

Plot individual components and the normalized activity (RvG ratio)

datT %>% 
  pivot_longer(c(nGFP, nRFP, RvG), names_to = "parameter", values_to = "intensity") %>% 
  mutate(parameter = ordered(parameter, levels = c("nGFP", "nRFP", "RvG"),
                             labels = c("Pho4-GFP", "_PHO5pr_ => RFP", "Activity = RFP/GFP"))) %>% 
  #pivot_longer(BL1.H:YL2.H, names_to = "parameter", values_to = "intensity") %>% 
  #mutate(parameter = ordered(parameter, levels = c("YL2.H", "BL1.H"))) %>% 
  ggplot(aes(x = symbol, y = intensity, group = host)) + 
  geom_bar(aes(fill = host), width = 0.5,# alpha = 0.8,
           stat = "summary", fun = "mean", position = position_dodge(0.5)) +
  geom_point(aes(color = host), size = 1, alpha = 0.9, shape = 3,
             position = position_jitterdodge(jitter.width = 0.2, dodge.width = 0.5)) + 
  scale_color_manual("co-TF", values = c("PHO2" = "gray30", "pho2∆" = "gray40")) +
  scale_fill_manual("co-TF", values = cols.two) +
  #stat_summary(fun = "mean", geom = "crossbar", color = "red", width = 0.25,
  #             position = position_dodge(0.75), ) +
  facet_wrap(~parameter, scale = "free_y", ncol = 1) +
  xlab("Pho4 chimera") + expand_limits(y = 0) +
  theme_bw(base_size = 14) +
  theme(axis.text.x = element_text(angle = 30, hjust = 1, family = "mono"),
        strip.text = element_markdown())

Plot the RvG values normalized against the corresponding ScPho4 construct on the same plate, to obtain a relative measure.

# useful to group the plasmids
ximera.grp <- datsum %>% 
  mutate(group = case_when(
    full < 0.2 ~ "defective",
    base > 5   ~ "less Pho2-dep.",
    TRUE       ~ "others"
  )) %>% select(plasmid, symbol, group)
p0 <- datT %>% 
  left_join(ximera.grp, by = c("symbol", "plasmid")) %>% 
  ggplot(aes(x = symbol, y = sRvG, group = host)) + 
  geom_bar(aes(fill = host), width = 0.5,# alpha = 0.8,
           stat = "summary", fun = "mean", position = position_dodge(0.5)) +
  geom_point(aes(color = host), size = 1, alpha = 0.9, shape = 3,
             position = position_jitterdodge(jitter.width = 0.2, dodge.width = 0.5)) + 
  scale_color_manual(values = c("PHO2" = "gray30", "pho2∆" = "gray40"), guide = "none") +
  scale_fill_manual(values = cols.two, guide = "none") +
  #stat_summary(fun = "mean", geom = "crossbar", color = "red", width = 0.25,
  #             position = position_dodge(0.75), ) +
  facet_grid(host~group, scale = "free") +
  xlab("Pho4 chimera") + ylab("A<sub>chimera</sub> / A<sub>ScPho4</sub>") +
  theme_bw(base_size = 14) + background_grid(minor = "none") +
  theme(axis.text.x = element_text(angle = 30, hjust = 1, family = "mono"),
        strip.text = element_markdown(), axis.title.y = element_markdown())

p1 <- datsum %>% 
  filter(symbol %in% test) %>% 
  left_join(ximera.grp, by = c("plasmid", "symbol")) %>% 
  ggplot(aes(x = symbol, y = boost)) +  
  geom_col(width = 0.3, color = "black", fill = "gray80") + 
  geom_hline(yintercept = 1, linetype = 2, color = "gray30") +
  facet_wrap(~group, scales = "free_x") + 
  scale_y_log10() +
  xlab("Pho4 chimera") + ylab("A<sub>PHO2</sub> / A<sub>pho2∆</sub>") +
  theme_bw(base_size = 14) + background_grid(minor = "none") +
  theme(axis.text.x = element_text(angle = 30, hjust = 1, family = "mono"),
        strip.text = element_blank(), axis.title.y = element_markdown())

set_null_device("png") # from https://github.com/wilkelab/cowplot/issues/174
plot_grid(p0 + theme(axis.title.x = element_blank()), 
          p1, ncol = 1, rel_heights = c(3,2))

save the data objects for the interactive data plotter

save(datO, datsum, meta, file = "../shinyapp/20220620-data-for-interactive-plotting.RData")

Design the plot

tmpsum %>% 
  mutate(Activity = ifelse(`R/G_PHO2` < 2*low.act.th["R/G_pho2∆"], "low", "pass")) %>% 
  ggplot(aes(x = symbol, y = `pho2∆/PHO2`)) + 
  geom_col(aes(group = date, fill = `R/G_PHO2`), width = 0.75, color = "gray50",
           position = position_dodge(0.9)) +
  #geom_point(aes(color = host), position = position_jitterdodge(dodge.width = 0.5)) + 
  scale_fill_gradient2("Activity") +
  #scale_color_manual(values = c(alpha("black",0), "red3")) +
  #stat_summary(fun = "mean", color = "red", geom = "crossbar", width = 0.2,
  #             position = position_dodge(0.75), ) +
  facet_grid(.~Activity, scales = "free_x", space = "free_x", labeller = "label_both") +
  theme_bw(base_size = 14) + xlab("Pho4 chimera") +
  theme(axis.text.x = element_text(angle = 30, hjust = 1, family = "mono"))

X-Y plot

p3 <- tmpsum %>% 
  mutate(`nR/G_PHO2` = signif(`nR/G_PHO2`, digits = 2),
         `nR/G_pho2∆` = signif(`nR/G_pho2∆`, digits = 2)) %>% 
  ggplot(aes(x = `nR/G_PHO2`, y = `nR/G_pho2∆`, label = symbol)) + 
  geom_point(size = 2.5) + geom_abline(slope = 1) +
  theme_gray(base_size = 14)
ggplotly(p3, tooltip = c("label", "x", "y"))
LS0tCnRpdGxlOiAiRTAxMyBQaG80IGNoaW1lcmEgYWN0aXZpdHkgYW5hbHlzaXMsIG5ldyBob3N0LCBjb25zdHJ1Y3RzIHdpdGggbXV0YXRpb25zIHJlcGxhY2VkIgphdXRob3I6IEJpbiBIZQpkYXRlOiAiMjAyMi0wMy0zMCAodXBkYXRlZCBgciBTeXMuRGF0ZSgpYCkiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMocmVxdWlyZShwbG90bHkpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMocmVxdWlyZSh0aWR5dmVyc2UpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMocmVxdWlyZShjb3dwbG90KSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHJlcXVpcmUoZ2d0ZXh0KSkKYGBgCgojIEJhY2tncm91bmQKRW1pbHkgZm91bmQgb3V0IHRoYXQgYSBudW1iZXIgb2YgY29uc3RydWN0cyBpbmNsdWRlZCBpbiB0aGUgbGFzdCBiYXRjaCBvZiBleHBlcmltZW50cyBoYWQgbm9uc3lub255bW91cyBtdXRhdGlvbnMuIFRvIGVuc3VyZSB0aGF0IHRoZSByZXN1bHRzIHdlcmUgbm90IGR1ZSB0byBtdXRhdGlvbnMsIHNoZSByZW1hZGUgdGhvc2UgY29uc3RydWN0cyB1c2luZyBoaWdoZXIgZmlkZWxpdHkgZW56eW1lcy4KCiMgR29hbAotIFF1YWxpdHkgY29udHJvbCBmb3IgdGhlIG5ldyBiYXRjaCBvZiByZXBlYXQgZXhwZXJpbWVudHMuIERldGVybWluZSBpZiB0aGVyZSBpcyBhbnkgd2VsbCBwb3NpdGlvbiBlZmZlY3QgYW5kIGhvdyB3ZWxsIHRoZSB2YWx1ZXMgYWdyZWUgYWNyb3NzIG11bHRpcGxlIGRheXMgb2YgZXhwZXJpbWVudHMuCi0gT25jZSBRQyBpcyBkb25lLCBtZXJnZSB0aGUgbmV3LCByZXBlYXQgZGF0YXNldCB3aXRoIHRoZSBvbGQgb25lLCByZXBsYWNpbmcgdGhlIHJlc3VsdHMgZm9yIHRoZSBvbGQgY29uc3RydWN0cyB3aXRoIG11dGF0aW9ucy4KLSBJbXBsZW1lbnQgdGhlIGlkZWEgb2Ygc2VwYXJhdGluZyB0aGUgYmFzYWwgYWN0aXZpdHkgYW5kIFBobzItYm9vc3QgdHJhaXRzLgoKIyBEYXRhClJlYWQgdGhlIHByZXZpb3VzIG1lcmdlZCBkYXRhCmBgYHtyfQpkYXRQcmUgPC0gcmVhZF90c3YoIi4uL291dHB1dC8yMDIyMDYxNC1tYXIyMi1iYXRjaC1iZy1zdWItZGF0YS50c3YiLCBjb2xfdHlwZXMgPSAiY2NjZmRkZGRkbGwiKSAlPiUgCiAgbXV0YXRlKGhvc3QgPSBvcmRlcmVkKGhvc3QpKQoKbGlzdC5tdXRhdGlvbnMgPC0gYXMuY2hhcmFjdGVyKGMoMjE1LCAyMDksIDIxMSwgMjEwLCAyMTcsIDIxOCwgMjIwLCAyMjEsIDIyMywgMjI0LCAyMjIsIDIyNywgMjMwLCAyMjksIDIzMSwgMjMzLCAyNDAsIDI0MSwgMjUwOjI1NSwgMjU3LCAyNTgpKQoKZXhwdFByZSA8LSBkYXRQcmUgJT4lIAogIGdyb3VwX2J5KGRhdGUsIHBsYXNtaWQsIGhvc3QpICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSwgbl9maWx0ZXIgPSBzdW0oIWxvd19ldmVudF9jb3VudCksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBtdXRhdGUoZmxhZyA9IGlmZWxzZShwbGFzbWlkICVpbiUgbGlzdC5tdXRhdGlvbnMsICJtdXRhdGlvbiIsICIiKSkKYGBgCgpSZWFkIHRoZSBuZXcgYmF0Y2hlcyBvZiBkYXRhCmBgYHtyfQpyYXcgPC0gbGlzdCgKICAiMDUvMTIvMjIiID0gcmVhZF90c3YoIi4uL2RhdGEvMjAyMjA1MTItRU8tcmVwZWF0LWJhdGNoLTEvMjAyMjA1MTItZ2F0ZWQtbWVkaWFuLW91dC50eHQiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSwKICAiMDUvMTcvMjIiID0gcmVhZF90c3YoIi4uL2RhdGEvMjAyMjA1MTctRU8tcmVwZWF0LWJhdGNoLTIvMjAyMjA1MTctZ2F0ZWQtbWVkaWFuLW91dC50eHQiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSwKICAiMDUvMTkvMjIiID0gcmVhZF90c3YoIi4uL2RhdGEvMjAyMjA1MTktRU8tcmVwZWF0LWJhdGNoLTMvMjAyMjA1MTktZ2F0ZWQtbWVkaWFuLW91dC50eHQiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSwKICAiMDUvMzEvMjIiID0gcmVhZF90c3YoIi4uL2RhdGEvMjAyMjA1MzEtRU8tcmVwZWF0LWJhdGNoLTQvMjAyMjA1MzEtZ2F0ZWQtbWVkaWFuLW91dC50eHQiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSwKICAiMDYvMDIvMjIiID0gcmVhZF90c3YoIi4uL2RhdGEvMjAyMjA2MDItRU8tcmVwZWF0LWJhdGNoLTUvMjAyMjA2MDItZ2F0ZWQtbWVkaWFuLW91dC50eHQiLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKQopCmRhdCA8LSBiaW5kX3Jvd3MocmF3LCAuaWQgPSAiZGF0ZSIpICU+JSAKICAjc2VwYXJhdGUoY29sID0gd2VsbCwgc2VwID0gMSwgaW50byA9IGMoInJvdyIsICJjb2wiKSkgJT4lIAogIHNlcGFyYXRlKGNvbCA9IHNhbXBsZSwgc2VwID0gIi0iLCBpbnRvID0gYygicGxhc21pZCIsICJob3N0IiwgInJlcCIpKSAlPiUgCiAgbXV0YXRlKHBsYXNtaWQgPSBuYV9pZihwbGFzbWlkLCAiTkEiKSkKYGBgCgoKIyBRQwojIyAxLiBOdW1iZXIgb2YgZXZlbnRzIHBlciBzYW1wbGUKYGBge3J9CmRhdCAlPiUgZ2dwbG90KGFlcyh4ID0gbl9pbmR1Y3Rpb24vMTAwMCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gImZvcmVzdGdyZWVuIikgKyAKICB4bGFiKCIjIGV2ZW50cyB4IDEwMDAiKSArCiAgZmFjZXRfZ3JpZChob3N0fmRhdGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSAjKyBwYW5lbF9ib3JkZXIoKQpgYGAKCj4gTWFqb3JpdHkgb2YgdGhlIGV4cGVyaW1lbnRhbCB3ZWxscyAobm90IGJsYW5rKSBoYXZlID4gMTAwMDAgZXZlbnRzLCB3aXRoIHRoZSBleGNlcHRpb24gb2YgYSBmZXcgc2FtcGxlcwoKYGBge3J9CmRhdCAlPiUgZmlsdGVyKGhvc3QgIT0gImJsYW5rIiwgbl9pbmR1Y3Rpb24gPCAxMDAwMCkKYGBgCj4gTmVhcmx5IGFsbCBzYW1wbGVzIHdpdGggYSBsb3cgZXZlbnQgY291bnQgd2VyZSBpbiB0aGUgNTU1IGJhY2tncm91bmQuIEVtaWx5IHJlcGVhdGVkIG1hbnkgb2YgdGhlbS4KPiBXaWxsIHJlbW92ZSBhbGwgc2FtcGxlcyB3aXRoIGxvd2VyIHRoYW4gNywwMDAgZXZlbnRzIGluIHRoZSBmaW5hbCBnYXRlZCBwb3B1bGF0aW9uIGZyb20gZnVydGhlciBhbmFseXNpcy4KCkZsYWcgc2FtcGxlcyB0aGF0IGhhdmUgYSBsb3cgZXZlbnQgY291bnQsIGNvbnRhaW4gbXV0YXRpb25zIG9yIHNob3cgbXVsdGlwbGUgcG9wdWxhdGlvbnMuCmBgYHtyfQpldmVudC50aCA8LSA3MDAwCgpkYXQgPC0gZGF0ICU+JSAKICBtdXRhdGUoCiAgICBsb3dfZXZlbnRfY291bnQgPSBuX2luZHVjdGlvbiA8IGV2ZW50LnRoLAogICAgIyBFbWlseSBsYWJlbGVkIHRoZSBvbGQgcGxhc21pZHMgd2l0aCBtdXRhdGlvbnMgd2l0aCBhbiAibyIgaW4gdGhlIGZsb3cgc2FtcGxlIG5hbWUgY29sdW1uCiAgICBtdXRhdGlvbiA9IGlmZWxzZShncmVwbCgibyQiLCBuYW1lKSwgVFJVRSwgRkFMU0UpCiAgKSAlPiUgCiAgZmlsdGVyKGhvc3QgIT0gImJsYW5rIikKYGBgCgojIyAyLiBCYWNrZ3JvdW5kIHN1YnRyYWN0aW9uCgpDaGVjayB0aGUgYmFja2dyb3VuZCBmbHVvcmVzY2VuY2UgbGV2ZWxzIGFjcm9zcyBkaWZmZXJlbnQgZGF5cy4KYGBge3J9CmRhdCAlPiUgZmlsdGVyKGhvc3QgPT0gIjE1NiIpICU+JSAKICBtdXRhdGUoZGF0ZSA9IGdzdWIoIi8yMiIsICIiLCBkYXRlKSkgJT4lIAogIHBpdm90X2xvbmdlcihCTDEuSDpuUkZQLCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAiaW50ZW5zaXR5IikgJT4lIAogIG11dGF0ZShwYXJhbWV0ZXIgPSBvcmRlcmVkKHBhcmFtZXRlciwgbGV2ZWxzID0gYygiQkwxLkgiLCAiWUwyLkgiLCAibkdGUCIsICJuUkZQIikpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGludGVuc2l0eSkpICsgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSB3ZWxsKSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX3NlIiwgZ2VvbSA9ICJwb2ludHJhbmdlIiwgY29sb3IgPSAicmVkIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4xKSkgKwogIGZhY2V0X3dyYXAofnBhcmFtZXRlciwgc2NhbGUgPSAiZnJlZV95IikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KQpgYGAKCj4gMDYvMDIgcnVuIGhhZCBzbWFsbGVyIEZTQyB2YWx1ZXMgKH4gY2VsbCB2b2x1bWUpIGNvbXBhcmVkIHdpdGggdGhlIG90aGVyIGRheXMsIHdoaWxlIHRoZSBiYWNrZ3JvdW5kIGZsdW9yZXNjZW5jZSBkb2Vzbid0IGFwcGVhciB0byBiZSBhIGxvdCBoaWdoZXIsIHJlc3VsdGluZyBpbiBoaWdoZXIgbm9ybWFsaXplZCB2YWx1ZXMuCgpTdWJ0cmFjdCB0aGUgYmFja2dyb3VuZApgYGB7cn0KYmcgPC0gZGF0ICU+JSAKICBmaWx0ZXIoaG9zdCA9PSAiMTU2IikgJT4lIAogIGdyb3VwX2J5KGRhdGUpICU+JSAKICBzdW1tYXJpemUoYWNyb3NzKEZTQy5IOm5SRlAsIH4gcm91bmQobWVhbigueCksMSkpKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJkYXRlIikKCmRhdDEgPC0gZGF0ICU+JSAKICBmaWx0ZXIoaG9zdCAhPSAiYmxhbmsiKSAlPiUgCiAgc2VsZWN0KGRhdGU6aG9zdCwgRlNDLkg6blJGUCwgbG93X2V2ZW50X2NvdW50Om11dGF0aW9uKSAlPiUKICBtdXRhdGUoCiAgICBCTDEuSCA9IEJMMS5IIC0gYmdbZGF0ZSwgIkJMMS5IIl0sCiAgICBZTDIuSCA9IFlMMi5IIC0gYmdbZGF0ZSwgIllMMi5IIl0sCiAgICBuR0ZQID0gbkdGUCAtIGJnW2RhdGUsICJuR0ZQIl0sCiAgICBuUkZQID0gblJGUCAtIGJnW2RhdGUsICJuUkZQIl0sCiAgKQpgYGAKCkRvdWJsZSBjaGVjayB0aGF0IHRoZSBzdWJ0cmFjdGlvbiB3b3JrZWQgY29ycmVjdGx5CmBgYHtyfQpkYXQxICU+JSBmaWx0ZXIoaG9zdCA9PSAiMTU2IikgJT4lIAogIHBpdm90X2xvbmdlcihCTDEuSDpuUkZQLCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAiaW50ZW5zaXR5IikgJT4lIAogIG11dGF0ZSgKICAgIHBhcmFtZXRlciA9IG9yZGVyZWQocGFyYW1ldGVyLCBsZXZlbHMgPSBjKCJCTDEuSCIsICJZTDIuSCIsICJuR0ZQIiwgIm5SRlAiKSksCiAgICBkYXRlID0gZ3N1YigiXFwvMjIkIiwgIiIsIGRhdGUpCiAgKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGludGVuc2l0eSkpICsgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSB3ZWxsKSkgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX3NlIiwgZ2VvbSA9ICJwb2ludHJhbmdlIiwgY29sb3IgPSAicmVkIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4xKSkgKwogIGZhY2V0X3dyYXAofnBhcmFtZXRlciwgc2NhbGUgPSAiZnJlZV95IikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KQoKIyByZW1vdmUgdGhlIHlIMTU2IHNhbXBsZXMKZGF0MSA8LSBkYXQxICU+JSAKICBmaWx0ZXIoaG9zdCAhPSAiMTU2IikgJT4lCiAgbXV0YXRlKGhvc3QgPSBvcmRlcmVkKGhvc3QsIGxldmVscyA9IGMoIjU1NSIsICIzNzMiKSwgbGFiZWxzID0gYygiUEhPMiIsICJwaG8y4oiGIikpKQpgYGAKCgojIyAzLiBXZWxsIHBvc2l0aW9uCgoqKl9SYXRpb25hbGVfKioKCkluIG15IHBsYXRlIGRlc2lnbiwgSSBwbGFjZWQgYSBwb3NpdGl2ZSBjb250cm9sIHN0cmFpbiAoQ2dQaG80LW1OZW9uIGluIF9QSE8yXyBiYWNrZ3JvdW5kKSBpbiB0aGUgY29udHJvbCBjb2x1bW5zICgxLCA1LCA5KSBvbiBldmVyeSBvdGhlciByb3cgKEEsIEMsIEUsIEcpLiBUaGUgcmF0aW9uYWxlIGZvciB0aGlzIGlzIHRvIHVzZSBpdCB0byBpZGVudGlmeSBhbnkgd2VsbCBwb3NpdGlvbiBlZmZlY3Qgb24gdGhlIGZsdW9yZXNjZW5jZSByZWFkaW5ncy4gSW4gdGhpcyByb3VuZCBvZiByZXBlYXQgZXhwZXJpbWVudHMsIEVtaWx5IGZvbGxvd2VkIHRoaXMgZGVzaWduIGFuZCBwdXQgcEgxODgteUgzMjMgaW4gdGhlc2Ugd2VsbHMuIE5vdyB3ZSBjYW4gcHJvcGVybHkgYXNzZXNzIHRoZSB3ZWxsIHBvc2l0aW9uIGVmZmVjdC4KCkZvciB0aGlzIGFuYWx5c2lzLCB3ZSB3aWxsIGNvbWJpbmUgYW5kIGNvbXBhcmUgdGhlIE1heS9KdW4gYmF0Y2ggd2l0aCB0aGUgTWFyIGJhdGNoCmBgYHtyfQpkYXRNIDwtIGJpbmRfcm93cyhkYXRQcmUsIGRhdDEpCmBgYAoKYGBge3J9CmRhdE0gJT4lIAogIGZpbHRlcihwbGFzbWlkID09ICIxODgiLCBob3N0ID09ICJQSE8yIikgJT4lIAogIHNlcGFyYXRlKHdlbGwsIGludG8gPSBjKCJyb3ciLCAiY29sIiksIHNlcCA9IDEpICU+JSAKICBwaXZvdF9sb25nZXIoQkwxLkg6WUwyLkgsIG5hbWVzX3RvID0gInBhcmFtZXRlciIsIHZhbHVlc190byA9ICJpbnRlbnNpdHkiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY29sLCB5ID0gaW50ZW5zaXR5LCBncm91cCA9IGRhdGUpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZGF0ZSksIHNpemUgPSAxKSArIAogICNnZW9tX2xpbmUoYWVzKGNvbG9yID0gZGF0ZSksIHNpemUgPSAwLjQpICsKICBzdGF0X3N1bW1hcnkoYWVzKGNvbG9yID0gZGF0ZSksIGdlb20gPSAibGluZSIsIGZ1biA9IG1lYW4pICsKICBzY2FsZV9jb2xvcl9icmV3ZXIodHlwZSA9ICJxdWFsIiwgcGFsZXR0ZSA9IDIpICsKICB4bGFiKCJDb2x1bW4iKSArCiAgZmFjZXRfZ3JpZChwYXJhbWV0ZXJ+cm93LCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KQpgYGAKCj4gLSBubyBvYnZpb3VzIHRyZW5kIGJldHdlZW4gdGhlIHJvd3Mgb3IgY29sdW1ucwo+IC0gYSBjbGVhciBjb3JyZWxhdGlvbiBiZXR3ZWVuIFlMMi5IIGFuZCBCTDEuSC4KClNhbWUgcGxvdCBmb3Igbm9ybWFsaXplZCBmbHVvcmVzY2VuY2UKYGBge3J9CmRhdE0gJT4lIAogIGZpbHRlcihwbGFzbWlkID09ICIxODgiLCBob3N0ID09ICJQSE8yIikgJT4lIAogIHNlcGFyYXRlKHdlbGwsIGludG8gPSBjKCJyb3ciLCAiY29sIiksIHNlcCA9IDEpICU+JSAKICBwaXZvdF9sb25nZXIoYyhuR0ZQLCBuUkZQKSwgbmFtZXNfdG8gPSAicGFyYW1ldGVyIiwgdmFsdWVzX3RvID0gImludGVuc2l0eSIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjb2wsIHkgPSBpbnRlbnNpdHksIGdyb3VwID0gZGF0ZSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkYXRlKSwgc2l6ZSA9IDEpICsgCiAgI2dlb21fbGluZShhZXMoY29sb3IgPSBkYXRlKSwgc2l6ZSA9IDAuNCkgKwogIHN0YXRfc3VtbWFyeShhZXMoY29sb3IgPSBkYXRlKSwgZ2VvbSA9ICJsaW5lIiwgZnVuID0gbWVhbikgKwogIHNjYWxlX2NvbG9yX2JyZXdlcih0eXBlID0gInF1YWwiLCBwYWxldHRlID0gMikgKwogIHhsYWIoIkNvbHVtbiIpICsKICBmYWNldF9ncmlkKHBhcmFtZXRlcn5yb3csIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpCmBgYAoKPiAtIFdoYXQgd2UgY2FyZSBhYm91dCBpcyB0aGUgcmF0aW8gYmV0d2VlbiBQaG80LW1OZW9uIGFuZCBfUEhPNXByXy1tQ2hlcnJ5CgpgYGB7cn0KZGF0TSAlPiUgCiAgZmlsdGVyKHBsYXNtaWQgPT0gIjE4OCIsIGhvc3QgPT0gIlBITzIiKSAlPiUgCiAgc2VwYXJhdGUod2VsbCwgaW50byA9IGMoInJvdyIsICJjb2wiKSwgc2VwID0gMSkgJT4lIAogIGdncGxvdChhZXMoeCA9IEJMMS5ILCB5ID0gWUwyLkgpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gZGF0ZSwgc2hhcGUgPSByb3cpLCBzaXplID0gMykgKyAKICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJncmF5NTAiLCBzaXplID0gMC41KSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHR5cGUgPSAicXVhbCIsIHBhbGV0dGUgPSAyKSArCiAgI3NjYWxlX2NvbG9yX3ZpcmlkaXNfZCgpICsKICAjc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMTU6MTcsIDIzLCAyNSkpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkKYGBgCgo+IC0gVGhlcmUgaXMgdmFyaWF0aW9uIGluIEJMMS5IIGFuZCBjb3JyZXNwb25kaW5nbHkgaW4gWUwyLkgsIGJ1dCB0aGUgcmF0aW8gYmV0d2VlbiB0aGUgdHdvIGFyZSB2ZXJ5IGNvbnNpc3RlbnQKCiMjIDQuIFJ1biBlZmZlY3QKCkhvdyBkb2VzIHRoZSBzYW1lIGNvbnRyb2wgc3RyYWluIGJlaGF2ZSBpbiBkaWZmZXJlbnQgcnVucyAocmVwcmVzZW50ZWQgYXMgZGF0ZSB2YXJpYWJsZSBoZXJlKT8gSXMgdGhlcmUgYSBzdHJvbmcgcnVuIGVmZmVjdD8KCkxldCdzIGNoZWNrIGJvdGggU2NQaG80IChwSDE5NCkgYW5kIENnUGhvNCAocEgxODgpIHRvIHNlZSBpZiB0aGVpciBiZWhhdmlvcnMgYXJlIGNvbnNpc3RlbnQgYWNyb3NzIGRheXMgYW5kIGJldHdlZW4gdGhpcyBhbmQgdGhlIGxhc3QgKDAzLzMwKSBiYXRjaC4KYGBge3J9CmRhdE0gJT4lIAogIGZpbHRlcihwbGFzbWlkICVpbiUgYygiMTg4IiwgIjE5NCIpKSAlPiUgCiAgbXV0YXRlKAogICAgZGF0ZSA9IGdzdWIoIi8yMiQiLCAiIiwgZGF0ZSksCiAgICBgWUwyLkggLyBCTDEuSGAgPSBZTDIuSCAvIEJMMS5ILAogICAgUGhvNCA9IGZhY3RvcihwbGFzbWlkLCBsZXZlbHMgPSBjKCIxOTQiLCAiMTg4IiksIGxhYmVscyA9IGMoIlNjUGhvNCIsICJDZ1BobzQiKSkKICApICU+JSAKICBzZXBhcmF0ZSh3ZWxsLCBpbnRvID0gYygicm93IiwgImNvbCIpLCBzZXAgPSAxKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGBZTDIuSCAvIEJMMS5IYCwgZ3JvdXAgPSBob3N0KSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGhvc3QpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcigwLjEpLCBhbHBoYSA9IDAuOCwgc2l6ZSA9IDEpICsgCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKGJlZ2luID0gMC4yLCBlbmQgPSAwLjYpICsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSAibWVhbl9zZSIsIGdlb20gPSAicG9pbnRyYW5nZSIsIHNoYXBlID0gMTYsIGNvbG9yID0gInJlZCIpICsKICB5bGltKDAsIDMwKSArIGZhY2V0X2dyaWQoUGhvNH4uKSArIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KQpgYGAKPiB3aGlsZSB0aGUgY2hhcmFjdGVyaXN0aWMgYmVoYXZpb3JzIG9mIFNjUGhvNCBhbmQgQ2dQaG80IGFyZSBjb25zaXN0ZW50IGFjcm9zcyBydW5zLCB0aGVyZSBhcmUgYWxzbyBjbGVhciB2YXJpYWJpbGl0eSBpbiB0aGUgUkZQL0dGUCByYXRpb3MgYmV0d2VlbiBwbGF0ZXMgZm9yIHRoZSBzYW1lIGdlbm90eXBlLgoKTmV4dCB3ZSBleGFtaW5lIHRoZSB1bmRlcmx5aW5nIGJhY2tncm91bmQtc3VidHJhY3RlZCBmbHVvcmVzY2VuY2UgdmFsdWVzIGZvciBwSDE4OCBhbmQgcEgxOTQgaW4gdGhlIHlINTU1IGJhY2tncm91bmQsIHdoaWNoIGFyZSBwcmVzZW50IG9uIGVhY2ggcGxhdGUuCgpgYGB7cn0KZGF0TSAlPiUgCiAgZmlsdGVyKHBsYXNtaWQgJWluJSBjKCIxODgiLCAiMTk0IiksIGhvc3QgPT0gIlBITzIiKSAlPiUgCiAgbXV0YXRlKAogICAgZGF0ZSA9IGdzdWIoIi8yMiQiLCAiIiwgZGF0ZSksCiAgICBwbGFzbWlkID0gZmFjdG9yKHBsYXNtaWQsIGxldmVscyA9IGMoIjE4OCIsICIxOTQiKSwgbGFiZWxzID0gYygiQ2dQaG80IiwgIlNjUGhvNCIpKQogICkgJT4lIAogIHBpdm90X2xvbmdlcihCTDEuSDpZTDIuSCwgbmFtZXNfdG8gPSAicGFyYW1ldGVyIiwgdmFsdWVzX3RvID0gImludGVuc2l0eSIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gaW50ZW5zaXR5LCBncm91cCA9IHBsYXNtaWQpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcGxhc21pZCksIGFscGhhID0gMC43LCBzaXplID0gMSwKICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2Uoaml0dGVyLndpZHRoID0gMC4xLCBkb2RnZS53aWR0aCA9IDAuNykpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlNjUGhvNCIgPSAiYmx1ZTMiLCAiQ2dQaG80IiA9ICJmb3Jlc3RncmVlbiIpKSArCiAgc3RhdF9zdW1tYXJ5KGFlcyhjb2xvciA9IHBsYXNtaWQpLCBmdW4uZGF0YSA9ICJtZWFuX3NlIiwgZ2VvbSA9ICJjcm9zc2JhciIsIHdpZHRoID0gMC40LAogICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNykpICsKICBmYWNldF9ncmlkKHBhcmFtZXRlcn4uLCBzY2FsZSA9ICJmcmVlX3kiKSArCiAgZXhwYW5kX2xpbWl0cyh5ID0gMCkgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArIGxhYnMoc3VidGl0bGUgPSAiaW4gUEhPMiBiYWNrZ3JvdW5kIikjICsKICAjdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfbWFya2Rvd24oKSkKYGBgCgo+IENnUGhvNCBhbmQgU2NQaG80IHZhbHVlcyB0cmFjayBlYWNoIG90aGVyIC0tIG9uIGRheXMgKHJ1bnMpIHdoZXJlIG9uZSBpcyBoaWdoLCB0aGUgb3RoZXIgb25lIGFsc28gdGVuZHMgdG8gYmUgaGlnaC4gT24gdGhlIDA1LzMxIHJ1biwgU2NQaG80IGlzIHNpZ25pZmljYW50bHkgaGlnaGVyIHRoYW4gQ2dQaG80LgoKYGBge3J9CmRhdE0gJT4lIAogIGZpbHRlcihwbGFzbWlkICVpbiUgYygiMTg4IiwgIjE5NCIpLCBob3N0ID09ICJQSE8yIikgJT4lIAogIG11dGF0ZSgKICAgIGRhdGUgPSBnc3ViKCIvMjIkIiwgIiIsIGRhdGUpLAogICAgcGxhc21pZCA9IGZhY3RvcihwbGFzbWlkLCBsZXZlbHMgPSBjKCIxODgiLCAiMTk0IiksIGxhYmVscyA9IGMoIkNnUGhvNCIsICJTY1BobzQiKSkKICApICU+JSAKICBwaXZvdF9sb25nZXIobkdGUDpuUkZQLCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAiaW50ZW5zaXR5IikgJT4lIAogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBpbnRlbnNpdHksIGdyb3VwID0gcGxhc21pZCkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBwbGFzbWlkKSwgYWxwaGEgPSAwLjcsIHNpemUgPSAxLAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShqaXR0ZXIud2lkdGggPSAwLjEsIGRvZGdlLndpZHRoID0gMC43KSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiU2NQaG80IiA9ICJibHVlMyIsICJDZ1BobzQiID0gImZvcmVzdGdyZWVuIikpICsKICBzdGF0X3N1bW1hcnkoYWVzKGNvbG9yID0gcGxhc21pZCksIGZ1bi5kYXRhID0gIm1lYW5fc2UiLCBnZW9tID0gImNyb3NzYmFyIiwgd2lkdGggPSAwLjQsCiAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC43KSkgKwogIGZhY2V0X2dyaWQocGFyYW1ldGVyfi4sIHNjYWxlID0gImZyZWVfeSIpICsKICBleHBhbmRfbGltaXRzKHkgPSAwKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsgbGFicyhzdWJ0aXRsZSA9ICJpbiBQSE8yIGJhY2tncm91bmQiKSMgKwogICN0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF9tYXJrZG93bigpKQpgYGAKPiBUaGUgc2l6ZSBub3JtYWxpemVkIHZhbHVlcyBzaG93IGxvd2VyIHZhcmlhbmNlIGJ1dCBhIHNpbWlsYXIgY29ycmVsYXRlZCBwYXR0ZXJuLiBIZXJlLCBob3dldmVyLCBTY1BobzQgb3ZlcnRha2VzIENnUGhvNCBvbiB0aGUgMDMvMjIgYW5kIDA1LzE3IHJ1bnMuCgpIb3cgYWJvdXQgdGhlIFJGUC9HRlAgcmF0aW9zPwpgYGB7cn0KZGF0TSAlPiUgCiAgZmlsdGVyKHBsYXNtaWQgJWluJSBjKCIxODgiLCAiMTk0IiksIGhvc3QgPT0gIlBITzIiKSAlPiUgCiAgbXV0YXRlKAogICAgZGF0ZSA9IGdzdWIoIi8yMiQiLCAiIiwgZGF0ZSksCiAgICBwbGFzbWlkID0gZmFjdG9yKHBsYXNtaWQsIGxldmVscyA9IGMoIjE4OCIsICIxOTQiKSwgbGFiZWxzID0gYygiQ2dQaG80IiwgIlNjUGhvNCIpKSwKICAgIGBZTDIgLyBCTDFgID0gWUwyLkggLyBCTDEuSCwKICAgIGBuUkZQIC8gbkdGUGAgPSBuUkZQIC8gbkdGUAogICkgJT4lIAogIHBpdm90X2xvbmdlcihgWUwyIC8gQkwxYDpgblJGUCAvIG5HRlBgLCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAicmF0aW8iKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IHJhdGlvLCBncm91cCA9IHBsYXNtaWQpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gcGxhc21pZCksIGFscGhhID0gMC42LCBzaXplID0gMSwgCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMSwgZG9kZ2Uud2lkdGggPSAwLjcpKSArIAogIHN0YXRfc3VtbWFyeShhZXMoY29sb3IgPSBwbGFzbWlkKSwgZnVuLmRhdGEgPSAibWVhbl9zZSIsIGdlb20gPSAiY3Jvc3NiYXIiLCB3aWR0aCA9IDAuNCwKICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjcpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlNjUGhvNCIgPSAiYmx1ZTMiLCAiQ2dQaG80IiA9ICJmb3Jlc3RncmVlbiIpKSArCiAgZmFjZXRfZ3JpZChwYXJhbWV0ZXJ+LikgKyBleHBhbmRfbGltaXRzKHkgPSBjKDAsMzApKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsgbGFicyhzdWJ0aXRsZSA9ICJpbiBQSE8yIGJhY2tncm91bmQiKSMgKwogICN0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF9tYXJrZG93bigpKQpgYGAKCiAKIyMgNS4gU3RhdGlzdGljYWwgdGVzdHMgZm9yIGNvbmZvdW5kaW5nIGZhY3RvcnMKVGVzdGluZyBmb3IgcnVuIChkYXRlKSBhcyB3ZWxsIGFzIHdlbGwgKGJsb2NrKSBwb3NpdGlvbiBlZmZlY3RzIG9uIGZsdW9yZXNjZW5jZSB2YWx1ZXMuIFVzaW5nIHRoZSBbbmVzdC1tYXAtdW5uZXN0IHdvcmtmbG93XShodHRwczovL3d3dy50aWR5bW9kZWxzLm9yZy9sZWFybi9zdGF0aXN0aWNzL3RpZHktYW5hbHlzaXMvKQoKTm90ZSB0aGF0IGluIG9yZGVyIHRvIG1haW50YWluIGEgYmFsYW5jZWQgZGVzaWduIChzYW1lIG51bWJlciBvZiByZXBsaWNhdGVzIGluIGVhY2ggZ3JvdXApLCB3ZSB3aWxsIHJlc3RyaWN0IHRoZSBhbmFseXNpcyB0byBiYXRjaGVzIDEtNCBpbiB0aGUgTWF5L0p1biBkYXRhc2V0LiBUaGUgTWFyY2ggZGF0YXNldCBoYWQgYSBkaWZmZXJlbnQgcGxhdGUgZGVzaWduLCB3aGlsZSBiYXRjaCA1IG9mIHRoZSBNYXkvSnVuIGRhdGFzZXQgaXMgaW5jb21wbGV0ZSB3LnIudC4gdGhlIGNvbnRyb2xzIChiZWNhdXNlIG9ubHkgaGFsZiBvZiB0aGUgcGxhdGUgd2FzIHVzZWQpLgoKYGBge3J9CnRtcCA8LSBmaWx0ZXIoZGF0MSwgcGxhc21pZCA9PSAiMTg4IiwgaG9zdCA9PSAiUEhPMiIsIGRhdGUgIT0gIjA2LzAyLzIyIikgJT4lICAgCiAgc2VwYXJhdGUod2VsbCwgaW50byA9IGMoInJvdyIsICJjb2wiKSwgc2VwID0gMSwgcmVtb3ZlID0gRkFMU0UpICU+JSAKICBzZWxlY3QoZGF0ZSwgYmxvY2sgPSB3ZWxsLCByb3csIGNvbCwgQkwxLkg6blJGUCkgJT4lIAogIG11dGF0ZShSdkcgPSBZTDIuSCAvIEJMMS5ILCBuUnZHID0gblJGUCAvIG5HRlApCmBgYAoKYGBge3J9CnRtcCAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBCTDEuSDpuUnZHLCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUgCiAgbmVzdChkYXRhID0gYygtcGFyYW1ldGVyKSkgJT4lIAogIG11dGF0ZSgKICAgIGZpdCA9IG1hcChkYXRhLCB+YW5vdmEobG0odmFsdWUgfiBkYXRlICsgcm93ICsgY29sLCBkYXRhID0gLngpKSksCiAgICB0aWRpZWQgPSBtYXAoZml0LCBicm9vbTo6dGlkeSkKICApICU+JSAKICB1bm5lc3QodGlkaWVkKSAlPiUgCiAgbXV0YXRlKAogICAgc2lnbmlmaWNhbnQgPSBjYXNlX3doZW4oCiAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICBwLnZhbHVlIDwgMC4wMSAgfiAiKioiLAogICAgICBwLnZhbHVlIDwgMC4wNSAgfiAiKiIsCiAgICAgIHAudmFsdWUgPCAwLjEgICB+ICIuIiwKICAgICAgVFJVRSB+ICIgIgogICAgKSkgJT4lIAogIGZpbHRlcih0ZXJtICE9ICJSZXNpZHVhbHMiKSAlPiUgCiAgc2VsZWN0KHBhcmFtZXRlciwgdGVybSwgZGYsIHN0YXRpc3RpYywgcC52YWx1ZSwgc2lnbmlmaWNhbnQpCmBgYAo+IFRoZXJlIGlzIGEgaGlnaGx5IHNpZ25pZmljYW50IHJ1biAoZGF0ZSkgZWZmZWN0IGZvciBhbGwgdmFyaWFibGVzLiBUaGUgUi9HIGFuZCBuUi9HIHJhdGlvcyBzaG93IHNpZ25pZmljYW50IGNvbHVtbiBlZmZlY3RzLgo+IEkgYWxzbyB0cmllZCB1c2luZyBibG9jayAoMTIgYmxvY2tzIG9uIHRoZSBwbGF0ZSkgYW5kIG1vc3Qgb2YgdGhlIGJsb2NrIGVmZmVjdHMgYXJlIHNpZ25pZmljYW50LgoKVXNlIGR1bW15IGVuY29kaW5nIGluIGxpbmVhciByZWdyZXNzaW9uIHRvIHZpZXcgdGhlIGVmZmVjdHMgb2YgcnVuIGFuZCB3ZWxsIHBvc2l0aW9uLgpgYGB7cn0KdG1wICU+JSAKICBtdXRhdGUocm93ID0gZmFjdG9yKHJvdywgbGV2ZWxzID0gYygiRyIsICJFIiwgIkMiLCAiQSIpKSkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gQkwxLkg6blJ2RywgbmFtZXNfdG8gPSAicGFyYW1ldGVyIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIAogIG5lc3QoZGF0YSA9IGMoLXBhcmFtZXRlcikpICU+JSAKICBtdXRhdGUoCiAgICBmaXQgPSBtYXAoZGF0YSwgfmxtKHZhbHVlIH4gZGF0ZSArIHJvdyArIGNvbCwgZGF0ID0gLngpKSwKICAgIHRpZGllZCA9IG1hcChmaXQsIGJyb29tOjp0aWR5KQogICkgJT4lIAogIHVubmVzdCh0aWRpZWQpICU+JSAKICBtdXRhdGUoCiAgICB0ZXJtID0gZ3N1YigiLzIyJCIsICIiLCB0ZXJtKSwKICAgIGVzdGltYXRlID0gcm91bmQoZXN0aW1hdGUsIGRpZ2l0cyA9IDIpLAogICAgc2lnbmlmaWNhbnQgPSBjYXNlX3doZW4oCiAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICBwLnZhbHVlIDwgMC4wMSAgfiAiKioiLAogICAgICBwLnZhbHVlIDwgMC4wNSAgfiAiKiIsCiAgICAgIHAudmFsdWUgPCAwLjEgICB+ICIuIiwKICAgICAgVFJVRSB+ICIgIgogICAgKSwKICAgIGVmZiA9IHBhc3RlKGVzdGltYXRlLCBzaWduaWZpY2FudCwgc2VwID0gIiAgIikKICApICU+JSAKICBzZWxlY3QocGFyYW1ldGVyLCB0ZXJtLCBlZmYpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcGFyYW1ldGVyLCB2YWx1ZXNfZnJvbSA9IGVmZikjICU+JSAKICAjbXV0YXRlKGFjcm9zcyhlX0JMMTplX25SRlAsIH4gcm91bmQoLngsIGRpZ2l0cyA9IDApKSkKYGBgCj4gLSBUaGVyZSBpcyBhIHNpZ25pZmljYW50IHJ1biAoZGF0ZSkgZWZmZWN0IGZvciBhbGwgdmFyaWFibGVzLiBSdkcgcmF0aW8gYXBwZWFycyB0byBiZSBiZXR0ZXIgdGhhbiBuUnZHIGluIHRlcm1zIG9mIGJlaW5nIGxlc3MgYWZmZWN0ZWQgYnkgZWl0aGVyIHJ1biBvciB3ZWxsIHBvc2l0aW9ucy4KPiAtIFJvdyBBIGhhcyBhIGhpZ2hlciBmbHVvcmVzY2VuY2UgdmFsdWVzIG92ZXJhbGwuIEJ1dCB0aGUgUnZHIHJhdGlvcyBhcmUgbm90IHNpZ25pZmljYW50bHkgaGlnaGVyIGluIHJvdyBBLgo+IC0gQ29sdW1uIDkgaGFzIGEgc2lnbmlmaWNhbnRseSBoaWdoZXIgUnZHLCBiZWNhdXNlLCBmb3Igc29tZSByZWFzb24sIHRoZSBSRlAgaXMgaGlnaGVyIGJ1dCBub3QgdGhlIEdGUC4KCldpdGggdGhlIGFib3ZlIG9ic2VydmF0aW9ucywgaXQgaXMgeWV0IHVuY2xlYXIgdG8gbWUgKDEpIHdoZXRoZXIgaXQgaXMgbmVjZXNzYXJ5IHRvIGFjY291bnQgZm9yIHRoZSBydW4gYW5kIHBvc2l0aW9uIGVmZmVjdHMgKGlmIHRoZSBlZmZlY3Qgc2l6ZXMgd2UgYXJlIGludGVyZXN0ZWQgaW4gYXJlIG11Y2ggbGFyZ2VyIHRoYW4gdGhlc2UsIHdlIG1heSBub3QgY2FyZSkgYW5kICgyKSBpZiBuZWNlc3NhcnksIHdoYXQncyB0aGUgYmVzdCB3YXkgdG8gYWNjb3VudCBmb3IgaXQuIE9uZSBpZGVhIEkgaGF2ZSBpcyB0byB1c2UgdGhlIGNvbW1vbiBzdHJhaW5zIG9uIGVhY2ggcGxhdGUsIGUuZy4sIHRoZSBob3N0IHN0cmFpbnMgKG5vIFBobzQpIG9yIENnUGhvNCBhbmQgU2NQaG80IHdpdGggYW5kIHdpdGhvdXQgUGhvMiwgYXMgbm9ybWFsaXppbmcgZmFjdG9ycy4gT25lIGNhbiB0aGluayBvZiBzZXZlcmFsIHdheXMgb2Ygbm9ybWFsaXphdGlvbiwgZS5nLiwgc2V0dGluZyBTY1BobzQgdy8gUGhvMidzIFJ2RyBhcyAxMDAlLiBXaWxsIGV4cGxvcmUgdGhlc2UgaWRlYXMgYmVsb3cuCgojIE1haW4KIyMgMS4gTXV0YXRpb24gZWZmZWN0cwpIZXJlIHdlIGV4YW1pbmUgdGhlIGVmZmVjdHMgb2YgdGhlIG11dGF0aW9ucyBvbiB0aGUgY2hpbWVyYSBhY3Rpdml0eS4gRW1pbHkgcmVtYWRlIGByIGxlbmd0aChsaXN0Lm11dGF0aW9ucylgIGNoaW1lcmljIGNvbnN0cnVjdHMgdG8gY29ycmVjdCB0aGUgbm9uLXN5bm9ueW1vdXMgbXV0YXRpb25zIGluIHRoZW0gYW5kIHJlcmFuIHRob3NlIGNvbnN0cnVjdHMgaW4gdGhlIE1heS9KdW4gYmF0Y2guIFdoaWxlIGRvaW5nIHRoYXQsIHNoZSBlbmNvdW50ZXJlZCBzb21lIGlzc3VlcyB3aXRoIGNlcnRhaW4gc2FtcGxlcyBub3QgZ3Jvd2luZyB3ZWxsIG9yIHRoZSBmbG93IGRhdGEgc2hvd2luZyBtdWx0aXBsZSBwb3B1bGF0aW9ucy4gU2hlIHJlcGVhdGVkIHNvbWUgb2YgdGhvc2Ugc3RyYWlucy4gQXMgYSByZXN1bHQsIHdlIGhhdmUgbW9yZSB0aGFuIHR3byBtZWFzdXJlbWVudHMgZm9yIHNvbWUgb2YgdGhlIHN0cmFpbnMuIFRoZSBnb2FsIGluIHRoaXMgYW5hbHlzaXMgaXMgdG8gY29tcGFyZSB0aGVpciBtZWFzdXJlbWVudHMgYm90aCB3aXRoIGFuZCB3aXRob3V0IG11dGF0aW9ucywgYW5kIGFsc28gYWNyb3NzIHRoZSByZXBlYXRzLgoKUmVhZCBpbiB0aGUgZXhwZXJpbWVudGFsIGZsYWdzIGZvciB0aGUgTWF5L0p1biBiYXRjaCwgZm9yIHRoZSBtdWx0aXBsZSBwb3B1bGF0aW9uIGxhYmVscwpgYGB7cn0KbXVsdGlwb3AgPC0gcmVhZF90c3YoIi4uL2RhdGEvMjAyMjA2MTQtRU8tcmVwZWF0LWV4cGVyaW1lbnQtaW5mby50c3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpICU+JSAKICBmaWx0ZXIoZmxhZyA9PSAibXVsdGkgcG9wIikgJT4lIHNlbGVjdCgtZmxhZykgJT4lIAogIHNlcGFyYXRlKHNhbXBsZSwgaW50byA9IGMoInBsYXNtaWQiLCAiaG9zdCIpLCBzZXAgPSAiLSIpICU+JSAKICBtdXRhdGUoaG9zdCA9IG9yZGVyZWQoaG9zdCwgbGV2ZWxzID0gYygiNTU1IiwgIjM3MyIpLCBsYWJlbHMgPSBjKCJQSE8yIiwgInBobzLiiIYiKSksIG11bHRpX3BvcCA9IFRSVUUpCmBgYAoKQ3JlYXRlIGEgZmxhZyB2YXJpYWJsZQpgYGB7cn0KZGF0TiA8LSBkYXRNICU+JSAKICBtdXRhdGUobXVsdGlfcG9wID0gRkFMU0UpICU+JSAKICByb3dzX3VwZGF0ZShtdWx0aXBvcCwgYnkgPSBjKCJkYXRlIiwgInBsYXNtaWQiLCAiaG9zdCIpKSAlPiUgCiAgbXV0YXRlKAogICAgUnZHID0gaWZlbHNlKEJMMS5IID4gMCwgWUwyLkgvQkwxLkgsIE5BKSwKICAgICNSdkcgPSBudW0oUnZHLCBkaWdpdHMgPSAyKSwKICAgIGZsYWcgPSBmYWN0b3IobXV0YXRpb24gKyBtdWx0aV9wb3AqMiwKICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYXMuY2hhcmFjdGVyKDA6MyksCiAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoInBhc3MiLCAibXV0YXRpb24iLCAibXVsdGlfcG9wIiwgIm11dGF0aW9uO211bHRpX3BvcCIpKQogICkgJT4lIHJlbG9jYXRlKFJ2RywgLmFmdGVyID0gblJGUCkKYGBgCgpFbWlseSBoYXMgaW5jbHVkZWQgdHdvIG9sZCBzYW1wbGVzIGNvbnRhaW5pbmcgbXV0YXRpb25zIChwSDIwOSwgMjEwKSBhbG9uZyB3aXRoIHRoZSByZW1hZGUsIG11dGF0aW9uLWZyZWUgcGxhc21pZHMsIGluIHRoZSBuZXcgYmF0Y2guIExldCdzIHNlZSBob3cgdGhleSBjb21wYXJlIHdpdGggZWFjaCBvdGhlciBhbmQgd2l0aCB0aGUgTWFyY2ggYmF0Y2ggKHdpdGggbXV0YXRpb25zKS4KYGBge3J9CnRtcCA8LSBmaWx0ZXIoZGF0TiwgcGxhc21pZCAlaW4lIGMoIjIwOSIsICIyMTAiKSkgJT4lIAogIG11dGF0ZSgKICAgIG1vbnRoID0gc3RyX3N1YihkYXRlLCAxLCAyKSwKICAgIHNhbXBsZSA9IGlmZWxzZShtb250aCA9PSAiMDMiLCAiMDMtb2xkIiwgaWZlbHNlKG11dGF0aW9uLCAiMDUtb2xkIiwgIjA1LW5ldyIpKSwKICAgIHNhbXBsZSA9IGZhY3RvcihzYW1wbGUsIGxldmVscyA9IGMoIjAzLW9sZCIsICIwNS1vbGQiLCAiMDUtbmV3IikpCiAgKQpgYGAKCkZpcnN0IGNvbXBhcmUgdGhlIHNhbWUgcGxhc21pZHMgKHdpdGggbXV0YXRpb25zKSBtZWFzdXJlZCBvbiBkaWZmZXJlbnQgZGF5cwpgYGB7ciBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQp0bXAgJT4lIAogIHNlbGVjdCgtRlNDLkgpICU+JSAKICBwaXZvdF9sb25nZXIoQkwxLkg6UnZHLCBuYW1lc190byA9ICJwYXJhbWV0ZXIiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUocGFyYW1ldGVyID0gZmFjdG9yKHBhcmFtZXRlciwgbGV2ZWxzID0gYygiQkwxLkgiLCAiWUwyLkgiLCAibkdGUCIsICJuUkZQIiwgIlJ2RyIpKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHBsYXNtaWQsIHkgPSB2YWx1ZSwgZ3JvdXAgPSBzYW1wbGUpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBzYW1wbGUpLCBzaXplID0gMSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjcpKSArCiAgI3N0YXRfc3VtbWFyeShhZXMoY29sb3IgPSBzYW1wbGUpLCBmdW4uZGF0YSA9ICJtZWFuX3NlIiwgZ2VvbSA9ICJjcm9zc2JhciIsIHdpZHRoID0gMC4xLAogICMgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjcpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIjAzLW9sZCIgPSAiZ3JheTUwIiwgIjA1LW9sZCIgPSAiZ3JheTMwIiwgIjA1LW5ldyIgPSAicmVkMiIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG4uYnJlYWtzID0gMykgKyBleHBhbmRfbGltaXRzKHkgPSAwKSArCiAgZmFjZXRfZ3JpZChwYXJhbWV0ZXJ+aG9zdCwgc2NhbGVzID0gImZyZWVfeSIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKyBiYWNrZ3JvdW5kX2dyaWQobWFqb3IgPSAieSIpCmBgYAoKYGBge3J9CnRtcCAlPiUgCiAgc2VsZWN0KC1GU0MuSCkgJT4lIAogIHBpdm90X2xvbmdlcihCTDEuSDpSdkcsIG5hbWVzX3RvID0gInBhcmFtZXRlciIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogIG11dGF0ZShwYXJhbWV0ZXIgPSBmYWN0b3IocGFyYW1ldGVyLCBsZXZlbHMgPSBjKCJCTDEuSCIsICJZTDIuSCIsICJuR0ZQIiwgIm5SRlAiLCAiUnZHIikpKSAlPiUgCiAgbmVzdChkYXRhID0gYygtcGFyYW1ldGVyKSkgJT4lIAogIG11dGF0ZSgKICAgIGZpdCA9IG1hcChkYXRhLCB+YW5vdmEobG0odmFsdWUgfiBzYW1wbGUgKyBob3N0LCBkYXRhID0gLngpKSksCiAgICB0aWRpZWQgPSBtYXAoZml0LCBicm9vbTo6dGlkeSkKICApICU+JSAKICB1bm5lc3QodGlkaWVkKSAlPiUgCiAgbXV0YXRlKAogICAgc2lnbmlmaWNhbnQgPSBjYXNlX3doZW4oCiAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICBwLnZhbHVlIDwgMC4wMSAgfiAiKioiLAogICAgICBwLnZhbHVlIDwgMC4wNSAgfiAiKiIsCiAgICAgIHAudmFsdWUgPCAwLjEgICB+ICIuIiwKICAgICAgVFJVRSB+ICIgIgogICAgKSkgJT4lIAogIGZpbHRlcih0ZXJtICE9ICJSZXNpZHVhbHMiKSAlPiUgCiAgc2VsZWN0KHBhcmFtZXRlciwgdGVybSwgZGYsIHN0YXRpc3RpYywgcC52YWx1ZSwgc2lnbmlmaWNhbnQpCmBgYAo+IEZvciB0aGUgUnZHIHJhdGlvLCB0aGVyZSBpcyBubyBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIDAzLW9sZCwgMDUtb2xkIGFuZCAwNS1uZXcuIEluIG90aGVyIHdvcmRzLCB3ZSBkb24ndCBoYXZlIGV2aWRlbmNlIHRoYXQgZWl0aGVyIHRoZSBkaWZmZXJlbnQgcnVucyBvciB0aGUgY29ycmVjdGlvbiBvZiBtdXRhdGlvbnMgaW1wYWN0ZWQgdGhlIGJlaGF2aW9yIG9mIHRoZSBjaGltZXJhIGluIHRoZSBjYXNlIG9mIHBIMjA5IGFuZCBwSDIxMC4KCldlIHdpbGwgbm93IG1vdmUgb24gdG8gdGhlIHJlc3Qgb2YgdGhlIHBsYXNtaWRzIHRoYXQgaGF2ZSBiZWVuIHJlbWFkZS4KYGBge3J9CnBwIDwtIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpteVBsb3RNdXRFZmZlY3QgPC0gZnVuY3Rpb24obCl7CiAgZXZlbl9udW1iZXJzIDwtIHNlcSgyLCBsZW5ndGgobCksIDIpICMgdXNlZCB0byBkcmF3IHN0cmlwZXMgb24gZXZlbiBudW1iZXJlZCB4LXZhbHVlcwogIGRmX3RpbGUgPC0gdGliYmxlKHBsYXNtaWQgPSByZXAoc29ydChsKVtldmVuX251bWJlcnNdLCB0aW1lcyA9IDIpLAogICAgICAgICAgICAgICAgICAgIGhvc3QgPSBmYWN0b3IocmVwKGMoIlBITzIiLCAicGhvMuKIhiIpLCBlYWNoID0gbGVuZ3RoKGV2ZW5fbnVtYmVycykpKSkKICBkYXROICU+JSAKICAgICNtdXRhdGUoZGF0ZSA9IGdzdWIoIi8yMiQiLCAiIiwgZGF0ZSkpICU+JSAKICAgIGZpbHRlcighbG93X2V2ZW50X2NvdW50LCBwbGFzbWlkICVpbiUgbCkgJT4lIAogICAgc2VsZWN0KGRhdGU6aG9zdCwgUnZHLCBmbGFnKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IHBsYXNtaWQsIHkgPSBSdkcpKSArCiAgICAjIGRyYXcgc3RyaXBlcyBvbiBldmVuIGNvbHVtbnMsCiAgICAjIGZyb206IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzU2OTYxNzQ0L2RyYXctYWx0ZXJuYXRlLXJlY3RhbmdsZXMtaW4tYm94cGxvdHMtd2l0aC1mYWNldHMtci1nZ3Bsb3QyJwogICAgZ2VvbV90aWxlKGFlcyh4ID0gcGxhc21pZCwgeSA9IDEpLCBoZWlnaHQgPSBJbmYsIHdpZHRoID0gMSwgZGF0YSA9IGRmX3RpbGUsIGFscGhhID0gMC4zKSArCiAgICAgICAgICAgICAgI3ltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCBmaWxsID0gImdyZXk4MCIsIGNvbG9yID0gTkEsIGFscGhhID0gMC41KSArCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGZsYWcsIGdyb3VwID0gZGF0ZSksIHNpemUgPSAxLjUsIHNoYXBlID0gMTksCiAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2Uoaml0dGVyLndpZHRoID0gMC4xLCBkb2RnZS53aWR0aCA9IDAuNykpICsKICAgICNzdGF0X3N1bW1hcnkoYWVzKGNvbG9yID0gc2FtcGxlKSwgZnVuLmRhdGEgPSAibWVhbl9zZSIsIGdlb20gPSAiY3Jvc3NiYXIiLCB3aWR0aCA9IDAuMSwKICAgICMgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjcpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygicGFzcyIgPSAiZm9yZXN0Z3JlZW4iLCAibXV0YXRpb24iID0gInB1cnBsZSIsICJtdWx0aV9wb3AiID0gInN0ZWVsYmx1ZTMiKSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKG4uYnJlYWtzID0gNCkgKyBleHBhbmRfbGltaXRzKHkgPSAwKSArCiAgICBmYWNldF9ncmlkKGhvc3R+Liwgc2NhbGVzID0gImZyZWVfeSIpICsKICAgIHRoZW1lX2Nvd3Bsb3QoKSArIHBhbmVsX2JvcmRlcihjb2xvciA9ICJncmF5MzAiKSArIAogICAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gMykpCn0KYGBgCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGggPSA1LCBmaWcuaGVpZ2h0ID0gN30KbHN0IDwtIHNwbGl0KGxpc3QubXV0YXRpb25zLCBmID0gY2VpbGluZyhzZXFfYWxvbmcobGlzdC5tdXRhdGlvbnMpLzkpKQpwIDwtIGxhcHBseShsc3QsIG15UGxvdE11dEVmZmVjdCkKbGVnZW5kX3AgPC0gZ2V0X2xlZ2VuZChwW1sxXV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIikpCnBsb3RfZ3JpZChwW1sxXV0gKyBwcCwgcFtbMl1dICsgcHAsIHBbWzNdXSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksIGxlZ2VuZF9wLCBuY29sID0gMSwgcmVsX2hlaWdodHMgPSBjKDEsMSwxLC4xNSkpCmBgYAo+IFNhbXBsZXMgc2hvd2luZyBtdWx0aXBsZSBwb3B1bGF0aW9ucyBtb3N0bHkgYWdyZWUgd2l0aCB0aGUgbGF0dGVyIG1lYXN1cmVtZW50cyB3aGVyZSB0aGUgaXNzdWUgd2FzIHJlc3NvbHZlZCwgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIG9uZSBvZiB0aGUgc2FtcGxlcyBvZiAyMzEgaW4gX1BITzJfIGJhY2tncm91bmQuCj4gCgpIZXJlIGFyZSB0aGUgb25lcyB0aGF0IHNob3cgb2J2aW91cyBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBvbGQgYW5kIGNvcnJlY3RlZCBjb25zdHJ1Y3RzOgpgYGB7cn0KbGwgPC0gYygiMjE1IiwgIjIxOCIsICIyMjciLCAiMjMzIiwgIjI0MSIsICIyNTIiLCAiMjU3IikKbXlQbG90TXV0RWZmZWN0KGxsKSArIHNjYWxlX3lfbG9nMTAoKQpgYGAKCiMjIDIuIFN1bW1hcml6ZSByZXN1bHRzIHBlciBjaGltZXJhCldlIHdpbGwgcmVtb3ZlIGFsbCB0aGUgbWVhc3VyZW1lbnRzIG1hZGUgb2YgY2hpbWVyYXMgd2l0aCBtdXRhdGlvbnMuIEZvciB0aGUgbWVhc3VyZW1lbnRzIG1hZGUgb2YgcmVtYWRlLCBjb3JyZWN0ZWQgY2hpbWVyYXMsIHdlIHdpbGwgcmVtb3ZlICoqb25lIHNhbXBsZSBmb3IgcEgyMzEgZnJvbSB0aGUgMDUvMTkgYmF0Y2gqKiAod2VsbCBDMiwgdGhlIG90aGVyIDIgcmVwbGljYXRlcyBvZiB0aGUgc2FtZSBzdHJhaW4gaW4gdGhhdCBiYXRjaCB3ZXJlIHJlbW92ZWQgZHVlIHRvIHRoZSBwcmVzZW5jZSBvZiBtdWx0aXBsZSBwb3B1bGF0aW9ucyBhbmQgbG93IGV2ZW50IGNvdW50IGluIHRoZSBnYXRlZCBwb3B1bGF0aW9uKSwgYXMgd2VsbCBhcyBvbmUgc2FtcGxlIGZvciAqKnBIMjMzIGZyb20gdGhlIDA2LzAyIGJhdGNoKiogKHdlbGwgRDQsIHdoaWNoIHNob3dlZCBvdmVyZXhwcmVzc2lvbiBvZiB0aGUgY2hpbWVyYSkuCgpOdW1iZXIgb2YgcmVwbGljYXRlcyBtZWFzdXJlZCBmb3IgZWFjaCBjaGltZXJhIHggaG9zdCBjb21iaW5hdGlvbjoKYGBge3J9CiMgbG9hZCBnZW5vdHlwZSBpbmZvcm1hdGlvbgptZXRhIDwtIHJlYWRfdHN2KCIuLi9kYXRhLzIwMjIwNjIxLWNoaW1lcmEtUGhvNC1tYWtldXAudHN2IiwgY29sX3R5cGVzID0gImNjY2NjIikgJT4lIAogIHJlbmFtZShnZW5vdHlwZSA9IGZ1bGwpICU+JSBzZWxlY3QoLXBsYXNtaWRfd3JvbmcpCgpkYXROICU+JSAKICBmaWx0ZXIoIWxvd19ldmVudF9jb3VudCwgIW11dGF0aW9uKSAlPiUgCiAgY291bnQocGxhc21pZCwgaG9zdCkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBob3N0LCB2YWx1ZXNfZnJvbSA9IG4pICU+JSAKICBmdWxsX2pvaW4obWV0YSwgYnkgPSAicGxhc21pZCIpICU+JSAKICBzZWxlY3QoLWxldHRlciwgLWdlbm90eXBlKQpgYGAKPiBwSDIxMSB3YXMgbWVhc3VyZWQgOSB0aW1lcyBpbiB0aGUgX1BITzJfIGJhY2tncm91bmQuIFRoZSByZXN1bHRzIHdlcmUgY29uc2lzdGVudC4KCkZvciBlYWNoIGNoaW1lcmEsIHdlIHdvdWxkIGxpa2UgdG8gY2FsY3VsYXRlICoqdGhyZWUgdmFsdWVzKio6CgoxLiBSdkcgaW4gX3BobzLiiIZfOiB0aGlzIGlzIGl0cyBiYXNlIGFjdGl2aXR5IHdpdGhvdXQgUGhvMgoxLiBSdkcgaW4gX1BITzJfOiB0aGlzIGlzIGl0cyBmdWxsIGFjdGl2aXR5IHdpdGggUGhvMgoxLiBSdkdfUEhPMiAvIFJ2R19waG8y4oiGOiB0aGlzIGlzIHRoZSBQaG8yIGVuaGFuY2VtZW50IG9mIGFjdGl2aXR5CgpUaGUgZmlyc3QgdHdvIHZhbHVlcyBhcmUgZnVydGhlciBub3JtYWxpemVkIGFnYWluc3QgdGhlIGNvcnJlc3BvbmRpbmcgU2NQaG80IG1lYXN1cmVtZW50cyBvbiB0aGUgc2FtZSBwbGF0ZS4KYGBge3J9CiMgZmlsdGVyIGRhdGEKdG1wIDwtIGZpbHRlcihkYXROLCAhbG93X2V2ZW50X2NvdW50LCAhbXV0YXRpb24sICFpcy5uYShwbGFzbWlkKSkgJT4lIHNlbGVjdChkYXRlOmhvc3QsIEJMMS5IOlJ2RykKCiMgY2FsY3VsYXRlIHRoZSBTY1BobzQgdmFsdWVzIHBlciBwbGF0ZQptU2NQaG80IDwtIHRtcCAlPiUgZmlsdGVyKHBsYXNtaWQgPT0gIjE5NCIpICU+JSBncm91cF9ieShkYXRlLCBob3N0KSAlPiUgc3VtbWFyaXplKG1lYW4gPSBtZWFuKFJ2RyksIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaG9zdCwgdmFsdWVzX2Zyb20gPSBtZWFuKSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKHZhciA9ICJkYXRlIikKCiMgbm9ybWFsaXplIHRoZSB2YWx1ZXMgZm9yIG5vbi1TY1BobzQgd2l0aCB0aG9zZSBvZiBTY1BobzQgcGVyIHBsYXRlCmRhdE8gPC0gdG1wICU+JSBtdXRhdGUoc1J2RyA9IFJ2RyAvIG1TY1BobzRbY2JpbmQoZGF0ZSwgYXMuY2hhcmFjdGVyKGhvc3QpKV0pCgojIHN1bW1hcml6ZQpkYXRzdW0gPC0gZGF0TyAlPiUgCiAgZ3JvdXBfYnkocGxhc21pZCwgaG9zdCkgJT4lIAogIHN1bW1hcml6ZShhY3Jvc3MoUnZHOnNSdkcsIG1lYW4pLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGhvc3QsIHZhbHVlc19mcm9tID0gUnZHOnNSdkcpICU+JSAKICByZW5hbWUoYEFfUEhPMmAgPSBgUnZHX1BITzJgLCBgQV9waG8yYCA9IGBSdkdfcGhvMuKIhmAsIGZ1bGwgPSBzUnZHX1BITzIsIGJhc2UgPSBgc1J2R19waG8y4oiGYCkgJT4lIAogIG11dGF0ZShib29zdCA9IGBBX1BITzJgIC8gYEFfcGhvMmAsIGFjcm9zcyhgQV9QSE8yYDpib29zdCwgfiByb3VuZCgueCwgZGlnaXRzID0gMykpKSAlPiUgCiAgZnVsbF9qb2luKG1ldGEsIGJ5ID0gInBsYXNtaWQiKQpgYGAKCkV4cG9ydCB0aGUgc3VtbWFyeSBkYXRhCmBgYHtyfQp3cml0ZV90c3YoZGF0c3VtLCBmaWxlID0gIi4uL291dHB1dC8yMDIyMDYxOS1jaGltZXJhLXN1bW1hcnktcmVzdWx0LnRzdiIpCmBgYAoKSGVyZSBhcmUgdGhlIGNoaW1lcmEgdGhhdCBoYXZlIGxpdHRsZSBmdWxsIGFjdGl2aXR5ICh3aXRoIFBobzIpOgpgciBkYXRzdW0gJT4lIGZpbHRlcihmdWxsIDwgMC4yKSAlPiUgYXJyYW5nZShmdWxsKSAlPiUgc2VsZWN0KC1sZXR0ZXIpICU+JSBrbml0cjo6a2FibGUoKWAKCkhlcmUgYXJlIHRoZSBvbmVzIHdpdGggdGhlIGhpZ2hlc3QgYmFzZSBhY3Rpdml0eSAod2l0aG91dCBQaG8yKToKYHIgZGF0c3VtICU+JSBhcnJhbmdlKGRlc2MoYmFzZSkpICU+JSBzZWxlY3QoLWxldHRlcikgJT4lIGhlYWQoMTApICU+JSAga25pdHI6OmthYmxlKClgCgojIyAzLiBQbG90dGluZyBmdW5jdGlvbnMKVGhlIGdvYWwgaGVyZSBpcyB0byBkZXZlbG9wIGEgc2V0IG9mIHBsb3R0aW5nIGZ1bmN0aW9ucyB0byB2aXN1YWxpemUgdGhlIHJlc3VsdHMuCgpGb3IgdGVzdGluZyBwdXJwb3Nlcywgd2Ugd2lsbCBzZWxlY3QgYSBzZXQgb2YgY2hpbWVyYSBhbG9uZyB3aXRoIHRoZSBlbmRvZ2Vub3VzIFNjUGhvNCBhbmQgQ2dQaG80LgpgYGB7cn0KIyBleHRyYWN0IHhpbWVyYSBuYW1lcwpyZWZzIDwtIGMoIkNDQ0NDIiwiU1NTU1MiKQp4aW1lcmFzIDwtIHNldGRpZmYobWV0YSRzeW1ib2wsIHJlZnMpCiMgbWFrZSBhIHRlc3Qgc2V0CnRlc3QgPC0gYyhyZWZzLCBmaWx0ZXIobWV0YSwgcGxhc21pZCAlaW4lIGMoIjIxMSIsICIyMjkiLCAiMjUwIiwgIjIyNCIsICIyNTciLCAiMjE5IiwgIjI2NiIpKSAlPiUgcHVsbChzeW1ib2wpKQojIHN1YnNldCBkYXRhCmRhdFQgPC0gbWV0YSAlPiUgCiAgZmlsdGVyKHN5bWJvbCAlaW4lIHRlc3QpICU+JSAKICBpbm5lcl9qb2luKGRhdE8sIGJ5ID0gInBsYXNtaWQiKSAlPiUgCiAgbXV0YXRlKHN5bWJvbCA9IGZhY3RvcihzeW1ib2wsIGxldmVscyA9IHRlc3QpKQpgYGAKCkRlc2lnbiBhIHNldCBvZiBjb2xvciBwYWxldHRlczoKYGBge3J9CiMgZm9yIHR3byBncm91cHMsIGUuZy4sIHdpdGggdnMgdy9vIFBobzIKY29scy50d28gPC0gYygiUEhPMiIgPSAiIzQ1N2RiYyIsICJwaG8y4oiGIiA9ICIjZWE5ZTI1IikKYGBgCgpQbG90IGluZGl2aWR1YWwgY29tcG9uZW50cyBhbmQgdGhlIG5vcm1hbGl6ZWQgYWN0aXZpdHkgKFJ2RyByYXRpbykKYGBge3IgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9Nn0KZGF0VCAlPiUgCiAgcGl2b3RfbG9uZ2VyKGMobkdGUCwgblJGUCwgUnZHKSwgbmFtZXNfdG8gPSAicGFyYW1ldGVyIiwgdmFsdWVzX3RvID0gImludGVuc2l0eSIpICU+JSAKICBtdXRhdGUocGFyYW1ldGVyID0gb3JkZXJlZChwYXJhbWV0ZXIsIGxldmVscyA9IGMoIm5HRlAiLCAiblJGUCIsICJSdkciKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJQaG80LUdGUCIsICJfUEhPNXByXyA9PiBSRlAiLCAiQWN0aXZpdHkgPSBSRlAvR0ZQIikpKSAlPiUgCiAgI3Bpdm90X2xvbmdlcihCTDEuSDpZTDIuSCwgbmFtZXNfdG8gPSAicGFyYW1ldGVyIiwgdmFsdWVzX3RvID0gImludGVuc2l0eSIpICU+JSAKICAjbXV0YXRlKHBhcmFtZXRlciA9IG9yZGVyZWQocGFyYW1ldGVyLCBsZXZlbHMgPSBjKCJZTDIuSCIsICJCTDEuSCIpKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN5bWJvbCwgeSA9IGludGVuc2l0eSwgZ3JvdXAgPSBob3N0KSkgKyAKICBnZW9tX2JhcihhZXMoZmlsbCA9IGhvc3QpLCB3aWR0aCA9IDAuNSwjIGFscGhhID0gMC44LAogICAgICAgICAgIHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBob3N0KSwgc2l6ZSA9IDEsIGFscGhhID0gMC45LCBzaGFwZSA9IDMsCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMiwgZG9kZ2Uud2lkdGggPSAwLjUpKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCgiY28tVEYiLCB2YWx1ZXMgPSBjKCJQSE8yIiA9ICJncmF5MzAiLCAicGhvMuKIhiIgPSAiZ3JheTQwIikpICsKICBzY2FsZV9maWxsX21hbnVhbCgiY28tVEYiLCB2YWx1ZXMgPSBjb2xzLnR3bykgKwogICNzdGF0X3N1bW1hcnkoZnVuID0gIm1lYW4iLCBnZW9tID0gImNyb3NzYmFyIiwgY29sb3IgPSAicmVkIiwgd2lkdGggPSAwLjI1LAogICMgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjc1KSwgKSArCiAgZmFjZXRfd3JhcCh+cGFyYW1ldGVyLCBzY2FsZSA9ICJmcmVlX3kiLCBuY29sID0gMSkgKwogIHhsYWIoIlBobzQgY2hpbWVyYSIpICsgZXhwYW5kX2xpbWl0cyh5ID0gMCkgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxLCBmYW1pbHkgPSAibW9ubyIpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X21hcmtkb3duKCkpCmBgYAoKUGxvdCB0aGUgUnZHIHZhbHVlcyBub3JtYWxpemVkIGFnYWluc3QgdGhlIGNvcnJlc3BvbmRpbmcgU2NQaG80IGNvbnN0cnVjdCBvbiB0aGUgc2FtZSBwbGF0ZSwgdG8gb2J0YWluIGEgcmVsYXRpdmUgbWVhc3VyZS4KYGBge3J9CiMgdXNlZnVsIHRvIGdyb3VwIHRoZSBwbGFzbWlkcwp4aW1lcmEuZ3JwIDwtIGRhdHN1bSAlPiUgCiAgbXV0YXRlKGdyb3VwID0gY2FzZV93aGVuKAogICAgZnVsbCA8IDAuMiB+ICJkZWZlY3RpdmUiLAogICAgYmFzZSA+IDUgICB+ICJsZXNzIFBobzItZGVwLiIsCiAgICBUUlVFICAgICAgIH4gIm90aGVycyIKICApKSAlPiUgc2VsZWN0KHBsYXNtaWQsIHN5bWJvbCwgZ3JvdXApCmBgYAoKYGBge3IgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9Nn0KcDAgPC0gZGF0VCAlPiUgCiAgbGVmdF9qb2luKHhpbWVyYS5ncnAsIGJ5ID0gYygic3ltYm9sIiwgInBsYXNtaWQiKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN5bWJvbCwgeSA9IHNSdkcsIGdyb3VwID0gaG9zdCkpICsgCiAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBob3N0KSwgd2lkdGggPSAwLjUsIyBhbHBoYSA9IDAuOCwKICAgICAgICAgICBzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gaG9zdCksIHNpemUgPSAxLCBhbHBoYSA9IDAuOSwgc2hhcGUgPSAzLAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShqaXR0ZXIud2lkdGggPSAwLjIsIGRvZGdlLndpZHRoID0gMC41KSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiUEhPMiIgPSAiZ3JheTMwIiwgInBobzLiiIYiID0gImdyYXk0MCIpLCBndWlkZSA9ICJub25lIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbHMudHdvLCBndWlkZSA9ICJub25lIikgKwogICNzdGF0X3N1bW1hcnkoZnVuID0gIm1lYW4iLCBnZW9tID0gImNyb3NzYmFyIiwgY29sb3IgPSAicmVkIiwgd2lkdGggPSAwLjI1LAogICMgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjc1KSwgKSArCiAgZmFjZXRfZ3JpZChob3N0fmdyb3VwLCBzY2FsZSA9ICJmcmVlIikgKwogIHhsYWIoIlBobzQgY2hpbWVyYSIpICsgeWxhYigiQTxzdWI+Y2hpbWVyYTwvc3ViPiAvIEE8c3ViPlNjUGhvNDwvc3ViPiIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKyBiYWNrZ3JvdW5kX2dyaWQobWlub3IgPSAibm9uZSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEsIGZhbWlseSA9ICJtb25vIiksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfbWFya2Rvd24oKSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF9tYXJrZG93bigpKQoKcDEgPC0gZGF0c3VtICU+JSAKICBmaWx0ZXIoc3ltYm9sICVpbiUgdGVzdCkgJT4lIAogIGxlZnRfam9pbih4aW1lcmEuZ3JwLCBieSA9IGMoInBsYXNtaWQiLCAic3ltYm9sIikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzeW1ib2wsIHkgPSBib29zdCkpICsgIAogIGdlb21fY29sKHdpZHRoID0gMC4zLCBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAiZ3JheTgwIikgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZSA9IDIsIGNvbG9yID0gImdyYXkzMCIpICsKICBmYWNldF93cmFwKH5ncm91cCwgc2NhbGVzID0gImZyZWVfeCIpICsgCiAgc2NhbGVfeV9sb2cxMCgpICsKICB4bGFiKCJQaG80IGNoaW1lcmEiKSArIHlsYWIoIkE8c3ViPlBITzI8L3N1Yj4gLyBBPHN1Yj5waG8y4oiGPC9zdWI+IikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE0KSArIGJhY2tncm91bmRfZ3JpZChtaW5vciA9ICJub25lIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSwgZmFtaWx5ID0gIm1vbm8iKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X21hcmtkb3duKCkpCgpzZXRfbnVsbF9kZXZpY2UoInBuZyIpICMgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vd2lsa2VsYWIvY293cGxvdC9pc3N1ZXMvMTc0CnBsb3RfZ3JpZChwMCArIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSksIAogICAgICAgICAgcDEsIG5jb2wgPSAxLCByZWxfaGVpZ2h0cyA9IGMoMywyKSkKYGBgCgpzYXZlIHRoZSBkYXRhIG9iamVjdHMgZm9yIHRoZSBpbnRlcmFjdGl2ZSBkYXRhIHBsb3R0ZXIKYGBge3J9CnNhdmUoZGF0TywgZGF0c3VtLCBtZXRhLCBmaWxlID0gIi4uL3NoaW55YXBwLzIwMjIwNjIwLWRhdGEtZm9yLWludGVyYWN0aXZlLXBsb3R0aW5nLlJEYXRhIikKYGBgCgpEZXNpZ24gdGhlIHBsb3QKYGBge3J9CnRtcHN1bSAlPiUgCiAgbXV0YXRlKEFjdGl2aXR5ID0gaWZlbHNlKGBSL0dfUEhPMmAgPCAyKmxvdy5hY3QudGhbIlIvR19waG8y4oiGIl0sICJsb3ciLCAicGFzcyIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc3ltYm9sLCB5ID0gYHBobzLiiIYvUEhPMmApKSArIAogIGdlb21fY29sKGFlcyhncm91cCA9IGRhdGUsIGZpbGwgPSBgUi9HX1BITzJgKSwgd2lkdGggPSAwLjc1LCBjb2xvciA9ICJncmF5NTAiLAogICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSkgKwogICNnZW9tX3BvaW50KGFlcyhjb2xvciA9IGhvc3QpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGRvZGdlLndpZHRoID0gMC41KSkgKyAKICBzY2FsZV9maWxsX2dyYWRpZW50MigiQWN0aXZpdHkiKSArCiAgI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKGFscGhhKCJibGFjayIsMCksICJyZWQzIikpICsKICAjc3RhdF9zdW1tYXJ5KGZ1biA9ICJtZWFuIiwgY29sb3IgPSAicmVkIiwgZ2VvbSA9ICJjcm9zc2JhciIsIHdpZHRoID0gMC4yLAogICMgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjc1KSwgKSArCiAgZmFjZXRfZ3JpZCgufkFjdGl2aXR5LCBzY2FsZXMgPSAiZnJlZV94Iiwgc3BhY2UgPSAiZnJlZV94IiwgbGFiZWxsZXIgPSAibGFiZWxfYm90aCIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKyB4bGFiKCJQaG80IGNoaW1lcmEiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxLCBmYW1pbHkgPSAibW9ubyIpKQpgYGAKClgtWSBwbG90CmBgYHtyfQpwMyA8LSB0bXBzdW0gJT4lIAogIG11dGF0ZShgblIvR19QSE8yYCA9IHNpZ25pZihgblIvR19QSE8yYCwgZGlnaXRzID0gMiksCiAgICAgICAgIGBuUi9HX3BobzLiiIZgID0gc2lnbmlmKGBuUi9HX3BobzLiiIZgLCBkaWdpdHMgPSAyKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IGBuUi9HX1BITzJgLCB5ID0gYG5SL0dfcGhvMuKIhmAsIGxhYmVsID0gc3ltYm9sKSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAyLjUpICsgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxKSArCiAgdGhlbWVfZ3JheShiYXNlX3NpemUgPSAxNCkKZ2dwbG90bHkocDMsIHRvb2x0aXAgPSBjKCJsYWJlbCIsICJ4IiwgInkiKSkKYGBgCgo=