1 ⚙️ Knit settings

Here we define our Knit settings, to make the output more user friendly, and to cache output for faster knitting.

2 📕 READ ME

This is the the R markdown script written in R studio (2023.09.0+463 “Desert Sunflower” Release) used to summarise the systematic map database from Martin et al. 2024 “Evidence of the impacts of pharmaceuticals on aquatic animal behaviour (EIPAAB): a systematic map and open access database” (doi: 🚧to be added🚧).

It is designed to act as a starting point for anyone who wishes to use the ‘Evidence of the Impacts of Pharmaceuticals on Aquatic Animal Behaviour’ (EIPAAB) database for their own projects. But also as a description of how the summary present in the Manuscript was conducted.

I recommended you read the ‘README’ files before you work with the EIPAAB database, there are two ‘“’README.md’ and ‘README.csv’, start with the ‘.md’ file (https://github.com/JakeMartinResearch/EIPAAB-database/blob/main/README.md)

P.s Apologies for any spelling mistakes in the script I (Jake Martin) am dyslexic and this is a very long document

3 📑 Sharing/accessing and citing

  1. Licenses/restrictions placed on the data: CC-BY 4.0

  2. Links to publications that cite or use the data: Martin, JM, Michelangeli, M, Bertram, MG, Blanchfield, PJ, Brand, JA, Brodin, T, Brooks, B, Cerveny, D, Fergusson, KN, Lagisz, M, Lovin, LM, Ligocki, IY, Nakagawa, S, Ozeki, S, Sandoval-Herrera, N, Kendall, S, Sundin, J, Tan, H, Thor´e, E, Wong, BBM, McCallum, ES, (2024) Evidence of the Impacts of Pharmaceuticals on aquatic animal behaviour (EIPAAB): a systematic map and open access database. EcoEvoRxiv https://doi.org/10.32942/X2NG9R

  3. Recommended citation for this dataset: Martin, JM, Michelangeli, M, Bertram, MG, Blanchfield, PJ, Brand, JA, Brodin, T, Brooks, B, Cerveny, D, Fergusson, KN, Lagisz, M, Lovin, LM, Ligocki, IY, Nakagawa, S, Ozeki, S, Sandoval-Herrera, N, Kendall, S, Sundin, J, Tan, H, Thor´e, E, Wong, BBM, McCallum, ES, (2024) EIPAAB database, https://doi.org/10.17605/OSF.IO/ATWY6

4 📧 Contact

Jake M. Martin

📧 Email: jake.martin@deakin.edu.au

📧 Alt Email: jake.martin.research@gmail.com

🌐 Web: jakemartin.org

🐙 GitHub: JakeMartinResearch

5 ⌨️ R informartion

If you are not familiar with R, here’s a beginners guide 📹

Here’s a link to download R 📥 and download R studio 📥

This is an R markdown file, which makes annotating and running R code more user friendly, it is also easy to reproducible and share in a variate of formates (e.g. htlm). The R code is embed within chunks, and the output for code will be embedded under the chuck.

# This is a chuck

All other text outside of the chucks are annotations (like this). Hashtags used outside of chucks are used to create headers and to structure the file. Hashtags within the chucks are used for more precise annotation within the code.

If you are not familiar with R markdown, here’s a guide

6 📦 Required packages

These are the R packages required to run the script. I have added them to a list so that I can install them all in one go using the function below called loaded_packages. This function I have made will load all the packages in the list below, if the packages are not already installed, this function will first install them.

If you want to install and load each package separately, you can use the code install.packages() and require(), I have given a example below. To run this code you will need to install pacman first install.packages("pacman")

# install.packages('pacman')
pacman::p_load(tidyverse, ggraph, igraph, ggrepel, RColorBrewer, ggtree, treeio,
    ape, gridExtra, ggdist, highcharter, pander, here, gt, readxl)

For ggtree and treeio you may need to run this code for instillation

# if (!requireNamespace('BiocManager', quietly = TRUE))
# install.packages('BiocManager') BiocManager::install('ggtree')

7 📂 Directories

Creating out input and output directories. They will be made within the current parent directory (i.e. where the R sciprt is saved)

7.1 Output directory 📤

This is code creates a folder and saves the directory as figure_path. This is where we will export our figures

figures_path <- here("figures")

if (!dir.exists(figures_path)) {
    dir.create(figures_path)
}

This is code creates a folder and saves the directory as output_path This is where we will export our data

output_path <- here("output-data")

if (!dir.exists(output_path)) {
    dir.create(output_path)
}

7.2 Input directory 📥

input_path <- here("input-data")

if (!dir.exists(figures_path)) {
    dir.create(figures_path)
}

8 📖 Database informartion

The ‘Evidence of the Impacts of Pharmaceuticals on Aquatic Animal Behaviour’ (EIPAAB) database has 111 columns and 1754 rows. The columns represent various forms of metadata extracted from articles that were included in Martin et al. 2024 “Evidence of the impacts of pharmaceuticals on aquatic animal behaviour: a systematic map and open access database” (doi: 🚧to be added🚧).

The 💿 READ-ME.csv file which explains what each metadata is, how it was extracted, what structure it has, and at what level it applies, is available at on GitHub (https://github.com/JakeMartinResearch/EIPAAB-database/tree/main/input-data) or on the OSF (10.17605/OSF.IO/ATWY6) Below I have imported the read me for accessibility. I highly recommend you read the READ-ME before conducting any of your own meta-analysis to make sure you have interoperated the data correctly.

More generally, column names that start with ‘validity’ are metadata relating to study validity, those that start with ‘specie’s relate to species information (population), those that start with ’compound’ relate to the chemical information (exposure), those that start with ‘behav’ relate to behaviour information (outcome). The order of columns reflects both the level the metadata is extracted at (i.e. article level or species by compound level; see level in READ-ME), as well as the general category of metadata (i.e. validity, species, compound, behaviour).

Here’s the first 10 rows of the READ ME file as an example

setwd(input_path)

READ_ME <- read.csv("READ-ME.csv", na = "NA")  # loading the READ-ME file

READ_ME %>%
    head() %>%
    gt()
column_name type structure level description validity_assessment CRED_criteria
article_id string free article A unique article id assigned during title and abstract screening 0 NA
response_id string free article A unique response id generated by the survey used to extract the article 0 NA
doi string free article The DOI of the article 0 NA
title string free article The title of the atricle 0 NA
year interger free article The year the article was publish 0 NA
journal string free article The name of the journal in which the article was published 0 NA

9 💿 Importing EIPAAB database

Importing the 💿 EIPAAB-database.csv database

It can be assessed from…

GitHub (https://github.com/JakeMartinResearch/EIPAAB-database/tree/main/input-data)

OSF (https://osf.io/atwy6/)

My personal webpage (https://jakemartin.org/eipaab-database/)

If the CSV files are in the same working directory (wd) as this R script, you will not need to use setwd(), but if the files are located elsewhere you will need to specify this in setwd(), and run all lines at once. In R markdown the working directory changes back to default after the chuck is run.

setwd(input_path)

EIPAAB_database <- read.csv("EIPAAB-database.csv", na = "NA")

10 🕵️ EIPAAB summary

10.1 Total numbers

The first thing we will look at is how many unique (distinct) articles there are in the database, and how many rows of data there are.

There are 901 articles

EIPAAB_database %>%  
  dplyr::distinct(article_id) %>% # Returns a list of distinct article_id
  nrow(.) # Returns the length of the current file (which is the list of distinct article_id)
## [1] 901

There are 1739 rows of data

EIPAAB_database %>%
    nrow(.)  # Returns the length of the current file (which is the length of the whole datafile)
## [1] 1739

Each row represent a unique species by compound combination within a given article. This is represented by the column unique_row_id This is a combination of the extractors response id, specie,s and compound. For example, R_0Bqz2RQ4JxPfBkZ_Danio_rerio_Diazepam, response id = R_0Bqz2RQ4JxPfBkZ, species = Danio rerio, and compound = Diazepam

EIPAAB_database %>% 
  dplyr::select(unique_row_id) %>% # selects just the unique_column_id column
  dplyr::arrange(unique_row_id) %>% # arranges the column alphabetically so the same examples will be given everytime 
  dplyr::slice(1:10) %>% # Returns only the first 10 rows 
  gt()
unique_row_id
R_0Bqz2RQ4JxPfBkZ_Danio_rerio_Diazepam
R_0CHlDBs9ipt4suZ_Astyanax_mexicanus_Aripiprazole
R_0Ck0AOjLDWukBUt_Procambarus_clarkii_Chlordiazepoxide
R_0JvaI9dlvTbozUl_Daphnia_magna_Fluoxetine
R_0JvaI9dlvTbozUl_Daphnia_magna_Sertraline
R_0Srt7zn9MwHKne1_Danio_rerio_Escitalopram
R_0p8ZEROmCGlSR7r_Oryzias_latipes_Fluoxetine
R_10C0XxjAUoZmibO_Amphiprion_ocellaris_17-alpha-ethinylestradiol
R_10GdzsXlrkwamUt_Daphnia_magna_Cisplatin
R_10NOT0XWL5TXN5m_Coenagrion_hastulatum_Diphenhydramine

Now the number of total treatments represented in the data, this is the total number of unique doses per species by compound combination.

In the map the number of treatments was only extracted for water-borne exposures, the NAs, represent other exposure routes. Therefore, the number of water-borne exposures treatments are 6294, and there are an additional 226 articles that don’t have treatment numbers. We know they all have at least two treatments, a control and a compound of interest, because that is part of the inclusion criteria. So we could add the number of NAs * 2 to the total, this would be 6746 total treatment groups. Although, this would likely be an underestimate of the true total.

EIPAAB_database %>% 
  dplyr::summarise(
    groups = sum(compound_treatment_levels, na.rm = TRUE), # Calculate the sum of 'compound_treatment_levels' while ignoring NA values
    nas = sum(is.na(compound_treatment_levels)), # Count the number of NA values in 'compound_treatment_levels'
    total = groups + (nas * 2) # Calculate the total by adding 'groups' to twice the number of NAs
  ) %>% 
  gt()
groups nas total
6152 226 6604

10.2 Study motivation

Let’s look at how the evidence collected breaks down by the three study motivations

total_atricles <- EIPAAB_database %>% 
  dplyr::distinct(article_id) %>% 
  nrow()

# Analyze the study motivations in the dataset
EIPAAB_database %>%
  dplyr::group_by(article_id) %>% # Group the data by 'article_id'
  dplyr::sample_n(1) %>% # Randomly sample one row from each group (i.e., each unique 'article_id')
  dplyr::ungroup() %>% # Ungroup the data to remove the previous grouping
  dplyr::group_by(study_motivation) %>% # Group the data by 'study_motivation'
  dplyr::reframe( # Create a summary data frame with the count and percentage of each study motivation
    n = length(study_motivation),  # Count the number of occurrences of each study motivation
    `%` = round(n / total_atricles, 3) * 100  # Calculate the percentage of total articles
  ) %>% 
  dplyr::arrange(desc(n)) %>%  # Arrange the resulting data frame in descending order of the count
  gt()
study_motivation n %
Environmental 510 56.6
Medical 233 25.9
Basic research 158 17.5

Here we are changing the order of these in the database to “Environmental”, “Medical”, “Basic research” for plots.

EIPAAB_database <- EIPAAB_database %>%
    dplyr::mutate(study_motivation = fct_relevel(study_motivation, "Environmental",
        "Medical", "Basic research"))

10.3 Publications by year

10.3.1 Number per year

Year range is 1974 to 2022, so 48 years worth of empirical research has contributed to this evidence base.

EIPAAB_database %>%
    dplyr::reframe(min_year = min(year), max_year = max(year), total_years = max_year -
        min_year) %>%
    gt()
min_year max_year total_years
1974 2022 48

Now making a summary for the number of publications per year based on study motivation

# Create a complete sequence of years and all unique study motivations
all_years <- as.character(1974:2022)
all_study_motivations <- unique(EIPAAB_database$study_motivation)

# Create a data frame with all combinations of year and study motivation
all_combinations <- expand.grid(year = all_years, study_motivation = all_study_motivations,
    stringsAsFactors = FALSE)

# Summarize the data
pub_year <- EIPAAB_database %>%
    group_by(year, study_motivation) %>%
    summarize(n = length(unique(article_id)), .groups = "drop") %>%
    mutate(year = as.character(year))

# Join with the complete grid of years and study motivations
pub_year_complete <- all_combinations %>%
    left_join(pub_year, by = c("year", "study_motivation")) %>%
    mutate(n = if_else(is.na(n), 0, n), year = as.numeric(year))

10.3.1.1 Fig 2a

Here’s a summary figure for the manuscript (MS).

# Define the colour palette
motivation_colour_theme <- c("#60BD6C", "#D359A1", "#3C82C4") # Making colour theme to apply to plot

# Create the plot
pub_year_fig <- pub_year_complete %>%
  # Group years before 1996 and reformat the year column
  dplyr::mutate(
    year = as.character(if_else(year < 1996, 1996, year)), # Grouping years before 1996
    year = if_else(year == "1996", "<1997", year)          # Renaming 1995 group to "<1996"
  ) %>%
  # Creating the plot
  ggplot(aes(y = n, x = year, fill = study_motivation)) +
  geom_bar(stat = "identity", width = 0.9) +
  # Apply the custom colours
  scale_fill_manual(values = motivation_colour_theme, name = "Study motivation") + 
  theme_classic() +
  # Customizing the theme
  theme(
    legend.position = c(0.05, 1), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1), # Ensuring the legend box aligns properly at the top-left corner
    axis.text.x = element_text(angle = 90, vjust = 0.5) # Rotating x-axis labels for better readability
  ) +
  # Adding axis labels
  labs(
    x = "Year of publication",
    y = "Number of articles"
  )

# Display the plot
pub_year_fig

Saving the figure as a PDF. I have hased this so I don’t re-write this file each time.

# setwd(figures_path) ggsave('pub_year_fig.png', plot = pub_year_fig, width =
# 10, height = 5, dpi = 300) #if you want to save a png
# ggsave('study_pub_year_fig.pdf', plot = pub_year_fig, width = 10, height = 5)

10.3.2 Cumulative and relative growth

Making values for cumulative and relative growth in articles. This is the cumulative number of articles per year for each study moitvation, as well as the relative growth based on 2007. We selected 2007 for a 15 year overview in growth.

pub_year_growth <- pub_year_complete %>%
  dplyr::group_by(study_motivation) %>%
  dplyr::mutate(
    n_cumulative = cumsum(n),  # Calculate the cumulative sum of 'n'
    n_cumulative_prop = n_cumulative / max(n_cumulative), # Calculate the cumulative proportion
    n_2007 = ifelse(year == 2007, n, NA_real_), # Get n value for year 2007
    n_2007 = first(na.omit(n_2007)), # Propagate the n_2012 value within the group
    n_ratio_to_2007 = n / n_2007 # Calculate number of articles relative to that of 2007
  ) %>%
  dplyr::ungroup() %>%
  dplyr::select(study_motivation, year, n, n_cumulative, n_cumulative_prop, n_ratio_to_2007)

Making a plot for each motivation cumulative growth since 1974 (the first identified study)

cumulative_articles_fig <- pub_year_growth %>% 
  ggplot(aes(y = n_cumulative, x = year, colour = study_motivation)) +
  geom_line(stat = "identity", linewidth = 1.5) +
  geom_hline(yintercept = 0) +
  scale_x_continuous(breaks = seq(1974, 2022, by = 1)) +
  scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
  theme_classic() +
  # Customizing the theme
  theme(
    legend.position = c(0.05, 1), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1), # Ensuring the legend box aligns properly at the top-left corner
    axis.text.x = element_text(angle = 90, vjust = 0.5) # Rotating x-axis labels for better readability
  ) +
  # Adding axis labels
  labs(
    x = "Year of publication",
    y = "Articles cumulative growth"
  )

cumulative_articles_fig

Saving this plot

# setwd(figures_path) ggsave('study_cumulative_articles_fig.pdf', plot =
# cumulative_articles_fig, width = 10, height = 5)

10.4 Reltive growth

Let’s look at relative growth compared to the research area more broadly

I will identify the most common research area based on each study motivation.

Environmental motivation = Environmental Sciences & Ecology
Medical motivation = Neurosciences & Neurology
Basic research = Neurosciences & Neurology

EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(study_motivation, wos_research_areas) %>%
    dplyr::reframe(n = length(doi)) %>%
    dplyr::mutate(wos_research_areas = str_trim(wos_research_areas)) %>%
    tidyr::separate_rows(wos_research_areas, sep = ";") %>%
    dplyr::mutate(wos_research_areas = str_trim(wos_research_areas)) %>%
    dplyr::group_by(study_motivation, wos_research_areas) %>%
    dplyr::reframe(n_total = sum(n)) %>%
    dplyr::arrange(desc(n_total)) %>%
    dplyr::arrange(study_motivation) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::slice(1:2) %>%
    dplyr::ungroup() %>%
    gt()
study_motivation wos_research_areas n_total
Environmental Environmental Sciences & Ecology 321
Environmental Toxicology 193
Medical Neurosciences & Neurology 106
Medical Pharmacology & Pharmacy 72
Basic research Neurosciences & Neurology 56
Basic research Behavioral Sciences 43

We will now compare the proportion cumulative growth of each study motivation against the most common research areas based on WoS.

I have searched articles published within these research areas from 1992-2022, and create a database to compare against.

Each search indued only a date range (e.g. PY=(1992-2021)) AND the given web of science resarch area (e.g. WC=(Pharmacology & Pharmacy)). Searchers were done on the 04/07/2024. Only the total number of articles each year was taken.

First we will import the research field annual number of articles database I create (martin-et-al-additional-file-10-wos-research-areas-1992-2022.xlsx). It is provide as supplementary file 9.

setwd(input_path)

wos_research_areas_n <- read_excel("martin-et-al-additional-file-10-wos-research-areas-1992-2022.xlsx", sheet = "sheet1") %>% 
  dplyr::arrange(year) %>%
  dplyr::group_by(research_area) %>%
  dplyr::mutate(
    n_cumulative = cumsum(n),  # Calculate the cumulative sum of 'n'
    n_cumulative_prop = n_cumulative / max(n_cumulative), # Calculate the cumulative proportion
    n_2007 = ifelse(year == 2007, n, NA_real_), # Get n value for year 2011
    n_2007= first(na.omit(n_2007)), # Propagate the n_2011 value within the group
    n_ratio_to_2007 = n / n_2007 # Calculate n_ratio_to_2000
  ) %>%
  dplyr::ungroup() %>%
  dplyr::select(research_area, year, n, n_cumulative, n_cumulative_prop, n_ratio_to_2007)

Combined the number of articles with those in the EIPAAB database

pub_year_growth_comp <- pub_year_growth %>%
    dplyr::rename(research_area = study_motivation)

wos_research_areas_comp <- wos_research_areas_n %>%
    rbind(., pub_year_growth_comp) %>%
    dplyr::mutate(research_area = factor(research_area, levels = c("Environmental",
        "Medical", "Basic research", "Environmental Sciences and Ecology", "Toxicology",
        "Neurosciences and Neurology", "Pharmacology and Pharmacy", "All Research Areas")))

Let’s see what the relative growth was in 2022 (the latest included year in the evidence base)

wos_research_areas_comp %>%
    dplyr::filter(year == 2022) %>%
    gt()
research_area year n n_cumulative n_cumulative_prop n_ratio_to_2007
Pharmacology and Pharmacy 2022 80433 1458833 1 1.765779
Neurosciences and Neurology 2022 24448 450515 1 1.604094
Toxicology 2022 16913 391858 1 1.409299
Environmental Sciences and Ecology 2022 4599 103123 1 1.066064
All Research Areas 2022 3618082 66839129 1 1.790462
Environmental 2022 57 510 1 19.000000
Medical 2022 30 233 1 10.000000
Basic research 2022 9 158 1 2.250000

10.4.1 Enviormental relative growth

10.4.1.1 Fig 2b-1

Let’s now compare the relative growth in Environmental research

# Define the colour palette
env_colour_theme <- c("#60BD6C", "#2E4B22", "black") # Making colour theme to apply to plot

enviro_comp <-  c("Environmental", "Environmental Sciences and Ecology", "All Research Areas")

line_types <- c("Environmental" = "solid", 
                "Environmental Sciences and Ecology" = "dashed", 
                "All Research Areas" = "solid")

relative_growth_env_fig <- wos_research_areas_comp %>% 
  dplyr::filter(research_area %in% enviro_comp, year > 2006) %>% 
  ggplot(aes(y = n_ratio_to_2007, x = year, colour = research_area, linetype = research_area)) +
  geom_line(stat = "identity", linewidth = 1.5) +
  scale_x_continuous(breaks = seq(2007, 2022, by = 1)) +
  scale_y_continuous(limits = c(0, 22), breaks = seq(0, 22, by = 4)) + # Scale Y axis from 0 to 22
  scale_colour_manual(values = env_colour_theme, name = "Research Area") +
  scale_linetype_manual(values = line_types) + # Apply manual line types
  guides(linetype = "none") + # Remove legend for line types
  theme_classic() +
  # Customizing the theme
  theme(
    legend.position = c(0.05, 1), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1), # Ensuring the legend box aligns properly at the top-left corner
    axis.text.x = element_text(angle = 90, vjust = 0.5) # Rotating x-axis labels for better readability
  ) +
  # Adding axis labels
  labs(
    x = "Year of publication",
    y = "Relative growth compared to 2007 (15 year baseline)"
  )

relative_growth_env_fig

Save this figure

# setwd(figures_path) ggsave('study_relative_growth_env_fig.pdf', plot =
# relative_growth_env_fig, width = 5, height = 5)

10.4.2 Medical relative growth

10.4.2.1 Fig 2b-2

Comparing the relative growth in medical research

# Define the colour palette
med_colour_theme <- c("#D359A1", "#D2137F", "black") # Making colour theme to apply to plot

med_comp <-  c("Medical", "Neurosciences and Neurology", "All Research Areas")

line_types <- c("Medical" = "solid", 
                "Neurosciences and Neurology" = "dashed", 
                "All Research Areas" = "solid")

relative_growth_med_fig <- wos_research_areas_comp %>% 
  dplyr::filter(research_area %in% med_comp, year > 2006) %>% 
  ggplot(aes(y = n_ratio_to_2007, x = year, colour = research_area, linetype = research_area)) +
  geom_line(stat = "identity", linewidth = 1.5) +
  scale_x_continuous(breaks = seq(2007, 2022, by = 1)) +
  scale_y_continuous(limits = c(0, 22), breaks = seq(0, 22, by = 4)) + # Scale Y axis from 0 to 22
  scale_colour_manual(values = med_colour_theme, name = "Research Area") +
  scale_linetype_manual(values = line_types) + # Apply manual line types
  guides(linetype = "none") + # Remove legend for line types
  theme_classic() +
  # Customizing the theme
  theme(
    legend.position = c(0.05, 1), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1), # Ensuring the legend box aligns properly at the top-left corner
    axis.text.x = element_text(angle = 90, vjust = 0.5) # Rotating x-axis labels for better readability
  ) +
  # Adding axis labels
  labs(
    x = "Year of publication",
    y = "Relative growth compared to 2007 (15 year baseline)"
  )

relative_growth_med_fig

Save this figure

# setwd(figures_path) ggsave('study_relative_growth_med_fig.pdf', plot =
# relative_growth_med_fig, width = 5, height = 5)

10.4.3 Basic resarch relative growth

10.4.3.1 Fig 2b-3

Comparing relative growth in basic research

# Define the colour palette
basic_colour_theme <- c("#3C82C4", "#26276D", "black") # Making colour theme to apply to plot

basic_comp <-  c("Basic research", "Neurosciences and Neurology", "All Research Areas")

line_types <- c("Basic research" = "solid", 
                "Neurosciences and Neurology" = "dashed", 
                "All Research Areas" = "solid")

relative_growth_base_fig <- wos_research_areas_comp %>% 
  dplyr::filter(research_area %in% basic_comp, year > 2006) %>% 
  ggplot(aes(y = n_ratio_to_2007, x = year, colour = research_area, linetype = research_area)) +
  geom_line(stat = "identity", linewidth = 1.5) +
  scale_x_continuous(breaks = seq(2007, 2022, by = 1)) +
  scale_y_continuous(limits = c(0, 22), breaks = seq(0, 22, by = 4)) + # Scale Y axis from 0 to 22
  scale_colour_manual(values = basic_colour_theme, name = "Research Area") +
  scale_linetype_manual(values = line_types) + # Apply manual line types
  guides(linetype = "none") + # Remove legend for line types
  theme_classic() +
  # Customizing the theme
  theme(
    legend.position = c(0.05, 1), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1), # Ensuring the legend box aligns properly at the top-left corner
    axis.text.x = element_text(angle = 90, vjust = 0.5) # Rotating x-axis labels for better readability
  ) +
  # Adding axis labels
  labs(
    x = "Year of publication",
    y = "Relative growth compared to 2007 (15 year baseline)"
  )

relative_growth_base_fig

Save this figure

# setwd(figures_path) ggsave('study_relative_growth_base_fig.pdf', plot =
# relative_growth_base_fig, width = 5, height = 5)

10.5 Population, Exposure and Outcome

Looking at the link between the PEO elements. What was the average study design.

Below I have made a table that groups by these elements to see the average study design

It was 1 compound, 1 species and 1 behavioural class (41%)

behav_boolean <- c("behav_movement_boolean", "behav_boldness_boolean", "behav_foraging_boolean", "behav_antipredator_boolean", "behav_mating_boolean", "behav_post_mating_boolean", "behav_agression_boolean", "behav_sociality_boolean", "behav_cognition_boolean", "behav_noncat_boolean")

EIPAAB_database %>%
  dplyr::mutate(behav_n = rowSums(across(all_of(behav_boolean)), na.rm = TRUE)) %>% # how many behav class measured
  dplyr::group_by(article_id) %>% 
  dplyr::arrange(desc(behav_n)) %>% 
  dplyr::slice(1) %>% 
  dplyr::ungroup() %>% 
  dplyr::select(compound_n, species_n, behav_n) %>% 
  dplyr::group_by(compound_n, species_n, behav_n) %>% 
  dplyr::reframe(n= length(compound_n),
                 '%' = round(n/902*100,1)) %>% 
  dplyr::arrange(desc(n)) %>% 
  dplyr::slice(1:10) %>% # Only the 10 most common combinations
  gt()
compound_n species_n behav_n n %
1 1 1 374 41.5
1 1 2 160 17.7
2 1 1 78 8.6
1 1 3 63 7.0
3 1 1 45 5.0
2 1 2 34 3.8
4 1 1 24 2.7
3 1 2 15 1.7
1 2 1 13 1.4
5 1 1 9 1.0

I summary df that has the number of PEO elements in each of the 901 studies

PEO_element_summary <- EIPAAB_database %>%
    dplyr::mutate(behav_n = rowSums(across(all_of(behav_boolean)), na.rm = TRUE)) %>%
    dplyr::group_by(article_id) %>%
    dplyr::arrange(desc(behav_n)) %>%
    dplyr::slice(1) %>%
    dplyr::ungroup() %>%
    dplyr::select(compound_n, species_n, behav_n)

Looking at the number of species used

PEO_element_summary %>%
    dplyr::group_by(species_n) %>%
    dplyr::reframe(n = length(species_n), `%` = n/901) %>%
    gt()
species_n n %
1 873 0.968923418
2 25 0.027746948
3 1 0.001109878
4 1 0.001109878
5 1 0.001109878

Looking at the number of compounds used

PEO_element_summary %>%
    dplyr::group_by(compound_n) %>%
    dplyr::reframe(n = length(compound_n), `%` = n/901) %>%
    dplyr::slice(1:10) %>%
    gt()
compound_n n %
1 624 0.692563818
2 127 0.140954495
3 67 0.074361820
4 32 0.035516093
5 16 0.017758047
6 8 0.008879023
7 6 0.006659267
8 5 0.005549390
9 1 0.001109878
10 2 0.002219756

The number of different behaviours

PEO_element_summary %>%
    dplyr::group_by(behav_n) %>%
    dplyr::reframe(n = length(species_n), `%` = n/901) %>%
    gt()
behav_n n %
1 583 0.647058824
2 227 0.251942286
3 78 0.086570477
4 10 0.011098779
5 2 0.002219756
7 1 0.001109878

10.6 Species

Let’s take a closer look at species information

10.6.1 Number of distict species

There are 173 species in the EIPAAB database

EIPAAB_database %>%
    dplyr::distinct(species_name) %>%
    nrow()
## [1] 173

The number of spp each study motivation

EIPAAB_database %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::reframe(n_spp = length(unique(species_name)), total_study = length(unique(article_id)),
        rel_n = n_spp/total_study) %>%
    gt()
study_motivation n_spp total_study rel_n
Environmental 143 510 0.2803922
Medical 25 233 0.1072961
Basic research 43 158 0.2721519

There are 21 class

EIPAAB_database %>%
    dplyr::distinct(species_class) %>%
    nrow()
## [1] 21

There are 935 different groups of animals used across all 901 studies (i.e. some studies had more then one species)

EIPAAB_database %>%
    dplyr::distinct(unique_population_id) %>%
    nrow(.)
## [1] 935

10.6.2 Major taxa groups

10.6.2.1 Cladogram (Taxonomic tree)

Let’s make a Cladogram to get an overview of what taxa are in the database

spp_taxonomy <- EIPAAB_database %>%
    dplyr::group_by(species_name) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::filter(!is.na(species_family), !str_detect(species_species, "spp."), species_kingdom !=
        "Chromista") %>%
    dplyr::select("species_kingdom", "species_phylum", "species_class", "species_order",
        "species_family", "species_genus", "species_species") %>%
    dplyr::mutate(species_species = paste0(substr(species_genus, 1, 1), ". ", sub("^[^ ]+ ",
        "", species_species)))
# The mutate changes the spp name to abbreviate the Genus (e.g. Aeshna cyanea
# to A. cyanea)

Create a hierarchical structure for the plot

taxonomy <- spp_taxonomy[, c("species_kingdom", "species_phylum", "species_class",
    "species_order", "species_family", "species_genus", "species_species")]

taxonomy[] <- lapply(taxonomy, factor)

# Create a phylogenetic tree
phylo_tree <- as.phylo.formula(~species_kingdom/species_phylum/species_class/species_order/species_family/species_genus/species_species,
    data = taxonomy)

Manual creating a phylo_tree (with equal branches)

ggtree_obj <- ggtree(phylo_tree, branch.length='none', layout='circular')

# Extract the phylum information for coloring
#taxonomy$label <- paste0(substr(spp_taxonomy$species_genus, 1, 1), ". ", spp_taxonomy$species_species)
class_info <- taxonomy$species_class[match(phylo_tree$tip.label, taxonomy$species_species)]

# Add the phylum information to the ggtree object
ggtree_obj <- ggtree_obj %<+% data.frame(label = phylo_tree$tip.label, class = class_info)

# Create a color vector for the phylum levels
class_colors <- rainbow(length(unique(class_info)))
names(class_colors) <- unique(class_info)

# Plot the cladogram with colored branches
spp_cladogram <- ggtree_obj +
  geom_tiplab(size=3) + #If you want to add species names
  geom_tree(aes(color=class)) +
  scale_color_manual(values = class_colors) +
  theme(legend.position = "right")

10.6.2.2 Fig 3a

spp_cladogram

Save the figure

# setwd(figures_path) ggsave('spp_cladogram.pdf', plot = spp_cladogram, width =
# 8, height = 5)

10.6.2.3 Class level

Let’s group by class to see the major taxonomic Classes used

First removing cases where species_species was “spp.” replacing with NA for taxonomic classification

EIPAAB_database <- EIPAAB_database %>%
    dplyr::mutate(species_species = if_else(species_species == "spp.", NA, species_species))

Let’s look at the major Class

# Total number of spp
n_spp <- EIPAAB_database %>%
    dplyr::distinct(species_name) %>%
    nrow()

# Number of spp per Class and per phylum
spp_classes <- EIPAAB_database %>%
    dplyr::group_by(species_class, species_phylum) %>%
    dplyr::reframe(count_class = length(unique(species_name)), percent_class = round(count_class/n_spp *
        100, 1)) %>%
    dplyr::group_by(species_phylum) %>%
    dplyr::mutate(count_phylum = sum(count_class), percent_phylum = round(count_phylum/n_spp *
        100, 1)) %>%
    dplyr::ungroup() %>%
    dplyr::arrange(desc(percent_class))


spp_classes %>%
    dplyr::slice(1:10) %>%
    gt()
species_class species_phylum count_class percent_class count_phylum percent_phylum
Actinopterygii Chordata 71 41.0 87 50.3
Malacostraca Arthropoda 21 12.1 42 24.3
Gastropoda Mollusca 19 11.0 28 16.2
Amphibia Chordata 12 6.9 87 50.3
Branchiopoda Arthropoda 10 5.8 42 24.3
Bivalvia Mollusca 8 4.6 28 16.2
Insecta Arthropoda 8 4.6 42 24.3
Rhabditophora Platyhelminthes 5 2.9 6 3.5
Reptilia Chordata 3 1.7 87 50.3
Copepoda Arthropoda 2 1.2 42 24.3

Making a figure for the 15 most abundant Class, it terms of species diversity in the EIPAAB database

class_n_spp_fig <- spp_classes %>% 
  dplyr::arrange(desc(percent_class)) %>% # arrange the dataset
  dplyr::slice(1:15) %>% # Take only the most diverse 15 Class
  dplyr::mutate(species_class = fct_reorder(species_class, percent_class), # Order by diversity
                species_phylum = fct_reorder(species_phylum, desc(percent_phylum))) %>% # Order by diversity
  ggplot(aes(x=species_class, y=count_class, color = species_phylum)) +
  geom_segment(aes(x=species_class, xend=species_class, y=0, yend=count_class)) +
  geom_point(size=4) +
  geom_text(aes(label = count_class), 
            hjust=-1.2, 
            size=3.5, 
            color="black") +
  scale_colour_brewer(palette= "Dark2") +
  coord_flip() +
  ylim(0, 75) +
  theme_classic() +
   labs(
    x = "",
    y = "Number of distict species in the database"
  ) +
   theme(legend.position = c(0., 0.05),  # Positioning the legend inside the plot
    legend.justification = c(-3, 0),   # Bottom left inside the plot
    legend.box.just = "right",
    legend.background = element_rect(fill=alpha('white', 0.5))
   )

class_n_spp_fig

Save the figure

# setwd(figures_path) ggsave('spp_class_n_spp_fig.pdf', plot = class_n_spp_fig,
# width = 5, height = 5)

10.6.2.4 Phylum level

Here’s a look at the % at the phylum level

# In the class summary we also included percent_phylum
spp_classes %>%
    dplyr::group_by(species_phylum) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::select(-species_class, -count_class, -percent_class) %>%
    dplyr::arrange(desc(percent_phylum)) %>%
    gt()
species_phylum count_phylum percent_phylum
Chordata 87 50.3
Arthropoda 42 24.3
Mollusca 28 16.2
Platyhelminthes 6 3.5
Annelida 3 1.7
Echinodermata 3 1.7
Cnidaria 2 1.2
Rotifera 2 1.2

A ring chart at the phylum level

ring_plot_df <- spp_classes %>%
    dplyr::slice(1:15) %>%
    dplyr::group_by(species_phylum) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::select(species_phylum, count_phylum) %>%
    dplyr::mutate(percent_phylum = count_phylum/sum(count_phylum)) %>%
    dplyr::arrange(desc(percent_phylum))

# Compute the cumulative percentages (top of each rectangle)
ring_plot_df$ymax = cumsum(ring_plot_df$percent_phylum)

# Compute the bottom of each rectangle
ring_plot_df$ymin = c(0, head(ring_plot_df$ymax, n = -1))

# Compute label position
ring_plot_df$labelPosition <- (ring_plot_df$ymax + ring_plot_df$ymin)/2

# Compute a good label
ring_plot_df$label <- paste0(ring_plot_df$species_phylum, "\n (n = ", ring_plot_df$count_phylum,
    ")")


phylum_ring_fig <- ring_plot_df %>%
    dplyr::mutate(species_phylum = fct_reorder(species_phylum, desc(percent_phylum))) %>%
    ggplot(aes(ymax = ymax, ymin = ymin, xmax = 4, xmin = 3, fill = species_phylum)) +
    geom_rect() + coord_polar(theta = "y") + geom_label(x = 5, aes(y = labelPosition,
    label = label), size = 3, alpha = 0.8) + scale_fill_brewer(palette = "Dark2") +
    xlim(c(2, 5)) + theme_void() + theme(legend.position = "none")

phylum_ring_fig

Save this plot

# setwd(figures_path) ggsave('spp_phylum_ring_fig.pdf', plot = phylum_ring_fig,
# width = 5, height = 5)

10.6.3 Taxa representation

Now we will look at how many times each phylum, class, order, family, genus, species appear in the database

First we will make a dataset that counts the number of species within each phylum, class, order, family, and genus.

# Step 1: Separate and pivot the data
lineage_data <- EIPAAB_database %>%
    pivot_longer(cols = c("species_phylum", "species_class", "species_order", "species_family",
        "species_genus", "species_species"), names_to = "lineage_level", values_to = "classification") %>%
    dplyr::mutate(lineage_level = str_remove(lineage_level, "species_"))


# Define the order
lineage_levels_order <- c("phylum", "class", "order", "family", "genus", "species")

# Step 2: Create parent-child relationships
lineage_data <- lineage_data %>%
    group_by(unique_row_id) %>%
    mutate(parent = case_when(lineage_level == "phylum" ~ "Animalia", lineage_level ==
        "class" ~ lag(classification, 1), lineage_level == "order" ~ lag(classification,
        1), lineage_level == "family" ~ lag(classification, 1), lineage_level ==
        "genus" ~ lag(classification, 1), lineage_level == "species" ~ lag(classification,
        1), )) %>%
    ungroup()

Here we sum the total number of species used in the database across each taxonomic classification

n_rows <- EIPAAB_database %>%
    nrow()

lineage_count_use <- lineage_data %>%
    dplyr::group_by(classification, lineage_level, parent) %>%
    dplyr::reframe(classification_count = length(unique_row_id), classification_percent = round(classification_count/n_rows *
        100, 1))

10.6.3.1 Fig 3b

Making a plot to look at the 15 most commonly used class, but you can do this at any of the taxonomic levels

class_use_fig <- lineage_count_use %>% 
  dplyr::filter(lineage_level == "class") %>% 
  dplyr::arrange(desc(classification_percent)) %>% 
  dplyr::slice(1:15) %>% 
  dplyr::mutate(classification = fct_reorder(classification, classification_percent),
                parent = fct_reorder(parent, desc(classification_percent))) %>%
  ggplot(aes(x=classification, y=classification_percent, color = parent)) +
  geom_segment(aes(x=classification, xend=classification, y=0, yend=classification_percent)) +
  geom_point(size=4) +
  geom_text(aes(label = paste0(round(classification_percent,2), "%")), 
            hjust=-0.5, 
            size=3.5, 
            color="black") +
  scale_colour_brewer(palette= "Dark2") +
  coord_flip() +
  ylim(0, 100) +
  theme_classic() +
   labs(
    x = "",
    y = "Percentage representation in the database"
  ) +
   theme(legend.position = c(0., 0.05),  # Positioning the legend inside the plot
    legend.justification = c(-3, 0),   # Bottom left inside the plot
    legend.box.just = "right",
    legend.background = element_rect(fill=alpha('white', 0.5))
   )

class_use_fig

Save plot

# setwd(figures_path) ggsave('spp_class_use_fig.pdf', plot = class_use_fig,
# width = 5, height = 5)

Table of occurrence, and percentage occurrence

lineage_count_use %>%
    dplyr::filter(lineage_level == "class") %>%
    dplyr::group_by(classification) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::arrange(desc(classification_percent)) %>%
    gt()
classification lineage_level parent classification_count classification_percent
Actinopterygii class Chordata 1311 75.4
Branchiopoda class Arthropoda 130 7.5
Gastropoda class Mollusca 69 4.0
Malacostraca class Arthropoda 61 3.5
Amphibia class Chordata 44 2.5
Rhabditophora class Platyhelminthes 29 1.7
Bivalvia class Mollusca 25 1.4
Hydrozoa class Cnidaria 22 1.3
Insecta class Arthropoda 17 1.0
Cephalopoda class Mollusca 7 0.4
Reptilia class Chordata 6 0.3
Polychaeta class Annelida 4 0.2
Trematoda class Platyhelminthes 3 0.2
Asteroidea class Echinodermata 1 0.1
Clitellata class Annelida 1 0.1
Copepoda class Arthropoda 2 0.1
Echinoidea class Echinodermata 1 0.1
Holothuroidea class Echinodermata 1 0.1
Mammalia class Chordata 2 0.1
Monogononta class Rotifera 2 0.1
Thecostraca class Arthropoda 1 0.1

Here’s break down by Phylum

ring_use_plot_df <- lineage_count_use %>%
    dplyr::filter(lineage_level == "phylum") %>%
    dplyr::arrange(desc(classification_percent)) %>%
    dplyr::mutate(classification_percent = round(classification_percent, 2)) %>%
    dplyr::slice(1:8)

# Compute the cumulative percentages (top of each rectangle)
ring_use_plot_df$ymax = cumsum(ring_use_plot_df$classification_percent)

# Compute the bottom of each rectangle
ring_use_plot_df$ymin = c(0, head(ring_use_plot_df$ymax, n = -1))

# Compute label position
ring_use_plot_df$labelPosition <- (ring_use_plot_df$ymax + ring_use_plot_df$ymin)/2

# Compute a good label
ring_use_plot_df$label <- paste0(ring_use_plot_df$classification, "\n (", ring_use_plot_df$classification_percent,
    "%)")


phylum_use_ring_fig <- ring_use_plot_df %>%
    dplyr::mutate(classification = fct_reorder(classification, desc(classification_percent))) %>%
    ggplot(aes(ymax = ymax, ymin = ymin, xmax = 4, xmin = 3, fill = classification)) +
    geom_rect() + coord_polar(theta = "y") + geom_label(x = 5, aes(y = labelPosition,
    label = label), size = 3, alpha = 0.8) + scale_fill_brewer(palette = "Dark2") +
    xlim(c(2, 5)) + theme_void()
# theme(legend.position = 'none')

phylum_use_ring_fig

Save the figure

# setwd(figures_path) ggsave('spp_phylum_use_ring_fig.pdf', plot =
# phylum_use_ring_fig, width = 5, height = 5)

10.6.3.2 Taxa representation by study motivation

Making a data set that looks at relative representation by each motivation, and the total

lineage_count_use_motivation <- lineage_data %>%
    dplyr::group_by(study_motivation, lineage_level, parent, classification) %>%
    dplyr::reframe(classification_count = length(unique_row_id)) %>%
    dplyr::group_by(study_motivation, lineage_level) %>%
    dplyr::mutate(n_motivation = sum(classification_count)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(classification_percent = (classification_count/n_motivation) *
        100)

lineage_count_use_all <- lineage_data %>%
    dplyr::group_by(lineage_level, parent, classification) %>%
    dplyr::reframe(classification_count = length(unique_row_id)) %>%
    dplyr::group_by(lineage_level) %>%
    dplyr::mutate(n_motivation = sum(classification_count)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(classification_percent = (classification_count/n_motivation) *
        100) %>%
    dplyr::mutate(study_motivation = "All")

lineage_count_use_motivation <- lineage_count_use_motivation %>%
    rbind(., lineage_count_use_all) %>%
    dplyr::mutate(study_motivation = fct_relevel(study_motivation, "All", "Environmental",
        "Medical", "Basic research"))

10.6.3.3 Fig S3

Here’s a tile plot to compare the use of different taxa across the study motivations

class_order_df <- lineage_count_use %>%
    dplyr::filter(lineage_level == "class") %>%
    dplyr::arrange(classification_percent) %>%
    dplyr::mutate(class_order = 1:nrow(.)) %>%
    dplyr::select(classification, class_order)


class_use_motivation_fig <- lineage_count_use_motivation %>%
    dplyr::filter(lineage_level == "class") %>%
    dplyr::full_join(., class_order_df, by = "classification") %>%
    dplyr::mutate(classification = fct_reorder(classification, class_order), parent = fct_reorder(parent,
        desc(class_order))) %>%
    ggplot(aes(x = study_motivation, y = classification, fill = classification_percent)) +
    geom_tile() + geom_text(aes(label = paste0(round(classification_percent, 1),
    "%"))) + scale_fill_gradient(name = expression("Relative\nabudance (%)"), low = "#FFFFFF",
    high = "#231F20") + theme_classic() + labs(x = "Study motivation", y = "Taxonomic class")
class_use_motivation_fig

Save the figure

# setwd(figures_path) ggsave('spp_class_use_motivation_fig.pdf', plot =
# class_use_motivation_fig, width = 5, height = 5)

10.6.3.4 Most common species

Let’s see what the most common species were. This is calculated at the population level (i.e. doesn’t count each species mutiple times if multiple compounds were used in a single article; unique_population_id)

n_total <- EIPAAB_database %>%
    dplyr::group_by(unique_population_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::reframe(n = length(unique_population_id)) %>%
    nrow(.)

n_spp <- EIPAAB_database %>%
    dplyr::group_by(unique_population_id, species_ncbi_taxonomy_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(species_name, species_ncbi_taxonomy_id) %>%
    dplyr::reframe(n = length(species_name), percent = round(n/n_total * 100, 1)) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::mutate(spp_number = 1:nrow(.))

n_spp %>%
    dplyr::slice(1:15) %>%
    gt()
species_name species_ncbi_taxonomy_id n percent spp_number
Danio rerio NCBI:txid7955 412 44.1 1
Daphnia magna NCBI:txid35525 54 5.8 2
Pimephales promelas NCBI:txid90988 32 3.4 3
Betta splendens NCBI:txid158456 26 2.8 4
Poecilia reticulata NCBI:txid8081 26 2.8 5
Gambusia holbrooki NCBI:txid37273 18 1.9 6
Carassius auratus NCBI:txid7957 16 1.7 7
Oryzias latipes NCBI:txid8090 16 1.7 8
Gasterosteus aculeatus NCBI:txid69293 14 1.5 9
Oncorhynchus mykiss NCBI:txid8022 12 1.3 10
Perca fluviatilis NCBI:txid8168 11 1.2 11
Xenopus laevis NCBI:txid8355 10 1.1 12
Salmo trutta NCBI:txid8032 8 0.9 13
Salmo salar NCBI:txid8030 7 0.7 14
Sepia officinalis NCBI:txid6610 7 0.7 15

Making a broad category of abundance (article_n_group) to make the summary and figure more digestible

n_spp_fig_data <- n_spp %>%
    dplyr::mutate(species_ncbi_taxonomy_id = fct_reorder(species_ncbi_taxonomy_id,
        desc(n))) %>%
    dplyr::mutate(article_n_group = case_when(n == 1 ~ "One only", n >= 2 & n <=
        5 ~ "Between 2 and 5", n >= 5 & n <= 10 ~ "Between 6 and 10", n >= 10 ~ "Greater than 10",
        TRUE ~ "Others"))

This is the number of species in each category

article_n_group_summary <- n_spp_fig_data %>%
    dplyr::group_by(article_n_group) %>%
    dplyr::reframe(n_cat = length(species_name))
article_n_group_summary %>%
    gt()
article_n_group n_cat
Between 2 and 5 53
Between 6 and 10 6
Greater than 10 11
One only 103

10.6.3.5 Fig S2

Making a plot to show the distribution of species use in the EIPAAB database

n_spp_fig <- n_spp_fig_data %>% 
  dplyr::mutate(article_n_group = fct_relevel(article_n_group, "Greater than 10", "Between 6 and 10", "Between 2 and 5", "One only")) %>% 
  ggplot(aes(y = n, x = spp_number, color = article_n_group)) +
  geom_line(linewidth = 1, alpha = 0.2) +
  geom_point(stat = "identity", size = 1, alpha = 0.8) +
  scale_color_manual(
    values = c(
    "One only" = "#E94039", 
    "Between 2 and 5" = "#F18E76", 
    "Between 6 and 10" = "#877FBC", 
    "Greater than 10" = "#4D479D"
    ),
  labels = c(
      "One only" = "One only (n = 104)",
      "Between 2 and 5" = "Between 2 and 5 (n = 53)",
      "Between 6 and 10" = "Between 6 and 10 (n = 11)",
      "Greater than 10" = "Greater than 10 (n = 6)"
      )
  ) +  # Set colours for each category
  theme_classic() +
  theme(
    legend.position = c(-0.3, 0.4),  # Positioning the legend inside the plot
    legend.justification = c(-3, 0),   # Bottom left inside the plot
    legend.box.just = "right"
    ) +
  labs(
    x = paste0("Species (1-174)"),
    y = "Number of articles",
    color = "Article number category"
  )

n_spp_fig

Save the figure

# setwd(figures_path) ggsave('spp_n_spp_fig.pdf', plot = n_spp_fig, width = 5,
# height = 5)

Making a list of the most common 15 species

n_spp_used <- EIPAAB_database %>%
    dplyr::distinct(unique_population_id) %>%
    nrow(.)

top_15_spp_list <- EIPAAB_database %>%
    dplyr::group_by(species_name) %>%
    dplyr::summarise(n = length(unique(unique_population_id)), .groups = "drop") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:15) %>%
    dplyr::pull(species_name) %>%
    as.list()

Making a summary dataframe base on study motivation

common_species <- EIPAAB_database %>%
    dplyr::filter(species_name %in% top_15_spp_list) %>%
    dplyr::group_by(species_name, study_motivation) %>%
    dplyr::summarise(n = length(unique(article_id)), .groups = "drop") %>%
    tidyr::complete(species_name, study_motivation, fill = list(n = 0))


species_order <- common_species %>%
    group_by(species_name) %>%
    summarise(total_n = sum(n), .groups = "drop") %>%
    arrange(desc(total_n)) %>%
    ungroup()


common_species <- common_species %>%
    inner_join(species_order, by = "species_name") %>%
    mutate(species_name = fct_reorder(species_name, total_n), study_motivation = fct_relevel(study_motivation,
        "Environmental", "Medical", "Basic research"))

10.6.3.6 Fig 3c

A plot of the number of times each of the 15 overall most common species appeared in articles within the EIPAAB databse by study motivation. It’s a little hard to see in the chunk output, try viewing in an external window.

top_15_spp_fig <- common_species %>%
    ggplot(aes(x = species_name, y = n, colour = study_motivation, fill = study_motivation,
        group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = n), hjust = -0.6, size = 3.5, color = "black", position = position_dodge(width = 0.8)) +
    scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
    scale_fill_manual(values = motivation_colour_theme, name = "Study motivation") +
    coord_flip() + theme_classic() + labs(x = "", y = "Number of studies") + theme()

top_15_spp_fig

Save the figure

# setwd(figures_path) ggsave('spp_top_15_spp_fig.pdf', plot = top_15_spp_fig,
# width = 5, height = 10)

Summarising the top 10 in each motivation more specifically

spp_moitivation_summary <- EIPAAB_database %>%
    dplyr::group_by(species_name, study_motivation) %>%
    dplyr::summarise(n = length(unique(unique_population_id)), .groups = "drop") %>%
    tidyr::complete(species_name, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(prop = n/total) %>%
    dplyr::select(-total)

This plot shows the top 10 in each motivation

top_10_env_spp <- spp_moitivation_summary %>%
    dplyr::filter(study_motivation == "Environmental") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(species_name = fct_reorder(species_name, n)) %>%
    ggplot(aes(x = species_name, y = n)) + geom_col(width = 0.01, colour = "#60BD6C",
    fill = "#60BD6C") + geom_point(size = 2, colour = "#60BD6C", fill = "#60BD6C") +
    geom_text(aes(label = n), hjust = -0.6, size = 3.5, color = "black") + coord_flip() +
    theme_classic() + labs(x = "", y = "Number of studies", title = "Environmental") +
    theme(plot.title = element_text(size = 12))

top_10_med_spp <- spp_moitivation_summary %>%
    dplyr::filter(study_motivation == "Medical") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(species_name = fct_reorder(species_name, n)) %>%
    ggplot(aes(x = species_name, y = n)) + geom_col(width = 0.01, colour = "#D359A1",
    fill = "#D359A1") + geom_point(size = 2, colour = "#D359A1", fill = "#D359A1") +
    geom_text(aes(label = n), hjust = -0.6, size = 3.5, color = "black") + coord_flip() +
    theme_classic() + labs(x = "", y = "Number of studies", title = "Medical") +
    theme(plot.title = element_text(size = 12))

top_10_base_spp <- spp_moitivation_summary %>%
    dplyr::filter(study_motivation == "Basic research") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(species_name = fct_reorder(species_name, n)) %>%
    ggplot(aes(x = species_name, y = n)) + geom_col(width = 0.01, colour = "#3C82C4",
    fill = "#3C82C4") + geom_point(size = 2, colour = "#3C82C4", fill = "#3C82C4") +
    geom_text(aes(label = n), hjust = -0.6, size = 3.5, color = "black") + coord_flip() +
    theme_classic() + labs(x = "", y = "Number of studies", title = "Basic") + theme(plot.title = element_text(size = 12))

Here’s a plot to compare the top 10 spp in each study motivation more specifically

top_10_combind_plot <- grid.arrange(top_10_env_spp, top_10_med_spp, top_10_base_spp,
    ncol = 3)

Looking at the number of distinct species used in each motivation group

EIPAAB_database %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::reframe(n_motivation = n_distinct(article_id), n_distinct_spp = n_distinct(species_name)) %>%
    gt()
study_motivation n_motivation n_distinct_spp
Environmental 510 143
Medical 233 25
Basic research 158 43

10.6.4 Species habitat

First checking how many species have IUCN data, which we will use to assess habitat differences

species_iucn_summary <- EIPAAB_database %>%
    dplyr::group_by(species_name) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(species_iucn_bin = if_else(is.na(species_iucn_doi), "No", "Yes")) %>%
    dplyr::group_by(species_iucn_bin) %>%
    dplyr::reframe(n = length(species_iucn_bin))

species_iucn_summary %>%
    gt()
species_iucn_bin n
No 67
Yes 106

Summarising the IUNC habitat type, some species will have multiple habitats, so we split the string by the sepreate (;)

habitat_summary <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(species_iucn_habitat) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_iucn_habitat = str_trim(species_iucn_habitat)) %>%
  tidyr::separate_rows(species_iucn_habitat, sep = ";") %>% # each spp has multiple habitats the string needs spliting
  dplyr::group_by(species_iucn_habitat) %>% 
  dplyr::reframe(n_articles = sum(n)) %>% # now a sum for each habitat
  arrange(desc(n_articles))
habitat_summary %>% 
  gt()
species_iucn_habitat n_articles
Wetlands inland 738
Artificial or Aquatic and Marine 187
NA 164
Marine Neritic 99
Marine Coastal or Supratidal 44
Marine Intertidal 27
Forest 23
Grassland 22
Artificial or Terrestrial 21
Shrubland 18
Savanna 13
Marine Oceanic 10
Unknown 2

Checking how many freshwater vs marine species there are. Wetlands inland categories are freshwater bodies where as Marine have multiple categories (Marine Neritic, Marine Coastal or Supratidal, Marine Intertidal, Marine Oceanic).

habitat_summary %>% 
  dplyr::filter(str_starts(species_iucn_habitat, "Marine") | species_iucn_habitat == "Wetlands inland") %>% # Only habitats of interest 
  dplyr::mutate(aquatic_type = if_else(species_iucn_habitat == "Wetlands inland", "Freshwater", "Marine")) %>% # New category
  dplyr::group_by(aquatic_type) %>% 
  dplyr::reframe(n_articles = sum(n_articles)) %>% # Final sums
  dplyr::ungroup() %>% 
  dplyr::mutate(n_total = sum(n_articles),
                percent =  round(n_articles/n_total*100,1)) %>% 
  gt()
aquatic_type n_articles n_total percent
Freshwater 738 918 80.4
Marine 180 918 19.6

Lets break this up by study motivation

habitat_summary_all <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation, species_iucn_habitat) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_iucn_habitat = str_trim(species_iucn_habitat)) %>%
  tidyr::separate_rows(species_iucn_habitat, sep = ";") %>% # each spp has multiple habitats the string needs spliting
  dplyr::group_by(species_iucn_habitat, study_motivation) %>% 
  dplyr::reframe(n_articles = sum(n)) %>% # now a sum for each habitat
  arrange(desc(n_articles))
habitat_summary_all %>% 
  gt()
species_iucn_habitat study_motivation n_articles
Wetlands inland Environmental 384
Wetlands inland Medical 223
Artificial or Aquatic and Marine Environmental 135
Wetlands inland Basic research 131
NA Environmental 131
Marine Neritic Environmental 80
Artificial or Aquatic and Marine Basic research 41
Marine Coastal or Supratidal Environmental 33
NA Basic research 22
Marine Intertidal Environmental 19
Artificial or Terrestrial Environmental 15
Marine Neritic Basic research 15
Grassland Environmental 13
Shrubland Environmental 13
Forest Environmental 12
Artificial or Aquatic and Marine Medical 11
NA Medical 11
Savanna Environmental 8
Forest Basic research 7
Marine Coastal or Supratidal Basic research 7
Marine Intertidal Basic research 7
Grassland Basic research 5
Artificial or Terrestrial Basic research 4
Forest Medical 4
Grassland Medical 4
Marine Coastal or Supratidal Medical 4
Marine Neritic Medical 4
Marine Oceanic Environmental 4
Marine Oceanic Medical 4
Savanna Basic research 3
Shrubland Basic research 3
Artificial or Terrestrial Medical 2
Marine Oceanic Basic research 2
Savanna Medical 2
Shrubland Medical 2
Unknown Environmental 2
Marine Intertidal Medical 1

Selecting only habitats of interest and allocating to Freshwater or Marine

freshwater_marine <- habitat_summary_all %>% 
  dplyr::filter(str_starts(species_iucn_habitat, "Marine") | species_iucn_habitat == "Wetlands inland") %>% # Only habitats of interest 
  dplyr::mutate(aquatic_type = if_else(species_iucn_habitat == "Wetlands inland", "Freshwater", "Marine")) %>% # New category
  dplyr::group_by(aquatic_type, study_motivation) %>% 
  dplyr::reframe(n_articles = sum(n_articles)) %>% # Final sums
  dplyr::group_by(study_motivation) %>% 
  dplyr::mutate(n_cat = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(prop =  n_articles/n_cat) # A proportion of those identify as freshwater vs marine

freshwater_marine %>% 
  gt()
aquatic_type study_motivation n_articles n_cat prop
Freshwater Environmental 384 520 0.73846154
Freshwater Medical 223 236 0.94491525
Freshwater Basic research 131 162 0.80864198
Marine Environmental 136 520 0.26153846
Marine Medical 13 236 0.05508475
Marine Basic research 31 162 0.19135802

Here’s a figure version of this summary

aquatic_type_order <- c("Freshwater", "Marine")

# Calculate cumulative positions for text labels
freshwater_marine <- freshwater_marine %>%
    dplyr::mutate(aquatic_type = factor(aquatic_type, levels = aquatic_type_order)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::arrange(desc(aquatic_type)) %>%
    dplyr::mutate(cumulative_prop = cumsum(prop) - prop/2)

# Define the black and grey color theme
color_theme <- c("#7FAB91", "#2A4A64")

# Create the plot
habitat_fig <- freshwater_marine %>%
    mutate(study_motivation = fct_relevel(study_motivation, "Basic research", "Medical",
        "Environmental")) %>%
    ggplot(aes(y = prop, x = study_motivation, fill = aquatic_type, group = aquatic_type)) +
    geom_bar(stat = "identity", width = 0.9) + geom_text(aes(label = round(prop,
    2), y = cumulative_prop), color = "white", size = 3) + scale_fill_manual(values = color_theme,
    name = "Habitat") + theme_classic() + theme(legend.position = "right") + labs(x = "Study motivation",
    y = "Proportion of all species assigned to freshwater or marine habitat") + coord_flip()

habitat_fig

Save the figure

# setwd(figures_path) ggsave('spp_habitat_fig.pdf', plot = habitat_fig, width =
# 10, height = 5)

We should also consider how many records did not inculde IUCN reports and thus habitat.

Let’s make a plot that shows how many didn’t have an assigned IUNC habitat. To add to the above figure.

no_habitat <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>%
  dplyr::mutate(species_iucn_bin = if_else(is.na(species_iucn_doi), "No", "Yes")) %>% 
  dplyr::group_by(species_iucn_bin) %>% 
  dplyr::reframe(n = length(species_iucn_bin))
  

n_total <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>%
  nrow(.)

no_habitat <- no_habitat %>%
  dplyr::mutate(prop = n/n_total)

no_habitat %>% 
  gt()
species_iucn_bin n prop
No 163 0.1743316
Yes 772 0.8256684

Here’s the plot

# Define the black and grey color theme
black_and_grey <- c("#BCBEC0", "#414042")

yes_order <- c("Yes", "No")

# Calculate cumulative positions for text labels
habitat_info_df_fig <- no_habitat %>%
  dplyr::mutate(species_iucn_bin = factor(species_iucn_bin, levels = yes_order)) %>% 
  dplyr::arrange(desc(species_iucn_bin)) %>% 
  dplyr::mutate(cumulative_prop = cumsum(prop) - prop / 2)

habitat_info_fig <- habitat_info_df_fig %>%
  dplyr::mutate(species_iucn_bin = factor(species_iucn_bin, levels = yes_order)) %>% 
  ggplot(aes(y = prop, x = 1, fill = species_iucn_bin)) +
  geom_bar(stat = "identity", width = 0.1) +
  geom_text(aes(label = round(prop, 2), y = cumulative_prop), color = "white") + 
  scale_fill_manual(values = black_and_grey, name = "Habitat") + 
  theme_classic() +
  theme(legend.position = "right",
        axis.text.x = element_blank(),  # Remove x-axis text
        axis.ticks.x = element_blank()  # Remove x-axis ticks 
        ) +
  labs(
    x = "",
    y = "Proportion of species tested in the database"
  )
habitat_info_fig

Save the plot

# setwd(figures_path) ggsave('spp_habitat_info_fig.pdf', plot =
# habitat_info_fig, width = 5, height = 10)

10.6.5 Species life satge

Let’s get an overall summary first, without Unknown or not specified life stages

EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(species_stage) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_stage = str_trim(species_stage)) %>%
  tidyr::separate_rows(species_stage, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::filter(species_stage != "Unknown or not specified") %>% 
  dplyr::group_by(species_stage) %>% 
  dplyr::reframe(n_articles = sum(n)) %>%  # now a sum for each habitat
  dplyr::mutate(total_stages = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(overall_percent = round(n_articles/total_stages*100,1)) %>% 
  gt()
species_stage n_articles total_stages overall_percent
Adult 443 831 53.3
Egg or embryo 46 831 5.5
Juvenile 123 831 14.8
Larvae 219 831 26.4

Let’s take a look at spp life stages used in the EIPAAB database on study motivation

First those that didn’t report it

stage_summary_all <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation, species_stage) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_stage = str_trim(species_stage)) %>%
  tidyr::separate_rows(species_stage, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(species_stage, study_motivation) %>% 
  dplyr::reframe(n_total = sum(n)) %>%  # now a sum for each habitat
  dplyr::group_by(study_motivation) %>% 
  dplyr::mutate(n_motivation = sum(n_total),
                percent = round(n_total/n_motivation*100,1)) %>% 
  dplyr::ungroup()

stage_summary_all %>%
  dplyr::filter(species_stage == "Unknown or not specified") %>% 
  dplyr::mutate(percent_reported = 100-percent) %>% 
  dplyr::rename(percent_not_report = percent) %>% 
  gt()
species_stage study_motivation n_total n_motivation percent_not_report percent_reported
Unknown or not specified Environmental 100 586 17.1 82.9
Unknown or not specified Medical 22 245 9.0 91.0
Unknown or not specified Basic research 44 166 26.5 73.5

A table by study motivation and age class

stage_order <- c("Adult", "Juvenile", "Larvae", "Egg or embryo")

stage_summary_reported <- stage_summary_all %>%
    dplyr::filter(species_stage != "Unknown or not specified") %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(n_motivation = sum(n_total), percent = round(n_total/n_motivation *
        100, 1), species_stage = factor(species_stage, levels = stage_order)) %>%
    dplyr::ungroup() %>%
    dplyr::arrange(species_stage)

stage_summary_reported %>%
    gt()
species_stage study_motivation n_total n_motivation percent
Adult Environmental 236 486 48.6
Adult Medical 134 223 60.1
Adult Basic research 73 122 59.8
Juvenile Environmental 92 486 18.9
Juvenile Medical 14 223 6.3
Juvenile Basic research 17 122 13.9
Larvae Environmental 127 486 26.1
Larvae Medical 64 223 28.7
Larvae Basic research 28 122 23.0
Egg or embryo Environmental 31 486 6.4
Egg or embryo Medical 11 223 4.9
Egg or embryo Basic research 4 122 3.3

Same data presented as a figure

For life stages that are described, what is the breakdown

# Define the black and grey color theme
color_theme <- c("#A14323", "#D86C2F", "#EE9E5A", "#F3E9A5")


# Calculate cumulative positions for text labels
stage_summary_reported <- stage_summary_reported %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::arrange(desc(species_stage)) %>%
    dplyr::mutate(cumulative_percent = cumsum(percent) - percent/4)

# Create the plot
life_stage_fig <- stage_summary_reported %>%
    mutate(study_motivation = fct_relevel(study_motivation, "Basic research", "Medical",
        "Environmental")) %>%
    ggplot(aes(y = percent, x = study_motivation, fill = species_stage, group = species_stage)) +
    geom_bar(stat = "identity", width = 0.9) + geom_text(aes(label = percent, y = cumulative_percent),
    color = "white", size = 3) + scale_fill_manual(values = color_theme, name = "Life stage") +
    theme_classic() + theme(legend.position = "right") + labs(x = "Study motivation",
    y = "Percent of all species assigned to a life stage") + coord_flip()

life_stage_fig

Save the figure

# setwd(figures_path) ggsave('spp_life_stage_fig.pdf', plot = life_stage_fig,
# width = 10, height = 5)

Let’s also look at how many where unknown or not described overall

stage_summary_info <- stage_summary_all %>%
    dplyr::mutate(stage_reported = if_else(species_stage == "Unknown or not specified",
        "No", "Yes")) %>%
    dplyr::group_by(stage_reported) %>%
    dplyr::reframe(n = sum(n_total))

n_total <- stage_summary_info %>%
    dplyr::reframe(n_total = sum(n)) %>%
    pull(n_total)

stage_summary_info <- stage_summary_info %>%
    dplyr::mutate(prop = n/n_total)

Here’s the plot

# Define the black and grey color theme
black_and_grey <- c("#BCBEC0", "#414042")

yes_order <- c("Yes", "No")

# Calculate cumulative positions for text labels
stage_summary_info <- stage_summary_info %>%
  dplyr::mutate(stage_reported = factor(stage_reported, levels = yes_order)) %>% 
  dplyr::arrange(desc(stage_reported)) %>% 
  dplyr::mutate(cumulative_prop = cumsum(prop) - prop / 2)

stage_info_fig <- stage_summary_info %>%
  dplyr::mutate(stage_reported = factor(stage_reported, levels = yes_order)) %>% 
  ggplot(aes(y = prop, x = 1, fill = stage_reported)) +
  geom_bar(stat = "identity", width = 0.9) +
  geom_text(aes(label = round(prop, 2), y = cumulative_prop), color = "white") + 
  scale_fill_manual(values = black_and_grey, name = "Stage reported") + 
  theme_classic() +
  theme(legend.position = "right",
        axis.text.x = element_blank(),  # Remove x-axis text
        axis.ticks.x = element_blank()  # Remove x-axis ticks 
  ) +
  labs(
    x = "",
    y = "Proportion of species tested in the database"
  )
stage_info_fig

Save the figure

# setwd(figures_path) ggsave('spp_stage_info_fig.pdf', plot = stage_info_fig,
# width = 2.5, height = 5)

10.6.6 Species sex

First overall breakdown by female and male without including unreported or hermaphroditic animals

EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(species_sex) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_sex = str_trim(species_sex)) %>%
  tidyr::separate_rows(species_sex, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(species_sex) %>% 
  dplyr::summarise(n_articles = sum(n), .groups = 'drop') %>%  # now a sum for each habitat
  tidyr::complete(species_sex, 
                  fill = list(n_articles = 0)) %>%  # make a full df with empty categories = 0
  dplyr::ungroup() %>%
  dplyr::filter(species_sex == "Female" | species_sex == "Male") %>% 
  dplyr::mutate(total_sex = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(overall_percent = round(n_articles/total_sex*100,1)) %>% 
  gt()
species_sex n_articles total_sex overall_percent
Female 280 623 44.9
Male 343 623 55.1

Let’s take a look at the sex of spp used in the EIPAAB database

sex_summary_all <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation, species_sex) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_sex = str_trim(species_sex)) %>%
  tidyr::separate_rows(species_sex, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(species_sex, study_motivation) %>% 
  dplyr::summarise(n_articles = sum(n), .groups = 'drop') %>%  # now a sum for each habitat
  tidyr::complete(species_sex, study_motivation, 
                  fill = list(n_articles = 0)) %>%  # make a full df with empty categories = 0
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation) %>% 
  dplyr::mutate(total_sex = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(overall_prop = n_articles/total_sex)
sex_summary_all %>% 
  gt()
species_sex study_motivation n_articles total_sex overall_prop
Female Environmental 136 645 0.21085271
Female Medical 91 322 0.28260870
Female Basic research 53 206 0.25728155
Hermaphrodites Environmental 4 645 0.00620155
Hermaphrodites Medical 0 322 0.00000000
Hermaphrodites Basic research 0 206 0.00000000
Male Environmental 180 645 0.27906977
Male Medical 99 322 0.30745342
Male Basic research 64 206 0.31067961
Unknown or not specified Environmental 325 645 0.50387597
Unknown or not specified Medical 132 322 0.40993789
Unknown or not specified Basic research 89 206 0.43203883

Let’s look at just the proportion of those defined as male and female

sex_male_female <- sex_summary_all %>%
    dplyr::filter(species_sex == "Female" | species_sex == "Male") %>%
    dplyr::select(-total_sex, -overall_prop) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_male_female = sum(n_articles)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n_articles/total_male_female * 100, 1))

sex_male_female %>%
    gt()
species_sex study_motivation n_articles total_male_female percent
Female Environmental 136 316 43.0
Female Medical 91 190 47.9
Female Basic research 53 117 45.3
Male Environmental 180 316 57.0
Male Medical 99 190 52.1
Male Basic research 64 117 54.7

Making the plot

sex_order <- c("Female", "Male")

color_theme <- c("#eb4729", "#1b909a")

# Calculate cumulative positions for text labels
sex_male_female <- sex_male_female %>%
    dplyr::mutate(species_sex = factor(species_sex, levels = sex_order)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::arrange(desc(species_sex)) %>%
    dplyr::mutate(cumulative_percent = cumsum(percent) - percent/2)

# Create the plot
sex_fig <- sex_male_female %>%
    mutate(study_motivation = fct_relevel(study_motivation, "Basic research", "Medical",
        "Environmental")) %>%
    ggplot(aes(y = percent, x = study_motivation, fill = species_sex, group = species_sex)) +
    geom_bar(stat = "identity", width = 0.9) + geom_text(aes(label = round(percent,
    2), y = cumulative_percent), color = "white", size = 3) + scale_fill_manual(values = color_theme,
    name = "Sex") + theme_classic() + theme(legend.position = "right") + labs(x = "Study motivation",
    y = "Percentage of all species assigned to female or male") + coord_flip()

sex_fig

Save the figure

# setwd(figures_path) ggsave('spp_sex_fig.pdf', plot = sex_fig, width = 10,
# height = 5)

Now let’s look at those not assigned to a sex

sex_summary_info <- sex_summary_all %>%
    dplyr::mutate(sex_reported = if_else(species_sex == "Unknown or not specified",
        "No", "Yes")) %>%
    dplyr::group_by(sex_reported) %>%
    dplyr::reframe(n = sum(n_articles))

n_total <- sex_summary_info %>%
    dplyr::reframe(n_total = sum(n)) %>%
    dplyr::pull(n_total)

sex_summary_info <- sex_summary_info %>%
    dplyr::mutate(prop = n/n_total)

Here’s the plot

# Define the black and grey color theme
black_and_grey <- c("#BCBEC0", "#414042")

yes_order <- c("Yes", "No")

# Calculate cumulative positions for text labels
sex_summary_info <- sex_summary_info %>%
  dplyr::mutate(sex_reported = factor(sex_reported, levels = yes_order)) %>% 
  dplyr::arrange(desc(sex_reported)) %>% 
  dplyr::mutate(cumulative_prop = cumsum(prop) - prop / 2)

sex_info_fig <- sex_summary_info %>%
  dplyr::mutate(sex_reported = factor(sex_reported, levels = yes_order)) %>% 
  ggplot(aes(y = prop, x = 1, fill = sex_reported)) +
  geom_bar(stat = "identity", width = 0.9) +
  geom_text(aes(label = round(prop, 2), y = cumulative_prop), color = "white") + 
  scale_fill_manual(values = black_and_grey, name = "Sex reported") + 
  theme_classic() +
  theme(legend.position = "right",
        axis.text.x = element_blank(),  # Remove x-axis text
        axis.ticks.x = element_blank()  # Remove x-axis ticks 
        ) +
  labs(
    x = "",
    y = "Proportion of all species"
  )
sex_info_fig

Save the figure

# setwd(figures_path) ggsave('spp_sex_info_fig.pdf', plot = sex_info_fig, width
# = 2.5, height = 5)

10.6.7 Species source

Breakdown without unreported

EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(species_source) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_source = str_trim(species_source)) %>%
  tidyr::separate_rows(species_source, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(species_source) %>% 
  dplyr::summarise(n_articles = sum(n), .groups = 'drop') %>%  # now a sum for each habitat
  tidyr::complete(species_source, 
                  fill = list(n_articles = 0)) %>%  # make a full df with empty categories = 0
  dplyr::filter(species_source != "Not reported") %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(total_source = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(overall_percent = round(n_articles/total_source*100, 1)) %>% 
  dplyr::arrange(desc(overall_percent)) %>% 
  gt()
species_source n_articles total_source overall_percent
Commercial supplier or fish farm 306 802 38.2
Lab stock of undisclosed origin 213 802 26.6
Wild collected 195 802 24.3
Lab stock from commercial supplier 55 802 6.9
Lab stock from wild population 33 802 4.1

Let’s look at where the animals were sourced for articles in the EIPAAB database

source_summary_all <- EIPAAB_database %>% 
  dplyr::group_by(unique_population_id) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation, species_source) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(species_source = str_trim(species_source)) %>%
  tidyr::separate_rows(species_source, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(species_source, study_motivation) %>% 
  dplyr::summarise(n_articles = sum(n), .groups = 'drop') %>%  # now a sum for each habitat
  tidyr::complete(species_source, study_motivation, 
                  fill = list(n_articles = 0)) %>%  # make a full df with empty categories = 0
  dplyr::ungroup() %>% 
  dplyr::group_by(study_motivation) %>% 
  dplyr::mutate(total_source = sum(n_articles)) %>% 
  dplyr::ungroup() %>% 
  dplyr::mutate(overall_percent = round(n_articles/total_source*100,1))

source_summary_all %>% 
  gt()
species_source study_motivation n_articles total_source overall_percent
Commercial supplier or fish farm Environmental 134 548 24.5
Commercial supplier or fish farm Medical 101 240 42.1
Commercial supplier or fish farm Basic research 71 162 43.8
Lab stock from commercial supplier Environmental 29 548 5.3
Lab stock from commercial supplier Medical 16 240 6.7
Lab stock from commercial supplier Basic research 10 162 6.2
Lab stock from wild population Environmental 25 548 4.6
Lab stock from wild population Medical 1 240 0.4
Lab stock from wild population Basic research 7 162 4.3
Lab stock of undisclosed origin Environmental 119 548 21.7
Lab stock of undisclosed origin Medical 63 240 26.2
Lab stock of undisclosed origin Basic research 31 162 19.1
Not reported Environmental 72 548 13.1
Not reported Medical 51 240 21.2
Not reported Basic research 25 162 15.4
Wild collected Environmental 169 548 30.8
Wild collected Medical 8 240 3.3
Wild collected Basic research 18 162 11.1

Only those with reported source

source_order <- c("Wild collected", "Lab stock from wild population", "Lab stock of undisclosed origin",
    "Lab stock from commercial supplier", "Commercial supplier or fish farm")

source_summary <- source_summary_all %>%
    dplyr::filter(species_source != "Not reported") %>%
    dplyr::select(species_source, study_motivation, n_articles) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_reported = sum(n_articles)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n_articles/total_reported * 100, 1), species_source = factor(species_source,
        levels = source_order)) %>%
    dplyr::arrange(species_source)

source_summary %>%
    gt()
species_source study_motivation n_articles total_reported percent
Wild collected Environmental 169 476 35.5
Wild collected Medical 8 189 4.2
Wild collected Basic research 18 137 13.1
Lab stock from wild population Environmental 25 476 5.3
Lab stock from wild population Medical 1 189 0.5
Lab stock from wild population Basic research 7 137 5.1
Lab stock of undisclosed origin Environmental 119 476 25.0
Lab stock of undisclosed origin Medical 63 189 33.3
Lab stock of undisclosed origin Basic research 31 137 22.6
Lab stock from commercial supplier Environmental 29 476 6.1
Lab stock from commercial supplier Medical 16 189 8.5
Lab stock from commercial supplier Basic research 10 137 7.3
Commercial supplier or fish farm Environmental 134 476 28.2
Commercial supplier or fish farm Medical 101 189 53.4
Commercial supplier or fish farm Basic research 71 137 51.8

A figure with the same information

source_order <- c("Wild collected", "Lab stock from wild population", "Lab stock of undisclosed origin",
    "Lab stock from commercial supplier", "Commercial supplier or fish farm")

# Define the black and grey color theme
color_theme <- c("#607C3B", "#A7D271", "#6B6E70", "#A66EAF", "#61346B")

# Calculate cumulative positions for text labels
source_summary <- source_summary %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::arrange(desc(species_source)) %>%
    dplyr::mutate(cumulative_percent = cumsum(percent) - percent/5)

# Create the plot
source_fig <- source_summary %>%
    mutate(study_motivation = fct_relevel(study_motivation, "Basic research", "Medical",
        "Environmental")) %>%
    ggplot(aes(y = percent, x = study_motivation, fill = species_source, group = species_source)) +
    geom_bar(stat = "identity", width = 0.9) + geom_text(aes(label = round(percent,
    2), y = cumulative_percent), color = "white", size = 3) + scale_fill_manual(values = color_theme,
    name = "Life stage") + theme_classic() + theme(legend.position = "right") + labs(x = "Study motivation",
    y = "Proportion of all species with a described source") + coord_flip()

source_fig

Save the figure

# setwd(figures_path) ggsave('spp_source_fig.pdf', plot = source_fig, width =
# 10, height = 5)

Now let’s look at those not assigned a source

source_summary_info <- source_summary_all %>%
    dplyr::mutate(source_reported = if_else(species_source == "Not reported", "No",
        "Yes")) %>%
    dplyr::group_by(source_reported) %>%
    dplyr::reframe(n = sum(n_articles))

n_total <- source_summary_info %>%
    dplyr::reframe(n_total = sum(n)) %>%
    dplyr::pull(n_total)

source_summary_info <- source_summary_info %>%
    dplyr::mutate(prop = n/n_total)

Here’s the plot

# Define the black and grey color theme
black_and_grey <- c("#BCBEC0", "#414042")

yes_order <- c("Yes", "No")

# Calculate cumulative positions for text labels
source_summary_info <- source_summary_info %>%
  dplyr::mutate(source_reported = factor(source_reported, levels = yes_order)) %>% 
  dplyr::arrange(desc(source_reported)) %>% 
  dplyr::mutate(cumulative_prop = cumsum(prop) - prop / 2)

source_info_fig <- source_summary_info %>%
  dplyr::mutate(source_reported = factor(source_reported, levels = yes_order)) %>% 
  ggplot(aes(y = prop, x = 1, fill = source_reported)) +
  geom_bar(stat = "identity", width = 0.9) +
  geom_text(aes(label = round(prop, 2), y = cumulative_prop), color = "white") + 
  scale_fill_manual(values = black_and_grey, name = "Source reported") + 
  theme_classic() +
  theme(legend.position = "right",
        axis.text.x = element_blank(),  # Remove x-axis text
        axis.ticks.x = element_blank()  # Remove x-axis ticks 
        ) +
  labs(
    x = "",
    y = "Proportion of all species"
  )
source_info_fig

Save the figure

# setwd(figures_path) ggsave('spp_source_info_fig.pdf', plot = source_info_fig,
# width = 5, height = 10)

10.7 Compounds

10.7.1 Number of compounds in database

There are 426 distinct compounds in the database

EIPAAB_database %>%
    dplyr::distinct(compound_name) %>%
    nrow()
## [1] 426

10.7.1.1 Number of compounds per study

article_n <- EIPAAB_database %>% 
  dplyr::distinct(article_id) %>% 
  nrow(.)

compound_n_summary <- EIPAAB_database %>% 
  dplyr::group_by(article_id) %>% 
  dplyr::sample_n(1) %>% 
  dplyr::ungroup() %>% 
  dplyr::group_by(compound_n) %>%
  dplyr::reframe(n = n(),
                   percent = round((n/article_n)*100,1))

compound_n_summary %>% 
  dplyr::slice(1:10) %>%  #10 most common number of compounds
  gt()
compound_n n percent
1 624 69.3
2 127 14.1
3 67 7.4
4 32 3.6
5 16 1.8
6 8 0.9
7 6 0.7
8 5 0.6
9 1 0.1
10 2 0.2

How many used more then 5

compound_n_summary %>%
    dplyr::filter(compound_n > 5) %>%
    reframe(n = sum(n), percent = round((n/article_n) * 100, 1)) %>%
    gt()
n percent
35 3.9

By motivation summary data frame

compound_n_summary <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(compound_n, study_motivation) %>%
    dplyr::summarise(n = n(), .groups = "drop") %>%
    tidyr::complete(compound_n, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(prop_motivation = n/total_motivation)

10.7.1.2 Fig S4

# Define the colour palette
motivation_colour_theme <- c("#60BD6C", "#D359A1", "#3C82C4") # Making colour theme to apply to plot

compound_n_oder <- c(1:9, ">10")

compound_n_fig <- compound_n_summary %>% 
  dplyr::mutate(
    compound_n = as.character(if_else(compound_n > 10, 10, compound_n)), # Grouping cases above 10
    compound_n = if_else(compound_n == "10", ">10", compound_n)
    ) %>% 
  dplyr::group_by(compound_n, study_motivation) %>% 
  dplyr::reframe(n = sum(n)) %>% 
  dplyr::mutate(compound_n = factor(compound_n, levels = compound_n_oder)) %>%
  ggplot(aes(x=compound_n, y=n, colour = study_motivation, fill = study_motivation, group = study_motivation)) +
  geom_col(position = position_dodge(width = 0.8), width = 0.1) +
  geom_point(position = position_dodge(width = 0.8), size = 3) +
  geom_text(aes(label = n), vjust=-0.6, size=3.5, color="black", position =  position_dodge(width = 0.8)) +
  scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
  scale_fill_manual(values = motivation_colour_theme, name = "Study motivation") +
  theme_classic() +
   labs(
    x = "",
    y = "Number of studies"
  ) +
   theme()

compound_n_fig

Save the figure

# setwd(figures_path) ggsave('comp_compound_n_fig.pdf', plot = compound_n_fig,
# width = 10, height = 5)

10.7.2 Therputic diversity in the database

First lets see how many compounds have an ATC classification.

305 out of 426 (71.6%)

EIPAAB_database %>% 
  dplyr::group_by(compound_name) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::group_by(compound_atc_boolean) %>% 
  dplyr::reframe(n = length(compound_atc_boolean)) %>% 
  gt()
compound_atc_boolean n
No 121
Yes 305

10.7.2.1 ATC level 1

Let’s seem how many classes there are at the Anatomical Therapeutic Chemical (ATC) level 1

There are 14 classes at the 1st ATC level (the highest class of the ATC). This is ever class at the first level

n_compound_atc <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::distinct(compound_name) %>% 
  nrow(.)

compound_ATC_L1_summary <- EIPAAB_database %>% 
  dplyr::group_by(compound_name) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::group_by(compound_atc_level_1) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(compound_atc_level_1 = str_trim(compound_atc_level_1)) %>%
  tidyr::separate_rows(compound_atc_level_1, sep = ";") %>% 
  dplyr::group_by(compound_atc_level_1) %>% 
  dplyr::reframe(n = sum(n),
                 percent = round(n/n_compound_atc*100,1),
                 measure = "compounds") %>% 
  arrange(desc(n))

compound_ATC_L1_summary %>% 
  gt()
compound_atc_level_1 n percent measure
n nervous system 137 44.9 compounds
c cardiovascular system 49 16.1 compounds
a alimentary tract and metabolism 35 11.5 compounds
s sensory organs 34 11.1 compounds
g genito urinary system and sex hormones 30 9.8 compounds
j antiinfectives for systemic use 28 9.2 compounds
d dermatologicals 27 8.9 compounds
r respiratory system 26 8.5 compounds
l antineoplastic and immunomodulating agents 19 6.2 compounds
m musculo-skeletal system 12 3.9 compounds
v various 9 3.0 compounds
h systemic hormonal preparations, excl. sex hormones and insulins 8 2.6 compounds
p antiparasitic products, insecticides and repellents 6 2.0 compounds
b blood and blood forming organs 4 1.3 compounds

Now we will make a similar data file to look at the overall use in the database at each ATC level 1

n_data_atc <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  nrow(.)

compound_ATC_L1_data_summary <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::group_by(compound_atc_level_1) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(compound_atc_level_1 = str_trim(compound_atc_level_1)) %>%
  tidyr::separate_rows(compound_atc_level_1, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(compound_atc_level_1) %>% 
  dplyr::reframe(n = sum(n),
                 percent =round(n/n_data_atc*100,1),
                 measure = "data") %>% # now a sum for each habitat
  arrange(desc(percent))
compound_ATC_L1_data_summary %>% 
  dplyr::select(-measure) %>% 
  gt()
compound_atc_level_1 n percent
n nervous system 1119 72.9
g genito urinary system and sex hormones 201 13.1
c cardiovascular system 158 10.3
d dermatologicals 130 8.5
s sensory organs 102 6.6
a alimentary tract and metabolism 93 6.1
l antineoplastic and immunomodulating agents 89 5.8
r respiratory system 76 4.9
m musculo-skeletal system 58 3.8
j antiinfectives for systemic use 57 3.7
v various 32 2.1
h systemic hormonal preparations, excl. sex hormones and insulins 15 1.0
b blood and blood forming organs 12 0.8
p antiparasitic products, insecticides and repellents 7 0.5
ATC_L1_summary <- compound_ATC_L1_summary %>%
    rbind(., compound_ATC_L1_data_summary) %>%
    dplyr::mutate(value = if_else(measure == "compounds", n, percent))

10.7.2.2 Fig S5

This plot shows the number of different compounds in each ATC classification as well as the total proportion of data it makes up

measure_colour_theme <- c("black", "grey")  # Making colour theme to apply to plot

# Making a list of act names in the order that we want them in the plot
level_1_order <- ATC_L1_summary %>%
    dplyr::filter(measure == "data") %>%
    dplyr::arrange(value) %>%
    dplyr::pull(compound_atc_level_1)

# Making the plot
atc_level_1_fig <- ATC_L1_summary %>%
    dplyr::mutate(compound_atc_level_1 = factor(compound_atc_level_1, levels = level_1_order)) %>%
    ggplot(aes(x = compound_atc_level_1, y = value, colour = measure, fill = measure,
        group = measure)) + geom_col(position = position_dodge(width = 0.8), width = 0.2,
    colour = NA) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = value), hjust = -0.6, size = 3.5, color = "black", position = position_dodge(width = 0.8)) +
    scale_colour_manual(values = measure_colour_theme, name = "Value type") + scale_fill_manual(values = measure_colour_theme,
    name = "Value type") + coord_flip() + scale_y_continuous(name = "Number of distinct compounds",
    sec.axis = sec_axis(~., name = "Total proportion of the database")  # Adjust scaling if needed
) +
    theme_classic() + labs(x = "", y = "Number of distict species in the database") +
    theme()

atc_level_1_fig

# setwd(figures_path) ggsave('comp_atc_level_1_fig.pdf', plot =
# atc_level_1_fig, width = 10, height = 10)

10.7.2.3 ATC level 3

Let’s seem how many classes there are at the Anatomical Therapeutic Chemical (ATC) level 3

There are 131 distinct classes, I am creating a table with the top 15.

n_compound_atc <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::distinct(compound_name) %>% 
  nrow(.)

compound_ATC_L3_summary <- EIPAAB_database %>% 
  dplyr::group_by(compound_name) %>% 
  dplyr::sample_n(1) %>% # sampling one row per article per species (i.e. ignoring multiple rows per article for compounds)
  dplyr::ungroup() %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::group_by(compound_atc_level_3) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(compound_atc_level_3 = str_trim(compound_atc_level_3)) %>%
  tidyr::separate_rows(compound_atc_level_3, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(compound_atc_level_3) %>% 
  dplyr::reframe(n = sum(n),
                 percent = round(n/n_compound_atc*100,1),
                 measure = "compounds") %>% # now a sum for each habitat
  arrange(desc(n))

compound_ATC_L3_summary %>% 
  dplyr::select(-measure) %>% 
  dplyr::slice(1:15) %>% # only the first 15
  gt()
compound_atc_level_3 n percent
n06a antidepressants 27 8.9
n03a antiepileptics 18 5.9
n05a antipsychotics 14 4.6
a01a stomatological preparations 12 3.9
n05b anxiolytics 11 3.6
n05c hypnotics and sedatives 11 3.6
n06b psychostimulants, agents used for adhd and nootropics 11 3.6
r06a antihistamines for systemic use 11 3.6
c07a beta blocking agents 9 3.0
d04a antipruritics, incl. antihistamines, anesthetics, etc. 9 3.0
s01e antiglaucoma preparations and miotics 9 3.0
c05a agents for treatment of hemorrhoids and anal fissures for topical use 8 2.6
g03c estrogens 8 2.6
n01a anesthetics, general 8 2.6
c10a lipid modifying agents, plain 7 2.3

Now we will make a similar data file to look at the overall use in the database at each ATC level 3.

Below I make a table with the top 15

n_data_atc <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  nrow(.)

compound_ATC_L3_data_summary <- EIPAAB_database %>% 
  dplyr::filter(compound_atc_boolean == "Yes") %>% 
  dplyr::group_by(compound_atc_level_3) %>% 
  dplyr::reframe(n = n()) %>%
  dplyr::mutate(compound_atc_level_3 = str_trim(compound_atc_level_3)) %>%
  tidyr::separate_rows(compound_atc_level_3, sep = ";") %>% # each spp has multiple habitats the string needs splitting
  dplyr::group_by(compound_atc_level_3) %>% 
  dplyr::reframe(n = sum(n),
                 percent = round(n/n_data_atc*100,1),
                 measure = "data") %>% # now a sum for each habitat
  arrange(desc(percent))

compound_ATC_L3_data_summary %>% 
  dplyr::select(-measure) %>% 
  dplyr::slice(1:15) %>% 
  gt()
compound_atc_level_3 n percent
n06a antidepressants 424 27.6
n03a antiepileptics 164 10.7
n05b anxiolytics 149 9.7
g03c estrogens 121 7.9
n06b psychostimulants, agents used for adhd and nootropics 84 5.5
l02a hormones and related agents 64 4.2
d11a other dermatological preparations 62 4.0
n05a antipsychotics 60 3.9
m01a antiinflammatory and antirheumatic products, non-steroids 50 3.3
n02a opioids 51 3.3
m02a topical products for joint and muscular pain 48 3.1
n02b other analgesics and antipyretics 45 2.9
n05c hypnotics and sedatives 40 2.6
c07a beta blocking agents 38 2.5
r02a throat preparations 35 2.3

Here we make a new column called value where we combined the count of distinct compounds and proportion of data

ATC_L3_summary <- compound_ATC_L3_summary %>%
    rbind(., compound_ATC_L3_data_summary) %>%
    dplyr::mutate(value = if_else(measure == "compounds", n, percent))

10.7.2.4 Fig 4a

This plot shows the number of different compounds in each ATC classification as well as the total proportion of data it makes up. This is done for only the 15 most commonly used groups.

measure_colour_theme <- c("black", "grey") # Making colour theme to apply to plot

# Making a list of act names in the order that we want them in the plot 
level_3_order_top_15 <- ATC_L3_summary %>% 
  dplyr::filter(measure == "data") %>% 
  dplyr::arrange(desc(value)) %>% 
  dplyr::slice(1:15) %>% 
  dplyr::arrange(desc(value)) %>%
  dplyr::pull(compound_atc_level_3)

# Making the plot
atc_level_3_fig <- ATC_L3_summary %>% 
  dplyr::filter(compound_atc_level_3 %in% level_3_order_top_15) %>% 
  dplyr::mutate(compound_atc_level_3 = factor(compound_atc_level_3, levels = level_3_order_top_15)) %>% 
  ggplot(aes(x=compound_atc_level_3, y=value, fill = measure, colour = measure, 
             group = measure)) +
  geom_col(position = position_dodge(width = 1), width = 0.2, colour = NA,) +
  geom_point(position = position_dodge(width = 1), size = 3) +
  geom_text(aes(label = value), vjust=-0.6, size=3.5, position =  position_dodge(width = 1)) +
  scale_colour_manual(values = measure_colour_theme, name = "Value type",
                      labels = c("Compounds (n)", "Percentage of data")) +
  scale_fill_manual(values = measure_colour_theme, name = "Value type",
                      labels = c("Compounds (n)", "Percentage of data")) +
  scale_y_continuous(
    name = "Distinct compounds",
    limits = c(0, 30),                   # Set the range of y-axis
    breaks = c(0, 10, 20, 30),           # Set the labels at 0, 10, 20, 30
    sec.axis = sec_axis(~ . , name = "Percentage of database") # Adjust scaling if needed
  ) +
  theme_classic() +
   labs(
    x = "",
    y = ""
  ) +
   theme(
    axis.text.y = element_text(size = 8),          # Change y-axis labels size
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1, size = 8), # Change x-axis labels orientation
    legend.title = element_text(size = 12),         # Change legend title size if needed
    legend.text = element_text(size = 10)  
   )

atc_level_3_fig

Save the figure

# setwd(figures_path) ggsave('atc_level_3_fig.pdf', plot = atc_level_3_fig,
# width = 10, height = 5)

10.7.3 Most common compounds

Overall the most common compounds are Fluoxetine, Diazepam and 17-alpha-ethinylestradiol

Below is a table of the top 15 compounds

n_row <- EIPAAB_database %>%
    nrow(.)

compound_use <- EIPAAB_database %>%
    dplyr::group_by(compound_name) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(prop = n/n_row) %>%
    arrange(desc(prop))

compound_use %>%
    dplyr::slice(1:15) %>%
    gt()
compound_name n prop
Fluoxetine 200 0.11500863
Diazepam 67 0.03852789
17-alpha-ethinylestradiol 63 0.03622772
Caffeine 45 0.02587694
Venlafaxine 43 0.02472685
Citalopram 42 0.02415181
Sertraline 39 0.02242668
Carbamazepine 38 0.02185164
Buspirone 30 0.01725129
Morphine 27 0.01552616
Oxazepam 26 0.01495112
Valproate 24 0.01380104
17-beta-estradiol 23 0.01322599
Ibuprofen 20 0.01150086
Nicotine 19 0.01092582

Let’s see what the numbers are for each motivation, but let’s also maintain the overall numbers so we can add it to the figure

n_row <- EIPAAB_database %>%
    nrow(.)

compound_use_motivation <- EIPAAB_database %>%
    dplyr::group_by(study_motivation, compound_name) %>%
    dplyr::summarise(n = n(), .groups = "drop") %>%
    tidyr::complete(compound_name, study_motivation, fill = list(n = 0))  # Making sure we have a complete dataframe

compound_use_motivation <- compound_use %>%
    dplyr::select(-prop) %>%
    dplyr::mutate(study_motivation = "All") %>%
    rbind(., compound_use_motivation)

The top 10 based on each study motivation as well as the overall total

top_10_comp_all_fig <- compound_use_motivation %>%
    dplyr::filter(study_motivation == "All") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(compound_name = fct_reorder(compound_name, n)) %>%
    ggplot(aes(x = compound_name, y = n)) + geom_col(width = 0.1, colour = NA, fill = "grey") +
    geom_point(size = 3, colour = "grey", fill = "grey") + geom_text(aes(label = n),
    hjust = -0.6, size = 3.5, color = "black") + coord_flip() + theme_classic() +
    labs(title = "All", x = "", y = "Total use in the database") + theme(plot.title = element_text(size = 11))


top_10_comp_env_fig <- compound_use_motivation %>%
    dplyr::filter(study_motivation == "Environmental") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(compound_name = fct_reorder(compound_name, n)) %>%
    ggplot(aes(x = compound_name, y = n)) + geom_col(width = 0.1, colour = NA, fill = "#60BD6C") +
    geom_point(size = 3, colour = "#60BD6C", fill = "#60BD6C") + geom_text(aes(label = n),
    hjust = -0.6, size = 3.5, color = "black") + coord_flip() + theme_classic() +
    labs(title = "Environmental", x = "", y = "Total use in the database") + theme(plot.title = element_text(size = 11))


top_10_comp_med_fig <- compound_use_motivation %>%
    dplyr::filter(study_motivation == "Medical") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(compound_name = fct_reorder(compound_name, n)) %>%
    ggplot(aes(x = compound_name, y = n)) + geom_col(width = 0.1, colour = NA, fill = "#D359A1") +
    geom_point(size = 3, colour = "#D359A1", fill = "#D359A1") + geom_text(aes(label = n),
    hjust = -0.6, size = 3.5, color = "black") + coord_flip() + theme_classic() +
    labs(title = "Medical", x = "", y = "Total use in the database") + theme(plot.title = element_text(size = 11))

top_10_comp_base_fig <- compound_use_motivation %>%
    dplyr::filter(study_motivation == "Basic research") %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::mutate(compound_name = fct_reorder(compound_name, n)) %>%
    ggplot(aes(x = compound_name, y = n)) + geom_col(width = 0.1, colour = NA, fill = "#3C82C4") +
    geom_point(size = 3, colour = "#3C82C4", fill = "#3C82C4") + geom_text(aes(label = n),
    hjust = -0.6, size = 3.5, color = "black") + coord_flip() + theme_classic() +
    labs(title = "Basic Research", x = "", y = "Total use in the database") + theme(plot.title = element_text(size = 11))

10.7.3.1 Fig 4b

Here are the resulting figures

top_10_comp_all_fig

top_10_comp_env_fig

top_10_comp_med_fig

top_10_comp_base_fig

Saving as PDFs

# setwd(figures_path) ggsave('comp_top_10_comp_all_fig.pdf', plot =
# top_10_comp_all_fig, width = 5, height = 10)
# ggsave('comp_top_10_comp_env_fig.pdf', plot = top_10_comp_env_fig, width = 5,
# height = 10) ggsave('comp_top_10_comp_med_fig.pdf', plot =
# top_10_comp_med_fig, width = 5, height = 10)
# ggsave('comp_top_10_comp_base_fig.pdf', plot = top_10_comp_base_fig, width =
# 5, height = 10)

10.7.4 Mixtures

It was recorded whether the animals were also exposed to compound mixtures

EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::reframe(mixture_yes = sum(compond_mixture == "Yes", na.rm = TRUE), mixture_no = sum(compond_mixture ==
        "No", na.rm = TRUE), mixture_percent = (mixture_yes/mixture_no) * 100) %>%
    gt()
mixture_yes mixture_no mixture_percent
165 736 22.41848

Medical articles have a much higher use of mixtures

EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::reframe(mixture_yes = sum(compond_mixture == "Yes", na.rm = TRUE), mixture_no = sum(compond_mixture ==
        "No", na.rm = TRUE), mixture_percent = round((mixture_yes/mixture_no) * 100,
        1)) %>%
    gt()
study_motivation mixture_yes mixture_no mixture_percent
Environmental 57 453 12.6
Medical 76 157 48.4
Basic research 32 126 25.4

10.7.5 Exposure route

Data on the method of exposure was also extracted

nrow <- EIPAAB_database %>%
    nrow(.)

EIPAAB_database %>%
    dplyr::group_by(compound_expose_route) %>%
    dplyr::reframe(n = n(), percent = round((n/nrow) * 100, 1)) %>%
    gt()
compound_expose_route n percent
Other exposure route 223 12.8
Waterborne only 1500 86.3
Waterborne plus any other route 16 0.9

10.7.6 Exposure length

The database has both the minimum and maximum duration of exposure prior to behavioural measure (compound_min_duration_exposure and compound_max_duration_exposure). Here we will focus on the maximum duration

These are the different categories of exposure length

EIPAAB_database %>%
    dplyr::distinct(compound_max_duration_exposure) %>%
    gt()
compound_max_duration_exposure
Less than 6 hours
1 to 3 months
3 to 8 days
22 to 29 days
Multigenerational
6 to 24 hours
1 to 3 days
8 to 15 days
Not stated
15 to 22 days
Transgenerational
3 to 6 months
Lifetime

Some articles did not report the exposure duration at all, or in sufficient detail to extract.

In total this occurred in 108 cases

EIPAAB_database %>%
    dplyr::filter(compound_min_duration_exposure == "Not stated" | compound_max_duration_exposure ==
        "Not stated") %>%
    nrow(.)
## [1] 108

Summary table

exposure_duration_order <- c("Less than 6 hours", "6 to 24 hours", "1 to 3 days",
    "3 to 8 days", "8 to 15 days", "15 to 22 days", "22 to 29 days", "1 to 3 months",
    "3 to 6 months", "Lifetime", "Transgenerational", "Multigenerational")

nrow <- EIPAAB_database %>%
    dplyr::filter(compound_max_duration_exposure != "Not stated") %>%
    nrow(.)

exposure_duration_summary <- EIPAAB_database %>%
    dplyr::filter(compound_max_duration_exposure != "Not stated") %>%
    dplyr::group_by(compound_max_duration_exposure) %>%
    dplyr::reframe(n = n(), percent = round((n/nrow) * 100, 1)) %>%
    dplyr::mutate(compound_max_duration_exposure = factor(compound_max_duration_exposure,
        levels = exposure_duration_order)) %>%
    dplyr::arrange(compound_max_duration_exposure) %>%
    dplyr::mutate(study_motivation = "All")

exposure_duration_summary %>%
    gt()
compound_max_duration_exposure n percent study_motivation
Less than 6 hours 679 41.3 All
6 to 24 hours 129 7.9 All
1 to 3 days 106 6.5 All
3 to 8 days 317 19.3 All
8 to 15 days 101 6.1 All
15 to 22 days 113 6.9 All
22 to 29 days 59 3.6 All
1 to 3 months 83 5.1 All
3 to 6 months 23 1.4 All
Lifetime 9 0.5 All
Transgenerational 15 0.9 All
Multigenerational 9 0.5 All

By motivation

exposure_duration_order <- c("Less than 6 hours", "6 to 24 hours", "1 to 3 days",
    "3 to 8 days", "8 to 15 days", "15 to 22 days", "22 to 29 days", "1 to 3 months",
    "3 to 6 months", "Lifetime", "Transgenerational", "Multigenerational")


exposure_duration_motivation_summary <- EIPAAB_database %>%
    dplyr::filter(compound_max_duration_exposure != "Not stated") %>%
    dplyr::group_by(compound_max_duration_exposure, study_motivation) %>%
    dplyr::summarise(n = n(), .groups = "drop") %>%
    tidyr::complete(compound_max_duration_exposure, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round((n/total_motivation) * 100, 1)) %>%
    dplyr::select(-total_motivation)

exp_duration_motivation_summary <- exposure_duration_motivation_summary %>%
    rbind(exposure_duration_summary) %>%
    dplyr::mutate(compound_max_duration_exposure = factor(compound_max_duration_exposure,
        levels = rev(exposure_duration_order))) %>%
    dplyr::arrange(desc(compound_max_duration_exposure))

Making plots for each study motivation

exp_duration_all_fig <- exp_duration_motivation_summary %>%
    dplyr::filter(study_motivation == "All") %>%
    ggplot(aes(x = compound_max_duration_exposure, y = percent)) + geom_col(width = 0.1,
    colour = NA, fill = "grey") + geom_point(size = 3, colour = "grey", fill = "grey") +
    geom_text(aes(label = percent), vjust = -0.6, size = 3.5, color = "black") +
    theme_classic() + coord_flip() + labs(title = "All", x = "", y = "Total percentage") +
    theme(plot.title = element_text(size = 11))


exp_duration_env_fig <- exp_duration_motivation_summary %>%
    dplyr::filter(study_motivation == "Environmental") %>%
    ggplot(aes(x = compound_max_duration_exposure, y = percent)) + geom_col(width = 0.1,
    colour = NA, fill = "#60BD6C") + geom_point(size = 3, colour = "#60BD6C", fill = "#60BD6C") +
    geom_text(aes(label = percent), vjust = -0.6, size = 3.5, color = "black") +
    theme_classic() + coord_flip() + labs(title = "Environmental", x = "", y = "Total percentage") +
    theme(plot.title = element_text(size = 11))

exp_duration_med_fig <- exp_duration_motivation_summary %>%
    dplyr::filter(study_motivation == "Medical") %>%
    ggplot(aes(x = compound_max_duration_exposure, y = percent)) + geom_col(width = 0.1,
    colour = NA, fill = "#D359A1") + geom_point(size = 3, colour = "#D359A1", fill = "#D359A1") +
    geom_text(aes(label = percent), vjust = -0.6, size = 3.5, color = "black") +
    theme_classic() + coord_flip() + labs(title = "Medical", x = "", y = "Total percentage") +
    theme(plot.title = element_text(size = 11))


exp_duration_base_fig <- exp_duration_motivation_summary %>%
    dplyr::filter(study_motivation == "Basic research") %>%
    ggplot(aes(x = compound_max_duration_exposure, y = percent)) + geom_col(width = 0.1,
    colour = NA, fill = "#3C82C4") + geom_point(size = 3, colour = "#3C82C4", fill = "#3C82C4") +
    geom_text(aes(label = percent), vjust = -0.6, size = 3.5, color = "black") +
    theme_classic() + coord_flip() + labs(title = "Basic research", x = "", y = "Total percentage") +
    theme(plot.title = element_text(size = 11))

10.7.6.1 Fig 5a

exp_duration_all_fig

exp_duration_env_fig

exp_duration_med_fig

exp_duration_base_fig

Save plots

# setwd(figures_path) ggsave('comp_exp_duration_all_fig.pdf', plot =
# exp_duration_all_fig, width = 8.3/3, height = 11.7/3)
# ggsave('comp_exp_duration_env_fig.pdf', plot = exp_duration_env_fig, width =
# 8.3/3, height = 11.7/3) ggsave('comp_exp_duration_med_fig.pdf', plot =
# exp_duration_med_fig, width = 8.3/3, height = 11.7/3)
# ggsave('comp_exp_duration_base_fig.pdf', plot = exp_duration_base_fig, width
# = 8.3/3, height = 11.7/3)

10.7.7 Number of doses

Here I will look at the number of doses used. This was meassured as the total treatments (i.e. inculding control), so if we want to know the number of doses for the compound we need to subtract 1. I have done this below.

n_doses_summary <- EIPAAB_database %>%
    dplyr::filter(!is.na(compound_treatment_levels)) %>%
    dplyr::mutate(n_doses = compound_treatment_levels - 1) %>%
    dplyr::group_by(n_doses) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(total = sum(n), percent = round((n/total) * 100, 1), study_motivation = "All")

n_doses_summary %>%
    gt()
n_doses n total percent study_motivation
1 449 1513 29.7 All
2 203 1513 13.4 All
3 377 1513 24.9 All
4 172 1513 11.4 All
5 163 1513 10.8 All
6 46 1513 3.0 All
7 50 1513 3.3 All
8 14 1513 0.9 All
9 11 1513 0.7 All
10 10 1513 0.7 All
11 10 1513 0.7 All
12 5 1513 0.3 All
13 2 1513 0.1 All
17 1 1513 0.1 All

Let’s see how many use more then 5

n_doses_summary %>%
    dplyr::filter(n_doses > 5) %>%
    dplyr::summarise(over_5_percent = sum(percent)) %>%
    gt()
over_5_percent
9.8

Looking by study motivation

n_doses_motivation_summary <- EIPAAB_database %>%
    dplyr::filter(!is.na(compound_treatment_levels)) %>%
    dplyr::mutate(n_doses = compound_treatment_levels - 1) %>%
    dplyr::group_by(n_doses, study_motivation) %>%
    dplyr::summarise(n = n(), .groups = "drop") %>%
    tidyr::complete(n_doses, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round((n/total) * 100, 1))

10.7.7.1 Fig 5b

Making a plot

dose_order <- c(1:12, ">12")

doses_fig <- n_doses_motivation_summary %>% 
  dplyr::mutate(n_doses = as.character(if_else(n_doses>13, 13, n_doses)),
                n_doses = if_else(n_doses == "13", ">12", n_doses),
                n_doses = factor(n_doses, levels = dose_order)
                )%>% 
  ggplot(aes(x=n_doses, y=percent, colour = study_motivation, 
             fill = study_motivation, group = study_motivation)) +
  geom_point(position = position_dodge(width = 0.8), size = 3) +
  geom_line(size = 1) +
  geom_text(aes(label = percent), vjust=-0.6, size=3.5, color="black") +
  scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
  scale_fill_manual(values = motivation_colour_theme, name = "Study motivation") +
  theme_classic() +
  facet_wrap(~study_motivation) +
  theme(
    legend.position = c(0.8, 0.9), # Positioning the legend in the top-left corner within the plot
    legend.justification = c(0, 1) # Ensuring the legend box aligns properly at the top-left corner
    ) +
   labs(
    x = "",
    y = "Number of studies"
  ) +
   theme()

doses_fig

Save the plot

# setwd(figures_path) ggsave('comp_doses_fig.pdf', plot = doses_fig, width =
# 8.3, height = 11.7/3)

10.7.8 Concentrations

Here I will have a look at the min and max and range of doses used in the database. For the MS, I am including only studies that reported in a mass to water volume measure so we can compare standardised unites (ug/L). This was the most common reporting methods (62% of all data; 1090 total).

nrow <- EIPAAB_database %>%
    nrow()

EIPAAB_database %>%
    dplyr::group_by(compound_min_dose_unit_std) %>%
    dplyr::reframe(n = n(), prop = n/nrow) %>%
    dplyr::arrange(desc(n)) %>%
    gt()
compound_min_dose_unit_std n prop
ug/L 1076 0.618746406
uM 397 0.228292122
NA 228 0.131109833
uM/L 25 0.014376078
ppm 9 0.005175388
uL/L 2 0.001150086
ug/g 2 0.001150086

Summary of the minimum concentration used (where reported in mass to volume)

EIPAAB_database <- EIPAAB_database %>%
    dplyr::mutate(range = compound_max_dose_std - compound_min_dose_std)

Dose summary by motivation

EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L", compound_max_dose_unit_std ==
        "ug/L") %>%
    dplyr::mutate(range = compound_max_dose_std - compound_min_dose_std) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::reframe(median_min = median(compound_min_dose_std, na.rm = T), sd_min = sd(compound_min_dose_std,
        na.rm = T), min_min = min(compound_min_dose_std, na.rm = T), max_min = max(compound_min_dose_std,
        na.rm = T), median_max = median(compound_max_dose_std, na.rm = T), sd_max = sd(compound_max_dose_std,
        na.rm = T), min_max = min(compound_max_dose_std, na.rm = T), max_max = max(compound_max_dose_std,
        na.rm = T), median_range = median(range, na.rm = T), sd_range = sd(range,
        na.rm = T), min_range = min(range, na.rm = T), max_range = max(range, na.rm = T)) %>%
    gt()
study_motivation median_min sd_min min_min max_min median_max sd_max min_max max_max median_range sd_range min_range max_range
Environmental 0.995 25255.8 3.13e-06 5.0e+05 100 140651.2 0.001 1600000 51.69 135347.17 -1e-05 1579600
Medical 1000.000 74500.7 5.00e-02 5.4e+05 5000 206906.9 0.050 1943000 0.00 196100.58 0e+00 1942030
Basic research 3000.000 5301683.4 1.00e-02 6.0e+07 10000 5299563.0 0.010 60000000 72.00 84083.83 0e+00 600000

10.7.8.1 Fig 5c-1

A plot for minimum doses, its on the log axis because the distribution is highly skewed motivation_colour_theme

motivation_colour_theme <- c("#60BD6C", "#D359A1", "#3C82C4")

min_conc_fig <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    ggplot(aes(x = log(compound_min_dose_std), fill = study_motivation, colour = study_motivation)) +
    stat_slab(alpha = 0.6, linewidth = 1.5, colour = NA) + stat_pointinterval(point_interval = "median_qi",
    position = position_dodge(width = 0.4, preserve = "single"), .width = c(0.89,
        0.95)) + scale_fill_manual(values = motivation_colour_theme, name = "Study motivation",
    guide = "none") + scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
    theme_classic() + labs(x = "Log10 minimum dose (ug/L)", y = "Density") + theme(legend.position = "bottom")

min_conc_fig

Save the figure

# setwd(figures_path) ggsave('comp_min_conc_fig.pdf', plot = min_conc_fig,
# width = 5, height = 6)

A summary table so we can see what the corresponding raw values are in the plot

min_conc_summary <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::summarise(median = median(log(compound_min_dose_std), na.rm = TRUE), lower_89 = quantile(log(compound_min_dose_std),
        probs = 0.11, na.rm = TRUE), upper_89 = quantile(log(compound_min_dose_std),
        probs = 0.89, na.rm = TRUE), lower_95 = quantile(log(compound_min_dose_std),
        probs = 0.05, na.rm = TRUE), upper_95 = quantile(log(compound_min_dose_std),
        probs = 0.95, na.rm = TRUE), .groups = "drop") %>%
    # Transform to a format suitable for ggplot annotation
pivot_longer(cols = -study_motivation, names_to = "stat", values_to = "value") %>%
    dplyr::mutate(vaule_raw = format(exp(value), scientific = FALSE))

10.7.8.2 Fig 5c-2

A plot for maximum doses, its on the log axis because the distribution is highly skewed motivation_colour_theme

motivation_colour_theme <- c("#60BD6C", "#D359A1", "#3C82C4")

max_conc_fig <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    ggplot(aes(x = log(compound_max_dose_std), fill = study_motivation, colour = study_motivation)) +
    stat_slab(alpha = 0.6, linewidth = 1.5, colour = NA) + stat_pointinterval(point_interval = "median_qi",
    position = position_dodge(width = 0.4, preserve = "single"), .width = c(0.89,
        0.95)) + scale_fill_manual(values = motivation_colour_theme, name = "Study motivation",
    guide = "none") + scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
    theme_classic() + labs(x = "Log10 maximum dose (ug/L)", y = "Density") + theme(legend.position = "bottom")

max_conc_fig

Save the figure

# setwd(figures_path) ggsave('comp_max_conc_fig.pdf', plot = max_conc_fig,
# width = 5, height = 6)

A summary table so we can see what the corresponding raw values are in the plot

max_conc_summary <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::summarise(median = median(log(compound_max_dose_std), na.rm = TRUE), lower_89 = quantile(log(compound_max_dose_std),
        probs = 0.11, na.rm = TRUE), upper_89 = quantile(log(compound_max_dose_std),
        probs = 0.89, na.rm = TRUE), lower_95 = quantile(log(compound_max_dose_std),
        probs = 0.05, na.rm = TRUE), upper_95 = quantile(log(compound_max_dose_std),
        probs = 0.95, na.rm = TRUE), .groups = "drop") %>%
    # Transform to a format suitable for ggplot annotation
pivot_longer(cols = -study_motivation, names_to = "stat", values_to = "value") %>%
    dplyr::mutate(vaule_raw = format(exp(value), scientific = FALSE))

10.7.8.3 Fig 5c-3

A plot for the range of doses, its on the log axis because the distribution is highly skewed. This includes only studies that had more then one dose and reported concentration in a mass to volume metric.

motivation_colour_theme <- c("#60BD6C", "#D359A1", "#3C82C4")

range_conc_fig <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    dplyr::filter(range > 0) %>%
    ggplot(aes(x = log(range), fill = study_motivation, colour = study_motivation)) +
    stat_slab(alpha = 0.6, linewidth = 1.5, colour = NA) + stat_pointinterval(point_interval = "median_qi",
    position = position_dodge(width = 0.4, preserve = "single"), .width = c(0.89,
        0.95)) + scale_fill_manual(values = motivation_colour_theme, name = "Study motivation",
    guide = "none") + scale_colour_manual(values = motivation_colour_theme, name = "Study motivation") +
    theme_classic() + labs(x = "Log10 range (ug/L)", y = "Density") + theme(legend.position = "bottom")

range_conc_fig

Save the figure

# setwd(figures_path) ggsave('comp_range_conc_fig.pdf', plot = range_conc_fig,
# width = 5, height = 6)

A summary table so we can see what the corresponding raw values are in the plot

range_conc_summary <- EIPAAB_database %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L", range > 0) %>%
    dplyr::group_by(study_motivation) %>%
    summarise(median = median(log(range), na.rm = TRUE), lower_89 = quantile(log(range),
        probs = 0.055, na.rm = TRUE), upper_89 = quantile(log(range), probs = 0.945,
        na.rm = TRUE), lower_95 = quantile(log(range), probs = 0.025, na.rm = TRUE),
        upper_95 = quantile(log(range), probs = 0.975, na.rm = TRUE)) %>%
    # Transform to a format suitable for ggplot annotation
pivot_longer(cols = -study_motivation, names_to = "stat", values_to = "value") %>%
    dplyr::mutate(vaule_raw = format(exp(value), scientific = FALSE))

Range of does

env_min_conc_fig <- EIPAAB_database %>%
    dplyr::filter(study_motivation == "Environmental") %>%
    dplyr::filter(compound_min_dose_unit_std == "ug/L") %>%
    ggplot(aes(x = log(compound_min_dose_std))) + stat_slab(aes(alpha = 0.8, linewidth = 1.5)) +
    stat_pointinterval(point_interval = "median_qi", position = position_dodge(width = 0.4,
        preserve = "single"), .width = c(0.89, 0.95)) + theme_classic() + theme(legend.position = "none")

env_min_conc_fig

A summary table so we can see what the corresponding raw values are in the plot

env_conc_summary <- EIPAAB_database %>%
    filter(study_motivation == "Environmental", compound_min_dose_unit_std == "ug/L") %>%
    summarise(median = median(log(compound_min_dose_std), na.rm = TRUE), lower_89 = quantile(log(compound_min_dose_std),
        probs = 0.055, na.rm = TRUE), upper_89 = quantile(log(compound_min_dose_std),
        probs = 0.945, na.rm = TRUE), lower_95 = quantile(log(compound_min_dose_std),
        probs = 0.025, na.rm = TRUE), upper_95 = quantile(log(compound_min_dose_std),
        probs = 0.975, na.rm = TRUE)) %>%
    # Transform to a format suitable for ggplot annotation
pivot_longer(cols = everything(), names_to = "stat", values_to = "value") %>%
    dplyr::mutate(vaule_raw = format(exp(value), scientific = FALSE))
env_conc_summary %>%
    gt()
stat value vaule_raw
median -0.005025168 0.9949874371
lower_89 -6.907755279 0.0010000000
upper_89 7.793933105 2425.8399279662
lower_95 -7.489709151 0.0005588055
upper_95 9.674172499 15901.5600424659

10.7.9 Exposure location

Where the exposure itself was conducted

EIPAAB_database %>%
    dplyr::group_by(compound_exposure_location) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(total = sum(n), perecent = round(n/total * 100, 1)) %>%
    gt()
compound_exposure_location n total perecent
Indoor laboratory setting or assumed indoors 1729 1739 99.4
Outdoor natural setting 4 1739 0.2
Outdoor restricted setting (cannot interact with wild species) 6 1739 0.3

10.8 Behaviour

10.8.1 Counts of catagoires

First I will make a new variable called beahv_catgory_n, which will look at how many of our 10 broad behavioural categories were measured in the article.

The 10 over-arching categories were: (1) movement and locomotion, (2) pre-mating and mating behaviour, (3) post-mating behaviour, (4) aggression, (5) sociality, (6) cognition and learning, (7) anxiety and boldness, (8) foraging and feeding, (9) antipredator behaviour, and (10) other behaviours not categorised

This will take the some of all the behaviour categories., so can range from 1 to 10 for a single behavioural category to all categories.

EIPAAB_database <- EIPAAB_database %>%
    dplyr::mutate(behav_category_n = rowSums(across(starts_with("behav_") & ends_with("_boolean"))))

The majority of evidence seems to be based on a single behavioural category

EIPAAB_database %>%
    dplyr::group_by(behav_category_n) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1)) %>%
    gt()
behav_category_n n percent
1 1205 69.3
2 400 23.0
3 115 6.6
4 16 0.9
5 2 0.1
7 1 0.1

Is this the same by study motivation

EIPAAB_database %>%
    dplyr::group_by(behav_category_n, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    gt()
behav_category_n study_motivation n total_motivation percent
1 Environmental 593 858 69.1
1 Medical 378 518 73.0
1 Basic research 234 363 64.5
2 Environmental 180 858 21.0
2 Medical 110 518 21.2
2 Basic research 110 363 30.3
3 Environmental 75 858 8.7
3 Medical 25 518 4.8
3 Basic research 15 363 4.1
4 Environmental 8 858 0.9
4 Medical 4 518 0.8
4 Basic research 4 363 1.1
5 Environmental 2 858 0.2
7 Medical 1 518 0.2

Here I make a dataframe where I have pivoted the data to long formate based on each of the 10 behaviour categories. This data frame can be used to ask more specific questions about the relationship between species, compound, and behaviour.

But first let’s use it to see what behaviours are most common overall all, and within each study motivation.

I have ploted the first 10 columns as an example of what this looks like

binary_behav <- EIPAAB_database %>%
    dplyr::select((starts_with("behav_") & ends_with("_boolean"))) %>%
    colnames()

PICO_long <- EIPAAB_database %>%
    tidyr::pivot_longer(., cols = all_of(binary_behav), names_to = "behav_category",
        values_to = "value") %>%
    dplyr::select(article_id, study_motivation, species_name, species_class, compound_name,
        compound_atc_level_3, behav_category, value) %>%
    dplyr::mutate(behav_category = behav_category %>%
        str_remove("behav_") %>%
        str_remove("_boolean"))

PICO_long %>%
    head() %>%
    gt()
article_id study_motivation species_name species_class compound_name compound_atc_level_3 behav_category value
236660465 Environmental Danio rerio Actinopterygii Buspirone n05b anxiolytics movement 0
236660465 Environmental Danio rerio Actinopterygii Buspirone n05b anxiolytics boldness 1
236660465 Environmental Danio rerio Actinopterygii Buspirone n05b anxiolytics foraging 0
236660465 Environmental Danio rerio Actinopterygii Buspirone n05b anxiolytics antipredator 0
236660465 Environmental Danio rerio Actinopterygii Buspirone n05b anxiolytics mating 0
236660465 Environmental Danio rerio Actinopterygii Buspirone n05b anxiolytics post_mating 0

Overall use of behaviour

behav_overall <- PICO_long %>%
    dplyr::group_by(behav_category) %>%
    reframe(n = sum(value)) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1)) %>%
    dplyr::arrange(desc(n))
behav_overall %>%
    gt()
behav_category n percent
movement 983 40.4
boldness 567 23.3
foraging 190 7.8
agression 145 6.0
sociality 143 5.9
mating 122 5.0
noncat 96 3.9
cognition 90 3.7
antipredator 85 3.5
post_mating 10 0.4

By study motivation

behav_motivation <- PICO_long %>%
    dplyr::group_by(behav_category, study_motivation) %>%
    dplyr::summarise(n = sum(value), .groups = "drop") %>%
    tidyr::complete(behav_category, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation) %>%
    dplyr::arrange(desc(study_motivation))

behav_overall <- behav_motivation %>%
    dplyr::group_by(behav_category) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1), study_motivation = "Overall")

behav_motivation <- rbind(behav_overall, behav_motivation)

10.8.1.1 Fig 6

motivation_colour_theme <- c("grey", "#60BD6C", "#D359A1", "#3C82C4")
behav_order <- c("movement", "boldness", "foraging", "antipredator", "mating", "post_mating",
    "agression", "sociality", "cognition", "noncat")
study_motivation_order <- c("Overall", "Environmental", "Medical", "Basic research")


behav_motivation_fig <- behav_motivation %>%
    dplyr::mutate(behav_category = factor(behav_category, levels = rev(behav_order)),
        study_motivation = factor(study_motivation, levels = study_motivation_order)) %>%
    ggplot(aes(x = behav_category, y = percent, colour = study_motivation, fill = study_motivation),
        group = study_motivation) + geom_col(width = 0.1, colour = NA) + geom_point(size = 3) +
    geom_text(aes(label = percent), vjust = -0.3, size = 3.5, color = "black") +
    theme_classic() + facet_grid(cols = vars(study_motivation)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + coord_flip() + labs(x = "", y = "Percentage") +
    theme(plot.title = element_text(size = 11))

behav_motivation_fig

Save the figure

# setwd(figures_path) ggsave('behav_motivation_fig.pdf', plot =
# behav_motivation_fig, width = 10, height = 5)

10.8.2 Behaviour sub-categories

behav_select <- EIPAAB_database %>%
    dplyr::select((starts_with("behav_") & !ends_with("_boolean") & !ends_with("is_social_context") &
        !ends_with("test_location") & !ends_with("category_n"))) %>%
    colnames()


behav_sub_cat_long <- EIPAAB_database %>%
    tidyr::pivot_longer(., cols = all_of(behav_select), names_to = "parent_category",
        values_to = "sub_category") %>%
    dplyr::select(article_id, study_motivation, species_name, species_class, compound_name,
        compound_atc_level_3, parent_category, sub_category) %>%
    dplyr::mutate(parent_category = parent_category %>%
        str_remove("behav_")) %>%
    tidyr::separate_rows(sub_category, sep = ";") %>%
    dplyr::filter(!is.na(sub_category))

Now a summary data file with sub-categories.

I have plotted the first 10 rows as an example

behav_sub_cat_summary <- behav_sub_cat_long %>%
    dplyr::group_by(study_motivation, parent_category, sub_category) %>%
    dplyr::summarise(n_sub_cat = n(), .groups = "drop") %>%
    dplyr::group_by(study_motivation, parent_category) %>%
    dplyr::mutate(n_parent = sum(n_sub_cat)) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(n_motivation = sum(n_sub_cat)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent_sub_cat = n_sub_cat/n_parent, percent_parent = n_parent/n_motivation)

behav_sub_cat_summary %>%
    head() %>%
    gt()
study_motivation parent_category sub_category n_sub_cat n_parent n_motivation percent_sub_cat percent_parent
Environmental agression aggression towards a live competitor free to interact 27 70 1511 0.38571429 0.04632694
Environmental agression aggression towards a live competitor with physical barrier 10 70 1511 0.14285714 0.04632694
Environmental agression aggression towards a mirror 20 70 1511 0.28571429 0.04632694
Environmental agression aggression towards a model or video 7 70 1511 0.10000000 0.04632694
Environmental agression locomotor activity within this context 6 70 1511 0.08571429 0.04632694
Environmental antipredator locomotor activity within this context 22 100 1511 0.22000000 0.06618134

Formating the data for a ring plot.

ring_plot_subcat <- behav_sub_cat_summary %>%
    dplyr::group_by(study_motivation, parent_category) %>%
    dplyr::mutate(ymax = cumsum(percent_sub_cat), ymin = lag(ymax, 1), ymin = if_else(is.na(ymin),
        0, ymin), labelPosition = (ymax + ymin)/2, label = paste0(sub_category, "\n (n = ",
        n_sub_cat, ")")) %>%
    dplyr::ungroup()

10.8.2.1 Movement plots

First making a complete dataset (adding zeros for missing sub-categories. in each motivation), and ordering by overall prevalence of sub-categories.

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "movement") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

movement_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "movement") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
10.8.2.1.1 Fig S6-1
beh_movement_subcat_fig <- movement_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_movement_subcat_fig

Save the figure

# n_subcat <- movement_subcat %>% dplyr::distinct(sub_category) %>% nrow(.)/10
# setwd(figures_path) ggsave('beh_movement_subcat_fig.pdf', plot =
# beh_movement_subcat_fig, width = 10, height = 11.7*n_subcat)

If you would like to make a doughnut chart here’s the code. However, for categories that have 5 or more sub-categories like movement I don’t think this is the clearest way to present the data.

movement_subcat %>%
    dplyr::arrange(sub_category) %>%
    dplyr::arrange(study_motivation) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(ymax = cumsum(percent_sub_cat), ymin = lag(ymax, 1), ymin = if_else(is.na(ymin),
        0, ymin), labelPosition = (ymax + ymin)/2, label = if_else(n_sub_cat == 0,
        NA, n_sub_cat)) %>%
    dplyr::ungroup() %>%
    ggplot(aes(ymax = ymax, ymin = ymin, xmax = 4, xmin = 3, fill = sub_category)) +
    geom_rect() + coord_polar(theta = "y") + geom_label(x = 4, aes(y = labelPosition,
    label = label), size = 3, alpha = 0.8) + facet_wrap(~study_motivation) + xlim(c(2,
    5)) + theme_void() + theme(legend.position = "bottom")

10.8.2.2 Boldness plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "boldness") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

boldness_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "boldness") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
10.8.2.2.1 Fig S6-2
beh_boldness_subcat_fig <- boldness_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_boldness_subcat_fig

Save the figure

# n_subcat <- boldness_subcat %>% dplyr::distinct(sub_category) %>% nrow(.)/10
# setwd(figures_path) ggsave('beh_boldness_subcat_fig.pdf', plot =
# beh_boldness_subcat_fig, width = 10, height = 11.7*n_subcat)

10.8.2.3 Foraging plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "foraging") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

foraging_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "foraging") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
10.8.2.3.1 Fig S6-3
beh_foraging_subcat_fig <- foraging_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_foraging_subcat_fig

Save the figure

# n_subcat <- foraging_subcat %>% dplyr::distinct(sub_category) %>% nrow(.)/10
# setwd(figures_path) ggsave('beh_foraging_subcat_fig.pdf', plot =
# beh_foraging_subcat_fig, width = 10, height = 11.7*n_subcat)

10.8.2.4 Antipredator plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "antipredator") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

antipredator_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "antipredator") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
10.8.2.4.1 Fig S6-4
beh_antipredator_subcat_fig <- antipredator_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_antipredator_subcat_fig

Save figure

# n_subcat <- antipredator_subcat %>% dplyr::distinct(sub_category) %>%
# nrow(.)/10 setwd(figures_path) ggsave('beh_antipredator_subcat_fig.pdf', plot
# = beh_antipredator_subcat_fig, width = 10, height = 11.7*n_subcat)

10.8.2.5 Mating plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "mating") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

mating_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "mating") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
10.8.2.5.1 Fig S6-5
beh_mating_subcat_fig <- mating_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_mating_subcat_fig

Save the figure

# n_subcat <- mating_subcat %>% dplyr::distinct(sub_category) %>% nrow(.)/10
# setwd(figures_path) ggsave('beh_mating_subcat_fig.pdf', plot =
# beh_mating_subcat_fig, width = 10, height = 11.7*n_subcat)

10.8.2.6 Post mating plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "post_mating") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

post_mating_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "post_mating") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
10.8.2.6.1 Fig S6-6
beh_post_mating_subcat_fig <- post_mating_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_post_mating_subcat_fig

Save the figure

# n_subcat <- post_mating_subcat %>% dplyr::distinct(sub_category) %>%
# nrow(.)/10 setwd(figures_path) ggsave('beh_post_mating_subcat_fig.pdf', plot
# = beh_post_mating_subcat_fig, width = 10, height = 11.7*n_subcat)

10.8.2.7 Agression plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "agression") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

agression_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "agression") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
10.8.2.7.1 Fig S6-7
beh_agression_subcat_fig <- agression_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_agression_subcat_fig

Save the figure

# n_subcat <- agression_subcat %>% dplyr::distinct(sub_category) %>% nrow(.)/10
# setwd(figures_path) ggsave('beh_agression_subcat_fig.pdf', plot =
# beh_agression_subcat_fig, width = 10, height = 11.7*n_subcat)

10.8.2.8 Sociality plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "sociality") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

sociality_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "sociality") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
10.8.2.8.1 Fig S6-8
beh_sociality_subcat_fig <- sociality_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_sociality_subcat_fig

Save the figure

# n_subcat <- sociality_subcat %>% dplyr::distinct(sub_category) %>% nrow(.)/10
# setwd(figures_path) ggsave('beh_sociality_subcat_fig.pdf', plot =
# beh_sociality_subcat_fig, width = 10, height = 11.7*n_subcat)

10.8.2.9 Cognition plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "cognition") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

cognition_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "cognition") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
10.8.2.9.1 Fig S6-9
beh_cognition_subcat_fig <- cognition_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_cognition_subcat_fig

Save the figure

# n_subcat <- cognition_subcat %>% dplyr::distinct(sub_category) %>% nrow(.)/10
# setwd(figures_path) ggsave('beh_cognition_subcat_fig.pdf', plot =
# beh_cognition_subcat_fig, width = 10, height = 11.7*n_subcat)

10.8.2.10 Non-categories plots

sub_category_order <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "noncat") %>%
    dplyr::group_by(sub_category) %>%
    dplyr::reframe(n = sum(n_sub_cat)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(sub_category)

noncat_subcat <- behav_sub_cat_summary %>%
    dplyr::filter(parent_category == "noncat") %>%
    dplyr::select(study_motivation, sub_category, percent_sub_cat, n_sub_cat, percent_parent) %>%
    tidyr::complete(sub_category, study_motivation, fill = list(percent_sub_cat = 0,
        n_sub_cat = 0)) %>%
    dplyr::mutate(sub_category = factor(sub_category, levels = sub_category_order))
10.8.2.10.1 Fig S6-10
beh_noncat_subcat_fig <- noncat_subcat %>%
    dplyr::mutate(percent_sub_cat = round(percent_sub_cat, 3) * 100) %>%
    ggplot(aes(x = sub_category, y = percent_sub_cat, colour = study_motivation,
        fill = study_motivation, group = study_motivation)) + geom_col(position = position_dodge(width = 0.8),
    width = 0.1) + geom_point(position = position_dodge(width = 0.8), size = 3) +
    geom_text(aes(label = percent_sub_cat), hjust = -0.6, size = 3.5, color = "black",
        position = position_dodge(width = 0.8)) + scale_colour_manual(values = motivation_colour_theme,
    name = "Study motivation") + scale_fill_manual(values = motivation_colour_theme,
    name = "Study motivation") + theme_classic() + coord_flip() + labs(x = "", y = "Percentage of data") +
    theme(legend.position = "none")

beh_noncat_subcat_fig

Save the figure

# n_subcat <- noncat_subcat %>% dplyr::distinct(sub_category) %>% nrow(.)/10
# setwd(figures_path) ggsave('beh_noncat_subcat_fig.pdf', plot =
# beh_noncat_subcat_fig, width = 10, height = 11.7*n_subcat)

10.8.3 Behaviour location

Check where behaviour was measured.

behav_location_summary <- EIPAAB_database %>%
    dplyr::group_by(study_motivation, behav_test_location) %>%
    dplyr::reframe(n = n()) %>%
    tidyr::separate_rows(behav_test_location, sep = ";") %>%
    dplyr::group_by(study_motivation, behav_test_location) %>%
    dplyr::reframe(n = sum(n)) %>%
    tidyr::complete(behav_test_location, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

behav_location_overall <- behav_location_summary %>%
    dplyr::group_by(behav_test_location) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1), study_motivation = "Overall")

behav_location_summary <- rbind(behav_location_overall, behav_location_summary) %>%
    dplyr::arrange(study_motivation)

behav_location_summary %>%
    gt()
behav_test_location n percent study_motivation
indoor laboratory setting or assumed indoors 363 99.7 Basic research
outdoor natural setting 1 0.3 Basic research
outdoor restricted setting (cannot interact with wild species) 0 0.0 Basic research
indoor laboratory setting or assumed indoors 852 98.7 Environmental
outdoor natural setting 8 0.9 Environmental
outdoor restricted setting (cannot interact with wild species) 3 0.3 Environmental
indoor laboratory setting or assumed indoors 518 99.6 Medical
outdoor natural setting 1 0.2 Medical
outdoor restricted setting (cannot interact with wild species) 1 0.2 Medical
indoor laboratory setting or assumed indoors 1733 99.2 Overall
outdoor natural setting 10 0.6 Overall
outdoor restricted setting (cannot interact with wild species) 4 0.2 Overall

10.8.4 Social context

Check how often behaviour was measured in a social context

behav_social_context_summary <- EIPAAB_database %>%
    dplyr::group_by(study_motivation, behav_is_social_context) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

behav_social_context_overall <- behav_social_context_summary %>%
    dplyr::group_by(behav_is_social_context) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1), study_motivation = "Overall")

behav_social_context_summary <- rbind(behav_social_context_overall, behav_social_context_summary) %>%
    dplyr::arrange(study_motivation)

behav_social_context_summary %>%
    gt()
behav_is_social_context n percent study_motivation
no 287 79.1 Basic research
yes 76 20.9 Basic research
no 634 73.9 Environmental
yes 224 26.1 Environmental
no 443 85.5 Medical
yes 75 14.5 Medical
no 1364 78.4 Overall
yes 375 21.6 Overall

10.8.5 Check how behaviour was meassured

Check how often behaviour was meassured in a social context

behav_behav_scoring_summary <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(study_motivation, validity_behav_scoring_method) %>%
    dplyr::reframe(n = n()) %>%
    tidyr::separate_rows(validity_behav_scoring_method, sep = ";") %>%
    dplyr::group_by(study_motivation, validity_behav_scoring_method) %>%
    dplyr::reframe(n = sum(n)) %>%
    tidyr::complete(validity_behav_scoring_method, study_motivation, fill = list(n = 0)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

behav_behav_scoring_overall <- behav_behav_scoring_summary %>%
    dplyr::group_by(validity_behav_scoring_method) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(percent = round(n/sum(n) * 100, 1), study_motivation = "Overall")

behav_behav_scoring_summary <- rbind(behav_behav_scoring_overall, behav_behav_scoring_summary) %>%
    dplyr::arrange(study_motivation)
behav_behav_scoring_summary %>%
    dplyr::filter(study_motivation == "Overall") %>%
    gt()
validity_behav_scoring_method n percent study_motivation
acoustic analysis software 1 0.1 Overall
live scoring in real time 84 8.6 Overall
manual or human scoring from videos or image 259 26.6 Overall
not specified 221 22.7 Overall
other 1 0.1 Overall
quantifying food consumption 21 2.2 Overall
sensory for physical movement 7 0.7 Overall
supervised automated tracking approaches 378 38.9 Overall

10.9 Linking PICO

Making a data frame for a flow diagram (sankey plot)

PICO_df <- EIPAAB_database %>%
    dplyr::mutate(behav_cat = case_when(behav_movement_boolean == 1 ~ "Movement",
        behav_boldness_boolean == 1 ~ "Boldness", behav_foraging_boolean == 1 ~ "Foraging",
        behav_antipredator_boolean == 1 ~ "Antipredator", behav_mating_boolean ==
            1 ~ "Mating", behav_post_mating_boolean == 1 ~ "Post mating", behav_agression_boolean ==
            1 ~ "Agression", behav_sociality_boolean == 1 ~ "Sociality", behav_cognition_boolean ==
            1 ~ "Cognition", behav_noncat_boolean == 1 ~ "Not categorised", )) %>%
    dplyr::select(study_motivation, compound_name, compound_atc_level_3, species_name,
        species_class, behav_cat)

Let’s look at the 10 most common classes and ATCs

PICO_class_atc <- PICO_df %>%
    dplyr::filter(!is.na(compound_atc_level_3), !is.na(species_class)) %>%
    tidyr::separate_rows(compound_atc_level_3, sep = ";") %>%
    dplyr::mutate(compound_atc_level_3 = str_trim(compound_atc_level_3))

PICO_atc_10 <- PICO_class_atc %>%
    dplyr::group_by(compound_atc_level_3) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::pull(compound_atc_level_3)

PICO_class_10 <- PICO_class_atc %>%
    dplyr::group_by(species_class) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::pull(species_class)

PICO_class_10 <- PICO_class_atc %>%
    dplyr::group_by(species_class) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:10) %>%
    dplyr::pull(species_class)


behav_cat_order <- PICO_class_atc %>%
    dplyr::filter(compound_atc_level_3 %in% PICO_atc_10 & species_class %in% PICO_class_10) %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::pull(behav_cat)


PICO_class_atc_10 <- PICO_class_atc %>%
    dplyr::filter(compound_atc_level_3 %in% PICO_atc_10 & species_class %in% PICO_class_10) %>%
    dplyr::mutate(compound_atc_level_3 = factor(compound_atc_level_3, levels = PICO_atc_10),
        species_class = factor(species_class, levels = PICO_class_10), behav_cat = factor(behav_cat,
            levels = behav_cat_order)) %>%
    dplyr::select(compound_atc_level_3, behav_cat, species_class)

10.9.0.1 Fig 7

PICO_atc_class_sankey <- highcharter::hchart(data_to_sankey(PICO_class_atc_10), "sankey")
PICO_atc_class_sankey

Save interactive version

# setwd(figures_path) htmlwidgets::saveWidget(widget = PICO_atc_class_sankey,
# file = 'PICO_atc_class_sankey.html')

Save static version

# setwd(figures_path) # Make a webshot in pdf : high quality but can not choose
# printed zone webshot::webshot('PICO_atc_class_sankey.html' ,
# 'PICO_atc_class_sankey.pdf', delay = 10)

10.9.1 Common compounds

Lets take a closer look at the 3 most common compounds

EIPAAB_database %>%
    dplyr::group_by(compound_name) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:3) %>%
    gt()
compound_name n
Fluoxetine 200
Diazepam 67
17-alpha-ethinylestradiol 63

10.9.1.1 Fluoxetine

spp_order <- PICO_df %>%
    dplyr::filter(compound_name == "Fluoxetine") %>%
    dplyr::group_by(species_name) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:5) %>%
    pull(species_name)

beh_order <- PICO_df %>%
    dplyr::filter(compound_name == "Fluoxetine" & species_name %in% spp_order) %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    pull(behav_cat)

PICO_fluoxetine <- PICO_df %>%
    dplyr::filter(compound_name == "Fluoxetine" & species_name %in% spp_order) %>%
    dplyr::mutate(species_name = factor(species_name, levels = spp_order), behav_cat = factor(behav_cat,
        levels = beh_order), ) %>%
    dplyr::select(species_name, behav_cat)
10.9.1.1.1 Fig S7-1
PICO_fluoxetine_sankey <- highcharter::hchart(data_to_sankey(PICO_fluoxetine), "sankey",
    name = "PICO")
PICO_fluoxetine_sankey
# setwd(figures_path) htmlwidgets::saveWidget(widget = PICO_fluoxetine_sankey,
# file = 'PICO_fluoxetine_sankey.html')
# setwd(figures_path) # Make a webshot in pdf : high quality but can not choose
# printed zone webshot::webshot('PICO_fluoxetine_sankey.html' ,
# 'PICO_fluoxetine_sankey.pdf', delay = 10)

10.9.1.2 Diazepam

spp_order <- PICO_df %>%
    dplyr::filter(compound_name == "Diazepam") %>%
    dplyr::group_by(species_name) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:5) %>%
    pull(species_name)

beh_order <- PICO_df %>%
    dplyr::filter(compound_name == "Diazepam" & species_name %in% spp_order) %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    pull(behav_cat)

PICO_diazepam <- PICO_df %>%
    dplyr::filter(compound_name == "Diazepam" & species_name %in% spp_order) %>%
    dplyr::mutate(species_name = factor(species_name, levels = spp_order), behav_cat = factor(behav_cat,
        levels = beh_order), ) %>%
    dplyr::select(species_name, behav_cat)
10.9.1.2.1 Fig S7-2
PICO_diazepam_sankey <- highcharter::hchart(data_to_sankey(PICO_diazepam), "sankey",
    name = "PICO")
PICO_diazepam_sankey

Save interactive plot

# setwd(figures_path) htmlwidgets::saveWidget(widget = PICO_diazepam_sankey,
# file = 'PICO_diazepam_sankey.html')

Save static plot

# setwd(figures_path) Make a webshot in pdf : high quality but can not choose
# printed zone webshot::webshot('PICO_diazepam_sankey.html' ,
# 'PICO_diazepam_sankey.pdf', delay = 10)

10.9.1.3 17-alpha-ethinylestradiol

spp_order <- PICO_df %>%
    dplyr::filter(compound_name == "17-alpha-ethinylestradiol") %>%
    dplyr::group_by(species_name) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::slice(1:5) %>%
    pull(species_name)

beh_order <- PICO_df %>%
    dplyr::filter(compound_name == "17-alpha-ethinylestradiol" & species_name %in%
        spp_order) %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::arrange(desc(n)) %>%
    pull(behav_cat)

PICO_EE2 <- PICO_df %>%
    dplyr::filter(compound_name == "17-alpha-ethinylestradiol" & species_name %in%
        spp_order) %>%
    dplyr::mutate(species_name = factor(species_name, levels = spp_order), behav_cat = factor(behav_cat,
        levels = beh_order), ) %>%
    dplyr::select(species_name, behav_cat)
10.9.1.3.1 Fig S7-3
PICO_EE2_sankey <- highcharter::hchart(data_to_sankey(PICO_EE2), "sankey", name = "PICO")
PICO_EE2_sankey

Save interactive plot

# setwd(figures_path) htmlwidgets::saveWidget(widget = PICO_EE2_sankey, file =
# 'PICO_EE2_sankey.html')

Save static plot

# setwd(figures_path) #Make a webshot in pdf : high quality but can not choose
# printed zone webshot::webshot('PICO_EE2_sankey.html' , 'PICO_EE2_sankey.pdf',
# delay = 10)

10.10 Knowledge clusters and gaps

Identify knowledge clusters and gaps.

We will also do this by study motivation, because the knowledge gaps will be motivation specific.

10.10.1 Species class

First look by species class

Making a data frame

behav_cat_class_long <- PICO_df %>%
    dplyr::group_by(study_motivation, species_class, behav_cat) %>%
    dplyr::reframe(count = n()) %>%
    tidyr::complete(study_motivation, species_class, behav_cat, fill = list(count = 0)) %>%
    dplyr::group_by(study_motivation, species_class) %>%
    dplyr::mutate(total_class_motivation = sum(count)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(rel_percent = round(count/total_class_motivation * 100, 0), rel_percent = if_else(is.finite(rel_percent),
        rel_percent, 0))

class_order <- behav_cat_class_long %>%
    dplyr::group_by(species_class) %>%
    dplyr::reframe(n = sum(count)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(species_class)

behav_cat_order <- behav_cat_class_long %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = sum(count)) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::pull(behav_cat)

behav_cat_class_long <- behav_cat_class_long %>%
    dplyr::mutate(species_class = factor(species_class, levels = class_order), behav_cat = factor(behav_cat,
        levels = behav_cat_order))

Creating a tile plot

cust_col <- colorRampPalette(c("#FDEDF4", "#F068A7"))(30)

behav_class_hm <- behav_cat_class_long %>%
    ggplot(aes(x = behav_cat, y = species_class, fill = count)) + geom_tile() + scale_fill_gradientn(colors = cust_col,
    na.value = "white", limits = c(1, max(behav_cat_class_long$count, na.rm = TRUE)),
    guide = "none") + theme_bw() + facet_wrap(~study_motivation) + theme(axis.text.x = element_text(angle = 45,
    hjust = 1)) + labs(x = "Behaviour", y = "Species Class", fill = "Count")
behav_class_hm

# setwd(figures_path) ggsave('behav_class_hm.pdf', plot = behav_class_hm, width
# = 8.3, height = 11.7/2)

This one uses relative vaules for each class (e.g. row in the heat map)

cust_col <- colorRampPalette(brewer.pal(4, "Oranges"))(30)

behav_class_rel_hm <- behav_cat_class_long %>%
    ggplot(aes(x = behav_cat, y = species_class, fill = rel_percent)) + geom_tile() +
    # geom_text(aes(label = ifelse(rel_percent == 0, NA, rel_percent)), color =
    # 'black', size = 3) +
scale_fill_gradientn(colors = cust_col, na.value = "white", limits = c(1, max(behav_cat_class_long$count,
    na.rm = TRUE)), guide = "none") + theme_bw() + facet_wrap(~study_motivation) +
    theme(axis.text.x = element_text(angle = 45, hjust = 1)) + labs(x = "Behaviour",
    y = "Species Class", fill = "Count")
behav_class_rel_hm

# setwd(figures_path) ggsave('behav_class_rel_hm.pdf', plot =
# behav_class_rel_hm, width = 8.3, height = 11.7/2)

10.10.2 Compound cluster/gaps

Now looking by compound

Making a data frame

behav_atc_long <- PICO_df %>%
    separate_rows(compound_atc_level_3, sep = ";") %>%
    dplyr::group_by(study_motivation, compound_atc_level_3, behav_cat) %>%
    dplyr::reframe(count = n()) %>%
    tidyr::complete(study_motivation, compound_atc_level_3, behav_cat, fill = list(count = 0)) %>%
    dplyr::group_by(study_motivation, compound_atc_level_3) %>%
    dplyr::mutate(total_atc_motivation = sum(count)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(rel_percent = round(count/total_atc_motivation * 100, 0), rel_percent = if_else(is.finite(rel_percent),
        rel_percent, 0))

atc_order <- behav_atc_long %>%
    dplyr::group_by(compound_atc_level_3) %>%
    dplyr::reframe(n = sum(count)) %>%
    dplyr::arrange(n) %>%
    dplyr::pull(compound_atc_level_3)

behav_cat_order <- behav_atc_long %>%
    dplyr::group_by(behav_cat) %>%
    dplyr::reframe(n = sum(count)) %>%
    dplyr::arrange(desc(n)) %>%
    dplyr::pull(behav_cat)

behav_atc_long <- behav_atc_long %>%
    dplyr::mutate(compound_atc_level_3 = factor(compound_atc_level_3, levels = atc_order),
        behav_cat = factor(behav_cat, levels = behav_cat_order))

There are 132 ATC level 3 codes. So a tile plot is not going to be very informative. It could be useful if you are only interested in a few ATC groups.

behav_atc_long %>%
    dplyr::distinct(compound_atc_level_3) %>%
    nrow()
## [1] 132

Code for title plot if you would like to make one.

# cust_col <- colorRampPalette(c('#FDEDF4', '#F068A7'))(30) behav_atc_hm <-
# behav_atc_long %>% ggplot(aes(x = behav_cat, y = compound_atc_level_3, fill =
# count)) + geom_tile() + #geom_text(aes(label = ifelse(count == 0, NA,
# count)), color = 'black', size = 3) + scale_fill_gradientn(colors = cust_col,
# na.value = 'white', limits = c(1, max(behav_atc_long$count, na.rm = TRUE)),
# guide = 'none') + theme_void() + facet_wrap(~study_motivation) +
# theme(axis.text.x = element_text(angle = 45, hjust = 1)) + labs( x =
# 'Behaviour', y = 'Species Class', fill = 'Count' ) behav_atc_hm

Save figure

# setwd(figures_path) ggsave('behav_atc_hm.pdf', plot = behav_atc_hm, width =
# 8.3, height = 11.7/2)

10.11 Additional biomarkers

How many meassured addtional biomarks

EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::group_by(additional_biomarkers) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(total = sum(n), percent = n/total) %>%
    gt()
additional_biomarkers n total percent
No 435 901 0.4827969
Yes 466 901 0.5172031

How many measured survival/growth/reproduction

EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::group_by(validity_survival_growth_reproduction) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::mutate(total = sum(n), percent = n/total) %>%
    gt()
validity_survival_growth_reproduction n total percent
No 543 901 0.6026637
Yes 358 901 0.3973363

10.12 Validity

There are 19 metadata columns relating to validty: “validity_guideline”, “validity_good_laboratory_practice”, “validity_survival_growth_reproduction”, “validity_animal_feeding”, “validity_water_quality”, “validity_light_cycle”, “validity_randomization”, “validity_behav_scoring_method”, “validity_behav_blinding”, “validity_conflict_statement”, “species_source”, “species_stage”, “species_sex”, “compound_min_duration_exposure”, “compound_max_duration_exposure”, “validity_compound_cas_reported”, “validity_compound_purity_reported”, “validity_compound_water_verification”, “validity_compound_animal_verification”.

10.12.1 Did it follow a guideline (CRED Q1)

guideline <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_guideline, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

guideline_all <- guideline %>%
    dplyr::group_by(validity_guideline) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


guideline_all <- rbind(guideline_all, guideline) %>%
    dplyr::filter(validity_guideline == "Yes")
guideline_all %>%
    gt()
validity_guideline n study_motivation percent
Yes 135 Overall 15.0
Yes 111 Environmental 21.8
Yes 14 Medical 6.0
Yes 10 Basic research 6.3

10.12.2 Did it use good laboratory practice (CRED Q2)

GLP <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_good_laboratory_practice, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

GLP_all <- GLP %>%
    dplyr::group_by(validity_good_laboratory_practice) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


GLP_all <- rbind(GLP_all, GLP) %>%
    dplyr::filter(validity_good_laboratory_practice == "Yes")
GLP_all %>%
    gt()
validity_good_laboratory_practice n study_motivation percent
Yes 6 Overall 0.7
Yes 5 Environmental 1.0
Yes 1 Medical 0.4

10.12.3 Did it report survival, growth and/or reproduction (CRED Q3)

survival_growth_reproduction <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_survival_growth_reproduction, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

survival_growth_reproduction_all <- survival_growth_reproduction %>%
    dplyr::group_by(validity_survival_growth_reproduction) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


survival_growth_reproduction_all <- rbind(survival_growth_reproduction_all, survival_growth_reproduction) %>%
    dplyr::filter(validity_survival_growth_reproduction == "Yes")
survival_growth_reproduction_all %>%
    gt()
validity_survival_growth_reproduction n study_motivation percent
Yes 358 Overall 39.7
Yes 273 Environmental 53.5
Yes 61 Medical 26.2
Yes 24 Basic research 15.2

10.12.4 Did it report compound cas (CRED Q5)

CAS <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_compound_cas_reported, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

CAS_all <- CAS %>%
    dplyr::group_by(validity_compound_cas_reported) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


CAS_all <- rbind(CAS_all, CAS) %>%
    dplyr::filter(validity_compound_cas_reported == "Yes")
CAS_all %>%
    gt()
validity_compound_cas_reported n study_motivation percent
Yes 223 Overall 24.8
Yes 187 Environmental 36.7
Yes 25 Medical 10.7
Yes 11 Basic research 7.0

10.12.5 Did it report compound purity (CRED Q6)

purity <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_compound_purity_reported, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

purity_all <- purity %>%
    dplyr::group_by(validity_compound_purity_reported) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


purity_all <- rbind(purity_all, purity) %>%
    dplyr::filter(validity_compound_purity_reported == "Yes")
purity_all %>%
    gt()
validity_compound_purity_reported n study_motivation percent
Yes 229 Overall 25.4
Yes 200 Environmental 39.2
Yes 20 Medical 8.6
Yes 9 Basic research 5.7

10.12.6 Species infomartion (CRED Q8)

10.12.6.1 Life stage

stage <- EIPAAB_database %>%
    dplyr::group_by(unique_population_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(species_stage, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    tidyr::separate_rows(species_stage, sep = ";") %>%
    dplyr::group_by(species_stage, study_motivation) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

stage_all <- stage %>%
    dplyr::group_by(species_stage) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


stage_all <- rbind(stage_all, stage) %>%
    dplyr::filter(species_stage == "Unknown or not specified") %>%
    dplyr::mutate(percent_reported = 100 - percent)
stage_all %>%
    gt()
species_stage n study_motivation percent percent_reported
Unknown or not specified 166 Overall 16.6 83.4
Unknown or not specified 100 Environmental 17.1 82.9
Unknown or not specified 22 Medical 9.0 91.0
Unknown or not specified 44 Basic research 26.5 73.5

10.12.6.2 Sex

sex <- EIPAAB_database %>%
    dplyr::group_by(unique_population_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(species_sex, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    tidyr::separate_rows(species_sex, sep = ";") %>%
    dplyr::group_by(species_sex, study_motivation) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

sex_all <- sex %>%
    dplyr::group_by(species_sex) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


sex_all <- rbind(sex_all, sex) %>%
    dplyr::filter(species_sex == "Unknown or not specified") %>%
    dplyr::mutate(percent_reported = 100 - percent)
sex_all %>%
    gt()
species_sex n study_motivation percent percent_reported
Unknown or not specified 546 Overall 46.5 53.5
Unknown or not specified 325 Environmental 50.4 49.6
Unknown or not specified 132 Medical 41.0 59.0
Unknown or not specified 89 Basic research 43.2 56.8

10.12.7 The soruce of species (CRED Q9)

source <- EIPAAB_database %>%
    dplyr::group_by(unique_population_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(species_source, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    tidyr::separate_rows(species_source, sep = ";") %>%
    dplyr::group_by(species_source, study_motivation) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

source_all <- source %>%
    dplyr::group_by(species_source) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


source_all <- rbind(source_all, source) %>%
    dplyr::filter(species_source == "Not reported") %>%
    dplyr::mutate(percent_reported = 100 - percent)
source_all %>%
    gt()
species_source n study_motivation percent percent_reported
Not reported 148 Overall 15.6 84.4
Not reported 72 Environmental 13.1 86.9
Not reported 51 Medical 21.2 78.8
Not reported 25 Basic research 15.4 84.6

10.12.8 experimental system (CRED Q11)

10.12.8.1 Feeding

feeding <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_animal_feeding, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

feeding_all <- feeding %>%
    dplyr::group_by(validity_animal_feeding) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


feeding_all <- rbind(feeding_all, feeding) %>%
    dplyr::filter(validity_animal_feeding == "Yes")
feeding_all %>%
    gt()
validity_animal_feeding n study_motivation percent
Yes 716 Overall 79.5
Yes 430 Environmental 84.3
Yes 159 Medical 68.2
Yes 127 Basic research 80.4

10.12.8.2 Water quality

water <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_water_quality, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

water_all <- water %>%
    dplyr::group_by(validity_water_quality) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


water_all <- rbind(water_all, water) %>%
    dplyr::filter(validity_water_quality == "Yes")
water_all %>%
    gt()
validity_water_quality n study_motivation percent
Yes 806 Overall 89.5
Yes 473 Environmental 92.7
Yes 206 Medical 88.4
Yes 127 Basic research 80.4

10.12.8.3 light cycle

light <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_light_cycle, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

light_all <- light %>%
    dplyr::group_by(validity_light_cycle) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


light_all <- rbind(light_all, light) %>%
    dplyr::filter(validity_light_cycle == "Yes")
light_all %>%
    gt()
validity_light_cycle n study_motivation percent
Yes 756 Overall 83.9
Yes 429 Environmental 84.1
Yes 200 Medical 85.8
Yes 127 Basic research 80.4

10.12.9 Exposure duration (CRED Q14)

10.12.9.1 Minimum duration

min_duration <- EIPAAB_database %>%
    dplyr::group_by(compound_min_duration_exposure, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

min_duration_all <- min_duration %>%
    dplyr::group_by(compound_min_duration_exposure) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


min_duration_all <- rbind(min_duration_all, min_duration) %>%
    dplyr::filter(compound_min_duration_exposure == "Not stated") %>%
    dplyr::mutate(percent_reported = 100 - percent)
min_duration_all %>%
    gt()
compound_min_duration_exposure n study_motivation percent percent_reported
Not stated 102 Overall 5.9 94.1
Not stated 38 Environmental 4.4 95.6
Not stated 52 Medical 10.0 90.0
Not stated 12 Basic research 3.3 96.7

10.12.10 Maximum duration

max_duration <- EIPAAB_database %>%
    dplyr::group_by(compound_max_duration_exposure, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

max_duration_all <- max_duration %>%
    dplyr::group_by(compound_max_duration_exposure) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


max_duration_all <- rbind(max_duration_all, max_duration) %>%
    dplyr::filter(compound_max_duration_exposure == "Not stated") %>%
    dplyr::mutate(percent_reported = 100 - percent)
max_duration_all %>%
    gt()
compound_max_duration_exposure n study_motivation percent percent_reported
Not stated 96 Overall 5.5 94.5
Not stated 32 Environmental 3.7 96.3
Not stated 53 Medical 10.2 89.8
Not stated 11 Basic research 3.0 97.0

10.12.11 Exposure verification (CRED Q15)

10.12.11.1 Water verification

water_verification <- EIPAAB_database %>%
    dplyr::filter(!is.na(validity_compound_water_verification)) %>%
    dplyr::group_by(validity_compound_water_verification, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

water_verification_all <- water_verification %>%
    dplyr::group_by(validity_compound_water_verification) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


water_verification_all <- rbind(water_verification_all, water_verification) %>%
    dplyr::filter(validity_compound_water_verification == "Measured")
water_verification_all %>%
    gt()
validity_compound_water_verification n study_motivation percent
Measured 313 Overall 20.6
Measured 295 Environmental 35.8
Measured 10 Medical 2.5
Measured 8 Basic research 2.7

10.12.11.2 Tissue verification

tissue_verification <- EIPAAB_database %>%
    # dplyr::filter(!is.na(validity_compound_animal_verification)) %>%
dplyr::group_by(validity_compound_animal_verification, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

tissue_verification_all <- tissue_verification %>%
    dplyr::group_by(validity_compound_animal_verification) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


tissue_verification_all <- rbind(tissue_verification_all, tissue_verification) %>%
    dplyr::filter(validity_compound_animal_verification == "Yes")
tissue_verification_all %>%
    gt()
validity_compound_animal_verification n study_motivation percent
Yes 154 Overall 8.9
Yes 115 Environmental 13.4
Yes 22 Medical 4.2
Yes 17 Basic research 4.7

10.12.12 Randomization (Not CRED)

randomization <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_randomization, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

randomization_all <- randomization %>%
    dplyr::group_by(validity_randomization) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


randomization_all <- rbind(randomization_all, randomization) %>%
    dplyr::filter(validity_randomization == "Yes") %>%
    dplyr::mutate(percent_disclosed = 100 - percent)
randomization_all %>%
    gt()
validity_randomization n study_motivation percent percent_disclosed
Yes 362 Overall 40.2 59.8
Yes 229 Environmental 44.9 55.1
Yes 75 Medical 32.2 67.8
Yes 58 Basic research 36.7 63.3

10.12.13 Blinding (Not CRED)

blinding <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_behav_blinding, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

blinding_all <- blinding %>%
    dplyr::group_by(validity_behav_blinding) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


blinding_all <- rbind(blinding_all, blinding) %>%
    dplyr::filter(validity_behav_blinding == "Yes")
blinding_all %>%
    gt()
validity_behav_blinding n study_motivation percent
Yes 153 Overall 17.0
Yes 75 Environmental 14.7
Yes 44 Medical 18.9
Yes 34 Basic research 21.5

10.12.14 Scoring method (Not CRED)

behav_scoring <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    tidyr::separate_rows(validity_behav_scoring_method, sep = ";") %>%
    dplyr::group_by(validity_behav_scoring_method, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

behav_scoring_all <- behav_scoring %>%
    dplyr::group_by(validity_behav_scoring_method) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


behav_scoring_all <- rbind(behav_scoring_all, behav_scoring) %>%
    dplyr::filter(validity_behav_scoring_method == "not specified") %>%
    dplyr::mutate(percent_specified = 100 - percent)
behav_scoring_all %>%
    gt()
validity_behav_scoring_method n study_motivation percent percent_specified
not specified 221 Overall 22.7 77.3
not specified 130 Environmental 24.0 76.0
not specified 56 Medical 21.5 78.5
not specified 35 Basic research 20.6 79.4

10.12.15 Conflict statement (Not CRED)

conflict <- EIPAAB_database %>%
    dplyr::group_by(article_id) %>%
    dplyr::sample_n(1) %>%
    dplyr::ungroup() %>%
    dplyr::group_by(validity_conflict_statement, study_motivation) %>%
    dplyr::reframe(n = n()) %>%
    dplyr::group_by(study_motivation) %>%
    dplyr::mutate(total_motivation = sum(n)) %>%
    dplyr::ungroup() %>%
    dplyr::mutate(percent = round(n/total_motivation * 100, 1)) %>%
    dplyr::select(-total_motivation)

conflict_all <- conflict %>%
    dplyr::group_by(validity_conflict_statement) %>%
    dplyr::reframe(n = sum(n)) %>%
    dplyr::mutate(study_motivation = "Overall", percent = round(n/sum(n) * 100, 1))


conflict_all <- rbind(conflict_all, conflict) %>%
    dplyr::filter(validity_conflict_statement == "No statement is made in the paper") %>%
    dplyr::mutate(percent_specified = 100 - percent)
conflict_all %>%
    gt()
validity_conflict_statement n study_motivation percent percent_specified
No statement is made in the paper 407 Overall 45.2 54.8
No statement is made in the paper 254 Environmental 49.8 50.2
No statement is made in the paper 65 Medical 27.9 72.1
No statement is made in the paper 88 Basic research 55.7 44.3

11 💻 Session Informtion

# pander for making it look nicer
sessionInfo() %>%
    pander()

R version 4.2.3 (2023-03-15 ucrt)

Platform: x86_64-w64-mingw32/x64 (64-bit)

locale: LC_COLLATE=English_Australia.utf8, LC_CTYPE=English_Australia.utf8, LC_MONETARY=English_Australia.utf8, LC_NUMERIC=C and LC_TIME=English_Australia.utf8

attached base packages: stats, graphics, grDevices, utils, datasets, methods and base

other attached packages: readxl(v.1.4.3), gt(v.0.11.0), here(v.1.0.1), pander(v.0.6.5), highcharter(v.0.9.4), ggdist(v.3.3.2), gridExtra(v.2.3), ape(v.5.8), treeio(v.1.22.0), ggtree(v.3.6.2), RColorBrewer(v.1.1-3), ggrepel(v.0.9.3), igraph(v.1.6.0), ggraph(v.2.1.0), lubridate(v.1.9.2), forcats(v.1.0.0), stringr(v.1.5.1), dplyr(v.1.1.1), purrr(v.1.0.1), readr(v.2.1.4), tidyr(v.1.3.0), tibble(v.3.2.1), ggplot2(v.3.5.1) and tidyverse(v.2.0.0)

loaded via a namespace (and not attached): nlme(v.3.1-162), fs(v.1.6.4), xts(v.0.14.0), rprojroot(v.2.0.4), tools(v.4.2.3), backports(v.1.4.1), bslib(v.0.7.0), utf8(v.1.2.3), R6(v.2.5.1), lazyeval(v.0.2.2), colorspace(v.2.1-0), withr(v.3.0.0), tidyselect(v.1.2.1), curl(v.5.2.1), compiler(v.4.2.3), cli(v.3.6.1), pacman(v.0.5.1), formatR(v.1.14), xml2(v.1.3.3), labeling(v.0.4.3), sass(v.0.4.9), scales(v.1.3.0), digest(v.0.6.31), yulab.utils(v.0.1.4), rmarkdown(v.2.21), pkgconfig(v.2.0.3), htmltools(v.0.5.8.1), highr(v.0.11), fastmap(v.1.1.1), htmlwidgets(v.1.6.2), rlang(v.1.1.0), TTR(v.0.24.4), rstudioapi(v.0.14), quantmod(v.0.4.26), gridGraphics(v.0.5-1), jquerylib(v.0.1.4), farver(v.2.1.1), generics(v.0.1.3), zoo(v.1.8-12), jsonlite(v.1.8.4), distributional(v.0.4.0), magrittr(v.2.0.3), rlist(v.0.4.6.2), ggplotify(v.0.1.2), patchwork(v.1.2.0), Rcpp(v.1.0.10), munsell(v.0.5.1), fansi(v.1.0.4), viridis(v.0.6.5), lifecycle(v.1.0.4), stringi(v.1.7.12), yaml(v.2.3.7), MASS(v.7.3-58.2), grid(v.4.2.3), parallel(v.4.2.3), lattice(v.0.20-45), graphlayouts(v.1.0.2), hms(v.1.1.3), knitr(v.1.42), pillar(v.1.9.0), codetools(v.0.2-19), glue(v.1.6.2), evaluate(v.0.24.0), ggfun(v.0.1.5), data.table(v.1.14.8), vctrs(v.0.6.1), tzdb(v.0.3.0), tweenr(v.2.0.3), cellranger(v.1.1.0), gtable(v.0.3.5), polyclip(v.1.10-6), assertthat(v.0.2.1), cachem(v.1.0.7), xfun(v.0.38), ggforce(v.0.4.1), broom(v.1.0.4), tidygraph(v.1.3.0), tidytree(v.0.4.6), viridisLite(v.0.4.2), aplot(v.0.2.3), memoise(v.2.0.1) and timechange(v.0.2.0)

LS0tDQp0aXRsZTogIkVJUEFBQl9kYXRhX3N1bW1hcnkiDQphdXRob3I6ICJKYWtlIE1hcnRpbiINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBkZXB0aDogNA0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6ICBjb3Ntbw0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQprbml0OiB8DQogIChmdW5jdGlvbihpbnB1dCwgLi4uKSB7DQogICAgcm1hcmtkb3duOjpyZW5kZXIoDQogICAgICBpbnB1dCwNCiAgICAgIG91dHB1dF9maWxlID0gcGFzdGUwKA0KICAgICAgICdpbmRleC5odG1sJw0KICAgICAgKSwNCiAgICAgIGVudmlyID0gZ2xvYmFsZW52KCkNCiAgICApDQogIH0pDQotLS0NCg0KPCEtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tPg0KIyDimpnvuI8gS25pdCBzZXR0aW5ncyANCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLT4NCg0KSGVyZSB3ZSBkZWZpbmUgb3VyIEtuaXQgc2V0dGluZ3MsIHRvIG1ha2UgdGhlIG91dHB1dCBtb3JlIHVzZXIgZnJpZW5kbHksIGFuZCB0byBjYWNoZSBvdXRwdXQgZm9yIGZhc3RlciBrbml0dGluZy4gIA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0KI2tuaXRlciBzZWV0dGluZw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KbWVzc2FnZSA9IEZBTFNFLA0Kd2FybmluZyA9IEZBTFNFLCAjIG5vIHdhcm5pbmdzDQpjYWNoZSA9IFRSVUUsIyBDYWNoZWluZyB0byBzYXZlIHRpbWUgd2hlbiBrbml0aW5nDQp0aWR5ID0gVFJVRQ0KKQ0KYGBgDQoNCg0KPCEtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tPg0KIyDwn5OVIFJFQUQgTUUgDQo8IS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+DQoNClRoaXMgaXMgdGhlIHRoZSBSIG1hcmtkb3duIHNjcmlwdCB3cml0dGVuIGluIFIgc3R1ZGlvICgyMDIzLjA5LjArNDYzICJEZXNlcnQgU3VuZmxvd2VyIiBSZWxlYXNlKSB1c2VkIHRvIHN1bW1hcmlzZSB0aGUgc3lzdGVtYXRpYyBtYXAgZGF0YWJhc2UgZnJvbSBNYXJ0aW4gZXQgYWwuIDIwMjQgIkV2aWRlbmNlIG9mIHRoZSBpbXBhY3RzIG9mIHBoYXJtYWNldXRpY2FscyBvbiBhcXVhdGljICBhbmltYWwgYmVoYXZpb3VyIChFSVBBQUIpOiBhIHN5c3RlbWF0aWMgbWFwIGFuZCBvcGVuIGFjY2VzcyBkYXRhYmFzZSIgKGRvaTogKirwn5qndG8gYmUgYWRkZWTwn5qnKiopLiANCg0KSXQgaXMgZGVzaWduZWQgdG8gYWN0IGFzIGEgc3RhcnRpbmcgcG9pbnQgZm9yIGFueW9uZSB3aG8gd2lzaGVzIHRvIHVzZSB0aGUgJ0V2aWRlbmNlIG9mIHRoZSBJbXBhY3RzIG9mIFBoYXJtYWNldXRpY2FscyBvbiBBcXVhdGljICBBbmltYWwgQmVoYXZpb3VyJyAoRUlQQUFCKSBkYXRhYmFzZSBmb3IgdGhlaXIgb3duIHByb2plY3RzLiBCdXQgYWxzbyBhcyBhIGRlc2NyaXB0aW9uIG9mIGhvdyB0aGUgc3VtbWFyeSBwcmVzZW50IGluIHRoZSBNYW51c2NyaXB0IHdhcyBjb25kdWN0ZWQuICAgIA0KDQpJIHJlY29tbWVuZGVkIHlvdSByZWFkIHRoZSAnUkVBRE1FJyBmaWxlcyBiZWZvcmUgeW91IHdvcmsgd2l0aCB0aGUgRUlQQUFCIGRhdGFiYXNlLCB0aGVyZSBhcmUgdHdvICciJ1JFQURNRS5tZCcgYW5kICdSRUFETUUuY3N2Jywgc3RhcnQgd2l0aCB0aGUgJy5tZCcgZmlsZSAoaHR0cHM6Ly9naXRodWIuY29tL0pha2VNYXJ0aW5SZXNlYXJjaC9FSVBBQUItZGF0YWJhc2UvYmxvYi9tYWluL1JFQURNRS5tZCkNCg0KDQoqKlAucyoqIEFwb2xvZ2llcyBmb3IgYW55IHNwZWxsaW5nIG1pc3Rha2VzIGluIHRoZSBzY3JpcHQgSSAoSmFrZSBNYXJ0aW4pIGFtIGR5c2xleGljIGFuZCB0aGlzIGlzIGEgdmVyeSBsb25nIGRvY3VtZW50IA0KDQo8IS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+DQojIPCfk5EgU2hhcmluZy9hY2Nlc3NpbmcgYW5kIGNpdGluZw0KPCEtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tPg0KDQoxLiAqKkxpY2Vuc2VzL3Jlc3RyaWN0aW9ucyBwbGFjZWQgb24gdGhlIGRhdGE6KiogQ0MtQlkgNC4wICANCg0KMi4gKipMaW5rcyB0byBwdWJsaWNhdGlvbnMgdGhhdCBjaXRlIG9yIHVzZSB0aGUgZGF0YToqKiBNYXJ0aW4sIEpNLCBNaWNoZWxhbmdlbGksIE0sIEJlcnRyYW0sIE1HLCBCbGFuY2hmaWVsZCwgUEosIEJyYW5kLCBKQSwgQnJvZGluLCBULCBCcm9va3MsIEIsIENlcnZlbnksIEQsIEZlcmd1c3NvbiwgS04sIExhZ2lzeiwgTSwgTG92aW4sIExNLCBMaWdvY2tpLCBJWSwgTmFrYWdhd2EsIFMsIE96ZWtpLCBTLCBTYW5kb3ZhbC1IZXJyZXJhLCBOLCBLZW5kYWxsLCBTLCBTdW5kaW4sIEosIFRhbiwgSCwgVGhvcsK0ZSwgRSwgV29uZywgQkJNLCBNY0NhbGx1bSwgRVMsICgyMDI0KSBFdmlkZW5jZSBvZiB0aGUgSW1wYWN0cyBvZiBQaGFybWFjZXV0aWNhbHMgb24gYXF1YXRpYyBhbmltYWwgYmVoYXZpb3VyIChFSVBBQUIpOiBhIHN5c3RlbWF0aWMgbWFwIGFuZCBvcGVuIGFjY2VzcyBkYXRhYmFzZS4gRWNvRXZvUnhpdiBodHRwczovL2RvaS5vcmcvMTAuMzI5NDIvWDJORzlSICAgIA0KDQozLiAqKlJlY29tbWVuZGVkIGNpdGF0aW9uIGZvciB0aGlzIGRhdGFzZXQ6KiogTWFydGluLCBKTSwgTWljaGVsYW5nZWxpLCBNLCBCZXJ0cmFtLCBNRywgQmxhbmNoZmllbGQsIFBKLCBCcmFuZCwgSkEsIEJyb2RpbiwgVCwgQnJvb2tzLCBCLCBDZXJ2ZW55LCBELCBGZXJndXNzb24sIEtOLCBMYWdpc3osIE0sIExvdmluLCBMTSwgTGlnb2NraSwgSVksIE5ha2FnYXdhLCBTLCBPemVraSwgUywgU2FuZG92YWwtSGVycmVyYSwgTiwgS2VuZGFsbCwgUywgU3VuZGluLCBKLCBUYW4sIEgsIFRob3LCtGUsIEUsIFdvbmcsIEJCTSwgTWNDYWxsdW0sIEVTLCAoMjAyNCkgRUlQQUFCIGRhdGFiYXNlLCBodHRwczovL2RvaS5vcmcvMTAuMTc2MDUvT1NGLklPL0FUV1k2ICAgIA0KDQo8IS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+DQojIPCfk6cgQ29udGFjdA0KPCEtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tPg0KDQoqKkpha2UgTS4gTWFydGluKioNCiAgDQrwn5OnICoqRW1haWw6KiogW2pha2UubWFydGluQGRlYWtpbi5lZHUuYXVdKG1haWx0bzpqYWtlLm1hcnRpbkBkZWFraW4uZWR1LmF1KSAgDQogIA0K8J+TpyAqKkFsdCBFbWFpbDoqKiBbamFrZS5tYXJ0aW4ucmVzZWFyY2hAZ21haWwuY29tXShtYWlsdG86amFrZS5tYXJ0aW4ucmVzZWFyY2hAZ21haWwuY29tKSANCiAgDQrwn4yQICoqV2ViOioqIFtqYWtlbWFydGluLm9yZ10oaHR0cHM6Ly9qYWtlbWFydGluLm9yZy8pICANCiAgDQrwn5CZICoqR2l0SHViKio6IFtKYWtlTWFydGluUmVzZWFyY2hdKGh0dHBzOi8vZ2l0aHViLmNvbS9KYWtlTWFydGluUmVzZWFyY2gpICANCg0KPCEtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tPg0KIyDijKjvuI8gUiBpbmZvcm1hcnRpb24NCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLT4NCg0KSWYgeW91IGFyZSBub3QgZmFtaWxpYXIgd2l0aCBSLCBbaGVyZSdzIGEgYmVnaW5uZXJzIGd1aWRlIPCfk7ldKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9X1Y4ZUtzdG8zVWcpICAgDQoNCkhlcmUncyBhIGxpbmsgdG8gZG93bmxvYWQgW1Ig8J+TpV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvKSBhbmQgZG93bmxvYWQgW1Igc3R1ZGlvIPCfk6VdKGh0dHBzOi8vcG9zaXQuY28vcHJvZHVjdHMvb3Blbi1zb3VyY2UvcnN0dWRpby8pICAgDQoNClRoaXMgaXMgYW4gUiBtYXJrZG93biBmaWxlLCB3aGljaCBtYWtlcyBhbm5vdGF0aW5nIGFuZCBydW5uaW5nIFIgY29kZSBtb3JlIHVzZXIgZnJpZW5kbHksIGl0IGlzIGFsc28gZWFzeSB0byByZXByb2R1Y2libGUgYW5kIHNoYXJlIGluIGEgdmFyaWF0ZSBvZiBmb3JtYXRlcyAoZS5nLiBodGxtKS4gVGhlIFIgY29kZSBpcyBlbWJlZCB3aXRoaW4gY2h1bmtzLCBhbmQgdGhlIG91dHB1dCBmb3IgY29kZSB3aWxsIGJlIGVtYmVkZGVkIHVuZGVyIHRoZSBjaHVjay4NCg0KYGBge3J9IA0KIyBUaGlzIGlzIGEgY2h1Y2sNCmBgYA0KDQpBbGwgb3RoZXIgdGV4dCBvdXRzaWRlIG9mIHRoZSBjaHVja3MgYXJlIGFubm90YXRpb25zIChsaWtlIHRoaXMpLiBIYXNodGFncyB1c2VkIG91dHNpZGUgb2YgY2h1Y2tzIGFyZSB1c2VkIHRvIGNyZWF0ZSBoZWFkZXJzIGFuZCB0byBzdHJ1Y3R1cmUgdGhlIGZpbGUuIEhhc2h0YWdzIHdpdGhpbiB0aGUgY2h1Y2tzIGFyZSB1c2VkIGZvciBtb3JlIHByZWNpc2UgYW5ub3RhdGlvbiB3aXRoaW4gdGhlIGNvZGUuDQoNCklmIHlvdSBhcmUgbm90IGZhbWlsaWFyIHdpdGggUiBtYXJrZG93biwgW2hlcmUncyBhIGd1aWRlXShodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PXRLVXVmenBvSERFKQ0KDQo8IS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+DQojIPCfk6YgUmVxdWlyZWQgcGFja2FnZXMNCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLT4NCg0KVGhlc2UgYXJlIHRoZSBSIHBhY2thZ2VzIHJlcXVpcmVkIHRvIHJ1biB0aGUgc2NyaXB0LiBJIGhhdmUgYWRkZWQgdGhlbSB0byBhIGxpc3Qgc28gdGhhdCBJIGNhbiBpbnN0YWxsIHRoZW0gYWxsIGluIG9uZSBnbyB1c2luZyB0aGUgZnVuY3Rpb24gYmVsb3cgY2FsbGVkIGxvYWRlZF9wYWNrYWdlcy4gVGhpcyBmdW5jdGlvbiBJIGhhdmUgbWFkZSB3aWxsIGxvYWQgYWxsIHRoZSBwYWNrYWdlcyBpbiB0aGUgbGlzdCBiZWxvdywgaWYgdGhlIHBhY2thZ2VzIGFyZSBub3QgYWxyZWFkeSBpbnN0YWxsZWQsIHRoaXMgZnVuY3Rpb24gd2lsbCBmaXJzdCBpbnN0YWxsIHRoZW0uDQoNCklmIHlvdSB3YW50IHRvIGluc3RhbGwgYW5kIGxvYWQgZWFjaCBwYWNrYWdlIHNlcGFyYXRlbHksIHlvdSBjYW4gdXNlIHRoZSBjb2RlIGluc3RhbGwucGFja2FnZXMoKSBhbmQgcmVxdWlyZSgpLCBJIGhhdmUgZ2l2ZW4gYSBleGFtcGxlIGJlbG93LiBUbyBydW4gdGhpcyBjb2RlIHlvdSB3aWxsIG5lZWQgdG8gaW5zdGFsbCBwYWNtYW4gZmlyc3QgYGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpYA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQojIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQpwYWNtYW46OnBfbG9hZCh0aWR5dmVyc2UsIA0KICAgICAgICAgICAgICAgZ2dyYXBoLCANCiAgICAgICAgICAgICAgIGlncmFwaCwgDQogICAgICAgICAgICAgICBnZ3JlcGVsLCANCiAgICAgICAgICAgICAgIFJDb2xvckJyZXdlciwNCiAgICAgICAgICAgICAgIGdndHJlZSwNCiAgICAgICAgICAgICAgIHRyZWVpbywNCiAgICAgICAgICAgICAgIGFwZSwNCiAgICAgICAgICAgICAgIGdyaWRFeHRyYSwNCiAgICAgICAgICAgICAgIGdnZGlzdCwNCiAgICAgICAgICAgICAgIGhpZ2hjaGFydGVyLA0KICAgICAgICAgICAgICAgcGFuZGVyLA0KICAgICAgICAgICAgICAgaGVyZSwgDQogICAgICAgICAgICAgICBndCwNCiAgICAgICAgICAgICAgIHJlYWR4bA0KKQ0KYGBgDQoNCg0KRm9yIGBnZ3RyZWVgIGFuZCBgdHJlZWlvYCB5b3UgbWF5IG5lZWQgdG8gcnVuIHRoaXMgY29kZSBmb3IgaW5zdGlsbGF0aW9uIA0KDQpgYGB7cn0NCiMgaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkNCiMgICAgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikNCiMgDQojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJnZ3RyZWUiKQ0KYGBgDQoNCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLT4NCiMg8J+TgiBEaXJlY3Rvcmllcw0KPCEtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tPg0KDQpDcmVhdGluZyBvdXQgaW5wdXQgYW5kIG91dHB1dCBkaXJlY3Rvcmllcy4gVGhleSB3aWxsIGJlIG1hZGUgd2l0aGluIHRoZSBjdXJyZW50IHBhcmVudCBkaXJlY3RvcnkgKGkuZS4gd2hlcmUgdGhlIFIgc2NpcHJ0IGlzIHNhdmVkKQ0KDQojIyBPdXRwdXQgZGlyZWN0b3J5IPCfk6QNCg0KVGhpcyBpcyBjb2RlIGNyZWF0ZXMgYSBmb2xkZXIgYW5kIHNhdmVzIHRoZSBkaXJlY3RvcnkgYXMgZmlndXJlX3BhdGguIFRoaXMgaXMgd2hlcmUgd2Ugd2lsbCBleHBvcnQgb3VyIGZpZ3VyZXMNCg0KYGBge3J9DQpmaWd1cmVzX3BhdGggPC0gaGVyZSgiZmlndXJlcyIpDQoNCmlmICghZGlyLmV4aXN0cyhmaWd1cmVzX3BhdGgpKSB7DQogIGRpci5jcmVhdGUoZmlndXJlc19wYXRoKQ0KfQ0KYGBgDQoNClRoaXMgaXMgY29kZSBjcmVhdGVzIGEgZm9sZGVyIGFuZCBzYXZlcyB0aGUgZGlyZWN0b3J5IGFzIG91dHB1dF9wYXRoIFRoaXMgaXMgd2hlcmUgd2Ugd2lsbCBleHBvcnQgb3VyIGRhdGENCg0KYGBge3J9DQpvdXRwdXRfcGF0aCA8LSBoZXJlKCJvdXRwdXQtZGF0YSIpDQoNCmlmICghZGlyLmV4aXN0cyhvdXRwdXRfcGF0aCkpIHsNCiAgZGlyLmNyZWF0ZShvdXRwdXRfcGF0aCkNCn0NCmBgYA0KDQojIyBJbnB1dCBkaXJlY3Rvcnkg8J+TpQ0KDQpgYGB7cn0NCmlucHV0X3BhdGggPC0gaGVyZSgiaW5wdXQtZGF0YSIpDQoNCmlmICghZGlyLmV4aXN0cyhmaWd1cmVzX3BhdGgpKSB7DQogIGRpci5jcmVhdGUoZmlndXJlc19wYXRoKQ0KfQ0KYGBgDQoNCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLT4NCiMg8J+TliBEYXRhYmFzZSBpbmZvcm1hcnRpb24NCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLT4NCg0KVGhlICdFdmlkZW5jZSBvZiB0aGUgSW1wYWN0cyBvZiBQaGFybWFjZXV0aWNhbHMgb24gQXF1YXRpYyAgQW5pbWFsIEJlaGF2aW91cicgKEVJUEFBQikgZGF0YWJhc2UgaGFzIDExMSBjb2x1bW5zIGFuZCAxNzU0IHJvd3MuIFRoZSBjb2x1bW5zIHJlcHJlc2VudCB2YXJpb3VzIGZvcm1zIG9mIG1ldGFkYXRhIGV4dHJhY3RlZCBmcm9tIGFydGljbGVzIHRoYXQgd2VyZSBpbmNsdWRlZCBpbiBNYXJ0aW4gZXQgYWwuIDIwMjQgIkV2aWRlbmNlIG9mIHRoZSBpbXBhY3RzIG9mIHBoYXJtYWNldXRpY2FscyBvbiBhcXVhdGljICBhbmltYWwgYmVoYXZpb3VyOiBhIHN5c3RlbWF0aWMgbWFwIGFuZCBvcGVuIGFjY2VzcyBkYXRhYmFzZSIgKGRvaTogKirwn5qndG8gYmUgYWRkZWTwn5qnKiopLiAgIA0KDQpUaGUgKirwn5K/IFJFQUQtTUUuY3N2KiogZmlsZSB3aGljaCBleHBsYWlucyB3aGF0IGVhY2ggbWV0YWRhdGEgaXMsIGhvdyBpdCB3YXMgZXh0cmFjdGVkLCB3aGF0IHN0cnVjdHVyZSBpdCBoYXMsIGFuZCBhdCB3aGF0IGxldmVsIGl0IGFwcGxpZXMsIGlzIGF2YWlsYWJsZSBhdCBvbiBHaXRIdWIgKGh0dHBzOi8vZ2l0aHViLmNvbS9KYWtlTWFydGluUmVzZWFyY2gvRUlQQUFCLWRhdGFiYXNlL3RyZWUvbWFpbi9pbnB1dC1kYXRhKSBvciBvbiB0aGUgT1NGICgxMC4xNzYwNS9PU0YuSU8vQVRXWTYpIEJlbG93IEkgaGF2ZSBpbXBvcnRlZCB0aGUgcmVhZCBtZSBmb3IgYWNjZXNzaWJpbGl0eS4gSSBoaWdobHkgcmVjb21tZW5kIHlvdSByZWFkIHRoZSBSRUFELU1FIGJlZm9yZSBjb25kdWN0aW5nIGFueSBvZiB5b3VyIG93biBtZXRhLWFuYWx5c2lzIHRvIG1ha2Ugc3VyZSB5b3UgaGF2ZSBpbnRlcm9wZXJhdGVkIHRoZSBkYXRhIGNvcnJlY3RseS4gICANCg0KTW9yZSBnZW5lcmFsbHksIGNvbHVtbiBuYW1lcyB0aGF0IHN0YXJ0IHdpdGggJ3ZhbGlkaXR5JyBhcmUgbWV0YWRhdGEgcmVsYXRpbmcgdG8gc3R1ZHkgdmFsaWRpdHksIHRob3NlIHRoYXQgc3RhcnQgd2l0aCAnc3BlY2llJ3MgcmVsYXRlIHRvIHNwZWNpZXMgaW5mb3JtYXRpb24gKHBvcHVsYXRpb24pLCB0aG9zZSB0aGF0IHN0YXJ0IHdpdGggJ2NvbXBvdW5kJyByZWxhdGUgdG8gdGhlIGNoZW1pY2FsIGluZm9ybWF0aW9uIChleHBvc3VyZSksIHRob3NlIHRoYXQgc3RhcnQgd2l0aCAnYmVoYXYnIHJlbGF0ZSB0byBiZWhhdmlvdXIgaW5mb3JtYXRpb24gKG91dGNvbWUpLiBUaGUgb3JkZXIgb2YgY29sdW1ucyByZWZsZWN0cyBib3RoIHRoZSBsZXZlbCB0aGUgbWV0YWRhdGEgaXMgZXh0cmFjdGVkIGF0IChpLmUuIGFydGljbGUgbGV2ZWwgb3Igc3BlY2llcyBieSBjb21wb3VuZCBsZXZlbDsgc2VlIGxldmVsIGluIFJFQUQtTUUpLCBhcyB3ZWxsIGFzIHRoZSBnZW5lcmFsIGNhdGVnb3J5IG9mIG1ldGFkYXRhIChpLmUuIHZhbGlkaXR5LCBzcGVjaWVzLCBjb21wb3VuZCwgYmVoYXZpb3VyKS4gICANCg0KSGVyZSdzIHRoZSBmaXJzdCAxMCByb3dzIG9mIHRoZSBSRUFEIE1FIGZpbGUgYXMgYW4gZXhhbXBsZQ0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGlucHV0X3BhdGgpDQoNClJFQURfTUUgPC0gcmVhZC5jc3YoIlJFQUQtTUUuY3N2IiwgbmEgPSAiTkEiKSAjIGxvYWRpbmcgdGhlIFJFQUQtTUUgZmlsZQ0KDQpSRUFEX01FICU+JSANCiAgaGVhZCgpICU+JSANCiAgZ3QoKQ0KYGBgDQoNCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLT4NCiMg8J+SvyBJbXBvcnRpbmcgRUlQQUFCIGRhdGFiYXNlDQo8IS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+DQoNCkltcG9ydGluZyB0aGUgKirwn5K/IEVJUEFBQi1kYXRhYmFzZS5jc3YqKiBkYXRhYmFzZSAgIA0KDQpJdCBjYW4gYmUgYXNzZXNzZWQgZnJvbS4uLiAgIA0KDQpHaXRIdWIgKGh0dHBzOi8vZ2l0aHViLmNvbS9KYWtlTWFydGluUmVzZWFyY2gvRUlQQUFCLWRhdGFiYXNlL3RyZWUvbWFpbi9pbnB1dC1kYXRhKSAgIA0KDQpPU0YgKGh0dHBzOi8vb3NmLmlvL2F0d3k2LykgICANCg0KTXkgcGVyc29uYWwgd2VicGFnZSAoaHR0cHM6Ly9qYWtlbWFydGluLm9yZy9laXBhYWItZGF0YWJhc2UvKSAgIA0KDQpJZiB0aGUgQ1NWIGZpbGVzIGFyZSBpbiB0aGUgc2FtZSB3b3JraW5nIGRpcmVjdG9yeSAod2QpIGFzIHRoaXMgUiBzY3JpcHQsIHlvdSB3aWxsIG5vdCBuZWVkIHRvIHVzZSBzZXR3ZCgpLCBidXQgaWYgdGhlIGZpbGVzIGFyZSBsb2NhdGVkIGVsc2V3aGVyZSB5b3Ugd2lsbCBuZWVkIHRvIHNwZWNpZnkgdGhpcyBpbiBzZXR3ZCgpLCBhbmQgcnVuIGFsbCBsaW5lcyBhdCBvbmNlLiBJbiBSIG1hcmtkb3duIHRoZSB3b3JraW5nIGRpcmVjdG9yeSBjaGFuZ2VzIGJhY2sgdG8gZGVmYXVsdCBhZnRlciB0aGUgY2h1Y2sgaXMgcnVuLiAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCnNldHdkKGlucHV0X3BhdGgpDQoNCkVJUEFBQl9kYXRhYmFzZSA8LSByZWFkLmNzdigiRUlQQUFCLWRhdGFiYXNlLmNzdiIsIG5hID0gIk5BIikNCmBgYA0KDQo8IS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0+DQojIPCflbXvuI8gRUlQQUFCIHN1bW1hcnkNCjwhLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLT4NCg0KIyMgVG90YWwgbnVtYmVycw0KDQpUaGUgZmlyc3QgdGhpbmcgd2Ugd2lsbCBsb29rIGF0IGlzIGhvdyBtYW55IHVuaXF1ZSAoZGlzdGluY3QpIGFydGljbGVzIHRoZXJlIGFyZSBpbiB0aGUgZGF0YWJhc2UsIGFuZCBob3cgbWFueSByb3dzIG9mIGRhdGEgdGhlcmUgYXJlLg0KDQpUaGVyZSBhcmUgOTAxIGFydGljbGVzICAgDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSAgDQogIGRwbHlyOjpkaXN0aW5jdChhcnRpY2xlX2lkKSAlPiUgIyBSZXR1cm5zIGEgbGlzdCBvZiBkaXN0aW5jdCBhcnRpY2xlX2lkDQogIG5yb3coLikgIyBSZXR1cm5zIHRoZSBsZW5ndGggb2YgdGhlIGN1cnJlbnQgZmlsZSAod2hpY2ggaXMgdGhlIGxpc3Qgb2YgZGlzdGluY3QgYXJ0aWNsZV9pZCkNCmBgYA0KDQpUaGVyZSBhcmUgMTczOSByb3dzIG9mIGRhdGENCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBucm93KC4pICMgUmV0dXJucyB0aGUgbGVuZ3RoIG9mIHRoZSBjdXJyZW50IGZpbGUgKHdoaWNoIGlzIHRoZSBsZW5ndGggb2YgdGhlIHdob2xlIGRhdGFmaWxlKQ0KYGBgDQoNCg0KRWFjaCByb3cgcmVwcmVzZW50IGEgdW5pcXVlIHNwZWNpZXMgYnkgY29tcG91bmQgY29tYmluYXRpb24gd2l0aGluIGEgZ2l2ZW4gYXJ0aWNsZS4gVGhpcyBpcyByZXByZXNlbnRlZCBieSB0aGUgY29sdW1uIHVuaXF1ZV9yb3dfaWQgVGhpcyBpcyBhIGNvbWJpbmF0aW9uIG9mIHRoZSBleHRyYWN0b3JzIHJlc3BvbnNlIGlkLCBzcGVjaWUscyBhbmQgY29tcG91bmQuIEZvciBleGFtcGxlLCBSXzBCcXoyUlE0SnhQZkJrWl9EYW5pb19yZXJpb19EaWF6ZXBhbSwgcmVzcG9uc2UgaWQgPSBSXzBCcXoyUlE0SnhQZkJrWiwgc3BlY2llcyA9IERhbmlvIHJlcmlvLCBhbmQgY29tcG91bmQgPSBEaWF6ZXBhbQ0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpzZWxlY3QodW5pcXVlX3Jvd19pZCkgJT4lICMgc2VsZWN0cyBqdXN0IHRoZSB1bmlxdWVfY29sdW1uX2lkIGNvbHVtbg0KICBkcGx5cjo6YXJyYW5nZSh1bmlxdWVfcm93X2lkKSAlPiUgIyBhcnJhbmdlcyB0aGUgY29sdW1uIGFscGhhYmV0aWNhbGx5IHNvIHRoZSBzYW1lIGV4YW1wbGVzIHdpbGwgYmUgZ2l2ZW4gZXZlcnl0aW1lIA0KICBkcGx5cjo6c2xpY2UoMToxMCkgJT4lICMgUmV0dXJucyBvbmx5IHRoZSBmaXJzdCAxMCByb3dzIA0KICBndCgpDQpgYGANCg0KTm93IHRoZSBudW1iZXIgb2YgdG90YWwgdHJlYXRtZW50cyByZXByZXNlbnRlZCBpbiB0aGUgZGF0YSwgdGhpcyBpcyB0aGUgdG90YWwgbnVtYmVyIG9mIHVuaXF1ZSBkb3NlcyBwZXIgc3BlY2llcyBieSBjb21wb3VuZCBjb21iaW5hdGlvbi4NCg0KSW4gdGhlIG1hcCB0aGUgbnVtYmVyIG9mIHRyZWF0bWVudHMgd2FzIG9ubHkgZXh0cmFjdGVkIGZvciB3YXRlci1ib3JuZSBleHBvc3VyZXMsIHRoZSBOQXMsIHJlcHJlc2VudCBvdGhlciBleHBvc3VyZSByb3V0ZXMuIFRoZXJlZm9yZSwgdGhlIG51bWJlciBvZiB3YXRlci1ib3JuZSBleHBvc3VyZXMgdHJlYXRtZW50cyBhcmUgNjI5NCwgYW5kIHRoZXJlIGFyZSBhbiBhZGRpdGlvbmFsIDIyNiBhcnRpY2xlcyB0aGF0IGRvbid0IGhhdmUgdHJlYXRtZW50IG51bWJlcnMuIFdlIGtub3cgdGhleSBhbGwgaGF2ZSBhdCBsZWFzdCB0d28gdHJlYXRtZW50cywgYSBjb250cm9sIGFuZCBhIGNvbXBvdW5kIG9mIGludGVyZXN0LCBiZWNhdXNlIHRoYXQgaXMgcGFydCBvZiB0aGUgaW5jbHVzaW9uIGNyaXRlcmlhLiBTbyB3ZSBjb3VsZCBhZGQgdGhlIG51bWJlciBvZiBOQXMgKiAyIHRvIHRoZSB0b3RhbCwgdGhpcyB3b3VsZCBiZSA2NzQ2IHRvdGFsIHRyZWF0bWVudCBncm91cHMuIEFsdGhvdWdoLCB0aGlzIHdvdWxkIGxpa2VseSBiZSBhbiB1bmRlcmVzdGltYXRlIG9mIHRoZSB0cnVlIHRvdGFsLg0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgZ3JvdXBzID0gc3VtKGNvbXBvdW5kX3RyZWF0bWVudF9sZXZlbHMsIG5hLnJtID0gVFJVRSksICMgQ2FsY3VsYXRlIHRoZSBzdW0gb2YgJ2NvbXBvdW5kX3RyZWF0bWVudF9sZXZlbHMnIHdoaWxlIGlnbm9yaW5nIE5BIHZhbHVlcw0KICAgIG5hcyA9IHN1bShpcy5uYShjb21wb3VuZF90cmVhdG1lbnRfbGV2ZWxzKSksICMgQ291bnQgdGhlIG51bWJlciBvZiBOQSB2YWx1ZXMgaW4gJ2NvbXBvdW5kX3RyZWF0bWVudF9sZXZlbHMnDQogICAgdG90YWwgPSBncm91cHMgKyAobmFzICogMikgIyBDYWxjdWxhdGUgdGhlIHRvdGFsIGJ5IGFkZGluZyAnZ3JvdXBzJyB0byB0d2ljZSB0aGUgbnVtYmVyIG9mIE5Bcw0KICApICU+JSANCiAgZ3QoKQ0KYGBgDQoNCiMjIFN0dWR5IG1vdGl2YXRpb24NCg0KTGV0J3MgbG9vayBhdCBob3cgdGhlIGV2aWRlbmNlIGNvbGxlY3RlZCBicmVha3MgZG93biBieSB0aGUgdGhyZWUgc3R1ZHkgbW90aXZhdGlvbnMNCg0KYGBge3J9DQp0b3RhbF9hdHJpY2xlcyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3QoYXJ0aWNsZV9pZCkgJT4lIA0KICBucm93KCkNCg0KIyBBbmFseXplIHRoZSBzdHVkeSBtb3RpdmF0aW9ucyBpbiB0aGUgZGF0YXNldA0KRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lICMgR3JvdXAgdGhlIGRhdGEgYnkgJ2FydGljbGVfaWQnDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgIyBSYW5kb21seSBzYW1wbGUgb25lIHJvdyBmcm9tIGVhY2ggZ3JvdXAgKGkuZS4sIGVhY2ggdW5pcXVlICdhcnRpY2xlX2lkJykNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgIyBVbmdyb3VwIHRoZSBkYXRhIHRvIHJlbW92ZSB0aGUgcHJldmlvdXMgZ3JvdXBpbmcNCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSAjIEdyb3VwIHRoZSBkYXRhIGJ5ICdzdHVkeV9tb3RpdmF0aW9uJw0KICBkcGx5cjo6cmVmcmFtZSggIyBDcmVhdGUgYSBzdW1tYXJ5IGRhdGEgZnJhbWUgd2l0aCB0aGUgY291bnQgYW5kIHBlcmNlbnRhZ2Ugb2YgZWFjaCBzdHVkeSBtb3RpdmF0aW9uDQogICAgbiA9IGxlbmd0aChzdHVkeV9tb3RpdmF0aW9uKSwgICMgQ291bnQgdGhlIG51bWJlciBvZiBvY2N1cnJlbmNlcyBvZiBlYWNoIHN0dWR5IG1vdGl2YXRpb24NCiAgICBgJWAgPSByb3VuZChuIC8gdG90YWxfYXRyaWNsZXMsIDMpICogMTAwICAjIENhbGN1bGF0ZSB0aGUgcGVyY2VudGFnZSBvZiB0b3RhbCBhcnRpY2xlcw0KICApICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lICAjIEFycmFuZ2UgdGhlIHJlc3VsdGluZyBkYXRhIGZyYW1lIGluIGRlc2NlbmRpbmcgb3JkZXIgb2YgdGhlIGNvdW50DQogIGd0KCkNCmBgYA0KDQpIZXJlIHdlIGFyZSBjaGFuZ2luZyB0aGUgb3JkZXIgb2YgdGhlc2UgaW4gdGhlIGRhdGFiYXNlIHRvICJFbnZpcm9ubWVudGFsIiwgIk1lZGljYWwiLCAiQmFzaWMgcmVzZWFyY2giIGZvciBwbG90cy4NCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSBmY3RfcmVsZXZlbChzdHVkeV9tb3RpdmF0aW9uLCAiRW52aXJvbm1lbnRhbCIsICJNZWRpY2FsIiwgIkJhc2ljIHJlc2VhcmNoIikpDQpgYGANCg0KIyMgUHVibGljYXRpb25zIGJ5IHllYXINCg0KIyMjIE51bWJlciBwZXIgeWVhcg0KDQpZZWFyIHJhbmdlIGlzIDE5NzQgdG8gMjAyMiwgc28gNDggeWVhcnMgd29ydGggb2YgZW1waXJpY2FsIHJlc2VhcmNoIGhhcyBjb250cmlidXRlZCB0byB0aGlzIGV2aWRlbmNlIGJhc2UuICAgIA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG1pbl95ZWFyID0gbWluKHllYXIpLA0KICAgICAgICAgICAgICAgICBtYXhfeWVhciA9IG1heCh5ZWFyKSwNCiAgICAgICAgICAgICAgICAgdG90YWxfeWVhcnMgPSBtYXhfeWVhci1taW5feWVhcikgJT4lIA0KICBndCgpDQpgYGANCg0KTm93IG1ha2luZyBhIHN1bW1hcnkgZm9yIHRoZSBudW1iZXIgb2YgcHVibGljYXRpb25zIHBlciB5ZWFyIGJhc2VkIG9uIHN0dWR5IG1vdGl2YXRpb24gICANCg0KYGBge3J9DQojIENyZWF0ZSBhIGNvbXBsZXRlIHNlcXVlbmNlIG9mIHllYXJzIGFuZCBhbGwgdW5pcXVlIHN0dWR5IG1vdGl2YXRpb25zDQphbGxfeWVhcnMgPC0gYXMuY2hhcmFjdGVyKDE5NzQ6MjAyMikNCmFsbF9zdHVkeV9tb3RpdmF0aW9ucyA8LSB1bmlxdWUoRUlQQUFCX2RhdGFiYXNlJHN0dWR5X21vdGl2YXRpb24pDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSB3aXRoIGFsbCBjb21iaW5hdGlvbnMgb2YgeWVhciBhbmQgc3R1ZHkgbW90aXZhdGlvbg0KYWxsX2NvbWJpbmF0aW9ucyA8LSBleHBhbmQuZ3JpZCh5ZWFyID0gYWxsX3llYXJzLCBzdHVkeV9tb3RpdmF0aW9uID0gYWxsX3N0dWR5X21vdGl2YXRpb25zLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCiMgU3VtbWFyaXplIHRoZSBkYXRhDQpwdWJfeWVhciA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIHN1bW1hcml6ZShuID0gbGVuZ3RoKHVuaXF1ZShhcnRpY2xlX2lkKSksIC5ncm91cHMgPSAnZHJvcCcpICU+JSANCiAgbXV0YXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhcikpDQoNCiMgSm9pbiB3aXRoIHRoZSBjb21wbGV0ZSBncmlkIG9mIHllYXJzIGFuZCBzdHVkeSBtb3RpdmF0aW9ucw0KcHViX3llYXJfY29tcGxldGUgPC0gYWxsX2NvbWJpbmF0aW9ucyAlPiUNCiAgbGVmdF9qb2luKHB1Yl95ZWFyLCBieSA9IGMoInllYXIiLCAic3R1ZHlfbW90aXZhdGlvbiIpKSAlPiUNCiAgbXV0YXRlKG4gPSBpZl9lbHNlKGlzLm5hKG4pLCAwLCBuKSwNCiAgICAgICAgIHllYXIgPSBhcy5udW1lcmljKHllYXIpKQ0KYGBgDQoNCiMjIyMgRmlnIDJhDQoNCkhlcmUncyBhIHN1bW1hcnkgZmlndXJlIGZvciB0aGUgbWFudXNjcmlwdCAoTVMpLiAgICANCg0KYGBge3J9DQojIERlZmluZSB0aGUgY29sb3VyIHBhbGV0dGUNCm1vdGl2YXRpb25fY29sb3VyX3RoZW1lIDwtIGMoIiM2MEJENkMiLCAiI0QzNTlBMSIsICIjM0M4MkM0IikgIyBNYWtpbmcgY29sb3VyIHRoZW1lIHRvIGFwcGx5IHRvIHBsb3QNCg0KIyBDcmVhdGUgdGhlIHBsb3QNCnB1Yl95ZWFyX2ZpZyA8LSBwdWJfeWVhcl9jb21wbGV0ZSAlPiUNCiAgIyBHcm91cCB5ZWFycyBiZWZvcmUgMTk5NiBhbmQgcmVmb3JtYXQgdGhlIHllYXIgY29sdW1uDQogIGRwbHlyOjptdXRhdGUoDQogICAgeWVhciA9IGFzLmNoYXJhY3RlcihpZl9lbHNlKHllYXIgPCAxOTk2LCAxOTk2LCB5ZWFyKSksICMgR3JvdXBpbmcgeWVhcnMgYmVmb3JlIDE5OTYNCiAgICB5ZWFyID0gaWZfZWxzZSh5ZWFyID09ICIxOTk2IiwgIjwxOTk3IiwgeWVhcikgICAgICAgICAgIyBSZW5hbWluZyAxOTk1IGdyb3VwIHRvICI8MTk5NiINCiAgKSAlPiUNCiAgIyBDcmVhdGluZyB0aGUgcGxvdA0KICBnZ3Bsb3QoYWVzKHkgPSBuLCB4ID0geWVhciwgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOSkgKw0KICAjIEFwcGx5IHRoZSBjdXN0b20gY29sb3Vycw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKyANCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIyBDdXN0b21pemluZyB0aGUgdGhlbWUNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjA1LCAxKSwgIyBQb3NpdGlvbmluZyB0aGUgbGVnZW5kIGluIHRoZSB0b3AtbGVmdCBjb3JuZXIgd2l0aGluIHRoZSBwbG90DQogICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAsIDEpLCAjIEVuc3VyaW5nIHRoZSBsZWdlbmQgYm94IGFsaWducyBwcm9wZXJseSBhdCB0aGUgdG9wLWxlZnQgY29ybmVyDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUpICMgUm90YXRpbmcgeC1heGlzIGxhYmVscyBmb3IgYmV0dGVyIHJlYWRhYmlsaXR5DQogICkgKw0KICAjIEFkZGluZyBheGlzIGxhYmVscw0KICBsYWJzKA0KICAgIHggPSAiWWVhciBvZiBwdWJsaWNhdGlvbiIsDQogICAgeSA9ICJOdW1iZXIgb2YgYXJ0aWNsZXMiDQogICkNCg0KIyBEaXNwbGF5IHRoZSBwbG90DQpwdWJfeWVhcl9maWcNCmBgYA0KDQpTYXZpbmcgdGhlIGZpZ3VyZSBhcyBhIFBERi4gSSBoYXZlIGhhc2VkIHRoaXMgc28gSSBkb24ndCByZS13cml0ZSB0aGlzIGZpbGUgZWFjaCB0aW1lLiAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoInB1Yl95ZWFyX2ZpZy5wbmciLCBwbG90ID0gcHViX3llYXJfZmlnLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA1LCBkcGkgPSAzMDApICNpZiB5b3Ugd2FudCB0byBzYXZlIGEgcG5nDQojIGdnc2F2ZSgic3R1ZHlfcHViX3llYXJfZmlnLnBkZiIsIHBsb3QgPSBwdWJfeWVhcl9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMjIEN1bXVsYXRpdmUgYW5kIHJlbGF0aXZlIGdyb3d0aA0KDQpNYWtpbmcgdmFsdWVzIGZvciBjdW11bGF0aXZlIGFuZCByZWxhdGl2ZSBncm93dGggaW4gYXJ0aWNsZXMuIFRoaXMgaXMgdGhlIGN1bXVsYXRpdmUgbnVtYmVyIG9mIGFydGljbGVzIHBlciB5ZWFyIGZvciBlYWNoIHN0dWR5IG1vaXR2YXRpb24sIGFzIHdlbGwgYXMgdGhlIHJlbGF0aXZlIGdyb3d0aCBiYXNlZCBvbiAyMDA3LiBXZSBzZWxlY3RlZCAyMDA3IGZvciBhIDE1IHllYXIgb3ZlcnZpZXcgaW4gZ3Jvd3RoLiAgICANCg0KYGBge3J9DQpwdWJfeWVhcl9ncm93dGggPC0gcHViX3llYXJfY29tcGxldGUgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUNCiAgZHBseXI6Om11dGF0ZSgNCiAgICBuX2N1bXVsYXRpdmUgPSBjdW1zdW0obiksICAjIENhbGN1bGF0ZSB0aGUgY3VtdWxhdGl2ZSBzdW0gb2YgJ24nDQogICAgbl9jdW11bGF0aXZlX3Byb3AgPSBuX2N1bXVsYXRpdmUgLyBtYXgobl9jdW11bGF0aXZlKSwgIyBDYWxjdWxhdGUgdGhlIGN1bXVsYXRpdmUgcHJvcG9ydGlvbg0KICAgIG5fMjAwNyA9IGlmZWxzZSh5ZWFyID09IDIwMDcsIG4sIE5BX3JlYWxfKSwgIyBHZXQgbiB2YWx1ZSBmb3IgeWVhciAyMDA3DQogICAgbl8yMDA3ID0gZmlyc3QobmEub21pdChuXzIwMDcpKSwgIyBQcm9wYWdhdGUgdGhlIG5fMjAxMiB2YWx1ZSB3aXRoaW4gdGhlIGdyb3VwDQogICAgbl9yYXRpb190b18yMDA3ID0gbiAvIG5fMjAwNyAjIENhbGN1bGF0ZSBudW1iZXIgb2YgYXJ0aWNsZXMgcmVsYXRpdmUgdG8gdGhhdCBvZiAyMDA3DQogICkgJT4lDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgeWVhciwgbiwgbl9jdW11bGF0aXZlLCBuX2N1bXVsYXRpdmVfcHJvcCwgbl9yYXRpb190b18yMDA3KQ0KYGBgDQoNCg0KTWFraW5nIGEgcGxvdCBmb3IgZWFjaCBtb3RpdmF0aW9uIGN1bXVsYXRpdmUgZ3Jvd3RoIHNpbmNlIDE5NzQgKHRoZSBmaXJzdCBpZGVudGlmaWVkIHN0dWR5KSAgIA0KDQpgYGB7cn0NCmN1bXVsYXRpdmVfYXJ0aWNsZXNfZmlnIDwtIHB1Yl95ZWFyX2dyb3d0aCAlPiUgDQogIGdncGxvdChhZXMoeSA9IG5fY3VtdWxhdGl2ZSwgeCA9IHllYXIsIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fbGluZShzdGF0ID0gImlkZW50aXR5IiwgbGluZXdpZHRoID0gMS41KSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxOTc0LCAyMDIyLCBieSA9IDEpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIyBDdXN0b21pemluZyB0aGUgdGhlbWUNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjA1LCAxKSwgIyBQb3NpdGlvbmluZyB0aGUgbGVnZW5kIGluIHRoZSB0b3AtbGVmdCBjb3JuZXIgd2l0aGluIHRoZSBwbG90DQogICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAsIDEpLCAjIEVuc3VyaW5nIHRoZSBsZWdlbmQgYm94IGFsaWducyBwcm9wZXJseSBhdCB0aGUgdG9wLWxlZnQgY29ybmVyDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUpICMgUm90YXRpbmcgeC1heGlzIGxhYmVscyBmb3IgYmV0dGVyIHJlYWRhYmlsaXR5DQogICkgKw0KICAjIEFkZGluZyBheGlzIGxhYmVscw0KICBsYWJzKA0KICAgIHggPSAiWWVhciBvZiBwdWJsaWNhdGlvbiIsDQogICAgeSA9ICJBcnRpY2xlcyBjdW11bGF0aXZlIGdyb3d0aCINCiAgKQ0KDQpjdW11bGF0aXZlX2FydGljbGVzX2ZpZw0KYGBgDQoNClNhdmluZyB0aGlzIHBsb3QNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJzdHVkeV9jdW11bGF0aXZlX2FydGljbGVzX2ZpZy5wZGYiLCBwbG90ID0gY3VtdWxhdGl2ZV9hcnRpY2xlc19maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMgUmVsdGl2ZSBncm93dGgNCg0KTGV0J3MgbG9vayBhdCByZWxhdGl2ZSBncm93dGggY29tcGFyZWQgdG8gdGhlIHJlc2VhcmNoIGFyZWEgbW9yZSBicm9hZGx5ICAgDQoNCkkgd2lsbCBpZGVudGlmeSB0aGUgbW9zdCBjb21tb24gcmVzZWFyY2ggYXJlYSBiYXNlZCBvbiBlYWNoIHN0dWR5IG1vdGl2YXRpb24uICAgDQoNCkVudmlyb25tZW50YWwgbW90aXZhdGlvbiA9IEVudmlyb25tZW50YWwgU2NpZW5jZXMgJiBFY29sb2d5ICAgDQpNZWRpY2FsIG1vdGl2YXRpb24gPSBOZXVyb3NjaWVuY2VzICYgTmV1cm9sb2d5ICAgDQpCYXNpYyByZXNlYXJjaCA9IE5ldXJvc2NpZW5jZXMgJiBOZXVyb2xvZ3kgICANCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHdvc19yZXNlYXJjaF9hcmVhcykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbGVuZ3RoKGRvaSkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHdvc19yZXNlYXJjaF9hcmVhcyA9IHN0cl90cmltKHdvc19yZXNlYXJjaF9hcmVhcykpICU+JQ0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyh3b3NfcmVzZWFyY2hfYXJlYXMsIHNlcCA9ICI7IikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHdvc19yZXNlYXJjaF9hcmVhcyA9IHN0cl90cmltKHdvc19yZXNlYXJjaF9hcmVhcykpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHdvc19yZXNlYXJjaF9hcmVhcykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuX3RvdGFsID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2Mobl90b3RhbCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2Uoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToyKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBndCgpDQpgYGANCg0KV2Ugd2lsbCBub3cgY29tcGFyZSB0aGUgcHJvcG9ydGlvbiBjdW11bGF0aXZlIGdyb3d0aCBvZiBlYWNoIHN0dWR5IG1vdGl2YXRpb24gYWdhaW5zdCB0aGUgbW9zdCBjb21tb24gcmVzZWFyY2ggYXJlYXMgYmFzZWQgb24gV29TLiAgIA0KDQpJIGhhdmUgc2VhcmNoZWQgIGFydGljbGVzIHB1Ymxpc2hlZCB3aXRoaW4gdGhlc2UgcmVzZWFyY2ggYXJlYXMgZnJvbSAxOTkyLTIwMjIsIGFuZCBjcmVhdGUgYSBkYXRhYmFzZSB0byBjb21wYXJlIGFnYWluc3QuICAgIA0KDQpFYWNoIHNlYXJjaCBpbmR1ZWQgb25seSBhIGRhdGUgcmFuZ2UgKGUuZy4gUFk9KDE5OTItMjAyMSkpIEFORCB0aGUgZ2l2ZW4gd2ViIG9mIHNjaWVuY2UgcmVzYXJjaCBhcmVhIChlLmcuIFdDPShQaGFybWFjb2xvZ3kgJiBQaGFybWFjeSkpLiBTZWFyY2hlcnMgd2VyZSBkb25lIG9uIHRoZSAwNC8wNy8yMDI0LiBPbmx5IHRoZSB0b3RhbCBudW1iZXIgb2YgYXJ0aWNsZXMgZWFjaCB5ZWFyIHdhcyB0YWtlbi4gICAgDQoNCkZpcnN0IHdlIHdpbGwgaW1wb3J0IHRoZSByZXNlYXJjaCBmaWVsZCBhbm51YWwgbnVtYmVyIG9mIGFydGljbGVzIGRhdGFiYXNlIEkgY3JlYXRlIChtYXJ0aW4tZXQtYWwtYWRkaXRpb25hbC1maWxlLTEwLXdvcy1yZXNlYXJjaC1hcmVhcy0xOTkyLTIwMjIueGxzeCkuIEl0IGlzIHByb3ZpZGUgYXMgc3VwcGxlbWVudGFyeSBmaWxlIDkuICAgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoaW5wdXRfcGF0aCkNCg0Kd29zX3Jlc2VhcmNoX2FyZWFzX24gPC0gcmVhZF9leGNlbCgibWFydGluLWV0LWFsLWFkZGl0aW9uYWwtZmlsZS0xMC13b3MtcmVzZWFyY2gtYXJlYXMtMTk5Mi0yMDIyLnhsc3giLCBzaGVldCA9ICJzaGVldDEiKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKHllYXIpICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkocmVzZWFyY2hfYXJlYSkgJT4lDQogIGRwbHlyOjptdXRhdGUoDQogICAgbl9jdW11bGF0aXZlID0gY3Vtc3VtKG4pLCAgIyBDYWxjdWxhdGUgdGhlIGN1bXVsYXRpdmUgc3VtIG9mICduJw0KICAgIG5fY3VtdWxhdGl2ZV9wcm9wID0gbl9jdW11bGF0aXZlIC8gbWF4KG5fY3VtdWxhdGl2ZSksICMgQ2FsY3VsYXRlIHRoZSBjdW11bGF0aXZlIHByb3BvcnRpb24NCiAgICBuXzIwMDcgPSBpZmVsc2UoeWVhciA9PSAyMDA3LCBuLCBOQV9yZWFsXyksICMgR2V0IG4gdmFsdWUgZm9yIHllYXIgMjAxMQ0KICAgIG5fMjAwNz0gZmlyc3QobmEub21pdChuXzIwMDcpKSwgIyBQcm9wYWdhdGUgdGhlIG5fMjAxMSB2YWx1ZSB3aXRoaW4gdGhlIGdyb3VwDQogICAgbl9yYXRpb190b18yMDA3ID0gbiAvIG5fMjAwNyAjIENhbGN1bGF0ZSBuX3JhdGlvX3RvXzIwMDANCiAgKSAlPiUNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUNCiAgZHBseXI6OnNlbGVjdChyZXNlYXJjaF9hcmVhLCB5ZWFyLCBuLCBuX2N1bXVsYXRpdmUsIG5fY3VtdWxhdGl2ZV9wcm9wLCBuX3JhdGlvX3RvXzIwMDcpDQpgYGANCg0KDQpDb21iaW5lZCB0aGUgbnVtYmVyIG9mIGFydGljbGVzIHdpdGggdGhvc2UgaW4gdGhlIEVJUEFBQiBkYXRhYmFzZQ0KDQpgYGB7cn0NCnB1Yl95ZWFyX2dyb3d0aF9jb21wIDwtIHB1Yl95ZWFyX2dyb3d0aCAlPiUgDQogIGRwbHlyOjpyZW5hbWUocmVzZWFyY2hfYXJlYSA9IHN0dWR5X21vdGl2YXRpb24pDQoNCndvc19yZXNlYXJjaF9hcmVhc19jb21wIDwtIHdvc19yZXNlYXJjaF9hcmVhc19uICU+JSANCiAgcmJpbmQoLiwgcHViX3llYXJfZ3Jvd3RoX2NvbXApICU+JSANCiAgZHBseXI6Om11dGF0ZShyZXNlYXJjaF9hcmVhID0gZmFjdG9yKHJlc2VhcmNoX2FyZWEsIGxldmVscz1jKCJFbnZpcm9ubWVudGFsIiwgIk1lZGljYWwiLCAiQmFzaWMgcmVzZWFyY2giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVudmlyb25tZW50YWwgU2NpZW5jZXMgYW5kIEVjb2xvZ3kiLCAiVG94aWNvbG9neSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTmV1cm9zY2llbmNlcyBhbmQgTmV1cm9sb2d5IiwgIlBoYXJtYWNvbG9neSBhbmQgUGhhcm1hY3kiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFsbCBSZXNlYXJjaCBBcmVhcyIpKSkNCmBgYA0KDQoNCkxldCdzIHNlZSB3aGF0IHRoZSByZWxhdGl2ZSBncm93dGggd2FzIGluIDIwMjIgKHRoZSBsYXRlc3QgaW5jbHVkZWQgeWVhciBpbiB0aGUgZXZpZGVuY2UgYmFzZSkNCg0KYGBge3J9DQp3b3NfcmVzZWFyY2hfYXJlYXNfY29tcCAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoeWVhciA9PSAyMDIyKSAlPiUgDQogIGd0KCkNCmBgYA0KDQoNCiMjIyBFbnZpb3JtZW50YWwgcmVsYXRpdmUgZ3Jvd3RoDQoNCiMjIyMgRmlnIDJiLTEgDQoNCkxldCdzIG5vdyBjb21wYXJlIHRoZSByZWxhdGl2ZSBncm93dGggaW4gRW52aXJvbm1lbnRhbCByZXNlYXJjaCAgICANCg0KYGBge3J9DQojIERlZmluZSB0aGUgY29sb3VyIHBhbGV0dGUNCmVudl9jb2xvdXJfdGhlbWUgPC0gYygiIzYwQkQ2QyIsICIjMkU0QjIyIiwgImJsYWNrIikgIyBNYWtpbmcgY29sb3VyIHRoZW1lIHRvIGFwcGx5IHRvIHBsb3QNCg0KZW52aXJvX2NvbXAgPC0gIGMoIkVudmlyb25tZW50YWwiLCAiRW52aXJvbm1lbnRhbCBTY2llbmNlcyBhbmQgRWNvbG9neSIsICJBbGwgUmVzZWFyY2ggQXJlYXMiKQ0KDQpsaW5lX3R5cGVzIDwtIGMoIkVudmlyb25tZW50YWwiID0gInNvbGlkIiwgDQogICAgICAgICAgICAgICAgIkVudmlyb25tZW50YWwgU2NpZW5jZXMgYW5kIEVjb2xvZ3kiID0gImRhc2hlZCIsIA0KICAgICAgICAgICAgICAgICJBbGwgUmVzZWFyY2ggQXJlYXMiID0gInNvbGlkIikNCg0KcmVsYXRpdmVfZ3Jvd3RoX2Vudl9maWcgPC0gd29zX3Jlc2VhcmNoX2FyZWFzX2NvbXAgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHJlc2VhcmNoX2FyZWEgJWluJSBlbnZpcm9fY29tcCwgeWVhciA+IDIwMDYpICU+JSANCiAgZ2dwbG90KGFlcyh5ID0gbl9yYXRpb190b18yMDA3LCB4ID0geWVhciwgY29sb3VyID0gcmVzZWFyY2hfYXJlYSwgbGluZXR5cGUgPSByZXNlYXJjaF9hcmVhKSkgKw0KICBnZW9tX2xpbmUoc3RhdCA9ICJpZGVudGl0eSIsIGxpbmV3aWR0aCA9IDEuNSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDcsIDIwMjIsIGJ5ID0gMSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMjIpLCBicmVha3MgPSBzZXEoMCwgMjIsIGJ5ID0gNCkpICsgIyBTY2FsZSBZIGF4aXMgZnJvbSAwIHRvIDIyDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gZW52X2NvbG91cl90aGVtZSwgbmFtZSA9ICJSZXNlYXJjaCBBcmVhIikgKw0KICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gbGluZV90eXBlcykgKyAjIEFwcGx5IG1hbnVhbCBsaW5lIHR5cGVzDQogIGd1aWRlcyhsaW5ldHlwZSA9ICJub25lIikgKyAjIFJlbW92ZSBsZWdlbmQgZm9yIGxpbmUgdHlwZXMNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIyBDdXN0b21pemluZyB0aGUgdGhlbWUNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjA1LCAxKSwgIyBQb3NpdGlvbmluZyB0aGUgbGVnZW5kIGluIHRoZSB0b3AtbGVmdCBjb3JuZXIgd2l0aGluIHRoZSBwbG90DQogICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAsIDEpLCAjIEVuc3VyaW5nIHRoZSBsZWdlbmQgYm94IGFsaWducyBwcm9wZXJseSBhdCB0aGUgdG9wLWxlZnQgY29ybmVyDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUpICMgUm90YXRpbmcgeC1heGlzIGxhYmVscyBmb3IgYmV0dGVyIHJlYWRhYmlsaXR5DQogICkgKw0KICAjIEFkZGluZyBheGlzIGxhYmVscw0KICBsYWJzKA0KICAgIHggPSAiWWVhciBvZiBwdWJsaWNhdGlvbiIsDQogICAgeSA9ICJSZWxhdGl2ZSBncm93dGggY29tcGFyZWQgdG8gMjAwNyAoMTUgeWVhciBiYXNlbGluZSkiDQogICkNCg0KcmVsYXRpdmVfZ3Jvd3RoX2Vudl9maWcNCmBgYA0KDQpTYXZlIHRoaXMgZmlndXJlICAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoInN0dWR5X3JlbGF0aXZlX2dyb3d0aF9lbnZfZmlnLnBkZiIsIHBsb3QgPSByZWxhdGl2ZV9ncm93dGhfZW52X2ZpZywgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQ0KYGBgDQoNCg0KIyMjIE1lZGljYWwgcmVsYXRpdmUgZ3Jvd3RoDQoNCiMjIyMgRmlnIDJiLTINCg0KQ29tcGFyaW5nIHRoZSByZWxhdGl2ZSBncm93dGggaW4gbWVkaWNhbCByZXNlYXJjaCAgIA0KDQpgYGB7cn0NCiMgRGVmaW5lIHRoZSBjb2xvdXIgcGFsZXR0ZQ0KbWVkX2NvbG91cl90aGVtZSA8LSBjKCIjRDM1OUExIiwgIiNEMjEzN0YiLCAiYmxhY2siKSAjIE1ha2luZyBjb2xvdXIgdGhlbWUgdG8gYXBwbHkgdG8gcGxvdA0KDQptZWRfY29tcCA8LSAgYygiTWVkaWNhbCIsICJOZXVyb3NjaWVuY2VzIGFuZCBOZXVyb2xvZ3kiLCAiQWxsIFJlc2VhcmNoIEFyZWFzIikNCg0KbGluZV90eXBlcyA8LSBjKCJNZWRpY2FsIiA9ICJzb2xpZCIsIA0KICAgICAgICAgICAgICAgICJOZXVyb3NjaWVuY2VzIGFuZCBOZXVyb2xvZ3kiID0gImRhc2hlZCIsIA0KICAgICAgICAgICAgICAgICJBbGwgUmVzZWFyY2ggQXJlYXMiID0gInNvbGlkIikNCg0KcmVsYXRpdmVfZ3Jvd3RoX21lZF9maWcgPC0gd29zX3Jlc2VhcmNoX2FyZWFzX2NvbXAgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHJlc2VhcmNoX2FyZWEgJWluJSBtZWRfY29tcCwgeWVhciA+IDIwMDYpICU+JSANCiAgZ2dwbG90KGFlcyh5ID0gbl9yYXRpb190b18yMDA3LCB4ID0geWVhciwgY29sb3VyID0gcmVzZWFyY2hfYXJlYSwgbGluZXR5cGUgPSByZXNlYXJjaF9hcmVhKSkgKw0KICBnZW9tX2xpbmUoc3RhdCA9ICJpZGVudGl0eSIsIGxpbmV3aWR0aCA9IDEuNSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDcsIDIwMjIsIGJ5ID0gMSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMjIpLCBicmVha3MgPSBzZXEoMCwgMjIsIGJ5ID0gNCkpICsgIyBTY2FsZSBZIGF4aXMgZnJvbSAwIHRvIDIyDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbWVkX2NvbG91cl90aGVtZSwgbmFtZSA9ICJSZXNlYXJjaCBBcmVhIikgKw0KICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gbGluZV90eXBlcykgKyAjIEFwcGx5IG1hbnVhbCBsaW5lIHR5cGVzDQogIGd1aWRlcyhsaW5ldHlwZSA9ICJub25lIikgKyAjIFJlbW92ZSBsZWdlbmQgZm9yIGxpbmUgdHlwZXMNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIyBDdXN0b21pemluZyB0aGUgdGhlbWUNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjA1LCAxKSwgIyBQb3NpdGlvbmluZyB0aGUgbGVnZW5kIGluIHRoZSB0b3AtbGVmdCBjb3JuZXIgd2l0aGluIHRoZSBwbG90DQogICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAsIDEpLCAjIEVuc3VyaW5nIHRoZSBsZWdlbmQgYm94IGFsaWducyBwcm9wZXJseSBhdCB0aGUgdG9wLWxlZnQgY29ybmVyDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUpICMgUm90YXRpbmcgeC1heGlzIGxhYmVscyBmb3IgYmV0dGVyIHJlYWRhYmlsaXR5DQogICkgKw0KICAjIEFkZGluZyBheGlzIGxhYmVscw0KICBsYWJzKA0KICAgIHggPSAiWWVhciBvZiBwdWJsaWNhdGlvbiIsDQogICAgeSA9ICJSZWxhdGl2ZSBncm93dGggY29tcGFyZWQgdG8gMjAwNyAoMTUgeWVhciBiYXNlbGluZSkiDQogICkNCg0KcmVsYXRpdmVfZ3Jvd3RoX21lZF9maWcNCmBgYA0KDQpTYXZlIHRoaXMgZmlndXJlDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGdnc2F2ZSgic3R1ZHlfcmVsYXRpdmVfZ3Jvd3RoX21lZF9maWcucGRmIiwgcGxvdCA9IHJlbGF0aXZlX2dyb3d0aF9tZWRfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDUpDQpgYGANCg0KDQojIyMgQmFzaWMgcmVzYXJjaCByZWxhdGl2ZSBncm93dGgNCg0KIyMjIyBGaWcgMmItMw0KDQpDb21wYXJpbmcgcmVsYXRpdmUgZ3Jvd3RoIGluIGJhc2ljIHJlc2VhcmNoICAgIA0KDQpgYGB7cn0NCiMgRGVmaW5lIHRoZSBjb2xvdXIgcGFsZXR0ZQ0KYmFzaWNfY29sb3VyX3RoZW1lIDwtIGMoIiMzQzgyQzQiLCAiIzI2Mjc2RCIsICJibGFjayIpICMgTWFraW5nIGNvbG91ciB0aGVtZSB0byBhcHBseSB0byBwbG90DQoNCmJhc2ljX2NvbXAgPC0gIGMoIkJhc2ljIHJlc2VhcmNoIiwgIk5ldXJvc2NpZW5jZXMgYW5kIE5ldXJvbG9neSIsICJBbGwgUmVzZWFyY2ggQXJlYXMiKQ0KDQpsaW5lX3R5cGVzIDwtIGMoIkJhc2ljIHJlc2VhcmNoIiA9ICJzb2xpZCIsIA0KICAgICAgICAgICAgICAgICJOZXVyb3NjaWVuY2VzIGFuZCBOZXVyb2xvZ3kiID0gImRhc2hlZCIsIA0KICAgICAgICAgICAgICAgICJBbGwgUmVzZWFyY2ggQXJlYXMiID0gInNvbGlkIikNCg0KcmVsYXRpdmVfZ3Jvd3RoX2Jhc2VfZmlnIDwtIHdvc19yZXNlYXJjaF9hcmVhc19jb21wICU+JSANCiAgZHBseXI6OmZpbHRlcihyZXNlYXJjaF9hcmVhICVpbiUgYmFzaWNfY29tcCwgeWVhciA+IDIwMDYpICU+JSANCiAgZ2dwbG90KGFlcyh5ID0gbl9yYXRpb190b18yMDA3LCB4ID0geWVhciwgY29sb3VyID0gcmVzZWFyY2hfYXJlYSwgbGluZXR5cGUgPSByZXNlYXJjaF9hcmVhKSkgKw0KICBnZW9tX2xpbmUoc3RhdCA9ICJpZGVudGl0eSIsIGxpbmV3aWR0aCA9IDEuNSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDIwMDcsIDIwMjIsIGJ5ID0gMSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMjIpLCBicmVha3MgPSBzZXEoMCwgMjIsIGJ5ID0gNCkpICsgIyBTY2FsZSBZIGF4aXMgZnJvbSAwIHRvIDIyDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYmFzaWNfY29sb3VyX3RoZW1lLCBuYW1lID0gIlJlc2VhcmNoIEFyZWEiKSArDQogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBsaW5lX3R5cGVzKSArICMgQXBwbHkgbWFudWFsIGxpbmUgdHlwZXMNCiAgZ3VpZGVzKGxpbmV0eXBlID0gIm5vbmUiKSArICMgUmVtb3ZlIGxlZ2VuZCBmb3IgbGluZSB0eXBlcw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICAjIEN1c3RvbWl6aW5nIHRoZSB0aGVtZQ0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuMDUsIDEpLCAjIFBvc2l0aW9uaW5nIHRoZSBsZWdlbmQgaW4gdGhlIHRvcC1sZWZ0IGNvcm5lciB3aXRoaW4gdGhlIHBsb3QNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMCwgMSksICMgRW5zdXJpbmcgdGhlIGxlZ2VuZCBib3ggYWxpZ25zIHByb3Blcmx5IGF0IHRoZSB0b3AtbGVmdCBjb3JuZXINCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSkgIyBSb3RhdGluZyB4LWF4aXMgbGFiZWxzIGZvciBiZXR0ZXIgcmVhZGFiaWxpdHkNCiAgKSArDQogICMgQWRkaW5nIGF4aXMgbGFiZWxzDQogIGxhYnMoDQogICAgeCA9ICJZZWFyIG9mIHB1YmxpY2F0aW9uIiwNCiAgICB5ID0gIlJlbGF0aXZlIGdyb3d0aCBjb21wYXJlZCB0byAyMDA3ICgxNSB5ZWFyIGJhc2VsaW5lKSINCiAgKQ0KDQpyZWxhdGl2ZV9ncm93dGhfYmFzZV9maWcNCmBgYA0KDQpTYXZlIHRoaXMgZmlndXJlICAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoInN0dWR5X3JlbGF0aXZlX2dyb3d0aF9iYXNlX2ZpZy5wZGYiLCBwbG90ID0gcmVsYXRpdmVfZ3Jvd3RoX2Jhc2VfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMgUG9wdWxhdGlvbiwgRXhwb3N1cmUgYW5kIE91dGNvbWUNCg0KTG9va2luZyBhdCB0aGUgbGluayBiZXR3ZWVuIHRoZSBQRU8gZWxlbWVudHMuIFdoYXQgd2FzIHRoZSBhdmVyYWdlIHN0dWR5IGRlc2lnbi4NCg0KQmVsb3cgSSBoYXZlIG1hZGUgYSB0YWJsZSB0aGF0IGdyb3VwcyBieSB0aGVzZSBlbGVtZW50cyB0byBzZWUgdGhlIGF2ZXJhZ2Ugc3R1ZHkgZGVzaWduDQoNCkl0IHdhcyAxIGNvbXBvdW5kLCAxIHNwZWNpZXMgYW5kIDEgYmVoYXZpb3VyYWwgY2xhc3MgKDQxJSkNCg0KYGBge3J9DQpiZWhhdl9ib29sZWFuIDwtIGMoImJlaGF2X21vdmVtZW50X2Jvb2xlYW4iLCAiYmVoYXZfYm9sZG5lc3NfYm9vbGVhbiIsICJiZWhhdl9mb3JhZ2luZ19ib29sZWFuIiwgImJlaGF2X2FudGlwcmVkYXRvcl9ib29sZWFuIiwgImJlaGF2X21hdGluZ19ib29sZWFuIiwgImJlaGF2X3Bvc3RfbWF0aW5nX2Jvb2xlYW4iLCAiYmVoYXZfYWdyZXNzaW9uX2Jvb2xlYW4iLCAiYmVoYXZfc29jaWFsaXR5X2Jvb2xlYW4iLCAiYmVoYXZfY29nbml0aW9uX2Jvb2xlYW4iLCAiYmVoYXZfbm9uY2F0X2Jvb2xlYW4iKQ0KDQpFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjptdXRhdGUoYmVoYXZfbiA9IHJvd1N1bXMoYWNyb3NzKGFsbF9vZihiZWhhdl9ib29sZWFuKSksIG5hLnJtID0gVFJVRSkpICU+JSAjIGhvdyBtYW55IGJlaGF2IGNsYXNzIG1lYXN1cmVkDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MoYmVoYXZfbikpICU+JSANCiAgZHBseXI6OnNsaWNlKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoY29tcG91bmRfbiwgc3BlY2llc19uLCBiZWhhdl9uKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9uLCBzcGVjaWVzX24sIGJlaGF2X24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobj0gbGVuZ3RoKGNvbXBvdW5kX24pLA0KICAgICAgICAgICAgICAgICAnJScgPSByb3VuZChuLzkwMioxMDAsMSkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToxMCkgJT4lICMgT25seSB0aGUgMTAgbW9zdCBjb21tb24gY29tYmluYXRpb25zDQogIGd0KCkNCmBgYA0KDQpJIHN1bW1hcnkgZGYgdGhhdCBoYXMgdGhlIG51bWJlciBvZiBQRU8gZWxlbWVudHMgaW4gZWFjaCBvZiB0aGUgOTAxIHN0dWRpZXMgDQoNCmBgYHtyfQ0KUEVPX2VsZW1lbnRfc3VtbWFyeSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjptdXRhdGUoYmVoYXZfbiA9IHJvd1N1bXMoYWNyb3NzKGFsbF9vZihiZWhhdl9ib29sZWFuKSksIG5hLnJtID0gVFJVRSkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhiZWhhdl9uKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6OnNlbGVjdChjb21wb3VuZF9uLCBzcGVjaWVzX24sIGJlaGF2X24pDQpgYGANCg0KTG9va2luZyBhdCB0aGUgbnVtYmVyIG9mIHNwZWNpZXMgdXNlZCAgICANCg0KYGBge3J9DQpQRU9fZWxlbWVudF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbGVuZ3RoKHNwZWNpZXNfbiksDQogICAgICAgICAgICAgICAgICclJyA9IG4vOTAxKSAlPiUgDQogIGd0KCkNCmBgYA0KDQpMb29raW5nIGF0IHRoZSBudW1iZXIgb2YgY29tcG91bmRzIHVzZWQgICAgDQoNCmBgYHtyfQ0KUEVPX2VsZW1lbnRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBsZW5ndGgoY29tcG91bmRfbiksDQogICAgICAgICAgICAgICAgICclJyA9IG4vOTAxKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjEwKSAlPiUgDQogIGd0KCkNCmBgYA0KDQpUaGUgbnVtYmVyIG9mIGRpZmZlcmVudCBiZWhhdmlvdXJzICAgDQoNCmBgYHtyfQ0KUEVPX2VsZW1lbnRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBsZW5ndGgoc3BlY2llc19uKSwNCiAgICAgICAgICAgICAgICAgJyUnID0gbi85MDEpICU+JSANCiAgZ3QoKQ0KYGBgDQoNCiMjIFNwZWNpZXMNCg0KTGV0J3MgdGFrZSBhIGNsb3NlciBsb29rIGF0IHNwZWNpZXMgaW5mb3JtYXRpb24gDQoNCiMjIyBOdW1iZXIgb2YgZGlzdGljdCBzcGVjaWVzDQoNClRoZXJlIGFyZSAxNzMgc3BlY2llcyBpbiB0aGUgRUlQQUFCIGRhdGFiYXNlICANCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3Qoc3BlY2llc19uYW1lKSAlPiUgDQogIG5yb3coKQ0KYGBgDQoNClRoZSBudW1iZXIgb2Ygc3BwIGVhY2ggc3R1ZHkgbW90aXZhdGlvbiAgICANCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuX3NwcCA9IGxlbmd0aCh1bmlxdWUoc3BlY2llc19uYW1lKSksDQogICAgICAgICAgICAgICAgIHRvdGFsX3N0dWR5ID0gbGVuZ3RoKHVuaXF1ZShhcnRpY2xlX2lkKSksDQogICAgICAgICAgICAgICAgIHJlbF9uID0gbl9zcHAvdG90YWxfc3R1ZHkpICU+JSANCiAgZ3QoKQ0KYGBgDQoNClRoZXJlIGFyZSAyMSBjbGFzcyAgIA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChzcGVjaWVzX2NsYXNzKSAlPiUgDQogIG5yb3coKQ0KYGBgDQoNClRoZXJlIGFyZSA5MzUgZGlmZmVyZW50IGdyb3VwcyBvZiBhbmltYWxzIHVzZWQgYWNyb3NzIGFsbCA5MDEgc3R1ZGllcyAoaS5lLiBzb21lIHN0dWRpZXMgaGFkIG1vcmUgdGhlbiBvbmUgc3BlY2llcykgICAgDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmRpc3RpbmN0KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIG5yb3coLikNCmBgYA0KDQoNCiMjIyBNYWpvciB0YXhhIGdyb3Vwcw0KDQojIyMjIENsYWRvZ3JhbSAoVGF4b25vbWljIHRyZWUpDQoNCkxldCdzIG1ha2UgYSBDbGFkb2dyYW0gdG8gZ2V0IGFuIG92ZXJ2aWV3IG9mIHdoYXQgdGF4YSBhcmUgaW4gdGhlIGRhdGFiYXNlICAgIA0KDQpgYGB7cn0NCnNwcF90YXhvbm9teSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX25hbWUpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKHNwZWNpZXNfZmFtaWx5KSwgIXN0cl9kZXRlY3Qoc3BlY2llc19zcGVjaWVzLCAic3BwLiIpLCBzcGVjaWVzX2tpbmdkb20gIT0gIkNocm9taXN0YSIpICU+JSANCiAgZHBseXI6OnNlbGVjdCgic3BlY2llc19raW5nZG9tIiwgInNwZWNpZXNfcGh5bHVtIiwgInNwZWNpZXNfY2xhc3MiLCAic3BlY2llc19vcmRlciIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgInNwZWNpZXNfZmFtaWx5IiwgInNwZWNpZXNfZ2VudXMiLCAic3BlY2llc19zcGVjaWVzIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc3BlY2llcyA9IHBhc3RlMChzdWJzdHIoc3BlY2llc19nZW51cywgMSwgMSksICIuICIsIHN1YigiXlteIF0rICIsICIiLCBzcGVjaWVzX3NwZWNpZXMpKSkNCiMgVGhlIG11dGF0ZSBjaGFuZ2VzIHRoZSBzcHAgbmFtZSB0byBhYmJyZXZpYXRlIHRoZSBHZW51cyAoZS5nLiBBZXNobmEgY3lhbmVhIHRvIEEuIGN5YW5lYSkNCmBgYA0KDQpDcmVhdGUgYSBoaWVyYXJjaGljYWwgc3RydWN0dXJlIGZvciB0aGUgcGxvdCAgICANCg0KYGBge3J9DQp0YXhvbm9teSA8LSBzcHBfdGF4b25vbXlbLCBjKCJzcGVjaWVzX2tpbmdkb20iLCAic3BlY2llc19waHlsdW0iLCAic3BlY2llc19jbGFzcyIsICJzcGVjaWVzX29yZGVyIiwgInNwZWNpZXNfZmFtaWx5IiwgInNwZWNpZXNfZ2VudXMiLCAic3BlY2llc19zcGVjaWVzIildDQoNCnRheG9ub215W10gPC0gbGFwcGx5KHRheG9ub215LCBmYWN0b3IpDQoNCiMgQ3JlYXRlIGEgcGh5bG9nZW5ldGljIHRyZWUNCnBoeWxvX3RyZWUgPC0gYXMucGh5bG8uZm9ybXVsYSh+c3BlY2llc19raW5nZG9tL3NwZWNpZXNfcGh5bHVtL3NwZWNpZXNfY2xhc3Mvc3BlY2llc19vcmRlci9zcGVjaWVzX2ZhbWlseS9zcGVjaWVzX2dlbnVzL3NwZWNpZXNfc3BlY2llcywgZGF0YSA9IHRheG9ub215KQ0KYGBgDQoNCk1hbnVhbCBjcmVhdGluZyBhIHBoeWxvX3RyZWUgKHdpdGggZXF1YWwgYnJhbmNoZXMpICAgDQoNCmBgYHtyfQ0KZ2d0cmVlX29iaiA8LSBnZ3RyZWUocGh5bG9fdHJlZSwgYnJhbmNoLmxlbmd0aD0nbm9uZScsIGxheW91dD0nY2lyY3VsYXInKQ0KDQojIEV4dHJhY3QgdGhlIHBoeWx1bSBpbmZvcm1hdGlvbiBmb3IgY29sb3JpbmcNCiN0YXhvbm9teSRsYWJlbCA8LSBwYXN0ZTAoc3Vic3RyKHNwcF90YXhvbm9teSRzcGVjaWVzX2dlbnVzLCAxLCAxKSwgIi4gIiwgc3BwX3RheG9ub215JHNwZWNpZXNfc3BlY2llcykNCmNsYXNzX2luZm8gPC0gdGF4b25vbXkkc3BlY2llc19jbGFzc1ttYXRjaChwaHlsb190cmVlJHRpcC5sYWJlbCwgdGF4b25vbXkkc3BlY2llc19zcGVjaWVzKV0NCg0KIyBBZGQgdGhlIHBoeWx1bSBpbmZvcm1hdGlvbiB0byB0aGUgZ2d0cmVlIG9iamVjdA0KZ2d0cmVlX29iaiA8LSBnZ3RyZWVfb2JqICU8KyUgZGF0YS5mcmFtZShsYWJlbCA9IHBoeWxvX3RyZWUkdGlwLmxhYmVsLCBjbGFzcyA9IGNsYXNzX2luZm8pDQoNCiMgQ3JlYXRlIGEgY29sb3IgdmVjdG9yIGZvciB0aGUgcGh5bHVtIGxldmVscw0KY2xhc3NfY29sb3JzIDwtIHJhaW5ib3cobGVuZ3RoKHVuaXF1ZShjbGFzc19pbmZvKSkpDQpuYW1lcyhjbGFzc19jb2xvcnMpIDwtIHVuaXF1ZShjbGFzc19pbmZvKQ0KDQojIFBsb3QgdGhlIGNsYWRvZ3JhbSB3aXRoIGNvbG9yZWQgYnJhbmNoZXMNCnNwcF9jbGFkb2dyYW0gPC0gZ2d0cmVlX29iaiArDQogIGdlb21fdGlwbGFiKHNpemU9MykgKyAjSWYgeW91IHdhbnQgdG8gYWRkIHNwZWNpZXMgbmFtZXMNCiAgZ2VvbV90cmVlKGFlcyhjb2xvcj1jbGFzcykpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNsYXNzX2NvbG9ycykgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQ0KYGBgDQoNCg0KIyMjIyBGaWcgM2EgDQoNCmBgYHtyfQ0Kc3BwX2NsYWRvZ3JhbQ0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoInNwcF9jbGFkb2dyYW0ucGRmIiwgcGxvdCA9IHNwcF9jbGFkb2dyYW0sIHdpZHRoID0gOCwgaGVpZ2h0ID0gNSkNCmBgYA0KDQoNCiMjIyMgQ2xhc3MgbGV2ZWwNCg0KTGV0J3MgZ3JvdXAgYnkgY2xhc3MgdG8gc2VlIHRoZSBtYWpvciB0YXhvbm9taWMgQ2xhc3NlcyB1c2VkICAgDQoNCkZpcnN0IHJlbW92aW5nIGNhc2VzIHdoZXJlIHNwZWNpZXNfc3BlY2llcyB3YXMgInNwcC4iIHJlcGxhY2luZyB3aXRoIE5BIGZvciB0YXhvbm9taWMgY2xhc3NpZmljYXRpb24gICANCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX3NwZWNpZXMgPSBpZl9lbHNlKHNwZWNpZXNfc3BlY2llcyA9PSAic3BwLiIsIE5BLCBzcGVjaWVzX3NwZWNpZXMpKQ0KYGBgDQoNCkxldCdzIGxvb2sgYXQgdGhlIG1ham9yIENsYXNzICANCg0KYGBge3J9DQojIFRvdGFsIG51bWJlciBvZiBzcHANCm5fc3BwIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChzcGVjaWVzX25hbWUpICU+JSANCiAgbnJvdygpIA0KDQojIE51bWJlciBvZiBzcHAgcGVyIENsYXNzIGFuZCBwZXIgcGh5bHVtIA0Kc3BwX2NsYXNzZXMgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfY2xhc3MsIHNwZWNpZXNfcGh5bHVtKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKGNvdW50X2NsYXNzID0gbGVuZ3RoKHVuaXF1ZShzcGVjaWVzX25hbWUpKSwNCiAgICAgICAgICAgICAgICAgcGVyY2VudF9jbGFzcyA9IHJvdW5kKGNvdW50X2NsYXNzL25fc3BwKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19waHlsdW0pICU+JSANCiAgZHBseXI6Om11dGF0ZShjb3VudF9waHlsdW0gPSBzdW0oY291bnRfY2xhc3MpLA0KICAgICAgICAgICAgICAgIHBlcmNlbnRfcGh5bHVtID0gcm91bmQoY291bnRfcGh5bHVtL25fc3BwKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhwZXJjZW50X2NsYXNzKSkNCiAgDQoNCnNwcF9jbGFzc2VzICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTApICU+JSANCiAgZ3QoKQ0KYGBgDQoNCk1ha2luZyBhIGZpZ3VyZSBmb3IgdGhlIDE1IG1vc3QgYWJ1bmRhbnQgQ2xhc3MsIGl0IHRlcm1zIG9mIHNwZWNpZXMgZGl2ZXJzaXR5IGluIHRoZSBFSVBBQUIgZGF0YWJhc2UgICANCg0KYGBge3J9DQpjbGFzc19uX3NwcF9maWcgPC0gc3BwX2NsYXNzZXMgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKHBlcmNlbnRfY2xhc3MpKSAlPiUgIyBhcnJhbmdlIHRoZSBkYXRhc2V0DQogIGRwbHlyOjpzbGljZSgxOjE1KSAlPiUgIyBUYWtlIG9ubHkgdGhlIG1vc3QgZGl2ZXJzZSAxNSBDbGFzcw0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfY2xhc3MgPSBmY3RfcmVvcmRlcihzcGVjaWVzX2NsYXNzLCBwZXJjZW50X2NsYXNzKSwgIyBPcmRlciBieSBkaXZlcnNpdHkNCiAgICAgICAgICAgICAgICBzcGVjaWVzX3BoeWx1bSA9IGZjdF9yZW9yZGVyKHNwZWNpZXNfcGh5bHVtLCBkZXNjKHBlcmNlbnRfcGh5bHVtKSkpICU+JSAjIE9yZGVyIGJ5IGRpdmVyc2l0eQ0KICBnZ3Bsb3QoYWVzKHg9c3BlY2llc19jbGFzcywgeT1jb3VudF9jbGFzcywgY29sb3IgPSBzcGVjaWVzX3BoeWx1bSkpICsNCiAgZ2VvbV9zZWdtZW50KGFlcyh4PXNwZWNpZXNfY2xhc3MsIHhlbmQ9c3BlY2llc19jbGFzcywgeT0wLCB5ZW5kPWNvdW50X2NsYXNzKSkgKw0KICBnZW9tX3BvaW50KHNpemU9NCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY291bnRfY2xhc3MpLCANCiAgICAgICAgICAgIGhqdXN0PS0xLjIsIA0KICAgICAgICAgICAgc2l6ZT0zLjUsIA0KICAgICAgICAgICAgY29sb3I9ImJsYWNrIikgKw0KICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGU9ICJEYXJrMiIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgeWxpbSgwLCA3NSkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJOdW1iZXIgb2YgZGlzdGljdCBzcGVjaWVzIGluIHRoZSBkYXRhYmFzZSINCiAgKSArDQogICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuLCAwLjA1KSwgICMgUG9zaXRpb25pbmcgdGhlIGxlZ2VuZCBpbnNpZGUgdGhlIHBsb3QNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoLTMsIDApLCAgICMgQm90dG9tIGxlZnQgaW5zaWRlIHRoZSBwbG90DQogICAgbGVnZW5kLmJveC5qdXN0ID0gInJpZ2h0IiwNCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPWFscGhhKCd3aGl0ZScsIDAuNSkpDQogICApDQoNCmNsYXNzX25fc3BwX2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZQ0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoInNwcF9jbGFzc19uX3NwcF9maWcucGRmIiwgcGxvdCA9IGNsYXNzX25fc3BwX2ZpZywgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQ0KYGBgDQoNCiMjIyMgUGh5bHVtIGxldmVsDQoNCkhlcmUncyBhIGxvb2sgYXQgdGhlICUgYXQgdGhlIHBoeWx1bSBsZXZlbCAgIA0KDQpgYGB7cn0NCiMgSW4gdGhlIGNsYXNzIHN1bW1hcnkgd2UgYWxzbyBpbmNsdWRlZCBwZXJjZW50X3BoeWx1bQ0Kc3BwX2NsYXNzZXMgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19waHlsdW0pICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXNwZWNpZXNfY2xhc3MsIC1jb3VudF9jbGFzcywgLXBlcmNlbnRfY2xhc3MpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhwZXJjZW50X3BoeWx1bSkpICU+JSANCiAgZ3QoKQ0KYGBgDQoNCkEgcmluZyBjaGFydCBhdCB0aGUgcGh5bHVtIGxldmVsDQoNCmBgYHtyfQ0KcmluZ19wbG90X2RmIDwtIHNwcF9jbGFzc2VzICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTUpICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19waHlsdW0pICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3BlY2llc19waHlsdW0sIGNvdW50X3BoeWx1bSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfcGh5bHVtID0gY291bnRfcGh5bHVtL3N1bShjb3VudF9waHlsdW0pKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MocGVyY2VudF9waHlsdW0pKQ0KDQojIENvbXB1dGUgdGhlIGN1bXVsYXRpdmUgcGVyY2VudGFnZXMgKHRvcCBvZiBlYWNoIHJlY3RhbmdsZSkNCnJpbmdfcGxvdF9kZiR5bWF4ID0gY3Vtc3VtKHJpbmdfcGxvdF9kZiRwZXJjZW50X3BoeWx1bSkNCg0KIyBDb21wdXRlIHRoZSBib3R0b20gb2YgZWFjaCByZWN0YW5nbGUNCnJpbmdfcGxvdF9kZiR5bWluID0gYygwLCBoZWFkKHJpbmdfcGxvdF9kZiR5bWF4LCBuPS0xKSkNCg0KIyBDb21wdXRlIGxhYmVsIHBvc2l0aW9uDQpyaW5nX3Bsb3RfZGYkbGFiZWxQb3NpdGlvbiA8LSAocmluZ19wbG90X2RmJHltYXggKyByaW5nX3Bsb3RfZGYkeW1pbikgLyAyDQoNCiMgQ29tcHV0ZSBhIGdvb2QgbGFiZWwNCnJpbmdfcGxvdF9kZiRsYWJlbCA8LSBwYXN0ZTAocmluZ19wbG90X2RmJHNwZWNpZXNfcGh5bHVtLCAiXG4gKG4gPSAiLCByaW5nX3Bsb3RfZGYkY291bnRfcGh5bHVtLCAiKSIpDQoNCg0KcGh5bHVtX3JpbmdfZmlnIDwtIHJpbmdfcGxvdF9kZiAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19waHlsdW0gPSBmY3RfcmVvcmRlcihzcGVjaWVzX3BoeWx1bSwgZGVzYyhwZXJjZW50X3BoeWx1bSkpKSAlPiUgDQogIGdncGxvdChhZXMoeW1heD15bWF4LCB5bWluPXltaW4sIHhtYXg9NCwgeG1pbj0zLCBmaWxsPXNwZWNpZXNfcGh5bHVtKSkgKw0KICBnZW9tX3JlY3QoKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhPSJ5IikgKyANCiAgZ2VvbV9sYWJlbCh4PTUsIGFlcyh5PWxhYmVsUG9zaXRpb24sIGxhYmVsPWxhYmVsKSwgc2l6ZT0zLCBhbHBoYSA9IDAuOCkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSAiRGFyazIiKSArDQogIHhsaW0oYygyLCA1KSkgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCnBoeWx1bV9yaW5nX2ZpZw0KYGBgDQoNClNhdmUgdGhpcyBwbG90ICAgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGdnc2F2ZSgic3BwX3BoeWx1bV9yaW5nX2ZpZy5wZGYiLCBwbG90ID0gcGh5bHVtX3JpbmdfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDUpDQpgYGANCg0KDQojIyMgVGF4YSByZXByZXNlbnRhdGlvbg0KDQpOb3cgd2Ugd2lsbCBsb29rIGF0IGhvdyBtYW55IHRpbWVzIGVhY2ggcGh5bHVtLCBjbGFzcywgb3JkZXIsIGZhbWlseSwgZ2VudXMsIHNwZWNpZXMgYXBwZWFyIGluIHRoZSBkYXRhYmFzZSAgICANCg0KRmlyc3Qgd2Ugd2lsbCBtYWtlIGEgZGF0YXNldCB0aGF0IGNvdW50cyB0aGUgbnVtYmVyIG9mIHNwZWNpZXMgd2l0aGluIGVhY2ggcGh5bHVtLCBjbGFzcywgb3JkZXIsIGZhbWlseSwgYW5kIGdlbnVzLiAgIA0KDQpgYGB7cn0NCiMgU3RlcCAxOiBTZXBhcmF0ZSBhbmQgcGl2b3QgdGhlIGRhdGENCmxpbmVhZ2VfZGF0YSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gYygic3BlY2llc19waHlsdW0iLCAic3BlY2llc19jbGFzcyIsICJzcGVjaWVzX29yZGVyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAic3BlY2llc19mYW1pbHkiLCAic3BlY2llc19nZW51cyIsICJzcGVjaWVzX3NwZWNpZXMiKSwgDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJsaW5lYWdlX2xldmVsIiwgdmFsdWVzX3RvID0gImNsYXNzaWZpY2F0aW9uIikgJT4lDQogIGRwbHlyOjptdXRhdGUobGluZWFnZV9sZXZlbCA9IHN0cl9yZW1vdmUobGluZWFnZV9sZXZlbCwgInNwZWNpZXNfIikpDQoNCg0KIyBEZWZpbmUgdGhlIG9yZGVyDQpsaW5lYWdlX2xldmVsc19vcmRlciA8LSBjKCJwaHlsdW0iLCAiY2xhc3MiLCAib3JkZXIiLCAiZmFtaWx5IiwgImdlbnVzIiwgInNwZWNpZXMiKQ0KDQojIFN0ZXAgMjogQ3JlYXRlIHBhcmVudC1jaGlsZCByZWxhdGlvbnNoaXBzDQpsaW5lYWdlX2RhdGEgPC0gbGluZWFnZV9kYXRhICU+JQ0KICBncm91cF9ieSh1bmlxdWVfcm93X2lkKSAlPiUNCiAgbXV0YXRlKHBhcmVudCA9IGNhc2Vfd2hlbigNCiAgICBsaW5lYWdlX2xldmVsID09ICJwaHlsdW0iIH4gIkFuaW1hbGlhIiwNCiAgICBsaW5lYWdlX2xldmVsID09ICJjbGFzcyIgfiBsYWcoY2xhc3NpZmljYXRpb24sIDEpLA0KICAgIGxpbmVhZ2VfbGV2ZWwgPT0gIm9yZGVyIiB+IGxhZyhjbGFzc2lmaWNhdGlvbiwgMSksDQogICAgbGluZWFnZV9sZXZlbCA9PSAiZmFtaWx5IiB+IGxhZyhjbGFzc2lmaWNhdGlvbiwgMSksDQogICAgbGluZWFnZV9sZXZlbCA9PSAiZ2VudXMiIH4gbGFnKGNsYXNzaWZpY2F0aW9uLCAxKSwNCiAgICBsaW5lYWdlX2xldmVsID09ICJzcGVjaWVzIiB+IGxhZyhjbGFzc2lmaWNhdGlvbiwgMSksDQogICkpICU+JQ0KICB1bmdyb3VwKCkNCmBgYA0KDQpIZXJlIHdlIHN1bSB0aGUgdG90YWwgbnVtYmVyIG9mIHNwZWNpZXMgdXNlZCBpbiB0aGUgZGF0YWJhc2UgYWNyb3NzIGVhY2ggdGF4b25vbWljIGNsYXNzaWZpY2F0aW9uICAgDQogICAgICAgICAgICAgICAgDQpgYGB7cn0NCm5fcm93cyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIG5yb3coKQ0KDQpsaW5lYWdlX2NvdW50X3VzZSA8LSBsaW5lYWdlX2RhdGEgJT4lDQogIGRwbHlyOjpncm91cF9ieShjbGFzc2lmaWNhdGlvbiwgbGluZWFnZV9sZXZlbCwgcGFyZW50KSAlPiUNCiAgZHBseXI6OnJlZnJhbWUoY2xhc3NpZmljYXRpb25fY291bnQgPSBsZW5ndGgodW5pcXVlX3Jvd19pZCksDQogICAgICAgICAgICAgICAgY2xhc3NpZmljYXRpb25fcGVyY2VudCA9IHJvdW5kKGNsYXNzaWZpY2F0aW9uX2NvdW50L25fcm93cyoxMDAsMSkpDQpgYGANCg0KDQojIyMjIEZpZyAzYg0KDQpNYWtpbmcgYSBwbG90IHRvIGxvb2sgYXQgdGhlIDE1IG1vc3QgY29tbW9ubHkgdXNlZCBjbGFzcywgYnV0IHlvdSBjYW4gZG8gdGhpcyBhdCBhbnkgb2YgdGhlIHRheG9ub21pYyBsZXZlbHMgICANCg0KYGBge3J9DQpjbGFzc191c2VfZmlnIDwtIGxpbmVhZ2VfY291bnRfdXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihsaW5lYWdlX2xldmVsID09ICJjbGFzcyIpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhjbGFzc2lmaWNhdGlvbl9wZXJjZW50KSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToxNSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNsYXNzaWZpY2F0aW9uID0gZmN0X3Jlb3JkZXIoY2xhc3NpZmljYXRpb24sIGNsYXNzaWZpY2F0aW9uX3BlcmNlbnQpLA0KICAgICAgICAgICAgICAgIHBhcmVudCA9IGZjdF9yZW9yZGVyKHBhcmVudCwgZGVzYyhjbGFzc2lmaWNhdGlvbl9wZXJjZW50KSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9Y2xhc3NpZmljYXRpb24sIHk9Y2xhc3NpZmljYXRpb25fcGVyY2VudCwgY29sb3IgPSBwYXJlbnQpKSArDQogIGdlb21fc2VnbWVudChhZXMoeD1jbGFzc2lmaWNhdGlvbiwgeGVuZD1jbGFzc2lmaWNhdGlvbiwgeT0wLCB5ZW5kPWNsYXNzaWZpY2F0aW9uX3BlcmNlbnQpKSArDQogIGdlb21fcG9pbnQoc2l6ZT00KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQoY2xhc3NpZmljYXRpb25fcGVyY2VudCwyKSwgIiUiKSksIA0KICAgICAgICAgICAgaGp1c3Q9LTAuNSwgDQogICAgICAgICAgICBzaXplPTMuNSwgDQogICAgICAgICAgICBjb2xvcj0iYmxhY2siKSArDQogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZT0gIkRhcmsyIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB5bGltKDAsIDEwMCkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQZXJjZW50YWdlIHJlcHJlc2VudGF0aW9uIGluIHRoZSBkYXRhYmFzZSINCiAgKSArDQogICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuLCAwLjA1KSwgICMgUG9zaXRpb25pbmcgdGhlIGxlZ2VuZCBpbnNpZGUgdGhlIHBsb3QNCiAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoLTMsIDApLCAgICMgQm90dG9tIGxlZnQgaW5zaWRlIHRoZSBwbG90DQogICAgbGVnZW5kLmJveC5qdXN0ID0gInJpZ2h0IiwNCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPWFscGhhKCd3aGl0ZScsIDAuNSkpDQogICApDQoNCmNsYXNzX3VzZV9maWcNCmBgYA0KDQpTYXZlIHBsb3QNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJzcHBfY2xhc3NfdXNlX2ZpZy5wZGYiLCBwbG90ID0gY2xhc3NfdXNlX2ZpZywgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQ0KYGBgDQoNClRhYmxlIG9mIG9jY3VycmVuY2UsIGFuZCBwZXJjZW50YWdlIG9jY3VycmVuY2UgICANCg0KYGBge3J9DQpsaW5lYWdlX2NvdW50X3VzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIobGluZWFnZV9sZXZlbCA9PSAiY2xhc3MiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjbGFzc2lmaWNhdGlvbikgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhjbGFzc2lmaWNhdGlvbl9wZXJjZW50KSkgJT4lIA0KICBndCgpDQpgYGANCg0KSGVyZSdzIGJyZWFrIGRvd24gYnkgUGh5bHVtICAgIA0KDQpgYGB7cn0NCnJpbmdfdXNlX3Bsb3RfZGYgPC0gbGluZWFnZV9jb3VudF91c2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGxpbmVhZ2VfbGV2ZWwgPT0gInBoeWx1bSIpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhjbGFzc2lmaWNhdGlvbl9wZXJjZW50KSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNsYXNzaWZpY2F0aW9uX3BlcmNlbnQgPSByb3VuZChjbGFzc2lmaWNhdGlvbl9wZXJjZW50LCAyKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMTo4KQ0KDQojIENvbXB1dGUgdGhlIGN1bXVsYXRpdmUgcGVyY2VudGFnZXMgKHRvcCBvZiBlYWNoIHJlY3RhbmdsZSkNCnJpbmdfdXNlX3Bsb3RfZGYkeW1heCA9IGN1bXN1bShyaW5nX3VzZV9wbG90X2RmJGNsYXNzaWZpY2F0aW9uX3BlcmNlbnQpDQoNCiMgQ29tcHV0ZSB0aGUgYm90dG9tIG9mIGVhY2ggcmVjdGFuZ2xlDQpyaW5nX3VzZV9wbG90X2RmJHltaW4gPSBjKDAsIGhlYWQocmluZ191c2VfcGxvdF9kZiR5bWF4LCBuPS0xKSkNCg0KIyBDb21wdXRlIGxhYmVsIHBvc2l0aW9uDQpyaW5nX3VzZV9wbG90X2RmJGxhYmVsUG9zaXRpb24gPC0gKHJpbmdfdXNlX3Bsb3RfZGYkeW1heCArIHJpbmdfdXNlX3Bsb3RfZGYkeW1pbikgLyAyDQoNCiMgQ29tcHV0ZSBhIGdvb2QgbGFiZWwNCnJpbmdfdXNlX3Bsb3RfZGYkbGFiZWwgPC0gcGFzdGUwKHJpbmdfdXNlX3Bsb3RfZGYkY2xhc3NpZmljYXRpb24sICJcbiAoIiwgcmluZ191c2VfcGxvdF9kZiRjbGFzc2lmaWNhdGlvbl9wZXJjZW50LCAiJSkiKQ0KDQoNCnBoeWx1bV91c2VfcmluZ19maWcgPC0gcmluZ191c2VfcGxvdF9kZiAlPiUgDQogIGRwbHlyOjptdXRhdGUoY2xhc3NpZmljYXRpb24gPSBmY3RfcmVvcmRlcihjbGFzc2lmaWNhdGlvbiwgZGVzYyhjbGFzc2lmaWNhdGlvbl9wZXJjZW50KSkpICU+JSANCiAgZ2dwbG90KGFlcyh5bWF4PXltYXgsIHltaW49eW1pbiwgeG1heD00LCB4bWluPTMsIGZpbGw9Y2xhc3NpZmljYXRpb24pKSArDQogIGdlb21fcmVjdCgpICsNCiAgY29vcmRfcG9sYXIodGhldGE9InkiKSArIA0KICBnZW9tX2xhYmVsKHg9NSwgYWVzKHk9bGFiZWxQb3NpdGlvbiwgbGFiZWw9bGFiZWwpLCBzaXplPTMsIGFscGhhID0gMC44KSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9ICJEYXJrMiIpICsNCiAgeGxpbShjKDIsIDUpKSArDQogIHRoZW1lX3ZvaWQoKSANCiAgI3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KcGh5bHVtX3VzZV9yaW5nX2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgICANCiANCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGdnc2F2ZSgic3BwX3BoeWx1bV91c2VfcmluZ19maWcucGRmIiwgcGxvdCA9IHBoeWx1bV91c2VfcmluZ19maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSkNCmBgYA0KDQojIyMjIFRheGEgcmVwcmVzZW50YXRpb24gYnkgc3R1ZHkgbW90aXZhdGlvbg0KDQpNYWtpbmcgYSBkYXRhIHNldCB0aGF0IGxvb2tzIGF0IHJlbGF0aXZlIHJlcHJlc2VudGF0aW9uIGJ5IGVhY2ggbW90aXZhdGlvbiwgYW5kIHRoZSB0b3RhbA0KDQpgYGB7cn0NCmxpbmVhZ2VfY291bnRfdXNlX21vdGl2YXRpb24gPC0gbGluZWFnZV9kYXRhICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgbGluZWFnZV9sZXZlbCwgcGFyZW50LCBjbGFzc2lmaWNhdGlvbikgJT4lDQogIGRwbHlyOjpyZWZyYW1lKGNsYXNzaWZpY2F0aW9uX2NvdW50ID0gbGVuZ3RoKHVuaXF1ZV9yb3dfaWQpKSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIGxpbmVhZ2VfbGV2ZWwpICU+JQ0KICBkcGx5cjo6bXV0YXRlKG5fbW90aXZhdGlvbiA9IHN1bShjbGFzc2lmaWNhdGlvbl9jb3VudCkpICU+JQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShjbGFzc2lmaWNhdGlvbl9wZXJjZW50ID0gKGNsYXNzaWZpY2F0aW9uX2NvdW50L25fbW90aXZhdGlvbikqMTAwKQ0KDQpsaW5lYWdlX2NvdW50X3VzZV9hbGwgPC0gbGluZWFnZV9kYXRhICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkobGluZWFnZV9sZXZlbCwgcGFyZW50LCBjbGFzc2lmaWNhdGlvbikgJT4lDQogIGRwbHlyOjpyZWZyYW1lKGNsYXNzaWZpY2F0aW9uX2NvdW50ID0gbGVuZ3RoKHVuaXF1ZV9yb3dfaWQpKSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGxpbmVhZ2VfbGV2ZWwpICU+JQ0KICBkcGx5cjo6bXV0YXRlKG5fbW90aXZhdGlvbiA9IHN1bShjbGFzc2lmaWNhdGlvbl9jb3VudCkpICU+JQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShjbGFzc2lmaWNhdGlvbl9wZXJjZW50ID0gKGNsYXNzaWZpY2F0aW9uX2NvdW50L25fbW90aXZhdGlvbikqMTAwKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJBbGwiKQ0KDQpsaW5lYWdlX2NvdW50X3VzZV9tb3RpdmF0aW9uIDwtIGxpbmVhZ2VfY291bnRfdXNlX21vdGl2YXRpb24gJT4lIA0KICByYmluZCguLCBsaW5lYWdlX2NvdW50X3VzZV9hbGwpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gZmN0X3JlbGV2ZWwoc3R1ZHlfbW90aXZhdGlvbiwgIkFsbCIsICJFbnZpcm9ubWVudGFsIiwgIk1lZGljYWwiLCAiQmFzaWMgcmVzZWFyY2giKSkNCmBgYA0KDQoNCiMjIyMgRmlnIFMzDQoNCkhlcmUncyBhIHRpbGUgcGxvdCB0byBjb21wYXJlIHRoZSB1c2Ugb2YgZGlmZmVyZW50IHRheGEgYWNyb3NzIHRoZSBzdHVkeSBtb3RpdmF0aW9ucyAgIA0KDQpgYGB7cn0NCmNsYXNzX29yZGVyX2RmIDwtIGxpbmVhZ2VfY291bnRfdXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihsaW5lYWdlX2xldmVsID09ICJjbGFzcyIpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoY2xhc3NpZmljYXRpb25fcGVyY2VudCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNsYXNzX29yZGVyID0gMTpucm93KC4pKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoY2xhc3NpZmljYXRpb24sIGNsYXNzX29yZGVyKQ0KDQoNCmNsYXNzX3VzZV9tb3RpdmF0aW9uX2ZpZyA8LSBsaW5lYWdlX2NvdW50X3VzZV9tb3RpdmF0aW9uICU+JSANCiAgZHBseXI6OmZpbHRlcihsaW5lYWdlX2xldmVsID09ICJjbGFzcyIpICU+JSANCiAgZHBseXI6OmZ1bGxfam9pbiguLCBjbGFzc19vcmRlcl9kZiwgYnkgPSAiY2xhc3NpZmljYXRpb24iKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY2xhc3NpZmljYXRpb24gPSBmY3RfcmVvcmRlcihjbGFzc2lmaWNhdGlvbiwgY2xhc3Nfb3JkZXIpLA0KICAgICAgICAgICAgICAgIHBhcmVudCA9IGZjdF9yZW9yZGVyKHBhcmVudCwgZGVzYyhjbGFzc19vcmRlcikpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gc3R1ZHlfbW90aXZhdGlvbiwgeSA9IGNsYXNzaWZpY2F0aW9uLCBmaWxsID0gY2xhc3NpZmljYXRpb25fcGVyY2VudCkpICsNCiAgZ2VvbV90aWxlKCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKGNsYXNzaWZpY2F0aW9uX3BlcmNlbnQsIDEpLCIlIikpKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobmFtZSA9IGV4cHJlc3Npb24oIlJlbGF0aXZlXG5hYnVkYW5jZSAoJSkiKSwNCiAgICAgICAgICAgICAgICAgICAgICBsb3cgPSAiI0ZGRkZGRiIsIGhpZ2ggPSAiIzIzMUYyMCIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgbGFicyh4ID0gIlN0dWR5IG1vdGl2YXRpb24iLA0KICAgICAgIHkgPSAiVGF4b25vbWljIGNsYXNzIikNCmNsYXNzX3VzZV9tb3RpdmF0aW9uX2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZQ0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoInNwcF9jbGFzc191c2VfbW90aXZhdGlvbl9maWcucGRmIiwgcGxvdCA9IGNsYXNzX3VzZV9tb3RpdmF0aW9uX2ZpZywgd2lkdGggPSA1LCBoZWlnaHQgPSA1KQ0KYGBgDQoNCg0KIyMjIyBNb3N0IGNvbW1vbiBzcGVjaWVzIA0KDQpMZXQncyBzZWUgd2hhdCB0aGUgbW9zdCBjb21tb24gc3BlY2llcyB3ZXJlLiBUaGlzIGlzIGNhbGN1bGF0ZWQgYXQgdGhlIHBvcHVsYXRpb24gbGV2ZWwgKGkuZS4gZG9lc24ndCBjb3VudCBlYWNoIHNwZWNpZXMgbXV0aXBsZSB0aW1lcyBpZiBtdWx0aXBsZSBjb21wb3VuZHMgd2VyZSB1c2VkIGluIGEgc2luZ2xlIGFydGljbGU7IHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAgICANCg0KYGBge3J9DQpuX3RvdGFsIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBsZW5ndGgodW5pcXVlX3BvcHVsYXRpb25faWQpKSAlPiUgDQogIG5yb3coLikNCg0Kbl9zcHAgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkLCBzcGVjaWVzX25jYmlfdGF4b25vbXlfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX25hbWUsIHNwZWNpZXNfbmNiaV90YXhvbm9teV9pZCkgJT4lDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBsZW5ndGgoc3BlY2llc19uYW1lKSwNCiAgICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vbl90b3RhbCoxMDAsMSkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHNwcF9udW1iZXIgPSAxOm5yb3coLikpDQoNCm5fc3BwICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTUpICU+JSANCiAgZ3QoKQ0KYGBgDQoNCk1ha2luZyBhIGJyb2FkIGNhdGVnb3J5IG9mIGFidW5kYW5jZSAoYXJ0aWNsZV9uX2dyb3VwKSB0byBtYWtlIHRoZSBzdW1tYXJ5IGFuZCBmaWd1cmUgbW9yZSBkaWdlc3RpYmxlICAgIA0KDQpgYGB7cn0NCm5fc3BwX2ZpZ19kYXRhIDwtIG5fc3BwICU+JSANCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX25jYmlfdGF4b25vbXlfaWQgPSBmY3RfcmVvcmRlcihzcGVjaWVzX25jYmlfdGF4b25vbXlfaWQsIGRlc2MobikpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgYXJ0aWNsZV9uX2dyb3VwID0gY2FzZV93aGVuKA0KICAgICAgbiA9PSAxIH4gIk9uZSBvbmx5IiwNCiAgICAgIG4gPj0gMiAmIG4gPD0gNSB+ICJCZXR3ZWVuIDIgYW5kIDUiLA0KICAgICAgbiA+PSA1ICYgbiA8PSAxMCB+ICJCZXR3ZWVuIDYgYW5kIDEwIiwNCiAgICAgIG4gPj0gMTAgfiAiR3JlYXRlciB0aGFuIDEwIiwNCiAgICAgIFRSVUUgfiAiT3RoZXJzIg0KICAgICkNCiAgKQ0KYGBgDQoNCg0KVGhpcyBpcyB0aGUgbnVtYmVyIG9mIHNwZWNpZXMgaW4gZWFjaCBjYXRlZ29yeSAgICAgDQoNCmBgYHtyfQ0KYXJ0aWNsZV9uX2dyb3VwX3N1bW1hcnkgPC0gbl9zcHBfZmlnX2RhdGEgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9uX2dyb3VwKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fY2F0ID0gbGVuZ3RoKHNwZWNpZXNfbmFtZSkpDQphcnRpY2xlX25fZ3JvdXBfc3VtbWFyeSAlPiUgDQogIGd0KCkNCmBgYA0KDQojIyMjIEZpZyBTMg0KDQpNYWtpbmcgYSBwbG90IHRvIHNob3cgdGhlIGRpc3RyaWJ1dGlvbiBvZiBzcGVjaWVzIHVzZSBpbiB0aGUgRUlQQUFCIGRhdGFiYXNlDQoNCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD01fQ0Kbl9zcHBfZmlnIDwtIG5fc3BwX2ZpZ19kYXRhICU+JSANCiAgZHBseXI6Om11dGF0ZShhcnRpY2xlX25fZ3JvdXAgPSBmY3RfcmVsZXZlbChhcnRpY2xlX25fZ3JvdXAsICJHcmVhdGVyIHRoYW4gMTAiLCAiQmV0d2VlbiA2IGFuZCAxMCIsICJCZXR3ZWVuIDIgYW5kIDUiLCAiT25lIG9ubHkiKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBuLCB4ID0gc3BwX251bWJlciwgY29sb3IgPSBhcnRpY2xlX25fZ3JvdXApKSArDQogIGdlb21fbGluZShsaW5ld2lkdGggPSAxLCBhbHBoYSA9IDAuMikgKw0KICBnZW9tX3BvaW50KHN0YXQgPSAiaWRlbnRpdHkiLCBzaXplID0gMSwgYWxwaGEgPSAwLjgpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKA0KICAgIHZhbHVlcyA9IGMoDQogICAgIk9uZSBvbmx5IiA9ICIjRTk0MDM5IiwgDQogICAgIkJldHdlZW4gMiBhbmQgNSIgPSAiI0YxOEU3NiIsIA0KICAgICJCZXR3ZWVuIDYgYW5kIDEwIiA9ICIjODc3RkJDIiwgDQogICAgIkdyZWF0ZXIgdGhhbiAxMCIgPSAiIzRENDc5RCINCiAgICApLA0KICBsYWJlbHMgPSBjKA0KICAgICAgIk9uZSBvbmx5IiA9ICJPbmUgb25seSAobiA9IDEwNCkiLA0KICAgICAgIkJldHdlZW4gMiBhbmQgNSIgPSAiQmV0d2VlbiAyIGFuZCA1IChuID0gNTMpIiwNCiAgICAgICJCZXR3ZWVuIDYgYW5kIDEwIiA9ICJCZXR3ZWVuIDYgYW5kIDEwIChuID0gMTEpIiwNCiAgICAgICJHcmVhdGVyIHRoYW4gMTAiID0gIkdyZWF0ZXIgdGhhbiAxMCAobiA9IDYpIg0KICAgICAgKQ0KICApICsgICMgU2V0IGNvbG91cnMgZm9yIGVhY2ggY2F0ZWdvcnkNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygtMC4zLCAwLjQpLCAgIyBQb3NpdGlvbmluZyB0aGUgbGVnZW5kIGluc2lkZSB0aGUgcGxvdA0KICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygtMywgMCksICAgIyBCb3R0b20gbGVmdCBpbnNpZGUgdGhlIHBsb3QNCiAgICBsZWdlbmQuYm94Lmp1c3QgPSAicmlnaHQiDQogICAgKSArDQogIGxhYnMoDQogICAgeCA9IHBhc3RlMCgiU3BlY2llcyAoMS0xNzQpIiksDQogICAgeSA9ICJOdW1iZXIgb2YgYXJ0aWNsZXMiLA0KICAgIGNvbG9yID0gIkFydGljbGUgbnVtYmVyIGNhdGVnb3J5Ig0KICApDQoNCm5fc3BwX2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgICANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJzcHBfbl9zcHBfZmlnLnBkZiIsIHBsb3QgPSBuX3NwcF9maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSkNCmBgYA0KDQpNYWtpbmcgYSBsaXN0IG9mIHRoZSBtb3N0IGNvbW1vbiAxNSBzcGVjaWVzICAgDQoNCmBgYHtyfQ0Kbl9zcHBfdXNlZCA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3QodW5pcXVlX3BvcHVsYXRpb25faWQpICU+JSANCiAgbnJvdyguKQ0KDQp0b3BfMTVfc3BwX2xpc3QgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKG4gPSBsZW5ndGgodW5pcXVlKHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSksIC5ncm91cHMgPSAnZHJvcCcpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lICANCiAgZHBseXI6OnNsaWNlKDE6MTUpICU+JSANCiAgZHBseXI6OnB1bGwoc3BlY2llc19uYW1lKSAlPiUgDQogIGFzLmxpc3QoKQ0KYGBgDQoNCk1ha2luZyBhIHN1bW1hcnkgZGF0YWZyYW1lIGJhc2Ugb24gc3R1ZHkgbW90aXZhdGlvbiAgICANCg0KYGBge3J9DQpjb21tb25fc3BlY2llcyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpmaWx0ZXIoc3BlY2llc19uYW1lICVpbiUgdG9wXzE1X3NwcF9saXN0KSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfbmFtZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lDQogIGRwbHlyOjpzdW1tYXJpc2UobiA9IGxlbmd0aCh1bmlxdWUoYXJ0aWNsZV9pZCkpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUNCiAgdGlkeXI6OmNvbXBsZXRlKHNwZWNpZXNfbmFtZSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QobiA9IDApKQ0KDQoNCnNwZWNpZXNfb3JkZXIgPC0gY29tbW9uX3NwZWNpZXMgJT4lDQogIGdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF9uID0gc3VtKG4pLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsX24pKSAlPiUNCiAgdW5ncm91cCgpDQoNCg0KY29tbW9uX3NwZWNpZXMgPC0gY29tbW9uX3NwZWNpZXMgJT4lDQogIGlubmVyX2pvaW4oc3BlY2llc19vcmRlciwgYnkgPSAic3BlY2llc19uYW1lIikgJT4lDQogIG11dGF0ZShzcGVjaWVzX25hbWUgPSBmY3RfcmVvcmRlcihzcGVjaWVzX25hbWUsIHRvdGFsX24pLA0KICAgICAgICAgc3R1ZHlfbW90aXZhdGlvbiA9IGZjdF9yZWxldmVsKHN0dWR5X21vdGl2YXRpb24sICJFbnZpcm9ubWVudGFsIiwgIk1lZGljYWwiLCAiQmFzaWMgcmVzZWFyY2giKSkgDQpgYGANCg0KDQojIyMjIEZpZyAzYw0KDQpBIHBsb3Qgb2YgdGhlIG51bWJlciBvZiB0aW1lcyBlYWNoIG9mIHRoZSAxNSBvdmVyYWxsIG1vc3QgY29tbW9uIHNwZWNpZXMgYXBwZWFyZWQgaW4gYXJ0aWNsZXMgd2l0aGluIHRoZSBFSVBBQUIgZGF0YWJzZSBieSBzdHVkeSBtb3RpdmF0aW9uLiBJdCdzIGEgbGl0dGxlIGhhcmQgdG8gc2VlIGluIHRoZSBjaHVuayBvdXRwdXQsIHRyeSB2aWV3aW5nIGluIGFuIGV4dGVybmFsIHdpbmRvdy4gICAgDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9NX0NCnRvcF8xNV9zcHBfZmlnIDwtIGNvbW1vbl9zcGVjaWVzICU+JSANCiAgZ2dwbG90KGFlcyh4PXNwZWNpZXNfbmFtZSwgeT1uLCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiwgZ3JvdXAgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjEpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIiwgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiTnVtYmVyIG9mIHN0dWRpZXMiDQogICkgKw0KICAgdGhlbWUoKQ0KDQp0b3BfMTVfc3BwX2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJzcHBfdG9wXzE1X3NwcF9maWcucGRmIiwgcGxvdCA9IHRvcF8xNV9zcHBfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDEwKQ0KYGBgDQoNClN1bW1hcmlzaW5nIHRoZSB0b3AgMTAgaW4gZWFjaCBtb3RpdmF0aW9uIG1vcmUgc3BlY2lmaWNhbGx5ICAgIA0KDQpgYGB7cn0NCnNwcF9tb2l0aXZhdGlvbl9zdW1tYXJ5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX25hbWUsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShuID0gbGVuZ3RoKHVuaXF1ZSh1bmlxdWVfcG9wdWxhdGlvbl9pZCkpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShzcGVjaWVzX25hbWUsIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KG4gPSAwKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHByb3AgPSBuL3RvdGFsKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsKQ0KYGBgDQoNClRoaXMgcGxvdCBzaG93cyB0aGUgdG9wIDEwIGluIGVhY2ggbW90aXZhdGlvbiAgIA0KDQpgYGB7cn0NCnRvcF8xMF9lbnZfc3BwIDwtIHNwcF9tb2l0aXZhdGlvbl9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJFbnZpcm9ubWVudGFsIikgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjEwKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19uYW1lID0gZmN0X3Jlb3JkZXIoc3BlY2llc19uYW1lLCBuKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3BlY2llc19uYW1lLCB5PW4pKSArDQogIGdlb21fY29sKHdpZHRoID0gMC4wMSwgY29sb3VyID0gIiM2MEJENkMiLCBmaWxsID0gIiM2MEJENkMiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIGNvbG91ciA9ICIjNjBCRDZDIiwgZmlsbCA9ICIjNjBCRDZDIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIk51bWJlciBvZiBzdHVkaWVzIiwNCiAgICB0aXRsZSA9ICJFbnZpcm9ubWVudGFsIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikNCiAgICkNCg0KdG9wXzEwX21lZF9zcHAgPC0gc3BwX21vaXRpdmF0aW9uX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0dWR5X21vdGl2YXRpb24gPT0gIk1lZGljYWwiKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTApICU+JSANCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX25hbWUgPSBmY3RfcmVvcmRlcihzcGVjaWVzX25hbWUsIG4pKSAlPiUgDQogIGdncGxvdChhZXMoeD1zcGVjaWVzX25hbWUsIHk9bikpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjAxLCBjb2xvdXIgPSAiI0QzNTlBMSIsIGZpbGwgPSAiI0QzNTlBMSIpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMiwgY29sb3VyID0gIiNEMzU5QTEiLCBmaWxsID0gIiNEMzU5QTEiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiTnVtYmVyIG9mIHN0dWRpZXMiLA0KICAgIHRpdGxlID0gIk1lZGljYWwiDQogICkgKw0KICAgdGhlbWUoDQogICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKQ0KICAgKQ0KDQp0b3BfMTBfYmFzZV9zcHAgPC0gc3BwX21vaXRpdmF0aW9uX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0dWR5X21vdGl2YXRpb24gPT0gIkJhc2ljIHJlc2VhcmNoIikgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjEwKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19uYW1lID0gZmN0X3Jlb3JkZXIoc3BlY2llc19uYW1lLCBuKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3BlY2llc19uYW1lLCB5PW4pKSArDQogIGdlb21fY29sKHdpZHRoID0gMC4wMSwgY29sb3VyID0gIiMzQzgyQzQiLCBmaWxsID0gIiMzQzgyQzQiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIGNvbG91ciA9ICIjM0M4MkM0IiwgZmlsbCA9ICIjM0M4MkM0IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIk51bWJlciBvZiBzdHVkaWVzIiwNCiAgICB0aXRsZSA9ICJCYXNpYyINCiAgKSArDQogICB0aGVtZSgNCiAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpDQogICApDQpgYGANCg0KSGVyZSdzIGEgcGxvdCB0byBjb21wYXJlIHRoZSB0b3AgMTAgc3BwIGluIGVhY2ggc3R1ZHkgbW90aXZhdGlvbiBtb3JlIHNwZWNpZmljYWxseSANCg0KYGBge3IgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9OH0NCnRvcF8xMF9jb21iaW5kX3Bsb3QgPC0gZ3JpZC5hcnJhbmdlKHRvcF8xMF9lbnZfc3BwLCB0b3BfMTBfbWVkX3NwcCwgdG9wXzEwX2Jhc2Vfc3BwLCBuY29sID0gMykNCmBgYA0KDQpMb29raW5nIGF0IHRoZSBudW1iZXIgb2YgZGlzdGluY3Qgc3BlY2llcyB1c2VkIGluIGVhY2ggbW90aXZhdGlvbiBncm91cA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fbW90aXZhdGlvbiA9IG5fZGlzdGluY3QoYXJ0aWNsZV9pZCksDQogICAgICAgICAgICAgICAgIG5fZGlzdGluY3Rfc3BwID0gbl9kaXN0aW5jdChzcGVjaWVzX25hbWUpKSAlPiUgDQogIGd0KCkNCmBgYA0KDQoNCiMjIyBTcGVjaWVzIGhhYml0YXQNCg0KRmlyc3QgY2hlY2tpbmcgaG93IG1hbnkgc3BlY2llcyBoYXZlIElVQ04gZGF0YSwgd2hpY2ggd2Ugd2lsbCB1c2UgdG8gYXNzZXNzIGhhYml0YXQgZGlmZmVyZW5jZXMNCg0KYGBge3J9DQpzcGVjaWVzX2l1Y25fc3VtbWFyeSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19uYW1lKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfaXVjbl9iaW4gPSBpZl9lbHNlKGlzLm5hKHNwZWNpZXNfaXVjbl9kb2kpLCAiTm8iLCAiWWVzIikpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfaXVjbl9iaW4pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IGxlbmd0aChzcGVjaWVzX2l1Y25fYmluKSkNCg0Kc3BlY2llc19pdWNuX3N1bW1hcnkgJT4lIA0KICBndCgpDQpgYGANCg0KU3VtbWFyaXNpbmcgdGhlIElVTkMgaGFiaXRhdCB0eXBlLCBzb21lIHNwZWNpZXMgd2lsbCBoYXZlIG11bHRpcGxlIGhhYml0YXRzLCBzbyB3ZSBzcGxpdCB0aGUgc3RyaW5nIGJ5IHRoZSBzZXByZWF0ZSAoOykgICANCg0KYGBge3J9DQpoYWJpdGF0X3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgIyBzYW1wbGluZyBvbmUgcm93IHBlciBhcnRpY2xlIHBlciBzcGVjaWVzIChpLmUuIGlnbm9yaW5nIG11bHRpcGxlIHJvd3MgcGVyIGFydGljbGUgZm9yIGNvbXBvdW5kcykNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX2l1Y25faGFiaXRhdCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX2l1Y25faGFiaXRhdCA9IHN0cl90cmltKHNwZWNpZXNfaXVjbl9oYWJpdGF0KSkgJT4lDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKHNwZWNpZXNfaXVjbl9oYWJpdGF0LCBzZXAgPSAiOyIpICU+JSAjIGVhY2ggc3BwIGhhcyBtdWx0aXBsZSBoYWJpdGF0cyB0aGUgc3RyaW5nIG5lZWRzIHNwbGl0aW5nDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX2l1Y25faGFiaXRhdCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuX2FydGljbGVzID0gc3VtKG4pKSAlPiUgIyBub3cgYSBzdW0gZm9yIGVhY2ggaGFiaXRhdA0KICBhcnJhbmdlKGRlc2Mobl9hcnRpY2xlcykpDQpoYWJpdGF0X3N1bW1hcnkgJT4lIA0KICBndCgpDQpgYGANCg0KQ2hlY2tpbmcgaG93IG1hbnkgZnJlc2h3YXRlciB2cyBtYXJpbmUgc3BlY2llcyB0aGVyZSBhcmUuIFdldGxhbmRzIGlubGFuZCBjYXRlZ29yaWVzIGFyZSBmcmVzaHdhdGVyIGJvZGllcyB3aGVyZSBhcyBNYXJpbmUgIGhhdmUgbXVsdGlwbGUgY2F0ZWdvcmllcyAoTWFyaW5lIE5lcml0aWMsIE1hcmluZSBDb2FzdGFsIG9yIFN1cHJhdGlkYWwsIE1hcmluZSBJbnRlcnRpZGFsLCBNYXJpbmUgT2NlYW5pYykuICAgDQoNCmBgYHtyfQ0KaGFiaXRhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHJfc3RhcnRzKHNwZWNpZXNfaXVjbl9oYWJpdGF0LCAiTWFyaW5lIikgfCBzcGVjaWVzX2l1Y25faGFiaXRhdCA9PSAiV2V0bGFuZHMgaW5sYW5kIikgJT4lICMgT25seSBoYWJpdGF0cyBvZiBpbnRlcmVzdCANCiAgZHBseXI6Om11dGF0ZShhcXVhdGljX3R5cGUgPSBpZl9lbHNlKHNwZWNpZXNfaXVjbl9oYWJpdGF0ID09ICJXZXRsYW5kcyBpbmxhbmQiLCAiRnJlc2h3YXRlciIsICJNYXJpbmUiKSkgJT4lICMgTmV3IGNhdGVnb3J5DQogIGRwbHlyOjpncm91cF9ieShhcXVhdGljX3R5cGUpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobl9hcnRpY2xlcyA9IHN1bShuX2FydGljbGVzKSkgJT4lICMgRmluYWwgc3Vtcw0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShuX3RvdGFsID0gc3VtKG5fYXJ0aWNsZXMpLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSAgcm91bmQobl9hcnRpY2xlcy9uX3RvdGFsKjEwMCwxKSkgJT4lIA0KICBndCgpDQpgYGANCg0KDQpMZXRzIGJyZWFrIHRoaXMgdXAgYnkgc3R1ZHkgbW90aXZhdGlvbiAgDQoNCmBgYHtyfQ0KaGFiaXRhdF9zdW1tYXJ5X2FsbCA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodW5pcXVlX3BvcHVsYXRpb25faWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIHNhbXBsaW5nIG9uZSByb3cgcGVyIGFydGljbGUgcGVyIHNwZWNpZXMgKGkuZS4gaWdub3JpbmcgbXVsdGlwbGUgcm93cyBwZXIgYXJ0aWNsZSBmb3IgY29tcG91bmRzKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHNwZWNpZXNfaXVjbl9oYWJpdGF0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfaXVjbl9oYWJpdGF0ID0gc3RyX3RyaW0oc3BlY2llc19pdWNuX2hhYml0YXQpKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3Moc3BlY2llc19pdWNuX2hhYml0YXQsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXRpbmcNCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfaXVjbl9oYWJpdGF0LCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fYXJ0aWNsZXMgPSBzdW0obikpICU+JSAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIGFycmFuZ2UoZGVzYyhuX2FydGljbGVzKSkNCmhhYml0YXRfc3VtbWFyeV9hbGwgJT4lIA0KICBndCgpDQpgYGANCg0KU2VsZWN0aW5nIG9ubHkgaGFiaXRhdHMgb2YgaW50ZXJlc3QgYW5kIGFsbG9jYXRpbmcgdG8gRnJlc2h3YXRlciBvciBNYXJpbmUgICAgDQoNCmBgYHtyfQ0KZnJlc2h3YXRlcl9tYXJpbmUgPC0gaGFiaXRhdF9zdW1tYXJ5X2FsbCAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3RyX3N0YXJ0cyhzcGVjaWVzX2l1Y25faGFiaXRhdCwgIk1hcmluZSIpIHwgc3BlY2llc19pdWNuX2hhYml0YXQgPT0gIldldGxhbmRzIGlubGFuZCIpICU+JSAjIE9ubHkgaGFiaXRhdHMgb2YgaW50ZXJlc3QgDQogIGRwbHlyOjptdXRhdGUoYXF1YXRpY190eXBlID0gaWZfZWxzZShzcGVjaWVzX2l1Y25faGFiaXRhdCA9PSAiV2V0bGFuZHMgaW5sYW5kIiwgIkZyZXNod2F0ZXIiLCAiTWFyaW5lIikpICU+JSAjIE5ldyBjYXRlZ29yeQ0KICBkcGx5cjo6Z3JvdXBfYnkoYXF1YXRpY190eXBlLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fYXJ0aWNsZXMgPSBzdW0obl9hcnRpY2xlcykpICU+JSAjIEZpbmFsIHN1bXMNCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZShuX2NhdCA9IHN1bShuX2FydGljbGVzKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwcm9wID0gIG5fYXJ0aWNsZXMvbl9jYXQpICMgQSBwcm9wb3J0aW9uIG9mIHRob3NlIGlkZW50aWZ5IGFzIGZyZXNod2F0ZXIgdnMgbWFyaW5lDQoNCmZyZXNod2F0ZXJfbWFyaW5lICU+JSANCiAgZ3QoKQ0KYGBgDQoNCkhlcmUncyBhIGZpZ3VyZSB2ZXJzaW9uIG9mIHRoaXMgc3VtbWFyeQ0KDQoNCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD0yLjV9DQphcXVhdGljX3R5cGVfb3JkZXIgPC0gYygiRnJlc2h3YXRlciIsICJNYXJpbmUiKQ0KDQojIENhbGN1bGF0ZSBjdW11bGF0aXZlIHBvc2l0aW9ucyBmb3IgdGV4dCBsYWJlbHMNCmZyZXNod2F0ZXJfbWFyaW5lIDwtIGZyZXNod2F0ZXJfbWFyaW5lICU+JQ0KICBkcGx5cjo6bXV0YXRlKGFxdWF0aWNfdHlwZSA9IGZhY3RvcihhcXVhdGljX3R5cGUsIGxldmVscyA9IGFxdWF0aWNfdHlwZV9vcmRlcikpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JQ0KICBkcGx5cjo6YXJyYW5nZShkZXNjKGFxdWF0aWNfdHlwZSkpICU+JSANCiAgZHBseXI6Om11dGF0ZShjdW11bGF0aXZlX3Byb3AgPSBjdW1zdW0ocHJvcCkgLSBwcm9wIC8gMikNCg0KIyBEZWZpbmUgdGhlIGJsYWNrIGFuZCBncmV5IGNvbG9yIHRoZW1lDQpjb2xvcl90aGVtZSA8LSBjKCIjN0ZBQjkxIiwgIiMyQTRBNjQiKQ0KDQojIENyZWF0ZSB0aGUgcGxvdA0KaGFiaXRhdF9maWcgPC0gZnJlc2h3YXRlcl9tYXJpbmUgJT4lDQogIG11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gZmN0X3JlbGV2ZWwoc3R1ZHlfbW90aXZhdGlvbiwgIkJhc2ljIHJlc2VhcmNoIiwgIk1lZGljYWwiLCAiRW52aXJvbm1lbnRhbCIpKSAlPiUgDQogIGdncGxvdChhZXMoeSA9IHByb3AsIHggPSBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gYXF1YXRpY190eXBlLCBncm91cCA9IGFxdWF0aWNfdHlwZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC45KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChwcm9wLCAyKSwgeSA9IGN1bXVsYXRpdmVfcHJvcCksIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDMpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yX3RoZW1lLCBuYW1lID0gIkhhYml0YXQiKSArIA0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKSArDQogIGxhYnMoDQogICAgeCA9ICJTdHVkeSBtb3RpdmF0aW9uIiwNCiAgICB5ID0gIlByb3BvcnRpb24gb2YgYWxsIHNwZWNpZXMgYXNzaWduZWQgdG8gZnJlc2h3YXRlciBvciBtYXJpbmUgaGFiaXRhdCINCiAgKSArDQogIGNvb3JkX2ZsaXAoKQ0KDQpoYWJpdGF0X2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoInNwcF9oYWJpdGF0X2ZpZy5wZGYiLCBwbG90ID0gaGFiaXRhdF9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpDQpgYGANCg0KV2Ugc2hvdWxkIGFsc28gY29uc2lkZXIgaG93IG1hbnkgcmVjb3JkcyBkaWQgbm90IGluY3VsZGUgSVVDTiByZXBvcnRzIGFuZCB0aHVzIGhhYml0YXQuICAgDQoNCkxldCdzIG1ha2UgYSBwbG90IHRoYXQgc2hvd3MgaG93IG1hbnkgZGlkbid0IGhhdmUgYW4gYXNzaWduZWQgSVVOQyBoYWJpdGF0LiBUbyBhZGQgdG8gdGhlIGFib3ZlIGZpZ3VyZS4gICANCg0KYGBge3J9DQpub19oYWJpdGF0IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh1bmlxdWVfcG9wdWxhdGlvbl9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lICMgc2FtcGxpbmcgb25lIHJvdyBwZXIgYXJ0aWNsZSBwZXIgc3BlY2llcyAoaS5lLiBpZ25vcmluZyBtdWx0aXBsZSByb3dzIHBlciBhcnRpY2xlIGZvciBjb21wb3VuZHMpDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19pdWNuX2JpbiA9IGlmX2Vsc2UoaXMubmEoc3BlY2llc19pdWNuX2RvaSksICJObyIsICJZZXMiKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19pdWNuX2JpbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbGVuZ3RoKHNwZWNpZXNfaXVjbl9iaW4pKQ0KICANCg0Kbl90b3RhbCA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodW5pcXVlX3BvcHVsYXRpb25faWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIHNhbXBsaW5nIG9uZSByb3cgcGVyIGFydGljbGUgcGVyIHNwZWNpZXMgKGkuZS4gaWdub3JpbmcgbXVsdGlwbGUgcm93cyBwZXIgYXJ0aWNsZSBmb3IgY29tcG91bmRzKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JQ0KICBucm93KC4pDQoNCm5vX2hhYml0YXQgPC0gbm9faGFiaXRhdCAlPiUNCiAgZHBseXI6Om11dGF0ZShwcm9wID0gbi9uX3RvdGFsKQ0KDQpub19oYWJpdGF0ICU+JSANCiAgZ3QoKQ0KYGBgDQoNCkhlcmUncyB0aGUgcGxvdCAgIA0KDQpgYGB7ciwgZmlnLndpZHRoPTIuNSwgZmlnLmhlaWdodD01fQ0KIyBEZWZpbmUgdGhlIGJsYWNrIGFuZCBncmV5IGNvbG9yIHRoZW1lDQpibGFja19hbmRfZ3JleSA8LSBjKCIjQkNCRUMwIiwgIiM0MTQwNDIiKQ0KDQp5ZXNfb3JkZXIgPC0gYygiWWVzIiwgIk5vIikNCg0KIyBDYWxjdWxhdGUgY3VtdWxhdGl2ZSBwb3NpdGlvbnMgZm9yIHRleHQgbGFiZWxzDQpoYWJpdGF0X2luZm9fZGZfZmlnIDwtIG5vX2hhYml0YXQgJT4lDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19pdWNuX2JpbiA9IGZhY3RvcihzcGVjaWVzX2l1Y25fYmluLCBsZXZlbHMgPSB5ZXNfb3JkZXIpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2Moc3BlY2llc19pdWNuX2JpbikpICU+JSANCiAgZHBseXI6Om11dGF0ZShjdW11bGF0aXZlX3Byb3AgPSBjdW1zdW0ocHJvcCkgLSBwcm9wIC8gMikNCg0KaGFiaXRhdF9pbmZvX2ZpZyA8LSBoYWJpdGF0X2luZm9fZGZfZmlnICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfaXVjbl9iaW4gPSBmYWN0b3Ioc3BlY2llc19pdWNuX2JpbiwgbGV2ZWxzID0geWVzX29yZGVyKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBwcm9wLCB4ID0gMSwgZmlsbCA9IHNwZWNpZXNfaXVjbl9iaW4pKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuMSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQocHJvcCwgMiksIHkgPSBjdW11bGF0aXZlX3Byb3ApLCBjb2xvciA9ICJ3aGl0ZSIpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGJsYWNrX2FuZF9ncmV5LCBuYW1lID0gIkhhYml0YXQiKSArIA0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgICMgUmVtb3ZlIHgtYXhpcyB0ZXh0DQogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSAgIyBSZW1vdmUgeC1heGlzIHRpY2tzIA0KICAgICAgICApICsNCiAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQcm9wb3J0aW9uIG9mIHNwZWNpZXMgdGVzdGVkIGluIHRoZSBkYXRhYmFzZSINCiAgKQ0KaGFiaXRhdF9pbmZvX2ZpZw0KYGBgDQoNClNhdmUgdGhlIHBsb3QgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGdnc2F2ZSgic3BwX2hhYml0YXRfaW5mb19maWcucGRmIiwgcGxvdCA9IGhhYml0YXRfaW5mb19maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMTApDQpgYGANCg0KDQojIyMgU3BlY2llcyBsaWZlIHNhdGdlIA0KDQpMZXQncyBnZXQgYW4gb3ZlcmFsbCBzdW1tYXJ5IGZpcnN0LCB3aXRob3V0IFVua25vd24gb3Igbm90IHNwZWNpZmllZCBsaWZlIHN0YWdlcw0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh1bmlxdWVfcG9wdWxhdGlvbl9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lICMgc2FtcGxpbmcgb25lIHJvdyBwZXIgYXJ0aWNsZSBwZXIgc3BlY2llcyAoaS5lLiBpZ25vcmluZyBtdWx0aXBsZSByb3dzIHBlciBhcnRpY2xlIGZvciBjb21wb3VuZHMpDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zdGFnZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX3N0YWdlID0gc3RyX3RyaW0oc3BlY2llc19zdGFnZSkpICU+JQ0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhzcGVjaWVzX3N0YWdlLCBzZXAgPSAiOyIpICU+JSAjIGVhY2ggc3BwIGhhcyBtdWx0aXBsZSBoYWJpdGF0cyB0aGUgc3RyaW5nIG5lZWRzIHNwbGl0dGluZw0KICBkcGx5cjo6ZmlsdGVyKHNwZWNpZXNfc3RhZ2UgIT0gIlVua25vd24gb3Igbm90IHNwZWNpZmllZCIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc3RhZ2UpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobl9hcnRpY2xlcyA9IHN1bShuKSkgJT4lICAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIGRwbHlyOjptdXRhdGUodG90YWxfc3RhZ2VzID0gc3VtKG5fYXJ0aWNsZXMpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG92ZXJhbGxfcGVyY2VudCA9IHJvdW5kKG5fYXJ0aWNsZXMvdG90YWxfc3RhZ2VzKjEwMCwxKSkgJT4lIA0KICBndCgpDQpgYGANCg0KDQpMZXQncyB0YWtlIGEgbG9vayBhdCBzcHAgbGlmZSBzdGFnZXMgdXNlZCBpbiB0aGUgRUlQQUFCIGRhdGFiYXNlIG9uIHN0dWR5IG1vdGl2YXRpb24gICANCg0KRmlyc3QgdGhvc2UgdGhhdCBkaWRuJ3QgcmVwb3J0IGl0ICAgDQoNCmBgYHtyfQ0Kc3RhZ2Vfc3VtbWFyeV9hbGwgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgIyBzYW1wbGluZyBvbmUgcm93IHBlciBhcnRpY2xlIHBlciBzcGVjaWVzIChpLmUuIGlnbm9yaW5nIG11bHRpcGxlIHJvd3MgcGVyIGFydGljbGUgZm9yIGNvbXBvdW5kcykNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBzcGVjaWVzX3N0YWdlKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc3RhZ2UgPSBzdHJfdHJpbShzcGVjaWVzX3N0YWdlKSkgJT4lDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKHNwZWNpZXNfc3RhZ2UsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXR0aW5nDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX3N0YWdlLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fdG90YWwgPSBzdW0obikpICU+JSAgIyBub3cgYSBzdW0gZm9yIGVhY2ggaGFiaXRhdA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG5fbW90aXZhdGlvbiA9IHN1bShuX3RvdGFsKSwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobl90b3RhbC9uX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkNCg0Kc3RhZ2Vfc3VtbWFyeV9hbGwgJT4lDQogIGRwbHlyOjpmaWx0ZXIoc3BlY2llc19zdGFnZSA9PSAiVW5rbm93biBvciBub3Qgc3BlY2lmaWVkIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfcmVwb3J0ZWQgPSAxMDAtcGVyY2VudCkgJT4lIA0KICBkcGx5cjo6cmVuYW1lKHBlcmNlbnRfbm90X3JlcG9ydCA9IHBlcmNlbnQpICU+JSANCiAgZ3QoKQ0KYGBgDQpBIHRhYmxlIGJ5IHN0dWR5IG1vdGl2YXRpb24gYW5kIGFnZSBjbGFzcyAgIA0KDQpgYGB7cn0NCnN0YWdlX29yZGVyIDwtIGMoIkFkdWx0IiwgIkp1dmVuaWxlIiwgIkxhcnZhZSIsICJFZ2cgb3IgZW1icnlvIikNCg0Kc3RhZ2Vfc3VtbWFyeV9yZXBvcnRlZCA8LSBzdGFnZV9zdW1tYXJ5X2FsbCAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3BlY2llc19zdGFnZSAhPSAiVW5rbm93biBvciBub3Qgc3BlY2lmaWVkIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG5fbW90aXZhdGlvbiA9IHN1bShuX3RvdGFsKSwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobl90b3RhbC9uX21vdGl2YXRpb24qMTAwLDEpLA0KICAgICAgICAgICAgICAgIHNwZWNpZXNfc3RhZ2UgPSBmYWN0b3Ioc3BlY2llc19zdGFnZSwgbGV2ZWxzID0gc3RhZ2Vfb3JkZXIpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShzcGVjaWVzX3N0YWdlKSANCg0Kc3RhZ2Vfc3VtbWFyeV9yZXBvcnRlZCAlPiUgDQogIGd0KCkNCmBgYA0KDQpTYW1lIGRhdGEgcHJlc2VudGVkIGFzIGEgZmlndXJlICAgIA0KDQpGb3IgbGlmZSBzdGFnZXMgdGhhdCBhcmUgZGVzY3JpYmVkLCB3aGF0IGlzIHRoZSBicmVha2Rvd24gICANCg0KYGBge3IsIGZpZy53aWR0aD01LCBmaWcuaGVpZ2h0PTIuNX0NCiMgRGVmaW5lIHRoZSBibGFjayBhbmQgZ3JleSBjb2xvciB0aGVtZQ0KY29sb3JfdGhlbWUgPC0gYygiI0ExNDMyMyIsICIjRDg2QzJGIiwgIiNFRTlFNUEiLCAiI0YzRTlBNSIpDQoNCg0KIyBDYWxjdWxhdGUgY3VtdWxhdGl2ZSBwb3NpdGlvbnMgZm9yIHRleHQgbGFiZWxzDQpzdGFnZV9zdW1tYXJ5X3JlcG9ydGVkIDwtIHN0YWdlX3N1bW1hcnlfcmVwb3J0ZWQgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUNCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzcGVjaWVzX3N0YWdlKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGN1bXVsYXRpdmVfcGVyY2VudCA9IGN1bXN1bShwZXJjZW50KSAtIHBlcmNlbnQgLyA0KQ0KDQojIENyZWF0ZSB0aGUgcGxvdA0KbGlmZV9zdGFnZV9maWcgPC0gc3RhZ2Vfc3VtbWFyeV9yZXBvcnRlZCAlPiUNCiAgbXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSBmY3RfcmVsZXZlbChzdHVkeV9tb3RpdmF0aW9uLCAiQmFzaWMgcmVzZWFyY2giLCAiTWVkaWNhbCIsICJFbnZpcm9ubWVudGFsIikpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSBwZXJjZW50LCB4ID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHNwZWNpZXNfc3RhZ2UsIGdyb3VwID0gc3BlY2llc19zdGFnZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC45KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50LCB5ID0gY3VtdWxhdGl2ZV9wZXJjZW50KSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKyANCiBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl90aGVtZSwgbmFtZSA9ICJMaWZlIHN0YWdlIikgKyANCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKw0KICBsYWJzKA0KICAgIHggPSAiU3R1ZHkgbW90aXZhdGlvbiIsDQogICAgeSA9ICJQZXJjZW50IG9mIGFsbCBzcGVjaWVzIGFzc2lnbmVkIHRvIGEgbGlmZSBzdGFnZSINCiAgKSArDQogIGNvb3JkX2ZsaXAoKQ0KDQpsaWZlX3N0YWdlX2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGdnc2F2ZSgic3BwX2xpZmVfc3RhZ2VfZmlnLnBkZiIsIHBsb3QgPSBsaWZlX3N0YWdlX2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkNCmBgYA0KDQpMZXQncyBhbHNvIGxvb2sgYXQgaG93IG1hbnkgd2hlcmUgdW5rbm93biBvciBub3QgZGVzY3JpYmVkIG92ZXJhbGwgICANCg0KYGBge3J9DQpzdGFnZV9zdW1tYXJ5X2luZm8gIDwtIHN0YWdlX3N1bW1hcnlfYWxsICU+JSANCiAgZHBseXI6Om11dGF0ZShzdGFnZV9yZXBvcnRlZCA9IGlmX2Vsc2Uoc3BlY2llc19zdGFnZSA9PSAiVW5rbm93biBvciBub3Qgc3BlY2lmaWVkIiwgIk5vIiwgIlllcyIpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdGFnZV9yZXBvcnRlZCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG5fdG90YWwpKQ0KDQpuX3RvdGFsIDwtIHN0YWdlX3N1bW1hcnlfaW5mbyAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fdG90YWwgPSBzdW0obikpICU+JSANCiAgcHVsbChuX3RvdGFsKQ0KDQpzdGFnZV9zdW1tYXJ5X2luZm8gPC0gc3RhZ2Vfc3VtbWFyeV9pbmZvICU+JSANCiAgZHBseXI6Om11dGF0ZShwcm9wID0gbi9uX3RvdGFsKQ0KYGBgDQoNCkhlcmUncyB0aGUgcGxvdCANCg0KYGBge3IsIGZpZy53aWR0aD0yLjUsIGZpZy5oZWlnaHQ9NX0NCiMgRGVmaW5lIHRoZSBibGFjayBhbmQgZ3JleSBjb2xvciB0aGVtZQ0KYmxhY2tfYW5kX2dyZXkgPC0gYygiI0JDQkVDMCIsICIjNDE0MDQyIikNCg0KeWVzX29yZGVyIDwtIGMoIlllcyIsICJObyIpDQoNCiMgQ2FsY3VsYXRlIGN1bXVsYXRpdmUgcG9zaXRpb25zIGZvciB0ZXh0IGxhYmVscw0Kc3RhZ2Vfc3VtbWFyeV9pbmZvIDwtIHN0YWdlX3N1bW1hcnlfaW5mbyAlPiUNCiAgZHBseXI6Om11dGF0ZShzdGFnZV9yZXBvcnRlZCA9IGZhY3RvcihzdGFnZV9yZXBvcnRlZCwgbGV2ZWxzID0geWVzX29yZGVyKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKHN0YWdlX3JlcG9ydGVkKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGN1bXVsYXRpdmVfcHJvcCA9IGN1bXN1bShwcm9wKSAtIHByb3AgLyAyKQ0KDQpzdGFnZV9pbmZvX2ZpZyA8LSBzdGFnZV9zdW1tYXJ5X2luZm8gJT4lDQogIGRwbHlyOjptdXRhdGUoc3RhZ2VfcmVwb3J0ZWQgPSBmYWN0b3Ioc3RhZ2VfcmVwb3J0ZWQsIGxldmVscyA9IHllc19vcmRlcikpICU+JSANCiAgZ2dwbG90KGFlcyh5ID0gcHJvcCwgeCA9IDEsIGZpbGwgPSBzdGFnZV9yZXBvcnRlZCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC45KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChwcm9wLCAyKSwgeSA9IGN1bXVsYXRpdmVfcHJvcCksIGNvbG9yID0gIndoaXRlIikgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYmxhY2tfYW5kX2dyZXksIG5hbWUgPSAiU3RhZ2UgcmVwb3J0ZWQiKSArIA0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwgICMgUmVtb3ZlIHgtYXhpcyB0ZXh0DQogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSAgIyBSZW1vdmUgeC1heGlzIHRpY2tzIA0KICApICsNCiAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQcm9wb3J0aW9uIG9mIHNwZWNpZXMgdGVzdGVkIGluIHRoZSBkYXRhYmFzZSINCiAgKQ0Kc3RhZ2VfaW5mb19maWcNCmBgYA0KDQpTYXZlIHRoZSBmaWd1cmUgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGdnc2F2ZSgic3BwX3N0YWdlX2luZm9fZmlnLnBkZiIsIHBsb3QgPSBzdGFnZV9pbmZvX2ZpZywgd2lkdGggPSAyLjUsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMjIFNwZWNpZXMgc2V4IA0KDQpGaXJzdCBvdmVyYWxsIGJyZWFrZG93biBieSBmZW1hbGUgYW5kIG1hbGUgd2l0aG91dCBpbmNsdWRpbmcgdW5yZXBvcnRlZCBvciBoZXJtYXBocm9kaXRpYyBhbmltYWxzDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgIyBzYW1wbGluZyBvbmUgcm93IHBlciBhcnRpY2xlIHBlciBzcGVjaWVzIChpLmUuIGlnbm9yaW5nIG11bHRpcGxlIHJvd3MgcGVyIGFydGljbGUgZm9yIGNvbXBvdW5kcykNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX3NleCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX3NleCA9IHN0cl90cmltKHNwZWNpZXNfc2V4KSkgJT4lDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKHNwZWNpZXNfc2V4LCBzZXAgPSAiOyIpICU+JSAjIGVhY2ggc3BwIGhhcyBtdWx0aXBsZSBoYWJpdGF0cyB0aGUgc3RyaW5nIG5lZWRzIHNwbGl0dGluZw0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zZXgpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShuX2FydGljbGVzID0gc3VtKG4pLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgICMgbm93IGEgc3VtIGZvciBlYWNoIGhhYml0YXQNCiAgdGlkeXI6OmNvbXBsZXRlKHNwZWNpZXNfc2V4LCANCiAgICAgICAgICAgICAgICAgIGZpbGwgPSBsaXN0KG5fYXJ0aWNsZXMgPSAwKSkgJT4lICAjIG1ha2UgYSBmdWxsIGRmIHdpdGggZW1wdHkgY2F0ZWdvcmllcyA9IDANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUNCiAgZHBseXI6OmZpbHRlcihzcGVjaWVzX3NleCA9PSAiRmVtYWxlIiB8IHNwZWNpZXNfc2V4ID09ICJNYWxlIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX3NleCA9IHN1bShuX2FydGljbGVzKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShvdmVyYWxsX3BlcmNlbnQgPSByb3VuZChuX2FydGljbGVzL3RvdGFsX3NleCoxMDAsMSkpICU+JSANCiAgZ3QoKQ0KYGBgDQoNCg0KTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIHNleCBvZiBzcHAgdXNlZCBpbiB0aGUgRUlQQUFCIGRhdGFiYXNlICAgDQoNCmBgYHtyfQ0Kc2V4X3N1bW1hcnlfYWxsIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh1bmlxdWVfcG9wdWxhdGlvbl9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lICMgc2FtcGxpbmcgb25lIHJvdyBwZXIgYXJ0aWNsZSBwZXIgc3BlY2llcyAoaS5lLiBpZ25vcmluZyBtdWx0aXBsZSByb3dzIHBlciBhcnRpY2xlIGZvciBjb21wb3VuZHMpDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgc3BlY2llc19zZXgpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoc3BlY2llc19zZXggPSBzdHJfdHJpbShzcGVjaWVzX3NleCkpICU+JQ0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhzcGVjaWVzX3NleCwgc2VwID0gIjsiKSAlPiUgIyBlYWNoIHNwcCBoYXMgbXVsdGlwbGUgaGFiaXRhdHMgdGhlIHN0cmluZyBuZWVkcyBzcGxpdHRpbmcNCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc2V4LCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2Uobl9hcnRpY2xlcyA9IHN1bShuKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lICAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIHRpZHlyOjpjb21wbGV0ZShzcGVjaWVzX3NleCwgc3R1ZHlfbW90aXZhdGlvbiwgDQogICAgICAgICAgICAgICAgICBmaWxsID0gbGlzdChuX2FydGljbGVzID0gMCkpICU+JSAgIyBtYWtlIGEgZnVsbCBkZiB3aXRoIGVtcHR5IGNhdGVnb3JpZXMgPSAwDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX3NleCA9IHN1bShuX2FydGljbGVzKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShvdmVyYWxsX3Byb3AgPSBuX2FydGljbGVzL3RvdGFsX3NleCkNCnNleF9zdW1tYXJ5X2FsbCAlPiUgDQogIGd0KCkNCmBgYA0KTGV0J3MgbG9vayBhdCBqdXN0IHRoZSBwcm9wb3J0aW9uIG9mIHRob3NlIGRlZmluZWQgYXMgbWFsZSBhbmQgZmVtYWxlICAgDQoNCmBgYHtyfQ0Kc2V4X21hbGVfZmVtYWxlIDwtICBzZXhfc3VtbWFyeV9hbGwgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHNwZWNpZXNfc2V4ID09ICJGZW1hbGUiIHwgc3BlY2llc19zZXggPT0gIk1hbGUiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX3NleCwgLW92ZXJhbGxfcHJvcCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21hbGVfZmVtYWxlID0gc3VtKG5fYXJ0aWNsZXMpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuX2FydGljbGVzL3RvdGFsX21hbGVfZmVtYWxlKjEwMCwxKSkNCg0Kc2V4X21hbGVfZmVtYWxlICU+JSANCiAgZ3QoKQ0KYGBgDQoNCk1ha2luZyB0aGUgcGxvdCAgIA0KDQpgYGB7ciwgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9Mi41fQ0Kc2V4X29yZGVyIDwtIGMoIkZlbWFsZSIsICJNYWxlIikNCg0KY29sb3JfdGhlbWUgPC0gYygiI2ViNDcyOSIsICIjMWI5MDlhIikNCg0KIyBDYWxjdWxhdGUgY3VtdWxhdGl2ZSBwb3NpdGlvbnMgZm9yIHRleHQgbGFiZWxzDQpzZXhfbWFsZV9mZW1hbGUgPC0gc2V4X21hbGVfZmVtYWxlICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc2V4ID0gZmFjdG9yKHNwZWNpZXNfc2V4LCBsZXZlbHMgPSBzZXhfb3JkZXIpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUNCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzcGVjaWVzX3NleCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShjdW11bGF0aXZlX3BlcmNlbnQgPSBjdW1zdW0ocGVyY2VudCkgLSBwZXJjZW50IC8gMikNCg0KIyBDcmVhdGUgdGhlIHBsb3QNCnNleF9maWcgPC0gc2V4X21hbGVfZmVtYWxlICU+JQ0KICBtdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9IGZjdF9yZWxldmVsKHN0dWR5X21vdGl2YXRpb24sICJCYXNpYyByZXNlYXJjaCIsICJNZWRpY2FsIiwgIkVudmlyb25tZW50YWwiKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBwZXJjZW50LCB4ID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHNwZWNpZXNfc2V4LCBncm91cCA9IHNwZWNpZXNfc2V4KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjkpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHBlcmNlbnQsIDIpLCB5ID0gY3VtdWxhdGl2ZV9wZXJjZW50KSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3JfdGhlbWUsIG5hbWUgPSAiU2V4IikgKyANCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKw0KICBsYWJzKA0KICAgIHggPSAiU3R1ZHkgbW90aXZhdGlvbiIsDQogICAgeSA9ICJQZXJjZW50YWdlIG9mIGFsbCBzcGVjaWVzIGFzc2lnbmVkIHRvIGZlbWFsZSBvciBtYWxlIg0KICApICsNCiAgY29vcmRfZmxpcCgpDQoNCnNleF9maWcNCmBgYA0KDQpTYXZlIHRoZSBmaWd1cmUgICAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoInNwcF9zZXhfZmlnLnBkZiIsIHBsb3QgPSBzZXhfZmlnLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA1KQ0KYGBgDQoNCk5vdyBsZXQncyBsb29rIGF0IHRob3NlIG5vdCBhc3NpZ25lZCB0byBhIHNleCAgIA0KDQpgYGB7cn0NCnNleF9zdW1tYXJ5X2luZm8gPC0gc2V4X3N1bW1hcnlfYWxsICU+JSANCiAgZHBseXI6Om11dGF0ZShzZXhfcmVwb3J0ZWQgPSBpZl9lbHNlKHNwZWNpZXNfc2V4ID09ICJVbmtub3duIG9yIG5vdCBzcGVjaWZpZWQiLCAiTm8iLCAiWWVzIikpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNleF9yZXBvcnRlZCkgJT4lDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obl9hcnRpY2xlcykpDQoNCm5fdG90YWwgPC0gc2V4X3N1bW1hcnlfaW5mbyAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG5fdG90YWwgPSBzdW0obikpICU+JSANCiAgZHBseXI6OnB1bGwobl90b3RhbCkNCg0Kc2V4X3N1bW1hcnlfaW5mbyA8LSBzZXhfc3VtbWFyeV9pbmZvICU+JQ0KICBkcGx5cjo6bXV0YXRlKHByb3AgPSBuL25fdG90YWwpDQpgYGANCg0KDQpIZXJlJ3MgdGhlIHBsb3QgICANCg0KYGBge3IsIGZpZy53aWR0aD0yLjUsIGZpZy5oZWlnaHQ9NX0NCiMgRGVmaW5lIHRoZSBibGFjayBhbmQgZ3JleSBjb2xvciB0aGVtZQ0KYmxhY2tfYW5kX2dyZXkgPC0gYygiI0JDQkVDMCIsICIjNDE0MDQyIikNCg0KeWVzX29yZGVyIDwtIGMoIlllcyIsICJObyIpDQoNCiMgQ2FsY3VsYXRlIGN1bXVsYXRpdmUgcG9zaXRpb25zIGZvciB0ZXh0IGxhYmVscw0Kc2V4X3N1bW1hcnlfaW5mbyA8LSBzZXhfc3VtbWFyeV9pbmZvICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNleF9yZXBvcnRlZCA9IGZhY3RvcihzZXhfcmVwb3J0ZWQsIGxldmVscyA9IHllc19vcmRlcikpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzZXhfcmVwb3J0ZWQpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY3VtdWxhdGl2ZV9wcm9wID0gY3Vtc3VtKHByb3ApIC0gcHJvcCAvIDIpDQoNCnNleF9pbmZvX2ZpZyA8LSBzZXhfc3VtbWFyeV9pbmZvICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNleF9yZXBvcnRlZCA9IGZhY3RvcihzZXhfcmVwb3J0ZWQsIGxldmVscyA9IHllc19vcmRlcikpICU+JSANCiAgZ2dwbG90KGFlcyh5ID0gcHJvcCwgeCA9IDEsIGZpbGwgPSBzZXhfcmVwb3J0ZWQpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQocHJvcCwgMiksIHkgPSBjdW11bGF0aXZlX3Byb3ApLCBjb2xvciA9ICJ3aGl0ZSIpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGJsYWNrX2FuZF9ncmV5LCBuYW1lID0gIlNleCByZXBvcnRlZCIpICsgDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCAgIyBSZW1vdmUgeC1heGlzIHRleHQNCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpICAjIFJlbW92ZSB4LWF4aXMgdGlja3MgDQogICAgICAgICkgKw0KICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlByb3BvcnRpb24gb2YgYWxsIHNwZWNpZXMiDQogICkNCnNleF9pbmZvX2ZpZw0KYGBgDQoNCg0KU2F2ZSB0aGUgZmlndXJlICAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoInNwcF9zZXhfaW5mb19maWcucGRmIiwgcGxvdCA9IHNleF9pbmZvX2ZpZywgd2lkdGggPSAyLjUsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMjIFNwZWNpZXMgc291cmNlDQoNCkJyZWFrZG93biB3aXRob3V0IHVucmVwb3J0ZWQgICANCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodW5pcXVlX3BvcHVsYXRpb25faWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIHNhbXBsaW5nIG9uZSByb3cgcGVyIGFydGljbGUgcGVyIHNwZWNpZXMgKGkuZS4gaWdub3JpbmcgbXVsdGlwbGUgcm93cyBwZXIgYXJ0aWNsZSBmb3IgY29tcG91bmRzKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc291cmNlKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNwZWNpZXNfc291cmNlID0gc3RyX3RyaW0oc3BlY2llc19zb3VyY2UpKSAlPiUNCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3Moc3BlY2llc19zb3VyY2UsIHNlcCA9ICI7IikgJT4lICMgZWFjaCBzcHAgaGFzIG11bHRpcGxlIGhhYml0YXRzIHRoZSBzdHJpbmcgbmVlZHMgc3BsaXR0aW5nDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX3NvdXJjZSkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKG5fYXJ0aWNsZXMgPSBzdW0obiksIC5ncm91cHMgPSAnZHJvcCcpICU+JSAgIyBub3cgYSBzdW0gZm9yIGVhY2ggaGFiaXRhdA0KICB0aWR5cjo6Y29tcGxldGUoc3BlY2llc19zb3VyY2UsIA0KICAgICAgICAgICAgICAgICAgZmlsbCA9IGxpc3Qobl9hcnRpY2xlcyA9IDApKSAlPiUgICMgbWFrZSBhIGZ1bGwgZGYgd2l0aCBlbXB0eSBjYXRlZ29yaWVzID0gMA0KICBkcGx5cjo6ZmlsdGVyKHNwZWNpZXNfc291cmNlICE9ICJOb3QgcmVwb3J0ZWQiKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX3NvdXJjZSA9IHN1bShuX2FydGljbGVzKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShvdmVyYWxsX3BlcmNlbnQgPSByb3VuZChuX2FydGljbGVzL3RvdGFsX3NvdXJjZSoxMDAsIDEpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2Mob3ZlcmFsbF9wZXJjZW50KSkgJT4lIA0KICBndCgpDQpgYGANCg0KTGV0J3MgbG9vayBhdCB3aGVyZSB0aGUgYW5pbWFscyB3ZXJlIHNvdXJjZWQgZm9yIGFydGljbGVzIGluIHRoZSBFSVBBQUIgZGF0YWJhc2UgICANCg0KYGBge3J9DQpzb3VyY2Vfc3VtbWFyeV9hbGwgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgIyBzYW1wbGluZyBvbmUgcm93IHBlciBhcnRpY2xlIHBlciBzcGVjaWVzIChpLmUuIGlnbm9yaW5nIG11bHRpcGxlIHJvd3MgcGVyIGFydGljbGUgZm9yIGNvbXBvdW5kcykNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBzcGVjaWVzX3NvdXJjZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX3NvdXJjZSA9IHN0cl90cmltKHNwZWNpZXNfc291cmNlKSkgJT4lDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKHNwZWNpZXNfc291cmNlLCBzZXAgPSAiOyIpICU+JSAjIGVhY2ggc3BwIGhhcyBtdWx0aXBsZSBoYWJpdGF0cyB0aGUgc3RyaW5nIG5lZWRzIHNwbGl0dGluZw0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zb3VyY2UsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShuX2FydGljbGVzID0gc3VtKG4pLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgICMgbm93IGEgc3VtIGZvciBlYWNoIGhhYml0YXQNCiAgdGlkeXI6OmNvbXBsZXRlKHNwZWNpZXNfc291cmNlLCBzdHVkeV9tb3RpdmF0aW9uLCANCiAgICAgICAgICAgICAgICAgIGZpbGwgPSBsaXN0KG5fYXJ0aWNsZXMgPSAwKSkgJT4lICAjIG1ha2UgYSBmdWxsIGRmIHdpdGggZW1wdHkgY2F0ZWdvcmllcyA9IDANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfc291cmNlID0gc3VtKG5fYXJ0aWNsZXMpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG92ZXJhbGxfcGVyY2VudCA9IHJvdW5kKG5fYXJ0aWNsZXMvdG90YWxfc291cmNlKjEwMCwxKSkNCg0Kc291cmNlX3N1bW1hcnlfYWxsICU+JSANCiAgZ3QoKQ0KYGBgDQoNCk9ubHkgdGhvc2Ugd2l0aCByZXBvcnRlZCBzb3VyY2UgICANCg0KYGBge3J9DQpzb3VyY2Vfb3JkZXIgPC0gYygiV2lsZCBjb2xsZWN0ZWQiLCAiTGFiIHN0b2NrIGZyb20gd2lsZCBwb3B1bGF0aW9uIiwgIkxhYiBzdG9jayBvZiB1bmRpc2Nsb3NlZCBvcmlnaW4iLCANCiAgICAgICAgICAgICAgICAgICJMYWIgc3RvY2sgZnJvbSBjb21tZXJjaWFsIHN1cHBsaWVyIiwgIkNvbW1lcmNpYWwgc3VwcGxpZXIgb3IgZmlzaCBmYXJtIikNCg0Kc291cmNlX3N1bW1hcnkgPC0gc291cmNlX3N1bW1hcnlfYWxsICU+JSANCiAgZHBseXI6OmZpbHRlcihzcGVjaWVzX3NvdXJjZSAhPSAiTm90IHJlcG9ydGVkIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHNwZWNpZXNfc291cmNlLCBzdHVkeV9tb3RpdmF0aW9uLCBuX2FydGljbGVzKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfcmVwb3J0ZWQgPSBzdW0obl9hcnRpY2xlcykpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG5fYXJ0aWNsZXMvdG90YWxfcmVwb3J0ZWQqMTAwLDEpLA0KICAgICAgICAgICAgICAgIHNwZWNpZXNfc291cmNlID0gZmFjdG9yKHNwZWNpZXNfc291cmNlLCBsZXZlbHMgPSBzb3VyY2Vfb3JkZXIpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKHNwZWNpZXNfc291cmNlKQ0KDQpzb3VyY2Vfc3VtbWFyeSAlPiUgDQogIGd0KCkNCmBgYA0KDQpBIGZpZ3VyZSB3aXRoIHRoZSBzYW1lIGluZm9ybWF0aW9uICAgDQoNCmBgYHtyLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD0yLjV9DQpzb3VyY2Vfb3JkZXIgPC0gYygiV2lsZCBjb2xsZWN0ZWQiLCAiTGFiIHN0b2NrIGZyb20gd2lsZCBwb3B1bGF0aW9uIiwgIkxhYiBzdG9jayBvZiB1bmRpc2Nsb3NlZCBvcmlnaW4iLCANCiAgICAgICAgICAgICAgICAgICJMYWIgc3RvY2sgZnJvbSBjb21tZXJjaWFsIHN1cHBsaWVyIiwgIkNvbW1lcmNpYWwgc3VwcGxpZXIgb3IgZmlzaCBmYXJtIikNCg0KIyBEZWZpbmUgdGhlIGJsYWNrIGFuZCBncmV5IGNvbG9yIHRoZW1lDQpjb2xvcl90aGVtZSA8LSBjKCIjNjA3QzNCIiwgIiNBN0QyNzEiLCAiIzZCNkU3MCIsICIjQTY2RUFGIiwgIiM2MTM0NkIiKQ0KDQojIENhbGN1bGF0ZSBjdW11bGF0aXZlIHBvc2l0aW9ucyBmb3IgdGV4dCBsYWJlbHMNCnNvdXJjZV9zdW1tYXJ5IDwtIHNvdXJjZV9zdW1tYXJ5ICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lDQogIGRwbHlyOjphcnJhbmdlKGRlc2Moc3BlY2llc19zb3VyY2UpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY3VtdWxhdGl2ZV9wZXJjZW50ID0gY3Vtc3VtKHBlcmNlbnQpIC0gcGVyY2VudCAvIDUpDQoNCiMgQ3JlYXRlIHRoZSBwbG90DQpzb3VyY2VfZmlnIDwtIHNvdXJjZV9zdW1tYXJ5ICU+JQ0KICBtdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9IGZjdF9yZWxldmVsKHN0dWR5X21vdGl2YXRpb24sICJCYXNpYyByZXNlYXJjaCIsICJNZWRpY2FsIiwgIkVudmlyb25tZW50YWwiKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBwZXJjZW50LCB4ID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHNwZWNpZXNfc291cmNlLCBncm91cCA9IHNwZWNpZXNfc291cmNlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjkpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHBlcmNlbnQsIDIpLCB5ID0gY3VtdWxhdGl2ZV9wZXJjZW50KSwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMykgKyANCiBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcl90aGVtZSwgbmFtZSA9ICJMaWZlIHN0YWdlIikgKyANCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikgKw0KICBsYWJzKA0KICAgIHggPSAiU3R1ZHkgbW90aXZhdGlvbiIsDQogICAgeSA9ICJQcm9wb3J0aW9uIG9mIGFsbCBzcGVjaWVzIHdpdGggYSBkZXNjcmliZWQgc291cmNlIg0KICApICsNCiAgY29vcmRfZmxpcCgpDQoNCnNvdXJjZV9maWcNCmBgYA0KDQpTYXZlIHRoZSBmaWd1cmUgICANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJzcHBfc291cmNlX2ZpZy5wZGYiLCBwbG90ID0gc291cmNlX2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkNCmBgYA0KDQpOb3cgbGV0J3MgbG9vayBhdCB0aG9zZSBub3QgYXNzaWduZWQgYSBzb3VyY2UgICANCg0KYGBge3J9DQpzb3VyY2Vfc3VtbWFyeV9pbmZvIDwtIHNvdXJjZV9zdW1tYXJ5X2FsbCAlPiUgDQogIGRwbHlyOjptdXRhdGUoc291cmNlX3JlcG9ydGVkID0gaWZfZWxzZShzcGVjaWVzX3NvdXJjZSA9PSAiTm90IHJlcG9ydGVkIiwgIk5vIiwgIlllcyIpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzb3VyY2VfcmVwb3J0ZWQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX2FydGljbGVzKSkNCg0Kbl90b3RhbCA8LSBzb3VyY2Vfc3VtbWFyeV9pbmZvICU+JSANCiAgZHBseXI6OnJlZnJhbWUobl90b3RhbCA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6cHVsbChuX3RvdGFsKQ0KICANCnNvdXJjZV9zdW1tYXJ5X2luZm8gPC0gc291cmNlX3N1bW1hcnlfaW5mbyAlPiUgDQogIGRwbHlyOjptdXRhdGUocHJvcCA9IG4vbl90b3RhbCkNCmBgYA0KDQpIZXJlJ3MgdGhlIHBsb3QgICANCg0KYGBge3IsIGZpZy53aWR0aD0yLjUsIGZpZy5oZWlnaHQ9NX0NCiMgRGVmaW5lIHRoZSBibGFjayBhbmQgZ3JleSBjb2xvciB0aGVtZQ0KYmxhY2tfYW5kX2dyZXkgPC0gYygiI0JDQkVDMCIsICIjNDE0MDQyIikNCg0KeWVzX29yZGVyIDwtIGMoIlllcyIsICJObyIpDQoNCiMgQ2FsY3VsYXRlIGN1bXVsYXRpdmUgcG9zaXRpb25zIGZvciB0ZXh0IGxhYmVscw0Kc291cmNlX3N1bW1hcnlfaW5mbyA8LSBzb3VyY2Vfc3VtbWFyeV9pbmZvICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNvdXJjZV9yZXBvcnRlZCA9IGZhY3Rvcihzb3VyY2VfcmVwb3J0ZWQsIGxldmVscyA9IHllc19vcmRlcikpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzb3VyY2VfcmVwb3J0ZWQpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY3VtdWxhdGl2ZV9wcm9wID0gY3Vtc3VtKHByb3ApIC0gcHJvcCAvIDIpDQoNCnNvdXJjZV9pbmZvX2ZpZyA8LSBzb3VyY2Vfc3VtbWFyeV9pbmZvICU+JQ0KICBkcGx5cjo6bXV0YXRlKHNvdXJjZV9yZXBvcnRlZCA9IGZhY3Rvcihzb3VyY2VfcmVwb3J0ZWQsIGxldmVscyA9IHllc19vcmRlcikpICU+JSANCiAgZ2dwbG90KGFlcyh5ID0gcHJvcCwgeCA9IDEsIGZpbGwgPSBzb3VyY2VfcmVwb3J0ZWQpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuOSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQocHJvcCwgMiksIHkgPSBjdW11bGF0aXZlX3Byb3ApLCBjb2xvciA9ICJ3aGl0ZSIpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGJsYWNrX2FuZF9ncmV5LCBuYW1lID0gIlNvdXJjZSByZXBvcnRlZCIpICsgDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCAgIyBSZW1vdmUgeC1heGlzIHRleHQNCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpICAjIFJlbW92ZSB4LWF4aXMgdGlja3MgDQogICAgICAgICkgKw0KICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlByb3BvcnRpb24gb2YgYWxsIHNwZWNpZXMiDQogICkNCnNvdXJjZV9pbmZvX2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJzcHBfc291cmNlX2luZm9fZmlnLnBkZiIsIHBsb3QgPSBzb3VyY2VfaW5mb19maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMTApDQpgYGANCg0KDQojIyBDb21wb3VuZHMgDQoNCiMjIyBOdW1iZXIgb2YgY29tcG91bmRzIGluIGRhdGFiYXNlDQoNClRoZXJlIGFyZSA0MjYgZGlzdGluY3QgY29tcG91bmRzIGluIHRoZSBkYXRhYmFzZSAgIA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChjb21wb3VuZF9uYW1lKSAlPiUgDQogIG5yb3coKQ0KYGBgDQoNCg0KIyMjIyBOdW1iZXIgb2YgY29tcG91bmRzIHBlciBzdHVkeQ0KDQpgYGB7cn0NCmFydGljbGVfbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZGlzdGluY3QoYXJ0aWNsZV9pZCkgJT4lIA0KICBucm93KC4pDQoNCmNvbXBvdW5kX25fc3VtbWFyeSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX24pICU+JQ0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpLA0KICAgICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZCgobi9hcnRpY2xlX24pKjEwMCwxKSkNCg0KY29tcG91bmRfbl9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTApICU+JSAgIzEwIG1vc3QgY29tbW9uIG51bWJlciBvZiBjb21wb3VuZHMNCiAgZ3QoKQ0KYGBgDQoNCkhvdyBtYW55IHVzZWQgbW9yZSB0aGVuIDUgIA0KDQpgYGB7cn0NCmNvbXBvdW5kX25fc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfbiA+IDUpICU+JSANCiAgcmVmcmFtZShuID0gc3VtKG4pLA0KICAgICAgICAgIHBlcmNlbnQgPSByb3VuZCgobi9hcnRpY2xlX24pKjEwMCwxKSkgJT4lIA0KICBndCgpDQpgYGANCg0KQnkgbW90aXZhdGlvbiBzdW1tYXJ5IGRhdGEgZnJhbWUgICANCg0KYGBge3J9DQpjb21wb3VuZF9uX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9uLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUNCiAgZHBseXI6OnN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShjb21wb3VuZF9uLCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChuID0gMCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHByb3BfbW90aXZhdGlvbiA9IG4vdG90YWxfbW90aXZhdGlvbikNCmBgYA0KDQojIyMjIEZpZyBTNA0KDQpgYGB7cn0NCiMgRGVmaW5lIHRoZSBjb2xvdXIgcGFsZXR0ZQ0KbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUgPC0gYygiIzYwQkQ2QyIsICIjRDM1OUExIiwgIiMzQzgyQzQiKSAjIE1ha2luZyBjb2xvdXIgdGhlbWUgdG8gYXBwbHkgdG8gcGxvdA0KDQpjb21wb3VuZF9uX29kZXIgPC0gYygxOjksICI+MTAiKQ0KDQpjb21wb3VuZF9uX2ZpZyA8LSBjb21wb3VuZF9uX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgIGNvbXBvdW5kX24gPSBhcy5jaGFyYWN0ZXIoaWZfZWxzZShjb21wb3VuZF9uID4gMTAsIDEwLCBjb21wb3VuZF9uKSksICMgR3JvdXBpbmcgY2FzZXMgYWJvdmUgMTANCiAgICBjb21wb3VuZF9uID0gaWZfZWxzZShjb21wb3VuZF9uID09ICIxMCIsICI+MTAiLCBjb21wb3VuZF9uKQ0KICAgICkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfbiwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY29tcG91bmRfbiA9IGZhY3Rvcihjb21wb3VuZF9uLCBsZXZlbHMgPSBjb21wb3VuZF9uX29kZXIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kX24sIHk9biwgY29sb3VyID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24sIGdyb3VwID0gc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4xKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSwgdmp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIsIHBvc2l0aW9uID0gIHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIk51bWJlciBvZiBzdHVkaWVzIg0KICApICsNCiAgIHRoZW1lKCkNCg0KY29tcG91bmRfbl9maWcNCmBgYA0KDQpTYXZlIHRoZSBmaWd1cmUgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGdnc2F2ZSgiY29tcF9jb21wb3VuZF9uX2ZpZy5wZGYiLCBwbG90ID0gY29tcG91bmRfbl9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMjIFRoZXJwdXRpYyBkaXZlcnNpdHkgaW4gdGhlIGRhdGFiYXNlDQoNCkZpcnN0IGxldHMgc2VlIGhvdyBtYW55IGNvbXBvdW5kcyBoYXZlIGFuIEFUQyBjbGFzc2lmaWNhdGlvbi4gICANCg0KMzA1IG91dCBvZiA0MjYgKDcxLjYlKSAgIA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9uYW1lKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgIyBzYW1wbGluZyBvbmUgcm93IHBlciBhcnRpY2xlIHBlciBzcGVjaWVzIChpLmUuIGlnbm9yaW5nIG11bHRpcGxlIHJvd3MgcGVyIGFydGljbGUgZm9yIGNvbXBvdW5kcykNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9hdGNfYm9vbGVhbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbGVuZ3RoKGNvbXBvdW5kX2F0Y19ib29sZWFuKSkgJT4lIA0KICBndCgpDQpgYGANCg0KDQojIyMjIEFUQyBsZXZlbCAxDQoNCkxldCdzIHNlZW0gaG93IG1hbnkgY2xhc3NlcyB0aGVyZSBhcmUgYXQgdGhlIEFuYXRvbWljYWwgVGhlcmFwZXV0aWMgQ2hlbWljYWwgKEFUQykgbGV2ZWwgMSAgIA0KDQpUaGVyZSBhcmUgMTQgY2xhc3NlcyBhdCB0aGUgMXN0IEFUQyBsZXZlbCAodGhlIGhpZ2hlc3QgY2xhc3Mgb2YgdGhlIEFUQykuIFRoaXMgaXMgZXZlciBjbGFzcyBhdCB0aGUgZmlyc3QgbGV2ZWwgICANCg0KYGBge3J9DQpuX2NvbXBvdW5kX2F0YyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX2F0Y19ib29sZWFuID09ICJZZXMiKSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChjb21wb3VuZF9uYW1lKSAlPiUgDQogIG5yb3coLikNCg0KY29tcG91bmRfQVRDX0wxX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX25hbWUpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIHNhbXBsaW5nIG9uZSByb3cgcGVyIGFydGljbGUgcGVyIHNwZWNpZXMgKGkuZS4gaWdub3JpbmcgbXVsdGlwbGUgcm93cyBwZXIgYXJ0aWNsZSBmb3IgY29tcG91bmRzKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9hdGNfYm9vbGVhbiA9PSAiWWVzIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfYXRjX2xldmVsXzEpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoY29tcG91bmRfYXRjX2xldmVsXzEgPSBzdHJfdHJpbShjb21wb3VuZF9hdGNfbGV2ZWxfMSkpICU+JQ0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhjb21wb3VuZF9hdGNfbGV2ZWxfMSwgc2VwID0gIjsiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9hdGNfbGV2ZWxfMSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pLA0KICAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9uX2NvbXBvdW5kX2F0YyoxMDAsMSksDQogICAgICAgICAgICAgICAgIG1lYXN1cmUgPSAiY29tcG91bmRzIikgJT4lIA0KICBhcnJhbmdlKGRlc2MobikpDQoNCmNvbXBvdW5kX0FUQ19MMV9zdW1tYXJ5ICU+JSANCiAgZ3QoKQ0KYGBgDQoNCk5vdyB3ZSB3aWxsIG1ha2UgYSBzaW1pbGFyIGRhdGEgZmlsZSB0byBsb29rIGF0IHRoZSBvdmVyYWxsIHVzZSBpbiB0aGUgZGF0YWJhc2UgYXQgZWFjaCBBVEMgbGV2ZWwgMSAgIA0KDQpgYGB7cn0NCm5fZGF0YV9hdGMgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9hdGNfYm9vbGVhbiA9PSAiWWVzIikgJT4lIA0KICBucm93KC4pDQoNCmNvbXBvdW5kX0FUQ19MMV9kYXRhX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9hdGNfYm9vbGVhbiA9PSAiWWVzIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfYXRjX2xldmVsXzEpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoY29tcG91bmRfYXRjX2xldmVsXzEgPSBzdHJfdHJpbShjb21wb3VuZF9hdGNfbGV2ZWxfMSkpICU+JQ0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhjb21wb3VuZF9hdGNfbGV2ZWxfMSwgc2VwID0gIjsiKSAlPiUgIyBlYWNoIHNwcCBoYXMgbXVsdGlwbGUgaGFiaXRhdHMgdGhlIHN0cmluZyBuZWVkcyBzcGxpdHRpbmcNCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX2F0Y19sZXZlbF8xKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obiksDQogICAgICAgICAgICAgICAgIHBlcmNlbnQgPXJvdW5kKG4vbl9kYXRhX2F0YyoxMDAsMSksDQogICAgICAgICAgICAgICAgIG1lYXN1cmUgPSAiZGF0YSIpICU+JSAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIGFycmFuZ2UoZGVzYyhwZXJjZW50KSkNCmNvbXBvdW5kX0FUQ19MMV9kYXRhX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1tZWFzdXJlKSAlPiUgDQogIGd0KCkNCmBgYA0KDQoNCmBgYHtyfQ0KQVRDX0wxX3N1bW1hcnkgPC0gY29tcG91bmRfQVRDX0wxX3N1bW1hcnkgJT4lIA0KICByYmluZCguLCBjb21wb3VuZF9BVENfTDFfZGF0YV9zdW1tYXJ5KSAlPiUgDQogIGRwbHlyOjptdXRhdGUodmFsdWUgPSBpZl9lbHNlKG1lYXN1cmUgPT0gImNvbXBvdW5kcyIsIG4sIHBlcmNlbnQpKQ0KYGBgDQoNCiMjIyMgRmlnIFM1DQoNClRoaXMgcGxvdCBzaG93cyB0aGUgbnVtYmVyIG9mIGRpZmZlcmVudCBjb21wb3VuZHMgaW4gZWFjaCBBVEMgY2xhc3NpZmljYXRpb24gYXMgd2VsbCBhcyB0aGUgdG90YWwgcHJvcG9ydGlvbiBvZiBkYXRhIGl0IG1ha2VzIHVwIA0KDQpgYGB7cn0NCm1lYXN1cmVfY29sb3VyX3RoZW1lIDwtIGMoImJsYWNrIiwgImdyZXkiKSAjIE1ha2luZyBjb2xvdXIgdGhlbWUgdG8gYXBwbHkgdG8gcGxvdA0KDQojIE1ha2luZyBhIGxpc3Qgb2YgYWN0IG5hbWVzIGluIHRoZSBvcmRlciB0aGF0IHdlIHdhbnQgdGhlbSBpbiB0aGUgcGxvdCANCmxldmVsXzFfb3JkZXIgPC0gQVRDX0wxX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKG1lYXN1cmUgPT0gImRhdGEiKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKHZhbHVlKSAlPiUgDQogIGRwbHlyOjpwdWxsKGNvbXBvdW5kX2F0Y19sZXZlbF8xKQ0KDQojIE1ha2luZyB0aGUgcGxvdA0KYXRjX2xldmVsXzFfZmlnIDwtIEFUQ19MMV9zdW1tYXJ5ICU+JSANCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9hdGNfbGV2ZWxfMSA9IGZhY3Rvcihjb21wb3VuZF9hdGNfbGV2ZWxfMSwgbGV2ZWxzID0gbGV2ZWxfMV9vcmRlcikpICU+JSANCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kX2F0Y19sZXZlbF8xLCB5PXZhbHVlLCBjb2xvdXIgPSBtZWFzdXJlLCBmaWxsID0gbWVhc3VyZSwgZ3JvdXAgPSBtZWFzdXJlKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjIsIGNvbG91ciA9IE5BKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSB2YWx1ZSksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siLCBwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtZWFzdXJlX2NvbG91cl90aGVtZSwgbmFtZSA9ICJWYWx1ZSB0eXBlIikgKw0KICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbWVhc3VyZV9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiVmFsdWUgdHlwZSIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgIG5hbWUgPSAiTnVtYmVyIG9mIGRpc3RpbmN0IGNvbXBvdW5kcyIsDQogICAgc2VjLmF4aXMgPSBzZWNfYXhpcyh+IC4gLCBuYW1lID0gIlRvdGFsIHByb3BvcnRpb24gb2YgdGhlIGRhdGFiYXNlIikgIyBBZGp1c3Qgc2NhbGluZyBpZiBuZWVkZWQNCiAgKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIk51bWJlciBvZiBkaXN0aWN0IHNwZWNpZXMgaW4gdGhlIGRhdGFiYXNlIg0KICApICsNCiAgIHRoZW1lKCkNCg0KYXRjX2xldmVsXzFfZmlnDQpgYGANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoImNvbXBfYXRjX2xldmVsXzFfZmlnLnBkZiIsIHBsb3QgPSBhdGNfbGV2ZWxfMV9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDEwKQ0KYGBgDQoNCiMjIyMgQVRDIGxldmVsIDMNCg0KTGV0J3Mgc2VlbSBob3cgbWFueSBjbGFzc2VzIHRoZXJlIGFyZSBhdCB0aGUgQW5hdG9taWNhbCBUaGVyYXBldXRpYyBDaGVtaWNhbCAoQVRDKSBsZXZlbCAzICAgDQoNClRoZXJlIGFyZSAxMzEgZGlzdGluY3QgY2xhc3NlcywgSSBhbSBjcmVhdGluZyBhIHRhYmxlIHdpdGggdGhlIHRvcCAxNS4gICANCg0KYGBge3J9DQpuX2NvbXBvdW5kX2F0YyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX2F0Y19ib29sZWFuID09ICJZZXMiKSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChjb21wb3VuZF9uYW1lKSAlPiUgDQogIG5yb3coLikNCg0KY29tcG91bmRfQVRDX0wzX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX25hbWUpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSAjIHNhbXBsaW5nIG9uZSByb3cgcGVyIGFydGljbGUgcGVyIHNwZWNpZXMgKGkuZS4gaWdub3JpbmcgbXVsdGlwbGUgcm93cyBwZXIgYXJ0aWNsZSBmb3IgY29tcG91bmRzKQ0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9hdGNfYm9vbGVhbiA9PSAiWWVzIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfYXRjX2xldmVsXzMpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoY29tcG91bmRfYXRjX2xldmVsXzMgPSBzdHJfdHJpbShjb21wb3VuZF9hdGNfbGV2ZWxfMykpICU+JQ0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhjb21wb3VuZF9hdGNfbGV2ZWxfMywgc2VwID0gIjsiKSAlPiUgIyBlYWNoIHNwcCBoYXMgbXVsdGlwbGUgaGFiaXRhdHMgdGhlIHN0cmluZyBuZWVkcyBzcGxpdHRpbmcNCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX2F0Y19sZXZlbF8zKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obiksDQogICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL25fY29tcG91bmRfYXRjKjEwMCwxKSwNCiAgICAgICAgICAgICAgICAgbWVhc3VyZSA9ICJjb21wb3VuZHMiKSAlPiUgIyBub3cgYSBzdW0gZm9yIGVhY2ggaGFiaXRhdA0KICBhcnJhbmdlKGRlc2MobikpDQoNCmNvbXBvdW5kX0FUQ19MM19zdW1tYXJ5ICU+JSANCiAgZHBseXI6OnNlbGVjdCgtbWVhc3VyZSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToxNSkgJT4lICMgb25seSB0aGUgZmlyc3QgMTUNCiAgZ3QoKQ0KYGBgDQoNCk5vdyB3ZSB3aWxsIG1ha2UgYSBzaW1pbGFyIGRhdGEgZmlsZSB0byBsb29rIGF0IHRoZSBvdmVyYWxsIHVzZSBpbiB0aGUgZGF0YWJhc2UgYXQgZWFjaCBBVEMgbGV2ZWwgMy4NCg0KQmVsb3cgSSBtYWtlIGEgdGFibGUgd2l0aCB0aGUgdG9wIDE1ICAgDQoNCmBgYHtyfQ0Kbl9kYXRhX2F0YyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX2F0Y19ib29sZWFuID09ICJZZXMiKSAlPiUgDQogIG5yb3coLikNCg0KY29tcG91bmRfQVRDX0wzX2RhdGFfc3VtbWFyeSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX2F0Y19ib29sZWFuID09ICJZZXMiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9hdGNfbGV2ZWxfMykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9hdGNfbGV2ZWxfMyA9IHN0cl90cmltKGNvbXBvdW5kX2F0Y19sZXZlbF8zKSkgJT4lDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKGNvbXBvdW5kX2F0Y19sZXZlbF8zLCBzZXAgPSAiOyIpICU+JSAjIGVhY2ggc3BwIGhhcyBtdWx0aXBsZSBoYWJpdGF0cyB0aGUgc3RyaW5nIG5lZWRzIHNwbGl0dGluZw0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfYXRjX2xldmVsXzMpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSwNCiAgICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vbl9kYXRhX2F0YyoxMDAsMSksDQogICAgICAgICAgICAgICAgIG1lYXN1cmUgPSAiZGF0YSIpICU+JSAjIG5vdyBhIHN1bSBmb3IgZWFjaCBoYWJpdGF0DQogIGFycmFuZ2UoZGVzYyhwZXJjZW50KSkNCg0KY29tcG91bmRfQVRDX0wzX2RhdGFfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLW1lYXN1cmUpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTUpICU+JSANCiAgZ3QoKQ0KYGBgDQpIZXJlIHdlIG1ha2UgYSBuZXcgY29sdW1uIGNhbGxlZCB2YWx1ZSB3aGVyZSB3ZSBjb21iaW5lZCB0aGUgY291bnQgb2YgZGlzdGluY3QgY29tcG91bmRzIGFuZCBwcm9wb3J0aW9uIG9mIGRhdGEgICANCg0KYGBge3J9DQpBVENfTDNfc3VtbWFyeSA8LSBjb21wb3VuZF9BVENfTDNfc3VtbWFyeSAlPiUgDQogIHJiaW5kKC4sIGNvbXBvdW5kX0FUQ19MM19kYXRhX3N1bW1hcnkpICU+JSANCiAgZHBseXI6Om11dGF0ZSh2YWx1ZSA9IGlmX2Vsc2UobWVhc3VyZSA9PSAiY29tcG91bmRzIiwgbiwgcGVyY2VudCkpDQpgYGANCg0KIyMjIyBGaWcgNGENCg0KVGhpcyBwbG90IHNob3dzIHRoZSBudW1iZXIgb2YgZGlmZmVyZW50IGNvbXBvdW5kcyBpbiBlYWNoIEFUQyBjbGFzc2lmaWNhdGlvbiBhcyB3ZWxsIGFzIHRoZSB0b3RhbCBwcm9wb3J0aW9uIG9mIGRhdGEgaXQgbWFrZXMgdXAuIFRoaXMgaXMgZG9uZSBmb3Igb25seSB0aGUgMTUgbW9zdCBjb21tb25seSB1c2VkIGdyb3Vwcy4gIA0KDQpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KbWVhc3VyZV9jb2xvdXJfdGhlbWUgPC0gYygiYmxhY2siLCAiZ3JleSIpICMgTWFraW5nIGNvbG91ciB0aGVtZSB0byBhcHBseSB0byBwbG90DQoNCiMgTWFraW5nIGEgbGlzdCBvZiBhY3QgbmFtZXMgaW4gdGhlIG9yZGVyIHRoYXQgd2Ugd2FudCB0aGVtIGluIHRoZSBwbG90IA0KbGV2ZWxfM19vcmRlcl90b3BfMTUgPC0gQVRDX0wzX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKG1lYXN1cmUgPT0gImRhdGEiKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2ModmFsdWUpKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjE1KSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2ModmFsdWUpKSAlPiUNCiAgZHBseXI6OnB1bGwoY29tcG91bmRfYXRjX2xldmVsXzMpDQoNCiMgTWFraW5nIHRoZSBwbG90DQphdGNfbGV2ZWxfM19maWcgPC0gQVRDX0wzX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX2F0Y19sZXZlbF8zICVpbiUgbGV2ZWxfM19vcmRlcl90b3BfMTUpICU+JSANCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9hdGNfbGV2ZWxfMyA9IGZhY3Rvcihjb21wb3VuZF9hdGNfbGV2ZWxfMywgbGV2ZWxzID0gbGV2ZWxfM19vcmRlcl90b3BfMTUpKSAlPiUgDQogIGdncGxvdChhZXMoeD1jb21wb3VuZF9hdGNfbGV2ZWxfMywgeT12YWx1ZSwgZmlsbCA9IG1lYXN1cmUsIGNvbG91ciA9IG1lYXN1cmUsIA0KICAgICAgICAgICAgIGdyb3VwID0gbWVhc3VyZSkpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCB3aWR0aCA9IDAuMiwgY29sb3VyID0gTkEsKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCBzaXplID0gMykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdmFsdWUpLCB2anVzdD0tMC42LCBzaXplPTMuNSwgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1lYXN1cmVfY29sb3VyX3RoZW1lLCBuYW1lID0gIlZhbHVlIHR5cGUiLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkNvbXBvdW5kcyAobikiLCAiUGVyY2VudGFnZSBvZiBkYXRhIikpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbWVhc3VyZV9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiVmFsdWUgdHlwZSIsDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQ29tcG91bmRzIChuKSIsICJQZXJjZW50YWdlIG9mIGRhdGEiKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgbmFtZSA9ICJEaXN0aW5jdCBjb21wb3VuZHMiLA0KICAgIGxpbWl0cyA9IGMoMCwgMzApLCAgICAgICAgICAgICAgICAgICAjIFNldCB0aGUgcmFuZ2Ugb2YgeS1heGlzDQogICAgYnJlYWtzID0gYygwLCAxMCwgMjAsIDMwKSwgICAgICAgICAgICMgU2V0IHRoZSBsYWJlbHMgYXQgMCwgMTAsIDIwLCAzMA0KICAgIHNlYy5heGlzID0gc2VjX2F4aXMofiAuICwgbmFtZSA9ICJQZXJjZW50YWdlIG9mIGRhdGFiYXNlIikgIyBBZGp1c3Qgc2NhbGluZyBpZiBuZWVkZWQNCiAgKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIiINCiAgKSArDQogICB0aGVtZSgNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksICAgICAgICAgICMgQ2hhbmdlIHktYXhpcyBsYWJlbHMgc2l6ZQ0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xLCBzaXplID0gOCksICMgQ2hhbmdlIHgtYXhpcyBsYWJlbHMgb3JpZW50YXRpb24NCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwgICAgICAgICAjIENoYW5nZSBsZWdlbmQgdGl0bGUgc2l6ZSBpZiBuZWVkZWQNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApICANCiAgICkNCg0KYXRjX2xldmVsXzNfZmlnDQpgYGANCg0KU2F2ZSB0aGUgZmlndXJlICANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJhdGNfbGV2ZWxfM19maWcucGRmIiwgcGxvdCA9IGF0Y19sZXZlbF8zX2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSkNCmBgYA0KDQoNCiMjIyBNb3N0IGNvbW1vbiBjb21wb3VuZHMgDQoNCk92ZXJhbGwgdGhlIG1vc3QgY29tbW9uIGNvbXBvdW5kcyBhcmUgRmx1b3hldGluZSwgRGlhemVwYW0gYW5kIDE3LWFscGhhLWV0aGlueWxlc3RyYWRpb2wgICAgDQoNCkJlbG93IGlzIGEgdGFibGUgb2YgdGhlIHRvcCAxNSBjb21wb3VuZHMgICANCg0KYGBge3J9DQpuX3JvdyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBucm93KC4pDQoNCmNvbXBvdW5kX3VzZSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfbmFtZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShwcm9wID0gbi9uX3JvdykgJT4lDQogIGFycmFuZ2UoZGVzYyhwcm9wKSkNCg0KY29tcG91bmRfdXNlICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTUpICU+JSANCiAgZ3QoKQ0KYGBgDQpMZXQncyBzZWUgd2hhdCB0aGUgbnVtYmVycyBhcmUgZm9yIGVhY2ggbW90aXZhdGlvbiwgYnV0IGxldCdzIGFsc28gbWFpbnRhaW4gdGhlIG92ZXJhbGwgbnVtYmVycyBzbyB3ZSBjYW4gYWRkIGl0IHRvIHRoZSBmaWd1cmUgICAgDQoNCmBgYHtyfQ0Kbl9yb3cgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgbnJvdyguKQ0KDQpjb21wb3VuZF91c2VfbW90aXZhdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbiwgY29tcG91bmRfbmFtZSkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKG4gPSBuKCksIC5ncm91cHMgPSAnZHJvcCcpICU+JQ0KICB0aWR5cjo6Y29tcGxldGUoY29tcG91bmRfbmFtZSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QobiA9IDApKSAjIE1ha2luZyBzdXJlIHdlIGhhdmUgYSBjb21wbGV0ZSBkYXRhZnJhbWUNCg0KY29tcG91bmRfdXNlX21vdGl2YXRpb24gPC0gY29tcG91bmRfdXNlICU+JSANCiAgZHBseXI6OnNlbGVjdCgtcHJvcCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiQWxsIikgJT4lIA0KICByYmluZCguLCBjb21wb3VuZF91c2VfbW90aXZhdGlvbikNCmBgYA0KDQpUaGUgdG9wIDEwIGJhc2VkIG9uIGVhY2ggc3R1ZHkgbW90aXZhdGlvbiBhcyB3ZWxsIGFzIHRoZSBvdmVyYWxsIHRvdGFsICAgICANCg0KYGBge3J9DQp0b3BfMTBfY29tcF9hbGxfZmlnIDwtIGNvbXBvdW5kX3VzZV9tb3RpdmF0aW9uICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJBbGwiKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTApICU+JSANCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9uYW1lID0gZmN0X3Jlb3JkZXIoY29tcG91bmRfbmFtZSwgbikpICU+JSANCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kX25hbWUsIHk9bikpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjEsIGNvbG91ciA9IE5BLCBmaWxsID0gImdyZXkiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG91ciA9ICJncmV5IiwgZmlsbCA9ICJncmV5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgICB0aXRsZSA9ICJBbGwiLA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlRvdGFsIHVzZSBpbiB0aGUgZGF0YWJhc2UiDQogICkgKw0KICAgdGhlbWUoDQogICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKQ0KICAgKQ0KDQoNCnRvcF8xMF9jb21wX2Vudl9maWcgPC0gY29tcG91bmRfdXNlX21vdGl2YXRpb24gJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0dWR5X21vdGl2YXRpb24gPT0gIkVudmlyb25tZW50YWwiKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6MTApICU+JSANCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9uYW1lID0gZmN0X3Jlb3JkZXIoY29tcG91bmRfbmFtZSwgbikpICU+JSANCiAgZ2dwbG90KGFlcyh4PWNvbXBvdW5kX25hbWUsIHk9bikpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjEsIGNvbG91ciA9IE5BLCBmaWxsID0gIiM2MEJENkMiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG91ciA9ICIjNjBCRDZDIiwgZmlsbCA9ICIjNjBCRDZDIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogICBsYWJzKA0KICAgICB0aXRsZSA9ICJFbnZpcm9ubWVudGFsIiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICJUb3RhbCB1c2UgaW4gdGhlIGRhdGFiYXNlIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkNCiAgICkNCg0KDQp0b3BfMTBfY29tcF9tZWRfZmlnIDwtIGNvbXBvdW5kX3VzZV9tb3RpdmF0aW9uICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJNZWRpY2FsIikgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjEwKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY29tcG91bmRfbmFtZSA9IGZjdF9yZW9yZGVyKGNvbXBvdW5kX25hbWUsIG4pKSAlPiUgDQogIGdncGxvdChhZXMoeD1jb21wb3VuZF9uYW1lLCB5PW4pKSArDQogIGdlb21fY29sKHdpZHRoID0gMC4xLCBjb2xvdXIgPSBOQSwgZmlsbCA9ICIjRDM1OUExIikgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzLCBjb2xvdXIgPSAiI0QzNTlBMSIsIGZpbGwgPSAiI0QzNTlBMSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG4pLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICAgbGFicygNCiAgICAgdGl0bGUgPSAiTWVkaWNhbCIsDQogICAgeCA9ICIiLA0KICAgIHkgPSAiVG90YWwgdXNlIGluIHRoZSBkYXRhYmFzZSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpDQogICApDQoNCnRvcF8xMF9jb21wX2Jhc2VfZmlnIDwtIGNvbXBvdW5kX3VzZV9tb3RpdmF0aW9uICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJCYXNpYyByZXNlYXJjaCIpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToxMCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNvbXBvdW5kX25hbWUgPSBmY3RfcmVvcmRlcihjb21wb3VuZF9uYW1lLCBuKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9Y29tcG91bmRfbmFtZSwgeT1uKSkgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDAuMSwgY29sb3VyID0gTkEsIGZpbGwgPSAiIzNDODJDNCIpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMywgY29sb3VyID0gIiMzQzgyQzQiLCBmaWxsID0gIiMzQzgyQzQiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgIGxhYnMoDQogICAgIHRpdGxlID0gIkJhc2ljIFJlc2VhcmNoIiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICJUb3RhbCB1c2UgaW4gdGhlIGRhdGFiYXNlIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkNCiAgICAgKQ0KYGBgDQoNCg0KIyMjIyBGaWcgNGINCg0KSGVyZSBhcmUgdGhlIHJlc3VsdGluZyBmaWd1cmVzIA0KDQpgYGB7ciwgZmlnLndpZHRoPTIuNSwgZmlnLmhlaWdodD01fQ0KdG9wXzEwX2NvbXBfYWxsX2ZpZw0KdG9wXzEwX2NvbXBfZW52X2ZpZw0KdG9wXzEwX2NvbXBfbWVkX2ZpZw0KdG9wXzEwX2NvbXBfYmFzZV9maWcNCmBgYA0KDQpTYXZpbmcgYXMgUERGcyAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoImNvbXBfdG9wXzEwX2NvbXBfYWxsX2ZpZy5wZGYiLCBwbG90ID0gdG9wXzEwX2NvbXBfYWxsX2ZpZywgd2lkdGggPSA1LCBoZWlnaHQgPSAxMCkNCiMgZ2dzYXZlKCJjb21wX3RvcF8xMF9jb21wX2Vudl9maWcucGRmIiwgcGxvdCA9IHRvcF8xMF9jb21wX2Vudl9maWcsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMTApDQojIGdnc2F2ZSgiY29tcF90b3BfMTBfY29tcF9tZWRfZmlnLnBkZiIsIHBsb3QgPSB0b3BfMTBfY29tcF9tZWRfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDEwKQ0KIyBnZ3NhdmUoImNvbXBfdG9wXzEwX2NvbXBfYmFzZV9maWcucGRmIiwgcGxvdCA9IHRvcF8xMF9jb21wX2Jhc2VfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDEwKQ0KYGBgDQoNCg0KIyMjIE1peHR1cmVzDQoNCkl0IHdhcyByZWNvcmRlZCB3aGV0aGVyIHRoZSBhbmltYWxzIHdlcmUgYWxzbyBleHBvc2VkIHRvIGNvbXBvdW5kIG1peHR1cmVzICAgDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG1peHR1cmVfeWVzID0gc3VtKGNvbXBvbmRfbWl4dHVyZSA9PSAiWWVzIiwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgICAgICAgbWl4dHVyZV9ubyA9IHN1bShjb21wb25kX21peHR1cmUgPT0gIk5vIiwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgICAgICAgbWl4dHVyZV9wZXJjZW50ID0gKG1peHR1cmVfeWVzL21peHR1cmVfbm8pKjEwMA0KICAgICAgICAgICAgICAgICApICU+JSANCiAgZ3QoKQ0KYGBgDQoNCk1lZGljYWwgYXJ0aWNsZXMgaGF2ZSBhIG11Y2ggaGlnaGVyIHVzZSBvZiBtaXh0dXJlcyAgICANCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobWl4dHVyZV95ZXMgPSBzdW0oY29tcG9uZF9taXh0dXJlID09ICJZZXMiLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICBtaXh0dXJlX25vID0gc3VtKGNvbXBvbmRfbWl4dHVyZSA9PSAiTm8iLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICBtaXh0dXJlX3BlcmNlbnQgPSByb3VuZCgobWl4dHVyZV95ZXMvbWl4dHVyZV9ubykqMTAwLDEpDQogICAgICAgICAgICAgICAgICkgJT4lIA0KICBndCgpDQpgYGANCg0KIyMjIEV4cG9zdXJlIHJvdXRlICAgDQoNCkRhdGEgb24gdGhlIG1ldGhvZCBvZiBleHBvc3VyZSB3YXMgYWxzbyBleHRyYWN0ZWQgICANCg0KYGBge3J9DQpucm93IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIG5yb3coLikNCg0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX2V4cG9zZV9yb3V0ZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpLA0KICAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQoKG4vbnJvdykqMTAwLDEpKSAlPiUNCiAgZ3QoKQ0KYGBgDQoNCiMjIyBFeHBvc3VyZSBsZW5ndGgNCg0KVGhlIGRhdGFiYXNlIGhhcyBib3RoIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIGR1cmF0aW9uIG9mIGV4cG9zdXJlIHByaW9yIHRvIGJlaGF2aW91cmFsIG1lYXN1cmUNCihjb21wb3VuZF9taW5fZHVyYXRpb25fZXhwb3N1cmUgYW5kIGNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSkuIEhlcmUgd2Ugd2lsbCBmb2N1cyBvbiB0aGUgbWF4aW11bSBkdXJhdGlvbiAgIA0KDQpUaGVzZSBhcmUgdGhlIGRpZmZlcmVudCBjYXRlZ29yaWVzIG9mIGV4cG9zdXJlIGxlbmd0aCAgIA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUpICU+JSANCiAgZ3QoKQ0KYGBgDQpTb21lIGFydGljbGVzIGRpZCBub3QgcmVwb3J0IHRoZSBleHBvc3VyZSBkdXJhdGlvbiBhdCBhbGwsIG9yIGluIHN1ZmZpY2llbnQgZGV0YWlsIHRvIGV4dHJhY3QuICAgDQoNCkluIHRvdGFsIHRoaXMgb2NjdXJyZWQgaW4gMTA4IGNhc2VzICAgDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9taW5fZHVyYXRpb25fZXhwb3N1cmUgPT0gIk5vdCBzdGF0ZWQiIHwgY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlID09ICJOb3Qgc3RhdGVkIikgJT4lIA0KICBucm93KC4pDQpgYGANCg0KU3VtbWFyeSB0YWJsZSAgICANCg0KYGBge3J9DQpleHBvc3VyZV9kdXJhdGlvbl9vcmRlciA8LSBjKCJMZXNzIHRoYW4gNiBob3VycyIsICI2IHRvIDI0IGhvdXJzIiwgIjEgdG8gMyBkYXlzIiwgIjMgdG8gOCBkYXlzIiwgIjggdG8gMTUgZGF5cyIsICIxNSB0byAyMiBkYXlzIiwgIjIyIHRvIDI5IGRheXMiLCAiMSB0byAzIG1vbnRocyIsICIzIHRvIDYgbW9udGhzIiwgIkxpZmV0aW1lIiwgIlRyYW5zZ2VuZXJhdGlvbmFsIiwgIk11bHRpZ2VuZXJhdGlvbmFsIikNCg0KbnJvdyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSAhPSAiTm90IHN0YXRlZCIpICU+JSANCiAgbnJvdyguKQ0KDQpleHBvc3VyZV9kdXJhdGlvbl9zdW1tYXJ5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlICE9ICJOb3Qgc3RhdGVkIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCksDQogICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZCgobi9ucm93KSoxMDAsMSkNCiAgICAgICAgICAgICAgICAgKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlID0gIGZhY3Rvcihjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gZXhwb3N1cmVfZHVyYXRpb25fb3JkZXIpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiQWxsIikNCg0KZXhwb3N1cmVfZHVyYXRpb25fc3VtbWFyeSAlPiUgDQogIGd0KCkNCmBgYA0KDQpCeSBtb3RpdmF0aW9uICAgDQoNCg0KYGBge3J9DQpleHBvc3VyZV9kdXJhdGlvbl9vcmRlciA8LSBjKCJMZXNzIHRoYW4gNiBob3VycyIsICI2IHRvIDI0IGhvdXJzIiwgIjEgdG8gMyBkYXlzIiwgIjMgdG8gOCBkYXlzIiwgIjggdG8gMTUgZGF5cyIsICIxNSB0byAyMiBkYXlzIiwgIjIyIHRvIDI5IGRheXMiLCAiMSB0byAzIG1vbnRocyIsICIzIHRvIDYgbW9udGhzIiwgIkxpZmV0aW1lIiwgIlRyYW5zZ2VuZXJhdGlvbmFsIiwgIk11bHRpZ2VuZXJhdGlvbmFsIikNCg0KDQpleHBvc3VyZV9kdXJhdGlvbl9tb3RpdmF0aW9uX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUgIT0gIk5vdCBzdGF0ZWQiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUsIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KG4gPSAwKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKChuL3RvdGFsX21vdGl2YXRpb24pKjEwMCwxKSkgJT4lDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmV4cF9kdXJhdGlvbl9tb3RpdmF0aW9uX3N1bW1hcnkgPC0gZXhwb3N1cmVfZHVyYXRpb25fbW90aXZhdGlvbl9zdW1tYXJ5ICU+JSANCiAgcmJpbmQoZXhwb3N1cmVfZHVyYXRpb25fc3VtbWFyeSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSA9ICBmYWN0b3IoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHJldihleHBvc3VyZV9kdXJhdGlvbl9vcmRlcikpDQogICAgICAgICAgICAgICAgKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlKSkNCmBgYA0KDQpNYWtpbmcgcGxvdHMgZm9yIGVhY2ggc3R1ZHkgbW90aXZhdGlvbiAgIA0KDQpgYGB7cn0NCmV4cF9kdXJhdGlvbl9hbGxfZmlnIDwtIGV4cF9kdXJhdGlvbl9tb3RpdmF0aW9uX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0dWR5X21vdGl2YXRpb24gPT0gIkFsbCIpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9Y29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlLCB5PXBlcmNlbnQpKSArDQogIGdlb21fY29sKHdpZHRoID0gMC4xLCBjb2xvdXIgPSBOQSwgZmlsbCA9ICJncmV5IikgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzLCBjb2xvdXIgPSAiZ3JleSIsIGZpbGwgPSAiZ3JleSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnQpLCB2anVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgbGFicygNCiAgICAgdGl0bGUgPSAiQWxsIiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICJUb3RhbCBwZXJjZW50YWdlIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkNCiAgICkNCg0KDQpleHBfZHVyYXRpb25fZW52X2ZpZyA8LSBleHBfZHVyYXRpb25fbW90aXZhdGlvbl9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJFbnZpcm9ubWVudGFsIikgJT4lDQogIGdncGxvdChhZXMoeD1jb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUsIHk9cGVyY2VudCkpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjEsIGNvbG91ciA9IE5BLCBmaWxsID0gIiM2MEJENkMiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG91ciA9ICIjNjBCRDZDIiwgZmlsbCA9ICIjNjBCRDZDIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudCksIHZqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgICB0aXRsZSA9ICJFbnZpcm9ubWVudGFsIiwNCiAgICB4ID0gIiIsDQogICAgeSA9ICJUb3RhbCBwZXJjZW50YWdlIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSkNCiAgICkNCg0KZXhwX2R1cmF0aW9uX21lZF9maWcgPC0gZXhwX2R1cmF0aW9uX21vdGl2YXRpb25fc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3R1ZHlfbW90aXZhdGlvbiA9PSAiTWVkaWNhbCIpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9Y29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlLCB5PXBlcmNlbnQpKSArDQogIGdlb21fY29sKHdpZHRoID0gMC4xLCBjb2xvdXIgPSBOQSwgZmlsbCA9ICIjRDM1OUExIikgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzLCBjb2xvdXIgPSAiI0QzNTlBMSIsIGZpbGwgPSAiI0QzNTlBMSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnQpLCB2anVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgbGFicygNCiAgICAgdGl0bGUgPSAiTWVkaWNhbCIsDQogICAgeCA9ICIiLA0KICAgIHkgPSAiVG90YWwgcGVyY2VudGFnZSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpDQogICApDQoNCg0KZXhwX2R1cmF0aW9uX2Jhc2VfZmlnIDwtIGV4cF9kdXJhdGlvbl9tb3RpdmF0aW9uX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0dWR5X21vdGl2YXRpb24gPT0gIkJhc2ljIHJlc2VhcmNoIikgJT4lDQogIGdncGxvdChhZXMoeD1jb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUsIHk9cGVyY2VudCkpICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjEsIGNvbG91ciA9IE5BLCBmaWxsID0gIiMzQzgyQzQiKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG91ciA9ICIjM0M4MkM0IiwgZmlsbCA9ICIjM0M4MkM0IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudCksIHZqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgICB0aXRsZSA9ICJCYXNpYyByZXNlYXJjaCIsDQogICAgeCA9ICIiLA0KICAgIHkgPSAiVG90YWwgcGVyY2VudGFnZSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpDQogICApDQpgYGANCg0KDQojIyMjIEZpZyA1YQ0KDQpgYGB7ciwgZmlnLndpZHRoPTguMy8zLCBmaWcuaGVpZ2h0PTExLjcvM30NCmV4cF9kdXJhdGlvbl9hbGxfZmlnDQpleHBfZHVyYXRpb25fZW52X2ZpZw0KZXhwX2R1cmF0aW9uX21lZF9maWcNCmV4cF9kdXJhdGlvbl9iYXNlX2ZpZw0KYGBgDQoNClNhdmUgcGxvdHMgICANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJjb21wX2V4cF9kdXJhdGlvbl9hbGxfZmlnLnBkZiIsIHBsb3QgPSBleHBfZHVyYXRpb25fYWxsX2ZpZywgd2lkdGggPSA4LjMvMywgaGVpZ2h0ID0gMTEuNy8zKQ0KIyBnZ3NhdmUoImNvbXBfZXhwX2R1cmF0aW9uX2Vudl9maWcucGRmIiwgcGxvdCA9IGV4cF9kdXJhdGlvbl9lbnZfZmlnLCB3aWR0aCA9IDguMy8zLCBoZWlnaHQgPSAxMS43LzMpDQojIGdnc2F2ZSgiY29tcF9leHBfZHVyYXRpb25fbWVkX2ZpZy5wZGYiLCBwbG90ID0gZXhwX2R1cmF0aW9uX21lZF9maWcsIHdpZHRoID0gOC4zLzMsIGhlaWdodCA9IDExLjcvMykNCiMgZ2dzYXZlKCJjb21wX2V4cF9kdXJhdGlvbl9iYXNlX2ZpZy5wZGYiLCBwbG90ID0gZXhwX2R1cmF0aW9uX2Jhc2VfZmlnLCB3aWR0aCA9IDguMy8zLCBoZWlnaHQgPSAxMS43LzMpDQpgYGANCg0KIyMjIE51bWJlciBvZiBkb3Nlcw0KDQpIZXJlIEkgd2lsbCBsb29rIGF0IHRoZSBudW1iZXIgb2YgZG9zZXMgdXNlZC4gVGhpcyB3YXMgbWVhc3N1cmVkIGFzIHRoZSB0b3RhbCB0cmVhdG1lbnRzIChpLmUuIGluY3VsZGluZyBjb250cm9sKSwgc28gaWYgd2Ugd2FudCB0byBrbm93IHRoZSBudW1iZXIgb2YgZG9zZXMgZm9yIHRoZSBjb21wb3VuZCB3ZSBuZWVkIHRvIHN1YnRyYWN0IDEuIEkgaGF2ZSBkb25lIHRoaXMgYmVsb3cuICANCg0KYGBge3J9DQpuX2Rvc2VzX3N1bW1hcnkgPC0gIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGNvbXBvdW5kX3RyZWF0bWVudF9sZXZlbHMpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUobl9kb3NlcyA9IGNvbXBvdW5kX3RyZWF0bWVudF9sZXZlbHMtMSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkobl9kb3NlcykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWwgPSBzdW0obiksDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKChuL3RvdGFsKSoxMDAsMSksDQogICAgICAgICAgICAgICAgc3R1ZHlfbW90aXZhdGlvbiA9ICJBbGwiKQ0KDQpuX2Rvc2VzX3N1bW1hcnkgJT4lIA0KICBndCgpDQpgYGANCkxldCdzIHNlZSBob3cgbWFueSB1c2UgbW9yZSB0aGVuIDUgICANCg0KYGBge3J9DQpuX2Rvc2VzX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKG5fZG9zZXMgPiA1KSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2Uob3Zlcl81X3BlcmNlbnQgPSBzdW0ocGVyY2VudCkpICU+JSANCiAgZ3QoKQ0KYGBgDQoNCkxvb2tpbmcgYnkgc3R1ZHkgbW90aXZhdGlvbiAgIA0KDQpgYGB7cn0NCm5fZG9zZXNfbW90aXZhdGlvbl9zdW1tYXJ5IDwtICBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShjb21wb3VuZF90cmVhdG1lbnRfbGV2ZWxzKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKG5fZG9zZXMgPSBjb21wb3VuZF90cmVhdG1lbnRfbGV2ZWxzLTEpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KG5fZG9zZXMsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUNCiAgdGlkeXI6OmNvbXBsZXRlKG5fZG9zZXMsIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KG4gPSAwKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZCgobi90b3RhbCkqMTAwLDEpKSANCmBgYA0KDQojIyMjIEZpZyA1Yg0KDQpNYWtpbmcgYSBwbG90DQogIA0KYGBge3J9DQpkb3NlX29yZGVyIDwtIGMoMToxMiwgIj4xMiIpDQoNCmRvc2VzX2ZpZyA8LSBuX2Rvc2VzX21vdGl2YXRpb25fc3VtbWFyeSAlPiUgDQogIGRwbHlyOjptdXRhdGUobl9kb3NlcyA9IGFzLmNoYXJhY3RlcihpZl9lbHNlKG5fZG9zZXM+MTMsIDEzLCBuX2Rvc2VzKSksDQogICAgICAgICAgICAgICAgbl9kb3NlcyA9IGlmX2Vsc2Uobl9kb3NlcyA9PSAiMTMiLCAiPjEyIiwgbl9kb3NlcyksDQogICAgICAgICAgICAgICAgbl9kb3NlcyA9IGZhY3RvcihuX2Rvc2VzLCBsZXZlbHMgPSBkb3NlX29yZGVyKQ0KICAgICAgICAgICAgICAgICklPiUgDQogIGdncGxvdChhZXMoeD1uX2Rvc2VzLCB5PXBlcmNlbnQsIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24sIA0KICAgICAgICAgICAgIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBncm91cCA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fbGluZShzaXplID0gMSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudCksIHZqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgZmFjZXRfd3JhcCh+c3R1ZHlfbW90aXZhdGlvbikgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuOCwgMC45KSwgIyBQb3NpdGlvbmluZyB0aGUgbGVnZW5kIGluIHRoZSB0b3AtbGVmdCBjb3JuZXIgd2l0aGluIHRoZSBwbG90DQogICAgbGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDAsIDEpICMgRW5zdXJpbmcgdGhlIGxlZ2VuZCBib3ggYWxpZ25zIHByb3Blcmx5IGF0IHRoZSB0b3AtbGVmdCBjb3JuZXINCiAgICApICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiTnVtYmVyIG9mIHN0dWRpZXMiDQogICkgKw0KICAgdGhlbWUoKQ0KDQpkb3Nlc19maWcNCmBgYA0KDQpTYXZlIHRoZSBwbG90ICAgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGdnc2F2ZSgiY29tcF9kb3Nlc19maWcucGRmIiwgcGxvdCA9IGRvc2VzX2ZpZywgd2lkdGggPSA4LjMsIGhlaWdodCA9IDExLjcvMykNCmBgYA0KDQoNCiMjIyBDb25jZW50cmF0aW9ucw0KDQpIZXJlIEkgd2lsbCBoYXZlIGEgbG9vayBhdCB0aGUgbWluIGFuZCBtYXggYW5kIHJhbmdlIG9mIGRvc2VzIHVzZWQgaW4gdGhlIGRhdGFiYXNlLiBGb3IgdGhlIE1TLCBJIGFtIGluY2x1ZGluZyBvbmx5IHN0dWRpZXMgdGhhdCByZXBvcnRlZCBpbiBhIG1hc3MgdG8gd2F0ZXIgdm9sdW1lIG1lYXN1cmUgc28gd2UgY2FuIGNvbXBhcmUgc3RhbmRhcmRpc2VkIHVuaXRlcyAodWcvTCkuIFRoaXMgd2FzIHRoZSBtb3N0IGNvbW1vbiByZXBvcnRpbmcgbWV0aG9kcyAoNjIlIG9mIGFsbCBkYXRhOyAxMDkwIHRvdGFsKS4gICAgDQoNCmBgYHtyfQ0KbnJvdyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBucm93KCkNCg0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCksDQogICAgICAgICAgICAgICAgIHByb3AgPSBuL25yb3cpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBndCgpDQpgYGANCg0KU3VtbWFyeSBvZiB0aGUgbWluaW11bSBjb25jZW50cmF0aW9uIHVzZWQgKHdoZXJlIHJlcG9ydGVkIGluIG1hc3MgdG8gdm9sdW1lKSAgIA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHJhbmdlID0gY29tcG91bmRfbWF4X2Rvc2Vfc3RkIC0gY29tcG91bmRfbWluX2Rvc2Vfc3RkKQ0KYGBgDQoNCkRvc2Ugc3VtbWFyeSBieSBtb3RpdmF0aW9uICANCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIiwgY29tcG91bmRfbWF4X2Rvc2VfdW5pdF9zdGQgPT0gInVnL0wiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocmFuZ2UgPSBjb21wb3VuZF9tYXhfZG9zZV9zdGQgLSBjb21wb3VuZF9taW5fZG9zZV9zdGQpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobWVkaWFuX21pbiA9ICBtZWRpYW4oY29tcG91bmRfbWluX2Rvc2Vfc3RkLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICBzZF9taW4gPSBzZChjb21wb3VuZF9taW5fZG9zZV9zdGQsIG5hLnJtID0gVCksDQogICAgICAgICAgICAgICAgIG1pbl9taW4gPSAgbWluKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCwgbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgbWF4X21pbiA9ICBtYXgoY29tcG91bmRfbWluX2Rvc2Vfc3RkLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICBtZWRpYW5fbWF4ID0gIG1lZGlhbihjb21wb3VuZF9tYXhfZG9zZV9zdGQsIG5hLnJtID0gVCksDQogICAgICAgICAgICAgICAgIHNkX21heCA9IHNkKGNvbXBvdW5kX21heF9kb3NlX3N0ZCwgbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgICAgbWluX21heCA9ICBtaW4oY29tcG91bmRfbWF4X2Rvc2Vfc3RkLCBuYS5ybSA9IFQpLA0KICAgICAgICAgICAgICAgICBtYXhfbWF4ID0gIG1heChjb21wb3VuZF9tYXhfZG9zZV9zdGQsIG5hLnJtID0gVCksDQogICAgICAgICAgICAgICAgIG1lZGlhbl9yYW5nZSA9ICBtZWRpYW4ocmFuZ2UsIG5hLnJtID0gVCksDQogICAgICAgICAgICAgICAgIHNkX3JhbmdlID0gc2QocmFuZ2UsIG5hLnJtID0gVCksDQogICAgICAgICAgICAgICAgIG1pbl9yYW5nZSA9ICBtaW4ocmFuZ2UsIG5hLnJtID0gVCksDQogICAgICAgICAgICAgICAgIG1heF9yYW5nZSA9ICBtYXgocmFuZ2UsIG5hLnJtID0gVCkpICU+JSANCiAgZ3QoKQ0KYGBgDQoNCiMjIyMgRmlnIDVjLTENCg0KQSBwbG90IGZvciBtaW5pbXVtIGRvc2VzLCBpdHMgb24gdGhlIGxvZyBheGlzIGJlY2F1c2UgdGhlIGRpc3RyaWJ1dGlvbiBpcyBoaWdobHkgc2tld2VkDQptb3RpdmF0aW9uX2NvbG91cl90aGVtZSAgICANCg0KYGBge3J9DQptb3RpdmF0aW9uX2NvbG91cl90aGVtZSA8LSBjKCIjNjBCRDZDIiwgIiNEMzU5QTEiLCAiIzNDODJDNCIpDQoNCm1pbl9jb25jX2ZpZyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9bG9nKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCksIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBzdGF0X3NsYWIoYWxwaGEgPSAwLjYsIGxpbmV3aWR0aCA9IDEuNSwgY29sb3VyID0gTkEpICsNCiAgc3RhdF9wb2ludGludGVydmFsKHBvaW50X2ludGVydmFsID0gIm1lZGlhbl9xaSIsDQogICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjQsIHByZXNlcnZlID0gInNpbmdsZSIpLA0KICAgICAgICAgICAgICAgICAgICAgLndpZHRoID0gYygwLjg5LCAwLjk1KSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIiwgZ3VpZGUgPSAnbm9uZScpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBsYWJzKA0KICAgIHggPSAiTG9nMTAgbWluaW11bSBkb3NlICh1Zy9MKSIsDQogICAgeSA9ICJEZW5zaXR5Ig0KICApICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKQ0KDQptaW5fY29uY19maWcNCmBgYA0KDQpTYXZlIHRoZSBmaWd1cmUgICANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJjb21wX21pbl9jb25jX2ZpZy5wZGYiLCBwbG90ID0gbWluX2NvbmNfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDYpDQpgYGANCg0KQSBzdW1tYXJ5IHRhYmxlIHNvIHdlIGNhbiBzZWUgd2hhdCB0aGUgY29ycmVzcG9uZGluZyByYXcgdmFsdWVzIGFyZSBpbiB0aGUgcGxvdA0KDQpgYGB7cn0NCm1pbl9jb25jX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIikgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgbWVkaWFuID0gbWVkaWFuKGxvZyhjb21wb3VuZF9taW5fZG9zZV9zdGQpLCBuYS5ybSA9IFRSVUUpLA0KICAgIGxvd2VyXzg5ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCksIHByb2JzID0gMC4xMSwgbmEucm0gPSBUUlVFKSwNCiAgICB1cHBlcl84OSA9IHF1YW50aWxlKGxvZyhjb21wb3VuZF9taW5fZG9zZV9zdGQpLCBwcm9icyA9IDAuODksIG5hLnJtID0gVFJVRSksDQogICAgbG93ZXJfOTUgPSBxdWFudGlsZShsb2coY29tcG91bmRfbWluX2Rvc2Vfc3RkKSwgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLA0KICAgIHVwcGVyXzk1ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCksIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkgJT4lDQogICMgVHJhbnNmb3JtIHRvIGEgZm9ybWF0IHN1aXRhYmxlIGZvciBnZ3Bsb3QgYW5ub3RhdGlvbg0KICBwaXZvdF9sb25nZXIoY29scyA9IC1zdHVkeV9tb3RpdmF0aW9uLCBuYW1lc190byA9ICJzdGF0IiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHZhdWxlX3JhdyA9IGZvcm1hdChleHAodmFsdWUpLCBzY2llbnRpZmljID0gRkFMU0UpKQ0KYGBgDQoNCiMjIyMgRmlnIDVjLTINCg0KQSBwbG90IGZvciBtYXhpbXVtIGRvc2VzLCBpdHMgb24gdGhlIGxvZyBheGlzIGJlY2F1c2UgdGhlIGRpc3RyaWJ1dGlvbiBpcyBoaWdobHkgc2tld2VkIG1vdGl2YXRpb25fY29sb3VyX3RoZW1lICAgDQoNCmBgYHtyfQ0KbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUgPC0gYygiIzYwQkQ2QyIsICIjRDM1OUExIiwgIiMzQzgyQzQiKQ0KDQptYXhfY29uY19maWcgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9taW5fZG9zZV91bml0X3N0ZCA9PSAidWcvTCIpICU+JSANCiAgZ2dwbG90KGFlcyh4PWxvZyhjb21wb3VuZF9tYXhfZG9zZV9zdGQpLCBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiwgY29sb3VyID0gc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgc3RhdF9zbGFiKGFscGhhID0gMC42LCBsaW5ld2lkdGggPSAxLjUsIGNvbG91ciA9IE5BKSArDQogIHN0YXRfcG9pbnRpbnRlcnZhbChwb2ludF9pbnRlcnZhbCA9ICJtZWRpYW5fcWkiLA0KICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC40LCBwcmVzZXJ2ZSA9ICJzaW5nbGUiKSwNCiAgICAgICAgICAgICAgICAgICAgIC53aWR0aCA9IGMoMC44OSwgMC45NSkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIsIGd1aWRlID0gJ25vbmUnKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgbGFicygNCiAgICB4ID0gIkxvZzEwIG1heGltdW0gZG9zZSAodWcvTCkiLA0KICAgIHkgPSAiRGVuc2l0eSINCiAgKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikNCg0KbWF4X2NvbmNfZmlnDQpgYGANCg0KU2F2ZSB0aGUgZmlndXJlICANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJjb21wX21heF9jb25jX2ZpZy5wZGYiLCBwbG90ID0gbWF4X2NvbmNfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDYpDQpgYGANCg0KQSBzdW1tYXJ5IHRhYmxlIHNvIHdlIGNhbiBzZWUgd2hhdCB0aGUgY29ycmVzcG9uZGluZyByYXcgdmFsdWVzIGFyZSBpbiB0aGUgcGxvdA0KDQpgYGB7cn0NCm1heF9jb25jX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIikgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgbWVkaWFuID0gbWVkaWFuKGxvZyhjb21wb3VuZF9tYXhfZG9zZV9zdGQpLCBuYS5ybSA9IFRSVUUpLA0KICAgIGxvd2VyXzg5ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21heF9kb3NlX3N0ZCksIHByb2JzID0gMC4xMSwgbmEucm0gPSBUUlVFKSwNCiAgICB1cHBlcl84OSA9IHF1YW50aWxlKGxvZyhjb21wb3VuZF9tYXhfZG9zZV9zdGQpLCBwcm9icyA9IDAuODksIG5hLnJtID0gVFJVRSksDQogICAgbG93ZXJfOTUgPSBxdWFudGlsZShsb2coY29tcG91bmRfbWF4X2Rvc2Vfc3RkKSwgcHJvYnMgPSAwLjA1LCBuYS5ybSA9IFRSVUUpLA0KICAgIHVwcGVyXzk1ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21heF9kb3NlX3N0ZCksIHByb2JzID0gMC45NSwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkgJT4lDQogICMgVHJhbnNmb3JtIHRvIGEgZm9ybWF0IHN1aXRhYmxlIGZvciBnZ3Bsb3QgYW5ub3RhdGlvbg0KICBwaXZvdF9sb25nZXIoY29scyA9IC1zdHVkeV9tb3RpdmF0aW9uLCBuYW1lc190byA9ICJzdGF0IiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHZhdWxlX3JhdyA9IGZvcm1hdChleHAodmFsdWUpLCBzY2llbnRpZmljID0gRkFMU0UpKQ0KYGBgDQoNCiMjIyMgRmlnIDVjLTMNCg0KQSBwbG90IGZvciB0aGUgcmFuZ2Ugb2YgZG9zZXMsIGl0cyBvbiB0aGUgbG9nIGF4aXMgYmVjYXVzZSB0aGUgZGlzdHJpYnV0aW9uIGlzIGhpZ2hseSBza2V3ZWQuIFRoaXMgaW5jbHVkZXMgb25seSBzdHVkaWVzIHRoYXQgaGFkIG1vcmUgdGhlbiBvbmUgZG9zZSBhbmQgcmVwb3J0ZWQgY29uY2VudHJhdGlvbiBpbiBhIG1hc3MgdG8gdm9sdW1lIG1ldHJpYy4gICAgDQoNCmBgYHtyfQ0KbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUgPC0gYygiIzYwQkQ2QyIsICIjRDM1OUExIiwgIiMzQzgyQzQiKQ0KDQpyYW5nZV9jb25jX2ZpZyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIikgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHJhbmdlID4gMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9bG9nKHJhbmdlKSwgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24sIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIHN0YXRfc2xhYihhbHBoYSA9IDAuNiwgbGluZXdpZHRoID0gMS41LCBjb2xvdXIgPSBOQSkgKw0KICBzdGF0X3BvaW50aW50ZXJ2YWwocG9pbnRfaW50ZXJ2YWwgPSAibWVkaWFuX3FpIiwNCiAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuNCwgcHJlc2VydmUgPSAic2luZ2xlIiksDQogICAgICAgICAgICAgICAgICAgICAud2lkdGggPSBjKDAuODksIDAuOTUpKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iLCBndWlkZSA9ICdub25lJykgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGxhYnMoDQogICAgeCA9ICJMb2cxMCByYW5nZSAodWcvTCkiLA0KICAgIHkgPSAiRGVuc2l0eSINCiAgKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikNCg0KcmFuZ2VfY29uY19maWcNCmBgYA0KDQpTYXZlIHRoZSBmaWd1cmUgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoImNvbXBfcmFuZ2VfY29uY19maWcucGRmIiwgcGxvdCA9IHJhbmdlX2NvbmNfZmlnLCB3aWR0aCA9IDUsIGhlaWdodCA9IDYpDQpgYGANCg0KDQpBIHN1bW1hcnkgdGFibGUgc28gd2UgY2FuIHNlZSB3aGF0IHRoZSBjb3JyZXNwb25kaW5nIHJhdyB2YWx1ZXMgYXJlIGluIHRoZSBwbG90DQoNCmBgYHtyfQ0KcmFuZ2VfY29uY19zdW1tYXJ5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9taW5fZG9zZV91bml0X3N0ZCA9PSAidWcvTCIsDQogICAgICAgICAgICAgICAgcmFuZ2UgPiAwKSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIG1lZGlhbiA9IG1lZGlhbihsb2cocmFuZ2UpLCBuYS5ybSA9IFRSVUUpLA0KICAgIGxvd2VyXzg5ID0gcXVhbnRpbGUobG9nKHJhbmdlKSwgcHJvYnMgPSAwLjA1NSwgbmEucm0gPSBUUlVFKSwNCiAgICB1cHBlcl84OSA9IHF1YW50aWxlKGxvZyhyYW5nZSksIHByb2JzID0gMC45NDUsIG5hLnJtID0gVFJVRSksDQogICAgbG93ZXJfOTUgPSBxdWFudGlsZShsb2cocmFuZ2UpLCBwcm9icyA9IDAuMDI1LCBuYS5ybSA9IFRSVUUpLA0KICAgIHVwcGVyXzk1ID0gcXVhbnRpbGUobG9nKHJhbmdlKSwgcHJvYnMgPSAwLjk3NSwgbmEucm0gPSBUUlVFKQ0KICApICU+JQ0KICAjIFRyYW5zZm9ybSB0byBhIGZvcm1hdCBzdWl0YWJsZSBmb3IgZ2dwbG90IGFubm90YXRpb24NCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtc3R1ZHlfbW90aXZhdGlvbiwgbmFtZXNfdG8gPSAic3RhdCIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JSANCiAgZHBseXI6Om11dGF0ZSh2YXVsZV9yYXcgPSBmb3JtYXQoZXhwKHZhbHVlKSwgc2NpZW50aWZpYyA9IEZBTFNFKSkNCmBgYA0KDQpSYW5nZSBvZiBkb2VzIA0KDQpgYGB7cn0NCmVudl9taW5fY29uY19maWcgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6OmZpbHRlcihzdHVkeV9tb3RpdmF0aW9uID09ICJFbnZpcm9ubWVudGFsIikgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21pbl9kb3NlX3VuaXRfc3RkID09ICJ1Zy9MIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9bG9nKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCkpKSArDQogIHN0YXRfc2xhYihhZXMoYWxwaGEgPSAwLjgsIGxpbmV3aWR0aCA9IDEuNSkpICsNCiAgc3RhdF9wb2ludGludGVydmFsKHBvaW50X2ludGVydmFsID0gIm1lZGlhbl9xaSIsDQogICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjQsIHByZXNlcnZlID0gInNpbmdsZSIpLA0KICAgICAgICAgICAgICAgICAgICAgLndpZHRoID0gYygwLjg5LCAwLjk1KSkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQ0KDQplbnZfbWluX2NvbmNfZmlnDQpgYGANCg0KQSBzdW1tYXJ5IHRhYmxlIHNvIHdlIGNhbiBzZWUgd2hhdCB0aGUgY29ycmVzcG9uZGluZyByYXcgdmFsdWVzIGFyZSBpbiB0aGUgcGxvdA0KDQpgYGB7cn0NCmVudl9jb25jX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBmaWx0ZXIoc3R1ZHlfbW90aXZhdGlvbiA9PSAiRW52aXJvbm1lbnRhbCIsIA0KICAgICAgICAgY29tcG91bmRfbWluX2Rvc2VfdW5pdF9zdGQgPT0gInVnL0wiKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG1lZGlhbiA9IG1lZGlhbihsb2coY29tcG91bmRfbWluX2Rvc2Vfc3RkKSwgbmEucm0gPSBUUlVFKSwNCiAgICBsb3dlcl84OSA9IHF1YW50aWxlKGxvZyhjb21wb3VuZF9taW5fZG9zZV9zdGQpLCBwcm9icyA9IDAuMDU1LCBuYS5ybSA9IFRSVUUpLA0KICAgIHVwcGVyXzg5ID0gcXVhbnRpbGUobG9nKGNvbXBvdW5kX21pbl9kb3NlX3N0ZCksIHByb2JzID0gMC45NDUsIG5hLnJtID0gVFJVRSksDQogICAgbG93ZXJfOTUgPSBxdWFudGlsZShsb2coY29tcG91bmRfbWluX2Rvc2Vfc3RkKSwgcHJvYnMgPSAwLjAyNSwgbmEucm0gPSBUUlVFKSwNCiAgICB1cHBlcl85NSA9IHF1YW50aWxlKGxvZyhjb21wb3VuZF9taW5fZG9zZV9zdGQpLCBwcm9icyA9IDAuOTc1LCBuYS5ybSA9IFRSVUUpDQogICkgJT4lDQogICMgVHJhbnNmb3JtIHRvIGEgZm9ybWF0IHN1aXRhYmxlIGZvciBnZ3Bsb3QgYW5ub3RhdGlvbg0KICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAic3RhdCIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JSANCiAgZHBseXI6Om11dGF0ZSh2YXVsZV9yYXcgPSBmb3JtYXQoZXhwKHZhbHVlKSwgc2NpZW50aWZpYyA9IEZBTFNFKSkNCmVudl9jb25jX3N1bW1hcnkgJT4lIA0KICBndCgpDQpgYGANCg0KIyMjIEV4cG9zdXJlIGxvY2F0aW9uDQoNCldoZXJlIHRoZSBleHBvc3VyZSBpdHNlbGYgd2FzIGNvbmR1Y3RlZA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9leHBvc3VyZV9sb2NhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWwgPSBzdW0obiksDQogICAgICAgICAgICAgICAgcGVyZWNlbnQgPSByb3VuZChuL3RvdGFsKjEwMCwxKSkgJT4lIA0KICBndCgpDQpgYGANCg0KIyMgQmVoYXZpb3VyDQoNCiMjIyBDb3VudHMgb2YgY2F0YWdvaXJlcw0KDQpGaXJzdCBJIHdpbGwgbWFrZSBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgYmVhaHZfY2F0Z29yeV9uLCB3aGljaCB3aWxsIGxvb2sgYXQgaG93IG1hbnkgb2Ygb3VyIDEwIGJyb2FkIGJlaGF2aW91cmFsIGNhdGVnb3JpZXMgd2VyZSBtZWFzdXJlZCBpbiB0aGUgYXJ0aWNsZS4gICAgDQoNClRoZSAxMCBvdmVyLWFyY2hpbmcgY2F0ZWdvcmllcyB3ZXJlOiAoMSkgbW92ZW1lbnQgYW5kIGxvY29tb3Rpb24sICgyKSBwcmUtbWF0aW5nIGFuZCBtYXRpbmcgYmVoYXZpb3VyLCAoMykgcG9zdC1tYXRpbmcgYmVoYXZpb3VyLCAoNCkgYWdncmVzc2lvbiwgKDUpIHNvY2lhbGl0eSwgKDYpIGNvZ25pdGlvbiBhbmQgbGVhcm5pbmcsICg3KSBhbnhpZXR5IGFuZCBib2xkbmVzcywgKDgpIGZvcmFnaW5nIGFuZCBmZWVkaW5nLCAoOSkgYW50aXByZWRhdG9yIGJlaGF2aW91ciwgYW5kICgxMCkgb3RoZXIgYmVoYXZpb3VycyBub3QgY2F0ZWdvcmlzZWQgICAgDQoNClRoaXMgd2lsbCB0YWtlIHRoZSBzb21lIG9mIGFsbCB0aGUgYmVoYXZpb3VyIGNhdGVnb3JpZXMuLCBzbyBjYW4gcmFuZ2UgZnJvbSAxIHRvIDEwIGZvciBhIHNpbmdsZSBiZWhhdmlvdXJhbCBjYXRlZ29yeSB0byBhbGwgY2F0ZWdvcmllcy4gICANCg0KYGBge3J9DQpFSVBBQUJfZGF0YWJhc2UgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6bXV0YXRlKGJlaGF2X2NhdGVnb3J5X24gPSByb3dTdW1zKGFjcm9zcyhzdGFydHNfd2l0aCgiYmVoYXZfIikgJiBlbmRzX3dpdGgoIl9ib29sZWFuIikpKSkNCmBgYA0KDQoNClRoZSBtYWpvcml0eSBvZiBldmlkZW5jZSBzZWVtcyB0byBiZSBiYXNlZCBvbiBhIHNpbmdsZSBiZWhhdmlvdXJhbCBjYXRlZ29yeQ0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXRlZ29yeV9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKSAlPiUgDQogIGd0KCkNCmBgYA0KSXMgdGhpcyB0aGUgc2FtZSBieSBzdHVkeSBtb3RpdmF0aW9uICAgIA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXRlZ29yeV9uLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGd0KCkNCmBgYA0KDQpIZXJlIEkgbWFrZSBhIGRhdGFmcmFtZSB3aGVyZSBJIGhhdmUgcGl2b3RlZCB0aGUgZGF0YSB0byBsb25nIGZvcm1hdGUgYmFzZWQgb24gZWFjaCBvZiB0aGUgMTAgYmVoYXZpb3VyIGNhdGVnb3JpZXMuIFRoaXMgZGF0YSBmcmFtZSBjYW4gYmUgdXNlZCB0byBhc2sgbW9yZSBzcGVjaWZpYyBxdWVzdGlvbnMgYWJvdXQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNwZWNpZXMsIGNvbXBvdW5kLCBhbmQgYmVoYXZpb3VyLiAgIA0KDQpCdXQgZmlyc3QgbGV0J3MgdXNlIGl0IHRvIHNlZSB3aGF0IGJlaGF2aW91cnMgYXJlIG1vc3QgY29tbW9uIG92ZXJhbGwgYWxsLCBhbmQgd2l0aGluIGVhY2ggc3R1ZHkgbW90aXZhdGlvbi4gIA0KDQpJIGhhdmUgcGxvdGVkIHRoZSBmaXJzdCAxMCBjb2x1bW5zIGFzIGFuIGV4YW1wbGUgb2Ygd2hhdCB0aGlzIGxvb2tzIGxpa2UNCiAgDQpgYGB7cn0NCmJpbmFyeV9iZWhhdiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6c2VsZWN0KChzdGFydHNfd2l0aCgiYmVoYXZfIikgJiBlbmRzX3dpdGgoIl9ib29sZWFuIikpKSAlPiUgDQogIGNvbG5hbWVzKCkNCg0KUElDT19sb25nIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIHRpZHlyOjpwaXZvdF9sb25nZXIoLiwgDQogICAgICAgICAgICAgICAgICAgICAgY29scyA9IGFsbF9vZihiaW5hcnlfYmVoYXYpLA0KICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gImJlaGF2X2NhdGVnb3J5IiwgDQogICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KGFydGljbGVfaWQsIHN0dWR5X21vdGl2YXRpb24sIHNwZWNpZXNfbmFtZSwgc3BlY2llc19jbGFzcywgDQogICAgICAgICAgICAgICAgY29tcG91bmRfbmFtZSwgY29tcG91bmRfYXRjX2xldmVsXzMsIGJlaGF2X2NhdGVnb3J5LCB2YWx1ZSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGJlaGF2X2NhdGVnb3J5ID0gYmVoYXZfY2F0ZWdvcnkgJT4lIHN0cl9yZW1vdmUoImJlaGF2XyIpICU+JSBzdHJfcmVtb3ZlKCJfYm9vbGVhbiIpKQ0KDQpQSUNPX2xvbmcgJT4lIA0KICBoZWFkKCkgJT4lIA0KICBndCgpDQpgYGANCg0KT3ZlcmFsbCB1c2Ugb2YgYmVoYXZpb3VyICAgDQoNCmBgYHtyfQ0KYmVoYXZfb3ZlcmFsbCA8LSBQSUNPX2xvbmcgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYmVoYXZfY2F0ZWdvcnkpICU+JSANCiAgcmVmcmFtZShuID0gc3VtKHZhbHVlKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsIDEpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpDQpiZWhhdl9vdmVyYWxsICU+JSANCiAgZ3QoKQ0KYGBgDQoNCkJ5IHN0dWR5IG1vdGl2YXRpb24gICANCg0KYGBge3J9DQpiZWhhdl9tb3RpdmF0aW9uIDwtIFBJQ09fbG9uZyAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXRlZ29yeSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKG4gPSBzdW0odmFsdWUpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUNCiAgdGlkeXI6OmNvbXBsZXRlKGJlaGF2X2NhdGVnb3J5LCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChuID0gMCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhzdHVkeV9tb3RpdmF0aW9uKSkNCg0KYmVoYXZfb3ZlcmFsbCA8LSBiZWhhdl9tb3RpdmF0aW9uICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGJlaGF2X2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpLA0KICAgICAgICAgICAgICAgIHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIpDQoNCmJlaGF2X21vdGl2YXRpb24gPC0gcmJpbmQoYmVoYXZfb3ZlcmFsbCwgYmVoYXZfbW90aXZhdGlvbikNCmBgYA0KDQojIyMjIEZpZyA2DQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUgPC0gYygiZ3JleSIsICIjNjBCRDZDIiwgIiNEMzU5QTEiLCAiIzNDODJDNCIpDQpiZWhhdl9vcmRlciA8LSBjKCJtb3ZlbWVudCIsICJib2xkbmVzcyIsICJmb3JhZ2luZyIsICJhbnRpcHJlZGF0b3IiLCAibWF0aW5nIiwgInBvc3RfbWF0aW5nIiwgImFncmVzc2lvbiIsICJzb2NpYWxpdHkiLCAiY29nbml0aW9uIiwgIm5vbmNhdCIpDQpzdHVkeV9tb3RpdmF0aW9uX29yZGVyIDwtIGMoIk92ZXJhbGwiLCAiRW52aXJvbm1lbnRhbCIsICJNZWRpY2FsIiwgIkJhc2ljIHJlc2VhcmNoIikNCg0KDQpiZWhhdl9tb3RpdmF0aW9uX2ZpZyA8LSBiZWhhdl9tb3RpdmF0aW9uICU+JSANCiAgZHBseXI6Om11dGF0ZShiZWhhdl9jYXRlZ29yeSA9IGZhY3RvcihiZWhhdl9jYXRlZ29yeSwgbGV2ZWxzID0gcmV2KGJlaGF2X29yZGVyKSksDQogICAgICAgICAgICAgICAgc3R1ZHlfbW90aXZhdGlvbiA9IGZhY3RvcihzdHVkeV9tb3RpdmF0aW9uLCBsZXZlbHMgPSBzdHVkeV9tb3RpdmF0aW9uX29yZGVyKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9YmVoYXZfY2F0ZWdvcnksIHk9cGVyY2VudCwgY29sb3VyID0gc3R1ZHlfbW90aXZhdGlvbiwgDQogICAgICAgICAgICAgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24pLCBncm91cCA9IHN0dWR5X21vdGl2YXRpb24pICsNCiAgZ2VvbV9jb2wod2lkdGggPSAwLjEsIGNvbG91ciA9IE5BKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnQpLCB2anVzdCA9IC0wLjMsIHNpemU9My41LCBjb2xvcj0iYmxhY2siKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMoc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2UiDQogICkgKw0KICB0aGVtZSgNCiAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpDQogICApDQoNCmJlaGF2X21vdGl2YXRpb25fZmlnDQpgYGANCg0KDQpTYXZlIHRoZSBmaWd1cmUgICANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJiZWhhdl9tb3RpdmF0aW9uX2ZpZy5wZGYiLCBwbG90ID0gYmVoYXZfbW90aXZhdGlvbl9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDUpDQpgYGANCg0KIyMjIEJlaGF2aW91ciBzdWItY2F0ZWdvcmllcw0KDQpgYGB7cn0NCmJlaGF2X3NlbGVjdCA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICBkcGx5cjo6c2VsZWN0KChzdGFydHNfd2l0aCgiYmVoYXZfIikgJiAhZW5kc193aXRoKCJfYm9vbGVhbiIpICYgIWVuZHNfd2l0aCgiaXNfc29jaWFsX2NvbnRleHQiKSAmICFlbmRzX3dpdGgoInRlc3RfbG9jYXRpb24iKSAmICFlbmRzX3dpdGgoImNhdGVnb3J5X24iKSkpICU+JSANCiAgY29sbmFtZXMoKQ0KDQoNCmJlaGF2X3N1Yl9jYXRfbG9uZyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lIA0KICB0aWR5cjo6cGl2b3RfbG9uZ2VyKC4sIA0KICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBhbGxfb2YoYmVoYXZfc2VsZWN0KSwNCiAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJwYXJlbnRfY2F0ZWdvcnkiLCANCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAic3ViX2NhdGVnb3J5IikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KGFydGljbGVfaWQsIHN0dWR5X21vdGl2YXRpb24sIHNwZWNpZXNfbmFtZSwgc3BlY2llc19jbGFzcywgDQogICAgICAgICAgICAgICAgY29tcG91bmRfbmFtZSwgY29tcG91bmRfYXRjX2xldmVsXzMsIHBhcmVudF9jYXRlZ29yeSwgc3ViX2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGFyZW50X2NhdGVnb3J5ID0gcGFyZW50X2NhdGVnb3J5ICU+JSBzdHJfcmVtb3ZlKCJiZWhhdl8iKSkgJT4lIA0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhzdWJfY2F0ZWdvcnksIHNlcCA9ICI7IikgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShzdWJfY2F0ZWdvcnkpKQ0KYGBgDQoNCg0KTm93IGEgc3VtbWFyeSBkYXRhIGZpbGUgd2l0aCBzdWItY2F0ZWdvcmllcy4gICAgDQoNCkkgaGF2ZSBwbG90dGVkIHRoZSBmaXJzdCAxMCByb3dzIGFzIGFuIGV4YW1wbGUgICANCg0KYGBge3J9DQpiZWhhdl9zdWJfY2F0X3N1bW1hcnkgPC0gYmVoYXZfc3ViX2NhdF9sb25nICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHBhcmVudF9jYXRlZ29yeSwgc3ViX2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2Uobl9zdWJfY2F0ID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBwYXJlbnRfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6Om11dGF0ZShuX3BhcmVudCA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lDQogIGRwbHlyOjptdXRhdGUobl9tb3RpdmF0aW9uID0gc3VtKG5fc3ViX2NhdCkpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9zdWJfY2F0ID0gbl9zdWJfY2F0L25fcGFyZW50LA0KICAgICAgICAgICAgICAgIHBlcmNlbnRfcGFyZW50ID0gbl9wYXJlbnQvbl9tb3RpdmF0aW9uKQ0KDQpiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBoZWFkKCkgJT4lIA0KICBndCgpDQpgYGANCg0KRm9ybWF0aW5nIHRoZSBkYXRhIGZvciBhIHJpbmcgcGxvdC4gICANCg0KYGBge3J9DQpyaW5nX3Bsb3Rfc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHBhcmVudF9jYXRlZ29yeSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHltYXggPSBjdW1zdW0ocGVyY2VudF9zdWJfY2F0KSwNCiAgICAgICAgICAgICAgICB5bWluID0gbGFnKHltYXgsMSksDQogICAgICAgICAgICAgICAgeW1pbiA9IGlmX2Vsc2UoaXMubmEoeW1pbiksIDAsIHltaW4pLA0KICAgICAgICAgICAgICAgIGxhYmVsUG9zaXRpb24gPSAoeW1heCt5bWluKS8yLA0KICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKHN1Yl9jYXRlZ29yeSwgIlxuIChuID0gIiwgbl9zdWJfY2F0LCAiKSIpKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkNCmBgYA0KDQoNCiMjIyMgTW92ZW1lbnQgcGxvdHMgDQoNCkZpcnN0IG1ha2luZyBhIGNvbXBsZXRlIGRhdGFzZXQgKGFkZGluZyB6ZXJvcyBmb3IgbWlzc2luZyBzdWItY2F0ZWdvcmllcy4gaW4gZWFjaCBtb3RpdmF0aW9uKSwgYW5kIG9yZGVyaW5nIGJ5IG92ZXJhbGwgcHJldmFsZW5jZSBvZiBzdWItY2F0ZWdvcmllcy4NCg0KYGBge3J9DQpzdWJfY2F0ZWdvcnlfb3JkZXIgPC0gYmVoYXZfc3ViX2NhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihwYXJlbnRfY2F0ZWdvcnkgPT0gIm1vdmVtZW50IikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViX2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obl9zdWJfY2F0KSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShuKSAlPiUgDQogIGRwbHlyOjpwdWxsKHN1Yl9jYXRlZ29yeSkNCg0KbW92ZW1lbnRfc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJtb3ZlbWVudCIpICU+JSANCiAgZHBseXI6OnNlbGVjdChzdHVkeV9tb3RpdmF0aW9uLCBzdWJfY2F0ZWdvcnksIHBlcmNlbnRfc3ViX2NhdCwgbl9zdWJfY2F0LCBwZXJjZW50X3BhcmVudCkgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoc3ViX2NhdGVnb3J5LCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChwZXJjZW50X3N1Yl9jYXQgPSAwLCBuX3N1Yl9jYXQgPSAwKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN1Yl9jYXRlZ29yeSA9IGZhY3RvcihzdWJfY2F0ZWdvcnksIGxldmVscyA9IHN1Yl9jYXRlZ29yeV9vcmRlcikpDQpgYGANCg0KDQojIyMjIyBGaWcgUzYtMQ0KDQpgYGB7cn0NCmJlaF9tb3ZlbWVudF9zdWJjYXRfZmlnIDwtIG1vdmVtZW50X3N1YmNhdCAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9zdWJfY2F0ID0gcm91bmQocGVyY2VudF9zdWJfY2F0LDMpKjEwMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3ViX2NhdGVnb3J5LCB5PXBlcmNlbnRfc3ViX2NhdCwgY29sb3VyID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24sIGdyb3VwID0gc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4xKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50X3N1Yl9jYXQpLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIiwgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUGVyY2VudGFnZSBvZiBkYXRhIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgICkNCg0KYmVoX21vdmVtZW50X3N1YmNhdF9maWcNCmBgYA0KDQpTYXZlIHRoZSBmaWd1cmUgICANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIG5fc3ViY2F0IDwtIG1vdmVtZW50X3N1YmNhdCAlPiUgDQojICAgZHBseXI6OmRpc3RpbmN0KHN1Yl9jYXRlZ29yeSkgJT4lIA0KIyAgIG5yb3coLikvMTANCiMgDQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJiZWhfbW92ZW1lbnRfc3ViY2F0X2ZpZy5wZGYiLCBwbG90ID0gYmVoX21vdmVtZW50X3N1YmNhdF9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDExLjcqbl9zdWJjYXQpDQpgYGANCg0KSWYgeW91IHdvdWxkIGxpa2UgdG8gbWFrZSBhIGRvdWdobnV0IGNoYXJ0IGhlcmUncyB0aGUgY29kZS4gSG93ZXZlciwgZm9yIGNhdGVnb3JpZXMgdGhhdCBoYXZlIDUgb3IgbW9yZSBzdWItY2F0ZWdvcmllcyBsaWtlIG1vdmVtZW50IEkgZG9uJ3QgdGhpbmsgdGhpcyBpcyB0aGUgY2xlYXJlc3Qgd2F5IHRvIHByZXNlbnQgdGhlIGRhdGEuICAgDQoNCmBgYHtyfQ0KbW92ZW1lbnRfc3ViY2F0ICU+JSANCiAgZHBseXI6OmFycmFuZ2Uoc3ViX2NhdGVnb3J5KSAlPiUNCiAgZHBseXI6OmFycmFuZ2Uoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHltYXggPSBjdW1zdW0ocGVyY2VudF9zdWJfY2F0KSwNCiAgICAgICAgICAgICAgICB5bWluID0gbGFnKHltYXgsMSksDQogICAgICAgICAgICAgICAgeW1pbiA9IGlmX2Vsc2UoaXMubmEoeW1pbiksIDAsIHltaW4pLA0KICAgICAgICAgICAgICAgIGxhYmVsUG9zaXRpb24gPSAoeW1heCt5bWluKS8yLA0KICAgICAgICAgICAgICAgIGxhYmVsID0gaWZfZWxzZShuX3N1Yl9jYXQgPT0gMCwgTkEsIG5fc3ViX2NhdCkpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUNCiAgZ2dwbG90KGFlcyh5bWF4PXltYXgsIHltaW49eW1pbiwgeG1heD00LCB4bWluPTMsIGZpbGw9c3ViX2NhdGVnb3J5KSkgKw0KICBnZW9tX3JlY3QoKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhPSJ5IikgKyANCiAgZ2VvbV9sYWJlbCh4PTQsIGFlcyh5PWxhYmVsUG9zaXRpb24sIGxhYmVsPWxhYmVsKSwgc2l6ZT0zLCBhbHBoYSA9IDAuOCkgKw0KICBmYWNldF93cmFwKH5zdHVkeV9tb3RpdmF0aW9uKSArDQogIHhsaW0oYygyLCA1KSkgKw0KICB0aGVtZV92b2lkKCkgICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQpgYGANCg0KIyMjIyBCb2xkbmVzcyBwbG90cyANCg0KYGBge3J9DQpzdWJfY2F0ZWdvcnlfb3JkZXIgPC0gYmVoYXZfc3ViX2NhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihwYXJlbnRfY2F0ZWdvcnkgPT0gImJvbGRuZXNzIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViX2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obl9zdWJfY2F0KSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShuKSAlPiUgDQogIGRwbHlyOjpwdWxsKHN1Yl9jYXRlZ29yeSkNCg0KYm9sZG5lc3Nfc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJib2xkbmVzcyIpICU+JSANCiAgZHBseXI6OnNlbGVjdChzdHVkeV9tb3RpdmF0aW9uLCBzdWJfY2F0ZWdvcnksIHBlcmNlbnRfc3ViX2NhdCwgbl9zdWJfY2F0LCBwZXJjZW50X3BhcmVudCkgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoc3ViX2NhdGVnb3J5LCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChwZXJjZW50X3N1Yl9jYXQgPSAwLCBuX3N1Yl9jYXQgPSAwKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN1Yl9jYXRlZ29yeSA9IGZhY3RvcihzdWJfY2F0ZWdvcnksIGxldmVscyA9IHN1Yl9jYXRlZ29yeV9vcmRlcikpDQpgYGANCg0KIyMjIyMgRmlnIFM2LTINCg0KYGBge3J9DQpiZWhfYm9sZG5lc3Nfc3ViY2F0X2ZpZyA8LSBib2xkbmVzc19zdWJjYXQgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfc3ViX2NhdCA9IHJvdW5kKHBlcmNlbnRfc3ViX2NhdCwzKSoxMDApICU+JSANCiAgZ2dwbG90KGFlcyh4PXN1Yl9jYXRlZ29yeSwgeT1wZXJjZW50X3N1Yl9jYXQsIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBncm91cCA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB3aWR0aCA9IDAuMSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudF9zdWJfY2F0KSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIsIHBvc2l0aW9uID0gIHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2Ugb2YgZGF0YSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICApDQoNCmJlaF9ib2xkbmVzc19zdWJjYXRfZmlnDQpgYGANCg0KU2F2ZSB0aGUgZmlndXJlIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgbl9zdWJjYXQgPC0gYm9sZG5lc3Nfc3ViY2F0ICU+JSANCiMgICBkcGx5cjo6ZGlzdGluY3Qoc3ViX2NhdGVnb3J5KSAlPiUgDQojICAgbnJvdyguKS8xMA0KIyANCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoImJlaF9ib2xkbmVzc19zdWJjYXRfZmlnLnBkZiIsIHBsb3QgPSBiZWhfYm9sZG5lc3Nfc3ViY2F0X2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTEuNypuX3N1YmNhdCkNCmBgYA0KDQoNCiMjIyMgRm9yYWdpbmcgcGxvdHMgDQoNCmBgYHtyfQ0Kc3ViX2NhdGVnb3J5X29yZGVyIDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJmb3JhZ2luZyIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN1Yl9jYXRlZ29yeSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG5fc3ViX2NhdCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UobikgJT4lIA0KICBkcGx5cjo6cHVsbChzdWJfY2F0ZWdvcnkpDQoNCmZvcmFnaW5nX3N1YmNhdCA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHBhcmVudF9jYXRlZ29yeSA9PSAiZm9yYWdpbmciKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgc3ViX2NhdGVnb3J5LCBwZXJjZW50X3N1Yl9jYXQsIG5fc3ViX2NhdCwgcGVyY2VudF9wYXJlbnQpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKHN1Yl9jYXRlZ29yeSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QocGVyY2VudF9zdWJfY2F0ID0gMCwgbl9zdWJfY2F0ID0gMCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdWJfY2F0ZWdvcnkgPSBmYWN0b3Ioc3ViX2NhdGVnb3J5LCBsZXZlbHMgPSBzdWJfY2F0ZWdvcnlfb3JkZXIpKQ0KYGBgDQoNCiMjIyMjIEZpZyBTNi0zDQoNCmBgYHtyfQ0KYmVoX2ZvcmFnaW5nX3N1YmNhdF9maWcgPC0gZm9yYWdpbmdfc3ViY2F0ICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3N1Yl9jYXQgPSByb3VuZChwZXJjZW50X3N1Yl9jYXQsMykqMTAwKSAlPiUgDQogIGdncGxvdChhZXMoeD1zdWJfY2F0ZWdvcnksIHk9cGVyY2VudF9zdWJfY2F0LCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiwgZ3JvdXAgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjEpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnRfc3ViX2NhdCksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siLCBwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQZXJjZW50YWdlIG9mIGRhdGEiDQogICkgKw0KICAgdGhlbWUoDQogICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICAgKQ0KDQpiZWhfZm9yYWdpbmdfc3ViY2F0X2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgbl9zdWJjYXQgPC0gZm9yYWdpbmdfc3ViY2F0ICU+JSANCiMgICBkcGx5cjo6ZGlzdGluY3Qoc3ViX2NhdGVnb3J5KSAlPiUgDQojICAgbnJvdyguKS8xMA0KIyANCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoImJlaF9mb3JhZ2luZ19zdWJjYXRfZmlnLnBkZiIsIHBsb3QgPSBiZWhfZm9yYWdpbmdfc3ViY2F0X2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTEuNypuX3N1YmNhdCkNCmBgYA0KDQoNCiMjIyMgIEFudGlwcmVkYXRvciBwbG90cyANCg0KYGBge3J9DQpzdWJfY2F0ZWdvcnlfb3JkZXIgPC0gYmVoYXZfc3ViX2NhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihwYXJlbnRfY2F0ZWdvcnkgPT0gImFudGlwcmVkYXRvciIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN1Yl9jYXRlZ29yeSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG5fc3ViX2NhdCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UobikgJT4lIA0KICBkcGx5cjo6cHVsbChzdWJfY2F0ZWdvcnkpDQoNCmFudGlwcmVkYXRvcl9zdWJjYXQgPC0gYmVoYXZfc3ViX2NhdF9zdW1tYXJ5ICU+JSANCiAgZHBseXI6OmZpbHRlcihwYXJlbnRfY2F0ZWdvcnkgPT0gImFudGlwcmVkYXRvciIpICU+JSANCiAgZHBseXI6OnNlbGVjdChzdHVkeV9tb3RpdmF0aW9uLCBzdWJfY2F0ZWdvcnksIHBlcmNlbnRfc3ViX2NhdCwgbl9zdWJfY2F0LCBwZXJjZW50X3BhcmVudCkgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoc3ViX2NhdGVnb3J5LCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChwZXJjZW50X3N1Yl9jYXQgPSAwLCBuX3N1Yl9jYXQgPSAwKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN1Yl9jYXRlZ29yeSA9IGZhY3RvcihzdWJfY2F0ZWdvcnksIGxldmVscyA9IHN1Yl9jYXRlZ29yeV9vcmRlcikpDQpgYGANCg0KIyMjIyMgRmlnIFM2LTQNCg0KYGBge3J9DQpiZWhfYW50aXByZWRhdG9yX3N1YmNhdF9maWcgPC0gYW50aXByZWRhdG9yX3N1YmNhdCAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9zdWJfY2F0ID0gcm91bmQocGVyY2VudF9zdWJfY2F0LDMpKjEwMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9c3ViX2NhdGVnb3J5LCB5PXBlcmNlbnRfc3ViX2NhdCwgY29sb3VyID0gc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IHN0dWR5X21vdGl2YXRpb24sIGdyb3VwID0gc3R1ZHlfbW90aXZhdGlvbikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHdpZHRoID0gMC4xKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIHNpemUgPSAzKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50X3N1Yl9jYXQpLCBoanVzdD0tMC42LCBzaXplPTMuNSwgY29sb3I9ImJsYWNrIiwgcG9zaXRpb24gPSAgcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbW90aXZhdGlvbl9jb2xvdXJfdGhlbWUsIG5hbWUgPSAiU3R1ZHkgbW90aXZhdGlvbiIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgIGxhYnMoDQogICAgeCA9ICIiLA0KICAgIHkgPSAiUGVyY2VudGFnZSBvZiBkYXRhIg0KICApICsNCiAgIHRoZW1lKA0KICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgICkNCg0KYmVoX2FudGlwcmVkYXRvcl9zdWJjYXRfZmlnDQpgYGANCg0KU2F2ZSBmaWd1cmUgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgbl9zdWJjYXQgPC0gYW50aXByZWRhdG9yX3N1YmNhdCAlPiUgDQojICAgZHBseXI6OmRpc3RpbmN0KHN1Yl9jYXRlZ29yeSkgJT4lIA0KIyAgIG5yb3coLikvMTANCiMgDQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJiZWhfYW50aXByZWRhdG9yX3N1YmNhdF9maWcucGRmIiwgcGxvdCA9IGJlaF9hbnRpcHJlZGF0b3Jfc3ViY2F0X2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTEuNypuX3N1YmNhdCkNCmBgYA0KDQoNCiMjIyMgTWF0aW5nIHBsb3RzIA0KDQpgYGB7cn0NCnN1Yl9jYXRlZ29yeV9vcmRlciA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHBhcmVudF9jYXRlZ29yeSA9PSAibWF0aW5nIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3ViX2NhdGVnb3J5KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obl9zdWJfY2F0KSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShuKSAlPiUgDQogIGRwbHlyOjpwdWxsKHN1Yl9jYXRlZ29yeSkNCg0KbWF0aW5nX3N1YmNhdCA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHBhcmVudF9jYXRlZ29yeSA9PSAibWF0aW5nIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHN0dWR5X21vdGl2YXRpb24sIHN1Yl9jYXRlZ29yeSwgcGVyY2VudF9zdWJfY2F0LCBuX3N1Yl9jYXQsIHBlcmNlbnRfcGFyZW50KSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShzdWJfY2F0ZWdvcnksIHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBsaXN0KHBlcmNlbnRfc3ViX2NhdCA9IDAsIG5fc3ViX2NhdCA9IDApKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3ViX2NhdGVnb3J5ID0gZmFjdG9yKHN1Yl9jYXRlZ29yeSwgbGV2ZWxzID0gc3ViX2NhdGVnb3J5X29yZGVyKSkNCmBgYA0KDQojIyMjIyBGaWcgUzYtNQ0KDQpgYGB7cn0NCmJlaF9tYXRpbmdfc3ViY2F0X2ZpZyA8LSBtYXRpbmdfc3ViY2F0ICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3N1Yl9jYXQgPSByb3VuZChwZXJjZW50X3N1Yl9jYXQsMykqMTAwKSAlPiUgDQogIGdncGxvdChhZXMoeD1zdWJfY2F0ZWdvcnksIHk9cGVyY2VudF9zdWJfY2F0LCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiwgZ3JvdXAgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjEpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnRfc3ViX2NhdCksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siLCBwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQZXJjZW50YWdlIG9mIGRhdGEiDQogICkgKw0KICAgdGhlbWUoDQogICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICAgKQ0KDQpiZWhfbWF0aW5nX3N1YmNhdF9maWcNCmBgYA0KDQpTYXZlIHRoZSBmaWd1cmUgICANCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgbl9zdWJjYXQgPC0gbWF0aW5nX3N1YmNhdCAlPiUgDQojICAgZHBseXI6OmRpc3RpbmN0KHN1Yl9jYXRlZ29yeSkgJT4lIA0KIyAgIG5yb3coLikvMTANCiMgDQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJiZWhfbWF0aW5nX3N1YmNhdF9maWcucGRmIiwgcGxvdCA9IGJlaF9tYXRpbmdfc3ViY2F0X2ZpZywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gMTEuNypuX3N1YmNhdCkNCmBgYA0KDQoNCiMjIyMgUG9zdCBtYXRpbmcgcGxvdHMgDQoNCmBgYHtyfQ0Kc3ViX2NhdGVnb3J5X29yZGVyIDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJwb3N0X21hdGluZyIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN1Yl9jYXRlZ29yeSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG5fc3ViX2NhdCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UobikgJT4lIA0KICBkcGx5cjo6cHVsbChzdWJfY2F0ZWdvcnkpDQoNCnBvc3RfbWF0aW5nX3N1YmNhdCA8LSBiZWhhdl9zdWJfY2F0X3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHBhcmVudF9jYXRlZ29yeSA9PSAicG9zdF9tYXRpbmciKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgc3ViX2NhdGVnb3J5LCBwZXJjZW50X3N1Yl9jYXQsIG5fc3ViX2NhdCwgcGVyY2VudF9wYXJlbnQpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKHN1Yl9jYXRlZ29yeSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QocGVyY2VudF9zdWJfY2F0ID0gMCwgbl9zdWJfY2F0ID0gMCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdWJfY2F0ZWdvcnkgPSBmYWN0b3Ioc3ViX2NhdGVnb3J5LCBsZXZlbHMgPSBzdWJfY2F0ZWdvcnlfb3JkZXIpKQ0KYGBgDQoNCiMjIyMjIEZpZyBTNi02DQoNCmBgYHtyfQ0KYmVoX3Bvc3RfbWF0aW5nX3N1YmNhdF9maWcgPC0gcG9zdF9tYXRpbmdfc3ViY2F0ICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3N1Yl9jYXQgPSByb3VuZChwZXJjZW50X3N1Yl9jYXQsMykqMTAwKSAlPiUgDQogIGdncGxvdChhZXMoeD1zdWJfY2F0ZWdvcnksIHk9cGVyY2VudF9zdWJfY2F0LCBjb2xvdXIgPSBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gc3R1ZHlfbW90aXZhdGlvbiwgZ3JvdXAgPSBzdHVkeV9tb3RpdmF0aW9uKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgd2lkdGggPSAwLjEpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgc2l6ZSA9IDMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnRfc3ViX2NhdCksIGhqdXN0PS0wLjYsIHNpemU9My41LCBjb2xvcj0iYmxhY2siLCBwb3NpdGlvbiA9ICBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBtb3RpdmF0aW9uX2NvbG91cl90aGVtZSwgbmFtZSA9ICJTdHVkeSBtb3RpdmF0aW9uIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJQZXJjZW50YWdlIG9mIGRhdGEiDQogICkgKw0KICAgdGhlbWUoDQogICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICAgKQ0KDQpiZWhfcG9zdF9tYXRpbmdfc3ViY2F0X2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBuX3N1YmNhdCA8LSBwb3N0X21hdGluZ19zdWJjYXQgJT4lIA0KIyAgIGRwbHlyOjpkaXN0aW5jdChzdWJfY2F0ZWdvcnkpICU+JSANCiMgICBucm93KC4pLzEwDQojIA0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGdnc2F2ZSgiYmVoX3Bvc3RfbWF0aW5nX3N1YmNhdF9maWcucGRmIiwgcGxvdCA9IGJlaF9wb3N0X21hdGluZ19zdWJjYXRfZmlnLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMS43Km5fc3ViY2F0KQ0KYGBgDQoNCg0KIyMjIyBBZ3Jlc3Npb24gcGxvdHMgDQoNCmBgYHtyfQ0Kc3ViX2NhdGVnb3J5X29yZGVyIDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJhZ3Jlc3Npb24iKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdWJfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKG4pICU+JSANCiAgZHBseXI6OnB1bGwoc3ViX2NhdGVnb3J5KQ0KDQphZ3Jlc3Npb25fc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJhZ3Jlc3Npb24iKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgc3ViX2NhdGVnb3J5LCBwZXJjZW50X3N1Yl9jYXQsIG5fc3ViX2NhdCwgcGVyY2VudF9wYXJlbnQpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKHN1Yl9jYXRlZ29yeSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QocGVyY2VudF9zdWJfY2F0ID0gMCwgbl9zdWJfY2F0ID0gMCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdWJfY2F0ZWdvcnkgPSBmYWN0b3Ioc3ViX2NhdGVnb3J5LCBsZXZlbHMgPSBzdWJfY2F0ZWdvcnlfb3JkZXIpKQ0KYGBgDQoNCiMjIyMjIEZpZyBTNi03DQoNCmBgYHtyfQ0KYmVoX2FncmVzc2lvbl9zdWJjYXRfZmlnIDwtIGFncmVzc2lvbl9zdWJjYXQgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfc3ViX2NhdCA9IHJvdW5kKHBlcmNlbnRfc3ViX2NhdCwzKSoxMDApICU+JSANCiAgZ2dwbG90KGFlcyh4PXN1Yl9jYXRlZ29yeSwgeT1wZXJjZW50X3N1Yl9jYXQsIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBncm91cCA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB3aWR0aCA9IDAuMSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudF9zdWJfY2F0KSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIsIHBvc2l0aW9uID0gIHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2Ugb2YgZGF0YSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICApDQoNCmJlaF9hZ3Jlc3Npb25fc3ViY2F0X2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBuX3N1YmNhdCA8LSBhZ3Jlc3Npb25fc3ViY2F0ICU+JSANCiMgICBkcGx5cjo6ZGlzdGluY3Qoc3ViX2NhdGVnb3J5KSAlPiUgDQojICAgbnJvdyguKS8xMA0KIyANCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoImJlaF9hZ3Jlc3Npb25fc3ViY2F0X2ZpZy5wZGYiLCBwbG90ID0gYmVoX2FncmVzc2lvbl9zdWJjYXRfZmlnLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMS43Km5fc3ViY2F0KQ0KYGBgDQoNCg0KIyMjIyBTb2NpYWxpdHkgcGxvdHMgDQoNCmBgYHtyfQ0Kc3ViX2NhdGVnb3J5X29yZGVyIDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJzb2NpYWxpdHkiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdWJfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKG4pICU+JSANCiAgZHBseXI6OnB1bGwoc3ViX2NhdGVnb3J5KQ0KDQpzb2NpYWxpdHlfc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJzb2NpYWxpdHkiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgc3ViX2NhdGVnb3J5LCBwZXJjZW50X3N1Yl9jYXQsIG5fc3ViX2NhdCwgcGVyY2VudF9wYXJlbnQpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKHN1Yl9jYXRlZ29yeSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QocGVyY2VudF9zdWJfY2F0ID0gMCwgbl9zdWJfY2F0ID0gMCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdWJfY2F0ZWdvcnkgPSBmYWN0b3Ioc3ViX2NhdGVnb3J5LCBsZXZlbHMgPSBzdWJfY2F0ZWdvcnlfb3JkZXIpKQ0KYGBgDQoNCiMjIyMjIEZpZyBTNi04DQoNCmBgYHtyfQ0KYmVoX3NvY2lhbGl0eV9zdWJjYXRfZmlnIDwtIHNvY2lhbGl0eV9zdWJjYXQgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfc3ViX2NhdCA9IHJvdW5kKHBlcmNlbnRfc3ViX2NhdCwzKSoxMDApICU+JSANCiAgZ2dwbG90KGFlcyh4PXN1Yl9jYXRlZ29yeSwgeT1wZXJjZW50X3N1Yl9jYXQsIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBncm91cCA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB3aWR0aCA9IDAuMSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudF9zdWJfY2F0KSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIsIHBvc2l0aW9uID0gIHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2Ugb2YgZGF0YSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICApDQoNCmJlaF9zb2NpYWxpdHlfc3ViY2F0X2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBuX3N1YmNhdCA8LSBzb2NpYWxpdHlfc3ViY2F0ICU+JSANCiMgICBkcGx5cjo6ZGlzdGluY3Qoc3ViX2NhdGVnb3J5KSAlPiUgDQojICAgbnJvdyguKS8xMA0KIyANCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoImJlaF9zb2NpYWxpdHlfc3ViY2F0X2ZpZy5wZGYiLCBwbG90ID0gYmVoX3NvY2lhbGl0eV9zdWJjYXRfZmlnLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMS43Km5fc3ViY2F0KQ0KYGBgDQoNCg0KIyMjIyBDb2duaXRpb24gcGxvdHMgDQoNCmBgYHtyfQ0Kc3ViX2NhdGVnb3J5X29yZGVyIDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJjb2duaXRpb24iKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdWJfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKG4pICU+JSANCiAgZHBseXI6OnB1bGwoc3ViX2NhdGVnb3J5KQ0KDQpjb2duaXRpb25fc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJjb2duaXRpb24iKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgc3ViX2NhdGVnb3J5LCBwZXJjZW50X3N1Yl9jYXQsIG5fc3ViX2NhdCwgcGVyY2VudF9wYXJlbnQpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKHN1Yl9jYXRlZ29yeSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QocGVyY2VudF9zdWJfY2F0ID0gMCwgbl9zdWJfY2F0ID0gMCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdWJfY2F0ZWdvcnkgPSBmYWN0b3Ioc3ViX2NhdGVnb3J5LCBsZXZlbHMgPSBzdWJfY2F0ZWdvcnlfb3JkZXIpKQ0KYGBgDQoNCiMjIyMjIEZpZyBTNi05DQoNCmBgYHtyfQ0KYmVoX2NvZ25pdGlvbl9zdWJjYXRfZmlnIDwtIGNvZ25pdGlvbl9zdWJjYXQgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfc3ViX2NhdCA9IHJvdW5kKHBlcmNlbnRfc3ViX2NhdCwzKSoxMDApICU+JSANCiAgZ2dwbG90KGFlcyh4PXN1Yl9jYXRlZ29yeSwgeT1wZXJjZW50X3N1Yl9jYXQsIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBncm91cCA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB3aWR0aCA9IDAuMSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudF9zdWJfY2F0KSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIsIHBvc2l0aW9uID0gIHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2Ugb2YgZGF0YSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICApDQoNCmJlaF9jb2duaXRpb25fc3ViY2F0X2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBuX3N1YmNhdCA8LSBjb2duaXRpb25fc3ViY2F0ICU+JSANCiMgICBkcGx5cjo6ZGlzdGluY3Qoc3ViX2NhdGVnb3J5KSAlPiUgDQojICAgbnJvdyguKS8xMA0KIyANCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoImJlaF9jb2duaXRpb25fc3ViY2F0X2ZpZy5wZGYiLCBwbG90ID0gYmVoX2NvZ25pdGlvbl9zdWJjYXRfZmlnLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMS43Km5fc3ViY2F0KQ0KYGBgDQoNCiMjIyMgTm9uLWNhdGVnb3JpZXMgcGxvdHMgDQoNCmBgYHtyfQ0Kc3ViX2NhdGVnb3J5X29yZGVyIDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJub25jYXQiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdWJfY2F0ZWdvcnkpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuX3N1Yl9jYXQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKG4pICU+JSANCiAgZHBseXI6OnB1bGwoc3ViX2NhdGVnb3J5KQ0KDQpub25jYXRfc3ViY2F0IDwtIGJlaGF2X3N1Yl9jYXRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIocGFyZW50X2NhdGVnb3J5ID09ICJub25jYXQiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3R1ZHlfbW90aXZhdGlvbiwgc3ViX2NhdGVnb3J5LCBwZXJjZW50X3N1Yl9jYXQsIG5fc3ViX2NhdCwgcGVyY2VudF9wYXJlbnQpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKHN1Yl9jYXRlZ29yeSwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QocGVyY2VudF9zdWJfY2F0ID0gMCwgbl9zdWJfY2F0ID0gMCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdWJfY2F0ZWdvcnkgPSBmYWN0b3Ioc3ViX2NhdGVnb3J5LCBsZXZlbHMgPSBzdWJfY2F0ZWdvcnlfb3JkZXIpKQ0KYGBgDQoNCiMjIyMjIEZpZyBTNi0xMA0KDQoNCmBgYHtyfQ0KYmVoX25vbmNhdF9zdWJjYXRfZmlnIDwtIG5vbmNhdF9zdWJjYXQgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfc3ViX2NhdCA9IHJvdW5kKHBlcmNlbnRfc3ViX2NhdCwzKSoxMDApICU+JSANCiAgZ2dwbG90KGFlcyh4PXN1Yl9jYXRlZ29yeSwgeT1wZXJjZW50X3N1Yl9jYXQsIGNvbG91ciA9IHN0dWR5X21vdGl2YXRpb24sIGZpbGwgPSBzdHVkeV9tb3RpdmF0aW9uLCBncm91cCA9IHN0dWR5X21vdGl2YXRpb24pKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB3aWR0aCA9IDAuMSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBzaXplID0gMykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudF9zdWJfY2F0KSwgaGp1c3Q9LTAuNiwgc2l6ZT0zLjUsIGNvbG9yPSJibGFjayIsIHBvc2l0aW9uID0gIHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG1vdGl2YXRpb25fY29sb3VyX3RoZW1lLCBuYW1lID0gIlN0dWR5IG1vdGl2YXRpb24iKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIGNvb3JkX2ZsaXAoKSArDQogICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2Ugb2YgZGF0YSINCiAgKSArDQogICB0aGVtZSgNCiAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICApDQoNCmJlaF9ub25jYXRfc3ViY2F0X2ZpZw0KYGBgDQoNClNhdmUgdGhlIGZpZ3VyZSAgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIG5fc3ViY2F0IDwtIG5vbmNhdF9zdWJjYXQgJT4lIA0KIyAgIGRwbHlyOjpkaXN0aW5jdChzdWJfY2F0ZWdvcnkpICU+JSANCiMgICBucm93KC4pLzEwDQojIA0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGdnc2F2ZSgiYmVoX25vbmNhdF9zdWJjYXRfZmlnLnBkZiIsIHBsb3QgPSBiZWhfbm9uY2F0X3N1YmNhdF9maWcsIHdpZHRoID0gMTAsIGhlaWdodCA9IDExLjcqbl9zdWJjYXQpDQpgYGANCg0KDQojIyMgQmVoYXZpb3VyIGxvY2F0aW9uIA0KDQpDaGVjayB3aGVyZSBiZWhhdmlvdXIgd2FzIG1lYXN1cmVkLg0KDQpgYGB7cn0NCmJlaGF2X2xvY2F0aW9uX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIGJlaGF2X3Rlc3RfbG9jYXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhiZWhhdl90ZXN0X2xvY2F0aW9uLCBzZXAgPSAiOyIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIGJlaGF2X3Rlc3RfbG9jYXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoYmVoYXZfdGVzdF9sb2NhdGlvbiwgc3R1ZHlfbW90aXZhdGlvbiwgZmlsbCA9IGxpc3QobiA9IDApKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpiZWhhdl9sb2NhdGlvbl9vdmVyYWxsIDwtIGJlaGF2X2xvY2F0aW9uX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYmVoYXZfdGVzdF9sb2NhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSwNCiAgICAgICAgICAgICAgICBzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiKQ0KDQpiZWhhdl9sb2NhdGlvbl9zdW1tYXJ5IDwtICByYmluZChiZWhhdl9sb2NhdGlvbl9vdmVyYWxsLCBiZWhhdl9sb2NhdGlvbl9zdW1tYXJ5KSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKHN0dWR5X21vdGl2YXRpb24pDQoNCmJlaGF2X2xvY2F0aW9uX3N1bW1hcnkgJT4lIA0KICBndCgpDQpgYGANCg0KDQojIyMgU29jaWFsIGNvbnRleHQNCg0KQ2hlY2sgaG93IG9mdGVuIGJlaGF2aW91ciB3YXMgbWVhc3VyZWQgaW4gYSBzb2NpYWwgY29udGV4dCAgIA0KDQpgYGB7cn0NCmJlaGF2X3NvY2lhbF9jb250ZXh0X3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIGJlaGF2X2lzX3NvY2lhbF9jb250ZXh0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmJlaGF2X3NvY2lhbF9jb250ZXh0X292ZXJhbGwgPC0gYmVoYXZfc29jaWFsX2NvbnRleHRfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9pc19zb2NpYWxfY29udGV4dCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSwNCiAgICAgICAgICAgICAgICBzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiKQ0KDQpiZWhhdl9zb2NpYWxfY29udGV4dF9zdW1tYXJ5IDwtICByYmluZChiZWhhdl9zb2NpYWxfY29udGV4dF9vdmVyYWxsLCBiZWhhdl9zb2NpYWxfY29udGV4dF9zdW1tYXJ5KSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKHN0dWR5X21vdGl2YXRpb24pDQoNCmJlaGF2X3NvY2lhbF9jb250ZXh0X3N1bW1hcnkgJT4lIA0KICBndCgpDQpgYGANCg0KDQojIyMgQ2hlY2sgaG93IGJlaGF2aW91ciB3YXMgbWVhc3N1cmVkDQoNCkNoZWNrIGhvdyBvZnRlbiBiZWhhdmlvdXIgd2FzIG1lYXNzdXJlZCBpbiBhIHNvY2lhbCBjb250ZXh0ICANCg0KYGBge3J9DQpiZWhhdl9iZWhhdl9zY29yaW5nX3N1bW1hcnkgPC0gRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCB2YWxpZGl0eV9iZWhhdl9zY29yaW5nX21ldGhvZCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKHZhbGlkaXR5X2JlaGF2X3Njb3JpbmdfbWV0aG9kLCBzZXAgPSAiOyIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHZhbGlkaXR5X2JlaGF2X3Njb3JpbmdfbWV0aG9kKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgdGlkeXI6OmNvbXBsZXRlKHZhbGlkaXR5X2JlaGF2X3Njb3JpbmdfbWV0aG9kLCBzdHVkeV9tb3RpdmF0aW9uLCBmaWxsID0gbGlzdChuID0gMCkpICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0KYmVoYXZfYmVoYXZfc2NvcmluZ19vdmVyYWxsIDwtIGJlaGF2X2JlaGF2X3Njb3Jpbmdfc3VtbWFyeSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9iZWhhdl9zY29yaW5nX21ldGhvZCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSwNCiAgICAgICAgICAgICAgICBzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiKQ0KDQpiZWhhdl9iZWhhdl9zY29yaW5nX3N1bW1hcnkgPC0gIHJiaW5kKGJlaGF2X2JlaGF2X3Njb3Jpbmdfb3ZlcmFsbCwgYmVoYXZfYmVoYXZfc2NvcmluZ19zdW1tYXJ5KSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKHN0dWR5X21vdGl2YXRpb24pDQpgYGANCg0KYGBge3J9DQpiZWhhdl9iZWhhdl9zY29yaW5nX3N1bW1hcnkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0dWR5X21vdGl2YXRpb24gID09ICJPdmVyYWxsIikgJT4lIA0KICBndCgpDQpgYGANCg0KIyMgTGlua2luZyBQSUNPDQoNCk1ha2luZyBhIGRhdGEgZnJhbWUgZm9yIGEgZmxvdyBkaWFncmFtIChzYW5rZXkgcGxvdCkgICANCg0KYGBge3J9DQpQSUNPX2RmIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Om11dGF0ZShiZWhhdl9jYXQgPSBjYXNlX3doZW4oDQogICAgYmVoYXZfbW92ZW1lbnRfYm9vbGVhbiA9PSAxIH4gIk1vdmVtZW50IiwNCiAgICBiZWhhdl9ib2xkbmVzc19ib29sZWFuID09IDEgfiAiQm9sZG5lc3MiLA0KICAgIGJlaGF2X2ZvcmFnaW5nX2Jvb2xlYW4gPT0gMSB+ICJGb3JhZ2luZyIsDQogICAgYmVoYXZfYW50aXByZWRhdG9yX2Jvb2xlYW4gPT0gMSB+ICJBbnRpcHJlZGF0b3IiLA0KICAgIGJlaGF2X21hdGluZ19ib29sZWFuID09IDEgfiAiTWF0aW5nIiwNCiAgICBiZWhhdl9wb3N0X21hdGluZ19ib29sZWFuID09IDEgfiAiUG9zdCBtYXRpbmciLA0KICAgIGJlaGF2X2FncmVzc2lvbl9ib29sZWFuID09IDEgfiAiQWdyZXNzaW9uIiwNCiAgICBiZWhhdl9zb2NpYWxpdHlfYm9vbGVhbiA9PSAxIH4gIlNvY2lhbGl0eSIsDQogICAgYmVoYXZfY29nbml0aW9uX2Jvb2xlYW4gPT0gMSB+ICJDb2duaXRpb24iLA0KICAgIGJlaGF2X25vbmNhdF9ib29sZWFuID09IDEgfiAiTm90IGNhdGVnb3Jpc2VkIiwNCiAgKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHN0dWR5X21vdGl2YXRpb24sIGNvbXBvdW5kX25hbWUsIGNvbXBvdW5kX2F0Y19sZXZlbF8zLCBzcGVjaWVzX25hbWUsIHNwZWNpZXNfY2xhc3MsIGJlaGF2X2NhdCkgDQpgYGANCg0KTGV0J3MgbG9vayBhdCB0aGUgMTAgbW9zdCBjb21tb24gY2xhc3NlcyBhbmQgQVRDcyAgIA0KDQpgYGB7cn0NClBJQ09fY2xhc3NfYXRjIDwtIFBJQ09fZGYgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShjb21wb3VuZF9hdGNfbGV2ZWxfMyksICFpcy5uYShzcGVjaWVzX2NsYXNzKSkgJT4lIA0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyhjb21wb3VuZF9hdGNfbGV2ZWxfMywgc2VwID0gIjsiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoY29tcG91bmRfYXRjX2xldmVsXzMgPSBzdHJfdHJpbShjb21wb3VuZF9hdGNfbGV2ZWxfMykpDQoNClBJQ09fYXRjXzEwIDwtIFBJQ09fY2xhc3NfYXRjICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX2F0Y19sZXZlbF8zKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToxMCkgJT4lIA0KICBkcGx5cjo6cHVsbChjb21wb3VuZF9hdGNfbGV2ZWxfMykNCg0KUElDT19jbGFzc18xMCA8LSBQSUNPX2NsYXNzX2F0YyAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzcGVjaWVzX2NsYXNzKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMToxMCkgJT4lIA0KICBkcGx5cjo6cHVsbChzcGVjaWVzX2NsYXNzKQ0KDQpQSUNPX2NsYXNzXzEwIDwtIFBJQ09fY2xhc3NfYXRjICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfY2xhc3MpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIGRwbHlyOjpzbGljZSgxOjEwKSAlPiUgDQogIGRwbHlyOjpwdWxsKHNwZWNpZXNfY2xhc3MpDQoNCg0KYmVoYXZfY2F0X29yZGVyIDwtIFBJQ09fY2xhc3NfYXRjICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9hdGNfbGV2ZWxfMyAlaW4lIFBJQ09fYXRjXzEwICYgc3BlY2llc19jbGFzcyAlaW4lIFBJQ09fY2xhc3NfMTApICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoYmVoYXZfY2F0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6cHVsbChiZWhhdl9jYXQpDQoNCg0KUElDT19jbGFzc19hdGNfMTAgPC0gUElDT19jbGFzc19hdGMgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX2F0Y19sZXZlbF8zICVpbiUgUElDT19hdGNfMTAgJiBzcGVjaWVzX2NsYXNzICVpbiUgUElDT19jbGFzc18xMCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGNvbXBvdW5kX2F0Y19sZXZlbF8zID0gZmFjdG9yKGNvbXBvdW5kX2F0Y19sZXZlbF8zLCBsZXZlbHMgPSBQSUNPX2F0Y18xMCksDQogICAgICAgICAgICAgICAgc3BlY2llc19jbGFzcyA9IGZhY3RvcihzcGVjaWVzX2NsYXNzLCBsZXZlbHMgPSBQSUNPX2NsYXNzXzEwKSwNCiAgICAgICAgICAgICAgICBiZWhhdl9jYXQgPSBmYWN0b3IoYmVoYXZfY2F0LCBsZXZlbHMgPSBiZWhhdl9jYXRfb3JkZXIpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoY29tcG91bmRfYXRjX2xldmVsXzMsIGJlaGF2X2NhdCwgc3BlY2llc19jbGFzcykNCmBgYA0KDQojIyMjIEZpZyA3DQoNCmBgYHtyfQ0KUElDT19hdGNfY2xhc3Nfc2Fua2V5IDwtIGhpZ2hjaGFydGVyOjpoY2hhcnQoZGF0YV90b19zYW5rZXkoUElDT19jbGFzc19hdGNfMTApLCAic2Fua2V5IikNClBJQ09fYXRjX2NsYXNzX3NhbmtleQ0KYGBgDQoNClNhdmUgaW50ZXJhY3RpdmUgdmVyc2lvbiAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBodG1sd2lkZ2V0czo6c2F2ZVdpZGdldCh3aWRnZXQgPSBQSUNPX2F0Y19jbGFzc19zYW5rZXksIGZpbGUgPSAiUElDT19hdGNfY2xhc3Nfc2Fua2V5Lmh0bWwiKQ0KYGBgDQoNCg0KU2F2ZSBzdGF0aWMgdmVyc2lvbiAgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyAjIE1ha2UgYSB3ZWJzaG90IGluIHBkZiA6IGhpZ2ggcXVhbGl0eSBidXQgY2FuIG5vdCBjaG9vc2UgcHJpbnRlZCB6b25lDQojIHdlYnNob3Q6OndlYnNob3QoIlBJQ09fYXRjX2NsYXNzX3NhbmtleS5odG1sIiAsICJQSUNPX2F0Y19jbGFzc19zYW5rZXkucGRmIiwgZGVsYXkgPSAxMCkNCmBgYA0KDQoNCiMjIyBDb21tb24gY29tcG91bmRzDQoNCkxldHMgdGFrZSBhIGNsb3NlciBsb29rIGF0IHRoZSAzIG1vc3QgY29tbW9uIGNvbXBvdW5kcyAgIA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9uYW1lKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6c2xpY2UoMTozKSAlPiUgDQogIGd0KCkNCmBgYA0KDQoNCiMjIyMgRmx1b3hldGluZSANCg0KYGBge3J9DQpzcHBfb3JkZXIgPC0gUElDT19kZiAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfbmFtZSA9PSAiRmx1b3hldGluZSIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6NSkgJT4lIA0KICBwdWxsKHNwZWNpZXNfbmFtZSkNCg0KYmVoX29yZGVyIDwtIFBJQ09fZGYgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX25hbWUgPT0gIkZsdW94ZXRpbmUiICYgc3BlY2llc19uYW1lICVpbiUgc3BwX29yZGVyKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIHB1bGwoYmVoYXZfY2F0KQ0KDQpQSUNPX2ZsdW94ZXRpbmUgPC0gUElDT19kZiAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfbmFtZSA9PSAiRmx1b3hldGluZSIgJiBzcGVjaWVzX25hbWUgJWluJSBzcHBfb3JkZXIpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICAgICAgICAgICAgICBzcGVjaWVzX25hbWUgPSBmYWN0b3Ioc3BlY2llc19uYW1lLCBsZXZlbHMgPSBzcHBfb3JkZXIpLA0KICAgICAgICAgICAgICAgIGJlaGF2X2NhdCA9IGZhY3RvcihiZWhhdl9jYXQsIGxldmVscyA9IGJlaF9vcmRlciksDQogICkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHNwZWNpZXNfbmFtZSwgYmVoYXZfY2F0KQ0KYGBgDQoNCiMjIyMjIEZpZyBTNy0xDQoNCmBgYHtyfQ0KUElDT19mbHVveGV0aW5lX3NhbmtleSA8LSBoaWdoY2hhcnRlcjo6aGNoYXJ0KGRhdGFfdG9fc2Fua2V5KFBJQ09fZmx1b3hldGluZSksICJzYW5rZXkiLCBuYW1lID0gIlBJQ08iKQ0KUElDT19mbHVveGV0aW5lX3NhbmtleQ0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGh0bWx3aWRnZXRzOjpzYXZlV2lkZ2V0KHdpZGdldCA9IFBJQ09fZmx1b3hldGluZV9zYW5rZXksIGZpbGUgPSAiUElDT19mbHVveGV0aW5lX3NhbmtleS5odG1sIikNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojICMgTWFrZSBhIHdlYnNob3QgaW4gcGRmIDogaGlnaCBxdWFsaXR5IGJ1dCBjYW4gbm90IGNob29zZSBwcmludGVkIHpvbmUNCiMgd2Vic2hvdDo6d2Vic2hvdCgiUElDT19mbHVveGV0aW5lX3NhbmtleS5odG1sIiAsICJQSUNPX2ZsdW94ZXRpbmVfc2Fua2V5LnBkZiIsIGRlbGF5ID0gMTApDQpgYGANCg0KDQojIyMjIERpYXplcGFtIA0KDQpgYGB7cn0NCnNwcF9vcmRlciA8LSBQSUNPX2RmICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9uYW1lID09ICJEaWF6ZXBhbSIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6NSkgJT4lIA0KICBwdWxsKHNwZWNpZXNfbmFtZSkNCg0KYmVoX29yZGVyIDwtIFBJQ09fZGYgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX25hbWUgPT0gIkRpYXplcGFtIiAmIHNwZWNpZXNfbmFtZSAlaW4lIHNwcF9vcmRlcikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoYmVoYXZfY2F0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBwdWxsKGJlaGF2X2NhdCkNCg0KUElDT19kaWF6ZXBhbSA8LSBQSUNPX2RmICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9uYW1lID09ICJEaWF6ZXBhbSIgJiBzcGVjaWVzX25hbWUgJWluJSBzcHBfb3JkZXIpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICAgICAgICAgICAgICBzcGVjaWVzX25hbWUgPSBmYWN0b3Ioc3BlY2llc19uYW1lLCBsZXZlbHMgPSBzcHBfb3JkZXIpLA0KICAgICAgICAgICAgICAgIGJlaGF2X2NhdCA9IGZhY3RvcihiZWhhdl9jYXQsIGxldmVscyA9IGJlaF9vcmRlciksDQogICkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHNwZWNpZXNfbmFtZSwgYmVoYXZfY2F0KQ0KYGBgDQoNCg0KIyMjIyMgRmlnIFM3LTINCg0KYGBge3J9DQpQSUNPX2RpYXplcGFtX3NhbmtleSA8LSBoaWdoY2hhcnRlcjo6aGNoYXJ0KGRhdGFfdG9fc2Fua2V5KFBJQ09fZGlhemVwYW0pLCAic2Fua2V5IiwgbmFtZSA9ICJQSUNPIikNClBJQ09fZGlhemVwYW1fc2Fua2V5DQpgYGANCg0KU2F2ZSBpbnRlcmFjdGl2ZSBwbG90ICAgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojIGh0bWx3aWRnZXRzOjpzYXZlV2lkZ2V0KHdpZGdldCA9IFBJQ09fZGlhemVwYW1fc2Fua2V5LCBmaWxlID0gIlBJQ09fZGlhemVwYW1fc2Fua2V5Lmh0bWwiKQ0KYGBgDQoNClNhdmUgc3RhdGljIHBsb3QgICANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgTWFrZSBhIHdlYnNob3QgaW4gcGRmIDogaGlnaCBxdWFsaXR5IGJ1dCBjYW4gbm90IGNob29zZSBwcmludGVkIHpvbmUNCiMgd2Vic2hvdDo6d2Vic2hvdCgiUElDT19kaWF6ZXBhbV9zYW5rZXkuaHRtbCIgLCAiUElDT19kaWF6ZXBhbV9zYW5rZXkucGRmIiwgZGVsYXkgPSAxMCkNCmBgYA0KDQoNCiMjIyMgMTctYWxwaGEtZXRoaW55bGVzdHJhZGlvbCANCg0KYGBge3J9DQpzcHBfb3JkZXIgPC0gUElDT19kZiAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoY29tcG91bmRfbmFtZSA9PSAiMTctYWxwaGEtZXRoaW55bGVzdHJhZGlvbCIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfbmFtZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKGRlc2MobikpICU+JSANCiAgZHBseXI6OnNsaWNlKDE6NSkgJT4lIA0KICBwdWxsKHNwZWNpZXNfbmFtZSkNCg0KYmVoX29yZGVyIDwtIFBJQ09fZGYgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX25hbWUgPT0gIjE3LWFscGhhLWV0aGlueWxlc3RyYWRpb2wiICYgc3BlY2llc19uYW1lICVpbiUgc3BwX29yZGVyKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShkZXNjKG4pKSAlPiUgDQogIHB1bGwoYmVoYXZfY2F0KQ0KDQpQSUNPX0VFMiA8LSBQSUNPX2RmICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9uYW1lID09ICIxNy1hbHBoYS1ldGhpbnlsZXN0cmFkaW9sIiAmIHNwZWNpZXNfbmFtZSAlaW4lIHNwcF9vcmRlcikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgICAgICAgICAgICAgIHNwZWNpZXNfbmFtZSA9IGZhY3RvcihzcGVjaWVzX25hbWUsIGxldmVscyA9IHNwcF9vcmRlciksDQogICAgICAgICAgICAgICAgYmVoYXZfY2F0ID0gZmFjdG9yKGJlaGF2X2NhdCwgbGV2ZWxzID0gYmVoX29yZGVyKSwNCiAgKSAlPiUgDQogIGRwbHlyOjpzZWxlY3Qoc3BlY2llc19uYW1lLCBiZWhhdl9jYXQpDQpgYGANCg0KDQojIyMjIyBGaWcgUzctMw0KDQpgYGB7cn0NClBJQ09fRUUyX3NhbmtleSA8LSBoaWdoY2hhcnRlcjo6aGNoYXJ0KGRhdGFfdG9fc2Fua2V5KFBJQ09fRUUyKSwgInNhbmtleSIsIG5hbWUgPSAiUElDTyIpDQpQSUNPX0VFMl9zYW5rZXkNCmBgYA0KDQpTYXZlIGludGVyYWN0aXZlIHBsb3QgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBodG1sd2lkZ2V0czo6c2F2ZVdpZGdldCh3aWRnZXQgPSBQSUNPX0VFMl9zYW5rZXksIGZpbGUgPSAiUElDT19FRTJfc2Fua2V5Lmh0bWwiKQ0KYGBgDQoNCg0KU2F2ZSBzdGF0aWMgcGxvdCAgDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBzZXR3ZChmaWd1cmVzX3BhdGgpDQojICNNYWtlIGEgd2Vic2hvdCBpbiBwZGYgOiBoaWdoIHF1YWxpdHkgYnV0IGNhbiBub3QgY2hvb3NlIHByaW50ZWQgem9uZQ0KIyB3ZWJzaG90Ojp3ZWJzaG90KCJQSUNPX0VFMl9zYW5rZXkuaHRtbCIgLCAiUElDT19FRTJfc2Fua2V5LnBkZiIsIGRlbGF5ID0gMTApDQpgYGANCg0KIyMgS25vd2xlZGdlIGNsdXN0ZXJzIGFuZCBnYXBzDQoNCklkZW50aWZ5IGtub3dsZWRnZSBjbHVzdGVycyBhbmQgZ2Fwcy4NCg0KV2Ugd2lsbCBhbHNvIGRvIHRoaXMgYnkgc3R1ZHkgbW90aXZhdGlvbiwgYmVjYXVzZSB0aGUga25vd2xlZGdlIGdhcHMgd2lsbCBiZSBtb3RpdmF0aW9uIHNwZWNpZmljLiANCg0KIyMjIFNwZWNpZXMgY2xhc3MNCg0KRmlyc3QgbG9vayBieSBzcGVjaWVzIGNsYXNzDQoNCk1ha2luZyBhIGRhdGEgZnJhbWUgICANCg0KYGBge3J9DQpiZWhhdl9jYXRfY2xhc3NfbG9uZyA8LSBQSUNPX2RmICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24sIHNwZWNpZXNfY2xhc3MsIGJlaGF2X2NhdCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShjb3VudCA9IG4oKSkgJT4lIA0KICB0aWR5cjo6Y29tcGxldGUoc3R1ZHlfbW90aXZhdGlvbiwgc3BlY2llc19jbGFzcywgYmVoYXZfY2F0LCBmaWxsID0gbGlzdChjb3VudCA9IDApKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBzcGVjaWVzX2NsYXNzKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfY2xhc3NfbW90aXZhdGlvbiA9IHN1bShjb3VudCkpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocmVsX3BlcmNlbnQgPSByb3VuZChjb3VudC90b3RhbF9jbGFzc19tb3RpdmF0aW9uKjEwMCwwKSwNCiAgICAgICAgICAgICAgICByZWxfcGVyY2VudCA9IGlmX2Vsc2UoaXMuZmluaXRlKHJlbF9wZXJjZW50KSwgcmVsX3BlcmNlbnQsIDApDQogICkNCg0KY2xhc3Nfb3JkZXIgPC0gYmVoYXZfY2F0X2NsYXNzX2xvbmcgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19jbGFzcykgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKGNvdW50KSkgJT4lIA0KICBkcGx5cjo6YXJyYW5nZShuKSAlPiUgDQogIGRwbHlyOjpwdWxsKHNwZWNpZXNfY2xhc3MpDQoNCmJlaGF2X2NhdF9vcmRlciA8LSBiZWhhdl9jYXRfY2xhc3NfbG9uZyAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShjb3VudCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6cHVsbChiZWhhdl9jYXQpDQoNCmJlaGF2X2NhdF9jbGFzc19sb25nIDwtIGJlaGF2X2NhdF9jbGFzc19sb25nICU+JSANCiAgZHBseXI6Om11dGF0ZShzcGVjaWVzX2NsYXNzID0gZmFjdG9yKHNwZWNpZXNfY2xhc3MsIGxldmVscyA9IGNsYXNzX29yZGVyKSwNCiAgICAgICAgICAgICAgICBiZWhhdl9jYXQgPSBmYWN0b3IoYmVoYXZfY2F0LCBsZXZlbHMgPSBiZWhhdl9jYXRfb3JkZXIpDQogICAgICAgICAgICAgICAgKQ0KYGBgDQoNCkNyZWF0aW5nIGEgdGlsZSBwbG90ICAgIA0KDQpgYGB7cn0NCmN1c3RfY29sIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygiI0ZERURGNCIsICIjRjA2OEE3IikpKDMwKQ0KDQpiZWhhdl9jbGFzc19obSA8LSBiZWhhdl9jYXRfY2xhc3NfbG9uZyAlPiUgDQogIGdncGxvdChhZXMoeCA9IGJlaGF2X2NhdCwgeSA9IHNwZWNpZXNfY2xhc3MsIGZpbGwgPSBjb3VudCkpICsNCiAgZ2VvbV90aWxlKCkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnMgPSBjdXN0X2NvbCwgbmEudmFsdWUgPSAid2hpdGUiLCBsaW1pdHMgPSBjKDEsIG1heChiZWhhdl9jYXRfY2xhc3NfbG9uZyRjb3VudCwgbmEucm0gPSBUUlVFKSksIGd1aWRlID0gIm5vbmUiKSArDQogIHRoZW1lX2J3KCkgKw0KICBmYWNldF93cmFwKH5zdHVkeV9tb3RpdmF0aW9uKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsNCiAgbGFicygNCiAgICB4ID0gIkJlaGF2aW91ciIsDQogICAgeSA9ICJTcGVjaWVzIENsYXNzIiwNCiAgICBmaWxsID0gIkNvdW50Ig0KICApDQpiZWhhdl9jbGFzc19obQ0KYGBgDQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJiZWhhdl9jbGFzc19obS5wZGYiLCBwbG90ID0gYmVoYXZfY2xhc3NfaG0sIHdpZHRoID0gOC4zLCBoZWlnaHQgPSAxMS43LzIpDQpgYGANCg0KDQpUaGlzIG9uZSB1c2VzIHJlbGF0aXZlIHZhdWxlcyBmb3IgZWFjaCBjbGFzcyAoZS5nLiByb3cgaW4gdGhlIGhlYXQgbWFwKQ0KDQpgYGB7cn0NCmN1c3RfY29sIDwtIGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg0LCAiT3JhbmdlcyIpKSgzMCkNCg0KYmVoYXZfY2xhc3NfcmVsX2htIDwtIGJlaGF2X2NhdF9jbGFzc19sb25nICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gYmVoYXZfY2F0LCB5ID0gc3BlY2llc19jbGFzcywgZmlsbCA9IHJlbF9wZXJjZW50KSkgKw0KICBnZW9tX3RpbGUoKSArDQogI2dlb21fdGV4dChhZXMobGFiZWwgPSBpZmVsc2UocmVsX3BlcmNlbnQgPT0gMCwgTkEsIHJlbF9wZXJjZW50KSksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzID0gY3VzdF9jb2wsIG5hLnZhbHVlID0gIndoaXRlIiwgbGltaXRzID0gYygxLCBtYXgoYmVoYXZfY2F0X2NsYXNzX2xvbmckY291bnQsIG5hLnJtID0gVFJVRSkpLCBndWlkZSA9ICJub25lIikgKw0KICB0aGVtZV9idygpICsNCiAgZmFjZXRfd3JhcCh+c3R1ZHlfbW90aXZhdGlvbikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArDQogIGxhYnMoDQogICAgeCA9ICJCZWhhdmlvdXIiLA0KICAgIHkgPSAiU3BlY2llcyBDbGFzcyIsDQogICAgZmlsbCA9ICJDb3VudCINCiAgKQ0KYmVoYXZfY2xhc3NfcmVsX2htDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIHNldHdkKGZpZ3VyZXNfcGF0aCkNCiMgZ2dzYXZlKCJiZWhhdl9jbGFzc19yZWxfaG0ucGRmIiwgcGxvdCA9IGJlaGF2X2NsYXNzX3JlbF9obSwgd2lkdGggPSA4LjMsIGhlaWdodCA9IDExLjcvMikNCmBgYA0KDQoNCiMjIyBDb21wb3VuZCBjbHVzdGVyL2dhcHMNCg0KTm93IGxvb2tpbmcgYnkgY29tcG91bmQgICANCg0KTWFraW5nIGEgZGF0YSBmcmFtZSAgDQoNCmBgYHtyfQ0KYmVoYXZfYXRjX2xvbmcgPC0gUElDT19kZiAlPiUgDQogIHNlcGFyYXRlX3Jvd3MoY29tcG91bmRfYXRjX2xldmVsXzMsIHNlcCA9ICI7IikgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBjb21wb3VuZF9hdGNfbGV2ZWxfMywgYmVoYXZfY2F0KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKGNvdW50ID0gbigpKSAlPiUgDQogIHRpZHlyOjpjb21wbGV0ZShzdHVkeV9tb3RpdmF0aW9uLCBjb21wb3VuZF9hdGNfbGV2ZWxfMywgYmVoYXZfY2F0LCBmaWxsID0gbGlzdChjb3VudCA9IDApKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uLCBjb21wb3VuZF9hdGNfbGV2ZWxfMykgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX2F0Y19tb3RpdmF0aW9uID0gc3VtKGNvdW50KSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShyZWxfcGVyY2VudCA9IHJvdW5kKGNvdW50L3RvdGFsX2F0Y19tb3RpdmF0aW9uKjEwMCwwKSwNCiAgICAgICAgICAgICAgICByZWxfcGVyY2VudCA9IGlmX2Vsc2UoaXMuZmluaXRlKHJlbF9wZXJjZW50KSwgcmVsX3BlcmNlbnQsIDApDQogICkNCg0KYXRjX29yZGVyIDwtIGJlaGF2X2F0Y19sb25nICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX2F0Y19sZXZlbF8zKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0oY291bnQpKSAlPiUgDQogIGRwbHlyOjphcnJhbmdlKG4pICU+JSANCiAgZHBseXI6OnB1bGwoY29tcG91bmRfYXRjX2xldmVsXzMpDQoNCmJlaGF2X2NhdF9vcmRlciA8LSBiZWhhdl9hdGNfbG9uZyAlPiUgDQogIGRwbHlyOjpncm91cF9ieShiZWhhdl9jYXQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShjb3VudCkpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoZGVzYyhuKSkgJT4lIA0KICBkcGx5cjo6cHVsbChiZWhhdl9jYXQpDQoNCmJlaGF2X2F0Y19sb25nIDwtIGJlaGF2X2F0Y19sb25nICU+JSANCiAgZHBseXI6Om11dGF0ZShjb21wb3VuZF9hdGNfbGV2ZWxfMyA9IGZhY3Rvcihjb21wb3VuZF9hdGNfbGV2ZWxfMywgbGV2ZWxzID0gYXRjX29yZGVyKSwNCiAgICAgICAgICAgICAgICBiZWhhdl9jYXQgPSBmYWN0b3IoYmVoYXZfY2F0LCBsZXZlbHMgPSBiZWhhdl9jYXRfb3JkZXIpDQogICAgICAgICAgICAgICAgKQ0KYGBgDQoNClRoZXJlIGFyZSAxMzIgQVRDIGxldmVsIDMgY29kZXMuIFNvIGEgdGlsZSBwbG90IGlzIG5vdCBnb2luZyB0byBiZSB2ZXJ5IGluZm9ybWF0aXZlLiBJdCBjb3VsZCBiZSB1c2VmdWwgaWYgeW91IGFyZSBvbmx5IGludGVyZXN0ZWQgaW4gYSBmZXcgQVRDIGdyb3Vwcy4gICANCg0KYGBge3J9DQpiZWhhdl9hdGNfbG9uZyAlPiUgDQogIGRwbHlyOjpkaXN0aW5jdChjb21wb3VuZF9hdGNfbGV2ZWxfMykgJT4lIA0KICBucm93KCkNCmBgYA0KDQpDb2RlIGZvciB0aXRsZSBwbG90IGlmIHlvdSB3b3VsZCBsaWtlIHRvIG1ha2Ugb25lLiANCg0KYGBge3J9DQojIGN1c3RfY29sIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygiI0ZERURGNCIsICIjRjA2OEE3IikpKDMwKQ0KIyANCiMgYmVoYXZfYXRjX2htIDwtIGJlaGF2X2F0Y19sb25nICU+JSANCiMgICBnZ3Bsb3QoYWVzKHggPSBiZWhhdl9jYXQsIHkgPSBjb21wb3VuZF9hdGNfbGV2ZWxfMywgZmlsbCA9IGNvdW50KSkgKw0KIyAgIGdlb21fdGlsZSgpICsNCiMgICAjZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGlmZWxzZShjb3VudCA9PSAwLCBOQSwgY291bnQpKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMykgKw0KIyAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGN1c3RfY29sLCBuYS52YWx1ZSA9ICJ3aGl0ZSIsIGxpbWl0cyA9IGMoMSwgbWF4KGJlaGF2X2F0Y19sb25nJGNvdW50LCBuYS5ybSA9IFRSVUUpKSwgZ3VpZGUgPSAibm9uZSIpICsNCiMgICB0aGVtZV92b2lkKCkgKw0KIyAgIGZhY2V0X3dyYXAofnN0dWR5X21vdGl2YXRpb24pICsNCiMgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArDQojICAgbGFicygNCiMgICAgIHggPSAiQmVoYXZpb3VyIiwNCiMgICAgIHkgPSAiU3BlY2llcyBDbGFzcyIsDQojICAgICBmaWxsID0gIkNvdW50Ig0KIyAgICkNCiMgYmVoYXZfYXRjX2htDQpgYGANCg0KU2F2ZSBmaWd1cmUgIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgc2V0d2QoZmlndXJlc19wYXRoKQ0KIyBnZ3NhdmUoImJlaGF2X2F0Y19obS5wZGYiLCBwbG90ID0gYmVoYXZfYXRjX2htLCB3aWR0aCA9IDguMywgaGVpZ2h0ID0gMTEuNy8yKQ0KYGBgDQoNCg0KIyMgQWRkaXRpb25hbCBiaW9tYXJrZXJzDQoNCkhvdyBtYW55IG1lYXNzdXJlZCBhZGR0aW9uYWwgYmlvbWFya3MgIA0KDQpgYGB7cn0NCkVJUEFBQl9kYXRhYmFzZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShhZGRpdGlvbmFsX2Jpb21hcmtlcnMpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsID0gc3VtKG4pLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSBuL3RvdGFsKSAlPiUgDQogIGd0KCkNCmBgYA0KDQpIb3cgbWFueSBtZWFzdXJlZCBzdXJ2aXZhbC9ncm93dGgvcmVwcm9kdWN0aW9uICAgDQoNCmBgYHtyfQ0KRUlQQUFCX2RhdGFiYXNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X3N1cnZpdmFsX2dyb3d0aF9yZXByb2R1Y3Rpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsID0gc3VtKG4pLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSBuL3RvdGFsKSAlPiUgDQogIGd0KCkNCmBgYA0KDQojIyBWYWxpZGl0eQ0KDQoNClRoZXJlIGFyZSAxOSBtZXRhZGF0YSBjb2x1bW5zIHJlbGF0aW5nIHRvIHZhbGlkdHk6ICJ2YWxpZGl0eV9ndWlkZWxpbmUiLCAidmFsaWRpdHlfZ29vZF9sYWJvcmF0b3J5X3ByYWN0aWNlIiwgInZhbGlkaXR5X3N1cnZpdmFsX2dyb3d0aF9yZXByb2R1Y3Rpb24iLCAidmFsaWRpdHlfYW5pbWFsX2ZlZWRpbmciLCAidmFsaWRpdHlfd2F0ZXJfcXVhbGl0eSIsICJ2YWxpZGl0eV9saWdodF9jeWNsZSIsICJ2YWxpZGl0eV9yYW5kb21pemF0aW9uIiwgInZhbGlkaXR5X2JlaGF2X3Njb3JpbmdfbWV0aG9kIiwgInZhbGlkaXR5X2JlaGF2X2JsaW5kaW5nIiwgInZhbGlkaXR5X2NvbmZsaWN0X3N0YXRlbWVudCIsICJzcGVjaWVzX3NvdXJjZSIsICJzcGVjaWVzX3N0YWdlIiwgInNwZWNpZXNfc2V4IiwgImNvbXBvdW5kX21pbl9kdXJhdGlvbl9leHBvc3VyZSIsICJjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUiLCAidmFsaWRpdHlfY29tcG91bmRfY2FzX3JlcG9ydGVkIiwgInZhbGlkaXR5X2NvbXBvdW5kX3B1cml0eV9yZXBvcnRlZCIsICJ2YWxpZGl0eV9jb21wb3VuZF93YXRlcl92ZXJpZmljYXRpb24iLCAidmFsaWRpdHlfY29tcG91bmRfYW5pbWFsX3ZlcmlmaWNhdGlvbiIuICAgDQoNCiMjIyBEaWQgaXQgZm9sbG93IGEgZ3VpZGVsaW5lIChDUkVEIFExKQ0KDQpgYGB7cn0NCmd1aWRlbGluZSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfZ3VpZGVsaW5lLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmd1aWRlbGluZV9hbGwgPC0gIGd1aWRlbGluZSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9ndWlkZWxpbmUpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkNCiAgDQoNCmd1aWRlbGluZV9hbGwgPC0gcmJpbmQoZ3VpZGVsaW5lX2FsbCwgZ3VpZGVsaW5lKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIodmFsaWRpdHlfZ3VpZGVsaW5lID09ICJZZXMiKQ0KZ3VpZGVsaW5lX2FsbCAlPiUgDQogIGd0KCkNCmBgYA0KDQoNCiMjIyBEaWQgaXQgdXNlIGdvb2QgbGFib3JhdG9yeSBwcmFjdGljZSAoQ1JFRCBRMikNCg0KYGBge3J9DQpHTFAgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2dvb2RfbGFib3JhdG9yeV9wcmFjdGljZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpHTFBfYWxsIDwtICBHTFAgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfZ29vZF9sYWJvcmF0b3J5X3ByYWN0aWNlKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0KR0xQX2FsbCA8LSByYmluZChHTFBfYWxsLCBHTFApICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9nb29kX2xhYm9yYXRvcnlfcHJhY3RpY2UgPT0gIlllcyIpDQpHTFBfYWxsICU+JSANCiAgZ3QoKQ0KYGBgDQoNCg0KIyMjIERpZCBpdCByZXBvcnQgc3Vydml2YWwsIGdyb3d0aCBhbmQvb3IgcmVwcm9kdWN0aW9uIChDUkVEIFEzKQ0KDQoNCmBgYHtyfQ0Kc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbiwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpzdXJ2aXZhbF9ncm93dGhfcmVwcm9kdWN0aW9uX2FsbCA8LSAgc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbiAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9zdXJ2aXZhbF9ncm93dGhfcmVwcm9kdWN0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpDQogIA0KDQpzdXJ2aXZhbF9ncm93dGhfcmVwcm9kdWN0aW9uX2FsbCA8LSByYmluZChzdXJ2aXZhbF9ncm93dGhfcmVwcm9kdWN0aW9uX2FsbCwgc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbikgICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9zdXJ2aXZhbF9ncm93dGhfcmVwcm9kdWN0aW9uID09ICJZZXMiKQ0Kc3Vydml2YWxfZ3Jvd3RoX3JlcHJvZHVjdGlvbl9hbGwgJT4lIA0KICBndCgpDQpgYGANCg0KDQojIyMgRGlkIGl0IHJlcG9ydCBjb21wb3VuZCBjYXMgKENSRUQgUTUpDQoNCmBgYHtyfQ0KQ0FTIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9jb21wb3VuZF9jYXNfcmVwb3J0ZWQsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0KQ0FTX2FsbCA8LSAgQ0FTICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2NvbXBvdW5kX2Nhc19yZXBvcnRlZCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIiwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKQ0KICANCg0KQ0FTX2FsbCA8LSByYmluZChDQVNfYWxsLCBDQVMpICAlPiUgDQogIGRwbHlyOjpmaWx0ZXIodmFsaWRpdHlfY29tcG91bmRfY2FzX3JlcG9ydGVkID09ICJZZXMiKQ0KQ0FTX2FsbCAlPiUgDQogIGd0KCkNCmBgYA0KDQojIyMgRGlkIGl0IHJlcG9ydCBjb21wb3VuZCBwdXJpdHkgKENSRUQgUTYpDQoNCmBgYHtyfQ0KcHVyaXR5IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9jb21wb3VuZF9wdXJpdHlfcmVwb3J0ZWQsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0KcHVyaXR5X2FsbCA8LSAgcHVyaXR5ICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2NvbXBvdW5kX3B1cml0eV9yZXBvcnRlZCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIiwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKSANCiAgDQoNCnB1cml0eV9hbGwgPC0gcmJpbmQocHVyaXR5X2FsbCwgcHVyaXR5KSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIodmFsaWRpdHlfY29tcG91bmRfcHVyaXR5X3JlcG9ydGVkID09ICJZZXMiKQ0KcHVyaXR5X2FsbCAlPiUgDQogIGd0KCkNCmBgYA0KDQojIyMgU3BlY2llcyBpbmZvbWFydGlvbiAgKENSRUQgUTgpDQoNCiMjIyMgTGlmZSBzdGFnZQ0KDQpgYGB7cn0NCnN0YWdlIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KHVuaXF1ZV9wb3B1bGF0aW9uX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zdGFnZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIHRpZHlyOjpzZXBhcmF0ZV9yb3dzKHNwZWNpZXNfc3RhZ2UsIHNlcCA9ICI7IikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zdGFnZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpzdGFnZV9hbGwgPC0gIHN0YWdlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc3RhZ2UpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkNCiAgDQoNCnN0YWdlX2FsbCA8LSByYmluZChzdGFnZV9hbGwsIHN0YWdlKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoc3BlY2llc19zdGFnZSA9PSAiVW5rbm93biBvciBub3Qgc3BlY2lmaWVkIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfcmVwb3J0ZWQgPSAxMDAtcGVyY2VudCkNCnN0YWdlX2FsbCAlPiUgDQogIGd0KCkNCmBgYA0KDQojIyMjIFNleA0KDQpgYGB7cn0NCnNleCA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieSh1bmlxdWVfcG9wdWxhdGlvbl9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc2V4LCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3Moc3BlY2llc19zZXgsIHNlcCA9ICI7IikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zZXgsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0Kc2V4X2FsbCA8LSAgc2V4ICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc2V4KSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpDQogIA0KDQpzZXhfYWxsIDwtIHJiaW5kKHNleF9hbGwsIHNleCkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHNwZWNpZXNfc2V4ID09ICJVbmtub3duIG9yIG5vdCBzcGVjaWZpZWQiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9yZXBvcnRlZCA9IDEwMC1wZXJjZW50KQ0Kc2V4X2FsbCAlPiUgDQogIGd0KCkNCmBgYA0KDQojIyMgVGhlIHNvcnVjZSBvZiBzcGVjaWVzIChDUkVEIFE5KQ0KDQpgYGB7cn0NCnNvdXJjZSA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieSh1bmlxdWVfcG9wdWxhdGlvbl9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc291cmNlLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgdGlkeXI6OnNlcGFyYXRlX3Jvd3Moc3BlY2llc19zb3VyY2UsIHNlcCA9ICI7IikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3BlY2llc19zb3VyY2UsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0Kc291cmNlX2FsbCA8LSAgc291cmNlICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHNwZWNpZXNfc291cmNlKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpDQogIA0KDQpzb3VyY2VfYWxsIDwtIHJiaW5kKHNvdXJjZV9hbGwsIHNvdXJjZSkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHNwZWNpZXNfc291cmNlID09ICJOb3QgcmVwb3J0ZWQiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9yZXBvcnRlZCA9IDEwMC1wZXJjZW50KQ0Kc291cmNlX2FsbCAlPiUgDQogIGd0KCkNCmBgYA0KDQojIyMgZXhwZXJpbWVudGFsIHN5c3RlbSAoQ1JFRCBRMTEpDQoNCiMjIyMgRmVlZGluZw0KDQpgYGB7cn0NCmZlZWRpbmcgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2FuaW1hbF9mZWVkaW5nLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmZlZWRpbmdfYWxsIDwtICBmZWVkaW5nICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2FuaW1hbF9mZWVkaW5nKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0KZmVlZGluZ19hbGwgPC0gcmJpbmQoZmVlZGluZ19hbGwsIGZlZWRpbmcpICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9hbmltYWxfZmVlZGluZyA9PSAiWWVzIikNCmZlZWRpbmdfYWxsICU+JSANCiAgZ3QoKQ0KYGBgDQoNCiMjIyMgV2F0ZXIgcXVhbGl0eQ0KDQpgYGB7cn0NCndhdGVyIDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV93YXRlcl9xdWFsaXR5LCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCndhdGVyX2FsbCA8LSAgd2F0ZXIgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfd2F0ZXJfcXVhbGl0eSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIiwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKSANCiAgDQoNCndhdGVyX2FsbCA8LSByYmluZCh3YXRlcl9hbGwsIHdhdGVyKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIodmFsaWRpdHlfd2F0ZXJfcXVhbGl0eSA9PSAiWWVzIikNCndhdGVyX2FsbCAlPiUgDQogIGd0KCkNCmBgYA0KDQojIyMjIGxpZ2h0IGN5Y2xlDQogDQpgYGB7cn0NCmxpZ2h0IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9saWdodF9jeWNsZSwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpsaWdodF9hbGwgPC0gIGxpZ2h0ICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2xpZ2h0X2N5Y2xlKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0KbGlnaHRfYWxsIDwtIHJiaW5kKGxpZ2h0X2FsbCwgbGlnaHQpICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9saWdodF9jeWNsZSA9PSAiWWVzIikNCmxpZ2h0X2FsbCAlPiUgDQogIGd0KCkNCmBgYA0KDQoNCiMjIyBFeHBvc3VyZSBkdXJhdGlvbiAoQ1JFRCBRMTQpDQoNCiMjIyMgTWluaW11bSBkdXJhdGlvbg0KDQpgYGB7cn0NCm1pbl9kdXJhdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9taW5fZHVyYXRpb25fZXhwb3N1cmUsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0KbWluX2R1cmF0aW9uX2FsbCA8LSAgbWluX2R1cmF0aW9uICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGNvbXBvdW5kX21pbl9kdXJhdGlvbl9leHBvc3VyZSkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIiwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKQ0KICANCg0KbWluX2R1cmF0aW9uX2FsbCA8LSByYmluZChtaW5fZHVyYXRpb25fYWxsLCBtaW5fZHVyYXRpb24pICU+JSANCiAgZHBseXI6OmZpbHRlcihjb21wb3VuZF9taW5fZHVyYXRpb25fZXhwb3N1cmUgPT0gIk5vdCBzdGF0ZWQiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9yZXBvcnRlZCA9IDEwMC1wZXJjZW50KQ0KbWluX2R1cmF0aW9uX2FsbCAlPiUgDQogIGd0KCkNCmBgYA0KDQojIyMgTWF4aW11bSBkdXJhdGlvbg0KDQpgYGB7cn0NCm1heF9kdXJhdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShjb21wb3VuZF9tYXhfZHVyYXRpb25fZXhwb3N1cmUsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQptYXhfZHVyYXRpb25fYWxsIDwtICBtYXhfZHVyYXRpb24gJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoY29tcG91bmRfbWF4X2R1cmF0aW9uX2V4cG9zdXJlKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpDQogIA0KDQptYXhfZHVyYXRpb25fYWxsIDwtIHJiaW5kKG1heF9kdXJhdGlvbl9hbGwsIG1heF9kdXJhdGlvbikgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKGNvbXBvdW5kX21heF9kdXJhdGlvbl9leHBvc3VyZSA9PSAiTm90IHN0YXRlZCIpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50X3JlcG9ydGVkID0gMTAwLXBlcmNlbnQpDQptYXhfZHVyYXRpb25fYWxsICU+JSANCiAgZ3QoKQ0KYGBgDQoNCiMjIyBFeHBvc3VyZSB2ZXJpZmljYXRpb24gKENSRUQgUTE1KQ0KDQojIyMjIFdhdGVyIHZlcmlmaWNhdGlvbg0KDQpgYGB7cn0NCndhdGVyX3ZlcmlmaWNhdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKHZhbGlkaXR5X2NvbXBvdW5kX3dhdGVyX3ZlcmlmaWNhdGlvbikpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2NvbXBvdW5kX3dhdGVyX3ZlcmlmaWNhdGlvbiwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQp3YXRlcl92ZXJpZmljYXRpb25fYWxsIDwtICB3YXRlcl92ZXJpZmljYXRpb24gJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfY29tcG91bmRfd2F0ZXJfdmVyaWZpY2F0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0Kd2F0ZXJfdmVyaWZpY2F0aW9uX2FsbCA8LSByYmluZCh3YXRlcl92ZXJpZmljYXRpb25fYWxsLCB3YXRlcl92ZXJpZmljYXRpb24pICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9jb21wb3VuZF93YXRlcl92ZXJpZmljYXRpb24gPT0gIk1lYXN1cmVkIikNCndhdGVyX3ZlcmlmaWNhdGlvbl9hbGwgJT4lIA0KICBndCgpDQpgYGANCg0KIyMjIyBUaXNzdWUgdmVyaWZpY2F0aW9uDQoNCmBgYHtyfQ0KdGlzc3VlX3ZlcmlmaWNhdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogICNkcGx5cjo6ZmlsdGVyKCFpcy5uYSh2YWxpZGl0eV9jb21wb3VuZF9hbmltYWxfdmVyaWZpY2F0aW9uKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfY29tcG91bmRfYW5pbWFsX3ZlcmlmaWNhdGlvbiwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQp0aXNzdWVfdmVyaWZpY2F0aW9uX2FsbCA8LSAgdGlzc3VlX3ZlcmlmaWNhdGlvbiAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9jb21wb3VuZF9hbmltYWxfdmVyaWZpY2F0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0KdGlzc3VlX3ZlcmlmaWNhdGlvbl9hbGwgPC0gcmJpbmQodGlzc3VlX3ZlcmlmaWNhdGlvbl9hbGwsIHRpc3N1ZV92ZXJpZmljYXRpb24pICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9jb21wb3VuZF9hbmltYWxfdmVyaWZpY2F0aW9uID09ICJZZXMiKQ0KdGlzc3VlX3ZlcmlmaWNhdGlvbl9hbGwgJT4lIA0KICBndCgpDQpgYGANCg0KDQojIyMgUmFuZG9taXphdGlvbiAoTm90IENSRUQpDQoNCmBgYHtyfQ0KcmFuZG9taXphdGlvbiA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfcmFuZG9taXphdGlvbiwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpyYW5kb21pemF0aW9uX2FsbCA8LSAgcmFuZG9taXphdGlvbiAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9yYW5kb21pemF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBzdW0obikpICU+JSANCiAgZHBseXI6Om11dGF0ZShzdHVkeV9tb3RpdmF0aW9uID0gIk92ZXJhbGwiLA0KICAgICAgICAgICAgICAgIHBlcmNlbnQgPSByb3VuZChuL3N1bShuKSoxMDAsMSkpIA0KICANCg0KcmFuZG9taXphdGlvbl9hbGwgPC0gcmJpbmQocmFuZG9taXphdGlvbl9hbGwsIHJhbmRvbWl6YXRpb24pICU+JSANCiAgZHBseXI6OmZpbHRlcih2YWxpZGl0eV9yYW5kb21pemF0aW9uID09ICJZZXMiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9kaXNjbG9zZWQgPSAxMDAtcGVyY2VudCkNCnJhbmRvbWl6YXRpb25fYWxsICU+JSANCiAgZ3QoKQ0KYGBgDQoNCiMjIyBCbGluZGluZyAoTm90IENSRUQpDQoNCmBgYHtyfQ0KYmxpbmRpbmcgPC0gRUlQQUFCX2RhdGFiYXNlICU+JQ0KICBkcGx5cjo6Z3JvdXBfYnkoYXJ0aWNsZV9pZCkgJT4lIA0KICBkcGx5cjo6c2FtcGxlX24oMSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHZhbGlkaXR5X2JlaGF2X2JsaW5kaW5nLCBzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjpyZWZyYW1lKG4gPSBuKCkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6Om11dGF0ZSh0b3RhbF9tb3RpdmF0aW9uID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnQgPSByb3VuZChuL3RvdGFsX21vdGl2YXRpb24qMTAwLDEpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXRvdGFsX21vdGl2YXRpb24pDQoNCmJsaW5kaW5nX2FsbCA8LSAgYmxpbmRpbmcgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkodmFsaWRpdHlfYmVoYXZfYmxpbmRpbmcpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkgDQogIA0KDQpibGluZGluZ19hbGwgPC0gcmJpbmQoYmxpbmRpbmdfYWxsLCBibGluZGluZykgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHZhbGlkaXR5X2JlaGF2X2JsaW5kaW5nID09ICJZZXMiKQ0KYmxpbmRpbmdfYWxsICU+JSANCiAgZ3QoKQ0KYGBgDQoNCiMjIyBTY29yaW5nIG1ldGhvZCAoTm90IENSRUQpDQoNCmBgYHtyfQ0KYmVoYXZfc2NvcmluZyA8LSBFSVBBQUJfZGF0YWJhc2UgJT4lDQogIGRwbHlyOjpncm91cF9ieShhcnRpY2xlX2lkKSAlPiUgDQogIGRwbHlyOjpzYW1wbGVfbigxKSAlPiUgDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lIA0KICB0aWR5cjo6c2VwYXJhdGVfcm93cyh2YWxpZGl0eV9iZWhhdl9zY29yaW5nX21ldGhvZCwgc2VwID0gIjsiKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9iZWhhdl9zY29yaW5nX21ldGhvZCwgc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gbigpKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShzdHVkeV9tb3RpdmF0aW9uKSAlPiUgDQogIGRwbHlyOjptdXRhdGUodG90YWxfbW90aXZhdGlvbiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6Om11dGF0ZShwZXJjZW50ID0gcm91bmQobi90b3RhbF9tb3RpdmF0aW9uKjEwMCwxKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC10b3RhbF9tb3RpdmF0aW9uKQ0KDQpiZWhhdl9zY29yaW5nX2FsbCA8LSAgYmVoYXZfc2NvcmluZyAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9iZWhhdl9zY29yaW5nX21ldGhvZCkgJT4lIA0KICBkcGx5cjo6cmVmcmFtZShuID0gc3VtKG4pKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc3R1ZHlfbW90aXZhdGlvbiA9ICJPdmVyYWxsIiwNCiAgICAgICAgICAgICAgICBwZXJjZW50ID0gcm91bmQobi9zdW0obikqMTAwLDEpKSANCiAgDQoNCmJlaGF2X3Njb3JpbmdfYWxsIDwtIHJiaW5kKGJlaGF2X3Njb3JpbmdfYWxsLCBiZWhhdl9zY29yaW5nKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIodmFsaWRpdHlfYmVoYXZfc2NvcmluZ19tZXRob2QgPT0gIm5vdCBzcGVjaWZpZWQiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudF9zcGVjaWZpZWQgPSAxMDAtcGVyY2VudCkNCmJlaGF2X3Njb3JpbmdfYWxsICU+JSANCiAgZ3QoKQ0KYGBgDQoNCiMjIyBDb25mbGljdCBzdGF0ZW1lbnQgKE5vdCBDUkVEKQ0KDQpgYGB7cn0NCmNvbmZsaWN0IDwtIEVJUEFBQl9kYXRhYmFzZSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGFydGljbGVfaWQpICU+JSANCiAgZHBseXI6OnNhbXBsZV9uKDEpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9jb25mbGljdF9zdGF0ZW1lbnQsIHN0dWR5X21vdGl2YXRpb24pICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IG4oKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoc3R1ZHlfbW90aXZhdGlvbikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHRvdGFsX21vdGl2YXRpb24gPSBzdW0obikpICU+JSANCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgDQogIGRwbHlyOjptdXRhdGUocGVyY2VudCA9IHJvdW5kKG4vdG90YWxfbW90aXZhdGlvbioxMDAsMSkpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtdG90YWxfbW90aXZhdGlvbikNCg0KY29uZmxpY3RfYWxsIDwtICBjb25mbGljdCAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh2YWxpZGl0eV9jb25mbGljdF9zdGF0ZW1lbnQpICU+JSANCiAgZHBseXI6OnJlZnJhbWUobiA9IHN1bShuKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHN0dWR5X21vdGl2YXRpb24gPSAiT3ZlcmFsbCIsDQogICAgICAgICAgICAgICAgcGVyY2VudCA9IHJvdW5kKG4vc3VtKG4pKjEwMCwxKSkgDQogIA0KDQpjb25mbGljdF9hbGwgPC0gcmJpbmQoY29uZmxpY3RfYWxsLCBjb25mbGljdCkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHZhbGlkaXR5X2NvbmZsaWN0X3N0YXRlbWVudCA9PSAiTm8gc3RhdGVtZW50IGlzIG1hZGUgaW4gdGhlIHBhcGVyIikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHBlcmNlbnRfc3BlY2lmaWVkID0gMTAwLXBlcmNlbnQpDQpjb25mbGljdF9hbGwgJT4lIA0KICBndCgpDQpgYGANCg0KDQojIPCfkrsgU2Vzc2lvbiBJbmZvcm10aW9uDQoNCmBgYHtyfQ0KIyBwYW5kZXIgZm9yIG1ha2luZyBpdCBsb29rIG5pY2VyDQpzZXNzaW9uSW5mbygpICU+JSBwYW5kZXIoKQ0KYGBgDQoNCg==