Objectives
This notebook will demonstrate how to:
- Navigate the terminal interface
- Organize an analysis project
- Apply FastQC
for quality control analysis of Illumina sequencing data
- Preprocess sequencing reads with fastp
- Quantify RNA-seq expression with Salmon
We will first learn how to process RNA-seq data at the command line
using samples that were assayed with paired-end sequencing.
These samples come from a project (PRJNA178120
)
that includes 8 samples from normal gastric tissue, gastric cancer cell
lines and primary gastric tumor cell cultures.
Here we will perform quality control checks, trimming, and estimate
the transcript abundances for a single sample, SRR585570.
Later, we will use the full dataset (n = 8) to explore how to
summarize estimates to the gene level and do some exploratory data
analyses with data the course directors have processed ahead of
time.
We’ll first want to set our working directory to the top-level of the
RNA-seq folder.
Copy and paste the text in the code blocks below into your
Terminal
window in RStudio. It should be in the lower left
hand corner as a tab next to Console
.
Set current directory to the top-level of the RNA-seq
module:
cd ~/training-modules/RNA-seq
Here ~/
refers to your home directory on the
RStudio Server, which is the base folder in which your files live,
including most of the materials for training. This is also the default
working directory when you open a new RStudio session. A home directory
is specific to you as a user on the RStudio Server; each user has their
own folder to store their files.
Because these steps are computationally time intensive, we’ve
prepared a script to start running things. Once we start
running the script, we will give a short lecture to introduce this
module and then walk through and explain each of the individual steps
that the script is executing.
Enter the following in the Terminal to start running the
script:
bash scripts/run_SRR585570.sh
Note: Don’t worry if the Salmon step does not complete by the
time we move on to the next notebook. This is a time and resource
intensive step, so we have prepared the required output in case we need
it.
Quality control with FastQC
The first thing our script does is use FastQC
for quality control in command line mode. Here’s a link to the FastQC
documentation: https://www.bioinformatics.babraham.ac.uk/projects/fastqc/Help/
Let’s take a look at some example reports from the authors of
FastQC:
FastQC runs a series of quality checks on sequencing data and
provides an HTML report. As the authors point out in the docs:
It is important to stress that although the analysis results appear
to give a pass/fail result, these evaluations must be taken in the
context of what you expect from your library.
The documentation
for individual modules/analyses in FastQC is a great resource!
To save time, our script only runs one FASTQ file for SRR585570 with
the following commands:
mkdir -p QC/gastric-cancer/fastqc/SRR585570
mkdir
allows us to create a new folder in the
QC/gastric-cancer/fastqc
directory specifically to hold the
report information that will be generated by FastQC for this
sample. The -p
allows us to create parent
directories and will prevent an error if the directory we specify
already exists.
# In the interest of time, we'll run one of the fastq files through FastQC
fastqc data/gastric-cancer/fastq/SRR585570/SRR585570_1.fastq.gz \
-o QC/gastric-cancer/fastqc/SRR585570
-o
The -o
flag allows us to specify where the output of
FastQC is saved. Note that this is saved in a separate place than the
raw data files and in a directory specifically for quality control
information.
For comparison to the report for SRR585570_1.fastq.gz
we
generate with our script, we’ve prepared a FastQC report for one of the
sets of reads for another sample in the experiment. It can be found at
QC/gastric-cancer/fastqc/SRR585574/SRR585574_1_fastqc.html
.
Let’s look at the reports for both samples.
Preprocessing with fastp
We use fastp to
preprocess the FASTQ files (Chen et
al. Bioinformatics. 2018.). Note that fastp has quality
control functionality and many different options for preprocessing (see
all
options on GitHub), most of which we will not cover. Here, we focus
on adapter trimming, quality filtering, and length filtering.
Below, we discuss the commands we used in the script.
Create output directories
# Create a directory to hold the trimmed fastq files
mkdir -p data/gastric-cancer/fastq-trimmed/SRR585570
# Create a directory to hold the QC output from fastp
mkdir -p QC/gastric_cancer/fastp/SRR585570
As we’ll cover below, fastp essentially has two kinds of output:
trimmed and filtered FASTQ files (data) and reports (quality
control).
fastp
# Run the adapter and quality trimming step -- also produces QC report
fastp -i data/gastric-cancer/fastq/SRR585570/SRR585570_1.fastq.gz \
-I data/gastric-cancer/fastq/SRR585570/SRR585570_2.fastq.gz \
-o data/gastric-cancer/fastq-trimmed/SRR585570/SRR585570_fastp_1.fastq.gz \
-O data/gastric-cancer/fastq-trimmed/SRR585570/SRR585570_fastp_2.fastq.gz \
--qualified_quality_phred 15 \
--length_required 20 \
--report_title "SRR585570" \
--json QC/gastric-cancer/fastp/SRR585570/SRR585570_fastp.json \
--html QC/gastric-cancer/fastp/SRR585570/SRR585570_fastp.html
Below, we’ll walk through the arguments/options we used to run
fastp
. By default, fastp performs adapter trimming, which
you can read more about here. For
paired-end data like the data we have for SRR585570, adapters can be
detected automatically without specifying an adapter sequence.
fastq output: -o
and -O
These arguments specify the read1 output and read2 output,
respectively. Note that the output is being placed in
data/gastric-cancer/fastq-trimmed/SRR585570/
, so the
processed FASTQ files will be kept separate from from the original
files. It is generally good practice to treat your “raw” data and its
directories as fixed and separate from any processing and analysis that
you do, to prevent accidentally modification of those original files.
And in the event that you accidentally do modify the originals, you know
exactly which files and directories to reset.
--qualified_quality_phred
Phred
scores are the quality information included in a FASTQ file and the
values indicate the chances that a base is called incorrectly. Let’s
look at a screenshot of the Per Base Sequence Quality module from FastQC
bad Illumina example we linked to above.
per-base-quality-screenshot
Anything below 20, where a Phred score of 20 represents a 1 in 100
chance that the call is incorrect, is considered poor quality by FastQC.
Using --qualified_quality_phred 15
(which is the default),
means scores >= 15 are considered “qualified.” Using the default
parameters as we do here, reads will be filtered out if >40% of the
bases are unqualified. You can read more about the quality
filtering functionality of fastp here.
The Salmon documentation notes that, given the way we run
salmon quant
, quantification may be more sensitive to calls
that are likely to be erroneous (of low quality) and, therefore, quality
trimming may be important.
Trimming, in contrast to filtering, refers to removing low quality
base calls from the (typically 3’) end of reads. A recent paper from the
Salmon authors (Srivastava et
al. 2020) notes that trimming did not affect mapping rates from
random publicly available human bulk (paired-end) RNA-seq samples (they
used TrimGalore). fastp
does have the
functionality to perform trimming using a sliding window, which must
be enabled. We are not using it here.
Note that there are two kinds of encoding for Phred scores: Phred
33 encoding and Phred 64 encoding. FastQC guessed that the file for
SRR585570 uses Sanger/Illumina 1.9 encoding (Phred 33). If we had Phred
64 data, we’d use the --phred64
flag. You can read a little
bit more about the encoding here.
--length_required
Trimming reads may result in short reads, which may affect gene
expression estimates (Williams et al. BMC
Bioinformatics. 2016.). Using --length_required 20
means that reads shorter than 20bp will be discarded (similar to what
was used in Srivastava et al. above).
--report_title
When we look at the HTML report, it’s helpful to quickly identify
what sample the report is for. Using
--report title "SRR585570"
means that the report will be
titled “SRR585570” rather than the default (“fastp report”).
--json
and --html
With these options, we’re specifying where the JSON and HTML reports will
be saved (in the QC/gastric-cancer/fastp/
directory we
created) and what the filenames will be. Including the sample name in
the filenames again may help us with project organization.
If we look at
QC/gastric-cancer/fastp/SRR585570_fastp.json
or the
top of the HTML report, we can see that fastp reports certain metrics
before and after filtering, which can be very useful in making analysis
decisions.
Quantification with Salmon
We’ll use Salmon
for quantifying transcript expression (documentation).
Salmon (Patro, et
al. Nature Methods. 2017.) is fast and requires very little
memory, which makes it a great choice for running on your laptop during
training. We can use the output for downstream analyses like
differential expression analysis and clustering. We use Salmon in
mapping mode, with mapping validation enabled, using the following
command:
# We perform quantification on the files that have been trimmed
# and use the index generated with -k 23, as this may "improve sensitivity"
# per the Salmon documentation
salmon quant -i index/Homo_sapiens/short_index \
-l A \
-1 data/gastric-cancer/fastq-trimmed/SRR585570/SRR585570_fastp_1.fastq.gz \
-2 data/gastric-cancer/fastq-trimmed/SRR585570/SRR585570_fastp_2.fastq.gz \
-o data/gastric-cancer/salmon_quant/SRR585570 \
--validateMappings --rangeFactorizationBins 4 \
--gcBias --seqBias \
--threads 4
Below, we’ll walk through the arguments/options we used to run
salmon quant
.
Transcriptome index: -i
Salmon requires a set of transcripts (what we want to quantify) in
the form of a transcriptome index built with salmon index
.
Building an index can take a while (but you only have to do it once!),
so we’ve built the one we use today ahead of time. Before we use it,
we’ll take a moment to give a bit of background.
You can see how we obtained this index and others on
GitHub. Note that we used Homo sapiens GRCh38, Ensembl release 95.
It is important to keep track of what build, resource, and files were
used and putting our shell scripts on GitHub allows us to do that.
The salmon index
command has a parameter -k
which sets the k-mer length. The index we used was built with
-k 23
and can be found here:
index/Homo_sapiens/short_index
Using a smaller value for k than the default (k =
31) is appropriate for shorter reads and may improve sensitivity when
using --validateMappings
according to the Salmon
documentation.
-l
We use -l A
to allow Salmon to automatically infer the
library type based on a subset of reads, but you can also provide the library
type to Salmon with this argument.
-o
Output directory, salmon quant
should create this for us
if it doesn’t exist yet.
--validateMappings
and
--rangeFactorizationBins
Using --validateMappings
enables mapping validation,
where Salmon checks its mappings using traditional alignment. This helps
prevent “spurious mappings” where a read maps to a target but does not
arise from it (see documentation
for flag and the release
notes for v0.10.0
where this was introduced).
When enabling mapping validation with
--validateMappings
, setting
--rangeFactorizationBins 4
can improve quantification for
certain classes of transcripts (docs).
--gcBias
With this option enabled, Salmon will attempt to correct for fragment
GC-bias. Regions with high or low GC content tend to be underrepresented
in sequencing data.
It should be noted that this is only appropriate for use with
paired-end reads, as fragment length can not be inferred from single-end
reads (see this GitHub
issue).
--seqBias
With this option enabled, Salmon will attempt to correct for the bias
that occurs when using random hexamer priming (preferential sequencing
of reads when certain motifs appear at the beginning).
--threads
The --threads
argument controls the number of threads
that are available to Salmon during quantification. This in essence
controls how much of the mapping can occur in parallel. If you had
access to a computer with many cores, you could increase the number of
threads to make quantification go faster.
Navigate to
data/gastric-cancer/salmon_quant/SRR585571/aux_info
and open meta_info.json
. Look for
a field called percent_mapped
– what value
does this sample have?
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIGJ1bGsgUk5BLXNlcSBkYXRhIHByb2Nlc3NpbmciCmF1dGhvcjogQ0NETCBmb3IgQUxTRgpkYXRlOiAyMDIxCm91dHB1dDogICAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCi0tLQoKIyMgT2JqZWN0aXZlcwoKVGhpcyBub3RlYm9vayB3aWxsIGRlbW9uc3RyYXRlIGhvdyB0bzoKCi0gTmF2aWdhdGUgdGhlIHRlcm1pbmFsIGludGVyZmFjZSAgCi0gT3JnYW5pemUgYW4gYW5hbHlzaXMgcHJvamVjdCAKLSBBcHBseSBbRmFzdFFDXShodHRwczovL3d3dy5iaW9pbmZvcm1hdGljcy5iYWJyYWhhbS5hYy51ay9wcm9qZWN0cy9mYXN0cWMvKSBmb3IgcXVhbGl0eSBjb250cm9sIGFuYWx5c2lzIG9mIElsbHVtaW5hIHNlcXVlbmNpbmcgZGF0YQotIFByZXByb2Nlc3Mgc2VxdWVuY2luZyByZWFkcyB3aXRoIFtmYXN0cF0oaHR0cHM6Ly9naXRodWIuY29tL09wZW5HZW5lL2Zhc3RwKQotIFF1YW50aWZ5IFJOQS1zZXEgZXhwcmVzc2lvbiB3aXRoIFtTYWxtb25dKGh0dHBzOi8vY29tYmluZS1sYWIuZ2l0aHViLmlvL3NhbG1vbi8pCgotLS0KCldlIHdpbGwgZmlyc3QgbGVhcm4gaG93IHRvIHByb2Nlc3MgUk5BLXNlcSBkYXRhIGF0IHRoZSBjb21tYW5kIGxpbmUgdXNpbmcgc2FtcGxlcyB0aGF0IHdlcmUgYXNzYXllZCB3aXRoIHBhaXJlZC1lbmQgc2VxdWVuY2luZy4KClRoZXNlIHNhbXBsZXMgY29tZSBmcm9tIGEgcHJvamVjdCAoW2BQUkpOQTE3ODEyMGBdKGh0dHBzOi8vd3d3LmViaS5hYy51ay9lbmEvZGF0YS92aWV3L1BSSk5BMTc4MTIwKSkgdGhhdCBpbmNsdWRlcyA4IHNhbXBsZXMgZnJvbSBub3JtYWwgZ2FzdHJpYyB0aXNzdWUsIGdhc3RyaWMgY2FuY2VyIGNlbGwgbGluZXMgYW5kIHByaW1hcnkgZ2FzdHJpYyB0dW1vciBjZWxsIGN1bHR1cmVzLgoKSGVyZSB3ZSB3aWxsIHBlcmZvcm0gcXVhbGl0eSBjb250cm9sIGNoZWNrcywgdHJpbW1pbmcsIGFuZCBlc3RpbWF0ZSB0aGUgdHJhbnNjcmlwdCBhYnVuZGFuY2VzIGZvciBhIHNpbmdsZSBzYW1wbGUsIFNSUjU4NTU3MC4KCiFbXShkaWFncmFtcy9ybmEtc2VxXzEucG5nKQoKTGF0ZXIsIHdlIHdpbGwgdXNlIHRoZSBmdWxsIGRhdGFzZXQgKG4gPSA4KSB0byBleHBsb3JlIGhvdyB0byBzdW1tYXJpemUgZXN0aW1hdGVzIHRvIHRoZSBnZW5lIGxldmVsIGFuZCBkbyBzb21lIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzZXMgd2l0aCBkYXRhIHRoZSBjb3Vyc2UgZGlyZWN0b3JzIGhhdmUgcHJvY2Vzc2VkIGFoZWFkIG9mIHRpbWUuCgotLS0KCldlJ2xsIGZpcnN0IHdhbnQgdG8gc2V0IG91ciB3b3JraW5nIGRpcmVjdG9yeSB0byB0aGUgdG9wLWxldmVsIG9mIHRoZSBSTkEtc2VxIGZvbGRlci4KCkNvcHkgYW5kIHBhc3RlIHRoZSB0ZXh0IGluIHRoZSBjb2RlIGJsb2NrcyBiZWxvdyBpbnRvIHlvdXIgYFRlcm1pbmFsYCB3aW5kb3cgaW4gUlN0dWRpby4KSXQgc2hvdWxkIGJlIGluIHRoZSBsb3dlciBsZWZ0IGhhbmQgY29ybmVyIGFzIGEgdGFiIG5leHQgdG8gYENvbnNvbGVgLgoKKipTZXQgY3VycmVudCBkaXJlY3RvcnkgdG8gdGhlIHRvcC1sZXZlbCBvZiB0aGUgUk5BLXNlcSBtb2R1bGU6KioKCmBgYGJhc2gKY2Qgfi90cmFpbmluZy1tb2R1bGVzL1JOQS1zZXEKYGBgCgpIZXJlIGB+L2AgcmVmZXJzIHRvIHlvdXIgX2hvbWUgZGlyZWN0b3J5XyBvbiB0aGUgUlN0dWRpbyBTZXJ2ZXIsIHdoaWNoIGlzIHRoZSBiYXNlIGZvbGRlciBpbiB3aGljaCB5b3VyIGZpbGVzIGxpdmUsIGluY2x1ZGluZyBtb3N0IG9mIHRoZSBtYXRlcmlhbHMgZm9yIHRyYWluaW5nLgpUaGlzIGlzIGFsc28gdGhlIGRlZmF1bHQgd29ya2luZyBkaXJlY3Rvcnkgd2hlbiB5b3Ugb3BlbiBhIG5ldyBSU3R1ZGlvIHNlc3Npb24uCkEgaG9tZSBkaXJlY3RvcnkgaXMgc3BlY2lmaWMgdG8geW91IGFzIGEgdXNlciBvbiB0aGUgUlN0dWRpbyBTZXJ2ZXI7IGVhY2ggdXNlciBoYXMgdGhlaXIgb3duIGZvbGRlciB0byBzdG9yZSB0aGVpciBmaWxlcy4KCioqQmVjYXVzZSB0aGVzZSBzdGVwcyBhcmUgY29tcHV0YXRpb25hbGx5IHRpbWUgaW50ZW5zaXZlLCB3ZSd2ZSBwcmVwYXJlZCBhIHNjcmlwdCB0byBzdGFydCBydW5uaW5nIHRoaW5ncy4qKgpPbmNlIHdlIHN0YXJ0IHJ1bm5pbmcgdGhlIHNjcmlwdCwgd2Ugd2lsbCBnaXZlIGEgc2hvcnQgbGVjdHVyZSB0byBpbnRyb2R1Y2UgdGhpcyBtb2R1bGUgYW5kIHRoZW4gd2FsayB0aHJvdWdoIGFuZCBleHBsYWluIGVhY2ggb2YgdGhlIGluZGl2aWR1YWwgc3RlcHMgdGhhdCB0aGUgc2NyaXB0IGlzIGV4ZWN1dGluZy4KCioqRW50ZXIgdGhlIGZvbGxvd2luZyBpbiB0aGUgVGVybWluYWwgdG8gc3RhcnQgcnVubmluZyB0aGUgc2NyaXB0OioqCgpgYGBiYXNoCmJhc2ggc2NyaXB0cy9ydW5fU1JSNTg1NTcwLnNoCmBgYAoKX05vdGU6IERvbid0IHdvcnJ5IGlmIHRoZSBTYWxtb24gc3RlcCBkb2VzIG5vdCBjb21wbGV0ZSBieSB0aGUgdGltZSB3ZSBtb3ZlIG9uIHRvIHRoZSBuZXh0IG5vdGVib29rLgpUaGlzIGlzIGEgdGltZSBhbmQgcmVzb3VyY2UgaW50ZW5zaXZlIHN0ZXAsIHNvIHdlIGhhdmUgcHJlcGFyZWQgdGhlIHJlcXVpcmVkIG91dHB1dCBpbiBjYXNlIHdlIG5lZWQgaXQuXwoKIyMjIElucHV0IGZpbGVzCgpUaGUgcmF3IGRhdGEgRkFTVFEgZmlsZXMgKGBmYXN0cS5nemApIGZvciB0aGlzIHNhbXBsZSwgU1JSNTg1NTcwLCBhcmUgaW4gYGRhdGEvZ2FzdHJpYy1jYW5jZXIvZmFzdHEvU1JSNTg1NTcwYC4KVGhlIGZpcnN0IHR3byBkaXJlY3RvcmllcywgYGRhdGEvYCBhbmQgYGdhc3RyaWMtY2FuY2VyL2AsIHRlbGwgdXMgdGhhdCB0aGVzZSBmaWxlcyBhcmUgZGF0YSBhbmQgd2hpY2ggZXhwZXJpbWVudCBvciBkYXRhc2V0IHRoZXNlIGRhdGEgYXJlIGZyb20uCldlJ2xsIGJlIHdvcmtpbmcgd2l0aCBhbiBhZGRpdGlvbmFsIGRhdGFzZXQgbGF0ZXIgaW4gdGhlIG1vZHVsZSwgc28gdGhpcyBsYXR0ZXIgZGlzdGluY3Rpb24gd2lsbCBiZWNvbWUgbW9yZSBpbXBvcnRhbnQuClRoZSB0aGlyZCBkaXJlY3RvcnksIGBmYXN0cS9gLCB0ZWxscyB1cyB0aGF0IHRoaXMgaXMgd2hlcmUgd2Ugd2lsbCBiZSBzdG9yaW5nIGZhc3RxIGZpbGVzLgoKVGhlIGZpbmFsIGRpcmVjdG9yeSwgYFNSUjU4NTU3MGAsIGlzIHNwZWNpZmljIHRvIHRoZSBzYW1wbGUgd2UgYXJlIHdvcmtpbmcgd2l0aC4KVGhlIHVzZSBvZiB0aGUgYFNSUjU4NTU3MGAgZm9sZGVyIG1pZ2h0IHNlZW0gdW5uZWNlc3NhcnkgYmVjYXVzZSB3ZSBhcmUgb25seSBwcm9jZXNzaW5nIGEgc2luZ2xlIHNhbXBsZSBoZXJlLCBidXQga2VlcGluZyBmaWxlcyBmb3IgaW5kaXZpZHVhbCBzYW1wbGVzIGluIHRoZWlyIG93biBmb2xkZXIgaGVscHMga2VlcCB0aGluZ3Mgb3JnYW5pemVkIGZvciBtdWx0aS1zYW1wbGUgd29ya2Zsb3dzLgooWW91IGNhbiBwZWVrIGFoZWFkIGFuZCBsb29rIGF0IHRoZSBgZGF0YS9OQi1jZWxsL3F1YW50YCBmb2xkZXIgZm9yIHN1Y2ggYW4gZXhhbXBsZS4pCgpUaGVyZSBpcyBubyAib25lIHNpemUgZml0cyBhbGwiIGFwcHJvYWNoIGZvciBwcm9qZWN0IG9yZ2FuaXphdGlvbi4KSXQncyBtb3N0IGltcG9ydGFudCB0aGF0IGl0J3MgY29uc2lzdGVudCwgZWFzeSBmb3IgeW91IGFuZCBvdGhlcnMgdG8gZmluZCB0aGUgZmlsZXMgeW91IG5lZWQgcXVpY2tseSwgYW5kIG1pbmltaXplcyB0aGUgbGlrZWxpaG9vZCBmb3IgZXJyb3JzIChlLmcuLCB3cml0aW5nIG92ZXIgZmlsZXMgYWNjaWRlbnRhbGx5KS4KCiMjIFF1YWxpdHkgY29udHJvbCB3aXRoIEZhc3RRQwoKIVtdKGRpYWdyYW1zL3JuYS1zZXFfMi5wbmcpCgpUaGUgZmlyc3QgdGhpbmcgb3VyIHNjcmlwdCBkb2VzIGlzIHVzZSBbRmFzdFFDXShodHRwczovL3d3dy5iaW9pbmZvcm1hdGljcy5iYWJyYWhhbS5hYy51ay9wcm9qZWN0cy9mYXN0cWMvKSBmb3IgcXVhbGl0eSBjb250cm9sIGluIGNvbW1hbmQgbGluZSBtb2RlLgpIZXJlJ3MgYSBsaW5rIHRvIHRoZSBGYXN0UUMgZG9jdW1lbnRhdGlvbjogaHR0cHM6Ly93d3cuYmlvaW5mb3JtYXRpY3MuYmFicmFoYW0uYWMudWsvcHJvamVjdHMvZmFzdHFjL0hlbHAvCgoqKkxldCdzIHRha2UgYSBsb29rIGF0IHNvbWUgZXhhbXBsZSByZXBvcnRzIGZyb20gdGhlIGF1dGhvcnMgb2YgRmFzdFFDOioqCgoqIFtHb29kIElsbHVtaW5hIGRhdGEgZXhhbXBsZSByZXBvcnRdKGh0dHBzOi8vd3d3LmJpb2luZm9ybWF0aWNzLmJhYnJhaGFtLmFjLnVrL3Byb2plY3RzL2Zhc3RxYy9nb29kX3NlcXVlbmNlX3Nob3J0X2Zhc3RxYy5odG1sKSBmcm9tIEZhc3RRQwoqIFtCYWQgSWxsdW1pbmEgZGF0YSBleGFtcGxlIHJlcG9ydF0oaHR0cHM6Ly93d3cuYmlvaW5mb3JtYXRpY3MuYmFicmFoYW0uYWMudWsvcHJvamVjdHMvZmFzdHFjL2JhZF9zZXF1ZW5jZV9mYXN0cWMuaHRtbCkgZnJvbSBGYXN0UUMKCkZhc3RRQyBydW5zIGEgc2VyaWVzIG9mIHF1YWxpdHkgY2hlY2tzIG9uIHNlcXVlbmNpbmcgZGF0YSBhbmQgcHJvdmlkZXMgYW4gSFRNTCByZXBvcnQuIEFzIHRoZSBhdXRob3JzIHBvaW50IG91dCBpbiB0aGUgW2RvY3NdKGh0dHBzOi8vd3d3LmJpb2luZm9ybWF0aWNzLmJhYnJhaGFtLmFjLnVrL3Byb2plY3RzL2Zhc3RxYy9IZWxwLzIlMjBCYXNpYyUyME9wZXJhdGlvbnMvMi4yJTIwRXZhbHVhdGluZyUyMFJlc3VsdHMuaHRtbCk6Cgo+IEl0IGlzIGltcG9ydGFudCB0byBzdHJlc3MgdGhhdCBhbHRob3VnaCB0aGUgYW5hbHlzaXMgcmVzdWx0cyBhcHBlYXIgdG8gZ2l2ZSBhIHBhc3MvZmFpbCByZXN1bHQsIHRoZXNlIGV2YWx1YXRpb25zIG11c3QgYmUgdGFrZW4gaW4gdGhlIGNvbnRleHQgb2Ygd2hhdCB5b3UgZXhwZWN0IGZyb20geW91ciBsaWJyYXJ5LgoKVGhlIFtkb2N1bWVudGF0aW9uIGZvciBpbmRpdmlkdWFsIG1vZHVsZXMvYW5hbHlzZXNdKGh0dHBzOi8vd3d3LmJpb2luZm9ybWF0aWNzLmJhYnJhaGFtLmFjLnVrL3Byb2plY3RzL2Zhc3RxYy9IZWxwLzMlMjBBbmFseXNpcyUyME1vZHVsZXMvKSBpbiBGYXN0UUMgaXMgYSBncmVhdCByZXNvdXJjZSEKClRvIHNhdmUgdGltZSwgb3VyIHNjcmlwdCBvbmx5IHJ1bnMgb25lIEZBU1RRIGZpbGUgZm9yIFNSUjU4NTU3MCB3aXRoIHRoZSBmb2xsb3dpbmcgY29tbWFuZHM6CgpgYGBiYXNoCm1rZGlyIC1wIFFDL2dhc3RyaWMtY2FuY2VyL2Zhc3RxYy9TUlI1ODU1NzAKYGBgCgpgbWtkaXJgIGFsbG93cyB1cyB0byBjcmVhdGUgYSBuZXcgZm9sZGVyIGluIHRoZSBgUUMvZ2FzdHJpYy1jYW5jZXIvZmFzdHFjYCBkaXJlY3Rvcnkgc3BlY2lmaWNhbGx5IHRvIGhvbGQgdGhlIHJlcG9ydCBpbmZvcm1hdGlvbiB0aGF0IHdpbGwgYmUgZ2VuZXJhdGVkIGJ5IEZhc3RRQyBfZm9yIHRoaXMgc2FtcGxlXy4KVGhlIGAtcGAgYWxsb3dzIHVzIHRvIGNyZWF0ZSBfcGFyZW50XyBkaXJlY3RvcmllcyBhbmQgd2lsbCBwcmV2ZW50IGFuIGVycm9yIGlmIHRoZSBkaXJlY3Rvcnkgd2Ugc3BlY2lmeSBhbHJlYWR5IGV4aXN0cy4KCmBgYGJhc2gKIyBJbiB0aGUgaW50ZXJlc3Qgb2YgdGltZSwgd2UnbGwgcnVuIG9uZSBvZiB0aGUgZmFzdHEgZmlsZXMgdGhyb3VnaCBGYXN0UUMKZmFzdHFjIGRhdGEvZ2FzdHJpYy1jYW5jZXIvZmFzdHEvU1JSNTg1NTcwL1NSUjU4NTU3MF8xLmZhc3RxLmd6IFwKCS1vIFFDL2dhc3RyaWMtY2FuY2VyL2Zhc3RxYy9TUlI1ODU1NzAKYGBgCgojIyMjIGAtb2AKClRoZSBgLW9gIGZsYWcgYWxsb3dzIHVzIHRvIHNwZWNpZnkgd2hlcmUgdGhlIG91dHB1dCBvZiBGYXN0UUMgaXMgc2F2ZWQuCk5vdGUgdGhhdCB0aGlzIGlzIHNhdmVkIGluIGEgc2VwYXJhdGUgcGxhY2UgdGhhbiB0aGUgcmF3IGRhdGEgZmlsZXMgYW5kIGluIGEgZGlyZWN0b3J5IHNwZWNpZmljYWxseSBmb3IgcXVhbGl0eSBjb250cm9sIGluZm9ybWF0aW9uLgoKRm9yIGNvbXBhcmlzb24gdG8gdGhlIHJlcG9ydCBmb3IgYFNSUjU4NTU3MF8xLmZhc3RxLmd6YCB3ZSBnZW5lcmF0ZSB3aXRoIG91ciBzY3JpcHQsIHdlJ3ZlIHByZXBhcmVkIGEgRmFzdFFDIHJlcG9ydCBmb3Igb25lIG9mIHRoZSBzZXRzIG9mIHJlYWRzIGZvciBhbm90aGVyIHNhbXBsZSBpbiB0aGUgZXhwZXJpbWVudC4KSXQgY2FuIGJlIGZvdW5kIGF0IGBRQy9nYXN0cmljLWNhbmNlci9mYXN0cWMvU1JSNTg1NTc0L1NSUjU4NTU3NF8xX2Zhc3RxYy5odG1sYC4KCioqTGV0J3MgbG9vayBhdCB0aGUgcmVwb3J0cyBmb3IgYm90aCBzYW1wbGVzLioqCgojIyBQcmVwcm9jZXNzaW5nIHdpdGggZmFzdHAKCiFbXShkaWFncmFtcy9ybmEtc2VxXzMucG5nKQoKV2UgdXNlIFtmYXN0cF0oaHR0cHM6Ly9naXRodWIuY29tL09wZW5HZW5lL2Zhc3RwKSB0byBwcmVwcm9jZXNzIHRoZSBGQVNUUSBmaWxlcyAoW0NoZW4gZXQgYWwuIF9CaW9pbmZvcm1hdGljcy5fIDIwMTguXShodHRwczovL2RvaS5vcmcvMTAuMTA5My9iaW9pbmZvcm1hdGljcy9idHk1NjApKS4KTm90ZSB0aGF0IGZhc3RwIGhhcyBxdWFsaXR5IGNvbnRyb2wgZnVuY3Rpb25hbGl0eSBhbmQgbWFueSBkaWZmZXJlbnQgb3B0aW9ucyBmb3IgcHJlcHJvY2Vzc2luZyAoc2VlIFthbGwgb3B0aW9ucyBvbiBHaXRIdWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuR2VuZS9mYXN0cC9ibG9iL21hc3Rlci9SRUFETUUubWQjYWxsLW9wdGlvbnMpKSwgbW9zdCBvZiB3aGljaCB3ZSB3aWxsIG5vdCBjb3Zlci4KSGVyZSwgd2UgZm9jdXMgb24gYWRhcHRlciB0cmltbWluZywgcXVhbGl0eSBmaWx0ZXJpbmcsIGFuZCBsZW5ndGggZmlsdGVyaW5nLgoKQmVsb3csIHdlIGRpc2N1c3MgdGhlIGNvbW1hbmRzIHdlIHVzZWQgaW4gdGhlIHNjcmlwdC4KCiMjIyBDcmVhdGUgb3V0cHV0IGRpcmVjdG9yaWVzCgpgYGBiYXNoCiMgQ3JlYXRlIGEgZGlyZWN0b3J5IHRvIGhvbGQgdGhlIHRyaW1tZWQgZmFzdHEgZmlsZXMKbWtkaXIgLXAgZGF0YS9nYXN0cmljLWNhbmNlci9mYXN0cS10cmltbWVkL1NSUjU4NTU3MAojIENyZWF0ZSBhIGRpcmVjdG9yeSB0byBob2xkIHRoZSBRQyBvdXRwdXQgZnJvbSBmYXN0cApta2RpciAtcCBRQy9nYXN0cmljX2NhbmNlci9mYXN0cC9TUlI1ODU1NzAKYGBgCgpBcyB3ZSdsbCBjb3ZlciBiZWxvdywgZmFzdHAgZXNzZW50aWFsbHkgaGFzIHR3byBraW5kcyBvZiBvdXRwdXQ6IHRyaW1tZWQgYW5kIGZpbHRlcmVkIEZBU1RRIGZpbGVzIChkYXRhKSBhbmQgcmVwb3J0cyAocXVhbGl0eSBjb250cm9sKS4KCiMjIyBmYXN0cAoKYGBgYmFzaAojIFJ1biB0aGUgYWRhcHRlciBhbmQgcXVhbGl0eSB0cmltbWluZyBzdGVwIC0tIGFsc28gcHJvZHVjZXMgUUMgcmVwb3J0CmZhc3RwIC1pIGRhdGEvZ2FzdHJpYy1jYW5jZXIvZmFzdHEvU1JSNTg1NTcwL1NSUjU4NTU3MF8xLmZhc3RxLmd6IFwKICAgIC1JIGRhdGEvZ2FzdHJpYy1jYW5jZXIvZmFzdHEvU1JSNTg1NTcwL1NSUjU4NTU3MF8yLmZhc3RxLmd6IFwKICAgIC1vIGRhdGEvZ2FzdHJpYy1jYW5jZXIvZmFzdHEtdHJpbW1lZC9TUlI1ODU1NzAvU1JSNTg1NTcwX2Zhc3RwXzEuZmFzdHEuZ3ogXAogICAgLU8gZGF0YS9nYXN0cmljLWNhbmNlci9mYXN0cS10cmltbWVkL1NSUjU4NTU3MC9TUlI1ODU1NzBfZmFzdHBfMi5mYXN0cS5neiBcCiAgICAtLXF1YWxpZmllZF9xdWFsaXR5X3BocmVkIDE1IFwKICAgIC0tbGVuZ3RoX3JlcXVpcmVkIDIwIFwKICAgIC0tcmVwb3J0X3RpdGxlICJTUlI1ODU1NzAiIFwKICAgIC0tanNvbiBRQy9nYXN0cmljLWNhbmNlci9mYXN0cC9TUlI1ODU1NzAvU1JSNTg1NTcwX2Zhc3RwLmpzb24gXAogICAgLS1odG1sIFFDL2dhc3RyaWMtY2FuY2VyL2Zhc3RwL1NSUjU4NTU3MC9TUlI1ODU1NzBfZmFzdHAuaHRtbApgYGAKCkJlbG93LCB3ZSdsbCB3YWxrIHRocm91Z2ggdGhlIGFyZ3VtZW50cy9vcHRpb25zIHdlIHVzZWQgdG8gcnVuIGBmYXN0cGAuCkJ5IGRlZmF1bHQsIGZhc3RwIHBlcmZvcm1zIGFkYXB0ZXIgdHJpbW1pbmcsIHdoaWNoIHlvdSBjYW4gcmVhZCBtb3JlIGFib3V0IFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vT3BlbkdlbmUvZmFzdHAjYWRhcHRlcnMpLgpGb3IgcGFpcmVkLWVuZCBkYXRhIGxpa2UgdGhlIGRhdGEgd2UgaGF2ZSBmb3IgU1JSNTg1NTcwLCBhZGFwdGVycyBjYW4gYmUgZGV0ZWN0ZWQgYXV0b21hdGljYWxseSB3aXRob3V0IHNwZWNpZnlpbmcgYW4gYWRhcHRlciBzZXF1ZW5jZS4KCiMjIyMgSW5wdXQ6IGAtaWAgYW5kIGAtSWAKClRoZXNlIGFyZ3VtZW50cyBzcGVjaWZ5IHRoZSByZWFkMSBpbnB1dCBhbmQgcmVhZDIgKHNvbWV0aW1lcyBjYWxsZWQgbGVmdCBhbmQgcmlnaHQpIGlucHV0LCByZXNwZWN0aXZlbHkuCgojIyMjIGZhc3RxIG91dHB1dDogYC1vYCBhbmQgYC1PYAoKVGhlc2UgYXJndW1lbnRzIHNwZWNpZnkgdGhlIHJlYWQxIG91dHB1dCBhbmQgcmVhZDIgb3V0cHV0LCByZXNwZWN0aXZlbHkuCk5vdGUgdGhhdCB0aGUgb3V0cHV0IGlzIGJlaW5nIHBsYWNlZCBpbiBgZGF0YS9nYXN0cmljLWNhbmNlci9mYXN0cS10cmltbWVkL1NSUjU4NTU3MC9gLCBzbyB0aGUgcHJvY2Vzc2VkIEZBU1RRIGZpbGVzIHdpbGwgYmUga2VwdCBzZXBhcmF0ZSBmcm9tIGZyb20gdGhlIG9yaWdpbmFsIGZpbGVzLgpJdCBpcyBnZW5lcmFsbHkgZ29vZCBwcmFjdGljZSB0byB0cmVhdCB5b3VyICJyYXciIGRhdGEgYW5kIGl0cyBkaXJlY3RvcmllcyBhcyBmaXhlZCBhbmQgc2VwYXJhdGUgZnJvbSBhbnkgcHJvY2Vzc2luZyBhbmQgYW5hbHlzaXMgdGhhdCB5b3UgZG8sIHRvIHByZXZlbnQgYWNjaWRlbnRhbGx5IG1vZGlmaWNhdGlvbiBvZiB0aG9zZSBvcmlnaW5hbCBmaWxlcy4gCkFuZCBpbiB0aGUgZXZlbnQgdGhhdCB5b3UgYWNjaWRlbnRhbGx5IGRvIG1vZGlmeSB0aGUgb3JpZ2luYWxzLCB5b3Uga25vdyBleGFjdGx5IHdoaWNoIGZpbGVzIGFuZCBkaXJlY3RvcmllcyB0byByZXNldC4KCiMjIyMgYC0tcXVhbGlmaWVkX3F1YWxpdHlfcGhyZWRgCgpbUGhyZWQgc2NvcmVzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QaHJlZF9xdWFsaXR5X3Njb3JlKSBhcmUgdGhlIHF1YWxpdHkgaW5mb3JtYXRpb24gaW5jbHVkZWQgaW4gYSBGQVNUUSBmaWxlIGFuZCB0aGUgdmFsdWVzIGluZGljYXRlIHRoZSBjaGFuY2VzIHRoYXQgYSBiYXNlIGlzIGNhbGxlZCBpbmNvcnJlY3RseS4gTGV0J3MgbG9vayBhdCBhIHNjcmVlbnNob3Qgb2YgdGhlIFBlciBCYXNlIFNlcXVlbmNlIFF1YWxpdHkgbW9kdWxlIGZyb20gW0Zhc3RRQyBiYWQgSWxsdW1pbmEgZXhhbXBsZV0oaHR0cHM6Ly93d3cuYmlvaW5mb3JtYXRpY3MuYmFicmFoYW0uYWMudWsvcHJvamVjdHMvZmFzdHFjL2JhZF9zZXF1ZW5jZV9mYXN0cWMuaHRtbCkgd2UgbGlua2VkIHRvIGFib3ZlLgoKIVtwZXItYmFzZS1xdWFsaXR5LXNjcmVlbnNob3RdKGh0dHBzOi8vdXNlci1pbWFnZXMuZ2l0aHVidXNlcmNvbnRlbnQuY29tLzE5NTM0MjA1LzU5MjkyMzE2LWQ2MjkyNTAwLThjNGEtMTFlOS05NjdiLTEzMmJkOGM1NDU3Ny5wbmcpCgpBbnl0aGluZyBiZWxvdyAyMCwgd2hlcmUgYSBQaHJlZCBzY29yZSBvZiAyMCByZXByZXNlbnRzIGEgMSBpbiAxMDAgY2hhbmNlIHRoYXQgdGhlIGNhbGwgaXMgaW5jb3JyZWN0LCBpcyBjb25zaWRlcmVkIHBvb3IgcXVhbGl0eSBieSBGYXN0UUMuClVzaW5nIGAtLXF1YWxpZmllZF9xdWFsaXR5X3BocmVkIDE1YCAod2hpY2ggaXMgdGhlIGRlZmF1bHQpLCBtZWFucyBzY29yZXMgPj0gMTUgYXJlIGNvbnNpZGVyZWQgInF1YWxpZmllZC4iClVzaW5nIHRoZSBkZWZhdWx0IHBhcmFtZXRlcnMgYXMgd2UgZG8gaGVyZSwgcmVhZHMgd2lsbCBiZSBmaWx0ZXJlZCBvdXQgaWYgPjQwJSBvZiB0aGUgYmFzZXMgYXJlIHVucXVhbGlmaWVkLgpZb3UgY2FuIHJlYWQgbW9yZSBhYm91dCB0aGUgKipxdWFsaXR5IGZpbHRlcmluZyoqIGZ1bmN0aW9uYWxpdHkgb2YgZmFzdHAgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9PcGVuR2VuZS9mYXN0cC9ibG9iL21hc3Rlci9SRUFETUUubWQjcXVhbGl0eS1maWx0ZXIpLgpUaGUgU2FsbW9uIGRvY3VtZW50YXRpb24gbm90ZXMgdGhhdCwgZ2l2ZW4gdGhlIHdheSB3ZSBydW4gYHNhbG1vbiBxdWFudGAsIHF1YW50aWZpY2F0aW9uIG1heSBiZSBtb3JlIHNlbnNpdGl2ZSB0byBjYWxscyB0aGF0IGFyZSBsaWtlbHkgdG8gYmUgZXJyb25lb3VzIChvZiBsb3cgcXVhbGl0eSkgYW5kLCB0aGVyZWZvcmUsIHF1YWxpdHkgdHJpbW1pbmcgbWF5IGJlIGltcG9ydGFudC4KClRyaW1taW5nLCBpbiBjb250cmFzdCB0byBmaWx0ZXJpbmcsIHJlZmVycyB0byByZW1vdmluZyBsb3cgcXVhbGl0eSBiYXNlIGNhbGxzIGZyb20gdGhlICh0eXBpY2FsbHkgMycpIGVuZCBvZiByZWFkcy4KQSByZWNlbnQgcGFwZXIgZnJvbSB0aGUgU2FsbW9uIGF1dGhvcnMgKFtTcml2YXN0YXZhIF9ldCBhbC5fIDIwMjBdKGh0dHBzOi8vZG9pLm9yZy8xMC4xMTg2L3MxMzA1OS0wMjAtMDIxNTEtOCkpIG5vdGVzIHRoYXQgdHJpbW1pbmcgZGlkIG5vdCBhZmZlY3QgbWFwcGluZyByYXRlcyBmcm9tIHJhbmRvbSBwdWJsaWNseSBhdmFpbGFibGUgaHVtYW4gYnVsayAocGFpcmVkLWVuZCkgUk5BLXNlcSBzYW1wbGVzICh0aGV5IHVzZWQgW1RyaW1HYWxvcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9GZWxpeEtydWVnZXIvVHJpbUdhbG9yZSkpLgpmYXN0cCBkb2VzIGhhdmUgW3RoZSBmdW5jdGlvbmFsaXR5XShodHRwczovL2dpdGh1Yi5jb20vT3BlbkdlbmUvZmFzdHAjcGVyLXJlYWQtY3V0dGluZy1ieS1xdWFsaXR5LXNjb3JlKSB0byBwZXJmb3JtIHRyaW1taW5nIHVzaW5nIGEgc2xpZGluZyB3aW5kb3csIHdoaWNoIG11c3QgYmUgZW5hYmxlZC4KV2UgYXJlIG5vdCB1c2luZyBpdCBoZXJlLgoKX05vdGUgdGhhdCB0aGVyZSBhcmUgdHdvIGtpbmRzIG9mIGVuY29kaW5nIGZvciBQaHJlZCBzY29yZXM6IFBocmVkIDMzIGVuY29kaW5nIGFuZCBQaHJlZCA2NCBlbmNvZGluZy4KRmFzdFFDIGd1ZXNzZWQgdGhhdCB0aGUgZmlsZSBmb3IgU1JSNTg1NTcwIHVzZXMgU2FuZ2VyL0lsbHVtaW5hIDEuOSBlbmNvZGluZyAoUGhyZWQgMzMpLgpJZiB3ZSBoYWQgUGhyZWQgNjQgZGF0YSwgd2UnZCB1c2UgdGhlIGAtLXBocmVkNjRgIGZsYWcuCllvdSBjYW4gcmVhZCBhIGxpdHRsZSBiaXQgbW9yZSBhYm91dCB0aGUgZW5jb2RpbmcgW2hlcmVdKGh0dHA6Ly9yZXNvdXJjZXMucWlhZ2VuYmlvaW5mb3JtYXRpY3MuY29tL21hbnVhbHMvY2xjZ2Vub21pY3N3b3JrYmVuY2gvNzAwL1F1YWxpdHlfc2NvcmVzX2luX0lsbHVtaW5hX3BsYXRmb3JtLmh0bWwpLl8KCiMjIyMgYC0tbGVuZ3RoX3JlcXVpcmVkYAoKVHJpbW1pbmcgcmVhZHMgbWF5IHJlc3VsdCBpbiBzaG9ydCByZWFkcywgd2hpY2ggbWF5IGFmZmVjdCBnZW5lIGV4cHJlc3Npb24gZXN0aW1hdGVzIChbV2lsbGlhbXMgZXQgYWwuIF9CTUMgQmlvaW5mb3JtYXRpY3MuXyAyMDE2Ll0oaHR0cHM6Ly9kb2kub3JnLzEwLjExODYvczEyODU5LTAxNi0wOTU2LTIpKS4KVXNpbmcgYC0tbGVuZ3RoX3JlcXVpcmVkIDIwYCBtZWFucyB0aGF0IHJlYWRzIHNob3J0ZXIgdGhhbiAyMGJwIHdpbGwgYmUgZGlzY2FyZGVkIChzaW1pbGFyIHRvIHdoYXQgd2FzIHVzZWQgaW4gU3JpdmFzdGF2YSBldCBhbC4gYWJvdmUpLgoKIyMjIyBgLS1yZXBvcnRfdGl0bGVgCgpXaGVuIHdlIGxvb2sgYXQgdGhlIEhUTUwgcmVwb3J0LCBpdCdzIGhlbHBmdWwgdG8gcXVpY2tseSBpZGVudGlmeSB3aGF0IHNhbXBsZSB0aGUgcmVwb3J0IGlzIGZvci4gVXNpbmcgYC0tcmVwb3J0IHRpdGxlICJTUlI1ODU1NzAiYCBtZWFucyB0aGF0IHRoZSByZXBvcnQgd2lsbCBiZSB0aXRsZWQgIlNSUjU4NTU3MCIgcmF0aGVyIHRoYW4gdGhlIGRlZmF1bHQgKCJmYXN0cCByZXBvcnQiKS4KCiMjIyMgYC0tanNvbmAgYW5kIGAtLWh0bWxgCgpXaXRoIHRoZXNlIG9wdGlvbnMsIHdlJ3JlIHNwZWNpZnlpbmcgd2hlcmUgdGhlIFtKU09OXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9KU09OKSBhbmQgSFRNTCByZXBvcnRzIHdpbGwgYmUgc2F2ZWQgKGluIHRoZSBgUUMvZ2FzdHJpYy1jYW5jZXIvZmFzdHAvYCBkaXJlY3Rvcnkgd2UgY3JlYXRlZCkgYW5kIHdoYXQgdGhlIGZpbGVuYW1lcyB3aWxsIGJlLgpJbmNsdWRpbmcgdGhlIHNhbXBsZSBuYW1lIGluIHRoZSBmaWxlbmFtZXMgYWdhaW4gbWF5IGhlbHAgdXMgd2l0aCBwcm9qZWN0IG9yZ2FuaXphdGlvbi4KCioqSWYgd2UgbG9vayBhdCoqIGBRQy9nYXN0cmljLWNhbmNlci9mYXN0cC9TUlI1ODU1NzBfZmFzdHAuanNvbmAgKipvciB0aGUgdG9wIG9mIHRoZSBIVE1MIHJlcG9ydCwgd2UgY2FuIHNlZSB0aGF0IGZhc3RwIHJlcG9ydHMgY2VydGFpbiBtZXRyaWNzIGJlZm9yZSBhbmQgYWZ0ZXIgZmlsdGVyaW5nLCB3aGljaCBjYW4gYmUgdmVyeSB1c2VmdWwgaW4gbWFraW5nIGFuYWx5c2lzIGRlY2lzaW9ucy4qKgoKIyMgUXVhbnRpZmljYXRpb24gd2l0aCBTYWxtb24KCiFbXShkaWFncmFtcy9ybmEtc2VxXzQucG5nKQoKV2UnbGwgdXNlIFtTYWxtb25dKGh0dHBzOi8vY29tYmluZS1sYWIuZ2l0aHViLmlvL3NhbG1vbi8pIGZvciBxdWFudGlmeWluZyB0cmFuc2NyaXB0IGV4cHJlc3Npb24gKFtkb2N1bWVudGF0aW9uXShodHRwOi8vc2FsbW9uLnJlYWR0aGVkb2NzLmlvL2VuL2xhdGVzdC8pKS4KU2FsbW9uIChbUGF0cm8sIGV0IGFsLiBfTmF0dXJlIE1ldGhvZHMuXyAyMDE3Ll0oaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvbm1ldGguNDE5NykpIGlzIGZhc3QgYW5kIHJlcXVpcmVzIHZlcnkgbGl0dGxlIG1lbW9yeSwgd2hpY2ggbWFrZXMgaXQgYSBncmVhdCBjaG9pY2UgZm9yIHJ1bm5pbmcgb24geW91ciBsYXB0b3AgZHVyaW5nIHRyYWluaW5nLgpXZSBjYW4gdXNlIHRoZSBvdXRwdXQgZm9yIGRvd25zdHJlYW0gYW5hbHlzZXMgbGlrZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcyBhbmQgY2x1c3RlcmluZy4KV2UgdXNlIFNhbG1vbiBpbiBtYXBwaW5nIG1vZGUsIHdpdGggbWFwcGluZyB2YWxpZGF0aW9uIGVuYWJsZWQsIHVzaW5nIHRoZSBmb2xsb3dpbmcgY29tbWFuZDoKCmBgYGJhc2gKIyBXZSBwZXJmb3JtIHF1YW50aWZpY2F0aW9uIG9uIHRoZSBmaWxlcyB0aGF0IGhhdmUgYmVlbiB0cmltbWVkCiMgYW5kIHVzZSB0aGUgaW5kZXggZ2VuZXJhdGVkIHdpdGggLWsgMjMsIGFzIHRoaXMgbWF5ICJpbXByb3ZlIHNlbnNpdGl2aXR5IgojIHBlciB0aGUgU2FsbW9uIGRvY3VtZW50YXRpb24Kc2FsbW9uIHF1YW50IC1pIGluZGV4L0hvbW9fc2FwaWVucy9zaG9ydF9pbmRleCBcCiAgICAtbCBBIFwKICAgIC0xIGRhdGEvZ2FzdHJpYy1jYW5jZXIvZmFzdHEtdHJpbW1lZC9TUlI1ODU1NzAvU1JSNTg1NTcwX2Zhc3RwXzEuZmFzdHEuZ3ogXAogICAgLTIgZGF0YS9nYXN0cmljLWNhbmNlci9mYXN0cS10cmltbWVkL1NSUjU4NTU3MC9TUlI1ODU1NzBfZmFzdHBfMi5mYXN0cS5neiBcCiAgICAtbyBkYXRhL2dhc3RyaWMtY2FuY2VyL3NhbG1vbl9xdWFudC9TUlI1ODU1NzAgXAogICAgLS12YWxpZGF0ZU1hcHBpbmdzIC0tcmFuZ2VGYWN0b3JpemF0aW9uQmlucyA0IFwKICAgIC0tZ2NCaWFzIC0tc2VxQmlhcyBcCiAgICAtLXRocmVhZHMgNApgYGAKCkJlbG93LCB3ZSdsbCB3YWxrIHRocm91Z2ggdGhlIGFyZ3VtZW50cy9vcHRpb25zIHdlIHVzZWQgdG8gcnVuIGBzYWxtb24gcXVhbnRgLgoKIyMjIyBUcmFuc2NyaXB0b21lIGluZGV4OiBgLWlgCgpTYWxtb24gcmVxdWlyZXMgYSBzZXQgb2YgdHJhbnNjcmlwdHMgKHdoYXQgd2Ugd2FudCB0byBxdWFudGlmeSkgaW4gdGhlIGZvcm0gb2YgYSB0cmFuc2NyaXB0b21lIGluZGV4IGJ1aWx0IHdpdGggYHNhbG1vbiBpbmRleGAuCkJ1aWxkaW5nIGFuIGluZGV4IGNhbiB0YWtlIGEgd2hpbGUgKGJ1dCB5b3Ugb25seSBoYXZlIHRvIGRvIGl0IG9uY2UhKSwgc28gd2UndmUgYnVpbHQgdGhlIG9uZSB3ZSB1c2UgdG9kYXkgYWhlYWQgb2YgdGltZS4KQmVmb3JlIHdlIHVzZSBpdCwgd2UnbGwgdGFrZSBhIG1vbWVudCB0byBnaXZlIGEgYml0IG9mIGJhY2tncm91bmQuCgpZb3UgY2FuIHNlZSBob3cgd2Ugb2J0YWluZWQgdGhpcyBpbmRleCBhbmQgb3RoZXJzIFtvbiBHaXRIdWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9BbGV4c0xlbW9uYWRlL3RyYWluaW5nLXR4b21lLXByZXApLgpOb3RlIHRoYXQgd2UgdXNlZCBIb21vIHNhcGllbnMgR1JDaDM4LCBFbnNlbWJsIHJlbGVhc2UgOTUuCkl0IGlzIGltcG9ydGFudCB0byBrZWVwIHRyYWNrIG9mIHdoYXQgYnVpbGQsIHJlc291cmNlLCBhbmQgZmlsZXMgd2VyZSB1c2VkIGFuZCBwdXR0aW5nIG91ciBzaGVsbCBzY3JpcHRzIG9uIEdpdEh1YiBhbGxvd3MgdXMgdG8gZG8gdGhhdC4gIAoKVGhlIGBzYWxtb24gaW5kZXhgIGNvbW1hbmQgaGFzIGEgcGFyYW1ldGVyIGAta2Agd2hpY2ggc2V0cyB0aGUgay1tZXIgbGVuZ3RoLgpUaGUgaW5kZXggd2UgdXNlZCB3YXMgYnVpbHQgd2l0aCBgLWsgMjNgIGFuZCBjYW4gYmUgZm91bmQgaGVyZToKCmBgYAppbmRleC9Ib21vX3NhcGllbnMvc2hvcnRfaW5kZXgKYGBgCgpVc2luZyBhIHNtYWxsZXIgdmFsdWUgZm9yIF9rXyB0aGFuIHRoZSBkZWZhdWx0IChfa18gPSAzMSkgaXMgYXBwcm9wcmlhdGUgZm9yIHNob3J0ZXIgcmVhZHMgYW5kIG1heSBpbXByb3ZlIHNlbnNpdGl2aXR5IHdoZW4gdXNpbmcgYC0tdmFsaWRhdGVNYXBwaW5nc2AgYWNjb3JkaW5nIHRvIHRoZSBbU2FsbW9uIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vc2FsbW9uLnJlYWR0aGVkb2NzLmlvL2VuL2xhdGVzdC9zYWxtb24uaHRtbCNwcmVwYXJpbmctdHJhbnNjcmlwdG9tZS1pbmRpY2VzLW1hcHBpbmctYmFzZWQtbW9kZSkuCgojIyMjIGAtbGAKCldlIHVzZSBgLWwgQWAgdG8gYWxsb3cgU2FsbW9uIHRvIGF1dG9tYXRpY2FsbHkgaW5mZXIgdGhlIGxpYnJhcnkgdHlwZSBiYXNlZCBvbiBhIHN1YnNldCBvZiByZWFkcywgYnV0IHlvdSBjYW4gYWxzbyBwcm92aWRlIHRoZSBbbGlicmFyeSB0eXBlXShodHRwOi8vc2FsbW9uLnJlYWR0aGVkb2NzLmlvL2VuL2xhdGVzdC9zYWxtb24uaHRtbCN3aGF0LXMtdGhpcy1saWJ0eXBlKSB0byBTYWxtb24gd2l0aCB0aGlzIGFyZ3VtZW50LgoKIyMjIyBJbnB1dDogYC0xYCBhbmQgYC0yYAoKVGhlc2UgZGF0YSBhcmUgcGFpcmVkLWVuZCwgd2UgdXNlIGAtMWAgYW5kIGAtMmAgdG8gc3BlY2lmeSByZWFkMSBhbmQgcmVhZDIsIHJlc3BlY3RpdmVseS4KCiMjIyMgYC1vYAoKT3V0cHV0IGRpcmVjdG9yeSwgYHNhbG1vbiBxdWFudGAgc2hvdWxkIGNyZWF0ZSB0aGlzIGZvciB1cyBpZiBpdCBkb2Vzbid0IGV4aXN0IHlldC4KCiMjIyMgYC0tdmFsaWRhdGVNYXBwaW5nc2AgYW5kIGAtLXJhbmdlRmFjdG9yaXphdGlvbkJpbnNgCgpVc2luZyBgLS12YWxpZGF0ZU1hcHBpbmdzYCBlbmFibGVzIG1hcHBpbmcgdmFsaWRhdGlvbiwgd2hlcmUgU2FsbW9uIGNoZWNrcyBpdHMgbWFwcGluZ3MgdXNpbmcgdHJhZGl0aW9uYWwgYWxpZ25tZW50LgpUaGlzIGhlbHBzIHByZXZlbnQgInNwdXJpb3VzIG1hcHBpbmdzIiB3aGVyZSBhIHJlYWQgbWFwcyB0byBhIHRhcmdldCBidXQgZG9lcyBub3QgYXJpc2UgZnJvbSBpdCAoc2VlIFtkb2N1bWVudGF0aW9uIGZvciBmbGFnXShodHRwczovL3NhbG1vbi5yZWFkdGhlZG9jcy5pby9lbi9sYXRlc3Qvc2FsbW9uLmh0bWwjdmFsaWRhdGVtYXBwaW5ncykgYW5kIHRoZSBbcmVsZWFzZSBub3RlcyBmb3IgYHYwLjEwLjBgXShodHRwczovL2dpdGh1Yi5jb20vQ09NQklORS1sYWIvc2FsbW9uL3JlbGVhc2VzL3RhZy92MC4xMC4wKSB3aGVyZSB0aGlzIHdhcyBpbnRyb2R1Y2VkKS4KCldoZW4gZW5hYmxpbmcgbWFwcGluZyB2YWxpZGF0aW9uIHdpdGggYC0tdmFsaWRhdGVNYXBwaW5nc2AsIHNldHRpbmcgYC0tcmFuZ2VGYWN0b3JpemF0aW9uQmlucyA0YCBjYW4gaW1wcm92ZSBxdWFudGlmaWNhdGlvbiBmb3IgY2VydGFpbiBjbGFzc2VzIG9mIHRyYW5zY3JpcHRzIChbZG9jc10oaHR0cHM6Ly9zYWxtb24ucmVhZHRoZWRvY3MuaW8vZW4vbGF0ZXN0L3NhbG1vbi5odG1sI3JhbmdlZmFjdG9yaXphdGlvbmJpbnMpKS4KCiMjIyMgYC0tZ2NCaWFzYAoKV2l0aCB0aGlzIG9wdGlvbiBlbmFibGVkLCBTYWxtb24gd2lsbCBhdHRlbXB0IHRvIGNvcnJlY3QgZm9yIGZyYWdtZW50IEdDLWJpYXMuClJlZ2lvbnMgd2l0aCBoaWdoIG9yIGxvdyBHQyBjb250ZW50IHRlbmQgdG8gYmUgdW5kZXJyZXByZXNlbnRlZCBpbiBzZXF1ZW5jaW5nIGRhdGEuCgpJdCBzaG91bGQgYmUgbm90ZWQgdGhhdCB0aGlzIGlzIG9ubHkgYXBwcm9wcmlhdGUgZm9yIHVzZSB3aXRoIHBhaXJlZC1lbmQgcmVhZHMsIGFzIGZyYWdtZW50IGxlbmd0aCBjYW4gbm90IGJlIGluZmVycmVkIGZyb20gc2luZ2xlLWVuZCByZWFkcyAoc2VlIFt0aGlzIEdpdEh1YiBpc3N1ZV0oaHR0cHM6Ly9naXRodWIuY29tL0NPTUJJTkUtbGFiL3NhbG1vbi9pc3N1ZXMvODMpKS4KCiMjIyMgYC0tc2VxQmlhc2AKCldpdGggdGhpcyBvcHRpb24gZW5hYmxlZCwgU2FsbW9uIHdpbGwgYXR0ZW1wdCB0byBjb3JyZWN0IGZvciB0aGUgYmlhcyB0aGF0IG9jY3VycyB3aGVuIHVzaW5nIHJhbmRvbSBoZXhhbWVyIHByaW1pbmcgKHByZWZlcmVudGlhbCBzZXF1ZW5jaW5nIG9mIHJlYWRzIHdoZW4gY2VydGFpbiBtb3RpZnMgYXBwZWFyIGF0IHRoZSBiZWdpbm5pbmcpLgoKIyMjIyBgLS10aHJlYWRzYAoKVGhlIGAtLXRocmVhZHNgIGFyZ3VtZW50IGNvbnRyb2xzIHRoZSBudW1iZXIgb2YgdGhyZWFkcyB0aGF0IGFyZSBhdmFpbGFibGUgdG8gU2FsbW9uIGR1cmluZyBxdWFudGlmaWNhdGlvbi4KVGhpcyBpbiBlc3NlbmNlIGNvbnRyb2xzIGhvdyBtdWNoIG9mIHRoZSBtYXBwaW5nIGNhbiBvY2N1ciBpbiBwYXJhbGxlbC4KSWYgeW91IGhhZCBhY2Nlc3MgdG8gYSBjb21wdXRlciB3aXRoIG1hbnkgY29yZXMsIHlvdSBjb3VsZCBpbmNyZWFzZSB0aGUgbnVtYmVyIG9mIHRocmVhZHMgdG8gbWFrZSBxdWFudGlmaWNhdGlvbiBnbyBmYXN0ZXIuCgoqKk5hdmlnYXRlIHRvKiogYGRhdGEvZ2FzdHJpYy1jYW5jZXIvc2FsbW9uX3F1YW50L1NSUjU4NTU3MS9hdXhfaW5mb2AgKiphbmQgb3BlbioqIGBtZXRhX2luZm8uanNvbmAqKi4KTG9vayBmb3IgYSBmaWVsZCBjYWxsZWQqKiBgcGVyY2VudF9tYXBwZWRgICoqLS0gd2hhdCB2YWx1ZSBkb2VzIHRoaXMgc2FtcGxlIGhhdmU/KioK