Last updated on Sun Feb 11 22:55:44 2024.

How to re-use this work

If you use the following figures in your own work, please cite:

# Load required packages
library(magrittr)
library(dplyr)
library(purrr)
library(jsonlite)
library(forcats)
library(ggplot2)
library(plotly)
library(here)
library(stringr)

# We need two queries: one for uppercase titles, the other for lowercase ones
pdb_queries <- c(
    uppercase = 'https://www.ebi.ac.uk/pdbe/search/pdb/select?q=title:*UCLEOSOM*%20AND%20status:REL&fl=pdb_id,citation_year,title,experimental_method,resolution,organism_scientific_name,molecule_name,molecule_type,number_of_protein_chains&rows=1000000&wt=json',
    lowercase = 'https://www.ebi.ac.uk/pdbe/search/pdb/select?q=title:*ucleosom*%20AND%20status:REL&fl=pdb_id,citation_year,title,experimental_method,resolution,organism_scientific_name,molecule_name,molecule_type,number_of_protein_chains&rows=1000000&wt=json',
    ncp = 'https://www.ebi.ac.uk/pdbe/search/pdb/select?q=title:*NCP*%20AND%20status:REL&fl=pdb_id,citation_year,title,experimental_method,resolution,organism_scientific_name,molecule_name,molecule_type,number_of_protein_chains&rows=1000000&wt=json'
)

# The following PDB entries have the word "nucleosome in their title, but do not
# actually contain a nucleosome, so we need to exclude them from the analysis.
# Unfortunately, there is no good way to automate this.
non_nucleosome_structures <- c(
    "1hst",
    "2z2r",
    "5x7v",
    "3uv2",
    "3fs3",
    "1wg3",
    "1nw3",
    "5ikf",
    "3gyw",
    "3gyv",
    "1ofc",
    "2ayu",
    "2iw5",
    "3hfd",
    "6uch",
    "5r4k",
    "5r4m",
    "5r4l",
    "5r4o",
    "5r4g",
    "5r4h",
    "5r4j",
    "5r4i",
    "5r4n",
    "1bj6",
    "6qds",
    "2iwj",
    "4dvk",
    "1a6b",
    "6qdu",
    "6ne8",
    "1tsu",
    "1esk",
    "7c4j"
)

# This is a helper pipeline to extract data
dig_up_data <- . %>%
    .$response %>%
    .$docs %>%
    as_tibble()

# This is a helper function to detect the presence of a binding factor
has_binding_factor_one <- function(number_of_protein_chains, title) {
    # It takes 8 histone chains to make a nucleosome, so if the number of
    # protein chains is not divisible by 8, this means there is a binding factor,
    # unless we're seeing the overlapping dinucleosome (14 proteins chains, but
    # they are all histones... one octamer + one hexamer)
    oldn <- str_detect(title, "unusual")
    if (number_of_protein_chains %% 8 != 0 & !oldn) {
        return(TRUE)
    } else {
        # But for multiple of 8 chains > 8 (i.e. 16, 24, 32, 40), we can have this
        # number of chains by chance even with binding factors. There is no good
        # way to automatically find these cases, unfortunately
        compass <- str_detect(title, "COMPASS")
        corest <- str_detect(title, "LSD1/CoREST")
        binding_factor <- compass || corest
        if (binding_factor) {
            return(TRUE)
        } else {
            return(FALSE)
        }
    }
}

# Vectorize the above function
has_binding_factor <- function(number_of_protein_chains_vector, title) {
    map2_lgl(number_of_protein_chains_vector, title, has_binding_factor_one)
}

# Query the PDB and clean up data
pdb_data <- pdb_queries %>% 
    map(fromJSON) %>% 
    map(dig_up_data) %>% 
    bind_rows() %>% 
    filter(!(pdb_id %in% non_nucleosome_structures)) %>% 
    mutate(
      has_binding_factor    = has_binding_factor(number_of_protein_chains, title),
      experimental_method   = as_factor(as.character(experimental_method)),
      citation_year         = as.integer(citation_year),
      molecule_name         = as.character(molecule_name),
      molecule_type         = as_factor(as.character(molecule_type))
      ) %>% 
    distinct(pdb_id, .keep_all = TRUE)

Nucleosome structures by year

All figures are interactive (you can zoom in, and hovering over elements will show more information).

Nucleosome structures by year and experimental method

nucleosome_structures_year <- pdb_data %>% 
    ggplot() +
    geom_bar(mapping = aes(x = citation_year, fill = experimental_method)) +
    guides(fill = guide_legend(title = "Experimental method")) +
    ggtitle("Structures of nucleosomes by year") +
    xlab("Publication year") +
    ylab("Number of PDB entries") +
    theme_bw()
ggplotly(nucleosome_structures_year)

Download figure in SVG format

Nucleosome structures by year and presence of a binding factor

nucleosome_structures_year_binding_factor <- pdb_data %>% 
    ggplot() +
    geom_bar(mapping = aes(x = citation_year, fill = has_binding_factor)) +
    guides(fill = guide_legend(title = "Contains a binding factor")) +
    ggtitle("Structures of nucleosomes by year") +
    xlab("Publication year") +
    ylab("Number of PDB entries") +
    theme_bw()
ggplotly(nucleosome_structures_year_binding_factor)

Download figure in SVG format

Nucleosome structures by experimental method

nucleosome_structures_method <- pdb_data %>% 
    ggplot() +
    geom_bar(mapping = aes(x = experimental_method, fill = experimental_method)) +
    guides(fill = guide_legend(title = "Experimental method")) +
    ggtitle("Structures of nucleosomes by experimental method") +
    xlab("") +
    ylab("Number of PDB entries") +
    theme_bw()
ggplotly(nucleosome_structures_method)

Download figure in SVG format

Nucleosome structures by presence of a binding factor

nucleosome_binding_factors_methods <- pdb_data %>% 
    ggplot() +
    geom_bar(mapping = aes(x = experimental_method, fill = has_binding_factor)) +
    guides(fill = guide_legend(title = "Presence of a binding factor")) +
    ggtitle("Structures of nucleosomes by presence of a binding factor") +
    xlab("Experimental method") +
    ylab("Number of PDB entries") +
    theme_bw()
ggplotly(nucleosome_binding_factors_methods)

Download figure in SVG format

nucleosome_binding_factors <- pdb_data %>% 
    ggplot() +
    geom_bar(mapping = aes(x = has_binding_factor, fill = has_binding_factor)) +
    guides(fill = guide_legend(title = "Presence of a binding factor")) +
    ggtitle("Structures of nucleosomes by presence of a binding factor") +
    xlab("Presence of a binding factor") +
    ylab("Number of PDB entries") +
    theme_bw()
ggplotly(nucleosome_binding_factors)

Download figure in SVG format

nucleosome_binding_factors_methods_2 <- pdb_data %>% 
    ggplot() +
    geom_bar(mapping = aes(x = has_binding_factor, fill = experimental_method)) +
    guides(fill = guide_legend(title = "Experimental method")) +
    ggtitle("Structures of nucleosomes by presence of a binding factor") +
    xlab("Presence of a binding factor") +
    ylab("Number of PDB entries") +
    theme_bw()
ggplotly(nucleosome_binding_factors_methods_2)

Download figure in SVG format

Nucleosome structures by histone species

Crystal structures of nucleosomes by histone species

nucleosome_xtal_species <- pdb_data %>% 
    filter(experimental_method == "X-ray diffraction") %>% 
    mutate(is_histone = str_detect(molecule_name, pattern = "Histone H")) %>% 
    filter(is_histone == TRUE) %>% 
    mutate(organism_scientific_name = as_factor(as.character(organism_scientific_name))) %>% 
    ggplot() +
    geom_bar(mapping = aes(x = organism_scientific_name,
                           fill = organism_scientific_name)) +
    guides(fill = guide_legend(title = "Histone species")) +
    ggtitle("Crystal structures of nucleosomes by histone species") +
    xlab("") +
    ylab("Number of PDB entries") +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 30, hjust = 1))
ggplotly(nucleosome_xtal_species)

Download figure in SVG format

Cryo-EM structures of nucleosomes by histone species

nucleosome_cryoem_species <- pdb_data %>% 
    filter(experimental_method == "Electron Microscopy") %>% 
    mutate(is_histone = str_detect(molecule_name, pattern = "Histone H")) %>% 
    filter(is_histone == TRUE) %>% 
    mutate(organism_scientific_name = as_factor(as.character(organism_scientific_name))) %>% 
    ggplot() +
    geom_bar(mapping = aes(x = organism_scientific_name,
                           fill = organism_scientific_name)) +
    guides(fill = guide_legend(title = "Histone species")) +
    ggtitle("Cryo-EM structures of nucleosomes by histone species") +
    xlab("") +
    ylab("Number of PDB entries") +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 30, hjust = 1))
ggplotly(nucleosome_cryoem_species)

Download figure in SVG format

Resolution of nucleosome structures by histone species

Crystal structures

pdb_data %>% dplyr::filter(experimental_method == "X-ray diffraction") %>% .$resolution %>% summary()
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.580   2.450   2.773   2.899   3.085   9.700
nucleosome_xtal_resolution_species <- pdb_data %>% 
    filter(experimental_method == "X-ray diffraction") %>% 
    mutate(is_histone = str_detect(molecule_name, pattern = "Histone H")) %>% 
    filter(is_histone == TRUE) %>% 
    mutate(organism_scientific_name = as_factor(as.character(organism_scientific_name))) %>% 
    select(resolution, organism_scientific_name) %>% 
    ggplot() +
    geom_histogram(aes(x = resolution, fill = organism_scientific_name),
                   binwidth = 0.2) +
    guides(fill = guide_legend(title = "Histone species")) +
    ggtitle("Resolution of nucleosome crystal structures by histone species") +
    xlab("Resolution (Å)") +
    ylab("Number of PDB entries") +
    theme_bw()
ggplotly(nucleosome_xtal_resolution_species)

Download figure in SVG format

Cryo-EM structures

pdb_data %>% dplyr::filter(experimental_method == "Electron Microscopy") %>% .$resolution %>% summary()
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##   1.890   3.200   3.700   4.219   4.312  20.000       2
nucleosome_cryoem_resolution_species <- pdb_data %>% 
    filter(experimental_method == "Electron Microscopy") %>% 
    mutate(is_histone = str_detect(molecule_name, pattern = "Histone H")) %>% 
    filter(is_histone == TRUE) %>% 
    mutate(organism_scientific_name = as_factor(as.character(organism_scientific_name))) %>% 
    select(resolution, organism_scientific_name) %>% 
    ggplot() +
    geom_histogram(aes(x = resolution, fill = organism_scientific_name),
                   binwidth = 0.2) +
    guides(fill = guide_legend(title = "Histone species")) +
    ggtitle("Resolution of nucleosome cryo-EM structures by histone species") +
    xlab("Resolution (Å)") +
    ylab("Number of PDB entries") +
    theme_bw()
ggplotly(nucleosome_cryoem_resolution_species)

Download figure in SVG format

Dataset

The graphs presented above are derived from the following dataset:

# Format table for display
pdb_table <- pdb_data %>% 
    arrange(desc(citation_year)) %>% 
    select(`PDB code` = pdb_id,
           `Citation year` = citation_year,
           `Experimental method` = experimental_method,
           Title = title)
pdb_table

Download raw dataset in JSON format

LS0tCnRpdGxlOiAiTnVjbGVvc29tZSBzdHJ1Y3R1cmVzIgotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpCmBgYAoKKipMYXN0IHVwZGF0ZWQgb24gYHIgZGF0ZSgpYC4qKgoKIyMgSG93IHRvIHJlLXVzZSB0aGlzIHdvcmsKCklmIHlvdSB1c2UgdGhlIGZvbGxvd2luZyBmaWd1cmVzIGluIHlvdXIgb3duIHdvcmssIHBsZWFzZSBjaXRlOgoKLSBaaG91IEssIEdhdWxsaWVyIEcgJiBMdWdlciBLICgyMDE5KSBOdWNsZW9zb21lIHN0cnVjdHVyZSBhbmQgZHluYW1pY3MgYXJlCiAgY29taW5nIG9mIGFnZS4gKk5hdHVyZSBTdHJ1Y3R1cmFsICYgTW9sZWN1bGFyIEJpb2xvZ3kqICoqMjYqKjogM+KAkzEzLgogIDxodHRwczovL2RvaS5vcmcvMTAuMTAzOC9zNDE1OTQtMDE4LTAxNjYteD4KLSBUaGlzIHdlYnNpdGU6IDxodHRwczovL2RvaS5vcmcvMTAuNTI4MS96ZW5vZG8uMzQ3MDExOT4KCmBgYHtyIExvYWQgcGFja2FnZXMsIGRvd25sb2FkIGRhdGEgYW5kIHByZXBhcmUgZGF0YXNldH0KIyBMb2FkIHJlcXVpcmVkIHBhY2thZ2VzCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocHVycnIpCmxpYnJhcnkoanNvbmxpdGUpCmxpYnJhcnkoZm9yY2F0cykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShoZXJlKQpsaWJyYXJ5KHN0cmluZ3IpCgojIFdlIG5lZWQgdHdvIHF1ZXJpZXM6IG9uZSBmb3IgdXBwZXJjYXNlIHRpdGxlcywgdGhlIG90aGVyIGZvciBsb3dlcmNhc2Ugb25lcwpwZGJfcXVlcmllcyA8LSBjKAogICAgdXBwZXJjYXNlID0gJ2h0dHBzOi8vd3d3LmViaS5hYy51ay9wZGJlL3NlYXJjaC9wZGIvc2VsZWN0P3E9dGl0bGU6KlVDTEVPU09NKiUyMEFORCUyMHN0YXR1czpSRUwmZmw9cGRiX2lkLGNpdGF0aW9uX3llYXIsdGl0bGUsZXhwZXJpbWVudGFsX21ldGhvZCxyZXNvbHV0aW9uLG9yZ2FuaXNtX3NjaWVudGlmaWNfbmFtZSxtb2xlY3VsZV9uYW1lLG1vbGVjdWxlX3R5cGUsbnVtYmVyX29mX3Byb3RlaW5fY2hhaW5zJnJvd3M9MTAwMDAwMCZ3dD1qc29uJywKICAgIGxvd2VyY2FzZSA9ICdodHRwczovL3d3dy5lYmkuYWMudWsvcGRiZS9zZWFyY2gvcGRiL3NlbGVjdD9xPXRpdGxlOip1Y2xlb3NvbSolMjBBTkQlMjBzdGF0dXM6UkVMJmZsPXBkYl9pZCxjaXRhdGlvbl95ZWFyLHRpdGxlLGV4cGVyaW1lbnRhbF9tZXRob2QscmVzb2x1dGlvbixvcmdhbmlzbV9zY2llbnRpZmljX25hbWUsbW9sZWN1bGVfbmFtZSxtb2xlY3VsZV90eXBlLG51bWJlcl9vZl9wcm90ZWluX2NoYWlucyZyb3dzPTEwMDAwMDAmd3Q9anNvbicsCiAgICBuY3AgPSAnaHR0cHM6Ly93d3cuZWJpLmFjLnVrL3BkYmUvc2VhcmNoL3BkYi9zZWxlY3Q/cT10aXRsZToqTkNQKiUyMEFORCUyMHN0YXR1czpSRUwmZmw9cGRiX2lkLGNpdGF0aW9uX3llYXIsdGl0bGUsZXhwZXJpbWVudGFsX21ldGhvZCxyZXNvbHV0aW9uLG9yZ2FuaXNtX3NjaWVudGlmaWNfbmFtZSxtb2xlY3VsZV9uYW1lLG1vbGVjdWxlX3R5cGUsbnVtYmVyX29mX3Byb3RlaW5fY2hhaW5zJnJvd3M9MTAwMDAwMCZ3dD1qc29uJwopCgojIFRoZSBmb2xsb3dpbmcgUERCIGVudHJpZXMgaGF2ZSB0aGUgd29yZCAibnVjbGVvc29tZSBpbiB0aGVpciB0aXRsZSwgYnV0IGRvIG5vdAojIGFjdHVhbGx5IGNvbnRhaW4gYSBudWNsZW9zb21lLCBzbyB3ZSBuZWVkIHRvIGV4Y2x1ZGUgdGhlbSBmcm9tIHRoZSBhbmFseXNpcy4KIyBVbmZvcnR1bmF0ZWx5LCB0aGVyZSBpcyBubyBnb29kIHdheSB0byBhdXRvbWF0ZSB0aGlzLgpub25fbnVjbGVvc29tZV9zdHJ1Y3R1cmVzIDwtIGMoCiAgICAiMWhzdCIsCiAgICAiMnoyciIsCiAgICAiNXg3diIsCiAgICAiM3V2MiIsCiAgICAiM2ZzMyIsCiAgICAiMXdnMyIsCiAgICAiMW53MyIsCiAgICAiNWlrZiIsCiAgICAiM2d5dyIsCiAgICAiM2d5diIsCiAgICAiMW9mYyIsCiAgICAiMmF5dSIsCiAgICAiMml3NSIsCiAgICAiM2hmZCIsCiAgICAiNnVjaCIsCiAgICAiNXI0ayIsCiAgICAiNXI0bSIsCiAgICAiNXI0bCIsCiAgICAiNXI0byIsCiAgICAiNXI0ZyIsCiAgICAiNXI0aCIsCiAgICAiNXI0aiIsCiAgICAiNXI0aSIsCiAgICAiNXI0biIsCiAgICAiMWJqNiIsCiAgICAiNnFkcyIsCiAgICAiMml3aiIsCiAgICAiNGR2ayIsCiAgICAiMWE2YiIsCiAgICAiNnFkdSIsCiAgICAiNm5lOCIsCiAgICAiMXRzdSIsCiAgICAiMWVzayIsCiAgICAiN2M0aiIKKQoKIyBUaGlzIGlzIGEgaGVscGVyIHBpcGVsaW5lIHRvIGV4dHJhY3QgZGF0YQpkaWdfdXBfZGF0YSA8LSAuICU+JQogICAgLiRyZXNwb25zZSAlPiUKICAgIC4kZG9jcyAlPiUKICAgIGFzX3RpYmJsZSgpCgojIFRoaXMgaXMgYSBoZWxwZXIgZnVuY3Rpb24gdG8gZGV0ZWN0IHRoZSBwcmVzZW5jZSBvZiBhIGJpbmRpbmcgZmFjdG9yCmhhc19iaW5kaW5nX2ZhY3Rvcl9vbmUgPC0gZnVuY3Rpb24obnVtYmVyX29mX3Byb3RlaW5fY2hhaW5zLCB0aXRsZSkgewogICAgIyBJdCB0YWtlcyA4IGhpc3RvbmUgY2hhaW5zIHRvIG1ha2UgYSBudWNsZW9zb21lLCBzbyBpZiB0aGUgbnVtYmVyIG9mCiAgICAjIHByb3RlaW4gY2hhaW5zIGlzIG5vdCBkaXZpc2libGUgYnkgOCwgdGhpcyBtZWFucyB0aGVyZSBpcyBhIGJpbmRpbmcgZmFjdG9yLAogICAgIyB1bmxlc3Mgd2UncmUgc2VlaW5nIHRoZSBvdmVybGFwcGluZyBkaW51Y2xlb3NvbWUgKDE0IHByb3RlaW5zIGNoYWlucywgYnV0CiAgICAjIHRoZXkgYXJlIGFsbCBoaXN0b25lcy4uLiBvbmUgb2N0YW1lciArIG9uZSBoZXhhbWVyKQogICAgb2xkbiA8LSBzdHJfZGV0ZWN0KHRpdGxlLCAidW51c3VhbCIpCiAgICBpZiAobnVtYmVyX29mX3Byb3RlaW5fY2hhaW5zICUlIDggIT0gMCAmICFvbGRuKSB7CiAgICAgICAgcmV0dXJuKFRSVUUpCiAgICB9IGVsc2UgewogICAgICAgICMgQnV0IGZvciBtdWx0aXBsZSBvZiA4IGNoYWlucyA+IDggKGkuZS4gMTYsIDI0LCAzMiwgNDApLCB3ZSBjYW4gaGF2ZSB0aGlzCiAgICAgICAgIyBudW1iZXIgb2YgY2hhaW5zIGJ5IGNoYW5jZSBldmVuIHdpdGggYmluZGluZyBmYWN0b3JzLiBUaGVyZSBpcyBubyBnb29kCiAgICAgICAgIyB3YXkgdG8gYXV0b21hdGljYWxseSBmaW5kIHRoZXNlIGNhc2VzLCB1bmZvcnR1bmF0ZWx5CiAgICAgICAgY29tcGFzcyA8LSBzdHJfZGV0ZWN0KHRpdGxlLCAiQ09NUEFTUyIpCiAgICAgICAgY29yZXN0IDwtIHN0cl9kZXRlY3QodGl0bGUsICJMU0QxL0NvUkVTVCIpCiAgICAgICAgYmluZGluZ19mYWN0b3IgPC0gY29tcGFzcyB8fCBjb3Jlc3QKICAgICAgICBpZiAoYmluZGluZ19mYWN0b3IpIHsKICAgICAgICAgICAgcmV0dXJuKFRSVUUpCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgcmV0dXJuKEZBTFNFKQogICAgICAgIH0KICAgIH0KfQoKIyBWZWN0b3JpemUgdGhlIGFib3ZlIGZ1bmN0aW9uCmhhc19iaW5kaW5nX2ZhY3RvciA8LSBmdW5jdGlvbihudW1iZXJfb2ZfcHJvdGVpbl9jaGFpbnNfdmVjdG9yLCB0aXRsZSkgewogICAgbWFwMl9sZ2wobnVtYmVyX29mX3Byb3RlaW5fY2hhaW5zX3ZlY3RvciwgdGl0bGUsIGhhc19iaW5kaW5nX2ZhY3Rvcl9vbmUpCn0KCiMgUXVlcnkgdGhlIFBEQiBhbmQgY2xlYW4gdXAgZGF0YQpwZGJfZGF0YSA8LSBwZGJfcXVlcmllcyAlPiUgCiAgICBtYXAoZnJvbUpTT04pICU+JSAKICAgIG1hcChkaWdfdXBfZGF0YSkgJT4lIAogICAgYmluZF9yb3dzKCkgJT4lIAogICAgZmlsdGVyKCEocGRiX2lkICVpbiUgbm9uX251Y2xlb3NvbWVfc3RydWN0dXJlcykpICU+JSAKICAgIG11dGF0ZSgKICAgICAgaGFzX2JpbmRpbmdfZmFjdG9yICAgID0gaGFzX2JpbmRpbmdfZmFjdG9yKG51bWJlcl9vZl9wcm90ZWluX2NoYWlucywgdGl0bGUpLAogICAgICBleHBlcmltZW50YWxfbWV0aG9kICAgPSBhc19mYWN0b3IoYXMuY2hhcmFjdGVyKGV4cGVyaW1lbnRhbF9tZXRob2QpKSwKICAgICAgY2l0YXRpb25feWVhciAgICAgICAgID0gYXMuaW50ZWdlcihjaXRhdGlvbl95ZWFyKSwKICAgICAgbW9sZWN1bGVfbmFtZSAgICAgICAgID0gYXMuY2hhcmFjdGVyKG1vbGVjdWxlX25hbWUpLAogICAgICBtb2xlY3VsZV90eXBlICAgICAgICAgPSBhc19mYWN0b3IoYXMuY2hhcmFjdGVyKG1vbGVjdWxlX3R5cGUpKQogICAgICApICU+JSAKICAgIGRpc3RpbmN0KHBkYl9pZCwgLmtlZXBfYWxsID0gVFJVRSkKYGBgCgojIyBOdWNsZW9zb21lIHN0cnVjdHVyZXMgYnkgeWVhcgoKQWxsIGZpZ3VyZXMgYXJlIGludGVyYWN0aXZlICh5b3UgY2FuIHpvb20gaW4sIGFuZCBob3ZlcmluZyBvdmVyIGVsZW1lbnRzIHdpbGwKc2hvdyBtb3JlIGluZm9ybWF0aW9uKS4KCiMjIyBOdWNsZW9zb21lIHN0cnVjdHVyZXMgYnkgeWVhciBhbmQgZXhwZXJpbWVudGFsIG1ldGhvZAoKYGBge3IgTnVjbGVvc29tZSBzdHJ1Y3R1cmVzIGJ5IHllYXJ9Cm51Y2xlb3NvbWVfc3RydWN0dXJlc195ZWFyIDwtIHBkYl9kYXRhICU+JSAKICAgIGdncGxvdCgpICsKICAgIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGNpdGF0aW9uX3llYXIsIGZpbGwgPSBleHBlcmltZW50YWxfbWV0aG9kKSkgKwogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiRXhwZXJpbWVudGFsIG1ldGhvZCIpKSArCiAgICBnZ3RpdGxlKCJTdHJ1Y3R1cmVzIG9mIG51Y2xlb3NvbWVzIGJ5IHllYXIiKSArCiAgICB4bGFiKCJQdWJsaWNhdGlvbiB5ZWFyIikgKwogICAgeWxhYigiTnVtYmVyIG9mIFBEQiBlbnRyaWVzIikgKwogICAgdGhlbWVfYncoKQpnZ3Bsb3RseShudWNsZW9zb21lX3N0cnVjdHVyZXNfeWVhcikKYGBgCgpgYGB7ciBTYXZlIFNWRyBmaWxlIG9mIHllYXIgZ3JhcGgsIGluY2x1ZGU9RkFMU0V9CiMgU2F2ZSBmaWd1cmUgZm9yIGRvd25sb2FkCmlmICghZGlyLmV4aXN0cyhoZXJlKCJmaWd1cmVzIikpKSB7CiAgICBkaXIuY3JlYXRlKGhlcmUoImZpZ3VyZXMiKSkKfQpnZ3NhdmUoZmlsZW5hbWUgPSAibnVjbGVvc29tZS1zdHJ1Y3R1cmVzLWJ5LXllYXIuc3ZnIiwKICAgICAgIHBsb3QgPSBudWNsZW9zb21lX3N0cnVjdHVyZXNfeWVhciwKICAgICAgIGRldmljZSA9ICJzdmciLAogICAgICAgcGF0aCA9IGhlcmUoImZpZ3VyZXMiKSkKYGBgCgpbKipEb3dubG9hZCBmaWd1cmUgaW4gU1ZHIGZvcm1hdCoqXShmaWd1cmVzL251Y2xlb3NvbWUtc3RydWN0dXJlcy1ieS15ZWFyLnN2ZykKCiMjIyBOdWNsZW9zb21lIHN0cnVjdHVyZXMgYnkgeWVhciBhbmQgcHJlc2VuY2Ugb2YgYSBiaW5kaW5nIGZhY3RvcgoKYGBge3IgTnVjbGVvc29tZSBzdHJ1Y3R1cmVzIGJ5IHllYXIgYW5kIGJpbmRpbmcgZmFjdG9yfQpudWNsZW9zb21lX3N0cnVjdHVyZXNfeWVhcl9iaW5kaW5nX2ZhY3RvciA8LSBwZGJfZGF0YSAlPiUgCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjaXRhdGlvbl95ZWFyLCBmaWxsID0gaGFzX2JpbmRpbmdfZmFjdG9yKSkgKwogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiQ29udGFpbnMgYSBiaW5kaW5nIGZhY3RvciIpKSArCiAgICBnZ3RpdGxlKCJTdHJ1Y3R1cmVzIG9mIG51Y2xlb3NvbWVzIGJ5IHllYXIiKSArCiAgICB4bGFiKCJQdWJsaWNhdGlvbiB5ZWFyIikgKwogICAgeWxhYigiTnVtYmVyIG9mIFBEQiBlbnRyaWVzIikgKwogICAgdGhlbWVfYncoKQpnZ3Bsb3RseShudWNsZW9zb21lX3N0cnVjdHVyZXNfeWVhcl9iaW5kaW5nX2ZhY3RvcikKYGBgCgpgYGB7ciBTYXZlIFNWRyBmaWxlIG9mIHllYXIgYW5kIGJpbmRpbmcgZmFjdG9yIGdyYXBoLCBpbmNsdWRlPUZBTFNFfQojIFNhdmUgZmlndXJlIGZvciBkb3dubG9hZAppZiAoIWRpci5leGlzdHMoaGVyZSgiZmlndXJlcyIpKSkgewogICAgZGlyLmNyZWF0ZShoZXJlKCJmaWd1cmVzIikpCn0KZ2dzYXZlKGZpbGVuYW1lID0gIm51Y2xlb3NvbWUtc3RydWN0dXJlcy1ieS15ZWFyLWJpbmRpbmctZmFjdG9yLnN2ZyIsCiAgICAgICBwbG90ID0gbnVjbGVvc29tZV9zdHJ1Y3R1cmVzX3llYXJfYmluZGluZ19mYWN0b3IsCiAgICAgICBkZXZpY2UgPSAic3ZnIiwKICAgICAgIHBhdGggPSBoZXJlKCJmaWd1cmVzIikpCmBgYAoKWyoqRG93bmxvYWQgZmlndXJlIGluIFNWRyBmb3JtYXQqKl0oZmlndXJlcy9udWNsZW9zb21lLXN0cnVjdHVyZXMtYnkteWVhci1iaW5kaW5nLWZhY3Rvci5zdmcpCgojIyBOdWNsZW9zb21lIHN0cnVjdHVyZXMgYnkgZXhwZXJpbWVudGFsIG1ldGhvZAoKYGBge3IgTnVjbGVvc29tZSBzdHJ1Y3R1cmVzIGJ5IGV4cGVyaW1lbnRhbCBtZXRob2R9Cm51Y2xlb3NvbWVfc3RydWN0dXJlc19tZXRob2QgPC0gcGRiX2RhdGEgJT4lIAogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gZXhwZXJpbWVudGFsX21ldGhvZCwgZmlsbCA9IGV4cGVyaW1lbnRhbF9tZXRob2QpKSArCiAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJFeHBlcmltZW50YWwgbWV0aG9kIikpICsKICAgIGdndGl0bGUoIlN0cnVjdHVyZXMgb2YgbnVjbGVvc29tZXMgYnkgZXhwZXJpbWVudGFsIG1ldGhvZCIpICsKICAgIHhsYWIoIiIpICsKICAgIHlsYWIoIk51bWJlciBvZiBQREIgZW50cmllcyIpICsKICAgIHRoZW1lX2J3KCkKZ2dwbG90bHkobnVjbGVvc29tZV9zdHJ1Y3R1cmVzX21ldGhvZCkKYGBgCgpgYGB7ciBTYXZlIFNWRyBmaWxlIG9mIG1ldGhvZCBncmFwaCwgaW5jbHVkZT1GQUxTRX0KIyBTYXZlIGZpZ3VyZSBmb3IgZG93bmxvYWQKaWYgKCFkaXIuZXhpc3RzKGhlcmUoImZpZ3VyZXMiKSkpIHsKICAgIGRpci5jcmVhdGUoaGVyZSgiZmlndXJlcyIpKQp9Cmdnc2F2ZShmaWxlbmFtZSA9ICJudWNsZW9zb21lLXN0cnVjdHVyZXMtYnktbWV0aG9kLnN2ZyIsCiAgICAgICBwbG90ID0gbnVjbGVvc29tZV9zdHJ1Y3R1cmVzX21ldGhvZCwKICAgICAgIGRldmljZSA9ICJzdmciLAogICAgICAgcGF0aCA9IGhlcmUoImZpZ3VyZXMiKSkKYGBgCgpbKipEb3dubG9hZCBmaWd1cmUgaW4gU1ZHIGZvcm1hdCoqXShmaWd1cmVzL251Y2xlb3NvbWUtc3RydWN0dXJlcy1ieS1tZXRob2Quc3ZnKQoKIyMgTnVjbGVvc29tZSBzdHJ1Y3R1cmVzIGJ5IHByZXNlbmNlIG9mIGEgYmluZGluZyBmYWN0b3IKCmBgYHtyIE51Y2xlb3NvbWUgc3RydWN0dXJlcyBieSBwcmVzZW5jZSBvZiBhIGJpbmRpbmcgZmFjdG9yIGFuZCBtZXRob2R9Cm51Y2xlb3NvbWVfYmluZGluZ19mYWN0b3JzX21ldGhvZHMgPC0gcGRiX2RhdGEgJT4lIAogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gZXhwZXJpbWVudGFsX21ldGhvZCwgZmlsbCA9IGhhc19iaW5kaW5nX2ZhY3RvcikpICsKICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIlByZXNlbmNlIG9mIGEgYmluZGluZyBmYWN0b3IiKSkgKwogICAgZ2d0aXRsZSgiU3RydWN0dXJlcyBvZiBudWNsZW9zb21lcyBieSBwcmVzZW5jZSBvZiBhIGJpbmRpbmcgZmFjdG9yIikgKwogICAgeGxhYigiRXhwZXJpbWVudGFsIG1ldGhvZCIpICsKICAgIHlsYWIoIk51bWJlciBvZiBQREIgZW50cmllcyIpICsKICAgIHRoZW1lX2J3KCkKZ2dwbG90bHkobnVjbGVvc29tZV9iaW5kaW5nX2ZhY3RvcnNfbWV0aG9kcykKYGBgCgpgYGB7ciBTYXZlIFNWRyBmaWxlIG9mIGJpbmRpbmcgZmFjdG9ycyBhbmQgbWV0aG9kcyBncmFwaCwgaW5jbHVkZT1GQUxTRX0KIyBTYXZlIGZpZ3VyZSBmb3IgZG93bmxvYWQKaWYgKCFkaXIuZXhpc3RzKGhlcmUoImZpZ3VyZXMiKSkpIHsKICAgIGRpci5jcmVhdGUoaGVyZSgiZmlndXJlcyIpKQp9Cmdnc2F2ZShmaWxlbmFtZSA9ICJudWNsZW9zb21lLWJpbmRpbmctZmFjdG9ycy1tZXRob2RzLnN2ZyIsCiAgICAgICBwbG90ID0gbnVjbGVvc29tZV9iaW5kaW5nX2ZhY3RvcnNfbWV0aG9kcywKICAgICAgIGRldmljZSA9ICJzdmciLAogICAgICAgcGF0aCA9IGhlcmUoImZpZ3VyZXMiKSkKYGBgCgpbKipEb3dubG9hZCBmaWd1cmUgaW4gU1ZHIGZvcm1hdCoqXShmaWd1cmVzL251Y2xlb3NvbWUtYmluZGluZy1mYWN0b3JzLW1ldGhvZHMuc3ZnKQoKYGBge3IgTnVjbGVvc29tZSBzdHJ1Y3R1cmVzIGJ5IHByZXNlbmNlIG9mIGEgYmluZGluZyBmYWN0b3J9Cm51Y2xlb3NvbWVfYmluZGluZ19mYWN0b3JzIDwtIHBkYl9kYXRhICU+JSAKICAgIGdncGxvdCgpICsKICAgIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGhhc19iaW5kaW5nX2ZhY3RvciwgZmlsbCA9IGhhc19iaW5kaW5nX2ZhY3RvcikpICsKICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIlByZXNlbmNlIG9mIGEgYmluZGluZyBmYWN0b3IiKSkgKwogICAgZ2d0aXRsZSgiU3RydWN0dXJlcyBvZiBudWNsZW9zb21lcyBieSBwcmVzZW5jZSBvZiBhIGJpbmRpbmcgZmFjdG9yIikgKwogICAgeGxhYigiUHJlc2VuY2Ugb2YgYSBiaW5kaW5nIGZhY3RvciIpICsKICAgIHlsYWIoIk51bWJlciBvZiBQREIgZW50cmllcyIpICsKICAgIHRoZW1lX2J3KCkKZ2dwbG90bHkobnVjbGVvc29tZV9iaW5kaW5nX2ZhY3RvcnMpCmBgYAoKYGBge3IgU2F2ZSBTVkcgZmlsZSBvZiBiaW5kaW5nIGZhY3RvcnMgZ3JhcGgsIGluY2x1ZGU9RkFMU0V9CiMgU2F2ZSBmaWd1cmUgZm9yIGRvd25sb2FkCmlmICghZGlyLmV4aXN0cyhoZXJlKCJmaWd1cmVzIikpKSB7CiAgICBkaXIuY3JlYXRlKGhlcmUoImZpZ3VyZXMiKSkKfQpnZ3NhdmUoZmlsZW5hbWUgPSAibnVjbGVvc29tZS1iaW5kaW5nLWZhY3RvcnMuc3ZnIiwKICAgICAgIHBsb3QgPSBudWNsZW9zb21lX2JpbmRpbmdfZmFjdG9ycywKICAgICAgIGRldmljZSA9ICJzdmciLAogICAgICAgcGF0aCA9IGhlcmUoImZpZ3VyZXMiKSkKYGBgCgpbKipEb3dubG9hZCBmaWd1cmUgaW4gU1ZHIGZvcm1hdCoqXShmaWd1cmVzL251Y2xlb3NvbWUtYmluZGluZy1mYWN0b3JzLnN2ZykKCmBgYHtyIE51Y2xlb3NvbWUgc3RydWN0dXJlcyBieSBwcmVzZW5jZSBvZiBhIGJpbmRpbmcgZmFjdG9yIGFuZCBtZXRob2QgMn0KbnVjbGVvc29tZV9iaW5kaW5nX2ZhY3RvcnNfbWV0aG9kc18yIDwtIHBkYl9kYXRhICU+JSAKICAgIGdncGxvdCgpICsKICAgIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGhhc19iaW5kaW5nX2ZhY3RvciwgZmlsbCA9IGV4cGVyaW1lbnRhbF9tZXRob2QpKSArCiAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJFeHBlcmltZW50YWwgbWV0aG9kIikpICsKICAgIGdndGl0bGUoIlN0cnVjdHVyZXMgb2YgbnVjbGVvc29tZXMgYnkgcHJlc2VuY2Ugb2YgYSBiaW5kaW5nIGZhY3RvciIpICsKICAgIHhsYWIoIlByZXNlbmNlIG9mIGEgYmluZGluZyBmYWN0b3IiKSArCiAgICB5bGFiKCJOdW1iZXIgb2YgUERCIGVudHJpZXMiKSArCiAgICB0aGVtZV9idygpCmdncGxvdGx5KG51Y2xlb3NvbWVfYmluZGluZ19mYWN0b3JzX21ldGhvZHNfMikKYGBgCgpgYGB7ciBTYXZlIFNWRyBmaWxlIG9mIGJpbmRpbmcgZmFjdG9ycyBtZXRob2RzIDIgZ3JhcGgsIGluY2x1ZGU9RkFMU0V9CiMgU2F2ZSBmaWd1cmUgZm9yIGRvd25sb2FkCmlmICghZGlyLmV4aXN0cyhoZXJlKCJmaWd1cmVzIikpKSB7CiAgICBkaXIuY3JlYXRlKGhlcmUoImZpZ3VyZXMiKSkKfQpnZ3NhdmUoZmlsZW5hbWUgPSAibnVjbGVvc29tZS1iaW5kaW5nLWZhY3RvcnMtbWV0aG9kcy0yLnN2ZyIsCiAgICAgICBwbG90ID0gbnVjbGVvc29tZV9iaW5kaW5nX2ZhY3RvcnNfbWV0aG9kc18yLAogICAgICAgZGV2aWNlID0gInN2ZyIsCiAgICAgICBwYXRoID0gaGVyZSgiZmlndXJlcyIpKQpgYGAKClsqKkRvd25sb2FkIGZpZ3VyZSBpbiBTVkcgZm9ybWF0KipdKGZpZ3VyZXMvbnVjbGVvc29tZS1iaW5kaW5nLWZhY3RvcnMtbWV0aG9kcy0yLnN2ZykKCiMjIE51Y2xlb3NvbWUgc3RydWN0dXJlcyBieSBoaXN0b25lIHNwZWNpZXMKIyMjIENyeXN0YWwgc3RydWN0dXJlcyBvZiBudWNsZW9zb21lcyBieSBoaXN0b25lIHNwZWNpZXMKCmBgYHtyIENyeXN0YWwgc3RydWN0dXJlcyBvZiBudWNsZW9zb21lcyBieSBoaXN0b25lIHNwZWNpZXN9Cm51Y2xlb3NvbWVfeHRhbF9zcGVjaWVzIDwtIHBkYl9kYXRhICU+JSAKICAgIGZpbHRlcihleHBlcmltZW50YWxfbWV0aG9kID09ICJYLXJheSBkaWZmcmFjdGlvbiIpICU+JSAKICAgIG11dGF0ZShpc19oaXN0b25lID0gc3RyX2RldGVjdChtb2xlY3VsZV9uYW1lLCBwYXR0ZXJuID0gIkhpc3RvbmUgSCIpKSAlPiUgCiAgICBmaWx0ZXIoaXNfaGlzdG9uZSA9PSBUUlVFKSAlPiUgCiAgICBtdXRhdGUob3JnYW5pc21fc2NpZW50aWZpY19uYW1lID0gYXNfZmFjdG9yKGFzLmNoYXJhY3RlcihvcmdhbmlzbV9zY2llbnRpZmljX25hbWUpKSkgJT4lIAogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gb3JnYW5pc21fc2NpZW50aWZpY19uYW1lLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gb3JnYW5pc21fc2NpZW50aWZpY19uYW1lKSkgKwogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiSGlzdG9uZSBzcGVjaWVzIikpICsKICAgIGdndGl0bGUoIkNyeXN0YWwgc3RydWN0dXJlcyBvZiBudWNsZW9zb21lcyBieSBoaXN0b25lIHNwZWNpZXMiKSArCiAgICB4bGFiKCIiKSArCiAgICB5bGFiKCJOdW1iZXIgb2YgUERCIGVudHJpZXMiKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSkpCmdncGxvdGx5KG51Y2xlb3NvbWVfeHRhbF9zcGVjaWVzKQpgYGAKCmBgYHtyIFNhdmUgU1ZHIGZpbGUgb2YgY3J5c3RhbC1zcGVjaWVzIGdyYXBoLCBpbmNsdWRlPUZBTFNFfQojIFNhdmUgZmlndXJlIGZvciBkb3dubG9hZAppZiAoIWRpci5leGlzdHMoaGVyZSgiZmlndXJlcyIpKSkgewogICAgZGlyLmNyZWF0ZShoZXJlKCJmaWd1cmVzIikpCn0KZ2dzYXZlKGZpbGVuYW1lID0gIm51Y2xlb3NvbWUteHRhbC1zdHJ1Y3R1cmVzLWJ5LWhpc3RvbmUtc3BlY2llcy5zdmciLAogICAgICAgcGxvdCA9IG51Y2xlb3NvbWVfeHRhbF9zcGVjaWVzLAogICAgICAgZGV2aWNlID0gInN2ZyIsCiAgICAgICBwYXRoID0gaGVyZSgiZmlndXJlcyIpKQpgYGAKClsqKkRvd25sb2FkIGZpZ3VyZSBpbiBTVkcgZm9ybWF0KipdKGZpZ3VyZXMvbnVjbGVvc29tZS14dGFsLXN0cnVjdHVyZXMtYnktaGlzdG9uZS1zcGVjaWVzLnN2ZykKCiMjIyBDcnlvLUVNIHN0cnVjdHVyZXMgb2YgbnVjbGVvc29tZXMgYnkgaGlzdG9uZSBzcGVjaWVzCgpgYGB7ciBDcnlvLUVNIHN0cnVjdHVyZXMgb2YgbnVjbGVvc29tZXMgYnkgaGlzdG9uZSBzcGVjaWVzfQpudWNsZW9zb21lX2NyeW9lbV9zcGVjaWVzIDwtIHBkYl9kYXRhICU+JSAKICAgIGZpbHRlcihleHBlcmltZW50YWxfbWV0aG9kID09ICJFbGVjdHJvbiBNaWNyb3Njb3B5IikgJT4lIAogICAgbXV0YXRlKGlzX2hpc3RvbmUgPSBzdHJfZGV0ZWN0KG1vbGVjdWxlX25hbWUsIHBhdHRlcm4gPSAiSGlzdG9uZSBIIikpICU+JSAKICAgIGZpbHRlcihpc19oaXN0b25lID09IFRSVUUpICU+JSAKICAgIG11dGF0ZShvcmdhbmlzbV9zY2llbnRpZmljX25hbWUgPSBhc19mYWN0b3IoYXMuY2hhcmFjdGVyKG9yZ2FuaXNtX3NjaWVudGlmaWNfbmFtZSkpKSAlPiUgCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBvcmdhbmlzbV9zY2llbnRpZmljX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBvcmdhbmlzbV9zY2llbnRpZmljX25hbWUpKSArCiAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJIaXN0b25lIHNwZWNpZXMiKSkgKwogICAgZ2d0aXRsZSgiQ3J5by1FTSBzdHJ1Y3R1cmVzIG9mIG51Y2xlb3NvbWVzIGJ5IGhpc3RvbmUgc3BlY2llcyIpICsKICAgIHhsYWIoIiIpICsKICAgIHlsYWIoIk51bWJlciBvZiBQREIgZW50cmllcyIpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkKZ2dwbG90bHkobnVjbGVvc29tZV9jcnlvZW1fc3BlY2llcykKYGBgCgpgYGB7ciBTYXZlIFNWRyBmaWxlIG9mIGNyeW9lbS1zcGVjaWVzIGdyYXBoLCBpbmNsdWRlPUZBTFNFfQojIFNhdmUgZmlndXJlIGZvciBkb3dubG9hZAppZiAoIWRpci5leGlzdHMoaGVyZSgiZmlndXJlcyIpKSkgewogICAgZGlyLmNyZWF0ZShoZXJlKCJmaWd1cmVzIikpCn0KZ2dzYXZlKGZpbGVuYW1lID0gIm51Y2xlb3NvbWUtY3J5b2VtLXN0cnVjdHVyZXMtYnktaGlzdG9uZS1zcGVjaWVzLnN2ZyIsCiAgICAgICBwbG90ID0gbnVjbGVvc29tZV9jcnlvZW1fc3BlY2llcywKICAgICAgIGRldmljZSA9ICJzdmciLAogICAgICAgcGF0aCA9IGhlcmUoImZpZ3VyZXMiKSkKYGBgCgpbKipEb3dubG9hZCBmaWd1cmUgaW4gU1ZHIGZvcm1hdCoqXShmaWd1cmVzL251Y2xlb3NvbWUtY3J5b2VtLXN0cnVjdHVyZXMtYnktaGlzdG9uZS1zcGVjaWVzLnN2ZykKCiMjIFJlc29sdXRpb24gb2YgbnVjbGVvc29tZSBzdHJ1Y3R1cmVzIGJ5IGhpc3RvbmUgc3BlY2llcwojIyMgQ3J5c3RhbCBzdHJ1Y3R1cmVzCgpgYGB7ciBSZXNvbHV0aW9uIG9mIG51Y2xlb3NvbWUgY3J5c3RhbCBzdHJ1Y3R1cmVzIGJ5IGhpc3RvbmUgc3BlY2llc30KcGRiX2RhdGEgJT4lIGRwbHlyOjpmaWx0ZXIoZXhwZXJpbWVudGFsX21ldGhvZCA9PSAiWC1yYXkgZGlmZnJhY3Rpb24iKSAlPiUgLiRyZXNvbHV0aW9uICU+JSBzdW1tYXJ5KCkKCm51Y2xlb3NvbWVfeHRhbF9yZXNvbHV0aW9uX3NwZWNpZXMgPC0gcGRiX2RhdGEgJT4lIAogICAgZmlsdGVyKGV4cGVyaW1lbnRhbF9tZXRob2QgPT0gIlgtcmF5IGRpZmZyYWN0aW9uIikgJT4lIAogICAgbXV0YXRlKGlzX2hpc3RvbmUgPSBzdHJfZGV0ZWN0KG1vbGVjdWxlX25hbWUsIHBhdHRlcm4gPSAiSGlzdG9uZSBIIikpICU+JSAKICAgIGZpbHRlcihpc19oaXN0b25lID09IFRSVUUpICU+JSAKICAgIG11dGF0ZShvcmdhbmlzbV9zY2llbnRpZmljX25hbWUgPSBhc19mYWN0b3IoYXMuY2hhcmFjdGVyKG9yZ2FuaXNtX3NjaWVudGlmaWNfbmFtZSkpKSAlPiUgCiAgICBzZWxlY3QocmVzb2x1dGlvbiwgb3JnYW5pc21fc2NpZW50aWZpY19uYW1lKSAlPiUgCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IHJlc29sdXRpb24sIGZpbGwgPSBvcmdhbmlzbV9zY2llbnRpZmljX25hbWUpLAogICAgICAgICAgICAgICAgICAgYmlud2lkdGggPSAwLjIpICsKICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkhpc3RvbmUgc3BlY2llcyIpKSArCiAgICBnZ3RpdGxlKCJSZXNvbHV0aW9uIG9mIG51Y2xlb3NvbWUgY3J5c3RhbCBzdHJ1Y3R1cmVzIGJ5IGhpc3RvbmUgc3BlY2llcyIpICsKICAgIHhsYWIoIlJlc29sdXRpb24gKMOFKSIpICsKICAgIHlsYWIoIk51bWJlciBvZiBQREIgZW50cmllcyIpICsKICAgIHRoZW1lX2J3KCkKZ2dwbG90bHkobnVjbGVvc29tZV94dGFsX3Jlc29sdXRpb25fc3BlY2llcykKYGBgCgpgYGB7ciBTYXZlIFNWRyBmaWxlIG9mIHh0YWwtcmVzb2x1dGlvbi1zcGVjaWVzIGdyYXBoLCBpbmNsdWRlPUZBTFNFfQojIFNhdmUgZmlndXJlIGZvciBkb3dubG9hZAppZiAoIWRpci5leGlzdHMoaGVyZSgiZmlndXJlcyIpKSkgewogICAgZGlyLmNyZWF0ZShoZXJlKCJmaWd1cmVzIikpCn0KZ2dzYXZlKGZpbGVuYW1lID0gIm51Y2xlb3NvbWUteHRhbC1yZXNvbHV0aW9uLWJ5LWhpc3RvbmUtc3BlY2llcy5zdmciLAogICAgICAgcGxvdCA9IG51Y2xlb3NvbWVfeHRhbF9yZXNvbHV0aW9uX3NwZWNpZXMsCiAgICAgICBkZXZpY2UgPSAic3ZnIiwKICAgICAgIHBhdGggPSBoZXJlKCJmaWd1cmVzIikpCmBgYAoKWyoqRG93bmxvYWQgZmlndXJlIGluIFNWRyBmb3JtYXQqKl0oZmlndXJlcy9udWNsZW9zb21lLXh0YWwtcmVzb2x1dGlvbi1ieS1oaXN0b25lLXNwZWNpZXMuc3ZnKQoKIyMjIENyeW8tRU0gc3RydWN0dXJlcwoKYGBge3IgUmVzb2x1dGlvbiBvZiBudWNsZW9zb21lIGNyeW8tRU0gc3RydWN0dXJlcyBieSBoaXN0b25lIHNwZWNpZXN9CnBkYl9kYXRhICU+JSBkcGx5cjo6ZmlsdGVyKGV4cGVyaW1lbnRhbF9tZXRob2QgPT0gIkVsZWN0cm9uIE1pY3Jvc2NvcHkiKSAlPiUgLiRyZXNvbHV0aW9uICU+JSBzdW1tYXJ5KCkKCm51Y2xlb3NvbWVfY3J5b2VtX3Jlc29sdXRpb25fc3BlY2llcyA8LSBwZGJfZGF0YSAlPiUgCiAgICBmaWx0ZXIoZXhwZXJpbWVudGFsX21ldGhvZCA9PSAiRWxlY3Ryb24gTWljcm9zY29weSIpICU+JSAKICAgIG11dGF0ZShpc19oaXN0b25lID0gc3RyX2RldGVjdChtb2xlY3VsZV9uYW1lLCBwYXR0ZXJuID0gIkhpc3RvbmUgSCIpKSAlPiUgCiAgICBmaWx0ZXIoaXNfaGlzdG9uZSA9PSBUUlVFKSAlPiUgCiAgICBtdXRhdGUob3JnYW5pc21fc2NpZW50aWZpY19uYW1lID0gYXNfZmFjdG9yKGFzLmNoYXJhY3RlcihvcmdhbmlzbV9zY2llbnRpZmljX25hbWUpKSkgJT4lIAogICAgc2VsZWN0KHJlc29sdXRpb24sIG9yZ2FuaXNtX3NjaWVudGlmaWNfbmFtZSkgJT4lIAogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSByZXNvbHV0aW9uLCBmaWxsID0gb3JnYW5pc21fc2NpZW50aWZpY19uYW1lKSwKICAgICAgICAgICAgICAgICAgIGJpbndpZHRoID0gMC4yKSArCiAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJIaXN0b25lIHNwZWNpZXMiKSkgKwogICAgZ2d0aXRsZSgiUmVzb2x1dGlvbiBvZiBudWNsZW9zb21lIGNyeW8tRU0gc3RydWN0dXJlcyBieSBoaXN0b25lIHNwZWNpZXMiKSArCiAgICB4bGFiKCJSZXNvbHV0aW9uICjDhSkiKSArCiAgICB5bGFiKCJOdW1iZXIgb2YgUERCIGVudHJpZXMiKSArCiAgICB0aGVtZV9idygpCmdncGxvdGx5KG51Y2xlb3NvbWVfY3J5b2VtX3Jlc29sdXRpb25fc3BlY2llcykKYGBgCgpgYGB7ciBTYXZlIFNWRyBmaWxlIG9mIGNyeW9lbS1yZXNvbHV0aW9uLXNwZWNpZXMgZ3JhcGgsIGluY2x1ZGU9RkFMU0V9CiMgU2F2ZSBmaWd1cmUgZm9yIGRvd25sb2FkCmlmICghZGlyLmV4aXN0cyhoZXJlKCJmaWd1cmVzIikpKSB7CiAgICBkaXIuY3JlYXRlKGhlcmUoImZpZ3VyZXMiKSkKfQpnZ3NhdmUoZmlsZW5hbWUgPSAibnVjbGVvc29tZS1jcnlvZW0tcmVzb2x1dGlvbi1ieS1oaXN0b25lLXNwZWNpZXMuc3ZnIiwKICAgICAgIHBsb3QgPSBudWNsZW9zb21lX2NyeW9lbV9yZXNvbHV0aW9uX3NwZWNpZXMsCiAgICAgICBkZXZpY2UgPSAic3ZnIiwKICAgICAgIHBhdGggPSBoZXJlKCJmaWd1cmVzIikpCmBgYAoKWyoqRG93bmxvYWQgZmlndXJlIGluIFNWRyBmb3JtYXQqKl0oZmlndXJlcy9udWNsZW9zb21lLWNyeW9lbS1yZXNvbHV0aW9uLWJ5LWhpc3RvbmUtc3BlY2llcy5zdmcpCgojIyBEYXRhc2V0CgpUaGUgZ3JhcGhzIHByZXNlbnRlZCBhYm92ZSBhcmUgZGVyaXZlZCBmcm9tIHRoZSBmb2xsb3dpbmcgZGF0YXNldDoKCmBgYHtyIEVudGlyZSBkYXRhc2V0fQojIEZvcm1hdCB0YWJsZSBmb3IgZGlzcGxheQpwZGJfdGFibGUgPC0gcGRiX2RhdGEgJT4lIAogICAgYXJyYW5nZShkZXNjKGNpdGF0aW9uX3llYXIpKSAlPiUgCiAgICBzZWxlY3QoYFBEQiBjb2RlYCA9IHBkYl9pZCwKICAgICAgICAgICBgQ2l0YXRpb24geWVhcmAgPSBjaXRhdGlvbl95ZWFyLAogICAgICAgICAgIGBFeHBlcmltZW50YWwgbWV0aG9kYCA9IGV4cGVyaW1lbnRhbF9tZXRob2QsCiAgICAgICAgICAgVGl0bGUgPSB0aXRsZSkKcGRiX3RhYmxlCmBgYAoKYGBge3IgU2F2ZSBkYXRhc2V0IGFzIEpTT04sIGluY2x1ZGU9RkFMU0V9CiMgU2F2ZSBkYXRhc2V0IGZvciBkb3dubG9hZAppZiAoIWRpci5leGlzdHMoaGVyZSgiZGF0YXNldHMiKSkpIHsKICAgIGRpci5jcmVhdGUoaGVyZSgiZGF0YXNldHMiKSkKfQoKd3JpdGVfanNvbihwZGJfZGF0YSwgaGVyZSgiZGF0YXNldHMiLCAibnVjbGVvc29tZS1zdHJ1Y3R1cmVzLmpzb24iKSkKYGBgCgpbKipEb3dubG9hZCByYXcgZGF0YXNldCBpbiBKU09OIGZvcm1hdCoqXShkYXRhc2V0cy9udWNsZW9zb21lLXN0cnVjdHVyZXMuanNvbikK