library(pagoda2)
Loading required package: Matrix
Loading required package: igraph
package ‘igraph’ was built under R version 3.5.3
Attaching package: ‘igraph’

The following objects are masked from ‘package:stats’:

    decompose, spectrum

The following object is masked from ‘package:base’:

    union
library(ggplot2)
library(cowplot)

Attaching package: ‘cowplot’

The following object is masked from ‘package:ggplot2’:

    ggsave

Load data

mat <- readRDS("E12.5.rds")
source("~/m/pavan/DLI/conp2.r")
data.table 1.11.8  Latest news: r-datatable.com
doublet.f <- get.scrublet.scores(mat)

Basic processing

r <- basicP2proc(mat[,doublet.f[colnames(mat)]<0.2],n.cores=20,nPcs=30,make.geneknn=F)
11590 cells, 27998 genes; normalizing ... using plain model winsorizing ... log scale ... done.
calculating variance fit ... using gam 1373 overdispersed genes ... 1373persisting ... done.
running PCA using 3000 OD genes .... done
creating space of type angular done
adding data ... done
building index ... done
querying ... done
Estimating embeddings.
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
running tSNE using 20 cores:
 - point 10000 of 11590
r$makeKnnGraph(k = 50, type = "PCA", center = TRUE, weight.type = "none", n.cores = 30, distance = "cosine")
creating space of type angular done
adding data ... done
building index ... done
querying ... done
r$getKnnClusters(type='PCA',method=function(x) conos::leiden.community(x,r=0.3),name='leiden')
set.seed(3) # 4/1e7  3/1e7   4/3e7/M2/a0.8   5/M2/a0.5/3e7   5/M2/a0.5/3e7  5/M3/a0.2/5e7
M <- 2; r$getEmbedding(type='PCA', embeddingType='largeVis', M=M,  gamma = 1/M,sgd_batches=5e7,perplexity = NA)
Estimating embeddings.
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
set.seed(2)
r$getEmbedding(type='PCA',embeddingType='tSNE',perplexity = 400)
calculating distance ... pearson ...running tSNE using 20 cores:
 - point 10000 of 11590
r$plotEmbedding(type = 'PCA', embedding = 'tSNE', colors=r$counts[,'Mki67'],alpha=0.5,cex=0.2)
treating colors as a gradient with zlim: 0 0.2466913 

r$plotEmbedding(type = 'PCA', embedding = 'tSNE', colors=r$counts[,'Id2'],alpha=0.5,cex=0.2)
treating colors as a gradient with zlim: 0 0.6343238 

r$plotEmbedding(type = 'PCA', embedding = 'tSNE', clusterType = 'leiden', mark.clusters = T,alpha=0.2,cex=0.1,mark.cluster.cex = 1)

par(mfrow=c(3,3))
gns <- c('Klk13','Pitx2','Sparcl1','Col1a1','Myl9','Stmn2','Acta2','Cav1','Wt1')

lapply(gns,function(gene) r$plotEmbedding(type = 'PCA', embedding = 'tSNE', colors=r$counts[,gene],alpha=0.5,cex=0.2,main=gene))
treating colors as a gradient with zlim: 0 0.3347215 
treating colors as a gradient with zlim: 0 0.3414924 
treating colors as a gradient with zlim: 0 0.454883 
treating colors as a gradient with zlim: 0 0.3963445 
treating colors as a gradient with zlim: 0 0.2912576 
treating colors as a gradient with zlim: 0 0.03126894 
treating colors as a gradient with zlim: 0 1.99891 
treating colors as a gradient with zlim: 0 0.4640115 
treating colors as a gradient with zlim: 0 0.341166 
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

[[4]]
NULL

[[5]]
NULL

[[6]]
NULL

[[7]]
NULL

[[8]]
NULL

[[9]]
NULL

par(mfrow=c(3,3))
gns <- c('Cpa1','Spp1','Neurog3','Col1a1','Fabp7','Tlx2','Pecam1','Col3a1','Hbb-bt')

lapply(gns,function(gene) r$plotEmbedding(type = 'PCA', embedding = 'tSNE', colors=r$counts[,gene],alpha=0.5,cex=0.2,main=gene))
treating colors as a gradient with zlim: 0 2.03234 
treating colors as a gradient with zlim: 0 1.351252 
treating colors as a gradient with zlim: 0 0.3198094 
treating colors as a gradient with zlim: 0 0.3963445 
treating colors as a gradient with zlim: 0 0.08929173 
treating colors as a gradient with zlim: 0 0.1353626 
treating colors as a gradient with zlim: 0 0.5760832 
treating colors as a gradient with zlim: 0 0.4638031 
treating colors as a gradient with zlim: 0 1.341928 
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

[[4]]
NULL

[[5]]
NULL

[[6]]
NULL

[[7]]
NULL

[[8]]
NULL

[[9]]
NULL

par(mfrow=c(3,3))
gns <- c('Krt19','Stmn2','Acta2','Col1a1','Fabp7','Rac2','Cxcl12','Nkx2-5','Sparcl1')

lapply(gns,function(gene) r$plotEmbedding(type = 'PCA', embedding = 'largeVis', colors=r$counts[,gene],alpha=0.5,cex=0.2,main=gene))
treating colors as a gradient with zlim: 0 0.3041981 
treating colors as a gradient with zlim: 0 0.03126894 
treating colors as a gradient with zlim: 0 1.99891 
treating colors as a gradient with zlim: 0 0.3963445 
treating colors as a gradient with zlim: 0 0.08929173 
treating colors as a gradient with zlim: 0 0.2900099 
treating colors as a gradient with zlim: 0 0.2836841 
treating colors as a gradient with zlim: 0 0.3769584 
treating colors as a gradient with zlim: 0 0.454883 
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

[[4]]
NULL

[[5]]
NULL

[[6]]
NULL

[[7]]
NULL

[[8]]
NULL

[[9]]
NULL

r$plotEmbedding(type = 'PCA', embedding = 'largeVis', colors=r$counts[,'Cd44'],alpha=0.5,cex=0.2)
treating colors as a gradient with zlim: 0 0.2337546 

a2 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=r$clusters$PCA$leiden,size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
a2

r$getDifferentialGenes(type='PCA',verbose=T,clusterType='leiden',append.auc = T,upregulated.only = T)
running differential expression with  8  clusters ... adjusting p-values ... done.
de <- r$diffgenes$PCA[['leiden']];
conos::plotDEheatmap(r,r$clusters$PCA$leiden,de=de,n.genes.per.cluster = 10)

#r$plotGeneHeatmap(genes=rownames(de)[1:30],groups=r$clusters$PCA[[1]])

Can’t tell the identity of the two Hbb-bt populations … both look like RBCs 1/17 - erythroblast/erythroid … 17 looks more primitive 15 seems to be myeloid / macrophages C1qc-high 9,5: neuroadrenergic … actively dividing though? 13 - vascular endothelial

Should align with TabMuris data

ann <- r$clusters$PCA$leiden
ann <- setNames(as.character(ann),names(ann))
ann[ann == '8'] <- 'vascular endothelial'
ann[ann %in% c('7')] <- 'neuroadrenergic'
ann[ann %in% c('5')] <- 'erythroid'
ann[ann %in% c('2')] <- 'mesothelium'
ann[ann %in% c('3')] <- 'VSM'
ann[ann %in% c('1','4')] <- 'epithelial'
ann[ann %in% c('6')] <- 'myeloid'
ann <- as.factor(ann)
a1 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=as.factor(ann),size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
a2 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=r$clusters$PCA$leiden,size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
a3 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Mki67"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
plot_grid(plotlist=list(a1,a2,a3),nrow=1)
set.seed(5)
r$getKnnClusters(type='PCA',method=function(x) conos::leiden.community(x,r=5),name='leiden2')
a1 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=as.factor(ann),size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
a2 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=r$clusters$PCA$leiden2,size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
a3 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Mki67"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
plot_grid(plotlist=list(a1,a2,a3),nrow=1)

Make a coarse clusering for illustrating cluster similarity

mcl <- setNames(rep(NA,length(ann)),names(ann))
mcl[ann == 'epithelial'] <- 'E1'
mcl[r$clusters$PCA$leiden2[names(mcl)] %in% c(16,22,17,20)] <- 'E2'
mcl[ann == 'mesothelium'] <- 'M1'
mcl[r$clusters$PCA$leiden2[names(mcl)] %in% c(23,26,31,35)] <- 'M2'
mcl[ann == 'VSM'] <- 'V1'
mcl[r$clusters$PCA$leiden2[names(mcl)] %in% c(32,27)] <- 'V2'
mcl <- as.factor(mcl)
set.seed(0)
a1 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=as.factor(ann),size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(4,5))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
a2 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=mcl,size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(5.5),palette = function(n) rainbow(n,s=0.7,v=0.7))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
a3 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Mki67"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
plot_grid(plotlist=list(a1,a2,a3),nrow=1)

Hierarchical clustering

cp <- conos:::collapseCellsByType(r$misc$rawCounts,mcl)
cp <- log10(cp/rowSums(cp)*1e6+1)
hc <- hclust(as.dist(1-cor(t(cp))),method='ward.D2')
plot(hc,main='',sub='',xlab='',yaxt='none',ylab='');

pdf(file='dend.pdf',width=3,height=3); plot(hc,main='',sub='',xlab='',yaxt='none',ylab=''); dev.off();

Clean plots:

set.seed(2)
a1 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=as.factor(ann),size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(4,5),palette = function(n) sample(rainbow(n,s=0.9,v=0.9)),box.padding=0.5)+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank(),plot.margin = margin(.1, .1, .1, .1, "cm"))
pdf(file='fp_celltypes.pdf',width=3,height=3); print(a1); dev.off()
null device 
          1 
a1

Clusters and markers:

plst <- theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank(),plot.margin = margin(.1, .1, .1, .1, "cm"));
set.seed(0)
a2 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=mcl,size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(5.5),palette = function(n) rainbow(n,s=0.7,v=0.7))+plst

a3 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Epcam"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+plst+ annotate('text',x=-Inf,y=Inf,hjust=0,vjust=1.2,label='Epcam',size=6)
a4 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Col3a1"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+plst+ annotate('text',x=-Inf,y=Inf,hjust=0,vjust=1.2,label='Col3a1',size=6)
a5 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Mki67"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+plst+ annotate('text',x=-Inf,y=Inf,hjust=0,vjust=1.2,label='Mki67',size=6)
pp <- plot_grid(plotlist=list(a2,a3,a4,a5),nrow=2)
pdf(file='fp_panels.pdf',width=4,height=4); print(pp); dev.off();
png 
  2 
pp

mcl2 <- setNames(as.character(mcl),names(mcl))
mcl2[is.na(mcl2)] <- ' '
mcl2 <- as.factor(mcl2)
plst <- theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank(),plot.margin = margin(.1, .1, .1, .1, "cm"));
set.seed(0)
a2 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=mcl2,size=0.2,alpha=0.2,raster=T,mark.groups=F,raster.height = 3,raster.width=3,font.size=c(5.5),palette = function(n) c('gray60',rainbow(n-1,s=0.7,v=0.7)))+plst

a3 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Epcam"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+plst+ annotate('text',x=-Inf,y=Inf,hjust=0,vjust=1.2,label='Epcam',size=6)
a4 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Col3a1"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+plst+ annotate('text',x=-Inf,y=Inf,hjust=0,vjust=1.2,label='Col3a1',size=6)
a5 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Mki67"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+plst+ annotate('text',x=-Inf,y=Inf,hjust=0,vjust=1.2,label='Mki67',size=6)
pp <- plot_grid(plotlist=list(a2,a3,a4,a5),nrow=1)
pdf(file='fp_panels2.pdf',width=8,height=2); print(pp); dev.off();
png 
  2 
pp

Combined figure

plst <- theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank(),plot.margin = margin(.1, .1, .1, .1, "cm"));
ann.size <- 7;
emb <- r$embeddings$PCA$tSNE
a1 <- conos::embeddingPlot(emb,groups=as.factor(ann),size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(3.5,5.5))+plst
set.seed(0)
a2 <- conos::embeddingPlot(emb,groups=mcl,size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(5.5),palette = function(n) rainbow(n,s=0.7,v=0.7),plot.na=F) +xlim(range(emb[,1]))+ylim(range(emb[,2]))+plst

a3 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Epcam"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+plst+ annotate('text',x=-Inf,y=Inf,hjust=-0.1,vjust=1.2,label='Epcam',size=ann.size)
a4 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Col3a1"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+plst+ annotate('text',x=-Inf,y=Inf,hjust=-0.1,vjust=1.2,label='Col3a1',size=ann.size)
a5 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,colors=pagoda2:::val2col(r$counts[,"Mki67"]),size=0.1,alpha=0.5,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+plst+ annotate('text',x=-Inf,y=Inf,hjust=-0.1,vjust=1.2,label='Mki67',size=ann.size)
pp <- plot_grid(plotlist=list(a1,a2,a3,a4,a5),nrow=1)
pdf(file='fp_panels_wide.pdf',width=15,height=3); print(pp); dev.off();
png 
  2 
pp

r$plotEmbedding(type = 'PCA', embedding = 'largeVis', groups=ann, mark.clusters = T,alpha=0.2,cex=0.2, mark.cluster.cex = 1)
a1 <- conos::embeddingPlot(r$embeddings$PCA$largeVis,groups=r$clusters$PCA$multilevel,size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
a1
a1 <- conos::embeddingPlot(r$embeddings$PCA$tSNE,groups=as.factor(ann),size=0.1,alpha=0.2,raster=T,raster.height = 3,raster.width=3,font.size=c(3,4))+
  theme(panel.border = element_rect(color = 1, size=0.2,linetype=1),axis.line=element_blank())
a1
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkocGFnb2RhMikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGNvd3Bsb3QpCmBgYAoKTG9hZCBkYXRhCmBgYHtyfQptYXQgPC0gcmVhZFJEUygiRTEyLjUucmRzIikKYGBgCgpgYGB7cn0Kc291cmNlKCJ+L20vcGF2YW4vRExJL2NvbnAyLnIiKQpkb3VibGV0LmYgPC0gZ2V0LnNjcnVibGV0LnNjb3JlcyhtYXQpCmBgYAoKCkJhc2ljIHByb2Nlc3NpbmcKYGBge3J9CnIgPC0gYmFzaWNQMnByb2MobWF0Wyxkb3VibGV0LmZbY29sbmFtZXMobWF0KV08MC4yXSxuLmNvcmVzPTIwLG5QY3M9MzAsbWFrZS5nZW5la25uPUYpCmBgYAoKYGBge3J9CnIkbWFrZUtubkdyYXBoKGsgPSA1MCwgdHlwZSA9ICJQQ0EiLCBjZW50ZXIgPSBUUlVFLCB3ZWlnaHQudHlwZSA9ICJub25lIiwgbi5jb3JlcyA9IDMwLCBkaXN0YW5jZSA9ICJjb3NpbmUiKQpgYGAKCmBgYHtyfQpyJGdldEtubkNsdXN0ZXJzKHR5cGU9J1BDQScsbWV0aG9kPWZ1bmN0aW9uKHgpIGNvbm9zOjpsZWlkZW4uY29tbXVuaXR5KHgscj0wLjMpLG5hbWU9J2xlaWRlbicpCmBgYAoKCmBgYHtyfQpzZXQuc2VlZCgzKSAjIDQvMWU3ICAzLzFlNyAgIDQvM2U3L00yL2EwLjggICA1L00yL2EwLjUvM2U3ICAgNS9NMi9hMC41LzNlNyAgNS9NMy9hMC4yLzVlNwpNIDwtIDI7IHIkZ2V0RW1iZWRkaW5nKHR5cGU9J1BDQScsIGVtYmVkZGluZ1R5cGU9J2xhcmdlVmlzJywgTT1NLCAgZ2FtbWEgPSAxL00sc2dkX2JhdGNoZXM9NWU3LHBlcnBsZXhpdHkgPSBOQSkKYGBgCgpgYGB7cn0Kc2V0LnNlZWQoMikKciRnZXRFbWJlZGRpbmcodHlwZT0nUENBJyxlbWJlZGRpbmdUeXBlPSd0U05FJyxwZXJwbGV4aXR5ID0gNDAwKQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTMsZmlnLndpZHRoPTN9CnIkcGxvdEVtYmVkZGluZyh0eXBlID0gJ1BDQScsIGVtYmVkZGluZyA9ICd0U05FJywgY29sb3JzPXIkY291bnRzWywnTWtpNjcnXSxhbHBoYT0wLjUsY2V4PTAuMikKYGBgCmBgYHtyIGZpZy5oZWlnaHQ9MyxmaWcud2lkdGg9M30KciRwbG90RW1iZWRkaW5nKHR5cGUgPSAnUENBJywgZW1iZWRkaW5nID0gJ3RTTkUnLCBjb2xvcnM9ciRjb3VudHNbLCdJZDInXSxhbHBoYT0wLjUsY2V4PTAuMikKYGBgCgoKYGBge3IgZmlnLmhlaWdodD0zLGZpZy53aWR0aD0zfQpyJHBsb3RFbWJlZGRpbmcodHlwZSA9ICdQQ0EnLCBlbWJlZGRpbmcgPSAndFNORScsIGNsdXN0ZXJUeXBlID0gJ2xlaWRlbicsIG1hcmsuY2x1c3RlcnMgPSBULGFscGhhPTAuMixjZXg9MC4xLG1hcmsuY2x1c3Rlci5jZXggPSAxKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9OSxmaWcud2lkdGg9OX0KcGFyKG1mcm93PWMoMywzKSkKZ25zIDwtIGMoJ0tsazEzJywnUGl0eDInLCdTcGFyY2wxJywnQ29sMWExJywnTXlsOScsJ1N0bW4yJywnQWN0YTInLCdDYXYxJywnV3QxJykKCmxhcHBseShnbnMsZnVuY3Rpb24oZ2VuZSkgciRwbG90RW1iZWRkaW5nKHR5cGUgPSAnUENBJywgZW1iZWRkaW5nID0gJ3RTTkUnLCBjb2xvcnM9ciRjb3VudHNbLGdlbmVdLGFscGhhPTAuNSxjZXg9MC4yLG1haW49Z2VuZSkpCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9OSxmaWcud2lkdGg9OX0KcGFyKG1mcm93PWMoMywzKSkKZ25zIDwtIGMoJ0NwYTEnLCdTcHAxJywnTmV1cm9nMycsJ0NvbDFhMScsJ0ZhYnA3JywnVGx4MicsJ1BlY2FtMScsJ0NvbDNhMScsJ0hiYi1idCcpCgpsYXBwbHkoZ25zLGZ1bmN0aW9uKGdlbmUpIHIkcGxvdEVtYmVkZGluZyh0eXBlID0gJ1BDQScsIGVtYmVkZGluZyA9ICd0U05FJywgY29sb3JzPXIkY291bnRzWyxnZW5lXSxhbHBoYT0wLjUsY2V4PTAuMixtYWluPWdlbmUpKQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTksZmlnLndpZHRoPTl9CnBhcihtZnJvdz1jKDMsMykpCmducyA8LSBjKCdLcnQxOScsJ1N0bW4yJywnQWN0YTInLCdDb2wxYTEnLCdGYWJwNycsJ1JhYzInLCdDeGNsMTInLCdOa3gyLTUnLCdTcGFyY2wxJykKCmxhcHBseShnbnMsZnVuY3Rpb24oZ2VuZSkgciRwbG90RW1iZWRkaW5nKHR5cGUgPSAnUENBJywgZW1iZWRkaW5nID0gJ2xhcmdlVmlzJywgY29sb3JzPXIkY291bnRzWyxnZW5lXSxhbHBoYT0wLjUsY2V4PTAuMixtYWluPWdlbmUpKQpgYGAKCgpgYGB7ciBmaWcud2lkdGg9MyxmaWcuaGVpZ2h0PTN9CnIkcGxvdEVtYmVkZGluZyh0eXBlID0gJ1BDQScsIGVtYmVkZGluZyA9ICdsYXJnZVZpcycsIGNvbG9ycz1yJGNvdW50c1ssJ0NkNDQnXSxhbHBoYT0wLjUsY2V4PTAuMikKYGBgCgoKYGBge3IgZmlnLndpZHRoPTMsZmlnLmhlaWdodD0zfQphMiA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJHRTTkUsZ3JvdXBzPXIkY2x1c3RlcnMkUENBJGxlaWRlbixzaXplPTAuMSxhbHBoYT0wLjIscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoMyw0KSkrCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gMSwgc2l6ZT0wLjIsbGluZXR5cGU9MSksYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSkKYTIKYGBgCgpgYGB7cn0KciRnZXREaWZmZXJlbnRpYWxHZW5lcyh0eXBlPSdQQ0EnLHZlcmJvc2U9VCxjbHVzdGVyVHlwZT0nbGVpZGVuJyxhcHBlbmQuYXVjID0gVCx1cHJlZ3VsYXRlZC5vbmx5ID0gVCkKYGBgCgpgYGB7ciBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTEwfQpkZSA8LSByJGRpZmZnZW5lcyRQQ0FbWydsZWlkZW4nXV07CmNvbm9zOjpwbG90REVoZWF0bWFwKHIsciRjbHVzdGVycyRQQ0EkbGVpZGVuLGRlPWRlLG4uZ2VuZXMucGVyLmNsdXN0ZXIgPSAxMCkKI3IkcGxvdEdlbmVIZWF0bWFwKGdlbmVzPXJvd25hbWVzKGRlKVsxOjMwXSxncm91cHM9ciRjbHVzdGVycyRQQ0FbWzFdXSkKYGBgCgpDYW4ndCB0ZWxsIHRoZSBpZGVudGl0eSBvZiB0aGUgdHdvIEhiYi1idCBwb3B1bGF0aW9ucyAuLi4gYm90aCBsb29rIGxpa2UgUkJDcwoxLzE3IC0gZXJ5dGhyb2JsYXN0L2VyeXRocm9pZCAuLi4gMTcgbG9va3MgbW9yZSBwcmltaXRpdmUKMTUgc2VlbXMgdG8gYmUgbXllbG9pZCAvIG1hY3JvcGhhZ2VzIEMxcWMtaGlnaAo5LDU6IG5ldXJvYWRyZW5lcmdpYyAuLi4gYWN0aXZlbHkgZGl2aWRpbmcgdGhvdWdoPyAKMTMgLSB2YXNjdWxhciBlbmRvdGhlbGlhbAoKU2hvdWxkIGFsaWduIHdpdGggVGFiTXVyaXMgZGF0YQoKCgoKYGBge3J9CmFubiA8LSByJGNsdXN0ZXJzJFBDQSRsZWlkZW4KYW5uIDwtIHNldE5hbWVzKGFzLmNoYXJhY3Rlcihhbm4pLG5hbWVzKGFubikpCmFublthbm4gPT0gJzgnXSA8LSAndmFzY3VsYXIgZW5kb3RoZWxpYWwnCmFublthbm4gJWluJSBjKCc3JyldIDwtICduZXVyb2FkcmVuZXJnaWMnCmFublthbm4gJWluJSBjKCc1JyldIDwtICdlcnl0aHJvaWQnCmFublthbm4gJWluJSBjKCcyJyldIDwtICdtZXNvdGhlbGl1bScKYW5uW2FubiAlaW4lIGMoJzMnKV0gPC0gJ1ZTTScKYW5uW2FubiAlaW4lIGMoJzEnLCc0JyldIDwtICdlcGl0aGVsaWFsJwphbm5bYW5uICVpbiUgYygnNicpXSA8LSAnbXllbG9pZCcKYW5uIDwtIGFzLmZhY3Rvcihhbm4pCmBgYAoKCmBgYHtyIGZpZy53aWR0aD05LGZpZy5oZWlnaHQ9M30KYTEgPC0gY29ub3M6OmVtYmVkZGluZ1Bsb3QociRlbWJlZGRpbmdzJFBDQSR0U05FLGdyb3Vwcz1hcy5mYWN0b3IoYW5uKSxzaXplPTAuMSxhbHBoYT0wLjIscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoMyw0KSkrCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gMSwgc2l6ZT0wLjIsbGluZXR5cGU9MSksYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSkKYTIgPC0gY29ub3M6OmVtYmVkZGluZ1Bsb3QociRlbWJlZGRpbmdzJFBDQSR0U05FLGdyb3Vwcz1yJGNsdXN0ZXJzJFBDQSRsZWlkZW4sc2l6ZT0wLjEsYWxwaGE9MC4yLHJhc3Rlcj1ULHJhc3Rlci5oZWlnaHQgPSAzLHJhc3Rlci53aWR0aD0zLGZvbnQuc2l6ZT1jKDMsNCkpKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9IDEsIHNpemU9MC4yLGxpbmV0eXBlPTEpLGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkpCmEzIDwtIGNvbm9zOjplbWJlZGRpbmdQbG90KHIkZW1iZWRkaW5ncyRQQ0EkdFNORSxjb2xvcnM9cGFnb2RhMjo6OnZhbDJjb2wociRjb3VudHNbLCJNa2k2NyJdKSxzaXplPTAuMSxhbHBoYT0wLjUscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoMyw0KSkrCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gMSwgc2l6ZT0wLjIsbGluZXR5cGU9MSksYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSkKcGxvdF9ncmlkKHBsb3RsaXN0PWxpc3QoYTEsYTIsYTMpLG5yb3c9MSkKYGBgCgoKYGBge3J9CnNldC5zZWVkKDUpCnIkZ2V0S25uQ2x1c3RlcnModHlwZT0nUENBJyxtZXRob2Q9ZnVuY3Rpb24oeCkgY29ub3M6OmxlaWRlbi5jb21tdW5pdHkoeCxyPTUpLG5hbWU9J2xlaWRlbjInKQpgYGAKCgoKYGBge3IgZmlnLndpZHRoPTksZmlnLmhlaWdodD0zfQphMSA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJHRTTkUsZ3JvdXBzPWFzLmZhY3Rvcihhbm4pLHNpemU9MC4xLGFscGhhPTAuMixyYXN0ZXI9VCxyYXN0ZXIuaGVpZ2h0ID0gMyxyYXN0ZXIud2lkdGg9Myxmb250LnNpemU9YygzLDQpKSsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAxLCBzaXplPTAuMixsaW5ldHlwZT0xKSxheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpKQphMiA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJHRTTkUsZ3JvdXBzPXIkY2x1c3RlcnMkUENBJGxlaWRlbjIsc2l6ZT0wLjEsYWxwaGE9MC4yLHJhc3Rlcj1ULHJhc3Rlci5oZWlnaHQgPSAzLHJhc3Rlci53aWR0aD0zLGZvbnQuc2l6ZT1jKDMsNCkpKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9IDEsIHNpemU9MC4yLGxpbmV0eXBlPTEpLGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkpCmEzIDwtIGNvbm9zOjplbWJlZGRpbmdQbG90KHIkZW1iZWRkaW5ncyRQQ0EkdFNORSxjb2xvcnM9cGFnb2RhMjo6OnZhbDJjb2wociRjb3VudHNbLCJNa2k2NyJdKSxzaXplPTAuMSxhbHBoYT0wLjUscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoMyw0KSkrCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gMSwgc2l6ZT0wLjIsbGluZXR5cGU9MSksYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSkKcGxvdF9ncmlkKHBsb3RsaXN0PWxpc3QoYTEsYTIsYTMpLG5yb3c9MSkKYGBgCgpNYWtlIGEgY29hcnNlIGNsdXNlcmluZyBmb3IgaWxsdXN0cmF0aW5nIGNsdXN0ZXIgc2ltaWxhcml0eQpgYGB7cn0KbWNsIDwtIHNldE5hbWVzKHJlcChOQSxsZW5ndGgoYW5uKSksbmFtZXMoYW5uKSkKbWNsW2FubiA9PSAnZXBpdGhlbGlhbCddIDwtICdFMScKbWNsW3IkY2x1c3RlcnMkUENBJGxlaWRlbjJbbmFtZXMobWNsKV0gJWluJSBjKDE2LDIyLDE3LDIwKV0gPC0gJ0UyJwptY2xbYW5uID09ICdtZXNvdGhlbGl1bSddIDwtICdNMScKbWNsW3IkY2x1c3RlcnMkUENBJGxlaWRlbjJbbmFtZXMobWNsKV0gJWluJSBjKDIzLDI2LDMxLDM1KV0gPC0gJ00yJwptY2xbYW5uID09ICdWU00nXSA8LSAnVjEnCm1jbFtyJGNsdXN0ZXJzJFBDQSRsZWlkZW4yW25hbWVzKG1jbCldICVpbiUgYygzMiwyNyldIDwtICdWMicKbWNsIDwtIGFzLmZhY3RvcihtY2wpCmBgYAoKYGBge3IgZmlnLndpZHRoPTksZmlnLmhlaWdodD0zfQpzZXQuc2VlZCgwKQphMSA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJHRTTkUsZ3JvdXBzPWFzLmZhY3Rvcihhbm4pLHNpemU9MC4xLGFscGhhPTAuMixyYXN0ZXI9VCxyYXN0ZXIuaGVpZ2h0ID0gMyxyYXN0ZXIud2lkdGg9Myxmb250LnNpemU9Yyg0LDUpKSsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAxLCBzaXplPTAuMixsaW5ldHlwZT0xKSxheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpKQphMiA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJHRTTkUsZ3JvdXBzPW1jbCxzaXplPTAuMSxhbHBoYT0wLjIscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoNS41KSxwYWxldHRlID0gZnVuY3Rpb24obikgcmFpbmJvdyhuLHM9MC43LHY9MC43KSkrCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gMSwgc2l6ZT0wLjIsbGluZXR5cGU9MSksYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSkKYTMgPC0gY29ub3M6OmVtYmVkZGluZ1Bsb3QociRlbWJlZGRpbmdzJFBDQSR0U05FLGNvbG9ycz1wYWdvZGEyOjo6dmFsMmNvbChyJGNvdW50c1ssIk1raTY3Il0pLHNpemU9MC4xLGFscGhhPTAuNSxyYXN0ZXI9VCxyYXN0ZXIuaGVpZ2h0ID0gMyxyYXN0ZXIud2lkdGg9Myxmb250LnNpemU9YygzLDQpKSsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAxLCBzaXplPTAuMixsaW5ldHlwZT0xKSxheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpKQpwbG90X2dyaWQocGxvdGxpc3Q9bGlzdChhMSxhMixhMyksbnJvdz0xKQpgYGAKCkhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nCgpgYGB7cn0KY3AgPC0gY29ub3M6Ojpjb2xsYXBzZUNlbGxzQnlUeXBlKHIkbWlzYyRyYXdDb3VudHMsbWNsKQpjcCA8LSBsb2cxMChjcC9yb3dTdW1zKGNwKSoxZTYrMSkKYGBgCgpgYGB7ciBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQpoYyA8LSBoY2x1c3QoYXMuZGlzdCgxLWNvcih0KGNwKSkpLG1ldGhvZD0nd2FyZC5EMicpCnBsb3QoaGMsbWFpbj0nJyxzdWI9JycseGxhYj0nJyx5YXh0PSdub25lJyx5bGFiPScnKTsKYGBgCmBgYHtyfQpwZGYoZmlsZT0nZGVuZC5wZGYnLHdpZHRoPTMsaGVpZ2h0PTMpOyBwbG90KGhjLG1haW49Jycsc3ViPScnLHhsYWI9JycseWF4dD0nbm9uZScseWxhYj0nJyk7IGRldi5vZmYoKTsKYGBgCgpDbGVhbiBwbG90czoKCmBgYHtyIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CnNldC5zZWVkKDIpCmExIDwtIGNvbm9zOjplbWJlZGRpbmdQbG90KHIkZW1iZWRkaW5ncyRQQ0EkdFNORSxncm91cHM9YXMuZmFjdG9yKGFubiksc2l6ZT0wLjEsYWxwaGE9MC4yLHJhc3Rlcj1ULHJhc3Rlci5oZWlnaHQgPSAzLHJhc3Rlci53aWR0aD0zLGZvbnQuc2l6ZT1jKDQsNSkscGFsZXR0ZSA9IGZ1bmN0aW9uKG4pIHNhbXBsZShyYWluYm93KG4scz0wLjksdj0wLjkpKSxib3gucGFkZGluZz0wLjUpKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9IDEsIHNpemU9MC4yLGxpbmV0eXBlPTEpLGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkscGxvdC5tYXJnaW4gPSBtYXJnaW4oLjEsIC4xLCAuMSwgLjEsICJjbSIpKQpwZGYoZmlsZT0nZnBfY2VsbHR5cGVzLnBkZicsd2lkdGg9MyxoZWlnaHQ9Myk7IHByaW50KGExKTsgZGV2Lm9mZigpCmExCmBgYAoKQ2x1c3RlcnMgYW5kIG1hcmtlcnM6CgoKYGBge3IgZmlnLndpZHRoPTQsZmlnLmhlaWdodD00fQpwbHN0IDwtIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9IDEsIHNpemU9MC4yLGxpbmV0eXBlPTEpLGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkscGxvdC5tYXJnaW4gPSBtYXJnaW4oLjEsIC4xLCAuMSwgLjEsICJjbSIpKTsKc2V0LnNlZWQoMCkKYTIgPC0gY29ub3M6OmVtYmVkZGluZ1Bsb3QociRlbWJlZGRpbmdzJFBDQSR0U05FLGdyb3Vwcz1tY2wsc2l6ZT0wLjEsYWxwaGE9MC4yLHJhc3Rlcj1ULHJhc3Rlci5oZWlnaHQgPSAzLHJhc3Rlci53aWR0aD0zLGZvbnQuc2l6ZT1jKDUuNSkscGFsZXR0ZSA9IGZ1bmN0aW9uKG4pIHJhaW5ib3cobixzPTAuNyx2PTAuNykpK3Bsc3QKCmEzIDwtIGNvbm9zOjplbWJlZGRpbmdQbG90KHIkZW1iZWRkaW5ncyRQQ0EkdFNORSxjb2xvcnM9cGFnb2RhMjo6OnZhbDJjb2wociRjb3VudHNbLCJFcGNhbSJdKSxzaXplPTAuMSxhbHBoYT0wLjUscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoMyw0KSkrcGxzdCsgYW5ub3RhdGUoJ3RleHQnLHg9LUluZix5PUluZixoanVzdD0wLHZqdXN0PTEuMixsYWJlbD0nRXBjYW0nLHNpemU9NikKYTQgPC0gY29ub3M6OmVtYmVkZGluZ1Bsb3QociRlbWJlZGRpbmdzJFBDQSR0U05FLGNvbG9ycz1wYWdvZGEyOjo6dmFsMmNvbChyJGNvdW50c1ssIkNvbDNhMSJdKSxzaXplPTAuMSxhbHBoYT0wLjUscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoMyw0KSkrcGxzdCsgYW5ub3RhdGUoJ3RleHQnLHg9LUluZix5PUluZixoanVzdD0wLHZqdXN0PTEuMixsYWJlbD0nQ29sM2ExJyxzaXplPTYpCmE1IDwtIGNvbm9zOjplbWJlZGRpbmdQbG90KHIkZW1iZWRkaW5ncyRQQ0EkdFNORSxjb2xvcnM9cGFnb2RhMjo6OnZhbDJjb2wociRjb3VudHNbLCJNa2k2NyJdKSxzaXplPTAuMSxhbHBoYT0wLjUscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoMyw0KSkrcGxzdCsgYW5ub3RhdGUoJ3RleHQnLHg9LUluZix5PUluZixoanVzdD0wLHZqdXN0PTEuMixsYWJlbD0nTWtpNjcnLHNpemU9NikKcHAgPC0gcGxvdF9ncmlkKHBsb3RsaXN0PWxpc3QoYTIsYTMsYTQsYTUpLG5yb3c9MikKcGRmKGZpbGU9J2ZwX3BhbmVscy5wZGYnLHdpZHRoPTQsaGVpZ2h0PTQpOyBwcmludChwcCk7IGRldi5vZmYoKTsKcHAKYGBgCgpgYGB7cn0KbWNsMiA8LSBzZXROYW1lcyhhcy5jaGFyYWN0ZXIobWNsKSxuYW1lcyhtY2wpKQptY2wyW2lzLm5hKG1jbDIpXSA8LSAnICcKbWNsMiA8LSBhcy5mYWN0b3IobWNsMikKYGBgCgpgYGB7ciBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTJ9CnBsc3QgPC0gdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gMSwgc2l6ZT0wLjIsbGluZXR5cGU9MSksYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSxwbG90Lm1hcmdpbiA9IG1hcmdpbiguMSwgLjEsIC4xLCAuMSwgImNtIikpOwpzZXQuc2VlZCgwKQphMiA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJHRTTkUsZ3JvdXBzPW1jbDIsc2l6ZT0wLjIsYWxwaGE9MC4yLHJhc3Rlcj1ULG1hcmsuZ3JvdXBzPUYscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoNS41KSxwYWxldHRlID0gZnVuY3Rpb24obikgYygnZ3JheTYwJyxyYWluYm93KG4tMSxzPTAuNyx2PTAuNykpKStwbHN0CgphMyA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJHRTTkUsY29sb3JzPXBhZ29kYTI6Ojp2YWwyY29sKHIkY291bnRzWywiRXBjYW0iXSksc2l6ZT0wLjEsYWxwaGE9MC41LHJhc3Rlcj1ULHJhc3Rlci5oZWlnaHQgPSAzLHJhc3Rlci53aWR0aD0zLGZvbnQuc2l6ZT1jKDMsNCkpK3Bsc3QrIGFubm90YXRlKCd0ZXh0Jyx4PS1JbmYseT1JbmYsaGp1c3Q9MCx2anVzdD0xLjIsbGFiZWw9J0VwY2FtJyxzaXplPTYpCmE0IDwtIGNvbm9zOjplbWJlZGRpbmdQbG90KHIkZW1iZWRkaW5ncyRQQ0EkdFNORSxjb2xvcnM9cGFnb2RhMjo6OnZhbDJjb2wociRjb3VudHNbLCJDb2wzYTEiXSksc2l6ZT0wLjEsYWxwaGE9MC41LHJhc3Rlcj1ULHJhc3Rlci5oZWlnaHQgPSAzLHJhc3Rlci53aWR0aD0zLGZvbnQuc2l6ZT1jKDMsNCkpK3Bsc3QrIGFubm90YXRlKCd0ZXh0Jyx4PS1JbmYseT1JbmYsaGp1c3Q9MCx2anVzdD0xLjIsbGFiZWw9J0NvbDNhMScsc2l6ZT02KQphNSA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJHRTTkUsY29sb3JzPXBhZ29kYTI6Ojp2YWwyY29sKHIkY291bnRzWywiTWtpNjciXSksc2l6ZT0wLjEsYWxwaGE9MC41LHJhc3Rlcj1ULHJhc3Rlci5oZWlnaHQgPSAzLHJhc3Rlci53aWR0aD0zLGZvbnQuc2l6ZT1jKDMsNCkpK3Bsc3QrIGFubm90YXRlKCd0ZXh0Jyx4PS1JbmYseT1JbmYsaGp1c3Q9MCx2anVzdD0xLjIsbGFiZWw9J01raTY3JyxzaXplPTYpCnBwIDwtIHBsb3RfZ3JpZChwbG90bGlzdD1saXN0KGEyLGEzLGE0LGE1KSxucm93PTEpCnBkZihmaWxlPSdmcF9wYW5lbHMyLnBkZicsd2lkdGg9OCxoZWlnaHQ9Mik7IHByaW50KHBwKTsgZGV2Lm9mZigpOwpwcApgYGAKCkNvbWJpbmVkIGZpZ3VyZQpgYGB7ciBmaWcud2lkdGg9MTUsZmlnLmhlaWdodD0zfQpwbHN0IDwtIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9IDEsIHNpemU9MC4yLGxpbmV0eXBlPTEpLGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkscGxvdC5tYXJnaW4gPSBtYXJnaW4oLjEsIC4xLCAuMSwgLjEsICJjbSIpKTsKYW5uLnNpemUgPC0gNzsKZW1iIDwtIHIkZW1iZWRkaW5ncyRQQ0EkdFNORQphMSA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChlbWIsZ3JvdXBzPWFzLmZhY3Rvcihhbm4pLHNpemU9MC4xLGFscGhhPTAuMixyYXN0ZXI9VCxyYXN0ZXIuaGVpZ2h0ID0gMyxyYXN0ZXIud2lkdGg9Myxmb250LnNpemU9YygzLjUsNS41KSkrcGxzdApzZXQuc2VlZCgwKQphMiA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChlbWIsZ3JvdXBzPW1jbCxzaXplPTAuMSxhbHBoYT0wLjIscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoNS41KSxwYWxldHRlID0gZnVuY3Rpb24obikgcmFpbmJvdyhuLHM9MC43LHY9MC43KSxwbG90Lm5hPUYpICt4bGltKHJhbmdlKGVtYlssMV0pKSt5bGltKHJhbmdlKGVtYlssMl0pKStwbHN0CgphMyA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJHRTTkUsY29sb3JzPXBhZ29kYTI6Ojp2YWwyY29sKHIkY291bnRzWywiRXBjYW0iXSksc2l6ZT0wLjEsYWxwaGE9MC41LHJhc3Rlcj1ULHJhc3Rlci5oZWlnaHQgPSAzLHJhc3Rlci53aWR0aD0zLGZvbnQuc2l6ZT1jKDMsNCkpK3Bsc3QrIGFubm90YXRlKCd0ZXh0Jyx4PS1JbmYseT1JbmYsaGp1c3Q9LTAuMSx2anVzdD0xLjIsbGFiZWw9J0VwY2FtJyxzaXplPWFubi5zaXplKQphNCA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJHRTTkUsY29sb3JzPXBhZ29kYTI6Ojp2YWwyY29sKHIkY291bnRzWywiQ29sM2ExIl0pLHNpemU9MC4xLGFscGhhPTAuNSxyYXN0ZXI9VCxyYXN0ZXIuaGVpZ2h0ID0gMyxyYXN0ZXIud2lkdGg9Myxmb250LnNpemU9YygzLDQpKStwbHN0KyBhbm5vdGF0ZSgndGV4dCcseD0tSW5mLHk9SW5mLGhqdXN0PS0wLjEsdmp1c3Q9MS4yLGxhYmVsPSdDb2wzYTEnLHNpemU9YW5uLnNpemUpCmE1IDwtIGNvbm9zOjplbWJlZGRpbmdQbG90KHIkZW1iZWRkaW5ncyRQQ0EkdFNORSxjb2xvcnM9cGFnb2RhMjo6OnZhbDJjb2wociRjb3VudHNbLCJNa2k2NyJdKSxzaXplPTAuMSxhbHBoYT0wLjUscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoMyw0KSkrcGxzdCsgYW5ub3RhdGUoJ3RleHQnLHg9LUluZix5PUluZixoanVzdD0tMC4xLHZqdXN0PTEuMixsYWJlbD0nTWtpNjcnLHNpemU9YW5uLnNpemUpCnBwIDwtIHBsb3RfZ3JpZChwbG90bGlzdD1saXN0KGExLGEyLGEzLGE0LGE1KSxucm93PTEpCnBkZihmaWxlPSdmcF9wYW5lbHNfd2lkZS5wZGYnLHdpZHRoPTE1LGhlaWdodD0zKTsgcHJpbnQocHApOyBkZXYub2ZmKCk7CnBwCmBgYAoKCgoKYGBge3IgZmlnLmhlaWdodD01LGZpZy53aWR0aD01fQpyJHBsb3RFbWJlZGRpbmcodHlwZSA9ICdQQ0EnLCBlbWJlZGRpbmcgPSAnbGFyZ2VWaXMnLCBncm91cHM9YW5uLCBtYXJrLmNsdXN0ZXJzID0gVCxhbHBoYT0wLjIsY2V4PTAuMiwgbWFyay5jbHVzdGVyLmNleCA9IDEpCmBgYAoKYGBge3IgZmlnLndpZHRoPTMsZmlnLmhlaWdodD0zfQphMSA8LSBjb25vczo6ZW1iZWRkaW5nUGxvdChyJGVtYmVkZGluZ3MkUENBJGxhcmdlVmlzLGdyb3Vwcz1yJGNsdXN0ZXJzJFBDQSRtdWx0aWxldmVsLHNpemU9MC4xLGFscGhhPTAuMixyYXN0ZXI9VCxyYXN0ZXIuaGVpZ2h0ID0gMyxyYXN0ZXIud2lkdGg9Myxmb250LnNpemU9YygzLDQpKSsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAxLCBzaXplPTAuMixsaW5ldHlwZT0xKSxheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpKQphMQpgYGAKCmBgYHtyIGZpZy53aWR0aD0zLGZpZy5oZWlnaHQ9M30KYTEgPC0gY29ub3M6OmVtYmVkZGluZ1Bsb3QociRlbWJlZGRpbmdzJFBDQSR0U05FLGdyb3Vwcz1hcy5mYWN0b3IoYW5uKSxzaXplPTAuMSxhbHBoYT0wLjIscmFzdGVyPVQscmFzdGVyLmhlaWdodCA9IDMscmFzdGVyLndpZHRoPTMsZm9udC5zaXplPWMoMyw0KSkrCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gMSwgc2l6ZT0wLjIsbGluZXR5cGU9MSksYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSkKYTEKYGBgCgo=