I want to find miRNAs that are conserved among either a subset of or all three species of interest (A.pulchra, P.evermanni, and P.meandrina) using Blastn. I want to generally investigate sequence similarity across and within species.

1 Prep data

1.1 Isolate mature miRNA sequences

Our ShortStack output contains sequences for the mature, star, and precursor sequences for each identified miRNA. We just want to look at the mature miRNA sequences right now, so let’s isolate those.

cd ../data/10-shortRNA-ShortStack-comparison

# Copy all sequences whose headers contain "mature"
awk '/^>/ {p = /mature/} p' ../../../D-Apul/output/13.2.1-Apul-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/mir.fasta > Apul_ShortStack_mature.fasta

awk '/^>/ {p = /mature/} p' ../../../E-Peve/output/08.2-Peve-sRNAseq-ShortStack-31bp-fastp-merged/ShortStack_out/mir.fasta > Peve_ShortStack_mature.fasta

awk '/^>/ {p = /mature/} p' ../../../F-Pmea/output/13.2.1-Pmea-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/mir.fasta > Pmea_ShortStack_mature.fasta

grep "^>" Apul_ShortStack_mature.fasta | wc -l 
grep "^>" Peve_ShortStack_mature.fasta | wc -l
grep "^>" Pmea_ShortStack_mature.fasta | wc -l
38
46
37

1.2 Check miRNA length distributions

# Set our color scheme for plotting -- options for both the abbreviated labels or the full, correct species names
species_colors <- c('A_pulchra' = '#408EC6',
                    'P_evermanni' = '#1E2761',
                    'P_tuahiniensis' = '#7A2048')

species_colors_nolabel <- c('#408EC6', '#1E2761', '#7A2048')

Apul:

# Extract sequence lengths and calculate statistics
grep -v '^>' ../data/10-shortRNA-ShortStack-comparison/Apul_ShortStack_mature.fasta | awk '{ print length($0) }' > ../data/10-shortRNA-ShortStack-comparison/Apul_ShortStack_mature_lengths.txt
# Read in the lengths
Apul_lengths <- read.table("../data/10-shortRNA-ShortStack-comparison/Apul_ShortStack_mature_lengths.txt", header = FALSE, col.names = "length")

# Make histogram of lengths
hist_Apul_lengths <- ggplot(Apul_lengths, aes(x = length)) +
  geom_histogram(binwidth = 1, fill = species_colors['A_pulchra'], color = "black") +
  geom_text(stat = 'count', aes(label = ..count..), vjust = -0.5) +
  labs(title = "A. pulchra miRNA sequence lengths",
       x = "Sequence Length [nucleotides]",
       y = "Frequency") +
  xlim(20, 25) +
  ylim(0, 41) +
  theme_minimal()

hist_Apul_lengths

ggexport(filename = "../output/10-shortRNA-ShortStack-comparison/figures/histogram_Apul_miRNA_lengths.png",
         plot   = hist_Apul_lengths,
         res    = 600,
         width  = 5000,
         height = 5000)

ggexport(filename = "../../supplemental/miRNA/histogram_Apul_miRNA_lengths.png",
         plot   = hist_Apul_lengths,
         res    = 600,
         width  = 5000,
         height = 5000)

Pmea:

# Extract sequence lengths and calculate statistics
grep -v '^>' ../data/10-shortRNA-ShortStack-comparison/Pmea_ShortStack_mature.fasta | awk '{ print length($0) }' > ../data/10-shortRNA-ShortStack-comparison/Pmea_ShortStack_mature_lengths.txt
# Read in the lengths
Pmea_lengths <- read.table("../data/10-shortRNA-ShortStack-comparison/Pmea_ShortStack_mature_lengths.txt", header = FALSE, col.names = "length")

# Make histogram of lengths
hist_Pmea_lengths <- ggplot(Pmea_lengths, aes(x = length)) +
  geom_histogram(binwidth = 1, fill = species_colors['P_tuahiniensis'], color = "black") +
  geom_text(stat = 'count', aes(label = ..count..), vjust = -0.5) +
  labs(title = "P. tuahiniensis miRNA sequence lengths",
       x = "Sequence Length [nucleotides]",
       y = "Frequency") +
  xlim(20.5, 24.5) +
  ylim(0, 41) +
  theme_minimal()

hist_Pmea_lengths

ggexport(filename = "../output/10-shortRNA-ShortStack-comparison/figures/histogram_Pmea_miRNA_lengths.png",
         plot   = hist_Pmea_lengths,
         res    = 600,
         width  = 5000,
         height = 5000)

ggexport(filename = "../../supplemental/miRNA/histogram_Pmea_miRNA_lengths.png",
         plot   = hist_Pmea_lengths,
         res    = 600,
         width  = 5000,
         height = 5000)

Peve:

# Extract sequence lengths and calculate statistics
grep -v '^>' ../data/10-shortRNA-ShortStack-comparison/Peve_ShortStack_mature.fasta | awk '{ print length($0) }' > ../data/10-shortRNA-ShortStack-comparison/Peve_ShortStack_mature_lengths.txt
# Read in the lengths
Peve_lengths <- read.table("../data/10-shortRNA-ShortStack-comparison/Peve_ShortStack_mature_lengths.txt", header = FALSE, col.names = "length")

# Make histogram of lengths
hist_Peve_lengths <- ggplot(Peve_lengths, aes(x = length)) +
  geom_histogram(binwidth = 1, 
                 fill = species_colors['P_evermanni'], 
                 color = "black") +
  geom_text(stat = 'count', aes(label = ..count..), vjust = -0.5) +
  labs(title = "P. evermanni miRNA sequence lengths",
       x = "Sequence Length [nucleotides]",
       y = "Frequency") +
  xlim(20.5, 24.5) +
  ylim(0, 41) +
  theme_minimal()

hist_Peve_lengths

ggexport(filename = "../output/10-shortRNA-ShortStack-comparison/figures/histogram_Peve_miRNA_lengths.png",
         plot   = hist_Peve_lengths,
         res    = 600,
         width  = 5000,
         height = 5000)

ggexport(filename = "../../supplemental/miRNA/histogram_Peve_miRNA_lengths.png",
         plot   = hist_Peve_lengths,
         res    = 600,
         width  = 5000,
         height = 5000)

Let’s also make a plot showing the length distributions of all three species

# Add a new column to each data frame to label the source file
Apul_lengths <- Apul_lengths %>% mutate(Species = 'A_pulchra')
Peve_lengths <- Peve_lengths %>% mutate(Species = 'P_evermanni')
Pmea_lengths <- Pmea_lengths %>% mutate(Species = 'P_tuahiniensis')

# Combine the data frames into one
all_lengths <- rbind(Apul_lengths, Peve_lengths, Pmea_lengths)
hist_all_lengths <- ggplot(all_lengths, aes(x = length, fill = Species)) +
  geom_histogram(binwidth = 1, 
                 position = position_dodge(width = 0.91), 
                 color = "black", 
                 width = 0.9) +
  geom_text(stat = 'count', 
            aes(label = ..count..), 
            vjust = -0.5, 
            position = position_dodge(width = 1)) +
  scale_fill_manual(values = species_colors) +
  labs(title = "Sequence lengths by species",
       x = "Sequence Length [nucleotides]",
       y = "Frequency",
       fill = "Species") +
  xlim(20.5, 24.5) +
  ylim(0, 41) +
  theme_minimal()

hist_all_lengths

ggexport(filename = "../output/10-shortRNA-ShortStack-comparison/figures/histogram_all_miRNA_lengths.png",
         plot   = hist_all_lengths,
         res    = 600,
         width  = 5000,
         height = 5000)

ggexport(filename = "../../supplemental/miRNA/histogram_all_miRNA_lengths.png",
         plot   = hist_all_lengths,
         res    = 600,
         width  = 5000,
         height = 5000)
# Summarize min, max, and average lengths for each species
length_summary <- all_lengths %>%
  group_by(Species) %>%
  summarise(
    Min_Length = min(length, na.rm = TRUE),
    Max_Length = max(length, na.rm = TRUE),
    Avg_Length = mean(length, na.rm = TRUE)
  )

print(length_summary)
# A tibble: 3 × 4
  Species        Min_Length Max_Length Avg_Length
  <chr>               <int>      <int>      <dbl>
1 A_pulchra              21         24       22.2
2 P_evermanni            21         23       21.9
3 P_tuahiniensis         21         23       21.9
rm -r ../data/10-shortRNA-ShortStack-comparison/*lengths.txt

1.3 Merge the three mature miRNA FASTAs

cd ../data/10-shortRNA-ShortStack-comparison

cat Apul_ShortStack_mature.fasta Peve_ShortStack_mature.fasta Pmea_ShortStack_mature.fasta > merged_all_ShortStack_mature.fasta

head merged_all_ShortStack_mature.fasta
tail merged_all_ShortStack_mature.fasta
>Cluster_316.mature::NC_058066.1:12757146-12757168(-)
TGATCTCTGCAATAGCCTGCCT
>Cluster_514.mature::NC_058066.1:20088678-20088700(+)
ACGCTAGGAAGGGATGCCGGGA
>Cluster_548.mature::NC_058066.1:20346248-20346271(-)
TTAACGAGTAGATAAATGAAGAG
>Cluster_1506.mature::NC_058067.1:5656213-5656236(-)
TTTGCTAGTTGCTTTTGTCCCGT
>Cluster_1900.mature::NC_058067.1:16118269-16118291(-)
aaaaatgtcggttgcttaagct
>Cluster_4846.mature::Pocillopora_meandrina_HIv1___Sc0000018:6855520-6855542(+)
TCACCCAACAGTTTTAATCTGA
>Cluster_5275.mature::Pocillopora_meandrina_HIv1___Sc0000021:4351838-4351860(+)
ACTGATATTCACCAAGTGATTA
>Cluster_5642.mature::Pocillopora_meandrina_HIv1___Sc0000024:4808687-4808708(+)
AGAACCCAAGAATCTCGAAGG
>Cluster_5770.mature::Pocillopora_meandrina_HIv1___Sc0000026:1154771-1154793(-)
TGTACTATGTTCATGATCTTGC
>Cluster_6429.mature::Pocillopora_meandrina_HIv1___Sc0000035:1989841-1989863(+)
TATTTACAACTCTCAAAACAAC

Let’s do a quick investigation of our merged mature miRNAs.

# Extract sequence lengths and calculate statistics
lengths=$(awk '/^>/ {if (seqlen) print seqlen; seqlen=0; next} {seqlen += length($0)} END {print seqlen}' ../data/10-shortRNA-ShortStack-comparison/merged_all_ShortStack_mature.fasta)
min_length=$(echo "$lengths" | sort -n | head -n 1)
max_length=$(echo "$lengths" | sort -n | tail -n 1)
total_length=$(echo "$lengths" | awk '{sum += $1} END {print sum}')
num_sequences=$(grep -c '^>' ../data/10-shortRNA-ShortStack-comparison/merged_all_ShortStack_mature.fasta)
average_length=$(echo "scale=2; $total_length / $num_sequences" | bc)

# Output results
echo "Minimum sequence length: $min_length"
echo "Maximum sequence length: $max_length"
echo "Average sequence length: $average_length"
Minimum sequence length: 21
Maximum sequence length: 24
Average sequence length: 21.99

2 BLASTs

2.1 Make database for each species:

Apul

/home/shared/ncbi-blast-2.11.0+/bin/makeblastdb \
-in ../data/10-shortRNA-ShortStack-comparison/Apul_ShortStack_mature.fasta \
-dbtype nucl \
-out ../output/10-shortRNA-ShortStack-comparison/blasts/Apul-db/Apul_ShortStack_mature


Building a new DB, current time: 08/15/2024 13:14:38
New DB name:   /home/shared/8TB_HDD_02/shedurkin/deep-dive/DEF-cross-species/output/10-shortRNA-ShortStack-comparison/blasts/Apul-db/Apul_ShortStack_mature
New DB title:  ../data/10-shortRNA-ShortStack-comparison/Apul_ShortStack_mature.fasta
Sequence type: Nucleotide
Deleted existing Nucleotide BLAST database named /home/shared/8TB_HDD_02/shedurkin/deep-dive/DEF-cross-species/output/10-shortRNA-ShortStack-comparison/blasts/Apul-db/Apul_ShortStack_mature
Keep MBits: T
Maximum file size: 1000000000B
Adding sequences from FASTA; added 38 sequences in 0.0024929 seconds.

Peve

/home/shared/ncbi-blast-2.11.0+/bin/makeblastdb \
-in ../data/10-shortRNA-ShortStack-comparison/Peve_ShortStack_mature.fasta \
-dbtype nucl \
-out ../output/10-shortRNA-ShortStack-comparison/blasts/Peve-db/Peve_ShortStack_mature


Building a new DB, current time: 08/15/2024 13:14:39
New DB name:   /home/shared/8TB_HDD_02/shedurkin/deep-dive/DEF-cross-species/output/10-shortRNA-ShortStack-comparison/blasts/Peve-db/Peve_ShortStack_mature
New DB title:  ../data/10-shortRNA-ShortStack-comparison/Peve_ShortStack_mature.fasta
Sequence type: Nucleotide
Deleted existing Nucleotide BLAST database named /home/shared/8TB_HDD_02/shedurkin/deep-dive/DEF-cross-species/output/10-shortRNA-ShortStack-comparison/blasts/Peve-db/Peve_ShortStack_mature
Keep MBits: T
Maximum file size: 1000000000B
Adding sequences from FASTA; added 46 sequences in 0.00225902 seconds.

Pmea

/home/shared/ncbi-blast-2.11.0+/bin/makeblastdb \
-in ../data/10-shortRNA-ShortStack-comparison/Pmea_ShortStack_mature.fasta \
-dbtype nucl \
-out ../output/10-shortRNA-ShortStack-comparison/blasts/Pmea-db/Pmea_ShortStack_mature


Building a new DB, current time: 08/15/2024 13:14:40
New DB name:   /home/shared/8TB_HDD_02/shedurkin/deep-dive/DEF-cross-species/output/10-shortRNA-ShortStack-comparison/blasts/Pmea-db/Pmea_ShortStack_mature
New DB title:  ../data/10-shortRNA-ShortStack-comparison/Pmea_ShortStack_mature.fasta
Sequence type: Nucleotide
Deleted existing Nucleotide BLAST database named /home/shared/8TB_HDD_02/shedurkin/deep-dive/DEF-cross-species/output/10-shortRNA-ShortStack-comparison/blasts/Pmea-db/Pmea_ShortStack_mature
Keep MBits: T
Maximum file size: 1000000000B
Adding sequences from FASTA; added 37 sequences in 0.00248694 seconds.

2.2 Run Blastn

Generate a list of blast results that, for each miRNA, shows the top hit in each of two other species. We want to see the top hits no matter how poor the match is, so we will not filter by e-value at this stage. We’ll also include the “-word_size 4” option, which reduces the required length of the initial match.

All to Apul:

/home/shared/ncbi-blast-2.11.0+/bin/blastn \
-task blastn-short \
-query ../data/10-shortRNA-ShortStack-comparison/merged_all_ShortStack_mature.fasta \
-db ../output/10-shortRNA-ShortStack-comparison/blasts/Apul-db/Apul_ShortStack_mature \
-out ../output/10-shortRNA-ShortStack-comparison/blasts/Apul_to_all_blastn.tab \
-num_threads 40 \
-word_size 4 \
-max_target_seqs 1 \
-max_hsps 1 \
-outfmt 6

wc -l ../output/10-shortRNA-ShortStack-comparison/blasts/Apul_to_all_blastn.tab
Warning: [blastn] Examining 5 or more matches is recommended
121 ../output/10-shortRNA-ShortStack-comparison/blasts/Apul_to_all_blastn.tab

All to Peve:

/home/shared/ncbi-blast-2.11.0+/bin/blastn \
-task blastn-short \
-query ../data/10-shortRNA-ShortStack-comparison/merged_all_ShortStack_mature.fasta \
-db ../output/10-shortRNA-ShortStack-comparison/blasts/Peve-db/Peve_ShortStack_mature \
-out ../output/10-shortRNA-ShortStack-comparison/blasts/Peve_to_all_blastn.tab \
-num_threads 40 \
-word_size 4 \
-max_target_seqs 1 \
-max_hsps 1 \
-outfmt 6

wc -l ../output/10-shortRNA-ShortStack-comparison/blasts/Peve_to_all_blastn.tab
Warning: [blastn] Examining 5 or more matches is recommended
121 ../output/10-shortRNA-ShortStack-comparison/blasts/Peve_to_all_blastn.tab

All to Pmea:

/home/shared/ncbi-blast-2.11.0+/bin/blastn \
-task blastn-short \
-query ../data/10-shortRNA-ShortStack-comparison/merged_all_ShortStack_mature.fasta \
-db ../output/10-shortRNA-ShortStack-comparison/blasts/Pmea-db/Pmea_ShortStack_mature \
-out ../output/10-shortRNA-ShortStack-comparison/blasts/Pmea_to_all_blastn.tab \
-num_threads 40 \
-word_size 4 \
-max_target_seqs 1 \
-max_hsps 1 \
-outfmt 6

wc -l ../output/10-shortRNA-ShortStack-comparison/blasts/Pmea_to_all_blastn.tab
Warning: [blastn] Examining 5 or more matches is recommended
121 ../output/10-shortRNA-ShortStack-comparison/blasts/Pmea_to_all_blastn.tab

2.3 Join BLAST tables

apul_to_all_blastn <- read.table("../output/10-shortRNA-ShortStack-comparison/blasts/Apul_to_all_blastn.tab", sep="\t", header=FALSE)
peve_to_all_blastn <- read.table("../output/10-shortRNA-ShortStack-comparison/blasts/Peve_to_all_blastn.tab", sep="\t", header=FALSE)
pmea_to_all_blastn <- read.table("../output/10-shortRNA-ShortStack-comparison/blasts/Pmea_to_all_blastn.tab", sep="\t", header=FALSE)

Column labels: qseqid: Query sequence ID sseqid: Subject (database) sequence ID pident: Percentage of identical matches length: Alignment length (number of base pairs or amino acids) mismatch: Number of mismatches gapopen: Number of gap openings qstart: Start of alignment in the query qend: End of alignment in the query sstart: Start of alignment in the subject send: End of alignment in the subject evalue: Expect value (number of hits expected by chance) bitscore: Bit score

# Combine the three blast tables
combined_blastn <- rbind(apul_to_all_blastn, peve_to_all_blastn, pmea_to_all_blastn)

# Assign informative column labels
colnames(combined_blastn) <- c("qseqid", "sseqid", "pident", "length", "mismatch", "gapopen", "qstart", "qend", "sstart", "send", "evalue", "bitscore")

# Save this original, unfiltered blast table.
write.table(combined_blastn, "../output/10-shortRNA-ShortStack-comparison/combined_blast.tab", sep="\t", row.names=FALSE, quote=FALSE)

3 Identify conserved miRNAs

Filter our list of blast hits to remove instances where sequences match themselves (e.g. from querying an Apul sequence against our combined database which contained all Apul sequences), and to retain only the significant hits (We’ll set this at eval > 1E-5)

# Filter
filtered_combined_blastn <- combined_blastn %>%
  filter(qseqid != sseqid) %>%
  filter(evalue < 0.00001)

# View
nrow(filtered_combined_blastn)
[1] 34
head(filtered_combined_blastn)
                                                               qseqid
1                   Cluster_2521.mature::NC_058068.1:597877-597899(+)
2                Cluster_10726.mature::NC_058079.1:5232178-5232199(+)
3               Cluster_16040.mature::NW_025322765.1:722296-722318(+)
4  Cluster_1153.mature::Porites_evermani_scaffold_49:151639-151661(-)
5 Cluster_5540.mature::Porites_evermani_scaffold_430:205886-205909(-)
6   Cluster_6211.mature::Porites_evermani_scaffold_502:58996-59018(-)
                                                 sseqid pident length mismatch
1     Cluster_2522.mature::NC_058068.1:598173-598195(+)    100     22        0
2  Cluster_10729.mature::NC_058079.1:5261442-5261463(+)    100     21        0
3 Cluster_16041.mature::NW_025322765.1:799181-799203(-)    100     22        0
4 Cluster_6977.mature::NC_058073.1:12437102-12437124(+)    100     22        0
5 Cluster_7025.mature::NC_058073.1:15996878-15996901(-)    100     23        0
6   Cluster_7077.mature::NC_058074.1:2966522-2966545(+)    100     22        0
  gapopen qstart qend sstart send   evalue bitscore
1       0      1   22      1   22 5.19e-10     44.1
2       0      1   21      1   21 1.92e-09     42.1
3       0      1   22      1   22 5.19e-10     44.1
4       0      1   22      1   22 5.19e-10     44.1
5       0      1   23      1   23 1.40e-10     46.1
6       0      1   22      1   22 5.19e-10     44.1
write.table(filtered_combined_blastn, "../output/10-shortRNA-ShortStack-comparison/filtered_combined_blast.tab", sep="\t", row.names=FALSE, quote=FALSE)

Ok now we can start identifying conserved miRNAs. Keep in mind that this list of filtered, combined blastn hits contains duplicates because, for example, querying Apul sequences against a database containing Peve sequences is functionally the same as querying those Peve sequences against a databse which contains Apul. So, for example, this list would contain a hit matching Apul.seq1 to Peve.seq2, and a hit matching Peve.seq2 to Apul.seq1.

3.1 Conserved across all three species (Apul, Peve, and Pmea)

First, lets find miRNAs conserved among all three species. These would show up as an miRNA from one species that has hits from both other species (e.g., Apul.seq1 has a hit from Peve and a hit from Pmea).

# Find Apul miRNAs that have matches from both Peve and Pmea
present_in_all <- filtered_combined_blastn %>%
  # isolate Apul miRNAs with hits
  filter(!grepl("Porites_evermani|Pocillopora_meandrina", sseqid)) %>%
  group_by(sseqid) %>%
  filter(any(grepl("Porites_evermani", qseqid)) & any(grepl("Pocillopora_meandrina", qseqid)))

# View the miRNAs that match across all three species
# (recall this will include two entries for each conserved miRNA, it's Apul match in Peve, and its Apul match to Pmea)
head(present_in_all, nrow(present_in_all))
# A tibble: 8 × 12
# Groups:   sseqid [4]
  qseqid         sseqid pident length mismatch gapopen qstart  qend sstart  send
  <chr>          <chr>   <dbl>  <int>    <int>   <int>  <int> <int>  <int> <int>
1 Cluster_1153.… Clust…    100     22        0       0      1    22      1    22
2 Cluster_5540.… Clust…    100     23        0       0      1    23      1    23
3 Cluster_6875.… Clust…    100     21        0       0      1    21      1    21
4 Cluster_14865… Clust…    100     22        0       0      1    22      1    22
5 Cluster_1108.… Clust…    100     22        0       0      1    22      1    22
6 Cluster_1279.… Clust…    100     21        0       0      2    22      2    22
7 Cluster_1783.… Clust…    100     21        0       0      1    21      1    21
8 Cluster_4059.… Clust…    100     22        0       0      1    22      1    22
# ℹ 2 more variables: evalue <dbl>, bitscore <dbl>
# Count the number of miRNAs conserved across all three species
paste("Number of miRNAs conserved across all three species:", nrow(distinct(present_in_all, sseqid)))
[1] "Number of miRNAs conserved across all three species: 4"

3.2 Conserved among subsets of the three species

Now we want to find miRNAs that are conserved withing subsets of the three species

3.2.1 Apul and Peve

Find Apul miRNAs that have hits to Peve miRNAs but not hits to Pmea miRNAs (that would make them conserved among all three species, which we’ve already identified)

# Find Apul miRNAs that have matches from only Peve
present_in_apul_peve <- filtered_combined_blastn %>%
  # isolate Apul miRNAs with hits
  filter(!grepl("Porites_evermani|Pocillopora_meandrina", sseqid)) %>%
  group_by(sseqid) %>%
  # filter for hits to Peve only
  filter(any(grepl("Porites_evermani", qseqid)) & !any(grepl("Pocillopora_meandrina", qseqid)))

# View the miRNAs that match between Apul and Peve
head(present_in_apul_peve, nrow(present_in_apul_peve))
# A tibble: 1 × 12
# Groups:   sseqid [1]
  qseqid         sseqid pident length mismatch gapopen qstart  qend sstart  send
  <chr>          <chr>   <dbl>  <int>    <int>   <int>  <int> <int>  <int> <int>
1 Cluster_6211.… Clust…    100     22        0       0      1    22      1    22
# ℹ 2 more variables: evalue <dbl>, bitscore <dbl>
# Count the number of miRNAs conserved across the two species
paste("Number of miRNAs conserved in Apul and Peve:", nrow(distinct(present_in_apul_peve, sseqid)))
[1] "Number of miRNAs conserved in Apul and Peve: 1"

3.2.2 Apul and Pmea

Find Apul miRNAs that have hits to Pmea miRNAs but not hits to Peve miRNAs

# Find Apul miRNAs that have matches from only Pmea
present_in_apul_pmea <- filtered_combined_blastn %>%
  # isolate Apul miRNAs with hits
  filter(!grepl("Porites_evermani|Pocillopora_meandrina", sseqid)) %>%
  group_by(sseqid) %>%
  # filter for hits to Pmea only
  filter(!any(grepl("Porites_evermani", qseqid)) & any(grepl("Pocillopora_meandrina", qseqid)))

# View the miRNAs that match between Apul and Pmea
head(present_in_apul_pmea, nrow(present_in_apul_pmea))
# A tibble: 1 × 12
# Groups:   sseqid [1]
  qseqid         sseqid pident length mismatch gapopen qstart  qend sstart  send
  <chr>          <chr>   <dbl>  <int>    <int>   <int>  <int> <int>  <int> <int>
1 Cluster_1056.… Clust…    100     22        0       0      1    22      1    22
# ℹ 2 more variables: evalue <dbl>, bitscore <dbl>
# Count the number of miRNAs conserved across the two species
paste("Number of miRNAs conserved in Apul and Pmea:", nrow(distinct(present_in_apul_pmea, sseqid)))
[1] "Number of miRNAs conserved in Apul and Pmea: 1"

3.2.3 Peve and Pmea

Find Peve miRNAs that have hits to Pmea miRNAs but not hits to Apul miRNAs

# Find Peve miRNAs that have matches from only Pmea
present_in_peve_pmea <- filtered_combined_blastn %>%
  # isolate Peve miRNAs with hits
  filter(grepl("Porites_evermani", sseqid)) %>%
  group_by(sseqid) %>%
  # filter for hits to Pmea only (note the Apul sequence IDs don't contain the species name, so we have to use a non-descriptive unique identifier for filtering)
  filter(!any(grepl("mature::N", qseqid)) & any(grepl("Pocillopora_meandrina", qseqid)))

# View the miRNAs that match between Peve and Pmea
head(present_in_peve_pmea, nrow(present_in_peve_pmea))
# A tibble: 1 × 12
# Groups:   sseqid [1]
  qseqid sseqid pident length mismatch gapopen qstart  qend sstart  send  evalue
  <chr>  <chr>   <dbl>  <int>    <int>   <int>  <int> <int>  <int> <int>   <dbl>
1 Clust… Clust…   94.7     19        1       0      2    20      3    21 8.73e-6
# ℹ 1 more variable: bitscore <dbl>
# Count the number of miRNAs conserved across the two species
paste("Number of miRNAs conserved in Peve and Pmea:", nrow(distinct(present_in_peve_pmea, sseqid)))
[1] "Number of miRNAs conserved in Peve and Pmea: 1"

3.3 Visualize

3.3.1 Data munging of the results

cd ../data/10-shortRNA-ShortStack-comparison
grep "^>"  merged_all_ShortStack_mature.fasta | sed 's/^>//' > merged_all_ShortStack_mature_IDs.txt

head -5 merged_all_ShortStack_mature_IDs.txt
Cluster_316.mature::NC_058066.1:12757146-12757168(-)
Cluster_514.mature::NC_058066.1:20088678-20088700(+)
Cluster_548.mature::NC_058066.1:20346248-20346271(-)
Cluster_1506.mature::NC_058067.1:5656213-5656236(-)
Cluster_1900.mature::NC_058067.1:16118269-16118291(-)
# Read in and separate the ids of all miRNAs from the three species
merged_IDs <- readLines("../data/10-shortRNA-ShortStack-comparison/merged_all_ShortStack_mature_IDs.txt")

apul_IDs <- merged_IDs[grep("mature::N", merged_IDs)]
peve_IDs <- merged_IDs[grep("Porites_evermani", merged_IDs)]
pmea_IDs <- merged_IDs[grep("Pocillopora_meandrina", merged_IDs)]
length(apul_IDs)
[1] 38
length(peve_IDs)
[1] 46
length(pmea_IDs)
[1] 37
# Assign shared miRNA IDs to conserved miRNAs

# Function to append IDs of matching miRNAs to the original query miRNA
append_IDs <- function(IDs_list, df) {
  appended_IDs_list <- vector("list", length(IDs_list))
  for (i in seq_along(IDs_list)) {
    matching_entries <- df$qseqid[df$sseqid == IDs_list[i]]
    if (length(matching_entries) > 0) {
      appended_IDs_list[[i]] <- paste(IDs_list[i], paste(matching_entries, collapse = "|"), sep = "|")
    } else {
      appended_IDs_list[[i]] <- IDs_list[i]
    }
  }
  return(appended_IDs_list)
}

# Apply the function to each set of conserved miRNAs
appendedIDs_apul_peve_pmea <- append_IDs(unique(present_in_all$sseqid), present_in_all)

appendedIDs_apul_peve <- append_IDs(unique(present_in_apul_peve$sseqid), present_in_apul_peve)
appendedIDs_apul_pmea <- append_IDs(unique(present_in_apul_pmea$sseqid), present_in_apul_pmea)
appendedIDs_peve_pmea <- append_IDs(unique(present_in_peve_pmea$sseqid), present_in_peve_pmea)

print(appendedIDs_apul_peve_pmea[1])
[[1]]
[1] "Cluster_6977.mature::NC_058073.1:12437102-12437124(+)|Cluster_1153.mature::Porites_evermani_scaffold_49:151639-151661(-)|Cluster_1279.mature::Pocillopora_meandrina_HIv1___Sc0000003:10366054-10366076(+)"
print(appendedIDs_apul_peve)
[[1]]
[1] "Cluster_7077.mature::NC_058074.1:2966522-2966545(+)|Cluster_6211.mature::Porites_evermani_scaffold_502:58996-59018(-)"
print(appendedIDs_apul_pmea)
[[1]]
[1] "Cluster_514.mature::NC_058066.1:20088678-20088700(+)|Cluster_1056.mature::Pocillopora_meandrina_HIv1___Sc0000002:15749309-15749331(+)"
print(appendedIDs_peve_pmea)
[[1]]
[1] "Cluster_8824.mature::Porites_evermani_scaffold_910:99254-99275(+)|Cluster_2786.mature::Pocillopora_meandrina_HIv1___Sc0000008:1783823-1783844(+)"
# combine the new appended IDs into a single list of conserved miRNAs
conserved_miRNAs_all_IDs <- c(appendedIDs_apul_peve_pmea, appendedIDs_apul_peve, appendedIDs_apul_pmea, appendedIDs_peve_pmea)
# For each species list of miRNA IDs, replace species-specific IDs of conserved miRNAs with our newly generated appended IDs. This will created lists of miRNA IDs that have shared IDs for the conserved mRNAs
replace_entries <- function(spec_list, new_conserved_IDs) {
  # Iterate over each entry in spec_list
  for (i in seq_along(spec_list)) {
    # Check if the current entry in spec_list exists in any entry in new_conserved_IDs
    matching_entry <- new_conserved_IDs[grep(spec_list[i], new_conserved_IDs, fixed = TRUE)]
    # If a match is found, replace the entry in spec_list with the matching entry from new_conserved_IDs
    if (length(matching_entry) > 0) {
      spec_list[i] <- matching_entry[[1]]  # Replace with the first element of matching_entry
    }
  }
  return(spec_list)  # Return the modified spec_list
}

apul_mature_newconservedID <- replace_entries(apul_IDs, conserved_miRNAs_all_IDs)
peve_mature_newconservedID <- replace_entries(peve_IDs, conserved_miRNAs_all_IDs)
pmea_mature_newconservedID <- replace_entries(pmea_IDs, conserved_miRNAs_all_IDs)

3.3.2 Venn diagram

# Note that mtORF data indicates our P.meandrina samples are actually P.tuahiniensis, so that's the species name we'll be using in figures
a <- list("A. pulchra" = apul_mature_newconservedID, 
          "P. evermanni" = peve_mature_newconservedID,
          "P. tuahiniensis" = pmea_mature_newconservedID)

venn_conserved <- ggvenn(a, show_percentage = FALSE, fill_color = species_colors_nolabel)
venn_conserved

ggexport(filename = "../output/10-shortRNA-ShortStack-comparison/figures/venn_conserved_miRNA.png",
         plot   = venn_conserved,
         res    = 600,
         width  = 5000,
         height = 5000)

ggexport(filename = "../../supplemental/miRNA/venn_conserved_miRNA.png",
         plot   = venn_conserved,
         res    = 600,
         width  = 5000,
         height = 5000)

4 Compare sequence similarity across all species

Aligned all mature miRNA sequences from all three species in MEGA using MUSCLE, then generated pairwise distance matrix

# Remove description text at bottom of file
head -121 ../output/10-shortRNA-ShortStack-comparison/mature_miRNA_all_to_all_distance_06062024.csv > ../output/10-shortRNA-ShortStack-comparison/mature_miRNA_all_to_all_distance_06062024_nodescription.csv

# For some reason the last line was saved as just the row name, with no comma-delimitation to mark each empty column. We need to reintroduce the (empty) comma-delimited columns in the final row.
# Create the string of commas
append_string=$(printf ', %.0s' {1..121})

# Remove the last comma and add a space at the end
append_string="${append_string%,}"

# Use sed to remove existing trailing whitespace and then append the string of commas to row 120
sed -i 's/\s*$//' ../output/10-shortRNA-ShortStack-comparison/mature_miRNA_all_to_all_distance_06062024_nodescription.csv
sed -i '121s/$/ '"$append_string"'/' ../output/10-shortRNA-ShortStack-comparison/mature_miRNA_all_to_all_distance_06062024_nodescription.csv

# MEGA sometimes can't compute a pairwise distance for statistical reasons, and these are noted in the file as "?" entries. MEGA documentation indicates this notation is associated with being unable to identify any shared sites (i.e., the sequences are too different to even compare). Non-numeric entries will mess with our analysis down the line, so we need to replace those. Since they're associated with no shared sites, we'll replace them with 1s (indicating very high sequence distance).
# Replace all "?" entries with 1s
sed -i 's/?/1/g' ../output/10-shortRNA-ShortStack-comparison/mature_miRNA_all_to_all_distance_06062024_nodescription.csv
# load data
all_to_all <- read.table("../output/10-shortRNA-ShortStack-comparison/mature_miRNA_all_to_all_distance_06062024_nodescription.csv", sep=",", header = FALSE, na.strings = "")

# Assign column 1 entries to row names and column names (pairwise matrices have identical row and column names)
rownames(all_to_all) <- all_to_all[, 1]
all_to_all <- all_to_all[, -1]
colnames(all_to_all) <- rownames(all_to_all)

# Convert this upper triangular matrix to a full, symmetric distance matrix
all_to_all_full <- t(all_to_all)
all_to_all_full[upper.tri(all_to_all_full)] <- all_to_all[upper.tri(all_to_all)]
# Check the new distance matrix is symmetric
isSymmetric(all_to_all_full)
[1] TRUE
# Convert matrix back to data frame
all_to_all_full <- as.data.frame(all_to_all_full)


# Replace the "NA" values with 0s (along the axis)
all_to_all_full <- replace(all_to_all_full, is.na(all_to_all_full), 0)
cd ../output/10-shortRNA-ShortStack-comparison
# Isolate sequence names
awk -F ',' '{print $1}' mature_miRNA_all_to_all_distance_06062024_nodescription.csv > miRNA_names.txt

# Add full species name in second column based on the seq ID
# Note that mtORF data indicates our P.meandrina samples are actually P.tuahiniensis, so that's the species name we'll be using in figures
sed -i 's/\s*$//' miRNA_names.txt
sed '/mature::N/s/$/,A_pulchra/' miRNA_names.txt > miRNA_species.csv
sed -i '/mature::Porites/s/$/,P_evermanni/' miRNA_species.csv
sed -i '/mature::Pocillopora/s/$/,P_tuahiniensis/' miRNA_species.csv
# Read in
miRNA_species <- read.csv("../output/10-shortRNA-ShortStack-comparison/miRNA_species.csv", header = FALSE)

# Make the miRNA labels row names
colnames(miRNA_species) <- c("miRNA_ID", "Species")
rownames(miRNA_species) <- miRNA_species[, "miRNA_ID"]

4.1 PCoA

Principal Coordinates Analysis – similar to PCA, but can take a distance matrix as input

pcoa <- pcoa(all_to_all_full, correction="none", rn=NULL)
pcoa_vec <- as.data.frame(pcoa$vectors)
pcoa_vec$rownames <- rownames(pcoa_vec)
pcoa_vec <- mutate(pcoa_vec, rownames = trimws(as.character(rownames)))
pcoa_vec_annot <- left_join(pcoa_vec, miRNA_species, by = c("rownames" = "miRNA_ID"))
rownames(pcoa_vec_annot) <- pcoa_vec_annot$rownames

percent_var <- round(pcoa[["values"]][["Relative_eig"]]*100)

# Note that mtORF data indicates our P.meandrina samples are actually P.tuahiniensis, so that's the species name we'll be using in figures
pcoa_plot <- ggplot(pcoa_vec_annot, aes(Axis.1, Axis.2, color = Species)) + 
  geom_point(size = 4, alpha = .5) +
  ggtitle("PCoA of mature miRNA pairwise genetic distance (all to all)") +
  xlab(paste0("PC1: ",percent_var[1],"% variance")) +
  ylab(paste0("PC2: ",percent_var[2],"% variance")) + 
  scale_color_manual(values = species_colors) +
  coord_fixed() +
  stat_ellipse()

pcoa_plot

# Save plot
ggexport(filename = "../output/10-shortRNA-ShortStack-comparison/figures/PCoA_all_species_sequence_similarity.png",
         plot   = pcoa_plot,
         res    = 600,
         width  = 5000,
         height = 5000)

ggexport(filename = "../../supplemental/miRNA/PCoA_all_species_sequence_similarity.png",
         plot   = pcoa_plot,
         res    = 600,
         width  = 5000,
         height = 5000)

4.2 Heatmap

# # Annotate heatmap
specID <- miRNA_species %>% 
  select(Species)

all_to_all_full_shortnames <- all_to_all_full
colnames(all_to_all_full_shortnames) <- substr(colnames(all_to_all_full), 1, 20)
rownames(all_to_all_full_shortnames) <- colnames(all_to_all_full_shortnames)

# Run pheatmap
all.spec.seqsim.heat <- pheatmap(all_to_all_full_shortnames, 
                     cluster_rows = T, 
                     show_rownames = T,
                     annotation = specID, 
                     border_color = NA, 
                     fontsize = 5, 
                     fontsize_row = 5, 
                     height = 20)

# Save plot
ggexport(filename = "../output/10-shortRNA-ShortStack-comparison/figures/heatmap_all_species_sequence_similarity.png",
         plot   = all.spec.seqsim.heat,
         res    = 600,
         width  = 5000,
         height = 5000)

ggexport(filename = "../../supplemental/miRNA/heatmap_all_species_sequence_similarity.png",
         plot   = all.spec.seqsim.heat,
         res    = 600,
         width  = 5000,
         height = 5000)

5 Identify miRNAs with identical mature miRNAs

It’s possible for identical mature miRNAs to arise from non-identical precursor miRNAs. These would be classified by ShortStack as different miRNAs, but could still have similar/identical functions. Let’s see if we have any of those in our data.

We’ve already eliminated instances of miRNAs matching to themselves, so to identify distinct miRNAs from with identical mature sequences we can just look for hits within the same species (e.g. Apul.seq1 matching Apul.seq4)

5.1 Apul

# Identify sets of identical miRNAs
apul_identical_miRNAs <- filtered_combined_blastn %>%
  filter(grepl("mature::N", sseqid)) %>%
  filter(grepl("mature::N", qseqid))
         
head(apul_identical_miRNAs)
                                                 qseqid
1     Cluster_2521.mature::NC_058068.1:597877-597899(+)
2  Cluster_10726.mature::NC_058079.1:5232178-5232199(+)
3 Cluster_16040.mature::NW_025322765.1:722296-722318(+)
                                                 sseqid pident length mismatch
1     Cluster_2522.mature::NC_058068.1:598173-598195(+)    100     22        0
2  Cluster_10729.mature::NC_058079.1:5261442-5261463(+)    100     21        0
3 Cluster_16041.mature::NW_025322765.1:799181-799203(-)    100     22        0
  gapopen qstart qend sstart send   evalue bitscore
1       0      1   22      1   22 5.19e-10     44.1
2       0      1   21      1   21 1.92e-09     42.1
3       0      1   22      1   22 5.19e-10     44.1
# Save
write.table(apul_identical_miRNAs, "../output/10-shortRNA-ShortStack-comparison/Apul_identical_miRNAs.tab", sep="\t", row.names = FALSE, col.names = TRUE)
# First pair
head -2 ../output/10-shortRNA-ShortStack-comparison/Apul_identical_miRNAs.tab | tail -1

seq1=$(awk 'NR==2 {print $1}' FS='\t' ../output/10-shortRNA-ShortStack-comparison/Apul_identical_miRNAs.tab | sed 's/.mature::.*//' | sed 's/"//g')
seq2=$(awk 'NR==2 {print $2}' FS='\t' ../output/10-shortRNA-ShortStack-comparison/Apul_identical_miRNAs.tab | sed 's/.mature::.*//' | sed 's/"//g')

echo ""
echo $seq1
echo $seq2
echo ""

# grab the precursor, star, and mature fasta sequences for the two miRNAs
awk -v seq="$seq1" 'BEGIN {RS=">"; FS="\n"} $1 ~ seq {print ">"$0}' ../../D-Apul/output/13.2.1-Apul-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/mir.fasta

awk -v seq="$seq2" 'BEGIN {RS=">"; FS="\n"} $1 ~ seq {print ">"$0}' ../../D-Apul/output/13.2.1-Apul-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/mir.fasta
"Cluster_2521.mature::NC_058068.1:597877-597899(+)" "Cluster_2522.mature::NC_058068.1:598173-598195(+)" 100 22  0   0   1   22  1   22  5.19e-10    44.1

Cluster_2521
Cluster_2522

>Cluster_2521::NC_058068.1:597826-597919(+)
TGAAAATTGGCCATAGTCACATTTCACTAGATAAGCGCTAACTGTTATTGTTCTGCGTTATCGGTGAAATTGTAACTGTCGCCTCCTATTGCT

>Cluster_2521.mature::NC_058068.1:597877-597899(+)
TCTGCGTTATCGGTGAAATTGT

>Cluster_2521.star::NC_058068.1:597846-597868(+)
ATTTCACTAGATAAGCGCTAAC

>Cluster_2522::NC_058068.1:598122-598215(+)
TGAAAACTGACAATAGTTACATTTCACTAGATGAGCGCTAACTGTTATTGTTCTGCGTTATCGGTGAAATTGTAACTGTTGTCTCCTGTTGTT

>Cluster_2522.mature::NC_058068.1:598173-598195(+)
TCTGCGTTATCGGTGAAATTGT

>Cluster_2522.star::NC_058068.1:598142-598164(+)
ATTTCACTAGATGAGCGCTAAC
# Second pair
head -3 ../output/10-shortRNA-ShortStack-comparison/Apul_identical_miRNAs.tab | tail -1

seq1=$(awk 'NR==3 {print $1}' FS='\t' ../output/10-shortRNA-ShortStack-comparison/Apul_identical_miRNAs.tab | sed 's/.mature::.*//' | sed 's/"//g')
seq2=$(awk 'NR==3 {print $2}' FS='\t' ../output/10-shortRNA-ShortStack-comparison/Apul_identical_miRNAs.tab | sed 's/.mature::.*//' | sed 's/"//g')

echo ""
echo $seq1
echo $seq2
echo ""

# grab the precursor, star, and mature fasta sequences for the two miRNAs
awk -v seq="$seq1" 'BEGIN {RS=">"; FS="\n"} $1 ~ seq {print ">"$0}' ../../D-Apul/output/13.2.1-Apul-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/mir.fasta

awk -v seq="$seq2" 'BEGIN {RS=">"; FS="\n"} $1 ~ seq {print ">"$0}' ../../D-Apul/output/13.2.1-Apul-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/mir.fasta
"Cluster_10726.mature::NC_058079.1:5232178-5232199(+)"  "Cluster_10729.mature::NC_058079.1:5261442-5261463(+)"  100 21  0   0   1   21  1   21  1.92e-09    42.1

Cluster_10726
Cluster_10729

>Cluster_10726::NC_058079.1:5232123-5232219(+)
GGCACGCGATCGTGTGGGTGTCCAATTACAGCTGTCCAATTTGAACTTTTTGTAATTGGACACCTGTAATTGGATACCCACGTGATTTTCACGCCA

>Cluster_10726.mature::NC_058079.1:5232178-5232199(+)
TTGGACACCTGTAATTGGATA

>Cluster_10726.star::NC_058079.1:5232143-5232164(+)
TCCAATTACAGCTGTCCAATT

>Cluster_10729::NC_058079.1:5261387-5261483(+)
GGCACGCGATCATGTGGGTGTCCAATTACAGCTGTCCAATTTGAACTTTTTGTAATTGGACACCTGTAATTGGATACCACGTGATTTTCACGCCAA

>Cluster_10729.mature::NC_058079.1:5261442-5261463(+)
TTGGACACCTGTAATTGGATA

>Cluster_10729.star::NC_058079.1:5261407-5261428(+)
TCCAATTACAGCTGTCCAATT
# Third pair
head -4 ../output/10-shortRNA-ShortStack-comparison/Apul_identical_miRNAs.tab | tail -1

seq1=$(awk 'NR==4 {print $1}' FS='\t' ../output/10-shortRNA-ShortStack-comparison/Apul_identical_miRNAs.tab | sed 's/.mature::.*//' | sed 's/"//g')
seq2=$(awk 'NR==4 {print $2}' FS='\t' ../output/10-shortRNA-ShortStack-comparison/Apul_identical_miRNAs.tab | sed 's/.mature::.*//' | sed 's/"//g')

echo ""
echo $seq1
echo $seq2
echo ""

# grab the precursor, star, and mature fasta sequences for the two miRNAs
awk -v seq="$seq1" 'BEGIN {RS=">"; FS="\n"} $1 ~ seq {print ">"$0}' ../../D-Apul/output/13.2.1-Apul-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/mir.fasta

awk -v seq="$seq2" 'BEGIN {RS=">"; FS="\n"} $1 ~ seq {print ">"$0}' ../../D-Apul/output/13.2.1-Apul-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/mir.fasta
"Cluster_16040.mature::NW_025322765.1:722296-722318(+)" "Cluster_16041.mature::NW_025322765.1:799181-799203(-)" 100 22  0   0   1   22  1   22  5.19e-10    44.1

Cluster_16040
Cluster_16041

>Cluster_16040::NW_025322765.1:722245-722338(+)
TTGaatgactgactgactgactgacgaCTGTTGCGCCATTGCTTGAACGACTATGGGTTGACAGTCGACGgtcagtcggccgacagttggtgG

>Cluster_16040.mature::NW_025322765.1:722296-722318(+)
TATGGGTTGACAGTCGACGgtc

>Cluster_16040.star::NW_025322765.1:722265-722287(+)
ctgacgaCTGTTGCGCCATTGC

>Cluster_16041::NW_025322765.1:799159-799254(-)
TTGAacgactgactgactgactgacgaCTGTTGCGCCATTGCTTGAACGACTATGGGTTGACAGTCGACGgtcagtcggccgacagttggtgGAC

>Cluster_16041.mature::NW_025322765.1:799181-799203(-)
TATGGGTTGACAGTCGACGgtc

>Cluster_16041.star::NW_025322765.1:799212-799234(-)
ctgacgaCTGTTGCGCCATTGC

For all three of these sets of identical miRNAs, the mature and star sequences are identical but the precursors have a couple of mismatches, in addition to being located in different places on the chromosome.

5.2 Peve

# Identify sets of identical miRNAs
peve_identical_miRNAs <- filtered_combined_blastn %>%
  filter(grepl("Porites_evermani", sseqid)) %>%
  filter(grepl("Porites_evermani", qseqid))
         
head(peve_identical_miRNAs)
                                                             qseqid
1 Cluster_7604.mature::Porites_evermani_scaffold_730:81384-81406(-)
                                                             sseqid pident
1 Cluster_7605.mature::Porites_evermani_scaffold_730:82422-82444(-)    100
  length mismatch gapopen qstart qend sstart send   evalue bitscore
1     22        0       0      1   22      1   22 6.19e-10     44.1
# Save
write.table(peve_identical_miRNAs, "../output/10-shortRNA-ShortStack-comparison/Peve_identical_miRNAs.tab", sep="\t", row.names = FALSE, col.names = TRUE)
# First pair
head -2 ../output/10-shortRNA-ShortStack-comparison/Peve_identical_miRNAs.tab | tail -1

seq1=$(awk 'NR==2 {print $1}' FS='\t' ../output/10-shortRNA-ShortStack-comparison/Peve_identical_miRNAs.tab | sed 's/.mature::.*//' | sed 's/"//g')
seq2=$(awk 'NR==2 {print $2}' FS='\t' ../output/10-shortRNA-ShortStack-comparison/Peve_identical_miRNAs.tab | sed 's/.mature::.*//' | sed 's/"//g')

echo ""
echo $seq1
echo $seq2
echo ""

# grab the precursor, star, and mature fasta sequences for the two miRNAs
awk -v seq="$seq1" 'BEGIN {RS=">"; FS="\n"} $1 ~ seq {print ">"$0}' ../../E-Peve/output/08.2-Peve-sRNAseq-ShortStack-31bp-fastp-merged/ShortStack_out/mir.fasta

awk -v seq="$seq2" 'BEGIN {RS=">"; FS="\n"} $1 ~ seq {print ">"$0}' ../../E-Peve/output/08.2-Peve-sRNAseq-ShortStack-31bp-fastp-merged/ShortStack_out/mir.fasta
"Cluster_7604.mature::Porites_evermani_scaffold_730:81384-81406(-)" "Cluster_7605.mature::Porites_evermani_scaffold_730:82422-82444(-)" 100 22  0   0   1   22  1   22  6.19e-10    44.1

Cluster_7604
Cluster_7605

>Cluster_7604::Porites_evermani_scaffold_730:81362-81456(-)
TCAACAGTAAAACTAACAAAACGCTAACTGTAAAACTAACAAGTTCAACTTGTTAGTTTACAGTTAGTGTTTTGTTAGCGTGGCTCAAACCCTG

>Cluster_7604.mature::Porites_evermani_scaffold_730:81384-81406(-)
TGTTAGTTTACAGTTAGTGTTT

>Cluster_7604.star::Porites_evermani_scaffold_730:81413-81436(-)
ACGCTAACTGTAAAACTAACAAG

>Cluster_7605::Porites_evermani_scaffold_730:82400-82494(-)
TCAACAGTAAAACTAACAAAACGCTAACTGTAAAACTAACAAGTTCAACTTGTTAGTTTACAGTTAGTGTTTTGTTAGCCTGGCTCAAACCCTG

>Cluster_7605.mature::Porites_evermani_scaffold_730:82422-82444(-)
TGTTAGTTTACAGTTAGTGTTT

>Cluster_7605.star::Porites_evermani_scaffold_730:82451-82474(-)
ACGCTAACTGTAAAACTAACAAG

For this set of identical miRNAs, the mature and star sequences are identical and the precursors only have a single mismatch, despite being located in different places on the chromosome.

5.3 Pmea

# Identify sets of identical miRNAs
pmea_identical_miRNAs <- filtered_combined_blastn %>%
  filter(grepl("Pocillopora_meandrina", sseqid)) %>%
  filter(grepl("Pocillopora_meandrina", qseqid))
         
head(pmea_identical_miRNAs)
 [1] qseqid   sseqid   pident   length   mismatch gapopen  qstart   qend    
 [9] sstart   send     evalue   bitscore
<0 rows> (or 0-length row.names)

There are 0 sets of identical miRNAs identified by ShortStack in P.meandrina

6 Look at the database matches

# isolate the full "Results" annotation for each mature miRNA, which includes sequence detail and database matches

# Apul
awk -F'\t' 'NR==1 || $20 == "Y"' ../../D-Apul/output/13.2.1-Apul-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/Results.txt > ../output/10-shortRNA-ShortStack-comparison/Apul_results_mature.txt

# Peve
awk -F'\t' 'NR==1 || $20 == "Y"' ../../E-Peve/output/08.2-Peve-sRNAseq-ShortStack-31bp-fastp-merged/ShortStack_out/Results.txt > ../output/10-shortRNA-ShortStack-comparison/Peve_results_mature.txt

# Pmea
awk -F'\t' 'NR==1 || $20 == "Y"' ../../F-Pmea/output/13.2.1-Pmea-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/Results.txt > ../output/10-shortRNA-ShortStack-comparison/Pmea_results_mature.txt

Annotate our mature miRNA fasta files with associated database matches

Apul

cd ../output/10-shortRNA-ShortStack-comparison

while IFS= read -r line; do
    if [[ $line == ">"* ]]; then
        # Extract sequence header (without ">") and the accession string
        header="${line:1}"
        accession=$(echo "$header" | awk -F '.' '{print $1}')

        # Search for the accession string in the metadata file
        metadata_line=$(grep -i "$accession" Apul_results_mature.txt)

        # Extract the last column entry from the metadata line
        last_column=$(echo "$metadata_line" | awk '{print $NF}')

        # Append the last column entry to the sequence header
        new_header="$header $last_column"

        # Output the new header
        echo ">$new_header"
    else
        # Output the sequence line unchanged
        echo "$line"
    fi
done < ../../data/10-shortRNA-ShortStack-comparison/Apul_ShortStack_mature.fasta > Apul_ShortStack_mature_annotated.fasta

Peve

cd ../output/10-shortRNA-ShortStack-comparison

while IFS= read -r line; do
    if [[ $line == ">"* ]]; then
        # Extract sequence header (without ">") and the accession string
        header="${line:1}"
        accession=$(echo "$header" | awk -F '.' '{print $1}')

        # Search for the accession string in the metadata file
        metadata_line=$(grep -i "$accession" Peve_results_mature.txt)

        # Extract the last column entry from the metadata line
        last_column=$(echo "$metadata_line" | awk '{print $NF}')

        # Append the last column entry to the sequence header
        new_header="$header $last_column"

        # Output the new header
        echo ">$new_header"
    else
        # Output the sequence line unchanged
        echo "$line"
    fi
done < ../../data/10-shortRNA-ShortStack-comparison/Peve_ShortStack_mature.fasta > Peve_ShortStack_mature_annotated.fasta

Pmea

cd ../output/10-shortRNA-ShortStack-comparison

while IFS= read -r line; do
    if [[ $line == ">"* ]]; then
        # Extract sequence header (without ">") and the accession string
        header="${line:1}"
        accession=$(echo "$header" | awk -F '.' '{print $1}')

        # Search for the accession string in the metadata file
        metadata_line=$(grep -i "$accession" Pmea_results_mature.txt)

        # Extract the last column entry from the metadata line
        last_column=$(echo "$metadata_line" | awk '{print $NF}')

        # Append the last column entry to the sequence header
        new_header="$header $last_column"

        # Output the new header
        echo ">$new_header"
    else
        # Output the sequence line unchanged
        echo "$line"
    fi
done < ../../data/10-shortRNA-ShortStack-comparison/Pmea_ShortStack_mature.fasta > Pmea_ShortStack_mature_annotated.fasta

6.1 Table

Apul_shortstack_results <- read.csv("../../D-Apul/output/13.2.1-Apul-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/Results.txt", sep="\t")

Peve_shortstack_results <- read.csv("../../E-Peve/output/08.2-Peve-sRNAseq-ShortStack-31bp-fastp-merged/ShortStack_out/Results.txt", sep="\t")

Pmea_shortstack_results <- read.csv("../../F-Pmea/output/13.2.1-Pmea-sRNAseq-ShortStack-31bp-fastp-merged-cnidarian_miRBase/ShortStack_out/Results.txt", sep="\t")

Apul_num_miRNA <- Apul_shortstack_results %>% filter(MIRNA == "Y") %>% nrow()
Apul_num_miRNAmatch <- Apul_shortstack_results %>% filter(MIRNA == "Y" ) %>% filter(!is.na(known_miRNAs)) %>% nrow()

Peve_num_miRNA <- Peve_shortstack_results %>% filter(MIRNA == "Y") %>% nrow()
Peve_num_miRNAmatch <- Peve_shortstack_results %>% filter(MIRNA == "Y" ) %>% filter(!is.na(known_miRNAs)) %>% nrow()

Pmea_num_miRNA <- Pmea_shortstack_results %>% filter(MIRNA == "Y") %>% nrow()
Pmea_num_miRNAmatch <- Pmea_shortstack_results %>% filter(MIRNA == "Y" ) %>% filter(!is.na(known_miRNAs)) %>% nrow()

table_data <- data.frame(
  Species = c("A. pulchra", "P. evermanni", "P. tuaheniensis"),
  miRNA = c(Apul_num_miRNA, Peve_num_miRNA, Pmea_num_miRNA),
  miRNAmatch = c(Apul_num_miRNAmatch, Peve_num_miRNAmatch, Pmea_num_miRNAmatch)
)
colnames(table_data) <- c("Species", "miRNA", "miRNA with database match(es)")
table <- tableGrob(table_data, rows=NULL)
miRNA_matches_table <- grid.arrange(table)

png("../output/10-shortRNA-ShortStack-comparison/figures/table_miRNA_matches.png", width = 400, height = 100)
grid.arrange(table)

png("../../supplemental/miRNA/table_miRNA_matches.png", width = 400, height = 100)
grid.arrange(table)
LS0tCnRpdGxlOiAiMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uIgphdXRob3I6ICJLYXRobGVlbiBEdXJraW4iCmRhdGU6ICIyMDI0LTA1LTI4IgpvdXRwdXQ6IAogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgZ2l0aHViX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IDcyCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoRFQpCmxpYnJhcnkoQmlvc3RyaW5ncykKbGlicmFyeSh0bSkKbGlicmFyeShnZ3Zlbm4pCmxpYnJhcnkoYXBlKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoZ2dwbG90MikKCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwgICAgICAgICAjIERpc3BsYXkgY29kZSBjaHVua3MKICBldmFsID0gVFJVRSwgICAgICAgICAjIEV2YWx1YXRlIGNvZGUgY2h1bmtzCiAgd2FybmluZyA9IEZBTFNFLCAgICAgIyBIaWRlIHdhcm5pbmdzCiAgbWVzc2FnZSA9IEZBTFNFLCAgICAgIyBIaWRlIG1lc3NhZ2VzCiAgZmlnLndpZHRoID0gNiwgICAgICAgIyBTZXQgcGxvdCB3aWR0aCBpbiBpbmNoZXMKICBmaWcuaGVpZ2h0ID0gNCwgICAgICAjIFNldCBwbG90IGhlaWdodCBpbiBpbmNoZXMKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgIyBBbGlnbiBwbG90cyB0byB0aGUgY2VudGVyCiAgY29tbWVudCA9ICIiICAgICAgICAgIyBQcmV2ZW50cyBhcHBlbmRpbmcgJyMjJyB0byBiZWdpbm5pbmcgb2YgbGluZXMgaW4gY29kZSBvdXRwdXQKKQpgYGAKCkkgd2FudCB0byBmaW5kIG1pUk5BcyB0aGF0IGFyZSBjb25zZXJ2ZWQgYW1vbmcgZWl0aGVyIGEgc3Vic2V0IG9mIG9yIGFsbCB0aHJlZSBzcGVjaWVzIG9mIGludGVyZXN0ICgqQS5wdWxjaHJhKiwgKlAuZXZlcm1hbm5pKiwgYW5kICpQLm1lYW5kcmluYSopIHVzaW5nIEJsYXN0bi4gSSB3YW50IHRvIGdlbmVyYWxseSBpbnZlc3RpZ2F0ZSBzZXF1ZW5jZSBzaW1pbGFyaXR5IGFjcm9zcyBhbmQgd2l0aGluIHNwZWNpZXMuCgojIFByZXAgZGF0YQoKIyMgSXNvbGF0ZSBtYXR1cmUgbWlSTkEgc2VxdWVuY2VzCgpPdXIgU2hvcnRTdGFjayBvdXRwdXQgY29udGFpbnMgc2VxdWVuY2VzIGZvciB0aGUgbWF0dXJlLCBzdGFyLCBhbmQgcHJlY3Vyc29yIHNlcXVlbmNlcyBmb3IgZWFjaCBpZGVudGlmaWVkIG1pUk5BLiBXZSBqdXN0IHdhbnQgdG8gbG9vayBhdCB0aGUgbWF0dXJlIG1pUk5BIHNlcXVlbmNlcyByaWdodCBub3csIHNvIGxldCdzIGlzb2xhdGUgdGhvc2UuCgpgYGB7ciBpc29sYXRlLW1hdHVyZS1taVJOQSwgZW5naW5lPSdiYXNoJ30KY2QgLi4vZGF0YS8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24KCiMgQ29weSBhbGwgc2VxdWVuY2VzIHdob3NlIGhlYWRlcnMgY29udGFpbiAibWF0dXJlIgphd2sgJy9ePi8ge3AgPSAvbWF0dXJlL30gcCcgLi4vLi4vLi4vRC1BcHVsL291dHB1dC8xMy4yLjEtQXB1bC1zUk5Bc2VxLVNob3J0U3RhY2stMzFicC1mYXN0cC1tZXJnZWQtY25pZGFyaWFuX21pUkJhc2UvU2hvcnRTdGFja19vdXQvbWlyLmZhc3RhID4gQXB1bF9TaG9ydFN0YWNrX21hdHVyZS5mYXN0YQoKYXdrICcvXj4vIHtwID0gL21hdHVyZS99IHAnIC4uLy4uLy4uL0UtUGV2ZS9vdXRwdXQvMDguMi1QZXZlLXNSTkFzZXEtU2hvcnRTdGFjay0zMWJwLWZhc3RwLW1lcmdlZC9TaG9ydFN0YWNrX291dC9taXIuZmFzdGEgPiBQZXZlX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhCgphd2sgJy9ePi8ge3AgPSAvbWF0dXJlL30gcCcgLi4vLi4vLi4vRi1QbWVhL291dHB1dC8xMy4yLjEtUG1lYS1zUk5Bc2VxLVNob3J0U3RhY2stMzFicC1mYXN0cC1tZXJnZWQtY25pZGFyaWFuX21pUkJhc2UvU2hvcnRTdGFja19vdXQvbWlyLmZhc3RhID4gUG1lYV9TaG9ydFN0YWNrX21hdHVyZS5mYXN0YQoKZ3JlcCAiXj4iIEFwdWxfU2hvcnRTdGFja19tYXR1cmUuZmFzdGEgfCB3YyAtbCAKZ3JlcCAiXj4iIFBldmVfU2hvcnRTdGFja19tYXR1cmUuZmFzdGEgfCB3YyAtbApncmVwICJePiIgUG1lYV9TaG9ydFN0YWNrX21hdHVyZS5mYXN0YSB8IHdjIC1sCmBgYAoKIyMgQ2hlY2sgbWlSTkEgbGVuZ3RoIGRpc3RyaWJ1dGlvbnMKCmBgYHtyIHNldC1jb2xvcnN9CiMgU2V0IG91ciBjb2xvciBzY2hlbWUgZm9yIHBsb3R0aW5nIC0tIG9wdGlvbnMgZm9yIGJvdGggdGhlIGFiYnJldmlhdGVkIGxhYmVscyBvciB0aGUgZnVsbCwgY29ycmVjdCBzcGVjaWVzIG5hbWVzCnNwZWNpZXNfY29sb3JzIDwtIGMoJ0FfcHVsY2hyYScgPSAnIzQwOEVDNicsCiAgICAgICAgICAgICAgICAgICAgJ1BfZXZlcm1hbm5pJyA9ICcjMUUyNzYxJywKICAgICAgICAgICAgICAgICAgICAnUF90dWFoaW5pZW5zaXMnID0gJyM3QTIwNDgnKQoKc3BlY2llc19jb2xvcnNfbm9sYWJlbCA8LSBjKCcjNDA4RUM2JywgJyMxRTI3NjEnLCAnIzdBMjA0OCcpCmBgYAoKQXB1bDoKYGBge3IgY2FsY3VsYXRlLUFwdWwtbWlSTkEtbGVuZ3RocywgZW5naW5lPSdiYXNoJ30KIyBFeHRyYWN0IHNlcXVlbmNlIGxlbmd0aHMgYW5kIGNhbGN1bGF0ZSBzdGF0aXN0aWNzCmdyZXAgLXYgJ14+JyAuLi9kYXRhLzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9BcHVsX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhIHwgYXdrICd7IHByaW50IGxlbmd0aCgkMCkgfScgPiAuLi9kYXRhLzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9BcHVsX1Nob3J0U3RhY2tfbWF0dXJlX2xlbmd0aHMudHh0CmBgYAoKYGBge3IgcGxvdC1BcHVsLW1pUk5BLWxlbmd0aHN9CiMgUmVhZCBpbiB0aGUgbGVuZ3RocwpBcHVsX2xlbmd0aHMgPC0gcmVhZC50YWJsZSgiLi4vZGF0YS8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vQXB1bF9TaG9ydFN0YWNrX21hdHVyZV9sZW5ndGhzLnR4dCIsIGhlYWRlciA9IEZBTFNFLCBjb2wubmFtZXMgPSAibGVuZ3RoIikKCiMgTWFrZSBoaXN0b2dyYW0gb2YgbGVuZ3RocwpoaXN0X0FwdWxfbGVuZ3RocyA8LSBnZ3Bsb3QoQXB1bF9sZW5ndGhzLCBhZXMoeCA9IGxlbmd0aCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGZpbGwgPSBzcGVjaWVzX2NvbG9yc1snQV9wdWxjaHJhJ10sIGNvbG9yID0gImJsYWNrIikgKwogIGdlb21fdGV4dChzdGF0ID0gJ2NvdW50JywgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgdmp1c3QgPSAtMC41KSArCiAgbGFicyh0aXRsZSA9ICJBLiBwdWxjaHJhIG1pUk5BIHNlcXVlbmNlIGxlbmd0aHMiLAogICAgICAgeCA9ICJTZXF1ZW5jZSBMZW5ndGggW251Y2xlb3RpZGVzXSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB4bGltKDIwLCAyNSkgKwogIHlsaW0oMCwgNDEpICsKICB0aGVtZV9taW5pbWFsKCkKCmhpc3RfQXB1bF9sZW5ndGhzCgpnZ2V4cG9ydChmaWxlbmFtZSA9ICIuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL2ZpZ3VyZXMvaGlzdG9ncmFtX0FwdWxfbWlSTkFfbGVuZ3Rocy5wbmciLAogICAgICAgICBwbG90ICAgPSBoaXN0X0FwdWxfbGVuZ3RocywKICAgICAgICAgcmVzICAgID0gNjAwLAogICAgICAgICB3aWR0aCAgPSA1MDAwLAogICAgICAgICBoZWlnaHQgPSA1MDAwKQoKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vLi4vc3VwcGxlbWVudGFsL21pUk5BL2hpc3RvZ3JhbV9BcHVsX21pUk5BX2xlbmd0aHMucG5nIiwKICAgICAgICAgcGxvdCAgID0gaGlzdF9BcHVsX2xlbmd0aHMsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKYGBgCgpQbWVhOgpgYGB7ciBjYWxjdWxhdGUtUG1lYS1taVJOQS1sZW5ndGhzLCBlbmdpbmU9J2Jhc2gnfQojIEV4dHJhY3Qgc2VxdWVuY2UgbGVuZ3RocyBhbmQgY2FsY3VsYXRlIHN0YXRpc3RpY3MKZ3JlcCAtdiAnXj4nIC4uL2RhdGEvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL1BtZWFfU2hvcnRTdGFja19tYXR1cmUuZmFzdGEgfCBhd2sgJ3sgcHJpbnQgbGVuZ3RoKCQwKSB9JyA+IC4uL2RhdGEvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL1BtZWFfU2hvcnRTdGFja19tYXR1cmVfbGVuZ3Rocy50eHQKYGBgCgpgYGB7ciBwbG90LVBtZWEtbWlSTkEtbGVuZ3Roc30KIyBSZWFkIGluIHRoZSBsZW5ndGhzClBtZWFfbGVuZ3RocyA8LSByZWFkLnRhYmxlKCIuLi9kYXRhLzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9QbWVhX1Nob3J0U3RhY2tfbWF0dXJlX2xlbmd0aHMudHh0IiwgaGVhZGVyID0gRkFMU0UsIGNvbC5uYW1lcyA9ICJsZW5ndGgiKQoKIyBNYWtlIGhpc3RvZ3JhbSBvZiBsZW5ndGhzCmhpc3RfUG1lYV9sZW5ndGhzIDwtIGdncGxvdChQbWVhX2xlbmd0aHMsIGFlcyh4ID0gbGVuZ3RoKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgZmlsbCA9IHNwZWNpZXNfY29sb3JzWydQX3R1YWhpbmllbnNpcyddLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX3RleHQoc3RhdCA9ICdjb3VudCcsIGFlcyhsYWJlbCA9IC4uY291bnQuLiksIHZqdXN0ID0gLTAuNSkgKwogIGxhYnModGl0bGUgPSAiUC4gdHVhaGluaWVuc2lzIG1pUk5BIHNlcXVlbmNlIGxlbmd0aHMiLAogICAgICAgeCA9ICJTZXF1ZW5jZSBMZW5ndGggW251Y2xlb3RpZGVzXSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIpICsKICB4bGltKDIwLjUsIDI0LjUpICsKICB5bGltKDAsIDQxKSArCiAgdGhlbWVfbWluaW1hbCgpCgpoaXN0X1BtZWFfbGVuZ3RocwoKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9maWd1cmVzL2hpc3RvZ3JhbV9QbWVhX21pUk5BX2xlbmd0aHMucG5nIiwKICAgICAgICAgcGxvdCAgID0gaGlzdF9QbWVhX2xlbmd0aHMsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKCmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uLy4uL3N1cHBsZW1lbnRhbC9taVJOQS9oaXN0b2dyYW1fUG1lYV9taVJOQV9sZW5ndGhzLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IGhpc3RfUG1lYV9sZW5ndGhzLAogICAgICAgICByZXMgICAgPSA2MDAsCiAgICAgICAgIHdpZHRoICA9IDUwMDAsCiAgICAgICAgIGhlaWdodCA9IDUwMDApCmBgYAoKUGV2ZToKYGBge3IgY2FsY3VsYXRlLVBldmUtbWlSTkEtbGVuZ3RocywgZW5naW5lPSdiYXNoJ30KIyBFeHRyYWN0IHNlcXVlbmNlIGxlbmd0aHMgYW5kIGNhbGN1bGF0ZSBzdGF0aXN0aWNzCmdyZXAgLXYgJ14+JyAuLi9kYXRhLzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9QZXZlX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhIHwgYXdrICd7IHByaW50IGxlbmd0aCgkMCkgfScgPiAuLi9kYXRhLzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9QZXZlX1Nob3J0U3RhY2tfbWF0dXJlX2xlbmd0aHMudHh0CmBgYAoKYGBge3IgcGxvdC1QZXZlLW1pUk5BLWxlbmd0aHN9CiMgUmVhZCBpbiB0aGUgbGVuZ3RocwpQZXZlX2xlbmd0aHMgPC0gcmVhZC50YWJsZSgiLi4vZGF0YS8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vUGV2ZV9TaG9ydFN0YWNrX21hdHVyZV9sZW5ndGhzLnR4dCIsIGhlYWRlciA9IEZBTFNFLCBjb2wubmFtZXMgPSAibGVuZ3RoIikKCiMgTWFrZSBoaXN0b2dyYW0gb2YgbGVuZ3RocwpoaXN0X1BldmVfbGVuZ3RocyA8LSBnZ3Bsb3QoUGV2ZV9sZW5ndGhzLCBhZXMoeCA9IGxlbmd0aCkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIAogICAgICAgICAgICAgICAgIGZpbGwgPSBzcGVjaWVzX2NvbG9yc1snUF9ldmVybWFubmknXSwgCiAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KHN0YXQgPSAnY291bnQnLCBhZXMobGFiZWwgPSAuLmNvdW50Li4pLCB2anVzdCA9IC0wLjUpICsKICBsYWJzKHRpdGxlID0gIlAuIGV2ZXJtYW5uaSBtaVJOQSBzZXF1ZW5jZSBsZW5ndGhzIiwKICAgICAgIHggPSAiU2VxdWVuY2UgTGVuZ3RoIFtudWNsZW90aWRlc10iLAogICAgICAgeSA9ICJGcmVxdWVuY3kiKSArCiAgeGxpbSgyMC41LCAyNC41KSArCiAgeWxpbSgwLCA0MSkgKwogIHRoZW1lX21pbmltYWwoKQoKaGlzdF9QZXZlX2xlbmd0aHMKCmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vZmlndXJlcy9oaXN0b2dyYW1fUGV2ZV9taVJOQV9sZW5ndGhzLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IGhpc3RfUGV2ZV9sZW5ndGhzLAogICAgICAgICByZXMgICAgPSA2MDAsCiAgICAgICAgIHdpZHRoICA9IDUwMDAsCiAgICAgICAgIGhlaWdodCA9IDUwMDApCgpnZ2V4cG9ydChmaWxlbmFtZSA9ICIuLi8uLi9zdXBwbGVtZW50YWwvbWlSTkEvaGlzdG9ncmFtX1BldmVfbWlSTkFfbGVuZ3Rocy5wbmciLAogICAgICAgICBwbG90ICAgPSBoaXN0X1BldmVfbGVuZ3RocywKICAgICAgICAgcmVzICAgID0gNjAwLAogICAgICAgICB3aWR0aCAgPSA1MDAwLAogICAgICAgICBoZWlnaHQgPSA1MDAwKQpgYGAKCkxldCdzIGFsc28gbWFrZSBhIHBsb3Qgc2hvd2luZyB0aGUgbGVuZ3RoIGRpc3RyaWJ1dGlvbnMgb2YgYWxsIHRocmVlIHNwZWNpZXMKCmBgYHtyIGNvbWJpbmUtbGVuZ3RoLWZpbGVzfQojIEFkZCBhIG5ldyBjb2x1bW4gdG8gZWFjaCBkYXRhIGZyYW1lIHRvIGxhYmVsIHRoZSBzb3VyY2UgZmlsZQpBcHVsX2xlbmd0aHMgPC0gQXB1bF9sZW5ndGhzICU+JSBtdXRhdGUoU3BlY2llcyA9ICdBX3B1bGNocmEnKQpQZXZlX2xlbmd0aHMgPC0gUGV2ZV9sZW5ndGhzICU+JSBtdXRhdGUoU3BlY2llcyA9ICdQX2V2ZXJtYW5uaScpClBtZWFfbGVuZ3RocyA8LSBQbWVhX2xlbmd0aHMgJT4lIG11dGF0ZShTcGVjaWVzID0gJ1BfdHVhaGluaWVuc2lzJykKCiMgQ29tYmluZSB0aGUgZGF0YSBmcmFtZXMgaW50byBvbmUKYWxsX2xlbmd0aHMgPC0gcmJpbmQoQXB1bF9sZW5ndGhzLCBQZXZlX2xlbmd0aHMsIFBtZWFfbGVuZ3RocykKYGBgCgpgYGB7ciBwbG90LWFsbC1sZW5ndGhzfQpoaXN0X2FsbF9sZW5ndGhzIDwtIGdncGxvdChhbGxfbGVuZ3RocywgYWVzKHggPSBsZW5ndGgsIGZpbGwgPSBTcGVjaWVzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgCiAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOTEpLCAKICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsIAogICAgICAgICAgICAgICAgIHdpZHRoID0gMC45KSArCiAgZ2VvbV90ZXh0KHN0YXQgPSAnY291bnQnLCAKICAgICAgICAgICAgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgCiAgICAgICAgICAgIHZqdXN0ID0gLTAuNSwgCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHNwZWNpZXNfY29sb3JzKSArCiAgbGFicyh0aXRsZSA9ICJTZXF1ZW5jZSBsZW5ndGhzIGJ5IHNwZWNpZXMiLAogICAgICAgeCA9ICJTZXF1ZW5jZSBMZW5ndGggW251Y2xlb3RpZGVzXSIsCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIsCiAgICAgICBmaWxsID0gIlNwZWNpZXMiKSArCiAgeGxpbSgyMC41LCAyNC41KSArCiAgeWxpbSgwLCA0MSkgKwogIHRoZW1lX21pbmltYWwoKQoKaGlzdF9hbGxfbGVuZ3RocwoKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9maWd1cmVzL2hpc3RvZ3JhbV9hbGxfbWlSTkFfbGVuZ3Rocy5wbmciLAogICAgICAgICBwbG90ICAgPSBoaXN0X2FsbF9sZW5ndGhzLAogICAgICAgICByZXMgICAgPSA2MDAsCiAgICAgICAgIHdpZHRoICA9IDUwMDAsCiAgICAgICAgIGhlaWdodCA9IDUwMDApCgpnZ2V4cG9ydChmaWxlbmFtZSA9ICIuLi8uLi9zdXBwbGVtZW50YWwvbWlSTkEvaGlzdG9ncmFtX2FsbF9taVJOQV9sZW5ndGhzLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IGhpc3RfYWxsX2xlbmd0aHMsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKYGBgCgpgYGB7ciBzdW1tYXJpemUtbGVuZ3RoLWRpc3RyaWJ1dGlvbnN9CiMgU3VtbWFyaXplIG1pbiwgbWF4LCBhbmQgYXZlcmFnZSBsZW5ndGhzIGZvciBlYWNoIHNwZWNpZXMKbGVuZ3RoX3N1bW1hcnkgPC0gYWxsX2xlbmd0aHMgJT4lCiAgZ3JvdXBfYnkoU3BlY2llcykgJT4lCiAgc3VtbWFyaXNlKAogICAgTWluX0xlbmd0aCA9IG1pbihsZW5ndGgsIG5hLnJtID0gVFJVRSksCiAgICBNYXhfTGVuZ3RoID0gbWF4KGxlbmd0aCwgbmEucm0gPSBUUlVFKSwKICAgIEF2Z19MZW5ndGggPSBtZWFuKGxlbmd0aCwgbmEucm0gPSBUUlVFKQogICkKCnByaW50KGxlbmd0aF9zdW1tYXJ5KQpgYGAKYGBge3IgcmVtb3ZlLXVubmVlZGVkLWxlbmd0aHMtZmlsZXMsIGVuZ2luZT0nYmFzaCd9CnJtIC1yIC4uL2RhdGEvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uLypsZW5ndGhzLnR4dApgYGAKCiMjIE1lcmdlIHRoZSB0aHJlZSBtYXR1cmUgbWlSTkEgRkFTVEFzCgpgYGB7ciBtZXJnZS1taVJOQS1GQVNUQXMsIGVuZ2luZT0nYmFzaCd9CmNkIC4uL2RhdGEvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uCgpjYXQgQXB1bF9TaG9ydFN0YWNrX21hdHVyZS5mYXN0YSBQZXZlX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhIFBtZWFfU2hvcnRTdGFja19tYXR1cmUuZmFzdGEgPiBtZXJnZWRfYWxsX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhCgpoZWFkIG1lcmdlZF9hbGxfU2hvcnRTdGFja19tYXR1cmUuZmFzdGEKdGFpbCBtZXJnZWRfYWxsX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhCmBgYAoKTGV0J3MgZG8gYSBxdWljayBpbnZlc3RpZ2F0aW9uIG9mIG91ciBtZXJnZWQgbWF0dXJlIG1pUk5Bcy4KCmBgYHtyIGNhbGN1bGF0ZS1taVJOQS1sZW5ndGgtc3RhdHMsIGVuZ2luZT0nYmFzaCd9CiMgRXh0cmFjdCBzZXF1ZW5jZSBsZW5ndGhzIGFuZCBjYWxjdWxhdGUgc3RhdGlzdGljcwpsZW5ndGhzPSQoYXdrICcvXj4vIHtpZiAoc2VxbGVuKSBwcmludCBzZXFsZW47IHNlcWxlbj0wOyBuZXh0fSB7c2VxbGVuICs9IGxlbmd0aCgkMCl9IEVORCB7cHJpbnQgc2VxbGVufScgLi4vZGF0YS8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vbWVyZ2VkX2FsbF9TaG9ydFN0YWNrX21hdHVyZS5mYXN0YSkKbWluX2xlbmd0aD0kKGVjaG8gIiRsZW5ndGhzIiB8IHNvcnQgLW4gfCBoZWFkIC1uIDEpCm1heF9sZW5ndGg9JChlY2hvICIkbGVuZ3RocyIgfCBzb3J0IC1uIHwgdGFpbCAtbiAxKQp0b3RhbF9sZW5ndGg9JChlY2hvICIkbGVuZ3RocyIgfCBhd2sgJ3tzdW0gKz0gJDF9IEVORCB7cHJpbnQgc3VtfScpCm51bV9zZXF1ZW5jZXM9JChncmVwIC1jICdePicgLi4vZGF0YS8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vbWVyZ2VkX2FsbF9TaG9ydFN0YWNrX21hdHVyZS5mYXN0YSkKYXZlcmFnZV9sZW5ndGg9JChlY2hvICJzY2FsZT0yOyAkdG90YWxfbGVuZ3RoIC8gJG51bV9zZXF1ZW5jZXMiIHwgYmMpCgojIE91dHB1dCByZXN1bHRzCmVjaG8gIk1pbmltdW0gc2VxdWVuY2UgbGVuZ3RoOiAkbWluX2xlbmd0aCIKZWNobyAiTWF4aW11bSBzZXF1ZW5jZSBsZW5ndGg6ICRtYXhfbGVuZ3RoIgplY2hvICJBdmVyYWdlIHNlcXVlbmNlIGxlbmd0aDogJGF2ZXJhZ2VfbGVuZ3RoIgpgYGAKCiMgQkxBU1RzCgojIyBNYWtlIGRhdGFiYXNlIGZvciBlYWNoIHNwZWNpZXM6CgpBcHVsCmBgYHtyIEFwdWwtYmxhc3QtZGIsIGVuZ2luZT0nYmFzaCd9Ci9ob21lL3NoYXJlZC9uY2JpLWJsYXN0LTIuMTEuMCsvYmluL21ha2VibGFzdGRiIFwKLWluIC4uL2RhdGEvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL0FwdWxfU2hvcnRTdGFja19tYXR1cmUuZmFzdGEgXAotZGJ0eXBlIG51Y2wgXAotb3V0IC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vYmxhc3RzL0FwdWwtZGIvQXB1bF9TaG9ydFN0YWNrX21hdHVyZQpgYGAKClBldmUKYGBge3IgUGV2ZS1ibGFzdC1kYiwgZW5naW5lPSdiYXNoJ30KL2hvbWUvc2hhcmVkL25jYmktYmxhc3QtMi4xMS4wKy9iaW4vbWFrZWJsYXN0ZGIgXAotaW4gLi4vZGF0YS8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vUGV2ZV9TaG9ydFN0YWNrX21hdHVyZS5mYXN0YSBcCi1kYnR5cGUgbnVjbCBcCi1vdXQgLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9ibGFzdHMvUGV2ZS1kYi9QZXZlX1Nob3J0U3RhY2tfbWF0dXJlCmBgYAoKUG1lYQpgYGB7ciBQbWVhLWJsYXN0LWRiLCBlbmdpbmU9J2Jhc2gnfQovaG9tZS9zaGFyZWQvbmNiaS1ibGFzdC0yLjExLjArL2Jpbi9tYWtlYmxhc3RkYiBcCi1pbiAuLi9kYXRhLzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9QbWVhX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhIFwKLWRidHlwZSBudWNsIFwKLW91dCAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL2JsYXN0cy9QbWVhLWRiL1BtZWFfU2hvcnRTdGFja19tYXR1cmUKYGBgCgojIyBSdW4gQmxhc3RuCgpHZW5lcmF0ZSBhIGxpc3Qgb2YgYmxhc3QgcmVzdWx0cyB0aGF0LCBmb3IgZWFjaCBtaVJOQSwgc2hvd3MgdGhlIHRvcCBoaXQgaW4gZWFjaCBvZiB0d28gb3RoZXIgc3BlY2llcy4gV2Ugd2FudCB0byBzZWUgdGhlIHRvcCBoaXRzIG5vIG1hdHRlciBob3cgcG9vciB0aGUgbWF0Y2ggaXMsIHNvIHdlIHdpbGwgbm90IGZpbHRlciBieSBlLXZhbHVlIGF0IHRoaXMgc3RhZ2UuIFdlJ2xsIGFsc28gaW5jbHVkZSB0aGUgIi13b3JkX3NpemUgNCIgb3B0aW9uLCB3aGljaCByZWR1Y2VzIHRoZSByZXF1aXJlZCBsZW5ndGggb2YgdGhlIGluaXRpYWwgbWF0Y2guCgpBbGwgdG8gQXB1bDoKYGBge3IgYmxhc3RuLWFsbC10by1BcHVsLCBlbmdpbmU9J2Jhc2gnfQovaG9tZS9zaGFyZWQvbmNiaS1ibGFzdC0yLjExLjArL2Jpbi9ibGFzdG4gXAotdGFzayBibGFzdG4tc2hvcnQgXAotcXVlcnkgLi4vZGF0YS8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vbWVyZ2VkX2FsbF9TaG9ydFN0YWNrX21hdHVyZS5mYXN0YSBcCi1kYiAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL2JsYXN0cy9BcHVsLWRiL0FwdWxfU2hvcnRTdGFja19tYXR1cmUgXAotb3V0IC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vYmxhc3RzL0FwdWxfdG9fYWxsX2JsYXN0bi50YWIgXAotbnVtX3RocmVhZHMgNDAgXAotd29yZF9zaXplIDQgXAotbWF4X3RhcmdldF9zZXFzIDEgXAotbWF4X2hzcHMgMSBcCi1vdXRmbXQgNgoKd2MgLWwgLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9ibGFzdHMvQXB1bF90b19hbGxfYmxhc3RuLnRhYgpgYGAKCgpBbGwgdG8gUGV2ZToKYGBge3IgYmxhc3RuLWFsbC10by1QZXZlLCBlbmdpbmU9J2Jhc2gnfQovaG9tZS9zaGFyZWQvbmNiaS1ibGFzdC0yLjExLjArL2Jpbi9ibGFzdG4gXAotdGFzayBibGFzdG4tc2hvcnQgXAotcXVlcnkgLi4vZGF0YS8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vbWVyZ2VkX2FsbF9TaG9ydFN0YWNrX21hdHVyZS5mYXN0YSBcCi1kYiAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL2JsYXN0cy9QZXZlLWRiL1BldmVfU2hvcnRTdGFja19tYXR1cmUgXAotb3V0IC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vYmxhc3RzL1BldmVfdG9fYWxsX2JsYXN0bi50YWIgXAotbnVtX3RocmVhZHMgNDAgXAotd29yZF9zaXplIDQgXAotbWF4X3RhcmdldF9zZXFzIDEgXAotbWF4X2hzcHMgMSBcCi1vdXRmbXQgNgoKd2MgLWwgLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9ibGFzdHMvUGV2ZV90b19hbGxfYmxhc3RuLnRhYgpgYGAKCkFsbCB0byBQbWVhOgpgYGB7ciBibGFzdG4tYWxsLXRvLVBtZWEsIGVuZ2luZT0nYmFzaCd9Ci9ob21lL3NoYXJlZC9uY2JpLWJsYXN0LTIuMTEuMCsvYmluL2JsYXN0biBcCi10YXNrIGJsYXN0bi1zaG9ydCBcCi1xdWVyeSAuLi9kYXRhLzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9tZXJnZWRfYWxsX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhIFwKLWRiIC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vYmxhc3RzL1BtZWEtZGIvUG1lYV9TaG9ydFN0YWNrX21hdHVyZSBcCi1vdXQgLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9ibGFzdHMvUG1lYV90b19hbGxfYmxhc3RuLnRhYiBcCi1udW1fdGhyZWFkcyA0MCBcCi13b3JkX3NpemUgNCBcCi1tYXhfdGFyZ2V0X3NlcXMgMSBcCi1tYXhfaHNwcyAxIFwKLW91dGZtdCA2Cgp3YyAtbCAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL2JsYXN0cy9QbWVhX3RvX2FsbF9ibGFzdG4udGFiCmBgYAoKIyMgSm9pbiBCTEFTVCB0YWJsZXMKCmBgYHtyIGxvYWQtYmxhc3QtdGFibGVzfQphcHVsX3RvX2FsbF9ibGFzdG4gPC0gcmVhZC50YWJsZSgiLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9ibGFzdHMvQXB1bF90b19hbGxfYmxhc3RuLnRhYiIsIHNlcD0iXHQiLCBoZWFkZXI9RkFMU0UpCnBldmVfdG9fYWxsX2JsYXN0biA8LSByZWFkLnRhYmxlKCIuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL2JsYXN0cy9QZXZlX3RvX2FsbF9ibGFzdG4udGFiIiwgc2VwPSJcdCIsIGhlYWRlcj1GQUxTRSkKcG1lYV90b19hbGxfYmxhc3RuIDwtIHJlYWQudGFibGUoIi4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vYmxhc3RzL1BtZWFfdG9fYWxsX2JsYXN0bi50YWIiLCBzZXA9Ilx0IiwgaGVhZGVyPUZBTFNFKQpgYGAKCkNvbHVtbiBsYWJlbHM6IApxc2VxaWQ6IFF1ZXJ5IHNlcXVlbmNlIElEIApzc2VxaWQ6IFN1YmplY3QgKGRhdGFiYXNlKQpzZXF1ZW5jZSBJRCBwaWRlbnQ6IFBlcmNlbnRhZ2Ugb2YgaWRlbnRpY2FsIG1hdGNoZXMgCmxlbmd0aDogQWxpZ25tZW50IGxlbmd0aCAobnVtYmVyIG9mIGJhc2UgcGFpcnMgb3IgYW1pbm8gYWNpZHMpIAptaXNtYXRjaDogTnVtYmVyIG9mIG1pc21hdGNoZXMgCmdhcG9wZW46IE51bWJlciBvZiBnYXAgb3BlbmluZ3MgCnFzdGFydDogU3RhcnQgb2YgYWxpZ25tZW50IGluIHRoZSBxdWVyeSAKcWVuZDogRW5kIG9mIGFsaWdubWVudCBpbiB0aGUgcXVlcnkgCnNzdGFydDogU3RhcnQgb2YgYWxpZ25tZW50IGluIHRoZSBzdWJqZWN0IApzZW5kOiBFbmQgb2YgYWxpZ25tZW50IGluIHRoZSBzdWJqZWN0IApldmFsdWU6IEV4cGVjdCB2YWx1ZSAobnVtYmVyIG9mIGhpdHMgZXhwZWN0ZWQgYnkgY2hhbmNlKSAKYml0c2NvcmU6IEJpdCBzY29yZQoKYGBge3Igam9pbi1ibGFzdC10YWJsZXN9CiMgQ29tYmluZSB0aGUgdGhyZWUgYmxhc3QgdGFibGVzCmNvbWJpbmVkX2JsYXN0biA8LSByYmluZChhcHVsX3RvX2FsbF9ibGFzdG4sIHBldmVfdG9fYWxsX2JsYXN0biwgcG1lYV90b19hbGxfYmxhc3RuKQoKIyBBc3NpZ24gaW5mb3JtYXRpdmUgY29sdW1uIGxhYmVscwpjb2xuYW1lcyhjb21iaW5lZF9ibGFzdG4pIDwtIGMoInFzZXFpZCIsICJzc2VxaWQiLCAicGlkZW50IiwgImxlbmd0aCIsICJtaXNtYXRjaCIsICJnYXBvcGVuIiwgInFzdGFydCIsICJxZW5kIiwgInNzdGFydCIsICJzZW5kIiwgImV2YWx1ZSIsICJiaXRzY29yZSIpCgojIFNhdmUgdGhpcyBvcmlnaW5hbCwgdW5maWx0ZXJlZCBibGFzdCB0YWJsZS4Kd3JpdGUudGFibGUoY29tYmluZWRfYmxhc3RuLCAiLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9jb21iaW5lZF9ibGFzdC50YWIiLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzPUZBTFNFLCBxdW90ZT1GQUxTRSkKYGBgCgoKIyBJZGVudGlmeSBjb25zZXJ2ZWQgbWlSTkFzCgpGaWx0ZXIgb3VyIGxpc3Qgb2YgYmxhc3QgaGl0cyB0byByZW1vdmUgaW5zdGFuY2VzIHdoZXJlIHNlcXVlbmNlcyBtYXRjaCB0aGVtc2VsdmVzIChlLmcuIGZyb20gcXVlcnlpbmcgYW4gQXB1bCBzZXF1ZW5jZSBhZ2FpbnN0IG91ciBjb21iaW5lZCBkYXRhYmFzZSB3aGljaCBjb250YWluZWQgYWxsIEFwdWwgc2VxdWVuY2VzKSwgYW5kIHRvIHJldGFpbiBvbmx5IHRoZSBzaWduaWZpY2FudCBoaXRzIChXZSdsbCBzZXQgdGhpcyBhdCBldmFsID4gMUUtNSkKYGBge3IgZmlsdGVyLWJsYXN0LWNvbWJpbmVkfQojIEZpbHRlcgpmaWx0ZXJlZF9jb21iaW5lZF9ibGFzdG4gPC0gY29tYmluZWRfYmxhc3RuICU+JQogIGZpbHRlcihxc2VxaWQgIT0gc3NlcWlkKSAlPiUKICBmaWx0ZXIoZXZhbHVlIDwgMC4wMDAwMSkKCiMgVmlldwpucm93KGZpbHRlcmVkX2NvbWJpbmVkX2JsYXN0bikKaGVhZChmaWx0ZXJlZF9jb21iaW5lZF9ibGFzdG4pCgp3cml0ZS50YWJsZShmaWx0ZXJlZF9jb21iaW5lZF9ibGFzdG4sICIuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL2ZpbHRlcmVkX2NvbWJpbmVkX2JsYXN0LnRhYiIsIHNlcD0iXHQiLCByb3cubmFtZXM9RkFMU0UsIHF1b3RlPUZBTFNFKQpgYGAKCk9rIG5vdyB3ZSBjYW4gc3RhcnQgaWRlbnRpZnlpbmcgY29uc2VydmVkIG1pUk5Bcy4gS2VlcCBpbiBtaW5kIHRoYXQgdGhpcyBsaXN0IG9mIGZpbHRlcmVkLCBjb21iaW5lZCBibGFzdG4gaGl0cyBjb250YWlucyBkdXBsaWNhdGVzIGJlY2F1c2UsIGZvciBleGFtcGxlLCBxdWVyeWluZyBBcHVsIHNlcXVlbmNlcyBhZ2FpbnN0IGEgZGF0YWJhc2UgY29udGFpbmluZyBQZXZlIHNlcXVlbmNlcyBpcyBmdW5jdGlvbmFsbHkgdGhlIHNhbWUgYXMgcXVlcnlpbmcgdGhvc2UgUGV2ZSBzZXF1ZW5jZXMgYWdhaW5zdCBhIGRhdGFic2Ugd2hpY2ggY29udGFpbnMgQXB1bC4gU28sIGZvciBleGFtcGxlLCB0aGlzIGxpc3Qgd291bGQgY29udGFpbiBhIGhpdCBtYXRjaGluZyBBcHVsLnNlcTEgdG8gUGV2ZS5zZXEyLCAqYW5kKiBhIGhpdCBtYXRjaGluZyBQZXZlLnNlcTIgdG8gQXB1bC5zZXExLgoKCiMjIENvbnNlcnZlZCBhY3Jvc3MgYWxsIHRocmVlIHNwZWNpZXMgKEFwdWwsIFBldmUsIGFuZCBQbWVhKQoKRmlyc3QsIGxldHMgZmluZCBtaVJOQXMgY29uc2VydmVkIGFtb25nIGFsbCB0aHJlZSBzcGVjaWVzLiBUaGVzZSB3b3VsZCBzaG93IHVwIGFzIGFuIG1pUk5BIGZyb20gb25lIHNwZWNpZXMgdGhhdCBoYXMgaGl0cyBmcm9tIGJvdGggb3RoZXIgc3BlY2llcyAoZS5nLiwgQXB1bC5zZXExIGhhcyBhIGhpdCBmcm9tIFBldmUgKmFuZCogYSBoaXQgZnJvbSBQbWVhKS4KYGBge3IgaWQtY29uc2VydmVkLXRocmVlLXNwZWNpZXN9CiMgRmluZCBBcHVsIG1pUk5BcyB0aGF0IGhhdmUgbWF0Y2hlcyBmcm9tIGJvdGggUGV2ZSBhbmQgUG1lYQpwcmVzZW50X2luX2FsbCA8LSBmaWx0ZXJlZF9jb21iaW5lZF9ibGFzdG4gJT4lCiAgIyBpc29sYXRlIEFwdWwgbWlSTkFzIHdpdGggaGl0cwogIGZpbHRlcighZ3JlcGwoIlBvcml0ZXNfZXZlcm1hbml8UG9jaWxsb3BvcmFfbWVhbmRyaW5hIiwgc3NlcWlkKSkgJT4lCiAgZ3JvdXBfYnkoc3NlcWlkKSAlPiUKICBmaWx0ZXIoYW55KGdyZXBsKCJQb3JpdGVzX2V2ZXJtYW5pIiwgcXNlcWlkKSkgJiBhbnkoZ3JlcGwoIlBvY2lsbG9wb3JhX21lYW5kcmluYSIsIHFzZXFpZCkpKQoKIyBWaWV3IHRoZSBtaVJOQXMgdGhhdCBtYXRjaCBhY3Jvc3MgYWxsIHRocmVlIHNwZWNpZXMKIyAocmVjYWxsIHRoaXMgd2lsbCBpbmNsdWRlIHR3byBlbnRyaWVzIGZvciBlYWNoIGNvbnNlcnZlZCBtaVJOQSwgaXQncyBBcHVsIG1hdGNoIGluIFBldmUsIGFuZCBpdHMgQXB1bCBtYXRjaCB0byBQbWVhKQpoZWFkKHByZXNlbnRfaW5fYWxsLCBucm93KHByZXNlbnRfaW5fYWxsKSkKIAojIENvdW50IHRoZSBudW1iZXIgb2YgbWlSTkFzIGNvbnNlcnZlZCBhY3Jvc3MgYWxsIHRocmVlIHNwZWNpZXMKcGFzdGUoIk51bWJlciBvZiBtaVJOQXMgY29uc2VydmVkIGFjcm9zcyBhbGwgdGhyZWUgc3BlY2llczoiLCBucm93KGRpc3RpbmN0KHByZXNlbnRfaW5fYWxsLCBzc2VxaWQpKSkKYGBgCgojIyBDb25zZXJ2ZWQgYW1vbmcgc3Vic2V0cyBvZiB0aGUgdGhyZWUgc3BlY2llcwoKTm93IHdlIHdhbnQgdG8gZmluZCBtaVJOQXMgdGhhdCBhcmUgY29uc2VydmVkIHdpdGhpbmcgc3Vic2V0cyBvZiB0aGUgdGhyZWUgc3BlY2llcwoKIyMjIEFwdWwgYW5kIFBldmUKCkZpbmQgQXB1bCBtaVJOQXMgdGhhdCBoYXZlIGhpdHMgdG8gUGV2ZSBtaVJOQXMgYnV0ICpub3QqIGhpdHMgdG8gUG1lYSBtaVJOQXMgKHRoYXQgd291bGQgbWFrZSB0aGVtIGNvbnNlcnZlZCBhbW9uZyBhbGwgdGhyZWUgc3BlY2llcywgd2hpY2ggd2UndmUgYWxyZWFkeSBpZGVudGlmaWVkKQpgYGB7ciBpZC1jb25zZXJ2ZWQtYXB1bC1wZXZlfQojIEZpbmQgQXB1bCBtaVJOQXMgdGhhdCBoYXZlIG1hdGNoZXMgZnJvbSBvbmx5IFBldmUKcHJlc2VudF9pbl9hcHVsX3BldmUgPC0gZmlsdGVyZWRfY29tYmluZWRfYmxhc3RuICU+JQogICMgaXNvbGF0ZSBBcHVsIG1pUk5BcyB3aXRoIGhpdHMKICBmaWx0ZXIoIWdyZXBsKCJQb3JpdGVzX2V2ZXJtYW5pfFBvY2lsbG9wb3JhX21lYW5kcmluYSIsIHNzZXFpZCkpICU+JQogIGdyb3VwX2J5KHNzZXFpZCkgJT4lCiAgIyBmaWx0ZXIgZm9yIGhpdHMgdG8gUGV2ZSBvbmx5CiAgZmlsdGVyKGFueShncmVwbCgiUG9yaXRlc19ldmVybWFuaSIsIHFzZXFpZCkpICYgIWFueShncmVwbCgiUG9jaWxsb3BvcmFfbWVhbmRyaW5hIiwgcXNlcWlkKSkpCgojIFZpZXcgdGhlIG1pUk5BcyB0aGF0IG1hdGNoIGJldHdlZW4gQXB1bCBhbmQgUGV2ZQpoZWFkKHByZXNlbnRfaW5fYXB1bF9wZXZlLCBucm93KHByZXNlbnRfaW5fYXB1bF9wZXZlKSkKIAojIENvdW50IHRoZSBudW1iZXIgb2YgbWlSTkFzIGNvbnNlcnZlZCBhY3Jvc3MgdGhlIHR3byBzcGVjaWVzCnBhc3RlKCJOdW1iZXIgb2YgbWlSTkFzIGNvbnNlcnZlZCBpbiBBcHVsIGFuZCBQZXZlOiIsIG5yb3coZGlzdGluY3QocHJlc2VudF9pbl9hcHVsX3BldmUsIHNzZXFpZCkpKQpgYGAKCgojIyMgQXB1bCBhbmQgUG1lYQoKRmluZCBBcHVsIG1pUk5BcyB0aGF0IGhhdmUgaGl0cyB0byBQbWVhIG1pUk5BcyBidXQgKm5vdCogaGl0cyB0byBQZXZlIG1pUk5BcwoKYGBge3IgaWQtY29uc2VydmVkLWFwdWwtcG1lYX0KIyBGaW5kIEFwdWwgbWlSTkFzIHRoYXQgaGF2ZSBtYXRjaGVzIGZyb20gb25seSBQbWVhCnByZXNlbnRfaW5fYXB1bF9wbWVhIDwtIGZpbHRlcmVkX2NvbWJpbmVkX2JsYXN0biAlPiUKICAjIGlzb2xhdGUgQXB1bCBtaVJOQXMgd2l0aCBoaXRzCiAgZmlsdGVyKCFncmVwbCgiUG9yaXRlc19ldmVybWFuaXxQb2NpbGxvcG9yYV9tZWFuZHJpbmEiLCBzc2VxaWQpKSAlPiUKICBncm91cF9ieShzc2VxaWQpICU+JQogICMgZmlsdGVyIGZvciBoaXRzIHRvIFBtZWEgb25seQogIGZpbHRlcighYW55KGdyZXBsKCJQb3JpdGVzX2V2ZXJtYW5pIiwgcXNlcWlkKSkgJiBhbnkoZ3JlcGwoIlBvY2lsbG9wb3JhX21lYW5kcmluYSIsIHFzZXFpZCkpKQoKIyBWaWV3IHRoZSBtaVJOQXMgdGhhdCBtYXRjaCBiZXR3ZWVuIEFwdWwgYW5kIFBtZWEKaGVhZChwcmVzZW50X2luX2FwdWxfcG1lYSwgbnJvdyhwcmVzZW50X2luX2FwdWxfcG1lYSkpCiAKIyBDb3VudCB0aGUgbnVtYmVyIG9mIG1pUk5BcyBjb25zZXJ2ZWQgYWNyb3NzIHRoZSB0d28gc3BlY2llcwpwYXN0ZSgiTnVtYmVyIG9mIG1pUk5BcyBjb25zZXJ2ZWQgaW4gQXB1bCBhbmQgUG1lYToiLCBucm93KGRpc3RpbmN0KHByZXNlbnRfaW5fYXB1bF9wbWVhLCBzc2VxaWQpKSkKYGBgCgojIyMgUGV2ZSBhbmQgUG1lYQoKRmluZCBQZXZlIG1pUk5BcyB0aGF0IGhhdmUgaGl0cyB0byBQbWVhIG1pUk5BcyBidXQgKm5vdCogaGl0cyB0byBBcHVsIG1pUk5BcwoKYGBge3IgaWQtY29uc2VydmVkLXBldmUtcG1lYX0KIyBGaW5kIFBldmUgbWlSTkFzIHRoYXQgaGF2ZSBtYXRjaGVzIGZyb20gb25seSBQbWVhCnByZXNlbnRfaW5fcGV2ZV9wbWVhIDwtIGZpbHRlcmVkX2NvbWJpbmVkX2JsYXN0biAlPiUKICAjIGlzb2xhdGUgUGV2ZSBtaVJOQXMgd2l0aCBoaXRzCiAgZmlsdGVyKGdyZXBsKCJQb3JpdGVzX2V2ZXJtYW5pIiwgc3NlcWlkKSkgJT4lCiAgZ3JvdXBfYnkoc3NlcWlkKSAlPiUKICAjIGZpbHRlciBmb3IgaGl0cyB0byBQbWVhIG9ubHkgKG5vdGUgdGhlIEFwdWwgc2VxdWVuY2UgSURzIGRvbid0IGNvbnRhaW4gdGhlIHNwZWNpZXMgbmFtZSwgc28gd2UgaGF2ZSB0byB1c2UgYSBub24tZGVzY3JpcHRpdmUgdW5pcXVlIGlkZW50aWZpZXIgZm9yIGZpbHRlcmluZykKICBmaWx0ZXIoIWFueShncmVwbCgibWF0dXJlOjpOIiwgcXNlcWlkKSkgJiBhbnkoZ3JlcGwoIlBvY2lsbG9wb3JhX21lYW5kcmluYSIsIHFzZXFpZCkpKQoKIyBWaWV3IHRoZSBtaVJOQXMgdGhhdCBtYXRjaCBiZXR3ZWVuIFBldmUgYW5kIFBtZWEKaGVhZChwcmVzZW50X2luX3BldmVfcG1lYSwgbnJvdyhwcmVzZW50X2luX3BldmVfcG1lYSkpCiAKIyBDb3VudCB0aGUgbnVtYmVyIG9mIG1pUk5BcyBjb25zZXJ2ZWQgYWNyb3NzIHRoZSB0d28gc3BlY2llcwpwYXN0ZSgiTnVtYmVyIG9mIG1pUk5BcyBjb25zZXJ2ZWQgaW4gUGV2ZSBhbmQgUG1lYToiLCBucm93KGRpc3RpbmN0KHByZXNlbnRfaW5fcGV2ZV9wbWVhLCBzc2VxaWQpKSkKYGBgCgoKIyMgVmlzdWFsaXplCgojIyMgRGF0YSBtdW5naW5nIG9mIHRoZSByZXN1bHRzCgpgYGB7ciBncmFiLWZhc3RhLWhlYWRlcnMsIGVuZ2luZT0nYmFzaCd9CmNkIC4uL2RhdGEvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uCmdyZXAgIl4+IiAgbWVyZ2VkX2FsbF9TaG9ydFN0YWNrX21hdHVyZS5mYXN0YSB8IHNlZCAncy9ePi8vJyA+IG1lcmdlZF9hbGxfU2hvcnRTdGFja19tYXR1cmVfSURzLnR4dAoKaGVhZCAtNSBtZXJnZWRfYWxsX1Nob3J0U3RhY2tfbWF0dXJlX0lEcy50eHQKYGBgCgpgYGB7ciBzZXBhcmF0ZS1pZHMtYnktc3BlY2llc30KIyBSZWFkIGluIGFuZCBzZXBhcmF0ZSB0aGUgaWRzIG9mIGFsbCBtaVJOQXMgZnJvbSB0aGUgdGhyZWUgc3BlY2llcwptZXJnZWRfSURzIDwtIHJlYWRMaW5lcygiLi4vZGF0YS8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vbWVyZ2VkX2FsbF9TaG9ydFN0YWNrX21hdHVyZV9JRHMudHh0IikKCmFwdWxfSURzIDwtIG1lcmdlZF9JRHNbZ3JlcCgibWF0dXJlOjpOIiwgbWVyZ2VkX0lEcyldCnBldmVfSURzIDwtIG1lcmdlZF9JRHNbZ3JlcCgiUG9yaXRlc19ldmVybWFuaSIsIG1lcmdlZF9JRHMpXQpwbWVhX0lEcyA8LSBtZXJnZWRfSURzW2dyZXAoIlBvY2lsbG9wb3JhX21lYW5kcmluYSIsIG1lcmdlZF9JRHMpXQpsZW5ndGgoYXB1bF9JRHMpCmxlbmd0aChwZXZlX0lEcykKbGVuZ3RoKHBtZWFfSURzKQpgYGAKCmBgYHtyIGNyZWF0ZS1zaGFyZWQtY29uc2VydmVkLWlkc30KIyBBc3NpZ24gc2hhcmVkIG1pUk5BIElEcyB0byBjb25zZXJ2ZWQgbWlSTkFzCgojIEZ1bmN0aW9uIHRvIGFwcGVuZCBJRHMgb2YgbWF0Y2hpbmcgbWlSTkFzIHRvIHRoZSBvcmlnaW5hbCBxdWVyeSBtaVJOQQphcHBlbmRfSURzIDwtIGZ1bmN0aW9uKElEc19saXN0LCBkZikgewogIGFwcGVuZGVkX0lEc19saXN0IDwtIHZlY3RvcigibGlzdCIsIGxlbmd0aChJRHNfbGlzdCkpCiAgZm9yIChpIGluIHNlcV9hbG9uZyhJRHNfbGlzdCkpIHsKICAgIG1hdGNoaW5nX2VudHJpZXMgPC0gZGYkcXNlcWlkW2RmJHNzZXFpZCA9PSBJRHNfbGlzdFtpXV0KICAgIGlmIChsZW5ndGgobWF0Y2hpbmdfZW50cmllcykgPiAwKSB7CiAgICAgIGFwcGVuZGVkX0lEc19saXN0W1tpXV0gPC0gcGFzdGUoSURzX2xpc3RbaV0sIHBhc3RlKG1hdGNoaW5nX2VudHJpZXMsIGNvbGxhcHNlID0gInwiKSwgc2VwID0gInwiKQogICAgfSBlbHNlIHsKICAgICAgYXBwZW5kZWRfSURzX2xpc3RbW2ldXSA8LSBJRHNfbGlzdFtpXQogICAgfQogIH0KICByZXR1cm4oYXBwZW5kZWRfSURzX2xpc3QpCn0KCiMgQXBwbHkgdGhlIGZ1bmN0aW9uIHRvIGVhY2ggc2V0IG9mIGNvbnNlcnZlZCBtaVJOQXMKYXBwZW5kZWRJRHNfYXB1bF9wZXZlX3BtZWEgPC0gYXBwZW5kX0lEcyh1bmlxdWUocHJlc2VudF9pbl9hbGwkc3NlcWlkKSwgcHJlc2VudF9pbl9hbGwpCgphcHBlbmRlZElEc19hcHVsX3BldmUgPC0gYXBwZW5kX0lEcyh1bmlxdWUocHJlc2VudF9pbl9hcHVsX3BldmUkc3NlcWlkKSwgcHJlc2VudF9pbl9hcHVsX3BldmUpCmFwcGVuZGVkSURzX2FwdWxfcG1lYSA8LSBhcHBlbmRfSURzKHVuaXF1ZShwcmVzZW50X2luX2FwdWxfcG1lYSRzc2VxaWQpLCBwcmVzZW50X2luX2FwdWxfcG1lYSkKYXBwZW5kZWRJRHNfcGV2ZV9wbWVhIDwtIGFwcGVuZF9JRHModW5pcXVlKHByZXNlbnRfaW5fcGV2ZV9wbWVhJHNzZXFpZCksIHByZXNlbnRfaW5fcGV2ZV9wbWVhKQoKcHJpbnQoYXBwZW5kZWRJRHNfYXB1bF9wZXZlX3BtZWFbMV0pCnByaW50KGFwcGVuZGVkSURzX2FwdWxfcGV2ZSkKcHJpbnQoYXBwZW5kZWRJRHNfYXB1bF9wbWVhKQpwcmludChhcHBlbmRlZElEc19wZXZlX3BtZWEpCgojIGNvbWJpbmUgdGhlIG5ldyBhcHBlbmRlZCBJRHMgaW50byBhIHNpbmdsZSBsaXN0IG9mIGNvbnNlcnZlZCBtaVJOQXMKY29uc2VydmVkX21pUk5Bc19hbGxfSURzIDwtIGMoYXBwZW5kZWRJRHNfYXB1bF9wZXZlX3BtZWEsIGFwcGVuZGVkSURzX2FwdWxfcGV2ZSwgYXBwZW5kZWRJRHNfYXB1bF9wbWVhLCBhcHBlbmRlZElEc19wZXZlX3BtZWEpCmBgYAoKYGBge3IgcmVwbGFjZS1lbnRyaWVzfQojIEZvciBlYWNoIHNwZWNpZXMgbGlzdCBvZiBtaVJOQSBJRHMsIHJlcGxhY2Ugc3BlY2llcy1zcGVjaWZpYyBJRHMgb2YgY29uc2VydmVkIG1pUk5BcyB3aXRoIG91ciBuZXdseSBnZW5lcmF0ZWQgYXBwZW5kZWQgSURzLiBUaGlzIHdpbGwgY3JlYXRlZCBsaXN0cyBvZiBtaVJOQSBJRHMgdGhhdCBoYXZlIHNoYXJlZCBJRHMgZm9yIHRoZSBjb25zZXJ2ZWQgbVJOQXMKcmVwbGFjZV9lbnRyaWVzIDwtIGZ1bmN0aW9uKHNwZWNfbGlzdCwgbmV3X2NvbnNlcnZlZF9JRHMpIHsKICAjIEl0ZXJhdGUgb3ZlciBlYWNoIGVudHJ5IGluIHNwZWNfbGlzdAogIGZvciAoaSBpbiBzZXFfYWxvbmcoc3BlY19saXN0KSkgewogICAgIyBDaGVjayBpZiB0aGUgY3VycmVudCBlbnRyeSBpbiBzcGVjX2xpc3QgZXhpc3RzIGluIGFueSBlbnRyeSBpbiBuZXdfY29uc2VydmVkX0lEcwogICAgbWF0Y2hpbmdfZW50cnkgPC0gbmV3X2NvbnNlcnZlZF9JRHNbZ3JlcChzcGVjX2xpc3RbaV0sIG5ld19jb25zZXJ2ZWRfSURzLCBmaXhlZCA9IFRSVUUpXQogICAgIyBJZiBhIG1hdGNoIGlzIGZvdW5kLCByZXBsYWNlIHRoZSBlbnRyeSBpbiBzcGVjX2xpc3Qgd2l0aCB0aGUgbWF0Y2hpbmcgZW50cnkgZnJvbSBuZXdfY29uc2VydmVkX0lEcwogICAgaWYgKGxlbmd0aChtYXRjaGluZ19lbnRyeSkgPiAwKSB7CiAgICAgIHNwZWNfbGlzdFtpXSA8LSBtYXRjaGluZ19lbnRyeVtbMV1dICAjIFJlcGxhY2Ugd2l0aCB0aGUgZmlyc3QgZWxlbWVudCBvZiBtYXRjaGluZ19lbnRyeQogICAgfQogIH0KICByZXR1cm4oc3BlY19saXN0KSAgIyBSZXR1cm4gdGhlIG1vZGlmaWVkIHNwZWNfbGlzdAp9CgphcHVsX21hdHVyZV9uZXdjb25zZXJ2ZWRJRCA8LSByZXBsYWNlX2VudHJpZXMoYXB1bF9JRHMsIGNvbnNlcnZlZF9taVJOQXNfYWxsX0lEcykKcGV2ZV9tYXR1cmVfbmV3Y29uc2VydmVkSUQgPC0gcmVwbGFjZV9lbnRyaWVzKHBldmVfSURzLCBjb25zZXJ2ZWRfbWlSTkFzX2FsbF9JRHMpCnBtZWFfbWF0dXJlX25ld2NvbnNlcnZlZElEIDwtIHJlcGxhY2VfZW50cmllcyhwbWVhX0lEcywgY29uc2VydmVkX21pUk5Bc19hbGxfSURzKQpgYGAKCgojIyMgVmVubiBkaWFncmFtCgpgYGB7ciB2ZW5uLWRpYWdyYW19CiMgTm90ZSB0aGF0IG10T1JGIGRhdGEgaW5kaWNhdGVzIG91ciBQLm1lYW5kcmluYSBzYW1wbGVzIGFyZSBhY3R1YWxseSBQLnR1YWhpbmllbnNpcywgc28gdGhhdCdzIHRoZSBzcGVjaWVzIG5hbWUgd2UnbGwgYmUgdXNpbmcgaW4gZmlndXJlcwphIDwtIGxpc3QoIkEuIHB1bGNocmEiID0gYXB1bF9tYXR1cmVfbmV3Y29uc2VydmVkSUQsIAogICAgICAgICAgIlAuIGV2ZXJtYW5uaSIgPSBwZXZlX21hdHVyZV9uZXdjb25zZXJ2ZWRJRCwKICAgICAgICAgICJQLiB0dWFoaW5pZW5zaXMiID0gcG1lYV9tYXR1cmVfbmV3Y29uc2VydmVkSUQpCgp2ZW5uX2NvbnNlcnZlZCA8LSBnZ3Zlbm4oYSwgc2hvd19wZXJjZW50YWdlID0gRkFMU0UsIGZpbGxfY29sb3IgPSBzcGVjaWVzX2NvbG9yc19ub2xhYmVsKQp2ZW5uX2NvbnNlcnZlZAoKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9maWd1cmVzL3Zlbm5fY29uc2VydmVkX21pUk5BLnBuZyIsCiAgICAgICAgIHBsb3QgICA9IHZlbm5fY29uc2VydmVkLAogICAgICAgICByZXMgICAgPSA2MDAsCiAgICAgICAgIHdpZHRoICA9IDUwMDAsCiAgICAgICAgIGhlaWdodCA9IDUwMDApCgpnZ2V4cG9ydChmaWxlbmFtZSA9ICIuLi8uLi9zdXBwbGVtZW50YWwvbWlSTkEvdmVubl9jb25zZXJ2ZWRfbWlSTkEucG5nIiwKICAgICAgICAgcGxvdCAgID0gdmVubl9jb25zZXJ2ZWQsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKYGBgCgoKIyBDb21wYXJlIHNlcXVlbmNlIHNpbWlsYXJpdHkgYWNyb3NzIGFsbCBzcGVjaWVzCkFsaWduZWQgYWxsIG1hdHVyZSBtaVJOQSBzZXF1ZW5jZXMgZnJvbSBhbGwgdGhyZWUgc3BlY2llcyBpbiBNRUdBIHVzaW5nIE1VU0NMRSwgdGhlbiBnZW5lcmF0ZWQgcGFpcndpc2UgZGlzdGFuY2UgbWF0cml4IAoKYGBge3IgZm9ybWF0LWRpc3RhbmNlLW1hdHJpeCwgZW5naW5lPSdiYXNoJ30KIyBSZW1vdmUgZGVzY3JpcHRpb24gdGV4dCBhdCBib3R0b20gb2YgZmlsZQpoZWFkIC0xMjEgLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9tYXR1cmVfbWlSTkFfYWxsX3RvX2FsbF9kaXN0YW5jZV8wNjA2MjAyNC5jc3YgPiAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL21hdHVyZV9taVJOQV9hbGxfdG9fYWxsX2Rpc3RhbmNlXzA2MDYyMDI0X25vZGVzY3JpcHRpb24uY3N2CgojIEZvciBzb21lIHJlYXNvbiB0aGUgbGFzdCBsaW5lIHdhcyBzYXZlZCBhcyBqdXN0IHRoZSByb3cgbmFtZSwgd2l0aCBubyBjb21tYS1kZWxpbWl0YXRpb24gdG8gbWFyayBlYWNoIGVtcHR5IGNvbHVtbi4gV2UgbmVlZCB0byByZWludHJvZHVjZSB0aGUgKGVtcHR5KSBjb21tYS1kZWxpbWl0ZWQgY29sdW1ucyBpbiB0aGUgZmluYWwgcm93LgojIENyZWF0ZSB0aGUgc3RyaW5nIG9mIGNvbW1hcwphcHBlbmRfc3RyaW5nPSQocHJpbnRmICcsICUuMHMnIHsxLi4xMjF9KQoKIyBSZW1vdmUgdGhlIGxhc3QgY29tbWEgYW5kIGFkZCBhIHNwYWNlIGF0IHRoZSBlbmQKYXBwZW5kX3N0cmluZz0iJHthcHBlbmRfc3RyaW5nJSx9IgoKIyBVc2Ugc2VkIHRvIHJlbW92ZSBleGlzdGluZyB0cmFpbGluZyB3aGl0ZXNwYWNlIGFuZCB0aGVuIGFwcGVuZCB0aGUgc3RyaW5nIG9mIGNvbW1hcyB0byByb3cgMTIwCnNlZCAtaSAncy9ccyokLy8nIC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vbWF0dXJlX21pUk5BX2FsbF90b19hbGxfZGlzdGFuY2VfMDYwNjIwMjRfbm9kZXNjcmlwdGlvbi5jc3YKc2VkIC1pICcxMjFzLyQvICciJGFwcGVuZF9zdHJpbmciJy8nIC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vbWF0dXJlX21pUk5BX2FsbF90b19hbGxfZGlzdGFuY2VfMDYwNjIwMjRfbm9kZXNjcmlwdGlvbi5jc3YKCiMgTUVHQSBzb21ldGltZXMgY2FuJ3QgY29tcHV0ZSBhIHBhaXJ3aXNlIGRpc3RhbmNlIGZvciBzdGF0aXN0aWNhbCByZWFzb25zLCBhbmQgdGhlc2UgYXJlIG5vdGVkIGluIHRoZSBmaWxlIGFzICI/IiBlbnRyaWVzLiBNRUdBIGRvY3VtZW50YXRpb24gaW5kaWNhdGVzIHRoaXMgbm90YXRpb24gaXMgYXNzb2NpYXRlZCB3aXRoIGJlaW5nIHVuYWJsZSB0byBpZGVudGlmeSBhbnkgc2hhcmVkIHNpdGVzIChpLmUuLCB0aGUgc2VxdWVuY2VzIGFyZSB0b28gZGlmZmVyZW50IHRvIGV2ZW4gY29tcGFyZSkuIE5vbi1udW1lcmljIGVudHJpZXMgd2lsbCBtZXNzIHdpdGggb3VyIGFuYWx5c2lzIGRvd24gdGhlIGxpbmUsIHNvIHdlIG5lZWQgdG8gcmVwbGFjZSB0aG9zZS4gU2luY2UgdGhleSdyZSBhc3NvY2lhdGVkIHdpdGggbm8gc2hhcmVkIHNpdGVzLCB3ZSdsbCByZXBsYWNlIHRoZW0gd2l0aCAxcyAoaW5kaWNhdGluZyB2ZXJ5IGhpZ2ggc2VxdWVuY2UgZGlzdGFuY2UpLgojIFJlcGxhY2UgYWxsICI/IiBlbnRyaWVzIHdpdGggMXMKc2VkIC1pICdzLz8vMS9nJyAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL21hdHVyZV9taVJOQV9hbGxfdG9fYWxsX2Rpc3RhbmNlXzA2MDYyMDI0X25vZGVzY3JpcHRpb24uY3N2CgpgYGAKCmBgYHtyIGZvcm1hdC1kaXN0YW5jZS1tYXRyaXgtY29udH0KIyBsb2FkIGRhdGEKYWxsX3RvX2FsbCA8LSByZWFkLnRhYmxlKCIuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL21hdHVyZV9taVJOQV9hbGxfdG9fYWxsX2Rpc3RhbmNlXzA2MDYyMDI0X25vZGVzY3JpcHRpb24uY3N2Iiwgc2VwPSIsIiwgaGVhZGVyID0gRkFMU0UsIG5hLnN0cmluZ3MgPSAiIikKCiMgQXNzaWduIGNvbHVtbiAxIGVudHJpZXMgdG8gcm93IG5hbWVzIGFuZCBjb2x1bW4gbmFtZXMgKHBhaXJ3aXNlIG1hdHJpY2VzIGhhdmUgaWRlbnRpY2FsIHJvdyBhbmQgY29sdW1uIG5hbWVzKQpyb3duYW1lcyhhbGxfdG9fYWxsKSA8LSBhbGxfdG9fYWxsWywgMV0KYWxsX3RvX2FsbCA8LSBhbGxfdG9fYWxsWywgLTFdCmNvbG5hbWVzKGFsbF90b19hbGwpIDwtIHJvd25hbWVzKGFsbF90b19hbGwpCgojIENvbnZlcnQgdGhpcyB1cHBlciB0cmlhbmd1bGFyIG1hdHJpeCB0byBhIGZ1bGwsIHN5bW1ldHJpYyBkaXN0YW5jZSBtYXRyaXgKYWxsX3RvX2FsbF9mdWxsIDwtIHQoYWxsX3RvX2FsbCkKYWxsX3RvX2FsbF9mdWxsW3VwcGVyLnRyaShhbGxfdG9fYWxsX2Z1bGwpXSA8LSBhbGxfdG9fYWxsW3VwcGVyLnRyaShhbGxfdG9fYWxsKV0KIyBDaGVjayB0aGUgbmV3IGRpc3RhbmNlIG1hdHJpeCBpcyBzeW1tZXRyaWMKaXNTeW1tZXRyaWMoYWxsX3RvX2FsbF9mdWxsKQoKIyBDb252ZXJ0IG1hdHJpeCBiYWNrIHRvIGRhdGEgZnJhbWUKYWxsX3RvX2FsbF9mdWxsIDwtIGFzLmRhdGEuZnJhbWUoYWxsX3RvX2FsbF9mdWxsKQoKCiMgUmVwbGFjZSB0aGUgIk5BIiB2YWx1ZXMgd2l0aCAwcyAoYWxvbmcgdGhlIGF4aXMpCmFsbF90b19hbGxfZnVsbCA8LSByZXBsYWNlKGFsbF90b19hbGxfZnVsbCwgaXMubmEoYWxsX3RvX2FsbF9mdWxsKSwgMCkKYGBgCgpgYGB7ciBhbm5vdGF0ZS1zcGVjaWVzLW5hbWUsIGVuZ2luZT0nYmFzaCd9CmNkIC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24KIyBJc29sYXRlIHNlcXVlbmNlIG5hbWVzCmF3ayAtRiAnLCcgJ3twcmludCAkMX0nIG1hdHVyZV9taVJOQV9hbGxfdG9fYWxsX2Rpc3RhbmNlXzA2MDYyMDI0X25vZGVzY3JpcHRpb24uY3N2ID4gbWlSTkFfbmFtZXMudHh0CgojIEFkZCBmdWxsIHNwZWNpZXMgbmFtZSBpbiBzZWNvbmQgY29sdW1uIGJhc2VkIG9uIHRoZSBzZXEgSUQKIyBOb3RlIHRoYXQgbXRPUkYgZGF0YSBpbmRpY2F0ZXMgb3VyIFAubWVhbmRyaW5hIHNhbXBsZXMgYXJlIGFjdHVhbGx5IFAudHVhaGluaWVuc2lzLCBzbyB0aGF0J3MgdGhlIHNwZWNpZXMgbmFtZSB3ZSdsbCBiZSB1c2luZyBpbiBmaWd1cmVzCnNlZCAtaSAncy9ccyokLy8nIG1pUk5BX25hbWVzLnR4dApzZWQgJy9tYXR1cmU6Ok4vcy8kLyxBX3B1bGNocmEvJyBtaVJOQV9uYW1lcy50eHQgPiBtaVJOQV9zcGVjaWVzLmNzdgpzZWQgLWkgJy9tYXR1cmU6OlBvcml0ZXMvcy8kLyxQX2V2ZXJtYW5uaS8nIG1pUk5BX3NwZWNpZXMuY3N2CnNlZCAtaSAnL21hdHVyZTo6UG9jaWxsb3BvcmEvcy8kLyxQX3R1YWhpbmllbnNpcy8nIG1pUk5BX3NwZWNpZXMuY3N2CmBgYAoKYGBge3Igc3BlY2llcy1saXN0fQojIFJlYWQgaW4KbWlSTkFfc3BlY2llcyA8LSByZWFkLmNzdigiLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9taVJOQV9zcGVjaWVzLmNzdiIsIGhlYWRlciA9IEZBTFNFKQoKIyBNYWtlIHRoZSBtaVJOQSBsYWJlbHMgcm93IG5hbWVzCmNvbG5hbWVzKG1pUk5BX3NwZWNpZXMpIDwtIGMoIm1pUk5BX0lEIiwgIlNwZWNpZXMiKQpyb3duYW1lcyhtaVJOQV9zcGVjaWVzKSA8LSBtaVJOQV9zcGVjaWVzWywgIm1pUk5BX0lEIl0KCmBgYAoKIyMgUENvQQoKIFByaW5jaXBhbCBDb29yZGluYXRlcyBBbmFseXNpcyAtLSBzaW1pbGFyIHRvIFBDQSwgYnV0IGNhbiB0YWtlIGEgZGlzdGFuY2UgbWF0cml4IGFzIGlucHV0CiAKYGBge3IgcGNvYS1wbG90fQpwY29hIDwtIHBjb2EoYWxsX3RvX2FsbF9mdWxsLCBjb3JyZWN0aW9uPSJub25lIiwgcm49TlVMTCkKcGNvYV92ZWMgPC0gYXMuZGF0YS5mcmFtZShwY29hJHZlY3RvcnMpCnBjb2FfdmVjJHJvd25hbWVzIDwtIHJvd25hbWVzKHBjb2FfdmVjKQpwY29hX3ZlYyA8LSBtdXRhdGUocGNvYV92ZWMsIHJvd25hbWVzID0gdHJpbXdzKGFzLmNoYXJhY3Rlcihyb3duYW1lcykpKQpwY29hX3ZlY19hbm5vdCA8LSBsZWZ0X2pvaW4ocGNvYV92ZWMsIG1pUk5BX3NwZWNpZXMsIGJ5ID0gYygicm93bmFtZXMiID0gIm1pUk5BX0lEIikpCnJvd25hbWVzKHBjb2FfdmVjX2Fubm90KSA8LSBwY29hX3ZlY19hbm5vdCRyb3duYW1lcwoKcGVyY2VudF92YXIgPC0gcm91bmQocGNvYVtbInZhbHVlcyJdXVtbIlJlbGF0aXZlX2VpZyJdXSoxMDApCgojIE5vdGUgdGhhdCBtdE9SRiBkYXRhIGluZGljYXRlcyBvdXIgUC5tZWFuZHJpbmEgc2FtcGxlcyBhcmUgYWN0dWFsbHkgUC50dWFoaW5pZW5zaXMsIHNvIHRoYXQncyB0aGUgc3BlY2llcyBuYW1lIHdlJ2xsIGJlIHVzaW5nIGluIGZpZ3VyZXMKcGNvYV9wbG90IDwtIGdncGxvdChwY29hX3ZlY19hbm5vdCwgYWVzKEF4aXMuMSwgQXhpcy4yLCBjb2xvciA9IFNwZWNpZXMpKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDQsIGFscGhhID0gLjUpICsKICBnZ3RpdGxlKCJQQ29BIG9mIG1hdHVyZSBtaVJOQSBwYWlyd2lzZSBnZW5ldGljIGRpc3RhbmNlIChhbGwgdG8gYWxsKSIpICsKICB4bGFiKHBhc3RlMCgiUEMxOiAiLHBlcmNlbnRfdmFyWzFdLCIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLHBlcmNlbnRfdmFyWzJdLCIlIHZhcmlhbmNlIikpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHNwZWNpZXNfY29sb3JzKSArCiAgY29vcmRfZml4ZWQoKSArCiAgc3RhdF9lbGxpcHNlKCkKCnBjb2FfcGxvdAoKIyBTYXZlIHBsb3QKZ2dleHBvcnQoZmlsZW5hbWUgPSAiLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9maWd1cmVzL1BDb0FfYWxsX3NwZWNpZXNfc2VxdWVuY2Vfc2ltaWxhcml0eS5wbmciLAogICAgICAgICBwbG90ICAgPSBwY29hX3Bsb3QsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKCmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uLy4uL3N1cHBsZW1lbnRhbC9taVJOQS9QQ29BX2FsbF9zcGVjaWVzX3NlcXVlbmNlX3NpbWlsYXJpdHkucG5nIiwKICAgICAgICAgcGxvdCAgID0gcGNvYV9wbG90LAogICAgICAgICByZXMgICAgPSA2MDAsCiAgICAgICAgIHdpZHRoICA9IDUwMDAsCiAgICAgICAgIGhlaWdodCA9IDUwMDApCmBgYAoKIyMgSGVhdG1hcAoKYGBge3IgaGVhdG1hcC1wbG90fQojICMgQW5ub3RhdGUgaGVhdG1hcApzcGVjSUQgPC0gbWlSTkFfc3BlY2llcyAlPiUgCiAgc2VsZWN0KFNwZWNpZXMpCgphbGxfdG9fYWxsX2Z1bGxfc2hvcnRuYW1lcyA8LSBhbGxfdG9fYWxsX2Z1bGwKY29sbmFtZXMoYWxsX3RvX2FsbF9mdWxsX3Nob3J0bmFtZXMpIDwtIHN1YnN0cihjb2xuYW1lcyhhbGxfdG9fYWxsX2Z1bGwpLCAxLCAyMCkKcm93bmFtZXMoYWxsX3RvX2FsbF9mdWxsX3Nob3J0bmFtZXMpIDwtIGNvbG5hbWVzKGFsbF90b19hbGxfZnVsbF9zaG9ydG5hbWVzKQoKIyBSdW4gcGhlYXRtYXAKYWxsLnNwZWMuc2Vxc2ltLmhlYXQgPC0gcGhlYXRtYXAoYWxsX3RvX2FsbF9mdWxsX3Nob3J0bmFtZXMsIAogICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBULCAKICAgICAgICAgICAgICAgICAgICAgc2hvd19yb3duYW1lcyA9IFQsCiAgICAgICAgICAgICAgICAgICAgIGFubm90YXRpb24gPSBzcGVjSUQsIAogICAgICAgICAgICAgICAgICAgICBib3JkZXJfY29sb3IgPSBOQSwgCiAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplID0gNSwgCiAgICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX3JvdyA9IDUsIAogICAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSAyMCkKCiMgU2F2ZSBwbG90CmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vZmlndXJlcy9oZWF0bWFwX2FsbF9zcGVjaWVzX3NlcXVlbmNlX3NpbWlsYXJpdHkucG5nIiwKICAgICAgICAgcGxvdCAgID0gYWxsLnNwZWMuc2Vxc2ltLmhlYXQsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKCmdnZXhwb3J0KGZpbGVuYW1lID0gIi4uLy4uL3N1cHBsZW1lbnRhbC9taVJOQS9oZWF0bWFwX2FsbF9zcGVjaWVzX3NlcXVlbmNlX3NpbWlsYXJpdHkucG5nIiwKICAgICAgICAgcGxvdCAgID0gYWxsLnNwZWMuc2Vxc2ltLmhlYXQsCiAgICAgICAgIHJlcyAgICA9IDYwMCwKICAgICAgICAgd2lkdGggID0gNTAwMCwKICAgICAgICAgaGVpZ2h0ID0gNTAwMCkKYGBgCgojIElkZW50aWZ5IG1pUk5BcyB3aXRoIGlkZW50aWNhbCBtYXR1cmUgbWlSTkFzCgpJdCdzIHBvc3NpYmxlIGZvciBpZGVudGljYWwgbWF0dXJlIG1pUk5BcyB0byBhcmlzZSBmcm9tIG5vbi1pZGVudGljYWwgcHJlY3Vyc29yIG1pUk5Bcy4gVGhlc2Ugd291bGQgYmUgY2xhc3NpZmllZCBieSBTaG9ydFN0YWNrIGFzIGRpZmZlcmVudCBtaVJOQXMsIGJ1dCBjb3VsZCBzdGlsbCBoYXZlIHNpbWlsYXIvaWRlbnRpY2FsIGZ1bmN0aW9ucy4gTGV0J3Mgc2VlIGlmIHdlIGhhdmUgYW55IG9mIHRob3NlIGluIG91ciBkYXRhLgoKV2UndmUgYWxyZWFkeSBlbGltaW5hdGVkIGluc3RhbmNlcyBvZiBtaVJOQXMgbWF0Y2hpbmcgdG8gdGhlbXNlbHZlcywgc28gdG8gaWRlbnRpZnkgZGlzdGluY3QgbWlSTkFzIGZyb20gd2l0aCBpZGVudGljYWwgbWF0dXJlIHNlcXVlbmNlcyB3ZSBjYW4ganVzdCBsb29rIGZvciBoaXRzIHdpdGhpbiB0aGUgc2FtZSBzcGVjaWVzIChlLmcuIEFwdWwuc2VxMSBtYXRjaGluZyBBcHVsLnNlcTQpCgojIyBBcHVsCgpgYGB7ciBhcHVsLWlkZW50aWNhbC1taXJuYX0KIyBJZGVudGlmeSBzZXRzIG9mIGlkZW50aWNhbCBtaVJOQXMKYXB1bF9pZGVudGljYWxfbWlSTkFzIDwtIGZpbHRlcmVkX2NvbWJpbmVkX2JsYXN0biAlPiUKICBmaWx0ZXIoZ3JlcGwoIm1hdHVyZTo6TiIsIHNzZXFpZCkpICU+JQogIGZpbHRlcihncmVwbCgibWF0dXJlOjpOIiwgcXNlcWlkKSkKICAgICAgICAgCmhlYWQoYXB1bF9pZGVudGljYWxfbWlSTkFzKQoKIyBTYXZlCndyaXRlLnRhYmxlKGFwdWxfaWRlbnRpY2FsX21pUk5BcywgIi4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vQXB1bF9pZGVudGljYWxfbWlSTkFzLnRhYiIsIHNlcD0iXHQiLCByb3cubmFtZXMgPSBGQUxTRSwgY29sLm5hbWVzID0gVFJVRSkKYGBgCgpgYGB7ciBhcHVsLWlkZW50aWNhbC1maXJzdCwgZW5naW5lPSdiYXNoJ30KIyBGaXJzdCBwYWlyCmhlYWQgLTIgLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9BcHVsX2lkZW50aWNhbF9taVJOQXMudGFiIHwgdGFpbCAtMQoKc2VxMT0kKGF3ayAnTlI9PTIge3ByaW50ICQxfScgRlM9J1x0JyAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL0FwdWxfaWRlbnRpY2FsX21pUk5Bcy50YWIgfCBzZWQgJ3MvLm1hdHVyZTo6LiovLycgfCBzZWQgJ3MvIi8vZycpCnNlcTI9JChhd2sgJ05SPT0yIHtwcmludCAkMn0nIEZTPSdcdCcgLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9BcHVsX2lkZW50aWNhbF9taVJOQXMudGFiIHwgc2VkICdzLy5tYXR1cmU6Oi4qLy8nIHwgc2VkICdzLyIvL2cnKQoKZWNobyAiIgplY2hvICRzZXExCmVjaG8gJHNlcTIKZWNobyAiIgoKIyBncmFiIHRoZSBwcmVjdXJzb3IsIHN0YXIsIGFuZCBtYXR1cmUgZmFzdGEgc2VxdWVuY2VzIGZvciB0aGUgdHdvIG1pUk5Bcwphd2sgLXYgc2VxPSIkc2VxMSIgJ0JFR0lOIHtSUz0iPiI7IEZTPSJcbiJ9ICQxIH4gc2VxIHtwcmludCAiPiIkMH0nIC4uLy4uL0QtQXB1bC9vdXRwdXQvMTMuMi4xLUFwdWwtc1JOQXNlcS1TaG9ydFN0YWNrLTMxYnAtZmFzdHAtbWVyZ2VkLWNuaWRhcmlhbl9taVJCYXNlL1Nob3J0U3RhY2tfb3V0L21pci5mYXN0YQoKYXdrIC12IHNlcT0iJHNlcTIiICdCRUdJTiB7UlM9Ij4iOyBGUz0iXG4ifSAkMSB+IHNlcSB7cHJpbnQgIj4iJDB9JyAuLi8uLi9ELUFwdWwvb3V0cHV0LzEzLjIuMS1BcHVsLXNSTkFzZXEtU2hvcnRTdGFjay0zMWJwLWZhc3RwLW1lcmdlZC1jbmlkYXJpYW5fbWlSQmFzZS9TaG9ydFN0YWNrX291dC9taXIuZmFzdGEKYGBgCgpgYGB7ciBhcHVsLWlkZW50aWNhbC1zZWNvbmQsIGVuZ2luZT0nYmFzaCd9CiMgU2Vjb25kIHBhaXIKaGVhZCAtMyAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL0FwdWxfaWRlbnRpY2FsX21pUk5Bcy50YWIgfCB0YWlsIC0xCgpzZXExPSQoYXdrICdOUj09MyB7cHJpbnQgJDF9JyBGUz0nXHQnIC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vQXB1bF9pZGVudGljYWxfbWlSTkFzLnRhYiB8IHNlZCAncy8ubWF0dXJlOjouKi8vJyB8IHNlZCAncy8iLy9nJykKc2VxMj0kKGF3ayAnTlI9PTMge3ByaW50ICQyfScgRlM9J1x0JyAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL0FwdWxfaWRlbnRpY2FsX21pUk5Bcy50YWIgfCBzZWQgJ3MvLm1hdHVyZTo6LiovLycgfCBzZWQgJ3MvIi8vZycpCgplY2hvICIiCmVjaG8gJHNlcTEKZWNobyAkc2VxMgplY2hvICIiCgojIGdyYWIgdGhlIHByZWN1cnNvciwgc3RhciwgYW5kIG1hdHVyZSBmYXN0YSBzZXF1ZW5jZXMgZm9yIHRoZSB0d28gbWlSTkFzCmF3ayAtdiBzZXE9IiRzZXExIiAnQkVHSU4ge1JTPSI+IjsgRlM9IlxuIn0gJDEgfiBzZXEge3ByaW50ICI+IiQwfScgLi4vLi4vRC1BcHVsL291dHB1dC8xMy4yLjEtQXB1bC1zUk5Bc2VxLVNob3J0U3RhY2stMzFicC1mYXN0cC1tZXJnZWQtY25pZGFyaWFuX21pUkJhc2UvU2hvcnRTdGFja19vdXQvbWlyLmZhc3RhCgphd2sgLXYgc2VxPSIkc2VxMiIgJ0JFR0lOIHtSUz0iPiI7IEZTPSJcbiJ9ICQxIH4gc2VxIHtwcmludCAiPiIkMH0nIC4uLy4uL0QtQXB1bC9vdXRwdXQvMTMuMi4xLUFwdWwtc1JOQXNlcS1TaG9ydFN0YWNrLTMxYnAtZmFzdHAtbWVyZ2VkLWNuaWRhcmlhbl9taVJCYXNlL1Nob3J0U3RhY2tfb3V0L21pci5mYXN0YQpgYGAKCmBgYHtyIGFwdWwtaWRlbnRpY2FsLXRoaXJkLCBlbmdpbmU9J2Jhc2gnfQojIFRoaXJkIHBhaXIKaGVhZCAtNCAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL0FwdWxfaWRlbnRpY2FsX21pUk5Bcy50YWIgfCB0YWlsIC0xCgpzZXExPSQoYXdrICdOUj09NCB7cHJpbnQgJDF9JyBGUz0nXHQnIC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vQXB1bF9pZGVudGljYWxfbWlSTkFzLnRhYiB8IHNlZCAncy8ubWF0dXJlOjouKi8vJyB8IHNlZCAncy8iLy9nJykKc2VxMj0kKGF3ayAnTlI9PTQge3ByaW50ICQyfScgRlM9J1x0JyAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL0FwdWxfaWRlbnRpY2FsX21pUk5Bcy50YWIgfCBzZWQgJ3MvLm1hdHVyZTo6LiovLycgfCBzZWQgJ3MvIi8vZycpCgplY2hvICIiCmVjaG8gJHNlcTEKZWNobyAkc2VxMgplY2hvICIiCgojIGdyYWIgdGhlIHByZWN1cnNvciwgc3RhciwgYW5kIG1hdHVyZSBmYXN0YSBzZXF1ZW5jZXMgZm9yIHRoZSB0d28gbWlSTkFzCmF3ayAtdiBzZXE9IiRzZXExIiAnQkVHSU4ge1JTPSI+IjsgRlM9IlxuIn0gJDEgfiBzZXEge3ByaW50ICI+IiQwfScgLi4vLi4vRC1BcHVsL291dHB1dC8xMy4yLjEtQXB1bC1zUk5Bc2VxLVNob3J0U3RhY2stMzFicC1mYXN0cC1tZXJnZWQtY25pZGFyaWFuX21pUkJhc2UvU2hvcnRTdGFja19vdXQvbWlyLmZhc3RhCgphd2sgLXYgc2VxPSIkc2VxMiIgJ0JFR0lOIHtSUz0iPiI7IEZTPSJcbiJ9ICQxIH4gc2VxIHtwcmludCAiPiIkMH0nIC4uLy4uL0QtQXB1bC9vdXRwdXQvMTMuMi4xLUFwdWwtc1JOQXNlcS1TaG9ydFN0YWNrLTMxYnAtZmFzdHAtbWVyZ2VkLWNuaWRhcmlhbl9taVJCYXNlL1Nob3J0U3RhY2tfb3V0L21pci5mYXN0YQpgYGAKCkZvciBhbGwgdGhyZWUgb2YgdGhlc2Ugc2V0cyBvZiBpZGVudGljYWwgbWlSTkFzLCB0aGUgbWF0dXJlIGFuZCBzdGFyIHNlcXVlbmNlcyBhcmUgaWRlbnRpY2FsIGJ1dCB0aGUgcHJlY3Vyc29ycyBoYXZlIGEgY291cGxlIG9mIG1pc21hdGNoZXMsIGluIGFkZGl0aW9uIHRvIGJlaW5nIGxvY2F0ZWQgaW4gZGlmZmVyZW50IHBsYWNlcyBvbiB0aGUgY2hyb21vc29tZS4KCiMjIFBldmUKCmBgYHtyIHBldmUtaWRlbnRpY2FsLW1pcm5hfQojIElkZW50aWZ5IHNldHMgb2YgaWRlbnRpY2FsIG1pUk5BcwpwZXZlX2lkZW50aWNhbF9taVJOQXMgPC0gZmlsdGVyZWRfY29tYmluZWRfYmxhc3RuICU+JQogIGZpbHRlcihncmVwbCgiUG9yaXRlc19ldmVybWFuaSIsIHNzZXFpZCkpICU+JQogIGZpbHRlcihncmVwbCgiUG9yaXRlc19ldmVybWFuaSIsIHFzZXFpZCkpCiAgICAgICAgIApoZWFkKHBldmVfaWRlbnRpY2FsX21pUk5BcykKCiMgU2F2ZQp3cml0ZS50YWJsZShwZXZlX2lkZW50aWNhbF9taVJOQXMsICIuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL1BldmVfaWRlbnRpY2FsX21pUk5Bcy50YWIiLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpCmBgYAoKYGBge3IgcGV2ZS1pZGVudGljYWwtZmlyc3QsIGVuZ2luZT0nYmFzaCd9CiMgRmlyc3QgcGFpcgpoZWFkIC0yIC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vUGV2ZV9pZGVudGljYWxfbWlSTkFzLnRhYiB8IHRhaWwgLTEKCnNlcTE9JChhd2sgJ05SPT0yIHtwcmludCAkMX0nIEZTPSdcdCcgLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9QZXZlX2lkZW50aWNhbF9taVJOQXMudGFiIHwgc2VkICdzLy5tYXR1cmU6Oi4qLy8nIHwgc2VkICdzLyIvL2cnKQpzZXEyPSQoYXdrICdOUj09MiB7cHJpbnQgJDJ9JyBGUz0nXHQnIC4uL291dHB1dC8xMC1zaG9ydFJOQS1TaG9ydFN0YWNrLWNvbXBhcmlzb24vUGV2ZV9pZGVudGljYWxfbWlSTkFzLnRhYiB8IHNlZCAncy8ubWF0dXJlOjouKi8vJyB8IHNlZCAncy8iLy9nJykKCmVjaG8gIiIKZWNobyAkc2VxMQplY2hvICRzZXEyCmVjaG8gIiIKCiMgZ3JhYiB0aGUgcHJlY3Vyc29yLCBzdGFyLCBhbmQgbWF0dXJlIGZhc3RhIHNlcXVlbmNlcyBmb3IgdGhlIHR3byBtaVJOQXMKYXdrIC12IHNlcT0iJHNlcTEiICdCRUdJTiB7UlM9Ij4iOyBGUz0iXG4ifSAkMSB+IHNlcSB7cHJpbnQgIj4iJDB9JyAuLi8uLi9FLVBldmUvb3V0cHV0LzA4LjItUGV2ZS1zUk5Bc2VxLVNob3J0U3RhY2stMzFicC1mYXN0cC1tZXJnZWQvU2hvcnRTdGFja19vdXQvbWlyLmZhc3RhCgphd2sgLXYgc2VxPSIkc2VxMiIgJ0JFR0lOIHtSUz0iPiI7IEZTPSJcbiJ9ICQxIH4gc2VxIHtwcmludCAiPiIkMH0nIC4uLy4uL0UtUGV2ZS9vdXRwdXQvMDguMi1QZXZlLXNSTkFzZXEtU2hvcnRTdGFjay0zMWJwLWZhc3RwLW1lcmdlZC9TaG9ydFN0YWNrX291dC9taXIuZmFzdGEKYGBgCkZvciB0aGlzIHNldCBvZiBpZGVudGljYWwgbWlSTkFzLCB0aGUgbWF0dXJlIGFuZCBzdGFyIHNlcXVlbmNlcyBhcmUgaWRlbnRpY2FsIGFuZCB0aGUgcHJlY3Vyc29ycyBvbmx5IGhhdmUgYSBzaW5nbGUgbWlzbWF0Y2gsIGRlc3BpdGUgYmVpbmcgbG9jYXRlZCBpbiBkaWZmZXJlbnQgcGxhY2VzIG9uIHRoZSBjaHJvbW9zb21lLgoKCiMjIFBtZWEKCmBgYHtyIHBtZWEtaWRlbnRpY2FsLW1pcm5hfQojIElkZW50aWZ5IHNldHMgb2YgaWRlbnRpY2FsIG1pUk5BcwpwbWVhX2lkZW50aWNhbF9taVJOQXMgPC0gZmlsdGVyZWRfY29tYmluZWRfYmxhc3RuICU+JQogIGZpbHRlcihncmVwbCgiUG9jaWxsb3BvcmFfbWVhbmRyaW5hIiwgc3NlcWlkKSkgJT4lCiAgZmlsdGVyKGdyZXBsKCJQb2NpbGxvcG9yYV9tZWFuZHJpbmEiLCBxc2VxaWQpKQogICAgICAgICAKaGVhZChwbWVhX2lkZW50aWNhbF9taVJOQXMpCmBgYApUaGVyZSBhcmUgMCBzZXRzIG9mIGlkZW50aWNhbCBtaVJOQXMgaWRlbnRpZmllZCBieSBTaG9ydFN0YWNrIGluIFAubWVhbmRyaW5hCgoKIyBMb29rIGF0IHRoZSBkYXRhYmFzZSBtYXRjaGVzCgpgYGB7ciBpc29sYXRlLW1pcm5hLWZyb20tcmVzdWx0c3R4dCwgZW5naW5lPSdiYXNoJ30KIyBpc29sYXRlIHRoZSBmdWxsICJSZXN1bHRzIiBhbm5vdGF0aW9uIGZvciBlYWNoIG1hdHVyZSBtaVJOQSwgd2hpY2ggaW5jbHVkZXMgc2VxdWVuY2UgZGV0YWlsIGFuZCBkYXRhYmFzZSBtYXRjaGVzCgojIEFwdWwKYXdrIC1GJ1x0JyAnTlI9PTEgfHwgJDIwID09ICJZIicgLi4vLi4vRC1BcHVsL291dHB1dC8xMy4yLjEtQXB1bC1zUk5Bc2VxLVNob3J0U3RhY2stMzFicC1mYXN0cC1tZXJnZWQtY25pZGFyaWFuX21pUkJhc2UvU2hvcnRTdGFja19vdXQvUmVzdWx0cy50eHQgPiAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uL0FwdWxfcmVzdWx0c19tYXR1cmUudHh0CgojIFBldmUKYXdrIC1GJ1x0JyAnTlI9PTEgfHwgJDIwID09ICJZIicgLi4vLi4vRS1QZXZlL291dHB1dC8wOC4yLVBldmUtc1JOQXNlcS1TaG9ydFN0YWNrLTMxYnAtZmFzdHAtbWVyZ2VkL1Nob3J0U3RhY2tfb3V0L1Jlc3VsdHMudHh0ID4gLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9QZXZlX3Jlc3VsdHNfbWF0dXJlLnR4dAoKIyBQbWVhCmF3ayAtRidcdCcgJ05SPT0xIHx8ICQyMCA9PSAiWSInIC4uLy4uL0YtUG1lYS9vdXRwdXQvMTMuMi4xLVBtZWEtc1JOQXNlcS1TaG9ydFN0YWNrLTMxYnAtZmFzdHAtbWVyZ2VkLWNuaWRhcmlhbl9taVJCYXNlL1Nob3J0U3RhY2tfb3V0L1Jlc3VsdHMudHh0ID4gLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9QbWVhX3Jlc3VsdHNfbWF0dXJlLnR4dAoKYGBgCgpBbm5vdGF0ZSBvdXIgbWF0dXJlIG1pUk5BIGZhc3RhIGZpbGVzIHdpdGggYXNzb2NpYXRlZCBkYXRhYmFzZSBtYXRjaGVzCgpBcHVsCmBgYHtyIGFwdWwtYW5ub3RhdGUtd2l0aC1kYi1tYXRjaGVzLCBlbmdpbmU9J2Jhc2gnfQpjZCAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uCgp3aGlsZSBJRlM9IHJlYWQgLXIgbGluZTsgZG8KICAgIGlmIFtbICRsaW5lID09ICI+IiogXV07IHRoZW4KICAgICAgICAjIEV4dHJhY3Qgc2VxdWVuY2UgaGVhZGVyICh3aXRob3V0ICI+IikgYW5kIHRoZSBhY2Nlc3Npb24gc3RyaW5nCiAgICAgICAgaGVhZGVyPSIke2xpbmU6MX0iCiAgICAgICAgYWNjZXNzaW9uPSQoZWNobyAiJGhlYWRlciIgfCBhd2sgLUYgJy4nICd7cHJpbnQgJDF9JykKCiAgICAgICAgIyBTZWFyY2ggZm9yIHRoZSBhY2Nlc3Npb24gc3RyaW5nIGluIHRoZSBtZXRhZGF0YSBmaWxlCiAgICAgICAgbWV0YWRhdGFfbGluZT0kKGdyZXAgLWkgIiRhY2Nlc3Npb24iIEFwdWxfcmVzdWx0c19tYXR1cmUudHh0KQoKICAgICAgICAjIEV4dHJhY3QgdGhlIGxhc3QgY29sdW1uIGVudHJ5IGZyb20gdGhlIG1ldGFkYXRhIGxpbmUKICAgICAgICBsYXN0X2NvbHVtbj0kKGVjaG8gIiRtZXRhZGF0YV9saW5lIiB8IGF3ayAne3ByaW50ICRORn0nKQoKICAgICAgICAjIEFwcGVuZCB0aGUgbGFzdCBjb2x1bW4gZW50cnkgdG8gdGhlIHNlcXVlbmNlIGhlYWRlcgogICAgICAgIG5ld19oZWFkZXI9IiRoZWFkZXIgJGxhc3RfY29sdW1uIgoKICAgICAgICAjIE91dHB1dCB0aGUgbmV3IGhlYWRlcgogICAgICAgIGVjaG8gIj4kbmV3X2hlYWRlciIKICAgIGVsc2UKICAgICAgICAjIE91dHB1dCB0aGUgc2VxdWVuY2UgbGluZSB1bmNoYW5nZWQKICAgICAgICBlY2hvICIkbGluZSIKICAgIGZpCmRvbmUgPCAuLi8uLi9kYXRhLzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9BcHVsX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhID4gQXB1bF9TaG9ydFN0YWNrX21hdHVyZV9hbm5vdGF0ZWQuZmFzdGEKYGBgCgpQZXZlCmBgYHtyIHBldmUtYW5ub3RhdGUtd2l0aC1kYi1tYXRjaGVzLCBlbmdpbmU9J2Jhc2gnfQpjZCAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uCgp3aGlsZSBJRlM9IHJlYWQgLXIgbGluZTsgZG8KICAgIGlmIFtbICRsaW5lID09ICI+IiogXV07IHRoZW4KICAgICAgICAjIEV4dHJhY3Qgc2VxdWVuY2UgaGVhZGVyICh3aXRob3V0ICI+IikgYW5kIHRoZSBhY2Nlc3Npb24gc3RyaW5nCiAgICAgICAgaGVhZGVyPSIke2xpbmU6MX0iCiAgICAgICAgYWNjZXNzaW9uPSQoZWNobyAiJGhlYWRlciIgfCBhd2sgLUYgJy4nICd7cHJpbnQgJDF9JykKCiAgICAgICAgIyBTZWFyY2ggZm9yIHRoZSBhY2Nlc3Npb24gc3RyaW5nIGluIHRoZSBtZXRhZGF0YSBmaWxlCiAgICAgICAgbWV0YWRhdGFfbGluZT0kKGdyZXAgLWkgIiRhY2Nlc3Npb24iIFBldmVfcmVzdWx0c19tYXR1cmUudHh0KQoKICAgICAgICAjIEV4dHJhY3QgdGhlIGxhc3QgY29sdW1uIGVudHJ5IGZyb20gdGhlIG1ldGFkYXRhIGxpbmUKICAgICAgICBsYXN0X2NvbHVtbj0kKGVjaG8gIiRtZXRhZGF0YV9saW5lIiB8IGF3ayAne3ByaW50ICRORn0nKQoKICAgICAgICAjIEFwcGVuZCB0aGUgbGFzdCBjb2x1bW4gZW50cnkgdG8gdGhlIHNlcXVlbmNlIGhlYWRlcgogICAgICAgIG5ld19oZWFkZXI9IiRoZWFkZXIgJGxhc3RfY29sdW1uIgoKICAgICAgICAjIE91dHB1dCB0aGUgbmV3IGhlYWRlcgogICAgICAgIGVjaG8gIj4kbmV3X2hlYWRlciIKICAgIGVsc2UKICAgICAgICAjIE91dHB1dCB0aGUgc2VxdWVuY2UgbGluZSB1bmNoYW5nZWQKICAgICAgICBlY2hvICIkbGluZSIKICAgIGZpCmRvbmUgPCAuLi8uLi9kYXRhLzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9QZXZlX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhID4gUGV2ZV9TaG9ydFN0YWNrX21hdHVyZV9hbm5vdGF0ZWQuZmFzdGEKYGBgCgpQbWVhCmBgYHtyIHBtZWEtYW5ub3RhdGUtd2l0aC1kYi1tYXRjaGVzLCBlbmdpbmU9J2Jhc2gnfQpjZCAuLi9vdXRwdXQvMTAtc2hvcnRSTkEtU2hvcnRTdGFjay1jb21wYXJpc29uCgp3aGlsZSBJRlM9IHJlYWQgLXIgbGluZTsgZG8KICAgIGlmIFtbICRsaW5lID09ICI+IiogXV07IHRoZW4KICAgICAgICAjIEV4dHJhY3Qgc2VxdWVuY2UgaGVhZGVyICh3aXRob3V0ICI+IikgYW5kIHRoZSBhY2Nlc3Npb24gc3RyaW5nCiAgICAgICAgaGVhZGVyPSIke2xpbmU6MX0iCiAgICAgICAgYWNjZXNzaW9uPSQoZWNobyAiJGhlYWRlciIgfCBhd2sgLUYgJy4nICd7cHJpbnQgJDF9JykKCiAgICAgICAgIyBTZWFyY2ggZm9yIHRoZSBhY2Nlc3Npb24gc3RyaW5nIGluIHRoZSBtZXRhZGF0YSBmaWxlCiAgICAgICAgbWV0YWRhdGFfbGluZT0kKGdyZXAgLWkgIiRhY2Nlc3Npb24iIFBtZWFfcmVzdWx0c19tYXR1cmUudHh0KQoKICAgICAgICAjIEV4dHJhY3QgdGhlIGxhc3QgY29sdW1uIGVudHJ5IGZyb20gdGhlIG1ldGFkYXRhIGxpbmUKICAgICAgICBsYXN0X2NvbHVtbj0kKGVjaG8gIiRtZXRhZGF0YV9saW5lIiB8IGF3ayAne3ByaW50ICRORn0nKQoKICAgICAgICAjIEFwcGVuZCB0aGUgbGFzdCBjb2x1bW4gZW50cnkgdG8gdGhlIHNlcXVlbmNlIGhlYWRlcgogICAgICAgIG5ld19oZWFkZXI9IiRoZWFkZXIgJGxhc3RfY29sdW1uIgoKICAgICAgICAjIE91dHB1dCB0aGUgbmV3IGhlYWRlcgogICAgICAgIGVjaG8gIj4kbmV3X2hlYWRlciIKICAgIGVsc2UKICAgICAgICAjIE91dHB1dCB0aGUgc2VxdWVuY2UgbGluZSB1bmNoYW5nZWQKICAgICAgICBlY2hvICIkbGluZSIKICAgIGZpCmRvbmUgPCAuLi8uLi9kYXRhLzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9QbWVhX1Nob3J0U3RhY2tfbWF0dXJlLmZhc3RhID4gUG1lYV9TaG9ydFN0YWNrX21hdHVyZV9hbm5vdGF0ZWQuZmFzdGEKYGBgCgojIyBUYWJsZQoKYGBge3IgZGF0YS1zdW1tYXJ5LWNvbXBhcmUtZGJtYXRjaH0KQXB1bF9zaG9ydHN0YWNrX3Jlc3VsdHMgPC0gcmVhZC5jc3YoIi4uLy4uL0QtQXB1bC9vdXRwdXQvMTMuMi4xLUFwdWwtc1JOQXNlcS1TaG9ydFN0YWNrLTMxYnAtZmFzdHAtbWVyZ2VkLWNuaWRhcmlhbl9taVJCYXNlL1Nob3J0U3RhY2tfb3V0L1Jlc3VsdHMudHh0Iiwgc2VwPSJcdCIpCgpQZXZlX3Nob3J0c3RhY2tfcmVzdWx0cyA8LSByZWFkLmNzdigiLi4vLi4vRS1QZXZlL291dHB1dC8wOC4yLVBldmUtc1JOQXNlcS1TaG9ydFN0YWNrLTMxYnAtZmFzdHAtbWVyZ2VkL1Nob3J0U3RhY2tfb3V0L1Jlc3VsdHMudHh0Iiwgc2VwPSJcdCIpCgpQbWVhX3Nob3J0c3RhY2tfcmVzdWx0cyA8LSByZWFkLmNzdigiLi4vLi4vRi1QbWVhL291dHB1dC8xMy4yLjEtUG1lYS1zUk5Bc2VxLVNob3J0U3RhY2stMzFicC1mYXN0cC1tZXJnZWQtY25pZGFyaWFuX21pUkJhc2UvU2hvcnRTdGFja19vdXQvUmVzdWx0cy50eHQiLCBzZXA9Ilx0IikKCkFwdWxfbnVtX21pUk5BIDwtIEFwdWxfc2hvcnRzdGFja19yZXN1bHRzICU+JSBmaWx0ZXIoTUlSTkEgPT0gIlkiKSAlPiUgbnJvdygpCkFwdWxfbnVtX21pUk5BbWF0Y2ggPC0gQXB1bF9zaG9ydHN0YWNrX3Jlc3VsdHMgJT4lIGZpbHRlcihNSVJOQSA9PSAiWSIgKSAlPiUgZmlsdGVyKCFpcy5uYShrbm93bl9taVJOQXMpKSAlPiUgbnJvdygpCgpQZXZlX251bV9taVJOQSA8LSBQZXZlX3Nob3J0c3RhY2tfcmVzdWx0cyAlPiUgZmlsdGVyKE1JUk5BID09ICJZIikgJT4lIG5yb3coKQpQZXZlX251bV9taVJOQW1hdGNoIDwtIFBldmVfc2hvcnRzdGFja19yZXN1bHRzICU+JSBmaWx0ZXIoTUlSTkEgPT0gIlkiICkgJT4lIGZpbHRlcighaXMubmEoa25vd25fbWlSTkFzKSkgJT4lIG5yb3coKQoKUG1lYV9udW1fbWlSTkEgPC0gUG1lYV9zaG9ydHN0YWNrX3Jlc3VsdHMgJT4lIGZpbHRlcihNSVJOQSA9PSAiWSIpICU+JSBucm93KCkKUG1lYV9udW1fbWlSTkFtYXRjaCA8LSBQbWVhX3Nob3J0c3RhY2tfcmVzdWx0cyAlPiUgZmlsdGVyKE1JUk5BID09ICJZIiApICU+JSBmaWx0ZXIoIWlzLm5hKGtub3duX21pUk5BcykpICU+JSBucm93KCkKCnRhYmxlX2RhdGEgPC0gZGF0YS5mcmFtZSgKICBTcGVjaWVzID0gYygiQS4gcHVsY2hyYSIsICJQLiBldmVybWFubmkiLCAiUC4gdHVhaGVuaWVuc2lzIiksCiAgbWlSTkEgPSBjKEFwdWxfbnVtX21pUk5BLCBQZXZlX251bV9taVJOQSwgUG1lYV9udW1fbWlSTkEpLAogIG1pUk5BbWF0Y2ggPSBjKEFwdWxfbnVtX21pUk5BbWF0Y2gsIFBldmVfbnVtX21pUk5BbWF0Y2gsIFBtZWFfbnVtX21pUk5BbWF0Y2gpCikKY29sbmFtZXModGFibGVfZGF0YSkgPC0gYygiU3BlY2llcyIsICJtaVJOQSIsICJtaVJOQSB3aXRoIGRhdGFiYXNlIG1hdGNoKGVzKSIpCmBgYAoKYGBge3IgbWFrZS1zdW1tYXJ5LXRhYmxlfQp0YWJsZSA8LSB0YWJsZUdyb2IodGFibGVfZGF0YSwgcm93cz1OVUxMKQptaVJOQV9tYXRjaGVzX3RhYmxlIDwtIGdyaWQuYXJyYW5nZSh0YWJsZSkKCnBuZygiLi4vb3V0cHV0LzEwLXNob3J0Uk5BLVNob3J0U3RhY2stY29tcGFyaXNvbi9maWd1cmVzL3RhYmxlX21pUk5BX21hdGNoZXMucG5nIiwgd2lkdGggPSA0MDAsIGhlaWdodCA9IDEwMCkKZ3JpZC5hcnJhbmdlKHRhYmxlKQoKcG5nKCIuLi8uLi9zdXBwbGVtZW50YWwvbWlSTkEvdGFibGVfbWlSTkFfbWF0Y2hlcy5wbmciLCB3aWR0aCA9IDQwMCwgaGVpZ2h0ID0gMTAwKQpncmlkLmFycmFuZ2UodGFibGUpCgpgYGA=