This Rmd file trims A.pulchra RNA-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
All trimmed FastQs produced by this script are here:
01.00-D-Apul-RNAseq-trimming-fastp-FastQC-MultiQC/trimmed-fastqs/
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.00-D-Apul-RNAseq-trimming-fastp-FastQC-MultiQC'
echo 'export raw_reads_dir=${timeseries_dir}/D-Apul/data/raw-fastqs'
echo 'export raw_reads_url="https://owl.fish.washington.edu/nightingales/E5-coral-time-series/30-1047560508/"'
echo 'export trimmed_fastqs_dir=${output_dir_top}/trimmed-fastqs'
echo 'export trimmed_fastqc_dir=${output_dir_top}/trimmed-fastqc'
echo ""
echo "# Paths to programs"
echo 'export programs_dir="/home/shared"'
echo 'export fastp="${programs_dir}/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='*fastp-trim.fq.gz'"
echo ""
echo "# Set number of CPUs to use"
echo 'export threads=40'
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 ""
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.00-D-Apul-RNAseq-trimming-fastp-FastQC-MultiQC
export raw_reads_dir=${timeseries_dir}/D-Apul/data/raw-fastqs
export raw_reads_url="https://owl.fish.washington.edu/nightingales/E5-coral-time-series/30-1047560508/"
export trimmed_fastqs_dir=${output_dir_top}/trimmed-fastqs
export trimmed_fastqc_dir=${output_dir_top}/trimmed-fastqc
# Paths to programs
export programs_dir="/home/shared"
export fastp="${programs_dir}/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='*fastp-trim.fq.gz'
# Set number of CPUs to use
export threads=40
## Inititalize arrays
export fastq_array_R1=()
export fastq_array_R2=()
export raw_fastqs_array=()
export R1_names_array=()
export R2_names_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.
Change eval=FALSE
to eval=TRUE
to execute the next two chunks to download RNA-seq and then verify MD5 checksums.
source .bashvars
mkdir --parents ${raw_reads_dir}
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 ""
formatted_list=$(printf "*%s_*," ${sample_list})
formatted_list=${formatted_list%,}
echo ""
echo "${line}"
echo ""
echo "Formatted wget accept list:"
echo ""
echo "wget --accept=\"$formatted_list\""
echo ""
echo "${line}"
echo ""
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
source .bashvars
cd "${raw_reads_dir}"
for file in *.md5
do
md5sum --check "${file}"
done
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.
source .bashvars
mkdir --parents "${trimmed_fastqs_dir}"
cd "${raw_reads_dir}"
for fastq in ${R1_fastq_pattern}
do
fastq_array_R1+=("${fastq}")
R1_names_array+=("$(echo "${fastq}" | awk -F"_" '{print $1}')")
done
for fastq in ${R2_fastq_pattern}
do
fastq_array_R2+=("${fastq}")
R2_names_array+=("$(echo "${fastq}" | awk -F"_" '{print $1}')")
done
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
for index in "${!fastq_array_R1[@]}"
do
R1_sample_name=$(echo "${R1_names_array[index]}")
R2_sample_name=$(echo "${R2_names_array[index]}")
${fastp} \
--in1 ${fastq_array_R1[index]} \
--in2 ${fastq_array_R2[index]} \
--detect_adapter_for_pe \
--trim_front1 20 \
--trim_front2 20 \
--thread ${threads} \
--html "${trimmed_fastqs_dir}"/"${R1_sample_name}".fastp-trim.report.html \
--json "${trimmed_fastqs_dir}"/"${R1_sample_name}".fastp-trim.report.json \
--out1 "${trimmed_fastqs_dir}"/"${R1_sample_name}"_R1_001.fastp-trim.fq.gz \
--out2 "${trimmed_fastqs_dir}"/"${R2_sample_name}"_R2_001.fastp-trim.fq.gz \
2>> "${trimmed_fastqs_dir}"/fastp.stderr
cd "${trimmed_fastqs_dir}"
md5sum "${R1_sample_name}"_R1_001.fastp-trim.fq.gz > "${R1_sample_name}"_R1_001.fastp-trim.fq.gz.md5
md5sum "${R2_sample_name}"_R2_001.fastp-trim.fq.gz > "${R2_sample_name}"_R2_001.fastp-trim.fq.gz.md5
cd -
done
Quality Check with FastQC and MultiQC
source .bashvars
mkdir --parents "${trimmed_fastqc_dir}"
trimmed_fastqs_array=(${trimmed_fastqs_dir}/${trimmed_fastq_pattern})
trimmed_fastqc_list=$(echo "${trimmed_fastqs_array[*]}")
echo "Beginning FastQC on trimmed reads..."
echo ""
${programs_array[fastqc]} \
--threads ${threads} \
--outdir ${trimmed_fastqc_dir} \
--quiet \
${trimmed_fastqc_list}
echo "FastQC on trimmed reads complete!"
echo ""
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 ""
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.
LS0tCnRpdGxlOiAiMDEuMDAtRC1BcHVsLVJOQXNlcS10cmltbWluZy1mYXN0cC1GYXN0UUMtTXVsdGlRQyIKYXV0aG9yOiAiU2FtIFdoaXRlIgpkYXRlOiAiMjAyNC0xMC0wNSIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGdpdGh1Yl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmJpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShrbml0cikKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLCAgICAgICAgICMgRGlzcGxheSBjb2RlIGNodW5rcwogIGV2YWwgPSBGQUxTRSwgICAgICAgICMgRXZhbHVhdGUgY29kZSBjaHVua3MKICB3YXJuaW5nID0gRkFMU0UsICAgICAjIEhpZGUgd2FybmluZ3MKICBtZXNzYWdlID0gRkFMU0UsICAgICAjIEhpZGUgbWVzc2FnZXMKICBjb21tZW50ID0gIiIgICAgICAgICAjIFByZXZlbnRzIGFwcGVuZGluZyAnIyMnIHRvIGJlZ2lubmluZyBvZiBsaW5lcyBpbiBjb2RlIG91dHB1dAopCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpUaGlzIFJtZCBmaWxlIHRyaW1zICpBLnB1bGNocmEqIFJOQS1zZXEgZmlsZXMgdXNpbmcgW2Zhc3RwXShodHRwczovL2dpdGh1Yi5jb20vT3BlbkdlbmUvZmFzdHApIFtAY2hlbjIwMjNdLCBmb2xsb3dlZCBieSBxdWFsaXR5IGNoZWNrcyB3aXRoIFtGYXN0UUNdKGh0dHBzOi8vZ2l0aHViLmNvbS9zLWFuZHJld3MvRmFzdFFDKSBhbmQgW011bHRpUUNdKGh0dHBzOi8vbXVsdGlxYy5pbmZvLylbQGV3ZWxzMjAxNl0uCgpFeHBlY3RzIGlucHV0IGZpbGVzIGZvcm1hdHRlZCBsaWtlIHNvOiBgPG51bWJlcj4tLTxzYW1wbGVfbmFtZT5fUlsxMl1fMDAxLmZhc3RxLmd6YAoKQWxsIHRyaW1tZWQgRmFzdFFzIHByb2R1Y2VkIGJ5IHRoaXMgc2NyaXB0IGFyZSBoZXJlOgoKWzAxLjAwLUQtQXB1bC1STkFzZXEtdHJpbW1pbmctZmFzdHAtRmFzdFFDLU11bHRpUUMvdHJpbW1lZC1mYXN0cXMvXShodHRwczovL2dhbm5ldC5maXNoLndhc2hpbmd0b24uZWR1L0F0dW1lZmFjaWVucy9naXRyZXBvcy91cm9sLWU1L3RpbWVzZXJpZXNfbW9sZWN1bGFyL0QtQXB1bC9vdXRwdXQvMDEuMDAtRC1BcHVsLVJOQXNlcS10cmltbWluZy1mYXN0cC1GYXN0UUMtTXVsdGlRQy90cmltbWVkLWZhc3Rxcy8pCgojIENyZWF0ZSBhIEJhc2ggdmFyaWFibGVzIGZpbGUKClRoaXMgYWxsb3dzIHVzYWdlIG9mIEJhc2ggdmFyaWFibGVzIGFjcm9zcyBSIE1hcmtkb3duIGNodW5rcy4KCmBgYHtyIHNhdmUtYmFzaC12YXJpYWJsZXMtdG8tcnZhcnMtZmlsZSwgZW5naW5lPSdiYXNoJywgZXZhbD1UUlVFfQp7CmVjaG8gIiMjIyMgQXNzaWduIFZhcmlhYmxlcyAjIyMjIgplY2hvICIiCgplY2hvICIjIERhdGEgZGlyZWN0b3JpZXMiCmVjaG8gJ2V4cG9ydCB0aW1lc2VyaWVzX2Rpcj0vaG9tZS9zaGFyZWQvOFRCX0hERF8wMi9zaGVkdXJraW4vdGltZXNlcmllc19tb2xlY3VsYXInCmVjaG8gJ2V4cG9ydCBvdXRwdXRfZGlyX3RvcD0ke3RpbWVzZXJpZXNfZGlyfS9ELUFwdWwvb3V0cHV0LzAxLjAwLUQtQXB1bC1STkFzZXEtdHJpbW1pbmctZmFzdHAtRmFzdFFDLU11bHRpUUMnCmVjaG8gJ2V4cG9ydCByYXdfcmVhZHNfZGlyPSR7dGltZXNlcmllc19kaXJ9L0QtQXB1bC9kYXRhL3Jhdy1mYXN0cXMnCmVjaG8gJ2V4cG9ydCByYXdfcmVhZHNfdXJsPSJodHRwczovL293bC5maXNoLndhc2hpbmd0b24uZWR1L25pZ2h0aW5nYWxlcy9FNS1jb3JhbC10aW1lLXNlcmllcy8zMC0xMDQ3NTYwNTA4LyInCmVjaG8gJ2V4cG9ydCB0cmltbWVkX2Zhc3Rxc19kaXI9JHtvdXRwdXRfZGlyX3RvcH0vdHJpbW1lZC1mYXN0cXMnCmVjaG8gJ2V4cG9ydCB0cmltbWVkX2Zhc3RxY19kaXI9JHtvdXRwdXRfZGlyX3RvcH0vdHJpbW1lZC1mYXN0cWMnCmVjaG8gIiIKCmVjaG8gIiMgUGF0aHMgdG8gcHJvZ3JhbXMiCmVjaG8gJ2V4cG9ydCBwcm9ncmFtc19kaXI9Ii9ob21lL3NoYXJlZCInCmVjaG8gJ2V4cG9ydCBmYXN0cD0iJHtwcm9ncmFtc19kaXJ9L2Zhc3RwIicKZWNobyAnZXhwb3J0IGZhc3RxYz0ke3Byb2dyYW1zX2Rpcn0vRmFzdFFDLTAuMTIuMS9mYXN0cWMnCmVjaG8gJ2V4cG9ydCBtdWx0aXFjPS9ob21lL3NhbS9wcm9ncmFtcy9tYW1iYWZvcmdlL2Jpbi9tdWx0aXFjJwplY2hvICIiCgplY2hvICIjIFNldCBGYXN0USBmaWxlbmFtZSBwYXR0ZXJucyIKZWNobyAiZXhwb3J0IGZhc3RxX3BhdHRlcm49JyouZmFzdHEuZ3onIgplY2hvICJleHBvcnQgUjFfZmFzdHFfcGF0dGVybj0nKl9SMV8qLmZhc3RxLmd6JyIKZWNobyAiZXhwb3J0IFIyX2Zhc3RxX3BhdHRlcm49JypfUjJfKi5mYXN0cS5neiciCmVjaG8gImV4cG9ydCB0cmltbWVkX2Zhc3RxX3BhdHRlcm49JypmYXN0cC10cmltLmZxLmd6JyIKZWNobyAiIgoKZWNobyAiIyBTZXQgbnVtYmVyIG9mIENQVXMgdG8gdXNlIgplY2hvICdleHBvcnQgdGhyZWFkcz00MCcKZWNobyAiIgoKCmVjaG8gIiMjIEluaXRpdGFsaXplIGFycmF5cyIKZWNobyAnZXhwb3J0IGZhc3RxX2FycmF5X1IxPSgpJwplY2hvICdleHBvcnQgZmFzdHFfYXJyYXlfUjI9KCknCmVjaG8gJ2V4cG9ydCByYXdfZmFzdHFzX2FycmF5PSgpJwplY2hvICdleHBvcnQgUjFfbmFtZXNfYXJyYXk9KCknCmVjaG8gJ2V4cG9ydCBSMl9uYW1lc19hcnJheT0oKScKZWNobyAiIgoKZWNobyAiIyBQcm9ncmFtcyBhc3NvY2lhdGl2ZSBhcnJheSIKZWNobyAiZGVjbGFyZSAtQSBwcm9ncmFtc19hcnJheSIKZWNobyAicHJvZ3JhbXNfYXJyYXk9KCIKZWNobyAnW2Zhc3RwXT0iJHtmYXN0cH0iIFwnCmVjaG8gJ1tmYXN0cWNdPSIke2Zhc3RxY30iIFwnCmVjaG8gJ1ttdWx0aXFjXT0iJHttdWx0aXFjfSIgXCcKZWNobyAiKSIKZWNobyAiIgoKZWNobyAiIyBQcmludCBmb3JtYXR0aW5nIgplY2hvICdleHBvcnQgbGluZT0iLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0iJwplY2hvICIiCn0gPiAuYmFzaHZhcnMKCmNhdCAuYmFzaHZhcnMKYGBgCgpJZiBuZWVkZWQsIGRvd25sb2FkIHJhdyBSTkEtc2VxLgoKQ2hhbmdlIGBldmFsPUZBTFNFYCB0byBgZXZhbD1UUlVFYCB0byBleGVjdXRlIHRoZSBuZXh0IHR3byBjaHVua3MgdG8gZG93bmxvYWQgUk5BLXNlcSBhbmQgdGhlbiB2ZXJpZnkgTUQ1IGNoZWNrc3Vtcy4KCmBgYHtiYXNoIGRvd25sb2FkLXJhdy1yZWFkcywgZW5naW5lPSdiYXNoJ30KIyBMb2FkIGJhc2ggdmFyaWFibGVzIGludG8gbWVtb3J5CnNvdXJjZSAuYmFzaHZhcnMKCiMgTWFrZSBvdXRwdXQgZGlyZWN0b3J5IGlmIGl0IGRvZXNuJ3QgZXhpc3QKbWtkaXIgLS1wYXJlbnRzICR7cmF3X3JlYWRzX2Rpcn0KCiMgQ3JlYXRlIGxpc3Qgb2Ygb25seSBBLnB1bGNocmEgc2FtcGxlIG5hbWVzCnNhbXBsZV9saXN0PSQoYXdrIC1GICIsIiAnJDYgfiAvXkFDUi8ge3ByaW50ICQ1fScgJHt0aW1lc2VyaWVzX2Rpcn0vTS1tdWx0aS1zcGVjaWVzL2RhdGEvcm5hX21ldGFkYXRhLmNzdikKCmVjaG8gIiIKZWNobyAiJHtsaW5lfSIKZWNobyAiIgplY2hvICJTYW1wbGUgbGlzdDoiCmVjaG8gIiIKZWNobyAiJHtzYW1wbGVfbGlzdH0iCmVjaG8gIiIKZWNobyAiJHtsaW5lfSIKZWNobyAiIgoKCiMgVXNlIHByaW50ZiB0byBmb3JtYXQgZWFjaCBpdGVtIGZvciB1c2UgaW4gd2dldApmb3JtYXR0ZWRfbGlzdD0kKHByaW50ZiAiKiVzXyosIiAke3NhbXBsZV9saXN0fSkKCiMgUmVtb3ZlIHRoZSB0cmFpbGluZyBjb21tYQpmb3JtYXR0ZWRfbGlzdD0ke2Zvcm1hdHRlZF9saXN0JSx9CgojIE91dHB1dCB0aGUgZmluYWwgd2dldCBjb21tYW5kCmVjaG8gIiIKZWNobyAiJHtsaW5lfSIKZWNobyAiIgplY2hvICJGb3JtYXR0ZWQgd2dldCBhY2NlcHQgbGlzdDoiCmVjaG8gIiIKZWNobyAid2dldCAtLWFjY2VwdD1cIiRmb3JtYXR0ZWRfbGlzdFwiIgplY2hvICIiCmVjaG8gIiR7bGluZX0iCmVjaG8gIiIKCiMgUnVuIHdnZXQgdG8gcmV0cmlldmUgRmFzdFFzIGFuZCBNRDUgZmlsZXMKIyBOb3RlOiB0aGUgLS1uby1jbG9iYmVyIGNvbW1hbmQgd2lsbCBza2lwIHJlLWRvd25sb2FkaW5nIGFueSBmaWxlcyB0aGF0IGFyZSBhbHJlYWR5IHByZXNlbnQgaW4gdGhlIG91dHB1dCBkaXJlY3RvcnkKd2dldCBcCi0tZGlyZWN0b3J5LXByZWZpeCAke3Jhd19yZWFkc19kaXJ9IFwKLS1yZWN1cnNpdmUgXAotLW5vLWNoZWNrLWNlcnRpZmljYXRlIFwKLS1jb250aW51ZSBcCi0tY3V0LWRpcnMgMyBcCi0tbm8taG9zdC1kaXJlY3RvcmllcyBcCi0tbm8tcGFyZW50IFwKLS1xdWlldCBcCi0tbm8tY2xvYmJlciBcCi0tYWNjZXB0PSR7Zm9ybWF0dGVkX2xpc3R9ICR7cmF3X3JlYWRzX3VybH0KCmxzIC1saCAiJHtyYXdfcmVhZHNfZGlyfSIKYGBgCgpWZXJpZnkgcmF3IHJlYWQgY2hlY2tzdW1zCmBgYHtiYXNoIHZlcmlmeS1yYXctcmVhZC1jaGVja3N1bXMsIGVuZ2luZT0nYmFzaCd9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgpjZCAiJHtyYXdfcmVhZHNfZGlyfSIKCiMgQ2hlY2tzdW1zIGZpbGUgY29udGFpbnMgb3RoZXIgZmlsZXMsIHNvIHRoaXMganVzdCBsb29rcyBmb3IgdGhlIHNSTkFzZXEgZmlsZXMuCmZvciBmaWxlIGluICoubWQ1CmRvCiAgbWQ1c3VtIC0tY2hlY2sgIiR7ZmlsZX0iCmRvbmUKYGBgCgojIEZhc3RwIFRyaW1taW5nCgpbZmFzdHBdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuR2VuZS9mYXN0cCkgW0BjaGVuMjAyM10gaXMgc2V0IHRvIGF1dG8tZGV0ZWN0IElsbHVtaW5hIGFkYXB0ZXJzLCBhcyB3ZWxsIGFzIHRyaW0gdGhlIGZpcnN0IDIwYnAgZnJvbSBlYWNoIHJlYWQsIGFzIHBhc3QgZXhwZXJpZW5jZSBzaG93cyB0aGVzZSBmaXJzdCAyMGJwIGFyZSBtb3JlIGluY29uc2lzdGVudCB0aGFuIHRoZSByZW1haW5kZXIgb2YgdGhlIHJlYWQgbGVuZ3RoLgoKYGBge2Jhc2ggZmFzdHAtdHJpbW1pbmcsIGVuZ2luZT0nYmFzaCd9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgojIE1ha2Ugb3V0cHV0IGRpcmVjdG9yaWVzLCBpZiBpdCBkb2Vzbid0IGV4aXN0Cm1rZGlyIC0tcGFyZW50cyAiJHt0cmltbWVkX2Zhc3Rxc19kaXJ9IgoKIyBDaGFuZ2UgdG8gcmF3IHJlYWRzIGRpcmVjdG9yeQpjZCAiJHtyYXdfcmVhZHNfZGlyfSIKCiMgQ3JlYXRlIGFycmF5cyBvZiBmYXN0cSBSMSBmaWxlcyBhbmQgc2FtcGxlIG5hbWVzCmZvciBmYXN0cSBpbiAke1IxX2Zhc3RxX3BhdHRlcm59CmRvCiAgZmFzdHFfYXJyYXlfUjErPSgiJHtmYXN0cX0iKQogIFIxX25hbWVzX2FycmF5Kz0oIiQoZWNobyAiJHtmYXN0cX0iIHwgYXdrIC1GIl8iICd7cHJpbnQgJDF9JykiKQpkb25lCgojIENyZWF0ZSBhcnJheSBvZiBmYXN0cSBSMiBmaWxlcwpmb3IgZmFzdHEgaW4gJHtSMl9mYXN0cV9wYXR0ZXJufQpkbwogIGZhc3RxX2FycmF5X1IyKz0oIiR7ZmFzdHF9IikKICBSMl9uYW1lc19hcnJheSs9KCIkKGVjaG8gIiR7ZmFzdHF9IiB8IGF3ayAtRiJfIiAne3ByaW50ICQxfScpIikKZG9uZQoKIyBDcmVhdGUgbGlzdCBvZiBmYXN0cSBmaWxlcyB1c2VkIGluIGFuYWx5c2lzCiMgQ3JlYXRlIE1ENSBjaGVja3N1bSBmb3IgcmVmZXJlbmNlCmlmIFsgISAtZiAiJHtvdXRwdXRfZGlyX3RvcH0iL3Jhdy1mYXN0cS1jaGVja3N1bXMubWQ1IF07IHRoZW4KZm9yIGZhc3RxIGluICouZ3oKICBkbwogICAgbWQ1c3VtICR7ZmFzdHF9ID4+ICIke291dHB1dF9kaXJfdG9wfSIvcmF3LWZhc3RxLWNoZWNrc3Vtcy5tZDUKICBkb25lCmZpCgojIFJ1biBmYXN0cCBvbiBmaWxlcwojIEFkZHMgSlNPTiByZXBvcnQgb3V0cHV0IGZvciBkb3duc3RyZWFtIHVzYWdlIGJ5IE11bHRpUUMKZm9yIGluZGV4IGluICIkeyFmYXN0cV9hcnJheV9SMVtAXX0iCmRvCiAgUjFfc2FtcGxlX25hbWU9JChlY2hvICIke1IxX25hbWVzX2FycmF5W2luZGV4XX0iKQogIFIyX3NhbXBsZV9uYW1lPSQoZWNobyAiJHtSMl9uYW1lc19hcnJheVtpbmRleF19IikKICAke2Zhc3RwfSBcCiAgLS1pbjEgJHtmYXN0cV9hcnJheV9SMVtpbmRleF19IFwKICAtLWluMiAke2Zhc3RxX2FycmF5X1IyW2luZGV4XX0gXAogIC0tZGV0ZWN0X2FkYXB0ZXJfZm9yX3BlIFwKICAtLXRyaW1fZnJvbnQxIDIwIFwKICAtLXRyaW1fZnJvbnQyIDIwIFwKICAtLXRocmVhZCAke3RocmVhZHN9IFwKICAtLWh0bWwgIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIvIiR7UjFfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLnJlcG9ydC5odG1sIFwKICAtLWpzb24gIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIvIiR7UjFfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLnJlcG9ydC5qc29uIFwKICAtLW91dDEgIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIvIiR7UjFfc2FtcGxlX25hbWV9Il9SMV8wMDEuZmFzdHAtdHJpbS5mcS5neiBcCiAgLS1vdXQyICIke3RyaW1tZWRfZmFzdHFzX2Rpcn0iLyIke1IyX3NhbXBsZV9uYW1lfSJfUjJfMDAxLmZhc3RwLXRyaW0uZnEuZ3ogXAogIDI+PiAiJHt0cmltbWVkX2Zhc3Rxc19kaXJ9Ii9mYXN0cC5zdGRlcnIKCiAgIyBHZW5lcmF0ZSBtZDUgY2hlY2tzdW1zIGZvciBuZXdseSB0cmltbWVkIGZpbGVzCiAgY2QgIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIKICBtZDVzdW0gIiR7UjFfc2FtcGxlX25hbWV9Il9SMV8wMDEuZmFzdHAtdHJpbS5mcS5neiA+ICIke1IxX3NhbXBsZV9uYW1lfSJfUjFfMDAxLmZhc3RwLXRyaW0uZnEuZ3oubWQ1CiAgbWQ1c3VtICIke1IyX3NhbXBsZV9uYW1lfSJfUjJfMDAxLmZhc3RwLXRyaW0uZnEuZ3ogPiAiJHtSMl9zYW1wbGVfbmFtZX0iX1IyXzAwMS5mYXN0cC10cmltLmZxLmd6Lm1kNQogIGNkIC0KZG9uZQpgYGAKCgojIFF1YWxpdHkgQ2hlY2sgd2l0aCBGYXN0UUMgYW5kIE11bHRpUUMKYGBge2Jhc2ggdHJpbW1lZC1mYXN0cWMtbXVsdGlxYywgZW5naW5lPSdiYXNoJ30KIyBMb2FkIGJhc2ggdmFyaWFibGVzIGludG8gbWVtb3J5CnNvdXJjZSAuYmFzaHZhcnMKCiMgTWFrZSBvdXRwdXQgZGlyZWN0b3J5IGlmIGl0IGRvZXNuJ3QgZXhpc3QKbWtkaXIgLS1wYXJlbnRzICIke3RyaW1tZWRfZmFzdHFjX2Rpcn0iCgojIyMjIyMjIyMjIyMgUlVOIEZBU1RRQyAjIyMjIyMjIyMjIyMKCgojIENyZWF0ZSBhcnJheSBvZiB0cmltbWVkIEZhc3RRcwp0cmltbWVkX2Zhc3Rxc19hcnJheT0oJHt0cmltbWVkX2Zhc3Rxc19kaXJ9LyR7dHJpbW1lZF9mYXN0cV9wYXR0ZXJufSkKCiMgUGFzcyBhcnJheSBjb250ZW50cyB0byBuZXcgdmFyaWFibGUgYXMgc3BhY2UtZGVsaW1pdGVkIGxpc3QKdHJpbW1lZF9mYXN0cWNfbGlzdD0kKGVjaG8gIiR7dHJpbW1lZF9mYXN0cXNfYXJyYXlbKl19IikKCmVjaG8gIkJlZ2lubmluZyBGYXN0UUMgb24gdHJpbW1lZCByZWFkcy4uLiIKZWNobyAiIgoKIyBSdW4gRmFzdFFDCiMjIyBOT1RFOiBEbyBOT1QgcXVvdGUgcmF3X2Zhc3RxY19saXN0CiR7cHJvZ3JhbXNfYXJyYXlbZmFzdHFjXX0gXAotLXRocmVhZHMgJHt0aHJlYWRzfSBcCi0tb3V0ZGlyICR7dHJpbW1lZF9mYXN0cWNfZGlyfSBcCi0tcXVpZXQgXAoke3RyaW1tZWRfZmFzdHFjX2xpc3R9CgplY2hvICJGYXN0UUMgb24gdHJpbW1lZCByZWFkcyBjb21wbGV0ZSEiCmVjaG8gIiIKCiMjIyMjIyMjIyMjIyBFTkQgRkFTVFFDICMjIyMjIyMjIyMjIwoKIyMjIyMjIyMjIyMjIFJVTiBNVUxUSVFDICMjIyMjIyMjIyMjIwplY2hvICJCZWdpbm5pbmcgTXVsdGlRQyBvbiB0cmltbWVkIEZhc3RRQy4uLiIKZWNobyAiIgoKJHtwcm9ncmFtc19hcnJheVttdWx0aXFjXX0gJHt0cmltbWVkX2Zhc3RxY19kaXJ9IC1vICR7dHJpbW1lZF9mYXN0cWNfZGlyfQoKZWNobyAiIgplY2hvICJNdWx0aVFDIG9uIHRyaW1tZWQgRmFzdFFzIGNvbXBsZXRlLiIKZWNobyAiIgoKIyMjIyMjIyMjIyMjIEVORCBNVUxUSVFDICMjIyMjIyMjIyMjIwoKZWNobyAiUmVtb3ZpbmcgRmFzdFFDIHppcCBmaWxlcy4iCmVjaG8gIiIKcm0gJHt0cmltbWVkX2Zhc3RxY19kaXJ9LyouemlwCmVjaG8gIkZhc3RRQyB6aXAgZmlsZXMgcmVtb3ZlZC4iCmVjaG8gIiIKYGBgCg==