(Adapted from the Data Carpentry Genomics wrangling materials at:- https://datacarpentry.org/wrangling-genomics/02-quality-control/index.html)

Overview

Covered in this section

  • Using the command line to download files
  • Compression and de-compression of files
  • Verifying that a download was completed
  • Quality assessment of raw sequencing data
  • Compiling multiple QC reports into a single file

Bioinformatics workflows

When working with high-throughput sequencing data, the raw reads you get off of the sequencer will need to pass through a number of different tools in order to generate your final desired output. The execution of this set of tools in a specified order is commonly referred to as a workflow or a pipeline.

An example of the workflow we will be using for our RNA-seq analysis is provided below with a brief description of each step.

workflow

  1. Quality control - Assessing quality using FastQC
  2. Align reads to reference genome
  3. Quantification to obtain gene-level counts post-alignment clean-up
  4. Differential Expression

These workflows in bioinformatics adopt a plug-and-play approach in that the output of one tool can be easily used as input to another tool without any extensive configuration. Having standards for data formats is what makes this feasible. Standards ensure that data is stored in a way that is generally accepted and agreed upon within the community. The tools that are used to analyze data at different stages of the workflow are therefore built under the assumption that the data will be provided in a specific format.

Although we are using RNA-seq as a case study, the initial steps for other NGS technologies are highly-similar

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…

Line Description
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

  1. Download the pre-computed md5sums available at http://sbc.shef.ac.uk/data/archive_md5.txt.
  2. Print the contents of this file and verify that the sum for Sample1.fastq is correct
  3. 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

  • E-MTAB-3101

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 code used to download the example dataset can be found in /home/dcuser/rnaseq_data/scripts/download_subset.sh. You do not need to run this as part of the workshop - it is just for information, or if you wanted to repeat the workshop in your own environment.

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)

fastq Sample Condition
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:

good_quality

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.

bad_quality

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+