Background
This notebook will trim raw WGBS FastQs using fastp. Samples which generate an error during trimming will attempt to be repaired using BBTools repairl.sh
(BBMap – Bushnell B. – sourceforge.net/projects/bbmap/). Trimming results will be analyzed with FastQC and summarized by MultiQC (Ewels et al. 2016).
Based off of the initial FastQC/MultiQC, we trimmed 15bp from each read.
Outputs
The expected outputs will be:
*_fastqc.html
: Individual FastQC reports.
*_fastqc.zip
: Individual FastQC ZIP files.
*fastp-trim*.fq.gz
: Trimmed FastQ files.
*.md5
: Individual MD5 checksums for trimmed FastQs.
*.fastp-trim.report.html
: Individual fastp trimming reports. HTML format.
*.fastp-trim.report.json
: Individual fastp trimming reports. JSON format.
multiqc_report.html
: A summary report of the alignment results generated by MultiQC, in HTML format.
Create a Bash variables file
This allows usage of Bash variables across R Markdown chunks.
{
echo "#### Assign Variables ####"
echo ""
echo "# Data directories"
echo 'export repo_dir=/home/shared/8TB_HDD_01/sam/gitrepos/urol-e5/timeseries_molecular'
echo 'export output_dir_top=${repo_dir}/D-Apul/output/01.20-D-Apul-WGBS-trimming-fastp-FastQC-MultiQC'
echo 'export raw_reads_dir="${repo_dir}/D-Apul/data/wgbs-raw-fastqs"'
echo 'export trimmed_fastqs_dir="${output_dir_top}/trimmed-fastqs"'
echo ""
echo "# Paths to programs"
echo 'export programs_dir="/home/shared"'
echo 'export bbmap_repair="${programs_dir}/bbmap-39.12/repair.sh"'
echo 'export bismark_dir="${programs_dir}/Bismark-0.24.0"'
echo 'export bowtie2_dir="${programs_dir}/bowtie2-2.4.4-linux-x86_64"'
echo 'export fastp="${programs_dir}/fastp-v0.24.0/fastp"'
echo 'export fastqc="${programs_dir}/FastQC-0.12.1/fastqc"'
echo 'export multiqc="/home/sam/programs/mambaforge/bin/multiqc"'
echo 'export samtools_dir="${programs_dir}/samtools-1.12"'
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 trimmed_fastqs_array=()'
echo 'export R1_names_array=()'
echo 'export R2_names_array=()'
echo ""
echo "# Print formatting"
echo 'export line="--------------------------------------------------------"'
echo ""
} > .bashvars
cat .bashvars
#### Assign Variables ####
# Data directories
export repo_dir=/home/shared/8TB_HDD_01/sam/gitrepos/urol-e5/timeseries_molecular
export output_dir_top=${repo_dir}/D-Apul/output/01.20-D-Apul-WGBS-trimming-fastp-FastQC-MultiQC
export raw_reads_dir="${repo_dir}/D-Apul/data/wgbs-raw-fastqs"
export trimmed_fastqs_dir="${output_dir_top}/trimmed-fastqs"
# Paths to programs
export programs_dir="/home/shared"
export bbmap_repair="${programs_dir}/bbmap-39.12/repair.sh"
export bismark_dir="${programs_dir}/Bismark-0.24.0"
export bowtie2_dir="${programs_dir}/bowtie2-2.4.4-linux-x86_64"
export fastp="${programs_dir}/fastp-v0.24.0/fastp"
export fastqc="${programs_dir}/FastQC-0.12.1/fastqc"
export multiqc="/home/sam/programs/mambaforge/bin/multiqc"
export samtools_dir="${programs_dir}/samtools-1.12"
# 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 trimmed_fastqs_array=()
export R1_names_array=()
export R2_names_array=()
# Print formatting
export line="--------------------------------------------------------"
Trimming and Error Repair
Trimming will remove any Illumina sequencing adapters, as well as polyG and polyX (primarily polyA) sequences. Trimming will also remove the first 25bp from the 5’ end of each read.
Samples generating an error during trimming will attempt to be repaired with BBTools’ repair.sh
script.
# Load bash variables into memory
source .bashvars
# Make output directory, if it doesn't exist
mkdir --parents ${output_dir_top}
cd "${raw_reads_dir}"
# Create arrays of fastq R1 files and sample names
# Do NOT quote R1_fastq_pattern variable
for fastq in ${R1_fastq_pattern}
do
fastq_array_R1+=("${fastq}")
# Use parameter substitution to remove all text up to and including last "." from
# right side of string.
R1_names_array+=("${fastq%%.*}")
done
# Create array of fastq R2 files
# Do NOT quote R2_fastq_pattern variable
for fastq in ${R2_fastq_pattern}
do
fastq_array_R2+=("${fastq}")
# Use parameter substitution to remove all text up to and including last "." from
# right side of string.
R2_names_array+=(${fastq%%.*})
done
# Run fastp on files
# Adds JSON report output for downstream usage by MultiQC
echo "Beginning fastp trimming."
echo ""
for index in "${!fastq_array_R1[@]}"
do
R1_sample_name="${R1_names_array[index]}"
R2_sample_name="${R2_names_array[index]}"
stderr_PE_name=$(echo ${R1_sample_name} | awk -F"_" '{print $1}')
${fastp} \
--in1 ${fastq_array_R1[index]} \
--in2 ${fastq_array_R2[index]} \
--detect_adapter_for_pe \
--trim_poly_g \
--trim_poly_x \
--thread 16 \
--trim_front1 25 \
--trim_front2 25 \
--html ${output_dir_top}/"${R1_sample_name}".fastp-trim.report.html \
--json ${output_dir_top}/"${R1_sample_name}".fastp-trim.report.json \
--out1 ${output_dir_top}/"${R1_sample_name}".fastp-trim.fq.gz \
--out2 ${output_dir_top}/"${R2_sample_name}".fastp-trim.fq.gz \
2> ${output_dir_top}/"${stderr_PE_name}".fastp-trim.stderr
grep --before-context 5 "ERROR" ${output_dir_top}/"${stderr_PE_name}".fastp-trim.stderr
# Check for fastp errors and then repair
if grep --quiet "ERROR" ${output_dir_top}/"${stderr_PE_name}".fastp-trim.stderr; then
rm ${output_dir_top}/"${R1_sample_name}".fastp-trim.fq.gz
rm ${output_dir_top}/"${R2_sample_name}".fastp-trim.fq.gz
${bbmap_repair} \
in1=${fastq_array_R1[index]} \
in2=${fastq_array_R2[index]} \
out1="${R1_sample_name}".REPAIRED.fastq.gz \
out2="${R2_sample_name}".REPAIRED.fastq.gz \
outs=/dev/null \
2> "${R1_sample_name}".REPAIRED.stderr
${fastp} \
--in1 "${R1_sample_name}".REPAIRED.fastq.gz \
--in2 "${R2_sample_name}".REPAIRED.fastq.gz \
--detect_adapter_for_pe \
--trim_poly_g \
--trim_poly_x \
--thread ${threads} \
--trim_front1 25 \
--trim_front2 25 \
--html ${output_dir_top}/"${R1_sample_name}".fastp-trim.REPAIRED.report.html \
--json ${output_dir_top}/"${R1_sample_name}".fastp-trim.REPAIRED.report.json \
--out1 ${output_dir_top}/"${R1_sample_name}".fastp-trim.REPAIRED.fq.gz \
--out2 ${output_dir_top}/"${R2_sample_name}".fastp-trim.REPAIRED.fq.gz \
2> ${output_dir_top}/"${stderr_PE_name}".fastp-trim.REPAIRED.stderr
if grep --quiet "ERROR" ${output_dir_top}/"${stderr_PE_name}".fastp-trim.REPAIRED.stderr; then
echo "These ${stderr_PE_name} samples are broken."
echo "Just give up. :("
echo ""
fi
fi
echo "Finished trimming:"
echo "${fastq_array_R1[index]}"
echo "${fastq_array_R1[index]}"
echo ""
# Generate md5 checksums for newly trimmed files
cd "${output_dir_top}"
md5sum "${R1_sample_name}".fastp-trim.fq.gz > "${R1_sample_name}".fastp-trim.fq.gz.md5
md5sum "${R2_sample_name}".fastp-trim.fq.gz > "${R2_sample_name}".fastp-trim.fq.gz.md5
cd "${raw_reads_dir}"
done
FastQC
# Load bash variables into memory
source .bashvars
cd "${output_dir_top}"
############ RUN FASTQC ############
# Create array of trimmed FastQs
trimmed_fastqs_array=(${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
${fastqc} \
--threads ${threads} \
--outdir "${output_dir_top}" \
--quiet \
${trimmed_fastqc_list}
echo "FastQC on trimmed reads complete!"
echo ""
############ END FASTQC ############
MultiQC
# Load bash variables into memory
source .bashvars
cd "${output_dir_top}"
${multiqc} \
--interactive \
.
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.
LS0tCnRpdGxlOiAiMDEuMjAtRC1BcHVsLVdHQlMtdHJpbW1pbmctZmFzdHAtRmFzdFFDLU11bHRpUUMiCmF1dGhvcjogIlNhbSBXaGl0ZSIKZGF0ZTogIjIwMjUtMDEtMDIiCm91dHB1dDogCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOgogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICBnaXRodWJfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQpiaWJsaW9ncmFwaHk6IHJlZmVyZW5jZXMuYmliCi0tLQoKIyBCYWNrZ3JvdW5kCgpUaGlzIG5vdGVib29rIHdpbGwgdHJpbSByYXcgV0dCUyBGYXN0UXMgdXNpbmcgW2Zhc3RwXShodHRwczovL2dpdGh1Yi5jb20vT3BlbkdlbmUvZmFzdHApLiBTYW1wbGVzIHdoaWNoIGdlbmVyYXRlIGFuIGVycm9yIGR1cmluZyB0cmltbWluZyB3aWxsIGF0dGVtcHQgdG8gYmUgcmVwYWlyZWQgdXNpbmcgW0JCVG9vbHMgYHJlcGFpcmwuc2hgXShodHRwczovL2pnaS5kb2UuZ292L2RhdGEtYW5kLXRvb2xzL3NvZnR3YXJlLXRvb2xzL2JidG9vbHMvKSAoQkJNYXAg4oCTIEJ1c2huZWxsIEIuIOKAkyBzb3VyY2Vmb3JnZS5uZXQvcHJvamVjdHMvYmJtYXAvKS4gVHJpbW1pbmcgcmVzdWx0cyB3aWxsIGJlIGFuYWx5emVkIHdpdGggRmFzdFFDIGFuZCBzdW1tYXJpemVkIGJ5IFtNdWx0aVFDXShodHRwczovL2dpdGh1Yi5jb20vTXVsdGlRQy9NdWx0aVFDKSBbQGV3ZWxzMjAxNl0uCgpCYXNlZCBvZmYgb2YgdGhlIGluaXRpYWwgRmFzdFFDL011bHRpUUMsIHdlIHRyaW1tZWQgMTVicCBmcm9tIGVhY2ggcmVhZC4KCiMjIElucHV0cwoKUmF3IFdHQlMgRmFzdFEgZmlsZXMgd2l0aCB0aGUgZm9sbG93aW5nIHBhdHRlcm46CgotIGAqLmZhc3RxLmd6YAoKOjo6IHsuY2FsbG91dC1ub3RlfQpJZiBvbmUgbmVlZHMgdG8gZG93bmxvYWQgdGhlIHJhdyBGYXN0UXMsIHBsZWFzZSBzZWUgWzAwLjIwLUQtQXB1bC1XR0JTLXJlYWRzLUZhc3RRQy1NdWx0aVFDLlJtZF0oLi8wMC4yMC1ELUFwdWwtV0dCUy1yZWFkcy1GYXN0UUMtTXVsdGlRQy5SbWQpCjo6OgoKCiMjIE91dHB1dHMKClRoZSBleHBlY3RlZCBvdXRwdXRzIHdpbGwgYmU6CgotIGAqX2Zhc3RxYy5odG1sYDogSW5kaXZpZHVhbCBGYXN0UUMgcmVwb3J0cy4KCi0gYCpfZmFzdHFjLnppcGA6IEluZGl2aWR1YWwgRmFzdFFDIFpJUCBmaWxlcy4KCi0gYCpmYXN0cC10cmltKi5mcS5nemA6IFRyaW1tZWQgRmFzdFEgZmlsZXMuCgotIGAqLm1kNWA6IEluZGl2aWR1YWwgTUQ1IGNoZWNrc3VtcyBmb3IgdHJpbW1lZCBGYXN0UXMuCgotIGAqLmZhc3RwLXRyaW0ucmVwb3J0Lmh0bWxgOiBJbmRpdmlkdWFsIGZhc3RwIHRyaW1taW5nIHJlcG9ydHMuIEhUTUwgZm9ybWF0LgoKLSBgKi5mYXN0cC10cmltLnJlcG9ydC5qc29uYDogSW5kaXZpZHVhbCBmYXN0cCB0cmltbWluZyByZXBvcnRzLiBKU09OIGZvcm1hdC4KCi0gYG11bHRpcWNfcmVwb3J0Lmh0bWxgOiBBIHN1bW1hcnkgcmVwb3J0IG9mIHRoZSBhbGlnbm1lbnQgcmVzdWx0cyBnZW5lcmF0ZWQgYnkgW011bHRpUUNdKGh0dHBzOi8vZ2l0aHViLmNvbS9NdWx0aVFDL011bHRpUUMpLCBpbiBIVE1MIGZvcm1hdC4KCgogIC0gRHVlIHRvIHRoZSBsYXJnZSBmaWxlIHNpemVzIG9mIEZhc3RRcywgdGhlc2UgY2Fubm90IGJlIGhvc3RlZCBpbiB0aGUgW3RpbWVzZXJpZXNfbW9sZWN1bGFyIEdpdEh1YiByZXBvXShodHRwczovL2dpdGh1Yi5jb20vdXJvbC1lNS90aW1lc2VyaWVzX21vbGVjdWxhci90cmVlL21haW4pLiBBcyBzdWNoIHRoZXNlIGZpbGVzIGFyZSBhdmFpbGFibGUgZm9yIGRvd25sb2FkIGhlcmU6CgogICAgLSBbaHR0cHM6Ly9nYW5uZXQuZmlzaC53YXNoaW5ndG9uLmVkdS9naXRyZXBvcy91cm9sLWU1L3RpbWVzZXJpZXNfbW9sZWN1bGFyL0QtQXB1bC9vdXRwdXQvMDEuMjAtRC1BcHVsLVdHQlMtdHJpbW1pbmctZmFzdHAtRmFzdFFDLU11bHRpUUMvXShodHRwczovL2dhbm5ldC5maXNoLndhc2hpbmd0b24uZWR1L2dpdHJlcG9zL3Vyb2wtZTUvdGltZXNlcmllc19tb2xlY3VsYXIvRC1BcHVsL291dHB1dC8wMS4yMC1ELUFwdWwtV0dCUy10cmltbWluZy1mYXN0cC1GYXN0UUMtTXVsdGlRQy8pCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShrbml0cikKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLCAgICAgICAgICMgRGlzcGxheSBjb2RlIGNodW5rcwogIGV2YWwgPSBGQUxTRSwgICAgICAgICMgRXZhbHVhdGUgY29kZSBjaHVua3MKICB3YXJuaW5nID0gRkFMU0UsICAgICAjIEhpZGUgd2FybmluZ3MKICBtZXNzYWdlID0gRkFMU0UsICAgICAjIEhpZGUgbWVzc2FnZXMKICBjb21tZW50ID0gIiIgICAgICAgICAjIFByZXZlbnRzIGFwcGVuZGluZyAnIyMnIHRvIGJlZ2lubmluZyBvZiBsaW5lcyBpbiBjb2RlIG91dHB1dAopCmBgYAoKIyBDcmVhdGUgYSBCYXNoIHZhcmlhYmxlcyBmaWxlCgpUaGlzIGFsbG93cyB1c2FnZSBvZiBCYXNoIHZhcmlhYmxlcyBhY3Jvc3MgUiBNYXJrZG93biBjaHVua3MuCgpgYGB7ciBzYXZlLWJhc2gtdmFyaWFibGVzLXRvLXJ2YXJzLWZpbGUsIGVuZ2luZT0nYmFzaCcsIGV2YWw9VFJVRX0KewplY2hvICIjIyMjIEFzc2lnbiBWYXJpYWJsZXMgIyMjIyIKZWNobyAiIgoKZWNobyAiIyBEYXRhIGRpcmVjdG9yaWVzIgplY2hvICdleHBvcnQgcmVwb19kaXI9L2hvbWUvc2hhcmVkLzhUQl9IRERfMDEvc2FtL2dpdHJlcG9zL3Vyb2wtZTUvdGltZXNlcmllc19tb2xlY3VsYXInCmVjaG8gJ2V4cG9ydCBvdXRwdXRfZGlyX3RvcD0ke3JlcG9fZGlyfS9ELUFwdWwvb3V0cHV0LzAxLjIwLUQtQXB1bC1XR0JTLXRyaW1taW5nLWZhc3RwLUZhc3RRQy1NdWx0aVFDJwplY2hvICdleHBvcnQgcmF3X3JlYWRzX2Rpcj0iJHtyZXBvX2Rpcn0vRC1BcHVsL2RhdGEvd2dicy1yYXctZmFzdHFzIicKZWNobyAnZXhwb3J0IHRyaW1tZWRfZmFzdHFzX2Rpcj0iJHtvdXRwdXRfZGlyX3RvcH0vdHJpbW1lZC1mYXN0cXMiJwplY2hvICIiCgplY2hvICIjIFBhdGhzIHRvIHByb2dyYW1zIgplY2hvICdleHBvcnQgcHJvZ3JhbXNfZGlyPSIvaG9tZS9zaGFyZWQiJwplY2hvICdleHBvcnQgYmJtYXBfcmVwYWlyPSIke3Byb2dyYW1zX2Rpcn0vYmJtYXAtMzkuMTIvcmVwYWlyLnNoIicKZWNobyAnZXhwb3J0IGJpc21hcmtfZGlyPSIke3Byb2dyYW1zX2Rpcn0vQmlzbWFyay0wLjI0LjAiJwplY2hvICdleHBvcnQgYm93dGllMl9kaXI9IiR7cHJvZ3JhbXNfZGlyfS9ib3d0aWUyLTIuNC40LWxpbnV4LXg4Nl82NCInCmVjaG8gJ2V4cG9ydCBmYXN0cD0iJHtwcm9ncmFtc19kaXJ9L2Zhc3RwLXYwLjI0LjAvZmFzdHAiJwplY2hvICdleHBvcnQgZmFzdHFjPSIke3Byb2dyYW1zX2Rpcn0vRmFzdFFDLTAuMTIuMS9mYXN0cWMiJwplY2hvICdleHBvcnQgbXVsdGlxYz0iL2hvbWUvc2FtL3Byb2dyYW1zL21hbWJhZm9yZ2UvYmluL211bHRpcWMiJwplY2hvICdleHBvcnQgc2FtdG9vbHNfZGlyPSIke3Byb2dyYW1zX2Rpcn0vc2FtdG9vbHMtMS4xMiInCmVjaG8gIiIKCgplY2hvICIjIFNldCBGYXN0USBmaWxlbmFtZSBwYXR0ZXJucyIKZWNobyAiZXhwb3J0IGZhc3RxX3BhdHRlcm49JyouZmFzdHEuZ3onIgplY2hvICJleHBvcnQgUjFfZmFzdHFfcGF0dGVybj0nKl9SMV8qLmZhc3RxLmd6JyIKZWNobyAiZXhwb3J0IFIyX2Zhc3RxX3BhdHRlcm49JypfUjJfKi5mYXN0cS5neiciCmVjaG8gImV4cG9ydCB0cmltbWVkX2Zhc3RxX3BhdHRlcm49JypmYXN0cC10cmltKi5mcS5neiciCmVjaG8gIiIKCmVjaG8gIiMgU2V0IG51bWJlciBvZiBDUFVzIHRvIHVzZSIKZWNobyAnZXhwb3J0IHRocmVhZHM9NDAnCmVjaG8gIiIKCgplY2hvICIjIyBJbml0aXRhbGl6ZSBhcnJheXMiCmVjaG8gJ2V4cG9ydCBmYXN0cV9hcnJheV9SMT0oKScKZWNobyAnZXhwb3J0IGZhc3RxX2FycmF5X1IyPSgpJwplY2hvICdleHBvcnQgdHJpbW1lZF9mYXN0cXNfYXJyYXk9KCknCmVjaG8gJ2V4cG9ydCBSMV9uYW1lc19hcnJheT0oKScKZWNobyAnZXhwb3J0IFIyX25hbWVzX2FycmF5PSgpJwplY2hvICIiCgplY2hvICIjIFByaW50IGZvcm1hdHRpbmciCmVjaG8gJ2V4cG9ydCBsaW5lPSItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSInCmVjaG8gIiIKfSA+IC5iYXNodmFycwoKY2F0IC5iYXNodmFycwpgYGAKCgojIFRyaW1taW5nIGFuZCBFcnJvciBSZXBhaXIKClRyaW1taW5nIHdpbGwgcmVtb3ZlIGFueSBJbGx1bWluYSBzZXF1ZW5jaW5nIGFkYXB0ZXJzLCBhcyB3ZWxsIGFzIHBvbHlHIGFuZCBwb2x5WCAocHJpbWFyaWx5IHBvbHlBKSBzZXF1ZW5jZXMuIFRyaW1taW5nIHdpbGwgYWxzbyByZW1vdmUgdGhlIGZpcnN0IDI1YnAgZnJvbSB0aGUgNScgZW5kIG9mIGVhY2ggcmVhZC4KClNhbXBsZXMgZ2VuZXJhdGluZyBhbiBlcnJvciBkdXJpbmcgdHJpbW1pbmcgd2lsbCBhdHRlbXB0IHRvIGJlIHJlcGFpcmVkIHdpdGggQkJUb29scycgYHJlcGFpci5zaGAgc2NyaXB0LgoKYGBge3IgZmFzdHAtdHJpbW1pbmcsIGVuZ2luZT0nYmFzaCcsIGV2YWw9RkFMU0V9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgojIE1ha2Ugb3V0cHV0IGRpcmVjdG9yeSwgaWYgaXQgZG9lc24ndCBleGlzdApta2RpciAtLXBhcmVudHMgJHtvdXRwdXRfZGlyX3RvcH0KCmNkICIke3Jhd19yZWFkc19kaXJ9IgoKCiMgQ3JlYXRlIGFycmF5cyBvZiBmYXN0cSBSMSBmaWxlcyBhbmQgc2FtcGxlIG5hbWVzCiMgRG8gTk9UIHF1b3RlIFIxX2Zhc3RxX3BhdHRlcm4gdmFyaWFibGUKCmZvciBmYXN0cSBpbiAke1IxX2Zhc3RxX3BhdHRlcm59CmRvCiAgZmFzdHFfYXJyYXlfUjErPSgiJHtmYXN0cX0iKQoKICAjIFVzZSBwYXJhbWV0ZXIgc3Vic3RpdHV0aW9uIHRvIHJlbW92ZSBhbGwgdGV4dCB1cCB0byBhbmQgaW5jbHVkaW5nIGxhc3QgIi4iIGZyb20KICAjIHJpZ2h0IHNpZGUgb2Ygc3RyaW5nLgogIFIxX25hbWVzX2FycmF5Kz0oIiR7ZmFzdHElJS4qfSIpCmRvbmUKCiMgQ3JlYXRlIGFycmF5IG9mIGZhc3RxIFIyIGZpbGVzCiMgRG8gTk9UIHF1b3RlIFIyX2Zhc3RxX3BhdHRlcm4gdmFyaWFibGUKZm9yIGZhc3RxIGluICR7UjJfZmFzdHFfcGF0dGVybn0KZG8KICBmYXN0cV9hcnJheV9SMis9KCIke2Zhc3RxfSIpCgogICMgVXNlIHBhcmFtZXRlciBzdWJzdGl0dXRpb24gdG8gcmVtb3ZlIGFsbCB0ZXh0IHVwIHRvIGFuZCBpbmNsdWRpbmcgbGFzdCAiLiIgZnJvbQogICMgcmlnaHQgc2lkZSBvZiBzdHJpbmcuCiAgUjJfbmFtZXNfYXJyYXkrPSgke2Zhc3RxJSUuKn0pCmRvbmUKCgoKIyBSdW4gZmFzdHAgb24gZmlsZXMKIyBBZGRzIEpTT04gcmVwb3J0IG91dHB1dCBmb3IgZG93bnN0cmVhbSB1c2FnZSBieSBNdWx0aVFDCgplY2hvICJCZWdpbm5pbmcgZmFzdHAgdHJpbW1pbmcuIgplY2hvICIiCgpmb3IgaW5kZXggaW4gIiR7IWZhc3RxX2FycmF5X1IxW0BdfSIKZG8KICBSMV9zYW1wbGVfbmFtZT0iJHtSMV9uYW1lc19hcnJheVtpbmRleF19IgogIFIyX3NhbXBsZV9uYW1lPSIke1IyX25hbWVzX2FycmF5W2luZGV4XX0iCiAgCiAgc3RkZXJyX1BFX25hbWU9JChlY2hvICR7UjFfc2FtcGxlX25hbWV9IHwgYXdrIC1GIl8iICd7cHJpbnQgJDF9JykKICAKICAke2Zhc3RwfSBcCiAgLS1pbjEgJHtmYXN0cV9hcnJheV9SMVtpbmRleF19IFwKICAtLWluMiAke2Zhc3RxX2FycmF5X1IyW2luZGV4XX0gXAogIC0tZGV0ZWN0X2FkYXB0ZXJfZm9yX3BlIFwKICAtLXRyaW1fcG9seV9nIFwKICAtLXRyaW1fcG9seV94IFwKICAtLXRocmVhZCAxNiBcCiAgLS10cmltX2Zyb250MSAyNSBcCiAgLS10cmltX2Zyb250MiAyNSBcCiAgLS1odG1sICR7b3V0cHV0X2Rpcl90b3B9LyIke1IxX3NhbXBsZV9uYW1lfSIuZmFzdHAtdHJpbS5yZXBvcnQuaHRtbCBcCiAgLS1qc29uICR7b3V0cHV0X2Rpcl90b3B9LyIke1IxX3NhbXBsZV9uYW1lfSIuZmFzdHAtdHJpbS5yZXBvcnQuanNvbiBcCiAgLS1vdXQxICR7b3V0cHV0X2Rpcl90b3B9LyIke1IxX3NhbXBsZV9uYW1lfSIuZmFzdHAtdHJpbS5mcS5neiBcCiAgLS1vdXQyICR7b3V0cHV0X2Rpcl90b3B9LyIke1IyX3NhbXBsZV9uYW1lfSIuZmFzdHAtdHJpbS5mcS5neiBcCiAgMj4gJHtvdXRwdXRfZGlyX3RvcH0vIiR7c3RkZXJyX1BFX25hbWV9Ii5mYXN0cC10cmltLnN0ZGVycgogIAogIGdyZXAgLS1iZWZvcmUtY29udGV4dCA1ICJFUlJPUiIgJHtvdXRwdXRfZGlyX3RvcH0vIiR7c3RkZXJyX1BFX25hbWV9Ii5mYXN0cC10cmltLnN0ZGVycgogIAogICMgQ2hlY2sgZm9yIGZhc3RwIGVycm9ycyBhbmQgdGhlbiByZXBhaXIKICBpZiBncmVwIC0tcXVpZXQgIkVSUk9SIiAke291dHB1dF9kaXJfdG9wfS8iJHtzdGRlcnJfUEVfbmFtZX0iLmZhc3RwLXRyaW0uc3RkZXJyOyB0aGVuCiAgICAgIAogICAgcm0gJHtvdXRwdXRfZGlyX3RvcH0vIiR7UjFfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLmZxLmd6CiAgICBybSAke291dHB1dF9kaXJfdG9wfS8iJHtSMl9zYW1wbGVfbmFtZX0iLmZhc3RwLXRyaW0uZnEuZ3oKICAgIAogICAgCiAgICAke2JibWFwX3JlcGFpcn0gXAogICAgaW4xPSR7ZmFzdHFfYXJyYXlfUjFbaW5kZXhdfSBcCiAgICBpbjI9JHtmYXN0cV9hcnJheV9SMltpbmRleF19IFwKICAgIG91dDE9IiR7UjFfc2FtcGxlX25hbWV9Ii5SRVBBSVJFRC5mYXN0cS5neiBcCiAgICBvdXQyPSIke1IyX3NhbXBsZV9uYW1lfSIuUkVQQUlSRUQuZmFzdHEuZ3ogXAogICAgb3V0cz0vZGV2L251bGwgXAogICAgMj4gIiR7UjFfc2FtcGxlX25hbWV9Ii5SRVBBSVJFRC5zdGRlcnIKICAgIAogICAgJHtmYXN0cH0gXAogICAgLS1pbjEgIiR7UjFfc2FtcGxlX25hbWV9Ii5SRVBBSVJFRC5mYXN0cS5neiBcCiAgICAtLWluMiAiJHtSMl9zYW1wbGVfbmFtZX0iLlJFUEFJUkVELmZhc3RxLmd6IFwKICAgIC0tZGV0ZWN0X2FkYXB0ZXJfZm9yX3BlIFwKICAgIC0tdHJpbV9wb2x5X2cgXAogICAgLS10cmltX3BvbHlfeCBcCiAgICAtLXRocmVhZCAke3RocmVhZHN9IFwKICAgIC0tdHJpbV9mcm9udDEgMjUgXAogICAgLS10cmltX2Zyb250MiAyNSBcCiAgICAtLWh0bWwgJHtvdXRwdXRfZGlyX3RvcH0vIiR7UjFfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLlJFUEFJUkVELnJlcG9ydC5odG1sIFwKICAgIC0tanNvbiAke291dHB1dF9kaXJfdG9wfS8iJHtSMV9zYW1wbGVfbmFtZX0iLmZhc3RwLXRyaW0uUkVQQUlSRUQucmVwb3J0Lmpzb24gXAogICAgLS1vdXQxICR7b3V0cHV0X2Rpcl90b3B9LyIke1IxX3NhbXBsZV9uYW1lfSIuZmFzdHAtdHJpbS5SRVBBSVJFRC5mcS5neiBcCiAgICAtLW91dDIgJHtvdXRwdXRfZGlyX3RvcH0vIiR7UjJfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLlJFUEFJUkVELmZxLmd6IFwKICAgIDI+ICR7b3V0cHV0X2Rpcl90b3B9LyIke3N0ZGVycl9QRV9uYW1lfSIuZmFzdHAtdHJpbS5SRVBBSVJFRC5zdGRlcnIKIAogICAgCiAgICBpZiBncmVwIC0tcXVpZXQgIkVSUk9SIiAke291dHB1dF9kaXJfdG9wfS8iJHtzdGRlcnJfUEVfbmFtZX0iLmZhc3RwLXRyaW0uUkVQQUlSRUQuc3RkZXJyOyB0aGVuCiAgICAgIGVjaG8gIlRoZXNlICR7c3RkZXJyX1BFX25hbWV9IHNhbXBsZXMgYXJlIGJyb2tlbi4iCiAgICAgIGVjaG8gIkp1c3QgZ2l2ZSB1cC4gIDooIgogICAgICBlY2hvICIiCiAgICBmaQogIGZpCgogIGVjaG8gIkZpbmlzaGVkIHRyaW1taW5nOiIKICBlY2hvICIke2Zhc3RxX2FycmF5X1IxW2luZGV4XX0iCiAgZWNobyAiJHtmYXN0cV9hcnJheV9SMVtpbmRleF19IgogIGVjaG8gIiIKICAKICAjIEdlbmVyYXRlIG1kNSBjaGVja3N1bXMgZm9yIG5ld2x5IHRyaW1tZWQgZmlsZXMKICBjZCAiJHtvdXRwdXRfZGlyX3RvcH0iCiAgbWQ1c3VtICIke1IxX3NhbXBsZV9uYW1lfSIuZmFzdHAtdHJpbS5mcS5neiA+ICIke1IxX3NhbXBsZV9uYW1lfSIuZmFzdHAtdHJpbS5mcS5nei5tZDUKICBtZDVzdW0gIiR7UjJfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLmZxLmd6ID4gIiR7UjJfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLmZxLmd6Lm1kNQogIAogIGNkICIke3Jhd19yZWFkc19kaXJ9Igpkb25lCmBgYAoKCgoKCiMgRmFzdFFDCmBgYHtyIGZhc3RxYywgZW5naW5lPSdiYXNoJ30KIyBMb2FkIGJhc2ggdmFyaWFibGVzIGludG8gbWVtb3J5CnNvdXJjZSAuYmFzaHZhcnMKCmNkICIke291dHB1dF9kaXJfdG9wfSIKCiMjIyMjIyMjIyMjIyBSVU4gRkFTVFFDICMjIyMjIyMjIyMjIwoKCiMgQ3JlYXRlIGFycmF5IG9mIHRyaW1tZWQgRmFzdFFzCnRyaW1tZWRfZmFzdHFzX2FycmF5PSgke3RyaW1tZWRfZmFzdHFfcGF0dGVybn0pCgojIFBhc3MgYXJyYXkgY29udGVudHMgdG8gbmV3IHZhcmlhYmxlIGFzIHNwYWNlLWRlbGltaXRlZCBsaXN0CnRyaW1tZWRfZmFzdHFjX2xpc3Q9JChlY2hvICIke3RyaW1tZWRfZmFzdHFzX2FycmF5WypdfSIpCgplY2hvICJCZWdpbm5pbmcgRmFzdFFDIG9uIHRyaW1tZWQgcmVhZHMuLi4iCmVjaG8gIiIKCiMgUnVuIEZhc3RRQwojIyMgTk9URTogRG8gTk9UIHF1b3RlIHJhd19mYXN0cWNfbGlzdAoke2Zhc3RxY30gXAotLXRocmVhZHMgJHt0aHJlYWRzfSBcCi0tb3V0ZGlyICIke291dHB1dF9kaXJfdG9wfSIgXAotLXF1aWV0IFwKJHt0cmltbWVkX2Zhc3RxY19saXN0fQoKZWNobyAiRmFzdFFDIG9uIHRyaW1tZWQgcmVhZHMgY29tcGxldGUhIgplY2hvICIiCgojIyMjIyMjIyMjIyMgRU5EIEZBU1RRQyAjIyMjIyMjIyMjIyMKYGBgCgoKCiMgTXVsdGlRQwpgYGB7ciBtdWx0aXFjLCBlbmdpbmU9J2Jhc2gnfQojIExvYWQgYmFzaCB2YXJpYWJsZXMgaW50byBtZW1vcnkKc291cmNlIC5iYXNodmFycwoKY2QgIiR7b3V0cHV0X2Rpcl90b3B9IgoKJHttdWx0aXFjfSBcCi0taW50ZXJhY3RpdmUgXAouCmBgYA==