Objectives

This notebook will demonstrate how to:

  • Navigate the terminal interface
  • Quantify single cell expression data with Alevin
  • Perform basic quality control and interpret results

In this notebook, we will be running through the basics of processing raw single-cell RNA-seq data.

We will be using a tag-based scRNA-seq sample from the Tabula Muris project. This dataset is made of 20 mouse organs that were sequenced using 10x Genomics Chromium single cell sequencing methods. For 10x Genomics scRNA-seq data, cells are separated by emulsion/droplets, and individual cells are given barcodes (often abbreviated ‘CB’ in documentation). Each transcript will also contain a Unique Molecular Identifiers (UMIs) which allow us to examine PCR amplification errors and biases.

Roadmap: Preprocessing & Initial QC
Roadmap: Preprocessing & Initial QC

About the data

We obtained these data from Tabula Muris project’s Figshare. The BAM files that were on Figshare were converted to fastq files using bamtofastq from 10x Genomics. We will process a fastq file from mouse bladder for this as an example.
To limit the amount of time this takes to run in the context of this workshop, we are only running part of the sample’s reads.

Note: Depending on the format of the data you are working with, i.e., if you have a set of .bcl files, you may need to use cellranger mkfastq to create .fastq files for each sample. However, most public data is available in fastq format, and most sequencing cores will generate the .fastq files, so that is where we will start.

Checking directories and files

If you have opened the scRNA-seq.Rproj file, your Terminal should already be set to the scRNA-seq directory, but it is worth checking with the pwd command in the Terminal (or by looking at the path shown in the command prompt or at the top of the Terminal pane).

If you are in a different directory, we will want to use cd to change to the training-modules/scRNA-seq directory.

Copy and paste the text in the code blocks below into your Terminal window in RStudio. It should be in the lower left hand corner as a tab next to Console.

cd ~/training-modules/scRNA-seq

Once you are there, you should be able to run the following command in the Terminal to look at the contents of the data/tabula-muris directory:

ls data/tabula-muris

Here you will see the fastq directory, which is actually a link to a shared folder with the raw fastq files, split by sample. We will use these files, but we will not write to this directory.

We can look inside the contents of the fastq directory, and we should see 16 subfolders corresponding to 16 different samples. Within each of these folders should be the fastq files associated with that sample. Again, we can use the ls command to show the contents of each of the directories.

In this scenario, 10X_P4_3 refers to the sample name that we will be processing, which contains data from mouse bladder cells.

ls data/tabula-muris/fastq/10X_P4_3

You should see a list of multiple fastq files all starting with 10X_P4_3, indicating the sample name.

If you notice, each fastq file name contains either R1 or R2. These correspond to the two sequencing reads of a paired-end library. For 10x data, the first read (the R1 file) will contain the cell barcode and UMI sequence, and the second read (the R2 file) will contain a cDNA sequence corresponding to the captured transcript. We will need both of these files to quantify our data.

10X_P4_3_L001_R1_001.fastq.gz  10X_P4_3_L002_R1_001.fastq.gz
10X_P4_3_L001_R1_002.fastq.gz  10X_P4_3_L002_R1_002.fastq.gz
10X_P4_3_L001_R1_003.fastq.gz  10X_P4_3_L002_R1_003.fastq.gz
10X_P4_3_L001_R2_001.fastq.gz  10X_P4_3_L002_R2_001.fastq.gz
10X_P4_3_L001_R2_002.fastq.gz  10X_P4_3_L002_R2_002.fastq.gz
10X_P4_3_L001_R2_003.fastq.gz  10X_P4_3_L002_R2_003.fastq.gz

Sequencing runs are often split into multiple fastq files, both when a sample was run across multiple lanes and to keep the individual file sizes down. This was the case for the Tabula Muris data we are using here as well. The files that you see in the data/tabula-muris/fastq/10X_P4_3 directory shown above represent 2 lanes worth of data, with three R1 and three R2 files per lane.

You will also see the file TM_droplet_metadata.csv, which contains metadata for the Tabula Muris experiments.

Set up output directory

Now that we are in scRNA-seq, we’ll make a directory for us to store our quantification files in. In Terminal, run the following command:

mkdir -p data/tabula-muris/alevin-quant/10X_P4_3_subset

Quantifying cell expression with Salmon Alevin

Alevin is run from the command line (Terminal) to perform mapping and quantification of tag-based single cell expression data.

Indexing the mouse transcriptome

Before you can quantify with Salmon and Alevin we need to index the transcriptome for the species we will be mapping to. This step would be the same for mapping bulk RNA-seq data, and you can use the same transcriptome indexes as bulk RNA-seq, however, due to the shorter read lengths in the 10x sequencing, we may want to use shorter kmers than the default index size that salmon uses. In this instance, we used a -k of 23.

In the interest of time, we have already run the command below and have the index built and ready for you in a shared directory.

But for your own reference, here is how you might do it yourself:

# salmon --threads=16 --no-version-check index \
#  -t Mus_musculus.GRCm38.cdna.all.fa.gz \
#  -i index/Mus_musculus/short_index \
#  -k 23

Scripts to build the indexes like those we are using here (and others) can be found in this repository.

Running Salmon Alevin

Copy and paste this in your Terminal to run the Alevin quantification. This will take about 20 minutes to run, so we will start now, then talk about the options.

Note that here we are only giving the full paths to one of the R1 files and one of the R2 files. For the sake of time, we are only going to be running this on a subset of reads, but will also show you how to run it on the full sample.

salmon alevin \
  -i index/Mus_musculus/short_index \
  -l ISR \
  -1 data/tabula-muris/fastq/10X_P4_3/10X_P4_3_L001_R1_001.fastq.gz \
  -2 data/tabula-muris/fastq/10X_P4_3/10X_P4_3_L001_R2_001.fastq.gz \
  -o data/tabula-muris/alevin-quant/10X_P4_3_subset \
  -p 4 \
  --chromium  \
  --tgMap index/Mus_musculus/Mus_musculus.GRCm38.95.versioned_tx2gene.tsv \
  --dumpFeatures

Salmon Alevin command line options

For detailed information about all options available see the Alevin documentation and Salmon documentation.

Many of the options for the salmon alevin command are the same as those you would see when mapping and quantifying bulk RNA-seq data with salmon quant:

  • -i gives the location of the transcriptome index
  • -1 and -2 are the paired read input files
  • -o designates the output folder
  • -p allows us to specify how many processors to use; in this case we will use 4

-l

The -l option is for designating the library format. For most single-cell quantification, you will want to use the ISR library type. See Salmon’s documentation for more information on fragment library types (and all of the other options available). Note that this option must come before the read files.

--chromium

Because we are using 10x v2 chromium data, we have to use this flag to tell alevin where to expect the barcodes, UMIs and sequence data. If we were using 10x v3 data, we would need the --chromiumV3 flag instead. Drop-seq data is also supported, for which we would use the --dropseq flag instead of this.

--tgMap

The transcriptome file that we are mapping to has separate sequences for each transcript of a gene, but due to the sparse nature of single-cell data, we are not likely to be able to meaningfully distinguish among different transcripts. For this reason, alevin will quantify our results at the gene level, so we need to provide a file that maps each transcript to its gene. For this example, we’ve pre-made the file Mus_musculus.GRCm38.95.versioned_tx2gene.tsv from the Ensembl transcriptome that we indexed above. The file is a TSV (tab-separated values) file with 2 columns: one of transcripts and the other the gene that each comes from.

--dumpFeatures

This option will print out information that we will use for quality checks later on, including files with information on the UMIs and cell barcodes.

See the Alevin documentation for a complete list of the Alevin options. There are also a number of example analyses at the Alevin tutorial website.

Note: Running the FULL sample.

When we took a look at the data/tabula-muris/fastq/10X_P4_3 directory earlier, we noticed that there were multiple files representing 2 lanes worth of data, with three R1 and three R2 files per lane:

We should really run all of these through Salmon, though that will take about six times as long as the single pair of reads we used. To do this, we could list each R1 and R2 file (space separated) after the -1 and -2 arguments, respectively. But that is a lot of typing, so a nice shortcut is to use a * character to represent a wildcard that will be filled in with whatever characters are present in the files at the given path. In the pattern 10X_P4_3_L*_R1_*.fastq.gz, this would allow any lane number and any subset, so would match all of the following files (all the R1 files in this case):

10X_P4_3_L001_R1_001.fastq.gz  10X_P4_3_L002_R1_001.fastq.gz
10X_P4_3_L001_R1_002.fastq.gz  10X_P4_3_L002_R1_002.fastq.gz
10X_P4_3_L001_R1_003.fastq.gz  10X_P4_3_L002_R1_003.fastq.gz

For this directory, that would make our full salmon alevin command look like this (don’t run this now!):

# salmon alevin \
#   -i index/Mus_musculus/short_index \
#   -l ISR \
#   -1 data/tabula-muris/fastq/10X_P4_3/10X_P4_3_L*_R1_*.fastq.gz \
#   -2 data/tabula-muris/fastq/10X_P4_3/10X_P4_3_L*_R2_*.fastq.gz \
#   -o data/tabula-muris/alevin-quant/10X_P4_3 \
#   -p 4 \
#   --chromium  \
#   --tgMap index/Mus_musculus/Mus_musculus.GRCm38.95.versioned_tx2gene.tsv \
#   --dumpFeatures

In general, you will want to run all lanes and all files for a given sample together. But DO NOT combine multiple samples into a single alevin quantification! Keep separate samples (and replicates) separate!

Initial quality control with alevinQC

Now that we have quantified our data with Alevin, we are ready to perform initial quality control checks.

In order to perform these quality control checks, we’ll use the alevinQC R package. Note that alevinQC depends on files that we get using the--dumpFeatures option in Alevin.

About the alevinQCReport() function: The first argument needs to be where the sample’s output data was put when Alevin was run (as a character string, aka using quotes). The rest of alevinQCReport()’s arguments tell R where to put the output QC report.

# First, define path to alevin output:
alevin_path <- file.path("data", "tabula-muris", "alevin-quant", "10X_P4_3_subset")

# Produce a QC report of results found in the `alevin_path` directory
alevinQC::alevinQCReport(alevin_path,
                         sampleId = "10X_P4_3_subset",
                         outputFile = "10X_P4_3_subset-qc_report.html",
                         outputDir = "qc-reports")

Look for the 10X_P4_3_subset-qc_report.html file created in the qc-reports directory to examine the quality of your data and performance of Alevin.

We have also placed an example of a poor quality sample alevinQC report in the qc-reports directory, with the name Bad_Example_10X_P4_2_qc_report.html.

This report will show a few key metrics that inform you about the quality of your sample. There is a lot of information included in the report, so some key metrics to note are included in the Summary tables:

  • Fraction of reads in whitelist barcodes
  • Mean number of reads per cell
  • Median number of detected genes per cell

The fraction of reads in whitelist barcodes is particularly important as a low percentage here means the library contains many reads that do not contain the expected cell barcodes. This is indicative of poor single-cell capture during library construction.

The mean number of reads per cell and median number of detected genes per cell can be helpful in understanding how deeply the library was sequenced. The higher these numbers are, the more information you will obtain per cell.

The knee plot shows the number of distinct UMIs for each possible cell barcode on the y-axis, with the barcodes ranked from the most UMIs to the fewest along the x-axis.

Cell barcodes with low UMI counts are likely to be empty droplets that did not contain a cell. These droplets must be filtered out so we only consider true cells for downstream analysis.

To do this, we can look for a “knee” on the curve where the number of UMIs per barcode starts to drop off rapidly, with the intuition that this is where we are reaching the end of the UMIs per cell distribution for true cells. We can then choose a threshold below the knee and only include barcodes above this threshold in the final cell barcode list.

This “knee” method, which is implemented by alevin, is fairly effective and does not require any read mapping or quantification before filtering. More recent versions of Cell Ranger use a somewhat different method based on the “empty drops” method of Lun et al. (2019), that is applied after initial gene quantification. This allows filtering to retain cells with low counts that are nonetheless likely to represent real cells.

Next steps: Loading Alevin output into R

After we have successfully quantified our tag-based scRNA-seq data (and done some QC), we will want to read it into R to start to analyze it. The easiest way to do this is to use the tximeta package, which we will introduce in the next notebook.

Session Info

sessionInfo()
R version 4.4.1 (2024-06-14)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 22.04.4 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so;  LAPACK version 3.10.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

time zone: Etc/UTC
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] optparse_1.7.5

loaded via a namespace (and not attached):
 [1] digest_0.6.35     R6_2.5.1          fastmap_1.1.1     xfun_0.43        
 [5] magrittr_2.0.3    cachem_1.0.8      getopt_1.20.4     glue_1.7.0       
 [9] stringr_1.5.1     knitr_1.46        htmltools_0.5.8.1 rmarkdown_2.26   
[13] lifecycle_1.0.4   cli_3.6.2         sass_0.4.9        vctrs_0.6.5      
[17] jquerylib_0.1.4   compiler_4.4.1    tools_4.4.1       bslib_0.7.0      
[21] evaluate_0.23     yaml_2.3.8        jsonlite_1.8.8    rlang_1.1.3      
[25] stringi_1.8.3    
LS0tCnRpdGxlOiAiUHJvY2Vzc2luZyB0YWctYmFzZWQgc2luZ2xlLWNlbGwgUk5BLXNlcSBkYXRhIHdpdGggQWxldmluIgphdXRob3I6IENDREwgZm9yIEFMU0YKZGF0ZTogMjAyMQpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KCiMjIE9iamVjdGl2ZXMKClRoaXMgbm90ZWJvb2sgd2lsbCBkZW1vbnN0cmF0ZSBob3cgdG86CgotIE5hdmlnYXRlIHRoZSB0ZXJtaW5hbCBpbnRlcmZhY2UKLSBRdWFudGlmeSBzaW5nbGUgY2VsbCBleHByZXNzaW9uIGRhdGEgd2l0aCBBbGV2aW4gCi0gUGVyZm9ybSBiYXNpYyBxdWFsaXR5IGNvbnRyb2wgYW5kIGludGVycHJldCByZXN1bHRzIAoKLS0tCgpJbiB0aGlzIG5vdGVib29rLCB3ZSB3aWxsIGJlIHJ1bm5pbmcgdGhyb3VnaCB0aGUgYmFzaWNzIG9mIHByb2Nlc3NpbmcgcmF3IHNpbmdsZS1jZWxsIFJOQS1zZXEgZGF0YS4KCldlIHdpbGwgYmUgdXNpbmcgYSB0YWctYmFzZWQgc2NSTkEtc2VxIHNhbXBsZSBmcm9tIHRoZSBbKlRhYnVsYSBNdXJpcyogcHJvamVjdF0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE1ODYtMDE4LTA1OTAtNCkuClRoaXMgZGF0YXNldCBpcyBtYWRlIG9mIDIwIG1vdXNlIG9yZ2FucyB0aGF0IHdlcmUgc2VxdWVuY2VkIHVzaW5nIDEweCBHZW5vbWljcyBDaHJvbWl1bSBzaW5nbGUgY2VsbCBzZXF1ZW5jaW5nIG1ldGhvZHMuCkZvciAxMHggR2Vub21pY3Mgc2NSTkEtc2VxIGRhdGEsIGNlbGxzIGFyZSBzZXBhcmF0ZWQgYnkgZW11bHNpb24vZHJvcGxldHMsIGFuZCBpbmRpdmlkdWFsIGNlbGxzIGFyZSBnaXZlbiBiYXJjb2RlcyAob2Z0ZW4gYWJicmV2aWF0ZWQgJ0NCJyBpbiBkb2N1bWVudGF0aW9uKS4KRWFjaCB0cmFuc2NyaXB0IHdpbGwgYWxzbyBjb250YWluIGEgW1VuaXF1ZSBNb2xlY3VsYXIgSWRlbnRpZmllcnMgKFVNSXMpXShodHRwOi8vd3d3Lm5hdHVyZS5jb20vZG9pZmluZGVyLzEwLjEwMzgvbm1ldGguMjc3Mikgd2hpY2ggYWxsb3cgdXMgdG8gZXhhbWluZSBQQ1IgYW1wbGlmaWNhdGlvbiBlcnJvcnMgYW5kIGJpYXNlcy4KCiFbUm9hZG1hcDogUHJlcHJvY2Vzc2luZyAmIEluaXRpYWwgUUNdKGRpYWdyYW1zL3JvYWRtYXBfc2luZ2xlX3ByZXByb2Nlc3NfcWMucG5nKQoKIyMgQWJvdXQgdGhlIGRhdGEKCldlIG9idGFpbmVkIHRoZXNlIGRhdGEgZnJvbSBUYWJ1bGEgTXVyaXMgcHJvamVjdCdzIFtGaWdzaGFyZV0oaHR0cHM6Ly9maWdzaGFyZS5jb20vcHJvamVjdHMvVGFidWxhX011cmlzX1RyYW5zY3JpcHRvbWljX2NoYXJhY3Rlcml6YXRpb25fb2ZfMjBfb3JnYW5zX2FuZF90aXNzdWVzX2Zyb21fTXVzX211c2N1bHVzX2F0X3NpbmdsZV9jZWxsX3Jlc29sdXRpb24vMjc3MzMpLgpUaGUgQkFNIGZpbGVzIHRoYXQgd2VyZSBvbiBGaWdzaGFyZSB3ZXJlIGNvbnZlcnRlZCB0byBgZmFzdHFgIGZpbGVzIHVzaW5nCltgYmFtdG9mYXN0cWBdKGh0dHBzOi8vc3VwcG9ydC4xMHhnZW5vbWljcy5jb20vZG9jcy9iYW10b2Zhc3RxKSBmcm9tIDEweCBHZW5vbWljcy4KV2Ugd2lsbCBwcm9jZXNzIGEgYGZhc3RxYCBmaWxlIGZyb20gbW91c2UgYmxhZGRlciBmb3IgdGhpcyBhcyBhbiBleGFtcGxlLiAgClRvIGxpbWl0IHRoZSBhbW91bnQgb2YgdGltZSB0aGlzIHRha2VzIHRvIHJ1biBpbiB0aGUgY29udGV4dCBvZiB0aGlzIHdvcmtzaG9wLAp3ZSBhcmUgb25seSBydW5uaW5nIHBhcnQgb2YgdGhlIHNhbXBsZSdzIHJlYWRzLgoKKk5vdGUqOiBEZXBlbmRpbmcgb24gdGhlIGZvcm1hdCBvZiB0aGUgZGF0YSB5b3UgYXJlIHdvcmtpbmcgd2l0aCwgaS5lLiwgaWYgeW91IGhhdmUgYSBzZXQgb2YgYC5iY2xgIGZpbGVzLCB5b3UgbWF5IG5lZWQgdG8gdXNlIFtgY2VsbHJhbmdlciBta2Zhc3RxYF0oaHR0cHM6Ly9zdXBwb3J0LjEweGdlbm9taWNzLmNvbS9zaW5nbGUtY2VsbC1nZW5lLWV4cHJlc3Npb24vc29mdHdhcmUvcGlwZWxpbmVzL2xhdGVzdC91c2luZy9ta2Zhc3RxKSB0byBjcmVhdGUgYC5mYXN0cWAgZmlsZXMgZm9yIGVhY2ggc2FtcGxlLgpIb3dldmVyLCBtb3N0IHB1YmxpYyBkYXRhIGlzIGF2YWlsYWJsZSBpbiBgZmFzdHFgIGZvcm1hdCwgYW5kIG1vc3Qgc2VxdWVuY2luZyBjb3JlcyB3aWxsIGdlbmVyYXRlIHRoZSBgLmZhc3RxYCBmaWxlcywgc28gdGhhdCBpcyB3aGVyZSB3ZSB3aWxsIHN0YXJ0LgoKCiMjIENoZWNraW5nIGRpcmVjdG9yaWVzIGFuZCBmaWxlcwoKSWYgeW91IGhhdmUgb3BlbmVkIHRoZSBgc2NSTkEtc2VxLlJwcm9qYCBmaWxlLCB5b3VyIFRlcm1pbmFsIHNob3VsZCBhbHJlYWR5IGJlIHNldCB0byB0aGUgYHNjUk5BLXNlcWAgZGlyZWN0b3J5LCBidXQgaXQgaXMgd29ydGggY2hlY2tpbmcgd2l0aCB0aGUgYHB3ZGAgY29tbWFuZCBpbiB0aGUgVGVybWluYWwgCihvciBieSBsb29raW5nIGF0IHRoZSBwYXRoIHNob3duIGluIHRoZSBjb21tYW5kIHByb21wdCBvciBhdCB0aGUgdG9wIG9mIHRoZSBUZXJtaW5hbCBwYW5lKS4gCgpJZiB5b3UgYXJlIGluIGEgZGlmZmVyZW50IGRpcmVjdG9yeSwgd2Ugd2lsbCB3YW50IHRvIHVzZSBgY2RgIHRvIGNoYW5nZSB0byB0aGUgYHRyYWluaW5nLW1vZHVsZXMvc2NSTkEtc2VxYCBkaXJlY3RvcnkuIAoKQ29weSBhbmQgcGFzdGUgdGhlIHRleHQgaW4gdGhlIGNvZGUgYmxvY2tzIGJlbG93IGludG8geW91ciBgVGVybWluYWxgIHdpbmRvdyBpbiBSU3R1ZGlvLgpJdCBzaG91bGQgYmUgaW4gdGhlIGxvd2VyIGxlZnQgaGFuZCBjb3JuZXIgYXMgYSB0YWIgbmV4dCB0byBgQ29uc29sZWAuCgpgYGBiYXNoCmNkIH4vdHJhaW5pbmctbW9kdWxlcy9zY1JOQS1zZXEKYGBgCgpPbmNlIHlvdSBhcmUgdGhlcmUsIHlvdSBzaG91bGQgYmUgYWJsZSB0byBydW4gdGhlIGZvbGxvd2luZyBjb21tYW5kIGluIHRoZSBUZXJtaW5hbCB0byBsb29rIGF0IHRoZSBjb250ZW50cyBvZiB0aGUgYGRhdGEvdGFidWxhLW11cmlzYCBkaXJlY3Rvcnk6CgpgYGBiYXNoCmxzIGRhdGEvdGFidWxhLW11cmlzCmBgYAoKSGVyZSB5b3Ugd2lsbCBzZWUgdGhlIGBmYXN0cWAgZGlyZWN0b3J5LCB3aGljaCBpcyBhY3R1YWxseSBhIGxpbmsgdG8gYSBzaGFyZWQgZm9sZGVyIHdpdGggdGhlIHJhdyBmYXN0cSBmaWxlcywgc3BsaXQgYnkgc2FtcGxlLgpXZSB3aWxsIHVzZSB0aGVzZSBmaWxlcywgYnV0IHdlIHdpbGwgbm90IHdyaXRlIHRvIHRoaXMgZGlyZWN0b3J5LiAKCldlIGNhbiBsb29rIGluc2lkZSB0aGUgY29udGVudHMgb2YgdGhlIGBmYXN0cWAgZGlyZWN0b3J5LCBhbmQgd2Ugc2hvdWxkIHNlZSAxNiBzdWJmb2xkZXJzIGNvcnJlc3BvbmRpbmcgdG8gMTYgZGlmZmVyZW50IHNhbXBsZXMuIApXaXRoaW4gZWFjaCBvZiB0aGVzZSBmb2xkZXJzIHNob3VsZCBiZSB0aGUgYGZhc3RxYCBmaWxlcyBhc3NvY2lhdGVkIHdpdGggdGhhdCBzYW1wbGUuIApBZ2Fpbiwgd2UgY2FuIHVzZSB0aGUgYGxzYCBjb21tYW5kIHRvIHNob3cgdGhlIGNvbnRlbnRzIG9mIGVhY2ggb2YgdGhlIGRpcmVjdG9yaWVzLiAKCkluIHRoaXMgc2NlbmFyaW8sIGAxMFhfUDRfM2AgcmVmZXJzIHRvIHRoZSBzYW1wbGUgbmFtZSB0aGF0IHdlIHdpbGwgYmUgcHJvY2Vzc2luZywgd2hpY2ggY29udGFpbnMgZGF0YSBmcm9tIG1vdXNlIGJsYWRkZXIgY2VsbHMuCgpgYGBiYXNoCmxzIGRhdGEvdGFidWxhLW11cmlzL2Zhc3RxLzEwWF9QNF8zCmBgYAoKWW91IHNob3VsZCBzZWUgYSBsaXN0IG9mIG11bHRpcGxlIGBmYXN0cWAgZmlsZXMgYWxsIHN0YXJ0aW5nIHdpdGggYDEwWF9QNF8zYCwgaW5kaWNhdGluZyB0aGUgc2FtcGxlIG5hbWUuIAoKSWYgeW91IG5vdGljZSwgZWFjaCBgZmFzdHFgIGZpbGUgbmFtZSBjb250YWlucyBlaXRoZXIgYFIxYCBvciBgUjJgLgpUaGVzZSBjb3JyZXNwb25kIHRvIHRoZSB0d28gc2VxdWVuY2luZyByZWFkcyBvZiBhIHBhaXJlZC1lbmQgbGlicmFyeS4KRm9yIDEweCBkYXRhLCB0aGUgZmlyc3QgcmVhZCAodGhlIGBSMWAgZmlsZSkgd2lsbCBjb250YWluIHRoZSBjZWxsIGJhcmNvZGUgYW5kIFVNSSBzZXF1ZW5jZSwgYW5kIHRoZSBzZWNvbmQgcmVhZCAodGhlIGBSMmAgZmlsZSkgd2lsbCBjb250YWluIGEgY0ROQSBzZXF1ZW5jZSBjb3JyZXNwb25kaW5nIHRvIHRoZSBjYXB0dXJlZCB0cmFuc2NyaXB0LgpXZSB3aWxsIG5lZWQgYm90aCBvZiB0aGVzZSBmaWxlcyB0byBxdWFudGlmeSBvdXIgZGF0YS4gCgpgYGAKMTBYX1A0XzNfTDAwMV9SMV8wMDEuZmFzdHEuZ3ogIDEwWF9QNF8zX0wwMDJfUjFfMDAxLmZhc3RxLmd6CjEwWF9QNF8zX0wwMDFfUjFfMDAyLmZhc3RxLmd6ICAxMFhfUDRfM19MMDAyX1IxXzAwMi5mYXN0cS5negoxMFhfUDRfM19MMDAxX1IxXzAwMy5mYXN0cS5neiAgMTBYX1A0XzNfTDAwMl9SMV8wMDMuZmFzdHEuZ3oKMTBYX1A0XzNfTDAwMV9SMl8wMDEuZmFzdHEuZ3ogIDEwWF9QNF8zX0wwMDJfUjJfMDAxLmZhc3RxLmd6CjEwWF9QNF8zX0wwMDFfUjJfMDAyLmZhc3RxLmd6ICAxMFhfUDRfM19MMDAyX1IyXzAwMi5mYXN0cS5negoxMFhfUDRfM19MMDAxX1IyXzAwMy5mYXN0cS5neiAgMTBYX1A0XzNfTDAwMl9SMl8wMDMuZmFzdHEuZ3oKYGBgCgpTZXF1ZW5jaW5nIHJ1bnMgYXJlIG9mdGVuIHNwbGl0IGludG8gbXVsdGlwbGUgYGZhc3RxYCBmaWxlcywgYm90aCB3aGVuIGEgc2FtcGxlIHdhcyBydW4gYWNyb3NzIG11bHRpcGxlIGxhbmVzIGFuZCB0byBrZWVwIHRoZSBpbmRpdmlkdWFsIGZpbGUgc2l6ZXMgZG93bi4gClRoaXMgd2FzIHRoZSBjYXNlIGZvciB0aGUgKlRhYnVsYSBNdXJpcyogZGF0YSB3ZSBhcmUgdXNpbmcgaGVyZSBhcyB3ZWxsLiAKVGhlIGZpbGVzIHRoYXQgeW91IHNlZSBpbiB0aGUgYGRhdGEvdGFidWxhLW11cmlzL2Zhc3RxLzEwWF9QNF8zYCBkaXJlY3Rvcnkgc2hvd24gYWJvdmUgcmVwcmVzZW50IDIgbGFuZXMgd29ydGggb2YgZGF0YSwgd2l0aCB0aHJlZSBSMSBhbmQgdGhyZWUgUjIgZmlsZXMgcGVyIGxhbmUuCgpZb3Ugd2lsbCBhbHNvIHNlZSB0aGUgZmlsZSBgVE1fZHJvcGxldF9tZXRhZGF0YS5jc3ZgLCB3aGljaCBjb250YWlucyBtZXRhZGF0YSBmb3IgdGhlICpUYWJ1bGEgTXVyaXMqIGV4cGVyaW1lbnRzLgoKIyMjIFNldCB1cCBvdXRwdXQgZGlyZWN0b3J5CgpOb3cgdGhhdCB3ZSBhcmUgaW4gYHNjUk5BLXNlcWAsIHdlJ2xsIG1ha2UgYSBkaXJlY3RvcnkgZm9yIHVzIHRvIHN0b3JlIG91ciBxdWFudGlmaWNhdGlvbiBmaWxlcyBpbi4KSW4gYFRlcm1pbmFsYCwgcnVuIHRoZSBmb2xsb3dpbmcgY29tbWFuZDoKCmBgYGJhc2gKbWtkaXIgLXAgZGF0YS90YWJ1bGEtbXVyaXMvYWxldmluLXF1YW50LzEwWF9QNF8zX3N1YnNldApgYGAKCiMjIFF1YW50aWZ5aW5nIGNlbGwgZXhwcmVzc2lvbiB3aXRoIFNhbG1vbiBBbGV2aW4KCltBbGV2aW5dKGh0dHBzOi8vZ2Vub21lYmlvbG9neS5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L3MxMzA1OS0wMTktMTY3MC15KSBpcyBydW4gZnJvbSB0aGUgY29tbWFuZCBsaW5lIChUZXJtaW5hbCkgdG8gcGVyZm9ybSBtYXBwaW5nIGFuZCBxdWFudGlmaWNhdGlvbiBvZiB0YWctYmFzZWQgc2luZ2xlIGNlbGwgZXhwcmVzc2lvbiBkYXRhLiAKCiMjIyBJbmRleGluZyB0aGUgbW91c2UgdHJhbnNjcmlwdG9tZSAKCkJlZm9yZSB5b3UgY2FuIHF1YW50aWZ5IHdpdGggU2FsbW9uIGFuZCBbQWxldmluXShodHRwczovL2dlbm9tZWJpb2xvZ3kuYmlvbWVkY2VudHJhbC5jb20vYXJ0aWNsZXMvMTAuMTE4Ni9zMTMwNTktMDE5LTE2NzAteSkgd2UgbmVlZCB0byBpbmRleCB0aGUgdHJhbnNjcmlwdG9tZSBmb3IgdGhlIHNwZWNpZXMgd2Ugd2lsbCBiZSBtYXBwaW5nIHRvLgpUaGlzIHN0ZXAgd291bGQgYmUgdGhlIHNhbWUgZm9yIG1hcHBpbmcgYnVsayBSTkEtc2VxIGRhdGEsIGFuZCB5b3UgY2FuIHVzZSB0aGUgc2FtZSB0cmFuc2NyaXB0b21lIGluZGV4ZXMgYXMgYnVsayBSTkEtc2VxLCBob3dldmVyLCBkdWUgdG8gdGhlIHNob3J0ZXIgcmVhZCBsZW5ndGhzIGluIHRoZSAxMHggc2VxdWVuY2luZywgd2UgbWF5IHdhbnQgdG8gdXNlIHNob3J0ZXIga21lcnMgdGhhbiB0aGUgZGVmYXVsdCBpbmRleCBzaXplIHRoYXQgc2FsbW9uIHVzZXMuCkluIHRoaXMgaW5zdGFuY2UsIHdlIHVzZWQgYSBgLWtgIG9mIDIzLgoKSW4gdGhlIGludGVyZXN0IG9mIHRpbWUsIHdlIGhhdmUgYWxyZWFkeSBydW4gdGhlIGNvbW1hbmQgYmVsb3cgYW5kIGhhdmUgdGhlIGluZGV4IGJ1aWx0IGFuZCByZWFkeSBmb3IgeW91IGluIGEgc2hhcmVkIGRpcmVjdG9yeS4KCkJ1dCBmb3IgeW91ciBvd24gcmVmZXJlbmNlLCBoZXJlIGlzIGhvdyB5b3UgbWlnaHQgZG8gaXQgeW91cnNlbGY6CmBgYAojIHNhbG1vbiAtLXRocmVhZHM9MTYgLS1uby12ZXJzaW9uLWNoZWNrIGluZGV4IFwKIyAgLXQgTXVzX211c2N1bHVzLkdSQ20zOC5jZG5hLmFsbC5mYS5neiBcCiMgIC1pIGluZGV4L011c19tdXNjdWx1cy9zaG9ydF9pbmRleCBcCiMgIC1rIDIzCmBgYAoKU2NyaXB0cyB0byBidWlsZCB0aGUgaW5kZXhlcyBsaWtlIHRob3NlIHdlIGFyZSB1c2luZyBoZXJlIChhbmQgb3RoZXJzKSBjYW4gYmUgZm91bmQgaW4gW3RoaXMgcmVwb3NpdG9yeV0oaHR0cHM6Ly9naXRodWIuY29tL0FsZXhzTGVtb25hZGUvdHJhaW5pbmctdHhvbWUtcHJlcCkuIAoKCiMjIyBSdW5uaW5nIFNhbG1vbiBBbGV2aW4KCkNvcHkgYW5kIHBhc3RlIHRoaXMgaW4geW91ciBgVGVybWluYWxgIHRvIHJ1biB0aGUgQWxldmluIHF1YW50aWZpY2F0aW9uLgpUaGlzIHdpbGwgdGFrZSBhYm91dCAyMCBtaW51dGVzIHRvIHJ1biwgc28gd2Ugd2lsbCBzdGFydCBub3csIHRoZW4gdGFsayBhYm91dCB0aGUgb3B0aW9ucy4KCk5vdGUgdGhhdCBoZXJlIHdlIGFyZSBvbmx5IGdpdmluZyB0aGUgZnVsbCBwYXRocyB0byBvbmUgb2YgdGhlIGBSMWAgZmlsZXMgYW5kIG9uZSBvZiB0aGUgYFIyYCBmaWxlcy4gCkZvciB0aGUgc2FrZSBvZiB0aW1lLCB3ZSBhcmUgb25seSBnb2luZyB0byBiZSBydW5uaW5nIHRoaXMgb24gYSBzdWJzZXQgb2YgcmVhZHMsIGJ1dCB3aWxsIGFsc28gc2hvdyB5b3UgaG93IHRvIHJ1biBpdCBvbiB0aGUgZnVsbCBzYW1wbGUuICAKCmBgYGJhc2gKc2FsbW9uIGFsZXZpbiBcCiAgLWkgaW5kZXgvTXVzX211c2N1bHVzL3Nob3J0X2luZGV4IFwKICAtbCBJU1IgXAogIC0xIGRhdGEvdGFidWxhLW11cmlzL2Zhc3RxLzEwWF9QNF8zLzEwWF9QNF8zX0wwMDFfUjFfMDAxLmZhc3RxLmd6IFwKICAtMiBkYXRhL3RhYnVsYS1tdXJpcy9mYXN0cS8xMFhfUDRfMy8xMFhfUDRfM19MMDAxX1IyXzAwMS5mYXN0cS5neiBcCiAgLW8gZGF0YS90YWJ1bGEtbXVyaXMvYWxldmluLXF1YW50LzEwWF9QNF8zX3N1YnNldCBcCiAgLXAgNCBcCiAgLS1jaHJvbWl1bSAgXAogIC0tdGdNYXAgaW5kZXgvTXVzX211c2N1bHVzL011c19tdXNjdWx1cy5HUkNtMzguOTUudmVyc2lvbmVkX3R4MmdlbmUudHN2IFwKICAtLWR1bXBGZWF0dXJlcwpgYGAKCiMjIyBTYWxtb24gQWxldmluIGNvbW1hbmQgbGluZSBvcHRpb25zCgpGb3IgZGV0YWlsZWQgaW5mb3JtYXRpb24gYWJvdXQgYWxsIG9wdGlvbnMgYXZhaWxhYmxlIHNlZSB0aGUgW0FsZXZpbiBkb2N1bWVudGF0aW9uXShodHRwczovL3NhbG1vbi5yZWFkdGhlZG9jcy5pby9lbi9sYXRlc3QvYWxldmluLmh0bWwpIGFuZCBbU2FsbW9uIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vc2FsbW9uLnJlYWR0aGVkb2NzLmlvL2VuL2xhdGVzdC9zYWxtb24uaHRtbCkuCgpNYW55IG9mIHRoZSBvcHRpb25zIGZvciB0aGUgYHNhbG1vbiBhbGV2aW5gIGNvbW1hbmQgYXJlIHRoZSBzYW1lIGFzIHRob3NlIHlvdSB3b3VsZCBzZWUgd2hlbiBtYXBwaW5nIGFuZCBxdWFudGlmeWluZyBidWxrIFJOQS1zZXEgZGF0YSB3aXRoIGBzYWxtb24gcXVhbnRgOgoKLSBgLWlgIGdpdmVzIHRoZSBsb2NhdGlvbiBvZiB0aGUgdHJhbnNjcmlwdG9tZSBpbmRleAotIGAtMWAgYW5kIGAtMmAgYXJlIHRoZSBwYWlyZWQgcmVhZCBpbnB1dCBmaWxlcwotIGAtb2AgZGVzaWduYXRlcyB0aGUgb3V0cHV0IGZvbGRlcgotIGAtcGAgYWxsb3dzIHVzIHRvIHNwZWNpZnkgaG93IG1hbnkgcHJvY2Vzc29ycyB0byB1c2U7IGluIHRoaXMgY2FzZSB3ZSB3aWxsIHVzZSA0CgoKIyMjIyBgLWxgClRoZSBgLWxgIG9wdGlvbiBpcyBmb3IgZGVzaWduYXRpbmcgdGhlIGxpYnJhcnkgZm9ybWF0LiAKRm9yIG1vc3Qgc2luZ2xlLWNlbGwgcXVhbnRpZmljYXRpb24sIHlvdSB3aWxsIHdhbnQgdG8gdXNlIHRoZSBgSVNSYCBsaWJyYXJ5IHR5cGUuClNlZSBbU2FsbW9uJ3MgZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9zYWxtb24ucmVhZHRoZWRvY3MuaW8vZW4vbGF0ZXN0L2xpYnJhcnlfdHlwZS5odG1sI2ZyYWdsaWJ0eXBlKSBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBmcmFnbWVudCBsaWJyYXJ5IHR5cGVzIChhbmQgYWxsIG9mIHRoZSBvdGhlciBvcHRpb25zIGF2YWlsYWJsZSkuCk5vdGUgdGhhdCB0aGlzIG9wdGlvbiBtdXN0IGNvbWUgKmJlZm9yZSogdGhlIHJlYWQgZmlsZXMuCgojIyMjIGAtLWNocm9taXVtYApCZWNhdXNlIHdlIGFyZSB1c2luZyAxMHggdjIgY2hyb21pdW0gZGF0YSwgd2UgaGF2ZSB0byB1c2UgdGhpcyBmbGFnIHRvIHRlbGwgYGFsZXZpbmAgd2hlcmUgdG8gZXhwZWN0IHRoZSBiYXJjb2RlcywgVU1JcyBhbmQgc2VxdWVuY2UgZGF0YS4KSWYgd2Ugd2VyZSB1c2luZyAxMHggdjMgZGF0YSwgd2Ugd291bGQgbmVlZCB0aGUgYC0tY2hyb21pdW1WM2AgZmxhZyBpbnN0ZWFkLiAKRHJvcC1zZXEgZGF0YSBpcyBhbHNvIHN1cHBvcnRlZCwgZm9yIHdoaWNoIHdlIHdvdWxkIHVzZSB0aGUgYC0tZHJvcHNlcWAgZmxhZyBpbnN0ZWFkIG9mIHRoaXMuCgoKIyMjIyBgLS10Z01hcGAKVGhlIHRyYW5zY3JpcHRvbWUgZmlsZSB0aGF0IHdlIGFyZSBtYXBwaW5nIHRvIGhhcyBzZXBhcmF0ZSBzZXF1ZW5jZXMgZm9yIGVhY2ggdHJhbnNjcmlwdCBvZiBhIGdlbmUsIGJ1dCBkdWUgdG8gdGhlIHNwYXJzZSBuYXR1cmUgb2Ygc2luZ2xlLWNlbGwgZGF0YSwgd2UgYXJlIG5vdCBsaWtlbHkgdG8gYmUgYWJsZSB0byBtZWFuaW5nZnVsbHkgZGlzdGluZ3Vpc2ggYW1vbmcgZGlmZmVyZW50IHRyYW5zY3JpcHRzLgpGb3IgdGhpcyByZWFzb24sIGBhbGV2aW5gIHdpbGwgcXVhbnRpZnkgb3VyIHJlc3VsdHMgYXQgdGhlIGdlbmUgbGV2ZWwsIHNvIHdlIG5lZWQgdG8gcHJvdmlkZSBhIGZpbGUgdGhhdCBtYXBzIGVhY2ggdHJhbnNjcmlwdCB0byBpdHMgZ2VuZS4KRm9yIHRoaXMgZXhhbXBsZSwgd2UndmUgcHJlLW1hZGUgdGhlIGZpbGUgYE11c19tdXNjdWx1cy5HUkNtMzguOTUudmVyc2lvbmVkX3R4MmdlbmUudHN2YCBmcm9tIHRoZSBFbnNlbWJsIHRyYW5zY3JpcHRvbWUgdGhhdCB3ZSBpbmRleGVkIGFib3ZlLiAKVGhlIGZpbGUgaXMgYSBUU1YgKHRhYi1zZXBhcmF0ZWQgdmFsdWVzKSBmaWxlIHdpdGggMiBjb2x1bW5zOiBvbmUgb2YgdHJhbnNjcmlwdHMgYW5kIHRoZSBvdGhlciB0aGUgZ2VuZSB0aGF0IGVhY2ggY29tZXMgZnJvbS4KCgojIyMjIGAtLWR1bXBGZWF0dXJlc2AKVGhpcyBvcHRpb24gd2lsbCBwcmludCBvdXQgaW5mb3JtYXRpb24gdGhhdCB3ZSB3aWxsIHVzZSBmb3IgcXVhbGl0eSBjaGVja3MgbGF0ZXIgb24sIGluY2x1ZGluZyBmaWxlcyB3aXRoIGluZm9ybWF0aW9uIG9uIHRoZSBVTUlzIGFuZCBjZWxsIGJhcmNvZGVzLgoKU2VlIHRoZSBbQWxldmluIGRvY3VtZW50YXRpb25dKGh0dHBzOi8vc2FsbW9uLnJlYWR0aGVkb2NzLmlvL2VuL2xhdGVzdC9hbGV2aW4uaHRtbCkgZm9yIGEgY29tcGxldGUgbGlzdCBvZiB0aGUgQWxldmluIG9wdGlvbnMuClRoZXJlIGFyZSBhbHNvIGEgbnVtYmVyIG9mIGV4YW1wbGUgYW5hbHlzZXMgYXQgdGhlIFtBbGV2aW4gdHV0b3JpYWxdKGh0dHBzOi8vY29tYmluZS1sYWIuZ2l0aHViLmlvL2FsZXZpbi10dXRvcmlhbC8pIHdlYnNpdGUuCgoKIyMjIE5vdGU6IFJ1bm5pbmcgdGhlIEZVTEwgc2FtcGxlLgoKV2hlbiB3ZSB0b29rIGEgbG9vayBhdCB0aGUgYGRhdGEvdGFidWxhLW11cmlzL2Zhc3RxLzEwWF9QNF8zYCBkaXJlY3RvcnkgZWFybGllciwgd2Ugbm90aWNlZCB0aGF0IHRoZXJlIHdlcmUgbXVsdGlwbGUgZmlsZXMgcmVwcmVzZW50aW5nIDIgbGFuZXMgd29ydGggb2YgZGF0YSwgd2l0aCB0aHJlZSBSMSBhbmQgdGhyZWUgUjIgZmlsZXMgcGVyIGxhbmU6CgpXZSBzaG91bGQgcmVhbGx5IHJ1biBhbGwgb2YgdGhlc2UgdGhyb3VnaCBTYWxtb24sIHRob3VnaCB0aGF0IHdpbGwgdGFrZSBhYm91dCBzaXggdGltZXMgYXMgbG9uZyBhcyB0aGUgc2luZ2xlIHBhaXIgb2YgcmVhZHMgd2UgdXNlZC4gClRvIGRvIHRoaXMsIHdlIGNvdWxkIGxpc3QgZWFjaCBSMSBhbmQgUjIgZmlsZSAoc3BhY2Ugc2VwYXJhdGVkKSBhZnRlciB0aGUgYC0xYCBhbmQgYC0yYCBhcmd1bWVudHMsIHJlc3BlY3RpdmVseS4KQnV0IHRoYXQgaXMgYSBsb3Qgb2YgdHlwaW5nLCBzbyBhIG5pY2Ugc2hvcnRjdXQgaXMgdG8gdXNlIGEgYCpgIGNoYXJhY3RlciB0byByZXByZXNlbnQgYSB3aWxkY2FyZCB0aGF0IHdpbGwgYmUgZmlsbGVkIGluIHdpdGggd2hhdGV2ZXIgY2hhcmFjdGVycyBhcmUgcHJlc2VudCBpbiB0aGUgZmlsZXMgYXQgdGhlIGdpdmVuIHBhdGguCkluIHRoZSBwYXR0ZXJuIGAxMFhfUDRfM19MKl9SMV8qLmZhc3RxLmd6YCwgdGhpcyB3b3VsZCBhbGxvdyBhbnkgbGFuZSBudW1iZXIgYW5kIGFueSBzdWJzZXQsIHNvIHdvdWxkIG1hdGNoIGFsbCBvZiB0aGUgZm9sbG93aW5nIGZpbGVzIChhbGwgdGhlIFIxIGZpbGVzIGluIHRoaXMgY2FzZSk6CgpgYGAKMTBYX1A0XzNfTDAwMV9SMV8wMDEuZmFzdHEuZ3ogIDEwWF9QNF8zX0wwMDJfUjFfMDAxLmZhc3RxLmd6CjEwWF9QNF8zX0wwMDFfUjFfMDAyLmZhc3RxLmd6ICAxMFhfUDRfM19MMDAyX1IxXzAwMi5mYXN0cS5negoxMFhfUDRfM19MMDAxX1IxXzAwMy5mYXN0cS5neiAgMTBYX1A0XzNfTDAwMl9SMV8wMDMuZmFzdHEuZ3oKYGBgCgpGb3IgdGhpcyBkaXJlY3RvcnksIHRoYXQgd291bGQgbWFrZSBvdXIgZnVsbCBgc2FsbW9uIGFsZXZpbmAgY29tbWFuZCBsb29rIGxpa2UgdGhpcyAoZG9uJ3QgcnVuIHRoaXMgbm93ISk6CgpgYGAKIyBzYWxtb24gYWxldmluIFwKIyAgIC1pIGluZGV4L011c19tdXNjdWx1cy9zaG9ydF9pbmRleCBcCiMgICAtbCBJU1IgXAojICAgLTEgZGF0YS90YWJ1bGEtbXVyaXMvZmFzdHEvMTBYX1A0XzMvMTBYX1A0XzNfTCpfUjFfKi5mYXN0cS5neiBcCiMgICAtMiBkYXRhL3RhYnVsYS1tdXJpcy9mYXN0cS8xMFhfUDRfMy8xMFhfUDRfM19MKl9SMl8qLmZhc3RxLmd6IFwKIyAgIC1vIGRhdGEvdGFidWxhLW11cmlzL2FsZXZpbi1xdWFudC8xMFhfUDRfMyBcCiMgICAtcCA0IFwKIyAgIC0tY2hyb21pdW0gIFwKIyAgIC0tdGdNYXAgaW5kZXgvTXVzX211c2N1bHVzL011c19tdXNjdWx1cy5HUkNtMzguOTUudmVyc2lvbmVkX3R4MmdlbmUudHN2IFwKIyAgIC0tZHVtcEZlYXR1cmVzCmBgYAoKSW4gZ2VuZXJhbCwgeW91IHdpbGwgd2FudCB0byBydW4gYWxsIGxhbmVzIGFuZCBhbGwgZmlsZXMgZm9yIGEgZ2l2ZW4gc2FtcGxlIHRvZ2V0aGVyLgpCdXQgKipETyBOT1QqKiBjb21iaW5lIG11bHRpcGxlICpzYW1wbGVzKiBpbnRvIGEgc2luZ2xlIGBhbGV2aW5gIHF1YW50aWZpY2F0aW9uIQpLZWVwIHNlcGFyYXRlIHNhbXBsZXMgKGFuZCByZXBsaWNhdGVzKSBzZXBhcmF0ZSEKCiMjIEluaXRpYWwgcXVhbGl0eSBjb250cm9sIHdpdGggYGFsZXZpblFDYAoKTm93IHRoYXQgd2UgaGF2ZSBxdWFudGlmaWVkIG91ciBkYXRhIHdpdGggQWxldmluLCB3ZSBhcmUgcmVhZHkgdG8gcGVyZm9ybSBpbml0aWFsIHF1YWxpdHkgY29udHJvbCBjaGVja3MuCgpJbiBvcmRlciB0byBwZXJmb3JtIHRoZXNlIHF1YWxpdHkgY29udHJvbCBjaGVja3MsIHdlJ2xsIHVzZSB0aGUgYGFsZXZpblFDYCBSIHBhY2thZ2UuCk5vdGUgdGhhdCBgYWxldmluUUNgIGRlcGVuZHMgb24gZmlsZXMgdGhhdCB3ZSBnZXQgdXNpbmcgdGhlYC0tZHVtcEZlYXR1cmVzYCBvcHRpb24gaW4gQWxldmluLgoKQWJvdXQgdGhlIGBhbGV2aW5RQ1JlcG9ydCgpYCBmdW5jdGlvbjoKVGhlIGZpcnN0IGFyZ3VtZW50IG5lZWRzIHRvIGJlIHdoZXJlIHRoZSBzYW1wbGUncyBvdXRwdXQgZGF0YSB3YXMgcHV0IHdoZW4gQWxldmluIHdhcyBydW4gKGFzIGEgY2hhcmFjdGVyIHN0cmluZywgYWthIHVzaW5nIHF1b3RlcykuClRoZSByZXN0IG9mIGBhbGV2aW5RQ1JlcG9ydCgpYCdzIGFyZ3VtZW50cyB0ZWxsIFIgd2hlcmUgdG8gcHV0IHRoZSBvdXRwdXQgUUMgcmVwb3J0LgoKYGBge3IgYWxldmluUUMsIGV2YWwgPSBGQUxTRX0KIyBGaXJzdCwgZGVmaW5lIHBhdGggdG8gYWxldmluIG91dHB1dDoKYWxldmluX3BhdGggPC0gZmlsZS5wYXRoKCJkYXRhIiwgInRhYnVsYS1tdXJpcyIsICJhbGV2aW4tcXVhbnQiLCAiMTBYX1A0XzNfc3Vic2V0IikKCiMgUHJvZHVjZSBhIFFDIHJlcG9ydCBvZiByZXN1bHRzIGZvdW5kIGluIHRoZSBgYWxldmluX3BhdGhgIGRpcmVjdG9yeQphbGV2aW5RQzo6YWxldmluUUNSZXBvcnQoYWxldmluX3BhdGgsCiAgICAgICAgICAgICAgICAgICAgICAgICBzYW1wbGVJZCA9ICIxMFhfUDRfM19zdWJzZXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0RmlsZSA9ICIxMFhfUDRfM19zdWJzZXQtcWNfcmVwb3J0Lmh0bWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0RGlyID0gInFjLXJlcG9ydHMiKQpgYGAKCkxvb2sgZm9yIHRoZSBgMTBYX1A0XzNfc3Vic2V0LXFjX3JlcG9ydC5odG1sYCBmaWxlIGNyZWF0ZWQgaW4gdGhlIGBxYy1yZXBvcnRzYCBkaXJlY3RvcnkgdG8gZXhhbWluZSB0aGUgcXVhbGl0eSBvZiB5b3VyIGRhdGEgYW5kIHBlcmZvcm1hbmNlIG9mIEFsZXZpbi4KCldlIGhhdmUgYWxzbyBwbGFjZWQgYW4gZXhhbXBsZSBvZiBhIHBvb3IgcXVhbGl0eSBzYW1wbGUgYWxldmluUUMgcmVwb3J0IGluIHRoZSBgcWMtcmVwb3J0c2AgZGlyZWN0b3J5LCB3aXRoIHRoZSBuYW1lIGBCYWRfRXhhbXBsZV8xMFhfUDRfMl9xY19yZXBvcnQuaHRtbGAuCgpUaGlzIHJlcG9ydCB3aWxsIHNob3cgYSBmZXcga2V5IG1ldHJpY3MgdGhhdCBpbmZvcm0geW91IGFib3V0IHRoZSBxdWFsaXR5IG9mIHlvdXIgc2FtcGxlLiAKVGhlcmUgaXMgYSBsb3Qgb2YgaW5mb3JtYXRpb24gaW5jbHVkZWQgaW4gdGhlIHJlcG9ydCwgc28gc29tZSBrZXkgbWV0cmljcyB0byBub3RlIGFyZSBpbmNsdWRlZCBpbiB0aGUgYFN1bW1hcnkgdGFibGVzYDoKCi0gRnJhY3Rpb24gb2YgcmVhZHMgaW4gd2hpdGVsaXN0IGJhcmNvZGVzIAotIE1lYW4gbnVtYmVyIG9mIHJlYWRzIHBlciBjZWxsCi0gTWVkaWFuIG51bWJlciBvZiBkZXRlY3RlZCBnZW5lcyBwZXIgY2VsbCAKClRoZSBmcmFjdGlvbiBvZiByZWFkcyBpbiB3aGl0ZWxpc3QgYmFyY29kZXMgaXMgcGFydGljdWxhcmx5IGltcG9ydGFudCBhcyBhIGxvdyBwZXJjZW50YWdlIGhlcmUgbWVhbnMgdGhlIGxpYnJhcnkgY29udGFpbnMgbWFueSByZWFkcyB0aGF0IGRvIG5vdCBjb250YWluIHRoZSBleHBlY3RlZCBjZWxsIGJhcmNvZGVzLiAKVGhpcyBpcyBpbmRpY2F0aXZlIG9mIHBvb3Igc2luZ2xlLWNlbGwgY2FwdHVyZSBkdXJpbmcgbGlicmFyeSBjb25zdHJ1Y3Rpb24uIAoKVGhlIG1lYW4gbnVtYmVyIG9mIHJlYWRzIHBlciBjZWxsIGFuZCBtZWRpYW4gbnVtYmVyIG9mIGRldGVjdGVkIGdlbmVzIHBlciBjZWxsIGNhbiBiZSBoZWxwZnVsIGluIHVuZGVyc3RhbmRpbmcgaG93IGRlZXBseSB0aGUgbGlicmFyeSB3YXMgc2VxdWVuY2VkLiAKVGhlIGhpZ2hlciB0aGVzZSBudW1iZXJzIGFyZSwgdGhlIG1vcmUgaW5mb3JtYXRpb24geW91IHdpbGwgb2J0YWluIHBlciBjZWxsLiAKClRoZSAqKmtuZWUgcGxvdCoqIHNob3dzIHRoZSBudW1iZXIgb2YgZGlzdGluY3QgVU1JcyBmb3IgZWFjaCBwb3NzaWJsZSBjZWxsIGJhcmNvZGUgb24gdGhlIHktYXhpcywgd2l0aCB0aGUgYmFyY29kZXMgcmFua2VkIGZyb20gdGhlIG1vc3QgVU1JcyB0byB0aGUgZmV3ZXN0IGFsb25nIHRoZSB4LWF4aXMuCgpDZWxsIGJhcmNvZGVzIHdpdGggbG93IFVNSSBjb3VudHMgYXJlIGxpa2VseSB0byBiZSBlbXB0eSBkcm9wbGV0cyB0aGF0IGRpZCBub3QgY29udGFpbiBhIGNlbGwuIApUaGVzZSBkcm9wbGV0cyBtdXN0IGJlIGZpbHRlcmVkIG91dCBzbyB3ZSBvbmx5IGNvbnNpZGVyIHRydWUgY2VsbHMgZm9yIGRvd25zdHJlYW0gYW5hbHlzaXMuCgpUbyBkbyB0aGlzLCB3ZSBjYW4gbG9vayBmb3IgYSAia25lZSIgb24gdGhlIGN1cnZlIHdoZXJlIHRoZSBudW1iZXIgb2YgVU1JcyBwZXIgYmFyY29kZSBzdGFydHMgdG8gZHJvcCBvZmYgcmFwaWRseSwgd2l0aCB0aGUgaW50dWl0aW9uIHRoYXQgdGhpcyBpcyB3aGVyZSB3ZSBhcmUgcmVhY2hpbmcgdGhlIGVuZCBvZiB0aGUgVU1JcyBwZXIgY2VsbCBkaXN0cmlidXRpb24gZm9yIHRydWUgY2VsbHMuCldlIGNhbiB0aGVuIGNob29zZSBhIHRocmVzaG9sZCBiZWxvdyB0aGUga25lZSBhbmQgb25seSBpbmNsdWRlIGJhcmNvZGVzIGFib3ZlIHRoaXMgdGhyZXNob2xkIGluIHRoZSBmaW5hbCBjZWxsIGJhcmNvZGUgbGlzdC4KClRoaXMgImtuZWUiIG1ldGhvZCwgd2hpY2ggaXMgaW1wbGVtZW50ZWQgYnkgYGFsZXZpbmAsIGlzIGZhaXJseSBlZmZlY3RpdmUgYW5kIGRvZXMgbm90IHJlcXVpcmUgYW55IHJlYWQgbWFwcGluZyBvciBxdWFudGlmaWNhdGlvbiBiZWZvcmUgZmlsdGVyaW5nLgpNb3JlIHJlY2VudCB2ZXJzaW9ucyBvZiBDZWxsIFJhbmdlciB1c2UgYSBzb21ld2hhdCBkaWZmZXJlbnQgbWV0aG9kIGJhc2VkIG9uIHRoZSAiZW1wdHkgZHJvcHMiIG1ldGhvZCBvZiBbTHVuICpldCBhbC4qICgyMDE5KV0oaHR0cHM6Ly9kb2kub3JnLzEwLjExODYvczEzMDU5LTAxOS0xNjYyLXkpLCB0aGF0IGlzIGFwcGxpZWQgYWZ0ZXIgaW5pdGlhbCBnZW5lIHF1YW50aWZpY2F0aW9uLgpUaGlzIGFsbG93cyBmaWx0ZXJpbmcgdG8gcmV0YWluIGNlbGxzIHdpdGggbG93IGNvdW50cyB0aGF0IGFyZSBub25ldGhlbGVzcyBsaWtlbHkgdG8gcmVwcmVzZW50IHJlYWwgY2VsbHMuCgojIyBOZXh0IHN0ZXBzOiBMb2FkaW5nIEFsZXZpbiBvdXRwdXQgaW50byBSCgpBZnRlciB3ZSBoYXZlIHN1Y2Nlc3NmdWxseSBxdWFudGlmaWVkIG91ciB0YWctYmFzZWQgc2NSTkEtc2VxIGRhdGEgKGFuZCBkb25lIHNvbWUgUUMpLCB3ZSB3aWxsIHdhbnQgdG8gcmVhZCBpdCBpbnRvIFIgdG8gc3RhcnQgdG8gYW5hbHl6ZSBpdC4gClRoZSBlYXNpZXN0IHdheSB0byBkbyB0aGlzIGlzIHRvIHVzZSB0aGUgYHR4aW1ldGFgIHBhY2thZ2UsIHdoaWNoIHdlIHdpbGwgaW50cm9kdWNlIGluIHRoZSBuZXh0IG5vdGVib29rLgoKCiMjIFNlc3Npb24gSW5mbwoKYGBge3Igc2Vzc2lvbmluZm99CnNlc3Npb25JbmZvKCkKYGBgCg==