This file describes the different steps to perform the training course for the EBAII n1 2022 Single Cell analysis, covering the preprocessing steps : * Raw matrix loading * Empty droplets filtering * Ambient RNA contamination estimation * QC metrics (%mito, %ribo, %stress, cell cycle status) * Barcodes filtering * Normalization

1 CHEAT SHEET

Here is a list of different guidelines you should refer to, as they correspond to actions you would perform frequently.

1.1 JupyterHub

1.1.1 Connecting, and opening a session

  • Connect to the IFB JupyterHub using your credentials :
  • Select the reservation dedicated to our training session : form_2022_32
  • Reservation :
    • For a Rstudio session, request 2 CPUs and 15 GB of memory (let the other options to their default value)
    • For a shell session, request the default minimum (1 CPU, 1 GB)

1.1.2 Inside a session

  • To open an app, click on its icon.
  • To get multiple apps open simultaneously
    • Click on [File > New Launcher]
    • or just click on the big blue [ + ] button

1.1.3 Closing a session

  • Close your browser/tab, won’t close your session. It will still be running in background despite being invisible : this is a normal behavior, so that you can get back later to your current active session.
  • To actually close and finish your session, you have to :
    • Select from the JupyterHub menu [File > Hub Control Panel]
    • Click on the red button [Stop my server]
    • This will release the resources used by your server

1.2 singleCellTK

1.2.1 Starting scTK

  • In the Rstudio console :
scTKcomp::scTK_launch()
  • Let the interface start, it should take a few dozen of seconds
  • singleCellTK opens a new tab in your favorite internet browser, opened by default on the dataset loading page.

1.2.2 Loading a dataset (count matrix)

  • [Data > Import Single Cell data]
    • For this course, the data source will always be a SingleCellExperiment as RDS file
    • For each dataset you want to load
      • [Browse] to select the ‘*.rds’ file containing the SingleCellExperiment you want to load
      • Wait for loading bar to be fullfilled (should be immediate for early steps ; may take a few dozen seconds for later steps, when the SCE object contains multiple matrices)
      • Then, [Add to sample list]
    • If you are importing a new dataset but another one is already loaded, please remember to Overwrite existing SCE object (radio button) before importing !
    • Once you added all the datasets you need, [Import]
    • Let the features for display as Rownames (which, for our course, are symbols) and [Set]
    • You may switch to the next analysis steps

1.2.3 Exporting a dataset

For this course, we will systematically export objects from singleCellTK in the SCE (SingleCellExperiment) format, saved as a RDS archive (a compressed format which contained a single, unnamed R object)

  • [Data > Export Single Cell data]
    • Select the output directory (your R working directory should already be well positioned)
    • Let the export type as RDS
    • You can use whatever file name, but it is heavily recommended to follow this course’s suggestions.

1.2.4 Deleting cell annotations

Sometimes, it will be recommended to remove some entries in the working SCE object, mainly to : * Avoid being confused among multiple matrices in the object, discarding those that won’t be required anymore at further steps * Slim down the object for faster import / export.

  • [Data > Delete Single Cell data]
    • Just check the data to remove.
    • Confirm with [Delete]
    • Please remember that any suppression is definitive for the currently loaded object.

1.2.5 Stopping singleCellTK

  • Close your scTK browser tab
  • In Rstudio :
    • Clic in the console and press [Esc].
    • or clic on the red [Stop] button.

1.3 scTKcomp

This package hosts a collection of functions built around singleCellTK to :

  • Fill some gaps existing in its course
    • Create a SingleCellExperiment object from multiple sources of data (Cell Ranger, UMI-tools, BUStools, Alevin) (scTK_load)
    • Filter empty droplets (scTK_edf)
    • Evaluate cell cycle phase status / scores, using Seurat (scTK_cc_seurat)
    • Regress of cell covariates on any type of matrix, using Seurat too (scTK_regress_covariate)
  • Bypass some bugs
    • Perform a UMAP reduction (still with Seurat) on a reduced dimension object which is not a PCA/ICA, without creating a SCE object that can’t be properly imported anymore (scTK_SeuratUMAP)
  • Add new functionalities
    • Quickly describe the content of a SingleCellExperiment object (scTK_descriptor)
    • Perform a quick and dirty UMAP for early stage matrices (for early visualization) (scTK_QnDuMAP)
    • Use of “sensitive genes” instead of “highly variable genes” for the feature-based dimension reduction, thanks to scSensitiveGeneDefine (scTK_scSG)
    • Assess the weight of cell covariates on a matrix, with a heatmap visualization (scTK_assess_covar)
    • Perform trajectory analysis with TinGa (scTK_TinGa)
  • Misc
    • Recompress a RDS with a better compression ratio than default (ie, from gzip to bzip2 compression) (scTK_recompress)

We are now done with the blah blah, let’s practice for real !

2 WARMUP

2.1 Preamble

2.1.1 The analysis framework/interface : singleCellTK

singleCellTK : * Allows to use some of the R tools we bioinformaticians use * Adds a graphical interface * Allows visualization of some of the results * Obviously there are some limits in what can be done, compared to the command line * Relies on a format to store and transform the data :

2.1.2 The SingleCellExperiment object

We will now see together the scructure of the R data object you will manipulate for the next fewdays : the SingleCellExperiment object.

2.2 Getting the source data

  • Create an IFB JupyterHub session for Rstudio
  • Open a terminal
  • Create a new “TD” directory in your project folder
MYPROJECTNAME=my_project_name
mkdir -p /shared/projects/${MYPROJECTNAME}/TD/DATA
  • Copy the source data
cp -r /shared/projects/form_2022_32/SingleCellRNASeq/TD/DATA/START_OBJECTS/* /shared/projects/${MYPROJECTNAME}/TD/DATA/
  • Copy the required resource files
cp -r /shared/projects/form_2022_32/SingleCellRNASeq/TD/RESOURCES /shared/projects/${MYPROJECTNAME}/TD/
  • Exit your terminal
exit

2.3 Starting Rstudio

  • Just click on the Rstudio logo
  • Optionally : load the scTKcomp package
library(scTKcomp)

3 FROM COUNTS TO CELLS

3.1 Purpose

Our typical input data (once the reads mapping has been done, and the count matrix generated) is a features (row) by barcodes (columns) matrix.

Our aim here is to go from these experimental barcodes to actual cells (or, at least, most probable cells)

We will now : * Filter barcodes that should correspond to empty droplets * Perform QC, evaluating : * The amount of UMIs and number of expressed features per barcode * Which barcodes correspond to cell multiplets (mainly doublets) * The level of expression per barcode of : * Mitochondrial genes (proxy for over-lysis / cell mortality) * Ribosomal protein genes (proxy for metabolic level status of cells) * Dissociation / mechanical stress response genes (from Macchiado PhD report) * We will then filter out barcodes according to these generated QC metrics, using a series of criteria.

3.2 Generating an SCE object from raw data

For this very first step, we will use a rather small public dataset provided by 10X Genomics, which consists into an assay containing ~1000 human PBMCs (Peripheral Blood Mononucleus Cells). The source data for this sample consists in a raw count matrix in the 10X Cell Ranger format, and are located in the [TD/DATA/PBMC1K] folder

We will first generate a SingleCellExperiment object from the raw Cell Ranger matrix :

  • Position your R working directory t o where the data are :
setwd('/shared/projects/<yourprojectname>/TD/DATA/PBMC1K')
  • Call the help for the scTK_load() function
?scTKcomp::scTK_load
  • Run it on the 10X PBMC 1K dataset
sname <- 'PBMC1K'
scTKcomp::scTK_load(
  data_path = '.',
  sample_name = sname,
  exp_name = sname
)
  • This should have created the [PBMC1K_00a_Raw.rds] file that contains a SingleCellExperiment
  • Read the console outputs while they pop
    • Q: Is the observed sparsity level alarming ?

3.3 Filtering empty droplets

We will now filter out all these empty barcodes/droplets from this huge matrix :

  • Call the help for the scTK_edf() function
?scTKcomp::scTK_edf
  • Run it on the freshly created [PBMC1K_00a_Raw.rds] SCE object
scTKcomp::scTK_edf(in_rds = './PBMC1K_00a_Raw.rds')
  • Read the console outputs while they pop
    • Q1 : How many droplets were retained ?
    • Q2 : Compare this value from emtyDrops with the one obtained with Cell Ranger (in the HTML report). Are they concordant ?
  • Observe the generated plots (kneeplot, saturation plot)
    • Q3 : What could you say from the kneeplot ?
  • We will now take a look inside the guts of the generated SCE object :
    • Call the help for the function scTK_descriptor()
      • ?scTKcomp::scTK_descriptor
    • Use this function on the newly created object [PBMC1K_01a_EDf.rds]
  • Observe the console output (and note the sparsity level)

3.4 Estimating contamination

We will now work with the ‘TDCT’ sample from Paiva et al. It consists in a cell dissociation of a grafted murine thymus from a juvenile mouse to another juvenile mouse, that serves as a control in their study.

  • Start Rstudio (if not already started)
  • Get to the data directory corresponding to the TDCT sample
setwd('/shared/projects/<myprojectname>/TD/DATA/TDCT')

3.4.1 Importing data

  • Import the [TDCT_01a_EDf.rds] SCE object
  • Get to [QC & Filtering > QC]
  • Run SoupX with its default parameters
  • Observe the generated uMAPs (and example soup markers)
  • Save the SCE as [TDCT_01X_SoupX.rds]
  • Stop scTK
  • Use scTK_descriptor on [TDCT_01X_SoupX.rds]
scTKcomp::scTK_descriptor('TDCT_01X_SoupX.rds')
  • Observe the console output
    • Q1 : What did SoupX actually do ?
  • (You may now delete [TDCT_01X_SoupX.rds], we won’t use it anymore)

Just for the show : Run scTK_descriptor on a post-SoupX RDS on an other sample : N705, from Bacon et al, 2018) :

scTKcomp::scTK_descriptor('/shared/projects/form_2022_32/SingleCellRNASeq/TD/DATA/ALL_STEPS_OBJECTS/N705/N705_01X_SoupX.rds')

3.5 QC Metrics : Genesets expression & doublets

We will now generate some QC metrics for our cells

  • Start scTK
  • Set your working directory on the sample data folder
setwd('/shared/projects/<yourprojectname>/TD/DATA/TDCT')
  • Import [TDCT_01a_EDf.rds] object again
  • Import the gene lists required for some QCs :
    • (Mus musculus mitochondrial genes are bundled with singleCellTK)
    • Ribosomal proteins geneset :
      • [Data > Import Gene Sets]
        • Let the list selection to ‘Upload a GMT file’
        • [Browse] to select the ‘../../RESOURCES/GENELISTS/mus_musculus_ribo_symbols_20221105.gmt’
        • Set ‘Ribo’ as Collection Name
        • [Upload].
    • Dissociation / mechanical stress geneset :
      • [Data > Import Gene Sets]
        • In the same way, let the list selection to ‘Upload a GMT file’
        • [Browse] to select the ‘../../RESOURCES/GENELISTS/mus_musculus_stress_symbols_20221107.gmt’
        • Set ‘Stress’ as Collection Name
        • [Upload].
  • Perform doublets identification with method :
    • Team A : scDblFinder
    • Team B : scds (cxds bcds hybrid)
    • Team C : both
    • Team D : DoubletFinder
  • Observe generated uMAP
  • Perform QC (and observe QC plots each time) with
    • Mito
    • Ribo
    • Stress
  • Get to the [Cell Viewer] to observe QC metrics on the [QC_UMAP]
  • Delete all metadata but the first 5 annotations, *_percent, percent.top.* and *_call
  • Save the SCE object as [TDCT_01b_QC.rds]
  • Stop scTK

3.6 Estimate the cell cycle phase

We will now estimate the cell cyle phase status of our cells thanks to Seurat

  • Call the help for the scTK_cc_seurat() function
?scTKcomp::scTK_cc_seurat
  • This function will also need another RDS object (available in the [/shared/projects//TD/RESOURCES/GENELISTS] direcory) that contains 2 genesets :
    • S phase signature
    • G2M phase signature
  • Run it on the freshly created [TDCT_01b_QC.rds] SCE object.
scTKcomp::scTK_cc_seurat(
  in_rds = 'TDCT_01b_QC.rds',
  assay = 'counts',
  cc_seurat_file = '/shared/projects/<yourprojectname>/TD/RESOURCES/GENELISTS/mus_musculus_Seurat_cc.genes_20191031.rds')
  • Read the contingency table for estimated phases in the console output
  • Start scTK
  • Set your working directory on the sample data folder
setwd('/shared/projects/<yourprojectname>/TD/DATA/TDCT')
  • Import the freshly created [TDCT_02a_counts_CC.seurat.rds] SCE object
  • in the [Cell Viewer], on the QC_UMAP, observe cell annotations :
    • CC phase
    • SmG2M score, with a split by CC Phase

3.7 Filter cells and features

  • At the barcode level : Apply these filtering criteria (step by step, to measure their impact):
    • nFeature > 199
    • nFeature < 2999
    • nCount >999
    • Mito_percent < 5 (%)
    • doublets_call : Singlet
  • At the feature level : keep features with :
    • 1 count in at least 5 cells
  • Delete unneeded QC_UMAP reduction
  • Save object as [TDCT_02b_QCf.rds]

4 NORMALIZATION

4.1 Merge datasets

The study from which came the TDCT sample had another sample : TD3A. This second sample consists into another graft of a juvenile mouse thymus to another juvenile one, except that in this case the host is mutated so that it cannot produce the expected T cell progenitors from its spine bone marrow.

In normal circumstances, when there is a short period during which the spine bone marrow is unable to produce such progenitors, it is already known that a mechanism (called autonomy) activates, such that some unknown immature cell type from the thymus behaves as a progenitor. The aim of this study was to identify which cell type in the T cell maturation stages has this ability.

It is also important to note that such mechanism, when lasting to long, is very prone to start leukemia…

We will know merge the two samples to analyze them, in a comparison purpose.

  • Stop scTK
  • Set your working directory on the sample data folder
setwd('/shared/projects/<yourprojectname>/TD/DATA/INTEGRATED')
  • Start scTK
  • Import [../TDCT/TDCT_02b_QCf.rds] and [../TD3A/TD3A_02b_QCf.rds].
    • WARNING : This time you import the 2 objects at the same time. Be careful to add them both to the sample list before importing.
  • Delete “rownames” (bypasses a bug for QC plots)
    • WARNING : Do not skip this step or you’ll be in trouble soon !
  • Perform basic QCs and observe boxplots
    • If you are lost in an infinite waiting loop, you did not read the last warning :D
    • Q1 : How similar are these two samples when considering :
      • Their globally measured expression level ?
      • The expression level of their top 50 expressed genes ?
  • Delete unneeded barcode annotations : sum, detected, total
  • Save the SCE object as [TDCT.TD31_02b_QCf.rds]
  • Stop scTK
  • Run scTK_descriptor (only describing assays) on these 3 SCE objects :
    • [TDCT_02b_QCf.RDS] (Control)
    • [TD3A_02b_QCf.RDS] (Autonomy)
    • [TDCT.TD31_02b_QCf.RDS] (Merged)
      • Q2 : Do things add up (features / cells) ?

4.2 Normalization

  • Start scTK
  • Set your working directory on the sample data folder
setwd('/shared/projects/<yourprojectname>/TD/DATA/INTEGRATED')
  • Import again the [TDCT.TD3A_02b_QCf.rds] SCE object
  • Get to [Normalization & Batch Correction > Normalization]
  • Use :
    • Method : Seurat - LogNormalize
    • Input assay : counts
    • Output assay name = ‘SLNst’
    • Use scaling
    • Use trimming, let default limits
  • Save the SCE object as [TDCT.TD3A_02c_SLNst.rds]
    • This should take more time than you are used to from earlier steps. This is due to the fact that while the raw ‘counts’ matrix consists in a very sparse, thus very compressed matrix, the normalized ‘SLNst’ matrix contains numeric values, which compress with a mediocre ratio
  • Stop scTK
  • Describe the freshly saved [TDCT.TD3A_02c_SLNst.rds]
scTKcomp::scTK_descriptor('TDCT.TD3A_02c_SLNst.rds')
  • Q1 : What could you say for our new assay ?
LS0tCnRpdGxlOiAiRUJBSUkgbjEgMjAyMiA6IFNpbmdsZSBDZWxsIEFuYWx5c2lzIFRyYWluaW5nXG5QUkVQUk9DRVNTSU5HIC0gUUMsIEZpbHRlcmluZyBhbmQgbm9ybWFsaXphdGlvbiIKYXV0aG9yOiAiQmFzdGllbiBKT0I8QlI+YmFzdGllbi5qb2JAZ3VzdGF2ZXJvdXNzeS5mciIKZGF0ZTogIjIwMjItMTEtMTQuMTgiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiAKICAgIGJhY2tncm91bmQ6IGJsYWNrCiAgICBmaWdfaGVpZ2h0OiAxMAogICAgZmlnX3dpZHRoOiAxNQogICAgaGlnaGxpZ2h0OiB0YW5nbyAgIyMgVGhlbWUgZm9yIHRoZSBjb2RlIGNodW5rcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMgICMjIEFkZHMgbnVtYmVyIHRvIGhlYWRlcnMgKHNlY3Rpb25zKQogICAgdGhlbWU6IGZsYXRseSAgIyMgQ1NTIHRoZW1lIGZvciB0aGUgSFRNTCBwYWdlCiAgICB0b2M6IHllcyAgIyMgQWRkcyBhIHRhYmxlIG9mIGNvbnRlbnQKICAgIHRvY19mbG9hdDogICMjIFRPQyBvcHRpb25zCiAgICAgIGNvbGxhcHNlZDogeWVzICAjIyBCeSBkZWZhdWx0LCB0aGUgVE9DIGlzIGZvbGRlZAogICAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMgIyMgU21vb3RoIHNjcm9sbCBvZiB0aGUgSFRNTCBwYWdlCiAgICBzZWxmX2NvbnRhaW5lZDogeWVzICMjIEluY2x1ZGVzIGFsbCBwbG90cy9pbWFnZXMgd2l0aGluIHRoZSBIVE1MCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMgIyMgQWRkcyBhIGJ1dHRvbiB0byBkb3dubG9hZCB0aGUgUm1kCiAgIyBybWRmb3JtYXRzYmlncjo6cmVhZHRoZWJpZ3Jkb2M6ICAjIGlmIHlvdSdkIGxpa2UgdG8gaGF2ZSBhIG5pY2UgdGhlbWUKICAjICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgIyAgIHRodW1ibmFpbHM6IGZhbHNlCiAgIyAgIGxpZ2h0Ym94OiB0cnVlCiAgIyAgIGhpZ2hsaWdodDogdHJ1ZQogICMgICBmaWdfY2FwdGlvbjogZmFsc2UKYWx3YXlzX2FsbG93X2h0bWw6IHllcyAjIyBBbGxvdyBwbGFpbiBIVE1MIGNvZGUgaW4gdGhlIFJtZAotLS0KCjwhLS0gQWxsb3dzIHRvIGhpZGUgdGhlIFRPQyBieSBkZWZhdWx0LCBkaXNwbGF5IGl0IHdpdGggYSBidXR0b24sIG1vdmUgaXQgdG8gdGhlIHJpZ2h0IG9yIGxlZnQgb2YgdGhlIHBhZ2UgLS0+CmByIEhtaXNjOjpoaWRpbmdUT0MoYnV0dG9uTGFiZWwgPSAnU2hvdyBUT0MnLCBoaWRkZW4gPSBUUlVFLCB0b2NTaWRlID0gJ2xlZnQnLCBidXR0b25TaWRlPSdsZWZ0JywgcG9zQ29sbGFwc2UgPSAnbWFyZ2luJywgbGV2ZWxzID0gMylgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBvcHRpb25zKHdpZHRoID0gNjApOwprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyA9IFRSVUUsICAgICAgICAjIFByaW50IHRoZSBjb2RlCiAgZXZhbCA9IEZBTFNFLCAgICAgICAjIERvIG5vdCBydW4gY29tbWFuZCBsaW5lcwogIG1lc3NhZ2UgPSBGQUxTRSwgICAgIyBQcmludCBtZXNzYWdlcwogIHByb21wdCA9IEZBTFNFLCAgICAgIyBEbyBub3QgZGlzcGxheSBwcm9tcHQKICBjb21tZW50ID0gTkEsICAgICAgICMgTm8gY29tbWVudHMgb24gdGhpcyBzZWN0aW9uCiAgd2FybmluZyA9IEZBTFNFLCAgICAjIERpc3BsYXkgd2FybmluZ3MKICB0aWR5ID0gRkFMU0UKICAjIHdpZHRoID0gMTAwICAgICAgICMgTnVtYmVyIG9mIGNoYXJhY3RlcnMgcGVyIGxpbmUKKQpgYGAKCjxjZW50ZXI+IVtdKC9ob21lL2pvYi9XT1JLU1BBQ0UvRU5DQURSRU1FTlQvMjAyMi9FQkFJSV9uMV8yMDIyL0FURUxJRVJfU0MvVEQvTUQvcmVzb3VyY2VzL2Jhbm5lci5wbmcpPC9jZW50ZXI+Cjxicj48YnI+CgpUaGlzIGZpbGUgZGVzY3JpYmVzIHRoZSBkaWZmZXJlbnQgc3RlcHMgdG8gcGVyZm9ybSB0aGUgdHJhaW5pbmcgY291cnNlIGZvciB0aGUgRUJBSUkgbjEgMjAyMiBTaW5nbGUgQ2VsbCBhbmFseXNpcywgY292ZXJpbmcgdGhlIHByZXByb2Nlc3Npbmcgc3RlcHMgOgoqIFJhdyBtYXRyaXggbG9hZGluZwoqIEVtcHR5IGRyb3BsZXRzIGZpbHRlcmluZwoqIEFtYmllbnQgUk5BIGNvbnRhbWluYXRpb24gZXN0aW1hdGlvbgoqIFFDIG1ldHJpY3MgKCVtaXRvLCAlcmlibywgJXN0cmVzcywgY2VsbCBjeWNsZSBzdGF0dXMpCiogQmFyY29kZXMgZmlsdGVyaW5nCiogTm9ybWFsaXphdGlvbgoKIyBDSEVBVCBTSEVFVAoKSGVyZSBpcyBhIGxpc3Qgb2YgZGlmZmVyZW50IGd1aWRlbGluZXMgeW91IHNob3VsZCByZWZlciB0bywgYXMgdGhleSBjb3JyZXNwb25kIHRvIGFjdGlvbnMgeW91IHdvdWxkIHBlcmZvcm0gZnJlcXVlbnRseS4KCjxhIG5hbWU9IkpIY29ubmVjdCI+PC9hPgoKIyMgW0p1cHl0ZXJIdWJdKGh0dHBzOi8vanVweXRlcmh1Yi5jbHVzdGVyLmZyYW5jZS1iaW9pbmZvcm1hdGlxdWUuZnIpCgojIyMgQ29ubmVjdGluZywgYW5kIG9wZW5pbmcgYSBzZXNzaW9uCgo8Y2VudGVyPiFbXSgvaG9tZS9qb2IvV09SS1NQQUNFL0VOQ0FEUkVNRU5ULzIwMjIvRUJBSUlfbjFfMjAyMi9BVEVMSUVSX1NDL1REL01EL3Jlc291cmNlcy9qdXBzaWduLnBuZyk8L2NlbnRlcj4KCiogQ29ubmVjdCB0byB0aGUgSUZCIEp1cHl0ZXJIdWIgdXNpbmcgeW91ciBjcmVkZW50aWFscyA6IAoqIFNlbGVjdCB0aGUgcmVzZXJ2YXRpb24gZGVkaWNhdGVkIHRvIG91ciB0cmFpbmluZyBzZXNzaW9uIDogKipmb3JtXzIwMjJfMzIqKgoqIFJlc2VydmF0aW9uIDoKICAqIEZvciBhICoqUnN0dWRpbyoqIHNlc3Npb24sIHJlcXVlc3QgKioyIENQVXMqKiBhbmQgKioxNSBHQiBvZiBtZW1vcnkqKiAobGV0IHRoZSBvdGhlciBvcHRpb25zIHRvIHRoZWlyIGRlZmF1bHQgdmFsdWUpCiAgKiBGb3IgYSAqKnNoZWxsKiogc2Vzc2lvbiwgcmVxdWVzdCB0aGUgZGVmYXVsdCBtaW5pbXVtICgxIENQVSwgMSBHQikKCjxjZW50ZXI+IVtdKC9ob21lL2pvYi9XT1JLU1BBQ0UvRU5DQURSRU1FTlQvMjAyMi9FQkFJSV9uMV8yMDIyL0FURUxJRVJfU0MvVEQvTUQvcmVzb3VyY2VzL2p1cF9zZXJ2ZXJfY3JlYXRlLnBuZyk8L2NlbnRlcj4KCiMjIyBJbnNpZGUgYSBzZXNzaW9uCgoqIFRvIG9wZW4gYW4gYXBwLCBjbGljayBvbiBpdHMgaWNvbi4KKiBUbyBnZXQgbXVsdGlwbGUgYXBwcyBvcGVuIHNpbXVsdGFuZW91c2x5CiAgKiBDbGljayBvbiAqKltGaWxlID4gTmV3IExhdW5jaGVyXSoqCiAgKiAqb3IqIGp1c3QgY2xpY2sgb24gdGhlIGJpZyBibHVlICoqWyArIF0qKiBidXR0b24KCjxjZW50ZXI+IVtdKC9ob21lL2pvYi9XT1JLU1BBQ0UvRU5DQURSRU1FTlQvMjAyMi9FQkFJSV9uMV8yMDIyL0FURUxJRVJfU0MvVEQvTUQvcmVzb3VyY2VzL2p1cG1lbnUucG5nKTwvY2VudGVyPgoKIyMjIDxhIG5hbWU9IkpIY2xvc2UiPjwvYT4gQ2xvc2luZyBhIHNlc3Npb24KCiogQ2xvc2UgeW91ciBicm93c2VyL3RhYiwgKip3b24ndCBjbG9zZSB5b3VyIHNlc3Npb24qKi4gSXQgd2lsbCBzdGlsbCBiZSBydW5uaW5nIGluIGJhY2tncm91bmQgZGVzcGl0ZSBiZWluZyBpbnZpc2libGUgOiB0aGlzIGlzIGEgbm9ybWFsIGJlaGF2aW9yLCBzbyB0aGF0IHlvdSBjYW4gZ2V0IGJhY2sgbGF0ZXIgdG8geW91ciBjdXJyZW50IGFjdGl2ZSBzZXNzaW9uLgoqIFRvIGFjdHVhbGx5IGNsb3NlIGFuZCBmaW5pc2ggeW91ciBzZXNzaW9uLCB5b3UgaGF2ZSB0byA6CiAgKiBTZWxlY3QgZnJvbSB0aGUgSnVweXRlckh1YiBtZW51ICoqW0ZpbGUgPiBIdWIgQ29udHJvbCBQYW5lbF0qKgogICogQ2xpY2sgb24gdGhlIHJlZCBidXR0b24gKipbU3RvcCBteSBzZXJ2ZXJdKioKICAqIFRoaXMgd2lsbCByZWxlYXNlIHRoZSByZXNvdXJjZXMgdXNlZCBieSB5b3VyIHNlcnZlcgoKPGNlbnRlcj5bXSgvaG9tZS9qb2IvV09SS1NQQUNFL0VOQ0FEUkVNRU5ULzIwMjIvRUJBSUlfbjFfMjAyMi9BVEVMSUVSX1NDL1REL01EL3Jlc291cmNlcy9qdXBzdG9wLnBuZyk8L2NlbnRlcj4KCiMjIFtzaW5nbGVDZWxsVEtdKGh0dHBzOi8vd3d3LmJpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL2h0bWwvc2luZ2xlQ2VsbFRLLmh0bWwpCgojIyMgPGEgbmFtZT0ic2NUS3N0YXJ0Ij48L2E+IFN0YXJ0aW5nIHNjVEsKCiogSW4gdGhlIFJzdHVkaW8gY29uc29sZSA6IApgYGAge3J9CnNjVEtjb21wOjpzY1RLX2xhdW5jaCgpCmBgYAogICogKkxldCB0aGUgaW50ZXJmYWNlIHN0YXJ0LCBpdCBzaG91bGQgdGFrZSBhIGZldyBkb3plbiBvZiBzZWNvbmRzKgogICogc2luZ2xlQ2VsbFRLIG9wZW5zIGEgbmV3IHRhYiBpbiB5b3VyIGZhdm9yaXRlIGludGVybmV0IGJyb3dzZXIsIG9wZW5lZCBieSBkZWZhdWx0IG9uIHRoZSBkYXRhc2V0IGxvYWRpbmcgcGFnZS4KCiMjIyA8YSBuYW1lPSJzY1RLaW1wb3J0Ij48L2E+IExvYWRpbmcgYSBkYXRhc2V0IChjb3VudCBtYXRyaXgpCgoqICoqW0RhdGEgPiBJbXBvcnQgU2luZ2xlIENlbGwgZGF0YV0qKgogICogRm9yIHRoaXMgY291cnNlLCB0aGUgZGF0YSBzb3VyY2Ugd2lsbCBhbHdheXMgYmUgYSAqKlNpbmdsZUNlbGxFeHBlcmltZW50IGFzIFJEUyBmaWxlKioKICAqIEZvciBlYWNoIGRhdGFzZXQgeW91IHdhbnQgdG8gbG9hZAogICAgKiAqKltCcm93c2VdKiogdG8gc2VsZWN0IHRoZSAqKidcKi5yZHMnKiogZmlsZSBjb250YWluaW5nIHRoZSBTaW5nbGVDZWxsRXhwZXJpbWVudCB5b3Ugd2FudCB0byBsb2FkCiAgICAqICoqV2FpdCBmb3IgbG9hZGluZyBiYXIgdG8gYmUgZnVsbGZpbGxlZCoqIChzaG91bGQgYmUgaW1tZWRpYXRlIGZvciBlYXJseSBzdGVwcyA7IG1heSB0YWtlIGEgZmV3IGRvemVuIHNlY29uZHMgZm9yIGxhdGVyIHN0ZXBzLCB3aGVuIHRoZSBTQ0Ugb2JqZWN0IGNvbnRhaW5zIG11bHRpcGxlIG1hdHJpY2VzKQogICAgKiBUaGVuLCAqKltBZGQgdG8gc2FtcGxlIGxpc3RdKioKICAqICpJZiB5b3UgYXJlIGltcG9ydGluZyBhIG5ldyBkYXRhc2V0IGJ1dCBhbm90aGVyIG9uZSBpcyBhbHJlYWR5IGxvYWRlZCwgcGxlYXNlIHJlbWVtYmVyIHRvICoqT3ZlcndyaXRlIGV4aXN0aW5nIFNDRSBvYmplY3QqKiAocmFkaW8gYnV0dG9uKSBiZWZvcmUgaW1wb3J0aW5nICEqCiAgKiBPbmNlIHlvdSBhZGRlZCBhbGwgdGhlIGRhdGFzZXRzIHlvdSBuZWVkLCAqKltJbXBvcnRdKioKICAqIExldCB0aGUgZmVhdHVyZXMgZm9yIGRpc3BsYXkgYXMgKipSb3duYW1lcyoqICh3aGljaCwgZm9yIG91ciBjb3Vyc2UsIGFyZSBzeW1ib2xzKSBhbmQgKipbU2V0XSoqCiAgKiBZb3UgbWF5IHN3aXRjaCB0byB0aGUgbmV4dCBhbmFseXNpcyBzdGVwcwoKPGNlbnRlcj5bXSgvaG9tZS9qb2IvV09SS1NQQUNFL0VOQ0FEUkVNRU5ULzIwMjIvRUJBSUlfbjFfMjAyMi9BVEVMSUVSX1NDL1REL01EL3Jlc291cmNlcy9zY3RrX2ltcG9ydC5wbmcpPC9jZW50ZXI+CgojIyMgPGEgbmFtZT0ic2NUS2V4cG9ydCI+PC9hPiBFeHBvcnRpbmcgYSBkYXRhc2V0CgpGb3IgdGhpcyBjb3Vyc2UsIHdlIHdpbGwgc3lzdGVtYXRpY2FsbHkgZXhwb3J0IG9iamVjdHMgZnJvbSBzaW5nbGVDZWxsVEsgaW4gdGhlIFNDRSAoU2luZ2xlQ2VsbEV4cGVyaW1lbnQpIGZvcm1hdCwgc2F2ZWQgYXMgYSBSRFMgYXJjaGl2ZSAoYSBjb21wcmVzc2VkIGZvcm1hdCB3aGljaCBjb250YWluZWQgYSBzaW5nbGUsIHVubmFtZWQgUiBvYmplY3QpCgoqICoqW0RhdGEgPiBFeHBvcnQgU2luZ2xlIENlbGwgZGF0YV0qKgogICogU2VsZWN0IHRoZSBvdXRwdXQgZGlyZWN0b3J5ICh5b3VyIFIgd29ya2luZyBkaXJlY3Rvcnkgc2hvdWxkIGFscmVhZHkgYmUgd2VsbCBwb3NpdGlvbmVkKQogICogTGV0IHRoZSBleHBvcnQgdHlwZSBhcyAqKlJEUyoqCiAgKiBZb3UgY2FuIHVzZSB3aGF0ZXZlciBmaWxlIG5hbWUsIGJ1dCBpdCBpcyBoZWF2aWx5IHJlY29tbWVuZGVkIHRvIGZvbGxvdyB0aGlzIGNvdXJzZSdzIHN1Z2dlc3Rpb25zLgoKPGNlbnRlcj5bXSgvaG9tZS9qb2IvV09SS1NQQUNFL0VOQ0FEUkVNRU5ULzIwMjIvRUJBSUlfbjFfMjAyMi9BVEVMSUVSX1NDL1REL01EL3Jlc291cmNlcy9zY3RrX2V4cG9ydC5wbmcpPC9jZW50ZXI+CgojIyMgPGEgbmFtZT0ic2NUS2RlbGV0ZSI+PC9hPiBEZWxldGluZyBjZWxsIGFubm90YXRpb25zCgpTb21ldGltZXMsIGl0IHdpbGwgYmUgcmVjb21tZW5kZWQgdG8gcmVtb3ZlIHNvbWUgZW50cmllcyBpbiB0aGUgd29ya2luZyBTQ0Ugb2JqZWN0LCBtYWlubHkgdG8gOgogICogQXZvaWQgYmVpbmcgY29uZnVzZWQgYW1vbmcgbXVsdGlwbGUgbWF0cmljZXMgaW4gdGhlIG9iamVjdCwgZGlzY2FyZGluZyB0aG9zZSB0aGF0IHdvbid0IGJlIHJlcXVpcmVkIGFueW1vcmUgYXQgZnVydGhlciBzdGVwcwogICogU2xpbSBkb3duIHRoZSBvYmplY3QgZm9yIGZhc3RlciBpbXBvcnQgLyBleHBvcnQuCgoqICoqW0RhdGEgPiBEZWxldGUgU2luZ2xlIENlbGwgZGF0YV0qKgogICogSnVzdCBjaGVjayB0aGUgZGF0YSB0byByZW1vdmUuCiAgKiBDb25maXJtIHdpdGggKipbRGVsZXRlXSoqCiAgKiBQbGVhc2UgcmVtZW1iZXIgdGhhdCAqKmFueSBzdXBwcmVzc2lvbiBpcyBkZWZpbml0aXZlKiogZm9yIHRoZSBjdXJyZW50bHkgbG9hZGVkIG9iamVjdC4KCjxjZW50ZXI+W10oL2hvbWUvam9iL1dPUktTUEFDRS9FTkNBRFJFTUVOVC8yMDIyL0VCQUlJX24xXzIwMjIvQVRFTElFUl9TQy9URC9NRC9yZXNvdXJjZXMvc2N0a19kZWxldGUucG5nKTwvY2VudGVyPgoKIyMjIDxhIG5hbWU9InNjVEtzdG9wIj48L2E+IFN0b3BwaW5nIHNpbmdsZUNlbGxUSwoKKiBDbG9zZSB5b3VyIHNjVEsgYnJvd3NlciB0YWIKKiBJbiBSc3R1ZGlvIDoKICAqIENsaWMgaW4gdGhlIGNvbnNvbGUgYW5kIHByZXNzICoqW0VzY10qKi4KICAqICoqKm9yKioqIGNsaWMgb24gdGhlIHJlZCAqKltTdG9wXSoqIGJ1dHRvbi4KCiMjIFtzY1RLY29tcF0oaHR0cHM6Ly9naXRodWIuY29tL2FvdW1lc3Mvc2NUS2NvbXApCgpUaGlzIHBhY2thZ2UgaG9zdHMgYSBjb2xsZWN0aW9uIG9mIGZ1bmN0aW9ucyBidWlsdCBhcm91bmQgc2luZ2xlQ2VsbFRLIHRvIDoKCiogRmlsbCBzb21lIGdhcHMgZXhpc3RpbmcgaW4gaXRzIGNvdXJzZQogICogQ3JlYXRlIGEgU2luZ2xlQ2VsbEV4cGVyaW1lbnQgb2JqZWN0IGZyb20gbXVsdGlwbGUgc291cmNlcyBvZiBkYXRhIChDZWxsIFJhbmdlciwgVU1JLXRvb2xzLCBCVVN0b29scywgQWxldmluKSAqKHNjVEtfbG9hZCkqCiAgKiBGaWx0ZXIgZW1wdHkgZHJvcGxldHMgKihzY1RLX2VkZikqCiAgKiBFdmFsdWF0ZSBjZWxsIGN5Y2xlIHBoYXNlIHN0YXR1cyAvIHNjb3JlcywgdXNpbmcgW1NldXJhdF0oaHR0cHM6Ly9zYXRpamFsYWIub3JnL3NldXJhdC8pICooc2NUS19jY19zZXVyYXQpKgogICogUmVncmVzcyBvZiBjZWxsIGNvdmFyaWF0ZXMgb24gYW55IHR5cGUgb2YgbWF0cml4LCB1c2luZyBTZXVyYXQgdG9vICooc2NUS19yZWdyZXNzX2NvdmFyaWF0ZSkqCiogQnlwYXNzIHNvbWUgYnVncwogICogUGVyZm9ybSBhIFVNQVAgcmVkdWN0aW9uIChzdGlsbCB3aXRoIFNldXJhdCkgb24gYSByZWR1Y2VkIGRpbWVuc2lvbiBvYmplY3Qgd2hpY2ggaXMgbm90IGEgUENBL0lDQSwgd2l0aG91dCBjcmVhdGluZyBhIFNDRSBvYmplY3QgdGhhdCBjYW4ndCBiZSBwcm9wZXJseSBpbXBvcnRlZCBhbnltb3JlICooc2NUS19TZXVyYXRVTUFQKSoKKiBBZGQgbmV3IGZ1bmN0aW9uYWxpdGllcwogICogUXVpY2tseSBkZXNjcmliZSB0aGUgY29udGVudCBvZiBhIFNpbmdsZUNlbGxFeHBlcmltZW50IG9iamVjdCAqKHNjVEtfZGVzY3JpcHRvcikqCiAgKiBQZXJmb3JtIGEgcXVpY2sgYW5kIGRpcnR5IFVNQVAgZm9yIGVhcmx5IHN0YWdlIG1hdHJpY2VzIChmb3IgZWFybHkgdmlzdWFsaXphdGlvbikgKihzY1RLX1FuRHVNQVApKgogICogVXNlIG9mICJzZW5zaXRpdmUgZ2VuZXMiIGluc3RlYWQgb2YgImhpZ2hseSB2YXJpYWJsZSBnZW5lcyIgZm9yIHRoZSBmZWF0dXJlLWJhc2VkIGRpbWVuc2lvbiByZWR1Y3Rpb24sIHRoYW5rcyB0byBbc2NTZW5zaXRpdmVHZW5lRGVmaW5lXShodHRwczovL2dpdGh1Yi5jb20vWmVjaHVhbi1DaGVuL3NjU2Vuc2l0aXZlR2VuZURlZmluZSkgKihzY1RLX3NjU0cpKgogICogQXNzZXNzIHRoZSB3ZWlnaHQgb2YgY2VsbCBjb3ZhcmlhdGVzIG9uIGEgbWF0cml4LCB3aXRoIGEgaGVhdG1hcCB2aXN1YWxpemF0aW9uICooc2NUS19hc3Nlc3NfY292YXIpKgogICogUGVyZm9ybSB0cmFqZWN0b3J5IGFuYWx5c2lzIHdpdGggW1RpbkdhXShodHRwczovL3d3dy5yZXNlYXJjaGdhdGUubmV0L3B1YmxpY2F0aW9uLzM0MjkyNDQzMl9UaW5HYV9mYXN0X2FuZF9mbGV4aWJsZV90cmFqZWN0b3J5X2luZmVyZW5jZV93aXRoX0dyb3dpbmdfTmV1cmFsX0dhcykgKihzY1RLX1RpbkdhKSoKKiBNaXNjCiAgKiBSZWNvbXByZXNzIGEgUkRTIHdpdGggYSBiZXR0ZXIgY29tcHJlc3Npb24gcmF0aW8gdGhhbiBkZWZhdWx0IChpZSwgZnJvbSAqZ3ppcCogdG8gKmJ6aXAyKiBjb21wcmVzc2lvbikgKihzY1RLX3JlY29tcHJlc3MpKgoKPGNlbnRlcj5bXSgvaG9tZS9qb2IvV09SS1NQQUNFL0VOQ0FEUkVNRU5ULzIwMjIvRUJBSUlfbjFfMjAyMi9BVEVMSUVSX1NDL1REL01EL3Jlc291cmNlcy9zY3RrY29tcC5wbmcpPC9jZW50ZXI+CgoKKioqV2UgYXJlIG5vdyBkb25lIHdpdGggdGhlIGJsYWggYmxhaCwgbGV0J3MgcHJhY3RpY2UgZm9yIHJlYWwgISoqKgoKIyBXQVJNVVAKCiMjIFByZWFtYmxlCgojIyMgVGhlIGFuYWx5c2lzIGZyYW1ld29yay9pbnRlcmZhY2UgOiBzaW5nbGVDZWxsVEsKCioqc2luZ2xlQ2VsbFRLKiogOgoqIEFsbG93cyB0byB1c2Ugc29tZSBvZiB0aGUgUiB0b29scyB3ZSBiaW9pbmZvcm1hdGljaWFucyB1c2UKKiBBZGRzIGEgZ3JhcGhpY2FsIGludGVyZmFjZQoqIEFsbG93cyB2aXN1YWxpemF0aW9uIG9mIHNvbWUgb2YgdGhlIHJlc3VsdHMKKiBPYnZpb3VzbHkgdGhlcmUgYXJlIHNvbWUgbGltaXRzIGluIHdoYXQgY2FuIGJlIGRvbmUsIGNvbXBhcmVkIHRvIHRoZSBjb21tYW5kIGxpbmUKKiBSZWxpZXMgb24gYSBmb3JtYXQgdG8gc3RvcmUgYW5kIHRyYW5zZm9ybSB0aGUgZGF0YSA6CgojIyMgVGhlIFNpbmdsZUNlbGxFeHBlcmltZW50IG9iamVjdAoKV2Ugd2lsbCBub3cgc2VlIHRvZ2V0aGVyIHRoZSBzY3J1Y3R1cmUgb2YgdGhlIFIgZGF0YSBvYmplY3QgeW91IHdpbGwgbWFuaXB1bGF0ZSBmb3IgdGhlIG5leHQgZmV3ZGF5cyA6IHRoZSAqU2luZ2xlQ2VsbEV4cGVyaW1lbnQqIG9iamVjdC4KCgojIyBHZXR0aW5nIHRoZSBzb3VyY2UgZGF0YQoKKiBDcmVhdGUgYW4gSUZCIFtKdXB5dGVySHViXSgjSkhjb25uZWN0KSBzZXNzaW9uIGZvciBSc3R1ZGlvCiogT3BlbiBhICoqdGVybWluYWwqKgoqIENyZWF0ZSBhIG5ldyAqKiJURCIqKiBkaXJlY3RvcnkgaW4geW91ciBwcm9qZWN0IGZvbGRlcgpgYGAge3NofQpNWVBST0pFQ1ROQU1FPW15X3Byb2plY3RfbmFtZQpta2RpciAtcCAvc2hhcmVkL3Byb2plY3RzLyR7TVlQUk9KRUNUTkFNRX0vVEQvREFUQQpgYGAKKiBDb3B5IHRoZSBzb3VyY2UgZGF0YQpgYGAge3NofQpjcCAtciAvc2hhcmVkL3Byb2plY3RzL2Zvcm1fMjAyMl8zMi9TaW5nbGVDZWxsUk5BU2VxL1REL0RBVEEvU1RBUlRfT0JKRUNUUy8qIC9zaGFyZWQvcHJvamVjdHMvJHtNWVBST0pFQ1ROQU1FfS9URC9EQVRBLwpgYGAKKiBDb3B5IHRoZSByZXF1aXJlZCByZXNvdXJjZSBmaWxlcwpgYGAge3NofQpjcCAtciAvc2hhcmVkL3Byb2plY3RzL2Zvcm1fMjAyMl8zMi9TaW5nbGVDZWxsUk5BU2VxL1REL1JFU09VUkNFUyAvc2hhcmVkL3Byb2plY3RzLyR7TVlQUk9KRUNUTkFNRX0vVEQvCmBgYAoqIEV4aXQgeW91ciB0ZXJtaW5hbApgYGAge3NofQpleGl0CmBgYAoKIyMgPGEgbmFtZT0ic3RhcnRSc3R1ZGlvIj48L2E+IFN0YXJ0aW5nIFJzdHVkaW8KCiogSnVzdCBjbGljayBvbiB0aGUgUnN0dWRpbyBsb2dvCiogKk9wdGlvbmFsbHkgOiBsb2FkIHRoZSAqKnNjVEtjb21wKiogcGFja2FnZSoKYGBgIHtyfQpsaWJyYXJ5KHNjVEtjb21wKQpgYGAKIyBGUk9NIENPVU5UUyBUTyBDRUxMUwoKIyMgUHVycG9zZQoKT3VyIHR5cGljYWwgaW5wdXQgZGF0YSAob25jZSB0aGUgcmVhZHMgbWFwcGluZyBoYXMgYmVlbiBkb25lLCBhbmQgdGhlIGNvdW50IG1hdHJpeCBnZW5lcmF0ZWQpIGlzIGEgZmVhdHVyZXMgKHJvdykgYnkgYmFyY29kZXMgKGNvbHVtbnMpIG1hdHJpeC4KCk91ciBhaW0gaGVyZSBpcyB0byBnbyBmcm9tIHRoZXNlIGV4cGVyaW1lbnRhbCBiYXJjb2RlcyB0byBhY3R1YWwgY2VsbHMgKihvciwgYXQgbGVhc3QsICoqbW9zdCBwcm9iYWJsZSBjZWxscyoqKSoKCldlIHdpbGwgbm93IDoKKiBGaWx0ZXIgYmFyY29kZXMgdGhhdCBzaG91bGQgY29ycmVzcG9uZCB0byBlbXB0eSBkcm9wbGV0cwoqIFBlcmZvcm0gUUMsIGV2YWx1YXRpbmcgOgogICogVGhlIGFtb3VudCBvZiBVTUlzIGFuZCBudW1iZXIgb2YgZXhwcmVzc2VkIGZlYXR1cmVzIHBlciBiYXJjb2RlCiAgKiBXaGljaCBiYXJjb2RlcyBjb3JyZXNwb25kIHRvIGNlbGwgbXVsdGlwbGV0cyAobWFpbmx5IGRvdWJsZXRzKQogICogVGhlIGxldmVsIG9mIGV4cHJlc3Npb24gcGVyIGJhcmNvZGUgb2YgOgogICAgKiBNaXRvY2hvbmRyaWFsIGdlbmVzIChwcm94eSBmb3Igb3Zlci1seXNpcyAvIGNlbGwgbW9ydGFsaXR5KQogICAgKiBSaWJvc29tYWwgcHJvdGVpbiBnZW5lcyAocHJveHkgZm9yIG1ldGFib2xpYyBsZXZlbCBzdGF0dXMgb2YgY2VsbHMpCiAgICAqIERpc3NvY2lhdGlvbiAvIG1lY2hhbmljYWwgc3RyZXNzIHJlc3BvbnNlIGdlbmVzIChmcm9tIFtNYWNjaGlhZG8gUGhEIHJlcG9ydF0oaHR0cHM6Ly9oYWwuYXJjaGl2ZXMtb3V2ZXJ0ZXMuZnIvaGFsLTAzNDIwNjk2L2RvY3VtZW50KSkKKiBXZSB3aWxsIHRoZW4gZmlsdGVyIG91dCBiYXJjb2RlcyBhY2NvcmRpbmcgdG8gdGhlc2UgZ2VuZXJhdGVkIFFDIG1ldHJpY3MsIHVzaW5nIGEgc2VyaWVzIG9mIGNyaXRlcmlhLgoKIyMgR2VuZXJhdGluZyBhbiBTQ0Ugb2JqZWN0IGZyb20gcmF3IGRhdGEKCkZvciB0aGlzIHZlcnkgZmlyc3Qgc3RlcCwgd2Ugd2lsbCB1c2UgYSByYXRoZXIgc21hbGwgcHVibGljIGRhdGFzZXQgcHJvdmlkZWQgYnkgMTBYIEdlbm9taWNzLCB3aGljaCBjb25zaXN0cyBpbnRvIGFuIGFzc2F5IGNvbnRhaW5pbmcgfjEwMDAgaHVtYW4gUEJNQ3MgKFBlcmlwaGVyYWwgQmxvb2QgTW9ub251Y2xldXMgQ2VsbHMpLgpUaGUgc291cmNlIGRhdGEgZm9yIHRoaXMgc2FtcGxlIGNvbnNpc3RzIGluIGEgcmF3IGNvdW50IG1hdHJpeCBpbiB0aGUgMTBYIENlbGwgUmFuZ2VyIGZvcm1hdCwgYW5kIGFyZSBsb2NhdGVkIGluIHRoZSAqKltURC9EQVRBL1BCTUMxS10qKiBmb2xkZXIKCldlIHdpbGwgZmlyc3QgZ2VuZXJhdGUgYSBTaW5nbGVDZWxsRXhwZXJpbWVudCBvYmplY3QgZnJvbSB0aGUgcmF3IENlbGwgUmFuZ2VyIG1hdHJpeCA6CgoqIFBvc2l0aW9uIHlvdXIgUiB3b3JraW5nIGRpcmVjdG9yeSB0IG8gd2hlcmUgdGhlIGRhdGEgYXJlIDoKYGBgIHtyfQpzZXR3ZCgnL3NoYXJlZC9wcm9qZWN0cy88eW91cnByb2plY3RuYW1lPi9URC9EQVRBL1BCTUMxSycpCmBgYAoqIENhbGwgdGhlIGhlbHAgZm9yIHRoZSAqKipzY1RLX2xvYWQoKSoqKiBmdW5jdGlvbgpgYGAge3J9Cj9zY1RLY29tcDo6c2NUS19sb2FkCmBgYAoqIFJ1biBpdCBvbiB0aGUgMTBYIFBCTUMgMUsgZGF0YXNldApgYGAge3J9CnNuYW1lIDwtICdQQk1DMUsnCnNjVEtjb21wOjpzY1RLX2xvYWQoCiAgZGF0YV9wYXRoID0gJy4nLAogIHNhbXBsZV9uYW1lID0gc25hbWUsCiAgZXhwX25hbWUgPSBzbmFtZQopCmBgYAoqIFRoaXMgc2hvdWxkIGhhdmUgY3JlYXRlZCB0aGUgKipbUEJNQzFLXzAwYV9SYXcucmRzXSoqIGZpbGUgdGhhdCBjb250YWlucyBhIFNpbmdsZUNlbGxFeHBlcmltZW50CiogUmVhZCB0aGUgY29uc29sZSBvdXRwdXRzIHdoaWxlIHRoZXkgcG9wCiAgKiAqKipROioqIElzIHRoZSBvYnNlcnZlZCBzcGFyc2l0eSBsZXZlbCBhbGFybWluZyA/KgoKIyMgRmlsdGVyaW5nIGVtcHR5IGRyb3BsZXRzCgpXZSB3aWxsIG5vdyBmaWx0ZXIgb3V0IGFsbCB0aGVzZSBlbXB0eSBiYXJjb2Rlcy9kcm9wbGV0cyBmcm9tIHRoaXMgaHVnZSBtYXRyaXggOgoKKiBDYWxsIHRoZSBoZWxwIGZvciB0aGUgKioqc2NUS19lZGYoKSoqKiBmdW5jdGlvbgpgYGAge3J9Cj9zY1RLY29tcDo6c2NUS19lZGYKYGBgCiogUnVuIGl0IG9uIHRoZSBmcmVzaGx5IGNyZWF0ZWQgKipbUEJNQzFLXzAwYV9SYXcucmRzXSoqIFNDRSBvYmplY3QKYGBgIHtyfQpzY1RLY29tcDo6c2NUS19lZGYoaW5fcmRzID0gJy4vUEJNQzFLXzAwYV9SYXcucmRzJykKYGBgCgoqIFJlYWQgdGhlIGNvbnNvbGUgb3V0cHV0cyB3aGlsZSB0aGV5IHBvcAogICogKioqUTEgOioqIEhvdyBtYW55IGRyb3BsZXRzIHdlcmUgcmV0YWluZWQgPyoKICAqICoqKlEyIDoqKiBDb21wYXJlIHRoaXMgdmFsdWUgZnJvbSAqKmVtdHlEcm9wcyoqIHdpdGggdGhlIG9uZSBvYnRhaW5lZCB3aXRoICoqQ2VsbCBSYW5nZXIqKiAoaW4gdGhlIEhUTUwgcmVwb3J0KS4gQXJlIHRoZXkgY29uY29yZGFudCA/KgoqIE9ic2VydmUgdGhlIGdlbmVyYXRlZCBwbG90cyAoa25lZXBsb3QsIHNhdHVyYXRpb24gcGxvdCkKICAqICoqKlEzIDoqKiBXaGF0IGNvdWxkIHlvdSBzYXkgZnJvbSB0aGUga25lZXBsb3QgPyoKKiBXZSB3aWxsIG5vdyB0YWtlIGEgbG9vayBpbnNpZGUgdGhlIGd1dHMgb2YgdGhlIGdlbmVyYXRlZCBTQ0Ugb2JqZWN0IDoKICAqIENhbGwgdGhlIGhlbHAgZm9yIHRoZSBmdW5jdGlvbiAqKipzY1RLX2Rlc2NyaXB0b3IoKSoqKgogICogKiBgP3NjVEtjb21wOjpzY1RLX2Rlc2NyaXB0b3JgCiAgKiBVc2UgdGhpcyBmdW5jdGlvbiBvbiB0aGUgbmV3bHkgY3JlYXRlZCBvYmplY3QgKipbUEJNQzFLXzAxYV9FRGYucmRzXSoqCiogT2JzZXJ2ZSB0aGUgY29uc29sZSBvdXRwdXQgKihhbmQgbm90ZSB0aGUgc3BhcnNpdHkgbGV2ZWwpKgoKPGNlbnRlcj5bXSgvaG9tZS9qb2IvV09SS1NQQUNFL0VOQ0FEUkVNRU5ULzIwMjIvRUJBSUlfbjFfMjAyMi9BVEVMSUVSX1NDL1REL01EL3Jlc291cmNlcy9QQk1DMUsxMFhfa25lZXBsb3QucG5nKTwvY2VudGVyPgoKIyMgRXN0aW1hdGluZyBjb250YW1pbmF0aW9uCgpXZSB3aWxsIG5vdyB3b3JrIHdpdGggdGhlICoqJ1REQ1QnKiogc2FtcGxlIGZyb20gW1BhaXZhIGV0IGFsXShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzMwMTg3Njk0LykuIEl0IGNvbnNpc3RzIGluIGEgY2VsbCBkaXNzb2NpYXRpb24gb2YgYSBncmFmdGVkIG11cmluZSB0aHltdXMgZnJvbSBhIGp1dmVuaWxlIG1vdXNlIHRvIGFub3RoZXIganV2ZW5pbGUgbW91c2UsIHRoYXQgc2VydmVzIGFzIGEgY29udHJvbCBpbiB0aGVpciBzdHVkeS4KCiogW1N0YXJ0IFJzdHVkaW9dKCNzdGFydFJzdHVkaW8pICooaWYgbm90IGFscmVhZHkgc3RhcnRlZCkqCiogR2V0IHRvIHRoZSBkYXRhIGRpcmVjdG9yeSBjb3JyZXNwb25kaW5nIHRvIHRoZSAqKlREQ1QqKiBzYW1wbGUKYGBgIHtyfQpzZXR3ZCgnL3NoYXJlZC9wcm9qZWN0cy88bXlwcm9qZWN0bmFtZT4vVEQvREFUQS9URENUJykKYGBgCiogW1N0YXJ0IHNjVEtdKCNzY1RLc3RhcnQpCgojIyMgSW1wb3J0aW5nIGRhdGEgCgoqIFtJbXBvcnRdKCNzY1RLaW1wb3J0KSB0aGUgKipbVERDVF8wMWFfRURmLnJkc10qKiBTQ0Ugb2JqZWN0CiogR2V0IHRvICoqW1FDICYgRmlsdGVyaW5nID4gUUNdKiogCiogUnVuICoqU291cFgqKiB3aXRoIGl0cyBkZWZhdWx0IHBhcmFtZXRlcnMKKiBPYnNlcnZlIHRoZSBnZW5lcmF0ZWQgdU1BUHMgKGFuZCBleGFtcGxlIHNvdXAgbWFya2VycykKKiBbU2F2ZV0oI3NjVEtleHBvcnQpIHRoZSBTQ0UgYXMgKipbVERDVF8wMVhfU291cFgucmRzXSoqCiogW1N0b3Agc2NUS10oI3NjVEtzdG9wKQoqIFVzZSBzY1RLX2Rlc2NyaXB0b3Igb24gKipbVERDVF8wMVhfU291cFgucmRzXSoqCmBgYCB7cn0Kc2NUS2NvbXA6OnNjVEtfZGVzY3JpcHRvcignVERDVF8wMVhfU291cFgucmRzJykKYGBgCiogT2JzZXJ2ZSB0aGUgY29uc29sZSBvdXRwdXQKICAqICoqKlExIDoqKiBXaGF0IGRpZCBTb3VwWCBhY3R1YWxseSBkbyA/KgoqICooWW91IG1heSBub3cgZGVsZXRlIFtURENUXzAxWF9Tb3VwWC5yZHNdLCB3ZSB3b24ndCB1c2UgaXQgYW55bW9yZSkqCgoqKkp1c3QgZm9yIHRoZSBzaG93KiogOiBSdW4gc2NUS19kZXNjcmlwdG9yIG9uIGEgcG9zdC1Tb3VwWCBSRFMgb24gYW4gb3RoZXIgc2FtcGxlIDogTjcwNSwgZnJvbSBbQmFjb24gZXQgYWwsIDIwMThdKGh0dHBzOi8vcHVibWVkLm5jYmkubmxtLm5paC5nb3YvMzA0NDMyNTQvKSkgOgpgYGAge3J9CnNjVEtjb21wOjpzY1RLX2Rlc2NyaXB0b3IoJy9zaGFyZWQvcHJvamVjdHMvZm9ybV8yMDIyXzMyL1NpbmdsZUNlbGxSTkFTZXEvVEQvREFUQS9BTExfU1RFUFNfT0JKRUNUUy9ONzA1L043MDVfMDFYX1NvdXBYLnJkcycpCmBgYAoKIyMgUUMgTWV0cmljcyA6IEdlbmVzZXRzIGV4cHJlc3Npb24gJiBkb3VibGV0cwoKV2Ugd2lsbCBub3cgZ2VuZXJhdGUgc29tZSBRQyBtZXRyaWNzIGZvciBvdXIgY2VsbHMKCiogW1N0YXJ0IHNjVEtdKCNzY1RLc3RhcnQpCiogU2V0IHlvdXIgd29ya2luZyBkaXJlY3Rvcnkgb24gdGhlIHNhbXBsZSBkYXRhIGZvbGRlcgpgYGAge3J9CnNldHdkKCcvc2hhcmVkL3Byb2plY3RzLzx5b3VycHJvamVjdG5hbWU+L1REL0RBVEEvVERDVCcpCmBgYAoqIFtJbXBvcnRdKCNzY1RLaW1wb3J0KSAqKltURENUXzAxYV9FRGYucmRzXSoqIG9iamVjdCBhZ2FpbgoqIEltcG9ydCB0aGUgZ2VuZSBsaXN0cyByZXF1aXJlZCBmb3Igc29tZSBRQ3MgOgogICogKihNdXMgbXVzY3VsdXMgbWl0b2Nob25kcmlhbCBnZW5lcyBhcmUgYnVuZGxlZCB3aXRoIHNpbmdsZUNlbGxUSykqCiAgKiBSaWJvc29tYWwgcHJvdGVpbnMgZ2VuZXNldCA6CiAgICAqICoqW0RhdGEgPiBJbXBvcnQgR2VuZSBTZXRzXSoqCiAgICAgICogTGV0IHRoZSBsaXN0IHNlbGVjdGlvbiB0byAqKidVcGxvYWQgYSBHTVQgZmlsZScqKgogICAgICAqICoqW0Jyb3dzZV0qKiB0byBzZWxlY3QgdGhlICoqJy4uLy4uL1JFU09VUkNFUy9HRU5FTElTVFMvbXVzX211c2N1bHVzX3JpYm9fc3ltYm9sc18yMDIyMTEwNS5nbXQnKioKICAgICAgKiBTZXQgKionUmlibycqKiBhcyBDb2xsZWN0aW9uIE5hbWUKICAgICAgKiAqKltVcGxvYWRdKiouCiAgKiBEaXNzb2NpYXRpb24gLyBtZWNoYW5pY2FsIHN0cmVzcyBnZW5lc2V0IDogICAKICAgICogKipbRGF0YSA+IEltcG9ydCBHZW5lIFNldHNdKioKICAgICAgKiBJbiB0aGUgc2FtZSB3YXksIGxldCB0aGUgbGlzdCBzZWxlY3Rpb24gdG8gKionVXBsb2FkIGEgR01UIGZpbGUnKioKICAgICAgKiAqKltCcm93c2VdKiogdG8gc2VsZWN0IHRoZSAqKicuLi8uLi9SRVNPVVJDRVMvR0VORUxJU1RTL211c19tdXNjdWx1c19zdHJlc3Nfc3ltYm9sc18yMDIyMTEwNy5nbXQgJyoqCiAgICAgICogU2V0ICoqJ1N0cmVzcycqKiBhcyBDb2xsZWN0aW9uIE5hbWUKICAgICAgKiAqKltVcGxvYWRdKiouCiogUGVyZm9ybSBkb3VibGV0cyBpZGVudGlmaWNhdGlvbiB3aXRoIG1ldGhvZCA6CiAgKiBUZWFtIEEgOiAqKnNjRGJsRmluZGVyKioKICAqIFRlYW0gQiA6ICoqc2NkcyAoY3hkcyBiY2RzIGh5YnJpZCkqKgogICogVGVhbSBDIDogKipib3RoKioKICAqIFRlYW0gRCA6ICoqRG91YmxldEZpbmRlcioqCiogT2JzZXJ2ZSBnZW5lcmF0ZWQgdU1BUAoqIFBlcmZvcm0gUUMgKGFuZCBvYnNlcnZlIFFDIHBsb3RzIGVhY2ggdGltZSkgd2l0aAogICogTWl0bwogICogUmlibwogICogU3RyZXNzCiogR2V0IHRvIHRoZSAqKltDZWxsIFZpZXdlcl0qKiB0byBvYnNlcnZlIFFDIG1ldHJpY3Mgb24gdGhlICoqW1FDX1VNQVBdKioKKiBbRGVsZXRlXSgjc2NUS2RlbGV0ZSkgYWxsIG1ldGFkYXRhICoqYnV0KiogdGhlIGZpcnN0IDUgYW5ub3RhdGlvbnMsIFwqX3BlcmNlbnQsIHBlcmNlbnQudG9wLlwqIGFuZCBcKl9jYWxsCiogW1NhdmVdKCNzY1RLZXhwb3J0KSB0aGUgU0NFIG9iamVjdCBhcyAqKltURENUXzAxYl9RQy5yZHNdKioKKiBbU3RvcCBzY1RLXSgjc2NUS3N0b3ApCgojIyBFc3RpbWF0ZSB0aGUgY2VsbCBjeWNsZSBwaGFzZQoKV2Ugd2lsbCBub3cgZXN0aW1hdGUgdGhlIGNlbGwgY3lsZSBwaGFzZSBzdGF0dXMgb2Ygb3VyIGNlbGxzIHRoYW5rcyB0byBTZXVyYXQKCiogQ2FsbCB0aGUgaGVscCBmb3IgdGhlICoqKnNjVEtfY2Nfc2V1cmF0KCkqKiogZnVuY3Rpb24KYGBgIHtyfQo/c2NUS2NvbXA6OnNjVEtfY2Nfc2V1cmF0CmBgYAoqIFRoaXMgZnVuY3Rpb24gd2lsbCBhbHNvIG5lZWQgYW5vdGhlciBSRFMgb2JqZWN0IChhdmFpbGFibGUgaW4gdGhlICoqWy9zaGFyZWQvcHJvamVjdHMvPHlvdXJwcm9qZWN0bmFtZT4vVEQvUkVTT1VSQ0VTL0dFTkVMSVNUU10qKiBkaXJlY29yeSkgdGhhdCBjb250YWlucyAyIGdlbmVzZXRzIDoKICAqIFMgcGhhc2Ugc2lnbmF0dXJlCiAgKiBHMk0gcGhhc2Ugc2lnbmF0dXJlCgoqIFJ1biBpdCBvbiB0aGUgZnJlc2hseSBjcmVhdGVkICoqW1REQ1RfMDFiX1FDLnJkc10qKiBTQ0Ugb2JqZWN0LiAKYGBgIHtyfQpzY1RLY29tcDo6c2NUS19jY19zZXVyYXQoCiAgaW5fcmRzID0gJ1REQ1RfMDFiX1FDLnJkcycsCiAgYXNzYXkgPSAnY291bnRzJywKICBjY19zZXVyYXRfZmlsZSA9ICcvc2hhcmVkL3Byb2plY3RzLzx5b3VycHJvamVjdG5hbWU+L1REL1JFU09VUkNFUy9HRU5FTElTVFMvbXVzX211c2N1bHVzX1NldXJhdF9jYy5nZW5lc18yMDE5MTAzMS5yZHMnKQpgYGAKKiBSZWFkIHRoZSBjb250aW5nZW5jeSB0YWJsZSBmb3IgZXN0aW1hdGVkIHBoYXNlcyBpbiB0aGUgY29uc29sZSBvdXRwdXQKKiBbU3RhcnQgc2NUS10oI3NjVEtzdGFydCkKKiBTZXQgeW91ciB3b3JraW5nIGRpcmVjdG9yeSBvbiB0aGUgc2FtcGxlIGRhdGEgZm9sZGVyCmBgYCB7cn0Kc2V0d2QoJy9zaGFyZWQvcHJvamVjdHMvPHlvdXJwcm9qZWN0bmFtZT4vVEQvREFUQS9URENUJykKYGBgCiogW0ltcG9ydF0oI3NjVEtpbXBvcnQpIHRoZSBmcmVzaGx5IGNyZWF0ZWQgKipbVERDVF8wMmFfY291bnRzX0NDLnNldXJhdC5yZHNdKiogU0NFIG9iamVjdAoqIGluIHRoZSAqKltDZWxsIFZpZXdlcl0qKiwgb24gdGhlICoqUUNfVU1BUCoqLCBvYnNlcnZlIGNlbGwgYW5ub3RhdGlvbnMgOgogICogQ0MgcGhhc2UKICAqIFNtRzJNIHNjb3JlLCB3aXRoIGEgc3BsaXQgYnkgQ0MgUGhhc2UKCiMjIEZpbHRlciBjZWxscyBhbmQgZmVhdHVyZXMKCiogKipBdCB0aGUgYmFyY29kZSBsZXZlbCoqIDogQXBwbHkgdGhlc2UgZmlsdGVyaW5nIGNyaXRlcmlhIChzdGVwIGJ5IHN0ZXAsIHRvIG1lYXN1cmUgdGhlaXIgaW1wYWN0KToKICAqIG5GZWF0dXJlICoqPiAxOTkqKgogICogbkZlYXR1cmUgKio8IDI5OTkqKgogICogbkNvdW50ICoqPjk5OSoqCiAgKiBNaXRvX3BlcmNlbnQgKio8IDUqKiAoJSkKICAqIGRvdWJsZXRzX2NhbGwgOiAqKlNpbmdsZXQqKgoqICoqQXQgdGhlIGZlYXR1cmUgbGV2ZWwqKiA6IGtlZXAgZmVhdHVyZXMgd2l0aCA6CiAgKiAqKjEgY291bnQqKiBpbiBhdCBsZWFzdCAqKjUgY2VsbHMqKgoqICpbRGVsZXRlXSgjc2NUS2RlbGV0ZSkgdW5uZWVkZWQgKipRQ19VTUFQKiogcmVkdWN0aW9uKgoqIFtTYXZlXSgjc2NUS2V4cG9ydCkgb2JqZWN0IGFzICoqW1REQ1RfMDJiX1FDZi5yZHNdKioKCiMgTk9STUFMSVpBVElPTgoKIyMgKk1lcmdlIGRhdGFzZXRzKgoKVGhlIHN0dWR5IGZyb20gd2hpY2ggY2FtZSB0aGUgKipURENUKiogc2FtcGxlIGhhZCBhbm90aGVyIHNhbXBsZSA6ICoqVEQzQSoqLiBUaGlzIHNlY29uZCBzYW1wbGUgY29uc2lzdHMgaW50byBhbm90aGVyIGdyYWZ0IG9mIGEganV2ZW5pbGUgbW91c2UgdGh5bXVzIHRvIGFub3RoZXIganV2ZW5pbGUgb25lLCBleGNlcHQgdGhhdCBpbiB0aGlzIGNhc2UgdGhlIGhvc3QgaXMgbXV0YXRlZCBzbyB0aGF0IGl0IGNhbm5vdCBwcm9kdWNlIHRoZSBleHBlY3RlZCBUIGNlbGwgcHJvZ2VuaXRvcnMgZnJvbSBpdHMgc3BpbmUgYm9uZSBtYXJyb3cuCgpJbiBub3JtYWwgY2lyY3Vtc3RhbmNlcywgd2hlbiB0aGVyZSBpcyBhIHNob3J0IHBlcmlvZCBkdXJpbmcgd2hpY2ggdGhlIHNwaW5lIGJvbmUgbWFycm93IGlzIHVuYWJsZSB0byBwcm9kdWNlIHN1Y2ggcHJvZ2VuaXRvcnMsIGl0IGlzIGFscmVhZHkga25vd24gdGhhdCBhIG1lY2hhbmlzbSAoY2FsbGVkICoqYXV0b25vbXkqKikgYWN0aXZhdGVzLCBzdWNoIHRoYXQgc29tZSB1bmtub3duIGltbWF0dXJlIGNlbGwgdHlwZSBmcm9tIHRoZSB0aHltdXMgYmVoYXZlcyBhcyBhIHByb2dlbml0b3IuIFRoZSBhaW0gb2YgdGhpcyBzdHVkeSB3YXMgdG8gaWRlbnRpZnkgd2hpY2ggY2VsbCB0eXBlIGluIHRoZSBUIGNlbGwgbWF0dXJhdGlvbiBzdGFnZXMgaGFzIHRoaXMgYWJpbGl0eS4KCkl0IGlzIGFsc28gaW1wb3J0YW50IHRvIG5vdGUgdGhhdCBzdWNoIG1lY2hhbmlzbSwgd2hlbiBsYXN0aW5nIHRvIGxvbmcsIGlzIHZlcnkgcHJvbmUgdG8gc3RhcnQgbGV1a2VtaWEuLi4KCldlIHdpbGwga25vdyBtZXJnZSB0aGUgdHdvIHNhbXBsZXMgdG8gYW5hbHl6ZSB0aGVtLCBpbiBhIGNvbXBhcmlzb24gcHVycG9zZS4KCiogW1N0b3Agc2NUS10oI3NjVEtzdG9wKQoqIFNldCB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5IG9uIHRoZSBzYW1wbGUgZGF0YSBmb2xkZXIKYGBgIHtyfQpzZXR3ZCgnL3NoYXJlZC9wcm9qZWN0cy88eW91cnByb2plY3RuYW1lPi9URC9EQVRBL0lOVEVHUkFURUQnKQpgYGAKKiBbU3RhcnQgc2NUS10oI3NjVEtzdGFydCkKKiBbSW1wb3J0XSgjc2NUS2ltcG9ydCkgKipbLi4vVERDVC9URENUXzAyYl9RQ2YucmRzXSoqIGFuZCAqKlsuLi9URDNBL1REM0FfMDJiX1FDZi5yZHNdKiouCiAgKiAqKipXQVJOSU5HIDoqKiBUaGlzIHRpbWUgeW91IGltcG9ydCB0aGUgMiBvYmplY3RzIGF0IHRoZSBzYW1lIHRpbWUuIEJlIGNhcmVmdWwgdG8gYWRkIHRoZW0gYm90aCB0byB0aGUgc2FtcGxlIGxpc3QgKipiZWZvcmUqKiBpbXBvcnRpbmcuKgoqIFtEZWxldGVdKCNzY1RLZGVsZXRlKSAicm93bmFtZXMiIChieXBhc3NlcyBhIGJ1ZyBmb3IgUUMgcGxvdHMpCiAgKiAqKipXQVJOSU5HIDoqKiBEbyBub3Qgc2tpcCB0aGlzIHN0ZXAgb3IgeW91J2xsIGJlIGluIHRyb3VibGUgc29vbiAhKgoqIFBlcmZvcm0gYmFzaWMgUUNzIGFuZCBvYnNlcnZlIGJveHBsb3RzCiAgKiAqSWYgeW91IGFyZSBsb3N0IGluIGFuIGluZmluaXRlIHdhaXRpbmcgbG9vcCwgeW91IGRpZCBub3QgcmVhZCB0aGUgbGFzdCB3YXJuaW5nIDpEKgogICogKioqUTEgOioqIEhvdyBzaW1pbGFyIGFyZSB0aGVzZSB0d28gc2FtcGxlcyB3aGVuIGNvbnNpZGVyaW5nIDoqCiAgICAqICpUaGVpciBnbG9iYWxseSBtZWFzdXJlZCBleHByZXNzaW9uIGxldmVsID8qCiAgICAqICpUaGUgZXhwcmVzc2lvbiBsZXZlbCBvZiB0aGVpciB0b3AgNTAgZXhwcmVzc2VkIGdlbmVzID8qCiogKltEZWxldGVdKHNjVEtkZWxldGUpIHVubmVlZGVkIGJhcmNvZGUgYW5ub3RhdGlvbnMgOiAqKnN1bSwgZGV0ZWN0ZWQsIHRvdGFsKioqCiogW1NhdmVdKCNzY1RLZXhwb3J0KSB0aGUgU0NFIG9iamVjdCBhcyAqKltURENULlREMzFfMDJiX1FDZi5yZHNdKioKKiBbU3RvcCBzY1RLXSgjc2NUS3N0b3ApCiogUnVuICoqKnNjVEtfZGVzY3JpcHRvcioqKiAob25seSBkZXNjcmliaW5nIGFzc2F5cykgb24gdGhlc2UgMyBTQ0Ugb2JqZWN0cyA6CiAgKiAqKltURENUXzAyYl9RQ2YuUkRTXSoqIChDb250cm9sKQogICogKipbVEQzQV8wMmJfUUNmLlJEU10qKiAoQXV0b25vbXkpCiAgKiAqKltURENULlREMzFfMDJiX1FDZi5SRFNdKiogKE1lcmdlZCkKICAgICogKioqUTIgOioqIERvIHRoaW5ncyBhZGQgdXAgKGZlYXR1cmVzIC8gY2VsbHMpID8qCgojIyBOb3JtYWxpemF0aW9uCgoqIFtTdGFydCBzY1RLXSgjc2NUS3N0YXJ0KQoqIFNldCB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5IG9uIHRoZSBzYW1wbGUgZGF0YSBmb2xkZXIKYGBgIHtyfQpzZXR3ZCgnL3NoYXJlZC9wcm9qZWN0cy88eW91cnByb2plY3RuYW1lPi9URC9EQVRBL0lOVEVHUkFURUQnKQpgYGAKKiBbSW1wb3J0XSgjc2NUS2ltcG9ydCkgYWdhaW4gdGhlICoqW1REQ1QuVEQzQV8wMmJfUUNmLnJkc10qKiBTQ0Ugb2JqZWN0CiogR2V0IHRvICoqW05vcm1hbGl6YXRpb24gJiBCYXRjaCBDb3JyZWN0aW9uID4gTm9ybWFsaXphdGlvbl0qKgoqIFVzZSA6CiAgKiBNZXRob2QgOiAqKlNldXJhdCAtIExvZ05vcm1hbGl6ZSoqCiAgKiBJbnB1dCBhc3NheSA6ICoqY291bnRzKioKICAqIE91dHB1dCBhc3NheSBuYW1lID0gKionU0xOc3QnKioKICAqIFVzZSBzY2FsaW5nCiAgKiBVc2UgdHJpbW1pbmcsIGxldCBkZWZhdWx0IGxpbWl0cwoqIFtTYXZlXSgjc2NUS2V4cG9ydCkgdGhlIFNDRSBvYmplY3QgYXMgKipbVERDVC5URDNBXzAyY19TTE5zdC5yZHNdKioKICAqICpUaGlzIHNob3VsZCB0YWtlIG1vcmUgdGltZSB0aGFuIHlvdSBhcmUgdXNlZCB0byBmcm9tIGVhcmxpZXIgc3RlcHMuIFRoaXMgaXMgZHVlIHRvIHRoZSBmYWN0IHRoYXQgd2hpbGUgdGhlICoqcmF3ICdjb3VudHMnKiogbWF0cml4IGNvbnNpc3RzIGluIGEgdmVyeSBzcGFyc2UsIHRodXMgdmVyeSBjb21wcmVzc2VkIG1hdHJpeCwgdGhlICoqbm9ybWFsaXplZCAnU0xOc3QnKiogbWF0cml4IGNvbnRhaW5zIG51bWVyaWMgdmFsdWVzLCB3aGljaCBjb21wcmVzcyB3aXRoIGEgbWVkaW9jcmUgcmF0aW8qCiogW1N0b3Agc2NUS10oI3NjVEtzdG9wKQoqIERlc2NyaWJlIHRoZSBmcmVzaGx5IHNhdmVkICoqW1REQ1QuVEQzQV8wMmNfU0xOc3QucmRzXSoqCmBgYCB7cn0Kc2NUS2NvbXA6OnNjVEtfZGVzY3JpcHRvcignVERDVC5URDNBXzAyY19TTE5zdC5yZHMnKQpgYGAKICAqICoqKlExIDoqKiBXaGF0IGNvdWxkIHlvdSBzYXkgZm9yIG91ciBuZXcgYXNzYXkgPyoK