Use miRTrace (Kang et al. 2018) to identify taxonomic origins of miRNA sequencing data.

NOTE: This requires you to have previously run 08-Apul-sRNAseq-trimming.Rmd, as the code relies on the trimmed reads output from that code.


Inputs:

Outputs:

  • mirtrace.config: A miRTrace config file. A comma-separated file with this layout (one FastQ per line): /path/to/fastq,custom_sample_name

  • “Collapsed” (i.e. unique sequences only) FastA for each corresponding input FastQ.

  • mirtrace-report.html: HTML-formatted report generated by miRTrace.

  • mirtrace-stats-contamination_basic.tsv: Tab-delimited report with counts of sequences from each collapsed FastAs having matches to known miRNAs within each of the miRTrace Clades.

  • mirtrace-stats-contamination_detailed.csv: Tab-delimited report of only Clades with which sequences were matched, along with the corresponding miRNA families in each clade, and the sequence counts.

1 Create a Bash variables file

This allows usage of Bash variables across R Markdown chunks.

{
echo "#### Assign Variables ####"
echo ""

echo "# Data directories"
echo 'export deep_dive_dir=/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive'
echo 'export output_dir_top=${deep_dive_dir}/D-Apul/output/09-Apul-sRNAseq-miRTrace'
echo 'export trimmed_reads_dir=${deep_dive_dir}/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads'
echo ""

echo "# Paths to programs"
echo 'export mirtrace=/home/sam/programs/mambaforge/envs/miRTrace_env/bin/mirtrace'
echo ""

echo "# Set number of CPUs to use"
echo 'export threads=40'
echo ""

echo "export fastq_pattern='*flexbar_trim.25bp*.gz'"

echo "# Programs associative array"
echo "declare -A programs_array"
echo "programs_array=("
echo '[mirtrace]="${mirtrace}"'
echo ")"
} > .bashvars

cat .bashvars
#### Assign Variables ####

# Data directories
export deep_dive_dir=/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive
export output_dir_top=${deep_dive_dir}/D-Apul/output/09-Apul-sRNAseq-miRTrace
export trimmed_reads_dir=${deep_dive_dir}/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads

# Paths to programs
export mirtrace=/home/sam/programs/mambaforge/envs/miRTrace_env/bin/mirtrace

# Set number of CPUs to use
export threads=40

export fastq_pattern='*flexbar_trim.25bp*.gz'
# Programs associative array
declare -A programs_array
programs_array=(
[mirtrace]="${mirtrace}"
)

2 Create miRTrace config file

# Load bash variables into memory
source .bashvars

# Declare array
fastq_array=()

# Populate array
fastq_array=(${trimmed_reads_dir}/${fastq_pattern})

# Loop through read pairs
# Increment by 2 to process next pair of FastQ files
if [ -f "${output_dir_top}/mirtrace.config" ]; then
  echo "mirtrace.config already exists. Nothing to do."
  
else

  for (( i=0; i<${#fastq_array[@]} ; i+=2 ))
  do
    # Use first three parts of filename to create short sample name
    R1_name=$(echo "${fastq_array[i]##*/}" | awk -F "-" '{print $1"-"$2"-"$3}')
    R2_name=$(echo "${fastq_array[i+1]##*/}" | awk -F "-" '{print $1"-"$2"-"$3}')
    echo "${fastq_array[i]},${R1_name}_1"
    echo "${fastq_array[i+1]},${R2_name}_2"
  done >> "${output_dir_top}/mirtrace.config"

fi

cat "${output_dir_top}/mirtrace.config"
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads/sRNA-ACR-140-S1-TP2.flexbar_trim.25bp_1.fastq.gz,sRNA-ACR-140_1
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads/sRNA-ACR-140-S1-TP2.flexbar_trim.25bp_2.fastq.gz,sRNA-ACR-140_2
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads/sRNA-ACR-145-S1-TP2.flexbar_trim.25bp_1.fastq.gz,sRNA-ACR-145_1
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads/sRNA-ACR-145-S1-TP2.flexbar_trim.25bp_2.fastq.gz,sRNA-ACR-145_2
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads/sRNA-ACR-150-S1-TP2.flexbar_trim.25bp_1.fastq.gz,sRNA-ACR-150_1
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads/sRNA-ACR-150-S1-TP2.flexbar_trim.25bp_2.fastq.gz,sRNA-ACR-150_2
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads/sRNA-ACR-173-S1-TP2.flexbar_trim.25bp_1.fastq.gz,sRNA-ACR-173_1
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads/sRNA-ACR-173-S1-TP2.flexbar_trim.25bp_2.fastq.gz,sRNA-ACR-173_2
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads/sRNA-ACR-178-S1-TP2.flexbar_trim.25bp_1.fastq.gz,sRNA-ACR-178_1
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/08-Apul-sRNAseq-trimming/trimmed-reads/sRNA-ACR-178-S1-TP2.flexbar_trim.25bp_2.fastq.gz,sRNA-ACR-178_2

3 Run miRTrace

# Load bash variables into memory
source .bashvars

time \
${programs_array[mirtrace]} trace \
--config ${output_dir_top}/mirtrace.config \
--write-fasta \
--num-threads ${threads} \
--output-dir ${output_dir_top} \
--force

tree -h ${output_dir_top}
miRTrace version 1.0.1 starting. Processing 10 sample(s).
NOTE: reusing existing output directory, outdated files may be present.

Run complete. Processed 10 sample(s) in 87 s.

Reports written to /home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/09-Apul-sRNAseq-miRTrace/
For information about citing our paper, run miRTrace in mode "cite".

real    1m28.271s
user    10m24.928s
sys 0m11.388s
/home/shared/8TB_HDD_01/sam/gitrepos/deep-dive/D-Apul/output/09-Apul-sRNAseq-miRTrace
├── [1.6K]  mirtrace.config
├── [302K]  mirtrace-report.html
├── [ 575]  mirtrace-stats-contamination_basic.tsv
├── [ 822]  mirtrace-stats-contamination_detailed.tsv
└── [4.0K]  qc_passed_reads.all.collapsed
    ├── [117M]  sRNA-ACR-140-S1-TP2.flexbar_trim.25bp_1.fasta
    ├── [163M]  sRNA-ACR-140-S1-TP2.flexbar_trim.25bp_2.fasta
    ├── [128M]  sRNA-ACR-145-S1-TP2.flexbar_trim.25bp_1.fasta
    ├── [175M]  sRNA-ACR-145-S1-TP2.flexbar_trim.25bp_2.fasta
    ├── [135M]  sRNA-ACR-150-S1-TP2.flexbar_trim.25bp_1.fasta
    ├── [179M]  sRNA-ACR-150-S1-TP2.flexbar_trim.25bp_2.fasta
    ├── [113M]  sRNA-ACR-173-S1-TP2.flexbar_trim.25bp_1.fasta
    ├── [151M]  sRNA-ACR-173-S1-TP2.flexbar_trim.25bp_2.fasta
    ├── [109M]  sRNA-ACR-178-S1-TP2.flexbar_trim.25bp_1.fasta
    └── [140M]  sRNA-ACR-178-S1-TP2.flexbar_trim.25bp_2.fasta

1 directory, 14 files

4 Results

4.1 Read in table as data frame

mirtrace.detailed.df <- read.csv("../output/09-Apul-sRNAseq-miRTrace/mirtrace-stats-contamination_detailed.tsv", sep = "\t", header = TRUE)

str(mirtrace.detailed.df)
'data.frame':   7 obs. of  14 variables:
 $ CLADE         : chr  "lophotrochozoa" "lophotrochozoa" "lophotrochozoa" "rodents" ...
 $ FAMILY_ID     : int  1994 1985 1984 351 618 576 576
 $ MIRBASE_IDS   : chr  "cla-miR-1994,cte-miR-1994,lgi-miR-1994a,lgi-miR-1994b" "hru-miR-1985,lgi-miR-1985" "hru-miR-1984,lgi-miR-1984" "mmu-miR-351,rno-miR-351" ...
 $ SEQ           : chr  "TGAGACAGTGTGTCCTCCCT" "TGCCATTTTTATCAGTCACT" "TGCCCTATCCGTCAGGAACT" "TCCCTGAGGAGCCCTTTGAG" ...
 $ sRNA.ACR.140_1: int  0 0 0 0 0 0 0
 $ sRNA.ACR.140_2: int  0 0 0 0 0 0 0
 $ sRNA.ACR.145_1: int  0 0 0 0 0 0 0
 $ sRNA.ACR.145_2: int  0 0 0 0 0 0 0
 $ sRNA.ACR.150_1: int  1 11 10 0 0 1 0
 $ sRNA.ACR.150_2: int  0 0 0 0 0 0 0
 $ sRNA.ACR.173_1: int  3 15 16 0 1 0 1
 $ sRNA.ACR.173_2: int  0 0 0 0 0 0 0
 $ sRNA.ACR.178_1: int  0 0 0 2 0 0 0
 $ sRNA.ACR.178_2: int  0 0 0 0 0 0 0

4.2 Number of samples with matches

# Select columns corresponding to sample names
sample_columns <- mirtrace.detailed.df %>%
  select(starts_with("sRNA.ACR."))

# Calculate the sum for each column
sample_sums <- colSums(sample_columns)

# Count the number of columns with a sum greater than 0
samples_with_sum_gt_0 <- sum(sample_sums > 0)

paste("Number of samples with matches: ", samples_with_sum_gt_0)
[1] "Number of samples with matches:  3"

4.3 Percentage of samples with matches

# Total number of samples (columns)
total_samples <- ncol(sample_columns)

# Percentage of samples with sums greater than 0
percentage_samples_gt_0 <- (samples_with_sum_gt_0 / total_samples) * 100

paste("Percentage of samples with matches: ", percentage_samples_gt_0)
[1] "Percentage of samples with matches:  30"

4.4 Number of clades with matches

unique_clade_count <- mirtrace.detailed.df %>%
  distinct(CLADE) %>%    # Get unique entries in CLADE column
  count()               # Count the number of unique entries



paste("Number of clades with matches:", unique_clade_count)
[1] "Number of clades with matches: 3"

4.5 miRTrace table

To make them easier to see, counts > 0 are highlighted in green.

mirtrace.detailed.df %>%
  mutate(
    across(
      starts_with("sRNA"),
      ~cell_spec(
        .,
        background = ifelse(
          . > 0,
          "lightgreen",
          "white"
          )
        )
      )
    ) %>%
  kable(escape = F, caption = "Clades identified as having sRNAseq matches.") %>%
  kable_styling("striped") %>% 
  scroll_box(width = "100%", height = "500px")
Table 4.1: Clades identified as having sRNAseq matches.
CLADE FAMILY_ID MIRBASE_IDS SEQ sRNA.ACR.140_1 sRNA.ACR.140_2 sRNA.ACR.145_1 sRNA.ACR.145_2 sRNA.ACR.150_1 sRNA.ACR.150_2 sRNA.ACR.173_1 sRNA.ACR.173_2 sRNA.ACR.178_1 sRNA.ACR.178_2
lophotrochozoa 1994 cla-miR-1994,cte-miR-1994,lgi-miR-1994a,lgi-miR-1994b TGAGACAGTGTGTCCTCCCT 0 0 0 0 1 0 3 0 0 0
lophotrochozoa 1985 hru-miR-1985,lgi-miR-1985 TGCCATTTTTATCAGTCACT 0 0 0 0 11 0 15 0 0 0
lophotrochozoa 1984 hru-miR-1984,lgi-miR-1984 TGCCCTATCCGTCAGGAACT 0 0 0 0 10 0 16 0 0 0
rodents 351 mmu-miR-351,rno-miR-351 TCCCTGAGGAGCCCTTTGAG 0 0 0 0 0 0 0 0 2 0
primates 618 hsa-miR-618,mml-miR-618,ppy-miR-618,ptr-miR-618 AAACTCTACTTGTCCTTCTG 0 0 0 0 0 0 1 0 0 0
primates 576 hsa-miR-576,mml-miR-576,ppy-miR-576,ptr-miR-576 AAGATGTGGAAAAATTGGAA 0 0 0 0 1 0 0 0 0 0
primates 576 hsa-miR-576 ATTCTAATTTCTCCACGTCT 0 0 0 0 0 0 1 0 0 0

Citations

Kang, Wenjing, Yrin Eldfjell, Bastian Fromm, Xavier Estivill, Inna Biryukova, and Marc R. Friedländer. 2018. “miRTrace Reveals the Organismal Origins of microRNA Sequencing Data.” Genome Biology 19 (1). https://doi.org/10.1186/s13059-018-1588-9.
LS0tCnRpdGxlOiAiMDktQXB1bC1zUk5Bc2VxLW1pUlRyYWNlIgphdXRob3I6ICJTYW0gV2hpdGUiCmRhdGU6ICIyMDIzLTExLTAxIgpvdXRwdXQ6IAogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmJpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShrbml0cikKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KGRwbHlyKQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyA9IFRSVUUsICAgICAgICAgIyBEaXNwbGF5IGNvZGUgY2h1bmtzCiAgZXZhbCA9IEZBTFNFLCAgICAgICAgIyBFdmFsdWF0ZSBjb2RlIGNodW5rcwogIHdhcm5pbmcgPSBGQUxTRSwgICAgICMgSGlkZSB3YXJuaW5ncwogIG1lc3NhZ2UgPSBGQUxTRSwgICAgICMgSGlkZSBtZXNzYWdlcwogIGNvbW1lbnQgPSAiIiAgICAgICAgICMgUHJldmVudHMgYXBwZW5kaW5nICcjIycgdG8gYmVnaW5uaW5nIG9mIGxpbmVzIGluIGNvZGUgb3V0cHV0CikKCmBgYAoKVXNlIFttaVJUcmFjZV0oaHR0cHM6Ly9naXRodWIuY29tL2ZyaWVkbGFuZGVybGFiL21pcnRyYWNlKSBbQGthbmcyMDE4XSB0byBpZGVudGlmeSB0YXhvbm9taWMgb3JpZ2lucyBvZiBtaVJOQSBzZXF1ZW5jaW5nIGRhdGEuCgpOT1RFOiBUaGlzIHJlcXVpcmVzIHlvdSB0byBoYXZlIHByZXZpb3VzbHkgcnVuIFtgMDgtQXB1bC1zUk5Bc2VxLXRyaW1taW5nLlJtZGBdKGh0dHBzOi8vZ2l0aHViLmNvbS91cm9sLWU1L2RlZXAtZGl2ZS9ibG9iL21haW4vRC1BcHVsL2NvZGUvMDgtQXB1bC1zUk5Bc2VxLXRyaW1taW5nLlJtZCksIGFzIHRoZSBjb2RlIHJlbGllcyBvbiB0aGUgdHJpbW1lZCByZWFkcyBvdXRwdXQgZnJvbSB0aGF0IGNvZGUuCgotLS0KCgpJbnB1dHM6CgotIFRyaW1tZWQgc1JOQXNlcSBGYXN0UXMgZ2VuZXJhdGVkIGJ5IFtgMDgtQXB1bC1zUk5Bc2VxLXRyaW1taW5nLlJtZGBdKGh0dHBzOi8vZ2l0aHViLmNvbS91cm9sLWU1L2RlZXAtZGl2ZS9ibG9iL21haW4vRC1BcHVsL2NvZGUvMDgtQXB1bC1zUk5Bc2VxLXRyaW1taW5nLlJtZCkKCiAgLSBGaWxlbmFtZXMgZm9ybWF0dGVkOiBgKmZsZXhiYXJfdHJpbS4yNWJwKi5nemAKICAKT3V0cHV0czoKCi0gYG1pcnRyYWNlLmNvbmZpZ2A6IEEgW21pUlRyYWNlXShodHRwczovL2dpdGh1Yi5jb20vZnJpZWRsYW5kZXJsYWIvbWlydHJhY2UpIGNvbmZpZyBmaWxlLiBBIGNvbW1hLXNlcGFyYXRlZCBmaWxlIHdpdGggdGhpcyBsYXlvdXQgKG9uZSBGYXN0USBwZXIgbGluZSk6IGAvcGF0aC90by9mYXN0cSxjdXN0b21fc2FtcGxlX25hbWVgCgotICJDb2xsYXBzZWQiIChpLmUuIHVuaXF1ZSBzZXF1ZW5jZXMgb25seSkgRmFzdEEgZm9yIGVhY2ggY29ycmVzcG9uZGluZyBpbnB1dCBGYXN0US4KCi0gYG1pcnRyYWNlLXJlcG9ydC5odG1sYDogSFRNTC1mb3JtYXR0ZWQgcmVwb3J0IGdlbmVyYXRlZCBieSBbbWlSVHJhY2VdKGh0dHBzOi8vZ2l0aHViLmNvbS9mcmllZGxhbmRlcmxhYi9taXJ0cmFjZSkuCgotIGBtaXJ0cmFjZS1zdGF0cy1jb250YW1pbmF0aW9uX2Jhc2ljLnRzdmA6IFRhYi1kZWxpbWl0ZWQgcmVwb3J0IHdpdGggY291bnRzIG9mIHNlcXVlbmNlcyBmcm9tIGVhY2ggY29sbGFwc2VkIEZhc3RBcyBoYXZpbmcgbWF0Y2hlcyB0byBrbm93biBtaVJOQXMgd2l0aGluIGVhY2ggb2YgdGhlIFttaVJUcmFjZV0oaHR0cHM6Ly9naXRodWIuY29tL2ZyaWVkbGFuZGVybGFiL21pcnRyYWNlKSBDbGFkZXMuCgotIGBtaXJ0cmFjZS1zdGF0cy1jb250YW1pbmF0aW9uX2RldGFpbGVkLmNzdmA6IFRhYi1kZWxpbWl0ZWQgcmVwb3J0IG9mIF9vbmx5XyBDbGFkZXMgd2l0aCB3aGljaCBzZXF1ZW5jZXMgd2VyZSBtYXRjaGVkLCBhbG9uZyB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIG1pUk5BIGZhbWlsaWVzIGluIGVhY2ggY2xhZGUsIGFuZCB0aGUgc2VxdWVuY2UgY291bnRzLgoKCiMgQ3JlYXRlIGEgQmFzaCB2YXJpYWJsZXMgZmlsZQoKVGhpcyBhbGxvd3MgdXNhZ2Ugb2YgQmFzaCB2YXJpYWJsZXMgYWNyb3NzIFIgTWFya2Rvd24gY2h1bmtzLgoKYGBge3Igc2F2ZS1iYXNoLXZhcmlhYmxlcy10by1ydmFycy1maWxlLCBlbmdpbmU9J2Jhc2gnLCBldmFsPVRSVUV9CnsKZWNobyAiIyMjIyBBc3NpZ24gVmFyaWFibGVzICMjIyMiCmVjaG8gIiIKCmVjaG8gIiMgRGF0YSBkaXJlY3RvcmllcyIKZWNobyAnZXhwb3J0IGRlZXBfZGl2ZV9kaXI9L2hvbWUvc2hhcmVkLzhUQl9IRERfMDEvc2FtL2dpdHJlcG9zL2RlZXAtZGl2ZScKZWNobyAnZXhwb3J0IG91dHB1dF9kaXJfdG9wPSR7ZGVlcF9kaXZlX2Rpcn0vRC1BcHVsL291dHB1dC8wOS1BcHVsLXNSTkFzZXEtbWlSVHJhY2UnCmVjaG8gJ2V4cG9ydCB0cmltbWVkX3JlYWRzX2Rpcj0ke2RlZXBfZGl2ZV9kaXJ9L0QtQXB1bC9vdXRwdXQvMDgtQXB1bC1zUk5Bc2VxLXRyaW1taW5nL3RyaW1tZWQtcmVhZHMnCmVjaG8gIiIKCmVjaG8gIiMgUGF0aHMgdG8gcHJvZ3JhbXMiCmVjaG8gJ2V4cG9ydCBtaXJ0cmFjZT0vaG9tZS9zYW0vcHJvZ3JhbXMvbWFtYmFmb3JnZS9lbnZzL21pUlRyYWNlX2Vudi9iaW4vbWlydHJhY2UnCmVjaG8gIiIKCmVjaG8gIiMgU2V0IG51bWJlciBvZiBDUFVzIHRvIHVzZSIKZWNobyAnZXhwb3J0IHRocmVhZHM9NDAnCmVjaG8gIiIKCmVjaG8gImV4cG9ydCBmYXN0cV9wYXR0ZXJuPScqZmxleGJhcl90cmltLjI1YnAqLmd6JyIKCmVjaG8gIiMgUHJvZ3JhbXMgYXNzb2NpYXRpdmUgYXJyYXkiCmVjaG8gImRlY2xhcmUgLUEgcHJvZ3JhbXNfYXJyYXkiCmVjaG8gInByb2dyYW1zX2FycmF5PSgiCmVjaG8gJ1ttaXJ0cmFjZV09IiR7bWlydHJhY2V9IicKZWNobyAiKSIKfSA+IC5iYXNodmFycwoKY2F0IC5iYXNodmFycwpgYGAKCiMgQ3JlYXRlIFttaVJUcmFjZV0oaHR0cHM6Ly9naXRodWIuY29tL2ZyaWVkbGFuZGVybGFiL21pcnRyYWNlKSBjb25maWcgZmlsZQpgYGB7ciBjcmVhdGUtY29uZmlnLWZpbGUsIGVuZ2luZT0nYmFzaCcsIGV2YWw9VFJVRX0KIyBMb2FkIGJhc2ggdmFyaWFibGVzIGludG8gbWVtb3J5CnNvdXJjZSAuYmFzaHZhcnMKCiMgRGVjbGFyZSBhcnJheQpmYXN0cV9hcnJheT0oKQoKIyBQb3B1bGF0ZSBhcnJheQpmYXN0cV9hcnJheT0oJHt0cmltbWVkX3JlYWRzX2Rpcn0vJHtmYXN0cV9wYXR0ZXJufSkKCiMgTG9vcCB0aHJvdWdoIHJlYWQgcGFpcnMKIyBJbmNyZW1lbnQgYnkgMiB0byBwcm9jZXNzIG5leHQgcGFpciBvZiBGYXN0USBmaWxlcwppZiBbIC1mICIke291dHB1dF9kaXJfdG9wfS9taXJ0cmFjZS5jb25maWciIF07IHRoZW4KICBlY2hvICJtaXJ0cmFjZS5jb25maWcgYWxyZWFkeSBleGlzdHMuIE5vdGhpbmcgdG8gZG8uIgogIAplbHNlCgogIGZvciAoKCBpPTA7IGk8JHsjZmFzdHFfYXJyYXlbQF19IDsgaSs9MiApKQogIGRvCiAgICAjIFVzZSBmaXJzdCB0aHJlZSBwYXJ0cyBvZiBmaWxlbmFtZSB0byBjcmVhdGUgc2hvcnQgc2FtcGxlIG5hbWUKICAgIFIxX25hbWU9JChlY2hvICIke2Zhc3RxX2FycmF5W2ldIyMqL30iIHwgYXdrIC1GICItIiAne3ByaW50ICQxIi0iJDIiLSIkM30nKQogICAgUjJfbmFtZT0kKGVjaG8gIiR7ZmFzdHFfYXJyYXlbaSsxXSMjKi99IiB8IGF3ayAtRiAiLSIgJ3twcmludCAkMSItIiQyIi0iJDN9JykKICAgIGVjaG8gIiR7ZmFzdHFfYXJyYXlbaV19LCR7UjFfbmFtZX1fMSIKICAgIGVjaG8gIiR7ZmFzdHFfYXJyYXlbaSsxXX0sJHtSMl9uYW1lfV8yIgogIGRvbmUgPj4gIiR7b3V0cHV0X2Rpcl90b3B9L21pcnRyYWNlLmNvbmZpZyIKCmZpCgpjYXQgIiR7b3V0cHV0X2Rpcl90b3B9L21pcnRyYWNlLmNvbmZpZyIKYGBgCgojIFJ1biBbbWlSVHJhY2VdKGh0dHBzOi8vZ2l0aHViLmNvbS9mcmllZGxhbmRlcmxhYi9taXJ0cmFjZSkKYGBge3IgcnVuLW1pcnRyYWNlLCBlbmdpbmU9J2Jhc2gnLCBldmFsPVRSVUV9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgp0aW1lIFwKJHtwcm9ncmFtc19hcnJheVttaXJ0cmFjZV19IHRyYWNlIFwKLS1jb25maWcgJHtvdXRwdXRfZGlyX3RvcH0vbWlydHJhY2UuY29uZmlnIFwKLS13cml0ZS1mYXN0YSBcCi0tbnVtLXRocmVhZHMgJHt0aHJlYWRzfSBcCi0tb3V0cHV0LWRpciAke291dHB1dF9kaXJfdG9wfSBcCi0tZm9yY2UKCnRyZWUgLWggJHtvdXRwdXRfZGlyX3RvcH0KYGBgCgoKIyBSZXN1bHRzCgojIyBSZWFkIGluIHRhYmxlIGFzIGRhdGEgZnJhbWUKYGBge3IgcmVhZC10YWJsZSwgZXZhbD1UUlVFfQptaXJ0cmFjZS5kZXRhaWxlZC5kZiA8LSByZWFkLmNzdigiLi4vb3V0cHV0LzA5LUFwdWwtc1JOQXNlcS1taVJUcmFjZS9taXJ0cmFjZS1zdGF0cy1jb250YW1pbmF0aW9uX2RldGFpbGVkLnRzdiIsIHNlcCA9ICJcdCIsIGhlYWRlciA9IFRSVUUpCgpzdHIobWlydHJhY2UuZGV0YWlsZWQuZGYpCmBgYAoKCiMjIE51bWJlciBvZiBzYW1wbGVzIHdpdGggbWF0Y2hlcwpgYGB7ciBjb3VudHMtc2FtcGxlcy13aXRoLW1hdGNoZXMsIGV2YWw9VFJVRX0KIyBTZWxlY3QgY29sdW1ucyBjb3JyZXNwb25kaW5nIHRvIHNhbXBsZSBuYW1lcwpzYW1wbGVfY29sdW1ucyA8LSBtaXJ0cmFjZS5kZXRhaWxlZC5kZiAlPiUKICBzZWxlY3Qoc3RhcnRzX3dpdGgoInNSTkEuQUNSLiIpKQoKIyBDYWxjdWxhdGUgdGhlIHN1bSBmb3IgZWFjaCBjb2x1bW4Kc2FtcGxlX3N1bXMgPC0gY29sU3VtcyhzYW1wbGVfY29sdW1ucykKCiMgQ291bnQgdGhlIG51bWJlciBvZiBjb2x1bW5zIHdpdGggYSBzdW0gZ3JlYXRlciB0aGFuIDAKc2FtcGxlc193aXRoX3N1bV9ndF8wIDwtIHN1bShzYW1wbGVfc3VtcyA+IDApCgpwYXN0ZSgiTnVtYmVyIG9mIHNhbXBsZXMgd2l0aCBtYXRjaGVzOiAiLCBzYW1wbGVzX3dpdGhfc3VtX2d0XzApCmBgYAojIyBQZXJjZW50YWdlIG9mIHNhbXBsZXMgd2l0aCBtYXRjaGVzCmBgYHtyIHBlcmNlbnRhZ2Utc2FtcGxlcy13aXRoLW1hdGNoZXMsIGV2YWw9VFJVRX0KIyBUb3RhbCBudW1iZXIgb2Ygc2FtcGxlcyAoY29sdW1ucykKdG90YWxfc2FtcGxlcyA8LSBuY29sKHNhbXBsZV9jb2x1bW5zKQoKIyBQZXJjZW50YWdlIG9mIHNhbXBsZXMgd2l0aCBzdW1zIGdyZWF0ZXIgdGhhbiAwCnBlcmNlbnRhZ2Vfc2FtcGxlc19ndF8wIDwtIChzYW1wbGVzX3dpdGhfc3VtX2d0XzAgLyB0b3RhbF9zYW1wbGVzKSAqIDEwMAoKcGFzdGUoIlBlcmNlbnRhZ2Ugb2Ygc2FtcGxlcyB3aXRoIG1hdGNoZXM6ICIsIHBlcmNlbnRhZ2Vfc2FtcGxlc19ndF8wKQpgYGAKCgojIyBOdW1iZXIgb2YgY2xhZGVzIHdpdGggbWF0Y2hlcwpgYGB7ciBkaXN0aW5jdC1jbGFkZXMsIGV2YWw9VFJVRSwgY2xhc3Muc291cmNlID0gJ2ZvbGQtaGlkZSd9Cgp1bmlxdWVfY2xhZGVfY291bnQgPC0gbWlydHJhY2UuZGV0YWlsZWQuZGYgJT4lCiAgZGlzdGluY3QoQ0xBREUpICU+JSAgICAjIEdldCB1bmlxdWUgZW50cmllcyBpbiBDTEFERSBjb2x1bW4KICBjb3VudCgpICAgICAgICAgICAgICAgIyBDb3VudCB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBlbnRyaWVzCgoKCnBhc3RlKCJOdW1iZXIgb2YgY2xhZGVzIHdpdGggbWF0Y2hlczoiLCB1bmlxdWVfY2xhZGVfY291bnQpCgoKYGBgCgoKIyMgW21pUlRyYWNlXShodHRwczovL2dpdGh1Yi5jb20vZnJpZWRsYW5kZXJsYWIvbWlydHJhY2UpIHRhYmxlCgpUbyBtYWtlIHRoZW0gZWFzaWVyIHRvIHNlZSwgY291bnRzID4gMCBhcmUgaGlnaGxpZ2h0ZWQgaW4gZ3JlZW4uCmBgYHtyIG1pcnRyYWNlLW91dHB1dC10YWJsZSwgZXZhbD1UUlVFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30KCm1pcnRyYWNlLmRldGFpbGVkLmRmICU+JQogIG11dGF0ZSgKICAgIGFjcm9zcygKICAgICAgc3RhcnRzX3dpdGgoInNSTkEiKSwKICAgICAgfmNlbGxfc3BlYygKICAgICAgICAuLAogICAgICAgIGJhY2tncm91bmQgPSBpZmVsc2UoCiAgICAgICAgICAuID4gMCwKICAgICAgICAgICJsaWdodGdyZWVuIiwKICAgICAgICAgICJ3aGl0ZSIKICAgICAgICAgICkKICAgICAgICApCiAgICAgICkKICAgICkgJT4lCiAga2FibGUoZXNjYXBlID0gRiwgY2FwdGlvbiA9ICJDbGFkZXMgaWRlbnRpZmllZCBhcyBoYXZpbmcgc1JOQXNlcSBtYXRjaGVzLiIpICU+JQogIGthYmxlX3N0eWxpbmcoInN0cmlwZWQiKSAlPiUgCiAgc2Nyb2xsX2JveCh3aWR0aCA9ICIxMDAlIiwgaGVpZ2h0ID0gIjUwMHB4IikKYGBgCgojIENpdGF0aW9ucwoKCg==