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/

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

# 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

2 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

3 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.
LS0tCnRpdGxlOiAiMDEuMDAtRC1BcHVsLVJOQXNlcS10cmltbWluZy1mYXN0cC1GYXN0UUMtTXVsdGlRQyIKYXV0aG9yOiAiU2FtIFdoaXRlIgpkYXRlOiAiMjAyNC0xMC0wNSIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogIGdpdGh1Yl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmJpYmxpb2dyYXBoeTogcmVmZXJlbmNlcy5iaWIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShrbml0cikKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLCAgICAgICAgICMgRGlzcGxheSBjb2RlIGNodW5rcwogIGV2YWwgPSBGQUxTRSwgICAgICAgICMgRXZhbHVhdGUgY29kZSBjaHVua3MKICB3YXJuaW5nID0gRkFMU0UsICAgICAjIEhpZGUgd2FybmluZ3MKICBtZXNzYWdlID0gRkFMU0UsICAgICAjIEhpZGUgbWVzc2FnZXMKICBjb21tZW50ID0gIiIgICAgICAgICAjIFByZXZlbnRzIGFwcGVuZGluZyAnIyMnIHRvIGJlZ2lubmluZyBvZiBsaW5lcyBpbiBjb2RlIG91dHB1dAopCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpUaGlzIFJtZCBmaWxlIHRyaW1zICpBLnB1bGNocmEqIFJOQS1zZXEgZmlsZXMgdXNpbmcgW2Zhc3RwXShodHRwczovL2dpdGh1Yi5jb20vT3BlbkdlbmUvZmFzdHApIFtAY2hlbjIwMjNdLCBmb2xsb3dlZCBieSBxdWFsaXR5IGNoZWNrcyB3aXRoIFtGYXN0UUNdKGh0dHBzOi8vZ2l0aHViLmNvbS9zLWFuZHJld3MvRmFzdFFDKSBhbmQgW011bHRpUUNdKGh0dHBzOi8vbXVsdGlxYy5pbmZvLylbQGV3ZWxzMjAxNl0uCgpFeHBlY3RzIGlucHV0IGZpbGVzIGZvcm1hdHRlZCBsaWtlIHNvOiBgPG51bWJlcj4tLTxzYW1wbGVfbmFtZT5fUlsxMl1fMDAxLmZhc3RxLmd6YAoKQWxsIHRyaW1tZWQgRmFzdFFzIHByb2R1Y2VkIGJ5IHRoaXMgc2NyaXB0IGFyZSBoZXJlOgoKWzAxLjAwLUQtQXB1bC1STkFzZXEtdHJpbW1pbmctZmFzdHAtRmFzdFFDLU11bHRpUUMvdHJpbW1lZC1mYXN0cXMvXShodHRwczovL2dhbm5ldC5maXNoLndhc2hpbmd0b24uZWR1L0F0dW1lZmFjaWVucy9naXRyZXBvcy91cm9sLWU1L3RpbWVzZXJpZXNfbW9sZWN1bGFyL0QtQXB1bC9vdXRwdXQvMDEuMDAtRC1BcHVsLVJOQXNlcS10cmltbWluZy1mYXN0cC1GYXN0UUMtTXVsdGlRQy90cmltbWVkLWZhc3Rxcy8pCgojIENyZWF0ZSBhIEJhc2ggdmFyaWFibGVzIGZpbGUKClRoaXMgYWxsb3dzIHVzYWdlIG9mIEJhc2ggdmFyaWFibGVzIGFjcm9zcyBSIE1hcmtkb3duIGNodW5rcy4KCmBgYHtyIHNhdmUtYmFzaC12YXJpYWJsZXMtdG8tcnZhcnMtZmlsZSwgZW5naW5lPSdiYXNoJywgZXZhbD1UUlVFfQp7CmVjaG8gIiMjIyMgQXNzaWduIFZhcmlhYmxlcyAjIyMjIgplY2hvICIiCgplY2hvICIjIERhdGEgZGlyZWN0b3JpZXMiCmVjaG8gJ2V4cG9ydCB0aW1lc2VyaWVzX2Rpcj0vaG9tZS9zaGFyZWQvOFRCX0hERF8wMi9zaGVkdXJraW4vdGltZXNlcmllc19tb2xlY3VsYXInCmVjaG8gJ2V4cG9ydCBvdXRwdXRfZGlyX3RvcD0ke3RpbWVzZXJpZXNfZGlyfS9ELUFwdWwvb3V0cHV0LzAxLjAwLUQtQXB1bC1STkFzZXEtdHJpbW1pbmctZmFzdHAtRmFzdFFDLU11bHRpUUMnCmVjaG8gJ2V4cG9ydCByYXdfcmVhZHNfZGlyPSR7dGltZXNlcmllc19kaXJ9L0QtQXB1bC9kYXRhL3Jhdy1mYXN0cXMnCmVjaG8gJ2V4cG9ydCByYXdfcmVhZHNfdXJsPSJodHRwczovL293bC5maXNoLndhc2hpbmd0b24uZWR1L25pZ2h0aW5nYWxlcy9FNS1jb3JhbC10aW1lLXNlcmllcy8zMC0xMDQ3NTYwNTA4LyInCmVjaG8gJ2V4cG9ydCB0cmltbWVkX2Zhc3Rxc19kaXI9JHtvdXRwdXRfZGlyX3RvcH0vdHJpbW1lZC1mYXN0cXMnCmVjaG8gJ2V4cG9ydCB0cmltbWVkX2Zhc3RxY19kaXI9JHtvdXRwdXRfZGlyX3RvcH0vdHJpbW1lZC1mYXN0cWMnCmVjaG8gIiIKCmVjaG8gIiMgUGF0aHMgdG8gcHJvZ3JhbXMiCmVjaG8gJ2V4cG9ydCBwcm9ncmFtc19kaXI9Ii9ob21lL3NoYXJlZCInCmVjaG8gJ2V4cG9ydCBmYXN0cD0iJHtwcm9ncmFtc19kaXJ9L2Zhc3RwIicKZWNobyAnZXhwb3J0IGZhc3RxYz0ke3Byb2dyYW1zX2Rpcn0vRmFzdFFDLTAuMTIuMS9mYXN0cWMnCmVjaG8gJ2V4cG9ydCBtdWx0aXFjPS9ob21lL3NhbS9wcm9ncmFtcy9tYW1iYWZvcmdlL2Jpbi9tdWx0aXFjJwplY2hvICIiCgplY2hvICIjIFNldCBGYXN0USBmaWxlbmFtZSBwYXR0ZXJucyIKZWNobyAiZXhwb3J0IGZhc3RxX3BhdHRlcm49JyouZmFzdHEuZ3onIgplY2hvICJleHBvcnQgUjFfZmFzdHFfcGF0dGVybj0nKl9SMV8qLmZhc3RxLmd6JyIKZWNobyAiZXhwb3J0IFIyX2Zhc3RxX3BhdHRlcm49JypfUjJfKi5mYXN0cS5neiciCmVjaG8gImV4cG9ydCB0cmltbWVkX2Zhc3RxX3BhdHRlcm49JypmYXN0cC10cmltLmZxLmd6JyIKZWNobyAiIgoKZWNobyAiIyBTZXQgbnVtYmVyIG9mIENQVXMgdG8gdXNlIgplY2hvICdleHBvcnQgdGhyZWFkcz00MCcKZWNobyAiIgoKCmVjaG8gIiMjIEluaXRpdGFsaXplIGFycmF5cyIKZWNobyAnZXhwb3J0IGZhc3RxX2FycmF5X1IxPSgpJwplY2hvICdleHBvcnQgZmFzdHFfYXJyYXlfUjI9KCknCmVjaG8gJ2V4cG9ydCByYXdfZmFzdHFzX2FycmF5PSgpJwplY2hvICdleHBvcnQgUjFfbmFtZXNfYXJyYXk9KCknCmVjaG8gJ2V4cG9ydCBSMl9uYW1lc19hcnJheT0oKScKZWNobyAiIgoKZWNobyAiIyBQcm9ncmFtcyBhc3NvY2lhdGl2ZSBhcnJheSIKZWNobyAiZGVjbGFyZSAtQSBwcm9ncmFtc19hcnJheSIKZWNobyAicHJvZ3JhbXNfYXJyYXk9KCIKZWNobyAnW2Zhc3RwXT0iJHtmYXN0cH0iIFwnCmVjaG8gJ1tmYXN0cWNdPSIke2Zhc3RxY30iIFwnCmVjaG8gJ1ttdWx0aXFjXT0iJHttdWx0aXFjfSIgXCcKZWNobyAiKSIKZWNobyAiIgoKZWNobyAiIyBQcmludCBmb3JtYXR0aW5nIgplY2hvICdleHBvcnQgbGluZT0iLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0iJwplY2hvICIiCn0gPiAuYmFzaHZhcnMKCmNhdCAuYmFzaHZhcnMKYGBgCgpJZiBuZWVkZWQsIGRvd25sb2FkIHJhdyBSTkEtc2VxLgoKQ2hhbmdlIGBldmFsPUZBTFNFYCB0byBgZXZhbD1UUlVFYCB0byBleGVjdXRlIHRoZSBuZXh0IHR3byBjaHVua3MgdG8gZG93bmxvYWQgUk5BLXNlcSBhbmQgdGhlbiB2ZXJpZnkgTUQ1IGNoZWNrc3Vtcy4KCmBgYHtiYXNoIGRvd25sb2FkLXJhdy1yZWFkcywgZW5naW5lPSdiYXNoJ30KIyBMb2FkIGJhc2ggdmFyaWFibGVzIGludG8gbWVtb3J5CnNvdXJjZSAuYmFzaHZhcnMKCiMgTWFrZSBvdXRwdXQgZGlyZWN0b3J5IGlmIGl0IGRvZXNuJ3QgZXhpc3QKbWtkaXIgLS1wYXJlbnRzICR7cmF3X3JlYWRzX2Rpcn0KCiMgQ3JlYXRlIGxpc3Qgb2Ygb25seSBBLnB1bGNocmEgc2FtcGxlIG5hbWVzCnNhbXBsZV9saXN0PSQoYXdrIC1GICIsIiAnJDYgfiAvXkFDUi8ge3ByaW50ICQ1fScgJHt0aW1lc2VyaWVzX2Rpcn0vTS1tdWx0aS1zcGVjaWVzL2RhdGEvcm5hX21ldGFkYXRhLmNzdikKCmVjaG8gIiIKZWNobyAiJHtsaW5lfSIKZWNobyAiIgplY2hvICJTYW1wbGUgbGlzdDoiCmVjaG8gIiIKZWNobyAiJHtzYW1wbGVfbGlzdH0iCmVjaG8gIiIKZWNobyAiJHtsaW5lfSIKZWNobyAiIgoKCiMgVXNlIHByaW50ZiB0byBmb3JtYXQgZWFjaCBpdGVtIGZvciB1c2UgaW4gd2dldApmb3JtYXR0ZWRfbGlzdD0kKHByaW50ZiAiKiVzXyosIiAke3NhbXBsZV9saXN0fSkKCiMgUmVtb3ZlIHRoZSB0cmFpbGluZyBjb21tYQpmb3JtYXR0ZWRfbGlzdD0ke2Zvcm1hdHRlZF9saXN0JSx9CgojIE91dHB1dCB0aGUgZmluYWwgd2dldCBjb21tYW5kCmVjaG8gIiIKZWNobyAiJHtsaW5lfSIKZWNobyAiIgplY2hvICJGb3JtYXR0ZWQgd2dldCBhY2NlcHQgbGlzdDoiCmVjaG8gIiIKZWNobyAid2dldCAtLWFjY2VwdD1cIiRmb3JtYXR0ZWRfbGlzdFwiIgplY2hvICIiCmVjaG8gIiR7bGluZX0iCmVjaG8gIiIKCiMgUnVuIHdnZXQgdG8gcmV0cmlldmUgRmFzdFFzIGFuZCBNRDUgZmlsZXMKIyBOb3RlOiB0aGUgLS1uby1jbG9iYmVyIGNvbW1hbmQgd2lsbCBza2lwIHJlLWRvd25sb2FkaW5nIGFueSBmaWxlcyB0aGF0IGFyZSBhbHJlYWR5IHByZXNlbnQgaW4gdGhlIG91dHB1dCBkaXJlY3RvcnkKd2dldCBcCi0tZGlyZWN0b3J5LXByZWZpeCAke3Jhd19yZWFkc19kaXJ9IFwKLS1yZWN1cnNpdmUgXAotLW5vLWNoZWNrLWNlcnRpZmljYXRlIFwKLS1jb250aW51ZSBcCi0tY3V0LWRpcnMgMyBcCi0tbm8taG9zdC1kaXJlY3RvcmllcyBcCi0tbm8tcGFyZW50IFwKLS1xdWlldCBcCi0tbm8tY2xvYmJlciBcCi0tYWNjZXB0PSR7Zm9ybWF0dGVkX2xpc3R9ICR7cmF3X3JlYWRzX3VybH0KCmxzIC1saCAiJHtyYXdfcmVhZHNfZGlyfSIKYGBgCgpWZXJpZnkgcmF3IHJlYWQgY2hlY2tzdW1zCmBgYHtiYXNoIHZlcmlmeS1yYXctcmVhZC1jaGVja3N1bXMsIGVuZ2luZT0nYmFzaCd9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgpjZCAiJHtyYXdfcmVhZHNfZGlyfSIKCiMgQ2hlY2tzdW1zIGZpbGUgY29udGFpbnMgb3RoZXIgZmlsZXMsIHNvIHRoaXMganVzdCBsb29rcyBmb3IgdGhlIHNSTkFzZXEgZmlsZXMuCmZvciBmaWxlIGluICoubWQ1CmRvCiAgbWQ1c3VtIC0tY2hlY2sgIiR7ZmlsZX0iCmRvbmUKYGBgCgojIEZhc3RwIFRyaW1taW5nCgpbZmFzdHBdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuR2VuZS9mYXN0cCkgW0BjaGVuMjAyM10gaXMgc2V0IHRvIGF1dG8tZGV0ZWN0IElsbHVtaW5hIGFkYXB0ZXJzLCBhcyB3ZWxsIGFzIHRyaW0gdGhlIGZpcnN0IDIwYnAgZnJvbSBlYWNoIHJlYWQsIGFzIHBhc3QgZXhwZXJpZW5jZSBzaG93cyB0aGVzZSBmaXJzdCAyMGJwIGFyZSBtb3JlIGluY29uc2lzdGVudCB0aGFuIHRoZSByZW1haW5kZXIgb2YgdGhlIHJlYWQgbGVuZ3RoLgoKYGBge2Jhc2ggZmFzdHAtdHJpbW1pbmcsIGVuZ2luZT0nYmFzaCd9CiMgTG9hZCBiYXNoIHZhcmlhYmxlcyBpbnRvIG1lbW9yeQpzb3VyY2UgLmJhc2h2YXJzCgojIE1ha2Ugb3V0cHV0IGRpcmVjdG9yaWVzLCBpZiBpdCBkb2Vzbid0IGV4aXN0Cm1rZGlyIC0tcGFyZW50cyAiJHt0cmltbWVkX2Zhc3Rxc19kaXJ9IgoKIyBDaGFuZ2UgdG8gcmF3IHJlYWRzIGRpcmVjdG9yeQpjZCAiJHtyYXdfcmVhZHNfZGlyfSIKCiMgQ3JlYXRlIGFycmF5cyBvZiBmYXN0cSBSMSBmaWxlcyBhbmQgc2FtcGxlIG5hbWVzCmZvciBmYXN0cSBpbiAke1IxX2Zhc3RxX3BhdHRlcm59CmRvCiAgZmFzdHFfYXJyYXlfUjErPSgiJHtmYXN0cX0iKQogIFIxX25hbWVzX2FycmF5Kz0oIiQoZWNobyAiJHtmYXN0cX0iIHwgYXdrIC1GIl8iICd7cHJpbnQgJDF9JykiKQpkb25lCgojIENyZWF0ZSBhcnJheSBvZiBmYXN0cSBSMiBmaWxlcwpmb3IgZmFzdHEgaW4gJHtSMl9mYXN0cV9wYXR0ZXJufQpkbwogIGZhc3RxX2FycmF5X1IyKz0oIiR7ZmFzdHF9IikKICBSMl9uYW1lc19hcnJheSs9KCIkKGVjaG8gIiR7ZmFzdHF9IiB8IGF3ayAtRiJfIiAne3ByaW50ICQxfScpIikKZG9uZQoKIyBDcmVhdGUgbGlzdCBvZiBmYXN0cSBmaWxlcyB1c2VkIGluIGFuYWx5c2lzCiMgQ3JlYXRlIE1ENSBjaGVja3N1bSBmb3IgcmVmZXJlbmNlCmlmIFsgISAtZiAiJHtvdXRwdXRfZGlyX3RvcH0iL3Jhdy1mYXN0cS1jaGVja3N1bXMubWQ1IF07IHRoZW4KZm9yIGZhc3RxIGluICouZ3oKICBkbwogICAgbWQ1c3VtICR7ZmFzdHF9ID4+ICIke291dHB1dF9kaXJfdG9wfSIvcmF3LWZhc3RxLWNoZWNrc3Vtcy5tZDUKICBkb25lCmZpCgojIFJ1biBmYXN0cCBvbiBmaWxlcwojIEFkZHMgSlNPTiByZXBvcnQgb3V0cHV0IGZvciBkb3duc3RyZWFtIHVzYWdlIGJ5IE11bHRpUUMKZm9yIGluZGV4IGluICIkeyFmYXN0cV9hcnJheV9SMVtAXX0iCmRvCiAgUjFfc2FtcGxlX25hbWU9JChlY2hvICIke1IxX25hbWVzX2FycmF5W2luZGV4XX0iKQogIFIyX3NhbXBsZV9uYW1lPSQoZWNobyAiJHtSMl9uYW1lc19hcnJheVtpbmRleF19IikKICAke2Zhc3RwfSBcCiAgLS1pbjEgJHtmYXN0cV9hcnJheV9SMVtpbmRleF19IFwKICAtLWluMiAke2Zhc3RxX2FycmF5X1IyW2luZGV4XX0gXAogIC0tZGV0ZWN0X2FkYXB0ZXJfZm9yX3BlIFwKICAtLXRyaW1fZnJvbnQxIDIwIFwKICAtLXRyaW1fZnJvbnQyIDIwIFwKICAtLXRocmVhZCAke3RocmVhZHN9IFwKICAtLWh0bWwgIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIvIiR7UjFfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLnJlcG9ydC5odG1sIFwKICAtLWpzb24gIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIvIiR7UjFfc2FtcGxlX25hbWV9Ii5mYXN0cC10cmltLnJlcG9ydC5qc29uIFwKICAtLW91dDEgIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIvIiR7UjFfc2FtcGxlX25hbWV9Il9SMV8wMDEuZmFzdHAtdHJpbS5mcS5neiBcCiAgLS1vdXQyICIke3RyaW1tZWRfZmFzdHFzX2Rpcn0iLyIke1IyX3NhbXBsZV9uYW1lfSJfUjJfMDAxLmZhc3RwLXRyaW0uZnEuZ3ogXAogIDI+PiAiJHt0cmltbWVkX2Zhc3Rxc19kaXJ9Ii9mYXN0cC5zdGRlcnIKCiAgIyBHZW5lcmF0ZSBtZDUgY2hlY2tzdW1zIGZvciBuZXdseSB0cmltbWVkIGZpbGVzCiAgY2QgIiR7dHJpbW1lZF9mYXN0cXNfZGlyfSIKICBtZDVzdW0gIiR7UjFfc2FtcGxlX25hbWV9Il9SMV8wMDEuZmFzdHAtdHJpbS5mcS5neiA+ICIke1IxX3NhbXBsZV9uYW1lfSJfUjFfMDAxLmZhc3RwLXRyaW0uZnEuZ3oubWQ1CiAgbWQ1c3VtICIke1IyX3NhbXBsZV9uYW1lfSJfUjJfMDAxLmZhc3RwLXRyaW0uZnEuZ3ogPiAiJHtSMl9zYW1wbGVfbmFtZX0iX1IyXzAwMS5mYXN0cC10cmltLmZxLmd6Lm1kNQogIGNkIC0KZG9uZQpgYGAKCgojIFF1YWxpdHkgQ2hlY2sgd2l0aCBGYXN0UUMgYW5kIE11bHRpUUMKYGBge2Jhc2ggdHJpbW1lZC1mYXN0cWMtbXVsdGlxYywgZW5naW5lPSdiYXNoJ30KIyBMb2FkIGJhc2ggdmFyaWFibGVzIGludG8gbWVtb3J5CnNvdXJjZSAuYmFzaHZhcnMKCiMgTWFrZSBvdXRwdXQgZGlyZWN0b3J5IGlmIGl0IGRvZXNuJ3QgZXhpc3QKbWtkaXIgLS1wYXJlbnRzICIke3RyaW1tZWRfZmFzdHFjX2Rpcn0iCgojIyMjIyMjIyMjIyMgUlVOIEZBU1RRQyAjIyMjIyMjIyMjIyMKCgojIENyZWF0ZSBhcnJheSBvZiB0cmltbWVkIEZhc3RRcwp0cmltbWVkX2Zhc3Rxc19hcnJheT0oJHt0cmltbWVkX2Zhc3Rxc19kaXJ9LyR7dHJpbW1lZF9mYXN0cV9wYXR0ZXJufSkKCiMgUGFzcyBhcnJheSBjb250ZW50cyB0byBuZXcgdmFyaWFibGUgYXMgc3BhY2UtZGVsaW1pdGVkIGxpc3QKdHJpbW1lZF9mYXN0cWNfbGlzdD0kKGVjaG8gIiR7dHJpbW1lZF9mYXN0cXNfYXJyYXlbKl19IikKCmVjaG8gIkJlZ2lubmluZyBGYXN0UUMgb24gdHJpbW1lZCByZWFkcy4uLiIKZWNobyAiIgoKIyBSdW4gRmFzdFFDCiMjIyBOT1RFOiBEbyBOT1QgcXVvdGUgcmF3X2Zhc3RxY19saXN0CiR7cHJvZ3JhbXNfYXJyYXlbZmFzdHFjXX0gXAotLXRocmVhZHMgJHt0aHJlYWRzfSBcCi0tb3V0ZGlyICR7dHJpbW1lZF9mYXN0cWNfZGlyfSBcCi0tcXVpZXQgXAoke3RyaW1tZWRfZmFzdHFjX2xpc3R9CgplY2hvICJGYXN0UUMgb24gdHJpbW1lZCByZWFkcyBjb21wbGV0ZSEiCmVjaG8gIiIKCiMjIyMjIyMjIyMjIyBFTkQgRkFTVFFDICMjIyMjIyMjIyMjIwoKIyMjIyMjIyMjIyMjIFJVTiBNVUxUSVFDICMjIyMjIyMjIyMjIwplY2hvICJCZWdpbm5pbmcgTXVsdGlRQyBvbiB0cmltbWVkIEZhc3RRQy4uLiIKZWNobyAiIgoKJHtwcm9ncmFtc19hcnJheVttdWx0aXFjXX0gJHt0cmltbWVkX2Zhc3RxY19kaXJ9IC1vICR7dHJpbW1lZF9mYXN0cWNfZGlyfQoKZWNobyAiIgplY2hvICJNdWx0aVFDIG9uIHRyaW1tZWQgRmFzdFFzIGNvbXBsZXRlLiIKZWNobyAiIgoKIyMjIyMjIyMjIyMjIEVORCBNVUxUSVFDICMjIyMjIyMjIyMjIwoKZWNobyAiUmVtb3ZpbmcgRmFzdFFDIHppcCBmaWxlcy4iCmVjaG8gIiIKcm0gJHt0cmltbWVkX2Zhc3RxY19kaXJ9LyouemlwCmVjaG8gIkZhc3RRQyB6aXAgZmlsZXMgcmVtb3ZlZC4iCmVjaG8gIiIKYGBgCg==