This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.
Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.
Complete analysis of WT T. brucei Chromium scRNA-seq
#install.packages(‘Seurat’) v3.2.2.999 #BiocManager::install(“scran”) v1.14.6 #BiocManager::install(“scater”) v1.14.6 #BiocManager::install(“MAST”) #BiocManager::install(“slingshot”) v1.4.0 #BiocManager::install(“tradeSeq”) 1.3.21 #BiocManager::install(“clusterExperiment”) v2.6.1 #BiocManager::install(“ggpubr”) v0.4.0 #BiocManager::install(“clustree”) v0.4.3 #install.packages(“phateR”) #BiocManager::install(“ComplexHeatmap”) v2.2.0 #remotes::install_github(“carmonalab/STACAS”) v1.0.1 #install.packages(“bigmemory”) v4.5.36
library(slingshot)
Loading required package: princurve
library(slingshot)
library(tradeSeq)
library(clusterExperiment)
Attaching package: ‘clusterExperiment’
The following object is masked from ‘package:scater’:
plotHeatmap
library(ComplexHeatmap)
Loading required package: grid
========================================
ComplexHeatmap version 2.2.0
Bioconductor page: http://bioconductor.org/packages/ComplexHeatmap/
Github page: https://github.com/jokergoo/ComplexHeatmap
Documentation: http://jokergoo.github.io/ComplexHeatmap-reference
If you use it in published research, please cite:
Gu, Z. Complex heatmaps reveal patterns and correlations in multidimensional
genomic data. Bioinformatics 2016.
========================================
library(ComplexHeatmap)
library(ggpubr)
library(dplyr)
Attaching package: ‘dplyr’
The following object is masked from ‘package:MAST’:
combine
The following object is masked from ‘package:matrixStats’:
count
The following object is masked from ‘package:Biobase’:
combine
The following objects are masked from ‘package:GenomicRanges’:
intersect, setdiff, union
The following object is masked from ‘package:GenomeInfoDb’:
intersect
The following objects are masked from ‘package:IRanges’:
collapse, desc, intersect, setdiff, slice, union
The following objects are masked from ‘package:S4Vectors’:
first, intersect, rename, setdiff, setequal, union
The following objects are masked from ‘package:BiocGenerics’:
combine, intersect, setdiff, union
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
library(STACAS)
library(STACAS)
library(gridExtra)
Attaching package: ‘gridExtra’
The following object is masked from ‘package:dplyr’:
combine
The following object is masked from ‘package:MAST’:
combine
The following object is masked from ‘package:Biobase’:
combine
The following object is masked from ‘package:BiocGenerics’:
combine
Load in WT integrated replicates already normalised and var genes found and ZC3H20 KO filtered data
# ZC3H20 KO count data and create seurat object
ZC3H20_KO_counts_data <- read.csv("PATH/ZC3H20_KO_counts_data.csv", row.names=1)
ZC3H20 <- CreateSeuratObject(ZC3H20_KO_counts_data, project = "ZC3H20_KO")
# WT replicate data is provided as an seurat object or can be generated with script "WT_differentiation_scRNA-seq"
load("PATH/WT_integrated_seurat_object")
# Load is VSGs provided
VSG_list <- read.table("PATH/VSG_list", quote="\"", comment.char="")
## Normalise data with SCRAN
# Export to a SingleCellExperiment object
sce_ZC3H20 <- as.SingleCellExperiment(ZC3H20)
# Pre-cluster cells. Factors are first generated within clusters then rescaled to normalize between clusters
qclust <- scran::quickCluster(sce_ZC3H20, min.size = 30)
# Compute size factors - removes low abundance genes
sce_ZC3H20 <- scran::computeSumFactors(sce_ZC3H20, clusters = qclust)
sce_ZC3H20 <- scater::logNormCounts(sce_ZC3H20)
## Convert back to Seurat object
ZC3H20 <- as.Seurat(sce_ZC3H20, counts = "counts", data = "logcounts")
## Detect variable genes and remove VSG
VSGs <-as.character(VSG_list$V1)
# find variable genes with scran
dec <- modelGeneVar(sce_ZC3H20)
top.hvgs2 <- getTopHVGs(dec, n=3000)
#write.csv(top.hvgs2, file = "scran_HVGs")
## variable genes with seurat
ZC3H20.features <- FindVariableFeatures(ZC3H20, selection.method = "vst", nfeatures = 3000, assay = "RNA")
top3000 <- head(VariableFeatures(ZC3H20.features), 3000)
#write.csv(top3000, file = "seurat_HVGs")
## find those in common
common_var_genes <- intersect(top.hvgs2, top3000)
## remove the VSGs
var_genes <- subset(common_var_genes, ! common_var_genes %in% VSGs)
# Add to object
ZC3H20@assays[["RNA"]]@var.features <- var_genes
#write.csv(var_genes, file = "Common_variable_genes_ZC3H20")
#save(ZC3H20, file = "ZC3H20_seurat_norm")
Integrate the ZC3H20 KO data and WT data with STACAS
ref.integrated <- IntegrateData(anchorset=ref.anchors.filtered, dims=1:8, features.to.integrate=all.genes, sample.tree = mySampleTree)
Merging dataset 2 into 1
Extracting anchors for merged samples
Finding integration vectors
Finding integration vector weights
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Integrating data
Adding a command log without an assay associated with it
rr ref.integrated <- FindClusters(ref.integrated, resolution = 0.4)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
Number of nodes: 10894
Number of edges: 547702
Running Louvain algorithm...
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8576
Number of communities: 6
Elapsed time: 2 seconds
rr ref.integrated <- FindClusters(ref.integrated, resolution = 0.4)
Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
Number of nodes: 10894
Number of edges: 547702
Running Louvain algorithm...
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Maximum modularity in 10 random starts: 0.8576
Number of communities: 6
Elapsed time: 2 seconds
rr # Run UMAP with same number of dims as for FindNeighbors ref.integrated <- RunUMAP(ref.integrated, reduction = , dims = 1:7, min.dist = 0.01)
14:48:17 UMAP embedding parameters a = 1.896 b = 0.8006
14:48:17 Read 10894 rows and found 7 numeric columns
14:48:17 Using Annoy for neighbor search, n_neighbors = 30
14:48:17 Building Annoy index with metric = cosine, n_trees = 50
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
14:48:18 Writing NN index file to temp file /var/folders/rd/tjq29jm572b7j_j3fg5k_s340000gn/T//RtmpyjyWIo/file14b54b378a0b
14:48:18 Searching Annoy index using 1 thread, search_k = 3000
14:48:22 Annoy recall = 100%
14:48:23 Commencing smooth kNN distance calibration using 1 thread
14:48:26 Initializing from normalized Laplacian + noise
14:48:26 Commencing optimization for 200 epochs, with 423126 positive edges
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
14:48:32 Optimization finished
rr # Run UMAP with same number of dims as for FindNeighbors ref.integrated <- RunUMAP(ref.integrated, reduction = , dims = 1:7, min.dist = 0.01)
14:48:32 UMAP embedding parameters a = 1.896 b = 0.8006
14:48:32 Read 10894 rows and found 7 numeric columns
14:48:32 Using Annoy for neighbor search, n_neighbors = 30
14:48:32 Building Annoy index with metric = cosine, n_trees = 50
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
14:48:34 Writing NN index file to temp file /var/folders/rd/tjq29jm572b7j_j3fg5k_s340000gn/T//RtmpyjyWIo/file14b52b47fec1
14:48:34 Searching Annoy index using 1 thread, search_k = 3000
14:48:37 Annoy recall = 100%
14:48:38 Commencing smooth kNN distance calibration using 1 thread
14:48:40 Initializing from normalized Laplacian + noise
14:48:40 Commencing optimization for 200 epochs, with 423126 positive edges
0% 10 20 30 40 50 60 70 80 90 100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
14:48:47 Optimization finished
rr p <- DimPlot(ref.integrated, label = FALSE) p[[1]]\(layers[[1]]\)aes_params\(alpha = 0.3 p[[1]]\)layers[[1]]\(aes_params\)shape = 16 #pdf(file = _WT_KO_intergation_cluster.pdf, width = 3, height = 3) p + NoLegend() + UMAP_theme

rr
save(ref.integrated, file = _WT_integrated_seurat_scaleall)








rr
Markers between clusters
DefaultAssay(ref.integrated) <-
WT_ZC3H20.markers <- FindAllMarkers(ref.integrated, only.pos = TRUE, min.pct = 0.25, logfc.threshold = 0.25, test.use = ) #write.csv(WT_ZC3H20.markers, file = _ZC3H20_integrated_markers.csv)







rr # Get the lineage, selecting the same starting cluster if any lin <- getLineages(SlingshotDataSet(sce), clusterLabels = clusters, start.clus = A.1)
Using full covariance matrix
rr #pdf(file = 3_mutant_smooth.pdf, width = 1.5, height = 1.5) plotSmoothers(sce_GAM_line, counts, gene = —Tb927.7.970, lwd = 0.3, size = 1/10, pointCol = , plotLineages = FALSE) + labs(title = 3) + scale_color_manual(values =c(#f8766d, #f8766d, #00bfc4)) + NoLegend() + geom_line(data = smooth_data_WT, aes(x = smooth_data_WT\(time, y = smooth_data_WT\)Tbrucei---Tb927.7.970)) + geom_line(data = smooth_data_ZC3H20, aes(x = smooth_data_ZC3H20\(time, y = smooth_data_ZC3H20\)Tbrucei---Tb927.7.970), color=#00bfc4) + theme(plot.title = element_text(size = 9, face = ), axis.text.x = element_text(size = 8), axis.title.x = element_text(size = 8), axis.title.y = element_text(size = 8), axis.text.y = element_text(size = 8))
Scale for 'colour' is already present. Adding another scale for 'colour',
which will replace the existing scale.



PrctCellExpringGene <- function(object, genes, group.by = "all"){
if(group.by == "all"){
prct = unlist(lapply(genes,calc_helper, object=object))
result = data.frame(Markers = genes, Cell_proportion = prct)
return(result)
}
else{
list = SplitObject(object, group.by)
factors = names(list)
results = lapply(list, PrctCellExpringGene, genes=genes)
for(i in 1:length(factors)){
results[[i]]$Feature = factors[i]
}
combined = do.call("rbind", results)
return(combined)
}
}
calc_helper <- function(object,genes){
counts = object[['RNA']]@counts
ncells = ncol(counts)
if(genes %in% row.names(counts)){
sum(counts[genes,]>0)/ncells
}else{return(NA)}
}


Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.
When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).
The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.
LS0tCnRpdGxlOiAiWkMzSDIwIG51bGwgbXV0YW50IGFuYWx5c2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiAKClRyeSBleGVjdXRpbmcgdGhpcyBjaHVuayBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgcGxhY2luZyB5b3VyIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICpDbWQrU2hpZnQrRW50ZXIqLiAKCiMjIyBDb21wbGV0ZSBhbmFseXNpcyBvZiBXVCBULiBicnVjZWkgQ2hyb21pdW0gc2NSTkEtc2VxICMjIwoKCiNpbnN0YWxsLnBhY2thZ2VzKCdTZXVyYXQnKSB2My4yLjIuOTk5CiNCaW9jTWFuYWdlcjo6aW5zdGFsbCgic2NyYW4iKSB2MS4xNC42CiNCaW9jTWFuYWdlcjo6aW5zdGFsbCgic2NhdGVyIikgdjEuMTQuNgojQmlvY01hbmFnZXI6Omluc3RhbGwoIk1BU1QiKQojQmlvY01hbmFnZXI6Omluc3RhbGwoInNsaW5nc2hvdCIpIHYxLjQuMAojQmlvY01hbmFnZXI6Omluc3RhbGwoInRyYWRlU2VxIikgMS4zLjIxCiNCaW9jTWFuYWdlcjo6aW5zdGFsbCgiY2x1c3RlckV4cGVyaW1lbnQiKSB2Mi42LjEKI0Jpb2NNYW5hZ2VyOjppbnN0YWxsKCJnZ3B1YnIiKSB2MC40LjAKI0Jpb2NNYW5hZ2VyOjppbnN0YWxsKCJjbHVzdHJlZSIpIHYwLjQuMwojaW5zdGFsbC5wYWNrYWdlcygicGhhdGVSIikKI0Jpb2NNYW5hZ2VyOjppbnN0YWxsKCJDb21wbGV4SGVhdG1hcCIpIHYyLjIuMAojcmVtb3Rlczo6aW5zdGFsbF9naXRodWIoImNhcm1vbmFsYWIvU1RBQ0FTIikgdjEuMC4xCiNpbnN0YWxsLnBhY2thZ2VzKCJiaWdtZW1vcnkiKSB2NC41LjM2CgpgYGB7cn0KI0xvYWQgcGFja2FnZXMKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoTUFTVCkKbGlicmFyeShzY2F0ZXIpCmxpYnJhcnkoc2NyYW4pCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoc2xpbmdzaG90KQpsaWJyYXJ5KHRyYWRlU2VxKQpsaWJyYXJ5KGNsdXN0ZXJFeHBlcmltZW50KQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShkcGx5cikKbGlicmFyeShTVEFDQVMpCmxpYnJhcnkoZ3JpZEV4dHJhKQpgYGAKIyMgTG9hZCBpbiBXVCBpbnRlZ3JhdGVkIHJlcGxpY2F0ZXMgYWxyZWFkeSBub3JtYWxpc2VkIGFuZCB2YXIgZ2VuZXMgZm91bmQgYW5kIFpDM0gyMCBLTyBmaWx0ZXJlZCBkYXRhCmBgYHtyfQoKIyBaQzNIMjAgS08gY291bnQgZGF0YSBhbmQgY3JlYXRlIHNldXJhdCBvYmplY3QKWkMzSDIwX0tPX2NvdW50c19kYXRhIDwtIHJlYWQuY3N2KCJQQVRIL1pDM0gyMF9LT19jb3VudHNfZGF0YS5jc3YiLCByb3cubmFtZXM9MSkKClpDM0gyMCA8LSBDcmVhdGVTZXVyYXRPYmplY3QoWkMzSDIwX0tPX2NvdW50c19kYXRhLCBwcm9qZWN0ID0gIlpDM0gyMF9LTyIpCgojIFdUIHJlcGxpY2F0ZSBkYXRhIGlzIHByb3ZpZGVkIGFzIGFuIHNldXJhdCBvYmplY3Qgb3IgY2FuIGJlIGdlbmVyYXRlZCB3aXRoIHNjcmlwdCAiV1RfZGlmZmVyZW50aWF0aW9uX3NjUk5BLXNlcSIKCmxvYWQoIlBBVEgvV1RfaW50ZWdyYXRlZF9zZXVyYXRfb2JqZWN0IikKCiMgTG9hZCBpcyBWU0dzIHByb3ZpZGVkClZTR19saXN0IDwtIHJlYWQudGFibGUoIlBBVEgvVlNHX2xpc3QiLCBxdW90ZT0iXCIiLCBjb21tZW50LmNoYXI9IiIpCgpgYGAKCmBgYHtyfQojIyBOb3JtYWxpc2UgZGF0YSB3aXRoIFNDUkFOCgojIEV4cG9ydCB0byBhIFNpbmdsZUNlbGxFeHBlcmltZW50IG9iamVjdCAKCnNjZV9aQzNIMjAgPC0gYXMuU2luZ2xlQ2VsbEV4cGVyaW1lbnQoWkMzSDIwKQoKIyBQcmUtY2x1c3RlciBjZWxscy4gRmFjdG9ycyBhcmUgZmlyc3QgZ2VuZXJhdGVkIHdpdGhpbiBjbHVzdGVycyB0aGVuIHJlc2NhbGVkIHRvIG5vcm1hbGl6ZSBiZXR3ZWVuIGNsdXN0ZXJzCnFjbHVzdCA8LSBzY3Jhbjo6cXVpY2tDbHVzdGVyKHNjZV9aQzNIMjAsIG1pbi5zaXplID0gMzApCgojIENvbXB1dGUgc2l6ZSBmYWN0b3JzIC0gcmVtb3ZlcyBsb3cgYWJ1bmRhbmNlIGdlbmVzCnNjZV9aQzNIMjAgPC0gc2NyYW46OmNvbXB1dGVTdW1GYWN0b3JzKHNjZV9aQzNIMjAsIGNsdXN0ZXJzID0gcWNsdXN0KQpzY2VfWkMzSDIwIDwtIHNjYXRlcjo6bG9nTm9ybUNvdW50cyhzY2VfWkMzSDIwKQoKIyMgQ29udmVydCBiYWNrIHRvIFNldXJhdCBvYmplY3QgClpDM0gyMCA8LSBhcy5TZXVyYXQoc2NlX1pDM0gyMCwgY291bnRzID0gImNvdW50cyIsIGRhdGEgPSAibG9nY291bnRzIikKCiMjIERldGVjdCB2YXJpYWJsZSBnZW5lcyBhbmQgcmVtb3ZlIFZTRwpWU0dzIDwtYXMuY2hhcmFjdGVyKFZTR19saXN0JFYxKQoKIyBmaW5kIHZhcmlhYmxlIGdlbmVzIHdpdGggc2NyYW4KCmRlYyA8LSBtb2RlbEdlbmVWYXIoc2NlX1pDM0gyMCkKdG9wLmh2Z3MyIDwtIGdldFRvcEhWR3MoZGVjLCBuPTMwMDApCiN3cml0ZS5jc3YodG9wLmh2Z3MyLCBmaWxlID0gInNjcmFuX0hWR3MiKQoKIyMgdmFyaWFibGUgZ2VuZXMgd2l0aCBzZXVyYXQKClpDM0gyMC5mZWF0dXJlcyA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhaQzNIMjAsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMzAwMCwgYXNzYXkgPSAiUk5BIikgCgp0b3AzMDAwIDwtIGhlYWQoVmFyaWFibGVGZWF0dXJlcyhaQzNIMjAuZmVhdHVyZXMpLCAzMDAwKQojd3JpdGUuY3N2KHRvcDMwMDAsIGZpbGUgPSAic2V1cmF0X0hWR3MiKQoKIyMgZmluZCB0aG9zZSBpbiBjb21tb24KCmNvbW1vbl92YXJfZ2VuZXMgPC0gaW50ZXJzZWN0KHRvcC5odmdzMiwgdG9wMzAwMCkKCiMjIHJlbW92ZSB0aGUgVlNHcwp2YXJfZ2VuZXMgPC0gc3Vic2V0KGNvbW1vbl92YXJfZ2VuZXMsICEgY29tbW9uX3Zhcl9nZW5lcyAlaW4lIFZTR3MpCgojIEFkZCB0byBvYmplY3QgCgpaQzNIMjBAYXNzYXlzW1siUk5BIl1dQHZhci5mZWF0dXJlcyA8LSB2YXJfZ2VuZXMKI3dyaXRlLmNzdih2YXJfZ2VuZXMsIGZpbGUgPSAiQ29tbW9uX3ZhcmlhYmxlX2dlbmVzX1pDM0gyMCIpCiNzYXZlKFpDM0gyMCwgZmlsZSA9ICJaQzNIMjBfc2V1cmF0X25vcm0iKQpgYGAKCiMgSW50ZWdyYXRlIHRoZSBaQzNIMjAgS08gZGF0YSBhbmQgV1QgZGF0YSB3aXRoIFNUQUNBUwpgYGB7cn0KCiMjIFNUQUNBUyBpbnRlZ3JhdGlvbgpEZWZhdWx0QXNzYXkoV1QuaW50ZWdyYXRlZCkgPC0gImludGVncmF0ZWQiCmxpc3QgPC0gbGlzdChXVC5pbnRlZ3JhdGVkLCBaQzNIMjApCgp0cnlwLmZlYXR1cmVzIDwtIFNlbGVjdEludGVncmF0aW9uRmVhdHVyZXMob2JqZWN0Lmxpc3QgPSBsaXN0KQoKcmVmLmFuY2hvcnMgPC0gRmluZEFuY2hvcnMuU1RBQ0FTKGxpc3QsIGRpbXM9MTo4LCBhbmNob3IuZmVhdHVyZXM9dHJ5cC5mZWF0dXJlcykKCnJlZi5hbmNob3JzLmZpbHRlcmVkIDwtIEZpbHRlckFuY2hvcnMuU1RBQ0FTKHJlZi5hbmNob3JzKQoKYWxsLmdlbmVzIDwtIHJvdy5uYW1lcyhsaXN0W1sxXV0pCmZvciAoaSBpbiAyOmxlbmd0aChsaXN0KSkgewogIGFsbC5nZW5lcyA8LSBpbnRlcnNlY3QoYWxsLmdlbmVzLCByb3cubmFtZXMobGlzdFtbaV1dKSkKfQoKbXlTYW1wbGVUcmVlIDwtIFNhbXBsZVRyZWUuU1RBQ0FTKHJlZi5hbmNob3JzLmZpbHRlcmVkKQoKcmVmLmludGVncmF0ZWQgPC0gSW50ZWdyYXRlRGF0YShhbmNob3JzZXQ9cmVmLmFuY2hvcnMuZmlsdGVyZWQsIGRpbXM9MTo4LCBmZWF0dXJlcy50by5pbnRlZ3JhdGU9YWxsLmdlbmVzLCBzYW1wbGUudHJlZSA9IG15U2FtcGxlVHJlZSkKCgojIyBTY2FsZSBkYXRhIGFuZCByZWdyZXNzIFJOQSBjb3VudApyZWYuaW50ZWdyYXRlZCA8LSBTY2FsZURhdGEocmVmLmludGVncmF0ZWQsIHZlcmJvc2UgPSBUUlVFLCB2YXJzLnRvLnJlZ3Jlc3MgPSAibkNvdW50X1JOQSIsIGZlYXR1cmVzID0gYWxsLmdlbmVzKQoKIyBSdW4gUENBIHVzaW5nIHZhcmlibGUgZ2VuZXMgCnJlZi5pbnRlZ3JhdGVkIDwtIFJ1blBDQShyZWYuaW50ZWdyYXRlZCwgdmVyYm9zZSA9IEZBTFNFKQoKYGBgCgpgYGB7cn0KCkRlZmF1bHRBc3NheShyZWYuaW50ZWdyYXRlZCkgPC0gImludGVncmF0ZWQiCgpyZWYuaW50ZWdyYXRlZCA8LSBGaW5kTmVpZ2hib3JzKHJlZi5pbnRlZ3JhdGVkLCBkaW1zID0gMTo4LCBrLnBhcmFtID0gMzAsIG5uLm1ldGhvZCA9ICJhbm5veSIsIGFubm95Lm1ldHJpYyA9ICJldWNsaWRlYW4iLCBhc3NheSA9ICJpbnRlZ3JhdGVkIikKCnJlZi5pbnRlZ3JhdGVkIDwtIEZpbmRDbHVzdGVycyhyZWYuaW50ZWdyYXRlZCwgcmVzb2x1dGlvbiA9IDAuNCkKIyBSdW4gVU1BUCB3aXRoIHNhbWUgbnVtYmVyIG9mIGRpbXMgYXMgZm9yIEZpbmROZWlnaGJvcnMKcmVmLmludGVncmF0ZWQgPC0gUnVuVU1BUChyZWYuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjcsIG1pbi5kaXN0ID0gMC4wMSkKCnAgPC0gRGltUGxvdChyZWYuaW50ZWdyYXRlZCwgbGFiZWwgPSBGQUxTRSkgCnBbWzFdXSRsYXllcnNbWzFdXSRhZXNfcGFyYW1zJGFscGhhID0gMC4zCnBbWzFdXSRsYXllcnNbWzFdXSRhZXNfcGFyYW1zJHNoYXBlID0gMTYKI3BkZihmaWxlID0gIlVNQVBfV1RfS09faW50ZXJnYXRpb25fY2x1c3Rlci5wZGYiLCB3aWR0aCA9IDMsIGhlaWdodCA9IDMpCnAgKyBOb0xlZ2VuZCgpICsgVU1BUF90aGVtZQojZGV2Lm9mZigpCgpgYGAKCmBgYHtyfQoKc2F2ZShyZWYuaW50ZWdyYXRlZCwgZmlsZSA9ICJtdXRhbnRfV1RfaW50ZWdyYXRlZF9zZXVyYXRfc2NhbGVhbGwiKQpgYGAKCmBgYHtyfQoKIyMgQWRkIGxpbmUgaW5mb3JtYXRpb24Kc2FtcGxlIDwtIHJlZi5pbnRlZ3JhdGVkQG1ldGEuZGF0YVtbIm9yaWcuaWRlbnQiXV0Kc2FtcGxlW3NhbXBsZSA9PSAiV1RfMDEiXSA8LSAgIldUIgpzYW1wbGVbc2FtcGxlID09ICJXVF8wMiJdIDwtICAiV1QiCnJlZi5pbnRlZ3JhdGVkIDwtIEFkZE1ldGFEYXRhKHJlZi5pbnRlZ3JhdGVkLCBtZXRhZGF0YSA9IHNhbXBsZSwgY29sLm5hbWUgPSAibGluZSIpCgojIEdlbmVyYXRlIHBsb3RzCgpwIDwtIERpbVBsb3QocmVmLmludGVncmF0ZWQsIGdyb3VwLmJ5ID0gImxpbmUiLCBsYWJlbCA9IEZBTFNFLCBsYWJlbC5zaXplID0gNSkKcFtbMV1dJGxheWVyc1tbMV1dJGFlc19wYXJhbXMkYWxwaGEgPSAwLjMKcFtbMV1dJGxheWVyc1tbMV1dJGFlc19wYXJhbXMkc2hhcGUgPSAxNgpwZGYoZmlsZSA9ICJVTUFQX1dUX1pDM0gyMC5pbnRlZ3JhdGVkX2xpbmUucGRmIiwgd2lkdGggPSAzLCBoZWlnaHQgPSAzKQpwICsgVU1BUF90aGVtZSArIE5vTGVnZW5kKCkKZGV2Lm9mZigpCmBgYAoKYGBge3J9CgpwIDwtIERpbVBsb3QocmVmLmludGVncmF0ZWQsIGdyb3VwLmJ5ID0gInNldXJhdF9jbHVzdGVycyIsIGxhYmVsID0gRkFMU0UsIGxhYmVsLnNpemUgPSA1KQpwW1sxXV0kbGF5ZXJzW1sxXV0kYWVzX3BhcmFtcyRhbHBoYSA9IDAuMwpwW1sxXV0kbGF5ZXJzW1sxXV0kYWVzX3BhcmFtcyRzaGFwZSA9IDE2CnAgKyBVTUFQX3RoZW1lCgpgYGAKYGBge3J9CiMjIFBsb3Qga25vd24gbWFya2VycwoKcCA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSByZWYuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAiVGJydWNlaS0tLVRiOTI3LjYuNDI4MCIsIG1pbi5jdXRvZmYgPSAwLCBtYXguY3V0b2ZmID0gNCkKcFtbMV1dJGxheWVyc1tbMV1dJGFlc19wYXJhbXMkYWxwaGEgPSAwLjUKcFtbMV1dJGxheWVyc1tbMV1dJGFlc19wYXJhbXMkc2hhcGUgPSAxNgojcGRmKGZpbGUgPSAiVU1BUF9XVF9LT19HQVBIRC5wZGYiLCB3aWR0aCA9IDEuOCwgaGVpZ2h0ID0gMikKcCArIGxhYnModGl0bGUgPSAiR0FQREgiLCBjb2xvciA9ICJFeHByZXNzaW9uIikgKyBOb0xlZ2VuZCgpICsgVU1BUF90aGVtZQojZGV2Lm9mZigpCmBgYApgYGB7cn0KcCA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSByZWYuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAiVGJydWNlaS0tLVRiOTI3LjEwLjE0MTQwIiwgbWluLmN1dG9mZiA9IDAsIG1heC5jdXRvZmYgPSA0KQpwW1sxXV0kbGF5ZXJzW1sxXV0kYWVzX3BhcmFtcyRhbHBoYSA9IDAuNQpwW1sxXV0kbGF5ZXJzW1sxXV0kYWVzX3BhcmFtcyRzaGFwZSA9IDE2CiNwZGYoZmlsZSA9ICJVTUFQX1dUX0tPX1BZSzEucGRmIiwgd2lkdGggPSAxLjgsIGhlaWdodCA9IDIpCnAgKyBsYWJzKHRpdGxlID0gIlBZSzEiLCBjb2xvciA9ICJFeHByZXNzaW9uIikgKyBOb0xlZ2VuZCgpICsgVU1BUF90aGVtZQojZGV2Lm9mZigpCmBgYApgYGB7cn0KcCA8LSBGZWF0dXJlUGxvdChvYmplY3QgPSByZWYuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAiVGJydWNlaS0tLVRiOTI3LjcuNTk0MCIsIG1pbi5jdXRvZmYgPSAwLCBtYXguY3V0b2ZmID0gNCkKcFtbMV1dJGxheWVyc1tbMV1dJGFlc19wYXJhbXMkYWxwaGEgPSAwLjUKcFtbMV1dJGxheWVyc1tbMV1dJGFlc19wYXJhbXMkc2hhcGUgPSAxNgojcGRmKGZpbGUgPSAiVU1BUF9XVF9LT19QQUQyLnBkZiIsIHdpZHRoID0gMS44LCBoZWlnaHQgPSAyKQpwICsgbGFicyh0aXRsZSA9ICJQQUQyIiwgY29sb3IgPSAiRXhwcmVzc2lvbiIpICsgTm9MZWdlbmQoKSArIFVNQVBfdGhlbWUKI2Rldi5vZmYoKQpgYGAKYGBge3J9CnAgPC0gRmVhdHVyZVBsb3Qob2JqZWN0ID0gcmVmLmludGVncmF0ZWQsIGZlYXR1cmVzID0gIlRicnVjZWktLS1UYjkyNy4xMC4xMDI2MCIsIG1pbi5jdXRvZmYgPSAwLCBtYXguY3V0b2ZmID0gNCkgKyBsYWJzKHRpdGxlID0gIkVQMSIsIGNvbG9yID0gIkV4cHJlc3Npb24iKQpwW1sxXV0kbGF5ZXJzW1sxXV0kYWVzX3BhcmFtcyRhbHBoYSA9IDAuNQpwW1sxXV0kbGF5ZXJzW1sxXV0kYWVzX3BhcmFtcyRzaGFwZSA9IDE2CiNwZGYoZmlsZSA9ICJVTUFQX1dUX0tPX0VQMS5wZGYiLCB3aWR0aCA9IDEuOCwgaGVpZ2h0ID0gMikKcCArIE5vTGVnZW5kKCkgKyBVTUFQX3RoZW1lCiNkZXYub2ZmKCkKYGBgCgpgYGB7cn0KIyBOYW1lIGNsdXN0ZXJzCgpuZXcuY2x1c3Rlci5pZHMgPC0gYygiTFMgQi4xIiwgIlNTIEIiLCJTUyBBIiwgIkxTIEEuMiIsICJMUyBCLjIiLCAiTFMgQS4xIikKCm5hbWVzKG5ldy5jbHVzdGVyLmlkcykgPC0gbGV2ZWxzKHJlZi5pbnRlZ3JhdGVkKQpyZWYuaW50ZWdyYXRlZCA8LSBSZW5hbWVJZGVudHMocmVmLmludGVncmF0ZWQsIG5ldy5jbHVzdGVyLmlkcykKbGV2ZWxzKHJlZi5pbnRlZ3JhdGVkKSA8LSBjKCJMUyBBLjEiLCAiTFMgQS4yIiwgIkxTIEIuMSIsICJMUyBCLjIiLCJTUyBBIiwgIlNTIEIiKQoKcCA8LSBEaW1QbG90KHJlZi5pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJpZGVudCIpCnBbWzFdXSRsYXllcnNbWzFdXSRhZXNfcGFyYW1zJGFscGhhID0gMC41CnBbWzFdXSRsYXllcnNbWzFdXSRhZXNfcGFyYW1zJHNoYXBlID0gMTYKI3BkZihmaWxlID0gIlVNQVBfaW50ZXJnYXRpb25fdHJ5cC5pbnRlZ3JhdGVkX1pDM0gyMF9jbHVzdGVyLnBkZiIsIHdpZHRoID0gNC42LCBoZWlnaHQgPSAzLjUpCnAgKyBVTUFQX3RoZW1lCiNkZXYub2ZmKCkKYGBgCgoKYGBge3J9CiMjIEZpbmQgY2x1c3RlciBwcm9wb3J0aW9ucwoKY2VsbF9wcm9wb3J0aW9ucyA8LSBhcy5kYXRhLmZyYW1lKHByb3AudGFibGUodGFibGUoSWRlbnRzKHJlZi5pbnRlZ3JhdGVkKSwgcmVmLmludGVncmF0ZWQkbGluZSksIG1hcmdpbiA9IDIpKQojd3JpdGUuY3N2KGNlbGxfcHJvcG9ydGlvbnMsIGZpbGUgPSAiY2VsbF9wcm9wb3J0aW9uc19tdXRhbnRfaW50ZWdyYXRpb24uY3N2IikKI3BkZihmaWxlID0gIldUX2NlbGxfcHJvcG9ydGlvbnMucGRmIiwgd2lkdGggPSAyLjUsIGhlaWdodCA9IDIuNSkKZ2dwbG90KGRhdGE9Y2VsbF9wcm9wb3J0aW9ucywgYWVzKHg9Y2VsbF9wcm9wb3J0aW9ucyRWYXIyLCB5PWNlbGxfcHJvcG9ydGlvbnMkRnJlcSwgZmlsbD1jZWxsX3Byb3BvcnRpb25zJFZhcjEpKSArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgY29sb3I9ImJsYWNrIikgKyBsYWJzKHg9InNhbXBsZSIsIHk9IlByb3BvcnRpb24gb2YgQ2VsbHMiLCBmaWxsPSJDbHVzdGVyIikKI2Rldi5vZmYoKQpgYGAKCmBgYHtyfQoKIyMgTWFya2VycyBiZXR3ZWVuIGNsdXN0ZXJzCkRlZmF1bHRBc3NheShyZWYuaW50ZWdyYXRlZCkgPC0gIlJOQSIKV1RfWkMzSDIwLm1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMocmVmLmludGVncmF0ZWQsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUsIHRlc3QudXNlID0gIk1BU1QiKQojd3JpdGUuY3N2KFdUX1pDM0gyMC5tYXJrZXJzLCBmaWxlID0gIldUX1pDM0gyMF9pbnRlZ3JhdGVkX21hcmtlcnMuY3N2IikKYGBgCgpgYGB7cn0KdG9wMTAgPC0gV1RfWkMzSDIwLm1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuID0gMTAsIHd0ID0gYXZnX2xvZ0ZDKQpEZWZhdWx0QXNzYXkocmVmLmludGVncmF0ZWQpIDwtICJpbnRlZ3JhdGVkIgojcGRmKGZpbGUgPSAiSGVhdG1hcF9XVF9aQzNIMjBfdG9wXzEwX21hcmtlcnNfUk5BLnBkZiIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNikKRG9IZWF0bWFwKHJlZi5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IHRvcDEwJGdlbmUsIGxhYmVsID0gRkFMU0UpCiNkZXYub2ZmKCkKYGBgCgpgYGB7cn0KIyMgdmlvbGluIHBsb3RzCgpEZWZhdWx0QXNzYXkocmVmLmludGVncmF0ZWQpIDwtICJSTkEiCiNwZGYoZmlsZSA9ICJMU0IyX21hcmtlcl92bG5QbG90cy5wZGYiLCBoZWlnaHQgPSAzLCB3aWR0aCA9IDEyKQpWbG5QbG90KHJlZi5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IGMoIlRicnVjZWktLS1UYjkyNy43LjY4NjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRicnVjZWktLS1UYjkyNy4xMS4xMTU2MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGJydWNlaS0tLVRiMi5OVC44IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUYnJ1Y2VpLS0tVGI5MjcuMTAuMTA0MCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGJydWNlaS0tLVRiOTI3LjQuNzEwIiksIHB0LnNpemUgPSAwLCBuY29sID0gNSkgCiNkZXYub2ZmKCkKYGBgCgpgYGB7cn0KCiMjIFBIQVRFIGFuZCB0cmFqZWN0b3J5IGFuYWx5c2lzCmZlYXR1cmVzIDwtIHJlZi5pbnRlZ3JhdGVkQGFzc2F5c1tbImludGVncmF0ZWQiXV1AdmFyLmZlYXR1cmVzCmRhdGEgPC0gcmVmLmludGVncmF0ZWRAYXNzYXlzW1siaW50ZWdyYXRlZCJdXUBkYXRhCmRhdGFfc3Vic2V0IDwtIHQoZGF0YVtmZWF0dXJlcywgXSkKcGhhdGVfb3V0cHV0IDwtIHBoYXRlKGRhdGFfc3Vic2V0KQpwaGF0ZV9vdXRwdXQgPC0gYXMubWF0cml4KHBoYXRlX291dHB1dCkKY29sbmFtZXMoeCA9IHBoYXRlX291dHB1dCkgPC0gcGFzdGUwKCJQSEFURV8iLCAxOm5jb2woeCA9IHBoYXRlX291dHB1dCkpCgpwaGF0ZS5yZWR1Y3Rpb24gPC0gQ3JlYXRlRGltUmVkdWNPYmplY3QoCiAgZW1iZWRkaW5ncyA9IHBoYXRlX291dHB1dCwKICBrZXkgPSAiUEhBVEVfIiwKICBhc3NheSA9ICJpbnRlZ3JhdGVkIikKCnJlZi5pbnRlZ3JhdGVkQHJlZHVjdGlvbnMkcGhhdGUgPC0gcGhhdGUucmVkdWN0aW9uCgojcGRmKGZpbGUgPSAiUEhBVEVfcmVmX2ludGVyZ2F0aW9uX2xpbmUucGRmIiwgd2lkdGggPSAzLCBoZWlnaHQgPSAzKQpEaW1QbG90KHJlZi5pbnRlZ3JhdGVkLCBncm91cC5ieSA9ICJsaW5lIiwgcmVkdWN0aW9uID0gInBoYXRlIikgKyBOb0xlZ2VuZCgpICsgUEhBVEVfdGhlbWUgKyB5bGltKDAuMDE1LCAtMC4wMTUpICsgeGxpbSgtMC4wMjUsIDAuMDMzKQojZGV2Lm9mZigpCmBgYAoKCgpgYGB7cn0KIyMgY29udmVydCB0byBzY2UgYW5kIGluZmVyIHRyYWplY3RvcnkKCmxpYnJhcnkoc2xpbmdzaG90KQoKc2NlIDwtIGFzLlNpbmdsZUNlbGxFeHBlcmltZW50KHJlZi5pbnRlZ3JhdGVkLCBhc3NheSA9ICJpbnRlZ3JhdGVkIikKCnNjZSA8LSBzbGluZ3Nob3Qoc2NlLCByZWR1Y2VkRGltID0gJ1BIQVRFJywgY2x1c3RlckxhYmVscyA9IHNjZUBjb2xEYXRhQGxpc3REYXRhW1siaWRlbnQiXV0sIHN0YXJ0LmNsdXMgPSAiTFMgQS4xIikKI3NhdmUoc2NlLCBmaWxlID0gInNjZV9pbnRfbXV0YW50X1dUX3NsaW5nc2hvdCIpCgojIFBsb3QgYnkgaWRlbnQKbXljb2xvdXJzIDwtIGMoIiNmODc2NmQiLCAiIzAxYmZjNCIpCnNjZSRsaW5lIDwtIGFzLmZhY3RvcihzY2UkbGluZSkKCiNwZGYoZmlsZSA9ICJyZWZfaW50ZXJnYXRpb25faWRlbnRfUEhBVEUucGRmIiwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDQuNSkKcGxvdChyZWR1Y2VkRGltcyhzY2UpJFBIQVRFLCBjb2wgPSBteWNvbG91cnNbc2NlJGxpbmVdLCBwY2ggPSAxNiwgY2V4ID0gMC41LCBidHk9J2wnLCB5bGltID0gcmV2KGMoLTAuMDE1LCAwLjAxNSkpLCAgYXhlcyA9IEZBTFNFLCBhbm4gPSBGQUxTRSwgeGF4dD0nbicsIHlheHQ9J24nKQpsaW5lcyhTbGluZ3Nob3REYXRhU2V0KHNjZSksIGNvbCA9ICJibGFjayIsIGx3ZCA9IDIpCiNkZXYub2ZmKCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKCmBgYAoKYGBge3J9CiMgUGxvdCBieSBwc2V1ZG90aW1lCgpjb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDExLCdZbE9yUmQnKVstNl0pKDEwMCkKcGxvdGNvbCA8LSBjb2xvcnNbY3V0KHNjZSRzbGluZ1BzZXVkb3RpbWVfMSwgYnJlYWtzPTEwMCldCiNwZGYoZmlsZSA9ICJyZWZfaW50ZXJnYXRpb25fcHNldWRvMV9QSEFURV9UcmFqLnBkZiIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNikKcGxvdChyZWR1Y2VkRGltcyhzY2UpJFBIQVRFLCBjb2wgPSBwbG90Y29sLCBwY2ggPSAxNiwgY2V4ID0gMC41LCBidHk9J2wnLCB5bGltID0gcmV2KGMoLTAuMDE1LCAwLjAxNSkpLCBheGVzID0gRkFMU0UsIGFubiA9IEZBTFNFLCB4YXh0PSduJywgeWF4dD0nbicpCmxpbmVzKFNsaW5nc2hvdERhdGFTZXQoc2NlKSwgY29sID0gImJsYWNrIiwgbHdkID0gMikKI2Rldi5vZmYoKSAKYGBgCgpgYGB7cn0KY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMSwnWWxHbkJ1JylbLTZdKSgxMDApCnBsb3Rjb2wgPC0gY29sb3JzW2N1dChzY2Ukc2xpbmdQc2V1ZG90aW1lXzIsIGJyZWFrcz0xMDApXQojcGRmKGZpbGUgPSAicmVmX2ludGVyZ2F0aW9uX3BzZXVkbzJfUEhBVEVfVHJhai5wZGYiLCB3aWR0aCA9IDYsIGhlaWdodCA9IDYpCnBsb3QocmVkdWNlZERpbXMoc2NlKSRQSEFURSwgY29sID0gcGxvdGNvbCwgcGNoID0gMTYsIGNleCA9IDAuNSwgYnR5PSdsJywgeWxpbSA9IHJldihjKC0wLjAxNSwgMC4wMTUpKSwgYXhlcyA9IEZBTFNFLCBhbm4gPSBGQUxTRSwgeGF4dD0nbicsIHlheHQ9J24nKQpsaW5lcyhTbGluZ3Nob3REYXRhU2V0KHNjZSksIGNvbCA9ICJibGFjayIsIGx3ZCA9IDIpCiNkZXYub2ZmKCkKYGBgCgpgYGB7cn0KIyMgQ29sb3VyIGNlbGxzIGJ5IGdlbmUKY29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMSwnQmx1ZXMnKVstNl0pKDEwMCkKZ2VuZV9sb2djb3VudHMgPC0gc2NlQGFzc2F5c0BkYXRhQGxpc3REYXRhW1sibG9nY291bnRzIl1dCnBsb3Rjb2wgPC0gY29sb3JzW2N1dChnZW5lX2xvZ2NvdW50c1siVGJydWNlaS0tLVRiOTI3LjExLjY4NzAiLCBdLCBicmVha3M9MTAwKV0KI3BkZihmaWxlID0gInJlZl9pbnRlcmdhdGlvbl9QSEFURV9QWUsxLnBkZiIsIHdpZHRoID0gNC41LCBoZWlnaHQgPSA0LjUpCnBsb3QocmVkdWNlZERpbXMoc2NlKSRQSEFURSwgY29sID0gcGxvdGNvbCwgcGNoID0gMTYsIGNleCA9IDAuNSwgYnR5PSdsJywgeWxpbSA9IHJldihjKC0wLjAxNSwgMC4wMTUpKSkKI2Rldi5vZmYoKSAKYGBgCgpgYGB7cn0KIyMgRGlmZmVyZW50aWFsIGV4cHJlc3Npb24gd2l0aCB0cmFkZXNlcQoKbGlicmFyeSh0cmFkZVNlcSkKbGlicmFyeShtZ2N2KQpsaWJyYXJ5KGNsdXN0ZXJFeHBlcmltZW50KQpsaWJyYXJ5KGNvd3Bsb3QpCgojIFlvdSBjYW4gc2V0IHRoaXMgY29udHJvbCB0byB0cnkgYW5kIHByZXZlbnQgb3ZlcmZpdHRpbmcgdGhlIGRhdGEKY29udHJvbCA8LSBnYW0uY29udHJvbCgpCmNvbnRyb2wkbWF4aXQgPC0gMTAwMAoKIyBHZXQgdGhlIGNvdW50cyBkYXRhIGZvciB0aGUgZ2VuZXMgeW91IHdhbnQgdG8gdXNlIChoZXJlLCB0b3AgMjAwMCkKIyBHZXQgYWxsIGNvdW50cwpjb3VudHMgPC0gYXMubWF0cml4KHJlZi5pbnRlZ3JhdGVkQGFzc2F5c1tbIlJOQSJdXUBjb3VudHMpCgojYWxsX2dlbmVzIDwtIHJvd25hbWVzKHJlZi5pbnRlZ3JhdGVkKQoKI3Ntb290aGVyc19hbGwgPC0gcHJlZGljdFNtb290aChzY2VfR0FNX2xpbmUsIGdlbmUgPSBhbGxfZ2VuZXMsIHRpZHkgPSBUUlVFKQoKIyMgRml0IGEgZ2VuZXJsaXNlZCBhZGRpdGl2ZSBtb2RlbCB1c2luZyB0aGUgbGluYWdlIGN1cnZlcyBpZGVudGlmaWVkIGJ5IHNsaW5nc2hvdAojIEdldCBjbHVzdGVyIGlkcwpjbHVzdGVycyA8LSBzY2VAY29sRGF0YUBsaXN0RGF0YVtbImlkZW50Il1dCgojIEdldCB0aGUgbGluZWFnZSwgc2VsZWN0aW5nIHRoZSBzYW1lIHN0YXJ0aW5nIGNsdXN0ZXIgaWYgYW55CmxpbiA8LSBnZXRMaW5lYWdlcyhTbGluZ3Nob3REYXRhU2V0KHNjZSksIGNsdXN0ZXJMYWJlbHMgPSBjbHVzdGVycywgc3RhcnQuY2x1cyA9ICJMUyBBLjEiKQojIEdldCB0aGUgY3VydmVzCmNydiA8LSBnZXRDdXJ2ZXMobGluKQoKIyBEZXRlcm1pbmUgdGhlIGFwcHJvcHJpYXRlIG51bWJlciBvZiBrbm90cyAocmVhZCBvbiB0cmFkZS1zZXEgcGFnZSBob3cgdG8gc2VsZWN0IGJlc3QgbnVtYmVyIG9mIGtub3RzIChwb2ludHMgb24gdHJhamVjdG9yeSkpCgojIFRlc3QgMyB0byAxNSBrbm90cwppY01hdCA8LSBldmFsdWF0ZUsoY291bnRzID0gY291bnRzLCBzZHMgPSBjcnYsIGs9MzoxNSwgbkdlbmVzID0gMjAwLAogICAgICAgICAgICAgICAgICAgdmVyYm9zZT1GQUxTRSkKCiMgZml0IHRoZSBHQU0gdG8gdGhlIGRhdGEgKEkgc2VsZWN0ZWQgOSBrbm90cykuIFRoaXMgdGFrZXMgYSBiaXQgb2YgdGltZS4gCnNjZV9HQU1fbGluZSA8LSBmaXRHQU0oY291bnRzID0gY291bnRzLCBzZHMgPSBjcnYsIG5rbm90cyA9IDksIGNvbnRyb2wgPSBjb250cm9sLCBjb25kaXRpb25zID1hcy5mYWN0b3Ioc2NlJGxpbmUpKQoKICAyIyBzYXZlIHRoZSBzaW5nbGUgY2VsbCB3aXRoIEdBTSAKc2F2ZShzY2VfR0FNX2xpbmUsIGZpbGUgPSAic2NlX0dBTV9XVF9aQzNIMjBfcGVybGluZV9hbGxfZ2VuZXMyIikKCiMgVGVzdCBnZW5lIGV4cHJlc3Npb24gYXNzb2NpYXRpb24gd2l0aCB0cmFqZWN0b3JpZXMsIHNldHRpbmcgbGluZWFnZXMgdG8gdHJ1ZSB3aWxsIHRlc3QgZWFjaCBsaW5lYWdlIHNlcGVyYXRsZWx5CmFzc29SZXNfbGluZSA8LSBhc3NvY2lhdGlvblRlc3Qoc2NlX0dBTV9saW5lLCBsaW5lYWdlID0gVFJVRSkKCgpoZWFkKGFzc29SZXMpCndyaXRlLmNzdihhc3NvUmVzX2xpbmUsIGZpbGUgPSAiYXNzb1Jlc19saW5lX1dUX1pDM0gyMCIpCmBgYAoKYGBge3J9CgojIyBQbG90IGluZGl2aWR1YWwgZ2VuZSBleHByZXNzaW9uIChmdWxsIG9mIGJ1Z3MgdG8gaGFkIHRvIG1ha2UgYSB3b3JrIGFyb3VuZCkKCnNtb290aCA8LSBwcmVkaWN0U21vb3RoKHNjZV9HQU1fbGluZSwgZ2VuZSA9ICJUYnJ1Y2VpLS0tVGI5MjcuNy45NzAiKQpzbW9vdGhfZGF0YV9XVCA8LSBzdWJzZXQoc21vb3RoLCBjb25kaXRpb24gPT0gIldUIikKc21vb3RoX2RhdGFfV1QgPC0gc3Vic2V0KHNtb290aF9kYXRhX1dULCBsaW5lYWdlID09ICIxIikKc21vb3RoX2RhdGFfV1QgPC0gcGl2b3Rfd2lkZXIoc21vb3RoX2RhdGFfV1QsIG5hbWVzX2Zyb20gPSBnZW5lLCB2YWx1ZXNfZnJvbSA9IHloYXQpCgpzbW9vdGhfZGF0YV9aQzNIMjAgPC0gc3Vic2V0KHNtb290aCwgY29uZGl0aW9uID09ICJaQzNIMjBfS08iKQpzbW9vdGhfZGF0YV9aQzNIMjAgPC0gc3Vic2V0KHNtb290aF9kYXRhX1pDM0gyMCwgbGluZWFnZSA9PSAiMiIpCnNtb290aF9kYXRhX1pDM0gyMCA8LSBwaXZvdF93aWRlcihzbW9vdGhfZGF0YV9aQzNIMjAsIG5hbWVzX2Zyb20gPSBnZW5lLCB2YWx1ZXNfZnJvbSA9IHloYXQpCgpwQ29sIDwtIGFzLmNoYXJhY3RlcigiI2Y4NzY2ZCIpCgpteWNvbG91cnMgPC0gYygiI2Y4NzY2ZCIsICIjMDBiZmM0IikKc2NlX0dBTV9saW5lJGxpbmUgPC0gcmVmLmludGVncmF0ZWQkbGluZSAKI3BkZihmaWxlID0gIk5NRDNfbXV0YW50X3Ntb290aC5wZGYiLCB3aWR0aCA9IDEuNSwgaGVpZ2h0ID0gMS41KQpwbG90U21vb3RoZXJzKHNjZV9HQU1fbGluZSwgY291bnRzLCBnZW5lID0gIlRicnVjZWktLS1UYjkyNy43Ljk3MCIsIGx3ZCA9IDAuMywgc2l6ZSA9IDEvMTAsIHBvaW50Q29sID0gImxpbmUiLCBwbG90TGluZWFnZXMgPSBGQUxTRSkgKwogIGxhYnModGl0bGUgPSAiTk1EMyIpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9YygiI2Y4NzY2ZCIsICIjZjg3NjZkIiwgIiMwMGJmYzQiKSkgKyBOb0xlZ2VuZCgpICsgZ2VvbV9saW5lKGRhdGEgPSBzbW9vdGhfZGF0YV9XVCwgYWVzKHggPSBzbW9vdGhfZGF0YV9XVCR0aW1lLCB5ID0gc21vb3RoX2RhdGFfV1QkYFRicnVjZWktLS1UYjkyNy43Ljk3MGApKSArIGdlb21fbGluZShkYXRhID0gc21vb3RoX2RhdGFfWkMzSDIwLCBhZXMoeCA9IHNtb290aF9kYXRhX1pDM0gyMCR0aW1lLCB5ID0gc21vb3RoX2RhdGFfWkMzSDIwJGBUYnJ1Y2VpLS0tVGI5MjcuNy45NzBgKSwgY29sb3I9IiMwMGJmYzQiKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFjZSA9ICJib2xkIiksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwgYXhpcy50ZXh0LnkgPSAgZWxlbWVudF90ZXh0KHNpemUgPSA4KSkgCiNkZXYub2ZmKCkKYGBgCgoKYGBge3J9CiMjIFBsb3QgcmVsYXRpdmUgZXhwcmVzc2lvbiBvZiBkaWZmZXJlbnRpYXRpb24gYXNzb2NpYXRlZCBnZW5lcyBhdCBoZWF0bWFwCgpsaWJyYXJ5KGNsdXN0ZXJFeHBlcmltZW50KQpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQoKIyBQbG90IGhlYXRtYXAKCiNHZXQgZGlmZmVyZW50aWF0aW9uIGdlbmVzIGluIGNvcnJlY3Qgb3JkZXIgZnJvbSBXVCBoZWF0bWFwIHBsb3QgZnJvbSBvdGhlciBzY3JpcHQKb3JkZXIgPC0gcm93bmFtZXMoZGF0YSkKCiMgZ2V0IHNtb290aCBnZW5lIGV4cHJlc3Npb24gZm9yIGVhY2gKc21vb3RoIDwtIHByZWRpY3RTbW9vdGgoc2NlX0dBTV9saW5lLCBnZW5lID0gb3JkZXIsIHRpZHkgPSBUUlVFKQpzbW9vdGhfc3Vic2V0X0tPIDwtIHN1YnNldChzbW9vdGgsIHNtb290aCRjb25kaXRpb24gPT0gJ1pDM0gyMF9LTycpCnNtb290aF9zdWJzZXRfS08xIDwtIHN1YnNldChzbW9vdGhfc3Vic2V0X0tPLCBzbW9vdGhfc3Vic2V0X0tPJGxpbmVhZ2UgPT0gJzEnKQpzbW9vdGhfc3Vic2V0X0tPMiA8LSBzdWJzZXQoc21vb3RoX3N1YnNldF9LTywgc21vb3RoX3N1YnNldF9LTyRsaW5lYWdlID09ICcyJykKc21vb3RoX3N1YnNldF9XVCA8LSBzdWJzZXQoc21vb3RoLCBzbW9vdGgkY29uZGl0aW9uID09ICdXVCcpCnNtb290aF9zdWJzZXRfV1QxIDwtIHN1YnNldChzbW9vdGhfc3Vic2V0X1dULCBzbW9vdGhfc3Vic2V0X1dUJGxpbmVhZ2UgPT0gJzEnKQpzbW9vdGhfc3Vic2V0X1dUMiA8LSBzdWJzZXQoc21vb3RoX3N1YnNldF9XVCwgc21vb3RoX3N1YnNldF9XVCRsaW5lYWdlID09ICcyJykKCiMjIHRyYW5zZm9ybSBkYXRhCktPMSA8LSBwaXZvdF93aWRlcihzbW9vdGhfc3Vic2V0X0tPMSwgbmFtZXNfZnJvbSA9IGdlbmUsIHZhbHVlc19mcm9tID0geWhhdCkKS08yIDwtIHBpdm90X3dpZGVyKHNtb290aF9zdWJzZXRfS08yLCBuYW1lc19mcm9tID0gZ2VuZSwgdmFsdWVzX2Zyb20gPSB5aGF0KQpXVDEgPC0gcGl2b3Rfd2lkZXIoc21vb3RoX3N1YnNldF9XVDEsIG5hbWVzX2Zyb20gPSBnZW5lLCB2YWx1ZXNfZnJvbSA9IHloYXQpCldUMiA8LSBwaXZvdF93aWRlcihzbW9vdGhfc3Vic2V0X1dUMiwgbmFtZXNfZnJvbSA9IGdlbmUsIHZhbHVlc19mcm9tID0geWhhdCkKCnJvd25hbWVzKEtPMSkgPC0gS08xJHRpbWUKS08xIDwtIHQoS08xWyAsIShuYW1lcyhLTzEpICVpbiUgYygibGluZWFnZSIsICJ0aW1lIiwgImNvbmRpdGlvbiIpKV0pCnJvd25hbWVzKEtPMikgPC0gS08yJHRpbWUKS08yIDwtIHQoS08yWyAsIShuYW1lcyhLTzIpICVpbiUgYygibGluZWFnZSIsICJ0aW1lIiwgImNvbmRpdGlvbiIpKV0pCnJvd25hbWVzKFdUMSkgPC0gV1QxJHRpbWUKV1QxIDwtIHQoV1QxWyAsIShuYW1lcyhXVDEpICVpbiUgYygibGluZWFnZSIsICJ0aW1lIiwgImNvbmRpdGlvbiIpKV0pCnJvd25hbWVzKFdUMikgPC0gV1QyJHRpbWUKV1QyIDwtIHQoV1QyWyAsIShuYW1lcyhXVDIpICVpbiUgYygibGluZWFnZSIsICJ0aW1lIiwgImNvbmRpdGlvbiIpKV0pCmRhdGEyIDwtIGNiaW5kKEtPMSwgS08yKQpkYXRhX3NjYWxlIDwtIHQoc2NhbGUodChkYXRhMikpKQpkYXRhX3NjYWxlX3N1YnNldCA8LSBkYXRhX3NjYWxlWyAsMTAxOjIwMF0KCiN3cml0ZS5jc3YoZGF0YSwgZmlsZSA9ICJHZW5lX21vZHVsZXNfV1RfaW50ZWdyYXRlZC5jc3YiKQoKY29sb3JzIDwtIHNldE5hbWVzKGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMSwnWWxHbkJ1JylbLTZdKSgxMDApLCAxOjEwMCkKcGxvdGNvbCA8LSBjb2xvcnNbY3V0KHNjZSRzbGluZ1BzZXVkb3RpbWVfMiwgYnJlYWtzPTEwMCldCmhhIDwtIEhlYXRtYXBBbm5vdGF0aW9uKHBzZXVkb3RpbWUgPSAxOjEwMCwgY29sID0gbGlzdChwc2V1ZG90aW1lID0gY29sb3JzKSwgIHNob3dfbGVnZW5kID0gRkFMU0UpCiNwZGYoZmlsZSA9ICJaYzNIMjBfbW9kdWxlX2hlYXRtYXA0LnBkZiIsIHdpZHRoID0gNC41LCBoZWlnaHQgPSA1KQpIZWF0bWFwKGRhdGFfc2NhbGVfc3Vic2V0LCBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwgc2hvd19jb2x1bW5fbmFtZXMgPSBGQUxTRSwgY2x1c3Rlcl9yb3dzID0gRkFMU0UsIHNob3dfcm93X25hbWVzID0gRkFMU0UsCiAgICAgICAgc2hvd19oZWF0bWFwX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdCh0aXRsZSA9ICJleHByZXNzaW9uIiksIHRvcF9hbm5vdGF0aW9uID0gaGEpCiNkZXYub2ZmKCkKYGBgCgpgYGB7cn0KIyMgRWFybHkgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIGdlbmUgYW5hbHlzaXMpICMjCgojIyBwbG90IHRoZSBrbm90IHBvc2l0aW9ucyAKbXljb2xvdXJzIDwtIGMoIiNkMzkyMDAiLCIjZjg3NjZkIiwgIiM3Y2FlMDAiLCAiIzAxYmZjNCIsIiNjNzdjZmYiLCAiIzYxOWNmZiIpCiNwZGYoZmlsZSA9ICJQSEFURV9jbHVzdGVyX2tub3RzLnBkZiIsIHdpZHRoID0gNywgaGVpZ2h0ID0gNykKCnBsb3RHZW5lQ291bnQoY3VydmUgPSBjcnYsIGNvdW50cyA9IGNvdW50cywKICAgICAgICAgICAgICBjbHVzdGVycyA9IGFwcGx5KHNsaW5nQ2x1c3RlckxhYmVscyhjcnYpLCAxLCB3aGljaC5tYXgpLAogICAgICAgICAgICAgIG1vZGVscyA9IHNjZV9HQU1fbGluZSkgKyBzY2FsZV95X3JldmVyc2UoKSArIE5vTGVnZW5kKCkgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPSBteWNvbG91cnMpCmRldi5vZmYoKQoKIyBmaW5kIGVhcmx5IGRpZmZlcmVudGlhbHkgZXhwcmVzc2VkIGdlbmVzIAplYXJseURFUmVzIDwtIGVhcmx5REVUZXN0KHNjZV9HQU1fbGluZSwga25vdHMgPSBjKDEsIDMpKQp3cml0ZS5jc3YoZWFybHlERVJlcywgZmlsZSA9ICJlYXJseV9yZXNfdGVzdC5jc3YiKQoKYGBgCgpgYGB7cn0KUHJjdENlbGxFeHByaW5nR2VuZSA8LSBmdW5jdGlvbihvYmplY3QsIGdlbmVzLCBncm91cC5ieSA9ICJhbGwiKXsKICBpZihncm91cC5ieSA9PSAiYWxsIil7CiAgICBwcmN0ID0gdW5saXN0KGxhcHBseShnZW5lcyxjYWxjX2hlbHBlciwgb2JqZWN0PW9iamVjdCkpCiAgICByZXN1bHQgPSBkYXRhLmZyYW1lKE1hcmtlcnMgPSBnZW5lcywgQ2VsbF9wcm9wb3J0aW9uID0gcHJjdCkKICAgIHJldHVybihyZXN1bHQpCiAgfQogIAogIGVsc2V7ICAgICAgICAKICAgIGxpc3QgPSBTcGxpdE9iamVjdChvYmplY3QsIGdyb3VwLmJ5KQogICAgZmFjdG9ycyA9IG5hbWVzKGxpc3QpCiAgICAKICAgIHJlc3VsdHMgPSBsYXBwbHkobGlzdCwgUHJjdENlbGxFeHByaW5nR2VuZSwgZ2VuZXM9Z2VuZXMpCiAgICBmb3IoaSBpbiAxOmxlbmd0aChmYWN0b3JzKSl7CiAgICAgIHJlc3VsdHNbW2ldXSRGZWF0dXJlID0gZmFjdG9yc1tpXQogICAgfQogICAgY29tYmluZWQgPSBkby5jYWxsKCJyYmluZCIsIHJlc3VsdHMpCiAgICByZXR1cm4oY29tYmluZWQpCiAgfQp9CgpjYWxjX2hlbHBlciA8LSBmdW5jdGlvbihvYmplY3QsZ2VuZXMpewogIGNvdW50cyA9IG9iamVjdFtbJ1JOQSddXUBjb3VudHMKICBuY2VsbHMgPSBuY29sKGNvdW50cykKICBpZihnZW5lcyAlaW4lIHJvdy5uYW1lcyhjb3VudHMpKXsKICAgIHN1bShjb3VudHNbZ2VuZXMsXT4wKS9uY2VsbHMKICB9ZWxzZXtyZXR1cm4oTkEpfQp9CmBgYAoKCmBgYHtyfQojIyMgQ2VsbCBjeWNsZSAjIwoKZ2VuZXMgPC0gcmVmLmludGVncmF0ZWRAYXNzYXlzW1siaW50ZWdyYXRlZCJdXUBkYXRhCmdlbmVzIDwtIGdlbmVzQERpbW5hbWVzW1sxXV0KY2VsbF9wcmN0IDwtIFByY3RDZWxsRXhwcmluZ0dlbmUocmVmLmludGVncmF0ZWQsIGdlbmVzID0gZ2VuZXMsIGdyb3VwLmJ5ID0gImFsbCIpCmdlbmVzXzEwcHJjdCA8LSBzdWJzZXQoY2VsbF9wcmN0LCBzdWJzZXQgPSBjZWxsX3ByY3QkQ2VsbF9wcm9wb3J0aW9uID4gMC4xKQpnZW5lc18xMCA8LSBnZW5lc18xMHByY3QkTWFya2VycwoKQ2VsbF9jeWNsZV9yZWd1bGF0ZWRfZ2VuZXMgPC0gcmVhZC5kZWxpbSgiQ2VsbF9jeWNsZV9yZWd1bGF0ZWRfZ2VuZXMudHh0IikKCnMuZ2VuZXMgPC0gc3Vic2V0KENlbGxfY3ljbGVfcmVndWxhdGVkX2dlbmVzLCBDZWxsX2N5Y2xlX3JlZ3VsYXRlZF9nZW5lcyRTLnBoYXNlICVpbiUgZ2VuZXMpCnMuZ2VuZXMgPC0gcy5nZW5lcyRTLnBoYXNlCmcybS5nZW5lcyA8LSBzdWJzZXQoQ2VsbF9jeWNsZV9yZWd1bGF0ZWRfZ2VuZXMsIENlbGxfY3ljbGVfcmVndWxhdGVkX2dlbmVzJEcyLk0ucGhhc2UgJWluJSBnZW5lcykKZzJtLmdlbmVzIDwtIGcybS5nZW5lcyRHMi5NLnBoYXNlCmVhcmx5LmcxLmdlbmVzIDwtIHN1YnNldChDZWxsX2N5Y2xlX3JlZ3VsYXRlZF9nZW5lcywgQ2VsbF9jeWNsZV9yZWd1bGF0ZWRfZ2VuZXMkRWFybHkuRzEgJWluJSBnZW5lcykKZWFybHkuZzEuZ2VuZXMgPC0gZWFybHkuZzEuZ2VuZXMkRWFybHkuRzEKbGF0ZS5nMS5nZW5lcyA8LSBzdWJzZXQoQ2VsbF9jeWNsZV9yZWd1bGF0ZWRfZ2VuZXMsIENlbGxfY3ljbGVfcmVndWxhdGVkX2dlbmVzJExhdGUuRzEgJWluJSBnZW5lcykKbGF0ZS5nMS5nZW5lcyA8LSBsYXRlLmcxLmdlbmVzJExhdGUuRzEKCnJlZi5pbnRlZ3JhdGVkIDwtIE1ldGFGZWF0dXJlKHJlZi5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IHMuZ2VuZXMsIG1ldGEubmFtZSA9ICJTLmFnZ3JlZ2F0ZSIpCnJlZi5pbnRlZ3JhdGVkIDwtIE1ldGFGZWF0dXJlKHJlZi5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IGcybS5nZW5lcywgbWV0YS5uYW1lID0gIkcyTS5hZ2dyZWdhdGUiKQpyZWYuaW50ZWdyYXRlZCA8LSBNZXRhRmVhdHVyZShyZWYuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSBlYXJseS5nMS5nZW5lcywgbWV0YS5uYW1lID0gIkVhcmx5LkcxLmFnZ3JlZ2F0ZSIpCnJlZi5pbnRlZ3JhdGVkIDwtIE1ldGFGZWF0dXJlKHJlZi5pbnRlZ3JhdGVkLCBmZWF0dXJlcyA9IGxhdGUuZzEuZ2VuZXMsIG1ldGEubmFtZSA9ICJMYXRlLkcxLmFnZ3JlZ2F0ZSIpCiMgQ3JlYXQgYW5kIGRhdGFmcmFtZSB3aXRoIHRoZSBleHByZXNzaW9uIHNjb3JlIG9mIGVhY2ggY2VsbCBhbmQgZWFjaCBwaGFzZQpkZiA8LSBkYXRhLmZyYW1lKHJlZi5pbnRlZ3JhdGVkQG1ldGEuZGF0YVtbIlMuYWdncmVnYXRlIl1dLCByZWYuaW50ZWdyYXRlZEBtZXRhLmRhdGFbWyJHMk0uYWdncmVnYXRlIl1dLCByZWYuaW50ZWdyYXRlZEBtZXRhLmRhdGFbWyJFYXJseS5HMS5hZ2dyZWdhdGUiXV0sIHJlZi5pbnRlZ3JhdGVkQG1ldGEuZGF0YVtbIkxhdGUuRzEuYWdncmVnYXRlIl1dKQpjb2xuYW1lcyhkZikgPC0gYygiUyIsICJHMk0iLCAiRWFybHkgRzEiLCAiTGF0ZSBHMSIpCnJvd25hbWVzKGRmKSA8LSByZWYuaW50ZWdyYXRlZEBhc3NheXNbWyJpbnRlZ3JhdGVkIl1dQGRhdGFARGltbmFtZXNbWzJdXQoKIyBGaW5kIHJhdGlvIGJldHdlZW4gdGhlIHNjb3JlIGFuZCBhdmVyYWdlCmRmJFMucmF0aW8gPC0gZGYkUyAvIG1lYW4oZGYkUykKZGYkRzJNLnJhdGlvIDwtIGRmJEcyTSAvIG1lYW4oZGYkRzJNKQpkZiRFYXJseV9HMS5yYXRpbyA8LSBkZiRgRWFybHkgRzFgIC8gbWVhbihkZiRgRWFybHkgRzFgKQpkZiRMYXRlX0cxLnJhdGlvIDwtIGRmJGBMYXRlIEcxYCAvIG1lYW4oZGYkYExhdGUgRzFgKQoKIyBGaW5kIHRoZSB0b3Agc2NvcmluZyBwaGFzZSBvZiBlYWNoIGNlbGwsIHdpdGggRkMgPiAxLjUuIAphc3NpZ25tZW50cyA8LSBhcHBseSgKICBYID0gZGZbLCA1OjhdLAogIE1BUkdJTiA9IDEsCiAgRlVOID0gZnVuY3Rpb24oc2NvcmVzLCBmaXJzdCA9ICdTJywgc2Vjb25kID0gJ0cyTScsIHRoaXJkID0gIkVhcmx5IEcxIiwgZm91cnRoID0gIkxhdGUgRzEiLCBudWxsID0gJ05vbi1jeWNsaW5nJykgewogICAgaWYgKGFsbChzY29yZXMgPCAxLjUpKSB7CiAgICAgIHJldHVybihudWxsKQogICAgfSBlbHNlIHsKICAgICAgaWYgKGxlbmd0aCh3aGljaCh4ID0gc2NvcmVzID09IG1heChzY29yZXMpKSkgPiAxKSB7CiAgICAgICAgcmV0dXJuKCdVbmRlY2lkZWQnKQogICAgICB9IGVsc2UgewogICAgICAgIHJldHVybihjKGZpcnN0LCBzZWNvbmQsIHRoaXJkLCBmb3VydGgpW3doaWNoKHggPSBzY29yZXMgPT0gbWF4KHNjb3JlcykpXSkKICAgICAgfQogICAgfQogIH0gICAgCikKCmRmJFBoYXNlIDwtIGFzc2lnbm1lbnRzCmRmJENsdXN0ZXIgPC0gcmVmLmludGVncmF0ZWRAYWN0aXZlLmlkZW50CiN3cml0ZS5jc3YoZGYsIGZpbGUgPSAibXV0YW5udF9XVF9DZWxsX2N5Y2xlX3BoYXNlX3Njb3JlLmNzdiIpCiMgU2F2ZSB0aGUgcGhhc2UgZm9yIGVhY2ggY2VsbApyZWYuaW50ZWdyYXRlZCA8LSBBZGRNZXRhRGF0YShyZWYuaW50ZWdyYXRlZCwgYXNzaWdubWVudHMsIGNvbC5uYW1lID0gIlBoYXNlIikKCm15Y29sb3VycyA8LSBjKCIjZjg3NjZkIiwgIiM3Y2FlMDAiLCAiIzAxYmZjNCIsICJncmV5IiwgIiNjNzdjZmYiKQojIFBsb3QgdGhlIGNlbGxzIGJ5IHBoYXNlIG9uIGEgVU1BUApwIDwtIERpbVBsb3Qob2JqZWN0ID0gcmVmLmludGVncmF0ZWQsIGdyb3VwLmJ5ID0gIlBoYXNlIiwgcmVkdWN0aW9uID0gInVtYXAiLCBwdC5zaXplID0gMC41LCBjb2xzID0gbXljb2xvdXJzKSArIFVNQVBfdGhlbWUKcFtbMV1dJGxheWVyc1tbMV1dJGFlc19wYXJhbXMkYWxwaGEgPSAwLjUKcFtbMV1dJGxheWVyc1tbMV1dJGFlc19wYXJhbXMkc2hhcGUgPSAxNgojcGRmKGZpbGUgPSAiTXV0YW50X1dUX3VtYXBfcGhhc2UucGRmIiwgd2lkdGggPSA0LCBoZWlnaHQgPSAyLjUpCnAKI2Rldi5vZmYoKQpgYGAKCgoKYGBge3J9CmNlbGxfcHJvcG9ydGlvbnMgPC0gYXMuZGF0YS5mcmFtZShwcm9wLnRhYmxlKHRhYmxlKHJlZi5pbnRlZ3JhdGVkJFBoYXNlLCByZWYuaW50ZWdyYXRlZEBhY3RpdmUuaWRlbnQpLCBtYXJnaW4gPSAyKSkKI3dyaXRlLmNzdihjZWxsX3Byb3BvcnRpb25zLCBmaWxlID0gImNlbGxfcHJvcG9ydGlvbnNfcGhhc2VfbXV0YW50X2ludGVncmF0aW9uX2NsdXN0ZXIuY3N2IikKI3BkZihmaWxlID0gIldUX2NlbGxfcHJvcG9ydGlvbnMucGRmIiwgd2lkdGggPSAyLjUsIGhlaWdodCA9IDIuNSkKZ2dwbG90KGRhdGE9Y2VsbF9wcm9wb3J0aW9ucywgYWVzKHg9Y2VsbF9wcm9wb3J0aW9ucyRWYXIyLCB5PWNlbGxfcHJvcG9ydGlvbnMkRnJlcSwgZmlsbD1jZWxsX3Byb3BvcnRpb25zJFZhcjEpKSArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgY29sb3I9ImJsYWNrIikgKyBsYWJzKHg9InNhbXBsZSIsIHk9IlByb3BvcnRpb24gb2YgQ2VsbHMiLCBmaWxsPSJDbHVzdGVyIikKI2Rldi5vZmYoKQpgYGAKCgoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLiAKClRoZSBwcmV2aWV3IHNob3dzIHlvdSBhIHJlbmRlcmVkIEhUTUwgY29weSBvZiB0aGUgY29udGVudHMgb2YgdGhlIGVkaXRvci4gQ29uc2VxdWVudGx5LCB1bmxpa2UgKktuaXQqLCAqUHJldmlldyogZG9lcyBub3QgcnVuIGFueSBSIGNvZGUgY2h1bmtzLiBJbnN0ZWFkLCB0aGUgb3V0cHV0IG9mIHRoZSBjaHVuayB3aGVuIGl0IHdhcyBsYXN0IHJ1biBpbiB0aGUgZWRpdG9yIGlzIGRpc3BsYXllZC4KCg==