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 an example pipeline for insect COI sequencing.
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:
- 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
- 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 MiSeq run
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, as the miseq does not put
indexes in fasta headers by default which is required for the index
swtiching calculation.
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
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:
# Download files from zenodo
download_zenodo(
doi = "10.5281/zenodo.7655352",
path = "reference"
)
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.
For this workflow a single primer set was used across all samples.
For multiple primers see the options in the General
introduction to the pipeRline workflow
# 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 out sample CSV for use in pipeline
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.
For this workflow a single primer set was used across all samples.
For multiple primers see the options in the General
introduction to the pipeRline workflow
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
Create parameters file
The pipeline also requires a locus parameters file which lists
important information about the target barcodes, as well as the PHMM
model used to clean the loci, as well as the different reference
databases that are to be used for taxonomic assignment.
If multiple reference databases are to be used iteratively for
assignment, they should be split with a semicolon, and in the order they
are to be used for assignment.
The below code generates the loci_params.csv file, however this can
also be done in excel.
# 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),
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 = "Metazoa",
target_phylum = "Arthropoda",
target_class = "Insecta",
target_order = "Diptera",
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),
# General pipeline parameters
threads = 1
)
# Write out the parameters file
write_csv(params, "sample_data/loci_params.csv")
Run the pipeline
Now that the sample data and parameters file is ready, its time to
run the pipeline!
Run the targets pipeline
tar_make()
Results
See the general
introduction vignette for an in-depth explanation of the results and
quality control outputs
LS0tDQp0aXRsZTogIlRlcGhyaXRpZCBtZXRhYmFyY29kaW5nIHdvcmtzaG9wIg0Kc3VidGl0bGU6ICJCaW9pbmZvcm1hdGljIGFuYWx5c2lzIg0KYXV0aG9yOiAiQWxleGFuZGVyIE0uIFBpcGVyIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICANCiAgaHRtbF9kb2N1bWVudDoNCiAgICBoaWdobGlnaHRlcjogbnVsbA0KICAgIHRoZW1lOiAiZmxhdGx5Ig0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IA0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIGRmX3ByaW50OiBwYWdlZCAgICANCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIEtuaXRyIGdsb2JhbCBzZXR1cCAtIGNoYW5nZSBldmFsIHRvIHRydWUgdG8gcnVuIGNvZGUNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHRhcmdldHMpDQpsaWJyYXJ5KHRhcmNoZXR5cGVzKQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsZXJyb3I9RkFMU0UsIGZpZy5zaG93ID0gImhvbGQiLCBmaWcua2VlcCA9ICJhbGwiKQ0Kb3B0c19jaHVuayRzZXQoZGV2ID0gJ3BuZycpDQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NCg0KVGhpcyBtZXRhYmFyY29kaW5nIHBpcGVsaW5lIGlzIGJhc2VkIGFyb3VuZCB0aGUgW3RhcmdldHNdKGh0dHBzOi8vYm9va3Mucm9wZW5zY2kub3JnL3RhcmdldHMvKSBwYWNrYWdlLCB3aGljaCBpcyBhIE1ha2UtbGlrZSBwaXBlbGluZSB0b29sIGZvciBSLiBUaGUgYmVuZWZpdCBvZiB0aGlzIGlzIHRoYXQgYWxsIHRoZSBjb2RlIGlzIGF1dG9tYXRpY2FsbHkgcnVuLCBhbmQgdGhlIHBpcGVsaW5lIHNraXBzIGNvc3RseSBydW50aW1lIGZvciB0YXNrcyB0aGF0IGFyZSBhbHJlYWR5IHVwIHRvIGRhdGUuDQoNClRoaXMgcGFnZSBsaXN0cyBhbiBleGFtcGxlIHBpcGVsaW5lIGZvciBpbnNlY3QgQ09JIHNlcXVlbmNpbmcuDQoNCiMgQ2xvbmUgdGhlIHBpcGVSbGluZSBnaXRodWIgcmVwb3NpdG9yeQ0KDQpUaGUgZmlyc3Qgc3RlcCBpcyB0byBjbG9uZSB0aGlzIGdpdGh1YiByZXBvc2l0b3J5LCB3aGljaCBjb250YWlucyB0aGUgcmVxdWlyZWQgY29kZSBhbmQgZGlyZWN0b3J5IHN0cnVjdHVyZSB0byBydW4gdGhlIHBpcGVsaW5lLiBUbyBkbyB0aGlzLCB5b3Ugd2lsbCBuZWVkIFtHaXRdKGh0dHBzOi8vZ2l0LXNjbS5jb20vKSBpbnN0YWxsZWQgb24geW91ciBjb21wdXRlci4gSWYgeW91IGFyZSBydW5uaW5nIHRoZSBwaXBlbGluZSBpbiBSc3R1ZGlvLCBpdCBpcyBiZXN0IHRvIGNyZWF0ZSBhIG5ldyBwcm9qZWN0IGZyb20gdGhlIGdpdGh1YiByZXBvc2l0b3J5LiBUaGlzIGNhbiBiZSBkb25lIGJ5IGdvaW5nICoqZmlsZSA+IG5ldyBwcm9qZWN0ID4gdmVyc2lvbiBjb250cm9sID4gZ2l0KiogdGhlbiBhZGRpbmcgaHR0cHM6Ly9naXRodWIuY29tL2FsZXhwaXBlci9waXBlcmxpbmUuZ2l0IHRoZW4gY2hhbmdlIHRoZSBuYW1lIG9mIHRoZSBwcm9qZWN0IHRvIHdoYXRldmVyIHlvdSBhcmUgd29ya2luZyB3aXRoLiANCg0KQWx0ZXJuYXRpdmVseSwgdGhlIHJlcG9zaXRvcnkgY2FuIGJlIGNsb25lZCB1c2luZyB0aGUgY29tbWFuZCBsaW5lLCBjaGFuZ2UgdGhlICdmb2xkZXItbmFtZScgdG8gdGhlIGRlc2lyZWQgbmFtZQ0KYGBge2Jhc2h9DQojIENoYW5nZSBpbnRvIHRoZSBtYWluIGRpcmVjdG9yeSB5b3Ugd2lzaCB0byBtYWtlIHRoZSBwcm9qZWN0IGluDQpjZCBtZXRhYmFyY29kaW5nDQoNCiMgQ2xvbmUgdGhlIHJlcG9zaXRvcnkNCmdpdCBjbG9uZSBodHRwczovL2dpdGh1Yi5jb20vYWxleHBpcGVyL3BpcGVybGluZS5naXQgZm9sZGVyLW5hbWUNCmBgYA0KDQojIyBVcGRhdGluZyB0aGUgcGlwZWxpbmUNCg0KVG8gdXBkYXRlIHRvIHRoZSBsYXRlc3QgdmVyc2lvbiBvZiB0aGUgcGlwZWxpbmUsIHJ1biB0aGUgYmVsb3cgY29kZSBpbiB0aGUgdGVybWluYWwuDQoNCmBgYHtiYXNofQ0KZ2l0IHB1bGwNCmBgYA0KDQoNCiMgUHJpb3IgdG8gYW5hbHlzaXMNClRoZSBQaXBlUmxpbmUgd29ya2Zsb3cgYXNzdW1lcyB0aGF0IHlvdXIgc2VxdWVuY2luZyBkYXRhIG1lZXRzIGNlcnRhaW4gY3JpdGVyaWE6DQoNCjEuIFNhbXBsZXMgaGF2ZSBiZWVuIGRlbXVsdGlwbGV4ZWQsIGkuZS4gc3BsaXQgaW50byBpbmRpdmlkdWFsIHBlci1zYW1wbGUgZmFzdHEgZmlsZXMuIElmIHlvdSB3YW50IHRoZSBwaXBlbGluZSB0byBjYWxjdWxhdGUgdGhlIGluZGV4LXN3aXRjaGluZyByYXRlLCB0aGUgZmFzdHEgZmlsZXMgbmVlZCB0byBiZSByZS1kZW11bHRpcGxleGVkIGFzIHRoZSBtaXNlcSBkb2VzIG5vdCBwdXQgaW5kZXhlcyBpbiBmYXN0YSBoZWFkZXJzIGJ5IGRlZmF1bHQNCjIuIEZvciBwYWlyZWQtZW5kIHNlcXVlbmNpbmcgZGF0YSwgdGhlIGZvcndhcmQgYW5kIHJldmVyc2UgcmVhZHMgYXJlIGluIHNlcGFyYXRlIGZpbGVzIChpZS4gbm90IGludGVybGVhdmVkKSB3aXRoIHJlYWRzIGFycmFuZ2VkIGluIG1hdGNoZWQgb3JkZXIuDQoNClRoZSBvdXRwdXQgZGlyZWN0b3J5IHNob3VsZCBiZSB1bmlxdWUgZm9yIGVhY2ggc2VxdWVuY2luZyBydW4sIG5hbWVkIGFzIHRoZSBmbG93Y2VsbCBpZCwgd2l0aGluIGEgZGlyZWN0b3J5IGNhbGxlZCBkYXRhDQoNCkZvciBleGFtcGxlOg0KDQogICAgcm9vdC8NCiAgICAgIOKUnOKUgOKUgCBkYXRhLw0KICAgICAgICAg4pSc4pSA4pSAIENKTDdELw0KICAgICAgICAgDQpZb3Ugd2lsbCBhbHNvIG5lZWQgQkxBU1QrIGluc3RhbGxlZCBvbiB5b3VyIGNvbXB1dGVyLCBpdCBjYW4gYmUgZG93bmxvYWRlZCBmcm9tIHRoZSBbTkNCSSB3ZWJzaXRlXShodHRwczovL2JsYXN0Lm5jYmkubmxtLm5paC5nb3YvQmxhc3QuY2dpP1BBR0VfVFlQRT1CbGFzdERvY3MmRE9DX1RZUEU9RG93bmxvYWQpIA0KDQojIERlbXVsdGlwbGV4IE1pU2VxIHJ1bg0KDQpGb3IgdGhpcyB3b3JrZmxvdyB0byBydW4sIHdlIHdpbGwgbmVlZCBzb21lIHNlcXVlbmNpbmcgcnVucyB0byB3b3JrIHdpdGguIElmIHlvdSBhcmUgd29ya2luZyB3aXRoIE1pU2VxIGRhdGEsIGl0IGlzIHJlY29tbWVuZGVkIHRoYXQgdGhlIGRhdGEgaXMgZGVtdWx0aXBsZXhlZCBhZ2FpbiB1c2luZyBiY2wyZmFzdHEsIGFzIHRoZSBtaXNlcSBkb2VzIG5vdCBwdXQgaW5kZXhlcyBpbiBmYXN0YSBoZWFkZXJzIGJ5IGRlZmF1bHQgd2hpY2ggaXMgcmVxdWlyZWQgZm9yIHRoZSBpbmRleCBzd3RpY2hpbmcgY2FsY3VsYXRpb24uDQoNClRoZSBiZWxvdyBjb2RlIGlzIHdyaXR0ZW4gZm9yIHRoZSBBZ3JpY3VsdHVyZSBWaWN0b3JpYSBCQVNDIHNlcnZlciwgYW5kIHRoZSBsb2NhdGlvbnMgd2lsbCBiZSBkaWZmZXJlbnQgaWYgeW91IGFyZSB1c2luZyBhIGRpZmZlcmVudCBIUEMgY2x1c3Rlci4NCg0KYGBge2Jhc2ggZGVtdWx0aXBsZXggMSBtaXNtYXRjaH0NCiNsb2FkIG1vZHVsZQ0KbW9kdWxlIGxvYWQgYmNsMmZhc3RxMi8yLjIwLjAtZm9zcy0yMDE4Yg0KDQojcmFpc2UgYW1vdW50IG9mIGF2YWlsYWJsZSBmaWxlIGhhbmRsZXMNCnVsaW1pdCAtbiA0MDAwDQoNCiMjI1J1bjENCg0KI1NldCB1cCBpbnB1dCBhbmQgb3V0cHV0cw0KaW5wdXRkaXI9L2dyb3VwL3NlcXVlbmNpbmcvMjEwMjE5X00wMzYzM18wNDg5XzAwMDAwMDAwMC1KRFlHMyAjQ0hBTkdFIFRPIFlPVVIgU0VRIFJVTg0Kb3V0cHV0ZGlyPS9ncm91cC9wYXRob2dlbnMvSUFXUy9Qcm9qZWN0cy9NZXRhYmFyY29kaW5nL2Ryb3Nfc3VydmVpbGxhbmNlL2RhdGEvSkRZRzMgI0NIQU5HRSBUTyBZT1VSIERBVEEgRk9MREVSIFJVTg0Kc2FtcGxlc2hlZXQ9L2dyb3VwL3BhdGhvZ2Vucy9JQVdTL1Byb2plY3RzL01ldGFiYXJjb2RpbmcvZHJvc19zdXJ2ZWlsbGFuY2UvU2FtcGxlU2hlZXRfSkRZRzMuY3N2ICNDSEFOR0UgVE8gWU9VUiBTQU1QTEVTSEVFVA0KDQojIGNvbnZlcnQgc2FtcGxlc2hlZXQgdG8gdW5peCBmb3JtYXQNCmRvczJ1bml4ICRzYW1wbGVzaGVldA0KDQojRGVtdWx0aXBsZXgNCmJjbDJmYXN0cSAtcCAxMiAtLXJ1bmZvbGRlci1kaXIgJGlucHV0ZGlyIFwNCi0tb3V0cHV0LWRpciAkb3V0cHV0ZGlyIFwNCi0tc2FtcGxlLXNoZWV0ICRzYW1wbGVzaGVldCBcDQotLW5vLWxhbmUtc3BsaXR0aW5nIC0tYmFyY29kZS1taXNtYXRjaGVzIDENCg0KIyBDb3B5IG90aGVyIG5lY2Vzc2FyeSBmaWxlcyBhbmQgbW92ZSBmYXN0cXMNCmNkICRvdXRwdXRkaXINCmNwIC1yICRpbnB1dGRpci9JbnRlck9wICRvdXRwdXRkaXINCmNwICRpbnB1dGRpci9SdW5JbmZvLnhtbCAkb3V0cHV0ZGlyDQpjcCAkaW5wdXRkaXIvW1JyXXVuUGFyYW1ldGVycy54bWwgJG91dHB1dGRpcg0KY3AgJHNhbXBsZXNoZWV0ICRvdXRwdXRkaXINCm12ICoqLyouZmFzdHEuZ3ogJG91dHB1dGRpcg0KDQojIEFwcGVuZCBmY2lkIHRvIHN0YXJ0IG9mIHNhbXBsZSBuYW1lcyBpZiBtaXNzaW5nDQpmY2lkPSQoZWNobyAkaW5wdXRkaXIgfCBzZWQgJ3MvXi4qLS8vJykNCmZvciBpIGluICouZmFzdHEuZ3o7IGRvDQogIGlmICEgW1sgJGkgPT0gJGZjaWQqIF1dOyB0aGVuDQogIG5ldz0kKGVjaG8gJHtmY2lkfSAke2l9KSAjYXBwZW5kIHRvZ2V0aGVyDQogIG5ldz0kKGVjaG8gJHtuZXcvLyAvX30pICNyZW1vdmUgYW55IHdoaXRlIHNwYWNlDQogIG12IC12ICIkaSIgIiRuZXciDQogIGZpDQpkb25lDQoNCmBgYA0KDQojIEluc3RhbGwgYW5kIGxvYWQgUiBwYWNrYWdlcyBhbmQgc2V0dXAgZGlyZWN0b3JpZXMNCg0KVGhpcyBwaXBlbGluZSBkZXBlbmRzIG9uIGEgbnVtYmVyIG9mIG90aGVyIFIgcGFja2FnZXMgd2hpY2ggdGhpcyBzdGVwIHdpbGwgaW5zdGFsbC4gVGhlIHZlcnNpb25zIG9mIHRoZXNlIHBhY2thZ2VzIGFyZSBtYW5hZ2VkIHVzaW5nIFtyZW52XShodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL3JlbnYvYXJ0aWNsZXMvcmVudi5odG1sKSB0byBlbnN1cmUgdGhleSBtYXRjaCB0aGUgdmVyc2lvbnMgdGhlIHBpcGVsaW5lIHdhcyBkZXZlbG9wZWQgb24uIFRoZSBmaXJzdCB0aW1lIGluc3RhbGxpbmcgcGFja2FnZXMgbWF5IHRha2Ugc29tZSB0aW1lLCBidXQgdGhleSBzaG91bGQgYmUgcXVpY2sgdG8gbG9hZCBmb3IgYW55IGZ1dHVyZSBydW5zLiANCg0KYGBge3IgTWFudWFsIGluc3RhbGx9IA0KIyBMb2FkIHRoZSB0YXJnZXRzIGFuZCByZW52IHBhY2thZ2VzDQpsaWJyYXJ5KHRhcmdldHMpDQpsaWJyYXJ5KHRhcmNoZXR5cGVzKQ0KDQojIExvYWQgYWxsIHBhY2thZ2VzIHVzaW5nIHJlbnY6OnJlc3RvcmUoKSBhbmQgc291cmNlIHBhY2thZ2UgbGlzdA0KcmVudjo6cmVzdG9yZSgpDQpzb3VyY2UoIl90YXJnZXRzX3BhY2thZ2VzLlIiKQ0KDQojIFNvdXJjZSBhbmNpbGxhcnkgZnVuY3Rpb25zDQpzb3VyY2UoIlIvZnVuY3Rpb25zLlIiKQ0Kc291cmNlKCJSL3RoZW1lcy5SIikNCmBgYA0KDQojIFJlZmVyZW5jZSBkYXRhYmFzZXMgDQoNClRoZSBwaXBlUmxpbmUgd29ya2Zsb3cgdXNlcyB0aGUgW0lEVEFYQV0oaHR0cHM6Ly9taWNyb2Jpb21lam91cm5hbC5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L3M0MDE2OC0wMTgtMDUyMS01KSBhbmQgQkxBU1Qgc29mdHdhcmUgdG8gYXNzaWduIHRheG9ub215IHRvIHRoZSBzZXF1ZW5jZSByZWFkcy4gVGhlc2UgcmVxdWlyZSBhIHByZS10cmFpbmVkIElEVEFYQSBtb2RlbCwgYW5kIGEgZmFzdGEgZmlsZSB3aXRoIGhlaXJhcmNoaWFsIHRheG9ub215LiBGb3IgaW5zZWN0cywgdGhlc2UgDQoNCiMjIERvd25sb2FkIHJlZmVyZW5jZSBkYXRhYmFzZQ0KDQpSZWZlcmVuY2UgZGF0YWJhc2VzIGZvciBpbnNlY3RzIGFuZCBhcmFjaG5pZHMgaGF2ZSBiZWVuIGhvc3RlZCBvbiBbWmVub2RvXShodHRwczovL3plbm9kby5vcmcvcmVjb3JkLzc2NTUzNTIjLllfTGdzSFpCei1nKSwgZWl0aGVyIGRvd25sb2FkIHRoZW0gbWFudWFsbHksIG9yIHdpdGggUiBiZWxvdzoNCg0KYGBge3J9DQojIERvd25sb2FkIGZpbGVzIGZyb20gemVub2RvDQpkb3dubG9hZF96ZW5vZG8oDQogIGRvaSA9ICIxMC41MjgxL3plbm9kby43NjU1MzUyIiwNCiAgcGF0aCA9ICJyZWZlcmVuY2UiDQopDQpgYGANCg0KDQojIENyZWF0ZSBzYW1wbGUgdHJhY2tpbmcgc2hlZXQgIA0KDQpJbiBvcmRlciB0byB0cmFjayBzYW1wbGVzIGFuZCByZWxldmFudCBRQyBzdGF0aXN0aWNzIHRocm91Z2hvdXQgdGhlIG1ldGFiYXJjb2RpbmcgcGlwZWxpbmUsIHdlIHdpbGwgZmlyc3QgY3JlYXRlIGEgbmV3IHNhbXBsZSB0cmFja2luZyBzaGVldCBmcm9tIG91ciBpbnB1dCBpbGx1bWluYSBzYW1wbGVzaGVldHMuIFRoaXMgZnVuY3Rpb24gcmVxdWlyZXMgYm90aCB0aGUgU2FtcGxlU2hlZXQuY3N2IHVzZWQgZm9yIHRoZSBzZXF1ZW5jaW5nIHJ1biwgYW5kIHRoZSBydW5QYXJhbWV0ZXJzLnhtbCwgYm90aCBvZiB3aGljaCBzaG91bGQgaGF2ZSBiZWVuIGF1dG9tYXRpY2FsbHkgb2J0YWluZWQgZnJvbSB0aGUgZGVtdWx0aXBsZXhlZCBzZXF1ZW5jaW5nIHJ1biBmb2xkZXIgaW4gdGhlIGJhc2ggc3RlcCBhYm92ZQ0KDQpgYGB7ciBjcmVhdGUgc2FtcGxlc2hlZXR9DQpydW5zIDwtIGRpcigiZGF0YS8iKSAjRmluZCBhbGwgZGlyZWN0b3JpZXMgd2l0aGluIGRhdGENClNhbXBsZVNoZWV0IDwtIGxpc3QuZmlsZXMocGFzdGUwKCJkYXRhLyIsIHJ1bnMpLCBwYXR0ZXJuPSAiU2FtcGxlU2hlZXQiLCBmdWxsLm5hbWVzID0gVFJVRSkNCnJ1blBhcmFtZXRlcnMgPC0gbGlzdC5maWxlcyhwYXN0ZTAoImRhdGEvIiwgcnVucyksIHBhdHRlcm49ICJbUnJddW5QYXJhbWV0ZXJzLnhtbCIsIGZ1bGwubmFtZXMgPSBUUlVFKQ0KDQojIENyZWF0ZSBzYW1wbGVzaGVldCBjb250YWluaW5nIHNhbXBsZXMgYW5kIHJ1biBwYXJhbWV0ZXJzIGZvciBhbGwgcnVucw0Kc2FtZGYgPC0gY3JlYXRlX3NhbXBsZXNoZWV0KFNhbXBsZVNoZWV0ID0gU2FtcGxlU2hlZXQsIHJ1blBhcmFtZXRlcnMgPSBydW5QYXJhbWV0ZXJzLCB0ZW1wbGF0ZSA9ICJWNCIpICU+JQ0KICBkaXN0aW5jdCgpDQoNCiMgQ2hlY2sgdGhhdCBzYW1wbGVfaWRzIGNvbnRhaW4gZmNpZCwgaWYgbm90OyBhdHRhdGNoDQpzYW1kZiA8LSBzYW1kZiAlPiUNCiAgbXV0YXRlKHNhbXBsZV9pZCA9IGNhc2Vfd2hlbigNCiAgICAhc3RyX2RldGVjdChzYW1wbGVfaWQsIGZjaWQpIH4gcGFzdGUwKGZjaWQsIl8iLHNhbXBsZV9pZCksDQogICAgVFJVRSB+IHNhbXBsZV9pZA0KICApKQ0KDQojIENoZWNrIHRoYXQgc2FtcGxlcyBtYXRjaCBzYW1wbGVzaGVldA0KZmFzdHFGcyA8LSBwdXJycjo6bWFwKGxpc3QuZGlycygiZGF0YSIsIHJlY3Vyc2l2ZT1GQUxTRSksDQogICAgICAgICAgICAgICAgICAgICAgbGlzdC5maWxlcywgcGF0dGVybj0iX1IxXyIsIGZ1bGwubmFtZXMgPSBUUlVFKSAlPiUNCiAgdW5saXN0KCkgJT4lDQogIHN0cl9yZW1vdmUocGF0dGVybiA9ICJeKC4qKVxcLyIpICU+JQ0KICBzdHJfcmVtb3ZlKHBhdHRlcm4gPSAiKD86Lig/IV9TKSkrJCIpDQoNCiMgRmlsdGVyIHVuZGV0ZXJtaW5lZCByZWFkcyBmcm9tIHNhbXBsZSBzaGVldA0KZmFzdHFGcyA8LSBmYXN0cUZzWyFzdHJfZGV0ZWN0KGZhc3RxRnMsICJVbmRldGVybWluZWQiKV0NCg0KIyBDaGVjayBmb3IgZmFzdHEgZmlsZXMgdGhhdCBhcmUgbWlzc2luZyBmcm9tIHNhbXBsZXNoZWV0DQppZiAobGVuZ3RoKHNldGRpZmYoZmFzdHFGcywgc2FtZGYkc2FtcGxlX2lkKSkgPiAwKSB7d2FybmluZygiVGhlIGZhc3RxIGZpbGUvczogIiwgc2V0ZGlmZihmYXN0cUZzLCBzYW1kZiRzYW1wbGVfaWQpLCAiIGFyZSBub3QgaW4gdGhlIHNhbXBsZSBzaGVldCIpIH0NCg0KIyBDaGVjayBmb3Igc2FtcGxlX2lkcyB0aGF0IGRvbnQgaGF2ZSBhIGNvcnJlc3BvbmRpbmcgZmFzdHEgZmlsZQ0KaWYgKGxlbmd0aChzZXRkaWZmKHNhbWRmJHNhbXBsZV9pZCwgZmFzdHFGcykpID4gMCkgew0KICB3YXJuaW5nKHBhc3RlMCgiVGhlIGZhc3RxIGZpbGU6ICIsDQogICAgICAgICAgICAgICAgIHNldGRpZmYoc2FtZGYkc2FtcGxlX2lkLCBmYXN0cUZzKSwNCiAgICAgICAgICAgICAgICAgIiBpcyBtaXNzaW5nLCBkcm9wcGluZyBmcm9tIHNhbXBsZXNoZWV0IFxuIikpIA0KICBzYW1kZiA8LSBzYW1kZiAlPiUNCiAgICBmaWx0ZXIoIXNhbXBsZV9pZCAlaW4lIHNldGRpZmYoc2FtZGYkc2FtcGxlX2lkLCBmYXN0cUZzKSkNCn0NCg0KIyBXcml0ZSBvdXQgc2FtcGxlIHRyYWNraW5nIHNoZWV0DQp3cml0ZV9jc3Yoc2FtZGYsICJzYW1wbGVfZGF0YS9TYW1wbGVfaW5mby5jc3YiKQ0KYGBgDQoNCiMgQWRkIFBDUiBwcmltZXJzIHRvIHNhbXBsZSBzaGVldCANCg0KVGhpcyBjYW4gZWl0aGVyIGJlIGRvbmUgbWFudWFsbHkgYnkgZWRpdGluZyB0aGUgc2FtcGxlX2RhdGEvU2FtcGxlX2luZm8uY3N2IGZpbGUsIG9yIGl0IGNhbiBiZSBkb25lIGluIFIgYXMgYmVsb3cuDQoNCkZvciB0aGlzIHdvcmtmbG93IGEgc2luZ2xlIHByaW1lciBzZXQgd2FzIHVzZWQgYWNyb3NzIGFsbCBzYW1wbGVzLiBGb3IgbXVsdGlwbGUgcHJpbWVycyBzZWUgdGhlIG9wdGlvbnMgaW4gdGhlIFtHZW5lcmFsIGludHJvZHVjdGlvbiB0byB0aGUgcGlwZVJsaW5lIHdvcmtmbG93XShodHRwczovL2FsZXhwaXBlci5naXRodWIuaW8vcGlwZXJsaW5lL3ZpZ25ldHRlcy9nZW5lcmFsLmh0bWwpDQoNCmBgYHtSfQ0KIyBBZGQgUENSIHByaW1lcnMgdG8gc2FtcGxlIHNoZWV0DQpzYW1kZiA8LSBzYW1kZiAlPiUNCiAgbXV0YXRlKA0KICAgIHBjcl9wcmltZXJzID0gImZ3aEYyLWZ3aFIybkRhYztFSUYzTG1pbmlGNC1FSUYzbG1pbmlSNCIsDQogICAgZm9yX3ByaW1lcl9zZXEgPSAiR0dEQUNXR0dXVEdBQUNXR1RXVEFZQ0NIQ0M7R0FUR0NHWUNHVFRBVEdDWUdBVEdDIiwNCiAgICByZXZfcHJpbWVyX3NlcSA9ICJHVFJBVFdHQ0hDQ0lHQ1RBQURBQ0hHRztUVFJBQVlBQ1RUQ1lBUkFUQ1JDQyINCiAgICApDQoNCiNXcml0ZSBvdXQgc2FtcGxlIENTViBmb3IgdXNlIGluIHBpcGVsaW5lDQp3cml0ZV9jc3Yoc2FtZGYsICJzYW1wbGVfZGF0YS9TYW1wbGVfaW5mby5jc3YiKQ0KYGBgDQoNCiMgQ3JlYXRlIHBhcmFtZXRlcnMgZmlsZSANCg0KVGhlIHBhcmFtZXRlcnMgZmlsZSB0YWJsZSB0aGUgcmVzcGVjdGl2ZSB0YXJnZXQgZ2VuZSwgcmVmZXJlbmNlIGRhdGFiYXNlcywgYW5kIGZpbHRlcmluZyBwYXJhbWV0ZXJzIGZvciBlYWNoIHByaW1lciBzZXQgdXNlZCB0byBhbXBsaWZ5IHRoZSBzYW1wbGVzLiBBcyB0aGUgcGNyX3ByaW1lcnMgY29sdW1uIGlzIHVzZWQgaW4gdGhlIHBpcGVsaW5lIHRvIG1hdGNoIHRoZSBwYXJhbWV0ZXJzIHRvIHRoZSByZXNwZWN0aXZlIHNhbXBsZSwgaXQgaXMgY3JpdGljYWwgdGhhdCB0aGUgcHJpbWVyIG5hbWVzIG1hdGNoIHRob3NlIHNldCBpbiB0aGUgcHJldmlvdXMgc3RlcC4NCg0KRm9yIHRoaXMgd29ya2Zsb3cgYSBzaW5nbGUgcHJpbWVyIHNldCB3YXMgdXNlZCBhY3Jvc3MgYWxsIHNhbXBsZXMuIEZvciBtdWx0aXBsZSBwcmltZXJzIHNlZSB0aGUgb3B0aW9ucyBpbiB0aGUgW0dlbmVyYWwgaW50cm9kdWN0aW9uIHRvIHRoZSBwaXBlUmxpbmUgd29ya2Zsb3ddKGh0dHBzOi8vYWxleHBpcGVyLmdpdGh1Yi5pby9waXBlcmxpbmUvdmlnbmV0dGVzL2dlbmVyYWwuaHRtbCkNCg0KKipQYXJhbWV0ZXIgb3B0aW9ucyoqDQoNCiogKipQcmltZXIgcGFyYW1ldGVyczoqKg0KICAgICsgKipwY3JfcHJpbWVycyoqIC0gTmFtZSBvZiBQQ1IgcHJpbWVycyAtIG11c3QgbWF0Y2ggc2FtZGYgZmlsZQ0KICAgICsgKip0YXJnZXRfZ2VuZSoqIC0gTmFtZSBvZiB0YXJnZXQgZ2VuZQ0KICAgICsgKiptYXhfcHJpbWVyX21pc21hdGNoKiogLSBIb3cgbXVjaCBtaXNtYXRjaCB0byBhbGxvdyB3aGVuIGRldGVjdGluZyBwcmltZXIgc2VxdWVuY2VzDQoNCiogKipSZWFkIGZpbHRlcmluZzoqKg0KICAgICsgKipyZWFkX21pbl9sZW5ndGgqKiAtIE1pbmltdW0gbGVuZ3RoIG9mIHByaW1lciB0cmltbWVkIHJlYWRzDQogICAgKyAqKnJlYWRfbWF4X2xlbmd0aCoqIC0gTWF4aW11bSBsZW5ndGggb2YgcHJpbWVyIHRyaW1tZWQgcmVhZHMNCiAgICArICoqcmVhZF9tYXhfZWUqKiAtIE1heGltdW0gZXhwZWN0ZWQgZXJyb3JzIG9mIHByaW1lciB0cmltbWVkIHJlYWRzDQogICAgKyAqKnJlYWRfdHJ1bmNfbGVuZ3RoKiogLSBMZW5ndGggdG8gY3V0IGFsbCBsb25nZXIgcmVhZHMgdG8NCiAgICArICoqcmVhZF90cmltX2xlZnQqKiAtIFJlbW92ZSB0aGlzIG1hbnkgYnAgZnJvbSBsZWZ0IHNpZGUgb2YgcHJpbWVyIHRyaW1tZWQgcmVhZHMNCiAgICArICoqcmVhZF90cmltX3JpZ2h0KiogLSBSZW1vdmUgdGhpcyBtYW55IGJwIGZyb20gcmlnaHQgc2lkZSBvZiBwcmltZXIgdHJpbW1lZCByZWFkcw0KDQoqICoqQVNWIGZpbHRlcmluZyoqDQogICAgKyAqKmFzdl9taW5fbGVuZ3RoKiogLSBNaW5pbXVtIGxlbmd0aCBvZiBhbXBsaWNvbg0KICAgICsgKiphc3ZfbWF4X2xlbmd0aCoqIC0gTWF4aW11bSBsZW5ndGggb2YgYW1wbGljb24NCiAgICArICoqaGlnaF9zZW5zaXRpdml0eSoqIC0gT3B0aW9uIHRvIHR1cm4gb24gW3BzZXVkbyBwb29saW5nXShodHRwczovL2JlbmpqbmViLmdpdGh1Yi5pby9kYWRhMi9wc2V1ZG8uaHRtbCksIHNldHRpbmcgdGhpcyB0byBGQUxTRSBncmVhdGx5IHNwZWVkcyB1cCBBU1YgaW5mZXJlbmNlIGF0IHRoZSBleHBlbnNlIG9mIGRldGVjdGluZyBmZXdlciByYXJlICg8NSByZWFkcykgdGF4YS4NCiAgICArICoqY29uY2F0X3VubWVyZ2VkKiogLSBSZXRhaW4gYW55IHVubWVyZ2VkIHJlYWQgcGFpcnMgYnkgY29uY2F0ZW5hdGluZyB0aGVtIHRvZ2V0aGVyIHNlcGFyYXRlZCBieSBhIHN0cmluZyBvZiAxMCBOIGJhc2VzDQogICAgKyAqKmdlbmV0aWNfY29kZSoqIC0gR2VuZXRpYyBjb2RlIGZvciBhbXBsaWNvbiAtIHNlZSBCaW9zdHJpbmdzOjpHRU5FVElDX0NPREVfVEFCTEUNCiAgICArICoqY29kaW5nKiogLSBJcyB0aGUgYW1wbGljb24gZnJvbSBhIHByb3RlaW4gY29kaW5nIGdlbmUNCiAgICArICoqcGhtbSoqIC0gUGF0aCB0byBwcm9maWxlIGhpZGRlbiBtYXJrb3YgbW9kZWwgKE9wdGlvbmFsKQ0KDQoqICoqVGF4b25vbWljIGFzc2lnbm1lbnQ6KioNCiAgICArICoqaWR0YXhhX2RiKiogLSBQYXRoIHRvIHRyYWluZWQgSURUQVhBIG1vZGVsDQogICAgKyAqKnJlZl9mYXN0YSoqIC0gUGF0aCB0byBmYXN0YSBmaWxlIG9mIHJlZmVyZW5jZSBkYXRhYmFzZQ0KICAgICsgKippZHRheGFfY29uZmlkZW5jZSoqIC0gTWluaW11bSBib290c3RyYXAgY29uZmlkZW5jZSBmb3IgSURUQVhBDQogICAgKyAqKnJ1bl9ibGFzdCoqIC0gV2hldGhlciBhIGJsYXN0IHRvcCBoaXQgc2VhcmNoIHNob3VsZCBiZSBjb25kdWN0ZWQgaW4gYWRkaXRpb24gdG8gSURUQVhBDQogICAgKyAqKmJsYXN0X21pbl9pZGVudGl0eSoqIC0gTWluaW11bSBudWNsZW90aWRlIGlkZW50aXR5IGZvciBCTEFTVA0KICAgICsgKipibGFzdF9taW5fY292ZXJhZ2UqKiAtIE1pbmltdW0gcXVlcnkgY292ZXJhZ2UgZm9yIEJMQVNUDQogICAgKyAqKnRhcmdldF9raW5nZG9tKiogLSBTdWJzZXQgdG8gdGFyZ2V0IGtpbmdkb20NCiAgICArICoqdGFyZ2V0X3BoeWx1bSoqIC0gU3Vic2V0IHRvIHRhcmdldCBwaHlsdW0NCiAgICArICoqdGFyZ2V0X2NsYXNzKiogLSBTdWJzZXQgdG8gdGFyZ2V0IGNsYXNzDQogICAgKyAqKnRhcmdldF9vcmRlcioqIC0gU3Vic2V0IHRvIHRhcmdldCBvcmRlcg0KICAgICsgKip0YXJnZXRfZmFtaWx5KiogLSBTdWJzZXQgdG8gdGFyZ2V0IGZhbWlseQ0KICAgICsgKip0YXJnZXRfZ2VudXMqKiAtIFN1YnNldCB0byB0YXJnZXQgZ2VudXMNCiAgICArICoqdGFyZ2V0X3NwZWNpZXMqKiAtIFN1YnNldCB0byB0YXJnZXQgc3BlY2llcw0KDQoqICoqU2FtcGxlICYgVGF4b24gZmlsdGVyaW5nOioqDQogICAgKyAqKm1pbl9zYW1wbGVfcmVhZHMqKiAtIE1pbmltdW0gcmVhZHMgcGVyIHNhbXBsZSBhZnRlciBmaWx0ZXJpbmcNCiAgICArICoqbWluX3RheGFfcmVhZHMqKiAtIE1pbmltdW0gcmVhZHMgcGVyIEFTViB0byByZXRhaW4NCiAgICArICoqbWluX3RheGFfcmEqKiAtIE1pbmltdW0gcmVsYXRpdmUgYWJ1bmRhbmNlIHBlciBBU1YgdG8gcmV0YWluLiAxZS00IGlzIDAuMDElDQogICAgDQoqICoqR2VuZXJhbCBwaXBlbGluZSBwYXJhbWV0ZXJzKioNCiAgICArICoqdGhyZWFkcyoqIC0gTnVtYmVyIG9mIENQVSB0aHJlYWRzIHRvIHJ1biB0aGUgcGlwZWxpbmUgYWNyb3NzDQogICAgDQojIyBDcmVhdGUgcGFyYW1ldGVycyBmaWxlDQoNClRoZSBwaXBlbGluZSBhbHNvIHJlcXVpcmVzIGEgbG9jdXMgcGFyYW1ldGVycyBmaWxlIHdoaWNoIGxpc3RzIGltcG9ydGFudCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgdGFyZ2V0IGJhcmNvZGVzLCBhcyB3ZWxsIGFzIHRoZSBQSE1NIG1vZGVsIHVzZWQgdG8gY2xlYW4gdGhlIGxvY2ksIGFzIHdlbGwgYXMgdGhlIGRpZmZlcmVudCByZWZlcmVuY2UgZGF0YWJhc2VzIHRoYXQgYXJlIHRvIGJlIHVzZWQgZm9yIHRheG9ub21pYyBhc3NpZ25tZW50Lg0KDQpJZiBtdWx0aXBsZSByZWZlcmVuY2UgZGF0YWJhc2VzIGFyZSB0byBiZSB1c2VkIGl0ZXJhdGl2ZWx5IGZvciBhc3NpZ25tZW50LCB0aGV5IHNob3VsZCBiZSBzcGxpdCB3aXRoIGEgc2VtaWNvbG9uLCBhbmQgaW4gdGhlIG9yZGVyIHRoZXkgYXJlIHRvIGJlIHVzZWQgZm9yIGFzc2lnbm1lbnQuDQoNClRoZSBiZWxvdyBjb2RlIGdlbmVyYXRlcyB0aGUgbG9jaV9wYXJhbXMuY3N2IGZpbGUsIGhvd2V2ZXIgdGhpcyBjYW4gYWxzbyBiZSBkb25lIGluIGV4Y2VsLg0KDQoNCmBgYHtyIENyZWF0ZSBwYXJhbWV0ZXJzIGZpbGV9DQojIFBhcmFtcyB0byBhZGQgaW4gc3RlcF9hZGRfcGFyYW1ldGVycw0KcGFyYW1zIDwtIHRpYmJsZSgNCiAgIyBQcmltZXIgcGFyYW1ldGVycw0KICBwY3JfcHJpbWVycyA9IGMoImZ3aEYyLWZ3aFIybkRhYyIsICJFSUYzTG1pbmlGNC1FSUYzbG1pbmlSNCIpLA0KICB0YXJnZXRfZ2VuZT1jKCJDT0kiLCAiRUlGM0wiKSwNCiAgbWF4X3ByaW1lcl9taXNtYXRjaD0xLA0KDQogICMgUmVhZCBmaWx0ZXJpbmcNCiAgcmVhZF9taW5fbGVuZ3RoID0gMjAsDQogIHJlYWRfbWF4X2xlbmd0aCA9IEluZiwNCiAgcmVhZF9tYXhfZWUgPSAxLA0KICByZWFkX3RydW5jX2xlbmd0aCA9IDE1MCwNCiAgcmVhZF90cmltX2xlZnQgPSAwLA0KICByZWFkX3RyaW1fcmlnaHQgPSAwLA0KICANCiAgIyBBU1YgZmlsdGVyaW5nDQogIGFzdl9taW5fbGVuZ3RoID0gYygxOTUsIDIwNyksDQogIGFzdl9tYXhfbGVuZ3RoID0gYygyMTUsIDIyNyksDQogIGdlbmV0aWNfY29kZSA9IGMoIlNHQzQiLCAiU0dDMCIpLA0KICBjb2RpbmcgPSBjKFRSVUUsIFRSVUUpLA0KICBwaG1tID0gYygicmVmZXJlbmNlL3BobW0vQmFjdHJvY2VyYV9DT0kucmRzIiwgInJlZmVyZW5jZS9waG1tL0JhY3Ryb2NlcmFfRUlGM0wucmRzIiksDQogIA0KICAjIFRheG9ub21pYyBhc3NpZ25tZW50DQogIGlkdGF4YV9kYiA9IGMoInJlZmVyZW5jZS9DT0lfaWR0YXhhLnJkcyIsInJlZmVyZW5jZS9FSUYzTF9pZHRheGEucmRzIiksDQogIHJlZl9mYXN0YSA9IGMoInJlZmVyZW5jZS9DT0lfaGllcmFyY2hpYWwuZmEuZ3oiLCAicmVmZXJlbmNlL0VJRjNMX2hpZXJhcmNoaWFsLmZhLmd6IiksDQogIGlkdGF4YV9jb25maWRlbmNlID0gNjAsDQogIHJ1bl9ibGFzdD1UUlVFLA0KICBibGFzdF9taW5faWRlbnRpdHkgPSA5NywNCiAgYmxhc3RfbWluX2NvdmVyYWdlID0gOTAsDQogIHRhcmdldF9raW5nZG9tID0gIk1ldGF6b2EiLA0KICB0YXJnZXRfcGh5bHVtID0gIkFydGhyb3BvZGEiLA0KICB0YXJnZXRfY2xhc3MgPSAiSW5zZWN0YSIsDQogIHRhcmdldF9vcmRlciA9ICJEaXB0ZXJhIiwNCiAgdGFyZ2V0X2ZhbWlseSA9IE5BLCANCiAgdGFyZ2V0X2dlbnVzID0gTkEsICANCiAgdGFyZ2V0X3NwZWNpZXMgPSBOQSwgIA0KICANCiAgIyBTYW1wbGUgJiBUYXhvbiBmaWx0ZXJpbmcNCiAgbWluX3NhbXBsZV9yZWFkcyA9IGMoMTAwMCwgMTAwMCksDQogIG1pbl90YXhhX3JlYWRzPSBOQSwgDQogIG1pbl90YXhhX3JhID0gYygxZS00LCAxZS00KSwNCiAgDQogICMgR2VuZXJhbCBwaXBlbGluZSBwYXJhbWV0ZXJzDQogIHRocmVhZHMgPSAxDQopDQoNCiMgV3JpdGUgb3V0IHRoZSBwYXJhbWV0ZXJzIGZpbGUNCndyaXRlX2NzdihwYXJhbXMsICJzYW1wbGVfZGF0YS9sb2NpX3BhcmFtcy5jc3YiKQ0KYGBgDQoNCiMgUnVuIHRoZSBwaXBlbGluZQ0KDQpOb3cgdGhhdCB0aGUgc2FtcGxlIGRhdGEgYW5kIHBhcmFtZXRlcnMgZmlsZSBpcyByZWFkeSwgaXRzIHRpbWUgdG8gcnVuIHRoZSBwaXBlbGluZSENCg0KDQojIyBSdW4gdGhlIHRhcmdldHMgcGlwZWxpbmUNCmBgYHtyfQ0KdGFyX21ha2UoKQ0KYGBgDQoNCiMgUmVzdWx0cw0KDQpTZWUgdGhlIFtnZW5lcmFsIGludHJvZHVjdGlvbl0oaHR0cHM6Ly9hbGV4cGlwZXIuZ2l0aHViLmlvL3BpcGVybGluZS92aWduZXR0ZXMvZ2VuZXJhbC5odG1sKSB2aWduZXR0ZSBmb3IgYW4gaW4tZGVwdGggZXhwbGFuYXRpb24gb2YgdGhlIHJlc3VsdHMgYW5kIHF1YWxpdHkgY29udHJvbCBvdXRwdXRzDQo=