Introduction

AncientMetagenomeDir is a repository listing published ancient metagenome (and related) samples. It contains critical metadata for ancient metagenome studies, and acts as a ‘sign post’ towards important data to help facilitate more robust and efficient comparative data.

This page provides summary statistics of the current status of the directory.

Libraries and Versions

library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ ggplot2 3.3.2     ✓ purrr   0.3.4
✓ tibble  3.0.3     ✓ dplyr   1.0.2
✓ tidyr   1.1.2     ✓ stringr 1.4.0
✓ readr   1.3.1     ✓ forcats 0.5.0
── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(scales)

Attaching package: ‘scales’

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

    discard

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

    col_factor
library(lubridate)

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
library(maps)

Attaching package: ‘maps’

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

    map
library(patchwork)
sessionInfo()
R version 3.6.3 (2020-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.1 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0

locale:
 [1] LC_CTYPE=en_GB.UTF-8       LC_NUMERIC=C               LC_TIME=en_GB.UTF-8        LC_COLLATE=en_GB.UTF-8     LC_MONETARY=en_GB.UTF-8   
 [6] LC_MESSAGES=en_GB.UTF-8    LC_PAPER=en_GB.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C       

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

other attached packages:
 [1] patchwork_1.0.1 maps_3.3.0      lubridate_1.7.9 scales_1.1.1    forcats_0.5.0   stringr_1.4.0   dplyr_1.0.2     purrr_0.3.4    
 [9] readr_1.3.1     tidyr_1.1.2     tibble_3.0.3    ggplot2_3.3.2   tidyverse_1.3.0

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.5       cellranger_1.1.0 pillar_1.4.6     compiler_3.6.3   dbplyr_1.4.4     tools_3.6.3      jsonlite_1.7.0   lifecycle_0.2.0 
 [9] gtable_0.3.0     pkgconfig_2.0.3  rlang_0.4.7      reprex_0.3.0     cli_2.0.2        DBI_1.1.0        rstudioapi_0.11  haven_2.3.1     
[17] xfun_0.16        withr_2.2.0      xml2_1.3.2       httr_1.4.2       knitr_1.29       fs_1.5.0         generics_0.0.2   vctrs_0.3.4     
[25] hms_0.5.3        grid_3.6.3       tidyselect_1.1.0 glue_1.4.2       R6_2.4.1         fansi_0.4.1      readxl_1.3.1     modelr_0.1.8    
[33] blob_1.2.1       magrittr_1.5     backports_1.1.9  ellipsis_0.3.1   rvest_0.3.6      assertthat_0.2.1 colorspace_1.4-1 stringi_1.4.6   
[41] munsell_0.5.0    broom_0.7.0      crayon_1.3.4    

Preparation

Functions

We will prepare some custom functions

Loading

## Load and standardise date across tables
load_thedir_data <- function(path, name) {
  read_tsv(path, col_types = cols()) %>%
    mutate(List = name) %>%
    select(List, everything())
}

Publication Timeline


stats_pub_timeline <- function(...) {
  x <- list(...)

  ## Get only relevent columns
  lapply(x, FUN = function(y) {
    select(
      y,
      List, publication_doi,
      publication_year
    ) %>% distinct()
  }) %>%
    bind_rows() %>%
    mutate(List = factor(List, levels = names(colours)))
}

plot_pub_timeline <- function(dat) {
  ## Get range so we plot x-axis nicely
  spanning_years <- dat %>% summarise(min = min(publication_year), max = max(publication_year))

  ggplot(dat, aes(publication_year, fill = List)) +
    scale_fill_manual(values = colours, guide = guide_legend(ncol = 1)) +
    scale_y_continuous(labels = scales::number_format(accuracy = 1)) +
    ylab("Number of publications") +
    xlab("Publication year") +
    geom_bar(bins = spanning_years$max - spanning_years$min, binwidth = 1) +
    scale_x_continuous(breaks = seq(spanning_years$min, spanning_years$max, 2)) +
    theme_classic() +
    theme(legend.position = "bottom") +
    facet_wrap(~List, ncol = 1) +
    labs(fill = NULL)
}

Cumulative Samples Timeline

stats_cumulative_timeline <- function(...) {
  ## Takes a list of AncientMetagenomeDir TSVs
  x <- list(...)

  ## Get only relevent columns
  dat <- lapply(x, FUN = function(y) {
    select(
      y,
      List, sample_name, publication_year,
      publication_year
    ) %>% distinct()
  }) %>%
    bind_rows() %>%
    mutate(List = factor(List, levels = names(colours)))

  spanning_years <- dat %>%
    ungroup() %>%
    summarise(min = min(publication_year), max = max(publication_year))

  ## Make fake base table to ensure all years for all lists
  ## Currently manually defined
  base_table <- list(
    seq(spanning_years$min, spanning_years$max, 1),
    seq(spanning_years$min, spanning_years$max, 1),
    seq(spanning_years$min, spanning_years$max, 1)
  )

  names(base_table) <- levels(dat$List)

  base_table <- base_table %>%
    enframe(name = "List", value = "publication_year") %>%
    unnest(publication_year)

  dat <- dat %>%
    group_by(List, publication_year) %>%
    summarise(count = n())

  dat %>%
    right_join(base_table, by = c("List", "publication_year")) %>%
    replace_na(list(count = 0)) %>%
    arrange(List, publication_year) %>%
    mutate(List = factor(List, levels = names(colours))) %>%
    group_by(List) %>%
    mutate(cumulative_sum = cumsum(count))
}


plot_cumulative_timeline <- function(x) {
  
  spanning_years <- list(min_year = min(x$publication_year), max_year = max(x$publication_year))

  ## Get range so we plot x-axis nicely
  ggplot(x, aes(publication_year, cumulative_sum, fill = List)) +
    geom_bar(stat = "identity") +
    scale_y_continuous(labels = scales::number_format(accuracy = 1)) +
    scale_x_continuous(breaks = seq(spanning_years$min_year, spanning_years$max_year, 2)) +
    theme_classic() +
    xlab("Publication year") +
    ylab("Number of samples (cumulative sum)") +
    scale_fill_manual(values = colours, guide = guide_legend(ncol = 1)) +
    theme(legend.position = "bottom") +
    facet_wrap(~List, ncol = 1) +
    labs(fill = NULL)
  
}

Map

stats_map <- function(...){

x <- list(raw_environmental, raw_hostmetagenome, raw_hostsinglegenome)

dat <- lapply(x, FUN = function(y) {
  select(
    y,
    List, sample_name, geo_loc_name, latitude, longitude,
    publication_year
  ) %>% distinct()
}) %>%
  bind_rows() %>%
  mutate(List = factor(List, levels = names(colours)))

dat <- dat %>%
  group_by(List, geo_loc_name, latitude, longitude) %>%
  summarise(count = n()) %>%
  mutate(List = factor(List, levels = names(colours)))
}


plot_map <- function(dat){
  
  world_map <- map_data("world")
  
  ggplot() +
    geom_polygon(data = world_map, aes(x = long, y = lat, group = group), fill = "white", colour = "grey") +
    geom_point(data = dat, aes(x = longitude, y = latitude, fill = List, size = count), shape = 21, alpha = 0.5) +
    scale_fill_brewer(palette ="Set1") +
    theme_linedraw() +
    facet_wrap(~List, ncol = 1) +
    theme_classic() +
    scale_fill_manual(values = colours, guide = guide_legend(ncol = 1)) +
    theme(legend.position = "bottom", legend.direction="vertical") +
    labs(fill = "Sample Type", size = "Sample Count") +
    xlab("Longitude") +
    ylab("Latitude")
  
}

Data Loading

We will load and analyse each list separately, as they contain slightly different metadata depending on context.

raw_hostmetagenome <- load_thedir_data("../../ancientmetagenome-hostassociated/ancientmetagenome-hostassociated.tsv", "Host Associated Metagenome") 
raw_hostsinglegenome <- load_thedir_data("../../ancientsinglegenome-hostassociated/ancientsinglegenome-hostassociated.tsv", "Host Associated Single Genome") 
raw_environmental <- load_thedir_data("../../ancientmetagenome-environmental/ancientmetagenome-environmental.tsv", "Environmental Metagenome") 
#raw_anthropogenic <- load_thedir_data("../../ancientmetagenome-anthropogenic/ancientmetagenome-anthropogenic.tsv", "Anthropogenic Metagenome") 

Design Assets

colours <- c(`Host Associated Metagenome` = "#73cff3",
            `Host Associated Single Genome` = "#d74182",
            `Environmental Metagenome` = "#2da46a")

notused_colours <- c(`Anthropogenic Metagenome` = "#d74182")

Publication Timelines

figure_publication_time <- stats_pub_timeline(raw_hostmetagenome, raw_hostsinglegenome, raw_environmental) %>% plot_pub_timeline()
Ignoring unknown parameters: bins, binwidth
figure_publication_time

Summary stats

stats_pub_timeline(raw_hostmetagenome, raw_hostsinglegenome, raw_environmental) %>% 
  select(publication_doi) %>% 
  arrange %>% 
  distinct %>% 
  summarise(n = n())

Cumulative Samples


figure_cumulative_samples <- stats_cumulative_timeline(raw_hostmetagenome, raw_hostsinglegenome, raw_environmental) %>% plot_cumulative_timeline()
`summarise()` regrouping output by 'List' (override with `.groups` argument)
figure_cumulative_samples

Summary stats

stats_cumulative_timeline(raw_hostmetagenome, raw_hostsinglegenome, raw_environmental) %>%
  group_by(List) %>%
  summarise(total = sum(count))
`summarise()` regrouping output by 'List' (override with `.groups` argument)
`summarise()` ungrouping output (override with `.groups` argument)

Timelines Combined

figure_timelines <- figure_publication_time + figure_cumulative_samples + plot_layout(ncol = 2) + plot_annotation(tag_levels = 'a')

figure_timelines

ggsave("AncientMetagenomeDir-PublicationSample_Timeline.pdf",
       figure_timelines,
       device = cairo_pdf(),
       units = "in",
       width = 3.5,
       height = 4,
       scale = 2
       )


ggsave("AncientMetagenomeDir-PublicationSample_Timeline.png",
       figure_timelines,
       device = "png",
       units = "in",
       width = 3.5,
       height = 4,
       scale = 2
       )

Geographic Spread

With known coordinates!

figure_map <- stats_map(raw_hostmetagenome, raw_hostsinglegenome, raw_environmental) %>% plot_map
`summarise()` regrouping output by 'List', 'geo_loc_name', 'latitude' (override with `.groups` argument)
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale.
figure_map

ggsave("AncientMetagenomeDir-Sample_Map.pdf",
       figure_map,
       device = cairo_pdf(),
       units = "in",
       width = 1,
       height = 2,
       scale = 4
       )

ggsave("AncientMetagenomeDir-Sample_Map.png",
       figure_map,
       device = "png",
       units = "in",
       width = 1,
       height = 2,
       scale = 4
       )

How many countries does this cover?

stats_map(raw_hostmetagenome, raw_hostsinglegenome, raw_environmental) %>% 
  ungroup() %>%
  select(geo_loc_name) %>% 
  distinct() %>% 
  summarise(n = n())
`summarise()` regrouping output by 'List', 'geo_loc_name', 'latitude' (override with `.groups` argument)
LS0tCnRpdGxlOiAiQW5jaWVudE1ldGFnZW5vbWVEaXIgLSBBbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBJbnRyb2R1Y3Rpb24KCkFuY2llbnRNZXRhZ2Vub21lRGlyIGlzIGEgcmVwb3NpdG9yeSBsaXN0aW5nIHB1Ymxpc2hlZCBhbmNpZW50IG1ldGFnZW5vbWUgKGFuZCAKcmVsYXRlZCkgc2FtcGxlcy4gSXQgY29udGFpbnMgY3JpdGljYWwgbWV0YWRhdGEgZm9yIGFuY2llbnQgbWV0YWdlbm9tZSBzdHVkaWVzLCAKYW5kIGFjdHMgYXMgYSAnc2lnbiBwb3N0JyB0b3dhcmRzIGltcG9ydGFudCBkYXRhIHRvIGhlbHAgZmFjaWxpdGF0ZSBtb3JlIHJvYnVzdAphbmQgZWZmaWNpZW50IGNvbXBhcmF0aXZlIGRhdGEuCgpUaGlzIHBhZ2UgcHJvdmlkZXMgc3VtbWFyeSBzdGF0aXN0aWNzIG9mIHRoZSBjdXJyZW50IHN0YXR1cyBvZiB0aGUgZGlyZWN0b3J5LgoKIyBMaWJyYXJpZXMgYW5kIFZlcnNpb25zCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShtYXBzKQpsaWJyYXJ5KHBhdGNod29yaykKc2Vzc2lvbkluZm8oKQpgYGAKCiMgUHJlcGFyYXRpb24KCiMjIEZ1bmN0aW9ucwoKV2Ugd2lsbCBwcmVwYXJlIHNvbWUgY3VzdG9tIGZ1bmN0aW9ucwoKCiMjIyBMb2FkaW5nCgpgYGB7cn0KIyMgTG9hZCBhbmQgc3RhbmRhcmRpc2UgZGF0ZSBhY3Jvc3MgdGFibGVzCmxvYWRfdGhlZGlyX2RhdGEgPC0gZnVuY3Rpb24ocGF0aCwgbmFtZSkgewogIHJlYWRfdHN2KHBhdGgsIGNvbF90eXBlcyA9IGNvbHMoKSkgJT4lCiAgICBtdXRhdGUoTGlzdCA9IG5hbWUpICU+JQogICAgc2VsZWN0KExpc3QsIGV2ZXJ5dGhpbmcoKSkKfQoKYGBgCgojIyMgUHVibGljYXRpb24gVGltZWxpbmUKCmBgYHtyfQoKc3RhdHNfcHViX3RpbWVsaW5lIDwtIGZ1bmN0aW9uKC4uLikgewogIHggPC0gbGlzdCguLi4pCgogICMjIEdldCBvbmx5IHJlbGV2ZW50IGNvbHVtbnMKICBsYXBwbHkoeCwgRlVOID0gZnVuY3Rpb24oeSkgewogICAgc2VsZWN0KAogICAgICB5LAogICAgICBMaXN0LCBwdWJsaWNhdGlvbl9kb2ksCiAgICAgIHB1YmxpY2F0aW9uX3llYXIKICAgICkgJT4lIGRpc3RpbmN0KCkKICB9KSAlPiUKICAgIGJpbmRfcm93cygpICU+JQogICAgbXV0YXRlKExpc3QgPSBmYWN0b3IoTGlzdCwgbGV2ZWxzID0gbmFtZXMoY29sb3VycykpKQp9CgpwbG90X3B1Yl90aW1lbGluZSA8LSBmdW5jdGlvbihkYXQpIHsKICAjIyBHZXQgcmFuZ2Ugc28gd2UgcGxvdCB4LWF4aXMgbmljZWx5CiAgc3Bhbm5pbmdfeWVhcnMgPC0gZGF0ICU+JSBzdW1tYXJpc2UobWluID0gbWluKHB1YmxpY2F0aW9uX3llYXIpLCBtYXggPSBtYXgocHVibGljYXRpb25feWVhcikpCgogIGdncGxvdChkYXQsIGFlcyhwdWJsaWNhdGlvbl95ZWFyLCBmaWxsID0gTGlzdCkpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG91cnMsIGd1aWRlID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAxKSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgICB5bGFiKCJOdW1iZXIgb2YgcHVibGljYXRpb25zIikgKwogICAgeGxhYigiUHVibGljYXRpb24geWVhciIpICsKICAgIGdlb21fYmFyKGJpbnMgPSBzcGFubmluZ195ZWFycyRtYXggLSBzcGFubmluZ195ZWFycyRtaW4sIGJpbndpZHRoID0gMSkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcShzcGFubmluZ195ZWFycyRtaW4sIHNwYW5uaW5nX3llYXJzJG1heCwgMikpICsKICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgZmFjZXRfd3JhcCh+TGlzdCwgbmNvbCA9IDEpICsKICAgIGxhYnMoZmlsbCA9IE5VTEwpCn0KYGBgCgojIyMgQ3VtdWxhdGl2ZSBTYW1wbGVzIFRpbWVsaW5lCgpgYGB7cn0Kc3RhdHNfY3VtdWxhdGl2ZV90aW1lbGluZSA8LSBmdW5jdGlvbiguLi4pIHsKICAjIyBUYWtlcyBhIGxpc3Qgb2YgQW5jaWVudE1ldGFnZW5vbWVEaXIgVFNWcwogIHggPC0gbGlzdCguLi4pCgogICMjIEdldCBvbmx5IHJlbGV2ZW50IGNvbHVtbnMKICBkYXQgPC0gbGFwcGx5KHgsIEZVTiA9IGZ1bmN0aW9uKHkpIHsKICAgIHNlbGVjdCgKICAgICAgeSwKICAgICAgTGlzdCwgc2FtcGxlX25hbWUsIHB1YmxpY2F0aW9uX3llYXIsCiAgICAgIHB1YmxpY2F0aW9uX3llYXIKICAgICkgJT4lIGRpc3RpbmN0KCkKICB9KSAlPiUKICAgIGJpbmRfcm93cygpICU+JQogICAgbXV0YXRlKExpc3QgPSBmYWN0b3IoTGlzdCwgbGV2ZWxzID0gbmFtZXMoY29sb3VycykpKQoKICBzcGFubmluZ195ZWFycyA8LSBkYXQgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBzdW1tYXJpc2UobWluID0gbWluKHB1YmxpY2F0aW9uX3llYXIpLCBtYXggPSBtYXgocHVibGljYXRpb25feWVhcikpCgogICMjIE1ha2UgZmFrZSBiYXNlIHRhYmxlIHRvIGVuc3VyZSBhbGwgeWVhcnMgZm9yIGFsbCBsaXN0cwogICMjIEN1cnJlbnRseSBtYW51YWxseSBkZWZpbmVkCiAgYmFzZV90YWJsZSA8LSBsaXN0KAogICAgc2VxKHNwYW5uaW5nX3llYXJzJG1pbiwgc3Bhbm5pbmdfeWVhcnMkbWF4LCAxKSwKICAgIHNlcShzcGFubmluZ195ZWFycyRtaW4sIHNwYW5uaW5nX3llYXJzJG1heCwgMSksCiAgICBzZXEoc3Bhbm5pbmdfeWVhcnMkbWluLCBzcGFubmluZ195ZWFycyRtYXgsIDEpCiAgKQoKICBuYW1lcyhiYXNlX3RhYmxlKSA8LSBsZXZlbHMoZGF0JExpc3QpCgogIGJhc2VfdGFibGUgPC0gYmFzZV90YWJsZSAlPiUKICAgIGVuZnJhbWUobmFtZSA9ICJMaXN0IiwgdmFsdWUgPSAicHVibGljYXRpb25feWVhciIpICU+JQogICAgdW5uZXN0KHB1YmxpY2F0aW9uX3llYXIpCgogIGRhdCA8LSBkYXQgJT4lCiAgICBncm91cF9ieShMaXN0LCBwdWJsaWNhdGlvbl95ZWFyKSAlPiUKICAgIHN1bW1hcmlzZShjb3VudCA9IG4oKSkKCiAgZGF0ICU+JQogICAgcmlnaHRfam9pbihiYXNlX3RhYmxlLCBieSA9IGMoIkxpc3QiLCAicHVibGljYXRpb25feWVhciIpKSAlPiUKICAgIHJlcGxhY2VfbmEobGlzdChjb3VudCA9IDApKSAlPiUKICAgIGFycmFuZ2UoTGlzdCwgcHVibGljYXRpb25feWVhcikgJT4lCiAgICBtdXRhdGUoTGlzdCA9IGZhY3RvcihMaXN0LCBsZXZlbHMgPSBuYW1lcyhjb2xvdXJzKSkpICU+JQogICAgZ3JvdXBfYnkoTGlzdCkgJT4lCiAgICBtdXRhdGUoY3VtdWxhdGl2ZV9zdW0gPSBjdW1zdW0oY291bnQpKQp9CgoKcGxvdF9jdW11bGF0aXZlX3RpbWVsaW5lIDwtIGZ1bmN0aW9uKHgpIHsKICAKICBzcGFubmluZ195ZWFycyA8LSBsaXN0KG1pbl95ZWFyID0gbWluKHgkcHVibGljYXRpb25feWVhciksIG1heF95ZWFyID0gbWF4KHgkcHVibGljYXRpb25feWVhcikpCgogICMjIEdldCByYW5nZSBzbyB3ZSBwbG90IHgtYXhpcyBuaWNlbHkKICBnZ3Bsb3QoeCwgYWVzKHB1YmxpY2F0aW9uX3llYXIsIGN1bXVsYXRpdmVfc3VtLCBmaWxsID0gTGlzdCkpICsKICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoc3Bhbm5pbmdfeWVhcnMkbWluX3llYXIsIHNwYW5uaW5nX3llYXJzJG1heF95ZWFyLCAyKSkgKwogICAgdGhlbWVfY2xhc3NpYygpICsKICAgIHhsYWIoIlB1YmxpY2F0aW9uIHllYXIiKSArCiAgICB5bGFiKCJOdW1iZXIgb2Ygc2FtcGxlcyAoY3VtdWxhdGl2ZSBzdW0pIikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3VycywgZ3VpZGUgPSBndWlkZV9sZWdlbmQobmNvbCA9IDEpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogICAgZmFjZXRfd3JhcCh+TGlzdCwgbmNvbCA9IDEpICsKICAgIGxhYnMoZmlsbCA9IE5VTEwpCiAgCn0KCgpgYGAKCiMjIyBNYXAKCmBgYHtyfQpzdGF0c19tYXAgPC0gZnVuY3Rpb24oLi4uKXsKCnggPC0gbGlzdChyYXdfZW52aXJvbm1lbnRhbCwgcmF3X2hvc3RtZXRhZ2Vub21lLCByYXdfaG9zdHNpbmdsZWdlbm9tZSkKCmRhdCA8LSBsYXBwbHkoeCwgRlVOID0gZnVuY3Rpb24oeSkgewogIHNlbGVjdCgKICAgIHksCiAgICBMaXN0LCBzYW1wbGVfbmFtZSwgZ2VvX2xvY19uYW1lLCBsYXRpdHVkZSwgbG9uZ2l0dWRlLAogICAgcHVibGljYXRpb25feWVhcgogICkgJT4lIGRpc3RpbmN0KCkKfSkgJT4lCiAgYmluZF9yb3dzKCkgJT4lCiAgbXV0YXRlKExpc3QgPSBmYWN0b3IoTGlzdCwgbGV2ZWxzID0gbmFtZXMoY29sb3VycykpKQoKZGF0IDwtIGRhdCAlPiUKICBncm91cF9ieShMaXN0LCBnZW9fbG9jX25hbWUsIGxhdGl0dWRlLCBsb25naXR1ZGUpICU+JQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lCiAgbXV0YXRlKExpc3QgPSBmYWN0b3IoTGlzdCwgbGV2ZWxzID0gbmFtZXMoY29sb3VycykpKQp9CgoKcGxvdF9tYXAgPC0gZnVuY3Rpb24oZGF0KXsKICAKICB3b3JsZF9tYXAgPC0gbWFwX2RhdGEoIndvcmxkIikKICAKICBnZ3Bsb3QoKSArCiAgICBnZW9tX3BvbHlnb24oZGF0YSA9IHdvcmxkX21hcCwgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwKSwgZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9ICJncmV5IikgKwogICAgZ2VvbV9wb2ludChkYXRhID0gZGF0LCBhZXMoeCA9IGxvbmdpdHVkZSwgeSA9IGxhdGl0dWRlLCBmaWxsID0gTGlzdCwgc2l6ZSA9IGNvdW50KSwgc2hhcGUgPSAyMSwgYWxwaGEgPSAwLjUpICsKICAgIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSJTZXQxIikgKwogICAgdGhlbWVfbGluZWRyYXcoKSArCiAgICBmYWNldF93cmFwKH5MaXN0LCBuY29sID0gMSkgKwogICAgdGhlbWVfY2xhc3NpYygpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG91cnMsIGd1aWRlID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAxKSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb249InZlcnRpY2FsIikgKwogICAgbGFicyhmaWxsID0gIlNhbXBsZSBUeXBlIiwgc2l6ZSA9ICJTYW1wbGUgQ291bnQiKSArCiAgICB4bGFiKCJMb25naXR1ZGUiKSArCiAgICB5bGFiKCJMYXRpdHVkZSIpCiAgCn0KYGBgCgoKIyMgRGF0YSBMb2FkaW5nCgpXZSB3aWxsIGxvYWQgYW5kIGFuYWx5c2UgZWFjaCBsaXN0IHNlcGFyYXRlbHksIGFzIHRoZXkgY29udGFpbiBzbGlnaHRseSBkaWZmZXJlbnQKbWV0YWRhdGEgZGVwZW5kaW5nIG9uIGNvbnRleHQuCgpgYGB7cn0KcmF3X2hvc3RtZXRhZ2Vub21lIDwtIGxvYWRfdGhlZGlyX2RhdGEoIi4uLy4uL2FuY2llbnRtZXRhZ2Vub21lLWhvc3Rhc3NvY2lhdGVkL2FuY2llbnRtZXRhZ2Vub21lLWhvc3Rhc3NvY2lhdGVkLnRzdiIsICJIb3N0IEFzc29jaWF0ZWQgTWV0YWdlbm9tZSIpIApyYXdfaG9zdHNpbmdsZWdlbm9tZSA8LSBsb2FkX3RoZWRpcl9kYXRhKCIuLi8uLi9hbmNpZW50c2luZ2xlZ2Vub21lLWhvc3Rhc3NvY2lhdGVkL2FuY2llbnRzaW5nbGVnZW5vbWUtaG9zdGFzc29jaWF0ZWQudHN2IiwgIkhvc3QgQXNzb2NpYXRlZCBTaW5nbGUgR2Vub21lIikgCnJhd19lbnZpcm9ubWVudGFsIDwtIGxvYWRfdGhlZGlyX2RhdGEoIi4uLy4uL2FuY2llbnRtZXRhZ2Vub21lLWVudmlyb25tZW50YWwvYW5jaWVudG1ldGFnZW5vbWUtZW52aXJvbm1lbnRhbC50c3YiLCAiRW52aXJvbm1lbnRhbCBNZXRhZ2Vub21lIikgCiNyYXdfYW50aHJvcG9nZW5pYyA8LSBsb2FkX3RoZWRpcl9kYXRhKCIuLi8uLi9hbmNpZW50bWV0YWdlbm9tZS1hbnRocm9wb2dlbmljL2FuY2llbnRtZXRhZ2Vub21lLWFudGhyb3BvZ2VuaWMudHN2IiwgIkFudGhyb3BvZ2VuaWMgTWV0YWdlbm9tZSIpIApgYGAKCiMjIERlc2lnbiBBc3NldHMKCmBgYHtyfQpjb2xvdXJzIDwtIGMoYEhvc3QgQXNzb2NpYXRlZCBNZXRhZ2Vub21lYCA9ICIjNzNjZmYzIiwKICAgICAgICAgICAgYEhvc3QgQXNzb2NpYXRlZCBTaW5nbGUgR2Vub21lYCA9ICIjZDc0MTgyIiwKICAgICAgICAgICAgYEVudmlyb25tZW50YWwgTWV0YWdlbm9tZWAgPSAiIzJkYTQ2YSIpCgpub3R1c2VkX2NvbG91cnMgPC0gYyhgQW50aHJvcG9nZW5pYyBNZXRhZ2Vub21lYCA9ICIjZDc0MTgyIikKCmBgYAoKCiMgUHVibGljYXRpb24gVGltZWxpbmVzCgpgYGB7ciwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9N30KZmlndXJlX3B1YmxpY2F0aW9uX3RpbWUgPC0gc3RhdHNfcHViX3RpbWVsaW5lKHJhd19ob3N0bWV0YWdlbm9tZSwgcmF3X2hvc3RzaW5nbGVnZW5vbWUsIHJhd19lbnZpcm9ubWVudGFsKSAlPiUgcGxvdF9wdWJfdGltZWxpbmUoKQoKZmlndXJlX3B1YmxpY2F0aW9uX3RpbWUKYGBgCgpTdW1tYXJ5IHN0YXRzCgpgYGB7cn0Kc3RhdHNfcHViX3RpbWVsaW5lKHJhd19ob3N0bWV0YWdlbm9tZSwgcmF3X2hvc3RzaW5nbGVnZW5vbWUsIHJhd19lbnZpcm9ubWVudGFsKSAlPiUgCiAgc2VsZWN0KHB1YmxpY2F0aW9uX2RvaSkgJT4lIAogIGFycmFuZ2UgJT4lIAogIGRpc3RpbmN0ICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkKYGBgCgoKIyBDdW11bGF0aXZlIFNhbXBsZXMKCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD03fQoKZmlndXJlX2N1bXVsYXRpdmVfc2FtcGxlcyA8LSBzdGF0c19jdW11bGF0aXZlX3RpbWVsaW5lKHJhd19ob3N0bWV0YWdlbm9tZSwgcmF3X2hvc3RzaW5nbGVnZW5vbWUsIHJhd19lbnZpcm9ubWVudGFsKSAlPiUgcGxvdF9jdW11bGF0aXZlX3RpbWVsaW5lKCkKCmZpZ3VyZV9jdW11bGF0aXZlX3NhbXBsZXMKYGBgCgpTdW1tYXJ5IHN0YXRzCgpgYGB7cn0Kc3RhdHNfY3VtdWxhdGl2ZV90aW1lbGluZShyYXdfaG9zdG1ldGFnZW5vbWUsIHJhd19ob3N0c2luZ2xlZ2Vub21lLCByYXdfZW52aXJvbm1lbnRhbCkgJT4lCiAgZ3JvdXBfYnkoTGlzdCkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsID0gc3VtKGNvdW50KSkKYGBgCgoKIyBUaW1lbGluZXMgQ29tYmluZWQKCmBgYHtyIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTh9CmZpZ3VyZV90aW1lbGluZXMgPC0gZmlndXJlX3B1YmxpY2F0aW9uX3RpbWUgKyBmaWd1cmVfY3VtdWxhdGl2ZV9zYW1wbGVzICsgcGxvdF9sYXlvdXQobmNvbCA9IDIpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAnYScpCgpmaWd1cmVfdGltZWxpbmVzCgpnZ3NhdmUoIkFuY2llbnRNZXRhZ2Vub21lRGlyLVB1YmxpY2F0aW9uU2FtcGxlX1RpbWVsaW5lLnBkZiIsCiAgICAgICBmaWd1cmVfdGltZWxpbmVzLAogICAgICAgZGV2aWNlID0gY2Fpcm9fcGRmKCksCiAgICAgICB1bml0cyA9ICJpbiIsCiAgICAgICB3aWR0aCA9IDMuNSwKICAgICAgIGhlaWdodCA9IDQsCiAgICAgICBzY2FsZSA9IDIKICAgICAgICkKCmdnc2F2ZSgiQW5jaWVudE1ldGFnZW5vbWVEaXItUHVibGljYXRpb25TYW1wbGVfVGltZWxpbmUucG5nIiwKICAgICAgIGZpZ3VyZV90aW1lbGluZXMsCiAgICAgICBkZXZpY2UgPSAicG5nIiwKICAgICAgIHVuaXRzID0gImluIiwKICAgICAgIHdpZHRoID0gMy41LAogICAgICAgaGVpZ2h0ID0gNCwKICAgICAgIHNjYWxlID0gMgogICAgICAgKQpgYGAKCgoKIyBHZW9ncmFwaGljIFNwcmVhZAoKV2l0aCBrbm93biBjb29yZGluYXRlcyEKCmBgYHtyLCBmaWcuaGVpZ2h0PTcuNSwgZmlnLndpZHRoPTV9CmZpZ3VyZV9tYXAgPC0gc3RhdHNfbWFwKHJhd19ob3N0bWV0YWdlbm9tZSwgcmF3X2hvc3RzaW5nbGVnZW5vbWUsIHJhd19lbnZpcm9ubWVudGFsKSAlPiUgcGxvdF9tYXAKCmZpZ3VyZV9tYXAKCmdnc2F2ZSgiQW5jaWVudE1ldGFnZW5vbWVEaXItU2FtcGxlX01hcC5wZGYiLAogICAgICAgZmlndXJlX21hcCwKICAgICAgIGRldmljZSA9IGNhaXJvX3BkZigpLAogICAgICAgdW5pdHMgPSAiaW4iLAogICAgICAgd2lkdGggPSAxLAogICAgICAgaGVpZ2h0ID0gMiwKICAgICAgIHNjYWxlID0gNAogICAgICAgKQoKZ2dzYXZlKCJBbmNpZW50TWV0YWdlbm9tZURpci1TYW1wbGVfTWFwLnBuZyIsCiAgICAgICBmaWd1cmVfbWFwLAogICAgICAgZGV2aWNlID0gInBuZyIsCiAgICAgICB1bml0cyA9ICJpbiIsCiAgICAgICB3aWR0aCA9IDEsCiAgICAgICBoZWlnaHQgPSAyLAogICAgICAgc2NhbGUgPSA0CiAgICAgICApCgpgYGAKCkhvdyBtYW55IGNvdW50cmllcyBkb2VzIHRoaXMgY292ZXI/CgpgYGB7cn0Kc3RhdHNfbWFwKHJhd19ob3N0bWV0YWdlbm9tZSwgcmF3X2hvc3RzaW5nbGVnZW5vbWUsIHJhd19lbnZpcm9ubWVudGFsKSAlPiUgCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdChnZW9fbG9jX25hbWUpICU+JSAKICBkaXN0aW5jdCgpICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkKYGBgCgo=