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_01/sam/gitrepos/urol-e5/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_01/sam/gitrepos/urol-e5/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.
# 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 "," 'NR > 2 {print $5"\t"$6}' ${timeseries_dir}/data/rna_metadata.csv | awk -F"[\t-]" '$2 == "ACR" {print $1}')
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 and append *.md5
formatted_list="${formatted_list%,},*.md5"
# 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
wget \
--directory-prefix ${raw_reads_dir} \
--recursive \
--no-check-certificate \
--continue \
--cut-dirs 3 \
--no-host-directories \
--no-parent \
--quiet \
--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
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 on files
# Adds JSON report output for downstream usage by MultiQC
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
# Generate md5 checksums for newly trimmed files
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
# 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_fastqs_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_fastqs_dir} -o ${trimmed_fastqs_dir}
echo ""
echo "MultiQC on trimmed FastQs complete."
echo ""
############ END MULTIQC ############
echo "Removing FastQC zip files."
echo ""
rm ${trimmed_fastqs_dir}/*.zip
echo "FastQC zip files removed."
echo ""
Beginning FastQC on trimmed reads...
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
application/gzip
FastQC on trimmed reads complete!
Beginning MultiQC on trimmed FastQC...
/// MultiQC π | v1.14
| multiqc | MultiQC Version v1.25.1 now available!
| multiqc | Search path : /home/shared/8TB_HDD_01/sam/gitrepos/urol-e5/timeseries_molecular/D-Apul/output/01.00-D-Apul-RNAseq-trimming-fastp-FastQC-MultiQC/trimmed-fastqs
| searching | ββββββββββββββββββββββββββββββββββββββββ 100% 450/450
| fastqc | Found 88 reports
| multiqc | Compressing plot data
| multiqc | Previous MultiQC output found! Adjusting filenames..
| multiqc | Use -f or --force to overwrite existing reports instead
| multiqc | Report : ../output/01.00-D-Apul-RNAseq-trimming-fastp-FastQC-MultiQC/trimmed-fastqs/multiqc_report_2.html
| multiqc | Data : ../output/01.00-D-Apul-RNAseq-trimming-fastp-FastQC-MultiQC/trimmed-fastqs/multiqc_data_2
| multiqc | MultiQC complete
| multiqc | 1 flat-image plot used in the report due to large sample numbers
| multiqc | To force interactive plots, use the '--interactive' flag.
See the documentation.
MultiQC on trimmed FastQs complete.
Removing FastQC zip files.
FastQC zip files removed.
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.
LS0tCnRpdGxlOiAiMDEuMDAtRC1BcHVsLVJOQXNlcS10cmltbWluZy1mYXN0cC1GYXN0UUMtTXVsdGlRQyIKYXV0aG9yOiAiU2FtIFdoaXRlIgpkYXRlOiAiMjAyNC0xMC0wNSIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGdpdGh1Yl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmJpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShrbml0cikKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLCAgICAgICAgICMgRGlzcGxheSBjb2RlIGNodW5rcwogIGV2YWwgPSBGQUxTRSwgICAgICAgICMgRXZhbHVhdGUgY29kZSBjaHVua3MKICB3YXJuaW5nID0gRkFMU0UsICAgICAjIEhpZGUgd2FybmluZ3MKICBtZXNzYWdlID0gRkFMU0UsICAgICAjIEhpZGUgbWVzc2FnZXMKICBjb21tZW50ID0gIiIgICAgICAgICAjIFByZXZlbnRzIGFwcGVuZGluZyAnIyMnIHRvIGJlZ2lubmluZyBvZiBsaW5lcyBpbiBjb2RlIG91dHB1dAopCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpUaGlzIFJtZCBmaWxlIHRyaW1zICpBLnB1bGNocmEqIFJOQS1zZXEgZmlsZXMgdXNpbmcgW2Zhc3RwXShodHRwczovL2dpdGh1Yi5jb20vT3BlbkdlbmUvZmFzdHApIFtAY2hlbjIwMjNdLCBmb2xsb3dlZCBieSBxdWFsaXR5IGNoZWNrcyB3aXRoIFtGYXN0UUNdKGh0dHBzOi8vZ2l0aHViLmNvbS9zLWFuZHJld3MvRmFzdFFDKSBhbmQgW011bHRpUUNdKGh0dHBzOi8vbXVsdGlxYy5pbmZvLylbQGV3ZWxzMjAxNl0uCgpFeHBlY3RzIGlucHV0IGZpbGVzIGZvcm1hdHRlZCBsaWtlIHNvOiBgPG51bWJlcj4tLTxzYW1wbGVfbmFtZT5fUlsxMl1fMDAxLmZhc3RxLmd6YAoKQWxsIHRyaW1tZWQgRmFzdFFzIHByb2R1Y2VkIGJ5IHRoaXMgc2NyaXB0IGFyZSBoZXJlOgoKWzAxLjAwLUQtQXB1bC1STkFzZXEtdHJpbW1pbmctZmFzdHAtRmFzdFFDLU11bHRpUUMvdHJpbW1lZC1mYXN0cXMvXShodHRwczovL2dhbm5ldC5maXNoLndhc2hpbmd0b24uZWR1L0F0dW1lZmFjaWVucy9naXRyZXBvcy91cm9sLWU1L3RpbWVzZXJpZXNfbW9sZWN1bGFyL0QtQXB1bC9vdXRwdXQvMDEuMDAtRC1BcHVsLVJOQXNlcS10cmltbWluZy1mYXN0cC1GYXN0UUMtTXVsdGlRQy90cmltbWVkLWZhc3Rxcy8pCgojIENyZWF0ZSBhIEJhc2ggdmFyaWFibGVzIGZpbGUKClRoaXMgYWxsb3dzIHVzYWdlIG9mIEJhc2ggdmFyaWFibGVzIGFjcm9zcyBSIE1hcmtkb3duIGNodW5rcy4KCmBgYHtyIHNhdmUtYmFzaC12YXJpYWJsZXMtdG8tcnZhcnMtZmlsZSwgZW5naW5lPSdiYXNoJywgZXZhbD1UUlVFfQp7CmVjaG8gIiMjIyMgQXNzaWduIFZhcmlhYmxlcyAjIyMjIgplY2hvICIiCgplY2hvICIjIERhdGEgZGlyZWN0b3JpZXMiCmVjaG8gJ2V4cG9ydCB0aW1lc2VyaWVzX2Rpcj0vaG9tZS9zaGFyZWQvOFRCX0hERF8wMS9zYW0vZ2l0cmVwb3MvdXJvbC1lNS90aW1lc2VyaWVzX21vbGVjdWxhcicKZWNobyAnZXhwb3J0IG91dHB1dF9kaXJfdG9wPSR7dGltZXNlcmllc19kaXJ9L0QtQXB1bC9vdXRwdXQvMDEuMDAtRC1BcHVsLVJOQXNlcS10cmltbWluZy1mYXN0cC1GYXN0UUMtTXVsdGlRQycKZWNobyAnZXhwb3J0IHJhd19yZWFkc19kaXI9JHt0aW1lc2VyaWVzX2Rpcn0vRC1BcHVsL2RhdGEvcmF3LWZhc3RxcycKZWNobyAnZXhwb3J0IHJhd19yZWFkc191cmw9Imh0dHBzOi8vb3dsLmZpc2gud2FzaGluZ3Rvbi5lZHUvbmlnaHRpbmdhbGVzL0U1LWNvcmFsLXRpbWUtc2VyaWVzLzMwLTEwNDc1NjA1MDgvIicKZWNobyAnZXhwb3J0IHRyaW1tZWRfZmFzdHFzX2Rpcj0ke291dHB1dF9kaXJfdG9wfS90cmltbWVkLWZhc3RxcycKZWNobyAnZXhwb3J0IHRyaW1tZWRfZmFzdHFjX2Rpcj0ke291dHB1dF9kaXJfdG9wfS90cmltbWVkLWZhc3RxYycKZWNobyAiIgoKZWNobyAiIyBQYXRocyB0byBwcm9ncmFtcyIKZWNobyAnZXhwb3J0IHByb2dyYW1zX2Rpcj0iL2hvbWUvc2hhcmVkIicKZWNobyAnZXhwb3J0IGZhc3RwPSIke3Byb2dyYW1zX2Rpcn0vZmFzdHAiJwplY2hvICdleHBvcnQgZmFzdHFjPSR7cHJvZ3JhbXNfZGlyfS9GYXN0UUMtMC4xMi4xL2Zhc3RxYycKZWNobyAnZXhwb3J0IG11bHRpcWM9L2hvbWUvc2FtL3Byb2dyYW1zL21hbWJhZm9yZ2UvYmluL211bHRpcWMnCmVjaG8gIiIKCmVjaG8gIiMgU2V0IEZhc3RRIGZpbGVuYW1lIHBhdHRlcm5zIgplY2hvICJleHBvcnQgZmFzdHFfcGF0dGVybj0nKi5mYXN0cS5neiciCmVjaG8gImV4cG9ydCBSMV9mYXN0cV9wYXR0ZXJuPScqX1IxXyouZmFzdHEuZ3onIgplY2hvICJleHBvcnQgUjJfZmFzdHFfcGF0dGVybj0nKl9SMl8qLmZhc3RxLmd6JyIKZWNobyAiZXhwb3J0IHRyaW1tZWRfZmFzdHFfcGF0dGVybj0nKmZhc3RwLXRyaW0uZnEuZ3onIgplY2hvICIiCgplY2hvICIjIFNldCBudW1iZXIgb2YgQ1BVcyB0byB1c2UiCmVjaG8gJ2V4cG9ydCB0aHJlYWRzPTQwJwplY2hvICIiCgoKZWNobyAiIyMgSW5pdGl0YWxpemUgYXJyYXlzIgplY2hvICdleHBvcnQgZmFzdHFfYXJyYXlfUjE9KCknCmVjaG8gJ2V4cG9ydCBmYXN0cV9hcnJheV9SMj0oKScKZWNobyAnZXhwb3J0IHJhd19mYXN0cXNfYXJyYXk9KCknCmVjaG8gJ2V4cG9ydCBSMV9uYW1lc19hcnJheT0oKScKZWNobyAnZXhwb3J0IFIyX25hbWVzX2FycmF5PSgpJwplY2hvICIiCgplY2hvICIjIFByb2dyYW1zIGFzc29jaWF0aXZlIGFycmF5IgplY2hvICJkZWNsYXJlIC1BIHByb2dyYW1zX2FycmF5IgplY2hvICJwcm9ncmFtc19hcnJheT0oIgplY2hvICdbZmFzdHBdPSIke2Zhc3RwfSIgXCcKZWNobyAnW2Zhc3RxY109IiR7ZmFzdHFjfSIgXCcKZWNobyAnW211bHRpcWNdPSIke211bHRpcWN9IiBcJwplY2hvICIpIgplY2hvICIiCgplY2hvICIjIFByaW50IGZvcm1hdHRpbmciCmVjaG8gJ2V4cG9ydCBsaW5lPSItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSInCmVjaG8gIiIKfSA+IC5iYXNodmFycwoKY2F0IC5iYXNodmFycwpgYGAKCklmIG5lZWRlZCwgZG93bmxvYWQgcmF3IFJOQS1zZXEuCgpDaGFuZ2UgYGV2YWw9RkFMU0VgIHRvIGBldmFsPVRSVUVgIHRvIGV4ZWN1dGUgdGhlIG5leHQgdHdvIGNodW5rcyB0byBkb3dubG9hZCBSTkEtc2VxIGFuZCB0aGVuIHZlcmlmeSBNRDUgY2hlY2tzdW1zLgoKYGBge2Jhc2ggZG93bmxvYWQtcmF3LXJlYWRzLCBlbmdpbmU9J2Jhc2gnLCBldmFsPUZBTFNFfQojIExvYWQgYmFzaCB2YXJpYWJsZXMgaW50byBtZW1vcnkKc291cmNlIC5iYXNodmFycwoKIyBNYWtlIG91dHB1dCBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdApta2RpciAtLXBhcmVudHMgJHtyYXdfcmVhZHNfZGlyfQoKIyBDcmVhdGUgbGlzdCBvZiBvbmx5IEEucHVsY2hyYSBzYW1wbGUgbmFtZXMKc2FtcGxlX2xpc3Q9JChhd2sgLUYgIiwiICdOUiA+IDIge3ByaW50ICQ1Ilx0IiQ2fScgJHt0aW1lc2VyaWVzX2Rpcn0vZGF0YS9ybmFfbWV0YWRhdGEuY3N2IHwgYXdrIC1GIltcdC1dIiAnJDIgPT0gIkFDUiIge3ByaW50ICQxfScpCgplY2hvICIiCmVjaG8gIiR7bGluZX0iCmVjaG8gIiIKZWNobyAiU2FtcGxlIGxpc3Q6IgplY2hvICIiCmVjaG8gIiR7c2FtcGxlX2xpc3R9IgplY2hvICIiCmVjaG8gIiR7bGluZX0iCmVjaG8gIiIKCgojIFVzZSBwcmludGYgdG8gZm9ybWF0IGVhY2ggaXRlbSBmb3IgdXNlIGluIHdnZXQKZm9ybWF0dGVkX2xpc3Q9JChwcmludGYgIiolcyosIiAke3NhbXBsZV9saXN0fSkKCiMgUmVtb3ZlIHRoZSB0cmFpbGluZyBjb21tYSBhbmQgYXBwZW5kICoubWQ1CmZvcm1hdHRlZF9saXN0PSIke2Zvcm1hdHRlZF9saXN0JSx9LCoubWQ1IgoKIyBPdXRwdXQgdGhlIGZpbmFsIHdnZXQgY29tbWFuZAplY2hvICIiCmVjaG8gIiR7bGluZX0iCmVjaG8gIiIKZWNobyAiRm9ybWF0dGVkIHdnZXQgYWNjZXB0IGxpc3Q6IgplY2hvICIiCmVjaG8gIndnZXQgLS1hY2NlcHQ9XCIkZm9ybWF0dGVkX2xpc3RcIiIKZWNobyAiIgplY2hvICIke2xpbmV9IgplY2hvICIiCgojIFJ1biB3Z2V0IHRvIHJldHJpZXZlIEZhc3RRcyBhbmQgTUQ1IGZpbGVzCndnZXQgXAotLWRpcmVjdG9yeS1wcmVmaXggJHtyYXdfcmVhZHNfZGlyfSBcCi0tcmVjdXJzaXZlIFwKLS1uby1jaGVjay1jZXJ0aWZpY2F0ZSBcCi0tY29udGludWUgXAotLWN1dC1kaXJzIDMgXAotLW5vLWhvc3QtZGlyZWN0b3JpZXMgXAotLW5vLXBhcmVudCBcCi0tcXVpZXQgXAotLWFjY2VwdD1cIiRmb3JtYXR0ZWRfbGlzdFwiICR7cmF3X3JlYWRzX3VybH0KCmxzIC1saCAiJHtyYXdfcmVhZHNfZGlyfSIKYGBgCgpWZXJpZnkgcmF3IHJlYWQgY2hlY2tzdW1zCmBgYHtiYXNoIHZlcmlmeS1yYXctcmVhZC1jaGVja3N1bXMsIGVuZ2luZT0nYmFzaCcsIGV2YWw9RkFMU0V9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgpjZCAiJHtyYXdfcmVhZHNfZGlyfSIKCiMgQ2hlY2tzdW1zIGZpbGUgY29udGFpbnMgb3RoZXIgZmlsZXMsIHNvIHRoaXMganVzdCBsb29rcyBmb3IgdGhlIHNSTkFzZXEgZmlsZXMuCmZvciBmaWxlIGluICoubWQ1CmRvCiAgbWQ1c3VtIC0tY2hlY2sgIiR7ZmlsZX0iCmRvbmUKYGBgCgojIEZhc3RwIFRyaW1taW5nCgpbZmFzdHBdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuR2VuZS9mYXN0cCkgW0BjaGVuMjAyM10gaXMgc2V0IHRvIGF1dG8tZGV0ZWN0IElsbHVtaW5hIGFkYXB0ZXJzLCBhcyB3ZWxsIGFzIHRyaW0gdGhlIGZpcnN0IDIwYnAgZnJvbSBlYWNoIHJlYWQsIGFzIHBhc3QgZXhwZXJpZW5jZSBzaG93cyB0aGVzZSBmaXJzdCAyMGJwIGFyZSBtb3JlIGluY29uc2lzdGVudCB0aGFuIHRoZSByZW1haW5kZXIgb2YgdGhlIHJlYWQgbGVuZ3RoLgoKYGBge2Jhc2ggZmFzdHAtdHJpbW1pbmcsIGVuZ2luZT0nYmFzaCcsIGV2YWw9RkFMU0V9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgojIE1ha2Ugb3V0cHV0IGRpcmVjdG9yaWVzLCBpZiBpdCBkb2Vzbid0IGV4aXN0Cm1rZGlyIC0tcGFyZW50cyAiJHt0cmltbWVkX2Zhc3Rxc19kaXJ9IgoKIyBDaGFuZ2UgdG8gcmF3IHJlYWRzIGRpcmVjdG9yeQpjZCAiJHtyYXdfcmVhZHNfZGlyfSIKCiMgQ3JlYXRlIGFycmF5cyBvZiBmYXN0cSBSMSBmaWxlcyBhbmQgc2FtcGxlIG5hbWVzCmZvciBmYXN0cSBpbiAke1IxX2Zhc3RxX3BhdHRlcm59CmRvCiAgZmFzdHFfYXJyYXlfUjErPSgiJHtmYXN0cX0iKQogIFIxX25hbWVzX2FycmF5Kz0oIiQoZWNobyAiJHtmYXN0cX0iIHwgYXdrIC1GIl8iICd7cHJpbnQgJDF9JykiKQpkb25lCgojIENyZWF0ZSBhcnJheSBvZiBmYXN0cSBSMiBmaWxlcwpmb3IgZmFzdHEgaW4gJHtSMl9mYXN0cV9wYXR0ZXJufQpkbwogIGZhc3RxX2FycmF5X1IyKz0oIiR7ZmFzdHF9IikKICBSMl9uYW1lc19hcnJheSs9KCIkKGVjaG8gIiR7ZmFzdHF9IiB8IGF3ayAtRiJfIiAne3ByaW50ICQxfScpIikKZG9uZQoKIyBDcmVhdGUgbGlzdCBvZiBmYXN0cSBmaWxlcyB1c2VkIGluIGFuYWx5c2lzCiMgQ3JlYXRlIE1ENSBjaGVja3N1bSBmb3IgcmVmZXJlbmNlCmlmIFsgISAtZiAiJHtvdXRwdXRfZGlyX3RvcH0iL3Jhdy1mYXN0cS1jaGVja3N1bXMubWQ1IF07IHRoZW4KZm9yIGZhc3RxIGluICouZ3oKICBkbwogICAgbWQ1c3VtICR7ZmFzdHF9ID4+ICIke291dHB1dF9kaXJfdG9wfSIvcmF3LWZhc3RxLWNoZWNrc3Vtcy5tZDUKICBkb25lCmZpCgojIFJ1biBmYXN0cCBvbiBmaWxlcwojIEFkZHMgSlNPTiByZXBvcnQgb3V0cHV0IGZvciBkb3duc3RyZWFtIHVzYWdlIGJ5IE11bHRpUUMKZm9yIGluZGV4IGluICIkeyFmYXN0cV9hcnJheV9SMVtAXX0iCmRvCiAgUjFfc2FtcGxlX25hbWU9JChlY2hvICIke1IxX25hbWVzX2FycmF5W2luZGV4XX0iKQogIFIyX3NhbXBsZV9uYW1lPSQoZWNobyAiJHtSMl9uYW1lc19hcnJheVtpbmRleF19IikKICAke2Zhc3RwfSBcCiAgLS1pbjEgJHtmYXN0cV9hcnJheV9SMVtpbmRleF19IFwKICAtLWluMiAke2Zhc3RxX2FycmF5X1IyW2luZGV4XX0gXAogIC0tZGV0ZWN0X2FkYXB0ZXJfZm9yX3BlIFwKICAtLXRyaW1fZnJvbnQxIDIwIFwKICAtLXRyaW1fZnJvbnQyIDIwIFwKICAtLXRocmVhZCAke3RocmVhZHN9IFwKICAtLWh0bWwgIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIvIiR7UjFfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLnJlcG9ydC5odG1sIFwKICAtLWpzb24gIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIvIiR7UjFfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLnJlcG9ydC5qc29uIFwKICAtLW91dDEgIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIvIiR7UjFfc2FtcGxlX25hbWV9Il9SMV8wMDEuZmFzdHAtdHJpbS5mcS5neiBcCiAgLS1vdXQyICIke3RyaW1tZWRfZmFzdHFzX2Rpcn0iLyIke1IyX3NhbXBsZV9uYW1lfSJfUjJfMDAxLmZhc3RwLXRyaW0uZnEuZ3ogXAogIDI+PiAiJHt0cmltbWVkX2Zhc3Rxc19kaXJ9Ii9mYXN0cC5zdGRlcnIKCiAgIyBHZW5lcmF0ZSBtZDUgY2hlY2tzdW1zIGZvciBuZXdseSB0cmltbWVkIGZpbGVzCiAgY2QgIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIKICBtZDVzdW0gIiR7UjFfc2FtcGxlX25hbWV9Il9SMV8wMDEuZmFzdHAtdHJpbS5mcS5neiA+ICIke1IxX3NhbXBsZV9uYW1lfSJfUjFfMDAxLmZhc3RwLXRyaW0uZnEuZ3oubWQ1CiAgbWQ1c3VtICIke1IyX3NhbXBsZV9uYW1lfSJfUjJfMDAxLmZhc3RwLXRyaW0uZnEuZ3ogPiAiJHtSMl9zYW1wbGVfbmFtZX0iX1IyXzAwMS5mYXN0cC10cmltLmZxLmd6Lm1kNQogIGNkIC0KZG9uZQpgYGAKCiMgUXVhbGl0eSBDaGVjayB3aXRoIEZhc3RRQyBhbmQgTXVsdGlRQwpgYGB7YmFzaCB0cmltbWVkLWZhc3RxYy1tdWx0aXFjLCBlbmdpbmU9J2Jhc2gnLCBldmFsPVRSVUV9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgojIE1ha2Ugb3V0cHV0IGRpcmVjdG9yeSBpZiBpdCBkb2Vzbid0IGV4aXN0Cm1rZGlyIC0tcGFyZW50cyAiJHt0cmltbWVkX2Zhc3RxY19kaXJ9IgoKIyMjIyMjIyMjIyMjIFJVTiBGQVNUUUMgIyMjIyMjIyMjIyMjCgoKIyBDcmVhdGUgYXJyYXkgb2YgdHJpbW1lZCBGYXN0UXMKdHJpbW1lZF9mYXN0cXNfYXJyYXk9KCR7dHJpbW1lZF9mYXN0cXNfZGlyfS8ke3RyaW1tZWRfZmFzdHFfcGF0dGVybn0pCgojIFBhc3MgYXJyYXkgY29udGVudHMgdG8gbmV3IHZhcmlhYmxlIGFzIHNwYWNlLWRlbGltaXRlZCBsaXN0CnRyaW1tZWRfZmFzdHFjX2xpc3Q9JChlY2hvICIke3RyaW1tZWRfZmFzdHFzX2FycmF5WypdfSIpCgplY2hvICJCZWdpbm5pbmcgRmFzdFFDIG9uIHRyaW1tZWQgcmVhZHMuLi4iCmVjaG8gIiIKCiMgUnVuIEZhc3RRQwojIyMgTk9URTogRG8gTk9UIHF1b3RlIHJhd19mYXN0cWNfbGlzdAoke3Byb2dyYW1zX2FycmF5W2Zhc3RxY119IFwKLS10aHJlYWRzICR7dGhyZWFkc30gXAotLW91dGRpciAke3RyaW1tZWRfZmFzdHFzX2Rpcn0gXAotLXF1aWV0IFwKJHt0cmltbWVkX2Zhc3RxY19saXN0fQoKZWNobyAiRmFzdFFDIG9uIHRyaW1tZWQgcmVhZHMgY29tcGxldGUhIgplY2hvICIiCgojIyMjIyMjIyMjIyMgRU5EIEZBU1RRQyAjIyMjIyMjIyMjIyMKCiMjIyMjIyMjIyMjIyBSVU4gTVVMVElRQyAjIyMjIyMjIyMjIyMKZWNobyAiQmVnaW5uaW5nIE11bHRpUUMgb24gdHJpbW1lZCBGYXN0UUMuLi4iCmVjaG8gIiIKCiR7cHJvZ3JhbXNfYXJyYXlbbXVsdGlxY119ICR7dHJpbW1lZF9mYXN0cXNfZGlyfSAtbyAke3RyaW1tZWRfZmFzdHFzX2Rpcn0KCmVjaG8gIiIKZWNobyAiTXVsdGlRQyBvbiB0cmltbWVkIEZhc3RRcyBjb21wbGV0ZS4iCmVjaG8gIiIKCiMjIyMjIyMjIyMjIyBFTkQgTVVMVElRQyAjIyMjIyMjIyMjIyMKCmVjaG8gIlJlbW92aW5nIEZhc3RRQyB6aXAgZmlsZXMuIgplY2hvICIiCnJtICR7dHJpbW1lZF9mYXN0cXNfZGlyfS8qLnppcAplY2hvICJGYXN0UUMgemlwIGZpbGVzIHJlbW92ZWQuIgplY2hvICIiCmBgYA==