1 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.

Figure: The data output revolution of sequencing machines. Image from Illumina documentation.

1.1 The bulk RNA-seq workflow

Library preparation steps:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. PCR amplification. To increase concentration, several PCR reaction cycles are performed.
  7. 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.

Figure: The sequencing workflow. Image adapted from Van den Berge et al. (2019).

1.2 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:
    1. Sequence identifier line, starting with @.
    2. The sequence.
    3. Another sequence identifier line, now starting with +.
    4. Quality scores.

Figure: One read in a FASTQ file. Slide courtesy by Charlotte Soneson.

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.

2 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.

Figure: An updated sequencing workflow, including sequencing and mapping. Image adapted from Van den Berge et al. (2019).

2.1 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.

2.2 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.

2.2.1 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.

Figure: A reference sequence of human chr1.

Figure: An example GTF file.

  • 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.

2.2.2 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.

Figure: Unspliced and spliced alignment. Figure from Van den Berge et al. (2019).

2.2.3 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.

Figure: Overview of kallisto, image from Bray et al. (2016).Figure: Overview of kallisto, image from Bray et al. (2016).

2.3 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?

Figure: Gene- and exon-level read counting. Image adapted from Charlotte Soneson.

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.

Figure: Abundance quantification using the EM algorithm. Figure from Van den Berge et al. (2019).

2.3.1 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.

Figure: An updated sequencing workflow. Image adapted from Van den Berge et al. (2019).

LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIHNlcXVlbmNpbmc6IFNlcXVlbmNpbmcgdGVjaG5vbG9neSBhbmQgcHJlcHJvY2Vzc2luZyBvZiBzZXF1ZW5jaW5nIGRhdGEiCmF1dGhvcjogIktvZW4gVmFuIGRlbiBCZXJnZSIKZGF0ZTogIkxhc3QgY29tcGlsZWQgb24gYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIGxhdGV4X2VuZ2luZTogeGVsYXRleAotLS0KCmBgYHtyIGZ1bmN0aW9ucywgaW5jbHVkZT1GQUxTRX0KIyBBIGZ1bmN0aW9uIGZvciBjYXB0aW9uaW5nIGFuZCByZWZlcmVuY2luZyBpbWFnZXMKZmlnIDwtIGxvY2FsKHsKICAgIGkgPC0gMAogICAgcmVmIDwtIGxpc3QoKQogICAgbGlzdCgKICAgICAgICBjYXA9ZnVuY3Rpb24ocmVmTmFtZSwgdGV4dCkgewogICAgICAgICAgICBpIDw8LSBpICsgMQogICAgICAgICAgICByZWZbW3JlZk5hbWVdXSA8PC0gaQogICAgICAgICAgICBwYXN0ZSgiRmlndXJlICIsIGksICI6ICIsIHRleHQsIHNlcD0iIikKICAgICAgICB9LAogICAgICAgIHJlZj1mdW5jdGlvbihyZWZOYW1lKSB7CiAgICAgICAgICAgIHJlZltbcmVmTmFtZV1dCiAgICAgICAgfSkKfSkKYGBgIAoKYGBge3IsIGVjaG89RkFMU0UsIGV2YWw9VFJVRX0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KGtuaXRyKQogIGxpYnJhcnkocm1hcmtkb3duKQogIGxpYnJhcnkoZ2dwbG90MikKfSkKYGBgCgojIFNlcXVlbmNpbmcgdGVjaG5vbG9neQoKIC0gTWVhc3VyaW5nIG1STkEgbW9sZWN1bGVzIHR5cGljYWxseSBoYXBwZW5zIHRocm91Z2ggc2VxdWVuY2luZy4KIC0gVGhlIHRlY2hub2xvZ3kgY29udGludWVzIHRvIGV2b2x2ZSBhdCBhbiBpbmNyZWRpYmxlIHNwZWVkLiBUaGUgZGF0YSBvdXRwdXQgb2Ygc28tY2FsbGVkIGBuZXh0IGdlbmVyYXRpb24nIHNlcXVlbmNpbmcgbWFjaGluZXMgaGFzIG1vcmUgdGhhbiBkb3VibGVkIGVhY2ggeWVhciEgU2ltdWx0YW5lb3VzbHksIHRoZSBjb3N0IG9mIHNlcXVlbmNpbmcgKGluIHRlcm1zIG9mICQgcGVyIEdpZ2FiYXNlKSBpcyBkcm9wcGluZy4gRWFjaCB5ZWFyLCB3ZSdyZSBhYmxlIHRvIHNlcXVlbmNlIG1vcmUgZm9yIGxlc3MgbW9uZXksIHByb3ZpZGluZyBtb3JlIGluZm9ybWF0aW9uLCBhcyB3ZWxsIGFzIGFsc28gY29tcHV0YXRpb25hbCBhbmQgc3RhdGlzdGljYWwgY2hhbGxlbmdlcy4KIC0gVGhpcyB0cmVtZW5kb3VzIHRlY2hub2xvZ2ljYWwgcmV2b2x1dGlvbiBoYXMgcmV2b2x1dGlvbml6ZWQgYmlvbG9neSwgYW5kIGdlbm9taWMgc2VxdWVuY2luZyBpcyBub3cgYSBjb3JlIGNvbXBvbmVudCBvZiB0aGUgbW9kZXJuLWRheSBiaW9sb2dpc3QncyB0b29sa2l0LgogLSBUaGUgbGFyZ2UgbWFqb3JpdHkgb2Ygc2VxdWVuY2luZyBkYXRhIGlzIGdlbmVyYXRlZCB1c2luZyBzZXF1ZW5jaW5nLWJ5LXN5bnRoZXNpcyB1c2luZyBtYWNoaW5lcyBwcm9kdWNlZCBieSB0aGUgY29tcGFueSBJbGx1bWluYS4gV2hpbGUgbmV3IHBsYXllcnMgc3VjaCBhcyBQYWNpZmljIEJpb3NjaWVuY2VzIGFuZCBPeGZvcmQgTmFub3BvcmUgaGF2ZSBlbnRlcmVkIHRoZSBzY2VuZSwgdGhlc2UgYXJlIHR5cGljYWxseSBtb3N0IHVzZWZ1bCBmb3IgKGJ1dCBub3QgbGltaXRlZCB0bykgRE5BIHNlcXVlbmNpbmcgcmF0aGVyIHRoYW4gZ2VuZSBleHByZXNzaW9uIHN0dWRpZXMsIG93aW5nIHRvIHRoZWlyIGNhcGFiaWxpdHkgb2Ygc2VxdWVuY2luZyBsb25nIG1vbGVjdWxlcy4KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IFRoZSBkYXRhIG91dHB1dCByZXZvbHV0aW9uIG9mIHNlcXVlbmNpbmcgbWFjaGluZXMuIEltYWdlIGZyb20gSWxsdW1pbmEgZG9jdW1lbnRhdGlvbi4iKX0KIyBBbGwgZGVmYXVsdHMKaW5jbHVkZV9ncmFwaGljcygiLi9maWd1cmVzL3NlcVRlY2hub2xvZ3lfdGhyb3VnaHB1dC5wbmciKQpgYGAKCiMjIFRoZSBidWxrIFJOQS1zZXEgd29ya2Zsb3cKCkxpYnJhcnkgcHJlcGFyYXRpb24gc3RlcHM6CgoxLiBGaXJzdCwgdGhlIGJpb2xvZ2ljYWwgKipzYW1wbGVzIG9mIGludGVyZXN0IGFyZSBjb2xsZWN0ZWQqKi4gT3dpbmcgdG8gdGhlIG1hdHVyaXR5IG9mIGRpZmZlcmVudCBwcm90b2NvbHMgZm9yIHNlcXVlbmNpbmcsIHNldmVyYWwgdHlwZXMgb2YgYmlvbG9naWNhbCBpbnB1dCBzYW1wbGVzIGFyZSBhbWVuYWJsZSB0byBzZXF1ZW5jaW5nLCBzdWNoIGFzIGZyb3plbiB0aXNzdWVzIG9yIEZGUEUtcHJlc2VydmVkIHNhbXBsZXMuCjIuIFRoZSAqKihtKVJOQSBtb2xlY3VsZXMgZnJvbSBvdXIgc2FtcGxlIGFyZSBjYXB0dXJlZCoqLiBUaGlzIHR5cGljYWxseSBpbnZvbHZlcyBjZWxsIGx5c2lzIGluIG9yZGVyIHRvIHJlbGVhc2UgdGhlIChtKVJOQSBtb2xlY3VsZXMgZnJvbSB3aXRoaW4gdGhlIGNlbGxzLiBUaGUgbVJOQSBtb2xlY3VsZXMgYXJlIG1vc3Qgb2Z0ZW4gY2FwdHVyZWQgdXNpbmcgKGkpIHBvbHlBLWNhcHR1cmUgdG8gc2VsZWN0IGZvciBwb2x5YWRlbnlsYXRlZCBSTkEsIG9yIChpaSkgcmlib3NvbWFsIGRlcGxldGlvbiwgd2hlcmUgcmlib3NvbWFsIGFuZCB0cmFuc2ZlciBSTkFzIGFyZSBkZXBsZXRlZCwgYW5kIHNvIGFsc28gbm9uLXBvbHlBLW1STkEgbW9sZWN1bGVzIG1heSBiZSBjYXB0dXJlZCwgc3VjaCBhcyBtaWNybyBSTkFzLiBJbiB0aGUgY2FzZSBvZiBgdGFyZ2V0ZWQgc2VxdWVuY2luZycsIHdoZXJlIHJlbGV2YW50IG1vbGVjdWxlcyBhcmUgb2YgbWFpbiBpbnRlcmVzdCAoZS5nLiwgYSBnZW5lIHBhbmVsKSwgdGhlc2UgdGFyZ2V0cyBjYW4gYmUgc3BlY2lmaWNhbGx5IHRhcmdldGVkIGluIHRoaXMgc3RlcC4KMy4gKipGcmFnbWVudGF0aW9uKiogb2YgY2FwdHVyZWQgbW9sZWN1bGVzLiBUaGUgY2FwdHVyZWQgbW9sZWN1bGVzIGFyZSBmcmFnbWVudGVkLCBlaXRoZXIgY2hlbWljYWxseSBvciBtZWNoYW5pY2FsbHkuIFRoZSBhcHByb3ByaWF0ZSBzaXplIG9mIGZyYWdtZW50cyBkZXBlbmRzIG9uIHRoZSBzZXF1ZW5jaW5nIG1hY2hpbmVzLCBidXQgaXMgb2Z0ZW4gaW4gdGhlIHJhbmdlIG9mIDMwMCAtIDUwMGJwLgo0LiAqKlJldmVyc2UgdHJhbnNjcmlwdGlvbioqLiBDdXJyZW50IGRvbWluYW50IHNlcXVlbmNpbmcgbWFjaGluZXMgb25seSBzZXF1ZW5jZSBkb3VibGUtc3RyYW5kZWQgRE5BIG1vbGVjdWxlcy4gVGhlcmVmb3JlLCBpbiBvcmRlciB0byBtZWFzdXJlIHNpbmdsZS1zdHJhbmRlZCBtUk5BLCB3ZSBtdXN0IGZpcnN0IHJldmVyc2UgdHJhbnNjcmliZSB0aGVzZSBtb2xlY3VsZXMgdG8gYSBkb3VibGUtc3RyYW5kZWQgY29tcGxlbWVudGFyeSAoY0ROQSkgbW9sZWN1bGUuCjUuICoqQWRhcHRlciBsaWdhdGlvbioqLiBBZGFwdGVycyBhcmUgb2xpZ29udWNsZW90aWRlcyAoc2hvcnQgc2VxdWVuY2VzIG9mIG51Y2xlb3RpZGVzKSB0aGF0IGFyZSBwbGF0Zm9ybS1zcGVjaWZpYyBzZXF1ZW5jZXMgZm9yIGZyYWdtZW50IHJlY29nbml0aW9uIGJ5IHRoZSBzZXF1ZW5jaW5nIG1hY2hpbmVzLiBUaGVzZSBhcmUgYWRkZWQgZWl0aGVyIHRvIHRoZSAzJyBvciA1JyBlbmQgb2YgdGhlIGNETkEgbW9sZWN1bGVzIG9yIHVzZWQgYXMgcHJpbWVycyBpbiB0aGUgcmV2ZXJzZSB0cmFuc2NyaXB0aW9uIHJlYWN0aW9uLiBUaGUgZmluYWwgY0ROQSBsaWJyYXJ5IGNvbnNpc3RzIG9mIGNETkEgaW5zZXJ0cyBmbGFua2VkIGJ5IGFuIGFkYXB0ZXIgc2VxdWVuY2Ugb24gZWFjaCBlbmQuIAo2LiAqKlBDUiBhbXBsaWZpY2F0aW9uKiouIFRvIGluY3JlYXNlIGNvbmNlbnRyYXRpb24sIHNldmVyYWwgUENSIHJlYWN0aW9uIGN5Y2xlcyBhcmUgcGVyZm9ybWVkLgo3LiBMb2FkaW5nIHRoZSBhbXBsaWZpZWQgY0ROQSBsaWJyYXJ5IG9uIHRoZSAqKnNlcXVlbmNpbmcqKiBtYWNoaW5lLiBGaW5kIG91dCBob3cgc2VxdWVuY2luZy1ieS1zeW50aGVzaXMgd29ya3MgdGhyb3VnaCBbdGhpcyB2aWRlb10oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1mQ2Q2QjVIUmFaOCkuIE5vdGUgdGhhdCB0aGUgdmlkZW8gc2hvd3MgcGFpcmVkLWVuZCBzZXF1ZW5jaW5nLCB3aGVyZSBhIG51bWJlciBvZiBiYXNlcGFpcnMgYXJlIHNlcXVlbmNlZCBhdCBlYWNoIGVuZCBvZiB0aGUgZnJhZ21lbnQuIEFsbCBwcmV2aW91cyBzdGVwcyB0b2dldGhlciBhcmUgZGVzY3JpYmVkIGFzIGBzYW1wbGUgcHJlcCcgaW4gdGhhdCB2aWRlby4KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IFRoZSBzZXF1ZW5jaW5nIHdvcmtmbG93LiBJbWFnZSBhZGFwdGVkIGZyb20gVmFuIGRlbiBCZXJnZSBldCBhbC4gKDIwMTkpLiIpfQppbmNsdWRlX2dyYXBoaWNzKCIuL2ZpZ3VyZXMvc2VxV29ya2Zsb3cxX2NsZWFuLnBuZyIpCmBgYAoKIyMgVGhlIHNlcXVlbmNpbmcgb3V0cHV0IGZpbGVzCgotIFRoZSB0eXBpY2FsIG91dHB1dCBvZiBhIHNlcXVlbmNpbmcgbWFjaGluZSB3ZSB3aWxsIGJlIHdvcmtpbmcgd2l0aCBhcmUgRkFTVEEgb3IgRkFTVFEgZmlsZXMgZm9yIGVhY2ggc2FtcGxlLiBFYWNoIG9mIHRoZXNlIGZpbGVzIGFyZSBzZXZlcmFsIGdpZ2Jhc2VzIGxhcmdlIGFuZCBjb250YWluIG1pbGxpb25zIG9mIHNlcXVlbmNlcywgd2hpY2ggd2Ugd2lsbCBjYWxsICoqcmVhZHMqKi4gRm9yIHBhaXJlZC1lbmQgc2VxdWVuY2luZywgdGhlcmUgYXJlIHR3byBmaWxlcyBmb3IgZWFjaCBzYW1wbGUsIG9uZSBmb3IgZWFjaCBlbmQgb2YgdGhlIHNlcXVlbmNlZCBmcmFnbWVudHMuCiAtIFRoZSBkaWZmZXJlbmNlIGJldHdlZW4gYSBGQVNUQSBmaWxlIGFuZCBhIEZBU1RRIGZpbGUsIGlzIHRoYXQgd2hpbGUgRkFTVEEgZmlsZXMgb25seSBzdG9yZSB0aGUgcmVzdWx0cyBvZiBiYXNlIGNhbGxzIChzZXF1ZW5jZXMpLCBGQVNUUSBmaWxlcyBhbHNvIHN0b3JlIHRoZSBxdWFsaXR5IHNjb3JlIG9mIGVhY2ggYmFzZSBjYWxsIChpLmUuLCBlYWNoIGNhbGxlZCBudWNsZW90aWRlKSwgd2hpY2ggY2FuIGJlIHVzZWZ1bCBpbiBkb3duc3RyZWFtIGFuYWx5c2VzIHN1Y2ggYXMgbWFwcGluZyBvciB2YXJpYW50IGNhbGxpbmcuCiAtIEEgRkFTVFEgZmlsZSBjb250YWlucyBmb3VyIGxpbmVzIGZvciBlYWNoIHNlcXVlbmNlZCByZWFkOgogICAgMS4gU2VxdWVuY2UgaWRlbnRpZmllciBsaW5lLCBzdGFydGluZyB3aXRoIEAuCiAgICAyLiBUaGUgc2VxdWVuY2UuCiAgICAzLiBBbm90aGVyIHNlcXVlbmNlIGlkZW50aWZpZXIgbGluZSwgbm93IHN0YXJ0aW5nIHdpdGggKy4KICAgIDQuIFF1YWxpdHkgc2NvcmVzLgoKYGBge3IsIGVjaG89RkFMU0UsIGZpZy5jYXA9cGFzdGUoIkZpZ3VyZTogT25lIHJlYWQgaW4gYSBGQVNUUSBmaWxlLiBTbGlkZSBjb3VydGVzeSBieSBDaGFybG90dGUgU29uZXNvbi4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9maWd1cmVzL2Zhc3RxTGluZS5wbmciKQpgYGAKCkFzIHlvdSdsbCBoYXZlIG5vdGljZWQsIHRoZSBiYXNlIGNhbGwgcXVhbGl0eSBzY29yZXMgYXJlIGVuY29kZWQgYXMgQVNDSUkgY2hhcmFjdGVycyBmb3IgZWZmaWNpZW50IHN0b3JhZ2UuIFRoZXNlIEFTQ0lJIGNoYXJhY3RlcnMgY2FuIGJlIGNvbnZlcnRlZCBpbnRvIGludGVnZXJzIGNhbGxlZCBQaHJlZCBzY29yZXMsIHdoaWNoIGFyZSBsb2dhcml0aG1pY2FsbHkgcmVsYXRlZCB0byB0aGUgcHJvYmFiaWxpdHkgb2YgYW4gZXJyb25lb3VzIGJhc2UgY2FsbC4KCiMgUHJlcHJvY2Vzc2luZyBvZiByYXcgc2VxdWVuY2luZyBkYXRhCgpBZnRlciBzZXF1ZW5jaW5nLCB3ZSB0eXBpY2FsbHkgZG8gYSBxdWFsaXR5IGNvbnRyb2wgKFFDKSBjaGVjayB0byB2ZXJpZnkgdGhlIHF1YWxpdHkgb2YgdGhlIHNhbXBsZXMuIER1cmluZyBRQyBjaGVjaywgYWJlcnJhbnQgc2FtcGxlcyBkdWUgdG8gZS5nLiBkZWdyYWRlZCBtUk5BIGNhbiBiZSBkZXRlY3RlZC4KClRoZSBzZXF1ZW5jaW5nIHJlYWRzIG9uIHRoZWlyIG93biBjb250YWluIGEgbG90IG9mIGluZm9ybWF0aW9uLCBidXQgYXJlIG1vc3QgdXNlZnVsIGlmIHdlIHdvdWxkIGJlIGFibGUgdG8gYXNzaWduIHNlcXVlbmNpbmcgcmVhZHMgdG8gZ2Vub21pYyBmZWF0dXJlcyAoZ2VuZXMsIGV4b25zLCB0cmFuc2NyaXB0cywgZXRjLiksIGkuZS4sIGZvciBlYWNoIHNlcXVlbmNpbmcgcmVhZCB3ZSB3aWxsIHRyeSB0byBkZXJpdmUgdGhlIChzZXQgb2YpIGZlYXR1cmUocykgdGhhdCBjb3VsZCBoYXZlIHBsYXVzaWJseSBwcm9kdWNlZCB0aGUgZnJhZ21lbnQgdGhyb3VnaCB0aGUgcHJvY2VzcyBvZiBnZW5lIGV4cHJlc3Npb24uIFRoaXMgcHJvY2VzcyBpcyBjYWxsZWQgKiptYXBwaW5nKiouIE1vc3Qgb2Z0ZW4gd2UgbWFwIHJlYWRzIHRvIGdlbmVzLiAKCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IEFuIHVwZGF0ZWQgc2VxdWVuY2luZyB3b3JrZmxvdywgaW5jbHVkaW5nIHNlcXVlbmNpbmcgYW5kIG1hcHBpbmcuIEltYWdlIGFkYXB0ZWQgZnJvbSBWYW4gZGVuIEJlcmdlIGV0IGFsLiAoMjAxOSkuIil9CmluY2x1ZGVfZ3JhcGhpY3MoIi4vZmlndXJlcy9zZXFXb3JrZmxvdzIucG5nIikKYGBgCgojIyBRdWFsaXR5IGNvbnRyb2wKCkR1cmluZyBxdWFsaXR5IGNvbnRyb2wsIGRpYWdub3N0aWMgcGxvdHMgYXJlIGNyZWF0ZWQgZm9yIGVhY2ggc2FtcGxlIGluIG9yZGVyIHRvIGRldGVybWluZSBpdHMgcXVhbGl0eS4gVGhlIG1vc3QgcG9wdWxhciBRQyB0b29sIGZvciBidWxrIFJOQS1zZXEgZGF0YSBpcyBbRmFzdFFDXShodHRwczovL3d3dy5iaW9pbmZvcm1hdGljcy5iYWJyYWhhbS5hYy51ay9wcm9qZWN0cy9mYXN0cWMvKS4gSWYgbWFueSBzYW1wbGVzIGFyZSBzZXF1ZW5jZWQsIHRoZW4gW011bHRpUUNdKGh0dHBzOi8vbXVsdGlxYy5pbmZvLykgY2FuIGJlIHVzZWQgdG8gYWdncmVnYXRlIHRoZSBRQyBjaGVja3MgYWNyb3NzIHNhbXBsZXMgaW4gYSBjb252ZW5pZW50bHkgb3JnYW5pemVkIG92ZXJ2aWV3LgoKVGhlIEZhc3RRQyB3ZWJzaXRlIHByb3ZpZGVzIGludGVyZXN0aW5nIGV4YW1wbGUgcmVwb3J0cyBmb3IgdXMgdG8gbG9vayBhdCBhbmQgY29tcGFyZSBhZ2FpbnN0LiBIZXJlIGFyZSBleGFtcGxlIHJlcG9ydHMgb2YgW2hpZ2gtcXVhbGl0eSBJbGx1bWluYSBkYXRhXShodHRwczovL3d3dy5iaW9pbmZvcm1hdGljcy5iYWJyYWhhbS5hYy51ay9wcm9qZWN0cy9mYXN0cWMvZ29vZF9zZXF1ZW5jZV9zaG9ydF9mYXN0cWMuaHRtbCkgYW5kIFtsb3ctcXVhbGl0eSBJbGx1bWluYSBkYXRhXShodHRwczovL3d3dy5iaW9pbmZvcm1hdGljcy5iYWJyYWhhbS5hYy51ay9wcm9qZWN0cy9mYXN0cWMvYmFkX3NlcXVlbmNlX2Zhc3RxYy5odG1sKS4KCiMjIE1hcHBpbmcKCiAtIE1hcHBpbmcgaXMgYSBjcml0aWNhbCBzdGVwIGluIHRoZSBpbnRlcnByZXRhdGlvbiBvZiBSTkEtc2VxIGRhdGEsIHdoZXJlIHdlIGFyZSBhdHRyaWJ1dGluZyByZWFkcyB0byBnZW5vbWljIGZlYXR1cmVzLiAKIC0gQWxsb3dzIHVzIHRvIG1lYXN1cmUgaG93IHN0cm9uZyBhIGZlYXR1cmUgc3VjaCBhcyBhIGdlbmUgaXMgZXhwcmVzc2VkOiB0aGUgbnVtYmVyIG9mIHJlYWRzIG1hcHBpbmcgdG8gYSBnZW5lIHNlcnZlIGFzIGEgcHJveHkgZm9yIGhvdyBoaWdoIHRoYXQgZ2VuZSBoYXMgYmVlbiBleHByZXNzZWQgaW4gdGhlIHNhbXBsZS4gCiAtIFdoaWxlIHRoaXMgb3BlbnMgdGhlIGRvb3IgdG8gbWFueSBvcHBvcnR1bml0aWVzLCBtYXBwaW5nIGlzIGhhcmQuCiAtIFdlIGFyZSAqKnR5cGljYWxseSB1bmFibGUgdG8gYXNzaWduIGVhY2ggaW5kaXZpZHVhbCByZWFkIHVuaXF1ZWx5KiogdG8gb25lIHNwZWNpZmljIGdlbmU7IHNvbWUgcmVhZHMgY2Fubm90IGJlIHVuYW1iaWd1b3VzbHkgbWFwcGVkIGFuZCBhcmUgY29tcGF0aWJsZSB3aXRoIG11bHRpcGxlIGdlbmVzLiBUaGVzZSByZWFkcyBhcmUgc2FpZCB0byBiZSAnbXVsdGktbWFwcGluZycuCiAKRmluYWxseSwgYSBub3RlIG9uIHRlcm1pbm9sb2d5LiBJbiB0aGlzIHRleHQgd2Ugd2lsbCB1c2UgdGhlIHdvcmRzICdyZWFkJyBvciAnZnJhZ21lbnQnIChyZWZlcnJpbmcgdG8gdGhlIGZyYWdtZW50ZWQgbVJOQSBtb2xlY3VsZSBiZWluZyBzZXF1ZW5jZWQpIHRvIGRlc2lnbmF0ZSBhIGRhdHVtLCBub3RlIHRoYXQgdGhpcyBjb3VsZCBiZSBlaXRoZXIgYSBzaW5nbGUgcmVhZCAoaW4gc2luZ2xlLWVuZCBzZXF1ZW5jaW5nKSBvciBhIHJlYWQgcGFpciAoaW4gcGFpcmVkLWVuZCBzZXF1ZW5jaW5nKS4gVGhlIGxpdGVyYXR1cmUgbWF5IGFsc28gdXNlIHRoZXNlIHdvcmRzIGludGVyY2hhbmdlYWJseSwgYWx0aG91Z2ggJ2ZyYWdtZW50JyBzZWVtcyBiZXR0ZXIgYXQgYXZvaWRpbmcgYW1iaWd1aXR5IGJldHdlZW4gc2luZ2xlLWVuZCByZWFkcyBhbmQgcGFpcmVkLWVuZCByZWFkIHBhaXJzLgoKIyMjIFJlZmVyZW5jZSBmaWxlcwoKIC0gVGhlIGFsaWdubWVudCBtb3N0IG9mdGVuIHJlbGllcyBvbiBhICoqcmVmZXJlbmNlIGdlbm9tZSoqIG9mIHRoZSBzcGVjaWVzLCB3aGljaCBjYW4gYmUgY29uc2lkZXJlZCBhICdyZXByZXNlbnRhdGl2ZSBleGFtcGxlJyBvZiB0aGUgZ2Vub21lIHNlcXVlbmNlIG9mIHRoYXQgc3BlY2llcy4gUmVmZXJlbmNlIGdlbm9tZXMgYXJlIGNvbnRpdW91c2x5IHVwZGF0ZWQgYW5kIHJlbGVhc2VkIHBlcmlvZGljYWxseS4KIC0gUmVmZXJlbmNlIGdlbm9tZXMgY2FuIGJlIGZyZWVseSBkb3dubG9hZGVkIGZyb20gc2V2ZXJhbCBwcm92aWRlcnMsIGZvciBleGFtcGxlIFtFbnNlbWJsXShodHRwOi8vd3d3LmVuc2VtYmwub3JnL2luZm8vZGF0YS9mdHAvaW5kZXguaHRtbCkgb3IgW0dlbmNvZGVdKGh0dHBzOi8vd3d3LmdlbmNvZGVnZW5lcy5vcmcvaHVtYW4vKS4KIC0gQWxvbmcgd2l0aCBhIHJlZmVyZW5jZSBnZW5vbWUsIGFuIGFubm90YXRpb24gR0ZGIG9yIEdURiBmaWxlIGRlZmluZXMgdGhlIGNvb3JkaW5hdGVzIG9mIHNwZWNpZmljIGdlbm9taWMgZmVhdHVyZXMuCiAtIFdoaWxlIGhlcmUgd2Ugd2lsbCBmb2N1cyBvbiByZWZlcmVuY2UtYmFzZWQgYWxpZ25tZW50LCBpLmUuLCBhbGlnbm1lbnQgd2hlcmUgYSByZWZlcmVuY2UgZ2Vub21lIG9yIHRyYW5zY3JpcHRvbWUgaXMgYXZhaWxhYmxlLCBub3RlIHRoYXQgYSAqZGUgbm92byogY29uc3RydWN0aW9uIG9mIGEgcmVmZXJlbmNlIHRyYW5zY3JpcHRvbWUgaXMgYWxzbyBwb3NzaWJsZSwgd2hlcmUgdGhlIHJlZmVyZW5jZSBtYXkgYmUgY29uc3RydWN0ZWQgZnJvbSB0aGUgb2JzZXJ2ZWQgc2VxdWVuY2luZyByZWFkcy4KIApgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmNhcD1wYXN0ZSgiRmlndXJlOiBBIHJlZmVyZW5jZSBzZXF1ZW5jZSBvZiBodW1hbiBjaHIxLiIpfQppbmNsdWRlX2dyYXBoaWNzKCIuL2ZpZ3VyZXMvcmVmZXJlbmNlR2Vub21lLnBuZyIpCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIGZpZy5jYXA9cGFzdGUoIkZpZ3VyZTogQW4gZXhhbXBsZSBHVEYgZmlsZS4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9maWd1cmVzL2d0ZkZpbGUucG5nIikKYGBgCgogLSBNb3JlIHJlY2VudGx5LCBtYXBwaW5nIG9mIFJOQS1zZXEgZGF0YSBvY2N1cnMgbW9yZSBvZnRlbiBhZ2FpbnN0IGEgKipyZWZlcmVuY2UgdHJhbnNjcmlwdG9tZSoqLCB3aGljaCBpcyBhIHJlZmVyZW5jZSBmaWxlIGNvbnRhaW5pbmcgdGhlIHNlcXVlbmNlcyBhbGwga25vd24gaXNvZm9ybXMgb2YgYSBwYXJ0aWN1bGFyIHNwZWNpZXMsIGUuZy4sIHVzaW5nIFtrYWxsaXN0b10oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9uYnQuMzUxOSkgb3IgW1NhbG1vbl0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9ubWV0aC40MTk3KS4KIC0gVGhlIHNldCBvZiBzcGxpY2VkIHRyYW5zY3JpcHRzIGlzIG11Y2ggc21hbGxlciB0aGFuIHRoZSBlbnRpcmUgZ2Vub21lLCBhbmQgdGhlcmVmb3JlIG1hcHBpbmcgYWdhaW5zdCBhIHJlZmVyZW5jZSB0cmFuc2NyaXB0b21lIGlzIHR5cGljYWxseSAqKmZhc3QgYW5kIG1lbW9yeSBlZmZpY2llbnQqKi4KIC0gSG93ZXZlciwgW2l0IGhhcyBiZWVuIG5vdGVkXShodHRwczovL3d3dy5iaW9yeGl2Lm9yZy9jb250ZW50LzEwLjExMDEvMjAyMS4wNS4wNS40NDI3NTV2MSkgdGhhdCBtYXBwaW5nIGFnYWluc3QgYSByZWZlcmVuY2UgdHJhbnNjcmlwdG9tZSBtYXkgYWxzbyBpbnRyb2R1Y2Ugc3B1cmlvdXMgZXhwcmVzc2lvbiBmb3IgZ2VuZXMgdGhhdCBhcmUgbm90IGV4cHJlc3NlZC4gVGhlc2Ugb2JzZXJ2YXRpb25zIGNhbiBiZSBleHBsYWluZWQgYnkgKippbnRyb25pYyByZWFkcyoqIHRoYXQgc2hhcmUgc29tZSBzZXF1ZW5jZSBzaW1pbGFyaXR5IHdpdGggdHJhbnNjcmlwdHMsIGFuZCBjb3VsZCBtYXAgdG8gc3BsaWNlZCB0cmFuc2NyaXB0IHNlcXVlbmNlcy4gUmVjZW50IG1ldGhvZHMsIHN1Y2ggYXMgW2FsZXZpbi1mcnldKGh0dHBzOi8vd3d3LmJpb3J4aXYub3JnL2NvbnRlbnQvMTAuMTEwMS8yMDIxLjA2LjI5LjQ1MDM3N3YxKSwgYXZvaWQgdGhpcyBieSBleHBhbmRpbmcgdGhlIHJlZmVyZW5jZSB0cmFuc2NyaXB0b21lIHRvIGFsc28gaW5jbHVkZSBpbnRyb25pYyBzZXF1ZW5jZXMuCgojIyMgQWxpZ25tZW50LWJhc2VkIHdvcmtmbG93cwoKIC0gVHJhZGl0aW9uYWxseSwgYWxpZ25tZW50LWJhc2VkIHdvcmtmbG93cyBoYXZlIGJlZW4gdXNlZCB0byBtYXAgcmVhZHMsIHdoZXJlIG9uZSB0cmllcyB0byAqKmZpbmQgdGhlIGV4YWN0IGNvb3JkaW5hdGVzIGEgcmVhZCBtYXBzIHRvKiogb24gdGhlIHJlZmVyZW5jZSBnZW5vbWUgb3IgdGhlIHJlZmVyZW5jZSB0cmFuc2NyaXB0b21lLgogLSBOb3RlIHRoYXQgZHVlIHRvIGFsdGVybmF0aXZlIHNwbGljaW5nLCByZWFkcyBkbyBub3QgbmVjZXNzYXJpbHkgbWFwIGNvbnRpZ3VvdXNseSBvbiBhIHJlZmVyZW5jZSBnZW5vbWUsIGFzIGEgcmVhZCBjYW4gb3ZlcmxhcCB3aXRoIGEgc3BsaWNpbmcganVuY3Rpb24sIHdoZXJlIGFuIGludHJvbiBoYXMgYmVlbiBleGNpc2VkLiBXaGVuIG1hcHBpbmcgYWdhaW5zdCBhIHRyYW5zY3JpcHRvbWUsIGhvd2V2ZXIsIHJlYWRzIHNob3VsZCBiZSBtYXBwaW5nIGNvbnRpZ3VvdXNseS4KICAtIEEgbWFpbiBjaGFsbGVuZ2UgaW4gc3BsaWNlZCBhbGlnbm1lbnQgYWdhaW5zdCBhIHJlZmVyZW5jZSBnZW5vbWUgaXMgdGhlIHByb3BlciBhbGlnbm1lbnQgb2YgcmVhZHMgdGhhdCBzcGFuIGEgc3BsaWNlIGp1bmN0aW9uLCBlc3BlY2lhbGx5IHdoZW4gdGhlc2UganVuY3Rpb25zIGFyZSBub3QgYW5ub3RhdGVkIGEgcHJpb3JpLiBJbmRlZWQsIGluIHNwbGljZWQgYWxpZ25tZW50IHJlYWRzIGNhbiBiZSBzcGxpdCBhdCBhbnkgbnVjbGVvdGlkZSwgYW5kIHRoZSBjb3JyZXNwb25kaW5nIHN1YnNlcXVlbmNlcyBjYW4gbWFwIHNldmVyYWwgdGhvdXNhbmRzIG9mIGJhc2VwYWlycyBhcGFydC4gTWVhbndoaWxlLCB0aGUgbWFpbiBjaGFsbGVuZ2UgaW4gdW5zcGxpY2VkIGFsaWdubWVudCB0byBhIHRyYW5zY3JpcHRvbWUgaXMgdGhlIHJlZHVuZGFudCBzZXF1ZW5jZSBhbW9uZyByZWxhdGVkIHRyYW5zY3JpcHRzIGluIHRoZSB0cmFuc2NyaXB0b21lLCB3aGljaCBvZnRlbiBsZWFkcyB0byBhIGhpZ2ggbXVsdGktbWFwcGluZyByYXRlIChpLmUuLCByZWFkcyB0aGF0IGNhbm5vdCBiZSB1bmFtYmlndW91c2x5IGFzc2lnbmVkIHRvIGEgc2luZ2xlIHRyYW5zY3JpcHQpLgogLSBTcGxpY2VkIGFsaWdubWVudCBhZ2FpbnN0IGEgZ2Vub21lIGlzIHRoZXJlZm9yZSBjb21wdXRhdGlvbmFsbHkgYSBtdWNoIGhhcmRlciB0YXNrLiBTaW5jZSB0aGUgdHJhbnNjcmlwdCBzZXF1ZW5jZXMgYXJlIGFscmVhZHkgc3BsaWNlZCB3aGVuIGFsaWduaW5nIHRvIGEgcmVmZXJlbmNlIHRyYW5zY3JpcHRvbWUsIHJlYWRzIHNob3VsZCBhbGlnbiBjb250aWd1b3VzbHksIGFuZCBtYW55IG9mIHRoZSBjb21wdXRhdGlvbmFsbHkgZXhwZW5zaXZlIHN0ZXBzIGFuZCBoZXVyaXN0aWNzIGNhbiBiZSBhdm9pZGVkLCB0aGVyZS4KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IFVuc3BsaWNlZCBhbmQgc3BsaWNlZCBhbGlnbm1lbnQuIEZpZ3VyZSBmcm9tIFZhbiBkZW4gQmVyZ2UgZXQgYWwuICgyMDE5KS4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9maWd1cmVzL3NwbGljZWRBbGlnbm1lbnQucG5nIikKYGBgCgojIyMgQWxpZ25tZW50LWZyZWUgd29ya2Zsb3dzCgogLSBNb2Rlcm4gYXBwcm9hY2hlcyAqKmF2b2lkIG1hcHBpbmcgZWFjaCBmcmFnbWVudCBpbmRpdmlkdWFsbHkqKiAoaS5lLiwgZG8gbm90IGF0dGVtcHQgdG8gZmluZCB0aGUgZXhhY3QgY29vcmRpbmF0ZXMgb2YgYSByZWFkJ3Mgb3JpZ2luKSwgYW5kIGluc3RlYWQgcG9zaXQgYSBwcm9iYWJpbGlzdGljIG1vZGVsIHdoZXJlICoqdHJhbnNjcmlwdCBhYnVuZGFuY2VzIGFyZSB0eXBpY2FsbHkgZGVmaW5lZCB1c2luZyBpdHMgY29uc3RpdHVlbnQgJGskLW1lcnMqKi4gVGhlc2UgbWV0aG9kcyBhcmUgc29tZXRpbWVzIHJlZmVycmVkIHRvIGFzICpsaWdodHdlaWdodCouCiAtIEEgJGskLW1lciBpcyBhIHNob3J0IHNlcXVlbmNlIG9mIG51Y2xlb3RpZGVzIG9mIGxlbmd0aCAkayQuIFRoZSBzcGFjZSBvZiBwb3NzaWJsZSAkayQtbWVycyBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgdHJhbnNjcmlwdHMgY2FuIGJlIHByZWNvbXB1dGVkIGluIGFkdmFuY2UgdXNpbmcgdGhlIHJlZmVyZW5jZSB0cmFuc2NyaXB0b21lLCBwcm92aWRpbmcgYSBjb21wdXRhdGlvbmFsIGFkdmFudGFnZSBhcyBpdCBvbmx5IG5lZWRzIHRvIGJlIGNvbXB1dGVkIG9uY2UuCiAtIEZvciBlYWNoIGZyYWdtZW50LCB0aGUgdHJhbnNjcmlwdHMgaXRzICRrJC1tZXJzIGFyZSBjb21wYXRpYmxlIHdpdGggaXMgc2VhcmNoZWQgZm9yIHVzaW5nIGFuIGluZGV4ZWQgKGVmZmljaWVudGx5IHNlYXJjaGFibGUpIHRyYW5zY3JpcHRvbWUuIFRoZSBzZXQgb2YgY29tcGF0aWJsZSB0cmFuc2NyaXB0cyBpcyBjYWxsZWQgdGhlICckayQtY29tcGF0aWJpbGl0eSBjbGFzcycsICdlcXVpdmFsZW5jZSBjbGFzcycgb3IgJ3RyYW5zY3JpcHQgY29tcGF0aWJpbGl0eSBjbGFzcycgb2YgdGhlIGZyYWdtZW50LgogCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IE92ZXJ2aWV3IG9mIGthbGxpc3RvLCBpbWFnZSBmcm9tIEJyYXkgZXQgYWwuICgyMDE2KS4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9maWd1cmVzL2thbGxpc3RvX2VxdWl2YWxlbmNlQ2xhc3Nlcy5wbmciKQppbmNsdWRlX2dyYXBoaWNzKCIuL2ZpZ3VyZXMva2FsbGlzdG9fZXF1aXZhbGVuY2VDbGFzc2VzX2NhcHRpb24ucG5nIikKYGBgCiAKIyMgQWJ1bmRhbmNlIHF1YW50aWZpY2F0aW9uCgpHaXZlbiBhIHNldCBvZiBtYXBwaW5ncywgdXNpbmcgZWl0aGVyIGFsaWdubWVudC1iYXNlZCBvciBhbGlnbm1lbnQtZnJlZSB3b3JrZmxvd3MsIHRoZSBlc3RpbWF0aW9uIG9mIGV4cHJlc3Npb24gb2YgYSBnZW5lL3RyYW5zY3JpcHQvZXhvbiBtYXkgb2NjdXIgaW4gc2V2ZXJhbCB3YXlzLgoKKipDb3VudGluZyoqOgoKIC0gSW4gYWxpZ25tZW50LWJhc2VkIHdvcmtmbG93cywgb25lIGNvdWxkIGRvIGEgZGlyZWN0IGNvdW50aW5nIG9mIGZyYWdtZW50cyBhdCwgZm9yIGluc3RhbmNlLCB0aGUgZ2VuZSBsZXZlbCwgY291bnRpbmcgdGhlIG51bWJlciBmcmFnbWVudHMgbWFwcGluZyB0byBlYWNoIGdlbmUuIFRoaXMgaGFzIGJlZW4gdGhlIGRvbWluYW50IGFwcHJvYWNoIGZvciB0aGUgZmlyc3QgZGVjYWRlIG9mIFJOQS1zZXEgZGF0YSwgb2Z0ZW4gb2J0YWluZWQgdXNpbmcgcmVmZXJlbmNlIGdlbm9tZSBhbGlnbm1lbnRzLiAKIC0gTWFueSBoZXVyaXN0aWMgY2hvaWNlcyBuZWVkIHRvIGJlIG1hZGU6IERvIHdlIGNvdW50IGEgZnJhZ21lbnQgYXMgc29vbiBhcyBpdCBpbnRlcnNlY3RzIHdpdGggdGhlIGdlbmUncyBjb29yZGluYXRlcywgb3IgZG8gd2UgcmVxdWlyZSB0aGUgZnVsbCBmcmFnbWVudCB0byBtYXAgdG8gdGhlIGdlbmU/IERvIHdlIGNvdW50IGludHJvbmljIHJlYWRzPyBEbyB3ZSBjb3VudCBtdWx0aS1tYXBwaW5nIHJlYWRzPwogCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IEdlbmUtIGFuZCBleG9uLWxldmVsIHJlYWQgY291bnRpbmcuIEltYWdlIGFkYXB0ZWQgZnJvbSBDaGFybG90dGUgU29uZXNvbi4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9maWd1cmVzL3JlYWRDb3VudGluZy5wbmciKQpgYGAKIAoqKkVzdGltYXRpb24qKjogCiAKIC0gQWJ1bmRhbmNlIHF1YW50aWZpY2F0aW9uIGlzIG1vcmUgcmVjZW50bHkgc3RhcnRpbmcgdG8gc2hpZnQgZnJvbSBjb3VudGluZyB0b3dhcmRzIHVzaW5nIHN0YXRpc3RpY2FsIG1vZGVscyB0byBlc3RpbWF0ZSB0aGUgZXhwcmVzc2lvbiBjb3VudHMgZm9yIGEgZmVhdHVyZSwgd2hpY2ggaW4gdGhpcyBjYXNlIGlzIHR5cGljYWxseSBhIHRyYW5zY3JpcHQuIAogLSBUaGlzIGFwcHJvYWNoIGlzIGFtZW5hYmxlIHRvIGFsaWdubWVudC1mcmVlIHdvcmtmbG93cywgc2luY2UgdGhlIG51bWJlciBvZiBmcmFnbWVudHMgaW4gZWFjaCBlcXVpdmFsZW5jZSBjbGFzcyBhcmUgc3VmZmljaWVudCBzdGF0aXN0aWNzIGZvciB0aGUgYWJ1bmRhbmNlIHF1YW50aWZpY2F0aW9uLCBtZWFuaW5nIHRoYXQgdGhleSBjb250YWluIGFsbCBpbmZvcm1hdGlvbiBuZWVkZWQgdG8gZXN0aW1hdGUgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIHN0YXRpc3RpY2FsIG1vZGVsLCBhbmQgaGVuY2UgdGhlIGZlYXR1cmUtbGV2ZWwgYWJ1bmRhbmNlcy4gU2luY2UgdGhlIGV4cHJlc3Npb24gY291bnRzIGluIHRoaXMgY2FzZSBhcmUgZXN0aW1hdGVkLCB0aGV5IGFyZSBub3QgbmVjZXNzYXJpbHkgaW50ZWdlciBjb3VudHMsIGFuZCB3aWxsIGJlIHJlZmVycmVkIHRvIGFzICdlc3RpbWF0ZWQgY291bnRzJy4gCiAtIEluIG9yZGVyIHRvIGRlcml2ZSB0aGVzZSwgdGhlIEVNLWFsZ29yaXRobSAoW0RlbXBzdGVyICpldCBhbC4qICgxOTc3KV0oaHR0cHM6Ly93d3cuanN0b3Iub3JnL3N0YWJsZS8yOTg0ODc1KSkgaXMgb2Z0ZW4gdXNlZCwgYWx0aG91Z2ggb3RoZXIgYXBwcm9hY2hlcyBoYXZlIGJlZW4gdXNlZCBieSB0b29scyBsaWtlIFNhbG1vbi4gQSBiaWcgYWR2YW50YWdlIG9mIHRoZSBlc3RpbWF0aW9uIGFwcHJvYWNoIGlzIHRoYXQgaXQgKipwcm9iYWJpbGlzdGljYWxseSBhc3NpZ25zIGZyYWdtZW50cyB0byB0cmFuc2NyaXB0cywgdGhlcmVieSBhdXRvbWF0aWNhbGx5IGRlYWxpbmcgd2l0aCBtdWx0aS1tYXBwaW5nIHJlYWRzKiouIFRoZSB0b3RhbCBudW1iZXIgb2YgZnJhZ21lbnRzIG1hcHBpbmcgdG8gZWFjaCB0cmFuc2NyaXB0IGlzIHRoZW4gdGhlIHN1bSBvZiBhbGwgZnJhZ21lbnQtbGV2ZWwgcHJvYmFiaWxpdGllcyB0byBiZSBhc3NpZ25lZCB0byB0aGF0IHJlc3BlY3RpdmUgdHJhbnNjcmlwdC4KIApgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmNhcD1wYXN0ZSgiRmlndXJlOiBBYnVuZGFuY2UgcXVhbnRpZmljYXRpb24gdXNpbmcgdGhlIEVNIGFsZ29yaXRobS4gRmlndXJlIGZyb20gVmFuIGRlbiBCZXJnZSBldCBhbC4gKDIwMTkpLiIpfQppbmNsdWRlX2dyYXBoaWNzKCIuL2ZpZ3VyZXMvYWJ1bmRhbmNlRU1BbGdvcml0aG0ucG5nIikKYGBgCgojIyMgVGhlIGZpbmFsIGNvdW50ZG93bgoKT25jZSBhYnVuZGFuY2VzIGhhdmUgYmVlbiBxdWFudGlmaWVkLCB0aGUgKGVzdGltYXRlZCkgY291bnRzIGFyZSB0eXBpY2FsbHkgc3RvcmVkIGluIGEgY291bnQgbWF0cml4LCB3aXRoIGdlbmVzIHNwYW5uaW5nIHRoZSByb3dzIGFuZCBzYW1wbGVzIHNwYW5uaW5nIHRoZSBjb2x1bW5zLiBUaGlzIGNvdW50IG1hdHJpeCBmb3JtcyB0aGUgYmFzaXMgb2YgbW9zdCBkb3duc3RyZWFtIGFuYWx5c2VzIHRvIGludGVycHJldCBSTkEtc2VxIGRhdGEsIGFuZCBpdCB3aWxsIGJlIHRoZSBtYWluIG9iamVjdCB3ZSB3aWxsIGJlIHdvcmtpbmcgd2l0aCBpbiB0aGUgZm9sbG93aW5nIGxlY3R1cmVzLgoKCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuY2FwPXBhc3RlKCJGaWd1cmU6IEFuIHVwZGF0ZWQgc2VxdWVuY2luZyB3b3JrZmxvdy4gSW1hZ2UgYWRhcHRlZCBmcm9tIFZhbiBkZW4gQmVyZ2UgZXQgYWwuICgyMDE5KS4iKX0KaW5jbHVkZV9ncmFwaGljcygiLi9maWd1cmVzL3NlcVdvcmtmbG93My5wbmciKQpgYGAK