Note: modified from Sam White’s code in deep-dive/D-Apul/code/08.2-Apul-sRNAseq-trimming-31bp-fastp-merged.Rmd
This Rmd file trims A.pulchra sRNA-seq files using fastp (Chen 2023), followed by quality checks with FastQC and MultiQC(Ewels et al. 2016).
Expects input files formatted like so: <number>--<sample_name>_R[12]_001.fastq.gz
Create a Bash variables file
This allows usage of Bash variables across R Markdown chunks.
{
echo "#### Assign Variables ####"
echo ""
echo "# Data directories"
echo 'export timeseries_dir=/home/shared/8TB_HDD_02/shedurkin/timeseries_molecular'
echo 'export output_dir_top=${timeseries_dir}/D-Apul/output/01.10-D-Apul-sRNAseq-trimming-fastp-FastQC-MultiQC'
echo 'export raw_reads_dir=${timeseries_dir}/D-Apul/data/raw-fastqs-sRNA'
echo 'export raw_reads_url="https://owl.fish.washington.edu/nightingales/E5-coral-time-series/30-1069297013/"'
echo 'export trimmed_fastqs_dir=${output_dir_top}/trimmed-fastqs-sRNA'
echo 'export trimmed_fastqc_dir=${output_dir_top}/trimmed-fastqc-sRNA'
echo ""
echo "# Paths to programs"
echo 'export programs_dir="/home/shared"'
echo 'export fastp=/home/shared/fastp'
echo 'export fastqc=${programs_dir}/FastQC-0.12.1/fastqc'
echo 'export multiqc=/home/sam/programs/mambaforge/bin/multiqc'
echo ""
echo "# Set FastQ filename patterns"
echo "export fastq_pattern='*.fastq.gz'"
echo "export R1_fastq_pattern='*_R1_*.fastq.gz'"
echo "export R2_fastq_pattern='*_R2_*.fastq.gz'"
echo "export trimmed_fastq_pattern='*31bp-merged.fq.gz'"
echo ""
echo "# Set number of CPUs to use"
echo 'export threads=40'
echo ""
echo "# Set maximum read length"
echo 'export max_read_length=31'
echo ""
echo "## NEB nebnext-small-rna-library-prep-set-for-illumina adapters"
echo 'export NEB_adapters_fasta=NEB-adapters.fasta'
echo 'export first_adapter="AGATCGGAAGAGCACACGTCTGAACTCCAGTCAC"'
echo 'export second_adapter="GATCGTCGGACTGTAGAACTCTGAACGTGTAGATCTCGGTGGTCGCCGTATCATT"'
echo ""
echo "## Inititalize arrays"
echo 'export fastq_array_R1=()'
echo 'export fastq_array_R2=()'
echo 'export raw_fastqs_array=()'
echo 'export R1_names_array=()'
echo 'export R2_names_array=()'
echo 'export trimmed_fastqs_array=()'
echo ""
echo "# Programs associative array"
echo "declare -A programs_array"
echo "programs_array=("
echo '[fastp]="${fastp}"'
echo '[fastqc]="${fastqc}" \'
echo '[multiqc]="${multiqc}" \'
echo ")"
echo ""
echo "# Print formatting"
echo 'export line="--------------------------------------------------------"'
echo ""
} > .bashvars
cat .bashvars
#### Assign Variables ####
# Data directories
export timeseries_dir=/home/shared/8TB_HDD_02/shedurkin/timeseries_molecular
export output_dir_top=${timeseries_dir}/D-Apul/output/01.10-D-Apul-sRNAseq-trimming-fastp-FastQC-MultiQC
export raw_reads_dir=${timeseries_dir}/D-Apul/data/raw-fastqs-sRNA
export raw_reads_url="https://owl.fish.washington.edu/nightingales/E5-coral-time-series/30-1069297013/"
export trimmed_fastqs_dir=${output_dir_top}/trimmed-fastqs-sRNA
export trimmed_fastqc_dir=${output_dir_top}/trimmed-fastqc-sRNA
# Paths to programs
export programs_dir="/home/shared"
export fastp=/home/shared/fastp
export fastqc=${programs_dir}/FastQC-0.12.1/fastqc
export multiqc=/home/sam/programs/mambaforge/bin/multiqc
# Set FastQ filename patterns
export fastq_pattern='*.fastq.gz'
export R1_fastq_pattern='*_R1_*.fastq.gz'
export R2_fastq_pattern='*_R2_*.fastq.gz'
export trimmed_fastq_pattern='*31bp-merged.fq.gz'
# Set number of CPUs to use
export threads=40
# Set maximum read length
export max_read_length=31
## NEB nebnext-small-rna-library-prep-set-for-illumina adapters
export NEB_adapters_fasta=NEB-adapters.fasta
export first_adapter="AGATCGGAAGAGCACACGTCTGAACTCCAGTCAC"
export second_adapter="GATCGTCGGACTGTAGAACTCTGAACGTGTAGATCTCGGTGGTCGCCGTATCATT"
## Inititalize arrays
export fastq_array_R1=()
export fastq_array_R2=()
export raw_fastqs_array=()
export R1_names_array=()
export R2_names_array=()
export trimmed_fastqs_array=()
# Programs associative array
declare -A programs_array
programs_array=(
[fastp]="${fastp}"
[fastqc]="${fastqc}" \
[multiqc]="${multiqc}" \
)
# Print formatting
export line="--------------------------------------------------------"
If needed, download raw RNA-seq.
Add eval=TRUE
to the chunk header to execute the next two chunks to download RNA-seq and then verify MD5 checksums.
# Load bash variables into memory
source .bashvars
# Make output directory if it doesn't exist
mkdir --parents ${raw_reads_dir}
# Create list of only A.pulchra sample names
sample_list=$(awk -F "," '$6 ~ /^ACR/ {print $5}' ${timeseries_dir}/M-multi-species/data/rna_metadata.csv)
echo ""
echo "${line}"
echo ""
echo "Sample list:"
echo ""
echo "${sample_list}"
echo ""
echo "${line}"
echo ""
# Use printf to format each item for use in wget
formatted_list=$(printf "%s_*," ${sample_list})
# Remove the trailing comma
formatted_list=${formatted_list%,}
# Output the final wget command
echo ""
echo "${line}"
echo ""
echo "Formatted wget accept list:"
echo ""
echo "wget --accept=\"$formatted_list\""
echo ""
echo "${line}"
echo ""
# Run wget to retrieve FastQs and MD5 files
# Note: the --no-clobber command will skip re-downloading any files that are already present in the output directory
wget \
--directory-prefix ${raw_reads_dir} \
--recursive \
--no-check-certificate \
--continue \
--cut-dirs 3 \
--no-host-directories \
--no-parent \
--quiet \
--no-clobber \
--accept=${formatted_list} ${raw_reads_url}
ls -lh "${raw_reads_dir}"
Verify raw read checksums
# Load bash variables into memory
source .bashvars
cd "${raw_reads_dir}"
# Checksums file contains other files, so this just looks for the sRNAseq files.
for file in *.md5
do
md5sum --check "${file}"
done
Create adapters FastA for use with fastp
trimming
# Load bash variables into memory
source .bashvars
mkdir --parents "${output_dir_top}"
echo "Creating adapters FastA."
echo ""
adapter_count=0
# Check for adapters file first
# Then create adapters file if doesn't exist
if [ -f "${output_dir_top}/${NEB_adapters_fasta}" ]; then
echo "${output_dir_top}/${NEB_adapters_fasta} already exists. Nothing to do."
else
for adapter in "${first_adapter}" "${second_adapter}"
do
adapter_count=$((adapter_count + 1))
printf ">%s\n%s\n" "adapter_${adapter_count}" "${adapter}"
done >> "${output_dir_top}/${NEB_adapters_fasta}"
fi
echo ""
echo "Adapters FastA:"
echo ""
cat "${output_dir_top}/${NEB_adapters_fasta}"
echo ""
Fastp Trimming
fastp (Chen 2023) is set to auto-detect Illumina adapters, as well as trim the first 20bp from each read, as past experience shows these first 20bp are more inconsistent than the remainder of the read length.
# Load bash variables into memory
source .bashvars
# Make output directories, if it doesn't exist
mkdir --parents "${trimmed_fastqs_dir}"
# Change to raw reads directory
cd "${raw_reads_dir}"
# Create arrays of fastq R1 files and sample names
for fastq in ${R1_fastq_pattern}
do
fastq_array_R1+=("${fastq}")
R1_names_array+=("$(echo "${fastq}" | awk -F"_" '{print $1}')")
done
# Create array of fastq R2 files
for fastq in ${R2_fastq_pattern}
do
fastq_array_R2+=("${fastq}")
R2_names_array+=("$(echo "${fastq}" | awk -F"_" '{print $1}')")
done
# Create list of fastq files used in analysis
# Create MD5 checksum for reference
if [ ! -f "${output_dir_top}"/raw-fastq-checksums.md5 ]; then
for fastq in *.gz
do
md5sum ${fastq} >> "${output_dir_top}"/raw-fastq-checksums.md5
done
fi
############ RUN FASTP ############
# Uses parameter substitution (e.g. ${R1_sample_name%%_*})to rm the _R[12]
# Run fastp on files
echo "Beginning fastp trimming."
echo ""
time \
for index in "${!fastq_array_R1[@]}"
do
# Get sample name
R1_sample_name="${R1_names_array[index]%%_*}"
# Set fastp report title
trimmed_fastp_report_title="${R1_sample_name}-fastp-adapters-polyG-${max_read_length}bp-merged"
# Set merged output location and filename
merged_output=${trimmed_fastqs_dir}/${trimmed_fastp_report_title}.fq.gz
# Begin fastp trimming
${programs_array[fastp]} \
--in1 ${fastq_array_R1[index]} \
--in2 ${fastq_array_R2[index]} \
--adapter_fasta ${output_dir_top}/${NEB_adapters_fasta} \
--trim_poly_g \
--overlap_len_require 17 \
--length_limit 31 \
--merge \
--merged_out ${merged_output} \
--thread ${threads} \
--html "${trimmed_fastp_report_title}.html" \
--json "${trimmed_fastp_report_title}.json" \
--report_title "${trimmed_fastp_report_title}"
# Move to trimmed directory
# This is done so checksums file doesn't include excess path
cd ${trimmed_fastqs_dir}
# Generate md5 checksums for newly trimmed files
{
md5sum "${trimmed_fastp_report_title}.fq.gz"
} >> "${trimmed_checksums}"
# Change back to to raw reads directory
cd "${raw_reads_dir}"
done
echo ""
echo "fastp trimming complete."
echo ""
echo "Trimmed FastQs MD5 checksums:"
echo ""
cat "${trimmed_fastqs_dir}/${trimmed_checksums}"
Quality Check with FastQC and MultiQC
# Load bash variables into memory
source .bashvars
# Make output directory if it doesn't exist
mkdir --parents "${trimmed_fastqc_dir}"
############ RUN FASTQC ############
# Create array of trimmed FastQs
trimmed_fastqs_array=(${trimmed_fastqs_dir}/${trimmed_fastq_pattern})
# Pass array contents to new variable as space-delimited list
trimmed_fastqc_list=$(echo "${trimmed_fastqs_array[*]}")
echo "Beginning FastQC on trimmed reads..."
echo ""
# Run FastQC
### NOTE: Do NOT quote raw_fastqc_list
${programs_array[fastqc]} \
--threads ${threads} \
--outdir ${trimmed_fastqc_dir} \
--quiet \
${trimmed_fastqc_list}
echo "FastQC on trimmed reads complete!"
echo ""
############ END FASTQC ############
############ RUN MULTIQC ############
echo "Beginning MultiQC on trimmed FastQC..."
echo ""
${programs_array[multiqc]} ${trimmed_fastqc_dir} -o ${trimmed_fastqc_dir}
echo ""
echo "MultiQC on trimmed FastQs complete."
echo ""
############ END MULTIQC ############
echo "Removing FastQC zip files."
echo ""
rm ${trimmed_fastqc_dir}/*.zip
echo "FastQC zip files removed."
echo ""
Chen, Shifu. 2023.
“Ultrafast One-Pass FASTQ Data Preprocessing, Quality Control, and Deduplication Using Fastp.” iMeta 2 (2).
https://doi.org/10.1002/imt2.107.
Ewels, Philip, Måns Magnusson, Sverker Lundin, and Max Käller. 2016.
“MultiQC: Summarize Analysis Results for Multiple Tools and Samples in a Single Report.” Bioinformatics 32 (19): 3047–48.
https://doi.org/10.1093/bioinformatics/btw354.
LS0tCnRpdGxlOiAiMDEuMTAtRC1BcHVsLXNSTkFzZXEtdHJpbW1pbmctZmFzdHAtRmFzdFFDLU11bHRpUUMiCmF1dGhvcjogIkthdGhsZWVuIER1cmtpbiIKZGF0ZTogIjIwMjQtMTItMTgiCm91dHB1dDogCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICBnaXRodWJfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliCi0tLQoKTm90ZTogbW9kaWZpZWQgZnJvbSBTYW0gV2hpdGUncyBjb2RlIGluIFtgZGVlcC1kaXZlL0QtQXB1bC9jb2RlLzA4LjItQXB1bC1zUk5Bc2VxLXRyaW1taW5nLTMxYnAtZmFzdHAtbWVyZ2VkLlJtZGBdKGh0dHBzOi8vZ2l0aHViLmNvbS91cm9sLWU1L2RlZXAtZGl2ZS9ibG9iL21haW4vRC1BcHVsL2NvZGUvMDguMi1BcHVsLXNSTkFzZXEtdHJpbW1pbmctMzFicC1mYXN0cC1tZXJnZWQuUm1kKQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwgICAgICAgICAjIERpc3BsYXkgY29kZSBjaHVua3MKICBldmFsID0gRkFMU0UsICAgICAgICAjIEV2YWx1YXRlIGNvZGUgY2h1bmtzCiAgd2FybmluZyA9IEZBTFNFLCAgICAgIyBIaWRlIHdhcm5pbmdzCiAgbWVzc2FnZSA9IEZBTFNFLCAgICAgIyBIaWRlIG1lc3NhZ2VzCiAgY29tbWVudCA9ICIiICAgICAgICAgIyBQcmV2ZW50cyBhcHBlbmRpbmcgJyMjJyB0byBiZWdpbm5pbmcgb2YgbGluZXMgaW4gY29kZSBvdXRwdXQKKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKVGhpcyBSbWQgZmlsZSB0cmltcyAqQS5wdWxjaHJhKiBzUk5BLXNlcSBmaWxlcyB1c2luZyBbZmFzdHBdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuR2VuZS9mYXN0cCkgW0BjaGVuMjAyM10sIGZvbGxvd2VkIGJ5IHF1YWxpdHkgY2hlY2tzIHdpdGggW0Zhc3RRQ10oaHR0cHM6Ly9naXRodWIuY29tL3MtYW5kcmV3cy9GYXN0UUMpIGFuZCBbTXVsdGlRQ10oaHR0cHM6Ly9tdWx0aXFjLmluZm8vKVtAZXdlbHMyMDE2XS4KCkV4cGVjdHMgaW5wdXQgZmlsZXMgZm9ybWF0dGVkIGxpa2Ugc286IGA8bnVtYmVyPi0tPHNhbXBsZV9uYW1lPl9SWzEyXV8wMDEuZmFzdHEuZ3pgCgojIENyZWF0ZSBhIEJhc2ggdmFyaWFibGVzIGZpbGUKClRoaXMgYWxsb3dzIHVzYWdlIG9mIEJhc2ggdmFyaWFibGVzIGFjcm9zcyBSIE1hcmtkb3duIGNodW5rcy4KCmBgYHtyIHNhdmUtYmFzaC12YXJpYWJsZXMtdG8tcnZhcnMtZmlsZSwgZW5naW5lPSdiYXNoJywgZXZhbD1UUlVFfQp7CmVjaG8gIiMjIyMgQXNzaWduIFZhcmlhYmxlcyAjIyMjIgplY2hvICIiCgplY2hvICIjIERhdGEgZGlyZWN0b3JpZXMiCmVjaG8gJ2V4cG9ydCB0aW1lc2VyaWVzX2Rpcj0vaG9tZS9zaGFyZWQvOFRCX0hERF8wMi9zaGVkdXJraW4vdGltZXNlcmllc19tb2xlY3VsYXInCmVjaG8gJ2V4cG9ydCBvdXRwdXRfZGlyX3RvcD0ke3RpbWVzZXJpZXNfZGlyfS9ELUFwdWwvb3V0cHV0LzAxLjEwLUQtQXB1bC1zUk5Bc2VxLXRyaW1taW5nLWZhc3RwLUZhc3RRQy1NdWx0aVFDJwplY2hvICdleHBvcnQgcmF3X3JlYWRzX2Rpcj0ke3RpbWVzZXJpZXNfZGlyfS9ELUFwdWwvZGF0YS9yYXctZmFzdHFzLXNSTkEnCmVjaG8gJ2V4cG9ydCByYXdfcmVhZHNfdXJsPSJodHRwczovL293bC5maXNoLndhc2hpbmd0b24uZWR1L25pZ2h0aW5nYWxlcy9FNS1jb3JhbC10aW1lLXNlcmllcy8zMC0xMDY5Mjk3MDEzLyInCmVjaG8gJ2V4cG9ydCB0cmltbWVkX2Zhc3Rxc19kaXI9JHtvdXRwdXRfZGlyX3RvcH0vdHJpbW1lZC1mYXN0cXMtc1JOQScKZWNobyAnZXhwb3J0IHRyaW1tZWRfZmFzdHFjX2Rpcj0ke291dHB1dF9kaXJfdG9wfS90cmltbWVkLWZhc3RxYy1zUk5BJwplY2hvICIiCgplY2hvICIjIFBhdGhzIHRvIHByb2dyYW1zIgplY2hvICdleHBvcnQgcHJvZ3JhbXNfZGlyPSIvaG9tZS9zaGFyZWQiJwplY2hvICdleHBvcnQgZmFzdHA9L2hvbWUvc2hhcmVkL2Zhc3RwJwplY2hvICdleHBvcnQgZmFzdHFjPSR7cHJvZ3JhbXNfZGlyfS9GYXN0UUMtMC4xMi4xL2Zhc3RxYycKZWNobyAnZXhwb3J0IG11bHRpcWM9L2hvbWUvc2FtL3Byb2dyYW1zL21hbWJhZm9yZ2UvYmluL211bHRpcWMnCmVjaG8gIiIKCmVjaG8gIiMgU2V0IEZhc3RRIGZpbGVuYW1lIHBhdHRlcm5zIgplY2hvICJleHBvcnQgZmFzdHFfcGF0dGVybj0nKi5mYXN0cS5neiciCmVjaG8gImV4cG9ydCBSMV9mYXN0cV9wYXR0ZXJuPScqX1IxXyouZmFzdHEuZ3onIgplY2hvICJleHBvcnQgUjJfZmFzdHFfcGF0dGVybj0nKl9SMl8qLmZhc3RxLmd6JyIKZWNobyAiZXhwb3J0IHRyaW1tZWRfZmFzdHFfcGF0dGVybj0nKjMxYnAtbWVyZ2VkLmZxLmd6JyIKZWNobyAiIgoKZWNobyAiIyBTZXQgbnVtYmVyIG9mIENQVXMgdG8gdXNlIgplY2hvICdleHBvcnQgdGhyZWFkcz00MCcKZWNobyAiIgoKZWNobyAiIyBTZXQgbWF4aW11bSByZWFkIGxlbmd0aCIKZWNobyAnZXhwb3J0IG1heF9yZWFkX2xlbmd0aD0zMScKZWNobyAiIgoKZWNobyAiIyMgTkVCIG5lYm5leHQtc21hbGwtcm5hLWxpYnJhcnktcHJlcC1zZXQtZm9yLWlsbHVtaW5hIGFkYXB0ZXJzIgplY2hvICdleHBvcnQgTkVCX2FkYXB0ZXJzX2Zhc3RhPU5FQi1hZGFwdGVycy5mYXN0YScKZWNobyAnZXhwb3J0IGZpcnN0X2FkYXB0ZXI9IkFHQVRDR0dBQUdBR0NBQ0FDR1RDVEdBQUNUQ0NBR1RDQUMiJwplY2hvICdleHBvcnQgc2Vjb25kX2FkYXB0ZXI9IkdBVENHVENHR0FDVEdUQUdBQUNUQ1RHQUFDR1RHVEFHQVRDVENHR1RHR1RDR0NDR1RBVENBVFQiJwplY2hvICIiCgplY2hvICIjIyBJbml0aXRhbGl6ZSBhcnJheXMiCmVjaG8gJ2V4cG9ydCBmYXN0cV9hcnJheV9SMT0oKScKZWNobyAnZXhwb3J0IGZhc3RxX2FycmF5X1IyPSgpJwplY2hvICdleHBvcnQgcmF3X2Zhc3Rxc19hcnJheT0oKScKZWNobyAnZXhwb3J0IFIxX25hbWVzX2FycmF5PSgpJwplY2hvICdleHBvcnQgUjJfbmFtZXNfYXJyYXk9KCknCmVjaG8gJ2V4cG9ydCB0cmltbWVkX2Zhc3Rxc19hcnJheT0oKScKZWNobyAiIgoKZWNobyAiIyBQcm9ncmFtcyBhc3NvY2lhdGl2ZSBhcnJheSIKZWNobyAiZGVjbGFyZSAtQSBwcm9ncmFtc19hcnJheSIKZWNobyAicHJvZ3JhbXNfYXJyYXk9KCIKZWNobyAnW2Zhc3RwXT0iJHtmYXN0cH0iJwplY2hvICdbZmFzdHFjXT0iJHtmYXN0cWN9IiBcJwplY2hvICdbbXVsdGlxY109IiR7bXVsdGlxY30iIFwnCmVjaG8gIikiCmVjaG8gIiIKCmVjaG8gIiMgUHJpbnQgZm9ybWF0dGluZyIKZWNobyAnZXhwb3J0IGxpbmU9Ii0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIicKZWNobyAiIgp9ID4gLmJhc2h2YXJzCgpjYXQgLmJhc2h2YXJzCmBgYAoKSWYgbmVlZGVkLCBkb3dubG9hZCByYXcgUk5BLXNlcS4KCkFkZCBgZXZhbD1UUlVFYCB0byB0aGUgY2h1bmsgaGVhZGVyIHRvIGV4ZWN1dGUgdGhlIG5leHQgdHdvIGNodW5rcyB0byBkb3dubG9hZCBSTkEtc2VxIGFuZCB0aGVuIHZlcmlmeSBNRDUgY2hlY2tzdW1zLgoKYGBge2Jhc2ggZG93bmxvYWQtcmF3LXJlYWRzLCBlbmdpbmU9J2Jhc2gnfQojIExvYWQgYmFzaCB2YXJpYWJsZXMgaW50byBtZW1vcnkKc291cmNlIC5iYXNodmFycwoKIyBNYWtlIG91dHB1dCBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdApta2RpciAtLXBhcmVudHMgJHtyYXdfcmVhZHNfZGlyfQoKIyBDcmVhdGUgbGlzdCBvZiBvbmx5IEEucHVsY2hyYSBzYW1wbGUgbmFtZXMKc2FtcGxlX2xpc3Q9JChhd2sgLUYgIiwiICckNiB+IC9eQUNSLyB7cHJpbnQgJDV9JyAke3RpbWVzZXJpZXNfZGlyfS9NLW11bHRpLXNwZWNpZXMvZGF0YS9ybmFfbWV0YWRhdGEuY3N2KQoKZWNobyAiIgplY2hvICIke2xpbmV9IgplY2hvICIiCmVjaG8gIlNhbXBsZSBsaXN0OiIKZWNobyAiIgplY2hvICIke3NhbXBsZV9saXN0fSIKZWNobyAiIgplY2hvICIke2xpbmV9IgplY2hvICIiCgoKIyBVc2UgcHJpbnRmIHRvIGZvcm1hdCBlYWNoIGl0ZW0gZm9yIHVzZSBpbiB3Z2V0CmZvcm1hdHRlZF9saXN0PSQocHJpbnRmICIlc18qLCIgJHtzYW1wbGVfbGlzdH0pCgojIFJlbW92ZSB0aGUgdHJhaWxpbmcgY29tbWEKZm9ybWF0dGVkX2xpc3Q9JHtmb3JtYXR0ZWRfbGlzdCUsfQoKIyBPdXRwdXQgdGhlIGZpbmFsIHdnZXQgY29tbWFuZAplY2hvICIiCmVjaG8gIiR7bGluZX0iCmVjaG8gIiIKZWNobyAiRm9ybWF0dGVkIHdnZXQgYWNjZXB0IGxpc3Q6IgplY2hvICIiCmVjaG8gIndnZXQgLS1hY2NlcHQ9XCIkZm9ybWF0dGVkX2xpc3RcIiIKZWNobyAiIgplY2hvICIke2xpbmV9IgplY2hvICIiCgojIFJ1biB3Z2V0IHRvIHJldHJpZXZlIEZhc3RRcyBhbmQgTUQ1IGZpbGVzCiMgTm90ZTogdGhlIC0tbm8tY2xvYmJlciBjb21tYW5kIHdpbGwgc2tpcCByZS1kb3dubG9hZGluZyBhbnkgZmlsZXMgdGhhdCBhcmUgYWxyZWFkeSBwcmVzZW50IGluIHRoZSBvdXRwdXQgZGlyZWN0b3J5CndnZXQgXAotLWRpcmVjdG9yeS1wcmVmaXggJHtyYXdfcmVhZHNfZGlyfSBcCi0tcmVjdXJzaXZlIFwKLS1uby1jaGVjay1jZXJ0aWZpY2F0ZSBcCi0tY29udGludWUgXAotLWN1dC1kaXJzIDMgXAotLW5vLWhvc3QtZGlyZWN0b3JpZXMgXAotLW5vLXBhcmVudCBcCi0tcXVpZXQgXAotLW5vLWNsb2JiZXIgXAotLWFjY2VwdD0ke2Zvcm1hdHRlZF9saXN0fSAke3Jhd19yZWFkc191cmx9CgpscyAtbGggIiR7cmF3X3JlYWRzX2Rpcn0iCmBgYAoKVmVyaWZ5IHJhdyByZWFkIGNoZWNrc3VtcwpgYGB7YmFzaCB2ZXJpZnktcmF3LXJlYWQtY2hlY2tzdW1zLCBlbmdpbmU9J2Jhc2gnfQojIExvYWQgYmFzaCB2YXJpYWJsZXMgaW50byBtZW1vcnkKc291cmNlIC5iYXNodmFycwoKY2QgIiR7cmF3X3JlYWRzX2Rpcn0iCgojIENoZWNrc3VtcyBmaWxlIGNvbnRhaW5zIG90aGVyIGZpbGVzLCBzbyB0aGlzIGp1c3QgbG9va3MgZm9yIHRoZSBzUk5Bc2VxIGZpbGVzLgpmb3IgZmlsZSBpbiAqLm1kNQpkbwogIG1kNXN1bSAtLWNoZWNrICIke2ZpbGV9Igpkb25lCmBgYAoKIyBDcmVhdGUgYWRhcHRlcnMgRmFzdEEgZm9yIHVzZSB3aXRoIFtgZmFzdHBgXShodHRwczovL2dpdGh1Yi5jb20vT3BlbkdlbmUvZmFzdHApIHRyaW1taW5nCgpgYGB7YmFzaCBjcmVhdGUtRmFzdEEtb2YtYWRhcHRlcnMsIGVuZ2luZT0nYmFzaCd9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgpta2RpciAtLXBhcmVudHMgIiR7b3V0cHV0X2Rpcl90b3B9IgoKZWNobyAiQ3JlYXRpbmcgYWRhcHRlcnMgRmFzdEEuIgplY2hvICIiCmFkYXB0ZXJfY291bnQ9MAoKIyBDaGVjayBmb3IgYWRhcHRlcnMgZmlsZSBmaXJzdAojIFRoZW4gY3JlYXRlIGFkYXB0ZXJzIGZpbGUgaWYgZG9lc24ndCBleGlzdAppZiBbIC1mICIke291dHB1dF9kaXJfdG9wfS8ke05FQl9hZGFwdGVyc19mYXN0YX0iIF07IHRoZW4KICBlY2hvICIke291dHB1dF9kaXJfdG9wfS8ke05FQl9hZGFwdGVyc19mYXN0YX0gYWxyZWFkeSBleGlzdHMuIE5vdGhpbmcgdG8gZG8uIgplbHNlCiAgZm9yIGFkYXB0ZXIgaW4gIiR7Zmlyc3RfYWRhcHRlcn0iICIke3NlY29uZF9hZGFwdGVyfSIKICBkbwogICAgYWRhcHRlcl9jb3VudD0kKChhZGFwdGVyX2NvdW50ICsgMSkpCiAgICBwcmludGYgIj4lc1xuJXNcbiIgImFkYXB0ZXJfJHthZGFwdGVyX2NvdW50fSIgIiR7YWRhcHRlcn0iCiAgZG9uZSA+PiAiJHtvdXRwdXRfZGlyX3RvcH0vJHtORUJfYWRhcHRlcnNfZmFzdGF9IgpmaQoKZWNobyAiIgplY2hvICJBZGFwdGVycyBGYXN0QToiCmVjaG8gIiIKY2F0ICIke291dHB1dF9kaXJfdG9wfS8ke05FQl9hZGFwdGVyc19mYXN0YX0iCmVjaG8gIiIKYGBgCgojIEZhc3RwIFRyaW1taW5nCgpbZmFzdHBdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuR2VuZS9mYXN0cCkgW0BjaGVuMjAyM10gaXMgc2V0IHRvIGF1dG8tZGV0ZWN0IElsbHVtaW5hIGFkYXB0ZXJzLCBhcyB3ZWxsIGFzIHRyaW0gdGhlIGZpcnN0IDIwYnAgZnJvbSBlYWNoIHJlYWQsIGFzIHBhc3QgZXhwZXJpZW5jZSBzaG93cyB0aGVzZSBmaXJzdCAyMGJwIGFyZSBtb3JlIGluY29uc2lzdGVudCB0aGFuIHRoZSByZW1haW5kZXIgb2YgdGhlIHJlYWQgbGVuZ3RoLgoKYGBge2Jhc2ggZmFzdHAtdHJpbW1pbmcsIGVuZ2luZT0nYmFzaCd9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgojIE1ha2Ugb3V0cHV0IGRpcmVjdG9yaWVzLCBpZiBpdCBkb2Vzbid0IGV4aXN0Cm1rZGlyIC0tcGFyZW50cyAiJHt0cmltbWVkX2Zhc3Rxc19kaXJ9IgoKIyBDaGFuZ2UgdG8gcmF3IHJlYWRzIGRpcmVjdG9yeQpjZCAiJHtyYXdfcmVhZHNfZGlyfSIKCiMgQ3JlYXRlIGFycmF5cyBvZiBmYXN0cSBSMSBmaWxlcyBhbmQgc2FtcGxlIG5hbWVzCmZvciBmYXN0cSBpbiAke1IxX2Zhc3RxX3BhdHRlcm59CmRvCiAgZmFzdHFfYXJyYXlfUjErPSgiJHtmYXN0cX0iKQogIFIxX25hbWVzX2FycmF5Kz0oIiQoZWNobyAiJHtmYXN0cX0iIHwgYXdrIC1GIl8iICd7cHJpbnQgJDF9JykiKQpkb25lCgojIENyZWF0ZSBhcnJheSBvZiBmYXN0cSBSMiBmaWxlcwpmb3IgZmFzdHEgaW4gJHtSMl9mYXN0cV9wYXR0ZXJufQpkbwogIGZhc3RxX2FycmF5X1IyKz0oIiR7ZmFzdHF9IikKICBSMl9uYW1lc19hcnJheSs9KCIkKGVjaG8gIiR7ZmFzdHF9IiB8IGF3ayAtRiJfIiAne3ByaW50ICQxfScpIikKZG9uZQoKIyBDcmVhdGUgbGlzdCBvZiBmYXN0cSBmaWxlcyB1c2VkIGluIGFuYWx5c2lzCiMgQ3JlYXRlIE1ENSBjaGVja3N1bSBmb3IgcmVmZXJlbmNlCmlmIFsgISAtZiAiJHtvdXRwdXRfZGlyX3RvcH0iL3Jhdy1mYXN0cS1jaGVja3N1bXMubWQ1IF07IHRoZW4KZm9yIGZhc3RxIGluICouZ3oKICBkbwogICAgbWQ1c3VtICR7ZmFzdHF9ID4+ICIke291dHB1dF9kaXJfdG9wfSIvcmF3LWZhc3RxLWNoZWNrc3Vtcy5tZDUKICBkb25lCmZpCgojIyMjIyMjIyMjIyMgUlVOIEZBU1RQICMjIyMjIyMjIyMjIwojIFVzZXMgcGFyYW1ldGVyIHN1YnN0aXR1dGlvbiAoZS5nLiAke1IxX3NhbXBsZV9uYW1lJSVfKn0pdG8gcm0gdGhlIF9SWzEyXQoKIyBSdW4gZmFzdHAgb24gZmlsZXMKZWNobyAiQmVnaW5uaW5nIGZhc3RwIHRyaW1taW5nLiIKZWNobyAiIgoKdGltZSBcCmZvciBpbmRleCBpbiAiJHshZmFzdHFfYXJyYXlfUjFbQF19IgpkbwogICMgR2V0IHNhbXBsZSBuYW1lCiAgUjFfc2FtcGxlX25hbWU9IiR7UjFfbmFtZXNfYXJyYXlbaW5kZXhdJSVfKn0iCgogICMgU2V0IGZhc3RwIHJlcG9ydCB0aXRsZQogIHRyaW1tZWRfZmFzdHBfcmVwb3J0X3RpdGxlPSIke1IxX3NhbXBsZV9uYW1lfS1mYXN0cC1hZGFwdGVycy1wb2x5Ry0ke21heF9yZWFkX2xlbmd0aH1icC1tZXJnZWQiCiAgCiAgIyBTZXQgbWVyZ2VkIG91dHB1dCBsb2NhdGlvbiBhbmQgZmlsZW5hbWUKICBtZXJnZWRfb3V0cHV0PSR7dHJpbW1lZF9mYXN0cXNfZGlyfS8ke3RyaW1tZWRfZmFzdHBfcmVwb3J0X3RpdGxlfS5mcS5negoKICAjIEJlZ2luIGZhc3RwIHRyaW1taW5nCiAgJHtwcm9ncmFtc19hcnJheVtmYXN0cF19IFwKICAtLWluMSAke2Zhc3RxX2FycmF5X1IxW2luZGV4XX0gXAogIC0taW4yICR7ZmFzdHFfYXJyYXlfUjJbaW5kZXhdfSBcCiAgLS1hZGFwdGVyX2Zhc3RhICR7b3V0cHV0X2Rpcl90b3B9LyR7TkVCX2FkYXB0ZXJzX2Zhc3RhfSBcCiAgLS10cmltX3BvbHlfZyBcCiAgLS1vdmVybGFwX2xlbl9yZXF1aXJlIDE3IFwKICAtLWxlbmd0aF9saW1pdCAzMSBcCiAgLS1tZXJnZSBcCiAgLS1tZXJnZWRfb3V0ICR7bWVyZ2VkX291dHB1dH0gXAogIC0tdGhyZWFkICR7dGhyZWFkc30gXAogIC0taHRtbCAiJHt0cmltbWVkX2Zhc3RwX3JlcG9ydF90aXRsZX0uaHRtbCIgXAogIC0tanNvbiAiJHt0cmltbWVkX2Zhc3RwX3JlcG9ydF90aXRsZX0uanNvbiIgXAogIC0tcmVwb3J0X3RpdGxlICIke3RyaW1tZWRfZmFzdHBfcmVwb3J0X3RpdGxlfSIKICAgIAogICMgTW92ZSB0byB0cmltbWVkIGRpcmVjdG9yeQogICMgVGhpcyBpcyBkb25lIHNvIGNoZWNrc3VtcyBmaWxlIGRvZXNuJ3QgaW5jbHVkZSBleGNlc3MgcGF0aAogIGNkICR7dHJpbW1lZF9mYXN0cXNfZGlyfQoKICAjIEdlbmVyYXRlIG1kNSBjaGVja3N1bXMgZm9yIG5ld2x5IHRyaW1tZWQgZmlsZXMKICB7CiAgICBtZDVzdW0gIiR7dHJpbW1lZF9mYXN0cF9yZXBvcnRfdGl0bGV9LmZxLmd6IgogIH0gPj4gIiR7dHJpbW1lZF9jaGVja3N1bXN9IgogIAogICMgQ2hhbmdlIGJhY2sgdG8gdG8gcmF3IHJlYWRzIGRpcmVjdG9yeQogIGNkICIke3Jhd19yZWFkc19kaXJ9IgoKZG9uZQoKZWNobyAiIgplY2hvICJmYXN0cCB0cmltbWluZyBjb21wbGV0ZS4iCmVjaG8gIiIKCmVjaG8gIlRyaW1tZWQgRmFzdFFzIE1ENSBjaGVja3N1bXM6IgplY2hvICIiCgpjYXQgIiR7dHJpbW1lZF9mYXN0cXNfZGlyfS8ke3RyaW1tZWRfY2hlY2tzdW1zfSIKYGBgCgojIFF1YWxpdHkgQ2hlY2sgd2l0aCBGYXN0UUMgYW5kIE11bHRpUUMKYGBge2Jhc2ggdHJpbW1lZC1mYXN0cWMtbXVsdGlxYywgZW5naW5lPSdiYXNoJ30KIyBMb2FkIGJhc2ggdmFyaWFibGVzIGludG8gbWVtb3J5CnNvdXJjZSAuYmFzaHZhcnMKCiMgTWFrZSBvdXRwdXQgZGlyZWN0b3J5IGlmIGl0IGRvZXNuJ3QgZXhpc3QKbWtkaXIgLS1wYXJlbnRzICIke3RyaW1tZWRfZmFzdHFjX2Rpcn0iCgojIyMjIyMjIyMjIyMgUlVOIEZBU1RRQyAjIyMjIyMjIyMjIyMKCgojIENyZWF0ZSBhcnJheSBvZiB0cmltbWVkIEZhc3RRcwp0cmltbWVkX2Zhc3Rxc19hcnJheT0oJHt0cmltbWVkX2Zhc3Rxc19kaXJ9LyR7dHJpbW1lZF9mYXN0cV9wYXR0ZXJufSkKCiMgUGFzcyBhcnJheSBjb250ZW50cyB0byBuZXcgdmFyaWFibGUgYXMgc3BhY2UtZGVsaW1pdGVkIGxpc3QKdHJpbW1lZF9mYXN0cWNfbGlzdD0kKGVjaG8gIiR7dHJpbW1lZF9mYXN0cXNfYXJyYXlbKl19IikKCmVjaG8gIkJlZ2lubmluZyBGYXN0UUMgb24gdHJpbW1lZCByZWFkcy4uLiIKZWNobyAiIgoKIyBSdW4gRmFzdFFDCiMjIyBOT1RFOiBEbyBOT1QgcXVvdGUgcmF3X2Zhc3RxY19saXN0CiR7cHJvZ3JhbXNfYXJyYXlbZmFzdHFjXX0gXAotLXRocmVhZHMgJHt0aHJlYWRzfSBcCi0tb3V0ZGlyICR7dHJpbW1lZF9mYXN0cWNfZGlyfSBcCi0tcXVpZXQgXAoke3RyaW1tZWRfZmFzdHFjX2xpc3R9CgplY2hvICJGYXN0UUMgb24gdHJpbW1lZCByZWFkcyBjb21wbGV0ZSEiCmVjaG8gIiIKCiMjIyMjIyMjIyMjIyBFTkQgRkFTVFFDICMjIyMjIyMjIyMjIwoKIyMjIyMjIyMjIyMjIFJVTiBNVUxUSVFDICMjIyMjIyMjIyMjIwplY2hvICJCZWdpbm5pbmcgTXVsdGlRQyBvbiB0cmltbWVkIEZhc3RRQy4uLiIKZWNobyAiIgoKJHtwcm9ncmFtc19hcnJheVttdWx0aXFjXX0gJHt0cmltbWVkX2Zhc3RxY19kaXJ9IC1vICR7dHJpbW1lZF9mYXN0cWNfZGlyfQoKZWNobyAiIgplY2hvICJNdWx0aVFDIG9uIHRyaW1tZWQgRmFzdFFzIGNvbXBsZXRlLiIKZWNobyAiIgoKIyMjIyMjIyMjIyMjIEVORCBNVUxUSVFDICMjIyMjIyMjIyMjIwoKZWNobyAiUmVtb3ZpbmcgRmFzdFFDIHppcCBmaWxlcy4iCmVjaG8gIiIKcm0gJHt0cmltbWVkX2Zhc3RxY19kaXJ9LyouemlwCmVjaG8gIkZhc3RRQyB6aXAgZmlsZXMgcmVtb3ZlZC4iCmVjaG8gIiIKYGBgCgo=