Introduction

This metabarcoding pipeline is based around the targets package, which is a Make-like pipeline tool for R. The benefit of this is that all the code is automatically run, and the pipeline skips costly runtime for tasks that are already up to date.

This page lists the general workflow and all the options that can be adapted for your dataset.

Clone the pipeRline github repository

The first step is to clone this github repository, which contains the required code and directory structure to run the pipeline. To do this, you will need Git installed on your computer. If you are running the pipeline in Rstudio, it is best to create a new project from the github repository. This can be done by going file > new project > version control > git then adding https://github.com/alexpiper/piperline.git then change the name of the project to whatever you are working with.

Alternatively, the repository can be cloned using the command line, change the ‘folder-name’ to the desired name

# Change into the main directory you wish to make the project in
cd metabarcoding

# Clone the repository
git clone https://github.com/alexpiper/piperline.git folder-name

Prior to analysis

The PipeRline workflow assumes that your sequencing data meets certain criteria:

  1. Samples have been demultiplexed, i.e. split into individual per-sample fastq files. If you want the pipeline to calculate the index-switching rate, the fastq files need to be re-demultiplexed as the miseq does not put indexes in fasta headers by default
  2. For paired-end sequencing data, the forward and reverse reads are in separate files (ie. not interleaved) with reads arranged in matched order.

The output directory should be unique for each sequencing run, named as the flowcell id, within a directory called data

For example:

root/
  ├── data/
     ├── CJL7D/
     

You will also need BLAST+ installed on your computer, it can be downloaded from the NCBI website

Demultiplex sequencing reads

For this workflow to run, we need to first demultiplex the miseq run again as the miseq does not put indexes in fasta headers by default, and also obtain some necessary files from the sequencing folder. The below code is written for the Agriculture Victoria BASC server, and the locations will be different if you are using a different HPC cluster.

#load module
module load bcl2fastq2/2.20.0-foss-2018b

#raise amount of available file handles
ulimit -n 4000

###Run1

#Set up input and outputs
inputdir=/group/sequencing/230127_M01054_0817_000000000-KWD4N
outputdir=/group/pathogens/IAWS/Projects/Metabarcoding/SVBS_marine_metabarcoding/data/KWD4N #CHANGE TO YOUR DATA FOLDER RUN
samplesheet=/group/pathogens/IAWS/Projects/Metabarcoding/SVBS_marine_metabarcoding/SampleSheet_KWD4N.csv #CHANGE TO YOUR SAMPLESHEET

# convert samplesheet to unix format
dos2unix $samplesheet

#Demultiplex
bcl2fastq -p 12 --runfolder-dir $inputdir \
--output-dir $outputdir \
--sample-sheet $samplesheet \
--no-lane-splitting --barcode-mismatches 1

# Copy other necessary files and move fastqs
cd $outputdir
cp -r $inputdir/InterOp $outputdir
cp $inputdir/RunInfo.xml $outputdir
cp $inputdir/[Rr]unParameters.xml $outputdir
cp $samplesheet $outputdir
mv **/*.fastq.gz $outputdir

# Append fcid to start of sample names if missing
fcid=$(echo $inputdir | sed 's/^.*-//')
for i in *.fastq.gz; do
  if ! [[ $i == $fcid* ]]; then
  new=$(echo ${fcid} ${i}) #append together
  new=$(echo ${new// /_}) #remove any white space
  mv -v "$i" "$new"
  fi
done

Install and load R packages and setup directories

# Load the targets and renv packages
library(targets)
library(tarchetypes)

# Load all packages using renv::restore() and source package list
renv::restore()
source("_targets_packages.R")

# Source ancillary functions
source("R/functions.R")
source("R/themes.R")

Create sample tracking sheet

In order to track samples and relevant QC statistics throughout the metabarcoding pipeline, we will first create a new samplesheet from our input samplesheets. This function requires both the SampleSheet.csv used for the sequencing run, and the runParameters.xml, both of which should have been automatically obtained from the demultiplexed sequencing run folder in the bash step above

runs <- dir("data/") #Find all directories within data
SampleSheet <- list.files(paste0("data/", runs), pattern= "SampleSheet", full.names = TRUE)
runParameters <- list.files(paste0("data/", runs), pattern= "[Rr]unParameters.xml", full.names = TRUE)

# Create samplesheet containing samples and run parameters for all runs
samdf <- create_samplesheet(SampleSheet = SampleSheet, runParameters = runParameters, template = "V4") %>%
  distinct()

# Check that sample_ids contain fcid, if not; attatch
samdf <- samdf %>%
  mutate(sample_id = case_when(
    !str_detect(sample_id, fcid) ~ paste0(fcid,"_",sample_id),
    TRUE ~ sample_id
  ))

# Check that samples match samplesheet
fastqFs <- purrr::map(list.dirs("data", recursive=FALSE),
                      list.files, pattern="_R1_", full.names = TRUE) %>%
  unlist() %>%
  str_remove(pattern = "^(.*)\\/") %>%
  str_remove(pattern = "(?:.(?!_S))+$")

# Filter undetermined reads from sample sheet
fastqFs <- fastqFs[!str_detect(fastqFs, "Undetermined")]

# Check for fastq files that are missing from samplesheet
if (length(setdiff(fastqFs, samdf$sample_id)) > 0) {warning("The fastq file/s: ", setdiff(fastqFs, samdf$sample_id), " are not in the sample sheet") }

# Check for sample_ids that dont have a corresponding fastq file
if (length(setdiff(samdf$sample_id, fastqFs)) > 0) {
  warning(paste0("The fastq file: ",
                 setdiff(samdf$sample_id, fastqFs),
                 " is missing, dropping from samplesheet \n")) 
  samdf <- samdf %>%
    filter(!sample_id %in% setdiff(samdf$sample_id, fastqFs))
}

# Write out sample tracking sheet
write_csv(samdf, "sample_data/Sample_info.csv")

Add PCR primers to sample sheet

This can either be done manually by editing the sample_data/Sample_info.csv file, or it can be done in R as below.

If a single primer set was used across all samples, these can simply be added using a mutate call (tab 1).

If different primers were used for different samples, these can be set using pattern matching on the sample names with case_when (tab 2).

If multiple primer sets are used per sample, before indexing, the pipeline will conduct an extra round of demultiplexing to split each sample by primer. This option can be set by splitting each primer set with a semicolon (tab 3)

Multiple primer sets per sample

# Add PCR primers to sample sheet
samdf <- samdf %>%
  mutate(
    pcr_primers = "mlCOIintF-jgHCO2198;Uni18S-Uni18SR",
    for_primer_seq = "GGWACWGGWTGAACWGTWTAYCCYCC;AGGGCAAKYCTGGTGCCAGC",
    rev_primer_seq = "TAIACYTCIGGRTGICCRAARAAYCA;GRCGGTATCTRATCGYCTT"
    )

write_csv(samdf, "sample_data/Sample_info.csv")

Create parameters file

The parameters file table the respective target gene, reference databases, and filtering parameters for each primer set used to amplify the samples. As the pcr_primers column is used in the pipeline to match the parameters to the respective sample, it is critical that the primer names match those set in the previous step.

If a single primer set was used across all samples, these can simply be added to the table as below (tab 1).

If different primers were used for different samples, these can be set as different rows in the table using c() when creatign the tibble (tab 2).

If multiple primer reference databases are to be used for each sample, these can be set by splitting each a semicolon. The taxonomic assignment will be conducted sequentially through the databases from left to right, with the second reference database only being used for those ASVs that couldnt be assigned to species level using the first databases (tab 3)

Parameter options

  • Primer parameters:
    • pcr_primers - Name of PCR primers - must match samdf file
    • target_gene - Name of target gene
    • max_primer_mismatch - How much mismatch to allow when detecting primer sequences
  • Read filterign:
    • read_min_length - Minimum length of primer trimmed reads
    • read_max_length - Maximum length of primer trimmed reads
    • read_max_ee - Maximum expected errors of primer trimmed reads
    • read_trunc_length - Length to cut all longer reads to
    • read_trim_left - Remove this many bp from left side of primer trimmed reads
    • read_trim_right - Remove this many bp from right side of primer trimmed reads
  • ASV filtering
    • asv_min_length - Minimum length of amplicon
    • asv_max_length - Maximum length of amplicon
    • high_sensitivity - Option to turn on pseudo pooling, setting this to FALSE greatly speeds up ASV inference at the expense of detecting fewer rare (<5 reads) taxa.
    • concat_unmerged - Retain any unmerged read pairs by concatenating them together separated by a string of 10 N bases
    • genetic_code - Genetic code for amplicon - see Biostrings::GENETIC_CODE_TABLE
    • coding - Is the amplicon from a protein coding gene
    • phmm - Path to profile hidden markov model (Optional)
  • Taxonomic assignment:
    • idtaxa_db - Path to trained IDTAXA model
    • ref_fasta - Path to fasta file of reference database
    • idtaxa_confidence - Minimum bootstrap confidence for IDTAXA
    • run_blast - Whether a blast top hit search should be conducted in addition to IDTAXA
    • blast_min_identity - Minimum nucleotide identity for BLAST
    • target_kingdom - Subset to target kingdom
    • target_phylum - Subset to target phylum
    • target_class - Subset to target class
    • target_order - Subset to target order
    • target_family - Subset to target family
    • target_genus - Subset to target genus
    • target_species - Subset to target species
  • Sample & Taxon filtering:
    • min_sample_reads - Minimum reads per sample after filtering
    • min_taxa_reads - Minimum reads per ASV to retain
    • min_taxa_ra - Minimum relative abundance per ASV to retain. 1e-4 is 0.01%
  • General pipeline parameters
    • threads - Number of CPU threads to run the pipeline across

Different or multiple primer sets per sample

# Params to add in step_add_parameters
params <- tibble(
  # Amplicon parameters
  pcr_primers = c("mlCOIintF-jgHCO2198", "Uni18S-Uni18SR"),
  target_gene=c("COI", "18S"),
  max_primer_mismatch=0,

  # Read filtering
  read_min_length = 20,
  read_max_length = Inf,
  read_max_ee = 1,
  read_trunc_length = 224,
  read_trim_left = 0,
  read_trim_right = 0,
  
  # ASV filtering
  asv_min_length = c(303, 50), #MtCOIintF-jgHCO2198 = 313bp
  asv_max_length = c(323, 500),
  high_sensitivity = TRUE,
  concat_unmerged = TRUE,
  genetic_code = c("SGC4", "SGC0"),
  coding = c(TRUE, FALSE),
  phmm = NA_character_,
  
  # Taxonomic assignment
  idtaxa_db = c("reference/COI_idtaxa.rds","reference/18S_idtaxa.rds"),
  ref_fasta = c("reference/COI_hierarchial.fa.gz", "reference/18S_hierarchial.fa.gz"),
  idtaxa_confidence = 60,
  run_blast=TRUE,
  blast_min_identity = 97,
  blast_min_coverage = 90,
  target_kingdom = NA_character_,
  target_phylum = NA_character_,
  target_class = NA_character_,
  target_order = NA_character_,
  target_family = NA_character_, 
  target_genus = NA_character_,  
  target_species= NA_character_,  
  
  # Sample & Taxon filtering
  min_sample_reads = 0,
  min_taxa_reads= 0, # Minimum reads per ASV to retain
  min_taxa_ra = 0, # Minimum relative abundance per ASV to retain. 1e-4 is 0.01%
  
  # General pipeline parameters
  threads = 1
)

write_csv(params, "sample_data/loci_params.csv")

Run pipeline

Now that the sample data sheet and parameters are defined, the pipeline steps can now be visualised, and then run automatically.

tar_make()

Results

See the general introduction vignette for an in-depth explanation of the results and quality control outputs

LS0tDQp0aXRsZTogIlBpcGVSbGluZSINCnN1YnRpdGxlOiAiTWFyaW5lIFN1cnZlaWxsYW5jZSINCmF1dGhvcjogIkEuTS4gUGlwZXIiDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6DQogIA0KICBodG1sX2RvY3VtZW50Og0KICAgIGhpZ2hsaWdodGVyOiBudWxsDQogICAgdGhlbWU6ICJmbGF0bHkiDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogDQogICAgICBjb2xsYXBzZWQ6IGZhbHNlDQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgZGZfcHJpbnQ6IHBhZ2VkICAgIA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgS25pdHIgZ2xvYmFsIHNldHVwIC0gY2hhbmdlIGV2YWwgdG8gdHJ1ZSB0byBydW4gY29kZQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkodGFyZ2V0cykNCmxpYnJhcnkodGFyY2hldHlwZXMpDQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSxlcnJvcj1GQUxTRSwgZmlnLnNob3cgPSAiaG9sZCIsIGZpZy5rZWVwID0gImFsbCIpDQpvcHRzX2NodW5rJHNldChkZXYgPSAncG5nJykNCmBgYA0KDQojIEludHJvZHVjdGlvbg0KDQpUaGlzIG1ldGFiYXJjb2RpbmcgcGlwZWxpbmUgaXMgYmFzZWQgYXJvdW5kIHRoZSB0YXJnZXRzIHBhY2thZ2UsIHdoaWNoIGlzIGEgTWFrZS1saWtlIHBpcGVsaW5lIHRvb2wgZm9yIFIuIFRoZSBiZW5lZml0IG9mIHRoaXMgaXMgdGhhdCBhbGwgdGhlIGNvZGUgaXMgYXV0b21hdGljYWxseSBydW4sIGFuZCB0aGUgcGlwZWxpbmUgc2tpcHMgY29zdGx5IHJ1bnRpbWUgZm9yIHRhc2tzIHRoYXQgYXJlIGFscmVhZHkgdXAgdG8gZGF0ZS4NCg0KVGhpcyBwYWdlIGxpc3RzIHRoZSBnZW5lcmFsIHdvcmtmbG93IGFuZCBhbGwgdGhlIG9wdGlvbnMgdGhhdCBjYW4gYmUgYWRhcHRlZCBmb3IgeW91ciBkYXRhc2V0Lg0KDQojIENsb25lIHRoZSBwaXBlUmxpbmUgZ2l0aHViIHJlcG9zaXRvcnkNCg0KVGhlIGZpcnN0IHN0ZXAgaXMgdG8gY2xvbmUgdGhpcyBnaXRodWIgcmVwb3NpdG9yeSwgd2hpY2ggY29udGFpbnMgdGhlIHJlcXVpcmVkIGNvZGUgYW5kIGRpcmVjdG9yeSBzdHJ1Y3R1cmUgdG8gcnVuIHRoZSBwaXBlbGluZS4gVG8gZG8gdGhpcywgeW91IHdpbGwgbmVlZCBbR2l0XShodHRwczovL2dpdC1zY20uY29tLykgaW5zdGFsbGVkIG9uIHlvdXIgY29tcHV0ZXIuIElmIHlvdSBhcmUgcnVubmluZyB0aGUgcGlwZWxpbmUgaW4gUnN0dWRpbywgaXQgaXMgYmVzdCB0byBjcmVhdGUgYSBuZXcgcHJvamVjdCBmcm9tIHRoZSBnaXRodWIgcmVwb3NpdG9yeS4gVGhpcyBjYW4gYmUgZG9uZSBieSBnb2luZyAqKmZpbGUgPiBuZXcgcHJvamVjdCA+IHZlcnNpb24gY29udHJvbCA+IGdpdCoqIHRoZW4gYWRkaW5nIGh0dHBzOi8vZ2l0aHViLmNvbS9hbGV4cGlwZXIvcGlwZXJsaW5lLmdpdCB0aGVuIGNoYW5nZSB0aGUgbmFtZSBvZiB0aGUgcHJvamVjdCB0byB3aGF0ZXZlciB5b3UgYXJlIHdvcmtpbmcgd2l0aC4gDQoNCkFsdGVybmF0aXZlbHksIHRoZSByZXBvc2l0b3J5IGNhbiBiZSBjbG9uZWQgdXNpbmcgdGhlIGNvbW1hbmQgbGluZSwgY2hhbmdlIHRoZSAnZm9sZGVyLW5hbWUnIHRvIHRoZSBkZXNpcmVkIG5hbWUNCmBgYHtiYXNofQ0KIyBDaGFuZ2UgaW50byB0aGUgbWFpbiBkaXJlY3RvcnkgeW91IHdpc2ggdG8gbWFrZSB0aGUgcHJvamVjdCBpbg0KY2QgbWV0YWJhcmNvZGluZw0KDQojIENsb25lIHRoZSByZXBvc2l0b3J5DQpnaXQgY2xvbmUgaHR0cHM6Ly9naXRodWIuY29tL2FsZXhwaXBlci9waXBlcmxpbmUuZ2l0IGZvbGRlci1uYW1lDQpgYGANCg0KIyBQcmlvciB0byBhbmFseXNpcw0KVGhlIFBpcGVSbGluZSB3b3JrZmxvdyBhc3N1bWVzIHRoYXQgeW91ciBzZXF1ZW5jaW5nIGRhdGEgbWVldHMgY2VydGFpbiBjcml0ZXJpYToNCg0KMS4gU2FtcGxlcyBoYXZlIGJlZW4gZGVtdWx0aXBsZXhlZCwgaS5lLiBzcGxpdCBpbnRvIGluZGl2aWR1YWwgcGVyLXNhbXBsZSBmYXN0cSBmaWxlcy4gSWYgeW91IHdhbnQgdGhlIHBpcGVsaW5lIHRvIGNhbGN1bGF0ZSB0aGUgaW5kZXgtc3dpdGNoaW5nIHJhdGUsIHRoZSBmYXN0cSBmaWxlcyBuZWVkIHRvIGJlIHJlLWRlbXVsdGlwbGV4ZWQgYXMgdGhlIG1pc2VxIGRvZXMgbm90IHB1dCBpbmRleGVzIGluIGZhc3RhIGhlYWRlcnMgYnkgZGVmYXVsdA0KMi4gRm9yIHBhaXJlZC1lbmQgc2VxdWVuY2luZyBkYXRhLCB0aGUgZm9yd2FyZCBhbmQgcmV2ZXJzZSByZWFkcyBhcmUgaW4gc2VwYXJhdGUgZmlsZXMgKGllLiBub3QgaW50ZXJsZWF2ZWQpIHdpdGggcmVhZHMgYXJyYW5nZWQgaW4gbWF0Y2hlZCBvcmRlci4NCg0KVGhlIG91dHB1dCBkaXJlY3Rvcnkgc2hvdWxkIGJlIHVuaXF1ZSBmb3IgZWFjaCBzZXF1ZW5jaW5nIHJ1biwgbmFtZWQgYXMgdGhlIGZsb3djZWxsIGlkLCB3aXRoaW4gYSBkaXJlY3RvcnkgY2FsbGVkIGRhdGENCg0KRm9yIGV4YW1wbGU6DQoNCiAgICByb290Lw0KICAgICAg4pSc4pSA4pSAIGRhdGEvDQogICAgICAgICDilJzilIDilIAgQ0pMN0QvDQogICAgICAgICANCllvdSB3aWxsIGFsc28gbmVlZCBCTEFTVCsgaW5zdGFsbGVkIG9uIHlvdXIgY29tcHV0ZXIsIGl0IGNhbiBiZSBkb3dubG9hZGVkIGZyb20gdGhlIFtOQ0JJIHdlYnNpdGVdKGh0dHBzOi8vYmxhc3QubmNiaS5ubG0ubmloLmdvdi9CbGFzdC5jZ2k/UEFHRV9UWVBFPUJsYXN0RG9jcyZET0NfVFlQRT1Eb3dubG9hZCkgDQogICAgICAgICANCiMjIERlbXVsdGlwbGV4IHNlcXVlbmNpbmcgcmVhZHMNCkZvciB0aGlzIHdvcmtmbG93IHRvIHJ1biwgd2UgbmVlZCB0byBmaXJzdCBkZW11bHRpcGxleCB0aGUgbWlzZXEgcnVuIGFnYWluIGFzIHRoZSBtaXNlcSBkb2VzIG5vdCBwdXQgaW5kZXhlcyBpbiBmYXN0YSBoZWFkZXJzIGJ5IGRlZmF1bHQsIGFuZCBhbHNvIG9idGFpbiBzb21lIG5lY2Vzc2FyeSBmaWxlcyBmcm9tIHRoZSBzZXF1ZW5jaW5nIGZvbGRlci4gVGhlIGJlbG93IGNvZGUgaXMgd3JpdHRlbiBmb3IgdGhlIEFncmljdWx0dXJlIFZpY3RvcmlhIEJBU0Mgc2VydmVyLCBhbmQgdGhlIGxvY2F0aW9ucyB3aWxsIGJlIGRpZmZlcmVudCBpZiB5b3UgYXJlIHVzaW5nIGEgZGlmZmVyZW50IEhQQyBjbHVzdGVyLg0KDQpgYGB7YmFzaCBkZW11bHRpcGxleCAxIG1pc21hdGNofQ0KI2xvYWQgbW9kdWxlDQptb2R1bGUgbG9hZCBiY2wyZmFzdHEyLzIuMjAuMC1mb3NzLTIwMThiDQoNCiNyYWlzZSBhbW91bnQgb2YgYXZhaWxhYmxlIGZpbGUgaGFuZGxlcw0KdWxpbWl0IC1uIDQwMDANCg0KIyMjUnVuMQ0KDQojU2V0IHVwIGlucHV0IGFuZCBvdXRwdXRzDQppbnB1dGRpcj0vZ3JvdXAvc2VxdWVuY2luZy8yMzAxMjdfTTAxMDU0XzA4MTdfMDAwMDAwMDAwLUtXRDRODQpvdXRwdXRkaXI9L2dyb3VwL3BhdGhvZ2Vucy9JQVdTL1Byb2plY3RzL01ldGFiYXJjb2RpbmcvU1ZCU19tYXJpbmVfbWV0YWJhcmNvZGluZy9kYXRhL0tXRDROICNDSEFOR0UgVE8gWU9VUiBEQVRBIEZPTERFUiBSVU4NCnNhbXBsZXNoZWV0PS9ncm91cC9wYXRob2dlbnMvSUFXUy9Qcm9qZWN0cy9NZXRhYmFyY29kaW5nL1NWQlNfbWFyaW5lX21ldGFiYXJjb2RpbmcvU2FtcGxlU2hlZXRfS1dENE4uY3N2ICNDSEFOR0UgVE8gWU9VUiBTQU1QTEVTSEVFVA0KDQojIGNvbnZlcnQgc2FtcGxlc2hlZXQgdG8gdW5peCBmb3JtYXQNCmRvczJ1bml4ICRzYW1wbGVzaGVldA0KDQojRGVtdWx0aXBsZXgNCmJjbDJmYXN0cSAtcCAxMiAtLXJ1bmZvbGRlci1kaXIgJGlucHV0ZGlyIFwNCi0tb3V0cHV0LWRpciAkb3V0cHV0ZGlyIFwNCi0tc2FtcGxlLXNoZWV0ICRzYW1wbGVzaGVldCBcDQotLW5vLWxhbmUtc3BsaXR0aW5nIC0tYmFyY29kZS1taXNtYXRjaGVzIDENCg0KIyBDb3B5IG90aGVyIG5lY2Vzc2FyeSBmaWxlcyBhbmQgbW92ZSBmYXN0cXMNCmNkICRvdXRwdXRkaXINCmNwIC1yICRpbnB1dGRpci9JbnRlck9wICRvdXRwdXRkaXINCmNwICRpbnB1dGRpci9SdW5JbmZvLnhtbCAkb3V0cHV0ZGlyDQpjcCAkaW5wdXRkaXIvW1JyXXVuUGFyYW1ldGVycy54bWwgJG91dHB1dGRpcg0KY3AgJHNhbXBsZXNoZWV0ICRvdXRwdXRkaXINCm12ICoqLyouZmFzdHEuZ3ogJG91dHB1dGRpcg0KDQojIEFwcGVuZCBmY2lkIHRvIHN0YXJ0IG9mIHNhbXBsZSBuYW1lcyBpZiBtaXNzaW5nDQpmY2lkPSQoZWNobyAkaW5wdXRkaXIgfCBzZWQgJ3MvXi4qLS8vJykNCmZvciBpIGluICouZmFzdHEuZ3o7IGRvDQogIGlmICEgW1sgJGkgPT0gJGZjaWQqIF1dOyB0aGVuDQogIG5ldz0kKGVjaG8gJHtmY2lkfSAke2l9KSAjYXBwZW5kIHRvZ2V0aGVyDQogIG5ldz0kKGVjaG8gJHtuZXcvLyAvX30pICNyZW1vdmUgYW55IHdoaXRlIHNwYWNlDQogIG12IC12ICIkaSIgIiRuZXciDQogIGZpDQpkb25lDQoNCmBgYA0KDQojIEluc3RhbGwgYW5kIGxvYWQgUiBwYWNrYWdlcyBhbmQgc2V0dXAgZGlyZWN0b3JpZXMgey50YWJzZXR9DQpgYGB7ciBNYW51YWwgaW5zdGFsbH0gDQojIExvYWQgdGhlIHRhcmdldHMgYW5kIHJlbnYgcGFja2FnZXMNCmxpYnJhcnkodGFyZ2V0cykNCmxpYnJhcnkodGFyY2hldHlwZXMpDQoNCiMgTG9hZCBhbGwgcGFja2FnZXMgdXNpbmcgcmVudjo6cmVzdG9yZSgpIGFuZCBzb3VyY2UgcGFja2FnZSBsaXN0DQpyZW52OjpyZXN0b3JlKCkNCnNvdXJjZSgiX3RhcmdldHNfcGFja2FnZXMuUiIpDQoNCiMgU291cmNlIGFuY2lsbGFyeSBmdW5jdGlvbnMNCnNvdXJjZSgiUi9mdW5jdGlvbnMuUiIpDQpzb3VyY2UoIlIvdGhlbWVzLlIiKQ0KYGBgDQoNCiMgQ3JlYXRlIHNhbXBsZSB0cmFja2luZyBzaGVldA0KDQpJbiBvcmRlciB0byB0cmFjayBzYW1wbGVzIGFuZCByZWxldmFudCBRQyBzdGF0aXN0aWNzIHRocm91Z2hvdXQgdGhlIG1ldGFiYXJjb2RpbmcgcGlwZWxpbmUsIHdlIHdpbGwgZmlyc3QgY3JlYXRlIGEgbmV3IHNhbXBsZXNoZWV0IGZyb20gb3VyIGlucHV0IHNhbXBsZXNoZWV0cy4gVGhpcyBmdW5jdGlvbiByZXF1aXJlcyBib3RoIHRoZSBTYW1wbGVTaGVldC5jc3YgdXNlZCBmb3IgdGhlIHNlcXVlbmNpbmcgcnVuLCBhbmQgdGhlIHJ1blBhcmFtZXRlcnMueG1sLCBib3RoIG9mIHdoaWNoIHNob3VsZCBoYXZlIGJlZW4gYXV0b21hdGljYWxseSBvYnRhaW5lZCBmcm9tIHRoZSBkZW11bHRpcGxleGVkIHNlcXVlbmNpbmcgcnVuIGZvbGRlciBpbiB0aGUgYmFzaCBzdGVwIGFib3ZlDQoNCmBgYHtyIGNyZWF0ZSBzYW1wbGVzaGVldH0NCnJ1bnMgPC0gZGlyKCJkYXRhLyIpICNGaW5kIGFsbCBkaXJlY3RvcmllcyB3aXRoaW4gZGF0YQ0KU2FtcGxlU2hlZXQgPC0gbGlzdC5maWxlcyhwYXN0ZTAoImRhdGEvIiwgcnVucyksIHBhdHRlcm49ICJTYW1wbGVTaGVldCIsIGZ1bGwubmFtZXMgPSBUUlVFKQ0KcnVuUGFyYW1ldGVycyA8LSBsaXN0LmZpbGVzKHBhc3RlMCgiZGF0YS8iLCBydW5zKSwgcGF0dGVybj0gIltScl11blBhcmFtZXRlcnMueG1sIiwgZnVsbC5uYW1lcyA9IFRSVUUpDQoNCiMgQ3JlYXRlIHNhbXBsZXNoZWV0IGNvbnRhaW5pbmcgc2FtcGxlcyBhbmQgcnVuIHBhcmFtZXRlcnMgZm9yIGFsbCBydW5zDQpzYW1kZiA8LSBjcmVhdGVfc2FtcGxlc2hlZXQoU2FtcGxlU2hlZXQgPSBTYW1wbGVTaGVldCwgcnVuUGFyYW1ldGVycyA9IHJ1blBhcmFtZXRlcnMsIHRlbXBsYXRlID0gIlY0IikgJT4lDQogIGRpc3RpbmN0KCkNCg0KIyBDaGVjayB0aGF0IHNhbXBsZV9pZHMgY29udGFpbiBmY2lkLCBpZiBub3Q7IGF0dGF0Y2gNCnNhbWRmIDwtIHNhbWRmICU+JQ0KICBtdXRhdGUoc2FtcGxlX2lkID0gY2FzZV93aGVuKA0KICAgICFzdHJfZGV0ZWN0KHNhbXBsZV9pZCwgZmNpZCkgfiBwYXN0ZTAoZmNpZCwiXyIsc2FtcGxlX2lkKSwNCiAgICBUUlVFIH4gc2FtcGxlX2lkDQogICkpDQoNCiMgQ2hlY2sgdGhhdCBzYW1wbGVzIG1hdGNoIHNhbXBsZXNoZWV0DQpmYXN0cUZzIDwtIHB1cnJyOjptYXAobGlzdC5kaXJzKCJkYXRhIiwgcmVjdXJzaXZlPUZBTFNFKSwNCiAgICAgICAgICAgICAgICAgICAgICBsaXN0LmZpbGVzLCBwYXR0ZXJuPSJfUjFfIiwgZnVsbC5uYW1lcyA9IFRSVUUpICU+JQ0KICB1bmxpc3QoKSAlPiUNCiAgc3RyX3JlbW92ZShwYXR0ZXJuID0gIl4oLiopXFwvIikgJT4lDQogIHN0cl9yZW1vdmUocGF0dGVybiA9ICIoPzouKD8hX1MpKSskIikNCg0KIyBGaWx0ZXIgdW5kZXRlcm1pbmVkIHJlYWRzIGZyb20gc2FtcGxlIHNoZWV0DQpmYXN0cUZzIDwtIGZhc3RxRnNbIXN0cl9kZXRlY3QoZmFzdHFGcywgIlVuZGV0ZXJtaW5lZCIpXQ0KDQojIENoZWNrIGZvciBmYXN0cSBmaWxlcyB0aGF0IGFyZSBtaXNzaW5nIGZyb20gc2FtcGxlc2hlZXQNCmlmIChsZW5ndGgoc2V0ZGlmZihmYXN0cUZzLCBzYW1kZiRzYW1wbGVfaWQpKSA+IDApIHt3YXJuaW5nKCJUaGUgZmFzdHEgZmlsZS9zOiAiLCBzZXRkaWZmKGZhc3RxRnMsIHNhbWRmJHNhbXBsZV9pZCksICIgYXJlIG5vdCBpbiB0aGUgc2FtcGxlIHNoZWV0IikgfQ0KDQojIENoZWNrIGZvciBzYW1wbGVfaWRzIHRoYXQgZG9udCBoYXZlIGEgY29ycmVzcG9uZGluZyBmYXN0cSBmaWxlDQppZiAobGVuZ3RoKHNldGRpZmYoc2FtZGYkc2FtcGxlX2lkLCBmYXN0cUZzKSkgPiAwKSB7DQogIHdhcm5pbmcocGFzdGUwKCJUaGUgZmFzdHEgZmlsZTogIiwNCiAgICAgICAgICAgICAgICAgc2V0ZGlmZihzYW1kZiRzYW1wbGVfaWQsIGZhc3RxRnMpLA0KICAgICAgICAgICAgICAgICAiIGlzIG1pc3NpbmcsIGRyb3BwaW5nIGZyb20gc2FtcGxlc2hlZXQgXG4iKSkgDQogIHNhbWRmIDwtIHNhbWRmICU+JQ0KICAgIGZpbHRlcighc2FtcGxlX2lkICVpbiUgc2V0ZGlmZihzYW1kZiRzYW1wbGVfaWQsIGZhc3RxRnMpKQ0KfQ0KDQojIFdyaXRlIG91dCBzYW1wbGUgdHJhY2tpbmcgc2hlZXQNCndyaXRlX2NzdihzYW1kZiwgInNhbXBsZV9kYXRhL1NhbXBsZV9pbmZvLmNzdiIpDQpgYGANCg0KIyBBZGQgUENSIHByaW1lcnMgdG8gc2FtcGxlIHNoZWV0IHsudGFic2V0fQ0KDQpUaGlzIGNhbiBlaXRoZXIgYmUgZG9uZSBtYW51YWxseSBieSBlZGl0aW5nIHRoZSBzYW1wbGVfZGF0YS9TYW1wbGVfaW5mby5jc3YgZmlsZSwgb3IgaXQgY2FuIGJlIGRvbmUgaW4gUiBhcyBiZWxvdy4NCg0KSWYgYSBzaW5nbGUgcHJpbWVyIHNldCB3YXMgdXNlZCBhY3Jvc3MgYWxsIHNhbXBsZXMsIHRoZXNlIGNhbiBzaW1wbHkgYmUgYWRkZWQgdXNpbmcgYSBtdXRhdGUgY2FsbCAoKip0YWIgMSoqKS4NCg0KSWYgZGlmZmVyZW50IHByaW1lcnMgd2VyZSB1c2VkIGZvciBkaWZmZXJlbnQgc2FtcGxlcywgdGhlc2UgY2FuIGJlIHNldCB1c2luZyBwYXR0ZXJuIG1hdGNoaW5nIG9uIHRoZSBzYW1wbGUgbmFtZXMgd2l0aCBjYXNlX3doZW4gKCoqdGFiIDIqKikuDQoNCklmIG11bHRpcGxlIHByaW1lciBzZXRzIGFyZSB1c2VkIHBlciBzYW1wbGUsIGJlZm9yZSBpbmRleGluZywgdGhlIHBpcGVsaW5lIHdpbGwgY29uZHVjdCBhbiBleHRyYSByb3VuZCBvZiBkZW11bHRpcGxleGluZyB0byBzcGxpdCBlYWNoIHNhbXBsZSBieSBwcmltZXIuIFRoaXMgb3B0aW9uIGNhbiBiZSBzZXQgYnkgc3BsaXR0aW5nIGVhY2ggcHJpbWVyIHNldCB3aXRoIGEgc2VtaWNvbG9uICgqKnRhYiAzKiopIA0KDQojIyBNdWx0aXBsZSBwcmltZXIgc2V0cyBwZXIgc2FtcGxlDQoNCmBgYHtSfQ0KIyBBZGQgUENSIHByaW1lcnMgdG8gc2FtcGxlIHNoZWV0DQpzYW1kZiA8LSBzYW1kZiAlPiUNCiAgbXV0YXRlKA0KICAgIHBjcl9wcmltZXJzID0gIm1sQ09JaW50Ri1qZ0hDTzIxOTg7VW5pMThTLVVuaTE4U1IiLA0KICAgIGZvcl9wcmltZXJfc2VxID0gIkdHV0FDV0dHV1RHQUFDV0dUV1RBWUNDWUNDO0FHR0dDQUFLWUNUR0dUR0NDQUdDIiwNCiAgICByZXZfcHJpbWVyX3NlcSA9ICJUQUlBQ1lUQ0lHR1JUR0lDQ1JBQVJBQVlDQTtHUkNHR1RBVENUUkFUQ0dZQ1RUIg0KICAgICkNCg0Kd3JpdGVfY3N2KHNhbWRmLCAic2FtcGxlX2RhdGEvU2FtcGxlX2luZm8uY3N2IikNCmBgYA0KDQoNCiMgQ3JlYXRlIHBhcmFtZXRlcnMgZmlsZSB7LnRhYnNldH0NCg0KVGhlIHBhcmFtZXRlcnMgZmlsZSB0YWJsZSB0aGUgcmVzcGVjdGl2ZSB0YXJnZXQgZ2VuZSwgcmVmZXJlbmNlIGRhdGFiYXNlcywgYW5kIGZpbHRlcmluZyBwYXJhbWV0ZXJzIGZvciBlYWNoIHByaW1lciBzZXQgdXNlZCB0byBhbXBsaWZ5IHRoZSBzYW1wbGVzLiBBcyB0aGUgcGNyX3ByaW1lcnMgY29sdW1uIGlzIHVzZWQgaW4gdGhlIHBpcGVsaW5lIHRvIG1hdGNoIHRoZSBwYXJhbWV0ZXJzIHRvIHRoZSByZXNwZWN0aXZlIHNhbXBsZSwgaXQgaXMgY3JpdGljYWwgdGhhdCB0aGUgcHJpbWVyIG5hbWVzIG1hdGNoIHRob3NlIHNldCBpbiB0aGUgcHJldmlvdXMgc3RlcC4NCg0KSWYgYSBzaW5nbGUgcHJpbWVyIHNldCB3YXMgdXNlZCBhY3Jvc3MgYWxsIHNhbXBsZXMsIHRoZXNlIGNhbiBzaW1wbHkgYmUgYWRkZWQgdG8gdGhlIHRhYmxlIGFzIGJlbG93ICgqKnRhYiAxKiopLg0KDQpJZiBkaWZmZXJlbnQgcHJpbWVycyB3ZXJlIHVzZWQgZm9yIGRpZmZlcmVudCBzYW1wbGVzLCB0aGVzZSBjYW4gYmUgc2V0IGFzIGRpZmZlcmVudCByb3dzIGluIHRoZSB0YWJsZSB1c2luZyBjKCkgd2hlbiBjcmVhdGlnbiB0aGUgdGliYmxlICgqKnRhYiAyKiopLg0KDQpJZiBtdWx0aXBsZSBwcmltZXIgcmVmZXJlbmNlIGRhdGFiYXNlcyBhcmUgdG8gYmUgdXNlZCBmb3IgZWFjaCBzYW1wbGUsIHRoZXNlIGNhbiBiZSBzZXQgYnkgc3BsaXR0aW5nIGVhY2ggYSBzZW1pY29sb24uIFRoZSB0YXhvbm9taWMgYXNzaWdubWVudCB3aWxsIGJlIGNvbmR1Y3RlZCBzZXF1ZW50aWFsbHkgdGhyb3VnaCB0aGUgZGF0YWJhc2VzIGZyb20gbGVmdCB0byByaWdodCwgd2l0aCB0aGUgc2Vjb25kIHJlZmVyZW5jZSBkYXRhYmFzZSBvbmx5IGJlaW5nIHVzZWQgZm9yIHRob3NlIEFTVnMgdGhhdCBjb3VsZG50IGJlIGFzc2lnbmVkIHRvIHNwZWNpZXMgbGV2ZWwgdXNpbmcgdGhlIGZpcnN0IGRhdGFiYXNlcyAoKip0YWIgMyoqKSANCg0KKipQYXJhbWV0ZXIgb3B0aW9ucyoqDQoNCiogKipQcmltZXIgcGFyYW1ldGVyczoqKg0KICAgICsgKipwY3JfcHJpbWVycyoqIC0gTmFtZSBvZiBQQ1IgcHJpbWVycyAtIG11c3QgbWF0Y2ggc2FtZGYgZmlsZQ0KICAgICsgKip0YXJnZXRfZ2VuZSoqIC0gTmFtZSBvZiB0YXJnZXQgZ2VuZQ0KICAgICsgKiptYXhfcHJpbWVyX21pc21hdGNoKiogLSBIb3cgbXVjaCBtaXNtYXRjaCB0byBhbGxvdyB3aGVuIGRldGVjdGluZyBwcmltZXIgc2VxdWVuY2VzDQoNCiogKipSZWFkIGZpbHRlcmlnbjoqKg0KICAgICsgKipyZWFkX21pbl9sZW5ndGgqKiAtIE1pbmltdW0gbGVuZ3RoIG9mIHByaW1lciB0cmltbWVkIHJlYWRzDQogICAgKyAqKnJlYWRfbWF4X2xlbmd0aCoqIC0gTWF4aW11bSBsZW5ndGggb2YgcHJpbWVyIHRyaW1tZWQgcmVhZHMNCiAgICArICoqcmVhZF9tYXhfZWUqKiAtIE1heGltdW0gZXhwZWN0ZWQgZXJyb3JzIG9mIHByaW1lciB0cmltbWVkIHJlYWRzDQogICAgKyAqKnJlYWRfdHJ1bmNfbGVuZ3RoKiogLSBMZW5ndGggdG8gY3V0IGFsbCBsb25nZXIgcmVhZHMgdG8NCiAgICArICoqcmVhZF90cmltX2xlZnQqKiAtIFJlbW92ZSB0aGlzIG1hbnkgYnAgZnJvbSBsZWZ0IHNpZGUgb2YgcHJpbWVyIHRyaW1tZWQgcmVhZHMNCiAgICArICoqcmVhZF90cmltX3JpZ2h0KiogLSBSZW1vdmUgdGhpcyBtYW55IGJwIGZyb20gcmlnaHQgc2lkZSBvZiBwcmltZXIgdHJpbW1lZCByZWFkcw0KDQoqICoqQVNWIGZpbHRlcmluZyoqDQogICAgKyAqKmFzdl9taW5fbGVuZ3RoKiogLSBNaW5pbXVtIGxlbmd0aCBvZiBhbXBsaWNvbg0KICAgICsgKiphc3ZfbWF4X2xlbmd0aCoqIC0gTWF4aW11bSBsZW5ndGggb2YgYW1wbGljb24NCiAgICArICoqaGlnaF9zZW5zaXRpdml0eSoqIC0gT3B0aW9uIHRvIHR1cm4gb24gW3BzZXVkbyBwb29saW5nXShodHRwczovL2JlbmpqbmViLmdpdGh1Yi5pby9kYWRhMi9wc2V1ZG8uaHRtbCksIHNldHRpbmcgdGhpcyB0byBGQUxTRSBncmVhdGx5IHNwZWVkcyB1cCBBU1YgaW5mZXJlbmNlIGF0IHRoZSBleHBlbnNlIG9mIGRldGVjdGluZyBmZXdlciByYXJlICg8NSByZWFkcykgdGF4YS4NCiAgICArICoqY29uY2F0X3VubWVyZ2VkKiogLSBSZXRhaW4gYW55IHVubWVyZ2VkIHJlYWQgcGFpcnMgYnkgY29uY2F0ZW5hdGluZyB0aGVtIHRvZ2V0aGVyIHNlcGFyYXRlZCBieSBhIHN0cmluZyBvZiAxMCBOIGJhc2VzDQogICAgKyAqKmdlbmV0aWNfY29kZSoqIC0gR2VuZXRpYyBjb2RlIGZvciBhbXBsaWNvbiAtIHNlZSBCaW9zdHJpbmdzOjpHRU5FVElDX0NPREVfVEFCTEUNCiAgICArICoqY29kaW5nKiogLSBJcyB0aGUgYW1wbGljb24gZnJvbSBhIHByb3RlaW4gY29kaW5nIGdlbmUNCiAgICArICoqcGhtbSoqIC0gUGF0aCB0byBwcm9maWxlIGhpZGRlbiBtYXJrb3YgbW9kZWwgKE9wdGlvbmFsKQ0KDQoqICoqVGF4b25vbWljIGFzc2lnbm1lbnQ6KioNCiAgICArICoqaWR0YXhhX2RiKiogLSBQYXRoIHRvIHRyYWluZWQgSURUQVhBIG1vZGVsDQogICAgKyAqKnJlZl9mYXN0YSoqIC0gUGF0aCB0byBmYXN0YSBmaWxlIG9mIHJlZmVyZW5jZSBkYXRhYmFzZQ0KICAgICsgKippZHRheGFfY29uZmlkZW5jZSoqIC0gTWluaW11bSBib290c3RyYXAgY29uZmlkZW5jZSBmb3IgSURUQVhBDQogICAgKyAqKnJ1bl9ibGFzdCoqIC0gV2hldGhlciBhIGJsYXN0IHRvcCBoaXQgc2VhcmNoIHNob3VsZCBiZSBjb25kdWN0ZWQgaW4gYWRkaXRpb24gdG8gSURUQVhBDQogICAgKyAqKmJsYXN0X21pbl9pZGVudGl0eSoqIC0gTWluaW11bSBudWNsZW90aWRlIGlkZW50aXR5IGZvciBCTEFTVA0KICAgICsgKip0YXJnZXRfa2luZ2RvbSoqIC0gU3Vic2V0IHRvIHRhcmdldCBraW5nZG9tDQogICAgKyAqKnRhcmdldF9waHlsdW0qKiAtIFN1YnNldCB0byB0YXJnZXQgcGh5bHVtDQogICAgKyAqKnRhcmdldF9jbGFzcyoqIC0gU3Vic2V0IHRvIHRhcmdldCBjbGFzcw0KICAgICsgKip0YXJnZXRfb3JkZXIqKiAtIFN1YnNldCB0byB0YXJnZXQgb3JkZXINCiAgICArICoqdGFyZ2V0X2ZhbWlseSoqIC0gU3Vic2V0IHRvIHRhcmdldCBmYW1pbHkNCiAgICArICoqdGFyZ2V0X2dlbnVzKiogLSBTdWJzZXQgdG8gdGFyZ2V0IGdlbnVzDQogICAgKyAqKnRhcmdldF9zcGVjaWVzKiogLSBTdWJzZXQgdG8gdGFyZ2V0IHNwZWNpZXMNCg0KKiAqKlNhbXBsZSAmIFRheG9uIGZpbHRlcmluZzoqKg0KICAgICsgKiptaW5fc2FtcGxlX3JlYWRzKiogLSBNaW5pbXVtIHJlYWRzIHBlciBzYW1wbGUgYWZ0ZXIgZmlsdGVyaW5nDQogICAgKyAqKm1pbl90YXhhX3JlYWRzKiogLSBNaW5pbXVtIHJlYWRzIHBlciBBU1YgdG8gcmV0YWluDQogICAgKyAqKm1pbl90YXhhX3JhKiogLSBNaW5pbXVtIHJlbGF0aXZlIGFidW5kYW5jZSBwZXIgQVNWIHRvIHJldGFpbi4gMWUtNCBpcyAwLjAxJQ0KDQoqICoqR2VuZXJhbCBwaXBlbGluZSBwYXJhbWV0ZXJzKioNCiAgICArICoqdGhyZWFkcyoqIC0gTnVtYmVyIG9mIENQVSB0aHJlYWRzIHRvIHJ1biB0aGUgcGlwZWxpbmUgYWNyb3NzDQogICAgDQojIyBEaWZmZXJlbnQgb3IgbXVsdGlwbGUgcHJpbWVyIHNldHMgcGVyIHNhbXBsZQ0KDQpgYGB7Un0NCiMgUGFyYW1zIHRvIGFkZCBpbiBzdGVwX2FkZF9wYXJhbWV0ZXJzDQpwYXJhbXMgPC0gdGliYmxlKA0KICAjIEFtcGxpY29uIHBhcmFtZXRlcnMNCiAgcGNyX3ByaW1lcnMgPSBjKCJtbENPSWludEYtamdIQ08yMTk4IiwgIlVuaTE4Uy1VbmkxOFNSIiksDQogIHRhcmdldF9nZW5lPWMoIkNPSSIsICIxOFMiKSwNCiAgbWF4X3ByaW1lcl9taXNtYXRjaD0wLA0KDQogICMgUmVhZCBmaWx0ZXJpbmcNCiAgcmVhZF9taW5fbGVuZ3RoID0gMjAsDQogIHJlYWRfbWF4X2xlbmd0aCA9IEluZiwNCiAgcmVhZF9tYXhfZWUgPSAxLA0KICByZWFkX3RydW5jX2xlbmd0aCA9IDIyNCwNCiAgcmVhZF90cmltX2xlZnQgPSAwLA0KICByZWFkX3RyaW1fcmlnaHQgPSAwLA0KICANCiAgIyBBU1YgZmlsdGVyaW5nDQogIGFzdl9taW5fbGVuZ3RoID0gYygzMDMsIDUwKSwgI010Q09JaW50Ri1qZ0hDTzIxOTggPSAzMTNicA0KICBhc3ZfbWF4X2xlbmd0aCA9IGMoMzIzLCA1MDApLA0KICBoaWdoX3NlbnNpdGl2aXR5ID0gVFJVRSwNCiAgY29uY2F0X3VubWVyZ2VkID0gVFJVRSwNCiAgZ2VuZXRpY19jb2RlID0gYygiU0dDNCIsICJTR0MwIiksDQogIGNvZGluZyA9IGMoVFJVRSwgRkFMU0UpLA0KICBwaG1tID0gTkFfY2hhcmFjdGVyXywNCiAgDQogICMgVGF4b25vbWljIGFzc2lnbm1lbnQNCiAgaWR0YXhhX2RiID0gYygicmVmZXJlbmNlL0NPSV9pZHRheGEucmRzIiwicmVmZXJlbmNlLzE4U19pZHRheGEucmRzIiksDQogIHJlZl9mYXN0YSA9IGMoInJlZmVyZW5jZS9DT0lfaGllcmFyY2hpYWwuZmEuZ3oiLCAicmVmZXJlbmNlLzE4U19oaWVyYXJjaGlhbC5mYS5neiIpLA0KICBpZHRheGFfY29uZmlkZW5jZSA9IDYwLA0KICBydW5fYmxhc3Q9VFJVRSwNCiAgYmxhc3RfbWluX2lkZW50aXR5ID0gOTcsDQogIGJsYXN0X21pbl9jb3ZlcmFnZSA9IDkwLA0KICB0YXJnZXRfa2luZ2RvbSA9IE5BX2NoYXJhY3Rlcl8sDQogIHRhcmdldF9waHlsdW0gPSBOQV9jaGFyYWN0ZXJfLA0KICB0YXJnZXRfY2xhc3MgPSBOQV9jaGFyYWN0ZXJfLA0KICB0YXJnZXRfb3JkZXIgPSBOQV9jaGFyYWN0ZXJfLA0KICB0YXJnZXRfZmFtaWx5ID0gTkFfY2hhcmFjdGVyXywgDQogIHRhcmdldF9nZW51cyA9IE5BX2NoYXJhY3Rlcl8sICANCiAgdGFyZ2V0X3NwZWNpZXM9IE5BX2NoYXJhY3Rlcl8sICANCiAgDQogICMgU2FtcGxlICYgVGF4b24gZmlsdGVyaW5nDQogIG1pbl9zYW1wbGVfcmVhZHMgPSAwLA0KICBtaW5fdGF4YV9yZWFkcz0gMCwgIyBNaW5pbXVtIHJlYWRzIHBlciBBU1YgdG8gcmV0YWluDQogIG1pbl90YXhhX3JhID0gMCwgIyBNaW5pbXVtIHJlbGF0aXZlIGFidW5kYW5jZSBwZXIgQVNWIHRvIHJldGFpbi4gMWUtNCBpcyAwLjAxJQ0KICANCiAgIyBHZW5lcmFsIHBpcGVsaW5lIHBhcmFtZXRlcnMNCiAgdGhyZWFkcyA9IDENCikNCg0Kd3JpdGVfY3N2KHBhcmFtcywgInNhbXBsZV9kYXRhL2xvY2lfcGFyYW1zLmNzdiIpDQpgYGANCg0KIyBSdW4gcGlwZWxpbmUgey19DQpOb3cgdGhhdCB0aGUgc2FtcGxlIGRhdGEgc2hlZXQgYW5kIHBhcmFtZXRlcnMgYXJlIGRlZmluZWQsIHRoZSBwaXBlbGluZSBzdGVwcyBjYW4gbm93IGJlIHZpc3VhbGlzZWQsIGFuZCB0aGVuIHJ1biBhdXRvbWF0aWNhbGx5Lg0KDQoNCmBgYHtyfQ0KdGFyX21ha2UoKQ0KYGBgDQoNCiMgUmVzdWx0cw0KDQpTZWUgdGhlIFtnZW5lcmFsIGludHJvZHVjdGlvbl0oaHR0cHM6Ly9hbGV4cGlwZXIuZ2l0aHViLmlvL3BpcGVybGluZS92aWduZXR0ZXMvZ2VuZXJhbC5odG1sKSB2aWduZXR0ZSBmb3IgYW4gaW4tZGVwdGggZXhwbGFuYXRpb24gb2YgdGhlIHJlc3VsdHMgYW5kIHF1YWxpdHkgY29udHJvbCBvdXRwdXRz