Prepare data
Get proteomes from ftp
C. auris proteome files were retrieved from NCBI ftp sites and stored in the data/proteome-fasta folder. The concatenated fasta file is stored in the same folder.
Write a fasta file
I wrote a combined fasta file using the command fwrite(x = Caurisfasta.table[, c(1,3)], file = “Cauris.txt”, sep = ", col.names = FALSE)
Using Notepad++ I changed /n to /n> then /t to /n to put in conventional fasta format. Saved as Caurisfasta.txt. There are 27278 proteins.
Note: I wrote a new fasta file to remove B11243 from the file. There are now 21772 proteins.
Update 2021-07-04 HB skipped this step as the concatenated file can be created by cat *.faa.gz > concatenated_cand_auris.faa.gz if needed
# we want to include the information about whether a protein is in our homologs list
# for that we will important the list of protein ids that were analyzed
Hil <- read_tsv("data/Hil-family-Cauris-homologs-id.txt", col_names = c("name", "strain"), col_types = "cc")
# initiate the seqInfo table
seqInfo <- read_tsv("data/Cauris-four-proteomes-seqLen.tsv", col_types = cols()) %>%
mutate(isHIL = name %in% Hil$name)
# number of Hil homologs by strain
seqInfo %>%
group_by(strain) %>%
summarize(Hil = sum(isHIL))
A total of 25 proteins in the four strains belong to the Hil family. B11221 misses Hil4 and B11245 misses Hil8. In both cases the reason is because of incomplete genome assembly rather than gene loss. B11220, the representative of clade II, indeed misses 5/8 homologs.
SignalP for signal peptides
Use SignalP 5.0 server to predict signal peptides. Maximum number of proteins is 5000, so I split the fasta file into 6 smaller files and submitted, providing my email each time. I used the old file with B11243 to run this. (HB: seems like the current result file contains B11245 instead). I resplit the new fasta into 5 files and reran. Downloaded .gff files as SignalP_(file #).gff3 and used command grep -v -h "##" SignalP* | sort > SignalP.txt
Note [HB]: SignalP output in GFF3 format only includes the input proteins that are predicted to have a signal peptide. There is a total of 1183 entried in the result file, from a total of >20,000 proteins submitted.
Modified file names, but otherwise Bin’s code:
# Signal peptide
gff.names <- c("id", "source", "name", "start", "end", "prob", "na1", "na2", "na3")
signalp5 <- read_tsv("output/SignalP.txt", comment = "#", col_names = gff.names, col_types = "ccciidccc")
# remove the column if it already exists
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)
New problem B11243 and B11245 are identical. Because B11245 is assembled to the chromosome level, I will retain it and remove B11243 from the results.
PredGPI
Following Bin’s method, I used PredGPI to predict GPI anchors. For PredGPI, the maximum number of sequences is 500. To split the file I used the command split Caurisfasta.txt -l 1000 in my Ubuntu instance, which made 55 new files. The output includes name | FPrate | most likely position and the sequence for each. GPI anchor is “highly probable” when FPrate < 0.001, “probable” when 0.001 < FPrate < 0.005, “lowly probable” when 0.005 < FPrate < 0.01. Retain only header lines with the command grep -h “>” GPIPE* > PredGPIResults.txt.
This was done using the file that contained B11243. To remove duplicate results, I used the command grep “>” PredGPIResults.txt | sort -u > PredGPIResults2.txt. Then I renamed PredGPIResults2 PredGPIResults. It has 21772 proteins.
Update 2021-07-27 [HB]
It turns out that GPI-anchored proteins can be divided into two categories: those that are retained in the plasma membrane and those that are subsequently released and then covalently linked to the cell wall components (β-1,6-glucan). The latter, named cell wall proteins (CWP) account for the majority of the GPI-anchored proteins while the former, named plasma membrane proteins (PMP) are the minority. Based on Caro et al. 1997 (PMID: 9434352), the PMPs usually have a dibasic motif prior to (within 12 residues from) the cleavage site, or ω-site. Frieman and Cormack 2004 (PMID: 15470092) further showed that an elevated Ser/Thr frequency in the body of the protein can override the dibasic motif signal. In particular, they empirically showed that a group of known PMPs with dibasic motifs all have Ser/Thr frequencies lower than 30%, while the CWPs don’t have the dibasic motifs and 28/41 (68%) have a Ser/Thr frequency > 30%.
To remove the PMPs from consideration (from all I can glean from the literature, adhesins are CWPs and not PMPs), I determined the presence of a dibasic motif (“KK/RR/KR/RK”) in the 12 residues immediately prior to the ω-site, using a custom Python script (realized later that I could have used the pred.gpi tibble and seqinr package to do the same thing right here). Below I’ll read that in and merge it into the pred.gpi table.
tmp <- read_delim("output/PredGPIResults.txt", delim = "|", col_names = c("name","fp","omega"), col_types = cols())
tmp1 <- read_tsv("output/PredGPI_dibasic.tsv", 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(tmp1, by = "name")
# remove the column if it already exists
if("pred.gpi" %in% names(seqInfo))
seqInfo <- select(seqInfo, -pred.gpi, -dibasic)
seqInfo <- left_join(seqInfo, select(pred.gpi, name, pred.gpi = is.gpi, dibasic), by = c("name"="name")) %>%
relocate(pred.gpi, dibasic, .after = signalp)
hmmscan for pfam domains
Using hmmscan to search the pfam database,the maximum allowed number of sequences is 500. I uploaded the same 55 files from PredGPI to hmmscan, providing my email address each time. HmmerWeb version 2.41.1. I resplit the new fasta into 44 files and reran. Copied and pasted results email into hmmer_results_emails.txt - checked to make sure that there were 44 and that each job id matched. Used the command grep “>” hmmer_results_emails.txt | sort > hmmer_results.txt. In Notepad++, copied and pasted header row from emails file.
This chunk will add a column that lists all non-overlapping domains found in each protein. In cases of overlap, the highest-scoring domain wins (using the outcompeted column in the data).
Update 2021-07-04 HB See HMMSCAN help page for clarification on the ’out-competed" column
In Pfam related entries are grouped into Clans, and as such can often match the same, or similar, regions on the query sequence. An additional column in the results table contains the clan accession for the family, if it belongs to a clan. Pfam employs a specific post processing on families from the same clan where the best match (determined by lowest E-value), is taken and the rest are out-competed.
hmm.names <- c("seq_id", "alignment_start", "alignment_end", "envelope_start", "envelope_end", "hmm_acc", "hmm_name", "hmm_start", "hmm_end", "hmm_length", "bit_score", "individual_e_value", "conditional_e_value", "database_significant", "outcompeted", "clan")
hmmscan_pfam <- read_table2(file = "output/hmmer_results.txt", col_names = hmm.names, col_types = "ciiiicciiidddiic", skip = 1)
df <- hmmscan_pfam %>%
filter(!outcompeted, # remove lower-scored overlapping domains
!hmm_name %in% c("Hyr1", "Candida_ALS")) %>% # remove two repeat domains
mutate(seq_id = str_sub(seq_id, 2)) %>% # remove >
group_by(seq_id) %>%
# collapse into list of pfam domains for each protein
summarise(pfam_domains = paste0(hmm_name, " (", envelope_start, "-", envelope_end, ")", collapse = ", "))
# remove the column if it already exists
if("pfam_domains" %in% names(seqInfo))
seqInfo <- select(seqInfo, -pfam_domains)
seqInfo <- left_join(seqInfo, df, by = c("name"="seq_id"))
TANGO
Created a .bat file to run tango on the condensed fasta. Used the command fwrite(x = Caurisfasta.table[, c(1,3)], file = "Cauris.txt", sep = "\t", col.names = FALSE). Command file is tango_in.bat. Ran it and compressed all results using the command gzip *.txt.
When I went to analyze I found that multiple files contained trash (columns with value -1.IO and values that didn’t match if the single line from the .bat file was rerun). Upon looking in the TANGO documentation, it says that files can’t be larger than 1000 sequences. Splitting it still induced errors, so I had Bin rerun all of the TANGO calculations and upload his error-free results to the github.
Note: Downloading and processing all of the TANGO output files takes a VERY long time. If you don’t need to regenerate the results, just import the file tango_results_df.txt as tango.res.df1. Everything after extracting the results will work off of that.
Using Bin’s tango extraction functions
require(dplyr)
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 interdigited
# 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 %>%
dplyr::filter(pass) %>% # drop residues not predicted to have aggregation potential
group_by(group) %>% # cluster by the runs
summarise(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 - dplyr::lag(end) - 1) %>%
dplyr::filter(length >= required_in_serial) %>%
select(-group)
return(agg.seq)
}
Apply to C. auris proteomes
tango.output.files <- list.files(path = "output/tango-output", pattern = ".txt|.txt.gz", full.names = TRUE)
# 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
# seqInfo <- read_tsv("raw-output/XP_028889033_homologs.tsv", comment = "#", col_types = c("ccci"))
tango.res.df <- bind_rows(tango.res, .id = "id")
# tango.res.df <- bind_rows(tango.res, .id = "id") %>%
# left_join(select(seqInfo, -length), by = c("id" = "id"))
# # save the tango output
# write_tsv(tango.res.df, "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
Top 20 TANGO hits ranked by number of occurrences in all proteins, restricted to the strong hits with a median score >= 30%.
# tango.res.df1 <- tango.res.df %>% left_join(seqInfo %>% select(name, strain), by = c("id" = "name"))
tango.res.df1 <- read_tsv("output/tango_results_df.txt.gz", col_types = cols())
# find unique motifs and count the number of proteins and strains represented
motif.summary <- tango.res.df1 %>%
left_join(select(seqInfo, id = name, isHIL)) %>%
group_by(seq) %>%
summarize(n = n(), n.HIL = sum(isHIL),
n.prot = n_distinct(id),
n.strains = n_distinct(strain),
medScore = round(mean(median),1),
IVT = round(mean(ivt),2),
avg.intv = round(mean(interval, na.rm = T),1),
mad.intv = round(mad(interval, na.rm = T),1),
.groups = "drop") %>%
arrange(desc(n))
Joining, by = "id"
motif.summary %>%
filter(round(medScore,0) >= 30) %>%
head(20)
Discussion
- Somewhat to our surprise, even in the entire C. auris proteome, the “GVVIVTT” and its variants are still the dominant TANGO motif! Are they all in the Hil family homologs?
Identify variants of “GVVIVTT”
Since this is the dominant motif in the C. auris proteome, we want to determine what percent of the TANGO sequences in the C. auris proteome belong to this class?
To design the regular expression, we looked at both the TANGO sequences that “look similar” to “GVVIVTT”. In particular, Jan manually went through the TANGO hits in C. lusitaneae, C. auris, C. haemulonis, C. pseudohaemulonis, C. duohaemulonis, S. stipitis, S. cerevisiae, and C. glabrata and summarized the following pattern: [VI][VIVM[VI][VI]T
Below we will restrict the patterns to those with a median TANGO probability above 30.
seqs <- motif.summary$seq
# core group, must be G-[VI]x4-TT
pat0 <- "G[VI]{4}TT"
# version 1, requires G-[ALVI][VI][LVI][VI]-(either end of string or at least 1 suitable residue)
# OR (G not required)-[VI]x4-(two suitable residues)
# pat1 <- "G[ALVI][VI][LVI][VI]([LVIFAWYTM]{1,2}|$)|[VI]{4}[LVIFAWYTM]{2}"
# version 2, based on Jan's manual inspection of TANGO hits in the following species:
# C. lusitaneae, C. auris, C. haemulonis, C. pseudohaemulonis, C. duohaemulonis, S. stipitis, S. cerevisiae, and C. glabrata
pat.jan <- "[VI][VIVM[VI][VI]T"
cat(paste("Identify the group of TANGO sequences most similar to 'GVVIVTT' using the pattern", pat0, sep = " "))
Identify the group of TANGO sequences most similar to ‘GVVIVTT’ using the pattern G[VI]{4}TT
match0 <- grep(pat0, seqs)
motif.summary[match0,] %>% filter(round(medScore,0) >= 30) %>% arrange(desc(n)) %>% select(seq, n, n.HIL, medScore, IVT)
cat(paste("Identify TANGO sequences with slightly more variation from 'GVVIVTT', using `", pat.jan, "`", sep = ""))
Identify TANGO sequences with slightly more variation from ‘GVVIVTT’, using [VI][VIVM[VI][VI]T
match.jan <- grep(pat.jan, seqs)
# exclude those already identified with pattern 0
motif.summary[setdiff(match.jan, match0),] %>% filter(round(medScore,0) >= 30) %>% arrange(desc(n)) %>% select(seq, n, n.HIL, medScore, IVT)
# export the list of motifs for manual inspection
motif.summary[union(match.jan, match0),] %>%
filter(round(medScore,0) >= 30) %>%
arrange(desc(n)) %>%
write_csv("output/TANGO-GVVIVTT-like-sequences.csv")
Discussion
We can see that the vast majority of GVVIVTT-like sequences are within the Hil family proteins
Which non-Hil proteins have GVVIVTT sequences?
Note that XP_028891378.1 is a partial protein entry that I have determined to be the C-termianl fragment of Hil4 in B11221. Looking closely at the sequence and the chromosomal locations of QEL63124 and its neighboring QEL63125, I found that the latter, at ~500 a.a. is the N-terminal domain of Hil1 in B11245 while QEL63124 is the remaining part of that protein. So in conclusion, **ALL “GVVIVTT” like sequences, based on Bin’s regex, are within the Hil family.
In the second table that lists GVVIVTT-like sequences that are captured by Jan’s more inclusive regex and not my strict one, there is a notable outlier, namely GVVIVT, which is both so close to GVVIVTT and yet only present in a group of nonHil sequences, including PIS58185 in B8441 and others.
I analyzed this group of sequences further – see README.md in this folder.
This protein is very interesting: it no longer has the PF11765 domain but otherwise shows a high degree of sequence similarity with the latter.
Number and spacing of TANGO hits in each protein sequence
We first summarize the motif sequences within each protein and then use that to determine the distribution of TANGO hit # and spacing in the entire proteome, with or without the Hil family.
# first count the number of tango hits with median score >= 30 hits for each protein
# motif.per.seq <- tango.res.df1 %>%
# group_by(id) %>%
# summarize(n.all = sum(round(median, 0) >= 30))
# next we will filter the tango dataset in order to recalculate the intervals
# this will result in 14 sequences to be dropped since they have 0 hits meeting
# the criteria. we will add them back by right_join() with the tibble above
motif.per.seq <- tango.res.df1 %>%
# limit to sequences with median score >= 30
filter(round(median,0) >= 30) %>%
group_by(id) %>%
# recalculate the interval since we are now limiting the hits to >= 30
mutate(interval = start - lag(end) - 1) %>%
# summarize the results at a sequence level
summarize(n.all = n(),
n.type = length(unique(seq)),
medScore = round(mean(median),1),
IVT = round(mean(ivt),2),
avg.intv = round(mean(interval, na.rm = T),1),
IQR.intv = round(IQR(interval, na.rm = T)/1.349 ,1),
# median absolute deviation is a robust measure of the scale parameter
# https://www.rdocumentation.org/packages/stats/versions/3.6.2/topics/mad
mad.intv = round(mad(interval, na.rm = T),1),
seqs = paste(unique(seq), collapse = ","),
.groups = "drop") %>%
right_join(select(seqInfo, strain, id = name, length, isHIL), by = "id") %>%
mutate(n.all = ifelse(is.na(n.all), 0, n.all), n.type = ifelse(is.na(n.type), 0, n.type)) %>%
arrange(desc(n.all), desc(mad.intv))
#motif.per.seq
Distribution of the number of TANGO hits per kilo amino acids protein across the proteome.
ggplot(motif.per.seq, aes(x = strain, y = n.all/length*1000)) +
geom_boxplot(fill = "gray70", alpha = 0.7, outlier.alpha = 0.2) + ylab("# of TANGO hits per 1000 amino acids") +
geom_point(data = filter(motif.per.seq, isHIL), aes(color = length), position = position_jitter(0.05), size = 1.5) +
scale_color_viridis_c() +
theme_cowplot()

We can see that the 8 Hil orthologs fall into two groups. Hil1-4, which are longer than 1000 amino acids, have relatively high number of TANGO hits relative to their length. In fact, they are all above 89% percentile of the data.
Compare the distribution of TANGO hits # and score in the Hil family vs the proteome
ggplot(motif.per.seq, aes(x = length, y = n.all/length*1000)) +
geom_bin_2d(binwidth = c(200, 2)) + scale_fill_viridis_c() +
geom_point(data = filter(motif.per.seq, isHIL), color = "red") +
xlab("Protein length") + ylab("# of TANGO hits per 1000 amino acids") +
facet_wrap(~strain, nrow = 2) + theme_grey(base_size = 14)

Discussion
- this is another way of plotting the same data, again showing that Hil1-4 are exceptional in the proteome in that they harbor a very high amount of TANGO hits per 1000 amino acid residues relative to proteins of similar length to them.
Next we add the TANGO information to the seqInfo dataset.
if("n.tango" %in% names(seqInfo)){
seqInfo <- seqInfo %>%
select(-n.tango, -reg.spaced)
}
seqInfo <- seqInfo %>%
left_join(select(motif.per.seq, name = id, n.tango = n.all, mad.intv), by = "name") %>%
mutate(mad.intv = ifelse(n.tango > 2, mad.intv, NA),
reg.spaced = ifelse(n.tango > 3 & mad.intv < 5, TRUE, FALSE)) %>%
select(-mad.intv)
Summarize tango results for table
Three metrics for the by protein tango results can be number of pat0 (GVVIVTT) sequences, pat1 (GVVIVTT-like) sequences, and total number of aggregation sequences with score > 30
Update 2021-07-15 [HB] The code below is no longer included because the above analysese have shown that GVVIVTT and its variants are highly specific to the Hil family, which appears to be an outlier in terms of TANGO hits per protein in the entire proteome. In predicting additional adhesins, we will only look at the total number of TANGO hits.
# core group, must be G-[VI]x4-TT
pat0 <- "G[VI]{4}TT"
# version 1, requires G-[ALVI][VI][LVI][VI]-(either end of string or at least 1 suitable residue)
# OR (G not required)-[VI]x4-(two suitable residues)
pat1 <- "G[ALVI][VI][LVI][VI]([LVIFAWYTM]{1,2}|$)|[VI]{4}[LVIFAWYTM]{2}"
pat2 <- "[VI][VIVM][VI][VI]T"
match0 <- grep(pat0, motif.per.seq$seq)
match1 <- grep(pat1, motif.per.seq$seq)
match2 <- grep(pat2, motif.per.seq$seq)
tango.summ <- seqInfo[,"name"] %>%
# add pat0 results
left_join(motif.per.seq[match0,] %>% group_by(id) %>% summarise(n.gvvivtt.seqs = sum(n)), by = c("name" = "id")) %>%
# add pat1 results
left_join(motif.per.seq[setdiff(match1, match0),] %>% group_by(id) %>% summarise(n.gvvivtt.like.seqs = sum(n)), by = c("name" = "id")) %>%
# add pat2 results - pat2 from Fassler manual curation of TANGO positive sequences from FungalRV positive proteins in C. lusitaneae, C. auris, C. haemulonis, C. pseudohaemulonis, C. duohaemulonis, S. stipitis, S. cerevisiae, and C. glabrata into GVVIVTT-like and non GVVIVTT groups
left_join(motif.per.seq[match2,] %>% group_by(id) %>% summarise(n.vvvvt.seqs = sum(n)), by = c("name" = "id")) %>%
# add motif.per.seq results
left_join(motif.per.seq %>% group_by(id) %>% summarise(n.high.score.agg.seq = sum(n)), by = c("name" = "id"))
# join to seqInfo table
# remove the column if it already exists
if("n.gvvivtt.seqs" %in% names(seqInfo))
seqInfo <- select(seqInfo, -n.gvvivtt.seqs, -n.gvvivtt.like.seqs, -n.vvvvt.seqs, -n.high.score.agg.seq)
seqInfo <- left_join(seqInfo, tango.summ)
seqInfo <- seqInfo %>% mutate(n.gvvivtt.seqs = replace_na(n.gvvivtt.seqs,0), n.gvvivtt.like.seqs = replace_na(n.gvvivtt.like.seqs,0), n.vvvvt.seqs = replace_na(n.vvvvt.seqs,0), n.high.score.agg.seq = replace_na(n.high.score.agg.seq,0))
S/T frequency
Using Bin’s method, I’m running EMBOSS freak for S/T, S, T with a stepping value of 10 and an averaging window of 100. The results were saved as freak_aminoacid(s)_100_10.txt. Using Bin’s format_freaq_output.py script, each was converted to a readable .out file and all files were compressed for storage.
Update 2021-07-16 [HB] we will use two types of statistics to summarize the serine/threonine frequencies here. 1) frequency of the residues over the entire protein; 2) maximum frequency of serine or threnonine in a 100 amino acid sliding window (which will ignore any proteins < 100 residues). in the second measure, we reason that a 100 amino acid window is a reasonable size to capture a genuine “hike” in Serine or Threonine frequency. For one thing, it is large enough to avoid capturing just a small cluster of S/T, and for another thing the Serine rich cluster we observe in Hil1 is ~200 amino acids long and with a consistently elevated Serine content, suggesting that a 100 amino acid window is not too large to lead to diluted signals by flanking residues.
# load data
ST.protein <- read_tsv("output/ST-freq/Cauris-ST-freq-per-protein.txt.gz", col_types = cols())
ST.freq <- read_tsv("output/ST-freq/freak_st_100_10_freak.out.gz", col_types = "cid")
S.freq <- read_tsv("output/ST-freq/freak_s_100_10_freak.out.gz", col_types = "cid")
T.freq <- read_tsv("output/ST-freq/freak_t_100_10_freak.out.gz", col_types = "cid")
ST.window <- bind_rows("ST" = ST.freq, "S" = S.freq, "T" = T.freq, .id = "residue") %>%
group_by(id, residue) %>%
summarize(max = max(freq))
`summarise()` has grouped output by 'id'. You can override using the `.groups` argument.
rm(list = c("ST.freq", "S.freq", "T.freq"))
ST.window %>%
left_join(select(seqInfo, id = name, isHIL), by = "id") %>%
mutate(residue = factor(residue, levels = c("ST", "S", "T"), labels = c("Ser/Thr", "Ser", "Thr")),
`Hil family` = ifelse(isHIL, "Yes", "No")) %>%
ggplot(aes(x = max)) + geom_histogram(binwidth = 0.02) +
xlab("Max frequency of Ser/Thr in 100 amino acid window") + scale_y_continuous(position = "right") +
facet_grid(`Hil family` ~ residue, scales = "free_y", labeller = "label_both", switch = "y") +
theme_cowplot() + panel_border()

Discussion
From the above we can see that the not all Hil family proteins have well-above-average Serine or Threonine content alone. But when both residues are counted together, they consistently rank above the majority of the proteome.
ST.protein %>%
left_join(select(seqInfo, ID = name, isHIL), by = "ID") %>%
mutate(`Ser/Thr` = (Ser+Thr)/length, Ser = Ser/length, Thr = Thr/length) %>%
pivot_longer(cols = c(`Ser/Thr`, Ser, Thr), names_to = "residue", values_to = "value") %>%
mutate(residue = factor(residue, levels = c("Ser/Thr", "Ser", "Thr")),
`Hil family` = ifelse(isHIL, "Yes", "No")) %>%
ggplot(aes(x = value)) + geom_histogram(binwidth = 0.02) +
xlab("Frequency of Ser/Thr in the whole protein") + scale_y_continuous(position = "right") +
facet_grid(`Hil family` ~ residue, scales = "free_y", labeller = "label_both", switch = "y") +
theme_cowplot() + panel_border()

Discussion
Similar as above, we see that the combined Ser/Thr frequency appear to better distinguish the Hil family from the rest of the proteins. For this reason let’s add the max S/T frequency in 100 amino acid windows and the overall S/T frequency per protein to seqInfo
#remove columns if present
if("ST.prot" %in% names(seqInfo))
seqInfo <- select(seqInfo, -ST.prot, -ST.window.max)
#join maximums back into seqInfo
tmp <- ST.protein %>%
mutate(ST.prot = round((Ser+Thr)/length, 3)) %>%
select(name = ID, ST.prot) %>%
left_join(ST.window %>% filter(residue == "ST") %>% select(name = id, ST.window.max = max), by = "name") %>%
# for proteins shorter than 100 a.a., the sliding window estimate would be NA. replace it with whole protein estimate in ST.protein
mutate(ST.window.max = round(coalesce(ST.window.max, ST.prot),3))
seqInfo <- seqInfo %>% left_join(tmp, by = "name")
# rm(list = c("ST.protein", "ST.window"))
Write the seqInfo to a file to be included as supplementary data
seqInfo %>%
select(-pfam_domains, pfam_domains) %>%
write_tsv(file = "output/Rmd-out/seqInfo_table_all.tsv")
Prediction
Here we try to use the sequence properties collected above to identify additional proteins outside of the Hil family that may function as adhesins. The idea here is to apply filters in a step-wise manner and watch if all Hil proteins are still retained and how many non-Hil proteins remain in the dataset.
Cell wall proteins
How many proteins are likely to be GPI-anchored cell wall proteins?
# Load function
# reference: http://rstudio-pubs-static.s3.amazonaws.com/6975_c4943349b6174f448104a5513fed59a9.html
source("http://pcwww.liv.ac.uk/~william/R/crosstab.r")
crosstab(seqInfo, row.vars = "signalp", col.vars = "pred.gpi", type = c("f", "t"), dec.places = 1, addmargins = FALSE)
Count Total %
pred.gpi FALSE TRUE FALSE TRUE
signalp
FALSE 20459.0 130.0 94.0 0.6
TRUE 861.0 322.0 4.0 1.5
We see that only a very small fraction (1.5%) of the proteome pass both the SignalP and PredGPI tests. By comparison, all eight C. auris Hil proteins pass both tests, and the vast majority of Hil homologs pass both tests as well. So far this is the most stringent (aka effective) filter to reduce the number of candidate proteins.
Update 2021-07-27 [HB] Following the discussion on GPI-CWP vs GPI-PMP (see notes in the PredGPI section above), we will additionally test whether proteins with Signal Peptide and GPI-anchor also have low (<30%) Ser/Thr frequency and the presence of a dibasic motif
filter1 <- seqInfo %>%
mutate(`Hil_family` = ifelse(isHIL, "Yes", "No"),
`GPI` = ifelse(signalp & pred.gpi, ifelse(ST.prot < 0.3 & !is.na(dibasic), "PMP", "CWP"), 'No'),
`GPI` = factor(GPI, levels = c("No", "CWP", "PMP"))) %>%
select(-signalp, -pred.gpi, -isHIL)
crosstab(filter1, row.vars = "GPI", col.vars = "Hil_family", addmargins = FALSE)
Hil_family No Yes
GPI
No 21448 2
CWP 273 23
PMP 26 0
The two proteins that dropped out
are both in the clade IV strain B11245 and appear to be missing the C-terminal sequence, hence failed the PredGPI test.
And the PMPs are shown below
Protein length
Below we show the distribution of protein length in the proteome.
p <- ggplot(data = seqInfo) +
geom_histogram(mapping = aes(x=length), binwidth = 50)+
geom_vline(aes(xintercept = 500), color="blue", size=1) +
annotate("text", x = 3000, y = 1500, label = paste0("# of proteins >= 500 residues: ", sum(seqInfo$length >= 500)), size = 5) +
xlab("Protein length (amino acids)") + ylab("# of proteins") + theme_cowplot()
print(p)

We classify the CWP hits into two groups based on their length. Those with more than 500 a.a. are labeled as “CWP long” and those smaller than 500 a.a. as “CWP short”.
filter2 <- filter1 %>%
mutate(Len = ifelse(length >= 500, ">=500", "<500"),
# group1 is the old definition
# group1 = ifelse(Hil_family == "Yes", # group 1: Hil family
# "Hil", ifelse(GPI != "No", # group 2&3: cell wall long / short
# ifelse(length >=500, "CWP long", "CWP short"),
# "Others")), # group 4: Others
# group1 = factor(group1, levels = c("Hil", "CWP long", "CWP short", "Others")),
# group is the new definition
GPI = as.character(GPI), # necessary for the case_when() statements
group = case_when(
Hil_family == "Yes" ~ "Hil",
GPI == "CWP" & length >= 500 ~ "CWP long",
GPI == "CWP" & length < 500 ~ "CWP short",
GPI == "PMP" ~ "PMP",
GPI == "No" ~ "Others",
),
group = factor(group, levels = c("Hil", "CWP long", "CWP short", "PMP", "Others")))
crosstab(filter2, row.vars = "group")
group Count Total %
Hil 25.00 0.11
CWP long 63.00 0.29
CWP short 210.00 0.96
PMP 26.00 0.12
Others 21448.00 98.51
Sum 21772.00 100.00
Ser/Thr frequency
seqInfo %>%
pivot_longer(cols = starts_with("ST."), names_to = "type", names_prefix = "ST.", values_to = "value") %>%
mutate(type = factor(type, levels = c("prot", "window.max"), labels = c("whole protein", "max in 100 a.a. windows"))) %>%
ggplot(aes(x = value, color = isHIL)) + stat_ecdf() + facet_wrap(~type) +
scale_x_continuous(limits = c(0,0.8)) + scale_color_manual("Hil family", values = c("black", "gold3")) +
xlab("Ser+Thr frequency") + ylab("Cumulative probability") +
theme_cowplot() + background_grid()
Warning: Removed 4 rows containing non-finite values (stat_ecdf).

p <- filter2 %>%
pivot_longer(cols = starts_with("ST."), names_to = "type", names_prefix = "ST.", values_to = "value") %>%
mutate(type = factor(type, levels = c("prot", "window.max"), labels = c("whole protein", "max in 100 a.a. window"))) %>%
ggplot(aes(x = type, y = value, fill = group)) + geom_boxplot(outlier.size = 0.5, outlier.shape = 1) +
scale_fill_viridis_d() + xlab("") + ylab("Ser/Thr frequency") + theme_cowplot()
p
ggsave(file = "output/figure/20210721-ST-boxplot-compare-cwp-to-rest.png", plot = p + theme(legend.position = "bottom"), width = 5, height = 4.5)

Seems like the two measures behave very similarly. Let’s see how they compare by applying the above cutoffs.
ST.th = c("ST.protein" = 0.15, "ST.window" = 0.25)
cat("Thresholds for whole protein or sliding window frequencies of Ser/Thr")
Thresholds for whole protein or sliding window frequencies of Ser/Thr
print(ST.th)
ST.protein ST.window
0.15 0.25
filter2 %>%
mutate(`S/T protein` = ST.prot > ST.th["ST.protein"],
`S/T max window` = ST.window.max > ST.th["ST.window"]) %>%
crosstab(row.vars = c("S/T protein", "S/T max window"), col.vars = "group", addmargins = FALSE)
group Hil CWP long CWP short PMP Others
S/T protein S/T max window
FALSE FALSE 0 0 44 6 14054
TRUE 0 0 0 0 463
TRUE FALSE 0 4 21 4 3835
TRUE 25 59 145 16 3096
Based on the above, we will apply a third filter of S/T frequency in the whole protein > 15%, which is roughly the lower cutoff for the group of CWPs in the Caro et al. 1997 paper.
# ref: https://stackoverflow.com/questions/34096162/dplyr-mutate-replace-several-columns-on-a-subset-of-rows
mutate_cond <- function(.data, condition, ..., envir = parent.frame()) {
condition <- eval(substitute(condition), .data, envir)
.data[condition, ] <- .data[condition, ] %>% mutate(...)
.data
}
filter3 <- filter2 %>%
mutate(`S/T protein` = ST.prot > 0.15) %>%
mutate_cond(str_sub(group,1,3) == "CWP" & !`S/T protein`, group = "Others") %>%
select(-Len, -`S/T protein`)
cat("Genes removed due to the S/T cutoff")
Genes removed due to the S/T cutoff
filter2 %>% filter(group %in% c("CWP long", "CWP short"), ST.prot <= 0.15)
We can see that all the proteins that fall out are within the “CWP short” category, which are less likely to function as adhesins to begin with. Thus this cutoff could help reduce the number of proteins we have to manually look at without losing many potential hits.
After this step we have a total of 229 proteins left.
TANGO hits
p <- filter3 %>%
ggplot(aes(x = n.tango, fill = group)) + geom_histogram(binwidth = 1) +
facet_wrap(~group, nrow = 5, scales = "free_y") +
scale_y_continuous(n.breaks = 3) +
scale_fill_viridis_d() +
xlab("# of strong TANGO hits") + theme_cowplot() + panel_border()
p
ggsave("output/figure/20210721-tango-hits-distribution-compare.png", plot = p, width = 6, height = 4.5)

As we already showed before, the number and spacing of strong TANGO hits is a divisive feature that separate the Hil family proteins in C. auris into two groups – those that are longer than 1000 a.a. have a lot of them and have them regularly spaced, while the four shorter members have few. We see a similar picture when we look at the candidate adhesin proteins in our analysis up to this point: the cell-wall protein long group showed above average number of TANGO hits while the short ones have very few. The PMPs, despite most of them being shorter than 500 amino acids, actually have relatively high number of TANGO hits.
Tandem repeats
We didn’t want to perform the tandem repeat analysis on >20,000 proteins. Now that we have narrowed the list down to a much more manageable one, the code below will perform XSTREAM analysis on the group of candidate proteins identified above.
- Export the protein IDs
cat(filter3 %>% filter(str_sub(group, 1, 3) == "CWP") %>% pull(name), file = "data/20210718-cwp-proteins-id.txt", sep = "\n")
- Extract the fasta, run the following code at the command line
/Users/bhe2/sw/miniconda3/bin/python script/extract_fasta_gz.py data/proteome-fasta/Caurisfasta.faa.gz data/20210718-cwp-proteins-id.txt data/20210718-cwp-proteins.faa
- Execute the xstream program
cd script
sh xstream.sh ../data/20210718-cwp-proteins.faa cwp-proteins ../output/tandem-repeats
cd ..
- Import the xstream results
repeats <- read_tsv("output/tandem-repeats/XSTREAM_cwp-proteins_i0.7_g3_m5_L15_chart.tsv", col_types = cols())
Cluster by similarity
Now that we settled on the “CWP long” and “CWP short” lists, we would like to visualize their domain architecture. Since we started with four proteomes, with the goal of capturing a “species-wide” set of candidates, we have presumably four alleles of each protein (may be fewer) in the list. To make it easier to examine the domain features, let’s cluster the proteins and assemble a representative list.
Submit the fasta to CD-hit webserver.
Reformat the CD-hit output
/Users/bhe2/sw/miniconda3/bin/python script/format_cd-hit_output.py output/cd-hit/20210727-CD-hit-0.85/1627438838.fas.1.clstr.sorted output/cd-hit/formatted-cd-hit-0.85.tsv
/Users/bhe2/sw/miniconda3/bin/python script/format_cd-hit_output.py output/cd-hit/20210727-CD-hit-0.6/1627439988.fas.1.clstr.sorted output/cd-hit/formatted-cd-hit-0.6.tsv
cdhit.lo <- read_tsv("output/cd-hit/formatted-cd-hit-0.6.tsv", col_types = "ccc") %>%
group_by(cluster) %>%
mutate(leader = id[which(identity == "*")], # assign the representative protein ID to new variable "leader"
identity = ifelse(identity == "*", 100, as.numeric(str_sub(identity, 1, -2)))) %>% # extract percent identity
ungroup()
cdhit.hi <- read_tsv("output/cd-hit/formatted-cd-hit-0.85.tsv", col_types = "ccc") %>%
group_by(cluster) %>%
mutate(leader = id[which(identity == "*")], # assign the representative protein ID to new variable "leader"
identity = ifelse(identity == "*", 100, as.numeric(str_sub(identity, 1, -2)))) %>% # extract percent identity
ungroup()
cdhit <- full_join(cdhit.hi, cdhit.lo, by = "id", suffix = c(".hi", ".lo")) %>%
mutate(agree = leader.hi == leader.lo) %>%
select(id, everything()) %>% arrange(cluster.lo)
rm(list = c("cdhit.lo", "cdhit.hi"))
Disagreement between the two clustering results:
cdhit %>% group_by(cluster.lo) %>% filter(length(unique(cluster.hi)) > 1, leader.hi == id) %>% ungroup()
To determine if the extra clusters identified with the 85% threshold is real, I used blastp (ncbi server) to align each of the additional leader sequence to the shared leader sequence identified with the 60% threshold. When necessary, I also checked the protein’s chromosomal location to determine if they indeed come from different loci.
Table. Determine the orthology of the cluster leaders using the two thresholds
| PIS51179.1 |
PIS54714.1 |
83% |
70% |
91 |
82 |
chr1 |
chr7 |
different |
both in B8441 |
| PIS48171.1 |
PIS48170.1 |
100% |
67% |
176 |
166 |
chr6:40562-41092 |
chr6:39307-39807 |
different |
tandem duplicates |
| PIS48171.1 |
PIS48172.1 |
100% |
66% |
176 |
173 |
chr6:40562-41092 |
chr6:41619-42140 |
different |
tandem duplicates |
| PIS54802.1 |
QEL63474.1 |
100% |
93% |
861 |
834 |
chr7:767294-769879 |
chr7:760044-760968,761039-762618 |
orthologs |
B8441 and B11245 |
| PIS56912.1 |
QEO20379.1 |
NA |
NA |
765 |
747 |
chr3,scaffold5:864995-867292 |
chr1:2549461-2551704 |
likely orthologs |
B8441 and B11220 |
| XP_028890844.1 |
QEO21242.1 |
100% |
85% |
790 |
755 |
chr1:3100225-3102597 |
chr2:1361822-1364089 |
likely orthologs |
B11221 and B11220 1 |
| QEL58520.1 |
PIS51941.1 |
97% |
88% |
457 |
440 |
chr1 |
chr1,scaffold1 |
orthologs |
B11245 and B8441 |
| PIS58185.1 |
QEO22553.1 |
100% |
94% |
2608 |
970 |
chr2 |
chr3 |
orthologs |
B8441 and B11220 1 |
1 According to Muñoz et al. 2021, there is a large scale translocation between chromosome 1 and 2 in the clade II strains and the chromosome 1 location for XP_028890844 is within the translocated region and matches the coordinates of QEO21242 in the translocated region in its chromosome 2.
3. Based on the results above, we will manually update the cdhit table
In addition to the changes mentioned in the table above, I also manually merged QEO60526 into the PIS58185 cluster (see README.md in this folder for the rationale); I merged QEO21241 from B11220 to the PIS51941 cluster. My goal here is to manually check the single gene clusters and determine if they actually belong to an existing cluster. All three remaining single gene clusters cannot be merged to any existing cluster, because their orthologs (by BLASTP) are either missing the signal peptide and/or GPI-anchor.
Lastly, CD-hit by default chooses the longest protein in a cluster as the representative. I manually changed the representative (aka leader) sequence to the B8441 protein if one exists. This way the final list will be mostly represented by sequences from a single strain (with some exceptions).
- Then load the updated table and merge the information to produce the final candidate table.Only the leaders (longest representative in each cluster) are shown below.
cdhit1 <- read_tsv("output/cd-hit/20210727-cdhit-cluster-manually-edited.tsv", col_types = cols()) %>%
left_join(select(seqInfo, id = name, length), by = "id") %>%
select(-ends_with(c(".hi",".lo"))) %>%
group_by(leader) %>%
mutate(leader.len = max(length), n = n()) %>%
ungroup()
cdhit1 <- cdhit1 %>%
filter(is.leader) %>%
select(leader, leader.len) %>%
arrange(desc(leader.len)) %>%
mutate(cluster = seq_along(leader)) %>%
right_join(cdhit1, by = c("leader", "leader.len")) %>%
select(cluster, n, leader, leader.len, id, length, is.leader)
- We will merge the cluster information with other sequence features
# calculate the per sequence repeat content and add to the candidates list
tmp <- repeats %>%
mutate(len = end - start + 1) %>%
group_by(identifier) %>%
summarize(perc = round(sum(len/seqLength),3)) %>%
rename(name = identifier, repeats = perc)
candidates <- filter3 %>%
filter(str_sub(group,1,3) == "CWP") %>%
rename(ST.win = ST.window.max) %>%
left_join(tmp, by = "name") %>%
replace_na(list(repeats = 0)) %>%
left_join(select(cdhit1, name = id, cluster, cluster.size = n, is.leader), by = "name") %>%
select(-Hil_family) %>%
arrange(cluster)
- Count the number of leaders in each group
candidates %>% filter(is.leader) %>% count(group)
- Show their sequence features for the CWP long and CWP short groups separately
cwp.long <- candidates %>% filter(is.leader, group == "CWP long") %>% select(-group, -is.leader, -pfam_domains, pfam_domains)
cwp.short <- candidates %>% filter(is.leader, group == "CWP short") %>% select(-group, -is.leader, -pfam_domains, pfam_domains)
cat("CWP long")
CWP long
cwp.long
cat("CWP short")
CWP short
cwp.short
Discussion
In the first table above, cluster 1 along with XP_028893057, which is not in the candidates list because it misses the C-terminal GPI-anchor sequence (this is a partial mRNA missing the 3’ portion), are the only ones containing the “GVVIVT” sequence (see README.md in this folder). They all have the GLEYA domain in the N-terminus, and had very similar central domain repeat units as the Hil1/2 protein.
Rows 2, 3 and 4 all have the Candida_ALS_N domain, and they are the ALS family members.
Examining the N-terminal Pfam domains among the rest candidate revealed Flo11, Asp, PLA2_B, CFEM, Glyco_hydro_72 and X8. Many of these domains have connections to adhesion.
Write the candidates info to files
candidates %>%
filter(is.leader) %>%
select(-is.leader, -pfam_domains, pfam_domains) %>%
relocate(group, .after = name) %>%
write_tsv(file = "output/Rmd-out/20210729-candidate-leaders-seqinfo.tsv")
Schematic plot for leaders
The goal is to create a domain schematic plot for all the leader proteins. The desired plot will include the following features: SignalP, GPI-anchor, any pfam domain (except for the Hyr1, Flocculin_t3 and Candida_ALS repeat domains), tandem repeats as identified by xstream, and the plot should be ordered by protein length from large to small.
Update 2021-07-20 [HB] I decide to remove the clusters whose leader protein length is less than 195 a.a. This helps to shorten the list, making the plot more readable.
# get the ids to plot
id.to.plot <- candidates %>% filter(is.leader, length >= 195) %>% pull(name)
# we will be building the plot in layers: 1) whole protein (grey); 2) tandem repeats; 3) pfam domains; 4) signalp and pred.gpi; 5) if possible, tango hits
# the relevant data can be assembled separately
df.whole <- candidates %>%
filter(name %in% id.to.plot) %>%
mutate(start = 1, end = length, feature = "whole protein",
name = ordered(name, levels = rev(id.to.plot))) %>%
select(name, feature, start, end, group)
df.repeats <- repeats %>%
mutate(feature = paste("TR", type, "-")) %>%
select(name = identifier, feature, start, end) %>%
filter(name %in% id.to.plot) %>%
left_join(select(df.whole, name, group), by = "name")
df.pfam <- hmmscan_pfam %>%
filter(!outcompeted, # remove lower-scored overlapping domains
!hmm_name %in% c("Hyr1", "Candida_ALS")) %>% # remove two repeat domains , "Flocculin_t3"
mutate(name = str_sub(seq_id, 2), # remove > from seq.id
feature = paste0(hmm_name, " (", gsub("\\.[0-9]", "", hmm_acc), ")")) %>% # feature name
filter(name %in% id.to.plot) %>%
left_join(select(df.whole, name, group), by = "name") %>%
select(name, feature, start = envelope_start, end = envelope_end, group)
df.signalp <- signalp5 %>%
filter(id %in% id.to.plot) %>%
mutate(feature = "SignalP") %>%
select(name = id, start, end) %>%
left_join(select(df.whole, name, group), by = "name")
df.gpi <- pred.gpi %>%
filter(name %in% id.to.plot, is.gpi) %>%
mutate(feature = "GPI-anchor") %>%
left_join(select(df.whole, name, group, end), by = "name") %>%
select(name, feature, start = cleavePos, end, group)
df.tango <- tango.res.df1 %>%
filter(id %in% id.to.plot) %>%
mutate(feature = "tango") %>%
select(name = id, feature, start, end, median, seq) %>%
left_join(select(df.whole, name, group), by = "name")
Build the plot
# protein backbone
p0 <- ggplot(df.whole, aes(x = name, y = start, xend = name, yend = end)) +
geom_hline(yintercept = 500, color = "grey80", size = 0.2) + # add a visual divider to distinguish between long and short
geom_segment(color = "grey80", size = 2)
# tandem repeats
p1 <- geom_segment(data = df.repeats, aes(size = "Tandem Repeats"), color = "orange4", alpha = 0.5)
# pfam
require(RColorBrewer)
feature.col <- c(brewer.pal(12, "Paired")[c(9,2,4,3,5,7,11,8)], brewer.pal(8, "Dark2")[c(2,8,3,4,6)],"brown3", "navyblue", "skyblue")
#(length(unique(df.pfam$feature))) # define the colors
p2 <- geom_segment(data = df.pfam, aes(color = feature), size = 2)
# signalp and gpi
p3 <- geom_segment(data = df.signalp, aes(size = "SignalP"), color = "#e31a1c")
p4 <- geom_segment(data = df.gpi, aes(size = "GPI-anchor"), color = "#6a3d9a")
# tango
p5 <- geom_segment(data = df.tango, aes(y = start, yend = end + 1, alpha = median),
position = position_nudge(x = -0.42, y = 0), color = "darkred", size = .8)
# plot
p0 + p1 + p2 + p3 + p4 + p5 + coord_flip() +
#facet_wrap(~group, scales = "free_y") +
scale_color_manual(values = c(feature.col)) +
scale_size_manual(
"Other features", values=rep(2,3),
guide=guide_legend(override.aes = list(colour=c("#6a3d9a", "#e31a1c", alpha("orange4",.5))))
) +
guides(alpha = "none") +
scale_y_continuous(breaks = seq(0,2500,500), expand = expansion(mult = 0.02)) +
theme_classic(base_size = 12) + background_grid(major = "x") +
theme(axis.text.y = element_text(size = 5), axis.title.y = element_blank(),
axis.line.y = element_blank(),# axis.ticks.y = element_blank(),
#axis.line.x = element_blank(),# axis.ticks.x = element_blank(),
legend.position = c(0.65, 0.45), legend.box = "horizontal",
panel.background = element_rect(fill = alpha("lightblue",0.1))) +
labs(y = "Position in sequence", x = "Sequences", color = "Pfam domains")

ggsave("output/figure/20210720-cwp-candidates-domain-schematic.png", width = 7.2, height = 5.4)
LS0tCnRpdGxlOiAiX0MuIGF1cmlzXyBhZGhlc2luIHByZWRpY3Rpb24gYmFzZWQgb24gSGlsIGZhbWlseSBwcm9wZXJ0aWVzIgphdXRob3I6ICJSYWNoZWwgU21vYWssIG1vZGlmaWVkIGJ5IEJpbiBIZSIKZGF0ZTogIjEvMjEvMjAyMSBVcGRhdGVkIGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogZGVmYXVsdAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZmlnX2FzcDogMQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCgpsaWJyYXJ5KFJTUUxpdGUpCmxpYnJhcnkoc2VxaW5yKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHN0cmluZ3IpCiN3b3JraW5nX2RpcmVjdG9yeSA9ICJDOi9Vc2Vycy9SYWNoZWwvT25lRHJpdmUgLSBVbml2ZXJzaXR5IG9mIElvd2EvRmFsbCAyMDE5L0Jpb2luZm9ybWF0aWNzL1Byb2plY3Qgd29yay9QYXBlci9BZGhlc2luX0FuYWx5c2lzIgpgYGAKCiMgUHJlcGFyZSBkYXRhCgojIyBHZXQgcHJvdGVvbWVzIGZyb20gZnRwCgoqQy4gYXVyaXMqIHByb3Rlb21lIGZpbGVzIHdlcmUgcmV0cmlldmVkIGZyb20gTkNCSSBmdHAgc2l0ZXMgYW5kIHN0b3JlZCBpbiB0aGUgYGRhdGEvcHJvdGVvbWUtZmFzdGFgIGZvbGRlci4gVGhlIGNvbmNhdGVuYXRlZCBmYXN0YSBmaWxlIGlzIHN0b3JlZCBpbiB0aGUgc2FtZSBmb2xkZXIuCgpgYGB7ciBnZXRfcHJvdGVvbWVzLCBpbmNsdWRlPUZBTFNFLCBldmFsPUZBTFNFfQpDYXVyaXNmYXN0YS50YWJsZSA8LSBOVUxMCgojIEdldCBkYXRhLiBzZXFpbnIgcGFja2FnZSBpcyBuZXcgYW5kIHNlZW1zIHBvd2VyZnVsIGJ1dCBoYXMgb2RkIGRhdGEgZm9ybXMgc28gSSBoYXZlIHRvIGV4dHJhY3QgdGhlbiByZW1ha2UgZGF0YSBmcmFtZXMKZmlsZS5saXN0IDwtIGxpc3QuZmlsZXMocGF0aCA9ICJkYXRhL3Byb3Rlb21lLWZhc3RhLyIsIHBhdHRlcm4gPSAiKi5mYWEuZ3oiKQpzdHJhaW4ubGlzdCA8LSBzdHJfZXh0cmFjdChmaWxlLmxpc3QsICJCWzAtOV0rIikKZmlsZS5saXN0IDwtIGZpbGUucGF0aCgiZGF0YS9wcm90ZW9tZS1mYXN0YSIsIGZpbGUubGlzdCkKbmFtZXMoZmlsZS5saXN0KSA8LSBzdHJhaW4ubGlzdAoKCiMgd29ya2luZ19kaXJlY3RvcnkgPSAiLi9zYW5kYm94IgpleHRyYWN0LmZhc3RhLmZuIDwtIGZ1bmN0aW9uKGZpbGUsIHdvcmtpbmdfZGlyZWN0b3J5ID0gInNhbmRib3giKXsKICAjcHJvdGVvbWVfZmlsZSA8LSBwYXN0ZSh3b3JraW5nX2RpcmVjdG9yeSwgIi8iLCJwcm90ZW9tZV9maWxlLnR4dC5neiIsIHNlcCA9ICIiKQogICNkb3dubG9hZC5maWxlKHVybCA9IHJhd191cmwsIGRlc3RmaWxlID0gcHJvdGVvbWVfZmlsZSwgcXVpZXQgPSBUUlVFKQogIGZhc3RhIDwtIHJlYWQuZmFzdGEoZmlsZSwgc2VxdHlwZSA9ICJBQSIsIGFzLnN0cmluZyA9IFRSVUUpCiAgdDEgPC0gdGliYmxlKGlkID0gZ2V0TmFtZShmYXN0YSksIGFubm90YXRpb24gPSB1bmxpc3QoZ2V0QW5ub3QoZmFzdGEpKSwgc2VxID0gdW5saXN0KGdldFNlcXVlbmNlKGZhc3RhLCBhcy5zdHJpbmcgPSBUUlVFKSkpCiAgcmV0dXJuKHQxKQp9CgpDYXVyaXNmYXN0YS50YWJsZSA8LSBtYXBfZGZyKGZpbGUubGlzdCwgfmV4dHJhY3QuZmFzdGEuZm4oLiksIC5pZCA9ICJzdHJhaW4iKSAlPiUgCiAgbXV0YXRlKGxlbmd0aCA9IG5jaGFyKHNlcSkpCndyaXRlX3RzdihzZWxlY3QoQ2F1cmlzZmFzdGEudGFibGUsIHN0cmFpbiwgbmFtZSA9IGlkLCBsZW5ndGgpLCBmaWxlID0gImRhdGEvQ2F1cmlzLWZvdXItcHJvdGVvbWVzLXNlcUxlbi50c3YiKQpgYGAKCiMjIFdyaXRlIGEgZmFzdGEgZmlsZQoKSSB3cm90ZSBhIGNvbWJpbmVkIGZhc3RhIGZpbGUgdXNpbmcgdGhlIGNvbW1hbmQgZndyaXRlKHggPSBDYXVyaXNmYXN0YS50YWJsZVssIGMoMSwzKV0sIGZpbGUgPSAiQ2F1cmlzLnR4dCIsIHNlcCA9ICJcdCIsIGNvbC5uYW1lcyA9IEZBTFNFKQoKVXNpbmcgTm90ZXBhZCsrIEkgY2hhbmdlZCAvbiB0byAvblw+IHRoZW4gL3QgdG8gL24gdG8gcHV0IGluIGNvbnZlbnRpb25hbCBmYXN0YSBmb3JtYXQuIFNhdmVkIGFzIENhdXJpc2Zhc3RhLnR4dC4gVGhlcmUgYXJlIDI3Mjc4IHByb3RlaW5zLgoKTm90ZTogSSB3cm90ZSBhIG5ldyBmYXN0YSBmaWxlIHRvIHJlbW92ZSBCMTEyNDMgZnJvbSB0aGUgZmlsZS4gVGhlcmUgYXJlIG5vdyAyMTc3MiBwcm90ZWlucy4KCj4gKipVcGRhdGUgMjAyMS0wNy0wNCBIQioqIHNraXBwZWQgdGhpcyBzdGVwIGFzIHRoZSBjb25jYXRlbmF0ZWQgZmlsZSBjYW4gYmUgY3JlYXRlZCBieSBgY2F0ICouZmFhLmd6ID4gY29uY2F0ZW5hdGVkX2NhbmRfYXVyaXMuZmFhLmd6YCBpZiBuZWVkZWQKCmBgYHtyIGluaXRpYXRlX3NlcUluZm99CiMgd2Ugd2FudCB0byBpbmNsdWRlIHRoZSBpbmZvcm1hdGlvbiBhYm91dCB3aGV0aGVyIGEgcHJvdGVpbiBpcyBpbiBvdXIgaG9tb2xvZ3MgbGlzdAojIGZvciB0aGF0IHdlIHdpbGwgaW1wb3J0YW50IHRoZSBsaXN0IG9mIHByb3RlaW4gaWRzIHRoYXQgd2VyZSBhbmFseXplZApIaWwgPC0gcmVhZF90c3YoImRhdGEvSGlsLWZhbWlseS1DYXVyaXMtaG9tb2xvZ3MtaWQudHh0IiwgY29sX25hbWVzID0gYygibmFtZSIsICJzdHJhaW4iKSwgY29sX3R5cGVzID0gImNjIikKCiMgaW5pdGlhdGUgdGhlIHNlcUluZm8gdGFibGUKc2VxSW5mbyA8LSByZWFkX3RzdigiZGF0YS9DYXVyaXMtZm91ci1wcm90ZW9tZXMtc2VxTGVuLnRzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkgJT4lIAogIG11dGF0ZShpc0hJTCA9IG5hbWUgJWluJSBIaWwkbmFtZSkKCiMgbnVtYmVyIG9mIEhpbCBob21vbG9ncyBieSBzdHJhaW4Kc2VxSW5mbyAlPiUgCiAgZ3JvdXBfYnkoc3RyYWluKSAlPiUgCiAgc3VtbWFyaXplKEhpbCA9IHN1bShpc0hJTCkpCmBgYAoKQSB0b3RhbCBvZiBgciBzdW0oc2VxSW5mbyRpc0hJTClgIHByb3RlaW5zIGluIHRoZSBmb3VyIHN0cmFpbnMgYmVsb25nIHRvIHRoZSBIaWwgZmFtaWx5LiBCMTEyMjEgbWlzc2VzIEhpbDQgYW5kIEIxMTI0NSBtaXNzZXMgSGlsOC4gSW4gYm90aCBjYXNlcyB0aGUgcmVhc29uIGlzIGJlY2F1c2Ugb2YgaW5jb21wbGV0ZSBnZW5vbWUgYXNzZW1ibHkgcmF0aGVyIHRoYW4gZ2VuZSBsb3NzLiBCMTEyMjAsIHRoZSByZXByZXNlbnRhdGl2ZSBvZiBjbGFkZSBJSSwgaW5kZWVkIG1pc3NlcyA1LzggaG9tb2xvZ3MuCgojIyBTaWduYWxQIGZvciBzaWduYWwgcGVwdGlkZXMKClVzZSBTaWduYWxQIDUuMCBzZXJ2ZXIgdG8gcHJlZGljdCBzaWduYWwgcGVwdGlkZXMuIE1heGltdW0gbnVtYmVyIG9mIHByb3RlaW5zIGlzIDUwMDAsIHNvIEkgc3BsaXQgdGhlIGZhc3RhIGZpbGUgaW50byA2IHNtYWxsZXIgZmlsZXMgYW5kIHN1Ym1pdHRlZCwgcHJvdmlkaW5nIG15IGVtYWlsIGVhY2ggdGltZS4gSSB1c2VkIHRoZSBvbGQgZmlsZSB3aXRoIEIxMTI0MyB0byBydW4gdGhpcy4gKEhCOiBzZWVtcyBsaWtlIHRoZSBjdXJyZW50IHJlc3VsdCBmaWxlIGNvbnRhaW5zIEIxMTI0NSBpbnN0ZWFkKS4gSSByZXNwbGl0IHRoZSBuZXcgZmFzdGEgaW50byA1IGZpbGVzIGFuZCByZXJhbi4gRG93bmxvYWRlZCAuZ2ZmIGZpbGVzIGFzIFNpZ25hbFBcXyhmaWxlIFwjKS5nZmYzIGFuZCB1c2VkIGNvbW1hbmQgYGdyZXAgLXYgLWggIiMjIiBTaWduYWxQKiB8IHNvcnQgPiBTaWduYWxQLnR4dGAKCioqTm90ZSBbSEJdKio6IFNpZ25hbFAgb3V0cHV0IGluIEdGRjMgZm9ybWF0IG9ubHkgaW5jbHVkZXMgdGhlIGlucHV0IHByb3RlaW5zIHRoYXQgYXJlIHByZWRpY3RlZCB0byBoYXZlIGEgc2lnbmFsIHBlcHRpZGUuIFRoZXJlIGlzIGEgdG90YWwgb2YgMTE4MyBlbnRyaWVkIGluIHRoZSByZXN1bHQgZmlsZSwgZnJvbSBhIHRvdGFsIG9mID4yMCwwMDAgcHJvdGVpbnMgc3VibWl0dGVkLgoKTW9kaWZpZWQgZmlsZSBuYW1lcywgYnV0IG90aGVyd2lzZSBCaW4ncyBjb2RlOgoKYGBge3Igc2lnbmFsUCwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NX0KIyBTaWduYWwgcGVwdGlkZQpnZmYubmFtZXMgPC0gYygiaWQiLCAic291cmNlIiwgIm5hbWUiLCAic3RhcnQiLCAiZW5kIiwgInByb2IiLCAibmExIiwgIm5hMiIsICJuYTMiKQpzaWduYWxwNSA8LSByZWFkX3Rzdigib3V0cHV0L1NpZ25hbFAudHh0IiwgY29tbWVudCA9ICIjIiwgY29sX25hbWVzID0gZ2ZmLm5hbWVzLCBjb2xfdHlwZXMgPSAiY2NjaWlkY2NjIikKCiMgcmVtb3ZlIHRoZSBjb2x1bW4gaWYgaXQgYWxyZWFkeSBleGlzdHMKaWYoInNpZ25hbHAiICVpbiUgbmFtZXMoc2VxSW5mbykpCiAgc2VxSW5mbyA8LSBzZWxlY3Qoc2VxSW5mbywgLXNpZ25hbHApCnNlcUluZm8gPC0gbGVmdF9qb2luKHNlcUluZm8sIHNlbGVjdChzaWduYWxwNSwgbmFtZSA9IGlkLCBwcm9iKSwgYnkgPSBjKCJuYW1lIiA9ICJuYW1lIikpICU+JSAKICBtdXRhdGUoc2lnbmFscCA9ICFpcy5uYShwcm9iKSkgJT4lIHNlbGVjdCgtcHJvYikKYGBgCgo+ICoqTmV3IHByb2JsZW0qKiBCMTEyNDMgYW5kIEIxMTI0NSBhcmUgaWRlbnRpY2FsLiBCZWNhdXNlIEIxMTI0NSBpcyBhc3NlbWJsZWQgdG8gdGhlIGNocm9tb3NvbWUgbGV2ZWwsIEkgd2lsbCByZXRhaW4gaXQgYW5kIHJlbW92ZSBCMTEyNDMgZnJvbSB0aGUgcmVzdWx0cy4KCiMjIFByZWRHUEkgeyNwcmVkZ3BpfQoKRm9sbG93aW5nIEJpbidzIG1ldGhvZCwgSSB1c2VkIFByZWRHUEkgdG8gcHJlZGljdCBHUEkgYW5jaG9ycy4gRm9yIFByZWRHUEksIHRoZSBtYXhpbXVtIG51bWJlciBvZiBzZXF1ZW5jZXMgaXMgNTAwLiBUbyBzcGxpdCB0aGUgZmlsZSBJIHVzZWQgdGhlIGNvbW1hbmQgc3BsaXQgQ2F1cmlzZmFzdGEudHh0IC1sIDEwMDAgaW4gbXkgVWJ1bnR1IGluc3RhbmNlLCB3aGljaCBtYWRlIDU1IG5ldyBmaWxlcy4gVGhlIG91dHB1dCBpbmNsdWRlcyBuYW1lIFx8IEZQcmF0ZSBcfCBtb3N0IGxpa2VseSBwb3NpdGlvbiBhbmQgdGhlIHNlcXVlbmNlIGZvciBlYWNoLiBHUEkgYW5jaG9yIGlzICJoaWdobHkgcHJvYmFibGUiIHdoZW4gRlByYXRlIFw8IDAuMDAxLCAicHJvYmFibGUiIHdoZW4gMC4wMDEgXDwgRlByYXRlIFw8IDAuMDA1LCAibG93bHkgcHJvYmFibGUiIHdoZW4gMC4wMDUgXDwgRlByYXRlIFw8IDAuMDEuIFJldGFpbiBvbmx5IGhlYWRlciBsaW5lcyB3aXRoIHRoZSBjb21tYW5kIGdyZXAgLWggIlw+IiBHUElQRVwqIFw+IFByZWRHUElSZXN1bHRzLnR4dC4KClRoaXMgd2FzIGRvbmUgdXNpbmcgdGhlIGZpbGUgdGhhdCBjb250YWluZWQgQjExMjQzLiBUbyByZW1vdmUgZHVwbGljYXRlIHJlc3VsdHMsIEkgdXNlZCB0aGUgY29tbWFuZCBncmVwICJcPiIgUHJlZEdQSVJlc3VsdHMudHh0IFx8IHNvcnQgLXUgXD4gUHJlZEdQSVJlc3VsdHMyLnR4dC4gVGhlbiBJIHJlbmFtZWQgUHJlZEdQSVJlc3VsdHMyIFByZWRHUElSZXN1bHRzLiBJdCBoYXMgMjE3NzIgcHJvdGVpbnMuCgoqKlVwZGF0ZSAyMDIxLTA3LTI3IFtIQl0qKgoKSXQgdHVybnMgb3V0IHRoYXQgR1BJLWFuY2hvcmVkIHByb3RlaW5zIGNhbiBiZSBkaXZpZGVkIGludG8gdHdvIGNhdGVnb3JpZXM6IHRob3NlIHRoYXQgYXJlIHJldGFpbmVkIGluIHRoZSBwbGFzbWEgbWVtYnJhbmUgYW5kIHRob3NlIHRoYXQgYXJlIHN1YnNlcXVlbnRseSByZWxlYXNlZCBhbmQgdGhlbiBjb3ZhbGVudGx5IGxpbmtlZCB0byB0aGUgY2VsbCB3YWxsIGNvbXBvbmVudHMgKM6yLTEsNi1nbHVjYW4pLiBUaGUgbGF0dGVyLCBuYW1lZCBjZWxsIHdhbGwgcHJvdGVpbnMgKENXUCkgYWNjb3VudCBmb3IgdGhlIG1ham9yaXR5IG9mIHRoZSBHUEktYW5jaG9yZWQgcHJvdGVpbnMgd2hpbGUgdGhlIGZvcm1lciwgbmFtZWQgcGxhc21hIG1lbWJyYW5lIHByb3RlaW5zIChQTVApIGFyZSB0aGUgbWlub3JpdHkuIEJhc2VkIG9uIENhcm8gX2V0IGFsLl8gMTk5NyAoUE1JRDogOTQzNDM1MiksIHRoZSBQTVBzIHVzdWFsbHkgaGF2ZSBhIGRpYmFzaWMgbW90aWYgcHJpb3IgdG8gKHdpdGhpbiAxMiByZXNpZHVlcyBmcm9tKSB0aGUgY2xlYXZhZ2Ugc2l0ZSwgb3Igz4ktc2l0ZS4gRnJpZW1hbiBhbmQgQ29ybWFjayAyMDA0IChQTUlEOiAxNTQ3MDA5MikgZnVydGhlciBzaG93ZWQgdGhhdCBhbiBlbGV2YXRlZCBTZXIvVGhyIGZyZXF1ZW5jeSBpbiB0aGUgYm9keSBvZiB0aGUgcHJvdGVpbiBjYW4gb3ZlcnJpZGUgdGhlIGRpYmFzaWMgbW90aWYgc2lnbmFsLiBJbiBwYXJ0aWN1bGFyLCB0aGV5IGVtcGlyaWNhbGx5IHNob3dlZCB0aGF0IGEgZ3JvdXAgb2Yga25vd24gUE1QcyB3aXRoIGRpYmFzaWMgbW90aWZzIGFsbCBoYXZlIFNlci9UaHIgZnJlcXVlbmNpZXMgbG93ZXIgdGhhbiAzMCUsIHdoaWxlIHRoZSBDV1BzIGRvbid0IGhhdmUgdGhlIGRpYmFzaWMgbW90aWZzIGFuZCAyOC80MSAoNjglKSBoYXZlIGEgU2VyL1RociBmcmVxdWVuY3kgPiAzMCUuCgpUbyByZW1vdmUgdGhlIFBNUHMgZnJvbSBjb25zaWRlcmF0aW9uIChmcm9tIGFsbCBJIGNhbiBnbGVhbiBmcm9tIHRoZSBsaXRlcmF0dXJlLCBhZGhlc2lucyBhcmUgQ1dQcyBhbmQgbm90IFBNUHMpLCBJIGRldGVybWluZWQgdGhlIHByZXNlbmNlIG9mIGEgZGliYXNpYyBtb3RpZiAoIktLL1JSL0tSL1JLIikgaW4gdGhlIDEyIHJlc2lkdWVzIGltbWVkaWF0ZWx5IHByaW9yIHRvIHRoZSDPiS1zaXRlLCB1c2luZyBhIGN1c3RvbSBQeXRob24gc2NyaXB0IChyZWFsaXplZCBsYXRlciB0aGF0IEkgY291bGQgaGF2ZSB1c2VkIHRoZSBgcHJlZC5ncGlgIHRpYmJsZSBhbmQgYHNlcWlucmAgcGFja2FnZSB0byBkbyB0aGUgc2FtZSB0aGluZyByaWdodCBoZXJlKS4gQmVsb3cgSSdsbCByZWFkIHRoYXQgaW4gYW5kIG1lcmdlIGl0IGludG8gdGhlIGBwcmVkLmdwaWAgdGFibGUuCmBgYHtyIGdwaX0KdG1wIDwtIHJlYWRfZGVsaW0oIm91dHB1dC9QcmVkR1BJUmVzdWx0cy50eHQiLCBkZWxpbSA9ICJ8IiwgY29sX25hbWVzID0gYygibmFtZSIsImZwIiwib21lZ2EiKSwgY29sX3R5cGVzID0gY29scygpKQp0bXAxIDwtIHJlYWRfdHN2KCJvdXRwdXQvUHJlZEdQSV9kaWJhc2ljLnRzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKcHJlZC5ncGkgPC0gdG1wICU+JSAKICBtdXRhdGUobmFtZSA9IHN0cl9zdWIobmFtZSwyLC0yKSwgIyByZW1vdmUgPiBhbmQgdGhlIHRyYWlsaW5nIHNwYWNlCiAgICAgICAgIGZwID0gYXMubnVtZXJpYyhzdHJfc3ViKGZwLCA5LCAtMikpLCAjIGV4dHJhY3QgdGhlIG51bWVyaWMgcGFydAogICAgICAgICBpcy5ncGkgPSBmcCA8PSAwLjAxLCAgICAjIGJhc2VkIG9uIHRoZSBjdXRvZmYgb2YgdGhlIFByZWRHUEkgc2VydmVyIChwcm9iIDwgOTklIC0+IG5vdCBHUEktYW5jaG9yZWQpCiAgICAgICAgIG9tZWdhID0gc3RyX3N1YihvbWVnYSwgOCksCiAgICAgICAgIGNsZWF2ZVJlcyA9IHN0cl9zdWIob21lZ2EsIDEsIDEpLAogICAgICAgICBjbGVhdmVQb3MgPSBhcy5pbnRlZ2VyKHN0cl9zdWIob21lZ2EsIDMpKQogICAgICAgICApICU+JSAKICBsZWZ0X2pvaW4odG1wMSwgYnkgPSAibmFtZSIpCgojIHJlbW92ZSB0aGUgY29sdW1uIGlmIGl0IGFscmVhZHkgZXhpc3RzCmlmKCJwcmVkLmdwaSIgJWluJSBuYW1lcyhzZXFJbmZvKSkKICBzZXFJbmZvIDwtIHNlbGVjdChzZXFJbmZvLCAtcHJlZC5ncGksIC1kaWJhc2ljKQpzZXFJbmZvIDwtIGxlZnRfam9pbihzZXFJbmZvLCBzZWxlY3QocHJlZC5ncGksIG5hbWUsIHByZWQuZ3BpID0gaXMuZ3BpLCBkaWJhc2ljKSwgYnkgPSBjKCJuYW1lIj0ibmFtZSIpKSAlPiUgCiAgcmVsb2NhdGUocHJlZC5ncGksIGRpYmFzaWMsIC5hZnRlciA9IHNpZ25hbHApCmBgYAoKIyMgaG1tc2NhbiBmb3IgcGZhbSBkb21haW5zCgpVc2luZyBobW1zY2FuIHRvIHNlYXJjaCB0aGUgcGZhbSBkYXRhYmFzZSx0aGUgbWF4aW11bSBhbGxvd2VkIG51bWJlciBvZiBzZXF1ZW5jZXMgaXMgNTAwLiBJIHVwbG9hZGVkIHRoZSBzYW1lIDU1IGZpbGVzIGZyb20gUHJlZEdQSSB0byBobW1zY2FuLCBwcm92aWRpbmcgbXkgZW1haWwgYWRkcmVzcyBlYWNoIHRpbWUuIEhtbWVyV2ViIHZlcnNpb24gMi40MS4xLiBJIHJlc3BsaXQgdGhlIG5ldyBmYXN0YSBpbnRvIDQ0IGZpbGVzIGFuZCByZXJhbi4gQ29waWVkIGFuZCBwYXN0ZWQgcmVzdWx0cyBlbWFpbCBpbnRvIGhtbWVyX3Jlc3VsdHNfZW1haWxzLnR4dCAtIGNoZWNrZWQgdG8gbWFrZSBzdXJlIHRoYXQgdGhlcmUgd2VyZSA0NCBhbmQgdGhhdCBlYWNoIGpvYiBpZCBtYXRjaGVkLiBVc2VkIHRoZSBjb21tYW5kIGdyZXAgIlw+IiBobW1lcl9yZXN1bHRzX2VtYWlscy50eHQgXHwgc29ydCBcPiBobW1lcl9yZXN1bHRzLnR4dC4gSW4gTm90ZXBhZCsrLCBjb3BpZWQgYW5kIHBhc3RlZCBoZWFkZXIgcm93IGZyb20gZW1haWxzIGZpbGUuCgpUaGlzIGNodW5rIHdpbGwgYWRkIGEgY29sdW1uIHRoYXQgbGlzdHMgYWxsIG5vbi1vdmVybGFwcGluZyBkb21haW5zIGZvdW5kIGluIGVhY2ggcHJvdGVpbi4gSW4gY2FzZXMgb2Ygb3ZlcmxhcCwgdGhlIGhpZ2hlc3Qtc2NvcmluZyBkb21haW4gd2lucyAodXNpbmcgdGhlIG91dGNvbXBldGVkIGNvbHVtbiBpbiB0aGUgZGF0YSkuCgoqKlVwZGF0ZSAyMDIxLTA3LTA0IEhCKiogU2VlIFtITU1TQ0FOIGhlbHAgcGFnZV0oaHR0cHM6Ly9obW1lci13ZWItZG9jcy5yZWFkdGhlZG9jcy5pby9lbi9sYXRlc3QvcmVzdWx0Lmh0bWwpIGZvciBjbGFyaWZpY2F0aW9uIG9uIHRoZSAnb3V0LWNvbXBldGVkIiBjb2x1bW4KCj4gSW4gUGZhbSByZWxhdGVkIGVudHJpZXMgYXJlIGdyb3VwZWQgaW50byBDbGFucywgYW5kIGFzIHN1Y2ggY2FuIG9mdGVuIG1hdGNoIHRoZSBzYW1lLCBvciBzaW1pbGFyLCByZWdpb25zIG9uIHRoZSBxdWVyeSBzZXF1ZW5jZS4gQW4gYWRkaXRpb25hbCBjb2x1bW4gaW4gdGhlIHJlc3VsdHMgdGFibGUgY29udGFpbnMgdGhlIGNsYW4gYWNjZXNzaW9uIGZvciB0aGUgZmFtaWx5LCBpZiBpdCBiZWxvbmdzIHRvIGEgY2xhbi4gUGZhbSBlbXBsb3lzIGEgc3BlY2lmaWMgcG9zdCBwcm9jZXNzaW5nIG9uIGZhbWlsaWVzIGZyb20gdGhlIHNhbWUgY2xhbiB3aGVyZSB0aGUgYmVzdCBtYXRjaCAoZGV0ZXJtaW5lZCBieSBsb3dlc3QgRS12YWx1ZSksIGlzIHRha2VuIGFuZCB0aGUgcmVzdCBhcmUgb3V0LWNvbXBldGVkLgoKYGBge3IgaG1tc2Nhbn0KaG1tLm5hbWVzIDwtIGMoInNlcV9pZCIsICJhbGlnbm1lbnRfc3RhcnQiLCAiYWxpZ25tZW50X2VuZCIsICJlbnZlbG9wZV9zdGFydCIsICJlbnZlbG9wZV9lbmQiLCAiaG1tX2FjYyIsICJobW1fbmFtZSIsICJobW1fc3RhcnQiLCAiaG1tX2VuZCIsICJobW1fbGVuZ3RoIiwgImJpdF9zY29yZSIsICJpbmRpdmlkdWFsX2VfdmFsdWUiLCAiY29uZGl0aW9uYWxfZV92YWx1ZSIsICJkYXRhYmFzZV9zaWduaWZpY2FudCIsICJvdXRjb21wZXRlZCIsICJjbGFuIikKaG1tc2Nhbl9wZmFtIDwtIHJlYWRfdGFibGUyKGZpbGUgPSAib3V0cHV0L2htbWVyX3Jlc3VsdHMudHh0IiwgY29sX25hbWVzID0gaG1tLm5hbWVzLCBjb2xfdHlwZXMgPSAiY2lpaWljY2lpaWRkZGlpYyIsIHNraXAgPSAxKQoKZGYgPC0gaG1tc2Nhbl9wZmFtICU+JSAKICBmaWx0ZXIoIW91dGNvbXBldGVkLCAgIyByZW1vdmUgbG93ZXItc2NvcmVkIG92ZXJsYXBwaW5nIGRvbWFpbnMKICAgICAgICAgIWhtbV9uYW1lICVpbiUgYygiSHlyMSIsICJDYW5kaWRhX0FMUyIpKSAlPiUgIyByZW1vdmUgdHdvIHJlcGVhdCBkb21haW5zCiAgbXV0YXRlKHNlcV9pZCA9IHN0cl9zdWIoc2VxX2lkLCAyKSkgJT4lICMgcmVtb3ZlID4KICBncm91cF9ieShzZXFfaWQpICU+JSAKICAjIGNvbGxhcHNlIGludG8gbGlzdCBvZiBwZmFtIGRvbWFpbnMgZm9yIGVhY2ggcHJvdGVpbgogIHN1bW1hcmlzZShwZmFtX2RvbWFpbnMgPSBwYXN0ZTAoaG1tX25hbWUsICIgKCIsIGVudmVsb3BlX3N0YXJ0LCAiLSIsIGVudmVsb3BlX2VuZCwgICIpIiwgY29sbGFwc2UgPSAiLCAiKSkKCiMgcmVtb3ZlIHRoZSBjb2x1bW4gaWYgaXQgYWxyZWFkeSBleGlzdHMKaWYoInBmYW1fZG9tYWlucyIgJWluJSBuYW1lcyhzZXFJbmZvKSkKICBzZXFJbmZvIDwtIHNlbGVjdChzZXFJbmZvLCAtcGZhbV9kb21haW5zKQpzZXFJbmZvIDwtIGxlZnRfam9pbihzZXFJbmZvLCBkZiwgYnkgPSBjKCJuYW1lIj0ic2VxX2lkIikpCmBgYAoKIyMgVEFOR08KCkNyZWF0ZWQgYSAuYmF0IGZpbGUgdG8gcnVuIHRhbmdvIG9uIHRoZSBjb25kZW5zZWQgZmFzdGEuIFVzZWQgdGhlIGNvbW1hbmQgYGZ3cml0ZSh4ID0gQ2F1cmlzZmFzdGEudGFibGVbLCBjKDEsMyldLCBmaWxlID0gIkNhdXJpcy50eHQiLCBzZXAgPSAiXHQiLCBjb2wubmFtZXMgPSBGQUxTRSlgLiBDb21tYW5kIGZpbGUgaXMgdGFuZ29faW4uYmF0LiBSYW4gaXQgYW5kIGNvbXByZXNzZWQgYWxsIHJlc3VsdHMgdXNpbmcgdGhlIGNvbW1hbmQgZ3ppcCBcKi50eHQuCgpXaGVuIEkgd2VudCB0byBhbmFseXplIEkgZm91bmQgdGhhdCBtdWx0aXBsZSBmaWxlcyBjb250YWluZWQgdHJhc2ggKGNvbHVtbnMgd2l0aCB2YWx1ZSAtMS5JTyBhbmQgdmFsdWVzIHRoYXQgZGlkbid0IG1hdGNoIGlmIHRoZSBzaW5nbGUgbGluZSBmcm9tIHRoZSAuYmF0IGZpbGUgd2FzIHJlcnVuKS4gVXBvbiBsb29raW5nIGluIHRoZSBUQU5HTyBkb2N1bWVudGF0aW9uLCBpdCBzYXlzIHRoYXQgZmlsZXMgY2FuJ3QgYmUgbGFyZ2VyIHRoYW4gMTAwMCBzZXF1ZW5jZXMuIFNwbGl0dGluZyBpdCBzdGlsbCBpbmR1Y2VkIGVycm9ycywgc28gSSBoYWQgQmluIHJlcnVuIGFsbCBvZiB0aGUgVEFOR08gY2FsY3VsYXRpb25zIGFuZCB1cGxvYWQgaGlzIGVycm9yLWZyZWUgcmVzdWx0cyB0byB0aGUgZ2l0aHViLgoKPiBOb3RlOiBEb3dubG9hZGluZyBhbmQgcHJvY2Vzc2luZyBhbGwgb2YgdGhlIFRBTkdPIG91dHB1dCBmaWxlcyB0YWtlcyBhIFZFUlkgbG9uZyB0aW1lLiBJZiB5b3UgZG9uJ3QgbmVlZCB0byByZWdlbmVyYXRlIHRoZSByZXN1bHRzLCBqdXN0IGltcG9ydCB0aGUgZmlsZSBgdGFuZ29fcmVzdWx0c19kZi50eHRgIGFzIGB0YW5nby5yZXMuZGYxYC4gRXZlcnl0aGluZyBhZnRlciBleHRyYWN0aW5nIHRoZSByZXN1bHRzIHdpbGwgd29yayBvZmYgb2YgdGhhdC4KClVzaW5nIEJpbidzIHRhbmdvIGV4dHJhY3Rpb24gZnVuY3Rpb25zCgpgYGB7ciBleHRyYWN0X3RhbmdvX2luZm8sIGV2YWw9RkFMU0V9CnJlcXVpcmUoZHBseXIpCmV4dHJhY3RfdGFuZ28gPC0gZnVuY3Rpb24odGFuZ29fb3V0cHV0LCBhZ2dfdGhyZXNob2xkID0gNSwgcmVxdWlyZWRfaW5fc2VyaWFsID0gNSkgewogICAgcmVxdWlyZSh0aWR5dmVyc2UpCiAgICB0bXAgPC0gcmVhZF90c3YoZmlsZSA9IHRhbmdvX291dHB1dCwgY29sX3R5cGVzID0gImljZGRkZGQiKSAlPiUgCiAgICAgICAgIyBhIGJvb2xlYW4gdmVjdG9yIGZvciByZXNpZHVlcyBhYm92ZSB0aHJlc2hvbGQKICAgICAgICBtdXRhdGUocGFzcyA9IEFnZ3JlZ2F0aW9uID4gYWdnX3RocmVzaG9sZCkKICAgIHBhc3MucmxlIDwtIHJsZSh0bXAkcGFzcykgIyB0aGlzIGNyZWF0ZXMgYSBydW4gbGVuZ3RoIGVuY29kaW5nIHRoYXQgd2lsbCBiZSB1c2VmdWwgZm9yIGlkZW50aWZ5aW5nIHRoZSBzdWItc2VxdWVuY2VzIGluIGEgcnVuIGxvbmdlciB0aGFuIGNlcnRhaW4gbGVuZ3RoCiAgICAjIC0tLSBFeHBsYW5hdGlvbiAtLS0KICAgICMgdGhpcyBybGUgb2JqZWN0IGlzIGF0IHRoZSBjb3JlIG9mIHRoaXMgZnVuY3Rpb24KICAgICMgYW4gZXhhbXBsZSBvZiB0aGUgcmxlIGxvb2tzIGxpa2UKICAgICMgICBsZW5ndGhzOiBpbnRbMToxMF0gNSAxOSAyMCA4IDEgNSAxOSA2IDE4MSAxOAogICAgIyAgIHZhbHVlczogbG9naVsxOjEwXSBGIFQgIEYgIFQgRiBUIEYgIFQgRiAgIFQKICAgICMgICBub3RlIHRoYXQgYnkgZGVmaW5pdGlvbiB0aGUgdmFsdWVzIHdpbGwgYWx3YXlzIGJlIFQvRiBpbnRlcmRpZ2l0ZWQKICAgICMgb3VyIGdvYWwgaXMgdG8gaWRlbnRpZnkgdGhlIHN1Yi1zZXF1ZW5jZXMgdGhhdCBpcyBkZWZpbmVkIGFzIGEgc3RyZXRjaCBvZiAKICAgICMgbiBjb25zZWN1dGl2ZSBwb3NpdGlvbnMgd2l0aCBhIHNjb3JlIGdyZWF0ZXIgdGhhbiB0aGUgY3V0b2ZmIGFuZCByZWNvcmQgdGhlCiAgICAjIHN1Yi1zZXF1ZW5jZSwgaXRzIGxlbmd0aCwgc3RhcnQgYW5kIGVuZCBwb3NpdGlvbiwgOTAlIHF1YW50aWxlIG9mIHRoZSBzY29yZQogICAgIyAtLS0gRW5kIG9mIGV4cGxhbmF0aW9uIC0tLQogICAgIyAxLiBhc3NpZ25zIGEgdW5pcXVlIGlkIGZvciBlYWNoIHJ1biBvZiBldmVudHMKICAgIHRtcCRncm91cCA8LSByZXAoMTpsZW5ndGgocGFzcy5ybGUkbGVuZ3RocyksIHRpbWVzID0gcGFzcy5ybGUkbGVuZ3RocykKICAgICMgIyAyLiBleHRyYWN0IHRoZSBzdWJzZXF1ZW5jZXMKICAgIGFnZy5zZXEgPC0gdG1wICU+JQogICAgICAgIGRwbHlyOjpmaWx0ZXIocGFzcykgJT4lICMgZHJvcCByZXNpZHVlcyBub3QgcHJlZGljdGVkIHRvIGhhdmUgYWdncmVnYXRpb24gcG90ZW50aWFsCiAgICAgICAgZ3JvdXBfYnkoZ3JvdXApICU+JSAjIGNsdXN0ZXIgYnkgdGhlIHJ1bnMKICAgICAgICBzdW1tYXJpc2Uoc2VxID0gcGFzdGUwKGFhLCBjb2xsYXBzZSA9ICIiKSwKICAgICAgICAgICAgICAgICAgc3RhcnQgPSBtaW4ocmVzKSwgZW5kID0gbWF4KHJlcyksIGxlbmd0aCA9IG4oKSwKICAgICAgICAgICAgICAgICAgbWVkaWFuID0gbWVkaWFuKEFnZ3JlZ2F0aW9uKSwKICAgICAgICAgICAgICAgICAgcTkwID0gcXVhbnRpbGUoQWdncmVnYXRpb24sIHByb2JzID0gMC45KSwKICAgICAgICAgICAgICAgICAgaXZ0ID0gc3VtKGFhICVpbiUgYygiSSIsIlYiLCJUIikpIC8gbGVuZ3RoKGFhKSwKICAgICAgICAgICAgICAgICAgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgICAgICAgbXV0YXRlKGludGVydmFsID0gc3RhcnQgLSBkcGx5cjo6bGFnKGVuZCkgLSAxKSAlPiUKICAgICAgICBkcGx5cjo6ZmlsdGVyKGxlbmd0aCA+PSByZXF1aXJlZF9pbl9zZXJpYWwpICU+JQogICAgICAgIHNlbGVjdCgtZ3JvdXApCiAgICByZXR1cm4oYWdnLnNlcSkKfQoKYGBgCgpBcHBseSB0byAqQy4gYXVyaXMqIHByb3Rlb21lcwoKYGBge3IgdGFuZ29fZXh0cmFjdCwgZXZhbD1GQUxTRSwgd2FybmluZz1GQUxTRX0KdGFuZ28ub3V0cHV0LmZpbGVzIDwtIGxpc3QuZmlsZXMocGF0aCA9ICJvdXRwdXQvdGFuZ28tb3V0cHV0IiwgcGF0dGVybiA9ICIudHh0fC50eHQuZ3oiLCBmdWxsLm5hbWVzID0gVFJVRSkKIyB0aGUgcmVhZF9jc3YoKSBmdW5jdGlvbiB1c2VkIGluIHRoZSBjdXN0b20gZnVuY3Rpb24gY2FuIGF1dG9tYXRpY2FsbHkgZGVjb21wcmVzcyBnemlwcGVkIGZpbGVzCnRhbmdvLnJlcyA8LSBsYXBwbHkodGFuZ28ub3V0cHV0LmZpbGVzLCBleHRyYWN0X3RhbmdvKQpuYW1lcyh0YW5nby5yZXMpIDwtIGdzdWIoIi50eHR8LnR4dC5neiIsICIiLCBiYXNlbmFtZSh0YW5nby5vdXRwdXQuZmlsZXMpKQojIHRvIGFkZCBzcGVjaWVzIGluZm9ybWF0aW9uCiMgc2VxSW5mbyA8LSByZWFkX3RzdigicmF3LW91dHB1dC9YUF8wMjg4ODkwMzNfaG9tb2xvZ3MudHN2IiwgY29tbWVudCA9ICIjIiwgY29sX3R5cGVzID0gYygiY2NjaSIpKQp0YW5nby5yZXMuZGYgPC0gYmluZF9yb3dzKHRhbmdvLnJlcywgLmlkID0gImlkIikKIyB0YW5nby5yZXMuZGYgPC0gYmluZF9yb3dzKHRhbmdvLnJlcywgLmlkID0gImlkIikgJT4lIAojICAgbGVmdF9qb2luKHNlbGVjdChzZXFJbmZvLCAtbGVuZ3RoKSwgYnkgPSBjKCJpZCIgPSAiaWQiKSkKIyAjIHNhdmUgdGhlIHRhbmdvIG91dHB1dAojIHdyaXRlX3Rzdih0YW5nby5yZXMuZGYsICJ0YW5nb19zdW1tYXJ5X3RhYmxlLnRzdi5neiIpCiMgIyBtdXRhdGUoc3BlY2llcyA9IHN0cl9zcGxpdChpZCwgIl8oPyEuKl8pIiwgc2ltcGxpZnkgPSBUUlVFKVssMl0pIAojICMgZXh0cmFjdCB0aGUgc3BlY2llcyBuYW1lcwojICMgY3JlZGl0OiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8yMDQ1NDc2OC9ob3ctdG8tc3BsaXQtYS1zdHJpbmctZnJvbS1yaWdodC10by1sZWZ0LWxpa2UtcHl0aG9ucy1yc3BsaXQKIyAjIHRoZSBzcGxpdCBwYXR0ZXJuIGlzIGVxdWl2YWxlbnQgdG8gdGhlIHJzcGxpdCgpIGZ1bmN0aW9uIGluIHB5dGhvbgpgYGAKClRvcCAyMCBUQU5HTyBoaXRzIHJhbmtlZCBieSBudW1iZXIgb2Ygb2NjdXJyZW5jZXMgaW4gYWxsIHByb3RlaW5zLCByZXN0cmljdGVkIHRvIHRoZSBzdHJvbmcgaGl0cyB3aXRoIGEgbWVkaWFuIHNjb3JlIFw+PSAzMCUuCgpgYGB7ciB1bmlxdWVfbW90aWZzfQojIHRhbmdvLnJlcy5kZjEgPC0gdGFuZ28ucmVzLmRmICU+JSBsZWZ0X2pvaW4oc2VxSW5mbyAlPiUgc2VsZWN0KG5hbWUsIHN0cmFpbiksIGJ5ID0gYygiaWQiID0gIm5hbWUiKSkKdGFuZ28ucmVzLmRmMSA8LSByZWFkX3Rzdigib3V0cHV0L3RhbmdvX3Jlc3VsdHNfZGYudHh0Lmd6IiwgY29sX3R5cGVzID0gY29scygpKQoKIyBmaW5kIHVuaXF1ZSBtb3RpZnMgYW5kIGNvdW50IHRoZSBudW1iZXIgb2YgcHJvdGVpbnMgYW5kIHN0cmFpbnMgcmVwcmVzZW50ZWQKbW90aWYuc3VtbWFyeSA8LSB0YW5nby5yZXMuZGYxICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KHNlcUluZm8sIGlkID0gbmFtZSwgaXNISUwpKSAlPiUgCiAgZ3JvdXBfYnkoc2VxKSAlPiUgCiAgc3VtbWFyaXplKG4gPSBuKCksIG4uSElMID0gc3VtKGlzSElMKSwKICAgICAgICAgICAgbi5wcm90ID0gbl9kaXN0aW5jdChpZCksIAogICAgICAgICAgICBuLnN0cmFpbnMgPSBuX2Rpc3RpbmN0KHN0cmFpbiksCiAgICAgICAgICAgIG1lZFNjb3JlID0gcm91bmQobWVhbihtZWRpYW4pLDEpLAogICAgICAgICAgICBJVlQgPSByb3VuZChtZWFuKGl2dCksMiksCiAgICAgICAgICAgIGF2Zy5pbnR2ID0gcm91bmQobWVhbihpbnRlcnZhbCwgbmEucm0gPSBUKSwxKSwgCiAgICAgICAgICAgIG1hZC5pbnR2ID0gcm91bmQobWFkKGludGVydmFsLCBuYS5ybSA9IFQpLDEpLAogICAgICAgICAgICAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgYXJyYW5nZShkZXNjKG4pKQptb3RpZi5zdW1tYXJ5ICU+JSAKICBmaWx0ZXIocm91bmQobWVkU2NvcmUsMCkgPj0gMzApICU+JSAKICBoZWFkKDIwKQpgYGAKCioqKkRpc2N1c3Npb24qKioKCi0gICBTb21ld2hhdCB0byBvdXIgc3VycHJpc2UsIGV2ZW4gaW4gdGhlIGVudGlyZSAqQy4gYXVyaXMqIHByb3Rlb21lLCB0aGUgIkdWVklWVFQiIGFuZCBpdHMgdmFyaWFudHMgYXJlIHN0aWxsIHRoZSBkb21pbmFudCBUQU5HTyBtb3RpZiEgQXJlIHRoZXkgYWxsIGluIHRoZSBIaWwgZmFtaWx5IGhvbW9sb2dzPwoKIyMjIElkZW50aWZ5IHZhcmlhbnRzIG9mICJHVlZJVlRUIgoKU2luY2UgdGhpcyBpcyB0aGUgZG9taW5hbnQgbW90aWYgaW4gdGhlICpDLiBhdXJpcyogcHJvdGVvbWUsIHdlIHdhbnQgdG8gZGV0ZXJtaW5lIHdoYXQgcGVyY2VudCBvZiB0aGUgVEFOR08gc2VxdWVuY2VzIGluIHRoZSAqQy4gYXVyaXMqIHByb3Rlb21lIGJlbG9uZyB0byB0aGlzIGNsYXNzPwoKVG8gZGVzaWduIHRoZSByZWd1bGFyIGV4cHJlc3Npb24sIHdlIGxvb2tlZCBhdCBib3RoIHRoZSBUQU5HTyBzZXF1ZW5jZXMgdGhhdCAibG9vayBzaW1pbGFyIiB0byAiR1ZWSVZUVCIuIEluIHBhcnRpY3VsYXIsIEphbiBtYW51YWxseSB3ZW50IHRocm91Z2ggdGhlIFRBTkdPIGhpdHMgaW4gKkMuIGx1c2l0YW5lYWUsIEMuIGF1cmlzLCBDLiBoYWVtdWxvbmlzLCBDLiBwc2V1ZG9oYWVtdWxvbmlzLCBDLiBkdW9oYWVtdWxvbmlzLCBTLiBzdGlwaXRpcywgUy4gY2VyZXZpc2lhZSosIGFuZCAqQy4gZ2xhYnJhdGEqIGFuZCBzdW1tYXJpemVkIHRoZSBmb2xsb3dpbmcgcGF0dGVybjogYFtWSV1bVklWTVtWSV1bVkldVGAKCkJlbG93IHdlIHdpbGwgcmVzdHJpY3QgdGhlIHBhdHRlcm5zIHRvIHRob3NlIHdpdGggYSBtZWRpYW4gVEFOR08gcHJvYmFiaWxpdHkgYWJvdmUgMzAuCgpgYGB7ciwgcmVzdWx0cz0nYXNpcyd9CnNlcXMgPC0gbW90aWYuc3VtbWFyeSRzZXEKIyBjb3JlIGdyb3VwLCBtdXN0IGJlIEctW1ZJXXg0LVRUCnBhdDAgPC0gIkdbVkldezR9VFQiCiMgdmVyc2lvbiAxLCByZXF1aXJlcyBHLVtBTFZJXVtWSV1bTFZJXVtWSV0tKGVpdGhlciBlbmQgb2Ygc3RyaW5nIG9yIGF0IGxlYXN0IDEgc3VpdGFibGUgcmVzaWR1ZSkgCiMgICAgICAgICAgICAgICAgICBPUiAoRyBub3QgcmVxdWlyZWQpLVtWSV14NC0odHdvIHN1aXRhYmxlIHJlc2lkdWVzKQojIHBhdDEgPC0gIkdbQUxWSV1bVkldW0xWSV1bVkldKFtMVklGQVdZVE1dezEsMn18JCl8W1ZJXXs0fVtMVklGQVdZVE1dezJ9IgojIHZlcnNpb24gMiwgYmFzZWQgb24gSmFuJ3MgbWFudWFsIGluc3BlY3Rpb24gb2YgVEFOR08gaGl0cyBpbiB0aGUgZm9sbG93aW5nIHNwZWNpZXM6CiMgQy4gbHVzaXRhbmVhZSwgQy4gYXVyaXMsIEMuIGhhZW11bG9uaXMsIEMuIHBzZXVkb2hhZW11bG9uaXMsIEMuIGR1b2hhZW11bG9uaXMsIFMuIHN0aXBpdGlzLCBTLiBjZXJldmlzaWFlLCBhbmQgQy4gZ2xhYnJhdGEKcGF0LmphbiA8LSAiW1ZJXVtWSVZNW1ZJXVtWSV1UIgpjYXQocGFzdGUoIklkZW50aWZ5IHRoZSBncm91cCBvZiBUQU5HTyBzZXF1ZW5jZXMgbW9zdCBzaW1pbGFyIHRvICdHVlZJVlRUJyB1c2luZyB0aGUgcGF0dGVybiIsIHBhdDAsIHNlcCA9ICIgIikpCm1hdGNoMCA8LSBncmVwKHBhdDAsIHNlcXMpCm1vdGlmLnN1bW1hcnlbbWF0Y2gwLF0gJT4lIGZpbHRlcihyb3VuZChtZWRTY29yZSwwKSA+PSAzMCkgJT4lIGFycmFuZ2UoZGVzYyhuKSkgJT4lIHNlbGVjdChzZXEsIG4sIG4uSElMLCBtZWRTY29yZSwgSVZUKQpjYXQocGFzdGUoIklkZW50aWZ5IFRBTkdPIHNlcXVlbmNlcyB3aXRoIHNsaWdodGx5IG1vcmUgdmFyaWF0aW9uIGZyb20gJ0dWVklWVFQnLCB1c2luZyBgIiwgcGF0LmphbiwgImAiLCBzZXAgPSAiIikpCm1hdGNoLmphbiA8LSBncmVwKHBhdC5qYW4sIHNlcXMpCiMgZXhjbHVkZSB0aG9zZSBhbHJlYWR5IGlkZW50aWZpZWQgd2l0aCBwYXR0ZXJuIDAKbW90aWYuc3VtbWFyeVtzZXRkaWZmKG1hdGNoLmphbiwgbWF0Y2gwKSxdICU+JSBmaWx0ZXIocm91bmQobWVkU2NvcmUsMCkgPj0gMzApICU+JSBhcnJhbmdlKGRlc2MobikpICU+JSBzZWxlY3Qoc2VxLCBuLCBuLkhJTCwgbWVkU2NvcmUsIElWVCkKCiMgZXhwb3J0IHRoZSBsaXN0IG9mIG1vdGlmcyBmb3IgbWFudWFsIGluc3BlY3Rpb24KbW90aWYuc3VtbWFyeVt1bmlvbihtYXRjaC5qYW4sIG1hdGNoMCksXSAlPiUgCiAgZmlsdGVyKHJvdW5kKG1lZFNjb3JlLDApID49IDMwKSAlPiUgCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUgCiAgd3JpdGVfY3N2KCJvdXRwdXQvVEFOR08tR1ZWSVZUVC1saWtlLXNlcXVlbmNlcy5jc3YiKQpgYGAKCioqKkRpc2N1c3Npb24qKioKCi0gICBXZSBjYW4gc2VlIHRoYXQgdGhlIHZhc3QgbWFqb3JpdHkgb2YgR1ZWSVZUVC1saWtlIHNlcXVlbmNlcyBhcmUgd2l0aGluIHRoZSBIaWwgZmFtaWx5IHByb3RlaW5zCgotICAgV2hpY2ggbm9uLUhpbCBwcm90ZWlucyBoYXZlIEdWVklWVFQgc2VxdWVuY2VzPwoKICAgIGByIG1vdGlmLnBlci5zZXEgJT4lIGZpbHRlcihncmVwbChwYXQwLHNlcXMpLCAhaXNISUwpYAoKICAgIE5vdGUgdGhhdCBYUF8wMjg4OTEzNzguMSBpcyBhIHBhcnRpYWwgcHJvdGVpbiBlbnRyeSB0aGF0IEkgaGF2ZSBkZXRlcm1pbmVkIHRvIGJlIHRoZSBDLXRlcm1pYW5sIGZyYWdtZW50IG9mIEhpbDQgaW4gQjExMjIxLiBMb29raW5nIGNsb3NlbHkgYXQgdGhlIHNlcXVlbmNlIGFuZCB0aGUgY2hyb21vc29tYWwgbG9jYXRpb25zIG9mIFFFTDYzMTI0IGFuZCBpdHMgbmVpZ2hib3JpbmcgUUVMNjMxMjUsIEkgZm91bmQgdGhhdCB0aGUgbGF0dGVyLCBhdCB+NTAwIGEuYS4gaXMgdGhlIE4tdGVybWluYWwgZG9tYWluIG9mIEhpbDEgaW4gQjExMjQ1IHdoaWxlIFFFTDYzMTI0IGlzIHRoZSByZW1haW5pbmcgcGFydCBvZiB0aGF0IHByb3RlaW4uIFNvIGluIGNvbmNsdXNpb24sICoqQUxMICJHVlZJVlRUIiBsaWtlIHNlcXVlbmNlcywgYmFzZWQgb24gQmluJ3MgcmVnZXgsIGFyZSB3aXRoaW4gdGhlIEhpbCBmYW1pbHkuCgotICAgSW4gdGhlIHNlY29uZCB0YWJsZSB0aGF0IGxpc3RzIEdWVklWVFQtbGlrZSBzZXF1ZW5jZXMgdGhhdCBhcmUgY2FwdHVyZWQgYnkgSmFuJ3MgbW9yZSBpbmNsdXNpdmUgcmVnZXggYW5kIG5vdCBteSBzdHJpY3Qgb25lLCB0aGVyZSBpcyBhIG5vdGFibGUgb3V0bGllciwgbmFtZWx5IEdWVklWVCwgd2hpY2ggaXMgYm90aCBzbyBjbG9zZSB0byBHVlZJVlRUIGFuZCB5ZXQgKipvbmx5KiogcHJlc2VudCBpbiBhIGdyb3VwIG9mIG5vbkhpbCBzZXF1ZW5jZXMsIGluY2x1ZGluZyBQSVM1ODE4NSBpbiBCODQ0MSBhbmQgb3RoZXJzLgoKICAgIGByIHRhbmdvLnJlcy5kZjEgJT4lIGZpbHRlcihzZXEgPT0gIkdWVklWVCIpICU+JSBzZWxlY3QoaWQsIHN0cmFpbikgJT4lIGxlZnRfam9pbihzZXFJbmZvLCBieSA9IGMoImlkIiA9ICJuYW1lIiwgInN0cmFpbiIpKSAlPiUgdW5pcXVlKClgCgogICAgSSBhbmFseXplZCB0aGlzIGdyb3VwIG9mIHNlcXVlbmNlcyBmdXJ0aGVyIC0tIHNlZSBgUkVBRE1FLm1kYCBpbiB0aGlzIGZvbGRlci4KCi0gICBUaGlzIHByb3RlaW4gaXMgdmVyeSBpbnRlcmVzdGluZzogaXQgbm8gbG9uZ2VyIGhhcyB0aGUgUEYxMTc2NSBkb21haW4gYnV0IG90aGVyd2lzZSBzaG93cyBhIGhpZ2ggZGVncmVlIG9mIHNlcXVlbmNlIHNpbWlsYXJpdHkgd2l0aCB0aGUgbGF0dGVyLgoKICAgICFbYWxpZ25dKG91dHB1dC9QSVM1ODE4NS9QSVM1ODE4NS1YUF8wMjg4ODkwMzMtYWxpZ25tZW50LnBuZykKCiMjIyMgTnVtYmVyIGFuZCBzcGFjaW5nIG9mIFRBTkdPIGhpdHMgaW4gZWFjaCBwcm90ZWluIHNlcXVlbmNlCgpXZSBmaXJzdCBzdW1tYXJpemUgdGhlIG1vdGlmIHNlcXVlbmNlcyB3aXRoaW4gZWFjaCBwcm90ZWluIGFuZCB0aGVuIHVzZSB0aGF0IHRvIGRldGVybWluZSB0aGUgZGlzdHJpYnV0aW9uIG9mIFRBTkdPIGhpdCBcIyBhbmQgc3BhY2luZyBpbiB0aGUgZW50aXJlIHByb3Rlb21lLCB3aXRoIG9yIHdpdGhvdXQgdGhlIEhpbCBmYW1pbHkuCgpgYGB7cn0KIyBmaXJzdCBjb3VudCB0aGUgbnVtYmVyIG9mIHRhbmdvIGhpdHMgd2l0aCBtZWRpYW4gc2NvcmUgPj0gMzAgaGl0cyBmb3IgZWFjaCBwcm90ZWluCiMgbW90aWYucGVyLnNlcSA8LSB0YW5nby5yZXMuZGYxICU+JSAKIyAgIGdyb3VwX2J5KGlkKSAlPiUgCiMgICBzdW1tYXJpemUobi5hbGwgPSBzdW0ocm91bmQobWVkaWFuLCAwKSA+PSAzMCkpCgojIG5leHQgd2Ugd2lsbCBmaWx0ZXIgdGhlIHRhbmdvIGRhdGFzZXQgaW4gb3JkZXIgdG8gcmVjYWxjdWxhdGUgdGhlIGludGVydmFscwojIHRoaXMgd2lsbCByZXN1bHQgaW4gMTQgc2VxdWVuY2VzIHRvIGJlIGRyb3BwZWQgc2luY2UgdGhleSBoYXZlIDAgaGl0cyBtZWV0aW5nCiMgdGhlIGNyaXRlcmlhLiB3ZSB3aWxsIGFkZCB0aGVtIGJhY2sgYnkgcmlnaHRfam9pbigpIHdpdGggdGhlIHRpYmJsZSBhYm92ZQptb3RpZi5wZXIuc2VxIDwtIHRhbmdvLnJlcy5kZjEgJT4lIAogICMgbGltaXQgdG8gc2VxdWVuY2VzIHdpdGggbWVkaWFuIHNjb3JlID49IDMwCiAgZmlsdGVyKHJvdW5kKG1lZGlhbiwwKSA+PSAzMCkgJT4lIAogIGdyb3VwX2J5KGlkKSAlPiUgCiAgIyByZWNhbGN1bGF0ZSB0aGUgaW50ZXJ2YWwgc2luY2Ugd2UgYXJlIG5vdyBsaW1pdGluZyB0aGUgaGl0cyB0byA+PSAzMAogIG11dGF0ZShpbnRlcnZhbCA9IHN0YXJ0IC0gbGFnKGVuZCkgLSAxKSAlPiUgCiAgIyBzdW1tYXJpemUgdGhlIHJlc3VsdHMgYXQgYSBzZXF1ZW5jZSBsZXZlbAogIHN1bW1hcml6ZShuLmFsbCA9IG4oKSwKICAgICAgICAgICAgbi50eXBlID0gbGVuZ3RoKHVuaXF1ZShzZXEpKSwKICAgICAgICAgICAgbWVkU2NvcmUgPSByb3VuZChtZWFuKG1lZGlhbiksMSksCiAgICAgICAgICAgIElWVCA9IHJvdW5kKG1lYW4oaXZ0KSwyKSwKICAgICAgICAgICAgYXZnLmludHYgPSByb3VuZChtZWFuKGludGVydmFsLCBuYS5ybSA9IFQpLDEpLCAKICAgICAgICAgICAgSVFSLmludHYgPSByb3VuZChJUVIoaW50ZXJ2YWwsIG5hLnJtID0gVCkvMS4zNDkgLDEpLAogICAgICAgICAgICAjIG1lZGlhbiBhYnNvbHV0ZSBkZXZpYXRpb24gaXMgYSByb2J1c3QgbWVhc3VyZSBvZiB0aGUgc2NhbGUgcGFyYW1ldGVyCiAgICAgICAgICAgICMgaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL3N0YXRzL3ZlcnNpb25zLzMuNi4yL3RvcGljcy9tYWQKICAgICAgICAgICAgbWFkLmludHYgPSByb3VuZChtYWQoaW50ZXJ2YWwsIG5hLnJtID0gVCksMSksCiAgICAgICAgICAgIHNlcXMgPSBwYXN0ZSh1bmlxdWUoc2VxKSwgY29sbGFwc2UgPSAiLCIpLAogICAgICAgICAgICAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgcmlnaHRfam9pbihzZWxlY3Qoc2VxSW5mbywgc3RyYWluLCBpZCA9IG5hbWUsIGxlbmd0aCwgaXNISUwpLCBieSA9ICJpZCIpICU+JSAKICBtdXRhdGUobi5hbGwgPSBpZmVsc2UoaXMubmEobi5hbGwpLCAwLCBuLmFsbCksIG4udHlwZSA9IGlmZWxzZShpcy5uYShuLnR5cGUpLCAwLCBuLnR5cGUpKSAlPiUgCiAgYXJyYW5nZShkZXNjKG4uYWxsKSwgZGVzYyhtYWQuaW50dikpCiNtb3RpZi5wZXIuc2VxCmBgYAoKRGlzdHJpYnV0aW9uIG9mIHRoZSBudW1iZXIgb2YgVEFOR08gaGl0cyBwZXIga2lsbyBhbWlubyBhY2lkcyBwcm90ZWluIGFjcm9zcyB0aGUgcHJvdGVvbWUuCgpgYGB7cn0KZ2dwbG90KG1vdGlmLnBlci5zZXEsIGFlcyh4ID0gc3RyYWluLCB5ID0gbi5hbGwvbGVuZ3RoKjEwMDApKSArIAogIGdlb21fYm94cGxvdChmaWxsID0gImdyYXk3MCIsIGFscGhhID0gMC43LCBvdXRsaWVyLmFscGhhID0gMC4yKSArIHlsYWIoIiMgb2YgVEFOR08gaGl0cyBwZXIgMTAwMCBhbWlubyBhY2lkcyIpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gZmlsdGVyKG1vdGlmLnBlci5zZXEsIGlzSElMKSwgYWVzKGNvbG9yID0gbGVuZ3RoKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoMC4wNSksIHNpemUgPSAxLjUpICsKICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoKSArCiAgdGhlbWVfY293cGxvdCgpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSA4IEhpbCBvcnRob2xvZ3MgZmFsbCBpbnRvIHR3byBncm91cHMuIEhpbDEtNCwgd2hpY2ggYXJlIGxvbmdlciB0aGFuIDEwMDAgYW1pbm8gYWNpZHMsIGhhdmUgcmVsYXRpdmVseSBoaWdoIG51bWJlciBvZiBUQU5HTyBoaXRzIHJlbGF0aXZlIHRvIHRoZWlyIGxlbmd0aC4gSW4gZmFjdCwgdGhleSBhcmUgYWxsIGFib3ZlIDg5JSBwZXJjZW50aWxlIG9mIHRoZSBkYXRhLgoKQ29tcGFyZSB0aGUgZGlzdHJpYnV0aW9uIG9mIFRBTkdPIGhpdHMgXCMgYW5kIHNjb3JlIGluIHRoZSBIaWwgZmFtaWx5IHZzIHRoZSBwcm90ZW9tZQoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9NC41fQpnZ3Bsb3QobW90aWYucGVyLnNlcSwgYWVzKHggPSBsZW5ndGgsIHkgPSBuLmFsbC9sZW5ndGgqMTAwMCkpICsgCiAgZ2VvbV9iaW5fMmQoYmlud2lkdGggPSBjKDIwMCwgMikpICsgc2NhbGVfZmlsbF92aXJpZGlzX2MoKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IGZpbHRlcihtb3RpZi5wZXIuc2VxLCBpc0hJTCksIGNvbG9yID0gInJlZCIpICsKICB4bGFiKCJQcm90ZWluIGxlbmd0aCIpICsgeWxhYigiIyBvZiBUQU5HTyBoaXRzIHBlciAxMDAwIGFtaW5vIGFjaWRzIikgKyAKICBmYWNldF93cmFwKH5zdHJhaW4sIG5yb3cgPSAyKSArIHRoZW1lX2dyZXkoYmFzZV9zaXplID0gMTQpCmBgYAoKKioqRGlzY3Vzc2lvbioqKgoKLSAgIHRoaXMgaXMgYW5vdGhlciB3YXkgb2YgcGxvdHRpbmcgdGhlIHNhbWUgZGF0YSwgYWdhaW4gc2hvd2luZyB0aGF0IEhpbDEtNCBhcmUgZXhjZXB0aW9uYWwgaW4gdGhlIHByb3Rlb21lIGluIHRoYXQgdGhleSBoYXJib3IgYSB2ZXJ5IGhpZ2ggYW1vdW50IG9mIFRBTkdPIGhpdHMgcGVyIDEwMDAgYW1pbm8gYWNpZCByZXNpZHVlcyByZWxhdGl2ZSB0byBwcm90ZWlucyBvZiBzaW1pbGFyIGxlbmd0aCB0byB0aGVtLgoKTmV4dCB3ZSBhZGQgdGhlIFRBTkdPIGluZm9ybWF0aW9uIHRvIHRoZSBzZXFJbmZvIGRhdGFzZXQuCgpgYGB7cn0KaWYoIm4udGFuZ28iICVpbiUgbmFtZXMoc2VxSW5mbykpewogIHNlcUluZm8gPC0gc2VxSW5mbyAlPiUgCiAgICBzZWxlY3QoLW4udGFuZ28sIC1yZWcuc3BhY2VkKQp9CnNlcUluZm8gPC0gc2VxSW5mbyAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChtb3RpZi5wZXIuc2VxLCBuYW1lID0gaWQsIG4udGFuZ28gPSBuLmFsbCwgbWFkLmludHYpLCBieSA9ICJuYW1lIikgJT4lIAogIG11dGF0ZShtYWQuaW50diA9IGlmZWxzZShuLnRhbmdvID4gMiwgbWFkLmludHYsIE5BKSwKICAgICAgICAgcmVnLnNwYWNlZCA9IGlmZWxzZShuLnRhbmdvID4gMyAmIG1hZC5pbnR2IDwgNSwgVFJVRSwgRkFMU0UpKSAlPiUgCiAgc2VsZWN0KC1tYWQuaW50dikKYGBgCgojIyMjIFN1bW1hcml6ZSB0YW5nbyByZXN1bHRzIGZvciB0YWJsZQoKVGhyZWUgbWV0cmljcyBmb3IgdGhlIGJ5IHByb3RlaW4gdGFuZ28gcmVzdWx0cyBjYW4gYmUgbnVtYmVyIG9mIHBhdDAgKEdWVklWVFQpIHNlcXVlbmNlcywgcGF0MSAoR1ZWSVZUVC1saWtlKSBzZXF1ZW5jZXMsIGFuZCB0b3RhbCBudW1iZXIgb2YgYWdncmVnYXRpb24gc2VxdWVuY2VzIHdpdGggc2NvcmUgXD4gMzAKCioqVXBkYXRlIDIwMjEtMDctMTUgW0hCXSoqIFRoZSBjb2RlIGJlbG93IGlzIG5vIGxvbmdlciBpbmNsdWRlZCBiZWNhdXNlIHRoZSBhYm92ZSBhbmFseXNlc2UgaGF2ZSBzaG93biB0aGF0IEdWVklWVFQgYW5kIGl0cyB2YXJpYW50cyBhcmUgaGlnaGx5IHNwZWNpZmljIHRvIHRoZSBIaWwgZmFtaWx5LCB3aGljaCBhcHBlYXJzIHRvIGJlIGFuIG91dGxpZXIgaW4gdGVybXMgb2YgVEFOR08gaGl0cyBwZXIgcHJvdGVpbiBpbiB0aGUgZW50aXJlIHByb3Rlb21lLiBJbiBwcmVkaWN0aW5nIGFkZGl0aW9uYWwgYWRoZXNpbnMsIHdlIHdpbGwgb25seSBsb29rIGF0IHRoZSB0b3RhbCBudW1iZXIgb2YgVEFOR08gaGl0cy4KCmBgYHIKIyBjb3JlIGdyb3VwLCBtdXN0IGJlIEctW1ZJXXg0LVRUCnBhdDAgPC0gIkdbVkldezR9VFQiCiMgdmVyc2lvbiAxLCByZXF1aXJlcyBHLVtBTFZJXVtWSV1bTFZJXVtWSV0tKGVpdGhlciBlbmQgb2Ygc3RyaW5nIG9yIGF0IGxlYXN0IDEgc3VpdGFibGUgcmVzaWR1ZSkgCiMgICAgICAgICAgICAgICAgICBPUiAoRyBub3QgcmVxdWlyZWQpLVtWSV14NC0odHdvIHN1aXRhYmxlIHJlc2lkdWVzKQpwYXQxIDwtICJHW0FMVkldW1ZJXVtMVkldW1ZJXShbTFZJRkFXWVRNXXsxLDJ9fCQpfFtWSV17NH1bTFZJRkFXWVRNXXsyfSIKcGF0MiA8LSAiW1ZJXVtWSVZNXVtWSV1bVkldVCIKbWF0Y2gwIDwtIGdyZXAocGF0MCwgbW90aWYucGVyLnNlcSRzZXEpCm1hdGNoMSA8LSBncmVwKHBhdDEsIG1vdGlmLnBlci5zZXEkc2VxKQptYXRjaDIgPC0gZ3JlcChwYXQyLCBtb3RpZi5wZXIuc2VxJHNlcSkKdGFuZ28uc3VtbSA8LSBzZXFJbmZvWywibmFtZSJdICU+JQogICMgYWRkIHBhdDAgcmVzdWx0cwogIGxlZnRfam9pbihtb3RpZi5wZXIuc2VxW21hdGNoMCxdICU+JSBncm91cF9ieShpZCkgJT4lIHN1bW1hcmlzZShuLmd2dml2dHQuc2VxcyA9IHN1bShuKSksIGJ5ID0gYygibmFtZSIgPSAiaWQiKSkgJT4lIAogICMgYWRkIHBhdDEgcmVzdWx0cwogIGxlZnRfam9pbihtb3RpZi5wZXIuc2VxW3NldGRpZmYobWF0Y2gxLCBtYXRjaDApLF0gJT4lIGdyb3VwX2J5KGlkKSAlPiUgc3VtbWFyaXNlKG4uZ3Z2aXZ0dC5saWtlLnNlcXMgPSBzdW0obikpLCBieSA9IGMoIm5hbWUiID0gImlkIikpICU+JSAKICAjIGFkZCBwYXQyIHJlc3VsdHMgLSBwYXQyIGZyb20gRmFzc2xlciBtYW51YWwgY3VyYXRpb24gb2YgVEFOR08gcG9zaXRpdmUgc2VxdWVuY2VzIGZyb20gRnVuZ2FsUlYgcG9zaXRpdmUgcHJvdGVpbnMgaW4gQy4gbHVzaXRhbmVhZSwgQy4gYXVyaXMsIEMuIGhhZW11bG9uaXMsIEMuIHBzZXVkb2hhZW11bG9uaXMsIEMuIGR1b2hhZW11bG9uaXMsIFMuIHN0aXBpdGlzLCBTLiBjZXJldmlzaWFlLCBhbmQgQy4gZ2xhYnJhdGEgaW50byBHVlZJVlRULWxpa2UgYW5kIG5vbiBHVlZJVlRUIGdyb3VwcwogIGxlZnRfam9pbihtb3RpZi5wZXIuc2VxW21hdGNoMixdICU+JSBncm91cF9ieShpZCkgJT4lIHN1bW1hcmlzZShuLnZ2dnZ0LnNlcXMgPSBzdW0obikpLCBieSA9IGMoIm5hbWUiID0gImlkIikpICU+JSAKICAjIGFkZCBtb3RpZi5wZXIuc2VxIHJlc3VsdHMKICBsZWZ0X2pvaW4obW90aWYucGVyLnNlcSAlPiUgZ3JvdXBfYnkoaWQpICU+JSBzdW1tYXJpc2Uobi5oaWdoLnNjb3JlLmFnZy5zZXEgPSBzdW0obikpLCBieSA9IGMoIm5hbWUiID0gImlkIikpCiMgam9pbiB0byBzZXFJbmZvIHRhYmxlCiMgcmVtb3ZlIHRoZSBjb2x1bW4gaWYgaXQgYWxyZWFkeSBleGlzdHMKaWYoIm4uZ3Z2aXZ0dC5zZXFzIiAlaW4lIG5hbWVzKHNlcUluZm8pKQogIHNlcUluZm8gPC0gc2VsZWN0KHNlcUluZm8sIC1uLmd2dml2dHQuc2VxcywgLW4uZ3Z2aXZ0dC5saWtlLnNlcXMsIC1uLnZ2dnZ0LnNlcXMsIC1uLmhpZ2guc2NvcmUuYWdnLnNlcSkKc2VxSW5mbyA8LSBsZWZ0X2pvaW4oc2VxSW5mbywgdGFuZ28uc3VtbSkKc2VxSW5mbyA8LSBzZXFJbmZvICU+JSBtdXRhdGUobi5ndnZpdnR0LnNlcXMgPSByZXBsYWNlX25hKG4uZ3Z2aXZ0dC5zZXFzLDApLCBuLmd2dml2dHQubGlrZS5zZXFzID0gcmVwbGFjZV9uYShuLmd2dml2dHQubGlrZS5zZXFzLDApLCBuLnZ2dnZ0LnNlcXMgPSByZXBsYWNlX25hKG4udnZ2dnQuc2VxcywwKSwgbi5oaWdoLnNjb3JlLmFnZy5zZXEgPSByZXBsYWNlX25hKG4uaGlnaC5zY29yZS5hZ2cuc2VxLDApKQpgYGAKCiMjIFMvVCBmcmVxdWVuY3kKClVzaW5nIEJpbidzIG1ldGhvZCwgSSdtIHJ1bm5pbmcgRU1CT1NTIGZyZWFrIGZvciBTL1QsIFMsIFQgd2l0aCBhIHN0ZXBwaW5nIHZhbHVlIG9mIDEwIGFuZCBhbiBhdmVyYWdpbmcgd2luZG93IG9mIDEwMC4gVGhlIHJlc3VsdHMgd2VyZSBzYXZlZCBhcyBmcmVha19hbWlub2FjaWQocylcXzEwMF8xMC50eHQuIFVzaW5nIEJpbidzIGZvcm1hdF9mcmVhcV9vdXRwdXQucHkgc2NyaXB0LCBlYWNoIHdhcyBjb252ZXJ0ZWQgdG8gYSByZWFkYWJsZSAub3V0IGZpbGUgYW5kIGFsbCBmaWxlcyB3ZXJlIGNvbXByZXNzZWQgZm9yIHN0b3JhZ2UuCgoqKlVwZGF0ZSAyMDIxLTA3LTE2IFtIQl0qKiB3ZSB3aWxsIHVzZSB0d28gdHlwZXMgb2Ygc3RhdGlzdGljcyB0byBzdW1tYXJpemUgdGhlIHNlcmluZS90aHJlb25pbmUgZnJlcXVlbmNpZXMgaGVyZS4gMSkgZnJlcXVlbmN5IG9mIHRoZSByZXNpZHVlcyBvdmVyIHRoZSBlbnRpcmUgcHJvdGVpbjsgMikgbWF4aW11bSBmcmVxdWVuY3kgb2Ygc2VyaW5lIG9yIHRocmVub25pbmUgaW4gYSAxMDAgYW1pbm8gYWNpZCBzbGlkaW5nIHdpbmRvdyAod2hpY2ggd2lsbCBpZ25vcmUgYW55IHByb3RlaW5zIFw8IDEwMCByZXNpZHVlcykuIGluIHRoZSBzZWNvbmQgbWVhc3VyZSwgd2UgcmVhc29uIHRoYXQgYSAxMDAgYW1pbm8gYWNpZCB3aW5kb3cgaXMgYSByZWFzb25hYmxlIHNpemUgdG8gY2FwdHVyZSBhIGdlbnVpbmUgImhpa2UiIGluIFNlcmluZSBvciBUaHJlb25pbmUgZnJlcXVlbmN5LiBGb3Igb25lIHRoaW5nLCBpdCBpcyBsYXJnZSBlbm91Z2ggdG8gYXZvaWQgY2FwdHVyaW5nIGp1c3QgYSBzbWFsbCBjbHVzdGVyIG9mIFMvVCwgYW5kIGZvciBhbm90aGVyIHRoaW5nIHRoZSBTZXJpbmUgcmljaCBjbHVzdGVyIHdlIG9ic2VydmUgaW4gSGlsMSBpcyBcfjIwMCBhbWlubyBhY2lkcyBsb25nIGFuZCB3aXRoIGEgY29uc2lzdGVudGx5IGVsZXZhdGVkIFNlcmluZSBjb250ZW50LCBzdWdnZXN0aW5nIHRoYXQgYSAxMDAgYW1pbm8gYWNpZCB3aW5kb3cgaXMgbm90IHRvbyBsYXJnZSB0byBsZWFkIHRvIGRpbHV0ZWQgc2lnbmFscyBieSBmbGFua2luZyByZXNpZHVlcy4KCmBgYHtyIFNfVF9mcmVxfQojIGxvYWQgZGF0YQpTVC5wcm90ZWluIDwtIHJlYWRfdHN2KCJvdXRwdXQvU1QtZnJlcS9DYXVyaXMtU1QtZnJlcS1wZXItcHJvdGVpbi50eHQuZ3oiLCBjb2xfdHlwZXMgPSBjb2xzKCkpClNULmZyZXEgPC0gcmVhZF90c3YoIm91dHB1dC9TVC1mcmVxL2ZyZWFrX3N0XzEwMF8xMF9mcmVhay5vdXQuZ3oiLCBjb2xfdHlwZXMgPSAiY2lkIikKUy5mcmVxIDwtIHJlYWRfdHN2KCJvdXRwdXQvU1QtZnJlcS9mcmVha19zXzEwMF8xMF9mcmVhay5vdXQuZ3oiLCBjb2xfdHlwZXMgPSAiY2lkIikKVC5mcmVxIDwtIHJlYWRfdHN2KCJvdXRwdXQvU1QtZnJlcS9mcmVha190XzEwMF8xMF9mcmVhay5vdXQuZ3oiLCBjb2xfdHlwZXMgPSAiY2lkIikKU1Qud2luZG93IDwtIGJpbmRfcm93cygiU1QiID0gU1QuZnJlcSwgIlMiID0gUy5mcmVxLCAiVCIgPSBULmZyZXEsIC5pZCA9ICJyZXNpZHVlIikgJT4lIAogIGdyb3VwX2J5KGlkLCByZXNpZHVlKSAlPiUgCiAgc3VtbWFyaXplKG1heCA9IG1heChmcmVxKSkKcm0obGlzdCA9IGMoIlNULmZyZXEiLCAiUy5mcmVxIiwgIlQuZnJlcSIpKQpgYGAKCmBgYHtyIGZpZy5jYXA9IlNlci9UaHIifQpTVC53aW5kb3cgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2VxSW5mbywgaWQgPSBuYW1lLCBpc0hJTCksIGJ5ID0gImlkIikgJT4lIAogIG11dGF0ZShyZXNpZHVlID0gZmFjdG9yKHJlc2lkdWUsIGxldmVscyA9IGMoIlNUIiwgIlMiLCAiVCIpLCBsYWJlbHMgPSBjKCJTZXIvVGhyIiwgIlNlciIsICJUaHIiKSksCiAgICAgICAgIGBIaWwgZmFtaWx5YCA9IGlmZWxzZShpc0hJTCwgIlllcyIsICJObyIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbWF4KSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuMDIpICsgCiAgeGxhYigiTWF4IGZyZXF1ZW5jeSBvZiBTZXIvVGhyIGluIDEwMCBhbWlubyBhY2lkIHdpbmRvdyIpICsgc2NhbGVfeV9jb250aW51b3VzKHBvc2l0aW9uID0gInJpZ2h0IikgKwogIGZhY2V0X2dyaWQoYEhpbCBmYW1pbHlgIH4gcmVzaWR1ZSwgc2NhbGVzID0gImZyZWVfeSIsIGxhYmVsbGVyID0gImxhYmVsX2JvdGgiLCBzd2l0Y2ggPSAieSIpICsKICB0aGVtZV9jb3dwbG90KCkgKyBwYW5lbF9ib3JkZXIoKQpgYGAKCioqKkRpc2N1c3Npb24qKioKCkZyb20gdGhlIGFib3ZlIHdlIGNhbiBzZWUgdGhhdCB0aGUgbm90IGFsbCBIaWwgZmFtaWx5IHByb3RlaW5zIGhhdmUgd2VsbC1hYm92ZS1hdmVyYWdlIFNlcmluZSBvciBUaHJlb25pbmUgY29udGVudCBhbG9uZS4gQnV0IHdoZW4gYm90aCByZXNpZHVlcyBhcmUgY291bnRlZCB0b2dldGhlciwgdGhleSBjb25zaXN0ZW50bHkgcmFuayBhYm92ZSB0aGUgbWFqb3JpdHkgb2YgdGhlIHByb3Rlb21lLgoKYGBge3J9ClNULnByb3RlaW4gJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2VxSW5mbywgSUQgPSBuYW1lLCBpc0hJTCksIGJ5ID0gIklEIikgJT4lIAogIG11dGF0ZShgU2VyL1RocmAgPSAoU2VyK1RocikvbGVuZ3RoLCBTZXIgPSBTZXIvbGVuZ3RoLCBUaHIgPSBUaHIvbGVuZ3RoKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGBTZXIvVGhyYCwgU2VyLCBUaHIpLCBuYW1lc190byA9ICJyZXNpZHVlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIAogIG11dGF0ZShyZXNpZHVlID0gZmFjdG9yKHJlc2lkdWUsIGxldmVscyA9IGMoIlNlci9UaHIiLCAiU2VyIiwgIlRociIpKSwKICAgICAgICAgYEhpbCBmYW1pbHlgID0gaWZlbHNlKGlzSElMLCAiWWVzIiwgIk5vIikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB2YWx1ZSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjAyKSArIAogIHhsYWIoIkZyZXF1ZW5jeSBvZiBTZXIvVGhyIGluIHRoZSB3aG9sZSBwcm90ZWluIikgKyBzY2FsZV95X2NvbnRpbnVvdXMocG9zaXRpb24gPSAicmlnaHQiKSArCiAgZmFjZXRfZ3JpZChgSGlsIGZhbWlseWAgfiByZXNpZHVlLCBzY2FsZXMgPSAiZnJlZV95IiwgbGFiZWxsZXIgPSAibGFiZWxfYm90aCIsIHN3aXRjaCA9ICJ5IikgKwogIHRoZW1lX2Nvd3Bsb3QoKSArIHBhbmVsX2JvcmRlcigpCmBgYAoKKioqRGlzY3Vzc2lvbioqKgoKU2ltaWxhciBhcyBhYm92ZSwgd2Ugc2VlIHRoYXQgdGhlIGNvbWJpbmVkIFNlci9UaHIgZnJlcXVlbmN5IGFwcGVhciB0byBiZXR0ZXIgZGlzdGluZ3Vpc2ggdGhlIEhpbCBmYW1pbHkgZnJvbSB0aGUgcmVzdCBvZiB0aGUgcHJvdGVpbnMuIEZvciB0aGlzIHJlYXNvbiBsZXQncyBhZGQgdGhlIG1heCBTL1QgZnJlcXVlbmN5IGluIDEwMCBhbWlubyBhY2lkIHdpbmRvd3MgYW5kIHRoZSBvdmVyYWxsIFMvVCBmcmVxdWVuY3kgcGVyIHByb3RlaW4gdG8gYHNlcUluZm9gCgpgYGB7cn0KI3JlbW92ZSBjb2x1bW5zIGlmIHByZXNlbnQKaWYoIlNULnByb3QiICVpbiUgbmFtZXMoc2VxSW5mbykpCiAgc2VxSW5mbyA8LSBzZWxlY3Qoc2VxSW5mbywgLVNULnByb3QsIC1TVC53aW5kb3cubWF4KQoKI2pvaW4gbWF4aW11bXMgYmFjayBpbnRvIHNlcUluZm8KdG1wIDwtIFNULnByb3RlaW4gJT4lIAogIG11dGF0ZShTVC5wcm90ID0gcm91bmQoKFNlcitUaHIpL2xlbmd0aCwgMykpICU+JSAKICBzZWxlY3QobmFtZSA9IElELCBTVC5wcm90KSAlPiUgCiAgbGVmdF9qb2luKFNULndpbmRvdyAlPiUgZmlsdGVyKHJlc2lkdWUgPT0gIlNUIikgJT4lIHNlbGVjdChuYW1lID0gaWQsIFNULndpbmRvdy5tYXggPSBtYXgpLCBieSA9ICJuYW1lIikgJT4lIAogICMgZm9yIHByb3RlaW5zIHNob3J0ZXIgdGhhbiAxMDAgYS5hLiwgdGhlIHNsaWRpbmcgd2luZG93IGVzdGltYXRlIHdvdWxkIGJlIE5BLiByZXBsYWNlIGl0IHdpdGggd2hvbGUgcHJvdGVpbiBlc3RpbWF0ZSBpbiBTVC5wcm90ZWluCiAgbXV0YXRlKFNULndpbmRvdy5tYXggPSByb3VuZChjb2FsZXNjZShTVC53aW5kb3cubWF4LCBTVC5wcm90KSwzKSkKCnNlcUluZm8gPC0gc2VxSW5mbyAlPiUgbGVmdF9qb2luKHRtcCwgYnkgPSAibmFtZSIpCiMgcm0obGlzdCA9IGMoIlNULnByb3RlaW4iLCAiU1Qud2luZG93IikpCmBgYAoKV3JpdGUgdGhlIGBzZXFJbmZvYCB0byBhIGZpbGUgdG8gYmUgaW5jbHVkZWQgYXMgc3VwcGxlbWVudGFyeSBkYXRhCmBgYHtyfQpzZXFJbmZvICU+JSAKICBzZWxlY3QoLXBmYW1fZG9tYWlucywgcGZhbV9kb21haW5zKSAlPiUgCiAgd3JpdGVfdHN2KGZpbGUgPSAib3V0cHV0L1JtZC1vdXQvc2VxSW5mb190YWJsZV9hbGwudHN2IikKYGBgCgojIFByZWRpY3Rpb24KCkhlcmUgd2UgdHJ5IHRvIHVzZSB0aGUgc2VxdWVuY2UgcHJvcGVydGllcyBjb2xsZWN0ZWQgYWJvdmUgdG8gaWRlbnRpZnkgYWRkaXRpb25hbCBwcm90ZWlucyBvdXRzaWRlIG9mIHRoZSBIaWwgZmFtaWx5IHRoYXQgbWF5IGZ1bmN0aW9uIGFzIGFkaGVzaW5zLiBUaGUgaWRlYSBoZXJlIGlzIHRvIGFwcGx5IGZpbHRlcnMgaW4gYSBzdGVwLXdpc2UgbWFubmVyIGFuZCB3YXRjaCBpZiBhbGwgSGlsIHByb3RlaW5zIGFyZSBzdGlsbCByZXRhaW5lZCBhbmQgaG93IG1hbnkgbm9uLUhpbCBwcm90ZWlucyByZW1haW4gaW4gdGhlIGRhdGFzZXQuCgojIyBDZWxsIHdhbGwgcHJvdGVpbnMKCkhvdyBtYW55IHByb3RlaW5zIGFyZSBsaWtlbHkgdG8gYmUgR1BJLWFuY2hvcmVkIGNlbGwgd2FsbCBwcm90ZWlucz8KYGBge3J9CiMgTG9hZCBmdW5jdGlvbgojIHJlZmVyZW5jZTogaHR0cDovL3JzdHVkaW8tcHVicy1zdGF0aWMuczMuYW1hem9uYXdzLmNvbS82OTc1X2M0OTQzMzQ5YjYxNzRmNDQ4MTA0YTU1MTNmZWQ1OWE5Lmh0bWwKc291cmNlKCJodHRwOi8vcGN3d3cubGl2LmFjLnVrL353aWxsaWFtL1IvY3Jvc3N0YWIuciIpCgpjcm9zc3RhYihzZXFJbmZvLCByb3cudmFycyA9ICJzaWduYWxwIiwgY29sLnZhcnMgPSAicHJlZC5ncGkiLCB0eXBlID0gYygiZiIsICJ0IiksIGRlYy5wbGFjZXMgPSAxLCBhZGRtYXJnaW5zID0gRkFMU0UpCmBgYAoKV2Ugc2VlIHRoYXQgb25seSBhIHZlcnkgc21hbGwgZnJhY3Rpb24gKDEuNSUpIG9mIHRoZSBwcm90ZW9tZSBwYXNzIGJvdGggdGhlIFNpZ25hbFAgYW5kIFByZWRHUEkgdGVzdHMuIEJ5IGNvbXBhcmlzb24sIGFsbCBlaWdodCAqQy4gYXVyaXMqIEhpbCBwcm90ZWlucyBwYXNzIGJvdGggdGVzdHMsIGFuZCB0aGUgdmFzdCBtYWpvcml0eSBvZiBIaWwgaG9tb2xvZ3MgcGFzcyBib3RoIHRlc3RzIGFzIHdlbGwuIFNvIGZhciB0aGlzIGlzIHRoZSBtb3N0IHN0cmluZ2VudCAoYWthIGVmZmVjdGl2ZSkgZmlsdGVyIHRvIHJlZHVjZSB0aGUgbnVtYmVyIG9mIGNhbmRpZGF0ZSBwcm90ZWlucy4KCioqVXBkYXRlIDIwMjEtMDctMjcgW0hCXSoqIEZvbGxvd2luZyB0aGUgZGlzY3Vzc2lvbiBvbiBHUEktQ1dQIHZzIEdQSS1QTVAgKHNlZSBub3RlcyBpbiB0aGUgW1ByZWRHUEldKCNwcmVkZ3BpKSBzZWN0aW9uIGFib3ZlKSwgd2Ugd2lsbCBhZGRpdGlvbmFsbHkgdGVzdCB3aGV0aGVyIHByb3RlaW5zIHdpdGggU2lnbmFsIFBlcHRpZGUgYW5kIEdQSS1hbmNob3IgYWxzbyBoYXZlIGxvdyAoPDMwJSkgU2VyL1RociBmcmVxdWVuY3kgYW5kIHRoZSBwcmVzZW5jZSBvZiBhIGRpYmFzaWMgbW90aWYKCmBgYHtyfQpmaWx0ZXIxIDwtIHNlcUluZm8gJT4lIAogIG11dGF0ZShgSGlsX2ZhbWlseWAgPSBpZmVsc2UoaXNISUwsICJZZXMiLCAiTm8iKSwgCiAgICAgICAgIGBHUElgID0gaWZlbHNlKHNpZ25hbHAgJiBwcmVkLmdwaSwgaWZlbHNlKFNULnByb3QgPCAwLjMgJiAhaXMubmEoZGliYXNpYyksICJQTVAiLCAiQ1dQIiksICdObycpLAogICAgICAgICBgR1BJYCA9IGZhY3RvcihHUEksIGxldmVscyA9IGMoIk5vIiwgIkNXUCIsICJQTVAiKSkpICU+JSAKICBzZWxlY3QoLXNpZ25hbHAsIC1wcmVkLmdwaSwgLWlzSElMKQoKY3Jvc3N0YWIoZmlsdGVyMSwgcm93LnZhcnMgPSAiR1BJIiwgY29sLnZhcnMgPSAiSGlsX2ZhbWlseSIsIGFkZG1hcmdpbnMgPSBGQUxTRSkKYGBgCgpUaGUgdHdvIHByb3RlaW5zIHRoYXQgZHJvcHBlZCBvdXQgYHIgZmlsdGVyMSAlPiUgZmlsdGVyKEdQSSA9PSAiTm8iLCBIaWxfZmFtaWx5ID09ICJZZXMiKWAgYXJlIGJvdGggaW4gdGhlIGNsYWRlIElWIHN0cmFpbiBCMTEyNDUgYW5kIGFwcGVhciB0byBiZSBtaXNzaW5nIHRoZSBDLXRlcm1pbmFsIHNlcXVlbmNlLCBoZW5jZSBmYWlsZWQgdGhlIFByZWRHUEkgdGVzdC4KCkFuZCB0aGUgUE1QcyBhcmUgc2hvd24gYmVsb3cgYHIgZmlsdGVyMSAlPiUgZmlsdGVyKEdQSSA9PSAiUE1QIilgCgojIyBQcm90ZWluIGxlbmd0aApCZWxvdyB3ZSBzaG93IHRoZSBkaXN0cmlidXRpb24gb2YgcHJvdGVpbiBsZW5ndGggaW4gdGhlIHByb3Rlb21lLgpgYGB7cn0KcCA8LSBnZ3Bsb3QoZGF0YSA9IHNlcUluZm8pICsgCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4PWxlbmd0aCksIGJpbndpZHRoID0gNTApKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSA1MDApLCBjb2xvcj0iYmx1ZSIsIHNpemU9MSkgKwogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDMwMDAsIHkgPSAxNTAwLCBsYWJlbCA9IHBhc3RlMCgiIyBvZiBwcm90ZWlucyA+PSA1MDAgcmVzaWR1ZXM6ICIsIHN1bShzZXFJbmZvJGxlbmd0aCA+PSA1MDApKSwgc2l6ZSA9IDUpICsKICB4bGFiKCJQcm90ZWluIGxlbmd0aCAoYW1pbm8gYWNpZHMpIikgKyB5bGFiKCIjIG9mIHByb3RlaW5zIikgKyB0aGVtZV9jb3dwbG90KCkKcHJpbnQocCkKYGBgCgpXZSBjbGFzc2lmeSB0aGUgQ1dQIGhpdHMgaW50byB0d28gZ3JvdXBzIGJhc2VkIG9uIHRoZWlyIGxlbmd0aC4gVGhvc2Ugd2l0aCBtb3JlIHRoYW4gNTAwIGEuYS4gYXJlIGxhYmVsZWQgYXMgIkNXUCBsb25nIiBhbmQgdGhvc2Ugc21hbGxlciB0aGFuIDUwMCBhLmEuIGFzICJDV1Agc2hvcnQiLgoKYGBge3J9CmZpbHRlcjIgPC0gZmlsdGVyMSAlPiUgCiAgbXV0YXRlKExlbiA9IGlmZWxzZShsZW5ndGggPj0gNTAwLCAiPj01MDAiLCAiPDUwMCIpLAogICAgICAgICAjIGdyb3VwMSBpcyB0aGUgb2xkIGRlZmluaXRpb24KICAgICAgICAgIyBncm91cDEgPSBpZmVsc2UoSGlsX2ZhbWlseSA9PSAiWWVzIiwgICAgICAgICAgICAgIyBncm91cCAxOiBIaWwgZmFtaWx5CiAgICAgICAgICMgICAgICAgICAgICAgICAgIkhpbCIsIGlmZWxzZShHUEkgIT0gIk5vIiwgICAgICAgICMgZ3JvdXAgMiYzOiBjZWxsIHdhbGwgbG9uZyAvIHNob3J0CiAgICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobGVuZ3RoID49NTAwLCAiQ1dQIGxvbmciLCAiQ1dQIHNob3J0IiksIAogICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk90aGVycyIpKSwgICAgICAgICAjIGdyb3VwIDQ6IE90aGVycwogICAgICAgICAjIGdyb3VwMSA9IGZhY3Rvcihncm91cDEsIGxldmVscyA9IGMoIkhpbCIsICJDV1AgbG9uZyIsICJDV1Agc2hvcnQiLCAiT3RoZXJzIikpLAogICAgICAgICAjIGdyb3VwIGlzIHRoZSBuZXcgZGVmaW5pdGlvbgogICAgICAgICBHUEkgPSBhcy5jaGFyYWN0ZXIoR1BJKSwgIyBuZWNlc3NhcnkgZm9yIHRoZSBjYXNlX3doZW4oKSBzdGF0ZW1lbnRzCiAgICAgICAgIGdyb3VwID0gY2FzZV93aGVuKAogICAgICAgICAgIEhpbF9mYW1pbHkgPT0gIlllcyIgfiAiSGlsIiwKICAgICAgICAgICBHUEkgPT0gIkNXUCIgJiBsZW5ndGggPj0gNTAwIH4gIkNXUCBsb25nIiwKICAgICAgICAgICBHUEkgPT0gIkNXUCIgJiBsZW5ndGggPCA1MDAgIH4gIkNXUCBzaG9ydCIsCiAgICAgICAgICAgR1BJID09ICJQTVAiIH4gIlBNUCIsCiAgICAgICAgICAgR1BJID09ICJObyIgfiAiT3RoZXJzIiwKICAgICAgICAgKSwKICAgICAgICAgZ3JvdXAgPSBmYWN0b3IoZ3JvdXAsIGxldmVscyA9IGMoIkhpbCIsICJDV1AgbG9uZyIsICJDV1Agc2hvcnQiLCAiUE1QIiwgIk90aGVycyIpKSkKCmNyb3NzdGFiKGZpbHRlcjIsIHJvdy52YXJzID0gImdyb3VwIikKYGBgCgojIyBTZXIvVGhyIGZyZXF1ZW5jeQoKYGBge3J9CnNlcUluZm8gJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gc3RhcnRzX3dpdGgoIlNULiIpLCBuYW1lc190byA9ICJ0eXBlIiwgbmFtZXNfcHJlZml4ID0gIlNULiIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JSAKICBtdXRhdGUodHlwZSA9IGZhY3Rvcih0eXBlLCBsZXZlbHMgPSBjKCJwcm90IiwgIndpbmRvdy5tYXgiKSwgbGFiZWxzID0gYygid2hvbGUgcHJvdGVpbiIsICJtYXggaW4gMTAwIGEuYS4gd2luZG93cyIpKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHZhbHVlLCBjb2xvciA9IGlzSElMKSkgKyBzdGF0X2VjZGYoKSArIGZhY2V0X3dyYXAofnR5cGUpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwwLjgpKSArIHNjYWxlX2NvbG9yX21hbnVhbCgiSGlsIGZhbWlseSIsIHZhbHVlcyA9IGMoImJsYWNrIiwgImdvbGQzIikpICsKICB4bGFiKCJTZXIrVGhyIGZyZXF1ZW5jeSIpICsgeWxhYigiQ3VtdWxhdGl2ZSBwcm9iYWJpbGl0eSIpICsgCiAgdGhlbWVfY293cGxvdCgpICsgYmFja2dyb3VuZF9ncmlkKCkKYGBgCgpgYGB7cn0KcCA8LSBmaWx0ZXIyICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IHN0YXJ0c193aXRoKCJTVC4iKSwgbmFtZXNfdG8gPSAidHlwZSIsIG5hbWVzX3ByZWZpeCA9ICJTVC4iLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUgCiAgbXV0YXRlKHR5cGUgPSBmYWN0b3IodHlwZSwgbGV2ZWxzID0gYygicHJvdCIsICJ3aW5kb3cubWF4IiksIGxhYmVscyA9IGMoIndob2xlIHByb3RlaW4iLCAibWF4IGluIDEwMCBhLmEuIHdpbmRvdyIpKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHR5cGUsIHkgPSB2YWx1ZSwgZmlsbCA9IGdyb3VwKSkgKyBnZW9tX2JveHBsb3Qob3V0bGllci5zaXplID0gMC41LCBvdXRsaWVyLnNoYXBlID0gMSkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKyB4bGFiKCIiKSArIHlsYWIoIlNlci9UaHIgZnJlcXVlbmN5IikgKyB0aGVtZV9jb3dwbG90KCkKcApnZ3NhdmUoZmlsZSA9ICJvdXRwdXQvZmlndXJlLzIwMjEwNzIxLVNULWJveHBsb3QtY29tcGFyZS1jd3AtdG8tcmVzdC5wbmciLCBwbG90ID0gcCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSwgd2lkdGggPSA1LCBoZWlnaHQgPSA0LjUpCmBgYAoKU2VlbXMgbGlrZSB0aGUgdHdvIG1lYXN1cmVzIGJlaGF2ZSB2ZXJ5IHNpbWlsYXJseS4gTGV0J3Mgc2VlIGhvdyB0aGV5IGNvbXBhcmUgYnkgYXBwbHlpbmcgdGhlIGFib3ZlIGN1dG9mZnMuCgpgYGB7cn0KU1QudGggPSBjKCJTVC5wcm90ZWluIiA9IDAuMTUsICJTVC53aW5kb3ciID0gMC4yNSkKY2F0KCJUaHJlc2hvbGRzIGZvciB3aG9sZSBwcm90ZWluIG9yIHNsaWRpbmcgd2luZG93IGZyZXF1ZW5jaWVzIG9mIFNlci9UaHIiKQpwcmludChTVC50aCkKZmlsdGVyMiAlPiUgCiAgbXV0YXRlKGBTL1QgcHJvdGVpbmAgPSBTVC5wcm90ID4gU1QudGhbIlNULnByb3RlaW4iXSwKICAgICAgICAgYFMvVCBtYXggd2luZG93YCA9IFNULndpbmRvdy5tYXggPiBTVC50aFsiU1Qud2luZG93Il0pICU+JSAKICBjcm9zc3RhYihyb3cudmFycyA9IGMoIlMvVCBwcm90ZWluIiwgIlMvVCBtYXggd2luZG93IiksIGNvbC52YXJzID0gImdyb3VwIiwgYWRkbWFyZ2lucyA9IEZBTFNFKQpgYGAKCkJhc2VkIG9uIHRoZSBhYm92ZSwgd2Ugd2lsbCBhcHBseSBhIHRoaXJkIGZpbHRlciBvZiBTL1QgZnJlcXVlbmN5IGluIHRoZSB3aG9sZSBwcm90ZWluIFw+IDE1JSwgd2hpY2ggaXMgcm91Z2hseSB0aGUgbG93ZXIgY3V0b2ZmIGZvciB0aGUgZ3JvdXAgb2YgQ1dQcyBpbiB0aGUgQ2FybyBfZXQgYWwuXyAxOTk3IHBhcGVyLgoKYGBge3J9CiMgcmVmOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zNDA5NjE2Mi9kcGx5ci1tdXRhdGUtcmVwbGFjZS1zZXZlcmFsLWNvbHVtbnMtb24tYS1zdWJzZXQtb2Ytcm93cwptdXRhdGVfY29uZCA8LSBmdW5jdGlvbiguZGF0YSwgY29uZGl0aW9uLCAuLi4sIGVudmlyID0gcGFyZW50LmZyYW1lKCkpIHsKICBjb25kaXRpb24gPC0gZXZhbChzdWJzdGl0dXRlKGNvbmRpdGlvbiksIC5kYXRhLCBlbnZpcikKICAuZGF0YVtjb25kaXRpb24sIF0gPC0gLmRhdGFbY29uZGl0aW9uLCBdICU+JSBtdXRhdGUoLi4uKQogIC5kYXRhCn0KCmZpbHRlcjMgPC0gZmlsdGVyMiAlPiUKICBtdXRhdGUoYFMvVCBwcm90ZWluYCA9IFNULnByb3QgPiAwLjE1KSAlPiUgCiAgbXV0YXRlX2NvbmQoc3RyX3N1Yihncm91cCwxLDMpID09ICJDV1AiICYgIWBTL1QgcHJvdGVpbmAsIGdyb3VwID0gIk90aGVycyIpICU+JSAKICBzZWxlY3QoLUxlbiwgLWBTL1QgcHJvdGVpbmApCgpjYXQoIkdlbmVzIHJlbW92ZWQgZHVlIHRvIHRoZSBTL1QgY3V0b2ZmIikKZmlsdGVyMiAlPiUgZmlsdGVyKGdyb3VwICVpbiUgYygiQ1dQIGxvbmciLCAiQ1dQIHNob3J0IiksIFNULnByb3QgPD0gMC4xNSkKYGBgCldlIGNhbiBzZWUgdGhhdCBhbGwgdGhlIHByb3RlaW5zIHRoYXQgZmFsbCBvdXQgYXJlIHdpdGhpbiB0aGUgIkNXUCBzaG9ydCIgY2F0ZWdvcnksIHdoaWNoIGFyZSBsZXNzIGxpa2VseSB0byBmdW5jdGlvbiBhcyBhZGhlc2lucyB0byBiZWdpbiB3aXRoLiBUaHVzIHRoaXMgY3V0b2ZmIGNvdWxkIGhlbHAgcmVkdWNlIHRoZSBudW1iZXIgb2YgcHJvdGVpbnMgd2UgaGF2ZSB0byBtYW51YWxseSBsb29rIGF0IHdpdGhvdXQgbG9zaW5nIG1hbnkgcG90ZW50aWFsIGhpdHMuCgpBZnRlciB0aGlzIHN0ZXAgd2UgaGF2ZSBhIHRvdGFsIG9mIGByIHdpdGgoZmlsdGVyMywgc3VtKHN0cl9zdWIoZ3JvdXAsIDEsIDMpID09ICJDV1AiKSlgIHByb3RlaW5zIGxlZnQuCgojIyBUQU5HTyBoaXRzCgpgYGB7cn0KcCA8LSBmaWx0ZXIzICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBuLnRhbmdvLCBmaWxsID0gZ3JvdXApKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkgKwogIGZhY2V0X3dyYXAofmdyb3VwLCBucm93ID0gNSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobi5icmVha3MgPSAzKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKSArCiAgeGxhYigiIyBvZiBzdHJvbmcgVEFOR08gaGl0cyIpICsgdGhlbWVfY293cGxvdCgpICsgcGFuZWxfYm9yZGVyKCkKcApnZ3NhdmUoIm91dHB1dC9maWd1cmUvMjAyMTA3MjEtdGFuZ28taGl0cy1kaXN0cmlidXRpb24tY29tcGFyZS5wbmciLCBwbG90ID0gcCwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LjUpCmBgYAoKQXMgd2UgYWxyZWFkeSBzaG93ZWQgYmVmb3JlLCB0aGUgbnVtYmVyIGFuZCBzcGFjaW5nIG9mIHN0cm9uZyBUQU5HTyBoaXRzIGlzIGEgZGl2aXNpdmUgZmVhdHVyZSB0aGF0IHNlcGFyYXRlIHRoZSBIaWwgZmFtaWx5IHByb3RlaW5zIGluICpDLiBhdXJpcyogaW50byB0d28gZ3JvdXBzIC0tIHRob3NlIHRoYXQgYXJlIGxvbmdlciB0aGFuIDEwMDAgYS5hLiBoYXZlIGEgbG90IG9mIHRoZW0gYW5kIGhhdmUgdGhlbSByZWd1bGFybHkgc3BhY2VkLCB3aGlsZSB0aGUgZm91ciBzaG9ydGVyIG1lbWJlcnMgaGF2ZSBmZXcuIFdlIHNlZSBhIHNpbWlsYXIgcGljdHVyZSB3aGVuIHdlIGxvb2sgYXQgdGhlIGNhbmRpZGF0ZSBhZGhlc2luIHByb3RlaW5zIGluIG91ciBhbmFseXNpcyB1cCB0byB0aGlzIHBvaW50OiB0aGUgY2VsbC13YWxsIHByb3RlaW4gbG9uZyBncm91cCBzaG93ZWQgYWJvdmUgYXZlcmFnZSBudW1iZXIgb2YgVEFOR08gaGl0cyB3aGlsZSB0aGUgc2hvcnQgb25lcyBoYXZlIHZlcnkgZmV3LiBUaGUgUE1QcywgZGVzcGl0ZSBtb3N0IG9mIHRoZW0gYmVpbmcgc2hvcnRlciB0aGFuIDUwMCBhbWlubyBhY2lkcywgYWN0dWFsbHkgaGF2ZSByZWxhdGl2ZWx5IGhpZ2ggbnVtYmVyIG9mIFRBTkdPIGhpdHMuCgojIyBUYW5kZW0gcmVwZWF0cwpXZSBkaWRuJ3Qgd2FudCB0byBwZXJmb3JtIHRoZSB0YW5kZW0gcmVwZWF0IGFuYWx5c2lzIG9uID4yMCwwMDAgcHJvdGVpbnMuIE5vdyB0aGF0IHdlIGhhdmUgbmFycm93ZWQgdGhlIGxpc3QgZG93biB0byBhIG11Y2ggbW9yZSBtYW5hZ2VhYmxlIG9uZSwgdGhlIGNvZGUgYmVsb3cgd2lsbCBwZXJmb3JtIFhTVFJFQU0gYW5hbHlzaXMgb24gdGhlIGdyb3VwIG9mIGNhbmRpZGF0ZSBwcm90ZWlucyBpZGVudGlmaWVkIGFib3ZlLgoKMS4gRXhwb3J0IHRoZSBwcm90ZWluIElEcwoKYGBge3J9CmNhdChmaWx0ZXIzICU+JSBmaWx0ZXIoc3RyX3N1Yihncm91cCwgMSwgMykgPT0gIkNXUCIpICU+JSBwdWxsKG5hbWUpLCBmaWxlID0gImRhdGEvMjAyMTA3MTgtY3dwLXByb3RlaW5zLWlkLnR4dCIsIHNlcCA9ICJcbiIpCmBgYAoKMi4gRXh0cmFjdCB0aGUgZmFzdGEsIHJ1biB0aGUgZm9sbG93aW5nIGNvZGUgYXQgdGhlIGNvbW1hbmQgbGluZQoKYGBge2Jhc2h9Ci9Vc2Vycy9iaGUyL3N3L21pbmljb25kYTMvYmluL3B5dGhvbiBzY3JpcHQvZXh0cmFjdF9mYXN0YV9nei5weSBkYXRhL3Byb3Rlb21lLWZhc3RhL0NhdXJpc2Zhc3RhLmZhYS5neiBkYXRhLzIwMjEwNzE4LWN3cC1wcm90ZWlucy1pZC50eHQgZGF0YS8yMDIxMDcxOC1jd3AtcHJvdGVpbnMuZmFhCmBgYAoKMy4gRXhlY3V0ZSB0aGUgeHN0cmVhbSBwcm9ncmFtCmBgYHtiYXNofQpjZCBzY3JpcHQKc2ggeHN0cmVhbS5zaCAuLi9kYXRhLzIwMjEwNzE4LWN3cC1wcm90ZWlucy5mYWEgY3dwLXByb3RlaW5zIC4uL291dHB1dC90YW5kZW0tcmVwZWF0cwpjZCAuLgpgYGAKCjQuIEltcG9ydCB0aGUgeHN0cmVhbSByZXN1bHRzCmBgYHtyfQpyZXBlYXRzIDwtIHJlYWRfdHN2KCJvdXRwdXQvdGFuZGVtLXJlcGVhdHMvWFNUUkVBTV9jd3AtcHJvdGVpbnNfaTAuN19nM19tNV9MMTVfY2hhcnQudHN2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCiMjIENsdXN0ZXIgYnkgc2ltaWxhcml0eQoKTm93IHRoYXQgd2Ugc2V0dGxlZCBvbiB0aGUgIkNXUCBsb25nIiBhbmQgIkNXUCBzaG9ydCIgbGlzdHMsIHdlIHdvdWxkIGxpa2UgdG8gdmlzdWFsaXplIHRoZWlyIGRvbWFpbiBhcmNoaXRlY3R1cmUuIFNpbmNlIHdlIHN0YXJ0ZWQgd2l0aCBmb3VyIHByb3Rlb21lcywgd2l0aCB0aGUgZ29hbCBvZiBjYXB0dXJpbmcgYSAic3BlY2llcy13aWRlIiBzZXQgb2YgY2FuZGlkYXRlcywgd2UgaGF2ZSBwcmVzdW1hYmx5IGZvdXIgYWxsZWxlcyBvZiBlYWNoIHByb3RlaW4gKG1heSBiZSBmZXdlcikgaW4gdGhlIGxpc3QuIFRvIG1ha2UgaXQgZWFzaWVyIHRvIGV4YW1pbmUgdGhlIGRvbWFpbiBmZWF0dXJlcywgbGV0J3MgY2x1c3RlciB0aGUgcHJvdGVpbnMgYW5kIGFzc2VtYmxlIGEgcmVwcmVzZW50YXRpdmUgbGlzdC4KCjEuICBTdWJtaXQgdGhlIGZhc3RhIHRvIFtDRC1oaXRdKGh0dHBzOi8vZ2l0aHViLmNvbS93ZWl6aG9uZ2xpL2NkaGl0KSBbd2Vic2VydmVyXShodHRwOi8vd2VpemhvbmctbGFiLnVjc2QuZWR1L2NkaGl0LXdlYi1zZXJ2ZXIvY2dpLWJpbi8pLgoKMi4gIFJlZm9ybWF0IHRoZSBDRC1oaXQgb3V0cHV0CgpgYGAgYmFzaAovVXNlcnMvYmhlMi9zdy9taW5pY29uZGEzL2Jpbi9weXRob24gc2NyaXB0L2Zvcm1hdF9jZC1oaXRfb3V0cHV0LnB5IG91dHB1dC9jZC1oaXQvMjAyMTA3MjctQ0QtaGl0LTAuODUvMTYyNzQzODgzOC5mYXMuMS5jbHN0ci5zb3J0ZWQgb3V0cHV0L2NkLWhpdC9mb3JtYXR0ZWQtY2QtaGl0LTAuODUudHN2Ci9Vc2Vycy9iaGUyL3N3L21pbmljb25kYTMvYmluL3B5dGhvbiBzY3JpcHQvZm9ybWF0X2NkLWhpdF9vdXRwdXQucHkgb3V0cHV0L2NkLWhpdC8yMDIxMDcyNy1DRC1oaXQtMC42LzE2Mjc0Mzk5ODguZmFzLjEuY2xzdHIuc29ydGVkIG91dHB1dC9jZC1oaXQvZm9ybWF0dGVkLWNkLWhpdC0wLjYudHN2CmBgYAoKYGBge3J9CmNkaGl0LmxvIDwtIHJlYWRfdHN2KCJvdXRwdXQvY2QtaGl0L2Zvcm1hdHRlZC1jZC1oaXQtMC42LnRzdiIsIGNvbF90eXBlcyA9ICJjY2MiKSAlPiUgCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogIG11dGF0ZShsZWFkZXIgPSBpZFt3aGljaChpZGVudGl0eSA9PSAiKiIpXSwgIyBhc3NpZ24gdGhlIHJlcHJlc2VudGF0aXZlIHByb3RlaW4gSUQgdG8gbmV3IHZhcmlhYmxlICJsZWFkZXIiCiAgICAgICAgIGlkZW50aXR5ID0gaWZlbHNlKGlkZW50aXR5ID09ICIqIiwgMTAwLCBhcy5udW1lcmljKHN0cl9zdWIoaWRlbnRpdHksIDEsIC0yKSkpKSAlPiUgICMgZXh0cmFjdCBwZXJjZW50IGlkZW50aXR5CiAgdW5ncm91cCgpCgpjZGhpdC5oaSA8LSByZWFkX3Rzdigib3V0cHV0L2NkLWhpdC9mb3JtYXR0ZWQtY2QtaGl0LTAuODUudHN2IiwgY29sX3R5cGVzID0gImNjYyIpICU+JSAKICBncm91cF9ieShjbHVzdGVyKSAlPiUgCiAgbXV0YXRlKGxlYWRlciA9IGlkW3doaWNoKGlkZW50aXR5ID09ICIqIildLCAjIGFzc2lnbiB0aGUgcmVwcmVzZW50YXRpdmUgcHJvdGVpbiBJRCB0byBuZXcgdmFyaWFibGUgImxlYWRlciIKICAgICAgICAgaWRlbnRpdHkgPSBpZmVsc2UoaWRlbnRpdHkgPT0gIioiLCAxMDAsIGFzLm51bWVyaWMoc3RyX3N1YihpZGVudGl0eSwgMSwgLTIpKSkpICU+JSAgIyBleHRyYWN0IHBlcmNlbnQgaWRlbnRpdHkKICB1bmdyb3VwKCkKCmNkaGl0IDwtIGZ1bGxfam9pbihjZGhpdC5oaSwgY2RoaXQubG8sIGJ5ID0gImlkIiwgc3VmZml4ID0gYygiLmhpIiwgIi5sbyIpKSAlPiUgCiAgbXV0YXRlKGFncmVlID0gbGVhZGVyLmhpID09IGxlYWRlci5sbykgJT4lIAogIHNlbGVjdChpZCwgZXZlcnl0aGluZygpKSAlPiUgYXJyYW5nZShjbHVzdGVyLmxvKQpybShsaXN0ID0gYygiY2RoaXQubG8iLCAiY2RoaXQuaGkiKSkKYGBgCgpEaXNhZ3JlZW1lbnQgYmV0d2VlbiB0aGUgdHdvIGNsdXN0ZXJpbmcgcmVzdWx0czoKCmBgYHtyfQpjZGhpdCAlPiUgZ3JvdXBfYnkoY2x1c3Rlci5sbykgJT4lIGZpbHRlcihsZW5ndGgodW5pcXVlKGNsdXN0ZXIuaGkpKSA+IDEsIGxlYWRlci5oaSA9PSBpZCkgJT4lIHVuZ3JvdXAoKQpgYGAKClRvIGRldGVybWluZSBpZiB0aGUgZXh0cmEgY2x1c3RlcnMgaWRlbnRpZmllZCB3aXRoIHRoZSA4NSUgdGhyZXNob2xkIGlzIHJlYWwsIEkgdXNlZCBibGFzdHAgKG5jYmkgc2VydmVyKSB0byBhbGlnbiBlYWNoIG9mIHRoZSBhZGRpdGlvbmFsIGxlYWRlciBzZXF1ZW5jZSB0byB0aGUgc2hhcmVkIGxlYWRlciBzZXF1ZW5jZSBpZGVudGlmaWVkIHdpdGggdGhlIDYwJSB0aHJlc2hvbGQuIFdoZW4gbmVjZXNzYXJ5LCBJIGFsc28gY2hlY2tlZCB0aGUgcHJvdGVpbidzIGNocm9tb3NvbWFsIGxvY2F0aW9uIHRvIGRldGVybWluZSBpZiB0aGV5IGluZGVlZCBjb21lIGZyb20gZGlmZmVyZW50IGxvY2kuCgp8IGxlYWRlci5sbyAgICAgIHwgbGVhZGVyLmhpICB8ICVxY292IHwgJWlkZW50IHwgbGVuLmxvIHwgbGVuLmhpIHwgY2hyb21vc29tZS5sbyAgICAgICAgICAgICAgICB8IGNocm9tb3NvbWUuaGkgICAgICAgICAgICAgICAgICAgIHwgY29uY2x1c2lvbiAgICAgICB8IGNvbW1lbnRzICAgICAgICAgICAgICAgICAgICAgICB8Cnw6LS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLXw6LS0tLS0tfDotLS0tLS0tfDotLS0tLS0tfDotLS0tLS0tfDotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCBQSVM1MTE3OS4xICAgICB8IFBJUzU0NzE0LjEgfCA4MyUgICB8IDcwJSAgICB8IDkxICAgICB8IDgyICAgICB8IGNocjEgICAgICAgICAgICAgICAgICAgICAgICAgfCBjaHI3ICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGRpZmZlcmVudCAgICAgICAgfCBib3RoIGluIEI4NDQxICAgICAgICAgICAgICAgICAgfAp8IFBJUzQ4MTcxLjEgICAgIHwgUElTNDgxNzAuMSB8IDEwMCUgIHwgNjclICAgIHwgMTc2ICAgIHwgMTY2ICAgIHwgY2hyNjo0MDU2Mi00MTA5MiAgICAgICAgICAgICB8IGNocjY6MzkzMDctMzk4MDcgICAgICAgICAgICAgICAgIHwgZGlmZmVyZW50ICAgICAgICB8IHRhbmRlbSBkdXBsaWNhdGVzICAgICAgICAgICAgICB8CnwgUElTNDgxNzEuMSAgICAgfCBQSVM0ODE3Mi4xIHwgMTAwJSAgfCA2NiUgICAgfCAxNzYgICAgfCAxNzMgICAgfCBjaHI2OjQwNTYyLTQxMDkyICAgICAgICAgICAgIHwgY2hyNjo0MTYxOS00MjE0MCAgICAgICAgICAgICAgICAgfCBkaWZmZXJlbnQgICAgICAgIHwgdGFuZGVtIGR1cGxpY2F0ZXMgICAgICAgICAgICAgIHwKfCBQSVM1NDgwMi4xICAgICB8IFFFTDYzNDc0LjEgfCAxMDAlICB8IDkzJSAgICB8IDg2MSAgICB8IDgzNCAgICB8IGNocjc6NzY3Mjk0LTc2OTg3OSAgICAgICAgICAgfCBjaHI3Ojc2MDA0NC03NjA5NjgsNzYxMDM5LTc2MjYxOCB8IG9ydGhvbG9ncyAgICAgICAgfCBCODQ0MSBhbmQgQjExMjQ1ICAgICAgICAgICAgICAgfAp8IFBJUzU2OTEyLjEgICAgIHwgUUVPMjAzNzkuMSB8IE5BICAgIHwgTkEgICAgIHwgNzY1ICAgIHwgNzQ3ICAgIHwgY2hyMyxzY2FmZm9sZDU6ODY0OTk1LTg2NzI5MiB8IGNocjE6MjU0OTQ2MS0yNTUxNzA0ICAgICAgICAgICAgIHwgbGlrZWx5IG9ydGhvbG9ncyB8IEI4NDQxIGFuZCBCMTEyMjAgICAgICAgICAgICAgICB8CnwgWFBfMDI4ODkwODQ0LjEgfCBRRU8yMTI0Mi4xIHwgMTAwJSAgfCA4NSUgICAgfCA3OTAgICAgfCA3NTUgICAgfCBjaHIxOjMxMDAyMjUtMzEwMjU5NyAgICAgICAgIHwgY2hyMjoxMzYxODIyLTEzNjQwODkgICAgICAgICAgICAgfCBsaWtlbHkgb3J0aG9sb2dzIHwgQjExMjIxIGFuZCBCMTEyMjAgPHN1cD4xPC9zdXA+IHwKfCBRRUw1ODUyMC4xICAgICB8IFBJUzUxOTQxLjEgfCA5NyUgICB8IDg4JSAgICB8IDQ1NyAgICB8IDQ0MCAgICB8IGNocjEgICAgICAgICAgICAgICAgICAgICAgICAgfCBjaHIxLHNjYWZmb2xkMSAgICAgICAgICAgICAgICAgICB8IG9ydGhvbG9ncyAgICAgICAgfCBCMTEyNDUgYW5kIEI4NDQxICAgICAgICAgICAgICAgfAp8IFBJUzU4MTg1LjEgICAgIHwgUUVPMjI1NTMuMSB8IDEwMCUgIHwgOTQlICAgIHwgMjYwOCAgIHwgOTcwICAgIHwgY2hyMiAgICAgICAgICAgICAgICAgICAgICAgICB8IGNocjMgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgb3J0aG9sb2dzICAgICAgICB8IEI4NDQxIGFuZCBCMTEyMjAgPHN1cD4xPC9zdXA+ICB8Cgo6ICoqVGFibGUuKiogRGV0ZXJtaW5lIHRoZSBvcnRob2xvZ3kgb2YgdGhlIGNsdXN0ZXIgbGVhZGVycyB1c2luZyB0aGUgdHdvIHRocmVzaG9sZHMKCjxzdXA+MTwvc3VwPiBBY2NvcmRpbmcgdG8gTXXDsW96IF9ldCBhbC5fIDIwMjEsIHRoZXJlIGlzIGEgbGFyZ2Ugc2NhbGUgdHJhbnNsb2NhdGlvbiBiZXR3ZWVuIGNocm9tb3NvbWUgMSBhbmQgMiBpbiB0aGUgY2xhZGUgSUkgc3RyYWlucyBhbmQgdGhlIGNocm9tb3NvbWUgMSBsb2NhdGlvbiBmb3IgWFBfMDI4ODkwODQ0IGlzIHdpdGhpbiB0aGUgdHJhbnNsb2NhdGVkIHJlZ2lvbiBhbmQgbWF0Y2hlcyB0aGUgY29vcmRpbmF0ZXMgb2YgUUVPMjEyNDIgaW4gdGhlIHRyYW5zbG9jYXRlZCByZWdpb24gaW4gaXRzIGNocm9tb3NvbWUgMi4KIVt0cmFuc2xvY2F0aW9uIGJldHdlZW4gY2hyMSBhbmQgMiBpbiBCMTEyMjBdKG91dHB1dC9jZC1oaXQvaW1nLzIwMjEwNzI4LXRyYW5zbG9jYXRpb24tYWZmZWN0cy1zeW50ZW55LWluLWNsdXN0ZXJpbmcucG5nKQozLiBCYXNlZCBvbiB0aGUgcmVzdWx0cyBhYm92ZSwgd2Ugd2lsbCBtYW51YWxseSB1cGRhdGUgdGhlIGBjZGhpdGAgdGFibGUKCmBgYHtyfQp3cml0ZV90c3YoY2RoaXQsIGZpbGUgPSAib3V0cHV0L2NkLWhpdC8yMDIxMDcyNy1jZGhpdC1jbHVzdGVyLWZvci1tYW51YWwtZWRpdGluZy50c3YiKQpgYGAKSW4gYWRkaXRpb24gdG8gdGhlIGNoYW5nZXMgbWVudGlvbmVkIGluIHRoZSB0YWJsZSBhYm92ZSwgSSBhbHNvIG1hbnVhbGx5IG1lcmdlZCBRRU82MDUyNiBpbnRvIHRoZSBQSVM1ODE4NSBjbHVzdGVyIChzZWUgUkVBRE1FLm1kIGluIHRoaXMgZm9sZGVyIGZvciB0aGUgcmF0aW9uYWxlKTsgSSBtZXJnZWQgUUVPMjEyNDEgZnJvbSBCMTEyMjAgdG8gdGhlIFBJUzUxOTQxIGNsdXN0ZXIuIE15IGdvYWwgaGVyZSBpcyB0byBtYW51YWxseSBjaGVjayB0aGUgc2luZ2xlIGdlbmUgY2x1c3RlcnMgYW5kIGRldGVybWluZSBpZiB0aGV5IGFjdHVhbGx5IGJlbG9uZyB0byBhbiBleGlzdGluZyBjbHVzdGVyLiBBbGwgdGhyZWUgcmVtYWluaW5nIHNpbmdsZSBnZW5lIGNsdXN0ZXJzIGNhbm5vdCBiZSBtZXJnZWQgdG8gYW55IGV4aXN0aW5nIGNsdXN0ZXIsIGJlY2F1c2UgdGhlaXIgb3J0aG9sb2dzIChieSBCTEFTVFApIGFyZSBlaXRoZXIgbWlzc2luZyB0aGUgc2lnbmFsIHBlcHRpZGUgYW5kL29yIEdQSS1hbmNob3IuCgpMYXN0bHksIENELWhpdCBieSBkZWZhdWx0IGNob29zZXMgdGhlIGxvbmdlc3QgcHJvdGVpbiBpbiBhIGNsdXN0ZXIgYXMgdGhlIHJlcHJlc2VudGF0aXZlLiBJIG1hbnVhbGx5IGNoYW5nZWQgdGhlIHJlcHJlc2VudGF0aXZlIChha2EgbGVhZGVyKSBzZXF1ZW5jZSB0byB0aGUgQjg0NDEgcHJvdGVpbiBpZiBvbmUgZXhpc3RzLiBUaGlzIHdheSB0aGUgZmluYWwgbGlzdCB3aWxsIGJlIG1vc3RseSByZXByZXNlbnRlZCBieSBzZXF1ZW5jZXMgZnJvbSBhIHNpbmdsZSBzdHJhaW4gKHdpdGggc29tZSBleGNlcHRpb25zKS4KCjQuIFRoZW4gbG9hZCB0aGUgdXBkYXRlZCB0YWJsZSBhbmQgbWVyZ2UgdGhlIGluZm9ybWF0aW9uIHRvIHByb2R1Y2UgdGhlIGZpbmFsIGNhbmRpZGF0ZSB0YWJsZS5Pbmx5IHRoZSBsZWFkZXJzIChsb25nZXN0IHJlcHJlc2VudGF0aXZlIGluIGVhY2ggY2x1c3RlcikgYXJlIHNob3duIGJlbG93LgpgYGB7cn0KY2RoaXQxIDwtIHJlYWRfdHN2KCJvdXRwdXQvY2QtaGl0LzIwMjEwNzI3LWNkaGl0LWNsdXN0ZXItbWFudWFsbHktZWRpdGVkLnRzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkgJT4lIAogIGxlZnRfam9pbihzZWxlY3Qoc2VxSW5mbywgaWQgPSBuYW1lLCBsZW5ndGgpLCBieSA9ICJpZCIpICU+JSAKICBzZWxlY3QoLWVuZHNfd2l0aChjKCIuaGkiLCIubG8iKSkpICU+JSAKICBncm91cF9ieShsZWFkZXIpICU+JSAKICBtdXRhdGUobGVhZGVyLmxlbiA9IG1heChsZW5ndGgpLCBuID0gbigpKSAlPiUgCiAgdW5ncm91cCgpCgpjZGhpdDEgPC0gY2RoaXQxICU+JSAKICBmaWx0ZXIoaXMubGVhZGVyKSAlPiUgCiAgc2VsZWN0KGxlYWRlciwgbGVhZGVyLmxlbikgJT4lIAogIGFycmFuZ2UoZGVzYyhsZWFkZXIubGVuKSkgJT4lIAogIG11dGF0ZShjbHVzdGVyID0gc2VxX2Fsb25nKGxlYWRlcikpICU+JSAKICByaWdodF9qb2luKGNkaGl0MSwgYnkgPSBjKCJsZWFkZXIiLCAibGVhZGVyLmxlbiIpKSAlPiUKICBzZWxlY3QoY2x1c3RlciwgbiwgbGVhZGVyLCBsZWFkZXIubGVuLCBpZCwgbGVuZ3RoLCBpcy5sZWFkZXIpCmBgYAoKNS4gV2Ugd2lsbCBtZXJnZSB0aGUgY2x1c3RlciBpbmZvcm1hdGlvbiB3aXRoIG90aGVyIHNlcXVlbmNlIGZlYXR1cmVzCmBgYHtyfQojIGNhbGN1bGF0ZSB0aGUgcGVyIHNlcXVlbmNlIHJlcGVhdCBjb250ZW50IGFuZCBhZGQgdG8gdGhlIGNhbmRpZGF0ZXMgbGlzdAp0bXAgPC0gcmVwZWF0cyAlPiUgCiAgbXV0YXRlKGxlbiA9IGVuZCAtIHN0YXJ0ICsgMSkgJT4lIAogIGdyb3VwX2J5KGlkZW50aWZpZXIpICU+JSAKICBzdW1tYXJpemUocGVyYyA9IHJvdW5kKHN1bShsZW4vc2VxTGVuZ3RoKSwzKSkgJT4lIAogIHJlbmFtZShuYW1lID0gaWRlbnRpZmllciwgcmVwZWF0cyA9IHBlcmMpCgpjYW5kaWRhdGVzIDwtIGZpbHRlcjMgJT4lIAogIGZpbHRlcihzdHJfc3ViKGdyb3VwLDEsMykgPT0gIkNXUCIpICU+JSAKICByZW5hbWUoU1Qud2luID0gU1Qud2luZG93Lm1heCkgJT4lIAogIGxlZnRfam9pbih0bXAsIGJ5ID0gIm5hbWUiKSAlPiUgCiAgcmVwbGFjZV9uYShsaXN0KHJlcGVhdHMgPSAwKSkgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoY2RoaXQxLCBuYW1lID0gaWQsIGNsdXN0ZXIsIGNsdXN0ZXIuc2l6ZSA9IG4sIGlzLmxlYWRlciksIGJ5ID0gIm5hbWUiKSAlPiUgCiAgc2VsZWN0KC1IaWxfZmFtaWx5KSAlPiUgCiAgYXJyYW5nZShjbHVzdGVyKQpgYGAKCjYuIENvdW50IHRoZSBudW1iZXIgb2YgbGVhZGVycyBpbiBlYWNoIGdyb3VwCmBgYHtyfQpjYW5kaWRhdGVzICU+JSBmaWx0ZXIoaXMubGVhZGVyKSAlPiUgY291bnQoZ3JvdXApCmBgYAoKNy4gU2hvdyB0aGVpciBzZXF1ZW5jZSBmZWF0dXJlcyBmb3IgdGhlIENXUCBsb25nIGFuZCBDV1Agc2hvcnQgZ3JvdXBzIHNlcGFyYXRlbHkKCmBgYHtyfQpjd3AubG9uZyA8LSBjYW5kaWRhdGVzICU+JSBmaWx0ZXIoaXMubGVhZGVyLCBncm91cCA9PSAiQ1dQIGxvbmciKSAlPiUgc2VsZWN0KC1ncm91cCwgLWlzLmxlYWRlciwgLXBmYW1fZG9tYWlucywgcGZhbV9kb21haW5zKQpjd3Auc2hvcnQgPC0gY2FuZGlkYXRlcyAlPiUgZmlsdGVyKGlzLmxlYWRlciwgZ3JvdXAgPT0gIkNXUCBzaG9ydCIpICU+JSBzZWxlY3QoLWdyb3VwLCAtaXMubGVhZGVyLCAtcGZhbV9kb21haW5zLCBwZmFtX2RvbWFpbnMpCmNhdCgiQ1dQIGxvbmciKQpjd3AubG9uZwpjYXQoIkNXUCBzaG9ydCIpCmN3cC5zaG9ydApgYGAKICAgIAoqKl9EaXNjdXNzaW9uXyoqCgoxLiBJbiB0aGUgZmlyc3QgdGFibGUgYWJvdmUsIGNsdXN0ZXIgMSBhbG9uZyB3aXRoIFhQXzAyODg5MzA1Nywgd2hpY2ggaXMgbm90IGluIHRoZSBjYW5kaWRhdGVzIGxpc3QgYmVjYXVzZSBpdCBtaXNzZXMgdGhlIEMtdGVybWluYWwgR1BJLWFuY2hvciBzZXF1ZW5jZSAodGhpcyBpcyBhIHBhcnRpYWwgbVJOQSBtaXNzaW5nIHRoZSAzJyBwb3J0aW9uKSwgYXJlIHRoZSBvbmx5IG9uZXMgY29udGFpbmluZyB0aGUgIkdWVklWVCIgc2VxdWVuY2UgKHNlZSBSRUFETUUubWQgaW4gdGhpcyBmb2xkZXIpLiBUaGV5IGFsbCBoYXZlIHRoZSBHTEVZQSBkb21haW4gaW4gdGhlIE4tdGVybWludXMsIGFuZCBoYWQgdmVyeSBzaW1pbGFyIGNlbnRyYWwgZG9tYWluIHJlcGVhdCB1bml0cyBhcyB0aGUgSGlsMS8yIHByb3RlaW4uCjEuIFJvd3MgMiwgMyBhbmQgNCBhbGwgaGF2ZSB0aGUgQ2FuZGlkYV9BTFNfTiBkb21haW4sIGFuZCB0aGV5IGFyZSB0aGUgQUxTIGZhbWlseSBtZW1iZXJzLgoxLiBFeGFtaW5pbmcgdGhlIE4tdGVybWluYWwgUGZhbSBkb21haW5zIGFtb25nIHRoZSByZXN0IGNhbmRpZGF0ZSByZXZlYWxlZCBGbG8xMSwgQXNwLCBQTEEyX0IsIENGRU0sIEdseWNvX2h5ZHJvXzcyIGFuZCBYOC4gTWFueSBvZiB0aGVzZSBkb21haW5zIGhhdmUgY29ubmVjdGlvbnMgdG8gYWRoZXNpb24uCgo4LiBXcml0ZSB0aGUgY2FuZGlkYXRlcyBpbmZvIHRvIGZpbGVzCmBgYHtyfQpjYW5kaWRhdGVzICU+JSAKICBmaWx0ZXIoaXMubGVhZGVyKSAlPiUgCiAgc2VsZWN0KC1pcy5sZWFkZXIsIC1wZmFtX2RvbWFpbnMsIHBmYW1fZG9tYWlucykgJT4lIAogIHJlbG9jYXRlKGdyb3VwLCAuYWZ0ZXIgPSBuYW1lKSAlPiUgCiAgd3JpdGVfdHN2KGZpbGUgPSAib3V0cHV0L1JtZC1vdXQvMjAyMTA3MjktY2FuZGlkYXRlLWxlYWRlcnMtc2VxaW5mby50c3YiKQpgYGAKCgojIyBTY2hlbWF0aWMgcGxvdCBmb3IgbGVhZGVycwpUaGUgZ29hbCBpcyB0byBjcmVhdGUgYSBkb21haW4gc2NoZW1hdGljIHBsb3QgZm9yIGFsbCB0aGUgbGVhZGVyIHByb3RlaW5zLiBUaGUgZGVzaXJlZCBwbG90IHdpbGwgaW5jbHVkZSB0aGUgZm9sbG93aW5nIGZlYXR1cmVzOiBTaWduYWxQLCBHUEktYW5jaG9yLCBhbnkgcGZhbSBkb21haW4gKGV4Y2VwdCBmb3IgdGhlIEh5cjEsIEZsb2NjdWxpbl90MyBhbmQgQ2FuZGlkYV9BTFMgcmVwZWF0IGRvbWFpbnMpLCB0YW5kZW0gcmVwZWF0cyBhcyBpZGVudGlmaWVkIGJ5IHhzdHJlYW0sIGFuZCB0aGUgcGxvdCBzaG91bGQgYmUgb3JkZXJlZCBieSBwcm90ZWluIGxlbmd0aCBmcm9tIGxhcmdlIHRvIHNtYWxsLgoKKipVcGRhdGUgMjAyMS0wNy0yMCBbSEJdKiogSSBkZWNpZGUgdG8gcmVtb3ZlIHRoZSBjbHVzdGVycyB3aG9zZSBsZWFkZXIgcHJvdGVpbiBsZW5ndGggaXMgbGVzcyB0aGFuIDE5NSBhLmEuIFRoaXMgaGVscHMgdG8gc2hvcnRlbiB0aGUgbGlzdCwgbWFraW5nIHRoZSBwbG90IG1vcmUgcmVhZGFibGUuCgpgYGB7cn0KIyBnZXQgdGhlIGlkcyB0byBwbG90CmlkLnRvLnBsb3QgPC0gY2FuZGlkYXRlcyAlPiUgZmlsdGVyKGlzLmxlYWRlciwgbGVuZ3RoID49IDE5NSkgJT4lIHB1bGwobmFtZSkKCiMgd2Ugd2lsbCBiZSBidWlsZGluZyB0aGUgcGxvdCBpbiBsYXllcnM6IDEpIHdob2xlIHByb3RlaW4gKGdyZXkpOyAyKSB0YW5kZW0gcmVwZWF0czsgMykgcGZhbSBkb21haW5zOyA0KSBzaWduYWxwIGFuZCBwcmVkLmdwaTsgNSkgaWYgcG9zc2libGUsIHRhbmdvIGhpdHMKIyB0aGUgcmVsZXZhbnQgZGF0YSBjYW4gYmUgYXNzZW1ibGVkIHNlcGFyYXRlbHkKCmRmLndob2xlIDwtIGNhbmRpZGF0ZXMgJT4lIAogIGZpbHRlcihuYW1lICVpbiUgaWQudG8ucGxvdCkgJT4lIAogIG11dGF0ZShzdGFydCA9IDEsIGVuZCA9IGxlbmd0aCwgZmVhdHVyZSA9ICJ3aG9sZSBwcm90ZWluIiwKICAgICAgICAgbmFtZSA9IG9yZGVyZWQobmFtZSwgbGV2ZWxzID0gcmV2KGlkLnRvLnBsb3QpKSkgJT4lIAogIHNlbGVjdChuYW1lLCBmZWF0dXJlLCBzdGFydCwgZW5kLCBncm91cCkKCmRmLnJlcGVhdHMgPC0gcmVwZWF0cyAlPiUgCiAgbXV0YXRlKGZlYXR1cmUgPSBwYXN0ZSgiVFIiLCB0eXBlLCAiLSIpKSAlPiUgCiAgc2VsZWN0KG5hbWUgPSBpZGVudGlmaWVyLCBmZWF0dXJlLCBzdGFydCwgZW5kKSAlPiUgCiAgZmlsdGVyKG5hbWUgJWluJSBpZC50by5wbG90KSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChkZi53aG9sZSwgbmFtZSwgZ3JvdXApLCBieSA9ICJuYW1lIikKCmRmLnBmYW0gPC0gaG1tc2Nhbl9wZmFtICU+JSAKICBmaWx0ZXIoIW91dGNvbXBldGVkLCAgIyByZW1vdmUgbG93ZXItc2NvcmVkIG92ZXJsYXBwaW5nIGRvbWFpbnMKICAgICAgICAgIWhtbV9uYW1lICVpbiUgYygiSHlyMSIsICJDYW5kaWRhX0FMUyIpKSAlPiUgIyByZW1vdmUgdHdvIHJlcGVhdCBkb21haW5zICwgIkZsb2NjdWxpbl90MyIKICBtdXRhdGUobmFtZSA9IHN0cl9zdWIoc2VxX2lkLCAyKSwgIyByZW1vdmUgPiBmcm9tIHNlcS5pZAogICAgICAgICBmZWF0dXJlID0gcGFzdGUwKGhtbV9uYW1lLCAiICgiLCBnc3ViKCJcXC5bMC05XSIsICIiLCBobW1fYWNjKSwgIikiKSkgJT4lICMgZmVhdHVyZSBuYW1lCiAgZmlsdGVyKG5hbWUgJWluJSBpZC50by5wbG90KSAlPiUgCiAgbGVmdF9qb2luKHNlbGVjdChkZi53aG9sZSwgbmFtZSwgZ3JvdXApLCBieSA9ICJuYW1lIikgJT4lIAogIHNlbGVjdChuYW1lLCBmZWF0dXJlLCBzdGFydCA9IGVudmVsb3BlX3N0YXJ0LCBlbmQgPSBlbnZlbG9wZV9lbmQsIGdyb3VwKQoKZGYuc2lnbmFscCA8LSBzaWduYWxwNSAlPiUgCiAgZmlsdGVyKGlkICVpbiUgaWQudG8ucGxvdCkgJT4lIAogIG11dGF0ZShmZWF0dXJlID0gIlNpZ25hbFAiKSAlPiUgCiAgc2VsZWN0KG5hbWUgPSBpZCwgc3RhcnQsIGVuZCkgJT4lIAogIGxlZnRfam9pbihzZWxlY3QoZGYud2hvbGUsIG5hbWUsIGdyb3VwKSwgYnkgPSAibmFtZSIpCgpkZi5ncGkgPC0gcHJlZC5ncGkgJT4lIAogIGZpbHRlcihuYW1lICVpbiUgaWQudG8ucGxvdCwgaXMuZ3BpKSAlPiUgCiAgbXV0YXRlKGZlYXR1cmUgPSAiR1BJLWFuY2hvciIpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGRmLndob2xlLCBuYW1lLCBncm91cCwgZW5kKSwgYnkgPSAibmFtZSIpICU+JSAKICBzZWxlY3QobmFtZSwgZmVhdHVyZSwgc3RhcnQgPSBjbGVhdmVQb3MsIGVuZCwgZ3JvdXApCgpkZi50YW5nbyA8LSB0YW5nby5yZXMuZGYxICU+JSAKICBmaWx0ZXIoaWQgJWluJSBpZC50by5wbG90KSAlPiUgCiAgbXV0YXRlKGZlYXR1cmUgPSAidGFuZ28iKSAlPiUgCiAgc2VsZWN0KG5hbWUgPSBpZCwgZmVhdHVyZSwgc3RhcnQsIGVuZCwgbWVkaWFuLCBzZXEpICU+JSAKICBsZWZ0X2pvaW4oc2VsZWN0KGRmLndob2xlLCBuYW1lLCBncm91cCksIGJ5ID0gIm5hbWUiKQpgYGAKCkJ1aWxkIHRoZSBwbG90CmBgYHtyLCBmaWcuaGVpZ2h0PTUuNCwgZmlnLndpZHRoPTcuMn0KIyBwcm90ZWluIGJhY2tib25lCnAwIDwtIGdncGxvdChkZi53aG9sZSwgYWVzKHggPSBuYW1lLCB5ID0gc3RhcnQsIHhlbmQgPSBuYW1lLCB5ZW5kID0gZW5kKSkgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSA1MDAsIGNvbG9yID0gImdyZXk4MCIsIHNpemUgPSAwLjIpICsgIyBhZGQgYSB2aXN1YWwgZGl2aWRlciB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIGxvbmcgYW5kIHNob3J0CiAgZ2VvbV9zZWdtZW50KGNvbG9yID0gImdyZXk4MCIsIHNpemUgPSAyKQojIHRhbmRlbSByZXBlYXRzCnAxIDwtIGdlb21fc2VnbWVudChkYXRhID0gZGYucmVwZWF0cywgYWVzKHNpemUgPSAiVGFuZGVtIFJlcGVhdHMiKSwgY29sb3IgPSAib3JhbmdlNCIsIGFscGhhID0gMC41KQoKIyBwZmFtCnJlcXVpcmUoUkNvbG9yQnJld2VyKQpmZWF0dXJlLmNvbCA8LSBjKGJyZXdlci5wYWwoMTIsICJQYWlyZWQiKVtjKDksMiw0LDMsNSw3LDExLDgpXSwgYnJld2VyLnBhbCg4LCAiRGFyazIiKVtjKDIsOCwzLDQsNildLCJicm93bjMiLCAibmF2eWJsdWUiLCAic2t5Ymx1ZSIpCiMobGVuZ3RoKHVuaXF1ZShkZi5wZmFtJGZlYXR1cmUpKSkgIyBkZWZpbmUgdGhlIGNvbG9ycwpwMiA8LSBnZW9tX3NlZ21lbnQoZGF0YSA9IGRmLnBmYW0sIGFlcyhjb2xvciA9IGZlYXR1cmUpLCBzaXplID0gMikKCiMgc2lnbmFscCBhbmQgZ3BpCnAzIDwtIGdlb21fc2VnbWVudChkYXRhID0gZGYuc2lnbmFscCwgYWVzKHNpemUgPSAiU2lnbmFsUCIpLCBjb2xvciA9ICIjZTMxYTFjIikKcDQgPC0gZ2VvbV9zZWdtZW50KGRhdGEgPSBkZi5ncGksIGFlcyhzaXplID0gIkdQSS1hbmNob3IiKSwgY29sb3IgPSAiIzZhM2Q5YSIpCgojIHRhbmdvCnA1IDwtIGdlb21fc2VnbWVudChkYXRhID0gZGYudGFuZ28sIGFlcyh5ID0gc3RhcnQsICB5ZW5kID0gZW5kICsgMSwgYWxwaGEgPSBtZWRpYW4pLAogICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9udWRnZSh4ID0gLTAuNDIsIHkgPSAwKSwgY29sb3IgPSAiZGFya3JlZCIsIHNpemUgPSAuOCkKCiMgcGxvdApwMCArIHAxICsgcDIgKyBwMyArIHA0ICsgcDUgKyBjb29yZF9mbGlwKCkgKyAKICAjZmFjZXRfd3JhcCh+Z3JvdXAsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoZmVhdHVyZS5jb2wpKSArIAogIHNjYWxlX3NpemVfbWFudWFsKAogICAgIk90aGVyIGZlYXR1cmVzIiwgdmFsdWVzPXJlcCgyLDMpLAogICAgZ3VpZGU9Z3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoY29sb3VyPWMoIiM2YTNkOWEiLCAiI2UzMWExYyIsIGFscGhhKCJvcmFuZ2U0IiwuNSkpKSkKICApICsKICBndWlkZXMoYWxwaGEgPSAibm9uZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMjUwMCw1MDApLCBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IDAuMDIpKSArCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemUgPSAxMikgKyBiYWNrZ3JvdW5kX2dyaWQobWFqb3IgPSAieCIpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNSksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueSA9IGVsZW1lbnRfYmxhbmsoKSwjIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAjYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCksIyBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjY1LCAwLjQ1KSwgbGVnZW5kLmJveCA9ICJob3Jpem9udGFsIiwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSBhbHBoYSgibGlnaHRibHVlIiwwLjEpKSkgKwogIGxhYnMoeSA9ICJQb3NpdGlvbiBpbiBzZXF1ZW5jZSIsIHggPSAiU2VxdWVuY2VzIiwgY29sb3IgPSAiUGZhbSBkb21haW5zIikKZ2dzYXZlKCJvdXRwdXQvZmlndXJlLzIwMjEwNzIwLWN3cC1jYW5kaWRhdGVzLWRvbWFpbi1zY2hlbWF0aWMucG5nIiwgd2lkdGggPSA3LjIsIGhlaWdodCA9IDUuNCkKYGBg