Setup knitr and load utility functions

knitr::opts_chunk$set(echo = TRUE)
knitr::opts_knit$set(root.dir="E:/DISC/reproducibility")

Load Depandent Functions and Packages

single_plot_line = function(data_mat, method_color, title = "1000 Genes", ylab = "Duration in hours", use_log=T, ymax=NULL){
  data_df = data.frame()
  for(ii in 1:ncol(data_mat)){
    data_df[seq(nrow(data_mat)) + nrow(data_mat) * (ii - 1), "method"] <- rep(colnames(data_mat)[ii], nrow(data_mat))
    data_df[seq(nrow(data_mat)) + nrow(data_mat) * (ii - 1), "method_color"] <- rep(method_color[ii], nrow(data_mat))
    data_df[seq(nrow(data_mat)) + nrow(data_mat) * (ii - 1), "cells"] <- factor(rownames(data_mat), levels = rownames(data_mat))
    data_df[seq(nrow(data_mat)) + nrow(data_mat) * (ii - 1), "value"] <- as.numeric(data_mat[, ii])
  }
  data_df$method = factor(data_df$method, levels = colnames(data_mat))
  this_plot = ggplot(data = data_df, aes(x = cells, y = value, color = method, group = method)) + geom_line(size = 1.5) + geom_point(size = 4) +
    scale_color_manual(values = method_color) + 
    scale_size_manual(values = 8) + 
    labs(title = title) +  xlab("Cell Count") + ylab(ylab) +
    scale_x_discrete() + 
    theme(panel.border = element_blank(), axis.line = element_line(), legend.background = element_blank(),
          panel.background = element_blank(), legend.spacing = element_blank(),
          legend.key = element_rect(colour = NA, fill = NA), legend.title = element_blank(),
          axis.title = element_text(size = 15, face = "bold"), axis.text = element_text(size = 12, face = "bold"),
          legend.text = element_text(size = 12, face = "bold"),
          plot.title = element_text(hjust = 0.5, size = 15, face = "bold"))
  if(use_log){
    this_plot = this_plot + scale_y_continuous(trans = 'log10')
  }
  if(!is.null(ymax)){
    this_plot = this_plot + ylim(c(0, ymax * 1.08)) + geom_hline(yintercept = ymax, color = "gray", size = 1, linetype=2)
  }
  return(this_plot)
}

single_plot_bar = function(data_mat, method_color, title = "10000 Genes", ylab = "Duration in hours", use_log=T, ymax=NULL){
  data_df = data.frame()
  for(ii in 1:ncol(data_mat)){
    data_df[seq(nrow(data_mat)) + nrow(data_mat) * (ii - 1), "method"] <- rep(colnames(data_mat)[ii], nrow(data_mat))
    data_df[seq(nrow(data_mat)) + nrow(data_mat) * (ii - 1), "method_color"] <- rep(method_color[ii], nrow(data_mat))
    data_df[seq(nrow(data_mat)) + nrow(data_mat) * (ii - 1), "cells"] <- factor(rownames(data_mat), levels = rownames(data_mat))
    data_df[seq(nrow(data_mat)) + nrow(data_mat) * (ii - 1), "value"] <- as.numeric(data_mat[, ii])
  }
  data_df$method = factor(data_df$method, levels = colnames(data_mat))
  this_plot = ggplot(data = data_df, aes(x = method, y = value, fill = cells, group = cells)) + geom_bar(stat="identity", position=position_dodge()) +
    scale_color_manual(values = method_color) + 
    scale_size_manual(values = 8) + 
    labs(title = title) +  xlab("Cell Count") + ylab(ylab) +
    scale_x_discrete() + 
    theme(panel.border = element_blank(), axis.line = element_line(), legend.background = element_blank(),
          panel.background = element_blank(), legend.spacing = element_blank(),
          legend.key = element_rect(colour = NA, fill = NA), legend.title = element_blank(),
          axis.title = element_text(size = 15, face = "bold"), axis.text = element_text(size = 12, face = "bold"), axis.text.x.bottom = element_text(vjust = 0.5, angle = 45),
          legend.text = element_text(size = 12, face = "bold"),
          plot.title = element_text(hjust = 0.5, size = 15, face = "bold"))
  if(use_log){
    this_plot = this_plot + scale_y_continuous(trans = 'log10')
  }
  if(!is.null(ymax)){
    this_plot = this_plot + ylim(c(0, ymax * 1.08)) + geom_hline(yintercept = ymax, color = "gray", size = 1, linetype=2)
  }
  return(this_plot)
}

g_legend = function(a.gplot){
  tmp = ggplot_gtable(ggplot_build(a.gplot))
  leg = which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
  legend = tmp$grobs[[leg]]
  return(legend)}

library(ggplot2)
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     
library(gridExtra)
col_name = c("DISC", "SAVER", "scImpute", "VIPER", "MAGIC", "DCA", "DeepImpute", "scScope", "scVI")
cell_number = c("10k", "50k", "100k", "500k", "1.3m", "2.6m")
method_name = c("DISC", "scVI", "MAGIC", "DCA", "scScope", "DeepImpute", "VIPER", "scImpute")
method_color = c("#E83828", "#278BC4", "#EADE36", "#198B41", "#920783", "#F8B62D", "#8E5E32", "#1E2B68")
method_lty = c(rep(1, 4), rep(4, 4), 1)


performance_mat = as.matrix(read.table("E:/DISC/reproducibility/Data Preparation, Imputation and Computational Resource Evaluation/Computational Resource Evaluation/raw_data/performance.txt", sep = "\t", header = F))[, -1]
runtime = performance_mat[2:14, ][-1, -1]
ram = performance_mat[17:29, ][-1, -1]


runtime1k = runtime[1:6, ]
colnames(runtime1k) = col_name
rownames(runtime1k) = cell_number

runtime10k = runtime[7:12, ]
colnames(runtime10k) = col_name
rownames(runtime10k) = cell_number

ram1k = ram[1:6, ]
colnames(ram1k) = col_name
rownames(ram1k) = cell_number

ram10k = ram[7:12, ]
colnames(ram10k) = col_name
rownames(ram10k) = cell_number
runtime1k_plot = single_plot_line(runtime1k[, method_names], method_color, "1000 Genes", "Duration in hours", use_log = F, ymax = 24)
ǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NA
runtime10k_plot = single_plot_bar(runtime10k[, method_names], method_color, "10000 Genes", "Duration in hours", use_log = F)
ǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NA
ram1k_plot = single_plot_line(ram1k[, method_names], method_color, "1000 Genes", "Peak RAM (GB)", use_log = F, ymax = 128)
ǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NA
ram10k_plot = single_plot_bar(ram10k[, method_names], method_color, "10000 Genes", "Peak RAM (GB)", use_log = F, ymax = 128)
ǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NAǿ搼㸶Ƹı攼㸴戼㸹昼㹤戼㸳挼㹣搼㸶в昼㹡挼㸹昼㹡挼㸱挼㹢NA
grid.arrange(arrangeGrob(runtime1k_plot + theme(legend.position = "none", plot.title = element_blank(), axis.title.x = element_blank()),
                         ram1k_plot + theme(legend.position = "none", plot.title = element_blank(), axis.title.x = element_blank()),
                         top = gridExtra:::text_grob(label = "1000 Genes", fontsize = 15, fontface = 2, hjust = 0.2), nrow = 1),
             g_legend(runtime1k_plot), bottom = gridExtra:::text_grob(label = "Cell Count", fontsize = 15, fontface = 2, hjust = 1), ncol = 2, widths = c(4, 2))

grid.arrange(arrangeGrob(runtime10k_plot + theme(legend.position = "none", plot.title = element_blank(), axis.title.x = element_blank()),
                         ram10k_plot + theme(legend.position = "none", plot.title = element_blank(), axis.title.x = element_blank()),
                         top = gridExtra:::text_grob(label = "10000 Genes", fontsize = 15, fontface = 2, hjust = 0.2), nrow = 1),
             g_legend(runtime10k_plot), bottom = gridExtra:::text_grob(label = "Cell Count", fontsize = 15, fontface = 2, hjust = 1), ncol = 2, widths = c(8, 1))

LS0tDQp0aXRsZTogIlJ1bm5pbmcgdGltZSBhbmQgTWVtb3J5IFBlYWsgVXNhZ2UgYWNyb3NzIEltcHV0YXRpb24gTWV0aG9kcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQojIyMgU2V0dXAga25pdHIgYW5kIGxvYWQgdXRpbGl0eSBmdW5jdGlvbnMNCmBgYHtyIHNldHVwfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0Ka25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXI9IkU6L0RJU0MvcmVwcm9kdWNpYmlsaXR5IikNCmBgYA0KTG9hZCBEZXBhbmRlbnQgRnVuY3Rpb25zIGFuZCBQYWNrYWdlcw0KYGBge3J9DQpzaW5nbGVfcGxvdF9saW5lID0gZnVuY3Rpb24oZGF0YV9tYXQsIG1ldGhvZF9jb2xvciwgdGl0bGUgPSAiMTAwMCBHZW5lcyIsIHlsYWIgPSAiRHVyYXRpb24gaW4gaG91cnMiLCB1c2VfbG9nPVQsIHltYXg9TlVMTCl7DQogIGRhdGFfZGYgPSBkYXRhLmZyYW1lKCkNCiAgZm9yKGlpIGluIDE6bmNvbChkYXRhX21hdCkpew0KICAgIGRhdGFfZGZbc2VxKG5yb3coZGF0YV9tYXQpKSArIG5yb3coZGF0YV9tYXQpICogKGlpIC0gMSksICJtZXRob2QiXSA8LSByZXAoY29sbmFtZXMoZGF0YV9tYXQpW2lpXSwgbnJvdyhkYXRhX21hdCkpDQogICAgZGF0YV9kZltzZXEobnJvdyhkYXRhX21hdCkpICsgbnJvdyhkYXRhX21hdCkgKiAoaWkgLSAxKSwgIm1ldGhvZF9jb2xvciJdIDwtIHJlcChtZXRob2RfY29sb3JbaWldLCBucm93KGRhdGFfbWF0KSkNCiAgICBkYXRhX2RmW3NlcShucm93KGRhdGFfbWF0KSkgKyBucm93KGRhdGFfbWF0KSAqIChpaSAtIDEpLCAiY2VsbHMiXSA8LSBmYWN0b3Iocm93bmFtZXMoZGF0YV9tYXQpLCBsZXZlbHMgPSByb3duYW1lcyhkYXRhX21hdCkpDQogICAgZGF0YV9kZltzZXEobnJvdyhkYXRhX21hdCkpICsgbnJvdyhkYXRhX21hdCkgKiAoaWkgLSAxKSwgInZhbHVlIl0gPC0gYXMubnVtZXJpYyhkYXRhX21hdFssIGlpXSkNCiAgfQ0KICBkYXRhX2RmJG1ldGhvZCA9IGZhY3RvcihkYXRhX2RmJG1ldGhvZCwgbGV2ZWxzID0gY29sbmFtZXMoZGF0YV9tYXQpKQ0KICB0aGlzX3Bsb3QgPSBnZ3Bsb3QoZGF0YSA9IGRhdGFfZGYsIGFlcyh4ID0gY2VsbHMsIHkgPSB2YWx1ZSwgY29sb3IgPSBtZXRob2QsIGdyb3VwID0gbWV0aG9kKSkgKyBnZW9tX2xpbmUoc2l6ZSA9IDEuNSkgKyBnZW9tX3BvaW50KHNpemUgPSA0KSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG1ldGhvZF9jb2xvcikgKyANCiAgICBzY2FsZV9zaXplX21hbnVhbCh2YWx1ZXMgPSA4KSArIA0KICAgIGxhYnModGl0bGUgPSB0aXRsZSkgKyAgeGxhYigiQ2VsbCBDb3VudCIpICsgeWxhYih5bGFiKSArDQogICAgc2NhbGVfeF9kaXNjcmV0ZSgpICsgDQogICAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLCBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoKSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnNwYWNpbmcgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSwgZmlsbCA9IE5BKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSwgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksDQogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpKQ0KICBpZih1c2VfbG9nKXsNCiAgICB0aGlzX3Bsb3QgPSB0aGlzX3Bsb3QgKyBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAnbG9nMTAnKQ0KICB9DQogIGlmKCFpcy5udWxsKHltYXgpKXsNCiAgICB0aGlzX3Bsb3QgPSB0aGlzX3Bsb3QgKyB5bGltKGMoMCwgeW1heCAqIDEuMDgpKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IHltYXgsIGNvbG9yID0gImdyYXkiLCBzaXplID0gMSwgbGluZXR5cGU9MikNCiAgfQ0KICByZXR1cm4odGhpc19wbG90KQ0KfQ0KDQpzaW5nbGVfcGxvdF9iYXIgPSBmdW5jdGlvbihkYXRhX21hdCwgbWV0aG9kX2NvbG9yLCB0aXRsZSA9ICIxMDAwMCBHZW5lcyIsIHlsYWIgPSAiRHVyYXRpb24gaW4gaG91cnMiLCB1c2VfbG9nPVQsIHltYXg9TlVMTCl7DQogIGRhdGFfZGYgPSBkYXRhLmZyYW1lKCkNCiAgZm9yKGlpIGluIDE6bmNvbChkYXRhX21hdCkpew0KICAgIGRhdGFfZGZbc2VxKG5yb3coZGF0YV9tYXQpKSArIG5yb3coZGF0YV9tYXQpICogKGlpIC0gMSksICJtZXRob2QiXSA8LSByZXAoY29sbmFtZXMoZGF0YV9tYXQpW2lpXSwgbnJvdyhkYXRhX21hdCkpDQogICAgZGF0YV9kZltzZXEobnJvdyhkYXRhX21hdCkpICsgbnJvdyhkYXRhX21hdCkgKiAoaWkgLSAxKSwgIm1ldGhvZF9jb2xvciJdIDwtIHJlcChtZXRob2RfY29sb3JbaWldLCBucm93KGRhdGFfbWF0KSkNCiAgICBkYXRhX2RmW3NlcShucm93KGRhdGFfbWF0KSkgKyBucm93KGRhdGFfbWF0KSAqIChpaSAtIDEpLCAiY2VsbHMiXSA8LSBmYWN0b3Iocm93bmFtZXMoZGF0YV9tYXQpLCBsZXZlbHMgPSByb3duYW1lcyhkYXRhX21hdCkpDQogICAgZGF0YV9kZltzZXEobnJvdyhkYXRhX21hdCkpICsgbnJvdyhkYXRhX21hdCkgKiAoaWkgLSAxKSwgInZhbHVlIl0gPC0gYXMubnVtZXJpYyhkYXRhX21hdFssIGlpXSkNCiAgfQ0KICBkYXRhX2RmJG1ldGhvZCA9IGZhY3RvcihkYXRhX2RmJG1ldGhvZCwgbGV2ZWxzID0gY29sbmFtZXMoZGF0YV9tYXQpKQ0KICB0aGlzX3Bsb3QgPSBnZ3Bsb3QoZGF0YSA9IGRhdGFfZGYsIGFlcyh4ID0gbWV0aG9kLCB5ID0gdmFsdWUsIGZpbGwgPSBjZWxscywgZ3JvdXAgPSBjZWxscykpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSgpKSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG1ldGhvZF9jb2xvcikgKyANCiAgICBzY2FsZV9zaXplX21hbnVhbCh2YWx1ZXMgPSA4KSArIA0KICAgIGxhYnModGl0bGUgPSB0aXRsZSkgKyAgeGxhYigiQ2VsbCBDb3VudCIpICsgeWxhYih5bGFiKSArDQogICAgc2NhbGVfeF9kaXNjcmV0ZSgpICsgDQogICAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLCBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoKSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnNwYWNpbmcgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSBOQSwgZmlsbCA9IE5BKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBmYWNlID0gImJvbGQiKSwgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksIGF4aXMudGV4dC54LmJvdHRvbSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDAuNSwgYW5nbGUgPSA0NSksDQogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTUsIGZhY2UgPSAiYm9sZCIpKQ0KICBpZih1c2VfbG9nKXsNCiAgICB0aGlzX3Bsb3QgPSB0aGlzX3Bsb3QgKyBzY2FsZV95X2NvbnRpbnVvdXModHJhbnMgPSAnbG9nMTAnKQ0KICB9DQogIGlmKCFpcy5udWxsKHltYXgpKXsNCiAgICB0aGlzX3Bsb3QgPSB0aGlzX3Bsb3QgKyB5bGltKGMoMCwgeW1heCAqIDEuMDgpKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IHltYXgsIGNvbG9yID0gImdyYXkiLCBzaXplID0gMSwgbGluZXR5cGU9MikNCiAgfQ0KICByZXR1cm4odGhpc19wbG90KQ0KfQ0KDQpnX2xlZ2VuZCA9IGZ1bmN0aW9uKGEuZ3Bsb3Qpew0KICB0bXAgPSBnZ3Bsb3RfZ3RhYmxlKGdncGxvdF9idWlsZChhLmdwbG90KSkNCiAgbGVnID0gd2hpY2goc2FwcGx5KHRtcCRncm9icywgZnVuY3Rpb24oeCkgeCRuYW1lKSA9PSAiZ3VpZGUtYm94IikNCiAgbGVnZW5kID0gdG1wJGdyb2JzW1tsZWddXQ0KICByZXR1cm4obGVnZW5kKX0NCg0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShncmlkRXh0cmEpDQpgYGANCmBgYHtyfQ0KY29sX25hbWUgPSBjKCJESVNDIiwgIlNBVkVSIiwgInNjSW1wdXRlIiwgIlZJUEVSIiwgIk1BR0lDIiwgIkRDQSIsICJEZWVwSW1wdXRlIiwgInNjU2NvcGUiLCAic2NWSSIpDQpjZWxsX251bWJlciA9IGMoIjEwayIsICI1MGsiLCAiMTAwayIsICI1MDBrIiwgIjEuM20iLCAiMi42bSIpDQptZXRob2RfbmFtZSA9IGMoIkRJU0MiLCAic2NWSSIsICJNQUdJQyIsICJEQ0EiLCAic2NTY29wZSIsICJEZWVwSW1wdXRlIiwgIlZJUEVSIiwgInNjSW1wdXRlIikNCm1ldGhvZF9jb2xvciA9IGMoIiNFODM4MjgiLCAiIzI3OEJDNCIsICIjRUFERTM2IiwgIiMxOThCNDEiLCAiIzkyMDc4MyIsICIjRjhCNjJEIiwgIiM4RTVFMzIiLCAiIzFFMkI2OCIpDQptZXRob2RfbHR5ID0gYyhyZXAoMSwgNCksIHJlcCg0LCA0KSwgMSkNCg0KDQpwZXJmb3JtYW5jZV9tYXQgPSBhcy5tYXRyaXgocmVhZC50YWJsZSgiRTovRElTQy9yZXByb2R1Y2liaWxpdHkvRGF0YSBQcmVwYXJhdGlvbiwgSW1wdXRhdGlvbiBhbmQgQ29tcHV0YXRpb25hbCBSZXNvdXJjZSBFdmFsdWF0aW9uL0NvbXB1dGF0aW9uYWwgUmVzb3VyY2UgRXZhbHVhdGlvbi9yYXdfZGF0YS9wZXJmb3JtYW5jZS50eHQiLCBzZXAgPSAiXHQiLCBoZWFkZXIgPSBGKSlbLCAtMV0NCnJ1bnRpbWUgPSBwZXJmb3JtYW5jZV9tYXRbMjoxNCwgXVstMSwgLTFdDQpyYW0gPSBwZXJmb3JtYW5jZV9tYXRbMTc6MjksIF1bLTEsIC0xXQ0KDQoNCnJ1bnRpbWUxayA9IHJ1bnRpbWVbMTo2LCBdDQpjb2xuYW1lcyhydW50aW1lMWspID0gY29sX25hbWUNCnJvd25hbWVzKHJ1bnRpbWUxaykgPSBjZWxsX251bWJlcg0KDQpydW50aW1lMTBrID0gcnVudGltZVs3OjEyLCBdDQpjb2xuYW1lcyhydW50aW1lMTBrKSA9IGNvbF9uYW1lDQpyb3duYW1lcyhydW50aW1lMTBrKSA9IGNlbGxfbnVtYmVyDQoNCnJhbTFrID0gcmFtWzE6NiwgXQ0KY29sbmFtZXMocmFtMWspID0gY29sX25hbWUNCnJvd25hbWVzKHJhbTFrKSA9IGNlbGxfbnVtYmVyDQoNCnJhbTEwayA9IHJhbVs3OjEyLCBdDQpjb2xuYW1lcyhyYW0xMGspID0gY29sX25hbWUNCnJvd25hbWVzKHJhbTEwaykgPSBjZWxsX251bWJlcg0KYGBgDQpgYGB7cn0NCnJ1bnRpbWUxa19wbG90ID0gc2luZ2xlX3Bsb3RfbGluZShydW50aW1lMWtbLCBtZXRob2RfbmFtZXNdLCBtZXRob2RfY29sb3IsICIxMDAwIEdlbmVzIiwgIkR1cmF0aW9uIGluIGhvdXJzIiwgdXNlX2xvZyA9IEYsIHltYXggPSAyNCkNCnJ1bnRpbWUxMGtfcGxvdCA9IHNpbmdsZV9wbG90X2JhcihydW50aW1lMTBrWywgbWV0aG9kX25hbWVzXSwgbWV0aG9kX2NvbG9yLCAiMTAwMDAgR2VuZXMiLCAiRHVyYXRpb24gaW4gaG91cnMiLCB1c2VfbG9nID0gRikNCg0KcmFtMWtfcGxvdCA9IHNpbmdsZV9wbG90X2xpbmUocmFtMWtbLCBtZXRob2RfbmFtZXNdLCBtZXRob2RfY29sb3IsICIxMDAwIEdlbmVzIiwgIlBlYWsgUkFNIChHQikiLCB1c2VfbG9nID0gRiwgeW1heCA9IDEyOCkNCnJhbTEwa19wbG90ID0gc2luZ2xlX3Bsb3RfYmFyKHJhbTEwa1ssIG1ldGhvZF9uYW1lc10sIG1ldGhvZF9jb2xvciwgIjEwMDAwIEdlbmVzIiwgIlBlYWsgUkFNIChHQikiLCB1c2VfbG9nID0gRiwgeW1heCA9IDEyOCkNCmBgYA0KYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9MTJ9DQpncmlkLmFycmFuZ2UoYXJyYW5nZUdyb2IocnVudGltZTFrX3Bsb3QgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgcmFtMWtfcGxvdCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICB0b3AgPSBncmlkRXh0cmE6Ojp0ZXh0X2dyb2IobGFiZWwgPSAiMTAwMCBHZW5lcyIsIGZvbnRzaXplID0gMTUsIGZvbnRmYWNlID0gMiwgaGp1c3QgPSAwLjIpLCBucm93ID0gMSksDQogICAgICAgICAgICAgZ19sZWdlbmQocnVudGltZTFrX3Bsb3QpLCBib3R0b20gPSBncmlkRXh0cmE6Ojp0ZXh0X2dyb2IobGFiZWwgPSAiQ2VsbCBDb3VudCIsIGZvbnRzaXplID0gMTUsIGZvbnRmYWNlID0gMiwgaGp1c3QgPSAxKSwgbmNvbCA9IDIsIHdpZHRocyA9IGMoNCwgMikpDQpncmlkLmFycmFuZ2UoYXJyYW5nZUdyb2IocnVudGltZTEwa19wbG90ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHJhbTEwa19wbG90ICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwbG90LnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHRvcCA9IGdyaWRFeHRyYTo6OnRleHRfZ3JvYihsYWJlbCA9ICIxMDAwMCBHZW5lcyIsIGZvbnRzaXplID0gMTUsIGZvbnRmYWNlID0gMiwgaGp1c3QgPSAwLjIpLCBucm93ID0gMSksDQogICAgICAgICAgICAgZ19sZWdlbmQocnVudGltZTEwa19wbG90KSwgYm90dG9tID0gZ3JpZEV4dHJhOjo6dGV4dF9ncm9iKGxhYmVsID0gIkNlbGwgQ291bnQiLCBmb250c2l6ZSA9IDE1LCBmb250ZmFjZSA9IDIsIGhqdXN0ID0gMSksIG5jb2wgPSAyLCB3aWR0aHMgPSBjKDgsIDEpKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==