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
CHEAT SHEET
Here is a list of different guidelines you should refer to, as they
correspond to actions you would perform frequently.
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)
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
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
Starting scTK
- 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.
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
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.
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.
Stopping singleCellTK
- Close your scTK browser tab
- In Rstudio :
- Clic in the console and press [Esc].
- or clic on the red [Stop]
button.
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 !
WARMUP
Preamble
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 :
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.
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
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/
Starting Rstudio
- Just click on the Rstudio logo
- Optionally : load the scTKcomp
package
FROM COUNTS TO
CELLS
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.
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
- 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
?
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
- 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)
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')
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')
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
- 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
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
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]
NORMALIZATION
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)
?
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