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

Updating the pipeline

To update to the latest version of the pipeline, run the below code in the terminal.

git pull

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

Sequencing reads

For this workflow to run, we will need some sequencing runs to work with. If you are working with MiSeq data, it is recommended that the data is demultiplexed again using bcl2fastq (see Demultiplex MiSeq run tab below), as the miseq does not put indexes in fasta headers by default which is required for the index swtiching calculation.

If you do not yet have any data, some test sequencing reads have been hosted on Zenodo for testing purposes. The below code in the Download example reads tab below will download these and put them inside the data folder.

Demultiplex MiSeq run

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/210219_M03633_0489_000000000-JDYG3 #CHANGE TO YOUR SEQ RUN
outputdir=/group/pathogens/IAWS/Projects/Metabarcoding/dros_surveillance/data/JDYG3 #CHANGE TO YOUR DATA FOLDER RUN
samplesheet=/group/pathogens/IAWS/Projects/Metabarcoding/dros_surveillance/SampleSheet_JDYG3.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

Optional: Run R on BASC

You may wish to run this workflow through the command line on Agriculture Victorias BASC server in order to take advantage of more processing power. To do this, you can start a new SLURM interactive session. Press the CODE button to the lower right to display the code for this optional step.

# Create new interactive SLURM session
sinteractive --ntasks=1 --cpus-per-task=10 --mem-per-cpu=10GB --time=72:00:00

module load R/4.2.0-foss-2021b
module load pkgconfig/1.5.1-GCCcore-9.3.0-Python-3.8.2
module load GDAL/3.3.0-foss-2021a
module load BLAST+/2.11.0-gompi-2020a
module load Pandoc/2.5
module load ZeroMQ/4.3.2-GCCcore-9.3.0

# Load R
R

Download example reads

Example tephritid metabarcoding reads have been hosted on Zenodo, either download them manually or with R below:

# Source the functions file which contains code to download from zenodo
source("R/functions.R")

# Create directory for data
if(!dir.exists("data/K77JP")) {dir.create("data/K77JP", recursive = TRUE)}
if(!dir.exists("data/K77JP/InterOp")) {dir.create("data/K77JP/InterOp", recursive = TRUE)}

# Download files from zenodo
download_zenodo(
  doi = "10.5281/zenodo.7112162",
  path = "data/K77JP"
)

# Move the interop files to the interop folder
fs::dir_ls(path="data/K77JP", glob="*.bin") %>%
  purrr::map(function(x){
    fs::file_copy(path = x, new_path = x %>% str_replace("data/K77JP", "data/K77JP/InterOp"))
    file.remove(x)
  })

Install and load R packages and setup directories

This pipeline depends on a number of other R packages which this step will install. The versions of these packages are managed using renv to ensure they match the versions the pipeline was developed on. The first time installing packages may take some time, but they should be quick to load for any future runs.

# 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")

Reference databases

The pipeRline workflow uses the IDTAXA and BLAST software to assign taxonomy to the sequence reads. These require a pre-trained IDTAXA model, and a fasta file with heirarchial taxonomy. For insects, these

Download reference database

Reference databases for insects and arachnids have been hosted on Zenodo, either download them manually, or with R below:

# Source the functions file which contains code to download from zenodo
source("R/functions.R")

# Download files from zenodo
download_zenodo(
  doi = "10.5281/zenodo.7655352",
  path = "reference"
)

Create your own reference database

If you need a new database, these can be created from genbank and blast using taxreturn or other simialr database curation packages.

>Accession|Root;Kingdom;Phylum;Class;Order;Family;Genus;Species
ACCTAGAAAGTCGTAGATCGAAGTTGAAGCATCGCCCGATGATCGTCTGAAGCTGTAGCATGAGTCGATTTTCACATTCAGGGATACCATAGGATAC
>Root;Kingdom;Phylum;Class;Order;Family;Genus;Species
CGCTAGAAAGTCGTAGAAGGCTCGGAGGTTTGAAGCATCGCCCGATGGGATCTCGTTGCTGTAGCATGAGTACGGACATTCAGGGATCATAGGATAC

The IDTAXA model can then be trained on this reference fasta - See the IDTAXA manual

Create sample tracking sheet

In order to track samples and relevant QC statistics throughout the metabarcoding pipeline, we will first create a new sample tracking sheet from our input illumina 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)

Single primer set

# Add primers to sample sheet
samdf <- samdf %>%
  mutate(pcr_primers = "fwhF2-fwhR2n",
  for_primer_seq = "GGDACWGGWTGAACWGTWTAYCCHCC",
  rev_primer_seq = "GTRATWGCHCCDGCTARWACWGG"
  )

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

Different primer sets per sample

# Add PCR primers to sample sheet
samdf <- samdf %>%
  mutate(pcr_primers = case_when(
    str_detect(sample_name, "primer1") ~ "fwhF2-fwhR2n",
    str_detect(sample_name, "primer2") ~ "EIF3LminiF4-EIF3lminiR4"
  ),
  for_primer_seq = case_when(
    str_detect(sample_name, "primer1") ~ "GGDACWGGWTGAACWGTWTAYCCHCC",
    str_detect(sample_name, "primer2") ~ "GATGCGYCGTTATGCYGATGC"
  ),
  rev_primer_seq = case_when(
    str_detect(sample_name, "primer1") ~ "GTRATWGCHCCDGCTARWACWGG",
    str_detect(sample_name, "primer2") ~ "TTRAAYACTTCYARATCRCC"
  ))

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

Multiple primer sets per sample

# Add PCR primers to sample sheet
samdf <- samdf %>%
  mutate(
    pcr_primers = "fwhF2-fwhR2nDac;EIF3LminiF4-EIF3lminiR4",
    for_primer_seq = "GGDACWGGWTGAACWGTWTAYCCHCC;GATGCGYCGTTATGCYGATGC",
    rev_primer_seq = "GTRATWGCHCCIGCTAADACHGG;TTRAAYACTTCYARATCRCC"
    )

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 filtering:
    • 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
    • blast_min_coverage - Minimum query coverage 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

Single primer set

# Params to add in step_add_parameters
params <- tibble(
  # Primer parameters
  pcr_primers = "fwhF2-fwhR2n",
  target_gene="COI",
  max_primer_mismatch=0,

  # Read filtering
  read_min_length = 20,
  read_max_length = Inf,
  read_max_ee = 1,
  read_trunc_length = 150,
  read_trim_left = 0, 
  read_trim_right = 0,
  
  # ASV filtering
  asv_min_length = 195, 
  asv_max_length = 215,
  high_sensitivity = TRUE,
  concat_unmerged = FALSE,
  genetic_code = "SGC4",
  coding = TRUE,
  phmm = "reference/folmer_fullength_model.rds",
  
  # Taxonomic assignment
  idtaxa_db = "reference/idtaxa_bftrimmed.rds",
  ref_fasta = "reference/insecta_hierarchial_bftrimmed.fa.gz",
  idtaxa_confidence = 60,
  run_blast=TRUE,
  blast_min_identity = 97,
  blast_min_coverage = 90,
  target_kingdom = "Metazoa",
  target_phylum = "Arthropoda",
  target_class = NA,
  target_order = NA,
  target_family = NA,
  target_genus = NA,
  target_species= NA,
  
  # Sample & Taxon filtering
  min_sample_reads = 1000,
  min_taxa_reads= NA,
  min_taxa_ra = 1e-4, #1e-4 is 0.01%
    
  # General pipeline parameters
  threads = 1
)

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

Different or multiple primer sets per sample

# Params to add in step_add_parameters
params <- tibble(
  # Primer parameters
  pcr_primers = c("fwhF2-fwhR2nDac", "EIF3LminiF4-EIF3lminiR4"),
  target_gene=c("COI", "EIF3L"),
  max_primer_mismatch=1,

  # Read filtering
  read_min_length = 20,
  read_max_length = Inf,
  read_max_ee = 1,
  read_trunc_length = 150,
  read_trim_left = 0,
  read_trim_right = 0,
  
  # ASV filtering
  asv_min_length = c(195, 207),
  asv_max_length = c(215, 227),
  high_sensitivity = TRUE,
  concat_unmerged = FALSE,
  genetic_code = c("SGC4", "SGC0"),
  coding = c(TRUE, TRUE),
  phmm = c("reference/phmm/Bactrocera_COI.rds", "reference/phmm/Bactrocera_EIF3L.rds"),
  
  # Taxonomic assignment
  idtaxa_db = c("reference/COI_idtaxa.rds","reference/EIF3L_idtaxa.rds"),
  ref_fasta = c("reference/COI_hierarchial.fa.gz", "reference/EIF3L_hierarchial.fa.gz"),
  idtaxa_confidence = 60,
  run_blast=TRUE,
  blast_min_identity = 97,
  blast_min_coverage = 90,
  target_kingdom = c("Metazoa", "Metazoa"),
  target_phylum = c("Arthropoda","Arthropoda"),
  target_class = NA,
  target_order = NA,
  target_family = NA, 
  target_genus = NA,  
  target_species= NA,  
  
  # Sample & Taxon filtering
  min_sample_reads = c(1000, 1000),
  min_taxa_reads= NA, 
  min_taxa_ra = c(1e-4, 1e-4),
)

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

Multiple reference databases

params <- tibble(
  # Primer parameters
  pcr_primers = c("fwhF2-fwhR2nDac", "EIF3LminiF4-EIF3lminiR4"),
  target_gene=c("COI", "EIF3L"),
  max_primer_mismatch=0,

  # Read filtering
  read_min_length = 20,
  read_max_length = Inf,
  read_max_ee = 1,
  read_trunc_length = 150,
  read_trim_left = 0,
  read_trim_right = 0,
  
  # ASV filtering
  asv_min_length = c(195, 207),
  asv_max_length = c(215, 227),
  high_sensitivity = TRUE,
  concat_unmerged = FALSE,
  genetic_code = c("SGC4", "SGC0"),
  coding = c(TRUE, TRUE),
  phmm = c("reference/phmm/Bactrocera_COI.rds", "reference/phmm/Bactrocera_EIF3L.rds"),
  
  # Taxonomic assignment
  idtaxa_db = c("reference/COI_internal_idtaxa.rds;reference/COI_idtaxa.rds",
             "reference/EIF3L_internal_idtaxa.rds;reference/EIF3L_idtaxa.rds"),
  ref_fasta = c("reference/COI_internal.fa.gz;reference/COI_hierarchial.fa.gz",
               "reference/EIF3L_internal.fa.gz;reference/EIF3L_hierarchial.fa.gz"),
  idtaxa_confidence = 60,
  run_blast=TRUE,
  blast_min_identity = 97,
  blast_min_coverage = 90,
  target_kingdom = c("Metazoa", "Metazoa"),
  target_phylum = c("Arthropoda","Arthropoda"),
  target_class = NA,
  target_order = NA,
  target_family = NA, 
  target_genus = NA,  
  target_species= NA,  
  
  # Sample & Taxon filtering
  min_sample_reads = c(1000, 1000),
  min_taxa_reads= NA,
  min_taxa_ra = c(1e-4, 1e-4),
)

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 run automatically using the tar_make() command

tar_make()

Results

After the run, two directories should have been made within the output folder, output/results/unfiltered which contains the results before any taxonomic subsetting, sample minimum abundance, and ASV minimum abundance filtering, and output/results/filtered containing the results after these steps. Within each of these folders there should be a series of outputs:

  • summary.csv - This is the main summary file which lists the abundance of each ASV, the taxonomy assigned to it, and the read counts for each sample it was detected in.

  • ps.rds - This phyloseq object contains the same information as the summary file, but in a format that can be analysed further using the phyloseq R package, a useful tool for plotting and further analysis of metabarcoding and microbiome datasets.

  • asvs.fasta - This contains the amplification sequence variants inferred from the data set

  • seqtab.csv - This lists the abundance of each ASV and the sample it was detected in. This file is generally for development purposes only, and all information contained here is present in the summmary csv.

  • taxtab.csv - This lists the heirarchial taxonomy assigned to each ASV. This file is generally for development purposes only, and all information contained here is present in the summmary csv.

  • samdf.csv - This is the sample tracking sheet that lists the sequencing details for each sample. This file is generally for development purposes only, and all information contained here is present in the summmary csv.

  • raw.csv - This is a large file containing all the above results in a single csv in a ‘long’ format appropriate for further statistical analysis.

Quality control

The pipeline also outputs some quality control plots that should be checked to ensure the pipeline has run correctly and the outputs are as desired

  • Per-flowcell quality checks
    • output/logs/FCID/FCID_flowcell_qc.pdf - This set of plots summarises the raw outputs from the sequencing run. The first page shows the average imaging intensity for the 90% percentile of the data for each tile on the sequencing flow cell. The second page shows the number of clusters (reads) imaged by the seqeuncer, and the number of clusters passing the machines filtering. The third page shows the Qscore by cycle for all reads.

    • output/logs/FCID/FCID_index_switching.pdf - This is a heatmap of the amount of index switching per index set and flowcell used. On the diagonal of the plot is the indexes applied to the samples, while the other squares on the grid display instances where either the i5 or i7 index has switched causing this read to end up in the undetermined reads file. The text above the plot lists the total reads demultiplex from that flowcell, the switch rate (only one of the indexes switching causing the read to end up in the undetermined reads file) as a percentage, the cross-contamination rate (both indexes switching the read ending up in another sample) as a percentage, and the number of “other reads” which were those where no applied indexes were detected. The cross-contamination rate is calculated as the square of the index switching rate as per (costello et al), and should be a rough guide to determine an appropriate ASV minimum abundance threshold for filtering. NOTE: This plot is only created when unique dual indexes were used on the sample.

    • output/logs/FCID/FCID_prefilt_qualplots.pdf - This multiplot summarises the read quality scores for the forward and reverse reads, pre filtering. These plots can serve as an indicator for adjusting read filtering parameters of the pipeline. The top two plots summarise the mean quality score by position for the forward and reverse reads respectively. For illumina data, these will start to decrease towards the end of the reads, particularly for the reverse reads. The two bottom plots show the cumulative expected errors along the reads, with different coloured dots for different quantiles of the read data (i.e. lower 10% to upper 90%). The red lines show the potential max expecter error cutoffs, with all reads above the set maximum expected error filter beign removed (param read_max_ee). For example, if the lower 10% quantile of reads goes above the red line for maxEE=1, you would expect 10% of the reads to be removed if read_max_ee was set to 1. As more errors commonly occur in the ends of the read, if there is sufficient overlap between the reads to cover the length of the amplicon, the reads could instead be truncated to smaller lengths to reduce the amount of reads that cross this minimum expected error filter which would retain more data. Note that when truncating reads you should aim to have at least 20bp of overlap to facilitate forward and reverse read merging.

    • output/logs/FCID/FCID_postfilt_qualplots.pdf - This multiplot summarises the read quality scores for the forward and reverse reads, pre filtering. These plots list the same information as the pre-filtering quality plots, and should be checked to ensure that the filtering has been correctly applied. i.e., if reads were truncated or trimmed on the left or right (params read_trunc_length, read_trim_left, read_trim_right) they should be shorter then the pre-filter plots, and if a maximum expected error filter (param read_max_ee) was applied, none of the EE quantiles should be above the corresponding red line

    • output/logs/FCID/FCID_pcrprimers_errormodel.pdf - There is a separate PDF for the forward and reverse error models for each primer set and flow cell. Each plot summarises the error model used for dada2 that was inferred from the data for the respective flow cell. The error rates for each possible transition (A→C, A→G, etc) are shown in each subplot. The dot-points are the error rates observed in the data for each quality score. The black line shows the estimated error rates from the machine-learning algorithm. The red line shows the error rates that would be expected if the Q-scores assigned by the sequencer were completely accurate. This plot can be more subjective to interpret, but generally you want to see the estimated error rates (black line) decrease as the quality score (x axis) increases, in a relatively linear fashion. Minor humps in the black line are no problem, but a very jagged line may indicate that the error model did not fit correctly. Note: for NextSeq and NovaSeq data, the binned quality scores provided by the sequencer can cause large humps or dips in the error model fit. This is generally not a big problem, see this github issue for a deeper discussion on fitting error models for binned quality scores.

  • Whole dataset quality checks:
    • output/logs/ASV_cleanup_summary.pdf - This plot lists the abundance, and number of unique sequence variance inferred from dada2, their lengths, and whether they were retained or filtered out during the ASV filtering step. Generally you should see a lot of unique sequences filtered out in this step, but the majority of the abundance should remain.

    • output/logs/ASV_cleanup_summary.csv - This table lists the individual sequence variants, their abudnance, length and whether they were retained or filtered out during the ASV filtering step. This table is useful for deeper investigation to ensure that real sequences were not removed in any of the ASV filtering steps.

    • output/logs/taxonomic_assignment_summary.pdf - This plot summarises the genetic distance of the ASVs to the reference database (from BLAST top hit identity), and what taxonomy was assigned to each. This plot gives a good overview of how well the analysed sequences are represented in the reference database, and how successful the taxonomic assignment was.

    • output/logs/taxonomic_assignment_summary.csv - This table lists the individual sequence variants and their assigned taxonomy and confidence scores with IDTAXA. The columns to the right also indicate the BLAST top hit and their distance to the closest blast hit. This table is useful for deeper investigation of how different sequences were assigned.

    • output/logs/read_tracker.pdf This plot summarises the number of reads retained through all steps of the pipeline, as well as how many reads were classified to different taxonomic ranks. This plot provides a useful overview of all pipeline steps to determine if too many reads are being lost at a certain step

    • output/logs/read_tracker.csv - Similar to the above plot, this table summarises the number of reads retained through all steps of the pipeline, as well as how many reads were classified to different taxonomic ranks.

    • output/logs/accumulation_curve.pdf - This plot shows the accumulation of ASVs within each sample as sequencing depth increases. The curves should start to plateau if adequate sequencing depth has been achieved to characterise the community. If the curves have not reached a plateau it may indicate that these samples should be sequenced again so that all taxa are captured in the data.

LS0tDQp0aXRsZTogIlBpcGVSbGluZSINCnN1YnRpdGxlOiAiR2VuZXJhbCBleGFtcGxlIg0KYXV0aG9yOiAiQS5NLiBQaXBlciINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgaGlnaGxpZ2h0ZXI6IG51bGwNCiAgICB0aGVtZTogImZsYXRseSINCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiANCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUNCiAgICBkZl9wcmludDogcGFnZWQgICAgDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBLbml0ciBnbG9iYWwgc2V0dXAgLSBjaGFuZ2UgZXZhbCB0byB0cnVlIHRvIHJ1biBjb2RlDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeSh0YXJnZXRzKQ0KbGlicmFyeSh0YXJjaGV0eXBlcykNCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVycm9yPUZBTFNFLCBmaWcuc2hvdyA9ICJob2xkIiwgZmlnLmtlZXAgPSAiYWxsIikNCm9wdHNfY2h1bmskc2V0KGRldiA9ICdwbmcnKQ0KYGBgDQoNCiMgSW50cm9kdWN0aW9uDQoNClRoaXMgbWV0YWJhcmNvZGluZyBwaXBlbGluZSBpcyBiYXNlZCBhcm91bmQgdGhlIFt0YXJnZXRzXShodHRwczovL2Jvb2tzLnJvcGVuc2NpLm9yZy90YXJnZXRzLykgcGFja2FnZSwgd2hpY2ggaXMgYSBNYWtlLWxpa2UgcGlwZWxpbmUgdG9vbCBmb3IgUi4gVGhlIGJlbmVmaXQgb2YgdGhpcyBpcyB0aGF0IGFsbCB0aGUgY29kZSBpcyBhdXRvbWF0aWNhbGx5IHJ1biwgYW5kIHRoZSBwaXBlbGluZSBza2lwcyBjb3N0bHkgcnVudGltZSBmb3IgdGFza3MgdGhhdCBhcmUgYWxyZWFkeSB1cCB0byBkYXRlLg0KDQpUaGlzIHBhZ2UgbGlzdHMgdGhlIGdlbmVyYWwgd29ya2Zsb3cgYW5kIGFsbCB0aGUgb3B0aW9ucyB0aGF0IGNhbiBiZSBhZGFwdGVkIGZvciB5b3VyIGRhdGFzZXQuDQoNCiMgQ2xvbmUgdGhlIHBpcGVSbGluZSBnaXRodWIgcmVwb3NpdG9yeQ0KDQpUaGUgZmlyc3Qgc3RlcCBpcyB0byBjbG9uZSB0aGlzIGdpdGh1YiByZXBvc2l0b3J5LCB3aGljaCBjb250YWlucyB0aGUgcmVxdWlyZWQgY29kZSBhbmQgZGlyZWN0b3J5IHN0cnVjdHVyZSB0byBydW4gdGhlIHBpcGVsaW5lLiBUbyBkbyB0aGlzLCB5b3Ugd2lsbCBuZWVkIFtHaXRdKGh0dHBzOi8vZ2l0LXNjbS5jb20vKSBpbnN0YWxsZWQgb24geW91ciBjb21wdXRlci4gSWYgeW91IGFyZSBydW5uaW5nIHRoZSBwaXBlbGluZSBpbiBSc3R1ZGlvLCBpdCBpcyBiZXN0IHRvIGNyZWF0ZSBhIG5ldyBwcm9qZWN0IGZyb20gdGhlIGdpdGh1YiByZXBvc2l0b3J5LiBUaGlzIGNhbiBiZSBkb25lIGJ5IGdvaW5nICoqZmlsZSA+IG5ldyBwcm9qZWN0ID4gdmVyc2lvbiBjb250cm9sID4gZ2l0KiogdGhlbiBhZGRpbmcgaHR0cHM6Ly9naXRodWIuY29tL2FsZXhwaXBlci9waXBlcmxpbmUuZ2l0IHRoZW4gY2hhbmdlIHRoZSBuYW1lIG9mIHRoZSBwcm9qZWN0IHRvIHdoYXRldmVyIHlvdSBhcmUgd29ya2luZyB3aXRoLiANCg0KQWx0ZXJuYXRpdmVseSwgdGhlIHJlcG9zaXRvcnkgY2FuIGJlIGNsb25lZCB1c2luZyB0aGUgY29tbWFuZCBsaW5lLCBjaGFuZ2UgdGhlICdmb2xkZXItbmFtZScgdG8gdGhlIGRlc2lyZWQgbmFtZQ0KYGBge2Jhc2h9DQojIENoYW5nZSBpbnRvIHRoZSBtYWluIGRpcmVjdG9yeSB5b3Ugd2lzaCB0byBtYWtlIHRoZSBwcm9qZWN0IGluDQpjZCBtZXRhYmFyY29kaW5nDQoNCiMgQ2xvbmUgdGhlIHJlcG9zaXRvcnkNCmdpdCBjbG9uZSBodHRwczovL2dpdGh1Yi5jb20vYWxleHBpcGVyL3BpcGVybGluZS5naXQgZm9sZGVyLW5hbWUNCmBgYA0KDQojIyBVcGRhdGluZyB0aGUgcGlwZWxpbmUNCg0KVG8gdXBkYXRlIHRvIHRoZSBsYXRlc3QgdmVyc2lvbiBvZiB0aGUgcGlwZWxpbmUsIHJ1biB0aGUgYmVsb3cgY29kZSBpbiB0aGUgdGVybWluYWwuDQoNCmBgYHtiYXNofQ0KZ2l0IHB1bGwNCmBgYA0KDQojIFByaW9yIHRvIGFuYWx5c2lzDQpUaGUgUGlwZVJsaW5lIHdvcmtmbG93IGFzc3VtZXMgdGhhdCB5b3VyIHNlcXVlbmNpbmcgZGF0YSBtZWV0cyBjZXJ0YWluIGNyaXRlcmlhOg0KDQoxLiBTYW1wbGVzIGhhdmUgYmVlbiBkZW11bHRpcGxleGVkLCBpLmUuIHNwbGl0IGludG8gaW5kaXZpZHVhbCBwZXItc2FtcGxlIGZhc3RxIGZpbGVzLiBJZiB5b3Ugd2FudCB0aGUgcGlwZWxpbmUgdG8gY2FsY3VsYXRlIHRoZSBpbmRleC1zd2l0Y2hpbmcgcmF0ZSwgdGhlIGZhc3RxIGZpbGVzIG5lZWQgdG8gYmUgcmUtZGVtdWx0aXBsZXhlZCBhcyB0aGUgbWlzZXEgZG9lcyBub3QgcHV0IGluZGV4ZXMgaW4gZmFzdGEgaGVhZGVycyBieSBkZWZhdWx0DQoyLiBGb3IgcGFpcmVkLWVuZCBzZXF1ZW5jaW5nIGRhdGEsIHRoZSBmb3J3YXJkIGFuZCByZXZlcnNlIHJlYWRzIGFyZSBpbiBzZXBhcmF0ZSBmaWxlcyAoaWUuIG5vdCBpbnRlcmxlYXZlZCkgd2l0aCByZWFkcyBhcnJhbmdlZCBpbiBtYXRjaGVkIG9yZGVyLg0KDQpUaGUgb3V0cHV0IGRpcmVjdG9yeSBzaG91bGQgYmUgdW5pcXVlIGZvciBlYWNoIHNlcXVlbmNpbmcgcnVuLCBuYW1lZCBhcyB0aGUgZmxvd2NlbGwgaWQsIHdpdGhpbiBhIGRpcmVjdG9yeSBjYWxsZWQgZGF0YQ0KDQpGb3IgZXhhbXBsZToNCg0KICAgIHJvb3QvDQogICAgICDilJzilIDilIAgZGF0YS8NCiAgICAgICAgIOKUnOKUgOKUgCBDSkw3RC8NCiAgICAgICAgIA0KWW91IHdpbGwgYWxzbyBuZWVkIEJMQVNUKyBpbnN0YWxsZWQgb24geW91ciBjb21wdXRlciwgaXQgY2FuIGJlIGRvd25sb2FkZWQgZnJvbSB0aGUgW05DQkkgd2Vic2l0ZV0oaHR0cHM6Ly9ibGFzdC5uY2JpLm5sbS5uaWguZ292L0JsYXN0LmNnaT9QQUdFX1RZUEU9Qmxhc3REb2NzJkRPQ19UWVBFPURvd25sb2FkKSANCg0KIyBTZXF1ZW5jaW5nIHJlYWRzIHsudGFic2V0fQ0KDQpGb3IgdGhpcyB3b3JrZmxvdyB0byBydW4sIHdlIHdpbGwgbmVlZCBzb21lIHNlcXVlbmNpbmcgcnVucyB0byB3b3JrIHdpdGguIElmIHlvdSBhcmUgd29ya2luZyB3aXRoIE1pU2VxIGRhdGEsIGl0IGlzIHJlY29tbWVuZGVkIHRoYXQgdGhlIGRhdGEgaXMgZGVtdWx0aXBsZXhlZCBhZ2FpbiB1c2luZyBiY2wyZmFzdHEgKHNlZSAqKkRlbXVsdGlwbGV4IE1pU2VxIHJ1bioqIHRhYiBiZWxvdyksIGFzIHRoZSBtaXNlcSBkb2VzIG5vdCBwdXQgaW5kZXhlcyBpbiBmYXN0YSBoZWFkZXJzIGJ5IGRlZmF1bHQgd2hpY2ggaXMgcmVxdWlyZWQgZm9yIHRoZSBpbmRleCBzd3RpY2hpbmcgY2FsY3VsYXRpb24uDQoNCklmIHlvdSBkbyBub3QgeWV0IGhhdmUgYW55IGRhdGEsIHNvbWUgdGVzdCBzZXF1ZW5jaW5nIHJlYWRzIGhhdmUgYmVlbiBob3N0ZWQgb24gWmVub2RvIGZvciB0ZXN0aW5nIHB1cnBvc2VzLiBUaGUgYmVsb3cgY29kZSBpbiB0aGUgKipEb3dubG9hZCBleGFtcGxlIHJlYWRzKiogdGFiIGJlbG93IHdpbGwgZG93bmxvYWQgdGhlc2UgYW5kIHB1dCB0aGVtIGluc2lkZSB0aGUgZGF0YSBmb2xkZXIuDQoNCiMjIERlbXVsdGlwbGV4IE1pU2VxIHJ1bg0KVGhlIGJlbG93IGNvZGUgaXMgd3JpdHRlbiBmb3IgdGhlIEFncmljdWx0dXJlIFZpY3RvcmlhIEJBU0Mgc2VydmVyLCBhbmQgdGhlIGxvY2F0aW9ucyB3aWxsIGJlIGRpZmZlcmVudCBpZiB5b3UgYXJlIHVzaW5nIGEgZGlmZmVyZW50IEhQQyBjbHVzdGVyLg0KDQpgYGB7YmFzaCBkZW11bHRpcGxleCAxIG1pc21hdGNofQ0KI2xvYWQgbW9kdWxlDQptb2R1bGUgbG9hZCBiY2wyZmFzdHEyLzIuMjAuMC1mb3NzLTIwMThiDQoNCiNyYWlzZSBhbW91bnQgb2YgYXZhaWxhYmxlIGZpbGUgaGFuZGxlcw0KdWxpbWl0IC1uIDQwMDANCg0KIyMjUnVuMQ0KDQojU2V0IHVwIGlucHV0IGFuZCBvdXRwdXRzDQppbnB1dGRpcj0vZ3JvdXAvc2VxdWVuY2luZy8yMTAyMTlfTTAzNjMzXzA0ODlfMDAwMDAwMDAwLUpEWUczICNDSEFOR0UgVE8gWU9VUiBTRVEgUlVODQpvdXRwdXRkaXI9L2dyb3VwL3BhdGhvZ2Vucy9JQVdTL1Byb2plY3RzL01ldGFiYXJjb2RpbmcvZHJvc19zdXJ2ZWlsbGFuY2UvZGF0YS9KRFlHMyAjQ0hBTkdFIFRPIFlPVVIgREFUQSBGT0xERVIgUlVODQpzYW1wbGVzaGVldD0vZ3JvdXAvcGF0aG9nZW5zL0lBV1MvUHJvamVjdHMvTWV0YWJhcmNvZGluZy9kcm9zX3N1cnZlaWxsYW5jZS9TYW1wbGVTaGVldF9KRFlHMy5jc3YgI0NIQU5HRSBUTyBZT1VSIFNBTVBMRVNIRUVUDQoNCiMgY29udmVydCBzYW1wbGVzaGVldCB0byB1bml4IGZvcm1hdA0KZG9zMnVuaXggJHNhbXBsZXNoZWV0DQoNCiNEZW11bHRpcGxleA0KYmNsMmZhc3RxIC1wIDEyIC0tcnVuZm9sZGVyLWRpciAkaW5wdXRkaXIgXA0KLS1vdXRwdXQtZGlyICRvdXRwdXRkaXIgXA0KLS1zYW1wbGUtc2hlZXQgJHNhbXBsZXNoZWV0IFwNCi0tbm8tbGFuZS1zcGxpdHRpbmcgLS1iYXJjb2RlLW1pc21hdGNoZXMgMQ0KDQojIENvcHkgb3RoZXIgbmVjZXNzYXJ5IGZpbGVzIGFuZCBtb3ZlIGZhc3Rxcw0KY2QgJG91dHB1dGRpcg0KY3AgLXIgJGlucHV0ZGlyL0ludGVyT3AgJG91dHB1dGRpcg0KY3AgJGlucHV0ZGlyL1J1bkluZm8ueG1sICRvdXRwdXRkaXINCmNwICRpbnB1dGRpci9bUnJddW5QYXJhbWV0ZXJzLnhtbCAkb3V0cHV0ZGlyDQpjcCAkc2FtcGxlc2hlZXQgJG91dHB1dGRpcg0KbXYgKiovKi5mYXN0cS5neiAkb3V0cHV0ZGlyDQoNCiMgQXBwZW5kIGZjaWQgdG8gc3RhcnQgb2Ygc2FtcGxlIG5hbWVzIGlmIG1pc3NpbmcNCmZjaWQ9JChlY2hvICRpbnB1dGRpciB8IHNlZCAncy9eLiotLy8nKQ0KZm9yIGkgaW4gKi5mYXN0cS5nejsgZG8NCiAgaWYgISBbWyAkaSA9PSAkZmNpZCogXV07IHRoZW4NCiAgbmV3PSQoZWNobyAke2ZjaWR9ICR7aX0pICNhcHBlbmQgdG9nZXRoZXINCiAgbmV3PSQoZWNobyAke25ldy8vIC9ffSkgI3JlbW92ZSBhbnkgd2hpdGUgc3BhY2UNCiAgbXYgLXYgIiRpIiAiJG5ldyINCiAgZmkNCmRvbmUNCg0KYGBgDQoNCg0KIyBPcHRpb25hbDogUnVuIFIgb24gQkFTQw0KDQpZb3UgbWF5IHdpc2ggdG8gcnVuIHRoaXMgd29ya2Zsb3cgdGhyb3VnaCB0aGUgY29tbWFuZCBsaW5lIG9uIEFncmljdWx0dXJlIFZpY3RvcmlhcyBCQVNDIHNlcnZlciBpbiBvcmRlciB0byB0YWtlIGFkdmFudGFnZSBvZiBtb3JlIHByb2Nlc3NpbmcgcG93ZXIuIFRvIGRvIHRoaXMsIHlvdSBjYW4gc3RhcnQgYSBuZXcgU0xVUk0gaW50ZXJhY3RpdmUgc2Vzc2lvbi4gUHJlc3MgdGhlIENPREUgYnV0dG9uIHRvIHRoZSBsb3dlciByaWdodCB0byBkaXNwbGF5IHRoZSBjb2RlIGZvciB0aGlzIG9wdGlvbmFsIHN0ZXAuDQoNCmBgYHtiYXNoLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1oaWRlJ30NCiMgQ3JlYXRlIG5ldyBpbnRlcmFjdGl2ZSBTTFVSTSBzZXNzaW9uDQpzaW50ZXJhY3RpdmUgLS1udGFza3M9MSAtLWNwdXMtcGVyLXRhc2s9MTAgLS1tZW0tcGVyLWNwdT0xMEdCIC0tdGltZT03MjowMDowMA0KDQptb2R1bGUgbG9hZCBSLzQuMi4wLWZvc3MtMjAyMWINCm1vZHVsZSBsb2FkIHBrZ2NvbmZpZy8xLjUuMS1HQ0Njb3JlLTkuMy4wLVB5dGhvbi0zLjguMg0KbW9kdWxlIGxvYWQgR0RBTC8zLjMuMC1mb3NzLTIwMjFhDQptb2R1bGUgbG9hZCBCTEFTVCsvMi4xMS4wLWdvbXBpLTIwMjBhDQptb2R1bGUgbG9hZCBQYW5kb2MvMi41DQptb2R1bGUgbG9hZCBaZXJvTVEvNC4zLjItR0NDY29yZS05LjMuMA0KDQojIExvYWQgUg0KUg0KYGBgDQoNCg0KDQojIyBEb3dubG9hZCBleGFtcGxlIHJlYWRzDQoNCkV4YW1wbGUgdGVwaHJpdGlkIG1ldGFiYXJjb2RpbmcgcmVhZHMgaGF2ZSBiZWVuIGhvc3RlZCBvbiBbWmVub2RvXShodHRwczovL3plbm9kby5vcmcvcmVjb3JkLzcxMTIxNjIjLllfTG9CWFpCei1nKSwgZWl0aGVyIGRvd25sb2FkIHRoZW0gbWFudWFsbHkgb3Igd2l0aCBSIGJlbG93OiANCg0KYGBge3J9DQojIFNvdXJjZSB0aGUgZnVuY3Rpb25zIGZpbGUgd2hpY2ggY29udGFpbnMgY29kZSB0byBkb3dubG9hZCBmcm9tIHplbm9kbw0Kc291cmNlKCJSL2Z1bmN0aW9ucy5SIikNCg0KIyBDcmVhdGUgZGlyZWN0b3J5IGZvciBkYXRhDQppZighZGlyLmV4aXN0cygiZGF0YS9LNzdKUCIpKSB7ZGlyLmNyZWF0ZSgiZGF0YS9LNzdKUCIsIHJlY3Vyc2l2ZSA9IFRSVUUpfQ0KaWYoIWRpci5leGlzdHMoImRhdGEvSzc3SlAvSW50ZXJPcCIpKSB7ZGlyLmNyZWF0ZSgiZGF0YS9LNzdKUC9JbnRlck9wIiwgcmVjdXJzaXZlID0gVFJVRSl9DQoNCiMgRG93bmxvYWQgZmlsZXMgZnJvbSB6ZW5vZG8NCmRvd25sb2FkX3plbm9kbygNCiAgZG9pID0gIjEwLjUyODEvemVub2RvLjcxMTIxNjIiLA0KICBwYXRoID0gImRhdGEvSzc3SlAiDQopDQoNCiMgTW92ZSB0aGUgaW50ZXJvcCBmaWxlcyB0byB0aGUgaW50ZXJvcCBmb2xkZXINCmZzOjpkaXJfbHMocGF0aD0iZGF0YS9LNzdKUCIsIGdsb2I9IiouYmluIikgJT4lDQogIHB1cnJyOjptYXAoZnVuY3Rpb24oeCl7DQogICAgZnM6OmZpbGVfY29weShwYXRoID0geCwgbmV3X3BhdGggPSB4ICU+JSBzdHJfcmVwbGFjZSgiZGF0YS9LNzdKUCIsICJkYXRhL0s3N0pQL0ludGVyT3AiKSkNCiAgICBmaWxlLnJlbW92ZSh4KQ0KICB9KQ0KYGBgDQoNCiMgSW5zdGFsbCBhbmQgbG9hZCBSIHBhY2thZ2VzIGFuZCBzZXR1cCBkaXJlY3RvcmllcyB7LX0NCg0KVGhpcyBwaXBlbGluZSBkZXBlbmRzIG9uIGEgbnVtYmVyIG9mIG90aGVyIFIgcGFja2FnZXMgd2hpY2ggdGhpcyBzdGVwIHdpbGwgaW5zdGFsbC4gVGhlIHZlcnNpb25zIG9mIHRoZXNlIHBhY2thZ2VzIGFyZSBtYW5hZ2VkIHVzaW5nIFtyZW52XShodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL3JlbnYvYXJ0aWNsZXMvcmVudi5odG1sKSB0byBlbnN1cmUgdGhleSBtYXRjaCB0aGUgdmVyc2lvbnMgdGhlIHBpcGVsaW5lIHdhcyBkZXZlbG9wZWQgb24uIFRoZSBmaXJzdCB0aW1lIGluc3RhbGxpbmcgcGFja2FnZXMgbWF5IHRha2Ugc29tZSB0aW1lLCBidXQgdGhleSBzaG91bGQgYmUgcXVpY2sgdG8gbG9hZCBmb3IgYW55IGZ1dHVyZSBydW5zLiANCg0KYGBge3IgTWFudWFsIGluc3RhbGx9IA0KIyBMb2FkIHRoZSB0YXJnZXRzIGFuZCByZW52IHBhY2thZ2VzDQpsaWJyYXJ5KHRhcmdldHMpDQpsaWJyYXJ5KHRhcmNoZXR5cGVzKQ0KDQojIExvYWQgYWxsIHBhY2thZ2VzIHVzaW5nIHJlbnY6OnJlc3RvcmUoKSBhbmQgc291cmNlIHBhY2thZ2UgbGlzdA0KcmVudjo6cmVzdG9yZSgpDQpzb3VyY2UoIl90YXJnZXRzX3BhY2thZ2VzLlIiKQ0KDQojIFNvdXJjZSBhbmNpbGxhcnkgZnVuY3Rpb25zDQpzb3VyY2UoIlIvZnVuY3Rpb25zLlIiKQ0Kc291cmNlKCJSL3RoZW1lcy5SIikNCmBgYA0KDQojIFJlZmVyZW5jZSBkYXRhYmFzZXMgey50YWJzZXR9DQoNClRoZSBwaXBlUmxpbmUgd29ya2Zsb3cgdXNlcyB0aGUgW0lEVEFYQV0oaHR0cHM6Ly9taWNyb2Jpb21lam91cm5hbC5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L3M0MDE2OC0wMTgtMDUyMS01KSBhbmQgQkxBU1Qgc29mdHdhcmUgdG8gYXNzaWduIHRheG9ub215IHRvIHRoZSBzZXF1ZW5jZSByZWFkcy4gVGhlc2UgcmVxdWlyZSBhIHByZS10cmFpbmVkIElEVEFYQSBtb2RlbCwgYW5kIGEgZmFzdGEgZmlsZSB3aXRoIGhlaXJhcmNoaWFsIHRheG9ub215LiBGb3IgaW5zZWN0cywgdGhlc2UgDQoNCiMjIERvd25sb2FkIHJlZmVyZW5jZSBkYXRhYmFzZQ0KDQpSZWZlcmVuY2UgZGF0YWJhc2VzIGZvciBpbnNlY3RzIGFuZCBhcmFjaG5pZHMgaGF2ZSBiZWVuIGhvc3RlZCBvbiBbWmVub2RvXShodHRwczovL3plbm9kby5vcmcvcmVjb3JkLzc2NTUzNTIjLllfTGdzSFpCei1nKSwgZWl0aGVyIGRvd25sb2FkIHRoZW0gbWFudWFsbHksIG9yIHdpdGggUiBiZWxvdzoNCg0KYGBge3J9DQojIFNvdXJjZSB0aGUgZnVuY3Rpb25zIGZpbGUgd2hpY2ggY29udGFpbnMgY29kZSB0byBkb3dubG9hZCBmcm9tIHplbm9kbw0Kc291cmNlKCJSL2Z1bmN0aW9ucy5SIikNCg0KIyBEb3dubG9hZCBmaWxlcyBmcm9tIHplbm9kbw0KZG93bmxvYWRfemVub2RvKA0KICBkb2kgPSAiMTAuNTI4MS96ZW5vZG8uNzY1NTM1MiIsDQogIHBhdGggPSAicmVmZXJlbmNlIg0KKQ0KYGBgDQoNCiMjIENyZWF0ZSB5b3VyIG93biByZWZlcmVuY2UgZGF0YWJhc2UNCg0KSWYgeW91IG5lZWQgYSBuZXcgZGF0YWJhc2UsIHRoZXNlIGNhbiBiZSBjcmVhdGVkIGZyb20gZ2VuYmFuayBhbmQgYmxhc3QgdXNpbmcgW3RheHJldHVybl0oaHR0cHM6Ly9naXRodWIuY29tL2FsZXhwaXBlci90YXhyZXR1cm4pIG9yIG90aGVyIHNpbWlhbHIgZGF0YWJhc2UgY3VyYXRpb24gcGFja2FnZXMuICANCg0KYGBge2NvZGV9DQo+QWNjZXNzaW9ufFJvb3Q7S2luZ2RvbTtQaHlsdW07Q2xhc3M7T3JkZXI7RmFtaWx5O0dlbnVzO1NwZWNpZXMNCkFDQ1RBR0FBQUdUQ0dUQUdBVENHQUFHVFRHQUFHQ0FUQ0dDQ0NHQVRHQVRDR1RDVEdBQUdDVEdUQUdDQVRHQUdUQ0dBVFRUVENBQ0FUVENBR0dHQVRBQ0NBVEFHR0FUQUMNCj5Sb290O0tpbmdkb207UGh5bHVtO0NsYXNzO09yZGVyO0ZhbWlseTtHZW51cztTcGVjaWVzDQpDR0NUQUdBQUFHVENHVEFHQUFHR0NUQ0dHQUdHVFRUR0FBR0NBVENHQ0NDR0FUR0dHQVRDVENHVFRHQ1RHVEFHQ0FUR0FHVEFDR0dBQ0FUVENBR0dHQVRDQVRBR0dBVEFDDQpgYGANCg0KVGhlIElEVEFYQSBtb2RlbCBjYW4gdGhlbiBiZSB0cmFpbmVkIG9uIHRoaXMgcmVmZXJlbmNlIGZhc3RhIC0gU2VlIHRoZSBbSURUQVhBIG1hbnVhbF0oaHR0cDovL3d3dzIuZGVjaXBoZXIuY29kZXMvRG9jdW1lbnRhdGlvbi9Eb2N1bWVudGF0aW9uLUNsYXNzaWZ5U2VxdWVuY2VzLmh0bWwpDQoNCiMgQ3JlYXRlIHNhbXBsZSB0cmFja2luZyBzaGVldCB7LX0NCg0KSW4gb3JkZXIgdG8gdHJhY2sgc2FtcGxlcyBhbmQgcmVsZXZhbnQgUUMgc3RhdGlzdGljcyB0aHJvdWdob3V0IHRoZSBtZXRhYmFyY29kaW5nIHBpcGVsaW5lLCB3ZSB3aWxsIGZpcnN0IGNyZWF0ZSBhIG5ldyBzYW1wbGUgdHJhY2tpbmcgc2hlZXQgZnJvbSBvdXIgaW5wdXQgaWxsdW1pbmEgc2FtcGxlc2hlZXRzLiBUaGlzIGZ1bmN0aW9uIHJlcXVpcmVzIGJvdGggdGhlIFNhbXBsZVNoZWV0LmNzdiB1c2VkIGZvciB0aGUgc2VxdWVuY2luZyBydW4sIGFuZCB0aGUgcnVuUGFyYW1ldGVycy54bWwsIGJvdGggb2Ygd2hpY2ggc2hvdWxkIGhhdmUgYmVlbiBhdXRvbWF0aWNhbGx5IG9idGFpbmVkIGZyb20gdGhlIGRlbXVsdGlwbGV4ZWQgc2VxdWVuY2luZyBydW4gZm9sZGVyIGluIHRoZSBiYXNoIHN0ZXAgYWJvdmUNCg0KYGBge3IgY3JlYXRlIHNhbXBsZXNoZWV0fQ0KcnVucyA8LSBkaXIoImRhdGEvIikgI0ZpbmQgYWxsIGRpcmVjdG9yaWVzIHdpdGhpbiBkYXRhDQpTYW1wbGVTaGVldCA8LSBsaXN0LmZpbGVzKHBhc3RlMCgiZGF0YS8iLCBydW5zKSwgcGF0dGVybj0gIlNhbXBsZVNoZWV0IiwgZnVsbC5uYW1lcyA9IFRSVUUpDQpydW5QYXJhbWV0ZXJzIDwtIGxpc3QuZmlsZXMocGFzdGUwKCJkYXRhLyIsIHJ1bnMpLCBwYXR0ZXJuPSAiW1JyXXVuUGFyYW1ldGVycy54bWwiLCBmdWxsLm5hbWVzID0gVFJVRSkNCg0KIyBDcmVhdGUgc2FtcGxlc2hlZXQgY29udGFpbmluZyBzYW1wbGVzIGFuZCBydW4gcGFyYW1ldGVycyBmb3IgYWxsIHJ1bnMNCnNhbWRmIDwtIGNyZWF0ZV9zYW1wbGVzaGVldChTYW1wbGVTaGVldCA9IFNhbXBsZVNoZWV0LCBydW5QYXJhbWV0ZXJzID0gcnVuUGFyYW1ldGVycywgdGVtcGxhdGUgPSAiVjQiKSAlPiUNCiAgZGlzdGluY3QoKQ0KDQojIENoZWNrIHRoYXQgc2FtcGxlX2lkcyBjb250YWluIGZjaWQsIGlmIG5vdDsgYXR0YXRjaA0Kc2FtZGYgPC0gc2FtZGYgJT4lDQogIG11dGF0ZShzYW1wbGVfaWQgPSBjYXNlX3doZW4oDQogICAgIXN0cl9kZXRlY3Qoc2FtcGxlX2lkLCBmY2lkKSB+IHBhc3RlMChmY2lkLCJfIixzYW1wbGVfaWQpLA0KICAgIFRSVUUgfiBzYW1wbGVfaWQNCiAgKSkNCg0KIyBDaGVjayB0aGF0IHNhbXBsZXMgbWF0Y2ggc2FtcGxlc2hlZXQNCmZhc3RxRnMgPC0gcHVycnI6Om1hcChsaXN0LmRpcnMoImRhdGEiLCByZWN1cnNpdmU9RkFMU0UpLA0KICAgICAgICAgICAgICAgICAgICAgIGxpc3QuZmlsZXMsIHBhdHRlcm49Il9SMV8iLCBmdWxsLm5hbWVzID0gVFJVRSkgJT4lDQogIHVubGlzdCgpICU+JQ0KICBzdHJfcmVtb3ZlKHBhdHRlcm4gPSAiXiguKilcXC8iKSAlPiUNCiAgc3RyX3JlbW92ZShwYXR0ZXJuID0gIig/Oi4oPyFfUykpKyQiKQ0KDQojIEZpbHRlciB1bmRldGVybWluZWQgcmVhZHMgZnJvbSBzYW1wbGUgc2hlZXQNCmZhc3RxRnMgPC0gZmFzdHFGc1shc3RyX2RldGVjdChmYXN0cUZzLCAiVW5kZXRlcm1pbmVkIildDQoNCiMgQ2hlY2sgZm9yIGZhc3RxIGZpbGVzIHRoYXQgYXJlIG1pc3NpbmcgZnJvbSBzYW1wbGVzaGVldA0KaWYgKGxlbmd0aChzZXRkaWZmKGZhc3RxRnMsIHNhbWRmJHNhbXBsZV9pZCkpID4gMCkge3dhcm5pbmcoIlRoZSBmYXN0cSBmaWxlL3M6ICIsIHNldGRpZmYoZmFzdHFGcywgc2FtZGYkc2FtcGxlX2lkKSwgIiBhcmUgbm90IGluIHRoZSBzYW1wbGUgc2hlZXQiKSB9DQoNCiMgQ2hlY2sgZm9yIHNhbXBsZV9pZHMgdGhhdCBkb250IGhhdmUgYSBjb3JyZXNwb25kaW5nIGZhc3RxIGZpbGUNCmlmIChsZW5ndGgoc2V0ZGlmZihzYW1kZiRzYW1wbGVfaWQsIGZhc3RxRnMpKSA+IDApIHsNCiAgd2FybmluZyhwYXN0ZTAoIlRoZSBmYXN0cSBmaWxlOiAiLA0KICAgICAgICAgICAgICAgICBzZXRkaWZmKHNhbWRmJHNhbXBsZV9pZCwgZmFzdHFGcyksDQogICAgICAgICAgICAgICAgICIgaXMgbWlzc2luZywgZHJvcHBpbmcgZnJvbSBzYW1wbGVzaGVldCBcbiIpKSANCiAgc2FtZGYgPC0gc2FtZGYgJT4lDQogICAgZmlsdGVyKCFzYW1wbGVfaWQgJWluJSBzZXRkaWZmKHNhbWRmJHNhbXBsZV9pZCwgZmFzdHFGcykpDQp9DQoNCiMgV3JpdGUgb3V0IHNhbXBsZSB0cmFja2luZyBzaGVldA0Kd3JpdGVfY3N2KHNhbWRmLCAic2FtcGxlX2RhdGEvU2FtcGxlX2luZm8uY3N2IikNCmBgYA0KDQojIEFkZCBQQ1IgcHJpbWVycyB0byBzYW1wbGUgc2hlZXQgey50YWJzZXR9DQoNClRoaXMgY2FuIGVpdGhlciBiZSBkb25lIG1hbnVhbGx5IGJ5IGVkaXRpbmcgdGhlIHNhbXBsZV9kYXRhL1NhbXBsZV9pbmZvLmNzdiBmaWxlLCBvciBpdCBjYW4gYmUgZG9uZSBpbiBSIGFzIGJlbG93Lg0KDQpJZiBhIHNpbmdsZSBwcmltZXIgc2V0IHdhcyB1c2VkIGFjcm9zcyBhbGwgc2FtcGxlcywgdGhlc2UgY2FuIHNpbXBseSBiZSBhZGRlZCB1c2luZyBhIG11dGF0ZSBjYWxsICgqKnRhYiAxKiopLg0KDQpJZiBkaWZmZXJlbnQgcHJpbWVycyB3ZXJlIHVzZWQgZm9yIGRpZmZlcmVudCBzYW1wbGVzLCB0aGVzZSBjYW4gYmUgc2V0IHVzaW5nIHBhdHRlcm4gbWF0Y2hpbmcgb24gdGhlIHNhbXBsZSBuYW1lcyB3aXRoIGNhc2Vfd2hlbiAoKip0YWIgMioqKS4NCg0KSWYgbXVsdGlwbGUgcHJpbWVyIHNldHMgYXJlIHVzZWQgcGVyIHNhbXBsZSwgYmVmb3JlIGluZGV4aW5nLCB0aGUgcGlwZWxpbmUgd2lsbCBjb25kdWN0IGFuIGV4dHJhIHJvdW5kIG9mIGRlbXVsdGlwbGV4aW5nIHRvIHNwbGl0IGVhY2ggc2FtcGxlIGJ5IHByaW1lci4gVGhpcyBvcHRpb24gY2FuIGJlIHNldCBieSBzcGxpdHRpbmcgZWFjaCBwcmltZXIgc2V0IHdpdGggYSBzZW1pY29sb24gKCoqdGFiIDMqKikgDQoNCiMjIFNpbmdsZSBwcmltZXIgc2V0DQoNCmBgYHtSfQ0KIyBBZGQgcHJpbWVycyB0byBzYW1wbGUgc2hlZXQNCnNhbWRmIDwtIHNhbWRmICU+JQ0KICBtdXRhdGUocGNyX3ByaW1lcnMgPSAiZndoRjItZndoUjJuIiwNCiAgZm9yX3ByaW1lcl9zZXEgPSAiR0dEQUNXR0dXVEdBQUNXR1RXVEFZQ0NIQ0MiLA0KICByZXZfcHJpbWVyX3NlcSA9ICJHVFJBVFdHQ0hDQ0RHQ1RBUldBQ1dHRyINCiAgKQ0KDQp3cml0ZV9jc3Yoc2FtZGYsICJzYW1wbGVfZGF0YS9TYW1wbGVfaW5mby5jc3YiKQ0KYGBgDQoNCiMjIERpZmZlcmVudCBwcmltZXIgc2V0cyBwZXIgc2FtcGxlDQoNCmBgYHtSfQ0KIyBBZGQgUENSIHByaW1lcnMgdG8gc2FtcGxlIHNoZWV0DQpzYW1kZiA8LSBzYW1kZiAlPiUNCiAgbXV0YXRlKHBjcl9wcmltZXJzID0gY2FzZV93aGVuKA0KICAgIHN0cl9kZXRlY3Qoc2FtcGxlX25hbWUsICJwcmltZXIxIikgfiAiZndoRjItZndoUjJuIiwNCiAgICBzdHJfZGV0ZWN0KHNhbXBsZV9uYW1lLCAicHJpbWVyMiIpIH4gIkVJRjNMbWluaUY0LUVJRjNsbWluaVI0Ig0KICApLA0KICBmb3JfcHJpbWVyX3NlcSA9IGNhc2Vfd2hlbigNCiAgICBzdHJfZGV0ZWN0KHNhbXBsZV9uYW1lLCAicHJpbWVyMSIpIH4gIkdHREFDV0dHV1RHQUFDV0dUV1RBWUNDSENDIiwNCiAgICBzdHJfZGV0ZWN0KHNhbXBsZV9uYW1lLCAicHJpbWVyMiIpIH4gIkdBVEdDR1lDR1RUQVRHQ1lHQVRHQyINCiAgKSwNCiAgcmV2X3ByaW1lcl9zZXEgPSBjYXNlX3doZW4oDQogICAgc3RyX2RldGVjdChzYW1wbGVfbmFtZSwgInByaW1lcjEiKSB+ICJHVFJBVFdHQ0hDQ0RHQ1RBUldBQ1dHRyIsDQogICAgc3RyX2RldGVjdChzYW1wbGVfbmFtZSwgInByaW1lcjIiKSB+ICJUVFJBQVlBQ1RUQ1lBUkFUQ1JDQyINCiAgKSkNCg0Kd3JpdGVfY3N2KHNhbWRmLCAic2FtcGxlX2RhdGEvU2FtcGxlX2luZm8uY3N2IikNCmBgYA0KDQojIyBNdWx0aXBsZSBwcmltZXIgc2V0cyBwZXIgc2FtcGxlDQoNCmBgYHtSfQ0KIyBBZGQgUENSIHByaW1lcnMgdG8gc2FtcGxlIHNoZWV0DQpzYW1kZiA8LSBzYW1kZiAlPiUNCiAgbXV0YXRlKA0KICAgIHBjcl9wcmltZXJzID0gImZ3aEYyLWZ3aFIybkRhYztFSUYzTG1pbmlGNC1FSUYzbG1pbmlSNCIsDQogICAgZm9yX3ByaW1lcl9zZXEgPSAiR0dEQUNXR0dXVEdBQUNXR1RXVEFZQ0NIQ0M7R0FUR0NHWUNHVFRBVEdDWUdBVEdDIiwNCiAgICByZXZfcHJpbWVyX3NlcSA9ICJHVFJBVFdHQ0hDQ0lHQ1RBQURBQ0hHRztUVFJBQVlBQ1RUQ1lBUkFUQ1JDQyINCiAgICApDQoNCndyaXRlX2NzdihzYW1kZiwgInNhbXBsZV9kYXRhL1NhbXBsZV9pbmZvLmNzdiIpDQpgYGANCg0KDQojIENyZWF0ZSBwYXJhbWV0ZXJzIGZpbGUgey50YWJzZXR9DQoNClRoZSBwYXJhbWV0ZXJzIGZpbGUgdGFibGUgdGhlIHJlc3BlY3RpdmUgdGFyZ2V0IGdlbmUsIHJlZmVyZW5jZSBkYXRhYmFzZXMsIGFuZCBmaWx0ZXJpbmcgcGFyYW1ldGVycyBmb3IgZWFjaCBwcmltZXIgc2V0IHVzZWQgdG8gYW1wbGlmeSB0aGUgc2FtcGxlcy4gQXMgdGhlIHBjcl9wcmltZXJzIGNvbHVtbiBpcyB1c2VkIGluIHRoZSBwaXBlbGluZSB0byBtYXRjaCB0aGUgcGFyYW1ldGVycyB0byB0aGUgcmVzcGVjdGl2ZSBzYW1wbGUsIGl0IGlzIGNyaXRpY2FsIHRoYXQgdGhlIHByaW1lciBuYW1lcyBtYXRjaCB0aG9zZSBzZXQgaW4gdGhlIHByZXZpb3VzIHN0ZXAuDQoNCklmIGEgc2luZ2xlIHByaW1lciBzZXQgd2FzIHVzZWQgYWNyb3NzIGFsbCBzYW1wbGVzLCB0aGVzZSBjYW4gc2ltcGx5IGJlIGFkZGVkIHRvIHRoZSB0YWJsZSBhcyBiZWxvdyAoKip0YWIgMSoqKS4NCg0KSWYgZGlmZmVyZW50IHByaW1lcnMgd2VyZSB1c2VkIGZvciBkaWZmZXJlbnQgc2FtcGxlcywgdGhlc2UgY2FuIGJlIHNldCBhcyBkaWZmZXJlbnQgcm93cyBpbiB0aGUgdGFibGUgdXNpbmcgYygpIHdoZW4gY3JlYXRpZ24gdGhlIHRpYmJsZSAoKip0YWIgMioqKS4NCg0KSWYgbXVsdGlwbGUgcHJpbWVyIHJlZmVyZW5jZSBkYXRhYmFzZXMgYXJlIHRvIGJlIHVzZWQgZm9yIGVhY2ggc2FtcGxlLCB0aGVzZSBjYW4gYmUgc2V0IGJ5IHNwbGl0dGluZyBlYWNoIGEgc2VtaWNvbG9uLiBUaGUgdGF4b25vbWljIGFzc2lnbm1lbnQgd2lsbCBiZSBjb25kdWN0ZWQgc2VxdWVudGlhbGx5IHRocm91Z2ggdGhlIGRhdGFiYXNlcyBmcm9tIGxlZnQgdG8gcmlnaHQsIHdpdGggdGhlIHNlY29uZCByZWZlcmVuY2UgZGF0YWJhc2Ugb25seSBiZWluZyB1c2VkIGZvciB0aG9zZSBBU1ZzIHRoYXQgY291bGRudCBiZSBhc3NpZ25lZCB0byBzcGVjaWVzIGxldmVsIHVzaW5nIHRoZSBmaXJzdCBkYXRhYmFzZXMgKCoqdGFiIDMqKikgDQoNCioqUGFyYW1ldGVyIG9wdGlvbnMqKg0KDQoqICoqUHJpbWVyIHBhcmFtZXRlcnM6KioNCiAgICArICoqcGNyX3ByaW1lcnMqKiAtIE5hbWUgb2YgUENSIHByaW1lcnMgLSBtdXN0IG1hdGNoIHNhbWRmIGZpbGUNCiAgICArICoqdGFyZ2V0X2dlbmUqKiAtIE5hbWUgb2YgdGFyZ2V0IGdlbmUNCiAgICArICoqbWF4X3ByaW1lcl9taXNtYXRjaCoqIC0gSG93IG11Y2ggbWlzbWF0Y2ggdG8gYWxsb3cgd2hlbiBkZXRlY3RpbmcgcHJpbWVyIHNlcXVlbmNlcw0KDQoqICoqUmVhZCBmaWx0ZXJpbmc6KioNCiAgICArICoqcmVhZF9taW5fbGVuZ3RoKiogLSBNaW5pbXVtIGxlbmd0aCBvZiBwcmltZXIgdHJpbW1lZCByZWFkcw0KICAgICsgKipyZWFkX21heF9sZW5ndGgqKiAtIE1heGltdW0gbGVuZ3RoIG9mIHByaW1lciB0cmltbWVkIHJlYWRzDQogICAgKyAqKnJlYWRfbWF4X2VlKiogLSBNYXhpbXVtIGV4cGVjdGVkIGVycm9ycyBvZiBwcmltZXIgdHJpbW1lZCByZWFkcw0KICAgICsgKipyZWFkX3RydW5jX2xlbmd0aCoqIC0gTGVuZ3RoIHRvIGN1dCBhbGwgbG9uZ2VyIHJlYWRzIHRvDQogICAgKyAqKnJlYWRfdHJpbV9sZWZ0KiogLSBSZW1vdmUgdGhpcyBtYW55IGJwIGZyb20gbGVmdCBzaWRlIG9mIHByaW1lciB0cmltbWVkIHJlYWRzDQogICAgKyAqKnJlYWRfdHJpbV9yaWdodCoqIC0gUmVtb3ZlIHRoaXMgbWFueSBicCBmcm9tIHJpZ2h0IHNpZGUgb2YgcHJpbWVyIHRyaW1tZWQgcmVhZHMNCg0KKiAqKkFTViBmaWx0ZXJpbmcqKg0KICAgICsgKiphc3ZfbWluX2xlbmd0aCoqIC0gTWluaW11bSBsZW5ndGggb2YgYW1wbGljb24NCiAgICArICoqYXN2X21heF9sZW5ndGgqKiAtIE1heGltdW0gbGVuZ3RoIG9mIGFtcGxpY29uDQogICAgKyAqKmhpZ2hfc2Vuc2l0aXZpdHkqKiAtIE9wdGlvbiB0byB0dXJuIG9uIFtwc2V1ZG8gcG9vbGluZ10oaHR0cHM6Ly9iZW5qam5lYi5naXRodWIuaW8vZGFkYTIvcHNldWRvLmh0bWwpLCBzZXR0aW5nIHRoaXMgdG8gRkFMU0UgZ3JlYXRseSBzcGVlZHMgdXAgQVNWIGluZmVyZW5jZSBhdCB0aGUgZXhwZW5zZSBvZiBkZXRlY3RpbmcgZmV3ZXIgcmFyZSAoPDUgcmVhZHMpIHRheGEuDQogICAgKyAqKmNvbmNhdF91bm1lcmdlZCoqIC0gUmV0YWluIGFueSB1bm1lcmdlZCByZWFkIHBhaXJzIGJ5IGNvbmNhdGVuYXRpbmcgdGhlbSB0b2dldGhlciBzZXBhcmF0ZWQgYnkgYSBzdHJpbmcgb2YgMTAgTiBiYXNlcw0KICAgICsgKipnZW5ldGljX2NvZGUqKiAtIEdlbmV0aWMgY29kZSBmb3IgYW1wbGljb24gLSBzZWUgQmlvc3RyaW5nczo6R0VORVRJQ19DT0RFX1RBQkxFDQogICAgKyAqKmNvZGluZyoqIC0gSXMgdGhlIGFtcGxpY29uIGZyb20gYSBwcm90ZWluIGNvZGluZyBnZW5lDQogICAgKyAqKnBobW0qKiAtIFBhdGggdG8gcHJvZmlsZSBoaWRkZW4gbWFya292IG1vZGVsIChPcHRpb25hbCkNCg0KKiAqKlRheG9ub21pYyBhc3NpZ25tZW50OioqDQogICAgKyAqKmlkdGF4YV9kYioqIC0gUGF0aCB0byB0cmFpbmVkIElEVEFYQSBtb2RlbA0KICAgICsgKipyZWZfZmFzdGEqKiAtIFBhdGggdG8gZmFzdGEgZmlsZSBvZiByZWZlcmVuY2UgZGF0YWJhc2UNCiAgICArICoqaWR0YXhhX2NvbmZpZGVuY2UqKiAtIE1pbmltdW0gYm9vdHN0cmFwIGNvbmZpZGVuY2UgZm9yIElEVEFYQQ0KICAgICsgKipydW5fYmxhc3QqKiAtIFdoZXRoZXIgYSBibGFzdCB0b3AgaGl0IHNlYXJjaCBzaG91bGQgYmUgY29uZHVjdGVkIGluIGFkZGl0aW9uIHRvIElEVEFYQQ0KICAgICsgKipibGFzdF9taW5faWRlbnRpdHkqKiAtIE1pbmltdW0gbnVjbGVvdGlkZSBpZGVudGl0eSBmb3IgQkxBU1QNCiAgICArICoqYmxhc3RfbWluX2NvdmVyYWdlKiogLSBNaW5pbXVtIHF1ZXJ5IGNvdmVyYWdlIGZvciBCTEFTVA0KICAgICsgKip0YXJnZXRfa2luZ2RvbSoqIC0gU3Vic2V0IHRvIHRhcmdldCBraW5nZG9tDQogICAgKyAqKnRhcmdldF9waHlsdW0qKiAtIFN1YnNldCB0byB0YXJnZXQgcGh5bHVtDQogICAgKyAqKnRhcmdldF9jbGFzcyoqIC0gU3Vic2V0IHRvIHRhcmdldCBjbGFzcw0KICAgICsgKip0YXJnZXRfb3JkZXIqKiAtIFN1YnNldCB0byB0YXJnZXQgb3JkZXINCiAgICArICoqdGFyZ2V0X2ZhbWlseSoqIC0gU3Vic2V0IHRvIHRhcmdldCBmYW1pbHkNCiAgICArICoqdGFyZ2V0X2dlbnVzKiogLSBTdWJzZXQgdG8gdGFyZ2V0IGdlbnVzDQogICAgKyAqKnRhcmdldF9zcGVjaWVzKiogLSBTdWJzZXQgdG8gdGFyZ2V0IHNwZWNpZXMNCg0KKiAqKlNhbXBsZSAmIFRheG9uIGZpbHRlcmluZzoqKg0KICAgICsgKiptaW5fc2FtcGxlX3JlYWRzKiogLSBNaW5pbXVtIHJlYWRzIHBlciBzYW1wbGUgYWZ0ZXIgZmlsdGVyaW5nDQogICAgKyAqKm1pbl90YXhhX3JlYWRzKiogLSBNaW5pbXVtIHJlYWRzIHBlciBBU1YgdG8gcmV0YWluDQogICAgKyAqKm1pbl90YXhhX3JhKiogLSBNaW5pbXVtIHJlbGF0aXZlIGFidW5kYW5jZSBwZXIgQVNWIHRvIHJldGFpbi4gMWUtNCBpcyAwLjAxJQ0KDQoqICoqR2VuZXJhbCBwaXBlbGluZSBwYXJhbWV0ZXJzKioNCiAgICArICoqdGhyZWFkcyoqIC0gTnVtYmVyIG9mIENQVSB0aHJlYWRzIHRvIHJ1biB0aGUgcGlwZWxpbmUgYWNyb3NzDQogICAgDQojIyBTaW5nbGUgcHJpbWVyIHNldA0KDQpgYGB7Un0NCiMgUGFyYW1zIHRvIGFkZCBpbiBzdGVwX2FkZF9wYXJhbWV0ZXJzDQpwYXJhbXMgPC0gdGliYmxlKA0KICAjIFByaW1lciBwYXJhbWV0ZXJzDQogIHBjcl9wcmltZXJzID0gImZ3aEYyLWZ3aFIybiIsDQogIHRhcmdldF9nZW5lPSJDT0kiLA0KICBtYXhfcHJpbWVyX21pc21hdGNoPTAsDQoNCiAgIyBSZWFkIGZpbHRlcmluZw0KICByZWFkX21pbl9sZW5ndGggPSAyMCwNCiAgcmVhZF9tYXhfbGVuZ3RoID0gSW5mLA0KICByZWFkX21heF9lZSA9IDEsDQogIHJlYWRfdHJ1bmNfbGVuZ3RoID0gMTUwLA0KICByZWFkX3RyaW1fbGVmdCA9IDAsIA0KICByZWFkX3RyaW1fcmlnaHQgPSAwLA0KICANCiAgIyBBU1YgZmlsdGVyaW5nDQogIGFzdl9taW5fbGVuZ3RoID0gMTk1LCANCiAgYXN2X21heF9sZW5ndGggPSAyMTUsDQogIGhpZ2hfc2Vuc2l0aXZpdHkgPSBUUlVFLA0KICBjb25jYXRfdW5tZXJnZWQgPSBGQUxTRSwNCiAgZ2VuZXRpY19jb2RlID0gIlNHQzQiLA0KICBjb2RpbmcgPSBUUlVFLA0KICBwaG1tID0gInJlZmVyZW5jZS9mb2xtZXJfZnVsbGVuZ3RoX21vZGVsLnJkcyIsDQogIA0KICAjIFRheG9ub21pYyBhc3NpZ25tZW50DQogIGlkdGF4YV9kYiA9ICJyZWZlcmVuY2UvaWR0YXhhX2JmdHJpbW1lZC5yZHMiLA0KICByZWZfZmFzdGEgPSAicmVmZXJlbmNlL2luc2VjdGFfaGllcmFyY2hpYWxfYmZ0cmltbWVkLmZhLmd6IiwNCiAgaWR0YXhhX2NvbmZpZGVuY2UgPSA2MCwNCiAgcnVuX2JsYXN0PVRSVUUsDQogIGJsYXN0X21pbl9pZGVudGl0eSA9IDk3LA0KICBibGFzdF9taW5fY292ZXJhZ2UgPSA5MCwNCiAgdGFyZ2V0X2tpbmdkb20gPSAiTWV0YXpvYSIsDQogIHRhcmdldF9waHlsdW0gPSAiQXJ0aHJvcG9kYSIsDQogIHRhcmdldF9jbGFzcyA9IE5BLA0KICB0YXJnZXRfb3JkZXIgPSBOQSwNCiAgdGFyZ2V0X2ZhbWlseSA9IE5BLA0KICB0YXJnZXRfZ2VudXMgPSBOQSwNCiAgdGFyZ2V0X3NwZWNpZXM9IE5BLA0KICANCiAgIyBTYW1wbGUgJiBUYXhvbiBmaWx0ZXJpbmcNCiAgbWluX3NhbXBsZV9yZWFkcyA9IDEwMDAsDQogIG1pbl90YXhhX3JlYWRzPSBOQSwNCiAgbWluX3RheGFfcmEgPSAxZS00LCAjMWUtNCBpcyAwLjAxJQ0KICAgIA0KICAjIEdlbmVyYWwgcGlwZWxpbmUgcGFyYW1ldGVycw0KICB0aHJlYWRzID0gMQ0KKQ0KDQp3cml0ZV9jc3YocGFyYW1zLCAic2FtcGxlX2RhdGEvbG9jaV9wYXJhbXMuY3N2IikNCmBgYA0KDQojIyBEaWZmZXJlbnQgb3IgbXVsdGlwbGUgcHJpbWVyIHNldHMgcGVyIHNhbXBsZQ0KDQpgYGB7Un0NCiMgUGFyYW1zIHRvIGFkZCBpbiBzdGVwX2FkZF9wYXJhbWV0ZXJzDQpwYXJhbXMgPC0gdGliYmxlKA0KICAjIFByaW1lciBwYXJhbWV0ZXJzDQogIHBjcl9wcmltZXJzID0gYygiZndoRjItZndoUjJuRGFjIiwgIkVJRjNMbWluaUY0LUVJRjNsbWluaVI0IiksDQogIHRhcmdldF9nZW5lPWMoIkNPSSIsICJFSUYzTCIpLA0KICBtYXhfcHJpbWVyX21pc21hdGNoPTEsDQoNCiAgIyBSZWFkIGZpbHRlcmluZw0KICByZWFkX21pbl9sZW5ndGggPSAyMCwNCiAgcmVhZF9tYXhfbGVuZ3RoID0gSW5mLA0KICByZWFkX21heF9lZSA9IDEsDQogIHJlYWRfdHJ1bmNfbGVuZ3RoID0gMTUwLA0KICByZWFkX3RyaW1fbGVmdCA9IDAsDQogIHJlYWRfdHJpbV9yaWdodCA9IDAsDQogIA0KICAjIEFTViBmaWx0ZXJpbmcNCiAgYXN2X21pbl9sZW5ndGggPSBjKDE5NSwgMjA3KSwNCiAgYXN2X21heF9sZW5ndGggPSBjKDIxNSwgMjI3KSwNCiAgaGlnaF9zZW5zaXRpdml0eSA9IFRSVUUsDQogIGNvbmNhdF91bm1lcmdlZCA9IEZBTFNFLA0KICBnZW5ldGljX2NvZGUgPSBjKCJTR0M0IiwgIlNHQzAiKSwNCiAgY29kaW5nID0gYyhUUlVFLCBUUlVFKSwNCiAgcGhtbSA9IGMoInJlZmVyZW5jZS9waG1tL0JhY3Ryb2NlcmFfQ09JLnJkcyIsICJyZWZlcmVuY2UvcGhtbS9CYWN0cm9jZXJhX0VJRjNMLnJkcyIpLA0KICANCiAgIyBUYXhvbm9taWMgYXNzaWdubWVudA0KICBpZHRheGFfZGIgPSBjKCJyZWZlcmVuY2UvQ09JX2lkdGF4YS5yZHMiLCJyZWZlcmVuY2UvRUlGM0xfaWR0YXhhLnJkcyIpLA0KICByZWZfZmFzdGEgPSBjKCJyZWZlcmVuY2UvQ09JX2hpZXJhcmNoaWFsLmZhLmd6IiwgInJlZmVyZW5jZS9FSUYzTF9oaWVyYXJjaGlhbC5mYS5neiIpLA0KICBpZHRheGFfY29uZmlkZW5jZSA9IDYwLA0KICBydW5fYmxhc3Q9VFJVRSwNCiAgYmxhc3RfbWluX2lkZW50aXR5ID0gOTcsDQogIGJsYXN0X21pbl9jb3ZlcmFnZSA9IDkwLA0KICB0YXJnZXRfa2luZ2RvbSA9IGMoIk1ldGF6b2EiLCAiTWV0YXpvYSIpLA0KICB0YXJnZXRfcGh5bHVtID0gYygiQXJ0aHJvcG9kYSIsIkFydGhyb3BvZGEiKSwNCiAgdGFyZ2V0X2NsYXNzID0gTkEsDQogIHRhcmdldF9vcmRlciA9IE5BLA0KICB0YXJnZXRfZmFtaWx5ID0gTkEsIA0KICB0YXJnZXRfZ2VudXMgPSBOQSwgIA0KICB0YXJnZXRfc3BlY2llcz0gTkEsICANCiAgDQogICMgU2FtcGxlICYgVGF4b24gZmlsdGVyaW5nDQogIG1pbl9zYW1wbGVfcmVhZHMgPSBjKDEwMDAsIDEwMDApLA0KICBtaW5fdGF4YV9yZWFkcz0gTkEsIA0KICBtaW5fdGF4YV9yYSA9IGMoMWUtNCwgMWUtNCksDQopDQoNCndyaXRlX2NzdihwYXJhbXMsICJzYW1wbGVfZGF0YS9sb2NpX3BhcmFtcy5jc3YiKQ0KYGBgDQoNCiMjIE11bHRpcGxlIHJlZmVyZW5jZSBkYXRhYmFzZXMNCg0KYGBge3J9DQpwYXJhbXMgPC0gdGliYmxlKA0KICAjIFByaW1lciBwYXJhbWV0ZXJzDQogIHBjcl9wcmltZXJzID0gYygiZndoRjItZndoUjJuRGFjIiwgIkVJRjNMbWluaUY0LUVJRjNsbWluaVI0IiksDQogIHRhcmdldF9nZW5lPWMoIkNPSSIsICJFSUYzTCIpLA0KICBtYXhfcHJpbWVyX21pc21hdGNoPTAsDQoNCiAgIyBSZWFkIGZpbHRlcmluZw0KICByZWFkX21pbl9sZW5ndGggPSAyMCwNCiAgcmVhZF9tYXhfbGVuZ3RoID0gSW5mLA0KICByZWFkX21heF9lZSA9IDEsDQogIHJlYWRfdHJ1bmNfbGVuZ3RoID0gMTUwLA0KICByZWFkX3RyaW1fbGVmdCA9IDAsDQogIHJlYWRfdHJpbV9yaWdodCA9IDAsDQogIA0KICAjIEFTViBmaWx0ZXJpbmcNCiAgYXN2X21pbl9sZW5ndGggPSBjKDE5NSwgMjA3KSwNCiAgYXN2X21heF9sZW5ndGggPSBjKDIxNSwgMjI3KSwNCiAgaGlnaF9zZW5zaXRpdml0eSA9IFRSVUUsDQogIGNvbmNhdF91bm1lcmdlZCA9IEZBTFNFLA0KICBnZW5ldGljX2NvZGUgPSBjKCJTR0M0IiwgIlNHQzAiKSwNCiAgY29kaW5nID0gYyhUUlVFLCBUUlVFKSwNCiAgcGhtbSA9IGMoInJlZmVyZW5jZS9waG1tL0JhY3Ryb2NlcmFfQ09JLnJkcyIsICJyZWZlcmVuY2UvcGhtbS9CYWN0cm9jZXJhX0VJRjNMLnJkcyIpLA0KICANCiAgIyBUYXhvbm9taWMgYXNzaWdubWVudA0KICBpZHRheGFfZGIgPSBjKCJyZWZlcmVuY2UvQ09JX2ludGVybmFsX2lkdGF4YS5yZHM7cmVmZXJlbmNlL0NPSV9pZHRheGEucmRzIiwNCiAgICAgICAgICAgICAicmVmZXJlbmNlL0VJRjNMX2ludGVybmFsX2lkdGF4YS5yZHM7cmVmZXJlbmNlL0VJRjNMX2lkdGF4YS5yZHMiKSwNCiAgcmVmX2Zhc3RhID0gYygicmVmZXJlbmNlL0NPSV9pbnRlcm5hbC5mYS5nejtyZWZlcmVuY2UvQ09JX2hpZXJhcmNoaWFsLmZhLmd6IiwNCiAgICAgICAgICAgICAgICJyZWZlcmVuY2UvRUlGM0xfaW50ZXJuYWwuZmEuZ3o7cmVmZXJlbmNlL0VJRjNMX2hpZXJhcmNoaWFsLmZhLmd6IiksDQogIGlkdGF4YV9jb25maWRlbmNlID0gNjAsDQogIHJ1bl9ibGFzdD1UUlVFLA0KICBibGFzdF9taW5faWRlbnRpdHkgPSA5NywNCiAgYmxhc3RfbWluX2NvdmVyYWdlID0gOTAsDQogIHRhcmdldF9raW5nZG9tID0gYygiTWV0YXpvYSIsICJNZXRhem9hIiksDQogIHRhcmdldF9waHlsdW0gPSBjKCJBcnRocm9wb2RhIiwiQXJ0aHJvcG9kYSIpLA0KICB0YXJnZXRfY2xhc3MgPSBOQSwNCiAgdGFyZ2V0X29yZGVyID0gTkEsDQogIHRhcmdldF9mYW1pbHkgPSBOQSwgDQogIHRhcmdldF9nZW51cyA9IE5BLCAgDQogIHRhcmdldF9zcGVjaWVzPSBOQSwgIA0KICANCiAgIyBTYW1wbGUgJiBUYXhvbiBmaWx0ZXJpbmcNCiAgbWluX3NhbXBsZV9yZWFkcyA9IGMoMTAwMCwgMTAwMCksDQogIG1pbl90YXhhX3JlYWRzPSBOQSwNCiAgbWluX3RheGFfcmEgPSBjKDFlLTQsIDFlLTQpLA0KKQ0KDQp3cml0ZV9jc3YocGFyYW1zLCAic2FtcGxlX2RhdGEvbG9jaV9wYXJhbXMuY3N2IikNCmBgYA0KDQojIFJ1biBwaXBlbGluZSB7LX0NCk5vdyB0aGF0IHRoZSBzYW1wbGUgZGF0YSBzaGVldCBhbmQgcGFyYW1ldGVycyBhcmUgZGVmaW5lZCwgdGhlIHBpcGVsaW5lIHN0ZXBzIGNhbiBub3cgYmUgcnVuIGF1dG9tYXRpY2FsbHkgdXNpbmcgdGhlIHRhcl9tYWtlKCkgY29tbWFuZA0KDQpgYGB7cn0NCnRhcl9tYWtlKCkNCmBgYA0KDQojIFJlc3VsdHMNCg0KQWZ0ZXIgdGhlIHJ1biwgdHdvIGRpcmVjdG9yaWVzIHNob3VsZCBoYXZlIGJlZW4gbWFkZSB3aXRoaW4gdGhlIG91dHB1dCBmb2xkZXIsIG91dHB1dC9yZXN1bHRzL3VuZmlsdGVyZWQgd2hpY2ggY29udGFpbnMgdGhlIHJlc3VsdHMgYmVmb3JlIGFueSB0YXhvbm9taWMgc3Vic2V0dGluZywgc2FtcGxlIG1pbmltdW0gYWJ1bmRhbmNlLCBhbmQgQVNWIG1pbmltdW0gYWJ1bmRhbmNlIGZpbHRlcmluZywgYW5kIG91dHB1dC9yZXN1bHRzL2ZpbHRlcmVkIGNvbnRhaW5pbmcgdGhlIHJlc3VsdHMgYWZ0ZXIgdGhlc2Ugc3RlcHMuIFdpdGhpbiBlYWNoIG9mIHRoZXNlIGZvbGRlcnMgdGhlcmUgc2hvdWxkIGJlIGEgc2VyaWVzIG9mIG91dHB1dHM6DQoNCiogKipzdW1tYXJ5LmNzdioqIC0gVGhpcyBpcyB0aGUgbWFpbiBzdW1tYXJ5IGZpbGUgd2hpY2ggbGlzdHMgdGhlIGFidW5kYW5jZSBvZiBlYWNoIEFTViwgdGhlIHRheG9ub215IGFzc2lnbmVkIHRvIGl0LCBhbmQgdGhlIHJlYWQgY291bnRzIGZvciBlYWNoIHNhbXBsZSBpdCB3YXMgZGV0ZWN0ZWQgaW4uDQoNCiogKipwcy5yZHMqKiAtIFRoaXMgcGh5bG9zZXEgb2JqZWN0IGNvbnRhaW5zIHRoZSBzYW1lIGluZm9ybWF0aW9uIGFzIHRoZSBzdW1tYXJ5IGZpbGUsIGJ1dCBpbiBhIGZvcm1hdCB0aGF0IGNhbiBiZSBhbmFseXNlZCBmdXJ0aGVyIHVzaW5nIHRoZSBbcGh5bG9zZXEgUiBwYWNrYWdlXShodHRwczovL2pvZXk3MTEuZ2l0aHViLmlvL3BoeWxvc2VxLyksIGEgdXNlZnVsIHRvb2wgZm9yIHBsb3R0aW5nIGFuZCBmdXJ0aGVyIGFuYWx5c2lzIG9mIG1ldGFiYXJjb2RpbmcgYW5kIG1pY3JvYmlvbWUgZGF0YXNldHMuDQoNCiogKiphc3ZzLmZhc3RhKiogLSBUaGlzIGNvbnRhaW5zIHRoZSBhbXBsaWZpY2F0aW9uIHNlcXVlbmNlIHZhcmlhbnRzIGluZmVycmVkIGZyb20gdGhlIGRhdGEgc2V0DQoNCiogKipzZXF0YWIuY3N2KiogLSBUaGlzIGxpc3RzIHRoZSBhYnVuZGFuY2Ugb2YgZWFjaCBBU1YgYW5kIHRoZSBzYW1wbGUgaXQgd2FzIGRldGVjdGVkIGluLiBUaGlzIGZpbGUgaXMgZ2VuZXJhbGx5IGZvciBkZXZlbG9wbWVudCBwdXJwb3NlcyBvbmx5LCBhbmQgYWxsIGluZm9ybWF0aW9uIGNvbnRhaW5lZCBoZXJlIGlzIHByZXNlbnQgaW4gdGhlIHN1bW1tYXJ5IGNzdi4NCg0KKiAqKnRheHRhYi5jc3YqKiAtIFRoaXMgbGlzdHMgdGhlIGhlaXJhcmNoaWFsIHRheG9ub215IGFzc2lnbmVkIHRvIGVhY2ggQVNWLiBUaGlzIGZpbGUgaXMgZ2VuZXJhbGx5IGZvciBkZXZlbG9wbWVudCBwdXJwb3NlcyBvbmx5LCBhbmQgYWxsIGluZm9ybWF0aW9uIGNvbnRhaW5lZCBoZXJlIGlzIHByZXNlbnQgaW4gdGhlIHN1bW1tYXJ5IGNzdi4NCg0KKiAqKnNhbWRmLmNzdioqIC0gVGhpcyBpcyB0aGUgc2FtcGxlIHRyYWNraW5nIHNoZWV0IHRoYXQgbGlzdHMgdGhlIHNlcXVlbmNpbmcgZGV0YWlscyBmb3IgZWFjaCBzYW1wbGUuIFRoaXMgZmlsZSBpcyBnZW5lcmFsbHkgZm9yIGRldmVsb3BtZW50IHB1cnBvc2VzIG9ubHksIGFuZCBhbGwgaW5mb3JtYXRpb24gY29udGFpbmVkIGhlcmUgaXMgcHJlc2VudCBpbiB0aGUgc3VtbW1hcnkgY3N2Lg0KDQoqICoqcmF3LmNzdioqIC0gVGhpcyBpcyBhIGxhcmdlIGZpbGUgY29udGFpbmluZyBhbGwgdGhlIGFib3ZlIHJlc3VsdHMgaW4gYSBzaW5nbGUgY3N2IGluIGEgJ2xvbmcnIGZvcm1hdCBhcHByb3ByaWF0ZSBmb3IgZnVydGhlciBzdGF0aXN0aWNhbCBhbmFseXNpcy4NCg0KIyMgUXVhbGl0eSBjb250cm9sDQoNClRoZSBwaXBlbGluZSBhbHNvIG91dHB1dHMgc29tZSBxdWFsaXR5IGNvbnRyb2wgcGxvdHMgdGhhdCBzaG91bGQgYmUgY2hlY2tlZCB0byBlbnN1cmUgdGhlIHBpcGVsaW5lIGhhcyBydW4gY29ycmVjdGx5IGFuZCB0aGUgb3V0cHV0cyBhcmUgYXMgZGVzaXJlZA0KDQoqICoqUGVyLWZsb3djZWxsIHF1YWxpdHkgY2hlY2tzKioNCiAgICArICoqb3V0cHV0L2xvZ3MvRkNJRC9GQ0lEX2Zsb3djZWxsX3FjLnBkZioqIC0gVGhpcyBzZXQgb2YgcGxvdHMgc3VtbWFyaXNlcyB0aGUgcmF3IG91dHB1dHMgZnJvbSB0aGUgc2VxdWVuY2luZyBydW4uIFRoZSBmaXJzdCBwYWdlIHNob3dzIHRoZSBhdmVyYWdlIGltYWdpbmcgaW50ZW5zaXR5IGZvciB0aGUgOTAlIHBlcmNlbnRpbGUgb2YgdGhlIGRhdGEgZm9yIGVhY2ggdGlsZSBvbiB0aGUgc2VxdWVuY2luZyBmbG93IGNlbGwuIFRoZSBzZWNvbmQgcGFnZSBzaG93cyB0aGUgbnVtYmVyIG9mIGNsdXN0ZXJzIChyZWFkcykgaW1hZ2VkIGJ5IHRoZSBzZXFldW5jZXIsIGFuZCB0aGUgbnVtYmVyIG9mIGNsdXN0ZXJzIHBhc3NpbmcgdGhlIG1hY2hpbmVzIGZpbHRlcmluZy4gVGhlIHRoaXJkIHBhZ2Ugc2hvd3MgdGhlIFFzY29yZSBieSBjeWNsZSBmb3IgYWxsIHJlYWRzLg0KICAgIA0KICAgICsgKipvdXRwdXQvbG9ncy9GQ0lEL0ZDSURfaW5kZXhfc3dpdGNoaW5nLnBkZioqIC0gVGhpcyBpcyBhIGhlYXRtYXAgb2YgdGhlIGFtb3VudCBvZiBpbmRleCBzd2l0Y2hpbmcgcGVyIGluZGV4IHNldCBhbmQgZmxvd2NlbGwgdXNlZC4gT24gdGhlIGRpYWdvbmFsIG9mIHRoZSBwbG90IGlzIHRoZSBpbmRleGVzIGFwcGxpZWQgdG8gdGhlIHNhbXBsZXMsIHdoaWxlIHRoZSBvdGhlciBzcXVhcmVzIG9uIHRoZSBncmlkIGRpc3BsYXkgaW5zdGFuY2VzIHdoZXJlIGVpdGhlciB0aGUgaTUgb3IgaTcgaW5kZXggaGFzIHN3aXRjaGVkIGNhdXNpbmcgdGhpcyByZWFkIHRvIGVuZCB1cCBpbiB0aGUgdW5kZXRlcm1pbmVkIHJlYWRzIGZpbGUuIFRoZSB0ZXh0IGFib3ZlIHRoZSBwbG90IGxpc3RzIHRoZSB0b3RhbCByZWFkcyBkZW11bHRpcGxleCBmcm9tIHRoYXQgZmxvd2NlbGwsIHRoZSBzd2l0Y2ggcmF0ZSAob25seSBvbmUgb2YgdGhlIGluZGV4ZXMgc3dpdGNoaW5nIGNhdXNpbmcgdGhlIHJlYWQgdG8gZW5kIHVwIGluIHRoZSB1bmRldGVybWluZWQgcmVhZHMgZmlsZSkgYXMgYSBwZXJjZW50YWdlLCB0aGUgY3Jvc3MtY29udGFtaW5hdGlvbiByYXRlIChib3RoIGluZGV4ZXMgc3dpdGNoaW5nIHRoZSByZWFkIGVuZGluZyB1cCBpbiBhbm90aGVyIHNhbXBsZSkgYXMgYSBwZXJjZW50YWdlLCBhbmQgdGhlIG51bWJlciBvZiAib3RoZXIgcmVhZHMiIHdoaWNoIHdlcmUgdGhvc2Ugd2hlcmUgbm8gYXBwbGllZCBpbmRleGVzIHdlcmUgZGV0ZWN0ZWQuIFRoZSBjcm9zcy1jb250YW1pbmF0aW9uIHJhdGUgaXMgY2FsY3VsYXRlZCBhcyB0aGUgc3F1YXJlIG9mIHRoZSBpbmRleCBzd2l0Y2hpbmcgcmF0ZSBhcyBwZXIgKGNvc3RlbGxvIGV0IGFsKSwgYW5kIHNob3VsZCBiZSBhIHJvdWdoIGd1aWRlIHRvIGRldGVybWluZSBhbiBhcHByb3ByaWF0ZSBBU1YgbWluaW11bSBhYnVuZGFuY2UgdGhyZXNob2xkIGZvciBmaWx0ZXJpbmcuIE5PVEU6IFRoaXMgcGxvdCBpcyBvbmx5IGNyZWF0ZWQgd2hlbiB1bmlxdWUgZHVhbCBpbmRleGVzIHdlcmUgdXNlZCBvbiB0aGUgc2FtcGxlLg0KDQogICAgKyAqKm91dHB1dC9sb2dzL0ZDSUQvRkNJRF9wcmVmaWx0X3F1YWxwbG90cy5wZGYqKiAtIFRoaXMgbXVsdGlwbG90IHN1bW1hcmlzZXMgdGhlIHJlYWQgcXVhbGl0eSBzY29yZXMgZm9yIHRoZSBmb3J3YXJkIGFuZCByZXZlcnNlIHJlYWRzLCBwcmUgZmlsdGVyaW5nLiBUaGVzZSBwbG90cyBjYW4gc2VydmUgYXMgYW4gaW5kaWNhdG9yIGZvciBhZGp1c3RpbmcgcmVhZCBmaWx0ZXJpbmcgcGFyYW1ldGVycyBvZiB0aGUgcGlwZWxpbmUuIFRoZSB0b3AgdHdvIHBsb3RzIHN1bW1hcmlzZSB0aGUgbWVhbiBxdWFsaXR5IHNjb3JlIGJ5IHBvc2l0aW9uIGZvciB0aGUgZm9yd2FyZCBhbmQgcmV2ZXJzZSByZWFkcyByZXNwZWN0aXZlbHkuIEZvciBpbGx1bWluYSBkYXRhLCB0aGVzZSB3aWxsIHN0YXJ0IHRvIGRlY3JlYXNlIHRvd2FyZHMgdGhlIGVuZCBvZiB0aGUgcmVhZHMsIHBhcnRpY3VsYXJseSBmb3IgdGhlIHJldmVyc2UgcmVhZHMuIFRoZSB0d28gYm90dG9tIHBsb3RzIHNob3cgdGhlIGN1bXVsYXRpdmUgZXhwZWN0ZWQgZXJyb3JzIGFsb25nIHRoZSByZWFkcywgd2l0aCBkaWZmZXJlbnQgY29sb3VyZWQgZG90cyBmb3IgZGlmZmVyZW50IHF1YW50aWxlcyBvZiB0aGUgcmVhZCBkYXRhIChpLmUuIGxvd2VyIDEwJSB0byB1cHBlciA5MCUpLiBUaGUgcmVkIGxpbmVzIHNob3cgdGhlIHBvdGVudGlhbCBtYXggZXhwZWN0ZXIgZXJyb3IgY3V0b2Zmcywgd2l0aCBhbGwgcmVhZHMgYWJvdmUgdGhlIHNldCBtYXhpbXVtIGV4cGVjdGVkIGVycm9yIGZpbHRlciBiZWlnbiByZW1vdmVkIChwYXJhbSByZWFkX21heF9lZSkuIEZvciBleGFtcGxlLCBpZiB0aGUgbG93ZXIgMTAlIHF1YW50aWxlIG9mIHJlYWRzIGdvZXMgYWJvdmUgdGhlIHJlZCBsaW5lIGZvciBtYXhFRT0xLCB5b3Ugd291bGQgZXhwZWN0IDEwJSBvZiB0aGUgcmVhZHMgdG8gYmUgcmVtb3ZlZCBpZiByZWFkX21heF9lZSB3YXMgc2V0IHRvIDEuIEFzIG1vcmUgZXJyb3JzIGNvbW1vbmx5IG9jY3VyIGluIHRoZSBlbmRzIG9mIHRoZSByZWFkLCBpZiB0aGVyZSBpcyBzdWZmaWNpZW50IG92ZXJsYXAgYmV0d2VlbiB0aGUgcmVhZHMgdG8gY292ZXIgdGhlIGxlbmd0aCBvZiB0aGUgYW1wbGljb24sIHRoZSByZWFkcyBjb3VsZCBpbnN0ZWFkIGJlIHRydW5jYXRlZCB0byBzbWFsbGVyIGxlbmd0aHMgdG8gcmVkdWNlIHRoZSBhbW91bnQgb2YgcmVhZHMgdGhhdCBjcm9zcyB0aGlzIG1pbmltdW0gZXhwZWN0ZWQgZXJyb3IgZmlsdGVyIHdoaWNoIHdvdWxkIHJldGFpbiBtb3JlIGRhdGEuIE5vdGUgdGhhdCB3aGVuIHRydW5jYXRpbmcgcmVhZHMgeW91IHNob3VsZCBhaW0gdG8gaGF2ZSBhdCBsZWFzdCAyMGJwIG9mIG92ZXJsYXAgdG8gZmFjaWxpdGF0ZSBmb3J3YXJkIGFuZCByZXZlcnNlIHJlYWQgbWVyZ2luZy4gDQogICAgDQogICAgKyAqKm91dHB1dC9sb2dzL0ZDSUQvRkNJRF9wb3N0ZmlsdF9xdWFscGxvdHMucGRmKiogLSBUaGlzIG11bHRpcGxvdCBzdW1tYXJpc2VzIHRoZSByZWFkIHF1YWxpdHkgc2NvcmVzIGZvciB0aGUgZm9yd2FyZCBhbmQgcmV2ZXJzZSByZWFkcywgcHJlIGZpbHRlcmluZy4gVGhlc2UgcGxvdHMgbGlzdCB0aGUgc2FtZSBpbmZvcm1hdGlvbiBhcyB0aGUgcHJlLWZpbHRlcmluZyBxdWFsaXR5IHBsb3RzLCBhbmQgc2hvdWxkIGJlIGNoZWNrZWQgdG8gZW5zdXJlIHRoYXQgdGhlIGZpbHRlcmluZyBoYXMgYmVlbiBjb3JyZWN0bHkgYXBwbGllZC4gaS5lLiwgaWYgcmVhZHMgd2VyZSB0cnVuY2F0ZWQgb3IgdHJpbW1lZCBvbiB0aGUgbGVmdCBvciByaWdodCAocGFyYW1zIHJlYWRfdHJ1bmNfbGVuZ3RoLCByZWFkX3RyaW1fbGVmdCwgcmVhZF90cmltX3JpZ2h0KSB0aGV5IHNob3VsZCBiZSBzaG9ydGVyIHRoZW4gdGhlIHByZS1maWx0ZXIgcGxvdHMsIGFuZCBpZiBhIG1heGltdW0gZXhwZWN0ZWQgZXJyb3IgZmlsdGVyIChwYXJhbSByZWFkX21heF9lZSkgd2FzIGFwcGxpZWQsIG5vbmUgb2YgdGhlIEVFIHF1YW50aWxlcyBzaG91bGQgYmUgYWJvdmUgdGhlIGNvcnJlc3BvbmRpbmcgcmVkIGxpbmUNCg0KICAgICsgKipvdXRwdXQvbG9ncy9GQ0lEL0ZDSURfcGNycHJpbWVyc19lcnJvcm1vZGVsLnBkZioqIC0gVGhlcmUgaXMgYSBzZXBhcmF0ZSBQREYgZm9yIHRoZSBmb3J3YXJkIGFuZCByZXZlcnNlIGVycm9yIG1vZGVscyBmb3IgZWFjaCBwcmltZXIgc2V0IGFuZCBmbG93IGNlbGwuIEVhY2ggcGxvdCBzdW1tYXJpc2VzIHRoZSBlcnJvciBtb2RlbCB1c2VkIGZvciBkYWRhMiB0aGF0IHdhcyBpbmZlcnJlZCBmcm9tIHRoZSBkYXRhIGZvciB0aGUgcmVzcGVjdGl2ZSBmbG93IGNlbGwuIFRoZSBlcnJvciByYXRlcyBmb3IgZWFjaCBwb3NzaWJsZSB0cmFuc2l0aW9uIChB4oaSQywgQeKGkkcsIGV0YykgYXJlIHNob3duIGluIGVhY2ggc3VicGxvdC4gVGhlIGRvdC1wb2ludHMgYXJlIHRoZSBlcnJvciByYXRlcyBvYnNlcnZlZCBpbiB0aGUgZGF0YSBmb3IgZWFjaCBxdWFsaXR5IHNjb3JlLiBUaGUgYmxhY2sgbGluZSBzaG93cyB0aGUgZXN0aW1hdGVkIGVycm9yIHJhdGVzIGZyb20gdGhlIG1hY2hpbmUtbGVhcm5pbmcgYWxnb3JpdGhtLiBUaGUgcmVkIGxpbmUgc2hvd3MgdGhlIGVycm9yIHJhdGVzIHRoYXQgd291bGQgYmUgZXhwZWN0ZWQgaWYgdGhlIFEtc2NvcmVzIGFzc2lnbmVkIGJ5IHRoZSBzZXF1ZW5jZXIgd2VyZSBjb21wbGV0ZWx5IGFjY3VyYXRlLiBUaGlzIHBsb3QgY2FuIGJlIG1vcmUgc3ViamVjdGl2ZSB0byBpbnRlcnByZXQsIGJ1dCBnZW5lcmFsbHkgeW91IHdhbnQgdG8gc2VlIHRoZSBlc3RpbWF0ZWQgZXJyb3IgcmF0ZXMgKGJsYWNrIGxpbmUpIGRlY3JlYXNlIGFzIHRoZSBxdWFsaXR5IHNjb3JlICh4IGF4aXMpIGluY3JlYXNlcywgaW4gYSByZWxhdGl2ZWx5IGxpbmVhciBmYXNoaW9uLiBNaW5vciBodW1wcyBpbiB0aGUgYmxhY2sgbGluZSBhcmUgbm8gcHJvYmxlbSwgYnV0IGEgdmVyeSBqYWdnZWQgbGluZSBtYXkgaW5kaWNhdGUgdGhhdCB0aGUgZXJyb3IgbW9kZWwgZGlkIG5vdCBmaXQgY29ycmVjdGx5LiBOb3RlOiBmb3IgTmV4dFNlcSBhbmQgTm92YVNlcSBkYXRhLCB0aGUgYmlubmVkIHF1YWxpdHkgc2NvcmVzIHByb3ZpZGVkIGJ5IHRoZSBzZXF1ZW5jZXIgY2FuIGNhdXNlIGxhcmdlIGh1bXBzIG9yIGRpcHMgaW4gdGhlIGVycm9yIG1vZGVsIGZpdC4gVGhpcyBpcyBnZW5lcmFsbHkgbm90IGEgYmlnIHByb2JsZW0sIHNlZSBbdGhpcyBnaXRodWIgaXNzdWVdKGh0dHBzOi8vZ2l0aHViLmNvbS9iZW5qam5lYi9kYWRhMi9pc3N1ZXMvMTMwNykgZm9yIGEgZGVlcGVyIGRpc2N1c3Npb24gb24gZml0dGluZyBlcnJvciBtb2RlbHMgZm9yIGJpbm5lZCBxdWFsaXR5IHNjb3Jlcy4NCg0KKiAqKldob2xlIGRhdGFzZXQgcXVhbGl0eSBjaGVja3M6KioNCiAgICArICoqb3V0cHV0L2xvZ3MvQVNWX2NsZWFudXBfc3VtbWFyeS5wZGYqKiAtIFRoaXMgcGxvdCBsaXN0cyB0aGUgYWJ1bmRhbmNlLCBhbmQgbnVtYmVyIG9mIHVuaXF1ZSBzZXF1ZW5jZSB2YXJpYW5jZSBpbmZlcnJlZCBmcm9tIGRhZGEyLCB0aGVpciBsZW5ndGhzLCBhbmQgd2hldGhlciB0aGV5IHdlcmUgcmV0YWluZWQgb3IgZmlsdGVyZWQgb3V0IGR1cmluZyB0aGUgQVNWIGZpbHRlcmluZyBzdGVwLiBHZW5lcmFsbHkgeW91IHNob3VsZCBzZWUgYSBsb3Qgb2YgdW5pcXVlIHNlcXVlbmNlcyBmaWx0ZXJlZCBvdXQgaW4gdGhpcyBzdGVwLCBidXQgdGhlIG1ham9yaXR5IG9mIHRoZSBhYnVuZGFuY2Ugc2hvdWxkIHJlbWFpbi4gDQoNCiAgICArICoqb3V0cHV0L2xvZ3MvQVNWX2NsZWFudXBfc3VtbWFyeS5jc3YqKiAtIFRoaXMgdGFibGUgbGlzdHMgdGhlIGluZGl2aWR1YWwgc2VxdWVuY2UgdmFyaWFudHMsIHRoZWlyIGFidWRuYW5jZSwgbGVuZ3RoIGFuZCB3aGV0aGVyIHRoZXkgd2VyZSByZXRhaW5lZCBvciBmaWx0ZXJlZCBvdXQgZHVyaW5nIHRoZSBBU1YgZmlsdGVyaW5nIHN0ZXAuIFRoaXMgdGFibGUgaXMgdXNlZnVsIGZvciBkZWVwZXIgaW52ZXN0aWdhdGlvbiB0byBlbnN1cmUgdGhhdCByZWFsIHNlcXVlbmNlcyB3ZXJlIG5vdCByZW1vdmVkIGluIGFueSBvZiB0aGUgQVNWIGZpbHRlcmluZyBzdGVwcy4NCg0KICAgICsgKipvdXRwdXQvbG9ncy90YXhvbm9taWNfYXNzaWdubWVudF9zdW1tYXJ5LnBkZioqIC0gVGhpcyBwbG90IHN1bW1hcmlzZXMgdGhlIGdlbmV0aWMgZGlzdGFuY2Ugb2YgdGhlIEFTVnMgdG8gdGhlIHJlZmVyZW5jZSBkYXRhYmFzZSAoZnJvbSBCTEFTVCB0b3AgaGl0IGlkZW50aXR5KSwgYW5kIHdoYXQgdGF4b25vbXkgd2FzIGFzc2lnbmVkIHRvIGVhY2guIFRoaXMgcGxvdCBnaXZlcyBhIGdvb2Qgb3ZlcnZpZXcgb2YgaG93IHdlbGwgdGhlIGFuYWx5c2VkIHNlcXVlbmNlcyBhcmUgcmVwcmVzZW50ZWQgaW4gdGhlIHJlZmVyZW5jZSBkYXRhYmFzZSwgYW5kIGhvdyBzdWNjZXNzZnVsIHRoZSB0YXhvbm9taWMgYXNzaWdubWVudCB3YXMuICANCg0KICAgICsgKipvdXRwdXQvbG9ncy90YXhvbm9taWNfYXNzaWdubWVudF9zdW1tYXJ5LmNzdioqIC0gVGhpcyB0YWJsZSBsaXN0cyB0aGUgaW5kaXZpZHVhbCBzZXF1ZW5jZSB2YXJpYW50cyBhbmQgdGhlaXIgYXNzaWduZWQgdGF4b25vbXkgYW5kIGNvbmZpZGVuY2Ugc2NvcmVzIHdpdGggSURUQVhBLiBUaGUgY29sdW1ucyB0byB0aGUgcmlnaHQgYWxzbyBpbmRpY2F0ZSB0aGUgQkxBU1QgdG9wIGhpdCBhbmQgdGhlaXIgZGlzdGFuY2UgdG8gdGhlIGNsb3Nlc3QgYmxhc3QgaGl0LiBUaGlzIHRhYmxlIGlzIHVzZWZ1bCBmb3IgZGVlcGVyIGludmVzdGlnYXRpb24gb2YgaG93IGRpZmZlcmVudCBzZXF1ZW5jZXMgd2VyZSBhc3NpZ25lZC4NCg0KICAgICsgKipvdXRwdXQvbG9ncy9yZWFkX3RyYWNrZXIucGRmKiogVGhpcyBwbG90IHN1bW1hcmlzZXMgdGhlIG51bWJlciBvZiByZWFkcyByZXRhaW5lZCB0aHJvdWdoIGFsbCBzdGVwcyBvZiB0aGUgcGlwZWxpbmUsIGFzIHdlbGwgYXMgaG93IG1hbnkgcmVhZHMgd2VyZSBjbGFzc2lmaWVkIHRvIGRpZmZlcmVudCB0YXhvbm9taWMgcmFua3MuIFRoaXMgcGxvdCBwcm92aWRlcyBhIHVzZWZ1bCBvdmVydmlldyBvZiBhbGwgcGlwZWxpbmUgc3RlcHMgdG8gZGV0ZXJtaW5lIGlmIHRvbyBtYW55IHJlYWRzIGFyZSBiZWluZyBsb3N0IGF0IGEgY2VydGFpbiBzdGVwDQoNCiAgICArICoqb3V0cHV0L2xvZ3MvcmVhZF90cmFja2VyLmNzdioqIC0gU2ltaWxhciB0byB0aGUgYWJvdmUgcGxvdCwgdGhpcyB0YWJsZSBzdW1tYXJpc2VzIHRoZSBudW1iZXIgb2YgcmVhZHMgcmV0YWluZWQgdGhyb3VnaCBhbGwgc3RlcHMgb2YgdGhlIHBpcGVsaW5lLCBhcyB3ZWxsIGFzIGhvdyBtYW55IHJlYWRzIHdlcmUgY2xhc3NpZmllZCB0byBkaWZmZXJlbnQgdGF4b25vbWljIHJhbmtzLg0KDQogICAgKyAqKm91dHB1dC9sb2dzL2FjY3VtdWxhdGlvbl9jdXJ2ZS5wZGYqKiAtIFRoaXMgcGxvdCBzaG93cyB0aGUgYWNjdW11bGF0aW9uIG9mIEFTVnMgd2l0aGluIGVhY2ggc2FtcGxlIGFzIHNlcXVlbmNpbmcgZGVwdGggaW5jcmVhc2VzLiBUaGUgY3VydmVzIHNob3VsZCBzdGFydCB0byBwbGF0ZWF1IGlmIGFkZXF1YXRlIHNlcXVlbmNpbmcgZGVwdGggaGFzIGJlZW4gYWNoaWV2ZWQgdG8gY2hhcmFjdGVyaXNlIHRoZSBjb21tdW5pdHkuIElmIHRoZSBjdXJ2ZXMgaGF2ZSBub3QgcmVhY2hlZCBhIHBsYXRlYXUgaXQgbWF5IGluZGljYXRlIHRoYXQgdGhlc2Ugc2FtcGxlcyBzaG91bGQgYmUgc2VxdWVuY2VkIGFnYWluIHNvIHRoYXQgYWxsIHRheGEgYXJlIGNhcHR1cmVkIGluIHRoZSBkYXRhLg0KDQo=