1 A fresh running of all proteomics tasks

I think I finally worked out all(most?) of the kinks in the processing of DIA data. Thus I want to have a fresh run of all the tasks required to interpret the results.

2 Annotation version: 20190718

2.1 Genome annotation input

2.1.2 Download from microbesonline

Apparently I queried the microbesonline too often and now I get an error whenever I try to use them, this disappoints me.

## The species being downloaded is: Mycobacterium tuberculosis H37Rv
## Downloading: http://www.microbesonline.org/cgi-bin/genomeInfo.cgi?tId=83332;export=tab

2.2 Getting ontology data

## The species being downloaded is: Mycobacterium tuberculosis H37Rv and is being downloaded as 83332.tab.

2.3 Some pattern matching

This little block is intended to seek out peptide sequences with the highly degenerate pattern: Y(E|D) with a varying number of amino acids between the Y and (E or D).

get_hits <- function(patterns, peptide_file, pct_limit=0.25) {
  pep_seq <- Biostrings::readAAStringSet(peptide_file)
  pep_lst <- as.data.frame(pep_seq)[["x"]]
  pos_df <- data.frame(stringsAsFactors=FALSE)
  pep_names <- names(pep_seq)
  rowname <- ""
  for (r in 1:length(pep_names)) {
    rowname <- pep_names[r]
    new_row <- vector()
    found_hits <- FALSE
    for (p in 1:length(patterns)) {
      pat <- patterns[[p]]
      pname <- names(patterns)[p]
      column <- gregexpr(pattern=pat, text=pep_lst)
      names(column) <- names(pep_seq)
      name <- names(column)[r]
      row <- column[[r]]
      len <- nchar(pep_lst[r])
      pct <- as.numeric(row) / len
      cdist <- len - as.numeric(row)
      pos_name <- glue::glue("pos_{pname}")
      num_name <- glue::glue("number_{pname}")
      nt_name <- glue::glue("nt_{pname}")
      ct_name <- glue::glue("ct_{pname}")
      pct_name <- glue::glue("pct_{pname}")
      pos_name <- glue::glue("pos_{pname}")
      ## An important caveat here:  There may be more than one value.
      new_row["rowname"] <- rowname
      number_hits <- length(as.numeric(row))
      if (as.numeric(row)[1] == -1) {
        number_hits <- "0"
      }
      new_row[num_name] <- number_hits
      new_row[pos_name] <- toString(as.numeric(row))
      if (new_row[pos_name] == "-1") {
        new_row[pos_name] <- "0"
      } else {
        found_hits <- TRUE
      }
      new_row["length"] <- len
      op <- options(warn=2)
      if (pct[1] < 0) {
        new_row[pct_name] <- "0"
      } else {
        new_row[pct_name] <- toString(pct)
      }
      options(op)
      nt_str <- ""
      ct_str <- ""
      max_pct <- 1 - pct_limit
      for (i in pct) {
        if (i < 0) {
          next
        }
        if (i < pct_limit) {
          nt_str <- paste0(nt_str, ", ", i)
        }
        if (i > max_pct) {
          ct_str <- paste0(ct_str, ", ", i)
        }
      }
      nt_str <- gsub(pattern="^\\, ", replacement="", x=nt_str)
      ct_str <- gsub(pattern="^\\, ", replacement="", x=ct_str)
      new_row[nt_name] <- nt_str
      new_row[ct_name] <- ct_str
    }
    if (isTRUE(found_hits)) {
      pos_df <- rbind(pos_df, new_row, stringsAsFactors=FALSE)
      colnames(pos_df) <- names(new_row)
    }
  } ## End for every gene
  rownames(pos_df) <- pos_df[["rowname"]]
  pos_df <- pos_df[-1, ]

  return(pos_df)
}

##patterns <- c("Y(E|D)", "Y.(E|D)", "Y..(E|D)", "Y...(E|D)", "Y....(E|D)", "Y.....(E|D)")
mtb_cds <- "reference/mtb_cds.fasta"
patterns <- c("Y..(E|D)", "Y...(E|D)")
names(patterns) <- c("two", "three")
yed_patterns <- get_hits(patterns, mtb_cds)
written <- write_xls(yed_patterns, excel="positions_by_patterns.xlsx")
## Saving to: positions_by_patterns.xlsx
## Note: zip::zip() is deprecated, please use zip::zipr() instead

2.6 Compare subset of interesting proteins vs. all

Najib and Volker requested a comparison of the distribution pattern hits of all proteins vs. the distribution in a specific subset of proteins. I don’t actually know the subset desired, so I will assume the

## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 083922869a37724ece10beed7b0bb758a179fdfb
## This is hpgltools commit: Thu Oct 17 11:43:00 2019 -0400: 083922869a37724ece10beed7b0bb758a179fdfb
## Saving to 01_annotation_20190718-v20190718.rda.xz
LS0tCnRpdGxlOiAiTS50dWJlcmN1bG9zaXMgMjAxOTA3MTggcHJvdGVvbWljczogQ29sbGVjdGluZyBhbm5vdGF0aW9uIGRhdGEuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRmX3ByaW50OiBwYWdlZAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgd2lkdGg6IDMwMAogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIEJpb2NTdHlsZTo6aHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiBmb250LXNpemU6IDE2cHgKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgiaHBnbHRvb2xzIikKdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHdpZHRoPTEyMCwKICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3M9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cz00LAogICAgICAgICAgICAgICAgICAgICAgIG1heC5wcmludD0xMjAsCiAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWw9ImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZT0xMCkpCnZlciA8LSAiMjAxOTA3MTgiCnByZXZpb3VzX2ZpbGUgPC0gImluZGV4LlJtZCIKCnRtcCA8LSB0cnkoc20obG9hZG1lKGZpbGVuYW1lPXBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cHJldmlvdXNfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKSkpKQpybWRfZmlsZSA8LSBwYXN0ZTAoIjAxX2Fubm90YXRpb25fIiwgdmVyLCAiLlJtZCIpCmBgYAoKQSBmcmVzaCBydW5uaW5nIG9mIGFsbCBwcm90ZW9taWNzIHRhc2tzCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKSSB0aGluayBJIGZpbmFsbHkgd29ya2VkIG91dCBhbGwobW9zdD8pIG9mIHRoZSBraW5rcyBpbiB0aGUgcHJvY2Vzc2luZyBvZiBESUEgZGF0YS4KVGh1cyBJIHdhbnQgdG8gaGF2ZSBhIGZyZXNoIHJ1biBvZiBhbGwgdGhlIHRhc2tzIHJlcXVpcmVkIHRvIGludGVycHJldCB0aGUgcmVzdWx0cy4KCiMgQW5ub3RhdGlvbiB2ZXJzaW9uOiBgciB2ZXJgCgojIyBHZW5vbWUgYW5ub3RhdGlvbiBpbnB1dAoKIyMjIFJlYWQgYSBnZmYgZmlsZQoKSW4gY29udHJhc3QsIGl0IGlzIHBvc3NpYmxlIHRvIGxvYWQgbW9zdCBhbm5vdGF0aW9ucyBvZiBpbnRlcmVzdCBkaXJlY3RseSBmcm9tIHRoZSBnZmYgZmlsZXMgdXNlZCBpbgp0aGUgYWxpZ25tZW50cy4gIE1vcmUgaW4tZGVwdGggaW5mb3JtYXRpb24gZm9yIHRoZSBodW1hbiB0cmFuc2NyaXB0b21lIG1heSBiZSBleHRyYWN0ZWQgZnJvbSBiaW9tYXJ0LgoKYGBge3IgZ2Vub21lX2lucHV0fQojIyBUaGUgb2xkIHdheSBvZiBnZXR0aW5nIGdlbm9tZS9hbm5vdGF0aW9uIGRhdGEKbXRiX2dmZiA8LSAicmVmZXJlbmNlL215Y29iYWN0ZXJpdW1fdHViZXJjdWxvc2lzX2gzN3J2XzIuZ2ZmLmd6IgptdGJfZ2Vub21lIDwtICJyZWZlcmVuY2UvbXR1YmVyY3Vsb3Npc19oMzdydl9nZW5iYW5rLmZhc3RhIgptdGJfY2RzIDwtICJyZWZlcmVuY2UvbXRiX2Nkcy5mYXN0YSIKCm10Yl9hbm5vdGF0aW9ucyA8LSBzbShsb2FkX2dmZl9hbm5vdGF0aW9ucyhtdGJfZ2ZmLCB0eXBlPSJnZW5lIikpCmNvbG5hbWVzKG10Yl9hbm5vdGF0aW9ucykgPC0gZ3N1YihwYXR0ZXJuPSJcXC4iLCByZXBsYWNlbWVudD0iIiwgeD1jb2xuYW1lcyhtdGJfYW5ub3RhdGlvbnMpKQptdGJfYW5ub3RhdGlvbnNbWyJkZXNjcmlwdGlvbiJdXSA8LSBnc3ViKHBhdHRlcm49IlxcKyIsIHJlcGxhY2VtZW50PSIgIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PW10Yl9hbm5vdGF0aW9uc1tbImRlc2NyaXB0aW9uIl1dKQptdGJfYW5ub3RhdGlvbnNbWyJmdW5jdGlvbiJdXSA8LSBnc3ViKHBhdHRlcm49IlxcKyIsIHJlcGxhY2VtZW50PSIgIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PW10Yl9hbm5vdGF0aW9uc1tbImZ1bmN0aW9uIl1dKQpyb3duYW1lcyhtdGJfYW5ub3RhdGlvbnMpIDwtIG10Yl9hbm5vdGF0aW9uc1tbIklEIl1dCmBgYAoKIyMjIERvd25sb2FkIGZyb20gbWljcm9iZXNvbmxpbmUKCkFwcGFyZW50bHkgSSBxdWVyaWVkIHRoZSBtaWNyb2Jlc29ubGluZSB0b28gb2Z0ZW4gYW5kIG5vdyBJIGdldCBhbiBlcnJvcgp3aGVuZXZlciBJIHRyeSB0byB1c2UgdGhlbSwgdGhpcyBkaXNhcHBvaW50cyBtZS4KCmBgYHtyIGdlbmJhbmt9CiMjIEkgbWFkZSBhIG5pZnR5IGZ1bmN0aW9uIHRvIGRvIHRoaXMgc3R1ZmY6IGxvYWRfdW5pcHJvdHdzX2Fubm90YXRpb25zKCkuCiMjIEl0IGlzIHNsb3csIHRob3VnaC4KbXRiX21pY3JvYmVzIDwtIGxvYWRfbWljcm9iZXNvbmxpbmVfYW5ub3RhdGlvbnMoaWQ9ODMzMzIpCiMjIG10Yl91bmlwcm90X2Fubm90IDwtIGxvYWRfdW5pcHJvdHdzX2Fubm90YXRpb25zKCkKbXRiX3VuaXByb3RfYW5ub3QgPC0gc20obG9hZF91bmlwcm90X2Fubm90YXRpb25zKGZpbGU9InJlZmVyZW5jZS91bmlwcm90XzNBVVAwMDAwMDE1ODQudHh0Lmd6IikpCmBgYAoKIyMgR2V0dGluZyBvbnRvbG9neSBkYXRhCgpgYGB7ciBvbnRvbG9neX0KbXRiX2dvIDwtIGxvYWRfbWljcm9iZXNvbmxpbmVfZ28oaWQ9ODMzMzIpCmBgYAoKIyMgU29tZSBwYXR0ZXJuIG1hdGNoaW5nCgpUaGlzIGxpdHRsZSBibG9jayBpcyBpbnRlbmRlZCB0byBzZWVrIG91dCBwZXB0aWRlIHNlcXVlbmNlcyB3aXRoIHRoZSBoaWdobHkgZGVnZW5lcmF0ZSBwYXR0ZXJuOgpZKEV8RCkgd2l0aCBhIHZhcnlpbmcgbnVtYmVyIG9mIGFtaW5vIGFjaWRzIGJldHdlZW4gdGhlIFkgYW5kIChFIG9yIEQpLgoKYGBge3IgcGF0dGVybn0KZ2V0X2hpdHMgPC0gZnVuY3Rpb24ocGF0dGVybnMsIHBlcHRpZGVfZmlsZSwgcGN0X2xpbWl0PTAuMjUpIHsKICBwZXBfc2VxIDwtIEJpb3N0cmluZ3M6OnJlYWRBQVN0cmluZ1NldChwZXB0aWRlX2ZpbGUpCiAgcGVwX2xzdCA8LSBhcy5kYXRhLmZyYW1lKHBlcF9zZXEpW1sieCJdXQogIHBvc19kZiA8LSBkYXRhLmZyYW1lKHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCiAgcGVwX25hbWVzIDwtIG5hbWVzKHBlcF9zZXEpCiAgcm93bmFtZSA8LSAiIgogIGZvciAociBpbiAxOmxlbmd0aChwZXBfbmFtZXMpKSB7CiAgICByb3duYW1lIDwtIHBlcF9uYW1lc1tyXQogICAgbmV3X3JvdyA8LSB2ZWN0b3IoKQogICAgZm91bmRfaGl0cyA8LSBGQUxTRQogICAgZm9yIChwIGluIDE6bGVuZ3RoKHBhdHRlcm5zKSkgewogICAgICBwYXQgPC0gcGF0dGVybnNbW3BdXQogICAgICBwbmFtZSA8LSBuYW1lcyhwYXR0ZXJucylbcF0KICAgICAgY29sdW1uIDwtIGdyZWdleHByKHBhdHRlcm49cGF0LCB0ZXh0PXBlcF9sc3QpCiAgICAgIG5hbWVzKGNvbHVtbikgPC0gbmFtZXMocGVwX3NlcSkKICAgICAgbmFtZSA8LSBuYW1lcyhjb2x1bW4pW3JdCiAgICAgIHJvdyA8LSBjb2x1bW5bW3JdXQogICAgICBsZW4gPC0gbmNoYXIocGVwX2xzdFtyXSkKICAgICAgcGN0IDwtIGFzLm51bWVyaWMocm93KSAvIGxlbgogICAgICBjZGlzdCA8LSBsZW4gLSBhcy5udW1lcmljKHJvdykKICAgICAgcG9zX25hbWUgPC0gZ2x1ZTo6Z2x1ZSgicG9zX3twbmFtZX0iKQogICAgICBudW1fbmFtZSA8LSBnbHVlOjpnbHVlKCJudW1iZXJfe3BuYW1lfSIpCiAgICAgIG50X25hbWUgPC0gZ2x1ZTo6Z2x1ZSgibnRfe3BuYW1lfSIpCiAgICAgIGN0X25hbWUgPC0gZ2x1ZTo6Z2x1ZSgiY3Rfe3BuYW1lfSIpCiAgICAgIHBjdF9uYW1lIDwtIGdsdWU6OmdsdWUoInBjdF97cG5hbWV9IikKICAgICAgcG9zX25hbWUgPC0gZ2x1ZTo6Z2x1ZSgicG9zX3twbmFtZX0iKQogICAgICAjIyBBbiBpbXBvcnRhbnQgY2F2ZWF0IGhlcmU6ICBUaGVyZSBtYXkgYmUgbW9yZSB0aGFuIG9uZSB2YWx1ZS4KICAgICAgbmV3X3Jvd1sicm93bmFtZSJdIDwtIHJvd25hbWUKICAgICAgbnVtYmVyX2hpdHMgPC0gbGVuZ3RoKGFzLm51bWVyaWMocm93KSkKICAgICAgaWYgKGFzLm51bWVyaWMocm93KVsxXSA9PSAtMSkgewogICAgICAgIG51bWJlcl9oaXRzIDwtICIwIgogICAgICB9CiAgICAgIG5ld19yb3dbbnVtX25hbWVdIDwtIG51bWJlcl9oaXRzCiAgICAgIG5ld19yb3dbcG9zX25hbWVdIDwtIHRvU3RyaW5nKGFzLm51bWVyaWMocm93KSkKICAgICAgaWYgKG5ld19yb3dbcG9zX25hbWVdID09ICItMSIpIHsKICAgICAgICBuZXdfcm93W3Bvc19uYW1lXSA8LSAiMCIKICAgICAgfSBlbHNlIHsKICAgICAgICBmb3VuZF9oaXRzIDwtIFRSVUUKICAgICAgfQogICAgICBuZXdfcm93WyJsZW5ndGgiXSA8LSBsZW4KICAgICAgb3AgPC0gb3B0aW9ucyh3YXJuPTIpCiAgICAgIGlmIChwY3RbMV0gPCAwKSB7CiAgICAgICAgbmV3X3Jvd1twY3RfbmFtZV0gPC0gIjAiCiAgICAgIH0gZWxzZSB7CiAgICAgICAgbmV3X3Jvd1twY3RfbmFtZV0gPC0gdG9TdHJpbmcocGN0KQogICAgICB9CiAgICAgIG9wdGlvbnMob3ApCiAgICAgIG50X3N0ciA8LSAiIgogICAgICBjdF9zdHIgPC0gIiIKICAgICAgbWF4X3BjdCA8LSAxIC0gcGN0X2xpbWl0CiAgICAgIGZvciAoaSBpbiBwY3QpIHsKICAgICAgICBpZiAoaSA8IDApIHsKICAgICAgICAgIG5leHQKICAgICAgICB9CiAgICAgICAgaWYgKGkgPCBwY3RfbGltaXQpIHsKICAgICAgICAgIG50X3N0ciA8LSBwYXN0ZTAobnRfc3RyLCAiLCAiLCBpKQogICAgICAgIH0KICAgICAgICBpZiAoaSA+IG1heF9wY3QpIHsKICAgICAgICAgIGN0X3N0ciA8LSBwYXN0ZTAoY3Rfc3RyLCAiLCAiLCBpKQogICAgICAgIH0KICAgICAgfQogICAgICBudF9zdHIgPC0gZ3N1YihwYXR0ZXJuPSJeXFwsICIsIHJlcGxhY2VtZW50PSIiLCB4PW50X3N0cikKICAgICAgY3Rfc3RyIDwtIGdzdWIocGF0dGVybj0iXlxcLCAiLCByZXBsYWNlbWVudD0iIiwgeD1jdF9zdHIpCiAgICAgIG5ld19yb3dbbnRfbmFtZV0gPC0gbnRfc3RyCiAgICAgIG5ld19yb3dbY3RfbmFtZV0gPC0gY3Rfc3RyCiAgICB9CiAgICBpZiAoaXNUUlVFKGZvdW5kX2hpdHMpKSB7CiAgICAgIHBvc19kZiA8LSByYmluZChwb3NfZGYsIG5ld19yb3csIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCiAgICAgIGNvbG5hbWVzKHBvc19kZikgPC0gbmFtZXMobmV3X3JvdykKICAgIH0KICB9ICMjIEVuZCBmb3IgZXZlcnkgZ2VuZQogIHJvd25hbWVzKHBvc19kZikgPC0gcG9zX2RmW1sicm93bmFtZSJdXQogIHBvc19kZiA8LSBwb3NfZGZbLTEsIF0KCiAgcmV0dXJuKHBvc19kZikKfQoKIyNwYXR0ZXJucyA8LSBjKCJZKEV8RCkiLCAiWS4oRXxEKSIsICJZLi4oRXxEKSIsICJZLi4uKEV8RCkiLCAiWS4uLi4oRXxEKSIsICJZLi4uLi4oRXxEKSIpCm10Yl9jZHMgPC0gInJlZmVyZW5jZS9tdGJfY2RzLmZhc3RhIgpwYXR0ZXJucyA8LSBjKCJZLi4oRXxEKSIsICJZLi4uKEV8RCkiKQpuYW1lcyhwYXR0ZXJucykgPC0gYygidHdvIiwgInRocmVlIikKeWVkX3BhdHRlcm5zIDwtIGdldF9oaXRzKHBhdHRlcm5zLCBtdGJfY2RzKQp3cml0dGVuIDwtIHdyaXRlX3hscyh5ZWRfcGF0dGVybnMsIGV4Y2VsPSJwb3NpdGlvbnNfYnlfcGF0dGVybnMueGxzeCIpCmBgYAoKIyMgUmFuZG9tIHF1ZXJ5IGZyb20gVm9sa2VyCgpXaGF0IHByb3RlaW5zIGRvIG5vdCBoYXZlIGdseWNpbmU/CgpHbHljaW5lIDogR2x5IDogRwpHbHV0YW1pbmUgOiBHbHUgOiBFCgpgYGB7ciBnbHljaW5lfQpwZXBfc2VxIDwtIEJpb3N0cmluZ3M6OnJlYWRBQVN0cmluZ1NldChtdGJfY2RzKQpwZXBfbHN0IDwtIGFzLmRhdGEuZnJhbWUocGVwX3NlcSlbWyJ4Il1dCnBvc19kZiA8LSBkYXRhLmZyYW1lKHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCnBlcF9uYW1lcyA8LSBuYW1lcyhwZXBfc2VxKQpwZXBfZGYgPC0gYXMuZGF0YS5mcmFtZShwZXBfc2VxKQpnbHljaW5lX2hpdHMgPC0gZ3JlcGwocGF0dGVybj0iRyIsIHg9cGVwX2RmW1sieCJdXSkKcm93bmFtZXMocGVwX2RmKVshZ2x5Y2luZV9oaXRzXQpgYGAKCiMjIEFkZCB0aGUgWUVEIHBhdHRlcm5zIHRvIHRoZSBhbm5vdGF0aW9uIGRhdGEKCmBgYHtyIHllZF9hZGRlZH0KbXRiX2Fubm90YXRpb25zIDwtIG1lcmdlKG10Yl9hbm5vdGF0aW9ucywgeWVkX3BhdHRlcm5zLCBieT0icm93Lm5hbWVzIiwgYWxsLng9VFJVRSkKcm93bmFtZXMobXRiX2Fubm90YXRpb25zKSA8LSBtdGJfYW5ub3RhdGlvbnNbWyJSb3cubmFtZXMiXV0KbXRiX2Fubm90YXRpb25zIDwtIG10Yl9hbm5vdGF0aW9uc1stMSwgXQpgYGAKCiMjIENvbXBhcmUgc3Vic2V0IG9mIGludGVyZXN0aW5nIHByb3RlaW5zIHZzLiBhbGwKCk5hamliIGFuZCBWb2xrZXIgcmVxdWVzdGVkIGEgY29tcGFyaXNvbiBvZiB0aGUgZGlzdHJpYnV0aW9uIHBhdHRlcm4gaGl0cyBvZiBhbGwKcHJvdGVpbnMgdnMuIHRoZSBkaXN0cmlidXRpb24gaW4gYSBzcGVjaWZpYyBzdWJzZXQgb2YgcHJvdGVpbnMuICBJIGRvbid0CmFjdHVhbGx5IGtub3cgdGhlIHN1YnNldCBkZXNpcmVkLCBzbyBJIHdpbGwgYXNzdW1lIHRoZQoKYGBge3IgcGVfdGVzdGluZywgZXZhbD1GQUxTRX0KcGVfaWRzIDwtIHJlYWQudGFibGUoInJlZmVyZW5jZS9hbm5vdGF0ZWRfcGVfZ2VuZXMudHh0IilbWyJWMSJdXQoKeWVkX3BlIDwtIHllZF9wYXR0ZXJuc1twZV9pZHMsIF0KCmFsbF9udW1iZXJzIDwtIGFzLm51bWVyaWMoeWVkX3BhdHRlcm5zW1sibnVtYmVyX3R3byJdXSkKcGVfbnVtYmVycyA8LSBhcy5udW1lcmljKHllZF9wZVtbIm51bWJlcl90d28iXV0pCgphbGx0aHJlZV9udW1iZXJzIDwtIGFzLm51bWVyaWMoeWVkX3BhdHRlcm5zW1sibnVtYmVyX3RocmVlIl1dKQpwZXRocmVlX251bWJlcnMgPC0gYXMubnVtZXJpYyh5ZWRfcGVbWyJudW1iZXJfdGhyZWUiXV0pCgphbGxfcGN0IDwtIHllZF9wYXR0ZXJuc1tbInBjdF90d28iXV0KcGVfcGN0IDwtIHllZF9wZVtbInBjdF90d28iXV0KYWxsX3Bvc2l0aW9ucyA8LSB5ZWRfcGF0dGVybnNbWyJwb3NfdHdvIl1dCnBlX3Bvc2l0aW9ucyA8LSB5ZWRfcGVbWyJwb3NfdHdvIl1dCgpzYW1wbGVkX251bWJlcnNfdHdvIDwtIHNhbXBsZSh4PWFsbF9udW1iZXJzLCBzaXplPTEwMDAsIHJlcGxhY2U9VFJVRSkKc3VtbWFyeShzYW1wbGVkX251bWJlcnNfdHdvKQpwZV9udW1iZXJzW2lzLm5hKHBlX251bWJlcnMpXSA8LSAwCnN1bW1hcnkocGVfbnVtYmVycykKCnNhbXBsZWRfbnVtYmVyc190aHJlZSA8LSBzYW1wbGUoeD1hbGx0aHJlZV9udW1iZXJzLCBzaXplPTEwMDAsIHJlcGxhY2U9VFJVRSkKc3VtbWFyeShzYW1wbGVkX251bWJlcnNfdGhyZWUpCnBldGhyZWVfbnVtYmVyc1tpcy5uYShwZXRocmVlX251bWJlcnMpXSA8LSAwCnN1bW1hcnkocGV0aHJlZV9udW1iZXJzKQpgYGAKCmBgYHtyIHNhdmVtZX0KaWYgKCFpc1RSVUUoZ2V0MCgic2tpcF9sb2FkIikpKSB7CiAgcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKICBtZXNzYWdlKHBhc3RlMCgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKSkKICB0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1ybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQogIG1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgdGhpc19zYXZlKSkKICB0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lPXRoaXNfc2F2ZSkpCn0KYGBgCg==