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.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

##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    0.00    0.00    1.00    1.17    2.00   13.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.0     0.0     1.0     1.2     2.0    10.0
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   0.000   1.000   0.708   1.000   4.000

4 Gathering parameters

In this first block, I will set a couple of variables and source a file containing the parameters for the rest of the script.

## If you wish to reproduce this exact build of hpgltools, invoke the following:
## > git clone http://github.com/abelew/hpgltools.git
## > git reset 8ca465bb9928ffe95082f64aed9cf64799bbf8e6
## This is hpgltools commit: Wed Jul 31 16:40:59 2019 -0400: 8ca465bb9928ffe95082f64aed9cf64799bbf8e6
## Saving to 01_preprocessing_20190718-v20190718.rda.xz
LS0tCnRpdGxlOiAiTS50dWJlcmN1bG9zaXMgMjAxOTA3MTggcHJvdGVvbWljczogUHJlcHJvY2Vzc2luZy4iCmF1dGhvcjogImF0YiBhYmVsZXdAZ21haWwuY29tIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICB3aWR0aDogMzAwCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgdG9jX2Zsb2F0OiB0cnVlCiAgQmlvY1N0eWxlOjpodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBzaG93CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgZmlnX2hlaWdodDogNwogICAgZmlnX3dpZHRoOiA3CiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBrZWVwX21kOiBmYWxzZQogICAgbW9kZTogc2VsZmNvbnRhaW5lZAogICAgdG9jX2Zsb2F0OiB0cnVlCiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZmlnX2NhcHRpb246IHRydWUKICAgIGZpZ19oZWlnaHQ6IDcKICAgIGZpZ193aWR0aDogNwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAga2VlcF9tZDogZmFsc2UKICAgIG1vZGU6IHNlbGZjb250YWluZWQKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIHRoZW1lOiByZWFkYWJsZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgpib2R5LCB0ZCB7CiAgZm9udC1zaXplOiAxNnB4Owp9CmNvZGUucnsKICBmb250LXNpemU6IDE2cHg7Cn0KcHJlIHsKIGZvbnQtc2l6ZTogMTZweAp9Cjwvc3R5bGU+CgpgYGB7ciBvcHRpb25zLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KCJocGdsdG9vbHMiKQp0dCA8LSBkZXZ0b29sczo6bG9hZF9hbGwoIi9kYXRhL2hwZ2x0b29scyIpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHdpZHRoPTEyMCwKICAgICAgICAgICAgICAgICAgICAgcHJvZ3Jlc3M9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFLAogICAgICAgICAgICAgICAgICAgICBlY2hvPVRSVUUpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlcnJvcj1UUlVFLAogICAgICAgICAgICAgICAgICAgICAgZHBpPTk2KQpvbGRfb3B0aW9ucyA8LSBvcHRpb25zKGRpZ2l0cz00LAogICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAga25pdHIuZHVwbGljYXRlLmxhYmVsPSJhbGxvdyIpCmdncGxvdDI6OnRoZW1lX3NldChnZ3Bsb3QyOjp0aGVtZV9idyhiYXNlX3NpemU9MTApKQp2ZXIgPC0gIjIwMTkwNzE4IgpwcmV2aW91c19maWxlIDwtICJpbmRleC5SbWQiCgp0bXAgPC0gdHJ5KHNtKGxvYWRtZShmaWxlbmFtZT1wYXN0ZTAoZ3N1YihwYXR0ZXJuPSJcXC5SbWQiLCByZXBsYWNlPSIiLCB4PXByZXZpb3VzX2ZpbGUpLCAiLXYiLCB2ZXIsICIucmRhLnh6IikpKSkKcm1kX2ZpbGUgPC0gcGFzdGUwKCIwMV9wcmVwcm9jZXNzaW5nXyIsIHZlciwgIi5SbWQiKQpgYGAKCmBgYHtiYXNoIHBhcmFtZXRlcnMsIGV2YWw9RkFMU0V9CmV4cG9ydCBWRVJTSU9OPSIyMDE5MDcxOCIKc291cmNlICJwYXJhbWV0ZXJzLyR7VkVSU0lPTn1fc2V0dGluZ3Muc2giCmBgYAoKCkEgZnJlc2ggcnVubmluZyBvZiBhbGwgcHJvdGVvbWljcyB0YXNrcwo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCkkgdGhpbmsgSSBmaW5hbGx5IHdvcmtlZCBvdXQgYWxsKG1vc3Q/KSBvZiB0aGUga2lua3MgaW4gdGhlIHByb2Nlc3Npbmcgb2YgRElBIGRhdGEuClRodXMgSSB3YW50IHRvIGhhdmUgYSBmcmVzaCBydW4gb2YgYWxsIHRoZSB0YXNrcyByZXF1aXJlZCB0byBpbnRlcnByZXQgdGhlIHJlc3VsdHMuCgojIEFubm90YXRpb24gdmVyc2lvbjogYHIgdmVyYAoKIyMgR2Vub21lIGFubm90YXRpb24gaW5wdXQKCiMjIyBSZWFkIGEgZ2ZmIGZpbGUKCkluIGNvbnRyYXN0LCBpdCBpcyBwb3NzaWJsZSB0byBsb2FkIG1vc3QgYW5ub3RhdGlvbnMgb2YgaW50ZXJlc3QgZGlyZWN0bHkgZnJvbSB0aGUgZ2ZmIGZpbGVzIHVzZWQgaW4KdGhlIGFsaWdubWVudHMuICBNb3JlIGluLWRlcHRoIGluZm9ybWF0aW9uIGZvciB0aGUgaHVtYW4gdHJhbnNjcmlwdG9tZSBtYXkgYmUgZXh0cmFjdGVkIGZyb20gYmlvbWFydC4KCmBgYHtyIGdlbm9tZV9pbnB1dH0KIyMgVGhlIG9sZCB3YXkgb2YgZ2V0dGluZyBnZW5vbWUvYW5ub3RhdGlvbiBkYXRhCm10Yl9nZmYgPC0gInJlZmVyZW5jZS9teWNvYmFjdGVyaXVtX3R1YmVyY3Vsb3Npc19oMzdydl8yLmdmZi5neiIKbXRiX2dlbm9tZSA8LSAicmVmZXJlbmNlL210dWJlcmN1bG9zaXNfaDM3cnZfZ2VuYmFuay5mYXN0YSIKbXRiX2NkcyA8LSAicmVmZXJlbmNlL210Yl9jZHMuZmFzdGEiCgptdGJfYW5ub3RhdGlvbnMgPC0gc20obG9hZF9nZmZfYW5ub3RhdGlvbnMobXRiX2dmZiwgdHlwZT0iZ2VuZSIpKQpjb2xuYW1lcyhtdGJfYW5ub3RhdGlvbnMpIDwtIGdzdWIocGF0dGVybj0iXFwuIiwgcmVwbGFjZW1lbnQ9IiIsIHg9Y29sbmFtZXMobXRiX2Fubm90YXRpb25zKSkKbXRiX2Fubm90YXRpb25zW1siZGVzY3JpcHRpb24iXV0gPC0gZ3N1YihwYXR0ZXJuPSJcXCsiLCByZXBsYWNlbWVudD0iICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD1tdGJfYW5ub3RhdGlvbnNbWyJkZXNjcmlwdGlvbiJdXSkKbXRiX2Fubm90YXRpb25zW1siZnVuY3Rpb24iXV0gPC0gZ3N1YihwYXR0ZXJuPSJcXCsiLCByZXBsYWNlbWVudD0iICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeD1tdGJfYW5ub3RhdGlvbnNbWyJmdW5jdGlvbiJdXSkKcm93bmFtZXMobXRiX2Fubm90YXRpb25zKSA8LSBtdGJfYW5ub3RhdGlvbnNbWyJJRCJdXQpgYGAKCiMjIyBEb3dubG9hZCBmcm9tIG1pY3JvYmVzb25saW5lCgpBcHBhcmVudGx5IEkgcXVlcmllZCB0aGUgbWljcm9iZXNvbmxpbmUgdG9vIG9mdGVuIGFuZCBub3cgSSBnZXQgYW4gZXJyb3IKd2hlbmV2ZXIgSSB0cnkgdG8gdXNlIHRoZW0sIHRoaXMgZGlzYXBwb2ludHMgbWUuCgpgYGB7ciBnZW5iYW5rfQojIyBJIG1hZGUgYSBuaWZ0eSBmdW5jdGlvbiB0byBkbyB0aGlzIHN0dWZmOiBsb2FkX3VuaXByb3R3c19hbm5vdGF0aW9ucygpLgojIyBJdCBpcyBzbG93LCB0aG91Z2guCm10Yl9taWNyb2JlcyA8LSBsb2FkX21pY3JvYmVzb25saW5lX2Fubm90YXRpb25zKGlkPTgzMzMyKQptdGJfdW5pcHJvdF9hbm5vdCA8LSBzbShsb2FkX3VuaXByb3RfYW5ub3RhdGlvbnMoZmlsZT0icmVmZXJlbmNlL3VuaXByb3RfM0FVUDAwMDAwMTU4NC50eHQuZ3oiKSkKYGBgCgojIyBHZXR0aW5nIG9udG9sb2d5IGRhdGEKCmBgYHtyIG9udG9sb2d5fQptdGJfZ28gPC0gbG9hZF9taWNyb2Jlc29ubGluZV9nbyhpZD04MzMzMikKYGBgCgojIyBTb21lIHBhdHRlcm4gbWF0Y2hpbmcKClRoaXMgbGl0dGxlIGJsb2NrIGlzIGludGVuZGVkIHRvIHNlZWsgb3V0IHBlcHRpZGUgc2VxdWVuY2VzIHdpdGggdGhlIGhpZ2hseSBkZWdlbmVyYXRlIHBhdHRlcm46ClkoRXxEKSB3aXRoIGEgdmFyeWluZyBudW1iZXIgb2YgYW1pbm8gYWNpZHMgYmV0d2VlbiB0aGUgWSBhbmQgKEUgb3IgRCkuCgpgYGB7ciBwYXR0ZXJufQpnZXRfaGl0cyA8LSBmdW5jdGlvbihwYXR0ZXJucywgcGVwdGlkZV9maWxlLCBwY3RfbGltaXQ9MC4yNSkgewogIHBlcF9zZXEgPC0gQmlvc3RyaW5nczo6cmVhZEFBU3RyaW5nU2V0KHBlcHRpZGVfZmlsZSkKICBwZXBfbHN0IDwtIGFzLmRhdGEuZnJhbWUocGVwX3NlcSlbWyJ4Il1dCiAgcG9zX2RmIDwtIGRhdGEuZnJhbWUoc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkKICBwZXBfbmFtZXMgPC0gbmFtZXMocGVwX3NlcSkKICByb3duYW1lIDwtICIiCiAgZm9yIChyIGluIDE6bGVuZ3RoKHBlcF9uYW1lcykpIHsKICAgIHJvd25hbWUgPC0gcGVwX25hbWVzW3JdCiAgICBuZXdfcm93IDwtIHZlY3RvcigpCiAgICBmb3VuZF9oaXRzIDwtIEZBTFNFCiAgICBmb3IgKHAgaW4gMTpsZW5ndGgocGF0dGVybnMpKSB7CiAgICAgIHBhdCA8LSBwYXR0ZXJuc1tbcF1dCiAgICAgIHBuYW1lIDwtIG5hbWVzKHBhdHRlcm5zKVtwXQogICAgICBjb2x1bW4gPC0gZ3JlZ2V4cHIocGF0dGVybj1wYXQsIHRleHQ9cGVwX2xzdCkKICAgICAgbmFtZXMoY29sdW1uKSA8LSBuYW1lcyhwZXBfc2VxKQogICAgICBuYW1lIDwtIG5hbWVzKGNvbHVtbilbcl0KICAgICAgcm93IDwtIGNvbHVtbltbcl1dCiAgICAgIGxlbiA8LSBuY2hhcihwZXBfbHN0W3JdKQogICAgICBwY3QgPC0gYXMubnVtZXJpYyhyb3cpIC8gbGVuCiAgICAgIGNkaXN0IDwtIGxlbiAtIGFzLm51bWVyaWMocm93KQogICAgICBwb3NfbmFtZSA8LSBnbHVlOjpnbHVlKCJwb3Nfe3BuYW1lfSIpCiAgICAgIG51bV9uYW1lIDwtIGdsdWU6OmdsdWUoIm51bWJlcl97cG5hbWV9IikKICAgICAgbnRfbmFtZSA8LSBnbHVlOjpnbHVlKCJudF97cG5hbWV9IikKICAgICAgY3RfbmFtZSA8LSBnbHVlOjpnbHVlKCJjdF97cG5hbWV9IikKICAgICAgcGN0X25hbWUgPC0gZ2x1ZTo6Z2x1ZSgicGN0X3twbmFtZX0iKQogICAgICBwb3NfbmFtZSA8LSBnbHVlOjpnbHVlKCJwb3Nfe3BuYW1lfSIpCiAgICAgICMjIEFuIGltcG9ydGFudCBjYXZlYXQgaGVyZTogIFRoZXJlIG1heSBiZSBtb3JlIHRoYW4gb25lIHZhbHVlLgogICAgICBuZXdfcm93WyJyb3duYW1lIl0gPC0gcm93bmFtZQogICAgICBudW1iZXJfaGl0cyA8LSBsZW5ndGgoYXMubnVtZXJpYyhyb3cpKQogICAgICBpZiAoYXMubnVtZXJpYyhyb3cpWzFdID09IC0xKSB7CiAgICAgICAgbnVtYmVyX2hpdHMgPC0gIjAiCiAgICAgIH0KICAgICAgbmV3X3Jvd1tudW1fbmFtZV0gPC0gbnVtYmVyX2hpdHMKICAgICAgbmV3X3Jvd1twb3NfbmFtZV0gPC0gdG9TdHJpbmcoYXMubnVtZXJpYyhyb3cpKQogICAgICBpZiAobmV3X3Jvd1twb3NfbmFtZV0gPT0gIi0xIikgewogICAgICAgIG5ld19yb3dbcG9zX25hbWVdIDwtICIwIgogICAgICB9IGVsc2UgewogICAgICAgIGZvdW5kX2hpdHMgPC0gVFJVRQogICAgICB9CiAgICAgIG5ld19yb3dbImxlbmd0aCJdIDwtIGxlbgogICAgICBvcCA8LSBvcHRpb25zKHdhcm49MikKICAgICAgaWYgKHBjdFsxXSA8IDApIHsKICAgICAgICBuZXdfcm93W3BjdF9uYW1lXSA8LSAiMCIKICAgICAgfSBlbHNlIHsKICAgICAgICBuZXdfcm93W3BjdF9uYW1lXSA8LSB0b1N0cmluZyhwY3QpCiAgICAgIH0KICAgICAgb3B0aW9ucyhvcCkKICAgICAgbnRfc3RyIDwtICIiCiAgICAgIGN0X3N0ciA8LSAiIgogICAgICBtYXhfcGN0IDwtIDEgLSBwY3RfbGltaXQKICAgICAgZm9yIChpIGluIHBjdCkgewogICAgICAgIGlmIChpIDwgMCkgewogICAgICAgICAgbmV4dAogICAgICAgIH0KICAgICAgICBpZiAoaSA8IHBjdF9saW1pdCkgewogICAgICAgICAgbnRfc3RyIDwtIHBhc3RlMChudF9zdHIsICIsICIsIGkpCiAgICAgICAgfQogICAgICAgIGlmIChpID4gbWF4X3BjdCkgewogICAgICAgICAgY3Rfc3RyIDwtIHBhc3RlMChjdF9zdHIsICIsICIsIGkpCiAgICAgICAgfQogICAgICB9CiAgICAgIG50X3N0ciA8LSBnc3ViKHBhdHRlcm49Il5cXCwgIiwgcmVwbGFjZW1lbnQ9IiIsIHg9bnRfc3RyKQogICAgICBjdF9zdHIgPC0gZ3N1YihwYXR0ZXJuPSJeXFwsICIsIHJlcGxhY2VtZW50PSIiLCB4PWN0X3N0cikKICAgICAgbmV3X3Jvd1tudF9uYW1lXSA8LSBudF9zdHIKICAgICAgbmV3X3Jvd1tjdF9uYW1lXSA8LSBjdF9zdHIKICAgIH0KICAgIGlmIChpc1RSVUUoZm91bmRfaGl0cykpIHsKICAgICAgcG9zX2RmIDwtIHJiaW5kKHBvc19kZiwgbmV3X3Jvdywgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkKICAgICAgY29sbmFtZXMocG9zX2RmKSA8LSBuYW1lcyhuZXdfcm93KQogICAgfQogIH0gIyMgRW5kIGZvciBldmVyeSBnZW5lCiAgcm93bmFtZXMocG9zX2RmKSA8LSBwb3NfZGZbWyJyb3duYW1lIl1dCiAgcG9zX2RmIDwtIHBvc19kZlstMSwgXQoKICByZXR1cm4ocG9zX2RmKQp9CgojI3BhdHRlcm5zIDwtIGMoIlkoRXxEKSIsICJZLihFfEQpIiwgIlkuLihFfEQpIiwgIlkuLi4oRXxEKSIsICJZLi4uLihFfEQpIiwgIlkuLi4uLihFfEQpIikKbXRiX2NkcyA8LSAicmVmZXJlbmNlL210Yl9jZHMuZmFzdGEiCnBhdHRlcm5zIDwtIGMoIlkuLihFfEQpIiwgIlkuLi4oRXxEKSIpCm5hbWVzKHBhdHRlcm5zKSA8LSBjKCJ0d28iLCAidGhyZWUiKQp5ZWRfcGF0dGVybnMgPC0gZ2V0X2hpdHMocGF0dGVybnMsIG10Yl9jZHMpCndyaXR0ZW4gPC0gd3JpdGVfeGxzKHllZF9wYXR0ZXJucywgZXhjZWw9InBvc2l0aW9uc19ieV9wYXR0ZXJucy54bHN4IikKYGBgCgojIyBSYW5kb20gcXVlcnkgZnJvbSBWb2xrZXIKCldoYXQgcHJvdGVpbnMgZG8gbm90IGhhdmUgZ2x5Y2luZT8KCkdseWNpbmUgOiBHbHkgOiBHCgpgYGB7ciBnbHljaW5lfQpwZXBfc2VxIDwtIEJpb3N0cmluZ3M6OnJlYWRBQVN0cmluZ1NldChtdGJfY2RzKQpwZXBfbHN0IDwtIGFzLmRhdGEuZnJhbWUocGVwX3NlcSlbWyJ4Il1dCnBvc19kZiA8LSBkYXRhLmZyYW1lKHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCnBlcF9uYW1lcyA8LSBuYW1lcyhwZXBfc2VxKQpwZXBfZGYgPC0gYXMuZGF0YS5mcmFtZShwZXBfc2VxKQpnbHljaW5lX2hpdHMgPC0gZ3JlcGwocGF0dGVybj0iRyIsIHg9cGVwX2RmW1sieCJdXSkKcm93bmFtZXMocGVwX2RmKVshZ2x5Y2luZV9oaXRzXQpgYGAKCiMjIEFkZCB0aGUgWUVEIHBhdHRlcm5zIHRvIHRoZSBhbm5vdGF0aW9uIGRhdGEKCmBgYHtyIHllZF9hZGRlZH0KbXRiX2Fubm90YXRpb25zIDwtIG1lcmdlKG10Yl9hbm5vdGF0aW9ucywgeWVkX3BhdHRlcm5zLCBieT0icm93Lm5hbWVzIiwgYWxsLng9VFJVRSkKcm93bmFtZXMobXRiX2Fubm90YXRpb25zKSA8LSBtdGJfYW5ub3RhdGlvbnNbWyJSb3cubmFtZXMiXV0KbXRiX2Fubm90YXRpb25zIDwtIG10Yl9hbm5vdGF0aW9uc1stMSwgXQpgYGAKCiMjIENvbXBhcmUgc3Vic2V0IG9mIGludGVyZXN0aW5nIHByb3RlaW5zIHZzLiBhbGwKCk5hamliIGFuZCBWb2xrZXIgcmVxdWVzdGVkIGEgY29tcGFyaXNvbiBvZiB0aGUgZGlzdHJpYnV0aW9uIHBhdHRlcm4gaGl0cyBvZiBhbGwKcHJvdGVpbnMgdnMuIHRoZSBkaXN0cmlidXRpb24gaW4gYSBzcGVjaWZpYyBzdWJzZXQgb2YgcHJvdGVpbnMuICBJIGRvbid0CmFjdHVhbGx5IGtub3cgdGhlIHN1YnNldCBkZXNpcmVkLCBzbyBJIHdpbGwgYXNzdW1lIHRoZQoKYGBge3IgcGVfdGVzdGluZ30KcGVfaWRzIDwtIHJlYWQudGFibGUoInJlZmVyZW5jZS9hbm5vdGF0ZWRfcGVfZ2VuZXMudHh0IilbWyJWMSJdXQoKeWVkX3BlIDwtIHllZF9wYXR0ZXJuc1twZV9pZHMsIF0KCmFsbF9udW1iZXJzIDwtIGFzLm51bWVyaWMoeWVkX3BhdHRlcm5zW1sibnVtYmVyX3R3byJdXSkKcGVfbnVtYmVycyA8LSBhcy5udW1lcmljKHllZF9wZVtbIm51bWJlcl90d28iXV0pCgphbGx0aHJlZV9udW1iZXJzIDwtIGFzLm51bWVyaWMoeWVkX3BhdHRlcm5zW1sibnVtYmVyX3RocmVlIl1dKQpwZXRocmVlX251bWJlcnMgPC0gYXMubnVtZXJpYyh5ZWRfcGVbWyJudW1iZXJfdGhyZWUiXV0pCgphbGxfcGN0IDwtIHllZF9wYXR0ZXJuc1tbInBjdF90d28iXV0KcGVfcGN0IDwtIHllZF9wZVtbInBjdF90d28iXV0KYWxsX3Bvc2l0aW9ucyA8LSB5ZWRfcGF0dGVybnNbWyJwb3NfdHdvIl1dCnBlX3Bvc2l0aW9ucyA8LSB5ZWRfcGVbWyJwb3NfdHdvIl1dCgpzYW1wbGVkX251bWJlcnNfdHdvIDwtIHNhbXBsZSh4PWFsbF9udW1iZXJzLCBzaXplPTEwMDAsIHJlcGxhY2U9VFJVRSkKc3VtbWFyeShzYW1wbGVkX251bWJlcnNfdHdvKQpwZV9udW1iZXJzW2lzLm5hKHBlX251bWJlcnMpXSA8LSAwCnN1bW1hcnkocGVfbnVtYmVycykKCnNhbXBsZWRfbnVtYmVyc190aHJlZSA8LSBzYW1wbGUoeD1hbGx0aHJlZV9udW1iZXJzLCBzaXplPTEwMDAsIHJlcGxhY2U9VFJVRSkKc3VtbWFyeShzYW1wbGVkX251bWJlcnNfdGhyZWUpCnBldGhyZWVfbnVtYmVyc1tpcy5uYShwZXRocmVlX251bWJlcnMpXSA8LSAwCnN1bW1hcnkocGV0aHJlZV9udW1iZXJzKQpgYGAKCiMgUmVhZCB0aGUgc2FtcGxlIHNoZWV0IGFuZCBleGFtaW5lIHRoZSBuZXcgcmF3IGRhdGEKCmBgYHtyIHJlYWRfc2FtcGxlcywgZXZhbD1GQUxTRX0Kc2FtcGxlX3NoZWV0IDwtIGdsdWU6OmdsdWUoInNhbXBsZV9zaGVldHMvTXRiX2RpYV9zYW1wbGVzX3t2ZXJ9Lnhsc3giKQpzYXZlZmlsZSA8LSBnbHVlOjpnbHVlKCJtenhtbF9kaWFfZGF0YV97dmVyfS5yZGEiKQoKaWYgKGZpbGUuZXhpc3RzKHNhdmVmaWxlKSkgewogIGxvYWQoc2F2ZWZpbGUpCn0gZWxzZSB7CiAgbXp4bWxfZGF0YSA8LSBleHRyYWN0X21zcmF3X2RhdGEoc2FtcGxlX3NoZWV0LCBwYXJhbGxlbD1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbGxvd193aW5kb3dfb3ZlcmxhcD1GQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2NvbHVtbj0iZmlsZW5hbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhdmVmaWxlPXNhdmVmaWxlKQoKICBtem1sX2RhdGEgPC0gZXh0cmFjdF9tc3Jhd19kYXRhKHNhbXBsZV9zaGVldCwgcGFyYWxsZWw9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQ9Im16TUwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxsb3dfd2luZG93X292ZXJsYXA9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlX2NvbHVtbj0ibXptbGZpbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2F2ZWZpbGU9InRlc3RpbmcucmRhIikKfQoKaW50ZW5zaXR5X2JveHBsb3QgPC0gcGxvdF9tenhtbF9ib3hwbG90KG16eG1sX2RhdGEpCnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL2RpYV9tenhtbF9pbnRlbnNpdGllcy12e3Zlcn0ucG5nIiksIGltYWdlPWludGVuc2l0eV9ib3hwbG90KQoKcmV0ZW50aW9uX2JveHBsb3QgPC0gcGxvdF9tenhtbF9ib3hwbG90KG16eG1sX2RhdGEsIHRhYmxlPSJzY2FucyIsIGNvbHVtbj0icGVha3Njb3VudCIpCnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL2RpYV9tenhtbF9yZXRlbnRpb24tdnt2ZXJ9LnBuZyIpLCBpbWFnZT1yZXRlbnRpb25fYm94cGxvdCkKCm16X2JveHBsb3QgPC0gcGxvdF9tenhtbF9ib3hwbG90KG16eG1sX2RhdGEsIHRhYmxlPSJzY2FucyIsIGNvbHVtbj0iYmFzZXBlYWtteiIpCnBwKGZpbGU9Z2x1ZTo6Z2x1ZSgiaW1hZ2VzL2RpYV9tenhtbF9temJhc2Utdnt2ZXJ9LnBuZyIpLCBpbWFnZT1tel9ib3hwbG90KQoKc2NhbmludGVuc2l0eV9ib3hwbG90IDwtIHBsb3RfbXp4bWxfYm94cGxvdChtenhtbF9kYXRhLCB0YWJsZT0ic2NhbnMiLCBjb2x1bW49ImJhc2VwZWFraW50ZW5zaXR5IikKcHAoZmlsZT1nbHVlOjpnbHVlKCJpbWFnZXMvZGlhX216eG1sX3NjYW5pbnRlbnNpdHktdnt2ZXJ9LnBuZyIpLCBpbWFnZT1zY2FuaW50ZW5zaXR5X2JveHBsb3QpCgojI2ludGVuc2l0eV93cnRfbXogPC0gcGxvdF9pbnRlbnNpdHlfbXoobXp4bWxfZGF0YSwgeF9zY2FsZT0ibG9nIiwgeV9zY2FsZT0ibG9nIikKIyNwcChmaWxlPXBhc3RlMCgiaW1hZ2VzL2RpYV9pbnRlbnNpdHlfd3J0X216X2RpYS12e3Zlcn0ucG5nIiksIGltYWdlPWludGVuc2l0eV93cnRfbXopCmBgYAoKIyBHYXRoZXJpbmcgcGFyYW1ldGVycwoKSW4gdGhpcyBmaXJzdCBibG9jaywgSSB3aWxsIHNldCBhIGNvdXBsZSBvZiB2YXJpYWJsZXMgYW5kIHNvdXJjZSBhIGZpbGUKY29udGFpbmluZyB0aGUgcGFyYW1ldGVycyBmb3IgdGhlIHJlc3Qgb2YgdGhlIHNjcmlwdC4KCmBgYHtyIHNhdmVtZX0KaWYgKCFpc1RSVUUoZ2V0MCgic2tpcF9sb2FkIikpKSB7CiAgcGFuZGVyOjpwYW5kZXIoc2Vzc2lvbkluZm8oKSkKICBtZXNzYWdlKHBhc3RlMCgiVGhpcyBpcyBocGdsdG9vbHMgY29tbWl0OiAiLCBnZXRfZ2l0X2NvbW1pdCgpKSkKICB0aGlzX3NhdmUgPC0gcGFzdGUwKGdzdWIocGF0dGVybj0iXFwuUm1kIiwgcmVwbGFjZT0iIiwgeD1ybWRfZmlsZSksICItdiIsIHZlciwgIi5yZGEueHoiKQogIG1lc3NhZ2UocGFzdGUwKCJTYXZpbmcgdG8gIiwgdGhpc19zYXZlKSkKICB0bXAgPC0gc20oc2F2ZW1lKGZpbGVuYW1lPXRoaXNfc2F2ZSkpCn0KYGBgCg==