1 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.

1.1 Inputs

Raw WGBS FastQ files with the following pattern:

  • *.fastq.gz

If one needs to download the raw FastQs, please see 00.20-D-Apul-WGBS-reads-FastQC-MultiQC.Rmd

1.2 Outputs

The expected outputs will be:

2 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="--------------------------------------------------------"

3 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

4 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 ############

5 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==