Alignment and Quantification
Two workflows are possible with RNA-seq data - with the difference being whether one performs an alignment to the reference genome or not.
Recent tools for RNA-seq analysis (e.g. salmon
, kallisto
) do not require the time-consuming step of whole-genome alignment to be performed, and can therefore produce gene-level counts in a much faster time frame. They not require the creation of large bam files, which is useful if constrained by file space on Galaxy.

(image from Harvard Bioinformatics Core)
We will demonstrate both methods, but for further analysis in R we will use counts that have been generated with salmon
.
A much reduced dataset will be used for illustration although the commands used can applied to more-realistic sizes of data.
We first make sure that we are located in the directory with our fastq files
cd ~/rnaseq_data
ls
We will need some reference data for the alignment, and a good place to obtain these data is from Ensembl.
Links to downloads for a variety of different organisms can be found at https://www.ensembl.org/info/data/ftp/index.html. We can navigate to the particular organism we are interested in through the interface and download the transcript and genome sequences to our laptop. However, we need the reference files to be present on the remote server that we are performing the analysis on.
The command wget
can be used to download a file from an FTP site to a local directory if you know the path to the file (URL). This path could be obtained by first locating the file in Ensembl and right-clicking to copy the link address.
The homepage of Ensembl FTP index links to reference data for common genomes

Files can be downloaded by clicking on the relevant link. However, we want to download the data using the command line so we have to right-click and select “Copy Link Location” (or similar)

The following commands should download reference data from Ensembl into a newly-created ref_data
folder. It is good practice to keep your reference data stored in a sub-folder. However, check first (with I.T or local Bioinformaticians) that you don’t have a local copy of reference genomes on your file system
mkdir ref_data
wget ftp://ftp.ensembl.org/pub/release-91/fasta/mus_musculus/cdna/Mus_musculus.GRCm38.cdna.all.fa.gz -P ref_data/
wget ftp://ftp.ensembl.org/pub/release-91/gtf/mus_musculus/Mus_musculus.GRCm38.91.chr.gtf.gz -P ref_data
wget ftp://ftp.ensembl.org/pub/release-91/fasta/mus_musculus/dna/Mus_musculus.GRCm38.dna.chromosome.1.fa.gz -P ref_data/
Workflow 1: Quantify the transcripts with salmon
Salmon is a tool for quantifying the expression of transcripts using RNA-seq data. It is based on a new algorithm that couples the concept of quasi-mapping with a two-phase inference procedure, providing accurate expression estimates very quickly and using little memory. It quantifies the expression of the transcripts from a given annotation, so it is not able to identify non annotated genes and transcripts.
The documentation of the tool is available at https://salmon.readthedocs.io/en/latest/salmon.html
Salmon is able to quantify transcript expression by using a quasi-mapping algorithm. Quasi-mappings are mappings of reads to transcript positions that are computed without performing a base-to-base alignment of the read to the transcript. This approach is typically much faster to compute than traditional (or full) alignments, and can sometimes provide superior accuracy by being more robust to errors in the read or genomic variation from the reference sequence
salmon
requires the user to create an index from the fasta
file of the transcripts. We have to specify a prefix name for all the files that salmon
is going to create.
salmon index -i index/GRCm38_salmon -t ref_data/Mus_musculus.GRCm38.cdna.all.fa.gz
The quasi-mapping approach of salmon
can be run with the salmon quant
command. Help on running this tool can be displayed with the following command.
salmon quant --help-reads
We need to specify the path of the index we have just created in the previous step, locations of our fastq
files, and the library type (if unsure the option A can be used. See the help page for more options https://salmon.readthedocs.io/en/latest/salmon.html#what-s-this-libtype). We can specify where salmon
write it’s output files to, but this directory does not need to exist prior to running the command.
salmon quant -i index/GRCm38_salmon --libType A -r SRR1552444.fastq.gz -o quant/SRR1552444
Challenge 1
Navigate to the quant folder and explore the files that salmon has created. What file contains the quantifications? Use the salmon documentation to understand the various output files https://salmon.readthedocs.io/en/latest/file_formats.html#fileformats
Running for all samples
If we want to repeat the quantification step for all our samples, we could employ a for
loop as we have seen previously.
for filename in *.fastq.gz
do
name=$(basename $filename .fastq.gz)
salmon quant -i index/GRCm38_salmon --libType A -r $filename.fastq.gz -o quant/$name
gzip quant/$name/quant.sf
done
Workflow 2: Align and then count
There are numerous tools performing short read alignment and the choice of aligner should be carefully made according to the analysis goals/requirements. Here we will use HISAT2, a fast aligner with low memory requirements that performs spliced alignments. It is the program suggested for the alignment in the new Tuxedo protocol (https://doi.org/10.1038/nprot.2016.095) and it requires an indexed genome to keep its memory footprint small and the running time short.
The program creates a genome index by using the FASTA file of the sequence we want to use as reference. A sequence in FASTA format begins with a single-line description, followed by lines of sequence data. The description line is distinguished from the sequence data by a greater-than (>
) symbol at the beginning.
Creating a genome index
We have already downloaded the reference file that we want to use. However, it is in a compressed format and not immediately useful for building the genome index. We need to un-compress the file first using the gunzip
command (similar to unzip
that we used earlier in the course). This should now replace the file ref_data/Mus_musculus.GRCm38.dna.chromosome.1.fa.gz
with ref_data/Mus_musculus.GRCm38.dna.chromosome.1.fa
The command hisat2-build
is used to take the reference sequence and create an efficient data structure for searching. We need to specify a prefix that will be used to name the files that hisat2
generates.
The index step only needs to be run once for a particular genome versions. You can use the same index to align multiple samples.
Note that the following index procedure may take a few minutes to run
gunzip ref_data/Mus_musculus.GRCm38.dna.chromosome.1.fa.gz
hisat2-build ref_data/Mus_musculus.GRCm38.dna.chromosome.1.fa index/GRCm38_chr1_hisat
The index files of Mouse genome GRCm38 chromosome 1 should now be in the directory index/
. All of them have a file name starting with the GRCm38_chr1_hisat
prefix.
Alignment with hisat2
There are several parameters we might want to specify in order to align our reads with HISAT2. To view them all type.
hisat2 --help
To align one of our example files against the index that we have just created we need to
- change the
-x
argument to be the file prefix of all the index files created in the previous step.
- specify that our reads are un-paired and to be found in the file
SRR1552444.fastq.gz
- specify an output file for the alignments. We will create a new directory to save these alignments to
aligned_reads
mkdir aligned_reads
hisat2 -x index/GRCm38_chr1_hisat -U SRR1552444.fastq.gz -S aligned_reads/SRR1552444.sam
The output file created is an example of a Sequence Alignment/Map (SAM) file. This is a human-readable file that tells us how well and where each of our sequencing reads aligned.
head aligned_reads/SRR1552444.sam
After a short section that describes the references sequences used for alignment (here we only have a single chromosome; chromosome 1). There is a tab-deliminted section describing the alignment of each read.
1 |
QNAME |
Sequence ID |
2 |
FLAG |
Sequence quality expressed as a bitwise flag |
3 |
RNAME |
Chromosome |
4 |
POS |
Start Position |
5 |
MAPQ |
Mapping Quality |
6 |
CIGAR |
Describes positions of matches, insertions, deletions w.r.t reference |
7 |
RNEXT |
Ref. name of mate / next read |
8 |
PNEXT |
Postion of mate / next read |
9 |
TLEN |
Observed Template length |
10 |
SEQ |
Sequence |
11 |
QUAL |
Base Qualities |
There can also be all manner of optional tags as extra columns introduce by an aligner or downstream analysis tool. A common use is the RG
tag which refers back to the read groups in the header.
The “flags” in the sam file can represent useful QC information
- Read is unmapped
- Read is paired / unpaired
- Read failed QC
- Read is a PCR duplicate (see later)
The combination of any of these properties is used to derive a numeric value
For instance, a particular read has a flag of 163

Derivation
There is a set of properties that a read can possess. If a particular property is observed, a corresponding power of 2 is added multiplied by 1. The final value is derived by summing all the powers of 2.
ReadHasProperty Binary MultiplyBy
isPaired TRUE 1 1
isProperPair TRUE 1 2
isUnmappedQuery FALSE 0 4
hasUnmappedMate FALSE 0 8
isMinusStrand FALSE 0 16
isMateMinusStrand TRUE 1 32
isFirstMateRead FALSE 0 64
isSecondMateRead TRUE 1 128
isSecondaryAlignment FALSE 0 256
isNotPassingQualityControls FALSE 0 512
isDuplicate FALSE 0 1024
Value of flag is given by
1x1 + 1x2 + 0x4 + 0x8 + 0x16 + 1x32 + 0x64 + 1x128 + 0x256 + 0x512 + 0x1024 = 163
See also
Challenge 2
Use HISAT2 to align one of the other fastq files to chromosome 1 of Mouse GRCm38 (say SRR1552445.fastq) What percentage of reads align?
Converting to a bam file
sam
files are easy to read, but rarely used in analysis as they can require large amounts of disk space. The alignments from a sequencing run are more-commonly stored in compressed, binary file know as a bam
file. Exactly the same information is contained, except they are more portable.
samtools
is used for the conversion and manipulation of sam and bam files.
The steps in producing a bam file for analysis are given below. The final step is important as it creates an index file. This index needs to be present in order for analysis tools to access the reads in the file in an efficient manner.
samtools view -bS aligned_reads/SRR1552444.sam > aligned_reads/SRR1552444.bam
samtools sort aligned_reads/SRR1552444.bam -o aligned_reads/SRR1552444.sorted.bam
samtools index aligned_reads/SRR1552444.sorted.bam
The samtools
suite also includes a couple of tools that are useful for QC purposes.
samtools flagstat aligned_reads/SRR1552444.sorted.bam
samtools idxstats aligned_reads/SRR1552444.sorted.bam
Counting features
We will use the featureCounts
tool to obtain transcript-level counts for the aligned reads that we have just created. This requires that gtf
files that we downloaded from Ensembl earlier and our newly-created bam file.
mkdir featureCounts
featureCounts -a ref_data/Mus_musculus.GRCm38.91.chr.gtf.gz -o featureCounts/SRR1552444.counts aligned_reads/SRR1552444.sorted.bam
The command is able to accept multiple bam files
Running alignment for all fastq
files
If we wanted to process all the fastq files in our dataset, the following workflow could be employed. This creates a variable i
that takes all values from 44 to 55 and processes the appropriate fastq file in turn. The echo
command is used here to print the particular sample that is being processed.
for filename in *.fastq.gz
do
name=$(basename $filename .fastq.gz)
echo Processing sample $name
hisat2 -x index/GRCm38_chr1_hisat -U $filename -S aligned_reads/$name.sam
samtools view -bS aligned_reads/$name.sam > aligned_reads/$name.bam
samtools sort aligned_reads/$name.bam -o aligned_reads/$name.sorted.bam
samtools index aligned_reads/$name.sorted.bam
done
LS0tCnRpdGxlOiAiQWxpZ25tZW50IGFuZCBxdWFudGlmaWNhdGlvbiIKYXV0aG9yOiAiTWFyayBEdW5uaW5nIgpkYXRlOiAnYHIgZm9ybWF0KFN5cy50aW1lKCksICJMYXN0IG1vZGlmaWVkOiAlZCAlYiAlWSIpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNzczogc3R5bGVzaGVldHMvc3R5bGVzLmNzcwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBBbGlnbm1lbnQgYW5kIFF1YW50aWZpY2F0aW9uCgpUd28gd29ya2Zsb3dzIGFyZSBwb3NzaWJsZSB3aXRoIFJOQS1zZXEgZGF0YSAtIHdpdGggdGhlIGRpZmZlcmVuY2UgYmVpbmcgd2hldGhlciBvbmUgcGVyZm9ybXMgYW4gYWxpZ25tZW50IHRvIHRoZSByZWZlcmVuY2UgZ2Vub21lIG9yIG5vdC4KClJlY2VudCB0b29scyBmb3IgUk5BLXNlcSBhbmFseXNpcyAoZS5nLiBgc2FsbW9uYCwgYGthbGxpc3RvYCkgZG8gbm90IHJlcXVpcmUgdGhlIHRpbWUtY29uc3VtaW5nIHN0ZXAgb2Ygd2hvbGUtZ2Vub21lIGFsaWdubWVudCB0byBiZSBwZXJmb3JtZWQsIGFuZCBjYW4gdGhlcmVmb3JlIHByb2R1Y2UgZ2VuZS1sZXZlbCBjb3VudHMgaW4gYSBtdWNoIGZhc3RlciB0aW1lIGZyYW1lLiBUaGV5IG5vdCByZXF1aXJlIHRoZSBjcmVhdGlvbiBvZiBsYXJnZSBiYW0gZmlsZXMsIHdoaWNoIGlzIHVzZWZ1bCBpZiBjb25zdHJhaW5lZCBieSBmaWxlIHNwYWNlIG9uIEdhbGF4eS4KCiFbXShodHRwczovL2hiY3RyYWluaW5nLmdpdGh1Yi5pby9JbnRyby10by1ybmFzZXEtaHBjLWd0L2ltZy9hbGlnbm1lbnRmcmVlX3dvcmtmbG93X2F1ZzIwMTcucG5nKQoKKGltYWdlIGZyb20gSGFydmFyZCBCaW9pbmZvcm1hdGljcyBDb3JlKQoKCldlIHdpbGwgZGVtb25zdHJhdGUgYm90aCBtZXRob2RzLCBidXQgZm9yIGZ1cnRoZXIgYW5hbHlzaXMgaW4gUiB3ZSB3aWxsIHVzZSBjb3VudHMgdGhhdCBoYXZlIGJlZW4gZ2VuZXJhdGVkIHdpdGggYHNhbG1vbmAuIAoKQSBtdWNoIHJlZHVjZWQgZGF0YXNldCB3aWxsIGJlIHVzZWQgZm9yIGlsbHVzdHJhdGlvbiBhbHRob3VnaCB0aGUgY29tbWFuZHMgdXNlZCBjYW4gYXBwbGllZCB0byBtb3JlLXJlYWxpc3RpYyBzaXplcyBvZiBkYXRhLgoKV2UgZmlyc3QgbWFrZSBzdXJlIHRoYXQgd2UgYXJlIGxvY2F0ZWQgaW4gdGhlIGRpcmVjdG9yeSB3aXRoIG91ciBmYXN0cSBmaWxlcwoKYGBge2Jhc2ggZXZhbD1GQUxTRX0KY2Qgfi9ybmFzZXFfZGF0YQpscwpgYGAKCldlIHdpbGwgbmVlZCBzb21lIHJlZmVyZW5jZSBkYXRhIGZvciB0aGUgYWxpZ25tZW50LCBhbmQgYSBnb29kIHBsYWNlIHRvIG9idGFpbiB0aGVzZSBkYXRhIGlzIGZyb20gRW5zZW1ibC4gCgpMaW5rcyB0byBkb3dubG9hZHMgZm9yIGEgdmFyaWV0eSBvZiBkaWZmZXJlbnQgb3JnYW5pc21zIGNhbiBiZSBmb3VuZCBhdCBodHRwczovL3d3dy5lbnNlbWJsLm9yZy9pbmZvL2RhdGEvZnRwL2luZGV4Lmh0bWwuIFdlIGNhbiBuYXZpZ2F0ZSB0byB0aGUgcGFydGljdWxhciBvcmdhbmlzbSB3ZSBhcmUgaW50ZXJlc3RlZCBpbiB0aHJvdWdoIHRoZSBpbnRlcmZhY2UgYW5kIGRvd25sb2FkIHRoZSB0cmFuc2NyaXB0IGFuZCBnZW5vbWUgc2VxdWVuY2VzIHRvIG91ciBsYXB0b3AuIEhvd2V2ZXIsIHdlIG5lZWQgdGhlIHJlZmVyZW5jZSBmaWxlcyB0byBiZSBwcmVzZW50IG9uIHRoZSByZW1vdGUgc2VydmVyIHRoYXQgd2UgYXJlIHBlcmZvcm1pbmcgdGhlIGFuYWx5c2lzIG9uLgoKVGhlIGNvbW1hbmQgYHdnZXRgIGNhbiBiZSB1c2VkIHRvIGRvd25sb2FkIGEgZmlsZSBmcm9tIGFuIEZUUCBzaXRlIHRvIGEgbG9jYWwgZGlyZWN0b3J5IGlmIHlvdSBrbm93IHRoZSBwYXRoIHRvIHRoZSBmaWxlIChVUkwpLiBUaGlzIHBhdGggY291bGQgYmUgb2J0YWluZWQgYnkgZmlyc3QgbG9jYXRpbmcgdGhlIGZpbGUgaW4gRW5zZW1ibCBhbmQgcmlnaHQtY2xpY2tpbmcgdG8gY29weSB0aGUgbGluayBhZGRyZXNzLgoKVGhlIGhvbWVwYWdlIG9mIEVuc2VtYmwgRlRQIGluZGV4IGxpbmtzIHRvIHJlZmVyZW5jZSBkYXRhIGZvciBjb21tb24gZ2Vub21lcwoKPGltZyBzcmM9ImltYWdlcy9lbnNlbWJsX2Rvd25sb2FkLnBuZyIvPgoKRmlsZXMgY2FuIGJlIGRvd25sb2FkZWQgYnkgY2xpY2tpbmcgb24gdGhlIHJlbGV2YW50IGxpbmsuIEhvd2V2ZXIsIHdlIHdhbnQgdG8gZG93bmxvYWQgdGhlIGRhdGEgdXNpbmcgdGhlIGNvbW1hbmQgbGluZSBzbyB3ZSBoYXZlIHRvIHJpZ2h0LWNsaWNrIGFuZCBzZWxlY3QgIkNvcHkgTGluayBMb2NhdGlvbiIgKG9yIHNpbWlsYXIpCgo8aW1nIHNyYz0iaW1hZ2VzL2NkbmFfZG93bmxvYWQucG5nIi8+CgpUaGUgZm9sbG93aW5nIGNvbW1hbmRzIHNob3VsZCBkb3dubG9hZCByZWZlcmVuY2UgZGF0YSBmcm9tIEVuc2VtYmwgaW50byBhIG5ld2x5LWNyZWF0ZWQgYHJlZl9kYXRhYCBmb2xkZXIuIEl0IGlzIGdvb2QgcHJhY3RpY2UgdG8ga2VlcCB5b3VyIHJlZmVyZW5jZSBkYXRhIHN0b3JlZCBpbiBhIHN1Yi1mb2xkZXIuICpIb3dldmVyLCBjaGVjayBmaXJzdCAod2l0aCBJLlQgb3IgbG9jYWwgQmlvaW5mb3JtYXRpY2lhbnMpIHRoYXQgeW91IGRvbid0IGhhdmUgYSBsb2NhbCBjb3B5IG9mIHJlZmVyZW5jZSBnZW5vbWVzIG9uIHlvdXIgZmlsZSBzeXN0ZW0qCgpgYGB7YmFzaCBldmFsPUZBTFNFfQpta2RpciByZWZfZGF0YQp3Z2V0IGZ0cDovL2Z0cC5lbnNlbWJsLm9yZy9wdWIvcmVsZWFzZS05MS9mYXN0YS9tdXNfbXVzY3VsdXMvY2RuYS9NdXNfbXVzY3VsdXMuR1JDbTM4LmNkbmEuYWxsLmZhLmd6IC1QIHJlZl9kYXRhLwp3Z2V0IGZ0cDovL2Z0cC5lbnNlbWJsLm9yZy9wdWIvcmVsZWFzZS05MS9ndGYvbXVzX211c2N1bHVzL011c19tdXNjdWx1cy5HUkNtMzguOTEuY2hyLmd0Zi5neiAtUCByZWZfZGF0YQp3Z2V0IGZ0cDovL2Z0cC5lbnNlbWJsLm9yZy9wdWIvcmVsZWFzZS05MS9mYXN0YS9tdXNfbXVzY3VsdXMvZG5hL011c19tdXNjdWx1cy5HUkNtMzguZG5hLmNocm9tb3NvbWUuMS5mYS5neiAtUCByZWZfZGF0YS8KYGBgCgoKCiMjIFdvcmtmbG93IDE6IFF1YW50aWZ5IHRoZSB0cmFuc2NyaXB0cyB3aXRoIHNhbG1vbgoKU2FsbW9uIGlzIGEgdG9vbCBmb3IgcXVhbnRpZnlpbmcgdGhlIGV4cHJlc3Npb24gb2YgdHJhbnNjcmlwdHMgdXNpbmcgUk5BLXNlcSBkYXRhLiBJdCBpcyBiYXNlZCBvbiBhIG5ldwphbGdvcml0aG0gdGhhdCBjb3VwbGVzIHRoZSBjb25jZXB0IG9mIHF1YXNpLW1hcHBpbmcgd2l0aCBhIHR3by1waGFzZSBpbmZlcmVuY2UgcHJvY2VkdXJlLCBwcm92aWRpbmcgYWNjdXJhdGUKZXhwcmVzc2lvbiBlc3RpbWF0ZXMgdmVyeSBxdWlja2x5IGFuZCB1c2luZyBsaXR0bGUgbWVtb3J5LiBJdCBxdWFudGlmaWVzIHRoZSBleHByZXNzaW9uIG9mIHRoZSB0cmFuc2NyaXB0cyBmcm9tCmEgZ2l2ZW4gYW5ub3RhdGlvbiwgc28gaXQgaXMgbm90IGFibGUgdG8gaWRlbnRpZnkgbm9uIGFubm90YXRlZCBnZW5lcyBhbmQgdHJhbnNjcmlwdHMuCgpUaGUgZG9jdW1lbnRhdGlvbiBvZiB0aGUgdG9vbCBpcyBhdmFpbGFibGUgYXQKaHR0cHM6Ly9zYWxtb24ucmVhZHRoZWRvY3MuaW8vZW4vbGF0ZXN0L3NhbG1vbi5odG1sCgpTYWxtb24gaXMgYWJsZSB0byBxdWFudGlmeSB0cmFuc2NyaXB0IGV4cHJlc3Npb24gYnkgdXNpbmcgYSBxdWFzaS1tYXBwaW5nIGFsZ29yaXRobS4gUXVhc2ktbWFwcGluZ3MgYXJlCm1hcHBpbmdzIG9mIHJlYWRzIHRvIHRyYW5zY3JpcHQgcG9zaXRpb25zIHRoYXQgYXJlIGNvbXB1dGVkIHdpdGhvdXQgcGVyZm9ybWluZyBhIGJhc2UtdG8tYmFzZSBhbGlnbm1lbnQKb2YgdGhlIHJlYWQgdG8gdGhlIHRyYW5zY3JpcHQuIFRoaXMgYXBwcm9hY2ggaXMgdHlwaWNhbGx5IG11Y2ggZmFzdGVyIHRvIGNvbXB1dGUgdGhhbiB0cmFkaXRpb25hbCAob3IgZnVsbCkKYWxpZ25tZW50cywgYW5kIGNhbiBzb21ldGltZXMgcHJvdmlkZSBzdXBlcmlvciBhY2N1cmFjeSBieSBiZWluZyBtb3JlIHJvYnVzdCB0byBlcnJvcnMgaW4gdGhlIHJlYWQgb3IKZ2Vub21pYyB2YXJpYXRpb24gZnJvbSB0aGUgcmVmZXJlbmNlIHNlcXVlbmNlCgpgc2FsbW9uYCByZXF1aXJlcyB0aGUgdXNlciB0byBjcmVhdGUgYW4gaW5kZXggZnJvbSB0aGUgYGZhc3RhYCBmaWxlIG9mIHRoZSB0cmFuc2NyaXB0cy4gV2UgaGF2ZSB0byBzcGVjaWZ5IGEgKnByZWZpeCogbmFtZSBmb3IgYWxsIHRoZSBmaWxlcyB0aGF0IGBzYWxtb25gIGlzIGdvaW5nIHRvIGNyZWF0ZS4gCgpgYGB7YmFzaCBldmFsPUZBTFNFfQpzYWxtb24gaW5kZXggLWkgaW5kZXgvR1JDbTM4X3NhbG1vbiAtdCByZWZfZGF0YS9NdXNfbXVzY3VsdXMuR1JDbTM4LmNkbmEuYWxsLmZhLmd6CmBgYAoKVGhlIHF1YXNpLW1hcHBpbmcgYXBwcm9hY2ggb2YgYHNhbG1vbmAgY2FuIGJlIHJ1biB3aXRoIHRoZSBgc2FsbW9uIHF1YW50YCBjb21tYW5kLiBIZWxwIG9uIHJ1bm5pbmcgdGhpcyB0b29sIGNhbiBiZSBkaXNwbGF5ZWQgd2l0aCB0aGUgZm9sbG93aW5nIGNvbW1hbmQuCgpgYGB7YmFzaCBldmFsPUZBTFNFfQpzYWxtb24gcXVhbnQgLS1oZWxwLXJlYWRzCmBgYAoKV2UgbmVlZCB0byBzcGVjaWZ5IHRoZSBwYXRoIG9mIHRoZSBpbmRleCB3ZSBoYXZlIGp1c3QgY3JlYXRlZCBpbiB0aGUgcHJldmlvdXMgc3RlcCwgbG9jYXRpb25zIG9mIG91ciBgZmFzdHFgIGZpbGVzLCBhbmQgdGhlIGxpYnJhcnkgdHlwZSAoaWYgdW5zdXJlIHRoZSBvcHRpb24gQSBjYW4gYmUgdXNlZC4gU2VlIHRoZSBoZWxwIHBhZ2UgZm9yIG1vcmUgb3B0aW9ucyBodHRwczovL3NhbG1vbi5yZWFkdGhlZG9jcy5pby9lbi9sYXRlc3Qvc2FsbW9uLmh0bWwjd2hhdC1zLXRoaXMtbGlidHlwZSkuIFdlIGNhbiBzcGVjaWZ5IHdoZXJlIGBzYWxtb25gIHdyaXRlIGl0J3Mgb3V0cHV0IGZpbGVzIHRvLCBidXQgdGhpcyBkaXJlY3RvcnkgZG9lcyBub3QgbmVlZCB0byBleGlzdCBwcmlvciB0byBydW5uaW5nIHRoZSBjb21tYW5kLgoKYGBge2Jhc2ggZXZhbD1GQUxTRX0Kc2FsbW9uIHF1YW50IC1pIGluZGV4L0dSQ20zOF9zYWxtb24gLS1saWJUeXBlIEEgLXIgU1JSMTU1MjQ0NC5mYXN0cS5neiAtbyBxdWFudC9TUlIxNTUyNDQ0CgpgYGAKCj4gIyMgQ2hhbGxlbmdlIDEgey5jaGFsbGVuZ2V9Cj4gCj4gTmF2aWdhdGUgdG8gdGhlIHF1YW50IGZvbGRlciBhbmQgZXhwbG9yZSB0aGUgZmlsZXMgdGhhdCBzYWxtb24gaGFzIGNyZWF0ZWQuCj4gV2hhdCBmaWxlIGNvbnRhaW5zIHRoZSBxdWFudGlmaWNhdGlvbnM/IAo+IFVzZSB0aGUgc2FsbW9uIGRvY3VtZW50YXRpb24gdG8gdW5kZXJzdGFuZCB0aGUgdmFyaW91cyBvdXRwdXQgZmlsZXMgaHR0cHM6Ly9zYWxtb24ucmVhZHRoZWRvY3MuaW8vZW4vbGF0ZXN0L2ZpbGVfZm9ybWF0cy5odG1sI2ZpbGVmb3JtYXRzCgojIyMgUnVubmluZyBmb3IgYWxsIHNhbXBsZXMKCklmIHdlIHdhbnQgdG8gcmVwZWF0IHRoZSBxdWFudGlmaWNhdGlvbiBzdGVwIGZvciBhbGwgb3VyIHNhbXBsZXMsIHdlIGNvdWxkIGVtcGxveSBhIGBmb3JgIGxvb3AgYXMgd2UgaGF2ZSBzZWVuIHByZXZpb3VzbHkuIAoKYGBge2Jhc2ggZXZhbD1GQUxTRX0KCmZvciBmaWxlbmFtZSBpbiAqLmZhc3RxLmd6CmRvCm5hbWU9JChiYXNlbmFtZSAkZmlsZW5hbWUgLmZhc3RxLmd6KQpzYWxtb24gcXVhbnQgLWkgaW5kZXgvR1JDbTM4X3NhbG1vbiAtLWxpYlR5cGUgQSAtciAkZmlsZW5hbWUuZmFzdHEuZ3ogLW8gcXVhbnQvJG5hbWUKZ3ppcCBxdWFudC8kbmFtZS9xdWFudC5zZgpkb25lCgpgYGAKCgojIyBXb3JrZmxvdyAyOiBBbGlnbiBhbmQgdGhlbiBjb3VudAoKVGhlcmUgYXJlIG51bWVyb3VzIHRvb2xzIHBlcmZvcm1pbmcgc2hvcnQgcmVhZCBhbGlnbm1lbnQgYW5kIHRoZSBjaG9pY2Ugb2YgYWxpZ25lciBzaG91bGQgYmUKY2FyZWZ1bGx5IG1hZGUgYWNjb3JkaW5nIHRvIHRoZSBhbmFseXNpcyBnb2Fscy9yZXF1aXJlbWVudHMuIEhlcmUgd2Ugd2lsbCB1c2UKSElTQVQyLCBhIGZhc3QgYWxpZ25lciB3aXRoIGxvdyBtZW1vcnkgcmVxdWlyZW1lbnRzIHRoYXQgcGVyZm9ybXMgc3BsaWNlZCBhbGlnbm1lbnRzLiBJdCBpcyB0aGUgcHJvZ3JhbQpzdWdnZXN0ZWQgZm9yIHRoZSBhbGlnbm1lbnQgaW4gdGhlIG5ldyBUdXhlZG8KcHJvdG9jb2wgKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDM4L25wcm90LjIwMTYuMDk1KSBhbmQgaXQgcmVxdWlyZXMgYW4gaW5kZXhlZCBnZW5vbWUgdG8ga2VlcCBpdHMgbWVtb3J5IGZvb3RwcmludCBzbWFsbCBhbmQgdGhlIHJ1bm5pbmcKdGltZSBzaG9ydC4gCgpUaGUgcHJvZ3JhbSBjcmVhdGVzIGEgZ2Vub21lIGluZGV4IGJ5IHVzaW5nIHRoZSAqRkFTVEEqIGZpbGUgb2YgdGhlCnNlcXVlbmNlIHdlIHdhbnQgdG8gdXNlIGFzIHJlZmVyZW5jZS4gQSBzZXF1ZW5jZSBpbiAqRkFTVEEqIGZvcm1hdCBiZWdpbnMgd2l0aCBhIHNpbmdsZS1saW5lCmRlc2NyaXB0aW9uLCBmb2xsb3dlZCBieSBsaW5lcyBvZiBzZXF1ZW5jZSBkYXRhLiBUaGUgZGVzY3JpcHRpb24gbGluZSBpcyBkaXN0aW5ndWlzaGVkIGZyb20gdGhlCnNlcXVlbmNlIGRhdGEgYnkgYSBncmVhdGVyLXRoYW4gKGA+YCkgc3ltYm9sIGF0IHRoZSBiZWdpbm5pbmcuCgojIyMgQ3JlYXRpbmcgYSBnZW5vbWUgaW5kZXgKCldlIGhhdmUgYWxyZWFkeSBkb3dubG9hZGVkIHRoZSByZWZlcmVuY2UgZmlsZSB0aGF0IHdlIHdhbnQgdG8gdXNlLiBIb3dldmVyLCBpdCBpcyBpbiBhIGNvbXByZXNzZWQgZm9ybWF0IGFuZCBub3QgaW1tZWRpYXRlbHkgdXNlZnVsIGZvciBidWlsZGluZyB0aGUgZ2Vub21lIGluZGV4LiBXZSBuZWVkIHRvIHVuLWNvbXByZXNzIHRoZSBmaWxlIGZpcnN0IHVzaW5nIHRoZSBgZ3VuemlwYCBjb21tYW5kIChzaW1pbGFyIHRvIGB1bnppcGAgdGhhdCB3ZSB1c2VkIGVhcmxpZXIgaW4gdGhlIGNvdXJzZSkuIFRoaXMgc2hvdWxkIG5vdyByZXBsYWNlIHRoZSBmaWxlIGByZWZfZGF0YS9NdXNfbXVzY3VsdXMuR1JDbTM4LmRuYS5jaHJvbW9zb21lLjEuZmEuZ3pgIHdpdGggYHJlZl9kYXRhL011c19tdXNjdWx1cy5HUkNtMzguZG5hLmNocm9tb3NvbWUuMS5mYWAKCgoKVGhlIGNvbW1hbmQgYGhpc2F0Mi1idWlsZGAgaXMgdXNlZCB0byB0YWtlIHRoZSByZWZlcmVuY2Ugc2VxdWVuY2UgYW5kIGNyZWF0ZSBhbiBlZmZpY2llbnQgZGF0YSBzdHJ1Y3R1cmUgZm9yIHNlYXJjaGluZy4gV2UgbmVlZCB0byBzcGVjaWZ5IGEgKnByZWZpeCogdGhhdCB3aWxsIGJlIHVzZWQgdG8gbmFtZSB0aGUgZmlsZXMgdGhhdCBgaGlzYXQyYCBnZW5lcmF0ZXMuIAoKVGhlIGluZGV4IHN0ZXAgb25seSBuZWVkcyB0byBiZSBydW4gb25jZSBmb3IgYSBwYXJ0aWN1bGFyIGdlbm9tZSB2ZXJzaW9ucy4gWW91IGNhbiB1c2UgdGhlIHNhbWUgaW5kZXggdG8gYWxpZ24gbXVsdGlwbGUgc2FtcGxlcy4KCioqTm90ZSB0aGF0IHRoZSBmb2xsb3dpbmcgaW5kZXggcHJvY2VkdXJlIG1heSB0YWtlIGEgZmV3IG1pbnV0ZXMgdG8gcnVuKioKCmBgYHtiYXNoIGV2YWw9RkFMU0V9Cmd1bnppcCByZWZfZGF0YS9NdXNfbXVzY3VsdXMuR1JDbTM4LmRuYS5jaHJvbW9zb21lLjEuZmEuZ3oKaGlzYXQyLWJ1aWxkIHJlZl9kYXRhL011c19tdXNjdWx1cy5HUkNtMzguZG5hLmNocm9tb3NvbWUuMS5mYSBpbmRleC9HUkNtMzhfY2hyMV9oaXNhdApgYGAKCgpUaGUgaW5kZXggZmlsZXMgb2YgTW91c2UgZ2Vub21lIEdSQ20zOCBjaHJvbW9zb21lIDEgIHNob3VsZCBub3cgYmUgaW4gdGhlIGRpcmVjdG9yeSBgaW5kZXgvYC4gQWxsIG9mIHRoZW0gaGF2ZSBhIGZpbGUgbmFtZSBzdGFydGluZyB3aXRoIHRoZSBgR1JDbTM4X2NocjFfaGlzYXRgIHByZWZpeC4KCiMjIyBBbGlnbm1lbnQgd2l0aCBoaXNhdDIKClRoZXJlIGFyZSBzZXZlcmFsIHBhcmFtZXRlcnMgd2UgbWlnaHQgd2FudCB0byBzcGVjaWZ5IGluIG9yZGVyIHRvIGFsaWduIG91ciByZWFkcyB3aXRoIEhJU0FUMi4gVG8gdmlldyB0aGVtIGFsbCB0eXBlLiAKCgpgYGB7YmFzaCBldmFsPUZBTFNFfQpoaXNhdDIgLS1oZWxwCmBgYAoKVG8gYWxpZ24gb25lIG9mIG91ciBleGFtcGxlIGZpbGVzIGFnYWluc3QgdGhlICppbmRleCogdGhhdCB3ZSBoYXZlIGp1c3QgY3JlYXRlZCB3ZSBuZWVkIHRvIAoKLSBjaGFuZ2UgdGhlIGAteGAgYXJndW1lbnQgdG8gYmUgdGhlIGZpbGUgcHJlZml4IG9mIGFsbCB0aGUgaW5kZXggZmlsZXMgY3JlYXRlZCBpbiB0aGUgcHJldmlvdXMgc3RlcC4gCi0gc3BlY2lmeSB0aGF0IG91ciByZWFkcyBhcmUgKnVuLXBhaXJlZCogYW5kIHRvIGJlIGZvdW5kIGluIHRoZSBmaWxlIGBTUlIxNTUyNDQ0LmZhc3RxLmd6YAotIHNwZWNpZnkgYW4gb3V0cHV0IGZpbGUgZm9yIHRoZSBhbGlnbm1lbnRzLiBXZSB3aWxsIGNyZWF0ZSBhIG5ldyBkaXJlY3RvcnkgdG8gc2F2ZSB0aGVzZSBhbGlnbm1lbnRzIHRvIGBhbGlnbmVkX3JlYWRzYAoKYGBge2Jhc2ggZXZhbD1GQUxTRX0KbWtkaXIgYWxpZ25lZF9yZWFkcwpoaXNhdDIgLXggaW5kZXgvR1JDbTM4X2NocjFfaGlzYXQgLVUgU1JSMTU1MjQ0NC5mYXN0cS5neiAtUyBhbGlnbmVkX3JlYWRzL1NSUjE1NTI0NDQuc2FtCmBgYAoKVGhlIG91dHB1dCBmaWxlIGNyZWF0ZWQgaXMgYW4gZXhhbXBsZSBvZiBhIFNlcXVlbmNlIEFsaWdubWVudC9NYXAgKFNBTSkgZmlsZS4gVGhpcyBpcyBhIGh1bWFuLXJlYWRhYmxlIGZpbGUgdGhhdCB0ZWxscyB1cyBob3cgd2VsbCBhbmQgd2hlcmUgZWFjaCBvZiBvdXIgc2VxdWVuY2luZyByZWFkcyBhbGlnbmVkLgoKYGBge2Jhc2ggZXZhbD1GQUxTRX0gCmhlYWQgYWxpZ25lZF9yZWFkcy9TUlIxNTUyNDQ0LnNhbQpgYGAKCkFmdGVyIGEgc2hvcnQgc2VjdGlvbiB0aGF0IGRlc2NyaWJlcyB0aGUgcmVmZXJlbmNlcyBzZXF1ZW5jZXMgdXNlZCBmb3IgYWxpZ25tZW50IChoZXJlIHdlIG9ubHkgaGF2ZSBhIHNpbmdsZSBjaHJvbW9zb21lOyBjaHJvbW9zb21lIDEpLiBUaGVyZSBpcyBhIHRhYi1kZWxpbWludGVkIHNlY3Rpb24gZGVzY3JpYmluZyB0aGUgYWxpZ25tZW50IG9mIGVhY2ggcmVhZC4KCgpDb2x1bW4gfCBPZmZpY2lhbCBOYW1lIHwgQnJpZWYKLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0gfCAtLS0tLS0tLS0tLQoxICAgICAgfCBRTkFNRSAgICAgICAgICB8IFNlcXVlbmNlIElECjIgICAgICB8IEZMQUcgICAgICAgICAgIHwgU2VxdWVuY2UgcXVhbGl0eSBleHByZXNzZWQgYXMgYSBiaXR3aXNlIGZsYWcKMyAgICAgIHwgUk5BTUUgICAgICAgICAgfCBDaHJvbW9zb21lCjQgICAgICB8IFBPUyAgICAgICAgICAgIHwgU3RhcnQgUG9zaXRpb24KNSAgICAgIHwgTUFQUSAgICAgICAgICAgfCBNYXBwaW5nIFF1YWxpdHkKNiAgICAgIHwgQ0lHQVIgICAgICAgICAgfCBEZXNjcmliZXMgcG9zaXRpb25zIG9mIG1hdGNoZXMsIGluc2VydGlvbnMsIGRlbGV0aW9ucyB3LnIudCByZWZlcmVuY2UKNyAgICAgIHwgUk5FWFQgICAgICAgICAgfCBSZWYuIG5hbWUgb2YgbWF0ZSAvIG5leHQgcmVhZAo4ICAgICAgfCBQTkVYVCAgICAgICAgICB8IFBvc3Rpb24gb2YgbWF0ZSAvIG5leHQgcmVhZAo5ICAgICAgfCBUTEVOICAgICAgICAgICB8IE9ic2VydmVkIFRlbXBsYXRlIGxlbmd0aAoxMCAgICAgfCBTRVEgICAgICAgICAgICB8IFNlcXVlbmNlCjExICAgICB8IFFVQUwgICAgICAgICAgIHwgQmFzZSBRdWFsaXRpZXMKClRoZXJlIGNhbiBhbHNvIGJlIGFsbCBtYW5uZXIgb2Ygb3B0aW9uYWwgdGFncyBhcyBleHRyYSBjb2x1bW5zIGludHJvZHVjZSBieSBhbiBhbGlnbmVyIG9yIGRvd25zdHJlYW0gYW5hbHlzaXMgdG9vbC4gQSBjb21tb24gdXNlIGlzIHRoZSBgUkdgIHRhZyB3aGljaCByZWZlcnMgYmFjayB0byB0aGUgcmVhZCBncm91cHMgaW4gdGhlIGhlYWRlci4KCgpUaGUgKiJmbGFncyIqIGluIHRoZSBzYW0gZmlsZSBjYW4gcmVwcmVzZW50IHVzZWZ1bCBRQyBpbmZvcm1hdGlvbgoKICArIFJlYWQgaXMgdW5tYXBwZWQKICArIFJlYWQgaXMgcGFpcmVkIC8gdW5wYWlyZWQKICArIFJlYWQgZmFpbGVkIFFDCiAgKyBSZWFkIGlzIGEgUENSIGR1cGxpY2F0ZSAoc2VlIGxhdGVyKQoKVGhlIGNvbWJpbmF0aW9uIG9mIGFueSBvZiB0aGVzZSBwcm9wZXJ0aWVzIGlzIHVzZWQgdG8gZGVyaXZlIGEgbnVtZXJpYyB2YWx1ZQoKCkZvciBpbnN0YW5jZSwgYSBwYXJ0aWN1bGFyIHJlYWQgaGFzIGEgZmxhZyBvZiAxNjMKCiFbXShpbWFnZXMvZmxhZy1oaWdobGlnaHQucG5nKQoKCiMjIyBEZXJpdmF0aW9uCgpUaGVyZSBpcyBhIHNldCBvZiBwcm9wZXJ0aWVzIHRoYXQgYSByZWFkIGNhbiBwb3NzZXNzLiBJZiBhIHBhcnRpY3VsYXIgcHJvcGVydHkgaXMgb2JzZXJ2ZWQsIGEgY29ycmVzcG9uZGluZyBwb3dlciBvZiAyIGlzIGFkZGVkIG11bHRpcGxpZWQgYnkgMS4gVGhlIGZpbmFsIHZhbHVlIGlzIGRlcml2ZWQgYnkgc3VtbWluZyBhbGwgdGhlIHBvd2VycyBvZiAyLgoKCmBgYAogCVJlYWRIYXNQcm9wZXJ0eSAJQmluYXJ5IAlNdWx0aXBseUJ5CmlzUGFpcmVkIAlUUlVFIAkxIAkxCmlzUHJvcGVyUGFpciAJVFJVRSAJMSAJMgppc1VubWFwcGVkUXVlcnkgCUZBTFNFIAkwIAk0Cmhhc1VubWFwcGVkTWF0ZSAJRkFMU0UgCTAgCTgKaXNNaW51c1N0cmFuZCAJRkFMU0UgCTAgCTE2CmlzTWF0ZU1pbnVzU3RyYW5kIAlUUlVFIAkxIAkzMgppc0ZpcnN0TWF0ZVJlYWQgCUZBTFNFIAkwIAk2NAppc1NlY29uZE1hdGVSZWFkIAlUUlVFIAkxIAkxMjgKaXNTZWNvbmRhcnlBbGlnbm1lbnQgCUZBTFNFIAkwIAkyNTYKaXNOb3RQYXNzaW5nUXVhbGl0eUNvbnRyb2xzIAlGQUxTRSAJMCAJNTEyCmlzRHVwbGljYXRlIAlGQUxTRSAJMCAJMTAyNAoKYGBgClZhbHVlIG9mIGZsYWcgaXMgZ2l2ZW4gYnkgCmBgYAoxeDEgKyAxeDIgKyAweDQgKyAweDggKyAweDE2ICsgMXgzMiArIDB4NjQgKyAxeDEyOCArIDB4MjU2ICsgMHg1MTIgKyAweDEwMjQgPSAxNjMKYGBgCgpTZWUgYWxzbwoKLSBodHRwczovL2Jyb2FkaW5zdGl0dXRlLmdpdGh1Yi5pby9waWNhcmQvZXhwbGFpbi1mbGFncy5odG1sCgoKPiAjIyBDaGFsbGVuZ2UgMiB7LmNoYWxsZW5nZX0KPiAKPiBVc2UgSElTQVQyIHRvIGFsaWduIG9uZSBvZiB0aGUgb3RoZXIgZmFzdHEgZmlsZXMgdG8gY2hyb21vc29tZSAxIG9mIE1vdXNlIEdSQ20zOCAoc2F5IFNSUjE1NTI0NDUuZmFzdHEpIAo+IFdoYXQgcGVyY2VudGFnZSBvZiByZWFkcyBhbGlnbj8KCiMjIyBDb252ZXJ0aW5nIHRvIGEgYmFtIGZpbGUKCmBzYW1gIGZpbGVzIGFyZSBlYXN5IHRvIHJlYWQsIGJ1dCByYXJlbHkgdXNlZCBpbiBhbmFseXNpcyBhcyB0aGV5IGNhbiByZXF1aXJlIGxhcmdlIGFtb3VudHMgb2YgZGlzayBzcGFjZS4gVGhlIGFsaWdubWVudHMgZnJvbSBhIHNlcXVlbmNpbmcgcnVuIGFyZSBtb3JlLWNvbW1vbmx5IHN0b3JlZCBpbiBjb21wcmVzc2VkLCBiaW5hcnkgZmlsZSBrbm93IGFzIGEgYGJhbWAgZmlsZS4gRXhhY3RseSB0aGUgc2FtZSBpbmZvcm1hdGlvbiBpcyBjb250YWluZWQsIGV4Y2VwdCB0aGV5IGFyZSBtb3JlIHBvcnRhYmxlLgoKYHNhbXRvb2xzYCBpcyB1c2VkIGZvciB0aGUgY29udmVyc2lvbiBhbmQgbWFuaXB1bGF0aW9uIG9mIHNhbSBhbmQgYmFtIGZpbGVzLiAKCi0gaHR0cDovL3d3dy5odHNsaWIub3JnLwoKVGhlIHN0ZXBzIGluIHByb2R1Y2luZyBhIGJhbSBmaWxlIGZvciBhbmFseXNpcyBhcmUgZ2l2ZW4gYmVsb3cuIFRoZSBmaW5hbCBzdGVwIGlzIGltcG9ydGFudCBhcyBpdCBjcmVhdGVzIGFuICppbmRleCBmaWxlKi4gVGhpcyBpbmRleCBuZWVkcyB0byBiZSBwcmVzZW50IGluIG9yZGVyIGZvciBhbmFseXNpcyB0b29scyB0byBhY2Nlc3MgdGhlIHJlYWRzIGluIHRoZSBmaWxlIGluIGFuIGVmZmljaWVudCBtYW5uZXIuCgoKYGBge2Jhc2ggZXZhbD1GQUxTRX0Kc2FtdG9vbHMgdmlldyAtYlMgYWxpZ25lZF9yZWFkcy9TUlIxNTUyNDQ0LnNhbSA+IGFsaWduZWRfcmVhZHMvU1JSMTU1MjQ0NC5iYW0Kc2FtdG9vbHMgc29ydCBhbGlnbmVkX3JlYWRzL1NSUjE1NTI0NDQuYmFtIC1vIGFsaWduZWRfcmVhZHMvU1JSMTU1MjQ0NC5zb3J0ZWQuYmFtCnNhbXRvb2xzIGluZGV4IGFsaWduZWRfcmVhZHMvU1JSMTU1MjQ0NC5zb3J0ZWQuYmFtCmBgYAoKVGhlIGBzYW10b29sc2Agc3VpdGUgYWxzbyBpbmNsdWRlcyBhIGNvdXBsZSBvZiB0b29scyB0aGF0IGFyZSB1c2VmdWwgZm9yIFFDIHB1cnBvc2VzLgoKYGBge2Jhc2ggZXZhbD1GQUxTRX0Kc2FtdG9vbHMgZmxhZ3N0YXQgYWxpZ25lZF9yZWFkcy9TUlIxNTUyNDQ0LnNvcnRlZC5iYW0Kc2FtdG9vbHMgaWR4c3RhdHMgYWxpZ25lZF9yZWFkcy9TUlIxNTUyNDQ0LnNvcnRlZC5iYW0KYGBgCgoKIyMjIENvdW50aW5nIGZlYXR1cmVzCgpXZSB3aWxsIHVzZSB0aGUgYGZlYXR1cmVDb3VudHNgIHRvb2wgdG8gb2J0YWluIHRyYW5zY3JpcHQtbGV2ZWwgY291bnRzIGZvciB0aGUgYWxpZ25lZCByZWFkcyB0aGF0IHdlIGhhdmUganVzdCBjcmVhdGVkLiBUaGlzIHJlcXVpcmVzIHRoYXQgYGd0ZmAgZmlsZXMgdGhhdCB3ZSBkb3dubG9hZGVkIGZyb20gRW5zZW1ibCBlYXJsaWVyIGFuZCBvdXIgbmV3bHktY3JlYXRlZCBiYW0gZmlsZS4KCgpgYGB7YmFzaCBldmFsPUZBTFNFfQpta2RpciBmZWF0dXJlQ291bnRzCmZlYXR1cmVDb3VudHMgLWEgcmVmX2RhdGEvTXVzX211c2N1bHVzLkdSQ20zOC45MS5jaHIuZ3RmLmd6IC1vIGZlYXR1cmVDb3VudHMvU1JSMTU1MjQ0NC5jb3VudHMgYWxpZ25lZF9yZWFkcy9TUlIxNTUyNDQ0LnNvcnRlZC5iYW0KCmBgYAoKVGhlIGNvbW1hbmQgaXMgYWJsZSB0byBhY2NlcHQgbXVsdGlwbGUgYmFtIGZpbGVzCgojIyMgUnVubmluZyBhbGlnbm1lbnQgZm9yIGFsbCBgZmFzdHFgIGZpbGVzCgpJZiB3ZSB3YW50ZWQgdG8gcHJvY2VzcyBhbGwgdGhlIGZhc3RxIGZpbGVzIGluIG91ciBkYXRhc2V0LCB0aGUgZm9sbG93aW5nIHdvcmtmbG93IGNvdWxkIGJlIGVtcGxveWVkLiBUaGlzIGNyZWF0ZXMgYSB2YXJpYWJsZSBgaWAgdGhhdCB0YWtlcyBhbGwgdmFsdWVzIGZyb20gNDQgdG8gNTUgYW5kIHByb2Nlc3NlcyB0aGUgYXBwcm9wcmlhdGUgZmFzdHEgZmlsZSBpbiB0dXJuLiBUaGUgYGVjaG9gIGNvbW1hbmQgaXMgdXNlZCBoZXJlIHRvIHByaW50IHRoZSBwYXJ0aWN1bGFyIHNhbXBsZSB0aGF0IGlzIGJlaW5nIHByb2Nlc3NlZC4KCmBgYHtiYXNoIGV2YWw9RkFMU0V9CmZvciBmaWxlbmFtZSBpbiAqLmZhc3RxLmd6CmRvCm5hbWU9JChiYXNlbmFtZSAkZmlsZW5hbWUgLmZhc3RxLmd6KQplY2hvIFByb2Nlc3Npbmcgc2FtcGxlICRuYW1lCmhpc2F0MiAteCBpbmRleC9HUkNtMzhfY2hyMV9oaXNhdCAtVSAkZmlsZW5hbWUgLVMgYWxpZ25lZF9yZWFkcy8kbmFtZS5zYW0gCnNhbXRvb2xzIHZpZXcgLWJTIGFsaWduZWRfcmVhZHMvJG5hbWUuc2FtID4gYWxpZ25lZF9yZWFkcy8kbmFtZS5iYW0Kc2FtdG9vbHMgc29ydCBhbGlnbmVkX3JlYWRzLyRuYW1lLmJhbSAtbyBhbGlnbmVkX3JlYWRzLyRuYW1lLnNvcnRlZC5iYW0Kc2FtdG9vbHMgaW5kZXggYWxpZ25lZF9yZWFkcy8kbmFtZS5zb3J0ZWQuYmFtCmRvbmUKYGBgCg==