library(plyr)
library(dplyr)
library(data.table)
library(ggplot2)
library(pheatmap)
library(methods)
library(grid)
library(reshape2)
library(nlme)
library(stringr)
library(psych)
library(tibble)
library(cluster)

library(metautils)
library(ithi.meta)
library(clonecluster)
library(paperutils)

Colour palettes

pal_patient <- select_palette("patient")

Parameters

db_path <- snakemake@params$db
cluster_label_file <- snakemake@input$cluster_labels
## For sample labels and plotting
data_matrix_file <- snakemake@input$data_matrix

Metadata

db <- src_sqlite(db_path, create = FALSE)
samples <- collect(tbl(db, "samples"))

Clusters

cluster_labels <- fread(cluster_label_file)
data_matrix <- fread(data_matrix_file)

mat <- as.matrix(cluster_labels)
rownames(mat) <- data_matrix$condensed_id

cluster_pct <- mat/rowSums(mat, na.rm = TRUE)
remove_ind <- apply(cluster_pct, 1, function(x) all(is.na(x)))
cluster_pct <- cluster_pct[!remove_ind, ]

Number of samples: 56.

Selecting k

cluster_counts <- 2:7
kmeans_results <- lapply(cluster_counts, function(k) {
    kmeans(cluster_pct, centers = k, iter.max = 500, nstart = 50)
})
silwidths <- sapply(kmeans_results, function(x) {
    mean(silhouette(x$cluster, dist(cluster_pct))[, "sil_width"])
})
withinss <- sapply(kmeans_results, function(x) {
    sum(x$withinss)
})

clustdf <- data.frame(nclust = cluster_counts, silhouette = silwidths, withinss = withinss)
clustdf_melted <- melt(clustdf, id.vars = "nclust", measure.vars = c("silhouette", 
    "withinss"), variable.name = "metric", value.name = "value")
ggplot(clustdf_melted, aes(x = nclust, y = value)) + geom_point() + theme_bw() + 
    theme_Publication() + facet_wrap(~metric, scales = "free")

It’s quite abundantly clear that 3 is the optimal number of clusters, by both the silhouette and elbow rule.

cluster_labels <- kmeans_results[[which(cluster_counts == 3)]]$cluster
cluster_labels_df <- rownames_to_column(data.frame(cluster_labels), "condensed_id")

Heatmap

data_matrix <- merge(data_matrix, cluster_labels_df, by = c("condensed_id"))
data_matrix$cluster_labels <- factor(data_matrix$cluster_labels)

data_matrix_subset <- subset(data_matrix, select = -c(condensed_id, cluster_labels))
datmat <- as.matrix(clip_values(scale(data_matrix_subset), 2, -2))
rownames(datmat) <- data_matrix$condensed_id

tmp <- scale(data_matrix_subset)
dists <- as.dist((1 - cor(tmp, use = "pairwise.complete"))/2)
hc <- hclust(dists, method = "ward.D")

annotation_row <- data.frame(data_matrix$cluster_labels)
rownames(annotation_row) <- data_matrix$condensed_id

annotation_colors <- list(cluster_labels = get_colour_palette(data_matrix$cluster_labels))

pheatmap(datmat[order(data_matrix$cluster_labels), hc$order], cluster_rows = FALSE, 
    cluster_cols = FALSE, annotation_row = annotation_row, annotation_colors = annotation_colors)

This doesn’t look that great …

Might have to do with the fact that the clonal analysis view isn’t accurate still (divergence will throw things off).

Plain hierarchical clustering

dists2 <- as.dist((1 - cor(t(tmp), use = "pairwise.complete"))/2)
hc2 <- hclust(dists2, method = "ward.D")
pheatmap(datmat[hc2$order, hc$order], cluster_rows = FALSE, cluster_cols = FALSE)

LS0tCnRpdGxlOiAiTXVsdGktdmlldyBjbHVzdGVyaW5nIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogNQogICAgdG9jX2Zsb2F0OiB0cnVlCnBhcmFtczoKICBybWQ6ICJtdWx0aXZpZXdjbHVzdGVyaW5nLlJtZCIKLS0tCiAgICAgICAgICAgICAgICAgICAgICAgIGBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyMjIyMjIyMgU25ha2VtYWtlIGhlYWRlciAjIyMjIyMjIwpsaWJyYXJ5KG1ldGhvZHMpClNuYWtlbWFrZSA8LSBzZXRDbGFzcygKICAgICJTbmFrZW1ha2UiLAogICAgc2xvdHMgPSBjKAogICAgICAgIGlucHV0ID0gImxpc3QiLAogICAgICAgIG91dHB1dCA9ICJsaXN0IiwKICAgICAgICBwYXJhbXMgPSAibGlzdCIsCiAgICAgICAgd2lsZGNhcmRzID0gImxpc3QiLAogICAgICAgIHRocmVhZHMgPSAibnVtZXJpYyIsCiAgICAgICAgbG9nID0gImxpc3QiLAogICAgICAgIHJlc291cmNlcyA9ICJsaXN0IiwKICAgICAgICBjb25maWcgPSAibGlzdCIsCiAgICAgICAgcnVsZSA9ICJjaGFyYWN0ZXIiCiAgICApCikKc25ha2VtYWtlIDwtIFNuYWtlbWFrZSgKICAgIGlucHV0ID0gbGlzdCgnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvaW50ZXJtZWRpYXRlcy9ydW4yL2NsdXN0ZXJpbmcvaXZtdm5tZl9jbHVzdHMuY3N2JywgJ1JtZC9tdWx0aXZpZXdjbHVzdGVyaW5nLlJtZCcsICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjIvY2x1c3RlcmluZy9kYXRhX21hdHJpeC50c3YnLCAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL2FuYWx5c2lzL1JtZC9fc2l0ZS55bWwnLCAiY2x1c3Rlcl9sYWJlbHMiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL2ludGVybWVkaWF0ZXMvcnVuMi9jbHVzdGVyaW5nL2l2bXZubWZfY2x1c3RzLmNzdicsICJub3RlYm9vayIgPSAnUm1kL211bHRpdmlld2NsdXN0ZXJpbmcuUm1kJywgImRhdGFfbWF0cml4IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvcmVzdWx0cy9pbnRlcm1lZGlhdGVzL3J1bjIvY2x1c3RlcmluZy9kYXRhX21hdHJpeC50c3YnLCAic2l0ZV9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvYW5hbHlzaXMvUm1kL19zaXRlLnltbCcpLAogICAgb3V0cHV0ID0gbGlzdCgnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvd2ViL211bHRpdmlld2NsdXN0ZXJpbmcubmIuaHRtbCcpLAogICAgcGFyYW1zID0gbGlzdCgnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL21ldGFkYXRhL2RiL2ltbXVuZV9wcm9qZWN0LnNxbGl0ZTMnLCAnaXRoaS1hbmFseXNpcy1tdWx0aW1vZGFsLWNsdXN0ZXJpbmcnLCAiZGIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9tZXRhZGF0YS9kYi9pbW11bmVfcHJvamVjdC5zcWxpdGUzJywgIm5hbWUiID0gJ2l0aGktYW5hbHlzaXMtbXVsdGltb2RhbC1jbHVzdGVyaW5nJyksCiAgICB3aWxkY2FyZHMgPSBsaXN0KCksCiAgICB0aHJlYWRzID0gMSwKICAgIGxvZyA9IGxpc3QoJy9zaGFobGFiL2FsemhhbmcvY2x1c3R0bXAvcGFwZXJhbmFseXNpczIvbXVsdGltb2RhbF9jbHVzdGVyaW5nLmxvZycpLAogICAgcmVzb3VyY2VzID0gbGlzdCgpLAogICAgY29uZmlnID0gbGlzdCgiYmNyX2RpdmVyc2l0eSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L3Bvc3Rwcm9jZXNzL0lHSC9wb3N0ZmlsdGVyX2RpdmVyc2l0eV9zdGF0cy9kaXZlcnNpdHkuc3RyaWN0LnJlc2FtcGxlZC50eHQnLCAiY2xhc3NpZmllcl90eXBlIiA9ICdkbGRhJywgInhjcl9xY19ub3RlYm9vayIgPSAnUm1kL3JlcGxpY2F0ZXMuUm1kJywgInBoZW5vdHlwZV90aHJlc2hvbGQiID0gMC44NSwgIml0aF90aWxfbm90ZWJvb2siID0gJ1JtZC9pdGhfdGlsX2RlbnNpdGllcy5SbWQnLCAibG9nZGlyIiA9ICcvc2hhaGxhYi9hbHpoYW5nL2NsdXN0dG1wL3BhcGVyYW5hbHlzaXMyJywgIm5hbm9zdHJpbmdfc2lnbmF0dXJlX25vdGVib29rIiA9ICdSbWQvbmFub3N0cmluZ19zaWduYXR1cmVzLlJtZCcsICJub3RlYm9va19kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3dlYicsICJ0aWxzX2Zvcl9jbHVzdGVyIiA9IGMoJ0VfQ0Q4X2RlbnNpdHknLCAnRV9DRDRfZGVuc2l0eScsICdFX0NEMjBfZGVuc2l0eScsICdFX1BsYXNtYV9kZW5zaXR5JyksICJiY3JwaHlsb19leGFtcGxlc19ub3RlYm9vayIgPSAnUm1kL2Jjcl9waHlsb19leGFtcGxlcy5SbWQnLCAic3VidHlwZV9tYXJrZXJfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9uYW5vc3RyaW5nL3N1YnR5cGVfbWFya2Vycy50c3YnLCAiZGIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9tZXRhZGF0YS9kYi9pbW11bmVfcHJvamVjdC5zcWxpdGUzJywgInZfZGljdGlvbmFyeSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3N1YnByb2plY3RzL2ltbXR5cGVyL21ldGFkYXRhL2ltZ3QvSG9tb19zYXBpZW5zX1RSQlYuZmFzdGEnLCAibXVsdGl2aWV3Y2x1c3RlcmluZ19ub3RlYm9vayIgPSAnUm1kL211bHRpdmlld2NsdXN0ZXJpbmcuUm1kJywgIm1vbHN1YnR5cGVfdGlsdHlwZXMiID0gYygnRV9DRDhfZGVuc2l0eScsICdFX0NENF9kZW5zaXR5JywgJ0VfQ0QyMF9kZW5zaXR5JywgJ0VfUGxhc21hX2RlbnNpdHknLCAnU19DRDhfZGVuc2l0eScsICdTX0NENF9kZW5zaXR5JywgJ1NfQ0QyMF9kZW5zaXR5JywgJ1NfUGxhc21hX2RlbnNpdHknKSwgImltbXR5cGVyX2xlbmd0aHMiID0gJzExIDEyIDEzIDE0IDE1IDE2IDE3IDE4JywgInhjcl9jbG9uZXNfbm90ZWJvb2siID0gJ1JtZC94Y3JfY2xvbmVzX2FuYWx5c2lzLlJtZCcsICJrbm93bl9zdWJ0eXBlX2ZpbGUiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9kYXRhL2V4cHJlc3Npb24vYXJyYXkvc3VidHlwZXMva25vd25fc3VidHlwZXMudHN2JywgInRjcl9jbG9ub3R5cGVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9taXhjci9taXhjcl9ydW5zL2l0aF8xXzJfMy9taXhjcjUvY2xvbm90eXBlcy9UUkJfY2xvbm90eXBlc19maWx0ZXJlZC50eHQnLCAibW9sc3VidHlwZV9ub3RlYm9vayIgPSAnUm1kL21vbGVjdWxhcl9zdWJ0eXBlcy5SbWQnLCAiaXRoX3N0YXRpc3RpY3Nfbm90ZWJvb2siID0gJ1JtZC9pdGhfc3RhdGlzdGljcy5SbWQnLCAibGlicmFyeV9zaXplcyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvbWl4Y3IvbWl4Y3JfcnVucy9pdGhfMV8yXzMvbWl4Y3I1L2xpYnJhcnlfc2l6ZXMudHN2JywgImpfZGljdGlvbmFyeSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3N1YnByb2plY3RzL2ltbXR5cGVyL21ldGFkYXRhL2ltZ3QvSG9tb19zYXBpZW5zX1RSQkouZmFzdGEnLCAic2l0ZV9maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvcGFwZXIvYW5hbHlzaXMvUm1kL19zaXRlLnltbCcsICJtdmNsdXN0X3RpbHR5cGVzIiA9IGMoJ0VfQ0Q4X2RlbnNpdHknLCAnRV9DRDRfZGVuc2l0eScsICdFX0NEMjBfZGVuc2l0eScsICdFX1BsYXNtYV9kZW5zaXR5JywgJ1NfQ0Q4X2RlbnNpdHknLCAnU19DRDRfZGVuc2l0eScsICdTX0NEMjBfZGVuc2l0eScsICdTX1BsYXNtYV9kZW5zaXR5JyksICJpbW10eXBlcl9tb2RlbHMiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL2ltbXR5cGVyX3Jlc3VsdHMva2xhcmVuYmVlay9hYV92ai9ncmFkYm9vc3QnLCAicHJldmFsZW5jZV90aHJlc2hvbGQiID0gMC4wMSwgImloY19ydW4xIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9paGMvY2Q4Y2QzY2QyMC92YWxpZGF0ZWRfc3RhdHNfd2VpZ2h0ZWQucmRhdGEnLCAidmFyaWFiaWxpdHlfdHlwZSIgPSAnc3RhYmlsaXplJywgImNsb25lX2JyYW5jaF9sZW5ndGhfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL2NvbXBsZXRlL2JyYW5jaF9kYXRhLnRzdicsICJ0YWJsZV9kaXIiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9wYXBlci9yZXN1bHRzL3RhYmxlcy9ydW4yJywgImJjcl9jbG9ub3R5cGVzIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9taXhjci9taXhjcl9ydW5zL2l0aF8xXzJfMy9taXhjcjUvY2xvbm90eXBlcy9JR0hfY2xvbm90eXBlc19maWx0ZXJlZC50eHQnLCAiaW50ZXJtZWRpYXRlX2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL3BhcGVyL3Jlc3VsdHMvaW50ZXJtZWRpYXRlcy9ydW4yJywgInhjcl9tYXBwaW5nX25vdGVib29rIiA9ICdSbWQveGNyX21hcHBpbmcuUm1kJywgImJlbmNobWFya2RpciIgPSAnL3NoYWhsYWIvYWx6aGFuZy9iZW5jaG1hcmtzL3BhcGVyYW5hbHlzaXMyJywgIml0aF9zdGF0c19maWxlIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9pdGgvY29tcGxldGUvY2xvbmFsX21lYXN1cmVzLnRzdicsICJ0Y3JfZGl2ZXJzaXR5IiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9taXhjci9taXhjcl9ydW5zL2l0aF8xXzJfMy9taXhjcjUvcG9zdHByb2Nlc3MvVFJCL3Bvc3RmaWx0ZXJfZGl2ZXJzaXR5X3N0YXRzL2RpdmVyc2l0eS5zdHJpY3QucmVzYW1wbGVkLnR4dCcsICJleGFtcGxlX2Fubm90YXRpb25zIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9pZ3BhcnRpdGlvbi9ydW4xMy9maW5hbF9wYXJ0aXRpb25zL2l0aDJfMi9jbHVzdDkvYW5ub3RhdGlvbnNfZmxhZ2dlZC50c3YnLCAibmFub3N0cmluZ19hbm5vdGF0aW9ucyIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvZXhwcmVzc2lvbi9uYW5vc3RyaW5nL3BhbmNhbmNlcl9hbm5vdGF0aW9ucy50c3YnLCAidGlsX2NsYXNzaWZpZXJfbm90ZWJvb2siID0gJ1JtZC90aWxfY2xhc3NpZmllci5SbWQnLCAibXZjbHVzdF9uY2x1c3QiID0gMywgImNsb25lX3ByZXZhbGVuY2VfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL2NvbXBsZXRlL2Nsb25lX2RhdGEudHN2JywgImloY19ydW4yIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3Byb2plY3RzL0lUSF9JbW11bmUvZGF0YS9paGMvY2Q3OWNkMTM4Y2Q2OC92YWxpZGF0ZWRfc3RhdHNfd2VpZ2h0ZWQucmRhdGEnLCAiaW1tdW5lX3ZhcmlhYmlsaXR5X25vdGVib29rIiA9ICdSbWQvaW1tdW5lX3ZhcmlhYmlsaXR5LlJtZCcsICJuYW5vc3RyaW5nX2RhdGEiID0gJy9zaGFobGFiL2FsemhhbmcvcHJvamVjdHMvSVRIX0ltbXVuZS9yZXN1bHRzL25hbm9zdHJpbmdfcmVzdWx0cy9pdGhfZnVsbC9xYy9saW1tYV90bW0vbm9ybWFsaXplZF9leHByZXNzaW9uX3ZvYV9sYWJlbHMudHN2JywgInhjcl9kaXN0YW5jZV9tZXRob2QiID0gJ2hvcm4nLCAibmNsdXN0cyIgPSAyLCAiZXhhbXBsZV9tc2FfcGxvdCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvaWdwYXJ0aXRpb24vcnVuMTMvb2xkL2FsaWdubWVudF9wbG90cy9tc2EvaXRoMl8yL2NsdXN0OS9pbmRlbF9yZXZlcnNlZC5odG1sJywgImNsb25lX3RyZWVfZmlsZSIgPSAnL3NoYWhsYWIvYWx6aGFuZy9wcm9qZWN0cy9JVEhfSW1tdW5lL2RhdGEvaXRoL2NvbXBsZXRlL3RyZWVfZGF0YS50c3YnLCAidGlsc19mb3JfdmFyaWFiaWxpdHkiID0gYygnRV9DRDhfZGVuc2l0eScsICdFX0NENF9kZW5zaXR5JywgJ0VfQ0QyMF9kZW5zaXR5JywgJ0VfUGxhc21hX2RlbnNpdHknLCAnU19DRDhfZGVuc2l0eScsICdTX0NENF9kZW5zaXR5JywgJ1NfQ0QyMF9kZW5zaXR5JywgJ1NfUGxhc21hX2RlbnNpdHknKSwgInNwYXRpYWxfcmVzdWx0X2RpcnMiID0gbGlzdCgic3Ryb21hbCIgPSAnL3NoYWhsYWIvYWx6aGFuZy9waXBlbGluZV9vdXRwdXRzL2l0aF9pbW11bmUvc3BhdHNpbS9pdGg1L2FiYycsICJlcGl0aGVsaWFsIiA9ICcvc2hhaGxhYi9hbHpoYW5nL3BpcGVsaW5lX291dHB1dHMvaXRoX2ltbXVuZS9zcGF0c2ltL2l0aDMvYWJjJyksICJpbmRleF9ub3RlYm9vayIgPSAnUm1kL2luZGV4LlJtZCcsICJzcGF0aWFsX25vdGVib29rIiA9ICdSbWQvc3BhdGlhbF9hbmFseXNpcy5SbWQnKSwKICAgIHJ1bGUgPSAnbXVsdGltb2RhbF9jbHVzdGVyaW5nJwopCiMjIyMjIyMjIE9yaWdpbmFsIHNjcmlwdCAjIyMjIyMjIyMKCiAgICAgICAgICAgICAgICAgICAgICAgIGBgYAoKCmBgYHtyIGdsb2JhbF9jaHVua19vcHRpb25zLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHRpZHk9VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSkKYGBgCgoKYGBge3J9CmxpYnJhcnkocGx5cikKbGlicmFyeShkcGx5cikKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGhlYXRtYXApCmxpYnJhcnkobWV0aG9kcykKbGlicmFyeShncmlkKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KG5sbWUpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShwc3ljaCkKbGlicmFyeSh0aWJibGUpCmxpYnJhcnkoY2x1c3RlcikKCmxpYnJhcnkobWV0YXV0aWxzKQpsaWJyYXJ5KGl0aGkubWV0YSkKbGlicmFyeShjbG9uZWNsdXN0ZXIpCmxpYnJhcnkocGFwZXJ1dGlscykKYGBgCgojIyBDb2xvdXIgcGFsZXR0ZXMKCmBgYHtyfQpwYWxfcGF0aWVudCA8LSBzZWxlY3RfcGFsZXR0ZSgicGF0aWVudCIpCmBgYAoKIyMgUGFyYW1ldGVycwoKYGBge3J9CmRiX3BhdGggPC0gc25ha2VtYWtlQHBhcmFtcyRkYgpjbHVzdGVyX2xhYmVsX2ZpbGUgPC0gc25ha2VtYWtlQGlucHV0JGNsdXN0ZXJfbGFiZWxzCiMjIEZvciBzYW1wbGUgbGFiZWxzIGFuZCBwbG90dGluZwpkYXRhX21hdHJpeF9maWxlIDwtIHNuYWtlbWFrZUBpbnB1dCRkYXRhX21hdHJpeApgYGAKCiMjIE1ldGFkYXRhCgpgYGB7cn0KZGIgPC0gc3JjX3NxbGl0ZShkYl9wYXRoLCBjcmVhdGU9RkFMU0UpCnNhbXBsZXMgPC0gY29sbGVjdCh0YmwoZGIsICJzYW1wbGVzIikpCmBgYAoKIyMgQ2x1c3RlcnMKCmBgYHtyfQpjbHVzdGVyX2xhYmVscyA8LSBmcmVhZChjbHVzdGVyX2xhYmVsX2ZpbGUpCmRhdGFfbWF0cml4IDwtIGZyZWFkKGRhdGFfbWF0cml4X2ZpbGUpCgptYXQgPC0gYXMubWF0cml4KGNsdXN0ZXJfbGFiZWxzKQpyb3duYW1lcyhtYXQpIDwtIGRhdGFfbWF0cml4JGNvbmRlbnNlZF9pZAoKY2x1c3Rlcl9wY3QgPC0gbWF0L3Jvd1N1bXMobWF0LCBuYS5ybSA9IFRSVUUpCnJlbW92ZV9pbmQgPC0gYXBwbHkoY2x1c3Rlcl9wY3QsIDEsIGZ1bmN0aW9uKHgpIGFsbChpcy5uYSh4KSkpCmNsdXN0ZXJfcGN0IDwtIGNsdXN0ZXJfcGN0WyFyZW1vdmVfaW5kLF0KYGBgCgpOdW1iZXIgb2Ygc2FtcGxlczogYHIgbnJvdyhtYXQpYC4gCgojIyMgU2VsZWN0aW5nIGsKCmBgYHtyfQpjbHVzdGVyX2NvdW50cyA8LSAyOjcKa21lYW5zX3Jlc3VsdHMgPC0gbGFwcGx5KGNsdXN0ZXJfY291bnRzLCBmdW5jdGlvbihrKSB7CiAga21lYW5zKGNsdXN0ZXJfcGN0LCBjZW50ZXJzID0gaywgaXRlci5tYXggPSA1MDAsIG5zdGFydD01MCkKfSkKc2lsd2lkdGhzIDwtIHNhcHBseShrbWVhbnNfcmVzdWx0cywgZnVuY3Rpb24oeCkgewogIG1lYW4oc2lsaG91ZXR0ZSh4JGNsdXN0ZXIsIGRpc3QoY2x1c3Rlcl9wY3QpKVssInNpbF93aWR0aCJdKQp9KQp3aXRoaW5zcyA8LSBzYXBwbHkoa21lYW5zX3Jlc3VsdHMsIGZ1bmN0aW9uKHgpIHsKICBzdW0oeCR3aXRoaW5zcykKfSkKCmNsdXN0ZGYgPC0gZGF0YS5mcmFtZShuY2x1c3Q9Y2x1c3Rlcl9jb3VudHMsIHNpbGhvdWV0dGU9c2lsd2lkdGhzLCB3aXRoaW5zcz13aXRoaW5zcykKY2x1c3RkZl9tZWx0ZWQgPC0gbWVsdChjbHVzdGRmLCBpZC52YXJzID0gIm5jbHVzdCIsIG1lYXN1cmUudmFycyA9IGMoInNpbGhvdWV0dGUiLCAid2l0aGluc3MiKSwgdmFyaWFibGUubmFtZSA9ICJtZXRyaWMiLAogICAgIHZhbHVlLm5hbWUgPSAidmFsdWUiKQoKYGBgCgpgYGB7cn0KZ2dwbG90KGNsdXN0ZGZfbWVsdGVkLCBhZXMoeD1uY2x1c3QsIHk9dmFsdWUpKSArIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkgKyB0aGVtZV9QdWJsaWNhdGlvbigpICsgZmFjZXRfd3JhcCh+IG1ldHJpYywgc2NhbGVzPSAiZnJlZSIpCmBgYAoKCkl0J3MgcXVpdGUgYWJ1bmRhbnRseSBjbGVhciB0aGF0IDMgaXMgdGhlIG9wdGltYWwgbnVtYmVyIG9mIGNsdXN0ZXJzLCBieSBib3RoIHRoZSBzaWxob3VldHRlIGFuZCBlbGJvdyBydWxlLiAKCmBgYHtyfQpjbHVzdGVyX2xhYmVscyA8LSBrbWVhbnNfcmVzdWx0c1tbd2hpY2goY2x1c3Rlcl9jb3VudHMgPT0gMyldXSRjbHVzdGVyCmNsdXN0ZXJfbGFiZWxzX2RmIDwtIHJvd25hbWVzX3RvX2NvbHVtbihkYXRhLmZyYW1lKGNsdXN0ZXJfbGFiZWxzKSwgImNvbmRlbnNlZF9pZCIpCmBgYAoKIyMjIEhlYXRtYXAKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9Nn0KZGF0YV9tYXRyaXggPC0gbWVyZ2UoZGF0YV9tYXRyaXgsIGNsdXN0ZXJfbGFiZWxzX2RmLCBieT1jKCJjb25kZW5zZWRfaWQiKSkKZGF0YV9tYXRyaXgkY2x1c3Rlcl9sYWJlbHMgPC0gZmFjdG9yKGRhdGFfbWF0cml4JGNsdXN0ZXJfbGFiZWxzKQoKZGF0YV9tYXRyaXhfc3Vic2V0IDwtIHN1YnNldChkYXRhX21hdHJpeCwgc2VsZWN0PS1jKGNvbmRlbnNlZF9pZCwgY2x1c3Rlcl9sYWJlbHMpKQpkYXRtYXQgPC0gYXMubWF0cml4KGNsaXBfdmFsdWVzKHNjYWxlKGRhdGFfbWF0cml4X3N1YnNldCksIDIsIC0yKSkKcm93bmFtZXMoZGF0bWF0KSA8LSBkYXRhX21hdHJpeCRjb25kZW5zZWRfaWQKCnRtcCA8LSBzY2FsZShkYXRhX21hdHJpeF9zdWJzZXQpCmRpc3RzIDwtIGFzLmRpc3QoKDEtY29yKHRtcCwgdXNlID0gInBhaXJ3aXNlLmNvbXBsZXRlIikpLzIpCmhjIDwtIGhjbHVzdChkaXN0cywgbWV0aG9kID0gIndhcmQuRCIpCgphbm5vdGF0aW9uX3JvdyA8LSBkYXRhLmZyYW1lKGRhdGFfbWF0cml4JGNsdXN0ZXJfbGFiZWxzKQpyb3duYW1lcyhhbm5vdGF0aW9uX3JvdykgPC0gZGF0YV9tYXRyaXgkY29uZGVuc2VkX2lkCgphbm5vdGF0aW9uX2NvbG9ycyA8LSBsaXN0KGNsdXN0ZXJfbGFiZWxzPWdldF9jb2xvdXJfcGFsZXR0ZShkYXRhX21hdHJpeCRjbHVzdGVyX2xhYmVscykpCgpwaGVhdG1hcChkYXRtYXRbb3JkZXIoZGF0YV9tYXRyaXgkY2x1c3Rlcl9sYWJlbHMpLCBoYyRvcmRlcl0sIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCBjbHVzdGVyX2NvbHMgPSBGQUxTRSwgYW5ub3RhdGlvbl9yb3cgPSBhbm5vdGF0aW9uX3JvdywgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uX2NvbG9ycykKYGBgCgpUaGlzIGRvZXNuJ3QgbG9vayB0aGF0IGdyZWF0IC4uLgoKTWlnaHQgaGF2ZSB0byBkbyB3aXRoIHRoZSBmYWN0IHRoYXQgdGhlIGNsb25hbCBhbmFseXNpcyB2aWV3IGlzbid0IGFjY3VyYXRlIHN0aWxsIChkaXZlcmdlbmNlIHdpbGwgdGhyb3cgdGhpbmdzIG9mZikuIAoKIyMgUGxhaW4gaGllcmFyY2hpY2FsIGNsdXN0ZXJpbmcKCmBgYHtyfQpkaXN0czIgPC0gYXMuZGlzdCgoMS1jb3IodCh0bXApLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUiKSkvMikKaGMyIDwtIGhjbHVzdChkaXN0czIsIG1ldGhvZCA9ICJ3YXJkLkQiKQpwaGVhdG1hcChkYXRtYXRbaGMyJG9yZGVyLGhjJG9yZGVyXSwgY2x1c3Rlcl9yb3dzID0gRkFMU0UsIGNsdXN0ZXJfY29scyA9IEZBTFNFKQpgYGAKCgo8IS0tICMjIHQtU05FIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gZGF0IDwtIGRhdGFfbWF0cml4W2FwcGx5KGRhdGFfbWF0cml4LCAxLCBmdW5jdGlvbih4KSFhbnkoaXMubmEoeCkpKSxdIC0tPgoKPCEtLSBwYXRpZW50cyA8LSBtYXBfaWQoZGF0JGNvbmRlbnNlZF9pZCwgZnJvbSA9ICJjb25kZW5zZWRfaWQiLCB0bz0icGF0aWVudF9pZCIsIGRiX3BhdGgpIC0tPgo8IS0tIGVjYiA8LSBmdW5jdGlvbih4LHkpe3Bsb3QoeCx0PSduJyk7dGV4dCh4LGxhYmVscz1wYXRpZW50cyxjb2w9Z2V0X2NvbG91cl9wYWxldHRlKHBhdGllbnRzKVtwYXRpZW50c10pfSAtLT4KCjwhLS0gdHNuZV9kYXQgPC0gdHNuZShzY2FsZShkYXRbLDI6bmNvbChkYXQpXSksIGVwb2NoX2NhbGxiYWNrID0gZWNiLCBwZXJwbGV4aXR5ID0gMiwgd2hpdGVuID0gVFJVRSwgbWF4X2l0ZXIgPSA1MDAwKSAtLT4KPCEtLSBgYGAgLS0+