The PCA plot for the larger zebrafish test compendium (05-pca_test_compendium) showed a separation between what may be 2 groups of RNA-seq samples in PC1.

Here, we’ll dig into what may underlie the difference between the two clusters. We suspect it may have to do with sample prep; specifically, it may be the selection strategy (poly-A enrichment vs. rRNA depletion). First, we need to identify a random selection of samples that we will then read the experimental methods for.

Set up

`%>%` <- dplyr::`%>%`
library(ggplot2)

Custom Functions

refinebio_sample_code_to_list <- function(accession_code) {
  # given a sample accession code, get the refine.bio sample information at
  # at the samples endpoint into list format with jsonlite::fromJSON
  #
  # Args:
  #   accession_code: sample accession code
  # 
  # Returns:
  #   sample endpoint info as a list (from jsonlite::fromJSON)
  api_url <- paste0("https://api.refine.bio/samples/?accession_code=", 
                    accession_code)
  sample_info <- jsonlite::fromJSON(api_url)
}
get_sample_project_accession <- function(accession_code) {
  # takes the output of refinebio_sample_code_to_list and returns a project
  # (e.g., SRPXXXXXX) for an RNA-seq sample
  # 
  # Args:
  #   accession_code: sample accession code (should be RNA-seq!)
  #
  # Returns:
  #   project_accession: the project accession code associated with sample,
  #                      which is extracted from the European Nucleotide 
  #                      Archive reference URL
  
  sample_info <- refinebio_sample_code_to_list(accession_code)
  
  # this is only intended to work for RNA-seq samples
  if (sample_info$results$technology != "RNA-SEQ") 
    stop("get_sample_project_accession only works with RNA-seq samples!")
  
  # what project accession number did this come from? we can get this from the
  # url of the source reference stored in refine.bio
  reference_url <- sample_info$results$protocol_info[[1]]$Reference
  if (!is.null(reference_url)) {
    project_accession <- stringr::word(reference_url, -1, sep = "/") 
  } else {
    project_accession <- NA
  }
}
extract_sample_metadata <- function(accession_code) {
  # given an RNA-seq sample (run) accession code (e.g., SRRXXXXX), return the 
  # following metadata from the refine.bio API as a data.frame that is a 
  # single row: 
  #   sample accession code, project accession code (e.g.), library layout, 
  #   percent of reads mapped by salmon quant, number of reads, inferred library
  #   type, compatible fragment ratio, which length salmon index was used
  # 
  # Args:
  #   accession_code: the sample (run in SRA parlance) accession code
  #                   for an RNA-seq sample such as "SRR998890" (character)
  # 
  # Returns:
  #   a data.frame of dimensions 1, 9 that contains the information for the
  #   sample outlined above
  #   
  
  # internal helper function -- there are a bunch of variables that we need
  # to pull from a data.frame and get rid of multiple NAs so we'll use 
  # rlang::sym to help us with that
  extract_var_na_rm <- function(var_name = "percent_mapped") {
    sample_info_df %>%
      dplyr::filter(!is.na(!!rlang::sym(var_name))) %>%
      dplyr::pull(!!rlang::sym(var_name))
  }
  
  # get the sample annotations, etc. from the refine.bio API
  sample_info <- refinebio_sample_code_to_list(accession_code)
  
  # this is only intended to work for RNA-seq samples
  if (sample_info$results$technology != "RNA-SEQ") 
    stop("extract_sample_metadata only works with RNA-seq samples!")
  
  # what's the SRP|ERP|DRP ? this will help us track down 
  project_accession <- get_sample_project_accession(accession_code)
  
  # the sample annotations contain all the relevant information about the salmon
  # run
  sample_annotations <- sample_info$results$results[[1]]$annotations
  
  # there are a bunch of empty data.frame -- we don't want that! so let's find
  # the index of what we want and extract it
  nonempty_index <- which(unlist(lapply(lapply(sample_annotations, colnames), 
                                        length)) != 0)
  # if there's more than one nonempty data.frame, pick the first one
  # this is a hack but will do for this purpose
  sample_info_df <- sample_annotations[[nonempty_index[1]]]$data
  
  # paired or single end read -- only paired end will have corrections for
  # GC bias
  gc_bias <- any(sample_info_df$gc_bias_correct)
  if (gc_bias & !is.na(gc_bias)) {
    library_layout <- "PAIRED"
  } else {
    library_layout <- "SINGLE"
  }
  
  # the library types inferred by salmon quant
  library_type <- unique(unlist(sample_info_df$library_types))
  # if more than one library type was detected, just report it as multiple
  # this will require extra examination
  if (length(library_type) > 1)
    library_type <- "multiple"
  # what % of the reads for this sample are successfully mapped to the txome
  # index?
  percent_mapped <- extract_var_na_rm("percent_mapped") 
  
  # how many reads does this sample have?
  num_reads <- extract_var_na_rm("num_processed")
  
  # compatible fragment ratio -- a measure of agreement with the inferred 
  # library type
  compatible_fragment_ratio <- extract_var_na_rm("compatible_fragment_ratio")
  
  # what length index was used? (short or long)
  index_length <- extract_var_na_rm("index_length")
  
  data.frame(
    accession_code,
    experiment = project_accession,
    library_layout,
    platform = sample_info$results$pretty_platform,
    num_reads,
    percent_mapped,
    library_type,
    compatible_fragment_ratio,
    index_length
  )
  
}
get_metadata_df <- function(accession_codes) {
  # given a vector of sample accession codes, return a data.frame with the
  # information returned by extract_sample_metadata; we bind all the rows 
  # together
  # 
  # Args:
  #   accession_codes: a vector of sample accession codes (should be RNA-seq
  #                    samples) to be used with extract_sample_metadata
  #
  # Returns:
  #   metadata_df: the output of extract_sample_metdata (a 1 row data.frame for
  #                each sample) for each sample, now with the rows in a single
  #                data.frame via dplyr::bind_rows
  metadata_list <- lapply(accession_codes, extract_sample_metadata)
  # metadata_list is a list of 1 row data.frames, so there will be 
  # length(metadata_list) warnings about coercing to vector
  metadata_df <- suppressWarnings(dplyr::bind_rows(metadata_list))
}

Set seed for reproducibility

set.seed(6345)

Initial investigation of RNA-seq sample groups

Read in the data for PC1 and PC2 from 05-pca_test_compendium and filter to only the RNA-seq samples.

pc_file <- file.path("results", "larger_compendium_PC1and2.tsv")
seq_df <- readr::read_tsv(pc_file) %>%
  dplyr::filter(compendium_technology_labels != "MICROARRAY")
Parsed with column specification:
cols(
  compendium_technology_labels = col_character(),
  Sample = col_character(),
  PC1 = col_double(),
  PC2 = col_double()
)

We’re going to somewhat arbitrarily divide samples into two groups on the basis of their values for PC1.

seq_df <- seq_df %>%
  dplyr::mutate(Group = dplyr::case_when(
    PC1 > 0 ~ "positive",
    PC1 < 0 ~ "negative"
  ))

How’s this look?

seq_df %>%
  ggplot(aes(x = PC1, y = PC2, colour = Group)) +
  geom_point() +
  theme_bw()

This is probably close enough for what we’re after here.

Random subset of samples from each group

positive_samples <- seq_df %>% 
  dplyr::filter(Group == "positive") %>% 
  dplyr::pull(Sample) %>%
  sample(50)
negative_samples <- seq_df %>% 
  dplyr::filter(Group == "negative") %>% 
  dplyr::pull(Sample) %>%
  sample(50)

We took a look at a handful of samples and couldn’t discern a pattern of poly-A enrichment vs. rRNA depletion. So we decided to dig a bit deeper into metadata from the salmon quant runs themselves. (See all the custom functions above.)

Extract (salmon quant) metadata about the two groups

Extract the relevant metadata for the random subset of positive samples

positive_metadata_df <- get_metadata_df(positive_samples)
positive_metadata_df %>%
  dplyr::arrange(experiment)

Extract the relevant metadata for the random subset of negative samples

negative_metadata_df <- get_metadata_df(negative_samples)
negative_metadata_df %>%
  dplyr::arrange(experiment)

Notes on features of two groups

  • The positive group contains a mix of library layouts, instruments, and short and long read lengths.
  • The negative group is entirely paired-end samples with short read lengths and generally it looks like there are lower % reads mapped. However only a few experiments appear to be represented in this group.

What experiments are represented in the “negative” group?

Do all the negative samples come from very large experiments? Because ERP008771 and ERP006132 each have over 2000 samples.

rr # to save on compute time, we’ll sort the sample accession codes so runs from # the same experiment should be next to each other and then examine every # 25th sample all_negative_samples <- sort(seq_df %>% dplyr::filter(Group == ) %>% dplyr::pull(Sample)) indices <- seq(1, length(all_negative_samples), 25) negative_experiment_accession_codes <- sapply(all_negative_samples[indices], get_sample_project_accession) # display in a readable format data.frame(sort(unique(negative_experiment_accession_codes)))

Conclusion

These are all samples from large experiments from the Wellcome Sanger Institute Zebrafish Mutation Project. These samples tend to have fewer reads and lower mapping rates compared to a random selection of samples from the other group.

Session Info

sessionInfo()
R version 3.5.1 (2018-07-02)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux 9 (stretch)

Matrix products: default
BLAS: /usr/lib/openblas-base/libblas.so.3
LAPACK: /usr/lib/libopenblasp-r0.2.19.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=C              LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] bindrcpp_0.2.2 ggplot2_3.1.0 

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.0       pillar_1.3.1     compiler_3.5.1   plyr_1.8.4       bindr_0.1.1      base64enc_0.1-3 
 [7] tools_3.5.1      digest_0.6.18    jsonlite_1.6     evaluate_0.12    tibble_1.4.2     gtable_0.2.0    
[13] pkgconfig_2.0.2  rlang_0.3.0.1    rstudioapi_0.8   curl_3.2         yaml_2.2.0       xfun_0.4        
[19] withr_2.1.2      dplyr_0.7.8      stringr_1.3.1    knitr_1.21       hms_0.4.2        grid_3.5.1      
[25] tidyselect_0.2.5 glue_1.3.0       R6_2.3.0         rmarkdown_1.11   readr_1.3.0      purrr_0.2.5     
[31] magrittr_1.5     scales_1.0.0     htmltools_0.3.6  assertthat_0.2.0 colorspace_1.3-2 labeling_0.3    
[37] stringi_1.2.4    lazyeval_0.2.1   munsell_0.5.0    crayon_1.3.4    
LS0tCnRpdGxlOiAiVGVjaG5pY2FsIGJpYXMgaW4gUk5BLXNlcSBkYXRhIGZyb20gbGFyZ2VyIGNvbXBlbmRpdW0iCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogVFJVRQogICAgdG9jX2Zsb2F0OiBUUlVFCmF1dGhvcjogSi4gVGFyb25pIGZvciBDQ0RMCmRhdGU6IDIwMTkKLS0tCgpUaGUgUENBIHBsb3QgZm9yIHRoZSBsYXJnZXIgemVicmFmaXNoIHRlc3QgY29tcGVuZGl1bSAoYDA1LXBjYV90ZXN0X2NvbXBlbmRpdW1gKQpzaG93ZWQgYSBzZXBhcmF0aW9uIGJldHdlZW4gd2hhdCBtYXkgYmUgMiBncm91cHMgb2YgUk5BLXNlcSBzYW1wbGVzIGluIFBDMS4KCkhlcmUsIHdlJ2xsIGRpZyBpbnRvIHdoYXQgbWF5IHVuZGVybGllIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHR3byBjbHVzdGVycy4KV2Ugc3VzcGVjdCBpdCBtYXkgaGF2ZSB0byBkbyB3aXRoIHNhbXBsZSBwcmVwOyBzcGVjaWZpY2FsbHksIGl0IG1heSBiZSB0aGUKc2VsZWN0aW9uIHN0cmF0ZWd5IChwb2x5LUEgZW5yaWNobWVudCB2cy4gclJOQSBkZXBsZXRpb24pLgpGaXJzdCwgd2UgbmVlZCB0byBpZGVudGlmeSBhIHJhbmRvbSBzZWxlY3Rpb24gb2Ygc2FtcGxlcyB0aGF0IHdlIHdpbGwgdGhlbgpyZWFkIHRoZSBleHBlcmltZW50YWwgbWV0aG9kcyBmb3IuCgojIyBTZXQgdXAKCmBgYHtyfQpgJT4lYCA8LSBkcGx5cjo6YCU+JWAKbGlicmFyeShnZ3Bsb3QyKQpgYGAKCiMjIyBDdXN0b20gRnVuY3Rpb25zCgpgYGB7cn0KcmVmaW5lYmlvX3NhbXBsZV9jb2RlX3RvX2xpc3QgPC0gZnVuY3Rpb24oYWNjZXNzaW9uX2NvZGUpIHsKICAjIGdpdmVuIGEgc2FtcGxlIGFjY2Vzc2lvbiBjb2RlLCBnZXQgdGhlIHJlZmluZS5iaW8gc2FtcGxlIGluZm9ybWF0aW9uIGF0CiAgIyBhdCB0aGUgc2FtcGxlcyBlbmRwb2ludCBpbnRvIGxpc3QgZm9ybWF0IHdpdGgganNvbmxpdGU6OmZyb21KU09OCiAgIwogICMgQXJnczoKICAjICAgYWNjZXNzaW9uX2NvZGU6IHNhbXBsZSBhY2Nlc3Npb24gY29kZQogICMgCiAgIyBSZXR1cm5zOgogICMgICBzYW1wbGUgZW5kcG9pbnQgaW5mbyBhcyBhIGxpc3QgKGZyb20ganNvbmxpdGU6OmZyb21KU09OKQogIGFwaV91cmwgPC0gcGFzdGUwKCJodHRwczovL2FwaS5yZWZpbmUuYmlvL3NhbXBsZXMvP2FjY2Vzc2lvbl9jb2RlPSIsIAogICAgICAgICAgICAgICAgICAgIGFjY2Vzc2lvbl9jb2RlKQogIHNhbXBsZV9pbmZvIDwtIGpzb25saXRlOjpmcm9tSlNPTihhcGlfdXJsKQp9CmBgYAoKYGBge3J9CmdldF9zYW1wbGVfcHJvamVjdF9hY2Nlc3Npb24gPC0gZnVuY3Rpb24oYWNjZXNzaW9uX2NvZGUpIHsKICAjIHRha2VzIHRoZSBvdXRwdXQgb2YgcmVmaW5lYmlvX3NhbXBsZV9jb2RlX3RvX2xpc3QgYW5kIHJldHVybnMgYSBwcm9qZWN0CiAgIyAoZS5nLiwgU1JQWFhYWFhYKSBmb3IgYW4gUk5BLXNlcSBzYW1wbGUKICAjIAogICMgQXJnczoKICAjICAgYWNjZXNzaW9uX2NvZGU6IHNhbXBsZSBhY2Nlc3Npb24gY29kZSAoc2hvdWxkIGJlIFJOQS1zZXEhKQogICMKICAjIFJldHVybnM6CiAgIyAgIHByb2plY3RfYWNjZXNzaW9uOiB0aGUgcHJvamVjdCBhY2Nlc3Npb24gY29kZSBhc3NvY2lhdGVkIHdpdGggc2FtcGxlLAogICMgICAgICAgICAgICAgICAgICAgICAgd2hpY2ggaXMgZXh0cmFjdGVkIGZyb20gdGhlIEV1cm9wZWFuIE51Y2xlb3RpZGUgCiAgIyAgICAgICAgICAgICAgICAgICAgICBBcmNoaXZlIHJlZmVyZW5jZSBVUkwKICAKICBzYW1wbGVfaW5mbyA8LSByZWZpbmViaW9fc2FtcGxlX2NvZGVfdG9fbGlzdChhY2Nlc3Npb25fY29kZSkKICAKICAjIHRoaXMgaXMgb25seSBpbnRlbmRlZCB0byB3b3JrIGZvciBSTkEtc2VxIHNhbXBsZXMKICBpZiAoc2FtcGxlX2luZm8kcmVzdWx0cyR0ZWNobm9sb2d5ICE9ICJSTkEtU0VRIikgCiAgICBzdG9wKCJnZXRfc2FtcGxlX3Byb2plY3RfYWNjZXNzaW9uIG9ubHkgd29ya3Mgd2l0aCBSTkEtc2VxIHNhbXBsZXMhIikKICAKICAjIHdoYXQgcHJvamVjdCBhY2Nlc3Npb24gbnVtYmVyIGRpZCB0aGlzIGNvbWUgZnJvbT8gd2UgY2FuIGdldCB0aGlzIGZyb20gdGhlCiAgIyB1cmwgb2YgdGhlIHNvdXJjZSByZWZlcmVuY2Ugc3RvcmVkIGluIHJlZmluZS5iaW8KICByZWZlcmVuY2VfdXJsIDwtIHNhbXBsZV9pbmZvJHJlc3VsdHMkcHJvdG9jb2xfaW5mb1tbMV1dJFJlZmVyZW5jZQogIGlmICghaXMubnVsbChyZWZlcmVuY2VfdXJsKSkgewogICAgcHJvamVjdF9hY2Nlc3Npb24gPC0gc3RyaW5ncjo6d29yZChyZWZlcmVuY2VfdXJsLCAtMSwgc2VwID0gIi8iKSAKICB9IGVsc2UgewogICAgcHJvamVjdF9hY2Nlc3Npb24gPC0gTkEKICB9Cn0KYGBgCgpgYGB7cn0KZXh0cmFjdF9zYW1wbGVfbWV0YWRhdGEgPC0gZnVuY3Rpb24oYWNjZXNzaW9uX2NvZGUpIHsKICAjIGdpdmVuIGFuIFJOQS1zZXEgc2FtcGxlIChydW4pIGFjY2Vzc2lvbiBjb2RlIChlLmcuLCBTUlJYWFhYWCksIHJldHVybiB0aGUgCiAgIyBmb2xsb3dpbmcgbWV0YWRhdGEgZnJvbSB0aGUgcmVmaW5lLmJpbyBBUEkgYXMgYSBkYXRhLmZyYW1lIHRoYXQgaXMgYSAKICAjIHNpbmdsZSByb3c6IAogICMgICBzYW1wbGUgYWNjZXNzaW9uIGNvZGUsIHByb2plY3QgYWNjZXNzaW9uIGNvZGUgKGUuZy4pLCBsaWJyYXJ5IGxheW91dCwgCiAgIyAgIHBlcmNlbnQgb2YgcmVhZHMgbWFwcGVkIGJ5IHNhbG1vbiBxdWFudCwgbnVtYmVyIG9mIHJlYWRzLCBpbmZlcnJlZCBsaWJyYXJ5CiAgIyAgIHR5cGUsIGNvbXBhdGlibGUgZnJhZ21lbnQgcmF0aW8sIHdoaWNoIGxlbmd0aCBzYWxtb24gaW5kZXggd2FzIHVzZWQKICAjIAogICMgQXJnczoKICAjICAgYWNjZXNzaW9uX2NvZGU6IHRoZSBzYW1wbGUgKHJ1biBpbiBTUkEgcGFybGFuY2UpIGFjY2Vzc2lvbiBjb2RlCiAgIyAgICAgICAgICAgICAgICAgICBmb3IgYW4gUk5BLXNlcSBzYW1wbGUgc3VjaCBhcyAiU1JSOTk4ODkwIiAoY2hhcmFjdGVyKQogICMgCiAgIyBSZXR1cm5zOgogICMgICBhIGRhdGEuZnJhbWUgb2YgZGltZW5zaW9ucyAxLCA5IHRoYXQgY29udGFpbnMgdGhlIGluZm9ybWF0aW9uIGZvciB0aGUKICAjICAgc2FtcGxlIG91dGxpbmVkIGFib3ZlCiAgIyAgIAogIAogICMgaW50ZXJuYWwgaGVscGVyIGZ1bmN0aW9uIC0tIHRoZXJlIGFyZSBhIGJ1bmNoIG9mIHZhcmlhYmxlcyB0aGF0IHdlIG5lZWQKICAjIHRvIHB1bGwgZnJvbSBhIGRhdGEuZnJhbWUgYW5kIGdldCByaWQgb2YgbXVsdGlwbGUgTkFzIHNvIHdlJ2xsIHVzZSAKICAjIHJsYW5nOjpzeW0gdG8gaGVscCB1cyB3aXRoIHRoYXQKICBleHRyYWN0X3Zhcl9uYV9ybSA8LSBmdW5jdGlvbih2YXJfbmFtZSA9ICJwZXJjZW50X21hcHBlZCIpIHsKICAgIHNhbXBsZV9pbmZvX2RmICU+JQogICAgICBkcGx5cjo6ZmlsdGVyKCFpcy5uYSghIXJsYW5nOjpzeW0odmFyX25hbWUpKSkgJT4lCiAgICAgIGRwbHlyOjpwdWxsKCEhcmxhbmc6OnN5bSh2YXJfbmFtZSkpCiAgfQogIAogICMgZ2V0IHRoZSBzYW1wbGUgYW5ub3RhdGlvbnMsIGV0Yy4gZnJvbSB0aGUgcmVmaW5lLmJpbyBBUEkKICBzYW1wbGVfaW5mbyA8LSByZWZpbmViaW9fc2FtcGxlX2NvZGVfdG9fbGlzdChhY2Nlc3Npb25fY29kZSkKICAKICAjIHRoaXMgaXMgb25seSBpbnRlbmRlZCB0byB3b3JrIGZvciBSTkEtc2VxIHNhbXBsZXMKICBpZiAoc2FtcGxlX2luZm8kcmVzdWx0cyR0ZWNobm9sb2d5ICE9ICJSTkEtU0VRIikgCiAgICBzdG9wKCJleHRyYWN0X3NhbXBsZV9tZXRhZGF0YSBvbmx5IHdvcmtzIHdpdGggUk5BLXNlcSBzYW1wbGVzISIpCiAgCiAgIyB3aGF0J3MgdGhlIFNSUHxFUlB8RFJQID8gdGhpcyB3aWxsIGhlbHAgdXMgdHJhY2sgZG93biAKICBwcm9qZWN0X2FjY2Vzc2lvbiA8LSBnZXRfc2FtcGxlX3Byb2plY3RfYWNjZXNzaW9uKGFjY2Vzc2lvbl9jb2RlKQogIAogICMgdGhlIHNhbXBsZSBhbm5vdGF0aW9ucyBjb250YWluIGFsbCB0aGUgcmVsZXZhbnQgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHNhbG1vbgogICMgcnVuCiAgc2FtcGxlX2Fubm90YXRpb25zIDwtIHNhbXBsZV9pbmZvJHJlc3VsdHMkcmVzdWx0c1tbMV1dJGFubm90YXRpb25zCiAgCiAgIyB0aGVyZSBhcmUgYSBidW5jaCBvZiBlbXB0eSBkYXRhLmZyYW1lIC0tIHdlIGRvbid0IHdhbnQgdGhhdCEgc28gbGV0J3MgZmluZAogICMgdGhlIGluZGV4IG9mIHdoYXQgd2Ugd2FudCBhbmQgZXh0cmFjdCBpdAogIG5vbmVtcHR5X2luZGV4IDwtIHdoaWNoKHVubGlzdChsYXBwbHkobGFwcGx5KHNhbXBsZV9hbm5vdGF0aW9ucywgY29sbmFtZXMpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aCkpICE9IDApCiAgIyBpZiB0aGVyZSdzIG1vcmUgdGhhbiBvbmUgbm9uZW1wdHkgZGF0YS5mcmFtZSwgcGljayB0aGUgZmlyc3Qgb25lCiAgIyB0aGlzIGlzIGEgaGFjayBidXQgd2lsbCBkbyBmb3IgdGhpcyBwdXJwb3NlCiAgc2FtcGxlX2luZm9fZGYgPC0gc2FtcGxlX2Fubm90YXRpb25zW1tub25lbXB0eV9pbmRleFsxXV1dJGRhdGEKICAKICAjIHBhaXJlZCBvciBzaW5nbGUgZW5kIHJlYWQgLS0gb25seSBwYWlyZWQgZW5kIHdpbGwgaGF2ZSBjb3JyZWN0aW9ucyBmb3IKICAjIEdDIGJpYXMKICBnY19iaWFzIDwtIGFueShzYW1wbGVfaW5mb19kZiRnY19iaWFzX2NvcnJlY3QpCiAgaWYgKGdjX2JpYXMgJiAhaXMubmEoZ2NfYmlhcykpIHsKICAgIGxpYnJhcnlfbGF5b3V0IDwtICJQQUlSRUQiCiAgfSBlbHNlIHsKICAgIGxpYnJhcnlfbGF5b3V0IDwtICJTSU5HTEUiCiAgfQogIAogICMgdGhlIGxpYnJhcnkgdHlwZXMgaW5mZXJyZWQgYnkgc2FsbW9uIHF1YW50CiAgbGlicmFyeV90eXBlIDwtIHVuaXF1ZSh1bmxpc3Qoc2FtcGxlX2luZm9fZGYkbGlicmFyeV90eXBlcykpCiAgIyBpZiBtb3JlIHRoYW4gb25lIGxpYnJhcnkgdHlwZSB3YXMgZGV0ZWN0ZWQsIGp1c3QgcmVwb3J0IGl0IGFzIG11bHRpcGxlCiAgIyB0aGlzIHdpbGwgcmVxdWlyZSBleHRyYSBleGFtaW5hdGlvbgogIGlmIChsZW5ndGgobGlicmFyeV90eXBlKSA+IDEpCiAgICBsaWJyYXJ5X3R5cGUgPC0gIm11bHRpcGxlIgoKICAjIHdoYXQgJSBvZiB0aGUgcmVhZHMgZm9yIHRoaXMgc2FtcGxlIGFyZSBzdWNjZXNzZnVsbHkgbWFwcGVkIHRvIHRoZSB0eG9tZQogICMgaW5kZXg/CiAgcGVyY2VudF9tYXBwZWQgPC0gZXh0cmFjdF92YXJfbmFfcm0oInBlcmNlbnRfbWFwcGVkIikgCiAgCiAgIyBob3cgbWFueSByZWFkcyBkb2VzIHRoaXMgc2FtcGxlIGhhdmU/CiAgbnVtX3JlYWRzIDwtIGV4dHJhY3RfdmFyX25hX3JtKCJudW1fcHJvY2Vzc2VkIikKICAKICAjIGNvbXBhdGlibGUgZnJhZ21lbnQgcmF0aW8gLS0gYSBtZWFzdXJlIG9mIGFncmVlbWVudCB3aXRoIHRoZSBpbmZlcnJlZCAKICAjIGxpYnJhcnkgdHlwZQogIGNvbXBhdGlibGVfZnJhZ21lbnRfcmF0aW8gPC0gZXh0cmFjdF92YXJfbmFfcm0oImNvbXBhdGlibGVfZnJhZ21lbnRfcmF0aW8iKQogIAogICMgd2hhdCBsZW5ndGggaW5kZXggd2FzIHVzZWQ/IChzaG9ydCBvciBsb25nKQogIGluZGV4X2xlbmd0aCA8LSBleHRyYWN0X3Zhcl9uYV9ybSgiaW5kZXhfbGVuZ3RoIikKICAKICBkYXRhLmZyYW1lKAogICAgYWNjZXNzaW9uX2NvZGUsCiAgICBleHBlcmltZW50ID0gcHJvamVjdF9hY2Nlc3Npb24sCiAgICBsaWJyYXJ5X2xheW91dCwKICAgIHBsYXRmb3JtID0gc2FtcGxlX2luZm8kcmVzdWx0cyRwcmV0dHlfcGxhdGZvcm0sCiAgICBudW1fcmVhZHMsCiAgICBwZXJjZW50X21hcHBlZCwKICAgIGxpYnJhcnlfdHlwZSwKICAgIGNvbXBhdGlibGVfZnJhZ21lbnRfcmF0aW8sCiAgICBpbmRleF9sZW5ndGgKICApCiAgCn0KYGBgCgpgYGB7cn0KZ2V0X21ldGFkYXRhX2RmIDwtIGZ1bmN0aW9uKGFjY2Vzc2lvbl9jb2RlcykgewogICMgZ2l2ZW4gYSB2ZWN0b3Igb2Ygc2FtcGxlIGFjY2Vzc2lvbiBjb2RlcywgcmV0dXJuIGEgZGF0YS5mcmFtZSB3aXRoIHRoZQogICMgaW5mb3JtYXRpb24gcmV0dXJuZWQgYnkgZXh0cmFjdF9zYW1wbGVfbWV0YWRhdGE7IHdlIGJpbmQgYWxsIHRoZSByb3dzIAogICMgdG9nZXRoZXIKICAjIAogICMgQXJnczoKICAjICAgYWNjZXNzaW9uX2NvZGVzOiBhIHZlY3RvciBvZiBzYW1wbGUgYWNjZXNzaW9uIGNvZGVzIChzaG91bGQgYmUgUk5BLXNlcQogICMgICAgICAgICAgICAgICAgICAgIHNhbXBsZXMpIHRvIGJlIHVzZWQgd2l0aCBleHRyYWN0X3NhbXBsZV9tZXRhZGF0YQogICMKICAjIFJldHVybnM6CiAgIyAgIG1ldGFkYXRhX2RmOiB0aGUgb3V0cHV0IG9mIGV4dHJhY3Rfc2FtcGxlX21ldGRhdGEgKGEgMSByb3cgZGF0YS5mcmFtZSBmb3IKICAjICAgICAgICAgICAgICAgIGVhY2ggc2FtcGxlKSBmb3IgZWFjaCBzYW1wbGUsIG5vdyB3aXRoIHRoZSByb3dzIGluIGEgc2luZ2xlCiAgIyAgICAgICAgICAgICAgICBkYXRhLmZyYW1lIHZpYSBkcGx5cjo6YmluZF9yb3dzCgogIG1ldGFkYXRhX2xpc3QgPC0gbGFwcGx5KGFjY2Vzc2lvbl9jb2RlcywgZXh0cmFjdF9zYW1wbGVfbWV0YWRhdGEpCiAgIyBtZXRhZGF0YV9saXN0IGlzIGEgbGlzdCBvZiAxIHJvdyBkYXRhLmZyYW1lcywgc28gdGhlcmUgd2lsbCBiZSAKICAjIGxlbmd0aChtZXRhZGF0YV9saXN0KSB3YXJuaW5ncyBhYm91dCBjb2VyY2luZyB0byB2ZWN0b3IKICBtZXRhZGF0YV9kZiA8LSBzdXBwcmVzc1dhcm5pbmdzKGRwbHlyOjpiaW5kX3Jvd3MobWV0YWRhdGFfbGlzdCkpCn0KYGBgCgojIyMgU2V0IHNlZWQgZm9yIHJlcHJvZHVjaWJpbGl0eQoKYGBge3J9CnNldC5zZWVkKDYzNDUpCmBgYAoKIyMgSW5pdGlhbCBpbnZlc3RpZ2F0aW9uIG9mIFJOQS1zZXEgc2FtcGxlIGdyb3VwcwoKUmVhZCBpbiB0aGUgZGF0YSBmb3IgUEMxIGFuZCBQQzIgZnJvbSBgMDUtcGNhX3Rlc3RfY29tcGVuZGl1bWAgYW5kIGZpbHRlciB0bwpvbmx5IHRoZSBSTkEtc2VxIHNhbXBsZXMuCgpgYGB7cn0KcGNfZmlsZSA8LSBmaWxlLnBhdGgoInJlc3VsdHMiLCAibGFyZ2VyX2NvbXBlbmRpdW1fUEMxYW5kMi50c3YiKQpzZXFfZGYgPC0gcmVhZHI6OnJlYWRfdHN2KHBjX2ZpbGUpICU+JQogIGRwbHlyOjpmaWx0ZXIoY29tcGVuZGl1bV90ZWNobm9sb2d5X2xhYmVscyAhPSAiTUlDUk9BUlJBWSIpCmBgYAoKV2UncmUgZ29pbmcgdG8gc29tZXdoYXQgYXJiaXRyYXJpbHkgZGl2aWRlIHNhbXBsZXMgaW50byB0d28gZ3JvdXBzIG9uIHRoZSBiYXNpcwpvZiB0aGVpciB2YWx1ZXMgZm9yIFBDMS4KCmBgYHtyfQpzZXFfZGYgPC0gc2VxX2RmICU+JQogIGRwbHlyOjptdXRhdGUoR3JvdXAgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgUEMxID4gMCB+ICJwb3NpdGl2ZSIsCiAgICBQQzEgPCAwIH4gIm5lZ2F0aXZlIgogICkpCmBgYAoKSG93J3MgdGhpcyBsb29rPwoKYGBge3J9CnNlcV9kZiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBQQzEsIHkgPSBQQzIsIGNvbG91ciA9IEdyb3VwKSkgKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWVfYncoKQpgYGAKClRoaXMgaXMgcHJvYmFibHkgY2xvc2UgZW5vdWdoIGZvciB3aGF0IHdlJ3JlIGFmdGVyIGhlcmUuCgojIyMgUmFuZG9tIHN1YnNldCBvZiBzYW1wbGVzIGZyb20gZWFjaCBncm91cAoKYGBge3J9CnBvc2l0aXZlX3NhbXBsZXMgPC0gc2VxX2RmICU+JSAKICBkcGx5cjo6ZmlsdGVyKEdyb3VwID09ICJwb3NpdGl2ZSIpICU+JSAKICBkcGx5cjo6cHVsbChTYW1wbGUpICU+JQogIHNhbXBsZSg1MCkKYGBgCgpgYGB7cn0KbmVnYXRpdmVfc2FtcGxlcyA8LSBzZXFfZGYgJT4lIAogIGRwbHlyOjpmaWx0ZXIoR3JvdXAgPT0gIm5lZ2F0aXZlIikgJT4lIAogIGRwbHlyOjpwdWxsKFNhbXBsZSkgJT4lCiAgc2FtcGxlKDUwKQpgYGAKCldlIHRvb2sgYSBsb29rIGF0IGEgaGFuZGZ1bCBvZiBzYW1wbGVzIGFuZCBjb3VsZG4ndCBkaXNjZXJuIGEgcGF0dGVybiBvZiBwb2x5LUEKZW5yaWNobWVudCB2cy4gclJOQSBkZXBsZXRpb24uClNvIHdlIGRlY2lkZWQgdG8gZGlnIGEgYml0IGRlZXBlciBpbnRvIG1ldGFkYXRhIGZyb20gdGhlIGBzYWxtb24gcXVhbnRgIHJ1bnMgCnRoZW1zZWx2ZXMuIAooU2VlIGFsbCB0aGUgY3VzdG9tIGZ1bmN0aW9ucyBhYm92ZS4pCgojIyMgRXh0cmFjdCAoYHNhbG1vbiBxdWFudGApIG1ldGFkYXRhIGFib3V0IHRoZSB0d28gZ3JvdXBzCgpFeHRyYWN0IHRoZSByZWxldmFudCBtZXRhZGF0YSBmb3IgdGhlIHJhbmRvbSBzdWJzZXQgb2YgcG9zaXRpdmUgc2FtcGxlcwoKYGBge3J9CnBvc2l0aXZlX21ldGFkYXRhX2RmIDwtIGdldF9tZXRhZGF0YV9kZihwb3NpdGl2ZV9zYW1wbGVzKQpwb3NpdGl2ZV9tZXRhZGF0YV9kZiAlPiUKICBkcGx5cjo6YXJyYW5nZShleHBlcmltZW50KQpgYGAKCkV4dHJhY3QgdGhlIHJlbGV2YW50IG1ldGFkYXRhIGZvciB0aGUgcmFuZG9tIHN1YnNldCBvZiBuZWdhdGl2ZSBzYW1wbGVzCgpgYGB7cn0KbmVnYXRpdmVfbWV0YWRhdGFfZGYgPC0gZ2V0X21ldGFkYXRhX2RmKG5lZ2F0aXZlX3NhbXBsZXMpCm5lZ2F0aXZlX21ldGFkYXRhX2RmICU+JQogIGRwbHlyOjphcnJhbmdlKGV4cGVyaW1lbnQpCmBgYAoKIyMjIyBOb3RlcyBvbiBmZWF0dXJlcyBvZiB0d28gZ3JvdXBzCgoqIFRoZSBwb3NpdGl2ZSBncm91cCBjb250YWlucyBhIG1peCBvZiBsaWJyYXJ5IGxheW91dHMsIGluc3RydW1lbnRzLCBhbmQgc2hvcnQKYW5kIGxvbmcgcmVhZCBsZW5ndGhzLgoqIFRoZSBuZWdhdGl2ZSBncm91cCBpcyBlbnRpcmVseSBwYWlyZWQtZW5kIHNhbXBsZXMgd2l0aCBzaG9ydCByZWFkIGxlbmd0aHMgYW5kIApnZW5lcmFsbHkgaXQgbG9va3MgbGlrZSB0aGVyZSBhcmUgbG93ZXIgJSByZWFkcyBtYXBwZWQuIF9Ib3dldmVyXyBvbmx5IGEgZmV3IApleHBlcmltZW50cyBhcHBlYXIgdG8gYmUgcmVwcmVzZW50ZWQgaW4gdGhpcyBncm91cC4KCiMjIyBXaGF0IGV4cGVyaW1lbnRzIGFyZSByZXByZXNlbnRlZCBpbiB0aGUgIm5lZ2F0aXZlIiBncm91cD8KCkRvIGFsbCB0aGUgbmVnYXRpdmUgc2FtcGxlcyBjb21lIGZyb20gdmVyeSBsYXJnZSBleHBlcmltZW50cz8KQmVjYXVzZSBgRVJQMDA4NzcxYCBhbmQgYEVSUDAwNjEzMmAgZWFjaCBoYXZlIG92ZXIgMjAwMCBzYW1wbGVzLgoKYGBge3J9CiMgdG8gc2F2ZSBvbiBjb21wdXRlIHRpbWUsIHdlJ2xsIHNvcnQgdGhlIHNhbXBsZSBhY2Nlc3Npb24gY29kZXMgc28gcnVucyBmcm9tCiMgdGhlIHNhbWUgZXhwZXJpbWVudCBzaG91bGQgYmUgbmV4dCB0byBlYWNoIG90aGVyIGFuZCB0aGVuIGV4YW1pbmUgZXZlcnkKIyAyNXRoIHNhbXBsZQphbGxfbmVnYXRpdmVfc2FtcGxlcyA8LSBzb3J0KHNlcV9kZiAlPiUgCiAgZHBseXI6OmZpbHRlcihHcm91cCA9PSAibmVnYXRpdmUiKSAlPiUgCiAgZHBseXI6OnB1bGwoU2FtcGxlKSkKaW5kaWNlcyA8LSBzZXEoMSwgbGVuZ3RoKGFsbF9uZWdhdGl2ZV9zYW1wbGVzKSwgMjUpCm5lZ2F0aXZlX2V4cGVyaW1lbnRfYWNjZXNzaW9uX2NvZGVzIDwtIAogIHNhcHBseShhbGxfbmVnYXRpdmVfc2FtcGxlc1tpbmRpY2VzXSwgZ2V0X3NhbXBsZV9wcm9qZWN0X2FjY2Vzc2lvbikKIyBkaXNwbGF5IGluIGEgcmVhZGFibGUgZm9ybWF0CmRhdGEuZnJhbWUoc29ydCh1bmlxdWUobmVnYXRpdmVfZXhwZXJpbWVudF9hY2Nlc3Npb25fY29kZXMpKSkKYGBgCgojIyBDb25jbHVzaW9uCgpUaGVzZSBhcmUgYWxsIHNhbXBsZXMgZnJvbSBsYXJnZSBleHBlcmltZW50cyBmcm9tIHRoZSBXZWxsY29tZSBTYW5nZXIgSW5zdGl0dXRlIApaZWJyYWZpc2ggTXV0YXRpb24gUHJvamVjdC4gClRoZXNlIHNhbXBsZXMgdGVuZCB0byBoYXZlIGZld2VyIHJlYWRzIGFuZCBsb3dlciBtYXBwaW5nIHJhdGVzIGNvbXBhcmVkIHRvIGEgCnJhbmRvbSBzZWxlY3Rpb24gb2Ygc2FtcGxlcyBmcm9tIHRoZSBvdGhlciBncm91cC4KCiMjIFNlc3Npb24gSW5mbwoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCg==