Introduction
Understanding GDC (genomics data common portal)
In this workshop we will access (The Cancer Genome Atlas) data available at the NCI’s Genomic Data Commons (GDC). Before we start, it is important to know that the data is deposit in two different databases:
An overview of the web portal is available at https://docs.gdc.cancer.gov/Data_Portal/Users_Guide/Getting_Started/.
Also, a more in-depth comparison between the legacy and Harmonized data was recently published:
Understanding TCGA data
Data access
GDC provides the data with two access levels:
- Open: includes high level genomic data that is not individually identifiable, as well as most clinical and all biospecimen data elements.
- Controlled: includes individually identifiable data such as low-level genomic sequencing data, germline variants, SNP6 genotype data, and certain clinical data elements
You can find more information about those two levels and how to get access to controlled data at: https://gdc.cancer.gov/access-data/data-access-processes-and-tools.
Data structure
In order to filter the data available in GDC some fields are available such as project (TCGA, TARGET, etc.), data category (Transcriptome Profiling, DNA methylation, Clinical, etc.), data type (Gene Expression Quantification, Isoform Expression Quantification, Methylation Beta Value, etc.), experimental strategy (miRNA-Seq, RNA-Seq, etc.), Workflow Type, platform, access type and others.
In terms of data granularity, a project has data on several categories, each category contains several data types that might have been produced with different workflows, experimental strategy and platforms. In that way, if you select data type “Gene Expression Quantification” the data category will be Transcriptome Profiling.
You can find the entry possibilities for each filter at the repository page of the database at https://portal.gdc.cancer.gov/repository.
The SummarizedExperiment data structure
Before we start, it is important to know that the R/Bioconductor environment provides a data structure called SummarizedExperiment
, which was created to handle both samples metadata (age, gender, etc), genomics data (i.e. DNA methylation beta value) and genomics metadata information (chr, start, end, gene symbol) in the same object. You can access samples metadata with colData
function, genomics data with assays
and genomics metadata with rowRanges
.
Loading required packages
library(TCGAbiolinks)
library(MultiAssayExperiment)
library(maftools)
library(dplyr)
library(ComplexHeatmap)
In case those packages are not available, you can install those packages using BiocManager.
if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
if (!requireNamespace("ComplexHeatmap", quietly = TRUE))
BiocManager::install("ComplexHeatmap") # from bioconductor
if (!requireNamespace("TCGAbiolinks", quietly = TRUE))
BiocManager::install("BioinformaticsFMRP/TCGAbiolinks") # from github
Working with TCGA data
During this workshop we will be using open access data from the harmonized GDC database (hg38 version), which can be accessed at https://portal.gdc.cancer.gov/.
Through the next sections we will:
- Access TCGA clinical data
- Search, download and make an R object from TCGA data
- RNA-seq data
- DNA methylation
- Download samples metadata
- Download and visualize mutations
- Download and visualize copy number alterations
Clinical data
In GDC database the clinical data can be retrieved from different sources:
- indexed clinical: a refined clinical data that is created using the XML files.
- XML files: original source of the data
- BCR Biotab: tsv files parsed from XML files
There are two main differences between the indexed clinical and XML files:
- XML has more information: radiation, drugs information, follow-ups, biospecimen, etc. So, the indexed one is only a subset of the XML files
- The indexed data contains the updated data with the follow up information. For example: if the patient was alive when the clinical data was collect and then in the next follow-up he is dead, the indexed data will show dead. The XML will have two fields, one for the first time saying he is alive (in the clinical part) and the follow-up saying he is dead.
Other useful clinical information available are:
- Tissue slide image
- Pathology report - Slide image
You can check examples in TCGAbiolinks vignette at https://bioconductor.org/packages/release/bioc/vignettes/TCGAbiolinks/inst/doc/clinical.html.
# Access indexed clinical data
clinical <- GDCquery_clinic("TCGA-COAD")
head(clinical)
The clinical indexed data is the same you can see in the GDC data portal. Observation: the GDC API provides age_at_diagnosis in days.
# Same case as figure above
clinical %>%
dplyr::filter(submitter_id == "TCGA-AA-3562") %>%
t %>%
as.data.frame
You can also access Biotab files which are TSV files created from the XML files (only works for TCGAbiolinks version higher than 2.13.5).
query <- GDCquery(project = "TCGA-ACC",
data.category = "Clinical",
data.type = "Clinical Supplement",
data.format = "BCR Biotab")
GDCdownload(query)
clinical.BCRtab.all <- GDCprepare(query)
names(clinical.BCRtab.all)
## [1] "clinical_omf_v4.0_acc" "clinical_follow_up_v4.0_nte_acc"
## [3] "clinical_radiation_acc" "clinical_patient_acc"
## [5] "clinical_nte_acc" "clinical_follow_up_v4.0_acc"
## [7] "clinical_drug_acc"
clinical.BCRtab.all$clinical_drug_acc %>%
head %>%
as.data.frame
RNA-Seq data
The RNA-Seq pipeline produces raw counts, FPKM and FPKM-UQ quantifications and is described at https://docs.gdc.cancer.gov/Data/Bioinformatics_Pipelines/Expression_mRNA_Pipeline/.
The following options are used to search mRNA results using TCGAbiolinks:
- data.category: “Transcriptome Profiling”
- data.type: “Gene Expression Quantification”
- workflow.type: “HTSeq - Counts”, “HTSeq - FPKM”, “HTSeq - FPKM-UQ”
Here is the example to download the raw counts, which can be used with DESeq2 (http://bioconductor.org/packages/DESeq2/) for differential expression analysis.
query.exp.hg38 <- GDCquery(project = "TCGA-GBM",
data.category = "Transcriptome Profiling",
data.type = "Gene Expression Quantification",
workflow.type = "HTSeq - Counts",
barcode = c("TCGA-14-0736-02A-01R-2005-01", "TCGA-06-0211-02A-02R-2005-01"))
GDCdownload(query.exp.hg38)
raw.counts <- GDCprepare(query = query.exp.hg38, summarizedExperiment = FALSE)
Here is the example to download the FPKM-UQ counts.
query.exp.hg38 <- GDCquery(project = "TCGA-GBM",
data.category = "Transcriptome Profiling",
data.type = "Gene Expression Quantification",
workflow.type = "HTSeq - FPKM-UQ",
barcode = c("TCGA-14-0736-02A-01R-2005-01", "TCGA-06-0211-02A-02R-2005-01"))
GDCdownload(query.exp.hg38)
fpkm.uq.counts <- GDCprepare(query = query.exp.hg38, summarizedExperiment = FALSE)
Mutation
TCGAbiolinks has provided a few functions to download mutation data from GDC. There are two options to download the data:
- Use
GDCquery_Maf
which will download MAF aligned against hg38.
This example will download MAF (mutation annotation files) for variant calling pipeline muse. Pipelines options are: muse
, varscan2
, somaticsniper
, mutect
. For more information please access GDC docs.
You can download the data using TCGAbiolinks GDCquery_Maf
function.
# GDCquery_Maf download the data from GDC
maf <- GDCquery_Maf("COAD", pipelines = "muse")
maf %>% head %>% as.data.frame
Then visualize the results using the maftools package.
# using maftools for data summary
maftools.input <- maf %>% read.maf
# Check summary
plotmafSummary(maf = maftools.input,
rmOutlier = TRUE,
addStat = 'median',
dashboard = TRUE)

oncoplot(maf = maftools.input,
top = 10,
removeNonMutated = TRUE)

# classifies Single Nucleotide Variants into Transitions and Transversions
titv = titv(maf = maftools.input,
plot = FALSE,
useSyn = TRUE)
plotTiTv(res = titv)

You can extract sample summary from MAF object.
getSampleSummary(maftools.input)
Copy number alteration data
The Copy Number Variation Analysis Pipeline is described at https://docs.gdc.cancer.gov/Data/Bioinformatics_Pipelines/CNV_Pipeline/
Numeric focal-level Copy Number Variation (CNV) values were generated with “Masked Copy Number Segment” files from tumor aliquots using GISTIC2 on a project level. Only protein-coding genes were kept, and their numeric CNV values were further thresholded by a noise cutoff of 0.3:
- Genes with focal CNV values smaller than -0.3 are categorized as a “loss” (-1)
- Genes with focal CNV values larger than 0.3 are categorized as a “gain” (+1)
- Genes with focal CNV values between and including -0.3 and 0.3 are categorized as “neutral” (0).
You can access “Gene Level Copy Number Scores” from GISTIC with the code below:
query <- GDCquery(project = "TCGA-GBM",
data.category = "Copy Number Variation",
data.type = "Gene Level Copy Number Scores",
access = "open")
GDCdownload(query)
scores <- GDCprepare(query)
You can visualize the data using the R/Bioconductor package complexHeatmap.
scores.matrix <- scores %>%
dplyr::select(-c(1:3)) %>% # Removes metadata from the first 3 columns
as.matrix
rownames(scores.matrix) <- paste0(scores$`Gene Symbol`,"_",scores$Cytoband)
# gain in more than 100 samples
gain.more.than.hundred.samples <- which(rowSums(scores.matrix == 1) > 100)
# loss in more than 100 samples
loss.more.than.hundred.samples <- which(rowSums(scores.matrix == -1) > 100)
lines.selected <- c(gain.more.than.hundred.samples,loss.more.than.hundred.samples)
Heatmap(scores.matrix[lines.selected,],
show_column_names = FALSE,
show_row_names = TRUE,
row_names_gp = gpar(fontsize = 8),
col = circlize::colorRamp2(c(-1,0,1), colors = c("red","white","blue")))

DNA methylation data
The processed DNA methylation data measure the level of methylation at known CpG sites as beta values, calculated from array intensities (Level 2 data) as Beta = \(M/(M+U)\) (Zhou, Laird, and Shen 2017) which ranges from 0 being unmethylated and 1 fully methylated.
More information about the DNA methylation pipeline is available at https://docs.gdc.cancer.gov/Data/Bioinformatics_Pipelines/Methylation_LO_Pipeline/.
We will download two Glioblastoma (GBM) as a summarizedExperiment object.
query_met.hg38 <- GDCquery(project = "TCGA-GBM",
data.category = "DNA Methylation",
platform = "Illumina Human Methylation 27",
barcode = c("TCGA-02-0116-01A","TCGA-14-3477-01A-01D"))
GDCdownload(query_met.hg38)
data.hg38 <- GDCprepare(query_met.hg38,summarizedExperiment = TRUE)
## class: RangedSummarizedExperiment
## dim: 27578 2
## metadata(1): data_release
## assays(1): ''
## rownames(27578): cg00000292 cg00002426 ... cg27662877 cg27665659
## rowData names(7): Composite.Element.REF Gene_Symbol ...
## CGI_Coordinate Feature_Type
## colnames(2): TCGA-02-0116-01A-01D-0199-05
## TCGA-14-3477-01A-01D-0915-05
## colData names(113): sample patient ...
## subtype_Telomere.length.estimate.in.blood.normal..Kb.
## subtype_Telomere.length.estimate.in.tumor..Kb.
You can access the probes information with rowRanges
.
data.hg38 %>% rowRanges %>% as.data.frame
You can access the samples metadata with colData
.
data.hg38 %>% colData %>% as.data.frame
You can access the DNA methylation levels with assay
.
data.hg38 %>% assay %>% head %>% as.data.frame
# plot 10 most variable probes
data.hg38 %>%
assay %>%
rowVars %>%
order(decreasing = TRUE) %>%
head(10) -> idx
pal_methylation <- colorRampPalette(c("#000436",
"#021EA9",
"#1632FB",
"#6E34FC",
"#C732D5",
"#FD619D",
"#FF9965",
"#FFD32B",
"#FFFC5A"))(100)
Heatmap(assay(data.hg38)[idx,],
show_column_names = TRUE,
show_row_names = TRUE,
name = "Methylation Beta-value",
row_names_gp = gpar(fontsize = 8),
column_names_gp = gpar(fontsize = 8),
col = circlize::colorRamp2(seq(0, 1, by = 1/99), pal_methylation))

LS0tCnRpdGxlOiAiV29ya3Nob3AgLSBUQ0dBIGRhdGEgYW5hbHlzaXMiCmF1dGhvcjogIkJlbmphbWluIFAuIEJlcm1hbiwgVGlhZ28gQy4gU2lsdmEiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIHJtYXJrZG93bjo6aHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBsdW1lbgogICAgaGlnaGxpZ2h0OiB6ZW5idXJuCiAgICB0b2M6IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKYmlibGlvZ3JhcGh5OiB0Y2dhYmlvbGlua3MuYmliICAgIAotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZHBpID0gMzAwKQpgYGAKCjxzdHlsZT4KZGl2LmJsdWUgeyBiYWNrZ3JvdW5kLWNvbG9yOiNlNmYwZmY7IGJvcmRlci1yYWRpdXM6IDVweDsgcGFkZGluZzogMjBweDt9CgogYm9keSB7dGV4dC1hbGlnbjoganVzdGlmeX0KcC5jYXB0aW9uIHsKICBmb250LXNpemU6IDAuOWVtOwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKICBjb2xvcjogZ3JleTsKICBtYXJnaW4tcmlnaHQ6IDEwJTsKICBtYXJnaW4tbGVmdDogMTAlOyAgCiAgdGV4dC1hbGlnbjoganVzdGlmeTsKfQo8L3N0eWxlPgoKCiMgSW5zdHJ1Y3RvciBuYW1lcyBhbmQgY29udGFjdCBpbmZvcm1hdGlvbgoKMS4gQmVuamFtaW4gUC4gQmVybWFuIChCZW5qYW1pbi5CZXJtYW4gYXQgY3Nocy5vcmcpCjIuIFRpYWdvIEMuIFNpbHZhICh0aWFnb2Noc3QgYXQgZ21haWwuY29tKQoKIyBXb3Jrc2hvcCBkZXNjcmlwdGlvbgoKIyMgQWltcwoKVGhpcyB3b3Jrc2hvcCB3aWxsOgoKMS4gSW50cm9kdWNlIHlvdSB0byB0aGUgVENHQSAoVGhlIENhbmNlciBHZW5vbWUgQXRsYXMpIGRhdGEgYXZhaWxhYmxlIGF0IHRoZSBOQ0kncyBHZW5vbWljIERhdGEgQ29tbW9ucyAoR0RDKS4KMi4gRGVtb25zdHJhdGUgaG93IHRvIGFjY2VzcyBhbmQgaW1wb3J0IFRDR0EgZGF0YSB1c2luZyB0aGUgUi9CaW9jb25kdWN0b3IgcGFja2FnZSBUQ0dBYmlvbGlua3MgW0Bjb2xhcHJpY28yMDE1dGNnYWJpb2xpbmtzXS4gCjMuIFByb3ZpZGUgaW5zdHJ1Y3Rpb24gdG8gdmlzdWFsaXplIGNvcHkgbnVtYmVyIGFsdGVyYXRpb24gYW5kIG11dGF0aW9uIGRhdGEgdXNpbmcgdGhlIFIvQmlvY29uZHVjdG9yIHBhY2thZ2UgbWFmdG9vbHMuCgoKIyMgVXNlZnVsIGxpbmtzIAoKLSB0aGUgTkNJJ3MgR2Vub21pYyBEYXRhIENvbW1vbnMgKEdEQyk6IGh0dHBzOi8vZ2RjLmNhbmNlci5nb3YvLgotIFRDR0FiaW9saW5rcyBwYWNrYWdlOiBodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9UQ0dBYmlvbGlua3MvCi0gbWFmdG9vbHMgcGFja2FnZTogaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvbWFmdG9vbHMvCgojIyBSZWZlcmVuY2UgYXJ0aWNsZXMgCgotIFRDR0FiaW9saW5rczoKICAtIENvbGFwcmljbywgQW50b25pbywgZXQgYWwuIOKAnFRDR0FiaW9saW5rczogYW4gUi9CaW9jb25kdWN0b3IgcGFja2FnZSBmb3IgaW50ZWdyYXRpdmUgYW5hbHlzaXMgb2YgVENHQSBkYXRhLuKAnSBOdWNsZWljIGFjaWRzIHJlc2VhcmNoIDQ0LjggKDIwMTUpOiBlNzEtZTcxLgpTaWx2YSwgVGlhZ28gQy4sIGV0IGFsLiDigJxUQ0dBIFdvcmtmbG93OiBBbmFseXplIGNhbmNlciBnZW5vbWljcyBhbmQgZXBpZ2Vub21pY3MgZGF0YSB1c2luZyBCaW9jb25kdWN0b3IgcGFja2FnZXMu4oCdIEYxMDAwUmVzZWFyY2ggNSAoMjAxNikuIChodHRwczovL2YxMDAwcmVzZWFyY2guY29tL2FydGljbGVzLzUtMTU0Mi92MikKICAtIE1vdW5pciwgTW9oYW1lZCwgZXQgYWwuIOKAnE5ldyBmdW5jdGlvbmFsaXRpZXMgaW4gdGhlIFRDR0FiaW9saW5rcyBwYWNrYWdlIGZvciB0aGUgc3R1ZHkgYW5kIGludGVncmF0aW9uIG9mIGNhbmNlciBkYXRhIGZyb20gR0RDIGFuZCBHVEV4LuKAnSBQTG9TIGNvbXB1dGF0aW9uYWwgYmlvbG9neSAxNS4zICgyMDE5KTogZTEwMDY3MDEuIChodHRwczovL2RvaS5vcmcvMTAuMTM3MS9qb3VybmFsLnBjYmkuMTAwNjcwMSkKICAtICBTaWx2YSBUQywgQ29sYXByaWNvIEEsIE9sc2VuIEMgZXQgYWwuVENHQSBXb3JrZmxvdzogQW5hbHl6ZSBjYW5jZXIgZ2Vub21pY3MgYW5kIGVwaWdlbm9taWNzIGRhdGEgdXNpbmcgQmlvY29uZHVjdG9yIHBhY2thZ2VzIFt2ZXJzaW9uIDI7IHBlZXIgcmV2aWV3OiAxIGFwcHJvdmVkLCAyIGFwcHJvdmVkIHdpdGggcmVzZXJ2YXRpb25zXS4gRjEwMDBSZXNlYXJjaCAyMDE2LCA1OjE1NDIKKGh0dHBzOi8vZG9pLm9yZy8xMC4xMjY4OC9mMTAwMHJlc2VhcmNoLjg5MjMuMikuIAoKLSBUaGUgTkNJJ3MgR2Vub21pYyBEYXRhIENvbW1vbnMgKEdEQyk6CiAgLSBHYW8sIEdhbGVuIEYuLCBldCBhbC4g4oCcQmVmb3JlIGFuZCBBZnRlcjogQ29tcGFyaXNvbiBvZiBMZWdhY3kgYW5kIEhhcm1vbml6ZWQgVENHQSBHZW5vbWljIERhdGEgQ29tbW9uc+KAmSBEYXRhLuKAnSBDZWxsIHN5c3RlbXMgOS4xICgyMDE5KTogMjQtMzQuIChodHRwczovL2RvaS5vcmcvMTAuMTAxNi9qLmNlbHMuMjAxOS4wNi4wMDYpCgotIE1hZnRvb2xzOgogIC0gTWF5YWtvbmRhIEEsIExpbiBELCBBc3Nlbm92IFksIFBsYXNzIEMsIEtvZWZmbGVyIFBIICgyMDE4KS4g4oCcTWFmdG9vbHM6IGVmZmljaWVudCBhbmQgY29tcHJlaGVuc2l2ZSBhbmFseXNpcyBvZiBzb21hdGljIHZhcmlhbnRzIGluIGNhbmNlci7igJ0gR2Vub21lIFJlc2VhcmNoLiBkb2k6IDEwLjExMDEvZ3IuMjM5MjQ0LjExOC4KCi0gQ29tcGxleGhlYXRtYXA6CiAgLSBHdSBaLCBFaWxzIFIsIFNjaGxlc25lciBNICgyMDE2KS4g4oCcQ29tcGxleCBoZWF0bWFwcyByZXZlYWwgcGF0dGVybnMgYW5kIGNvcnJlbGF0aW9ucyBpbiBtdWx0aWRpbWVuc2lvbmFsIGdlbm9taWMgZGF0YS7igJ0gQmlvaW5mb3JtYXRpY3MuCgojIyAgUi9CaW9jb25kdWN0b3IgcGFja2FnZXMgdXNlZAoKKiBbVENHQWJpb2xpbmtzXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9UQ0dBYmlvbGlua3MvKQoqIFtNdWx0aUFzc2F5RXhwZXJpbWVudF0oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvTXVsdGlBc3NheUV4cGVyaW1lbnQvKQoqIFttYWZ0b29sc10oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvbWFmdG9vbHMvKQoqIFtDb21wbGV4SGVhdG1hcF0oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvQ29tcGxleEhlYXRtYXAvKQoKIyMgUHJlLXJlcXVpc2l0ZXMKCiogQmFzaWMga25vd2xlZGdlIG9mIFIgc3ludGF4CiogVW5kZXJzdGFuZCB0aGUgcGlwZSBvcGVyYXRvciAoIiU+JSIpIChoZWxwIG1hdGVyaWFsIGh0dHBzOi8vcjRkcy5oYWQuY28ubnovcGlwZXMuaHRtbCkKKiBVbmRlcnN0YW5kIHRoZSBTdW1tYXJpemVkRXhwZXJpbWVudCBkYXRhIHN0cnVjdHVyZSAoaGVscCBtYXRlcmlhbCAJaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvU3VtbWFyaXplZEV4cGVyaW1lbnQvKQoKIyBJbnRyb2R1Y3Rpb24KCiMjIFVuZGVyc3RhbmRpbmcgR0RDIChnZW5vbWljcyBkYXRhIGNvbW1vbiBwb3J0YWwpCgpJbiB0aGlzIHdvcmtzaG9wIHdlIHdpbGwgYWNjZXNzIChUaGUgQ2FuY2VyIEdlbm9tZSBBdGxhcykgZGF0YSBhdmFpbGFibGUgYXQgdGhlIE5DSSdzIEdlbm9taWMgRGF0YSBDb21tb25zIChHREMpLgpCZWZvcmUgd2Ugc3RhcnQsIGl0IGlzIGltcG9ydGFudCB0byBrbm93IHRoYXQgdGhlIGRhdGEgaXMgZGVwb3NpdCBpbiB0d28gZGlmZmVyZW50IGRhdGFiYXNlczogCgotIFRoZSBsZWdhY3kgYXJjaGl2ZSAoaHR0cHM6Ly9wb3J0YWwuZ2RjLmNhbmNlci5nb3YvbGVnYWN5LWFyY2hpdmUvc2VhcmNoL2YpIHdoaWNoIGNvbnRhaW5zIHVuaGFybW9uaXplZCBsZWdhY3kgZGF0YSBmcm9tIHJlcG9zaXRvcmllcyB0aGF0IHByZWRhdGUgdGhlIEdEQyAoZS5nLiBDR0h1YikuIEFsc28sIGxlZ2FjeSBkYXRhIGlzIG5vdCBhY3RpdmVseSBtYWludGFpbmVkLCBwcm9jZXNzZWQsIG9yIGhhcm1vbml6ZWQgYnkgdGhlIEdEQyAoU291cmNlOiBodHRwczovL2RvY3MuZ2RjLmNhbmNlci5nb3YvRGF0YV9Qb3J0YWwvVXNlcnNfR3VpZGUvTGVnYWN5X0FyY2hpdmUvKQoKLSBIYXJtb25pemVkIGRhdGFiYXNlIChodHRwczovL3BvcnRhbC5nZGMuY2FuY2VyLmdvdi8pIHdoaWNoIGNvbnRhaW5zIGRhdGEgZnJvbSBtYW55IGNhbmNlciBwcm9qZWN0cyBwcm9jZXNzZWQgdXNpbmcgc3RhbmRhcmRpemVkIHBpcGVsaW5lcyBhbmQgdGhlIHJlZmVyZW5jZSBnZW5vbWUgR1JDaDM4IChoZzM4KS4gVGhpcyBnaXZlcyB0aGUgYWR2YW50YWdlIG9mIGFuYWx5emluZyBtdWx0aXBsZSBjYW5jZXIgdHlwZXMgb3IgdGhlIHNhbWUgY2FuY2VyIHR5cGUgYWNyb3NzIG11bHRpcGxlIHByb2plY3RzLiBZb3UgY2FuIGZpbmQgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgcGlwZWxpbmVzIHN1cHBvcnRpbmcgZGF0YSBoYXJtb25pemF0aW9uIGF0IGh0dHBzOi8vZ2RjLmNhbmNlci5nb3YvYWJvdXQtZGF0YS9nZGMtZGF0YS1oYXJtb25pemF0aW9uIGFuZCBhdCBodHRwczovL2RvY3MuZ2RjLmNhbmNlci5nb3YvRW5jeWNsb3BlZGlhL3BhZ2VzL0hhcm1vbml6ZWRfRGF0YS8uCgpBbiBvdmVydmlldyBvZiB0aGUgd2ViIHBvcnRhbCBpcyBhdmFpbGFibGUgYXQgaHR0cHM6Ly9kb2NzLmdkYy5jYW5jZXIuZ292L0RhdGFfUG9ydGFsL1VzZXJzX0d1aWRlL0dldHRpbmdfU3RhcnRlZC8uCgpBbHNvLCBhIG1vcmUgaW4tZGVwdGggY29tcGFyaXNvbiBiZXR3ZWVuIHRoZSBsZWdhY3kgYW5kIEhhcm1vbml6ZWQgZGF0YSB3YXMgcmVjZW50bHkgcHVibGlzaGVkOgoKICAtIEdhbywgR2FsZW4gRi4sIGV0IGFsLiDigJxCZWZvcmUgYW5kIEFmdGVyOiBDb21wYXJpc29uIG9mIExlZ2FjeSBhbmQgSGFybW9uaXplZCBUQ0dBIEdlbm9taWMgRGF0YSBDb21tb25z4oCZIERhdGEu4oCdIENlbGwgc3lzdGVtcyA5LjEgKDIwMTkpOiAyNC0zNC4gKGh0dHBzOi8vZG9pLm9yZy8xMC4xMDE2L2ouY2Vscy4yMDE5LjA2LjAwNikKCiFbRmlndXJlOiBUQ0dBIGRhdGFiYXNlcyAoYmx1ZTogbGVnYWN5IGFyY2hpdmUuIHJlZDogaGFybW9uaXplZCBkYXRhYmFzZSkgU291cmNlOiBodHRwczovL3BvcnRhbC5nZGMuY2FuY2VyLmdvdi9dKGltYWdlcy9tYWluLnBuZykKCgojIyBVbmRlcnN0YW5kaW5nIFRDR0EgZGF0YQoKIyMjIERhdGEgYWNjZXNzCgpHREMgcHJvdmlkZXMgdGhlIGRhdGEgd2l0aCB0d28gYWNjZXNzIGxldmVsczoKCi0gT3BlbjogaW5jbHVkZXMgaGlnaCBsZXZlbCBnZW5vbWljIGRhdGEgdGhhdCBpcyBub3QgaW5kaXZpZHVhbGx5IGlkZW50aWZpYWJsZSwgYXMgd2VsbCBhcyBtb3N0IGNsaW5pY2FsIGFuZCBhbGwgYmlvc3BlY2ltZW4gZGF0YSBlbGVtZW50cy4KLSBDb250cm9sbGVkOiBpbmNsdWRlcyBpbmRpdmlkdWFsbHkgaWRlbnRpZmlhYmxlIGRhdGEgc3VjaCBhcyBsb3ctbGV2ZWwgZ2Vub21pYyBzZXF1ZW5jaW5nIGRhdGEsIGdlcm1saW5lIHZhcmlhbnRzLCBTTlA2IGdlbm90eXBlIGRhdGEsIGFuZCBjZXJ0YWluIGNsaW5pY2FsIGRhdGEgZWxlbWVudHMgCgpZb3UgY2FuIGZpbmQgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB0aG9zZSB0d28gbGV2ZWxzIGFuZCBob3cgdG8gZ2V0IGFjY2VzcyB0byBjb250cm9sbGVkIGRhdGEgYXQ6IGh0dHBzOi8vZ2RjLmNhbmNlci5nb3YvYWNjZXNzLWRhdGEvZGF0YS1hY2Nlc3MtcHJvY2Vzc2VzLWFuZC10b29scy4KCiMjIyBUQ0dBIGJhcmNvZGUgZGVzY3JpcHRpb24KCkVhY2ggVENHQSBzYW1wbGUgaGFzIGEgdW5pcXVlIGlkZW50aWZpZXIgY2FsbGVkIFRDR0EgYmFyY29kZSwgd2hpY2ggY29udGFpbnMgaW1wb3J0YW50IGluZm9ybWF0aW9uIGFib3V0IGVhY2ggc2FtcGxlLiAKQSBkZXNjcmlwdGlvbiBvZiB0aGUgYmFyY29kZSBpcyBzaG93biBiZWxvdyAoU291cmNlOiBodHRwczovL2RvY3MuZ2RjLmNhbmNlci5nb3YvRW5jeWNsb3BlZGlhL3BhZ2VzL1RDR0FfQmFyY29kZS8pLgoKIVtGaWd1cmU6IFRDR0EgYmFyY29kZSBTb3VyY2U6IGh0dHBzOi8vZG9jcy5nZGMuY2FuY2VyLmdvdi9FbmN5Y2xvcGVkaWEvcGFnZXMvVENHQV9CYXJjb2RlL10oaW1hZ2VzL1RDR0FiYXJjb2RlLnBuZykKCllvdSBjYW4gZmluZCBhIHRhYmxlIHdpdGggYWxsIHRoZSBjb2RlIGFuZCBtZWFuaW5ncyBhdCBodHRwczovL2dkYy5jYW5jZXIuZ292L3Jlc291cmNlcy10Y2dhLXVzZXJzL3RjZ2EtY29kZS10YWJsZXMuClRoZSBTYW1wbGUgVHlwZSBDb2RlcyBpcyBzaG93biBiZWxvdzoKCiFbRmlndXJlOiBUQ0dBIHNhbXBsZXMgdHlwZS4gU291cmNlOiBodHRwczovL2dkYy5jYW5jZXIuZ292L3Jlc291cmNlcy10Y2dhLXVzZXJzL3RjZ2EtY29kZS10YWJsZXMvc2FtcGxlLXR5cGUtY29kZXNdKGltYWdlcy9zYW1wbGV0eXBlcy5wbmcpCgojIyMgRGF0YSBzdHJ1Y3R1cmUKCkluIG9yZGVyIHRvIGZpbHRlciB0aGUgZGF0YSBhdmFpbGFibGUgaW4gR0RDIHNvbWUgZmllbGRzIGFyZSBhdmFpbGFibGUgc3VjaCBhcyBwcm9qZWN0IChUQ0dBLCBUQVJHRVQsIGV0Yy4pLCBkYXRhIGNhdGVnb3J5IChUcmFuc2NyaXB0b21lIFByb2ZpbGluZywgRE5BIG1ldGh5bGF0aW9uLCBDbGluaWNhbCwgZXRjLiksIGRhdGEgdHlwZSAoR2VuZSBFeHByZXNzaW9uIFF1YW50aWZpY2F0aW9uLCBJc29mb3JtIEV4cHJlc3Npb24gUXVhbnRpZmljYXRpb24sIE1ldGh5bGF0aW9uIEJldGEgVmFsdWUsIGV0Yy4pLCBleHBlcmltZW50YWwgc3RyYXRlZ3kgKG1pUk5BLVNlcSwgUk5BLVNlcSwgZXRjLiksIFdvcmtmbG93IFR5cGUsIHBsYXRmb3JtLCBhY2Nlc3MgdHlwZSBhbmQgb3RoZXJzLgoKIVtGaWd1cmU6IERhdGEgY2F0ZWdvcnkgZmlsdGVyXShpbWFnZXMvY2F0ZWdvcnkucG5nKQoKIVtGaWd1cmU6IERhdGEgdHlwZSBmaWx0ZXJdKGltYWdlcy9jYXRlZ29yeS5wbmcpCgpJbiB0ZXJtcyBvZiBkYXRhIGdyYW51bGFyaXR5LCBhIHByb2plY3QgaGFzIGRhdGEgb24gc2V2ZXJhbCBjYXRlZ29yaWVzLCBlYWNoIGNhdGVnb3J5IGNvbnRhaW5zIHNldmVyYWwgZGF0YSB0eXBlcyB0aGF0IG1pZ2h0IGhhdmUgYmVlbiBwcm9kdWNlZCB3aXRoIGRpZmZlcmVudCB3b3JrZmxvd3MsIGV4cGVyaW1lbnRhbCBzdHJhdGVneSBhbmQgcGxhdGZvcm1zLiBJbiB0aGF0IHdheSwgaWYgeW91IHNlbGVjdCBkYXRhIHR5cGUgIkdlbmUgRXhwcmVzc2lvbiBRdWFudGlmaWNhdGlvbiIgdGhlIGRhdGEgY2F0ZWdvcnkgd2lsbCBiZSBUcmFuc2NyaXB0b21lIFByb2ZpbGluZy4KCiFbRmlndXJlOiBGaWx0ZXJpbmcgYnkgR2VuZSBFeHByZXNzaW9uIFF1YW50aWZpY2F0aW9uXShpbWFnZXMvRXhhbXBsZUZpbHRlci5wbmcpCgpZb3UgY2FuIGZpbmQgdGhlIGVudHJ5IHBvc3NpYmlsaXRpZXMgZm9yIGVhY2ggZmlsdGVyIGF0IHRoZSByZXBvc2l0b3J5IHBhZ2Ugb2YgdGhlIGRhdGFiYXNlIGF0IGh0dHBzOi8vcG9ydGFsLmdkYy5jYW5jZXIuZ292L3JlcG9zaXRvcnkuCgojIyBUaGUgU3VtbWFyaXplZEV4cGVyaW1lbnQgZGF0YSBzdHJ1Y3R1cmUKCkJlZm9yZSB3ZSBzdGFydCwgaXQgaXMgaW1wb3J0YW50IHRvIGtub3cgdGhhdCB0aGUgUi9CaW9jb25kdWN0b3IgZW52aXJvbm1lbnQgcHJvdmlkZXMgYSBkYXRhIHN0cnVjdHVyZSBjYWxsZWQgYFN1bW1hcml6ZWRFeHBlcmltZW50YCwgd2hpY2ggd2FzIGNyZWF0ZWQgdG8gaGFuZGxlIGJvdGggc2FtcGxlcyBtZXRhZGF0YSAoYWdlLCBnZW5kZXIsIGV0YyksIGdlbm9taWNzIGRhdGEgKGkuZS4gRE5BIG1ldGh5bGF0aW9uIGJldGEgdmFsdWUpIGFuZCBnZW5vbWljcyBtZXRhZGF0YSBpbmZvcm1hdGlvbiAoY2hyLCBzdGFydCwgZW5kLCBnZW5lIHN5bWJvbCkgaW4gdGhlIHNhbWUgb2JqZWN0LgpZb3UgY2FuIGFjY2VzcyBzYW1wbGVzIG1ldGFkYXRhIHdpdGggYGNvbERhdGFgIGZ1bmN0aW9uLCBnZW5vbWljcyBkYXRhIHdpdGggYGFzc2F5c2AgYW5kIGdlbm9taWNzIG1ldGFkYXRhIHdpdGggYHJvd1Jhbmdlc2AuCgohW0ZpZ3VyZTogU3VtbWFyaXplZCBFeHBlcmltZW50IGRhdGEgc3RydWN0dXJlLiBTb3VyY2U6IGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL1N1bW1hcml6ZWRFeHBlcmltZW50L10oaW1hZ2VzL1NFLnN2ZykKCgojIyBMb2FkaW5nIHJlcXVpcmVkIHBhY2thZ2VzCgpgYGB7ciwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShUQ0dBYmlvbGlua3MpCmxpYnJhcnkoTXVsdGlBc3NheUV4cGVyaW1lbnQpCmxpYnJhcnkobWFmdG9vbHMpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoQ29tcGxleEhlYXRtYXApCmBgYAoKSW4gY2FzZSB0aG9zZSBwYWNrYWdlcyBhcmUgbm90IGF2YWlsYWJsZSwgeW91IGNhbiBpbnN0YWxsIHRob3NlIHBhY2thZ2VzIHVzaW5nIEJpb2NNYW5hZ2VyLgpgYGB7ZXZhbCA9IEZBTFNFfQppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIkJpb2NNYW5hZ2VyIiwgcXVpZXRseSA9IFRSVUUpKQogICAgaW5zdGFsbC5wYWNrYWdlcygiQmlvY01hbmFnZXIiKQoKaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJDb21wbGV4SGVhdG1hcCIsIHF1aWV0bHkgPSBUUlVFKSkKICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiQ29tcGxleEhlYXRtYXAiKSAjIGZyb20gYmlvY29uZHVjdG9yCgppZiAoIXJlcXVpcmVOYW1lc3BhY2UoIlRDR0FiaW9saW5rcyIsIHF1aWV0bHkgPSBUUlVFKSkKICBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiQmlvaW5mb3JtYXRpY3NGTVJQL1RDR0FiaW9saW5rcyIpICMgZnJvbSBnaXRodWIKYGBgCgojIFdvcmtpbmcgd2l0aCBUQ0dBIGRhdGEKCgpEdXJpbmcgdGhpcyB3b3Jrc2hvcCB3ZSB3aWxsIGJlIHVzaW5nIG9wZW4gYWNjZXNzIGRhdGEgZnJvbSB0aGUgaGFybW9uaXplZCBHREMgZGF0YWJhc2UgKGhnMzggdmVyc2lvbiksIHdoaWNoIGNhbiBiZSBhY2Nlc3NlZCAKYXQgaHR0cHM6Ly9wb3J0YWwuZ2RjLmNhbmNlci5nb3YvLgoKVGhyb3VnaCB0aGUgbmV4dCBzZWN0aW9ucyB3ZSB3aWxsOgoKMS4gQWNjZXNzIFRDR0EgY2xpbmljYWwgZGF0YQoyLiBTZWFyY2gsIGRvd25sb2FkIGFuZCBtYWtlIGFuIFIgb2JqZWN0IGZyb20gVENHQSBkYXRhCiAtIFJOQS1zZXEgZGF0YQogLSBETkEgbWV0aHlsYXRpb24KMy4gRG93bmxvYWQgc2FtcGxlcyBtZXRhZGF0YQo0LiBEb3dubG9hZCBhbmQgdmlzdWFsaXplIG11dGF0aW9ucwo1LiBEb3dubG9hZCBhbmQgdmlzdWFsaXplIGNvcHkgbnVtYmVyIGFsdGVyYXRpb25zIAoKCiMjIENsaW5pY2FsIGRhdGEKCkluIEdEQyBkYXRhYmFzZSB0aGUgY2xpbmljYWwgZGF0YSBjYW4gYmUgcmV0cmlldmVkIGZyb20gZGlmZmVyZW50IHNvdXJjZXM6CgotIGluZGV4ZWQgY2xpbmljYWw6IGEgcmVmaW5lZCBjbGluaWNhbCBkYXRhIHRoYXQgaXMgY3JlYXRlZCB1c2luZyB0aGUgWE1MIGZpbGVzLgotIFhNTCBmaWxlczogb3JpZ2luYWwgc291cmNlIG9mIHRoZSBkYXRhCi0gQkNSIEJpb3RhYjogdHN2IGZpbGVzIHBhcnNlZCBmcm9tIFhNTCBmaWxlcwoKClRoZXJlIGFyZSB0d28gbWFpbiBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBpbmRleGVkIGNsaW5pY2FsIGFuZCBYTUwgZmlsZXM6CgotIFhNTCBoYXMgbW9yZSBpbmZvcm1hdGlvbjogcmFkaWF0aW9uLCBkcnVncyBpbmZvcm1hdGlvbiwgZm9sbG93LXVwcywgYmlvc3BlY2ltZW4sIGV0Yy4KU28sIHRoZSBpbmRleGVkIG9uZSBpcyBvbmx5IGEgc3Vic2V0IG9mIHRoZSBYTUwgZmlsZXMKLSBUaGUgaW5kZXhlZCBkYXRhIGNvbnRhaW5zIHRoZSB1cGRhdGVkIGRhdGEgd2l0aCB0aGUgZm9sbG93IHVwIGluZm9ybWF0aW9uLiAKRm9yIGV4YW1wbGU6IGlmIHRoZSBwYXRpZW50IHdhcyBhbGl2ZSB3aGVuIHRoZSBjbGluaWNhbCBkYXRhIHdhcyBjb2xsZWN0IGFuZCB0aGVuIGluIHRoZSBuZXh0IGZvbGxvdy11cCBoZSBpcyBkZWFkLCAKdGhlIGluZGV4ZWQgZGF0YSB3aWxsIHNob3cgZGVhZC4gClRoZSBYTUwgd2lsbCBoYXZlIHR3byBmaWVsZHMsIG9uZSBmb3IgdGhlIGZpcnN0IHRpbWUgc2F5aW5nIGhlIGlzIGFsaXZlIChpbiB0aGUgY2xpbmljYWwgcGFydCkgYW5kIHRoZSBmb2xsb3ctdXAgc2F5aW5nIGhlIGlzIGRlYWQuCgpPdGhlciB1c2VmdWwgY2xpbmljYWwgaW5mb3JtYXRpb24gYXZhaWxhYmxlIGFyZToKCiogVGlzc3VlIHNsaWRlIGltYWdlIAoqIFBhdGhvbG9neSByZXBvcnQgLSBTbGlkZSBpbWFnZQoKWW91IGNhbiBjaGVjayBleGFtcGxlcyBpbiBUQ0dBYmlvbGlua3MgdmlnbmV0dGUgYXQgaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy92aWduZXR0ZXMvVENHQWJpb2xpbmtzL2luc3QvZG9jL2NsaW5pY2FsLmh0bWwuCgohW0ZpZ3VyZTogQ2xpbmljYWwgZGF0YSBwYXRpZW50OiBUQ0dBLUFBLTM1NjIuIFNvdXJjZTogaHR0cHM6Ly9wb3J0YWwuZ2RjLmNhbmNlci5nb3YvY2FzZXMvMTI3ZjczOGQtYWZhMS00MmY2LWE5YTAtZjMzODA2NjY3Yjg0XShpbWFnZXMvY2xpbmljYWxpbmRleC5wbmcpCgoKYGBge1IsIGV2YWwgPSBUUlVFfQojIEFjY2VzcyBpbmRleGVkIGNsaW5pY2FsIGRhdGEKY2xpbmljYWwgPC0gR0RDcXVlcnlfY2xpbmljKCJUQ0dBLUNPQUQiKQpoZWFkKGNsaW5pY2FsKQpgYGAKClRoZSBjbGluaWNhbCBpbmRleGVkIGRhdGEgaXMgdGhlIHNhbWUgeW91IGNhbiBzZWUgaW4gdGhlIEdEQyBkYXRhIHBvcnRhbC4gT2JzZXJ2YXRpb246IHRoZSBHREMgQVBJIHByb3ZpZGVzICoqYWdlX2F0X2RpYWdub3NpcyoqIGluIGRheXMuCgpgYGB7UiwgZXZhbCA9IFRSVUV9CiMgU2FtZSBjYXNlIGFzIGZpZ3VyZSBhYm92ZQpjbGluaWNhbCAlPiUgCiAgZHBseXI6OmZpbHRlcihzdWJtaXR0ZXJfaWQgPT0gIlRDR0EtQUEtMzU2MiIpICU+JSAKICB0ICU+JSAKICBhcy5kYXRhLmZyYW1lCmBgYAoKWW91IGNhbiBhbHNvIGFjY2VzcyBCaW90YWIgZmlsZXMgd2hpY2ggYXJlIFRTViBmaWxlcyBjcmVhdGVkIGZyb20gdGhlIFhNTCBmaWxlcwoob25seSB3b3JrcyBmb3IgVENHQWJpb2xpbmtzIHZlcnNpb24gaGlnaGVyIHRoYW4gMi4xMy41KS4KCmBgYHtSIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBmaWcua2VlcD0nYWxsJywgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMCwgY2FjaGUgPSBUUlVFfQpxdWVyeSA8LSBHRENxdWVyeShwcm9qZWN0ID0gIlRDR0EtQUNDIiwgCiAgICAgICAgICAgICAgICAgIGRhdGEuY2F0ZWdvcnkgPSAiQ2xpbmljYWwiLAogICAgICAgICAgICAgICAgICBkYXRhLnR5cGUgPSAiQ2xpbmljYWwgU3VwcGxlbWVudCIsIAogICAgICAgICAgICAgICAgICBkYXRhLmZvcm1hdCA9ICJCQ1IgQmlvdGFiIikKR0RDZG93bmxvYWQocXVlcnkpCmNsaW5pY2FsLkJDUnRhYi5hbGwgPC0gR0RDcHJlcGFyZShxdWVyeSkKYGBgCgpgYGB7Un0KbmFtZXMoY2xpbmljYWwuQkNSdGFiLmFsbCkKYGBgCgpgYGB7ciBlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CmNsaW5pY2FsLkJDUnRhYi5hbGwkY2xpbmljYWxfZHJ1Z19hY2MgICU+JSAKICBoZWFkICAlPiUgCiAgYXMuZGF0YS5mcmFtZQpgYGAKCiMjIFJOQS1TZXEgZGF0YQoKVGhlIFJOQS1TZXEgcGlwZWxpbmUgcHJvZHVjZXMgcmF3IGNvdW50cywgRlBLTSBhbmQgRlBLTS1VUSBxdWFudGlmaWNhdGlvbnMgYW5kIGlzIGRlc2NyaWJlZAphdCBodHRwczovL2RvY3MuZ2RjLmNhbmNlci5nb3YvRGF0YS9CaW9pbmZvcm1hdGljc19QaXBlbGluZXMvRXhwcmVzc2lvbl9tUk5BX1BpcGVsaW5lLy4KCgohW0ZpZ3VyZTogZ2VuZSBleHByZXNzaW9uIHBpcGVsaW5lLiBTb3VyY2U6IGh0dHBzOi8vZG9jcy5nZGMuY2FuY2VyLmdvdi9EYXRhL0Jpb2luZm9ybWF0aWNzX1BpcGVsaW5lcy9FeHByZXNzaW9uX21STkFfUGlwZWxpbmUvXShpbWFnZXMvZ2VuZS1leHByZXNzaW9uLXF1YW50aWZpY2F0aW9uLXBpcGVsaW5lLXYyLnBuZykKCiFbRmlndXJlOiBtUk5BIGZpbGVzLiBTb3VyY2U6IGh0dHBzOi8vZG9jcy5nZGMuY2FuY2VyLmdvdi9EYXRhL0Jpb2luZm9ybWF0aWNzX1BpcGVsaW5lcy9FeHByZXNzaW9uX21STkFfUGlwZWxpbmUvXShpbWFnZXMvbVJOQWZpbGVzLnBuZykKCgpUaGUgZm9sbG93aW5nIG9wdGlvbnMgYXJlIHVzZWQgdG8gc2VhcmNoIG1STkEgcmVzdWx0cyB1c2luZyBUQ0dBYmlvbGlua3M6CgotIGRhdGEuY2F0ZWdvcnk6ICJUcmFuc2NyaXB0b21lIFByb2ZpbGluZyIKLSBkYXRhLnR5cGU6ICJHZW5lIEV4cHJlc3Npb24gUXVhbnRpZmljYXRpb24iCi0gd29ya2Zsb3cudHlwZTogIkhUU2VxIC0gQ291bnRzIiwgIkhUU2VxIC0gRlBLTSIsICJIVFNlcSAtIEZQS00tVVEiCgpIZXJlIGlzIHRoZSBleGFtcGxlIHRvIGRvd25sb2FkIHRoZSByYXcgY291bnRzLCB3aGljaCBjYW4gYmUgdXNlZCB3aXRoIERFU2VxMiAoaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvREVTZXEyLykgZm9yIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzLgoKYGBge1IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZScsIGZpZy5rZWVwPSdhbGwnLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwLCBjYWNoZSA9IFRSVUV9CnF1ZXJ5LmV4cC5oZzM4IDwtIEdEQ3F1ZXJ5KHByb2plY3QgPSAiVENHQS1HQk0iLCAKICAgICAgICAgICAgICAgICAgZGF0YS5jYXRlZ29yeSA9ICJUcmFuc2NyaXB0b21lIFByb2ZpbGluZyIsIAogICAgICAgICAgICAgICAgICBkYXRhLnR5cGUgPSAiR2VuZSBFeHByZXNzaW9uIFF1YW50aWZpY2F0aW9uIiwgCiAgICAgICAgICAgICAgICAgIHdvcmtmbG93LnR5cGUgPSAiSFRTZXEgLSBDb3VudHMiLAogICAgICAgICAgICAgICAgICBiYXJjb2RlID0gIGMoIlRDR0EtMTQtMDczNi0wMkEtMDFSLTIwMDUtMDEiLCAiVENHQS0wNi0wMjExLTAyQS0wMlItMjAwNS0wMSIpKQpHRENkb3dubG9hZChxdWVyeS5leHAuaGczOCkKcmF3LmNvdW50cyA8LSBHRENwcmVwYXJlKHF1ZXJ5ID0gcXVlcnkuZXhwLmhnMzgsIHN1bW1hcml6ZWRFeHBlcmltZW50ID0gRkFMU0UpCmBgYAoKYGBge1J9CmhlYWQocmF3LmNvdW50cykKYGBgCgpIZXJlIGlzIHRoZSBleGFtcGxlIHRvIGRvd25sb2FkIHRoZSBGUEtNLVVRIGNvdW50cy4KCmBgYHtSIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBmaWcua2VlcD0nYWxsJywgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMCwgY2FjaGUgPSBUUlVFfQpxdWVyeS5leHAuaGczOCA8LSBHRENxdWVyeShwcm9qZWN0ID0gIlRDR0EtR0JNIiwgCiAgICAgICAgICAgICAgICAgIGRhdGEuY2F0ZWdvcnkgPSAiVHJhbnNjcmlwdG9tZSBQcm9maWxpbmciLCAKICAgICAgICAgICAgICAgICAgZGF0YS50eXBlID0gIkdlbmUgRXhwcmVzc2lvbiBRdWFudGlmaWNhdGlvbiIsIAogICAgICAgICAgICAgICAgICB3b3JrZmxvdy50eXBlID0gIkhUU2VxIC0gRlBLTS1VUSIsCiAgICAgICAgICAgICAgICAgIGJhcmNvZGUgPSAgYygiVENHQS0xNC0wNzM2LTAyQS0wMVItMjAwNS0wMSIsICJUQ0dBLTA2LTAyMTEtMDJBLTAyUi0yMDA1LTAxIikpCkdEQ2Rvd25sb2FkKHF1ZXJ5LmV4cC5oZzM4KQpmcGttLnVxLmNvdW50cyA8LSBHRENwcmVwYXJlKHF1ZXJ5ID0gcXVlcnkuZXhwLmhnMzgsIHN1bW1hcml6ZWRFeHBlcmltZW50ID0gRkFMU0UpCmBgYAoKYGBge1J9CmhlYWQoZnBrbS51cS5jb3VudHMpCmBgYAoKCgojIyBNdXRhdGlvbgoKKipUQ0dBYmlvbGlua3MqKiBoYXMgcHJvdmlkZWQgYSBmZXcgZnVuY3Rpb25zIHRvIGRvd25sb2FkIG11dGF0aW9uIGRhdGEgZnJvbSBHREMuClRoZXJlIGFyZSB0d28gb3B0aW9ucyB0byBkb3dubG9hZCB0aGUgZGF0YToKCjEuIFVzZSBgR0RDcXVlcnlfTWFmYCB3aGljaCB3aWxsIGRvd25sb2FkIE1BRiBhbGlnbmVkIGFnYWluc3QgaGczOC4KClRoaXMgZXhhbXBsZSB3aWxsIGRvd25sb2FkIE1BRiAobXV0YXRpb24gYW5ub3RhdGlvbiBmaWxlcykgZm9yIHZhcmlhbnQgY2FsbGluZyBwaXBlbGluZSBtdXNlLgpQaXBlbGluZXMgb3B0aW9ucyBhcmU6IGBtdXNlYCwgYHZhcnNjYW4yYCwgYHNvbWF0aWNzbmlwZXJgLCBgbXV0ZWN0YC4gRm9yIG1vcmUgaW5mb3JtYXRpb24gcGxlYXNlIGFjY2VzcwpbR0RDIGRvY3NdKGh0dHBzOi8vZG9jcy5nZGMuY2FuY2VyLmdvdi9EYXRhL0Jpb2luZm9ybWF0aWNzX1BpcGVsaW5lcy9ETkFfU2VxX1ZhcmlhbnRfQ2FsbGluZ19QaXBlbGluZS8pLgoKCllvdSBjYW4gZG93bmxvYWQgdGhlIGRhdGEgdXNpbmcgVENHQWJpb2xpbmtzIGBHRENxdWVyeV9NYWZgIGZ1bmN0aW9uLiAKYGBge1IgR0RDcXVlcnlfTWFmLCBldmFsID0gVFJVRSwgY2FjaGUgPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CiMgR0RDcXVlcnlfTWFmIGRvd25sb2FkIHRoZSBkYXRhIGZyb20gR0RDCm1hZiA8LSBHRENxdWVyeV9NYWYoIkNPQUQiLCBwaXBlbGluZXMgPSAibXVzZSIpCmBgYAoKYGBge1J9Cm1hZiAlPiUgaGVhZCAlPiUgYXMuZGF0YS5mcmFtZQpgYGAKClRoZW4gdmlzdWFsaXplIHRoZSByZXN1bHRzIHVzaW5nIHRoZSBtYWZ0b29scyBwYWNrYWdlLgoKYGBge1IgIG1hZnRvb2xzLCBldmFsID0gVFJVRSwgY2FjaGUgPSBUUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CiMgdXNpbmcgbWFmdG9vbHMgZm9yIGRhdGEgc3VtbWFyeSAKbWFmdG9vbHMuaW5wdXQgPC0gbWFmICU+JSByZWFkLm1hZgoKIyBDaGVjayBzdW1tYXJ5CnBsb3RtYWZTdW1tYXJ5KG1hZiA9IG1hZnRvb2xzLmlucHV0LCAKICAgICAgICAgICAgICAgcm1PdXRsaWVyID0gVFJVRSwgCiAgICAgICAgICAgICAgIGFkZFN0YXQgPSAnbWVkaWFuJywgCiAgICAgICAgICAgICAgIGRhc2hib2FyZCA9IFRSVUUpCgpvbmNvcGxvdChtYWYgPSBtYWZ0b29scy5pbnB1dCwgCiAgICAgICAgIHRvcCA9IDEwLCAKICAgICAgICAgcmVtb3ZlTm9uTXV0YXRlZCA9IFRSVUUpCgojIGNsYXNzaWZpZXMgU2luZ2xlIE51Y2xlb3RpZGUgVmFyaWFudHMgaW50byBUcmFuc2l0aW9ucyBhbmQgVHJhbnN2ZXJzaW9ucwp0aXR2ID0gdGl0dihtYWYgPSBtYWZ0b29scy5pbnB1dCwgCiAgICAgICAgICAgIHBsb3QgPSBGQUxTRSwgCiAgICAgICAgICAgIHVzZVN5biA9IFRSVUUpCnBsb3RUaVR2KHJlcyA9IHRpdHYpCmBgYAoKWW91IGNhbiBleHRyYWN0IHNhbXBsZSBzdW1tYXJ5IGZyb20gTUFGIG9iamVjdC4KCmBgYHtSfQpnZXRTYW1wbGVTdW1tYXJ5KG1hZnRvb2xzLmlucHV0KQpgYGAKCiMjIENvcHkgbnVtYmVyIGFsdGVyYXRpb24gZGF0YQoKVGhlIENvcHkgTnVtYmVyIFZhcmlhdGlvbiBBbmFseXNpcyBQaXBlbGluZSBpcyBkZXNjcmliZWQgYXQgaHR0cHM6Ly9kb2NzLmdkYy5jYW5jZXIuZ292L0RhdGEvQmlvaW5mb3JtYXRpY3NfUGlwZWxpbmVzL0NOVl9QaXBlbGluZS8KCk51bWVyaWMgZm9jYWwtbGV2ZWwgQ29weSBOdW1iZXIgVmFyaWF0aW9uIChDTlYpIHZhbHVlcyB3ZXJlIGdlbmVyYXRlZCB3aXRoICJNYXNrZWQgQ29weSBOdW1iZXIgU2VnbWVudCIgZmlsZXMgZnJvbSB0dW1vciBhbGlxdW90cyB1c2luZyBHSVNUSUMyIG9uIGEgcHJvamVjdCBsZXZlbC4gT25seSBwcm90ZWluLWNvZGluZyBnZW5lcyB3ZXJlIGtlcHQsIGFuZCB0aGVpciBudW1lcmljIENOViB2YWx1ZXMgd2VyZSBmdXJ0aGVyIHRocmVzaG9sZGVkIGJ5IGEgbm9pc2UgY3V0b2ZmIG9mIDAuMzoKCi0gR2VuZXMgd2l0aCBmb2NhbCBDTlYgdmFsdWVzIHNtYWxsZXIgdGhhbiAtMC4zIGFyZSBjYXRlZ29yaXplZCBhcyBhICJsb3NzIiAoLTEpCi0gR2VuZXMgd2l0aCBmb2NhbCBDTlYgdmFsdWVzIGxhcmdlciB0aGFuIDAuMyBhcmUgY2F0ZWdvcml6ZWQgYXMgYSAiZ2FpbiIgKCsxKQotIEdlbmVzIHdpdGggZm9jYWwgQ05WIHZhbHVlcyBiZXR3ZWVuIGFuZCBpbmNsdWRpbmcgLTAuMyBhbmQgMC4zIGFyZSBjYXRlZ29yaXplZCBhcyAibmV1dHJhbCIgKDApLgoKCllvdSBjYW4gYWNjZXNzICJHZW5lIExldmVsIENvcHkgTnVtYmVyIFNjb3JlcyIgZnJvbSBHSVNUSUMgd2l0aCB0aGUgY29kZSBiZWxvdzoKYGBge1IgZ2lzdGljLCBtZXNzYWdlPUZBTFNFLCBjYWNoZSA9IFRSVUUsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBmaWcua2VlcD0nYWxsJywgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMH0KcXVlcnkgPC0gR0RDcXVlcnkocHJvamVjdCA9ICJUQ0dBLUdCTSIsCiAgICAgICAgICAgICBkYXRhLmNhdGVnb3J5ID0gIkNvcHkgTnVtYmVyIFZhcmlhdGlvbiIsCiAgICAgICAgICAgICBkYXRhLnR5cGUgPSAiR2VuZSBMZXZlbCBDb3B5IE51bWJlciBTY29yZXMiLCAgICAgICAgICAgICAgCiAgICAgICAgICAgICBhY2Nlc3MgPSAib3BlbiIpCkdEQ2Rvd25sb2FkKHF1ZXJ5KQpzY29yZXMgPC0gR0RDcHJlcGFyZShxdWVyeSkKYGBgCgpgYGB7UiB3YXJuaW5nID0gRkFMU0UsZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMH0Kc2NvcmVzWzE6NSwxOjVdCmBgYAoKWW91IGNhbiB2aXN1YWxpemUgdGhlIGRhdGEgdXNpbmcgdGhlIFIvQmlvY29uZHVjdG9yIHBhY2thZ2UgY29tcGxleEhlYXRtYXAuIApgYGB7UiBnaXN0aWNoZWF0bWFwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTB9CnNjb3Jlcy5tYXRyaXggPC0gc2NvcmVzICU+JSAKICBkcGx5cjo6c2VsZWN0KC1jKDE6MykpICU+JSAgIyBSZW1vdmVzIG1ldGFkYXRhIGZyb20gdGhlIGZpcnN0IDMgY29sdW1ucwogIGFzLm1hdHJpeAoKcm93bmFtZXMoc2NvcmVzLm1hdHJpeCkgPC0gcGFzdGUwKHNjb3JlcyRgR2VuZSBTeW1ib2xgLCJfIixzY29yZXMkQ3l0b2JhbmQpCgojIGdhaW4gaW4gbW9yZSB0aGFuIDEwMCBzYW1wbGVzCmdhaW4ubW9yZS50aGFuLmh1bmRyZWQuc2FtcGxlcyA8LSB3aGljaChyb3dTdW1zKHNjb3Jlcy5tYXRyaXggPT0gMSkgPiAxMDApCgojIGxvc3MgaW4gbW9yZSB0aGFuIDEwMCBzYW1wbGVzCmxvc3MubW9yZS50aGFuLmh1bmRyZWQuc2FtcGxlcyA8LSB3aGljaChyb3dTdW1zKHNjb3Jlcy5tYXRyaXggPT0gLTEpID4gMTAwKQoKbGluZXMuc2VsZWN0ZWQgPC0gYyhnYWluLm1vcmUudGhhbi5odW5kcmVkLnNhbXBsZXMsbG9zcy5tb3JlLnRoYW4uaHVuZHJlZC5zYW1wbGVzKQoKSGVhdG1hcChzY29yZXMubWF0cml4W2xpbmVzLnNlbGVjdGVkLF0sCiAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBGQUxTRSwgCiAgICAgICAgc2hvd19yb3dfbmFtZXMgPSBUUlVFLAogICAgICAgICByb3dfbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gOCksCiAgICAgICAgY29sID0gY2lyY2xpemU6OmNvbG9yUmFtcDIoYygtMSwwLDEpLCBjb2xvcnMgPSBjKCJyZWQiLCJ3aGl0ZSIsImJsdWUiKSkpCgpgYGAKCgojIyBETkEgbWV0aHlsYXRpb24gZGF0YQoKVGhlIHByb2Nlc3NlZCBETkEgbWV0aHlsYXRpb24gZGF0YSBtZWFzdXJlIHRoZSBsZXZlbCBvZiBtZXRoeWxhdGlvbiBhdCBrbm93biBDcEcgc2l0ZXMgYXMgYmV0YSB2YWx1ZXMsIGNhbGN1bGF0ZWQgZnJvbSBhcnJheSBpbnRlbnNpdGllcyAoTGV2ZWwgMiBkYXRhKSBhcyBCZXRhID0gJE0vKE0rVSkkIFtAemhvdTIwMTdjb21wcmVoZW5zaXZlXSB3aGljaCByYW5nZXMgZnJvbSAwIGJlaW5nIHVubWV0aHlsYXRlZCBhbmQgMSBmdWxseSBtZXRoeWxhdGVkLiAKCk1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIEROQSBtZXRoeWxhdGlvbiBwaXBlbGluZSBpcyBhdmFpbGFibGUgYXQgaHR0cHM6Ly9kb2NzLmdkYy5jYW5jZXIuZ292L0RhdGEvQmlvaW5mb3JtYXRpY3NfUGlwZWxpbmVzL01ldGh5bGF0aW9uX0xPX1BpcGVsaW5lLy4KCgpXZSB3aWxsIGRvd25sb2FkIHR3byBHbGlvYmxhc3RvbWEgKEdCTSkgYXMgYSBzdW1tYXJpemVkRXhwZXJpbWVudCBvYmplY3QuIApgYGB7UiBtZXNzYWdlPUZBTFNFLCBjYWNoZSA9IFRSVUUsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBmaWcua2VlcD0nYWxsJywgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMH0KcXVlcnlfbWV0LmhnMzggPC0gR0RDcXVlcnkocHJvamVjdCA9ICJUQ0dBLUdCTSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmNhdGVnb3J5ID0gIkROQSBNZXRoeWxhdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBwbGF0Zm9ybSA9ICJJbGx1bWluYSBIdW1hbiBNZXRoeWxhdGlvbiAyNyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBiYXJjb2RlID0gYygiVENHQS0wMi0wMTE2LTAxQSIsIlRDR0EtMTQtMzQ3Ny0wMUEtMDFEIikpCkdEQ2Rvd25sb2FkKHF1ZXJ5X21ldC5oZzM4KQpkYXRhLmhnMzggPC0gR0RDcHJlcGFyZShxdWVyeV9tZXQuaGczOCxzdW1tYXJpemVkRXhwZXJpbWVudCA9IFRSVUUpCmBgYAoKYGBge1J9CmRhdGEuaGczOApgYGAKCllvdSBjYW4gYWNjZXNzIHRoZSBwcm9iZXMgaW5mb3JtYXRpb24gd2l0aCBgcm93UmFuZ2VzYC4KYGBge1J9CmRhdGEuaGczOCAlPiUgcm93UmFuZ2VzICU+JSBhcy5kYXRhLmZyYW1lCmBgYAoKWW91IGNhbiBhY2Nlc3MgdGhlIHNhbXBsZXMgbWV0YWRhdGEgd2l0aCBgY29sRGF0YWAuCmBgYHtSfQpkYXRhLmhnMzggJT4lIGNvbERhdGEgJT4lIGFzLmRhdGEuZnJhbWUKYGBgCllvdSBjYW4gYWNjZXNzIHRoZSBETkEgbWV0aHlsYXRpb24gbGV2ZWxzIHdpdGggYGFzc2F5YC4KYGBge1J9CmRhdGEuaGczOCAlPiUgYXNzYXkgJT4lIGhlYWQgJT4lIGFzLmRhdGEuZnJhbWUKYGBgCgpgYGB7Un0KIyBwbG90IDEwIG1vc3QgdmFyaWFibGUgcHJvYmVzCmRhdGEuaGczOCAlPiUgCiAgYXNzYXkgJT4lIAogIHJvd1ZhcnMgJT4lIAogIG9yZGVyKGRlY3JlYXNpbmcgPSBUUlVFKSAlPiUgCiAgaGVhZCgxMCkgLT4gaWR4CgpwYWxfbWV0aHlsYXRpb24gPC0gY29sb3JSYW1wUGFsZXR0ZShjKCIjMDAwNDM2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIzAyMUVBOSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiMxNjMyRkIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjNkUzNEZDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI0M3MzJENSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNGRDYxOUQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjRkY5OTY1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI0ZGRDMyQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNGRkZDNUEiKSkoMTAwKQoKSGVhdG1hcChhc3NheShkYXRhLmhnMzgpW2lkeCxdLAogICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gVFJVRSwgCiAgICAgICAgc2hvd19yb3dfbmFtZXMgPSBUUlVFLAogICAgICAgICBuYW1lID0gIk1ldGh5bGF0aW9uIEJldGEtdmFsdWUiLCAKICAgICAgICAgcm93X25hbWVzX2dwID0gZ3Bhcihmb250c2l6ZSA9IDgpLAogICAgICAgICBjb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gOCksCiAgICAgICAgY29sID0gY2lyY2xpemU6OmNvbG9yUmFtcDIoc2VxKDAsIDEsIGJ5ID0gMS85OSksIHBhbF9tZXRoeWxhdGlvbikpCmBgYAoKIyMgQVRBQy1TZXEgZGF0YQoKUGxlYXNlLCBjaGVjayBvdXIgQVRBQy1zZXEgV29ya3Nob3A6IGh0dHA6Ly9ycHVicy5jb20vdGlhZ29jaHN0L2F0YWNfc2VxX3dvcmtzaG9wCgojIFNlc3Npb24gaW5mb3JtYXRpb24KYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgojIFdvcmtzaG9wIG1hdGVyaWFscwoKIyMgU291cmNlIGNvZGUKCkFsbCBzb3VyY2UgY29kZSB1c2VkIHRvIHByb2R1Y2UgdGhlIHdvcmtzaG9wcyBhcmUgYXZhaWxhYmxlIGF0IGh0dHBzOi8vZ2l0aHViLmNvbS90aWFnb2Noc3QvRUxNRVJfd29ya3Nob3BfMjAxOS4KCiMjIFdvcmtzaG9wcyBIVE1McwoKKiBFTE1FUiBkYXRhIFdvcmtzaG9wIEhUTUw6IGh0dHA6Ly9ycHVicy5jb20vdGlhZ29jaHN0L2VsbWVyLWRhdGEtd29ya3Nob3AtMjAxOQoqIEVMTUVSIGFuYWx5c2lzIFdvcmtzaG9wIEhUTUw6IGh0dHA6Ly9ycHVicy5jb20vdGlhZ29jaHN0L0VMTUVSX3dvcmtzaG9wCiogQVRBQy1zZXEgV29ya3Nob3AgSFRNTDogaHR0cDovL3JwdWJzLmNvbS90aWFnb2Noc3QvYXRhY19zZXFfd29ya3Nob3AKCgojIyBXb3Jrc2hvcCB2aWRlb3MKCldlIGhhdmUgYSBzZXQgb2YgcmVjb3JkZWQgdmlkZW9zLCBleHBsYWluaW5nIHNvbWUgb2YgdGhlIHdvcmtzaG9wcy4KCiogQWxsIHZpZGVvcyBwbGF5bGlzdDogaHR0cHM6Ly93d3cueW91dHViZS5jb20vcGxheWxpc3Q/bGlzdD1QTG9EekFLTUpoMTVrTnBDU0l4cFN1Wmdrc1piSk5mbU10CiogRUxNRVIgYWxnb3JpdGhtOiBodHRwczovL3lvdXR1LmJlL1B6QzMxSzl2ZnUwCiogRUxNRVIgZGF0YTogaHR0cHM6Ly95b3V0dS5iZS9SMDB3Ry0tdEdvOAoqIEVMTUVSIGFuYWx5c2lzIHBhcnQxOiBodHRwczovL3lvdXR1LmJlL2JjZDR1eXhyWkN3CiogRUxNRVIgYW5hbHlzaXMgcGFydDI6IGh0dHBzOi8veW91dHUuYmUvdmNKX0RTQ3Q0TW8KKiBFTE1FUiBzdW1tYXJpemluZyBzZXZlcmFsIGFuYWx5c2VzOiBodHRwczovL3lvdXR1LmJlL21vTGVpazdKakxrCiogQVRBQy1TZXEgd29ya3Nob3A6IGh0dHBzOi8veW91dHUuYmUvM2Z0WmVjejBsVTQKCgpgYGB7UiwgZXZhbCA9IEZBTFNFLCBpbmNsdWRlID0gRkFMU0V9CiMgbWlSTkEKbGlicmFyeShUQ0dBYmlvbGlua3MpCnF1ZXJ5Lm1pcm5hIDwtIEdEQ3F1ZXJ5KHByb2plY3QgPSAiVEFSR0VULUFNTCIsIAogICAgICAgICAgICAgICAgICAgICAgICBleHBlcmltZW50YWwuc3RyYXRlZ3kgPSAibWlSTkEtU2VxIiwKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5jYXRlZ29yeSA9ICJUcmFuc2NyaXB0b21lIFByb2ZpbGluZyIsIAogICAgICAgICAgICAgICAgICAgICAgICBiYXJjb2RlID0gYygiVEFSR0VULTIwLVBBVEROTiIsIlRBUkdFVC0yMC1QQVBVTlIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS50eXBlID0gIm1pUk5BIEV4cHJlc3Npb24gUXVhbnRpZmljYXRpb24iKQpHRENkb3dubG9hZChxdWVyeS5taXJuYSkKbWlybmEgPC0gR0RDcHJlcGFyZShxdWVyeSA9IHF1ZXJ5Lm1pcm5hLAogICAgICAgICAgICAgICAgICAgICBzYXZlID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgIHNhdmUuZmlsZW5hbWUgPSAibWlybmEucmRhIikKCgpxdWVyeS5pc29mb3JtIDwtIEdEQ3F1ZXJ5KHByb2plY3QgPSAiVEFSR0VULUFNTCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGV4cGVyaW1lbnRhbC5zdHJhdGVneSA9ICJtaVJOQS1TZXEiLAogICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuY2F0ZWdvcnkgPSAiVHJhbnNjcmlwdG9tZSBQcm9maWxpbmciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBiYXJjb2RlID0gYygiVEFSR0VULTIwLVBBVEROTiIsIlRBUkdFVC0yMC1QQVBVTlIiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLnR5cGUgPSAiSXNvZm9ybSBFeHByZXNzaW9uIFF1YW50aWZpY2F0aW9uIikKR0RDZG93bmxvYWQocXVlcnkuaXNvZm9ybSkKCmlzb2Zvcm0gPC0gR0RDcHJlcGFyZShxdWVyeSA9IHF1ZXJ5Lmlzb2Zvcm0sCiAgICAgICAgICAgICAgICAgICAgc2F2ZSA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgIHNhdmUuZmlsZW5hbWUgPSAibWlybmEtaXNvZm9ybS5yZGEiKQpgYGAKCgojIFJlZmVyZW5jZXMK