Background

This is the flow cytometry data for miglog phase Cg stained with PI/PI+SYTO9/ SYTO+PI in different staining orders, and run through flow cytometry (details in ELN). The goal is to establish FungaLight’s distinguishing power with different staining protocols.

require(tidyverse)
require(flowCore)
require(flowClust)
require(openCyto)
require(ggcyto)
require(cowplot)
require(ggridges)
old <- theme_set(theme_minimal())

Import data

FCS files are stored in RDSS/user/flow cytometry, FCS is read and write into an input tsv table. The tsv file is avaliable from the Input folder.

# use relative path to make it easier for collaboration
data.path = "/Volumes/rdss_bhe2/User/Hanxi Tang/Flow Cytometry/20240109_0116 Dye order/"
dat0 <- read.flowSet(path = data.path, transformation = FALSE,  # the original values are already linearized. 
                     emptyValue = FALSE,  alter.names = TRUE,   # change parameter names to R format
                     column.pattern = ".H|FSC|SSC") # only load the height variables for the fluorescent parameters

Simplify the sample names

#require(PTXQC)
#source("../script/20220326-simplify-names-subroutine.R")
oriNames <- sampleNames(dat0)
tmp <- str_split(oriNames, pattern = "[ _]+", simplify = TRUE)[,c(1, 6, 7)]
colnames(tmp) <- c("Date", "Treatment", "Dye")
sample <- data.frame(tmp) %>% 
  mutate(
    Dye = case_match(
      Dye,
      "p.fcs" ~ "PI alone",
      "pf.fcs" ~ "PI first",
      "sf.fcs" ~ "SYTO9+PI",
      .default = NA
    )
  )
rownames(sample) <- oriNames
pData(dat0) <- sample
dat <- dat0[!is.na(sample$Dye)]
print(pData(dat) %>% as_tibble())
write_tsv(pData(dat), file = "../data/10.01-sample-list.tsv")

Basic gating

Outlier

The following gaphing steps are used to gate singlets by FSC and SSC values. Only singlets are included in analysis.

outlier.gate <- rectangleGate(filterId = "-outlier", "FSC.H" = c(1.2e5, 1e6), "SSC.H" = c(1e2, 1e6))
ggcyto(dat[c(2,20)], aes(x = FSC.H, y = SSC.H), subset = "root") +
  geom_hex(bins = 64) + geom_gate(outlier.gate) + facet_wrap(~name, ncol = 2) + ggcyto_par_set(limits = "instrument")
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Add gate to GS

# shorten the names of the samples for plotting
shortNames <- with(pData(dat), 
                   paste(substr(Date, 1, 4), paste0(Treatment, " mM")
                         , Dye, sep = "_"))
names(shortNames) <- sampleNames(dat)
gs <- GatingSet(dat) # create a GatingSet
# rename the GatingSet
if(all(sampleNames(gs) == names(shortNames)))
  pData(gs)$name <- shortNames
# repair the Date column in pData
pData(gs)$Date = paste0("0", pData(gs)$Date)
# add the outlier gate
gs_pop_add(gs, outlier.gate, parent = "root")
[1] 2
# compute
recompute(gs)
done!

Gate for singlets

scPars <- ggcyto_par_set(limits = list(x = c(0,1e6), y = c(30,300)))
ex <- Subset(dat[[1]], outlier.gate)
polygon <- matrix(c(1e5, 1e5, 1e6, 1e6, 
                    60, 105, 135,60), ncol = 2)
colnames(polygon) <- c("FSC.H", "FSC.W")
singlet.gate <- polygonGate(filterId = "singlet", .gate = polygon)
ggcyto(ex, aes(x = FSC.H, y = FSC.W)) + geom_hex(bins = 128) + geom_gate(singlet.gate) + geom_stats() + scPars
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Add this gate to the gatingSet

gs_pop_add(gs, singlet.gate, parent = "-outlier", name = "singlet")
[1] 3
recompute(gs)
done!
scPars <- ggcyto_par_set(limits = list(x = c(0,1e6), y = c(30,200)))
test <- sample(1:length(gs), 8)
ggcyto(gs[test], aes(x = FSC.H, y = FSC.W), subset = "-outlier") +
  geom_hex(bins = 128) + geom_gate("singlet") + facet_wrap(~name, ncol = 4) + 
  scPars# + theme(strip.text = element_blank())
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

FSC and SSC vs treatment and dye

FSC

mult_format <- function() {
     function(x) format(x/10000,digits = 2) 
}
for(date in c("011124", "011524", "011624")){
  p <- ggcyto(gs[pData(gs)$Date == date], aes(x = FSC.H), subset = "singlet") + 
    geom_density_ridges(aes(y = Treatment), fill = "forestgreen", alpha = 0.8) + 
    scale_x_continuous(labels = mult_format(), name = "FSC.H x 10000") +
    facet_wrap(~Dye) + labs(title = paste0("Date: ", date))
  print(p)
}

Mock treated sample stands out - the three H2O2 treated samples show a trend of decreasing FSC with increasing ROS Mock has a FSC in between 10 and 100 mM

FSC vs BL1.H (green staining)

for(date in c("011124", "011524", "011624")){
  p <- ggcyto(gs[pData(gs)$Date == date], aes(x = BL1.H, y = FSC.H), subset = "singlet") + 
    geom_hex(bins = 128) + 
    #geom_gate(live.gate) + 
    #geom_stats(location = "data", adjust = c(0.1, 0.8), digits = 2) + 
    labs(title = paste0("Date: ", date)) +
    facet_grid(Dye ~ Treatment) +
    scale_x_logicle() + #scale_y_logicle() + 
    theme(strip.text = element_text(size = rel(1.1), color = "steelblue", face = 2))
  print(p)
}

SSC

for(date in c("011124", "011524", "011624")){
  p <- ggcyto(gs[pData(gs)$Date == date], aes(x = SSC.H), subset = "singlet") + 
    geom_density_ridges(aes(y = Treatment), fill = "forestgreen", alpha = 0.8) + 
    scale_x_continuous(labels = mult_format(), name = "FSC.H x 10000") +
    facet_wrap(~Dye) + labs(title = paste0("Date: ", date))
  print(p)
}

SSC (complexity of cell, roughly) decreases with increasing H2O2 concentration Mock again show a different pattern.

Gate for scoring

Live = red negative

This is the live population with red fluorescence below 10^2.2

Important: I changed the Red top boundary to 10^2.3 from 10^2.2

Main takeaway

  1. From 10mM to 1M treated samples, %live decreases and the change is much more obvious in the dual stain (PI first or simultaneous) than PI alone

  2. The mock treated sample has a visible high red high green (not as high and prominent as the 100 mM treated) than 10 mM treated. It doesn’t follow the trend above.

#scPars <- ggcyto_par_set(limits = list(x = c(0,1e6), y = c(0,1e5)))
polygon <- matrix(c(0, 10^5, 10^5, 0,
                    10^2.3, 10^2.3, 0, 0), ncol = 2)
colnames(polygon) <- c("BL1.H", "BL3.H")
live.gate <- polygonGate(filterId = "live", .gate = polygon)
for(date in c("011124", "011524", "011624")){
  p <- ggcyto(gs[pData(gs)$Date == date], aes(x = BL1.H, y = BL3.H), subset = "singlet") + 
    geom_hex(bins = 128) + 
    geom_gate(live.gate) + 
    geom_stats(location = "data", adjust = c(0.1, 0.8), digits = 2) + 
    labs(title = paste0("Date: ", date)) +
    facet_grid(Dye ~ Treatment) +
    scale_x_logicle() + scale_y_logicle() + 
    theme(strip.text = element_text(size = rel(1.1), color = "steelblue", face = 2))
  print(p)
}

Notice the higher percentage of events in the live gate in 10 mM vs mock.

Add this gate to the gatingSet

Intermediate = high G/R

This is the intermediate population with high Red and Green. We hypothesize that they represent the

Important: I changed the bottom boundary from 10^2.2 to 10^2.3, and the left boundary from 10^3 to 2*10^3

Main takeaway

  1. Different from the %live gate, the intermediate population is most obvious in the 100 mM treated sample, and absent in both the 10 mM and 1M treated ones. This suggests that this population could be useful for distinguishing stress levels below the lethal concentration but above the tolerance levels of the species - in this case, < 1M and > 10 mM.

  2. The mock treated sample showed an intermediate population. Was unexpected.

#scPars <- ggcyto_par_set(limits = list(x = c(0,1e6), y = c(0,1e6)))
#ex <- Subset(dat.f1g[[9]], singlet.gate)
polygon <- matrix(c(10^5, 2*10^3, 10^5,
                    10^2.3, 10^2.3, 10^4), ncol = 2)
colnames(polygon) <- c("BL1.H", "BL3.H")
inter.gate <- polygonGate(filterId = "inter", .gate = polygon)
for(date in c("011124", "011524", "011624")){
  p <- ggcyto(gs[pData(gs)$Date == date], aes(x = BL1.H, y = BL3.H), subset = "singlet") + 
    geom_hex(bins = 128) + 
    geom_gate(inter.gate) + 
    geom_stats(location = "data",  adjust = c(0.1, 0.8), digits = 2) + 
    labs(title = paste0("Date: ", date)) +
    facet_grid(Dye ~ Treatment) +
    scale_x_logicle() + scale_y_logicle() + 
    theme(strip.text = element_text(size = rel(1.1), color = "steelblue", face = 2))
  print(p)
}

Add this gate to the gatingSet

Dead = High red low green

We don’t need to set the dead gate because all we want is the percent of events in that gate, not the MFI for either channel. The percentage can be calculated by subtracting the percent of events in the previous two gates from 100%.

Exported gate stats

% of events in each of the three gates

gated_stats <- gs_pop_get_stats(gs, type = "count") %>% 
  as_tibble() %>% 
  mutate(pop = gsub(".*/", "", pop), pop = gsub("-outlier", "cells", pop)) %>% 
  pivot_wider(names_from = pop, names_prefix = "n_", values_from = count) %>% 
  mutate(
    #p_singlet = n_singlet / n_cells,
    p_live = n_live / n_singlet,
    p_intermediate = n_intermediate / n_singlet,
    p_dead = 1 - p_live - p_intermediate
  )
#write_tsv(gated_data, file = "../Input/20240124-fig-2-Dye-Order-gated-ht.tsv")
#print(gated_data)

MFI in the live and intermediate gates

popMFI <- gs_pop_get_stats(gs, nodes = c("live", "intermediate"), type = pop.MFI) %>% 
  as_tibble() %>% 
  select(sample, pop, FSC = `FSC-H`, BL1 = `Fungalight Green-H`) %>% 
  pivot_wider(names_from = pop, values_from = c(FSC, BL1))

Combine the data and meta data

final <- select(pData(dat), sample = name, everything()) %>% 
  left_join(select(gated_stats, -starts_with("n_")),  by = "sample") %>% 
  left_join(popMFI, by = "sample")

write_tsv(final, file = "../data/12.01-gated-output-20240117.tsv")
print(final %>% select(-sample))

Exploratory comparison between PI alone and combo

PI alone

p1 <- final %>% 
  dplyr::filter(Dye == "PI alone") %>% 
  ggplot(aes(x = Treatment, y = 1-p_live)) + 
  geom_point(size = 2, shape = 21, position = position_jitter(0.05)) + 
  #stat_summary(fun = "mean", geom = "point", color = "red") +
  labs(x = bquote(H[2]*O[2]~(mM)), y = "1 - %Live") +
  theme_cowplot()

inset <- final %>% 
  dplyr::filter(Dye == "PI alone", Treatment != "1000") %>% 
  ggplot(aes(x = Treatment, y = 1-p_live)) + 
  geom_bar(stat = "summary", fun = "mean", fill = "skyblue2", alpha = 0.7) +
  geom_point(size = 2, position = position_jitter(0.05)) + 
  #stat_summary(fun = "mean", geom = "point", size = 15, shape = "-", color = "red") +
  labs(x = bquote(H[2]*O[2]~(mM)), y = "1 - %Live") +
  theme_minimal_hgrid(11)

ggdraw(p1 + labs(subtitle = "PI alone, doesn't disguish 10 vs 100 mM")) + 
  draw_plot(inset, .2, .8, .4, .5, vjust = 1) +
  draw_plot_label(c("A", "B"), c(0, 0.18), c(1, 0.85))

ggsave("../output/12.01-PI-alone-one-minus-perc-live.png", width = 5, height = 4)

PI+SYTO9

p2 <- final %>% 
  dplyr::filter(Dye != "PI alone", Treatment != "0") %>% 
  ggplot(aes(x = Treatment, y = 1-p_live)) + 
  geom_bar(stat = "summary", fun = "mean", fill = "gray", alpha = 0.7) +
  geom_point(size = 2, position = position_jitter(0.05)) + 
  #stat_summary(fun = "mean", geom = "point", shape = "-", 
  #             size = 15, color = "red", position = position_nudge(x = 0.2)) +
  labs(x = bquote(H[2]*O[2]~(mM)), y = "1 - %Live") +
  facet_wrap(~Dye) +
  theme_cowplot() +
  theme(strip.text = element_text(size = rel(1.2), face = 2),
        strip.background = element_blank())

p2
ggsave("../output/12.01-PI+SYTO9-one-minus-plive.png")
Saving 7.29 x 4.51 in image

Plot % Dead and Compare

```r
pf1g <- gated_data %>%
  dplyr::filter(!(Dye %in% c(\PI\))) %>% 
  dplyr::filter(!(Treatment %in% c(\1000 mM\)))  %>%
  #mutate(Dilution = factor(Dilution, levels = c(\250 x\, \500 x\, \1000 x\, \2000 x\))) %>%
  ggplot(aes(x = Treatment, y = percent_Live)) +
  facet_wrap(~ Dye, scale = \free_y\) +
  geom_boxplot() +
  geom_point(stroke = 1, size = 2, position = position_jitter(0.2)) +
  scale_y_continuous(labels = scales::percent) +
  theme_minimal()
pf1g +
  labs(x = \Hydrogen Peroxide Treatment Concentration\, y = \Gated Live Cells\) +
  panel_border(color = \black\, size = 1.5) +
  theme(axis.line = element_blank(),
        strip.background = element_blank(),
        axis.text.x = element_text(size = 12, face = \bold\, color = \black\),  # Adjust size and face (bold)
        axis.text.y = element_text(size = 16, face = \bold\, color = \black\),
        axis.title.x = element_text(size = 16, face = \bold\),
        axis.title.y = element_text(size = 16, face = \bold\)
        )+ 
  theme(strip.text = element_text(size = 16, face = \bold\)) 
#ggsave(\../output/20240104-PI-Dilutions-Gated_RP-Plot.png\, width = 7, height = 5)

```

LS0tCnRpdGxlOiAiRHllIE9yZGVyICYgRGlzdGluZ3Vpc2hpbmcgUG93ZXIiCmF1dGhvcjogSGFueGkgVGFuZywgQmluIEhlCmRhdGU6ICIyMDI0LTAxLTE3ICh1cGRhdGVkIGByIFN5cy50aW1lKClgKSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogNAogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKIyBCYWNrZ3JvdW5kClRoaXMgaXMgdGhlIGZsb3cgY3l0b21ldHJ5IGRhdGEgZm9yIG1pZ2xvZyBwaGFzZSBDZyBzdGFpbmVkIHdpdGggUEkvUEkrU1lUTzkvIFNZVE8rUEkgaW4gZGlmZmVyZW50IHN0YWluaW5nIG9yZGVycywgYW5kIHJ1biB0aHJvdWdoIGZsb3cgY3l0b21ldHJ5IChkZXRhaWxzIGluIEVMTikuIFRoZSBnb2FsIGlzIHRvIGVzdGFibGlzaCBGdW5nYUxpZ2h0J3MgZGlzdGluZ3Vpc2hpbmcgcG93ZXIgd2l0aCBkaWZmZXJlbnQgc3RhaW5pbmcgcHJvdG9jb2xzLgoKYGBge3Igc2V0dXAsIG1lc3NhZ2U9RkFMU0V9CnJlcXVpcmUodGlkeXZlcnNlKQpyZXF1aXJlKGZsb3dDb3JlKQpyZXF1aXJlKGZsb3dDbHVzdCkKcmVxdWlyZShvcGVuQ3l0bykKcmVxdWlyZShnZ2N5dG8pCnJlcXVpcmUoY293cGxvdCkKcmVxdWlyZShnZ3JpZGdlcykKYGBgCgpgYGB7cn0Kb2xkIDwtIHRoZW1lX3NldCh0aGVtZV9taW5pbWFsKCkpCmBgYAoKIyBJbXBvcnQgZGF0YQoKPiBGQ1MgZmlsZXMgYXJlIHN0b3JlZCBpbiBSRFNTL3VzZXIvZmxvdyBjeXRvbWV0cnksIEZDUyBpcyByZWFkIGFuZCB3cml0ZSBpbnRvIGFuIGlucHV0IHRzdiB0YWJsZS4gVGhlIHRzdiBmaWxlIGlzIGF2YWxpYWJsZSBmcm9tIHRoZSBJbnB1dCBmb2xkZXIuCgpgYGB7cn0KIyB1c2UgcmVsYXRpdmUgcGF0aCB0byBtYWtlIGl0IGVhc2llciBmb3IgY29sbGFib3JhdGlvbgpkYXRhLnBhdGggPSAiL1ZvbHVtZXMvcmRzc19iaGUyL1VzZXIvSGFueGkgVGFuZy9GbG93IEN5dG9tZXRyeS8yMDI0MDEwOV8wMTE2IER5ZSBvcmRlci8iCmRhdDAgPC0gcmVhZC5mbG93U2V0KHBhdGggPSBkYXRhLnBhdGgsIHRyYW5zZm9ybWF0aW9uID0gRkFMU0UsICAjIHRoZSBvcmlnaW5hbCB2YWx1ZXMgYXJlIGFscmVhZHkgbGluZWFyaXplZC4gCiAgICAgICAgICAgICAgICAgICAgIGVtcHR5VmFsdWUgPSBGQUxTRSwgIGFsdGVyLm5hbWVzID0gVFJVRSwgICAjIGNoYW5nZSBwYXJhbWV0ZXIgbmFtZXMgdG8gUiBmb3JtYXQKICAgICAgICAgICAgICAgICAgICAgY29sdW1uLnBhdHRlcm4gPSAiLkh8RlNDfFNTQyIpICMgb25seSBsb2FkIHRoZSBoZWlnaHQgdmFyaWFibGVzIGZvciB0aGUgZmx1b3Jlc2NlbnQgcGFyYW1ldGVycwpgYGAKCiMjIFNpbXBsaWZ5IHRoZSBzYW1wbGUgbmFtZXMKCmBgYHtyfQojcmVxdWlyZShQVFhRQykKI3NvdXJjZSgiLi4vc2NyaXB0LzIwMjIwMzI2LXNpbXBsaWZ5LW5hbWVzLXN1YnJvdXRpbmUuUiIpCm9yaU5hbWVzIDwtIHNhbXBsZU5hbWVzKGRhdDApCnRtcCA8LSBzdHJfc3BsaXQob3JpTmFtZXMsIHBhdHRlcm4gPSAiWyBfXSsiLCBzaW1wbGlmeSA9IFRSVUUpWyxjKDEsIDYsIDcpXQpjb2xuYW1lcyh0bXApIDwtIGMoIkRhdGUiLCAiVHJlYXRtZW50IiwgIkR5ZSIpCnNhbXBsZSA8LSBkYXRhLmZyYW1lKHRtcCkgJT4lIAogIG11dGF0ZSgKICAgIER5ZSA9IGNhc2VfbWF0Y2goCiAgICAgIER5ZSwKICAgICAgInAuZmNzIiB+ICJQSSBhbG9uZSIsCiAgICAgICJwZi5mY3MiIH4gIlBJIGZpcnN0IiwKICAgICAgInNmLmZjcyIgfiAiU1lUTzkrUEkiLAogICAgICAuZGVmYXVsdCA9IE5BCiAgICApCiAgKQpyb3duYW1lcyhzYW1wbGUpIDwtIG9yaU5hbWVzCnBEYXRhKGRhdDApIDwtIHNhbXBsZQpkYXQgPC0gZGF0MFshaXMubmEoc2FtcGxlJER5ZSldCnByaW50KHBEYXRhKGRhdCkgJT4lIGFzX3RpYmJsZSgpKQp3cml0ZV90c3YocERhdGEoZGF0KSwgZmlsZSA9ICIuLi9kYXRhLzEyLjAxLXNhbXBsZS1saXN0LTIwMjQwMTE3LnRzdiIpCmBgYAoKIyBCYXNpYyBnYXRpbmcKIyMgT3V0bGllcgpUaGUgZm9sbG93aW5nIGdhcGhpbmcgc3RlcHMgYXJlIHVzZWQgdG8gZ2F0ZSBzaW5nbGV0cyBieSBGU0MgYW5kIFNTQyB2YWx1ZXMuIE9ubHkgc2luZ2xldHMgYXJlIGluY2x1ZGVkIGluIGFuYWx5c2lzLgoKYGBge3J9Cm91dGxpZXIuZ2F0ZSA8LSByZWN0YW5nbGVHYXRlKGZpbHRlcklkID0gIi1vdXRsaWVyIiwgIkZTQy5IIiA9IGMoMS4yZTUsIDFlNiksICJTU0MuSCIgPSBjKDFlMiwgMWU2KSkKZ2djeXRvKGRhdFtjKDIsMjApXSwgYWVzKHggPSBGU0MuSCwgeSA9IFNTQy5IKSwgc3Vic2V0ID0gInJvb3QiKSArCiAgZ2VvbV9oZXgoYmlucyA9IDY0KSArIGdlb21fZ2F0ZShvdXRsaWVyLmdhdGUpICsgZmFjZXRfd3JhcCh+bmFtZSwgbmNvbCA9IDIpICsgZ2djeXRvX3Bhcl9zZXQobGltaXRzID0gImluc3RydW1lbnQiKQpgYGAKQWRkIGdhdGUgdG8gR1MKYGBge3J9CiMgc2hvcnRlbiB0aGUgbmFtZXMgb2YgdGhlIHNhbXBsZXMgZm9yIHBsb3R0aW5nCnNob3J0TmFtZXMgPC0gd2l0aChwRGF0YShkYXQpLCAKICAgICAgICAgICAgICAgICAgIHBhc3RlKHN1YnN0cihEYXRlLCAxLCA0KSwgcGFzdGUwKFRyZWF0bWVudCwgIiBtTSIpCiAgICAgICAgICAgICAgICAgICAgICAgICAsIER5ZSwgc2VwID0gIl8iKSkKbmFtZXMoc2hvcnROYW1lcykgPC0gc2FtcGxlTmFtZXMoZGF0KQpncyA8LSBHYXRpbmdTZXQoZGF0KSAjIGNyZWF0ZSBhIEdhdGluZ1NldAojIHJlbmFtZSB0aGUgR2F0aW5nU2V0CmlmKGFsbChzYW1wbGVOYW1lcyhncykgPT0gbmFtZXMoc2hvcnROYW1lcykpKQogIHBEYXRhKGdzKSRuYW1lIDwtIHNob3J0TmFtZXMKIyByZXBhaXIgdGhlIERhdGUgY29sdW1uIGluIHBEYXRhCnBEYXRhKGdzKSREYXRlID0gcGFzdGUwKCIwIiwgcERhdGEoZ3MpJERhdGUpCiMgYWRkIHRoZSBvdXRsaWVyIGdhdGUKZ3NfcG9wX2FkZChncywgb3V0bGllci5nYXRlLCBwYXJlbnQgPSAicm9vdCIpCiMgY29tcHV0ZQpyZWNvbXB1dGUoZ3MpCmBgYAoKIyMgR2F0ZSBmb3Igc2luZ2xldHMKCmBgYHtyIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTR9CnNjUGFycyA8LSBnZ2N5dG9fcGFyX3NldChsaW1pdHMgPSBsaXN0KHggPSBjKDAsMWU2KSwgeSA9IGMoMzAsMzAwKSkpCmV4IDwtIFN1YnNldChkYXRbWzFdXSwgb3V0bGllci5nYXRlKQpwb2x5Z29uIDwtIG1hdHJpeChjKDFlNSwgMWU1LCAxZTYsIDFlNiwgCiAgICAgICAgICAgICAgICAgICAgNjAsIDEwNSwgMTM1LDYwKSwgbmNvbCA9IDIpCmNvbG5hbWVzKHBvbHlnb24pIDwtIGMoIkZTQy5IIiwgIkZTQy5XIikKc2luZ2xldC5nYXRlIDwtIHBvbHlnb25HYXRlKGZpbHRlcklkID0gInNpbmdsZXQiLCAuZ2F0ZSA9IHBvbHlnb24pCmdnY3l0byhleCwgYWVzKHggPSBGU0MuSCwgeSA9IEZTQy5XKSkgKyBnZW9tX2hleChiaW5zID0gMTI4KSArIGdlb21fZ2F0ZShzaW5nbGV0LmdhdGUpICsgZ2VvbV9zdGF0cygpICsgc2NQYXJzCmBgYAoKCkFkZCB0aGlzIGdhdGUgdG8gdGhlIGdhdGluZ1NldApgYGB7cn0KZ3NfcG9wX2FkZChncywgc2luZ2xldC5nYXRlLCBwYXJlbnQgPSAiLW91dGxpZXIiLCBuYW1lID0gInNpbmdsZXQiKQpyZWNvbXB1dGUoZ3MpCmBgYApgYGB7ciBmaWcud2lkdGg9Nn0Kc2NQYXJzIDwtIGdnY3l0b19wYXJfc2V0KGxpbWl0cyA9IGxpc3QoeCA9IGMoMCwxZTYpLCB5ID0gYygzMCwyMDApKSkKdGVzdCA8LSBzYW1wbGUoMTpsZW5ndGgoZ3MpLCA4KQpnZ2N5dG8oZ3NbdGVzdF0sIGFlcyh4ID0gRlNDLkgsIHkgPSBGU0MuVyksIHN1YnNldCA9ICItb3V0bGllciIpICsKICBnZW9tX2hleChiaW5zID0gMTI4KSArIGdlb21fZ2F0ZSgic2luZ2xldCIpICsgZmFjZXRfd3JhcCh+bmFtZSwgbmNvbCA9IDQpICsgCiAgc2NQYXJzIyArIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpCgpgYGAKIyMgRlNDIGFuZCBTU0MgdnMgdHJlYXRtZW50IGFuZCBkeWUgey50YWJzZXR9CgojIyMgRlNDCgpgYGB7cn0KbXVsdF9mb3JtYXQgPC0gZnVuY3Rpb24oKSB7CiAgICAgZnVuY3Rpb24oeCkgZm9ybWF0KHgvMTAwMDAsZGlnaXRzID0gMikgCn0KZm9yKGRhdGUgaW4gYygiMDExMTI0IiwgIjAxMTUyNCIsICIwMTE2MjQiKSl7CiAgcCA8LSBnZ2N5dG8oZ3NbcERhdGEoZ3MpJERhdGUgPT0gZGF0ZV0sIGFlcyh4ID0gRlNDLkgpLCBzdWJzZXQgPSAic2luZ2xldCIpICsgCiAgICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGFlcyh5ID0gVHJlYXRtZW50KSwgZmlsbCA9ICJmb3Jlc3RncmVlbiIsIGFscGhhID0gMC44KSArIAogICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IG11bHRfZm9ybWF0KCksIG5hbWUgPSAiRlNDLkggeCAxMDAwMCIpICsKICAgIGZhY2V0X3dyYXAofkR5ZSkgKyBsYWJzKHRpdGxlID0gcGFzdGUwKCJEYXRlOiAiLCBkYXRlKSkKICBwcmludChwKQp9CmBgYAo+IE1vY2sgdHJlYXRlZCBzYW1wbGUgc3RhbmRzIG91dCAtIHRoZSB0aHJlZSBIMk8yIHRyZWF0ZWQgc2FtcGxlcyBzaG93IGEgdHJlbmQgb2YgZGVjcmVhc2luZyBGU0Mgd2l0aCBpbmNyZWFzaW5nIFJPUwo+IE1vY2sgaGFzIGEgRlNDIGluIGJldHdlZW4gMTAgYW5kIDEwMCBtTQoKIyMjIEZTQyB2cyBCTDEuSCAoZ3JlZW4gc3RhaW5pbmcpCmBgYHtyfQpmb3IoZGF0ZSBpbiBjKCIwMTExMjQiLCAiMDExNTI0IiwgIjAxMTYyNCIpKXsKICBwIDwtIGdnY3l0byhnc1twRGF0YShncykkRGF0ZSA9PSBkYXRlXSwgYWVzKHggPSBCTDEuSCwgeSA9IEZTQy5IKSwgc3Vic2V0ID0gInNpbmdsZXQiKSArIAogICAgZ2VvbV9oZXgoYmlucyA9IDEyOCkgKyAKICAgICNnZW9tX2dhdGUobGl2ZS5nYXRlKSArIAogICAgI2dlb21fc3RhdHMobG9jYXRpb24gPSAiZGF0YSIsIGFkanVzdCA9IGMoMC4xLCAwLjgpLCBkaWdpdHMgPSAyKSArIAogICAgbGFicyh0aXRsZSA9IHBhc3RlMCgiRGF0ZTogIiwgZGF0ZSkpICsKICAgIGZhY2V0X2dyaWQoRHllIH4gVHJlYXRtZW50KSArCiAgICBzY2FsZV94X2xvZ2ljbGUoKSArICNzY2FsZV95X2xvZ2ljbGUoKSArIAogICAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMSksIGNvbG9yID0gInN0ZWVsYmx1ZSIsIGZhY2UgPSAyKSkKICBwcmludChwKQp9CmBgYAoKCiMjIyBTU0MKCmBgYHtyfQpmb3IoZGF0ZSBpbiBjKCIwMTExMjQiLCAiMDExNTI0IiwgIjAxMTYyNCIpKXsKICBwIDwtIGdnY3l0byhnc1twRGF0YShncykkRGF0ZSA9PSBkYXRlXSwgYWVzKHggPSBTU0MuSCksIHN1YnNldCA9ICJzaW5nbGV0IikgKyAKICAgIGdlb21fZGVuc2l0eV9yaWRnZXMoYWVzKHkgPSBUcmVhdG1lbnQpLCBmaWxsID0gImZvcmVzdGdyZWVuIiwgYWxwaGEgPSAwLjgpICsgCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbXVsdF9mb3JtYXQoKSwgbmFtZSA9ICJGU0MuSCB4IDEwMDAwIikgKwogICAgZmFjZXRfd3JhcCh+RHllKSArIGxhYnModGl0bGUgPSBwYXN0ZTAoIkRhdGU6ICIsIGRhdGUpKQogIHByaW50KHApCn0KYGBgCj4gU1NDIChjb21wbGV4aXR5IG9mIGNlbGwsIHJvdWdobHkpIGRlY3JlYXNlcyB3aXRoIGluY3JlYXNpbmcgSDJPMiBjb25jZW50cmF0aW9uCj4gTW9jayBhZ2FpbiBzaG93IGEgZGlmZmVyZW50IHBhdHRlcm4uCgoKIyBHYXRlIGZvciBzY29yaW5nIHsudGFic2V0fQoKIyMgTGl2ZSA9IHJlZCBuZWdhdGl2ZQoKVGhpcyBpcyB0aGUgbGl2ZSBwb3B1bGF0aW9uIHdpdGggcmVkIGZsdW9yZXNjZW5jZSBiZWxvdyAxMF4yLjIKCj4gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+SW1wb3J0YW50OiBJIGNoYW5nZWQgdGhlIFJlZCB0b3AgYm91bmRhcnkgdG8gMTBeMi4zIGZyb20gMTBeMi4yPC9zcGFuPgoKPiAqKk1haW4gdGFrZWF3YXkqKgo+Cj4gMS4gRnJvbSAxMG1NIHRvIDFNIHRyZWF0ZWQgc2FtcGxlcywgJWxpdmUgZGVjcmVhc2VzIGFuZCB0aGUgY2hhbmdlIGlzIG11Y2ggbW9yZSBvYnZpb3VzIGluIHRoZSBkdWFsIHN0YWluIChQSSBmaXJzdCBvciBzaW11bHRhbmVvdXMpIHRoYW4gUEkgYWxvbmUKPgo+IDIuIFRoZSBtb2NrIHRyZWF0ZWQgc2FtcGxlIGhhcyBhIHZpc2libGUgaGlnaCByZWQgaGlnaCBncmVlbiAobm90IGFzIGhpZ2ggYW5kIHByb21pbmVudCBhcyB0aGUgMTAwIG1NIHRyZWF0ZWQpIHRoYW4gMTAgbU0gdHJlYXRlZC4gSXQgZG9lc24ndCBmb2xsb3cgdGhlIHRyZW5kIGFib3ZlLgoKYGBge3IsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTV9CiNzY1BhcnMgPC0gZ2djeXRvX3Bhcl9zZXQobGltaXRzID0gbGlzdCh4ID0gYygwLDFlNiksIHkgPSBjKDAsMWU1KSkpCnBvbHlnb24gPC0gbWF0cml4KGMoMCwgMTBeNSwgMTBeNSwgMCwKICAgICAgICAgICAgICAgICAgICAxMF4yLjMsIDEwXjIuMywgMCwgMCksIG5jb2wgPSAyKQpjb2xuYW1lcyhwb2x5Z29uKSA8LSBjKCJCTDEuSCIsICJCTDMuSCIpCmxpdmUuZ2F0ZSA8LSBwb2x5Z29uR2F0ZShmaWx0ZXJJZCA9ICJsaXZlIiwgLmdhdGUgPSBwb2x5Z29uKQpmb3IoZGF0ZSBpbiBjKCIwMTExMjQiLCAiMDExNTI0IiwgIjAxMTYyNCIpKXsKICBwIDwtIGdnY3l0byhnc1twRGF0YShncykkRGF0ZSA9PSBkYXRlXSwgYWVzKHggPSBCTDEuSCwgeSA9IEJMMy5IKSwgc3Vic2V0ID0gInNpbmdsZXQiKSArIAogICAgZ2VvbV9oZXgoYmlucyA9IDEyOCkgKyAKICAgIGdlb21fZ2F0ZShsaXZlLmdhdGUpICsgCiAgICBnZW9tX3N0YXRzKGxvY2F0aW9uID0gImRhdGEiLCBhZGp1c3QgPSBjKDAuMSwgMC44KSwgZGlnaXRzID0gMikgKyAKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAoIkRhdGU6ICIsIGRhdGUpKSArCiAgICBmYWNldF9ncmlkKER5ZSB+IFRyZWF0bWVudCkgKwogICAgc2NhbGVfeF9sb2dpY2xlKCkgKyBzY2FsZV95X2xvZ2ljbGUoKSArIAogICAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMSksIGNvbG9yID0gInN0ZWVsYmx1ZSIsIGZhY2UgPSAyKSkKICBwcmludChwKQp9CmBgYAo+IE5vdGljZSB0aGUgaGlnaGVyIHBlcmNlbnRhZ2Ugb2YgZXZlbnRzIGluIHRoZSBsaXZlIGdhdGUgaW4gMTAgbU0gdnMgbW9jay4KCkFkZCB0aGlzIGdhdGUgdG8gdGhlIGdhdGluZ1NldAoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KZ3NfcG9wX2FkZChncywgbGl2ZS5nYXRlLCBwYXJlbnQgPSAic2luZ2xldCIsIG5hbWUgPSAibGl2ZSIpCnJlY29tcHV0ZShncykKYGBgCgojIyBJbnRlcm1lZGlhdGUgPSBoaWdoIEcvUgpUaGlzIGlzIHRoZSBpbnRlcm1lZGlhdGUgcG9wdWxhdGlvbiB3aXRoIGhpZ2ggUmVkIGFuZCBHcmVlbi4gV2UgaHlwb3RoZXNpemUgdGhhdCB0aGV5IHJlcHJlc2VudCB0aGUgCgo+IDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPkltcG9ydGFudDogSSBjaGFuZ2VkIHRoZSBib3R0b20gYm91bmRhcnkgZnJvbSAxMF4yLjIgdG8gMTBeMi4zLCBhbmQgdGhlIGxlZnQgYm91bmRhcnkgZnJvbSAxMF4zIHRvIDIqMTBeMzwvc3Bhbj4KCj4gKipNYWluIHRha2Vhd2F5KioKPgo+IDEuIERpZmZlcmVudCBmcm9tIHRoZSAlbGl2ZSBnYXRlLCB0aGUgaW50ZXJtZWRpYXRlIHBvcHVsYXRpb24gaXMgbW9zdCBvYnZpb3VzIGluIHRoZSAKPiAxMDAgbU0gdHJlYXRlZCBzYW1wbGUsIGFuZCBhYnNlbnQgaW4gYm90aCB0aGUgMTAgbU0gYW5kIDFNIHRyZWF0ZWQgb25lcy4gVGhpcyBzdWdnZXN0cwo+IHRoYXQgdGhpcyBwb3B1bGF0aW9uIGNvdWxkIGJlIHVzZWZ1bCBmb3IgZGlzdGluZ3Vpc2hpbmcgc3RyZXNzIGxldmVscyBiZWxvdyB0aGUgbGV0aGFsIGNvbmNlbnRyYXRpb24KPiBidXQgYWJvdmUgdGhlIHRvbGVyYW5jZSBsZXZlbHMgb2YgdGhlIHNwZWNpZXMgLSBpbiB0aGlzIGNhc2UsIDwgMU0gYW5kID4gMTAgbU0uCj4KPiAyLiBUaGUgbW9jayB0cmVhdGVkIHNhbXBsZSBzaG93ZWQgYW4gaW50ZXJtZWRpYXRlIHBvcHVsYXRpb24uIFdhcyB1bmV4cGVjdGVkLgoKYGBge3IsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTV9CiNzY1BhcnMgPC0gZ2djeXRvX3Bhcl9zZXQobGltaXRzID0gbGlzdCh4ID0gYygwLDFlNiksIHkgPSBjKDAsMWU2KSkpCiNleCA8LSBTdWJzZXQoZGF0LmYxZ1tbOV1dLCBzaW5nbGV0LmdhdGUpCnBvbHlnb24gPC0gbWF0cml4KGMoMTBeNSwgMioxMF4zLCAxMF41LAogICAgICAgICAgICAgICAgICAgIDEwXjIuMywgMTBeMi4zLCAxMF40KSwgbmNvbCA9IDIpCmNvbG5hbWVzKHBvbHlnb24pIDwtIGMoIkJMMS5IIiwgIkJMMy5IIikKaW50ZXIuZ2F0ZSA8LSBwb2x5Z29uR2F0ZShmaWx0ZXJJZCA9ICJpbnRlciIsIC5nYXRlID0gcG9seWdvbikKZm9yKGRhdGUgaW4gYygiMDExMTI0IiwgIjAxMTUyNCIsICIwMTE2MjQiKSl7CiAgcCA8LSBnZ2N5dG8oZ3NbcERhdGEoZ3MpJERhdGUgPT0gZGF0ZV0sIGFlcyh4ID0gQkwxLkgsIHkgPSBCTDMuSCksIHN1YnNldCA9ICJzaW5nbGV0IikgKyAKICAgIGdlb21faGV4KGJpbnMgPSAxMjgpICsgCiAgICBnZW9tX2dhdGUoaW50ZXIuZ2F0ZSkgKyAKICAgIGdlb21fc3RhdHMobG9jYXRpb24gPSAiZGF0YSIsICBhZGp1c3QgPSBjKDAuMSwgMC44KSwgZGlnaXRzID0gMikgKyAKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAoIkRhdGU6ICIsIGRhdGUpKSArCiAgICBmYWNldF9ncmlkKER5ZSB+IFRyZWF0bWVudCkgKwogICAgc2NhbGVfeF9sb2dpY2xlKCkgKyBzY2FsZV95X2xvZ2ljbGUoKSArIAogICAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMSksIGNvbG9yID0gInN0ZWVsYmx1ZSIsIGZhY2UgPSAyKSkKICBwcmludChwKQp9CmBgYAoKCkFkZCB0aGlzIGdhdGUgdG8gdGhlIGdhdGluZ1NldAoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KZ3NfcG9wX2FkZChncywgaW50ZXIuZ2F0ZSwgcGFyZW50ID0gInNpbmdsZXQiLCBuYW1lID0gImludGVybWVkaWF0ZSIpCnJlY29tcHV0ZShncykKYGBgCgojIyBEZWFkID0gSGlnaCByZWQgbG93IGdyZWVuCldlIGRvbid0IG5lZWQgdG8gc2V0IHRoZSBkZWFkIGdhdGUgYmVjYXVzZSBhbGwgd2Ugd2FudCBpcyB0aGUgcGVyY2VudCBvZiBldmVudHMgaW4gdGhhdCBnYXRlLCBub3QgdGhlIE1GSSBmb3IgZWl0aGVyIGNoYW5uZWwuIFRoZSBwZXJjZW50YWdlIGNhbiBiZSBjYWxjdWxhdGVkIGJ5IHN1YnRyYWN0aW5nIHRoZSBwZXJjZW50IG9mIGV2ZW50cyBpbiB0aGUgcHJldmlvdXMgdHdvIGdhdGVzIGZyb20gMTAwJS4KCgojIEV4cG9ydGVkIGdhdGUgc3RhdHMKCiUgb2YgZXZlbnRzIGluIGVhY2ggb2YgdGhlIHRocmVlIGdhdGVzCmBgYHtyfQpnYXRlZF9zdGF0cyA8LSBnc19wb3BfZ2V0X3N0YXRzKGdzLCB0eXBlID0gImNvdW50IikgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBtdXRhdGUocG9wID0gZ3N1YigiLiovIiwgIiIsIHBvcCksIHBvcCA9IGdzdWIoIi1vdXRsaWVyIiwgImNlbGxzIiwgcG9wKSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBwb3AsIG5hbWVzX3ByZWZpeCA9ICJuXyIsIHZhbHVlc19mcm9tID0gY291bnQpICU+JSAKICBtdXRhdGUoCiAgICAjcF9zaW5nbGV0ID0gbl9zaW5nbGV0IC8gbl9jZWxscywKICAgIHBfbGl2ZSA9IG5fbGl2ZSAvIG5fc2luZ2xldCwKICAgIHBfaW50ZXJtZWRpYXRlID0gbl9pbnRlcm1lZGlhdGUgLyBuX3NpbmdsZXQsCiAgICBwX2RlYWQgPSAxIC0gcF9saXZlIC0gcF9pbnRlcm1lZGlhdGUKICApCiN3cml0ZV90c3YoZ2F0ZWRfZGF0YSwgZmlsZSA9ICIuLi9JbnB1dC8yMDI0MDEyNC1maWctMi1EeWUtT3JkZXItZ2F0ZWQtaHQudHN2IikKI3ByaW50KGdhdGVkX2RhdGEpCmBgYAoKTUZJIGluIHRoZSBsaXZlIGFuZCBpbnRlcm1lZGlhdGUgZ2F0ZXMKYGBge3J9CnBvcE1GSSA8LSBnc19wb3BfZ2V0X3N0YXRzKGdzLCBub2RlcyA9IGMoImxpdmUiLCAiaW50ZXJtZWRpYXRlIiksIHR5cGUgPSBwb3AuTUZJKSAlPiUgCiAgYXNfdGliYmxlKCkgJT4lIAogIHNlbGVjdChzYW1wbGUsIHBvcCwgRlNDID0gYEZTQy1IYCwgQkwxID0gYEZ1bmdhbGlnaHQgR3JlZW4tSGApICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcG9wLCB2YWx1ZXNfZnJvbSA9IGMoRlNDLCBCTDEpKQpgYGAKCkNvbWJpbmUgdGhlIGRhdGEgYW5kIG1ldGEgZGF0YQpgYGB7cn0KZmluYWwgPC0gc2VsZWN0KHBEYXRhKGRhdCksIHNhbXBsZSA9IG5hbWUsIGV2ZXJ5dGhpbmcoKSkgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZ2F0ZWRfc3RhdHMsIC1zdGFydHNfd2l0aCgibl8iKSksICBieSA9ICJzYW1wbGUiKSAlPiUgCiAgbGVmdF9qb2luKHBvcE1GSSwgYnkgPSAic2FtcGxlIikKCndyaXRlX3RzdihmaW5hbCwgZmlsZSA9ICIuLi9kYXRhLzEyLjAxLWdhdGVkLW91dHB1dC0yMDI0MDExNy50c3YiKQpwcmludChmaW5hbCAlPiUgc2VsZWN0KC1zYW1wbGUpKQpgYGAKCgojIEV4cGxvcmF0b3J5IGNvbXBhcmlzb24gYmV0d2VlbiBQSSBhbG9uZSBhbmQgY29tYm8KClBJIGFsb25lCmBgYHtyfQpwMSA8LSBmaW5hbCAlPiUgCiAgZHBseXI6OmZpbHRlcihEeWUgPT0gIlBJIGFsb25lIikgJT4lIAogIGdncGxvdChhZXMoeCA9IFRyZWF0bWVudCwgeSA9IDEtcF9saXZlKSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAyLCBzaGFwZSA9IDIxLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcigwLjA1KSkgKyAKICAjc3RhdF9zdW1tYXJ5KGZ1biA9ICJtZWFuIiwgZ2VvbSA9ICJwb2ludCIsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHggPSBicXVvdGUoSFsyXSpPWzJdfihtTSkpLCB5ID0gIjEgLSAlTGl2ZSIpICsKICB0aGVtZV9jb3dwbG90KCkKCmluc2V0IDwtIGZpbmFsICU+JSAKICBkcGx5cjo6ZmlsdGVyKER5ZSA9PSAiUEkgYWxvbmUiLCBUcmVhdG1lbnQgIT0gIjEwMDAiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVHJlYXRtZW50LCB5ID0gMS1wX2xpdmUpKSArIAogIGdlb21fYmFyKHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgZmlsbCA9ICJza3libHVlMiIsIGFscGhhID0gMC43KSArCiAgZ2VvbV9wb2ludChzaXplID0gMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoMC4wNSkpICsgCiAgI3N0YXRfc3VtbWFyeShmdW4gPSAibWVhbiIsIGdlb20gPSAicG9pbnQiLCBzaXplID0gMTUsIHNoYXBlID0gIi0iLCBjb2xvciA9ICJyZWQiKSArCiAgbGFicyh4ID0gYnF1b3RlKEhbMl0qT1syXX4obU0pKSwgeSA9ICIxIC0gJUxpdmUiKSArCiAgdGhlbWVfbWluaW1hbF9oZ3JpZCgxMSkKCmdnZHJhdyhwMSArIGxhYnMoc3VidGl0bGUgPSAiUEkgYWxvbmUsIGRvZXNuJ3QgZGlzZ3Vpc2ggMTAgdnMgMTAwIG1NIikpICsgCiAgZHJhd19wbG90KGluc2V0LCAuMiwgLjgsIC40LCAuNSwgdmp1c3QgPSAxKSArCiAgZHJhd19wbG90X2xhYmVsKGMoIkEiLCAiQiIpLCBjKDAsIDAuMTgpLCBjKDEsIDAuODUpKQoKZ2dzYXZlKCIuLi9vdXRwdXQvMTIuMDEtUEktYWxvbmUtb25lLW1pbnVzLXBlcmMtbGl2ZS5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDQpCmBgYAoKUEkrU1lUTzkKYGBge3J9CnAyIDwtIGZpbmFsICU+JSAKICBkcGx5cjo6ZmlsdGVyKER5ZSAhPSAiUEkgYWxvbmUiLCBUcmVhdG1lbnQgIT0gIjAiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVHJlYXRtZW50LCB5ID0gMS1wX2xpdmUpKSArIAogIGdlb21fYmFyKHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgZmlsbCA9ICJncmF5IiwgYWxwaGEgPSAwLjcpICsKICBnZW9tX3BvaW50KHNpemUgPSAyLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcigwLjA1KSkgKyAKICAjc3RhdF9zdW1tYXJ5KGZ1biA9ICJtZWFuIiwgZ2VvbSA9ICJwb2ludCIsIHNoYXBlID0gIi0iLCAKICAjICAgICAgICAgICAgIHNpemUgPSAxNSwgY29sb3IgPSAicmVkIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gMC4yKSkgKwogIGxhYnMoeCA9IGJxdW90ZShIWzJdKk9bMl1+KG1NKSksIHkgPSAiMSAtICVMaXZlIikgKwogIGZhY2V0X3dyYXAofkR5ZSkgKwogIHRoZW1lX2Nvd3Bsb3QoKSArCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMiksIGZhY2UgPSAyKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQoKcDIKZ2dzYXZlKCIuLi9vdXRwdXQvMTIuMDEtUEkrU1lUTzktb25lLW1pbnVzLXBsaXZlLnBuZyIpCmBgYAo+IFBsb3QgJSBEZWFkIGFuZCBDb21wYXJlCgpgYGB7cn0KcGYxZyA8LSBnYXRlZF9kYXRhICU+JQogIGRwbHlyOjpmaWx0ZXIoIShEeWUgJWluJSBjKCJQSSIpKSkgJT4lIAogIGRwbHlyOjpmaWx0ZXIoIShUcmVhdG1lbnQgJWluJSBjKCIxMDAwIG1NIikpKSAgJT4lCiAgI211dGF0ZShEaWx1dGlvbiA9IGZhY3RvcihEaWx1dGlvbiwgbGV2ZWxzID0gYygiMjUwIHgiLCAiNTAwIHgiLCAiMTAwMCB4IiwgIjIwMDAgeCIpKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gVHJlYXRtZW50LCB5ID0gcGVyY2VudF9MaXZlKSkgKwogIGZhY2V0X3dyYXAofiBEeWUsIHNjYWxlID0gImZyZWVfeSIpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZ2VvbV9wb2ludChzdHJva2UgPSAxLCBzaXplID0gMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoMC4yKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICB0aGVtZV9taW5pbWFsKCkKcGYxZyArCiAgbGFicyh4ID0gIkh5ZHJvZ2VuIFBlcm94aWRlIFRyZWF0bWVudCBDb25jZW50cmF0aW9uIiwgeSA9ICJHYXRlZCBMaXZlIENlbGxzIikgKwogIHBhbmVsX2JvcmRlcihjb2xvciA9ICJibGFjayIsIHNpemUgPSAxLjUpICsKICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gImJsYWNrIiksICAjIEFkanVzdCBzaXplIGFuZCBmYWNlIChib2xkKQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKQogICAgICAgICkrIAogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSkgCiNnZ3NhdmUoIi4uL291dHB1dC8yMDI0MDEwNC1QSS1EaWx1dGlvbnMtR2F0ZWRfUlAtUGxvdC5wbmciLCB3aWR0aCA9IDcsIGhlaWdodCA9IDUpCmBgYA==