Objectives:

  • Overview of reproducible research & analysis setup
  • Broad introduction to DESeq2 & why it is widely used for differential expression comparisons
  • How to import and review gene count table

1 Differential Expression Workflow

Today we will proceed through key steps in a differential expression analysis, starting from a count table that’s similar to what you generated in the first half of the workshop and similar to the one of the outputs included in the data that the Advanced Genomics Core delivers for RNA-seq libraries.

2 Reproducible Research

Today we’ll be exploring some RNA-seq data that is fairly representative of what we see in the core and start with input files similar to the count table you generated in the previous steps and similar to one of the outputs currently being delivered by the Advanced Sequencing Core.

2.0.0.1 [Warm-Up]

To get started, let’s get a sense of what approaches you already use to compare gene expression:

  • If you’ve run a qPCR assay and enjoyed all the pipetting, put up a green ‘check’. If you’ve run a qPCR assay and needed some time away from the multichannels, put up a red ‘x’ from the reaction panel.
  • If cloning a gene reporter construct (ie: promoter + GFP), worked for you the first time, put up a green check. If you have a freezer box full of cloning attempts, put up a red ‘x’.
  • If you are ready to learn about bioinformatic tools for comparing gene expression, put up a green check. If you have some questions that should be addressed before we get started, use the ‘raise hand’ reaction.

2.1 Logging into the RStudio server

First navigate to server address bfx-workshop01.med.umich.edu, using a web browser. You may see a sign-in prompt screen, similar to shown below:



Next, use your unique name and the same password used yesterday to log-in to the server from the command line. You should now see some familiar RStudio panels in your web browser window:



2.2 Creating our code file

First, we’ll create a new code file, using the toolbar at the top of our window and clicking the icon that looks like a white square with a small green plus symbol.

From the drop down menu, select the first option named ‘R Script’.

A new window should pop up in your console.

Checkpoint: Please use the red ‘x’ button in your zoom reaction panel if you would like these steps repeated and the green ‘check’ if you see a new pane with a code file named Untitled1

2.3 Best practices for file organization

As widely discussed including in a Nobel, 2009 review, file organization and data stewardship are an important parts of reproducible research.

To follow best practices for file organization for bioinformatics/computational projects, we will need to make sure there are separate locations for:

  • Raw data
  • Code
  • Output files

Such as illustrated in this figure from the Noble review:

To organize our files for our analysis today, we’ll first navigate into the RSD_R directory.

We can see that there is only one folder, data:



However, if we check our working directory, what do we see?

getwd()

Since we aren’t working in RSD_R we will need to set our working directory before creating any new directories.

setwd("~/RSD_R")

Before moving forward, let’s double check that we’re in the right place.

getwd()

After we’ve set our working directory, we’ll use the blue floppy disc icon save our ‘Untitled1’ file as “DE_Analysis.R” in the RSD_R directory.

This new “DE_Analysis.R” will serve as a record of the analysis steps we follow for the remainder of the workshop.

Then we’ll create a new directory called outputs to use later in our code.

dir.create("./DE_outputs")
## Warning in dir.create("./DE_outputs"): './DE_outputs' already exists

Checkpoint: Please use the green ‘check’ if you have saved your code file and see both the data and outputs directories your RSD_R folder and the red ‘x’ if you do not.

2.3.0.1 Code execution shortcut reminder

Ctrl-Enter is a standard shortcut in Rstudio to send the current line (or selected lines) to the console. If you see an >, then R has executed the command. If you see a +, this means that the command is not complete and R is waiting (usually for a )).

Click for review of R conventions for object names

R has some restrictions for naming objects:

  • Cannot start with numbers
    • Cannot include dashes
    • Cannot have spaces
    • Should not be identical to a named function
    • Dots & underscores will work but are better to avoid

2.4 Check package installations

Several packages have already been installed on the server, so we can load them into our R session now. To do that we’ll use the library function to load the required packages.

library(DESeq2)
library(ggplot2)
library(tidyr)
library(dplyr)
library(matrixStats)
library(ggrepel)
library(pheatmap)
library(RColorBrewer)
library(data.table)

Note: We expect to see some red messages in your console while these packages are loading

R/RStudio has great resources for getting help, including code ‘cheatsheets’ and package vignettes, like for tidyr.

Since we loaded the libraries into our R session, we can see documentation out using the ? operator.

?`DESeq2-package`

Checkpoint: If you see the R documentation for DESeq2 pop up in your ‘help’ panel on the right, please indicate with the green ‘check’ button. If not please use the red ‘x’ button.


3 Tools for Differential Gene Expression analysis

As discussed during the webinar, a common application for bulk RNA-seq is to test for differential expression between conditions or treatments, using statistical approaches that are appropriate for biological data.

While there are several tools that can be used for differential expression comparisons, we will use DESeq2 in our analysis today.

DESeq2 is one of two tools, along with EdgeR, considered ‘best practice’ for differential expression. Both tools apply similar methods that account for the distributions we expect to see for RNA-seq and are fairly stringent in calling differentially expressed genes, lowering the risk of investigating genes that were really false positives (e.g. don’t really have different expression between treatment groups and therefore are not relevant to the biological process).

Additionally, DESeq2 also has an excellent vignette click link to open from Love, Anders, and Huber, from which our workflow is partially adapted, and is a good resource when analyzing your own data (see also: Love, Anders, and Huber. Genome Biology. 2014.).

Click for additional resources regarding statistical testing and tool comparison for RNA-seq data To learn more about statistical testing and what distributions best model the behavior of RNA-seq data, a good resource is this EdX lecture by Rafael Irizarry or this lecture by Kasper Hansen. Another helpful guide is this Comparative Study for Differential Expression Analysis by Zhang et al. from 2014.

3.1 DESeq2 assumptions and requirements

A key assumption of DESeq2 is that for most experiments biological variance is much greater than technical variance (especially if best practices for quality RNA isolation are followed, including DNase treatment!).

Since calculating variance is key to the statistical approach used for DESeq2, if we tried to compare two treatment groups with less than two replicates, we would get an error (as shown in this blog post). Without replicates, there can’t be statistical significance (e.g. p-values), but qualitative approaches are an option, like looking at the top expressed genes after normalization.

3.1.1 Replicates in RNA-seq experiments

A frequent question for RNA-seq projects is “How many replicates do I need?”.

The general goal of our analyses is to separate the “interesting” biological contributions from the “uninteresting” technical or other contributions that either cannot be or were not controlled in the experimental design. The more sources of variation, such as samples coming from heterogenous tissues or experiments with incomplete knockdowns, the more replicates (>3) are recommended.

Image of technical, biological, and experimental contributors to gene expression, from HBC training materials

For a more in depth discussion of experimental design considerations, particularly for the number of replicates, please read A Beginner’s Guide to Analysis of RNA Sequencing Data and papers like this one by Hart et al that focus on estimating statistical power for RNA-seq experiments.

3.1.1.1 Sequencing depth recommendations

A related experimental design consideration is how much sequencing depth should be generated per sample. This figure shared by Illumina in their technical talks is helpful to understand the relative importance of replicates versus sequencing depth.

Illumina’s differential expression recovery across replicate number and sequencing depth

Generally, for the human and mouse genomes, the recommendation is 30-40 million reads per sample for polyA library preps to capture both highly expressed (abundant) and more lowly expressed (rarer) transcripts, assuming that ~25,000 protein-coding genes would be measured. However, as the image above shows, sequencing depth has less of an impact than number of replicates in detecting differentially expressed genes (DEGs).

3.1.1.2 [Exercise]: Building a better understanding of differential expression analysis

  1. Post a comment below regarding what key question/misconception regarding designing an RNA-seq experiment we were able to address OR
  2. Post a question that that was NOT addressed but that you hope we will address in the later modules OR
  3. Add a thumbs up to your favorite comment(s) to upvote it

3.1.2 Raw data as input

Another key assumption for DESeq2 is that the analysis will start with un-normalized counts.

To begin our analysis, we’ll read in the raw count data file, gene_expected_count_trimmed.txt which is similar to what would be generated in the alignment steps yesterday (and what you could receive from AGC). We’ll discuss later a few normalizations that can be helpful for us to understand how much a gene is expressed within or between samples, but normalized data should not be used as an input for DESeq2.

CountTable <- read.table("data/gene_expected_count_trimmed.txt", header = TRUE, row.names = 1)
head(CountTable, n=2) # look at the top of the table
##                    Sample_116498 Sample_116499 Sample_116500 Sample_116501 Sample_116502
## ENSMUSG00000000001          8256          6680          7532          5122          6684
## ENSMUSG00000000003             0             0             0             0             0
##                    Sample_116503 Sample_116504 Sample_116505 Sample_116506 Sample_116507
## ENSMUSG00000000001          8047          6446          5559          5443          5906
## ENSMUSG00000000003             0             0             0             0             0
##                    Sample_116508 Sample_116509
## ENSMUSG00000000001          5771          4792
## ENSMUSG00000000003             0             0

Now that the file is read into R, note that we’ve created a data frame that includes ‘gene ids’ in ENSEMBL format as rownames and count data from twelve different samples.

3.1.2.1 [Exercise]: RSEM outputs versus DESeq2 input requirements

If we think back to the RSEM outputs, the ‘expected_counts’ table may include fractions due to how the alignment tool resolves reads that map to multiple locuses). Since DESeq2 requires whole numbers, if we try to use the RSEM ouputs directly, DESeq2 will give us an error.

First let’s check the count table in a different way, to see if our table includes fractions.

tail(CountTable, n=2)
##                    Sample_116498 Sample_116499 Sample_116500 Sample_116501 Sample_116502
## ENSMUSG00000118577        752.33        613.24        417.04        412.63        429.74
## ENSMUSG00000118578         34.49         20.58         12.10         14.88         14.05
##                    Sample_116503 Sample_116504 Sample_116505 Sample_116506 Sample_116507
## ENSMUSG00000118577        553.50        479.16        825.36        520.06        383.61
## ENSMUSG00000118578         34.62         18.57         14.01         11.14          4.69
##                    Sample_116508 Sample_116509
## ENSMUSG00000118577        404.31        353.35
## ENSMUSG00000118578         11.81          7.74

[Question]: To resolve this discrepancy between the RSEM outputs and expected input for DESeq2, what could we do?

To round down all the columns of our CountTable that include count data (all columns since we set the gene names to be our row names), we can use the round()` function.

CountTable <- round(CountTable)
tail(CountTable, n=2) # now whole numbers
##                    Sample_116498 Sample_116499 Sample_116500 Sample_116501 Sample_116502
## ENSMUSG00000118577           752           613           417           413           430
## ENSMUSG00000118578            34            21            12            15            14
##                    Sample_116503 Sample_116504 Sample_116505 Sample_116506 Sample_116507
## ENSMUSG00000118577           554           479           825           520           384
## ENSMUSG00000118578            35            19            14            11             5
##                    Sample_116508 Sample_116509
## ENSMUSG00000118577           404           353
## ENSMUSG00000118578            12             8

An important note is that there are several bonus content sections on the instruction pages, like the two below that we will not be covering in this workshop, but that may have useful context or be helpful when you review this material.

Click for alternative DESeq2 input options for RSEM outputs

The package tximport is another optionrecommended the DESeq2 authors to read in the RSEM expected_counts, as this package allows for the average transcript length per gene to be used in the DE analysis and, as described by the author, the tximport-to-DESeqDataSet constructor function round the non-integer data generated by RSEM to whole numbers.

Click for comparison of RNA-seq data and microarray data

With higher sensitivity, greater flexiblity, and decreasing cost, sequencing has largely replaced microarray assays for measuring gene expression. A key difference between the platforms is that microarrays measure intensities and are therefore continous data while the count data from sequencing is discrete. A more detailed comparison between microarrays and sequencing technologies/analysis is outlined in the online materials for Penn State’s STAT555 course

3.2 Getting help

R/Rstudio has a strong community component so if you are getting an error or wondering how to make a command work or how to perform a specific task, there is likely already a solution out there. Remember that Google is your friend, although it can sometimes be a challenge to figure out what to search for. Key parts of a successful search:

  • Package or command run
  • R or Bioconductor
  • The error message if there is one
  • Version information

How to get session information to aid in a search:

sessionInfo()

Highly recommend using resources like Bioconductor Support, Biostars, and Stack Overflow, including threads on specific packages or common bioinformatic tasks.

I personally use one or more of these resources every day.

10x also has a helpful 10 tips for biologists learning bioinformatics included in their resources.

4 Summary

In this section, we:

  • Set up our compute environment
  • Learned about DESeq2
  • Loaded our raw count tables (input file 1)

Now that we have our count data processed, we can move on to “unblinding” our data, as the sample names are unique identifiers generated by a sequencing center and not very informative as far as our experimental conditions.


5 Sources

5.1 Training resources used to develop materials


These materials have been adapted and extended from materials listed above. These are open access materials distributed under the terms of the Creative Commons Attribution license (CC BY 4.0), which permits unrestricted use, distribution, and reproduction in any medium, provided the original author and source are credited.

LS0tCnRpdGxlOiAiRGF5IDIgLSBNb2R1bGUgMDY6IEFuYWx5c2lzIFNldHVwICYgSW50cm9kdWN0aW9uIHRvIERFU2VxMiIKYXV0aG9yOiAiVU0gQmlvaW5mb3JtYXRpY3MgQ29yZSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgICAgICAgaHRtbF9kb2N1bWVudDoKICAgICAgICAgICAgaW5jbHVkZXM6CiAgICAgICAgICAgICAgICBpbl9oZWFkZXI6IGhlYWRlci5odG1sCiAgICAgICAgICAgIHRoZW1lOiBwYXBlcgogICAgICAgICAgICB0b2M6IHRydWUKICAgICAgICAgICAgdG9jX2RlcHRoOiA0CiAgICAgICAgICAgIHRvY19mbG9hdDogdHJ1ZQogICAgICAgICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgICAgICAgICAgZmlnX2NhcHRpb246IHRydWUKICAgICAgICAgICAgbWFya2Rvd246IEdGTQogICAgICAgICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpib2R5eyAvKiBOb3JtYWwgICovCiAgICAgIGZvbnQtc2l6ZTogMTRwdDsKICB9CnByZSB7CiAgZm9udC1zaXplOiAxMnB0Cn0KY29kZS5yewogIGZvbnQtc2l6ZTogMTJwdDsKfQo8L3N0eWxlPgoKPCEtLS0gQWxsb3cgdGhlIHBhZ2UgdG8gYmUgd2lkZXIgLS0tPgo8c3R5bGU+CiAgICBib2R5IC5tYWluLWNvbnRhaW5lciB7CiAgICAgICAgbWF4LXdpZHRoOiAxMjAwcHg7CiAgICB9Cjwvc3R5bGU+CgoKPiAjIE9iamVjdGl2ZXM6ICAgIAo+ICogT3ZlcnZpZXcgb2YgcmVwcm9kdWNpYmxlIHJlc2VhcmNoICYgYW5hbHlzaXMgc2V0dXAKPiAqIEJyb2FkIGludHJvZHVjdGlvbiB0byBERVNlcTIgJiB3aHkgaXQgaXMgd2lkZWx5IHVzZWQgZm9yIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGNvbXBhcmlzb25zCj4gKiBIb3cgdG8gaW1wb3J0IGFuZCByZXZpZXcgZ2VuZSBjb3VudCB0YWJsZQoKCiMgRGlmZmVyZW50aWFsIEV4cHJlc3Npb24gV29ya2Zsb3cKClRvZGF5IHdlIHdpbGwgcHJvY2VlZCB0aHJvdWdoIGtleSBzdGVwcyBpbiBhIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzLCBzdGFydGluZyBmcm9tIGEgY291bnQgdGFibGUgdGhhdCdzIHNpbWlsYXIgdG8gd2hhdCB5b3UgZ2VuZXJhdGVkIGluIHRoZSBmaXJzdCBoYWxmIG9mIHRoZSB3b3Jrc2hvcCBhbmQgc2ltaWxhciB0byB0aGUgb25lIG9mIHRoZSBvdXRwdXRzIGluY2x1ZGVkIGluIHRoZSBbZGF0YSB0aGF0IHRoZSBBZHZhbmNlZCBHZW5vbWljcyBDb3JlIGRlbGl2ZXJzXShodHRwczovL2JyY2YubWVkaWNpbmUudW1pY2guZWR1L2NvcmVzL2FkdmFuY2VkLWdlbm9taWNzL2RhdGEtZGVsaXZlcnkvKSBmb3IgUk5BLXNlcSBsaWJyYXJpZXMuCgohW10oLi9pbWFnZXMvd2F5ZmluZGVyL3dheWZpbmRlci0wNC5wbmcpe3dpZHRoPTk1JX0KCiMgUmVwcm9kdWNpYmxlIFJlc2VhcmNoCgpUb2RheSB3ZSdsbCBiZSBleHBsb3Jpbmcgc29tZSBSTkEtc2VxIGRhdGEgdGhhdCBpcyBmYWlybHkgcmVwcmVzZW50YXRpdmUgb2Ygd2hhdCB3ZSBzZWUgaW4gdGhlIGNvcmUgYW5kIHN0YXJ0IHdpdGggaW5wdXQgZmlsZXMgc2ltaWxhciB0byB0aGUgY291bnQgdGFibGUgeW91IGdlbmVyYXRlZCBpbiB0aGUgcHJldmlvdXMgc3RlcHMgYW5kIHNpbWlsYXIgdG8gb25lIG9mIHRoZSBvdXRwdXRzIGN1cnJlbnRseSBiZWluZyBkZWxpdmVyZWQgYnkgdGhlIEFkdmFuY2VkIFNlcXVlbmNpbmcgQ29yZS4KCiMjIyMgW1dhcm0tVXBdCgpUbyBnZXQgc3RhcnRlZCwgbGV0J3MgZ2V0IGEgc2Vuc2Ugb2Ygd2hhdCBhcHByb2FjaGVzIHlvdSBhbHJlYWR5IHVzZSB0byBjb21wYXJlIGdlbmUgZXhwcmVzc2lvbjogICAgCgoqIElmIHlvdSd2ZSBydW4gYSBxUENSIGFzc2F5IGFuZCBlbmpveWVkIGFsbCB0aGUgcGlwZXR0aW5nLCBwdXQgdXAgYSBncmVlbiAnY2hlY2snLiBJZiB5b3UndmUgcnVuIGEgcVBDUiBhc3NheSBhbmQgbmVlZGVkIHNvbWUgdGltZSBhd2F5IGZyb20gdGhlIG11bHRpY2hhbm5lbHMsIHB1dCB1cCBhIHJlZCAneCcgZnJvbSB0aGUgcmVhY3Rpb24gcGFuZWwuICAgIAoqIElmIGNsb25pbmcgYSBnZW5lIHJlcG9ydGVyIGNvbnN0cnVjdCAoaWU6IHByb21vdGVyICsgR0ZQKSwgd29ya2VkIGZvciB5b3UgdGhlIGZpcnN0IHRpbWUsIHB1dCB1cCBhIGdyZWVuIGNoZWNrLiBJZiB5b3UgaGF2ZSBhIGZyZWV6ZXIgYm94IGZ1bGwgb2YgY2xvbmluZyBhdHRlbXB0cywgcHV0IHVwIGEgcmVkICd4Jy4gICAgCiogSWYgeW91IGFyZSByZWFkeSB0byBsZWFybiBhYm91dCBiaW9pbmZvcm1hdGljIHRvb2xzIGZvciBjb21wYXJpbmcgZ2VuZSBleHByZXNzaW9uLCBwdXQgdXAgYSBncmVlbiBjaGVjay4gSWYgeW91IGhhdmUgc29tZSBxdWVzdGlvbnMgdGhhdCBzaG91bGQgYmUgYWRkcmVzc2VkIGJlZm9yZSB3ZSBnZXQgc3RhcnRlZCwgdXNlIHRoZSAncmFpc2UgaGFuZCcgcmVhY3Rpb24uICAKCgojIyBMb2dnaW5nIGludG8gdGhlIFJTdHVkaW8gc2VydmVyCgpGaXJzdCBuYXZpZ2F0ZSB0byBzZXJ2ZXIgYWRkcmVzcyBgYmZ4LXdvcmtzaG9wMDEubWVkLnVtaWNoLmVkdWAsIHVzaW5nIGEgd2ViIGJyb3dzZXIuIFlvdSBtYXkgc2VlIGEgc2lnbi1pbiBwcm9tcHQgc2NyZWVuLCBzaW1pbGFyIHRvIHNob3duIGJlbG93OgoKPGJyPgohW10oLi9pbWFnZXMvUlN0dWRpb0xvZ0luUHJvbXB0LnBuZyl7d2lkdGg9NTAlfQo8YnI+CgpOZXh0LCB1c2UgeW91ciB1bmlxdWUgbmFtZSBhbmQgdGhlIHNhbWUgcGFzc3dvcmQgdXNlZCB5ZXN0ZXJkYXkgdG8gbG9nLWluIHRvIHRoZSBzZXJ2ZXIgZnJvbSB0aGUgY29tbWFuZCBsaW5lLiBZb3Ugc2hvdWxkIG5vdyBzZWUgc29tZSBmYW1pbGlhciBSU3R1ZGlvIHBhbmVscyBpbiB5b3VyIHdlYiBicm93c2VyIHdpbmRvdzoKCjxicj4KIVtdKC4vaW1hZ2VzL1JTdHVkaW9TZXJ2ZXJXaW5kb3cucG5nKXt3aWR0aD01MCV9Cjxicj4KCiMjIENyZWF0aW5nIG91ciBjb2RlIGZpbGUKCkZpcnN0LCB3ZSdsbCBjcmVhdGUgYSBuZXcgY29kZSBmaWxlLCB1c2luZyB0aGUgdG9vbGJhciBhdCB0aGUgdG9wIG9mIG91ciB3aW5kb3cgYW5kIGNsaWNraW5nIHRoZSBpY29uIHRoYXQgbG9va3MgbGlrZSBhICoqd2hpdGUgc3F1YXJlIHdpdGggYSBzbWFsbCBncmVlbiBwbHVzIHN5bWJvbCoqLgoKRnJvbSB0aGUgZHJvcCBkb3duIG1lbnUsIHNlbGVjdCB0aGUgZmlyc3Qgb3B0aW9uIG5hbWVkICdSIFNjcmlwdCcuCgpBIG5ldyB3aW5kb3cgc2hvdWxkIHBvcCB1cCBpbiB5b3VyIGNvbnNvbGUuIAoKKipDaGVja3BvaW50Kio6ICpQbGVhc2UgdXNlIHRoZSByZWQgJ3gnIGJ1dHRvbiBpbiB5b3VyIHpvb20gcmVhY3Rpb24gcGFuZWwgaWYgeW91IHdvdWxkIGxpa2UgdGhlc2Ugc3RlcHMgcmVwZWF0ZWQgYW5kIHRoZSBncmVlbiAnY2hlY2snIGlmIHlvdSBzZWUgYSBuZXcgcGFuZSB3aXRoIGEgY29kZSBmaWxlIG5hbWVkIGBVbnRpdGxlZDFgKgoKCiMjIEJlc3QgcHJhY3RpY2VzIGZvciBmaWxlIG9yZ2FuaXphdGlvbgoKQXMgd2lkZWx5IGRpc2N1c3NlZCBpbmNsdWRpbmcgaW4gYSBbTm9iZWwsIDIwMDldKGh0dHBzOi8vam91cm5hbHMucGxvcy5vcmcvcGxvc2NvbXBiaW9sL2FydGljbGU/aWQ9MTAuMTM3MS9qb3VybmFsLnBjYmkuMTAwMDQyNCkgcmV2aWV3LCBmaWxlIG9yZ2FuaXphdGlvbiBhbmQgZGF0YSBzdGV3YXJkc2hpcCBhcmUgYW4gaW1wb3J0YW50IHBhcnRzIG9mIHJlcHJvZHVjaWJsZSByZXNlYXJjaC4KClRvIGZvbGxvdyBiZXN0IHByYWN0aWNlcyBmb3IgZmlsZSBvcmdhbml6YXRpb24gZm9yIGJpb2luZm9ybWF0aWNzL2NvbXB1dGF0aW9uYWwgcHJvamVjdHMsIHdlIHdpbGwgbmVlZCB0byBtYWtlIHN1cmUgdGhlcmUgYXJlIHNlcGFyYXRlIGxvY2F0aW9ucyBmb3I6CgoqIFJhdyBkYXRhCiogQ29kZQoqIE91dHB1dCBmaWxlcwoKU3VjaCBhcyBpbGx1c3RyYXRlZCBpbiB0aGlzIGZpZ3VyZSBmcm9tIHRoZSBOb2JsZSByZXZpZXc6CgohW10oLi9pbWFnZXMvTm9ibGUyMDA5X2RhdGFwcm9qZWN0cy5wbmcpe3dpZHRoPTc1JX0KClRvIG9yZ2FuaXplIG91ciBmaWxlcyBmb3Igb3VyIGFuYWx5c2lzIHRvZGF5LCB3ZSdsbCBmaXJzdCBuYXZpZ2F0ZSBpbnRvIHRoZSBgUlNEX1JgIGRpcmVjdG9yeS4KCldlIGNhbiBzZWUgdGhhdCB0aGVyZSBpcyBvbmx5IG9uZSBmb2xkZXIsIGBkYXRhYDoKCjxicj4KIVtdKC4vaW1hZ2VzL1JTRF9SX3NjcmVlbnNob3QucG5nKXt3aWR0aD01MCV9Cjxicj4KCkhvd2V2ZXIsIGlmIHdlIGNoZWNrIG91ciB3b3JraW5nIGRpcmVjdG9yeSwgd2hhdCBkbyB3ZSBzZWU/CmBgYHtyIFNldHVwRGlyZWN0b3JpZXMsIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0KZ2V0d2QoKQpgYGAKClNpbmNlIHdlIGFyZW4ndCB3b3JraW5nIGluIGBSU0RfUmAgd2Ugd2lsbCBuZWVkIHRvIHNldCBvdXIgd29ya2luZyBkaXJlY3RvcnkgYmVmb3JlIGNyZWF0aW5nIGFueSBuZXcgZGlyZWN0b3JpZXMuCmBgYHtyIFNldFdvcmtpbmdEaXIsIGVjaG8gPSBUUlVFLCBldmFsPUZBTFNFfQpzZXR3ZCgifi9SU0RfUiIpCmBgYAoKQmVmb3JlIG1vdmluZyBmb3J3YXJkLCBsZXQncyBkb3VibGUgY2hlY2sgdGhhdCB3ZSdyZSBpbiB0aGUgcmlnaHQgcGxhY2UuCmBgYHtyIENoZWNrRGlyZWN0b3JpZXMsIGV2YWw9RkFMU0V9CmdldHdkKCkKYGBgCgpBZnRlciB3ZSd2ZSBzZXQgb3VyIHdvcmtpbmcgZGlyZWN0b3J5LCB3ZSdsbCB1c2UgdGhlIGJsdWUgZmxvcHB5IGRpc2MgaWNvbiBzYXZlIG91ciAnVW50aXRsZWQxJyBmaWxlIGFzICJERV9BbmFseXNpcy5SIiBpbiB0aGUgYFJTRF9SYCBkaXJlY3RvcnkuCgpUaGlzIG5ldyAiREVfQW5hbHlzaXMuUiIgd2lsbCBzZXJ2ZSBhcyBhIHJlY29yZCBvZiB0aGUgYW5hbHlzaXMgc3RlcHMgd2UgZm9sbG93IGZvciB0aGUgcmVtYWluZGVyIG9mIHRoZSB3b3Jrc2hvcC4KClRoZW4gd2UnbGwgY3JlYXRlIGEgbmV3IGRpcmVjdG9yeSBjYWxsZWQgYG91dHB1dHNgIHRvIHVzZSBsYXRlciBpbiBvdXIgY29kZS4KYGBge3IgQ3JlYXRlT3V0cHV0c30KZGlyLmNyZWF0ZSgiLi9ERV9vdXRwdXRzIikKYGBgCgoKKipDaGVja3BvaW50Kio6ICpQbGVhc2UgdXNlIHRoZSBncmVlbiAnY2hlY2snIGlmIHlvdSBoYXZlIHNhdmVkIHlvdXIgY29kZSBmaWxlIGFuZCBzZWUgYm90aCB0aGUgYGRhdGFgIGFuZCBgb3V0cHV0c2AgZGlyZWN0b3JpZXMgeW91ciBgUlNEX1JgIGZvbGRlciBhbmQgdGhlIHJlZCAneCcgaWYgeW91IGRvIG5vdC4qCgojIyMjIENvZGUgZXhlY3V0aW9uIHNob3J0Y3V0IHJlbWluZGVyCgoqKkN0cmwtRW50ZXIqKiBpcyBhIHN0YW5kYXJkIHNob3J0Y3V0IGluIFJzdHVkaW8gdG8gc2VuZCB0aGUgY3VycmVudCBsaW5lIChvciBzZWxlY3RlZCBsaW5lcykgdG8gdGhlIGNvbnNvbGUuIElmIHlvdSBzZWUgYW4gYD5gLCB0aGVuIFIgaGFzIGV4ZWN1dGVkIHRoZSBjb21tYW5kLiBJZiB5b3Ugc2VlIGEgYCtgLCB0aGlzIG1lYW5zIHRoYXQgdGhlIGNvbW1hbmQgaXMgbm90IGNvbXBsZXRlIGFuZCBSIGlzIHdhaXRpbmcgKHVzdWFsbHkgZm9yIGEgYClgKS4KCjxkZXRhaWxzPgogICAgPHN1bW1hcnk+KkNsaWNrIGZvciByZXZpZXcgb2YgUiBjb252ZW50aW9ucyBmb3Igb2JqZWN0IG5hbWVzKjwvc3VtbWFyeT4KICAgIFIgaGFzIHNvbWUgcmVzdHJpY3Rpb25zIGZvciBuYW1pbmcgb2JqZWN0czoKICAgIAogICAgKiBDYW5ub3Qgc3RhcnQgd2l0aCBudW1iZXJzCiAgICAqIENhbm5vdCBpbmNsdWRlIGRhc2hlcwogICAgKiBDYW5ub3QgaGF2ZSBzcGFjZXMKICAgICogU2hvdWxkIG5vdCBiZSBpZGVudGljYWwgdG8gYSBuYW1lZCBmdW5jdGlvbgogICAgKiBEb3RzICYgdW5kZXJzY29yZXMgd2lsbCB3b3JrIGJ1dCBhcmUgYmV0dGVyIHRvIGF2b2lkCjwvZGV0YWlscz4KCi0tLQoKIyMgQ2hlY2sgcGFja2FnZSBpbnN0YWxsYXRpb25zCgpTZXZlcmFsICBwYWNrYWdlcyBoYXZlIGFscmVhZHkgYmVlbiBpbnN0YWxsZWQgb24gdGhlIHNlcnZlciwgc28gd2UgY2FuIGxvYWQgdGhlbSBpbnRvIG91ciBSIHNlc3Npb24gbm93LiBUbyBkbyB0aGF0IHdlJ2xsIHVzZSB0aGUgYGxpYnJhcnlgIGZ1bmN0aW9uIHRvIGxvYWQgdGhlIHJlcXVpcmVkIHBhY2thZ2VzLgoKYGBge3IgTW9kdWxlcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz0gRkFMU0UsIGV2YWw9VFJVRX0KbGlicmFyeShERVNlcTIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKbGlicmFyeShtYXRyaXhTdGF0cykKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShkYXRhLnRhYmxlKQpgYGAKCgoqTm90ZTogV2UgZXhwZWN0IHRvIHNlZSBzb21lIHJlZCBtZXNzYWdlcyBpbiB5b3VyIGNvbnNvbGUgd2hpbGUgdGhlc2UgcGFja2FnZXMgYXJlIGxvYWRpbmcqCgpSL1JTdHVkaW8gaGFzIGdyZWF0IHJlc291cmNlcyBmb3IgZ2V0dGluZyBoZWxwLCBpbmNsdWRpbmcgW2NvZGUgJ2NoZWF0c2hlZXRzJ10oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTYvMTAvci1jaGVhdC1zaGVldC0zLnBkZikgYW5kIHBhY2thZ2UgdmlnbmV0dGVzLCBsaWtlIGZvciBbdGlkeXJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy90aWR5ci92aWduZXR0ZXMvdGlkeS1kYXRhLmh0bWwpLgoKU2luY2Ugd2UgbG9hZGVkIHRoZSBsaWJyYXJpZXMgaW50byBvdXIgUiBzZXNzaW9uLCB3ZSBjYW4gc2VlIGRvY3VtZW50YXRpb24gb3V0IHVzaW5nIHRoZSBgP2Agb3BlcmF0b3IuCmBgYHtyIENoZWNrRG9jdW1lbnRhaW9ufQo/YERFU2VxMi1wYWNrYWdlYApgYGAKCioqQ2hlY2twb2ludCoqOiAqSWYgeW91IHNlZSB0aGUgUiBkb2N1bWVudGF0aW9uIGZvciBgREVTZXEyYCBwb3AgdXAgaW4geW91ciAnaGVscCcgcGFuZWwgb24gdGhlIHJpZ2h0LCBwbGVhc2UgaW5kaWNhdGUgd2l0aCB0aGUgZ3JlZW4gJ2NoZWNrJyBidXR0b24uIElmIG5vdCBwbGVhc2UgdXNlIHRoZSByZWQgJ3gnIGJ1dHRvbi4qCgotLS0tCgojIFRvb2xzIGZvciBEaWZmZXJlbnRpYWwgR2VuZSBFeHByZXNzaW9uIGFuYWx5c2lzCgpBcyBkaXNjdXNzZWQgZHVyaW5nIHRoZSB3ZWJpbmFyLCBhIGNvbW1vbiBhcHBsaWNhdGlvbiBmb3IgYnVsayBSTkEtc2VxIGlzIHRvIHRlc3QgZm9yIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGJldHdlZW4gY29uZGl0aW9ucyBvciB0cmVhdG1lbnRzLCB1c2luZyBzdGF0aXN0aWNhbCBhcHByb2FjaGVzIHRoYXQgYXJlIGFwcHJvcHJpYXRlIGZvciBiaW9sb2dpY2FsIGRhdGEuCgpXaGlsZSB0aGVyZSBhcmUgc2V2ZXJhbCB0b29scyB0aGF0IGNhbiBiZSB1c2VkIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBjb21wYXJpc29ucywgd2Ugd2lsbCB1c2UgW0RFU2VxMl0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL0RFU2VxMi5odG1sKSBpbiBvdXIgYW5hbHlzaXMgdG9kYXkuCgpERVNlcTIgaXMgb25lIG9mIHR3byB0b29scywgYWxvbmcgd2l0aCBbRWRnZVJdKGh0dHBzOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9lZGdlUi5odG1sKSwgY29uc2lkZXJlZCBbJ2Jlc3QgcHJhY3RpY2UnXShodHRwczovL2JtY2Jpb2luZm9ybWF0aWNzLmJpb21lZGNlbnRyYWwuY29tL2FydGljbGVzLzEwLjExODYvMTQ3MS0yMTA1LTE0LTkxKSBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24uIEJvdGggdG9vbHMgYXBwbHkgc2ltaWxhciBtZXRob2RzIHRoYXQgYWNjb3VudCBmb3IgdGhlIGRpc3RyaWJ1dGlvbnMgd2UgZXhwZWN0IHRvIHNlZSBmb3IgUk5BLXNlcSBhbmQgYXJlIGZhaXJseSBzdHJpbmdlbnQgaW4gY2FsbGluZyBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgZ2VuZXMsIGxvd2VyaW5nIHRoZSByaXNrIG9mIGludmVzdGlnYXRpbmcgZ2VuZXMgdGhhdCB3ZXJlIHJlYWxseSBmYWxzZSBwb3NpdGl2ZXMgKGUuZy4gZG9uJ3QgcmVhbGx5IGhhdmUgZGlmZmVyZW50IGV4cHJlc3Npb24gYmV0d2VlbiB0cmVhdG1lbnQgZ3JvdXBzIGFuZCB0aGVyZWZvcmUgYXJlIG5vdCByZWxldmFudCB0byB0aGUgYmlvbG9naWNhbCBwcm9jZXNzKS4KCkFkZGl0aW9uYWxseSwgYERFU2VxMmAgYWxzbyBoYXMgYW4KW2V4Y2VsbGVudCB2aWduZXR0ZV0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy92aWduZXR0ZXMvREVTZXEyL2luc3QvZG9jL0RFU2VxMi5odG1sKSAqY2xpY2sgbGluayB0byBvcGVuKgpmcm9tIExvdmUsIEFuZGVycywgYW5kIEh1YmVyLCBmcm9tIHdoaWNoIG91ciB3b3JrZmxvdyBpcyBwYXJ0aWFsbHkgYWRhcHRlZCwgYW5kIGlzIGEgZ29vZCByZXNvdXJjZSB3aGVuIGFuYWx5emluZyB5b3VyIG93biBkYXRhCihzZWUgYWxzbzogW0xvdmUsIEFuZGVycywgYW5kIEh1YmVyLiBfR2Vub21lIEJpb2xvZ3lfLiAyMDE0Ll0oaHR0cHM6Ly9kb2kub3JnLzEwLjExODYvczEzMDU5LTAxNC0wNTUwLTgpKS4KCgo8ZGV0YWlscz4KICAgIDxzdW1tYXJ5PipDbGljayBmb3IgYWRkaXRpb25hbCByZXNvdXJjZXMgcmVnYXJkaW5nIHN0YXRpc3RpY2FsIHRlc3RpbmcgYW5kIHRvb2wgY29tcGFyaXNvbiBmb3IgUk5BLXNlcSBkYXRhKjwvc3VtbWFyeT4KICAgIFRvIGxlYXJuIG1vcmUgYWJvdXQgc3RhdGlzdGljYWwgdGVzdGluZyBhbmQgd2hhdCBkaXN0cmlidXRpb25zIGJlc3QgbW9kZWwgdGhlIGJlaGF2aW9yIG9mIFJOQS1zZXEgZGF0YSwgYSBnb29kIHJlc291cmNlIGlzIHRoaXMgW0VkWCBsZWN0dXJlIGJ5IFJhZmFlbCBJcml6YXJyeV0oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1ISzdXS3NMM2MydyZmZWF0dXJlPXlvdXR1LmJlKSBvciB0aGlzIFtsZWN0dXJlIGJ5IEthc3BlciBIYW5zZW5dKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9QzhSTnZXdTdwQXcpLiBBbm90aGVyIGhlbHBmdWwgZ3VpZGUgaXMgdGhpcyBbQ29tcGFyYXRpdmUgU3R1ZHkgZm9yIERpZmZlcmVudGlhbCBFeHByZXNzaW9uIEFuYWx5c2lzIGJ5IFpoYW5nIGV0IGFsLl0oaHR0cHM6Ly9qb3VybmFscy5wbG9zLm9yZy9wbG9zb25lL2FydGljbGU/aWQ9MTAuMTM3MS9qb3VybmFsLnBvbmUuMDEwMzIwNykgZnJvbSAyMDE0Lgo8L2RldGFpbHM+CgoKIyMgREVTZXEyIGFzc3VtcHRpb25zIGFuZCByZXF1aXJlbWVudHMKCkEga2V5IGFzc3VtcHRpb24gb2YgREVTZXEyIGlzIHRoYXQgZm9yIG1vc3QgZXhwZXJpbWVudHMgKmJpb2xvZ2ljYWwgdmFyaWFuY2UgaXMgbXVjaCBncmVhdGVyIHRoYW4gdGVjaG5pY2FsIHZhcmlhbmNlKiAoZXNwZWNpYWxseSBpZiBbYmVzdCBwcmFjdGljZXNdKGh0dHBzOi8vd3d3LnR4Z2VuLnRhbXUuZWR1L2ZhcS9ybmEtaXNvbGF0aW9uLWJlc3QtcHJhY3RpY2VzLykgZm9yIFtxdWFsaXR5IFJOQSBpc29sYXRpb25dKGh0dHBzOi8vd3d3LmJpb2NvbXBhcmUuY29tL0JlbmNoLVRpcHMvMTI4NzkwLUZvdXItVGlwcy1mb3ItUGVyZmVjdGluZy1STkEtSXNvbGF0aW9uLykgYXJlIGZvbGxvd2VkLCBpbmNsdWRpbmcgRE5hc2UgdHJlYXRtZW50ISkuCgoKU2luY2UgY2FsY3VsYXRpbmcgdmFyaWFuY2UgaXMga2V5IHRvIHRoZSBzdGF0aXN0aWNhbCBhcHByb2FjaCB1c2VkIGZvciBERVNlcTIsIGlmIHdlIHRyaWVkIHRvIGNvbXBhcmUgdHdvIHRyZWF0bWVudCBncm91cHMgd2l0aCBsZXNzIHRoYW4gKip0d28qKiByZXBsaWNhdGVzLCB3ZSB3b3VsZCBnZXQgYW4gZXJyb3IgKGFzIHNob3duIGluIFt0aGlzIGJsb2cgcG9zdF0oaHR0cHM6Ly9zdXBwb3J0LmJpb2NvbmR1Y3Rvci5vcmcvcC84OTc0Ni8pKS4gV2l0aG91dCByZXBsaWNhdGVzLCB0aGVyZSBjYW4ndCBiZSBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UgKGUuZy4gcC12YWx1ZXMpLCBidXQgKnF1YWxpdGF0aXZlKiBhcHByb2FjaGVzIGFyZSBhbiBvcHRpb24sIGxpa2UgbG9va2luZyBhdCB0aGUgdG9wIGV4cHJlc3NlZCBnZW5lcyBhZnRlciBub3JtYWxpemF0aW9uLgoKIyMjIFJlcGxpY2F0ZXMgaW4gUk5BLXNlcSBleHBlcmltZW50cwoKQSBmcmVxdWVudCBxdWVzdGlvbiBmb3IgUk5BLXNlcSBwcm9qZWN0cyBpcyAiSG93IG1hbnkgcmVwbGljYXRlcyBkbyBJIG5lZWQ/Ii4KClRoZSBnZW5lcmFsIGdvYWwgb2Ygb3VyIGFuYWx5c2VzIGlzIHRvIHNlcGFyYXRlIHRoZSDigJxpbnRlcmVzdGluZ+KAnSBiaW9sb2dpY2FsIGNvbnRyaWJ1dGlvbnMgZnJvbSB0aGUg4oCcdW5pbnRlcmVzdGluZ+KAnSB0ZWNobmljYWwgb3Igb3RoZXIgY29udHJpYnV0aW9ucyB0aGF0IGVpdGhlciBjYW5ub3QgYmUgb3Igd2VyZSBub3QgY29udHJvbGxlZCBpbiB0aGUgZXhwZXJpbWVudGFsIGRlc2lnbi4gVGhlIG1vcmUgc291cmNlcyBvZiB2YXJpYXRpb24sIHN1Y2ggYXMgc2FtcGxlcyBjb21pbmcgZnJvbSBoZXRlcm9nZW5vdXMgdGlzc3VlcyBvciBleHBlcmltZW50cyB3aXRoIGluY29tcGxldGUga25vY2tkb3ducywgdGhlIG1vcmUgcmVwbGljYXRlcyAoPjMpIGFyZSByZWNvbW1lbmRlZC4gIAoKCiFbSW1hZ2Ugb2YgdGVjaG5pY2FsLCBiaW9sb2dpY2FsLCBhbmQgZXhwZXJpbWVudGFsIGNvbnRyaWJ1dG9ycyB0byBnZW5lIGV4cHJlc3Npb24sIGZyb20gSEJDIHRyYWluaW5nIG1hdGVyaWFsc10oLi9pbWFnZXMvZGVfdmFyaWF0aW9uLnBuZyl7d2lkdGg9NzUlfQoKCkZvciBhIG1vcmUgaW4gZGVwdGggZGlzY3Vzc2lvbiBvZiBleHBlcmltZW50YWwgZGVzaWduIGNvbnNpZGVyYXRpb25zLCBwYXJ0aWN1bGFybHkgZm9yIHRoZSBudW1iZXIgb2YgcmVwbGljYXRlcywgcGxlYXNlIHJlYWQgW0EgQmVnaW5uZXLigJlzIEd1aWRlIHRvIEFuYWx5c2lzIG9mIFJOQSBTZXF1ZW5jaW5nIERhdGFdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzYwOTYzNDYvKSBhbmQgcGFwZXJzIGxpa2UgdGhpcyBvbmUgYnkgW0hhcnQgZXQgYWxdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcG1jL2FydGljbGVzL1BNQzM4NDI4ODQvKSB0aGF0IGZvY3VzIG9uIGVzdGltYXRpbmcgc3RhdGlzdGljYWwgcG93ZXIgZm9yIFJOQS1zZXEgZXhwZXJpbWVudHMuCgojIyMjIFNlcXVlbmNpbmcgZGVwdGggcmVjb21tZW5kYXRpb25zCgpBIHJlbGF0ZWQgZXhwZXJpbWVudGFsIGRlc2lnbiBjb25zaWRlcmF0aW9uIGlzIGhvdyBtdWNoIHNlcXVlbmNpbmcgZGVwdGggc2hvdWxkIGJlIGdlbmVyYXRlZCBwZXIgc2FtcGxlLiBUaGlzIGZpZ3VyZSBzaGFyZWQgYnkgSWxsdW1pbmEgaW4gdGhlaXIgdGVjaG5pY2FsIHRhbGtzIGlzIGhlbHBmdWwgdG8gdW5kZXJzdGFuZCB0aGUgcmVsYXRpdmUgaW1wb3J0YW5jZSBvZiByZXBsaWNhdGVzIHZlcnN1cyBzZXF1ZW5jaW5nIGRlcHRoLgoKCiFbSWxsdW1pbmEncyBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiByZWNvdmVyeSBhY3Jvc3MgcmVwbGljYXRlIG51bWJlciBhbmQgc2VxdWVuY2luZyBkZXB0aF0oLi9pbWFnZXMvZGVfcmVwbGljYXRlc19pbWcucG5nKXt3aWR0aD03NSV9CgpHZW5lcmFsbHksIGZvciB0aGUgaHVtYW4gYW5kIG1vdXNlIGdlbm9tZXMsIHRoZSByZWNvbW1lbmRhdGlvbiBpcyAzMC00MCBtaWxsaW9uIHJlYWRzIHBlciBzYW1wbGUgZm9yIHBvbHlBIGxpYnJhcnkgcHJlcHMgdG8gY2FwdHVyZSBib3RoIGhpZ2hseSBleHByZXNzZWQgKGFidW5kYW50KSBhbmQgbW9yZSBsb3dseSBleHByZXNzZWQgKHJhcmVyKSB0cmFuc2NyaXB0cywgYXNzdW1pbmcgdGhhdCB+MjUsMDAwIHByb3RlaW4tY29kaW5nIGdlbmVzIHdvdWxkIGJlIG1lYXN1cmVkLiBIb3dldmVyLCBhcyB0aGUgaW1hZ2UgYWJvdmUgc2hvd3MsIHNlcXVlbmNpbmcgZGVwdGggaGFzIGxlc3Mgb2YgYW4gaW1wYWN0IHRoYW4gbnVtYmVyIG9mIHJlcGxpY2F0ZXMgaW4gZGV0ZWN0aW5nIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyAoREVHcykuCgojIyMjIFtFeGVyY2lzZV06IEJ1aWxkaW5nIGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgb2YgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMKCjEpIFBvc3QgYSBjb21tZW50IGJlbG93IHJlZ2FyZGluZyB3aGF0IGtleSBxdWVzdGlvbi9taXNjb25jZXB0aW9uIHJlZ2FyZGluZyBkZXNpZ25pbmcgYW4gUk5BLXNlcSBleHBlcmltZW50IHdlIHdlcmUgYWJsZSB0byBhZGRyZXNzICoqT1IqKiAgIAoxKSBQb3N0IGEgcXVlc3Rpb24gdGhhdCB0aGF0IHdhcyBOT1QgYWRkcmVzc2VkIGJ1dCB0aGF0IHlvdSBob3BlIHdlIHdpbGwgYWRkcmVzcyBpbiB0aGUgbGF0ZXIgbW9kdWxlcyAqKk9SKiogICAgCjEpIEFkZCBhIHRodW1icyB1cCB0byB5b3VyIGZhdm9yaXRlIGNvbW1lbnQocykgdG8gdXB2b3RlIGl0ICAgIAoKLS0tLQoKCiMjIyBSYXcgZGF0YSBhcyBpbnB1dAoKQW5vdGhlciBrZXkgYXNzdW1wdGlvbiBmb3IgREVTZXEyIGlzIHRoYXQgdGhlIGFuYWx5c2lzIHdpbGwgc3RhcnQgd2l0aCBbdW4tbm9ybWFsaXplZCBjb3VudHNdKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL2RldmVsL2Jpb2MvdmlnbmV0dGVzL0RFU2VxMi9pbnN0L2RvYy9ERVNlcTIuaHRtbCN3aHktdW4tbm9ybWFsaXplZC1jb3VudHMpLgoKVG8gYmVnaW4gb3VyIGFuYWx5c2lzLCB3ZSdsbCByZWFkIGluIHRoZSAqKnJhdyoqIGNvdW50IGRhdGEgZmlsZSwgYGdlbmVfZXhwZWN0ZWRfY291bnRfdHJpbW1lZC50eHRgIHdoaWNoIGlzIHNpbWlsYXIgdG8gd2hhdCB3b3VsZCBiZSBnZW5lcmF0ZWQgaW4gdGhlIGFsaWdubWVudCBzdGVwcyB5ZXN0ZXJkYXkgKGFuZCB3aGF0IHlvdSBjb3VsZCByZWNlaXZlIGZyb20gQUdDKS4gV2UnbGwgZGlzY3VzcyBsYXRlciBhIGZldyBub3JtYWxpemF0aW9ucyB0aGF0IGNhbiBiZSBoZWxwZnVsIGZvciB1cyB0byB1bmRlcnN0YW5kIGhvdyBtdWNoIGEgZ2VuZSBpcyBleHByZXNzZWQgd2l0aGluIG9yIGJldHdlZW4gc2FtcGxlcywgYnV0IG5vcm1hbGl6ZWQgZGF0YSAqKnNob3VsZCBub3QqKiBiZSB1c2VkIGFzIGFuIGlucHV0IGZvciBERVNlcTIuCgpgYGB7ciBEYXRhVGFibGUsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0KIyMgbmVlZCB0byBpbmNsdWRlIHBhdGhzIHJlbGF0aXZlIHRvIHNpdGUgYnVpbGQgbG9jYXRpb25zIGJ1dCBrZWVwIGNvZGUgYmxvY2sgaGlkZGVuCkNvdW50VGFibGUgPC0gcmVhZC50YWJsZSgiLi4vZGF0YS9nZW5lX2V4cGVjdGVkX2NvdW50X3RyaW1tZWQudHh0IiwgaGVhZGVyID0gVFJVRSwgcm93Lm5hbWVzID0gMSkKYGBgCgpgYGB7ciBEYXRhVGFibGUyLCBldmFsPUZBTFNFfQpDb3VudFRhYmxlIDwtIHJlYWQudGFibGUoImRhdGEvZ2VuZV9leHBlY3RlZF9jb3VudF90cmltbWVkLnR4dCIsIGhlYWRlciA9IFRSVUUsIHJvdy5uYW1lcyA9IDEpCmBgYApgYGB7ciBEYXRhVGFibGVDaGVjaywgZXZhbD1UUlVFfQpoZWFkKENvdW50VGFibGUsIG49MikgIyBsb29rIGF0IHRoZSB0b3Agb2YgdGhlIHRhYmxlCmBgYAoKTm93IHRoYXQgdGhlIGZpbGUgaXMgcmVhZCBpbnRvIFIsIG5vdGUgdGhhdCB3ZSd2ZSBjcmVhdGVkIGEgZGF0YSBmcmFtZSB0aGF0IGluY2x1ZGVzICdnZW5lIGlkcycgaW4gRU5TRU1CTCBmb3JtYXQgYXMgcm93bmFtZXMgYW5kIGNvdW50IGRhdGEgZnJvbSB0d2VsdmUgZGlmZmVyZW50IHNhbXBsZXMuCgojIyMjIFtFeGVyY2lzZV06IFJTRU0gb3V0cHV0cyB2ZXJzdXMgREVTZXEyIGlucHV0IHJlcXVpcmVtZW50cwoKSWYgd2UgdGhpbmsgYmFjayB0byB0aGUgUlNFTSBvdXRwdXRzLCB0aGUgJ2V4cGVjdGVkX2NvdW50cycgdGFibGUgbWF5IGluY2x1ZGUgZnJhY3Rpb25zIGR1ZSB0byBob3cgdGhlIGFsaWdubWVudCB0b29sIHJlc29sdmVzIHJlYWRzIHRoYXQgbWFwIHRvIG11bHRpcGxlIGxvY3VzZXMpLiBTaW5jZSBERVNlcTIgcmVxdWlyZXMgd2hvbGUgbnVtYmVycywgaWYgd2UgdHJ5IHRvIHVzZSB0aGUgUlNFTSBvdXB1dHMgZGlyZWN0bHksIERFU2VxMiB3aWxsIGdpdmUgdXMgYW4gZXJyb3IuCgpGaXJzdCBsZXQncyBjaGVjayB0aGUgY291bnQgdGFibGUgaW4gYSBkaWZmZXJlbnQgd2F5LCB0byBzZWUgaWYgb3VyIHRhYmxlIGluY2x1ZGVzIGZyYWN0aW9ucy4KYGBge3IgUlNFTW91dHB1dH0KdGFpbChDb3VudFRhYmxlLCBuPTIpCmBgYAoKKltRdWVzdGlvbl06IFRvIHJlc29sdmUgdGhpcyBkaXNjcmVwYW5jeSBiZXR3ZWVuIHRoZSBSU0VNIG91dHB1dHMgYW5kIGV4cGVjdGVkIGlucHV0IGZvciBERVNlcTIsIHdoYXQgY291bGQgd2UgZG8/KgoKVG8gcm91bmQgZG93biBhbGwgdGhlIGNvbHVtbnMgb2Ygb3VyIGBDb3VudFRhYmxlYCB0aGF0IGluY2x1ZGUgY291bnQgZGF0YSAoYWxsIGNvbHVtbnMgc2luY2Ugd2Ugc2V0IHRoZSBnZW5lIG5hbWVzIHRvIGJlIG91ciByb3cgbmFtZXMpLCB3ZSBjYW4gdXNlIHRoZSBgcm91bmRgKClgIGZ1bmN0aW9uLgpgYGB7ciBSb3VuZFJhd0NvdW50c30KQ291bnRUYWJsZSA8LSByb3VuZChDb3VudFRhYmxlKQp0YWlsKENvdW50VGFibGUsIG49MikgIyBub3cgd2hvbGUgbnVtYmVycwpgYGAKCkFuIGltcG9ydGFudCBub3RlIGlzIHRoYXQgdGhlcmUgYXJlIHNldmVyYWwgYm9udXMgY29udGVudCBzZWN0aW9ucyBvbiB0aGUgaW5zdHJ1Y3Rpb24gcGFnZXMsIGxpa2UgdGhlIHR3byBiZWxvdyB0aGF0IHdlIHdpbGwgbm90IGJlIGNvdmVyaW5nIGluIHRoaXMgd29ya3Nob3AsIGJ1dCB0aGF0IG1heSBoYXZlIHVzZWZ1bCBjb250ZXh0IG9yIGJlIGhlbHBmdWwgd2hlbiB5b3UgcmV2aWV3IHRoaXMgbWF0ZXJpYWwuCgo8ZGV0YWlscz4KICAgIDxzdW1tYXJ5PipDbGljayBmb3IgYWx0ZXJuYXRpdmUgREVTZXEyIGlucHV0IG9wdGlvbnMgZm9yIFJTRU0gb3V0cHV0cyo8L3N1bW1hcnk+CiAgICBUaGUgcGFja2FnZSBgdHhpbXBvcnRgIGlzIGFub3RoZXIgb3B0aW9uW3JlY29tbWVuZGVkIHRoZSBERVNlcTIgIGF1dGhvcnNdKGh0dHBzOi8vc3VwcG9ydC5iaW9jb25kdWN0b3Iub3JnL3AvOTA2NzIvKSB0byByZWFkIGluIHRoZSBSU0VNIGV4cGVjdGVkX2NvdW50cywgYXMgdGhpcyAgcGFja2FnZSBhbGxvd3MgZm9yIHRoZSBhdmVyYWdlIHRyYW5zY3JpcHQgbGVuZ3RoIHBlciBnZW5lIHRvIGJlIHVzZWQgaW4gdGhlIERFIGFuYWx5c2lzIGFuZCwgYXMgW2Rlc2NyaWJlZCBieSB0aGUgYXV0aG9yXShodHRwczovL3N1cHBvcnQuYmlvY29uZHVjdG9yLm9yZy9wLzg4NzYzLyksIHRoZSBgdHhpbXBvcnQtdG8tREVTZXFEYXRhU2V0YCBjb25zdHJ1Y3RvciBmdW5jdGlvbiByb3VuZCB0aGUgbm9uLWludGVnZXIgZGF0YSBnZW5lcmF0ZWQgYnkgUlNFTSB0byB3aG9sZSBudW1iZXJzLgoKPC9kZXRhaWxzPgoKPGRldGFpbHM+CiAgICA8c3VtbWFyeT4qQ2xpY2sgZm9yIGNvbXBhcmlzb24gb2YgUk5BLXNlcSBkYXRhIGFuZCBtaWNyb2FycmF5IGRhdGEqPC9zdW1tYXJ5PgogICAgV2l0aCBbaGlnaGVyIHNlbnNpdGl2aXR5LCBncmVhdGVyIGZsZXhpYmxpdHksIGFuZCBkZWNyZWFzaW5nIGNvc3RdKGh0dHBzOi8vd3d3LmlsbHVtaW5hLmNvbS9zY2llbmNlL3RlY2hub2xvZ3kvbmV4dC1nZW5lcmF0aW9uLXNlcXVlbmNpbmcvbWljcm9hcnJheS1ybmEtc2VxLWNvbXBhcmlzb24uaHRtbCksIHNlcXVlbmNpbmcgaGFzIGxhcmdlbHkgcmVwbGFjZWQgbWljcm9hcnJheSBhc3NheXMgZm9yIG1lYXN1cmluZyBnZW5lIGV4cHJlc3Npb24uIEEga2V5IGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgcGxhdGZvcm1zIGlzIHRoYXQgbWljcm9hcnJheXMgbWVhc3VyZSBpbnRlbnNpdGllcyBhbmQgYXJlIHRoZXJlZm9yZSAqY29udGlub3VzKiBkYXRhIHdoaWxlIHRoZSBjb3VudCBkYXRhIGZyb20gc2VxdWVuY2luZyBpcyAqZGlzY3JldGUqLiBBIG1vcmUgZGV0YWlsZWQgY29tcGFyaXNvbiBiZXR3ZWVuIG1pY3JvYXJyYXlzIGFuZCBzZXF1ZW5jaW5nIHRlY2hub2xvZ2llcy9hbmFseXNpcyBpcyBvdXRsaW5lZCBpbiBbdGhlIG9ubGluZSBtYXRlcmlhbHMgZm9yIFBlbm4gU3RhdGUncyBTVEFUNTU1IGNvdXJzZV0oaHR0cHM6Ly9vbmxpbmUuc3RhdC5wc3UuZWR1L3N0YXQ1NTUvbm9kZS8zMC8pCgo8L2RldGFpbHM+CgoKIyMgR2V0dGluZyBoZWxwCgpSL1JzdHVkaW8gaGFzIGEgc3Ryb25nIGNvbW11bml0eSBjb21wb25lbnQgc28gaWYgeW91IGFyZSBnZXR0aW5nIGFuIGVycm9yIG9yIHdvbmRlcmluZyBob3cgdG8gbWFrZSBhIGNvbW1hbmQgd29yayBvciBob3cgdG8gcGVyZm9ybSBhIHNwZWNpZmljIHRhc2ssIHRoZXJlIGlzIGxpa2VseSBhbHJlYWR5IGEgc29sdXRpb24gb3V0IHRoZXJlLiBSZW1lbWJlciB0aGF0IEdvb2dsZSBpcyB5b3VyIGZyaWVuZCwgYWx0aG91Z2ggaXQgY2FuIHNvbWV0aW1lcyBiZSBhIGNoYWxsZW5nZSB0byBmaWd1cmUgb3V0ICp3aGF0IHRvIHNlYXJjaCBmb3IqLiBLZXkgcGFydHMgb2YgYSBzdWNjZXNzZnVsIHNlYXJjaDoKCiogUGFja2FnZSBvciBjb21tYW5kIHJ1bgoqIGBSYCBvciBgQmlvY29uZHVjdG9yYAoqIFRoZSBlcnJvciBtZXNzYWdlIGlmIHRoZXJlIGlzIG9uZQoqIFZlcnNpb24gaW5mb3JtYXRpb24KCkhvdyB0byBnZXQgc2Vzc2lvbiBpbmZvcm1hdGlvbiB0byBhaWQgaW4gYSBzZWFyY2g6CmBgYHtyIFNlc3Npb24gaW5mbywgZXZhbCA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CnNlc3Npb25JbmZvKCkKYGBgCgoKSGlnaGx5IHJlY29tbWVuZCB1c2luZyByZXNvdXJjZXMgbGlrZSBbQmlvY29uZHVjdG9yIFN1cHBvcnRdKGh0dHBzOi8vc3VwcG9ydC5iaW9jb25kdWN0b3Iub3JnLyksIFtCaW9zdGFyc10oaHR0cHM6Ly93d3cuYmlvc3RhcnMub3JnLyksIGFuZCBbU3RhY2sgT3ZlcmZsb3ddKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zL3RhZ2dlZC9yKSwgaW5jbHVkaW5nIHRocmVhZHMgb24gc3BlY2lmaWMgcGFja2FnZXMgb3IgY29tbW9uIGJpb2luZm9ybWF0aWMgdGFza3MuCgpJIHBlcnNvbmFsbHkgdXNlIG9uZSBvciBtb3JlIG9mIHRoZXNlIHJlc291cmNlcyAqKmV2ZXJ5IGRheSoqLgoKMTB4IGFsc28gaGFzIGEgaGVscGZ1bCBbMTAgdGlwcyBmb3IgYmlvbG9naXN0cyBsZWFybmluZyAgYmlvaW5mb3JtYXRpY3NdKGh0dHBzOi8vd3d3LjEweGdlbm9taWNzLmNvbS9yZXNvdXJjZXMvYW5hbHlzaXMtZ3VpZGVzLzEwLXRpcHMtZm9yLWJpb2xvZ2lzdHMtbGVhcm5pbmctYmlvaW5mb3JtYXRpY3MpIGluY2x1ZGVkIGluIHRoZWlyIHJlc291cmNlcy4KCiMgU3VtbWFyeQoKSW4gdGhpcyBzZWN0aW9uLCB3ZToKCiogU2V0IHVwIG91ciBjb21wdXRlIGVudmlyb25tZW50CiogTGVhcm5lZCBhYm91dCBERVNlcTIKKiBMb2FkZWQgb3VyIHJhdyBjb3VudCB0YWJsZXMgKGlucHV0IGZpbGUgMSkKCk5vdyB0aGF0IHdlIGhhdmUgb3VyIGNvdW50IGRhdGEgcHJvY2Vzc2VkLCB3ZSBjYW4gbW92ZSBvbiB0byAidW5ibGluZGluZyIgb3VyIGRhdGEsIGFzIHRoZSBzYW1wbGUgbmFtZXMgYXJlIHVuaXF1ZSBpZGVudGlmaWVycyBnZW5lcmF0ZWQgYnkgYSBzZXF1ZW5jaW5nIGNlbnRlciBhbmQgbm90IHZlcnkgaW5mb3JtYXRpdmUgYXMgZmFyIGFzIG91ciBleHBlcmltZW50YWwgY29uZGl0aW9ucy4KCgotLS0KCiMgU291cmNlcwojIyBUcmFpbmluZyByZXNvdXJjZXMgdXNlZCB0byBkZXZlbG9wIG1hdGVyaWFscwoqIEhCQyBER0Ugc2V0dXA6IGh0dHBzOi8vaGJjdHJhaW5pbmcuZ2l0aHViLmlvL0RHRV93b3Jrc2hvcC9sZXNzb25zLzAxX0RHRV9zZXR1cF9hbmRfb3ZlcnZpZXcuaHRtbCAgIAoqIEhCQyBDb3VudCBOb3JtYWxpemF0aW9uOiBodHRwczovL2hiY3RyYWluaW5nLmdpdGh1Yi5pby9ER0Vfd29ya3Nob3AvbGVzc29ucy8wMl9ER0VfY291bnRfbm9ybWFsaXphdGlvbi5odG1sICAgCiogREVTZXEyIHN0YW5kYXJkIHZpZ25ldHRlOiBodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9kZXZlbC9iaW9jL3ZpZ25ldHRlcy9ERVNlcTIvaW5zdC9kb2MvREVTZXEyLmh0bWwgICAKKiBERVNlcTIgYmVnaW5uZXJzIHZpZ25ldHRlOiBodHRwczovL2Jpb2MuaXNtLmFjLmpwL3BhY2thZ2VzLzIuMTQvYmlvYy92aWduZXR0ZXMvREVTZXEyL2luc3QvZG9jL2JlZ2lubmVyLnBkZiAgIAoqIEJpb2NvbmR1Y3RvciBSTkEtc2VxIFdvcmtmbG93czogaHR0cHM6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9oZWxwL2NvdXJzZS1tYXRlcmlhbHMvMjAxNS9MZWFybkJpb2NvbmR1Y3RvckZlYjIwMTUvQjAyLjFfUk5BU2VxLmh0bWwgICAKKiBDQ0RMIEdhc3RyaWMgY2FuY2VyIHRyYWluaW5nIG1hdGVyaWFsczogaHR0cHM6Ly9hbGV4c2xlbW9uYWRlLmdpdGh1Yi5pby90cmFpbmluZy1tb2R1bGVzL1JOQS1zZXEvMDMtZ2FzdHJpY19jYW5jZXJfZXhwbG9yYXRvcnkubmIuaHRtbAoqIENDREwgTmV1cm9ibGFzdG9tYSB0cmFpbmluZyBtYXRlcmlhbHM6IGh0dHBzOi8vYWxleHNsZW1vbmFkZS5naXRodWIuaW8vdHJhaW5pbmctbW9kdWxlcy9STkEtc2VxLzA1LW5iX2NlbGxfbGluZV9ERVNlcTIubmIuaHRtbAoKCmBgYHtyIFdyaXRlT3V0LlJEYXRhLCBldmFsPVRSVUUsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiNIaWRkZW4gY29kZSBibG9jayB0byB3cml0ZSBvdXQgZGF0YSBmb3Iga25pdHRpbmcKCmRpci5jcmVhdGUoInJkYXRhIiwgc2hvd1dhcm5pbmdzPUZBTFNFKQpzYXZlLmltYWdlKGZpbGUgPSAicmRhdGEvUnVubmluZ0RhdGEuUkRhdGEiKQojSG93IHRvIGxvYWQgZm9yIG5leHQgc2VnbWVudAojbG9hZCgicmRhdGEvUnVubmluZ0RhdGEuUkRhdGEiKQpgYGAKCi0tLQoKVGhlc2UgbWF0ZXJpYWxzIGhhdmUgYmVlbiBhZGFwdGVkIGFuZCBleHRlbmRlZCBmcm9tIG1hdGVyaWFscyBsaXN0ZWQgYWJvdmUuIFRoZXNlIGFyZSBvcGVuIGFjY2VzcyBtYXRlcmlhbHMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBbQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbiBsaWNlbnNlIChDQyBCWSA0LjApXShodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS80LjAvKSwgd2hpY2ggcGVybWl0cyB1bnJlc3RyaWN0ZWQgdXNlLCBkaXN0cmlidXRpb24sIGFuZCByZXByb2R1Y3Rpb24gaW4gYW55IG1lZGl1bSwgcHJvdmlkZWQgdGhlIG9yaWdpbmFsIGF1dGhvciBhbmQgc291cmNlIGFyZSBjcmVkaXRlZC4K