require(tidyverse)
require(cowplot)

Introduction

Goal

Plotting ASR data for Fig. 1, S1, …

Data

Jinye’s table goes here

Read in data

tmp <- read_tsv("../input/20220726-ASR-CFU-raw.tsv", col_types = cols(), comment = "#")
raw <- read_csv("../input/20221224-ASR-CFU-raw.csv", col_types = cols(), comment = "#") %>% 
  mutate(Date = gsub("d(\\d\\d)(\\d\\d)(\\d\\d)", "\\1/\\2/\\3", Date),
         Len_1 = recode(Len_1, `2hr` = "2 hr", `45min` = "45 min"),
         Len_2 = recode(Len_2, `2hr` = "2 hr")) %>% 
  select(-`MO/MM`, -`PO/PM`) %>% 
  bind_rows(add_column(tmp, Experimenter = "JL"))

# data sanity check, quick view
sapply(select(raw, Species, Strain, Genotype, Len_1, Len_2, H2O2), unique)
$Species
[1] "Cg" "Sc" "Kl"

$Strain
 [1] "yH001" "yH154" "yH181" "yH149" "yH002" "yH609" "yH610" "yH271" "yH272" "yH273" "yH262" "yH275"

$Genotype
[1] "wt"         "rim15Δ"     "cta1Δ"      "msn2Δ"      "msn4Δ"      "msn2Δmsn4Δ"

$Len_1
[1] "45 min"  "2hr"     "90 min"  "135 min"

$Len_2
[1] "2 hr"  "0 min"

$H2O2
 [1] "Mock"   "20mM"   "40mM"   "60mM"   "80mM"   "100mM"  "2mM"    "4mM"    "6mM"    "8mM"    "10mM"   "15mM"   "25mM"  
[14] "30mM"   "35mM"   "1.5mM"  "2.5mM"  "3mM"    "3.5mM"  "0.5mM"  "1mM"    "0.2mM"  "0.3mM"  "0.4mM"  "0.26mM" "0.34mM"
[27] "0 mM"   "20 mM"  "40 mM"  "60 mM"  "80 mM"  "100 mM" "2.2 mM" "2.5 mM" "2 mM"   "4 mM"   "6 mM"   "8 mM"   "10 mM" 

Common plotting functions

species.label <- c(Sc = "S. cerevisiae", Cg = "C. glabrata")

p.survival <- list(
  geom_point(shape = 1, stroke = 1, size = 2, 
             position = position_jitter(width = 0.15)),
  stat_summary(fun = mean, fun.max = mean, fun.min = mean,
               geom = "crossbar", color = "red", width = 0.5),
  facet_wrap(~Species, scales = "free_x", labeller = as_labeller(species.label)),
  theme_cowplot(line_size = 0.7, font_size = 14),
  theme(strip.text = element_text(size = rel(1), face = 3))
)

p.asr <- list(
  geom_hline(yintercept = 1, linetype = 2, color = "gray50"),
  geom_point(position = position_jitter(width = 0.1), size = 2),
  stat_summary(fun.data = "mean_cl_boot", geom = "pointrange", color = "red",
               position = position_nudge(x = 0.2)),
  facet_wrap(~Species, scales = "free_x", labeller = as_labeller(species.label)),
  theme_cowplot(line_size = 0.7),
  theme(strip.text = element_text(size = rel(1.1), face = 3))
)

Fig1: ASR between species

Goal

  • Compare the ASR effect between S. cerevisiae and C. glabrata at 10 mM and 100 mM [H2O2], respectively.

Experiment

Jinye has performed several experiments at these two concentrations, as shown below

raw %>% 
  filter(Genotype == "wt", H2O2 %in% c("10mM", "10 mM", "100mM", "100 mM"),
         Len_1 == "45 min", Group == "PO") %>% 
  mutate(group = paste(recode(Strain, yH154 = "Sc", yH001 = "Cg1", yH002 = "Cg2"), 
                       gsub(" ?mM", "", H2O2), sep = "_")) %>% 
  count(Date, group) %>% 
  pivot_wider(names_from = group, values_from = n)

We will use the 05/30/20, 06/01/20 and 06/04/20 data, which were three consecutive replicates meant to compare the ASR under -Pi between the two species. The other datasets were part of an experiment with different purposes.

Data

Main dataset:

Date Species Replicate
05/30/20 Sc, Cg 1
06/01/20 Sc, Cg 2
06/04/20 Sc, Cg 2

Note: one replicate for Sc on 05/30/20 showed much lower CFU numbers than the other plates.

filter(raw, Date == "05/30/20", Species == "Sc")

Jinye removed the second replicate for both Sc and Cg from her downstream analyses.

Below are the filtered data:

use.f1 <- paste0(c("06/04", "06/01", "05/30"), "/20")
tmp <-  raw %>%
  filter(Date %in% use.f1) %>% 
  mutate(
    scaled = Count * Dilutions * 1e-2
  ) %>% 
  # remove uninformative columns. only one H2O2 conc used for each species
  select(-Strain, -Genotype, -H2O2, -Len_1, -Len_2, -Experimenter)
  
# Assume the triplicates were paired in the order they appear in the table,
# i.e., the first row in the MO, MM, PO, PM groups belong to the same biological 
# replicate, we can derive three ASR_scores for each date x species x Len_1

dat.f1 <- tmp %>% 
  group_by(Date, Species, Group) %>%
  mutate(Repl = row_number()) %>% 
  # group by primary to calculate r (MO/MM) or r' (PO/PM)
  separate(Group, into = c("Primary", "Secondary"), sep = 1) %>% 
  group_by(Date, Species, Repl, Primary) %>% 
  # calculate % survival
  mutate(r = num(scaled / scaled[Secondary == "M"], digits = 3)) %>% 
  # remove the secondary mock as the information are all used
  filter(Secondary != "M") %>% 
  # 5/30/20 replicate 2 is excluded
  filter(!(Date == "05/30/20" & Repl == 2))
dat.f1

Plotting

Plot

dat.f1 %>% 
  mutate(Primary = recode(Primary, M = "Mock", P = "-Pi")) %>% 
  ggplot(aes(x = Primary, y = r)) + p.survival +
  scale_y_continuous(labels = scales::percent) +
  xlab("Primary stress (45 min)") + ylab("% survival")

ggsave("../output/20230228-fig1d-asr-noPi-compare.png", width = 3.5, height = 3)

Statistical tests

Statistical tests

  1. Determine if the basal survival rates are different between species (Wilcoxon signed-rank test)
  2. Determine if the primary stress enhanced the survival in each species (Wilcoxon signed-rank test)

Basal survival rate

The basal survival rates between species within the same day are not “paired”. We will use a rank-sum test here.

tmp <- dat.f1 %>% 
  filter(Primary == "M") %>% 
  pivot_wider(id_cols = c(Date, Repl), names_from = Species, values_from = r)
tmp
with(tmp, t.test(as.numeric(Cg), as.numeric(Sc), paired = FALSE))

    Welch Two Sample t-test

data:  as.numeric(Cg) and as.numeric(Sc)
t = 0.60672, df = 11.515, p-value = 0.5558
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.005202894  0.009192871
sample estimates:
 mean of x  mean of y 
0.01301413 0.01101914 
with(tmp, wilcox.test(Cg, Sc, paired = FALSE))

    Wilcoxon rank sum exact test

data:  Cg and Sc
W = 41, p-value = 0.3823
alternative hypothesis: true location shift is not equal to 0

Primary stress enhanced in Cg

The comparison between r and r’ is paired. We will use a signed-rank test.

tmp <- dat.f1 %>% 
  filter(Species == "Cg") %>% 
  pivot_wider(id_cols = c(Date, Repl), names_from = Primary, values_from = r) %>% 
  mutate(ASR = P/M)
tmp

x <- Hmisc::smean.cl.boot(tmp$ASR)
sprintf("ASR_score mean = %.2f, 95%% CI by bootstrap = [%.2f, %.2f]", x[1], x[2], x[3])
[1] "ASR_score mean = 3.44, 95% CI by bootstrap = [2.66, 4.26]"
with(tmp, t.test(as.numeric(P), as.numeric(M), paired = TRUE, alternative = "g"))

    Paired t-test

data:  as.numeric(P) and as.numeric(M)
t = 5.5041, df = 7, p-value = 0.0004513
alternative hypothesis: true mean difference is greater than 0
95 percent confidence interval:
 0.01921734        Inf
sample estimates:
mean difference 
     0.02930431 
with(tmp, wilcox.test(P, M, paired = TRUE, alternative = "g"))

    Wilcoxon signed rank exact test

data:  P and M
V = 36, p-value = 0.003906
alternative hypothesis: true location shift is greater than 0

Primary stress no effect in Sc

tmp <- dat.f1 %>% 
  filter(Species == "Sc") %>% 
  pivot_wider(id_cols = c(Date, Repl), names_from = Primary, values_from = r) %>% 
  mutate(ASR = P/M)

tmp

x <- Hmisc::smean.cl.boot(tmp$ASR)

sprintf("ASR_score mean = %.2f, 95%% CI by bootstrap = [%.2f, %.2f]", x[1], x[2], x[3])
[1] "ASR_score mean = 1.27, 95% CI by bootstrap = [0.90, 1.63]"
with(tmp, t.test(as.numeric(P), as.numeric(M), paired = TRUE, alternative = "g"))

    Paired t-test

data:  as.numeric(P) and as.numeric(M)
t = -0.10757, df = 7, p-value = 0.5413
alternative hypothesis: true mean difference is greater than 0
95 percent confidence interval:
 -0.003806367          Inf
sample estimates:
mean difference 
  -0.0002045084 
with(tmp, wilcox.test(P, M, paired = TRUE, alternative = "g"))

    Wilcoxon signed rank exact test

data:  P and M
V = 21, p-value = 0.3711
alternative hypothesis: true location shift is greater than 0

S1A: Basal H2O2 resistance

Goal

  • Compare the basal survival rates of the two species at different [H2O2] to identify comparable concentrations for ASR.

Experiment

  • Jinye measured CFU for S. cerevisiae and C. glabrata exposed to a range of [H2O2]

Data

  • Filter the data for the relevant experiments.

Main dataset:

Species H2O2 Description
C. glabrata 0, 20, 40, 60, 80, 100 mM Only M and O, no primary stress
S. cerevisiae 0, 2, 4, 6, 8, 10 mM Only M and O, no primary stress
Date Species Replicate
03/21/22 Sc, Cg 1
03/22/22 Sc, Cg 2
03/24/22 Sc, Cg 3
03/28/22 Sc, Cg 4
04/01/22 Sc, Cg 5
use.s1 <- paste0(c("03/21", "03/22", "03/24", "03/28", "04/01"), "/22")
dat.s1 <- raw %>% select(-Experimenter, -Len_1, -Len_2, -Genotype) %>% 
  mutate(scaled = Count * Dilutions * 1e-3) %>% 
  filter(Date %in% use.s1) %>% 
  group_by(Date, Strain) %>% 
  mutate(r = num(scaled / scaled[Group == "M"], digits = 3))
dat.s1

Plot

p <- dat.s1 %>% 
  mutate(H2O2 = gsub(" mM", "", H2O2),
         H2O2 = fct_reorder(H2O2, as.numeric(H2O2))) %>% 
  filter(H2O2 != "0") %>% 
  ggplot(aes(x = H2O2, y = r)) +
  geom_point(aes(shape = Date)) + 
  #geom_line(aes(group = Date, color = Date), alpha = 0.8) +
  scale_color_brewer(palette = "Dark2") +
  scale_shape_manual(values = 1:5, guide = "none") +
  stat_summary(fun.data = "mean_cl_boot", geom = "pointrange", color = "red2",
               size = 0.8, position = position_nudge(x = 0.3)) +
  facet_wrap(~Species, scales = "free_x", labeller = as_labeller(species.label)) +
  xlab(bquote(H[2]*O[2]~(mM))) + ylab("Basal survial rate (r)") +
  theme_cowplot(line_size = 0.7) +
  theme(strip.text = element_text(size = rel(1), face = 3))
p
ggsave("../output/20230101-basal-survival-across-h2o2-range-sc-cg.png", width = 5, height = 3)

Statistical tests

Statistical test for difference between species at the highest concentration. Using the Wilcoxon rank-sum test (aka Mann-Whitney’s U test)

tmp <- dat.s1 %>% 
  filter(H2O2 %in% c("100 mM", "10 mM"))
tmp %>% group_by(Species) %>% summarize(mean = mean(r))

wilcox.test(r ~ Species, data = tmp, paired = FALSE)

    Wilcoxon rank sum exact test

data:  r by Species
W = 12, p-value = 1
alternative hypothesis: true location shift is not equal to 0

S1B: ASR at different H2O2

Goal

  • Generalize the main figure finding of a stronger ASR in C. glabrata than in S. cerevisiae at a single primary stress treatment length by extending the analysis to multiple length of primary treatment

Data

Main dataset:

Species H2O2 Description
C. glabrata 0, 20, 40, 60, 80, 100 mM full ASR experiment
S. cerevisiae 0, 2, 4, 6, 8, 10mM full ASR experiment
Date Species Strain Replicate
07/16/22 Cg yH001,2 a1
07/17/22 Cg yH001,2 a2
07/18/22 Cg yH001,2 a3
07/29/22 Cg yH001 b1
07/29/22 Sc yH154 b1
08/01/22 Cg yH001 b2
08/01/22 Sc yH154 b2
08/02/22 Cg yH001 b3
08/02/22 Sc yH154 b3
08/04/22 Cg yH001 b4
08/04/22 Sc yH154 b4
08/11/22 Cg yH001 b5
08/11/22 Sc yH154 b5
use.s1b <- paste0(c("07/16", "07/17", "07/18", "07/29", "08/01", "08/02", "08/04", "08/11"), "/22")
dat.s1b <-  raw %>%
  separate(Group, into = c("Primary", "Secondary"), sep = 1) %>% 
  mutate(
    # arbitrarily decide any CFU counts < 3 are not included due to high CV
    Count = ifelse(Count < 3, NA, Count),
    scaled = Count * Dilutions * 1e-3
  ) %>% 
  filter(Date %in% use.s1b) %>% 
  group_by(Date, Strain, Primary) %>% 
  # calculate r and r'
  mutate(r = num(scaled / scaled[Secondary == "M"], digits = 3)) %>% 
  # remove the secondary mock as the information are all used
  filter(Secondary != "M") %>%
  pivot_wider(id_cols = c(Date, Strain, Species, H2O2), 
              names_from = Primary, values_from = r, names_prefix = "r") %>% 
  mutate(ASR_score = rP / rM)
  
dat.s1b

Plot

p <- dat.s1b %>% 
  filter(!is.na(ASR_score)) %>% 
  mutate(H2O2 = gsub(" ?mM", "", H2O2),
         H2O2 = fct_reorder(H2O2, as.numeric(H2O2))) %>% 
  filter(H2O2 != "0") %>% 
  ggplot(aes(x = H2O2, y = ASR_score)) + p.asr +
  #geom_hline(yintercept = 1, linetype = 2, color = "gray50") +
  #geom_point(position = position_jitter(width = 0.1), alpha = 0.8) + 
  #stat_summary(fun.data = "mean_cl_boot", geom = "pointrange", color = "red",
  #             size = 0.8, position = position_nudge(x = 0.2)) +
  #scale_y_log10() +
  #facet_wrap(~Species, scales = "free_x", labeller = as_labeller(species.label)) +
  xlab(bquote(H[2]*O[2]~(mM))) + ylab("ASR score (r'/r)")# +
  #theme_cowplot(line_size = 0.7) +
  #theme(strip.text = element_text(size = rel(1), face = 3))
p
ggsave("../output/20230102-ASR-score-across-h2o2-range-sc-cg.png", width = 5, height = 3)

S2: ASR at different primary stress duration

Goal

  • Generalize the main figure finding of a stronger ASR in C. glabrata than in S. cerevisiae at a single [H2O2] by extending the analysis to multiple concentrations

Data

Main dataset:

Species Len_noPi H2O2 Description
C. glabrata 45, 90, 135 min 100 mM full ASR experiment
S. cerevisiae 45, 90, 135 min 10mM full ASR experiment
Date Species Len_noPi Strain
06/06/20 Cg 45 min yH001
06/06/20 Sc 45 min yH154
06/06/20 Cg 90 min yH001
06/06/20 Sc 90 min yH154
06/06/20 Cg 135 min yH001
06/06/20 Sc 135 min yH154

Supporting dataset:

Date Species Len_noPi Strain
05/30/22 Cg 45 min yH001
05/30/22 Sc 45 min yH154
06/01/22 Cg 45 min yH001
06/01/22 Sc 45 min yH154
06/04/22 Cg 45 min yH001
06/04/22 Sc 45 min yH154
use.s2 <- paste0(c("06/06", "06/04", "06/01", "05/30"), "/20")
tmp <-  raw %>%
  filter(Date %in% use.s2) %>% 
  mutate(
    # arbitrarily decide any CFU counts < 3 are not included due to high CV
    # not in use here. instead, label them in the plot (see below)
    # count = ifelse(Count < 3, NA, Count),
    scaled = Count * Dilutions * 1e-2
  ) %>% 
  # remove uninformative columns. only one H2O2 conc used for each species
  select(-Strain, -Genotype, -H2O2, -Len_2, -Experimenter)

Assume the triplicates were paired in the order they appear in the table, i.e., the first row in the MO, MM, PO, PM groups belong to the same biological replicate, we can derive three ASR_scores for each date x species x Len_1

dat.s2 <- tmp %>% 
  group_by(Date, Species, Len_1, Group) %>%
  mutate(Repl = row_number()) %>% 
  pivot_wider(id_cols = c(Date, Species, Len_1, Repl),
              names_from = Group, values_from = scaled, names_sep = "") %>% 
  mutate(
    r = MO/MM, 
    rp = PO/PM, 
    ASR_score = rp/r,
    low_count = MO < 1 # mark experiments with < 3 counts
  )
dat.s2

Plot

p <- dat.s2 %>% 
  #filter(!is.na(ASR_score)) %>% 
  mutate(len_1 = factor(gsub(" ?min", "", Len_1), levels = c("45", "90", "135"))) %>% 
  ggplot(aes(x = len_1, y = ASR_score)) + p.asr +
#  geom_hline(yintercept = 1, linetype = 2, color = "gray50") +
#  geom_point(position = position_jitter(width = 0.1), size = 2) + 
#  stat_summary(position = position_nudge(x = 0.2),
#               fun.data = "mean_cl_boot", geom = "pointrange", color = "red") +
  xlab("Length of primary stress (min)") + ylab("ASR score (r'/r)") +
#  facet_wrap(~Species, scales = "free_x", labeller = as_labeller(species.label)) +
#  theme_cowplot(line_size = 0.7) +
  theme(legend.text = element_text(size = rel(1), face = 3),
        legend.position = c(0.1, 0.85),
        strip.text = element_text(size = rel(1), face = 3))
p
ggsave("../output/20230103-ASR-score-across-noPi-length-sc-cg.png", width = 5, height = 3)

p <- dat.s2 %>% 
  #filter(!is.na(ASR_score)) %>% 
  mutate(len_1 = factor(Len_1, levels = c("45 min", "90 min", "135 min"))) %>% 
  ggplot(aes(x = Species, y = ASR_score)) +
  geom_point(#aes(fill = low_count),
    position = position_jitter(0.1), size = 1.5, shape = 21) + 
  stat_summary(fun.data = "mean_se", geom = "pointrange", color = "red") +
  #scale_y_log10() +
  scale_shape_manual(values = c(21,22), labels = species.label) +
  #scale_fill_manual(values = c("white", "gray40"), guide = "none") +
  #facet_wrap(~Species, scales = "free_x", labeller = as_labeller(species.label)) +
  facet_wrap(~ len_1, scales = "free") +
  xlab("Length of primary stress (min)") + ylab("ASR score (r'/r)") +
  theme_cowplot(line_size = 0.7)
p
ggsave("../output/20230103-ASR-score-across-noPi-length-sep-panel.png", width = 6, height = 3)

Fig3: cta1∆

Goal

  • Determine if CTA1 is required for the ASR

Experiment

  • Jinye deleted CTA1 and compared ASR in this strain to the wt C. glabrata

Data

Species Strain Genotype H2O2
C. glabrata yH001, yH002 wildtype 80, 100 mM
C. glabrata yH271, yH272 cta1∆ 2.2, 2.5 mM

Six replicates, two each from 07/08, 07/11, 07/12 of 2022.

use.f3 <- paste0(c("07/08", "07/11", "07/12"), "/22")
tmp <-  raw %>%
  filter(Date %in% use.f3) %>% 
  mutate(
    scaled = Count * Dilutions * 1e-2
  ) %>% 
  # remove uninformative columns. only one H2O2 conc used for each species
  select(-Len_1, -Len_2, -Experimenter)
# Assume the replicates were paired in the order they appear in the table,
# i.e., the first row in the MO, MM, PO, PM groups belong to the same biological 
# replicate, we can derive three ASR_scores for each date x species x Len_1

dat.f3 <- tmp %>% 
  # group by primary to calculate r (MO/MM) or r' (PO/PM)
  separate(Group, into = c("Primary", "Secondary"), sep = 1) %>% 
  group_by(Date, Strain, Primary) %>% 
  # calculate % survival
  mutate(r = num(scaled / scaled[Secondary == "M"], digits = 3)) %>% 
  # remove the secondary mock as the information are all used
  filter(Secondary != "M")
dat.f3

Plot (all data)

100 vs 2.5 mM

To be consistent with panel C, we will use the 100 mM vs 2.5 mM pair and leave out the 80 mM vs 2.2 mM pair.

dat.f3a <- dat.f3 %>% 
  mutate( Primary = factor(Primary, levels = c("M", "P"), 
                           labels = c("Mock", "-Pi")),
          Genotype = factor(Genotype, levels = c("wt", "cta1Δ"),
                            labels = c("wildtype", "cta1Δ")),
          Group = factor(H2O2, levels = c("100 mM", "2.5 mM", "80 mM", "2.2 mM"),
                         labels = c("High", "High", "Medium", "Medium"))) %>%
  filter(Group == "High") %>% 
  ungroup()

Plot

p <- ggplot(dat.f3a, aes(x = H2O2, y = r)) +
  geom_point(aes(shape = Primary), stroke = 0.9, size = 2.5, 
             position = position_jitterdodge(jitter.width = 0.3, dodge.width = 0.9)) +
  stat_summary(aes(group = Primary), position = position_dodge(0.9),
               fun = mean, fun.max = mean, fun.min = mean,
               geom = "crossbar", color = "red", width = 0.5) +
  facet_wrap(~ Genotype, nrow = 1, scales = "free_x") +
  scale_shape_manual(name = "Primary stress", values = c("Mock" = 1, "-Pi" = 16)) +
  scale_y_continuous(labels = scales::percent) +
  xlab(bquote(H[2]*O[2]~(mM))) + ylab("% survival") +
  theme_cowplot(line_size = 1.2) +
  panel_border(color = "black", size = 1) +
  theme(strip.text = element_text(size = rel(1)),
        strip.background = element_blank(),
        #strip.placement = "inside",
        axis.line = element_blank(),
        axis.ticks.x = element_blank(),
        legend.position = "top",
        legend.justification = "center",
        legend.margin = margin(b = -10),
        legend.text = element_text(size = rel(0.9)),
        legend.title = element_text(size = rel(0.9)))
p

ggsave("../output/20230301-fig3d-asr-cta1.png", width = 3.5, height = 3.5)

Statistical tests

Statistical test

  1. Determine if the basal survival rates are different between species (Wilcoxon signed-rank test)
  2. Determine if the primary stress enhanced the survival in each species (Wilcoxon signed-rank test)

Basal survival rate Across species, unpaired, rank-sum test.

tmp <- dat.f3a %>% 
  filter(Primary == "Mock") %>% 
  select(Date, Genotype, r) %>% 
  arrange(Genotype)

tmp %>% group_by(Genotype) %>% summarize(mean = mean(r), sd = num(sd(r), digits = 3))

wilcox.test(r ~ Genotype, paired = FALSE, data = tmp)

    Wilcoxon rank sum exact test

data:  r by Genotype
W = 12, p-value = 0.3939
alternative hypothesis: true location shift is not equal to 0

Primary stress enhanced in wildtype

Comparison between r and r’, paired, signed-rank test.

tmp <- dat.f3a %>% 
  filter(Genotype == "wildtype") %>% 
  pivot_wider(id_cols = c(Date, Strain), names_from = Primary, values_from = r) %>% 
  mutate(ASR = `-Pi`/Mock)

tmp

x <- Hmisc::smean.cl.boot(tmp$ASR)
sprintf("ASR_score mean = %.2f, 95%% CI by bootstrap = [%.2f, %.2f]", x[1], x[2], x[3])
[1] "ASR_score mean = 9.79, 95% CI by bootstrap = [5.48, 15.19]"
with(tmp, t.test(as.numeric(`-Pi`), as.numeric(Mock), paired = TRUE, alternative = "g"))

    Paired t-test

data:  as.numeric(`-Pi`) and as.numeric(Mock)
t = 8.8845, df = 5, p-value = 0.0001503
alternative hypothesis: true mean difference is greater than 0
95 percent confidence interval:
 0.0666749       Inf
sample estimates:
mean difference 
     0.08623283 
with(tmp, wilcox.test(`-Pi`, Mock, paired = TRUE, alternative = "g"))

    Wilcoxon signed rank exact test

data:  -Pi and Mock
V = 21, p-value = 0.01563
alternative hypothesis: true location shift is greater than 0
with(tmp, wilcox.test(`-Pi`, Mock, paired = FALSE, alternative = "g"))

    Wilcoxon rank sum exact test

data:  -Pi and Mock
W = 36, p-value = 0.001082
alternative hypothesis: true location shift is greater than 0

Primary stress no effect in cta1Δ

Paired, signed-rank test

tmp <- dat.f3a %>% 
  filter(Genotype == "cta1Δ") %>% 
  pivot_wider(id_cols = c(Date, Strain), names_from = Primary, values_from = r) %>% 
  mutate(ASR = `-Pi`/Mock)

tmp

x <- Hmisc::smean.cl.boot(tmp$ASR)
sprintf("ASR_score mean = %.2f, 95%% CI by bootstrap = [%.2f, %.2f]", x[1], x[2], x[3])
[1] "ASR_score mean = 1.47, 95% CI by bootstrap = [1.18, 1.80]"
with(tmp, t.test(as.numeric(`-Pi`), as.numeric(Mock), paired = TRUE, alternative = "g"))

    Paired t-test

data:  as.numeric(`-Pi`) and as.numeric(Mock)
t = 2.8069, df = 5, p-value = 0.01884
alternative hypothesis: true mean difference is greater than 0
95 percent confidence interval:
 0.002249032         Inf
sample estimates:
mean difference 
    0.007972278 
with(tmp, wilcox.test(`-Pi`, Mock, paired = TRUE, alternative = "g"))

    Wilcoxon signed rank exact test

data:  -Pi and Mock
V = 21, p-value = 0.01563
alternative hypothesis: true location shift is greater than 0
with(tmp, wilcox.test(`-Pi`, Mock, paired = FALSE, alternative = "g"))

    Wilcoxon rank sum exact test

data:  -Pi and Mock
W = 26, p-value = 0.1201
alternative hypothesis: true location shift is greater than 0

80 vs 2.2 mM

Corresponding results for 80 mM vs 2.2 mM

dat.s3b <- dat.f3 %>% 
  mutate( Primary = factor(Primary, levels = c("M", "P"), 
                           labels = c("Mock", "-Pi")),
          Genotype = factor(Genotype, levels = c("wt", "cta1Δ"),
                            labels = c("wildtype", "cta1Δ")),
          Group = factor(H2O2, levels = c("100 mM", "2.5 mM", "80 mM", "2.2 mM"),
                         labels = c("High", "High", "Medium", "Medium"))) %>%
  filter(Group == "Medium") %>% 
  ungroup()

Plot

p <- ggplot(dat.s3b, aes(x = H2O2, y = r)) +
  geom_point(aes(shape = Primary), stroke = 0.9, size = 2.5, 
             position = position_jitterdodge(jitter.width = 0.3, dodge.width = 0.9)) +
  stat_summary(aes(group = Primary), position = position_dodge(0.9),
               fun = mean, fun.max = mean, fun.min = mean,
               geom = "crossbar", color = "red", width = 0.5) +
  facet_wrap(~ Genotype, nrow = 1, scales = "free_x") +
  scale_shape_manual(name = "Primary stress", values = c("Mock" = 1, "-Pi" = 16)) +
  scale_y_continuous(labels = scales::percent) +
  xlab(bquote(H[2]*O[2]~(mM))) + ylab("% survival") +
  theme_cowplot(line_size = 1.2) +
  panel_border(color = "black", size = 1) +
  theme(strip.text = element_text(size = rel(1)),
        strip.background = element_blank(),
        #strip.placement = "inside",
        axis.line = element_blank(),
        axis.ticks.x = element_blank(),
        legend.position = "top",
        legend.justification = "center",
        legend.margin = margin(b = -10),
        legend.text = element_text(size = rel(0.9)),
        legend.title = element_text(size = rel(0.9)))
p

ggsave("../output/20230301-s3b-asr-cta1.png", width = 3.5, height = 3.5)

Statistical tests

Statistical test

  1. Determine if the basal survival rates are different between species (Wilcoxon signed-rank test)
  2. Determine if the primary stress enhanced the survival in each species (Wilcoxon signed-rank test)

Basal survival rate Across species, unpaired, rank-sum test.

tmp <- dat.s3b %>% 
  filter(Primary == "Mock") %>% 
  select(Date, Genotype, r) %>% 
  arrange(Genotype)
tmp %>% group_by(Genotype) %>% summarize(mean = mean(r), sd = num(sd(r), digits = 3))
wilcox.test(r ~ Genotype, paired = FALSE, data = tmp)

    Wilcoxon rank sum exact test

data:  r by Genotype
W = 7, p-value = 0.09307
alternative hypothesis: true location shift is not equal to 0

Primary stress enhanced in wildtype

Comparison between r and r’, paired, signed-rank test.

tmp <- dat.s3b %>% 
  filter(Genotype == "wildtype") %>% 
  pivot_wider(id_cols = c(Date, Strain), names_from = Primary, values_from = r) %>% 
  mutate(ASR = `-Pi`/Mock)

tmp

x <- Hmisc::smean.cl.boot(tmp$ASR)
sprintf("ASR_score mean = %.2f, 95%% CI by bootstrap = [%.2f, %.2f]", x[1], x[2], x[3])
[1] "ASR_score mean = 4.46, 95% CI by bootstrap = [3.77, 5.16]"
with(tmp, t.test(as.numeric(`-Pi`), as.numeric(Mock), paired = TRUE, alternative = "g"))

    Paired t-test

data:  as.numeric(`-Pi`) and as.numeric(Mock)
t = 8.9447, df = 5, p-value = 0.0001455
alternative hypothesis: true mean difference is greater than 0
95 percent confidence interval:
 0.09212352        Inf
sample estimates:
mean difference 
      0.1189116 
with(tmp, wilcox.test(`-Pi`, Mock, paired = TRUE, alternative = "g"))

    Wilcoxon signed rank exact test

data:  -Pi and Mock
V = 21, p-value = 0.01563
alternative hypothesis: true location shift is greater than 0
with(tmp, wilcox.test(`-Pi`, Mock, paired = FALSE, alternative = "g"))

    Wilcoxon rank sum exact test

data:  -Pi and Mock
W = 36, p-value = 0.001082
alternative hypothesis: true location shift is greater than 0

Primary stress no effect in cta1Δ

Paired, signed-rank test

tmp <- dat.s3b %>% 
  filter(Genotype == "cta1Δ") %>% 
  pivot_wider(id_cols = c(Date, Strain), names_from = Primary, values_from = r) %>% 
  mutate(ASR = `-Pi`/Mock)

tmp

x <- Hmisc::smean.cl.boot(tmp$ASR)
sprintf("ASR_score mean = %.2f, 95%% CI by bootstrap = [%.2f, %.2f]", x[1], x[2], x[3])
[1] "ASR_score mean = 0.93, 95% CI by bootstrap = [0.56, 1.38]"
with(tmp, t.test(as.numeric(`-Pi`), as.numeric(Mock), paired = TRUE, alternative = "g"))

    Paired t-test

data:  as.numeric(`-Pi`) and as.numeric(Mock)
t = -0.84267, df = 5, p-value = 0.7811
alternative hypothesis: true mean difference is greater than 0
95 percent confidence interval:
 -0.02818646         Inf
sample estimates:
mean difference 
    -0.00831149 
with(tmp, wilcox.test(`-Pi`, Mock, paired = TRUE, alternative = "g"))

    Wilcoxon signed rank exact test

data:  -Pi and Mock
V = 7, p-value = 0.7812
alternative hypothesis: true location shift is greater than 0
with(tmp, wilcox.test(`-Pi`, Mock, paired = FALSE, alternative = "g"))

    Wilcoxon rank sum exact test

data:  -Pi and Mock
W = 12, p-value = 0.8452
alternative hypothesis: true location shift is greater than 0

Fig6: ASR by rapamycin

Goal

  • Test the hypothesis that direct inhibition of TORC1 can provide ASR in C. glabrata. We will also test S. cerevisiae to determine if the negative regulation by TORC1 on stress response genes behind the ASR is conserved.

Data

Species Rapamycin (ng/mL) H2O2 Description
C. glabrata 50, 62.5, 125, 150 60 mM full ASR experiment
S. cerevisiae 50, 62.5, 125, 150 6 mM full ASR experiment
Date Species Rapa (ng/mL) H2O2 Strain
01/12/23 Cg 62.5, 125 60 mM yH181
01/18/23 Cg 62.5, 125 60 mM yH181
01/21/23 Sc 62.5, 125 4, 6 mM yH154
01/21/23 Cg 62.5, 125 40, 60 mM yH181
01/25/23 Sc 62.5, 125 4, 6 mM yH154
01/25/23 Cg 62.5, 125 40, 60 mM yH181
01/26/23 Sc 62.5, 125 4, 6 mM yH154
01/26/23 Cg 62.5, 125 40, 60 mM yH181
01/31/23 Sc 62.5, 125 4, 6 mM yH154
01/31/23 Cg 62.5, 125 40, 60 mM yH181
02/02/23 Cg 62.5, 125 40, 60 mM yH181

Note

Jinye used lower H2O2 concentration compared with preivous ASR experiments (100 mM for Cg and 10 mM for Sc) because the primary stresses tested here, i.e., rapamycin and nitrogen starvation, reduced survival while phosphate starvation used in previous ASR experiments didn’t. In order to maintain a similar CFU at the end, a lower H2O2 concentration was applied.

dat.6 <- read_csv("../input/20230205-Sc-Cg-rapamycin-nitrogen-ASR-raw.csv", col_types = cols(), comment = "#") %>% 
  mutate(Date = gsub("d(\\d\\d)(\\d\\d)(\\d\\d)", "\\1/\\2/\\3", Date))

# data sanity check, quick view
sapply(select(dat.6, Species, Strain, Genotype), unique)
$Species
[1] "Cg" "Sc"

$Strain
[1] "yH181" "yH154"

$Genotype
[1] "wt"

Plotting

Effect of primary stress (Rapamycin and -N) on survival

Jinye mentioned that unlike phosphate starvation, rapamycin and nitrogen starvation reduce survival by themselves. To see this myself, I’m plotting the CFU after just the primary

tmp <- dat.6 %>% 
  filter(H2O2 == "Mock") %>% 
  group_by(Date, Species) %>% 
  mutate(
    # arbitrarily decide any CFU counts < 3 are not included due to high CV
    Count = ifelse(Count < 3, NA, Count),
    scaled = Count * Dilutions * 1e-2,
    r = scaled / scaled[`1st_Stress` == "Mock"]
  ) %>% 
  ungroup() %>% 
  filter(`1st_Stress` != "Mock") %>% 
  select(Date, Species, Strain, Primary = `1st_Stress`, Count, r)

dat.Prim <-  raw %>%
  separate(Group, into = c("Primary", "Secondary"), sep = 1) %>% 
  # use the S2 dataset to examine the effect of phosphate starvation on survival
  filter(Date %in% use.s1b, Secondary == "M") %>% 
  mutate(
    # arbitrarily decide any CFU counts < 3 are not included due to high CV
    Count = ifelse(Count < 3, NA, Count),
    scaled = Count * Dilutions * 1e-2
  ) %>% 
  group_by(Date, Strain) %>% 
  # calculate r and r'
  mutate(r = scaled / scaled[Primary == "M"]) %>% 
  ungroup() %>% filter(Primary != "M") %>% 
  select(Date, Species, Strain, Primary, Count, r) %>% 
  bind_rows(tmp) %>% 
  mutate(Primary = factor(Primary,
                          levels = c("P", "62.5", "125", "0Ni"),
                          labels = c("-Pi", "Rapa\n62.5", 
                                     "Rapa\n125", "-Nitrogen")))

Statistical tests

Use the nest-map-unnest workflow

dat.Prim %>% 
  select(Species, Primary, r) %>% 
  nest(data = r) %>% 
  mutate(
    test = map(data, ~ t.test(.x, mu = 1, alternative = "two")),
    tidied = map(test, tidy)
  ) %>% 
  unnest(tidied) %>% 
  select(Species, Primary, mean_r = estimate, p.value, conf.low, conf.high, alternative) %>% 
  mutate(P.adj = p.adjust(p.value, method = "BH"),
         across(where(is.numeric), round, digits = 3)) %>% 
  arrange(Species, Primary)

Calibrate secondary stress strength

Jinye used two sets of H2O2 concentrations in this experiment, i.e., 40/4 mM and 60/6 mM for C. glabrata and S. cerevisiae, respectively.

with(dat.6, table(Date, paste(Species, H2O2, sep = ":")))
          
Date       Cg:40mM Cg:60mM Cg:Mock Sc:4mM Sc:6mM Sc:Mock
  01/12/23       0       3       3      0      0       0
  01/18/23       0       3       3      0      0       0
  01/21/23       4       4       4      4      4       4
  01/25/23       4       4       4      4      4       4
  01/26/23       4       4       4      4      4       4
  01/31/23       4       4       4      4      4       4
  02/02/23       4       4       4      0      0       0

First, we will test if the survival under these H2O2 concentrations are comparable across species, by analyzing the basal survival rate r

Statistical test for differences in basal survival between species at 60 or 6 mM. A Wilcoxon signed-rank test is used here since the two groups are dependent (=grouped) by the day of the experiment. One replicate was run per day. Using a paired-test ensures that day-to-day variation is accounted for.

tmp <- dat.6 %>% 
  filter(H2O2 %in% c("60mM", "6mM"), Group == "MO", 
         !(Date %in% c("01/12/23", "01/18/23", "02/02/23")))# %>% 
tmp %>% group_by(Species) %>% summarize(mean = mean(`MO/MM`))
wilcox.test(`MO/MM` ~ Species, data = tmp, paired = TRUE)

    Wilcoxon signed rank exact test

data:  MO/MM by Species
V = 3, p-value = 0.625
alternative hypothesis: true location shift is not equal to 0

Statistical test for differences in basal survival between species at 40 or 4 mM.

tmp <- dat.6 %>% 
  filter(H2O2 %in% c("40mM", "4mM"), Group == "MO", !(Date %in% c("02/02/23")))
tmp %>% group_by(Species) %>% summarize(mean = mean(`MO/MM`))
wilcox.test(`MO/MM` ~ Species, data = tmp, paired = TRUE)

    Wilcoxon signed rank exact test

data:  MO/MM by Species
V = 1, p-value = 0.25
alternative hypothesis: true location shift is not equal to 0

Statistical test for differences in basal survival between the high and low H2O2 concentrations (60/6 vs 40/4 mM), species combined.

tmp <- filter(dat.6, Group == "MO") %>% 
  mutate(secondary = factor(H2O2, levels = c("60mM", "6mM", "40mM", "4mM"),
                            labels = c("high", "high", "low", "low")))
tmp %>% 
  group_by(secondary, Species) %>% 
  summarize(mean = num(mean(`MO/MM`), digits = 3), .groups = "drop")
wilcox.test(`MO/MM` ~ secondary, data = tmp, paired = FALSE)

    Wilcoxon rank sum exact test

data:  MO/MM by secondary
W = 21, p-value = 0.03103
alternative hypothesis: true location shift is not equal to 0
anova(lm(`MO/MM` ~ Species + secondary, data = tmp))
Analysis of Variance Table

Response: MO/MM
          Df    Sum Sq   Mean Sq F value  Pr(>F)  
Species    1 0.0006071 0.0006071  0.3490 0.56246  
secondary  1 0.0078300 0.0078300  4.5011 0.04887 *
Residuals 17 0.0295725 0.0017396                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

We can conclude that there is no significant difference in survival when comparing 40 mM vs 4 mM for C. glabrata vs S. cerevisiae. Similarly, there is no significant difference in survival when 60 mM and 6 mM were used to treat the two species, respectively. However, the survival rate is significantly lower under the higher set of concentrations (60 and 6 mM) compared with the lower ones (40 and 4 mM)

Rapamycin ASR

Will use JY’s pre-calculated ASR values. We will first plot the 40/4 mM and 60/6 mM data separately. Then, we will combine them. A final conclusion will be drawn.

# we will not use the days of experiments where only one species was assayed
dat.6p <- filter(dat.6, H2O2 != "Mock") %>% # remove the XM groups
  rename(primary = `1st_Stress`, r = `MO/MM`, rP = `PO/PM`) %>% 
  group_by(Date, Strain, H2O2) %>% # form groups to apply the same MO/MM
  mutate(r = r[primary == "Mock"], # MO/MM for each group
         secondary = 
           factor(H2O2, levels = c("40mM", "4mM", "60mM", "6mM"),
                  labels = c("40/4mM", "40/4mM", "60/6mM", "60/6mM"))) %>% 
  ungroup() %>%
  filter(!is.na(rP))

my calculation is the same as JY’s

with(dat.6p, sum(round(rP/r, 5) != round(ASR_Score, 5)))
[1] 0

Plot

Statistical test

Wilcoxon signed-rank test comparing r’ and r (paired data)

dat.6p %>% 
  #filter(secondary == "60/6mM") %>% 
  select(Species, primary, r, rP) %>% 
  nest(data = c(r, rP)) %>% 
  mutate(
    test = map(data, ~ wilcox.test(.x$rP, .x$r, paired = TRUE, alternative = "g")),
    tidied = map(test, tidy)
  ) %>% 
  unnest(tidied) %>% 
  select(Species, primary, T = statistic, p.value, method, alternative) %>% 
  mutate(P.adj = p.adjust(p.value, method = "BH"),
         across(where(is.numeric), round, digits = 3))

Paired t-tests comparing r’ and r

dat.6p %>% 
  #filter(primary != "0Ni") %>% 
  select(Species, primary, r, rP) %>% 
  nest(data = c(r, rP)) %>% 
  mutate(
    test = map(data, ~ t.test(.x$rP, .x$r, paired = TRUE, alternative = "g")),
    tidied = map(test, tidy)
  ) %>% 
  unnest(tidied) %>% 
  select(Species, primary, p.value, method, alternative) %>% 
  mutate(P.adj = p.adjust(p.value, method = "BH"),
         across(where(is.numeric), round, digits = 3))

In conclusion, we found significant ASR effect at 125 ng/mL rapamycin treatment in C. glabrata using either a Wilcoxon signed-rank test (nonparametric) or a paired t test, both using a 0.05 rejection threhold. We couldn’t reject the null hypothesis of no survival difference between rapamycin treated vs untreated samples for the 62.5 ng/mL concentration, and also not for the higher dose in S. cerevisiae

LS0tCnRpdGxlOiAiUGxvdCBBU1IgcGhlb250eXBpYyByZXN1bHRzIgphdXRob3I6IEJpbiBIZQpkYXRlOiAiMjAyMy0xLTEgKHVwZGF0ZWQgYHIgU3lzLkRhdGUoKWApIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRoZW1lOiBjZXJ1bGVhbgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKYGBge3Igc2V0dXAsIG1lc3NhZ2U9RkFMU0V9CnJlcXVpcmUodGlkeXZlcnNlKQpyZXF1aXJlKGNvd3Bsb3QpCnJlcXVpcmUoYnJvb20pCmBgYAoKIyMgSW50cm9kdWN0aW9uCiMjIyBHb2FsCgpQbG90dGluZyBBU1IgZGF0YSBmb3IgRmlnLiAxLCBTMSwgLi4uCgojIyMgRGF0YQpKaW55ZSdzIHRhYmxlIGdvZXMgaGVyZQoKUmVhZCBpbiBkYXRhCmBgYHtyfQp0bXAgPC0gcmVhZF90c3YoIi4uL2lucHV0LzIwMjIwNzI2LUFTUi1DRlUtcmF3LnRzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSwgY29tbWVudCA9ICIjIikKcmF3IDwtIHJlYWRfY3N2KCIuLi9pbnB1dC8yMDIyMTIyNC1BU1ItQ0ZVLXJhdy5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCksIGNvbW1lbnQgPSAiIyIpICU+JSAKICBtdXRhdGUoRGF0ZSA9IGdzdWIoImQoXFxkXFxkKShcXGRcXGQpKFxcZFxcZCkiLCAiXFwxL1xcMi9cXDMiLCBEYXRlKSwKICAgICAgICAgTGVuXzEgPSByZWNvZGUoTGVuXzEsIGAyaHJgID0gIjIgaHIiLCBgNDVtaW5gID0gIjQ1IG1pbiIpLAogICAgICAgICBMZW5fMiA9IHJlY29kZShMZW5fMiwgYDJocmAgPSAiMiBociIpKSAlPiUgCiAgc2VsZWN0KC1gTU8vTU1gLCAtYFBPL1BNYCkgJT4lIAogIGJpbmRfcm93cyhhZGRfY29sdW1uKHRtcCwgRXhwZXJpbWVudGVyID0gIkpMIikpCgojIGRhdGEgc2FuaXR5IGNoZWNrLCBxdWljayB2aWV3CnNhcHBseShzZWxlY3QocmF3LCBTcGVjaWVzLCBTdHJhaW4sIEdlbm90eXBlLCBMZW5fMSwgTGVuXzIsIEgyTzIpLCB1bmlxdWUpCmBgYAoKIyMjIENvbW1vbiBwbG90dGluZyBmdW5jdGlvbnMKCmBgYHtyfQpzcGVjaWVzLmxhYmVsIDwtIGMoU2MgPSAiUy4gY2VyZXZpc2lhZSIsIENnID0gIkMuIGdsYWJyYXRhIikKCnAuc3Vydml2YWwgPC0gbGlzdCgKICBnZW9tX3BvaW50KHNoYXBlID0gMSwgc3Ryb2tlID0gMSwgc2l6ZSA9IDIsIAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjE1KSksCiAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sIGZ1bi5tYXggPSBtZWFuLCBmdW4ubWluID0gbWVhbiwKICAgICAgICAgICAgICAgZ2VvbSA9ICJjcm9zc2JhciIsIGNvbG9yID0gInJlZCIsIHdpZHRoID0gMC41KSwKICBmYWNldF93cmFwKH5TcGVjaWVzLCBzY2FsZXMgPSAiZnJlZV94IiwgbGFiZWxsZXIgPSBhc19sYWJlbGxlcihzcGVjaWVzLmxhYmVsKSksCiAgdGhlbWVfY293cGxvdChsaW5lX3NpemUgPSAwLjcsIGZvbnRfc2l6ZSA9IDE0KSwKICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMSksIGZhY2UgPSAzKSkKKQoKcC5hc3IgPC0gbGlzdCgKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLCBsaW5ldHlwZSA9IDIsIGNvbG9yID0gImdyYXk1MCIpLAogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjEpLCBzaXplID0gMiksCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gIm1lYW5fY2xfYm9vdCIsIGdlb20gPSAicG9pbnRyYW5nZSIsIGNvbG9yID0gInJlZCIsCiAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoeCA9IDAuMikpLAogIGZhY2V0X3dyYXAoflNwZWNpZXMsIHNjYWxlcyA9ICJmcmVlX3giLCBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKHNwZWNpZXMubGFiZWwpKSwKICB0aGVtZV9jb3dwbG90KGxpbmVfc2l6ZSA9IDAuNyksCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMSksIGZhY2UgPSAzKSkKKQpgYGAKCgojIyBGaWcxOiBBU1IgYmV0d2VlbiBzcGVjaWVzCl8qKkdvYWwqKl8KCi0gQ29tcGFyZSB0aGUgQVNSIGVmZmVjdCBiZXR3ZWVuIF9TLiBjZXJldmlzaWFlXyBhbmQgX0MuIGdsYWJyYXRhXyBhdCAxMCBtTSBhbmQgMTAwIG1NIFtIMk8yXSwgcmVzcGVjdGl2ZWx5LgoKXyoqRXhwZXJpbWVudCoqXwoKSmlueWUgaGFzIHBlcmZvcm1lZCBzZXZlcmFsIGV4cGVyaW1lbnRzIGF0IHRoZXNlIHR3byBjb25jZW50cmF0aW9ucywgYXMgc2hvd24gYmVsb3cKYGBge3J9CnJhdyAlPiUgCiAgZmlsdGVyKEdlbm90eXBlID09ICJ3dCIsIEgyTzIgJWluJSBjKCIxMG1NIiwgIjEwIG1NIiwgIjEwMG1NIiwgIjEwMCBtTSIpLAogICAgICAgICBMZW5fMSA9PSAiNDUgbWluIiwgR3JvdXAgPT0gIlBPIikgJT4lIAogIG11dGF0ZShncm91cCA9IHBhc3RlKHJlY29kZShTdHJhaW4sIHlIMTU0ID0gIlNjIiwgeUgwMDEgPSAiQ2cxIiwgeUgwMDIgPSAiQ2cyIiksIAogICAgICAgICAgICAgICAgICAgICAgIGdzdWIoIiA/bU0iLCAiIiwgSDJPMiksIHNlcCA9ICJfIikpICU+JSAKICBjb3VudChEYXRlLCBncm91cCkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBncm91cCwgdmFsdWVzX2Zyb20gPSBuKQpgYGAKV2Ugd2lsbCB1c2UgdGhlIDA1LzMwLzIwLCAwNi8wMS8yMCBhbmQgMDYvMDQvMjAgZGF0YSwgd2hpY2ggd2VyZSB0aHJlZSBjb25zZWN1dGl2ZSByZXBsaWNhdGVzIG1lYW50IHRvIGNvbXBhcmUgdGhlIEFTUiB1bmRlciAtUGkgYmV0d2VlbiB0aGUgdHdvIHNwZWNpZXMuIFRoZSBvdGhlciBkYXRhc2V0cyB3ZXJlIHBhcnQgb2YgYW4gZXhwZXJpbWVudCB3aXRoIGRpZmZlcmVudCBwdXJwb3Nlcy4KCl8qKkRhdGEqKl8KCioqTWFpbiBkYXRhc2V0Kio6IAoKRGF0ZSAgICAgICBTcGVjaWVzICAgUmVwbGljYXRlCi0tLS0tLS0tICAgLS0tLS0tLS0gIC0tLS0tLS0tLS0KMDUvMzAvMjAgICBTYywgQ2cgICAgMQowNi8wMS8yMCAgIFNjLCBDZyAgICAyCjA2LzA0LzIwICAgU2MsIENnICAgIDIKCioqTm90ZSoqOiBvbmUgcmVwbGljYXRlIGZvciBTYyBvbiAwNS8zMC8yMCBzaG93ZWQgbXVjaCBsb3dlciBDRlUgbnVtYmVycyB0aGFuIHRoZSBvdGhlciBwbGF0ZXMuCmBgYHtyfQpmaWx0ZXIocmF3LCBEYXRlID09ICIwNS8zMC8yMCIsIFNwZWNpZXMgPT0gIlNjIikKYGBgCkppbnllIHJlbW92ZWQgdGhlIHNlY29uZCByZXBsaWNhdGUgZm9yIGJvdGggU2MgYW5kIENnIGZyb20gaGVyIGRvd25zdHJlYW0gYW5hbHlzZXMuCgpCZWxvdyBhcmUgdGhlIGZpbHRlcmVkIGRhdGE6CgpgYGB7cn0KdXNlLmYxIDwtIHBhc3RlMChjKCIwNi8wNCIsICIwNi8wMSIsICIwNS8zMCIpLCAiLzIwIikKdG1wIDwtICByYXcgJT4lCiAgZmlsdGVyKERhdGUgJWluJSB1c2UuZjEpICU+JSAKICBtdXRhdGUoCiAgICBzY2FsZWQgPSBDb3VudCAqIERpbHV0aW9ucyAqIDFlLTIKICApICU+JSAKICAjIHJlbW92ZSB1bmluZm9ybWF0aXZlIGNvbHVtbnMuIG9ubHkgb25lIEgyTzIgY29uYyB1c2VkIGZvciBlYWNoIHNwZWNpZXMKICBzZWxlY3QoLVN0cmFpbiwgLUdlbm90eXBlLCAtSDJPMiwgLUxlbl8xLCAtTGVuXzIsIC1FeHBlcmltZW50ZXIpCiAgCiMgQXNzdW1lIHRoZSB0cmlwbGljYXRlcyB3ZXJlIHBhaXJlZCBpbiB0aGUgb3JkZXIgdGhleSBhcHBlYXIgaW4gdGhlIHRhYmxlLAojIGkuZS4sIHRoZSBmaXJzdCByb3cgaW4gdGhlIE1PLCBNTSwgUE8sIFBNIGdyb3VwcyBiZWxvbmcgdG8gdGhlIHNhbWUgYmlvbG9naWNhbCAKIyByZXBsaWNhdGUsIHdlIGNhbiBkZXJpdmUgdGhyZWUgQVNSX3Njb3JlcyBmb3IgZWFjaCBkYXRlIHggc3BlY2llcyB4IExlbl8xCgpkYXQuZjEgPC0gdG1wICU+JSAKICBncm91cF9ieShEYXRlLCBTcGVjaWVzLCBHcm91cCkgJT4lCiAgbXV0YXRlKFJlcGwgPSByb3dfbnVtYmVyKCkpICU+JSAKICAjIGdyb3VwIGJ5IHByaW1hcnkgdG8gY2FsY3VsYXRlIHIgKE1PL01NKSBvciByJyAoUE8vUE0pCiAgc2VwYXJhdGUoR3JvdXAsIGludG8gPSBjKCJQcmltYXJ5IiwgIlNlY29uZGFyeSIpLCBzZXAgPSAxKSAlPiUgCiAgZ3JvdXBfYnkoRGF0ZSwgU3BlY2llcywgUmVwbCwgUHJpbWFyeSkgJT4lIAogICMgY2FsY3VsYXRlICUgc3Vydml2YWwKICBtdXRhdGUociA9IG51bShzY2FsZWQgLyBzY2FsZWRbU2Vjb25kYXJ5ID09ICJNIl0sIGRpZ2l0cyA9IDMpKSAlPiUgCiAgIyByZW1vdmUgdGhlIHNlY29uZGFyeSBtb2NrIGFzIHRoZSBpbmZvcm1hdGlvbiBhcmUgYWxsIHVzZWQKICBmaWx0ZXIoU2Vjb25kYXJ5ICE9ICJNIikgJT4lIAogICMgNS8zMC8yMCByZXBsaWNhdGUgMiBpcyBleGNsdWRlZAogIGZpbHRlcighKERhdGUgPT0gIjA1LzMwLzIwIiAmIFJlcGwgPT0gMikpCmRhdC5mMQpgYGAKCl8qKlBsb3R0aW5nKipfCgojIyMjIFBsb3QKYGBge3J9CmRhdC5mMSAlPiUgCiAgbXV0YXRlKFByaW1hcnkgPSByZWNvZGUoUHJpbWFyeSwgTSA9ICJNb2NrIiwgUCA9ICItUGkiKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IFByaW1hcnksIHkgPSByKSkgKyBwLnN1cnZpdmFsICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArCiAgeGxhYigiUHJpbWFyeSBzdHJlc3MgKDQ1IG1pbikiKSArIHlsYWIoIiUgc3Vydml2YWwiKQoKZ2dzYXZlKCIuLi9vdXRwdXQvMjAyMzAyMjgtZmlnMWQtYXNyLW5vUGktY29tcGFyZS5wbmciLCB3aWR0aCA9IDMuNSwgaGVpZ2h0ID0gMykKYGBgCgpfKipTdGF0aXN0aWNhbCB0ZXN0cyoqXwoKIyMjIyBTdGF0aXN0aWNhbCB0ZXN0cwoxLiBEZXRlcm1pbmUgaWYgdGhlIGJhc2FsIHN1cnZpdmFsIHJhdGVzIGFyZSBkaWZmZXJlbnQgYmV0d2VlbiBzcGVjaWVzIChXaWxjb3hvbiBzaWduZWQtcmFuayB0ZXN0KQoxLiBEZXRlcm1pbmUgaWYgdGhlIHByaW1hcnkgc3RyZXNzIGVuaGFuY2VkIHRoZSBzdXJ2aXZhbCBpbiBfZWFjaF8gc3BlY2llcyAoV2lsY294b24gc2lnbmVkLXJhbmsgdGVzdCkKCl9CYXNhbCBzdXJ2aXZhbCByYXRlXwoKVGhlIGJhc2FsIHN1cnZpdmFsIHJhdGVzIGJldHdlZW4gc3BlY2llcyB3aXRoaW4gdGhlIHNhbWUgZGF5IGFyZSBub3QgInBhaXJlZCIuIFdlIHdpbGwgdXNlIGEgcmFuay1zdW0gdGVzdCBoZXJlLgpgYGB7cn0KdG1wIDwtIGRhdC5mMSAlPiUgCiAgZmlsdGVyKFByaW1hcnkgPT0gIk0iKSAlPiUgCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMoRGF0ZSwgUmVwbCksIG5hbWVzX2Zyb20gPSBTcGVjaWVzLCB2YWx1ZXNfZnJvbSA9IHIpCnRtcAp3aXRoKHRtcCwgdC50ZXN0KGFzLm51bWVyaWMoQ2cpLCBhcy5udW1lcmljKFNjKSwgcGFpcmVkID0gRkFMU0UpKQoKd2l0aCh0bXAsIHdpbGNveC50ZXN0KENnLCBTYywgcGFpcmVkID0gRkFMU0UpKQpgYGAKX1ByaW1hcnkgc3RyZXNzIGVuaGFuY2VkIGluIENnXwoKVGhlIGNvbXBhcmlzb24gYmV0d2VlbiByIGFuZCByJyBpcyBwYWlyZWQuIFdlIHdpbGwgdXNlIGEgc2lnbmVkLXJhbmsgdGVzdC4KYGBge3J9CnRtcCA8LSBkYXQuZjEgJT4lIAogIGZpbHRlcihTcGVjaWVzID09ICJDZyIpICU+JSAKICBwaXZvdF93aWRlcihpZF9jb2xzID0gYyhEYXRlLCBSZXBsKSwgbmFtZXNfZnJvbSA9IFByaW1hcnksIHZhbHVlc19mcm9tID0gcikgJT4lIAogIG11dGF0ZShBU1IgPSBQL00pCnRtcAoKeCA8LSBIbWlzYzo6c21lYW4uY2wuYm9vdCh0bXAkQVNSKQpzcHJpbnRmKCJBU1Jfc2NvcmUgbWVhbiA9ICUuMmYsIDk1JSUgQ0kgYnkgYm9vdHN0cmFwID0gWyUuMmYsICUuMmZdIiwgeFsxXSwgeFsyXSwgeFszXSkKCndpdGgodG1wLCB0LnRlc3QoYXMubnVtZXJpYyhQKSwgYXMubnVtZXJpYyhNKSwgcGFpcmVkID0gVFJVRSwgYWx0ZXJuYXRpdmUgPSAiZyIpKQoKd2l0aCh0bXAsIHdpbGNveC50ZXN0KFAsIE0sIHBhaXJlZCA9IFRSVUUsIGFsdGVybmF0aXZlID0gImciKSkKYGBgCgpfUHJpbWFyeSBzdHJlc3Mgbm8gZWZmZWN0IGluIFNjXwoKYGBge3J9CnRtcCA8LSBkYXQuZjEgJT4lIAogIGZpbHRlcihTcGVjaWVzID09ICJTYyIpICU+JSAKICBwaXZvdF93aWRlcihpZF9jb2xzID0gYyhEYXRlLCBSZXBsKSwgbmFtZXNfZnJvbSA9IFByaW1hcnksIHZhbHVlc19mcm9tID0gcikgJT4lIAogIG11dGF0ZShBU1IgPSBQL00pCgp0bXAKCnggPC0gSG1pc2M6OnNtZWFuLmNsLmJvb3QodG1wJEFTUikKCnNwcmludGYoIkFTUl9zY29yZSBtZWFuID0gJS4yZiwgOTUlJSBDSSBieSBib290c3RyYXAgPSBbJS4yZiwgJS4yZl0iLCB4WzFdLCB4WzJdLCB4WzNdKQoKd2l0aCh0bXAsIHQudGVzdChhcy5udW1lcmljKFApLCBhcy5udW1lcmljKE0pLCBwYWlyZWQgPSBUUlVFLCBhbHRlcm5hdGl2ZSA9ICJnIikpCgp3aXRoKHRtcCwgd2lsY294LnRlc3QoUCwgTSwgcGFpcmVkID0gVFJVRSwgYWx0ZXJuYXRpdmUgPSAiZyIpKQpgYGAKCgojIyBTMUE6IEJhc2FsIEgyTzIgcmVzaXN0YW5jZQpfKipHb2FsKipfCgotIENvbXBhcmUgdGhlIGJhc2FsIHN1cnZpdmFsIHJhdGVzIG9mIHRoZSB0d28gc3BlY2llcyBhdCBkaWZmZXJlbnQgW0gyTzJdIHRvIGlkZW50aWZ5IGNvbXBhcmFibGUgY29uY2VudHJhdGlvbnMgZm9yIEFTUi4KCl8qKkV4cGVyaW1lbnQqKl8KCi0gSmlueWUgbWVhc3VyZWQgQ0ZVIGZvciBfUy4gY2VyZXZpc2lhZV8gYW5kIF9DLiBnbGFicmF0YV8gZXhwb3NlZCB0byBhIHJhbmdlIG9mIFtIMk8yXQoKXyoqRGF0YSoqXwoKLSBGaWx0ZXIgdGhlIGRhdGEgZm9yIHRoZSByZWxldmFudCBleHBlcmltZW50cy4KCioqTWFpbiBkYXRhc2V0Kio6IAoKU3BlY2llcyAgICAgICAgIEgyTzIgICAgICAgICAgICAgICAgICAgICAgICBEZXNjcmlwdGlvbgotLS0tLS0tLS0tLS0tLSAgLS0tLS0tLS0tLS0tLSAgICAgICAgICAgICAgIC0tLS0tLS0tLS0tLS0tLQpDLiBnbGFicmF0YSAgICAgMCwgMjAsIDQwLCA2MCwgODAsIDEwMCBtTSAgIE9ubHkgTSBhbmQgTywgbm8gcHJpbWFyeSBzdHJlc3MKUy4gY2VyZXZpc2lhZSAgIDAsIDIsIDQsIDYsIDgsIDEwIG1NICAgICAgICBPbmx5IE0gYW5kIE8sIG5vIHByaW1hcnkgc3RyZXNzCgpEYXRlICAgICAgIFNwZWNpZXMgICBSZXBsaWNhdGUKLS0tLS0tLS0gICAtLS0tLS0tLSAgLS0tLS0tLS0tLQowMy8yMS8yMiAgIFNjLCBDZyAgICAxCjAzLzIyLzIyICAgU2MsIENnICAgIDIKMDMvMjQvMjIgICBTYywgQ2cgICAgMwowMy8yOC8yMiAgIFNjLCBDZyAgICA0CjA0LzAxLzIyICAgU2MsIENnICAgIDUKCgpgYGB7cn0KdXNlLnMxIDwtIHBhc3RlMChjKCIwMy8yMSIsICIwMy8yMiIsICIwMy8yNCIsICIwMy8yOCIsICIwNC8wMSIpLCAiLzIyIikKZGF0LnMxIDwtIHJhdyAlPiUgc2VsZWN0KC1FeHBlcmltZW50ZXIsIC1MZW5fMSwgLUxlbl8yLCAtR2Vub3R5cGUpICU+JSAKICBtdXRhdGUoc2NhbGVkID0gQ291bnQgKiBEaWx1dGlvbnMgKiAxZS0zKSAlPiUgCiAgZmlsdGVyKERhdGUgJWluJSB1c2UuczEpICU+JSAKICBncm91cF9ieShEYXRlLCBTdHJhaW4pICU+JSAKICBtdXRhdGUociA9IG51bShzY2FsZWQgLyBzY2FsZWRbR3JvdXAgPT0gIk0iXSwgZGlnaXRzID0gMykpCmRhdC5zMQpgYGAKIyMjIyBQbG90CgpgYGB7cn0KcCA8LSBkYXQuczEgJT4lIAogIG11dGF0ZShIMk8yID0gZ3N1YigiIG1NIiwgIiIsIEgyTzIpLAogICAgICAgICBIMk8yID0gZmN0X3Jlb3JkZXIoSDJPMiwgYXMubnVtZXJpYyhIMk8yKSkpICU+JSAKICBmaWx0ZXIoSDJPMiAhPSAiMCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBIMk8yLCB5ID0gcikpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IERhdGUpKSArIAogICNnZW9tX2xpbmUoYWVzKGdyb3VwID0gRGF0ZSwgY29sb3IgPSBEYXRlKSwgYWxwaGEgPSAwLjgpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gMTo1LCBndWlkZSA9ICJub25lIikgKwogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX2NsX2Jvb3QiLCBnZW9tID0gInBvaW50cmFuZ2UiLCBjb2xvciA9ICJyZWQyIiwKICAgICAgICAgICAgICAgc2l6ZSA9IDAuOCwgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4zKSkgKwogIGZhY2V0X3dyYXAoflNwZWNpZXMsIHNjYWxlcyA9ICJmcmVlX3giLCBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKHNwZWNpZXMubGFiZWwpKSArCiAgeGxhYihicXVvdGUoSFsyXSpPWzJdfihtTSkpKSArIHlsYWIoIkJhc2FsIHN1cnZpYWwgcmF0ZSAocikiKSArCiAgdGhlbWVfY293cGxvdChsaW5lX3NpemUgPSAwLjcpICsKICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMSksIGZhY2UgPSAzKSkKcApnZ3NhdmUoIi4uL291dHB1dC8yMDIzMDEwMS1iYXNhbC1zdXJ2aXZhbC1hY3Jvc3MtaDJvMi1yYW5nZS1zYy1jZy5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMpCmBgYAoKIyMjIyBTdGF0aXN0aWNhbCB0ZXN0cwpTdGF0aXN0aWNhbCB0ZXN0IGZvciBkaWZmZXJlbmNlIGJldHdlZW4gc3BlY2llcyBhdCB0aGUgaGlnaGVzdCBjb25jZW50cmF0aW9uLiBVc2luZyB0aGUgV2lsY294b24gcmFuay1zdW0gdGVzdCAoYWthIE1hbm4tV2hpdG5leSdzIFUgdGVzdCkKYGBge3J9CnRtcCA8LSBkYXQuczEgJT4lIAogIGZpbHRlcihIMk8yICVpbiUgYygiMTAwIG1NIiwgIjEwIG1NIikpCnRtcCAlPiUgZ3JvdXBfYnkoU3BlY2llcykgJT4lIHN1bW1hcml6ZShtZWFuID0gbWVhbihyKSkKCndpbGNveC50ZXN0KHIgfiBTcGVjaWVzLCBkYXRhID0gdG1wLCBwYWlyZWQgPSBGQUxTRSkKYGBgCgojIyBTMUI6IEFTUiBhdCBkaWZmZXJlbnQgSDJPMgpfKipHb2FsKipfCgotIEdlbmVyYWxpemUgdGhlIG1haW4gZmlndXJlIGZpbmRpbmcgb2YgYSBzdHJvbmdlciBBU1IgaW4gX0MuIGdsYWJyYXRhXyB0aGFuIGluIF9TLiBjZXJldmlzaWFlXyBhdCBhIHNpbmdsZSBwcmltYXJ5IHN0cmVzcyB0cmVhdG1lbnQgbGVuZ3RoIGJ5IGV4dGVuZGluZyB0aGUgYW5hbHlzaXMgdG8gbXVsdGlwbGUgbGVuZ3RoIG9mIHByaW1hcnkgdHJlYXRtZW50CgpfKipEYXRhKipfCgoqKk1haW4gZGF0YXNldCoqOiAKClNwZWNpZXMgICAgICAgSDJPMiAgICAgICAgICAgICAgICAgICAgICAgRGVzY3JpcHRpb24gCi0tLS0tLS0tICAgICAgLS0tLS0gICAgICAgICAgICAgICAgICAgICAgLS0tLS0tLS0tLS0tCkMuIGdsYWJyYXRhICAgMCwgMjAsIDQwLCA2MCwgODAsIDEwMCBtTSAgZnVsbCBBU1IgZXhwZXJpbWVudApTLiBjZXJldmlzaWFlIDAsIDIsIDQsIDYsIDgsIDEwbU0gICAgICAgIGZ1bGwgQVNSIGV4cGVyaW1lbnQKCkRhdGUgICAgICAgU3BlY2llcyAgIFN0cmFpbiAgICBSZXBsaWNhdGUKLS0tLS0gICAgICAtLS0tLS0tLSAgLS0tLS0tLSAgIC0tLS0tLS0tLS0KMDcvMTYvMjIgICBDZyAgICAgICAgeUgwMDEsMiAgICBhMQowNy8xNy8yMiAgIENnICAgICAgICB5SDAwMSwyICAgIGEyCjA3LzE4LzIyICAgQ2cgICAgICAgIHlIMDAxLDIgICAgYTMKMDcvMjkvMjIgICBDZyAgICAgICAgeUgwMDEgICAgICBiMQowNy8yOS8yMiAgIFNjICAgICAgICB5SDE1NCAgICAgIGIxCjA4LzAxLzIyICAgQ2cgICAgICAgIHlIMDAxICAgICAgYjIKMDgvMDEvMjIgICBTYyAgICAgICAgeUgxNTQgICAgICBiMgowOC8wMi8yMiAgIENnICAgICAgICB5SDAwMSAgICAgIGIzCjA4LzAyLzIyICAgU2MgICAgICAgIHlIMTU0ICAgICAgYjMKMDgvMDQvMjIgICBDZyAgICAgICAgeUgwMDEgICAgICBiNAowOC8wNC8yMiAgIFNjICAgICAgICB5SDE1NCAgICAgIGI0CjA4LzExLzIyICAgQ2cgICAgICAgIHlIMDAxICAgICAgYjUKMDgvMTEvMjIgICBTYyAgICAgICAgeUgxNTQgICAgICBiNQoKCmBgYHtyfQp1c2UuczFiIDwtIHBhc3RlMChjKCIwNy8xNiIsICIwNy8xNyIsICIwNy8xOCIsICIwNy8yOSIsICIwOC8wMSIsICIwOC8wMiIsICIwOC8wNCIsICIwOC8xMSIpLCAiLzIyIikKZGF0LnMxYiA8LSAgcmF3ICU+JQogIHNlcGFyYXRlKEdyb3VwLCBpbnRvID0gYygiUHJpbWFyeSIsICJTZWNvbmRhcnkiKSwgc2VwID0gMSkgJT4lIAogIG11dGF0ZSgKICAgICMgYXJiaXRyYXJpbHkgZGVjaWRlIGFueSBDRlUgY291bnRzIDwgMyBhcmUgbm90IGluY2x1ZGVkIGR1ZSB0byBoaWdoIENWCiAgICBDb3VudCA9IGlmZWxzZShDb3VudCA8IDMsIE5BLCBDb3VudCksCiAgICBzY2FsZWQgPSBDb3VudCAqIERpbHV0aW9ucyAqIDFlLTMKICApICU+JSAKICBmaWx0ZXIoRGF0ZSAlaW4lIHVzZS5zMWIpICU+JSAKICBncm91cF9ieShEYXRlLCBTdHJhaW4sIFByaW1hcnkpICU+JSAKICAjIGNhbGN1bGF0ZSByIGFuZCByJwogIG11dGF0ZShyID0gbnVtKHNjYWxlZCAvIHNjYWxlZFtTZWNvbmRhcnkgPT0gIk0iXSwgZGlnaXRzID0gMykpICU+JSAKICAjIHJlbW92ZSB0aGUgc2Vjb25kYXJ5IG1vY2sgYXMgdGhlIGluZm9ybWF0aW9uIGFyZSBhbGwgdXNlZAogIGZpbHRlcihTZWNvbmRhcnkgIT0gIk0iKSAlPiUKICBwaXZvdF93aWRlcihpZF9jb2xzID0gYyhEYXRlLCBTdHJhaW4sIFNwZWNpZXMsIEgyTzIpLCAKICAgICAgICAgICAgICBuYW1lc19mcm9tID0gUHJpbWFyeSwgdmFsdWVzX2Zyb20gPSByLCBuYW1lc19wcmVmaXggPSAiciIpICU+JSAKICBtdXRhdGUoQVNSX3Njb3JlID0gclAgLyByTSkKICAKZGF0LnMxYgpgYGAKIyMjIyBQbG90CgpgYGB7cn0KcCA8LSBkYXQuczFiICU+JSAKICBmaWx0ZXIoIWlzLm5hKEFTUl9zY29yZSkpICU+JSAKICBtdXRhdGUoSDJPMiA9IGdzdWIoIiA/bU0iLCAiIiwgSDJPMiksCiAgICAgICAgIEgyTzIgPSBmY3RfcmVvcmRlcihIMk8yLCBhcy5udW1lcmljKEgyTzIpKSkgJT4lIAogIGZpbHRlcihIMk8yICE9ICIwIikgJT4lIAogIGdncGxvdChhZXMoeCA9IEgyTzIsIHkgPSBBU1Jfc2NvcmUpKSArIHAuYXNyICsKICAjZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGUgPSAyLCBjb2xvciA9ICJncmF5NTAiKSArCiAgI2dlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjEpLCBhbHBoYSA9IDAuOCkgKyAKICAjc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gIm1lYW5fY2xfYm9vdCIsIGdlb20gPSAicG9pbnRyYW5nZSIsIGNvbG9yID0gInJlZCIsCiAgIyAgICAgICAgICAgICBzaXplID0gMC44LCBwb3NpdGlvbiA9IHBvc2l0aW9uX251ZGdlKHggPSAwLjIpKSArCiAgI3NjYWxlX3lfbG9nMTAoKSArCiAgI2ZhY2V0X3dyYXAoflNwZWNpZXMsIHNjYWxlcyA9ICJmcmVlX3giLCBsYWJlbGxlciA9IGFzX2xhYmVsbGVyKHNwZWNpZXMubGFiZWwpKSArCiAgeGxhYihicXVvdGUoSFsyXSpPWzJdfihtTSkpKSArIHlsYWIoIkFTUiBzY29yZSAocicvcikiKSMgKwogICN0aGVtZV9jb3dwbG90KGxpbmVfc2l6ZSA9IDAuNykgKwogICN0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMSksIGZhY2UgPSAzKSkKcApnZ3NhdmUoIi4uL291dHB1dC8yMDIzMDEwMi1BU1Itc2NvcmUtYWNyb3NzLWgybzItcmFuZ2Utc2MtY2cucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSAzKQpgYGAKCiMjIFMyOiBBU1IgYXQgZGlmZmVyZW50IHByaW1hcnkgc3RyZXNzIGR1cmF0aW9uCl8qKkdvYWwqKl8KCi0gR2VuZXJhbGl6ZSB0aGUgbWFpbiBmaWd1cmUgZmluZGluZyBvZiBhIHN0cm9uZ2VyIEFTUiBpbiBfQy4gZ2xhYnJhdGFfIHRoYW4gaW4gX1MuIGNlcmV2aXNpYWVfIGF0IGEgc2luZ2xlIFtIfjJ+T34yfl0gYnkgZXh0ZW5kaW5nIHRoZSBhbmFseXNpcyB0byBtdWx0aXBsZSBjb25jZW50cmF0aW9ucwoKXyoqRGF0YSoqXwoKKipNYWluIGRhdGFzZXQqKjogCgpTcGVjaWVzICAgICAgIExlbl9ub1BpICAgICAgICAgIEgyTzIgICAgICAgIERlc2NyaXB0aW9uIAotLS0tLS0tLSAgICAgIC0tLS0tLS0tLSAgICAgICAgIC0tLS0tLSAgICAgIC0tLS0tLS0tLS0tLQpDLiBnbGFicmF0YSAgIDQ1LCA5MCwgMTM1IG1pbiAgIDEwMCBtTSAgICAgIGZ1bGwgQVNSIGV4cGVyaW1lbnQKUy4gY2VyZXZpc2lhZSA0NSwgOTAsIDEzNSBtaW4gICAxMG1NICAgICAgICBmdWxsIEFTUiBleHBlcmltZW50CgpEYXRlICAgICAgIFNwZWNpZXMgICBMZW5fbm9QaSAgICBTdHJhaW4gCi0tLS0tICAgICAgLS0tLS0tLS0gIC0tLS0tLS0tLSAgIC0tLS0tLS0KMDYvMDYvMjAgICBDZyAgICAgICAgNDUgbWluICAgICAgeUgwMDEKMDYvMDYvMjAgICBTYyAgICAgICAgNDUgbWluICAgICAgeUgxNTQKMDYvMDYvMjAgICBDZyAgICAgICAgOTAgbWluICAgICAgeUgwMDEKMDYvMDYvMjAgICBTYyAgICAgICAgOTAgbWluICAgICAgeUgxNTQKMDYvMDYvMjAgICBDZyAgICAgICAgMTM1IG1pbiAgICAgeUgwMDEKMDYvMDYvMjAgICBTYyAgICAgICAgMTM1IG1pbiAgICAgeUgxNTQKCioqU3VwcG9ydGluZyBkYXRhc2V0Kio6IAoKRGF0ZSAgICAgICBTcGVjaWVzICAgTGVuX25vUGkgICAgU3RyYWluIAotLS0tLSAgICAgIC0tLS0tLS0tICAtLS0tLS0tLS0gICAtLS0tLS0tCjA1LzMwLzIyICAgQ2cgICAgICAgIDQ1IG1pbiAgICAgIHlIMDAxICAKMDUvMzAvMjIgICBTYyAgICAgICAgNDUgbWluICAgICAgeUgxNTQKMDYvMDEvMjIgICBDZyAgICAgICAgNDUgbWluICAgICAgeUgwMDEKMDYvMDEvMjIgICBTYyAgICAgICAgNDUgbWluICAgICAgeUgxNTQKMDYvMDQvMjIgICBDZyAgICAgICAgNDUgbWluICAgICAgeUgwMDEKMDYvMDQvMjIgICBTYyAgICAgICAgNDUgbWluICAgICAgeUgxNTQKCmBgYHtyfQp1c2UuczIgPC0gcGFzdGUwKGMoIjA2LzA2IiwgIjA2LzA0IiwgIjA2LzAxIiwgIjA1LzMwIiksICIvMjAiKQp0bXAgPC0gIHJhdyAlPiUKICBmaWx0ZXIoRGF0ZSAlaW4lIHVzZS5zMikgJT4lIAogIG11dGF0ZSgKICAgICMgYXJiaXRyYXJpbHkgZGVjaWRlIGFueSBDRlUgY291bnRzIDwgMyBhcmUgbm90IGluY2x1ZGVkIGR1ZSB0byBoaWdoIENWCiAgICAjIG5vdCBpbiB1c2UgaGVyZS4gaW5zdGVhZCwgbGFiZWwgdGhlbSBpbiB0aGUgcGxvdCAoc2VlIGJlbG93KQogICAgIyBjb3VudCA9IGlmZWxzZShDb3VudCA8IDMsIE5BLCBDb3VudCksCiAgICBzY2FsZWQgPSBDb3VudCAqIERpbHV0aW9ucyAqIDFlLTIKICApICU+JSAKICAjIHJlbW92ZSB1bmluZm9ybWF0aXZlIGNvbHVtbnMuIG9ubHkgb25lIEgyTzIgY29uYyB1c2VkIGZvciBlYWNoIHNwZWNpZXMKICBzZWxlY3QoLVN0cmFpbiwgLUdlbm90eXBlLCAtSDJPMiwgLUxlbl8yLCAtRXhwZXJpbWVudGVyKQpgYGAKICAKQXNzdW1lIHRoZSB0cmlwbGljYXRlcyB3ZXJlIHBhaXJlZCBpbiB0aGUgb3JkZXIgdGhleSBhcHBlYXIgaW4gdGhlIHRhYmxlLCBpLmUuLCB0aGUgZmlyc3Qgcm93IGluIHRoZSBNTywgTU0sIFBPLCBQTSBncm91cHMgYmVsb25nIHRvIHRoZSBzYW1lIGJpb2xvZ2ljYWwgcmVwbGljYXRlLCB3ZSBjYW4gZGVyaXZlIHRocmVlIEFTUl9zY29yZXMgZm9yIGVhY2ggZGF0ZSB4IHNwZWNpZXMgeCBMZW5fMQpgYGB7cn0KZGF0LnMyIDwtIHRtcCAlPiUgCiAgZ3JvdXBfYnkoRGF0ZSwgU3BlY2llcywgTGVuXzEsIEdyb3VwKSAlPiUKICBtdXRhdGUoUmVwbCA9IHJvd19udW1iZXIoKSkgJT4lIAogIHBpdm90X3dpZGVyKGlkX2NvbHMgPSBjKERhdGUsIFNwZWNpZXMsIExlbl8xLCBSZXBsKSwKICAgICAgICAgICAgICBuYW1lc19mcm9tID0gR3JvdXAsIHZhbHVlc19mcm9tID0gc2NhbGVkLCBuYW1lc19zZXAgPSAiIikgJT4lIAogIG11dGF0ZSgKICAgIHIgPSBNTy9NTSwgCiAgICBycCA9IFBPL1BNLCAKICAgIEFTUl9zY29yZSA9IHJwL3IsCiAgICBsb3dfY291bnQgPSBNTyA8IDEgIyBtYXJrIGV4cGVyaW1lbnRzIHdpdGggPCAzIGNvdW50cwogICkKZGF0LnMyCmBgYAojIyMjIFBsb3QKYGBge3J9CnAgPC0gZGF0LnMyICU+JSAKICAjZmlsdGVyKCFpcy5uYShBU1Jfc2NvcmUpKSAlPiUgCiAgbXV0YXRlKGxlbl8xID0gZmFjdG9yKGdzdWIoIiA/bWluIiwgIiIsIExlbl8xKSwgbGV2ZWxzID0gYygiNDUiLCAiOTAiLCAiMTM1IikpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbGVuXzEsIHkgPSBBU1Jfc2NvcmUpKSArIHAuYXNyICsKIyAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMSwgbGluZXR5cGUgPSAyLCBjb2xvciA9ICJncmF5NTAiKSArCiMgIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAwLjEpLCBzaXplID0gMikgKyAKIyAgc3RhdF9zdW1tYXJ5KHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoeCA9IDAuMiksCiMgICAgICAgICAgICAgICBmdW4uZGF0YSA9ICJtZWFuX2NsX2Jvb3QiLCBnZW9tID0gInBvaW50cmFuZ2UiLCBjb2xvciA9ICJyZWQiKSArCiAgeGxhYigiTGVuZ3RoIG9mIHByaW1hcnkgc3RyZXNzIChtaW4pIikgKyB5bGFiKCJBU1Igc2NvcmUgKHInL3IpIikgKwojICBmYWNldF93cmFwKH5TcGVjaWVzLCBzY2FsZXMgPSAiZnJlZV94IiwgbGFiZWxsZXIgPSBhc19sYWJlbGxlcihzcGVjaWVzLmxhYmVsKSkgKwojICB0aGVtZV9jb3dwbG90KGxpbmVfc2l6ZSA9IDAuNykgKwogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMSksIGZhY2UgPSAzKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuMSwgMC44NSksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEpLCBmYWNlID0gMykpCnAKZ2dzYXZlKCIuLi9vdXRwdXQvMjAyMzAxMDMtQVNSLXNjb3JlLWFjcm9zcy1ub1BpLWxlbmd0aC1zYy1jZy5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMpCmBgYAoKCmBgYHtyfQpwIDwtIGRhdC5zMiAlPiUgCiAgI2ZpbHRlcighaXMubmEoQVNSX3Njb3JlKSkgJT4lIAogIG11dGF0ZShsZW5fMSA9IGZhY3RvcihMZW5fMSwgbGV2ZWxzID0gYygiNDUgbWluIiwgIjkwIG1pbiIsICIxMzUgbWluIikpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gU3BlY2llcywgeSA9IEFTUl9zY29yZSkpICsKICBnZW9tX3BvaW50KCNhZXMoZmlsbCA9IGxvd19jb3VudCksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcigwLjEpLCBzaXplID0gMS41LCBzaGFwZSA9IDIxKSArIAogIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9ICJtZWFuX3NlIiwgZ2VvbSA9ICJwb2ludHJhbmdlIiwgY29sb3IgPSAicmVkIikgKwogICNzY2FsZV95X2xvZzEwKCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDIxLDIyKSwgbGFiZWxzID0gc3BlY2llcy5sYWJlbCkgKwogICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJ3aGl0ZSIsICJncmF5NDAiKSwgZ3VpZGUgPSAibm9uZSIpICsKICAjZmFjZXRfd3JhcCh+U3BlY2llcywgc2NhbGVzID0gImZyZWVfeCIsIGxhYmVsbGVyID0gYXNfbGFiZWxsZXIoc3BlY2llcy5sYWJlbCkpICsKICBmYWNldF93cmFwKH4gbGVuXzEsIHNjYWxlcyA9ICJmcmVlIikgKwogIHhsYWIoIkxlbmd0aCBvZiBwcmltYXJ5IHN0cmVzcyAobWluKSIpICsgeWxhYigiQVNSIHNjb3JlIChyJy9yKSIpICsKICB0aGVtZV9jb3dwbG90KGxpbmVfc2l6ZSA9IDAuNykKcApnZ3NhdmUoIi4uL291dHB1dC8yMDIzMDEwMy1BU1Itc2NvcmUtYWNyb3NzLW5vUGktbGVuZ3RoLXNlcC1wYW5lbC5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDMpCmBgYAoKIyMgRmlnMzogY3RhMeKIhgpfKipHb2FsKipfCgotIERldGVybWluZSBpZiBfQ1RBMV8gaXMgcmVxdWlyZWQgZm9yIHRoZSBBU1IKCl8qKkV4cGVyaW1lbnQqKl8KCi0gSmlueWUgZGVsZXRlZCBfQ1RBMV8gYW5kIGNvbXBhcmVkIEFTUiBpbiB0aGlzIHN0cmFpbiB0byB0aGUgd3QgX0MuIGdsYWJyYXRhXwoKXyoqRGF0YSoqXwoKU3BlY2llcyAgICAgICBTdHJhaW4gICAgICAgICAgIEdlbm90eXBlICAgICBIMk8yICAgICAgICAgCi0tLS0tLS0tICAgICAgLS0tLS0tLS0tLS0tLSAgICAtLS0tLS0tLS0tICAgLS0tLS0tLS0tLS0tCkMuIGdsYWJyYXRhICAgeUgwMDEsIHlIMDAyICAgICB3aWxkdHlwZSAgICAgODAsIDEwMCBtTSAKQy4gZ2xhYnJhdGEgICB5SDI3MSwgeUgyNzIgICAgIF9jdGEx4oiGXyAgICAgIDIuMiwgMi41IG1NIAoKU2l4IHJlcGxpY2F0ZXMsIHR3byBlYWNoIGZyb20gMDcvMDgsIDA3LzExLCAwNy8xMiBvZiAyMDIyLgoKYGBge3J9CnVzZS5mMyA8LSBwYXN0ZTAoYygiMDcvMDgiLCAiMDcvMTEiLCAiMDcvMTIiKSwgIi8yMiIpCnRtcCA8LSAgcmF3ICU+JQogIGZpbHRlcihEYXRlICVpbiUgdXNlLmYzKSAlPiUgCiAgbXV0YXRlKAogICAgc2NhbGVkID0gQ291bnQgKiBEaWx1dGlvbnMgKiAxZS0yCiAgKSAlPiUgCiAgIyByZW1vdmUgdW5pbmZvcm1hdGl2ZSBjb2x1bW5zLiBvbmx5IG9uZSBIMk8yIGNvbmMgdXNlZCBmb3IgZWFjaCBzcGVjaWVzCiAgc2VsZWN0KC1MZW5fMSwgLUxlbl8yLCAtRXhwZXJpbWVudGVyKQojIEFzc3VtZSB0aGUgcmVwbGljYXRlcyB3ZXJlIHBhaXJlZCBpbiB0aGUgb3JkZXIgdGhleSBhcHBlYXIgaW4gdGhlIHRhYmxlLAojIGkuZS4sIHRoZSBmaXJzdCByb3cgaW4gdGhlIE1PLCBNTSwgUE8sIFBNIGdyb3VwcyBiZWxvbmcgdG8gdGhlIHNhbWUgYmlvbG9naWNhbCAKIyByZXBsaWNhdGUsIHdlIGNhbiBkZXJpdmUgdGhyZWUgQVNSX3Njb3JlcyBmb3IgZWFjaCBkYXRlIHggc3BlY2llcyB4IExlbl8xCgpkYXQuZjMgPC0gdG1wICU+JSAKICAjIGdyb3VwIGJ5IHByaW1hcnkgdG8gY2FsY3VsYXRlIHIgKE1PL01NKSBvciByJyAoUE8vUE0pCiAgc2VwYXJhdGUoR3JvdXAsIGludG8gPSBjKCJQcmltYXJ5IiwgIlNlY29uZGFyeSIpLCBzZXAgPSAxKSAlPiUgCiAgZ3JvdXBfYnkoRGF0ZSwgU3RyYWluLCBQcmltYXJ5KSAlPiUgCiAgIyBjYWxjdWxhdGUgJSBzdXJ2aXZhbAogIG11dGF0ZShyID0gbnVtKHNjYWxlZCAvIHNjYWxlZFtTZWNvbmRhcnkgPT0gIk0iXSwgZGlnaXRzID0gMykpICU+JSAKICAjIHJlbW92ZSB0aGUgc2Vjb25kYXJ5IG1vY2sgYXMgdGhlIGluZm9ybWF0aW9uIGFyZSBhbGwgdXNlZAogIGZpbHRlcihTZWNvbmRhcnkgIT0gIk0iKQpkYXQuZjMKYGBgCiMjIyBQbG90IChhbGwgZGF0YSkKYGBge3J9CmRhdC5mMyAlPiUgCiAgbXV0YXRlKAogICAgUHJpbWFyeSA9IGZhY3RvcihQcmltYXJ5LCBsZXZlbHMgPSBjKCJNIiwgIlAiKSwgCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk1vY2siLCAiLVBpIikpLAogICAgR2Vub3R5cGUgPSBmYWN0b3IoR2Vub3R5cGUsIGxldmVscyA9IGMoInd0IiwgImN0YTHOlCIpLAogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygid2lsZHR5cGUiLCAiY3RhMc6UIikpLAogICAgR3JvdXAgPSBmYWN0b3IoSDJPMiwgbGV2ZWxzID0gYygiMTAwIG1NIiwgIjIuNSBtTSIsICI4MCBtTSIsICIyLjIgbU0iKSwKICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkhpZ2giLCAiSGlnaCIsICJNZWRpdW0iLCAiTWVkaXVtIikpCiAgKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBIMk8yLCB5ID0gcikpICsgI3Auc3Vydml2YWxbLTNdICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IFByaW1hcnkpLCBzdHJva2UgPSAxLCBzaXplID0gMiwgCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSkpICsKICBzdGF0X3N1bW1hcnkoYWVzKGdyb3VwID0gUHJpbWFyeSksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwKICAgICAgICAgICAgICAgZnVuID0gbWVhbiwgZnVuLm1heCA9IG1lYW4sIGZ1bi5taW4gPSBtZWFuLAogICAgICAgICAgICAgICBnZW9tID0gImNyb3NzYmFyIiwgY29sb3IgPSAicmVkIiwgd2lkdGggPSAwLjUpICsKICBmYWNldF93cmFwKH4gR3JvdXAgKyBHZW5vdHlwZSwgbnJvdyA9IDEsIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoIk1vY2siID0gMSwgIi1QaSIgPSAxNikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArCiAgeGxhYigiUHJpbWFyeSBzdHJlc3MgKDQ1IG1pbikiKSArIHlsYWIoIiUgc3Vydml2YWwiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQsIGJhc2VfbGluZV9zaXplID0gMSkgKwogIHBhbmVsX2JvcmRlcihjb2xvciA9ICJibGFjayIsIHNpemUgPSAxKSArCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEpLCBmYWNlID0gMyksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgojIyMgMTAwIHZzIDIuNSBtTQpUbyBiZSBjb25zaXN0ZW50IHdpdGggcGFuZWwgQywgd2Ugd2lsbCB1c2UgdGhlIDEwMCBtTSB2cyAyLjUgbU0gcGFpciBhbmQgbGVhdmUgb3V0IHRoZSA4MCBtTSB2cyAyLjIgbU0gcGFpci4KYGBge3J9CmRhdC5mM2EgPC0gZGF0LmYzICU+JSAKICBtdXRhdGUoIFByaW1hcnkgPSBmYWN0b3IoUHJpbWFyeSwgbGV2ZWxzID0gYygiTSIsICJQIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJNb2NrIiwgIi1QaSIpKSwKICAgICAgICAgIEdlbm90eXBlID0gZmFjdG9yKEdlbm90eXBlLCBsZXZlbHMgPSBjKCJ3dCIsICJjdGExzpQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIndpbGR0eXBlIiwgImN0YTHOlCIpKSwKICAgICAgICAgIEdyb3VwID0gZmFjdG9yKEgyTzIsIGxldmVscyA9IGMoIjEwMCBtTSIsICIyLjUgbU0iLCAiODAgbU0iLCAiMi4yIG1NIiksCiAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJIaWdoIiwgIkhpZ2giLCAiTWVkaXVtIiwgIk1lZGl1bSIpKSkgJT4lCiAgZmlsdGVyKEdyb3VwID09ICJIaWdoIikgJT4lIAogIHVuZ3JvdXAoKQpgYGAKCiMjIyMgUGxvdApgYGB7cn0KcCA8LSBnZ3Bsb3QoZGF0LmYzYSwgYWVzKHggPSBIMk8yLCB5ID0gcikpICsKICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IFByaW1hcnkpLCBzdHJva2UgPSAwLjksIHNpemUgPSAyLjUsIAogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShqaXR0ZXIud2lkdGggPSAwLjMsIGRvZGdlLndpZHRoID0gMC45KSkgKwogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSBQcmltYXJ5KSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpLAogICAgICAgICAgICAgICBmdW4gPSBtZWFuLCBmdW4ubWF4ID0gbWVhbiwgZnVuLm1pbiA9IG1lYW4sCiAgICAgICAgICAgICAgIGdlb20gPSAiY3Jvc3NiYXIiLCBjb2xvciA9ICJyZWQiLCB3aWR0aCA9IDAuNSkgKwogIGZhY2V0X3dyYXAofiBHZW5vdHlwZSwgbnJvdyA9IDEsIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKG5hbWUgPSAiUHJpbWFyeSBzdHJlc3MiLCB2YWx1ZXMgPSBjKCJNb2NrIiA9IDEsICItUGkiID0gMTYpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKwogIHhsYWIoYnF1b3RlKEhbMl0qT1syXX4obU0pKSkgKyB5bGFiKCIlIHN1cnZpdmFsIikgKwogIHRoZW1lX2Nvd3Bsb3QobGluZV9zaXplID0gMS4yKSArCiAgcGFuZWxfYm9yZGVyKGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDEpICsKICB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMSkpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgI3N0cmlwLnBsYWNlbWVudCA9ICJpbnNpZGUiLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAiY2VudGVyIiwKICAgICAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKGIgPSAtMTApLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC45KSksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMC45KSkpCnAKCmdnc2F2ZSgiLi4vb3V0cHV0LzIwMjMwMzAxLWZpZzNkLWFzci1jdGExLnBuZyIsIHdpZHRoID0gMy41LCBoZWlnaHQgPSAzLjUpCmBgYAoKXyoqU3RhdGlzdGljYWwgdGVzdHMqKl8KCiMjIyMgU3RhdGlzdGljYWwgdGVzdAoxLiBEZXRlcm1pbmUgaWYgdGhlIGJhc2FsIHN1cnZpdmFsIHJhdGVzIGFyZSBkaWZmZXJlbnQgYmV0d2VlbiBzcGVjaWVzIChXaWxjb3hvbiBzaWduZWQtcmFuayB0ZXN0KQoxLiBEZXRlcm1pbmUgaWYgdGhlIHByaW1hcnkgc3RyZXNzIGVuaGFuY2VkIHRoZSBzdXJ2aXZhbCBpbiBfZWFjaF8gc3BlY2llcyAoV2lsY294b24gc2lnbmVkLXJhbmsgdGVzdCkKCl9CYXNhbCBzdXJ2aXZhbCByYXRlXwpBY3Jvc3Mgc3BlY2llcywgdW5wYWlyZWQsIHJhbmstc3VtIHRlc3QuCmBgYHtyfQp0bXAgPC0gZGF0LmYzYSAlPiUgCiAgZmlsdGVyKFByaW1hcnkgPT0gIk1vY2siKSAlPiUgCiAgc2VsZWN0KERhdGUsIEdlbm90eXBlLCByKSAlPiUgCiAgYXJyYW5nZShHZW5vdHlwZSkKCnRtcCAlPiUgZ3JvdXBfYnkoR2Vub3R5cGUpICU+JSBzdW1tYXJpemUobWVhbiA9IG1lYW4ociksIHNkID0gbnVtKHNkKHIpLCBkaWdpdHMgPSAzKSkKCndpbGNveC50ZXN0KHIgfiBHZW5vdHlwZSwgcGFpcmVkID0gRkFMU0UsIGRhdGEgPSB0bXApCmBgYAoKCl9QcmltYXJ5IHN0cmVzcyBlbmhhbmNlZCBpbiB3aWxkdHlwZV8KCkNvbXBhcmlzb24gYmV0d2VlbiByIGFuZCByJywgcGFpcmVkLCBzaWduZWQtcmFuayB0ZXN0LgpgYGB7cn0KdG1wIDwtIGRhdC5mM2EgJT4lIAogIGZpbHRlcihHZW5vdHlwZSA9PSAid2lsZHR5cGUiKSAlPiUgCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMoRGF0ZSwgU3RyYWluKSwgbmFtZXNfZnJvbSA9IFByaW1hcnksIHZhbHVlc19mcm9tID0gcikgJT4lIAogIG11dGF0ZShBU1IgPSBgLVBpYC9Nb2NrKQoKdG1wCgp4IDwtIEhtaXNjOjpzbWVhbi5jbC5ib290KHRtcCRBU1IpCnNwcmludGYoIkFTUl9zY29yZSBtZWFuID0gJS4yZiwgOTUlJSBDSSBieSBib290c3RyYXAgPSBbJS4yZiwgJS4yZl0iLCB4WzFdLCB4WzJdLCB4WzNdKQoKd2l0aCh0bXAsIHQudGVzdChhcy5udW1lcmljKGAtUGlgKSwgYXMubnVtZXJpYyhNb2NrKSwgcGFpcmVkID0gVFJVRSwgYWx0ZXJuYXRpdmUgPSAiZyIpKQp3aXRoKHRtcCwgd2lsY294LnRlc3QoYC1QaWAsIE1vY2ssIHBhaXJlZCA9IFRSVUUsIGFsdGVybmF0aXZlID0gImciKSkKd2l0aCh0bXAsIHdpbGNveC50ZXN0KGAtUGlgLCBNb2NrLCBwYWlyZWQgPSBGQUxTRSwgYWx0ZXJuYXRpdmUgPSAiZyIpKQpgYGAKCl9QcmltYXJ5IHN0cmVzcyBubyBlZmZlY3QgaW4gY3RhMc6UXwoKUGFpcmVkLCBzaWduZWQtcmFuayB0ZXN0CmBgYHtyfQp0bXAgPC0gZGF0LmYzYSAlPiUgCiAgZmlsdGVyKEdlbm90eXBlID09ICJjdGExzpQiKSAlPiUgCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMoRGF0ZSwgU3RyYWluKSwgbmFtZXNfZnJvbSA9IFByaW1hcnksIHZhbHVlc19mcm9tID0gcikgJT4lIAogIG11dGF0ZShBU1IgPSBgLVBpYC9Nb2NrKQoKdG1wCgp4IDwtIEhtaXNjOjpzbWVhbi5jbC5ib290KHRtcCRBU1IpCnNwcmludGYoIkFTUl9zY29yZSBtZWFuID0gJS4yZiwgOTUlJSBDSSBieSBib290c3RyYXAgPSBbJS4yZiwgJS4yZl0iLCB4WzFdLCB4WzJdLCB4WzNdKQoKd2l0aCh0bXAsIHQudGVzdChhcy5udW1lcmljKGAtUGlgKSwgYXMubnVtZXJpYyhNb2NrKSwgcGFpcmVkID0gVFJVRSwgYWx0ZXJuYXRpdmUgPSAiZyIpKQp3aXRoKHRtcCwgd2lsY294LnRlc3QoYC1QaWAsIE1vY2ssIHBhaXJlZCA9IFRSVUUsIGFsdGVybmF0aXZlID0gImciKSkKd2l0aCh0bXAsIHdpbGNveC50ZXN0KGAtUGlgLCBNb2NrLCBwYWlyZWQgPSBGQUxTRSwgYWx0ZXJuYXRpdmUgPSAiZyIpKQpgYGAKCiMjIyA4MCB2cyAyLjIgbU0KQ29ycmVzcG9uZGluZyByZXN1bHRzIGZvciA4MCBtTSB2cyAyLjIgbU0KYGBge3J9CmRhdC5zM2IgPC0gZGF0LmYzICU+JSAKICBtdXRhdGUoIFByaW1hcnkgPSBmYWN0b3IoUHJpbWFyeSwgbGV2ZWxzID0gYygiTSIsICJQIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJNb2NrIiwgIi1QaSIpKSwKICAgICAgICAgIEdlbm90eXBlID0gZmFjdG9yKEdlbm90eXBlLCBsZXZlbHMgPSBjKCJ3dCIsICJjdGExzpQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIndpbGR0eXBlIiwgImN0YTHOlCIpKSwKICAgICAgICAgIEdyb3VwID0gZmFjdG9yKEgyTzIsIGxldmVscyA9IGMoIjEwMCBtTSIsICIyLjUgbU0iLCAiODAgbU0iLCAiMi4yIG1NIiksCiAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJIaWdoIiwgIkhpZ2giLCAiTWVkaXVtIiwgIk1lZGl1bSIpKSkgJT4lCiAgZmlsdGVyKEdyb3VwID09ICJNZWRpdW0iKSAlPiUgCiAgdW5ncm91cCgpCmBgYAoKIyMjIyBQbG90CmBgYHtyfQpwIDwtIGdncGxvdChkYXQuczNiLCBhZXMoeCA9IEgyTzIsIHkgPSByKSkgKwogIGdlb21fcG9pbnQoYWVzKHNoYXBlID0gUHJpbWFyeSksIHN0cm9rZSA9IDAuOSwgc2l6ZSA9IDIuNSwgCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMywgZG9kZ2Uud2lkdGggPSAwLjkpKSArCiAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IFByaW1hcnkpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSksCiAgICAgICAgICAgICAgIGZ1biA9IG1lYW4sIGZ1bi5tYXggPSBtZWFuLCBmdW4ubWluID0gbWVhbiwKICAgICAgICAgICAgICAgZ2VvbSA9ICJjcm9zc2JhciIsIGNvbG9yID0gInJlZCIsIHdpZHRoID0gMC41KSArCiAgZmFjZXRfd3JhcCh+IEdlbm90eXBlLCBucm93ID0gMSwgc2NhbGVzID0gImZyZWVfeCIpICsKICBzY2FsZV9zaGFwZV9tYW51YWwobmFtZSA9ICJQcmltYXJ5IHN0cmVzcyIsIHZhbHVlcyA9IGMoIk1vY2siID0gMSwgIi1QaSIgPSAxNikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArCiAgeGxhYihicXVvdGUoSFsyXSpPWzJdfihtTSkpKSArIHlsYWIoIiUgc3Vydml2YWwiKSArCiAgdGhlbWVfY293cGxvdChsaW5lX3NpemUgPSAxLjIpICsKICBwYW5lbF9ib3JkZXIoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMSkgKwogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgxKSksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAjc3RyaXAucGxhY2VtZW50ID0gImluc2lkZSIsCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJjZW50ZXIiLAogICAgICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oYiA9IC0xMCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjkpKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IHJlbCgwLjkpKSkKcAoKZ2dzYXZlKCIuLi9vdXRwdXQvMjAyMzAzMDEtczNiLWFzci1jdGExLnBuZyIsIHdpZHRoID0gMy41LCBoZWlnaHQgPSAzLjUpCmBgYAoKXyoqU3RhdGlzdGljYWwgdGVzdHMqKl8KCiMjIyMgU3RhdGlzdGljYWwgdGVzdAoxLiBEZXRlcm1pbmUgaWYgdGhlIGJhc2FsIHN1cnZpdmFsIHJhdGVzIGFyZSBkaWZmZXJlbnQgYmV0d2VlbiBzcGVjaWVzIChXaWxjb3hvbiBzaWduZWQtcmFuayB0ZXN0KQoxLiBEZXRlcm1pbmUgaWYgdGhlIHByaW1hcnkgc3RyZXNzIGVuaGFuY2VkIHRoZSBzdXJ2aXZhbCBpbiBfZWFjaF8gc3BlY2llcyAoV2lsY294b24gc2lnbmVkLXJhbmsgdGVzdCkKCl9CYXNhbCBzdXJ2aXZhbCByYXRlXwpBY3Jvc3Mgc3BlY2llcywgdW5wYWlyZWQsIHJhbmstc3VtIHRlc3QuCmBgYHtyfQp0bXAgPC0gZGF0LnMzYiAlPiUgCiAgZmlsdGVyKFByaW1hcnkgPT0gIk1vY2siKSAlPiUgCiAgc2VsZWN0KERhdGUsIEdlbm90eXBlLCByKSAlPiUgCiAgYXJyYW5nZShHZW5vdHlwZSkKdG1wICU+JSBncm91cF9ieShHZW5vdHlwZSkgJT4lIHN1bW1hcml6ZShtZWFuID0gbWVhbihyKSwgc2QgPSBudW0oc2QociksIGRpZ2l0cyA9IDMpKQp3aWxjb3gudGVzdChyIH4gR2Vub3R5cGUsIHBhaXJlZCA9IEZBTFNFLCBkYXRhID0gdG1wKQpgYGAKCgpfUHJpbWFyeSBzdHJlc3MgZW5oYW5jZWQgaW4gd2lsZHR5cGVfCgpDb21wYXJpc29uIGJldHdlZW4gciBhbmQgcicsIHBhaXJlZCwgc2lnbmVkLXJhbmsgdGVzdC4KYGBge3J9CnRtcCA8LSBkYXQuczNiICU+JSAKICBmaWx0ZXIoR2Vub3R5cGUgPT0gIndpbGR0eXBlIikgJT4lIAogIHBpdm90X3dpZGVyKGlkX2NvbHMgPSBjKERhdGUsIFN0cmFpbiksIG5hbWVzX2Zyb20gPSBQcmltYXJ5LCB2YWx1ZXNfZnJvbSA9IHIpICU+JSAKICBtdXRhdGUoQVNSID0gYC1QaWAvTW9jaykKCnRtcAoKeCA8LSBIbWlzYzo6c21lYW4uY2wuYm9vdCh0bXAkQVNSKQpzcHJpbnRmKCJBU1Jfc2NvcmUgbWVhbiA9ICUuMmYsIDk1JSUgQ0kgYnkgYm9vdHN0cmFwID0gWyUuMmYsICUuMmZdIiwgeFsxXSwgeFsyXSwgeFszXSkKCndpdGgodG1wLCB0LnRlc3QoYXMubnVtZXJpYyhgLVBpYCksIGFzLm51bWVyaWMoTW9jayksIHBhaXJlZCA9IFRSVUUsIGFsdGVybmF0aXZlID0gImciKSkKd2l0aCh0bXAsIHdpbGNveC50ZXN0KGAtUGlgLCBNb2NrLCBwYWlyZWQgPSBUUlVFLCBhbHRlcm5hdGl2ZSA9ICJnIikpCndpdGgodG1wLCB3aWxjb3gudGVzdChgLVBpYCwgTW9jaywgcGFpcmVkID0gRkFMU0UsIGFsdGVybmF0aXZlID0gImciKSkKYGBgCgpfUHJpbWFyeSBzdHJlc3Mgbm8gZWZmZWN0IGluIGN0YTHOlF8KClBhaXJlZCwgc2lnbmVkLXJhbmsgdGVzdApgYGB7cn0KdG1wIDwtIGRhdC5zM2IgJT4lIAogIGZpbHRlcihHZW5vdHlwZSA9PSAiY3RhMc6UIikgJT4lIAogIHBpdm90X3dpZGVyKGlkX2NvbHMgPSBjKERhdGUsIFN0cmFpbiksIG5hbWVzX2Zyb20gPSBQcmltYXJ5LCB2YWx1ZXNfZnJvbSA9IHIpICU+JSAKICBtdXRhdGUoQVNSID0gYC1QaWAvTW9jaykKCnRtcAoKeCA8LSBIbWlzYzo6c21lYW4uY2wuYm9vdCh0bXAkQVNSKQpzcHJpbnRmKCJBU1Jfc2NvcmUgbWVhbiA9ICUuMmYsIDk1JSUgQ0kgYnkgYm9vdHN0cmFwID0gWyUuMmYsICUuMmZdIiwgeFsxXSwgeFsyXSwgeFszXSkKCndpdGgodG1wLCB0LnRlc3QoYXMubnVtZXJpYyhgLVBpYCksIGFzLm51bWVyaWMoTW9jayksIHBhaXJlZCA9IFRSVUUsIGFsdGVybmF0aXZlID0gImciKSkKd2l0aCh0bXAsIHdpbGNveC50ZXN0KGAtUGlgLCBNb2NrLCBwYWlyZWQgPSBUUlVFLCBhbHRlcm5hdGl2ZSA9ICJnIikpCndpdGgodG1wLCB3aWxjb3gudGVzdChgLVBpYCwgTW9jaywgcGFpcmVkID0gRkFMU0UsIGFsdGVybmF0aXZlID0gImciKSkKYGBgCgojIyBGaWc2OiBBU1IgYnkgcmFwYW15Y2luCl8qKkdvYWwqKl8KCi0gVGVzdCB0aGUgaHlwb3RoZXNpcyB0aGF0IGRpcmVjdCBpbmhpYml0aW9uIG9mIFRPUkMxIGNhbiBwcm92aWRlIEFTUiBpbiBfQy4gZ2xhYnJhdGFfLiBXZSB3aWxsIGFsc28gdGVzdCBfUy4gY2VyZXZpc2lhZV8gdG8gZGV0ZXJtaW5lIGlmIHRoZSBuZWdhdGl2ZSByZWd1bGF0aW9uIGJ5IFRPUkMxIG9uIHN0cmVzcyByZXNwb25zZSBnZW5lcyBiZWhpbmQgdGhlIEFTUiBpcyBjb25zZXJ2ZWQuCgpfKipEYXRhKipfCgpTcGVjaWVzICAgICAgIFJhcGFteWNpbiAobmcvbUwpICAgIEgyTzIgICAgICAgIERlc2NyaXB0aW9uIAotLS0tLS0tLSAgICAgIC0tLS0tLS0tLS0tLS0tLS0tLSAgIC0tLS0tLSAgICAgIC0tLS0tLS0tLS0tLQpDLiBnbGFicmF0YSAgIDUwLCA2Mi41LCAxMjUsIDE1MCAgIDYwIG1NICAgICAgIGZ1bGwgQVNSIGV4cGVyaW1lbnQKUy4gY2VyZXZpc2lhZSA1MCwgNjIuNSwgMTI1LCAxNTAgICA2ICBtTSAgICAgICBmdWxsIEFTUiBleHBlcmltZW50CgpEYXRlICAgICAgIFNwZWNpZXMgICBSYXBhIChuZy9tTCkgIEgyTzIgICAgICAgIFN0cmFpbiAKLS0tLS0gICAgICAtLS0tLS0tLSAgLS0tLS0tLS0tLS0tICAtLS0tICAgICAgICAtLS0tLS0tCjAxLzEyLzIzICAgQ2cgICAgICAgIDYyLjUsIDEyNSAgICAgNjAgbU0gICAgICAgeUgxODEKMDEvMTgvMjMgICBDZyAgICAgICAgNjIuNSwgMTI1ICAgICA2MCBtTSAgICAgICB5SDE4MQowMS8yMS8yMyAgIFNjICAgICAgICA2Mi41LCAxMjUgICAgIDQsIDYgbU0gICAgIHlIMTU0CjAxLzIxLzIzICAgQ2cgICAgICAgIDYyLjUsIDEyNSAgICAgNDAsIDYwIG1NICAgeUgxODEKMDEvMjUvMjMgICBTYyAgICAgICAgNjIuNSwgMTI1ICAgICA0LCA2IG1NICAgICB5SDE1NAowMS8yNS8yMyAgIENnICAgICAgICA2Mi41LCAxMjUgICAgIDQwLCA2MCBtTSAgIHlIMTgxCjAxLzI2LzIzICAgU2MgICAgICAgIDYyLjUsIDEyNSAgICAgNCwgNiBtTSAgICAgeUgxNTQKMDEvMjYvMjMgICBDZyAgICAgICAgNjIuNSwgMTI1ICAgICA0MCwgNjAgbU0gICB5SDE4MQowMS8zMS8yMyAgIFNjICAgICAgICA2Mi41LCAxMjUgICAgIDQsIDYgbU0gICAgIHlIMTU0CjAxLzMxLzIzICAgQ2cgICAgICAgIDYyLjUsIDEyNSAgICAgNDAsIDYwIG1NICAgeUgxODEKMDIvMDIvMjMgICBDZyAgICAgICAgNjIuNSwgMTI1ICAgICA0MCwgNjAgbU0gICB5SDE4MQoKXyoqTm90ZSoqXwoKSmlueWUgdXNlZCBsb3dlciBIMk8yIGNvbmNlbnRyYXRpb24gY29tcGFyZWQgd2l0aCBwcmVpdm91cyBBU1IgZXhwZXJpbWVudHMgKDEwMCBtTSBmb3IgQ2cgYW5kIDEwIG1NIGZvciBTYykgYmVjYXVzZSB0aGUgcHJpbWFyeSBzdHJlc3NlcyB0ZXN0ZWQgaGVyZSwgaS5lLiwgcmFwYW15Y2luIGFuZCBuaXRyb2dlbiBzdGFydmF0aW9uLCByZWR1Y2VkIHN1cnZpdmFsIHdoaWxlIHBob3NwaGF0ZSBzdGFydmF0aW9uIHVzZWQgaW4gcHJldmlvdXMgQVNSIGV4cGVyaW1lbnRzIGRpZG4ndC4gSW4gb3JkZXIgdG8gbWFpbnRhaW4gYSBzaW1pbGFyIENGVSBhdCB0aGUgZW5kLCBhIGxvd2VyIEgyTzIgY29uY2VudHJhdGlvbiB3YXMgYXBwbGllZC4KCmBgYHtyfQpkYXQuNiA8LSByZWFkX2NzdigiLi4vaW5wdXQvMjAyMzAyMDUtU2MtQ2ctcmFwYW15Y2luLW5pdHJvZ2VuLUFTUi1yYXcuY3N2IiwgY29sX3R5cGVzID0gY29scygpLCBjb21tZW50ID0gIiMiKSAlPiUgCiAgbXV0YXRlKERhdGUgPSBnc3ViKCJkKFxcZFxcZCkoXFxkXFxkKShcXGRcXGQpIiwgIlxcMS9cXDIvXFwzIiwgRGF0ZSkpCgojIGRhdGEgc2FuaXR5IGNoZWNrLCBxdWljayB2aWV3CnNhcHBseShzZWxlY3QoZGF0LjYsIFNwZWNpZXMsIFN0cmFpbiwgR2Vub3R5cGUpLCB1bmlxdWUpCmBgYAoKXyoqUGxvdHRpbmcqKl8KCiMjIyBFZmZlY3Qgb2YgcHJpbWFyeSBzdHJlc3MgKFJhcGFteWNpbiBhbmQgLU4pIG9uIHN1cnZpdmFsCkppbnllIG1lbnRpb25lZCB0aGF0IHVubGlrZSBwaG9zcGhhdGUgc3RhcnZhdGlvbiwgcmFwYW15Y2luIGFuZCBuaXRyb2dlbiBzdGFydmF0aW9uIHJlZHVjZSBzdXJ2aXZhbCBieSB0aGVtc2VsdmVzLiBUbyBzZWUgdGhpcyBteXNlbGYsIEknbSBwbG90dGluZyB0aGUgQ0ZVIGFmdGVyIGp1c3QgdGhlIHByaW1hcnkgCgpgYGB7cn0KdG1wIDwtIGRhdC42ICU+JSAKICBmaWx0ZXIoSDJPMiA9PSAiTW9jayIpICU+JSAKICBncm91cF9ieShEYXRlLCBTcGVjaWVzKSAlPiUgCiAgbXV0YXRlKAogICAgIyBhcmJpdHJhcmlseSBkZWNpZGUgYW55IENGVSBjb3VudHMgPCAzIGFyZSBub3QgaW5jbHVkZWQgZHVlIHRvIGhpZ2ggQ1YKICAgIENvdW50ID0gaWZlbHNlKENvdW50IDwgMywgTkEsIENvdW50KSwKICAgIHNjYWxlZCA9IENvdW50ICogRGlsdXRpb25zICogMWUtMiwKICAgIHIgPSBzY2FsZWQgLyBzY2FsZWRbYDFzdF9TdHJlc3NgID09ICJNb2NrIl0KICApICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGZpbHRlcihgMXN0X1N0cmVzc2AgIT0gIk1vY2siKSAlPiUgCiAgc2VsZWN0KERhdGUsIFNwZWNpZXMsIFN0cmFpbiwgUHJpbWFyeSA9IGAxc3RfU3RyZXNzYCwgQ291bnQsIHIpCgpkYXQuUHJpbSA8LSAgcmF3ICU+JQogIHNlcGFyYXRlKEdyb3VwLCBpbnRvID0gYygiUHJpbWFyeSIsICJTZWNvbmRhcnkiKSwgc2VwID0gMSkgJT4lIAogICMgdXNlIHRoZSBTMiBkYXRhc2V0IHRvIGV4YW1pbmUgdGhlIGVmZmVjdCBvZiBwaG9zcGhhdGUgc3RhcnZhdGlvbiBvbiBzdXJ2aXZhbAogIGZpbHRlcihEYXRlICVpbiUgdXNlLnMxYiwgU2Vjb25kYXJ5ID09ICJNIikgJT4lIAogIG11dGF0ZSgKICAgICMgYXJiaXRyYXJpbHkgZGVjaWRlIGFueSBDRlUgY291bnRzIDwgMyBhcmUgbm90IGluY2x1ZGVkIGR1ZSB0byBoaWdoIENWCiAgICBDb3VudCA9IGlmZWxzZShDb3VudCA8IDMsIE5BLCBDb3VudCksCiAgICBzY2FsZWQgPSBDb3VudCAqIERpbHV0aW9ucyAqIDFlLTIKICApICU+JSAKICBncm91cF9ieShEYXRlLCBTdHJhaW4pICU+JSAKICAjIGNhbGN1bGF0ZSByIGFuZCByJwogIG11dGF0ZShyID0gc2NhbGVkIC8gc2NhbGVkW1ByaW1hcnkgPT0gIk0iXSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgZmlsdGVyKFByaW1hcnkgIT0gIk0iKSAlPiUgCiAgc2VsZWN0KERhdGUsIFNwZWNpZXMsIFN0cmFpbiwgUHJpbWFyeSwgQ291bnQsIHIpICU+JSAKICBiaW5kX3Jvd3ModG1wKSAlPiUgCiAgbXV0YXRlKFByaW1hcnkgPSBmYWN0b3IoUHJpbWFyeSwKICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJQIiwgIjYyLjUiLCAiMTI1IiwgIjBOaSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIi1QaSIsICJSYXBhXG42Mi41IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUmFwYVxuMTI1IiwgIi1OaXRyb2dlbiIpKSkKYGBgCgpgYGB7cn0KZ2dwbG90KGRhdC5QcmltLCBhZXMoeCA9IFByaW1hcnksIHkgPSByKSkgKyBwLmFzciArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLjIsIDEuMiwgYnkgPSAwLjIpLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICB4bGFiKCJQcmltYXJ5IHN0cmVzcyAoNDUgbWluKSIpICsgeWxhYigiU3Vydml2YWwgJSIpCmdnc2F2ZSgiLi4vb3V0cHV0LzIwMjMwMjExLXByaW1hcnktc3RyZXNzLWVmZmVjdC1vbi1zdXJ2aXZhbC5wbmciKQpgYGAKCl8qKlN0YXRpc3RpY2FsIHRlc3RzKipfCgpVc2UgdGhlIFtuZXN0LW1hcC11bm5lc3Qgd29ya2Zsb3ddKGh0dHBzOi8vYnJvb20udGlkeW1vZGVscy5vcmcvYXJ0aWNsZXMvYnJvb21fYW5kX2RwbHlyLmh0bWwpCgpgYGB7cn0KZGF0LlByaW0gJT4lIAogIHNlbGVjdChTcGVjaWVzLCBQcmltYXJ5LCByKSAlPiUgCiAgbmVzdChkYXRhID0gcikgJT4lIAogIG11dGF0ZSgKICAgIHRlc3QgPSBtYXAoZGF0YSwgfiB0LnRlc3QoLngsIG11ID0gMSwgYWx0ZXJuYXRpdmUgPSAidHdvIikpLAogICAgdGlkaWVkID0gbWFwKHRlc3QsIHRpZHkpCiAgKSAlPiUgCiAgdW5uZXN0KHRpZGllZCkgJT4lIAogIHNlbGVjdChTcGVjaWVzLCBQcmltYXJ5LCBtZWFuX3IgPSBlc3RpbWF0ZSwgcC52YWx1ZSwgY29uZi5sb3csIGNvbmYuaGlnaCwgYWx0ZXJuYXRpdmUpICU+JSAKICBtdXRhdGUoUC5hZGogPSBwLmFkanVzdChwLnZhbHVlLCBtZXRob2QgPSAiQkgiKSwKICAgICAgICAgYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCByb3VuZCwgZGlnaXRzID0gMykpICU+JSAKICBhcnJhbmdlKFNwZWNpZXMsIFByaW1hcnkpCmBgYAoKIyMjIENhbGlicmF0ZSBzZWNvbmRhcnkgc3RyZXNzIHN0cmVuZ3RoCkppbnllIHVzZWQgdHdvIHNldHMgb2YgSDJPMiBjb25jZW50cmF0aW9ucyBpbiB0aGlzIGV4cGVyaW1lbnQsIGkuZS4sIDQwLzQgbU0gYW5kIDYwLzYgbU0gZm9yIF9DLiBnbGFicmF0YV8gYW5kIF9TLiBjZXJldmlzaWFlXywgcmVzcGVjdGl2ZWx5LiAKCmBgYHtyfQp3aXRoKGRhdC42LCB0YWJsZShEYXRlLCBwYXN0ZShTcGVjaWVzLCBIMk8yLCBzZXAgPSAiOiIpKSkKYGBgCgpGaXJzdCwgd2Ugd2lsbCB0ZXN0IGlmIHRoZSBzdXJ2aXZhbCB1bmRlciB0aGVzZSBIMk8yIGNvbmNlbnRyYXRpb25zIGFyZSBjb21wYXJhYmxlIGFjcm9zcyBzcGVjaWVzLCBieSBhbmFseXppbmcgdGhlIGJhc2FsIHN1cnZpdmFsIHJhdGUgcgoKU3RhdGlzdGljYWwgdGVzdCBmb3IgZGlmZmVyZW5jZXMgaW4gYmFzYWwgc3Vydml2YWwgYmV0d2VlbiBzcGVjaWVzIGF0IDYwIG9yIDYgbU0uIEEgV2lsY294b24gc2lnbmVkLXJhbmsgdGVzdCBpcyB1c2VkIGhlcmUgc2luY2UgdGhlIHR3byBncm91cHMgYXJlIGRlcGVuZGVudCAoPWdyb3VwZWQpIGJ5IHRoZSBkYXkgb2YgdGhlIGV4cGVyaW1lbnQuIE9uZSByZXBsaWNhdGUgd2FzIHJ1biBwZXIgZGF5LiBVc2luZyBhIHBhaXJlZC10ZXN0IGVuc3VyZXMgdGhhdCBkYXktdG8tZGF5IHZhcmlhdGlvbiBpcyBhY2NvdW50ZWQgZm9yLgpgYGB7cn0KdG1wIDwtIGRhdC42ICU+JSAKICBmaWx0ZXIoSDJPMiAlaW4lIGMoIjYwbU0iLCAiNm1NIiksIEdyb3VwID09ICJNTyIsIAogICAgICAgICAhKERhdGUgJWluJSBjKCIwMS8xMi8yMyIsICIwMS8xOC8yMyIsICIwMi8wMi8yMyIpKSkjICU+JSAKdG1wICU+JSBncm91cF9ieShTcGVjaWVzKSAlPiUgc3VtbWFyaXplKG1lYW4gPSBtZWFuKGBNTy9NTWApKQp3aWxjb3gudGVzdChgTU8vTU1gIH4gU3BlY2llcywgZGF0YSA9IHRtcCwgcGFpcmVkID0gVFJVRSkKYGBgCgpTdGF0aXN0aWNhbCB0ZXN0IGZvciBkaWZmZXJlbmNlcyBpbiBiYXNhbCBzdXJ2aXZhbCBiZXR3ZWVuIHNwZWNpZXMgYXQgNDAgb3IgNCBtTS4KYGBge3J9CnRtcCA8LSBkYXQuNiAlPiUgCiAgZmlsdGVyKEgyTzIgJWluJSBjKCI0MG1NIiwgIjRtTSIpLCBHcm91cCA9PSAiTU8iLCAhKERhdGUgJWluJSBjKCIwMi8wMi8yMyIpKSkKdG1wICU+JSBncm91cF9ieShTcGVjaWVzKSAlPiUgc3VtbWFyaXplKG1lYW4gPSBtZWFuKGBNTy9NTWApKQp3aWxjb3gudGVzdChgTU8vTU1gIH4gU3BlY2llcywgZGF0YSA9IHRtcCwgcGFpcmVkID0gVFJVRSkKYGBgCgpTdGF0aXN0aWNhbCB0ZXN0IGZvciBkaWZmZXJlbmNlcyBpbiBiYXNhbCBzdXJ2aXZhbCBiZXR3ZWVuIHRoZSBoaWdoIGFuZCBsb3cgSDJPMiBjb25jZW50cmF0aW9ucyAoNjAvNiB2cyA0MC80IG1NKSwgc3BlY2llcyBjb21iaW5lZC4KYGBge3J9CnRtcCA8LSBmaWx0ZXIoZGF0LjYsIEdyb3VwID09ICJNTyIpICU+JSAKICBtdXRhdGUoc2Vjb25kYXJ5ID0gZmFjdG9yKEgyTzIsIGxldmVscyA9IGMoIjYwbU0iLCAiNm1NIiwgIjQwbU0iLCAiNG1NIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJoaWdoIiwgImhpZ2giLCAibG93IiwgImxvdyIpKSkKdG1wICU+JSAKICBncm91cF9ieShzZWNvbmRhcnksIFNwZWNpZXMpICU+JSAKICBzdW1tYXJpemUobWVhbiA9IG51bShtZWFuKGBNTy9NTWApLCBkaWdpdHMgPSAzKSwgLmdyb3VwcyA9ICJkcm9wIikKd2lsY294LnRlc3QoYE1PL01NYCB+IHNlY29uZGFyeSwgZGF0YSA9IHRtcCwgcGFpcmVkID0gRkFMU0UpCmFub3ZhKGxtKGBNTy9NTWAgfiBTcGVjaWVzICsgc2Vjb25kYXJ5LCBkYXRhID0gdG1wKSkKYGBgCgo+IFdlIGNhbiBjb25jbHVkZSB0aGF0IHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gc3Vydml2YWwgd2hlbiBjb21wYXJpbmcgNDAgbU0gdnMgNCBtTSBmb3IgX0MuIGdsYWJyYXRhXyB2cyBfUy4gY2VyZXZpc2lhZV8uIFNpbWlsYXJseSwgdGhlcmUgaXMgbm8gc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiBzdXJ2aXZhbCB3aGVuIDYwIG1NIGFuZCA2IG1NIHdlcmUgdXNlZCB0byB0cmVhdCB0aGUgdHdvIHNwZWNpZXMsIHJlc3BlY3RpdmVseS4gSG93ZXZlciwgdGhlIHN1cnZpdmFsIHJhdGUgaXMgc2lnbmlmaWNhbnRseSBsb3dlciB1bmRlciB0aGUgaGlnaGVyIHNldCBvZiBjb25jZW50cmF0aW9ucyAoNjAgYW5kIDYgbU0pIGNvbXBhcmVkIHdpdGggdGhlIGxvd2VyIG9uZXMgKDQwIGFuZCA0IG1NKQoKIyMjIFJhcGFteWNpbiBBU1IKV2lsbCB1c2UgSlkncyBwcmUtY2FsY3VsYXRlZCBBU1IgdmFsdWVzLiBXZSB3aWxsIGZpcnN0IHBsb3QgdGhlIDQwLzQgbU0gYW5kIDYwLzYgbU0gZGF0YSBzZXBhcmF0ZWx5LiBUaGVuLCB3ZSB3aWxsIGNvbWJpbmUgdGhlbS4gQSBmaW5hbCBjb25jbHVzaW9uIHdpbGwgYmUgZHJhd24uCmBgYHtyfQojIHdlIHdpbGwgbm90IHVzZSB0aGUgZGF5cyBvZiBleHBlcmltZW50cyB3aGVyZSBvbmx5IG9uZSBzcGVjaWVzIHdhcyBhc3NheWVkCmRhdC42cCA8LSBmaWx0ZXIoZGF0LjYsIEgyTzIgIT0gIk1vY2siKSAlPiUgIyByZW1vdmUgdGhlIFhNIGdyb3VwcwogIHJlbmFtZShwcmltYXJ5ID0gYDFzdF9TdHJlc3NgLCByID0gYE1PL01NYCwgclAgPSBgUE8vUE1gKSAlPiUgCiAgZ3JvdXBfYnkoRGF0ZSwgU3RyYWluLCBIMk8yKSAlPiUgIyBmb3JtIGdyb3VwcyB0byBhcHBseSB0aGUgc2FtZSBNTy9NTQogIG11dGF0ZSgKICAgIHIgPSByW3ByaW1hcnkgPT0gIk1vY2siXSwgIyBNTy9NTSBmb3IgZWFjaCBncm91cAogICAgc2Vjb25kYXJ5ID0gIGZhY3RvcihIMk8yLCBsZXZlbHMgPSBjKCI0MG1NIiwgIjRtTSIsICI2MG1NIiwgIjZtTSIpLAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCI0MC80bU0iLCAiNDAvNG1NIiwgIjYwLzZtTSIsICI2MC82bU0iKSkKICApICU+JSAKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKCFpcy5uYShyUCkpCmBgYAoKbXkgY2FsY3VsYXRpb24gaXMgdGhlIHNhbWUgYXMgSlkncwpgYGB7cn0Kd2l0aChkYXQuNnAsIHN1bShyb3VuZChyUC9yLCA1KSAhPSByb3VuZChBU1JfU2NvcmUsIDUpKSkKYGBgCgojIyMjIFBsb3QKYGBge3J9CmRhdC42cCAlPiUgCiAgZmlsdGVyKHByaW1hcnkgIT0gIjBOaSIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBwcmltYXJ5LCB5ID0gQVNSX1Njb3JlKSkgKyBwLmFzciArCiAgbGFicyh4ID0gIlJhcGFteWNpbiAobmcvbUwpIiwgeSA9ICJBU1IgU2NvcmUgKHInL3IpIikKZ2dzYXZlKCIuLi9vdXRwdXQvMjAyMzAyMjEtcmFwYW15Y2luLUFTUi5wbmciLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQpCmBgYAogIAojIyMjIFN0YXRpc3RpY2FsIHRlc3QKCldpbGNveG9uIHNpZ25lZC1yYW5rIHRlc3QgY29tcGFyaW5nIHInIGFuZCByIChwYWlyZWQgZGF0YSkKYGBge3J9CmRhdC42cCAlPiUgCiAgI2ZpbHRlcihzZWNvbmRhcnkgPT0gIjYwLzZtTSIpICU+JSAKICBzZWxlY3QoU3BlY2llcywgcHJpbWFyeSwgciwgclApICU+JSAKICBuZXN0KGRhdGEgPSBjKHIsIHJQKSkgJT4lIAogIG11dGF0ZSgKICAgIHRlc3QgPSBtYXAoZGF0YSwgfiB3aWxjb3gudGVzdCgueCRyUCwgLngkciwgcGFpcmVkID0gVFJVRSwgYWx0ZXJuYXRpdmUgPSAiZyIpKSwKICAgIHRpZGllZCA9IG1hcCh0ZXN0LCB0aWR5KQogICkgJT4lIAogIHVubmVzdCh0aWRpZWQpICU+JSAKICBzZWxlY3QoU3BlY2llcywgcHJpbWFyeSwgVCA9IHN0YXRpc3RpYywgcC52YWx1ZSwgbWV0aG9kLCBhbHRlcm5hdGl2ZSkgJT4lIAogIG11dGF0ZShQLmFkaiA9IHAuYWRqdXN0KHAudmFsdWUsIG1ldGhvZCA9ICJCSCIpLAogICAgICAgICBhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIHJvdW5kLCBkaWdpdHMgPSAzKSkKYGBgCgpQYWlyZWQgdC10ZXN0cyBjb21wYXJpbmcgcicgYW5kIHIKYGBge3J9CmRhdC42cCAlPiUgCiAgI2ZpbHRlcihwcmltYXJ5ICE9ICIwTmkiKSAlPiUgCiAgc2VsZWN0KFNwZWNpZXMsIHByaW1hcnksIHIsIHJQKSAlPiUgCiAgbmVzdChkYXRhID0gYyhyLCByUCkpICU+JSAKICBtdXRhdGUoCiAgICB0ZXN0ID0gbWFwKGRhdGEsIH4gdC50ZXN0KC54JHJQLCAueCRyLCBwYWlyZWQgPSBUUlVFLCBhbHRlcm5hdGl2ZSA9ICJnIikpLAogICAgdGlkaWVkID0gbWFwKHRlc3QsIHRpZHkpCiAgKSAlPiUgCiAgdW5uZXN0KHRpZGllZCkgJT4lIAogIHNlbGVjdChTcGVjaWVzLCBwcmltYXJ5LCBwLnZhbHVlLCBtZXRob2QsIGFsdGVybmF0aXZlKSAlPiUgCiAgbXV0YXRlKFAuYWRqID0gcC5hZGp1c3QocC52YWx1ZSwgbWV0aG9kID0gIkJIIiksCiAgICAgICAgIGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgcm91bmQsIGRpZ2l0cyA9IDMpKQpgYGAKCj4gSW4gY29uY2x1c2lvbiwgd2UgZm91bmQgc2lnbmlmaWNhbnQgQVNSIGVmZmVjdCBhdCAxMjUgbmcvbUwgcmFwYW15Y2luIHRyZWF0bWVudCBpbiBfQy4gZ2xhYnJhdGFfIHVzaW5nIGVpdGhlciBhIFdpbGNveG9uIHNpZ25lZC1yYW5rIHRlc3QgKG5vbnBhcmFtZXRyaWMpIG9yIGEgcGFpcmVkIHQgdGVzdCwgYm90aCB1c2luZyBhIDAuMDUgcmVqZWN0aW9uIHRocmVob2xkLiBXZSBjb3VsZG4ndCByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvZiBubyBzdXJ2aXZhbCBkaWZmZXJlbmNlIGJldHdlZW4gcmFwYW15Y2luIHRyZWF0ZWQgdnMgdW50cmVhdGVkIHNhbXBsZXMgZm9yIHRoZSA2Mi41IG5nL21MIGNvbmNlbnRyYXRpb24sIGFuZCBhbHNvIG5vdCBmb3IgdGhlIGhpZ2hlciBkb3NlIGluIF9TLiBjZXJldmlzaWFlXw==