library(ggplot2)
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.
# mRNA-only genome gff
# Count total sequences in genome gff
wc -l ../output/05-Apul-annotate-UTRs/Apulcra-genome-mRNA_only.gff
# Count the number of sequences that contain >1000 bp
awk '{if ($5 - $4 > 1000) count++} END {print count}' ../output/05-Apul-annotate-UTRs/Apulcra-genome-mRNA_only.gff
# Check how the sequence names are formatted
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"
# mRNA-only genome gff
# Count total sequences in genome gff
wc -l ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff
# Count the number of sequences that contain >1000 bp
awk '{if ($5 - $4 > 1000) count++} END {print count}' ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff
# Check how the sequence names are formatted
head -50 ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff | tail -5
echo ""
echo ""
# I'm getting an error in getfasta related to some lines of the gff having a different number of columns.
# Each line should contain 9 columns. Count number of lines with more than 9
awk -F'\t' 'NF > 9 {count++} END {print count}' ../output/06-Apul-miRNA-mRNA-RNAhybrid/Apulcra-genome-mRNA_only_MAX1000.gff
# For some lines, the final column is being interpreted as two columns
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”
# 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
# Count number of entries with >9 columns (should be nothing now)
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
# Use mRNA gff and genome fasta to extract mRNA fastas
/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.
# RNAhybrid only has built-in support for humans, worms, and flies.
# We can use RNAcalibrate to derive Extreme Value Distribution parameters for our data.
# USe 3'UTR as input, since we expect majority binding there
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
# Now we need to pick a distance parameter and shape parameter
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")
# Also try with the full mRNA sequences
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
# Now we need to pick a distance parameter and shape parameter
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
# How many significant hybridizations predicted for each input?
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=":")
# Recombine Columns 1 and 2 (fix incorrect separation of target ID components)
RNAhybrid_mRNA$V1 <- paste(RNAhybrid_mRNA$V1, RNAhybrid_mRNA$V2, sep = ":")
RNAhybrid_mRNA$V2 <- NULL
# Do the same for Columns 4-7 (query ID components)
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
# Rename all columns for readability/accessibility
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=":")
# Recombine Columns 1 and 2 (fix incorrect separation of target ID components)
RNAhybrid_5UTR$V1 <- paste(RNAhybrid_5UTR$V1, RNAhybrid_5UTR$V2, sep = ":")
RNAhybrid_5UTR$V2 <- NULL
# Do the same for Columns 4-7 (query ID components)
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
# Rename all columns for readability/accessibility
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=":")
# Recombine Columns 1 and 2 (fix incorrect separation of target ID components)
RNAhybrid_3UTR$V1 <- paste(RNAhybrid_3UTR$V1, RNAhybrid_3UTR$V2, sep = ":")
RNAhybrid_3UTR$V2 <- NULL
# Do the same for Columns 4-7 (query ID components)
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
# Rename all columns for readability/accessibility
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"
# Combine the datasets into a single data frame
combined_data <- rbind(RNAhybrid_mRNA, RNAhybrid_5UTR, RNAhybrid_3UTR)
# Create the faceted histogram
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 and output file paths
INPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-mRNA-compact_3utr_worm-formatted.txt" # Replace with the path to your input file
OUTPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-mRNA-compact_3utr_worm.gff"
# Write GFF3 header to the output file
echo "##gff-version 3" > "$OUTPUT_FILE"
# Process the input file, skipping the header line
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
# Extract locus name and coordinates from target_name
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))
# Extract strandedness from query_name
strand=$(echo "$query_name" | grep -o '(-\|+)' | tr -d '()')
# Write the GFF3 line
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 and output file paths
INPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-5UTR-compact_3utr_worm-formatted.txt" # Replace with the path to your input file
OUTPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-5UTR-compact_3utr_worm.gff"
# Write GFF3 header to the output file
echo "##gff-version 3" > "$OUTPUT_FILE"
# Process the input file, skipping the header line
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
# Extract locus name and coordinates from target_name
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))
# Extract strandedness from query_name
strand=$(echo "$query_name" | grep -o '(-\|+)' | tr -d '()')
# Write the GFF3 line
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 and output file paths
INPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-3UTR-compact_3utr_worm-formatted.txt" # Replace with the path to your input file
OUTPUT_FILE="../output/06-Apul-miRNA-mRNA-RNAhybrid/Apul-RNAhybrid-3UTR-compact_3utr_worm.gff"
# Write GFF3 header to the output file
echo "##gff-version 3" > "$OUTPUT_FILE"
# Process the input file, skipping the header line
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
# Extract locus name and coordinates from target_name
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))
# Extract strandedness from query_name
strand=$(echo "$query_name" | grep -o '(-\|+)' | tr -d '()')
# Write the GFF3 line
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