M.tuberculosis 20181112 proteomics: Collecting annotation data.

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.

Annotation version: 20181112

Getting ontology data

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

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

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

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.00    0.00    1.00    1.22    2.00    8.00
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   0.000   0.000   0.329   1.000   3.000
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.00    0.00    1.00    1.22    2.00   13.00
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   0.000   1.000   0.708   1.000   4.000
## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 455a7f0db4618c2209c21a978a41441bd4891095
## This is hpgltools commit: Mon Nov 12 15:13:53 2018 -0500: 455a7f0db4618c2209c21a978a41441bd4891095
## Saving to 01_annotation_20181112-v20181112.rda.xz

atb abelew@gmail.com

2018-11-12

LS0tCnRpdGxlOiAiTS50dWJlcmN1bG9zaXMgMjAxODExMTIgcHJvdGVvbWljczogQ29sbGVjdGluZyBhbm5vdGF0aW9uIGRhdGEuIgphdXRob3I6ICJhdGIgYWJlbGV3QGdtYWlsLmNvbSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGRmX3ByaW50OiBwYWdlZAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgd2lkdGg6IDMwMAogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIEJpb2NTdHlsZTo6aHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIHRvY19mbG9hdDogdHJ1ZQogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBmaWdfaGVpZ2h0OiA3CiAgICBmaWdfd2lkdGg6IDcKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IGZhbHNlCiAgICBtb2RlOiBzZWxmY29udGFpbmVkCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICB0aGVtZTogcmVhZGFibGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlCi0tLQoKPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KYm9keSwgdGQgewogIGZvbnQtc2l6ZTogMTZweDsKfQpjb2RlLnJ7CiAgZm9udC1zaXplOiAxNnB4Owp9CnByZSB7CiBmb250LXNpemU6IDE2cHgKfQo8L3N0eWxlPgoKYGBge3Igb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgiaHBnbHRvb2xzIikKdHQgPC0gZGV2dG9vbHM6OmxvYWRfYWxsKCJ+L2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHdpZHRoPTEyMCwKICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3M9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cz00LAogICAgICAgICAgICAgICAgICAgICAgIG1heC5wcmludD0xMjAsCiAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBrbml0ci5kdXBsaWNhdGUubGFiZWw9ImFsbG93IikKZ2dwbG90Mjo6dGhlbWVfc2V0KGdncGxvdDI6OnRoZW1lX2J3KGJhc2Vfc2l6ZT0xMCkpCnZlciA8LSAiMjAxODExMTIiCnByZXZpb3VzX2ZpbGUgPC0gImluZGV4LlJtZCIKCnRtcCA8LSB0cnkoc20obG9hZG1lKGZpbGVuYW1lPXBhc3RlMChnc3ViKHBhdHRlcm49IlxcLlJtZCIsIHJlcGxhY2U9IiIsIHg9cHJldmlvdXNfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKSkpKQpybWRfZmlsZSA8LSBwYXN0ZTAoIjAxX2Fubm90YXRpb25fIiwgdmVyLCAiLlJtZCIpCmBgYAoKQSBmcmVzaCBydW5uaW5nIG9mIGFsbCBwcm90ZW9taWNzIHRhc2tzCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKSSB0aGluayBJIGZpbmFsbHkgd29ya2VkIG91dCBhbGwobW9zdD8pIG9mIHRoZSBraW5rcyBpbiB0aGUgcHJvY2Vzc2luZyBvZiBESUEgZGF0YS4KVGh1cyBJIHdhbnQgdG8gaGF2ZSBhIGZyZXNoIHJ1biBvZiBhbGwgdGhlIHRhc2tzIHJlcXVpcmVkIHRvIGludGVycHJldCB0aGUgcmVzdWx0cy4KCiMgQW5ub3RhdGlvbiB2ZXJzaW9uOiBgciB2ZXJgCgojIyBHZW5vbWUgYW5ub3RhdGlvbiBpbnB1dAoKIyMjIFJlYWQgYSBnZmYgZmlsZQoKSW4gY29udHJhc3QsIGl0IGlzIHBvc3NpYmxlIHRvIGxvYWQgbW9zdCBhbm5vdGF0aW9ucyBvZiBpbnRlcmVzdCBkaXJlY3RseSBmcm9tIHRoZSBnZmYgZmlsZXMgdXNlZCBpbgp0aGUgYWxpZ25tZW50cy4gIE1vcmUgaW4tZGVwdGggaW5mb3JtYXRpb24gZm9yIHRoZSBodW1hbiB0cmFuc2NyaXB0b21lIG1heSBiZSBleHRyYWN0ZWQgZnJvbSBiaW9tYXJ0LgoKYGBge3IgZ2Vub21lX2lucHV0fQojIyBUaGUgb2xkIHdheSBvZiBnZXR0aW5nIGdlbm9tZS9hbm5vdGF0aW9uIGRhdGEKbXRiX2dmZiA8LSAicmVmZXJlbmNlL215Y29iYWN0ZXJpdW1fdHViZXJjdWxvc2lzX2gzN3J2XzIuZ2ZmLmd6IgptdGJfZ2Vub21lIDwtICJyZWZlcmVuY2UvbXR1YmVyY3Vsb3Npc19oMzdydl9nZW5iYW5rLmZhc3RhIgptdGJfY2RzIDwtICJyZWZlcmVuY2UvbXRiX2Nkcy5mYXN0YSIKCm10Yl9hbm5vdGF0aW9ucyA8LSBzbShsb2FkX2dmZl9hbm5vdGF0aW9ucyhtdGJfZ2ZmLCB0eXBlPSJnZW5lIikpCmNvbG5hbWVzKG10Yl9hbm5vdGF0aW9ucykgPC0gZ3N1YihwYXR0ZXJuPSJcXC4iLCByZXBsYWNlbWVudD0iIiwgeD1jb2xuYW1lcyhtdGJfYW5ub3RhdGlvbnMpKQptdGJfYW5ub3RhdGlvbnNbWyJkZXNjcmlwdGlvbiJdXSA8LSBnc3ViKHBhdHRlcm49IlxcKyIsIHJlcGxhY2VtZW50PSIgIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PW10Yl9hbm5vdGF0aW9uc1tbImRlc2NyaXB0aW9uIl1dKQptdGJfYW5ub3RhdGlvbnNbWyJmdW5jdGlvbiJdXSA8LSBnc3ViKHBhdHRlcm49IlxcKyIsIHJlcGxhY2VtZW50PSIgIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4PW10Yl9hbm5vdGF0aW9uc1tbImZ1bmN0aW9uIl1dKQpyb3duYW1lcyhtdGJfYW5ub3RhdGlvbnMpIDwtIG10Yl9hbm5vdGF0aW9uc1tbIklEIl1dCmBgYAoKIyMjIERvd25sb2FkIGZyb20gbWljcm9iZXNvbmxpbmUKCkFwcGFyZW50bHkgSSBxdWVyaWVkIHRoZSBtaWNyb2Jlc29ubGluZSB0b28gb2Z0ZW4gYW5kIG5vdyBJIGdldCBhbiBlcnJvcgp3aGVuZXZlciBJIHRyeSB0byB1c2UgdGhlbSwgdGhpcyBkaXNhcHBvaW50cyBtZS4KCmBgYHtyIGdlbmJhbmt9CiMjIEkgbWFkZSBhIG5pZnR5IGZ1bmN0aW9uIHRvIGRvIHRoaXMgc3R1ZmY6IGxvYWRfdW5pcHJvdHdzX2Fubm90YXRpb25zKCkuCiMjIEl0IGlzIHNsb3csIHRob3VnaC4KbXRiX21pY3JvYmVzIDwtIGxvYWRfbWljcm9iZXNvbmxpbmVfYW5ub3RhdGlvbnMoaWQ9ODMzMzIpCiMjIG10Yl91bmlwcm90X2Fubm90IDwtIGxvYWRfdW5pcHJvdHdzX2Fubm90YXRpb25zKCkKbXRiX3VuaXByb3RfYW5ub3QgPC0gc20obG9hZF91bmlwcm90X2Fubm90YXRpb25zKGZpbGU9InJlZmVyZW5jZS91bmlwcm90XzNBVVAwMDAwMDE1ODQudHh0Lmd6IikpCmBgYAoKIyMgR2V0dGluZyBvbnRvbG9neSBkYXRhCgpgYGB7ciBvbnRvbG9neX0KbXRiX2dvIDwtIGxvYWRfbWljcm9iZXNvbmxpbmVfZ28oaWQ9ODMzMzIpCmBgYAoKIyMgU29tZSBwYXR0ZXJuIG1hdGNoaW5nCgpUaGlzIGxpdHRsZSBibG9jayBpcyBpbnRlbmRlZCB0byBzZWVrIG91dCBwZXB0aWRlIHNlcXVlbmNlcyB3aXRoIHRoZSBoaWdobHkgZGVnZW5lcmF0ZSBwYXR0ZXJuOgpZKEV8RCkgd2l0aCBhIHZhcnlpbmcgbnVtYmVyIG9mIGFtaW5vIGFjaWRzIGJldHdlZW4gdGhlIFkgYW5kIChFIG9yIEQpLgoKYGBge3IgcGF0dGVybn0KZ2V0X2hpdHMgPC0gZnVuY3Rpb24ocGF0dGVybnMsIHBlcHRpZGVfZmlsZSwgcGN0X2xpbWl0PTAuMjUpIHsKICBwZXBfc2VxIDwtIEJpb3N0cmluZ3M6OnJlYWRBQVN0cmluZ1NldChwZXB0aWRlX2ZpbGUpCiAgcGVwX2xzdCA8LSBhcy5kYXRhLmZyYW1lKHBlcF9zZXEpW1sieCJdXQogIHBvc19kZiA8LSBkYXRhLmZyYW1lKHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCiAgcGVwX25hbWVzIDwtIG5hbWVzKHBlcF9zZXEpCiAgcm93bmFtZSA8LSAiIgogIGZvciAociBpbiAxOmxlbmd0aChwZXBfbmFtZXMpKSB7CiAgICByb3duYW1lIDwtIHBlcF9uYW1lc1tyXQogICAgbmV3X3JvdyA8LSB2ZWN0b3IoKQogICAgZm91bmRfaGl0cyA8LSBGQUxTRQogICAgZm9yIChwIGluIDE6bGVuZ3RoKHBhdHRlcm5zKSkgewogICAgICBwYXQgPC0gcGF0dGVybnNbW3BdXQogICAgICBwbmFtZSA8LSBuYW1lcyhwYXR0ZXJucylbcF0KICAgICAgY29sdW1uIDwtIGdyZWdleHByKHBhdHRlcm49cGF0LCB0ZXh0PXBlcF9sc3QpCiAgICAgIG5hbWVzKGNvbHVtbikgPC0gbmFtZXMocGVwX3NlcSkKICAgICAgbmFtZSA8LSBuYW1lcyhjb2x1bW4pW3JdCiAgICAgIHJvdyA8LSBjb2x1bW5bW3JdXQogICAgICBsZW4gPC0gbmNoYXIocGVwX2xzdFtyXSkKICAgICAgcGN0IDwtIGFzLm51bWVyaWMocm93KSAvIGxlbgogICAgICBjZGlzdCA8LSBsZW4gLSBhcy5udW1lcmljKHJvdykKICAgICAgcG9zX25hbWUgPC0gZ2x1ZTo6Z2x1ZSgicG9zX3twbmFtZX0iKQogICAgICBudW1fbmFtZSA8LSBnbHVlOjpnbHVlKCJudW1iZXJfe3BuYW1lfSIpCiAgICAgIG50X25hbWUgPC0gZ2x1ZTo6Z2x1ZSgibnRfe3BuYW1lfSIpCiAgICAgIGN0X25hbWUgPC0gZ2x1ZTo6Z2x1ZSgiY3Rfe3BuYW1lfSIpCiAgICAgIHBjdF9uYW1lIDwtIGdsdWU6OmdsdWUoInBjdF97cG5hbWV9IikKICAgICAgcG9zX25hbWUgPC0gZ2x1ZTo6Z2x1ZSgicG9zX3twbmFtZX0iKQogICAgICAjIyBBbiBpbXBvcnRhbnQgY2F2ZWF0IGhlcmU6ICBUaGVyZSBtYXkgYmUgbW9yZSB0aGFuIG9uZSB2YWx1ZS4KICAgICAgbmV3X3Jvd1sicm93bmFtZSJdIDwtIHJvd25hbWUKICAgICAgbnVtYmVyX2hpdHMgPC0gbGVuZ3RoKGFzLm51bWVyaWMocm93KSkKICAgICAgaWYgKGFzLm51bWVyaWMocm93KVsxXSA9PSAtMSkgewogICAgICAgIG51bWJlcl9oaXRzIDwtICIwIgogICAgICB9CiAgICAgIG5ld19yb3dbbnVtX25hbWVdIDwtIG51bWJlcl9oaXRzCiAgICAgIG5ld19yb3dbcG9zX25hbWVdIDwtIHRvU3RyaW5nKGFzLm51bWVyaWMocm93KSkKICAgICAgaWYgKG5ld19yb3dbcG9zX25hbWVdID09ICItMSIpIHsKICAgICAgICBuZXdfcm93W3Bvc19uYW1lXSA8LSAiMCIKICAgICAgfSBlbHNlIHsKICAgICAgICBmb3VuZF9oaXRzIDwtIFRSVUUKICAgICAgfQogICAgICBuZXdfcm93WyJsZW5ndGgiXSA8LSBsZW4KICAgICAgb3AgPC0gb3B0aW9ucyh3YXJuPTIpCiAgICAgIGlmIChwY3RbMV0gPCAwKSB7CiAgICAgICAgbmV3X3Jvd1twY3RfbmFtZV0gPC0gIjAiCiAgICAgIH0gZWxzZSB7CiAgICAgICAgbmV3X3Jvd1twY3RfbmFtZV0gPC0gdG9TdHJpbmcocGN0KQogICAgICB9CiAgICAgIG9wdGlvbnMob3ApCiAgICAgIG50X3N0ciA8LSAiIgogICAgICBjdF9zdHIgPC0gIiIKICAgICAgbWF4X3BjdCA8LSAxIC0gcGN0X2xpbWl0CiAgICAgIGZvciAoaSBpbiBwY3QpIHsKICAgICAgICBpZiAoaSA8IDApIHsKICAgICAgICAgIG5leHQKICAgICAgICB9CiAgICAgICAgaWYgKGkgPCBwY3RfbGltaXQpIHsKICAgICAgICAgIG50X3N0ciA8LSBwYXN0ZTAobnRfc3RyLCAiLCAiLCBpKQogICAgICAgIH0KICAgICAgICBpZiAoaSA+IG1heF9wY3QpIHsKICAgICAgICAgIGN0X3N0ciA8LSBwYXN0ZTAoY3Rfc3RyLCAiLCAiLCBpKQogICAgICAgIH0KICAgICAgfQogICAgICBudF9zdHIgPC0gZ3N1YihwYXR0ZXJuPSJeXFwsICIsIHJlcGxhY2VtZW50PSIiLCB4PW50X3N0cikKICAgICAgY3Rfc3RyIDwtIGdzdWIocGF0dGVybj0iXlxcLCAiLCByZXBsYWNlbWVudD0iIiwgeD1jdF9zdHIpCiAgICAgIG5ld19yb3dbbnRfbmFtZV0gPC0gbnRfc3RyCiAgICAgIG5ld19yb3dbY3RfbmFtZV0gPC0gY3Rfc3RyCiAgICB9CiAgICBpZiAoaXNUUlVFKGZvdW5kX2hpdHMpKSB7CiAgICAgIHBvc19kZiA8LSByYmluZChwb3NfZGYsIG5ld19yb3csIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCiAgICAgIGNvbG5hbWVzKHBvc19kZikgPC0gbmFtZXMobmV3X3JvdykKICAgIH0KICB9ICMjIEVuZCBmb3IgZXZlcnkgZ2VuZQogIHJvd25hbWVzKHBvc19kZikgPC0gcG9zX2RmW1sicm93bmFtZSJdXQogIHBvc19kZiA8LSBwb3NfZGZbLTEsIF0KCiAgcmV0dXJuKHBvc19kZikKfQoKIyNwYXR0ZXJucyA8LSBjKCJZKEV8RCkiLCAiWS4oRXxEKSIsICJZLi4oRXxEKSIsICJZLi4uKEV8RCkiLCAiWS4uLi4oRXxEKSIsICJZLi4uLi4oRXxEKSIpCm10Yl9jZHMgPC0gInJlZmVyZW5jZS9tdGJfY2RzLmZhc3RhIgpwYXR0ZXJucyA8LSBjKCJZLi4oRXxEKSIsICJZLi4uKEV8RCkiKQpuYW1lcyhwYXR0ZXJucykgPC0gYygidHdvIiwgInRocmVlIikKeWVkX3BhdHRlcm5zIDwtIGdldF9oaXRzKHBhdHRlcm5zLCBtdGJfY2RzKQp3cml0dGVuIDwtIHdyaXRlX3hscyh5ZWRfcGF0dGVybnMsIGV4Y2VsPSJwb3NpdGlvbnNfYnlfcGF0dGVybnMueGxzeCIpCmBgYAoKIyMgQWRkIHRoZSBZRUQgcGF0dGVybnMgdG8gdGhlIGFubm90YXRpb24gZGF0YQoKYGBge3IgeWVkX2FkZGVkfQptdGJfYW5ub3RhdGlvbnMgPC0gbWVyZ2UobXRiX2Fubm90YXRpb25zLCB5ZWRfcGF0dGVybnMsIGJ5PSJyb3cubmFtZXMiLCBhbGwueD1UUlVFKQpyb3duYW1lcyhtdGJfYW5ub3RhdGlvbnMpIDwtIG10Yl9hbm5vdGF0aW9uc1tbIlJvdy5uYW1lcyJdXQptdGJfYW5ub3RhdGlvbnMgPC0gbXRiX2Fubm90YXRpb25zWy0xLCBdCmBgYAoKIyMgQ29tcGFyZSBzdWJzZXQgb2YgaW50ZXJlc3RpbmcgcHJvdGVpbnMgdnMuIGFsbAoKTmFqaWIgYW5kIFZvbGtlciByZXF1ZXN0ZWQgYSBjb21wYXJpc29uIG9mIHRoZSBkaXN0cmlidXRpb24gcGF0dGVybiBoaXRzIG9mIGFsbApwcm90ZWlucyB2cy4gdGhlIGRpc3RyaWJ1dGlvbiBpbiBhIHNwZWNpZmljIHN1YnNldCBvZiBwcm90ZWlucy4gIEkgZG9uJ3QKYWN0dWFsbHkga25vdyB0aGUgc3Vic2V0IGRlc2lyZWQsIHNvIEkgd2lsbCBhc3N1bWUgdGhlCgpgYGB7ciBwZV90ZXN0aW5nfQpwZV9pZHMgPC0gcmVhZC50YWJsZSgicmVmZXJlbmNlL2Fubm90YXRlZF9wZV9nZW5lcy50eHQiKVtbIlYxIl1dCgp5ZWRfcGUgPC0geWVkX3BhdHRlcm5zW3BlX2lkcywgXQoKYWxsX251bWJlcnMgPC0gYXMubnVtZXJpYyh5ZWRfcGF0dGVybnNbWyJudW1iZXJfdHdvIl1dKQpwZV9udW1iZXJzIDwtIGFzLm51bWVyaWMoeWVkX3BlW1sibnVtYmVyX3R3byJdXSkKCmFsbHRocmVlX251bWJlcnMgPC0gYXMubnVtZXJpYyh5ZWRfcGF0dGVybnNbWyJudW1iZXJfdGhyZWUiXV0pCnBldGhyZWVfbnVtYmVycyA8LSBhcy5udW1lcmljKHllZF9wZVtbIm51bWJlcl90aHJlZSJdXSkKCmFsbF9wY3QgPC0geWVkX3BhdHRlcm5zW1sicGN0X3R3byJdXQpwZV9wY3QgPC0geWVkX3BlW1sicGN0X3R3byJdXQphbGxfcG9zaXRpb25zIDwtIHllZF9wYXR0ZXJuc1tbInBvc190d28iXV0KcGVfcG9zaXRpb25zIDwtIHllZF9wZVtbInBvc190d28iXV0KCnNhbXBsZWRfbnVtYmVyc190d28gPC0gc2FtcGxlKHg9YWxsX251bWJlcnMsIHNpemU9MTAwMCwgcmVwbGFjZT1UUlVFKQpzdW1tYXJ5KHNhbXBsZWRfbnVtYmVyc190d28pCnBlX251bWJlcnNbaXMubmEocGVfbnVtYmVycyldIDwtIDAKc3VtbWFyeShwZV9udW1iZXJzKQoKc2FtcGxlZF9udW1iZXJzX3RocmVlIDwtIHNhbXBsZSh4PWFsbHRocmVlX251bWJlcnMsIHNpemU9MTAwMCwgcmVwbGFjZT1UUlVFKQpzdW1tYXJ5KHNhbXBsZWRfbnVtYmVyc190aHJlZSkKcGV0aHJlZV9udW1iZXJzW2lzLm5hKHBldGhyZWVfbnVtYmVycyldIDwtIDAKc3VtbWFyeShwZXRocmVlX251bWJlcnMpCmBgYAoKYGBge3Igc2F2ZW1lfQppZiAoIWlzVFJVRShnZXQwKCJza2lwX2xvYWQiKSkpIHsKICBwYW5kZXI6OnBhbmRlcihzZXNzaW9uSW5mbygpKQogIG1lc3NhZ2UocGFzdGUwKCJUaGlzIGlzIGhwZ2x0b29scyBjb21taXQ6ICIsIGdldF9naXRfY29tbWl0KCkpKQogIHRoaXNfc2F2ZSA8LSBwYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXJtZF9maWxlKSwgIi12IiwgdmVyLCAiLnJkYS54eiIpCiAgbWVzc2FnZShwYXN0ZTAoIlNhdmluZyB0byAiLCB0aGlzX3NhdmUpKQogIHRtcCA8LSBzbShzYXZlbWUoZmlsZW5hbWU9dGhpc19zYXZlKSkKfQpgYGAK