Homologs identification
Homologs of the PF11765 domain containing proteins were identified in the five strains of C. auris used in Muñoz et al. 2018 Nat. Genet. Homologs from C. pseudohaemulonis and C. haemuloni were added to help provide the evolutionary context, e.g. timing of gene duplication and sequence evolution both within and between closely related species. Finally, two homologs from the outrgroup species D. hansenii were added to root the gene tree. A third D. hansenii sequencing with the PF11765 domain was not included as it belong to the Clavispora/Candida duplicate 2 branch, which didn’t include any C. auris sequences.
Update 2021-05-21 [HB] Clade I strain 6684 is removed from this analysis, leaving four strains repesenting one of the four clades
As shown in Muñoz et al. 2021 Genetics, C. auris as a species has a total of eight members in this family. The number of members present in each strain varies. In particular, Clade II strains, represented by B11220 in our dataset, has only three. Below we will show the domain architecture for the eight members from the clade I strain B8441. The data for this plot is actually generated in the latter part of this R markdown file
# read in data
len <- read_tsv("input/B8441-homologs-length-name.tsv", col_types = cols())
B8441 <- read_tsv("input/B8441-homologs-feature-table.tsv", col_types = cols()) %>%
mutate(type = ifelse(grepl("TR-",type), "Tandem Repeat", type), type = ordered(type, levels = unique(type))) %>%
left_join(select(len, shortName = name, gID, pID), by = c("name" = "pID")) %>%
select(shortName, gID, pID = name, type, start, end)
B8441.tango <- read_tsv("input/B8441-homologs-tango.tsv", col_types = cols()) %>%
left_join(select(len, shortName = name, gID, pID), by = c("name" = "pID"))
# sort the sequences by protein length
seq.order <- len$gID
B8441$gID <- ordered(B8441$gID, levels = seq.order)
B8441.tango$gID <- ordered(B8441.tango$gID, levels = seq.order)
# plot
colors <- c("grey", "#1f78b4", "#e31a1c", "#6a3d9a", "orange4")
p1 <- ggplot(B8441, aes(x = gID, y = start)) + geom_segment(aes(xend = gID, yend = end), color = "black", size = 7)
p2 <- geom_segment(aes(x = gID, y = start + 1, xend = gID, yend = end - 1, color = type), size = 6.5)
p3 <- geom_segment(data = B8441.tango, aes(xend = gID, y = ifelse(start-3 >= 0, start-3, 0), yend = end + 3, alpha = median),
position = position_nudge(x = -0.4, y = 0), color = "darkred", size = 2)
p4 <- p1 + p2 + p3 + coord_flip() + theme_cowplot() +
scale_color_manual(values = colors) +
scale_x_discrete(labels = paste0(len$gID, " (", len$name, ")")) +
scale_alpha(guide = "none") +
labs(y = "Position in sequence", x = NULL, color = "FEATURES") +
theme(legend.position = c(0.7,0.4),
legend.box.margin = margin(6,6,6,6),
legend.box.background = element_rect(size = 0.5, linetype = "solid", color = 1))
p4

ggsave("output/figure/20210526-B8441-domain-tandem-repeats.png", width = 8, height = 3.5)
Fig. 1 Domain schematic of the eight homologs in the Hyr/Iff-like (Hil) family in C. auris strain B8441. The gene name is shown to the left and sorted based on the length of the predicted proteins. Various features were shown as colored blocks, including the Hyphal_reg_CWP (PF11765) domain, Signal Peptide as predicted by SignalP 5.0 server, GPI-anchor predicted by PredGPI server and tandem repeats predicted by XSTREAM (see Materials and Methods). The short bars behind each sequence’s schematic represents TANGO predicted β-aggregation motifs, whose predicted strength (score) is proportional to the transparency of the bar.
Evolution (duplications and losses)
Gene tree
The gene tree inferred based on the PF11765 domain in each sequence is presented below:
Fig. 2 RAxML inferred gene tree for Hyr/Iff-Like (HIL) family members in C. auris, two MDR clade species C. pseudohaemulonis and C. haemuloni, as well as an outgroup D. hansenii. The branch thickness is shown proportional to the value of the rapid bootstrapping value. The tree is manually rooted on the two D. hansenii sequences. The root choice is based on the gene tree including homologs from across the Ascomycetes. The short terminal branch lengths among the C. auris strains indicate that there had been little divergence in the PF11765 domain in these sequences. Lastly, the colors of the leaf node names for the C. auris strains are based on Muñoz et al. 2018 Nat. Genet.
Reconciliation and rearrangement
To infer the timing of gene duplication and loss events, the gene tree is reconciled with the species tree in Notung 2.9. Rearrangement of the reconciled gene tree was performed in the same software, allowing for swapping of branches with rapid bootstrapping values lower than 90%. The rearranged tree has a total of 15 duplication and 13 losses. Note that the clade I strain 6684 appeared to have experienced several losses, but this is very likely due to the relatively poor assembly status of the strain, not real evolutionary losses.
# read in reconciled and rearranged gene tree
gene.tree <- read.nhx("output/gene-tree/notung/RAxML_bipartitions.clustalo-cauris-four-strains_rearranged90.nhx") %>% as_tibble() %>% # convert to a tibble
mutate(strains = ordered(S, levels = c("Cauris.B8441", "Cauris.B11220", "Cauris.B11221", "Cauris.B11243",
"Cpseudohaemulonis", "Chaemuloni", "Dhansenii"),
labels = c("Clade I", "Clade II", "Clade III", "Clade IV",
"C. pseudohaemulonis", "C. haemuloni", "D. hansenii")))
# set up species/strains tip label colors
#gene.tree <- gene.tree %>%
# groupOTU()
gene.tree %>%
as.treedata() %>%
ggtree() + geom_tiplab(aes(colour = strains), fontface = 3, size = 3) + xlim(0,20) +
scale_color_manual(name = "LEGEND", values = c("#345714", "#952395", "#0030ff", "#ff2900",
"#008ab8", "#008ab8", "#000000")) +
geom_hilight(node = 98, fill = "gray20", alpha = 0.2, color = "white") + # Hil-1
geom_hilight(node = 94, fill = "gray20", alpha = 0.2, color = "white") + # Hil-2
geom_hilight(node = 78, fill = "gray20", alpha = 0.2, color = "white") + # Hil-3
geom_hilight(node = 102, fill = "gray20", alpha = 0.2, color = "white") + # Hil-4
geom_hilight(node = 57, fill = "gray20", alpha = 0.2, color = "white") + # Hil-5
geom_hilight(node = 68, fill = "gray20", alpha = 0.2, color = "white") + # Hil-6
geom_hilight(node = 82, fill = "gray20", alpha = 0.2, color = "white") + # Hil-7
geom_hilight(node = 73, fill = "gray20", alpha = 0.2, color = "white") + # Hil-8
geom_cladelabel(node = 98, label = "Hil-1", offset = 7, color = "red", fontface = 2) + # Hil-1
geom_cladelabel(node = 94, label = "Hil-2", offset = 7, color = "red", fontface = 2) + # Hil-1
geom_cladelabel(node = 78, label = "Hil-3", offset = 7, color = "red", fontface = 2) + # Hil-1
geom_cladelabel(node = 102, label = "Hil-4", offset = 7, color = "red", fontface = 2) + # Hil-1
geom_cladelabel(node = 57, label = "Hil-5", offset = 7, color = "red", fontface = 2) + # Hil-1
geom_cladelabel(node = 68, label = "Hil-6", offset = 7, color = "red", fontface = 2) + # Hil-1
geom_cladelabel(node = 82, label = "Hil-7", offset = 7, color = "red", fontface = 2) + # Hil-1
geom_cladelabel(node = 73, label = "Hil-8", offset = 7, color = "red", fontface = 2) + # Hil-1
theme(legend.position = "none")
'edge.length' contains NA values...
## setting 'edge.length' to NULL automatically when plotting the tree...Ignoring unknown parameters: fontfaceIgnoring unknown parameters: fontfaceIgnoring unknown parameters: fontfaceIgnoring unknown parameters: fontfaceIgnoring unknown parameters: fontfaceIgnoring unknown parameters: fontfaceIgnoring unknown parameters: fontfaceIgnoring unknown parameters: fontface

ggsave("output/figure/20210601-reconciled-NTD-tree-annotated.png", width = 8, height = 8)
Fig. 3 The same tree in Fig. 3 after reconciliation and rearrangement using Notung v2.9. The species/strains tree and the gene tree as shown in Fig. 3 were used as input for reconciliation in Notung v2.9. Rooting and reconciliation were performed in a single step, after which the tree is rearranged by allowing branches with < 90% rapid bootstrap support to be swapped in order to reduce the total number of events (duplications and losses), resulting in the rearranged tree. Because of the rearrangement, branch lengths do not correspond to the estimated substitution number. Red nodes indicate inferred duplication events. Losses were not shown explicitly. Sequence names were colored in the same way as in Fig. 2
We can summarize the inferred gains and losses on the species/strains tree.
- Read in the tree in Newick format
- Read in the parsable statistic (copied from Notung “events summary” output)
- Plot using ggtree
sps.tree <- read.tree("input/cauris-four-strains-outgroup-tree.nwk")
notung.stat <- read_tsv("output/gene-tree/notung/RAxML_bipartitions.clustalo-cauris-four-strains_rearranged90_stats.txt", col_types = 'cii')
sps.tree.tb <- as_tibble(sps.tree) %>%
full_join(notung.stat, by = "label")
sps.tree <- as.treedata(sps.tree.tb)
sps.tree %>%
ggtree() +
geom_tiplab(as_ylab = TRUE, size = 11, face = 4) +
geom_text(aes(x = branch, label = duplications), vjust = -.4, size = 3, color = "red", face = 2) +
geom_text(aes(x = branch, label = losses), vjust = 1.4, size = 3, color = "grey20", face = 2)

ggsave("output/figure/20210601-gains-losses-reconciliation.png", width = 3, height = 3)
Fig. 4 Summary of inferred duplication and loss events in C. auris strains and selected outgroups. The tree topology is based on Muñoz et al. 2018 PMID: 30559369. The number of duplications (red) and losses (black) were inferred using Notung 2.9 and labeled on the top and bottom of the branches respectively.
Note that all seven duplications that led to the eight members of the Hil family in C. auris occurred in the ancestor of the MDR clade, which includes C. pseudohamulonis, C. haemuloni and C. duobushaemulonis, the last of which was not included in this tree. Additional duplications were inferred in the MDR clade but not on the C. auris branches. In terms of losses, the most notable branch is the C. auris B11220 strain, which belongs to clade II, that has lost five of the eight members. This is consistent with previous studies, e.g. Muñoz et al. 2021 Genetics. The single loss event in the C. auris strain B11221 was inconsistent with the study just mentioned. Further investigations suggested that this was most likely due to incomplete assembly of its genome.
Evolution of sequence features
Adhesin prediction
FungalRV threshold: 0.51; FaaPred using ACHM model with the recommended -0.8 threshold.
frv.th = 0.511 # recommended FungalRV score threshold
frv <- read_tsv("output/seq-feature/cauris-renamed-fungalrv.txt", skip = 3, col_names = c("name","frv.score"), col_types = "cd") %>%
mutate(name = str_sub(name, 2), frv.pred = frv.score > frv.th)
faa <- read_tsv("output/seq-feature/cauris-renamed-faapred.txt", col_names = c("name","faa.score","faa.pred"), col_types = "cdc") %>%
mutate(faa.pred = ifelse(faa.pred == "Adhesin", TRUE, FALSE))
if("frv.score" %in% names(seqInfo))
seqInfo <- select(seqInfo, -frv.score, -frv.pred, -faa.score, -faa.pred)
seqInfo <- seqInfo %>% left_join(frv) %>% left_join(faa)
Joining, by = "name"
Joining, by = "name"
seqInfo %>%
group_by(species_id, strain) %>%
summarize(n = n(), fungalRV = sum(frv.score > 0.511), faapred = sum(faa.pred, na.rm = T),
both = sum(frv.score > 0.511 & faa.pred))
`summarise()` has grouped output by 'species_id'. You can override using the `.groups` argument.
SignalP and GPI prediction
GPI-anchored proteins are characterized by an N-terminal signal peptide, which would direct the protein to the secretary pathway, and a C-terminal GPI-anchor peptide, which would be cleaved and replaced by the GPI-anchor, allowing the protein to be tethered to the cell wall. For signal peptide, I used SignalP server. Its latest version is 5.0. But I also ran the sequences through their 4.1 version, with two settings. The results of the latter two are almost identical, except for one sequence “XP_024711350.1”, which is only included in the sensitive version, and has a probability lower than 0.5.
# Signal peptide
gff.names <- c("id", "source", "name", "start", "end", "prob", "na1", "na2", "na3")
signalp5 <- read_tsv("output/seq-feature/cauris-renamed-signalp5.gff3", comment = "#", col_names = gff.names, col_types = "ccciidccc")
if("signalp" %in% names(seqInfo))
seqInfo <- select(seqInfo, -signalp)
seqInfo <- left_join(seqInfo, select(signalp5, name = id, prob), by = c("name" = "name")) %>%
mutate(signalp = !is.na(prob)) %>% select(-prob)
tmp <- read_delim("output/seq-feature/cauris-renamed-predgpi.txt", delim = "|", col_names = c("name","fp","omega"), col_types = cols())
pred.gpi <- tmp %>%
mutate(name = str_sub(name, 2, -2), # remove > and the trailing space
fp = as.numeric(str_sub(fp, 9, -2)), # extract the numeric part
is.gpi = fp <= 0.01, # based on the cutoff of the PredGPI server (prob < 99% -> not GPI-anchored)
omega = str_sub(omega, 8),
cleaveRes = str_sub(omega, 1, 1),
cleavePos = as.integer(str_sub(omega, 3)),
) %>%
left_join(select(seqInfo, name, length), by = c("name" = "name"))
# remove the column if it already exists
if("pred.gpi" %in% names(seqInfo))
seqInfo <- select(seqInfo, -pred.gpi)
seqInfo <- left_join(seqInfo, select(pred.gpi, name, pred.gpi = is.gpi), by = c("name"="name"))
seqInfo %>%
group_by(species_id, strain) %>%
summarize(Total = n(), SignalP = sum(signalp), GPI_Pred = sum(pred.gpi), Both = sum(signalp & pred.gpi), .groups = "drop")
write_tsv(seqInfo, "output/seq-feature/R-seqinfo-table.tsv", col_names = TRUE)
Tandem repeat structures
The non-NTD portion of the proteins evolve rapidly and many of them contain tandem repeats. Therefore, characterizing and visualizing the type, number and spatial distribution of the tandem repeats serve to highlight the differences in the non-NTD part of the proteins in this family.
To identify and group tandem repeats, I used XSTREAM with the following parameters java -Xmx1000m -Xms1000m -jar ~/sw/XSTREAM/xstream.jar $in -i.7 -I.7 -g3 -e2 -L15 -z -G -O -Asub.txt
. The parameters were chosen to identify degenerate tandem repeats that occur at least two times and must be a minimum length of 5 a.a. or longer and the minimum length of a tandem repeat domain (=period x copy #) must be greater than 15 a.a. Please see script/xstream.sh
for explanation of the parameters.
tandem <- read_tsv("output/tandem-repeats/XSTREAM_cauris_outgr_sub_i0.7_g3_m5_L15_chart.tsv",
col_types = "ciiifidcccd", comment = "#") %>%
rename(name = identifier)
# now let's create a tibble for plotting, which would contain each instance of the tandem repeat on a separate row
tandem.div <- tandem %>%
rowwise(name) %>%
summarize(div = list(c(seq(from = start, to = end, by = period), end)), .groups = "drop") %>%
unnest(div)
# summarize stats of tandem repeats
repeats <- tandem %>%
group_by(type, period) %>%
summarize(n = n(), copyMean = mean(copyN), .groups = "drop") %>%
mutate(length = period * copyMean)
ggplot(repeats, aes(x = period, y = copyMean)) + geom_hex(binwidth = c(3,2)) +
scale_fill_gradient(low = "grey10", high = "yellow2", breaks = seq(1,17,2)) +
scale_x_continuous(breaks = seq(0,100,6)) +
scale_y_continuous(breaks = seq(0,100,4)) +
ylab("Mean copy number per sequence") + theme_bw()

Fig. 4 Tandem Repeats (TRs) identified among the protein sequences. A total of 117 types of TRs were identified by the XSTREAM program as described above. The period (unit length) of the TRs are plotted against the mean copy number per sequence for the same TRs. Data are binned by 3 for the period and 2 for the mean copy number, and the number of TRs in each bin is shown in dark-gray to yellow gradient. Note that many TRs are both short (<= 15 a.a.) and have few copies per sequence (< 4). There are, however, a number of TRs that are long (> 30 a.a.) and repeat for more than 10 times per sequence. Those are potentially of more interest.
repeats %>%
ggplot(aes(x = length)) + stat_ecdf(geom = "step") +
scale_x_continuous(breaks = c(10,20,40,80,160,320,640,1280), trans = "log2") +
ylab("Probability") + xlab("length (= period * mean copies)") +
theme_cowplot() + background_grid()

Fig. 5 Tandem Repeat domain length cumulative distribution. Empirical cumulative distribution is calculated for the length of each tandem repeat domain, defined as the period (unit length) of a domain multiplied by the mean copy number in all sequences that contain this domain. The x-axis is log2 transformed. Note that ~50% of the domains have a length < 40 residues and ~80% < 160 residues.
# this is for the purpose of drawing just XP_028889033
tandem %>% filter(grepl("XP_028889033", name)) %>% write_tsv(file = "../01-XP_028889033_drawing/input/XP_028889033_tandem_sub.tsv")
tandem.div %>% filter(grepl("XP_028889033", name)) %>%
write_tsv(file = "../01-XP_028889033_drawing/input/XP_028889033_tandem_sub_div.tsv")
# also export the subset belonging to the B8441 homologs
tandem.div %>% filter(grepl("PIS", name)) %>%
write_tsv(file = "output/seq-feature/B8441-homologs-tandem_sub_div.tsv")
Domain architecture
The goal is to produce a cartoon-like plot for each homolog outlining their main features, such as the locations of the pfam domains (mainly the Hyp_reg_CWP), locations of the signal peptide and GPI-anchor, types and distribution of tandem repeats. Note that all these features can be represented as a range with associated metadata. So the first step is to collect the coordinates of the features
organize the non-TR features
# GPI-anchor
# use pred.gpi
# Pfam domains
pfam <- read_tsv("output/seq-feature/cauris-renamed-hmmer-scan.txt", col_types = "ciiiicciiidddiic")
# save feature file for Jalview examination
# pfam %>% filter(grepl("XP_028889033",seq_id)) %>% select(hmm_name, seq_id, envelope_start, envelope_end) %>% mutate(featuretype = "domain") %>% write_tsv("XP_028889033_features.jalview")
# I manually edited the feature file, so I commented out the line above to avoid accidentally
# overwriting my own edits
# feature set
# structure: id feature start end
feature <- bind_rows(
seqInfo %>% mutate(type = "entire protein", start = 1) %>% select(name, type, start, end = length),
pfam %>% select(name = seq_id, type = hmm_name, start = envelope_start, end = envelope_end) %>%
filter(type == "Hyphal_reg_CWP"),
# extend the signal peptide segment by 10 amino acids to make it more visible
signalp5 %>% mutate(type = "SignalP", end = end + 10) %>% select(name = id, type, start = start, end),
# extend the GPI-anchor C-terminus segment by 20 amino acids to make it more visible
pred.gpi %>% filter(is.gpi) %>% mutate(type = "GPI-anchor", start = cleavePos-10) %>%
select(name, type, start, end = length)
) %>% filter(!grepl("KND", name)) %>% # remove strain 6684
mutate(tip = ifelse(type == "entire protein", as.character(name), as.character(type)))
#feature$type = ordered(feature$type, levels = c("entire protein", "Hyphal_reg_CWP", "SignalP", "GPI-anchor"))
feature.colors <- c("grey", "#1f78b4","#e31a1c", "#6a3d9a")
organize the tandem repeats features
tr <- tandem %>%
left_join(select(repeats, type, copyMean), by = c("type" = "type")) %>%
mutate(type = paste("TR", type, sep = "-"),
tip = paste0(consensus_nogap,
"\ntype: ", type,
"\nperiod: ", period,
"\ncopyN: ", copyMean)) %>%
select(name, type, start, end, tip)
require(RColorBrewer)
tr.col <- character(nrow(repeats)) # create a color vector
short.rp <- which(repeats$length < 40) # identify the short repeats indices
long.rp <- setdiff(1:nrow(repeats), short.rp) # the long repeats indices
set.seed(123) # for reproducibly shuffling the order before assigning the colors
short.rp <- sample(short.rp)
tr.col[short.rp] <- colorRampPalette(
brewer.pal(12, "Paired")[seq(3,11,by=2)])(length(short.rp)
) # assign the short repeats a lower contrast color
set.seed(231) # for reproducibly shuffling the order before assigning the colors
long.rp <- sample(long.rp)
tr.col[long.rp] <- colorRampPalette(
brewer.pal(12, "Paired")[seq(4,12,by=2)])(length(long.rp)
) # assign the long repeats a higher contrast color
repeats$color <- tr.col
Combine domains, SP and GPI-anchor with TR features.
# combine sequence features with tandem repeats
tr.feature <- bind_rows(feature, tr) %>%
mutate(type = ordered(type, levels = unique(type)))
comb.col <- c(feature.colors, tr.col)
# Extract the subset for XP_028889033 for plotting
tr.feature %>% select(-tip) %>%
filter(grepl("XP_028889033", name)) %>%
write_tsv(file = "../01-XP_028889033_drawing/input/XP_028889033-domain-features.txt")
# Extract the subset from _C. auris_ B8441 for the schematic plot in the beginning.
B8441 <- tr.feature %>%
select(-tip) %>%
filter(grepl("PIS", name))
write_tsv(B8441, file = "output/seq-feature/B8441-homologs-feature-table.tsv", col_names = TRUE)
reorder the sequences by their positions in the gene tree
# in order to plot properties of the sequences in an order that is consistent with the sequences' position in the gene tree
genetreeOrder <- scan("input/cauris-four-strains-reorder-by-gene-tree.txt", what = "character")
Read 52 items
genetreeColor <- tibble(name = genetreeOrder) %>%
mutate(color = case_when(
grepl("haemuloni", name) ~ "#2596be70",
grepl("B8441", name) ~ "#0e8c07",
grepl("B11220", name) ~ "#780a76",
grepl("B11221", name) ~ "#0409fb",
grepl("B11243", name) ~ "#ff4c00",
TRUE ~ "#000000"
))
#feature$name <- ordered(feature$name, levels = rev(genetreeOrder))
tr.feature$name <- ordered(tr.feature$name, levels = rev(genetreeOrder))
write_tsv(tr.feature, file = "output/seq-feature/R-feature-table.tsv", col_names = TRUE)
# plot
p1 <- ggplot(tr.feature, aes(x = name, y = start, xend = name, yend = end)) +
geom_segment(aes(color = type, text = tip), size = 2.5)
p2 <- geom_segment(data = tandem.div, aes(x = name, xend = name, y = div, yend = div + 1.5), size = 2.5, color = "white")
p3 <- p1 + coord_flip() + theme_classic() +
scale_color_manual(values = comb.col) +
theme(axis.text.y = element_text(size = 7, colour = rev(genetreeColor$color)),
axis.line.y = element_blank(), axis.ticks.y = element_blank(),
axis.line.x = element_blank(), axis.ticks.x = element_blank(),
legend.position = "none",
panel.background = element_rect(fill = alpha("lightblue",0.5))) +
ylim(-2, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "FEATURES") +
ggtitle("Protein sequence features")
p3 + p2

ggsave("output/figure/20210524-domain-tandem-repeats.png", width = 7, height = 6)
DT::datatable(
tandem %>%
rename(seqL = seqLength, err = consensus_error, seq = consensus_nogap) %>%
select(-seqAlign, -type, -consensus_gap, -seq, seq) %>%
arrange(desc(name)),
fillContainer = FALSE, options = list(pageLength = 10)
)
# plot
require(plotly)
ggplotly(p3, tooltip = "text", width = 800, height = 700)
Note Blue boxes indicate the PF11765 domains while all other non-grey boxes indicate XSTREAM-determined tandem repeat domains. Colors are used to group highly similar tandem repeats. The black thin lines demarcate adjacent tandem repeat units. The table below shows the copy number, period and consensus sequence for each tandem domain organized by the host sequences.
TANGO prediction of \(\beta\)-aggregation prone sequences
The amyloid-like \(\beta\)-aggregation prone sequences have the ability to mediate self-aggregation, which boosts the local concentration of the adhesin molecules on the cell-surface. Similar to the S/T frequency above, we would like to use the output from the prediction algorithm, TANGO, to visulize the distribution of such sequence motifs along the length of the XP_028889033 homolog sequences.
Parse tango output
extract_tango <- function(tango_output, agg_threshold = 5, required_in_serial = 5) {
require(tidyverse)
tmp <- read_tsv(file = tango_output, col_types = "icddddd") %>%
# a boolean vector for residues above threshold
mutate(pass = Aggregation > agg_threshold)
pass.rle <- rle(tmp$pass) # this creates a run length encoding that will be useful for identifying the sub-sequences in a run longer than certain length
# --- Explanation ---
# this rle object is at the core of this function
# an example of the rle looks like
# lengths: int[1:10] 5 19 20 8 1 5 19 6 181 18
# values: logi[1:10] F T F T F T F T F T
# note that by definition the values will always be T/F interdigitated
# our goal is to identify the sub-sequences that is defined as a stretch of
# n consecutive positions with a score greater than the cutoff and record the
# sub-sequence, its length, start and end position, 90% quantile of the score
# --- End of explanation ---
# 1. assigns a unique id for each run of events
tmp$group <- rep(1:length(pass.rle$lengths), times = pass.rle$lengths)
# 2. extract the subsequences
agg.seq <- tmp %>%
filter(pass) %>% # drop residues not predicted to have aggregation potential
group_by(group) %>% # cluster by the runs
summarize(seq = paste0(aa, collapse = ""),
start = min(res), end = max(res), length = n(),
median = median(Aggregation),
q90 = quantile(Aggregation, probs = 0.9),
ivt = sum(aa %in% c("I","V","T")) / length(aa),
.groups = "drop") %>%
mutate(interval = start - lag(end) - 1) %>%
filter(length >= required_in_serial) %>%
select(-group)
return(agg.seq)
}
tango.output.files <- list.files(path = "output/tango", pattern = ".txt|.txt.gz", full.names = T)
# the read_csv() function used in the custom function can automatically decompress gzipped files
tango.res <- lapply(tango.output.files, extract_tango)
names(tango.res) <- gsub(".txt|.txt.gz", "", basename(tango.output.files))
# to add species information
tango.res.df <- bind_rows(tango.res, .id = "id") %>%
mutate(id = gsub("_B[0-9]+$", "", id))
# save the tango output
write_tsv(tango.res.df, "output/tango/tango_summary_table.tsv.gz")
# mutate(species = str_split(id, "_(?!.*_)", simplify = TRUE)[,2])
# extract the species names
# credit: https://stackoverflow.com/questions/20454768/how-to-split-a-string-from-right-to-left-like-pythons-rsplit
# the split pattern is equivalent to the rsplit() function in python
Plotting TANGO hits
# add species and strain information for plotting
tango <- left_join(select(seqInfo, name, id, species_id, strain), tango.res.df, by = c("id" = "id"))
# write results to file for B8441 for plotting
tango %>% filter(grepl("PIS", name)) %>% write_tsv(file = "./input/B8441-homologs-tango.tsv")
# reorder the sequences for plotting
feature1 <- feature %>%
mutate(name = ordered(name, levels = rev(genetreeOrder)))
tango$name <- ordered(tango$name, levels = rev(genetreeOrder))
# plot
p1 <- ggplot(filter(feature1, type == "entire protein")) +
geom_segment(aes(x = name, y = start, xend = name, yend = end), size = 2.5, color = "grey40")
p2 <- geom_segment(data = filter(feature1, type == "Hyphal_reg_CWP"), aes(x = name, y = start, xend = name, yend = end), size = 2.5, color = "#1f78b4")
p3 <- geom_segment(data = tango, aes(x = name, xend = name, y = ifelse(start-4 >= 0, start-4, 0), yend = end + 4, color = median), size = 2.5)
p1 + p2 + p3 + coord_flip() + theme_classic() +
scale_color_distiller(type = "seq", palette = 17, direction = 1) +
theme(axis.text.y = element_text(size = 7, colour = rev(genetreeColor$color)),
axis.line.y = element_blank(), axis.ticks.y = element_blank(),
axis.line.x = element_blank(), axis.ticks.x = element_blank(),
legend.position = c(0.8,0.8),
panel.background = element_rect(fill = alpha("lightblue",0.5))) +
ylim(-2, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "Median TANGO score") +
ggtitle("TANGO hits with Hyphal_reg_CWP domain shown behind")

ggsave("output/figure/20210526-tango-score-segment.png", width = 7, height = 6)
Serine/Threonine frequencies
S/T sites are potential sites for O-glycosylation, which could increase the rididity of the stalk of the protein and allow the N-terminal domain to protrude out of the cell wall facing the exterior. More evidence for the importance of O-glycosylation in a serine/threonine-rich domain can be found here.
To determine the S/T frequency in the XP_028889033 homologs, I ran the program freak
from the EMBOSS suite with the parameters of 100 aa sliding window and a step size of 10 aa. After reformating the output, the rest of the analysis is accomplished below.
# load data
ST.freq <- read_tsv("output/seq-feature/ST_freq_100_10_freak.out.gz", col_types = "cid")
Error in read_tsv("output/seq-feature/ST_freq_100_10_freak.out.gz", col_types = "cid") :
could not find function "read_tsv"
ggplot(ST.freq, aes(x = id, y = pos)) + geom_tile(aes(fill = freq)) +
coord_flip() + theme_classic() + scale_fill_distiller(palette = "RdGy", limits = c(0, 0.8), oob = scales::squish, breaks = seq(0, 0.6, by = 0.2)) +
theme(axis.text.y = element_text(size = 7, colour = rev(genetreeColor$color)),
axis.line.y = element_blank(), axis.ticks.y = element_blank(),
axis.line.x = element_blank(), axis.ticks.x = element_blank(),
legend.position = c(0.8,0.8),
panel.background = element_rect(fill = alpha("lightblue",0.5))) +
ylim(-2, 4500) + labs(y = "Position in sequence", x = "Sequences", color = "Frequency") +
ggtitle("Serine/Threonine frequency in 100 aa sliding windows")
Vectorized input to `element_text()` is not officially supported.
Results may be unexpected or may change in future versions of ggplot2.

ggsave("output/figure/20210530-homologs-ST-freq-100aa-window.png", bg = "transparent", width = 7, height = 6)
ST.comb <- bind_rows("S/T" = ST.freq, S = S.freq, T = T.freq, .id = "Var") %>%
mutate(Var = ordered(Var, levels = c("S/T","S","T")))
ggplot(ST.comb, aes(x = id, y = pos)) + geom_tile(aes(fill = freq)) +
facet_wrap(~Var, scales = "fixed") + theme_minimal() + coord_flip() +
scale_fill_distiller(palette = "RdGy", limits = c(-0.05, 0.55), oob = scales::squish, breaks = seq(0,0.5,by=0.1)) +
#scale_fill_gradient2(low = "#1a1a1a", high = "#b30000", midpoint = 0.2) +
theme(axis.text.y = element_text(size = 7, colour = rev(genetreeColor$color)),
axis.line.y = element_blank(), axis.ticks.y = element_blank(),
axis.line.x = element_blank(), axis.ticks.x = element_blank(),
legend.position = c(0.95,0.8),
panel.background = element_rect(fill = alpha("lightblue",0.5))) +
ylim(1, 4500) + ylab("Position in sequence") + xlab("Sequences") +
ggtitle("Ser/Thr frequency in 100 aa windows (frequency > 0.55 replaced by 0.55)")
Vectorized input to `element_text()` is not officially supported.
Results may be unexpected or may change in future versions of ggplot2.

ggsave("output/figure/20210530-ST-freq-composite.png", width = 10, height = 6)
LS0tCnRpdGxlOiAiQW5hbHl6ZSBYUF8wMjg4ODkwMzMgaG9tb2xvZ3MgaW4gQy4gYXVyaXMgc3RyYWlucyIKYXV0aG9yOiAiQmluIEhlIgpkYXRlOiAiMDQvMjMvMjAyMSAgKHVwZGF0ZWQ6IGByIFN5cy5EYXRlKClgKSIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKYGBge3IgbG9hZF9saWJyYXJpZXMsIGVjaG8gPSBGQUxTRX0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkodGlkeXZlcnNlKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoY293cGxvdCkpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KHRyZWVpbykpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KGdndHJlZSkpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KHBsb3RseSkpCmBgYAoKIyMgR29hbAoKQW5hbHl6ZSB0aGUgZXZvbHV0aW9uIG9mIHNlcXVlbmNlIGZlYXR1cmVzIG9mIHRoZSBYUF8wMjg4ODkwMzMgaG9tb2xvZ3Mgd2l0aGluIF9DLiBhdXJpc18gc3BlY2llcy4gSW4gcGFydGljdWxhciwgd2UgYXJlIGludGVyZXN0ZWQgaW4gaW50cmEtc3BlY2llcyB2YXJpYXRpb24gaW4gY29weSBudW1iZXIsIE5URCBwcm90ZWluIHNlcXVlbmNlIGV2b2x1dGlvbmFyeSByYXRlcywgc3RhbGsgcmVwZWF0IG51bWJlcnMgYW5kIHNlcXVlbmNlcy4KCiMjIEhvbW9sb2dzIGlkZW50aWZpY2F0aW9uCkhvbW9sb2dzIG9mIHRoZSBQRjExNzY1IGRvbWFpbiBjb250YWluaW5nIHByb3RlaW5zIHdlcmUgaWRlbnRpZmllZCBpbiB0aGUgZml2ZSBzdHJhaW5zIG9mIF9DLiBhdXJpc18gdXNlZCBpbiBNdcOxb3ogX2V0IGFsLl8gMjAxOCBOYXQuIEdlbmV0LiBIb21vbG9ncyBmcm9tIF9DLiBwc2V1ZG9oYWVtdWxvbmlzXyBhbmQgX0MuIGhhZW11bG9uaV8gd2VyZSBhZGRlZCB0byBoZWxwIHByb3ZpZGUgdGhlIGV2b2x1dGlvbmFyeSBjb250ZXh0LCBlLmcuIHRpbWluZyBvZiBnZW5lIGR1cGxpY2F0aW9uIGFuZCBzZXF1ZW5jZSBldm9sdXRpb24gYm90aCB3aXRoaW4gYW5kIGJldHdlZW4gY2xvc2VseSByZWxhdGVkIHNwZWNpZXMuIEZpbmFsbHksIHR3byBob21vbG9ncyBmcm9tIHRoZSBvdXRyZ3JvdXAgc3BlY2llcyBfRC4gaGFuc2VuaWlfIHdlcmUgYWRkZWQgdG8gcm9vdCB0aGUgZ2VuZSB0cmVlLiBBIHRoaXJkIF9ELiBoYW5zZW5paV8gc2VxdWVuY2luZyB3aXRoIHRoZSBQRjExNzY1IGRvbWFpbiB3YXMgbm90IGluY2x1ZGVkIGFzIGl0IGJlbG9uZyB0byB0aGUgQ2xhdmlzcG9yYS9DYW5kaWRhIGR1cGxpY2F0ZSAyIGJyYW5jaCwgd2hpY2ggZGlkbid0IGluY2x1ZGUgYW55IF9DLiBhdXJpc18gc2VxdWVuY2VzLgoKKipVcGRhdGUgMjAyMS0wNS0yMSBbSEJdIENsYWRlIEkgc3RyYWluIDY2ODQgaXMgcmVtb3ZlZCBmcm9tIHRoaXMgYW5hbHlzaXMsIGxlYXZpbmcgZm91ciBzdHJhaW5zIHJlcGVzZW50aW5nIG9uZSBvZiB0aGUgZm91ciBjbGFkZXMqKgoKQXMgc2hvd24gaW4gTXXDsW96IF9ldCBhbC5fIDIwMjEgR2VuZXRpY3MsIF9DLiBhdXJpc18gYXMgYSBzcGVjaWVzIGhhcyBhIHRvdGFsIG9mIGVpZ2h0IG1lbWJlcnMgaW4gdGhpcyBmYW1pbHkuIFRoZSBudW1iZXIgb2YgbWVtYmVycyBwcmVzZW50IGluIGVhY2ggc3RyYWluIHZhcmllcy4gSW4gcGFydGljdWxhciwgQ2xhZGUgSUkgc3RyYWlucywgcmVwcmVzZW50ZWQgYnkgQjExMjIwIGluIG91ciBkYXRhc2V0LCBoYXMgb25seSB0aHJlZS4gQmVsb3cgd2Ugd2lsbCBzaG93IHRoZSBkb21haW4gYXJjaGl0ZWN0dXJlIGZvciB0aGUgZWlnaHQgbWVtYmVycyBmcm9tIHRoZSBjbGFkZSBJIHN0cmFpbiBCODQ0MS4gVGhlIGRhdGEgZm9yIHRoaXMgcGxvdCBpcyBhY3R1YWxseSBnZW5lcmF0ZWQgaW4gdGhlIFtsYXR0ZXIgcGFydF0oI0I4NDQxKSBvZiB0aGlzIFIgbWFya2Rvd24gZmlsZQoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTMuNX0KIyByZWFkIGluIGRhdGEKbGVuIDwtIHJlYWRfdHN2KCJpbnB1dC9CODQ0MS1ob21vbG9ncy1sZW5ndGgtbmFtZS50c3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCkI4NDQxIDwtIHJlYWRfdHN2KCJpbnB1dC9CODQ0MS1ob21vbG9ncy1mZWF0dXJlLXRhYmxlLnRzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkgJT4lIAogIG11dGF0ZSh0eXBlID0gaWZlbHNlKGdyZXBsKCJUUi0iLHR5cGUpLCAiVGFuZGVtIFJlcGVhdCIsIHR5cGUpLCB0eXBlID0gb3JkZXJlZCh0eXBlLCBsZXZlbHMgPSB1bmlxdWUodHlwZSkpKSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChsZW4sIHNob3J0TmFtZSA9IG5hbWUsIGdJRCwgcElEKSwgYnkgPSBjKCJuYW1lIiA9ICJwSUQiKSkgJT4lIAogIHNlbGVjdChzaG9ydE5hbWUsIGdJRCwgcElEID0gbmFtZSwgdHlwZSwgc3RhcnQsIGVuZCkKQjg0NDEudGFuZ28gPC0gcmVhZF90c3YoImlucHV0L0I4NDQxLWhvbW9sb2dzLXRhbmdvLnRzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkgJT4lIAogIGxlZnRfam9pbihzZWxlY3QobGVuLCBzaG9ydE5hbWUgPSBuYW1lLCBnSUQsIHBJRCksIGJ5ID0gYygibmFtZSIgPSAicElEIikpCgojIHNvcnQgdGhlIHNlcXVlbmNlcyBieSBwcm90ZWluIGxlbmd0aApzZXEub3JkZXIgPC0gbGVuJGdJRApCODQ0MSRnSUQgPC0gb3JkZXJlZChCODQ0MSRnSUQsIGxldmVscyA9IHNlcS5vcmRlcikKQjg0NDEudGFuZ28kZ0lEIDwtIG9yZGVyZWQoQjg0NDEudGFuZ28kZ0lELCBsZXZlbHMgPSBzZXEub3JkZXIpCgojIHBsb3QKY29sb3JzIDwtIGMoImdyZXkiLCAiIzFmNzhiNCIsICIjZTMxYTFjIiwgIiM2YTNkOWEiLCAib3JhbmdlNCIpCnAxIDwtIGdncGxvdChCODQ0MSwgYWVzKHggPSBnSUQsIHkgPSBzdGFydCkpICsgIGdlb21fc2VnbWVudChhZXMoeGVuZCA9IGdJRCwgeWVuZCA9IGVuZCksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDcpCnAyIDwtIGdlb21fc2VnbWVudChhZXMoeCA9IGdJRCwgeSA9IHN0YXJ0ICsgMSwgeGVuZCA9IGdJRCwgeWVuZCA9IGVuZCAtIDEsIGNvbG9yID0gdHlwZSksIHNpemUgPSA2LjUpCnAzIDwtIGdlb21fc2VnbWVudChkYXRhID0gQjg0NDEudGFuZ28sIGFlcyh4ZW5kID0gZ0lELCAgeSA9IGlmZWxzZShzdGFydC0zID49IDAsIHN0YXJ0LTMsIDApLCAgeWVuZCA9IGVuZCArIDMsIGFscGhhID0gbWVkaWFuKSwKICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fbnVkZ2UoeCA9IC0wLjQsIHkgPSAwKSwgY29sb3IgPSAiZGFya3JlZCIsIHNpemUgPSAyKQpwNCA8LSBwMSArIHAyICsgcDMgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9jb3dwbG90KCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JzKSArIAogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gcGFzdGUwKGxlbiRnSUQsICIgKCIsIGxlbiRuYW1lLCAiKSIpKSArCiAgc2NhbGVfYWxwaGEoZ3VpZGUgPSAibm9uZSIpICsKICBsYWJzKHkgPSAiUG9zaXRpb24gaW4gc2VxdWVuY2UiLCB4ID0gTlVMTCwgY29sb3IgPSAiRkVBVFVSRVMiKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC43LDAuNCksCiAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oNiw2LDYsNiksCiAgICAgICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KHNpemUgPSAwLjUsIGxpbmV0eXBlID0gInNvbGlkIiwgY29sb3IgPSAxKSkKcDQKZ2dzYXZlKCJvdXRwdXQvZmlndXJlLzIwMjEwNTI2LUI4NDQxLWRvbWFpbi10YW5kZW0tcmVwZWF0cy5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDMuNSkKYGBgCioqRmlnLiAxIERvbWFpbiBzY2hlbWF0aWMgb2YgdGhlIGVpZ2h0IGhvbW9sb2dzIGluIHRoZSBIeXIvSWZmLWxpa2UgKEhpbCkgZmFtaWx5IGluIF9DLiBhdXJpc18gc3RyYWluIEI4NDQxKiouIFRoZSBnZW5lIG5hbWUgaXMgc2hvd24gdG8gdGhlIGxlZnQgYW5kIHNvcnRlZCBiYXNlZCBvbiB0aGUgbGVuZ3RoIG9mIHRoZSBwcmVkaWN0ZWQgcHJvdGVpbnMuIFZhcmlvdXMgZmVhdHVyZXMgd2VyZSBzaG93biBhcyBjb2xvcmVkIGJsb2NrcywgaW5jbHVkaW5nIHRoZSBIeXBoYWxfcmVnX0NXUCAoUEYxMTc2NSkgZG9tYWluLCBTaWduYWwgUGVwdGlkZSBhcyBwcmVkaWN0ZWQgYnkgU2lnbmFsUCA1LjAgc2VydmVyLCBHUEktYW5jaG9yIHByZWRpY3RlZCBieSBQcmVkR1BJIHNlcnZlciBhbmQgdGFuZGVtIHJlcGVhdHMgcHJlZGljdGVkIGJ5IFhTVFJFQU0gKHNlZSBNYXRlcmlhbHMgYW5kIE1ldGhvZHMpLiBUaGUgc2hvcnQgYmFycyBiZWhpbmQgZWFjaCBzZXF1ZW5jZSdzIHNjaGVtYXRpYyByZXByZXNlbnRzIFRBTkdPIHByZWRpY3RlZCDOsi1hZ2dyZWdhdGlvbiBtb3RpZnMsIHdob3NlIHByZWRpY3RlZCBzdHJlbmd0aCAoc2NvcmUpIGlzIHByb3BvcnRpb25hbCB0byB0aGUgdHJhbnNwYXJlbmN5IG9mIHRoZSBiYXIuCgpgciBsZW4gJT4lIGFycmFuZ2UoZGVzYyhsZW5ndGgpKWAKCiMjIEV2b2x1dGlvbiAoZHVwbGljYXRpb25zIGFuZCBsb3NzZXMpCiMjIyBHZW5lIHRyZWUKVGhlIGdlbmUgdHJlZSBpbmZlcnJlZCBiYXNlZCBvbiB0aGUgUEYxMTc2NSBkb21haW4gaW4gZWFjaCBzZXF1ZW5jZSBpcyBwcmVzZW50ZWQgYmVsb3c6CgohW2dlbmUgdHJlZV0ob3V0cHV0L2dlbmUtdHJlZS93aXRoLW91dGdyb3VwL2ZvdXItc3RyYWlucy9SQXhNTF9iaXBhcnRpdGlvbnMuY2x1c3RhbG8tY2F1cmlzLWZvdXItc3RyYWlucy5maWd0cmVlLWFubm8ucG5nKQoqKkZpZy4gMiBSQXhNTCBpbmZlcnJlZCBnZW5lIHRyZWUgZm9yIEh5ci9JZmYtTGlrZSAoSElMKSBmYW1pbHkgbWVtYmVycyBpbiBfQy4gYXVyaXNfLCB0d28gTURSIGNsYWRlIHNwZWNpZXMgX0MuIHBzZXVkb2hhZW11bG9uaXNfIGFuZCBfQy4gaGFlbXVsb25pXywgYXMgd2VsbCBhcyBhbiBvdXRncm91cCBfRC4gaGFuc2VuaWlfLioqIFRoZSBicmFuY2ggdGhpY2tuZXNzIGlzIHNob3duIHByb3BvcnRpb25hbCB0byB0aGUgdmFsdWUgb2YgdGhlIHJhcGlkIGJvb3RzdHJhcHBpbmcgdmFsdWUuIFRoZSB0cmVlIGlzIG1hbnVhbGx5IHJvb3RlZCBvbiB0aGUgdHdvIF9ELiBoYW5zZW5paV8gc2VxdWVuY2VzLiBUaGUgcm9vdCBjaG9pY2UgaXMgYmFzZWQgb24gdGhlIGdlbmUgdHJlZSBpbmNsdWRpbmcgaG9tb2xvZ3MgZnJvbSBhY3Jvc3MgdGhlIEFzY29teWNldGVzLiBUaGUgc2hvcnQgdGVybWluYWwgYnJhbmNoIGxlbmd0aHMgYW1vbmcgdGhlIF9DLiBhdXJpc18gc3RyYWlucyBpbmRpY2F0ZSB0aGF0IHRoZXJlIGhhZCBiZWVuIGxpdHRsZSBkaXZlcmdlbmNlIGluIHRoZSBQRjExNzY1IGRvbWFpbiBpbiB0aGVzZSBzZXF1ZW5jZXMuIExhc3RseSwgdGhlIGNvbG9ycyBvZiB0aGUgbGVhZiBub2RlIG5hbWVzIGZvciB0aGUgX0MuIGF1cmlzXyBzdHJhaW5zIGFyZSBiYXNlZCBvbiBNdcOxb3ogX2V0IGFsLl8gMjAxOCBOYXQuIEdlbmV0LgoKIyMjIFJlY29uY2lsaWF0aW9uIGFuZCByZWFycmFuZ2VtZW50ClRvIGluZmVyIHRoZSB0aW1pbmcgb2YgZ2VuZSBkdXBsaWNhdGlvbiBhbmQgbG9zcyBldmVudHMsIHRoZSBnZW5lIHRyZWUgaXMgcmVjb25jaWxlZCB3aXRoIHRoZSBzcGVjaWVzIHRyZWUgaW4gTm90dW5nIDIuOS4gUmVhcnJhbmdlbWVudCBvZiB0aGUgcmVjb25jaWxlZCBnZW5lIHRyZWUgd2FzIHBlcmZvcm1lZCBpbiB0aGUgc2FtZSBzb2Z0d2FyZSwgYWxsb3dpbmcgZm9yIHN3YXBwaW5nIG9mIGJyYW5jaGVzIHdpdGggcmFwaWQgYm9vdHN0cmFwcGluZyB2YWx1ZXMgbG93ZXIgdGhhbiAqKjkwJSoqLiBUaGUgcmVhcnJhbmdlZCB0cmVlIGhhcyBhIHRvdGFsIG9mICoqMTUqKiBkdXBsaWNhdGlvbiBhbmQgKioxMyoqIGxvc3Nlcy4gTm90ZSB0aGF0IHRoZSBjbGFkZSBJIHN0cmFpbiA2Njg0IGFwcGVhcmVkIHRvIGhhdmUgZXhwZXJpZW5jZWQgc2V2ZXJhbCBsb3NzZXMsIGJ1dCB0aGlzIGlzIHZlcnkgbGlrZWx5IGR1ZSB0byB0aGUgcmVsYXRpdmVseSBwb29yIGFzc2VtYmx5IHN0YXR1cyBvZiB0aGUgc3RyYWluLCBub3QgcmVhbCBldm9sdXRpb25hcnkgbG9zc2VzLgoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0KIyByZWFkIGluIHJlY29uY2lsZWQgYW5kIHJlYXJyYW5nZWQgZ2VuZSB0cmVlCmdlbmUudHJlZSA8LSByZWFkLm5oeCgib3V0cHV0L2dlbmUtdHJlZS9ub3R1bmcvUkF4TUxfYmlwYXJ0aXRpb25zLmNsdXN0YWxvLWNhdXJpcy1mb3VyLXN0cmFpbnNfcmVhcnJhbmdlZDkwLm5oeCIpICU+JSAgYXNfdGliYmxlKCkgJT4lICMgY29udmVydCB0byBhIHRpYmJsZQogIG11dGF0ZShzdHJhaW5zID0gb3JkZXJlZChTLCBsZXZlbHMgPSBjKCJDYXVyaXMuQjg0NDEiLCAiQ2F1cmlzLkIxMTIyMCIsICJDYXVyaXMuQjExMjIxIiwgIkNhdXJpcy5CMTEyNDMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNwc2V1ZG9oYWVtdWxvbmlzIiwgIkNoYWVtdWxvbmkiLCAiRGhhbnNlbmlpIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkNsYWRlIEkiLCAiQ2xhZGUgSUkiLCAiQ2xhZGUgSUlJIiwgIkNsYWRlIElWIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQy4gcHNldWRvaGFlbXVsb25pcyIsICJDLiBoYWVtdWxvbmkiLCAiRC4gaGFuc2VuaWkiKSkpCgojIHNldCB1cCBzcGVjaWVzL3N0cmFpbnMgdGlwIGxhYmVsIGNvbG9ycwojZ2VuZS50cmVlIDwtIGdlbmUudHJlZSAlPiUgCiMgIGdyb3VwT1RVKCkKZ2VuZS50cmVlICU+JQogIGFzLnRyZWVkYXRhKCkgJT4lIAogIGdndHJlZSgpICsgIGdlb21fdGlwbGFiKGFlcyhjb2xvdXIgPSBzdHJhaW5zKSwgZm9udGZhY2UgPSAzLCBzaXplID0gMykgKyB4bGltKDAsMjApICsKICBzY2FsZV9jb2xvcl9tYW51YWwobmFtZSA9ICJMRUdFTkQiLCB2YWx1ZXMgPSBjKCIjMzQ1NzE0IiwgIiM5NTIzOTUiLCAiIzAwMzBmZiIsICIjZmYyOTAwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIzAwOGFiOCIsICIjMDA4YWI4IiwgIiMwMDAwMDAiKSkgKwogIGdlb21faGlsaWdodChub2RlID0gOTgsICBmaWxsID0gImdyYXkyMCIsIGFscGhhID0gMC4yLCBjb2xvciA9ICJ3aGl0ZSIpICsgIyBIaWwtMQogIGdlb21faGlsaWdodChub2RlID0gOTQsICBmaWxsID0gImdyYXkyMCIsIGFscGhhID0gMC4yLCBjb2xvciA9ICJ3aGl0ZSIpICsgIyBIaWwtMgogIGdlb21faGlsaWdodChub2RlID0gNzgsICBmaWxsID0gImdyYXkyMCIsIGFscGhhID0gMC4yLCBjb2xvciA9ICJ3aGl0ZSIpICsgIyBIaWwtMwogIGdlb21faGlsaWdodChub2RlID0gMTAyLCBmaWxsID0gImdyYXkyMCIsIGFscGhhID0gMC4yLCBjb2xvciA9ICJ3aGl0ZSIpICsgIyBIaWwtNAogIGdlb21faGlsaWdodChub2RlID0gNTcsICBmaWxsID0gImdyYXkyMCIsIGFscGhhID0gMC4yLCBjb2xvciA9ICJ3aGl0ZSIpICsgIyBIaWwtNQogIGdlb21faGlsaWdodChub2RlID0gNjgsICBmaWxsID0gImdyYXkyMCIsIGFscGhhID0gMC4yLCBjb2xvciA9ICJ3aGl0ZSIpICsgIyBIaWwtNgogIGdlb21faGlsaWdodChub2RlID0gODIsICBmaWxsID0gImdyYXkyMCIsIGFscGhhID0gMC4yLCBjb2xvciA9ICJ3aGl0ZSIpICsgIyBIaWwtNwogIGdlb21faGlsaWdodChub2RlID0gNzMsICBmaWxsID0gImdyYXkyMCIsIGFscGhhID0gMC4yLCBjb2xvciA9ICJ3aGl0ZSIpICsgIyBIaWwtOAogIGdlb21fY2xhZGVsYWJlbChub2RlID0gOTgsICBsYWJlbCA9ICJIaWwtMSIsIG9mZnNldCA9IDcsIGNvbG9yID0gInJlZCIsIGZvbnRmYWNlID0gMikgKyAjIEhpbC0xCiAgZ2VvbV9jbGFkZWxhYmVsKG5vZGUgPSA5NCwgIGxhYmVsID0gIkhpbC0yIiwgb2Zmc2V0ID0gNywgY29sb3IgPSAicmVkIiwgZm9udGZhY2UgPSAyKSArICMgSGlsLTEKICBnZW9tX2NsYWRlbGFiZWwobm9kZSA9IDc4LCAgbGFiZWwgPSAiSGlsLTMiLCBvZmZzZXQgPSA3LCBjb2xvciA9ICJyZWQiLCBmb250ZmFjZSA9IDIpICsgIyBIaWwtMQogIGdlb21fY2xhZGVsYWJlbChub2RlID0gMTAyLCBsYWJlbCA9ICJIaWwtNCIsIG9mZnNldCA9IDcsIGNvbG9yID0gInJlZCIsIGZvbnRmYWNlID0gMikgKyAjIEhpbC0xCiAgZ2VvbV9jbGFkZWxhYmVsKG5vZGUgPSA1NywgIGxhYmVsID0gIkhpbC01Iiwgb2Zmc2V0ID0gNywgY29sb3IgPSAicmVkIiwgZm9udGZhY2UgPSAyKSArICMgSGlsLTEKICBnZW9tX2NsYWRlbGFiZWwobm9kZSA9IDY4LCAgbGFiZWwgPSAiSGlsLTYiLCBvZmZzZXQgPSA3LCBjb2xvciA9ICJyZWQiLCBmb250ZmFjZSA9IDIpICsgIyBIaWwtMQogIGdlb21fY2xhZGVsYWJlbChub2RlID0gODIsICBsYWJlbCA9ICJIaWwtNyIsIG9mZnNldCA9IDcsIGNvbG9yID0gInJlZCIsIGZvbnRmYWNlID0gMikgKyAjIEhpbC0xCiAgZ2VvbV9jbGFkZWxhYmVsKG5vZGUgPSA3MywgIGxhYmVsID0gIkhpbC04Iiwgb2Zmc2V0ID0gNywgY29sb3IgPSAicmVkIiwgZm9udGZhY2UgPSAyKSArICMgSGlsLTEKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmdnc2F2ZSgib3V0cHV0L2ZpZ3VyZS8yMDIxMDYwMS1yZWNvbmNpbGVkLU5URC10cmVlLWFubm90YXRlZC5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDgpCmBgYAoqKkZpZy4gMyBUaGUgc2FtZSB0cmVlIGluIEZpZy4gMyBhZnRlciByZWNvbmNpbGlhdGlvbiBhbmQgcmVhcnJhbmdlbWVudCB1c2luZyBOb3R1bmcgdjIuOS4qKiBUaGUgc3BlY2llcy9zdHJhaW5zIHRyZWUgYW5kIHRoZSBnZW5lIHRyZWUgYXMgc2hvd24gaW4gRmlnLiAzIHdlcmUgdXNlZCBhcyBpbnB1dCBmb3IgcmVjb25jaWxpYXRpb24gaW4gTm90dW5nIHYyLjkuIFJvb3RpbmcgYW5kIHJlY29uY2lsaWF0aW9uIHdlcmUgcGVyZm9ybWVkIGluIGEgc2luZ2xlIHN0ZXAsIGFmdGVyIHdoaWNoIHRoZSB0cmVlIGlzIHJlYXJyYW5nZWQgYnkgYWxsb3dpbmcgYnJhbmNoZXMgd2l0aCA8IDkwJSByYXBpZCBib290c3RyYXAgc3VwcG9ydCB0byBiZSBzd2FwcGVkIGluIG9yZGVyIHRvIHJlZHVjZSB0aGUgdG90YWwgbnVtYmVyIG9mIGV2ZW50cyAoZHVwbGljYXRpb25zIGFuZCBsb3NzZXMpLCByZXN1bHRpbmcgaW4gdGhlIHJlYXJyYW5nZWQgdHJlZS4gQmVjYXVzZSBvZiB0aGUgcmVhcnJhbmdlbWVudCwgYnJhbmNoIGxlbmd0aHMgZG8gbm90IGNvcnJlc3BvbmQgdG8gdGhlIGVzdGltYXRlZCBzdWJzdGl0dXRpb24gbnVtYmVyLiBSZWQgbm9kZXMgaW5kaWNhdGUgaW5mZXJyZWQgZHVwbGljYXRpb24gZXZlbnRzLiBMb3NzZXMgd2VyZSBub3Qgc2hvd24gZXhwbGljaXRseS4gU2VxdWVuY2UgbmFtZXMgd2VyZSBjb2xvcmVkIGluIHRoZSBzYW1lIHdheSBhcyBpbiBGaWcuIDIKCldlIGNhbiBzdW1tYXJpemUgdGhlIGluZmVycmVkIGdhaW5zIGFuZCBsb3NzZXMgb24gdGhlIHNwZWNpZXMvc3RyYWlucyB0cmVlLgoKMS4gUmVhZCBpbiB0aGUgdHJlZSBpbiBOZXdpY2sgZm9ybWF0CjEuIFJlYWQgaW4gdGhlIHBhcnNhYmxlIHN0YXRpc3RpYyAoY29waWVkIGZyb20gTm90dW5nICJldmVudHMgc3VtbWFyeSIgb3V0cHV0KQoxLiBQbG90IHVzaW5nIGdndHJlZQoKYGBge3IgcGFyc2Vfc3RhdHN9CnNwcy50cmVlIDwtIHJlYWQudHJlZSgiaW5wdXQvY2F1cmlzLWZvdXItc3RyYWlucy1vdXRncm91cC10cmVlLm53ayIpCm5vdHVuZy5zdGF0IDwtIHJlYWRfdHN2KCJvdXRwdXQvZ2VuZS10cmVlL25vdHVuZy9SQXhNTF9iaXBhcnRpdGlvbnMuY2x1c3RhbG8tY2F1cmlzLWZvdXItc3RyYWluc19yZWFycmFuZ2VkOTBfc3RhdHMudHh0IiwgY29sX3R5cGVzID0gJ2NpaScpCnNwcy50cmVlLnRiIDwtIGFzX3RpYmJsZShzcHMudHJlZSkgJT4lIAogIGZ1bGxfam9pbihub3R1bmcuc3RhdCwgYnkgPSAibGFiZWwiKQpzcHMudHJlZSA8LSBhcy50cmVlZGF0YShzcHMudHJlZS50YikKYGBgCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9M30Kc3BzLnRyZWUgJT4lCiAgZ2d0cmVlKCkgKyAKICBnZW9tX3RpcGxhYihhc195bGFiID0gVFJVRSwgc2l6ZSA9IDExLCBmYWNlID0gNCkgKwogIGdlb21fdGV4dChhZXMoeCA9IGJyYW5jaCwgbGFiZWwgPSBkdXBsaWNhdGlvbnMpLCB2anVzdCA9IC0uNCwgc2l6ZSA9IDMsIGNvbG9yID0gInJlZCIsIGZhY2UgPSAyKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gYnJhbmNoLCBsYWJlbCA9IGxvc3NlcyksIHZqdXN0ID0gMS40LCBzaXplID0gMywgY29sb3IgPSAiZ3JleTIwIiwgZmFjZSA9IDIpCmdnc2F2ZSgib3V0cHV0L2ZpZ3VyZS8yMDIxMDYwMS1nYWlucy1sb3NzZXMtcmVjb25jaWxpYXRpb24ucG5nIiwgd2lkdGggPSAzLCBoZWlnaHQgPSAzKQpgYGAKKipGaWcuIDQgU3VtbWFyeSBvZiBpbmZlcnJlZCBkdXBsaWNhdGlvbiBhbmQgbG9zcyBldmVudHMgaW4gX0MuIGF1cmlzXyBzdHJhaW5zIGFuZCBzZWxlY3RlZCBvdXRncm91cHMuKiogVGhlIHRyZWUgdG9wb2xvZ3kgaXMgYmFzZWQgb24gTXXDsW96IF9ldCBhbC5fIDIwMTggUE1JRDogMzA1NTkzNjkuIFRoZSBudW1iZXIgb2YgZHVwbGljYXRpb25zIChyZWQpIGFuZCBsb3NzZXMgKGJsYWNrKSB3ZXJlIGluZmVycmVkIHVzaW5nIE5vdHVuZyAyLjkgYW5kIGxhYmVsZWQgb24gdGhlIHRvcCBhbmQgYm90dG9tIG9mIHRoZSBicmFuY2hlcyByZXNwZWN0aXZlbHkuIAoKPiBOb3RlIHRoYXQgYWxsIHNldmVuIGR1cGxpY2F0aW9ucyB0aGF0IGxlZCB0byB0aGUgZWlnaHQgbWVtYmVycyBvZiB0aGUgSGlsIGZhbWlseSBpbiBfQy4gYXVyaXNfIG9jY3VycmVkIGluIHRoZSBhbmNlc3RvciBvZiB0aGUgTURSIGNsYWRlLCB3aGljaCBpbmNsdWRlcyBfQy4gcHNldWRvaGFtdWxvbmlzXywgX0MuIGhhZW11bG9uaV8gYW5kIF9DLiBkdW9idXNoYWVtdWxvbmlzXywgdGhlIGxhc3Qgb2Ygd2hpY2ggd2FzIG5vdCBpbmNsdWRlZCBpbiB0aGlzIHRyZWUuIEFkZGl0aW9uYWwgZHVwbGljYXRpb25zIHdlcmUgaW5mZXJyZWQgaW4gdGhlIE1EUiBjbGFkZSBidXQgbm90IG9uIHRoZSBfQy4gYXVyaXNfIGJyYW5jaGVzLiBJbiB0ZXJtcyBvZiBsb3NzZXMsIHRoZSBtb3N0IG5vdGFibGUgYnJhbmNoIGlzIHRoZSBfQy4gYXVyaXNfIEIxMTIyMCBzdHJhaW4sIHdoaWNoIGJlbG9uZ3MgdG8gY2xhZGUgSUksIHRoYXQgaGFzIGxvc3QgZml2ZSBvZiB0aGUgZWlnaHQgbWVtYmVycy4gVGhpcyBpcyBjb25zaXN0ZW50IHdpdGggcHJldmlvdXMgc3R1ZGllcywgZS5nLiBNdcOxb3ogX2V0IGFsLl8gMjAyMSBHZW5ldGljcy4gVGhlIHNpbmdsZSBsb3NzIGV2ZW50IGluIHRoZSBfQy4gYXVyaXNfIHN0cmFpbiBCMTEyMjEgd2FzIGluY29uc2lzdGVudCB3aXRoIHRoZSBzdHVkeSBqdXN0IG1lbnRpb25lZC4gRnVydGhlciBpbnZlc3RpZ2F0aW9ucyBzdWdnZXN0ZWQgdGhhdCB0aGlzIHdhcyBtb3N0IGxpa2VseSBkdWUgdG8gaW5jb21wbGV0ZSBhc3NlbWJseSBvZiBpdHMgZ2Vub21lLgoKIyMgRXZvbHV0aW9uIG9mIHNlcXVlbmNlIGZlYXR1cmVzCiMjIyBTZXF1ZW5jZSBJRHMsIHNwZWNpZXMgYW5kIHN0cmFpbiBpbmZvcm1hdGlvbi4KYGBge3IgbG9hZF9zZXFfaW5mb30Kc3BzLmxpc3QgPC0gYygiQ2F1cmlzIiwiQ3BzZXVkb2hhZW11bG9uaXMiLCJDaGFlbXVsb25pIiwiRGhhbnNlbmlpIikKc2VxSW5mbyA8LSByZWFkX3Rzdigib3V0cHV0L3NlcS1mZWF0dXJlL2NhdXJpcy1yZW5hbWVkLXNlcWluZm8udHN2IiwgY29tbWVudCA9ICIjIiwgY29sX3R5cGVzID0gImNjY2NpIikgJT4lIAogIG11dGF0ZShzcGVjaWVzX2lkID0gZmFjdG9yKHNwZWNpZXMsIGxldmVscyA9IHNwcy5saXN0KSwgc3BlY2llcyA9IE5VTEwpCmBgYAoKIyMjIEFkaGVzaW4gcHJlZGljdGlvbgoKICAgIEZ1bmdhbFJWIHRocmVzaG9sZDogMC41MTsgRmFhUHJlZCB1c2luZyBBQ0hNIG1vZGVsIHdpdGggdGhlIHJlY29tbWVuZGVkIC0wLjggdGhyZXNob2xkLgogICAgCmBgYHtyIGFkaGVzaW5fcHJlZGljdGlvbn0KZnJ2LnRoID0gMC41MTEgIyByZWNvbW1lbmRlZCBGdW5nYWxSViBzY29yZSB0aHJlc2hvbGQKZnJ2IDwtIHJlYWRfdHN2KCJvdXRwdXQvc2VxLWZlYXR1cmUvY2F1cmlzLXJlbmFtZWQtZnVuZ2FscnYudHh0Iiwgc2tpcCA9IDMsIGNvbF9uYW1lcyA9IGMoIm5hbWUiLCJmcnYuc2NvcmUiKSwgY29sX3R5cGVzID0gImNkIikgJT4lIAogIG11dGF0ZShuYW1lID0gc3RyX3N1YihuYW1lLCAyKSwgZnJ2LnByZWQgPSBmcnYuc2NvcmUgPiBmcnYudGgpCmZhYSA8LSByZWFkX3Rzdigib3V0cHV0L3NlcS1mZWF0dXJlL2NhdXJpcy1yZW5hbWVkLWZhYXByZWQudHh0IiwgY29sX25hbWVzID0gYygibmFtZSIsImZhYS5zY29yZSIsImZhYS5wcmVkIiksIGNvbF90eXBlcyA9ICJjZGMiKSAlPiUgCiAgbXV0YXRlKGZhYS5wcmVkID0gaWZlbHNlKGZhYS5wcmVkID09ICJBZGhlc2luIiwgVFJVRSwgRkFMU0UpKQppZigiZnJ2LnNjb3JlIiAlaW4lIG5hbWVzKHNlcUluZm8pKQogIHNlcUluZm8gPC0gc2VsZWN0KHNlcUluZm8sIC1mcnYuc2NvcmUsIC1mcnYucHJlZCwgLWZhYS5zY29yZSwgLWZhYS5wcmVkKQpzZXFJbmZvIDwtIHNlcUluZm8gJT4lIGxlZnRfam9pbihmcnYpICU+JSBsZWZ0X2pvaW4oZmFhKQpzZXFJbmZvICU+JSAKICBncm91cF9ieShzcGVjaWVzX2lkLCBzdHJhaW4pICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSwgZnVuZ2FsUlYgPSBzdW0oZnJ2LnNjb3JlID4gMC41MTEpLCBmYWFwcmVkID0gc3VtKGZhYS5wcmVkLCBuYS5ybSA9IFQpLCAKICAgICAgICAgICAgYm90aCA9IHN1bShmcnYuc2NvcmUgPiAwLjUxMSAmIGZhYS5wcmVkKSkKYGBgCgojIyMgU2lnbmFsUCBhbmQgR1BJIHByZWRpY3Rpb24KCkdQSS1hbmNob3JlZCBwcm90ZWlucyBhcmUgY2hhcmFjdGVyaXplZCBieSBhbiBOLXRlcm1pbmFsIHNpZ25hbCBwZXB0aWRlLCB3aGljaCB3b3VsZCBkaXJlY3QgdGhlIHByb3RlaW4gdG8gdGhlIHNlY3JldGFyeSBwYXRod2F5LCBhbmQgYSBDLXRlcm1pbmFsIEdQSS1hbmNob3IgcGVwdGlkZSwgd2hpY2ggd291bGQgYmUgY2xlYXZlZCBhbmQgcmVwbGFjZWQgYnkgdGhlIEdQSS1hbmNob3IsIGFsbG93aW5nIHRoZSBwcm90ZWluIHRvIGJlIHRldGhlcmVkIHRvIHRoZSBjZWxsIHdhbGwuIEZvciBzaWduYWwgcGVwdGlkZSwgSSB1c2VkIFNpZ25hbFAgc2VydmVyLiBJdHMgbGF0ZXN0IHZlcnNpb24gaXMgNS4wLiBCdXQgSSBhbHNvIHJhbiB0aGUgc2VxdWVuY2VzIHRocm91Z2ggdGhlaXIgNC4xIHZlcnNpb24sIHdpdGggdHdvIHNldHRpbmdzLiBUaGUgcmVzdWx0cyBvZiB0aGUgbGF0dGVyIHR3byBhcmUgYWxtb3N0IGlkZW50aWNhbCwgZXhjZXB0IGZvciBvbmUgc2VxdWVuY2UgIlhQXzAyNDcxMTM1MC4xIiwgd2hpY2ggaXMgb25seSBpbmNsdWRlZCBpbiB0aGUgc2Vuc2l0aXZlIHZlcnNpb24sIGFuZCBoYXMgYSBwcm9iYWJpbGl0eSBsb3dlciB0aGFuIDAuNS4KCi0gRm9yIEdQSS1hbmNob3IgcHJlZGljdGlvbiwgSSB1c2VkIHRoZSBbUHJlZEdQSSBzZXJ2ZXJdKGh0dHA6Ly9ncGNyLmJpb2NvbXAudW5pYm8uaXQvcHJlZGdwaS8pLgotIEZvciBzaWduYWwgcGVwdGlkZSBwcmVkaWN0aW9uLCBJIHVzZWQgdGhlIFtTaWduYWxQIDUuMCBzZXJ2ZXJdKGh0dHA6Ly93d3cuY2JzLmR0dS5kay9zZXJ2aWNlcy9TaWduYWxQLykKCmBgYHtyIHNpZ25hbFAsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTV9CiMgU2lnbmFsIHBlcHRpZGUKZ2ZmLm5hbWVzIDwtIGMoImlkIiwgInNvdXJjZSIsICJuYW1lIiwgInN0YXJ0IiwgImVuZCIsICJwcm9iIiwgIm5hMSIsICJuYTIiLCAibmEzIikKc2lnbmFscDUgPC0gcmVhZF90c3YoIm91dHB1dC9zZXEtZmVhdHVyZS9jYXVyaXMtcmVuYW1lZC1zaWduYWxwNS5nZmYzIiwgY29tbWVudCA9ICIjIiwgY29sX25hbWVzID0gZ2ZmLm5hbWVzLCBjb2xfdHlwZXMgPSAiY2NjaWlkY2NjIikKCmlmKCJzaWduYWxwIiAlaW4lIG5hbWVzKHNlcUluZm8pKQogIHNlcUluZm8gPC0gc2VsZWN0KHNlcUluZm8sIC1zaWduYWxwKQoKc2VxSW5mbyA8LSBsZWZ0X2pvaW4oc2VxSW5mbywgc2VsZWN0KHNpZ25hbHA1LCBuYW1lID0gaWQsIHByb2IpLCBieSA9IGMoIm5hbWUiID0gIm5hbWUiKSkgJT4lIAogIG11dGF0ZShzaWduYWxwID0gIWlzLm5hKHByb2IpKSAlPiUgc2VsZWN0KC1wcm9iKQpgYGAKCmBgYHtyIGdwaX0KdG1wIDwtIHJlYWRfZGVsaW0oIm91dHB1dC9zZXEtZmVhdHVyZS9jYXVyaXMtcmVuYW1lZC1wcmVkZ3BpLnR4dCIsIGRlbGltID0gInwiLCBjb2xfbmFtZXMgPSBjKCJuYW1lIiwiZnAiLCJvbWVnYSIpLCBjb2xfdHlwZXMgPSBjb2xzKCkpCnByZWQuZ3BpIDwtIHRtcCAlPiUgIAogIG11dGF0ZShuYW1lID0gc3RyX3N1YihuYW1lLCAyLCAtMiksICMgcmVtb3ZlID4gYW5kIHRoZSB0cmFpbGluZyBzcGFjZQogICAgICAgICBmcCA9IGFzLm51bWVyaWMoc3RyX3N1YihmcCwgOSwgLTIpKSwgIyBleHRyYWN0IHRoZSBudW1lcmljIHBhcnQKICAgICAgICAgaXMuZ3BpID0gZnAgPD0gMC4wMSwgICAgIyBiYXNlZCBvbiB0aGUgY3V0b2ZmIG9mIHRoZSBQcmVkR1BJIHNlcnZlciAocHJvYiA8IDk5JSAtPiBub3QgR1BJLWFuY2hvcmVkKQogICAgICAgICBvbWVnYSA9IHN0cl9zdWIob21lZ2EsIDgpLAogICAgICAgICBjbGVhdmVSZXMgPSBzdHJfc3ViKG9tZWdhLCAxLCAxKSwKICAgICAgICAgY2xlYXZlUG9zID0gYXMuaW50ZWdlcihzdHJfc3ViKG9tZWdhLCAzKSksCiAgICAgICAgICkgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2VxSW5mbywgbmFtZSwgbGVuZ3RoKSwgYnkgPSBjKCJuYW1lIiA9ICJuYW1lIikpCgojIHJlbW92ZSB0aGUgY29sdW1uIGlmIGl0IGFscmVhZHkgZXhpc3RzCmlmKCJwcmVkLmdwaSIgJWluJSBuYW1lcyhzZXFJbmZvKSkKICBzZXFJbmZvIDwtIHNlbGVjdChzZXFJbmZvLCAtcHJlZC5ncGkpCnNlcUluZm8gPC0gbGVmdF9qb2luKHNlcUluZm8sIHNlbGVjdChwcmVkLmdwaSwgbmFtZSwgcHJlZC5ncGkgPSBpcy5ncGkpLCBieSA9IGMoIm5hbWUiPSJuYW1lIikpCgpzZXFJbmZvICU+JSAKICBncm91cF9ieShzcGVjaWVzX2lkLCBzdHJhaW4pICU+JSAKICBzdW1tYXJpemUoVG90YWwgPSBuKCksIFNpZ25hbFAgPSBzdW0oc2lnbmFscCksIEdQSV9QcmVkID0gc3VtKHByZWQuZ3BpKSwgQm90aCA9IHN1bShzaWduYWxwICYgcHJlZC5ncGkpLCAuZ3JvdXBzID0gImRyb3AiKQoKd3JpdGVfdHN2KHNlcUluZm8sICJvdXRwdXQvc2VxLWZlYXR1cmUvUi1zZXFpbmZvLXRhYmxlLnRzdiIsIGNvbF9uYW1lcyA9IFRSVUUpCmBgYAoKIyMjIFRhbmRlbSByZXBlYXQgc3RydWN0dXJlcwoKVGhlIG5vbi1OVEQgcG9ydGlvbiBvZiB0aGUgcHJvdGVpbnMgZXZvbHZlIHJhcGlkbHkgYW5kIG1hbnkgb2YgdGhlbSBjb250YWluIHRhbmRlbSByZXBlYXRzLiBUaGVyZWZvcmUsIGNoYXJhY3Rlcml6aW5nIGFuZCB2aXN1YWxpemluZyB0aGUgdHlwZSwgbnVtYmVyIGFuZCBzcGF0aWFsIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdGFuZGVtIHJlcGVhdHMgc2VydmUgdG8gaGlnaGxpZ2h0IHRoZSBkaWZmZXJlbmNlcyBpbiB0aGUgbm9uLU5URCBwYXJ0IG9mIHRoZSBwcm90ZWlucyBpbiB0aGlzIGZhbWlseS4KClRvIGlkZW50aWZ5IGFuZCBncm91cCB0YW5kZW0gcmVwZWF0cywgSSB1c2VkIFtYU1RSRUFNXShodHRwczovL2FtbmV3bWFubGFiLnN0YW5mb3JkLmVkdS94c3RyZWFtKSB3aXRoIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBgamF2YSAtWG14MTAwMG0gLVhtczEwMDBtIC1qYXIgfi9zdy9YU1RSRUFNL3hzdHJlYW0uamFyICRpbiAtaS43IC1JLjcgLWczIC1lMiAtTDE1IC16IC1HIC1PIC1Bc3ViLnR4dGAuIFRoZSBwYXJhbWV0ZXJzIHdlcmUgY2hvc2VuIHRvIGlkZW50aWZ5IGRlZ2VuZXJhdGUgdGFuZGVtIHJlcGVhdHMgdGhhdCBvY2N1ciBhdCBsZWFzdCB0d28gdGltZXMgYW5kIG11c3QgYmUgYSBtaW5pbXVtIGxlbmd0aCBvZiA1IGEuYS4gb3IgbG9uZ2VyIGFuZCB0aGUgbWluaW11bSBsZW5ndGggb2YgYSB0YW5kZW0gcmVwZWF0IGRvbWFpbiAoPXBlcmlvZCB4IGNvcHkgIykgbXVzdCBiZSBncmVhdGVyIHRoYW4gMTUgYS5hLiBQbGVhc2Ugc2VlIGBzY3JpcHQveHN0cmVhbS5zaGAgZm9yIGV4cGxhbmF0aW9uIG9mIHRoZSBwYXJhbWV0ZXJzLgoKYGBge3J9CnRhbmRlbSA8LSByZWFkX3Rzdigib3V0cHV0L3RhbmRlbS1yZXBlYXRzL1hTVFJFQU1fY2F1cmlzX291dGdyX3N1Yl9pMC43X2czX201X0wxNV9jaGFydC50c3YiLCAKICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9ICJjaWlpZmlkY2NjZCIsIGNvbW1lbnQgPSAiIyIpICU+JSAKICByZW5hbWUobmFtZSA9IGlkZW50aWZpZXIpCiMgbm93IGxldCdzIGNyZWF0ZSBhIHRpYmJsZSBmb3IgcGxvdHRpbmcsIHdoaWNoIHdvdWxkIGNvbnRhaW4gZWFjaCBpbnN0YW5jZSBvZiB0aGUgdGFuZGVtIHJlcGVhdCBvbiBhIHNlcGFyYXRlIHJvdwp0YW5kZW0uZGl2IDwtIHRhbmRlbSAlPiUgCiAgcm93d2lzZShuYW1lKSAlPiUgCiAgc3VtbWFyaXplKGRpdiA9IGxpc3QoYyhzZXEoZnJvbSA9IHN0YXJ0LCB0byA9IGVuZCwgYnkgPSBwZXJpb2QpLCBlbmQpKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIHVubmVzdChkaXYpCmBgYAoKYGBge3IsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTV9CiMgc3VtbWFyaXplIHN0YXRzIG9mIHRhbmRlbSByZXBlYXRzCnJlcGVhdHMgPC0gdGFuZGVtICU+JSAKICBncm91cF9ieSh0eXBlLCBwZXJpb2QpICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSwgY29weU1lYW4gPSBtZWFuKGNvcHlOKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIG11dGF0ZShsZW5ndGggPSBwZXJpb2QgKiBjb3B5TWVhbikKZ2dwbG90KHJlcGVhdHMsIGFlcyh4ID0gcGVyaW9kLCB5ID0gY29weU1lYW4pKSArIGdlb21faGV4KGJpbndpZHRoID0gYygzLDIpKSArIAogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gImdyZXkxMCIsIGhpZ2ggPSAieWVsbG93MiIsIGJyZWFrcyA9IHNlcSgxLDE3LDIpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDEwMCw2KSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAwLDQpKSArIAogIHlsYWIoIk1lYW4gY29weSBudW1iZXIgcGVyIHNlcXVlbmNlIikgKyB0aGVtZV9idygpCmBgYAoqKkZpZy4gNCBUYW5kZW0gUmVwZWF0cyAoVFJzKSBpZGVudGlmaWVkIGFtb25nIHRoZSBwcm90ZWluIHNlcXVlbmNlcy4qKiBBIHRvdGFsIG9mIGByIG5yb3cocmVwZWF0cylgIHR5cGVzIG9mIFRScyB3ZXJlIGlkZW50aWZpZWQgYnkgdGhlIFhTVFJFQU0gcHJvZ3JhbSBhcyBkZXNjcmliZWQgYWJvdmUuIFRoZSBwZXJpb2QgKHVuaXQgbGVuZ3RoKSBvZiB0aGUgVFJzIGFyZSBwbG90dGVkIGFnYWluc3QgdGhlIG1lYW4gY29weSBudW1iZXIgcGVyIHNlcXVlbmNlIGZvciB0aGUgc2FtZSBUUnMuIERhdGEgYXJlIGJpbm5lZCBieSAzIGZvciB0aGUgcGVyaW9kIGFuZCAyIGZvciB0aGUgbWVhbiBjb3B5IG51bWJlciwgYW5kIHRoZSBudW1iZXIgb2YgVFJzIGluIGVhY2ggYmluIGlzIHNob3duIGluIGRhcmstZ3JheSB0byB5ZWxsb3cgZ3JhZGllbnQuIE5vdGUgdGhhdCBtYW55IFRScyBhcmUgYm90aCBzaG9ydCAoPD0gMTUgYS5hLikgYW5kIGhhdmUgZmV3IGNvcGllcyBwZXIgc2VxdWVuY2UgKDwgNCkuIFRoZXJlIGFyZSwgaG93ZXZlciwgYSBudW1iZXIgb2YgVFJzIHRoYXQgYXJlIGxvbmcgKD4gMzAgYS5hLikgYW5kIHJlcGVhdCBmb3IgbW9yZSB0aGFuIDEwIHRpbWVzIHBlciBzZXF1ZW5jZS4gVGhvc2UgYXJlIHBvdGVudGlhbGx5IG9mIG1vcmUgaW50ZXJlc3QuCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmFzcD0wLjh9CnJlcGVhdHMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbGVuZ3RoKSkgKyBzdGF0X2VjZGYoZ2VvbSA9ICJzdGVwIikgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxMCwyMCw0MCw4MCwxNjAsMzIwLDY0MCwxMjgwKSwgdHJhbnMgPSAibG9nMiIpICsKICB5bGFiKCJQcm9iYWJpbGl0eSIpICsgeGxhYigibGVuZ3RoICg9IHBlcmlvZCAqIG1lYW4gY29waWVzKSIpICsgCiAgdGhlbWVfY293cGxvdCgpICsgYmFja2dyb3VuZF9ncmlkKCkKYGBgCioqRmlnLiA1IFRhbmRlbSBSZXBlYXQgZG9tYWluIGxlbmd0aCBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbi4qKiBFbXBpcmljYWwgY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gaXMgY2FsY3VsYXRlZCBmb3IgdGhlIGxlbmd0aCBvZiBlYWNoIHRhbmRlbSByZXBlYXQgZG9tYWluLCBkZWZpbmVkIGFzIHRoZSBwZXJpb2QgKHVuaXQgbGVuZ3RoKSBvZiBhIGRvbWFpbiBtdWx0aXBsaWVkIGJ5IHRoZSBtZWFuIGNvcHkgbnVtYmVyIGluIGFsbCBzZXF1ZW5jZXMgdGhhdCBjb250YWluIHRoaXMgZG9tYWluLiBUaGUgeC1heGlzIGlzIGxvZzIgdHJhbnNmb3JtZWQuIE5vdGUgdGhhdCB+NTAlIG9mIHRoZSBkb21haW5zIGhhdmUgYSBsZW5ndGggPCA0MCByZXNpZHVlcyBhbmQgfjgwJSA8IDE2MCByZXNpZHVlcy4KCmBgYHtyIHdyaXRlX1hQXzAyODg4OTAzM190b190YWJsZX0KIyB0aGlzIGlzIGZvciB0aGUgcHVycG9zZSBvZiBkcmF3aW5nIGp1c3QgWFBfMDI4ODg5MDMzCnRhbmRlbSAlPiUgZmlsdGVyKGdyZXBsKCJYUF8wMjg4ODkwMzMiLCBuYW1lKSkgJT4lIHdyaXRlX3RzdihmaWxlID0gIi4uLzAxLVhQXzAyODg4OTAzM19kcmF3aW5nL2lucHV0L1hQXzAyODg4OTAzM190YW5kZW1fc3ViLnRzdiIpCnRhbmRlbS5kaXYgJT4lIGZpbHRlcihncmVwbCgiWFBfMDI4ODg5MDMzIiwgbmFtZSkpICU+JSAKICB3cml0ZV90c3YoZmlsZSA9ICIuLi8wMS1YUF8wMjg4ODkwMzNfZHJhd2luZy9pbnB1dC9YUF8wMjg4ODkwMzNfdGFuZGVtX3N1Yl9kaXYudHN2IikKCiMgYWxzbyBleHBvcnQgdGhlIHN1YnNldCBiZWxvbmdpbmcgdG8gdGhlIEI4NDQxIGhvbW9sb2dzCnRhbmRlbS5kaXYgJT4lIGZpbHRlcihncmVwbCgiUElTIiwgbmFtZSkpICU+JSAKICB3cml0ZV90c3YoZmlsZSA9ICJvdXRwdXQvc2VxLWZlYXR1cmUvQjg0NDEtaG9tb2xvZ3MtdGFuZGVtX3N1Yl9kaXYudHN2IikKYGBgCgojIyMgRG9tYWluIGFyY2hpdGVjdHVyZSB7I0I4NDQxfQoKVGhlIGdvYWwgaXMgdG8gcHJvZHVjZSBhIGNhcnRvb24tbGlrZSBwbG90IGZvciBlYWNoIGhvbW9sb2cgb3V0bGluaW5nIHRoZWlyIG1haW4gZmVhdHVyZXMsIHN1Y2ggYXMgdGhlIGxvY2F0aW9ucyBvZiB0aGUgcGZhbSBkb21haW5zIChtYWlubHkgdGhlIEh5cF9yZWdfQ1dQKSwgbG9jYXRpb25zIG9mIHRoZSBzaWduYWwgcGVwdGlkZSBhbmQgR1BJLWFuY2hvciwgdHlwZXMgYW5kIGRpc3RyaWJ1dGlvbiBvZiB0YW5kZW0gcmVwZWF0cy4gTm90ZSB0aGF0IGFsbCB0aGVzZSBmZWF0dXJlcyBjYW4gYmUgcmVwcmVzZW50ZWQgYXMgYSByYW5nZSB3aXRoIGFzc29jaWF0ZWQgbWV0YWRhdGEuIFNvIHRoZSBmaXJzdCBzdGVwIGlzIHRvIGNvbGxlY3QgdGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBmZWF0dXJlcwoKb3JnYW5pemUgdGhlIG5vbi1UUiBmZWF0dXJlcwpgYGB7cn0KIyBHUEktYW5jaG9yCiMgdXNlIHByZWQuZ3BpCiMgUGZhbSBkb21haW5zCnBmYW0gPC0gcmVhZF90c3YoIm91dHB1dC9zZXEtZmVhdHVyZS9jYXVyaXMtcmVuYW1lZC1obW1lci1zY2FuLnR4dCIsIGNvbF90eXBlcyA9ICJjaWlpaWNjaWlpZGRkaWljIikKIyBzYXZlIGZlYXR1cmUgZmlsZSBmb3IgSmFsdmlldyBleGFtaW5hdGlvbgojIHBmYW0gJT4lIGZpbHRlcihncmVwbCgiWFBfMDI4ODg5MDMzIixzZXFfaWQpKSAlPiUgc2VsZWN0KGhtbV9uYW1lLCBzZXFfaWQsIGVudmVsb3BlX3N0YXJ0LCBlbnZlbG9wZV9lbmQpICU+JSBtdXRhdGUoZmVhdHVyZXR5cGUgPSAiZG9tYWluIikgJT4lIHdyaXRlX3RzdigiWFBfMDI4ODg5MDMzX2ZlYXR1cmVzLmphbHZpZXciKQojIEkgbWFudWFsbHkgZWRpdGVkIHRoZSBmZWF0dXJlIGZpbGUsIHNvIEkgY29tbWVudGVkIG91dCB0aGUgbGluZSBhYm92ZSB0byBhdm9pZCBhY2NpZGVudGFsbHkgCiMgb3ZlcndyaXRpbmcgbXkgb3duIGVkaXRzCgojIGZlYXR1cmUgc2V0CiMgc3RydWN0dXJlOiBpZCAgZmVhdHVyZSAgc3RhcnQgIGVuZApmZWF0dXJlIDwtIGJpbmRfcm93cygKICBzZXFJbmZvICU+JSBtdXRhdGUodHlwZSA9ICJlbnRpcmUgcHJvdGVpbiIsIHN0YXJ0ID0gMSkgJT4lIHNlbGVjdChuYW1lLCB0eXBlLCBzdGFydCwgZW5kID0gbGVuZ3RoKSwKICBwZmFtICU+JSBzZWxlY3QobmFtZSA9IHNlcV9pZCwgdHlwZSA9IGhtbV9uYW1lLCBzdGFydCA9IGVudmVsb3BlX3N0YXJ0LCBlbmQgPSBlbnZlbG9wZV9lbmQpICU+JSAKICAgIGZpbHRlcih0eXBlID09ICJIeXBoYWxfcmVnX0NXUCIpLAogICMgZXh0ZW5kIHRoZSBzaWduYWwgcGVwdGlkZSBzZWdtZW50IGJ5IDEwIGFtaW5vIGFjaWRzIHRvIG1ha2UgaXQgbW9yZSB2aXNpYmxlCiAgc2lnbmFscDUgJT4lIG11dGF0ZSh0eXBlID0gIlNpZ25hbFAiLCBlbmQgPSBlbmQgKyAxMCkgJT4lIHNlbGVjdChuYW1lID0gaWQsIHR5cGUsIHN0YXJ0ID0gc3RhcnQsIGVuZCksCiAgIyBleHRlbmQgdGhlIEdQSS1hbmNob3IgQy10ZXJtaW51cyBzZWdtZW50IGJ5IDIwIGFtaW5vIGFjaWRzIHRvIG1ha2UgaXQgbW9yZSB2aXNpYmxlCiAgcHJlZC5ncGkgJT4lIGZpbHRlcihpcy5ncGkpICU+JSBtdXRhdGUodHlwZSA9ICJHUEktYW5jaG9yIiwgc3RhcnQgPSBjbGVhdmVQb3MtMTApICU+JSAKICAgIHNlbGVjdChuYW1lLCB0eXBlLCBzdGFydCwgZW5kID0gbGVuZ3RoKQogICkgJT4lIGZpbHRlcighZ3JlcGwoIktORCIsIG5hbWUpKSAlPiUgIyByZW1vdmUgc3RyYWluIDY2ODQKICBtdXRhdGUodGlwID0gaWZlbHNlKHR5cGUgPT0gImVudGlyZSBwcm90ZWluIiwgYXMuY2hhcmFjdGVyKG5hbWUpLCBhcy5jaGFyYWN0ZXIodHlwZSkpKQojZmVhdHVyZSR0eXBlID0gb3JkZXJlZChmZWF0dXJlJHR5cGUsIGxldmVscyA9IGMoImVudGlyZSBwcm90ZWluIiwgIkh5cGhhbF9yZWdfQ1dQIiwgIlNpZ25hbFAiLCAiR1BJLWFuY2hvciIpKQpmZWF0dXJlLmNvbG9ycyA8LSBjKCJncmV5IiwgIiMxZjc4YjQiLCIjZTMxYTFjIiwgIiM2YTNkOWEiKQpgYGAKCm9yZ2FuaXplIHRoZSB0YW5kZW0gcmVwZWF0cyBmZWF0dXJlcwpgYGB7cn0KdHIgPC0gdGFuZGVtICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KHJlcGVhdHMsIHR5cGUsIGNvcHlNZWFuKSwgYnkgPSBjKCJ0eXBlIiA9ICJ0eXBlIikpICU+JSAKICBtdXRhdGUodHlwZSA9IHBhc3RlKCJUUiIsIHR5cGUsIHNlcCA9ICItIiksIAogICAgICAgICB0aXAgPSBwYXN0ZTAoY29uc2Vuc3VzX25vZ2FwLAogICAgICAgICAgICAgICAgICAgICAgIlxudHlwZTogIiwgdHlwZSwKICAgICAgICAgICAgICAgICAgICAgICJcbnBlcmlvZDogIiwgcGVyaW9kLCAKICAgICAgICAgICAgICAgICAgICAgICJcbmNvcHlOOiAiLCBjb3B5TWVhbikpICU+JSAKICBzZWxlY3QobmFtZSwgdHlwZSwgc3RhcnQsIGVuZCwgdGlwKQpyZXF1aXJlKFJDb2xvckJyZXdlcikKdHIuY29sIDwtIGNoYXJhY3Rlcihucm93KHJlcGVhdHMpKSAjIGNyZWF0ZSBhIGNvbG9yIHZlY3RvcgpzaG9ydC5ycCA8LSB3aGljaChyZXBlYXRzJGxlbmd0aCA8IDQwKSAjIGlkZW50aWZ5IHRoZSBzaG9ydCByZXBlYXRzIGluZGljZXMKbG9uZy5ycCA8LSBzZXRkaWZmKDE6bnJvdyhyZXBlYXRzKSwgc2hvcnQucnApICMgdGhlIGxvbmcgcmVwZWF0cyBpbmRpY2VzCnNldC5zZWVkKDEyMykgIyBmb3IgcmVwcm9kdWNpYmx5IHNodWZmbGluZyB0aGUgb3JkZXIgYmVmb3JlIGFzc2lnbmluZyB0aGUgY29sb3JzCnNob3J0LnJwIDwtIHNhbXBsZShzaG9ydC5ycCkKdHIuY29sW3Nob3J0LnJwXSA8LSBjb2xvclJhbXBQYWxldHRlKAogIGJyZXdlci5wYWwoMTIsICJQYWlyZWQiKVtzZXEoMywxMSxieT0yKV0pKGxlbmd0aChzaG9ydC5ycCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgIyBhc3NpZ24gdGhlIHNob3J0IHJlcGVhdHMgYSBsb3dlciBjb250cmFzdCBjb2xvcgpzZXQuc2VlZCgyMzEpICMgZm9yIHJlcHJvZHVjaWJseSBzaHVmZmxpbmcgdGhlIG9yZGVyIGJlZm9yZSBhc3NpZ25pbmcgdGhlIGNvbG9ycwpsb25nLnJwIDwtIHNhbXBsZShsb25nLnJwKQp0ci5jb2xbbG9uZy5ycF0gPC0gY29sb3JSYW1wUGFsZXR0ZSgKICBicmV3ZXIucGFsKDEyLCAiUGFpcmVkIilbc2VxKDQsMTIsYnk9MildKShsZW5ndGgobG9uZy5ycCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkgIyBhc3NpZ24gdGhlIGxvbmcgcmVwZWF0cyBhIGhpZ2hlciBjb250cmFzdCBjb2xvcgpyZXBlYXRzJGNvbG9yIDwtIHRyLmNvbApgYGAKCkNvbWJpbmUgZG9tYWlucywgU1AgYW5kIEdQSS1hbmNob3Igd2l0aCBUUiBmZWF0dXJlcy4KYGBge3IgdHJhbnNmb3JtX3RhbmRlbV9mZWF0dXJlX2RhdGF9CiMgY29tYmluZSBzZXF1ZW5jZSBmZWF0dXJlcyB3aXRoIHRhbmRlbSByZXBlYXRzCnRyLmZlYXR1cmUgPC0gYmluZF9yb3dzKGZlYXR1cmUsIHRyKSAlPiUgCiAgbXV0YXRlKHR5cGUgPSBvcmRlcmVkKHR5cGUsIGxldmVscyA9IHVuaXF1ZSh0eXBlKSkpCmNvbWIuY29sIDwtIGMoZmVhdHVyZS5jb2xvcnMsIHRyLmNvbCkKCiMgRXh0cmFjdCB0aGUgc3Vic2V0IGZvciBYUF8wMjg4ODkwMzMgZm9yIHBsb3R0aW5nCnRyLmZlYXR1cmUgJT4lICBzZWxlY3QoLXRpcCkgJT4lIAogIGZpbHRlcihncmVwbCgiWFBfMDI4ODg5MDMzIiwgbmFtZSkpICU+JQogIHdyaXRlX3RzdihmaWxlID0gIi4uLzAxLVhQXzAyODg4OTAzM19kcmF3aW5nL2lucHV0L1hQXzAyODg4OTAzMy1kb21haW4tZmVhdHVyZXMudHh0IikKCiMgRXh0cmFjdCB0aGUgc3Vic2V0IGZyb20gX0MuIGF1cmlzXyBCODQ0MSBmb3IgdGhlIHNjaGVtYXRpYyBwbG90IGluIHRoZSBiZWdpbm5pbmcuCkI4NDQxIDwtIHRyLmZlYXR1cmUgJT4lIAogIHNlbGVjdCgtdGlwKSAlPiUgCiAgZmlsdGVyKGdyZXBsKCJQSVMiLCBuYW1lKSkKd3JpdGVfdHN2KEI4NDQxLCBmaWxlID0gIm91dHB1dC9zZXEtZmVhdHVyZS9CODQ0MS1ob21vbG9ncy1mZWF0dXJlLXRhYmxlLnRzdiIsIGNvbF9uYW1lcyA9IFRSVUUpCmBgYAoKcmVvcmRlciB0aGUgc2VxdWVuY2VzIGJ5IHRoZWlyIHBvc2l0aW9ucyBpbiB0aGUgZ2VuZSB0cmVlCmBgYHtyfQojIGluIG9yZGVyIHRvIHBsb3QgcHJvcGVydGllcyBvZiB0aGUgc2VxdWVuY2VzIGluIGFuIG9yZGVyIHRoYXQgaXMgY29uc2lzdGVudCB3aXRoIHRoZSBzZXF1ZW5jZXMnIHBvc2l0aW9uIGluIHRoZSBnZW5lIHRyZWUKZ2VuZXRyZWVPcmRlciA8LSBzY2FuKCJpbnB1dC9jYXVyaXMtZm91ci1zdHJhaW5zLXJlb3JkZXItYnktZ2VuZS10cmVlLnR4dCIsIHdoYXQgPSAiY2hhcmFjdGVyIikKZ2VuZXRyZWVDb2xvciA8LSB0aWJibGUobmFtZSA9IGdlbmV0cmVlT3JkZXIpICU+JSAKICBtdXRhdGUoY29sb3IgPSBjYXNlX3doZW4oCiAgICBncmVwbCgiaGFlbXVsb25pIiwgbmFtZSkgfiAiIzI1OTZiZTcwIiwKICAgIGdyZXBsKCJCODQ0MSIsIG5hbWUpIH4gIiMwZThjMDciLAogICAgZ3JlcGwoIkIxMTIyMCIsIG5hbWUpIH4gIiM3ODBhNzYiLAogICAgZ3JlcGwoIkIxMTIyMSIsIG5hbWUpIH4gIiMwNDA5ZmIiLAogICAgZ3JlcGwoIkIxMTI0MyIsIG5hbWUpIH4gIiNmZjRjMDAiLAogICAgVFJVRSB+ICIjMDAwMDAwIgogICAgKSkKI2ZlYXR1cmUkbmFtZSA8LSBvcmRlcmVkKGZlYXR1cmUkbmFtZSwgbGV2ZWxzID0gcmV2KGdlbmV0cmVlT3JkZXIpKQp0ci5mZWF0dXJlJG5hbWUgPC0gb3JkZXJlZCh0ci5mZWF0dXJlJG5hbWUsIGxldmVscyA9IHJldihnZW5ldHJlZU9yZGVyKSkKd3JpdGVfdHN2KHRyLmZlYXR1cmUsIGZpbGUgPSAib3V0cHV0L3NlcS1mZWF0dXJlL1ItZmVhdHVyZS10YWJsZS50c3YiLCBjb2xfbmFtZXMgPSBUUlVFKQpgYGAKCmBgYHtyIHBsb3RseV90YW5kZW1fcmVwZWF0cywgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9OX0KIyBwbG90CnAxIDwtIGdncGxvdCh0ci5mZWF0dXJlLCBhZXMoeCA9IG5hbWUsIHkgPSBzdGFydCwgeGVuZCA9IG5hbWUsIHllbmQgPSBlbmQpKSArIAogIGdlb21fc2VnbWVudChhZXMoY29sb3IgPSB0eXBlLCB0ZXh0ID0gdGlwKSwgc2l6ZSA9IDIuNSkKcDIgPC0gZ2VvbV9zZWdtZW50KGRhdGEgPSB0YW5kZW0uZGl2LCBhZXMoeCA9IG5hbWUsIHhlbmQgPSBuYW1lLCB5ID0gZGl2LCB5ZW5kID0gZGl2ICsgMS41KSwgc2l6ZSA9IDIuNSwgY29sb3IgPSAid2hpdGUiKQpwMyA8LSBwMSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb21iLmNvbCkgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3LCBjb2xvdXIgPSByZXYoZ2VuZXRyZWVDb2xvciRjb2xvcikpLAogICAgICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYWxwaGEoImxpZ2h0Ymx1ZSIsMC41KSkpICsKICB5bGltKC0yLCA0NTAwKSArIGxhYnMoeSA9ICJQb3NpdGlvbiBpbiBzZXF1ZW5jZSIsIHggPSAiU2VxdWVuY2VzIiwgY29sb3IgPSAiRkVBVFVSRVMiKSArIAogIGdndGl0bGUoIlByb3RlaW4gc2VxdWVuY2UgZmVhdHVyZXMiKQpwMyArIHAyCmdnc2F2ZSgib3V0cHV0L2ZpZ3VyZS8yMDIxMDUyNC1kb21haW4tdGFuZGVtLXJlcGVhdHMucG5nIiwgd2lkdGggPSA3LCBoZWlnaHQgPSA2KQpgYGAKCmBgYHtyfQpEVDo6ZGF0YXRhYmxlKAogIHRhbmRlbSAlPiUgCiAgICByZW5hbWUoc2VxTCA9IHNlcUxlbmd0aCwgZXJyID0gY29uc2Vuc3VzX2Vycm9yLCBzZXEgPSBjb25zZW5zdXNfbm9nYXApICU+JSAKICAgIHNlbGVjdCgtc2VxQWxpZ24sIC10eXBlLCAtY29uc2Vuc3VzX2dhcCwgLXNlcSwgc2VxKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MobmFtZSkpLAogIGZpbGxDb250YWluZXIgPSBGQUxTRSwgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IDEwKQopCmBgYAoKYGBge3IgcGxvdF90YW5kZW1fcmVwZWF0cywgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodD05LCBmaWcud2lkdGg9OX0KIyBwbG90CnJlcXVpcmUocGxvdGx5KQpnZ3Bsb3RseShwMywgdG9vbHRpcCA9ICJ0ZXh0Iiwgd2lkdGggPSA4MDAsIGhlaWdodCA9IDcwMCkKYGBgCioqTm90ZSoqIEJsdWUgYm94ZXMgaW5kaWNhdGUgdGhlIFBGMTE3NjUgZG9tYWlucyB3aGlsZSBhbGwgb3RoZXIgbm9uLWdyZXkgYm94ZXMgaW5kaWNhdGUgWFNUUkVBTS1kZXRlcm1pbmVkIHRhbmRlbSByZXBlYXQgZG9tYWlucy4gQ29sb3JzIGFyZSB1c2VkIHRvIGdyb3VwIGhpZ2hseSBzaW1pbGFyIHRhbmRlbSByZXBlYXRzLiBUaGUgYmxhY2sgdGhpbiBsaW5lcyBkZW1hcmNhdGUgYWRqYWNlbnQgdGFuZGVtIHJlcGVhdCB1bml0cy4gVGhlIHRhYmxlIGJlbG93IHNob3dzIHRoZSBjb3B5IG51bWJlciwgcGVyaW9kIGFuZCBjb25zZW5zdXMgc2VxdWVuY2UgZm9yIGVhY2ggdGFuZGVtIGRvbWFpbiBvcmdhbml6ZWQgYnkgdGhlIGhvc3Qgc2VxdWVuY2VzLgoKIyMjIFRBTkdPIHByZWRpY3Rpb24gb2YgJFxiZXRhJC1hZ2dyZWdhdGlvbiBwcm9uZSBzZXF1ZW5jZXMKClRoZSBhbXlsb2lkLWxpa2UgJFxiZXRhJC1hZ2dyZWdhdGlvbiBwcm9uZSBzZXF1ZW5jZXMgaGF2ZSB0aGUgYWJpbGl0eSB0byBtZWRpYXRlIHNlbGYtYWdncmVnYXRpb24sIHdoaWNoIGJvb3N0cyB0aGUgbG9jYWwgY29uY2VudHJhdGlvbiBvZiB0aGUgYWRoZXNpbiBtb2xlY3VsZXMgb24gdGhlIGNlbGwtc3VyZmFjZS4gU2ltaWxhciB0byB0aGUgUy9UIGZyZXF1ZW5jeSBhYm92ZSwgd2Ugd291bGQgbGlrZSB0byB1c2UgdGhlIG91dHB1dCBmcm9tIHRoZSBwcmVkaWN0aW9uIGFsZ29yaXRobSwgVEFOR08sIHRvIHZpc3VsaXplIHRoZSBkaXN0cmlidXRpb24gb2Ygc3VjaCBzZXF1ZW5jZSBtb3RpZnMgYWxvbmcgdGhlIGxlbmd0aCBvZiB0aGUgWFBfMDI4ODg5MDMzIGhvbW9sb2cgc2VxdWVuY2VzLgoKIyMjIyBQYXJzZSB0YW5nbyBvdXRwdXQKYGBge3IgZXh0cmFjdF90YW5nb19pbmZvfQpleHRyYWN0X3RhbmdvIDwtIGZ1bmN0aW9uKHRhbmdvX291dHB1dCwgYWdnX3RocmVzaG9sZCA9IDUsIHJlcXVpcmVkX2luX3NlcmlhbCA9IDUpIHsKICAgIHJlcXVpcmUodGlkeXZlcnNlKQogICAgdG1wIDwtIHJlYWRfdHN2KGZpbGUgPSB0YW5nb19vdXRwdXQsIGNvbF90eXBlcyA9ICJpY2RkZGRkIikgJT4lIAogICAgICAgICMgYSBib29sZWFuIHZlY3RvciBmb3IgcmVzaWR1ZXMgYWJvdmUgdGhyZXNob2xkCiAgICAgICAgbXV0YXRlKHBhc3MgPSBBZ2dyZWdhdGlvbiA+IGFnZ190aHJlc2hvbGQpCiAgICBwYXNzLnJsZSA8LSBybGUodG1wJHBhc3MpICMgdGhpcyBjcmVhdGVzIGEgcnVuIGxlbmd0aCBlbmNvZGluZyB0aGF0IHdpbGwgYmUgdXNlZnVsIGZvciBpZGVudGlmeWluZyB0aGUgc3ViLXNlcXVlbmNlcyBpbiBhIHJ1biBsb25nZXIgdGhhbiBjZXJ0YWluIGxlbmd0aAogICAgIyAtLS0gRXhwbGFuYXRpb24gLS0tCiAgICAjIHRoaXMgcmxlIG9iamVjdCBpcyBhdCB0aGUgY29yZSBvZiB0aGlzIGZ1bmN0aW9uCiAgICAjIGFuIGV4YW1wbGUgb2YgdGhlIHJsZSBsb29rcyBsaWtlCiAgICAjICAgbGVuZ3RoczogaW50WzE6MTBdIDUgMTkgMjAgOCAxIDUgMTkgNiAxODEgMTgKICAgICMgICB2YWx1ZXM6IGxvZ2lbMToxMF0gRiBUICBGICBUIEYgVCBGICBUIEYgICBUCiAgICAjICAgbm90ZSB0aGF0IGJ5IGRlZmluaXRpb24gdGhlIHZhbHVlcyB3aWxsIGFsd2F5cyBiZSBUL0YgaW50ZXJkaWdpdGF0ZWQKICAgICMgb3VyIGdvYWwgaXMgdG8gaWRlbnRpZnkgdGhlIHN1Yi1zZXF1ZW5jZXMgdGhhdCBpcyBkZWZpbmVkIGFzIGEgc3RyZXRjaCBvZiAKICAgICMgbiBjb25zZWN1dGl2ZSBwb3NpdGlvbnMgd2l0aCBhIHNjb3JlIGdyZWF0ZXIgdGhhbiB0aGUgY3V0b2ZmIGFuZCByZWNvcmQgdGhlCiAgICAjIHN1Yi1zZXF1ZW5jZSwgaXRzIGxlbmd0aCwgc3RhcnQgYW5kIGVuZCBwb3NpdGlvbiwgOTAlIHF1YW50aWxlIG9mIHRoZSBzY29yZQogICAgIyAtLS0gRW5kIG9mIGV4cGxhbmF0aW9uIC0tLQogICAgIyAxLiBhc3NpZ25zIGEgdW5pcXVlIGlkIGZvciBlYWNoIHJ1biBvZiBldmVudHMKICAgIHRtcCRncm91cCA8LSByZXAoMTpsZW5ndGgocGFzcy5ybGUkbGVuZ3RocyksIHRpbWVzID0gcGFzcy5ybGUkbGVuZ3RocykKICAgICMgMi4gZXh0cmFjdCB0aGUgc3Vic2VxdWVuY2VzCiAgICBhZ2cuc2VxIDwtIHRtcCAlPiUgCiAgICAgICAgZmlsdGVyKHBhc3MpICU+JSAjIGRyb3AgcmVzaWR1ZXMgbm90IHByZWRpY3RlZCB0byBoYXZlIGFnZ3JlZ2F0aW9uIHBvdGVudGlhbAogICAgICAgIGdyb3VwX2J5KGdyb3VwKSAlPiUgIyBjbHVzdGVyIGJ5IHRoZSBydW5zCiAgICAgICAgc3VtbWFyaXplKHNlcSA9IHBhc3RlMChhYSwgY29sbGFwc2UgPSAiIiksCiAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gbWluKHJlcyksIGVuZCA9IG1heChyZXMpLCBsZW5ndGggPSBuKCksCiAgICAgICAgICAgICAgICAgIG1lZGlhbiA9IG1lZGlhbihBZ2dyZWdhdGlvbiksCiAgICAgICAgICAgICAgICAgIHE5MCA9IHF1YW50aWxlKEFnZ3JlZ2F0aW9uLCBwcm9icyA9IDAuOSksCiAgICAgICAgICAgICAgICAgIGl2dCA9IHN1bShhYSAlaW4lIGMoIkkiLCJWIiwiVCIpKSAvIGxlbmd0aChhYSksCiAgICAgICAgICAgICAgICAgIC5ncm91cHMgPSAiZHJvcCIpICU+JSAKICAgICAgICBtdXRhdGUoaW50ZXJ2YWwgPSBzdGFydCAtIGxhZyhlbmQpIC0gMSkgJT4lIAogICAgICAgIGZpbHRlcihsZW5ndGggPj0gcmVxdWlyZWRfaW5fc2VyaWFsKSAlPiUgCiAgICAgICAgc2VsZWN0KC1ncm91cCkKICAgIHJldHVybihhZ2cuc2VxKQp9CmBgYAoKYGBge3IgYXBwbHl9CnRhbmdvLm91dHB1dC5maWxlcyA8LSBsaXN0LmZpbGVzKHBhdGggPSAib3V0cHV0L3RhbmdvIiwgcGF0dGVybiA9ICIudHh0fC50eHQuZ3oiLCBmdWxsLm5hbWVzID0gVCkKIyB0aGUgcmVhZF9jc3YoKSBmdW5jdGlvbiB1c2VkIGluIHRoZSBjdXN0b20gZnVuY3Rpb24gY2FuIGF1dG9tYXRpY2FsbHkgZGVjb21wcmVzcyBnemlwcGVkIGZpbGVzCnRhbmdvLnJlcyA8LSBsYXBwbHkodGFuZ28ub3V0cHV0LmZpbGVzLCBleHRyYWN0X3RhbmdvKQpuYW1lcyh0YW5nby5yZXMpIDwtIGdzdWIoIi50eHR8LnR4dC5neiIsICIiLCBiYXNlbmFtZSh0YW5nby5vdXRwdXQuZmlsZXMpKQojIHRvIGFkZCBzcGVjaWVzIGluZm9ybWF0aW9uCnRhbmdvLnJlcy5kZiA8LSBiaW5kX3Jvd3ModGFuZ28ucmVzLCAuaWQgPSAiaWQiKSAlPiUKICBtdXRhdGUoaWQgPSBnc3ViKCJfQlswLTldKyQiLCAiIiwgaWQpKQojIHNhdmUgdGhlIHRhbmdvIG91dHB1dAp3cml0ZV90c3YodGFuZ28ucmVzLmRmLCAib3V0cHV0L3RhbmdvL3RhbmdvX3N1bW1hcnlfdGFibGUudHN2Lmd6IikKIyBtdXRhdGUoc3BlY2llcyA9IHN0cl9zcGxpdChpZCwgIl8oPyEuKl8pIiwgc2ltcGxpZnkgPSBUUlVFKVssMl0pIAojIGV4dHJhY3QgdGhlIHNwZWNpZXMgbmFtZXMKIyBjcmVkaXQ6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzIwNDU0NzY4L2hvdy10by1zcGxpdC1hLXN0cmluZy1mcm9tLXJpZ2h0LXRvLWxlZnQtbGlrZS1weXRob25zLXJzcGxpdAojIHRoZSBzcGxpdCBwYXR0ZXJuIGlzIGVxdWl2YWxlbnQgdG8gdGhlIHJzcGxpdCgpIGZ1bmN0aW9uIGluIHB5dGhvbgpgYGAKCiMjIyMgUGxvdHRpbmcgVEFOR08gaGl0cwpgYGB7ciBwbG90X3RhbmdvX3NlcXVlbmNlcywgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9OX0KIyBhZGQgc3BlY2llcyBhbmQgc3RyYWluIGluZm9ybWF0aW9uIGZvciBwbG90dGluZwp0YW5nbyA8LSBsZWZ0X2pvaW4oc2VsZWN0KHNlcUluZm8sIG5hbWUsIGlkLCBzcGVjaWVzX2lkLCBzdHJhaW4pLCAgdGFuZ28ucmVzLmRmLCBieSA9IGMoImlkIiA9ICJpZCIpKQojIHdyaXRlIHJlc3VsdHMgdG8gZmlsZSBmb3IgQjg0NDEgZm9yIHBsb3R0aW5nCnRhbmdvICU+JSBmaWx0ZXIoZ3JlcGwoIlBJUyIsIG5hbWUpKSAlPiUgd3JpdGVfdHN2KGZpbGUgPSAiLi9pbnB1dC9CODQ0MS1ob21vbG9ncy10YW5nby50c3YiKQojIHJlb3JkZXIgdGhlIHNlcXVlbmNlcyBmb3IgcGxvdHRpbmcKZmVhdHVyZTEgPC0gZmVhdHVyZSAlPiUgCiAgbXV0YXRlKG5hbWUgPSBvcmRlcmVkKG5hbWUsIGxldmVscyA9IHJldihnZW5ldHJlZU9yZGVyKSkpCnRhbmdvJG5hbWUgPC0gb3JkZXJlZCh0YW5nbyRuYW1lLCBsZXZlbHMgPSByZXYoZ2VuZXRyZWVPcmRlcikpCiMgcGxvdApwMSA8LSBnZ3Bsb3QoZmlsdGVyKGZlYXR1cmUxLCB0eXBlID09ICJlbnRpcmUgcHJvdGVpbiIpKSArIAogIGdlb21fc2VnbWVudChhZXMoeCA9IG5hbWUsIHkgPSBzdGFydCwgeGVuZCA9IG5hbWUsIHllbmQgPSBlbmQpLCBzaXplID0gMi41LCBjb2xvciA9ICJncmV5NDAiKQpwMiA8LSBnZW9tX3NlZ21lbnQoZGF0YSA9IGZpbHRlcihmZWF0dXJlMSwgdHlwZSA9PSAiSHlwaGFsX3JlZ19DV1AiKSwgYWVzKHggPSBuYW1lLCB5ID0gc3RhcnQsIHhlbmQgPSBuYW1lLCB5ZW5kID0gZW5kKSwgc2l6ZSA9IDIuNSwgY29sb3IgPSAiIzFmNzhiNCIpCnAzIDwtIGdlb21fc2VnbWVudChkYXRhID0gdGFuZ28sIGFlcyh4ID0gbmFtZSwgeGVuZCA9IG5hbWUsICB5ID0gaWZlbHNlKHN0YXJ0LTQgPj0gMCwgc3RhcnQtNCwgMCksIHllbmQgPSBlbmQgKyA0LCBjb2xvciA9IG1lZGlhbiksIHNpemUgPSAyLjUpCnAxICsgcDIgKyBwMyArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2NsYXNzaWMoKSArIAogIHNjYWxlX2NvbG9yX2Rpc3RpbGxlcih0eXBlID0gInNlcSIsIHBhbGV0dGUgPSAxNywgZGlyZWN0aW9uID0gMSkgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3LCBjb2xvdXIgPSByZXYoZ2VuZXRyZWVDb2xvciRjb2xvcikpLAogICAgICAgIGF4aXMubGluZS55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuOCwwLjgpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGFscGhhKCJsaWdodGJsdWUiLDAuNSkpKSArCiAgeWxpbSgtMiwgNDUwMCkgKyBsYWJzKHkgPSAiUG9zaXRpb24gaW4gc2VxdWVuY2UiLCB4ID0gIlNlcXVlbmNlcyIsIGNvbG9yID0gIk1lZGlhbiBUQU5HTyBzY29yZSIpICsgCiAgZ2d0aXRsZSgiVEFOR08gaGl0cyB3aXRoIEh5cGhhbF9yZWdfQ1dQIGRvbWFpbiBzaG93biBiZWhpbmQiKQpnZ3NhdmUoIm91dHB1dC9maWd1cmUvMjAyMTA1MjYtdGFuZ28tc2NvcmUtc2VnbWVudC5wbmciLCB3aWR0aCA9IDcsIGhlaWdodCA9IDYpCmBgYAoKIyMjIFNlcmluZS9UaHJlb25pbmUgZnJlcXVlbmNpZXMKClMvVCBzaXRlcyBhcmUgcG90ZW50aWFsIHNpdGVzIGZvciBPLWdseWNvc3lsYXRpb24sIHdoaWNoIGNvdWxkIGluY3JlYXNlIHRoZSByaWRpZGl0eSBvZiB0aGUgc3RhbGsgb2YgdGhlIHByb3RlaW4gYW5kIGFsbG93IHRoZSBOLXRlcm1pbmFsIGRvbWFpbiB0byBwcm90cnVkZSBvdXQgb2YgdGhlIGNlbGwgd2FsbCBmYWNpbmcgdGhlIGV4dGVyaW9yLiBNb3JlIGV2aWRlbmNlIGZvciB0aGUgaW1wb3J0YW5jZSBvZiBPLWdseWNvc3lsYXRpb24gaW4gYSBzZXJpbmUvdGhyZW9uaW5lLXJpY2ggZG9tYWluIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9lYy5hc20ub3JnL2NvbnRlbnQvMTAvMTAvMTMxNy5sb25nKS4KClRvIGRldGVybWluZSB0aGUgUy9UIGZyZXF1ZW5jeSBpbiB0aGUgWFBfMDI4ODg5MDMzIGhvbW9sb2dzLCBJIHJhbiB0aGUgcHJvZ3JhbSBgZnJlYWtgIGZyb20gdGhlIEVNQk9TUyBzdWl0ZSB3aXRoIHRoZSBwYXJhbWV0ZXJzIG9mIDEwMCBhYSBzbGlkaW5nIHdpbmRvdyBhbmQgYSBzdGVwIHNpemUgb2YgMTAgYWEuIEFmdGVyIHJlZm9ybWF0aW5nIHRoZSBvdXRwdXQsIHRoZSByZXN0IG9mIHRoZSBhbmFseXNpcyBpcyBhY2NvbXBsaXNoZWQgYmVsb3cuCgpgYGB7ciBTX1RfZnJlcX0KIyBsb2FkIGRhdGEKU1QuZnJlcSA8LSByZWFkX3Rzdigib3V0cHV0L3NlcS1mZWF0dXJlL1NUX2ZyZXFfMTAwXzEwX2ZyZWFrLm91dC5neiIsIGNvbF90eXBlcyA9ICJjaWQiKQpTLmZyZXEgPC0gcmVhZF90c3YoIm91dHB1dC9zZXEtZmVhdHVyZS9TX2ZyZXFfMTAwXzEwX2ZyZWFrLm91dC5neiIsIGNvbF90eXBlcyA9ICJjaWQiKQpULmZyZXEgPC0gcmVhZF90c3YoIm91dHB1dC9zZXEtZmVhdHVyZS9UX2ZyZXFfMTAwXzEwX2ZyZWFrLm91dC5neiIsIGNvbF90eXBlcyA9ICJjaWQiKQojIGNvbnZlcnQgc2VxdWVuY2UgbmFtZSBjb2x1bW4gdG8gYW4gb3JkZXJlZCBsaXN0IHNvcnRlZCBiYXNlZCBvbiB0aGUgZ2VuZSB0cmVlIHNlcXVlbmNlClNULmZyZXEgPC0gU1QuZnJlcSAlPiUgIG11dGF0ZShpZCA9IG9yZGVyZWQoaWQsIGxldmVscyA9IHJldihnZW5ldHJlZU9yZGVyKSkpICMgdGhpcyB3aWxsIHByb2R1Y2UgdGhlIGRlc2lyZWQgb3JkZXIKUy5mcmVxIDwtIFMuZnJlcSAlPiUgIG11dGF0ZShpZCA9IG9yZGVyZWQoaWQsIGxldmVscyA9IHJldihnZW5ldHJlZU9yZGVyKSkpICMgdGhpcyB3aWxsIHByb2R1Y2UgdGhlIGRlc2lyZWQgb3JkZXIKVC5mcmVxIDwtIFQuZnJlcSAlPiUgIG11dGF0ZShpZCA9IG9yZGVyZWQoaWQsIGxldmVscyA9IHJldihnZW5ldHJlZU9yZGVyKSkpICMgdGhpcyB3aWxsIHByb2R1Y2UgdGhlIGRlc2lyZWQgb3JkZXIKYGBgCgpgYGB7ciBwbG90X1NUX2ZyZXEsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTl9CmdncGxvdChTVC5mcmVxLCBhZXMoeCA9IGlkLCB5ID0gcG9zKSkgKyAgZ2VvbV90aWxlKGFlcyhmaWxsID0gZnJlcSkpICsKICBjb29yZF9mbGlwKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyBzY2FsZV9maWxsX2Rpc3RpbGxlcihwYWxldHRlID0gIlJkR3kiLCBsaW1pdHMgPSBjKDAsIDAuOCksIG9vYiA9IHNjYWxlczo6c3F1aXNoLCBicmVha3MgPSBzZXEoMCwgMC42LCBieSA9IDAuMikpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgY29sb3VyID0gcmV2KGdlbmV0cmVlQ29sb3IkY29sb3IpKSwKICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsMC44KSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBhbHBoYSgibGlnaHRibHVlIiwwLjUpKSkgKwogIHlsaW0oLTIsIDQ1MDApICsgbGFicyh5ID0gIlBvc2l0aW9uIGluIHNlcXVlbmNlIiwgeCA9ICJTZXF1ZW5jZXMiLCBjb2xvciA9ICJGcmVxdWVuY3kiKSArIAogIGdndGl0bGUoIlNlcmluZS9UaHJlb25pbmUgZnJlcXVlbmN5IGluIDEwMCBhYSBzbGlkaW5nIHdpbmRvd3MiKQpnZ3NhdmUoIm91dHB1dC9maWd1cmUvMjAyMTA1MzAtaG9tb2xvZ3MtU1QtZnJlcS0xMDBhYS13aW5kb3cucG5nIiwgYmcgPSAidHJhbnNwYXJlbnQiLCB3aWR0aCA9IDcsIGhlaWdodCA9IDYpCmBgYApgYGB7ciwgZmlnLndpZHRoPTEwfQpTVC5jb21iIDwtIGJpbmRfcm93cygiUy9UIiA9IFNULmZyZXEsIFMgPSBTLmZyZXEsIFQgPSBULmZyZXEsIC5pZCA9ICJWYXIiKSAlPiUgCiAgbXV0YXRlKFZhciA9IG9yZGVyZWQoVmFyLCBsZXZlbHMgPSBjKCJTL1QiLCJTIiwiVCIpKSkKZ2dwbG90KFNULmNvbWIsIGFlcyh4ID0gaWQsIHkgPSBwb3MpKSArIGdlb21fdGlsZShhZXMoZmlsbCA9IGZyZXEpKSArIAogIGZhY2V0X3dyYXAoflZhciwgc2NhbGVzID0gImZpeGVkIikgKyB0aGVtZV9taW5pbWFsKCkgKyBjb29yZF9mbGlwKCkgKyAKICBzY2FsZV9maWxsX2Rpc3RpbGxlcihwYWxldHRlID0gIlJkR3kiLCBsaW1pdHMgPSBjKC0wLjA1LCAwLjU1KSwgb29iID0gc2NhbGVzOjpzcXVpc2gsIGJyZWFrcyA9IHNlcSgwLDAuNSxieT0wLjEpKSArCiAgI3NjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICIjMWExYTFhIiwgaGlnaCA9ICIjYjMwMDAwIiwgbWlkcG9pbnQgPSAwLjIpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgY29sb3VyID0gcmV2KGdlbmV0cmVlQ29sb3IkY29sb3IpKSwKICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjk1LDAuOCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYWxwaGEoImxpZ2h0Ymx1ZSIsMC41KSkpICsKICB5bGltKDEsIDQ1MDApICsgeWxhYigiUG9zaXRpb24gaW4gc2VxdWVuY2UiKSArIHhsYWIoIlNlcXVlbmNlcyIpICsgCiAgZ2d0aXRsZSgiU2VyL1RociBmcmVxdWVuY3kgaW4gMTAwIGFhIHdpbmRvd3MgKGZyZXF1ZW5jeSA+IDAuNTUgcmVwbGFjZWQgYnkgMC41NSkiKQpnZ3NhdmUoIm91dHB1dC9maWd1cmUvMjAyMTA1MzAtU1QtZnJlcS1jb21wb3NpdGUucG5nIiwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNikKYGBgCg==