• How to re-use this work
  • Nucleosome structures by year
    • Nucleosome structures by year and experimental method
    • Nucleosome structures by year and presence of a binding factor
  • Nucleosome structures by experimental method
  • Nucleosome structures by presence of a binding factor
  • Nucleosome structures by histone species
    • Crystal structures of nucleosomes by histone species
    • Cryo-EM structures of nucleosomes by histone species
  • Resolution of nucleosome structures by histone species
    • Crystal structures
    • Cryo-EM structures
  • Dataset

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)
2000200520102015202020250255075100
Experimental methodX-ray diffractionElectron MicroscopyStructures of nucleosomes by yearPublication yearNumber of PDB entries

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)
2000200520102015202020250255075100
Contains a binding factorFALSETRUEStructures of nucleosomes by yearPublication yearNumber of PDB entries

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)
X-ray diffractionElectron Microscopy0100200300400
Experimental methodX-ray diffractionElectron MicroscopyStructures of nucleosomes by experimental methodNumber of PDB entries

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)
X-ray diffractionElectron Microscopy0100200300400
Presence of a binding factorFALSETRUEStructures of nucleosomes by presence of a binding factorExperimental methodNumber of PDB entries

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)
FALSETRUE0100200300
Presence of a binding factorFALSETRUEStructures of nucleosomes by presence of a binding factorPresence of a binding factorNumber of PDB entries

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)
FALSETRUE0100200300
Experimental methodX-ray diffractionElectron MicroscopyStructures of nucleosomes by presence of a binding factorPresence of a binding factorNumber of PDB entries

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)
Xenopus laevisMus musculusHomo sapiensSaccharomyces cerevisiae S288CDrosophila melanogasterArabidopsis thalianaLeishmania major0255075
Histone speciesXenopus laevisMus musculusHomo sapiensSaccharomyces cerevisiae S288CDrosophila melanogasterArabidopsis thalianaLeishmania majorCrystal structures of nucleosomes by histone speciesNumber of PDB entries

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)
Drosophila melanogasterXenopus laevisHomo sapiensGallus gallusSaccharomyces cerevisiae S288CTrypanosoma brucei brucei TREU927XenopusMarseillevirus marseillevirusKomagataella pastorisXenopus tropicalisMus musculusGiardia intestinalissynthetic construct050100150
Histone speciesDrosophila melanogasterXenopus laevisHomo sapiensGallus gallusSaccharomyces cerevisiae S288CTrypanosoma brucei brucei TREU927XenopusMarseillevirus marseillevirusKomagataella pastorisXenopus tropicalisMus musculusGiardia intestinalissynthetic constructCryo-EM structures of nucleosomes by histone speciesNumber of PDB entries

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)
2.55.07.510.001020
Histone speciesXenopus laevisMus musculusHomo sapiensSaccharomyces cerevisiae S288CDrosophila melanogasterArabidopsis thalianaLeishmania majorResolution of nucleosome crystal structures by histone speciesResolution (Å)Number of PDB entries

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)
510150102030
Histone speciesDrosophila melanogasterXenopus laevisHomo sapiensGallus gallusSaccharomyces cerevisiae S288CTrypanosoma brucei brucei TREU927XenopusMarseillevirus marseillevirusKomagataella pastorisXenopus tropicalisMus musculusGiardia intestinalissynthetic constructResolution of nucleosome cryo-EM structures by histone speciesResolution (Å)Number of PDB entries

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
ABCDEFGHIJ0123456789
PDB code
<chr>
Citation year
<int>
Experimental method
<fct>
8u142024Electron Microscopy
8upf2024Electron Microscopy
8sn82024Electron Microscopy
8txx2024Electron Microscopy
8syp2024Electron Microscopy
8sn12024Electron Microscopy
8hr12024Electron Microscopy
8sn52024Electron Microscopy
8smw2024Electron Microscopy
8hqy2024Electron Microscopy

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