Initial Print: 2024-07-31

Print Date: 2024-09-14

# List of most of the required libraries used
required_libraries <- c("ggplot2", "stringr", "readxl", "dplyr", "lubridate", "hms", "openxlsx", "writexl", "rmarkdown", "knitr", "kableExtra")

# ggplot2     for 'declaratively' creating graphics, based on "The Grammar of Graphics". 
# stringr     for working with strings, i.e., character data.
# readxl      for reading Excel files by providing a way to read xls and xlsx files into R without dependencies on external software.
# dplyr       for data manipulation, providing a consistent set of verbs that help you solve the most common data manipulation challenges.
# lubridate   for working with dates and times in R.
# hms         for storing time-of-day values and interfacing these values with base R's date-time classes.
# openxlsx    for reading from and writing to Microsoft Excel .xlsx files. It provides more functionality than just handling data; it also allows you to modify various aspects of the Excel file itself.
# writexl     for a fast and portable way to write data frames to Excel .xlsx files, focusing solely on writing data without any dependencies.
# rmarkdown   for dynamic report generation from R. It integrates the core syntax of markdown (a simple markup language) with R code, allowing for the automatic update of reports to reflect data changes and analysis updates.
# knitr       for using functions such as kable() to format dataframes as markdown tables. 
# kableExtra  for enhanced functionality for styling tables such as displaying columns evenly

# Check which libraries are not installed
installed_libs <- rownames(installed.packages())
libraries_to_install <- required_libraries[!required_libraries %in% installed_libs]

# Install missing libraries
if(length(libraries_to_install) > 0) {
  install.packages(libraries_to_install)
}

# Load all required libraries
lapply(required_libraries, library, character.only = TRUE)

TABLE OF CONTENTS

Utilize the Table of Contents on the left to scroll through the different sections and help navigate this report. You can click on the title to go directly to the section.

If you’re viewing the PDF version, the Table of Contents stays at the top of this report. To go directly to a section, copy and paste the title into the search box. Use the following shortcut keys to help navigate with ease:

Shortcut Keys:

  • Hold Ctrl and press the Home key to go to the top of the page.
  • Hold Ctrl and press the End key to go to the bottom of the page.
  • Hold Ctrl and press the F key to search for specific text or strings of text.
  • Press the Esc key to quickly exit the search box.

About This Report

This report is published on RPubs1. KDF stands for Ken Does Fitness. Refer to References at the bottom of this page for cited sources. The RMD file to produce this report, and some of the figures from this report, may be found in the Google Drive folder 2.

STRENGTH STANDARDS

Strength Standards provide valuable benchmarks for assessing an individual’s performance in key strength exercises that are widely practiced in fitness and strength training. These standards categorize performance levels based on either amount of weight executed relative to bodyweight, or repetitions executed, and are segmented by gender and experience levels. By comparing an individual’s performance against these established standards, trainers and athletes can identify strengths and weaknesses in their training regimens, set realistic goals, and measure progress in a structured manner.

Strength Standards Overview

Several strength standards are readily available online:

Finding accurate strength standards depends on the demographic, exercise type, and required accuracy. Each has its pros and cons: some cater to specific demographics, others focus on certain exercises, and their credibility affects reliability. Usability and comprehensive data for benchmarking are crucial, as are regular updates to reflect current trends. Considering these factors helps trainers and athletes choose the best standards for assessing and improving performance.

# Load necessary libraries
library(knitr)
library(kableExtra)

# Define the pros and cons as lists
pros <- c("Benchmarking: Strength standards provide clear benchmarks to measure progress and set goals.",
          "Motivation: Seeing how your performance stacks up against established standards can be highly motivating.",
          "Guidance: They offer guidance on what is considered strong or weak for different exercises, helping you tailor your training accordingly.",
          "Comparison: They allow for meaningful comparisons between individuals, helping to identify strengths and weaknesses.",
          "Structured Training: Strength standards can help in designing more structured and effective training programs.")

cons <- c("Generic: Strength standards can be too generic and may not account for individual differences in genetics, body composition, and training history.",
          "Pressure: They can create undue pressure to meet certain benchmarks, potentially leading to injury or burnout.",
          "Outdated Information: Some standards may be based on outdated information or not reflect recent advancements in sports science.",
          "Not Comprehensive: They might not cover all exercises or account for different training goals, such as hypertrophy versus strength.",
          "Misleading: For beginners, strength standards can be misleading if they don’t account for the starting point or rate of progress appropriate for different fitness levels.")

# Combine the pros and cons into a data frame
strength_standards_pnc <- data.frame(
  Pros = pros,
  Cons = cons,
  stringsAsFactors = FALSE
)

# Print the table using kable and kableExtra
kable(strength_standards_pnc, format = "html", escape = FALSE, col.names = c("Pros", "Cons")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = TRUE) %>%
  column_spec(1, width = "50%") %>%
  column_spec(2, width = "50%")
Pros Cons
Benchmarking: Strength standards provide clear benchmarks to measure progress and set goals. Generic: Strength standards can be too generic and may not account for individual differences in genetics, body composition, and training history.
Motivation: Seeing how your performance stacks up against established standards can be highly motivating. Pressure: They can create undue pressure to meet certain benchmarks, potentially leading to injury or burnout.
Guidance: They offer guidance on what is considered strong or weak for different exercises, helping you tailor your training accordingly. Outdated Information: Some standards may be based on outdated information or not reflect recent advancements in sports science.
Comparison: They allow for meaningful comparisons between individuals, helping to identify strengths and weaknesses. Not Comprehensive: They might not cover all exercises or account for different training goals, such as hypertrophy versus strength.
Structured Training: Strength standards can help in designing more structured and effective training programs. Misleading: For beginners, strength standards can be misleading if they don’t account for the starting point or rate of progress appropriate for different fitness levels.

I’ve compiled some of the standards into an Excel file3. This allows for comparison between personal performance measures and the specified strength standards. I recommend consulting each source for confirmation on the latest version, as the structure or numbers may have changed over time.

# File Path Definition: The script defines a path to an Excel file containing "Strength Standards".
file_path_strength_standards <- "C://Users//kendr//OneDrive//Documents//Data Analytics//KenDoesFitness/Strength Standards Final.xlsm"

# Workbook Loading: Loads the Excel workbook into R using the openxlsx package, which provides more advanced control over Excel files than readxl.
strength_standards <- loadWorkbook(file_path_strength_standards)

Standards Categories

The standards compiled are separated into categories, as shown in the following table, making it easy to determine which exercise to use as a benchmark.

# Sheet Names Display: Retrieves and displays the names of sheets within the Excel workbook to help identify available data.

# Check to confirm which number of names to display
# names(strength_standards)

# Display specific elements from the strength_standards object with Indexing
names_subset_strength_standards <- names(strength_standards)[4:15]
names_subset_strength_standards_gsub = gsub("_"," ", names_subset_strength_standards)
# names_subset_strength_standards

# Calculate the number of names
num_names <- length(names_subset_strength_standards_gsub)

# Calculate the number of names per column
names_per_column <- ceiling(num_names / 2)

# Split the names into two columns
column_1 <- names_subset_strength_standards_gsub[1:min(names_per_column, num_names)]
column_2 <- names_subset_strength_standards_gsub[(min(names_per_column, num_names) + 1):num_names]

# Pad the shorter column with NA values if necessary
if(length(column_1) < length(column_2)) {
  column_1 <- c(column_1, rep("", length(column_2) - length(column_1)))
} else if(length(column_2) < length(column_1)) {
  column_2 <- c(column_2, rep("", length(column_1) - length(column_2)))
}
  
# Create a data frame with two columns
names_subset_strength_standards_gsub_df <- data.frame(Column_1 = column_1,
                              Column_2 = column_2)

# Calculate the width dynamically
col_width <- paste0(100 / ncol(names_subset_strength_standards_gsub_df), "%")

# Print the data frame using knitr::kable
knitr::kable(names_subset_strength_standards_gsub_df, format = "markdown", col.names = c("Categories", "Categories")) %>%
  column_spec(1:2, width = col_width, extra_css = "text-align: left;")
Categories Categories
Push Ups Romanian Deadlift
Bench Press T Bar Row
Incline Bench Press Press
Pull Ups Barbell Shoulder Press
Lat Pulldown Dumbbell Shoulder Press
Deadlift Military Press

Strength Standards List

Below is the list of Strength Standards compiled into the SS Excel file4. This file references the source of each standard table. We’ll delve into Mark Rippetoe’s Starting Strength Standards, as his and his colleagues’ methods and research are based on comprehensive and technical information.

library(openxlsx)
library(readxl)
library(knitr)
library(kableExtra)

# Read Named Ranges: Reads a specific sheet named "Named_Ranges" that presumably contains metadata about other named ranges in the workbook. It keeps only the columns related to named ranges and their respective sheets.
named_ranges <- read_excel(file_path_strength_standards, sheet = "Named_Ranges")
sheet_names_filtered <- unique(named_ranges$`Category Sheet`)
named_ranges <- named_ranges[named_ranges$`Category Sheet` %in% sheet_names_filtered, c("Strength Standard", "Category Sheet")]

# Display the modified 'Strength Standard' column with spaces instead of underscores
strength_standards_list_display <- named_ranges %>%
  mutate(`Strength Standard` = gsub("_", " ", `Strength Standard`)) %>%
  mutate(`Category Name` = gsub("_", " ", `Category Sheet`)) %>%
  select(-`Category Sheet`)  # This excludes the 'Category Sheet' column

# View the data frame if needed (not during knitting). View function opens the raw_data dataframe in the RStudio data viewer for interactive exploration.
View(named_ranges)
View(strength_standards_list_display)

# Define the ratios and total width for column widths
total_width <- 100
ratio_strength_standards <- 2
ratio_category <- 1.25
total_ratio <- ratio_strength_standards + ratio_category

# Calculate the column widths
width_strength_standards <- (ratio_strength_standards / total_ratio) * total_width
width_category <- (ratio_category / total_ratio) * total_width

# Print the dataframe using kable for a nicely formatted markdown table.
kable(strength_standards_list_display, format = "html", col.names = c("Strength Standard", "Category")) %>%
  kable_styling(full_width = TRUE) %>%
  column_spec(1, width = paste0(width_strength_standards, "%")) %>%
  column_spec(2, width = paste0(width_category, "%"))
Strength Standard Category
Male Barbell Curl Std 1RM By Age Strengthlevel Barbell Curl
Male Barbell Curl Std 1RM By Bodyweight Strengthlevel Barbell Curl
Male Barbell Curl Std 1RM Strengthlevel Barbell Curl
Male Barbell Shoulder Press Std 1RM By Age Strengthlevel Barbell Shoulder Press
Male Barbell Shoulder Press Std 1RM By Bodyweight Strengthlevel Barbell Shoulder Press
Male Barbell Shoulder Press Std 1RM Strengthlevel Barbell Shoulder Press
Male Bench Press Std 1RM By Age Strengthlevel Bench Press
Male Bench Press Std 1RM By Bodyweight Mark Rippetoe Bench Press
Male Bench Press Std 1RM By Bodyweight Strengthlevel Bench Press
Male Bench Press Std 1RM Strengthlevel Bench Press
Male Deadlift Std 1RM By Age Strengthlevel Deadlift
Male Deadlift Std 1RM By Bodyweight Mark Rippetoe Deadlift
Male Deadlift Std 1RM By Bodyweight Strengthlevel Deadlift
Male Deadlift Std 1RM Strengthlevel Deadlift
Male Dumbbell Shoulder Press Std 1RM By Age Strengthlevel Dumbbell Shoulder Press
Male Dumbbell Shoulder Press Std 1RM By Bodyweight Strengthlevel Dumbbell Shoulder Press
Male Dumbbell Shoulder Press Std 1RM Strengthlevel Dumbbell Shoulder Press
Male Incline Bench Press Std 1RM By Age Strengthlevel Incline Bench Press
Male Incline Bench Press Std 1RM By Bodyweight Strengthlevel Incline Bench Press
Male Incline Bench Press Std 1RM Strengthlevel Incline Bench Press
Male Lat Pulldown Std 1RM By Age Strengthlevel Lat Pulldown
Male Lat Pulldown Std 1RM By Bodyweight Strengthlevel Lat Pulldown
Male Lat Pulldown Std 1RM Strengthlevel Lat Pulldown
Male Military Press Std 1RM By Age Strengthlevel Military Press
Male Military Press Std 1RM By Bodyweight Strengthlevel Military Press
Male Military Press Std 1RM Strengthlevel Military Press
Named Range List Named Ranges
Male Press Std 1RM By Bodyweight Mark Rippetoe Press
Male Pull Ups Std 1RM Strengthlevel Pull Ups
Male Pull Ups Std 1RM Weight By Age Strengthlevel Pull Ups
Male Pull Ups Std 1RM Weight By Bodyweight Strengthlevel Pull Ups
Male Pull Ups Std Reps By Age Strengthlevel Pull Ups
Male Pull Ups Std Reps By Bodyweight Strengthlevel Pull Ups
Male Push Ups Std Reps By Age Strengthlevel Push Ups
Male Push Ups Std Reps By Bodyweight Strengthlevel Push Ups
Male Push Ups Std Reps Strengthlevel Push Ups
Male Romanian Deadlift Std 1RM By Age Strengthlevel Romanian Deadlift
Male Romanian Deadlift Std 1RM By Bodyweight Strengthlevel Romanian Deadlift
Male Romanian Deadlift Std 1RM Strengthlevel Romanian Deadlift
Male Squat Std 1RM By Age Strengthlevel Squat
Male Squat Std 1RM By Bodyweight Mark Rippetoe Squat
Male Squat Std 1RM By Bodyweight Strengthlevel Squat
Male Squat Std 1RM Strengthlevel Squat
Male T Bar Row Std 1RM By Age Strengthlevel T Bar Row
Male T Bar Row Std 1RM By Bodyweight Strengthlevel T Bar Row
Male T Bar Row Std 1RM Strengthlevel T Bar Row
# Create lists to store data frames
named_ranges_list <- list()
named_ranges_sheets_list <- list()

# Loop through the named ranges
for (i in 1:nrow(named_ranges)) {
  named_range_value <- named_ranges$`Strength Standard`[i]
  named_range_sheet_value <- named_ranges$`Category Sheet`[i]
  named_range_lower <- tolower(gsub(" ", "_", named_range_value))
  named_range_sheet_lower <- tolower(gsub(" ", "_", named_range_sheet_value))
  
  if (named_range_sheet_value == "Named_Ranges") {
    next  # Skip iteration if the sheet is "Named_Ranges" to avoid redundancy
  }
  
  # Read data from the named range
  named_range_data <- tryCatch({
    read.xlsx(file_path_strength_standards, namedRegion = named_range_value)
  }, error = function(e) {
    message(paste("Warning: Workbook has no such named region:", named_range_value))
    NULL
  })
  
  if (!is.null(named_range_data) && is.data.frame(named_range_data)) {
    # Update column names
    colnames(named_range_data) <- gsub("\\.", " ", colnames(named_range_data))
    # Store the data frame in the list
    named_ranges_list[[named_range_lower]] <- named_range_data
    # Assign the data frame to the global environment with the lower case name
    assign(named_range_lower, named_range_data, envir = .GlobalEnv)
  }
  
  # Read data from the sheet
  named_range_sheet_data <- tryCatch({
    read.xlsx(file_path_strength_standards, sheet = named_range_sheet_value)
  }, error = function(e) {
    message(paste("Warning: Workbook has no such sheet:", named_range_sheet_value))
    NULL
  })
  
  if (!is.null(named_range_sheet_data) && is.data.frame(named_range_sheet_data)) {
    # Update column names
    colnames(named_range_sheet_data) <- gsub("\\.", " ", colnames(named_range_sheet_data))
    # Store the data frame in the list
    named_ranges_sheets_list[[named_range_sheet_lower]] <- named_range_sheet_data
    # Assign the data frame to the global environment with the lower case name
    assign(named_range_sheet_lower, named_range_sheet_data, envir = .GlobalEnv)
  }
}

# Display the structure of the lists
# str(named_ranges_list)
# str(named_ranges_sheets_list)

# Optional: View the contents of the lists in RStudio Viewer
# Instead of viewing the whole list, view individual data frames
# Uncomment the below lines to view specific named ranges or sheets
# View(named_ranges_list[["male_barbell_curl_std_1rm_by_age_strengthlevel"]])
# View(male_barbell_curl_std_1rm_by_age_strengthlevel)

MARK RIPPETOE’S STANDARDS

Mark Rippetoe’s Strength Standard: 1 Rep Max By Bodyweight.

Here we utilize Mark Rippetoe’s Strength Standards5 to benchmark individual performance against established criteria for primary strength exercises. These standards are instrumental in evaluating an individual’s lifting capabilities in relation to their bodyweight and training experience. By doing so, we can effectively gauge progress, pinpoint areas that need improvement, and tailor training programs to better meet the specific strength goals of each individual.

The exercises use the technique described in “Starting Strength: Basic Barbell Training, 3rd ed.” The Bluebook may be purchased through The Aasgaard Company online store6 and on Amazon in various mediums (paperback, Kindle, audio). All lifts are performed with the barbell, as indicated by the book title.

To properly utilize these standards, it is recommended to review “Starting Strength: Basic Barbell Training”7 and “Practical Programming for Strength Training.”8 The most recent and relevant 3rd editions (2012) are available on their website, as well as in different mediums on Amazon. You can download online book samples to determine if Starting Strength suits your needs.

# Code extracts and refines a subset of data related to "Mark Rippetoe" standards from a broader dataset, making it more accessible and easier to work with by cleaning up the category names for further analysis or reporting

# subset() filters rows from the named_ranges dataframe.
# grepl() checks each entry in the "Strength Standard" column for the substring 
mark_rippetoe_standards_list <- subset(named_ranges, grepl("Mark_Rippetoe", `Strength Standard`))

# Pipe Operator (%>%) is used to pass the result of one function to the next. It helps in writing cleaner and more readable code, especially when performing multiple operations on a dataset.
# gsub("_", " ", Category Sheet) replaces underscores (_) with spaces in the Category Sheet column.
# New column is created. 
mark_rippetoe_standards_list <- mark_rippetoe_standards_list %>%
  mutate(`Category Name` = gsub("_", " ", `Category Sheet`))

# Display the modified 'Strength Standard' column with spaces instead of underscores
display_mark_rippetoe_standards_list <- mark_rippetoe_standards_list %>%
  mutate(`Strength Standard` = gsub("_", " ", `Strength Standard`)) %>%
  select(-`Category Sheet`)  # This excludes the 'Category Sheet' column

# The View function is used to open the raw_data dataframe in the RStudio data viewer for interactive exploration.
View(mark_rippetoe_standards_list) #Run this line of code to view table. 

# Print for reference. 
# print(mark_rippetoe_standards_list)
# print(display_mark_rippetoe_standards_list)

# Define the ratios and total width for column widths
total_width <- 100
ratio_strength_standards <- 2
ratio_category <- 1.25
total_ratio <- ratio_strength_standards + ratio_category

# Calculate the column widths
width_strength_standards <- (ratio_strength_standards / total_ratio) * total_width
width_category <- (ratio_category / total_ratio) * total_width

# Print the dataframe using kable for a nicely formatted markdown table.
kable(display_mark_rippetoe_standards_list, format = "html", col.names = c("Strength Standard", "Category")) %>%
  kable_styling(full_width = TRUE) %>%
  column_spec(1, width = paste0(width_strength_standards, "%")) %>%
  column_spec(2, width = paste0(width_category, "%"))
Strength Standard Category
Male Bench Press Std 1RM By Bodyweight Mark Rippetoe Bench Press
Male Deadlift Std 1RM By Bodyweight Mark Rippetoe Deadlift
Male Press Std 1RM By Bodyweight Mark Rippetoe Press
Male Squat Std 1RM By Bodyweight Mark Rippetoe Squat

There are five Starting Strength Standards, with the Power Clean excluded in this report as my colleagues and I do not perform that exercise. Each of the four remaining Standards is presented below, followed by a plot to visualize performances for comparison and motivation.

# Keep fig.width=10 for PDF display (via browser > Save As PDF). While fig.width=9 (instead of 10) fits width of output, saving as PDF with fig.width=9 will result in small figure; width=10 will fill the PDF page.

# Load the required packages if not already installed
library(ggplot2)
library(dplyr)
library(knitr)
library(kableExtra) # Ensure kableExtra is loaded for styling

# Function to generate ggplot for each data frame
generate_ggplot <- function(data, category_name, mark_rippetoe_strength_standard) {
  data_number <- data %>%
    mutate(Bodyweight = as.numeric(gsub("[^0-9]", "", Bodyweight)))

  # Rename columns to remove double periods
  colnames(data_number) <- gsub("\\.\\.", ". ", colnames(data_number))

  # Print column names for debugging
  # print(colnames(data_number))
    
  ggplot(data_number, aes(x = Bodyweight)) +
    geom_ribbon(aes(ymin = `Cat. I`, ymax = `Cat. II`), fill = "blue", alpha = 0.2) +
    geom_ribbon(aes(ymin = `Cat. II`, ymax = `Cat. III`), fill = "green", alpha = 0.2) +
    geom_ribbon(aes(ymin = `Cat. III`, ymax = `Cat. IV`), fill = "orange", alpha = 0.2) +
    geom_ribbon(aes(ymin = `Cat. IV`, ymax = `Cat. V`), fill = "red", alpha = 0.2) +
    geom_ribbon(aes(ymin = `Cat. V`, ymax = Inf), fill = "purple", alpha = 0.2) +
    
    # Fill the remaining non-colored part
    geom_ribbon(aes(ymin = -Inf, ymax = `Cat. I`), fill = "gray", alpha = 0.2) +
    
    # Create lines
    geom_line(aes(y = `Cat. I`), color = "blue", size = 1) +
    geom_line(aes(y = `Cat. II`), color = "green", size = 1) +
    geom_line(aes(y = `Cat. III`), color = "orange", size = 1) +
    geom_line(aes(y = `Cat. IV`), color = "red", size = 1) +
    geom_line(aes(y = `Cat. V`), color = "purple", size = 1) +
    
    # Set labels
    labs(
      x = "Bodyweight (lb)",
      y = "1RM Weight Load Execution",
      title = paste("Male", category_name, "Standards"),
      subtitle = "Comparison of Strength Standards Across Experience Levels",
      caption = paste("Source:", mark_rippetoe_strength_standard) # Change Source info PRN
    ) +
    
    # Add more markers on the y-axis at increments of 20
    scale_y_continuous(breaks = seq(0, 999, by = 20)) +
    # Add more markers on the x-axis at increments of 10
    scale_x_continuous(breaks = seq(0, 999, by = 10)) +
    
    # Add text labels for skill levels with matching colors
    geom_text(aes(x = max(Bodyweight), y = min(`Cat. I`), label = ""), color = "dimgray", vjust = -1) +
    geom_text(aes(x = max(Bodyweight), y = max(`Cat. I`), label = "Cat. I"), color = "darkblue", vjust = -1) +
    geom_text(aes(x = max(Bodyweight), y = max(`Cat. II`), label = "Cat. II"), color = "darkgreen", vjust = -1) +
    geom_text(aes(x = max(Bodyweight), y = max(`Cat. III`), label = "Cat. III"), color = "darkorange", vjust = -1) +
    geom_text(aes(x = max(Bodyweight), y = max(`Cat. IV`), label = "Cat. IV"), color = "darkred", vjust = -1) +
    geom_text(aes(x = max(Bodyweight), y = max(`Cat. V`), label = "Cat. V"), color = "purple", vjust = -1) +
    
    # Customize theme
    theme_minimal() +
    theme(
      plot.title = element_text(hjust = 0.5, size = 16),
      plot.subtitle = element_text(hjust = 0.5, size = 12),
      plot.caption = element_text(hjust = 0.5),
      axis.title.x = element_text(size = 14),
      axis.title.y = element_text(size = 14),
      axis.text = element_text(size = 12),
      legend.position = "right",
      legend.title = element_blank(),
      legend.text = element_text(size = 12),
      legend.key.size = unit(1, "cm")
    )
}

# Lists to store the plots and tables
plots_list_strength_standards_mark_rippetoe <- list()
tables_list_strength_standards_mark_rippetoe <- list()

# Check and create the 'plots' directory if it doesn't exist
if (!dir.exists("plots")) {
  dir.create("plots")
}

# Check and create the 'tables' directory if it doesn't exist
if (!dir.exists("tables")) {
  dir.create("tables")
}

# Loop through each named range from the filtered mark_rippetoe_standards_list dataframe
for (i in 1:nrow(mark_rippetoe_standards_list)) {
  strength_standard_named_range <- mark_rippetoe_standards_list$`Strength Standard`[i]
  category_name <- mark_rippetoe_standards_list$`Category Name`[i]
  
  # Load the data from the named range
  data_frame <- readWorkbook(strength_standards, namedRegion = strength_standard_named_range)
  
  # Check if the 'Bodyweight' column exists in the data frame
  if (!"Bodyweight" %in% colnames(data_frame)) {
    cat(paste("Skipping", strength_standard_named_range, "- 'Bodyweight' column missing.\n"))
    next
  }

  # Ensure column names are trimmed of whitespace
  colnames(data_frame) <- trimws(colnames(data_frame))

  # Rename columns to remove double periods for both table and plot
  colnames(data_frame) <- gsub("\\.\\.", ". ", colnames(data_frame))

  # Format the title of the plot and head of the table using the cleaned category name
  formatted_header <- gsub("_", " ", strength_standard_named_range)
  formatted_header <- (sub(" Std 1RM By Bodyweight Mark Rippetoe", " Standards", formatted_header))
  
  # Generate the plot
  plot <- generate_ggplot(data_frame, category_name, strength_standard_named_range)
  
  # Print the name of the named range as a markdown header
  cat(paste0("\n\n<h3> ", formatted_header, "</h3>\n"))

  # Rename 'Bodyweight' column to 'Bodyweight (lb)'
  names(data_frame)[names(data_frame) == "Bodyweight"] <- "Bodyweight (lb)"

  # Print the plot
  print(plot)

  # Save the plot to the list
  plots_list_strength_standards_mark_rippetoe[[formatted_header]] <- plot

  # Output the data frame as a markdown table with even column widths
  print(
    table_html <- kable(data_frame, format = "html", align = 'l') %>%
      kable_styling(full_width = TRUE) %>%
      column_spec(1:ncol(data_frame), width = paste0(100 / ncol(data_frame), "%"))
  )
  
  # Save the table to the list
  tables_list_strength_standards_mark_rippetoe[[formatted_header]] <- table_html

  # Optionally save the plot and table
  ggsave(filename = paste0("plots/", tolower(strength_standard_named_range), ".png"), plot = plot, width = 12, height = 8)

  # Save the data frame as a CSV file
  write.csv(data_frame, file = paste0("tables/", tolower(strength_standard_named_range), ".csv"), row.names = FALSE)
}

Male Bench Press Standards

Bodyweight (lb) Cat. I Cat. II Cat. III Cat. IV Cat. V
114 84 107 130 179 222
123 91 116 142 194 242
132 98 125 153 208 260
148 109 140 172 234 291
165 119 152 187 255 319
181 128 164 201 275 343
198 135 173 213 289 362
220 142 183 225 306 381
242 149 190 232 316 395
275 153 196 239 325 407
319 156 199 244 333 416
320+ 159 204 248 340 425

Male Deadlift Standards

Bodyweight (lb) Cat. I Cat. II Cat. III Cat. IV Cat. V
114 97 179 204 299 387
123 105 194 222 320 414
132 113 209 239 342 438
148 126 234 269 380 482
165 137 254 293 411 518
181 148 274 315 438 548
198 156 289 333 457 567
220 164 305 351 479 586
242 172 318 363 490 596
275 176 326 373 499 602
319 180 333 381 506 608
320+ 183 340 388 512 617

Male Press Standards

Bodyweight (lb) Cat. I Cat. II Cat. III Cat. IV Cat. V
114 53 72 90 107 129
123 57 78 98 116 141
132 61 84 105 125 151
148 69 94 119 140 169
165 75 102 129 153 186
181 81 110 138 164 218
198 85 116 146 173 234
220 89 122 155 183 255
242 93 127 159 189 264
275 96 131 164 194 272
319 98 133 167 199 278
320+ 100 136 171 203 284

Male Squat Standards

Bodyweight (lb) Cat. I Cat. II Cat. III Cat. IV Cat. V
114 78 144 174 240 320
123 84 155 190 259 346
132 91 168 205 278 369
148 101 188 230 313 410
165 110 204 250 342 445
181 119 220 269 367 479
198 125 232 285 387 504
220 132 244 301 409 532
242 137 255 311 423 551
275 141 261 319 435 567
319 144 267 326 445 580
320+ 147 272 332 454 593

# Example of how to recall and print a specific plot and table from the lists
# print(plots_list_strength_standards_mark_rippetoe[["Male Bench Press Std 1RM By Bodyweight Mark Rippetoe"]])
# print(tables_list_strength_standards_mark_rippetoe)
# print(tables_list_strength_standards_mark_rippetoe["Male Bench Press Std 1RM By Bodyweight Mark Rippetoe"])
# cat(as.character(tables_list_strength_standards_mark_rippetoe[["Male Bench Press Std 1RM By Bodyweight Mark Rippetoe"]]))

REFERENCES


  1. Tham, K. (2024). Strength Standards (2024-09-14). RPubs by RStudio. Retrieved from https://rpubs.com/KenDoesData/.↩︎

  2. Tham, K. (2024). KDF (KEN DOES FITNESS). Google Drive. Available at https://drive.google.com/drive/folders/1-41FJ_c41Kj7KaK0h1aJ5EBvEhPwwIsi?usp=sharing↩︎

  3. Tham, K. (2024). Strength Standards Final.xlsm. Ken Does Data. Retrieved from https://1drv.ms/x/s!AsYYZA9nL8lf8CK6k6rAP3LSkvry?e=ylARXi.↩︎

  4. Tham, K. (2024). Strength Standards Final.xlsm. Ken Does Data. Retrieved from https://1drv.ms/x/s!AsYYZA9nL8lf8CK6k6rAP3LSkvry?e=ylARXi.↩︎

  5. Rippetoe, M. (2012). Strength Standards. Starting Strength. Retrieved from https://startingstrength.com/files/standards.pdf.↩︎

  6. Rippetoe, M. (2017). Starting Strength: Basic Barbell Training (3rd ed.). The Aasgaard Company. Retrieved from https://aasgaardco.com/store/books-posters-dvd/books/starting-strength-basic-barbell-training/.↩︎

  7. Rippetoe, M. (2017). Starting Strength: Basic Barbell Training, 3rd Edition by Mark Rippetoe. Available at https://www.amazon.com/Starting-Strength-Mark-Rippetoe-ebook/dp/B006XJR5ZA/ref=sr_1_1?crid=21521YXBKX4AI&dib=eyJ2IjoiMSJ9.1qTeh_8DJhqDmxrrajmjTbLiQz-wPaKOifgi787M7WurNxwUwKVbhQadJEw8Wdu2ygDP8X0D23Y5xGqEZAJ2L5luEw0gvCIIyuTmugYZ_bRmG35hqLRPlbOyQx4e5pRf2wVoGnsQPzFQEfEOlrhiHKp8BSWCuQkf2RELFKSOLQO49Fq8Y57PU_MuPm9ge91UcC3ebmCZ8pCWHmqbUURN6tyocDT-CR3ZaQAKPJXnmYPsocCP4jz4Y_QTLE1hecsk8Vuugf3HIBjBWkOVMZFmSDlS9ujVxqF4vRqC7GsVJlw._9jNplpd9L6PPFzk7WMC-nSDfWXPhmckFiiaMSwaCyo.↩︎

  8. Rippetoe, M. Practical Programming for Strength Training, 3rd Edition by Mark Rippetoe. Available at https://www.amazon.com/Practical-Programming-Strength-Training-Rippetoe-ebook/dp/B00IU8YETW/ref=sr_1_2?crid=21521YXBKX4AI&dib=eyJ2IjoiMSJ9.1qTeh_8DJhqDmxrrajmjTbLiQz-wPaKOifgi787M7WurNxwUwKVbhQadJEw8Wdu2ygDP8X0D23Y5xGqEZAJ2L5luEw0gvCIIyuTmugYZ_bRmG35hqLRPlbOyQx4e5pRf2wVoGnsQPzFQEfEOlrhiHKp8BSWCuQkf2RELFKSOLQO49Fq8Y57PU_MuPm9ge91UcC3ebmCZ8pCWHmqbUURN6tyocDT-CR3ZaQAKPJXnmYPsocCP4jz4Y_QTLE1hecsk8Vuugf3HIBjBWkOVMZFmSDlS9ujVxqF4vRqC7GsVJlw._9jNplpd9L6PPFzk7WMC-nSDfWXPhmckFiiaMSwaCyo.↩︎

LS0tDQp0aXRsZTogIlN0cmVuZ3RoIFN0YW5kYXJkcyINCmF1dGhvcjogIktlbmRyaWNrIFRoYW0iDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogICAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICAgIHBsYWNlbWVudDogdG9wDQogICAgICB0b2Mtc3VidHJlZTogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlICAgIyBIaWRlIHRoZSBjb2RlIGJ5IGRlZmF1bHQNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAjIEFkZCBhIGJ1dHRvbiB0byBkb3dubG9hZCB0aGUgUiBjb2RlDQoNCi0tLQ0KDQo8IS0tDQotLT4NCg0KSW5pdGlhbCBQcmludDogMjAyNC0wNy0zMQ0KDQpQcmludCBEYXRlOiBgciBTeXMuRGF0ZSgpYA0KDQo8IS0tIFJNRCBTZXR1cCAtLT4NCg0KPHN0eWxlPg0KDQovKiBSZWR1Y2UgdGhlIGZvbnQgc2l6ZSBvZiB0aGUgVE9DICovDQp7DQogIGZvbnQtc2l6ZTogMC45MGVtOyAvKiBBZGp1c3QgdGhlIHNpemUgYXMgbmVlZGVkICovDQp9DQoNCi8qIEFkZCBib3JkZXJzIGFuZCBzcGFjaW5nIHRvIGFsbCBmaWd1cmVzICovDQppbWcgew0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRkOyAvKiBTcGVjaWZ5IGJvcmRlciBzdHlsZSAqLw0KICBwYWRkaW5nOiA1cHg7IC8qIEFkZCBwYWRkaW5nIGFyb3VuZCB0aGUgZmlndXJlcyAqLw0KICBib3JkZXItcmFkaXVzOiA1cHg7IC8qIEFkZCByb3VuZGVkIGNvcm5lcnMgdG8gdGhlIGJvcmRlciAqLw0KICBkaXNwbGF5OiBibG9jazsgLyogRW5zdXJlIHRoZSBpbWFnZSBpcyB0cmVhdGVkIGFzIGEgYmxvY2sgZWxlbWVudCB0byByZXNwZWN0IG1hcmdpbiAqLw0KICBtYXJnaW4tYm90dG9tOiAyMHB4OyAvKiBBZGQgYm90dG9tIG1hcmdpbiB0byBlYWNoIGltYWdlIGZvciBzcGFjaW5nICovDQp9DQoNCi8qIEFkZCBib3JkZXJzIHRvIGFsbCB0YWJsZXMgKi8NCnRhYmxlIHsNCiAgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsgLyogQ29sbGFwc2UgYm9yZGVycyBpbnRvIGEgc2luZ2xlIGJvcmRlciAqLw0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRkOyAvKiBTcGVjaWZ5IGJvcmRlciBzdHlsZSAqLw0KICBtYXJnaW4tYm90dG9tOiAyMHB4OyAvKiBBZGQgYm90dG9tIG1hcmdpbiB0byBlYWNoIHRhYmxlIGZvciBzcGFjaW5nICovDQp9DQoNCi8qIEFkZCBib3JkZXJzIHRvIHRhYmxlIGNlbGxzICovDQp0aCwgdGQgew0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRkOyAvKiBTcGVjaWZ5IGJvcmRlciBzdHlsZSBmb3IgdGFibGUgY2VsbHMgKi8NCiAgcGFkZGluZzogOHB4OyAvKiBBZGQgcGFkZGluZyBpbnNpZGUgdGhlIHRhYmxlIGNlbGxzICovDQogIHRleHQtYWxpZ246IGxlZnQ7IC8qIEFsaWduIHRleHQgdG8gdGhlIGxlZnQgd2l0aGluIHRhYmxlIGNlbGxzICovDQp9DQoNCi8qIEFwcGx5IHN0eWxlcyB0byBhbGwgaGVhZGVycyAqLw0KdGggew0KICBwb3NpdGlvbjogc3RpY2t5OyAvKiBFbnN1cmUgaGVhZGVycyBzdGljayB3aGVuIHNjcm9sbGluZyAqLw0KICB0b3A6IDA7IC8qIFBvc2l0aW9uIGhlYWRlcnMgYXQgdGhlIHRvcCAqLw0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjJmMmYyOyAvKiBCYWNrZ3JvdW5kIGNvbG9yIGZvciBoZWFkZXJzICovDQogIHotaW5kZXg6IDk5OTsgLyogRW5zdXJlIGhlYWRlcnMgc3RheSBvbiB0b3Agb2Ygb3RoZXIgZWxlbWVudHMgKi8NCn0NCg0KLyogQXBwbHkgc3R5bGVzIHRvIGFsbCB0YWJsZXMgKi8NCnRhYmxlIHsNCiAgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsgLyogQ29sbGFwc2UgYm9yZGVycyBpbnRvIGEgc2luZ2xlIGJvcmRlciAqLw0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRkOyAvKiBTcGVjaWZ5IGJvcmRlciBzdHlsZSAqLw0KfQ0KDQovKiBBcHBseSBzdHlsZXMgdG8gdGFibGUgY2VsbHMgKi8NCnRoLCB0ZCB7DQogIGJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IC8qIFNwZWNpZnkgYm9yZGVyIHN0eWxlIGZvciB0YWJsZSBjZWxscyAqLw0KICBwYWRkaW5nOiA4cHg7IC8qIEFkZCBwYWRkaW5nIGluc2lkZSB0aGUgdGFibGUgY2VsbHMgKi8NCiAgdGV4dC1hbGlnbjogbGVmdDsgLyogQWxpZ24gdGV4dCB0byB0aGUgbGVmdCB3aXRoaW4gdGFibGUgY2VsbHMgKi8NCn0NCg0KLyogU3R5bGUgdGFibGVzIHdpdGggYWx0ZXJuYXRpbmcgc3RyaXBlZCByb3dzICovDQp0YWJsZSB7DQogIGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7DQogIHdpZHRoOiAxMDAlOw0KfQ0KDQp0aCwgdGQgew0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOw0KICB0ZXh0LWFsaWduOiBsZWZ0Ow0KICBwYWRkaW5nOiA4cHg7DQp9DQoNCi8qIEFkZCBhbHRlcm5hdGluZyBiYWNrZ3JvdW5kIGNvbG9ycyB0byB0YWJsZSByb3dzICovDQp0cjpudGgtY2hpbGQoZXZlbikgew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjJmMmYyOw0KfQ0KDQp0cjpudGgtY2hpbGQob2RkKSB7DQogIGJhY2tncm91bmQtY29sb3I6ICNmZmZmZmY7IC8qIFdoaXRlIGJhY2tncm91bmQgZm9yIG9kZCByb3dzICovDQp9DQoNCi5mdWxsLXdpZHRoLWltYWdlIGltZyB7DQogIGRpc3BsYXk6IGJsb2NrOw0KICB3aWR0aDogMTAwJTsNCiAgaGVpZ2h0OiBhdXRvOw0KfQ0KDQoNCjwvc3R5bGU+DQoNCg0KPCEtLSBQcmltYXJ5IFBpYyAtLT4NCg0KPGRpdiBjbGFzcz0iZnVsbC13aWR0aC1pbWFnZSI+DQogICFbIF0oQzovL1VzZXJzLy9rZW5kci8vT25lRHJpdmUvL0RvY3VtZW50cy8vRGF0YSBBbmFseXRpY3MvL0tlbkRvZXNGaXRuZXNzLy9TdHJlbmd0aCBTdGFuZGFyZHMvL01hbGVfQmVuY2hfUHJlc3NfU3RkXzFSTV9CeV9Cb2R5d2VpZ2h0X01hcmtfUmlwcGV0b2UucG5nKQ0KPC9kaXY+DQoNCjwhLS0gRGVmYXVsdCBDaHVuayBPcHRpb25zIC0tPg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIH0NCiMgU2V0IHJlcG9zaXRvcnkgYW5kIGRlZmF1bHQgY2h1bmsgb3B0aW9ucw0Kb3B0aW9ucyhyZXBvcyA9IGMoQ1JBTiA9ICJodHRwczovL2Nsb3VkLnItcHJvamVjdC5vcmciKSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPVRSVUUsIGV2YWw9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFKQ0KYGBgDQoNCjwhLS0gDQpPcHRpb25zIHN1Y2ggYXMgZWNobywgbWVzc2FnZSwgd2FybmluZywgcmVzdWx0cywgaW5jbHVkZSwgZXZhbCwgY2FjaGUsIGFuZCBtb3JlLiANCg0KLSBlY2hvOiBTaG93IG9yIGhpZGUgY29kZSBpbiB0aGUgb3V0cHV0IChlY2hvID0gRkFMU0UgaGlkZXMgdGhlIGNvZGUpLg0KLSBtZXNzYWdlOiBTaG93IG9yIGhpZGUgbWVzc2FnZXMgaW4gdGhlIG91dHB1dCAobWVzc2FnZSA9IEZBTFNFIHN1cHByZXNzZXMgbWVzc2FnZXMpLg0KLSB3YXJuaW5nOiBTaG93IG9yIGhpZGUgd2FybmluZ3MgaW4gdGhlIG91dHB1dCAod2FybmluZyA9IEZBTFNFIHN1cHByZXNzZXMgd2FybmluZ3MpLg0KLSByZXN1bHRzOiBDb250cm9sIGhvdyByZXN1bHRzIGFyZSBzaG93bjoNCiAgLSAnbWFya3VwJzogRGlzcGxheSByZXN1bHRzIGFzIHRoZXkgYXJlLg0KICAtICdhc2lzJzogSW5jbHVkZSByZXN1bHRzIGFzIHJhdyBIVE1MIG9yIExhVGVYLg0KICAtICdoaWRlJzogSGlkZSByZXN1bHRzIGZyb20gb3V0cHV0Lg0KLSBpbmNsdWRlOiBJbmNsdWRlIG9yIGV4Y2x1ZGUgYm90aCBjb2RlIGFuZCByZXN1bHRzIGZyb20gdGhlIG91dHB1dCAoaW5jbHVkZSA9IEZBTFNFIGV4Y2x1ZGVzIGV2ZXJ5dGhpbmcpLg0KLSBldmFsOiBFdmFsdWF0ZSB0aGUgY29kZSBjaHVuayBvciBub3QgKGV2YWwgPSBGQUxTRSBwcmV2ZW50cyBjb2RlIGV4ZWN1dGlvbikuDQotIGNhY2hlOiBDYWNoZSB0aGUgcmVzdWx0cyBvZiB0aGUgY2h1bmsgdG8gc3BlZWQgdXAgcmVuZGVyaW5nIChjYWNoZSA9IFRSVUUgZW5hYmxlcyBjYWNoaW5nKS4NCi0gZmlnLmNhcDogQWRkIGEgY2FwdGlvbiB0byBncmFwaGljYWwgb3V0cHV0cy4NCi0gb3V0LndpZHRoL291dC5oZWlnaHQ6IFNldCB0aGUgb3V0cHV0IHNpemUgb2YgcGxvdHMuDQotIGNvbGxhcHNlOiBDb25jYXRlbmF0ZSB0ZXh0dWFsIG91dHB1dCBpbnRvIGEgc2luZ2xlIGJsb2NrLg0KLSB0aWR5OiBUaWR5IHVwIHRoZSBkaXNwbGF5IG9mIGNvZGUgb3IgcmVzdWx0cyAodGlkeSA9IFRSVUUgdGlkaWVzIHRoZSBvdXRwdXQpLg0KLS0+DQoNCjwhLS0gIyMjIFBhY2thZ2VzIGFuZCBMaWJyYXJpZXMgLS0+DQpgYGB7ciBwYWNrYWdlc19hbmRfbGlicmFyaWVzLCBldmFsPVRSVUV9DQoNCiMgTGlzdCBvZiBtb3N0IG9mIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMgdXNlZA0KcmVxdWlyZWRfbGlicmFyaWVzIDwtIGMoImdncGxvdDIiLCAic3RyaW5nciIsICJyZWFkeGwiLCAiZHBseXIiLCAibHVicmlkYXRlIiwgImhtcyIsICJvcGVueGxzeCIsICJ3cml0ZXhsIiwgInJtYXJrZG93biIsICJrbml0ciIsICJrYWJsZUV4dHJhIikNCg0KIyBnZ3Bsb3QyICAgICBmb3IgJ2RlY2xhcmF0aXZlbHknIGNyZWF0aW5nIGdyYXBoaWNzLCBiYXNlZCBvbiAiVGhlIEdyYW1tYXIgb2YgR3JhcGhpY3MiLiANCiMgc3RyaW5nciAgICAgZm9yIHdvcmtpbmcgd2l0aCBzdHJpbmdzLCBpLmUuLCBjaGFyYWN0ZXIgZGF0YS4NCiMgcmVhZHhsICAgICAgZm9yIHJlYWRpbmcgRXhjZWwgZmlsZXMgYnkgcHJvdmlkaW5nIGEgd2F5IHRvIHJlYWQgeGxzIGFuZCB4bHN4IGZpbGVzIGludG8gUiB3aXRob3V0IGRlcGVuZGVuY2llcyBvbiBleHRlcm5hbCBzb2Z0d2FyZS4NCiMgZHBseXIgICAgICAgZm9yIGRhdGEgbWFuaXB1bGF0aW9uLCBwcm92aWRpbmcgYSBjb25zaXN0ZW50IHNldCBvZiB2ZXJicyB0aGF0IGhlbHAgeW91IHNvbHZlIHRoZSBtb3N0IGNvbW1vbiBkYXRhIG1hbmlwdWxhdGlvbiBjaGFsbGVuZ2VzLg0KIyBsdWJyaWRhdGUgICBmb3Igd29ya2luZyB3aXRoIGRhdGVzIGFuZCB0aW1lcyBpbiBSLg0KIyBobXMgICAgICAgICBmb3Igc3RvcmluZyB0aW1lLW9mLWRheSB2YWx1ZXMgYW5kIGludGVyZmFjaW5nIHRoZXNlIHZhbHVlcyB3aXRoIGJhc2UgUidzIGRhdGUtdGltZSBjbGFzc2VzLg0KIyBvcGVueGxzeCAgICBmb3IgcmVhZGluZyBmcm9tIGFuZCB3cml0aW5nIHRvIE1pY3Jvc29mdCBFeGNlbCAueGxzeCBmaWxlcy4gSXQgcHJvdmlkZXMgbW9yZSBmdW5jdGlvbmFsaXR5IHRoYW4ganVzdCBoYW5kbGluZyBkYXRhOyBpdCBhbHNvIGFsbG93cyB5b3UgdG8gbW9kaWZ5IHZhcmlvdXMgYXNwZWN0cyBvZiB0aGUgRXhjZWwgZmlsZSBpdHNlbGYuDQojIHdyaXRleGwgICAgIGZvciBhIGZhc3QgYW5kIHBvcnRhYmxlIHdheSB0byB3cml0ZSBkYXRhIGZyYW1lcyB0byBFeGNlbCAueGxzeCBmaWxlcywgZm9jdXNpbmcgc29sZWx5IG9uIHdyaXRpbmcgZGF0YSB3aXRob3V0IGFueSBkZXBlbmRlbmNpZXMuDQojIHJtYXJrZG93biAgIGZvciBkeW5hbWljIHJlcG9ydCBnZW5lcmF0aW9uIGZyb20gUi4gSXQgaW50ZWdyYXRlcyB0aGUgY29yZSBzeW50YXggb2YgbWFya2Rvd24gKGEgc2ltcGxlIG1hcmt1cCBsYW5ndWFnZSkgd2l0aCBSIGNvZGUsIGFsbG93aW5nIGZvciB0aGUgYXV0b21hdGljIHVwZGF0ZSBvZiByZXBvcnRzIHRvIHJlZmxlY3QgZGF0YSBjaGFuZ2VzIGFuZCBhbmFseXNpcyB1cGRhdGVzLg0KIyBrbml0ciAgICAgICBmb3IgdXNpbmcgZnVuY3Rpb25zIHN1Y2ggYXMga2FibGUoKSB0byBmb3JtYXQgZGF0YWZyYW1lcyBhcyBtYXJrZG93biB0YWJsZXMuIA0KIyBrYWJsZUV4dHJhICBmb3IgZW5oYW5jZWQgZnVuY3Rpb25hbGl0eSBmb3Igc3R5bGluZyB0YWJsZXMgc3VjaCBhcyBkaXNwbGF5aW5nIGNvbHVtbnMgZXZlbmx5DQoNCiMgQ2hlY2sgd2hpY2ggbGlicmFyaWVzIGFyZSBub3QgaW5zdGFsbGVkDQppbnN0YWxsZWRfbGlicyA8LSByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkNCmxpYnJhcmllc190b19pbnN0YWxsIDwtIHJlcXVpcmVkX2xpYnJhcmllc1shcmVxdWlyZWRfbGlicmFyaWVzICVpbiUgaW5zdGFsbGVkX2xpYnNdDQoNCiMgSW5zdGFsbCBtaXNzaW5nIGxpYnJhcmllcw0KaWYobGVuZ3RoKGxpYnJhcmllc190b19pbnN0YWxsKSA+IDApIHsNCiAgaW5zdGFsbC5wYWNrYWdlcyhsaWJyYXJpZXNfdG9faW5zdGFsbCkNCn0NCg0KIyBMb2FkIGFsbCByZXF1aXJlZCBsaWJyYXJpZXMNCmxhcHBseShyZXF1aXJlZF9saWJyYXJpZXMsIGxpYnJhcnksIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCmBgYA0KDQojIFRBQkxFIE9GIENPTlRFTlRTDQpVdGlsaXplIHRoZSBUYWJsZSBvZiBDb250ZW50cyBvbiB0aGUgbGVmdCB0byBzY3JvbGwgdGhyb3VnaCB0aGUgZGlmZmVyZW50IHNlY3Rpb25zIGFuZCBoZWxwIG5hdmlnYXRlIHRoaXMgcmVwb3J0LiBZb3UgY2FuIGNsaWNrIG9uIHRoZSB0aXRsZSB0byBnbyBkaXJlY3RseSB0byB0aGUgc2VjdGlvbi4NCg0KSWYgeW91J3JlIHZpZXdpbmcgdGhlIFBERiB2ZXJzaW9uLCB0aGUgVGFibGUgb2YgQ29udGVudHMgc3RheXMgYXQgdGhlIHRvcCBvZiB0aGlzIHJlcG9ydC4gVG8gZ28gZGlyZWN0bHkgdG8gYSBzZWN0aW9uLCBjb3B5IGFuZCBwYXN0ZSB0aGUgdGl0bGUgaW50byB0aGUgc2VhcmNoIGJveC4gVXNlIHRoZSBmb2xsb3dpbmcgc2hvcnRjdXQga2V5cyB0byBoZWxwIG5hdmlnYXRlIHdpdGggZWFzZToNCg0KU2hvcnRjdXQgS2V5czoNCg0KLSBIb2xkIGBDdHJsYCBhbmQgcHJlc3MgdGhlIGBIb21lYCBrZXkgdG8gZ28gdG8gdGhlIHRvcCBvZiB0aGUgcGFnZS4NCi0gSG9sZCBgQ3RybGAgYW5kIHByZXNzIHRoZSBgRW5kYCBrZXkgdG8gZ28gdG8gdGhlIGJvdHRvbSBvZiB0aGUgcGFnZS4NCi0gSG9sZCBgQ3RybGAgYW5kIHByZXNzIHRoZSBgRmAga2V5IHRvIHNlYXJjaCBmb3Igc3BlY2lmaWMgdGV4dCBvciBzdHJpbmdzIG9mIHRleHQuDQotIFByZXNzIHRoZSBgRXNjYCBrZXkgdG8gcXVpY2tseSBleGl0IHRoZSBzZWFyY2ggYm94Lg0KDQojIyBBYm91dCBUaGlzIFJlcG9ydCANCg0KVGhpcyByZXBvcnQgaXMgcHVibGlzaGVkIG9uIFJQdWJzW14xXS4gS0RGIHN0YW5kcyBmb3IgS2VuIERvZXMgRml0bmVzcy4gUmVmZXIgdG8gUmVmZXJlbmNlcyBhdCB0aGUgYm90dG9tIG9mIHRoaXMgcGFnZSBmb3IgY2l0ZWQgc291cmNlcy4gVGhlIFJNRCBmaWxlIHRvIHByb2R1Y2UgdGhpcyByZXBvcnQsIGFuZCBzb21lIG9mIHRoZSBmaWd1cmVzIGZyb20gdGhpcyByZXBvcnQsIG1heSBiZSBmb3VuZCBpbiB0aGUgR29vZ2xlIERyaXZlIGZvbGRlciBbXjJdLiANCg0KIyBTVFJFTkdUSCBTVEFOREFSRFMNCg0KU3RyZW5ndGggU3RhbmRhcmRzIHByb3ZpZGUgdmFsdWFibGUgYmVuY2htYXJrcyBmb3IgYXNzZXNzaW5nIGFuIGluZGl2aWR1YWwncyBwZXJmb3JtYW5jZSBpbiBrZXkgc3RyZW5ndGggZXhlcmNpc2VzIHRoYXQgYXJlIHdpZGVseSBwcmFjdGljZWQgaW4gZml0bmVzcyBhbmQgc3RyZW5ndGggdHJhaW5pbmcuIFRoZXNlIHN0YW5kYXJkcyBjYXRlZ29yaXplIHBlcmZvcm1hbmNlIGxldmVscyBiYXNlZCBvbiBlaXRoZXIgYW1vdW50IG9mIHdlaWdodCBleGVjdXRlZCByZWxhdGl2ZSB0byBib2R5d2VpZ2h0LCBvciByZXBldGl0aW9ucyBleGVjdXRlZCwgYW5kIGFyZSBzZWdtZW50ZWQgYnkgZ2VuZGVyIGFuZCBleHBlcmllbmNlIGxldmVscy4gQnkgY29tcGFyaW5nIGFuIGluZGl2aWR1YWwncyBwZXJmb3JtYW5jZSBhZ2FpbnN0IHRoZXNlIGVzdGFibGlzaGVkIHN0YW5kYXJkcywgdHJhaW5lcnMgYW5kIGF0aGxldGVzIGNhbiBpZGVudGlmeSBzdHJlbmd0aHMgYW5kIHdlYWtuZXNzZXMgaW4gdGhlaXIgdHJhaW5pbmcgcmVnaW1lbnMsIHNldCByZWFsaXN0aWMgZ29hbHMsIGFuZCBtZWFzdXJlIHByb2dyZXNzIGluIGEgc3RydWN0dXJlZCBtYW5uZXIuDQoNCiMjIFN0cmVuZ3RoIFN0YW5kYXJkcyBPdmVydmlldyANCg0KU2V2ZXJhbCBzdHJlbmd0aCBzdGFuZGFyZHMgYXJlIHJlYWRpbHkgYXZhaWxhYmxlIG9ubGluZToNCg0KLSBFeFJ4IFN0cmVuZ3RoIFN0YW5kYXJkczogPGh0dHBzOi8vZXhyeC5uZXQvVGVzdGluZy9XZWlnaHRMaWZ0aW5nL1N0cmVuZ3RoU3RhbmRhcmRzPg0KLSBTdHJlbmd0aExldmVsLmNvbSBTdHJlbmd0aCBTdGFuZGFyZHM6IDxodHRwczovL3N0cmVuZ3RobGV2ZWwuY29tL3N0cmVuZ3RoLXN0YW5kYXJkcz4NCi0gU3ltbWV0cmljIFN0cmVuZ3RoOiA8aHR0cHM6Ly9zeW1tZXRyaWNzdHJlbmd0aC5jb20vPg0KLSBNYXJrIFJpcHBldG9lJ3MgU3RyZW5ndGggU3RhbmRhcmRzOiA8aHR0cHM6Ly9zdGFydGluZ3N0cmVuZ3RoLmNvbS9maWxlcy9zdGFuZGFyZHMucGRmPg0KDQpGaW5kaW5nIGFjY3VyYXRlIHN0cmVuZ3RoIHN0YW5kYXJkcyBkZXBlbmRzIG9uIHRoZSBkZW1vZ3JhcGhpYywgZXhlcmNpc2UgdHlwZSwgYW5kIHJlcXVpcmVkIGFjY3VyYWN5LiBFYWNoIGhhcyBpdHMgcHJvcyBhbmQgY29uczogc29tZSBjYXRlciB0byBzcGVjaWZpYyBkZW1vZ3JhcGhpY3MsIG90aGVycyBmb2N1cyBvbiBjZXJ0YWluIGV4ZXJjaXNlcywgYW5kIHRoZWlyIGNyZWRpYmlsaXR5IGFmZmVjdHMgcmVsaWFiaWxpdHkuIFVzYWJpbGl0eSBhbmQgY29tcHJlaGVuc2l2ZSBkYXRhIGZvciBiZW5jaG1hcmtpbmcgYXJlIGNydWNpYWwsIGFzIGFyZSByZWd1bGFyIHVwZGF0ZXMgdG8gcmVmbGVjdCBjdXJyZW50IHRyZW5kcy4gQ29uc2lkZXJpbmcgdGhlc2UgZmFjdG9ycyBoZWxwcyB0cmFpbmVycyBhbmQgYXRobGV0ZXMgY2hvb3NlIHRoZSBiZXN0IHN0YW5kYXJkcyBmb3IgYXNzZXNzaW5nIGFuZCBpbXByb3ZpbmcgcGVyZm9ybWFuY2UuDQoNCmBgYHtyIHN0cmVuZ3RoX3N0YW5kYXJkc19wbmMsIGV2YWw9VFJVRSwgcmVzdWx0cz0nYXNpcyd9DQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcw0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoa2FibGVFeHRyYSkNCg0KIyBEZWZpbmUgdGhlIHByb3MgYW5kIGNvbnMgYXMgbGlzdHMNCnByb3MgPC0gYygiQmVuY2htYXJraW5nOiBTdHJlbmd0aCBzdGFuZGFyZHMgcHJvdmlkZSBjbGVhciBiZW5jaG1hcmtzIHRvIG1lYXN1cmUgcHJvZ3Jlc3MgYW5kIHNldCBnb2Fscy4iLA0KICAgICAgICAgICJNb3RpdmF0aW9uOiBTZWVpbmcgaG93IHlvdXIgcGVyZm9ybWFuY2Ugc3RhY2tzIHVwIGFnYWluc3QgZXN0YWJsaXNoZWQgc3RhbmRhcmRzIGNhbiBiZSBoaWdobHkgbW90aXZhdGluZy4iLA0KICAgICAgICAgICJHdWlkYW5jZTogVGhleSBvZmZlciBndWlkYW5jZSBvbiB3aGF0IGlzIGNvbnNpZGVyZWQgc3Ryb25nIG9yIHdlYWsgZm9yIGRpZmZlcmVudCBleGVyY2lzZXMsIGhlbHBpbmcgeW91IHRhaWxvciB5b3VyIHRyYWluaW5nIGFjY29yZGluZ2x5LiIsDQogICAgICAgICAgIkNvbXBhcmlzb246IFRoZXkgYWxsb3cgZm9yIG1lYW5pbmdmdWwgY29tcGFyaXNvbnMgYmV0d2VlbiBpbmRpdmlkdWFscywgaGVscGluZyB0byBpZGVudGlmeSBzdHJlbmd0aHMgYW5kIHdlYWtuZXNzZXMuIiwNCiAgICAgICAgICAiU3RydWN0dXJlZCBUcmFpbmluZzogU3RyZW5ndGggc3RhbmRhcmRzIGNhbiBoZWxwIGluIGRlc2lnbmluZyBtb3JlIHN0cnVjdHVyZWQgYW5kIGVmZmVjdGl2ZSB0cmFpbmluZyBwcm9ncmFtcy4iKQ0KDQpjb25zIDwtIGMoIkdlbmVyaWM6IFN0cmVuZ3RoIHN0YW5kYXJkcyBjYW4gYmUgdG9vIGdlbmVyaWMgYW5kIG1heSBub3QgYWNjb3VudCBmb3IgaW5kaXZpZHVhbCBkaWZmZXJlbmNlcyBpbiBnZW5ldGljcywgYm9keSBjb21wb3NpdGlvbiwgYW5kIHRyYWluaW5nIGhpc3RvcnkuIiwNCiAgICAgICAgICAiUHJlc3N1cmU6IFRoZXkgY2FuIGNyZWF0ZSB1bmR1ZSBwcmVzc3VyZSB0byBtZWV0IGNlcnRhaW4gYmVuY2htYXJrcywgcG90ZW50aWFsbHkgbGVhZGluZyB0byBpbmp1cnkgb3IgYnVybm91dC4iLA0KICAgICAgICAgICJPdXRkYXRlZCBJbmZvcm1hdGlvbjogU29tZSBzdGFuZGFyZHMgbWF5IGJlIGJhc2VkIG9uIG91dGRhdGVkIGluZm9ybWF0aW9uIG9yIG5vdCByZWZsZWN0IHJlY2VudCBhZHZhbmNlbWVudHMgaW4gc3BvcnRzIHNjaWVuY2UuIiwNCiAgICAgICAgICAiTm90IENvbXByZWhlbnNpdmU6IFRoZXkgbWlnaHQgbm90IGNvdmVyIGFsbCBleGVyY2lzZXMgb3IgYWNjb3VudCBmb3IgZGlmZmVyZW50IHRyYWluaW5nIGdvYWxzLCBzdWNoIGFzIGh5cGVydHJvcGh5IHZlcnN1cyBzdHJlbmd0aC4iLA0KICAgICAgICAgICJNaXNsZWFkaW5nOiBGb3IgYmVnaW5uZXJzLCBzdHJlbmd0aCBzdGFuZGFyZHMgY2FuIGJlIG1pc2xlYWRpbmcgaWYgdGhleSBkb27igJl0IGFjY291bnQgZm9yIHRoZSBzdGFydGluZyBwb2ludCBvciByYXRlIG9mIHByb2dyZXNzIGFwcHJvcHJpYXRlIGZvciBkaWZmZXJlbnQgZml0bmVzcyBsZXZlbHMuIikNCg0KIyBDb21iaW5lIHRoZSBwcm9zIGFuZCBjb25zIGludG8gYSBkYXRhIGZyYW1lDQpzdHJlbmd0aF9zdGFuZGFyZHNfcG5jIDwtIGRhdGEuZnJhbWUoDQogIFByb3MgPSBwcm9zLA0KICBDb25zID0gY29ucywNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgUHJpbnQgdGhlIHRhYmxlIHVzaW5nIGthYmxlIGFuZCBrYWJsZUV4dHJhDQprYWJsZShzdHJlbmd0aF9zdGFuZGFyZHNfcG5jLCBmb3JtYXQgPSAiaHRtbCIsIGVzY2FwZSA9IEZBTFNFLCBjb2wubmFtZXMgPSBjKCJQcm9zIiwgIkNvbnMiKSkgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIiksIGZ1bGxfd2lkdGggPSBUUlVFKSAlPiUNCiAgY29sdW1uX3NwZWMoMSwgd2lkdGggPSAiNTAlIikgJT4lDQogIGNvbHVtbl9zcGVjKDIsIHdpZHRoID0gIjUwJSIpDQoNCmBgYA0KDQpJJ3ZlIGNvbXBpbGVkIHNvbWUgb2YgdGhlIHN0YW5kYXJkcyBpbnRvIGFuIEV4Y2VsIGZpbGVbXjNdLiBUaGlzIGFsbG93cyBmb3IgY29tcGFyaXNvbiBiZXR3ZWVuIHBlcnNvbmFsIHBlcmZvcm1hbmNlIG1lYXN1cmVzIGFuZCB0aGUgc3BlY2lmaWVkIHN0cmVuZ3RoIHN0YW5kYXJkcy4gSSByZWNvbW1lbmQgY29uc3VsdGluZyBlYWNoIHNvdXJjZSBmb3IgY29uZmlybWF0aW9uIG9uIHRoZSBsYXRlc3QgdmVyc2lvbiwgYXMgdGhlIHN0cnVjdHVyZSBvciBudW1iZXJzIG1heSBoYXZlIGNoYW5nZWQgb3ZlciB0aW1lLiANCg0KYGBge3IgcmVhZF9zdHJlbmd0aF9zdGFuZGFyZHMsIGV2YWw9VFJVRX0NCg0KIyBGaWxlIFBhdGggRGVmaW5pdGlvbjogVGhlIHNjcmlwdCBkZWZpbmVzIGEgcGF0aCB0byBhbiBFeGNlbCBmaWxlIGNvbnRhaW5pbmcgIlN0cmVuZ3RoIFN0YW5kYXJkcyIuDQpmaWxlX3BhdGhfc3RyZW5ndGhfc3RhbmRhcmRzIDwtICJDOi8vVXNlcnMvL2tlbmRyLy9PbmVEcml2ZS8vRG9jdW1lbnRzLy9EYXRhIEFuYWx5dGljcy8vS2VuRG9lc0ZpdG5lc3MvU3RyZW5ndGggU3RhbmRhcmRzIEZpbmFsLnhsc20iDQoNCiMgV29ya2Jvb2sgTG9hZGluZzogTG9hZHMgdGhlIEV4Y2VsIHdvcmtib29rIGludG8gUiB1c2luZyB0aGUgb3Blbnhsc3ggcGFja2FnZSwgd2hpY2ggcHJvdmlkZXMgbW9yZSBhZHZhbmNlZCBjb250cm9sIG92ZXIgRXhjZWwgZmlsZXMgdGhhbiByZWFkeGwuDQpzdHJlbmd0aF9zdGFuZGFyZHMgPC0gbG9hZFdvcmtib29rKGZpbGVfcGF0aF9zdHJlbmd0aF9zdGFuZGFyZHMpDQpgYGANCg0KIyMgU3RhbmRhcmRzIENhdGVnb3JpZXMgIA0KVGhlIHN0YW5kYXJkcyBjb21waWxlZCBhcmUgc2VwYXJhdGVkIGludG8gY2F0ZWdvcmllcywgYXMgc2hvd24gaW4gdGhlIGZvbGxvd2luZyB0YWJsZSwgbWFraW5nIGl0IGVhc3kgdG8gZGV0ZXJtaW5lIHdoaWNoIGV4ZXJjaXNlIHRvIHVzZSBhcyBhIGJlbmNobWFyay4NCg0KYGBge3Igc3RyZW5ndGhfc3RhbmRhcmRzX3NoZWV0X25hbWVzLCBldmFsPVRSVUUsIHJlc3VsdHM9J21hcmt1cCd9DQoNCiMgU2hlZXQgTmFtZXMgRGlzcGxheTogUmV0cmlldmVzIGFuZCBkaXNwbGF5cyB0aGUgbmFtZXMgb2Ygc2hlZXRzIHdpdGhpbiB0aGUgRXhjZWwgd29ya2Jvb2sgdG8gaGVscCBpZGVudGlmeSBhdmFpbGFibGUgZGF0YS4NCg0KIyBDaGVjayB0byBjb25maXJtIHdoaWNoIG51bWJlciBvZiBuYW1lcyB0byBkaXNwbGF5DQojIG5hbWVzKHN0cmVuZ3RoX3N0YW5kYXJkcykNCg0KIyBEaXNwbGF5IHNwZWNpZmljIGVsZW1lbnRzIGZyb20gdGhlIHN0cmVuZ3RoX3N0YW5kYXJkcyBvYmplY3Qgd2l0aCBJbmRleGluZw0KbmFtZXNfc3Vic2V0X3N0cmVuZ3RoX3N0YW5kYXJkcyA8LSBuYW1lcyhzdHJlbmd0aF9zdGFuZGFyZHMpWzQ6MTVdDQpuYW1lc19zdWJzZXRfc3RyZW5ndGhfc3RhbmRhcmRzX2dzdWIgPSBnc3ViKCJfIiwiICIsIG5hbWVzX3N1YnNldF9zdHJlbmd0aF9zdGFuZGFyZHMpDQojIG5hbWVzX3N1YnNldF9zdHJlbmd0aF9zdGFuZGFyZHMNCg0KIyBDYWxjdWxhdGUgdGhlIG51bWJlciBvZiBuYW1lcw0KbnVtX25hbWVzIDwtIGxlbmd0aChuYW1lc19zdWJzZXRfc3RyZW5ndGhfc3RhbmRhcmRzX2dzdWIpDQoNCiMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgbmFtZXMgcGVyIGNvbHVtbg0KbmFtZXNfcGVyX2NvbHVtbiA8LSBjZWlsaW5nKG51bV9uYW1lcyAvIDIpDQoNCiMgU3BsaXQgdGhlIG5hbWVzIGludG8gdHdvIGNvbHVtbnMNCmNvbHVtbl8xIDwtIG5hbWVzX3N1YnNldF9zdHJlbmd0aF9zdGFuZGFyZHNfZ3N1YlsxOm1pbihuYW1lc19wZXJfY29sdW1uLCBudW1fbmFtZXMpXQ0KY29sdW1uXzIgPC0gbmFtZXNfc3Vic2V0X3N0cmVuZ3RoX3N0YW5kYXJkc19nc3ViWyhtaW4obmFtZXNfcGVyX2NvbHVtbiwgbnVtX25hbWVzKSArIDEpOm51bV9uYW1lc10NCg0KIyBQYWQgdGhlIHNob3J0ZXIgY29sdW1uIHdpdGggTkEgdmFsdWVzIGlmIG5lY2Vzc2FyeQ0KaWYobGVuZ3RoKGNvbHVtbl8xKSA8IGxlbmd0aChjb2x1bW5fMikpIHsNCiAgY29sdW1uXzEgPC0gYyhjb2x1bW5fMSwgcmVwKCIiLCBsZW5ndGgoY29sdW1uXzIpIC0gbGVuZ3RoKGNvbHVtbl8xKSkpDQp9IGVsc2UgaWYobGVuZ3RoKGNvbHVtbl8yKSA8IGxlbmd0aChjb2x1bW5fMSkpIHsNCiAgY29sdW1uXzIgPC0gYyhjb2x1bW5fMiwgcmVwKCIiLCBsZW5ndGgoY29sdW1uXzEpIC0gbGVuZ3RoKGNvbHVtbl8yKSkpDQp9DQogIA0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggdHdvIGNvbHVtbnMNCm5hbWVzX3N1YnNldF9zdHJlbmd0aF9zdGFuZGFyZHNfZ3N1Yl9kZiA8LSBkYXRhLmZyYW1lKENvbHVtbl8xID0gY29sdW1uXzEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDb2x1bW5fMiA9IGNvbHVtbl8yKQ0KDQojIENhbGN1bGF0ZSB0aGUgd2lkdGggZHluYW1pY2FsbHkNCmNvbF93aWR0aCA8LSBwYXN0ZTAoMTAwIC8gbmNvbChuYW1lc19zdWJzZXRfc3RyZW5ndGhfc3RhbmRhcmRzX2dzdWJfZGYpLCAiJSIpDQoNCiMgUHJpbnQgdGhlIGRhdGEgZnJhbWUgdXNpbmcga25pdHI6OmthYmxlDQprbml0cjo6a2FibGUobmFtZXNfc3Vic2V0X3N0cmVuZ3RoX3N0YW5kYXJkc19nc3ViX2RmLCBmb3JtYXQgPSAibWFya2Rvd24iLCBjb2wubmFtZXMgPSBjKCJDYXRlZ29yaWVzIiwgIkNhdGVnb3JpZXMiKSkgJT4lDQogIGNvbHVtbl9zcGVjKDE6Miwgd2lkdGggPSBjb2xfd2lkdGgsIGV4dHJhX2NzcyA9ICJ0ZXh0LWFsaWduOiBsZWZ0OyIpDQoNCmBgYA0KDQojIyBTdHJlbmd0aCBTdGFuZGFyZHMgTGlzdCANCkJlbG93IGlzIHRoZSBsaXN0IG9mIFN0cmVuZ3RoIFN0YW5kYXJkcyBjb21waWxlZCBpbnRvIHRoZSBTUyBFeGNlbCBmaWxlW14zXS4gVGhpcyBmaWxlIHJlZmVyZW5jZXMgdGhlIHNvdXJjZSBvZiBlYWNoIHN0YW5kYXJkIHRhYmxlLiBXZSdsbCBkZWx2ZSBpbnRvIE1hcmsgUmlwcGV0b2UncyBTdGFydGluZyBTdHJlbmd0aCBTdGFuZGFyZHMsIGFzIGhpcyBhbmQgaGlzIGNvbGxlYWd1ZXMnIG1ldGhvZHMgYW5kIHJlc2VhcmNoIGFyZSBiYXNlZCBvbiBjb21wcmVoZW5zaXZlIGFuZCB0ZWNobmljYWwgaW5mb3JtYXRpb24uDQoNCmBgYHtyIG5hbWVkX3JhbmdlcywgZXZhbD1UUlVFLCByZXN1bHRzPSdtYXJrdXAnfQ0KDQpsaWJyYXJ5KG9wZW54bHN4KQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KDQojIFJlYWQgTmFtZWQgUmFuZ2VzOiBSZWFkcyBhIHNwZWNpZmljIHNoZWV0IG5hbWVkICJOYW1lZF9SYW5nZXMiIHRoYXQgcHJlc3VtYWJseSBjb250YWlucyBtZXRhZGF0YSBhYm91dCBvdGhlciBuYW1lZCByYW5nZXMgaW4gdGhlIHdvcmtib29rLiBJdCBrZWVwcyBvbmx5IHRoZSBjb2x1bW5zIHJlbGF0ZWQgdG8gbmFtZWQgcmFuZ2VzIGFuZCB0aGVpciByZXNwZWN0aXZlIHNoZWV0cy4NCm5hbWVkX3JhbmdlcyA8LSByZWFkX2V4Y2VsKGZpbGVfcGF0aF9zdHJlbmd0aF9zdGFuZGFyZHMsIHNoZWV0ID0gIk5hbWVkX1JhbmdlcyIpDQpzaGVldF9uYW1lc19maWx0ZXJlZCA8LSB1bmlxdWUobmFtZWRfcmFuZ2VzJGBDYXRlZ29yeSBTaGVldGApDQpuYW1lZF9yYW5nZXMgPC0gbmFtZWRfcmFuZ2VzW25hbWVkX3JhbmdlcyRgQ2F0ZWdvcnkgU2hlZXRgICVpbiUgc2hlZXRfbmFtZXNfZmlsdGVyZWQsIGMoIlN0cmVuZ3RoIFN0YW5kYXJkIiwgIkNhdGVnb3J5IFNoZWV0IildDQoNCiMgRGlzcGxheSB0aGUgbW9kaWZpZWQgJ1N0cmVuZ3RoIFN0YW5kYXJkJyBjb2x1bW4gd2l0aCBzcGFjZXMgaW5zdGVhZCBvZiB1bmRlcnNjb3Jlcw0Kc3RyZW5ndGhfc3RhbmRhcmRzX2xpc3RfZGlzcGxheSA8LSBuYW1lZF9yYW5nZXMgJT4lDQogIG11dGF0ZShgU3RyZW5ndGggU3RhbmRhcmRgID0gZ3N1YigiXyIsICIgIiwgYFN0cmVuZ3RoIFN0YW5kYXJkYCkpICU+JQ0KICBtdXRhdGUoYENhdGVnb3J5IE5hbWVgID0gZ3N1YigiXyIsICIgIiwgYENhdGVnb3J5IFNoZWV0YCkpICU+JQ0KICBzZWxlY3QoLWBDYXRlZ29yeSBTaGVldGApICAjIFRoaXMgZXhjbHVkZXMgdGhlICdDYXRlZ29yeSBTaGVldCcgY29sdW1uDQoNCiMgVmlldyB0aGUgZGF0YSBmcmFtZSBpZiBuZWVkZWQgKG5vdCBkdXJpbmcga25pdHRpbmcpLiBWaWV3IGZ1bmN0aW9uIG9wZW5zIHRoZSByYXdfZGF0YSBkYXRhZnJhbWUgaW4gdGhlIFJTdHVkaW8gZGF0YSB2aWV3ZXIgZm9yIGludGVyYWN0aXZlIGV4cGxvcmF0aW9uLg0KVmlldyhuYW1lZF9yYW5nZXMpDQpWaWV3KHN0cmVuZ3RoX3N0YW5kYXJkc19saXN0X2Rpc3BsYXkpDQoNCiMgRGVmaW5lIHRoZSByYXRpb3MgYW5kIHRvdGFsIHdpZHRoIGZvciBjb2x1bW4gd2lkdGhzDQp0b3RhbF93aWR0aCA8LSAxMDANCnJhdGlvX3N0cmVuZ3RoX3N0YW5kYXJkcyA8LSAyDQpyYXRpb19jYXRlZ29yeSA8LSAxLjI1DQp0b3RhbF9yYXRpbyA8LSByYXRpb19zdHJlbmd0aF9zdGFuZGFyZHMgKyByYXRpb19jYXRlZ29yeQ0KDQojIENhbGN1bGF0ZSB0aGUgY29sdW1uIHdpZHRocw0Kd2lkdGhfc3RyZW5ndGhfc3RhbmRhcmRzIDwtIChyYXRpb19zdHJlbmd0aF9zdGFuZGFyZHMgLyB0b3RhbF9yYXRpbykgKiB0b3RhbF93aWR0aA0Kd2lkdGhfY2F0ZWdvcnkgPC0gKHJhdGlvX2NhdGVnb3J5IC8gdG90YWxfcmF0aW8pICogdG90YWxfd2lkdGgNCg0KIyBQcmludCB0aGUgZGF0YWZyYW1lIHVzaW5nIGthYmxlIGZvciBhIG5pY2VseSBmb3JtYXR0ZWQgbWFya2Rvd24gdGFibGUuDQprYWJsZShzdHJlbmd0aF9zdGFuZGFyZHNfbGlzdF9kaXNwbGF5LCBmb3JtYXQgPSAiaHRtbCIsIGNvbC5uYW1lcyA9IGMoIlN0cmVuZ3RoIFN0YW5kYXJkIiwgIkNhdGVnb3J5IikpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUUlVFKSAlPiUNCiAgY29sdW1uX3NwZWMoMSwgd2lkdGggPSBwYXN0ZTAod2lkdGhfc3RyZW5ndGhfc3RhbmRhcmRzLCAiJSIpKSAlPiUNCiAgY29sdW1uX3NwZWMoMiwgd2lkdGggPSBwYXN0ZTAod2lkdGhfY2F0ZWdvcnksICIlIikpDQoNCiMgQ3JlYXRlIGxpc3RzIHRvIHN0b3JlIGRhdGEgZnJhbWVzDQpuYW1lZF9yYW5nZXNfbGlzdCA8LSBsaXN0KCkNCm5hbWVkX3Jhbmdlc19zaGVldHNfbGlzdCA8LSBsaXN0KCkNCg0KIyBMb29wIHRocm91Z2ggdGhlIG5hbWVkIHJhbmdlcw0KZm9yIChpIGluIDE6bnJvdyhuYW1lZF9yYW5nZXMpKSB7DQogIG5hbWVkX3JhbmdlX3ZhbHVlIDwtIG5hbWVkX3JhbmdlcyRgU3RyZW5ndGggU3RhbmRhcmRgW2ldDQogIG5hbWVkX3JhbmdlX3NoZWV0X3ZhbHVlIDwtIG5hbWVkX3JhbmdlcyRgQ2F0ZWdvcnkgU2hlZXRgW2ldDQogIG5hbWVkX3JhbmdlX2xvd2VyIDwtIHRvbG93ZXIoZ3N1YigiICIsICJfIiwgbmFtZWRfcmFuZ2VfdmFsdWUpKQ0KICBuYW1lZF9yYW5nZV9zaGVldF9sb3dlciA8LSB0b2xvd2VyKGdzdWIoIiAiLCAiXyIsIG5hbWVkX3JhbmdlX3NoZWV0X3ZhbHVlKSkNCiAgDQogIGlmIChuYW1lZF9yYW5nZV9zaGVldF92YWx1ZSA9PSAiTmFtZWRfUmFuZ2VzIikgew0KICAgIG5leHQgICMgU2tpcCBpdGVyYXRpb24gaWYgdGhlIHNoZWV0IGlzICJOYW1lZF9SYW5nZXMiIHRvIGF2b2lkIHJlZHVuZGFuY3kNCiAgfQ0KICANCiAgIyBSZWFkIGRhdGEgZnJvbSB0aGUgbmFtZWQgcmFuZ2UNCiAgbmFtZWRfcmFuZ2VfZGF0YSA8LSB0cnlDYXRjaCh7DQogICAgcmVhZC54bHN4KGZpbGVfcGF0aF9zdHJlbmd0aF9zdGFuZGFyZHMsIG5hbWVkUmVnaW9uID0gbmFtZWRfcmFuZ2VfdmFsdWUpDQogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgew0KICAgIG1lc3NhZ2UocGFzdGUoIldhcm5pbmc6IFdvcmtib29rIGhhcyBubyBzdWNoIG5hbWVkIHJlZ2lvbjoiLCBuYW1lZF9yYW5nZV92YWx1ZSkpDQogICAgTlVMTA0KICB9KQ0KICANCiAgaWYgKCFpcy5udWxsKG5hbWVkX3JhbmdlX2RhdGEpICYmIGlzLmRhdGEuZnJhbWUobmFtZWRfcmFuZ2VfZGF0YSkpIHsNCiAgICAjIFVwZGF0ZSBjb2x1bW4gbmFtZXMNCiAgICBjb2xuYW1lcyhuYW1lZF9yYW5nZV9kYXRhKSA8LSBnc3ViKCJcXC4iLCAiICIsIGNvbG5hbWVzKG5hbWVkX3JhbmdlX2RhdGEpKQ0KICAgICMgU3RvcmUgdGhlIGRhdGEgZnJhbWUgaW4gdGhlIGxpc3QNCiAgICBuYW1lZF9yYW5nZXNfbGlzdFtbbmFtZWRfcmFuZ2VfbG93ZXJdXSA8LSBuYW1lZF9yYW5nZV9kYXRhDQogICAgIyBBc3NpZ24gdGhlIGRhdGEgZnJhbWUgdG8gdGhlIGdsb2JhbCBlbnZpcm9ubWVudCB3aXRoIHRoZSBsb3dlciBjYXNlIG5hbWUNCiAgICBhc3NpZ24obmFtZWRfcmFuZ2VfbG93ZXIsIG5hbWVkX3JhbmdlX2RhdGEsIGVudmlyID0gLkdsb2JhbEVudikNCiAgfQ0KICANCiAgIyBSZWFkIGRhdGEgZnJvbSB0aGUgc2hlZXQNCiAgbmFtZWRfcmFuZ2Vfc2hlZXRfZGF0YSA8LSB0cnlDYXRjaCh7DQogICAgcmVhZC54bHN4KGZpbGVfcGF0aF9zdHJlbmd0aF9zdGFuZGFyZHMsIHNoZWV0ID0gbmFtZWRfcmFuZ2Vfc2hlZXRfdmFsdWUpDQogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgew0KICAgIG1lc3NhZ2UocGFzdGUoIldhcm5pbmc6IFdvcmtib29rIGhhcyBubyBzdWNoIHNoZWV0OiIsIG5hbWVkX3JhbmdlX3NoZWV0X3ZhbHVlKSkNCiAgICBOVUxMDQogIH0pDQogIA0KICBpZiAoIWlzLm51bGwobmFtZWRfcmFuZ2Vfc2hlZXRfZGF0YSkgJiYgaXMuZGF0YS5mcmFtZShuYW1lZF9yYW5nZV9zaGVldF9kYXRhKSkgew0KICAgICMgVXBkYXRlIGNvbHVtbiBuYW1lcw0KICAgIGNvbG5hbWVzKG5hbWVkX3JhbmdlX3NoZWV0X2RhdGEpIDwtIGdzdWIoIlxcLiIsICIgIiwgY29sbmFtZXMobmFtZWRfcmFuZ2Vfc2hlZXRfZGF0YSkpDQogICAgIyBTdG9yZSB0aGUgZGF0YSBmcmFtZSBpbiB0aGUgbGlzdA0KICAgIG5hbWVkX3Jhbmdlc19zaGVldHNfbGlzdFtbbmFtZWRfcmFuZ2Vfc2hlZXRfbG93ZXJdXSA8LSBuYW1lZF9yYW5nZV9zaGVldF9kYXRhDQogICAgIyBBc3NpZ24gdGhlIGRhdGEgZnJhbWUgdG8gdGhlIGdsb2JhbCBlbnZpcm9ubWVudCB3aXRoIHRoZSBsb3dlciBjYXNlIG5hbWUNCiAgICBhc3NpZ24obmFtZWRfcmFuZ2Vfc2hlZXRfbG93ZXIsIG5hbWVkX3JhbmdlX3NoZWV0X2RhdGEsIGVudmlyID0gLkdsb2JhbEVudikNCiAgfQ0KfQ0KDQojIERpc3BsYXkgdGhlIHN0cnVjdHVyZSBvZiB0aGUgbGlzdHMNCiMgc3RyKG5hbWVkX3Jhbmdlc19saXN0KQ0KIyBzdHIobmFtZWRfcmFuZ2VzX3NoZWV0c19saXN0KQ0KDQojIE9wdGlvbmFsOiBWaWV3IHRoZSBjb250ZW50cyBvZiB0aGUgbGlzdHMgaW4gUlN0dWRpbyBWaWV3ZXINCiMgSW5zdGVhZCBvZiB2aWV3aW5nIHRoZSB3aG9sZSBsaXN0LCB2aWV3IGluZGl2aWR1YWwgZGF0YSBmcmFtZXMNCiMgVW5jb21tZW50IHRoZSBiZWxvdyBsaW5lcyB0byB2aWV3IHNwZWNpZmljIG5hbWVkIHJhbmdlcyBvciBzaGVldHMNCiMgVmlldyhuYW1lZF9yYW5nZXNfbGlzdFtbIm1hbGVfYmFyYmVsbF9jdXJsX3N0ZF8xcm1fYnlfYWdlX3N0cmVuZ3RobGV2ZWwiXV0pDQojIFZpZXcobWFsZV9iYXJiZWxsX2N1cmxfc3RkXzFybV9ieV9hZ2Vfc3RyZW5ndGhsZXZlbCkNCg0KYGBgDQoNCiMgTUFSSyBSSVBQRVRPRSdTIFNUQU5EQVJEUw0KDQpNYXJrIFJpcHBldG9lJ3MgU3RyZW5ndGggU3RhbmRhcmQ6IDEgUmVwIE1heCBCeSBCb2R5d2VpZ2h0LiAgDQoNCkhlcmUgd2UgdXRpbGl6ZSBNYXJrIFJpcHBldG9lJ3MgU3RyZW5ndGggU3RhbmRhcmRzW140XSB0byBiZW5jaG1hcmsgaW5kaXZpZHVhbCBwZXJmb3JtYW5jZSBhZ2FpbnN0IGVzdGFibGlzaGVkIGNyaXRlcmlhIGZvciBwcmltYXJ5IHN0cmVuZ3RoIGV4ZXJjaXNlcy4gVGhlc2Ugc3RhbmRhcmRzIGFyZSBpbnN0cnVtZW50YWwgaW4gZXZhbHVhdGluZyBhbiBpbmRpdmlkdWFsJ3MgbGlmdGluZyBjYXBhYmlsaXRpZXMgaW4gcmVsYXRpb24gdG8gdGhlaXIgYm9keXdlaWdodCBhbmQgdHJhaW5pbmcgZXhwZXJpZW5jZS4gQnkgZG9pbmcgc28sIHdlIGNhbiBlZmZlY3RpdmVseSBnYXVnZSBwcm9ncmVzcywgcGlucG9pbnQgYXJlYXMgdGhhdCBuZWVkIGltcHJvdmVtZW50LCBhbmQgdGFpbG9yIHRyYWluaW5nIHByb2dyYW1zIHRvIGJldHRlciBtZWV0IHRoZSBzcGVjaWZpYyBzdHJlbmd0aCBnb2FscyBvZiBlYWNoIGluZGl2aWR1YWwuDQoNClRoZSBleGVyY2lzZXMgdXNlIHRoZSB0ZWNobmlxdWUgZGVzY3JpYmVkIGluICJTdGFydGluZyBTdHJlbmd0aDogQmFzaWMgQmFyYmVsbCBUcmFpbmluZywgM3JkIGVkLiIgVGhlIEJsdWVib29rIG1heSBiZSBwdXJjaGFzZWQgdGhyb3VnaCBUaGUgQWFzZ2FhcmQgQ29tcGFueSBvbmxpbmUgc3RvcmVbXjVdIGFuZCBvbiBBbWF6b24gaW4gdmFyaW91cyBtZWRpdW1zIChwYXBlcmJhY2ssIEtpbmRsZSwgYXVkaW8pLiBBbGwgbGlmdHMgYXJlIHBlcmZvcm1lZCB3aXRoIHRoZSBiYXJiZWxsLCBhcyBpbmRpY2F0ZWQgYnkgdGhlIGJvb2sgdGl0bGUuDQoNClRvIHByb3Blcmx5IHV0aWxpemUgdGhlc2Ugc3RhbmRhcmRzLCBpdCBpcyByZWNvbW1lbmRlZCB0byByZXZpZXcgIlN0YXJ0aW5nIFN0cmVuZ3RoOiBCYXNpYyBCYXJiZWxsIFRyYWluaW5nIlteOF0gYW5kICJQcmFjdGljYWwgUHJvZ3JhbW1pbmcgZm9yIFN0cmVuZ3RoIFRyYWluaW5nLiJbXjldIFRoZSBtb3N0IHJlY2VudCBhbmQgcmVsZXZhbnQgM3JkIGVkaXRpb25zICgyMDEyKSBhcmUgYXZhaWxhYmxlIG9uIHRoZWlyIHdlYnNpdGUsIGFzIHdlbGwgYXMgaW4gZGlmZmVyZW50IG1lZGl1bXMgb24gQW1hem9uLiBZb3UgY2FuIGRvd25sb2FkIG9ubGluZSBib29rIHNhbXBsZXMgdG8gZGV0ZXJtaW5lIGlmIFN0YXJ0aW5nIFN0cmVuZ3RoIHN1aXRzIHlvdXIgbmVlZHMuDQoNCmBgYHtyIG1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QsIGV2YWw9VFJVRSwgcmVzdWx0cz0nbWFya3VwJ30NCg0KIyBDb2RlIGV4dHJhY3RzIGFuZCByZWZpbmVzIGEgc3Vic2V0IG9mIGRhdGEgcmVsYXRlZCB0byAiTWFyayBSaXBwZXRvZSIgc3RhbmRhcmRzIGZyb20gYSBicm9hZGVyIGRhdGFzZXQsIG1ha2luZyBpdCBtb3JlIGFjY2Vzc2libGUgYW5kIGVhc2llciB0byB3b3JrIHdpdGggYnkgY2xlYW5pbmcgdXAgdGhlIGNhdGVnb3J5IG5hbWVzIGZvciBmdXJ0aGVyIGFuYWx5c2lzIG9yIHJlcG9ydGluZw0KDQojIHN1YnNldCgpIGZpbHRlcnMgcm93cyBmcm9tIHRoZSBuYW1lZF9yYW5nZXMgZGF0YWZyYW1lLg0KIyBncmVwbCgpIGNoZWNrcyBlYWNoIGVudHJ5IGluIHRoZSAiU3RyZW5ndGggU3RhbmRhcmQiIGNvbHVtbiBmb3IgdGhlIHN1YnN0cmluZyANCm1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QgPC0gc3Vic2V0KG5hbWVkX3JhbmdlcywgZ3JlcGwoIk1hcmtfUmlwcGV0b2UiLCBgU3RyZW5ndGggU3RhbmRhcmRgKSkNCg0KIyBQaXBlIE9wZXJhdG9yICglPiUpIGlzIHVzZWQgdG8gcGFzcyB0aGUgcmVzdWx0IG9mIG9uZSBmdW5jdGlvbiB0byB0aGUgbmV4dC4gSXQgaGVscHMgaW4gd3JpdGluZyBjbGVhbmVyIGFuZCBtb3JlIHJlYWRhYmxlIGNvZGUsIGVzcGVjaWFsbHkgd2hlbiBwZXJmb3JtaW5nIG11bHRpcGxlIG9wZXJhdGlvbnMgb24gYSBkYXRhc2V0Lg0KIyBnc3ViKCJfIiwgIiAiLCBDYXRlZ29yeSBTaGVldCkgcmVwbGFjZXMgdW5kZXJzY29yZXMgKF8pIHdpdGggc3BhY2VzIGluIHRoZSBDYXRlZ29yeSBTaGVldCBjb2x1bW4uDQojIE5ldyBjb2x1bW4gaXMgY3JlYXRlZC4gDQptYXJrX3JpcHBldG9lX3N0YW5kYXJkc19saXN0IDwtIG1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QgJT4lDQogIG11dGF0ZShgQ2F0ZWdvcnkgTmFtZWAgPSBnc3ViKCJfIiwgIiAiLCBgQ2F0ZWdvcnkgU2hlZXRgKSkNCg0KIyBEaXNwbGF5IHRoZSBtb2RpZmllZCAnU3RyZW5ndGggU3RhbmRhcmQnIGNvbHVtbiB3aXRoIHNwYWNlcyBpbnN0ZWFkIG9mIHVuZGVyc2NvcmVzDQpkaXNwbGF5X21hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QgPC0gbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCAlPiUNCiAgbXV0YXRlKGBTdHJlbmd0aCBTdGFuZGFyZGAgPSBnc3ViKCJfIiwgIiAiLCBgU3RyZW5ndGggU3RhbmRhcmRgKSkgJT4lDQogIHNlbGVjdCgtYENhdGVnb3J5IFNoZWV0YCkgICMgVGhpcyBleGNsdWRlcyB0aGUgJ0NhdGVnb3J5IFNoZWV0JyBjb2x1bW4NCg0KIyBUaGUgVmlldyBmdW5jdGlvbiBpcyB1c2VkIHRvIG9wZW4gdGhlIHJhd19kYXRhIGRhdGFmcmFtZSBpbiB0aGUgUlN0dWRpbyBkYXRhIHZpZXdlciBmb3IgaW50ZXJhY3RpdmUgZXhwbG9yYXRpb24uDQpWaWV3KG1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QpICNSdW4gdGhpcyBsaW5lIG9mIGNvZGUgdG8gdmlldyB0YWJsZS4gDQoNCiMgUHJpbnQgZm9yIHJlZmVyZW5jZS4gDQojIHByaW50KG1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QpDQojIHByaW50KGRpc3BsYXlfbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCkNCg0KIyBEZWZpbmUgdGhlIHJhdGlvcyBhbmQgdG90YWwgd2lkdGggZm9yIGNvbHVtbiB3aWR0aHMNCnRvdGFsX3dpZHRoIDwtIDEwMA0KcmF0aW9fc3RyZW5ndGhfc3RhbmRhcmRzIDwtIDINCnJhdGlvX2NhdGVnb3J5IDwtIDEuMjUNCnRvdGFsX3JhdGlvIDwtIHJhdGlvX3N0cmVuZ3RoX3N0YW5kYXJkcyArIHJhdGlvX2NhdGVnb3J5DQoNCiMgQ2FsY3VsYXRlIHRoZSBjb2x1bW4gd2lkdGhzDQp3aWR0aF9zdHJlbmd0aF9zdGFuZGFyZHMgPC0gKHJhdGlvX3N0cmVuZ3RoX3N0YW5kYXJkcyAvIHRvdGFsX3JhdGlvKSAqIHRvdGFsX3dpZHRoDQp3aWR0aF9jYXRlZ29yeSA8LSAocmF0aW9fY2F0ZWdvcnkgLyB0b3RhbF9yYXRpbykgKiB0b3RhbF93aWR0aA0KDQojIFByaW50IHRoZSBkYXRhZnJhbWUgdXNpbmcga2FibGUgZm9yIGEgbmljZWx5IGZvcm1hdHRlZCBtYXJrZG93biB0YWJsZS4NCmthYmxlKGRpc3BsYXlfbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCwgZm9ybWF0ID0gImh0bWwiLCBjb2wubmFtZXMgPSBjKCJTdHJlbmd0aCBTdGFuZGFyZCIsICJDYXRlZ29yeSIpKSAlPiUNCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gVFJVRSkgJT4lDQogIGNvbHVtbl9zcGVjKDEsIHdpZHRoID0gcGFzdGUwKHdpZHRoX3N0cmVuZ3RoX3N0YW5kYXJkcywgIiUiKSkgJT4lDQogIGNvbHVtbl9zcGVjKDIsIHdpZHRoID0gcGFzdGUwKHdpZHRoX2NhdGVnb3J5LCAiJSIpKQ0KDQoNCmBgYA0KDQpUaGVyZSBhcmUgZml2ZSBTdGFydGluZyBTdHJlbmd0aCBTdGFuZGFyZHMsIHdpdGggdGhlIFBvd2VyIENsZWFuIGV4Y2x1ZGVkIGluIHRoaXMgcmVwb3J0IGFzIG15IGNvbGxlYWd1ZXMgYW5kIEkgZG8gbm90IHBlcmZvcm0gdGhhdCBleGVyY2lzZS4gRWFjaCBvZiB0aGUgZm91ciByZW1haW5pbmcgU3RhbmRhcmRzIGlzIHByZXNlbnRlZCBiZWxvdywgZm9sbG93ZWQgYnkgYSBwbG90IHRvIHZpc3VhbGl6ZSBwZXJmb3JtYW5jZXMgZm9yIGNvbXBhcmlzb24gYW5kIG1vdGl2YXRpb24uDQoNCmBgYHtyIG1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX3RhYmxlc19hbmRfcGxvdHMsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03LCBldmFsPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQ0KDQojIEtlZXAgZmlnLndpZHRoPTEwIGZvciBQREYgZGlzcGxheSAodmlhIGJyb3dzZXIgPiBTYXZlIEFzIFBERikuIFdoaWxlIGZpZy53aWR0aD05IChpbnN0ZWFkIG9mIDEwKSBmaXRzIHdpZHRoIG9mIG91dHB1dCwgc2F2aW5nIGFzIFBERiB3aXRoIGZpZy53aWR0aD05IHdpbGwgcmVzdWx0IGluIHNtYWxsIGZpZ3VyZTsgd2lkdGg9MTAgd2lsbCBmaWxsIHRoZSBQREYgcGFnZS4NCg0KIyBMb2FkIHRoZSByZXF1aXJlZCBwYWNrYWdlcyBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShrYWJsZUV4dHJhKSAjIEVuc3VyZSBrYWJsZUV4dHJhIGlzIGxvYWRlZCBmb3Igc3R5bGluZw0KDQojIEZ1bmN0aW9uIHRvIGdlbmVyYXRlIGdncGxvdCBmb3IgZWFjaCBkYXRhIGZyYW1lDQpnZW5lcmF0ZV9nZ3Bsb3QgPC0gZnVuY3Rpb24oZGF0YSwgY2F0ZWdvcnlfbmFtZSwgbWFya19yaXBwZXRvZV9zdHJlbmd0aF9zdGFuZGFyZCkgew0KICBkYXRhX251bWJlciA8LSBkYXRhICU+JQ0KICAgIG11dGF0ZShCb2R5d2VpZ2h0ID0gYXMubnVtZXJpYyhnc3ViKCJbXjAtOV0iLCAiIiwgQm9keXdlaWdodCkpKQ0KDQogICMgUmVuYW1lIGNvbHVtbnMgdG8gcmVtb3ZlIGRvdWJsZSBwZXJpb2RzDQogIGNvbG5hbWVzKGRhdGFfbnVtYmVyKSA8LSBnc3ViKCJcXC5cXC4iLCAiLiAiLCBjb2xuYW1lcyhkYXRhX251bWJlcikpDQoNCiAgIyBQcmludCBjb2x1bW4gbmFtZXMgZm9yIGRlYnVnZ2luZw0KICAjIHByaW50KGNvbG5hbWVzKGRhdGFfbnVtYmVyKSkNCiAgICANCiAgZ2dwbG90KGRhdGFfbnVtYmVyLCBhZXMoeCA9IEJvZHl3ZWlnaHQpKSArDQogICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBgQ2F0LiBJYCwgeW1heCA9IGBDYXQuIElJYCksIGZpbGwgPSAiYmx1ZSIsIGFscGhhID0gMC4yKSArDQogICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBgQ2F0LiBJSWAsIHltYXggPSBgQ2F0LiBJSUlgKSwgZmlsbCA9ICJncmVlbiIsIGFscGhhID0gMC4yKSArDQogICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBgQ2F0LiBJSUlgLCB5bWF4ID0gYENhdC4gSVZgKSwgZmlsbCA9ICJvcmFuZ2UiLCBhbHBoYSA9IDAuMikgKw0KICAgIGdlb21fcmliYm9uKGFlcyh5bWluID0gYENhdC4gSVZgLCB5bWF4ID0gYENhdC4gVmApLCBmaWxsID0gInJlZCIsIGFscGhhID0gMC4yKSArDQogICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBgQ2F0LiBWYCwgeW1heCA9IEluZiksIGZpbGwgPSAicHVycGxlIiwgYWxwaGEgPSAwLjIpICsNCiAgICANCiAgICAjIEZpbGwgdGhlIHJlbWFpbmluZyBub24tY29sb3JlZCBwYXJ0DQogICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSAtSW5mLCB5bWF4ID0gYENhdC4gSWApLCBmaWxsID0gImdyYXkiLCBhbHBoYSA9IDAuMikgKw0KICAgIA0KICAgICMgQ3JlYXRlIGxpbmVzDQogICAgZ2VvbV9saW5lKGFlcyh5ID0gYENhdC4gSWApLCBjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDEpICsNCiAgICBnZW9tX2xpbmUoYWVzKHkgPSBgQ2F0LiBJSWApLCBjb2xvciA9ICJncmVlbiIsIHNpemUgPSAxKSArDQogICAgZ2VvbV9saW5lKGFlcyh5ID0gYENhdC4gSUlJYCksIGNvbG9yID0gIm9yYW5nZSIsIHNpemUgPSAxKSArDQogICAgZ2VvbV9saW5lKGFlcyh5ID0gYENhdC4gSVZgKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDEpICsNCiAgICBnZW9tX2xpbmUoYWVzKHkgPSBgQ2F0LiBWYCksIGNvbG9yID0gInB1cnBsZSIsIHNpemUgPSAxKSArDQogICAgDQogICAgIyBTZXQgbGFiZWxzDQogICAgbGFicygNCiAgICAgIHggPSAiQm9keXdlaWdodCAobGIpIiwNCiAgICAgIHkgPSAiMVJNIFdlaWdodCBMb2FkIEV4ZWN1dGlvbiIsDQogICAgICB0aXRsZSA9IHBhc3RlKCJNYWxlIiwgY2F0ZWdvcnlfbmFtZSwgIlN0YW5kYXJkcyIpLA0KICAgICAgc3VidGl0bGUgPSAiQ29tcGFyaXNvbiBvZiBTdHJlbmd0aCBTdGFuZGFyZHMgQWNyb3NzIEV4cGVyaWVuY2UgTGV2ZWxzIiwNCiAgICAgIGNhcHRpb24gPSBwYXN0ZSgiU291cmNlOiIsIG1hcmtfcmlwcGV0b2Vfc3RyZW5ndGhfc3RhbmRhcmQpICMgQ2hhbmdlIFNvdXJjZSBpbmZvIFBSTg0KICAgICkgKw0KICAgIA0KICAgICMgQWRkIG1vcmUgbWFya2VycyBvbiB0aGUgeS1heGlzIGF0IGluY3JlbWVudHMgb2YgMjANCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDk5OSwgYnkgPSAyMCkpICsNCiAgICAjIEFkZCBtb3JlIG1hcmtlcnMgb24gdGhlIHgtYXhpcyBhdCBpbmNyZW1lbnRzIG9mIDEwDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA5OTksIGJ5ID0gMTApKSArDQogICAgDQogICAgIyBBZGQgdGV4dCBsYWJlbHMgZm9yIHNraWxsIGxldmVscyB3aXRoIG1hdGNoaW5nIGNvbG9ycw0KICAgIGdlb21fdGV4dChhZXMoeCA9IG1heChCb2R5d2VpZ2h0KSwgeSA9IG1pbihgQ2F0LiBJYCksIGxhYmVsID0gIiIpLCBjb2xvciA9ICJkaW1ncmF5Iiwgdmp1c3QgPSAtMSkgKw0KICAgIGdlb21fdGV4dChhZXMoeCA9IG1heChCb2R5d2VpZ2h0KSwgeSA9IG1heChgQ2F0LiBJYCksIGxhYmVsID0gIkNhdC4gSSIpLCBjb2xvciA9ICJkYXJrYmx1ZSIsIHZqdXN0ID0gLTEpICsNCiAgICBnZW9tX3RleHQoYWVzKHggPSBtYXgoQm9keXdlaWdodCksIHkgPSBtYXgoYENhdC4gSUlgKSwgbGFiZWwgPSAiQ2F0LiBJSSIpLCBjb2xvciA9ICJkYXJrZ3JlZW4iLCB2anVzdCA9IC0xKSArDQogICAgZ2VvbV90ZXh0KGFlcyh4ID0gbWF4KEJvZHl3ZWlnaHQpLCB5ID0gbWF4KGBDYXQuIElJSWApLCBsYWJlbCA9ICJDYXQuIElJSSIpLCBjb2xvciA9ICJkYXJrb3JhbmdlIiwgdmp1c3QgPSAtMSkgKw0KICAgIGdlb21fdGV4dChhZXMoeCA9IG1heChCb2R5d2VpZ2h0KSwgeSA9IG1heChgQ2F0LiBJVmApLCBsYWJlbCA9ICJDYXQuIElWIiksIGNvbG9yID0gImRhcmtyZWQiLCB2anVzdCA9IC0xKSArDQogICAgZ2VvbV90ZXh0KGFlcyh4ID0gbWF4KEJvZHl3ZWlnaHQpLCB5ID0gbWF4KGBDYXQuIFZgKSwgbGFiZWwgPSAiQ2F0LiBWIiksIGNvbG9yID0gInB1cnBsZSIsIHZqdXN0ID0gLTEpICsNCiAgICANCiAgICAjIEN1c3RvbWl6ZSB0aGVtZQ0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgdGhlbWUoDQogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTYpLA0KICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEyKSwNCiAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLA0KICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgImNtIikNCiAgICApDQp9DQoNCiMgTGlzdHMgdG8gc3RvcmUgdGhlIHBsb3RzIGFuZCB0YWJsZXMNCnBsb3RzX2xpc3Rfc3RyZW5ndGhfc3RhbmRhcmRzX21hcmtfcmlwcGV0b2UgPC0gbGlzdCgpDQp0YWJsZXNfbGlzdF9zdHJlbmd0aF9zdGFuZGFyZHNfbWFya19yaXBwZXRvZSA8LSBsaXN0KCkNCg0KIyBDaGVjayBhbmQgY3JlYXRlIHRoZSAncGxvdHMnIGRpcmVjdG9yeSBpZiBpdCBkb2Vzbid0IGV4aXN0DQppZiAoIWRpci5leGlzdHMoInBsb3RzIikpIHsNCiAgZGlyLmNyZWF0ZSgicGxvdHMiKQ0KfQ0KDQojIENoZWNrIGFuZCBjcmVhdGUgdGhlICd0YWJsZXMnIGRpcmVjdG9yeSBpZiBpdCBkb2Vzbid0IGV4aXN0DQppZiAoIWRpci5leGlzdHMoInRhYmxlcyIpKSB7DQogIGRpci5jcmVhdGUoInRhYmxlcyIpDQp9DQoNCiMgTG9vcCB0aHJvdWdoIGVhY2ggbmFtZWQgcmFuZ2UgZnJvbSB0aGUgZmlsdGVyZWQgbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCBkYXRhZnJhbWUNCmZvciAoaSBpbiAxOm5yb3cobWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCkpIHsNCiAgc3RyZW5ndGhfc3RhbmRhcmRfbmFtZWRfcmFuZ2UgPC0gbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCRgU3RyZW5ndGggU3RhbmRhcmRgW2ldDQogIGNhdGVnb3J5X25hbWUgPC0gbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCRgQ2F0ZWdvcnkgTmFtZWBbaV0NCiAgDQogICMgTG9hZCB0aGUgZGF0YSBmcm9tIHRoZSBuYW1lZCByYW5nZQ0KICBkYXRhX2ZyYW1lIDwtIHJlYWRXb3JrYm9vayhzdHJlbmd0aF9zdGFuZGFyZHMsIG5hbWVkUmVnaW9uID0gc3RyZW5ndGhfc3RhbmRhcmRfbmFtZWRfcmFuZ2UpDQogIA0KICAjIENoZWNrIGlmIHRoZSAnQm9keXdlaWdodCcgY29sdW1uIGV4aXN0cyBpbiB0aGUgZGF0YSBmcmFtZQ0KICBpZiAoISJCb2R5d2VpZ2h0IiAlaW4lIGNvbG5hbWVzKGRhdGFfZnJhbWUpKSB7DQogICAgY2F0KHBhc3RlKCJTa2lwcGluZyIsIHN0cmVuZ3RoX3N0YW5kYXJkX25hbWVkX3JhbmdlLCAiLSAnQm9keXdlaWdodCcgY29sdW1uIG1pc3NpbmcuXG4iKSkNCiAgICBuZXh0DQogIH0NCg0KICAjIEVuc3VyZSBjb2x1bW4gbmFtZXMgYXJlIHRyaW1tZWQgb2Ygd2hpdGVzcGFjZQ0KICBjb2xuYW1lcyhkYXRhX2ZyYW1lKSA8LSB0cmltd3MoY29sbmFtZXMoZGF0YV9mcmFtZSkpDQoNCiAgIyBSZW5hbWUgY29sdW1ucyB0byByZW1vdmUgZG91YmxlIHBlcmlvZHMgZm9yIGJvdGggdGFibGUgYW5kIHBsb3QNCiAgY29sbmFtZXMoZGF0YV9mcmFtZSkgPC0gZ3N1YigiXFwuXFwuIiwgIi4gIiwgY29sbmFtZXMoZGF0YV9mcmFtZSkpDQoNCiAgIyBGb3JtYXQgdGhlIHRpdGxlIG9mIHRoZSBwbG90IGFuZCBoZWFkIG9mIHRoZSB0YWJsZSB1c2luZyB0aGUgY2xlYW5lZCBjYXRlZ29yeSBuYW1lDQogIGZvcm1hdHRlZF9oZWFkZXIgPC0gZ3N1YigiXyIsICIgIiwgc3RyZW5ndGhfc3RhbmRhcmRfbmFtZWRfcmFuZ2UpDQogIGZvcm1hdHRlZF9oZWFkZXIgPC0gKHN1YigiIFN0ZCAxUk0gQnkgQm9keXdlaWdodCBNYXJrIFJpcHBldG9lIiwgIiBTdGFuZGFyZHMiLCBmb3JtYXR0ZWRfaGVhZGVyKSkNCiAgDQogICMgR2VuZXJhdGUgdGhlIHBsb3QNCiAgcGxvdCA8LSBnZW5lcmF0ZV9nZ3Bsb3QoZGF0YV9mcmFtZSwgY2F0ZWdvcnlfbmFtZSwgc3RyZW5ndGhfc3RhbmRhcmRfbmFtZWRfcmFuZ2UpDQogIA0KICAjIFByaW50IHRoZSBuYW1lIG9mIHRoZSBuYW1lZCByYW5nZSBhcyBhIG1hcmtkb3duIGhlYWRlcg0KICBjYXQocGFzdGUwKCJcblxuPGgzPiAiLCBmb3JtYXR0ZWRfaGVhZGVyLCAiPC9oMz5cbiIpKQ0KDQogICMgUmVuYW1lICdCb2R5d2VpZ2h0JyBjb2x1bW4gdG8gJ0JvZHl3ZWlnaHQgKGxiKScNCiAgbmFtZXMoZGF0YV9mcmFtZSlbbmFtZXMoZGF0YV9mcmFtZSkgPT0gIkJvZHl3ZWlnaHQiXSA8LSAiQm9keXdlaWdodCAobGIpIg0KDQogICMgUHJpbnQgdGhlIHBsb3QNCiAgcHJpbnQocGxvdCkNCg0KICAjIFNhdmUgdGhlIHBsb3QgdG8gdGhlIGxpc3QNCiAgcGxvdHNfbGlzdF9zdHJlbmd0aF9zdGFuZGFyZHNfbWFya19yaXBwZXRvZVtbZm9ybWF0dGVkX2hlYWRlcl1dIDwtIHBsb3QNCg0KICAjIE91dHB1dCB0aGUgZGF0YSBmcmFtZSBhcyBhIG1hcmtkb3duIHRhYmxlIHdpdGggZXZlbiBjb2x1bW4gd2lkdGhzDQogIHByaW50KA0KICAgIHRhYmxlX2h0bWwgPC0ga2FibGUoZGF0YV9mcmFtZSwgZm9ybWF0ID0gImh0bWwiLCBhbGlnbiA9ICdsJykgJT4lDQogICAgICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUUlVFKSAlPiUNCiAgICAgIGNvbHVtbl9zcGVjKDE6bmNvbChkYXRhX2ZyYW1lKSwgd2lkdGggPSBwYXN0ZTAoMTAwIC8gbmNvbChkYXRhX2ZyYW1lKSwgIiUiKSkNCiAgKQ0KICANCiAgIyBTYXZlIHRoZSB0YWJsZSB0byB0aGUgbGlzdA0KICB0YWJsZXNfbGlzdF9zdHJlbmd0aF9zdGFuZGFyZHNfbWFya19yaXBwZXRvZVtbZm9ybWF0dGVkX2hlYWRlcl1dIDwtIHRhYmxlX2h0bWwNCg0KICAjIE9wdGlvbmFsbHkgc2F2ZSB0aGUgcGxvdCBhbmQgdGFibGUNCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKCJwbG90cy8iLCB0b2xvd2VyKHN0cmVuZ3RoX3N0YW5kYXJkX25hbWVkX3JhbmdlKSwgIi5wbmciKSwgcGxvdCA9IHBsb3QsIHdpZHRoID0gMTIsIGhlaWdodCA9IDgpDQoNCiAgIyBTYXZlIHRoZSBkYXRhIGZyYW1lIGFzIGEgQ1NWIGZpbGUNCiAgd3JpdGUuY3N2KGRhdGFfZnJhbWUsIGZpbGUgPSBwYXN0ZTAoInRhYmxlcy8iLCB0b2xvd2VyKHN0cmVuZ3RoX3N0YW5kYXJkX25hbWVkX3JhbmdlKSwgIi5jc3YiKSwgcm93Lm5hbWVzID0gRkFMU0UpDQp9DQoNCiMgRXhhbXBsZSBvZiBob3cgdG8gcmVjYWxsIGFuZCBwcmludCBhIHNwZWNpZmljIHBsb3QgYW5kIHRhYmxlIGZyb20gdGhlIGxpc3RzDQojIHByaW50KHBsb3RzX2xpc3Rfc3RyZW5ndGhfc3RhbmRhcmRzX21hcmtfcmlwcGV0b2VbWyJNYWxlIEJlbmNoIFByZXNzIFN0ZCAxUk0gQnkgQm9keXdlaWdodCBNYXJrIFJpcHBldG9lIl1dKQ0KIyBwcmludCh0YWJsZXNfbGlzdF9zdHJlbmd0aF9zdGFuZGFyZHNfbWFya19yaXBwZXRvZSkNCiMgcHJpbnQodGFibGVzX2xpc3Rfc3RyZW5ndGhfc3RhbmRhcmRzX21hcmtfcmlwcGV0b2VbIk1hbGUgQmVuY2ggUHJlc3MgU3RkIDFSTSBCeSBCb2R5d2VpZ2h0IE1hcmsgUmlwcGV0b2UiXSkNCiMgY2F0KGFzLmNoYXJhY3Rlcih0YWJsZXNfbGlzdF9zdHJlbmd0aF9zdGFuZGFyZHNfbWFya19yaXBwZXRvZVtbIk1hbGUgQmVuY2ggUHJlc3MgU3RkIDFSTSBCeSBCb2R5d2VpZ2h0IE1hcmsgUmlwcGV0b2UiXV0pKQ0KDQpgYGANCg0KIyBSRUZFUkVOQ0VTIA0KDQoNClteMV06IFRoYW0sIEsuICgyMDI0KS4gKlN0cmVuZ3RoIFN0YW5kYXJkcyAoYHIgU3lzLkRhdGUoKWApLiogUlB1YnMgYnkgUlN0dWRpby4gUmV0cmlldmVkIGZyb20gPGh0dHBzOi8vcnB1YnMuY29tL0tlbkRvZXNEYXRhLz4uDQoNClteMl06IFRoYW0sIEsuICgyMDI0KS4gKktERiAoS0VOIERPRVMgRklUTkVTUykuKiBHb29nbGUgRHJpdmUuIEF2YWlsYWJsZSBhdCA8aHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2RyaXZlL2ZvbGRlcnMvMS00MUZKX2M0MUtqN0thSzBoMWFKNUVCdkVoUHd3SXNpP3VzcD1zaGFyaW5nPg0KDQpbXjNdOiBUaGFtLCBLLiAoMjAyNCkuICpTdHJlbmd0aCBTdGFuZGFyZHMgRmluYWwueGxzbS4qIEtlbiBEb2VzIERhdGEuIFJldHJpZXZlZCBmcm9tIDxodHRwczovLzFkcnYubXMveC9zIUFzWVlaQTluTDhsZjhDSzZrNnJBUDNMU2t2cnk/ZT15bEFSWGk+Lg0KDQpbXjRdOiBSaXBwZXRvZSwgTS4gKDIwMTIpLiAqU3RyZW5ndGggU3RhbmRhcmRzLiogU3RhcnRpbmcgU3RyZW5ndGguIFJldHJpZXZlZCBmcm9tIDxodHRwczovL3N0YXJ0aW5nc3RyZW5ndGguY29tL2ZpbGVzL3N0YW5kYXJkcy5wZGY+Lg0KDQpbXjVdOiBSaXBwZXRvZSwgTS4gKDIwMTcpLiAqU3RhcnRpbmcgU3RyZW5ndGg6IEJhc2ljIEJhcmJlbGwgVHJhaW5pbmcgKDNyZCBlZC4pLiogVGhlIEFhc2dhYXJkIENvbXBhbnkuIFJldHJpZXZlZCBmcm9tIDxodHRwczovL2Fhc2dhYXJkY28uY29tL3N0b3JlL2Jvb2tzLXBvc3RlcnMtZHZkL2Jvb2tzL3N0YXJ0aW5nLXN0cmVuZ3RoLWJhc2ljLWJhcmJlbGwtdHJhaW5pbmcvPi4NCg0KW142XTogTGVnaW9uIEF0aGxldGljcy4gKDIwMTkpLiAqVGhlc2UgQXJlIHRoZSBCZXN0IFN0cmVuZ3RoIFN0YW5kYXJkcyBvbiB0aGUgSW50ZXJuZXQuKiBSZXRyaWV2ZWQgZnJvbSA8aHR0cHM6Ly9sZWdpb25hdGhsZXRpY3MuY29tL3N0cmVuZ3RoLXN0YW5kYXJkcy8+Lg0KDQpbXjddOiBSaXBwZXRvZSwgTS4gKDIwMTIpLiAqVGhlIFN0cmVuZ3RoIFN0YW5kYXJkcyBUYWJsZXMgYXJlIGJhY2sgdXAuKiBTdGFydGluZyBTdHJlbmd0aCBGb3J1bS4gUmV0cmlldmVkIGZyb20gPGh0dHBzOi8vc3RhcnRpbmdzdHJlbmd0aC5jb20vcmVzb3VyY2VzL2ZvcnVtL21hcmstcmlwcGV0b2UtcS1hbmQtYS8zMzAyOS1zdHJlbmd0aC1zdGFuZGFyZHMtdGFibGVzLmh0bWw+Lg0KDQpbXjhdOiBSaXBwZXRvZSwgTS4gKDIwMTcpLiAqU3RhcnRpbmcgU3RyZW5ndGg6IEJhc2ljIEJhcmJlbGwgVHJhaW5pbmcsIDNyZCBFZGl0aW9uKiBieSBNYXJrIFJpcHBldG9lLiBBdmFpbGFibGUgYXQgPGh0dHBzOi8vd3d3LmFtYXpvbi5jb20vU3RhcnRpbmctU3RyZW5ndGgtTWFyay1SaXBwZXRvZS1lYm9vay9kcC9CMDA2WEpSNVpBL3JlZj1zcl8xXzE/Y3JpZD0yMTUyMVlYQktYNEFJJmRpYj1leUoySWpvaU1TSjkuMXFUZWhfOERKaHFEbXhycmFqbWpUYkxpUXotd1BhS09pZmdpNzg3TTdXdXJOeHdVd0tWYmhRYWRKRXc4V2R1MnlnRFA4WDBEMjNZNXhHcUVaQUoyTDVsdUV3MGd2Q0lJeXVUbXVnWVpfYlJtRzM1aHFMUlBsYk95UXg0ZTVwUmYyd1ZvR25zUVB6RlFFZkVPbHJoaUhLcDhCU1dDdVFrZjJSRUxGS1NPTFFPNDlGcThZNTdQVV9NdVBtOWdlOTFVY0MzZWJtQ1o4cENXSG1xYlVVUk42dHlvY0RULUNSM1phUUFLUEpYbm1ZUHNvY0NQNGp6NFlfUVRMRTFoZWNzazhWdXVnZjNISUJqQldrT1ZNWkZtU0RsUzl1alZ4cUY0dlJxQzdHc1ZKbHcuXzlqTnBscGQ5TDZQUEZ6azdXTUMtblNEZldYUGhtY2tGaWlhTVN3YUN5bz4uDQoNClteOV06IFJpcHBldG9lLCBNLiAqUHJhY3RpY2FsIFByb2dyYW1taW5nIGZvciBTdHJlbmd0aCBUcmFpbmluZywgM3JkIEVkaXRpb24qIGJ5IE1hcmsgUmlwcGV0b2UuIEF2YWlsYWJsZSBhdCA8aHR0cHM6Ly93d3cuYW1hem9uLmNvbS9QcmFjdGljYWwtUHJvZ3JhbW1pbmctU3RyZW5ndGgtVHJhaW5pbmctUmlwcGV0b2UtZWJvb2svZHAvQjAwSVU4WUVUVy9yZWY9c3JfMV8yP2NyaWQ9MjE1MjFZWEJLWDRBSSZkaWI9ZXlKMklqb2lNU0o5LjFxVGVoXzhESmhxRG14cnJham1qVGJMaVF6LXdQYUtPaWZnaTc4N003V3VyTnh3VXdLVmJoUWFkSkV3OFdkdTJ5Z0RQOFgwRDIzWTV4R3FFWkFKMkw1bHVFdzBndkNJSXl1VG11Z1laX2JSbUczNWhxTFJQbGJPeVF4NGU1cFJmMndWb0duc1FQekZRRWZFT2xyaGlIS3A4QlNXQ3VRa2YyUkVMRktTT0xRTzQ5RnE4WTU3UFVfTXVQbTlnZTkxVWNDM2VibUNaOHBDV0htcWJVVVJONnR5b2NEVC1DUjNaYVFBS1BKWG5tWVBzb2NDUDRqejRZX1FUTEUxaGVjc2s4VnV1Z2YzSElCakJXa09WTVpGbVNEbFM5dWpWeHFGNHZScUM3R3NWSmx3Ll85ak5wbHBkOUw2UFBGems3V01DLW5TRGZXWFBobWNrRmlpYU1Td2FDeW8+Lg0K