The study of gene expression
- The first part of this course focussed on proteomics, studying the concentration of proteins in biological samples. We have seen that identification of proteins and measuring their respective concentrations are extremely challenging, leading to many technological and statistical challenges in order to interpret these data.
- In the second part of the course, we will focus on measuring gene expression, i.e., measuring the concentration of mRNA molecules, that may eventually be translated into proteins, but may also have functions on their own.
Sequencing technology
- Measuring mRNA molecules typically happens through sequencing.
- The technology continues to evolve at an incredible speed. The data output of so-called `next generation’ sequencing machines has more than doubled each year! Simultaneously, the cost of sequencing (in terms of $ per Gigabase) is dropping. Each year, we’re able to sequence more for less money, providing more information, as well as also computational and statistical challenges.
- This tremendous technological revolution has revolutionized biology, and genomic sequencing is now a core component of the modern-day biologist’s toolkit.
- The large majority of sequencing data is generated using sequencing-by-synthesis using machines produced by the company Illumina. While new players such as Pacific Biosciences and Oxford Nanopore have entered the scene, these are typically most useful for (but not limited to) DNA sequencing rather than gene expression studies, owing to their capability of sequencing long molecules.
The sequencing workflow
Library preparation steps:
- First, the biological samples of interest are collected. Owing to the maturity of different protocols for sequencing, several types of biological input samples are amenable to sequencing, such as frozen tissues or FFPE-preserved samples.
- The (m)RNA molecules from our sample are captured. This typically involves cell lysis in order to release the (m)RNA molecules from within the cells. The mRNA molecules are most often captured using (i) polyA-capture to select for polyadenylated RNA, or (ii) ribosomal depletion, where ribosomal and transfer RNAs are depleted, and so also non-polyA-mRNA molecules may be captured, such as micro RNAs. In the case of `targeted sequencing’, where relevant molecules are of main interest (e.g., a gene panel), these targets can be specifically targeted in this step.
- Fragmentation of captured molecules. The captured molecules are fragmented, either chemically or mechanically. The appropriate size of fragments depends on the sequencing machines, but is often in the range of 300 - 500bp.
- Reverse transcription. Current dominant sequencing machines only sequence double-stranded DNA molecules. Therefore, in order to measure single-stranded mRNA, we must first reverse transcribe these molecules to a double-stranded complementary (cDNA) molecule.
- Adapter ligation. Adapters are oligonucleotides (short sequences of nucleotides) that are platform-specific sequences for fragment recognition by the sequencing machines. These are added either to the 3’ or 5’ end of the cDNA molecules or used as primers in the reverse transcription reaction. The final cDNA library consists of cDNA inserts flanked by an adapter sequence on each end.
- PCR amplification. To increase concentration, several PCR reaction cycles are performed.
- Loading the amplified cDNA library on the sequencing machine. Find out how sequencing-by-synthesis works through this video. Note that the video shows paired-end sequencing, where a number of basepairs are sequenced at each end of the fragment. All previous steps together are described as `sample prep’ in that video.
Note that several variants of library preparation protocols are available. The most important ones are:
- Single-end vs paired-end sequencing: In single-end sequencing, a single end (3’ or 5’) of the cDNA fragment is sequenced. In paired-end sequencing, both ends are sequenced, and depending on the size of the fragment, the reads may or may not overlap.
- Strand-specific protocols: Some library preparation protocols allow measuring strand specificity, where the strand information (i.e., sense/antisense) of each read can be preserved.
The sequencing output files
- The typical output of a sequencing machine we will be working with are FASTA or FASTQ files for each sample. Each of these files are several gigbases large and contain millions of sequences, which we will call reads. For paired-end sequencing, there are two files for each sample, one for each end of the sequenced fragments.
- The difference between a FASTA file and a FASTQ file, is that while FASTA files only store the results of base calls (sequences), FASTQ files also store the quality score of each base call (i.e., each called nucleotide), which can be useful in downstream analyses such as mapping or variant calling.
- A FASTQ file contains four lines for each sequenced read:
- Sequence identifier line, starting with @.
- The sequence.
- Another sequence identifier line, now starting with +.
- Quality scores.
As you’ll have noticed, the base call quality scores are encoded as ASCII characters for efficient storage. These ASCII characters can be converted into integers called Phred scores, which are logarithmically related to the probability of an erroneous base call.
Many published papers upload their raw FASTQ-files on the Gene Expression Omnibus (GEO). If you’ll be working in transcriptomics, you will most likely have to download files from there. You can get the links manually, e.g., by following this tutorial, through R
using custom packages, e.g., GEOfastq, or you can use a command-line program like kingfisher (recommended).
Preprocessing of raw sequencing data
After sequencing, we typically do a quality control (QC) check to verify the quality of the samples. During QC check, aberrant samples due to e.g. degraded mRNA can be detected.
The sequencing reads on their own contain a lot of information, but are most useful if we would be able to assign sequencing reads to genomic features (genes, exons, transcripts, etc.), i.e., for each sequencing read we will try to derive the (set of) feature(s) that could have plausibly produced the fragment through the process of gene expression. This process is called mapping. Most often we map reads to genes.
Quality control
During quality control, diagnostic plots are created for each sample in order to determine its quality. The most popular QC tool for bulk RNA-seq data is FastQC. If many samples are sequenced, then MultiQC can be used to aggregate the QC checks across samples in a conveniently organized overview.
The FastQC website provides interesting example reports for us to look at and compare against. Here are example reports of high-quality Illumina data and low-quality Illumina data.
Mapping
- Mapping is a critical step in the interpretation of RNA-seq data, where we are attributing reads to genomic features.
- Allows us to measure how strong a feature such as a gene is expressed: the number of reads mapping to a gene serve as a proxy for how high that gene has been expressed in the sample.
- While this opens the door to many opportunities, mapping is hard.
- We are typically unable to assign each individual read uniquely to one specific gene; some reads cannot be unambiguously mapped and are compatible with multiple genes. These reads are said to be ‘multi-mapping’.
Finally, a note on terminology. In this text we will use the words ‘read’ or ‘fragment’ (referring to the fragmented mRNA molecule being sequenced) to designate a datum, note that this could be either a single read (in single-end sequencing) or a read pair (in paired-end sequencing). The literature may also use these words interchangeably, although ‘fragment’ seems better at avoiding ambiguity between single-end reads and paired-end read pairs.
Reference files
- The alignment most often relies on a reference genome of the species, which can be considered a ‘representative example’ of the genome sequence of that species. Reference genomes are contiuously updated and released periodically.
- Reference genomes can be freely downloaded from several providers, for example Ensembl or Gencode.
- Along with a reference genome, an annotation GFF or GTF file defines the coordinates of specific genomic features.
- While here we will focus on reference-based alignment, i.e., alignment where a reference genome or transcriptome is available, note that a de novo construction of a reference transcriptome is also possible, where the reference may be constructed from the observed sequencing reads.
- More recently, mapping of RNA-seq data occurs more often against a reference transcriptome, which is a reference file containing the sequences all known isoforms of a particular species, e.g., using kallisto or Salmon.
- The set of spliced transcripts is much smaller than the entire genome, and therefore mapping against a reference transcriptome is typically fast and memory efficient.
- However, it has been noted that mapping against a reference transcriptome may also introduce spurious expression for genes that are not expressed. These observations can be explained by intronic reads that share some sequence similarity with transcripts, and could map to spliced transcript sequences. Recent methods, such as alevin-fry, avoid this by expanding the reference transcriptome to also include intronic sequences.
Alignment-based workflows
- Traditionally, alignment-based workflows have been used to map reads, where one tries to find the exact coordinates a read maps to on the reference genome or the reference transcriptome.
- Note that due to alternative splicing, reads do not necessarily map contiguously on a reference genome, as a read can overlap with a splicing junction, where an intron has been excised. When mapping against a transcriptome, however, reads should be mapping contiguously.
- A main challenge in spliced alignment against a reference genome is the proper alignment of reads that span a splice junction, especially when these junctions are not annotated a priori. Indeed, in spliced alignment reads can be split at any nucleotide, and the corresponding subsequences can map several thousands of basepairs apart. Meanwhile, the main challenge in unspliced alignment to a transcriptome is the redundant sequence among related transcripts in the transcriptome, which often leads to a high multi-mapping rate (i.e., reads that cannot be unambiguously assigned to a single transcript).
- Spliced alignment against a genome is therefore computationally a much harder task. Since the transcript sequences are already spliced when aligning to a reference transcriptome, reads should align contiguously, and many of the computationally expensive steps and heuristics can be avoided, there.
Alignment-free workflows
- Modern approaches avoid mapping each fragment individually (i.e., do not attempt to find the exact coordinates of a read’s origin), and instead posit a probabilistic model where transcript abundances are typically defined using its constituent \(k\)-mers. These methods are sometimes referred to as lightweight.
- A \(k\)-mer is a short sequence of nucleotides of length \(k\). The space of possible \(k\)-mers and the corresponding transcripts can be precomputed in advance using the reference transcriptome, providing a computational advantage as it only needs to be computed once.
- For each fragment, the transcripts its \(k\)-mers are compatible with is searched for using an indexed (efficiently searchable) transcriptome. The set of compatible transcripts is called the ‘\(k\)-compatibility class’, ‘equivalence class’ or ‘transcript compatibility class’ of the fragment.
Abundance quantification
Given a set of mappings, using either alignment-based or alignment-free workflows, the estimation of expression of a gene/transcript/exon may occur in several ways.
Counting:
- In alignment-based workflows, one could do a direct counting of fragments at, for instance, the gene level, counting the number fragments mapping to each gene. This has been the dominant approach for the first decade of RNA-seq data, often obtained using reference genome alignments.
- Many heuristic choices need to be made: Do we count a fragment as soon as it intersects with the gene’s coordinates, or do we require the full fragment to map to the gene? Do we count intronic reads? Do we count multi-mapping reads?
Estimation:
- Abundance quantification is more recently starting to shift from counting towards using statistical models to estimate the expression counts for a feature, which in this case is typically a transcript.
- This approach is amenable to alignment-free workflows, since the number of fragments in each equivalence class are sufficient statistics for the abundance quantification, meaning that they contain all information needed to estimate the parameters of the statistical model, and hence the feature-level abundances. Since the expression counts in this case are estimated, they are not necessarily integer counts, and will be referred to as ‘estimated counts’.
- In order to derive these, the EM-algorithm (Dempster et al. (1977)) is often used, although other approaches have been used by tools like Salmon. A big advantage of the estimation approach is that it probabilistically assigns fragments to transcripts, thereby automatically dealing with multi-mapping reads. The total number of fragments mapping to each transcript is then the sum of all fragment-level probabilities to be assigned to that respective transcript.
Abundance metrics
- For simplicity, we have mainly been talking about feature-level counts as in sums of fragments. However, this is merely one metric that can be used as a proxy for expression, and several others exist.
- Most of these were introduced to attempt to make the abundances more comparable across samples or features, as compared to the simple counts. These mainly serve to correct for technical biases such as transcript length and sequencing depth, both of which have significant impact on the observed counts.
- Indeed, for a gene with the same mRNA concentration in two samples, sequencing one sample deeper, will on average result in a higher count.
- Likewise, for two transcripts with the same mRNA concentration but different transcript lengths, one will tend to observe more fragments from the longer transcript due to the fragmentation step in the RNA-seq protocol, where longer transcripts can be split into more fragments of appropriate length.
Below we introduce several relevant abundance metrics, but note that most data analysis methods we will discuss in this course will work with (estimated) counts. In what follows, let \(Y_{fi}\) denote the random variable representing the expression counts of feature \(f\) in sample \(i\) (obtained either as a simple sum of fragments or estimated using lightweight approaches), and let \(N_i = \sum_f Y_{fi}\) denote the sequencing depth (‘library size’) of sample \(i\).
- Counts per million (CPM) are the counts one could expect to observe if the sample was sequenced to a depth of one million.
\[ CPM_{fi} = \frac{Y_{fi}}{N_i} 10^6 \]
- Transcripts per million (TPM) refers to the concentration or proportion of your feature in the sample. TPMs take into account the length of the feature, which is often reformulated into an effective length \(l_{fi}^{(eff)}\), relating to the number of possible start sites that a feature may have in order to generate fragments of a typical length observed in your dataset. This typical length is often calculated using the observed fragment length distribution from the data and defined as \[ l_{fi}^{(eff)} = l_{f} - \hat{\bar{F}}_i + 1,\] where \(l_{f}\) is the total length of a feature in terms of number of nucleotides, and \(\hat{\bar{F}}_i\) is the estimated average fragment length in sample \(i\). We can use this to define \[ TPM_{fi} = \frac{Y_{fi}}{l_{fi}^{(eff)}} \left( \frac{1}{\sum_f \frac{Y_{fi}}{l_{fi}^{(eff)}}} \right) 10^6.\] Note that the first part of the right-hand-side (RHS), \(\frac{Y_{fi}}{l_{fi}^{(eff)}}\) is the expression counts normalized for the length of the feature. This measure, however, is still affected by the sequencing depth, which is then alleviated by dividing by the sum of the length-normalized counts across all features, i.e., \(\sum_f \frac{Y_{fi}}{l_{fi}^{(eff)}}\). TPMs hence normalize for the feature length as well as sequencing depth.
The final countdown
Once abundances have been quantified, the (estimated) counts are typically stored in a count matrix, with genes spanning the rows and samples spanning the columns. This count matrix forms the basis of most downstream analyses to interpret RNA-seq data, and it will be the main object we will be working with in the following lectures.
A preprocessing tutorial
The course GitHub repository contains code to download and quantify a sample from an RNA-seq dataset we will analyze later. Take a look at the code here, and try to run the code, which will require you to install several bioinformatics software tools, as mentioned in the file. If successful, you could try adapting the script in order to download and quantify all samples from that dataset.
References
LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIHNlcXVlbmNpbmc6IFNlcXVlbmNpbmcgdGVjaG5vbG9neSBhbmQgcHJlcHJvY2Vzc2luZyBvZiBzZXF1ZW5jaW5nIGRhdGEiCmF1dGhvcjogIktvZW4gVmFuIGRlbiBCZXJnZSIKZGF0ZTogIkxhc3QgY29tcGlsZWQgb24gYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGxhdGV4X2VuZ2luZTogeGVsYXRleAotLS0KCmBgYHtyIGZ1bmN0aW9ucywgaW5jbHVkZT1GQUxTRX0KIyBBIGZ1bmN0aW9uIGZvciBjYXB0aW9uaW5nIGFuZCByZWZlcmVuY2luZyBpbWFnZXMKZmlnIDwtIGxvY2FsKHsKICAgIGkgPC0gMAogICAgcmVmIDwtIGxpc3QoKQogICAgbGlzdCgKICAgICAgICBjYXA9ZnVuY3Rpb24ocmVmTmFtZSwgdGV4dCkgewogICAgICAgICAgICBpIDw8LSBpICsgMQogICAgICAgICAgICByZWZbW3JlZk5hbWVdXSA8PC0gaQogICAgICAgICAgICBwYXN0ZSgiRmlndXJlICIsIGksICI6ICIsIHRleHQsIHNlcD0iIikKICAgICAgICB9LAogICAgICAgIHJlZj1mdW5jdGlvbihyZWZOYW1lKSB7CiAgICAgICAgICAgIHJlZltbcmVmTmFtZV1dCiAgICAgICAgfSkKfSkKYGBgIAoKYGBge3IsIGVjaG89RkFMU0UsIGV2YWw9VFJVRX0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KGtuaXRyKQogIGxpYnJhcnkocm1hcmtkb3duKQogIGxpYnJhcnkoZ2dwbG90MikKfSkKYGBgCgojIFRoZSBzdHVkeSBvZiBnZW5lIGV4cHJlc3Npb24KCiAtIFRoZSBmaXJzdCBwYXJ0IG9mIHRoaXMgY291cnNlIGZvY3Vzc2VkIG9uIHByb3Rlb21pY3MsIHN0dWR5aW5nIHRoZSBjb25jZW50cmF0aW9uIG9mIHByb3RlaW5zIGluIGJpb2xvZ2ljYWwgc2FtcGxlcy4gV2UgaGF2ZSBzZWVuIHRoYXQgaWRlbnRpZmljYXRpb24gb2YgcHJvdGVpbnMgYW5kIG1lYXN1cmluZyB0aGVpciByZXNwZWN0aXZlIGNvbmNlbnRyYXRpb25zIGFyZSBleHRyZW1lbHkgY2hhbGxlbmdpbmcsIGxlYWRpbmcgdG8gbWFueSB0ZWNobm9sb2dpY2FsIGFuZCBzdGF0aXN0aWNhbCBjaGFsbGVuZ2VzIGluIG9yZGVyIHRvIGludGVycHJldCB0aGVzZSBkYXRhLgogLSBJbiB0aGUgc2Vjb25kIHBhcnQgb2YgdGhlIGNvdXJzZSwgd2Ugd2lsbCBmb2N1cyBvbiBtZWFzdXJpbmcgZ2VuZSBleHByZXNzaW9uLCBpLmUuLCBtZWFzdXJpbmcgdGhlIGNvbmNlbnRyYXRpb24gb2YgbVJOQSBtb2xlY3VsZXMsIHRoYXQgbWF5IGV2ZW50dWFsbHkgYmUgdHJhbnNsYXRlZCBpbnRvIHByb3RlaW5zLCBidXQgbWF5IGFsc28gaGF2ZSBmdW5jdGlvbnMgb24gdGhlaXIgb3duLgoKIyBTZXF1ZW5jaW5nIHRlY2hub2xvZ3kKCiAtIE1lYXN1cmluZyBtUk5BIG1vbGVjdWxlcyB0eXBpY2FsbHkgaGFwcGVucyB0aHJvdWdoIHNlcXVlbmNpbmcuCiAtIFRoZSB0ZWNobm9sb2d5IGNvbnRpbnVlcyB0byBldm9sdmUgYXQgYW4gaW5jcmVkaWJsZSBzcGVlZC4gVGhlIGRhdGEgb3V0cHV0IG9mIHNvLWNhbGxlZCBgbmV4dCBnZW5lcmF0aW9uJyBzZXF1ZW5jaW5nIG1hY2hpbmVzIGhhcyBtb3JlIHRoYW4gZG91YmxlZCBlYWNoIHllYXIhIFNpbXVsdGFuZW91c2x5LCB0aGUgY29zdCBvZiBzZXF1ZW5jaW5nIChpbiB0ZXJtcyBvZiAkIHBlciBHaWdhYmFzZSkgaXMgZHJvcHBpbmcuIEVhY2ggeWVhciwgd2UncmUgYWJsZSB0byBzZXF1ZW5jZSBtb3JlIGZvciBsZXNzIG1vbmV5LCBwcm92aWRpbmcgbW9yZSBpbmZvcm1hdGlvbiwgYXMgd2VsbCBhcyBhbHNvIGNvbXB1dGF0aW9uYWwgYW5kIHN0YXRpc3RpY2FsIGNoYWxsZW5nZXMuCiAtIFRoaXMgdHJlbWVuZG91cyB0ZWNobm9sb2dpY2FsIHJldm9sdXRpb24gaGFzIHJldm9sdXRpb25pemVkIGJpb2xvZ3ksIGFuZCBnZW5vbWljIHNlcXVlbmNpbmcgaXMgbm93IGEgY29yZSBjb21wb25lbnQgb2YgdGhlIG1vZGVybi1kYXkgYmlvbG9naXN0J3MgdG9vbGtpdC4KIC0gVGhlIGxhcmdlIG1ham9yaXR5IG9mIHNlcXVlbmNpbmcgZGF0YSBpcyBnZW5lcmF0ZWQgdXNpbmcgc2VxdWVuY2luZy1ieS1zeW50aGVzaXMgdXNpbmcgbWFjaGluZXMgcHJvZHVjZWQgYnkgdGhlIGNvbXBhbnkgSWxsdW1pbmEuIFdoaWxlIG5ldyBwbGF5ZXJzIHN1Y2ggYXMgUGFjaWZpYyBCaW9zY2llbmNlcyBhbmQgT3hmb3JkIE5hbm9wb3JlIGhhdmUgZW50ZXJlZCB0aGUgc2NlbmUsIHRoZXNlIGFyZSB0eXBpY2FsbHkgbW9zdCB1c2VmdWwgZm9yIChidXQgbm90IGxpbWl0ZWQgdG8pIEROQSBzZXF1ZW5jaW5nIHJhdGhlciB0aGFuIGdlbmUgZXhwcmVzc2lvbiBzdHVkaWVzLCBvd2luZyB0byB0aGVpciBjYXBhYmlsaXR5IG9mIHNlcXVlbmNpbmcgbG9uZyBtb2xlY3VsZXMuCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmNhcD1wYXN0ZSgiRmlndXJlOiBUaGUgZGF0YSBvdXRwdXQgcmV2b2x1dGlvbiBvZiBzZXF1ZW5jaW5nIG1hY2hpbmVzLiBJbWFnZSBmcm9tIElsbHVtaW5hIGRvY3VtZW50YXRpb24uIil9CiMgQWxsIGRlZmF1bHRzCmluY2x1ZGVfZ3JhcGhpY3MoIi4vaW1hZ2VzX3NlcXVlbmNpbmcvc2VxVGVjaG5vbG9neV90aHJvdWdocHV0LnBuZyIpCmBgYAoKIyMgVGhlIHNlcXVlbmNpbmcgd29ya2Zsb3cKCkxpYnJhcnkgcHJlcGFyYXRpb24gc3RlcHM6CgoxLiBGaXJzdCwgdGhlIGJpb2xvZ2ljYWwgKipzYW1wbGVzIG9mIGludGVyZXN0IGFyZSBjb2xsZWN0ZWQqKi4gT3dpbmcgdG8gdGhlIG1hdHVyaXR5IG9mIGRpZmZlcmVudCBwcm90b2NvbHMgZm9yIHNlcXVlbmNpbmcsIHNldmVyYWwgdHlwZXMgb2YgYmlvbG9naWNhbCBpbnB1dCBzYW1wbGVzIGFyZSBhbWVuYWJsZSB0byBzZXF1ZW5jaW5nLCBzdWNoIGFzIGZyb3plbiB0aXNzdWVzIG9yIEZGUEUtcHJlc2VydmVkIHNhbXBsZXMuCjIuIFRoZSAqKihtKVJOQSBtb2xlY3VsZXMgZnJvbSBvdXIgc2FtcGxlIGFyZSBjYXB0dXJlZCoqLiBUaGlzIHR5cGljYWxseSBpbnZvbHZlcyBjZWxsIGx5c2lzIGluIG9yZGVyIHRvIHJlbGVhc2UgdGhlIChtKVJOQSBtb2xlY3VsZXMgZnJvbSB3aXRoaW4gdGhlIGNlbGxzLiBUaGUgbVJOQSBtb2xlY3VsZXMgYXJlIG1vc3Qgb2Z0ZW4gY2FwdHVyZWQgdXNpbmcgKGkpIHBvbHlBLWNhcHR1cmUgdG8gc2VsZWN0IGZvciBwb2x5YWRlbnlsYXRlZCBSTkEsIG9yIChpaSkgcmlib3NvbWFsIGRlcGxldGlvbiwgd2hlcmUgcmlib3NvbWFsIGFuZCB0cmFuc2ZlciBSTkFzIGFyZSBkZXBsZXRlZCwgYW5kIHNvIGFsc28gbm9uLXBvbHlBLW1STkEgbW9sZWN1bGVzIG1heSBiZSBjYXB0dXJlZCwgc3VjaCBhcyBtaWNybyBSTkFzLiBJbiB0aGUgY2FzZSBvZiBgdGFyZ2V0ZWQgc2VxdWVuY2luZycsIHdoZXJlIHJlbGV2YW50IG1vbGVjdWxlcyBhcmUgb2YgbWFpbiBpbnRlcmVzdCAoZS5nLiwgYSBnZW5lIHBhbmVsKSwgdGhlc2UgdGFyZ2V0cyBjYW4gYmUgc3BlY2lmaWNhbGx5IHRhcmdldGVkIGluIHRoaXMgc3RlcC4KMy4gKipGcmFnbWVudGF0aW9uKiogb2YgY2FwdHVyZWQgbW9sZWN1bGVzLiBUaGUgY2FwdHVyZWQgbW9sZWN1bGVzIGFyZSBmcmFnbWVudGVkLCBlaXRoZXIgY2hlbWljYWxseSBvciBtZWNoYW5pY2FsbHkuIFRoZSBhcHByb3ByaWF0ZSBzaXplIG9mIGZyYWdtZW50cyBkZXBlbmRzIG9uIHRoZSBzZXF1ZW5jaW5nIG1hY2hpbmVzLCBidXQgaXMgb2Z0ZW4gaW4gdGhlIHJhbmdlIG9mIDMwMCAtIDUwMGJwLgo0LiAqKlJldmVyc2UgdHJhbnNjcmlwdGlvbioqLiBDdXJyZW50IGRvbWluYW50IHNlcXVlbmNpbmcgbWFjaGluZXMgb25seSBzZXF1ZW5jZSBkb3VibGUtc3RyYW5kZWQgRE5BIG1vbGVjdWxlcy4gVGhlcmVmb3JlLCBpbiBvcmRlciB0byBtZWFzdXJlIHNpbmdsZS1zdHJhbmRlZCBtUk5BLCB3ZSBtdXN0IGZpcnN0IHJldmVyc2UgdHJhbnNjcmliZSB0aGVzZSBtb2xlY3VsZXMgdG8gYSBkb3VibGUtc3RyYW5kZWQgY29tcGxlbWVudGFyeSAoY0ROQSkgbW9sZWN1bGUuCjUuICoqQWRhcHRlciBsaWdhdGlvbioqLiBBZGFwdGVycyBhcmUgb2xpZ29udWNsZW90aWRlcyAoc2hvcnQgc2VxdWVuY2VzIG9mIG51Y2xlb3RpZGVzKSB0aGF0IGFyZSBwbGF0Zm9ybS1zcGVjaWZpYyBzZXF1ZW5jZXMgZm9yIGZyYWdtZW50IHJlY29nbml0aW9uIGJ5IHRoZSBzZXF1ZW5jaW5nIG1hY2hpbmVzLiBUaGVzZSBhcmUgYWRkZWQgZWl0aGVyIHRvIHRoZSAzJyBvciA1JyBlbmQgb2YgdGhlIGNETkEgbW9sZWN1bGVzIG9yIHVzZWQgYXMgcHJpbWVycyBpbiB0aGUgcmV2ZXJzZSB0cmFuc2NyaXB0aW9uIHJlYWN0aW9uLiBUaGUgZmluYWwgY0ROQSBsaWJyYXJ5IGNvbnNpc3RzIG9mIGNETkEgaW5zZXJ0cyBmbGFua2VkIGJ5IGFuIGFkYXB0ZXIgc2VxdWVuY2Ugb24gZWFjaCBlbmQuIAo2LiAqKlBDUiBhbXBsaWZpY2F0aW9uKiouIFRvIGluY3JlYXNlIGNvbmNlbnRyYXRpb24sIHNldmVyYWwgUENSIHJlYWN0aW9uIGN5Y2xlcyBhcmUgcGVyZm9ybWVkLgo3LiBMb2FkaW5nIHRoZSBhbXBsaWZpZWQgY0ROQSBsaWJyYXJ5IG9uIHRoZSAqKnNlcXVlbmNpbmcqKiBtYWNoaW5lLiBGaW5kIG91dCBob3cgc2VxdWVuY2luZy1ieS1zeW50aGVzaXMgd29ya3MgdGhyb3VnaCBbdGhpcyB2aWRlb10oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1mQ2Q2QjVIUmFaOCkuIE5vdGUgdGhhdCB0aGUgdmlkZW8gc2hvd3MgcGFpcmVkLWVuZCBzZXF1ZW5jaW5nLCB3aGVyZSBhIG51bWJlciBvZiBiYXNlcGFpcnMgYXJlIHNlcXVlbmNlZCBhdCBlYWNoIGVuZCBvZiB0aGUgZnJhZ21lbnQuIEFsbCBwcmV2aW91cyBzdGVwcyB0b2dldGhlciBhcmUgZGVzY3JpYmVkIGFzIGBzYW1wbGUgcHJlcCcgaW4gdGhhdCB2aWRlby4KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IFRoZSBzZXF1ZW5jaW5nIHdvcmtmbG93LiBJbWFnZSBhZGFwdGVkIGZyb20gVmFuIGRlbiBCZXJnZSBldCBhbC4gKDIwMTkpLiIpfQppbmNsdWRlX2dyYXBoaWNzKCIuL2ltYWdlc19zZXF1ZW5jaW5nL3NlcVdvcmtmbG93MV9jbGVhbi5wbmciKQpgYGAKCk5vdGUgdGhhdCBzZXZlcmFsIHZhcmlhbnRzIG9mIGxpYnJhcnkgcHJlcGFyYXRpb24gcHJvdG9jb2xzIGFyZSBhdmFpbGFibGUuIFRoZSBtb3N0IGltcG9ydGFudCBvbmVzIGFyZToKCiAtIFNpbmdsZS1lbmQgdnMgcGFpcmVkLWVuZCBzZXF1ZW5jaW5nOiBJbiBzaW5nbGUtZW5kIHNlcXVlbmNpbmcsIGEgc2luZ2xlIGVuZCAoMycgb3IgNScpIG9mIHRoZSBjRE5BIGZyYWdtZW50IGlzIHNlcXVlbmNlZC4gSW4gcGFpcmVkLWVuZCBzZXF1ZW5jaW5nLCBib3RoIGVuZHMgYXJlIHNlcXVlbmNlZCwgYW5kIGRlcGVuZGluZyBvbiB0aGUgc2l6ZSBvZiB0aGUgZnJhZ21lbnQsIHRoZSByZWFkcyBtYXkgb3IgbWF5IG5vdCBvdmVybGFwLgogLSBTdHJhbmQtc3BlY2lmaWMgcHJvdG9jb2xzOiBTb21lIGxpYnJhcnkgcHJlcGFyYXRpb24gcHJvdG9jb2xzIGFsbG93IG1lYXN1cmluZyBzdHJhbmQgc3BlY2lmaWNpdHksIHdoZXJlIHRoZSBzdHJhbmQgaW5mb3JtYXRpb24gKGkuZS4sIHNlbnNlL2FudGlzZW5zZSkgb2YgZWFjaCByZWFkIGNhbiBiZSBwcmVzZXJ2ZWQuCgojIyBUaGUgc2VxdWVuY2luZyBvdXRwdXQgZmlsZXMKCi0gVGhlIHR5cGljYWwgb3V0cHV0IG9mIGEgc2VxdWVuY2luZyBtYWNoaW5lIHdlIHdpbGwgYmUgd29ya2luZyB3aXRoIGFyZSBGQVNUQSBvciBGQVNUUSBmaWxlcyBmb3IgZWFjaCBzYW1wbGUuIEVhY2ggb2YgdGhlc2UgZmlsZXMgYXJlIHNldmVyYWwgZ2lnYmFzZXMgbGFyZ2UgYW5kIGNvbnRhaW4gbWlsbGlvbnMgb2Ygc2VxdWVuY2VzLCB3aGljaCB3ZSB3aWxsIGNhbGwgKipyZWFkcyoqLiBGb3IgcGFpcmVkLWVuZCBzZXF1ZW5jaW5nLCB0aGVyZSBhcmUgdHdvIGZpbGVzIGZvciBlYWNoIHNhbXBsZSwgb25lIGZvciBlYWNoIGVuZCBvZiB0aGUgc2VxdWVuY2VkIGZyYWdtZW50cy4KIC0gVGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBhIEZBU1RBIGZpbGUgYW5kIGEgRkFTVFEgZmlsZSwgaXMgdGhhdCB3aGlsZSBGQVNUQSBmaWxlcyBvbmx5IHN0b3JlIHRoZSByZXN1bHRzIG9mIGJhc2UgY2FsbHMgKHNlcXVlbmNlcyksIEZBU1RRIGZpbGVzIGFsc28gc3RvcmUgdGhlIHF1YWxpdHkgc2NvcmUgb2YgZWFjaCBiYXNlIGNhbGwgKGkuZS4sIGVhY2ggY2FsbGVkIG51Y2xlb3RpZGUpLCB3aGljaCBjYW4gYmUgdXNlZnVsIGluIGRvd25zdHJlYW0gYW5hbHlzZXMgc3VjaCBhcyBtYXBwaW5nIG9yIHZhcmlhbnQgY2FsbGluZy4KIC0gQSBGQVNUUSBmaWxlIGNvbnRhaW5zIGZvdXIgbGluZXMgZm9yIGVhY2ggc2VxdWVuY2VkIHJlYWQ6CiAgICAxLiBTZXF1ZW5jZSBpZGVudGlmaWVyIGxpbmUsIHN0YXJ0aW5nIHdpdGggQC4KICAgIDIuIFRoZSBzZXF1ZW5jZS4KICAgIDMuIEFub3RoZXIgc2VxdWVuY2UgaWRlbnRpZmllciBsaW5lLCBub3cgc3RhcnRpbmcgd2l0aCArLgogICAgNC4gUXVhbGl0eSBzY29yZXMuCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmNhcD1wYXN0ZSgiRmlndXJlOiBPbmUgcmVhZCBpbiBhIEZBU1RRIGZpbGUuIFNsaWRlIGNvdXJ0ZXN5IGJ5IENoYXJsb3R0ZSBTb25lc29uLiIpfQppbmNsdWRlX2dyYXBoaWNzKCIuL2ltYWdlc19zZXF1ZW5jaW5nL2Zhc3RxTGluZS5wbmciKQpgYGAKCkFzIHlvdSdsbCBoYXZlIG5vdGljZWQsIHRoZSBiYXNlIGNhbGwgcXVhbGl0eSBzY29yZXMgYXJlIGVuY29kZWQgYXMgQVNDSUkgY2hhcmFjdGVycyBmb3IgZWZmaWNpZW50IHN0b3JhZ2UuIFRoZXNlIEFTQ0lJIGNoYXJhY3RlcnMgY2FuIGJlIGNvbnZlcnRlZCBpbnRvIGludGVnZXJzIGNhbGxlZCBQaHJlZCBzY29yZXMsIHdoaWNoIGFyZSBsb2dhcml0aG1pY2FsbHkgcmVsYXRlZCB0byB0aGUgcHJvYmFiaWxpdHkgb2YgYW4gZXJyb25lb3VzIGJhc2UgY2FsbC4KCiAtLS0KIApNYW55IHB1Ymxpc2hlZCBwYXBlcnMgdXBsb2FkIHRoZWlyIHJhdyBGQVNUUS1maWxlcyBvbiB0aGUgR2VuZSBFeHByZXNzaW9uIE9tbmlidXMgKEdFTykuIApJZiB5b3UnbGwgYmUgd29ya2luZyBpbiB0cmFuc2NyaXB0b21pY3MsIHlvdSB3aWxsIG1vc3QgbGlrZWx5IGhhdmUgdG8gZG93bmxvYWQgZmlsZXMgZnJvbSB0aGVyZS4gWW91IGNhbiBnZXQgdGhlIGxpbmtzIG1hbnVhbGx5LCBlLmcuLCBieSBmb2xsb3dpbmcgW3RoaXMgdHV0b3JpYWxdKGh0dHBzOi8vd3d3LmltbS5veC5hYy51ay9maWxlcy9jY2IvZG93bmxvYWRpbmdfZmFzdHFfZ2VvKSwgdGhyb3VnaCBgUmAgdXNpbmcgY3VzdG9tIHBhY2thZ2VzLCBlLmcuLCBbR0VPZmFzdHFdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9HRU9mYXN0cS5odG1sKSwgb3IgeW91IGNhbiB1c2UgYSBjb21tYW5kLWxpbmUgcHJvZ3JhbSBsaWtlIFtraW5nZmlzaGVyXShodHRwczovL2dpdGh1Yi5jb20vd3dvb2Qva2luZ2Zpc2hlci1kb3dubG9hZCkgKHJlY29tbWVuZGVkKS4KCiMgUHJlcHJvY2Vzc2luZyBvZiByYXcgc2VxdWVuY2luZyBkYXRhCgpBZnRlciBzZXF1ZW5jaW5nLCB3ZSB0eXBpY2FsbHkgZG8gYSBxdWFsaXR5IGNvbnRyb2wgKFFDKSBjaGVjayB0byB2ZXJpZnkgdGhlIHF1YWxpdHkgb2YgdGhlIHNhbXBsZXMuIER1cmluZyBRQyBjaGVjaywgYWJlcnJhbnQgc2FtcGxlcyBkdWUgdG8gZS5nLiBkZWdyYWRlZCBtUk5BIGNhbiBiZSBkZXRlY3RlZC4KClRoZSBzZXF1ZW5jaW5nIHJlYWRzIG9uIHRoZWlyIG93biBjb250YWluIGEgbG90IG9mIGluZm9ybWF0aW9uLCBidXQgYXJlIG1vc3QgdXNlZnVsIGlmIHdlIHdvdWxkIGJlIGFibGUgdG8gYXNzaWduIHNlcXVlbmNpbmcgcmVhZHMgdG8gZ2Vub21pYyBmZWF0dXJlcyAoZ2VuZXMsIGV4b25zLCB0cmFuc2NyaXB0cywgZXRjLiksIGkuZS4sIGZvciBlYWNoIHNlcXVlbmNpbmcgcmVhZCB3ZSB3aWxsIHRyeSB0byBkZXJpdmUgdGhlIChzZXQgb2YpIGZlYXR1cmUocykgdGhhdCBjb3VsZCBoYXZlIHBsYXVzaWJseSBwcm9kdWNlZCB0aGUgZnJhZ21lbnQgdGhyb3VnaCB0aGUgcHJvY2VzcyBvZiBnZW5lIGV4cHJlc3Npb24uIFRoaXMgcHJvY2VzcyBpcyBjYWxsZWQgKiptYXBwaW5nKiouIE1vc3Qgb2Z0ZW4gd2UgbWFwIHJlYWRzIHRvIGdlbmVzLiAKCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IEFuIHVwZGF0ZWQgc2VxdWVuY2luZyB3b3JrZmxvdywgaW5jbHVkaW5nIHNlcXVlbmNpbmcgYW5kIG1hcHBpbmcuIEltYWdlIGFkYXB0ZWQgZnJvbSBWYW4gZGVuIEJlcmdlIGV0IGFsLiAoMjAxOSkuIil9CmluY2x1ZGVfZ3JhcGhpY3MoIi4vaW1hZ2VzX3NlcXVlbmNpbmcvc2VxV29ya2Zsb3cyLnBuZyIpCmBgYAoKIyMgUXVhbGl0eSBjb250cm9sCgpEdXJpbmcgcXVhbGl0eSBjb250cm9sLCBkaWFnbm9zdGljIHBsb3RzIGFyZSBjcmVhdGVkIGZvciBlYWNoIHNhbXBsZSBpbiBvcmRlciB0byBkZXRlcm1pbmUgaXRzIHF1YWxpdHkuIFRoZSBtb3N0IHBvcHVsYXIgUUMgdG9vbCBmb3IgYnVsayBSTkEtc2VxIGRhdGEgaXMgW0Zhc3RRQ10oaHR0cHM6Ly93d3cuYmlvaW5mb3JtYXRpY3MuYmFicmFoYW0uYWMudWsvcHJvamVjdHMvZmFzdHFjLykuIElmIG1hbnkgc2FtcGxlcyBhcmUgc2VxdWVuY2VkLCB0aGVuIFtNdWx0aVFDXShodHRwczovL211bHRpcWMuaW5mby8pIGNhbiBiZSB1c2VkIHRvIGFnZ3JlZ2F0ZSB0aGUgUUMgY2hlY2tzIGFjcm9zcyBzYW1wbGVzIGluIGEgY29udmVuaWVudGx5IG9yZ2FuaXplZCBvdmVydmlldy4KClRoZSBGYXN0UUMgd2Vic2l0ZSBwcm92aWRlcyBpbnRlcmVzdGluZyBleGFtcGxlIHJlcG9ydHMgZm9yIHVzIHRvIGxvb2sgYXQgYW5kIGNvbXBhcmUgYWdhaW5zdC4gSGVyZSBhcmUgZXhhbXBsZSByZXBvcnRzIG9mIFtoaWdoLXF1YWxpdHkgSWxsdW1pbmEgZGF0YV0oaHR0cHM6Ly93d3cuYmlvaW5mb3JtYXRpY3MuYmFicmFoYW0uYWMudWsvcHJvamVjdHMvZmFzdHFjL2dvb2Rfc2VxdWVuY2Vfc2hvcnRfZmFzdHFjLmh0bWwpIGFuZCBbbG93LXF1YWxpdHkgSWxsdW1pbmEgZGF0YV0oaHR0cHM6Ly93d3cuYmlvaW5mb3JtYXRpY3MuYmFicmFoYW0uYWMudWsvcHJvamVjdHMvZmFzdHFjL2JhZF9zZXF1ZW5jZV9mYXN0cWMuaHRtbCkuCgojIyBNYXBwaW5nCgogLSBNYXBwaW5nIGlzIGEgY3JpdGljYWwgc3RlcCBpbiB0aGUgaW50ZXJwcmV0YXRpb24gb2YgUk5BLXNlcSBkYXRhLCB3aGVyZSB3ZSBhcmUgYXR0cmlidXRpbmcgcmVhZHMgdG8gZ2Vub21pYyBmZWF0dXJlcy4gCiAtIEFsbG93cyB1cyB0byBtZWFzdXJlIGhvdyBzdHJvbmcgYSBmZWF0dXJlIHN1Y2ggYXMgYSBnZW5lIGlzIGV4cHJlc3NlZDogdGhlIG51bWJlciBvZiByZWFkcyBtYXBwaW5nIHRvIGEgZ2VuZSBzZXJ2ZSBhcyBhIHByb3h5IGZvciBob3cgaGlnaCB0aGF0IGdlbmUgaGFzIGJlZW4gZXhwcmVzc2VkIGluIHRoZSBzYW1wbGUuIAogLSBXaGlsZSB0aGlzIG9wZW5zIHRoZSBkb29yIHRvIG1hbnkgb3Bwb3J0dW5pdGllcywgbWFwcGluZyBpcyBoYXJkLgogLSBXZSBhcmUgKip0eXBpY2FsbHkgdW5hYmxlIHRvIGFzc2lnbiBlYWNoIGluZGl2aWR1YWwgcmVhZCB1bmlxdWVseSoqIHRvIG9uZSBzcGVjaWZpYyBnZW5lOyBzb21lIHJlYWRzIGNhbm5vdCBiZSB1bmFtYmlndW91c2x5IG1hcHBlZCBhbmQgYXJlIGNvbXBhdGlibGUgd2l0aCBtdWx0aXBsZSBnZW5lcy4gVGhlc2UgcmVhZHMgYXJlIHNhaWQgdG8gYmUgJ211bHRpLW1hcHBpbmcnLgogCkZpbmFsbHksIGEgbm90ZSBvbiB0ZXJtaW5vbG9neS4gSW4gdGhpcyB0ZXh0IHdlIHdpbGwgdXNlIHRoZSB3b3JkcyAncmVhZCcgb3IgJ2ZyYWdtZW50JyAocmVmZXJyaW5nIHRvIHRoZSBmcmFnbWVudGVkIG1STkEgbW9sZWN1bGUgYmVpbmcgc2VxdWVuY2VkKSB0byBkZXNpZ25hdGUgYSBkYXR1bSwgbm90ZSB0aGF0IHRoaXMgY291bGQgYmUgZWl0aGVyIGEgc2luZ2xlIHJlYWQgKGluIHNpbmdsZS1lbmQgc2VxdWVuY2luZykgb3IgYSByZWFkIHBhaXIgKGluIHBhaXJlZC1lbmQgc2VxdWVuY2luZykuIFRoZSBsaXRlcmF0dXJlIG1heSBhbHNvIHVzZSB0aGVzZSB3b3JkcyBpbnRlcmNoYW5nZWFibHksIGFsdGhvdWdoICdmcmFnbWVudCcgc2VlbXMgYmV0dGVyIGF0IGF2b2lkaW5nIGFtYmlndWl0eSBiZXR3ZWVuIHNpbmdsZS1lbmQgcmVhZHMgYW5kIHBhaXJlZC1lbmQgcmVhZCBwYWlycy4KCiMjIyBSZWZlcmVuY2UgZmlsZXMKCiAtIFRoZSBhbGlnbm1lbnQgbW9zdCBvZnRlbiByZWxpZXMgb24gYSAqKnJlZmVyZW5jZSBnZW5vbWUqKiBvZiB0aGUgc3BlY2llcywgd2hpY2ggY2FuIGJlIGNvbnNpZGVyZWQgYSAncmVwcmVzZW50YXRpdmUgZXhhbXBsZScgb2YgdGhlIGdlbm9tZSBzZXF1ZW5jZSBvZiB0aGF0IHNwZWNpZXMuIFJlZmVyZW5jZSBnZW5vbWVzIGFyZSBjb250aXVvdXNseSB1cGRhdGVkIGFuZCByZWxlYXNlZCBwZXJpb2RpY2FsbHkuCiAtIFJlZmVyZW5jZSBnZW5vbWVzIGNhbiBiZSBmcmVlbHkgZG93bmxvYWRlZCBmcm9tIHNldmVyYWwgcHJvdmlkZXJzLCBmb3IgZXhhbXBsZSBbRW5zZW1ibF0oaHR0cDovL3d3dy5lbnNlbWJsLm9yZy9pbmZvL2RhdGEvZnRwL2luZGV4Lmh0bWwpIG9yIFtHZW5jb2RlXShodHRwczovL3d3dy5nZW5jb2RlZ2VuZXMub3JnL2h1bWFuLykuCiAtIEFsb25nIHdpdGggYSByZWZlcmVuY2UgZ2Vub21lLCBhbiBhbm5vdGF0aW9uIEdGRiBvciBHVEYgZmlsZSBkZWZpbmVzIHRoZSBjb29yZGluYXRlcyBvZiBzcGVjaWZpYyBnZW5vbWljIGZlYXR1cmVzLgogLSBXaGlsZSBoZXJlIHdlIHdpbGwgZm9jdXMgb24gcmVmZXJlbmNlLWJhc2VkIGFsaWdubWVudCwgaS5lLiwgYWxpZ25tZW50IHdoZXJlIGEgcmVmZXJlbmNlIGdlbm9tZSBvciB0cmFuc2NyaXB0b21lIGlzIGF2YWlsYWJsZSwgbm90ZSB0aGF0IGEgKmRlIG5vdm8qIGNvbnN0cnVjdGlvbiBvZiBhIHJlZmVyZW5jZSB0cmFuc2NyaXB0b21lIGlzIGFsc28gcG9zc2libGUsIHdoZXJlIHRoZSByZWZlcmVuY2UgbWF5IGJlIGNvbnN0cnVjdGVkIGZyb20gdGhlIG9ic2VydmVkIHNlcXVlbmNpbmcgcmVhZHMuCiAKYGBge3IsIGVjaG89RkFMU0UsIGZpZy5jYXA9cGFzdGUoIkZpZ3VyZTogQSByZWZlcmVuY2Ugc2VxdWVuY2Ugb2YgaHVtYW4gY2hyMS4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9pbWFnZXNfc2VxdWVuY2luZy9yZWZlcmVuY2VHZW5vbWUucG5nIikKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmNhcD1wYXN0ZSgiRmlndXJlOiBBbiBleGFtcGxlIEdURiBmaWxlLiIpfQppbmNsdWRlX2dyYXBoaWNzKCIuL2ltYWdlc19zZXF1ZW5jaW5nL2d0ZkZpbGUucG5nIikKYGBgCgogLSBNb3JlIHJlY2VudGx5LCBtYXBwaW5nIG9mIFJOQS1zZXEgZGF0YSBvY2N1cnMgbW9yZSBvZnRlbiBhZ2FpbnN0IGEgKipyZWZlcmVuY2UgdHJhbnNjcmlwdG9tZSoqLCB3aGljaCBpcyBhIHJlZmVyZW5jZSBmaWxlIGNvbnRhaW5pbmcgdGhlIHNlcXVlbmNlcyBhbGwga25vd24gaXNvZm9ybXMgb2YgYSBwYXJ0aWN1bGFyIHNwZWNpZXMsIGUuZy4sIHVzaW5nIFtrYWxsaXN0b10oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9uYnQuMzUxOSkgb3IgW1NhbG1vbl0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9ubWV0aC40MTk3KS4KIC0gVGhlIHNldCBvZiBzcGxpY2VkIHRyYW5zY3JpcHRzIGlzIG11Y2ggc21hbGxlciB0aGFuIHRoZSBlbnRpcmUgZ2Vub21lLCBhbmQgdGhlcmVmb3JlIG1hcHBpbmcgYWdhaW5zdCBhIHJlZmVyZW5jZSB0cmFuc2NyaXB0b21lIGlzIHR5cGljYWxseSAqKmZhc3QgYW5kIG1lbW9yeSBlZmZpY2llbnQqKi4KIC0gSG93ZXZlciwgW2l0IGhhcyBiZWVuIG5vdGVkXShodHRwczovL3d3dy5iaW9yeGl2Lm9yZy9jb250ZW50LzEwLjExMDEvMjAyMS4wNS4wNS40NDI3NTV2MSkgdGhhdCBtYXBwaW5nIGFnYWluc3QgYSByZWZlcmVuY2UgdHJhbnNjcmlwdG9tZSBtYXkgYWxzbyBpbnRyb2R1Y2Ugc3B1cmlvdXMgZXhwcmVzc2lvbiBmb3IgZ2VuZXMgdGhhdCBhcmUgbm90IGV4cHJlc3NlZC4gVGhlc2Ugb2JzZXJ2YXRpb25zIGNhbiBiZSBleHBsYWluZWQgYnkgKippbnRyb25pYyByZWFkcyoqIHRoYXQgc2hhcmUgc29tZSBzZXF1ZW5jZSBzaW1pbGFyaXR5IHdpdGggdHJhbnNjcmlwdHMsIGFuZCBjb3VsZCBtYXAgdG8gc3BsaWNlZCB0cmFuc2NyaXB0IHNlcXVlbmNlcy4gUmVjZW50IG1ldGhvZHMsIHN1Y2ggYXMgW2FsZXZpbi1mcnldKGh0dHBzOi8vd3d3LmJpb3J4aXYub3JnL2NvbnRlbnQvMTAuMTEwMS8yMDIxLjA2LjI5LjQ1MDM3N3YxKSwgYXZvaWQgdGhpcyBieSBleHBhbmRpbmcgdGhlIHJlZmVyZW5jZSB0cmFuc2NyaXB0b21lIHRvIGFsc28gaW5jbHVkZSBpbnRyb25pYyBzZXF1ZW5jZXMuCgojIyMgQWxpZ25tZW50LWJhc2VkIHdvcmtmbG93cwoKIC0gVHJhZGl0aW9uYWxseSwgYWxpZ25tZW50LWJhc2VkIHdvcmtmbG93cyBoYXZlIGJlZW4gdXNlZCB0byBtYXAgcmVhZHMsIHdoZXJlIG9uZSB0cmllcyB0byAqKmZpbmQgdGhlIGV4YWN0IGNvb3JkaW5hdGVzIGEgcmVhZCBtYXBzIHRvKiogb24gdGhlIHJlZmVyZW5jZSBnZW5vbWUgb3IgdGhlIHJlZmVyZW5jZSB0cmFuc2NyaXB0b21lLgogLSBOb3RlIHRoYXQgZHVlIHRvIGFsdGVybmF0aXZlIHNwbGljaW5nLCByZWFkcyBkbyBub3QgbmVjZXNzYXJpbHkgbWFwIGNvbnRpZ3VvdXNseSBvbiBhIHJlZmVyZW5jZSBnZW5vbWUsIGFzIGEgcmVhZCBjYW4gb3ZlcmxhcCB3aXRoIGEgc3BsaWNpbmcganVuY3Rpb24sIHdoZXJlIGFuIGludHJvbiBoYXMgYmVlbiBleGNpc2VkLiBXaGVuIG1hcHBpbmcgYWdhaW5zdCBhIHRyYW5zY3JpcHRvbWUsIGhvd2V2ZXIsIHJlYWRzIHNob3VsZCBiZSBtYXBwaW5nIGNvbnRpZ3VvdXNseS4KICAtIEEgbWFpbiBjaGFsbGVuZ2UgaW4gc3BsaWNlZCBhbGlnbm1lbnQgYWdhaW5zdCBhIHJlZmVyZW5jZSBnZW5vbWUgaXMgdGhlIHByb3BlciBhbGlnbm1lbnQgb2YgcmVhZHMgdGhhdCBzcGFuIGEgc3BsaWNlIGp1bmN0aW9uLCBlc3BlY2lhbGx5IHdoZW4gdGhlc2UganVuY3Rpb25zIGFyZSBub3QgYW5ub3RhdGVkIGEgcHJpb3JpLiBJbmRlZWQsIGluIHNwbGljZWQgYWxpZ25tZW50IHJlYWRzIGNhbiBiZSBzcGxpdCBhdCBhbnkgbnVjbGVvdGlkZSwgYW5kIHRoZSBjb3JyZXNwb25kaW5nIHN1YnNlcXVlbmNlcyBjYW4gbWFwIHNldmVyYWwgdGhvdXNhbmRzIG9mIGJhc2VwYWlycyBhcGFydC4gTWVhbndoaWxlLCB0aGUgbWFpbiBjaGFsbGVuZ2UgaW4gdW5zcGxpY2VkIGFsaWdubWVudCB0byBhIHRyYW5zY3JpcHRvbWUgaXMgdGhlIHJlZHVuZGFudCBzZXF1ZW5jZSBhbW9uZyByZWxhdGVkIHRyYW5zY3JpcHRzIGluIHRoZSB0cmFuc2NyaXB0b21lLCB3aGljaCBvZnRlbiBsZWFkcyB0byBhIGhpZ2ggbXVsdGktbWFwcGluZyByYXRlIChpLmUuLCByZWFkcyB0aGF0IGNhbm5vdCBiZSB1bmFtYmlndW91c2x5IGFzc2lnbmVkIHRvIGEgc2luZ2xlIHRyYW5zY3JpcHQpLgogLSBTcGxpY2VkIGFsaWdubWVudCBhZ2FpbnN0IGEgZ2Vub21lIGlzIHRoZXJlZm9yZSBjb21wdXRhdGlvbmFsbHkgYSBtdWNoIGhhcmRlciB0YXNrLiBTaW5jZSB0aGUgdHJhbnNjcmlwdCBzZXF1ZW5jZXMgYXJlIGFscmVhZHkgc3BsaWNlZCB3aGVuIGFsaWduaW5nIHRvIGEgcmVmZXJlbmNlIHRyYW5zY3JpcHRvbWUsIHJlYWRzIHNob3VsZCBhbGlnbiBjb250aWd1b3VzbHksIGFuZCBtYW55IG9mIHRoZSBjb21wdXRhdGlvbmFsbHkgZXhwZW5zaXZlIHN0ZXBzIGFuZCBoZXVyaXN0aWNzIGNhbiBiZSBhdm9pZGVkLCB0aGVyZS4KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IFVuc3BsaWNlZCBhbmQgc3BsaWNlZCBhbGlnbm1lbnQuIEZpZ3VyZSBmcm9tIFZhbiBkZW4gQmVyZ2UgZXQgYWwuICgyMDE5KS4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9pbWFnZXNfc2VxdWVuY2luZy9zcGxpY2VkQWxpZ25tZW50LnBuZyIpCmBgYAoKIyMjIEFsaWdubWVudC1mcmVlIHdvcmtmbG93cwoKIC0gTW9kZXJuIGFwcHJvYWNoZXMgKiphdm9pZCBtYXBwaW5nIGVhY2ggZnJhZ21lbnQgaW5kaXZpZHVhbGx5KiogKGkuZS4sIGRvIG5vdCBhdHRlbXB0IHRvIGZpbmQgdGhlIGV4YWN0IGNvb3JkaW5hdGVzIG9mIGEgcmVhZCdzIG9yaWdpbiksIGFuZCBpbnN0ZWFkIHBvc2l0IGEgcHJvYmFiaWxpc3RpYyBtb2RlbCB3aGVyZSAqKnRyYW5zY3JpcHQgYWJ1bmRhbmNlcyBhcmUgdHlwaWNhbGx5IGRlZmluZWQgdXNpbmcgaXRzIGNvbnN0aXR1ZW50ICRrJC1tZXJzKiouIFRoZXNlIG1ldGhvZHMgYXJlIHNvbWV0aW1lcyByZWZlcnJlZCB0byBhcyAqbGlnaHR3ZWlnaHQqLgogLSBBICRrJC1tZXIgaXMgYSBzaG9ydCBzZXF1ZW5jZSBvZiBudWNsZW90aWRlcyBvZiBsZW5ndGggJGskLiBUaGUgc3BhY2Ugb2YgcG9zc2libGUgJGskLW1lcnMgYW5kIHRoZSBjb3JyZXNwb25kaW5nIHRyYW5zY3JpcHRzIGNhbiBiZSBwcmVjb21wdXRlZCBpbiBhZHZhbmNlIHVzaW5nIHRoZSByZWZlcmVuY2UgdHJhbnNjcmlwdG9tZSwgcHJvdmlkaW5nIGEgY29tcHV0YXRpb25hbCBhZHZhbnRhZ2UgYXMgaXQgb25seSBuZWVkcyB0byBiZSBjb21wdXRlZCBvbmNlLgogLSBGb3IgZWFjaCBmcmFnbWVudCwgdGhlIHRyYW5zY3JpcHRzIGl0cyAkayQtbWVycyBhcmUgY29tcGF0aWJsZSB3aXRoIGlzIHNlYXJjaGVkIGZvciB1c2luZyBhbiBpbmRleGVkIChlZmZpY2llbnRseSBzZWFyY2hhYmxlKSB0cmFuc2NyaXB0b21lLiBUaGUgc2V0IG9mIGNvbXBhdGlibGUgdHJhbnNjcmlwdHMgaXMgY2FsbGVkIHRoZSAnJGskLWNvbXBhdGliaWxpdHkgY2xhc3MnLCAnZXF1aXZhbGVuY2UgY2xhc3MnIG9yICd0cmFuc2NyaXB0IGNvbXBhdGliaWxpdHkgY2xhc3MnIG9mIHRoZSBmcmFnbWVudC4KIApgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmNhcD1wYXN0ZSgiRmlndXJlOiBPdmVydmlldyBvZiBrYWxsaXN0bywgaW1hZ2UgZnJvbSBCcmF5IGV0IGFsLiAoMjAxNikuIil9CmluY2x1ZGVfZ3JhcGhpY3MoIi4vaW1hZ2VzX3NlcXVlbmNpbmcva2FsbGlzdG9fZXF1aXZhbGVuY2VDbGFzc2VzLnBuZyIpCmluY2x1ZGVfZ3JhcGhpY3MoIi4vaW1hZ2VzX3NlcXVlbmNpbmcva2FsbGlzdG9fZXF1aXZhbGVuY2VDbGFzc2VzX2NhcHRpb24ucG5nIikKYGBgCiAKIyMgQWJ1bmRhbmNlIHF1YW50aWZpY2F0aW9uCgpHaXZlbiBhIHNldCBvZiBtYXBwaW5ncywgdXNpbmcgZWl0aGVyIGFsaWdubWVudC1iYXNlZCBvciBhbGlnbm1lbnQtZnJlZSB3b3JrZmxvd3MsIHRoZSBlc3RpbWF0aW9uIG9mIGV4cHJlc3Npb24gb2YgYSBnZW5lL3RyYW5zY3JpcHQvZXhvbiBtYXkgb2NjdXIgaW4gc2V2ZXJhbCB3YXlzLgoKKipDb3VudGluZyoqOgoKIC0gSW4gYWxpZ25tZW50LWJhc2VkIHdvcmtmbG93cywgb25lIGNvdWxkIGRvIGEgZGlyZWN0IGNvdW50aW5nIG9mIGZyYWdtZW50cyBhdCwgZm9yIGluc3RhbmNlLCB0aGUgZ2VuZSBsZXZlbCwgY291bnRpbmcgdGhlIG51bWJlciBmcmFnbWVudHMgbWFwcGluZyB0byBlYWNoIGdlbmUuIFRoaXMgaGFzIGJlZW4gdGhlIGRvbWluYW50IGFwcHJvYWNoIGZvciB0aGUgZmlyc3QgZGVjYWRlIG9mIFJOQS1zZXEgZGF0YSwgb2Z0ZW4gb2J0YWluZWQgdXNpbmcgcmVmZXJlbmNlIGdlbm9tZSBhbGlnbm1lbnRzLiAKIC0gTWFueSBoZXVyaXN0aWMgY2hvaWNlcyBuZWVkIHRvIGJlIG1hZGU6IERvIHdlIGNvdW50IGEgZnJhZ21lbnQgYXMgc29vbiBhcyBpdCBpbnRlcnNlY3RzIHdpdGggdGhlIGdlbmUncyBjb29yZGluYXRlcywgb3IgZG8gd2UgcmVxdWlyZSB0aGUgZnVsbCBmcmFnbWVudCB0byBtYXAgdG8gdGhlIGdlbmU/IERvIHdlIGNvdW50IGludHJvbmljIHJlYWRzPyBEbyB3ZSBjb3VudCBtdWx0aS1tYXBwaW5nIHJlYWRzPwogCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IEdlbmUtIGFuZCBleG9uLWxldmVsIHJlYWQgY291bnRpbmcuIEltYWdlIGFkYXB0ZWQgZnJvbSBDaGFybG90dGUgU29uZXNvbi4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9pbWFnZXNfc2VxdWVuY2luZy9yZWFkQ291bnRpbmcucG5nIikKYGBgCiAKKipFc3RpbWF0aW9uKio6IAogCiAtIEFidW5kYW5jZSBxdWFudGlmaWNhdGlvbiBpcyBtb3JlIHJlY2VudGx5IHN0YXJ0aW5nIHRvIHNoaWZ0IGZyb20gY291bnRpbmcgdG93YXJkcyB1c2luZyBzdGF0aXN0aWNhbCBtb2RlbHMgdG8gZXN0aW1hdGUgdGhlIGV4cHJlc3Npb24gY291bnRzIGZvciBhIGZlYXR1cmUsIHdoaWNoIGluIHRoaXMgY2FzZSBpcyB0eXBpY2FsbHkgYSB0cmFuc2NyaXB0LiAKIC0gVGhpcyBhcHByb2FjaCBpcyBhbWVuYWJsZSB0byBhbGlnbm1lbnQtZnJlZSB3b3JrZmxvd3MsIHNpbmNlIHRoZSBudW1iZXIgb2YgZnJhZ21lbnRzIGluIGVhY2ggZXF1aXZhbGVuY2UgY2xhc3MgYXJlIHN1ZmZpY2llbnQgc3RhdGlzdGljcyBmb3IgdGhlIGFidW5kYW5jZSBxdWFudGlmaWNhdGlvbiwgbWVhbmluZyB0aGF0IHRoZXkgY29udGFpbiBhbGwgaW5mb3JtYXRpb24gbmVlZGVkIHRvIGVzdGltYXRlIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBzdGF0aXN0aWNhbCBtb2RlbCwgYW5kIGhlbmNlIHRoZSBmZWF0dXJlLWxldmVsIGFidW5kYW5jZXMuIFNpbmNlIHRoZSBleHByZXNzaW9uIGNvdW50cyBpbiB0aGlzIGNhc2UgYXJlIGVzdGltYXRlZCwgdGhleSBhcmUgbm90IG5lY2Vzc2FyaWx5IGludGVnZXIgY291bnRzLCBhbmQgd2lsbCBiZSByZWZlcnJlZCB0byBhcyAnZXN0aW1hdGVkIGNvdW50cycuIAogLSBJbiBvcmRlciB0byBkZXJpdmUgdGhlc2UsIHRoZSBFTS1hbGdvcml0aG0gKFtEZW1wc3RlciAqZXQgYWwuKiAoMTk3NyldKGh0dHBzOi8vd3d3LmpzdG9yLm9yZy9zdGFibGUvMjk4NDg3NSkpIGlzIG9mdGVuIHVzZWQsIGFsdGhvdWdoIG90aGVyIGFwcHJvYWNoZXMgaGF2ZSBiZWVuIHVzZWQgYnkgdG9vbHMgbGlrZSBTYWxtb24uIEEgYmlnIGFkdmFudGFnZSBvZiB0aGUgZXN0aW1hdGlvbiBhcHByb2FjaCBpcyB0aGF0IGl0ICoqcHJvYmFiaWxpc3RpY2FsbHkgYXNzaWducyBmcmFnbWVudHMgdG8gdHJhbnNjcmlwdHMsIHRoZXJlYnkgYXV0b21hdGljYWxseSBkZWFsaW5nIHdpdGggbXVsdGktbWFwcGluZyByZWFkcyoqLiBUaGUgdG90YWwgbnVtYmVyIG9mIGZyYWdtZW50cyBtYXBwaW5nIHRvIGVhY2ggdHJhbnNjcmlwdCBpcyB0aGVuIHRoZSBzdW0gb2YgYWxsIGZyYWdtZW50LWxldmVsIHByb2JhYmlsaXRpZXMgdG8gYmUgYXNzaWduZWQgdG8gdGhhdCByZXNwZWN0aXZlIHRyYW5zY3JpcHQuCiAKYGBge3IsIGVjaG89RkFMU0UsIGZpZy5jYXA9cGFzdGUoIkZpZ3VyZTogQWJ1bmRhbmNlIHF1YW50aWZpY2F0aW9uIHVzaW5nIHRoZSBFTSBhbGdvcml0aG0uIEZpZ3VyZSBmcm9tIFZhbiBkZW4gQmVyZ2UgZXQgYWwuICgyMDE5KS4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9pbWFnZXNfc2VxdWVuY2luZy9hYnVuZGFuY2VFTUFsZ29yaXRobS5wbmciKQpgYGAKCiMjIyBBYnVuZGFuY2UgbWV0cmljcwoKIC0gRm9yIHNpbXBsaWNpdHksIHdlIGhhdmUgbWFpbmx5IGJlZW4gdGFsa2luZyBhYm91dCBmZWF0dXJlLWxldmVsIGNvdW50cyBhcyBpbiBzdW1zIG9mIGZyYWdtZW50cy4gSG93ZXZlciwgdGhpcyBpcyBtZXJlbHkgb25lIG1ldHJpYyB0aGF0IGNhbiBiZSB1c2VkIGFzIGEgcHJveHkgZm9yIGV4cHJlc3Npb24sIGFuZCBzZXZlcmFsIG90aGVycyBleGlzdC4gCiAtIE1vc3Qgb2YgdGhlc2Ugd2VyZSBpbnRyb2R1Y2VkIHRvIGF0dGVtcHQgdG8gbWFrZSB0aGUgYWJ1bmRhbmNlcyBtb3JlIGNvbXBhcmFibGUgYWNyb3NzIHNhbXBsZXMgb3IgZmVhdHVyZXMsIGFzIGNvbXBhcmVkIHRvIHRoZSBzaW1wbGUgY291bnRzLiBUaGVzZSBtYWlubHkgc2VydmUgdG8gY29ycmVjdCBmb3IgdGVjaG5pY2FsIGJpYXNlcyBzdWNoIGFzIHRyYW5zY3JpcHQgbGVuZ3RoIGFuZCBzZXF1ZW5jaW5nIGRlcHRoLCBib3RoIG9mIHdoaWNoIGhhdmUgc2lnbmlmaWNhbnQgaW1wYWN0IG9uIHRoZSBvYnNlcnZlZCBjb3VudHMuIAogIC0gSW5kZWVkLCBmb3IgYSBnZW5lIHdpdGggdGhlIHNhbWUgbVJOQSBjb25jZW50cmF0aW9uIGluIHR3byBzYW1wbGVzLCBzZXF1ZW5jaW5nIG9uZSBzYW1wbGUgZGVlcGVyLCB3aWxsIG9uIGF2ZXJhZ2UgcmVzdWx0IGluIGEgaGlnaGVyIGNvdW50LiAKICAtIExpa2V3aXNlLCBmb3IgdHdvIHRyYW5zY3JpcHRzIHdpdGggdGhlIHNhbWUgbVJOQSBjb25jZW50cmF0aW9uIGJ1dCBkaWZmZXJlbnQgdHJhbnNjcmlwdCBsZW5ndGhzLCBvbmUgd2lsbCB0ZW5kIHRvIG9ic2VydmUgbW9yZSBmcmFnbWVudHMgZnJvbSB0aGUgbG9uZ2VyIHRyYW5zY3JpcHQgZHVlIHRvIHRoZSBmcmFnbWVudGF0aW9uIHN0ZXAgaW4gdGhlIFJOQS1zZXEgcHJvdG9jb2wsIHdoZXJlIGxvbmdlciB0cmFuc2NyaXB0cyBjYW4gYmUgc3BsaXQgaW50byBtb3JlIGZyYWdtZW50cyBvZiBhcHByb3ByaWF0ZSBsZW5ndGguCgoKQmVsb3cgd2UgaW50cm9kdWNlIHNldmVyYWwgcmVsZXZhbnQgYWJ1bmRhbmNlIG1ldHJpY3MsIGJ1dCBub3RlIHRoYXQgbW9zdCBkYXRhIGFuYWx5c2lzIG1ldGhvZHMgd2Ugd2lsbCBkaXNjdXNzIGluIHRoaXMgY291cnNlIHdpbGwgd29yayB3aXRoIChlc3RpbWF0ZWQpIGNvdW50cy4gSW4gd2hhdCBmb2xsb3dzLCBsZXQgJFlfe2ZpfSQgZGVub3RlIHRoZSByYW5kb20gdmFyaWFibGUgcmVwcmVzZW50aW5nIHRoZSBleHByZXNzaW9uIGNvdW50cyBvZiBmZWF0dXJlICRmJCBpbiBzYW1wbGUgJGkkIChvYnRhaW5lZCBlaXRoZXIgYXMgYSBzaW1wbGUgc3VtIG9mIGZyYWdtZW50cyBvciBlc3RpbWF0ZWQgdXNpbmcgbGlnaHR3ZWlnaHQgYXBwcm9hY2hlcyksIGFuZCBsZXQgJE5faSA9IFxzdW1fZiBZX3tmaX0kIGRlbm90ZSB0aGUgc2VxdWVuY2luZyBkZXB0aCAoJ2xpYnJhcnkgc2l6ZScpIG9mIHNhbXBsZSAkaSQuCgogKiAqKkNvdW50cyBwZXIgbWlsbGlvbiAoQ1BNKSoqIGFyZSB0aGUgY291bnRzIG9uZSBjb3VsZCBleHBlY3QgdG8gb2JzZXJ2ZSBpZiB0aGUgc2FtcGxlIHdhcyBzZXF1ZW5jZWQgdG8gYSBkZXB0aCBvZiBvbmUgbWlsbGlvbi4KIApcWyBDUE1fe2ZpfSA9IFxmcmFje1lfe2ZpfX17Tl9pfSAxMF42IFxdCgogKiAqKlRyYW5zY3JpcHRzIHBlciBtaWxsaW9uIChUUE0pKiogcmVmZXJzIHRvIHRoZSBjb25jZW50cmF0aW9uIG9yIHByb3BvcnRpb24gb2YgeW91ciBmZWF0dXJlIGluIHRoZSBzYW1wbGUuIFRQTXMgdGFrZSBpbnRvIGFjY291bnQgdGhlIGxlbmd0aCBvZiB0aGUgZmVhdHVyZSwgd2hpY2ggaXMgb2Z0ZW4gcmVmb3JtdWxhdGVkIGludG8gYW4gKmVmZmVjdGl2ZSBsZW5ndGgqICRsX3tmaX1eeyhlZmYpfSQsIHJlbGF0aW5nIHRvIHRoZSBudW1iZXIgb2YgcG9zc2libGUgc3RhcnQgc2l0ZXMgdGhhdCBhIGZlYXR1cmUgbWF5IGhhdmUgaW4gb3JkZXIgdG8gZ2VuZXJhdGUgZnJhZ21lbnRzIG9mIGEgdHlwaWNhbCBsZW5ndGggb2JzZXJ2ZWQgaW4geW91ciBkYXRhc2V0LiBUaGlzIHR5cGljYWwgbGVuZ3RoIGlzIG9mdGVuIGNhbGN1bGF0ZWQgdXNpbmcgdGhlIG9ic2VydmVkIGZyYWdtZW50IGxlbmd0aCBkaXN0cmlidXRpb24gZnJvbSB0aGUgZGF0YSBhbmQgZGVmaW5lZCBhcyAkJCBsX3tmaX1eeyhlZmYpfSA9IGxfe2Z9IC0gXGhhdHtcYmFye0Z9fV9pICsgMSwkJCB3aGVyZSAkbF97Zn0kIGlzIHRoZSB0b3RhbCBsZW5ndGggb2YgYSBmZWF0dXJlIGluIHRlcm1zIG9mIG51bWJlciBvZiBudWNsZW90aWRlcywgYW5kICRcaGF0e1xiYXJ7Rn19X2kkIGlzIHRoZSBlc3RpbWF0ZWQgYXZlcmFnZSBmcmFnbWVudCBsZW5ndGggaW4gc2FtcGxlICRpJC4gV2UgY2FuIHVzZSB0aGlzIHRvIGRlZmluZSAkJCBUUE1fe2ZpfSA9IFxmcmFje1lfe2ZpfX17bF97Zml9XnsoZWZmKX19IFxsZWZ0KCBcZnJhY3sxfXtcc3VtX2YgXGZyYWN7WV97Zml9fXtsX3tmaX1eeyhlZmYpfX19IFxyaWdodCkgMTBeNi4kJCBOb3RlIHRoYXQgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIHJpZ2h0LWhhbmQtc2lkZSAoUkhTKSwgJFxmcmFje1lfe2ZpfX17bF97Zml9XnsoZWZmKX19JCBpcyB0aGUgZXhwcmVzc2lvbiBjb3VudHMgbm9ybWFsaXplZCBmb3IgdGhlIGxlbmd0aCBvZiB0aGUgZmVhdHVyZS4gVGhpcyBtZWFzdXJlLCBob3dldmVyLCBpcyBzdGlsbCBhZmZlY3RlZCBieSB0aGUgc2VxdWVuY2luZyBkZXB0aCwgd2hpY2ggaXMgdGhlbiBhbGxldmlhdGVkIGJ5IGRpdmlkaW5nIGJ5IHRoZSBzdW0gb2YgdGhlIGxlbmd0aC1ub3JtYWxpemVkIGNvdW50cyBhY3Jvc3MgYWxsIGZlYXR1cmVzLCBpLmUuLCAkXHN1bV9mIFxmcmFje1lfe2ZpfX17bF97Zml9XnsoZWZmKX19JC4gVFBNcyBoZW5jZSBub3JtYWxpemUgZm9yIHRoZSBmZWF0dXJlIGxlbmd0aCBhcyB3ZWxsIGFzIHNlcXVlbmNpbmcgZGVwdGguCgojIyMgVGhlIGZpbmFsIGNvdW50ZG93bgoKT25jZSBhYnVuZGFuY2VzIGhhdmUgYmVlbiBxdWFudGlmaWVkLCB0aGUgKGVzdGltYXRlZCkgY291bnRzIGFyZSB0eXBpY2FsbHkgc3RvcmVkIGluIGEgY291bnQgbWF0cml4LCB3aXRoIGdlbmVzIHNwYW5uaW5nIHRoZSByb3dzIGFuZCBzYW1wbGVzIHNwYW5uaW5nIHRoZSBjb2x1bW5zLiBUaGlzIGNvdW50IG1hdHJpeCBmb3JtcyB0aGUgYmFzaXMgb2YgbW9zdCBkb3duc3RyZWFtIGFuYWx5c2VzIHRvIGludGVycHJldCBSTkEtc2VxIGRhdGEsIGFuZCBpdCB3aWxsIGJlIHRoZSBtYWluIG9iamVjdCB3ZSB3aWxsIGJlIHdvcmtpbmcgd2l0aCBpbiB0aGUgZm9sbG93aW5nIGxlY3R1cmVzLgoKCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IEFuIHVwZGF0ZWQgc2VxdWVuY2luZyB3b3JrZmxvdy4gSW1hZ2UgYWRhcHRlZCBmcm9tIFZhbiBkZW4gQmVyZ2UgZXQgYWwuICgyMDE5KS4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9pbWFnZXNfc2VxdWVuY2luZy9zZXFXb3JrZmxvdzMucG5nIikKYGBgCgojIEEgcHJlcHJvY2Vzc2luZyB0dXRvcmlhbAoKVGhlIGNvdXJzZSBHaXRIdWIgcmVwb3NpdG9yeSBjb250YWlucyBjb2RlIHRvIGRvd25sb2FkIGFuZCBxdWFudGlmeSBhIHNhbXBsZSBmcm9tIGFuIFJOQS1zZXEgZGF0YXNldCB3ZSB3aWxsIGFuYWx5emUgbGF0ZXIuIFRha2UgYSBsb29rIGF0IHRoZSBjb2RlIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vc3RhdE9taWNzL1NHQTIxL2Jsb2IvbWFzdGVyL3NlcXVlbmNpbmdfcHJlcHJvY2Vzc2luZy5zaCksIGFuZCB0cnkgdG8gcnVuIHRoZSBjb2RlLCB3aGljaCB3aWxsIHJlcXVpcmUgeW91IHRvIGluc3RhbGwgc2V2ZXJhbCBiaW9pbmZvcm1hdGljcyBzb2Z0d2FyZSB0b29scywgYXMgbWVudGlvbmVkIGluIHRoZSBmaWxlLgpJZiBzdWNjZXNzZnVsLCB5b3UgY291bGQgdHJ5IGFkYXB0aW5nIHRoZSBzY3JpcHQgaW4gb3JkZXIgdG8gZG93bmxvYWQgYW5kIHF1YW50aWZ5IGFsbCBzYW1wbGVzIGZyb20gdGhhdCBkYXRhc2V0LgoKIyBSZWZlcmVuY2VzCgoK