library(Seurat)
library(SeuratWrappers)
library(monocle)
library(monocle3)
library(ggplot2)
options(repr.plot.width=9, repr.plot.height=6)
ggplot(seu@meta.data, aes(nCount_RNA, nFeature_RNA)) +
geom_hex(bins = 100) +
scale_fill_scico(palette = "devon", direction = -1, end = 0.9) +
scale_x_log10(breaks = breaks_log(12)) +
scale_y_log10(breaks = breaks_log(12)) + annotation_logticks() +
labs(x = "Total UMI counts", y = "Number of genes detected") +
theme(panel.grid.minor = element_blank())
#mitochondrial percentages
ggplot(seu@meta.data, aes(nCount_RNA, percent.mt)) +
geom_pointdensity() +
scale_color_scico(palette = "devon", direction = -1, end = 0.9) +
labs(x = "Total UMI counts", y = "Percentage mitochondrial")
# set up list of canonical cell type markers
canonical_markers <- list(
'Astrocyte' = c('GFAP', 'AQP4', 'SLC1A2'),
'Pan-neuronal' = c('SNAP25', 'SYT1'),
'Excitatory Neuron' = c('SLC17A7', 'SATB2'),
'Inhibitory Neuron' = c('GAD1', 'GAD2'),
'Microglia' = c('CSF1R', 'CD74', 'P2RY12'),
'Oligodendrocyte' = c('MOBP', 'MBP', 'MOG'),
'Olig. Progenitor' = c('PDGFRA', 'CSPG4')
)
# plot heatmap:
library(viridis)
png('figures/basic_canonical_marker_heatmap.png', width=10, height=10, units='in', res=200)
DoHeatmap(seurat_obj, group.by ="seurat_clusters", features=as.character(unlist(canonical_markers))) # + scale_fill_gradientn(colors=viridis(256))
dev.off()
# create feature plots, cutoff expression values for the 98th and 99th percentile
plot_list <- FeaturePlot(
seurat_obj,
features=unlist(canonical_markers),
combine=FALSE, cols=viridis(256),
max.cutoff='q98'
)
# apply theme to each feature plot
for(i in 1:length(plot_list)){
plot_list[[i]] <- plot_list[[i]] + umap_theme + NoLegend()
}
png('figures/basic_canonical_marker_featurePlot.png', width=10, height=10, units='in', res=200)
CombinePlots(plot_list)
dev.off()
for(celltype in names(canonical_markers)){
print(celltype)
cur_features <- canonical_markers[[celltype]]
# plot distributions for marker genes:
p <- VlnPlot(
seurat_obj,
group.by='seurat_clusters',
features=cur_features,
pt.size = 0, ncol=1
)
png(paste0('figures/basic_canonical_marker_',celltype,'_vlnPlot.png'), width=10, height=3*length(cur_features), units='in', res=200)
print(p)
dev.off()
}
# add barcode and UMAP to metadata
seurat_obj$barcode <- colnames(seurat_obj)
seurat_obj$UMAP_1 <- seurat_obj@reductions$umap@cell.embeddings[,1]
seurat_obj$UMAP_2 <- seurat_obj@reductions$umap@cell.embeddings[,2]
# save seurat object
saveRDS(seurat_obj, file='data/processed_seurat_object.rds')
# load seurat object
seurat_obj <- readRDS(ile='data/processed_seurat_object.rds')
library(Seurat)
library(tidyverse)
library(Matrix)
library(cowplot)
theme_set(theme_cowplot())
data_dir <- '/dfs3/swaruplab/smorabit/analysis/cross-disorder/data/trem2_nmed/'
files <- dir(data_dir)
files <- files[grepl('matrix', files)]
file_stems <- str_replace_all(files, '_matrix.mtx', '')
# construct a list of seurat objects for each sample by iteratively loading each file
seurat_list <- lapply(file_stems, function(file){
print(file)
X <- readMM(paste0(data_dir,file,'_matrix.mtx'))
genes <- read.csv(file=paste0(data_dir,file,'_features.tsv'), sep='\t', header=FALSE)
barcodes <- read.csv(file=paste0(data_dir,file,'_barcodes.tsv'), sep='\t', header=FALSE)
colnames(X) <- barcodes$V1
rownames(X) <- genes$V2
cur_seurat <- CreateSeuratObject(
counts = X,
project = "tutorial"
)
cur_seurat@meta.data$SampleID <- file
cur_seurat
})
# merge into one big seurat object
seurat_obj <- merge(x=seurat_list[[1]], y=seurat_list[2:length(seurat_list)])
# add metadata
meta <- read.csv(paste0(data_dir, 'meta.csv'))
rownames(meta) <- meta$Sample.ID.in.snRNA.seq
meta.data <- meta[seurat_obj$SampleID,]
for(m in names(meta.data)){
seurat_obj@meta.data[[m]] <- meta.data[[m]]
}
# remove individual seurat objects to save memory
rm(seurat_list); gc();
# use table function to get the number of cells in each Sample as a dataframe
df <- as.data.frame(rev(table(seurat_obj$SampleID)))
colnames(df) <- c('SampleID', 'n_cells')
# bar plot of the number of cells in each sample
p <- ggplot(df, aes(y=n_cells, x=reorder(SampleID, -n_cells), fill=SampleID)) +
geom_bar(stat='identity') +
scale_y_continuous(expand = c(0,0)) +
NoLegend() + RotatedAxis() +
ylab(expression(italic(N)[cells])) + xlab('Sample ID') +
ggtitle(paste('Total cells:', sum(df$n_cells))) +
theme(
panel.grid.minor=element_blank(),
panel.grid.major.y=element_line(colour="lightgray", size=0.5),
)
png('figures/basic_cells_per_sample.png', width=9, height=4, res=200, units='in')
print(p)
dev.off()
# plot the number of DEGs per cluster:
df <- as.data.frame(rev(table(cluster_markers$CellType_cluster)))
colnames(df) <- c('cluster', 'n_DEGs')
# bar plot of the number of cells in each sample
p <- ggplot(df, aes(y=n_DEGs, x=reorder(cluster, -n_DEGs), fill=cluster)) +
geom_bar(stat='identity') +
scale_y_continuous(expand = c(0,0)) +
NoLegend() + RotatedAxis() +
ylab(expression(italic(N)[DEGs])) + xlab('') +
theme(
panel.grid.minor=element_blank(),
panel.grid.major.y=element_line(colour="lightgray", size=0.5),
)
png('figures/basic_DEGs_barplot.png', width=9, height=4, res=300, units='in')
print(p)
dev.off()
# plot the top 3 DEGs per cluster as a heatmap:
top_DEGs <- cluster_markers %>%
group_by(CellType_cluster) %>%
top_n(3, wt=avg_logFC) %>%
.$gene
png('figures/basic_DEGs_heatmap.png', width=10, height=10, res=300, units='in')
pdf('figures/basic_DEGs_heatmap.pdf', width=15, height=12, useDingbats=FALSE)
DoHeatmap(seurat_obj, features=top_DEGs, group.by='seurat_clusters', label=FALSE) + scale_fill_gradientn(colors=viridis(256)) + NoLegend()
dev.off()
cds <- cluster_cells(cds)
plot_cells(cds, color_cells_by = "partition", group_cells_by = "partition",
group_label_size = 4)
#monocle plot cells
plot_cells(cds, reduction_method = "PCA",
color_cells_by = "cell_type", group_label_size = 3.5,
label_groups_by_cluster = FALSE) +
scale_color_d3(palette = "category20b")
# Seed for random initiation of UMAP
set.seed(4837)
cds <- reduce_dimension(cds, reduction_method = "UMAP", preprocess_method = "PCA", init = "random")
plot_cells(cds, color_cells_by = "cell_type", group_label_size = 3.5,
label_groups_by_cluster = FALSE) +
scale_color_d3(palette = "category20b")
plot_cells(cds, color_cells_by = "cluster", group_cells_by = "cluster",
group_label_size = 4)
#Monocle 3’s trajectory inference is inspired by PAGA.
cds <- learn_graph(cds, verbose = FALSE,
learn_graph_control = list(minimal_branch_len = 7,
geodesic_distance_ratio = 0.5))
plot_cells(cds, color_cells_by = "cell_type", label_groups_by_cluster = FALSE,
group_label_size = 3.5, graph_label_size = 2) +
scale_color_d3(palette = "category20b")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQotLS0KdGl0bGU6ICJiYXNpY3MgZm9yIG1vbm9jbGUgYW5kIHNldXJhdCBiYXNlZCBwbG90cyIKb3V0cHV0OgogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKLS0tCmBgYHtyfQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShTZXVyYXRXcmFwcGVycykKbGlicmFyeShtb25vY2xlKQpsaWJyYXJ5KG1vbm9jbGUzKQpsaWJyYXJ5KGdncGxvdDIpCgpvcHRpb25zKHJlcHIucGxvdC53aWR0aD05LCByZXByLnBsb3QuaGVpZ2h0PTYpCmdncGxvdChzZXVAbWV0YS5kYXRhLCBhZXMobkNvdW50X1JOQSwgbkZlYXR1cmVfUk5BKSkgKwogIGdlb21faGV4KGJpbnMgPSAxMDApICsKICBzY2FsZV9maWxsX3NjaWNvKHBhbGV0dGUgPSAiZGV2b24iLCBkaXJlY3Rpb24gPSAtMSwgZW5kID0gMC45KSArCiAgc2NhbGVfeF9sb2cxMChicmVha3MgPSBicmVha3NfbG9nKDEyKSkgKyAKICBzY2FsZV95X2xvZzEwKGJyZWFrcyA9IGJyZWFrc19sb2coMTIpKSArIGFubm90YXRpb25fbG9ndGlja3MoKSArCiAgbGFicyh4ID0gIlRvdGFsIFVNSSBjb3VudHMiLCB5ID0gIk51bWJlciBvZiBnZW5lcyBkZXRlY3RlZCIpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQpgYGAKYGBge3J9CiNtaXRvY2hvbmRyaWFsIHBlcmNlbnRhZ2VzCmdncGxvdChzZXVAbWV0YS5kYXRhLCBhZXMobkNvdW50X1JOQSwgcGVyY2VudC5tdCkpICsKICBnZW9tX3BvaW50ZGVuc2l0eSgpICsKICBzY2FsZV9jb2xvcl9zY2ljbyhwYWxldHRlID0gImRldm9uIiwgZGlyZWN0aW9uID0gLTEsIGVuZCA9IDAuOSkgKwogIGxhYnMoeCA9ICJUb3RhbCBVTUkgY291bnRzIiwgeSA9ICJQZXJjZW50YWdlIG1pdG9jaG9uZHJpYWwiKQpgYGAKCmBgYHtyfQojIHNldCB1cCBsaXN0IG9mIGNhbm9uaWNhbCBjZWxsIHR5cGUgbWFya2VycwpjYW5vbmljYWxfbWFya2VycyA8LSBsaXN0KAogICdBc3Ryb2N5dGUnID0gYygnR0ZBUCcsICdBUVA0JywgJ1NMQzFBMicpLAogICdQYW4tbmV1cm9uYWwnID0gYygnU05BUDI1JywgJ1NZVDEnKSwKICAnRXhjaXRhdG9yeSBOZXVyb24nID0gYygnU0xDMTdBNycsICdTQVRCMicpLAogICdJbmhpYml0b3J5IE5ldXJvbicgPSBjKCdHQUQxJywgJ0dBRDInKSwKICAnTWljcm9nbGlhJyA9IGMoJ0NTRjFSJywgJ0NENzQnLCAnUDJSWTEyJyksCiAgJ09saWdvZGVuZHJvY3l0ZScgPSBjKCdNT0JQJywgJ01CUCcsICdNT0cnKSwKICAnT2xpZy4gUHJvZ2VuaXRvcicgPSBjKCdQREdGUkEnLCAnQ1NQRzQnKQopCgojIHBsb3QgaGVhdG1hcDoKbGlicmFyeSh2aXJpZGlzKQpwbmcoJ2ZpZ3VyZXMvYmFzaWNfY2Fub25pY2FsX21hcmtlcl9oZWF0bWFwLnBuZycsIHdpZHRoPTEwLCBoZWlnaHQ9MTAsIHVuaXRzPSdpbicsIHJlcz0yMDApCkRvSGVhdG1hcChzZXVyYXRfb2JqLCBncm91cC5ieSA9InNldXJhdF9jbHVzdGVycyIsIGZlYXR1cmVzPWFzLmNoYXJhY3Rlcih1bmxpc3QoY2Fub25pY2FsX21hcmtlcnMpKSkgIyArIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz12aXJpZGlzKDI1NikpCmRldi5vZmYoKQoKIyBjcmVhdGUgZmVhdHVyZSBwbG90cywgY3V0b2ZmIGV4cHJlc3Npb24gdmFsdWVzIGZvciB0aGUgOTh0aCBhbmQgOTl0aCBwZXJjZW50aWxlCnBsb3RfbGlzdCA8LSBGZWF0dXJlUGxvdCgKICBzZXVyYXRfb2JqLAogIGZlYXR1cmVzPXVubGlzdChjYW5vbmljYWxfbWFya2VycyksCiAgY29tYmluZT1GQUxTRSwgY29scz12aXJpZGlzKDI1NiksCiAgbWF4LmN1dG9mZj0ncTk4JwopCgojIGFwcGx5IHRoZW1lIHRvIGVhY2ggZmVhdHVyZSBwbG90CmZvcihpIGluIDE6bGVuZ3RoKHBsb3RfbGlzdCkpewogIHBsb3RfbGlzdFtbaV1dIDwtIHBsb3RfbGlzdFtbaV1dICsgdW1hcF90aGVtZSArIE5vTGVnZW5kKCkKfQoKcG5nKCdmaWd1cmVzL2Jhc2ljX2Nhbm9uaWNhbF9tYXJrZXJfZmVhdHVyZVBsb3QucG5nJywgd2lkdGg9MTAsIGhlaWdodD0xMCwgdW5pdHM9J2luJywgcmVzPTIwMCkKQ29tYmluZVBsb3RzKHBsb3RfbGlzdCkKZGV2Lm9mZigpCmZvcihjZWxsdHlwZSBpbiBuYW1lcyhjYW5vbmljYWxfbWFya2VycykpewoKICBwcmludChjZWxsdHlwZSkKICBjdXJfZmVhdHVyZXMgPC0gY2Fub25pY2FsX21hcmtlcnNbW2NlbGx0eXBlXV0KCiAgIyBwbG90IGRpc3RyaWJ1dGlvbnMgZm9yIG1hcmtlciBnZW5lczoKICBwIDwtIFZsblBsb3QoCiAgICBzZXVyYXRfb2JqLAogICAgZ3JvdXAuYnk9J3NldXJhdF9jbHVzdGVycycsCiAgICBmZWF0dXJlcz1jdXJfZmVhdHVyZXMsCiAgICBwdC5zaXplID0gMCwgbmNvbD0xCiAgKQogIHBuZyhwYXN0ZTAoJ2ZpZ3VyZXMvYmFzaWNfY2Fub25pY2FsX21hcmtlcl8nLGNlbGx0eXBlLCdfdmxuUGxvdC5wbmcnKSwgd2lkdGg9MTAsIGhlaWdodD0zKmxlbmd0aChjdXJfZmVhdHVyZXMpLCB1bml0cz0naW4nLCByZXM9MjAwKQogIHByaW50KHApCiAgZGV2Lm9mZigpCgp9CmBgYAoKCmBgYHtyfQojIGFkZCBiYXJjb2RlIGFuZCBVTUFQIHRvIG1ldGFkYXRhCnNldXJhdF9vYmokYmFyY29kZSA8LSBjb2xuYW1lcyhzZXVyYXRfb2JqKQpzZXVyYXRfb2JqJFVNQVBfMSA8LSBzZXVyYXRfb2JqQHJlZHVjdGlvbnMkdW1hcEBjZWxsLmVtYmVkZGluZ3NbLDFdCnNldXJhdF9vYmokVU1BUF8yIDwtIHNldXJhdF9vYmpAcmVkdWN0aW9ucyR1bWFwQGNlbGwuZW1iZWRkaW5nc1ssMl0KCiMgc2F2ZSBzZXVyYXQgb2JqZWN0CnNhdmVSRFMoc2V1cmF0X29iaiwgZmlsZT0nZGF0YS9wcm9jZXNzZWRfc2V1cmF0X29iamVjdC5yZHMnKQoKIyBsb2FkIHNldXJhdCBvYmplY3QKc2V1cmF0X29iaiA8LSByZWFkUkRTKGlsZT0nZGF0YS9wcm9jZXNzZWRfc2V1cmF0X29iamVjdC5yZHMnKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoTWF0cml4KQpsaWJyYXJ5KGNvd3Bsb3QpCnRoZW1lX3NldCh0aGVtZV9jb3dwbG90KCkpCgpkYXRhX2RpciA8LSAnL2RmczMvc3dhcnVwbGFiL3Ntb3JhYml0L2FuYWx5c2lzL2Nyb3NzLWRpc29yZGVyL2RhdGEvdHJlbTJfbm1lZC8nCmZpbGVzIDwtIGRpcihkYXRhX2RpcikKZmlsZXMgPC0gZmlsZXNbZ3JlcGwoJ21hdHJpeCcsIGZpbGVzKV0KZmlsZV9zdGVtcyA8LSBzdHJfcmVwbGFjZV9hbGwoZmlsZXMsICdfbWF0cml4Lm10eCcsICcnKQoKIyBjb25zdHJ1Y3QgYSBsaXN0IG9mIHNldXJhdCBvYmplY3RzIGZvciBlYWNoIHNhbXBsZSBieSBpdGVyYXRpdmVseSBsb2FkaW5nIGVhY2ggZmlsZQpzZXVyYXRfbGlzdCA8LSBsYXBwbHkoZmlsZV9zdGVtcywgZnVuY3Rpb24oZmlsZSl7CiAgcHJpbnQoZmlsZSkKICBYIDwtIHJlYWRNTShwYXN0ZTAoZGF0YV9kaXIsZmlsZSwnX21hdHJpeC5tdHgnKSkKCiAgZ2VuZXMgPC0gcmVhZC5jc3YoZmlsZT1wYXN0ZTAoZGF0YV9kaXIsZmlsZSwnX2ZlYXR1cmVzLnRzdicpLCBzZXA9J1x0JywgaGVhZGVyPUZBTFNFKQogIGJhcmNvZGVzIDwtIHJlYWQuY3N2KGZpbGU9cGFzdGUwKGRhdGFfZGlyLGZpbGUsJ19iYXJjb2Rlcy50c3YnKSwgc2VwPSdcdCcsIGhlYWRlcj1GQUxTRSkKCiAgY29sbmFtZXMoWCkgPC0gYmFyY29kZXMkVjEKICByb3duYW1lcyhYKSA8LSBnZW5lcyRWMgoKICBjdXJfc2V1cmF0IDwtIENyZWF0ZVNldXJhdE9iamVjdCgKICAgIGNvdW50cyA9IFgsCiAgICBwcm9qZWN0ID0gInR1dG9yaWFsIgogICkKICBjdXJfc2V1cmF0QG1ldGEuZGF0YSRTYW1wbGVJRCA8LSBmaWxlCiAgY3VyX3NldXJhdAp9KQoKIyBtZXJnZSBpbnRvIG9uZSBiaWcgc2V1cmF0IG9iamVjdApzZXVyYXRfb2JqIDwtIG1lcmdlKHg9c2V1cmF0X2xpc3RbWzFdXSwgeT1zZXVyYXRfbGlzdFsyOmxlbmd0aChzZXVyYXRfbGlzdCldKQoKIyBhZGQgbWV0YWRhdGEKbWV0YSA8LSByZWFkLmNzdihwYXN0ZTAoZGF0YV9kaXIsICdtZXRhLmNzdicpKQpyb3duYW1lcyhtZXRhKSA8LSBtZXRhJFNhbXBsZS5JRC5pbi5zblJOQS5zZXEKCm1ldGEuZGF0YSA8LSBtZXRhW3NldXJhdF9vYmokU2FtcGxlSUQsXQpmb3IobSBpbiBuYW1lcyhtZXRhLmRhdGEpKXsKICBzZXVyYXRfb2JqQG1ldGEuZGF0YVtbbV1dIDwtIG1ldGEuZGF0YVtbbV1dCn0KCiMgcmVtb3ZlIGluZGl2aWR1YWwgc2V1cmF0IG9iamVjdHMgdG8gc2F2ZSBtZW1vcnkKcm0oc2V1cmF0X2xpc3QpOyBnYygpOwpgYGAKCmBgYHtyfQojIHVzZSB0YWJsZSBmdW5jdGlvbiB0byBnZXQgdGhlIG51bWJlciBvZiBjZWxscyBpbiBlYWNoIFNhbXBsZSBhcyBhIGRhdGFmcmFtZQpkZiA8LSBhcy5kYXRhLmZyYW1lKHJldih0YWJsZShzZXVyYXRfb2JqJFNhbXBsZUlEKSkpCmNvbG5hbWVzKGRmKSA8LSBjKCdTYW1wbGVJRCcsICduX2NlbGxzJykKCiMgYmFyIHBsb3Qgb2YgdGhlIG51bWJlciBvZiBjZWxscyBpbiBlYWNoIHNhbXBsZQpwIDwtIGdncGxvdChkZiwgYWVzKHk9bl9jZWxscywgeD1yZW9yZGVyKFNhbXBsZUlELCAtbl9jZWxscyksIGZpbGw9U2FtcGxlSUQpKSArCiAgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKwogIE5vTGVnZW5kKCkgKyBSb3RhdGVkQXhpcygpICsKICB5bGFiKGV4cHJlc3Npb24oaXRhbGljKE4pW2NlbGxzXSkpICsgeGxhYignU2FtcGxlIElEJykgKwogIGdndGl0bGUocGFzdGUoJ1RvdGFsIGNlbGxzOicsIHN1bShkZiRuX2NlbGxzKSkpICsKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55PWVsZW1lbnRfbGluZShjb2xvdXI9ImxpZ2h0Z3JheSIsIHNpemU9MC41KSwKICApCgpwbmcoJ2ZpZ3VyZXMvYmFzaWNfY2VsbHNfcGVyX3NhbXBsZS5wbmcnLCB3aWR0aD05LCBoZWlnaHQ9NCwgcmVzPTIwMCwgdW5pdHM9J2luJykKcHJpbnQocCkKZGV2Lm9mZigpCmBgYAoKYGBge3J9CiMgcGxvdCB0aGUgbnVtYmVyIG9mIERFR3MgcGVyIGNsdXN0ZXI6CmRmIDwtIGFzLmRhdGEuZnJhbWUocmV2KHRhYmxlKGNsdXN0ZXJfbWFya2VycyRDZWxsVHlwZV9jbHVzdGVyKSkpCmNvbG5hbWVzKGRmKSA8LSBjKCdjbHVzdGVyJywgJ25fREVHcycpCgojIGJhciBwbG90IG9mIHRoZSBudW1iZXIgb2YgY2VsbHMgaW4gZWFjaCBzYW1wbGUKcCA8LSBnZ3Bsb3QoZGYsIGFlcyh5PW5fREVHcywgeD1yZW9yZGVyKGNsdXN0ZXIsIC1uX0RFR3MpLCBmaWxsPWNsdXN0ZXIpKSArCiAgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkgKwogIE5vTGVnZW5kKCkgKyBSb3RhdGVkQXhpcygpICsKICB5bGFiKGV4cHJlc3Npb24oaXRhbGljKE4pW0RFR3NdKSkgKyB4bGFiKCcnKSArCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueT1lbGVtZW50X2xpbmUoY29sb3VyPSJsaWdodGdyYXkiLCBzaXplPTAuNSksCiAgKQoKcG5nKCdmaWd1cmVzL2Jhc2ljX0RFR3NfYmFycGxvdC5wbmcnLCB3aWR0aD05LCBoZWlnaHQ9NCwgcmVzPTMwMCwgdW5pdHM9J2luJykKcHJpbnQocCkKZGV2Lm9mZigpCgojIHBsb3QgdGhlIHRvcCAzIERFR3MgcGVyIGNsdXN0ZXIgYXMgYSBoZWF0bWFwOgp0b3BfREVHcyA8LSBjbHVzdGVyX21hcmtlcnMgJT4lCiAgZ3JvdXBfYnkoQ2VsbFR5cGVfY2x1c3RlcikgJT4lCiAgdG9wX24oMywgd3Q9YXZnX2xvZ0ZDKSAlPiUKICAuJGdlbmUKCnBuZygnZmlndXJlcy9iYXNpY19ERUdzX2hlYXRtYXAucG5nJywgd2lkdGg9MTAsIGhlaWdodD0xMCwgcmVzPTMwMCwgdW5pdHM9J2luJykKcGRmKCdmaWd1cmVzL2Jhc2ljX0RFR3NfaGVhdG1hcC5wZGYnLCB3aWR0aD0xNSwgaGVpZ2h0PTEyLCB1c2VEaW5nYmF0cz1GQUxTRSkKRG9IZWF0bWFwKHNldXJhdF9vYmosIGZlYXR1cmVzPXRvcF9ERUdzLCBncm91cC5ieT0nc2V1cmF0X2NsdXN0ZXJzJywgbGFiZWw9RkFMU0UpICsgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPXZpcmlkaXMoMjU2KSkgKyBOb0xlZ2VuZCgpCmRldi5vZmYoKQpgYGAKCmBgYHtyfQpjZHMgPC0gY2x1c3Rlcl9jZWxscyhjZHMpCnBsb3RfY2VsbHMoY2RzLCBjb2xvcl9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLCBncm91cF9jZWxsc19ieSA9ICJwYXJ0aXRpb24iLCAKICAgICAgICAgICBncm91cF9sYWJlbF9zaXplID0gNCkKYGBgCgoKYGBge3J9CiNtb25vY2xlIHBsb3QgY2VsbHMKcGxvdF9jZWxscyhjZHMsIHJlZHVjdGlvbl9tZXRob2QgPSAiUENBIiwKICAgICAgICAgICBjb2xvcl9jZWxsc19ieSA9ICJjZWxsX3R5cGUiLCBncm91cF9sYWJlbF9zaXplID0gMy41LAogICAgICAgICAgIGxhYmVsX2dyb3Vwc19ieV9jbHVzdGVyID0gRkFMU0UpICsKICBzY2FsZV9jb2xvcl9kMyhwYWxldHRlID0gImNhdGVnb3J5MjBiIikKIyBTZWVkIGZvciByYW5kb20gaW5pdGlhdGlvbiBvZiBVTUFQCnNldC5zZWVkKDQ4MzcpCmNkcyA8LSByZWR1Y2VfZGltZW5zaW9uKGNkcywgcmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIiwgcHJlcHJvY2Vzc19tZXRob2QgPSAiUENBIiwgaW5pdCA9ICJyYW5kb20iKQpwbG90X2NlbGxzKGNkcywgY29sb3JfY2VsbHNfYnkgPSAiY2VsbF90eXBlIiwgZ3JvdXBfbGFiZWxfc2l6ZSA9IDMuNSwKICAgICAgICAgICBsYWJlbF9ncm91cHNfYnlfY2x1c3RlciA9IEZBTFNFKSArCiAgc2NhbGVfY29sb3JfZDMocGFsZXR0ZSA9ICJjYXRlZ29yeTIwYiIpCmBgYAoKYGBge3J9CnBsb3RfY2VsbHMoY2RzLCBjb2xvcl9jZWxsc19ieSA9ICJjbHVzdGVyIiwgZ3JvdXBfY2VsbHNfYnkgPSAiY2x1c3RlciIsIAogICAgICAgICAgIGdyb3VwX2xhYmVsX3NpemUgPSA0KQpgYGAKCmBgYHtyfQojTW9ub2NsZSAz4oCZcyB0cmFqZWN0b3J5IGluZmVyZW5jZSBpcyBpbnNwaXJlZCBieSBQQUdBLgpjZHMgPC0gbGVhcm5fZ3JhcGgoY2RzLCB2ZXJib3NlID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgbGVhcm5fZ3JhcGhfY29udHJvbCA9IGxpc3QobWluaW1hbF9icmFuY2hfbGVuID0gNywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb2Rlc2ljX2Rpc3RhbmNlX3JhdGlvID0gMC41KSkKYGBgCgpgYGB7cn0KcGxvdF9jZWxscyhjZHMsIGNvbG9yX2NlbGxzX2J5ID0gImNlbGxfdHlwZSIsIGxhYmVsX2dyb3Vwc19ieV9jbHVzdGVyID0gRkFMU0UsCiAgICAgICAgICAgZ3JvdXBfbGFiZWxfc2l6ZSA9IDMuNSwgZ3JhcGhfbGFiZWxfc2l6ZSA9IDIpICsKICBzY2FsZV9jb2xvcl9kMyhwYWxldHRlID0gImNhdGVnb3J5MjBiIikKYGBgCgpgYGB7cn0KCmBgYAoK