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 RPubs. 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 .
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 file. 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
file.
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 Standards 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 store 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” and “Practical
Programming for Strength Training.” 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"]]))
LS0tDQp0aXRsZTogIlN0cmVuZ3RoIFN0YW5kYXJkcyINCmF1dGhvcjogIktlbmRyaWNrIFRoYW0iDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogICAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICAgIHBsYWNlbWVudDogdG9wDQogICAgICB0b2Mtc3VidHJlZTogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlICAgIyBIaWRlIHRoZSBjb2RlIGJ5IGRlZmF1bHQNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAjIEFkZCBhIGJ1dHRvbiB0byBkb3dubG9hZCB0aGUgUiBjb2RlDQoNCi0tLQ0KDQo8IS0tDQotLT4NCg0KSW5pdGlhbCBQcmludDogMjAyNC0wNy0zMQ0KDQpQcmludCBEYXRlOiBgciBTeXMuRGF0ZSgpYA0KDQo8IS0tIFJNRCBTZXR1cCAtLT4NCg0KPHN0eWxlPg0KDQovKiBSZWR1Y2UgdGhlIGZvbnQgc2l6ZSBvZiB0aGUgVE9DICovDQp7DQogIGZvbnQtc2l6ZTogMC45MGVtOyAvKiBBZGp1c3QgdGhlIHNpemUgYXMgbmVlZGVkICovDQp9DQoNCi8qIEFkZCBib3JkZXJzIGFuZCBzcGFjaW5nIHRvIGFsbCBmaWd1cmVzICovDQppbWcgew0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRkOyAvKiBTcGVjaWZ5IGJvcmRlciBzdHlsZSAqLw0KICBwYWRkaW5nOiA1cHg7IC8qIEFkZCBwYWRkaW5nIGFyb3VuZCB0aGUgZmlndXJlcyAqLw0KICBib3JkZXItcmFkaXVzOiA1cHg7IC8qIEFkZCByb3VuZGVkIGNvcm5lcnMgdG8gdGhlIGJvcmRlciAqLw0KICBkaXNwbGF5OiBibG9jazsgLyogRW5zdXJlIHRoZSBpbWFnZSBpcyB0cmVhdGVkIGFzIGEgYmxvY2sgZWxlbWVudCB0byByZXNwZWN0IG1hcmdpbiAqLw0KICBtYXJnaW4tYm90dG9tOiAyMHB4OyAvKiBBZGQgYm90dG9tIG1hcmdpbiB0byBlYWNoIGltYWdlIGZvciBzcGFjaW5nICovDQp9DQoNCi8qIEFkZCBib3JkZXJzIHRvIGFsbCB0YWJsZXMgKi8NCnRhYmxlIHsNCiAgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsgLyogQ29sbGFwc2UgYm9yZGVycyBpbnRvIGEgc2luZ2xlIGJvcmRlciAqLw0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRkOyAvKiBTcGVjaWZ5IGJvcmRlciBzdHlsZSAqLw0KICBtYXJnaW4tYm90dG9tOiAyMHB4OyAvKiBBZGQgYm90dG9tIG1hcmdpbiB0byBlYWNoIHRhYmxlIGZvciBzcGFjaW5nICovDQp9DQoNCi8qIEFkZCBib3JkZXJzIHRvIHRhYmxlIGNlbGxzICovDQp0aCwgdGQgew0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRkOyAvKiBTcGVjaWZ5IGJvcmRlciBzdHlsZSBmb3IgdGFibGUgY2VsbHMgKi8NCiAgcGFkZGluZzogOHB4OyAvKiBBZGQgcGFkZGluZyBpbnNpZGUgdGhlIHRhYmxlIGNlbGxzICovDQogIHRleHQtYWxpZ246IGxlZnQ7IC8qIEFsaWduIHRleHQgdG8gdGhlIGxlZnQgd2l0aGluIHRhYmxlIGNlbGxzICovDQp9DQoNCi8qIEFwcGx5IHN0eWxlcyB0byBhbGwgaGVhZGVycyAqLw0KdGggew0KICBwb3NpdGlvbjogc3RpY2t5OyAvKiBFbnN1cmUgaGVhZGVycyBzdGljayB3aGVuIHNjcm9sbGluZyAqLw0KICB0b3A6IDA7IC8qIFBvc2l0aW9uIGhlYWRlcnMgYXQgdGhlIHRvcCAqLw0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjJmMmYyOyAvKiBCYWNrZ3JvdW5kIGNvbG9yIGZvciBoZWFkZXJzICovDQogIHotaW5kZXg6IDk5OTsgLyogRW5zdXJlIGhlYWRlcnMgc3RheSBvbiB0b3Agb2Ygb3RoZXIgZWxlbWVudHMgKi8NCn0NCg0KLyogQXBwbHkgc3R5bGVzIHRvIGFsbCB0YWJsZXMgKi8NCnRhYmxlIHsNCiAgYm9yZGVyLWNvbGxhcHNlOiBjb2xsYXBzZTsgLyogQ29sbGFwc2UgYm9yZGVycyBpbnRvIGEgc2luZ2xlIGJvcmRlciAqLw0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRkOyAvKiBTcGVjaWZ5IGJvcmRlciBzdHlsZSAqLw0KfQ0KDQovKiBBcHBseSBzdHlsZXMgdG8gdGFibGUgY2VsbHMgKi8NCnRoLCB0ZCB7DQogIGJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IC8qIFNwZWNpZnkgYm9yZGVyIHN0eWxlIGZvciB0YWJsZSBjZWxscyAqLw0KICBwYWRkaW5nOiA4cHg7IC8qIEFkZCBwYWRkaW5nIGluc2lkZSB0aGUgdGFibGUgY2VsbHMgKi8NCiAgdGV4dC1hbGlnbjogbGVmdDsgLyogQWxpZ24gdGV4dCB0byB0aGUgbGVmdCB3aXRoaW4gdGFibGUgY2VsbHMgKi8NCn0NCg0KLyogU3R5bGUgdGFibGVzIHdpdGggYWx0ZXJuYXRpbmcgc3RyaXBlZCByb3dzICovDQp0YWJsZSB7DQogIGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7DQogIHdpZHRoOiAxMDAlOw0KfQ0KDQp0aCwgdGQgew0KICBib3JkZXI6IDFweCBzb2xpZCAjZGRkZGRkOw0KICB0ZXh0LWFsaWduOiBsZWZ0Ow0KICBwYWRkaW5nOiA4cHg7DQp9DQoNCi8qIEFkZCBhbHRlcm5hdGluZyBiYWNrZ3JvdW5kIGNvbG9ycyB0byB0YWJsZSByb3dzICovDQp0cjpudGgtY2hpbGQoZXZlbikgew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjJmMmYyOw0KfQ0KDQp0cjpudGgtY2hpbGQob2RkKSB7DQogIGJhY2tncm91bmQtY29sb3I6ICNmZmZmZmY7IC8qIFdoaXRlIGJhY2tncm91bmQgZm9yIG9kZCByb3dzICovDQp9DQoNCi5mdWxsLXdpZHRoLWltYWdlIGltZyB7DQogIGRpc3BsYXk6IGJsb2NrOw0KICB3aWR0aDogMTAwJTsNCiAgaGVpZ2h0OiBhdXRvOw0KfQ0KDQoNCjwvc3R5bGU+DQoNCg0KPCEtLSBQcmltYXJ5IFBpYyAtLT4NCg0KPGRpdiBjbGFzcz0iZnVsbC13aWR0aC1pbWFnZSI+DQogICFbIF0oQzovL1VzZXJzLy9rZW5kci8vT25lRHJpdmUvL0RvY3VtZW50cy8vRGF0YSBBbmFseXRpY3MvL0tlbkRvZXNGaXRuZXNzLy9TdHJlbmd0aCBTdGFuZGFyZHMvL01hbGVfQmVuY2hfUHJlc3NfU3RkXzFSTV9CeV9Cb2R5d2VpZ2h0X01hcmtfUmlwcGV0b2UucG5nKQ0KPC9kaXY+DQoNCjwhLS0gRGVmYXVsdCBDaHVuayBPcHRpb25zIC0tPg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIH0NCiMgU2V0IHJlcG9zaXRvcnkgYW5kIGRlZmF1bHQgY2h1bmsgb3B0aW9ucw0Kb3B0aW9ucyhyZXBvcyA9IGMoQ1JBTiA9ICJodHRwczovL2Nsb3VkLnItcHJvamVjdC5vcmciKSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvPVRSVUUsIGV2YWw9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFKQ0KYGBgDQoNCjwhLS0gDQpPcHRpb25zIHN1Y2ggYXMgZWNobywgbWVzc2FnZSwgd2FybmluZywgcmVzdWx0cywgaW5jbHVkZSwgZXZhbCwgY2FjaGUsIGFuZCBtb3JlLiANCg0KLSBlY2hvOiBTaG93IG9yIGhpZGUgY29kZSBpbiB0aGUgb3V0cHV0IChlY2hvID0gRkFMU0UgaGlkZXMgdGhlIGNvZGUpLg0KLSBtZXNzYWdlOiBTaG93IG9yIGhpZGUgbWVzc2FnZXMgaW4gdGhlIG91dHB1dCAobWVzc2FnZSA9IEZBTFNFIHN1cHByZXNzZXMgbWVzc2FnZXMpLg0KLSB3YXJuaW5nOiBTaG93IG9yIGhpZGUgd2FybmluZ3MgaW4gdGhlIG91dHB1dCAod2FybmluZyA9IEZBTFNFIHN1cHByZXNzZXMgd2FybmluZ3MpLg0KLSByZXN1bHRzOiBDb250cm9sIGhvdyByZXN1bHRzIGFyZSBzaG93bjoNCiAgLSAnbWFya3VwJzogRGlzcGxheSByZXN1bHRzIGFzIHRoZXkgYXJlLg0KICAtICdhc2lzJzogSW5jbHVkZSByZXN1bHRzIGFzIHJhdyBIVE1MIG9yIExhVGVYLg0KICAtICdoaWRlJzogSGlkZSByZXN1bHRzIGZyb20gb3V0cHV0Lg0KLSBpbmNsdWRlOiBJbmNsdWRlIG9yIGV4Y2x1ZGUgYm90aCBjb2RlIGFuZCByZXN1bHRzIGZyb20gdGhlIG91dHB1dCAoaW5jbHVkZSA9IEZBTFNFIGV4Y2x1ZGVzIGV2ZXJ5dGhpbmcpLg0KLSBldmFsOiBFdmFsdWF0ZSB0aGUgY29kZSBjaHVuayBvciBub3QgKGV2YWwgPSBGQUxTRSBwcmV2ZW50cyBjb2RlIGV4ZWN1dGlvbikuDQotIGNhY2hlOiBDYWNoZSB0aGUgcmVzdWx0cyBvZiB0aGUgY2h1bmsgdG8gc3BlZWQgdXAgcmVuZGVyaW5nIChjYWNoZSA9IFRSVUUgZW5hYmxlcyBjYWNoaW5nKS4NCi0gZmlnLmNhcDogQWRkIGEgY2FwdGlvbiB0byBncmFwaGljYWwgb3V0cHV0cy4NCi0gb3V0LndpZHRoL291dC5oZWlnaHQ6IFNldCB0aGUgb3V0cHV0IHNpemUgb2YgcGxvdHMuDQotIGNvbGxhcHNlOiBDb25jYXRlbmF0ZSB0ZXh0dWFsIG91dHB1dCBpbnRvIGEgc2luZ2xlIGJsb2NrLg0KLSB0aWR5OiBUaWR5IHVwIHRoZSBkaXNwbGF5IG9mIGNvZGUgb3IgcmVzdWx0cyAodGlkeSA9IFRSVUUgdGlkaWVzIHRoZSBvdXRwdXQpLg0KLS0+DQoNCjwhLS0gIyMjIFBhY2thZ2VzIGFuZCBMaWJyYXJpZXMgLS0+DQpgYGB7ciBwYWNrYWdlc19hbmRfbGlicmFyaWVzLCBldmFsPVRSVUV9DQoNCiMgTGlzdCBvZiBtb3N0IG9mIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMgdXNlZA0KcmVxdWlyZWRfbGlicmFyaWVzIDwtIGMoImdncGxvdDIiLCAic3RyaW5nciIsICJyZWFkeGwiLCAiZHBseXIiLCAibHVicmlkYXRlIiwgImhtcyIsICJvcGVueGxzeCIsICJ3cml0ZXhsIiwgInJtYXJrZG93biIsICJrbml0ciIsICJrYWJsZUV4dHJhIikNCg0KIyBnZ3Bsb3QyICAgICBmb3IgJ2RlY2xhcmF0aXZlbHknIGNyZWF0aW5nIGdyYXBoaWNzLCBiYXNlZCBvbiAiVGhlIEdyYW1tYXIgb2YgR3JhcGhpY3MiLiANCiMgc3RyaW5nciAgICAgZm9yIHdvcmtpbmcgd2l0aCBzdHJpbmdzLCBpLmUuLCBjaGFyYWN0ZXIgZGF0YS4NCiMgcmVhZHhsICAgICAgZm9yIHJlYWRpbmcgRXhjZWwgZmlsZXMgYnkgcHJvdmlkaW5nIGEgd2F5IHRvIHJlYWQgeGxzIGFuZCB4bHN4IGZpbGVzIGludG8gUiB3aXRob3V0IGRlcGVuZGVuY2llcyBvbiBleHRlcm5hbCBzb2Z0d2FyZS4NCiMgZHBseXIgICAgICAgZm9yIGRhdGEgbWFuaXB1bGF0aW9uLCBwcm92aWRpbmcgYSBjb25zaXN0ZW50IHNldCBvZiB2ZXJicyB0aGF0IGhlbHAgeW91IHNvbHZlIHRoZSBtb3N0IGNvbW1vbiBkYXRhIG1hbmlwdWxhdGlvbiBjaGFsbGVuZ2VzLg0KIyBsdWJyaWRhdGUgICBmb3Igd29ya2luZyB3aXRoIGRhdGVzIGFuZCB0aW1lcyBpbiBSLg0KIyBobXMgICAgICAgICBmb3Igc3RvcmluZyB0aW1lLW9mLWRheSB2YWx1ZXMgYW5kIGludGVyZmFjaW5nIHRoZXNlIHZhbHVlcyB3aXRoIGJhc2UgUidzIGRhdGUtdGltZSBjbGFzc2VzLg0KIyBvcGVueGxzeCAgICBmb3IgcmVhZGluZyBmcm9tIGFuZCB3cml0aW5nIHRvIE1pY3Jvc29mdCBFeGNlbCAueGxzeCBmaWxlcy4gSXQgcHJvdmlkZXMgbW9yZSBmdW5jdGlvbmFsaXR5IHRoYW4ganVzdCBoYW5kbGluZyBkYXRhOyBpdCBhbHNvIGFsbG93cyB5b3UgdG8gbW9kaWZ5IHZhcmlvdXMgYXNwZWN0cyBvZiB0aGUgRXhjZWwgZmlsZSBpdHNlbGYuDQojIHdyaXRleGwgICAgIGZvciBhIGZhc3QgYW5kIHBvcnRhYmxlIHdheSB0byB3cml0ZSBkYXRhIGZyYW1lcyB0byBFeGNlbCAueGxzeCBmaWxlcywgZm9jdXNpbmcgc29sZWx5IG9uIHdyaXRpbmcgZGF0YSB3aXRob3V0IGFueSBkZXBlbmRlbmNpZXMuDQojIHJtYXJrZG93biAgIGZvciBkeW5hbWljIHJlcG9ydCBnZW5lcmF0aW9uIGZyb20gUi4gSXQgaW50ZWdyYXRlcyB0aGUgY29yZSBzeW50YXggb2YgbWFya2Rvd24gKGEgc2ltcGxlIG1hcmt1cCBsYW5ndWFnZSkgd2l0aCBSIGNvZGUsIGFsbG93aW5nIGZvciB0aGUgYXV0b21hdGljIHVwZGF0ZSBvZiByZXBvcnRzIHRvIHJlZmxlY3QgZGF0YSBjaGFuZ2VzIGFuZCBhbmFseXNpcyB1cGRhdGVzLg0KIyBrbml0ciAgICAgICBmb3IgdXNpbmcgZnVuY3Rpb25zIHN1Y2ggYXMga2FibGUoKSB0byBmb3JtYXQgZGF0YWZyYW1lcyBhcyBtYXJrZG93biB0YWJsZXMuIA0KIyBrYWJsZUV4dHJhICBmb3IgZW5oYW5jZWQgZnVuY3Rpb25hbGl0eSBmb3Igc3R5bGluZyB0YWJsZXMgc3VjaCBhcyBkaXNwbGF5aW5nIGNvbHVtbnMgZXZlbmx5DQoNCiMgQ2hlY2sgd2hpY2ggbGlicmFyaWVzIGFyZSBub3QgaW5zdGFsbGVkDQppbnN0YWxsZWRfbGlicyA8LSByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkNCmxpYnJhcmllc190b19pbnN0YWxsIDwtIHJlcXVpcmVkX2xpYnJhcmllc1shcmVxdWlyZWRfbGlicmFyaWVzICVpbiUgaW5zdGFsbGVkX2xpYnNdDQoNCiMgSW5zdGFsbCBtaXNzaW5nIGxpYnJhcmllcw0KaWYobGVuZ3RoKGxpYnJhcmllc190b19pbnN0YWxsKSA+IDApIHsNCiAgaW5zdGFsbC5wYWNrYWdlcyhsaWJyYXJpZXNfdG9faW5zdGFsbCkNCn0NCg0KIyBMb2FkIGFsbCByZXF1aXJlZCBsaWJyYXJpZXMNCmxhcHBseShyZXF1aXJlZF9saWJyYXJpZXMsIGxpYnJhcnksIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCmBgYA0KDQojIFRBQkxFIE9GIENPTlRFTlRTDQpVdGlsaXplIHRoZSBUYWJsZSBvZiBDb250ZW50cyBvbiB0aGUgbGVmdCB0byBzY3JvbGwgdGhyb3VnaCB0aGUgZGlmZmVyZW50IHNlY3Rpb25zIGFuZCBoZWxwIG5hdmlnYXRlIHRoaXMgcmVwb3J0LiBZb3UgY2FuIGNsaWNrIG9uIHRoZSB0aXRsZSB0byBnbyBkaXJlY3RseSB0byB0aGUgc2VjdGlvbi4NCg0KSWYgeW91J3JlIHZpZXdpbmcgdGhlIFBERiB2ZXJzaW9uLCB0aGUgVGFibGUgb2YgQ29udGVudHMgc3RheXMgYXQgdGhlIHRvcCBvZiB0aGlzIHJlcG9ydC4gVG8gZ28gZGlyZWN0bHkgdG8gYSBzZWN0aW9uLCBjb3B5IGFuZCBwYXN0ZSB0aGUgdGl0bGUgaW50byB0aGUgc2VhcmNoIGJveC4gVXNlIHRoZSBmb2xsb3dpbmcgc2hvcnRjdXQga2V5cyB0byBoZWxwIG5hdmlnYXRlIHdpdGggZWFzZToNCg0KU2hvcnRjdXQgS2V5czoNCg0KLSBIb2xkIGBDdHJsYCBhbmQgcHJlc3MgdGhlIGBIb21lYCBrZXkgdG8gZ28gdG8gdGhlIHRvcCBvZiB0aGUgcGFnZS4NCi0gSG9sZCBgQ3RybGAgYW5kIHByZXNzIHRoZSBgRW5kYCBrZXkgdG8gZ28gdG8gdGhlIGJvdHRvbSBvZiB0aGUgcGFnZS4NCi0gSG9sZCBgQ3RybGAgYW5kIHByZXNzIHRoZSBgRmAga2V5IHRvIHNlYXJjaCBmb3Igc3BlY2lmaWMgdGV4dCBvciBzdHJpbmdzIG9mIHRleHQuDQotIFByZXNzIHRoZSBgRXNjYCBrZXkgdG8gcXVpY2tseSBleGl0IHRoZSBzZWFyY2ggYm94Lg0KDQojIyBBYm91dCBUaGlzIFJlcG9ydCANCg0KVGhpcyByZXBvcnQgaXMgcHVibGlzaGVkIG9uIFJQdWJzW14xXS4gS0RGIHN0YW5kcyBmb3IgS2VuIERvZXMgRml0bmVzcy4gUmVmZXIgdG8gUmVmZXJlbmNlcyBhdCB0aGUgYm90dG9tIG9mIHRoaXMgcGFnZSBmb3IgY2l0ZWQgc291cmNlcy4gVGhlIFJNRCBmaWxlIHRvIHByb2R1Y2UgdGhpcyByZXBvcnQsIGFuZCBzb21lIG9mIHRoZSBmaWd1cmVzIGZyb20gdGhpcyByZXBvcnQsIG1heSBiZSBmb3VuZCBpbiB0aGUgR29vZ2xlIERyaXZlIGZvbGRlciBbXjJdLiANCg0KIyBTVFJFTkdUSCBTVEFOREFSRFMNCg0KU3RyZW5ndGggU3RhbmRhcmRzIHByb3ZpZGUgdmFsdWFibGUgYmVuY2htYXJrcyBmb3IgYXNzZXNzaW5nIGFuIGluZGl2aWR1YWwncyBwZXJmb3JtYW5jZSBpbiBrZXkgc3RyZW5ndGggZXhlcmNpc2VzIHRoYXQgYXJlIHdpZGVseSBwcmFjdGljZWQgaW4gZml0bmVzcyBhbmQgc3RyZW5ndGggdHJhaW5pbmcuIFRoZXNlIHN0YW5kYXJkcyBjYXRlZ29yaXplIHBlcmZvcm1hbmNlIGxldmVscyBiYXNlZCBvbiBlaXRoZXIgYW1vdW50IG9mIHdlaWdodCBleGVjdXRlZCByZWxhdGl2ZSB0byBib2R5d2VpZ2h0LCBvciByZXBldGl0aW9ucyBleGVjdXRlZCwgYW5kIGFyZSBzZWdtZW50ZWQgYnkgZ2VuZGVyIGFuZCBleHBlcmllbmNlIGxldmVscy4gQnkgY29tcGFyaW5nIGFuIGluZGl2aWR1YWwncyBwZXJmb3JtYW5jZSBhZ2FpbnN0IHRoZXNlIGVzdGFibGlzaGVkIHN0YW5kYXJkcywgdHJhaW5lcnMgYW5kIGF0aGxldGVzIGNhbiBpZGVudGlmeSBzdHJlbmd0aHMgYW5kIHdlYWtuZXNzZXMgaW4gdGhlaXIgdHJhaW5pbmcgcmVnaW1lbnMsIHNldCByZWFsaXN0aWMgZ29hbHMsIGFuZCBtZWFzdXJlIHByb2dyZXNzIGluIGEgc3RydWN0dXJlZCBtYW5uZXIuDQoNCiMjIFN0cmVuZ3RoIFN0YW5kYXJkcyBPdmVydmlldyANCg0KU2V2ZXJhbCBzdHJlbmd0aCBzdGFuZGFyZHMgYXJlIHJlYWRpbHkgYXZhaWxhYmxlIG9ubGluZToNCg0KLSBFeFJ4IFN0cmVuZ3RoIFN0YW5kYXJkczogPGh0dHBzOi8vZXhyeC5uZXQvVGVzdGluZy9XZWlnaHRMaWZ0aW5nL1N0cmVuZ3RoU3RhbmRhcmRzPg0KLSBTdHJlbmd0aExldmVsLmNvbSBTdHJlbmd0aCBTdGFuZGFyZHM6IDxodHRwczovL3N0cmVuZ3RobGV2ZWwuY29tL3N0cmVuZ3RoLXN0YW5kYXJkcz4NCi0gU3ltbWV0cmljIFN0cmVuZ3RoOiA8aHR0cHM6Ly9zeW1tZXRyaWNzdHJlbmd0aC5jb20vPg0KLSBNYXJrIFJpcHBldG9lJ3MgU3RyZW5ndGggU3RhbmRhcmRzOiA8aHR0cHM6Ly9zdGFydGluZ3N0cmVuZ3RoLmNvbS9maWxlcy9zdGFuZGFyZHMucGRmPg0KDQpGaW5kaW5nIGFjY3VyYXRlIHN0cmVuZ3RoIHN0YW5kYXJkcyBkZXBlbmRzIG9uIHRoZSBkZW1vZ3JhcGhpYywgZXhlcmNpc2UgdHlwZSwgYW5kIHJlcXVpcmVkIGFjY3VyYWN5LiBFYWNoIGhhcyBpdHMgcHJvcyBhbmQgY29uczogc29tZSBjYXRlciB0byBzcGVjaWZpYyBkZW1vZ3JhcGhpY3MsIG90aGVycyBmb2N1cyBvbiBjZXJ0YWluIGV4ZXJjaXNlcywgYW5kIHRoZWlyIGNyZWRpYmlsaXR5IGFmZmVjdHMgcmVsaWFiaWxpdHkuIFVzYWJpbGl0eSBhbmQgY29tcHJlaGVuc2l2ZSBkYXRhIGZvciBiZW5jaG1hcmtpbmcgYXJlIGNydWNpYWwsIGFzIGFyZSByZWd1bGFyIHVwZGF0ZXMgdG8gcmVmbGVjdCBjdXJyZW50IHRyZW5kcy4gQ29uc2lkZXJpbmcgdGhlc2UgZmFjdG9ycyBoZWxwcyB0cmFpbmVycyBhbmQgYXRobGV0ZXMgY2hvb3NlIHRoZSBiZXN0IHN0YW5kYXJkcyBmb3IgYXNzZXNzaW5nIGFuZCBpbXByb3ZpbmcgcGVyZm9ybWFuY2UuDQoNCmBgYHtyIHN0cmVuZ3RoX3N0YW5kYXJkc19wbmMsIGV2YWw9VFJVRSwgcmVzdWx0cz0nYXNpcyd9DQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcw0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoa2FibGVFeHRyYSkNCg0KIyBEZWZpbmUgdGhlIHByb3MgYW5kIGNvbnMgYXMgbGlzdHMNCnByb3MgPC0gYygiQmVuY2htYXJraW5nOiBTdHJlbmd0aCBzdGFuZGFyZHMgcHJvdmlkZSBjbGVhciBiZW5jaG1hcmtzIHRvIG1lYXN1cmUgcHJvZ3Jlc3MgYW5kIHNldCBnb2Fscy4iLA0KICAgICAgICAgICJNb3RpdmF0aW9uOiBTZWVpbmcgaG93IHlvdXIgcGVyZm9ybWFuY2Ugc3RhY2tzIHVwIGFnYWluc3QgZXN0YWJsaXNoZWQgc3RhbmRhcmRzIGNhbiBiZSBoaWdobHkgbW90aXZhdGluZy4iLA0KICAgICAgICAgICJHdWlkYW5jZTogVGhleSBvZmZlciBndWlkYW5jZSBvbiB3aGF0IGlzIGNvbnNpZGVyZWQgc3Ryb25nIG9yIHdlYWsgZm9yIGRpZmZlcmVudCBleGVyY2lzZXMsIGhlbHBpbmcgeW91IHRhaWxvciB5b3VyIHRyYWluaW5nIGFjY29yZGluZ2x5LiIsDQogICAgICAgICAgIkNvbXBhcmlzb246IFRoZXkgYWxsb3cgZm9yIG1lYW5pbmdmdWwgY29tcGFyaXNvbnMgYmV0d2VlbiBpbmRpdmlkdWFscywgaGVscGluZyB0byBpZGVudGlmeSBzdHJlbmd0aHMgYW5kIHdlYWtuZXNzZXMuIiwNCiAgICAgICAgICAiU3RydWN0dXJlZCBUcmFpbmluZzogU3RyZW5ndGggc3RhbmRhcmRzIGNhbiBoZWxwIGluIGRlc2lnbmluZyBtb3JlIHN0cnVjdHVyZWQgYW5kIGVmZmVjdGl2ZSB0cmFpbmluZyBwcm9ncmFtcy4iKQ0KDQpjb25zIDwtIGMoIkdlbmVyaWM6IFN0cmVuZ3RoIHN0YW5kYXJkcyBjYW4gYmUgdG9vIGdlbmVyaWMgYW5kIG1heSBub3QgYWNjb3VudCBmb3IgaW5kaXZpZHVhbCBkaWZmZXJlbmNlcyBpbiBnZW5ldGljcywgYm9keSBjb21wb3NpdGlvbiwgYW5kIHRyYWluaW5nIGhpc3RvcnkuIiwNCiAgICAgICAgICAiUHJlc3N1cmU6IFRoZXkgY2FuIGNyZWF0ZSB1bmR1ZSBwcmVzc3VyZSB0byBtZWV0IGNlcnRhaW4gYmVuY2htYXJrcywgcG90ZW50aWFsbHkgbGVhZGluZyB0byBpbmp1cnkgb3IgYnVybm91dC4iLA0KICAgICAgICAgICJPdXRkYXRlZCBJbmZvcm1hdGlvbjogU29tZSBzdGFuZGFyZHMgbWF5IGJlIGJhc2VkIG9uIG91dGRhdGVkIGluZm9ybWF0aW9uIG9yIG5vdCByZWZsZWN0IHJlY2VudCBhZHZhbmNlbWVudHMgaW4gc3BvcnRzIHNjaWVuY2UuIiwNCiAgICAgICAgICAiTm90IENvbXByZWhlbnNpdmU6IFRoZXkgbWlnaHQgbm90IGNvdmVyIGFsbCBleGVyY2lzZXMgb3IgYWNjb3VudCBmb3IgZGlmZmVyZW50IHRyYWluaW5nIGdvYWxzLCBzdWNoIGFzIGh5cGVydHJvcGh5IHZlcnN1cyBzdHJlbmd0aC4iLA0KICAgICAgICAgICJNaXNsZWFkaW5nOiBGb3IgYmVnaW5uZXJzLCBzdHJlbmd0aCBzdGFuZGFyZHMgY2FuIGJlIG1pc2xlYWRpbmcgaWYgdGhleSBkb27igJl0IGFjY291bnQgZm9yIHRoZSBzdGFydGluZyBwb2ludCBvciByYXRlIG9mIHByb2dyZXNzIGFwcHJvcHJpYXRlIGZvciBkaWZmZXJlbnQgZml0bmVzcyBsZXZlbHMuIikNCg0KIyBDb21iaW5lIHRoZSBwcm9zIGFuZCBjb25zIGludG8gYSBkYXRhIGZyYW1lDQpzdHJlbmd0aF9zdGFuZGFyZHNfcG5jIDwtIGRhdGEuZnJhbWUoDQogIFByb3MgPSBwcm9zLA0KICBDb25zID0gY29ucywNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgUHJpbnQgdGhlIHRhYmxlIHVzaW5nIGthYmxlIGFuZCBrYWJsZUV4dHJhDQprYWJsZShzdHJlbmd0aF9zdGFuZGFyZHNfcG5jLCBmb3JtYXQgPSAiaHRtbCIsIGVzY2FwZSA9IEZBTFNFLCBjb2wubmFtZXMgPSBjKCJQcm9zIiwgIkNvbnMiKSkgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIiksIGZ1bGxfd2lkdGggPSBUUlVFKSAlPiUNCiAgY29sdW1uX3NwZWMoMSwgd2lkdGggPSAiNTAlIikgJT4lDQogIGNvbHVtbl9zcGVjKDIsIHdpZHRoID0gIjUwJSIpDQoNCmBgYA0KDQpJJ3ZlIGNvbXBpbGVkIHNvbWUgb2YgdGhlIHN0YW5kYXJkcyBpbnRvIGFuIEV4Y2VsIGZpbGVbXjNdLiBUaGlzIGFsbG93cyBmb3IgY29tcGFyaXNvbiBiZXR3ZWVuIHBlcnNvbmFsIHBlcmZvcm1hbmNlIG1lYXN1cmVzIGFuZCB0aGUgc3BlY2lmaWVkIHN0cmVuZ3RoIHN0YW5kYXJkcy4gSSByZWNvbW1lbmQgY29uc3VsdGluZyBlYWNoIHNvdXJjZSBmb3IgY29uZmlybWF0aW9uIG9uIHRoZSBsYXRlc3QgdmVyc2lvbiwgYXMgdGhlIHN0cnVjdHVyZSBvciBudW1iZXJzIG1heSBoYXZlIGNoYW5nZWQgb3ZlciB0aW1lLiANCg0KYGBge3IgcmVhZF9zdHJlbmd0aF9zdGFuZGFyZHMsIGV2YWw9VFJVRX0NCg0KIyBGaWxlIFBhdGggRGVmaW5pdGlvbjogVGhlIHNjcmlwdCBkZWZpbmVzIGEgcGF0aCB0byBhbiBFeGNlbCBmaWxlIGNvbnRhaW5pbmcgIlN0cmVuZ3RoIFN0YW5kYXJkcyIuDQpmaWxlX3BhdGhfc3RyZW5ndGhfc3RhbmRhcmRzIDwtICJDOi8vVXNlcnMvL2tlbmRyLy9PbmVEcml2ZS8vRG9jdW1lbnRzLy9EYXRhIEFuYWx5dGljcy8vS2VuRG9lc0ZpdG5lc3MvU3RyZW5ndGggU3RhbmRhcmRzIEZpbmFsLnhsc20iDQoNCiMgV29ya2Jvb2sgTG9hZGluZzogTG9hZHMgdGhlIEV4Y2VsIHdvcmtib29rIGludG8gUiB1c2luZyB0aGUgb3Blbnhsc3ggcGFja2FnZSwgd2hpY2ggcHJvdmlkZXMgbW9yZSBhZHZhbmNlZCBjb250cm9sIG92ZXIgRXhjZWwgZmlsZXMgdGhhbiByZWFkeGwuDQpzdHJlbmd0aF9zdGFuZGFyZHMgPC0gbG9hZFdvcmtib29rKGZpbGVfcGF0aF9zdHJlbmd0aF9zdGFuZGFyZHMpDQpgYGANCg0KIyMgU3RhbmRhcmRzIENhdGVnb3JpZXMgIA0KVGhlIHN0YW5kYXJkcyBjb21waWxlZCBhcmUgc2VwYXJhdGVkIGludG8gY2F0ZWdvcmllcywgYXMgc2hvd24gaW4gdGhlIGZvbGxvd2luZyB0YWJsZSwgbWFraW5nIGl0IGVhc3kgdG8gZGV0ZXJtaW5lIHdoaWNoIGV4ZXJjaXNlIHRvIHVzZSBhcyBhIGJlbmNobWFyay4NCg0KYGBge3Igc3RyZW5ndGhfc3RhbmRhcmRzX3NoZWV0X25hbWVzLCBldmFsPVRSVUUsIHJlc3VsdHM9J21hcmt1cCd9DQoNCiMgU2hlZXQgTmFtZXMgRGlzcGxheTogUmV0cmlldmVzIGFuZCBkaXNwbGF5cyB0aGUgbmFtZXMgb2Ygc2hlZXRzIHdpdGhpbiB0aGUgRXhjZWwgd29ya2Jvb2sgdG8gaGVscCBpZGVudGlmeSBhdmFpbGFibGUgZGF0YS4NCg0KIyBDaGVjayB0byBjb25maXJtIHdoaWNoIG51bWJlciBvZiBuYW1lcyB0byBkaXNwbGF5DQojIG5hbWVzKHN0cmVuZ3RoX3N0YW5kYXJkcykNCg0KIyBEaXNwbGF5IHNwZWNpZmljIGVsZW1lbnRzIGZyb20gdGhlIHN0cmVuZ3RoX3N0YW5kYXJkcyBvYmplY3Qgd2l0aCBJbmRleGluZw0KbmFtZXNfc3Vic2V0X3N0cmVuZ3RoX3N0YW5kYXJkcyA8LSBuYW1lcyhzdHJlbmd0aF9zdGFuZGFyZHMpWzQ6MTVdDQpuYW1lc19zdWJzZXRfc3RyZW5ndGhfc3RhbmRhcmRzX2dzdWIgPSBnc3ViKCJfIiwiICIsIG5hbWVzX3N1YnNldF9zdHJlbmd0aF9zdGFuZGFyZHMpDQojIG5hbWVzX3N1YnNldF9zdHJlbmd0aF9zdGFuZGFyZHMNCg0KIyBDYWxjdWxhdGUgdGhlIG51bWJlciBvZiBuYW1lcw0KbnVtX25hbWVzIDwtIGxlbmd0aChuYW1lc19zdWJzZXRfc3RyZW5ndGhfc3RhbmRhcmRzX2dzdWIpDQoNCiMgQ2FsY3VsYXRlIHRoZSBudW1iZXIgb2YgbmFtZXMgcGVyIGNvbHVtbg0KbmFtZXNfcGVyX2NvbHVtbiA8LSBjZWlsaW5nKG51bV9uYW1lcyAvIDIpDQoNCiMgU3BsaXQgdGhlIG5hbWVzIGludG8gdHdvIGNvbHVtbnMNCmNvbHVtbl8xIDwtIG5hbWVzX3N1YnNldF9zdHJlbmd0aF9zdGFuZGFyZHNfZ3N1YlsxOm1pbihuYW1lc19wZXJfY29sdW1uLCBudW1fbmFtZXMpXQ0KY29sdW1uXzIgPC0gbmFtZXNfc3Vic2V0X3N0cmVuZ3RoX3N0YW5kYXJkc19nc3ViWyhtaW4obmFtZXNfcGVyX2NvbHVtbiwgbnVtX25hbWVzKSArIDEpOm51bV9uYW1lc10NCg0KIyBQYWQgdGhlIHNob3J0ZXIgY29sdW1uIHdpdGggTkEgdmFsdWVzIGlmIG5lY2Vzc2FyeQ0KaWYobGVuZ3RoKGNvbHVtbl8xKSA8IGxlbmd0aChjb2x1bW5fMikpIHsNCiAgY29sdW1uXzEgPC0gYyhjb2x1bW5fMSwgcmVwKCIiLCBsZW5ndGgoY29sdW1uXzIpIC0gbGVuZ3RoKGNvbHVtbl8xKSkpDQp9IGVsc2UgaWYobGVuZ3RoKGNvbHVtbl8yKSA8IGxlbmd0aChjb2x1bW5fMSkpIHsNCiAgY29sdW1uXzIgPC0gYyhjb2x1bW5fMiwgcmVwKCIiLCBsZW5ndGgoY29sdW1uXzEpIC0gbGVuZ3RoKGNvbHVtbl8yKSkpDQp9DQogIA0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggdHdvIGNvbHVtbnMNCm5hbWVzX3N1YnNldF9zdHJlbmd0aF9zdGFuZGFyZHNfZ3N1Yl9kZiA8LSBkYXRhLmZyYW1lKENvbHVtbl8xID0gY29sdW1uXzEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDb2x1bW5fMiA9IGNvbHVtbl8yKQ0KDQojIENhbGN1bGF0ZSB0aGUgd2lkdGggZHluYW1pY2FsbHkNCmNvbF93aWR0aCA8LSBwYXN0ZTAoMTAwIC8gbmNvbChuYW1lc19zdWJzZXRfc3RyZW5ndGhfc3RhbmRhcmRzX2dzdWJfZGYpLCAiJSIpDQoNCiMgUHJpbnQgdGhlIGRhdGEgZnJhbWUgdXNpbmcga25pdHI6OmthYmxlDQprbml0cjo6a2FibGUobmFtZXNfc3Vic2V0X3N0cmVuZ3RoX3N0YW5kYXJkc19nc3ViX2RmLCBmb3JtYXQgPSAibWFya2Rvd24iLCBjb2wubmFtZXMgPSBjKCJDYXRlZ29yaWVzIiwgIkNhdGVnb3JpZXMiKSkgJT4lDQogIGNvbHVtbl9zcGVjKDE6Miwgd2lkdGggPSBjb2xfd2lkdGgsIGV4dHJhX2NzcyA9ICJ0ZXh0LWFsaWduOiBsZWZ0OyIpDQoNCmBgYA0KDQojIyBTdHJlbmd0aCBTdGFuZGFyZHMgTGlzdCANCkJlbG93IGlzIHRoZSBsaXN0IG9mIFN0cmVuZ3RoIFN0YW5kYXJkcyBjb21waWxlZCBpbnRvIHRoZSBTUyBFeGNlbCBmaWxlW14zXS4gVGhpcyBmaWxlIHJlZmVyZW5jZXMgdGhlIHNvdXJjZSBvZiBlYWNoIHN0YW5kYXJkIHRhYmxlLiBXZSdsbCBkZWx2ZSBpbnRvIE1hcmsgUmlwcGV0b2UncyBTdGFydGluZyBTdHJlbmd0aCBTdGFuZGFyZHMsIGFzIGhpcyBhbmQgaGlzIGNvbGxlYWd1ZXMnIG1ldGhvZHMgYW5kIHJlc2VhcmNoIGFyZSBiYXNlZCBvbiBjb21wcmVoZW5zaXZlIGFuZCB0ZWNobmljYWwgaW5mb3JtYXRpb24uDQoNCmBgYHtyIG5hbWVkX3JhbmdlcywgZXZhbD1UUlVFLCByZXN1bHRzPSdtYXJrdXAnfQ0KDQpsaWJyYXJ5KG9wZW54bHN4KQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KDQojIFJlYWQgTmFtZWQgUmFuZ2VzOiBSZWFkcyBhIHNwZWNpZmljIHNoZWV0IG5hbWVkICJOYW1lZF9SYW5nZXMiIHRoYXQgcHJlc3VtYWJseSBjb250YWlucyBtZXRhZGF0YSBhYm91dCBvdGhlciBuYW1lZCByYW5nZXMgaW4gdGhlIHdvcmtib29rLiBJdCBrZWVwcyBvbmx5IHRoZSBjb2x1bW5zIHJlbGF0ZWQgdG8gbmFtZWQgcmFuZ2VzIGFuZCB0aGVpciByZXNwZWN0aXZlIHNoZWV0cy4NCm5hbWVkX3JhbmdlcyA8LSByZWFkX2V4Y2VsKGZpbGVfcGF0aF9zdHJlbmd0aF9zdGFuZGFyZHMsIHNoZWV0ID0gIk5hbWVkX1JhbmdlcyIpDQpzaGVldF9uYW1lc19maWx0ZXJlZCA8LSB1bmlxdWUobmFtZWRfcmFuZ2VzJGBDYXRlZ29yeSBTaGVldGApDQpuYW1lZF9yYW5nZXMgPC0gbmFtZWRfcmFuZ2VzW25hbWVkX3JhbmdlcyRgQ2F0ZWdvcnkgU2hlZXRgICVpbiUgc2hlZXRfbmFtZXNfZmlsdGVyZWQsIGMoIlN0cmVuZ3RoIFN0YW5kYXJkIiwgIkNhdGVnb3J5IFNoZWV0IildDQoNCiMgRGlzcGxheSB0aGUgbW9kaWZpZWQgJ1N0cmVuZ3RoIFN0YW5kYXJkJyBjb2x1bW4gd2l0aCBzcGFjZXMgaW5zdGVhZCBvZiB1bmRlcnNjb3Jlcw0Kc3RyZW5ndGhfc3RhbmRhcmRzX2xpc3RfZGlzcGxheSA8LSBuYW1lZF9yYW5nZXMgJT4lDQogIG11dGF0ZShgU3RyZW5ndGggU3RhbmRhcmRgID0gZ3N1YigiXyIsICIgIiwgYFN0cmVuZ3RoIFN0YW5kYXJkYCkpICU+JQ0KICBtdXRhdGUoYENhdGVnb3J5IE5hbWVgID0gZ3N1YigiXyIsICIgIiwgYENhdGVnb3J5IFNoZWV0YCkpICU+JQ0KICBzZWxlY3QoLWBDYXRlZ29yeSBTaGVldGApICAjIFRoaXMgZXhjbHVkZXMgdGhlICdDYXRlZ29yeSBTaGVldCcgY29sdW1uDQoNCiMgVmlldyB0aGUgZGF0YSBmcmFtZSBpZiBuZWVkZWQgKG5vdCBkdXJpbmcga25pdHRpbmcpLiBWaWV3IGZ1bmN0aW9uIG9wZW5zIHRoZSByYXdfZGF0YSBkYXRhZnJhbWUgaW4gdGhlIFJTdHVkaW8gZGF0YSB2aWV3ZXIgZm9yIGludGVyYWN0aXZlIGV4cGxvcmF0aW9uLg0KVmlldyhuYW1lZF9yYW5nZXMpDQpWaWV3KHN0cmVuZ3RoX3N0YW5kYXJkc19saXN0X2Rpc3BsYXkpDQoNCiMgRGVmaW5lIHRoZSByYXRpb3MgYW5kIHRvdGFsIHdpZHRoIGZvciBjb2x1bW4gd2lkdGhzDQp0b3RhbF93aWR0aCA8LSAxMDANCnJhdGlvX3N0cmVuZ3RoX3N0YW5kYXJkcyA8LSAyDQpyYXRpb19jYXRlZ29yeSA8LSAxLjI1DQp0b3RhbF9yYXRpbyA8LSByYXRpb19zdHJlbmd0aF9zdGFuZGFyZHMgKyByYXRpb19jYXRlZ29yeQ0KDQojIENhbGN1bGF0ZSB0aGUgY29sdW1uIHdpZHRocw0Kd2lkdGhfc3RyZW5ndGhfc3RhbmRhcmRzIDwtIChyYXRpb19zdHJlbmd0aF9zdGFuZGFyZHMgLyB0b3RhbF9yYXRpbykgKiB0b3RhbF93aWR0aA0Kd2lkdGhfY2F0ZWdvcnkgPC0gKHJhdGlvX2NhdGVnb3J5IC8gdG90YWxfcmF0aW8pICogdG90YWxfd2lkdGgNCg0KIyBQcmludCB0aGUgZGF0YWZyYW1lIHVzaW5nIGthYmxlIGZvciBhIG5pY2VseSBmb3JtYXR0ZWQgbWFya2Rvd24gdGFibGUuDQprYWJsZShzdHJlbmd0aF9zdGFuZGFyZHNfbGlzdF9kaXNwbGF5LCBmb3JtYXQgPSAiaHRtbCIsIGNvbC5uYW1lcyA9IGMoIlN0cmVuZ3RoIFN0YW5kYXJkIiwgIkNhdGVnb3J5IikpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUUlVFKSAlPiUNCiAgY29sdW1uX3NwZWMoMSwgd2lkdGggPSBwYXN0ZTAod2lkdGhfc3RyZW5ndGhfc3RhbmRhcmRzLCAiJSIpKSAlPiUNCiAgY29sdW1uX3NwZWMoMiwgd2lkdGggPSBwYXN0ZTAod2lkdGhfY2F0ZWdvcnksICIlIikpDQoNCiMgQ3JlYXRlIGxpc3RzIHRvIHN0b3JlIGRhdGEgZnJhbWVzDQpuYW1lZF9yYW5nZXNfbGlzdCA8LSBsaXN0KCkNCm5hbWVkX3Jhbmdlc19zaGVldHNfbGlzdCA8LSBsaXN0KCkNCg0KIyBMb29wIHRocm91Z2ggdGhlIG5hbWVkIHJhbmdlcw0KZm9yIChpIGluIDE6bnJvdyhuYW1lZF9yYW5nZXMpKSB7DQogIG5hbWVkX3JhbmdlX3ZhbHVlIDwtIG5hbWVkX3JhbmdlcyRgU3RyZW5ndGggU3RhbmRhcmRgW2ldDQogIG5hbWVkX3JhbmdlX3NoZWV0X3ZhbHVlIDwtIG5hbWVkX3JhbmdlcyRgQ2F0ZWdvcnkgU2hlZXRgW2ldDQogIG5hbWVkX3JhbmdlX2xvd2VyIDwtIHRvbG93ZXIoZ3N1YigiICIsICJfIiwgbmFtZWRfcmFuZ2VfdmFsdWUpKQ0KICBuYW1lZF9yYW5nZV9zaGVldF9sb3dlciA8LSB0b2xvd2VyKGdzdWIoIiAiLCAiXyIsIG5hbWVkX3JhbmdlX3NoZWV0X3ZhbHVlKSkNCiAgDQogIGlmIChuYW1lZF9yYW5nZV9zaGVldF92YWx1ZSA9PSAiTmFtZWRfUmFuZ2VzIikgew0KICAgIG5leHQgICMgU2tpcCBpdGVyYXRpb24gaWYgdGhlIHNoZWV0IGlzICJOYW1lZF9SYW5nZXMiIHRvIGF2b2lkIHJlZHVuZGFuY3kNCiAgfQ0KICANCiAgIyBSZWFkIGRhdGEgZnJvbSB0aGUgbmFtZWQgcmFuZ2UNCiAgbmFtZWRfcmFuZ2VfZGF0YSA8LSB0cnlDYXRjaCh7DQogICAgcmVhZC54bHN4KGZpbGVfcGF0aF9zdHJlbmd0aF9zdGFuZGFyZHMsIG5hbWVkUmVnaW9uID0gbmFtZWRfcmFuZ2VfdmFsdWUpDQogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgew0KICAgIG1lc3NhZ2UocGFzdGUoIldhcm5pbmc6IFdvcmtib29rIGhhcyBubyBzdWNoIG5hbWVkIHJlZ2lvbjoiLCBuYW1lZF9yYW5nZV92YWx1ZSkpDQogICAgTlVMTA0KICB9KQ0KICANCiAgaWYgKCFpcy5udWxsKG5hbWVkX3JhbmdlX2RhdGEpICYmIGlzLmRhdGEuZnJhbWUobmFtZWRfcmFuZ2VfZGF0YSkpIHsNCiAgICAjIFVwZGF0ZSBjb2x1bW4gbmFtZXMNCiAgICBjb2xuYW1lcyhuYW1lZF9yYW5nZV9kYXRhKSA8LSBnc3ViKCJcXC4iLCAiICIsIGNvbG5hbWVzKG5hbWVkX3JhbmdlX2RhdGEpKQ0KICAgICMgU3RvcmUgdGhlIGRhdGEgZnJhbWUgaW4gdGhlIGxpc3QNCiAgICBuYW1lZF9yYW5nZXNfbGlzdFtbbmFtZWRfcmFuZ2VfbG93ZXJdXSA8LSBuYW1lZF9yYW5nZV9kYXRhDQogICAgIyBBc3NpZ24gdGhlIGRhdGEgZnJhbWUgdG8gdGhlIGdsb2JhbCBlbnZpcm9ubWVudCB3aXRoIHRoZSBsb3dlciBjYXNlIG5hbWUNCiAgICBhc3NpZ24obmFtZWRfcmFuZ2VfbG93ZXIsIG5hbWVkX3JhbmdlX2RhdGEsIGVudmlyID0gLkdsb2JhbEVudikNCiAgfQ0KICANCiAgIyBSZWFkIGRhdGEgZnJvbSB0aGUgc2hlZXQNCiAgbmFtZWRfcmFuZ2Vfc2hlZXRfZGF0YSA8LSB0cnlDYXRjaCh7DQogICAgcmVhZC54bHN4KGZpbGVfcGF0aF9zdHJlbmd0aF9zdGFuZGFyZHMsIHNoZWV0ID0gbmFtZWRfcmFuZ2Vfc2hlZXRfdmFsdWUpDQogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgew0KICAgIG1lc3NhZ2UocGFzdGUoIldhcm5pbmc6IFdvcmtib29rIGhhcyBubyBzdWNoIHNoZWV0OiIsIG5hbWVkX3JhbmdlX3NoZWV0X3ZhbHVlKSkNCiAgICBOVUxMDQogIH0pDQogIA0KICBpZiAoIWlzLm51bGwobmFtZWRfcmFuZ2Vfc2hlZXRfZGF0YSkgJiYgaXMuZGF0YS5mcmFtZShuYW1lZF9yYW5nZV9zaGVldF9kYXRhKSkgew0KICAgICMgVXBkYXRlIGNvbHVtbiBuYW1lcw0KICAgIGNvbG5hbWVzKG5hbWVkX3JhbmdlX3NoZWV0X2RhdGEpIDwtIGdzdWIoIlxcLiIsICIgIiwgY29sbmFtZXMobmFtZWRfcmFuZ2Vfc2hlZXRfZGF0YSkpDQogICAgIyBTdG9yZSB0aGUgZGF0YSBmcmFtZSBpbiB0aGUgbGlzdA0KICAgIG5hbWVkX3Jhbmdlc19zaGVldHNfbGlzdFtbbmFtZWRfcmFuZ2Vfc2hlZXRfbG93ZXJdXSA8LSBuYW1lZF9yYW5nZV9zaGVldF9kYXRhDQogICAgIyBBc3NpZ24gdGhlIGRhdGEgZnJhbWUgdG8gdGhlIGdsb2JhbCBlbnZpcm9ubWVudCB3aXRoIHRoZSBsb3dlciBjYXNlIG5hbWUNCiAgICBhc3NpZ24obmFtZWRfcmFuZ2Vfc2hlZXRfbG93ZXIsIG5hbWVkX3JhbmdlX3NoZWV0X2RhdGEsIGVudmlyID0gLkdsb2JhbEVudikNCiAgfQ0KfQ0KDQojIERpc3BsYXkgdGhlIHN0cnVjdHVyZSBvZiB0aGUgbGlzdHMNCiMgc3RyKG5hbWVkX3Jhbmdlc19saXN0KQ0KIyBzdHIobmFtZWRfcmFuZ2VzX3NoZWV0c19saXN0KQ0KDQojIE9wdGlvbmFsOiBWaWV3IHRoZSBjb250ZW50cyBvZiB0aGUgbGlzdHMgaW4gUlN0dWRpbyBWaWV3ZXINCiMgSW5zdGVhZCBvZiB2aWV3aW5nIHRoZSB3aG9sZSBsaXN0LCB2aWV3IGluZGl2aWR1YWwgZGF0YSBmcmFtZXMNCiMgVW5jb21tZW50IHRoZSBiZWxvdyBsaW5lcyB0byB2aWV3IHNwZWNpZmljIG5hbWVkIHJhbmdlcyBvciBzaGVldHMNCiMgVmlldyhuYW1lZF9yYW5nZXNfbGlzdFtbIm1hbGVfYmFyYmVsbF9jdXJsX3N0ZF8xcm1fYnlfYWdlX3N0cmVuZ3RobGV2ZWwiXV0pDQojIFZpZXcobWFsZV9iYXJiZWxsX2N1cmxfc3RkXzFybV9ieV9hZ2Vfc3RyZW5ndGhsZXZlbCkNCg0KYGBgDQoNCiMgTUFSSyBSSVBQRVRPRSdTIFNUQU5EQVJEUw0KDQpNYXJrIFJpcHBldG9lJ3MgU3RyZW5ndGggU3RhbmRhcmQ6IDEgUmVwIE1heCBCeSBCb2R5d2VpZ2h0LiAgDQoNCkhlcmUgd2UgdXRpbGl6ZSBNYXJrIFJpcHBldG9lJ3MgU3RyZW5ndGggU3RhbmRhcmRzW140XSB0byBiZW5jaG1hcmsgaW5kaXZpZHVhbCBwZXJmb3JtYW5jZSBhZ2FpbnN0IGVzdGFibGlzaGVkIGNyaXRlcmlhIGZvciBwcmltYXJ5IHN0cmVuZ3RoIGV4ZXJjaXNlcy4gVGhlc2Ugc3RhbmRhcmRzIGFyZSBpbnN0cnVtZW50YWwgaW4gZXZhbHVhdGluZyBhbiBpbmRpdmlkdWFsJ3MgbGlmdGluZyBjYXBhYmlsaXRpZXMgaW4gcmVsYXRpb24gdG8gdGhlaXIgYm9keXdlaWdodCBhbmQgdHJhaW5pbmcgZXhwZXJpZW5jZS4gQnkgZG9pbmcgc28sIHdlIGNhbiBlZmZlY3RpdmVseSBnYXVnZSBwcm9ncmVzcywgcGlucG9pbnQgYXJlYXMgdGhhdCBuZWVkIGltcHJvdmVtZW50LCBhbmQgdGFpbG9yIHRyYWluaW5nIHByb2dyYW1zIHRvIGJldHRlciBtZWV0IHRoZSBzcGVjaWZpYyBzdHJlbmd0aCBnb2FscyBvZiBlYWNoIGluZGl2aWR1YWwuDQoNClRoZSBleGVyY2lzZXMgdXNlIHRoZSB0ZWNobmlxdWUgZGVzY3JpYmVkIGluICJTdGFydGluZyBTdHJlbmd0aDogQmFzaWMgQmFyYmVsbCBUcmFpbmluZywgM3JkIGVkLiIgVGhlIEJsdWVib29rIG1heSBiZSBwdXJjaGFzZWQgdGhyb3VnaCBUaGUgQWFzZ2FhcmQgQ29tcGFueSBvbmxpbmUgc3RvcmVbXjVdIGFuZCBvbiBBbWF6b24gaW4gdmFyaW91cyBtZWRpdW1zIChwYXBlcmJhY2ssIEtpbmRsZSwgYXVkaW8pLiBBbGwgbGlmdHMgYXJlIHBlcmZvcm1lZCB3aXRoIHRoZSBiYXJiZWxsLCBhcyBpbmRpY2F0ZWQgYnkgdGhlIGJvb2sgdGl0bGUuDQoNClRvIHByb3Blcmx5IHV0aWxpemUgdGhlc2Ugc3RhbmRhcmRzLCBpdCBpcyByZWNvbW1lbmRlZCB0byByZXZpZXcgIlN0YXJ0aW5nIFN0cmVuZ3RoOiBCYXNpYyBCYXJiZWxsIFRyYWluaW5nIlteOF0gYW5kICJQcmFjdGljYWwgUHJvZ3JhbW1pbmcgZm9yIFN0cmVuZ3RoIFRyYWluaW5nLiJbXjldIFRoZSBtb3N0IHJlY2VudCBhbmQgcmVsZXZhbnQgM3JkIGVkaXRpb25zICgyMDEyKSBhcmUgYXZhaWxhYmxlIG9uIHRoZWlyIHdlYnNpdGUsIGFzIHdlbGwgYXMgaW4gZGlmZmVyZW50IG1lZGl1bXMgb24gQW1hem9uLiBZb3UgY2FuIGRvd25sb2FkIG9ubGluZSBib29rIHNhbXBsZXMgdG8gZGV0ZXJtaW5lIGlmIFN0YXJ0aW5nIFN0cmVuZ3RoIHN1aXRzIHlvdXIgbmVlZHMuDQoNCmBgYHtyIG1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QsIGV2YWw9VFJVRSwgcmVzdWx0cz0nbWFya3VwJ30NCg0KIyBDb2RlIGV4dHJhY3RzIGFuZCByZWZpbmVzIGEgc3Vic2V0IG9mIGRhdGEgcmVsYXRlZCB0byAiTWFyayBSaXBwZXRvZSIgc3RhbmRhcmRzIGZyb20gYSBicm9hZGVyIGRhdGFzZXQsIG1ha2luZyBpdCBtb3JlIGFjY2Vzc2libGUgYW5kIGVhc2llciB0byB3b3JrIHdpdGggYnkgY2xlYW5pbmcgdXAgdGhlIGNhdGVnb3J5IG5hbWVzIGZvciBmdXJ0aGVyIGFuYWx5c2lzIG9yIHJlcG9ydGluZw0KDQojIHN1YnNldCgpIGZpbHRlcnMgcm93cyBmcm9tIHRoZSBuYW1lZF9yYW5nZXMgZGF0YWZyYW1lLg0KIyBncmVwbCgpIGNoZWNrcyBlYWNoIGVudHJ5IGluIHRoZSAiU3RyZW5ndGggU3RhbmRhcmQiIGNvbHVtbiBmb3IgdGhlIHN1YnN0cmluZyANCm1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QgPC0gc3Vic2V0KG5hbWVkX3JhbmdlcywgZ3JlcGwoIk1hcmtfUmlwcGV0b2UiLCBgU3RyZW5ndGggU3RhbmRhcmRgKSkNCg0KIyBQaXBlIE9wZXJhdG9yICglPiUpIGlzIHVzZWQgdG8gcGFzcyB0aGUgcmVzdWx0IG9mIG9uZSBmdW5jdGlvbiB0byB0aGUgbmV4dC4gSXQgaGVscHMgaW4gd3JpdGluZyBjbGVhbmVyIGFuZCBtb3JlIHJlYWRhYmxlIGNvZGUsIGVzcGVjaWFsbHkgd2hlbiBwZXJmb3JtaW5nIG11bHRpcGxlIG9wZXJhdGlvbnMgb24gYSBkYXRhc2V0Lg0KIyBnc3ViKCJfIiwgIiAiLCBDYXRlZ29yeSBTaGVldCkgcmVwbGFjZXMgdW5kZXJzY29yZXMgKF8pIHdpdGggc3BhY2VzIGluIHRoZSBDYXRlZ29yeSBTaGVldCBjb2x1bW4uDQojIE5ldyBjb2x1bW4gaXMgY3JlYXRlZC4gDQptYXJrX3JpcHBldG9lX3N0YW5kYXJkc19saXN0IDwtIG1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QgJT4lDQogIG11dGF0ZShgQ2F0ZWdvcnkgTmFtZWAgPSBnc3ViKCJfIiwgIiAiLCBgQ2F0ZWdvcnkgU2hlZXRgKSkNCg0KIyBEaXNwbGF5IHRoZSBtb2RpZmllZCAnU3RyZW5ndGggU3RhbmRhcmQnIGNvbHVtbiB3aXRoIHNwYWNlcyBpbnN0ZWFkIG9mIHVuZGVyc2NvcmVzDQpkaXNwbGF5X21hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QgPC0gbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCAlPiUNCiAgbXV0YXRlKGBTdHJlbmd0aCBTdGFuZGFyZGAgPSBnc3ViKCJfIiwgIiAiLCBgU3RyZW5ndGggU3RhbmRhcmRgKSkgJT4lDQogIHNlbGVjdCgtYENhdGVnb3J5IFNoZWV0YCkgICMgVGhpcyBleGNsdWRlcyB0aGUgJ0NhdGVnb3J5IFNoZWV0JyBjb2x1bW4NCg0KIyBUaGUgVmlldyBmdW5jdGlvbiBpcyB1c2VkIHRvIG9wZW4gdGhlIHJhd19kYXRhIGRhdGFmcmFtZSBpbiB0aGUgUlN0dWRpbyBkYXRhIHZpZXdlciBmb3IgaW50ZXJhY3RpdmUgZXhwbG9yYXRpb24uDQpWaWV3KG1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QpICNSdW4gdGhpcyBsaW5lIG9mIGNvZGUgdG8gdmlldyB0YWJsZS4gDQoNCiMgUHJpbnQgZm9yIHJlZmVyZW5jZS4gDQojIHByaW50KG1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX2xpc3QpDQojIHByaW50KGRpc3BsYXlfbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCkNCg0KIyBEZWZpbmUgdGhlIHJhdGlvcyBhbmQgdG90YWwgd2lkdGggZm9yIGNvbHVtbiB3aWR0aHMNCnRvdGFsX3dpZHRoIDwtIDEwMA0KcmF0aW9fc3RyZW5ndGhfc3RhbmRhcmRzIDwtIDINCnJhdGlvX2NhdGVnb3J5IDwtIDEuMjUNCnRvdGFsX3JhdGlvIDwtIHJhdGlvX3N0cmVuZ3RoX3N0YW5kYXJkcyArIHJhdGlvX2NhdGVnb3J5DQoNCiMgQ2FsY3VsYXRlIHRoZSBjb2x1bW4gd2lkdGhzDQp3aWR0aF9zdHJlbmd0aF9zdGFuZGFyZHMgPC0gKHJhdGlvX3N0cmVuZ3RoX3N0YW5kYXJkcyAvIHRvdGFsX3JhdGlvKSAqIHRvdGFsX3dpZHRoDQp3aWR0aF9jYXRlZ29yeSA8LSAocmF0aW9fY2F0ZWdvcnkgLyB0b3RhbF9yYXRpbykgKiB0b3RhbF93aWR0aA0KDQojIFByaW50IHRoZSBkYXRhZnJhbWUgdXNpbmcga2FibGUgZm9yIGEgbmljZWx5IGZvcm1hdHRlZCBtYXJrZG93biB0YWJsZS4NCmthYmxlKGRpc3BsYXlfbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCwgZm9ybWF0ID0gImh0bWwiLCBjb2wubmFtZXMgPSBjKCJTdHJlbmd0aCBTdGFuZGFyZCIsICJDYXRlZ29yeSIpKSAlPiUNCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gVFJVRSkgJT4lDQogIGNvbHVtbl9zcGVjKDEsIHdpZHRoID0gcGFzdGUwKHdpZHRoX3N0cmVuZ3RoX3N0YW5kYXJkcywgIiUiKSkgJT4lDQogIGNvbHVtbl9zcGVjKDIsIHdpZHRoID0gcGFzdGUwKHdpZHRoX2NhdGVnb3J5LCAiJSIpKQ0KDQoNCmBgYA0KDQpUaGVyZSBhcmUgZml2ZSBTdGFydGluZyBTdHJlbmd0aCBTdGFuZGFyZHMsIHdpdGggdGhlIFBvd2VyIENsZWFuIGV4Y2x1ZGVkIGluIHRoaXMgcmVwb3J0IGFzIG15IGNvbGxlYWd1ZXMgYW5kIEkgZG8gbm90IHBlcmZvcm0gdGhhdCBleGVyY2lzZS4gRWFjaCBvZiB0aGUgZm91ciByZW1haW5pbmcgU3RhbmRhcmRzIGlzIHByZXNlbnRlZCBiZWxvdywgZm9sbG93ZWQgYnkgYSBwbG90IHRvIHZpc3VhbGl6ZSBwZXJmb3JtYW5jZXMgZm9yIGNvbXBhcmlzb24gYW5kIG1vdGl2YXRpb24uDQoNCmBgYHtyIG1hcmtfcmlwcGV0b2Vfc3RhbmRhcmRzX3RhYmxlc19hbmRfcGxvdHMsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD03LCBldmFsPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQ0KDQojIEtlZXAgZmlnLndpZHRoPTEwIGZvciBQREYgZGlzcGxheSAodmlhIGJyb3dzZXIgPiBTYXZlIEFzIFBERikuIFdoaWxlIGZpZy53aWR0aD05IChpbnN0ZWFkIG9mIDEwKSBmaXRzIHdpZHRoIG9mIG91dHB1dCwgc2F2aW5nIGFzIFBERiB3aXRoIGZpZy53aWR0aD05IHdpbGwgcmVzdWx0IGluIHNtYWxsIGZpZ3VyZTsgd2lkdGg9MTAgd2lsbCBmaWxsIHRoZSBQREYgcGFnZS4NCg0KIyBMb2FkIHRoZSByZXF1aXJlZCBwYWNrYWdlcyBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShrYWJsZUV4dHJhKSAjIEVuc3VyZSBrYWJsZUV4dHJhIGlzIGxvYWRlZCBmb3Igc3R5bGluZw0KDQojIEZ1bmN0aW9uIHRvIGdlbmVyYXRlIGdncGxvdCBmb3IgZWFjaCBkYXRhIGZyYW1lDQpnZW5lcmF0ZV9nZ3Bsb3QgPC0gZnVuY3Rpb24oZGF0YSwgY2F0ZWdvcnlfbmFtZSwgbWFya19yaXBwZXRvZV9zdHJlbmd0aF9zdGFuZGFyZCkgew0KICBkYXRhX251bWJlciA8LSBkYXRhICU+JQ0KICAgIG11dGF0ZShCb2R5d2VpZ2h0ID0gYXMubnVtZXJpYyhnc3ViKCJbXjAtOV0iLCAiIiwgQm9keXdlaWdodCkpKQ0KDQogICMgUmVuYW1lIGNvbHVtbnMgdG8gcmVtb3ZlIGRvdWJsZSBwZXJpb2RzDQogIGNvbG5hbWVzKGRhdGFfbnVtYmVyKSA8LSBnc3ViKCJcXC5cXC4iLCAiLiAiLCBjb2xuYW1lcyhkYXRhX251bWJlcikpDQoNCiAgIyBQcmludCBjb2x1bW4gbmFtZXMgZm9yIGRlYnVnZ2luZw0KICAjIHByaW50KGNvbG5hbWVzKGRhdGFfbnVtYmVyKSkNCiAgICANCiAgZ2dwbG90KGRhdGFfbnVtYmVyLCBhZXMoeCA9IEJvZHl3ZWlnaHQpKSArDQogICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBgQ2F0LiBJYCwgeW1heCA9IGBDYXQuIElJYCksIGZpbGwgPSAiYmx1ZSIsIGFscGhhID0gMC4yKSArDQogICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBgQ2F0LiBJSWAsIHltYXggPSBgQ2F0LiBJSUlgKSwgZmlsbCA9ICJncmVlbiIsIGFscGhhID0gMC4yKSArDQogICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBgQ2F0LiBJSUlgLCB5bWF4ID0gYENhdC4gSVZgKSwgZmlsbCA9ICJvcmFuZ2UiLCBhbHBoYSA9IDAuMikgKw0KICAgIGdlb21fcmliYm9uKGFlcyh5bWluID0gYENhdC4gSVZgLCB5bWF4ID0gYENhdC4gVmApLCBmaWxsID0gInJlZCIsIGFscGhhID0gMC4yKSArDQogICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSBgQ2F0LiBWYCwgeW1heCA9IEluZiksIGZpbGwgPSAicHVycGxlIiwgYWxwaGEgPSAwLjIpICsNCiAgICANCiAgICAjIEZpbGwgdGhlIHJlbWFpbmluZyBub24tY29sb3JlZCBwYXJ0DQogICAgZ2VvbV9yaWJib24oYWVzKHltaW4gPSAtSW5mLCB5bWF4ID0gYENhdC4gSWApLCBmaWxsID0gImdyYXkiLCBhbHBoYSA9IDAuMikgKw0KICAgIA0KICAgICMgQ3JlYXRlIGxpbmVzDQogICAgZ2VvbV9saW5lKGFlcyh5ID0gYENhdC4gSWApLCBjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDEpICsNCiAgICBnZW9tX2xpbmUoYWVzKHkgPSBgQ2F0LiBJSWApLCBjb2xvciA9ICJncmVlbiIsIHNpemUgPSAxKSArDQogICAgZ2VvbV9saW5lKGFlcyh5ID0gYENhdC4gSUlJYCksIGNvbG9yID0gIm9yYW5nZSIsIHNpemUgPSAxKSArDQogICAgZ2VvbV9saW5lKGFlcyh5ID0gYENhdC4gSVZgKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDEpICsNCiAgICBnZW9tX2xpbmUoYWVzKHkgPSBgQ2F0LiBWYCksIGNvbG9yID0gInB1cnBsZSIsIHNpemUgPSAxKSArDQogICAgDQogICAgIyBTZXQgbGFiZWxzDQogICAgbGFicygNCiAgICAgIHggPSAiQm9keXdlaWdodCAobGIpIiwNCiAgICAgIHkgPSAiMVJNIFdlaWdodCBMb2FkIEV4ZWN1dGlvbiIsDQogICAgICB0aXRsZSA9IHBhc3RlKCJNYWxlIiwgY2F0ZWdvcnlfbmFtZSwgIlN0YW5kYXJkcyIpLA0KICAgICAgc3VidGl0bGUgPSAiQ29tcGFyaXNvbiBvZiBTdHJlbmd0aCBTdGFuZGFyZHMgQWNyb3NzIEV4cGVyaWVuY2UgTGV2ZWxzIiwNCiAgICAgIGNhcHRpb24gPSBwYXN0ZSgiU291cmNlOiIsIG1hcmtfcmlwcGV0b2Vfc3RyZW5ndGhfc3RhbmRhcmQpICMgQ2hhbmdlIFNvdXJjZSBpbmZvIFBSTg0KICAgICkgKw0KICAgIA0KICAgICMgQWRkIG1vcmUgbWFya2VycyBvbiB0aGUgeS1heGlzIGF0IGluY3JlbWVudHMgb2YgMjANCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDk5OSwgYnkgPSAyMCkpICsNCiAgICAjIEFkZCBtb3JlIG1hcmtlcnMgb24gdGhlIHgtYXhpcyBhdCBpbmNyZW1lbnRzIG9mIDEwDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA5OTksIGJ5ID0gMTApKSArDQogICAgDQogICAgIyBBZGQgdGV4dCBsYWJlbHMgZm9yIHNraWxsIGxldmVscyB3aXRoIG1hdGNoaW5nIGNvbG9ycw0KICAgIGdlb21fdGV4dChhZXMoeCA9IG1heChCb2R5d2VpZ2h0KSwgeSA9IG1pbihgQ2F0LiBJYCksIGxhYmVsID0gIiIpLCBjb2xvciA9ICJkaW1ncmF5Iiwgdmp1c3QgPSAtMSkgKw0KICAgIGdlb21fdGV4dChhZXMoeCA9IG1heChCb2R5d2VpZ2h0KSwgeSA9IG1heChgQ2F0LiBJYCksIGxhYmVsID0gIkNhdC4gSSIpLCBjb2xvciA9ICJkYXJrYmx1ZSIsIHZqdXN0ID0gLTEpICsNCiAgICBnZW9tX3RleHQoYWVzKHggPSBtYXgoQm9keXdlaWdodCksIHkgPSBtYXgoYENhdC4gSUlgKSwgbGFiZWwgPSAiQ2F0LiBJSSIpLCBjb2xvciA9ICJkYXJrZ3JlZW4iLCB2anVzdCA9IC0xKSArDQogICAgZ2VvbV90ZXh0KGFlcyh4ID0gbWF4KEJvZHl3ZWlnaHQpLCB5ID0gbWF4KGBDYXQuIElJSWApLCBsYWJlbCA9ICJDYXQuIElJSSIpLCBjb2xvciA9ICJkYXJrb3JhbmdlIiwgdmp1c3QgPSAtMSkgKw0KICAgIGdlb21fdGV4dChhZXMoeCA9IG1heChCb2R5d2VpZ2h0KSwgeSA9IG1heChgQ2F0LiBJVmApLCBsYWJlbCA9ICJDYXQuIElWIiksIGNvbG9yID0gImRhcmtyZWQiLCB2anVzdCA9IC0xKSArDQogICAgZ2VvbV90ZXh0KGFlcyh4ID0gbWF4KEJvZHl3ZWlnaHQpLCB5ID0gbWF4KGBDYXQuIFZgKSwgbGFiZWwgPSAiQ2F0LiBWIiksIGNvbG9yID0gInB1cnBsZSIsIHZqdXN0ID0gLTEpICsNCiAgICANCiAgICAjIEN1c3RvbWl6ZSB0aGVtZQ0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgdGhlbWUoDQogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTYpLA0KICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEyKSwNCiAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLA0KICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgImNtIikNCiAgICApDQp9DQoNCiMgTGlzdHMgdG8gc3RvcmUgdGhlIHBsb3RzIGFuZCB0YWJsZXMNCnBsb3RzX2xpc3Rfc3RyZW5ndGhfc3RhbmRhcmRzX21hcmtfcmlwcGV0b2UgPC0gbGlzdCgpDQp0YWJsZXNfbGlzdF9zdHJlbmd0aF9zdGFuZGFyZHNfbWFya19yaXBwZXRvZSA8LSBsaXN0KCkNCg0KIyBDaGVjayBhbmQgY3JlYXRlIHRoZSAncGxvdHMnIGRpcmVjdG9yeSBpZiBpdCBkb2Vzbid0IGV4aXN0DQppZiAoIWRpci5leGlzdHMoInBsb3RzIikpIHsNCiAgZGlyLmNyZWF0ZSgicGxvdHMiKQ0KfQ0KDQojIENoZWNrIGFuZCBjcmVhdGUgdGhlICd0YWJsZXMnIGRpcmVjdG9yeSBpZiBpdCBkb2Vzbid0IGV4aXN0DQppZiAoIWRpci5leGlzdHMoInRhYmxlcyIpKSB7DQogIGRpci5jcmVhdGUoInRhYmxlcyIpDQp9DQoNCiMgTG9vcCB0aHJvdWdoIGVhY2ggbmFtZWQgcmFuZ2UgZnJvbSB0aGUgZmlsdGVyZWQgbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCBkYXRhZnJhbWUNCmZvciAoaSBpbiAxOm5yb3cobWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCkpIHsNCiAgc3RyZW5ndGhfc3RhbmRhcmRfbmFtZWRfcmFuZ2UgPC0gbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCRgU3RyZW5ndGggU3RhbmRhcmRgW2ldDQogIGNhdGVnb3J5X25hbWUgPC0gbWFya19yaXBwZXRvZV9zdGFuZGFyZHNfbGlzdCRgQ2F0ZWdvcnkgTmFtZWBbaV0NCiAgDQogICMgTG9hZCB0aGUgZGF0YSBmcm9tIHRoZSBuYW1lZCByYW5nZQ0KICBkYXRhX2ZyYW1lIDwtIHJlYWRXb3JrYm9vayhzdHJlbmd0aF9zdGFuZGFyZHMsIG5hbWVkUmVnaW9uID0gc3RyZW5ndGhfc3RhbmRhcmRfbmFtZWRfcmFuZ2UpDQogIA0KICAjIENoZWNrIGlmIHRoZSAnQm9keXdlaWdodCcgY29sdW1uIGV4aXN0cyBpbiB0aGUgZGF0YSBmcmFtZQ0KICBpZiAoISJCb2R5d2VpZ2h0IiAlaW4lIGNvbG5hbWVzKGRhdGFfZnJhbWUpKSB7DQogICAgY2F0KHBhc3RlKCJTa2lwcGluZyIsIHN0cmVuZ3RoX3N0YW5kYXJkX25hbWVkX3JhbmdlLCAiLSAnQm9keXdlaWdodCcgY29sdW1uIG1pc3NpbmcuXG4iKSkNCiAgICBuZXh0DQogIH0NCg0KICAjIEVuc3VyZSBjb2x1bW4gbmFtZXMgYXJlIHRyaW1tZWQgb2Ygd2hpdGVzcGFjZQ0KICBjb2xuYW1lcyhkYXRhX2ZyYW1lKSA8LSB0cmltd3MoY29sbmFtZXMoZGF0YV9mcmFtZSkpDQoNCiAgIyBSZW5hbWUgY29sdW1ucyB0byByZW1vdmUgZG91YmxlIHBlcmlvZHMgZm9yIGJvdGggdGFibGUgYW5kIHBsb3QNCiAgY29sbmFtZXMoZGF0YV9mcmFtZSkgPC0gZ3N1YigiXFwuXFwuIiwgIi4gIiwgY29sbmFtZXMoZGF0YV9mcmFtZSkpDQoNCiAgIyBGb3JtYXQgdGhlIHRpdGxlIG9mIHRoZSBwbG90IGFuZCBoZWFkIG9mIHRoZSB0YWJsZSB1c2luZyB0aGUgY2xlYW5lZCBjYXRlZ29yeSBuYW1lDQogIGZvcm1hdHRlZF9oZWFkZXIgPC0gZ3N1YigiXyIsICIgIiwgc3RyZW5ndGhfc3RhbmRhcmRfbmFtZWRfcmFuZ2UpDQogIGZvcm1hdHRlZF9oZWFkZXIgPC0gKHN1YigiIFN0ZCAxUk0gQnkgQm9keXdlaWdodCBNYXJrIFJpcHBldG9lIiwgIiBTdGFuZGFyZHMiLCBmb3JtYXR0ZWRfaGVhZGVyKSkNCiAgDQogICMgR2VuZXJhdGUgdGhlIHBsb3QNCiAgcGxvdCA8LSBnZW5lcmF0ZV9nZ3Bsb3QoZGF0YV9mcmFtZSwgY2F0ZWdvcnlfbmFtZSwgc3RyZW5ndGhfc3RhbmRhcmRfbmFtZWRfcmFuZ2UpDQogIA0KICAjIFByaW50IHRoZSBuYW1lIG9mIHRoZSBuYW1lZCByYW5nZSBhcyBhIG1hcmtkb3duIGhlYWRlcg0KICBjYXQocGFzdGUwKCJcblxuPGgzPiAiLCBmb3JtYXR0ZWRfaGVhZGVyLCAiPC9oMz5cbiIpKQ0KDQogICMgUmVuYW1lICdCb2R5d2VpZ2h0JyBjb2x1bW4gdG8gJ0JvZHl3ZWlnaHQgKGxiKScNCiAgbmFtZXMoZGF0YV9mcmFtZSlbbmFtZXMoZGF0YV9mcmFtZSkgPT0gIkJvZHl3ZWlnaHQiXSA8LSAiQm9keXdlaWdodCAobGIpIg0KDQogICMgUHJpbnQgdGhlIHBsb3QNCiAgcHJpbnQocGxvdCkNCg0KICAjIFNhdmUgdGhlIHBsb3QgdG8gdGhlIGxpc3QNCiAgcGxvdHNfbGlzdF9zdHJlbmd0aF9zdGFuZGFyZHNfbWFya19yaXBwZXRvZVtbZm9ybWF0dGVkX2hlYWRlcl1dIDwtIHBsb3QNCg0KICAjIE91dHB1dCB0aGUgZGF0YSBmcmFtZSBhcyBhIG1hcmtkb3duIHRhYmxlIHdpdGggZXZlbiBjb2x1bW4gd2lkdGhzDQogIHByaW50KA0KICAgIHRhYmxlX2h0bWwgPC0ga2FibGUoZGF0YV9mcmFtZSwgZm9ybWF0ID0gImh0bWwiLCBhbGlnbiA9ICdsJykgJT4lDQogICAgICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUUlVFKSAlPiUNCiAgICAgIGNvbHVtbl9zcGVjKDE6bmNvbChkYXRhX2ZyYW1lKSwgd2lkdGggPSBwYXN0ZTAoMTAwIC8gbmNvbChkYXRhX2ZyYW1lKSwgIiUiKSkNCiAgKQ0KICANCiAgIyBTYXZlIHRoZSB0YWJsZSB0byB0aGUgbGlzdA0KICB0YWJsZXNfbGlzdF9zdHJlbmd0aF9zdGFuZGFyZHNfbWFya19yaXBwZXRvZVtbZm9ybWF0dGVkX2hlYWRlcl1dIDwtIHRhYmxlX2h0bWwNCg0KICAjIE9wdGlvbmFsbHkgc2F2ZSB0aGUgcGxvdCBhbmQgdGFibGUNCiAgZ2dzYXZlKGZpbGVuYW1lID0gcGFzdGUwKCJwbG90cy8iLCB0b2xvd2VyKHN0cmVuZ3RoX3N0YW5kYXJkX25hbWVkX3JhbmdlKSwgIi5wbmciKSwgcGxvdCA9IHBsb3QsIHdpZHRoID0gMTIsIGhlaWdodCA9IDgpDQoNCiAgIyBTYXZlIHRoZSBkYXRhIGZyYW1lIGFzIGEgQ1NWIGZpbGUNCiAgd3JpdGUuY3N2KGRhdGFfZnJhbWUsIGZpbGUgPSBwYXN0ZTAoInRhYmxlcy8iLCB0b2xvd2VyKHN0cmVuZ3RoX3N0YW5kYXJkX25hbWVkX3JhbmdlKSwgIi5jc3YiKSwgcm93Lm5hbWVzID0gRkFMU0UpDQp9DQoNCiMgRXhhbXBsZSBvZiBob3cgdG8gcmVjYWxsIGFuZCBwcmludCBhIHNwZWNpZmljIHBsb3QgYW5kIHRhYmxlIGZyb20gdGhlIGxpc3RzDQojIHByaW50KHBsb3RzX2xpc3Rfc3RyZW5ndGhfc3RhbmRhcmRzX21hcmtfcmlwcGV0b2VbWyJNYWxlIEJlbmNoIFByZXNzIFN0ZCAxUk0gQnkgQm9keXdlaWdodCBNYXJrIFJpcHBldG9lIl1dKQ0KIyBwcmludCh0YWJsZXNfbGlzdF9zdHJlbmd0aF9zdGFuZGFyZHNfbWFya19yaXBwZXRvZSkNCiMgcHJpbnQodGFibGVzX2xpc3Rfc3RyZW5ndGhfc3RhbmRhcmRzX21hcmtfcmlwcGV0b2VbIk1hbGUgQmVuY2ggUHJlc3MgU3RkIDFSTSBCeSBCb2R5d2VpZ2h0IE1hcmsgUmlwcGV0b2UiXSkNCiMgY2F0KGFzLmNoYXJhY3Rlcih0YWJsZXNfbGlzdF9zdHJlbmd0aF9zdGFuZGFyZHNfbWFya19yaXBwZXRvZVtbIk1hbGUgQmVuY2ggUHJlc3MgU3RkIDFSTSBCeSBCb2R5d2VpZ2h0IE1hcmsgUmlwcGV0b2UiXV0pKQ0KDQpgYGANCg0KIyBSRUZFUkVOQ0VTIA0KDQoNClteMV06IFRoYW0sIEsuICgyMDI0KS4gKlN0cmVuZ3RoIFN0YW5kYXJkcyAoYHIgU3lzLkRhdGUoKWApLiogUlB1YnMgYnkgUlN0dWRpby4gUmV0cmlldmVkIGZyb20gPGh0dHBzOi8vcnB1YnMuY29tL0tlbkRvZXNEYXRhLz4uDQoNClteMl06IFRoYW0sIEsuICgyMDI0KS4gKktERiAoS0VOIERPRVMgRklUTkVTUykuKiBHb29nbGUgRHJpdmUuIEF2YWlsYWJsZSBhdCA8aHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2RyaXZlL2ZvbGRlcnMvMS00MUZKX2M0MUtqN0thSzBoMWFKNUVCdkVoUHd3SXNpP3VzcD1zaGFyaW5nPg0KDQpbXjNdOiBUaGFtLCBLLiAoMjAyNCkuICpTdHJlbmd0aCBTdGFuZGFyZHMgRmluYWwueGxzbS4qIEtlbiBEb2VzIERhdGEuIFJldHJpZXZlZCBmcm9tIDxodHRwczovLzFkcnYubXMveC9zIUFzWVlaQTluTDhsZjhDSzZrNnJBUDNMU2t2cnk/ZT15bEFSWGk+Lg0KDQpbXjRdOiBSaXBwZXRvZSwgTS4gKDIwMTIpLiAqU3RyZW5ndGggU3RhbmRhcmRzLiogU3RhcnRpbmcgU3RyZW5ndGguIFJldHJpZXZlZCBmcm9tIDxodHRwczovL3N0YXJ0aW5nc3RyZW5ndGguY29tL2ZpbGVzL3N0YW5kYXJkcy5wZGY+Lg0KDQpbXjVdOiBSaXBwZXRvZSwgTS4gKDIwMTcpLiAqU3RhcnRpbmcgU3RyZW5ndGg6IEJhc2ljIEJhcmJlbGwgVHJhaW5pbmcgKDNyZCBlZC4pLiogVGhlIEFhc2dhYXJkIENvbXBhbnkuIFJldHJpZXZlZCBmcm9tIDxodHRwczovL2Fhc2dhYXJkY28uY29tL3N0b3JlL2Jvb2tzLXBvc3RlcnMtZHZkL2Jvb2tzL3N0YXJ0aW5nLXN0cmVuZ3RoLWJhc2ljLWJhcmJlbGwtdHJhaW5pbmcvPi4NCg0KW142XTogTGVnaW9uIEF0aGxldGljcy4gKDIwMTkpLiAqVGhlc2UgQXJlIHRoZSBCZXN0IFN0cmVuZ3RoIFN0YW5kYXJkcyBvbiB0aGUgSW50ZXJuZXQuKiBSZXRyaWV2ZWQgZnJvbSA8aHR0cHM6Ly9sZWdpb25hdGhsZXRpY3MuY29tL3N0cmVuZ3RoLXN0YW5kYXJkcy8+Lg0KDQpbXjddOiBSaXBwZXRvZSwgTS4gKDIwMTIpLiAqVGhlIFN0cmVuZ3RoIFN0YW5kYXJkcyBUYWJsZXMgYXJlIGJhY2sgdXAuKiBTdGFydGluZyBTdHJlbmd0aCBGb3J1bS4gUmV0cmlldmVkIGZyb20gPGh0dHBzOi8vc3RhcnRpbmdzdHJlbmd0aC5jb20vcmVzb3VyY2VzL2ZvcnVtL21hcmstcmlwcGV0b2UtcS1hbmQtYS8zMzAyOS1zdHJlbmd0aC1zdGFuZGFyZHMtdGFibGVzLmh0bWw+Lg0KDQpbXjhdOiBSaXBwZXRvZSwgTS4gKDIwMTcpLiAqU3RhcnRpbmcgU3RyZW5ndGg6IEJhc2ljIEJhcmJlbGwgVHJhaW5pbmcsIDNyZCBFZGl0aW9uKiBieSBNYXJrIFJpcHBldG9lLiBBdmFpbGFibGUgYXQgPGh0dHBzOi8vd3d3LmFtYXpvbi5jb20vU3RhcnRpbmctU3RyZW5ndGgtTWFyay1SaXBwZXRvZS1lYm9vay9kcC9CMDA2WEpSNVpBL3JlZj1zcl8xXzE/Y3JpZD0yMTUyMVlYQktYNEFJJmRpYj1leUoySWpvaU1TSjkuMXFUZWhfOERKaHFEbXhycmFqbWpUYkxpUXotd1BhS09pZmdpNzg3TTdXdXJOeHdVd0tWYmhRYWRKRXc4V2R1MnlnRFA4WDBEMjNZNXhHcUVaQUoyTDVsdUV3MGd2Q0lJeXVUbXVnWVpfYlJtRzM1aHFMUlBsYk95UXg0ZTVwUmYyd1ZvR25zUVB6RlFFZkVPbHJoaUhLcDhCU1dDdVFrZjJSRUxGS1NPTFFPNDlGcThZNTdQVV9NdVBtOWdlOTFVY0MzZWJtQ1o4cENXSG1xYlVVUk42dHlvY0RULUNSM1phUUFLUEpYbm1ZUHNvY0NQNGp6NFlfUVRMRTFoZWNzazhWdXVnZjNISUJqQldrT1ZNWkZtU0RsUzl1alZ4cUY0dlJxQzdHc1ZKbHcuXzlqTnBscGQ5TDZQUEZ6azdXTUMtblNEZldYUGhtY2tGaWlhTVN3YUN5bz4uDQoNClteOV06IFJpcHBldG9lLCBNLiAqUHJhY3RpY2FsIFByb2dyYW1taW5nIGZvciBTdHJlbmd0aCBUcmFpbmluZywgM3JkIEVkaXRpb24qIGJ5IE1hcmsgUmlwcGV0b2UuIEF2YWlsYWJsZSBhdCA8aHR0cHM6Ly93d3cuYW1hem9uLmNvbS9QcmFjdGljYWwtUHJvZ3JhbW1pbmctU3RyZW5ndGgtVHJhaW5pbmctUmlwcGV0b2UtZWJvb2svZHAvQjAwSVU4WUVUVy9yZWY9c3JfMV8yP2NyaWQ9MjE1MjFZWEJLWDRBSSZkaWI9ZXlKMklqb2lNU0o5LjFxVGVoXzhESmhxRG14cnJham1qVGJMaVF6LXdQYUtPaWZnaTc4N003V3VyTnh3VXdLVmJoUWFkSkV3OFdkdTJ5Z0RQOFgwRDIzWTV4R3FFWkFKMkw1bHVFdzBndkNJSXl1VG11Z1laX2JSbUczNWhxTFJQbGJPeVF4NGU1cFJmMndWb0duc1FQekZRRWZFT2xyaGlIS3A4QlNXQ3VRa2YyUkVMRktTT0xRTzQ5RnE4WTU3UFVfTXVQbTlnZTkxVWNDM2VibUNaOHBDV0htcWJVVVJONnR5b2NEVC1DUjNaYVFBS1BKWG5tWVBzb2NDUDRqejRZX1FUTEUxaGVjc2s4VnV1Z2YzSElCakJXa09WTVpGbVNEbFM5dWpWeHFGNHZScUM3R3NWSmx3Ll85ak5wbHBkOUw2UFBGems3V01DLW5TRGZXWFBobWNrRmlpYU1Td2FDeW8+Lg0K