RNAhybrid is a miRNA-mRNA target prediction tool, which bases its predictions primarily on thermodynamic binding stability.
Inputs:
- miRNA “query” FASTA file – mature miRNA sequences, since the mature miRNA molecule is what will presumably bind to an mRNA
- mRNA “target” FASTA file – the A. pulchra genome fasta
target prediction for full mRNA
While miRNas are primarily observed binding to the 3’ UTR region of mRNAs, they are also believed to functionally bind to CDS regions, though effects on translation are weaker.
formate mRNA fasta
get a gff file of only CDS sequences
Notably, RNAhybrid only accepts FASTA sequences of 1000 characters or fewer. We’ll need to ensure the CDS file only contains sequences of <1000bp, and break up the sequences that are too long.
wc -l ../output/05-Apul-annotate-UTRs/Apulcra-genome-mRNA_only.gff
awk '{if ($5 - $4 > 1000) count++} END {print count}' ../output/05-Apul-annotate-UTRs/Apulcra-genome-mRNA_only.gff
head -2 ../output/05-Apul-annotate-UTRs/Apulcra-genome-mRNA_only.gff
## 36447 ../output/05-Apul-annotate-UTRs/Apulcra-genome-mRNA_only.gff
## 28668
## ntLink_0 funannotate mRNA 1105 7056 . + . ID=FUN_000001-T1;Parent=FUN_000001;product=hypothetical protein;
## ntLink_0 funannotate mRNA 10215 15286 . + . ID=FUN_000002-T1;Parent=FUN_000002;product=hypothetical protein;
Welp, looks like the genome-based mRNA gff largely contains long, >1000bp sequences (28668/36447, or 78.7%)
First let’s deal with the long sequences while we’re in the compact gff form. I want to break up any sequence >1000bp into 1000bp chunks, adding a line to the gff for each chunk.
(I also want there to be overlap among the chunks, in case the break between two chunks falls in the middle of an miRNA binding site. Let’s say a 25bp overlap, since that is just over the maximum expected miRNA length.)
for now let’s not worry about the overlap.
awk -v chunk_size=1000 '
BEGIN {OFS="\t"}
{
seq_length = $5 - $4
if (seq_length > chunk_size) {
start = $4
ogend = $5
while (start < ogend) {
end = start + chunk_size
if (end > ogend) end = ogend
$4 = start
$5 = end
print
start = end
}
} else {
print
}
}' "../output/05-Apul-annotate-UTRs/Apulcra-genome-mRNA_only.gff" > "../data/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff"
wc -l ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff
awk '{if ($5 - $4 > 1000) count++} END {print count}' ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff
head -50 ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff | tail -5
echo ""
echo ""
awk -F'\t' 'NF > 9 {count++} END {print count}' ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff
head -50 ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff | tail -5 | awk -F'\t' '{print $9}'
head -50 ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff | tail -5 | awk -F'\t' '{print $10}'
Fix # columns issue. Replace any instances of “hypothetical [tab] protein” with “hypothetical [space] protein”
sed 's/hypothetical\tprotein/hypothetical protein/g' ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff > ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000_formatted.gff
Check
awk -F'\t' 'NF > 9 {count++} END {print count}' ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000_formatted.gff
get an mRNA fasta file
/home/shared/bedtools2/bin/bedtools getfasta -fi "../data/Apulchra-genome.fa" -bed "../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000_formatted.gff" -fo "../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.fa"
Ok, we now have a fasta file of mRNA sequences, broken up so that no sequence exceeds 1000bp. We should now be able to run RNAhybrid!
I have RNAhybrid installed on a miniconda environment
# Check path to the conda environment I'm using
which conda
# Install RNAhybrid if neccessary
conda install -y -c genomedk rnahybrid
# Check installation
conda list rnahybrid
RNAcalibrate
Note: I’m not using the RNAcalibrate results for now because of a weird issue with all-zero RNAhybrid pvals.
RNAcalibrate \
-t ../output/05-Apul-annotate-UTRs/Apul_3UTR_1kb.fasta \
-q ../data/06-Apul-miRNA-mRNA-RNAhybrid/miRNA_mature-Apul.fasta \
> ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAcalibrate-3UTR.txt
RNAcalibrate_out <- read.table("../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAcalibrate-3UTR.txt", sep = " ")
ggplot(RNAcalibrate_out, aes(x = V3)) +
geom_histogram(aes(y = after_stat(density)), binwidth = 0.05, fill = "blue", color = "black", alpha = 0.7) +
geom_density(color = "red", size = 1) +
geom_vline(aes(xintercept = mean(V3)), color = "red", linetype = "dashed", size = 1) +
geom_text(aes(x = mean(V3) + 0.15, y = 4, label = paste("Mean =", round(mean(V3), 2))),
color = "red", vjust = -0.5, hjust = 1.2) +
labs(title = "Distance Parameter distribution", x = "Values", y = "Density")
ggplot(RNAcalibrate_out, aes(x = V4)) +
geom_histogram(aes(y = after_stat(density)), binwidth = 0.005, fill = "blue", color = "black", alpha = 0.7) +
geom_density(color = "red", size = 1) +
geom_vline(aes(xintercept = mean(V4)), color = "red", linetype = "dashed", size = 1) +
geom_text(aes(x = mean(V4) + 0.017, y = 37, label = paste("Mean =", round(mean(V4), 2))),
color = "red", vjust = -0.5, hjust = 1.2) +
labs(title = "Shape Parameter distribution", x = "Values", y = "Density")
RNAcalibrate \
-t ../data/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.fa \
-q ../data/06-Apul-miRNA-mRNA-RNAhybrid/miRNA_mature-Apul.fasta \
> ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAcalibrate-mRNA.txt
RNAcalibrate_out <- read.table("../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAcalibrate-mRNA.txt", sep = " ")
ggplot(RNAcalibrate_out, aes(x = V3)) +
geom_histogram(aes(y = after_stat(density)), binwidth = 0.05, fill = "blue", color = "black", alpha = 0.7) +
geom_density(color = "red", size = 1) +
geom_vline(aes(xintercept = mean(V3)), color = "red", linetype = "dashed", size = 1) +
geom_text(aes(x = mean(V3) + 0.15, y = 4, label = paste("Mean =", round(mean(V3), 2))),
color = "red", vjust = -0.5, hjust = 1.2) +
labs(title = "Distance Parameter distribution", x = "Values", y = "Density")
ggplot(RNAcalibrate_out, aes(x = V4)) +
geom_histogram(aes(y = after_stat(density)), binwidth = 0.005, fill = "blue", color = "black", alpha = 0.7) +
geom_density(color = "red", size = 1) +
geom_vline(aes(xintercept = mean(V4)), color = "red", linetype = "dashed", size = 1) +
geom_text(aes(x = mean(V4) + 0.017, y = 37, label = paste("Mean =", round(mean(V4), 2))),
color = "red", vjust = -0.5, hjust = 1.2) +
labs(title = "Shape Parameter distribution", x = "Values", y = "Density")
Distributions looks roughly normal, so I’ll use the mean distance and shape parameters calculated by RNAcalibrate as input in RNAhybrid.
RNAhybrid: mRNA file
I’m having problems using the RNAcalibrate estimated parameters, where every output hybridization has a p-value of 0. This still happens if I remove the -e
energy cutoff and the -p
pvalue cutoff, so the -d
parameter specification must be causing it.
I’ll use a built-in estimation for now, since those result in reasonable pvalues. Options are 3utr_human, 3utr_fly, and 3utr-worm. Not sure if fly or worm is most closely related to corals (they’re both quite distant), but I’ll just arbitrarily pick worm for now.
RNAhybrid \
-s 3utr_worm \
-e -20 \
-p 0.05 \
-c \
-t ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.fa \
-q ../data/06-Apul-miRNA-mRNA-RNAhybrid/miRNA_mature-Apul.fasta \
> ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-mRNA-compact_3utrworm.txt
RNAhybrid: 3’UTR
RNAhybrid \
-s 3utr_worm \
-e -20 \
-p 0.05 \
-c \
-t ../output/05-Apul-annotate-UTRs/Apul_3UTR_1kb.fasta \
-q ../data/06-Apul-miRNA-mRNA-RNAhybrid/miRNA_mature-Apul.fasta \
> ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-3UTR-compact_3utrworm.txt
RNAhybrid: 5’UTR
RNAhybrid \
-s 3utr_worm \
-e -20 \
-p 0.05 \
-c \
-t ../output/05-Apul-annotate-UTRs/Apul_5UTR_1kb.fasta \
-q ../data/06-Apul-miRNA-mRNA-RNAhybrid/miRNA_mature-Apul.fasta \
> ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-5UTR-compact_3utrworm.txt
Summarize results
wc -l ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-mRNA-compact_3utrworm.txt
wc -l ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-5UTR-compact_3utrworm.txt
wc -l ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-3UTR-compact_3utrworm.txt
## 6559 ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-mRNA-compact_3utrworm.txt
## 1191 ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-5UTR-compact_3utrworm.txt
## 1041 ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-3UTR-compact_3utrworm.txt
head -5 ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-3UTR-compact_3utrworm.txt
## ntLink_8:32704327-32705327:999:Cluster_1832.mature::ntLink_6:4847465-4847486(-):22:-27.8:0.036639:710:A A : ACAAGGAGAGUGCUGU : UGUUUCUUUCACGAUA : CUAGUA
## ntLink_3:84074-84461:387:Cluster_1832.mature::ntLink_6:4847465-4847486(-):22:-26.7:0.014807:51: C U : GAGAGUGCUGUGGUU : CUUUCACGAUACUAG :UGUUU UA
## ntLink_6:2139830-2140830:999:Cluster_1832.mature::ntLink_6:4847465-4847486(-):22:-27.7:0.038633:949: G G : GGGGGGGGUGCUAUGAU : UUUCUUUCACGAUACUA :UG GUA
## ptg000001l:20692198-20693198:999:Cluster_1832.mature::ntLink_6:4847465-4847486(-):22:-30.0:0.011310:399: A U : GAGGAAGGUGUUAUGAUC : UUUCUUUCACGAUACUAG :UG UA
## ptg000018l:9119047-9120047:999:Cluster_1832.mature::ntLink_6:4847465-4847486(-):22:-28.0:0.032950:773:U A : GCAAGGAGAGUGCUAU : UGUUUCUUUCACGAUA : CUAGUA
Now let’s read our RNAhybrid results into R for visualization. Note this is going to be slightly more complicated than it sounds because the RNAhybrid compact output is colon-delimited and our target- and query-IDs contain intentional colons than could get confused with column delimiters.
mRNA output:
options(scipen=999)
options(digits = 10)
RNAhybrid_mRNA <- read.table("../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-mRNA-compact_3utrworm.txt", sep=":")
RNAhybrid_mRNA$V1 <- paste(RNAhybrid_mRNA$V1, RNAhybrid_mRNA$V2, sep = ":")
RNAhybrid_mRNA$V2 <- NULL
RNAhybrid_mRNA$V4 <- paste(RNAhybrid_mRNA$V4, RNAhybrid_mRNA$V5, RNAhybrid_mRNA$V6, RNAhybrid_mRNA$V7 , sep = ":")
RNAhybrid_mRNA$V4 <- gsub(":NA:", "::", RNAhybrid_mRNA$V4)
RNAhybrid_mRNA$V5 <- NULL
RNAhybrid_mRNA$V6 <- NULL
RNAhybrid_mRNA$V7 <- NULL
colnames(RNAhybrid_mRNA) <- c("target_name", "target_length", "query_name", "query_length",
"mfe", "pval", "position",
"noncomp_target_seq", "comp_target_seq", "comp_query_seq", "noncomp_query_seq")
5’UTR output:
RNAhybrid_5UTR <- read.table("../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-5UTR-compact_3utrworm.txt", sep=":")
RNAhybrid_5UTR$V1 <- paste(RNAhybrid_5UTR$V1, RNAhybrid_5UTR$V2, sep = ":")
RNAhybrid_5UTR$V2 <- NULL
RNAhybrid_5UTR$V4 <- paste(RNAhybrid_5UTR$V4, RNAhybrid_5UTR$V5, RNAhybrid_5UTR$V6, RNAhybrid_5UTR$V7 , sep = ":")
RNAhybrid_5UTR$V4 <- gsub(":NA:", "::", RNAhybrid_5UTR$V4)
RNAhybrid_5UTR$V5 <- NULL
RNAhybrid_5UTR$V6 <- NULL
RNAhybrid_5UTR$V7 <- NULL
colnames(RNAhybrid_5UTR) <- c("target_name", "target_length", "query_name", "query_length",
"mfe", "pval", "position",
"noncomp_target_seq", "comp_target_seq", "comp_query_seq", "noncomp_query_seq")
3’UTR output:
RNAhybrid_3UTR <- read.table("../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-3UTR-compact_3utrworm.txt", sep=":")
RNAhybrid_3UTR$V1 <- paste(RNAhybrid_3UTR$V1, RNAhybrid_3UTR$V2, sep = ":")
RNAhybrid_3UTR$V2 <- NULL
RNAhybrid_3UTR$V4 <- paste(RNAhybrid_3UTR$V4, RNAhybrid_3UTR$V5, RNAhybrid_3UTR$V6, RNAhybrid_3UTR$V7 , sep = ":")
RNAhybrid_3UTR$V4 <- gsub(":NA:", "::", RNAhybrid_3UTR$V4)
RNAhybrid_3UTR$V5 <- NULL
RNAhybrid_3UTR$V6 <- NULL
RNAhybrid_3UTR$V7 <- NULL
colnames(RNAhybrid_3UTR) <- c("target_name", "target_length", "query_name", "query_length",
"mfe", "pval", "position",
"noncomp_target_seq", "comp_target_seq", "comp_query_seq", "noncomp_query_seq")
RNAhybrid_mRNA$Dataset <- "Dataset 1"
RNAhybrid_5UTR$Dataset <- "Dataset 2"
RNAhybrid_3UTR$Dataset <- "Dataset 3"
combined_data <- rbind(RNAhybrid_mRNA, RNAhybrid_5UTR, RNAhybrid_3UTR)
ggplot(combined_data, aes(x = pval)) +
geom_histogram(binwidth = 0.005, color = "black", fill = "skyblue") +
facet_wrap(~Dataset) +
theme_minimal() +
labs(title = "Histogram of Column C", x = "C", y = "Frequency")

I’d also like to get the RNAhybrid results in a gff form for IGV visualization
Save outputs as tab-delimited files
write.table(RNAhybrid_mRNA, file="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-mRNA-compact_3utr_worm-formatted.txt", sep="\t", row.names = FALSE, col.names=TRUE, quote = FALSE)
write.table(RNAhybrid_5UTR, file="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-5UTR-compact_3utr_worm-formatted.txt", sep="\t", row.names = FALSE, quote = FALSE)
write.table(RNAhybrid_3UTR, file="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-3UTR-compact_3utr_worm-formatted.txt", sep="\t", row.names = FALSE, quote = FALSE)
Now convert these formatted RNAhybrid output into a gff-formatted file
mRNA:
#!/bin/bash
INPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-mRNA-compact_3utr_worm-formatted.txt"
OUTPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-mRNA-compact_3utr_worm.gff"
echo "##gff-version 3" > "$OUTPUT_FILE"
tail -n +2 "$INPUT_FILE" | while IFS=$'\t' read -r target_name target_length query_name query_length mfe pval position noncomp_target_seq comp_target_seq comp_query_seq noncomp_query_seq
do
locus=$(echo "$target_name" | cut -d':' -f1)
start_coord=$(echo "$target_name" | cut -d':' -f2 | cut -d'-' -f1)
start_gff=$((start_coord + position))
end_gff=$((start_gff + query_length))
strand=$(echo "$query_name" | grep -o '(-\|+)' | tr -d '()')
echo -e "$locus\tRNAhybrid\tmiRNA_binding\t$start_gff\t$end_gff\t.\t$strand\t.\tID=$query_name;MFE=$mfe;Pval=$pval" >> "$OUTPUT_FILE"
done
5’UTR:
#!/bin/bash
INPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-5UTR-compact_3utr_worm-formatted.txt"
OUTPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-5UTR-compact_3utr_worm.gff"
echo "##gff-version 3" > "$OUTPUT_FILE"
tail -n +2 "$INPUT_FILE" | while IFS=$'\t' read -r target_name target_length query_name query_length mfe pval position noncomp_target_seq comp_target_seq comp_query_seq noncomp_query_seq
do
locus=$(echo "$target_name" | cut -d':' -f1)
start_coord=$(echo "$target_name" | cut -d':' -f2 | cut -d'-' -f1)
start_gff=$((start_coord + position))
end_gff=$((start_gff + query_length))
strand=$(echo "$query_name" | grep -o '(-\|+)' | tr -d '()')
echo -e "$locus\tRNAhybrid\tmiRNA_binding\t$start_gff\t$end_gff\t.\t$strand\t.\tID=$query_name;MFE=$mfe;Pval=$pval" >> "$OUTPUT_FILE"
done
3’UTR:
#!/bin/bash
INPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-3UTR-compact_3utr_worm-formatted.txt"
OUTPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-3UTR-compact_3utr_worm.gff"
echo "##gff-version 3" > "$OUTPUT_FILE"
tail -n +2 "$INPUT_FILE" | while IFS=$'\t' read -r target_name target_length query_name query_length mfe pval position noncomp_target_seq comp_target_seq comp_query_seq noncomp_query_seq
do
locus=$(echo "$target_name" | cut -d':' -f1)
start_coord=$(echo "$target_name" | cut -d':' -f2 | cut -d'-' -f1)
start_gff=$((start_coord + position))
end_gff=$((start_gff + query_length))
strand=$(echo "$query_name" | grep -o '(-\|+)' | tr -d '()')
echo -e "$locus\tRNAhybrid\tmiRNA_binding\t$start_gff\t$end_gff\t.\t$strand\t.\tID=$query_name;MFE=$mfe;Pval=$pval" >> "$OUTPUT_FILE"
done
LS0tCnRpdGxlOiAiMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZCIKYXV0aG9yOiAiS2F0aGxlZW4gRHVya2luIgpkYXRlOiAiMjAyNC0xMi0xOSIKYWx3YXlzX2FsbG93X2h0bWw6IHRydWUKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGdpdGh1Yl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGh0bWxfcHJldmlldzogdHJ1ZSAKLS0tCgpgYGB7ciBsb2FkLXBhY2thZ2VzfQpsaWJyYXJ5KGdncGxvdDIpCgpgYGAKClJOQWh5YnJpZCBpcyBhIG1pUk5BLW1STkEgdGFyZ2V0IHByZWRpY3Rpb24gdG9vbCwgd2hpY2ggYmFzZXMgaXRzIHByZWRpY3Rpb25zIHByaW1hcmlseSBvbiB0aGVybW9keW5hbWljIGJpbmRpbmcgc3RhYmlsaXR5LiAKCklucHV0czoKLSBtaVJOQSAicXVlcnkiIEZBU1RBIGZpbGUgLS0gbWF0dXJlIG1pUk5BIHNlcXVlbmNlcywgc2luY2UgdGhlIG1hdHVyZSBtaVJOQSBtb2xlY3VsZSBpcyB3aGF0IHdpbGwgcHJlc3VtYWJseSBiaW5kIHRvIGFuIG1STkEKICAKLSBtUk5BICJ0YXJnZXQiIEZBU1RBIGZpbGUgLS0gdGhlICpBLiBwdWxjaHJhKiBnZW5vbWUgZmFzdGEKCgojIGZvcm1hdCBtaVJOQSBmYXN0YQoKU2hvcnRTdGFjayBvdXRwdXRzIGEgZmFzdGEgY29udGFpbmluZyBhbGwgYW5ub3RhdGVkIG1pUk5BcywgYnV0IGl0IGluY2x1ZGVzIHRoZSBmdWxsIHByZWN1cnNvciBzZXF1ZW5jZSBhbmQgc3RhciBzZXF1ZW5jZSwgaW4gYWRkaXRpb24gdG8gdGhlIG1hdHVyZSBtaVJOQS4gU2luY2UgbWF0dXJlIG1pUk5BcyBhcmUgdGhlICJmaW5hbCBmb3JtcyIgdGhhdCBhcmUgZ2VuZXJhbGx5IG11Y2ggbW9yZSBoaWdobHkgZXhwcmVzc2VkLCB3ZSdsbCBqdXN0IGxvb2sgYXQgYmluZGluZyBvZiBtYXR1cmUgbWlSTkFzIGZvciBub3cuIAoKYGBge3IsIGVuZ2luZT0nYmFzaCd9CiMgbG9vayBhdCBtaVJOQSBmYXN0YSBmaWxlCmhlYWQgLTUgLi4vb3V0cHV0LzA0LUFwdWwtc1JOQS1kaXNjb3ZlcnktU2hvcnRTdGFjay9TaG9ydFN0YWNrX291dC9taXIuZmFzdGEKCmVjaG8gIiIKCiMgY2hlY2sgdGhlIG5hbWluZyBjb252ZW50aW9uIGZvciBzZXF1ZW5jZXMKZ3JlcCAiXj4iIC4uL291dHB1dC8wNC1BcHVsLXNSTkEtZGlzY292ZXJ5LVNob3J0U3RhY2svU2hvcnRTdGFja19vdXQvbWlyLmZhc3RhIHwgaGVhZCAtMTAKCiMgaXNvbGF0ZSBqdXN0IHRoZSBtYXR1cmUgbWlSTkEgc2VxdWVuY2VzCmF3ayAnL14+LyB7aGVhZGVyPSQwfSAvbWF0dXJlLyB7cHJpbnQgaGVhZGVyOyBmb3VuZD0xOyBuZXh0fSBmb3VuZCB7cHJpbnQ7IGZvdW5kPTB9JyAuLi9vdXRwdXQvMDQtQXB1bC1zUk5BLWRpc2NvdmVyeS1TaG9ydFN0YWNrL1Nob3J0U3RhY2tfb3V0L21pci5mYXN0YSA+IC4uL2RhdGEvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9taVJOQV9tYXR1cmUtQXB1bC5mYXN0YQoKZWNobyAiIgoKIyBjaGVjayBmaWx0ZXJlZCBmaWxlCmhlYWQgLTYgLi4vZGF0YS8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL21pUk5BX21hdHVyZS1BcHVsLmZhc3RhCmBgYAoKIyB0YXJnZXQgcHJlZGljdGlvbiBmb3IgZnVsbCBtUk5BCgpXaGlsZSBtaVJOYXMgYXJlIHByaW1hcmlseSBvYnNlcnZlZCBiaW5kaW5nIHRvIHRoZSAzJyBVVFIgcmVnaW9uIG9mIG1STkFzLCB0aGV5IGFyZSBhbHNvIGJlbGlldmVkIHRvIGZ1bmN0aW9uYWxseSBiaW5kIHRvIENEUyByZWdpb25zLCB0aG91Z2ggZWZmZWN0cyBvbiB0cmFuc2xhdGlvbiBhcmUgd2Vha2VyLgoKIyBmb3JtYXRlIG1STkEgZmFzdGEKCmdldCBhIGdmZiBmaWxlIG9mIG9ubHkgQ0RTIHNlcXVlbmNlcwoKTm90YWJseSwgUk5BaHlicmlkIG9ubHkgYWNjZXB0cyBGQVNUQSBzZXF1ZW5jZXMgb2YgMTAwMCBjaGFyYWN0ZXJzIG9yIGZld2VyLiBXZSdsbCBuZWVkIHRvIGVuc3VyZSB0aGUgQ0RTIGZpbGUgb25seSBjb250YWlucyBzZXF1ZW5jZXMgb2YgPDEwMDBicCwgYW5kIGJyZWFrIHVwIHRoZSBzZXF1ZW5jZXMgdGhhdCBhcmUgdG9vIGxvbmcuCgpgYGB7ciBjaGVjay1nZW5vbWUtc2VxLWxlbmd0aHMsIGVuZ2luZT0nYmFzaCd9CgojIG1STkEtb25seSBnZW5vbWUgZ2ZmCiMgQ291bnQgdG90YWwgc2VxdWVuY2VzIGluIGdlbm9tZSBnZmYKd2MgLWwgLi4vb3V0cHV0LzA1LUFwdWwtYW5ub3RhdGUtVVRScy9BcHVsY3JhLWdlbm9tZS1tUk5BX29ubHkuZ2ZmCgojIENvdW50IHRoZSBudW1iZXIgb2Ygc2VxdWVuY2VzIHRoYXQgY29udGFpbiA+MTAwMCBicAphd2sgJ3tpZiAoJDUgLSAkNCA+IDEwMDApIGNvdW50Kyt9IEVORCB7cHJpbnQgY291bnR9JyAuLi9vdXRwdXQvMDUtQXB1bC1hbm5vdGF0ZS1VVFJzL0FwdWxjcmEtZ2Vub21lLW1STkFfb25seS5nZmYKCiMgQ2hlY2sgaG93IHRoZSBzZXF1ZW5jZSBuYW1lcyBhcmUgZm9ybWF0dGVkCmhlYWQgLTIgLi4vb3V0cHV0LzA1LUFwdWwtYW5ub3RhdGUtVVRScy9BcHVsY3JhLWdlbm9tZS1tUk5BX29ubHkuZ2ZmCgpgYGAKV2VscCwgbG9va3MgbGlrZSB0aGUgZ2Vub21lLWJhc2VkIG1STkEgZ2ZmIGxhcmdlbHkgY29udGFpbnMgbG9uZywgPjEwMDBicCBzZXF1ZW5jZXMgKDI4NjY4LzM2NDQ3LCBvciA3OC43JSkKCkZpcnN0IGxldCdzIGRlYWwgd2l0aCB0aGUgbG9uZyBzZXF1ZW5jZXMgd2hpbGUgd2UncmUgaW4gdGhlIGNvbXBhY3QgZ2ZmIGZvcm0uIEkgd2FudCB0byBicmVhayB1cCBhbnkgc2VxdWVuY2UgPjEwMDBicCBpbnRvIDEwMDBicCBjaHVua3MsIGFkZGluZyBhIGxpbmUgdG8gdGhlIGdmZiBmb3IgZWFjaCBjaHVuay4gCgooSSBhbHNvIHdhbnQgdGhlcmUgdG8gYmUgb3ZlcmxhcCBhbW9uZyB0aGUgY2h1bmtzLCBpbiBjYXNlIHRoZSBicmVhayBiZXR3ZWVuIHR3byBjaHVua3MgZmFsbHMgaW4gdGhlIG1pZGRsZSBvZiBhbiBtaVJOQSBiaW5kaW5nIHNpdGUuIExldCdzIHNheSBhIDI1YnAgb3ZlcmxhcCwgc2luY2UgdGhhdCBpcyBqdXN0IG92ZXIgdGhlIG1heGltdW0gZXhwZWN0ZWQgbWlSTkEgbGVuZ3RoLikKCmZvciBub3cgbGV0J3Mgbm90IHdvcnJ5IGFib3V0IHRoZSBvdmVybGFwLgoKYGBge3IsIGVuZ2luZT0nYmFzaCcsIGV2YWw9RkFMU0V9CmF3ayAtdiBjaHVua19zaXplPTEwMDAgJwpCRUdJTiB7T0ZTPSJcdCJ9CnsKICAgIHNlcV9sZW5ndGggPSAkNSAtICQ0CiAgICBpZiAoc2VxX2xlbmd0aCA+IGNodW5rX3NpemUpIHsKICAgICAgICBzdGFydCA9ICQ0CiAgICAgICAgb2dlbmQgPSAkNQogICAgICAgIHdoaWxlIChzdGFydCA8IG9nZW5kKSB7CiAgICAgICAgICAgIGVuZCA9IHN0YXJ0ICsgY2h1bmtfc2l6ZSAKICAgICAgICAgICAgaWYgKGVuZCA+IG9nZW5kKSBlbmQgPSBvZ2VuZAogICAgICAgICAgICAkNCA9IHN0YXJ0CiAgICAgICAgICAgICQ1ID0gZW5kCiAgICAgICAgICAgIHByaW50CiAgICAgICAgICAgIHN0YXJ0ID0gZW5kCiAgICAgICAgfQogICAgfSBlbHNlIHsKICAgICAgICBwcmludAogICAgfQp9JyAiLi4vb3V0cHV0LzA1LUFwdWwtYW5ub3RhdGUtVVRScy9BcHVsY3JhLWdlbm9tZS1tUk5BX29ubHkuZ2ZmIiA+ICIuLi9kYXRhLzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bGNyYS1nZW5vbWUtbVJOQV9vbmx5X01BWDEwMDAuZ2ZmIgoKYGBgCgpgYGB7ciwgZW5naW5lPSdiYXNoJywgZXZhbD1GQUxTRX0KCiMgbVJOQS1vbmx5IGdlbm9tZSBnZmYKIyBDb3VudCB0b3RhbCBzZXF1ZW5jZXMgaW4gZ2Vub21lIGdmZgp3YyAtbCAuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsY3JhLWdlbm9tZS1tUk5BX29ubHlfTUFYMTAwMC5nZmYKCiMgQ291bnQgdGhlIG51bWJlciBvZiBzZXF1ZW5jZXMgdGhhdCBjb250YWluID4xMDAwIGJwCmF3ayAne2lmICgkNSAtICQ0ID4gMTAwMCkgY291bnQrK30gRU5EIHtwcmludCBjb3VudH0nIC4uL291dHB1dC8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL0FwdWxjcmEtZ2Vub21lLW1STkFfb25seV9NQVgxMDAwLmdmZgoKIyBDaGVjayBob3cgdGhlIHNlcXVlbmNlIG5hbWVzIGFyZSBmb3JtYXR0ZWQKaGVhZCAtNTAgLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bGNyYS1nZW5vbWUtbVJOQV9vbmx5X01BWDEwMDAuZ2ZmIHwgdGFpbCAtNQoKZWNobyAiIgplY2hvICIiCgojIEknbSBnZXR0aW5nIGFuIGVycm9yIGluIGdldGZhc3RhIHJlbGF0ZWQgdG8gc29tZSBsaW5lcyBvZiB0aGUgZ2ZmIGhhdmluZyBhIGRpZmZlcmVudCBudW1iZXIgb2YgY29sdW1ucy4KIyBFYWNoIGxpbmUgc2hvdWxkIGNvbnRhaW4gOSBjb2x1bW5zLiBDb3VudCBudW1iZXIgb2YgbGluZXMgd2l0aCBtb3JlIHRoYW4gOQphd2sgLUYnXHQnICdORiA+IDkge2NvdW50Kyt9IEVORCB7cHJpbnQgY291bnR9JyAuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsY3JhLWdlbm9tZS1tUk5BX29ubHlfTUFYMTAwMC5nZmYKCiMgRm9yIHNvbWUgbGluZXMsIHRoZSBmaW5hbCBjb2x1bW4gaXMgYmVpbmcgaW50ZXJwcmV0ZWQgYXMgdHdvIGNvbHVtbnMKaGVhZCAtNTAgLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bGNyYS1nZW5vbWUtbVJOQV9vbmx5X01BWDEwMDAuZ2ZmIHwgdGFpbCAtNSB8IGF3ayAtRidcdCcgJ3twcmludCAkOX0nCmhlYWQgLTUwIC4uL291dHB1dC8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL0FwdWxjcmEtZ2Vub21lLW1STkFfb25seV9NQVgxMDAwLmdmZiB8IHRhaWwgLTUgfCBhd2sgLUYnXHQnICd7cHJpbnQgJDEwfScKCmBgYAoKRml4ICMgY29sdW1ucyBpc3N1ZS4gUmVwbGFjZSBhbnkgaW5zdGFuY2VzIG9mICJoeXBvdGhldGljYWwgW3RhYl0gcHJvdGVpbiIgd2l0aCAiaHlwb3RoZXRpY2FsIFtzcGFjZV0gcHJvdGVpbiIKYGBge3IsIGVuZ2luZT0nYmFzaCcsIGV2YWw9RkFMU0V9CiMgUmVwbGFjZSBhbnkgaW5zdGFuY2VzIG9mICJoeXBvdGhldGljYWwgLXRhYi0gcHJvdGVpbiIgd2l0aCAiaHlwb3RoZXRpY2FsIC1zcGFjZS0gcHJvdGVpbiIKc2VkICdzL2h5cG90aGV0aWNhbFx0cHJvdGVpbi9oeXBvdGhldGljYWwgcHJvdGVpbi9nJyAgLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bGNyYS1nZW5vbWUtbVJOQV9vbmx5X01BWDEwMDAuZ2ZmID4gLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bGNyYS1nZW5vbWUtbVJOQV9vbmx5X01BWDEwMDBfZm9ybWF0dGVkLmdmZgpgYGAKCkNoZWNrCmBgYHtyLCBlbmdpbmU9J2Jhc2gnfQojIENvdW50IG51bWJlciBvZiBlbnRyaWVzIHdpdGggPjkgY29sdW1ucyAoc2hvdWxkIGJlIG5vdGhpbmcgbm93KQphd2sgLUYnXHQnICdORiA+IDkge2NvdW50Kyt9IEVORCB7cHJpbnQgY291bnR9JyAuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsY3JhLWdlbm9tZS1tUk5BX29ubHlfTUFYMTAwMF9mb3JtYXR0ZWQuZ2ZmCmBgYAoKZ2V0IGFuIG1STkEgZmFzdGEgZmlsZQpgYGB7ciwgZW5naW5lPSdiYXNoJywgZXZhbD1GQUxTRX0KCiMgVXNlIG1STkEgZ2ZmIGFuZCBnZW5vbWUgZmFzdGEgdG8gZXh0cmFjdCBtUk5BIGZhc3RhcwovaG9tZS9zaGFyZWQvYmVkdG9vbHMyL2Jpbi9iZWR0b29scyBnZXRmYXN0YSAtZmkgIi4uL2RhdGEvQXB1bGNocmEtZ2Vub21lLmZhIiAtYmVkICIuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsY3JhLWdlbm9tZS1tUk5BX29ubHlfTUFYMTAwMF9mb3JtYXR0ZWQuZ2ZmIiAtZm8gIi4uL291dHB1dC8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL0FwdWxjcmEtZ2Vub21lLW1STkFfb25seV9NQVgxMDAwLmZhIgoKYGBgCgoKT2ssIHdlIG5vdyBoYXZlIGEgZmFzdGEgZmlsZSBvZiBtUk5BIHNlcXVlbmNlcywgYnJva2VuIHVwIHNvIHRoYXQgbm8gc2VxdWVuY2UgZXhjZWVkcyAxMDAwYnAuIFdlIHNob3VsZCBub3cgYmUgYWJsZSB0byBydW4gUk5BaHlicmlkIQoKSSBoYXZlIFJOQWh5YnJpZCBpbnN0YWxsZWQgb24gYSBtaW5pY29uZGEgZW52aXJvbm1lbnQKYGBgCiMgQ2hlY2sgcGF0aCB0byB0aGUgY29uZGEgZW52aXJvbm1lbnQgSSdtIHVzaW5nCndoaWNoIGNvbmRhCgojIEluc3RhbGwgUk5BaHlicmlkIGlmIG5lY2Nlc3NhcnkKY29uZGEgaW5zdGFsbCAteSAtYyBnZW5vbWVkayBybmFoeWJyaWQKCiMgQ2hlY2sgaW5zdGFsbGF0aW9uCmNvbmRhIGxpc3Qgcm5haHlicmlkCmBgYAojIFJOQWNhbGlicmF0ZQoKTm90ZTogSSdtIG5vdCB1c2luZyB0aGUgUk5BY2FsaWJyYXRlIHJlc3VsdHMgZm9yIG5vdyBiZWNhdXNlIG9mIGEgd2VpcmQgaXNzdWUgd2l0aCBhbGwtemVybyBSTkFoeWJyaWQgcHZhbHMuCgpgYGB7ciwgZW5naW5lPSdiYXNoJywgZXZhbD1GQUxTRX0KIyBSTkFoeWJyaWQgb25seSBoYXMgYnVpbHQtaW4gc3VwcG9ydCBmb3IgaHVtYW5zLCB3b3JtcywgYW5kIGZsaWVzLgojIFdlIGNhbiB1c2UgUk5BY2FsaWJyYXRlIHRvIGRlcml2ZSBFeHRyZW1lIFZhbHVlIERpc3RyaWJ1dGlvbiBwYXJhbWV0ZXJzIGZvciBvdXIgZGF0YS4KCiMgVVNlIDMnVVRSIGFzIGlucHV0LCBzaW5jZSB3ZSBleHBlY3QgbWFqb3JpdHkgYmluZGluZyB0aGVyZQpSTkFjYWxpYnJhdGUgXAotdCAuLi9vdXRwdXQvMDUtQXB1bC1hbm5vdGF0ZS1VVFJzL0FwdWxfM1VUUl8xa2IuZmFzdGEgXAotcSAuLi9kYXRhLzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvbWlSTkFfbWF0dXJlLUFwdWwuZmFzdGEgXAo+IC4uL291dHB1dC8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL0FwdWwtUk5BY2FsaWJyYXRlLTNVVFIudHh0CmBgYAoKYGBge3IsIGV2YWw9RkFMU0V9CgojIE5vdyB3ZSBuZWVkIHRvIHBpY2sgYSBkaXN0YW5jZSBwYXJhbWV0ZXIgYW5kIHNoYXBlIHBhcmFtZXRlcgpSTkFjYWxpYnJhdGVfb3V0IDwtIHJlYWQudGFibGUoIi4uL291dHB1dC8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL0FwdWwtUk5BY2FsaWJyYXRlLTNVVFIudHh0Iiwgc2VwID0gIiAiKQoKZ2dwbG90KFJOQWNhbGlicmF0ZV9vdXQsIGFlcyh4ID0gVjMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwgYmlud2lkdGggPSAwLjA1LCBmaWxsID0gImJsdWUiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gInJlZCIsIHNpemUgPSAxKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lYW4oVjMpKSwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IDEpICsKICBnZW9tX3RleHQoYWVzKHggPSBtZWFuKFYzKSArIDAuMTUsIHkgPSA0LCBsYWJlbCA9IHBhc3RlKCJNZWFuID0iLCByb3VuZChtZWFuKFYzKSwgMikpKSwgCiAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIHZqdXN0ID0gLTAuNSwgaGp1c3QgPSAxLjIpICsKICBsYWJzKHRpdGxlID0gIkRpc3RhbmNlIFBhcmFtZXRlciBkaXN0cmlidXRpb24iLCB4ID0gIlZhbHVlcyIsIHkgPSAiRGVuc2l0eSIpCgpnZ3Bsb3QoUk5BY2FsaWJyYXRlX291dCwgYWVzKHggPSBWNCkpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IGFmdGVyX3N0YXQoZGVuc2l0eSkpLCBiaW53aWR0aCA9IDAuMDA1LCBmaWxsID0gImJsdWUiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArCiAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gInJlZCIsIHNpemUgPSAxKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lYW4oVjQpKSwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IDEpICsKICBnZW9tX3RleHQoYWVzKHggPSBtZWFuKFY0KSArIDAuMDE3LCB5ID0gMzcsIGxhYmVsID0gcGFzdGUoIk1lYW4gPSIsIHJvdW5kKG1lYW4oVjQpLCAyKSkpLCAKICAgICAgICAgICAgY29sb3IgPSAicmVkIiwgdmp1c3QgPSAtMC41LCBoanVzdCA9IDEuMikgKwogIGxhYnModGl0bGUgPSAiU2hhcGUgUGFyYW1ldGVyIGRpc3RyaWJ1dGlvbiIsIHggPSAiVmFsdWVzIiwgeSA9ICJEZW5zaXR5IikKYGBgCgoKYGBge3IsIGVuZ2luZT0nYmFzaCcsIGV2YWw9RkFMU0V9CgojIEFsc28gdHJ5IHdpdGggdGhlIGZ1bGwgbVJOQSBzZXF1ZW5jZXMKUk5BY2FsaWJyYXRlIFwKLXQgLi4vZGF0YS8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL0FwdWxjcmEtZ2Vub21lLW1STkFfb25seV9NQVgxMDAwLmZhIFwKLXEgLi4vZGF0YS8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL21pUk5BX21hdHVyZS1BcHVsLmZhc3RhIFwKPiAuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsLVJOQWNhbGlicmF0ZS1tUk5BLnR4dApgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQoKIyBOb3cgd2UgbmVlZCB0byBwaWNrIGEgZGlzdGFuY2UgcGFyYW1ldGVyIGFuZCBzaGFwZSBwYXJhbWV0ZXIKUk5BY2FsaWJyYXRlX291dCA8LSByZWFkLnRhYmxlKCIuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsLVJOQWNhbGlicmF0ZS1tUk5BLnR4dCIsIHNlcCA9ICIgIikKCmdncGxvdChSTkFjYWxpYnJhdGVfb3V0LCBhZXMoeCA9IFYzKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5ID0gYWZ0ZXJfc3RhdChkZW5zaXR5KSksIGJpbndpZHRoID0gMC4wNSwgZmlsbCA9ICJibHVlIiwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNykgKwogIGdlb21fZGVuc2l0eShjb2xvciA9ICJyZWQiLCBzaXplID0gMSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtZWFuKFYzKSksIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gbWVhbihWMykgKyAwLjE1LCB5ID0gNCwgbGFiZWwgPSBwYXN0ZSgiTWVhbiA9Iiwgcm91bmQobWVhbihWMyksIDIpKSksIAogICAgICAgICAgICBjb2xvciA9ICJyZWQiLCB2anVzdCA9IC0wLjUsIGhqdXN0ID0gMS4yKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0YW5jZSBQYXJhbWV0ZXIgZGlzdHJpYnV0aW9uIiwgeCA9ICJWYWx1ZXMiLCB5ID0gIkRlbnNpdHkiKQoKZ2dwbG90KFJOQWNhbGlicmF0ZV9vdXQsIGFlcyh4ID0gVjQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwgYmlud2lkdGggPSAwLjAwNSwgZmlsbCA9ICJibHVlIiwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNykgKwogIGdlb21fZGVuc2l0eShjb2xvciA9ICJyZWQiLCBzaXplID0gMSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtZWFuKFY0KSksIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gbWVhbihWNCkgKyAwLjAxNywgeSA9IDM3LCBsYWJlbCA9IHBhc3RlKCJNZWFuID0iLCByb3VuZChtZWFuKFY0KSwgMikpKSwgCiAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIHZqdXN0ID0gLTAuNSwgaGp1c3QgPSAxLjIpICsKICBsYWJzKHRpdGxlID0gIlNoYXBlIFBhcmFtZXRlciBkaXN0cmlidXRpb24iLCB4ID0gIlZhbHVlcyIsIHkgPSAiRGVuc2l0eSIpCmBgYAoKRGlzdHJpYnV0aW9ucyBsb29rcyByb3VnaGx5IG5vcm1hbCwgc28gSSdsbCB1c2UgdGhlIG1lYW4gZGlzdGFuY2UgYW5kIHNoYXBlIHBhcmFtZXRlcnMgY2FsY3VsYXRlZCBieSBSTkFjYWxpYnJhdGUgYXMgaW5wdXQgaW4gUk5BaHlicmlkLgoKIyBSTkFoeWJyaWQ6IG1STkEgZmlsZQoKSSdtIGhhdmluZyBwcm9ibGVtcyB1c2luZyB0aGUgUk5BY2FsaWJyYXRlIGVzdGltYXRlZCBwYXJhbWV0ZXJzLCB3aGVyZSBldmVyeSBvdXRwdXQgaHlicmlkaXphdGlvbiBoYXMgYSBwLXZhbHVlIG9mIDAuIFRoaXMgc3RpbGwgaGFwcGVucyBpZiBJIHJlbW92ZSB0aGUgYC1lYCBlbmVyZ3kgY3V0b2ZmIGFuZCB0aGUgYC1wYCBwdmFsdWUgY3V0b2ZmLCBzbyB0aGUgYC1kYCBwYXJhbWV0ZXIgc3BlY2lmaWNhdGlvbiBtdXN0IGJlIGNhdXNpbmcgaXQuCgpJJ2xsIHVzZSBhIGJ1aWx0LWluIGVzdGltYXRpb24gZm9yIG5vdywgc2luY2UgdGhvc2UgcmVzdWx0IGluIHJlYXNvbmFibGUgcHZhbHVlcy4gT3B0aW9ucyBhcmUgM3V0cl9odW1hbiwgM3V0cl9mbHksIGFuZCAzdXRyLXdvcm0uIE5vdCBzdXJlIGlmIGZseSBvciB3b3JtIGlzIG1vc3QgY2xvc2VseSByZWxhdGVkIHRvIGNvcmFscyAodGhleSdyZSBib3RoIHF1aXRlIGRpc3RhbnQpLCBidXQgSSdsbCBqdXN0IGFyYml0cmFyaWx5IHBpY2sgd29ybSBmb3Igbm93LgoKYGBge3IsIGVuZ2luZT0nYmFzaCcsIGV2YWw9RkFMU0V9CgpSTkFoeWJyaWQgXAotcyAzdXRyX3dvcm0gXAotZSAtMjAgXAotcCAwLjA1IFwKLWMgXAotdCAuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsY3JhLWdlbm9tZS1tUk5BX29ubHlfTUFYMTAwMC5mYSBcCi1xIC4uL2RhdGEvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9taVJOQV9tYXR1cmUtQXB1bC5mYXN0YSBcCj4gLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bC1STkFoeWJyaWQtbVJOQS1jb21wYWN0XzN1dHJ3b3JtLnR4dAoKYGBgCgojIFJOQWh5YnJpZDogMydVVFIKCmBgYHtyLCBlbmdpbmU9J2Jhc2gnLCBldmFsPUZBTFNFfQoKUk5BaHlicmlkIFwKLXMgM3V0cl93b3JtIFwKLWUgLTIwIFwKLXAgMC4wNSBcCi1jIFwKLXQgLi4vb3V0cHV0LzA1LUFwdWwtYW5ub3RhdGUtVVRScy9BcHVsXzNVVFJfMWtiLmZhc3RhIFwKLXEgLi4vZGF0YS8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL21pUk5BX21hdHVyZS1BcHVsLmZhc3RhIFwKPiAuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsLVJOQWh5YnJpZC0zVVRSLWNvbXBhY3RfM3V0cndvcm0udHh0CgpgYGAKCgojIFJOQWh5YnJpZDogNSdVVFIKCmBgYHtyLCBlbmdpbmU9J2Jhc2gnLCBldmFsPUZBTFNFfQoKUk5BaHlicmlkIFwKLXMgM3V0cl93b3JtIFwKLWUgLTIwIFwKLXAgMC4wNSBcCi1jIFwKLXQgLi4vb3V0cHV0LzA1LUFwdWwtYW5ub3RhdGUtVVRScy9BcHVsXzVVVFJfMWtiLmZhc3RhIFwKLXEgLi4vZGF0YS8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL21pUk5BX21hdHVyZS1BcHVsLmZhc3RhIFwKPiAuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsLVJOQWh5YnJpZC01VVRSLWNvbXBhY3RfM3V0cndvcm0udHh0CgpgYGAKCgojIFN1bW1hcml6ZSByZXN1bHRzCgpgYGB7ciwgZW5naW5lPSdiYXNoJ30KIyBIb3cgbWFueSBzaWduaWZpY2FudCBoeWJyaWRpemF0aW9ucyBwcmVkaWN0ZWQgZm9yIGVhY2ggaW5wdXQ/CndjIC1sIC4uL291dHB1dC8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL0FwdWwtUk5BaHlicmlkLW1STkEtY29tcGFjdF8zdXRyd29ybS50eHQKd2MgLWwgLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bC1STkFoeWJyaWQtNVVUUi1jb21wYWN0XzN1dHJ3b3JtLnR4dAp3YyAtbCAuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsLVJOQWh5YnJpZC0zVVRSLWNvbXBhY3RfM3V0cndvcm0udHh0CmBgYAoKYGBge3IsIGVuZ2luZT0nYmFzaCd9CmhlYWQgLTUgLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bC1STkFoeWJyaWQtM1VUUi1jb21wYWN0XzN1dHJ3b3JtLnR4dAoKYGBgCgpOb3cgbGV0J3MgcmVhZCBvdXIgUk5BaHlicmlkIHJlc3VsdHMgaW50byBSIGZvciB2aXN1YWxpemF0aW9uLiBOb3RlIHRoaXMgaXMgZ29pbmcgdG8gYmUgc2xpZ2h0bHkgbW9yZSBjb21wbGljYXRlZCB0aGFuIGl0IHNvdW5kcyBiZWNhdXNlIHRoZSBSTkFoeWJyaWQgY29tcGFjdCBvdXRwdXQgaXMgY29sb24tZGVsaW1pdGVkIGFuZCBvdXIgdGFyZ2V0LSBhbmQgcXVlcnktSURzIGNvbnRhaW4gaW50ZW50aW9uYWwgY29sb25zIHRoYW4gY291bGQgZ2V0IGNvbmZ1c2VkIHdpdGggY29sdW1uIGRlbGltaXRlcnMuCgptUk5BIG91dHB1dDoKYGBge3J9Cm9wdGlvbnMoc2NpcGVuPTk5OSkKb3B0aW9ucyhkaWdpdHMgPSAxMCkKUk5BaHlicmlkX21STkEgPC0gcmVhZC50YWJsZSgiLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bC1STkFoeWJyaWQtbVJOQS1jb21wYWN0XzN1dHJ3b3JtLnR4dCIsIHNlcD0iOiIpCgojIFJlY29tYmluZSBDb2x1bW5zIDEgYW5kIDIgKGZpeCBpbmNvcnJlY3Qgc2VwYXJhdGlvbiBvZiB0YXJnZXQgSUQgY29tcG9uZW50cykKUk5BaHlicmlkX21STkEkVjEgPC0gcGFzdGUoUk5BaHlicmlkX21STkEkVjEsIFJOQWh5YnJpZF9tUk5BJFYyLCBzZXAgPSAiOiIpClJOQWh5YnJpZF9tUk5BJFYyIDwtIE5VTEwKCiMgRG8gdGhlIHNhbWUgZm9yIENvbHVtbnMgNC03IChxdWVyeSBJRCBjb21wb25lbnRzKQpSTkFoeWJyaWRfbVJOQSRWNCA8LSBwYXN0ZShSTkFoeWJyaWRfbVJOQSRWNCwgUk5BaHlicmlkX21STkEkVjUsIFJOQWh5YnJpZF9tUk5BJFY2LCBSTkFoeWJyaWRfbVJOQSRWNyAsIHNlcCA9ICI6IikKUk5BaHlicmlkX21STkEkVjQgPC0gZ3N1YigiOk5BOiIsICI6OiIsIFJOQWh5YnJpZF9tUk5BJFY0KQpSTkFoeWJyaWRfbVJOQSRWNSA8LSBOVUxMClJOQWh5YnJpZF9tUk5BJFY2IDwtIE5VTEwKUk5BaHlicmlkX21STkEkVjcgPC0gTlVMTAoKIyBSZW5hbWUgYWxsIGNvbHVtbnMgZm9yIHJlYWRhYmlsaXR5L2FjY2Vzc2liaWxpdHkgCmNvbG5hbWVzKFJOQWh5YnJpZF9tUk5BKSA8LSBjKCJ0YXJnZXRfbmFtZSIsICJ0YXJnZXRfbGVuZ3RoIiwgInF1ZXJ5X25hbWUiLCAicXVlcnlfbGVuZ3RoIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1mZSIsICJwdmFsIiwgInBvc2l0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5vbmNvbXBfdGFyZ2V0X3NlcSIsICJjb21wX3RhcmdldF9zZXEiLCAiY29tcF9xdWVyeV9zZXEiLCAibm9uY29tcF9xdWVyeV9zZXEiKQpgYGAKCjUnVVRSIG91dHB1dDoKYGBge3J9ClJOQWh5YnJpZF81VVRSIDwtIHJlYWQudGFibGUoIi4uL291dHB1dC8wNi1BcHVsLW1pUk5BLW1STkEtUk5BaHlicmlkL0FwdWwtUk5BaHlicmlkLTVVVFItY29tcGFjdF8zdXRyd29ybS50eHQiLCBzZXA9IjoiKQoKIyBSZWNvbWJpbmUgQ29sdW1ucyAxIGFuZCAyIChmaXggaW5jb3JyZWN0IHNlcGFyYXRpb24gb2YgdGFyZ2V0IElEIGNvbXBvbmVudHMpClJOQWh5YnJpZF81VVRSJFYxIDwtIHBhc3RlKFJOQWh5YnJpZF81VVRSJFYxLCBSTkFoeWJyaWRfNVVUUiRWMiwgc2VwID0gIjoiKQpSTkFoeWJyaWRfNVVUUiRWMiA8LSBOVUxMCgojIERvIHRoZSBzYW1lIGZvciBDb2x1bW5zIDQtNyAocXVlcnkgSUQgY29tcG9uZW50cykKUk5BaHlicmlkXzVVVFIkVjQgPC0gcGFzdGUoUk5BaHlicmlkXzVVVFIkVjQsIFJOQWh5YnJpZF81VVRSJFY1LCBSTkFoeWJyaWRfNVVUUiRWNiwgUk5BaHlicmlkXzVVVFIkVjcgLCBzZXAgPSAiOiIpClJOQWh5YnJpZF81VVRSJFY0IDwtIGdzdWIoIjpOQToiLCAiOjoiLCBSTkFoeWJyaWRfNVVUUiRWNCkKUk5BaHlicmlkXzVVVFIkVjUgPC0gTlVMTApSTkFoeWJyaWRfNVVUUiRWNiA8LSBOVUxMClJOQWh5YnJpZF81VVRSJFY3IDwtIE5VTEwKCiMgUmVuYW1lIGFsbCBjb2x1bW5zIGZvciByZWFkYWJpbGl0eS9hY2Nlc3NpYmlsaXR5IApjb2xuYW1lcyhSTkFoeWJyaWRfNVVUUikgPC0gYygidGFyZ2V0X25hbWUiLCAidGFyZ2V0X2xlbmd0aCIsICJxdWVyeV9uYW1lIiwgInF1ZXJ5X2xlbmd0aCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtZmUiLCAicHZhbCIsICJwb3NpdGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJub25jb21wX3RhcmdldF9zZXEiLCAiY29tcF90YXJnZXRfc2VxIiwgImNvbXBfcXVlcnlfc2VxIiwgIm5vbmNvbXBfcXVlcnlfc2VxIikKYGBgCgozJ1VUUiBvdXRwdXQ6CmBgYHtyfQpSTkFoeWJyaWRfM1VUUiA8LSByZWFkLnRhYmxlKCIuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsLVJOQWh5YnJpZC0zVVRSLWNvbXBhY3RfM3V0cndvcm0udHh0Iiwgc2VwPSI6IikKCiMgUmVjb21iaW5lIENvbHVtbnMgMSBhbmQgMiAoZml4IGluY29ycmVjdCBzZXBhcmF0aW9uIG9mIHRhcmdldCBJRCBjb21wb25lbnRzKQpSTkFoeWJyaWRfM1VUUiRWMSA8LSBwYXN0ZShSTkFoeWJyaWRfM1VUUiRWMSwgUk5BaHlicmlkXzNVVFIkVjIsIHNlcCA9ICI6IikKUk5BaHlicmlkXzNVVFIkVjIgPC0gTlVMTAoKIyBEbyB0aGUgc2FtZSBmb3IgQ29sdW1ucyA0LTcgKHF1ZXJ5IElEIGNvbXBvbmVudHMpClJOQWh5YnJpZF8zVVRSJFY0IDwtIHBhc3RlKFJOQWh5YnJpZF8zVVRSJFY0LCBSTkFoeWJyaWRfM1VUUiRWNSwgUk5BaHlicmlkXzNVVFIkVjYsIFJOQWh5YnJpZF8zVVRSJFY3ICwgc2VwID0gIjoiKQpSTkFoeWJyaWRfM1VUUiRWNCA8LSBnc3ViKCI6TkE6IiwgIjo6IiwgUk5BaHlicmlkXzNVVFIkVjQpClJOQWh5YnJpZF8zVVRSJFY1IDwtIE5VTEwKUk5BaHlicmlkXzNVVFIkVjYgPC0gTlVMTApSTkFoeWJyaWRfM1VUUiRWNyA8LSBOVUxMCgojIFJlbmFtZSBhbGwgY29sdW1ucyBmb3IgcmVhZGFiaWxpdHkvYWNjZXNzaWJpbGl0eSAKY29sbmFtZXMoUk5BaHlicmlkXzNVVFIpIDwtIGMoInRhcmdldF9uYW1lIiwgInRhcmdldF9sZW5ndGgiLCAicXVlcnlfbmFtZSIsICJxdWVyeV9sZW5ndGgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWZlIiwgInB2YWwiLCAicG9zaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibm9uY29tcF90YXJnZXRfc2VxIiwgImNvbXBfdGFyZ2V0X3NlcSIsICJjb21wX3F1ZXJ5X3NlcSIsICJub25jb21wX3F1ZXJ5X3NlcSIpCmBgYAoKCgpgYGB7cn0KUk5BaHlicmlkX21STkEkRGF0YXNldCA8LSAiRGF0YXNldCAxIgpSTkFoeWJyaWRfNVVUUiREYXRhc2V0IDwtICJEYXRhc2V0IDIiClJOQWh5YnJpZF8zVVRSJERhdGFzZXQgPC0gIkRhdGFzZXQgMyIKCiMgQ29tYmluZSB0aGUgZGF0YXNldHMgaW50byBhIHNpbmdsZSBkYXRhIGZyYW1lCmNvbWJpbmVkX2RhdGEgPC0gcmJpbmQoUk5BaHlicmlkX21STkEsIFJOQWh5YnJpZF81VVRSLCBSTkFoeWJyaWRfM1VUUikKCiMgQ3JlYXRlIHRoZSBmYWNldGVkIGhpc3RvZ3JhbQpnZ3Bsb3QoY29tYmluZWRfZGF0YSwgYWVzKHggPSBwdmFsKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMC4wMDUsIGNvbG9yID0gImJsYWNrIiwgZmlsbCA9ICJza3libHVlIikgKwogIGZhY2V0X3dyYXAofkRhdGFzZXQpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtIG9mIENvbHVtbiBDIiwgeCA9ICJDIiwgeSA9ICJGcmVxdWVuY3kiKQoKCmBgYAoKCkknZCBhbHNvIGxpa2UgdG8gZ2V0IHRoZSBSTkFoeWJyaWQgcmVzdWx0cyBpbiBhIGdmZiBmb3JtIGZvciBJR1YgdmlzdWFsaXphdGlvbgoKU2F2ZSBvdXRwdXRzIGFzIHRhYi1kZWxpbWl0ZWQgZmlsZXMKYGBge3IsIGV2YWw9RkFMU0V9CndyaXRlLnRhYmxlKFJOQWh5YnJpZF9tUk5BLCBmaWxlPSIuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsLVJOQWh5YnJpZC1tUk5BLWNvbXBhY3RfM3V0cl93b3JtLWZvcm1hdHRlZC50eHQiLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcz1UUlVFLCBxdW90ZSA9IEZBTFNFKQp3cml0ZS50YWJsZShSTkFoeWJyaWRfNVVUUiwgZmlsZT0iLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bC1STkFoeWJyaWQtNVVUUi1jb21wYWN0XzN1dHJfd29ybS1mb3JtYXR0ZWQudHh0Iiwgc2VwPSJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQp3cml0ZS50YWJsZShSTkFoeWJyaWRfM1VUUiwgZmlsZT0iLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bC1STkFoeWJyaWQtM1VUUi1jb21wYWN0XzN1dHJfd29ybS1mb3JtYXR0ZWQudHh0Iiwgc2VwPSJcdCIsIHJvdy5uYW1lcyA9IEZBTFNFLCBxdW90ZSA9IEZBTFNFKQpgYGAKCk5vdyBjb252ZXJ0IHRoZXNlIGZvcm1hdHRlZCBSTkFoeWJyaWQgb3V0cHV0IGludG8gYSBnZmYtZm9ybWF0dGVkIGZpbGUKCm1STkE6CmBgYHtyLCBlbmdpbmU9J2Jhc2gnLCBldmFsPUZBTFNFfQojIS9iaW4vYmFzaAoKIyBJbnB1dCBhbmQgb3V0cHV0IGZpbGUgcGF0aHMKSU5QVVRfRklMRT0iLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bC1STkFoeWJyaWQtbVJOQS1jb21wYWN0XzN1dHJfd29ybS1mb3JtYXR0ZWQudHh0IiAgIyBSZXBsYWNlIHdpdGggdGhlIHBhdGggdG8geW91ciBpbnB1dCBmaWxlCk9VVFBVVF9GSUxFPSIuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsLVJOQWh5YnJpZC1tUk5BLWNvbXBhY3RfM3V0cl93b3JtLmdmZiIKCiMgV3JpdGUgR0ZGMyBoZWFkZXIgdG8gdGhlIG91dHB1dCBmaWxlCmVjaG8gIiMjZ2ZmLXZlcnNpb24gMyIgPiAiJE9VVFBVVF9GSUxFIgoKIyBQcm9jZXNzIHRoZSBpbnB1dCBmaWxlLCBza2lwcGluZyB0aGUgaGVhZGVyIGxpbmUKdGFpbCAtbiArMiAiJElOUFVUX0ZJTEUiIHwgd2hpbGUgSUZTPSQnXHQnIHJlYWQgLXIgdGFyZ2V0X25hbWUgdGFyZ2V0X2xlbmd0aCBxdWVyeV9uYW1lIHF1ZXJ5X2xlbmd0aCBtZmUgcHZhbCBwb3NpdGlvbiBub25jb21wX3RhcmdldF9zZXEgY29tcF90YXJnZXRfc2VxIGNvbXBfcXVlcnlfc2VxIG5vbmNvbXBfcXVlcnlfc2VxCmRvCiAgIyBFeHRyYWN0IGxvY3VzIG5hbWUgYW5kIGNvb3JkaW5hdGVzIGZyb20gdGFyZ2V0X25hbWUKICBsb2N1cz0kKGVjaG8gIiR0YXJnZXRfbmFtZSIgfCBjdXQgLWQnOicgLWYxKQogIHN0YXJ0X2Nvb3JkPSQoZWNobyAiJHRhcmdldF9uYW1lIiB8IGN1dCAtZCc6JyAtZjIgfCBjdXQgLWQnLScgLWYxKQogIHN0YXJ0X2dmZj0kKChzdGFydF9jb29yZCArIHBvc2l0aW9uKSkKICBlbmRfZ2ZmPSQoKHN0YXJ0X2dmZiArIHF1ZXJ5X2xlbmd0aCkpCgogICMgRXh0cmFjdCBzdHJhbmRlZG5lc3MgZnJvbSBxdWVyeV9uYW1lCiAgc3RyYW5kPSQoZWNobyAiJHF1ZXJ5X25hbWUiIHwgZ3JlcCAtbyAnKC1cfCspJyB8IHRyIC1kICcoKScpCgogICMgV3JpdGUgdGhlIEdGRjMgbGluZQogIGVjaG8gLWUgIiRsb2N1c1x0Uk5BaHlicmlkXHRtaVJOQV9iaW5kaW5nXHQkc3RhcnRfZ2ZmXHQkZW5kX2dmZlx0Llx0JHN0cmFuZFx0Llx0SUQ9JHF1ZXJ5X25hbWU7TUZFPSRtZmU7UHZhbD0kcHZhbCIgPj4gIiRPVVRQVVRfRklMRSIKZG9uZQoKYGBgCgoKNSdVVFI6CmBgYHtyLCBlbmdpbmU9J2Jhc2gnLCBldmFsPUZBTFNFfQojIS9iaW4vYmFzaAoKIyBJbnB1dCBhbmQgb3V0cHV0IGZpbGUgcGF0aHMKSU5QVVRfRklMRT0iLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bC1STkFoeWJyaWQtNVVUUi1jb21wYWN0XzN1dHJfd29ybS1mb3JtYXR0ZWQudHh0IiAgIyBSZXBsYWNlIHdpdGggdGhlIHBhdGggdG8geW91ciBpbnB1dCBmaWxlCk9VVFBVVF9GSUxFPSIuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsLVJOQWh5YnJpZC01VVRSLWNvbXBhY3RfM3V0cl93b3JtLmdmZiIKCiMgV3JpdGUgR0ZGMyBoZWFkZXIgdG8gdGhlIG91dHB1dCBmaWxlCmVjaG8gIiMjZ2ZmLXZlcnNpb24gMyIgPiAiJE9VVFBVVF9GSUxFIgoKIyBQcm9jZXNzIHRoZSBpbnB1dCBmaWxlLCBza2lwcGluZyB0aGUgaGVhZGVyIGxpbmUKdGFpbCAtbiArMiAiJElOUFVUX0ZJTEUiIHwgd2hpbGUgSUZTPSQnXHQnIHJlYWQgLXIgdGFyZ2V0X25hbWUgdGFyZ2V0X2xlbmd0aCBxdWVyeV9uYW1lIHF1ZXJ5X2xlbmd0aCBtZmUgcHZhbCBwb3NpdGlvbiBub25jb21wX3RhcmdldF9zZXEgY29tcF90YXJnZXRfc2VxIGNvbXBfcXVlcnlfc2VxIG5vbmNvbXBfcXVlcnlfc2VxCmRvCiAgIyBFeHRyYWN0IGxvY3VzIG5hbWUgYW5kIGNvb3JkaW5hdGVzIGZyb20gdGFyZ2V0X25hbWUKICBsb2N1cz0kKGVjaG8gIiR0YXJnZXRfbmFtZSIgfCBjdXQgLWQnOicgLWYxKQogIHN0YXJ0X2Nvb3JkPSQoZWNobyAiJHRhcmdldF9uYW1lIiB8IGN1dCAtZCc6JyAtZjIgfCBjdXQgLWQnLScgLWYxKQogIHN0YXJ0X2dmZj0kKChzdGFydF9jb29yZCArIHBvc2l0aW9uKSkKICBlbmRfZ2ZmPSQoKHN0YXJ0X2dmZiArIHF1ZXJ5X2xlbmd0aCkpCgogICMgRXh0cmFjdCBzdHJhbmRlZG5lc3MgZnJvbSBxdWVyeV9uYW1lCiAgc3RyYW5kPSQoZWNobyAiJHF1ZXJ5X25hbWUiIHwgZ3JlcCAtbyAnKC1cfCspJyB8IHRyIC1kICcoKScpCgogICMgV3JpdGUgdGhlIEdGRjMgbGluZQogIGVjaG8gLWUgIiRsb2N1c1x0Uk5BaHlicmlkXHRtaVJOQV9iaW5kaW5nXHQkc3RhcnRfZ2ZmXHQkZW5kX2dmZlx0Llx0JHN0cmFuZFx0Llx0SUQ9JHF1ZXJ5X25hbWU7TUZFPSRtZmU7UHZhbD0kcHZhbCIgPj4gIiRPVVRQVVRfRklMRSIKZG9uZQoKYGBgCgoKMydVVFI6CmBgYHtyLCBlbmdpbmU9J2Jhc2gnLCBldmFsPUZBTFNFfQojIS9iaW4vYmFzaAoKIyBJbnB1dCBhbmQgb3V0cHV0IGZpbGUgcGF0aHMKSU5QVVRfRklMRT0iLi4vb3V0cHV0LzA2LUFwdWwtbWlSTkEtbVJOQS1STkFoeWJyaWQvQXB1bC1STkFoeWJyaWQtM1VUUi1jb21wYWN0XzN1dHJfd29ybS1mb3JtYXR0ZWQudHh0IiAgIyBSZXBsYWNlIHdpdGggdGhlIHBhdGggdG8geW91ciBpbnB1dCBmaWxlCk9VVFBVVF9GSUxFPSIuLi9vdXRwdXQvMDYtQXB1bC1taVJOQS1tUk5BLVJOQWh5YnJpZC9BcHVsLVJOQWh5YnJpZC0zVVRSLWNvbXBhY3RfM3V0cl93b3JtLmdmZiIKCiMgV3JpdGUgR0ZGMyBoZWFkZXIgdG8gdGhlIG91dHB1dCBmaWxlCmVjaG8gIiMjZ2ZmLXZlcnNpb24gMyIgPiAiJE9VVFBVVF9GSUxFIgoKIyBQcm9jZXNzIHRoZSBpbnB1dCBmaWxlLCBza2lwcGluZyB0aGUgaGVhZGVyIGxpbmUKdGFpbCAtbiArMiAiJElOUFVUX0ZJTEUiIHwgd2hpbGUgSUZTPSQnXHQnIHJlYWQgLXIgdGFyZ2V0X25hbWUgdGFyZ2V0X2xlbmd0aCBxdWVyeV9uYW1lIHF1ZXJ5X2xlbmd0aCBtZmUgcHZhbCBwb3NpdGlvbiBub25jb21wX3RhcmdldF9zZXEgY29tcF90YXJnZXRfc2VxIGNvbXBfcXVlcnlfc2VxIG5vbmNvbXBfcXVlcnlfc2VxCmRvCiAgIyBFeHRyYWN0IGxvY3VzIG5hbWUgYW5kIGNvb3JkaW5hdGVzIGZyb20gdGFyZ2V0X25hbWUKICBsb2N1cz0kKGVjaG8gIiR0YXJnZXRfbmFtZSIgfCBjdXQgLWQnOicgLWYxKQogIHN0YXJ0X2Nvb3JkPSQoZWNobyAiJHRhcmdldF9uYW1lIiB8IGN1dCAtZCc6JyAtZjIgfCBjdXQgLWQnLScgLWYxKQogIHN0YXJ0X2dmZj0kKChzdGFydF9jb29yZCArIHBvc2l0aW9uKSkKICBlbmRfZ2ZmPSQoKHN0YXJ0X2dmZiArIHF1ZXJ5X2xlbmd0aCkpCgogICMgRXh0cmFjdCBzdHJhbmRlZG5lc3MgZnJvbSBxdWVyeV9uYW1lCiAgc3RyYW5kPSQoZWNobyAiJHF1ZXJ5X25hbWUiIHwgZ3JlcCAtbyAnKC1cfCspJyB8IHRyIC1kICcoKScpCgogICMgV3JpdGUgdGhlIEdGRjMgbGluZQogIGVjaG8gLWUgIiRsb2N1c1x0Uk5BaHlicmlkXHRtaVJOQV9iaW5kaW5nXHQkc3RhcnRfZ2ZmXHQkZW5kX2dmZlx0Llx0JHN0cmFuZFx0Llx0SUQ9JHF1ZXJ5X25hbWU7TUZFPSRtZmU7UHZhbD0kcHZhbCIgPj4gIiRPVVRQVVRfRklMRSIKZG9uZQoKYGBg