Cluster cell types
Cluster young cells
sce10x_yng <- sce10x[, colData(sce10x)$condition == "yng"]
n_exprs_genes_yng <-
nexprs(sce10x_yng,
detection_limit = 5,
byrow = TRUE
)
table(n_exprs_genes_yng)[1:20]
n_exprs_genes_yng
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
24696 1436 778 467 333 269 236 200 175 125 150 129 111 111 112 84 71 88
18 19
68 74
set.seed(42)
# t-UMAP is equivalent to a = 1, b = 1
# get the nearest neighbor data back
sce10x_yng_tumap <-
tumap(t(assay(sce10x_yng[n_exprs_genes_yng >= 3, ], "counts") %>%
as.matrix()),
metric = "cosine",
ret_nn = TRUE
)
set.seed(42)
sce10x_umap_yng <-
umap(t(assay(
sce10x_yng[n_exprs_genes_yng >= 3, ],
"counts"
) %>%
as.matrix()),
metric = "cosine",
nn_method = sce10x_yng_tumap$nn,
a = .6,
b = .55
)
colnames(sce10x_umap_yng) <- paste0("umap", seq(1, 2))
reducedDim(sce10x_yng, "umap") <- sce10x_umap_yng
dt <-
bind_cols(
colData(sce10x_yng) %>%
as_tibble(),
sce10x_umap_yng %>%
as_tibble()
)
p2 <-
ggplot(dt) +
geom_point(aes(umap1,
umap2,
colour = markers
),
size = 3,
alpha = 1
)
p2
# ggsave(file.path(figures_dir, "umap_cosine_a160_b33_17928_cells_markers.pdf"), p2 )
set.seed(42)
g <- buildSNNGraph(sce10x_yng, k = 20, use.dimred = "umap")
clusters_out <- igraph::cluster_walktrap(g)
# colLabels(sce10x) <- factor(igraph::cluster_louvain(g)$membership)
table(clusters_out$membership)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
147 72 354 370 147 434 88 90 93 87 272 236 250 176 214 404 146 295 493 110 238 151 172 98 69 96 233
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
162 78 74 81 63 133 144 62 67 102 61 55 83 64 42 41 38 24 26 29 46 23 35 45 21 38 31
55
32
igraph_clusters <- igraph::cut_at(clusters_out, n = 16)
table(igraph_clusters)
igraph_clusters
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
404 109 1535 173 1056 1848 890 122 483 291 88 87 41 45 31 32
cluster_by_marker <-
table(igraph_clusters, colData(sce10x_yng)$markers)
cluster_by_marker
igraph_clusters fap macrophage none stem
1 0 402 0 2
2 0 109 0 0
3 1457 3 64 11
4 6 17 126 24
5 0 3 58 995
6 5 8 146 1689
7 7 3 68 812
8 15 0 99 8
9 0 480 2 1
10 1 0 18 272
11 1 1 25 61
12 0 1 8 78
13 4 5 22 10
14 2 3 39 1
15 2 2 27 0
16 0 1 24 7
labels <- apply(cluster_by_marker, 1, which.max)
level_key_1 <- colnames(cluster_by_marker)[labels]
names(level_key_1) <- names(labels)
level_key_1
1 2 3 4 5 6 7 8
"macrophage" "macrophage" "fap" "none" "stem" "stem" "stem" "none"
9 10 11 12 13 14 15 16
"macrophage" "stem" "stem" "stem" "none" "none" "none" "none"
table(level_key_1)
level_key_1
fap macrophage none stem
1 3 6 6
level_key_2 <- paste(level_key_1, names(level_key_1), sep = "_")
names(level_key_2) <- names(labels)
colData(sce10x_yng)$clusters_level1 <- recode(igraph_clusters, !!!level_key_1)
colData(sce10x_yng)$clusters_level2 <- recode(igraph_clusters, !!!level_key_2)
table(colData(sce10x_yng)$clusters_level1, colData(sce10x_yng)$sample)
yng1 yng2 yng3
fap 502 393 640
macrophage 289 289 418
none 185 158 101
stem 1261 1936 1063
table(colData(sce10x_yng)$clusters_level2, colData(sce10x_yng)$sample)
yng1 yng2 yng3
fap_3 502 393 640
macrophage_1 107 146 151
macrophage_2 9 31 69
macrophage_9 173 112 198
none_13 15 8 18
none_14 14 22 9
none_15 23 3 5
none_16 0 0 32
none_4 96 74 3
none_8 37 51 34
stem_10 16 274 1
stem_11 0 0 88
stem_12 60 17 10
stem_5 111 865 80
stem_6 1066 766 16
stem_7 8 14 868
dt <-
bind_cols(
colData(sce10x_yng) %>%
as_tibble(),
sce10x_umap_yng %>%
as_tibble()
)
p3 <-
ggplot(dt, aes(umap1,
umap2,
colour = subsets_mitotic_detected >1
)) +
geom_jitter(
width = .1,
height = .1,
size = 3,
alpha = 1
)
p3 + facet_wrap(~clusters_level2)
# ggsave(file.path(figures_dir, "umap_cosine_a160_b33_17928_louvain_clusters.pdf"), p3 )
colData(sce10x_yng)$clusters_level1[colData(sce10x_yng)$clusters_level2 =="stem_12"] <- "stem_mitotic"
dt <-
bind_cols(
colData(sce10x_yng) %>%
as_tibble(),
sce10x_umap_yng %>%
as_tibble()
)
p3 <-
ggplot(dt, aes(umap1,
umap2,
colour = clusters_level1
)) +
geom_jitter(
width = .1,
height = .1,
size = 3,
alpha = 1
)
p3
# ggsave(file.path(figures_dir, "umap_cosine_a160_b33_17928_louvain_clusters.pdf"), p3 )
Cluster aged cells
sce10x_aged <- sce10x[, colData(sce10x)$condition == "aged"]
n_exprs_genes_aged <-
nexprs(sce10x_aged,
detection_limit = 5,
byrow = TRUE
)
table(n_exprs_genes_aged)[1:20]
n_exprs_genes_aged
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
25860 1574 714 507 365 253 220 195 175 129 137 108 122 90 80 71 71 83
18 19
66 71
# t-UMAP is equivalent to a = 1, b = 1
# get the nearest neighbor data back
sce10x_aged_tumap <-
tumap(t(assay(
sce10x_aged[n_exprs_genes_aged >= 3, ],
"counts"
) %>%
as.matrix()),
metric = "cosine",
ret_nn = TRUE
)
set.seed(42)
sce10x_umap_aged <-
umap(t(assay(
sce10x_aged[n_exprs_genes_aged >= 3, ],
"counts"
) %>%
as.matrix()),
metric = "cosine",
nn_method = sce10x_aged_tumap$nn,
a = .6,
b = .6
)
colnames(sce10x_umap_aged) <- paste0("umap", seq(1, 2))
reducedDim(sce10x_aged, "umap") <- sce10x_umap_aged
dt <-
bind_cols(
colData(sce10x_aged) %>%
as_tibble(),
sce10x_umap_aged %>%
as_tibble()
)
p2 <-
ggplot(dt) +
geom_point(aes(umap1,
umap2,
colour = markers
),
size = 1,
alpha = 1
)
p2
# ggsave(file.path(figures_dir, "umap_cosine_a160_b33_17928_cells_markers.pdf"), p2 )
set.seed(42)
g <- buildSNNGraph(sce10x_aged, k = 20, use.dimred = "umap")
clusters_out <- igraph::cluster_walktrap(g)
# colLabels(sce10x) <- factor(igraph::cluster_louvain(g)$membership)
table(clusters_out$membership)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
788 319 135 715 84 321 239 407 740 58 353 157 191 474 837 286 122 105 325 506 422 200 236 123 279 116 160
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
69 203 187 92 49 54 97 57 106 93 64 180 59 48 67 33 55 68 34 65 41 28 40 56 45 44 37
55
24
igraph_clusters <- igraph::cut_at(clusters_out, n = 9)
table(igraph_clusters)
igraph_clusters
1 2 3 4 5 6 7 8 9
6639 131 343 674 2335 157 82 295 37
cluster_by_marker <-
table(igraph_clusters, colData(sce10x_aged)$markers)
cluster_by_marker
igraph_clusters fap macrophage none stem
1 5865 37 710 27
2 0 127 3 1
3 6 3 332 2
4 6 664 3 1
5 14 20 694 1607
6 10 6 136 5
7 3 2 74 3
8 63 5 224 3
9 32 0 5 0
labels <- apply(cluster_by_marker, 1, which.max)
level_key_1 <- colnames(cluster_by_marker)[labels]
names(level_key_1) <- names(labels)
level_key_1
1 2 3 4 5 6 7 8
"fap" "macrophage" "none" "macrophage" "stem" "none" "none" "none"
9
"fap"
table(level_key_1)
level_key_1
fap macrophage none stem
2 2 4 1
level_key_2 <- paste(level_key_1, names(level_key_1), sep = "_")
names(level_key_2) <- names(labels)
level_key_2
1 2 3 4 5 6 7
"fap_1" "macrophage_2" "none_3" "macrophage_4" "stem_5" "none_6" "none_7"
8 9
"none_8" "fap_9"
colData(sce10x_aged)$clusters_level1 <- recode(igraph_clusters, !!!level_key_1)
colData(sce10x_aged)$clusters_level2 <- recode(igraph_clusters, !!!level_key_2)
table(colData(sce10x_aged)$clusters_level1, colData(sce10x_aged)$sample)
aged1 aged2 aged3 aged4
fap 2027 2022 1583 1044
macrophage 65 398 149 193
none 168 345 143 221
stem 545 692 337 761
table(colData(sce10x_aged)$clusters_level2, colData(sce10x_aged)$sample)
aged1 aged2 aged3 aged4
fap_1 1993 2021 1582 1043
fap_9 34 1 1 1
macrophage_2 0 128 0 3
macrophage_4 65 270 149 190
none_3 70 99 100 74
none_6 36 85 10 26
none_7 11 27 8 36
none_8 51 134 25 85
stem_5 545 692 337 761
dt <-
bind_cols(
colData(sce10x_aged) %>%
as_tibble(),
sce10x_umap_aged %>%
as_tibble()
)
p3 <-
ggplot(dt, aes(umap1,
umap2,
colour = clusters_level1
)) +
geom_jitter(
width = .1,
height = .1,
size = .7,
alpha = 1
)
p3 #+facet_wrap(~clusters_level2)
# ggsave(file.path(figures_dir, "umap_cosine_a160_b33_17928_louvain_clusters.pdf"), p3 )
Save data
meta_dt <-
rbind(colData(sce10x_aged), colData(sce10x_yng))
colData(sce10x)$cluster_level2 <- paste(meta_dt$condition, meta_dt$clusters_level1, sep="_")
colData(sce10x) <- meta_dt
saveRDS(sce10x,
file.path(
data_dir,
"preprocessed",
"sce10x_filtered_cells.rds"))
Normalize and correct for batch effects
Discard non-marked and mitotic cells
sce10x <- sce10x[, colData(sce10x)$clusters_level1 %in% c("macrophage", "fap", "stem") ]
n_exprs_genes <-
nexprs(sce10x,
detection_limit = 0,
byrow = TRUE
)
table(n_exprs_genes)[1:20]
n_exprs_genes
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
981 2716 1434 1055 759 591 471 444 357 357 336 333 285 252 226 239 231 190 209 167
sce10x <- sce10x[n_exprs_genes >0,]
sce10x
class: SingleCellExperiment
dim: 33578 16520
metadata(42): tximetaInfo quantInfo ... txomeInfo txdbInfo
assays(3): counts spliced unspliced
rownames(33578): Gm1992 Gm6123 ... mt-Cytb mt-Nd6
rowData names(9): ensembl_gene_id_version external_gene_name ... nexprs_l1_s keep
colnames(16520): GACTATGTCCGGCTTT_d1 ATGGTTGGTTGTAAAG_d1 ... GTCCCTCTCCCTCTAG_g3
AAACGCTGTCGTTTAC_g3
colData names(22): sum detected ... clusters_level1 clusters_level2
reducedDimNames(0):
altExpNames(0):
colData(sce10x)$clusters_level2 <-
paste(colData(sce10x)$condition,
colData(sce10x)$clusters_level1, sep="_")
Normalize data across samples
sce10x <-
multiBatchNorm(sce10x,
batch = colData(sce10x)$sample
)
n_exprs_genes <-
nexprs(sce10x,
detection_limit = 5,
byrow = TRUE
)
table(n_exprs_genes)[1:20]
n_exprs_genes
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
23438 1596 722 483 357 280 220 191 166 164 128 134 95 88 121 68 73 80
18 19
67 71
Run fast mutual nearest neighbors correction
sce10x_corrected <-
fastMNN(sce10x,
batch = colData(sce10x)$sample,
k = 20,
d = 200,
subset.row = names(n_exprs_genes)[n_exprs_genes >= 3]
)
reducedDim(sce10x, "mnn_corrected") <- reducedDim(sce10x_corrected, "corrected")
Run UMAP
set.seed(42)
# t-UMAP is equivalent to a = 1, b = 1
# get the nearest neighbor data back
sce10x_tumap <-
tumap(reducedDim(sce10x,
"mnn_corrected"),
metric = "cosine",
ret_nn = TRUE)
set.seed(42)
sce10x_umap <-
umap(reducedDim(sce10x,
"mnn_corrected"),
metric = "cosine",
nn_method = sce10x_tumap$nn,
a = .8,
b = .55
)
colnames(sce10x_umap) <- paste0("umap", seq(1, 2))
reducedDim(sce10x, "mnn_umap") <- sce10x_umap
dt <-
bind_cols(
colData(sce10x) %>%
as_tibble(),
sce10x_umap %>%
as_tibble()
)
p2 <-
ggplot(dt) +
geom_point(aes(umap1,
umap2,
colour = clusters_level1
),
size = .6,
alpha = 1
) #+ facet_wrap(~condition)
p2
ggsave(file.path(figures_dir, "mnn_umap.pdf"), p2 )
Saving 14 x 8 in image
Cluster stem cells
set.seed(42)
g <- buildSNNGraph(sce10x, k = 100, use.dimred = "mnn_umap")
clusters_out <- igraph::cluster_walktrap(g)
set.seed(42)
# t-UMAP is equivalent to a = 1, b = 1
# get the nearest neighbor data back
sce10x_stem_tumap <-
tumap(reducedDim(sce10x_stem,
"mnn_corrected"),
metric = "cosine",
ret_nn = TRUE)
set.seed(42)
sce10x_stem_umap <-
umap(reducedDim(sce10x_stem,
"mnn_corrected"),
metric = "cosine",
nn_method = sce10x_stem_tumap$nn,
a = .85,
b = .43
)
colnames(sce10x_stem_umap) <- paste0("umap", seq(1, 2))
reducedDim(sce10x_stem, "mnn_umap") <- sce10x_stem_umap
dt <-
bind_cols(
colData(sce10x_stem) %>%
as_tibble(),
sce10x_stem_umap %>%
as_tibble()
)
p2 <-
ggplot(dt) +
geom_point(aes(umap1,
umap2,
colour = clusters_level2
),
size = 1,
alpha =.6
)
p2
# ggsave(file.path(figures_dir, "umap_cosine_a160_b33_17928_cells_markers.pdf"), p2 )
set.seed(42)
g <- buildSNNGraph(sce10x_stem, k = 100, use.dimred = "mnn_umap")
clusters_out <- igraph::cluster_walktrap(g)
igraph_clusters <- factor(clusters_out$membership)
table(igraph_clusters)
igraph_clusters
1 2 3 4 5 6 7 8 9 10 11 12 13 14
433 711 773 430 912 852 464 386 234 433 188 157 290 245
igraph_clusters <- igraph::cut_at(clusters_out, n = 5)
table(igraph_clusters)
igraph_clusters
1 2 3 4 5
1931 621 2043 1061 852
discard_cell <- sce10x_stem_umap[,1] < -10 | sce10x_stem_umap[,1] > 22 | (igraph_clusters ==2 & colData(sce10x_stem)$condition=="aged")
table(discard_cell)
discard_cell
FALSE TRUE
6429 79
igraph_clusters[discard_cell] <- 6
cluster_by_marker <-
table(igraph_clusters, colData(sce10x_stem)$sample)
cluster_by_marker
igraph_clusters aged1 aged2 aged3 aged4 yng1 yng2 yng3
1 20 86 52 85 495 902 291
2 0 0 0 0 250 220 126
3 98 178 79 196 356 606 530
4 135 214 102 255 68 141 92
5 268 204 93 203 30 44 10
6 24 10 11 22 2 6 4
colData(sce10x_stem)$clusters <- factor(igraph_clusters)
sce10x_stem_subset <-
sce10x_stem[, colData(sce10x_stem)$clusters!=6]
dt <-
bind_cols(
colData(sce10x_stem_subset) %>%
as_tibble(),
reducedDim(sce10x_stem_subset, "mnn_umap") %>%
as_tibble()
)
p2 <-
ggplot(dt) +
geom_point(aes(umap1,
umap2,
colour = clusters
),
size = 1.7,
alpha = 1
)
p2 # + facet_wrap(~clusters)
ggsave(file.path(figures_dir, "mnn_umap_stem.pdf"), p2 )
Saving 14 x 10 in image
Cluster fap cells
sce10x_fap <- sce10x[,colData(sce10x)$clusters_level1 =="fap"]
set.seed(42)
# t-UMAP is equivalent to a = 1, b = 1
# get the nearest neighbor data back
sce10x_fap_tumap <-
tumap(reducedDim(sce10x_fap,
"mnn_corrected"),
metric = "cosine",
ret_nn = TRUE)
set.seed(42)
sce10x_fap_umap <-
umap(reducedDim(sce10x_fap,
"mnn_corrected"),
metric = "cosine",
nn_method = sce10x_fap_tumap$nn,
a = .9,
b = .78
)
colnames(sce10x_fap_umap) <- paste0("umap", seq(1, 2))
reducedDim(sce10x_fap, "mnn_umap") <- sce10x_fap_umap
dt <-
bind_cols(
colData(sce10x_fap) %>%
as_tibble(),
sce10x_fap_umap %>%
as_tibble()
)
p2 <-
ggplot(dt) +
geom_point(aes(umap1,
umap2,
colour = clusters_level2
),
size = 1,
alpha =.6
)
p2
# ggsave(file.path(figures_dir, "umap_cosine_a160_b33_17928_cells_markers.pdf"), p2 )
set.seed(42)
g <- buildSNNGraph(sce10x_fap, k = 100, use.dimred = "mnn_umap")
clusters_out <- igraph::cluster_walktrap(g)
igraph_clusters <- factor(clusters_out$membership)
table(igraph_clusters)
igraph_clusters
1 2 3 4 5 6 7 8 9 10
1217 889 1246 664 1710 1383 413 304 239 146
igraph_clusters <- igraph::cut_at(clusters_out, n = 3)
table(igraph_clusters)
igraph_clusters
1 2 3
6102 1963 146
discard_cell <- sce10x_fap_umap[,1] > 5
table(discard_cell)
discard_cell
FALSE TRUE
8149 62
igraph_clusters[discard_cell] <- 4
cluster_by_marker <-
table(igraph_clusters, colData(sce10x_fap)$sample)
cluster_by_marker
igraph_clusters aged1 aged2 aged3 aged4 yng1 yng2 yng3
1 1608 1562 1120 824 289 273 364
2 369 419 434 189 196 107 249
3 43 28 14 14 13 10 24
4 7 13 15 17 4 3 3
colData(sce10x_fap)$clusters <- factor(igraph_clusters)
sce10x_fap_subset <-
sce10x_fap[, colData(sce10x_fap)$clusters!=4]
dt <-
bind_cols(
colData(sce10x_fap_subset) %>%
as_tibble(),
reducedDim(sce10x_fap_subset, "mnn_umap") %>%
as_tibble()
)
p2 <-
ggplot(dt) +
geom_point(aes(umap1,
umap2,
colour = clusters
),
size = 1.7,
alpha = 1
)
p2 # + facet_wrap(~clusters)
ggsave(file.path(figures_dir, "mnn_umap_fap.pdf"), p2 )
Saving 14 x 10 in image
Cluster macrophage cells
sce10x_macrophage <- sce10x[,colData(sce10x)$clusters_level1 =="macrophage"]
set.seed(42)
# t-UMAP is equivalent to a = 1, b = 1
# get the nearest neighbor data back
sce10x_macrophage_tumap <-
tumap(reducedDim(sce10x_macrophage,
"mnn_corrected"),
metric = "cosine",
ret_nn = TRUE)
set.seed(42)
sce10x_macrophage_umap <-
umap(reducedDim(sce10x_macrophage,
"mnn_corrected"),
metric = "cosine",
nn_method = sce10x_macrophage_tumap$nn,
a = 0.75,
b = 0.65
)
colnames(sce10x_macrophage_umap) <- paste0("umap", seq(1, 2))
reducedDim(sce10x_macrophage, "mnn_umap") <- sce10x_macrophage_umap
dt <-
bind_cols(
colData(sce10x_macrophage) %>%
as_tibble(),
sce10x_macrophage_umap %>%
as_tibble()
)
p2 <-
ggplot(dt) +
geom_point(aes(umap1,
umap2,
colour = clusters_level2
),
size = 1,
alpha =.6
)
p2
# ggsave(file.path(figures_dir, "umap_cosine_a160_b33_17928_cells_markers.pdf"), p2 )
set.seed(42)
g <- buildSNNGraph(sce10x_macrophage, k = 50, use.dimred = "mnn_umap")
clusters_out <- igraph::cluster_walktrap(g)
igraph_clusters <- factor(clusters_out$membership)
table(igraph_clusters)
igraph_clusters
1 2 3 4 5 6 7 8 9 10 11 12
224 215 253 193 246 158 108 73 93 78 62 98
igraph_clusters <- igraph::cut_at(clusters_out, n = 5)
table(igraph_clusters)
igraph_clusters
1 2 3 4 5
134 1156 305 108 98
cluster_by_marker <-
table(igraph_clusters, colData(sce10x_macrophage)$sample)
cluster_by_marker
igraph_clusters aged1 aged2 aged3 aged4 yng1 yng2 yng3
1 0 24 4 2 10 69 25
2 37 138 137 89 265 171 319
3 21 83 8 98 7 34 54
4 7 56 0 3 7 15 20
5 0 97 0 1 0 0 0
colData(sce10x_macrophage)$clusters <- factor(igraph_clusters)
sce10x_macrophage_subset <-
sce10x_macrophage[, colData(sce10x_macrophage)$clusters %in% c(1,2, 3)]
dt <-
bind_cols(
colData(sce10x_macrophage_subset) %>%
as_tibble(),
reducedDim(sce10x_macrophage_subset, "mnn_umap") %>%
as_tibble()
)
p2 <-
ggplot(dt) +
geom_point(aes(umap1,
umap2,
colour = clusters
),
size = 1.7,
alpha = 1
)
p2 # + facet_wrap(~clusters)
ggsave(file.path(figures_dir, "mnn_umap_macrophage.pdf"), p2 )
Saving 14 x 10 in image
Save data
meta_dt <-
rbind(colData(sce10x_stem_subset), colData(sce10x_fap_subset), colData(sce10x_macrophage_subset)) %>%
as_tibble(rownames = "cell") %>%
mutate(cluster_level1_1= paste(clusters_level1, clusters, sep="_" ),
cluster_level2_1= paste(clusters_level2, clusters, sep="_" )) %>%
select(cell, cluster_level1_1, cluster_level2_1 )
meta_dt
colData(sce10x) <-
left_join(colData(sce10x)%>%
as_tibble(rownames = "cell"),
meta_dt,
by="cell") %>%
replace_na(list(cluster_level2_1 = "discard", cluster_level1_1 = "discard")) %>%
select(-clusters) %>%
column_to_rownames("cell") %>%
DataFrame(.)
discard_idx <-
colData(sce10x)$cluster_level2_1 == "discard"
table(discard_idx)
discard_idx
FALSE TRUE
16173 347
sce10x <- sce10x[, !discard_idx]
n_exprs_genes <-
nexprs(sce10x,
detection_limit = 0,
byrow = TRUE
)
table(n_exprs_genes)[1:20]
n_exprs_genes
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
104 2706 1447 1072 738 601 471 433 372 344 344 329 283 236 233 239 218 205 198 171
sce10x <- sce10x[n_exprs_genes>0, ]
saveRDS(
sce10x,
file.path(
data_dir,
"preprocessed",
"sce10x_filtered_final.rds"
)
)
make plots
dt <-
bind_cols(
colData(sce10x) %>%
as_tibble(),
reducedDim(sce10x, "mnn_umap") %>%
as_tibble()
)
p2 <-
ggplot(dt) +
geom_point(aes(umap1,
umap2,
colour = cluster_level1_1
),
size = .6,
alpha = 1
) + facet_wrap(~condition)
p2
ggsave(file.path(figures_dir, "mnn_umap_split.pdf"), p2 )
Saving 14 x 8 in image
sessionInfo()
R version 4.0.0 (2020-04-24)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.4 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C LC_TIME=en_US.UTF-8
[4] LC_COLLATE=en_US.UTF-8 LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=en_US.UTF-8 LC_NAME=C LC_ADDRESS=C
[10] LC_TELEPHONE=C LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] parallel stats4 stats graphics grDevices utils datasets methods base
other attached packages:
[1] BiocSingular_1.4.0 batchelor_1.4.0 dbscan_1.1-5
[4] uwot_0.1.8 Matrix_1.2-18 forcats_0.5.0
[7] stringr_1.4.0 dplyr_0.8.5 purrr_0.3.4
[10] readr_1.3.1 tidyr_1.1.0 tibble_3.0.1
[13] tidyverse_1.3.0 scran_1.16.0 scater_1.16.0
[16] ggplot2_3.3.0 SingleCellExperiment_1.10.1 SummarizedExperiment_1.18.1
[19] DelayedArray_0.14.0 matrixStats_0.56.0 Biobase_2.48.0
[22] GenomicRanges_1.40.0 GenomeInfoDb_1.24.0 IRanges_2.22.2
[25] S4Vectors_0.26.1 BiocGenerics_0.34.0
loaded via a namespace (and not attached):
[1] nlme_3.1-147 fs_1.4.1 bitops_1.0-6 lubridate_1.7.8
[5] RcppAnnoy_0.0.16 httr_1.4.1 rprojroot_1.3-2 tools_4.0.0
[9] backports_1.1.7 utf8_1.1.4 R6_2.4.1 irlba_2.3.3
[13] vipor_0.4.5 DBI_1.1.0 colorspace_1.4-1 withr_2.2.0
[17] tidyselect_1.1.0 gridExtra_2.3 compiler_4.0.0 cli_2.0.2
[21] rvest_0.3.5 BiocNeighbors_1.6.0 xml2_1.3.2 labeling_0.3
[25] scales_1.1.1 digest_0.6.25 rmarkdown_2.1 XVector_0.28.0
[29] base64enc_0.1-3 pkgconfig_2.0.3 htmltools_0.4.0 dbplyr_1.4.4
[33] limma_3.44.1 rlang_0.4.6 readxl_1.3.1 rstudioapi_0.11
[37] DelayedMatrixStats_1.10.0 farver_2.0.3 generics_0.0.2 jsonlite_1.6.1
[41] BiocParallel_1.22.0 RCurl_1.98-1.2 magrittr_1.5 GenomeInfoDbData_1.2.3
[45] fansi_0.4.1 Rcpp_1.0.4.6 ggbeeswarm_0.6.0 munsell_0.5.0
[49] viridis_0.5.1 lifecycle_0.2.0 stringi_1.4.6 yaml_2.2.1
[53] edgeR_3.30.0 zlibbioc_1.34.0 grid_4.0.0 blob_1.2.1
[57] dqrng_0.2.1 crayon_1.3.4 lattice_0.20-41 haven_2.3.0
[61] hms_0.5.3 locfit_1.5-9.4 knitr_1.28 pillar_1.4.4
[65] igraph_1.2.5 codetools_0.2-16 reprex_0.3.0 glue_1.4.1
[69] evaluate_0.14 modelr_0.1.8 vctrs_0.3.0 cellranger_1.1.0
[73] gtable_0.3.0 assertthat_0.2.1 xfun_0.14 rsvd_1.0.3
[77] broom_0.5.6 RSpectra_0.16-0 viridisLite_0.3.0 beeswarm_0.2.3
[81] statmod_1.4.34 ellipsis_0.3.1
LS0tCnRpdGxlOiAiTW91c2UgTXVzY2xlIFN0ZW0gQ2VsbCBQcm9qZWN0ICIKc3VidGl0bGU6ICJQYXJ0IDM6IGNsdXN0ZXIgY2VsbHMiCmF1dGhvcjogCi0gbmFtZTogUmljayBGYXJvdW5pCiAgYWZmaWxpYXRpb246CiAgLSAmY3J1ayBHw6lub21lIFF1w6liZWMgSW5ub3ZhdGlvbiBDZW50cmUsIE1jR2lsbCBVbml2ZXJzaXR5LCBNb250cmVhbCwgQ2FuYWRhCmRhdGU6ICdgciBmb3JtYXQoU3lzLkRhdGUoKSwgIiVZLSVCLSVkIilgJwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICB0b2M6IG5vCiAgICB0b2NfZmxvYXQ6IAogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKCgojIFByZXBhcmUgYW5hbHlzaXMgd29ya2Zsb3cKCiMjIFNldCBmaWxlcGF0aHMgYW5kIHBhcmFtZXRlcnMKCmBgYHtyIHNldHVwfQpzZXQuc2VlZCg0MikKa25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSBycHJvanJvb3Q6OmZpbmRfcnN0dWRpb19yb290X2ZpbGUoKSkKb3B0aW9ucygKICByZWFkci5zaG93X3Byb2dyZXNzID0gRkFMU0UsCiAgZGlnaXRzID0gMgopCmBgYAoKIyMgTG9hZCBwYWNrYWdlcwpgYGB7cn0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KHNjYXRlcikKICBsaWJyYXJ5KHNjcmFuKQogIGxpYnJhcnkodGlkeXZlcnNlKQogIGxpYnJhcnkodXdvdCkgIyBGb3IgdW1hcAogIGxpYnJhcnkoZGJzY2FuKQogIGxpYnJhcnkoYmF0Y2hlbG9yKQogIGxpYnJhcnkoQmlvY1Npbmd1bGFyKQp9KQp0aGVtZV9zZXQodGhlbWVfYncoKSkKYGBgCgojIyBEZWZpbmUgZmlsZSBwYXRocwoKYGBge3J9CmRhdGFfZGlyIDwtICIuL2RhdGEiCmZpZ3VyZXNfZGlyIDwtIGZpbGUucGF0aCgiLi9maWd1cmVzIiwgInFjX2NlbGxzIikKYGBgCgoKIyMgTG9hZCBkYXRhCgpgYGB7cn0Kc2NlMTB4IDwtCiAgcmVhZFJEUyhmaWxlLnBhdGgoCiAgICBkYXRhX2RpciwKICAgICJwcmVwcm9jZXNzZWQiLAogICAgInNjZTEweF9maWx0ZXJlZF9jZWxscy5yZHMiCiAgKSkKYGBgCgoKCmBgYHtyfQptaXRvdGljX2R0PC0KICBwZXJDZWxsUUNNZXRyaWNzKAogICAgICBzY2UxMHgsCiAgICAgIHN1YnNldHMgPSBsaXN0KG1pdG90aWMgPSB3aGljaChyb3dEYXRhKHNjZTEweCkkZ2VuZV9uYW1lICVpbiUgYygiQ2NuYTIiLCAiQ2NuYjEiLCAiQ2NuYjIiKSkpLAogICAgICBwZXJjZW50X3RvcCA9TlVMTCwKICAgICAgZXhwcnNfdmFsdWVzID0gYygiY291bnRzIiksCiAgICAgIGZsYXR0ZW4gPSBUUlVFCiAgICApICU+JQogICAgYXNfdGliYmxlKCkgJT4lCiAgICBkcGx5cjo6c2VsZWN0KHN1YnNldHNfbWl0b3RpY19zdW0sIHN1YnNldHNfbWl0b3RpY19kZXRlY3RlZCwgc3Vic2V0c19taXRvdGljX3BlcmNlbnQpCm1pdG90aWNfZHQKYGBgCgoKCmBgYHtyfQpjb2xEYXRhKHNjZTEweCkgPC0KICBjYmluZChjb2xEYXRhKHNjZTEweCksIG1pdG90aWNfZHQpCmBgYAoKIyBDbHVzdGVyIGNlbGwgdHlwZXMKCiMjIENsdXN0ZXIgeW91bmcgY2VsbHMKCmBgYHtyfQpzY2UxMHhfeW5nIDwtIHNjZTEweFssIGNvbERhdGEoc2NlMTB4KSRjb25kaXRpb24gPT0gInluZyJdCmBgYAoKYGBge3J9Cm5fZXhwcnNfZ2VuZXNfeW5nIDwtCiAgbmV4cHJzKHNjZTEweF95bmcsCiAgICBkZXRlY3Rpb25fbGltaXQgPSA1LAogICAgYnlyb3cgPSBUUlVFCiAgKQoKdGFibGUobl9leHByc19nZW5lc195bmcpWzE6MjBdCmBgYAoKCgoKYGBge3J9CnNldC5zZWVkKDQyKQojIHQtVU1BUCBpcyBlcXVpdmFsZW50IHRvIGEgPSAxLCBiID0gMQojIGdldCB0aGUgbmVhcmVzdCBuZWlnaGJvciBkYXRhIGJhY2sKc2NlMTB4X3luZ190dW1hcCA8LQogIHR1bWFwKHQoYXNzYXkoc2NlMTB4X3luZ1tuX2V4cHJzX2dlbmVzX3luZyA+PSAzLCBdLCAiY291bnRzIikgJT4lCiAgICBhcy5tYXRyaXgoKSksCiAgbWV0cmljID0gImNvc2luZSIsCiAgcmV0X25uID0gVFJVRQogICkKYGBgCgpgYGB7cn0Kc2V0LnNlZWQoNDIpCnNjZTEweF91bWFwX3luZyA8LQogIHVtYXAodChhc3NheSgKICAgIHNjZTEweF95bmdbbl9leHByc19nZW5lc195bmcgPj0gMywgXSwKICAgICJjb3VudHMiCiAgKSAlPiUKICAgIGFzLm1hdHJpeCgpKSwKICBtZXRyaWMgPSAiY29zaW5lIiwKICBubl9tZXRob2QgPSBzY2UxMHhfeW5nX3R1bWFwJG5uLAogIGEgPSAuNiwKICBiID0gLjU1CiAgKQpjb2xuYW1lcyhzY2UxMHhfdW1hcF95bmcpIDwtIHBhc3RlMCgidW1hcCIsIHNlcSgxLCAyKSkKcmVkdWNlZERpbShzY2UxMHhfeW5nLCAidW1hcCIpIDwtIHNjZTEweF91bWFwX3luZwpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xNH0KZHQgPC0KICBiaW5kX2NvbHMoCiAgICBjb2xEYXRhKHNjZTEweF95bmcpICU+JQogICAgICBhc190aWJibGUoKSwKICAgIHNjZTEweF91bWFwX3luZyAlPiUKICAgICAgYXNfdGliYmxlKCkKICApCnAyIDwtCiAgZ2dwbG90KGR0KSArCiAgZ2VvbV9wb2ludChhZXModW1hcDEsCiAgICB1bWFwMiwKICAgIGNvbG91ciA9IG1hcmtlcnMKICApLAogIHNpemUgPSAzLAogIGFscGhhID0gMQogICkKcDIKIyBnZ3NhdmUoZmlsZS5wYXRoKGZpZ3VyZXNfZGlyLCAidW1hcF9jb3NpbmVfYTE2MF9iMzNfMTc5MjhfY2VsbHNfbWFya2Vycy5wZGYiKSwgcDIgKQpgYGAKCgpgYGB7cn0Kc2V0LnNlZWQoNDIpCmcgPC0gYnVpbGRTTk5HcmFwaChzY2UxMHhfeW5nLCBrID0gMjAsIHVzZS5kaW1yZWQgPSAidW1hcCIpCmBgYAoKYGBge3J9CmNsdXN0ZXJzX291dCA8LSBpZ3JhcGg6OmNsdXN0ZXJfd2Fsa3RyYXAoZykKIyBjb2xMYWJlbHMoc2NlMTB4KSA8LSBmYWN0b3IoaWdyYXBoOjpjbHVzdGVyX2xvdXZhaW4oZykkbWVtYmVyc2hpcCkKdGFibGUoY2x1c3RlcnNfb3V0JG1lbWJlcnNoaXApCmBgYAoKCmBgYHtyfQppZ3JhcGhfY2x1c3RlcnMgPC0gaWdyYXBoOjpjdXRfYXQoY2x1c3RlcnNfb3V0LCBuID0gMTYpCnRhYmxlKGlncmFwaF9jbHVzdGVycykKYGBgCgoKYGBge3J9CmNsdXN0ZXJfYnlfbWFya2VyIDwtCiAgdGFibGUoaWdyYXBoX2NsdXN0ZXJzLCBjb2xEYXRhKHNjZTEweF95bmcpJG1hcmtlcnMpCmNsdXN0ZXJfYnlfbWFya2VyCmBgYAoKCgpgYGB7cn0KbGFiZWxzIDwtIGFwcGx5KGNsdXN0ZXJfYnlfbWFya2VyLCAxLCB3aGljaC5tYXgpCmxldmVsX2tleV8xIDwtIGNvbG5hbWVzKGNsdXN0ZXJfYnlfbWFya2VyKVtsYWJlbHNdCm5hbWVzKGxldmVsX2tleV8xKSA8LSBuYW1lcyhsYWJlbHMpCmxldmVsX2tleV8xCmBgYApgYGB7cn0KdGFibGUobGV2ZWxfa2V5XzEpCmBgYAoKYGBge3J9CmxldmVsX2tleV8yIDwtIHBhc3RlKGxldmVsX2tleV8xLCBuYW1lcyhsZXZlbF9rZXlfMSksIHNlcCA9ICJfIikKbmFtZXMobGV2ZWxfa2V5XzIpIDwtIG5hbWVzKGxhYmVscykKY29sRGF0YShzY2UxMHhfeW5nKSRjbHVzdGVyc19sZXZlbDEgPC0gcmVjb2RlKGlncmFwaF9jbHVzdGVycywgISEhbGV2ZWxfa2V5XzEpCmNvbERhdGEoc2NlMTB4X3luZykkY2x1c3RlcnNfbGV2ZWwyIDwtIHJlY29kZShpZ3JhcGhfY2x1c3RlcnMsICEhIWxldmVsX2tleV8yKQp0YWJsZShjb2xEYXRhKHNjZTEweF95bmcpJGNsdXN0ZXJzX2xldmVsMSwgY29sRGF0YShzY2UxMHhfeW5nKSRzYW1wbGUpCmBgYAoKYGBge3J9CnRhYmxlKGNvbERhdGEoc2NlMTB4X3luZykkY2x1c3RlcnNfbGV2ZWwyLCBjb2xEYXRhKHNjZTEweF95bmcpJHNhbXBsZSkKYGBgCgoKYGBge3IgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE0fQpkdCA8LQogIGJpbmRfY29scygKICAgIGNvbERhdGEoc2NlMTB4X3luZykgJT4lCiAgICAgIGFzX3RpYmJsZSgpLAogICAgc2NlMTB4X3VtYXBfeW5nICU+JQogICAgICBhc190aWJibGUoKQogICkKcDMgPC0KICBnZ3Bsb3QoZHQsIGFlcyh1bWFwMSwKICAgIHVtYXAyLAogICAgY29sb3VyID0gc3Vic2V0c19taXRvdGljX2RldGVjdGVkID4xCiAgKSkgKwogIGdlb21faml0dGVyKAogICAgd2lkdGggPSAuMSwKICAgIGhlaWdodCA9IC4xLAogICAgc2l6ZSA9IDMsCiAgICBhbHBoYSA9IDEKICApCnAzICsgZmFjZXRfd3JhcCh+Y2x1c3RlcnNfbGV2ZWwyKQojIGdnc2F2ZShmaWxlLnBhdGgoZmlndXJlc19kaXIsICJ1bWFwX2Nvc2luZV9hMTYwX2IzM18xNzkyOF9sb3V2YWluX2NsdXN0ZXJzLnBkZiIpLCBwMyApCmBgYAoKCmBgYHtyfQpjb2xEYXRhKHNjZTEweF95bmcpJGNsdXN0ZXJzX2xldmVsMVtjb2xEYXRhKHNjZTEweF95bmcpJGNsdXN0ZXJzX2xldmVsMiA9PSJzdGVtXzEyIl0gPC0gInN0ZW1fbWl0b3RpYyIKYGBgCgoKYGBge3IgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTE0fQpkdCA8LQogIGJpbmRfY29scygKICAgIGNvbERhdGEoc2NlMTB4X3luZykgJT4lCiAgICAgIGFzX3RpYmJsZSgpLAogICAgc2NlMTB4X3VtYXBfeW5nICU+JQogICAgICBhc190aWJibGUoKQogICkKcDMgPC0KICBnZ3Bsb3QoZHQsIGFlcyh1bWFwMSwKICAgIHVtYXAyLAogICAgY29sb3VyID0gY2x1c3RlcnNfbGV2ZWwxCiAgKSkgKwogIGdlb21faml0dGVyKAogICAgd2lkdGggPSAuMSwKICAgIGhlaWdodCA9IC4xLAogICAgc2l6ZSA9IDMsCiAgICBhbHBoYSA9IDEKICApCnAzIAojIGdnc2F2ZShmaWxlLnBhdGgoZmlndXJlc19kaXIsICJ1bWFwX2Nvc2luZV9hMTYwX2IzM18xNzkyOF9sb3V2YWluX2NsdXN0ZXJzLnBkZiIpLCBwMyApCmBgYAoKIyMgQ2x1c3RlciBhZ2VkIGNlbGxzCgpgYGB7cn0Kc2NlMTB4X2FnZWQgPC0gc2NlMTB4WywgY29sRGF0YShzY2UxMHgpJGNvbmRpdGlvbiA9PSAiYWdlZCJdCmBgYAoKYGBge3J9Cm5fZXhwcnNfZ2VuZXNfYWdlZCA8LQogIG5leHBycyhzY2UxMHhfYWdlZCwKICAgIGRldGVjdGlvbl9saW1pdCA9IDUsCiAgICBieXJvdyA9IFRSVUUKICApCgp0YWJsZShuX2V4cHJzX2dlbmVzX2FnZWQpWzE6MjBdCmBgYAoKYGBge3J9CiMgdC1VTUFQIGlzIGVxdWl2YWxlbnQgdG8gYSA9IDEsIGIgPSAxCiMgZ2V0IHRoZSBuZWFyZXN0IG5laWdoYm9yIGRhdGEgYmFjawpzY2UxMHhfYWdlZF90dW1hcCA8LQogIHR1bWFwKHQoYXNzYXkoCiAgICBzY2UxMHhfYWdlZFtuX2V4cHJzX2dlbmVzX2FnZWQgPj0gMywgXSwKICAgICJjb3VudHMiCiAgKSAlPiUKICAgIGFzLm1hdHJpeCgpKSwKICBtZXRyaWMgPSAiY29zaW5lIiwKICByZXRfbm4gPSBUUlVFCiAgKQpgYGAKCgpgYGB7cn0Kc2V0LnNlZWQoNDIpCnNjZTEweF91bWFwX2FnZWQgPC0KICB1bWFwKHQoYXNzYXkoCiAgICBzY2UxMHhfYWdlZFtuX2V4cHJzX2dlbmVzX2FnZWQgPj0gMywgXSwKICAgICJjb3VudHMiCiAgKSAlPiUKICAgIGFzLm1hdHJpeCgpKSwKICBtZXRyaWMgPSAiY29zaW5lIiwKICBubl9tZXRob2QgPSBzY2UxMHhfYWdlZF90dW1hcCRubiwKICBhID0gLjYsCiAgYiA9IC42CiAgKQpjb2xuYW1lcyhzY2UxMHhfdW1hcF9hZ2VkKSA8LSBwYXN0ZTAoInVtYXAiLCBzZXEoMSwgMikpCnJlZHVjZWREaW0oc2NlMTB4X2FnZWQsICJ1bWFwIikgPC0gc2NlMTB4X3VtYXBfYWdlZApgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xNH0KZHQgPC0KICBiaW5kX2NvbHMoCiAgICBjb2xEYXRhKHNjZTEweF9hZ2VkKSAlPiUKICAgICAgYXNfdGliYmxlKCksCiAgICBzY2UxMHhfdW1hcF9hZ2VkICU+JQogICAgICBhc190aWJibGUoKQogICkKcDIgPC0KICBnZ3Bsb3QoZHQpICsKICBnZW9tX3BvaW50KGFlcyh1bWFwMSwKICAgIHVtYXAyLAogICAgY29sb3VyID0gbWFya2VycwogICksCiAgc2l6ZSA9IDEsCiAgYWxwaGEgPSAxCiAgKQpwMgojIGdnc2F2ZShmaWxlLnBhdGgoZmlndXJlc19kaXIsICJ1bWFwX2Nvc2luZV9hMTYwX2IzM18xNzkyOF9jZWxsc19tYXJrZXJzLnBkZiIpLCBwMiApCmBgYAoKCgoKCmBgYHtyfQpzZXQuc2VlZCg0MikKZyA8LSBidWlsZFNOTkdyYXBoKHNjZTEweF9hZ2VkLCBrID0gMjAsIHVzZS5kaW1yZWQgPSAidW1hcCIpCmBgYAoKYGBge3J9CmNsdXN0ZXJzX291dCA8LSBpZ3JhcGg6OmNsdXN0ZXJfd2Fsa3RyYXAoZykKIyBjb2xMYWJlbHMoc2NlMTB4KSA8LSBmYWN0b3IoaWdyYXBoOjpjbHVzdGVyX2xvdXZhaW4oZykkbWVtYmVyc2hpcCkKdGFibGUoY2x1c3RlcnNfb3V0JG1lbWJlcnNoaXApCmBgYAoKYGBge3J9CmlncmFwaF9jbHVzdGVycyA8LSBpZ3JhcGg6OmN1dF9hdChjbHVzdGVyc19vdXQsIG4gPSA5KQp0YWJsZShpZ3JhcGhfY2x1c3RlcnMpCmBgYAoKCmBgYHtyfQpjbHVzdGVyX2J5X21hcmtlciA8LQogIHRhYmxlKGlncmFwaF9jbHVzdGVycywgY29sRGF0YShzY2UxMHhfYWdlZCkkbWFya2VycykKY2x1c3Rlcl9ieV9tYXJrZXIKYGBgCgoKCmBgYHtyfQpsYWJlbHMgPC0gYXBwbHkoY2x1c3Rlcl9ieV9tYXJrZXIsIDEsIHdoaWNoLm1heCkKbGV2ZWxfa2V5XzEgPC0gY29sbmFtZXMoY2x1c3Rlcl9ieV9tYXJrZXIpW2xhYmVsc10KbmFtZXMobGV2ZWxfa2V5XzEpIDwtIG5hbWVzKGxhYmVscykKbGV2ZWxfa2V5XzEKYGBgCmBgYHtyfQp0YWJsZShsZXZlbF9rZXlfMSkKYGBgCgpgYGB7cn0KbGV2ZWxfa2V5XzIgPC0gcGFzdGUobGV2ZWxfa2V5XzEsIG5hbWVzKGxldmVsX2tleV8xKSwgc2VwID0gIl8iKQpuYW1lcyhsZXZlbF9rZXlfMikgPC0gbmFtZXMobGFiZWxzKQpsZXZlbF9rZXlfMgpgYGAKCmBgYHtyfQpjb2xEYXRhKHNjZTEweF9hZ2VkKSRjbHVzdGVyc19sZXZlbDEgPC0gcmVjb2RlKGlncmFwaF9jbHVzdGVycywgISEhbGV2ZWxfa2V5XzEpCmNvbERhdGEoc2NlMTB4X2FnZWQpJGNsdXN0ZXJzX2xldmVsMiA8LSByZWNvZGUoaWdyYXBoX2NsdXN0ZXJzLCAhISFsZXZlbF9rZXlfMikKYGBgCmBgYHtyfQp0YWJsZShjb2xEYXRhKHNjZTEweF9hZ2VkKSRjbHVzdGVyc19sZXZlbDEsIGNvbERhdGEoc2NlMTB4X2FnZWQpJHNhbXBsZSkKYGBgCmBgYHtyfQp0YWJsZShjb2xEYXRhKHNjZTEweF9hZ2VkKSRjbHVzdGVyc19sZXZlbDIsIGNvbERhdGEoc2NlMTB4X2FnZWQpJHNhbXBsZSkKYGBgCgoKCgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTR9CmR0IDwtCiAgYmluZF9jb2xzKAogICAgY29sRGF0YShzY2UxMHhfYWdlZCkgJT4lCiAgICAgIGFzX3RpYmJsZSgpLAogICAgc2NlMTB4X3VtYXBfYWdlZCAlPiUKICAgICAgYXNfdGliYmxlKCkKICApCnAzIDwtCiAgZ2dwbG90KGR0LCBhZXModW1hcDEsCiAgICB1bWFwMiwKICAgIGNvbG91ciA9IGNsdXN0ZXJzX2xldmVsMQogICkpICsKICBnZW9tX2ppdHRlcigKICAgIHdpZHRoID0gLjEsCiAgICBoZWlnaHQgPSAuMSwKICAgIHNpemUgPSAuNywKICAgIGFscGhhID0gMQogICkKcDMgIytmYWNldF93cmFwKH5jbHVzdGVyc19sZXZlbDIpCiMgZ2dzYXZlKGZpbGUucGF0aChmaWd1cmVzX2RpciwgInVtYXBfY29zaW5lX2ExNjBfYjMzXzE3OTI4X2xvdXZhaW5fY2x1c3RlcnMucGRmIiksIHAzICkKYGBgCgojIyBTYXZlIGRhdGEKCgpgYGB7cn0KbWV0YV9kdCA8LQogIHJiaW5kKGNvbERhdGEoc2NlMTB4X2FnZWQpLCBjb2xEYXRhKHNjZTEweF95bmcpKQpjb2xEYXRhKHNjZTEweCkgPC0gbWV0YV9kdApgYGAKCgpgYGB7cn0Kc2F2ZVJEUyhzY2UxMHgsCiAgICAgICAgZmlsZS5wYXRoKAogIGRhdGFfZGlyLAogICJwcmVwcm9jZXNzZWQiLAogICJzY2UxMHhfZmlsdGVyZWRfY2VsbHMucmRzIikpCmBgYAoKCiMgTm9ybWFsaXplIGFuZCBjb3JyZWN0IGZvciBiYXRjaCBlZmZlY3RzCgojIyBEaXNjYXJkIG5vbi1tYXJrZWQgYW5kIG1pdG90aWMgY2VsbHMKCgpgYGB7cn0Kc2NlMTB4IDwtIHNjZTEweFssIGNvbERhdGEoc2NlMTB4KSRjbHVzdGVyc19sZXZlbDEgJWluJSBjKCJtYWNyb3BoYWdlIiwgImZhcCIsICJzdGVtIikgXQpgYGAKCmBgYHtyfQpuX2V4cHJzX2dlbmVzIDwtCiAgbmV4cHJzKHNjZTEweCwKICAgIGRldGVjdGlvbl9saW1pdCA9IDAsCiAgICBieXJvdyA9IFRSVUUKICApCnRhYmxlKG5fZXhwcnNfZ2VuZXMpWzE6MjBdCmBgYAoKYGBge3J9CnNjZTEweCA8LSBzY2UxMHhbbl9leHByc19nZW5lcyA+MCxdCnNjZTEweApgYGAKCgoKYGBge3J9CmNvbERhdGEoc2NlMTB4KSRjbHVzdGVyc19sZXZlbDIgPC0gCiAgcGFzdGUoY29sRGF0YShzY2UxMHgpJGNvbmRpdGlvbiwgCiAgICAgICAgY29sRGF0YShzY2UxMHgpJGNsdXN0ZXJzX2xldmVsMSwgc2VwPSJfIikKCmBgYAoKIyMgTm9ybWFsaXplIGRhdGEgYWNyb3NzIHNhbXBsZXMKCmBgYHtyfQpzY2UxMHggPC0KICAgIG11bHRpQmF0Y2hOb3JtKHNjZTEweCwKICAgICAgYmF0Y2ggPSBjb2xEYXRhKHNjZTEweCkkc2FtcGxlCiAgICApCmBgYAoKYGBge3J9Cm5fZXhwcnNfZ2VuZXMgPC0KICBuZXhwcnMoc2NlMTB4LAogICAgZGV0ZWN0aW9uX2xpbWl0ID0gNSwKICAgIGJ5cm93ID0gVFJVRQogICkKdGFibGUobl9leHByc19nZW5lcylbMToyMF0KYGBgCgojIyBSdW4gZmFzdCBtdXR1YWwgbmVhcmVzdCBuZWlnaGJvcnMgY29ycmVjdGlvbgoKYGBge3J9CnNjZTEweF9jb3JyZWN0ZWQgPC0KICBmYXN0TU5OKHNjZTEweCwKICAgIGJhdGNoID0gY29sRGF0YShzY2UxMHgpJHNhbXBsZSwKICAgIGsgPSAyMCwKICAgIGQgPSAyMDAsCiAgICBzdWJzZXQucm93ID0gbmFtZXMobl9leHByc19nZW5lcylbbl9leHByc19nZW5lcyA+PSAzXQogICkKYGBgCgpgYGB7cn0KcmVkdWNlZERpbShzY2UxMHgsICJtbm5fY29ycmVjdGVkIikgPC0gcmVkdWNlZERpbShzY2UxMHhfY29ycmVjdGVkLCAiY29ycmVjdGVkIikKYGBgCgoKIyMgUnVuIFVNQVAKCgoKYGBge3J9CnNldC5zZWVkKDQyKQojIHQtVU1BUCBpcyBlcXVpdmFsZW50IHRvIGEgPSAxLCBiID0gMQojIGdldCB0aGUgbmVhcmVzdCBuZWlnaGJvciBkYXRhIGJhY2sKc2NlMTB4X3R1bWFwIDwtCiAgdHVtYXAocmVkdWNlZERpbShzY2UxMHgsIAogICAgICAgICAgICAgICAgICAgIm1ubl9jb3JyZWN0ZWQiKSwKICAgICAgICBtZXRyaWMgPSAiY29zaW5lIiwKICAgICAgICByZXRfbm4gPSBUUlVFKQpgYGAKCmBgYHtyfQpzZXQuc2VlZCg0MikKc2NlMTB4X3VtYXAgPC0KICB1bWFwKHJlZHVjZWREaW0oc2NlMTB4LAogICAgICAgICAgICAgICAgICAibW5uX2NvcnJlY3RlZCIpLAogICAgbWV0cmljID0gImNvc2luZSIsCiAgICBubl9tZXRob2QgPSBzY2UxMHhfdHVtYXAkbm4sCiAgICBhID0gLjgsCiAgICBiID0gLjU1CiAgKQpjb2xuYW1lcyhzY2UxMHhfdW1hcCkgPC0gcGFzdGUwKCJ1bWFwIiwgc2VxKDEsIDIpKQpyZWR1Y2VkRGltKHNjZTEweCwgIm1ubl91bWFwIikgPC0gc2NlMTB4X3VtYXAKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNH0KZHQgPC0KICBiaW5kX2NvbHMoCiAgICBjb2xEYXRhKHNjZTEweCkgJT4lCiAgICAgIGFzX3RpYmJsZSgpLAogICAgc2NlMTB4X3VtYXAgJT4lCiAgICAgIGFzX3RpYmJsZSgpCiAgKQpwMiA8LQogIGdncGxvdChkdCkgKwogIGdlb21fcG9pbnQoYWVzKHVtYXAxLAogICAgdW1hcDIsCiAgICBjb2xvdXIgPSBjbHVzdGVyc19sZXZlbDEKICApLAogIHNpemUgPSAuNiwKICBhbHBoYSA9IDEKICApICMrIGZhY2V0X3dyYXAofmNvbmRpdGlvbikKcDIgCmdnc2F2ZShmaWxlLnBhdGgoZmlndXJlc19kaXIsICJtbm5fdW1hcC5wZGYiKSwgcDIgKQpgYGAKCgoKCgojIyBDbHVzdGVyIHN0ZW0gY2VsbHMKCmBgYHtyfQpzY2UxMHhfc3RlbSA8LSBzY2UxMHhbLGNvbERhdGEoc2NlMTB4KSRjbHVzdGVyc19sZXZlbDEgPT0ic3RlbSJdCmBgYAoKCgpgYGB7cn0Kc2V0LnNlZWQoNDIpCiMgdC1VTUFQIGlzIGVxdWl2YWxlbnQgdG8gYSA9IDEsIGIgPSAxCiMgZ2V0IHRoZSBuZWFyZXN0IG5laWdoYm9yIGRhdGEgYmFjawpzY2UxMHhfc3RlbV90dW1hcCA8LQogIHR1bWFwKHJlZHVjZWREaW0oc2NlMTB4X3N0ZW0sIAogICAgICAgICAgICAgICAgICAgIm1ubl9jb3JyZWN0ZWQiKSwKICAgICAgICBtZXRyaWMgPSAiY29zaW5lIiwKICAgICAgICByZXRfbm4gPSBUUlVFKQpgYGAKCmBgYHtyfQpzZXQuc2VlZCg0MikKc2NlMTB4X3N0ZW1fdW1hcCA8LQogIHVtYXAocmVkdWNlZERpbShzY2UxMHhfc3RlbSwKICAgICAgICAgICAgICAgICAgIm1ubl9jb3JyZWN0ZWQiKSwKICAgIG1ldHJpYyA9ICJjb3NpbmUiLAogICAgbm5fbWV0aG9kID0gc2NlMTB4X3N0ZW1fdHVtYXAkbm4sCiAgICBhID0gLjg1LAogICAgYiA9IC40MwogICkKY29sbmFtZXMoc2NlMTB4X3N0ZW1fdW1hcCkgPC0gcGFzdGUwKCJ1bWFwIiwgc2VxKDEsIDIpKQpyZWR1Y2VkRGltKHNjZTEweF9zdGVtLCAibW5uX3VtYXAiKSA8LSBzY2UxMHhfc3RlbV91bWFwCmBgYAoKYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE0fQpkdCA8LQogIGJpbmRfY29scygKICAgIGNvbERhdGEoc2NlMTB4X3N0ZW0pICU+JQogICAgICBhc190aWJibGUoKSwKICAgIHNjZTEweF9zdGVtX3VtYXAgJT4lCiAgICAgIGFzX3RpYmJsZSgpCiAgKQpwMiA8LQogIGdncGxvdChkdCkgKwogIGdlb21fcG9pbnQoYWVzKHVtYXAxLAogICAgdW1hcDIsCiAgICBjb2xvdXIgPSBjbHVzdGVyc19sZXZlbDIKICApLAogIHNpemUgPSAxLAogIGFscGhhID0uNgogICkKcDIKIyBnZ3NhdmUoZmlsZS5wYXRoKGZpZ3VyZXNfZGlyLCAidW1hcF9jb3NpbmVfYTE2MF9iMzNfMTc5MjhfY2VsbHNfbWFya2Vycy5wZGYiKSwgcDIgKQpgYGAKCgoKYGBge3J9CnNldC5zZWVkKDQyKQpnIDwtIGJ1aWxkU05OR3JhcGgoc2NlMTB4X3N0ZW0sIGsgPSAxMDAsIHVzZS5kaW1yZWQgPSAibW5uX3VtYXAiKQpjbHVzdGVyc19vdXQgPC0gaWdyYXBoOjpjbHVzdGVyX3dhbGt0cmFwKGcpCmBgYAoKYGBge3J9CmlncmFwaF9jbHVzdGVycyA8LSBmYWN0b3IoY2x1c3RlcnNfb3V0JG1lbWJlcnNoaXApCnRhYmxlKGlncmFwaF9jbHVzdGVycykKYGBgCgpgYGB7cn0KaWdyYXBoX2NsdXN0ZXJzIDwtIGlncmFwaDo6Y3V0X2F0KGNsdXN0ZXJzX291dCwgbiA9IDUpCnRhYmxlKGlncmFwaF9jbHVzdGVycykKYGBgCgoKYGBge3J9CmRpc2NhcmRfY2VsbCA8LSBzY2UxMHhfc3RlbV91bWFwWywxXSA8IC0xMCB8IHNjZTEweF9zdGVtX3VtYXBbLDFdID4gMjIgIHwgKGlncmFwaF9jbHVzdGVycyA9PTIgJiBjb2xEYXRhKHNjZTEweF9zdGVtKSRjb25kaXRpb249PSJhZ2VkIikKdGFibGUoZGlzY2FyZF9jZWxsKQpgYGAKCgoKYGBge3J9CmlncmFwaF9jbHVzdGVyc1tkaXNjYXJkX2NlbGxdIDwtIDYKYGBgCgoKYGBge3J9CmNsdXN0ZXJfYnlfbWFya2VyIDwtCiAgdGFibGUoaWdyYXBoX2NsdXN0ZXJzLCBjb2xEYXRhKHNjZTEweF9zdGVtKSRzYW1wbGUpCmNsdXN0ZXJfYnlfbWFya2VyCmBgYAoKCgpgYGB7cn0KY29sRGF0YShzY2UxMHhfc3RlbSkkY2x1c3RlcnMgPC0gZmFjdG9yKGlncmFwaF9jbHVzdGVycykKYGBgCgpgYGB7cn0Kc2NlMTB4X3N0ZW1fc3Vic2V0IDwtCiAgc2NlMTB4X3N0ZW1bLCBjb2xEYXRhKHNjZTEweF9zdGVtKSRjbHVzdGVycyE9Nl0KYGBgCgoKYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE0fQpkdCA8LQogIGJpbmRfY29scygKICAgIGNvbERhdGEoc2NlMTB4X3N0ZW1fc3Vic2V0KSAlPiUKICAgICAgYXNfdGliYmxlKCksCiAgICByZWR1Y2VkRGltKHNjZTEweF9zdGVtX3N1YnNldCwgIm1ubl91bWFwIikgJT4lCiAgICAgIGFzX3RpYmJsZSgpCiAgKQpwMiA8LQogIGdncGxvdChkdCkgKwogIGdlb21fcG9pbnQoYWVzKHVtYXAxLAogICAgdW1hcDIsCiAgICBjb2xvdXIgPSBjbHVzdGVycwogICksCiAgc2l6ZSA9IDEuNywKICBhbHBoYSA9IDEKICApCnAyICAjICsgZmFjZXRfd3JhcCh+Y2x1c3RlcnMpCmdnc2F2ZShmaWxlLnBhdGgoZmlndXJlc19kaXIsICJtbm5fdW1hcF9zdGVtLnBkZiIpLCBwMiApCmBgYAoKCgoKCgoKIyMgQ2x1c3RlciBmYXAgY2VsbHMKCmBgYHtyfQpzY2UxMHhfZmFwIDwtIHNjZTEweFssY29sRGF0YShzY2UxMHgpJGNsdXN0ZXJzX2xldmVsMSA9PSJmYXAiXQpgYGAKCgoKYGBge3J9CnNldC5zZWVkKDQyKQojIHQtVU1BUCBpcyBlcXVpdmFsZW50IHRvIGEgPSAxLCBiID0gMQojIGdldCB0aGUgbmVhcmVzdCBuZWlnaGJvciBkYXRhIGJhY2sKc2NlMTB4X2ZhcF90dW1hcCA8LQogIHR1bWFwKHJlZHVjZWREaW0oc2NlMTB4X2ZhcCwgCiAgICAgICAgICAgICAgICAgICAibW5uX2NvcnJlY3RlZCIpLAogICAgICAgIG1ldHJpYyA9ICJjb3NpbmUiLAogICAgICAgIHJldF9ubiA9IFRSVUUpCmBgYAoKYGBge3J9CnNldC5zZWVkKDQyKQpzY2UxMHhfZmFwX3VtYXAgPC0KICB1bWFwKHJlZHVjZWREaW0oc2NlMTB4X2ZhcCwKICAgICAgICAgICAgICAgICAgIm1ubl9jb3JyZWN0ZWQiKSwKICAgIG1ldHJpYyA9ICJjb3NpbmUiLAogICAgbm5fbWV0aG9kID0gc2NlMTB4X2ZhcF90dW1hcCRubiwKICAgIGEgPSAuOSwKICAgIGIgPSAuNzUKICApCmNvbG5hbWVzKHNjZTEweF9mYXBfdW1hcCkgPC0gcGFzdGUwKCJ1bWFwIiwgc2VxKDEsIDIpKQpyZWR1Y2VkRGltKHNjZTEweF9mYXAsICJtbm5fdW1hcCIpIDwtIHNjZTEweF9mYXBfdW1hcApgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xNH0KZHQgPC0KICBiaW5kX2NvbHMoCiAgICBjb2xEYXRhKHNjZTEweF9mYXApICU+JQogICAgICBhc190aWJibGUoKSwKICAgIHNjZTEweF9mYXBfdW1hcCAlPiUKICAgICAgYXNfdGliYmxlKCkKICApCnAyIDwtCiAgZ2dwbG90KGR0KSArCiAgZ2VvbV9wb2ludChhZXModW1hcDEsCiAgICB1bWFwMiwKICAgIGNvbG91ciA9IGNsdXN0ZXJzX2xldmVsMgogICksCiAgc2l6ZSA9IDEsCiAgYWxwaGEgPS42CiAgKQpwMgojIGdnc2F2ZShmaWxlLnBhdGgoZmlndXJlc19kaXIsICJ1bWFwX2Nvc2luZV9hMTYwX2IzM18xNzkyOF9jZWxsc19tYXJrZXJzLnBkZiIpLCBwMiApCmBgYAoKCgpgYGB7cn0Kc2V0LnNlZWQoNDIpCmcgPC0gYnVpbGRTTk5HcmFwaChzY2UxMHhfZmFwLCBrID0gMTAwLCB1c2UuZGltcmVkID0gIm1ubl91bWFwIikKY2x1c3RlcnNfb3V0IDwtIGlncmFwaDo6Y2x1c3Rlcl93YWxrdHJhcChnKQpgYGAKCmBgYHtyfQppZ3JhcGhfY2x1c3RlcnMgPC0gZmFjdG9yKGNsdXN0ZXJzX291dCRtZW1iZXJzaGlwKQp0YWJsZShpZ3JhcGhfY2x1c3RlcnMpCmBgYAoKYGBge3J9CmlncmFwaF9jbHVzdGVycyA8LSBpZ3JhcGg6OmN1dF9hdChjbHVzdGVyc19vdXQsIG4gPSAzKQp0YWJsZShpZ3JhcGhfY2x1c3RlcnMpCmBgYAoKCmBgYHtyfQpkaXNjYXJkX2NlbGwgPC0gIHNjZTEweF9mYXBfdW1hcFssMV0gPiA1CnRhYmxlKGRpc2NhcmRfY2VsbCkKYGBgCgoKCmBgYHtyfQppZ3JhcGhfY2x1c3RlcnNbZGlzY2FyZF9jZWxsXSA8LSA0CmBgYAoKCmBgYHtyfQpjbHVzdGVyX2J5X21hcmtlciA8LQogIHRhYmxlKGlncmFwaF9jbHVzdGVycywgY29sRGF0YShzY2UxMHhfZmFwKSRzYW1wbGUpCmNsdXN0ZXJfYnlfbWFya2VyCmBgYAoKCgpgYGB7cn0KY29sRGF0YShzY2UxMHhfZmFwKSRjbHVzdGVycyA8LSBmYWN0b3IoaWdyYXBoX2NsdXN0ZXJzKQpgYGAKCmBgYHtyfQpzY2UxMHhfZmFwX3N1YnNldCA8LQogIHNjZTEweF9mYXBbLCBjb2xEYXRhKHNjZTEweF9mYXApJGNsdXN0ZXJzIT00XQpgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTR9CmR0IDwtCiAgYmluZF9jb2xzKAogICAgY29sRGF0YShzY2UxMHhfZmFwX3N1YnNldCkgJT4lCiAgICAgIGFzX3RpYmJsZSgpLAogICAgcmVkdWNlZERpbShzY2UxMHhfZmFwX3N1YnNldCwgIm1ubl91bWFwIikgJT4lCiAgICAgIGFzX3RpYmJsZSgpCiAgKQpwMiA8LQogIGdncGxvdChkdCkgKwogIGdlb21fcG9pbnQoYWVzKHVtYXAxLAogICAgdW1hcDIsCiAgICBjb2xvdXIgPSBjbHVzdGVycwogICksCiAgc2l6ZSA9IDEuNywKICBhbHBoYSA9IDEKICApCnAyICAjICsgZmFjZXRfd3JhcCh+Y2x1c3RlcnMpCmdnc2F2ZShmaWxlLnBhdGgoZmlndXJlc19kaXIsICJtbm5fdW1hcF9mYXAucGRmIiksIHAyICkKYGBgCgoKCiMjIENsdXN0ZXIgbWFjcm9waGFnZSBjZWxscwoKYGBge3J9CnNjZTEweF9tYWNyb3BoYWdlIDwtIHNjZTEweFssY29sRGF0YShzY2UxMHgpJGNsdXN0ZXJzX2xldmVsMSA9PSJtYWNyb3BoYWdlIl0KYGBgCgoKCmBgYHtyfQpzZXQuc2VlZCg0MikKIyB0LVVNQVAgaXMgZXF1aXZhbGVudCB0byBhID0gMSwgYiA9IDEKIyBnZXQgdGhlIG5lYXJlc3QgbmVpZ2hib3IgZGF0YSBiYWNrCnNjZTEweF9tYWNyb3BoYWdlX3R1bWFwIDwtCiAgdHVtYXAocmVkdWNlZERpbShzY2UxMHhfbWFjcm9waGFnZSwgCiAgICAgICAgICAgICAgICAgICAibW5uX2NvcnJlY3RlZCIpLAogICAgICAgIG1ldHJpYyA9ICJjb3NpbmUiLAogICAgICAgIHJldF9ubiA9IFRSVUUpCmBgYAoKYGBge3J9CnNldC5zZWVkKDQyKQpzY2UxMHhfbWFjcm9waGFnZV91bWFwIDwtCiAgdW1hcChyZWR1Y2VkRGltKHNjZTEweF9tYWNyb3BoYWdlLAogICAgICAgICAgICAgICAgICAibW5uX2NvcnJlY3RlZCIpLAogICAgbWV0cmljID0gImNvc2luZSIsCiAgICBubl9tZXRob2QgPSBzY2UxMHhfbWFjcm9waGFnZV90dW1hcCRubiwKICAgIGEgPSAwLjc1LAogICAgYiA9IDAuNjUKICApCmNvbG5hbWVzKHNjZTEweF9tYWNyb3BoYWdlX3VtYXApIDwtIHBhc3RlMCgidW1hcCIsIHNlcSgxLCAyKSkKcmVkdWNlZERpbShzY2UxMHhfbWFjcm9waGFnZSwgIm1ubl91bWFwIikgPC0gc2NlMTB4X21hY3JvcGhhZ2VfdW1hcApgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xNH0KZHQgPC0KICBiaW5kX2NvbHMoCiAgICBjb2xEYXRhKHNjZTEweF9tYWNyb3BoYWdlKSAlPiUKICAgICAgYXNfdGliYmxlKCksCiAgICBzY2UxMHhfbWFjcm9waGFnZV91bWFwICU+JQogICAgICBhc190aWJibGUoKQogICkKcDIgPC0KICBnZ3Bsb3QoZHQpICsKICBnZW9tX3BvaW50KGFlcyh1bWFwMSwKICAgIHVtYXAyLAogICAgY29sb3VyID0gY2x1c3RlcnNfbGV2ZWwyCiAgKSwKICBzaXplID0gMSwKICBhbHBoYSA9LjYKICApCnAyCiMgZ2dzYXZlKGZpbGUucGF0aChmaWd1cmVzX2RpciwgInVtYXBfY29zaW5lX2ExNjBfYjMzXzE3OTI4X2NlbGxzX21hcmtlcnMucGRmIiksIHAyICkKYGBgCgoKCmBgYHtyfQpzZXQuc2VlZCg0MikKZyA8LSBidWlsZFNOTkdyYXBoKHNjZTEweF9tYWNyb3BoYWdlLCBrID0gNTAsIHVzZS5kaW1yZWQgPSAibW5uX3VtYXAiKQpjbHVzdGVyc19vdXQgPC0gaWdyYXBoOjpjbHVzdGVyX3dhbGt0cmFwKGcpCmBgYAoKYGBge3J9CmlncmFwaF9jbHVzdGVycyA8LSBmYWN0b3IoY2x1c3RlcnNfb3V0JG1lbWJlcnNoaXApCnRhYmxlKGlncmFwaF9jbHVzdGVycykKYGBgCgpgYGB7cn0KaWdyYXBoX2NsdXN0ZXJzIDwtIGlncmFwaDo6Y3V0X2F0KGNsdXN0ZXJzX291dCwgbiA9IDUpCnRhYmxlKGlncmFwaF9jbHVzdGVycykKYGBgCgoKYGBge3J9CmNsdXN0ZXJfYnlfbWFya2VyIDwtCiAgdGFibGUoaWdyYXBoX2NsdXN0ZXJzLCBjb2xEYXRhKHNjZTEweF9tYWNyb3BoYWdlKSRzYW1wbGUpCmNsdXN0ZXJfYnlfbWFya2VyCmBgYAoKCgpgYGB7cn0KY29sRGF0YShzY2UxMHhfbWFjcm9waGFnZSkkY2x1c3RlcnMgPC0gZmFjdG9yKGlncmFwaF9jbHVzdGVycykKYGBgCgpgYGB7cn0Kc2NlMTB4X21hY3JvcGhhZ2Vfc3Vic2V0IDwtCiAgc2NlMTB4X21hY3JvcGhhZ2VbLCBjb2xEYXRhKHNjZTEweF9tYWNyb3BoYWdlKSRjbHVzdGVycyAlaW4lIGMoMSwyLCAzKV0KYGBgCgoKYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTE0fQpkdCA8LQogIGJpbmRfY29scygKICAgIGNvbERhdGEoc2NlMTB4X21hY3JvcGhhZ2Vfc3Vic2V0KSAlPiUKICAgICAgYXNfdGliYmxlKCksCiAgICByZWR1Y2VkRGltKHNjZTEweF9tYWNyb3BoYWdlX3N1YnNldCwgIm1ubl91bWFwIikgJT4lCiAgICAgIGFzX3RpYmJsZSgpCiAgKQpwMiA8LQogIGdncGxvdChkdCkgKwogIGdlb21fcG9pbnQoYWVzKHVtYXAxLAogICAgdW1hcDIsCiAgICBjb2xvdXIgPSBjbHVzdGVycwogICksCiAgc2l6ZSA9IDEuNywKICBhbHBoYSA9IDEKICApCnAyICAjICsgZmFjZXRfd3JhcCh+Y2x1c3RlcnMpCmdnc2F2ZShmaWxlLnBhdGgoZmlndXJlc19kaXIsICJtbm5fdW1hcF9tYWNyb3BoYWdlLnBkZiIpLCBwMiApCmBgYAoKCgojIyBTYXZlIGRhdGEKCgpgYGB7cn0KbWV0YV9kdCA8LQogIHJiaW5kKGNvbERhdGEoc2NlMTB4X3N0ZW1fc3Vic2V0KSwgY29sRGF0YShzY2UxMHhfZmFwX3N1YnNldCksIGNvbERhdGEoc2NlMTB4X21hY3JvcGhhZ2Vfc3Vic2V0KSkgJT4lCiAgYXNfdGliYmxlKHJvd25hbWVzID0gImNlbGwiKSAlPiUKICBtdXRhdGUoY2x1c3Rlcl9sZXZlbDFfMT0gcGFzdGUoY2x1c3RlcnNfbGV2ZWwxLCBjbHVzdGVycywgc2VwPSJfIiApLAogICAgICAgICBjbHVzdGVyX2xldmVsMl8xPSBwYXN0ZShjbHVzdGVyc19sZXZlbDIsIGNsdXN0ZXJzLCBzZXA9Il8iICkpICU+JQogIHNlbGVjdChjZWxsLCBjbHVzdGVyX2xldmVsMV8xLCBjbHVzdGVyX2xldmVsMl8xICkKbWV0YV9kdApgYGAKCmBgYHtyfQpjb2xEYXRhKHNjZTEweCkgPC0KICBsZWZ0X2pvaW4oY29sRGF0YShzY2UxMHgpJT4lCiAgYXNfdGliYmxlKHJvd25hbWVzID0gImNlbGwiKSwKICBtZXRhX2R0LAogIGJ5PSJjZWxsIikgJT4lCiAgcmVwbGFjZV9uYShsaXN0KGNsdXN0ZXJfbGV2ZWwyXzEgPSAiZGlzY2FyZCIsIGNsdXN0ZXJfbGV2ZWwxXzEgPSAiZGlzY2FyZCIpKSAlPiUKICBzZWxlY3QoLWNsdXN0ZXJzKSAlPiUKICBjb2x1bW5fdG9fcm93bmFtZXMoImNlbGwiKSAlPiUKICBEYXRhRnJhbWUoLikKCmBgYCAKCmBgYHtyfQpkaXNjYXJkX2lkeCA8LSAKICBjb2xEYXRhKHNjZTEweCkkY2x1c3Rlcl9sZXZlbDJfMSA9PSAiZGlzY2FyZCIKdGFibGUoZGlzY2FyZF9pZHgpCmBgYAoKCmBgYHtyfQpzY2UxMHggPC0gc2NlMTB4WywgIWRpc2NhcmRfaWR4XQpgYGAKCmBgYHtyfQpuX2V4cHJzX2dlbmVzIDwtCiAgbmV4cHJzKHNjZTEweCwKICAgIGRldGVjdGlvbl9saW1pdCA9IDAsCiAgICBieXJvdyA9IFRSVUUKICApCnRhYmxlKG5fZXhwcnNfZ2VuZXMpWzE6MjBdCmBgYAoKYGBge3J9CnNjZTEweCA8LSBzY2UxMHhbbl9leHByc19nZW5lcz4wLCBdCmBgYAoKCgpgYGB7cn0Kc2F2ZVJEUygKICBzY2UxMHgsCiAgZmlsZS5wYXRoKAogICAgZGF0YV9kaXIsCiAgICAicHJlcHJvY2Vzc2VkIiwKICAgICJzY2UxMHhfZmlsdGVyZWRfZmluYWwucmRzIgogICkKKQpgYGAKCiMjIG1ha2UgcGxvdHMKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE0fQpkdCA8LQogIGJpbmRfY29scygKICAgIGNvbERhdGEoc2NlMTB4KSAlPiUKICAgICAgYXNfdGliYmxlKCksCiAgICByZWR1Y2VkRGltKHNjZTEweCwgIm1ubl91bWFwIikgJT4lCiAgICAgIGFzX3RpYmJsZSgpCiAgKQpwMiA8LQogIGdncGxvdChkdCkgKwogIGdlb21fcG9pbnQoYWVzKHVtYXAxLAogICAgdW1hcDIsCiAgICBjb2xvdXIgPSBjbHVzdGVyX2xldmVsMV8xCiAgKSwKICBzaXplID0gLjYsCiAgYWxwaGEgPSAxCiAgKSArIGZhY2V0X3dyYXAofmNvbmRpdGlvbikKcDIgCmdnc2F2ZShmaWxlLnBhdGgoZmlndXJlc19kaXIsICJtbm5fdW1hcF9zcGxpdC5wZGYiKSwgcDIgKQpgYGAKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAo=