tissue_of_interest = "Liver"
library(here)
source("/restricted/projectnb/waxmanlab/kkarri/scRNAseq_data_integration/boilerplate.R")
#tiss = load_tissue_droplet(tissue_of_interest)
#library(scater)
library(dplyr)
library(Seurat)
library(cowplot)
#library(MAST)
########## function load_tissue_droplet############
droplet_metadata_G171B <- read.csv("/net/waxman-server/mnt/data/waxmanlabvm_home/kkarri/G171/Analysis/G171_metadata_droplet_liver.csv", sep=",", header = TRUE)
colnames(droplet_metadata_G171B)[1] <- "channel"
tissue_metadata_G171B = filter(droplet_metadata_G171B, tissue == tissue_of_interest)[,c('channel','tissue','subtissue','mouse.sex', 'mouse.id')]
raw.data <- Read10X("/net/waxman-server/mnt/data/waxmanlabvm_home/kkarri/G171/Analysis/Transcript_Refined/Liver-10X_G171B/")
#raw.data <- Read10X("/net/waxman-server/mnt/data/waxmanlabvm_home/kkarri/G171/Analysis/Transcript_downsampled_0.5/Liver-10X_G171B")
colnames(raw.data) <- lapply(colnames(raw.data), function(x) paste0(tissue_metadata_G171B$channel[1],'-',x))
meta.data1 = data.frame(row.names = colnames(raw.data))
meta.data1['channel'] = tissue_metadata_G171B$channel[1]
rnames = row.names(meta.data1)
meta.data1 <- merge(meta.data1, tissue_metadata_G171B, sort = F)
row.names(meta.data1) <- rnames
# Order the cells alphabetically to ensure consistency.
ordered_cell_names = order(colnames(raw.data))
raw.data = raw.data[,ordered_cell_names]
meta.data1 = meta.data1[ordered_cell_names,]
# Find ERCC's, compute the percent ERCC, and drop them from the raw data.
erccs <- grep(pattern = "^ERCC-", x = rownames(x = raw.data), value = TRUE)
percent.ercc <- Matrix::colSums(raw.data[erccs, ])/Matrix::colSums(raw.data)
ercc.index <- grep(pattern = "^ERCC-", x = rownames(x = raw.data), value = FALSE)
raw.data <- raw.data[-ercc.index,]
ncRNA.genes <- grep(pattern = "^ncRNA", x = rownames(x = raw.data), value = TRUE)
percent.ncRNA <- Matrix::colSums(raw.data[ncRNA.genes, ])/Matrix::colSums(raw.data)
KRAB.genes <- grep(pattern = "^KRAB", x = rownames(x = raw.data), value = TRUE)
cherry.genes <- grep(pattern = "^mcherry", x = rownames(x = raw.data), value = TRUE)
# Create the Seurat object with all the data
droplet <- CreateSeuratObject(raw.data) # dropseq
droplet <- AddMetaData(object = droplet, meta.data1)
droplet@meta.data$tech <- "G171B"
#droplet <- SubsetData(droplet,subset.names = c("nGene", "nUMI"), low.thresholds = c(500, 1000)) # old version of seurat
#droplet <- subset(droplet, subset = nFeature_RNA > 200 & nCount_RNA > 500)
droplet <- NormalizeData(droplet, verbose = FALSE)
droplet <- FindVariableFeatures(droplet, selection.method = "vst", nfeatures = 2000)
droplet$stim <- "G171B"
#lnc5998 <- subset(droplet, subset = `ncRNA-inter-chr7-5998` >1)
#lnc5998 <- NormalizeData(lnc5998, verbose = FALSE)
#lnc5998 <- FindVariableFeatures(lnc5998, selection.method = "vst", nfeatures = 2000)
#lnc5998$stim <- "lnc5998G171B"
### this is tranformation option for develpment SCtransform program #######
droplet <- SCTransform(droplet,verbose =TRUE)
droplet <- ScaleData(droplet, verbose = FALSE)
droplet <- RunPCA(droplet, npcs = 30, verbose = FALSE)
# t-SNE and Clustering
droplet <- RunUMAP(droplet, reduction = "pca", dims = 1:25)
droplet <- FindNeighbors(droplet, reduction = "pca", dims = 1:25)
droplet <- FindClusters(droplet, resolution = 1)
droplet <- RunTSNE(droplet, reduction = "pca", dims = 1:20)
pd1 <- UMAPPlot(droplet, reduction = "umap", group.by = "stim", label=TRUE, label.size=5)
pd1.1 <- UMAPPlot(droplet, reduction = "umap", split.by = "stim",label=TRUE, label.size=5)
pd2 <- UMAPPlot(droplet, reduction = "umap", group.by = "mouse.sex")
pd3 <- UMAPPlot(droplet, reduction = "umap", label = TRUE, label.size=3)
pd4 <- UMAPPlot(droplet, label=TRUE, label.size=6)
pd1 <- TSNEPlot(droplet, reduction = "tsne", label=TRUE, label.size=5)
DefaultAssay(droplet) <- "RNA"
droplet <- NormalizeData(droplet)
d1 <- DotPlot(droplet, features = all_genes)
lnc5998 <- SCTransform(lnc5998, verbose = TRUE)
####################### droplet G171C #######################################
droplet_metadata_G171C <- read.csv("/net/waxman-server/mnt/data/waxmanlabvm_home/kkarri/G171/Analysis/G171C_metadata_droplet_liver.csv", sep=",", header = TRUE)
colnames(droplet_metadata_G171C)[1] <- "channel"
tissue_metadata_G171C = filter(droplet_metadata_G171C, tissue == tissue_of_interest)[,c('channel','tissue','subtissue','mouse.sex', 'mouse.id')]
raw.data1 <- Read10X("/net/waxman-server/mnt/data/waxmanlabvm_home/kkarri/G171/Analysis/Transcript_Refined/Liver-10X_G171C/")
colnames(raw.data1) <- lapply(colnames(raw.data1), function(x) paste0(tissue_metadata_G171C$channel[1],'-',x))
meta.data = data.frame(row.names = colnames(raw.data1))
meta.data['channel'] = tissue_metadata_G171C$channel[1]
rnames = row.names(meta.data)
meta.data <- merge(meta.data, tissue_metadata_G171C, sort = F)
row.names(meta.data) <- rnames
# Order the cells alphabetically to ensure consistency.
ordered_cell_names1 = order(colnames(raw.data1))
raw.data1 = raw.data1[,ordered_cell_names1]
meta.data = meta.data[ordered_cell_names1,]
# Find ERCC's, compute the percent ERCC, and drop them from the raw data.
erccs1 <- grep(pattern = "^ERCC-", x = rownames(x = raw.data1), value = TRUE)
percent.ercc <- Matrix::colSums(raw.data1[erccs1, ])/Matrix::colSums(raw.data1)
ercc.index1 <- grep(pattern = "^ERCC-", x = rownames(x = raw.data1), value = FALSE)
raw.data1 <- raw.data1[-ercc.index1,]
# Create the Seurat object with all the data
droplet1 <- CreateSeuratObject(raw.data1) # dropseq
droplet1 <- AddMetaData(object = droplet1, meta.data)
droplet1@meta.data$tech <- "G171C"
#droplet <- SubsetData(droplet,subset.names = c("nGene", "nUMI"), low.thresholds = c(500, 1000)) # old version of seurat
#droplet1 <- subset(droplet1, subset = nFeature_RNA > 200 & nCount_RNA > 500)
droplet1 <- NormalizeData(droplet1, verbose = FALSE)
droplet1 <- FindVariableFeatures(droplet1, selection.method = "vst", nfeatures = 2000)
droplet1$stim <- "G171C"
droplet1 <- SCTransform(droplet1,verbose =TRUE)
###############################################################################
combined.features <- SelectIntegrationFeatures(object.list = list(droplet, droplet1), nfeatures = 2000)
combined.list <- PrepSCTIntegration(object.list = list(droplet, droplet1), anchor.features = combined.features,
verbose = TRUE)
combined.anchors <- FindIntegrationAnchors(object.list = combined.list, normalization.method = "SCT",anchor.features = combined.features, verbose = TRUE)
combined.integrated <- IntegrateData(anchorset = combined.anchors, normalization.method = "SCT", verbose = TRUE)
combined.integrated <- RunPCA(combined.integrated, verbose = FALSE)
combined.integrated <- RunUMAP(combined.integrated, dims = 1:30)
plots <- DimPlot(combined.integrated, group.by = c("stim", "mouse.sex"), combine = FALSE)
plots <- lapply(X = plots, FUN = function(x) x + theme(legend.position = "top") + guides(color = guide_legend(nrow = 3,
byrow = TRUE, override.aes = list(size = 3))))
CombinePlots(plots)
#######################3 option 2 standard workflow merging ################################
anchors <- FindIntegrationAnchors(object.list = list(droplet, droplet1), dims = 1:50, anchor.features = 3000)
#anchors <- FindIntegrationAnchors(object.list = list(lnc5998, droplet1), dims = 1:50, anchor.features = 3000)
combined <- IntegrateData(anchorset = anchors, dims = 1:50)
DefaultAssay(combined) <- "integrated"
# Run the standard workflow for visualization and clustering
combined <- ScaleData(combined, verbose = FALSE)
combined <- RunPCA(combined, npcs = 30, verbose = FALSE)
# t-SNE and Clustering
combined <- RunUMAP(combined, reduction = "pca", dims = 1:25)
combined <- FindNeighbors(combined, reduction = "pca", dims = 1:10)
combined <- FindClusters(combined, resolution = 0.5 )
combined <- RunTSNE(combined, reduction = "pca", dims = 1:20)
# Visualization
p1 <- UMAPPlot(combined, reduction = "umap", group.by = "stim", label=TRUE, label.size=5)
p1.1 <- UMAPPlot(combined, reduction = "umap", split.by = "stim",label=TRUE, label.size=5)
p2 <- UMAPPlot(combined, reduction = "umap", group.by = "mouse.sex")
p3 <- UMAPPlot(combined, reduction = "umap", label = TRUE, label.size=3)
p4 <- UMAPPlot(combined, label=TRUE, label.size=6)
plot_grid(p1, p4)
DimPlot(combined, reduction = "umap", split.by = "stim")
#cluster.averages <- AverageExpression(combined,use.counts = TRUE,)
p5 <- DimPlot(combined, reduction = "tsne", group.by = "stim")
p6 <- DimPlot(combined, reduction = "tsne", group.by = "mouse.sex")
p7 <- DimPlot(combined, reduction = "tsne", label = TRUE)
p8 <- TSNEPlot(combined, label =T)
plot_grid(p6, p7,p8)
DimPlot(combined, reduction = "tsne", split.by = "stim")
diffusion plt code
# Before running MDS, we first calculate a distance matrix between all pairs of cells. Here we
# use a simple euclidean distance metric on all genes, using scale.data as input
d <- dist(t(GetAssayData(combined, slot = "scale.data")))
# Run the MDS procedure, k determines the number of dimensions
mds <- cmdscale(d = d, k = 2)
# cmdscale returns the cell embeddings, we first label the columns to ensure downstream
# consistency
colnames(mds) <- paste0("MDS_", 1:2)
# We will now store this as a custom dimensional reduction called 'mds'
combined[["mds"]] <- CreateDimReducObject(embeddings = mds, key = "MDS_", assay = DefaultAssay(combined))
# We can now use this as you would any other dimensional reduction in all downstream functions
DimPlot(combined, reduction = "mds", pt.size = 0.5)
droplet_metadata <- read.csv("/restricted/projectnb/waxmanlab/kkarri/scRNAseq_data_integration/metadata_droplet_liver.csv", sep=",", header = TRUE)
colnames(droplet_metadata)[1] <- "channel"
tissue_metadata1 = filter(droplet_metadata, tissue == tissue_of_interest)[,c('channel','tissue','subtissue','mouse.sex', 'mouse.id')]
raw.data2 <- Read10X("/restricted/projectnb/waxmanlab/kkarri/scRNAseq_data_integration/Refined_cellmatrices/Liver-10X_P4_2/")
colnames(raw.data2) <- lapply(colnames(raw.data2), function(x) paste0(tissue_metadata1$channel[1],'_',x))
meta.data2 = data.frame(row.names = colnames(raw.data2))
meta.data2['channel'] = tissue_metadata1$channel[1]
if (length(tissue_metadata1$channel) > 1){
# Some tissues, like Thymus and Heart had only one channel
for(i in 2:nrow(tissue_metadata1)){
subfolder = paste0("/restricted/projectnb/waxmanlab/kkarri/scRNAseq_data_integration/Refined_cellmatrices/",tissue_of_interest, '-', tissue_metadata1$channel[i])
new.data1 <- Read10X(data.dir = subfolder)
colnames(new.data1) <- lapply(colnames(new.data1), function(x) paste0(tissue_metadata1$channel[i],'_', x))
new.metadata1 = data.frame(row.names = colnames(new.data1))
new.metadata1['channel'] = tissue_metadata1$channel[i]
raw.data2 = cbind(raw.data2, new.data1)
meta.data2 = rbind(meta.data2, new.metadata1) }}
rnames = row.names(meta.data2)
meta.data2 <- merge(meta.data2, tissue_metadata1, sort = F)
row.names(meta.data2) <- rnames
# Order the cells alphabetically to ensure consistency.
ordered_cell_names = order(colnames(raw.data2))
raw.data2 = raw.data2[,ordered_cell_names]
meta.data2 = meta.data2[ordered_cell_names,]
# Find ERCC's, compute the percent ERCC, and drop them from the raw data.
erccs <- grep(pattern = "^ERCC-", x = rownames(x = raw.data2), value = TRUE)
percent.ercc <- Matrix::colSums(raw.data2[erccs, ])/Matrix::colSums(raw.data2)
ercc.index <- grep(pattern = "^ERCC-", x = rownames(x = raw.data2), value = FALSE)
raw.data2 <- raw.data2[-ercc.index,]
# Create the Seurat object with all the data
droplet2 <- CreateSeuratObject(raw.data2) # dropseq
droplet2 <- AddMetaData(object = droplet2, meta.data2)
droplet2@meta.data$tech <- "droplet"
#droplet <- SubsetData(droplet,subset.names = c("nGene", "nUMI"), low.thresholds = c(500, 1000)) # old version of seurat
droplet2 <- subset(droplet2, subset = nFeature_RNA > 500 & nCount_RNA > 1000)
droplet2 <- NormalizeData(droplet2, verbose = FALSE)
droplet2 <- FindVariableFeatures(droplet2, selection.method = "vst", nfeatures = 2000)
droplet2$stim <- "control"
DefaultAssay(combined) <- "RNA"
#combined <- NormalizeData(combined, verbose = TRUE, normalization.method = "RC", scale.factor = 1e6)
combined <- NormalizeData(combined, verbose = TRUE)
# Normalize RNA data for visualization purposes if using sctranform
#combined.integrated <- NormalizeData(combined.integrated, verbose = FALSE)
DotPlot(combined, features = all_genes)
FeaturePlot(combined, features = genes_hep_main, min.cutoff = "q9")
#hepatocytes
subtissplot <- DotPlot(combined, features = c(genes_hep_main, genes_endo, genes_bec_b_immune, genes_kuppfer, genes_nk))
PC <- DotPlot(combined, features = c(genes_hep_main,genes_zones))
NPC <- DotPlot(combined, features = c(genes_endo,genes_kuppfer, genes_nk))
all <- DotPlot(combined, features=c(all_genes))
### coexpression plots####
f1 <- FeaturePlot(KO.cells, features = c('Cyp2b10','ncRNA-inter-chr7-5998'), reduction = "mds", order = TRUE,split.by = "stim", blend = TRUE,sort.cell = TRUE, max.cutoff = 0.5)
########## this is exact averaging formula ###############33
x <- (AverageExpression(KO.cells, verbose = TRUE, assays = "RNA" ,slot="counts")$RNA)
x["ncRNA-inter-chr7-5998",]
# G171B G171C
#ncRNA-inter-chr7-5998 1.871795 1.091463
########
#Idents(combined) <- factor(Idents(combined), levels = c(0,1,12))
markers.to.plot <- c("Alb","ncRNA-inter-chr7-5998")
DotPlot(combined, features = rev(markers.to.plot), cols = c("blue", "red"), dot.scale = 8,
split.by = "stim") + RotatedAxis()
FeaturePlot(combined, features = c("Alb", "ncRNA-inter-chr7-5998","Cyp2b10","dSaCas9","KRAB","AAV8-mCherry"), split.by = "stim", max.cutoff = 3, cols = c("grey", "red"))
######################### vlnplot ##########################
plots <- VlnPlot(combined, features = c("Alb", "ncRNA-inter-chr7-5998","Cyp2b10","dSaCas9"), split.by = "stim", group.by = "seurat_clusters", pt.size = 0, combine = FALSE)
CombinePlots(plots = plots, ncol = 1)
plots <- VlnPlot(combined, features = c("Lhx4","Dtna","Fam189a1","Galnt16","Kalrn"), split.by = "stim", group.by = "seurat_clusters", pt.size = 0, combine = FALSE)
CombinePlots(plots = plots, ncol = 1)
#endothelial
DotPlot(combined, features = genes_endo)
#zones
zones <- DotPlot(combined, features = genes_zones)
f1 <- FeaturePlot(combined, features = c('Cyp2e1','Cyp2f2','Ass1'), min.cutoff = "q9", reduction = "tsne")
DimPlot(combined, label = TRUE)
save(combined, file="Seurat_smart-drop_integrated.Robj")
################# save raw counts from cluster #####################
Idents(combined) <- "stim"
### to avergae out the matrix from KO cells
combined.raw.data.0.1 <- as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 0,idents = "stim")])
combined.raw.data.1 <- as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 0)])
combined.raw.data.2 <- as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 0)])
#combined.raw.data.[i] <- as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 1)])
#combined.raw.data.12 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 12)])
#combined.raw.data.1 <- as.matrix(GetAssayData(combined, slot = "counts"))
x <- AverageExpression(test.combined,assays = "RNA",add.ident = "stim", slot = "data",use.scale = FALSE, use.counts = FALSE)$RNA
#}######## CAR data
avg.combined.cells <- (AverageExpression(combined, verbose = FALSE)$RNA)
avg.combined.cells$gene <- rownames(avg.combined.cells)
CAR_FP <- FeaturePlot(combined, features = c('Cyp2b10','Nr1i3'), reduction = "umap", order = TRUE,split.by = "stim", blend = TRUE,sort.cell = TRUE, max.cutoff = 1, min.cutoff = 0, pt.size = 0.5, repel = TRUE)
CAR_DOT_NR <- DotPlot(combined, features = 'Nr1i3', col.min = 0)
Cyp2b10_FP <- FeaturePlot(combined, features = 'Cyp2b10', reduction = "umap", min.cutoff = 0)
########### tSNE #################################
combined <- NormalizeData(object = combined)
combined <- FindVariableFeatures(combined, selection.method = "vst", nfeatures = 2000)
KO.cells <- subset(combined, idents = c("0","1","12"))
Idents(KO.cells) <- "stim"
### to avergae out the matrix from KO cells
raw.data.0 <- as.matrix(GetAssayData(combined, slot = c("counts","data"))[, WhichCells(combined, ident = 0)])
raw.data.1 <- as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 1)])
raw.data.2 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 2)])
raw.data.3 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 3)])
raw.data.4 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 4)])
raw.data.5 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 5)])
raw.data.6 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 6)])
raw.data.7 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 7)])
raw.data.8 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 8)])
raw.data.9 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 9)])
raw.data.10 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 10)])
raw.data.11 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 11)])
raw.data.12 <-as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 12)])
TPMcount0<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 0)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 0)]))
TPMcount1<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 1)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 1)]))
TPMcount2<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 2)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 2)]))
TPMcount3<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 3)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 3)]))
TPMcount4<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 4)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 4)]))
TPMcount5<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 5)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 5)]))
TPMcount6<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 6)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 6)]))
TPMcount7<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 7)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 7)]))
TPMcount8<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 8)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 8)]))
TPMcount9<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 9)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 9)]))
TPMcount10<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 10)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 10)]))
TPMcount11<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 11)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 11)]))
TPMcount12<- cbind(as.matrix(GetAssayData(combined, slot = "counts")[, WhichCells(combined, ident = 12)]), as.matrix(GetAssayData(combined, slot = "data")[, WhichCells(combined, ident = 12)]))
write.csv(TPMcount0, "CountResult/counts.TPMcount0.csv")
write.csv(TPMcount1, "CountResult/counts.TPMcount1.csv")
write.csv(TPMcount2, "CountResult/counts.TPMcount2.csv")
write.csv(TPMcount3, "CountResult/counts.TPMcount3.csv")
write.csv(TPMcount4, "CountResult/counts.TPMcount4.csv")
write.csv(TPMcount5, "CountResult/counts.TPMcount5.csv")
write.csv(TPMcount6, "CountResult/counts.TPMcount6.csv")
write.csv(TPMcount7, "CountResult/counts.TPMcount7.csv")
write.csv(TPMcount8, "CountResult/counts.TPMcount8.csv")
write.csv(TPMcount9, "CountResult/counts.TPMcount9.csv")
write.csv(TPMcount10, "CountResult/counts.TPMcount10.csv")
write.csv(TPMcount11, "CountResult/counts.TPMcount11.csv")
write.csv(TPMcount12, "CountResult/counts.TPMcount12.csv")
#avg.KO.cells <- log1p(AverageExpression(KO.cells, verbose = FALSE)$RNA) #original code log transformed
avg.KO.cells <- (AverageExpression(KO.cells, verbose = FALSE)$RNA)
avg.KO.cells$gene <- rownames(avg.KO.cells)
genes.to.label= ("ncRNA-inter-chr7-5998")
#genes.to.label = c("ISG15", "LY6E", "IFI6", "ISG20", "MX1", "IFIT2", "IFIT1", "CXCL10", "CCL8")
p1 <- ggplot(avg.KO.cells, aes(CTRL, STIM)) + geom_point() + ggtitle("CD4 Naive T Cells")
p1 <- LabelPoints(plot = p1, points = genes.to.label, repel = TRUE)
p2 <- ggplot(avg.cd14.mono, aes(CTRL, STIM)) + geom_point() + ggtitle("CD14 Monocytes")
p2 <- LabelPoints(plot = p2, points = genes.to.label, repel = TRUE)
plot_grid(p1, p2)
DefaultAssay(combined) <- "RNA"
KO.cells.0 <- subset(combined, idents = c("0"))
Idents(KO.cells.0) <- "All0"
DefaultAssay(KO.cells.0) <- "RNA"
KO.cells.0.lnc5998 <- subset(KO.cells.0 , subset = `ncRNA-inter-chr7-5998` >0)
KO.cells.0.lnc5998 <- NormalizeData(KO.cells.0.lnc5998, verbose = FALSE)
KO.cells.0.lnc5998 <- FindVariableFeatures(KO.cells.0.lnc5998, selection.method = "vst", nfeatures = 2000)
KO.cells.0.lnc5998 <- ScaleData(KO.cells.0.lnc5998, verbose = FALSE)
KO.cells.0.lnc5998 <- RunPCA(KO.cells.0.lnc5998, npcs = 30, verbose = FALSE)
# t-SNE and Clustering
KO.cells.0.lnc5998 <- RunUMAP(KO.cells.0.lnc5998, reduction = "pca", dims = 1:20)
KO.cells.0.lnc5998 <- FindNeighbors(KO.cells.0.lnc5998, reduction = "pca", dims = 1:20)
KO.cells.0.lnc5998 <- FindClusters(KO.cells.0.lnc5998, resolution = 0.5)
KO.cells.0.lnc5998 <- RunTSNE(KO.cells.0.lnc5998, reduction = "pca", dims = 1:20)
# Visualization
p1 <- UMAPPlot(KO.cells.0.lnc5998, reduction = "umap", split.by = "tech", label=TRUE, label.size=5)
p1.1 <- UMAPPlot(KO.cells.0.lnc5998, reduction = "umap", group.by = "tech",label=TRUE, label.size=5)
p2 <- UMAPPlot(KO.cells.0.lnc5998, reduction = "umap", group.by = "mouse.sex")
p3 <- UMAPPlot(KO.cells.0.lnc5998, reduction = "umap", label = TRUE, label.size=3)
p4 <- UMAPPlot(KO.cells.0.lnc5998, label=TRUE, label.size=6)
KO.cell.0.lnc5998_DE1 <- FindMarkers(KO.cells.0.lnc5998, ident.1 = c(1,2), ident.2 = 0,verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.0.lnc5998_AllMarkers <- FindAllMarkers(KO.cells.0.lnc5998, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
KO.cell.0.lnc5998_AllMarkers %>% group_by(cluster) %>% top_n(2, avg_logFC)
write.csv(KO.cell.0.lnc5998_DE1, "Analysis/CountResult/Markers/KO.cell.0.lnc5998_DE1")
write.csv(KO.cell.0.lnc5998_AllMarkers, "Analysis/CountResult/Markers/KO.cell.0.lnc5998_AllMarkers")
KO.cells.0.lnc5998$celltype.stim <- paste(Idents(KO.cells.0.lnc5998), KO.cells.0.lnc5998$tech, sep = "_")
KO.cells.0.lnc5998$celltype <- Idents(KO.cells.0.lnc5998)
Idents(KO.cells.0.lnc5998) <- "celltype.stim"
#############3 KO cells that express lnc5998 #################
DefaultAssay(combined) <- "RNA"
KO.cells.1 <- subset(combined, idents = c("1"))
Idents(KO.cells.1) <- "All0"
DefaultAssay(KO.cells.0) <- "RNA"
KO.cells.1.lnc5998 <- subset(KO.cells.1 , subset = `ncRNA-inter-chr7-5998` >0)
KO.cells.1.lnc5998 <- NormalizeData(KO.cells.1.lnc5998, verbose = FALSE)
KO.cells.1.lnc5998 <- FindVariableFeatures(KO.cells.1.lnc5998, selection.method = "vst", nfeatures = 2000)
KO.cells.1.lnc5998 <- ScaleData(KO.cells.1.lnc5998, verbose = FALSE)
KO.cells.1.lnc5998 <- RunPCA(KO.cells.1.lnc5998, npcs = 30, verbose = FALSE)
# t-SNE and Clustering
KO.cells.1.lnc5998 <- RunUMAP(KO.cells.1.lnc5998, reduction = "pca", dims = 1:20)
KO.cells.1.lnc5998 <- FindNeighbors(KO.cells.1.lnc5998, reduction = "pca", dims = 1:20)
KO.cells.1.lnc5998 <- FindClusters(KO.cells.1.lnc5998, resolution = 0.5)
KO.cells.1.lnc5998 <- RunTSNE(KO.cells.1.lnc5998, reduction = "pca", dims = 1:20)
# Visualization
p11 <- UMAPPlot(KO.cells.1.lnc5998, reduction = "umap", split.by = "tech", label=TRUE, label.size=5)
p11.1 <- UMAPPlot(KO.cells.1.lnc5998, reduction = "umap", group.by = "tech",label=TRUE, label.size=5)
p11.2 <- UMAPPlot(KO.cells.1.lnc5998, reduction = "umap", label = TRUE, label.size=3)
KO.cells.1.lnc5998$celltype.stim <- paste(Idents(KO.cells.1.lnc5998), KO.cells.1.lnc5998$stim, sep = "_")
KO.cells.1.lnc5998$celltype <- Idents(KO.cells.1.lnc5998)
Idents(KO.cells.1.lnc5998) <- "celltype.stim"
KO.cell.1.lnc5998_DE1 <- FindMarkers(KO.cells.1.lnc5998, ident.1 = c('0_G171B','1_G171B'), ident.2 = c('0_G171C','1_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.lnc5998_DE2 <- FindMarkers(KO.cells.1.lnc5998, ident.1 = c('1_G171B'), ident.2 = c('0_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.lnc5998_DE3 <- FindMarkers(KO.cells.1.lnc5998, ident.1 = c('0_G171B'), ident.2 = c('0_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.lnc5998_AllMarkers <- FindAllMarkers(KO.cells.1.lnc5998, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
KO.cell.1.lnc5998_AllMarkers %>% group_by(cluster) %>% top_n(2, avg_logFC)
write.csv(KO.cell.1.lnc5998_DE1, "Analysis/CountResult/Markers/KO.cell.1.lnc5998_DE1")
write.csv(KO.cell.1.lnc5998_AllMarkers, "Analysis/CountResult/Markers/KO.cell.1.lnc5998_AllMarkers")
write.csv(KO.cell.1.lnc5998_DE2, "Analysis/CountResult/Markers/KO.cell.1.lnc5998_DE2_1-G171B_0-G171C")
write.csv(KO.cell.1.lnc5998_DE3, "Analysis/CountResult/Markers/KO.cell.1.lnc5998_DE3_0-G171B_0-G171C")
cell clusters 0 and cluster 1 from main UMAP that do not epxress lnc5998 in G171B and G171C
DefaultAssay(combined) <- "RNA"
KO.cells.0 <- subset(combined, idents = c("0"))
Idents(KO.cells.0) <- "All0"
DefaultAssay(KO.cells.0) <- "RNA"
KO.cells.0.null <- subset(KO.cells.0 , subset = `ncRNA-inter-chr7-5998`== 0)
KO.cells.0.null <- NormalizeData(KO.cells.0.null, verbose = FALSE)
KO.cells.0.null <- FindVariableFeatures(KO.cells.0.null, selection.method = "vst", nfeatures = 2000)
KO.cells.0.null <- ScaleData(KO.cells.0.null, verbose = FALSE)
KO.cells.0.null <- RunPCA(KO.cells.0.null, npcs = 30, verbose = FALSE)
# t-SNE and Clustering
KO.cells.0.null <- RunUMAP(KO.cells.0.null, reduction = "pca", dims = 1:20)
KO.cells.0.null <- FindNeighbors(KO.cells.0.null, reduction = "pca", dims = 1:20)
KO.cells.0.null <- FindClusters(KO.cells.0.null, resolution = 0.5)
KO.cells.0.null <- RunTSNE(KO.cells.0.null, reduction = "pca", dims = 1:20)
# Visualization
pnull1 <- UMAPPlot(KO.cells.0.null, reduction = "umap", split.by = "tech", label=TRUE, label.size=5)
pnull1.1 <- UMAPPlot(KO.cells.0.null, reduction = "umap", group.by = "tech",label=TRUE, label.size=5)
pnull2 <- UMAPPlot(KO.cells.0.null, reduction = "umap", group.by = "mouse.sex")
pnull3 <- UMAPPlot(KO.cells.0.null, reduction = "umap", label = TRUE, label.size=3)
pnull4 <- UMAPPlot(KO.cells.0.null, label=TRUE, label.size=6)
KO.cell.0.null_DE1 <- FindMarkers(KO.cells.0.null, ident.1 = c(1,2,3), ident.2 = 0,verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.0.null_AllMarkers <- FindAllMarkers(KO.cells.0.null, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
KO.cell.0.null_AllMarkers %>% group_by(cluster) %>% top_n(2, avg_logFC)
write.csv(KO.cell.0.null_DE1, "CountResult/Markers/KO_cell_0_null_DE1_All_G171B_vs_G171C")
write.csv(KO.cell.0.null_AllMarkers, "CountResult/Markers/KO_cell_0_null_AllMarkers")
KO.cells.0.null$celltype.stim <- paste(Idents(KO.cells.0.null), KO.cells.0.null$tech, sep = "_")
KO.cells.0.null$celltype <- Idents(KO.cells.0.null)
Idents(KO.cells.0.null) <- "celltype.stim"
#############3 KO cells that express lnc5998 #################
DefaultAssay(combined) <- "RNA"
KO.cells.1 <- subset(combined, idents = c("1"))
Idents(KO.cells.1) <- "All0"
DefaultAssay(KO.cells.1) <- "RNA"
KO.cells.1.null <- subset(KO.cells.1 , subset = `ncRNA-inter-chr7-5998` ==0)
KO.cells.1.null <- NormalizeData(KO.cells.1.null, verbose = FALSE)
KO.cells.1.null <- FindVariableFeatures(KO.cells.1.null, selection.method = "vst", nfeatures = 2000)
KO.cells.1.null <- ScaleData(KO.cells.1.null, verbose = FALSE)
KO.cells.1.null <- RunPCA(KO.cells.1.null, npcs = 30, verbose = FALSE)
# t-SNE and Clustering
KO.cells.1.null <- RunUMAP(KO.cells.1.null, reduction = "pca", dims = 1:20)
KO.cells.1.null <- FindNeighbors(KO.cells.1.null, reduction = "pca", dims = 1:20)
KO.cells.1.null <- FindClusters(KO.cells.1.null, resolution = 0.5)
KO.cells.1.null <- RunTSNE(KO.cells.1.null, reduction = "pca", dims = 1:20)
# Visualization
p11 <- UMAPPlot(KO.cells.1.null, reduction = "umap", split.by = "tech", label=TRUE, label.size=5)
p11.1 <- UMAPPlot(KO.cells.1.null, reduction = "umap", group.by = "tech",label=TRUE, label.size=5)
p11.2 <- UMAPPlot(KO.cells.1.null, reduction = "umap", label = TRUE, label.size=3)
KO.cells.1.null$celltype.stim <- paste(Idents(KO.cells.1.null), KO.cells.1.null$stim, sep = "_")
KO.cells.1.null$celltype <- Idents(KO.cells.1.null)
Idents(KO.cells.1.null) <- "celltype.stim"
KO.cell.1.null_DE1 <- FindMarkers(KO.cells.1.null, ident.1 = c('0_G171B','1_G171B'), ident.2 = c('0_G171C','1_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.null_DE2 <- FindMarkers(KO.cells.1.null, ident.1 = c('1_G171B'), ident.2 = c('1_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.null_DE3 <- FindMarkers(KO.cells.1.null, ident.1 = c('0_G171B'), ident.2 = c('0_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.null_DE4 <- FindMarkers(KO.cells.1.null, ident.1 = c('1_G171B'), ident.2 = c('0_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.null_DE5 <- FindMarkers(KO.cells.1.null, ident.1 = c('0_G171B'), ident.2 = c('1_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.null_AllMarkers <- FindAllMarkers(KO.cells.1.null, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
KO.cell.1.null_AllMarkers %>% group_by(cluster) %>% top_n(2, avg_logFC)
write.csv(KO.cell.1.null_DE1, "CountResult/Markers/KO_cell_1_null_DE1_all_G171B_vs_G171C")
write.csv(KO.cell.1.null_AllMarkers, "CountResult/Markers/KO.cell.1.null_AllMarkers")
write.csv(KO.cell.1.null_DE2, "CountResult/Markers/KO_cell_1_null_DE2_1-G171B_1-G171C")
write.csv(KO.cell.1.null_DE3, "CountResult/Markers/KO_cell_1_null_DE3_0-G171B_0-G171C")
write.csv(KO.cell.1.null_DE4, "CountResult/Markers/KO_cell_1_null_DE4_1-G171B_0-G171C")
write.csv(KO.cell.1.null_DE5, "CountResult/Markers/KO_cell_1_null_DE5_0-G171B_1-G171C")
All cell clusters that express lnc5998
DefaultAssay(combined) <- "RNA"
KO.cells.1.all <- subset(combined, idents = c("1"))
Idents(KO.cells.1) <- "All1"
DefaultAssay(KO.cells.1.all) <- "RNA"
KO.cells.1.all <- NormalizeData(KO.cells.1.all, verbose = FALSE)
KO.cells.1.all <- FindVariableFeatures(KO.cells.1.all, selection.method = "vst", nfeatures = 2000)
KO.cells.1.all <- ScaleData(KO.cells.1.all, verbose = FALSE)
KO.cells.1.all <- RunPCA(KO.cells.1.all, npcs = 30, verbose = FALSE)
# t-SNE and Clustering
KO.cells.1.all <- RunUMAP(KO.cells.1.all, reduction = "pca", dims = 1:20)
KO.cells.1.all <- FindNeighbors(KO.cells.1.all, reduction = "pca", dims = 1:20)
KO.cells.1.all <- FindClusters(KO.cells.1.all, resolution = 0.5)
KO.cells.1.all <- RunTSNE(KO.cells.1.all, reduction = "pca", dims = 1:20)
# Visualization
pall1 <- UMAPPlot(KO.cells.1.all, reduction = "umap", split.by = "tech", label=TRUE, label.size=5)
pall1.1 <- UMAPPlot(KO.cells.1.all, reduction = "umap", group.by = "tech",label=TRUE, label.size=5)
pall1.2 <- UMAPPlot(KO.cells.1.all, reduction = "umap", label = TRUE, label.size=3)
KO.cells.1.all$celltype.stim <- paste(Idents(KO.cells.1.all), KO.cells.1.all$stim, sep = "_")
KO.cells.1.all$celltype <- Idents(KO.cells.1.all)
Idents(KO.cells.1.all) <- "celltype.stim"
KO.cell.1.all_DE1 <- FindMarkers(KO.cells.1.all, ident.1 = c('0_G171B','1_G171B', '2_G171B','3_G171B'), ident.2 = c('0_G171C','1_G171C','2_G171C','3_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.all_DE2 <- FindMarkers(KO.cells.1.all, ident.1 = c('1_G171B'), ident.2 = c('1_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.all_DE3 <- FindMarkers(KO.cells.1.all, ident.1 = c('0_G171B'), ident.2 = c('0_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.all_DE4 <- FindMarkers(KO.cells.1.all, ident.1 = c('1_G171B'), ident.2 = c('0_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.all_DE5 <- FindMarkers(KO.cells.1.all, ident.1 = c('0_G171B'), ident.2 = c('1_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.1.all_AllMarkers <- FindAllMarkers(KO.cells.1.all, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
KO.cell.1.all_AllMarkers %>% group_by(cluster) %>% top_n(2, avg_logFC)
write.csv(KO.cell.1.all_DE1, "CountResult/Markers/KO_cell_1_all_DE1_all_G171B_vs_G171C")
write.csv(KO.cell.1.all_AllMarkers, "CountResult/Markers/KO.cell.1.all_AllMarkers")
write.csv(KO.cell.1.all_DE2, "CountResult/Markers/KO_cell_1_all_DE2_1-G171B_1-G171C")
write.csv(KO.cell.1.all_DE3, "CountResult/Markers/KO_cell_1_all_DE3_0-G171B_0-G171C")
write.csv(KO.cell.1.all_DE4, "CountResult/Markers/KO_cell_1_all_DE4_1-G171B_0-G171C")
write.csv(KO.cell.1.all_DE5, "CountResult/Markers/KO_cell_1_all_DE5_0-G171B_1-G171C")
###################3 cluster 00 ####################
DefaultAssay(combined) <- "RNA"
KO.cells.0.all <- subset(combined, idents = c("0"))
Idents(KO.cells.0.all) <- "All0"
DefaultAssay(KO.cells.0.all) <- "RNA"
KO.cells.0.all <- NormalizeData(KO.cells.0.all, verbose = FALSE)
KO.cells.0.all <- FindVariableFeatures(KO.cells.0.all, selection.method = "vst", nfeatures = 2000)
KO.cells.0.all <- ScaleData(KO.cells.0.all, verbose = FALSE)
KO.cells.0.all <- RunPCA(KO.cells.0.all, npcs = 30, verbose = FALSE)
# t-SNE and Clustering
KO.cells.0.all <- RunUMAP(KO.cells.0.all, reduction = "pca", dims = 1:20)
KO.cells.0.all <- FindNeighbors(KO.cells.0.all, reduction = "pca", dims = 1:20)
KO.cells.0.all <- FindClusters(KO.cells.0.all, resolution = 0.5)
KO.cells.0.all <- RunTSNE(KO.cells.0.all, reduction = "pca", dims = 1:20)
# Visualization
pall01 <- UMAPPlot(KO.cells.0.all, reduction = "umap", split.by = "tech", label=TRUE, label.size=5)
pall0.1 <- UMAPPlot(KO.cells.0.all, reduction = "umap", group.by = "tech",label=TRUE, label.size=5)
pall0.2 <- UMAPPlot(KO.cells.0.all, reduction = "umap", group.by = "mouse.sex")
pall0.3 <- UMAPPlot(KO.cells.0.all, reduction = "umap", label = TRUE, label.size=3)
pall0.4 <- UMAPPlot(KO.cells.0.all, label=TRUE, label.size=6)
KO.cell.0.all_DE1 <- FindMarkers(KO.cells.0.all, ident.1 = c('0_G171B','1_G171B','2_G171B','3_G171B','4_G171B'), ident.2 = c('0_G171C','2_G171C'),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.0.all_AllMarkers <- FindAllMarkers(KO.cells.0.all, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
KO.cell.0.all_AllMarkers %>% group_by(cluster) %>% top_n(2, avg_logFC)
write.csv(KO.cell.0.all_DE1, "CountResult/Markers/KO_cell_0_all_DE1_All_G171B_vs_G171C")
write.csv(KO.cell.0.all_AllMarkers, "CountResult/Markers/KO_cell_0_all_AllMarkers")
KO.cells.0.all$celltype.stim <- paste(Idents(KO.cells.0.all), KO.cells.0.all$tech, sep = "_")
KO.cells.0.all$celltype <- Idents(KO.cells.0.all)
Idents(KO.cells.0.all) <- "celltype.stim"
######################### cluster 2 ##############################
DefaultAssay(combined) <- "RNA"
KO.cells.2.all <- subset(combined, idents = c("2"))
Idents(KO.cells.2.all) <- "All2"
DefaultAssay(KO.cells.2.all) <- "RNA"
KO.cells.2.all <- NormalizeData(KO.cells.2.all, verbose = FALSE)
KO.cells.2.all <- FindVariableFeatures(KO.cells.2.all, selection.method = "vst", nfeatures = 2000)
KO.cells.2.all <- ScaleData(KO.cells.2.all, verbose = FALSE)
KO.cells.2.all <- RunPCA(KO.cells.2.all, npcs = 30, verbose = FALSE)
# t-SNE and Clustering
KO.cells.2.all <- RunUMAP(KO.cells.2.all, reduction = "pca", dims = 1:20)
KO.cells.2.all <- FindNeighbors(KO.cells.2.all, reduction = "pca", dims = 1:20)
KO.cells.2.all <- FindClusters(KO.cells.2.all, resolution = 0.5)
KO.cells.2.all <- RunTSNE(KO.cells.2.all, reduction = "pca", dims = 1:20)
# Visualization
pall21 <- UMAPPlot(KO.cells.2.all, reduction = "umap", split.by = "tech", label=TRUE, label.size=5)
pall2.1 <- UMAPPlot(KO.cells.2.all, reduction = "umap", group.by = "tech",label=TRUE, label.size=5)
pall2.2 <- UMAPPlot(KO.cells.2.all, reduction = "umap", group.by = "mouse.sex")
pall2.3 <- UMAPPlot(KO.cells.2.all, reduction = "umap", label = TRUE, label.size=3)
pall2.4 <- UMAPPlot(KO.cells.2.all, label=TRUE, label.size=6)
KO.cell.2.all_DE1 <- FindMarkers(KO.cells.2.all, ident.1 = c(1,2,3), ident.2 = 0,verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cell.2.all_AllMarkers <- FindAllMarkers(KO.cells.2.all, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
KO.cell.2.all_AllMarkers %>% group_by(cluster) %>% top_n(2, avg_logFC)
write.csv(KO.cell.2.all_DE1, "CountResult/Markers/KO_cell_0_all_DE1_All_G171B_vs_G171C")
write.csv(KO.cell.2.all_AllMarkers, "CountResult/Markers/KO_cell_0_all_AllMarkers")
KO.cells.2.all$celltype.stim <- paste(Idents(KO.cells.2.all), KO.cells.2.all$tech, sep = "_")
KO.cells.2.all$celltype <- Idents(KO.cells.2.all)
Idents(KO.cells.2.all) <- "celltype.stim"
droplet_metadata <- read.csv("/restricted/projectnb/waxmanlab/kkarri/scRNAseq_data_integration/metadata_droplet_liver.csv", sep=",", header = TRUE)
colnames(droplet_metadata)[1] <- "channel"
tissue_metadata = filter(droplet_metadata, tissue == tissue_of_interest)[,c('channel','tissue','subtissue','mouse.sex', 'mouse.id')]
raw.data <- Read10X("/restricted/projectnb/waxmanlab/kkarri/scRNAseq_data_integration/Refined_cellmatrices/Liver-10X_P4_2/")
colnames(raw.data) <- lapply(colnames(raw.data), function(x) paste0(tissue_metadata$channel[1],'_',x))
meta.data1 = data.frame(row.names = colnames(raw.data))
meta.data1['channel'] = tissue_metadata$channel[1]
if (length(tissue_metadata$channel) > 1){
# Some tissues, like Thymus and Heart had only one channel
for(i in 2:nrow(tissue_metadata)){
subfolder = paste0("/restricted/projectnb/waxmanlab/kkarri/scRNAseq_data_integration/Refined_cellmatrices/",tissue_of_interest, '-', tissue_metadata$channel[i])
new.data1 <- Read10X(data.dir = subfolder)
colnames(new.data1) <- lapply(colnames(new.data1), function(x) paste0(tissue_metadata$channel[i],'_', x))
new.metadata1 = data.frame(row.names = colnames(new.data1))
new.metadata1['channel'] = tissue_metadata$channel[i]
raw.data = cbind(raw.data, new.data1)
meta.data1 = rbind(meta.data1, new.metadata1)
}
}
rnames = row.names(meta.data1)
meta.data1 <- merge(meta.data1, tissue_metadata, sort = F)
row.names(meta.data1) <- rnames
# Order the cells alphabetically to ensure consistency.
ordered_cell_names = order(colnames(raw.data))
raw.data = raw.data[,ordered_cell_names]
meta.data1 = meta.data1[ordered_cell_names,]
# Find ERCC's, compute the percent ERCC, and drop them from the raw data.
erccs <- grep(pattern = "^ERCC-", x = rownames(x = raw.data), value = TRUE)
percent.ercc <- Matrix::colSums(raw.data[erccs, ])/Matrix::colSums(raw.data)
ercc.index <- grep(pattern = "^ERCC-", x = rownames(x = raw.data), value = FALSE)
raw.data <- raw.data[-ercc.index,]
# Create the Seurat object with all the data
droplet <- CreateSeuratObject(raw.data) # dropseq
droplet <- AddMetaData(object = droplet, meta.data1)
droplet@meta.data$tech <- "droplet"
#n.pcs = 10
#droplet <- SubsetData(droplet,subset.names = c("nGene", "nUMI"), low.thresholds = c(500, 1000)) # old version of seurat
droplet <- subset(droplet, subset = nFeature_RNA > 500 & nCount_RNA > 1000)
droplet <- NormalizeData(droplet, verbose = FALSE)
droplet <- FindVariableFeatures(droplet, selection.method = "vst", nfeatures = 2000)
droplet <- ScaleData(droplet, verbose = FALSE)
#droplet <- RunPCA(droplet, npcs = 10, verbose = FALSE)
droplet$stim <- "droplet"
# droplet <- ScaleData(droplet, verbose = FALSE)
droplet <- RunPCA(droplet, npcs = 30, verbose = FALSE)
droplet <- RunUMAP(droplet, reduction = "pca", dims = 1:25)
droplet <- FindNeighbors(droplet, reduction = "pca", dims = 1:10)
droplet <- FindClusters(droplet, resolution = 0.5 )
p1<- UMAPPlot(droplet, reduction = "umap", group.by = "channel", label=TRUE, label.size=5)
p2 <- UMAPPlot(droplet, label=TRUE, label.size=6)
p3<- UMAPPlot(droplet, reduction = "umap", group.by = "mouse.sex", label=TRUE, label.size=5)
res.used <- 1
droplet <- FindClusters(object = droplet, reduction.type = "pca", dims.use = 1:n.pcs, resolution = res.used, print.output = 0, save.SNN = TRUE, force.recalc = TRUE)
droplet <- RunTSNE(object = droplet, dims.use = 1:n.pcs, seed.use = 10, perplexity=30)
TSNEPlot(object = droplet, do.label = T, pt.size = 1.2, label.size = 4)
KO.cells$celltype.stim <- paste(Idents(KO.cells), KO.cells$stim, sep = "_")
KO.cells$celltype <- Idents(KO.cells)
Idents(KO.cells) <- "celltype.stim"
response3 <- FindMarkers(KO.cells, ident.1 = c("1_G171B","0_G171B","2_G171B"), ident.2 = c("1_G171C", "0_G171C","2_G171C"), verbose = TRUE, test.use = "MAST", logfc.threshold = FALSE,min.pct = FALSE)
head(response3, n = 15)
KO.cell.0.lnc5998_DE1 <- FindMarkers(KO.cells.0.lnc5998, ident.1 = "4_G171C", ident.2 = "4_G171B",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
KO.cells.1 <- subset(combined, idents = c("1"))
Idents(KO.cells.1) <- "All1"
```
KO.cells <- RunUMAP(KO.cells, reduction = "pca", dims = 1:20 )
KO.cells <- FindNeighbors(KO.cells, reduction = "pca", dims = 1:20)
KO.cells <- FindClusters(KO.cells, resolution = 0.5 )
KO.cells <- RunTSNE(KO.cells, reduction = "pca", dims = 1:20)
Hep.cells <- RunUMAP(Hep.cells, reduction = "pca", dims = 1:20 )
Hep.cells <- FindNeighbors(Hep.cells, reduction = "pca", dims = 1:20)
Hep.cells <- FindClusters(Hep.cells, resolution = 0.5 )
Hep.cells <- RunTSNE(Hep.cells, reduction = "pca", dims = 1:20)
# Visualization
p1 <- UMAPPlot(KO.cells, reduction = "umap", group.by = "stim")
p2 <- UMAPPlot(KO.cells, reduction = "umap", group.by = "mouse.sex")
p3 <- UMAPPlot(KO.cells, reduction = "umap", label = TRUE)
p4 <- UMAPPlot(KO.cells, label=TRUE)
plot_grid(p1,p4)
DimPlot(KO.cells, reduction = "umap", split.by = "stim")
#hepatocyte cells
p5 <- UMAPPlot(Hep.cells, reduction = "umap", group.by = "stim")
p6 <- UMAPPlot(Hep.cells, reduction = "umap", group.by = "mouse.sex")
p7 <- UMAPPlot(Hep.cells, reduction = "umap", label = TRUE)
p8 <- UMAPPlot(Hep.cells, label=TRUE)
plot_grid(p5,p8)
DimPlot(KO.cells, reduction = "umap", split.by = "stim")
raw.data.KO.0 <- as.matrix(GetAssayData(KO.cells, slot = "counts")[, WhichCells(KO.cells, ident = 0)])
raw.data.KO.1 <- as.matrix(GetAssayData(KO.cells, slot = "counts")[, WhichCells(KO.cells, ident = 1)])
raw.data.KO.2 <-as.matrix(GetAssayData(KO.cells, slot = "counts")[, WhichCells(KO.cells, ident = 2)])
raw.data.KO.3 <-as.matrix(GetAssayData(KO.cells, slot = "counts")[, WhichCells(KO.cells, ident = 3)])
raw.data.KO.4 <-as.matrix(GetAssayData(KO.cells, slot = "counts")[, WhichCells(KO.cells, ident = 4)])
raw.data.KO.5 <-as.matrix(GetAssayData(KO.cells, slot = "counts")[, WhichCells(KO.cells, ident = 5)])
write.csv(raw.data.KO.0, "CountResult/Markers/raw.data.KO.0")
write.csv(raw.data.KO.1, "CountResult/Markers/raw.data.KO.1")
write.csv(raw.data.KO.2, "CountResult/Markers/raw.data.KO.2")
write.csv(raw.data.KO.3, "CountResult/Markers/raw.data.KO.3")
write.csv(raw.data.KO.4, "CountResult/Markers/raw.data.KO.4")
write.csv(raw.data.KO.5, "CountResult/Markers/raw.data.KO.5")
f1 <- FeaturePlot(KO.cells, features = c('ncRNA-inter-chr7-5998'), reduction = "umap", split.by = "stim")
plot_grid(f1,p1,p4)
DefaultAssay(KO.cells) <- "RNA"
KO.cells <- NormalizeData(KO.cells, verbose = FALSE)
plots <- VlnPlot(KO.cells, features = c("Alb", "ncRNA-inter-chr7-5998","Cyp2b10","Cyp2e1","Cyp2f2"), split.by = "stim", group.by = "seurat_clusters", pt.size = 0, combine = FALSE)
CombinePlots(plots = plots, ncol = 1)
Three_five_six <- subset(KO.cells, idents = c("5","6"))
Three_five_six <- RunUMAP(Three_five_six, reduction = "pca", dims = 1:20 )
Three_five_six <- FindNeighbors(Three_five_six, reduction = "pca", dims = 1:20)
Three_five_six <- FindClusters(Three_five_six, resolution = 1 )
Three_five_six <- RunTSNE(Three_five_six, reduction = "pca", dims = 1:20)
p1 <- UMAPPlot(Three_five_six, reduction = "umap", group.by = "stim")
p2 <- UMAPPlot(Three_five_six, reduction = "umap", group.by = "mouse.sex")
p3 <- UMAPPlot(Three_five_six, reduction = "umap", label = TRUE)
p4 <- UMAPPlot(Three_five_six, label=TRUE)
plot_grid(p1,p4)
DimPlot(Three_five_six, reduction = "umap", split.by = "stim")
f1 <- FeaturePlot(Three_five_six, features = c('ncRNA-inter-chr7-5998'), reduction = "umap", split.by = "stim")
lnc5998 <- subset(combined, cells = lnc5998.cells, idents = "1")
lnc5998 <- RunUMAP(lnc5998, reduction = "pca", dims = 1:20 )
lnc5998 <- FindNeighbors(lnc5998, reduction = "pca", dims = 1:20)
lnc5998 <- FindClusters(lnc5998, resolution = 1 )
lnc5998 <- RunTSNE(lnc5998, reduction = "pca", dims = 1:20)
# Visualization
p1 <- UMAPPlot(lnc5998, reduction = "umap", group.by = "stim")
p2 <- UMAPPlot(lnc5998, reduction = "umap", group.by = "mouse.sex")
p3 <- UMAPPlot(lnc5998, reduction = "umap", label = TRUE)
p4 <- UMAPPlot(lnc5998, label=TRUE)
plot_grid(p1,p4)
DimPlot(lnc5998, reduction = "umap", split.by = "stim")
lnc5998.cells <- WhichCells(object = combined, expression = "ncRNA-inter-chr7-5998" > 1)
FeaturePlot(lnc5998, features = c("ncRNA-inter-chr7-5998"), split.by = "stim",
+ cols = c("grey", "red"), cells = lnc5998.cells,min.cutoff = 0.5)
DefaultAssay(lnc5998) <- "RNA"
lnc5998 <- NormalizeData(lnc5998, verbose = FALSE)
plots <- VlnPlot(lnc5998, features = c("Alb", "ncRNA-inter-chr7-5998","Cyp2b10","Cyp2e1","Cyp2f2"), split.by = "stim", group.by = "seurat_clusters", pt.size = 0, combine = FALSE)
CombinePlots(plots = plots, ncol = 1)
d <- dist(t(GetAssayData(KO.cells, slot = "scale.data")))
# Run the MDS procedure, k determines the number of dimensions
mds <- cmdscale(d = d, k = 2)
# cmdscale returns the cell embeddings, we first label the columns to ensure downstream
# consistency
colnames(mds) <- paste0("MDS_", 1:2)
# We will now store this as a custom dimensional reduction called 'mds'
KO.cells[["mds"]] <- CreateDimReducObject(embeddings = mds, key = "MDS_", assay = DefaultAssay(KO.cells))
# We can now use this as you would any other dimensional reduction in all downstream functions
DimPlot(KO.cells, reduction = "mds", pt.size = 0.5)
Find differential markers
KO.cells$celltype.stim <- paste(Idents(KO.cells), KO.cells$stim, sep = "_")
KO.cells$celltype <- Idents(KO.cells)
Idents(KO.cells) <- "celltype.stim"
response3 <- FindMarkers(KO.cells, ident.1 = c("1_G171B","0_G171B","2_G171B"), ident.2 = c("1_G171C", "0_G171C","2_G171C"), verbose = TRUE, test.use = "MAST", logfc.threshold = FALSE,min.pct = FALSE)
head(response3, n = 15)
#DE1: Compare cluster 0+1+12 (that expressed lnc5998) with Other hepatocyte clusters (2+5+8)
#DE2: compare cluster 1 (showed major effects in the KD) vs Cluster 0 (that showed little KD)
#DE3: For KO.cells that formed five subcluster, compare clusters 3+4+5+1 vs 2+0
#DE4: for KO.cells that formed five clusters. Comapre cluster 4 vs. 2
DE0112.258 <- FindMarkers(combined, ident.1 = c("0","1","12" ), ident.2 = c("2","5","8"),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DE0112.All <- FindMarkers(combined, ident.1 = c("0","1","12" ), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DE1.2 <- FindMarkers(combined, ident.1 = c("1" ), ident.2 = c("2"),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DE1.5 <- FindMarkers(combined, ident.1 = c("1" ), ident.2 = c("5"),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DE1.8 <- FindMarkers(combined, ident.1 = c("1" ), ident.2 = c("8"),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DE2.5 <- FindMarkers(combined, ident.1 = c("2" ), ident.2 = c("5"),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DE2.8 <- FindMarkers(combined, ident.1 = c("2" ), ident.2 = c("8"),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DE5.8 <- FindMarkers(combined, ident.1 = c("5" ), ident.2 = c("8"),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK4351.20 <- FindMarkers(KO.cells, ident.1 = c("3","4","5","1" ), ident.2 = c("2","0"),verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK4.3 <- FindMarkers(KO.cells, ident.1 = "4", ident.2 = "3",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK4.2 <- FindMarkers(KO.cells, ident.1 = "4", ident.2 = "2",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK4.0 <- FindMarkers(KO.cells, ident.1 = "4", ident.2 = "0",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK4.1 <- FindMarkers(KO.cells, ident.1 = "4", ident.2 = "1",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK4.5 <- FindMarkers(KO.cells, ident.1 = "4", ident.2 = "5",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
##### comaprison between G171B vs G171C for KO.cell clusters of 0+1+12 ######33
DEK4_C.B <- FindMarkers(KO.cells, ident.1 = "4_G171C", ident.2 = "4_G171B",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK3_C.B <- FindMarkers(KO.cells, ident.1 = "3_G171C", ident.2 = "3_G171B",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK1_C.B <- FindMarkers(KO.cells, ident.1 = "1_G171C", ident.2 = "1_G171B",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK2_C.B <- FindMarkers(KO.cells, ident.1 = "2_G171C", ident.2 = "2_G171B",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK0_C.B <- FindMarkers(KO.cells, ident.1 = "0_G171C", ident.2 = "0_G171B",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
DEK5_C.B <- FindMarkers(KO.cells, ident.1 = "5_G171C", ident.2 = "5_G171B",verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
################################### Write the results #########################
write.csv(DE0112.258, "CountResult/Markers/DE0112.258")
write.csv(DE0112.All, "CountResult/Markers/DE0112.All")
write.csv(DE1.2, "CountResult/Markers/DE1.2")
write.csv(DE1.5, "CountResult/Markers/DE1.5")
write.csv(DE1.8, "CountResult/Markers/DE1.8")
write.csv(DE2.5, "CountResult/Markers/DE2.5")
write.csv(DE2.8, "CountResult/Markers/DE2.8")
write.csv(DE5.8, "CountResult/Markers/DE5.8")
write.csv(DEK4351.20, "CountResult/Markers/DEK4351.20")
write.csv(DEK4.3, "CountResult/Markers/DEK4.3")
write.csv(DEK4.2, "CountResult/Markers/DEK4.2")
write.csv(DEK4.0, "CountResult/Markers/DEK4.0")
write.csv(DEK4.1, "CountResult/Markers/DEK4.1")
write.csv(DEK4.5, "CountResult/Markers/DEK4.5")
write.csv(DEK4_C.B, "CountResult/Markers/DEK4_C.B")
write.csv(DEK3_C.B, "CountResult/Markers/DEK3_C.B")
write.csv(DEK1_C.B, "CountResult/Markers/DEK1_C.B")
write.csv(DEK2_C.B, "CountResult/Markers/DEK2_C.B")
write.csv(DEK0_C.B, "CountResult/Markers/DEK0_C.B")
write.csv(DEK5_C.B, "CountResult/Markers/DEK5_C.B")
combined$celltype.stim <- paste(Idents(combined), combined$stim, sep = "_")
combined$celltype <- Idents(combined)
Idents(combined) <- "celltype.stim"
test.combined$celltype.stim <- paste(Idents(test.combined), test.combined$stim, sep = "_")
test.combined$celltype <- Idents(test.combined)
Idents(test.combined) <- "celltype.stim"
Combined_G171B_vs_G171C <- FindMarkers(combined, ident.1 = c("0_G171B","1_G171B","2_G171B","3_G171B","4_G171B","5_G171B","6_G171B","7_G171B","8_G171B","9_G171B","10_G171B","11_G171B","12_G171B" ), ident.2 = c("0_G171C","1_G171C","2_G171C","3_G171C","4_G171C","5_G171C","6_G171C","7_G171C","8_G171C","9_G171C","10_G171C","11_G171C","12_G171C" ), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust1 <- FindMarkers(combined, ident.1 = c("1_G171C"), ident.2 = c("1_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust0 <- FindMarkers(combined, ident.1 = c("0_G171C"), ident.2 = c("0_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust12 <- FindMarkers(combined, ident.1 = c("12_G171C"), ident.2 = c("12_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust2 <- FindMarkers(combined, ident.1 = c("2_G171C"), ident.2 = c("2_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust5 <- FindMarkers(combined, ident.1 = c("5_G171C"), ident.2 = c("5_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust8 <- FindMarkers(combined, ident.1 = c("8_G171C"), ident.2 = c("8_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust3 <- FindMarkers(combined, ident.1 = c("3_G171C"), ident.2 = c("3_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust4 <- FindMarkers(combined, ident.1 = c("4_G171C"), ident.2 = c("4_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust6 <- FindMarkers(combined, ident.1 = c("6_G171C"), ident.2 = c("6_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust7 <- FindMarkers(combined, ident.1 = c("7_G171C"), ident.2 = c("7_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust9 <- FindMarkers(combined, ident.1 = c("9_G171C"), ident.2 = c("9_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust10 <- FindMarkers(combined, ident.1 = c("10_G171C"), ident.2 = c("10_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
Combined_G171C_vs_G171B_Clust11 <- FindMarkers(combined, ident.1 = c("11_G171C"), ident.2 = c("11_G171B"), verbose = TRUE, logfc.threshold = FALSE,min.pct = FALSE)
write.csv(Combined_G171C_vs_G171B_Clust1, "CountResult/Markers/Combined_G171C_vs_G171B_Clust1")
write.csv(Combined_G171C_vs_G171B_Clust0, "CountResult/Markers/Combined_G171C_vs_G171B_Clust0")
write.csv(Combined_G171C_vs_G171B_Clust12, "CountResult/Markers/Combined_G171C_vs_G171B_Clust12")
write.csv(Combined_G171C_vs_G171B_Clust2, "CountResult/Markers/Combined_G171C_vs_G171B_Clust2")
write.csv(Combined_G171C_vs_G171B_Clust5, "CountResult/Markers/Combined_G171C_vs_G171B_Clust5")
write.csv(Combined_G171C_vs_G171B_Clust8, "CountResult/Markers/Combined_G171C_vs_G171B_Clust8")
write.csv(Combined_G171C_vs_G171B_Clust3, "CountResult/Markers/Combined_G171C_vs_G171B_Clust3")
write.csv(Combined_G171C_vs_G171B_Clust4, "CountResult/Markers/Combined_G171C_vs_G171B_Clust4")
write.csv(Combined_G171C_vs_G171B_Clust6, "CountResult/Markers/Combined_G171C_vs_G171B_Clust6")
write.csv(Combined_G171C_vs_G171B_Clust7, "CountResult/Markers/Combined_G171C_vs_G171B_Clust7")
write.csv(Combined_G171C_vs_G171B_Clust9, "CountResult/Markers/Combined_G171C_vs_G171B_Clust9")
write.csv(Combined_G171C_vs_G171B_Clust10, "CountResult/Markers/Combined_G171C_vs_G171B_Clust10")
write.csv(Combined_G171C_vs_G171B_Clust11, "CountResult/Markers/Combined_G171C_vs_G171B_Clust11")
PC_vs_PP_G171B <- FindMarkers(KO.cells, ident.1 = c("4_G171B","3_G171B"), ident.2 = c("0_G171B","2_G171B"), verbose = TRUE, test.use = "MAST", logfc.threshold = FALSE,min.pct = FALSE)
head(PC_vs_PP_G171B, n = 15)
PC_vs_PP_G171C <- FindMarkers(KO.cells, ident.1 = c("4_G171C","3_G171C"), ident.2 = c("0_G171C","2_G171C"), verbose = TRUE, test.use = "MAST", logfc.threshold = FALSE,min.pct = FALSE)
head(PC_vs_PP_G171C, n = 15)
PC_vs_PP_G171BC <- FindMarkers(KO.cells, ident.1 = c("4_G171B","3_G171B","4_G171C","3_G171C"), ident.2 = c("0_G171B","2_G171B","0_G171C","2_G171C"), verbose = TRUE, test.use = "MAST", logfc.threshold = FALSE,min.pct = FALSE)
head(PC_vs_PP_G171C, n = 15)
lnc5998_KO_DE_1 <- FindMarkers(KO.cells, ident.1 = c("4_G171B","3_G171B","5_G171B"), ident.2 = c("4_G171C","3_G171C","5_G171C"), verbose = TRUE, test.use = "MAST", logfc.threshold = FALSE,min.pct = FALSE)
head(lnc5998_KO_DE, n = 15)
lnc5998_KO_DE_2 <- FindMarkers(KO.cells, ident.1 = c("4_G171C","3_G171C","5_G171C"), ident.2 =c("4_G171B","3_G171B","5_G171B") , verbose = TRUE, test.use = "MAST", logfc.threshold = FALSE,min.pct = FALSE)
head(lnc5998_KO_DE, n = 15)
cell.type.genes <- (PC_vs_PP_G171BC[1]) # Takes all the unique cell type specific genes
GOterms = topGOterms(fg.genes = cell.type.genes, bg.genes = rownames(KO.cells@assays$RNA@dataKO.cells@assays$RNA@data), organism = "Mouse")
cell.type.genes <- (PC_vs_PP_G171BC[1]) # Takes all the unique cell type specific genes
GOterms = topGOterms(fg.genes = rownames(cell.type.genes), bg.genes = rownames(KO.cells@assays$RNA@data), organism = "Mouse")
AvergeExpression2 <- function (object, assays = NULL, features = NULL, return.seurat = FALSE,
add.ident = NULL, slot = "data", use.scale = FALSE, use.counts = FALSE,
verbose = TRUE, ...)
{
fxn.average <- switch(EXPR = slot, data = function(x) {
return(mean(x = x))
}, mean)
object.assays <- FilterObjects(object = object, classes.keep = "Assay")
assays <- assays %||% object.assays
ident.orig <- Idents(object = object)
orig.levels <- levels(x = Idents(object = object))
ident.new <- c()
if (!all(assays %in% object.assays)) {
assays <- assays[assays %in% object.assays]
if (length(assays) == 0) {
stop("None of the requested assays are present in the object")
}
else {
warning("Requested assays that do not exist in object. Proceeding with existing assays only.")
}
}
if (!is.null(x = add.ident)) {
new.data <- FetchData(object = object, vars = add.ident)
new.ident <- paste(Idents(object)[rownames(x = new.data)],
new.data[, 1], sep = "_")
Idents(object, cells = rownames(new.data)) <- new.ident
}
data.return <- list()
for (i in 1:length(x = assays)) {
data.use <- GetAssayData(object = object, assay = assays[i],
slot = slot)
features.assay <- features
if (length(x = intersect(x = features, y = rownames(x = data.use))) <
1) {
features.assay <- rownames(x = data.use)
}
data.all <- data.frame(row.names = features.assay)
for (j in levels(x = Idents(object))) {
temp.cells <- WhichCells(object = object, idents = j)
features.assay <- unique(x = intersect(x = features.assay,
y = rownames(x = data.use)))
if (length(x = temp.cells) == 1) {
data.temp <- (data.use[features.assay, temp.cells])
if (slot == "data") {
data.temp <- data.temp
}
}
if (length(x = temp.cells) > 1) {
data.temp <- apply(X = data.use[features.assay,
temp.cells, drop = FALSE], MARGIN = 1, FUN = fxn.average)
}
data.all <- cbind(data.all, data.temp)
colnames(x = data.all)[ncol(x = data.all)] <- j
if (verbose) {
message(paste("Finished averaging", assays[i],
"for cluster", j))
}
if (i == 1) {
ident.new <- c(ident.new, as.character(x = ident.orig[temp.cells[1]]))
}
}
names(x = ident.new) <- levels(x = Idents(object))
data.return[[i]] <- data.all
names(x = data.return)[i] <- assays[[i]]
}
if (return.seurat) {
toRet <- CreateSeuratObject(counts = data.return[[1]],
project = "Average", assay = names(x = data.return)[1],
...)
if (length(x = data.return) > 1) {
for (i in 2:length(x = data.return)) {
toRet[[names(x = data.return)[i]]] <- CreateAssayObject(counts = data.return[[i]])
}
}
if (DefaultAssay(object = object) %in% names(x = data.return)) {
DefaultAssay(object = toRet) <- DefaultAssay(object = object)
}
Idents(toRet, cells = colnames(x = toRet)) <- ident.new[colnames(x = toRet)]
Idents(object = toRet) <- factor(x = Idents(object = toRet),
levels = as.character(x = orig.levels), ordered = TRUE)
toRet <- NormalizeData(object = toRet, verbose = verbose)
toRet <- ScaleData(object = toRet, verbose = verbose)
return(toRet)
}
else {
return(data.return)
}
}
Find differential expression markers
combined.markers <- FindAllMarkers(object = combined, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
combined.markers %>% group_by(cluster) %>% top_n(2, avg_logFC)
KO.markers <- FindAllMarkers(object = KO.cells, only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
response3 <- FindMarkers(combined, ident.1 = c("1_G171B","0_G171B","2_G171B"), ident.2 = c("1_G171C", "0_G171C","2_G171C"), verbose = TRUE, test.use = "MAST", logfc.threshold = FALSE,min.pct = FALSE)
head(response3, n = 15)
genes_hep_main =c('Alb', 'Ttr', 'Apoa1', 'Serpina1c')
genes_hep = c('Alb', 'Ttr', 'Apoa1', 'Serpina1c',
'Cyp2e1', 'Glul', 'Oat', 'Gulo',
'Ass1', 'Hamp', 'Gstp1', 'Ubb',
'Cyp2f2', 'Pck1', 'Hal', 'Cdh1')
genes_endo = c('Pecam1', 'Nrp1', 'Kdr','Oit3')
genes_kuppfer = c( 'Clec4f', 'Cd68')
genes_nk = c('Il2rb', 'Nkg7', 'Cxcr6', 'Gzma')
genes_b = c('Cd79a', 'Cd79b')
genes_bec = c('Epcam', 'Krt19', 'Krt7')
genes_immune = 'Ptprc'
HSC = c("Acta2", "Gfap","Des","Ngfr","Col2a1","Vim","Lama1","Nes")
all_genes = c(genes_hep, genes_endo, genes_kuppfer, genes_nk, genes_b, genes_bec, genes_immune, HSC)
genes_bec_b_immune = c(genes_bec,genes_b,genes_immune)
genes_zones = c('Cyp2e1', 'Glul', 'Oat', 'Gulo',
'Ass1', 'Hamp', 'Gstp1', 'Ubb',
'Cyp2f2', 'Pck1', 'Hal', 'Cdh1')
receptor_KO <- c("ncRNA-inter-chr7-5998","Cyp2b10","Nr1i2","Nr1i3","Ppara","Pparg","Ppargc1b","Ppard")
Visualize top genes in principal components
Later on (in FindClusters and TSNE) you will pick a number of principal components to use. This has the effect of keeping the major directions of variation in the data and, ideally, supressing noise. There is no correct answer to the number to use, but a decent rule of thumb is to go until the plot plateaus.
PCElbowPlot(object = tiss1)
Choose the number of principal components to use.
# Set number of principal components.
n.pcs = 10
The clustering is performed based on a nearest neighbors graph. Cells that have similar expression will be joined together. The Louvain algorithm looks for groups of cells with high modularity–more connections within the group than between groups. The resolution parameter determines the scale. Higher resolution will give more clusters, lower resolution will give fewer.
For the top-level clustering, aim to under-cluster instead of over-cluster. It will be easy to subset groups and further analyze them below.
# Set resolution
res.used <- 4
tiss1 <- FindClusters(object = tiss1, reduction.type = "pca", dims.use = 1:n.pcs,
resolution = res.used, print.output = 0, save.SNN = TRUE, force.recalc = TRUE)
We use TSNE solely to visualize the data.
# If cells are too spread out, you can raise the perplexity. If you have few cells, try a lower perplexity (but never less than 10).
tiss1 <- RunTSNE(object = tiss1, dims.use = 1:n.pcs, seed.use = 10, perplexity=30)
TSNEPlot(object = tiss1, do.label = T, pt.size = 1.2, label.size = 4)
Compare to previous annotations
previous_annotation = read.csv("/Users/kkarri/Documents/Lab/Single_cell_project/dropseq/Liver_droplet_annotation.csv", stringsAsFactors = FALSE)
cols = c('free_annotation', 'cell_ontology_class')
for (col in cols){
previous_col = paste0('previous_', col)
tiss1@meta.data[, previous_col] <- "NA"
tiss1@meta.data[as.character(previous_annotation$X), previous_col] <- previous_annotation[, col]
print(table(tiss1@meta.data[, previous_col]))
print(table(tiss1@meta.data[, previous_col], tiss@ident))
}
tiss1 = compare_previous_annotation(tiss1, tissue_of_interest, "droplet")
TSNEPlot(object = tiss1, do.return = TRUE, group.by = "previous_cell_ontology_class")
table(tiss1@meta.data[, "previous_cell_ontology_class"], tiss@ident)
tiss1 = compare_previous_annotation(tiss1, tissue_of_interest, "droplet")
TSNEPlot(object = tiss1, do.return = TRUE, group.by = "previous_cell_ontology_class")
table(tiss1@meta.data[, "previous_cell_ontology_class"], tiss1@ident)
TSNEPlot(tiss1, group.by="mouse.sex")
TSNEPlot(tiss1, group.by="mouse.id")
Significant genes:
hepatocyte: Alb, Ttr, Apoa1, and Serpina1c pericentral: Cyp2e1, Glul, Oat, Gulo midlobular: Ass1, Hamp, Gstp1, Ubb periportal: Cyp2f2, Pck1, Hal, Cdh1
endothelial cells: Pecam1, Nrp1, Kdr+ and Oit3+ Kuppfer cells: Emr1, Clec4f, Cd68, Irf7 NK/NKT cells: Zap70, Il2rb, Nkg7, Cxcr6, Klr1c, Gzma B cells: Cd79a, Cd79b, Cd74 and Cd19 Immune cells: Ptprc
Dotplots let you see the intensity of exppression and the fraction of cells expressing for each of your genes of interest. The radius shows you the percent of cells in that cluster with at least one read sequenced from that gene. The color level indicates the average Z-score of gene expression for cells in that cluster, where the scaling is done over taken over all cells in the sample.
We have various immune cell types in the last cluster
Using the markers above, we can confidentaly label many of the clusters:
19: endothelial cells 20: bile duct epithelial cells 21: immune cells rest are hepatocytes
We will add those cell_ontology_classes to the dataset.
tiss1 <- StashIdent(object = tiss1, save.name = "cluster.ids")
cluster.ids <- c(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
free_annotation <- c(
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
NA,
"bile duct epithelial cells",
"endothelial cell of hepatic sinusoid",
NA
)
cell_ontology_class <- c(
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"hepatocyte",
"duct epithelial cell",
"endothelial cell of hepatic sinusoid",
"hepatocyte")
tiss1 = stash_annotations(tiss1, cluster.ids, free_annotation, cell_ontology_class)
Checking for batch effects
Color by metadata, like plate barcode, to check for batch effects.
TSNEPlot(object = tiss1, do.return = TRUE, group.by = "channel")
TSNEPlot(object = tiss1, do.return = TRUE, group.by = "free_annotation")
Subcluster
Let’s drill down on the hepatocytes.
subtiss1 = SubsetData(tiss1, ident.use = c(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,20))
subtiss1 <- subtiss1 %>% ScaleData() %>%
FindVariableGenes(do.plot = FALSE, x.high.cutoff = Inf, y.cutoff = 0.5) %>%
RunPCA(do.print = FALSE)
PCHeatmap(object = subtiss1, pc.use = 1:3, cells.use = 20, do.balanced = TRUE, label.columns = FALSE, num.genes = 8)
PCElbowPlot(subtiss1)
sub.n.pcs = 8
sub.res.use = 0.5
subtiss1 <- subtiss1 %>% FindClusters(reduction.type = "pca", dims.use = 1:sub.n.pcs,
resolution = sub.res.use, print.output = 0, save.SNN = TRUE, force.recalc = TRUE) %>%
RunTSNE(dims.use = 1:sub.n.pcs, seed.use = 10, perplexity=8)
TSNEPlot(object = subtiss1, do.label = T, pt.size = 1, label.size = 4)
BuildClusterTree(subtiss1)
From these genes, it appears that the clusters represent:
0: midlobular male 1: pericentral female 2: periportal female 3: periportal male 4: midlobular male 5: pericentral male 6: midlobular female 7: midlobular female
The multitude of clusters of each type correspond mostly to individual animals/sexes.
table(FetchData(subtiss1, c('mouse.sex','ident')) %>% droplevels())
sub.cluster.ids <- c(0, 1, 2, 3, 4, 5, 6, 7)
sub.free_annotation <- c("periportal female", "midlobular male", "pericentral female", "periportal male", "midlobular male", "pericentral male", "midlobular female", "midlobular female")
sub.cell_ontology_class <- c("hepatocyte", "hepatocyte", "hepatocyte", "hepatocyte", "hepatocyte", "hepatocyte", "hepatocyte", "hepatocyte")
subtiss1 = stash_annotations(subtiss1, sub.cluster.ids, sub.free_annotation, sub.cell_ontology_class)
tiss1 = stash_subtiss_in_tiss(tiss1, subtiss1)
Liver zonation markers
genes_zones = c('Cyp2e1', 'Glul', 'Oat', 'Gulo',
'Ass1', 'Hamp', 'Gstp1', 'Ubb',
'Cyp2f2', 'Pck1', 'Hal', 'Cdh1')
FeaturePlot(subtiss1,c(genes_zones),cols.use = c("grey", "red"), pt.size = 1, nCol = 4)
DotPlot(subtiss1,c(genes_zones), plot.legend = T, col.max = 2.5, do.return = T) + coord_flip()
TSNEPlot(object = subtiss1, do.label = T, pt.size = 1, label.size = 4, group.by="free_annotation")
TSNEPlot(object = tiss1, do.label = T, pt.size = 1, label.size = 4, group.by="free_annotation")
Find cluster markers for lncRNAs
MIN_LOGFOLD_CHANGE = 1 # set to minimum required average log fold change in gene expression.
MIN_PCT_CELLS_EXPR_GENE = 0.1
all.markers = FindAllMarkers(tiss1,
min.pct = MIN_PCT_CELLS_EXPR_GENE,
logfc.threshold = MIN_LOGFOLD_CHANGE,
only.pos = TRUE,
test.use="bimod") # likelihood ratio test
lnc_all_markers <- grep(pattern = "^ncRNA", x= rownames(all.markers), value = TRUE)
lnc_all_markers
#[1] "ncRNA_inter_chr10_92081" "ncRNA_intra_chr16_13383" "ncRNA_inter_chr17_13605" "ncRNA_inter_chr14_11815"
#[5] "ncRNA_inter_chr18_14344"
FeaturePlot(subtiss1,c(lnc_all_markers),cols.use = c("grey", "red"), pt.size = 1, nCol = 4)
######################### lncRNA markers- CELL TYPE MARKER ############
markers.hep <- FindMarkers(object = tiss1, ident.1 = c(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,20), ident.2 = c(18,19),only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
lnc_markers_hep <- grep(pattern = "^ncRNA", x= rownames(markers.hep), value = TRUE)
lnc_markers_hep
FeaturePlot(tiss1,c(lnc_markers_hep),cols.use = c("grey", "red"), pt.size = 1, nCol = 4)
DotPlot(tiss1,lnc_markers_hep, plot.legend = T, col.max = 2.5, do.return = T) + coord_flip()
#[1] "ncRNA_as_chr11_9423" "ncRNA_as_chr7_6166" "ncRNA_inter_chr4_3295" "ncRNA_inter_chr17_14026"
#[5] "ncRNA_inter_chr3_2915" "ncRNA_inter_chr5_4547" "ncRNA_inter_chr15_12684"
markers.hep.MAST <- FindMarkers(object = tiss1, ident.1 = c(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,20), ident.2 = c(18,19),only.pos = TRUE, test.use = "MAST")
lnc_markers_hep_MAST_TABLE <- subset(markers.hep.MAST, grepl("^ncRNA", rownames(markers.hep.MAST)))
lnc_markers_hep_MAST <- grep(pattern = "^ncRNA", x= rownames(markers.hep.MAST), value = TRUE)
lnc_markers_hep_MAST
markers.endo <- FindMarkers(object = tiss1, ident.1 = c(18,19), only.pos = TRUE, min.pct = 0.25, thresh.use = 0.5)
lnc_markers_endo <- grep(pattern = "^ncRNA", x= rownames(markers.endo), value = TRUE)
lnc_markers_endo
FeaturePlot(tiss1,c(lnc_markers_endo),cols.use = c("grey", "red"), pt.size = 1, nCol = 4)
DotPlot(tiss1,lnc_markers_endo, plot.legend = T, col.max = 2.5, do.return = T) + coord_flip()
#"ncRNA_inter_chr15_12770", "ncRNA_inter_chr12_10817", "ncRNA_as_chr13_11451",
markers.endo.MAST <- FindMarkers(object = tiss1, ident.1 = 19, test.use = "MAST" ,only.pos = TRUE)
lnc_markers_endo_MAST_TABLE <- subset(markers.endo.MAST, grepl("^ncRNA", rownames(markers.endo.MAST)))
lnc_markers_endo_MAST <- grep(pattern = "^ncRNA", x= rownames(markers.endo.MAST), value = TRUE)
lnc_markers_endo_MAST
################## lncRNA expression ########################3
# "ncRNA_inter_chr17_13605" , "ncRNA_intra_chr16_13383"
########## Periporal markers- zonation markers ############
markers.pc <- FindMarkers(object = subtiss1, ident.1 = c(2,5),
only.pos = FALSE, min.pct = 0.001, thresh.use = 0.001, test.use = "bimod" )
markers.pc.MAST <- FindMarkers(object = subtiss1, ident.1 = c(2,5), ident.2 = c(0,3), test.use = "MAST" ,only.pos = TRUE)
lnc_markers_pc <- subset(markers.pc, grepl("^ncRNA", rownames(markers.pc)))
lnc_markers_pc <- grep(pattern = "^ncRNA", x= rownames(markers.pc), value = TRUE)
lnc_markers_pc
markers.pc.MAST <- FindMarkers(object = subtiss1, ident.1 = c(2,5), ident.2 = c(0,3), test.use = "MAST" ,only.pos = TRUE)
lnc_markers_pc_MAST <- subset(markers.pc.MAST, grepl("^ncRNA", rownames(markers.pc.MAST)))
lnc_markers_pc_MAST <- grep(pattern = "^ncRNA", x= rownames(markers.pc.MAST), value = TRUE)
lnc_markers_pc_MAST
DotPlot(tiss1, lnc_markers_pc, plot.legend = T, col.max = 2.5, do.return = T, group.by="free_annotation") + coord_flip()
FeaturePlot(subtiss1,c(lnc_markers_pc),cols.use = c("grey", "red"), pt.size = 1, nCol = 4)
############################### midlobular genes #############
markers.mid <- FindMarkers(object = subtiss1, ident.1 = c(1,4,6,7),
only.pos = FALSE, min.pct = 0.001, thresh.use = 0.05)
lnc_markers_mid <- subset(markers.mid, grepl("^ncRNA", rownames(markers.mid)))
lnc_markers_mid <- grep(pattern = "^ncRNA", x= rownames(markers.mid), value = TRUE)
lnc_markers_mid
DotPlot(tiss1, lnc_markers_mid, plot.legend = T, col.max = 2.5, do.return = T, group.by="free_annotation") + coord_flip()
FeaturePlot(subtiss1,c(lnc_markers_mid),cols.use = c("grey", "red"), pt.size = 1, nCol = 4)
markers.mid.MAST <- FindMarkers(object = subtiss1, ident.1 = c(1,4,6,7),test.use = "MAST",only.pos = TRUE )
lnc_markers_mid_MAST_TABLE <- subset(markers.mid.MAST, grepl("^ncRNA", rownames(markers.mid.MAST)))
lnc_markers_mid_MAST <- grep(pattern = "^ncRNA", x= rownames(markers.mid.MAST), value = TRUE)
lnc_markers_mid_MAST
#####3 periportalmarker genes############3
markers.pp <- FindMarkers(object = subtiss1, ident.1 = c(0,3),
only.pos = FALSE, min.pct = 0.001, thresh.use = 0.05)
lnc_markers_pp <- subset(markers.pp, grepl("^ncRNA", rownames(markers.pp)))
lnc_markers_pp <- grep(pattern = "^ncRNA", x= rownames(markers.pp), value = TRUE)
lnc_markers_pp
markers.pp.MAST <- FindMarkers(object = subtiss1, ident.1 = c(0,3), ident.2 = c(2,5),test.use = "MAST",only.pos = TRUE )
lnc_markers_pp_MAST_TABLE <- subset(markers.pp.MAST, grepl("^ncRNA", rownames(markers.pp.MAST)))
lnc_markers_pp_MAST <- grep(pattern = "^ncRNA", x= rownames(markers.pp.MAST), value = TRUE)
lnc_markers_pp_MAST
FeaturePlot(subtiss1,c(lnc_markers_pp),cols.use = c("grey", "red"), pt.size = 1, nCol = 4, max.cutoff = 1)
DotPlot(tiss1, c(lnc_markers_pp,"Cyp2e1","Cyp2f2"), plot.legend = T, col.max = 2.5, do.return = T, group.by= "free_annotation") + coord_flip()
################## amle and female specific ############################
markers.female <- FindMarkers(object = subtiss1, ident.1 = c(0,2,6,7),
only.pos = TRUE, min.pct = 0.1, logfc.threshold = 1)
lnc_markers_female <- subset(markers.female, grepl("^ncRNA", rownames(markers.female)))
lnc_markers_female <- grep(pattern = "^ncRNA", x= rownames(markers.female), value = TRUE)
lnc_markers_female
FeaturePlot(subtiss1,c(lnc_markers_female),cols.use = c("grey", "red"), pt.size = 1, nCol = 4, max.cutoff = 1)
DotPlot(tiss1, c(lnc_markers_female,"Cyp2e1","Cyp2f2"), plot.legend = T, col.max = 2.5, do.return = T, group.by= "free_annotation") + coord_flip()
markers.male <- FindMarkers(object = subtiss1, ident.1 = c(1,3,4,5),
only.pos = TRUE, min.pct = 0.001, thresh.use = 0.05)
lnc_markers_male <- subset(markers.male, grepl("^ncRNA", rownames(markers.male)))
lnc_markers_male <- grep(pattern = "^ncRNA", x= rownames(markers.male), value = TRUE)
lnc_markers_male
FeaturePlot(subtiss1,c(lnc_markers_male),cols.use = c("grey", "red"), pt.size = 1, nCol = 4, max.cutoff = 1)
DotPlot(tiss1, c(lnc_markers_male,"Cyp2e1","Cyp2f2"), plot.legend = T, col.max = 2.5, do.return = T, group.by= "free_annotation") + coord_flip()
############################ Female zonate specific genes ###################################
markers.pericentral.female <- FindMarkers(object = tiss1, ident.1 = c(6,11,14,20), test.use = "MAST",
only.pos = TRUE, min.pct = 0.1, ident.2 = c(2,3,15,12,13,8,5,16), logfc.threshold = 1)
markers.periportal.female <- FindMarkers(object = tiss1, ident.1 = c(2,3,15),
only.pos = TRUE, min.pct = 0.1, ident.2 = c(6,11,14,20,12,13,8,5,16), logfc.threshold = 1)
markers.pericentral.male <- FindMarkers(object = tiss1, ident.1 = c(13,12), test.use = "MAST",
only.pos = TRUE, min.pct = 0.1, ident.2 = c(2,3,15,8,5,16,6,11,14,20), logfc.threshold = 1)
markers.periportal.male <- FindMarkers(object = tiss1, ident.1 = c(8,5,16), test.use = "MAST",
only.pos = TRUE, min.pct = 0.1, ident.2 = c(2,3,15,13,12,6,11,14,20), logfc.threshold = 1)
############### xeno-lncs CAR?RXR ##################
FeaturePlot(tiss1,c("ncRNA_inter_chr15_12684","ncRNA_inter_chr8_7430","ncRNA_inter_chr7_6222"),cols.use = c("grey", "red"), pt.size = 1, nCol = 4, max.cutoff = 1)
#######################################################################
markers.endo.2 <- FindMarkers(object = seurat_drop, logfc.threshold = 2,ident.1 = "Endothelial",
only.pos = TRUE, min.pct = 0.25, thresh.use = 0.25)
lnc.endo.2 <- grep(pattern = "^ncRNA", x= rownames(markers.endo.2), value = TRUE)
lnc.endo.2
Zonated lncRNAs
pp_zontaed <- c('ncRNA_inter_chr14_12016','ncRNA_as_chr19_15090','ncRNA_inter_chr10_9351','ncRNA_inter_chr16_13170',
'ncRNA_inter_chr3_2697','ncRNA_inter_chr1_274','ncRNA_as_chr6_5518','ncRNA_inter_chr14_12066','ncRNA_intra_chr12_10871',
'ncRNA_inter_chr16_13510','ncRNA_inter_chr3_2314','ncRNA_inter_chr10_9264,'ncRNA_inter_chr9_8122')
Checking for batch effects
Color by metadata, like plate barcode, to check for batch effects.
TSNEPlot(object = subtiss1, do.return = TRUE, group.by = "mouse.sex")
Final coloring
Color by cell ontology class on the original TSNE.
TSNEPlot(object = tiss1, do.return = TRUE, group.by = "cell_ontology_class")
Save the Robject for later
filename = here('00_data_ingest', '04_tiss1ue_robj_generated',
paste0("droplet_", tiss1ue_of_interest, "refinedcells_seurat_tiss1.Robj"))
print(filename)
save(tiss1, file=filename)
# To reload a saved object
filename = here('00_data_ingest', '04_tiss1ue_robj_generated',
paste0("droplet_", tissue_of_interest, "seurat_smartdrop-integrated-8272019.Robj"))
load(file=filename)
LS0tCiB0aXRsZTogIkxpdmVyIERyb3BsZXQtIFJhdyBkYXRhIE5vdGVib29rIgogb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnRpc3N1ZV9vZl9pbnRlcmVzdCA9ICJMaXZlciIKbGlicmFyeShoZXJlKQpzb3VyY2UoIi9yZXN0cmljdGVkL3Byb2plY3RuYi93YXhtYW5sYWIva2thcnJpL3NjUk5Bc2VxX2RhdGFfaW50ZWdyYXRpb24vYm9pbGVycGxhdGUuUiIpCiN0aXNzID0gbG9hZF90aXNzdWVfZHJvcGxldCh0aXNzdWVfb2ZfaW50ZXJlc3QpCiNsaWJyYXJ5KHNjYXRlcikKbGlicmFyeShkcGx5cikKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoY293cGxvdCkKI2xpYnJhcnkoTUFTVCkKIyMjIyMjIyMjIyBmdW5jdGlvbiBsb2FkX3Rpc3N1ZV9kcm9wbGV0IyMjIyMjIyMjIyMjCmRyb3BsZXRfbWV0YWRhdGFfRzE3MUIgPC0gcmVhZC5jc3YoIi9uZXQvd2F4bWFuLXNlcnZlci9tbnQvZGF0YS93YXhtYW5sYWJ2bV9ob21lL2trYXJyaS9HMTcxL0FuYWx5c2lzL0cxNzFfbWV0YWRhdGFfZHJvcGxldF9saXZlci5jc3YiLCBzZXA9IiwiLCBoZWFkZXIgPSBUUlVFKQpjb2xuYW1lcyhkcm9wbGV0X21ldGFkYXRhX0cxNzFCKVsxXSA8LSAiY2hhbm5lbCIKdGlzc3VlX21ldGFkYXRhX0cxNzFCID0gZmlsdGVyKGRyb3BsZXRfbWV0YWRhdGFfRzE3MUIsIHRpc3N1ZSA9PSB0aXNzdWVfb2ZfaW50ZXJlc3QpWyxjKCdjaGFubmVsJywndGlzc3VlJywnc3VidGlzc3VlJywnbW91c2Uuc2V4JywgJ21vdXNlLmlkJyldCgpyYXcuZGF0YSA8LSBSZWFkMTBYKCIvbmV0L3dheG1hbi1zZXJ2ZXIvbW50L2RhdGEvd2F4bWFubGFidm1faG9tZS9ra2FycmkvRzE3MS9BbmFseXNpcy9UcmFuc2NyaXB0X1JlZmluZWQvTGl2ZXItMTBYX0cxNzFCLyIpCiNyYXcuZGF0YSA8LSBSZWFkMTBYKCIvbmV0L3dheG1hbi1zZXJ2ZXIvbW50L2RhdGEvd2F4bWFubGFidm1faG9tZS9ra2FycmkvRzE3MS9BbmFseXNpcy9UcmFuc2NyaXB0X2Rvd25zYW1wbGVkXzAuNS9MaXZlci0xMFhfRzE3MUIiKQoKY29sbmFtZXMocmF3LmRhdGEpIDwtIGxhcHBseShjb2xuYW1lcyhyYXcuZGF0YSksIGZ1bmN0aW9uKHgpIHBhc3RlMCh0aXNzdWVfbWV0YWRhdGFfRzE3MUIkY2hhbm5lbFsxXSwnLScseCkpCiAgbWV0YS5kYXRhMSA9IGRhdGEuZnJhbWUocm93Lm5hbWVzID0gY29sbmFtZXMocmF3LmRhdGEpKQogIG1ldGEuZGF0YTFbJ2NoYW5uZWwnXSA9IHRpc3N1ZV9tZXRhZGF0YV9HMTcxQiRjaGFubmVsWzFdCiAgCiAgcm5hbWVzID0gcm93Lm5hbWVzKG1ldGEuZGF0YTEpCiAgbWV0YS5kYXRhMSA8LSBtZXJnZShtZXRhLmRhdGExLCB0aXNzdWVfbWV0YWRhdGFfRzE3MUIsIHNvcnQgPSBGKQogIHJvdy5uYW1lcyhtZXRhLmRhdGExKSA8LSBybmFtZXMKICAjIE9yZGVyIHRoZSBjZWxscyBhbHBoYWJldGljYWxseSB0byBlbnN1cmUgY29uc2lzdGVuY3kuCiAgCiAgb3JkZXJlZF9jZWxsX25hbWVzID0gb3JkZXIoY29sbmFtZXMocmF3LmRhdGEpKQogIHJhdy5kYXRhID0gcmF3LmRhdGFbLG9yZGVyZWRfY2VsbF9uYW1lc10KICBtZXRhLmRhdGExID0gbWV0YS5kYXRhMVtvcmRlcmVkX2NlbGxfbmFtZXMsXQogIAogICMgRmluZCBFUkNDJ3MsIGNvbXB1dGUgdGhlIHBlcmNlbnQgRVJDQywgYW5kIGRyb3AgdGhlbSBmcm9tIHRoZSByYXcgZGF0YS4KICBlcmNjcyA8LSBncmVwKHBhdHRlcm4gPSAiXkVSQ0MtIiwgeCA9IHJvd25hbWVzKHggPSByYXcuZGF0YSksIHZhbHVlID0gVFJVRSkKICBwZXJjZW50LmVyY2MgPC0gTWF0cml4Ojpjb2xTdW1zKHJhdy5kYXRhW2VyY2NzLCBdKS9NYXRyaXg6OmNvbFN1bXMocmF3LmRhdGEpCiAgZXJjYy5pbmRleCA8LSBncmVwKHBhdHRlcm4gPSAiXkVSQ0MtIiwgeCA9IHJvd25hbWVzKHggPSByYXcuZGF0YSksIHZhbHVlID0gRkFMU0UpCiAgcmF3LmRhdGEgPC0gcmF3LmRhdGFbLWVyY2MuaW5kZXgsXQogIAogIG5jUk5BLmdlbmVzIDwtIGdyZXAocGF0dGVybiA9ICJebmNSTkEiLCB4ID0gcm93bmFtZXMoeCA9IHJhdy5kYXRhKSwgdmFsdWUgPSBUUlVFKQogIHBlcmNlbnQubmNSTkEgPC0gTWF0cml4Ojpjb2xTdW1zKHJhdy5kYXRhW25jUk5BLmdlbmVzLCBdKS9NYXRyaXg6OmNvbFN1bXMocmF3LmRhdGEpCiAgS1JBQi5nZW5lcyA8LSBncmVwKHBhdHRlcm4gPSAiXktSQUIiLCB4ID0gcm93bmFtZXMoeCA9IHJhdy5kYXRhKSwgdmFsdWUgPSBUUlVFKQogIGNoZXJyeS5nZW5lcyA8LSBncmVwKHBhdHRlcm4gPSAiXm1jaGVycnkiLCB4ID0gcm93bmFtZXMoeCA9IHJhdy5kYXRhKSwgdmFsdWUgPSBUUlVFKQogIAogICMgQ3JlYXRlIHRoZSBTZXVyYXQgb2JqZWN0IHdpdGggYWxsIHRoZSBkYXRhCiAgZHJvcGxldCA8LSBDcmVhdGVTZXVyYXRPYmplY3QocmF3LmRhdGEpICAgIyBkcm9wc2VxCiAgZHJvcGxldCA8LSBBZGRNZXRhRGF0YShvYmplY3QgPSBkcm9wbGV0LCBtZXRhLmRhdGExKSAKICBkcm9wbGV0QG1ldGEuZGF0YSR0ZWNoIDwtICJHMTcxQiIKCiNkcm9wbGV0IDwtIFN1YnNldERhdGEoZHJvcGxldCxzdWJzZXQubmFtZXMgPSBjKCJuR2VuZSIsICJuVU1JIiksIGxvdy50aHJlc2hvbGRzID0gYyg1MDAsIDEwMDApKSAgIyBvbGQgdmVyc2lvbiBvZiBzZXVyYXQKI2Ryb3BsZXQgPC0gIHN1YnNldChkcm9wbGV0LCBzdWJzZXQgPSBuRmVhdHVyZV9STkEgPiAyMDAgJiBuQ291bnRfUk5BID4gNTAwKQpkcm9wbGV0IDwtIE5vcm1hbGl6ZURhdGEoZHJvcGxldCwgdmVyYm9zZSA9IEZBTFNFKQpkcm9wbGV0IDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKGRyb3BsZXQsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKZHJvcGxldCRzdGltIDwtICJHMTcxQiIKCiNsbmM1OTk4IDwtIHN1YnNldChkcm9wbGV0LCBzdWJzZXQgPSBgbmNSTkEtaW50ZXItY2hyNy01OTk4YCA+MSkKI2xuYzU5OTggPC0gTm9ybWFsaXplRGF0YShsbmM1OTk4LCB2ZXJib3NlID0gRkFMU0UpCiNsbmM1OTk4IDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKGxuYzU5OTgsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKI2xuYzU5OTgkc3RpbSA8LSAibG5jNTk5OEcxNzFCIgoKIyMjIHRoaXMgaXMgdHJhbmZvcm1hdGlvbiBvcHRpb24gZm9yIGRldmVscG1lbnQgU0N0cmFuc2Zvcm0gcHJvZ3JhbSAjIyMjIyMjCmRyb3BsZXQgPC0gU0NUcmFuc2Zvcm0oZHJvcGxldCx2ZXJib3NlID1UUlVFKQpkcm9wbGV0IDwtIFNjYWxlRGF0YShkcm9wbGV0LCB2ZXJib3NlID0gRkFMU0UpCmRyb3BsZXQgPC0gUnVuUENBKGRyb3BsZXQsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiMgdC1TTkUgYW5kIENsdXN0ZXJpbmcKZHJvcGxldCA8LSBSdW5VTUFQKGRyb3BsZXQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyNSkKZHJvcGxldCA8LSBGaW5kTmVpZ2hib3JzKGRyb3BsZXQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyNSkKZHJvcGxldCA8LSBGaW5kQ2x1c3RlcnMoZHJvcGxldCwgcmVzb2x1dGlvbiA9IDEpICAgCmRyb3BsZXQgPC0gUnVuVFNORShkcm9wbGV0LCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjApCiAgCnBkMSA8LSBVTUFQUGxvdChkcm9wbGV0LCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInN0aW0iLCBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTUpCgpwZDEuMSA8LSBVTUFQUGxvdChkcm9wbGV0LCByZWR1Y3Rpb24gPSAidW1hcCIsIHNwbGl0LmJ5ID0gInN0aW0iLGxhYmVsPVRSVUUsIGxhYmVsLnNpemU9NSkgICAKCnBkMiA8LSBVTUFQUGxvdChkcm9wbGV0LCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gIm1vdXNlLnNleCIpCnBkMyA8LSBVTUFQUGxvdChkcm9wbGV0LCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgbGFiZWwuc2l6ZT0zKQpwZDQgPC0gVU1BUFBsb3QoZHJvcGxldCwgbGFiZWw9VFJVRSwgbGFiZWwuc2l6ZT02KQoKCnBkMSA8LSBUU05FUGxvdChkcm9wbGV0LCByZWR1Y3Rpb24gPSAidHNuZSIsIGxhYmVsPVRSVUUsIGxhYmVsLnNpemU9NSkKCkRlZmF1bHRBc3NheShkcm9wbGV0KSA8LSAiUk5BIgpkcm9wbGV0IDwtIE5vcm1hbGl6ZURhdGEoZHJvcGxldCkKZDEgPC0gRG90UGxvdChkcm9wbGV0LCBmZWF0dXJlcyA9IGFsbF9nZW5lcykKCgpsbmM1OTk4IDwtIFNDVHJhbnNmb3JtKGxuYzU5OTgsIHZlcmJvc2UgPSBUUlVFKQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBkcm9wbGV0IEcxNzFDICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwpkcm9wbGV0X21ldGFkYXRhX0cxNzFDIDwtIHJlYWQuY3N2KCIvbmV0L3dheG1hbi1zZXJ2ZXIvbW50L2RhdGEvd2F4bWFubGFidm1faG9tZS9ra2FycmkvRzE3MS9BbmFseXNpcy9HMTcxQ19tZXRhZGF0YV9kcm9wbGV0X2xpdmVyLmNzdiIsIHNlcD0iLCIsIGhlYWRlciA9IFRSVUUpCmNvbG5hbWVzKGRyb3BsZXRfbWV0YWRhdGFfRzE3MUMpWzFdIDwtICJjaGFubmVsIgp0aXNzdWVfbWV0YWRhdGFfRzE3MUMgPSBmaWx0ZXIoZHJvcGxldF9tZXRhZGF0YV9HMTcxQywgdGlzc3VlID09IHRpc3N1ZV9vZl9pbnRlcmVzdClbLGMoJ2NoYW5uZWwnLCd0aXNzdWUnLCdzdWJ0aXNzdWUnLCdtb3VzZS5zZXgnLCAnbW91c2UuaWQnKV0KCnJhdy5kYXRhMSA8LSBSZWFkMTBYKCIvbmV0L3dheG1hbi1zZXJ2ZXIvbW50L2RhdGEvd2F4bWFubGFidm1faG9tZS9ra2FycmkvRzE3MS9BbmFseXNpcy9UcmFuc2NyaXB0X1JlZmluZWQvTGl2ZXItMTBYX0cxNzFDLyIpCmNvbG5hbWVzKHJhdy5kYXRhMSkgPC0gbGFwcGx5KGNvbG5hbWVzKHJhdy5kYXRhMSksIGZ1bmN0aW9uKHgpIHBhc3RlMCh0aXNzdWVfbWV0YWRhdGFfRzE3MUMkY2hhbm5lbFsxXSwnLScseCkpCiAgbWV0YS5kYXRhID0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSBjb2xuYW1lcyhyYXcuZGF0YTEpKQogIG1ldGEuZGF0YVsnY2hhbm5lbCddID0gdGlzc3VlX21ldGFkYXRhX0cxNzFDJGNoYW5uZWxbMV0KICBybmFtZXMgPSByb3cubmFtZXMobWV0YS5kYXRhKQogIG1ldGEuZGF0YSA8LSBtZXJnZShtZXRhLmRhdGEsIHRpc3N1ZV9tZXRhZGF0YV9HMTcxQywgc29ydCA9IEYpCiAgcm93Lm5hbWVzKG1ldGEuZGF0YSkgPC0gcm5hbWVzCiAgIyBPcmRlciB0aGUgY2VsbHMgYWxwaGFiZXRpY2FsbHkgdG8gZW5zdXJlIGNvbnNpc3RlbmN5LgogIAogIG9yZGVyZWRfY2VsbF9uYW1lczEgPSBvcmRlcihjb2xuYW1lcyhyYXcuZGF0YTEpKQogIHJhdy5kYXRhMSA9IHJhdy5kYXRhMVssb3JkZXJlZF9jZWxsX25hbWVzMV0KICBtZXRhLmRhdGEgPSBtZXRhLmRhdGFbb3JkZXJlZF9jZWxsX25hbWVzMSxdCiAgCiAgIyBGaW5kIEVSQ0MncywgY29tcHV0ZSB0aGUgcGVyY2VudCBFUkNDLCBhbmQgZHJvcCB0aGVtIGZyb20gdGhlIHJhdyBkYXRhLgogIGVyY2NzMSA8LSBncmVwKHBhdHRlcm4gPSAiXkVSQ0MtIiwgeCA9IHJvd25hbWVzKHggPSByYXcuZGF0YTEpLCB2YWx1ZSA9IFRSVUUpCiAgcGVyY2VudC5lcmNjIDwtIE1hdHJpeDo6Y29sU3VtcyhyYXcuZGF0YTFbZXJjY3MxLCBdKS9NYXRyaXg6OmNvbFN1bXMocmF3LmRhdGExKQogIGVyY2MuaW5kZXgxIDwtIGdyZXAocGF0dGVybiA9ICJeRVJDQy0iLCB4ID0gcm93bmFtZXMoeCA9IHJhdy5kYXRhMSksIHZhbHVlID0gRkFMU0UpCiAgcmF3LmRhdGExIDwtIHJhdy5kYXRhMVstZXJjYy5pbmRleDEsXQogIAogICMgQ3JlYXRlIHRoZSBTZXVyYXQgb2JqZWN0IHdpdGggYWxsIHRoZSBkYXRhCiAgZHJvcGxldDEgPC0gQ3JlYXRlU2V1cmF0T2JqZWN0KHJhdy5kYXRhMSkgICAjIGRyb3BzZXEKICBkcm9wbGV0MSA8LSBBZGRNZXRhRGF0YShvYmplY3QgPSBkcm9wbGV0MSwgbWV0YS5kYXRhKSAKICBkcm9wbGV0MUBtZXRhLmRhdGEkdGVjaCA8LSAiRzE3MUMiCgojZHJvcGxldCA8LSBTdWJzZXREYXRhKGRyb3BsZXQsc3Vic2V0Lm5hbWVzID0gYygibkdlbmUiLCAiblVNSSIpLCBsb3cudGhyZXNob2xkcyA9IGMoNTAwLCAxMDAwKSkgICMgb2xkIHZlcnNpb24gb2Ygc2V1cmF0CiNkcm9wbGV0MSA8LSAgc3Vic2V0KGRyb3BsZXQxLCBzdWJzZXQgPSBuRmVhdHVyZV9STkEgPiAyMDAgJiBuQ291bnRfUk5BID4gNTAwKQpkcm9wbGV0MSA8LSBOb3JtYWxpemVEYXRhKGRyb3BsZXQxLCB2ZXJib3NlID0gRkFMU0UpCmRyb3BsZXQxIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKGRyb3BsZXQxLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCmRyb3BsZXQxJHN0aW0gPC0gIkcxNzFDIgoKZHJvcGxldDEgPC0gU0NUcmFuc2Zvcm0oZHJvcGxldDEsdmVyYm9zZSA9VFJVRSkKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmNvbWJpbmVkLmZlYXR1cmVzIDwtIFNlbGVjdEludGVncmF0aW9uRmVhdHVyZXMob2JqZWN0Lmxpc3QgPSBsaXN0KGRyb3BsZXQsIGRyb3BsZXQxKSwgbmZlYXR1cmVzID0gMjAwMCkKY29tYmluZWQubGlzdCA8LSBQcmVwU0NUSW50ZWdyYXRpb24ob2JqZWN0Lmxpc3QgPSBsaXN0KGRyb3BsZXQsIGRyb3BsZXQxKSwgYW5jaG9yLmZlYXR1cmVzID0gY29tYmluZWQuZmVhdHVyZXMsIAogICAgdmVyYm9zZSA9IFRSVUUpCgpjb21iaW5lZC5hbmNob3JzIDwtIEZpbmRJbnRlZ3JhdGlvbkFuY2hvcnMob2JqZWN0Lmxpc3QgPSBjb21iaW5lZC5saXN0LCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJTQ1QiLGFuY2hvci5mZWF0dXJlcyA9IGNvbWJpbmVkLmZlYXR1cmVzLCB2ZXJib3NlID0gVFJVRSkKY29tYmluZWQuaW50ZWdyYXRlZCA8LSBJbnRlZ3JhdGVEYXRhKGFuY2hvcnNldCA9IGNvbWJpbmVkLmFuY2hvcnMsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIlNDVCIsIHZlcmJvc2UgPSBUUlVFKQoKY29tYmluZWQuaW50ZWdyYXRlZCA8LSBSdW5QQ0EoY29tYmluZWQuaW50ZWdyYXRlZCwgdmVyYm9zZSA9IEZBTFNFKQpjb21iaW5lZC5pbnRlZ3JhdGVkIDwtIFJ1blVNQVAoY29tYmluZWQuaW50ZWdyYXRlZCwgZGltcyA9IDE6MzApCnBsb3RzIDwtIERpbVBsb3QoY29tYmluZWQuaW50ZWdyYXRlZCwgZ3JvdXAuYnkgPSBjKCJzdGltIiwgIm1vdXNlLnNleCIpLCBjb21iaW5lID0gRkFMU0UpCnBsb3RzIDwtIGxhcHBseShYID0gcGxvdHMsIEZVTiA9IGZ1bmN0aW9uKHgpIHggKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKyBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQobnJvdyA9IDMsIAogICAgYnlyb3cgPSBUUlVFLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSkpKQpDb21iaW5lUGxvdHMocGxvdHMpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIzMgb3B0aW9uIDIgc3RhbmRhcmQgd29ya2Zsb3cgbWVyZ2luZyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwphbmNob3JzIDwtIEZpbmRJbnRlZ3JhdGlvbkFuY2hvcnMob2JqZWN0Lmxpc3QgPSBsaXN0KGRyb3BsZXQsIGRyb3BsZXQxKSwgZGltcyA9IDE6NTAsIGFuY2hvci5mZWF0dXJlcyA9IDMwMDApCiNhbmNob3JzIDwtIEZpbmRJbnRlZ3JhdGlvbkFuY2hvcnMob2JqZWN0Lmxpc3QgPSBsaXN0KGxuYzU5OTgsIGRyb3BsZXQxKSwgZGltcyA9IDE6NTAsIGFuY2hvci5mZWF0dXJlcyA9IDMwMDApCmNvbWJpbmVkIDwtIEludGVncmF0ZURhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgZGltcyA9IDE6NTApICAgIAoKRGVmYXVsdEFzc2F5KGNvbWJpbmVkKSA8LSAiaW50ZWdyYXRlZCIKIyBSdW4gdGhlIHN0YW5kYXJkIHdvcmtmbG93IGZvciB2aXN1YWxpemF0aW9uIGFuZCBjbHVzdGVyaW5nCmNvbWJpbmVkIDwtIFNjYWxlRGF0YShjb21iaW5lZCwgdmVyYm9zZSA9IEZBTFNFKQpjb21iaW5lZCA8LSBSdW5QQ0EoY29tYmluZWQsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiMgdC1TTkUgYW5kIENsdXN0ZXJpbmcKY29tYmluZWQgPC0gUnVuVU1BUChjb21iaW5lZCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjI1KQpjb21iaW5lZCA8LSBGaW5kTmVpZ2hib3JzKGNvbWJpbmVkLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MTApCmNvbWJpbmVkIDwtIEZpbmRDbHVzdGVycyhjb21iaW5lZCwgcmVzb2x1dGlvbiA9IDAuNSApICAgCmNvbWJpbmVkIDwtIFJ1blRTTkUoY29tYmluZWQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKICAgIAogIyBWaXN1YWxpemF0aW9uCnAxIDwtIFVNQVBQbG90KGNvbWJpbmVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInN0aW0iLCBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTUpCnAxLjEgPC0gVU1BUFBsb3QoY29tYmluZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgc3BsaXQuYnkgPSAic3RpbSIsbGFiZWw9VFJVRSwgbGFiZWwuc2l6ZT01KSAgIAoKcDIgPC0gVU1BUFBsb3QoY29tYmluZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAibW91c2Uuc2V4IikKcDMgPC0gVU1BUFBsb3QoY29tYmluZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5zaXplPTMpCnA0IDwtIFVNQVBQbG90KGNvbWJpbmVkLCBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTYpCgpwbG90X2dyaWQocDEsIHA0KSAKCkRpbVBsb3QoY29tYmluZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgc3BsaXQuYnkgPSAic3RpbSIpICAgCgoKI2NsdXN0ZXIuYXZlcmFnZXMgPC0gQXZlcmFnZUV4cHJlc3Npb24oY29tYmluZWQsdXNlLmNvdW50cyA9IFRSVUUsKQoKcDUgPC0gRGltUGxvdChjb21iaW5lZCwgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJzdGltIikKcDYgPC0gRGltUGxvdChjb21iaW5lZCwgcmVkdWN0aW9uID0gInRzbmUiLCBncm91cC5ieSA9ICJtb3VzZS5zZXgiKQpwNyA8LSBEaW1QbG90KGNvbWJpbmVkLCByZWR1Y3Rpb24gPSAidHNuZSIsIGxhYmVsID0gVFJVRSkKcDggPC0gVFNORVBsb3QoY29tYmluZWQsIGxhYmVsID1UKQpwbG90X2dyaWQocDYsIHA3LHA4KSAKRGltUGxvdChjb21iaW5lZCwgcmVkdWN0aW9uID0gInRzbmUiLCBzcGxpdC5ieSA9ICJzdGltIikgICAKCmBgYAoKCgpkaWZmdXNpb24gcGx0IGNvZGUgCgpgYGB7cn0KIyBCZWZvcmUgcnVubmluZyBNRFMsIHdlIGZpcnN0IGNhbGN1bGF0ZSBhIGRpc3RhbmNlIG1hdHJpeCBiZXR3ZWVuIGFsbCBwYWlycyBvZiBjZWxscy4gIEhlcmUgd2UKIyB1c2UgYSBzaW1wbGUgZXVjbGlkZWFuIGRpc3RhbmNlIG1ldHJpYyBvbiBhbGwgZ2VuZXMsIHVzaW5nIHNjYWxlLmRhdGEgYXMgaW5wdXQKZCA8LSBkaXN0KHQoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gInNjYWxlLmRhdGEiKSkpCiMgUnVuIHRoZSBNRFMgcHJvY2VkdXJlLCBrIGRldGVybWluZXMgdGhlIG51bWJlciBvZiBkaW1lbnNpb25zCm1kcyA8LSBjbWRzY2FsZShkID0gZCwgayA9IDIpCiMgY21kc2NhbGUgcmV0dXJucyB0aGUgY2VsbCBlbWJlZGRpbmdzLCB3ZSBmaXJzdCBsYWJlbCB0aGUgY29sdW1ucyB0byBlbnN1cmUgZG93bnN0cmVhbQojIGNvbnNpc3RlbmN5CmNvbG5hbWVzKG1kcykgPC0gcGFzdGUwKCJNRFNfIiwgMToyKQojIFdlIHdpbGwgbm93IHN0b3JlIHRoaXMgYXMgYSBjdXN0b20gZGltZW5zaW9uYWwgcmVkdWN0aW9uIGNhbGxlZCAnbWRzJwpjb21iaW5lZFtbIm1kcyJdXSA8LSBDcmVhdGVEaW1SZWR1Y09iamVjdChlbWJlZGRpbmdzID0gbWRzLCBrZXkgPSAiTURTXyIsIGFzc2F5ID0gRGVmYXVsdEFzc2F5KGNvbWJpbmVkKSkKCiMgV2UgY2FuIG5vdyB1c2UgdGhpcyBhcyB5b3Ugd291bGQgYW55IG90aGVyIGRpbWVuc2lvbmFsIHJlZHVjdGlvbiBpbiBhbGwgZG93bnN0cmVhbSBmdW5jdGlvbnMKRGltUGxvdChjb21iaW5lZCwgcmVkdWN0aW9uID0gIm1kcyIsIHB0LnNpemUgPSAwLjUpCmBgYAoKCgoKYGBge3J9Cgpkcm9wbGV0X21ldGFkYXRhIDwtIHJlYWQuY3N2KCIvcmVzdHJpY3RlZC9wcm9qZWN0bmIvd2F4bWFubGFiL2trYXJyaS9zY1JOQXNlcV9kYXRhX2ludGVncmF0aW9uL21ldGFkYXRhX2Ryb3BsZXRfbGl2ZXIuY3N2Iiwgc2VwPSIsIiwgaGVhZGVyID0gVFJVRSkKY29sbmFtZXMoZHJvcGxldF9tZXRhZGF0YSlbMV0gPC0gImNoYW5uZWwiCnRpc3N1ZV9tZXRhZGF0YTEgPSBmaWx0ZXIoZHJvcGxldF9tZXRhZGF0YSwgdGlzc3VlID09IHRpc3N1ZV9vZl9pbnRlcmVzdClbLGMoJ2NoYW5uZWwnLCd0aXNzdWUnLCdzdWJ0aXNzdWUnLCdtb3VzZS5zZXgnLCAnbW91c2UuaWQnKV0KCnJhdy5kYXRhMiA8LSBSZWFkMTBYKCIvcmVzdHJpY3RlZC9wcm9qZWN0bmIvd2F4bWFubGFiL2trYXJyaS9zY1JOQXNlcV9kYXRhX2ludGVncmF0aW9uL1JlZmluZWRfY2VsbG1hdHJpY2VzL0xpdmVyLTEwWF9QNF8yLyIpCmNvbG5hbWVzKHJhdy5kYXRhMikgPC0gbGFwcGx5KGNvbG5hbWVzKHJhdy5kYXRhMiksIGZ1bmN0aW9uKHgpIHBhc3RlMCh0aXNzdWVfbWV0YWRhdGExJGNoYW5uZWxbMV0sJ18nLHgpKQogIG1ldGEuZGF0YTIgPSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGNvbG5hbWVzKHJhdy5kYXRhMikpCiAgbWV0YS5kYXRhMlsnY2hhbm5lbCddID0gdGlzc3VlX21ldGFkYXRhMSRjaGFubmVsWzFdCgogIAogICAgaWYgKGxlbmd0aCh0aXNzdWVfbWV0YWRhdGExJGNoYW5uZWwpID4gMSl7CiAgICAjIFNvbWUgdGlzc3VlcywgbGlrZSBUaHltdXMgYW5kIEhlYXJ0IGhhZCBvbmx5IG9uZSBjaGFubmVsCiAgICBmb3IoaSBpbiAyOm5yb3codGlzc3VlX21ldGFkYXRhMSkpewpzdWJmb2xkZXIgPSBwYXN0ZTAoIi9yZXN0cmljdGVkL3Byb2plY3RuYi93YXhtYW5sYWIva2thcnJpL3NjUk5Bc2VxX2RhdGFfaW50ZWdyYXRpb24vUmVmaW5lZF9jZWxsbWF0cmljZXMvIix0aXNzdWVfb2ZfaW50ZXJlc3QsICctJywgdGlzc3VlX21ldGFkYXRhMSRjaGFubmVsW2ldKQogICAgICBuZXcuZGF0YTEgPC0gUmVhZDEwWChkYXRhLmRpciA9IHN1YmZvbGRlcikKICAgICAgY29sbmFtZXMobmV3LmRhdGExKSA8LSBsYXBwbHkoY29sbmFtZXMobmV3LmRhdGExKSwgZnVuY3Rpb24oeCkgcGFzdGUwKHRpc3N1ZV9tZXRhZGF0YTEkY2hhbm5lbFtpXSwnXycsIHgpKQogICAgICBuZXcubWV0YWRhdGExID0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSBjb2xuYW1lcyhuZXcuZGF0YTEpKQogICAgICBuZXcubWV0YWRhdGExWydjaGFubmVsJ10gPSB0aXNzdWVfbWV0YWRhdGExJGNoYW5uZWxbaV0KCiAgICAgIHJhdy5kYXRhMiA9IGNiaW5kKHJhdy5kYXRhMiwgbmV3LmRhdGExKQogICAgICBtZXRhLmRhdGEyID0gcmJpbmQobWV0YS5kYXRhMiwgbmV3Lm1ldGFkYXRhMSkgfX0KICAKICAKICBybmFtZXMgPSByb3cubmFtZXMobWV0YS5kYXRhMikKICBtZXRhLmRhdGEyIDwtIG1lcmdlKG1ldGEuZGF0YTIsIHRpc3N1ZV9tZXRhZGF0YTEsIHNvcnQgPSBGKQogIHJvdy5uYW1lcyhtZXRhLmRhdGEyKSA8LSBybmFtZXMKICAgCiAgIyBPcmRlciB0aGUgY2VsbHMgYWxwaGFiZXRpY2FsbHkgdG8gZW5zdXJlIGNvbnNpc3RlbmN5LgoKICBvcmRlcmVkX2NlbGxfbmFtZXMgPSBvcmRlcihjb2xuYW1lcyhyYXcuZGF0YTIpKQogIHJhdy5kYXRhMiA9IHJhdy5kYXRhMlssb3JkZXJlZF9jZWxsX25hbWVzXQogIG1ldGEuZGF0YTIgPSBtZXRhLmRhdGEyW29yZGVyZWRfY2VsbF9uYW1lcyxdCgogICMgRmluZCBFUkNDJ3MsIGNvbXB1dGUgdGhlIHBlcmNlbnQgRVJDQywgYW5kIGRyb3AgdGhlbSBmcm9tIHRoZSByYXcgZGF0YS4KICBlcmNjcyA8LSBncmVwKHBhdHRlcm4gPSAiXkVSQ0MtIiwgeCA9IHJvd25hbWVzKHggPSByYXcuZGF0YTIpLCB2YWx1ZSA9IFRSVUUpCiAgcGVyY2VudC5lcmNjIDwtIE1hdHJpeDo6Y29sU3VtcyhyYXcuZGF0YTJbZXJjY3MsIF0pL01hdHJpeDo6Y29sU3VtcyhyYXcuZGF0YTIpCiAgZXJjYy5pbmRleCA8LSBncmVwKHBhdHRlcm4gPSAiXkVSQ0MtIiwgeCA9IHJvd25hbWVzKHggPSByYXcuZGF0YTIpLCB2YWx1ZSA9IEZBTFNFKQogIHJhdy5kYXRhMiA8LSByYXcuZGF0YTJbLWVyY2MuaW5kZXgsXQoKICAjIENyZWF0ZSB0aGUgU2V1cmF0IG9iamVjdCB3aXRoIGFsbCB0aGUgZGF0YQogIAogIGRyb3BsZXQyIDwtIENyZWF0ZVNldXJhdE9iamVjdChyYXcuZGF0YTIpICAgIyBkcm9wc2VxCiAgZHJvcGxldDIgPC0gQWRkTWV0YURhdGEob2JqZWN0ID0gZHJvcGxldDIsIG1ldGEuZGF0YTIpCiAgZHJvcGxldDJAbWV0YS5kYXRhJHRlY2ggPC0gImRyb3BsZXQiCgojZHJvcGxldCA8LSBTdWJzZXREYXRhKGRyb3BsZXQsc3Vic2V0Lm5hbWVzID0gYygibkdlbmUiLCAiblVNSSIpLCBsb3cudGhyZXNob2xkcyA9IGMoNTAwLCAxMDAwKSkgICMgb2xkIHZlcnNpb24gb2Ygc2V1cmF0CmRyb3BsZXQyIDwtICBzdWJzZXQoZHJvcGxldDIsIHN1YnNldCA9IG5GZWF0dXJlX1JOQSA+IDUwMCAmIG5Db3VudF9STkEgPiAxMDAwKQoKZHJvcGxldDIgPC0gTm9ybWFsaXplRGF0YShkcm9wbGV0MiwgdmVyYm9zZSA9IEZBTFNFKQpkcm9wbGV0MiA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhkcm9wbGV0Miwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQoKZHJvcGxldDIkc3RpbSA8LSAiY29udHJvbCIKCgoKYGBgCgoKCmBgYHtyfQpEZWZhdWx0QXNzYXkoY29tYmluZWQpIDwtICJSTkEiCiNjb21iaW5lZCA8LSBOb3JtYWxpemVEYXRhKGNvbWJpbmVkLCB2ZXJib3NlID0gVFJVRSwgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiUkMiLCBzY2FsZS5mYWN0b3IgPSAxZTYpCmNvbWJpbmVkIDwtIE5vcm1hbGl6ZURhdGEoY29tYmluZWQsIHZlcmJvc2UgPSBUUlVFKQojIE5vcm1hbGl6ZSBSTkEgZGF0YSBmb3IgdmlzdWFsaXphdGlvbiBwdXJwb3NlcyAgaWYgdXNpbmcgc2N0cmFuZm9ybSAKI2NvbWJpbmVkLmludGVncmF0ZWQgPC0gTm9ybWFsaXplRGF0YShjb21iaW5lZC5pbnRlZ3JhdGVkLCB2ZXJib3NlID0gRkFMU0UpCgpEb3RQbG90KGNvbWJpbmVkLCBmZWF0dXJlcyA9IGFsbF9nZW5lcykKCkZlYXR1cmVQbG90KGNvbWJpbmVkLCBmZWF0dXJlcyA9IGdlbmVzX2hlcF9tYWluLCBtaW4uY3V0b2ZmID0gInE5IikKI2hlcGF0b2N5dGVzIApzdWJ0aXNzcGxvdCA8LSBEb3RQbG90KGNvbWJpbmVkLCBmZWF0dXJlcyA9IGMoZ2VuZXNfaGVwX21haW4sIGdlbmVzX2VuZG8sIGdlbmVzX2JlY19iX2ltbXVuZSwgZ2VuZXNfa3VwcGZlciwgZ2VuZXNfbmspKQpQQyA8LSBEb3RQbG90KGNvbWJpbmVkLCBmZWF0dXJlcyA9IGMoZ2VuZXNfaGVwX21haW4sZ2VuZXNfem9uZXMpKQpOUEMgPC0gRG90UGxvdChjb21iaW5lZCwgZmVhdHVyZXMgPSBjKGdlbmVzX2VuZG8sZ2VuZXNfa3VwcGZlciwgZ2VuZXNfbmspKQphbGwgPC0gRG90UGxvdChjb21iaW5lZCwgZmVhdHVyZXM9YyhhbGxfZ2VuZXMpKQoKIyMjIGNvZXhwcmVzc2lvbiBwbG90cyMjIyMKCmYxIDwtIEZlYXR1cmVQbG90KEtPLmNlbGxzLCBmZWF0dXJlcyA9IGMoJ0N5cDJiMTAnLCduY1JOQS1pbnRlci1jaHI3LTU5OTgnKSwgcmVkdWN0aW9uID0gIm1kcyIsIG9yZGVyID0gVFJVRSxzcGxpdC5ieSA9ICJzdGltIiwgYmxlbmQgPSBUUlVFLHNvcnQuY2VsbCA9IFRSVUUsIG1heC5jdXRvZmYgPSAwLjUpCgoKIyMjIyMjIyMjIyB0aGlzIGlzIGV4YWN0IGF2ZXJhZ2luZyBmb3JtdWxhICMjIyMjIyMjIyMjIyMjIzMzCiAgeCA8LSAoQXZlcmFnZUV4cHJlc3Npb24oS08uY2VsbHMsIHZlcmJvc2UgPSBUUlVFLCBhc3NheXMgPSAiUk5BIiAsc2xvdD0iY291bnRzIikkUk5BKQogICB4WyJuY1JOQS1pbnRlci1jaHI3LTU5OTgiLF0KIyAgICAgICAgICAgICAgICAgICAgICAgICBHMTcxQiAgICBHMTcxQwojbmNSTkEtaW50ZXItY2hyNy01OTk4IDEuODcxNzk1IDEuMDkxNDYzCiMjIyMjIyMjCiNJZGVudHMoY29tYmluZWQpIDwtIGZhY3RvcihJZGVudHMoY29tYmluZWQpLCBsZXZlbHMgPSBjKDAsMSwxMikpCm1hcmtlcnMudG8ucGxvdCA8LSBjKCJBbGIiLCJuY1JOQS1pbnRlci1jaHI3LTU5OTgiKQpEb3RQbG90KGNvbWJpbmVkLCBmZWF0dXJlcyA9IHJldihtYXJrZXJzLnRvLnBsb3QpLCBjb2xzID0gYygiYmx1ZSIsICJyZWQiKSwgZG90LnNjYWxlID0gOCwgCiAgICBzcGxpdC5ieSA9ICJzdGltIikgKyBSb3RhdGVkQXhpcygpCgpGZWF0dXJlUGxvdChjb21iaW5lZCwgZmVhdHVyZXMgPSBjKCJBbGIiLCAibmNSTkEtaW50ZXItY2hyNy01OTk4IiwiQ3lwMmIxMCIsImRTYUNhczkiLCJLUkFCIiwiQUFWOC1tQ2hlcnJ5IiksIHNwbGl0LmJ5ID0gInN0aW0iLCBtYXguY3V0b2ZmID0gMywgY29scyA9IGMoImdyZXkiLCAicmVkIikpCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyB2bG5wbG90ICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpwbG90cyA8LSBWbG5QbG90KGNvbWJpbmVkLCBmZWF0dXJlcyA9IGMoIkFsYiIsICJuY1JOQS1pbnRlci1jaHI3LTU5OTgiLCJDeXAyYjEwIiwiZFNhQ2FzOSIpLCBzcGxpdC5ieSA9ICJzdGltIiwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgcHQuc2l6ZSA9IDAsIGNvbWJpbmUgPSBGQUxTRSkKQ29tYmluZVBsb3RzKHBsb3RzID0gcGxvdHMsIG5jb2wgPSAxKQoKcGxvdHMgPC0gVmxuUGxvdChjb21iaW5lZCwgZmVhdHVyZXMgPSBjKCJMaHg0IiwiRHRuYSIsIkZhbTE4OWExIiwiR2FsbnQxNiIsIkthbHJuIiksIHNwbGl0LmJ5ID0gInN0aW0iLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBwdC5zaXplID0gMCwgY29tYmluZSA9IEZBTFNFKQpDb21iaW5lUGxvdHMocGxvdHMgPSBwbG90cywgbmNvbCA9IDEpCgoKI2VuZG90aGVsaWFsCkRvdFBsb3QoY29tYmluZWQsIGZlYXR1cmVzID0gZ2VuZXNfZW5kbykKCiN6b25lcwp6b25lcyA8LSBEb3RQbG90KGNvbWJpbmVkLCBmZWF0dXJlcyA9IGdlbmVzX3pvbmVzKQoKZjEgPC0gRmVhdHVyZVBsb3QoY29tYmluZWQsIGZlYXR1cmVzID0gYygnQ3lwMmUxJywnQ3lwMmYyJywnQXNzMScpLCBtaW4uY3V0b2ZmID0gInE5IiwgcmVkdWN0aW9uID0gInRzbmUiKQoKRGltUGxvdChjb21iaW5lZCwgbGFiZWwgPSBUUlVFKQoKc2F2ZShjb21iaW5lZCwgZmlsZT0iU2V1cmF0X3NtYXJ0LWRyb3BfaW50ZWdyYXRlZC5Sb2JqIikKCgojIyMjIyMjIyMjIyMjIyMjIyBzYXZlIHJhdyBjb3VudHMgZnJvbSBjbHVzdGVyICMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKSWRlbnRzKGNvbWJpbmVkKSA8LSAic3RpbSIKCiMjIyB0byBhdmVyZ2FlIG91dCB0aGUgbWF0cml4IGZyb20gS08gY2VsbHMgCgpjb21iaW5lZC5yYXcuZGF0YS4wLjEgPC0gYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJkYXRhIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDAsaWRlbnRzID0gInN0aW0iKV0pCmNvbWJpbmVkLnJhdy5kYXRhLjEgPC0gYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJjb3VudHMiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gMCldKQpjb21iaW5lZC5yYXcuZGF0YS4yIDwtIGFzLm1hdHJpeChHZXRBc3NheURhdGEoY29tYmluZWQsIHNsb3QgPSAiY291bnRzIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDApXSkKCiNjb21iaW5lZC5yYXcuZGF0YS5baV0gPC0gYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJjb3VudHMiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gMSldKQojY29tYmluZWQucmF3LmRhdGEuMTIgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSAxMildKQojY29tYmluZWQucmF3LmRhdGEuMSA8LSBhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpKQp4IDwtIEF2ZXJhZ2VFeHByZXNzaW9uKHRlc3QuY29tYmluZWQsYXNzYXlzID0gIlJOQSIsYWRkLmlkZW50ID0gInN0aW0iLCBzbG90ID0gImRhdGEiLHVzZS5zY2FsZSA9IEZBTFNFLCB1c2UuY291bnRzID0gRkFMU0UpJFJOQQoKCgojfSMjIyMjIyMjIENBUiBkYXRhIAphdmcuY29tYmluZWQuY2VsbHMgPC0gKEF2ZXJhZ2VFeHByZXNzaW9uKGNvbWJpbmVkLCB2ZXJib3NlID0gRkFMU0UpJFJOQSkgCmF2Zy5jb21iaW5lZC5jZWxscyRnZW5lIDwtIHJvd25hbWVzKGF2Zy5jb21iaW5lZC5jZWxscykKCkNBUl9GUCA8LSBGZWF0dXJlUGxvdChjb21iaW5lZCwgZmVhdHVyZXMgPSBjKCdDeXAyYjEwJywnTnIxaTMnKSwgcmVkdWN0aW9uID0gInVtYXAiLCBvcmRlciA9IFRSVUUsc3BsaXQuYnkgPSAic3RpbSIsIGJsZW5kID0gVFJVRSxzb3J0LmNlbGwgPSBUUlVFLCBtYXguY3V0b2ZmID0gMSwgbWluLmN1dG9mZiA9IDAsIHB0LnNpemUgPSAwLjUsIHJlcGVsID0gVFJVRSkKQ0FSX0RPVF9OUiA8LSBEb3RQbG90KGNvbWJpbmVkLCBmZWF0dXJlcyA9ICdOcjFpMycsIGNvbC5taW4gPSAwKQoKQ3lwMmIxMF9GUCA8LSBGZWF0dXJlUGxvdChjb21iaW5lZCwgZmVhdHVyZXMgPSAnQ3lwMmIxMCcsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbWluLmN1dG9mZiA9IDApCiMjIyMjIyMjIyMjIHRTTkUgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCmNvbWJpbmVkIDwtIE5vcm1hbGl6ZURhdGEob2JqZWN0ID0gY29tYmluZWQpCmNvbWJpbmVkIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKGNvbWJpbmVkLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCgpgYGAKCgpgYGB7cn0KCktPLmNlbGxzIDwtIHN1YnNldChjb21iaW5lZCwgaWRlbnRzID0gYygiMCIsIjEiLCIxMiIpKQpJZGVudHMoS08uY2VsbHMpIDwtICJzdGltIgoKCiMjIyB0byBhdmVyZ2FlIG91dCB0aGUgbWF0cml4IGZyb20gS08gY2VsbHMgCnJhdy5kYXRhLjAgPC0gYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9IGMoImNvdW50cyIsImRhdGEiKSlbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDApXSkKcmF3LmRhdGEuMSA8LSBhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSAxKV0pCnJhdy5kYXRhLjIgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSAyKV0pCnJhdy5kYXRhLjMgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSAzKV0pCnJhdy5kYXRhLjQgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSA0KV0pCnJhdy5kYXRhLjUgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSA1KV0pCnJhdy5kYXRhLjYgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSA2KV0pCnJhdy5kYXRhLjcgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSA3KV0pCnJhdy5kYXRhLjggPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSA4KV0pCnJhdy5kYXRhLjkgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSA5KV0pCnJhdy5kYXRhLjEwIDwtYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJjb3VudHMiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gMTApXSkKcmF3LmRhdGEuMTEgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSAxMSldKQpyYXcuZGF0YS4xMiA8LWFzLm1hdHJpeChHZXRBc3NheURhdGEoY29tYmluZWQsIHNsb3QgPSAiY291bnRzIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDEyKV0pCgoKVFBNY291bnQwPC0gY2JpbmQoYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJjb3VudHMiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gMCldKSwgYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJkYXRhIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDApXSkpCgpUUE1jb3VudDE8LSBjYmluZChhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSAxKV0pLCBhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImRhdGEiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gMSldKSkKClRQTWNvdW50MjwtIGNiaW5kKGFzLm1hdHJpeChHZXRBc3NheURhdGEoY29tYmluZWQsIHNsb3QgPSAiY291bnRzIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDIpXSksIGFzLm1hdHJpeChHZXRBc3NheURhdGEoY29tYmluZWQsIHNsb3QgPSAiZGF0YSIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSAyKV0pKQoKVFBNY291bnQzPC0gY2JpbmQoYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJjb3VudHMiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gMyldKSwgYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJkYXRhIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDMpXSkpCgpUUE1jb3VudDQ8LSBjYmluZChhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSA0KV0pLCBhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImRhdGEiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gNCldKSkKClRQTWNvdW50NTwtIGNiaW5kKGFzLm1hdHJpeChHZXRBc3NheURhdGEoY29tYmluZWQsIHNsb3QgPSAiY291bnRzIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDUpXSksIGFzLm1hdHJpeChHZXRBc3NheURhdGEoY29tYmluZWQsIHNsb3QgPSAiZGF0YSIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSA1KV0pKQoKVFBNY291bnQ2PC0gY2JpbmQoYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJjb3VudHMiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gNildKSwgYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJkYXRhIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDYpXSkpCgpUUE1jb3VudDc8LSBjYmluZChhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSA3KV0pLCBhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImRhdGEiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gNyldKSkKClRQTWNvdW50ODwtIGNiaW5kKGFzLm1hdHJpeChHZXRBc3NheURhdGEoY29tYmluZWQsIHNsb3QgPSAiY291bnRzIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDgpXSksIGFzLm1hdHJpeChHZXRBc3NheURhdGEoY29tYmluZWQsIHNsb3QgPSAiZGF0YSIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSA4KV0pKQoKVFBNY291bnQ5PC0gY2JpbmQoYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJjb3VudHMiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gOSldKSwgYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJkYXRhIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDkpXSkpCgpUUE1jb3VudDEwPC0gY2JpbmQoYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJjb3VudHMiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gMTApXSksIGFzLm1hdHJpeChHZXRBc3NheURhdGEoY29tYmluZWQsIHNsb3QgPSAiZGF0YSIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSAxMCldKSkKClRQTWNvdW50MTE8LSBjYmluZChhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhjb21iaW5lZCwgaWRlbnQgPSAxMSldKSwgYXMubWF0cml4KEdldEFzc2F5RGF0YShjb21iaW5lZCwgc2xvdCA9ICJkYXRhIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDExKV0pKQoKVFBNY291bnQxMjwtIGNiaW5kKGFzLm1hdHJpeChHZXRBc3NheURhdGEoY29tYmluZWQsIHNsb3QgPSAiY291bnRzIilbLCBXaGljaENlbGxzKGNvbWJpbmVkLCBpZGVudCA9IDEyKV0pLCBhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKGNvbWJpbmVkLCBzbG90ID0gImRhdGEiKVssIFdoaWNoQ2VsbHMoY29tYmluZWQsIGlkZW50ID0gMTIpXSkpCgoKCgp3cml0ZS5jc3YoVFBNY291bnQwLCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50MC5jc3YiKQp3cml0ZS5jc3YoVFBNY291bnQxLCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50MS5jc3YiKQp3cml0ZS5jc3YoVFBNY291bnQyLCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50Mi5jc3YiKQp3cml0ZS5jc3YoVFBNY291bnQzLCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50My5jc3YiKQp3cml0ZS5jc3YoVFBNY291bnQ0LCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50NC5jc3YiKQp3cml0ZS5jc3YoVFBNY291bnQ1LCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50NS5jc3YiKQp3cml0ZS5jc3YoVFBNY291bnQ2LCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50Ni5jc3YiKQp3cml0ZS5jc3YoVFBNY291bnQ3LCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50Ny5jc3YiKQp3cml0ZS5jc3YoVFBNY291bnQ4LCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50OC5jc3YiKQp3cml0ZS5jc3YoVFBNY291bnQ5LCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50OS5jc3YiKQp3cml0ZS5jc3YoVFBNY291bnQxMCwgIkNvdW50UmVzdWx0L2NvdW50cy5UUE1jb3VudDEwLmNzdiIpCndyaXRlLmNzdihUUE1jb3VudDExLCAiQ291bnRSZXN1bHQvY291bnRzLlRQTWNvdW50MTEuY3N2IikKd3JpdGUuY3N2KFRQTWNvdW50MTIsICJDb3VudFJlc3VsdC9jb3VudHMuVFBNY291bnQxMi5jc3YiKQoKCgojYXZnLktPLmNlbGxzIDwtIGxvZzFwKEF2ZXJhZ2VFeHByZXNzaW9uKEtPLmNlbGxzLCB2ZXJib3NlID0gRkFMU0UpJFJOQSkgICNvcmlnaW5hbCBjb2RlIGxvZyB0cmFuc2Zvcm1lZAphdmcuS08uY2VsbHMgPC0gKEF2ZXJhZ2VFeHByZXNzaW9uKEtPLmNlbGxzLCB2ZXJib3NlID0gRkFMU0UpJFJOQSkgCmF2Zy5LTy5jZWxscyRnZW5lIDwtIHJvd25hbWVzKGF2Zy5LTy5jZWxscykKCmdlbmVzLnRvLmxhYmVsPSAoIm5jUk5BLWludGVyLWNocjctNTk5OCIpCiNnZW5lcy50by5sYWJlbCA9IGMoIklTRzE1IiwgIkxZNkUiLCAiSUZJNiIsICJJU0cyMCIsICJNWDEiLCAiSUZJVDIiLCAiSUZJVDEiLCAiQ1hDTDEwIiwgIkNDTDgiKQpwMSA8LSBnZ3Bsb3QoYXZnLktPLmNlbGxzLCBhZXMoQ1RSTCwgU1RJTSkpICsgZ2VvbV9wb2ludCgpICsgZ2d0aXRsZSgiQ0Q0IE5haXZlIFQgQ2VsbHMiKQpwMSA8LSBMYWJlbFBvaW50cyhwbG90ID0gcDEsIHBvaW50cyA9IGdlbmVzLnRvLmxhYmVsLCByZXBlbCA9IFRSVUUpCnAyIDwtIGdncGxvdChhdmcuY2QxNC5tb25vLCBhZXMoQ1RSTCwgU1RJTSkpICsgZ2VvbV9wb2ludCgpICsgZ2d0aXRsZSgiQ0QxNCBNb25vY3l0ZXMiKQpwMiA8LSBMYWJlbFBvaW50cyhwbG90ID0gcDIsIHBvaW50cyA9IGdlbmVzLnRvLmxhYmVsLCByZXBlbCA9IFRSVUUpCnBsb3RfZ3JpZChwMSwgcDIpCmBgYAoKCgoKCmBgYHtyfQpEZWZhdWx0QXNzYXkoY29tYmluZWQpIDwtICJSTkEiCktPLmNlbGxzLjAgPC0gc3Vic2V0KGNvbWJpbmVkLCBpZGVudHMgPSBjKCIwIikpCklkZW50cyhLTy5jZWxscy4wKSA8LSAiQWxsMCIKRGVmYXVsdEFzc2F5KEtPLmNlbGxzLjApIDwtICJSTkEiCktPLmNlbGxzLjAubG5jNTk5OCA8LSBzdWJzZXQoS08uY2VsbHMuMCAsIHN1YnNldCA9IGBuY1JOQS1pbnRlci1jaHI3LTU5OThgID4wKQpLTy5jZWxscy4wLmxuYzU5OTggPC0gTm9ybWFsaXplRGF0YShLTy5jZWxscy4wLmxuYzU5OTgsIHZlcmJvc2UgPSBGQUxTRSkKS08uY2VsbHMuMC5sbmM1OTk4IDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKEtPLmNlbGxzLjAubG5jNTk5OCwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQoKS08uY2VsbHMuMC5sbmM1OTk4IDwtIFNjYWxlRGF0YShLTy5jZWxscy4wLmxuYzU5OTgsIHZlcmJvc2UgPSBGQUxTRSkKS08uY2VsbHMuMC5sbmM1OTk4IDwtIFJ1blBDQShLTy5jZWxscy4wLmxuYzU5OTgsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQojIHQtU05FIGFuZCBDbHVzdGVyaW5nCktPLmNlbGxzLjAubG5jNTk5OCA8LSBSdW5VTUFQKEtPLmNlbGxzLjAubG5jNTk5OCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwKQpLTy5jZWxscy4wLmxuYzU5OTggPC0gRmluZE5laWdoYm9ycyhLTy5jZWxscy4wLmxuYzU5OTgsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKS08uY2VsbHMuMC5sbmM1OTk4IDwtIEZpbmRDbHVzdGVycyhLTy5jZWxscy4wLmxuYzU5OTgsIHJlc29sdXRpb24gPSAwLjUpICAgCktPLmNlbGxzLjAubG5jNTk5OCA8LSBSdW5UU05FKEtPLmNlbGxzLjAubG5jNTk5OCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwKQogICAgCiAjIFZpc3VhbGl6YXRpb24KcDEgPC0gVU1BUFBsb3QoS08uY2VsbHMuMC5sbmM1OTk4LCByZWR1Y3Rpb24gPSAidW1hcCIsIHNwbGl0LmJ5ID0gInRlY2giLCBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTUpCnAxLjEgPC0gVU1BUFBsb3QoS08uY2VsbHMuMC5sbmM1OTk4LCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInRlY2giLGxhYmVsPVRSVUUsIGxhYmVsLnNpemU9NSkgICAKcDIgPC0gVU1BUFBsb3QoS08uY2VsbHMuMC5sbmM1OTk4LCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gIm1vdXNlLnNleCIpCnAzIDwtIFVNQVBQbG90KEtPLmNlbGxzLjAubG5jNTk5OCwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGxhYmVsLnNpemU9MykKcDQgPC0gVU1BUFBsb3QoS08uY2VsbHMuMC5sbmM1OTk4LCBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTYpCgoKS08uY2VsbC4wLmxuYzU5OThfREUxIDwtIEZpbmRNYXJrZXJzKEtPLmNlbGxzLjAubG5jNTk5OCwgaWRlbnQuMSA9IGMoMSwyKSwgaWRlbnQuMiA9IDAsdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKS08uY2VsbC4wLmxuYzU5OThfQWxsTWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhLTy5jZWxscy4wLmxuYzU5OTgsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIHRocmVzaC51c2UgPSAwLjI1KQoKS08uY2VsbC4wLmxuYzU5OThfQWxsTWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKDIsIGF2Z19sb2dGQykKd3JpdGUuY3N2KEtPLmNlbGwuMC5sbmM1OTk4X0RFMSwgIkFuYWx5c2lzL0NvdW50UmVzdWx0L01hcmtlcnMvS08uY2VsbC4wLmxuYzU5OThfREUxIikKd3JpdGUuY3N2KEtPLmNlbGwuMC5sbmM1OTk4X0FsbE1hcmtlcnMsICJBbmFseXNpcy9Db3VudFJlc3VsdC9NYXJrZXJzL0tPLmNlbGwuMC5sbmM1OTk4X0FsbE1hcmtlcnMiKQoKCktPLmNlbGxzLjAubG5jNTk5OCRjZWxsdHlwZS5zdGltIDwtIHBhc3RlKElkZW50cyhLTy5jZWxscy4wLmxuYzU5OTgpLCBLTy5jZWxscy4wLmxuYzU5OTgkdGVjaCwgc2VwID0gIl8iKQpLTy5jZWxscy4wLmxuYzU5OTgkY2VsbHR5cGUgPC0gSWRlbnRzKEtPLmNlbGxzLjAubG5jNTk5OCkKSWRlbnRzKEtPLmNlbGxzLjAubG5jNTk5OCkgPC0gImNlbGx0eXBlLnN0aW0iCiMjIyMjIyMjIyMjIyMzIEtPIGNlbGxzIHRoYXQgZXhwcmVzcyBsbmM1OTk4ICMjIyMjIyMjIyMjIyMjIyMjCgpEZWZhdWx0QXNzYXkoY29tYmluZWQpIDwtICJSTkEiCktPLmNlbGxzLjEgPC0gc3Vic2V0KGNvbWJpbmVkLCBpZGVudHMgPSBjKCIxIikpCklkZW50cyhLTy5jZWxscy4xKSA8LSAiQWxsMCIKRGVmYXVsdEFzc2F5KEtPLmNlbGxzLjApIDwtICJSTkEiCktPLmNlbGxzLjEubG5jNTk5OCA8LSBzdWJzZXQoS08uY2VsbHMuMSAsIHN1YnNldCA9IGBuY1JOQS1pbnRlci1jaHI3LTU5OThgID4wKQpLTy5jZWxscy4xLmxuYzU5OTggPC0gTm9ybWFsaXplRGF0YShLTy5jZWxscy4xLmxuYzU5OTgsIHZlcmJvc2UgPSBGQUxTRSkKS08uY2VsbHMuMS5sbmM1OTk4IDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKEtPLmNlbGxzLjEubG5jNTk5OCwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQoKS08uY2VsbHMuMS5sbmM1OTk4IDwtIFNjYWxlRGF0YShLTy5jZWxscy4xLmxuYzU5OTgsIHZlcmJvc2UgPSBGQUxTRSkKS08uY2VsbHMuMS5sbmM1OTk4IDwtIFJ1blBDQShLTy5jZWxscy4xLmxuYzU5OTgsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQojIHQtU05FIGFuZCBDbHVzdGVyaW5nCktPLmNlbGxzLjEubG5jNTk5OCA8LSBSdW5VTUFQKEtPLmNlbGxzLjEubG5jNTk5OCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwKQpLTy5jZWxscy4xLmxuYzU5OTggPC0gRmluZE5laWdoYm9ycyhLTy5jZWxscy4xLmxuYzU5OTgsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKS08uY2VsbHMuMS5sbmM1OTk4IDwtIEZpbmRDbHVzdGVycyhLTy5jZWxscy4xLmxuYzU5OTgsIHJlc29sdXRpb24gPSAwLjUpICAgCktPLmNlbGxzLjEubG5jNTk5OCA8LSBSdW5UU05FKEtPLmNlbGxzLjEubG5jNTk5OCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwKQogICAgCiAjIFZpc3VhbGl6YXRpb24KcDExIDwtIFVNQVBQbG90KEtPLmNlbGxzLjEubG5jNTk5OCwgcmVkdWN0aW9uID0gInVtYXAiLCBzcGxpdC5ieSA9ICJ0ZWNoIiwgbGFiZWw9VFJVRSwgbGFiZWwuc2l6ZT01KQpwMTEuMSA8LSBVTUFQUGxvdChLTy5jZWxscy4xLmxuYzU5OTgsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAidGVjaCIsbGFiZWw9VFJVRSwgbGFiZWwuc2l6ZT01KSAgIApwMTEuMiA8LSBVTUFQUGxvdChLTy5jZWxscy4xLmxuYzU5OTgsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5zaXplPTMpCgpLTy5jZWxscy4xLmxuYzU5OTgkY2VsbHR5cGUuc3RpbSA8LSBwYXN0ZShJZGVudHMoS08uY2VsbHMuMS5sbmM1OTk4KSwgS08uY2VsbHMuMS5sbmM1OTk4JHN0aW0sIHNlcCA9ICJfIikKS08uY2VsbHMuMS5sbmM1OTk4JGNlbGx0eXBlIDwtIElkZW50cyhLTy5jZWxscy4xLmxuYzU5OTgpCklkZW50cyhLTy5jZWxscy4xLmxuYzU5OTgpIDwtICJjZWxsdHlwZS5zdGltIgoKCktPLmNlbGwuMS5sbmM1OTk4X0RFMSA8LSBGaW5kTWFya2VycyhLTy5jZWxscy4xLmxuYzU5OTgsIGlkZW50LjEgPSBjKCcwX0cxNzFCJywnMV9HMTcxQicpLCBpZGVudC4yID0gYygnMF9HMTcxQycsJzFfRzE3MUMnKSx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQoKS08uY2VsbC4xLmxuYzU5OThfREUyIDwtIEZpbmRNYXJrZXJzKEtPLmNlbGxzLjEubG5jNTk5OCwgaWRlbnQuMSA9IGMoJzFfRzE3MUInKSwgaWRlbnQuMiA9IGMoJzBfRzE3MUMnKSx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQoKS08uY2VsbC4xLmxuYzU5OThfREUzIDwtIEZpbmRNYXJrZXJzKEtPLmNlbGxzLjEubG5jNTk5OCwgaWRlbnQuMSA9IGMoJzBfRzE3MUInKSwgaWRlbnQuMiA9IGMoJzBfRzE3MUMnKSx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQoKS08uY2VsbC4xLmxuYzU5OThfQWxsTWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhLTy5jZWxscy4xLmxuYzU5OTgsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIHRocmVzaC51c2UgPSAwLjI1KQoKCktPLmNlbGwuMS5sbmM1OTk4X0FsbE1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbigyLCBhdmdfbG9nRkMpCndyaXRlLmNzdihLTy5jZWxsLjEubG5jNTk5OF9ERTEsICJBbmFseXNpcy9Db3VudFJlc3VsdC9NYXJrZXJzL0tPLmNlbGwuMS5sbmM1OTk4X0RFMSIpCndyaXRlLmNzdihLTy5jZWxsLjEubG5jNTk5OF9BbGxNYXJrZXJzLCAiQW5hbHlzaXMvQ291bnRSZXN1bHQvTWFya2Vycy9LTy5jZWxsLjEubG5jNTk5OF9BbGxNYXJrZXJzIikKd3JpdGUuY3N2KEtPLmNlbGwuMS5sbmM1OTk4X0RFMiwgIkFuYWx5c2lzL0NvdW50UmVzdWx0L01hcmtlcnMvS08uY2VsbC4xLmxuYzU5OThfREUyXzEtRzE3MUJfMC1HMTcxQyIpCndyaXRlLmNzdihLTy5jZWxsLjEubG5jNTk5OF9ERTMsICJBbmFseXNpcy9Db3VudFJlc3VsdC9NYXJrZXJzL0tPLmNlbGwuMS5sbmM1OTk4X0RFM18wLUcxNzFCXzAtRzE3MUMiKQoKCgoKYGBgCgoKCiMjIyMjIyMjIyBjZWxsIGNsdXN0ZXJzIDAgYW5kIGNsdXN0ZXIgMSBmcm9tIG1haW4gVU1BUCB0aGF0IGRvIG5vdCBlcHhyZXNzIGxuYzU5OTggaW4gRzE3MUIgYW5kIEcxNzFDICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKYGBge3J9CgpEZWZhdWx0QXNzYXkoY29tYmluZWQpIDwtICJSTkEiCktPLmNlbGxzLjAgPC0gc3Vic2V0KGNvbWJpbmVkLCBpZGVudHMgPSBjKCIwIikpCklkZW50cyhLTy5jZWxscy4wKSA8LSAiQWxsMCIKRGVmYXVsdEFzc2F5KEtPLmNlbGxzLjApIDwtICJSTkEiCktPLmNlbGxzLjAubnVsbCA8LSBzdWJzZXQoS08uY2VsbHMuMCAsIHN1YnNldCA9IGBuY1JOQS1pbnRlci1jaHI3LTU5OThgPT0gMCkKS08uY2VsbHMuMC5udWxsIDwtIE5vcm1hbGl6ZURhdGEoS08uY2VsbHMuMC5udWxsLCB2ZXJib3NlID0gRkFMU0UpCktPLmNlbGxzLjAubnVsbCA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhLTy5jZWxscy4wLm51bGwsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKCktPLmNlbGxzLjAubnVsbCA8LSBTY2FsZURhdGEoS08uY2VsbHMuMC5udWxsLCB2ZXJib3NlID0gRkFMU0UpCktPLmNlbGxzLjAubnVsbCA8LSBSdW5QQ0EoS08uY2VsbHMuMC5udWxsLCBucGNzID0gMzAsIHZlcmJvc2UgPSBGQUxTRSkKIyB0LVNORSBhbmQgQ2x1c3RlcmluZwpLTy5jZWxscy4wLm51bGwgPC0gUnVuVU1BUChLTy5jZWxscy4wLm51bGwsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKS08uY2VsbHMuMC5udWxsIDwtIEZpbmROZWlnaGJvcnMoS08uY2VsbHMuMC5udWxsLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjApCktPLmNlbGxzLjAubnVsbCA8LSBGaW5kQ2x1c3RlcnMoS08uY2VsbHMuMC5udWxsLCByZXNvbHV0aW9uID0gMC41KSAgIApLTy5jZWxscy4wLm51bGwgPC0gUnVuVFNORShLTy5jZWxscy4wLm51bGwsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKICAgIAogIyBWaXN1YWxpemF0aW9uCnBudWxsMSA8LSBVTUFQUGxvdChLTy5jZWxscy4wLm51bGwsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgc3BsaXQuYnkgPSAidGVjaCIsIGxhYmVsPVRSVUUsIGxhYmVsLnNpemU9NSkKcG51bGwxLjEgPC0gVU1BUFBsb3QoS08uY2VsbHMuMC5udWxsLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInRlY2giLGxhYmVsPVRSVUUsIGxhYmVsLnNpemU9NSkgICAKcG51bGwyIDwtIFVNQVBQbG90KEtPLmNlbGxzLjAubnVsbCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJtb3VzZS5zZXgiKQpwbnVsbDMgPC0gVU1BUFBsb3QoS08uY2VsbHMuMC5udWxsLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgbGFiZWwuc2l6ZT0zKQpwbnVsbDQgPC0gVU1BUFBsb3QoS08uY2VsbHMuMC5udWxsLCBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTYpCgoKS08uY2VsbC4wLm51bGxfREUxIDwtIEZpbmRNYXJrZXJzKEtPLmNlbGxzLjAubnVsbCwgaWRlbnQuMSA9IGMoMSwyLDMpLCBpZGVudC4yID0gMCx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpLTy5jZWxsLjAubnVsbF9BbGxNYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKEtPLmNlbGxzLjAubnVsbCwgb25seS5wb3MgPSBUUlVFLCBtaW4ucGN0ID0gMC4yNSwgdGhyZXNoLnVzZSA9IDAuMjUpCgpLTy5jZWxsLjAubnVsbF9BbGxNYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24oMiwgYXZnX2xvZ0ZDKQp3cml0ZS5jc3YoS08uY2VsbC4wLm51bGxfREUxLCAiQ291bnRSZXN1bHQvTWFya2Vycy9LT19jZWxsXzBfbnVsbF9ERTFfQWxsX0cxNzFCX3ZzX0cxNzFDIikKd3JpdGUuY3N2KEtPLmNlbGwuMC5udWxsX0FsbE1hcmtlcnMsICJDb3VudFJlc3VsdC9NYXJrZXJzL0tPX2NlbGxfMF9udWxsX0FsbE1hcmtlcnMiKQoKCktPLmNlbGxzLjAubnVsbCRjZWxsdHlwZS5zdGltIDwtIHBhc3RlKElkZW50cyhLTy5jZWxscy4wLm51bGwpLCBLTy5jZWxscy4wLm51bGwkdGVjaCwgc2VwID0gIl8iKQpLTy5jZWxscy4wLm51bGwkY2VsbHR5cGUgPC0gSWRlbnRzKEtPLmNlbGxzLjAubnVsbCkKSWRlbnRzKEtPLmNlbGxzLjAubnVsbCkgPC0gImNlbGx0eXBlLnN0aW0iCgoKIyMjIyMjIyMjIyMjIzMgS08gY2VsbHMgdGhhdCBleHByZXNzIGxuYzU5OTggIyMjIyMjIyMjIyMjIyMjIyMKCkRlZmF1bHRBc3NheShjb21iaW5lZCkgPC0gIlJOQSIKS08uY2VsbHMuMSA8LSBzdWJzZXQoY29tYmluZWQsIGlkZW50cyA9IGMoIjEiKSkKSWRlbnRzKEtPLmNlbGxzLjEpIDwtICJBbGwwIgpEZWZhdWx0QXNzYXkoS08uY2VsbHMuMSkgPC0gIlJOQSIKS08uY2VsbHMuMS5udWxsIDwtIHN1YnNldChLTy5jZWxscy4xICwgc3Vic2V0ID0gYG5jUk5BLWludGVyLWNocjctNTk5OGAgPT0wKQpLTy5jZWxscy4xLm51bGwgPC0gTm9ybWFsaXplRGF0YShLTy5jZWxscy4xLm51bGwsIHZlcmJvc2UgPSBGQUxTRSkKS08uY2VsbHMuMS5udWxsIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKEtPLmNlbGxzLjEubnVsbCwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQoKS08uY2VsbHMuMS5udWxsIDwtIFNjYWxlRGF0YShLTy5jZWxscy4xLm51bGwsIHZlcmJvc2UgPSBGQUxTRSkKS08uY2VsbHMuMS5udWxsIDwtIFJ1blBDQShLTy5jZWxscy4xLm51bGwsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQojIHQtU05FIGFuZCBDbHVzdGVyaW5nCktPLmNlbGxzLjEubnVsbCA8LSBSdW5VTUFQKEtPLmNlbGxzLjEubnVsbCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwKQpLTy5jZWxscy4xLm51bGwgPC0gRmluZE5laWdoYm9ycyhLTy5jZWxscy4xLm51bGwsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKS08uY2VsbHMuMS5udWxsIDwtIEZpbmRDbHVzdGVycyhLTy5jZWxscy4xLm51bGwsIHJlc29sdXRpb24gPSAwLjUpICAgCktPLmNlbGxzLjEubnVsbCA8LSBSdW5UU05FKEtPLmNlbGxzLjEubnVsbCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwKQogICAgCiAjIFZpc3VhbGl6YXRpb24KcDExIDwtIFVNQVBQbG90KEtPLmNlbGxzLjEubnVsbCwgcmVkdWN0aW9uID0gInVtYXAiLCBzcGxpdC5ieSA9ICJ0ZWNoIiwgbGFiZWw9VFJVRSwgbGFiZWwuc2l6ZT01KQpwMTEuMSA8LSBVTUFQUGxvdChLTy5jZWxscy4xLm51bGwsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAidGVjaCIsbGFiZWw9VFJVRSwgbGFiZWwuc2l6ZT01KSAgIApwMTEuMiA8LSBVTUFQUGxvdChLTy5jZWxscy4xLm51bGwsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5zaXplPTMpCktPLmNlbGxzLjEubnVsbCRjZWxsdHlwZS5zdGltIDwtIHBhc3RlKElkZW50cyhLTy5jZWxscy4xLm51bGwpLCBLTy5jZWxscy4xLm51bGwkc3RpbSwgc2VwID0gIl8iKQpLTy5jZWxscy4xLm51bGwkY2VsbHR5cGUgPC0gSWRlbnRzKEtPLmNlbGxzLjEubnVsbCkKSWRlbnRzKEtPLmNlbGxzLjEubnVsbCkgPC0gImNlbGx0eXBlLnN0aW0iCgoKS08uY2VsbC4xLm51bGxfREUxIDwtIEZpbmRNYXJrZXJzKEtPLmNlbGxzLjEubnVsbCwgaWRlbnQuMSA9IGMoJzBfRzE3MUInLCcxX0cxNzFCJyksIGlkZW50LjIgPSBjKCcwX0cxNzFDJywnMV9HMTcxQycpLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCgpLTy5jZWxsLjEubnVsbF9ERTIgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMuMS5udWxsLCBpZGVudC4xID0gYygnMV9HMTcxQicpLCBpZGVudC4yID0gYygnMV9HMTcxQycpLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCgpLTy5jZWxsLjEubnVsbF9ERTMgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMuMS5udWxsLCBpZGVudC4xID0gYygnMF9HMTcxQicpLCBpZGVudC4yID0gYygnMF9HMTcxQycpLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCgpLTy5jZWxsLjEubnVsbF9ERTQgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMuMS5udWxsLCBpZGVudC4xID0gYygnMV9HMTcxQicpLCBpZGVudC4yID0gYygnMF9HMTcxQycpLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCgpLTy5jZWxsLjEubnVsbF9ERTUgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMuMS5udWxsLCBpZGVudC4xID0gYygnMF9HMTcxQicpLCBpZGVudC4yID0gYygnMV9HMTcxQycpLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCgoKS08uY2VsbC4xLm51bGxfQWxsTWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhLTy5jZWxscy4xLm51bGwsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIHRocmVzaC51c2UgPSAwLjI1KQoKCktPLmNlbGwuMS5udWxsX0FsbE1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbigyLCBhdmdfbG9nRkMpCndyaXRlLmNzdihLTy5jZWxsLjEubnVsbF9ERTEsICJDb3VudFJlc3VsdC9NYXJrZXJzL0tPX2NlbGxfMV9udWxsX0RFMV9hbGxfRzE3MUJfdnNfRzE3MUMiKQp3cml0ZS5jc3YoS08uY2VsbC4xLm51bGxfQWxsTWFya2VycywgIkNvdW50UmVzdWx0L01hcmtlcnMvS08uY2VsbC4xLm51bGxfQWxsTWFya2VycyIpCndyaXRlLmNzdihLTy5jZWxsLjEubnVsbF9ERTIsICJDb3VudFJlc3VsdC9NYXJrZXJzL0tPX2NlbGxfMV9udWxsX0RFMl8xLUcxNzFCXzEtRzE3MUMiKQp3cml0ZS5jc3YoS08uY2VsbC4xLm51bGxfREUzLCAiQ291bnRSZXN1bHQvTWFya2Vycy9LT19jZWxsXzFfbnVsbF9ERTNfMC1HMTcxQl8wLUcxNzFDIikKd3JpdGUuY3N2KEtPLmNlbGwuMS5udWxsX0RFNCwgIkNvdW50UmVzdWx0L01hcmtlcnMvS09fY2VsbF8xX251bGxfREU0XzEtRzE3MUJfMC1HMTcxQyIpCndyaXRlLmNzdihLTy5jZWxsLjEubnVsbF9ERTUsICJDb3VudFJlc3VsdC9NYXJrZXJzL0tPX2NlbGxfMV9udWxsX0RFNV8wLUcxNzFCXzEtRzE3MUMiKQoKCgoKYGBgCgpBbGwgY2VsbCBjbHVzdGVycyB0aGF0IGV4cHJlc3MgbG5jNTk5OCAKYGBge3J9CgpEZWZhdWx0QXNzYXkoY29tYmluZWQpIDwtICJSTkEiCktPLmNlbGxzLjEuYWxsIDwtIHN1YnNldChjb21iaW5lZCwgaWRlbnRzID0gYygiMSIpKQpJZGVudHMoS08uY2VsbHMuMSkgPC0gIkFsbDEiCkRlZmF1bHRBc3NheShLTy5jZWxscy4xLmFsbCkgPC0gIlJOQSIKS08uY2VsbHMuMS5hbGwgPC0gTm9ybWFsaXplRGF0YShLTy5jZWxscy4xLmFsbCwgdmVyYm9zZSA9IEZBTFNFKQpLTy5jZWxscy4xLmFsbCA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhLTy5jZWxscy4xLmFsbCwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQoKS08uY2VsbHMuMS5hbGwgPC0gU2NhbGVEYXRhKEtPLmNlbGxzLjEuYWxsLCB2ZXJib3NlID0gRkFMU0UpCktPLmNlbGxzLjEuYWxsIDwtIFJ1blBDQShLTy5jZWxscy4xLmFsbCwgbnBjcyA9IDMwLCB2ZXJib3NlID0gRkFMU0UpCiMgdC1TTkUgYW5kIENsdXN0ZXJpbmcKS08uY2VsbHMuMS5hbGwgPC0gUnVuVU1BUChLTy5jZWxscy4xLmFsbCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwKQpLTy5jZWxscy4xLmFsbCA8LSBGaW5kTmVpZ2hib3JzKEtPLmNlbGxzLjEuYWxsLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjApCktPLmNlbGxzLjEuYWxsIDwtIEZpbmRDbHVzdGVycyhLTy5jZWxscy4xLmFsbCwgcmVzb2x1dGlvbiA9IDAuNSkgICAKS08uY2VsbHMuMS5hbGwgPC0gUnVuVFNORShLTy5jZWxscy4xLmFsbCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwKQogICAgCiAjIFZpc3VhbGl6YXRpb24KcGFsbDEgPC0gVU1BUFBsb3QoS08uY2VsbHMuMS5hbGwsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgc3BsaXQuYnkgPSAidGVjaCIsIGxhYmVsPVRSVUUsIGxhYmVsLnNpemU9NSkKcGFsbDEuMSA8LSBVTUFQUGxvdChLTy5jZWxscy4xLmFsbCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJ0ZWNoIixsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTUpICAgCnBhbGwxLjIgPC0gVU1BUFBsb3QoS08uY2VsbHMuMS5hbGwsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBsYWJlbC5zaXplPTMpCktPLmNlbGxzLjEuYWxsJGNlbGx0eXBlLnN0aW0gPC0gcGFzdGUoSWRlbnRzKEtPLmNlbGxzLjEuYWxsKSwgS08uY2VsbHMuMS5hbGwkc3RpbSwgc2VwID0gIl8iKQpLTy5jZWxscy4xLmFsbCRjZWxsdHlwZSA8LSBJZGVudHMoS08uY2VsbHMuMS5hbGwpCklkZW50cyhLTy5jZWxscy4xLmFsbCkgPC0gImNlbGx0eXBlLnN0aW0iCgoKS08uY2VsbC4xLmFsbF9ERTEgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMuMS5hbGwsIGlkZW50LjEgPSBjKCcwX0cxNzFCJywnMV9HMTcxQicsICcyX0cxNzFCJywnM19HMTcxQicpLCBpZGVudC4yID0gYygnMF9HMTcxQycsJzFfRzE3MUMnLCcyX0cxNzFDJywnM19HMTcxQycpLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCgpLTy5jZWxsLjEuYWxsX0RFMiA8LSBGaW5kTWFya2VycyhLTy5jZWxscy4xLmFsbCwgaWRlbnQuMSA9IGMoJzFfRzE3MUInKSwgaWRlbnQuMiA9IGMoJzFfRzE3MUMnKSx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQoKS08uY2VsbC4xLmFsbF9ERTMgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMuMS5hbGwsIGlkZW50LjEgPSBjKCcwX0cxNzFCJyksIGlkZW50LjIgPSBjKCcwX0cxNzFDJyksdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKCktPLmNlbGwuMS5hbGxfREU0IDwtIEZpbmRNYXJrZXJzKEtPLmNlbGxzLjEuYWxsLCBpZGVudC4xID0gYygnMV9HMTcxQicpLCBpZGVudC4yID0gYygnMF9HMTcxQycpLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCgpLTy5jZWxsLjEuYWxsX0RFNSA8LSBGaW5kTWFya2VycyhLTy5jZWxscy4xLmFsbCwgaWRlbnQuMSA9IGMoJzBfRzE3MUInKSwgaWRlbnQuMiA9IGMoJzFfRzE3MUMnKSx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQoKCktPLmNlbGwuMS5hbGxfQWxsTWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhLTy5jZWxscy4xLmFsbCwgb25seS5wb3MgPSBUUlVFLCBtaW4ucGN0ID0gMC4yNSwgdGhyZXNoLnVzZSA9IDAuMjUpCgoKS08uY2VsbC4xLmFsbF9BbGxNYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24oMiwgYXZnX2xvZ0ZDKQp3cml0ZS5jc3YoS08uY2VsbC4xLmFsbF9ERTEsICJDb3VudFJlc3VsdC9NYXJrZXJzL0tPX2NlbGxfMV9hbGxfREUxX2FsbF9HMTcxQl92c19HMTcxQyIpCndyaXRlLmNzdihLTy5jZWxsLjEuYWxsX0FsbE1hcmtlcnMsICJDb3VudFJlc3VsdC9NYXJrZXJzL0tPLmNlbGwuMS5hbGxfQWxsTWFya2VycyIpCndyaXRlLmNzdihLTy5jZWxsLjEuYWxsX0RFMiwgIkNvdW50UmVzdWx0L01hcmtlcnMvS09fY2VsbF8xX2FsbF9ERTJfMS1HMTcxQl8xLUcxNzFDIikKd3JpdGUuY3N2KEtPLmNlbGwuMS5hbGxfREUzLCAiQ291bnRSZXN1bHQvTWFya2Vycy9LT19jZWxsXzFfYWxsX0RFM18wLUcxNzFCXzAtRzE3MUMiKQp3cml0ZS5jc3YoS08uY2VsbC4xLmFsbF9ERTQsICJDb3VudFJlc3VsdC9NYXJrZXJzL0tPX2NlbGxfMV9hbGxfREU0XzEtRzE3MUJfMC1HMTcxQyIpCndyaXRlLmNzdihLTy5jZWxsLjEuYWxsX0RFNSwgIkNvdW50UmVzdWx0L01hcmtlcnMvS09fY2VsbF8xX2FsbF9ERTVfMC1HMTcxQl8xLUcxNzFDIikKCgoKIyMjIyMjIyMjIyMjIyMjIyMjIzMgY2x1c3RlciAwMCAjIyMjIyMjIyMjIyMjIyMjIyMjIwpEZWZhdWx0QXNzYXkoY29tYmluZWQpIDwtICJSTkEiCktPLmNlbGxzLjAuYWxsIDwtIHN1YnNldChjb21iaW5lZCwgaWRlbnRzID0gYygiMCIpKQpJZGVudHMoS08uY2VsbHMuMC5hbGwpIDwtICJBbGwwIgpEZWZhdWx0QXNzYXkoS08uY2VsbHMuMC5hbGwpIDwtICJSTkEiCktPLmNlbGxzLjAuYWxsIDwtIE5vcm1hbGl6ZURhdGEoS08uY2VsbHMuMC5hbGwsIHZlcmJvc2UgPSBGQUxTRSkKS08uY2VsbHMuMC5hbGwgPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoS08uY2VsbHMuMC5hbGwsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKCktPLmNlbGxzLjAuYWxsIDwtIFNjYWxlRGF0YShLTy5jZWxscy4wLmFsbCwgdmVyYm9zZSA9IEZBTFNFKQpLTy5jZWxscy4wLmFsbCA8LSBSdW5QQ0EoS08uY2VsbHMuMC5hbGwsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQojIHQtU05FIGFuZCBDbHVzdGVyaW5nCktPLmNlbGxzLjAuYWxsIDwtIFJ1blVNQVAoS08uY2VsbHMuMC5hbGwsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKS08uY2VsbHMuMC5hbGwgPC0gRmluZE5laWdoYm9ycyhLTy5jZWxscy4wLmFsbCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwKQpLTy5jZWxscy4wLmFsbCA8LSBGaW5kQ2x1c3RlcnMoS08uY2VsbHMuMC5hbGwsIHJlc29sdXRpb24gPSAwLjUpICAgCktPLmNlbGxzLjAuYWxsIDwtIFJ1blRTTkUoS08uY2VsbHMuMC5hbGwsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKICAgIAogIyBWaXN1YWxpemF0aW9uCnBhbGwwMSA8LSBVTUFQUGxvdChLTy5jZWxscy4wLmFsbCwgcmVkdWN0aW9uID0gInVtYXAiLCBzcGxpdC5ieSA9ICJ0ZWNoIiwgbGFiZWw9VFJVRSwgbGFiZWwuc2l6ZT01KQpwYWxsMC4xIDwtIFVNQVBQbG90KEtPLmNlbGxzLjAuYWxsLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gInRlY2giLGxhYmVsPVRSVUUsIGxhYmVsLnNpemU9NSkgICAKcGFsbDAuMiA8LSBVTUFQUGxvdChLTy5jZWxscy4wLmFsbCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJtb3VzZS5zZXgiKQpwYWxsMC4zIDwtIFVNQVBQbG90KEtPLmNlbGxzLjAuYWxsLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgbGFiZWwuc2l6ZT0zKQpwYWxsMC40IDwtIFVNQVBQbG90KEtPLmNlbGxzLjAuYWxsLCBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTYpCgoKS08uY2VsbC4wLmFsbF9ERTEgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMuMC5hbGwsIGlkZW50LjEgPSBjKCcwX0cxNzFCJywnMV9HMTcxQicsJzJfRzE3MUInLCczX0cxNzFCJywnNF9HMTcxQicpLCBpZGVudC4yID0gYygnMF9HMTcxQycsJzJfRzE3MUMnKSx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpLTy5jZWxsLjAuYWxsX0FsbE1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoS08uY2VsbHMuMC5hbGwsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIHRocmVzaC51c2UgPSAwLjI1KQoKS08uY2VsbC4wLmFsbF9BbGxNYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24oMiwgYXZnX2xvZ0ZDKQp3cml0ZS5jc3YoS08uY2VsbC4wLmFsbF9ERTEsICJDb3VudFJlc3VsdC9NYXJrZXJzL0tPX2NlbGxfMF9hbGxfREUxX0FsbF9HMTcxQl92c19HMTcxQyIpCndyaXRlLmNzdihLTy5jZWxsLjAuYWxsX0FsbE1hcmtlcnMsICJDb3VudFJlc3VsdC9NYXJrZXJzL0tPX2NlbGxfMF9hbGxfQWxsTWFya2VycyIpCgoKS08uY2VsbHMuMC5hbGwkY2VsbHR5cGUuc3RpbSA8LSBwYXN0ZShJZGVudHMoS08uY2VsbHMuMC5hbGwpLCBLTy5jZWxscy4wLmFsbCR0ZWNoLCBzZXAgPSAiXyIpCktPLmNlbGxzLjAuYWxsJGNlbGx0eXBlIDwtIElkZW50cyhLTy5jZWxscy4wLmFsbCkKSWRlbnRzKEtPLmNlbGxzLjAuYWxsKSA8LSAiY2VsbHR5cGUuc3RpbSIKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIGNsdXN0ZXIgMiAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKRGVmYXVsdEFzc2F5KGNvbWJpbmVkKSA8LSAiUk5BIgpLTy5jZWxscy4yLmFsbCA8LSBzdWJzZXQoY29tYmluZWQsIGlkZW50cyA9IGMoIjIiKSkKSWRlbnRzKEtPLmNlbGxzLjIuYWxsKSA8LSAiQWxsMiIKRGVmYXVsdEFzc2F5KEtPLmNlbGxzLjIuYWxsKSA8LSAiUk5BIgpLTy5jZWxscy4yLmFsbCA8LSBOb3JtYWxpemVEYXRhKEtPLmNlbGxzLjIuYWxsLCB2ZXJib3NlID0gRkFMU0UpCktPLmNlbGxzLjIuYWxsIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKEtPLmNlbGxzLjIuYWxsLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCgpLTy5jZWxscy4yLmFsbCA8LSBTY2FsZURhdGEoS08uY2VsbHMuMi5hbGwsIHZlcmJvc2UgPSBGQUxTRSkKS08uY2VsbHMuMi5hbGwgPC0gUnVuUENBKEtPLmNlbGxzLjIuYWxsLCBucGNzID0gMzAsIHZlcmJvc2UgPSBGQUxTRSkKIyB0LVNORSBhbmQgQ2x1c3RlcmluZwpLTy5jZWxscy4yLmFsbCA8LSBSdW5VTUFQKEtPLmNlbGxzLjIuYWxsLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjApCktPLmNlbGxzLjIuYWxsIDwtIEZpbmROZWlnaGJvcnMoS08uY2VsbHMuMi5hbGwsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKS08uY2VsbHMuMi5hbGwgPC0gRmluZENsdXN0ZXJzKEtPLmNlbGxzLjIuYWxsLCByZXNvbHV0aW9uID0gMC41KSAgIApLTy5jZWxscy4yLmFsbCA8LSBSdW5UU05FKEtPLmNlbGxzLjIuYWxsLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjApCiAgICAKICMgVmlzdWFsaXphdGlvbgpwYWxsMjEgPC0gVU1BUFBsb3QoS08uY2VsbHMuMi5hbGwsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgc3BsaXQuYnkgPSAidGVjaCIsIGxhYmVsPVRSVUUsIGxhYmVsLnNpemU9NSkKcGFsbDIuMSA8LSBVTUFQUGxvdChLTy5jZWxscy4yLmFsbCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJ0ZWNoIixsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTUpICAgCnBhbGwyLjIgPC0gVU1BUFBsb3QoS08uY2VsbHMuMi5hbGwsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAibW91c2Uuc2V4IikKcGFsbDIuMyA8LSBVTUFQUGxvdChLTy5jZWxscy4yLmFsbCwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGxhYmVsLnNpemU9MykKcGFsbDIuNCA8LSBVTUFQUGxvdChLTy5jZWxscy4yLmFsbCwgbGFiZWw9VFJVRSwgbGFiZWwuc2l6ZT02KQoKS08uY2VsbC4yLmFsbF9ERTEgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMuMi5hbGwsIGlkZW50LjEgPSBjKDEsMiwzKSwgaWRlbnQuMiA9IDAsdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKS08uY2VsbC4yLmFsbF9BbGxNYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKEtPLmNlbGxzLjIuYWxsLCBvbmx5LnBvcyA9IFRSVUUsIG1pbi5wY3QgPSAwLjI1LCB0aHJlc2gudXNlID0gMC4yNSkKCktPLmNlbGwuMi5hbGxfQWxsTWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKDIsIGF2Z19sb2dGQykKd3JpdGUuY3N2KEtPLmNlbGwuMi5hbGxfREUxLCAiQ291bnRSZXN1bHQvTWFya2Vycy9LT19jZWxsXzBfYWxsX0RFMV9BbGxfRzE3MUJfdnNfRzE3MUMiKQp3cml0ZS5jc3YoS08uY2VsbC4yLmFsbF9BbGxNYXJrZXJzLCAiQ291bnRSZXN1bHQvTWFya2Vycy9LT19jZWxsXzBfYWxsX0FsbE1hcmtlcnMiKQoKCktPLmNlbGxzLjIuYWxsJGNlbGx0eXBlLnN0aW0gPC0gcGFzdGUoSWRlbnRzKEtPLmNlbGxzLjIuYWxsKSwgS08uY2VsbHMuMi5hbGwkdGVjaCwgc2VwID0gIl8iKQpLTy5jZWxscy4yLmFsbCRjZWxsdHlwZSA8LSBJZGVudHMoS08uY2VsbHMuMi5hbGwpCklkZW50cyhLTy5jZWxscy4yLmFsbCkgPC0gImNlbGx0eXBlLnN0aW0iCgoKCgoKYGBgCgoKYGBge3J9CgoKZHJvcGxldF9tZXRhZGF0YSA8LSByZWFkLmNzdigiL3Jlc3RyaWN0ZWQvcHJvamVjdG5iL3dheG1hbmxhYi9ra2Fycmkvc2NSTkFzZXFfZGF0YV9pbnRlZ3JhdGlvbi9tZXRhZGF0YV9kcm9wbGV0X2xpdmVyLmNzdiIsIHNlcD0iLCIsIGhlYWRlciA9IFRSVUUpCmNvbG5hbWVzKGRyb3BsZXRfbWV0YWRhdGEpWzFdIDwtICJjaGFubmVsIgp0aXNzdWVfbWV0YWRhdGEgPSBmaWx0ZXIoZHJvcGxldF9tZXRhZGF0YSwgdGlzc3VlID09IHRpc3N1ZV9vZl9pbnRlcmVzdClbLGMoJ2NoYW5uZWwnLCd0aXNzdWUnLCdzdWJ0aXNzdWUnLCdtb3VzZS5zZXgnLCAnbW91c2UuaWQnKV0KCnJhdy5kYXRhIDwtIFJlYWQxMFgoIi9yZXN0cmljdGVkL3Byb2plY3RuYi93YXhtYW5sYWIva2thcnJpL3NjUk5Bc2VxX2RhdGFfaW50ZWdyYXRpb24vUmVmaW5lZF9jZWxsbWF0cmljZXMvTGl2ZXItMTBYX1A0XzIvIikKY29sbmFtZXMocmF3LmRhdGEpIDwtIGxhcHBseShjb2xuYW1lcyhyYXcuZGF0YSksIGZ1bmN0aW9uKHgpIHBhc3RlMCh0aXNzdWVfbWV0YWRhdGEkY2hhbm5lbFsxXSwnXycseCkpCiAgbWV0YS5kYXRhMSA9IGRhdGEuZnJhbWUocm93Lm5hbWVzID0gY29sbmFtZXMocmF3LmRhdGEpKQogIG1ldGEuZGF0YTFbJ2NoYW5uZWwnXSA9IHRpc3N1ZV9tZXRhZGF0YSRjaGFubmVsWzFdCgogIGlmIChsZW5ndGgodGlzc3VlX21ldGFkYXRhJGNoYW5uZWwpID4gMSl7CiAgICAjIFNvbWUgdGlzc3VlcywgbGlrZSBUaHltdXMgYW5kIEhlYXJ0IGhhZCBvbmx5IG9uZSBjaGFubmVsCiAgICBmb3IoaSBpbiAyOm5yb3codGlzc3VlX21ldGFkYXRhKSl7CnN1YmZvbGRlciA9IHBhc3RlMCgiL3Jlc3RyaWN0ZWQvcHJvamVjdG5iL3dheG1hbmxhYi9ra2Fycmkvc2NSTkFzZXFfZGF0YV9pbnRlZ3JhdGlvbi9SZWZpbmVkX2NlbGxtYXRyaWNlcy8iLHRpc3N1ZV9vZl9pbnRlcmVzdCwgJy0nLCB0aXNzdWVfbWV0YWRhdGEkY2hhbm5lbFtpXSkKICAgICAgbmV3LmRhdGExIDwtIFJlYWQxMFgoZGF0YS5kaXIgPSBzdWJmb2xkZXIpCiAgICAgIGNvbG5hbWVzKG5ldy5kYXRhMSkgPC0gbGFwcGx5KGNvbG5hbWVzKG5ldy5kYXRhMSksIGZ1bmN0aW9uKHgpIHBhc3RlMCh0aXNzdWVfbWV0YWRhdGEkY2hhbm5lbFtpXSwnXycsIHgpKQogICAgICAKICAgICAgbmV3Lm1ldGFkYXRhMSA9IGRhdGEuZnJhbWUocm93Lm5hbWVzID0gY29sbmFtZXMobmV3LmRhdGExKSkKICAgICAgbmV3Lm1ldGFkYXRhMVsnY2hhbm5lbCddID0gdGlzc3VlX21ldGFkYXRhJGNoYW5uZWxbaV0KICAgICAgCiAgICAgIHJhdy5kYXRhID0gY2JpbmQocmF3LmRhdGEsIG5ldy5kYXRhMSkKICAgICAgbWV0YS5kYXRhMSA9IHJiaW5kKG1ldGEuZGF0YTEsIG5ldy5tZXRhZGF0YTEpCiAgICB9CiAgfQogIAogIHJuYW1lcyA9IHJvdy5uYW1lcyhtZXRhLmRhdGExKQogIG1ldGEuZGF0YTEgPC0gbWVyZ2UobWV0YS5kYXRhMSwgdGlzc3VlX21ldGFkYXRhLCBzb3J0ID0gRikKICByb3cubmFtZXMobWV0YS5kYXRhMSkgPC0gcm5hbWVzCiAgIyBPcmRlciB0aGUgY2VsbHMgYWxwaGFiZXRpY2FsbHkgdG8gZW5zdXJlIGNvbnNpc3RlbmN5LgogICAgb3JkZXJlZF9jZWxsX25hbWVzID0gb3JkZXIoY29sbmFtZXMocmF3LmRhdGEpKQogIHJhdy5kYXRhID0gcmF3LmRhdGFbLG9yZGVyZWRfY2VsbF9uYW1lc10KICBtZXRhLmRhdGExID0gbWV0YS5kYXRhMVtvcmRlcmVkX2NlbGxfbmFtZXMsXQogICAgIyBGaW5kIEVSQ0MncywgY29tcHV0ZSB0aGUgcGVyY2VudCBFUkNDLCBhbmQgZHJvcCB0aGVtIGZyb20gdGhlIHJhdyBkYXRhLgogIGVyY2NzIDwtIGdyZXAocGF0dGVybiA9ICJeRVJDQy0iLCB4ID0gcm93bmFtZXMoeCA9IHJhdy5kYXRhKSwgdmFsdWUgPSBUUlVFKQogIHBlcmNlbnQuZXJjYyA8LSBNYXRyaXg6OmNvbFN1bXMocmF3LmRhdGFbZXJjY3MsIF0pL01hdHJpeDo6Y29sU3VtcyhyYXcuZGF0YSkKICBlcmNjLmluZGV4IDwtIGdyZXAocGF0dGVybiA9ICJeRVJDQy0iLCB4ID0gcm93bmFtZXMoeCA9IHJhdy5kYXRhKSwgdmFsdWUgPSBGQUxTRSkKICByYXcuZGF0YSA8LSByYXcuZGF0YVstZXJjYy5pbmRleCxdCiAgCiAgIyBDcmVhdGUgdGhlIFNldXJhdCBvYmplY3Qgd2l0aCBhbGwgdGhlIGRhdGEKICBkcm9wbGV0IDwtIENyZWF0ZVNldXJhdE9iamVjdChyYXcuZGF0YSkgICAjIGRyb3BzZXEKICBkcm9wbGV0IDwtIEFkZE1ldGFEYXRhKG9iamVjdCA9IGRyb3BsZXQsIG1ldGEuZGF0YTEpIAogIGRyb3BsZXRAbWV0YS5kYXRhJHRlY2ggPC0gImRyb3BsZXQiCgojbi5wY3MgPSAxMAogICNkcm9wbGV0IDwtIFN1YnNldERhdGEoZHJvcGxldCxzdWJzZXQubmFtZXMgPSBjKCJuR2VuZSIsICJuVU1JIiksIGxvdy50aHJlc2hvbGRzID0gYyg1MDAsIDEwMDApKSAgIyBvbGQgdmVyc2lvbiBvZiBzZXVyYXQKZHJvcGxldCA8LSAgc3Vic2V0KGRyb3BsZXQsIHN1YnNldCA9IG5GZWF0dXJlX1JOQSA+IDUwMCAmIG5Db3VudF9STkEgPiAxMDAwKQpkcm9wbGV0IDwtIE5vcm1hbGl6ZURhdGEoZHJvcGxldCwgdmVyYm9zZSA9IEZBTFNFKQpkcm9wbGV0IDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKGRyb3BsZXQsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKZHJvcGxldCA8LSBTY2FsZURhdGEoZHJvcGxldCwgdmVyYm9zZSA9IEZBTFNFKQojZHJvcGxldCA8LSBSdW5QQ0EoZHJvcGxldCwgbnBjcyA9IDEwLCB2ZXJib3NlID0gRkFMU0UpCmRyb3BsZXQkc3RpbSA8LSAiZHJvcGxldCIKCiMgZHJvcGxldCA8LSBTY2FsZURhdGEoZHJvcGxldCwgdmVyYm9zZSA9IEZBTFNFKQogZHJvcGxldCA8LSBSdW5QQ0EoZHJvcGxldCwgbnBjcyA9IDMwLCB2ZXJib3NlID0gRkFMU0UpCiBkcm9wbGV0IDwtIFJ1blVNQVAoZHJvcGxldCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjI1KQogZHJvcGxldCA8LSBGaW5kTmVpZ2hib3JzKGRyb3BsZXQsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToxMCkKIGRyb3BsZXQgPC0gRmluZENsdXN0ZXJzKGRyb3BsZXQsIHJlc29sdXRpb24gPSAwLjUgKSAgIAogcDE8LSBVTUFQUGxvdChkcm9wbGV0LCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gImNoYW5uZWwiLCBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTUpCiBwMiA8LSBVTUFQUGxvdChkcm9wbGV0LCBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTYpCiBwMzwtIFVNQVBQbG90KGRyb3BsZXQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAibW91c2Uuc2V4IiwgbGFiZWw9VFJVRSwgbGFiZWwuc2l6ZT01KQoKcmVzLnVzZWQgPC0gMQpkcm9wbGV0IDwtIEZpbmRDbHVzdGVycyhvYmplY3QgPSBkcm9wbGV0LCByZWR1Y3Rpb24udHlwZSA9ICJwY2EiLCBkaW1zLnVzZSA9IDE6bi5wY3MsIHJlc29sdXRpb24gPSByZXMudXNlZCwgcHJpbnQub3V0cHV0ID0gMCwgc2F2ZS5TTk4gPSBUUlVFLCBmb3JjZS5yZWNhbGMgPSBUUlVFKQoKZHJvcGxldCA8LSBSdW5UU05FKG9iamVjdCA9IGRyb3BsZXQsIGRpbXMudXNlID0gMTpuLnBjcywgc2VlZC51c2UgPSAxMCwgcGVycGxleGl0eT0zMCkKVFNORVBsb3Qob2JqZWN0ID0gZHJvcGxldCwgZG8ubGFiZWwgPSBULCBwdC5zaXplID0gMS4yLCBsYWJlbC5zaXplID0gNCkKCgpgYGAKCgoKYGBge3J9CktPLmNlbGxzJGNlbGx0eXBlLnN0aW0gPC0gcGFzdGUoSWRlbnRzKEtPLmNlbGxzKSwgS08uY2VsbHMkc3RpbSwgc2VwID0gIl8iKQpLTy5jZWxscyRjZWxsdHlwZSA8LSBJZGVudHMoS08uY2VsbHMpCklkZW50cyhLTy5jZWxscykgPC0gImNlbGx0eXBlLnN0aW0iCnJlc3BvbnNlMyA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9IGMoIjFfRzE3MUIiLCIwX0cxNzFCIiwiMl9HMTcxQiIpLCBpZGVudC4yID0gYygiMV9HMTcxQyIsICIwX0cxNzFDIiwiMl9HMTcxQyIpLCB2ZXJib3NlID0gVFJVRSwgdGVzdC51c2UgPSAiTUFTVCIsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKaGVhZChyZXNwb25zZTMsIG4gPSAxNSkKCgpLTy5jZWxsLjAubG5jNTk5OF9ERTEgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMuMC5sbmM1OTk4LCBpZGVudC4xID0gIjRfRzE3MUMiLCBpZGVudC4yID0gIjRfRzE3MUIiLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCgoKCktPLmNlbGxzLjEgPC0gc3Vic2V0KGNvbWJpbmVkLCBpZGVudHMgPSBjKCIxIikpCklkZW50cyhLTy5jZWxscy4xKSA8LSAiQWxsMSIKCmBgYAoKYGBgCgoKCgoKCmBgYHtyfQpLTy5jZWxscyA8LSBSdW5VTUFQKEtPLmNlbGxzLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjAgKQpLTy5jZWxscyA8LSBGaW5kTmVpZ2hib3JzKEtPLmNlbGxzLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjApCktPLmNlbGxzIDwtIEZpbmRDbHVzdGVycyhLTy5jZWxscywgcmVzb2x1dGlvbiA9IDAuNSApICAgCktPLmNlbGxzIDwtIFJ1blRTTkUoS08uY2VsbHMsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKIAoKSGVwLmNlbGxzIDwtIFJ1blVNQVAoSGVwLmNlbGxzLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjAgKQpIZXAuY2VsbHMgPC0gRmluZE5laWdoYm9ycyhIZXAuY2VsbHMsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKSGVwLmNlbGxzIDwtIEZpbmRDbHVzdGVycyhIZXAuY2VsbHMsIHJlc29sdXRpb24gPSAwLjUgKSAgIApIZXAuY2VsbHMgPC0gUnVuVFNORShIZXAuY2VsbHMsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKIAoKICAgCiAjIFZpc3VhbGl6YXRpb24KcDEgPC0gVU1BUFBsb3QoS08uY2VsbHMsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAic3RpbSIpCnAyIDwtIFVNQVBQbG90KEtPLmNlbGxzLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gIm1vdXNlLnNleCIpCnAzIDwtIFVNQVBQbG90KEtPLmNlbGxzLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSkKcDQgPC0gVU1BUFBsb3QoS08uY2VsbHMsIGxhYmVsPVRSVUUpCnBsb3RfZ3JpZChwMSxwNCkgCkRpbVBsb3QoS08uY2VsbHMsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgc3BsaXQuYnkgPSAic3RpbSIpICAgCgoKI2hlcGF0b2N5dGUgY2VsbHMKCnA1IDwtIFVNQVBQbG90KEhlcC5jZWxscywgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJzdGltIikKcDYgPC0gVU1BUFBsb3QoSGVwLmNlbGxzLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gIm1vdXNlLnNleCIpCnA3IDwtIFVNQVBQbG90KEhlcC5jZWxscywgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUpCnA4IDwtIFVNQVBQbG90KEhlcC5jZWxscywgbGFiZWw9VFJVRSkKcGxvdF9ncmlkKHA1LHA4KSAKRGltUGxvdChLTy5jZWxscywgcmVkdWN0aW9uID0gInVtYXAiLCBzcGxpdC5ieSA9ICJzdGltIikgICAKCgpyYXcuZGF0YS5LTy4wIDwtIGFzLm1hdHJpeChHZXRBc3NheURhdGEoS08uY2VsbHMsIHNsb3QgPSAiY291bnRzIilbLCBXaGljaENlbGxzKEtPLmNlbGxzLCBpZGVudCA9IDApXSkKcmF3LmRhdGEuS08uMSA8LSBhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKEtPLmNlbGxzLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhLTy5jZWxscywgaWRlbnQgPSAxKV0pCnJhdy5kYXRhLktPLjIgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKEtPLmNlbGxzLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhLTy5jZWxscywgaWRlbnQgPSAyKV0pCnJhdy5kYXRhLktPLjMgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKEtPLmNlbGxzLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhLTy5jZWxscywgaWRlbnQgPSAzKV0pCnJhdy5kYXRhLktPLjQgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKEtPLmNlbGxzLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhLTy5jZWxscywgaWRlbnQgPSA0KV0pCnJhdy5kYXRhLktPLjUgPC1hcy5tYXRyaXgoR2V0QXNzYXlEYXRhKEtPLmNlbGxzLCBzbG90ID0gImNvdW50cyIpWywgV2hpY2hDZWxscyhLTy5jZWxscywgaWRlbnQgPSA1KV0pCgoKd3JpdGUuY3N2KHJhdy5kYXRhLktPLjAsICJDb3VudFJlc3VsdC9NYXJrZXJzL3Jhdy5kYXRhLktPLjAiKQp3cml0ZS5jc3YocmF3LmRhdGEuS08uMSwgIkNvdW50UmVzdWx0L01hcmtlcnMvcmF3LmRhdGEuS08uMSIpCndyaXRlLmNzdihyYXcuZGF0YS5LTy4yLCAiQ291bnRSZXN1bHQvTWFya2Vycy9yYXcuZGF0YS5LTy4yIikKd3JpdGUuY3N2KHJhdy5kYXRhLktPLjMsICJDb3VudFJlc3VsdC9NYXJrZXJzL3Jhdy5kYXRhLktPLjMiKQp3cml0ZS5jc3YocmF3LmRhdGEuS08uNCwgIkNvdW50UmVzdWx0L01hcmtlcnMvcmF3LmRhdGEuS08uNCIpCndyaXRlLmNzdihyYXcuZGF0YS5LTy41LCAiQ291bnRSZXN1bHQvTWFya2Vycy9yYXcuZGF0YS5LTy41IikKCgoKZjEgPC0gRmVhdHVyZVBsb3QoS08uY2VsbHMsIGZlYXR1cmVzID0gYygnbmNSTkEtaW50ZXItY2hyNy01OTk4JyksICByZWR1Y3Rpb24gPSAidW1hcCIsIHNwbGl0LmJ5ID0gInN0aW0iKQpwbG90X2dyaWQoZjEscDEscDQpIAoKRGVmYXVsdEFzc2F5KEtPLmNlbGxzKSA8LSAiUk5BIgpLTy5jZWxscyA8LSBOb3JtYWxpemVEYXRhKEtPLmNlbGxzLCB2ZXJib3NlID0gRkFMU0UpCgpwbG90cyA8LSBWbG5QbG90KEtPLmNlbGxzLCBmZWF0dXJlcyA9IGMoIkFsYiIsICJuY1JOQS1pbnRlci1jaHI3LTU5OTgiLCJDeXAyYjEwIiwiQ3lwMmUxIiwiQ3lwMmYyIiksIHNwbGl0LmJ5ID0gInN0aW0iLCBncm91cC5ieSA9ICJzZXVyYXRfY2x1c3RlcnMiLCBwdC5zaXplID0gMCwgY29tYmluZSA9IEZBTFNFKQpDb21iaW5lUGxvdHMocGxvdHMgPSBwbG90cywgbmNvbCA9IDEpCgpUaHJlZV9maXZlX3NpeCA8LSBzdWJzZXQoS08uY2VsbHMsIGlkZW50cyA9IGMoIjUiLCI2IikpCgpUaHJlZV9maXZlX3NpeCA8LSBSdW5VTUFQKFRocmVlX2ZpdmVfc2l4LCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjAgKQpUaHJlZV9maXZlX3NpeCA8LSBGaW5kTmVpZ2hib3JzKFRocmVlX2ZpdmVfc2l4LCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjApClRocmVlX2ZpdmVfc2l4IDwtIEZpbmRDbHVzdGVycyhUaHJlZV9maXZlX3NpeCwgcmVzb2x1dGlvbiA9IDEgKSAgIApUaHJlZV9maXZlX3NpeCA8LSBSdW5UU05FKFRocmVlX2ZpdmVfc2l4LCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjApCgpwMSA8LSBVTUFQUGxvdChUaHJlZV9maXZlX3NpeCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJzdGltIikKcDIgPC0gVU1BUFBsb3QoVGhyZWVfZml2ZV9zaXgsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAibW91c2Uuc2V4IikKcDMgPC0gVU1BUFBsb3QoVGhyZWVfZml2ZV9zaXgsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFKQpwNCA8LSBVTUFQUGxvdChUaHJlZV9maXZlX3NpeCwgbGFiZWw9VFJVRSkKcGxvdF9ncmlkKHAxLHA0KSAKRGltUGxvdChUaHJlZV9maXZlX3NpeCwgcmVkdWN0aW9uID0gInVtYXAiLCBzcGxpdC5ieSA9ICJzdGltIikgICAKCmYxIDwtIEZlYXR1cmVQbG90KFRocmVlX2ZpdmVfc2l4LCBmZWF0dXJlcyA9IGMoJ25jUk5BLWludGVyLWNocjctNTk5OCcpLCAgcmVkdWN0aW9uID0gInVtYXAiLCBzcGxpdC5ieSA9ICJzdGltIikKCgpsbmM1OTk4IDwtIHN1YnNldChjb21iaW5lZCwgY2VsbHMgPSBsbmM1OTk4LmNlbGxzLCBpZGVudHMgPSAiMSIpCgpsbmM1OTk4IDwtIFJ1blVNQVAobG5jNTk5OCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwICkKbG5jNTk5OCA8LSBGaW5kTmVpZ2hib3JzKGxuYzU5OTgsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToyMCkKbG5jNTk5OCA8LSBGaW5kQ2x1c3RlcnMobG5jNTk5OCwgcmVzb2x1dGlvbiA9IDEgKSAgIApsbmM1OTk4IDwtIFJ1blRTTkUobG5jNTk5OCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIwKQogICAgCiAjIFZpc3VhbGl6YXRpb24KcDEgPC0gVU1BUFBsb3QobG5jNTk5OCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJzdGltIikKcDIgPC0gVU1BUFBsb3QobG5jNTk5OCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJtb3VzZS5zZXgiKQpwMyA8LSBVTUFQUGxvdChsbmM1OTk4LCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSkKcDQgPC0gVU1BUFBsb3QobG5jNTk5OCwgbGFiZWw9VFJVRSkKcGxvdF9ncmlkKHAxLHA0KSAKRGltUGxvdChsbmM1OTk4LCByZWR1Y3Rpb24gPSAidW1hcCIsIHNwbGl0LmJ5ID0gInN0aW0iKSAgIAoKbG5jNTk5OC5jZWxscyA8LSBXaGljaENlbGxzKG9iamVjdCA9IGNvbWJpbmVkLCBleHByZXNzaW9uID0gIm5jUk5BLWludGVyLWNocjctNTk5OCIgPiAxKQpGZWF0dXJlUGxvdChsbmM1OTk4LCBmZWF0dXJlcyA9IGMoIm5jUk5BLWludGVyLWNocjctNTk5OCIpLCBzcGxpdC5ieSA9ICJzdGltIiwgIAorICAgICAgICAgICAgIGNvbHMgPSBjKCJncmV5IiwgInJlZCIpLCBjZWxscyA9IGxuYzU5OTguY2VsbHMsbWluLmN1dG9mZiA9IDAuNSkKCgpEZWZhdWx0QXNzYXkobG5jNTk5OCkgPC0gIlJOQSIKbG5jNTk5OCA8LSBOb3JtYWxpemVEYXRhKGxuYzU5OTgsIHZlcmJvc2UgPSBGQUxTRSkKCnBsb3RzIDwtIFZsblBsb3QobG5jNTk5OCwgZmVhdHVyZXMgPSBjKCJBbGIiLCAibmNSTkEtaW50ZXItY2hyNy01OTk4IiwiQ3lwMmIxMCIsIkN5cDJlMSIsIkN5cDJmMiIpLCBzcGxpdC5ieSA9ICJzdGltIiwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzIiwgcHQuc2l6ZSA9IDAsIGNvbWJpbmUgPSBGQUxTRSkKQ29tYmluZVBsb3RzKHBsb3RzID0gcGxvdHMsIG5jb2wgPSAxKQoKIApgYGAKCmBgYHtyfQpkIDwtIGRpc3QodChHZXRBc3NheURhdGEoS08uY2VsbHMsIHNsb3QgPSAic2NhbGUuZGF0YSIpKSkKIyBSdW4gdGhlIE1EUyBwcm9jZWR1cmUsIGsgZGV0ZXJtaW5lcyB0aGUgbnVtYmVyIG9mIGRpbWVuc2lvbnMKbWRzIDwtIGNtZHNjYWxlKGQgPSBkLCBrID0gMikKIyBjbWRzY2FsZSByZXR1cm5zIHRoZSBjZWxsIGVtYmVkZGluZ3MsIHdlIGZpcnN0IGxhYmVsIHRoZSBjb2x1bW5zIHRvIGVuc3VyZSBkb3duc3RyZWFtCiMgY29uc2lzdGVuY3kKY29sbmFtZXMobWRzKSA8LSBwYXN0ZTAoIk1EU18iLCAxOjIpCiMgV2Ugd2lsbCBub3cgc3RvcmUgdGhpcyBhcyBhIGN1c3RvbSBkaW1lbnNpb25hbCByZWR1Y3Rpb24gY2FsbGVkICdtZHMnCktPLmNlbGxzW1sibWRzIl1dIDwtIENyZWF0ZURpbVJlZHVjT2JqZWN0KGVtYmVkZGluZ3MgPSBtZHMsIGtleSA9ICJNRFNfIiwgYXNzYXkgPSBEZWZhdWx0QXNzYXkoS08uY2VsbHMpKQoKIyBXZSBjYW4gbm93IHVzZSB0aGlzIGFzIHlvdSB3b3VsZCBhbnkgb3RoZXIgZGltZW5zaW9uYWwgcmVkdWN0aW9uIGluIGFsbCBkb3duc3RyZWFtIGZ1bmN0aW9ucwpEaW1QbG90KEtPLmNlbGxzLCByZWR1Y3Rpb24gPSAibWRzIiwgcHQuc2l6ZSA9IDAuNSkKYGBgCgpGaW5kIGRpZmZlcmVudGlhbCBtYXJrZXJzCgpgYGB7cn0KS08uY2VsbHMkY2VsbHR5cGUuc3RpbSA8LSBwYXN0ZShJZGVudHMoS08uY2VsbHMpLCBLTy5jZWxscyRzdGltLCBzZXAgPSAiXyIpCktPLmNlbGxzJGNlbGx0eXBlIDwtIElkZW50cyhLTy5jZWxscykKSWRlbnRzKEtPLmNlbGxzKSA8LSAiY2VsbHR5cGUuc3RpbSIKcmVzcG9uc2UzIDwtIEZpbmRNYXJrZXJzKEtPLmNlbGxzLCBpZGVudC4xID0gYygiMV9HMTcxQiIsIjBfRzE3MUIiLCIyX0cxNzFCIiksIGlkZW50LjIgPSBjKCIxX0cxNzFDIiwgIjBfRzE3MUMiLCIyX0cxNzFDIiksIHZlcmJvc2UgPSBUUlVFLCB0ZXN0LnVzZSA9ICJNQVNUIiwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpoZWFkKHJlc3BvbnNlMywgbiA9IDE1KQoKCiNERTE6IENvbXBhcmUgY2x1c3RlciAwKzErMTIgKHRoYXQgZXhwcmVzc2VkIGxuYzU5OTgpIHdpdGggT3RoZXIgaGVwYXRvY3l0ZSBjbHVzdGVycyAoMis1KzgpCiNERTI6IGNvbXBhcmUgY2x1c3RlciAxIChzaG93ZWQgbWFqb3IgZWZmZWN0cyBpbiB0aGUgS0QpIHZzIENsdXN0ZXIgMCAodGhhdCBzaG93ZWQgbGl0dGxlIEtEKQojREUzOiBGb3IgS08uY2VsbHMgdGhhdCBmb3JtZWQgZml2ZSBzdWJjbHVzdGVyLCBjb21wYXJlIGNsdXN0ZXJzIDMrNCs1KzEgdnMgMiswCiNERTQ6IGZvciBLTy5jZWxscyB0aGF0IGZvcm1lZCBmaXZlIGNsdXN0ZXJzLiBDb21hcHJlIGNsdXN0ZXIgNCB2cy4gMgoKREUwMTEyLjI1OCA8LSBGaW5kTWFya2Vycyhjb21iaW5lZCwgaWRlbnQuMSA9IGMoIjAiLCIxIiwiMTIiICksIGlkZW50LjIgPSBjKCIyIiwiNSIsIjgiKSx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpERTAxMTIuQWxsIDwtIEZpbmRNYXJrZXJzKGNvbWJpbmVkLCBpZGVudC4xID0gYygiMCIsIjEiLCIxMiIgKSwgdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKREUxLjIgPC0gRmluZE1hcmtlcnMoY29tYmluZWQsIGlkZW50LjEgPSBjKCIxIiApLCBpZGVudC4yID0gYygiMiIpLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCkRFMS41IDwtIEZpbmRNYXJrZXJzKGNvbWJpbmVkLCBpZGVudC4xID0gYygiMSIgKSwgaWRlbnQuMiA9IGMoIjUiKSx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpERTEuOCA8LSBGaW5kTWFya2Vycyhjb21iaW5lZCwgaWRlbnQuMSA9IGMoIjEiICksIGlkZW50LjIgPSBjKCI4IiksdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKCgpERTIuNSA8LSBGaW5kTWFya2Vycyhjb21iaW5lZCwgaWRlbnQuMSA9IGMoIjIiICksIGlkZW50LjIgPSBjKCI1IiksdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKREUyLjggPC0gRmluZE1hcmtlcnMoY29tYmluZWQsIGlkZW50LjEgPSBjKCIyIiApLCBpZGVudC4yID0gYygiOCIpLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCkRFNS44IDwtIEZpbmRNYXJrZXJzKGNvbWJpbmVkLCBpZGVudC4xID0gYygiNSIgKSwgaWRlbnQuMiA9IGMoIjgiKSx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQoKCkRFSzQzNTEuMjAgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMsIGlkZW50LjEgPSBjKCIzIiwiNCIsIjUiLCIxIiApLCBpZGVudC4yID0gYygiMiIsIjAiKSx2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQoKREVLNC4zIDwtIEZpbmRNYXJrZXJzKEtPLmNlbGxzLCBpZGVudC4xID0gIjQiLCBpZGVudC4yID0gIjMiLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCkRFSzQuMiA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9ICI0IiwgaWRlbnQuMiA9ICIyIix2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpERUs0LjAgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMsIGlkZW50LjEgPSAiNCIsIGlkZW50LjIgPSAiMCIsdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKREVLNC4xIDwtIEZpbmRNYXJrZXJzKEtPLmNlbGxzLCBpZGVudC4xID0gIjQiLCBpZGVudC4yID0gIjEiLHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCkRFSzQuNSA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9ICI0IiwgaWRlbnQuMiA9ICI1Iix2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQoKCgojIyMjIyBjb21hcHJpc29uIGJldHdlZW4gRzE3MUIgdnMgRzE3MUMgZm9yIEtPLmNlbGwgY2x1c3RlcnMgb2YgMCsxKzEyICMjIyMjIzMzCgpERUs0X0MuQiA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9ICI0X0cxNzFDIiwgaWRlbnQuMiA9ICI0X0cxNzFCIix2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpERUszX0MuQiA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9ICIzX0cxNzFDIiwgaWRlbnQuMiA9ICIzX0cxNzFCIix2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpERUsxX0MuQiA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9ICIxX0cxNzFDIiwgaWRlbnQuMiA9ICIxX0cxNzFCIix2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpERUsyX0MuQiA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9ICIyX0cxNzFDIiwgaWRlbnQuMiA9ICIyX0cxNzFCIix2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpERUswX0MuQiA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9ICIwX0cxNzFDIiwgaWRlbnQuMiA9ICIwX0cxNzFCIix2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpERUs1X0MuQiA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9ICI1X0cxNzFDIiwgaWRlbnQuMiA9ICI1X0cxNzFCIix2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIFdyaXRlIHRoZSByZXN1bHRzICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKd3JpdGUuY3N2KERFMDExMi4yNTgsICJDb3VudFJlc3VsdC9NYXJrZXJzL0RFMDExMi4yNTgiKQp3cml0ZS5jc3YoREUwMTEyLkFsbCwgIkNvdW50UmVzdWx0L01hcmtlcnMvREUwMTEyLkFsbCIpCndyaXRlLmNzdihERTEuMiwgIkNvdW50UmVzdWx0L01hcmtlcnMvREUxLjIiKQp3cml0ZS5jc3YoREUxLjUsICJDb3VudFJlc3VsdC9NYXJrZXJzL0RFMS41IikKd3JpdGUuY3N2KERFMS44LCAiQ291bnRSZXN1bHQvTWFya2Vycy9ERTEuOCIpCndyaXRlLmNzdihERTIuNSwgIkNvdW50UmVzdWx0L01hcmtlcnMvREUyLjUiKQp3cml0ZS5jc3YoREUyLjgsICJDb3VudFJlc3VsdC9NYXJrZXJzL0RFMi44IikKd3JpdGUuY3N2KERFNS44LCAiQ291bnRSZXN1bHQvTWFya2Vycy9ERTUuOCIpCgp3cml0ZS5jc3YoREVLNDM1MS4yMCwgIkNvdW50UmVzdWx0L01hcmtlcnMvREVLNDM1MS4yMCIpCndyaXRlLmNzdihERUs0LjMsICJDb3VudFJlc3VsdC9NYXJrZXJzL0RFSzQuMyIpCndyaXRlLmNzdihERUs0LjIsICJDb3VudFJlc3VsdC9NYXJrZXJzL0RFSzQuMiIpCndyaXRlLmNzdihERUs0LjAsICJDb3VudFJlc3VsdC9NYXJrZXJzL0RFSzQuMCIpCndyaXRlLmNzdihERUs0LjEsICJDb3VudFJlc3VsdC9NYXJrZXJzL0RFSzQuMSIpCndyaXRlLmNzdihERUs0LjUsICJDb3VudFJlc3VsdC9NYXJrZXJzL0RFSzQuNSIpCgoKd3JpdGUuY3N2KERFSzRfQy5CLCAiQ291bnRSZXN1bHQvTWFya2Vycy9ERUs0X0MuQiIpCndyaXRlLmNzdihERUszX0MuQiwgIkNvdW50UmVzdWx0L01hcmtlcnMvREVLM19DLkIiKQp3cml0ZS5jc3YoREVLMV9DLkIsICJDb3VudFJlc3VsdC9NYXJrZXJzL0RFSzFfQy5CIikKd3JpdGUuY3N2KERFSzJfQy5CLCAiQ291bnRSZXN1bHQvTWFya2Vycy9ERUsyX0MuQiIpCndyaXRlLmNzdihERUswX0MuQiwgIkNvdW50UmVzdWx0L01hcmtlcnMvREVLMF9DLkIiKQp3cml0ZS5jc3YoREVLNV9DLkIsICJDb3VudFJlc3VsdC9NYXJrZXJzL0RFSzVfQy5CIikKCgoKCmNvbWJpbmVkJGNlbGx0eXBlLnN0aW0gPC0gcGFzdGUoSWRlbnRzKGNvbWJpbmVkKSwgY29tYmluZWQkc3RpbSwgc2VwID0gIl8iKQpjb21iaW5lZCRjZWxsdHlwZSA8LSBJZGVudHMoY29tYmluZWQpCklkZW50cyhjb21iaW5lZCkgPC0gImNlbGx0eXBlLnN0aW0iCgoKdGVzdC5jb21iaW5lZCRjZWxsdHlwZS5zdGltIDwtIHBhc3RlKElkZW50cyh0ZXN0LmNvbWJpbmVkKSwgdGVzdC5jb21iaW5lZCRzdGltLCBzZXAgPSAiXyIpCnRlc3QuY29tYmluZWQkY2VsbHR5cGUgPC0gSWRlbnRzKHRlc3QuY29tYmluZWQpCklkZW50cyh0ZXN0LmNvbWJpbmVkKSA8LSAiY2VsbHR5cGUuc3RpbSIKCgoKCkNvbWJpbmVkX0cxNzFCX3ZzX0cxNzFDIDwtIEZpbmRNYXJrZXJzKGNvbWJpbmVkLCBpZGVudC4xID0gYygiMF9HMTcxQiIsIjFfRzE3MUIiLCIyX0cxNzFCIiwiM19HMTcxQiIsIjRfRzE3MUIiLCI1X0cxNzFCIiwiNl9HMTcxQiIsIjdfRzE3MUIiLCI4X0cxNzFCIiwiOV9HMTcxQiIsIjEwX0cxNzFCIiwiMTFfRzE3MUIiLCIxMl9HMTcxQiIgKSwgaWRlbnQuMiA9IGMoIjBfRzE3MUMiLCIxX0cxNzFDIiwiMl9HMTcxQyIsIjNfRzE3MUMiLCI0X0cxNzFDIiwiNV9HMTcxQyIsIjZfRzE3MUMiLCI3X0cxNzFDIiwiOF9HMTcxQyIsIjlfRzE3MUMiLCIxMF9HMTcxQyIsIjExX0cxNzFDIiwiMTJfRzE3MUMiICksIHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCgoKQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3QxIDwtIEZpbmRNYXJrZXJzKGNvbWJpbmVkLCBpZGVudC4xID0gYygiMV9HMTcxQyIpLCBpZGVudC4yID0gYygiMV9HMTcxQiIpLCB2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpDb21iaW5lZF9HMTcxQ192c19HMTcxQl9DbHVzdDAgPC0gRmluZE1hcmtlcnMoY29tYmluZWQsIGlkZW50LjEgPSBjKCIwX0cxNzFDIiksIGlkZW50LjIgPSBjKCIwX0cxNzFCIiksIHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCkNvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0MTIgPC0gRmluZE1hcmtlcnMoY29tYmluZWQsIGlkZW50LjEgPSBjKCIxMl9HMTcxQyIpLCBpZGVudC4yID0gYygiMTJfRzE3MUIiKSwgdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3QyIDwtIEZpbmRNYXJrZXJzKGNvbWJpbmVkLCBpZGVudC4xID0gYygiMl9HMTcxQyIpLCBpZGVudC4yID0gYygiMl9HMTcxQiIpLCB2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpDb21iaW5lZF9HMTcxQ192c19HMTcxQl9DbHVzdDUgPC0gRmluZE1hcmtlcnMoY29tYmluZWQsIGlkZW50LjEgPSBjKCI1X0cxNzFDIiksIGlkZW50LjIgPSBjKCI1X0cxNzFCIiksIHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCkNvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0OCA8LSBGaW5kTWFya2Vycyhjb21iaW5lZCwgaWRlbnQuMSA9IGMoIjhfRzE3MUMiKSwgaWRlbnQuMiA9IGMoIjhfRzE3MUIiKSwgdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKCgpDb21iaW5lZF9HMTcxQ192c19HMTcxQl9DbHVzdDMgPC0gRmluZE1hcmtlcnMoY29tYmluZWQsIGlkZW50LjEgPSBjKCIzX0cxNzFDIiksIGlkZW50LjIgPSBjKCIzX0cxNzFCIiksIHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCkNvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0NCA8LSBGaW5kTWFya2Vycyhjb21iaW5lZCwgaWRlbnQuMSA9IGMoIjRfRzE3MUMiKSwgaWRlbnQuMiA9IGMoIjRfRzE3MUIiKSwgdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3Q2IDwtIEZpbmRNYXJrZXJzKGNvbWJpbmVkLCBpZGVudC4xID0gYygiNl9HMTcxQyIpLCBpZGVudC4yID0gYygiNl9HMTcxQiIpLCB2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpDb21iaW5lZF9HMTcxQ192c19HMTcxQl9DbHVzdDcgPC0gRmluZE1hcmtlcnMoY29tYmluZWQsIGlkZW50LjEgPSBjKCI3X0cxNzFDIiksIGlkZW50LjIgPSBjKCI3X0cxNzFCIiksIHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCkNvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0OSA8LSBGaW5kTWFya2Vycyhjb21iaW5lZCwgaWRlbnQuMSA9IGMoIjlfRzE3MUMiKSwgaWRlbnQuMiA9IGMoIjlfRzE3MUIiKSwgdmVyYm9zZSA9IFRSVUUsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3QxMCA8LSBGaW5kTWFya2Vycyhjb21iaW5lZCwgaWRlbnQuMSA9IGMoIjEwX0cxNzFDIiksIGlkZW50LjIgPSBjKCIxMF9HMTcxQiIpLCB2ZXJib3NlID0gVFJVRSwgbG9nZmMudGhyZXNob2xkID0gRkFMU0UsbWluLnBjdCA9IEZBTFNFKQpDb21iaW5lZF9HMTcxQ192c19HMTcxQl9DbHVzdDExIDwtIEZpbmRNYXJrZXJzKGNvbWJpbmVkLCBpZGVudC4xID0gYygiMTFfRzE3MUMiKSwgaWRlbnQuMiA9IGMoIjExX0cxNzFCIiksIHZlcmJvc2UgPSBUUlVFLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCgoKCgoKd3JpdGUuY3N2KENvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0MSwgIkNvdW50UmVzdWx0L01hcmtlcnMvQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3QxIikKd3JpdGUuY3N2KENvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0MCwgIkNvdW50UmVzdWx0L01hcmtlcnMvQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3QwIikKd3JpdGUuY3N2KENvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0MTIsICJDb3VudFJlc3VsdC9NYXJrZXJzL0NvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0MTIiKQp3cml0ZS5jc3YoQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3QyLCAiQ291bnRSZXN1bHQvTWFya2Vycy9Db21iaW5lZF9HMTcxQ192c19HMTcxQl9DbHVzdDIiKQp3cml0ZS5jc3YoQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3Q1LCAiQ291bnRSZXN1bHQvTWFya2Vycy9Db21iaW5lZF9HMTcxQ192c19HMTcxQl9DbHVzdDUiKQp3cml0ZS5jc3YoQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3Q4LCAiQ291bnRSZXN1bHQvTWFya2Vycy9Db21iaW5lZF9HMTcxQ192c19HMTcxQl9DbHVzdDgiKQoKd3JpdGUuY3N2KENvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0MywgIkNvdW50UmVzdWx0L01hcmtlcnMvQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3QzIikKd3JpdGUuY3N2KENvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0NCwgIkNvdW50UmVzdWx0L01hcmtlcnMvQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3Q0IikKd3JpdGUuY3N2KENvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0NiwgIkNvdW50UmVzdWx0L01hcmtlcnMvQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3Q2IikKd3JpdGUuY3N2KENvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0NywgIkNvdW50UmVzdWx0L01hcmtlcnMvQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3Q3IikKd3JpdGUuY3N2KENvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0OSwgIkNvdW50UmVzdWx0L01hcmtlcnMvQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3Q5IikKd3JpdGUuY3N2KENvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0MTAsICJDb3VudFJlc3VsdC9NYXJrZXJzL0NvbWJpbmVkX0cxNzFDX3ZzX0cxNzFCX0NsdXN0MTAiKQp3cml0ZS5jc3YoQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3QxMSwgIkNvdW50UmVzdWx0L01hcmtlcnMvQ29tYmluZWRfRzE3MUNfdnNfRzE3MUJfQ2x1c3QxMSIpCgoKCgoKUENfdnNfUFBfRzE3MUIgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMsIGlkZW50LjEgPSBjKCI0X0cxNzFCIiwiM19HMTcxQiIpLCBpZGVudC4yID0gYygiMF9HMTcxQiIsIjJfRzE3MUIiKSwgdmVyYm9zZSA9IFRSVUUsIHRlc3QudXNlID0gIk1BU1QiLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCmhlYWQoUENfdnNfUFBfRzE3MUIsIG4gPSAxNSkKCgpQQ192c19QUF9HMTcxQyA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9IGMoIjRfRzE3MUMiLCIzX0cxNzFDIiksIGlkZW50LjIgPSBjKCIwX0cxNzFDIiwiMl9HMTcxQyIpLCB2ZXJib3NlID0gVFJVRSwgdGVzdC51c2UgPSAiTUFTVCIsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKaGVhZChQQ192c19QUF9HMTcxQywgbiA9IDE1KQoKClBDX3ZzX1BQX0cxNzFCQyA8LSBGaW5kTWFya2VycyhLTy5jZWxscywgaWRlbnQuMSA9IGMoIjRfRzE3MUIiLCIzX0cxNzFCIiwiNF9HMTcxQyIsIjNfRzE3MUMiKSwgaWRlbnQuMiA9IGMoIjBfRzE3MUIiLCIyX0cxNzFCIiwiMF9HMTcxQyIsIjJfRzE3MUMiKSwgdmVyYm9zZSA9IFRSVUUsIHRlc3QudXNlID0gIk1BU1QiLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCmhlYWQoUENfdnNfUFBfRzE3MUMsIG4gPSAxNSkKCgpsbmM1OTk4X0tPX0RFXzEgPC0gRmluZE1hcmtlcnMoS08uY2VsbHMsIGlkZW50LjEgPSBjKCI0X0cxNzFCIiwiM19HMTcxQiIsIjVfRzE3MUIiKSwgaWRlbnQuMiA9IGMoIjRfRzE3MUMiLCIzX0cxNzFDIiwiNV9HMTcxQyIpLCB2ZXJib3NlID0gVFJVRSwgdGVzdC51c2UgPSAiTUFTVCIsIGxvZ2ZjLnRocmVzaG9sZCA9IEZBTFNFLG1pbi5wY3QgPSBGQUxTRSkKaGVhZChsbmM1OTk4X0tPX0RFLCBuID0gMTUpCgoKbG5jNTk5OF9LT19ERV8yIDwtIEZpbmRNYXJrZXJzKEtPLmNlbGxzLCBpZGVudC4xID0gYygiNF9HMTcxQyIsIjNfRzE3MUMiLCI1X0cxNzFDIiksIGlkZW50LjIgPWMoIjRfRzE3MUIiLCIzX0cxNzFCIiwiNV9HMTcxQiIpICwgdmVyYm9zZSA9IFRSVUUsIHRlc3QudXNlID0gIk1BU1QiLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCmhlYWQobG5jNTk5OF9LT19ERSwgbiA9IDE1KQoKY2VsbC50eXBlLmdlbmVzIDwtIChQQ192c19QUF9HMTcxQkNbMV0pICMgVGFrZXMgYWxsIHRoZSB1bmlxdWUgY2VsbCB0eXBlIHNwZWNpZmljIGdlbmVzCkdPdGVybXMgPSB0b3BHT3Rlcm1zKGZnLmdlbmVzID0gY2VsbC50eXBlLmdlbmVzLCBiZy5nZW5lcyA9IHJvd25hbWVzKEtPLmNlbGxzQGFzc2F5cyRSTkFAZGF0YUtPLmNlbGxzQGFzc2F5cyRSTkFAZGF0YSksIG9yZ2FuaXNtID0gIk1vdXNlIikKCmNlbGwudHlwZS5nZW5lcyA8LSAoUENfdnNfUFBfRzE3MUJDWzFdKSAjIFRha2VzIGFsbCB0aGUgdW5pcXVlIGNlbGwgdHlwZSBzcGVjaWZpYyBnZW5lcwpHT3Rlcm1zID0gdG9wR090ZXJtcyhmZy5nZW5lcyA9IHJvd25hbWVzKGNlbGwudHlwZS5nZW5lcyksIGJnLmdlbmVzID0gcm93bmFtZXMoS08uY2VsbHNAYXNzYXlzJFJOQUBkYXRhKSwgb3JnYW5pc20gPSAiTW91c2UiKQogCmBgYAoKYGBge3J9CgoKCgoKQXZlcmdlRXhwcmVzc2lvbjIgPC0gZnVuY3Rpb24gKG9iamVjdCwgYXNzYXlzID0gTlVMTCwgZmVhdHVyZXMgPSBOVUxMLCByZXR1cm4uc2V1cmF0ID0gRkFMU0UsIAogICAgICAgICAgYWRkLmlkZW50ID0gTlVMTCwgc2xvdCA9ICJkYXRhIiwgdXNlLnNjYWxlID0gRkFMU0UsIHVzZS5jb3VudHMgPSBGQUxTRSwgCiAgICAgICAgICB2ZXJib3NlID0gVFJVRSwgLi4uKSAKewogICAgCiAgICBmeG4uYXZlcmFnZSA8LSBzd2l0Y2goRVhQUiA9IHNsb3QsIGRhdGEgPSBmdW5jdGlvbih4KSB7CiAgICAgICAgcmV0dXJuKG1lYW4oeCA9IHgpKQogICAgfSwgbWVhbikKICAgIG9iamVjdC5hc3NheXMgPC0gRmlsdGVyT2JqZWN0cyhvYmplY3QgPSBvYmplY3QsIGNsYXNzZXMua2VlcCA9ICJBc3NheSIpCiAgICBhc3NheXMgPC0gYXNzYXlzICV8fCUgb2JqZWN0LmFzc2F5cwogICAgaWRlbnQub3JpZyA8LSBJZGVudHMob2JqZWN0ID0gb2JqZWN0KQogICAgb3JpZy5sZXZlbHMgPC0gbGV2ZWxzKHggPSBJZGVudHMob2JqZWN0ID0gb2JqZWN0KSkKICAgIGlkZW50Lm5ldyA8LSBjKCkKICAgIGlmICghYWxsKGFzc2F5cyAlaW4lIG9iamVjdC5hc3NheXMpKSB7CiAgICAgICAgYXNzYXlzIDwtIGFzc2F5c1thc3NheXMgJWluJSBvYmplY3QuYXNzYXlzXQogICAgICAgIGlmIChsZW5ndGgoYXNzYXlzKSA9PSAwKSB7CiAgICAgICAgICAgIHN0b3AoIk5vbmUgb2YgdGhlIHJlcXVlc3RlZCBhc3NheXMgYXJlIHByZXNlbnQgaW4gdGhlIG9iamVjdCIpCiAgICAgICAgfQogICAgICAgIGVsc2UgewogICAgICAgICAgICB3YXJuaW5nKCJSZXF1ZXN0ZWQgYXNzYXlzIHRoYXQgZG8gbm90IGV4aXN0IGluIG9iamVjdC4gUHJvY2VlZGluZyB3aXRoIGV4aXN0aW5nIGFzc2F5cyBvbmx5LiIpCiAgICAgICAgfQogICAgfQogICAgaWYgKCFpcy5udWxsKHggPSBhZGQuaWRlbnQpKSB7CiAgICAgICAgbmV3LmRhdGEgPC0gRmV0Y2hEYXRhKG9iamVjdCA9IG9iamVjdCwgdmFycyA9IGFkZC5pZGVudCkKICAgICAgICBuZXcuaWRlbnQgPC0gcGFzdGUoSWRlbnRzKG9iamVjdClbcm93bmFtZXMoeCA9IG5ldy5kYXRhKV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcuZGF0YVssIDFdLCBzZXAgPSAiXyIpCiAgICAgICAgSWRlbnRzKG9iamVjdCwgY2VsbHMgPSByb3duYW1lcyhuZXcuZGF0YSkpIDwtIG5ldy5pZGVudAogICAgfQogICAgZGF0YS5yZXR1cm4gPC0gbGlzdCgpCiAgICBmb3IgKGkgaW4gMTpsZW5ndGgoeCA9IGFzc2F5cykpIHsKICAgICAgICBkYXRhLnVzZSA8LSBHZXRBc3NheURhdGEob2JqZWN0ID0gb2JqZWN0LCBhc3NheSA9IGFzc2F5c1tpXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNsb3QgPSBzbG90KQogICAgICAgIGZlYXR1cmVzLmFzc2F5IDwtIGZlYXR1cmVzCiAgICAgICAgaWYgKGxlbmd0aCh4ID0gaW50ZXJzZWN0KHggPSBmZWF0dXJlcywgeSA9IHJvd25hbWVzKHggPSBkYXRhLnVzZSkpKSA8IAogICAgICAgICAgICAxKSB7CiAgICAgICAgICAgIGZlYXR1cmVzLmFzc2F5IDwtIHJvd25hbWVzKHggPSBkYXRhLnVzZSkKICAgICAgICB9CiAgICAgICAgZGF0YS5hbGwgPC0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSBmZWF0dXJlcy5hc3NheSkKICAgICAgICBmb3IgKGogaW4gbGV2ZWxzKHggPSBJZGVudHMob2JqZWN0KSkpIHsKICAgICAgICAgICAgdGVtcC5jZWxscyA8LSBXaGljaENlbGxzKG9iamVjdCA9IG9iamVjdCwgaWRlbnRzID0gaikKICAgICAgICAgICAgZmVhdHVyZXMuYXNzYXkgPC0gdW5pcXVlKHggPSBpbnRlcnNlY3QoeCA9IGZlYXR1cmVzLmFzc2F5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHJvd25hbWVzKHggPSBkYXRhLnVzZSkpKQogICAgICAgICAgICBpZiAobGVuZ3RoKHggPSB0ZW1wLmNlbGxzKSA9PSAxKSB7CiAgICAgICAgICAgICAgICBkYXRhLnRlbXAgPC0gKGRhdGEudXNlW2ZlYXR1cmVzLmFzc2F5LCB0ZW1wLmNlbGxzXSkKICAgICAgICAgICAgICAgIGlmIChzbG90ID09ICJkYXRhIikgewogICAgICAgICAgICAgICAgICAgIGRhdGEudGVtcCA8LSAgZGF0YS50ZW1wCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYgKGxlbmd0aCh4ID0gdGVtcC5jZWxscykgPiAxKSB7CiAgICAgICAgICAgICAgICBkYXRhLnRlbXAgPC0gYXBwbHkoWCA9IGRhdGEudXNlW2ZlYXR1cmVzLmFzc2F5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVtcC5jZWxscywgZHJvcCA9IEZBTFNFXSwgTUFSR0lOID0gMSwgRlVOID0gZnhuLmF2ZXJhZ2UpCiAgICAgICAgICAgIH0KICAgICAgICAgICAgZGF0YS5hbGwgPC0gY2JpbmQoZGF0YS5hbGwsIGRhdGEudGVtcCkKICAgICAgICAgICAgY29sbmFtZXMoeCA9IGRhdGEuYWxsKVtuY29sKHggPSBkYXRhLmFsbCldIDwtIGoKICAgICAgICAgICAgaWYgKHZlcmJvc2UpIHsKICAgICAgICAgICAgICAgIG1lc3NhZ2UocGFzdGUoIkZpbmlzaGVkIGF2ZXJhZ2luZyIsIGFzc2F5c1tpXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmb3IgY2x1c3RlciIsIGopKQogICAgICAgICAgICB9CiAgICAgICAgICAgIGlmIChpID09IDEpIHsKICAgICAgICAgICAgICAgIGlkZW50Lm5ldyA8LSBjKGlkZW50Lm5ldywgYXMuY2hhcmFjdGVyKHggPSBpZGVudC5vcmlnW3RlbXAuY2VsbHNbMV1dKSkKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBuYW1lcyh4ID0gaWRlbnQubmV3KSA8LSBsZXZlbHMoeCA9IElkZW50cyhvYmplY3QpKQogICAgICAgIGRhdGEucmV0dXJuW1tpXV0gPC0gZGF0YS5hbGwKICAgICAgICBuYW1lcyh4ID0gZGF0YS5yZXR1cm4pW2ldIDwtIGFzc2F5c1tbaV1dCiAgICB9CiAgICBpZiAocmV0dXJuLnNldXJhdCkgewogICAgICAgIHRvUmV0IDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBkYXRhLnJldHVybltbMV1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvamVjdCA9ICJBdmVyYWdlIiwgYXNzYXkgPSBuYW1lcyh4ID0gZGF0YS5yZXR1cm4pWzFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uKQogICAgICAgIGlmIChsZW5ndGgoeCA9IGRhdGEucmV0dXJuKSA+IDEpIHsKICAgICAgICAgICAgZm9yIChpIGluIDI6bGVuZ3RoKHggPSBkYXRhLnJldHVybikpIHsKICAgICAgICAgICAgICAgIHRvUmV0W1tuYW1lcyh4ID0gZGF0YS5yZXR1cm4pW2ldXV0gPC0gQ3JlYXRlQXNzYXlPYmplY3QoY291bnRzID0gZGF0YS5yZXR1cm5bW2ldXSkKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZiAoRGVmYXVsdEFzc2F5KG9iamVjdCA9IG9iamVjdCkgJWluJSBuYW1lcyh4ID0gZGF0YS5yZXR1cm4pKSB7CiAgICAgICAgICAgIERlZmF1bHRBc3NheShvYmplY3QgPSB0b1JldCkgPC0gRGVmYXVsdEFzc2F5KG9iamVjdCA9IG9iamVjdCkKICAgICAgICB9CiAgICAgICAgSWRlbnRzKHRvUmV0LCBjZWxscyA9IGNvbG5hbWVzKHggPSB0b1JldCkpIDwtIGlkZW50Lm5ld1tjb2xuYW1lcyh4ID0gdG9SZXQpXQogICAgICAgIElkZW50cyhvYmplY3QgPSB0b1JldCkgPC0gZmFjdG9yKHggPSBJZGVudHMob2JqZWN0ID0gdG9SZXQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBhcy5jaGFyYWN0ZXIoeCA9IG9yaWcubGV2ZWxzKSwgb3JkZXJlZCA9IFRSVUUpCiAgICAgICAgdG9SZXQgPC0gTm9ybWFsaXplRGF0YShvYmplY3QgPSB0b1JldCwgdmVyYm9zZSA9IHZlcmJvc2UpCiAgICAgICAgdG9SZXQgPC0gU2NhbGVEYXRhKG9iamVjdCA9IHRvUmV0LCB2ZXJib3NlID0gdmVyYm9zZSkKICAgICAgICByZXR1cm4odG9SZXQpCiAgICB9CiAgICBlbHNlIHsKICAgICAgICByZXR1cm4oZGF0YS5yZXR1cm4pCiAgICB9Cn0KYGBgCgoKCkZpbmQgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gbWFya2VycwoKYGBge3J9CmNvbWJpbmVkLm1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMob2JqZWN0ID0gY29tYmluZWQsIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIHRocmVzaC51c2UgPSAwLjI1KQpjb21iaW5lZC5tYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24oMiwgYXZnX2xvZ0ZDKQoKS08ubWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhvYmplY3QgPSBLTy5jZWxscywgb25seS5wb3MgPSBUUlVFLCBtaW4ucGN0ID0gMC4yNSwgdGhyZXNoLnVzZSA9IDAuMjUpCgpyZXNwb25zZTMgPC0gRmluZE1hcmtlcnMoY29tYmluZWQsIGlkZW50LjEgPSBjKCIxX0cxNzFCIiwiMF9HMTcxQiIsIjJfRzE3MUIiKSwgaWRlbnQuMiA9IGMoIjFfRzE3MUMiLCAiMF9HMTcxQyIsIjJfRzE3MUMiKSwgdmVyYm9zZSA9IFRSVUUsIHRlc3QudXNlID0gIk1BU1QiLCBsb2dmYy50aHJlc2hvbGQgPSBGQUxTRSxtaW4ucGN0ID0gRkFMU0UpCmhlYWQocmVzcG9uc2UzLCBuID0gMTUpCgpgYGAKCgoKCmBgYHtyfQpnZW5lc19oZXBfbWFpbiA9YygnQWxiJywgJ1R0cicsICdBcG9hMScsICdTZXJwaW5hMWMnKQpnZW5lc19oZXAgPSBjKCdBbGInLCAnVHRyJywgJ0Fwb2ExJywgJ1NlcnBpbmExYycsCiAgICAgICAgICAgICAgICAgICAnQ3lwMmUxJywgJ0dsdWwnLCAnT2F0JywgJ0d1bG8nLAogICAgICAgICAgICAgICAgICAgJ0FzczEnLCAnSGFtcCcsICdHc3RwMScsICdVYmInLAogICAgICAgICAgICAgICAgICAgJ0N5cDJmMicsICdQY2sxJywgJ0hhbCcsICdDZGgxJykKZ2VuZXNfZW5kbyA9IGMoJ1BlY2FtMScsICdOcnAxJywgJ0tkcicsJ09pdDMnKQpnZW5lc19rdXBwZmVyID0gYyggJ0NsZWM0ZicsICdDZDY4JykKZ2VuZXNfbmsgPSBjKCdJbDJyYicsICdOa2c3JywgJ0N4Y3I2JywgJ0d6bWEnKQpnZW5lc19iID0gYygnQ2Q3OWEnLCAnQ2Q3OWInKQpnZW5lc19iZWMgPSBjKCdFcGNhbScsICdLcnQxOScsICdLcnQ3JykKZ2VuZXNfaW1tdW5lID0gJ1B0cHJjJwpIU0MgPSBjKCJBY3RhMiIsICJHZmFwIiwiRGVzIiwiTmdmciIsIkNvbDJhMSIsIlZpbSIsIkxhbWExIiwiTmVzIikKCmFsbF9nZW5lcyA9IGMoZ2VuZXNfaGVwLCBnZW5lc19lbmRvLCBnZW5lc19rdXBwZmVyLCBnZW5lc19uaywgZ2VuZXNfYiwgZ2VuZXNfYmVjLCBnZW5lc19pbW11bmUsIEhTQykKZ2VuZXNfYmVjX2JfaW1tdW5lICA9IGMoZ2VuZXNfYmVjLGdlbmVzX2IsZ2VuZXNfaW1tdW5lKQpnZW5lc196b25lcyA9IGMoJ0N5cDJlMScsICdHbHVsJywgJ09hdCcsICdHdWxvJywKICAgICAgICAgICAgICAnQXNzMScsICdIYW1wJywgJ0dzdHAxJywgJ1ViYicsCiAgICAgICAgICAgICAgJ0N5cDJmMicsICdQY2sxJywgJ0hhbCcsICdDZGgxJykKCnJlY2VwdG9yX0tPIDwtIGMoIm5jUk5BLWludGVyLWNocjctNTk5OCIsIkN5cDJiMTAiLCJOcjFpMiIsIk5yMWkzIiwiUHBhcmEiLCJQcGFyZyIsIlBwYXJnYzFiIiwiUHBhcmQiKQpgYGAKCgoKVmlzdWFsaXplIHRvcCBnZW5lcyBpbiBwcmluY2lwYWwgY29tcG9uZW50cwoKYGBge3IsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTh9ClBDSGVhdG1hcChvYmplY3QgPSB0aXNzMSwgcGMudXNlID0gMTozLCBjZWxscy51c2UgPSA1MDAsIGRvLmJhbGFuY2VkID0gVFJVRSwgbGFiZWwuY29sdW1ucyA9IEZBTFNFLCBudW0uZ2VuZXMgPSA4KQpgYGAKCkxhdGVyIG9uIChpbiBGaW5kQ2x1c3RlcnMgYW5kIFRTTkUpIHlvdSB3aWxsIHBpY2sgYSBudW1iZXIgb2YgcHJpbmNpcGFsIGNvbXBvbmVudHMgdG8gdXNlLiBUaGlzIGhhcyB0aGUgZWZmZWN0IG9mIGtlZXBpbmcgdGhlIG1ham9yIGRpcmVjdGlvbnMgb2YgdmFyaWF0aW9uIGluIHRoZSBkYXRhIGFuZCwgaWRlYWxseSwgc3VwcmVzc2luZyBub2lzZS4gVGhlcmUgaXMgbm8gY29ycmVjdCBhbnN3ZXIgdG8gdGhlIG51bWJlciB0byB1c2UsIGJ1dCBhIGRlY2VudCBydWxlIG9mIHRodW1iIGlzIHRvIGdvIHVudGlsIHRoZSBwbG90IHBsYXRlYXVzLgoKYGBge3J9ClBDRWxib3dQbG90KG9iamVjdCA9IHRpc3MxKQpgYGAKCkNob29zZSB0aGUgbnVtYmVyIG9mIHByaW5jaXBhbCBjb21wb25lbnRzIHRvIHVzZS4KYGBge3J9CiMgU2V0IG51bWJlciBvZiBwcmluY2lwYWwgY29tcG9uZW50cy4gCm4ucGNzID0gMTAKYGBgCgpUaGUgY2x1c3RlcmluZyBpcyBwZXJmb3JtZWQgYmFzZWQgb24gYSBuZWFyZXN0IG5laWdoYm9ycyBncmFwaC4gQ2VsbHMgdGhhdCBoYXZlIHNpbWlsYXIgZXhwcmVzc2lvbiB3aWxsIGJlIGpvaW5lZCB0b2dldGhlci4gVGhlIExvdXZhaW4gYWxnb3JpdGhtIGxvb2tzIGZvciBncm91cHMgb2YgY2VsbHMgd2l0aCBoaWdoIG1vZHVsYXJpdHktLW1vcmUgY29ubmVjdGlvbnMgd2l0aGluIHRoZSBncm91cCB0aGFuIGJldHdlZW4gZ3JvdXBzLiBUaGUgcmVzb2x1dGlvbiBwYXJhbWV0ZXIgZGV0ZXJtaW5lcyB0aGUgc2NhbGUuIEhpZ2hlciByZXNvbHV0aW9uIHdpbGwgZ2l2ZSBtb3JlIGNsdXN0ZXJzLCBsb3dlciByZXNvbHV0aW9uIHdpbGwgZ2l2ZSBmZXdlci4KCkZvciB0aGUgdG9wLWxldmVsIGNsdXN0ZXJpbmcsIGFpbSB0byB1bmRlci1jbHVzdGVyIGluc3RlYWQgb2Ygb3Zlci1jbHVzdGVyLiBJdCB3aWxsIGJlIGVhc3kgdG8gc3Vic2V0IGdyb3VwcyBhbmQgZnVydGhlciBhbmFseXplIHRoZW0gYmVsb3cuCgpgYGB7cn0KIyBTZXQgcmVzb2x1dGlvbiAKcmVzLnVzZWQgPC0gNAp0aXNzMSA8LSBGaW5kQ2x1c3RlcnMob2JqZWN0ID0gdGlzczEsIHJlZHVjdGlvbi50eXBlID0gInBjYSIsIGRpbXMudXNlID0gMTpuLnBjcywgCiAgICByZXNvbHV0aW9uID0gcmVzLnVzZWQsIHByaW50Lm91dHB1dCA9IDAsIHNhdmUuU05OID0gVFJVRSwgZm9yY2UucmVjYWxjID0gVFJVRSkKYGBgCgpXZSB1c2UgVFNORSBzb2xlbHkgdG8gdmlzdWFsaXplIHRoZSBkYXRhLgpgYGB7cn0KIyBJZiBjZWxscyBhcmUgdG9vIHNwcmVhZCBvdXQsIHlvdSBjYW4gcmFpc2UgdGhlIHBlcnBsZXhpdHkuIElmIHlvdSBoYXZlIGZldyBjZWxscywgdHJ5IGEgbG93ZXIgcGVycGxleGl0eSAoYnV0IG5ldmVyIGxlc3MgdGhhbiAxMCkuCnRpc3MxIDwtIFJ1blRTTkUob2JqZWN0ID0gdGlzczEsIGRpbXMudXNlID0gMTpuLnBjcywgc2VlZC51c2UgPSAxMCwgcGVycGxleGl0eT0zMCkKYGBgCgpgYGB7cn0KVFNORVBsb3Qob2JqZWN0ID0gdGlzczEsIGRvLmxhYmVsID0gVCwgcHQuc2l6ZSA9IDEuMiwgbGFiZWwuc2l6ZSA9IDQpCmBgYAojIyBDb21wYXJlIHRvIHByZXZpb3VzIGFubm90YXRpb25zCmBgYHtyfQpwcmV2aW91c19hbm5vdGF0aW9uID0gcmVhZC5jc3YoIi9Vc2Vycy9ra2FycmkvRG9jdW1lbnRzL0xhYi9TaW5nbGVfY2VsbF9wcm9qZWN0L2Ryb3BzZXEvTGl2ZXJfZHJvcGxldF9hbm5vdGF0aW9uLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKY29scyA9IGMoJ2ZyZWVfYW5ub3RhdGlvbicsICdjZWxsX29udG9sb2d5X2NsYXNzJykKICAgIGZvciAoY29sIGluIGNvbHMpewogICAgICBwcmV2aW91c19jb2wgPSBwYXN0ZTAoJ3ByZXZpb3VzXycsIGNvbCkKICAgICAgdGlzczFAbWV0YS5kYXRhWywgcHJldmlvdXNfY29sXSA8LSAiTkEiCiAgICAgIHRpc3MxQG1ldGEuZGF0YVthcy5jaGFyYWN0ZXIocHJldmlvdXNfYW5ub3RhdGlvbiRYKSwgcHJldmlvdXNfY29sXSA8LSBwcmV2aW91c19hbm5vdGF0aW9uWywgY29sXQogICAgICBwcmludCh0YWJsZSh0aXNzMUBtZXRhLmRhdGFbLCBwcmV2aW91c19jb2xdKSkKICAgICAgcHJpbnQodGFibGUodGlzczFAbWV0YS5kYXRhWywgcHJldmlvdXNfY29sXSwgdGlzc0BpZGVudCkpCiAgICAgIAogICAgfQogICAgCnRpc3MxID0gY29tcGFyZV9wcmV2aW91c19hbm5vdGF0aW9uKHRpc3MxLCB0aXNzdWVfb2ZfaW50ZXJlc3QsICJkcm9wbGV0IikKVFNORVBsb3Qob2JqZWN0ID0gdGlzczEsIGRvLnJldHVybiA9IFRSVUUsIGdyb3VwLmJ5ID0gInByZXZpb3VzX2NlbGxfb250b2xvZ3lfY2xhc3MiKQp0YWJsZSh0aXNzMUBtZXRhLmRhdGFbLCAicHJldmlvdXNfY2VsbF9vbnRvbG9neV9jbGFzcyJdLCB0aXNzQGlkZW50KQpgYGAKCgpgYGB7cn0KdGlzczEgPSBjb21wYXJlX3ByZXZpb3VzX2Fubm90YXRpb24odGlzczEsIHRpc3N1ZV9vZl9pbnRlcmVzdCwgImRyb3BsZXQiKQpUU05FUGxvdChvYmplY3QgPSB0aXNzMSwgZG8ucmV0dXJuID0gVFJVRSwgZ3JvdXAuYnkgPSAicHJldmlvdXNfY2VsbF9vbnRvbG9neV9jbGFzcyIpCnRhYmxlKHRpc3MxQG1ldGEuZGF0YVssICJwcmV2aW91c19jZWxsX29udG9sb2d5X2NsYXNzIl0sIHRpc3MxQGlkZW50KQpgYGAKCgpgYGB7cn0KVFNORVBsb3QodGlzczEsIGdyb3VwLmJ5PSJtb3VzZS5zZXgiKQpUU05FUGxvdCh0aXNzMSwgZ3JvdXAuYnk9Im1vdXNlLmlkIikKYGBgCgoKU2lnbmlmaWNhbnQgZ2VuZXM6CgpoZXBhdG9jeXRlOiBBbGIsIFR0ciwgQXBvYTEsIGFuZCBTZXJwaW5hMWMKcGVyaWNlbnRyYWw6IEN5cDJlMSwgR2x1bCwgT2F0LCBHdWxvCm1pZGxvYnVsYXI6IEFzczEsIEhhbXAsIEdzdHAxLCBVYmIKcGVyaXBvcnRhbDogQ3lwMmYyLCBQY2sxLCBIYWwsIENkaDEKCmVuZG90aGVsaWFsIGNlbGxzOiBQZWNhbTEsIE5ycDEsIEtkcisgYW5kIE9pdDMrCkt1cHBmZXIgY2VsbHM6IEVtcjEsIENsZWM0ZiwgQ2Q2OCwgSXJmNwpOSy9OS1QgY2VsbHM6IFphcDcwLCBJbDJyYiwgTmtnNywgQ3hjcjYsIEtscjFjLCBHem1hCkIgY2VsbHM6IENkNzlhLCBDZDc5YiwgQ2Q3NCBhbmQgQ2QxOQpJbW11bmUgY2VsbHM6IFB0cHJjCgoKCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD0xNiwgZmlnLndpZHRoPTEyfQojIEhlcGF0aWMgbWFya2VyCkZlYXR1cmVQbG90KHRpc3MxLCBjKGdlbmVzX2hlcCksIHB0LnNpemUgPSAxLCBuQ29sID0gNCwgY29scy51c2UgPSBjKCJncmV5IiwgInJlZCIpKQoKIyBFbmRvdGhlbGlhbCBtYXJrZXJzCkZlYXR1cmVQbG90KHRpc3MxLCBjKGdlbmVzX2VuZG8pLCBwdC5zaXplID0gMSwgbkNvbCA9IDQsIGNvbHMudXNlID0gYygiZ3JleSIsICJyZWQiKSkKCiMgS3VwZmZlciBjZWxscwpGZWF0dXJlUGxvdCh0aXNzMSwgYyhnZW5lc19rdXBwZmVyKSwgcHQuc2l6ZSA9IDEsIG5Db2wgPSA0LCBjb2xzLnVzZSA9IGMoImdyZXkiLCAicmVkIikpCgojIGdlbmVzX25rCkZlYXR1cmVQbG90KHRpc3MxLCBjKGdlbmVzX25rKSwgcHQuc2l6ZSA9IDEsIG5Db2wgPSA0LCBjb2xzLnVzZSA9IGMoImdyZXkiLCAicmVkIikpCgojIGdlbmVzX2IKRmVhdHVyZVBsb3QodGlzczEsIGMoZ2VuZXNfYiksIHB0LnNpemUgPSAxLCBuQ29sID0gNCwgY29scy51c2UgPSBjKCJncmV5IiwgInJlZCIpKQoKIyBnZW5lcyBiaWxlIGR1Y3QgZW5kbyBjZWxscwpGZWF0dXJlUGxvdCh0aXNzMSwgYyhnZW5lc19iZWMpLCBwdC5zaXplID0gMSwgbkNvbCA9IDQsIGNvbHMudXNlID0gYygiZ3JleSIsICJyZWQiKSkKCiMgZ2VuZXMgaW1tdW5lCkZlYXR1cmVQbG90KHRpc3MxLCBjKGdlbmVzX2ltbXVuZSksIHB0LnNpemUgPSAxLCBuQ29sID0gNCwgY29scy51c2UgPSBjKCJncmV5IiwgInJlZCIpKQoKCmBgYAoKRG90cGxvdHMgbGV0IHlvdSBzZWUgdGhlIGludGVuc2l0eSBvZiBleHBwcmVzc2lvbiBhbmQgdGhlIGZyYWN0aW9uIG9mIGNlbGxzIGV4cHJlc3NpbmcgZm9yIGVhY2ggb2YgeW91ciBnZW5lcyBvZiBpbnRlcmVzdC4KVGhlIHJhZGl1cyBzaG93cyB5b3UgdGhlIHBlcmNlbnQgb2YgY2VsbHMgaW4gdGhhdCBjbHVzdGVyIHdpdGggYXQgbGVhc3Qgb25lIHJlYWQgc2VxdWVuY2VkIGZyb20gdGhhdCBnZW5lLiBUaGUgY29sb3IgbGV2ZWwgaW5kaWNhdGVzIHRoZSBhdmVyYWdlClotc2NvcmUgb2YgZ2VuZSBleHByZXNzaW9uIGZvciBjZWxscyBpbiB0aGF0IGNsdXN0ZXIsIHdoZXJlIHRoZSBzY2FsaW5nIGlzIGRvbmUgb3ZlciB0YWtlbiBvdmVyIGFsbCBjZWxscyBpbiB0aGUgc2FtcGxlLgoKI1dlIGhhdmUgdmFyaW91cyBpbW11bmUgY2VsbCB0eXBlcyBpbiB0aGUgbGFzdCBjbHVzdGVyCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0xMH0KRG90UGxvdCh0aXNzMSwgYyhnZW5lc19rdXBwZmVyLCBnZW5lc19uaywgZ2VuZXNfYiwgIlB0cHJjIiksIHBsb3QubGVnZW5kID0gVCwgY29sLm1heCA9IDIuNSwgZG8ucmV0dXJuID0gVCkgKyBjb29yZF9mbGlwKCkKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CkRvdFBsb3QodGlzczEsIGMoZ2VuZXNfaGVwX21haW4sIGdlbmVzX2VuZG8sIGdlbmVzX25rLCBnZW5lc19rdXBwZmVyLCBnZW5lc19iZWNfYl9pbW11bmUpLCBwbG90LmxlZ2VuZCA9IFQsIGNvbC5tYXggPSAyLjUsIGRvLnJldHVybiA9IFQpICsgY29vcmRfZmxpcCgpCmBgYAoKVXNpbmcgdGhlIG1hcmtlcnMgYWJvdmUsIHdlIGNhbiBjb25maWRlbnRhbHkgbGFiZWwgbWFueSBvZiB0aGUgY2x1c3RlcnM6CgoxOTogZW5kb3RoZWxpYWwgY2VsbHMKMjA6IGJpbGUgZHVjdCBlcGl0aGVsaWFsIGNlbGxzCjIxOiBpbW11bmUgY2VsbHMKcmVzdCBhcmUgaGVwYXRvY3l0ZXMKCldlIHdpbGwgYWRkIHRob3NlIGNlbGxfb250b2xvZ3lfY2xhc3NlcyB0byB0aGUgZGF0YXNldC4KCmBgYHtyfQp0aXNzMSA8LSBTdGFzaElkZW50KG9iamVjdCA9IHRpc3MxLCBzYXZlLm5hbWUgPSAiY2x1c3Rlci5pZHMiKQpjbHVzdGVyLmlkcyA8LSBjKDAsMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgsMTksMjApCmZyZWVfYW5ub3RhdGlvbiA8LSBjKAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogIE5BLAogICJiaWxlIGR1Y3QgZXBpdGhlbGlhbCBjZWxscyIsCiAgImVuZG90aGVsaWFsIGNlbGwgb2YgaGVwYXRpYyBzaW51c29pZCIsCiAgTkEKICApCmNlbGxfb250b2xvZ3lfY2xhc3MgPC0gYygKICAiaGVwYXRvY3l0ZSIsCiAgImhlcGF0b2N5dGUiLAogICJoZXBhdG9jeXRlIiwKICAiaGVwYXRvY3l0ZSIsCiAgImhlcGF0b2N5dGUiLAogICJoZXBhdG9jeXRlIiwKICAiaGVwYXRvY3l0ZSIsCiAgImhlcGF0b2N5dGUiLAogICJoZXBhdG9jeXRlIiwKICAiaGVwYXRvY3l0ZSIsCiAgImhlcGF0b2N5dGUiLAogICJoZXBhdG9jeXRlIiwKICAiaGVwYXRvY3l0ZSIsCiAgImhlcGF0b2N5dGUiLAogICJoZXBhdG9jeXRlIiwKICAiaGVwYXRvY3l0ZSIsCiAgImhlcGF0b2N5dGUiLAogICJoZXBhdG9jeXRlIiwKICAiZHVjdCBlcGl0aGVsaWFsIGNlbGwiLAogICJlbmRvdGhlbGlhbCBjZWxsIG9mIGhlcGF0aWMgc2ludXNvaWQiLAogICJoZXBhdG9jeXRlIikKdGlzczEgPSBzdGFzaF9hbm5vdGF0aW9ucyh0aXNzMSwgY2x1c3Rlci5pZHMsIGZyZWVfYW5ub3RhdGlvbiwgY2VsbF9vbnRvbG9neV9jbGFzcykKYGBgCgojIyBDaGVja2luZyBmb3IgYmF0Y2ggZWZmZWN0cwoKQ29sb3IgYnkgbWV0YWRhdGEsIGxpa2UgcGxhdGUgYmFyY29kZSwgdG8gY2hlY2sgZm9yIGJhdGNoIGVmZmVjdHMuCmBgYHtyfQpUU05FUGxvdChvYmplY3QgPSB0aXNzMSwgZG8ucmV0dXJuID0gVFJVRSwgZ3JvdXAuYnkgPSAiY2hhbm5lbCIpClRTTkVQbG90KG9iamVjdCA9IHRpc3MxLCBkby5yZXR1cm4gPSBUUlVFLCBncm91cC5ieSA9ICJmcmVlX2Fubm90YXRpb24iKQoKYGBgCgojIyBTdWJjbHVzdGVyCgpMZXQncyBkcmlsbCBkb3duIG9uIHRoZSBoZXBhdG9jeXRlcy4KCmBgYHtyfQpzdWJ0aXNzMSA9IFN1YnNldERhdGEodGlzczEsIGlkZW50LnVzZSA9IGMoMCwxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywyMCkpCgoKYGBgCgpgYGB7cn0Kc3VidGlzczEgPC0gc3VidGlzczEgJT4lIFNjYWxlRGF0YSgpICU+JQogIEZpbmRWYXJpYWJsZUdlbmVzKGRvLnBsb3QgPSBGQUxTRSwgeC5oaWdoLmN1dG9mZiA9IEluZiwgeS5jdXRvZmYgPSAwLjUpICU+JQogIFJ1blBDQShkby5wcmludCA9IEZBTFNFKQpgYGAKCmBgYHtyfQpQQ0hlYXRtYXAob2JqZWN0ID0gc3VidGlzczEsIHBjLnVzZSA9IDE6MywgY2VsbHMudXNlID0gMjAsIGRvLmJhbGFuY2VkID0gVFJVRSwgbGFiZWwuY29sdW1ucyA9IEZBTFNFLCBudW0uZ2VuZXMgPSA4KQpQQ0VsYm93UGxvdChzdWJ0aXNzMSkKYGBgCgoKYGBge3J9CnN1Yi5uLnBjcyA9IDgKc3ViLnJlcy51c2UgPSAwLjUKc3VidGlzczEgPC0gc3VidGlzczEgJT4lIEZpbmRDbHVzdGVycyhyZWR1Y3Rpb24udHlwZSA9ICJwY2EiLCBkaW1zLnVzZSA9IDE6c3ViLm4ucGNzLAogICAgcmVzb2x1dGlvbiA9IHN1Yi5yZXMudXNlLCBwcmludC5vdXRwdXQgPSAwLCBzYXZlLlNOTiA9IFRSVUUsIGZvcmNlLnJlY2FsYyA9IFRSVUUpICU+JQogICAgUnVuVFNORShkaW1zLnVzZSA9IDE6c3ViLm4ucGNzLCBzZWVkLnVzZSA9IDEwLCBwZXJwbGV4aXR5PTgpClRTTkVQbG90KG9iamVjdCA9IHN1YnRpc3MxLCBkby5sYWJlbCA9IFQsIHB0LnNpemUgPSAxLCBsYWJlbC5zaXplID0gNCkKYGBgCgpgYGB7ciwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD0yNSwgZmlnLndpZHRoPTI1fQpGZWF0dXJlUGxvdChzdWJ0aXNzMSwgZ2VuZXNfaGVwLGNvbHMudXNlID0gYygiZ3JleSIsICJyZWQiKSwgcHQuc2l6ZSA9IDQsIG5Db2wgPSA0KQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KRG90UGxvdChzdWJ0aXNzMSwgYWxsX2dlbmVzLCBjb2wubWF4ID0gMi41LCBwbG90LmxlZ2VuZCA9IFQsIGRvLnJldHVybiA9IFQpICsgY29vcmRfZmxpcCgpCmBgYAoKYGBge3J9CkJ1aWxkQ2x1c3RlclRyZWUoc3VidGlzczEpCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD04fQojZmVtYWxlIGdlbmVzIGhhdmUgbG93ZXIgZXhwcmVzc2lvbiBpbiBjbHVzdGVyIDYgcmVsYXRpdmUgdG8gb3RoZXIgZmVtYWxlIGNsdXN0ZXJzLCBlc3BlY2FsbHkgWGlzdApGZWF0dXJlUGxvdChzdWJ0aXNzMSxjKCdNdXAyMCcsICdNdXAxJywnTXVwMTInLCAnTXVwMjEnLCAnQ3lwMmQ5JywgJ1hpc3QnLCAnQTFiZycsICdDeXAyYzY5JyksY29scy51c2UgPSBjKCJncmV5IiwgInJlZCIpLCBwdC5zaXplID0gMywgbkNvbCA9IDIpCgpEb3RQbG90KHRpc3MxLGMoJ011cDIwJywgJ011cDEnLCdNdXAxMicsICdNdXAyMScsICdDeXAyZDknLCAnWGlzdCcsICdBMWJnJywgJ0N5cDJjNjknKSwgcGxvdC5sZWdlbmQgPSBULCBjb2wubWF4ID0gMi41LCBkby5yZXR1cm4gPSBUKSArIGNvb3JkX2ZsaXAoKQoKYGBgCgoKRnJvbSB0aGVzZSBnZW5lcywgaXQgYXBwZWFycyB0aGF0IHRoZSBjbHVzdGVycyByZXByZXNlbnQ6CgowOiBtaWRsb2J1bGFyIG1hbGUKMTogcGVyaWNlbnRyYWwgZmVtYWxlCjI6IHBlcmlwb3J0YWwgZmVtYWxlCjM6IHBlcmlwb3J0YWwgbWFsZQo0OiBtaWRsb2J1bGFyIG1hbGUKNTogcGVyaWNlbnRyYWwgbWFsZQo2OiBtaWRsb2J1bGFyIGZlbWFsZQo3OiBtaWRsb2J1bGFyIGZlbWFsZQoKVGhlIG11bHRpdHVkZSBvZiBjbHVzdGVycyBvZiBlYWNoIHR5cGUgY29ycmVzcG9uZCBtb3N0bHkgdG8gaW5kaXZpZHVhbCBhbmltYWxzL3NleGVzLgoKYGBge3J9CnRhYmxlKEZldGNoRGF0YShzdWJ0aXNzMSwgYygnbW91c2Uuc2V4JywnaWRlbnQnKSkgJT4lIGRyb3BsZXZlbHMoKSkKYGBgCgpgYGB7cn0Kc3ViLmNsdXN0ZXIuaWRzIDwtIGMoMCwgMSwgMiwgMywgNCwgNSwgNiwgNykKc3ViLmZyZWVfYW5ub3RhdGlvbiA8LSBjKCJwZXJpcG9ydGFsIGZlbWFsZSIsICJtaWRsb2J1bGFyIG1hbGUiLCAicGVyaWNlbnRyYWwgZmVtYWxlIiwgInBlcmlwb3J0YWwgbWFsZSIsICJtaWRsb2J1bGFyIG1hbGUiLCAicGVyaWNlbnRyYWwgbWFsZSIsICJtaWRsb2J1bGFyIGZlbWFsZSIsICJtaWRsb2J1bGFyIGZlbWFsZSIpCnN1Yi5jZWxsX29udG9sb2d5X2NsYXNzIDwtIGMoImhlcGF0b2N5dGUiLCAiaGVwYXRvY3l0ZSIsICJoZXBhdG9jeXRlIiwgImhlcGF0b2N5dGUiLCAiaGVwYXRvY3l0ZSIsICJoZXBhdG9jeXRlIiwgImhlcGF0b2N5dGUiLCAiaGVwYXRvY3l0ZSIpCnN1YnRpc3MxID0gc3Rhc2hfYW5ub3RhdGlvbnMoc3VidGlzczEsIHN1Yi5jbHVzdGVyLmlkcywgc3ViLmZyZWVfYW5ub3RhdGlvbiwgc3ViLmNlbGxfb250b2xvZ3lfY2xhc3MpCnRpc3MxID0gc3Rhc2hfc3VidGlzc19pbl90aXNzKHRpc3MxLCBzdWJ0aXNzMSkKYGBgCgpMaXZlciB6b25hdGlvbiBtYXJrZXJzCgpgYGB7cn0KZ2VuZXNfem9uZXMgPSBjKCdDeXAyZTEnLCAnR2x1bCcsICdPYXQnLCAnR3VsbycsCiAgICAgICAgICAgICAgJ0FzczEnLCAnSGFtcCcsICdHc3RwMScsICdVYmInLAogICAgICAgICAgICAgICdDeXAyZjInLCAnUGNrMScsICdIYWwnLCAnQ2RoMScpCgpGZWF0dXJlUGxvdChzdWJ0aXNzMSxjKGdlbmVzX3pvbmVzKSxjb2xzLnVzZSA9IGMoImdyZXkiLCAicmVkIiksIHB0LnNpemUgPSAxLCBuQ29sID0gNCkKCkRvdFBsb3Qoc3VidGlzczEsYyhnZW5lc196b25lcyksIHBsb3QubGVnZW5kID0gVCwgY29sLm1heCA9IDIuNSwgZG8ucmV0dXJuID0gVCkgKyBjb29yZF9mbGlwKCkKCgpUU05FUGxvdChvYmplY3QgPSBzdWJ0aXNzMSwgZG8ubGFiZWwgPSBULCBwdC5zaXplID0gMSwgbGFiZWwuc2l6ZSA9IDQsIGdyb3VwLmJ5PSJmcmVlX2Fubm90YXRpb24iKQoKVFNORVBsb3Qob2JqZWN0ID0gdGlzczEsIGRvLmxhYmVsID0gVCwgcHQuc2l6ZSA9IDEsIGxhYmVsLnNpemUgPSA0LCBncm91cC5ieT0iZnJlZV9hbm5vdGF0aW9uIikKCmBgYAoKCgojIyMjIyMjIyMjCkZpbmQgY2x1c3RlciBtYXJrZXJzIGZvciBsbmNSTkFzCmBgYHtyfQoKTUlOX0xPR0ZPTERfQ0hBTkdFID0gMSAjIHNldCB0byBtaW5pbXVtIHJlcXVpcmVkIGF2ZXJhZ2UgbG9nIGZvbGQgY2hhbmdlIGluIGdlbmUgZXhwcmVzc2lvbi4KTUlOX1BDVF9DRUxMU19FWFBSX0dFTkUgPSAwLjEKCmFsbC5tYXJrZXJzID0gRmluZEFsbE1hcmtlcnModGlzczEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluLnBjdCA9IE1JTl9QQ1RfQ0VMTFNfRVhQUl9HRU5FLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IE1JTl9MT0dGT0xEX0NIQU5HRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVzdC51c2U9ImJpbW9kIikgIyBsaWtlbGlob29kIHJhdGlvIHRlc3QKbG5jX2FsbF9tYXJrZXJzIDwtIGdyZXAocGF0dGVybiA9ICJebmNSTkEiLCB4PSByb3duYW1lcyhhbGwubWFya2VycyksIHZhbHVlID0gVFJVRSkKbG5jX2FsbF9tYXJrZXJzCgojWzFdICJuY1JOQV9pbnRlcl9jaHIxMF85MjA4MSIgIm5jUk5BX2ludHJhX2NocjE2XzEzMzgzIiAibmNSTkFfaW50ZXJfY2hyMTdfMTM2MDUiICJuY1JOQV9pbnRlcl9jaHIxNF8xMTgxNSIKI1s1XSAibmNSTkFfaW50ZXJfY2hyMThfMTQzNDQiCgpGZWF0dXJlUGxvdChzdWJ0aXNzMSxjKGxuY19hbGxfbWFya2VycyksY29scy51c2UgPSBjKCJncmV5IiwgInJlZCIpLCBwdC5zaXplID0gMSwgbkNvbCA9IDQpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIGxuY1JOQSBtYXJrZXJzLSBDRUxMIFRZUEUgTUFSS0VSICMjIyMjIyMjIyMjIwptYXJrZXJzLmhlcCA8LSBGaW5kTWFya2VycyhvYmplY3QgPSB0aXNzMSwgaWRlbnQuMSA9IGMoMCwxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiwxMywxNCwxNSwxNiwxNywyMCksIGlkZW50LjIgPSBjKDE4LDE5KSxvbmx5LnBvcyA9IFRSVUUsIG1pbi5wY3QgPSAwLjI1LCB0aHJlc2gudXNlID0gMC4yNSkKbG5jX21hcmtlcnNfaGVwIDwtIGdyZXAocGF0dGVybiA9ICJebmNSTkEiLCB4PSByb3duYW1lcyhtYXJrZXJzLmhlcCksIHZhbHVlID0gVFJVRSkKbG5jX21hcmtlcnNfaGVwCkZlYXR1cmVQbG90KHRpc3MxLGMobG5jX21hcmtlcnNfaGVwKSxjb2xzLnVzZSA9IGMoImdyZXkiLCAicmVkIiksIHB0LnNpemUgPSAxLCBuQ29sID0gNCkKRG90UGxvdCh0aXNzMSxsbmNfbWFya2Vyc19oZXAsIHBsb3QubGVnZW5kID0gVCwgY29sLm1heCA9IDIuNSwgZG8ucmV0dXJuID0gVCkgKyBjb29yZF9mbGlwKCkKI1sxXSAibmNSTkFfYXNfY2hyMTFfOTQyMyIgICAgICJuY1JOQV9hc19jaHI3XzYxNjYiICAgICAgIm5jUk5BX2ludGVyX2NocjRfMzI5NSIgICAibmNSTkFfaW50ZXJfY2hyMTdfMTQwMjYiCiNbNV0gIm5jUk5BX2ludGVyX2NocjNfMjkxNSIgICAibmNSTkFfaW50ZXJfY2hyNV80NTQ3IiAgICJuY1JOQV9pbnRlcl9jaHIxNV8xMjY4NCIKCgptYXJrZXJzLmhlcC5NQVNUIDwtIEZpbmRNYXJrZXJzKG9iamVjdCA9IHRpc3MxLCBpZGVudC4xID0gYygwLDEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyLDEzLDE0LDE1LDE2LDE3LDIwKSwgaWRlbnQuMiA9IGMoMTgsMTkpLG9ubHkucG9zID0gVFJVRSwgdGVzdC51c2UgPSAiTUFTVCIpCmxuY19tYXJrZXJzX2hlcF9NQVNUX1RBQkxFIDwtIHN1YnNldChtYXJrZXJzLmhlcC5NQVNULCBncmVwbCgiXm5jUk5BIiwgcm93bmFtZXMobWFya2Vycy5oZXAuTUFTVCkpKQpsbmNfbWFya2Vyc19oZXBfTUFTVCA8LSBncmVwKHBhdHRlcm4gPSAiXm5jUk5BIiwgeD0gcm93bmFtZXMobWFya2Vycy5oZXAuTUFTVCksIHZhbHVlID0gVFJVRSkKbG5jX21hcmtlcnNfaGVwX01BU1QKCgoKbWFya2Vycy5lbmRvIDwtIEZpbmRNYXJrZXJzKG9iamVjdCA9IHRpc3MxLCBpZGVudC4xID0gYygxOCwxOSksICBvbmx5LnBvcyA9IFRSVUUsIG1pbi5wY3QgPSAwLjI1LCB0aHJlc2gudXNlID0gMC41KQpsbmNfbWFya2Vyc19lbmRvIDwtIGdyZXAocGF0dGVybiA9ICJebmNSTkEiLCB4PSByb3duYW1lcyhtYXJrZXJzLmVuZG8pLCB2YWx1ZSA9IFRSVUUpCmxuY19tYXJrZXJzX2VuZG8KRmVhdHVyZVBsb3QodGlzczEsYyhsbmNfbWFya2Vyc19lbmRvKSxjb2xzLnVzZSA9IGMoImdyZXkiLCAicmVkIiksIHB0LnNpemUgPSAxLCBuQ29sID0gNCkKRG90UGxvdCh0aXNzMSxsbmNfbWFya2Vyc19lbmRvLCBwbG90LmxlZ2VuZCA9IFQsIGNvbC5tYXggPSAyLjUsIGRvLnJldHVybiA9IFQpICsgY29vcmRfZmxpcCgpCgoKIyJuY1JOQV9pbnRlcl9jaHIxNV8xMjc3MCIsICJuY1JOQV9pbnRlcl9jaHIxMl8xMDgxNyIsICJuY1JOQV9hc19jaHIxM18xMTQ1MSIsCgoKbWFya2Vycy5lbmRvLk1BU1QgPC0gRmluZE1hcmtlcnMob2JqZWN0ID0gdGlzczEsIGlkZW50LjEgPSAxOSwgdGVzdC51c2UgPSAiTUFTVCIgLG9ubHkucG9zID0gVFJVRSkKbG5jX21hcmtlcnNfZW5kb19NQVNUX1RBQkxFIDwtIHN1YnNldChtYXJrZXJzLmVuZG8uTUFTVCwgZ3JlcGwoIl5uY1JOQSIsIHJvd25hbWVzKG1hcmtlcnMuZW5kby5NQVNUKSkpCmxuY19tYXJrZXJzX2VuZG9fTUFTVCA8LSBncmVwKHBhdHRlcm4gPSAiXm5jUk5BIiwgeD0gcm93bmFtZXMobWFya2Vycy5lbmRvLk1BU1QpLCB2YWx1ZSA9IFRSVUUpCmxuY19tYXJrZXJzX2VuZG9fTUFTVAoKCiMjIyMjIyMjIyMjIyMjIyMjIyBsbmNSTkEgZXhwcmVzc2lvbiAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMzCgojICJuY1JOQV9pbnRlcl9jaHIxN18xMzYwNSIgLCAibmNSTkFfaW50cmFfY2hyMTZfMTMzODMiCgojIyMjIyMjIyMjIFBlcmlwb3JhbCBtYXJrZXJzLSB6b25hdGlvbiBtYXJrZXJzICMjIyMjIyMjIyMjIwptYXJrZXJzLnBjIDwtIEZpbmRNYXJrZXJzKG9iamVjdCA9IHN1YnRpc3MxLCBpZGVudC4xID0gYygyLDUpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBGQUxTRSwgbWluLnBjdCA9IDAuMDAxLCB0aHJlc2gudXNlID0gMC4wMDEsIHRlc3QudXNlID0gImJpbW9kIiApCgptYXJrZXJzLnBjLk1BU1QgPC0gRmluZE1hcmtlcnMob2JqZWN0ID0gc3VidGlzczEsIGlkZW50LjEgPSBjKDIsNSksIGlkZW50LjIgPSBjKDAsMyksIHRlc3QudXNlID0gIk1BU1QiICxvbmx5LnBvcyA9IFRSVUUpCmxuY19tYXJrZXJzX3BjIDwtIHN1YnNldChtYXJrZXJzLnBjLCBncmVwbCgiXm5jUk5BIiwgcm93bmFtZXMobWFya2Vycy5wYykpKQpsbmNfbWFya2Vyc19wYyA8LSBncmVwKHBhdHRlcm4gPSAiXm5jUk5BIiwgeD0gcm93bmFtZXMobWFya2Vycy5wYyksIHZhbHVlID0gVFJVRSkKbG5jX21hcmtlcnNfcGMgCgptYXJrZXJzLnBjLk1BU1QgPC0gRmluZE1hcmtlcnMob2JqZWN0ID0gc3VidGlzczEsIGlkZW50LjEgPSBjKDIsNSksIGlkZW50LjIgPSBjKDAsMyksIHRlc3QudXNlID0gIk1BU1QiICxvbmx5LnBvcyA9IFRSVUUpCmxuY19tYXJrZXJzX3BjX01BU1QgPC0gc3Vic2V0KG1hcmtlcnMucGMuTUFTVCwgZ3JlcGwoIl5uY1JOQSIsIHJvd25hbWVzKG1hcmtlcnMucGMuTUFTVCkpKQpsbmNfbWFya2Vyc19wY19NQVNUIDwtIGdyZXAocGF0dGVybiA9ICJebmNSTkEiLCB4PSByb3duYW1lcyhtYXJrZXJzLnBjLk1BU1QpLCB2YWx1ZSA9IFRSVUUpCmxuY19tYXJrZXJzX3BjX01BU1QKCkRvdFBsb3QodGlzczEsIGxuY19tYXJrZXJzX3BjLCBwbG90LmxlZ2VuZCA9IFQsIGNvbC5tYXggPSAyLjUsIGRvLnJldHVybiA9IFQsIGdyb3VwLmJ5PSJmcmVlX2Fubm90YXRpb24iKSArIGNvb3JkX2ZsaXAoKQpGZWF0dXJlUGxvdChzdWJ0aXNzMSxjKGxuY19tYXJrZXJzX3BjKSxjb2xzLnVzZSA9IGMoImdyZXkiLCAicmVkIiksIHB0LnNpemUgPSAxLCBuQ29sID0gNCkKCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIG1pZGxvYnVsYXIgZ2VuZXMgIyMjIyMjIyMjIyMjIwoKbWFya2Vycy5taWQgPC0gRmluZE1hcmtlcnMob2JqZWN0ID0gc3VidGlzczEsIGlkZW50LjEgPSBjKDEsNCw2LDcpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBGQUxTRSwgbWluLnBjdCA9IDAuMDAxLCB0aHJlc2gudXNlID0gMC4wNSkKCmxuY19tYXJrZXJzX21pZCA8LSBzdWJzZXQobWFya2Vycy5taWQsIGdyZXBsKCJebmNSTkEiLCByb3duYW1lcyhtYXJrZXJzLm1pZCkpKQpsbmNfbWFya2Vyc19taWQgPC0gZ3JlcChwYXR0ZXJuID0gIl5uY1JOQSIsIHg9IHJvd25hbWVzKG1hcmtlcnMubWlkKSwgdmFsdWUgPSBUUlVFKQpsbmNfbWFya2Vyc19taWQKRG90UGxvdCh0aXNzMSwgbG5jX21hcmtlcnNfbWlkLCBwbG90LmxlZ2VuZCA9IFQsIGNvbC5tYXggPSAyLjUsIGRvLnJldHVybiA9IFQsIGdyb3VwLmJ5PSJmcmVlX2Fubm90YXRpb24iKSArIGNvb3JkX2ZsaXAoKQoKCkZlYXR1cmVQbG90KHN1YnRpc3MxLGMobG5jX21hcmtlcnNfbWlkKSxjb2xzLnVzZSA9IGMoImdyZXkiLCAicmVkIiksIHB0LnNpemUgPSAxLCBuQ29sID0gNCkKCgoKbWFya2Vycy5taWQuTUFTVCA8LSBGaW5kTWFya2VycyhvYmplY3QgPSBzdWJ0aXNzMSwgaWRlbnQuMSA9IGMoMSw0LDYsNyksdGVzdC51c2UgPSAiTUFTVCIsb25seS5wb3MgPSBUUlVFICkKCmxuY19tYXJrZXJzX21pZF9NQVNUX1RBQkxFIDwtIHN1YnNldChtYXJrZXJzLm1pZC5NQVNULCBncmVwbCgiXm5jUk5BIiwgcm93bmFtZXMobWFya2Vycy5taWQuTUFTVCkpKQpsbmNfbWFya2Vyc19taWRfTUFTVCA8LSBncmVwKHBhdHRlcm4gPSAiXm5jUk5BIiwgeD0gcm93bmFtZXMobWFya2Vycy5taWQuTUFTVCksIHZhbHVlID0gVFJVRSkKbG5jX21hcmtlcnNfbWlkX01BU1QKCgojIyMjIzMgcGVyaXBvcnRhbG1hcmtlciBnZW5lcyMjIyMjIyMjIyMjIzMKCm1hcmtlcnMucHAgPC0gRmluZE1hcmtlcnMob2JqZWN0ID0gc3VidGlzczEsIGlkZW50LjEgPSBjKDAsMyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gRkFMU0UsIG1pbi5wY3QgPSAwLjAwMSwgdGhyZXNoLnVzZSA9IDAuMDUpCgoKbG5jX21hcmtlcnNfcHAgPC0gc3Vic2V0KG1hcmtlcnMucHAsIGdyZXBsKCJebmNSTkEiLCByb3duYW1lcyhtYXJrZXJzLnBwKSkpCmxuY19tYXJrZXJzX3BwIDwtIGdyZXAocGF0dGVybiA9ICJebmNSTkEiLCB4PSByb3duYW1lcyhtYXJrZXJzLnBwKSwgdmFsdWUgPSBUUlVFKQpsbmNfbWFya2Vyc19wcAoKbWFya2Vycy5wcC5NQVNUIDwtIEZpbmRNYXJrZXJzKG9iamVjdCA9IHN1YnRpc3MxLCBpZGVudC4xID0gYygwLDMpLCBpZGVudC4yID0gYygyLDUpLHRlc3QudXNlID0gIk1BU1QiLG9ubHkucG9zID0gVFJVRSApCgpsbmNfbWFya2Vyc19wcF9NQVNUX1RBQkxFIDwtIHN1YnNldChtYXJrZXJzLnBwLk1BU1QsIGdyZXBsKCJebmNSTkEiLCByb3duYW1lcyhtYXJrZXJzLnBwLk1BU1QpKSkKbG5jX21hcmtlcnNfcHBfTUFTVCA8LSBncmVwKHBhdHRlcm4gPSAiXm5jUk5BIiwgeD0gcm93bmFtZXMobWFya2Vycy5wcC5NQVNUKSwgdmFsdWUgPSBUUlVFKQpsbmNfbWFya2Vyc19wcF9NQVNUCgpGZWF0dXJlUGxvdChzdWJ0aXNzMSxjKGxuY19tYXJrZXJzX3BwKSxjb2xzLnVzZSA9IGMoImdyZXkiLCAicmVkIiksIHB0LnNpemUgPSAxLCBuQ29sID0gNCwgbWF4LmN1dG9mZiA9IDEpCkRvdFBsb3QodGlzczEsIGMobG5jX21hcmtlcnNfcHAsIkN5cDJlMSIsIkN5cDJmMiIpLCBwbG90LmxlZ2VuZCA9IFQsIGNvbC5tYXggPSAyLjUsIGRvLnJldHVybiA9IFQsIGdyb3VwLmJ5PSAiZnJlZV9hbm5vdGF0aW9uIikgKyBjb29yZF9mbGlwKCkKCgojIyMjIyMjIyMjIyMjIyMjIyMgYW1sZSBhbmQgZmVtYWxlIHNwZWNpZmljICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCm1hcmtlcnMuZmVtYWxlIDwtIEZpbmRNYXJrZXJzKG9iamVjdCA9IHN1YnRpc3MxLCBpZGVudC4xID0gYygwLDIsNiw3KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCBtaW4ucGN0ID0gMC4xLCBsb2dmYy50aHJlc2hvbGQgPSAxKQoKbG5jX21hcmtlcnNfZmVtYWxlIDwtIHN1YnNldChtYXJrZXJzLmZlbWFsZSwgZ3JlcGwoIl5uY1JOQSIsIHJvd25hbWVzKG1hcmtlcnMuZmVtYWxlKSkpCmxuY19tYXJrZXJzX2ZlbWFsZSA8LSBncmVwKHBhdHRlcm4gPSAiXm5jUk5BIiwgeD0gcm93bmFtZXMobWFya2Vycy5mZW1hbGUpLCB2YWx1ZSA9IFRSVUUpCmxuY19tYXJrZXJzX2ZlbWFsZQoKRmVhdHVyZVBsb3Qoc3VidGlzczEsYyhsbmNfbWFya2Vyc19mZW1hbGUpLGNvbHMudXNlID0gYygiZ3JleSIsICJyZWQiKSwgcHQuc2l6ZSA9IDEsIG5Db2wgPSA0LCBtYXguY3V0b2ZmID0gMSkKRG90UGxvdCh0aXNzMSwgYyhsbmNfbWFya2Vyc19mZW1hbGUsIkN5cDJlMSIsIkN5cDJmMiIpLCBwbG90LmxlZ2VuZCA9IFQsIGNvbC5tYXggPSAyLjUsIGRvLnJldHVybiA9IFQsIGdyb3VwLmJ5PSAiZnJlZV9hbm5vdGF0aW9uIikgKyBjb29yZF9mbGlwKCkKCgoKbWFya2Vycy5tYWxlIDwtIEZpbmRNYXJrZXJzKG9iamVjdCA9IHN1YnRpc3MxLCBpZGVudC4xID0gYygxLDMsNCw1KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCBtaW4ucGN0ID0gMC4wMDEsIHRocmVzaC51c2UgPSAwLjA1KQoKbG5jX21hcmtlcnNfbWFsZSA8LSBzdWJzZXQobWFya2Vycy5tYWxlLCBncmVwbCgiXm5jUk5BIiwgcm93bmFtZXMobWFya2Vycy5tYWxlKSkpCmxuY19tYXJrZXJzX21hbGUgPC0gZ3JlcChwYXR0ZXJuID0gIl5uY1JOQSIsIHg9IHJvd25hbWVzKG1hcmtlcnMubWFsZSksIHZhbHVlID0gVFJVRSkKbG5jX21hcmtlcnNfbWFsZQoKRmVhdHVyZVBsb3Qoc3VidGlzczEsYyhsbmNfbWFya2Vyc19tYWxlKSxjb2xzLnVzZSA9IGMoImdyZXkiLCAicmVkIiksIHB0LnNpemUgPSAxLCBuQ29sID0gNCwgbWF4LmN1dG9mZiA9IDEpCkRvdFBsb3QodGlzczEsIGMobG5jX21hcmtlcnNfbWFsZSwiQ3lwMmUxIiwiQ3lwMmYyIiksIHBsb3QubGVnZW5kID0gVCwgY29sLm1heCA9IDIuNSwgZG8ucmV0dXJuID0gVCwgZ3JvdXAuYnk9ICJmcmVlX2Fubm90YXRpb24iKSArIGNvb3JkX2ZsaXAoKQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMgRmVtYWxlIHpvbmF0ZSBzcGVjaWZpYyBnZW5lcyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKbWFya2Vycy5wZXJpY2VudHJhbC5mZW1hbGUgPC0gRmluZE1hcmtlcnMob2JqZWN0ID0gdGlzczEsIGlkZW50LjEgPSBjKDYsMTEsMTQsMjApLCB0ZXN0LnVzZSA9ICJNQVNUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMSwgaWRlbnQuMiA9IGMoMiwzLDE1LDEyLDEzLDgsNSwxNiksIGxvZ2ZjLnRocmVzaG9sZCA9IDEpCgptYXJrZXJzLnBlcmlwb3J0YWwuZmVtYWxlIDwtIEZpbmRNYXJrZXJzKG9iamVjdCA9IHRpc3MxLCBpZGVudC4xID0gYygyLDMsMTUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCBtaW4ucGN0ID0gMC4xLCBpZGVudC4yID0gYyg2LDExLDE0LDIwLDEyLDEzLDgsNSwxNiksIGxvZ2ZjLnRocmVzaG9sZCA9IDEpCgoKbWFya2Vycy5wZXJpY2VudHJhbC5tYWxlIDwtIEZpbmRNYXJrZXJzKG9iamVjdCA9IHRpc3MxLCBpZGVudC4xID0gYygxMywxMiksIHRlc3QudXNlID0gIk1BU1QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgb25seS5wb3MgPSBUUlVFLCBtaW4ucGN0ID0gMC4xLCBpZGVudC4yID0gYygyLDMsMTUsOCw1LDE2LDYsMTEsMTQsMjApLCBsb2dmYy50aHJlc2hvbGQgPSAxKQoKCm1hcmtlcnMucGVyaXBvcnRhbC5tYWxlIDwtIEZpbmRNYXJrZXJzKG9iamVjdCA9IHRpc3MxLCBpZGVudC4xID0gYyg4LDUsMTYpLCB0ZXN0LnVzZSA9ICJNQVNUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMSwgaWRlbnQuMiA9IGMoMiwzLDE1LDEzLDEyLDYsMTEsMTQsMjApLCBsb2dmYy50aHJlc2hvbGQgPSAxKQoKCgoKIyMjIyMjIyMjIyMjIyMjIHhlbm8tbG5jcyBDQVI/UlhSICMjIyMjIyMjIyMjIyMjIyMjIwoKRmVhdHVyZVBsb3QodGlzczEsYygibmNSTkFfaW50ZXJfY2hyMTVfMTI2ODQiLCJuY1JOQV9pbnRlcl9jaHI4Xzc0MzAiLCJuY1JOQV9pbnRlcl9jaHI3XzYyMjIiKSxjb2xzLnVzZSA9IGMoImdyZXkiLCAicmVkIiksIHB0LnNpemUgPSAxLCBuQ29sID0gNCwgbWF4LmN1dG9mZiA9IDEpCgoKCgoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgptYXJrZXJzLmVuZG8uMiA8LSBGaW5kTWFya2VycyhvYmplY3QgPSBzZXVyYXRfZHJvcCwgbG9nZmMudGhyZXNob2xkID0gMixpZGVudC4xID0gIkVuZG90aGVsaWFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ubHkucG9zID0gVFJVRSwgbWluLnBjdCA9IDAuMjUsIHRocmVzaC51c2UgPSAwLjI1KQoKbG5jLmVuZG8uMiA8LSBncmVwKHBhdHRlcm4gPSAiXm5jUk5BIiwgeD0gcm93bmFtZXMobWFya2Vycy5lbmRvLjIpLCB2YWx1ZSA9IFRSVUUpCmxuYy5lbmRvLjIKCgoKCgpgYGAKCgoKWm9uYXRlZCBsbmNSTkFzIAoKYGBge3J9CnBwX3pvbnRhZWQgPC0gYygnbmNSTkFfaW50ZXJfY2hyMTRfMTIwMTYnLCduY1JOQV9hc19jaHIxOV8xNTA5MCcsJ25jUk5BX2ludGVyX2NocjEwXzkzNTEnLCduY1JOQV9pbnRlcl9jaHIxNl8xMzE3MCcsCiduY1JOQV9pbnRlcl9jaHIzXzI2OTcnLCduY1JOQV9pbnRlcl9jaHIxXzI3NCcsJ25jUk5BX2FzX2NocjZfNTUxOCcsJ25jUk5BX2ludGVyX2NocjE0XzEyMDY2JywnbmNSTkFfaW50cmFfY2hyMTJfMTA4NzEnLAonbmNSTkFfaW50ZXJfY2hyMTZfMTM1MTAnLCduY1JOQV9pbnRlcl9jaHIzXzIzMTQnLCduY1JOQV9pbnRlcl9jaHIxMF85MjY0LCduY1JOQV9pbnRlcl9jaHI5XzgxMjInKQoKCgoKCmBgYAoKIyMgQ2hlY2tpbmcgZm9yIGJhdGNoIGVmZmVjdHMKCkNvbG9yIGJ5IG1ldGFkYXRhLCBsaWtlIHBsYXRlIGJhcmNvZGUsIHRvIGNoZWNrIGZvciBiYXRjaCBlZmZlY3RzLgpgYGB7cn0KVFNORVBsb3Qob2JqZWN0ID0gc3VidGlzczEsIGRvLnJldHVybiA9IFRSVUUsIGdyb3VwLmJ5ID0gIm1vdXNlLnNleCIpCgpgYGAKCiMgRmluYWwgY29sb3JpbmcKCkNvbG9yIGJ5IGNlbGwgb250b2xvZ3kgY2xhc3Mgb24gdGhlIG9yaWdpbmFsIFRTTkUuCgpgYGB7cn0KVFNORVBsb3Qob2JqZWN0ID0gdGlzczEsIGRvLnJldHVybiA9IFRSVUUsIGdyb3VwLmJ5ID0gImNlbGxfb250b2xvZ3lfY2xhc3MiKQpgYGAKCiMgU2F2ZSB0aGUgUm9iamVjdCBmb3IgbGF0ZXIKCmBgYHtyfQpmaWxlbmFtZSA9IGhlcmUoJzAwX2RhdGFfaW5nZXN0JywgJzA0X3Rpc3MxdWVfcm9ial9nZW5lcmF0ZWQnLCAKICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJkcm9wbGV0XyIsIHRpc3MxdWVfb2ZfaW50ZXJlc3QsICJyZWZpbmVkY2VsbHNfc2V1cmF0X3Rpc3MxLlJvYmoiKSkKcHJpbnQoZmlsZW5hbWUpCnNhdmUodGlzczEsIGZpbGU9ZmlsZW5hbWUpCmBgYAoKYGBge3J9CiMgVG8gcmVsb2FkIGEgc2F2ZWQgb2JqZWN0CmZpbGVuYW1lID0gaGVyZSgnMDBfZGF0YV9pbmdlc3QnLCAnMDRfdGlzczF1ZV9yb2JqX2dlbmVyYXRlZCcsCiAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoImRyb3BsZXRfIiwgdGlzc3VlX29mX2ludGVyZXN0LCAic2V1cmF0X3NtYXJ0ZHJvcC1pbnRlZ3JhdGVkLTgyNzIwMTkuUm9iaiIpKQpsb2FkKGZpbGU9ZmlsZW5hbWUpCmBgYAoKCiMgRXhwb3J0IHRoZSBmaW5hbCBtZXRhZGF0YQoKCmBgYHtyfQpzYXZlX2Fubm90YXRpb25fY3N2KHRpc3MxLCB0aXNzMXVlX29mX2ludGVyZXN0LCAiZHJvcGxldCIpCmBgYAo=