Overview
The netboxr package composes a number of functions to retrive and process genetic data from large-scale genomics projects (e.g. TCGA projects) including from mutations, copy number alterations, gene expression and DNA methylation. The netboxr package implements NetBox algorithm in R package. NetBox algorithm integrates genetic alterations with literature-curated pathway knowledge to identify pathway modules in cancer. NetBox algorithm uses (1) global network null model and (2) local network null model to access the statistic significance of the discovered pathway modules.
Basics
Installation
BiocManager::install("netboxr")
Getting Started
Load netboxr package:
r
r library(netboxr)
A list of all accessible vignettes and methods is available with the following command:
help(package="netboxr")
For help on any netboxr package functions, use one of the following command formats:
help(geneConnector)
?geneConnector
Example of Cerami et al. PLoS One 2010
This is an example to reproduce the network discovered on Cerami et al.(2010).
The results presented here are comparable to the those from Cerami et al. 2010 though the unadjusted p-values for linker genes are not the same. It is because the unadjusted p-value of linker genes in Cerami et al. 2010 were calculated by the probabiliy of the observed data point, Pr(X). The netboxr used the probability of an observed or more extreme assuming the null hypothesis is true, Pr(X>=x|H), as unadjusted p-value for linker genes. The final number of linker genes after FDR correction are the same between netboxr result and original Cerami et al. 2010.
Load Human Interactions Network (HIN) network
Load pre-defined HIN network and simplify the interactions by removing loops and duplicated interactions in the network. The netowork after reduction contains 9264 nodes and 68111 interactions.
r
r data(netbox2010) sifNetwork <- netbox2010$network graphReduced <- networkSimplify(sifNetwork,directed = FALSE)
Load altered gene list
The altered gene list contains 517 candidates from mutations and copy number alterations.
r
r geneList <- as.character(netbox2010$geneList) length(geneList)
Map altered gene list on HIN network
The geneConnector function in the netboxr package takes altered gene list as input and maps the genes on the curated network to find the local processes represented by the gene list.
r
r ## Use Benjamini-Hochberg method to do multiple hypothesis ## correction for linker candidates.
Add edge annotations
library(RColorBrewer) edges <- results$netboxOutput interactionType<-unique(edges[,2]) interactionTypeColor<-brewer.pal(length(interactionType),name=)
edgeColors<-data.frame(interactionType,interactionTypeColor,stringsAsFactors = FALSE) colnames(edgeColors)<-c(_TYPE,)
netboxGraphAnnotated <- annotateGraph(netboxResults = results, edgeColors = edgeColors, directed = FALSE, linker = TRUE)
Check the p-value of the selected linker
linkerDF <- results\(neighborData linkerDF[linkerDF\)pValueFDR<threshold,]
The geneConnector function returns a list of data frames.
names(results)
Plot graph with the Fruchterman-Reingold layout algorithm
As an example, plot both the original and the annotated graphs
Save the layout for easier comparison
graph_layout <- layout_with_fr(results$netboxGraph)
plot the original graph
plot(results\(netboxCommunity,results\)netboxGraph, layout=graph_layout)
Plot the edge annotated graph
plot(results\(netboxCommunity, netboxGraphAnnotated, layout = graph_layout, vertex.size = 10, vertex.shape = V(netboxGraphAnnotated)\)shape, edge.color = E(netboxGraphAnnotated)$interactionColor, edge.width = 3)
Add interaction type annotations
legend(, legend=interactionType, col=interactionTypeColor, lty=1,lwd=2, bty=, cex=1)
Consistency with Previously Published Results
The GBM result by netboxr identified exactly the same linker genes (6 linker genes), the same number of modules (10 modules) and the same genes in each identified module as GBM result in Cerami et al. 2010.
The results of netboxr are consistent with previous implementation of the NetBox algorithm. The RB1 and PIK3R1 modules are clearly represented in the figure. For example, the RB1 module contains genes in blue color and enclosed by light orange circle. The PIK3R1 module contains genes in orange color and enclosed by pink circle.
Statistical Significance of Discovered Network
NetBox algorithm used (1) global network null model and (2) local network null model to access the statistical significance of the discovered network.
Global Network Null Model
The global network null model calculates the empirical p-value as the number of times (over a set of iterations) the size of the largest connected component (the giant component) in the network coming from the same number of randomly selected genes (number of genes is 274 in this example) equals or exceeds the size of the largest connected component in the observed network. The suggested iterations are 1000.
## This function will need a lot of time to complete.
globalTest <- globalNullModel(netboxGraph=results$netboxGraph, networkGraph=graphReduced, iterations=10, numOfGenes = 274)
Local Network Null Model
Local network null model evaluates the deviation of modularity in the observed network from modularity distribution in the random network. For each interaction, a random network is produced from local re-wiring of literature curated network. It means all nodes in the network kept the same degree of connections but connect to new neighbors randomly. Suggested iterations is 1000.
r
r localTest <- localNullModel(netboxGraph=results$netboxGraph, iterations=1000)
Through 1000 iterations, we can obtain the mean and the standard deviation of modularity in the local network null model. Using the mean (~0.3) and the standard deviation (0.06), we can covert the observed modularity in the network (0.519) into a Z-score (~3.8). From the Z-score, we can calculate one-tail p-value. If one-tail pvalue is less than 0.05, the observed modularity is significantly different from random. In the histogram, the blue region is the distribution of modularity in the local network null model. The red vertical line is the observed modularity in the NetBox results.
r
r h<-hist(localTest\(randomModularityScore,breaks=35,plot=FALSE) h\)density = h\(counts/sum(h\)counts) plot(h,freq=FALSE,ylim=c(0,0.1),xlim=c(0.1,0.6), col=) abline(v=localTest$modularityScoreObs,col=)
The global null model is used to assess the global connectivity (number of nodes and edges) of the largest module in the identified network compared with the same number but randomly selected gene list.
The local null model is used to assess the network modularity in the identified network compared with random re-wired network.
View Module Membership
The table below shows the module memberships for all genes.
r
r DT::datatable(results$moduleMembership, rownames = FALSE)
Write NetBox Output to Files
# Write results for further visilaztion in the cytoscape software.
#
# network.sif file is the NetBox algorithm output in SIF format.
write.table(results$netboxOutput, file="network.sif", sep="\t", quote=FALSE, col.names=FALSE, row.names=FALSE)
#
# netighborList.txt file contains the information of all neighbor nodes.
write.table(results$neighborData, file="neighborList.txt", sep="\t", quote=FALSE, col.names=TRUE, row.names=FALSE)
#
# community.membership.txt file indicates the identified pathway module numbers.
write.table(results$moduleMembership, file="community.membership.txt", sep="\t", quote=FALSE, col.names=FALSE, row.names=FALSE)
#
# nodeType.txt file indicates the node is "linker" node or "candidate" node.
write.table(results$nodeType,file="nodeType.txt", sep="\t", quote=FALSE, col.names=FALSE, row.names=FALSE)
Term Enrichment in Modules using Gene Ontology (GO) Analysis
After module identification, one main task is understanding the biological processes that may be represented by the returned modules. Here we use the Bioncoductor clusterProfiler to do an enrichment analysis using GO Biological Process terms on a selected module.
r
r library(clusterProfiler) library(org.Hs.eg.db)
module <- 6 selectedModule <- results\(moduleMembership[results\)moduleMembership\(membership == module,] geneList <-selectedModule\)geneSymbol
Check available ID types in for the org.Hs.eg.db annotation package
keytypes(org.Hs.eg.db)
ids <- bitr(geneList, fromType=, toType=c(), OrgDb=.Hs.eg.db) head(ids)
ego <- enrichGO(gene = ids$ENTREZID, OrgDb = org.Hs.eg.db, ont = , pAdjustMethod = , pvalueCutoff = 0.01, qvalueCutoff = 0.05, readable = TRUE)
Enrichment Results
r
r head(ego)
Visualize Enrichment Results
r
r dotplot(ego)
Alternative Module Discovery Methods
In netboxr, we used the Girvan-Newman algorithm (communityMethod=“ebc”) as the default method to detect community membership in the identified network. The Girvan-Newman algorithm iteratativly removes the edge in the network with highest edge betweeness until no edges left. When the identified network contains many edges, the Girvan-Newman algorithm will spend a large amount of time to remove edges and re-calucalte the edge betweenese score in the network. If the user cannot get the community detection result in reasonable time, we suggest to switch to leading eigenvector method (communityMethod=“lec”) for community detection. Users can check original papers of the Girvan-Newman algorithm and leading eigenvector method for more details.
References
- Cerami E, Demir E, Schultz N, Taylor BS, Sander C (2010) Automated Network Analysis Identifies Core Pathways in Glioblastoma. PLoS ONE 5(2): e8918. doi:10.1371/journal.pone.0008918
- Cerami EG, Gross BE, Demir E, Rodchenkov I, Babur O, Anwar N, Schultz N, Bader GD, Sander C. Pathway Commons, a web resource for biological pathway data. Nucleic Acids Res. 2011 Jan;39(Database issue):D685-90. doi:10.1093/nar/gkq1039. Epub 2010 Nov 10.
LS0tCnRpdGxlOiAiTmV0Qm94UiBUdXRvcmlhbCIKYXV0aG9yOiAiRXJpYyBNaW53ZWkgTGl1IGFuZCBBdWd1c3RpbiBMdW5hIgpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiCm91dHB1dDoKICBCaW9jU3R5bGU6Omh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiBubwogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIG1kX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHZhcmlhbnQ6IGdmbQogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCmFsd2F5c19hbGxvd19odG1sOiB5ZXMKdmlnbmV0dGU6ID4KICAlXFZpZ25ldHRlSW5kZXhFbnRyeXtOZXRCb3hSIFR1dG9yaWFsfSAKICAlXFZpZ25ldHRlRW5jb2Rpbmd7VVRGLTh9IAogICVcVmlnbmV0dGVFbmdpbmV7a25pdHI6OnJtYXJrZG93bn0KLS0tCgoKYGBge3Iga25pdHJTZXR1cCwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShrbml0cikKb3B0c19jaHVuayRzZXQob3V0LmV4dHJhPSdzdHlsZT0iZGlzcGxheTpibG9jazsgbWFyZ2luOiBhdXRvIicsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyLCB0aWR5PVRSVUUpCmBgYAoKYGBge3Igc3R5bGUsIGluY2x1ZGU9RkFMU0UsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQpCaW9jU3R5bGU6Om1hcmtkb3duKCkKYGBgCgojIE92ZXJ2aWV3CgpUaGUgKipuZXRib3hyKiogcGFja2FnZSBjb21wb3NlcyBhIG51bWJlciBvZiBmdW5jdGlvbnMgdG8gcmV0cml2ZSBhbmQgcHJvY2VzcyAKZ2VuZXRpYyBkYXRhIGZyb20gbGFyZ2Utc2NhbGUgZ2Vub21pY3MgcHJvamVjdHMgKGUuZy4gVENHQSBwcm9qZWN0cykgaW5jbHVkaW5nIApmcm9tIG11dGF0aW9ucywgY29weSBudW1iZXIgYWx0ZXJhdGlvbnMsIGdlbmUgZXhwcmVzc2lvbiBhbmQgRE5BIG1ldGh5bGF0aW9uLiAKVGhlIG5ldGJveHIgcGFja2FnZSBpbXBsZW1lbnRzIE5ldEJveCBhbGdvcml0aG0gaW4gUiBwYWNrYWdlLiBOZXRCb3ggYWxnb3JpdGhtIAppbnRlZ3JhdGVzIGdlbmV0aWMgYWx0ZXJhdGlvbnMgd2l0aCBsaXRlcmF0dXJlLWN1cmF0ZWQgcGF0aHdheSBrbm93bGVkZ2UgdG8gCmlkZW50aWZ5IHBhdGh3YXkgbW9kdWxlcyBpbiBjYW5jZXIuIE5ldEJveCBhbGdvcml0aG0gdXNlcyAoMSkgZ2xvYmFsIG5ldHdvcmsgCm51bGwgbW9kZWwgYW5kICgyKSBsb2NhbCBuZXR3b3JrIG51bGwgbW9kZWwgdG8gYWNjZXNzIHRoZSBzdGF0aXN0aWMgc2lnbmlmaWNhbmNlIApvZiB0aGUgZGlzY292ZXJlZCBwYXRod2F5IG1vZHVsZXMuCgojIEJhc2ljcwojIyBJbnN0YWxsYXRpb24KCmBgYHtyIGluc3RhbGxOZXRCb3hyLCBldmFsPUZBTFNFfQpCaW9jTWFuYWdlcjo6aW5zdGFsbCgibmV0Ym94ciIpCmBgYAoKIyMgR2V0dGluZyBTdGFydGVkCgpMb2FkICoqbmV0Ym94cioqIHBhY2thZ2U6IAoKYGBge3IgbG9hZExpYnJhcnksIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkobmV0Ym94cikKYGBgCgpBIGxpc3Qgb2YgYWxsIGFjY2Vzc2libGUgdmlnbmV0dGVzIGFuZCBtZXRob2RzIGlzIGF2YWlsYWJsZSB3aXRoIHRoZSBmb2xsb3dpbmcgY29tbWFuZDogCgpgYGB7ciBzZWFyY2hIZWxwLCBldmFsPUZBTFNFLCB0aWR5PUZBTFNFfQpoZWxwKHBhY2thZ2U9Im5ldGJveHIiKQpgYGAKCkZvciBoZWxwIG9uIGFueSAqKm5ldGJveHIqKiBwYWNrYWdlIGZ1bmN0aW9ucywgdXNlIG9uZSBvZiB0aGUgZm9sbG93aW5nIGNvbW1hbmQgZm9ybWF0czoKCmBgYHtyIHNob3dIZWxwLCBldmFsPUZBTFNFLCB0aWR5PUZBTFNFfQpoZWxwKGdlbmVDb25uZWN0b3IpCj9nZW5lQ29ubmVjdG9yCmBgYAoKIyBFeGFtcGxlIG9mIENlcmFtaSBldCBhbC4gUExvUyBPbmUgMjAxMAoKVGhpcyBpcyBhbiBleGFtcGxlIHRvIHJlcHJvZHVjZSB0aGUgbmV0d29yayBkaXNjb3ZlcmVkIG9uIFtDZXJhbWkgZXQgYWwuKDIwMTApXShodHRwOi8vam91cm5hbHMucGxvcy5vcmcvcGxvc29uZS9hcnRpY2xlP2lkPTEwLjEzNzEvam91cm5hbC5wb25lLjAwMDg5MTgpLgoKVGhlIHJlc3VsdHMgcHJlc2VudGVkIGhlcmUgYXJlIGNvbXBhcmFibGUgdG8gdGhlIHRob3NlIGZyb20gQ2VyYW1pIGV0IGFsLiAyMDEwIAp0aG91Z2ggdGhlIHVuYWRqdXN0ZWQgcC12YWx1ZXMgZm9yIGxpbmtlciBnZW5lcyBhcmUgbm90IHRoZSBzYW1lLiAKSXQgaXMgYmVjYXVzZSB0aGUgdW5hZGp1c3RlZCBwLXZhbHVlIG9mIGxpbmtlciBnZW5lcyBpbiBDZXJhbWkgZXQgYWwuIDIwMTAgd2VyZQpjYWxjdWxhdGVkIGJ5IHRoZSBwcm9iYWJpbGl5IG9mIHRoZSBvYnNlcnZlZCBkYXRhIHBvaW50LCBQcihYKS4gVGhlIG5ldGJveHIgdXNlZCB0aGUgcHJvYmFiaWxpdHkKb2YgYW4gb2JzZXJ2ZWQgb3IgbW9yZSBleHRyZW1lIGFzc3VtaW5nIHRoZSBudWxsIGh5cG90aGVzaXMgaXMgdHJ1ZSwgIFByKFg+PXh8SCksCmFzIHVuYWRqdXN0ZWQgcC12YWx1ZSBmb3IgbGlua2VyIGdlbmVzLiBUaGUgZmluYWwgbnVtYmVyIG9mIGxpbmtlciBnZW5lcyBhZnRlciAKRkRSIGNvcnJlY3Rpb24gYXJlIHRoZSBzYW1lIGJldHdlZW4gbmV0Ym94ciByZXN1bHQgYW5kIG9yaWdpbmFsIENlcmFtaSBldCBhbC4gMjAxMC4KCiMjIExvYWQgSHVtYW4gSW50ZXJhY3Rpb25zIE5ldHdvcmsgKEhJTikgbmV0d29yawoKTG9hZCBwcmUtZGVmaW5lZCBISU4gbmV0d29yayBhbmQgc2ltcGxpZnkgdGhlIGludGVyYWN0aW9ucyBieSByZW1vdmluZyBsb29wcwphbmQgZHVwbGljYXRlZCBpbnRlcmFjdGlvbnMgaW4gdGhlIG5ldHdvcmsuIFRoZSBuZXRvd29yayBhZnRlciByZWR1Y3Rpb24KY29udGFpbnMgOTI2NCBub2RlcyBhbmQgNjgxMTEgaW50ZXJhY3Rpb25zLiAKCmBgYHtyIG5ldGJveHJFeGFtcGxlTmV0d29ya30KZGF0YShuZXRib3gyMDEwKQpzaWZOZXR3b3JrIDwtIG5ldGJveDIwMTAkbmV0d29yawpncmFwaFJlZHVjZWQgPC0gbmV0d29ya1NpbXBsaWZ5KHNpZk5ldHdvcmssZGlyZWN0ZWQgPSBGQUxTRSkgICAgICAKYGBgCgojIyBMb2FkIGFsdGVyZWQgZ2VuZSBsaXN0CgpUaGUgYWx0ZXJlZCBnZW5lIGxpc3QgY29udGFpbnMgNTE3IGNhbmRpZGF0ZXMgZnJvbSBtdXRhdGlvbnMgYW5kIGNvcHkgbnVtYmVyCmFsdGVyYXRpb25zLiAKCmBgYHtyIG5ldGJveHJFeGFtcGxlR2VuZX0KZ2VuZUxpc3QgPC0gYXMuY2hhcmFjdGVyKG5ldGJveDIwMTAkZ2VuZUxpc3QpIApsZW5ndGgoZ2VuZUxpc3QpCmBgYAoKIyMgTWFwIGFsdGVyZWQgZ2VuZSBsaXN0IG9uIEhJTiBuZXR3b3JrCgpUaGUgZ2VuZUNvbm5lY3RvciBmdW5jdGlvbiBpbiB0aGUgbmV0Ym94ciBwYWNrYWdlIHRha2VzIGFsdGVyZWQgZ2VuZSBsaXN0IGFzCmlucHV0IGFuZCBtYXBzIHRoZSBnZW5lcyBvbiB0aGUgY3VyYXRlZCBuZXR3b3JrIHRvIGZpbmQgdGhlIGxvY2FsIHByb2Nlc3NlcyAKcmVwcmVzZW50ZWQgYnkgdGhlIGdlbmUgbGlzdC4gCgpgYGB7ciBuZXRib3hyRXhhbXBsZUdlbmVDb25uZWN0b3IsIGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD0xMn0KIyMgVXNlIEJlbmphbWluaS1Ib2NoYmVyZyBtZXRob2QgdG8gZG8gbXVsdGlwbGUgaHlwb3RoZXNpcyAKIyMgY29ycmVjdGlvbiBmb3IgbGlua2VyIGNhbmRpZGF0ZXMuCgojIyBVc2UgZWRnZS1iZXR3ZWVuZXNzIG1ldGhvZCB0byBkZXRlY3QgY29tbXVuaXR5IHN0cnVjdHVyZSBpbiB0aGUgbmV0d29yay4gCnRocmVzaG9sZCA8LSAwLjA1CnJlc3VsdHMgPC0gZ2VuZUNvbm5lY3RvcihnZW5lTGlzdD1nZW5lTGlzdCwKICAgICAgICAgICAgICAgICAgICAgICAgbmV0d29ya0dyYXBoPWdyYXBoUmVkdWNlZCwKICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0ZWQ9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgcFZhbHVlQWRqPSJCSCIsCiAgICAgICAgICAgICAgICAgICAgICAgcFZhbHVlQ3V0b2ZmPXRocmVzaG9sZCwKICAgICAgICAgICAgICAgICAgICAgICBjb21tdW5pdHlNZXRob2Q9ImViYyIsCiAgICAgICAgICAgICAgICAgICAgICAga2VlcElzb2xhdGVkTm9kZXM9RkFMU0UpCgojIEFkZCBlZGdlIGFubm90YXRpb25zCmxpYnJhcnkoUkNvbG9yQnJld2VyKQplZGdlcyA8LSByZXN1bHRzJG5ldGJveE91dHB1dAppbnRlcmFjdGlvblR5cGU8LXVuaXF1ZShlZGdlc1ssMl0pCmludGVyYWN0aW9uVHlwZUNvbG9yPC1icmV3ZXIucGFsKGxlbmd0aChpbnRlcmFjdGlvblR5cGUpLG5hbWU9IlNwZWN0cmFsIikKCmVkZ2VDb2xvcnM8LWRhdGEuZnJhbWUoaW50ZXJhY3Rpb25UeXBlLGludGVyYWN0aW9uVHlwZUNvbG9yLHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKY29sbmFtZXMoZWRnZUNvbG9ycyk8LWMoIklOVEVSQUNUSU9OX1RZUEUiLCJDT0xPUiIpCgoKbmV0Ym94R3JhcGhBbm5vdGF0ZWQgPC0gYW5ub3RhdGVHcmFwaChuZXRib3hSZXN1bHRzID0gcmVzdWx0cywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZGdlQ29sb3JzID0gZWRnZUNvbG9ycywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3RlZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmtlciA9IFRSVUUpCgojIENoZWNrIHRoZSBwLXZhbHVlIG9mIHRoZSBzZWxlY3RlZCBsaW5rZXIKbGlua2VyREYgPC0gcmVzdWx0cyRuZWlnaGJvckRhdGEKbGlua2VyREZbbGlua2VyREYkcFZhbHVlRkRSPHRocmVzaG9sZCxdCgojIFRoZSBnZW5lQ29ubmVjdG9yIGZ1bmN0aW9uIHJldHVybnMgYSBsaXN0IG9mIGRhdGEgZnJhbWVzLiAKbmFtZXMocmVzdWx0cykKCiMgUGxvdCBncmFwaCB3aXRoIHRoZSBGcnVjaHRlcm1hbi1SZWluZ29sZCBsYXlvdXQgYWxnb3JpdGhtCiMgQXMgYW4gZXhhbXBsZSwgcGxvdCBib3RoIHRoZSBvcmlnaW5hbCBhbmQgdGhlIGFubm90YXRlZCBncmFwaHMKIyBTYXZlIHRoZSBsYXlvdXQgZm9yIGVhc2llciBjb21wYXJpc29uCmdyYXBoX2xheW91dCA8LSBsYXlvdXRfd2l0aF9mcihyZXN1bHRzJG5ldGJveEdyYXBoKSAKCiMgcGxvdCB0aGUgb3JpZ2luYWwgZ3JhcGgKcGxvdChyZXN1bHRzJG5ldGJveENvbW11bml0eSxyZXN1bHRzJG5ldGJveEdyYXBoLCBsYXlvdXQ9Z3JhcGhfbGF5b3V0KSAKCiMgUGxvdCB0aGUgZWRnZSBhbm5vdGF0ZWQgZ3JhcGgKcGxvdChyZXN1bHRzJG5ldGJveENvbW11bml0eSwgbmV0Ym94R3JhcGhBbm5vdGF0ZWQsIGxheW91dCA9IGdyYXBoX2xheW91dCwKICAgICB2ZXJ0ZXguc2l6ZSA9IDEwLAogICAgIHZlcnRleC5zaGFwZSA9IFYobmV0Ym94R3JhcGhBbm5vdGF0ZWQpJHNoYXBlLAogICAgIGVkZ2UuY29sb3IgPSBFKG5ldGJveEdyYXBoQW5ub3RhdGVkKSRpbnRlcmFjdGlvbkNvbG9yLAogICAgIGVkZ2Uud2lkdGggPSAzKQoKIyBBZGQgaW50ZXJhY3Rpb24gdHlwZSBhbm5vdGF0aW9ucwpsZWdlbmQoImJvdHRvbWxlZnQiLCAKICAgICAgIGxlZ2VuZD1pbnRlcmFjdGlvblR5cGUsCiAgICAgICBjb2w9aW50ZXJhY3Rpb25UeXBlQ29sb3IsCiAgICAgICBsdHk9MSxsd2Q9MiwKICAgICAgIGJ0eT0ibiIsCiAgICAgICBjZXg9MSkKCgpgYGAKCiMjIENvbnNpc3RlbmN5IHdpdGggUHJldmlvdXNseSBQdWJsaXNoZWQgUmVzdWx0cyAKVGhlIEdCTSByZXN1bHQgYnkgbmV0Ym94ciBpZGVudGlmaWVkIGV4YWN0bHkgdGhlIHNhbWUgbGlua2VyIGdlbmVzICg2IGxpbmtlciBnZW5lcyksIHRoZSBzYW1lIG51bWJlciBvZiBtb2R1bGVzICgxMCBtb2R1bGVzKSBhbmQgdGhlIHNhbWUgZ2VuZXMgaW4gZWFjaCBpZGVudGlmaWVkIG1vZHVsZSBhcyBHQk0gcmVzdWx0IGluIENlcmFtaSBldCBhbC4gMjAxMC4gIAoKVGhlIHJlc3VsdHMgb2YgbmV0Ym94ciBhcmUgY29uc2lzdGVudCB3aXRoIHByZXZpb3VzIGltcGxlbWVudGF0aW9uIG9mIHRoZSBOZXRCb3ggYWxnb3JpdGhtLiBUaGUgUkIxIGFuZCBQSUszUjEgbW9kdWxlcyBhcmUgY2xlYXJseSByZXByZXNlbnRlZCBpbiB0aGUgZmlndXJlLiBGb3IgZXhhbXBsZSwgdGhlIFJCMSBtb2R1bGUgY29udGFpbnMgZ2VuZXMgaW4gYmx1ZSBjb2xvciBhbmQgZW5jbG9zZWQgYnkgbGlnaHQgb3JhbmdlIGNpcmNsZS4gVGhlIFBJSzNSMSBtb2R1bGUgY29udGFpbnMgZ2VuZXMgaW4gb3JhbmdlIGNvbG9yIGFuZCBlbmNsb3NlZCBieSBwaW5rIGNpcmNsZS4gCgojIFN0YXRpc3RpY2FsIFNpZ25pZmljYW5jZSBvZiBEaXNjb3ZlcmVkIE5ldHdvcmsgCgpOZXRCb3ggYWxnb3JpdGhtIHVzZWQgKDEpIGdsb2JhbCBuZXR3b3JrIG51bGwgbW9kZWwgYW5kICgyKSBsb2NhbCBuZXR3b3JrIG51bGwgbW9kZWwgdG8gYWNjZXNzIHRoZSBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2Ugb2YgdGhlIGRpc2NvdmVyZWQgbmV0d29yay4gCgojIyBHbG9iYWwgTmV0d29yayBOdWxsIE1vZGVsIApUaGUgZ2xvYmFsIG5ldHdvcmsgbnVsbCBtb2RlbCBjYWxjdWxhdGVzIHRoZSBlbXBpcmljYWwgcC12YWx1ZSBhcyB0aGUgbnVtYmVyIG9mIHRpbWVzIChvdmVyIGEgc2V0IG9mIGl0ZXJhdGlvbnMpIHRoZSBzaXplIG9mIHRoZSBsYXJnZXN0IGNvbm5lY3RlZCBjb21wb25lbnQgKHRoZSBnaWFudCBjb21wb25lbnQpIGluIHRoZSBuZXR3b3JrIGNvbWluZyBmcm9tIHRoZSBzYW1lIG51bWJlciBvZiByYW5kb21seSBzZWxlY3RlZCBnZW5lcyAobnVtYmVyIG9mIGdlbmVzIGlzIDI3NCBpbiB0aGlzIGV4YW1wbGUpIGVxdWFscyBvciBleGNlZWRzIHRoZSBzaXplIG9mIHRoZSBsYXJnZXN0IGNvbm5lY3RlZCBjb21wb25lbnQgaW4gdGhlIG9ic2VydmVkIG5ldHdvcmsuIFRoZSBzdWdnZXN0ZWQgaXRlcmF0aW9ucyBhcmUgMTAwMC4gIAoKYGBge3IgbmV0Ym94ckV4YW1wbGVHbG9iYWxUZXN0LCBldmFsPUZBTFNFfQojIyBUaGlzIGZ1bmN0aW9uIHdpbGwgbmVlZCBhIGxvdCBvZiB0aW1lIHRvIGNvbXBsZXRlLiAKZ2xvYmFsVGVzdCA8LSBnbG9iYWxOdWxsTW9kZWwobmV0Ym94R3JhcGg9cmVzdWx0cyRuZXRib3hHcmFwaCwgbmV0d29ya0dyYXBoPWdyYXBoUmVkdWNlZCwgaXRlcmF0aW9ucz0xMCwgbnVtT2ZHZW5lcyA9IDI3NCkKYGBgCgojIyBMb2NhbCBOZXR3b3JrIE51bGwgTW9kZWwKTG9jYWwgbmV0d29yayBudWxsIG1vZGVsIGV2YWx1YXRlcyB0aGUgZGV2aWF0aW9uIG9mIG1vZHVsYXJpdHkgaW4gdGhlIG9ic2VydmVkIG5ldHdvcmsgZnJvbSBtb2R1bGFyaXR5IGRpc3RyaWJ1dGlvbiBpbiB0aGUgcmFuZG9tIG5ldHdvcmsuIEZvciBlYWNoIGludGVyYWN0aW9uLCBhIHJhbmRvbSBuZXR3b3JrIGlzIHByb2R1Y2VkIGZyb20gbG9jYWwgcmUtd2lyaW5nIG9mIGxpdGVyYXR1cmUgY3VyYXRlZCBuZXR3b3JrLiBJdCBtZWFucyBhbGwgbm9kZXMgaW4gdGhlIG5ldHdvcmsga2VwdCB0aGUgc2FtZSBkZWdyZWUgb2YgY29ubmVjdGlvbnMgYnV0IGNvbm5lY3QgdG8gbmV3IG5laWdoYm9ycyByYW5kb21seS4gU3VnZ2VzdGVkIGl0ZXJhdGlvbnMgaXMgMTAwMC4KCgpgYGB7ciBuZXRib3hyRXhhbXBsZUxvY2FsVGVzdH0KbG9jYWxUZXN0IDwtIGxvY2FsTnVsbE1vZGVsKG5ldGJveEdyYXBoPXJlc3VsdHMkbmV0Ym94R3JhcGgsIGl0ZXJhdGlvbnM9MTAwMCkKCmBgYAoKVGhyb3VnaCAxMDAwIGl0ZXJhdGlvbnMsIHdlIGNhbiBvYnRhaW4gdGhlIG1lYW4gYW5kIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgbW9kdWxhcml0eSBpbiB0aGUgbG9jYWwgbmV0d29yayBudWxsIG1vZGVsLiBVc2luZyB0aGUgbWVhbiAgKH4wLjMpIGFuZCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uICgwLjA2KSwgd2UgY2FuIGNvdmVydCB0aGUgb2JzZXJ2ZWQgbW9kdWxhcml0eSBpbiB0aGUgbmV0d29yayAoMC41MTkpIGludG8gYSBaLXNjb3JlICh+My44KS4gRnJvbSB0aGUgWi1zY29yZSwgd2UgY2FuIGNhbGN1bGF0ZSBvbmUtdGFpbCBwLXZhbHVlLiBJZiBvbmUtdGFpbCBwdmFsdWUgaXMgbGVzcyB0aGFuIDAuMDUsIHRoZSBvYnNlcnZlZCBtb2R1bGFyaXR5IGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gcmFuZG9tLiBJbiB0aGUgaGlzdG9ncmFtLCB0aGUgYmx1ZSByZWdpb24gaXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBtb2R1bGFyaXR5IGluIHRoZSBsb2NhbCBuZXR3b3JrIG51bGwgbW9kZWwuIFRoZSByZWQgdmVydGljYWwgbGluZSBpcyB0aGUgb2JzZXJ2ZWQgbW9kdWxhcml0eSBpbiB0aGUgTmV0Qm94IHJlc3VsdHMuCgpgYGB7ciBuZXRib3hyRXhhbXBsZUxvY2FsVGVzdFBsb3R9Cmg8LWhpc3QobG9jYWxUZXN0JHJhbmRvbU1vZHVsYXJpdHlTY29yZSxicmVha3M9MzUscGxvdD1GQUxTRSkKaCRkZW5zaXR5ID0gaCRjb3VudHMvc3VtKGgkY291bnRzKQpwbG90KGgsZnJlcT1GQUxTRSx5bGltPWMoMCwwLjEpLHhsaW09YygwLjEsMC42KSwgY29sPSJsaWdodGJsdWUiKQphYmxpbmUodj1sb2NhbFRlc3QkbW9kdWxhcml0eVNjb3JlT2JzLGNvbD0icmVkIikKYGBgCgoqIFRoZSBnbG9iYWwgbnVsbCBtb2RlbCBpcyB1c2VkIHRvIGFzc2VzcyB0aGUgZ2xvYmFsIGNvbm5lY3Rpdml0eSAobnVtYmVyIG9mIG5vZGVzIGFuZCBlZGdlcykgb2YgdGhlIGxhcmdlc3QgbW9kdWxlIGluIHRoZSBpZGVudGlmaWVkIG5ldHdvcmsgY29tcGFyZWQgd2l0aCB0aGUgc2FtZSBudW1iZXIgYnV0IHJhbmRvbWx5IHNlbGVjdGVkIGdlbmUgbGlzdC4KCiogVGhlIGxvY2FsIG51bGwgbW9kZWwgaXMgdXNlZCB0byBhc3Nlc3MgdGhlIG5ldHdvcmsgbW9kdWxhcml0eSBpbiB0aGUgaWRlbnRpZmllZCBuZXR3b3JrIGNvbXBhcmVkIHdpdGggcmFuZG9tIHJlLXdpcmVkIG5ldHdvcmsuIAoKIyBWaWV3IE1vZHVsZSBNZW1iZXJzaGlwIAoKVGhlIHRhYmxlIGJlbG93IHNob3dzIHRoZSBtb2R1bGUgbWVtYmVyc2hpcHMgZm9yIGFsbCBnZW5lcy4gCgpgYGB7cn0KRFQ6OmRhdGF0YWJsZShyZXN1bHRzJG1vZHVsZU1lbWJlcnNoaXAsIHJvd25hbWVzID0gRkFMU0UpCmBgYAoKIyBXcml0ZSBOZXRCb3ggT3V0cHV0IHRvIEZpbGVzIAoKYGBge3IgbmV0Ym94ckVhbXBsZU91dHB1dCwgZXZhbD1GQUxTRX0KIyBXcml0ZSByZXN1bHRzIGZvciBmdXJ0aGVyIHZpc2lsYXp0aW9uIGluIHRoZSBjeXRvc2NhcGUgc29mdHdhcmUuIAojCiMgbmV0d29yay5zaWYgZmlsZSBpcyB0aGUgTmV0Qm94IGFsZ29yaXRobSBvdXRwdXQgaW4gU0lGIGZvcm1hdC4gIAp3cml0ZS50YWJsZShyZXN1bHRzJG5ldGJveE91dHB1dCwgZmlsZT0ibmV0d29yay5zaWYiLCBzZXA9Ilx0IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcz1GQUxTRSwgcm93Lm5hbWVzPUZBTFNFKQojCiMgbmV0aWdoYm9yTGlzdC50eHQgZmlsZSBjb250YWlucyB0aGUgaW5mb3JtYXRpb24gb2YgYWxsIG5laWdoYm9yIG5vZGVzLiAKd3JpdGUudGFibGUocmVzdWx0cyRuZWlnaGJvckRhdGEsIGZpbGU9Im5laWdoYm9yTGlzdC50eHQiLCBzZXA9Ilx0IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcz1UUlVFLCByb3cubmFtZXM9RkFMU0UpCiMKIyBjb21tdW5pdHkubWVtYmVyc2hpcC50eHQgZmlsZSBpbmRpY2F0ZXMgdGhlIGlkZW50aWZpZWQgcGF0aHdheSBtb2R1bGUgbnVtYmVycy4Kd3JpdGUudGFibGUocmVzdWx0cyRtb2R1bGVNZW1iZXJzaGlwLCBmaWxlPSJjb21tdW5pdHkubWVtYmVyc2hpcC50eHQiLCBzZXA9Ilx0IiwgcXVvdGU9RkFMU0UsIGNvbC5uYW1lcz1GQUxTRSwgcm93Lm5hbWVzPUZBTFNFKQojCiMgbm9kZVR5cGUudHh0IGZpbGUgaW5kaWNhdGVzIHRoZSBub2RlIGlzICJsaW5rZXIiIG5vZGUgb3IgImNhbmRpZGF0ZSIgbm9kZS4gCndyaXRlLnRhYmxlKHJlc3VsdHMkbm9kZVR5cGUsZmlsZT0ibm9kZVR5cGUudHh0Iiwgc2VwPSJcdCIsIHF1b3RlPUZBTFNFLCBjb2wubmFtZXM9RkFMU0UsIHJvdy5uYW1lcz1GQUxTRSkKYGBgCgojIFRlcm0gRW5yaWNobWVudCBpbiBNb2R1bGVzIHVzaW5nIEdlbmUgT250b2xvZ3kgKEdPKSBBbmFseXNpcyAKCkFmdGVyIG1vZHVsZSBpZGVudGlmaWNhdGlvbiwgb25lIG1haW4gdGFzayBpcyB1bmRlcnN0YW5kaW5nIHRoZSBiaW9sb2dpY2FsIHByb2Nlc3NlcyB0aGF0IG1heSBiZSByZXByZXNlbnRlZCBieSB0aGUgcmV0dXJuZWQgbW9kdWxlcy4gSGVyZSB3ZSB1c2UgdGhlIEJpb25jb2R1Y3RvciBjbHVzdGVyUHJvZmlsZXIgdG8gZG8gYW4gZW5yaWNobWVudCBhbmFseXNpcyB1c2luZyBHTyBCaW9sb2dpY2FsIFByb2Nlc3MgdGVybXMgb24gYSBzZWxlY3RlZCBtb2R1bGUuIAoKYGBge3IgY2x1c3RlckV4YW1wbGUsIGV2YWw9VFJVRX0KbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpCmxpYnJhcnkob3JnLkhzLmVnLmRiKQoKbW9kdWxlIDwtIDYKc2VsZWN0ZWRNb2R1bGUgPC0gcmVzdWx0cyRtb2R1bGVNZW1iZXJzaGlwW3Jlc3VsdHMkbW9kdWxlTWVtYmVyc2hpcCRtZW1iZXJzaGlwID09IG1vZHVsZSxdCmdlbmVMaXN0IDwtc2VsZWN0ZWRNb2R1bGUkZ2VuZVN5bWJvbAoKIyBDaGVjayBhdmFpbGFibGUgSUQgdHlwZXMgaW4gZm9yIHRoZSBvcmcuSHMuZWcuZGIgYW5ub3RhdGlvbiBwYWNrYWdlCmtleXR5cGVzKG9yZy5Icy5lZy5kYikKCmlkcyA8LSBiaXRyKGdlbmVMaXN0LCBmcm9tVHlwZT0iU1lNQk9MIiwgdG9UeXBlPWMoIkVOVFJFWklEIiksIE9yZ0RiPSJvcmcuSHMuZWcuZGIiKQpoZWFkKGlkcykKCmVnbyA8LSBlbnJpY2hHTyhnZW5lID0gaWRzJEVOVFJFWklELAogICAgICAgICAgICAgICAgT3JnRGIgPSBvcmcuSHMuZWcuZGIsCiAgICAgICAgICAgICAgICBvbnQgPSAiQlAiLAogICAgICAgICAgICAgICBwQWRqdXN0TWV0aG9kID0gIkJIIiwKICAgICAgICAgICAgICAgIHB2YWx1ZUN1dG9mZiAgPSAwLjAxLAogICAgICAgICAgICAgICBxdmFsdWVDdXRvZmYgID0gMC4wNSwKICAgICAgICAgICAgICAgcmVhZGFibGUgPSBUUlVFKQpgYGAKCiMjIEVucmljaG1lbnQgUmVzdWx0cyAKCmBgYHtyfQpoZWFkKGVnbykKYGBgCgojIyBWaXN1YWxpemUgRW5yaWNobWVudCBSZXN1bHRzCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NX0KZG90cGxvdChlZ28pCmBgYAoKIyBBbHRlcm5hdGl2ZSBNb2R1bGUgRGlzY292ZXJ5IE1ldGhvZHMgCkluIG5ldGJveHIsIHdlIHVzZWQgdGhlIEdpcnZhbi1OZXdtYW4gYWxnb3JpdGhtIChjb21tdW5pdHlNZXRob2Q9ImViYyIpIGFzIHRoZSBkZWZhdWx0IG1ldGhvZCB0byBkZXRlY3QgY29tbXVuaXR5IG1lbWJlcnNoaXAgaW4gdGhlIGlkZW50aWZpZWQgbmV0d29yay4gVGhlIEdpcnZhbi1OZXdtYW4gYWxnb3JpdGhtIGl0ZXJhdGF0aXZseSByZW1vdmVzIHRoZSBlZGdlIGluIHRoZSBuZXR3b3JrIHdpdGggaGlnaGVzdCBlZGdlIGJldHdlZW5lc3MgdW50aWwgbm8gZWRnZXMgbGVmdC4gV2hlbiB0aGUgaWRlbnRpZmllZCBuZXR3b3JrIGNvbnRhaW5zIG1hbnkgZWRnZXMsIHRoZSBHaXJ2YW4tTmV3bWFuIGFsZ29yaXRobSB3aWxsIHNwZW5kIGEgbGFyZ2UgYW1vdW50IG9mIHRpbWUgdG8gcmVtb3ZlIGVkZ2VzIGFuZCByZS1jYWx1Y2FsdGUgdGhlIGVkZ2UgYmV0d2VlbmVzZSBzY29yZSBpbiB0aGUgbmV0d29yay4gIElmICB0aGUgdXNlciBjYW5ub3QgZ2V0IHRoZSBjb21tdW5pdHkgZGV0ZWN0aW9uIHJlc3VsdCBpbiByZWFzb25hYmxlIHRpbWUsICB3ZSBzdWdnZXN0IHRvIHN3aXRjaCB0byBsZWFkaW5nIGVpZ2VudmVjdG9yIG1ldGhvZCAoY29tbXVuaXR5TWV0aG9kPSJsZWMiKSBmb3IgY29tbXVuaXR5IGRldGVjdGlvbi4gVXNlcnMgY2FuIGNoZWNrIG9yaWdpbmFsIHBhcGVycyBvZiBbdGhlIEdpcnZhbi1OZXdtYW4gYWxnb3JpdGhtXShodHRwOi8vd3d3LnBuYXMub3JnL2NvbnRlbnQvOTkvMTIvNzgyMSkgYW5kIFtsZWFkaW5nIGVpZ2VudmVjdG9yIG1ldGhvZF0oaHR0cHM6Ly9qb3VybmFscy5hcHMub3JnL3ByZS9hYnN0cmFjdC8xMC4xMTAzL1BoeXNSZXZFLjc0LjAzNjEwNCkgZm9yIG1vcmUgZGV0YWlscy4gIAoKIyBBbHRlcm5hdGl2ZSBQYXRod2F5IERhdGEgCiMjIFVzaW5nIFRhYnVsYXIgU2ltcGxlIEludGVyYWN0aW9uIEZvcm1hdCAoU0lGKS1CYXNlZCBOZXR3b3JrIERhdGEKVXNlcnMgY2FuIGxvYWQgYWx0ZXJuYXRpdmUgcGF0aHdheSBkYXRhIGZvcm1hdHRlZCBpbiB0aGUgU0lGIGZvcm1hdCAoU2ltcGxlIEludGVyYWN0aW9uIEZvcm1hdCkuIFNJRiBpcyBhIHNwYWNlL3RhYiBzZXBhcmF0ZWQgZm9ybWF0IHRoYXQgc3VtbWFyaXplcyBpbnRlcmFjdGlvbnMgaW4gYSBncmFwaCBhcyBhbiBlZGdlbGlzdC4gSW4gdGhlIGZvcm1hdCwgIGV2ZXJ5IHJvdyBjb3JyZXNwb25kcyB0byBhbiBpbmRpdmlkdWFsIGludGVyYWN0aW9uIChlZGdlKSBiZXR3ZWVuIGEgc291cmNlIGFuZCBhIHRhcmdldCBub2RlLiBOT1RFOiBBbiBhcmJpdHJhcnkgaW50ZXJhY3Rpb24gdHlwZSBjYW4gYmUgdXNlZCwgc3VjaCBhcyAiaW50ZXJhY3RzIiBpZiB0aGUgdHJ1ZSBpbnRlcmFjdGlvbiB0eXBlIGlzIHVua25vd24uCgpgYGAgClBBUlRJQ0lQQU5UX0EgSU5URVJBQ1RJT05fVFlQRSBQQVJUSUNJUEFOVF9CCm5vZGVBIHJlbGF0aW9uc2hpcCBub2RlQgpub2RlQyByZWxhdGlvbnNoaXAgbm9kZUEKbm9kZUQgcmVsYXRpb25zaGlwIG5vZGVFCmBgYAoKUmVzb3VyY2VzLCBzdWNoIGFzIHRoZSBGdW5jdGlvbmFsIEludGVyYWN0aW9uIG5ldHdvcmsgZnJvbSBSZWFjdG9tZSAoaHR0cHM6Ly9yZWFjdG9tZS5vcmcvZG93bmxvYWQtZGF0YSkgYW5kIFN0cmluZ0RCIChodHRwczovL3N0cmluZy1kYi5vcmcvKSBwcm92aWRlIG5ldHdvcmsgaW5mb3JtYXRpb24gaW4gZm9ybWF0cyByZXVzYWJsZSBhcyBhIFNJRi4gTk9URTogVGhlIG5leHQgc2VjdGlvbiBkZW1vbnN0cmF0ZXMgaG93IHRvIHJldHJpZXZlIFNJRi1iYXNlZCBuZXR3b3JrcyBmb3IgbWFueSB3ZWxsLWtub3duIGludGVyYWN0aW9uIGRhdGFiYXNlcyB1c2luZyBwYXh0b29sc3IuIAoKU0lGIGZvcm1hdHRlZCBkYXRhIGNhbiBiZSBwYXNzZWQgdG8gbmV0d29ya1NpbXBsaWZ5KCkuIFRoZSByZXN1bHQgb2Ygd2hpY2ggaXMgdXNlZCB3aXRoIHRoZSBnZW5lQ29ubmVjdG9yKCkgZnVuY3Rpb24gYXMgb3RoZXIgZXhhbXBsZXMgaW4gdGhpcyB2aWduZXR0ZSBkZW1vbnN0cmF0ZS4gCgpgYGB7cn0KZXhhbXBsZSA8LSAiUEFSVElDSVBBTlRfQQlJTlRFUkFDVElPTl9UWVBFCVBBUlRJQ0lQQU5UX0IKVFA1MwlpbnRlcmFjdHMJTURNMgpNRE0yCWludGVyYWN0cwlNRE00IgoKc2lmIDwtIHJlYWQudGFibGUodGV4dD1leGFtcGxlLCBoZWFkZXI9VFJVRSwgc2VwPSJcdCIsIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCgpncmFwaFJlZHVjZWQgPC0gbmV0d29ya1NpbXBsaWZ5KHNpZiwgZGlyZWN0ZWQgPSBGQUxTRSkgIApgYGAKCiMjIFVzaW5nIFBheHRvb2xzUiBmb3IgUGF0aHdheSBDb21tb25zIERhdGEKVXNlcnMgY2FuIGxvYWQgYWx0ZXJuYXRpdmUgcGF0aHdheSBkYXRhIGZyb20gdGhlIFtQYXRod2F5IENvbW1vbnNdKGh0dHA6Ly93d3cucGF0aHdheWNvbW1vbnMub3JnLykgcmVwb3NpdG9yeSB1c2luZyB0aGUgKipwYXh0b29sc3IqKiBwYWNrYWdlIGZyb20gW0Jpb2NvbmR1Y3Rvcl0oaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvYmlvYy9odG1sL3BheHRvb2xzci5odG1sKS4gVGhpcyBwYXRod2F5IGRhdGEgcmVwcmVzZW50cyBhbiB1cGRhdGUgdG8gdGhlIFBhdGh3YXkgQ29tbW9ucyBkYXRhIHVzZWQgaW4gdGhlIG9yaWdpbmFsIDIwMTAgTmV0Qm94IHB1YmxpY2F0aW9uLiBCZWxvdyBpcyBhbiBleGFtcGxlIHRoYXQgbWFrZXMgdXNlIG9mIGRhdGEgZnJvbSB0aGUgW1JlYWN0b21lIHBhdGh3YXkgZGF0YWJhc2VdKGh0dHA6Ly93d3cucmVhY3RvbWUub3JnLykuIAoKKipOT1RFOioqIERvd25sb2FkZWQgZGF0YSBpcyBhdXRvbWF0aWNhbGx5IGNhY2hlZCB0byBhdm9pZCB1bm5lY2Vzc2FyeSBkb3dubG9hZHMuIAoKYGBge3IgcGF4dG9vbHNyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9MTUsIGV2YWw9RkFMU0V9CmxpYnJhcnkocGF4dG9vbHNyKQoKZmlsZW5hbWUgPC0gIlBhdGh3YXlDb21tb25zLjgucmVhY3RvbWUuRVhURU5ERURfQklOQVJZX1NJRi5oZ25jLnR4dC5neiIKc2lmIDwtIGRvd25sb2FkUGMyKGZpbGVuYW1lLCB2ZXJzaW9uPSI4IikKCgojIEZpbHRlciBpbnRlcmFjdGlvbnMgZm9yIHNwZWNpZmljIHR5cGVzCmludGVyYWN0aW9uVHlwZXMgPC0gZ2V0U2lmSW50ZXJhY3Rpb25DYXRlZ29yaWVzKCkKCmZpbHRlcmVkU2lmIDwtIGZpbHRlclNpZihzaWYkZWRnZXMsIGludGVyYWN0aW9uVHlwZXM9aW50ZXJhY3Rpb25UeXBlc1tbIkJldHdlZW5Qcm90ZWlucyJdXSkKZmlsdGVyZWRTaWYgPC0gZmlsdGVyZWRTaWZbKGZpbHRlcmVkU2lmJElOVEVSQUNUSU9OX1RZUEUgJWluJSAiaW4tY29tcGxleC13aXRoIiksIF0KCiMgUmUtcnVuIE5ldEJveCBhbGdvcml0aG0gd2l0aCBuZXcgbmV0d29yawpncmFwaFJlZHVjZWQgPC0gbmV0d29ya1NpbXBsaWZ5KGZpbHRlcmVkU2lmLCBkaXJlY3RlZD1GQUxTRSkgICAgICAKZ2VuZUxpc3QgPC0gYXMuY2hhcmFjdGVyKG5ldGJveDIwMTAkZ2VuZUxpc3QpIAoKdGhyZXNob2xkIDwtIDAuMDUKcGNSZXN1bHRzIDwtIGdlbmVDb25uZWN0b3IoZ2VuZUxpc3Q9Z2VuZUxpc3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmV0d29ya0dyYXBoPWdyYXBoUmVkdWNlZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0ZWQ9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBWYWx1ZUFkaj0iQkgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBwVmFsdWVDdXRvZmY9dGhyZXNob2xkLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tdW5pdHlNZXRob2Q9ImxlYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXBJc29sYXRlZE5vZGVzPUZBTFNFKQoKIyBDaGVjayB0aGUgcC12YWx1ZSBvZiB0aGUgc2VsZWN0ZWQgbGlua2VyCmxpbmtlckRGIDwtIHJlc3VsdHMkbmVpZ2hib3JEYXRhCmxpbmtlckRGW2xpbmtlckRGJHBWYWx1ZUZEUjx0aHJlc2hvbGQsXQoKIyBUaGUgZ2VuZUNvbm5lY3RvciBmdW5jdGlvbiByZXR1cm5zIGEgbGlzdCBvZiBkYXRhIGZyYW1lcy4gCm5hbWVzKHJlc3VsdHMpCgojIHBsb3QgZ3JhcGggd2l0aCB0aGUgRnJ1Y2h0ZXJtYW4tUmVpbmdvbGQgbGF5b3V0IGFsZ29yaXRobQpwbG90KHJlc3VsdHMkbmV0Ym94Q29tbXVuaXR5LHJlc3VsdHMkbmV0Ym94R3JhcGgsIGxheW91dD1sYXlvdXRfd2l0aF9mcikgCmBgYAoKIyBTZWxlY3RpbmcgSW5wdXQgR2VuZSBMaXN0cyBmb3IgdXNlIHdpdGggTmV0Qm94CgpUaGUgbWFpbiBpbnB1dCBmb3IgdGhlIE5ldEJveCBhbGdvcml0aG0gaXMgYW4gaW5wdXQgbGlzdCBvZiAic2lnbmlmaWNhbnRseSIgYWx0ZXJlZCBnZW5lcy4gRWFjaCBwcm9qZWN0IGlzIGRpZmZlcmVudCwgdW5pcXVlIGNvbnNpZGVyYXRpb25zIGZvciBob3cgc2lnbmlmaWNhbmNlIHNob3VsZCBiZSBjb25zaWRlcmVkIG1heSBiZSByZXF1aXJlZC4gUmVzZWFyY2hlcnMgbWF5IHNlZWsgc3Ryb25nZXIgdGhyZXNob2xkcyBvZiBzaWduaWZpY2FuY2UgZm9yIHBhcnRpY3VsYXIgcXVlc3Rpb25zIGFuZCBkaWZmZXJlbnQgcHJvZmlsaW5nIHRlY2hub2xvZ2llcyBtYXkgaGF2ZSB0aGVpciBvd24gY29uc2lkZXJhdGlvbnMuIEl0IGlzIGJleW9uZCB0aGUgc2NvcGUgb2YgdGhpcyB3b3JrIHRvIHByb3ZpZGUgZ3VpZGFuY2UgZm9yIGFsbCBzaXR1YXRpb25zLiAKCkhvd2V2ZXIsIHRvIGhlbHAgdXNlcnMgYmV0dGVyIHVuZGVyc3RhbmQgdGhlIHByb2Nlc3Mgb2YgZ2VuZXJhdGluZyBhbiBpbnB1dCBnZW5lIGxpc3Qgd2UgcHJvdmlkZSBleGFtcGxlcyB1c2luZyBiZXN0IHByYWN0aWNlcyBkZXJpdmVkIGZyb20gdGhlIFRoZSBDYW5jZXIgR2Vub21lIFByb2plY3QgdXNpbmcgdGhlIGNCaW9Qb3J0YWwgKGh0dHA6Ly9jYmlvcG9ydGFsLm9yZy8pLCBhIHBsYXRmb3JtIHRoYXQgYWdncmVnYXRlcyBjbGluaWNhbCBnZW5vbWljcyBkYXRhc2V0cyBpbnRvIGEgc3RhbmRhcmQgcmVwcmVzZW50YXRpb24uIEFzIG9mIEF1Z3VzdCAyMDIwLCBjQmlvUG9ydGFsIGhhcyBhcHByb3hpbWF0ZWx5IDI5MCBzdHVkaWVzLiBJbiBjYXNlcyB3aGVyZSBhcHByb3ByaWF0ZSBkYXRhIGlzIGF2YWlsYWJsZSBhIHNpbWlsYXIgcHJvY2VkdXJlIHRvIHRoZSBleGFtcGxlIGNhbiBiZSB1c2VkLiAKCiMjIEFjY2VzaW5nIFByZS1Db21wdXRlZCBBbHRlcmF0aW9uIFJlc3VsdHMgZnJvbSB0aGUgY0Jpb1BvcnRhbCBEYXRhSHViIAoKRm9yIFRDR0Egc3R1ZGllcyBvbiBjQmlvUG9ydGFsLCB1c2VycyBjYW4gYWNjZXNzIHByZS1wcm9jZXNzZWQgZGF0YXNldHMgZnJvbSB0aGUgW2NCaW9Qb3J0YWwgRGF0YUh1Yl0oaHR0cHM6Ly9naXRodWIuY29tL2NCaW9Qb3J0YWwvZGF0YWh1Yi90cmVlL21hc3Rlci9wdWJsaWMpIHRoYXQgY29udGFpbiBzaWduaWZpY2FudGx5IGFsdGVyZWQgZ2VuZXMgYnkgbXV0YXRpb25zIGFuZCBjb3B5IG51bWJlci4gRXhhbXBsZSBzdHVkeSBsaW5rOiBodHRwczovL2dpdGh1Yi5jb20vY0Jpb1BvcnRhbC9kYXRhaHViL3RyZWUvbWFzdGVyL3B1YmxpYy9hY2NfdGNnYQoKKiBTaWduaWZpY2FudGx5IGFsdGVyZWQgZ2VuZXMgYnkgbXV0YXRpb25zICh2aWEgTXV0U2lnIGFsZ29yaXRobSkgYXJlIGFjY2Vzc2libGUgd2l0aGluIHRoZSAnZGF0YV9tdXRzaWcudHh0JyBmaWxlIGZvciBhIHN0dWR5OyB0eXBpY2FsbHkgbXV0YXRpb25zIHdpdGggYSBxLXZhbHVlIDwgMC4xIGFyZSBzZWxlY3RlZCBhcyBzaWduaWZpY2FudGx5IGFsdGVyZWQKKiBTaWduaWZpY2FudGx5IGFsdGVyZWQgZ2VuZXMgYnkgY29weSBudW1iZXIgKHZpYSBHSVNUSUMgYWxnb3JpdGhtKSBhcmUgYWNjZXNzaWJsZSB3aXRoaW4gdGhlICdkYXRhX2dpc3RpY19nZW5lc19kZWwudHh0JyAoZGVsZXRpb25zKSBmaWxlIGFuZCAnZGF0YV9naXN0aWNfZ2VuZXNfYW1wLnR4dCcgKGFtcGxpZmljYXRpb25zKS4gCgpVc2VycyBhcmUgZGlyZWN0ZWQgdG8gdGhlIGFjY29tcGFueWluZyBzdHVkeSBwdWJsaWNhdGlvbnM7IHN0dWR5IHB1YmxpY2F0aW9uIGRldGFpbHMgYXJlIGluIHRoZSAnbWV0YV9zdHVkeS50eHQnIGZpbGUgZm9yIGEgc3R1ZHkuCgojIyBBY2Nlc3NpbmcgQ2FuY2VyIEdlbm9taWNzIERhdGEgZnJvbSBjQmlvUG9ydGFsCgpVc2VycyBjYW4gZG93bmxvYWQgY2FuY2VyIGFsdGVyYXRpb24gZGF0YSBmcm9tIFtjQmlvUG9ydGFsXShodHRwczovL3d3dy5jYmlvcG9ydGFsLm9yZy8pIHVzaW5nIHRoZSAqKmNnZHNyKiogcGFja2FnZSBmcm9tIFtDUkFOXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvY2dkc3IvaW5kZXguaHRtbCkuIEhlcmUgd2Ugc2hvdyBob3cgYSBzaW1wbGUgZXhhbXBsZSBmb3Igc2VsZWN0aW5nIGdlbmVzIGZvciB1c2Ugd2l0aCBuZXRib3hyIGZvciBkYXRhc2V0cyBwcm92aWRlZCBieSBjQmlvUG9ydGFsIHVzaW5nIGEgdXNpbmcgYSAxMCUgYWx0ZXJhdGlvbiBmcmVxdWVuY3kgdGhyZXNob2xkIHRvIHNlbGVjdCBnZW5lczsgdGhpcyBnZW5lcmFsIHByb2NlZHVyZSBoYXMgcHJldmlvdXNseSBiZWVuIHVzZWQgYXMgcGFydCBvZiBbVENHQSBzdHVkaWVzXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3BtYy9hcnRpY2xlcy9QTUMzOTEwNTAwLykuIEluIHRoZSBleGFtcGxlLCB3ZSBjb25zaWRlcjogCgoqIEZvciBtdXRhdGlvbnMsIG11dGF0aW9ucyBvZiBhbnkgdHlwZSBjb250cmlidXRlIHRvIHRoZSBvdmVyYWxsIGFsdGVyYXRpb24gZnJlcXVlbmN5IG9mIHRoZSBnZW5lCiogRm9yIGNvcHkgbnVtYmVyLCBkaXNjcmV0aXplZCBHSVNUSUMtZGVyaXZlZCB2YWx1ZXMgZm9yIGFtcGxpZmljYXRpb24gb3IgZGVlcCBkZWxldGlvbnMgY29udHJpYnV0ZSB0byB0aGUgb3ZlcmFsbCBhbHRlcmF0aW9uIGZyZXF1ZW5jeQoKVGhlIHJlc3VsdGluZyBnZW5lIGxpc3QgdGhlbiBiZWNvbWVzIGFuIGlucHV0IGZvciBuZXRib3hyLiBUaGUgcmVzdWx0aW5nIGdlbmUgbGlzdCB3aWxsIHNlbGVjdCBFR0ZSIGFuZCBUUDUzLCB3aGljaCBoYXZlIGhpZ2ggYWx0ZXJhdGlvbiBmcmVxdWVuY2llcyBpbiBnbGlvYmxhc3RvbWEgKEdCTSkgb3ZlciB0aGUgaG91c2VrZWVwaW5nIGdlbmVzIEFDVEIgYW5kIEdBUERILCB3aGljaCBoYXZlIHZlcnkgbG93IGFsdGVyYXRpb24gZnJlcXVlbmNpZXMuCgpgYGB7ciwgZXZhbD1GQUxTRX0KbGlicmFyeShjZ2RzcikKCm15Y2dkcyA8LSBDR0RTKCJodHRwOi8vd3d3LmNiaW9wb3J0YWwub3JnLyIpCgojIEZpbmQgYXZhaWxhYmxlIHN0dWRpZXMsIGNhc2VsaXN0cywgYW5kIGdlbmV0aWNQcm9maWxlcyAKc3R1ZGllcyA8LSBnZXRDYW5jZXJTdHVkaWVzKG15Y2dkcykKY2FzZWxpc3RzIDwtIGdldENhc2VMaXN0cyhteWNnZHMsJ2dibV90Y2dhX3B1YicpCmdlbmV0aWNQcm9maWxlcyA8LSBnZXRHZW5ldGljUHJvZmlsZXMobXljZ2RzLCdnYm1fdGNnYV9wdWInKQoKZ2VuZXMgPC0gYygiRUdGUiIsICJUUDUzIiwgIkFDVEIiLCAiR0FQREgiKQoKcmVzdWx0cyA8LSBzYXBwbHkoZ2VuZXMsIGZ1bmN0aW9uKGdlbmUpIHsKICBnZW5ldGljUHJvZmlsZXMgPC0gYygiZ2JtX3RjZ2FfcHViX2NuYV9jb25zZW5zdXMiLCAiZ2JtX3RjZ2FfcHViX211dGF0aW9ucyIpCiAgY2FzZUxpc3QgPC0gImdibV90Y2dhX3B1Yl9jbmFzZXEiCiAgCiAgZGF0IDwtIGdldFByb2ZpbGVEYXRhKG15Y2dkcywgZ2VuZXM9Z2VuZSwgZ2VuZXRpY1Byb2ZpbGVzPWdlbmV0aWNQcm9maWxlcywgY2FzZUxpc3Q9Y2FzZUxpc3QpCiAgaGVhZChkYXQpCiAgCiAgY25hIDwtIGRhdCRnYm1fdGNnYV9wdWJfY25hX2NvbnNlbnN1cwogIGNuYSA8LSBhcy5udW1lcmljKGxldmVscyhjbmEpKVtjbmFdCiAgCiAgbXV0IDwtIGRhdCRnYm1fdGNnYV9wdWJfbXV0YXRpb25zCiAgbXV0IDwtIGFzLmNoYXJhY3RlcihsZXZlbHMobXV0KSlbbXV0XQogIAogIHRtcCA8LSBkYXRhLmZyYW1lKGNuYT1jbmEsIG11dD1tdXQsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKICB0bXAkaXNBbHRlcmVkIDwtIGFicyh0bXAkY25hKSA9PSAyIHwgIWlzLm5hKHRtcCRtdXQpICMgQW1wbGlmaWNhdGlvbiBvciBEZWVwIERlbGV0aW9uIG9yIGFueSBtdXRhdGlvbgogIGxlbmd0aCh3aGljaCh0bXAkaXNBbHRlcmVkKSkvbnJvdyh0bXApCn0sIFVTRS5OQU1FUyA9IFRSVUUpCgojIDEwIHBlcmNlbnQgYWx0ZXJhdGlvbiBmcmVxdWVuY3kgY3V0b2ZmIApnZW5lTGlzdCA8LSBuYW1lcyhyZXN1bHRzKVtyZXN1bHRzID4gMC4xXQpgYGAKCiMgUmVmZXJlbmNlcwoKKiBDZXJhbWkgRSwgRGVtaXIgRSwgU2NodWx0eiBOLCBUYXlsb3IgQlMsIFNhbmRlciBDICgyMDEwKSBBdXRvbWF0ZWQgTmV0d29yayBBbmFseXNpcyBJZGVudGlmaWVzIENvcmUgUGF0aHdheXMgaW4gR2xpb2JsYXN0b21hLiBQTG9TIE9ORSA1KDIpOiBlODkxOC4gZG9pOjEwLjEzNzEvam91cm5hbC5wb25lLjAwMDg5MTgKKiBDZXJhbWkgRUcsIEdyb3NzIEJFLCBEZW1pciBFLCBSb2RjaGVua292IEksIEJhYnVyIE8sIEFud2FyIE4sIFNjaHVsdHogTiwgQmFkZXIgR0QsIFNhbmRlciBDLiBQYXRod2F5IENvbW1vbnMsIGEgd2ViIHJlc291cmNlIGZvciBiaW9sb2dpY2FsIHBhdGh3YXkgZGF0YS4gTnVjbGVpYyBBY2lkcyBSZXMuIDIwMTEgSmFuOzM5KERhdGFiYXNlIGlzc3VlKTpENjg1LTkwLiBkb2k6MTAuMTA5My9uYXIvZ2txMTAzOS4gRXB1YiAyMDEwIE5vdiAxMC4KCiMgU2Vzc2lvbiBJbmZvcm1hdGlvbgoKYGBge3Igc2Vzc2lvbkluZm99CnNlc3Npb25JbmZvKCkKYGBgCg==