J. Taroni 2018

In 29-train_models_different_sample_size.sh, we trained models of different sample sizes (5x repeats with different random seeds) and in 28-train_different_biological_contexts.sh, we trained models using training sets comprised of different (predicted by MetaSRA) Here, we’re interested in evaluating these models. Specifically, we want to know:

  • How many latent variables were learned by each model? We expect this number to increase with sample size.
  • Of the pathway supplied to the model during training, what proportion of these are captured by the model? (We refer to this measure as “pathway coverage.”) We also expect this number to go up with sample size, at least initially, and for this metric to be somewhat stable across repeats, based on the results displayed/plotted in 17-plotting_repeat_evals (calculated in 15-evaluate_subsampling). The different biological contexts datasets are of varying sizes as well.
  • What pathways are captured? Here, again we’re concerned with pathways that were supplied to the model during training. We’ll want to do this evaluation in a separate notebook, but we expect a model trained on something like blood will be quite good at capturing immune cell signatures.
  • What oncogenic pathways are captured by the model? The oncogenic pathways from MSigDB were not supplied to the model during training, so this is a holdout set. I hypothesize that models trained on more samples and models that with “more relevant” training sets (e.g., cancer) will do a bit better at capturing these heldout pathways.

Set up

Custom functions + libraries

`%>%` <- dplyr::`%>%`
source(file.path("util", "plier_util.R"))
# intended for use only in this context -- functionalized because the two
# sets of models have the same structure (e.g., repeats are performed for 
# both the sample size evaluation _and_ the biological context evaluation)
EvalRepeats <- function(model.files, holdout.mat, outer.identifier, 
                        model.names) {
  # For a vector of model files that are deemed to be related in some way
  # (e.g., different sample sizes) AND that contain repeats (output of 
  # scripts/subsampling_PLIER.R with --num_repeats > 1), perform the 
  # evaluations contained in EvalWrapperWithHoldout AND tidy the results
  # for use downstream. Returns a list of data.frames.
  # 
  # Args:
  #  model.files: a vector of full paths to different, related model files
  #  holdout.mat: matrix of heldout pathways for use with EvalWrapperWithHoldout
  #               see the documentation of CalculateHoldoutAUC for more info
  #  outer.identifier: character; what are the different, related models 
  #                    evaluating? e.g., "sample_size" or "biological_context"
  #  model.names: what should the names of the list of results be? a character
  #               vector
  #              
  # Returns:
  #   a list of data.frames that contains the following elements: holdout.df,
  #   num.lvs.df, and coverage.df
  
  # calculate pathway coverage, number of latent variables, and the AUC
  # for the heldout pathways
  results.list <- 
    lapply(model.files, # for each set of models
           function(x) {
             plier.models <- readRDS(x)  # read in list of models
             # for each individual repeat
             lapply(plier.models, function(y) {
               EvalWrapperWithHoldout(plier.model = y$PLIER,
                                      holdout.matrix = holdout.mat)
             })
           })
  
  # we'll name the elements of the list based on the model.names argument
  names(results.list) <- model.names
  
  ## HELDOUT PATHWAYS ----------------------------------------------------------
  
  # extract the heldout results element -- the structure of the results list is
  # sample size -> repeat -> pathway.coverage, num.lvs, heldout.results
  # we want all the heldout.results from results.list
  holdout.results <- lapply(results.list, 
                            function(x) lapply(x, 
                                               function(y) y$heldout.results))
  
  # now we want the results in the form of a data.frame, where we include 
  # information about the sample size or biological context as well as the 
  # random seed used to generate that repeat's results
  holdout.df <- 
    dplyr::bind_rows(
      # for each condition, create a data.frame of all the holdout results and
      # include the random seed as an identifier
      lapply(holdout.results, 
             function(x) dplyr::bind_rows(x, .id = "seed")), 
      # use the outer.identifer arg as an id when we bind all the data.frames 
      # together
      .id = outer.identifier 
    )
  
  ## NUMBER OF LATENT VARIABLES ------------------------------------------------
  
  # first extract the num.lvs elements, then melt into a data.frame
  num.lvs.df <- 
    reshape2::melt(lapply(results.list,
                          function(x) lapply(x, 
                                             function(y) y$num.lvs)),
                   value.name = "number_of_latent_variables")
  colnames(num.lvs.df)[2:3] <- c("seed", outer.identifier)
  
  ### PATHWAY COVERAGE ---------------------------------------------------------
  
  # extract only the pathway.coverage elements
  pathway.coverage.list <- 
    lapply(results.list, 
           function(x) lapply(x, function(y) y$pathway.coverage))
  # melt into data.frame
  coverage.df <- reshape2::melt(pathway.coverage.list)
  # since we've melted from a list, rename the columns 
  colnames(coverage.df)[2:4] <- c("metric", "seed", outer.identifier)
  
  # we're only really interested in 2 out of 3 of the metrics calculated by
  # GetPathwayCoverage -- filter to only those and recode 
  coverage.df <- coverage.df %>%
    dplyr::filter(metric %in% c("pathway", "lv")) %>%
    dplyr::mutate(metric = 
                    dplyr::case_when(
                      (metric == "lv") ~ 
                        "LV associated with pathways",
                      (metric =="pathway") ~ "pathway coverage"
                    ))
 
  ## RETURN --------------------------------------------------------------------
  
  # return a list of wrangled data.frames
  return(list(
    holdout.df = holdout.df,
    num.lvs.df = num.lvs.df,
    coverage.df = coverage.df
  ))
   
}
# this is required to get the oncogenic pathways -- we're going to use this
# as our holdout set here
library(PLIER)
Loading required package: RColorBrewer
Loading required package: gplots

Attaching package: ‘gplots’

The following object is masked from ‘package:stats’:

    lowess

Loading required package: pheatmap
Loading required package: glmnet
Loading required package: Matrix
Loading required package: foreach
Loaded glmnet 2.0-13

Loading required package: knitr
Loading required package: rsvd
Loading required package: qvalue

Directory setup

# plot and result directory setup for this notebook
plot.dir <- file.path("plots", "30")
dir.create(plot.dir, recursive = TRUE, showWarnings = FALSE)
results.dir <- file.path("results", "30")
dir.create(results.dir, recursive = TRUE, showWarnings = FALSE)

Models to read in

All models we’ll evaluate are in models/

models.dir <- "models"
# we want all the models with 'subsampled' in the file name -- these are the
# sample size evaluations
size.model.files <- list.files(models.dir, pattern = "subsampled", 
                               full.names = TRUE)
size.model.files
[1] "models/subsampled_recount2_PLIER_model_1000.RDS"  "models/subsampled_recount2_PLIER_model_16000.RDS"
[3] "models/subsampled_recount2_PLIER_model_2000.RDS"  "models/subsampled_recount2_PLIER_model_32000.RDS"
[5] "models/subsampled_recount2_PLIER_model_4000.RDS"  "models/subsampled_recount2_PLIER_model_500.RDS"  
[7] "models/subsampled_recount2_PLIER_model_8000.RDS" 

Now for the different biological contexts

# biological context models have 'accessions' in the file names
context.model.files <- list.files(models.dir, pattern = "accessions",
                                  full.names = TRUE)
context.model.files
[1] "models/recount2_blood_accessions_PLIER_model.RDS"         "models/recount2_cancer_accessions_PLIER_model.RDS"       
[3] "models/recount2_cell_line_accessions_PLIER_model.RDS"     "models/recount2_other_tissues_accessions_PLIER_model.RDS"
[5] "models/recount2_tissue_accessions_PLIER_model.RDS"       

Evaluations

We’re going to use the oncogenic pathways that come with PLIER as our holdout set.

# load in holdout set
data("oncogenicPathways")

Sample size

# we'll name the elements of the list based on their sample size, which we 
# can extract from the filenames themselves
size.model.names <- sub(".RDS", "", sub(".*[_]", "", size.model.files))

Main evaluation with EvalRepeats

size.results <- EvalRepeats(model.files = size.model.files,
                            holdout.mat = oncogenicPathways,
                            outer.identifier = "sample_size",
                            model.names = size.model.names)

Heldout pathways

# write to file
size.holdout.file <- file.path(results.dir, 
                               "subsampled_oncogenic_pathways_AUC.tsv")
readr::write_tsv(size.results$holdout.df, path = size.holdout.file)

Number of latent variables

# write to file
size.num.lvs.file <- file.path(results.dir, "subsampled_number_of_lvs.tsv")
readr::write_tsv(size.results$num.lvs.df, path = size.num.lvs.file)

Pathway coverage

# write to file!
size.coverage.file <- file.path(results.dir, "subsampled_pathway_coverage.tsv")
readr::write_tsv(size.results$coverage.df, path = size.coverage.file)

Remove size.results for memory reasons – we’ve saved everything to file.

rm(size.results)

Biological contexts

# extract the biological contexts from the file names 
context.model.names <- stringr::str_match(context.model.files, 
                                          "recount2_(.*?)_accessions")[, 2]

Main evaluation with EvalRepeats

context.results <- EvalRepeats(model.files = context.model.files,
                               holdout.mat = oncogenicPathways,
                               outer.identifier = "biological_context",
                               model.names = context.model.names)

Heldout pathways

# write to file
context.holdout.file <- 
  file.path(results.dir, "biological_contexts_oncogenic_pathways_AUC.tsv")
readr::write_tsv(context.results$holdout.df, path = context.holdout.file)

Number of latent variables

# write to file
context.num.lvs.file <- 
  file.path(results.dir, "biological_context_number_of_lvs.tsv")
readr::write_tsv(context.results$num.lvs.df, path = context.num.lvs.file)

Pathway coverage

# write to file!
context.coverage.file <- 
  file.path(results.dir, "biological_context_pathway_coverage.tsv")
readr::write_tsv(context.results$coverage.df, path = context.coverage.file)
LS0tCnRpdGxlOiAiRXZhbHVhdGluZyBzdWJzYW1wbGluZzogc2FtcGxlIHNpemUgJ3N3ZWVwJyBhbmQgYmlvbG9naWNhbCBjb250ZXh0cyIKb3V0cHV0OiAgIAogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgoqKkouIFRhcm9uaSAyMDE4KioKCkluIGAyOS10cmFpbl9tb2RlbHNfZGlmZmVyZW50X3NhbXBsZV9zaXplLnNoYCwgd2UgdHJhaW5lZCBtb2RlbHMgb2YgZGlmZmVyZW50IApzYW1wbGUgc2l6ZXMgKDV4IHJlcGVhdHMgd2l0aCBkaWZmZXJlbnQgcmFuZG9tIHNlZWRzKSBhbmQgaW4gCmAyOC10cmFpbl9kaWZmZXJlbnRfYmlvbG9naWNhbF9jb250ZXh0cy5zaGAsIHdlIHRyYWluZWQgbW9kZWxzIHVzaW5nIHRyYWluaW5nCnNldHMgY29tcHJpc2VkIG9mIGRpZmZlcmVudCAocHJlZGljdGVkIGJ5IE1ldGFTUkEpIApIZXJlLCB3ZSdyZSBpbnRlcmVzdGVkIGluIGV2YWx1YXRpbmcgdGhlc2UgbW9kZWxzLgpTcGVjaWZpY2FsbHksIHdlIHdhbnQgdG8ga25vdzoKCiogKipIb3cgbWFueSBsYXRlbnQgdmFyaWFibGVzIHdlcmUgbGVhcm5lZCBieSBlYWNoIG1vZGVsPyoqIAogIFdlIGV4cGVjdCB0aGlzIG51bWJlciB0byBpbmNyZWFzZSB3aXRoIHNhbXBsZSBzaXplLgoqICoqT2YgdGhlIHBhdGh3YXkgc3VwcGxpZWQgdG8gdGhlIG1vZGVsIGR1cmluZyB0cmFpbmluZywgd2hhdCBwcm9wb3J0aW9uIG9mIAogIHRoZXNlIGFyZSBjYXB0dXJlZCBieSB0aGUgbW9kZWw/KioKICAoV2UgcmVmZXIgdG8gdGhpcyBtZWFzdXJlIGFzICJwYXRod2F5IGNvdmVyYWdlLiIpCiAgV2UgYWxzbyBleHBlY3QgdGhpcyBudW1iZXIgdG8gZ28gdXAgd2l0aCBzYW1wbGUgc2l6ZSwgYXQgbGVhc3QgaW5pdGlhbGx5LCBhbmQKICBmb3IgdGhpcyBtZXRyaWMgdG8gYmUgc29tZXdoYXQgc3RhYmxlIGFjcm9zcyByZXBlYXRzLCBiYXNlZCBvbiB0aGUgcmVzdWx0cwogIGRpc3BsYXllZC9wbG90dGVkIGluIGAxNy1wbG90dGluZ19yZXBlYXRfZXZhbHNgIChjYWxjdWxhdGVkIGluIAogIGAxNS1ldmFsdWF0ZV9zdWJzYW1wbGluZ2ApLgogIFRoZSBkaWZmZXJlbnQgYmlvbG9naWNhbCBjb250ZXh0cyBkYXRhc2V0cyBhcmUgb2YgdmFyeWluZyBzaXplcyBhcyB3ZWxsLgoqICoqV2hhdCBwYXRod2F5cyBhcmUgY2FwdHVyZWQ/KioKICBIZXJlLCBhZ2FpbiB3ZSdyZSBjb25jZXJuZWQgd2l0aCBwYXRod2F5cyB0aGF0IHdlcmUgc3VwcGxpZWQgdG8gdGhlIG1vZGVsIAogIGR1cmluZyB0cmFpbmluZy4KICBXZSdsbCB3YW50IHRvIGRvIHRoaXMgZXZhbHVhdGlvbiBpbiBhIHNlcGFyYXRlIG5vdGVib29rLCBidXQgd2UgZXhwZWN0IGEgbW9kZWwKICB0cmFpbmVkIG9uIHNvbWV0aGluZyBsaWtlIGJsb29kIHdpbGwgYmUgcXVpdGUgZ29vZCBhdCBjYXB0dXJpbmcgaW1tdW5lIGNlbGwKICBzaWduYXR1cmVzLgoqICoqV2hhdCBvbmNvZ2VuaWMgcGF0aHdheXMgYXJlIGNhcHR1cmVkIGJ5IHRoZSBtb2RlbD8qKgogIFRoZSBbb25jb2dlbmljIHBhdGh3YXlzIGZyb20gTVNpZ0RCXShzb2Z0d2FyZS5icm9hZGluc3RpdHV0ZS5vcmcvZ3NlYS9tc2lnZGIvZ2VuZXNldHMuanNwP2NvbGxlY3Rpb249QzYpIAogIHdlcmUgX25vdF8gc3VwcGxpZWQgdG8gdGhlIG1vZGVsIGR1cmluZyB0cmFpbmluZywgc28gdGhpcyBpcyBhIGhvbGRvdXQgc2V0LgogIEkgaHlwb3RoZXNpemUgdGhhdCBtb2RlbHMgdHJhaW5lZCBvbiBtb3JlIHNhbXBsZXMgYW5kIG1vZGVscyB0aGF0IHdpdGggCiAgIm1vcmUgcmVsZXZhbnQiIHRyYWluaW5nIHNldHMgKGUuZy4sIGNhbmNlcikgd2lsbCBkbyBhIGJpdCBiZXR0ZXIgYXQKICBjYXB0dXJpbmcgdGhlc2UgaGVsZG91dCBwYXRod2F5cy4KCiMjIFNldCB1cAoKIyMjIyBDdXN0b20gZnVuY3Rpb25zICsgbGlicmFyaWVzCgpgYGB7cn0KYCU+JWAgPC0gZHBseXI6OmAlPiVgCnNvdXJjZShmaWxlLnBhdGgoInV0aWwiLCAicGxpZXJfdXRpbC5SIikpCmBgYAoKYGBge3J9CiMgaW50ZW5kZWQgZm9yIHVzZSBvbmx5IGluIHRoaXMgY29udGV4dCAtLSBmdW5jdGlvbmFsaXplZCBiZWNhdXNlIHRoZSB0d28KIyBzZXRzIG9mIG1vZGVscyBoYXZlIHRoZSBzYW1lIHN0cnVjdHVyZSAoZS5nLiwgcmVwZWF0cyBhcmUgcGVyZm9ybWVkIGZvciAKIyBib3RoIHRoZSBzYW1wbGUgc2l6ZSBldmFsdWF0aW9uIF9hbmRfIHRoZSBiaW9sb2dpY2FsIGNvbnRleHQgZXZhbHVhdGlvbikKRXZhbFJlcGVhdHMgPC0gZnVuY3Rpb24obW9kZWwuZmlsZXMsIGhvbGRvdXQubWF0LCBvdXRlci5pZGVudGlmaWVyLCAKICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWwubmFtZXMpIHsKICAjIEZvciBhIHZlY3RvciBvZiBtb2RlbCBmaWxlcyB0aGF0IGFyZSBkZWVtZWQgdG8gYmUgcmVsYXRlZCBpbiBzb21lIHdheQogICMgKGUuZy4sIGRpZmZlcmVudCBzYW1wbGUgc2l6ZXMpIEFORCB0aGF0IGNvbnRhaW4gcmVwZWF0cyAob3V0cHV0IG9mIAogICMgc2NyaXB0cy9zdWJzYW1wbGluZ19QTElFUi5SIHdpdGggLS1udW1fcmVwZWF0cyA+IDEpLCBwZXJmb3JtIHRoZSAKICAjIGV2YWx1YXRpb25zIGNvbnRhaW5lZCBpbiBFdmFsV3JhcHBlcldpdGhIb2xkb3V0IEFORCB0aWR5IHRoZSByZXN1bHRzCiAgIyBmb3IgdXNlIGRvd25zdHJlYW0uIFJldHVybnMgYSBsaXN0IG9mIGRhdGEuZnJhbWVzLgogICMgCiAgIyBBcmdzOgogICMgIG1vZGVsLmZpbGVzOiBhIHZlY3RvciBvZiBmdWxsIHBhdGhzIHRvIGRpZmZlcmVudCwgcmVsYXRlZCBtb2RlbCBmaWxlcwogICMgIGhvbGRvdXQubWF0OiBtYXRyaXggb2YgaGVsZG91dCBwYXRod2F5cyBmb3IgdXNlIHdpdGggRXZhbFdyYXBwZXJXaXRoSG9sZG91dAogICMgICAgICAgICAgICAgICBzZWUgdGhlIGRvY3VtZW50YXRpb24gb2YgQ2FsY3VsYXRlSG9sZG91dEFVQyBmb3IgbW9yZSBpbmZvCiAgIyAgb3V0ZXIuaWRlbnRpZmllcjogY2hhcmFjdGVyOyB3aGF0IGFyZSB0aGUgZGlmZmVyZW50LCByZWxhdGVkIG1vZGVscyAKICAjICAgICAgICAgICAgICAgICAgICBldmF1bGF0aW5nPyBlLmcuLCAic2FtcGxlX3NpemUiIG9yICJiaW9sb2dpY2FsX2NvbnRleHQiCiAgIyAgbW9kZWwubmFtZXM6IHdoYXQgc2hvdWxkIHRoZSBuYW1lcyBvZiB0aGUgbGlzdCBvZiByZXN1bHRzIGJlPyBhIGNoYXJhY3RlcgogICMgICAgICAgICAgICAgICB2ZWN0b3IKICAjICAgICAgICAgICAgICAKICAjIFJldHVybnM6CiAgIyAgIGEgbGlzdCBvZiBkYXRhLmZyYW1lcyB0aGF0IGNvbnRhaW5zIHRoZSBmb2xsb3dpbmcgZWxlbWVudHM6IGhvbGRvdXQuZGYsCiAgIyAgIG51bS5sdnMuZGYsIGFuZCBjb3ZlcmFnZS5kZgogIAogICMgY2FsY3VsYXRlIHBhdGh3YXkgY292ZXJhZ2UsIG51bWJlciBvZiBsYXRlbnQgdmFyaWFibGVzLCBhbmQgdGhlIEFVQwogICMgZm9yIHRoZSBoZWxkb3V0IHBhdGh3YXlzCiAgcmVzdWx0cy5saXN0IDwtIAogICAgbGFwcGx5KG1vZGVsLmZpbGVzLCAjIGZvciBlYWNoIHNldCBvZiBtb2RlbHMKICAgICAgICAgICBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgICBwbGllci5tb2RlbHMgPC0gcmVhZFJEUyh4KSAgIyByZWFkIGluIGxpc3Qgb2YgbW9kZWxzCiAgICAgICAgICAgICAjIGZvciBlYWNoIGluZGl2aWR1YWwgcmVwZWF0CiAgICAgICAgICAgICBsYXBwbHkocGxpZXIubW9kZWxzLCBmdW5jdGlvbih5KSB7CiAgICAgICAgICAgICAgIEV2YWxXcmFwcGVyV2l0aEhvbGRvdXQocGxpZXIubW9kZWwgPSB5JFBMSUVSLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvbGRvdXQubWF0cml4ID0gaG9sZG91dC5tYXQpCiAgICAgICAgICAgICB9KQogICAgICAgICAgIH0pCiAgCiAgIyB3ZSdsbCBuYW1lIHRoZSBlbGVtZW50cyBvZiB0aGUgbGlzdCBiYXNlZCBvbiB0aGUgbW9kZWwubmFtZXMgYXJndW1lbnQKICBuYW1lcyhyZXN1bHRzLmxpc3QpIDwtIG1vZGVsLm5hbWVzCiAgCiAgIyMgSEVMRE9VVCBQQVRIV0FZUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgCiAgIyBleHRyYWN0IHRoZSBoZWxkb3V0IHJlc3VsdHMgZWxlbWVudCAtLSB0aGUgc3RydWN0dXJlIG9mIHRoZSByZXN1bHRzIGxpc3QgaXMKICAjIHNhbXBsZSBzaXplIC0+IHJlcGVhdCAtPiBwYXRod2F5LmNvdmVyYWdlLCBudW0ubHZzLCBoZWxkb3V0LnJlc3VsdHMKICAjIHdlIHdhbnQgYWxsIHRoZSBoZWxkb3V0LnJlc3VsdHMgZnJvbSByZXN1bHRzLmxpc3QKICBob2xkb3V0LnJlc3VsdHMgPC0gbGFwcGx5KHJlc3VsdHMubGlzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbih4KSBsYXBwbHkoeCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeSkgeSRoZWxkb3V0LnJlc3VsdHMpKQogIAogICMgbm93IHdlIHdhbnQgdGhlIHJlc3VsdHMgaW4gdGhlIGZvcm0gb2YgYSBkYXRhLmZyYW1lLCB3aGVyZSB3ZSBpbmNsdWRlIAogICMgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHNhbXBsZSBzaXplIG9yIGJpb2xvZ2ljYWwgY29udGV4dCBhcyB3ZWxsIGFzIHRoZSAKICAjIHJhbmRvbSBzZWVkIHVzZWQgdG8gZ2VuZXJhdGUgdGhhdCByZXBlYXQncyByZXN1bHRzCiAgaG9sZG91dC5kZiA8LSAKICAgIGRwbHlyOjpiaW5kX3Jvd3MoCiAgICAgICMgZm9yIGVhY2ggY29uZGl0aW9uLCBjcmVhdGUgYSBkYXRhLmZyYW1lIG9mIGFsbCB0aGUgaG9sZG91dCByZXN1bHRzIGFuZAogICAgICAjIGluY2x1ZGUgdGhlIHJhbmRvbSBzZWVkIGFzIGFuIGlkZW50aWZpZXIKICAgICAgbGFwcGx5KGhvbGRvdXQucmVzdWx0cywgCiAgICAgICAgICAgICBmdW5jdGlvbih4KSBkcGx5cjo6YmluZF9yb3dzKHgsIC5pZCA9ICJzZWVkIikpLCAKICAgICAgIyB1c2UgdGhlIG91dGVyLmlkZW50aWZlciBhcmcgYXMgYW4gaWQgd2hlbiB3ZSBiaW5kIGFsbCB0aGUgZGF0YS5mcmFtZXMgCiAgICAgICMgdG9nZXRoZXIKICAgICAgLmlkID0gb3V0ZXIuaWRlbnRpZmllciAKICAgICkKICAKICAjIyBOVU1CRVIgT0YgTEFURU5UIFZBUklBQkxFUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIGZpcnN0IGV4dHJhY3QgdGhlIG51bS5sdnMgZWxlbWVudHMsIHRoZW4gbWVsdCBpbnRvIGEgZGF0YS5mcmFtZQogIG51bS5sdnMuZGYgPC0gCiAgICByZXNoYXBlMjo6bWVsdChsYXBwbHkocmVzdWx0cy5saXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIGxhcHBseSh4LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeSkgeSRudW0ubHZzKSksCiAgICAgICAgICAgICAgICAgICB2YWx1ZS5uYW1lID0gIm51bWJlcl9vZl9sYXRlbnRfdmFyaWFibGVzIikKICBjb2xuYW1lcyhudW0ubHZzLmRmKVsyOjNdIDwtIGMoInNlZWQiLCBvdXRlci5pZGVudGlmaWVyKQogIAogICMjIyBQQVRIV0FZIENPVkVSQUdFIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogIAogICMgZXh0cmFjdCBvbmx5IHRoZSBwYXRod2F5LmNvdmVyYWdlIGVsZW1lbnRzCiAgcGF0aHdheS5jb3ZlcmFnZS5saXN0IDwtIAogICAgbGFwcGx5KHJlc3VsdHMubGlzdCwgCiAgICAgICAgICAgZnVuY3Rpb24oeCkgbGFwcGx5KHgsIGZ1bmN0aW9uKHkpIHkkcGF0aHdheS5jb3ZlcmFnZSkpCiAgIyBtZWx0IGludG8gZGF0YS5mcmFtZQogIGNvdmVyYWdlLmRmIDwtIHJlc2hhcGUyOjptZWx0KHBhdGh3YXkuY292ZXJhZ2UubGlzdCkKICAjIHNpbmNlIHdlJ3ZlIG1lbHRlZCBmcm9tIGEgbGlzdCwgcmVuYW1lIHRoZSBjb2x1bW5zIAogIGNvbG5hbWVzKGNvdmVyYWdlLmRmKVsyOjRdIDwtIGMoIm1ldHJpYyIsICJzZWVkIiwgb3V0ZXIuaWRlbnRpZmllcikKICAKICAjIHdlJ3JlIG9ubHkgcmVhbGx5IGludGVyZXN0ZWQgaW4gMiBvdXQgb2YgMyBvZiB0aGUgbWV0cmljcyBjYWxjdWxhdGVkIGJ5CiAgIyBHZXRQYXRod2F5Q292ZXJhZ2UgLS0gZmlsdGVyIHRvIG9ubHkgdGhvc2UgYW5kIHJlY29kZSAKICBjb3ZlcmFnZS5kZiA8LSBjb3ZlcmFnZS5kZiAlPiUKICAgIGRwbHlyOjpmaWx0ZXIobWV0cmljICVpbiUgYygicGF0aHdheSIsICJsdiIpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUobWV0cmljID0gCiAgICAgICAgICAgICAgICAgICAgZHBseXI6OmNhc2Vfd2hlbigKICAgICAgICAgICAgICAgICAgICAgIChtZXRyaWMgPT0gImx2IikgfiAKICAgICAgICAgICAgICAgICAgICAgICAgIkxWIGFzc29jaWF0ZWQgd2l0aCBwYXRod2F5cyIsCiAgICAgICAgICAgICAgICAgICAgICAobWV0cmljID09InBhdGh3YXkiKSB+ICJwYXRod2F5IGNvdmVyYWdlIgogICAgICAgICAgICAgICAgICAgICkpCiAKICAjIyBSRVRVUk4gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KICAKICAjIHJldHVybiBhIGxpc3Qgb2Ygd3JhbmdsZWQgZGF0YS5mcmFtZXMKICByZXR1cm4obGlzdCgKICAgIGhvbGRvdXQuZGYgPSBob2xkb3V0LmRmLAogICAgbnVtLmx2cy5kZiA9IG51bS5sdnMuZGYsCiAgICBjb3ZlcmFnZS5kZiA9IGNvdmVyYWdlLmRmCiAgKSkKICAgCn0KYGBgCgpgYGB7cn0KIyB0aGlzIGlzIHJlcXVpcmVkIHRvIGdldCB0aGUgb25jb2dlbmljIHBhdGh3YXlzIC0tIHdlJ3JlIGdvaW5nIHRvIHVzZSB0aGlzCiMgYXMgb3VyIGhvbGRvdXQgc2V0IGhlcmUKbGlicmFyeShQTElFUikKYGBgCgojIyMjIERpcmVjdG9yeSBzZXR1cAoKYGBge3J9CiMgcGxvdCBhbmQgcmVzdWx0IGRpcmVjdG9yeSBzZXR1cCBmb3IgdGhpcyBub3RlYm9vawpwbG90LmRpciA8LSBmaWxlLnBhdGgoInBsb3RzIiwgIjMwIikKZGlyLmNyZWF0ZShwbG90LmRpciwgcmVjdXJzaXZlID0gVFJVRSwgc2hvd1dhcm5pbmdzID0gRkFMU0UpCnJlc3VsdHMuZGlyIDwtIGZpbGUucGF0aCgicmVzdWx0cyIsICIzMCIpCmRpci5jcmVhdGUocmVzdWx0cy5kaXIsIHJlY3Vyc2l2ZSA9IFRSVUUsIHNob3dXYXJuaW5ncyA9IEZBTFNFKQpgYGAKCiMjIyMgTW9kZWxzIHRvIHJlYWQgaW4KCkFsbCBtb2RlbHMgd2UnbGwgZXZhbHVhdGUgYXJlIGluIGBtb2RlbHMvYAoKYGBge3J9Cm1vZGVscy5kaXIgPC0gIm1vZGVscyIKIyB3ZSB3YW50IGFsbCB0aGUgbW9kZWxzIHdpdGggJ3N1YnNhbXBsZWQnIGluIHRoZSBmaWxlIG5hbWUgLS0gdGhlc2UgYXJlIHRoZQojIHNhbXBsZSBzaXplIGV2YWx1YXRpb25zCnNpemUubW9kZWwuZmlsZXMgPC0gbGlzdC5maWxlcyhtb2RlbHMuZGlyLCBwYXR0ZXJuID0gInN1YnNhbXBsZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXMgPSBUUlVFKQpzaXplLm1vZGVsLmZpbGVzCmBgYAoKTm93IGZvciB0aGUgZGlmZmVyZW50IGJpb2xvZ2ljYWwgY29udGV4dHMKCmBgYHtyfQojIGJpb2xvZ2ljYWwgY29udGV4dCBtb2RlbHMgaGF2ZSAnYWNjZXNzaW9ucycgaW4gdGhlIGZpbGUgbmFtZXMKY29udGV4dC5tb2RlbC5maWxlcyA8LSBsaXN0LmZpbGVzKG1vZGVscy5kaXIsIHBhdHRlcm4gPSAiYWNjZXNzaW9ucyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkKY29udGV4dC5tb2RlbC5maWxlcwpgYGAKCgojIyBFdmFsdWF0aW9ucwoKV2UncmUgZ29pbmcgdG8gdXNlIHRoZSBvbmNvZ2VuaWMgcGF0aHdheXMgdGhhdCBjb21lIHdpdGggUExJRVIgYXMgb3VyIGhvbGRvdXQKc2V0LgoKYGBge3J9CiMgbG9hZCBpbiBob2xkb3V0IHNldApkYXRhKCJvbmNvZ2VuaWNQYXRod2F5cyIpCmBgYAoKIyMjIFNhbXBsZSBzaXplCgpgYGB7cn0KIyB3ZSdsbCBuYW1lIHRoZSBlbGVtZW50cyBvZiB0aGUgbGlzdCBiYXNlZCBvbiB0aGVpciBzYW1wbGUgc2l6ZSwgd2hpY2ggd2UgCiMgY2FuIGV4dHJhY3QgZnJvbSB0aGUgZmlsZW5hbWVzIHRoZW1zZWx2ZXMKc2l6ZS5tb2RlbC5uYW1lcyA8LSBzdWIoIi5SRFMiLCAiIiwgc3ViKCIuKltfXSIsICIiLCBzaXplLm1vZGVsLmZpbGVzKSkKYGBgCgpNYWluIGV2YWx1YXRpb24gd2l0aCBgRXZhbFJlcGVhdHNgCgpgYGB7cn0Kc2l6ZS5yZXN1bHRzIDwtIEV2YWxSZXBlYXRzKG1vZGVsLmZpbGVzID0gc2l6ZS5tb2RlbC5maWxlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvbGRvdXQubWF0ID0gb25jb2dlbmljUGF0aHdheXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRlci5pZGVudGlmaWVyID0gInNhbXBsZV9zaXplIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsLm5hbWVzID0gc2l6ZS5tb2RlbC5uYW1lcykKYGBgCgojIyMjIEhlbGRvdXQgcGF0aHdheXMKCmBgYHtyfQojIHdyaXRlIHRvIGZpbGUKc2l6ZS5ob2xkb3V0LmZpbGUgPC0gZmlsZS5wYXRoKHJlc3VsdHMuZGlyLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzdWJzYW1wbGVkX29uY29nZW5pY19wYXRod2F5c19BVUMudHN2IikKcmVhZHI6OndyaXRlX3RzdihzaXplLnJlc3VsdHMkaG9sZG91dC5kZiwgcGF0aCA9IHNpemUuaG9sZG91dC5maWxlKQpgYGAKCiMjIyMgTnVtYmVyIG9mIGxhdGVudCB2YXJpYWJsZXMKCmBgYHtyfQojIHdyaXRlIHRvIGZpbGUKc2l6ZS5udW0ubHZzLmZpbGUgPC0gZmlsZS5wYXRoKHJlc3VsdHMuZGlyLCAic3Vic2FtcGxlZF9udW1iZXJfb2ZfbHZzLnRzdiIpCnJlYWRyOjp3cml0ZV90c3Yoc2l6ZS5yZXN1bHRzJG51bS5sdnMuZGYsIHBhdGggPSBzaXplLm51bS5sdnMuZmlsZSkKYGBgCgojIyMjIFBhdGh3YXkgY292ZXJhZ2UKCmBgYHtyfQojIHdyaXRlIHRvIGZpbGUhCnNpemUuY292ZXJhZ2UuZmlsZSA8LSBmaWxlLnBhdGgocmVzdWx0cy5kaXIsICJzdWJzYW1wbGVkX3BhdGh3YXlfY292ZXJhZ2UudHN2IikKcmVhZHI6OndyaXRlX3RzdihzaXplLnJlc3VsdHMkY292ZXJhZ2UuZGYsIHBhdGggPSBzaXplLmNvdmVyYWdlLmZpbGUpCmBgYAoKUmVtb3ZlIGBzaXplLnJlc3VsdHNgIGZvciBtZW1vcnkgcmVhc29ucyAtLSB3ZSd2ZSBzYXZlZCBldmVyeXRoaW5nIHRvIGZpbGUuCgpgYGB7cn0Kcm0oc2l6ZS5yZXN1bHRzKQpgYGAKCiMjIyBCaW9sb2dpY2FsIGNvbnRleHRzCgpgYGB7cn0KIyBleHRyYWN0IHRoZSBiaW9sb2dpY2FsIGNvbnRleHRzIGZyb20gdGhlIGZpbGUgbmFtZXMgCmNvbnRleHQubW9kZWwubmFtZXMgPC0gc3RyaW5ncjo6c3RyX21hdGNoKGNvbnRleHQubW9kZWwuZmlsZXMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmVjb3VudDJfKC4qPylfYWNjZXNzaW9ucyIpWywgMl0KYGBgCgpNYWluIGV2YWx1YXRpb24gd2l0aCBgRXZhbFJlcGVhdHNgCgpgYGB7cn0KY29udGV4dC5yZXN1bHRzIDwtIEV2YWxSZXBlYXRzKG1vZGVsLmZpbGVzID0gY29udGV4dC5tb2RlbC5maWxlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvbGRvdXQubWF0ID0gb25jb2dlbmljUGF0aHdheXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRlci5pZGVudGlmaWVyID0gImJpb2xvZ2ljYWxfY29udGV4dCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5uYW1lcyA9IGNvbnRleHQubW9kZWwubmFtZXMpCmBgYAoKIyMjIyBIZWxkb3V0IHBhdGh3YXlzCgpgYGB7cn0KIyB3cml0ZSB0byBmaWxlCmNvbnRleHQuaG9sZG91dC5maWxlIDwtIAogIGZpbGUucGF0aChyZXN1bHRzLmRpciwgImJpb2xvZ2ljYWxfY29udGV4dHNfb25jb2dlbmljX3BhdGh3YXlzX0FVQy50c3YiKQpyZWFkcjo6d3JpdGVfdHN2KGNvbnRleHQucmVzdWx0cyRob2xkb3V0LmRmLCBwYXRoID0gY29udGV4dC5ob2xkb3V0LmZpbGUpCmBgYAoKIyMjIyBOdW1iZXIgb2YgbGF0ZW50IHZhcmlhYmxlcwoKYGBge3J9CiMgd3JpdGUgdG8gZmlsZQpjb250ZXh0Lm51bS5sdnMuZmlsZSA8LSAKICBmaWxlLnBhdGgocmVzdWx0cy5kaXIsICJiaW9sb2dpY2FsX2NvbnRleHRfbnVtYmVyX29mX2x2cy50c3YiKQpyZWFkcjo6d3JpdGVfdHN2KGNvbnRleHQucmVzdWx0cyRudW0ubHZzLmRmLCBwYXRoID0gY29udGV4dC5udW0ubHZzLmZpbGUpCmBgYAoKIyMjIyBQYXRod2F5IGNvdmVyYWdlCgpgYGB7cn0KIyB3cml0ZSB0byBmaWxlIQpjb250ZXh0LmNvdmVyYWdlLmZpbGUgPC0gCiAgZmlsZS5wYXRoKHJlc3VsdHMuZGlyLCAiYmlvbG9naWNhbF9jb250ZXh0X3BhdGh3YXlfY292ZXJhZ2UudHN2IikKcmVhZHI6OndyaXRlX3Rzdihjb250ZXh0LnJlc3VsdHMkY292ZXJhZ2UuZGYsIHBhdGggPSBjb250ZXh0LmNvdmVyYWdlLmZpbGUpCmBgYAo=