This analysis has been adapted from this refine.bio-examples notebook

1 Purpose of the analysis

In this analysis, we will use this acute myeloid leukemia sample dataset from @Shih2017 and pre-processed by @refinebio.

The data that we downloaded from refine.bio for this analysis has 19 samples (obtained from 19 mice with acute myeloid leukemia (AML)), containing RNA-sequencing results for types of AML under controlled treatment conditions.

This dataset can be downloaded from this page on refine.bio. 00-download-data.py downloads it already processed and quantile normalized.

1.1 Set up analysis folders

# Create the data folder if it doesn't exist
if (!dir.exists("data")) {
  dir.create("data")
}

# Define the file path to the plots directory
plots_dir <- "plots"

# Create the plots folder if it doesn't exist
if (!dir.exists(plots_dir)) {
  dir.create(plots_dir)
}

# Define the file path to the results directory
results_dir <- "results"

# Create the results folder if it doesn't exist
if (!dir.exists(results_dir)) {
  dir.create(results_dir)
}
# Define the file path to the data directory
data_dir <- file.path("data", "SRP070849")

# Declare the file path to the gene expression matrix file
data_file <- file.path(data_dir, "SRP070849.tsv")

# Declare the file path to the metadata file
# inside the directory saved as `data_dir`
metadata_file <- file.path(data_dir, "metadata_SRP070849.tsv")

2 Clustering Heatmap - RNA-seq

2.1 Install libraries

We will use pheatmap [@Slowikowski2017] for clustering and creating a heatmap.

if (!("pheatmap" %in% installed.packages())) {
  # Install pheatmap
  install.packages("pheatmap", update = FALSE)
}

Attach the pheatmap and magrittr libraries:

# Attach the `pheatmap` library
library(pheatmap)
package ‘pheatmap’ was built under R version 4.0.3
# We will need this so we can use the pipe: %>%
library(magrittr)

# Set the seed so our results are reproducible:
set.seed(12345)

2.2 Import and set up data

This chunk of code will read in both TSV files and add them as data frames to your environment.

# Read in metadata TSV file
metadata <- readr::read_tsv(metadata_file)

── Column specification ─────────────────────────────────────────────────────────────────────────
cols(
  .default = col_character(),
  refinebio_age = col_logical(),
  refinebio_cell_line = col_logical(),
  refinebio_compound = col_logical(),
  refinebio_disease = col_logical(),
  refinebio_disease_stage = col_logical(),
  refinebio_genetic_information = col_logical(),
  refinebio_processed = col_logical(),
  refinebio_processor_id = col_double(),
  refinebio_race = col_logical(),
  refinebio_sex = col_logical(),
  refinebio_source_archive_url = col_logical(),
  refinebio_time = col_logical()
)
ℹ Use `spec()` for the full column specifications.
# Read in data TSV file
expression_df <- readr::read_tsv(data_file) %>%
  # Here we are going to store the gene IDs as row names so that
  # we can have only numeric values to perform calculations on later
  tibble::column_to_rownames("Gene")

── Column specification ─────────────────────────────────────────────────────────────────────────
cols(
  .default = col_double(),
  Gene = col_character()
)
ℹ Use `spec()` for the full column specifications.

Let’s take a look at the metadata object that we read into the R environment.

head(metadata)

Now let’s ensure that the metadata and data are in the same sample order.

# Make the data in the order of the metadata
expression_df <- expression_df %>%
  dplyr::select(metadata$refinebio_accession_code)

# Check if this is in the same order
all.equal(colnames(expression_df), metadata$refinebio_accession_code)
[1] TRUE

Now we are going to use the pheatmap package to look at how are samples and genes are clustering.

2.3 Choose genes of interest

For this example, we will sort genes by variance and select genes in the upper quartile, but there are many alternative criterion by which you may want to sort your genes, e.g. fold change, t-statistic, membership in a particular gene ontology, so on.

# Calculate the variance for each gene
variances <- apply(expression_df, 1, var)

# Determine the upper quartile variance cutoff value
upper_var <- quantile(variances, 0.75)

# Filter the data choosing only genes whose variances are in the upper quartile
df_by_var <- data.frame(expression_df) %>%
  dplyr::filter(variances > upper_var)

Let’s save these to our results folder as a TSV file.

readr::write_tsv(df_by_var, file.path(results_dir, "top_90_var_genes.tsv"))

2.4 Prepare metadata for annotation

From the accompanying paper, we know that the mice with IDH2 mutant AML were treated with vehicle or AG-221 (the first small molecule in-vivo inhibitor of IDH2 to enter clinical trials) and the mice with TET2 mutant AML were treated with vehicle or 5-Azacytidine (Decitabine, hypomethylating agent). [@Shih2017]

# Let's prepare the annotation for the uncollapsed `DESeqData` set object
# which will be used to annotate the heatmap
annotation_df <- metadata %>%
  # Create a variable to store the cancer type information
  dplyr::mutate(
    mutation = dplyr::case_when(
      startsWith(refinebio_title, "TET2") ~ "TET2",
      startsWith(refinebio_title, "IDH2") ~ "IDH2",
      startsWith(refinebio_title, "WT") ~ "WT",
      # If none of the above criteria are satisfied,
      # we mark the `mutation` variable as "unknown"
      TRUE ~ "unknown"
    )
  ) %>%
  # select only the columns we need for annotation
  dplyr::select(
    refinebio_accession_code,
    mutation,
    refinebio_treatment
  ) %>%
  # The `pheatmap()` function requires that the row names of our annotation
  # data frame match the column names of our `DESeaDataSet` object
  tibble::column_to_rownames("refinebio_accession_code")

2.4.1 Create annotated heatmap

# Create and store the annotated heatmap object
heatmap_annotated <-
  pheatmap(
    df_by_var,
    cluster_rows = TRUE,
    cluster_cols = TRUE,
    show_rownames = FALSE,
    annotation_col = annotation_df, # Specify our annotation here
    main = "Annotated Heatmap",
    colorRampPalette(c(
      "deepskyblue",
      "black",
      "yellow"
    ))(25
    ),
    scale = "row" # Scale values in the direction of genes (rows)
  )

2.4.2 Save annotated heatmap as a PNG

You can switch this to save to a JPEG or TIFF by changing the function and file name within the function to the respective file suffix.

# Open a PNG file
png(file.path(
  plots_dir,
  "aml_heatmap.png" # Replace with a relevant file name
))

# Print the heatmap
heatmap_annotated

# Close the PNG file:
dev.off()
null device 
          1 

3 Session info

# Print session info
sessioninfo::session_info()
─ Session info ────────────────────────────────────────────────────────────────────────────────

─ Packages ────────────────────────────────────────────────────────────────────────────────────
 package      * version date       lib source                            
 assertthat     0.2.1   2019-03-21 [1] RSPM (R 4.0.3)                    
 cli            2.0.2   2020-02-28 [1] RSPM (R 4.0.0)                    
 colorspace     1.4-1   2019-03-18 [1] RSPM (R 4.0.0)                    
 crayon         1.3.4   2017-09-16 [1] RSPM (R 4.0.0)                    
 digest         0.6.25  2020-02-23 [1] RSPM (R 4.0.0)                    
 dplyr          1.0.2   2020-08-18 [1] RSPM (R 4.0.2)                    
 ellipsis       0.3.1   2020-05-15 [1] RSPM (R 4.0.3)                    
 evaluate       0.14    2019-05-28 [1] RSPM (R 4.0.3)                    
 fansi          0.4.1   2020-01-08 [1] RSPM (R 4.0.0)                    
 farver         2.0.3   2020-01-16 [1] RSPM (R 4.0.3)                    
 fs             1.5.0   2020-07-31 [1] RSPM (R 4.0.3)                    
 generics       0.0.2   2018-11-29 [1] RSPM (R 4.0.0)                    
 glue           1.4.2   2020-08-27 [1] RSPM (R 4.0.3)                    
 gtable         0.3.0   2019-03-25 [1] RSPM (R 4.0.3)                    
 hms            0.5.3   2020-01-08 [1] RSPM (R 4.0.0)                    
 htmltools      0.5.0   2020-06-16 [1] RSPM (R 4.0.1)                    
 knitr          1.33    2021-09-29 [1] Github (yihui/knitr@a1052d1)      
 lattice        0.20-41 2020-04-02 [2] CRAN (R 4.0.2)                    
 leanbuild      0.1.2   2021-09-29 [1] Github (jhudsl/leanbuild@dc8f933) 
 lifecycle      1.0.0   2021-02-15 [1] CRAN (R 4.0.2)                    
 magrittr     * 1.5     2014-11-22 [1] RSPM (R 4.0.0)                    
 Matrix         1.2-18  2019-11-27 [2] CRAN (R 4.0.2)                    
 munsell        0.5.0   2018-06-12 [1] RSPM (R 4.0.3)                    
 pheatmap     * 1.0.12  2019-01-04 [1] RSPM (R 4.0.3)                    
 pillar         1.4.6   2020-07-10 [1] RSPM (R 4.0.2)                    
 pkgconfig      2.0.3   2019-09-22 [1] RSPM (R 4.0.3)                    
 purrr          0.3.4   2020-04-17 [1] RSPM (R 4.0.3)                    
 R6             2.4.1   2019-11-12 [1] RSPM (R 4.0.0)                    
 RColorBrewer   1.1-2   2014-12-07 [1] RSPM (R 4.0.3)                    
 readr          1.4.0   2020-10-05 [1] RSPM (R 4.0.2)                    
 rlang          0.4.10  2021-09-29 [1] Github (r-lib/rlang@f0c9be5)      
 rmarkdown      2.10    2021-09-29 [1] Github (rstudio/rmarkdown@02d3c25)
 rstudioapi     0.11    2020-02-07 [1] RSPM (R 4.0.0)                    
 scales         1.1.1   2020-05-11 [1] RSPM (R 4.0.3)                    
 sessioninfo    1.1.1   2018-11-05 [1] RSPM (R 4.0.3)                    
 tibble         3.0.3   2020-07-10 [1] RSPM (R 4.0.2)                    
 tidyselect     1.1.0   2020-05-11 [1] RSPM (R 4.0.3)                    
 tinytex        0.26    2020-09-22 [1] RSPM (R 4.0.2)                    
 vctrs          0.3.4   2020-08-29 [1] RSPM (R 4.0.2)                    
 withr          2.3.0   2020-09-22 [1] RSPM (R 4.0.2)                    
 xfun           0.26    2021-09-29 [1] Github (yihui/xfun@74c2a66)       
 yaml           2.2.1   2020-02-01 [1] RSPM (R 4.0.3)                    

[1] /usr/local/lib/R/site-library
[2] /usr/local/lib/R/library
LS0tCnRpdGxlOiAiQWN1dGUgTXllbG9pZCBMZXVrZW1pYSBIZWF0bWFwIgphdXRob3I6ICJDQ0RMIGZvciBBTFNGIC0gQWRhcHRlZCBmb3IgdGhpcyByZXBvc2l0b3J5IGJ5IENhbmRhY2UgU2F2b25lbiIKZGF0ZTogIk9jdG9iZXIgMjAyMSIKb3V0cHV0OiAgIAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQpfVGhpcyBhbmFseXNpcyBoYXMgYmVlbiBhZGFwdGVkIGZyb20gdGhpcyBbcmVmaW5lLmJpby1leGFtcGxlcyBub3RlYm9va10oaHR0cHM6Ly9hbGV4c2xlbW9uYWRlLmdpdGh1Yi5pby9yZWZpbmViaW8tZXhhbXBsZXMvMDMtcm5hc2VxL2NsdXN0ZXJpbmdfcm5hc2VxXzAxX2hlYXRtYXAuaHRtbClfCgojIFB1cnBvc2Ugb2YgdGhlIGFuYWx5c2lzCgpJbiB0aGlzIGFuYWx5c2lzLCB3ZSB3aWxsIHVzZSB0aGlzIFthY3V0ZSBteWVsb2lkIGxldWtlbWlhIHNhbXBsZSBkYXRhc2V0XShodHRwczovL3d3dy5yZWZpbmUuYmlvL2V4cGVyaW1lbnRzL1NSUDA3MDg0OSkgZnJvbSBAU2hpaDIwMTcgYW5kIHByZS1wcm9jZXNzZWQgYnkgQHJlZmluZWJpby4KClRoZSBkYXRhIHRoYXQgd2UgZG93bmxvYWRlZCBmcm9tIFtyZWZpbmUuYmlvXShodHRwczovL3d3dy5yZWZpbmUuYmlvLykgZm9yIHRoaXMgYW5hbHlzaXMgaGFzIDE5IHNhbXBsZXMgKG9idGFpbmVkIGZyb20gMTkgbWljZSB3aXRoIGFjdXRlIG15ZWxvaWQgbGV1a2VtaWEgKEFNTCkpLCBjb250YWluaW5nIFJOQS1zZXF1ZW5jaW5nIHJlc3VsdHMgZm9yIHR5cGVzIG9mIEFNTCB1bmRlciBjb250cm9sbGVkIHRyZWF0bWVudCBjb25kaXRpb25zLgoKVGhpcyBbZGF0YXNldCBjYW4gYmUgZG93bmxvYWRlZCBmcm9tIHRoaXMgcGFnZSBvbiByZWZpbmUuYmlvXShodHRwczovL3d3dy5yZWZpbmUuYmlvL2V4cGVyaW1lbnRzL1NSUDA3MDg0OSkuCmAwMC1kb3dubG9hZC1kYXRhLnB5YCBkb3dubG9hZHMgaXQgYWxyZWFkeSBbcHJvY2Vzc2VkIGFuZCBxdWFudGlsZSBub3JtYWxpemVkXShodHRwOi8vZG9jcy5yZWZpbmUuYmlvL2VuL2xhdGVzdC9tYWluX3RleHQuaHRtbCNyZWZpbmUtYmlvLXByb2Nlc3NlZC1yZWZpbmViaW8tcHJvY2Vzc2VkaWJhZGdlKS4KCiMjIFNldCB1cCBhbmFseXNpcyBmb2xkZXJzCgpgYGB7cn0KIyBDcmVhdGUgdGhlIGRhdGEgZm9sZGVyIGlmIGl0IGRvZXNuJ3QgZXhpc3QKaWYgKCFkaXIuZXhpc3RzKCJkYXRhIikpIHsKICBkaXIuY3JlYXRlKCJkYXRhIikKfQoKIyBEZWZpbmUgdGhlIGZpbGUgcGF0aCB0byB0aGUgcGxvdHMgZGlyZWN0b3J5CnBsb3RzX2RpciA8LSAicGxvdHMiCgojIENyZWF0ZSB0aGUgcGxvdHMgZm9sZGVyIGlmIGl0IGRvZXNuJ3QgZXhpc3QKaWYgKCFkaXIuZXhpc3RzKHBsb3RzX2RpcikpIHsKICBkaXIuY3JlYXRlKHBsb3RzX2RpcikKfQoKIyBEZWZpbmUgdGhlIGZpbGUgcGF0aCB0byB0aGUgcmVzdWx0cyBkaXJlY3RvcnkKcmVzdWx0c19kaXIgPC0gInJlc3VsdHMiCgojIENyZWF0ZSB0aGUgcmVzdWx0cyBmb2xkZXIgaWYgaXQgZG9lc24ndCBleGlzdAppZiAoIWRpci5leGlzdHMocmVzdWx0c19kaXIpKSB7CiAgZGlyLmNyZWF0ZShyZXN1bHRzX2RpcikKfQpgYGAKCmBgYHtyfQojIERlZmluZSB0aGUgZmlsZSBwYXRoIHRvIHRoZSBkYXRhIGRpcmVjdG9yeQpkYXRhX2RpciA8LSBmaWxlLnBhdGgoImRhdGEiLCAiU1JQMDcwODQ5IikKCiMgRGVjbGFyZSB0aGUgZmlsZSBwYXRoIHRvIHRoZSBnZW5lIGV4cHJlc3Npb24gbWF0cml4IGZpbGUKZGF0YV9maWxlIDwtIGZpbGUucGF0aChkYXRhX2RpciwgIlNSUDA3MDg0OS50c3YiKQoKIyBEZWNsYXJlIHRoZSBmaWxlIHBhdGggdG8gdGhlIG1ldGFkYXRhIGZpbGUKIyBpbnNpZGUgdGhlIGRpcmVjdG9yeSBzYXZlZCBhcyBgZGF0YV9kaXJgCm1ldGFkYXRhX2ZpbGUgPC0gZmlsZS5wYXRoKGRhdGFfZGlyLCAibWV0YWRhdGFfU1JQMDcwODQ5LnRzdiIpCmBgYAoKIyBDbHVzdGVyaW5nIEhlYXRtYXAgLSBSTkEtc2VxCgojIyBJbnN0YWxsIGxpYnJhcmllcwoKV2Ugd2lsbCB1c2UgYHBoZWF0bWFwYCBbQFNsb3dpa293c2tpMjAxN10gZm9yIGNsdXN0ZXJpbmcgYW5kIGNyZWF0aW5nIGEgaGVhdG1hcC4KCmBgYHtyfQppZiAoISgicGhlYXRtYXAiICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSB7CiAgIyBJbnN0YWxsIHBoZWF0bWFwCiAgaW5zdGFsbC5wYWNrYWdlcygicGhlYXRtYXAiLCB1cGRhdGUgPSBGQUxTRSkKfQpgYGAKCkF0dGFjaCB0aGUgYHBoZWF0bWFwYCBhbmQgYG1hZ3JpdHRyYCBsaWJyYXJpZXM6CgpgYGB7ciBtZXNzYWdlPUZBTFNFfQojIEF0dGFjaCB0aGUgYHBoZWF0bWFwYCBsaWJyYXJ5CmxpYnJhcnkocGhlYXRtYXApCgojIFdlIHdpbGwgbmVlZCB0aGlzIHNvIHdlIGNhbiB1c2UgdGhlIHBpcGU6ICU+JQpsaWJyYXJ5KG1hZ3JpdHRyKQoKIyBTZXQgdGhlIHNlZWQgc28gb3VyIHJlc3VsdHMgYXJlIHJlcHJvZHVjaWJsZToKc2V0LnNlZWQoMTIzNDUpCmBgYAoKIyMgSW1wb3J0IGFuZCBzZXQgdXAgZGF0YQoKVGhpcyBjaHVuayBvZiBjb2RlIHdpbGwgcmVhZCBpbiBib3RoIFRTViBmaWxlcyBhbmQgYWRkIHRoZW0gYXMgZGF0YSBmcmFtZXMgdG8geW91ciBlbnZpcm9ubWVudC4KCmBgYHtyfQojIFJlYWQgaW4gbWV0YWRhdGEgVFNWIGZpbGUKbWV0YWRhdGEgPC0gcmVhZHI6OnJlYWRfdHN2KG1ldGFkYXRhX2ZpbGUpCgojIFJlYWQgaW4gZGF0YSBUU1YgZmlsZQpleHByZXNzaW9uX2RmIDwtIHJlYWRyOjpyZWFkX3RzdihkYXRhX2ZpbGUpICU+JQogICMgSGVyZSB3ZSBhcmUgZ29pbmcgdG8gc3RvcmUgdGhlIGdlbmUgSURzIGFzIHJvdyBuYW1lcyBzbyB0aGF0CiAgIyB3ZSBjYW4gaGF2ZSBvbmx5IG51bWVyaWMgdmFsdWVzIHRvIHBlcmZvcm0gY2FsY3VsYXRpb25zIG9uIGxhdGVyCiAgdGliYmxlOjpjb2x1bW5fdG9fcm93bmFtZXMoIkdlbmUiKQpgYGAKCkxldCdzIHRha2UgYSBsb29rIGF0IHRoZSBtZXRhZGF0YSBvYmplY3QgdGhhdCB3ZSByZWFkIGludG8gdGhlIFIgZW52aXJvbm1lbnQuCgpgYGB7cn0KaGVhZChtZXRhZGF0YSkKYGBgCgpOb3cgbGV0J3MgZW5zdXJlIHRoYXQgdGhlIG1ldGFkYXRhIGFuZCBkYXRhIGFyZSBpbiB0aGUgc2FtZSBzYW1wbGUgb3JkZXIuCgpgYGB7cn0KIyBNYWtlIHRoZSBkYXRhIGluIHRoZSBvcmRlciBvZiB0aGUgbWV0YWRhdGEKZXhwcmVzc2lvbl9kZiA8LSBleHByZXNzaW9uX2RmICU+JQogIGRwbHlyOjpzZWxlY3QobWV0YWRhdGEkcmVmaW5lYmlvX2FjY2Vzc2lvbl9jb2RlKQoKIyBDaGVjayBpZiB0aGlzIGlzIGluIHRoZSBzYW1lIG9yZGVyCmFsbC5lcXVhbChjb2xuYW1lcyhleHByZXNzaW9uX2RmKSwgbWV0YWRhdGEkcmVmaW5lYmlvX2FjY2Vzc2lvbl9jb2RlKQpgYGAKCk5vdyB3ZSBhcmUgZ29pbmcgdG8gdXNlIHRoZSBgcGhlYXRtYXBgIHBhY2thZ2UgdG8gbG9vayBhdCBob3cgYXJlIHNhbXBsZXMgYW5kIGdlbmVzIGFyZSBjbHVzdGVyaW5nLgoKIyMgQ2hvb3NlIGdlbmVzIG9mIGludGVyZXN0CgpGb3IgdGhpcyBleGFtcGxlLCB3ZSB3aWxsIHNvcnQgZ2VuZXMgYnkgdmFyaWFuY2UgYW5kIHNlbGVjdCBnZW5lcyBpbiB0aGUgdXBwZXIgcXVhcnRpbGUsIGJ1dCB0aGVyZSBhcmUgbWFueSBhbHRlcm5hdGl2ZSBjcml0ZXJpb24gYnkgd2hpY2ggeW91IG1heSB3YW50IHRvIHNvcnQgeW91ciBnZW5lcywgPGk+ZS5nLjwvaT4gZm9sZCBjaGFuZ2UsIHQtc3RhdGlzdGljLCBtZW1iZXJzaGlwIGluIGEgcGFydGljdWxhciBnZW5lIG9udG9sb2d5LCBzbyBvbi4KCmBgYHtyfQojIENhbGN1bGF0ZSB0aGUgdmFyaWFuY2UgZm9yIGVhY2ggZ2VuZQp2YXJpYW5jZXMgPC0gYXBwbHkoZXhwcmVzc2lvbl9kZiwgMSwgdmFyKQoKIyBEZXRlcm1pbmUgdGhlIHVwcGVyIHF1YXJ0aWxlIHZhcmlhbmNlIGN1dG9mZiB2YWx1ZQp1cHBlcl92YXIgPC0gcXVhbnRpbGUodmFyaWFuY2VzLCAwLjc1KQoKIyBGaWx0ZXIgdGhlIGRhdGEgY2hvb3Npbmcgb25seSBnZW5lcyB3aG9zZSB2YXJpYW5jZXMgYXJlIGluIHRoZSB1cHBlciBxdWFydGlsZQpkZl9ieV92YXIgPC0gZGF0YS5mcmFtZShleHByZXNzaW9uX2RmKSAlPiUKICBkcGx5cjo6ZmlsdGVyKHZhcmlhbmNlcyA+IHVwcGVyX3ZhcikKYGBgCgpMZXQncyBzYXZlIHRoZXNlIHRvIG91ciByZXN1bHRzIGZvbGRlciBhcyBhIFRTViBmaWxlLiAKCmBgYHtyfQpyZWFkcjo6d3JpdGVfdHN2KGRmX2J5X3ZhciwgZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCAidG9wXzkwX3Zhcl9nZW5lcy50c3YiKSkKYGBgCgojIyBQcmVwYXJlIG1ldGFkYXRhIGZvciBhbm5vdGF0aW9uCgpGcm9tIHRoZSBhY2NvbXBhbnlpbmcgW3BhcGVyXShodHRwczovL3B1Ym1lZC5uY2JpLm5sbS5uaWguZ292LzI4MTkzNzc5LyksIHdlIGtub3cgdGhhdCB0aGUgbWljZSB3aXRoIGBJREgyYCBtdXRhbnQgQU1MIHdlcmUgdHJlYXRlZCB3aXRoIHZlaGljbGUgb3IgQUctMjIxICh0aGUgZmlyc3Qgc21hbGwgbW9sZWN1bGUgaW4tdml2byBpbmhpYml0b3Igb2YgSURIMiB0byBlbnRlciBjbGluaWNhbCB0cmlhbHMpIGFuZCB0aGUgbWljZSB3aXRoIGBURVQyYCBtdXRhbnQgQU1MIHdlcmUgdHJlYXRlZCB3aXRoIHZlaGljbGUgb3IgNS1BemFjeXRpZGluZSAoRGVjaXRhYmluZSwgaHlwb21ldGh5bGF0aW5nIGFnZW50KS4gW0BTaGloMjAxN10KCmBgYHtyfQojIExldCdzIHByZXBhcmUgdGhlIGFubm90YXRpb24gZm9yIHRoZSB1bmNvbGxhcHNlZCBgREVTZXFEYXRhYCBzZXQgb2JqZWN0CiMgd2hpY2ggd2lsbCBiZSB1c2VkIHRvIGFubm90YXRlIHRoZSBoZWF0bWFwCmFubm90YXRpb25fZGYgPC0gbWV0YWRhdGEgJT4lCiAgIyBDcmVhdGUgYSB2YXJpYWJsZSB0byBzdG9yZSB0aGUgY2FuY2VyIHR5cGUgaW5mb3JtYXRpb24KICBkcGx5cjo6bXV0YXRlKAogICAgbXV0YXRpb24gPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICBzdGFydHNXaXRoKHJlZmluZWJpb190aXRsZSwgIlRFVDIiKSB+ICJURVQyIiwKICAgICAgc3RhcnRzV2l0aChyZWZpbmViaW9fdGl0bGUsICJJREgyIikgfiAiSURIMiIsCiAgICAgIHN0YXJ0c1dpdGgocmVmaW5lYmlvX3RpdGxlLCAiV1QiKSB+ICJXVCIsCiAgICAgICMgSWYgbm9uZSBvZiB0aGUgYWJvdmUgY3JpdGVyaWEgYXJlIHNhdGlzZmllZCwKICAgICAgIyB3ZSBtYXJrIHRoZSBgbXV0YXRpb25gIHZhcmlhYmxlIGFzICJ1bmtub3duIgogICAgICBUUlVFIH4gInVua25vd24iCiAgICApCiAgKSAlPiUKICAjIHNlbGVjdCBvbmx5IHRoZSBjb2x1bW5zIHdlIG5lZWQgZm9yIGFubm90YXRpb24KICBkcGx5cjo6c2VsZWN0KAogICAgcmVmaW5lYmlvX2FjY2Vzc2lvbl9jb2RlLAogICAgbXV0YXRpb24sCiAgICByZWZpbmViaW9fdHJlYXRtZW50CiAgKSAlPiUKICAjIFRoZSBgcGhlYXRtYXAoKWAgZnVuY3Rpb24gcmVxdWlyZXMgdGhhdCB0aGUgcm93IG5hbWVzIG9mIG91ciBhbm5vdGF0aW9uCiAgIyBkYXRhIGZyYW1lIG1hdGNoIHRoZSBjb2x1bW4gbmFtZXMgb2Ygb3VyIGBERVNlYURhdGFTZXRgIG9iamVjdAogIHRpYmJsZTo6Y29sdW1uX3RvX3Jvd25hbWVzKCJyZWZpbmViaW9fYWNjZXNzaW9uX2NvZGUiKQpgYGAKCiMjIyBDcmVhdGUgYW5ub3RhdGVkIGhlYXRtYXAKCmBgYHtyfQojIENyZWF0ZSBhbmQgc3RvcmUgdGhlIGFubm90YXRlZCBoZWF0bWFwIG9iamVjdApoZWF0bWFwX2Fubm90YXRlZCA8LQogIHBoZWF0bWFwKAogICAgZGZfYnlfdmFyLAogICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICBzaG93X3Jvd25hbWVzID0gRkFMU0UsCiAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm90YXRpb25fZGYsICMgU3BlY2lmeSBvdXIgYW5ub3RhdGlvbiBoZXJlCiAgICBtYWluID0gIkFubm90YXRlZCBIZWF0bWFwIiwKICAgIGNvbG9yUmFtcFBhbGV0dGUoYygKICAgICAgImRlZXBza3libHVlIiwKICAgICAgImJsYWNrIiwKICAgICAgInllbGxvdyIKICAgICkpKDI1CiAgICApLAogICAgc2NhbGUgPSAicm93IiAjIFNjYWxlIHZhbHVlcyBpbiB0aGUgZGlyZWN0aW9uIG9mIGdlbmVzIChyb3dzKQogICkKYGBgCiMjIyBTYXZlIGFubm90YXRlZCBoZWF0bWFwIGFzIGEgUE5HCgpZb3UgY2FuIHN3aXRjaCB0aGlzIHRvIHNhdmUgdG8gYSBKUEVHIG9yIFRJRkYgYnkgY2hhbmdpbmcgdGhlIGZ1bmN0aW9uIGFuZCBmaWxlIG5hbWUgd2l0aGluIHRoZSBmdW5jdGlvbiB0byB0aGUgcmVzcGVjdGl2ZSBmaWxlIHN1ZmZpeC4KCmBgYHtyfQojIE9wZW4gYSBQTkcgZmlsZQpwbmcoZmlsZS5wYXRoKAogIHBsb3RzX2RpciwKICAiYW1sX2hlYXRtYXAucG5nIiAjIFJlcGxhY2Ugd2l0aCBhIHJlbGV2YW50IGZpbGUgbmFtZQopKQoKIyBQcmludCB0aGUgaGVhdG1hcApoZWF0bWFwX2Fubm90YXRlZAoKIyBDbG9zZSB0aGUgUE5HIGZpbGU6CmRldi5vZmYoKQpgYGAKCiMgU2Vzc2lvbiBpbmZvCgpgYGB7cn0KIyBQcmludCBzZXNzaW9uIGluZm8Kc2Vzc2lvbmluZm86OnNlc3Npb25faW5mbygpCmBgYAo=