1 Instructor names and contact information

  1. Benjamin P. Berman (Benjamin.Berman at cshs.org)
  2. Tiago C. Silva (tiagochst at gmail.com)

2 Workshop description

2.1 Aims

This workshop will:

  1. Introduce you to the TCGA (The Cancer Genome Atlas) data available at the NCI’s Genomic Data Commons (GDC).
  2. Demonstrate how to access and import TCGA data using the R/Bioconductor package TCGAbiolinks (Colaprico et al. 2015).
  3. Provide instruction to visualize copy number alteration and mutation data using the R/Bioconductor package maftools.

2.3 Reference articles

  • TCGAbiolinks:
    • Colaprico, Antonio, et al. “TCGAbiolinks: an R/Bioconductor package for integrative analysis of TCGA data.” Nucleic acids research 44.8 (2015): e71-e71. Silva, Tiago C., et al. “TCGA Workflow: Analyze cancer genomics and epigenomics data using Bioconductor packages.” F1000Research 5 (2016). (https://f1000research.com/articles/5-1542/v2)
    • Mounir, Mohamed, et al. “New functionalities in the TCGAbiolinks package for the study and integration of cancer data from GDC and GTEx.” PLoS computational biology 15.3 (2019): e1006701. (https://doi.org/10.1371/journal.pcbi.1006701)
    • Silva TC, Colaprico A, Olsen C et al.TCGA Workflow: Analyze cancer genomics and epigenomics data using Bioconductor packages [version 2; peer review: 1 approved, 2 approved with reservations]. F1000Research 2016, 5:1542 (https://doi.org/10.12688/f1000research.8923.2).
  • The NCI’s Genomic Data Commons (GDC):
  • Maftools:
    • Mayakonda A, Lin D, Assenov Y, Plass C, Koeffler PH (2018). “Maftools: efficient and comprehensive analysis of somatic variants in cancer.” Genome Research. doi: 10.1101/gr.239244.118.
  • Complexheatmap:
    • Gu Z, Eils R, Schlesner M (2016). “Complex heatmaps reveal patterns and correlations in multidimensional genomic data.” Bioinformatics.

2.4 R/Bioconductor packages used

2.5 Pre-requisites

3 Introduction

3.1 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:

Figure: TCGA databases (blue: legacy archive. red: harmonized database) Source: https://portal.gdc.cancer.gov/

3.2 Understanding TCGA data

3.2.1 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.

3.2.2 TCGA barcode description

Each TCGA sample has a unique identifier called TCGA barcode, which contains important information about each sample. A description of the barcode is shown below (Source: https://docs.gdc.cancer.gov/Encyclopedia/pages/TCGA_Barcode/).

You can find a table with all the code and meanings at https://gdc.cancer.gov/resources-tcga-users/tcga-code-tables. The Sample Type Codes is shown below:

3.2.3 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.

Figure: Data category filter

Figure: Data type filter

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.

Figure: Filtering by Gene Expression Quantification

You can find the entry possibilities for each filter at the repository page of the database at https://portal.gdc.cancer.gov/repository.

3.3 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.

Figure: Summarized Experiment data structure. Source: http://bioconductor.org/packages/SummarizedExperiment/

3.4 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

4 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:

  1. Access TCGA clinical data
  2. Search, download and make an R object from TCGA data
  • RNA-seq data
  • DNA methylation
  1. Download samples metadata
  2. Download and visualize mutations
  3. Download and visualize copy number alterations

4.1 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.

Figure: Clinical data patient: TCGA-AA-3562. Source: https://portal.gdc.cancer.gov/cases/127f738d-afa1-42f6-a9a0-f33806667b84

# 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

4.2 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)
head(raw.counts)

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)
head(fpkm.uq.counts)

4.3 Mutation

TCGAbiolinks has provided a few functions to download mutation data from GDC. There are two options to download the data:

  1. 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)

4.4 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)
scores[1:5,1:5]

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")))

4.5 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)
data.hg38
## 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))

4.6 ATAC-Seq data

Please, check our ATAC-seq Workshop: http://rpubs.com/tiagochst/atac_seq_workshop

5 Session information

sessionInfo()
## R version 3.5.3 Patched (2019-03-11 r76979)
## Platform: x86_64-apple-darwin15.6.0 (64-bit)
## Running under: macOS Mojave 10.14.6
## 
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
##  [1] grid      parallel  stats4    stats     graphics  grDevices utils    
##  [8] datasets  methods   base     
## 
## other attached packages:
##  [1] ComplexHeatmap_2.1.0        dplyr_0.8.3                
##  [3] maftools_2.0.16             MultiAssayExperiment_1.8.3 
##  [5] SummarizedExperiment_1.12.0 DelayedArray_0.8.0         
##  [7] BiocParallel_1.16.6         matrixStats_0.54.0         
##  [9] Biobase_2.42.0              GenomicRanges_1.34.0       
## [11] GenomeInfoDb_1.18.2         IRanges_2.16.0             
## [13] S4Vectors_0.20.1            BiocGenerics_0.28.0        
## [15] TCGAbiolinks_2.13.5        
## 
## loaded via a namespace (and not attached):
##   [1] backports_1.1.4             circlize_0.4.6             
##   [3] aroma.light_3.12.0          NMF_0.21.0                 
##   [5] plyr_1.8.4                  selectr_0.4-1              
##   [7] ConsensusClusterPlus_1.46.0 lazyeval_0.2.2             
##   [9] splines_3.5.3               ggplot2_3.2.1              
##  [11] gridBase_0.4-7              sva_3.30.1                 
##  [13] digest_0.6.20               foreach_1.4.7              
##  [15] htmltools_0.3.6             magrittr_1.5               
##  [17] memoise_1.1.0               cluster_2.0.7-1            
##  [19] doParallel_1.0.15           limma_3.38.3               
##  [21] Biostrings_2.50.2           readr_1.3.1                
##  [23] annotate_1.60.1             wordcloud_2.6              
##  [25] R.utils_2.9.0               prettyunits_1.0.2          
##  [27] colorspace_1.4-1            blob_1.2.0                 
##  [29] rvest_0.3.4                 ggrepel_0.8.1              
##  [31] xfun_0.8                    crayon_1.3.4               
##  [33] RCurl_1.95-4.12             jsonlite_1.6               
##  [35] genefilter_1.64.0           zeallot_0.1.0              
##  [37] survival_2.43-3             zoo_1.8-6                  
##  [39] iterators_1.0.12            glue_1.3.1                 
##  [41] survminer_0.4.5             registry_0.5-1             
##  [43] gtable_0.3.0                zlibbioc_1.28.0            
##  [45] XVector_0.22.0              GetoptLong_0.1.7           
##  [47] shape_1.4.4                 scales_1.0.0               
##  [49] DESeq_1.34.1                rngtools_1.3.1             
##  [51] DBI_1.0.0                   edgeR_3.24.3               
##  [53] bibtex_0.4.2                ggthemes_4.2.0             
##  [55] Rcpp_1.0.2                  xtable_1.8-4               
##  [57] progress_1.2.2              clue_0.3-57                
##  [59] bit_1.1-14                  matlab_1.0.2               
##  [61] km.ci_0.5-2                 httr_1.4.1                 
##  [63] RColorBrewer_1.1-2          pkgconfig_2.0.2            
##  [65] XML_3.98-1.20               R.methodsS3_1.7.1          
##  [67] locfit_1.5-9.1              tidyselect_0.2.5           
##  [69] rlang_0.4.0                 reshape2_1.4.3             
##  [71] AnnotationDbi_1.44.0        munsell_0.5.0              
##  [73] tools_3.5.3                 downloader_0.4             
##  [75] generics_0.0.2              RSQLite_2.1.2              
##  [77] broom_0.5.2                 evaluate_0.14              
##  [79] stringr_1.4.0               yaml_2.2.0                 
##  [81] knitr_1.24                  bit64_0.9-7                
##  [83] survMisc_0.5.5              purrr_0.3.2                
##  [85] EDASeq_2.16.3               nlme_3.1-137               
##  [87] R.oo_1.22.0                 xml2_1.2.2                 
##  [89] biomaRt_2.38.0              compiler_3.5.3             
##  [91] curl_4.0                    png_0.1-7                  
##  [93] ggsignif_0.6.0              tibble_2.1.3               
##  [95] geneplotter_1.60.0          stringi_1.4.3              
##  [97] GenomicFeatures_1.34.6      lattice_0.20-38            
##  [99] Matrix_1.2-15               KMsurv_0.1-5               
## [101] vctrs_0.2.0                 pillar_1.4.2               
## [103] GlobalOptions_0.1.0         data.table_1.12.2          
## [105] bitops_1.0-6                rtracklayer_1.42.2         
## [107] R6_2.4.0                    latticeExtra_0.6-28        
## [109] hwriter_1.3.2               ShortRead_1.40.0           
## [111] gridExtra_2.3               codetools_0.2-16           
## [113] assertthat_0.2.1            pkgmaker_0.27              
## [115] rjson_0.2.20                withr_2.1.2                
## [117] GenomicAlignments_1.18.1    Rsamtools_1.34.1           
## [119] GenomeInfoDbData_1.2.0      mgcv_1.8-27                
## [121] hms_0.5.0                   tidyr_0.8.3                
## [123] rmarkdown_1.14              ggpubr_0.2.2               
## [125] base64enc_0.1-3

6 Workshop materials

6.1 Source code

All source code used to produce the workshops are available at https://github.com/tiagochst/ELMER_workshop_2019.

6.2 Workshops HTMLs

6.3 Workshop videos

We have a set of recorded videos, explaining some of the workshops.

References

Zhou, Wanding, Peter W Laird, and Hui Shen. 2017. “Comprehensive Characterization, Annotation and Innovative Use of Infinium Dna Methylation Beadchip Probes.” Nucleic Acids Research 45 (4): e22–e22.

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