Obtaining raw reads
Before we can begin the analysis, we need to make our raw sequencing
data accessible within the same computing environment that we are going
to use for analysis. Assuming that you will be using a computing node
without a GUI, this can be a non-trivial task. For example, we cannot
easily drag-and-drop the files from one location to another or click a
download link. Therefore we will introduce some commands for
transferring files, compressing and de-compressing and checking file
integrity.
Lets create a temporary directory to test these tools:-
cd
mkdir tmp
cd tmp
Use wget
to download from a remote location
If your data are hosted on a website or FTP site, you can use the
wget
command to download to the current working directory.
A small fastq
file is provided on the Sheffield
Bioinformatics Core website as an example. The output updates you on the
progress of the download.
Note that if downloading from an FTP site you might be prompted for a
username and password.
wget http://sbc.shef.ac.uk/data/example_reads.fastq
ls -lh
The contents of the file can be printed to the screen using the
head
command you should have learnt about previously
head -n 4 example_reads.fastq
Details on the FASTQ format
Although it looks complicated (and it is), we can understand the fastq format with
a little decoding. Some rules about the format include…
1 |
Always begins with ‘@’ and then information about the read |
2 |
The actual DNA sequence |
3 |
Always begins with a ‘+’ and sometimes the same info in line 1 |
4 |
Has a string of characters which represent the quality scores; must
have same number of characters as line 2 |
@SRR2584863.1 HWI-ST957:244:H73TDADXX:1:1101:4712:2181/1
TTCACATCCTGACCATTCAGTTGAGCAAAATAGTTCTTCAGTGCCTGTTTAACCGAGTCACGCAGGGGTTTTTGGGTTACCTGATCCTGAGAGTTAACGGTAGAAACGGTCAGTACGTCAGAATTTACGCGTTGTTCGAACATAGTTCTG
+
CCCFFFFFGHHHHJIJJJJIJJJIIJJJJIIIJJGFIIIJEDDFEGGJIFHHJIJJDECCGGEGIIJFHFFFACD:BBBDDACCCCAA@@CA@C>C3>@5(8&>C:9?8+89<4(:83825C(:A#########################
Line 4 shows the quality for each nucleotide in the read. Quality is
interpreted as the probability of an incorrect base call (e.g. 1 in 10)
or, equivalently, the base call accuracy (e.g. 90%). To make it possible
to line up each individual nucleotide with its quality score, the
numerical score is converted into a code where each individual character
represents the numerical quality score for an individual nucleotide. For
example, in the line above, the quality score line is:
CCCFFFFFGHHHHJIJJJJIJJJIIJJJJIIIJJGFIIIJEDDFEGGJIFHHJIJJDECCGGEGIIJFHFFFACD:BBBDDACCCCAA@@CA@C>C3>@5(8&>C:9?8+89<4(:83825C(:A#########################
The numerical value assigned to each of these characters depends on
the sequencing platform that generated the reads. The sequencing machine
used to generate our data uses the standard Sanger quality PHRED score
encoding, using Illumina version 1.8 onwards. Each character is assigned
a quality score between 0 and 41 as shown in the chart below.
Quality encoding: !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJ
| | | | |
Quality score: 01........11........21........31........41
Each quality score represents the probability that the corresponding
nucleotide call is incorrect. This quality score is logarithmically
based, so a quality score of 10 reflects a base call accuracy of 90%,
but a quality score of 20 reflects a base call accuracy of 99%. These
probability values are the results from the base calling algorithm and
depend on how much signal was captured for the base incorporation.
@SRR2584863.1 HWI-ST957:244:H73TDADXX:1:1101:4712:2181/1
TTCACATCCTGACCATTCAGTTGAGCAAAATAGTTCTTCAGTGCCTGTTTAACCGAGTCACGCAGGGGTTTTTGGGTTACCTGATCCTGAGAGTTAACGGTAGAAACGGTCAGTACGTCAGAATTTACGCGTTGTTCGAACATAGTTCTG
+
CCCFFFFFGHHHHJIJJJJIJJJIIJJJJIIIJJGFIIIJEDDFEGGJIFHHJIJJDECCGGEGIIJFHFFFACD:BBBDDACCCCAA@@CA@C>C3>@5(8&>C:9?8+89<4(:83825C(:A#########################
Since this file is so small, we needn’t worry about the file size.
However, in a real life experiment our raw sequencing reads can be many
10s of Gb in size. It is common practice to compress the file so that it
takes less space on disk. The standard way of achieving this in Unix
systems is to use the gzip
command. A side-effect of the
compression is that the resulting file can no longer be printed with
cat
. However, a zcat
command can be used to
the same effect.
##example of compressing the file
gzip example_reads.fastq
## list the directory to see what changed...
ls -lh
## Now have to use zcat to print...
zcat example_reads.fastq | head -n4
Download an archived directory
Another popular technique for compressing and transfering a
collection of files is to organise them into a single file (or
tarball), which can then be compressed. Such a file is also
available on the Sheffield Bioinformatics Core website for demonstration
purposes. The wget
command can be used as before.
wget http://sbc.shef.ac.uk/data/archive.tar.gz
ls
The tar
command with the options zxvf
(look
these up if you want to understand more) can be used to create a
directory structure containing all the files.
tar zxvf archive.tar.gz
ls
Checking the download worked
Having downloaded all your files, you should probably check they have
been downloaded successfully and been corrupted in transit. Partial or
incomplete files can be a source of errors later on in the analysis. If
you are downloading many files, it can be difficult to spot if a file
failed to download. A simple way is to check the file sizes, but this
can be unreliable.
A common way of doing this is to generate an md5sum from the
file. You can think of this as a unique digital barcode of a text file.
The same file will always give the same md5sum. Sequencing vendors will
often calculate these files on their servers and send the results to you
in the form of a text file that you can use to check. Note that for
large fastq files, these can take several minutes to compute.
### show md5sum for a particular file
md5sum fastq/Sample1/Sample1.fastq
## help is available on the function
md5sum --help
To see what would happen if a file didn’t transfer properly, we can
create a copy of Sample1.fastq
containing fewer lines. The
resulting md5sum will be different
## Use > to redirect the output
head fastq/Sample1/Sample1.fastq > fastq/Sample1/Sample1_sub.fastq
md5sum fastq/Sample1/Sample1_sub.fastq
Challenge 1
- Download the pre-computed md5sums available at
http://sbc.shef.ac.uk/data/archive_md5.txt
.
- Print the contents of this file and verify that the sum for
Sample1.fastq is correct
- The md5sum command is able to check the md5sums for a collection of
files against some pre-computed values. Use documentation (and google!)
to discover how to do this for the files we have downloaded.
Obtaining public data and About the example data
A good resource for obtaining public data is the SRA explorer.
In the Search box you can enter the accession number of a study
(usually quoted in the published paper), to obtain download links for
all the fastq files. It will even generate a bash script for you to
run.
The data for this tutorial comes from the paper, Induction of
fibroblast senescence generates a non-fibrogenic myofibroblast phenotype
that differentially impacts on cancer prognosis..
Cancer associated fibroblasts characterized by an myofibroblastic
phenotype play a major role in the tumour microenvironment, being
associated with poor prognosis. We found that this cell population is
made in part by senescent fibroblasts in vivo. As senescent fibroblasts
and myofibroblasts have been shown to share similar tumour promoting
functions in vitro we compared the transcriptosomes of these two
fibroblast types and performed RNA-seq of human foetal foreskin
fibroblasts 2 (HFFF2) treated with 2ng/ml TGF-beta-1 to induce
myofibroblast differentiation or 10Gy gamma irradiation to induce
senescence. We isolated RNA 7 days upon this treatments changing the
medium 3 days before the RNA extraction.
The paper states a particular accession number that can be
used to access the data
This ID can be used to find the data on ArrayExpress, but is also
recognised by SRA explorer (you don’t need the [All
fields] text shown in the screenshot). Gene Expression Omnibus
(GSE..) or Sequencing Read Archive
(SRP…) identifiers are also recognised.
If the identifier is recognised the names of samples belonging to the
dataset will be shown. These can be selected and added to a collection.
From the saved datasets button (top-right) the user can then access
download links.
For this particular dataset we created a download script using the
links provided by SRA explorer. To keep the run-time of the workshop
short (and to keep computing requirements down), each raw file was
subset to a more manageable amount.
The example dataset consists of nine raw (fastq files). The files are
named according to names assigned when the data were uploaded to the
public repository. We can use a sample sheet to associate each of these
database names to something more memorable, and eventually the
biological conditions being studied (beyond the scope of what we will
cover today)
ERR732901_sub |
CTR_1 |
Control |
ERR732901_sub |
TGF_1 |
TGF_Treated |
… |
… |
… |
Assessing Quality using FastQC
In real life, you won’t be assessing the quality of your reads by
visually inspecting your FASTQ files. Rather, you’ll be using a software
program to assess read quality and filter out poor quality reads. We’ll
first use a program called FastQC
to visualize the quality of our reads. Later in our workflow, we’ll use
another program to filter out poor quality reads.
FastQC has a number of features which can give you a quick impression
of any problems your data may have, so you can take these issues into
consideration before moving forward with your analyses. Rather than
looking at quality scores for each individual read, FastQC looks at
quality collectively across all reads within a sample. The image below
shows a FastQC-generated plot that indicates a very high quality
sample:
The x-axis displays the base position in the read, and the y-axis
shows quality scores. In this example, the sample contains reads that
are 40 bp long. For each position, there is a box-and-whisker plot
showing the distribution of quality scores for all reads at that
position. The horizontal red line indicates the median quality score and
the yellow box shows the 2nd to 3rd quartile range. This means that 50%
of reads have a quality score that falls within the range of the yellow
box at that position. The whiskers show the range to the 1st and 4th
quartile.
For each position in this sample, the quality values do not drop much
lower than 32. This is a high quality score. The plot background is also
color-coded to identify good (green), acceptable (yellow), and bad (red)
quality scores.
Now let’s take a look at a quality plot on the other end of the
spectrum.
Here, we see positions within the read in which the boxes span a much
wider range. Also, quality scores drop quite low into the “bad” range,
particularly on the tail end of the reads. The FastQC tool produces
several other diagnostic plots to assess sample quality, in addition to
the one plotted above.
Running FastQC
We will be working with a set of sample data that is located in the
directory (rnaseq_data
). These files have been compressed,
so have the fastq.gz
extension. FastQC is happy with either
compressed on un-compressed files.
Navigate to your FASTQ dataset:
cd /home/dcuser/rnaseq_data
To run the FastQC program, we would normally have to tell our
computer where the program is located. In this particular case, FastQC
has been installed in a location that can be accessed from all
directories.
which fastqc
/usr/bin/fastqc
This is the first program we have seen that is specific to
NGS analysis, so might not be available on all file systems by
default.
FastQC can accept multiple file names as input, so we can use the
*.fastq.gz
wildcard to run FastQC on all of the FASTQ files
in this directory.
fastqc fastq/*.fastq.gz
You will see an automatically updating output message telling you the
progress of the analysis. It will start like this:
Started analysis of ERR732901_sub.fastq.gz
Approx 100% complete for ERR732901_sub.fastq.gz
Analysis complete for ERR732901_sub.fastq.gz
In total, it should take less than 1 minute for FastQC to run on all
of our FASTQ files. When the analysis completes, your prompt will
return. So your screen will look something like this:
Started analysis of ERR732909_sub.fastq.gz
Approx 100% complete for ERR732909_sub.fastq.gz
Analysis complete for ERR732909_sub.fastq.gz
The FastQC program has created several new files within our
/data/fastq
directory.
ls fastq/
ERR732901_sub.fastqc.html ERR732901_sub.fastqc.zip ERR732901_sub.fastq.gz ERR732901_sub.fastqc.html
....
For each input FASTQ file, FastQC has created a .zip
file and a .html
file. The .zip
file extension
indicates that this is actually a compressed set of multiple output
files. We’ll be working with these output files soon. The
.html
file is a stable webpage displaying the summary
report for each of our samples.
We want to keep our data files and our results files separate, so we
will move these output files into a new directory within our
results/
directory. If this directory does not exist, we
will have to create it.
## -p flag stops a message from appearing if the directory already exists
mkdir -p qc
mv fastq/*.html qc/
mv fastq/*.zip qc/
Combining the reports with multiqc
It can be quite tiresome to click through multiple QC reports and
compare the results for different samples. It is useful to have all the
QC plots on the same page so that we can more easily spot trends in the
data.
The multiqc tool has been designed for the tasks of aggregating qc
reports and combining into a single report that is easy to digest.
multiqc
multiqc --help
Challenge 2
Use the multiqc tool to create a single QC report for the dataset.
Look at the help for the tool, and figure out how to run the tool on the
fastqc output we have just generated. Make sure that
multiqc
creates saves the report file in the
qc
folder.
The environment that we are working inside includes a version of the
Firefox web browser. We can open a particular HTML file with firefox
using the command:-
firefox qc/ERR732901_sub.fastqc.html
If this doesn’t work, there is a File Explorer tool available in the
desktop environment that you can use to navigate to, and view the
files.
Challenge 3
Discuss your results with a neighbour. - Which samples most the
highest / lowest number of reads - Which sample(s) looks the best in
terms of per base sequence quality? - Which sample(s) look the
worst?
Click
Here for next part
LS0tDQp0aXRsZTogIkFzc2Vzc2luZyBSZWFkIFF1YWxpdHkiDQphdXRob3I6ICJNYXJrIER1bm5pbmciDQpkYXRlOiAnYHIgZm9ybWF0KFN5cy50aW1lKCksICJMYXN0IG1vZGlmaWVkOiAlZCAlYiAlWSIpYCcNCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY3NzOiBzdHlsZXNoZWV0cy9zdHlsZXMuY3NzDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsZXZhbD1GQUxTRSkNCmBgYA0KDQooQWRhcHRlZCBmcm9tIHRoZSBEYXRhIENhcnBlbnRyeSBHZW5vbWljcyB3cmFuZ2xpbmcgbWF0ZXJpYWxzIGF0Oi0gaHR0cHM6Ly9kYXRhY2FycGVudHJ5Lm9yZy93cmFuZ2xpbmctZ2Vub21pY3MvMDItcXVhbGl0eS1jb250cm9sL2luZGV4Lmh0bWwpDQoNCiMgT3ZlcnZpZXcNCg0KQ292ZXJlZCBpbiB0aGlzIHNlY3Rpb24NCg0KLSBVc2luZyB0aGUgY29tbWFuZCBsaW5lIHRvIGRvd25sb2FkIGZpbGVzDQotIENvbXByZXNzaW9uIGFuZCBkZS1jb21wcmVzc2lvbiBvZiBmaWxlcw0KLSBWZXJpZnlpbmcgdGhhdCBhIGRvd25sb2FkIHdhcyBjb21wbGV0ZWQNCi0gUXVhbGl0eSBhc3Nlc3NtZW50IG9mIHJhdyBzZXF1ZW5jaW5nIGRhdGENCi0gQ29tcGlsaW5nIG11bHRpcGxlIFFDIHJlcG9ydHMgaW50byBhIHNpbmdsZSBmaWxlDQoNCg0KIyBCaW9pbmZvcm1hdGljcyB3b3JrZmxvd3MNCg0KV2hlbiB3b3JraW5nIHdpdGggaGlnaC10aHJvdWdocHV0IHNlcXVlbmNpbmcgZGF0YSwgdGhlIHJhdyByZWFkcyB5b3UgZ2V0IG9mZiBvZiB0aGUgc2VxdWVuY2VyIHdpbGwgbmVlZCB0byBwYXNzDQp0aHJvdWdoIGEgbnVtYmVyIG9mICBkaWZmZXJlbnQgdG9vbHMgaW4gb3JkZXIgdG8gZ2VuZXJhdGUgeW91ciBmaW5hbCBkZXNpcmVkIG91dHB1dC4gVGhlIGV4ZWN1dGlvbiBvZiB0aGlzIHNldCBvZg0KdG9vbHMgaW4gYSBzcGVjaWZpZWQgb3JkZXIgaXMgY29tbW9ubHkgcmVmZXJyZWQgdG8gYXMgYSAqd29ya2Zsb3cqIG9yIGEgKnBpcGVsaW5lKi4gDQoNCkFuIGV4YW1wbGUgb2YgdGhlIHdvcmtmbG93IHdlIHdpbGwgYmUgdXNpbmcgZm9yIG91ciBSTkEtc2VxIGFuYWx5c2lzIGlzIHByb3ZpZGVkIGJlbG93IHdpdGggYSBicmllZg0KZGVzY3JpcHRpb24gb2YgZWFjaCBzdGVwLiANCg0KIVt3b3JrZmxvd10oaW1hZ2VzL3dvcmtmbG93LnBuZykNCg0KDQoxLiBRdWFsaXR5IGNvbnRyb2wgLSBBc3Nlc3NpbmcgcXVhbGl0eSB1c2luZyBGYXN0UUMNCjIuIEFsaWduIHJlYWRzIHRvIHJlZmVyZW5jZSBnZW5vbWUgDQozLiBRdWFudGlmaWNhdGlvbiB0byBvYnRhaW4gZ2VuZS1sZXZlbCBjb3VudHMgcG9zdC1hbGlnbm1lbnQgY2xlYW4tdXANCjQuIERpZmZlcmVudGlhbCBFeHByZXNzaW9uDQoNClRoZXNlIHdvcmtmbG93cyBpbiBiaW9pbmZvcm1hdGljcyBhZG9wdCBhIHBsdWctYW5kLXBsYXkgYXBwcm9hY2ggaW4gdGhhdCB0aGUgb3V0cHV0IG9mIG9uZSB0b29sIGNhbiBiZSBlYXNpbHkNCnVzZWQgYXMgaW5wdXQgdG8gYW5vdGhlciB0b29sIHdpdGhvdXQgYW55IGV4dGVuc2l2ZSBjb25maWd1cmF0aW9uLiBIYXZpbmcgc3RhbmRhcmRzIGZvciBkYXRhIGZvcm1hdHMgaXMgd2hhdCANCm1ha2VzIHRoaXMgZmVhc2libGUuIFN0YW5kYXJkcyBlbnN1cmUgdGhhdCBkYXRhIGlzIHN0b3JlZCBpbiBhIHdheSB0aGF0IGlzIGdlbmVyYWxseSBhY2NlcHRlZCBhbmQgYWdyZWVkIHVwb24gDQp3aXRoaW4gdGhlIGNvbW11bml0eS4gVGhlIHRvb2xzIHRoYXQgYXJlIHVzZWQgdG8gYW5hbHl6ZSBkYXRhIGF0IGRpZmZlcmVudCBzdGFnZXMgb2YgdGhlIHdvcmtmbG93IGFyZSB0aGVyZWZvcmUgDQpidWlsdCB1bmRlciB0aGUgYXNzdW1wdGlvbiB0aGF0IHRoZSBkYXRhIHdpbGwgYmUgcHJvdmlkZWQgaW4gYSBzcGVjaWZpYyBmb3JtYXQuICANCg0KKipBbHRob3VnaCB3ZSBhcmUgdXNpbmcgUk5BLXNlcSBhcyBhIGNhc2Ugc3R1ZHksIHRoZSBpbml0aWFsIHN0ZXBzIGZvciBvdGhlciBOR1MgdGVjaG5vbG9naWVzIGFyZSBoaWdobHktc2ltaWxhcioqDQoNCiMgT2J0YWluaW5nIHJhdyByZWFkcw0KDQpCZWZvcmUgd2UgY2FuIGJlZ2luIHRoZSBhbmFseXNpcywgd2UgbmVlZCB0byBtYWtlIG91ciByYXcgc2VxdWVuY2luZyBkYXRhIGFjY2Vzc2libGUgd2l0aGluIHRoZSBzYW1lIGNvbXB1dGluZyBlbnZpcm9ubWVudCB0aGF0IHdlIGFyZSBnb2luZyB0byB1c2UgZm9yIGFuYWx5c2lzLiBBc3N1bWluZyB0aGF0IHlvdSB3aWxsIGJlIHVzaW5nIGEgY29tcHV0aW5nIG5vZGUgd2l0aG91dCBhIEdVSSwgdGhpcyBjYW4gYmUgYSBub24tdHJpdmlhbCB0YXNrLiBGb3IgZXhhbXBsZSwgd2UgY2Fubm90IGVhc2lseSBkcmFnLWFuZC1kcm9wIHRoZSBmaWxlcyBmcm9tIG9uZSBsb2NhdGlvbiB0byBhbm90aGVyIG9yIGNsaWNrIGEgZG93bmxvYWQgbGluay4gVGhlcmVmb3JlIHdlIHdpbGwgaW50cm9kdWNlIHNvbWUgY29tbWFuZHMgZm9yIHRyYW5zZmVycmluZyBmaWxlcywgY29tcHJlc3NpbmcgYW5kIGRlLWNvbXByZXNzaW5nIGFuZCBjaGVja2luZyBmaWxlIGludGVncml0eS4NCg0KTGV0cyBjcmVhdGUgYSB0ZW1wb3JhcnkgZGlyZWN0b3J5IHRvIHRlc3QgdGhlc2UgdG9vbHM6LQ0KDQpgYGB7YmFzaCBldmFsPUZBTFNFfQ0KY2QNCm1rZGlyIHRtcA0KY2QgdG1wDQpgYGANCg0KDQojIyBVc2UgYHdnZXRgIHRvIGRvd25sb2FkIGZyb20gYSByZW1vdGUgbG9jYXRpb24NCg0KSWYgeW91ciBkYXRhIGFyZSBob3N0ZWQgb24gYSB3ZWJzaXRlIG9yIEZUUCBzaXRlLCB5b3UgY2FuIHVzZSB0aGUgYHdnZXRgIGNvbW1hbmQgdG8gZG93bmxvYWQgdG8gdGhlIGN1cnJlbnQgd29ya2luZyBkaXJlY3RvcnkuIEEgc21hbGwgYGZhc3RxYCBmaWxlIGlzIHByb3ZpZGVkIG9uIHRoZSBTaGVmZmllbGQgQmlvaW5mb3JtYXRpY3MgQ29yZSB3ZWJzaXRlIGFzIGFuIGV4YW1wbGUuIFRoZSBvdXRwdXQgdXBkYXRlcyB5b3Ugb24gdGhlIHByb2dyZXNzIG9mIHRoZSBkb3dubG9hZC4NCg0KTm90ZSB0aGF0IGlmIGRvd25sb2FkaW5nIGZyb20gYW4gRlRQIHNpdGUgeW91IG1pZ2h0IGJlIHByb21wdGVkIGZvciBhIHVzZXJuYW1lIGFuZCBwYXNzd29yZC4NCg0KYGBge2Jhc2ggZXZhbD1GQUxTRX0NCndnZXQgaHR0cDovL3NiYy5zaGVmLmFjLnVrL2RhdGEvZXhhbXBsZV9yZWFkcy5mYXN0cQ0KbHMgLWxoDQpgYGANCg0KVGhlIGNvbnRlbnRzIG9mIHRoZSBmaWxlIGNhbiBiZSBwcmludGVkIHRvIHRoZSBzY3JlZW4gdXNpbmcgdGhlIGBoZWFkYCBjb21tYW5kIHlvdSBzaG91bGQgaGF2ZSBsZWFybnQgYWJvdXQgcHJldmlvdXNseQ0KDQpgYGB7YmFzaCBldmFsPUZBTFNFfQ0KaGVhZCAtbiA0IGV4YW1wbGVfcmVhZHMuZmFzdHENCmBgYA0KDQojIyBEZXRhaWxzIG9uIHRoZSBGQVNUUSBmb3JtYXQNCg0KQWx0aG91Z2ggaXQgbG9va3MgY29tcGxpY2F0ZWQgKGFuZCBpdCBpcyksIHdlIGNhbiB1bmRlcnN0YW5kIHRoZQ0KW2Zhc3RxXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9GQVNUUV9mb3JtYXQpIGZvcm1hdCB3aXRoIGEgbGl0dGxlIGRlY29kaW5nLiBTb21lIHJ1bGVzIGFib3V0IHRoZSBmb3JtYXQNCmluY2x1ZGUuLi4NCg0KfExpbmV8RGVzY3JpcHRpb258DQp8LS0tLXwtLS0tLS0tLS0tLXwNCnwxfEFsd2F5cyBiZWdpbnMgd2l0aCAnQCcgYW5kIHRoZW4gaW5mb3JtYXRpb24gYWJvdXQgdGhlIHJlYWR8DQp8MnxUaGUgYWN0dWFsIEROQSBzZXF1ZW5jZXwNCnwzfEFsd2F5cyBiZWdpbnMgd2l0aCBhICcrJyBhbmQgc29tZXRpbWVzIHRoZSBzYW1lIGluZm8gaW4gbGluZSAxfA0KfDR8SGFzIGEgc3RyaW5nIG9mIGNoYXJhY3RlcnMgd2hpY2ggcmVwcmVzZW50IHRoZSBxdWFsaXR5IHNjb3JlczsgbXVzdCBoYXZlIHNhbWUgbnVtYmVyIG9mIGNoYXJhY3RlcnMgYXMgbGluZSAyfA0KDQoNCmBgYA0KQFNSUjI1ODQ4NjMuMSBIV0ktU1Q5NTc6MjQ0Okg3M1REQURYWDoxOjExMDE6NDcxMjoyMTgxLzENClRUQ0FDQVRDQ1RHQUNDQVRUQ0FHVFRHQUdDQUFBQVRBR1RUQ1RUQ0FHVEdDQ1RHVFRUQUFDQ0dBR1RDQUNHQ0FHR0dHVFRUVFRHR0dUVEFDQ1RHQVRDQ1RHQUdBR1RUQUFDR0dUQUdBQUFDR0dUQ0FHVEFDR1RDQUdBQVRUVEFDR0NHVFRHVFRDR0FBQ0FUQUdUVENURw0KKw0KQ0NDRkZGRkZHSEhISEpJSkpKSklKSkpJSUpKSkpJSUlKSkdGSUlJSkVEREZFR0dKSUZISEpJSkpERUNDR0dFR0lJSkZIRkZGQUNEOkJCQkREQUNDQ0NBQUBAQ0FAQz5DMz5ANSg4Jj5DOjk/OCs4OTw0KDo4MzgyNUMoOkEjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpgYGANCg0KDQpMaW5lIDQgc2hvd3MgdGhlIHF1YWxpdHkgZm9yIGVhY2ggbnVjbGVvdGlkZSBpbiB0aGUgcmVhZC4gUXVhbGl0eSBpcyBpbnRlcnByZXRlZCBhcyB0aGUNCnByb2JhYmlsaXR5IG9mIGFuIGluY29ycmVjdCBiYXNlIGNhbGwgKGUuZy4gMSBpbiAxMCkgb3IsIGVxdWl2YWxlbnRseSwgdGhlIGJhc2UgY2FsbA0KYWNjdXJhY3kgKGUuZy4gOTAlKS4gVG8gbWFrZSBpdCBwb3NzaWJsZSB0byBsaW5lIHVwIGVhY2ggaW5kaXZpZHVhbCBudWNsZW90aWRlIHdpdGggaXRzIHF1YWxpdHkNCnNjb3JlLCB0aGUgbnVtZXJpY2FsIHNjb3JlIGlzIGNvbnZlcnRlZCBpbnRvIGEgY29kZSB3aGVyZSBlYWNoIGluZGl2aWR1YWwgY2hhcmFjdGVyDQpyZXByZXNlbnRzIHRoZSBudW1lcmljYWwgcXVhbGl0eSBzY29yZSBmb3IgYW4gaW5kaXZpZHVhbCBudWNsZW90aWRlLiBGb3IgZXhhbXBsZSwgaW4gdGhlIGxpbmUNCmFib3ZlLCB0aGUgcXVhbGl0eSBzY29yZSBsaW5lIGlzOg0KDQpgYGANCkNDQ0ZGRkZGR0hISEhKSUpKSkpJSkpKSUlKSkpKSUlJSkpHRklJSUpFRERGRUdHSklGSEhKSUpKREVDQ0dHRUdJSUpGSEZGRkFDRDpCQkJEREFDQ0NDQUFAQENBQEM+QzM+QDUoOCY+Qzo5PzgrODk8NCg6ODM4MjVDKDpBIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KYGBgDQoNClRoZSBudW1lcmljYWwgdmFsdWUgYXNzaWduZWQgdG8gZWFjaCBvZiB0aGVzZSBjaGFyYWN0ZXJzIGRlcGVuZHMgb24gdGhlDQpzZXF1ZW5jaW5nIHBsYXRmb3JtIHRoYXQgZ2VuZXJhdGVkIHRoZSByZWFkcy4gVGhlIHNlcXVlbmNpbmcgbWFjaGluZSB1c2VkIHRvIGdlbmVyYXRlIG91ciBkYXRhDQp1c2VzIHRoZSBzdGFuZGFyZCBTYW5nZXIgcXVhbGl0eSBQSFJFRCBzY29yZSBlbmNvZGluZywgdXNpbmcgSWxsdW1pbmEgdmVyc2lvbiAxLjggb253YXJkcy4NCkVhY2ggY2hhcmFjdGVyIGlzIGFzc2lnbmVkIGEgcXVhbGl0eSBzY29yZSBiZXR3ZWVuIDAgYW5kIDQxIGFzIHNob3duIGluDQp0aGUgY2hhcnQgYmVsb3cuDQoNCmBgYA0KUXVhbGl0eSBlbmNvZGluZzogISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKDQogICAgICAgICAgICAgICAgICAgfCAgICAgICAgIHwgICAgICAgICB8ICAgICAgICAgfCAgICAgICAgIHwNClF1YWxpdHkgc2NvcmU6ICAgIDAxLi4uLi4uLi4xMS4uLi4uLi4uMjEuLi4uLi4uLjMxLi4uLi4uLi40MQ0KYGBgDQoNCkVhY2ggcXVhbGl0eSBzY29yZSByZXByZXNlbnRzIHRoZSBwcm9iYWJpbGl0eSB0aGF0IHRoZSBjb3JyZXNwb25kaW5nIG51Y2xlb3RpZGUgY2FsbCBpcw0KaW5jb3JyZWN0LiBUaGlzIHF1YWxpdHkgc2NvcmUgaXMgbG9nYXJpdGhtaWNhbGx5IGJhc2VkLCBzbyBhIHF1YWxpdHkgc2NvcmUgb2YgMTAgcmVmbGVjdHMgYQ0KYmFzZSBjYWxsIGFjY3VyYWN5IG9mIDkwJSwgYnV0IGEgcXVhbGl0eSBzY29yZSBvZiAyMCByZWZsZWN0cyBhIGJhc2UgY2FsbCBhY2N1cmFjeSBvZiA5OSUuDQpUaGVzZSBwcm9iYWJpbGl0eSB2YWx1ZXMgYXJlIHRoZSByZXN1bHRzIGZyb20gdGhlIGJhc2UgY2FsbGluZyBhbGdvcml0aG0gYW5kIGRlcGVuZCBvbiBob3cNCm11Y2ggc2lnbmFsIHdhcyBjYXB0dXJlZCBmb3IgdGhlIGJhc2UgaW5jb3Jwb3JhdGlvbi4NCg0KDQpgYGANCkBTUlIyNTg0ODYzLjEgSFdJLVNUOTU3OjI0NDpINzNUREFEWFg6MToxMTAxOjQ3MTI6MjE4MS8xDQpUVENBQ0FUQ0NUR0FDQ0FUVENBR1RUR0FHQ0FBQUFUQUdUVENUVENBR1RHQ0NUR1RUVEFBQ0NHQUdUQ0FDR0NBR0dHR1RUVFRUR0dHVFRBQ0NUR0FUQ0NUR0FHQUdUVEFBQ0dHVEFHQUFBQ0dHVENBR1RBQ0dUQ0FHQUFUVFRBQ0dDR1RUR1RUQ0dBQUNBVEFHVFRDVEcNCisNCkNDQ0ZGRkZGR0hISEhKSUpKSkpJSkpKSUlKSkpKSUlJSkpHRklJSUpFRERGRUdHSklGSEhKSUpKREVDQ0dHRUdJSUpGSEZGRkFDRDpCQkJEREFDQ0NDQUFAQENBQEM+QzM+QDUoOCY+Qzo5PzgrODk8NCg6ODM4MjVDKDpBIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KYGBgDQoNCg0KDQpTaW5jZSB0aGlzIGZpbGUgaXMgc28gc21hbGwsIHdlIG5lZWRuJ3Qgd29ycnkgYWJvdXQgdGhlIGZpbGUgc2l6ZS4gSG93ZXZlciwgaW4gYSByZWFsIGxpZmUgZXhwZXJpbWVudCBvdXIgcmF3IHNlcXVlbmNpbmcgcmVhZHMgY2FuIGJlIG1hbnkgMTBzIG9mIEdiIGluIHNpemUuIEl0IGlzIGNvbW1vbiBwcmFjdGljZSB0byBjb21wcmVzcyB0aGUgZmlsZSBzbyB0aGF0IGl0IHRha2VzIGxlc3Mgc3BhY2Ugb24gZGlzay4gVGhlIHN0YW5kYXJkIHdheSBvZiBhY2hpZXZpbmcgdGhpcyBpbiBVbml4IHN5c3RlbXMgaXMgdG8gdXNlIHRoZSBgZ3ppcGAgY29tbWFuZC4gQSBzaWRlLWVmZmVjdCBvZiB0aGUgY29tcHJlc3Npb24gaXMgdGhhdCB0aGUgcmVzdWx0aW5nIGZpbGUgY2FuIG5vIGxvbmdlciBiZSBwcmludGVkIHdpdGggYGNhdGAuIEhvd2V2ZXIsIGEgYHpjYXRgIGNvbW1hbmQgY2FuIGJlIHVzZWQgdG8gdGhlIHNhbWUgZWZmZWN0Lg0KDQpgYGB7YmFzaCBldmFsPUZBTFNFfQ0KIyNleGFtcGxlIG9mIGNvbXByZXNzaW5nIHRoZSBmaWxlDQpnemlwIGV4YW1wbGVfcmVhZHMuZmFzdHENCiMjIGxpc3QgdGhlIGRpcmVjdG9yeSB0byBzZWUgd2hhdCBjaGFuZ2VkLi4uDQpscyAtbGgNCiMjIE5vdyBoYXZlIHRvIHVzZSB6Y2F0IHRvIHByaW50Li4uDQp6Y2F0IGV4YW1wbGVfcmVhZHMuZmFzdHEgfCBoZWFkIC1uNA0KYGBgDQoNCg0KIyMgRG93bmxvYWQgYW4gYXJjaGl2ZWQgZGlyZWN0b3J5DQoNCkFub3RoZXIgcG9wdWxhciB0ZWNobmlxdWUgZm9yIGNvbXByZXNzaW5nIGFuZCB0cmFuc2ZlcmluZyBhIGNvbGxlY3Rpb24gb2YgZmlsZXMgaXMgdG8gb3JnYW5pc2UgdGhlbSBpbnRvIGEgc2luZ2xlIGZpbGUgKG9yICp0YXJiYWxsKiksIHdoaWNoIGNhbiB0aGVuIGJlIGNvbXByZXNzZWQuIFN1Y2ggYSBmaWxlIGlzIGFsc28gYXZhaWxhYmxlIG9uIHRoZSBTaGVmZmllbGQgQmlvaW5mb3JtYXRpY3MgQ29yZSB3ZWJzaXRlIGZvciBkZW1vbnN0cmF0aW9uIHB1cnBvc2VzLiBUaGUgYHdnZXRgIGNvbW1hbmQgY2FuIGJlIHVzZWQgYXMgYmVmb3JlLg0KDQpgYGB7YmFzaCBldmFsPUZBTFNFfQ0Kd2dldCBodHRwOi8vc2JjLnNoZWYuYWMudWsvZGF0YS9hcmNoaXZlLnRhci5neg0KbHMNCmBgYA0KDQpUaGUgYHRhcmAgY29tbWFuZCB3aXRoIHRoZSBvcHRpb25zIGB6eHZmYCAobG9vayB0aGVzZSB1cCBpZiB5b3Ugd2FudCB0byB1bmRlcnN0YW5kIG1vcmUpIGNhbiBiZSB1c2VkIHRvIGNyZWF0ZSBhIGRpcmVjdG9yeSBzdHJ1Y3R1cmUgY29udGFpbmluZyBhbGwgdGhlIGZpbGVzLg0KDQpgYGB7YmFzaCBldmFsPUZBTFNFfQ0KdGFyIHp4dmYgYXJjaGl2ZS50YXIuZ3oNCmxzDQpgYGANCg0KDQoNCiMjIyBDaGVja2luZyB0aGUgZG93bmxvYWQgd29ya2VkDQoNCkhhdmluZyBkb3dubG9hZGVkIGFsbCB5b3VyIGZpbGVzLCB5b3Ugc2hvdWxkIHByb2JhYmx5IGNoZWNrIHRoZXkgaGF2ZSBiZWVuIGRvd25sb2FkZWQgc3VjY2Vzc2Z1bGx5IGFuZCBiZWVuIGNvcnJ1cHRlZCBpbiB0cmFuc2l0LiBQYXJ0aWFsIG9yIGluY29tcGxldGUgZmlsZXMgY2FuIGJlIGEgc291cmNlIG9mIGVycm9ycyBsYXRlciBvbiBpbiB0aGUgYW5hbHlzaXMuIElmIHlvdSBhcmUgZG93bmxvYWRpbmcgbWFueSBmaWxlcywgaXQgY2FuIGJlIGRpZmZpY3VsdCB0byBzcG90IGlmIGEgZmlsZSBmYWlsZWQgdG8gZG93bmxvYWQuIEEgc2ltcGxlIHdheSBpcyB0byBjaGVjayB0aGUgZmlsZSBzaXplcywgYnV0IHRoaXMgY2FuIGJlIHVucmVsaWFibGUuDQoNCkEgY29tbW9uIHdheSBvZiBkb2luZyB0aGlzIGlzIHRvIGdlbmVyYXRlIGFuICptZDVzdW0qIGZyb20gdGhlIGZpbGUuIFlvdSBjYW4gdGhpbmsgb2YgdGhpcyBhcyBhIHVuaXF1ZSBkaWdpdGFsIGJhcmNvZGUgb2YgYSB0ZXh0IGZpbGUuIFRoZSBzYW1lIGZpbGUgd2lsbCBhbHdheXMgZ2l2ZSB0aGUgc2FtZSBtZDVzdW0uIFNlcXVlbmNpbmcgdmVuZG9ycyB3aWxsIG9mdGVuIGNhbGN1bGF0ZSB0aGVzZSBmaWxlcyBvbiB0aGVpciBzZXJ2ZXJzIGFuZCBzZW5kIHRoZSByZXN1bHRzIHRvIHlvdSBpbiB0aGUgZm9ybSBvZiBhIHRleHQgZmlsZSB0aGF0IHlvdSBjYW4gdXNlIHRvIGNoZWNrLiBOb3RlIHRoYXQgZm9yIGxhcmdlIGZhc3RxIGZpbGVzLCB0aGVzZSBjYW4gdGFrZSBzZXZlcmFsIG1pbnV0ZXMgdG8gY29tcHV0ZS4NCg0KYGBge2Jhc2ggZXZhbD1GQUxTRX0NCiMjIyBzaG93IG1kNXN1bSBmb3IgYSBwYXJ0aWN1bGFyIGZpbGUNCm1kNXN1bSBmYXN0cS9TYW1wbGUxL1NhbXBsZTEuZmFzdHENCiMjIGhlbHAgaXMgYXZhaWxhYmxlIG9uIHRoZSBmdW5jdGlvbg0KbWQ1c3VtIC0taGVscA0KYGBgDQoNClRvIHNlZSB3aGF0IHdvdWxkIGhhcHBlbiBpZiBhIGZpbGUgZGlkbid0IHRyYW5zZmVyIHByb3Blcmx5LCB3ZSBjYW4gY3JlYXRlIGEgY29weSBvZiBgU2FtcGxlMS5mYXN0cWAgY29udGFpbmluZyBmZXdlciBsaW5lcy4gVGhlIHJlc3VsdGluZyBtZDVzdW0gd2lsbCBiZSBkaWZmZXJlbnQNCg0KYGBge2Jhc2h9DQojIyBVc2UgPiB0byByZWRpcmVjdCB0aGUgb3V0cHV0DQpoZWFkIGZhc3RxL1NhbXBsZTEvU2FtcGxlMS5mYXN0cSA+IGZhc3RxL1NhbXBsZTEvU2FtcGxlMV9zdWIuZmFzdHENCm1kNXN1bSBmYXN0cS9TYW1wbGUxL1NhbXBsZTFfc3ViLmZhc3RxDQpgYGANCg0KIyMgQ2hhbGxlbmdlIDEgey5jaGFsbGVuZ2V9DQoNCjxkaXYgY2xhc3M9ImV4ZXJjaXNlIj4NCiAxLiBEb3dubG9hZCB0aGUgcHJlLWNvbXB1dGVkIG1kNXN1bXMgYXZhaWxhYmxlIGF0IGBodHRwOi8vc2JjLnNoZWYuYWMudWsvZGF0YS9hcmNoaXZlX21kNS50eHRgLiANCiAyLiBQcmludCB0aGUgY29udGVudHMgb2YgdGhpcyBmaWxlIGFuZCB2ZXJpZnkgdGhhdCB0aGUgc3VtIGZvciBTYW1wbGUxLmZhc3RxIGlzIGNvcnJlY3QNCiAzLiBUaGUgbWQ1c3VtIGNvbW1hbmQgaXMgYWJsZSB0byBjaGVjayB0aGUgbWQ1c3VtcyBmb3IgYSBjb2xsZWN0aW9uIG9mIGZpbGVzIGFnYWluc3Qgc29tZSBwcmUtY29tcHV0ZWQgdmFsdWVzLiBVc2UgZG9jdW1lbnRhdGlvbiAoYW5kIGdvb2dsZSEpIHRvIGRpc2NvdmVyIGhvdyB0byBkbyB0aGlzIGZvciB0aGUgZmlsZXMgd2UgaGF2ZSBkb3dubG9hZGVkLg0KPC9kaXY+DQoNCg0KDQoNCiMjICBPYnRhaW5pbmcgcHVibGljIGRhdGEgYW5kIEFib3V0IHRoZSBleGFtcGxlIGRhdGENCg0KQSBnb29kIHJlc291cmNlIGZvciBvYnRhaW5pbmcgcHVibGljIGRhdGEgaXMgdGhlIFNSQSBleHBsb3Jlci4NCg0KLSBbaHR0cHM6Ly9zcmEtZXhwbG9yZXIuaW5mby9dKGh0dHBzOi8vc3JhLWV4cGxvcmVyLmluZm8vKQ0KDQpJbiB0aGUgU2VhcmNoIGJveCB5b3UgY2FuIGVudGVyIHRoZSBhY2Nlc3Npb24gbnVtYmVyIG9mIGEgc3R1ZHkgKHVzdWFsbHkgcXVvdGVkIGluIHRoZSBwdWJsaXNoZWQgcGFwZXIpLCB0byBvYnRhaW4gZG93bmxvYWQgbGlua3MgZm9yIGFsbCB0aGUgZmFzdHEgZmlsZXMuIEl0IHdpbGwgZXZlbiBnZW5lcmF0ZSBhIGJhc2ggc2NyaXB0IGZvciB5b3UgdG8gcnVuLiANCg0KVGhlIGRhdGEgZm9yIHRoaXMgdHV0b3JpYWwgY29tZXMgZnJvbSB0aGUgcGFwZXIsIFsqSW5kdWN0aW9uIG9mIGZpYnJvYmxhc3Qgc2VuZXNjZW5jZSBnZW5lcmF0ZXMgYSBub24tZmlicm9nZW5pYyBteW9maWJyb2JsYXN0IHBoZW5vdHlwZSB0aGF0IGRpZmZlcmVudGlhbGx5IGltcGFjdHMgb24gY2FuY2VyIHByb2dub3Npcy4qXShodHRwOi8vZXVyb3BlcG1jLm9yZy9hcnRpY2xlL01FRC8yNzk5Mjg1NikuIA0KDQo+IENhbmNlciBhc3NvY2lhdGVkIGZpYnJvYmxhc3RzIGNoYXJhY3Rlcml6ZWQgYnkgYW4gbXlvZmlicm9ibGFzdGljIHBoZW5vdHlwZSBwbGF5IGEgbWFqb3Igcm9sZSBpbiB0aGUgdHVtb3VyIG1pY3JvZW52aXJvbm1lbnQsIGJlaW5nIGFzc29jaWF0ZWQgd2l0aCBwb29yIHByb2dub3Npcy4gV2UgZm91bmQgdGhhdCB0aGlzIGNlbGwgcG9wdWxhdGlvbiBpcyBtYWRlIGluIHBhcnQgYnkgc2VuZXNjZW50IGZpYnJvYmxhc3RzIGluIHZpdm8uIEFzIHNlbmVzY2VudCBmaWJyb2JsYXN0cyBhbmQgbXlvZmlicm9ibGFzdHMgaGF2ZSBiZWVuIHNob3duIHRvIHNoYXJlIHNpbWlsYXIgdHVtb3VyIHByb21vdGluZyBmdW5jdGlvbnMgaW4gdml0cm8gd2UgY29tcGFyZWQgdGhlIHRyYW5zY3JpcHRvc29tZXMgb2YgdGhlc2UgdHdvIGZpYnJvYmxhc3QgdHlwZXMgYW5kIHBlcmZvcm1lZCBSTkEtc2VxIG9mIGh1bWFuIGZvZXRhbCBmb3Jlc2tpbiBmaWJyb2JsYXN0cyAyIChIRkZGMikgdHJlYXRlZCB3aXRoIDJuZy9tbCBUR0YtYmV0YS0xIHRvIGluZHVjZSBteW9maWJyb2JsYXN0IGRpZmZlcmVudGlhdGlvbiBvciAxMEd5IGdhbW1hIGlycmFkaWF0aW9uIHRvIGluZHVjZSBzZW5lc2NlbmNlLiBXZSBpc29sYXRlZCBSTkEgNyBkYXlzIHVwb24gdGhpcyB0cmVhdG1lbnRzIGNoYW5naW5nIHRoZSBtZWRpdW0gMyBkYXlzIGJlZm9yZSB0aGUgUk5BIGV4dHJhY3Rpb24uDQoNCg0KVGhlIHBhcGVyIHN0YXRlcyBhIHBhcnRpY3VsYXIgKmFjY2Vzc2lvbiBudW1iZXIqIHRoYXQgY2FuIGJlIHVzZWQgdG8gYWNjZXNzIHRoZSBkYXRhDQoNCi0gKipFLU1UQUItMzEwMSoqDQoNClRoaXMgSUQgY2FuIGJlIHVzZWQgdG8gZmluZCB0aGUgZGF0YSBvbiBBcnJheUV4cHJlc3MsIGJ1dCBpcyBhbHNvIHJlY29nbmlzZWQgYnkgU1JBIGV4cGxvcmVyICh5b3UgZG9uJ3QgbmVlZCB0aGUgKipbQWxsIGZpZWxkc10qKiB0ZXh0IHNob3duIGluIHRoZSBzY3JlZW5zaG90KS4gR2VuZSBFeHByZXNzaW9uIE9tbmlidXMgKCoqR1NFLi4qKikgb3IgU2VxdWVuY2luZyBSZWFkIEFyY2hpdmUgKCoqU1JQLi4uKiopIGlkZW50aWZpZXJzIGFyZSBhbHNvIHJlY29nbmlzZWQuDQoNCiFbXShpbWFnZXMvc3JhX2V4cGxvcmVyLlBORykNCg0KSWYgdGhlIGlkZW50aWZpZXIgaXMgcmVjb2duaXNlZCB0aGUgbmFtZXMgb2Ygc2FtcGxlcyBiZWxvbmdpbmcgdG8gdGhlIGRhdGFzZXQgd2lsbCBiZSBzaG93bi4gVGhlc2UgY2FuIGJlIHNlbGVjdGVkIGFuZCBhZGRlZCB0byBhIGNvbGxlY3Rpb24uIEZyb20gdGhlIHNhdmVkIGRhdGFzZXRzIGJ1dHRvbiAodG9wLXJpZ2h0KSB0aGUgdXNlciBjYW4gdGhlbiBhY2Nlc3MgZG93bmxvYWQgbGlua3MuDQoNCkZvciB0aGlzIHBhcnRpY3VsYXIgZGF0YXNldCB3ZSBjcmVhdGVkIGEgZG93bmxvYWQgc2NyaXB0IHVzaW5nIHRoZSBsaW5rcyBwcm92aWRlZCBieSBTUkEgZXhwbG9yZXIuIFRvIGtlZXAgdGhlIHJ1bi10aW1lIG9mIHRoZSB3b3Jrc2hvcCBzaG9ydCAoYW5kIHRvIGtlZXAgY29tcHV0aW5nIHJlcXVpcmVtZW50cyBkb3duKSwgZWFjaCByYXcgZmlsZSB3YXMgc3Vic2V0IHRvIGEgbW9yZSBtYW5hZ2VhYmxlIGFtb3VudC4NCg0KPGRpdiBjbGFzcz0iaW5mb3JtYXRpb24iPg0KVGhlIGNvZGUgdXNlZCB0byBkb3dubG9hZCB0aGUgZXhhbXBsZSBkYXRhc2V0IGNhbiBiZSBmb3VuZCBpbiBgL2hvbWUvZGN1c2VyL3JuYXNlcV9kYXRhL3NjcmlwdHMvZG93bmxvYWRfc3Vic2V0LnNoYC4gWW91IGRvIG5vdCBuZWVkIHRvIHJ1biB0aGlzIGFzIHBhcnQgb2YgdGhlIHdvcmtzaG9wIC0gaXQgaXMganVzdCBmb3IgaW5mb3JtYXRpb24sIG9yIGlmIHlvdSB3YW50ZWQgdG8gcmVwZWF0IHRoZSB3b3Jrc2hvcCBpbiB5b3VyIG93biBlbnZpcm9ubWVudC4NCjwvZGl2Pg0KDQpUaGUgZXhhbXBsZSBkYXRhc2V0IGNvbnNpc3RzIG9mIG5pbmUgcmF3IChmYXN0cSBmaWxlcykuIFRoZSBmaWxlcyBhcmUgbmFtZWQgYWNjb3JkaW5nIHRvIG5hbWVzIGFzc2lnbmVkIHdoZW4gdGhlIGRhdGEgd2VyZSB1cGxvYWRlZCB0byB0aGUgcHVibGljIHJlcG9zaXRvcnkuIFdlIGNhbiB1c2UgYSBzYW1wbGUgc2hlZXQgdG8gYXNzb2NpYXRlIGVhY2ggb2YgdGhlc2UgZGF0YWJhc2UgbmFtZXMgdG8gc29tZXRoaW5nIG1vcmUgbWVtb3JhYmxlLCBhbmQgZXZlbnR1YWxseSB0aGUgYmlvbG9naWNhbCBjb25kaXRpb25zIGJlaW5nIHN0dWRpZWQgKGJleW9uZCB0aGUgc2NvcGUgb2Ygd2hhdCB3ZSB3aWxsIGNvdmVyIHRvZGF5KQ0KDQp8IGZhc3RxICAgICB8IFNhbXBsZSB8IENvbmRpdGlvbiAgIHwNCnwtLS0tLS0tLS0tLXwtLS0tLS0tLXwtLS0tLS0tLS0tLS0tfA0KfCBFUlI3MzI5MDFfc3ViIHwgQ1RSXzEgIHwgQ29udHJvbCAgICAgfA0KfCBFUlI3MzI5MDFfc3ViIHwgVEdGXzEgIHwgVEdGX1RyZWF0ZWQgfA0KfCAuLi4gICAgICAgfCAuLi4gICAgfCAuLi4gICAgICAgICB8DQoNCg0KIyBBc3Nlc3NpbmcgUXVhbGl0eSB1c2luZyBGYXN0UUMNCg0KSW4gcmVhbCBsaWZlLCB5b3Ugd29uJ3QgYmUgYXNzZXNzaW5nIHRoZSBxdWFsaXR5IG9mIHlvdXIgcmVhZHMgYnkgdmlzdWFsbHkgaW5zcGVjdGluZyB5b3VyIA0KRkFTVFEgZmlsZXMuIFJhdGhlciwgeW91J2xsIGJlIHVzaW5nIGEgc29mdHdhcmUgcHJvZ3JhbSB0byBhc3Nlc3MgcmVhZCBxdWFsaXR5IGFuZCANCmZpbHRlciBvdXQgcG9vciBxdWFsaXR5IHJlYWRzLiBXZSdsbCBmaXJzdCB1c2UgYSBwcm9ncmFtIGNhbGxlZCBbRmFzdFFDXShodHRwOi8vd3d3LmJpb2luZm9ybWF0aWNzLmJhYnJhaGFtLmFjLnVrL3Byb2plY3RzL2Zhc3RxYy8pIHRvIHZpc3VhbGl6ZSB0aGUgcXVhbGl0eSBvZiBvdXIgcmVhZHMuIA0KTGF0ZXIgaW4gb3VyIHdvcmtmbG93LCB3ZSdsbCB1c2UgYW5vdGhlciBwcm9ncmFtIHRvIGZpbHRlciBvdXQgcG9vciBxdWFsaXR5IHJlYWRzLiANCg0KRmFzdFFDIGhhcyBhIG51bWJlciBvZiBmZWF0dXJlcyB3aGljaCBjYW4gZ2l2ZSB5b3UgYSAgcXVpY2sgaW1wcmVzc2lvbiBvZiBhbnkgcHJvYmxlbXMgeW91cg0KZGF0YSBtYXkgaGF2ZSwgc28geW91IGNhbiB0YWtlIHRoZXNlIGlzc3VlcyBpbnRvIGNvbnNpZGVyYXRpb24gYmVmb3JlIG1vdmluZyBmb3J3YXJkIHdpdGggeW91cg0KYW5hbHlzZXMuIFJhdGhlciB0aGFuIGxvb2tpbmcgYXQgcXVhbGl0eSBzY29yZXMgZm9yIGVhY2ggaW5kaXZpZHVhbCByZWFkLCBGYXN0UUMgbG9va3MgYXQNCnF1YWxpdHkgY29sbGVjdGl2ZWx5IGFjcm9zcyBhbGwgcmVhZHMgd2l0aGluIGEgc2FtcGxlLiBUaGUgaW1hZ2UgYmVsb3cgc2hvd3MgYSBGYXN0UUMtZ2VuZXJhdGVkIHBsb3QgdGhhdCBpbmRpY2F0ZXMNCmEgdmVyeSBoaWdoIHF1YWxpdHkgc2FtcGxlOg0KDQohW2dvb2RfcXVhbGl0eV0oaW1hZ2VzL2dvb2RfcXVhbGl0eTEuOC5wbmcpDQoNClRoZSB4LWF4aXMgZGlzcGxheXMgdGhlIGJhc2UgcG9zaXRpb24gaW4gdGhlIHJlYWQsIGFuZCB0aGUgeS1heGlzIHNob3dzIHF1YWxpdHkgc2NvcmVzLiBJbiB0aGlzDQpleGFtcGxlLCB0aGUgc2FtcGxlIGNvbnRhaW5zIHJlYWRzIHRoYXQgYXJlIDQwIGJwIGxvbmcuIEZvciBlYWNoIHBvc2l0aW9uLCB0aGVyZSBpcyBhIA0KYm94LWFuZC13aGlza2VyIHBsb3Qgc2hvd2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHF1YWxpdHkgc2NvcmVzIGZvciBhbGwgcmVhZHMgYXQgdGhhdCBwb3NpdGlvbi4NClRoZSBob3Jpem9udGFsIHJlZCBsaW5lIGluZGljYXRlcyB0aGUgbWVkaWFuIHF1YWxpdHkgc2NvcmUgYW5kIHRoZSB5ZWxsb3cgYm94IHNob3dzIHRoZSAybmQgdG8NCjNyZCBxdWFydGlsZSByYW5nZS4gVGhpcyBtZWFucyB0aGF0IDUwJSBvZiByZWFkcyBoYXZlIGEgcXVhbGl0eSBzY29yZSB0aGF0IGZhbGxzIHdpdGhpbiB0aGUNCnJhbmdlIG9mIHRoZSB5ZWxsb3cgYm94IGF0IHRoYXQgcG9zaXRpb24uIFRoZSB3aGlza2VycyBzaG93IHRoZSByYW5nZSB0byB0aGUgMXN0IGFuZCA0dGggDQpxdWFydGlsZS4NCg0KRm9yIGVhY2ggcG9zaXRpb24gaW4gdGhpcyBzYW1wbGUsIHRoZSBxdWFsaXR5IHZhbHVlcyBkbyBub3QgZHJvcCBtdWNoIGxvd2VyIHRoYW4gMzIuIFRoaXMgDQppcyBhIGhpZ2ggcXVhbGl0eSBzY29yZS4gVGhlIHBsb3QgYmFja2dyb3VuZCBpcyBhbHNvIGNvbG9yLWNvZGVkIHRvIGlkZW50aWZ5IGdvb2QgKGdyZWVuKSwNCmFjY2VwdGFibGUgKHllbGxvdyksIGFuZCBiYWQgKHJlZCkgcXVhbGl0eSBzY29yZXMuDQoNCk5vdyBsZXQncyB0YWtlIGEgbG9vayBhdCBhIHF1YWxpdHkgcGxvdCBvbiB0aGUgb3RoZXIgZW5kIG9mIHRoZSBzcGVjdHJ1bS4gDQoNCiFbYmFkX3F1YWxpdHldKGltYWdlcy9iYWRfcXVhbGl0eTEuOC5wbmcpDQoNCkhlcmUsIHdlIHNlZSBwb3NpdGlvbnMgd2l0aGluIHRoZSByZWFkIGluIHdoaWNoIHRoZSBib3hlcyBzcGFuIGEgbXVjaCB3aWRlciByYW5nZS4gQWxzbywgcXVhbGl0eSBzY29yZXMgZHJvcCBxdWl0ZSBsb3cgaW50byB0aGUgImJhZCIgcmFuZ2UsIHBhcnRpY3VsYXJseSBvbiB0aGUgdGFpbCBlbmQgb2YgdGhlIHJlYWRzLiBUaGUgRmFzdFFDIHRvb2wgcHJvZHVjZXMgc2V2ZXJhbCBvdGhlciBkaWFnbm9zdGljIHBsb3RzIHRvIGFzc2VzcyBzYW1wbGUgcXVhbGl0eSwgaW4gYWRkaXRpb24gdG8gdGhlIG9uZSBwbG90dGVkIGFib3ZlLiANCg0KIyMgUnVubmluZyBGYXN0UUMgIA0KDQpXZSB3aWxsIGJlIHdvcmtpbmcgd2l0aCBhIHNldCBvZiBzYW1wbGUgZGF0YSB0aGF0IGlzIGxvY2F0ZWQgaW4gdGhlIGRpcmVjdG9yeSAoYHJuYXNlcV9kYXRhYCkuIFRoZXNlIGZpbGVzIGhhdmUgYmVlbiBjb21wcmVzc2VkLCBzbyBoYXZlIHRoZSBgZmFzdHEuZ3pgIGV4dGVuc2lvbi4gRmFzdFFDIGlzIGhhcHB5IHdpdGggZWl0aGVyIGNvbXByZXNzZWQgb24gdW4tY29tcHJlc3NlZCBmaWxlcy4NCg0KDQpOYXZpZ2F0ZSB0byB5b3VyIEZBU1RRIGRhdGFzZXQ6IA0KDQpgYGB7YmFzaCBldmFsPUZBTFNFfQ0KY2QgL2hvbWUvZGN1c2VyL3JuYXNlcV9kYXRhDQpgYGANCg0KDQoNClRvIHJ1biB0aGUgRmFzdFFDIHByb2dyYW0sIHdlIHdvdWxkIG5vcm1hbGx5IGhhdmUgdG8gdGVsbCBvdXIgY29tcHV0ZXIgd2hlcmUgdGhlIHByb2dyYW0gaXMgbG9jYXRlZC4gSW4gdGhpcyBwYXJ0aWN1bGFyIGNhc2UsIEZhc3RRQyBoYXMgYmVlbiBpbnN0YWxsZWQgaW4gYSBsb2NhdGlvbiB0aGF0IGNhbiBiZSBhY2Nlc3NlZCBmcm9tIGFsbCBkaXJlY3Rvcmllcy4gDQoNCmBgYHtiYXNoIGV2YWw9RkFMU0V9DQp3aGljaCBmYXN0cWMNCmBgYA0KDQpgYGANCi91c3IvYmluL2Zhc3RxYw0KYGBgDQoNCioqVGhpcyBpcyB0aGUgZmlyc3QgcHJvZ3JhbSB3ZSBoYXZlIHNlZW4gdGhhdCBpcyBzcGVjaWZpYyB0byBOR1MgYW5hbHlzaXMsIHNvIG1pZ2h0IG5vdCBiZSBhdmFpbGFibGUgb24gYWxsIGZpbGUgc3lzdGVtcyBieSBkZWZhdWx0LioqDQoNCkZhc3RRQyBjYW4gYWNjZXB0IG11bHRpcGxlIGZpbGUgbmFtZXMgYXMgaW5wdXQsIHNvIHdlIGNhbiB1c2UgdGhlIGAqLmZhc3RxLmd6YCB3aWxkY2FyZCB0byBydW4gRmFzdFFDIG9uIGFsbCBvZiB0aGUgRkFTVFEgZmlsZXMgaW4gdGhpcyBkaXJlY3RvcnkuDQoNCmBgYHtiYXNoIGV2YWw9RkFMU0V9DQpmYXN0cWMgZmFzdHEvKi5mYXN0cS5neg0KYGBgDQoNCg0KWW91IHdpbGwgc2VlIGFuIGF1dG9tYXRpY2FsbHkgdXBkYXRpbmcgb3V0cHV0IG1lc3NhZ2UgdGVsbGluZyB5b3UgdGhlIA0KcHJvZ3Jlc3Mgb2YgdGhlIGFuYWx5c2lzLiBJdCB3aWxsIHN0YXJ0IGxpa2UgdGhpczogDQoNCg0KYGBgDQpTdGFydGVkIGFuYWx5c2lzIG9mIEVSUjczMjkwMV9zdWIuZmFzdHEuZ3oNCkFwcHJveCAxMDAlIGNvbXBsZXRlIGZvciBFUlI3MzI5MDFfc3ViLmZhc3RxLmd6DQpBbmFseXNpcyBjb21wbGV0ZSBmb3IgRVJSNzMyOTAxX3N1Yi5mYXN0cS5neg0KDQpgYGANCg0KSW4gdG90YWwsIGl0IHNob3VsZCB0YWtlIGxlc3MgdGhhbiAxIG1pbnV0ZSBmb3IgRmFzdFFDIHRvIHJ1biBvbiBhbGwNCm9mIG91ciBGQVNUUSBmaWxlcy4gV2hlbiB0aGUgYW5hbHlzaXMgY29tcGxldGVzLCB5b3VyIHByb21wdA0Kd2lsbCByZXR1cm4uIFNvIHlvdXIgc2NyZWVuIHdpbGwgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOg0KDQpgYGANClN0YXJ0ZWQgYW5hbHlzaXMgb2YgRVJSNzMyOTA5X3N1Yi5mYXN0cS5neg0KQXBwcm94IDEwMCUgY29tcGxldGUgZm9yIEVSUjczMjkwOV9zdWIuZmFzdHEuZ3oNCkFuYWx5c2lzIGNvbXBsZXRlIGZvciBFUlI3MzI5MDlfc3ViLmZhc3RxLmd6DQoNCmBgYA0KDQpUaGUgRmFzdFFDIHByb2dyYW0gaGFzIGNyZWF0ZWQgc2V2ZXJhbCBuZXcgZmlsZXMgd2l0aGluIG91cg0KYC9kYXRhL2Zhc3RxYCBkaXJlY3RvcnkuIA0KDQpgYGB7YmFzaCBldmFsPUZBTFNFfQ0KbHMgZmFzdHEvDQpgYGANCg0KDQpgYGANCkVSUjczMjkwMV9zdWIuZmFzdHFjLmh0bWwgICAgRVJSNzMyOTAxX3N1Yi5mYXN0cWMuemlwICAgICBFUlI3MzI5MDFfc3ViLmZhc3RxLmd6ICAgICBFUlI3MzI5MDFfc3ViLmZhc3RxYy5odG1sICAgICANCi4uLi4NCmBgYA0KDQoNCkZvciBlYWNoIGlucHV0IEZBU1RRIGZpbGUsIEZhc3RRQyBoYXMgY3JlYXRlZCBhIGAuemlwYCBmaWxlIGFuZCBhDQpgLmh0bWxgIGZpbGUuIFRoZSBgLnppcGAgZmlsZSBleHRlbnNpb24gaW5kaWNhdGVzIHRoYXQgdGhpcyBpcyANCmFjdHVhbGx5IGEgY29tcHJlc3NlZCBzZXQgb2YgbXVsdGlwbGUgb3V0cHV0IGZpbGVzLiBXZSdsbCBiZSB3b3JraW5nDQp3aXRoIHRoZXNlIG91dHB1dCBmaWxlcyBzb29uLiBUaGUgYC5odG1sYCBmaWxlIGlzIGEgc3RhYmxlIHdlYnBhZ2UNCmRpc3BsYXlpbmcgdGhlIHN1bW1hcnkgcmVwb3J0IGZvciBlYWNoIG9mIG91ciBzYW1wbGVzLg0KDQpXZSB3YW50IHRvIGtlZXAgb3VyIGRhdGEgZmlsZXMgYW5kIG91ciByZXN1bHRzIGZpbGVzIHNlcGFyYXRlLCBzbyB3ZQ0Kd2lsbCBtb3ZlIHRoZXNlIG91dHB1dCBmaWxlcyBpbnRvIGEgbmV3IGRpcmVjdG9yeSB3aXRoaW4gb3VyIGByZXN1bHRzL2AgZGlyZWN0b3J5LiBJZiB0aGlzIGRpcmVjdG9yeSBkb2VzIG5vdCBleGlzdCwgd2Ugd2lsbCBoYXZlIHRvIGNyZWF0ZSBpdC4NCg0KYGBge2Jhc2ggZXZhbD1GQUxTRX0NCiMjIC1wIGZsYWcgc3RvcHMgYSBtZXNzYWdlIGZyb20gYXBwZWFyaW5nIGlmIHRoZSBkaXJlY3RvcnkgYWxyZWFkeSBleGlzdHMNCm1rZGlyIC1wIHFjDQptdiBmYXN0cS8qLmh0bWwgcWMvDQptdiBmYXN0cS8qLnppcCBxYy8NCmBgYA0KDQoNCiMjIENvbWJpbmluZyB0aGUgcmVwb3J0cyB3aXRoIGBtdWx0aXFjYA0KDQpJdCBjYW4gYmUgcXVpdGUgdGlyZXNvbWUgdG8gY2xpY2sgdGhyb3VnaCBtdWx0aXBsZSBRQyByZXBvcnRzIGFuZCBjb21wYXJlIHRoZSByZXN1bHRzIGZvciBkaWZmZXJlbnQgc2FtcGxlcy4gSXQgaXMgdXNlZnVsIHRvIGhhdmUgYWxsIHRoZSBRQyBwbG90cyBvbiB0aGUgc2FtZSBwYWdlIHNvIHRoYXQgd2UgY2FuIG1vcmUgZWFzaWx5IHNwb3QgdHJlbmRzIGluIHRoZSBkYXRhLg0KDQpUaGUgbXVsdGlxYyB0b29sIGhhcyBiZWVuIGRlc2lnbmVkIGZvciB0aGUgdGFza3Mgb2YgYWdncmVnYXRpbmcgcWMgcmVwb3J0cyBhbmQgY29tYmluaW5nIGludG8gYSBzaW5nbGUgcmVwb3J0IHRoYXQgaXMgZWFzeSB0byBkaWdlc3QuDQoNCmBgYHtiYXNoIGV2YWw9RkFMU0V9DQptdWx0aXFjDQptdWx0aXFjIC0taGVscA0KYGBgDQoNCg0KIyMgQ2hhbGxlbmdlIDIgey5jaGFsbGVuZ2V9DQoNCjxkaXYgY2xhc3M9ImV4ZXJjaXNlIj4gDQpVc2UgdGhlIG11bHRpcWMgdG9vbCB0byBjcmVhdGUgYSBzaW5nbGUgUUMgcmVwb3J0IGZvciB0aGUgZGF0YXNldC4NCkxvb2sgYXQgdGhlIGhlbHAgZm9yIHRoZSB0b29sLCBhbmQgZmlndXJlIG91dCBob3cgdG8gcnVuIHRoZSB0b29sIG9uIHRoZSBmYXN0cWMgb3V0cHV0IHdlIGhhdmUganVzdCBnZW5lcmF0ZWQuIE1ha2Ugc3VyZSB0aGF0IGBtdWx0aXFjYCBjcmVhdGVzIHNhdmVzIHRoZSByZXBvcnQgZmlsZSBpbiB0aGUgYHFjYCBmb2xkZXIuDQo8L2Rpdj4NCg0KVGhlIGVudmlyb25tZW50IHRoYXQgd2UgYXJlIHdvcmtpbmcgaW5zaWRlIGluY2x1ZGVzIGEgdmVyc2lvbiBvZiB0aGUgRmlyZWZveCB3ZWIgYnJvd3Nlci4gV2UgY2FuIG9wZW4gYSBwYXJ0aWN1bGFyIEhUTUwgZmlsZSB3aXRoIGZpcmVmb3ggdXNpbmcgdGhlIGNvbW1hbmQ6LQ0KDQpgYGANCmZpcmVmb3ggcWMvRVJSNzMyOTAxX3N1Yi5mYXN0cWMuaHRtbA0KYGBgDQoNCklmIHRoaXMgZG9lc24ndCB3b3JrLCB0aGVyZSBpcyBhIEZpbGUgRXhwbG9yZXIgdG9vbCBhdmFpbGFibGUgaW4gdGhlIGRlc2t0b3AgZW52aXJvbm1lbnQgdGhhdCB5b3UgY2FuIHVzZSB0byBuYXZpZ2F0ZSB0bywgYW5kIHZpZXcgdGhlIGZpbGVzLg0KDQojIyBDaGFsbGVuZ2UgMyB7LmNoYWxsZW5nZX0NCjxkaXYgY2xhc3M9ImV4ZXJjaXNlIj4gDQpEaXNjdXNzIHlvdXIgcmVzdWx0cyB3aXRoIGEgbmVpZ2hib3VyLiANCi0gV2hpY2ggc2FtcGxlcyBtb3N0IHRoZSBoaWdoZXN0IC8gbG93ZXN0IG51bWJlciBvZiByZWFkcw0KLSBXaGljaCBzYW1wbGUocykgbG9va3MgdGhlIGJlc3QgaW4gdGVybXMgb2YgcGVyIGJhc2Ugc2VxdWVuY2UgcXVhbGl0eT8gLSBXaGljaCBzYW1wbGUocykgbG9vayB0aGUgd29yc3Q/DQo8L2Rpdj4NCg0KPGEgaHJlZj0icGFydDMubmIuaHRtbCIgc3R5bGU9ImZvbnQtc2l6ZTogNTBweDsgdGV4dC1kZWNvcmF0aW9uOiBub25lIj5DbGljayBIZXJlIGZvciBuZXh0IHBhcnQ8L2E+