Introduction
Loading necessary libraries and dataset
library(tidyverse)
library(magrittr)
library(broom)
library(e1071)
library(clValid)
library(fpc)
library(gplots)
load("OAI_JSW_Data.RData")
Prepairing data to be analysed
feats <-
OAI_JSW_Data %>%
filter(VISITID == 0, complete.cases(.)) %>%
select(-c(VISITID, IDSIDE, ID, SITE, BASEVISITDATE_C, FUVISITDATE, DaysFomStart, DAYSFROMBL,
DaystoTKR, TimeToEvent, DeathVisit, BLKL2, WOMACTOTAL,
WOMAC2YTotalChange, `2YIncreaseSymptoms`, YearTOKL2),
-starts_with("Y2")) %>%
mutate_at(vars(BLKL, mJSN,lJSN, PainMedication, AnySurgery), as.integer) %>%
mutate_if(is.double, funs(scale))
Bootstrapping
Calculate optimal k s by:
- Sample of 25% of data with replacement
- Calculate Dunn index for said sample per clustering algorithm for k s between and 2 and a given value
- Find k that maximizes the Dunn index per clustering algorithm
- Repeat steps 1 to 3 x times
- Get mean best k per clustering algorithm
res <- clustest::find_k(dataset = feats, train_size = 0.25, iters = 28, max_k = 5)
train <- res$train
test <- res$test
k_stats <- res$k_stats
best_k <- res$best_k
all_best_ks <- res$all_best_ks
c_samples <- res$c_samples
remove(res)
Plotting optimal k s
k_stats %>%
ggplot(aes(x = method, y = mean_best_k)) +
geom_col(aes(fill = method)) +
guides(fill = F) +
geom_errorbar(aes(ymin = ci_min, ymax = ci_max))

best_k
Jaccard Stability Test
Fuzzy c-Means Clustering Bootstrap Interface
cmeansCBI <- function(data, k) {
result <- cmeans(x = data, center = k)
list(result = result,
partition = result$cluster,
clusterlist = map(1:k, ~. == result$cluster),
clustermethod = "fcmeans",
nc = k)
}
Jaccard evaluation of all algorithms
jac <- list(
KMeans = clusterboot(train, B = 30, clustermethod = kmeansCBI, k = best_k$KMeans)$bootresult,
FCMeans = clusterboot(train, B = 30, clustermethod = cmeansCBI, k = best_k$FCMeans)$bootresult,
HCWard = clusterboot(train, B = 30, clustermethod = hclustCBI, k = best_k$HCWard,
method = "ward.D")$bootresult,
HCSing = clusterboot(train, B = 30, clustermethod = hclustCBI, k = best_k$HCSing,
method = "single")$bootresult,
HCComp = clusterboot(train, B = 30, clustermethod = hclustCBI, k = best_k$HCComp,
method = "complete")$bootresult)
Plotting stability tests summary
get_stats <- function(jac_mat){
jac_mat %>%
t() %>%
as_tibble() %>%
summarise_all(funs(ci_min = t.test(.)$conf.int[1],
ci_max = t.test(.)$conf.int[2],
mean_jaccard = mean(.))) %>%
gather() %>%
separate(key, into = c("cluster", "stat"), extra = "merge") %>%
spread(stat, value)
}
jac %>%
map_df(get_stats, .id = "method") %>%
ggplot(aes(x = cluster, y = mean_jaccard)) +
facet_wrap(~method) +
geom_col(aes(fill = cluster)) +
guides(fill = F) +
geom_errorbar(aes(ymin = ci_min, ymax = ci_max))

ANOVA
Plot training sets ANOVA
a_o_v <-
c_samples %>%
group_by(sample) %>%
do(clustest::var_clust_aov(., methods = c("KMeans", "FCMeans", "HCWard", "HCSing", "HCComp"),
dep_vars = c("WOMACPAIN", "BLKL", "TKREvent")))
|===========================================================================================|100% ~0 s remaining
a_o_v %>%
group_by(dep_var, term) %>%
summarise(signif_percent = sum(p.value <= 0.05)/n(),
ci_min = t.test(p.value)$conf.int[1],
ci_max = t.test(p.value)$conf.int[2],
mean_p_value = mean(p.value)) %T>%
print() %>%
ggplot(aes(x = term, y = mean_p_value, fill = term)) +
facet_wrap(~dep_var, ncol = 2) +
geom_col() +
guides(fill = F) +
geom_errorbar(aes(ymin = ci_min, ymax = ci_max))

Print testing set ANOVA
Hierarchical Clustering Heatmap

LS0tCnRpdGxlOiAiT0FJX0NsdXN0IgphdXRob3I6ICJEYXZpZCBEdWFydGUiCmRhdGU6ICIyLzYvMjAxOCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgSW50cm9kdWN0aW9uCgpMb2FkaW5nIG5lY2Vzc2FyeSBsaWJyYXJpZXMgYW5kIGRhdGFzZXQKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeShlMTA3MSkKbGlicmFyeShmcGMpCmxpYnJhcnkoZ3Bsb3RzKQpsb2FkKCJPQUlfSlNXX0RhdGEuUkRhdGEiKQpgYGAKCjwvYnI+CgpQcmVwYWlyaW5nIGRhdGEgdG8gYmUgYW5hbHlzZWQKCmBgYHtyfQpmZWF0cyA8LQogIE9BSV9KU1dfRGF0YSAlPiUgCiAgZmlsdGVyKFZJU0lUSUQgPT0gMCwgY29tcGxldGUuY2FzZXMoLikpICU+JSAKICBzZWxlY3QoLWMoVklTSVRJRCwgSURTSURFLCBJRCwgU0lURSwgQkFTRVZJU0lUREFURV9DLCBGVVZJU0lUREFURSwgRGF5c0ZvbVN0YXJ0LCBEQVlTRlJPTUJMLAogICAgICAgICAgICBEYXlzdG9US1IsIFRpbWVUb0V2ZW50LCBEZWF0aFZpc2l0LCBCTEtMMiwgV09NQUNUT1RBTCwgCiAgICAgICAgICAgIFdPTUFDMllUb3RhbENoYW5nZSwgYDJZSW5jcmVhc2VTeW1wdG9tc2AsIFllYXJUT0tMMiksIAogICAgICAgICAtc3RhcnRzX3dpdGgoIlkyIikpICU+JSAKICBtdXRhdGVfYXQodmFycyhCTEtMLCBtSlNOLGxKU04sIFBhaW5NZWRpY2F0aW9uLCBBbnlTdXJnZXJ5KSwgYXMuaW50ZWdlcikgJT4lIAogIG11dGF0ZV9pZihpcy5kb3VibGUsIGZ1bnMoc2NhbGUpKQpgYGAKCjwvYnI+CgojIyBCb290c3RyYXBwaW5nCgpDYWxjdWxhdGUgb3B0aW1hbCBfa18gcyBieToKCjEuIFNhbXBsZSBvZiAyNSUgb2YgZGF0YSB3aXRoIHJlcGxhY2VtZW50CjIuIENhbGN1bGF0ZSBEdW5uIGluZGV4IGZvciBzYWlkIHNhbXBsZSBwZXIgY2x1c3RlcmluZyBhbGdvcml0aG0gZm9yIF9rXyBzIGJldHdlZW4gYW5kIDIgYW5kIGEgZ2l2ZW4gdmFsdWUKMy4gRmluZCBfa18gdGhhdCBtYXhpbWl6ZXMgdGhlIER1bm4gaW5kZXggcGVyIGNsdXN0ZXJpbmcgYWxnb3JpdGhtCjQuIFJlcGVhdCBzdGVwcyAxIHRvIDMgX3hfIHRpbWVzCjUuIEdldCBtZWFuIGJlc3QgX2tfIHBlciBjbHVzdGVyaW5nIGFsZ29yaXRobQoKYGBge3J9CgpyZXMgICAgICAgICA8LSBjbHVzdGVzdDo6ZmluZF9rKGRhdGFzZXQgPSBmZWF0cywgdHJhaW5fc2l6ZSA9IDAuMjUsIGl0ZXJzID0gMjgsIG1heF9rID0gNSkKdHJhaW4gICAgICAgPC0gcmVzJHRyYWluCnRlc3QgICAgICAgIDwtIHJlcyR0ZXN0Cmtfc3RhdHMgICAgIDwtIHJlcyRrX3N0YXRzCmJlc3RfayAgICAgIDwtIHJlcyRiZXN0X2sgCmFsbF9iZXN0X2tzIDwtIHJlcyRhbGxfYmVzdF9rcwpjX3NhbXBsZXMgICA8LSByZXMkY19zYW1wbGVzCgpyZW1vdmUocmVzKQoKYGBgCgo8L2JyPgoKUGxvdHRpbmcgb3B0aW1hbCBfa18gcwoKYGBge3J9CgprX3N0YXRzICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBtZXRob2QsIHkgPSBtZWFuX2Jlc3RfaykpICsKICAgIGdlb21fY29sKGFlcyhmaWxsID0gbWV0aG9kKSkgKwogICAgZ3VpZGVzKGZpbGwgPSBGKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gY2lfbWluLCB5bWF4ID0gY2lfbWF4KSkKCmJlc3RfawpgYGAKCjwvYnI+CgojIyBKYWNjYXJkIFN0YWJpbGl0eSBUZXN0CgpGdXp6eSBfY18tTWVhbnMgQ2x1c3RlcmluZyBCb290c3RyYXAgSW50ZXJmYWNlCgpgYGB7cn0KY21lYW5zQ0JJIDwtIGZ1bmN0aW9uKGRhdGEsIGspIHsKICByZXN1bHQgPC0gY21lYW5zKHggPSBkYXRhLCBjZW50ZXIgPSBrKQogIAogIGxpc3QocmVzdWx0ID0gcmVzdWx0LCAKICAgICAgIHBhcnRpdGlvbiA9IHJlc3VsdCRjbHVzdGVyLAogICAgICAgY2x1c3Rlcmxpc3QgPSBtYXAoMTprLCB+LiA9PSByZXN1bHQkY2x1c3RlciksCiAgICAgICBjbHVzdGVybWV0aG9kID0gImZjbWVhbnMiLAogICAgICAgbmMgPSBrKQp9CmBgYAoKPC9icj4KCkphY2NhcmQgZXZhbHVhdGlvbiBvZiBhbGwgYWxnb3JpdGhtcwoKYGBge3J9CmphYyA8LSBsaXN0KAogIEtNZWFucyAgPSBjbHVzdGVyYm9vdCh0cmFpbiwgQiA9IDMwLCBjbHVzdGVybWV0aG9kID0ga21lYW5zQ0JJLCBrID0gYmVzdF9rJEtNZWFucykkYm9vdHJlc3VsdCwKICBGQ01lYW5zID0gY2x1c3RlcmJvb3QodHJhaW4sIEIgPSAzMCwgY2x1c3Rlcm1ldGhvZCA9IGNtZWFuc0NCSSwgayA9IGJlc3RfayRGQ01lYW5zKSRib290cmVzdWx0LAogIEhDV2FyZCAgPSBjbHVzdGVyYm9vdCh0cmFpbiwgQiA9IDMwLCBjbHVzdGVybWV0aG9kID0gaGNsdXN0Q0JJLCBrID0gYmVzdF9rJEhDV2FyZCwgCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJ3YXJkLkQiKSRib290cmVzdWx0LAogIEhDU2luZyAgPSBjbHVzdGVyYm9vdCh0cmFpbiwgQiA9IDMwLCBjbHVzdGVybWV0aG9kID0gaGNsdXN0Q0JJLCBrID0gYmVzdF9rJEhDU2luZywgCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJzaW5nbGUiKSRib290cmVzdWx0LAogIEhDQ29tcCAgPSBjbHVzdGVyYm9vdCh0cmFpbiwgQiA9IDMwLCBjbHVzdGVybWV0aG9kID0gaGNsdXN0Q0JJLCBrID0gYmVzdF9rJEhDQ29tcCwgCiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJjb21wbGV0ZSIpJGJvb3RyZXN1bHQpCmBgYAoKPC9icj4KClBsb3R0aW5nIHN0YWJpbGl0eSB0ZXN0cyBzdW1tYXJ5CgpgYGB7cn0KZ2V0X3N0YXRzIDwtIGZ1bmN0aW9uKGphY19tYXQpewogIGphY19tYXQgJT4lIAogICAgdCgpICU+JSAKICAgIGFzX3RpYmJsZSgpICU+JSAKICAgIHN1bW1hcmlzZV9hbGwoZnVucyhjaV9taW4gPSB0LnRlc3QoLikkY29uZi5pbnRbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgY2lfbWF4ID0gdC50ZXN0KC4pJGNvbmYuaW50WzJdLAogICAgICAgICAgICAgICAgICAgICAgIG1lYW5famFjY2FyZCA9IG1lYW4oLikpKSAlPiUgCiAgICBnYXRoZXIoKSAlPiUgCiAgICBzZXBhcmF0ZShrZXksIGludG8gPSBjKCJjbHVzdGVyIiwgInN0YXQiKSwgZXh0cmEgPSAibWVyZ2UiKSAlPiUgCiAgICBzcHJlYWQoc3RhdCwgdmFsdWUpCn0KCmphYyAlPiUgCiAgbWFwX2RmKGdldF9zdGF0cywgLmlkID0gIm1ldGhvZCIpICU+JSAgCiAgZ2dwbG90KGFlcyh4ID0gY2x1c3RlciwgeSA9IG1lYW5famFjY2FyZCkpICsKICAgIGZhY2V0X3dyYXAofm1ldGhvZCkgKwogICAgZ2VvbV9jb2woYWVzKGZpbGwgPSBjbHVzdGVyKSkgKwogICAgZ3VpZGVzKGZpbGwgPSBGKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gY2lfbWluLCB5bWF4ID0gY2lfbWF4KSkKYGBgCgo8L2JyPgoKIyMgQU5PVkEKCjwvYnI+CgpQbG90IHRyYWluaW5nIHNldHMgQU5PVkEKCmBgYHtyfQphX29fdiA8LSAKICBjX3NhbXBsZXMgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSkgJT4lIAogIGRvKGNsdXN0ZXN0Ojp2YXJfY2x1c3RfYW92KC4sIG1ldGhvZHMgPSAgYygiS01lYW5zIiwgIkZDTWVhbnMiLCAiSENXYXJkIiwgIkhDU2luZyIsICJIQ0NvbXAiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVwX3ZhcnMgPSBjKCJXT01BQ1BBSU4iLCAiQkxLTCIsICJUS1JFdmVudCIpKSkKCmFfb192ICU+JSAKICBncm91cF9ieShkZXBfdmFyLCB0ZXJtKSAlPiUgCiAgc3VtbWFyaXNlKHNpZ25pZl9wZXJjZW50ID0gc3VtKHAudmFsdWUgPD0gMC4wNSkvbigpLAogICAgICAgICAgICBjaV9taW4gPSB0LnRlc3QocC52YWx1ZSkkY29uZi5pbnRbMV0sCiAgICAgICAgICAgIGNpX21heCA9IHQudGVzdChwLnZhbHVlKSRjb25mLmludFsyXSwKICAgICAgICAgICAgbWVhbl9wX3ZhbHVlID0gbWVhbihwLnZhbHVlKSkgJVQ+JQogIHByaW50KCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHRlcm0sIHkgPSBtZWFuX3BfdmFsdWUsIGZpbGwgPSB0ZXJtKSkgKwogICAgZmFjZXRfd3JhcCh+ZGVwX3ZhciwgbmNvbCA9IDIpICsKICAgIGdlb21fY29sKCkgKwogICAgZ3VpZGVzKGZpbGwgPSBGKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gY2lfbWluLCB5bWF4ID0gY2lfbWF4KSkKYGBgCgo8L2JyPgoKUHJpbnQgdGVzdGluZyBzZXQgQU5PVkEKCjwvYnI+CgpgYGB7cn0KZF90ZXN0IDwtIGRpc3QodGVzdCkKCmNscyA8LSBtYXAoYygid2FyZC5EIiwgInNpbmdsZSIsICJjb21wbGV0ZSIpLCB+aGNsdXN0KGRfdGVzdCwgLikpCm5hbWVzKGNscykgPC0gYygiSENXYXJkIiwgIkhDU2luZyIsICJIQ0NvbXAiKQoKY2x1c3RlcmVkX3Rlc3QgPC0gCiAgdGVzdCAlPiUgCiAgYmluZF9jb2xzKAogICAgS01lYW5zICA9IGttZWFucyguLCBiZXN0X2skS01lYW5zKSRjbHVzdGVyLAogICAgRkNNZWFucyA9IGNtZWFucyguLCBiZXN0X2skRkNNZWFucykkY2x1c3RlciwKICAgIEhDV2FyZCAgPSAKICAgICAgY2xzJEhDV2FyZCAlPiUgCiAgICAgIGN1dHJlZShiZXN0X2skSENXYXJkKSwKICAgIEhDU2luZyAgPSAKICAgICAgY2xzJEhDU2luZyAlPiUgCiAgICAgIGN1dHJlZShiZXN0X2skSENTaW5nKSwKICAgIEhDQ29tcCAgPSAKICAgICAgY2xzJEhDQ29tcCAlPiUgCiAgICAgIGN1dHJlZShiZXN0X2skSENDb21wKQogICkKCmNsdXN0ZXJlZF90ZXN0ICU+JSAgCiAgY2x1c3Rlc3Q6OnZhcl9jbHVzdF9hb3YoYygiS01lYW5zIiwgIkZDTWVhbnMiLCAiSENXYXJkIiwgIkhDU2luZyIsICJIQ0NvbXAiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJXT01BQ1BBSU4iLCAiQkxLTCIsICJUS1JFdmVudCIpKSAlPiUgCiAgZmlsdGVyKHAudmFsdWUgPD0gMC4wNSkKYGBgCgo8L2JyPgoKIyMgSGllcmFyY2hpY2FsIENsdXN0ZXJpbmcgSGVhdG1hcAoKYGBge3J9CmNvbG9ybWF0IDwtIHNhcHBseShuYW1lcyhiZXN0X2spLCBmdW5jdGlvbiguKSByYWluYm93KGJlc3Rfa1tbLl1dKVtjbHVzdGVyZWRfdGVzdFtbLl1dXSkKCnBsb3RmdW4gPC0gZnVuY3Rpb24oKXsKICByaW5keCA8LSBnZXQoJ3Jvd0luZCcscGFyZW50LmZyYW1lKCkpCiAgY2luZHggPC0gZ2V0KCdjb2xJbmQnLCBwYXJlbnQuZnJhbWUoKSkKICBtYXJnICA8LSBnZXQoJ21hcmdpbnMnLCBwYXJlbnQuZnJhbWUoKSkKICAKICBmb3IgKGkgaW4gMTpuY29sKGNvbG9ybWF0KSl7CiAgICBwYXIobWFyID0gYygwLjI1LCAwLCAwLCBtYXJnWzJdKSwgY2V4ID0gMC42NikKICAgIGltYWdlKGNiaW5kKDE6bnJvdyhjb2xvcm1hdCkpLCBjb2wgPSBjb2xvcm1hdFssaV1bY2luZHhdLCBheGVzID0gRikKICAgIG10ZXh0KGNvbG5hbWVzKGNvbG9ybWF0KVtpXSwgc2lkZSA9IDQsIGxpbmUgPSAxLCBjZXg9MC40LGxhcz0xLCBjb2w9ImJsYWNrIikKICB9CiAgCiAgcGFyKG1hciA9IGMoMC4yNSwgMCwgMCwgbWFyZ1syXSksIG1ncD1jKDAsMCwwKSwgcHR5PSJtIix4YXhzPSJpIikKICBwbG90KDE6bnJvdyhjb2xvcm1hdCksIGNsdXN0ZXJlZF90ZXN0JFdPTUFDUEFJTiwgdHlwZSA9ICJzIiwgYXhlcz1GQUxTRSx5bGFiPSIiLHhsYWI9IiIpCiAgbXRleHQoIldPTUFDUEFJTiIsIHNpZGU9IDQsIGxpbmU9MSwgY2V4PTAuNCxsYXM9MSwgY29sPSJibGFjayIpCiAgCiAgcGFyKG1hciA9IGMoMC4yNSwgMCwgMCwgbWFyZ1syXSksbWdwPWMoMCwwLDApLHB0eT0ibSIseGF4cz0iaSIpCiAgaW1hZ2UoY2JpbmQoMTpucm93KGNvbG9ybWF0KSksIAogICAgICAgIGNvbCA9IGdyZXkuY29sb3JzKGxlbmd0aCh1bmlxdWUoY2x1c3RlcmVkX3Rlc3QkVEtSRXZlbnQpKSlbY2x1c3RlcmVkX3Rlc3QkVEtSRXZlbnQrMV0sIGF4ZXMgPSBGKQogIG10ZXh0KCJUS1JFdmVudCIsIHNpZGU9IDQsIGxpbmU9MSwgY2V4PTAuNCxsYXM9MSwgY29sPSJibGFjayIpCiAgCiAgcGFyKG1hciA9IGMoMC4yNSwgMCwgMCwgbWFyZ1syXSksbWdwPWMoMCwwLDApLHB0eT0ibSIseGF4cz0iaSIpCiAgaW1hZ2UoY2JpbmQoMTpucm93KGNvbG9ybWF0KSksIAogICAgICAgIGNvbCA9IHJhaW5ib3cobGVuZ3RoKHVuaXF1ZShjbHVzdGVyZWRfdGVzdCRCTEtMKSkpW2NsdXN0ZXJlZF90ZXN0JEJMS0xdLCBheGVzID0gRikKICBtdGV4dCgiQkxLTCIsIHNpZGU9IDQsIGxpbmU9MSwgY2V4PTAuNCxsYXM9MSwgY29sPSJibGFjayIpCiAgCiAgcGFyKG1hciA9IGMoMC4yNSwgMCwgMS41LCBtYXJnWzJdKSwgbWdwPWMoMCwwLjUsMCkscHR5PSJtIix4YXhzPSJpIikKICAKICBibGtsX3ZhbHVlcyA8LSAKICBjbHVzdGVyZWRfdGVzdCRCTEtMICU+JSAKICB1bmlxdWUoKSAlPiUgCiAgc29ydCgpCgogIGltYWdlKHkgPSBibGtsX3ZhbHVlcywgeiA9IHJiaW5kKDE6bGVuZ3RoKGJsa2xfdmFsdWVzKSksIGNvbCA9IHJhaW5ib3cobGVuZ3RoKGJsa2xfdmFsdWVzKSksIHhheHQgPSAnbicsIAogICAgICAgIHlsYWIgPSAiIiwgY2V4LmF4aXMgPSAwLjcpCiAgdGl0bGUoIkJMS0wiLCBjZXgubWFpbiA9IDAuNykKfQoKdGVzdCAlPiUgCiAgdCgpICU+JSAKICBoZWF0bWFwLjIoZGVuZHJvZ3JhbSA9ICJjb2wiLCBDb2x2ID0gYXMuZGVuZHJvZ3JhbShjbHMkSENXYXJkKSwgdHJhY2UgPSAibm9uZSIsIAogICAgICAgICAgICBzY2FsZSA9ICJub25lIiwgYnJlYWtzID0gc2VxKC0yLCAyLCBsZW5ndGgub3V0ID0gMTAxKSwgCiAgICAgICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUoY29sb3JzID0gYygiY3lhbiIsImJsdWUiLCJibGFjayIsInJlZCIsInllbGxvdyIpKSwKICAgICAgICAgICAgZGVuc2l0eS5pbmZvID0gImRlbnNpdHkiLCBjZXhSb3cgPSAwLjQsIGV4dHJhZnVuID0gcGxvdGZ1biwgCiAgICAgICAgICAgIGxtYXQgPSByYmluZChjKDQsIDMsIDEzKSwgYygwLCA4LCAwKSwgYygwLCA2LCAwKSwgYygwLCA3LCAwKSwgYygwLCA1LCAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGMoMCwgOSwgMCksIGMoMCwgMTAsIDApLCBjKDIsIDExLCAwKSwgYygyLCAxMiwgMCksIGMoMiwgMSwgMCkpLCAKICAgICAgICAgICAgbHdpZCA9IGMoMS4yLCAzLjM4LCAwLjYyKSwgCiAgICAgICAgICAgIGxoZWkgPSBjKDEuNSwwLjEsMC4xLDAuMSwwLjEsMC4xLCAwLjEsIDAuMSwgMC4xLCAzLjUpKQoKYGBgCg==