Abstract
Adult obesity prevalence varies across U.S. counties. This study
examines whether county-level geographic differences remain after
accounting for measured behavioral, socioeconomic, food-related, and
environmental characteristics. County-level data are assembled from the
IHME datasets and supporting public data files maintained in the
project’s GitHub repository. The primary outcome is an approximate
county-level adult obesity prevalence measure calculated as the
arithmetic mean of the male and female 2009 IHME county estimates.
Predictors are selected from the available county-level measures of
physical inactivity, alcohol use, educational attainment, unemployment,
household income or wealth, food insecurity, sunlight exposure,
environmental quality, and population.
The analysis uses descriptive statistics, exploratory visualizations,
multiple ordinary least squares regression, and a state fixed-effects
model. Model fit is assessed using adjusted R-squared, root mean squared
error, a nested-model comparison, and regression diagnostics. Because
the data are observational and aggregated at the county level, all
findings are interpreted as associations rather than causal effects. The
final interpretation will focus on the amount of variation explained by
measured county characteristics and whether adding state indicators
provides additional explanatory value.
The numerical findings in this abstract are generated from
the current data when the document is knitted. The outcome
definition and the years represented by each source must be considered
when interpreting the results.
Keywords: adult obesity, county-level analysis,
geographic variation, physical inactivity, socioeconomic factors, state
fixed effects, spatial disparities
1. Introduction
Adult obesity is an important public-health issue in the United
States, and prevalence differs across geographic areas. National and
state summaries can conceal substantial variation among counties.
Counties differ in economic resources, educational attainment,
employment conditions, food security, behavioral patterns, and
environmental characteristics. These differences provide an important
context for examining county-level variation in adult obesity.
Many known characteristics have been associated with obesity,
including physical activity, socioeconomic conditions, and food-related
circumstances. The purpose of this study is not simply to identify
whether these established factors are associated with obesity. Instead,
the central question is whether geographic differences among U.S.
counties remain after accounting for measured county-level
characteristics.
This study combines publicly available county-level data from
multiple sources and uses regression modeling to estimate the
relationship between adult obesity prevalence and selected explanatory
variables. A baseline ordinary least squares (OLS) model is compared
with a model that includes state fixed effects. The comparison evaluates
whether state-level geographic indicators provide additional explanatory
information after adjustment for the measured risk factors.
The analysis is observational. It does not establish that county
location or any individual predictor causes obesity. Because the unit of
analysis is the county, results describe county-level associations and
should not be interpreted as individual-level relationships.
1.1 Importance of the
Study
Understanding geographic differences in obesity may help identify
communities where observed prevalence is higher or lower than expected
given measured county characteristics. If geographic differences remain
after adjustment, this may indicate that additional contextual,
policy-related, healthcare, demographic, or spatially patterned factors
warrant investigation.
The study also demonstrates how data from multiple public sources can
be integrated and analyzed using reproducible statistical methods in R.
The emphasis is on model comparison, effect estimates, uncertainty, and
diagnostic evaluation rather than statistical significance alone.
2. Literature
Review
2.1 Obesity and
Geographic Differences
Public-health research has examined obesity in relation to
behavioral, socioeconomic, and environmental characteristics. A
county-level perspective is useful because counties within the same
state can differ substantially in population composition, economic
conditions, access to resources, and health-related environments. The
present study uses this geographic variation as the focus of its
analysis.
2.2 Behavioral and
Socioeconomic Characteristics
Physical activity is an important behavioral characteristic in the
study of obesity. County-level differences in physical activity may be
associated with differences in obesity prevalence. Economic and
educational characteristics may also be related to community resources,
opportunities, and health conditions. This study therefore considers
physical inactivity, alcohol use, education, unemployment, and household
income or wealth as potential explanatory or control variables.
2.4 Geographic and
Spatial Variation
State fixed effects represent systematic differences among states
that are not captured by the measured explanatory variables. If the
fixed-effects model improves model fit, this suggests that state
membership provides additional explanatory information. State fixed
effects do not, by themselves, identify local spatial dependence between
neighboring counties. A separate spatial-autocorrelation analysis would
be required to assess that question.
2.5 Research
Contribution
The contribution of this study is its focus on the amount of
county-level geographic variation that remains after adjustment for
measured behavioral, socioeconomic, food-related, and environmental
characteristics. The study does not claim that the selected predictors
or the geographic approach are unprecedented. Rather, it applies a
consistent county-level modeling framework to assess the additional
explanatory value of state-level geographic indicators.
3. Research Questions
and Hypotheses
3.1 Primary Research
Question
To what extent do county-level geographic differences in adult
obesity prevalence remain after controlling for known behavioral,
socioeconomic, food-related, and environmental factors?
3.2 Supporting
Research Questions
- How much variation in adult obesity prevalence exists across U.S.
counties before accounting for other county-level characteristics?
- To what extent are measured behavioral, socioeconomic, food-related,
and environmental characteristics associated with county-level adult
obesity prevalence?
- Does adding state fixed effects improve the explanatory performance
of the model after adjustment for the measured characteristics?
- Do residual diagnostics indicate important departures from the
assumptions of the OLS regression model?
3.3 Hypotheses
- H1: County-level adult obesity prevalence varies
across U.S. counties.
- H2: The selected behavioral, socioeconomic,
food-related, and environmental characteristics jointly explain a
statistically meaningful portion of the variation in county-level adult
obesity prevalence.
- H3: Adding state fixed effects improves model fit
beyond the baseline model containing measured county-level
characteristics.
- H4: After adjustment, residuals may still exhibit
patterns that indicate unexplained county-level variation. This
hypothesis will be evaluated descriptively; state fixed effects alone
are not a test of neighboring-county spatial autocorrelation.
4. Data and
Variables
4.1 Data Sources
The project repository contains the county-level source files used
for this analysis. The files are read directly from the public GitHub
repository so the analysis can be reproduced. The principal sources
identified in the approved proposal include the Institute for Health
Metrics and Evaluation (IHME), U.S. government datasets, the U.S.
Environmental Protection Agency, Feeding America, and CDC environmental
data.
The data files include:
IHME_Obesity.csv
IHME_PhysicalActivity.csv
AlcoholConsumption.csv
Education.csv
Unemployment.csv
Wealth.csv
FoodInsecurity.csv
Sunlight.csv
EnvironmentalQualityIndex.csv
population.csv
The analysis uses only variables that can be identified and merged
reliably from the available source files. The code below prints the
selected source columns and reports any optional measure that is not
found. Missing variables are not silently replaced with unrelated
measures.
4.2 Outcome
Variable
The IHME obesity file contains separate male and female county
prevalence estimates for 2009. For this analysis, the primary outcome is
defined as the arithmetic mean of those two estimates:
\[
\text{Adult Obesity}_{i} =
\frac{\text{Male Obesity}_{i,2009}+
\text{Female Obesity}_{i,2009}}{2}
\]
This is an approximation, not a population-weighted combined
prevalence estimate. A population-weighted overall estimate would
require county-level male and female population weights that are aligned
to the same year and definition. The outcome is expressed in percentage
points.
4.3 Explanatory
Variables
| Physical inactivity |
Behavioral |
100 minus the average male/female sufficient physical
activity prevalence, where available |
| Alcohol use |
Behavioral |
County-level alcohol-use measure supplied in the
project repository |
| Educational attainment |
Socioeconomic |
County-level college or bachelor’s attainment
measure |
| Unemployment |
Socioeconomic |
County unemployment rate |
| Household income / wealth |
Socioeconomic |
County-level income or wealth measure |
| Food insecurity |
Food-related |
County-level food-insecurity measure |
| Sunlight exposure |
Environmental |
Average daily sunlight, where available |
| Environmental quality |
Environmental |
Environmental Quality Index, where available |
| Population |
Contextual |
County population; considered as log population in a
sensitivity specification |
| State |
Geographic |
State indicator used for fixed effects |
4.4 Geographic Data
Integration
County records are matched using standardized state and county names.
The original proposal described the use of five-digit FIPS codes. The
current repository files do not all expose a consistently named FIPS
field, so this version uses a normalized state-plus-county key. This
approach avoids matching counties with the same name in different
states, but it is not equivalent to a verified FIPS join. The merge
diagnostics below report unmatched records and should be reviewed before
the results are finalized.
repo_base <- "https://raw.githubusercontent.com/BIKASHBHOWMIK15/Data-698/main/"
read_project_csv <- function(filename) {
url <- paste0(repo_base, filename)
tryCatch(
readr::read_csv(url, show_col_types = FALSE, name_repair = "unique"),
error = function(e) {
stop("Could not read ", filename, ". Check the repository filename and internet connection. Details: ",
conditionMessage(e))
}
)
}
normalize_state <- function(x) {
x <- stringr::str_squish(as.character(x))
x <- stringr::str_replace_all(x, "\\.", "")
abbr <- match(toupper(x), state.abb)
x[!is.na(abbr)] <- state.name[abbr[!is.na(abbr)]]
dplyr::case_when(
toupper(x) %in% c("DC", "DISTRICT OF COLUMBIA") ~ "District of Columbia",
TRUE ~ stringr::str_to_title(x)
)
}
normalize_county <- function(x) {
x <- as.character(x)
x <- stringi::stri_trans_general(x, "Latin-ASCII")
x <- stringr::str_to_lower(x)
x <- stringr::str_replace(x, ",.*$", "")
x <- stringr::str_remove(x, "\\s+(county|parish|borough|census area|municipality)$")
x <- stringr::str_replace_all(x, "[^a-z0-9]", "")
x
}
find_column <- function(data, patterns, required = TRUE, label = "variable") {
nm <- names(data)
hits <- unique(unlist(lapply(patterns, function(p) {
which(stringr::str_detect(nm, stringr::regex(p, ignore_case = TRUE)))
})))
if (length(hits) == 0) {
if (required) {
stop("Could not identify ", label, ". Available columns: ",
paste(nm, collapse = " | "))
}
return(NA_character_)
}
nm[hits[1]]
}
standardize_geo <- function(data, source_name = "dataset") {
original_names <- names(data)
# Normalize column names: remove spaces, underscores,
# punctuation, and convert to lowercase
normalized_names <- tolower(
gsub("[^a-zA-Z0-9]", "", original_names)
)
# Identify state column
state_idx <- which(
normalized_names %in% c("state", "stabr", "statename", "stname")
)[1]
# Identify county column
county_idx <- which(
normalized_names %in% c(
"county",
"location",
"areaname",
"countyname",
"countystate",
"ctyname"
)
)[1]
if (is.na(state_idx)) {
stop(
paste0(
"Could not identify state column in ",
source_name,
". Available columns: ",
paste(original_names, collapse = " | ")
)
)
}
if (is.na(county_idx)) {
stop(
paste0(
"Could not identify county column in ",
source_name,
". Available columns: ",
paste(original_names, collapse = " | ")
)
)
}
state_original <- original_names[state_idx]
county_original <- original_names[county_idx]
data %>%
mutate(
State = stringr::str_squish(as.character(.data[[state_original]])),
County = stringr::str_squish(as.character(.data[[county_original]]))
) %>%
mutate(
County_key = paste(
normalize_state(State),
normalize_county(County),
sep = "|"
)
)
}
numeric_value <- function(x) {
readr::parse_number(as.character(x), na = c("", "NA", "N/A", "-", "—"))
}
make_one_variable <- function(filename, output_name, patterns,
required = FALSE, transform = identity) {
raw <- read_project_csv(filename)
geo <- standardize_geo(raw, filename)
value_col <- find_column(
geo, patterns, required = required,
label = paste(output_name, "in", filename)
)
if (is.na(value_col)) {
message("Optional variable not found; omitted: ", output_name,
" (", filename, ")")
return(NULL)
}
message("Mapped ", output_name, " from ", filename, " column: ", value_col)
geo %>%
transmute(
State, County_key,
!!output_name := transform(numeric_value(.data[[value_col]]))
) %>%
distinct(State, County_key, .keep_all = TRUE)
}
4.5 Constructing the
County-Level Analytical Dataset
# Outcome: average of the male and female 2009 obesity estimates.
obesity_raw <- read_project_csv("IHME_Obesity.csv")
obesity_geo <- standardize_geo(obesity_raw, "IHME_Obesity.csv")
male_obesity_col <- find_column(
obesity_geo, "^Male obesity prevalence, 2009",
label = "male 2009 obesity prevalence"
)
female_obesity_col <- find_column(
obesity_geo, "^Female\\s+obesity\\s+prevalence,\\s*2009",
label = "female 2009 obesity prevalence"
)
obesity_data <- obesity_geo %>%
transmute(
State, County_key,
male_obesity_2009 = numeric_value(.data[[male_obesity_col]]),
female_obesity_2009 = numeric_value(.data[[female_obesity_col]]),
adult_obesity = rowMeans(
cbind(
numeric_value(.data[[male_obesity_col]]),
numeric_value(.data[[female_obesity_col]])
),
na.rm = TRUE
)
) %>%
mutate(
adult_obesity = ifelse(is.nan(adult_obesity), NA_real_, adult_obesity)
) %>%
distinct(State, County_key, .keep_all = TRUE)
# Physical inactivity: complement of sufficient physical activity prevalence.
activity_raw <- read_project_csv("IHME_PhysicalActivity.csv")
activity_geo <- standardize_geo(activity_raw, "IHME_PhysicalActivity.csv")
male_activity_col <- find_column(
activity_geo,
"^Male\\s+sufficient\\s+physical\\s+activity\\s+prevalence,\\s*2009",
label = "male 2009 sufficient physical activity"
)
female_activity_col <- find_column(
activity_geo,
"^Female\\s+sufficient\\s+physical\\s+activity\\s+prevalence,\\s*2009",
label = "female 2009 sufficient physical activity"
)
activity_data <- activity_geo %>%
transmute(
State, County_key,
physical_inactivity = 100 - rowMeans(
cbind(
numeric_value(.data[[male_activity_col]]),
numeric_value(.data[[female_activity_col]])
),
na.rm = TRUE
)
) %>%
mutate(
physical_inactivity = ifelse(
is.nan(physical_inactivity), NA_real_, physical_inactivity
)
) %>%
distinct(State, County_key, .keep_all = TRUE)
# Additional candidate measures. A source variable is included only when a
# corresponding county-level column can be identified.
optional_sources <- list(
make_one_variable(
"AlcoholConsumption.csv", "alcohol_use",
c("^Hvy$", "heavy.*(prevalence|rate)", "heavy drinking")
),
make_one_variable(
"Education.csv", "college_education",
c("^College$", "bachelor", "college.*percent", "college.*rate")
),
make_one_variable(
"Unemployment.csv", "unemployment",
c("^Unemployment_rate_2019$", "^Unemployment$", "unemployment.*2019")
),
make_one_variable(
"Wealth.csv", "median_income",
c("^Income$", "median household income", "median.*income", "wealth")
),
make_one_variable(
"FoodInsecurity.csv", "food_insecurity",
c("^FoodInsecurity$", "food insecurity.*(rate|percent|pct)?",
"food insecurity")
),
make_one_variable(
"Sunlight.csv", "sunlight",
c("^Sun$", "Avg Daily Sunlight", "average_daily_sunlight",
"average daily sunlight")
),
make_one_variable(
"EnvironmentalQualityIndex.csv", "environmental_quality",
c("^EQI$", "environmental quality index")
),
make_one_variable(
"population.csv", "population",
c("^Population$", "POPESTIMATE2019", "population.*2019")
)
)
optional_sources <- optional_sources[!vapply(optional_sources, is.null, logical(1))]
analysis_data <- obesity_data %>%
left_join(activity_data, by = c("State", "County_key"))
for (source_data in optional_sources) {
analysis_data <- analysis_data %>%
left_join(source_data, by = c("State", "County_key"))
}
analysis_data <- analysis_data %>%
mutate(
log_population = if ("population" %in% names(.)) {
ifelse(population > 0, log(population), NA_real_)
} else {
NA_real_
}
)
# Keep counties with a valid outcome.
analysis_data <- analysis_data %>%
filter(is.finite(adult_obesity))
# Merge diagnostics.
merge_summary <- tibble(
Measure = c(
"Counties with obesity outcome",
"Counties with physical inactivity",
"Counties with missing physical inactivity"
),
Count = c(
nrow(analysis_data),
sum(!is.na(analysis_data$physical_inactivity)),
sum(is.na(analysis_data$physical_inactivity))
)
)
knitr::kable(
merge_summary,
caption = "County-level data availability after merging"
) %>%
kableExtra::kable_styling(full_width = FALSE)
County-level data availability after merging
|
Measure
|
Count
|
|
Counties with obesity outcome
|
3194
|
|
Counties with physical inactivity
|
3194
|
|
Counties with missing physical inactivity
|
0
|
# Show available variables and their missingness.
missingness_table <- tibble(
Variable = names(analysis_data),
Non_Missing = vapply(analysis_data, function(x) sum(!is.na(x)), integer(1)),
Missing = vapply(analysis_data, function(x) sum(is.na(x)), integer(1))
)
knitr::kable(
missingness_table,
caption = "Missing-value summary for the merged analytical dataset"
) %>%
kableExtra::kable_styling(full_width = FALSE)
Missing-value summary for the merged analytical dataset
|
Variable
|
Non_Missing
|
Missing
|
|
State
|
3194
|
0
|
|
County_key
|
3194
|
0
|
|
male_obesity_2009
|
3194
|
0
|
|
female_obesity_2009
|
3194
|
0
|
|
adult_obesity
|
3194
|
0
|
|
physical_inactivity
|
3194
|
0
|
|
college_education
|
0
|
3194
|
|
unemployment
|
0
|
3194
|
|
median_income
|
0
|
3194
|
|
food_insecurity
|
0
|
3194
|
|
sunlight
|
3153
|
41
|
|
population
|
3135
|
59
|
|
log_population
|
3135
|
59
|
4.6 Data Quality and
Analysis Sample
The number of counties available for each measure may differ because
the source datasets may have different geographic coverage and missing
values. The regression sample is therefore defined by the observations
with complete data for the outcome and the predictors included in the
final model. The final paper should report this sample size and should
not imply that every model uses all U.S. counties.
summary(analysis_data$adult_obesity)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 18.00 34.70 36.85 36.94 39.40 52.25
county_counts <- analysis_data %>%
summarise(
counties = n(),
states = n_distinct(State),
mean_obesity = mean(adult_obesity, na.rm = TRUE),
sd_obesity = sd(adult_obesity, na.rm = TRUE),
min_obesity = min(adult_obesity, na.rm = TRUE),
median_obesity = median(adult_obesity, na.rm = TRUE),
max_obesity = max(adult_obesity, na.rm = TRUE)
)
knitr::kable(
county_counts,
digits = 2,
caption = "Summary of the county-level obesity outcome"
) %>%
kableExtra::kable_styling(full_width = FALSE)
Summary of the county-level obesity outcome
|
counties
|
states
|
mean_obesity
|
sd_obesity
|
min_obesity
|
median_obesity
|
max_obesity
|
|
3194
|
52
|
36.94
|
4.28
|
18
|
36.85
|
52.25
|
5. Methodology
5.1 Exploratory Data
Analysis
Exploratory data analysis is used to describe the distribution of
adult obesity prevalence and examine the relationships among the outcome
and available explanatory variables. Descriptive statistics and
visualizations are reviewed before fitting regression models.
ggplot(analysis_data, aes(x = adult_obesity)) +
geom_histogram(bins = 30, color = "white") +
labs(
title = "Distribution of County-Level Adult Obesity Prevalence",
x = "Adult obesity prevalence (%)",
y = "Number of counties"
) +
theme_minimal()

state_summary <- analysis_data %>%
group_by(State) %>%
summarise(
counties = n(),
mean_obesity = mean(adult_obesity, na.rm = TRUE),
median_obesity = median(adult_obesity, na.rm = TRUE),
.groups = "drop"
) %>%
arrange(desc(mean_obesity))
knitr::kable(
head(state_summary, 15),
digits = 2,
caption = "States with the highest mean county-level obesity prevalence (top 15)"
) %>%
kableExtra::kable_styling(full_width = FALSE)
States with the highest mean county-level obesity prevalence (top 15)
|
State
|
counties
|
mean_obesity
|
median_obesity
|
|
Mississippi
|
83
|
42.44
|
42.10
|
|
Louisiana
|
65
|
41.58
|
41.85
|
|
Alabama
|
68
|
41.05
|
40.40
|
|
South Carolina
|
47
|
40.23
|
39.70
|
|
Georgia
|
160
|
39.94
|
40.58
|
|
Kentucky
|
121
|
39.35
|
39.00
|
|
Arkansas
|
76
|
39.19
|
38.38
|
|
West Virginia
|
56
|
39.15
|
38.70
|
|
Tennessee
|
96
|
38.72
|
39.02
|
|
Oklahoma
|
78
|
38.56
|
38.40
|
|
Texas
|
255
|
38.25
|
38.30
|
|
North Carolina
|
101
|
37.96
|
37.10
|
|
Ohio
|
89
|
37.93
|
37.95
|
|
Missouri
|
116
|
37.88
|
37.68
|
|
Delaware
|
4
|
37.56
|
37.15
|
library(dplyr)
library(ggplot2)
state_extremes <- bind_rows(
state_summary %>%
slice_max(mean_obesity, n = 10) %>%
mutate(Group = "Highest"),
state_summary %>%
slice_min(mean_obesity, n = 10) %>%
mutate(Group = "Lowest")
) %>%
arrange(mean_obesity) %>%
mutate(State = factor(State, levels = State))
ggplot(state_extremes,
aes(x = State, y = mean_obesity, fill = Group)) +
geom_col(width = 0.7) +
coord_flip() +
labs(
title = "States with the Highest and Lowest Mean County Obesity",
x = NULL,
y = "Mean county obesity prevalence (%)",
fill = "State group"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold"),
legend.position = "bottom"
)

5.2 Correlation
Analysis
Pearson correlations are used as an exploratory measure of linear
association among numeric variables. Correlation does not establish
causation and does not account for other variables in the model.
numeric_data <- analysis_data %>%
select(where(is.numeric)) %>%
select(where(~ sum(!is.na(.x)) > 10))
correlation_matrix <- cor(
numeric_data,
use = "pairwise.complete.obs"
)
corrplot_available <- requireNamespace("corrplot", quietly = TRUE)
if (corrplot_available) {
corrplot::corrplot(
correlation_matrix,
method = "color",
type = "upper",
tl.col = "black",
tl.cex = 0.75,
addCoef.col = "black",
number.cex = 0.5
)
} else {
knitr::kable(
round(correlation_matrix, 2),
caption = "Pearson correlation matrix"
)
}

5.3 Multiple Linear
Regression
The baseline model uses adult obesity prevalence as the dependent
variable and the available county-level explanatory variables as
predictors. The model is specified using the predictors that are
successfully identified in the repository and have sufficient
non-missing observations.
The general model is:
\[
Obesity_i = \beta_0 + \sum_{k=1}^{K}\beta_k X_{ki} + \epsilon_i
\]
where \(Obesity_i\) is the adult
obesity prevalence measure for county \(i\), \(X_{ki}\) represents the measured
county-level characteristics, and \(\epsilon_i\) is the error term.
candidate_predictors <- c(
"physical_inactivity",
"alcohol_use",
"college_education",
"unemployment",
"median_income",
"food_insecurity",
"sunlight",
"environmental_quality",
"population"
)
# Identify predictors available in the dataset
existing_predictors <- intersect(
candidate_predictors,
names(analysis_data)
)
# Check predictor quality
predictor_diagnostics <- purrr::map_dfr(
existing_predictors,
function(v) {
x <- analysis_data[[v]]
tibble(
Variable = v,
Non_Missing = sum(!is.na(x)),
Distinct_Values = dplyr::n_distinct(x, na.rm = TRUE),
Data_Type = class(x)[1]
)
}
)
knitr::kable(
predictor_diagnostics,
caption = "Regression predictor diagnostics"
) %>%
kableExtra::kable_styling(full_width = FALSE)
Regression predictor diagnostics
|
Variable
|
Non_Missing
|
Distinct_Values
|
Data_Type
|
|
physical_inactivity
|
3194
|
756
|
numeric
|
|
college_education
|
0
|
0
|
numeric
|
|
unemployment
|
0
|
0
|
numeric
|
|
median_income
|
0
|
0
|
numeric
|
|
food_insecurity
|
0
|
0
|
numeric
|
|
sunlight
|
3153
|
3141
|
numeric
|
|
population
|
3135
|
3081
|
numeric
|
# Select usable numerical predictors
available_predictors <- predictor_diagnostics %>%
filter(
Non_Missing >= 100,
Distinct_Values > 1,
Data_Type %in% c("numeric", "integer")
) %>%
pull(Variable)
cat("Usable predictors:",
paste(available_predictors, collapse = ", "))
## Usable predictors: physical_inactivity, sunlight, population
if (length(available_predictors) < 3) {
stop(
"Fewer than three usable predictors. ",
"Review the diagnostic table before continuing."
)
}
# Create complete-case regression dataset
model_variables <- c(
"adult_obesity",
"State",
"County_key",
available_predictors
)
model_data <- analysis_data %>%
select(all_of(model_variables)) %>%
drop_na() %>%
mutate(State = factor(State))
if (nrow(model_data) < 100) {
stop("Regression sample contains fewer than 100 counties.")
}
# Baseline OLS model
baseline_formula <- as.formula(
paste(
"adult_obesity ~",
paste(available_predictors, collapse = " + ")
)
)
model_ols <- lm(
baseline_formula,
data = model_data
)
# State fixed-effects model
state_formula <- as.formula(
paste(
"adult_obesity ~",
paste(available_predictors, collapse = " + "),
"+ State"
)
)
model_state <- lm(
state_formula,
data = model_data
)
cat("\nRegression sample:",
nrow(model_data), "counties")
##
## Regression sample: 3101 counties
cat("\nStates represented:",
n_distinct(model_data$State))
##
## States represented: 49
cat("\nBaseline adjusted R-squared:",
round(summary(model_ols)$adj.r.squared, 4))
##
## Baseline adjusted R-squared: 0.707
cat("\nState model adjusted R-squared:",
round(summary(model_state)$adj.r.squared, 4))
##
## State model adjusted R-squared: 0.7971
5.4 State
Fixed-Effects Model
The geographic model adds state indicators to the baseline
regression:
\[
Obesity_{is} = \beta_0 + \sum_{k=1}^{K}\beta_k X_{kis} + \gamma_s +
\epsilon_{is}
\]
where \(\gamma_s\) represents the
state fixed effect. One state is treated as the reference category by
the regression software.
The state fixed-effects model tests whether state membership adds
explanatory information after adjustment for the measured county-level
variables. It does not establish that state location causes differences
in obesity prevalence.
5.5 Model
Evaluation
The models are compared using adjusted R-squared and RMSE. A
nested-model F-test evaluates whether the state indicators collectively
improve the in-sample fit. These measures describe explanatory
performance in the analysis sample and should not be confused with
out-of-sample predictive validation.
rmse <- function(model) {
sqrt(mean(residuals(model)^2))
}
model_comparison <- tibble(
Model = c("Baseline OLS", "OLS with state fixed effects"),
Observations = c(nobs(model_ols), nobs(model_state)),
R_Squared = c(summary(model_ols)$r.squared,
summary(model_state)$r.squared),
Adjusted_R_Squared = c(summary(model_ols)$adj.r.squared,
summary(model_state)$adj.r.squared),
RMSE = c(rmse(model_ols), rmse(model_state))
)
knitr::kable(
model_comparison,
digits = 4,
caption = "Comparison of baseline and state fixed-effects models"
) %>%
kableExtra::kable_styling(full_width = FALSE)
Comparison of baseline and state fixed-effects models
|
Model
|
Observations
|
R_Squared
|
Adjusted_R_Squared
|
RMSE
|
|
Baseline OLS
|
3101
|
0.7073
|
0.7070
|
2.3016
|
|
OLS with state fixed effects
|
3101
|
0.8004
|
0.7971
|
1.9003
|
state_model_test <- anova(model_ols, model_state)
knitr::kable(
broom::tidy(state_model_test),
digits = 4,
caption = "Nested-model F-test: additional contribution of state fixed effects"
) %>%
kableExtra::kable_styling(full_width = FALSE)
Nested-model F-test: additional contribution of state fixed effects
|
term
|
df.residual
|
rss
|
df
|
sumsq
|
statistic
|
p.value
|
|
adult_obesity ~ physical_inactivity + sunlight + population
|
3097
|
16427.01
|
NA
|
NA
|
NA
|
NA
|
|
adult_obesity ~ physical_inactivity + sunlight + population + State
|
3049
|
11197.89
|
48
|
5229.118
|
29.6625
|
0
|
5.6 Regression
Coefficients and Uncertainty
The coefficients are interpreted as adjusted county-level
associations. A coefficient represents the estimated difference in adult
obesity prevalence associated with a one-unit difference in a predictor,
holding the other included variables constant. Units must be considered
when interpreting the size of each coefficient.
Heteroscedasticity-consistent standard errors (HC3) are reported as a
robustness measure.
robust_results <- lmtest::coeftest(
model_state,
vcov. = sandwich::vcovHC(model_state, type = "HC3")
)
coefficient_table <- broom::tidy(robust_results) %>%
rename(
Estimate = estimate,
Std_Error_HC3 = std.error,
t_value = statistic,
p_value = p.value
) %>%
mutate(
CI_Lower = Estimate - qt(0.975, df.residual(model_state)) * Std_Error_HC3,
CI_Upper = Estimate + qt(0.975, df.residual(model_state)) * Std_Error_HC3
)
knitr::kable(
coefficient_table,
digits = 4,
caption = "State fixed-effects regression coefficients with HC3 robust standard errors"
) %>%
kableExtra::kable_styling(full_width = FALSE, font_size = 11)
State fixed-effects regression coefficients with HC3 robust standard
errors
|
term
|
Estimate
|
Std_Error_HC3
|
t_value
|
p_value
|
CI_Lower
|
CI_Upper
|
|
(Intercept)
|
-1.8414
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
physical_inactivity
|
0.6658
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
sunlight
|
0.0003
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
population
|
0.0000
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateArizona
|
2.0828
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateArkansas
|
0.4114
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateCalifornia
|
2.1268
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateColorado
|
-0.3809
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateConnecticut
|
-0.0820
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateDelaware
|
3.0589
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateDistrict of Columbia
|
-1.0196
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateFlorida
|
0.6223
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateGeorgia
|
1.2014
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateIdaho
|
3.0474
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateIllinois
|
2.3759
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateIndiana
|
1.2373
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateIowa
|
2.1367
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateKansas
|
1.8379
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateKentucky
|
-0.2502
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateLouisiana
|
0.6253
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateMaine
|
4.3100
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateMaryland
|
2.9480
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateMassachusetts
|
-0.3727
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateMichigan
|
5.4586
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateMinnesota
|
3.0931
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateMississippi
|
0.2031
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateMissouri
|
1.8512
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateMontana
|
2.4744
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateNebraska
|
2.8708
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateNevada
|
1.7372
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateNew Hampshire
|
3.9369
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateNew Jersey
|
-0.6874
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateNew Mexico
|
0.2666
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateNew York
|
2.4980
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateNorth Carolina
|
0.9091
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateNorth Dakota
|
2.5510
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateOhio
|
3.0466
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateOklahoma
|
1.0174
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateOregon
|
5.5529
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StatePennsylvania
|
3.3849
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateRhode Island
|
-1.4941
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateSouth Carolina
|
2.8095
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateSouth Dakota
|
2.4899
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateTennessee
|
-2.7053
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateTexas
|
0.6439
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateUtah
|
1.7079
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateVermont
|
3.0854
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateVirginia
|
1.2315
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateWashington
|
5.9157
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateWest Virginia
|
0.2676
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateWisconsin
|
4.9081
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
|
StateWyoming
|
1.9160
|
NaN
|
NaN
|
NaN
|
NaN
|
NaN
|
5.7 Regression
Diagnostics
Regression diagnostics are used to evaluate whether the fitted models
show important departures from the assumptions of linear regression. The
analysis examines residual patterns, approximate normality,
heteroscedasticity, and multicollinearity. Statistical significance
should be interpreted cautiously because counties may not be
statistically independent.
old_par <- par(no.readonly = TRUE)
par(mfrow = c(2, 2))
plot(model_state)

vif_values <- tryCatch(
car::vif(model_state),
error = function(e) NULL
)
if (!is.null(vif_values)) {
if (is.matrix(vif_values)) {
vif_output <- as.data.frame(vif_values) %>%
tibble::rownames_to_column("Variable")
} else {
vif_output <- tibble(
Variable = names(vif_values),
VIF = as.numeric(vif_values)
)
}
knitr::kable(
vif_output,
digits = 3,
caption = "Variance inflation factor diagnostics"
) %>%
kableExtra::kable_styling(full_width = FALSE)
} else {
cat("VIF could not be calculated for this model specification.")
}
Variance inflation factor diagnostics
|
Variable
|
GVIF
|
Df
|
GVIF^(1/(2*Df))
|
|
physical_inactivity
|
2.512
|
1
|
1.585
|
|
sunlight
|
12.270
|
1
|
3.503
|
|
population
|
1.096
|
1
|
1.047
|
|
State
|
29.607
|
48
|
1.036
|
5.8 Residual
Geographic Variation
A residual is the difference between observed and model-predicted
obesity prevalence:
\[
Residual_i = Observed_i - Predicted_i
\]
Positive residuals indicate that the observed county prevalence is
higher than the model predicts. Negative residuals indicate that
observed prevalence is lower than predicted. Residuals are examined to
identify counties with larger deviations from the model.
model_data <- model_data %>%
mutate(
fitted_obesity = fitted(model_state),
residual = residuals(model_state),
absolute_residual = abs(residual)
)
residual_summary <- model_data %>%
summarise(
Mean_residual = mean(residual),
SD_residual = sd(residual),
Mean_absolute_residual = mean(absolute_residual),
Minimum_residual = min(residual),
Maximum_residual = max(residual)
)
knitr::kable(
residual_summary,
digits = 3,
caption = "Summary of residuals from the state fixed-effects model"
) %>%
kableExtra::kable_styling(full_width = FALSE)
Summary of residuals from the state fixed-effects model
|
Mean_residual
|
SD_residual
|
Mean_absolute_residual
|
Minimum_residual
|
Maximum_residual
|
|
0
|
1.901
|
1.448
|
-10.788
|
7.618
|
ggplot(model_data, aes(x = fitted_obesity, y = residual)) +
geom_point(alpha = 0.45) +
geom_hline(yintercept = 0, linetype = "dashed") +
labs(
title = "Residuals Versus Fitted Values",
x = "Predicted adult obesity prevalence (%)",
y = "Residual (percentage points)"
) +
theme_minimal()

largest_residuals <- model_data %>%
mutate(County = analysis_data$County_key[match(
paste(State, County_key), paste(analysis_data$State, analysis_data$County_key)
)]) %>%
arrange(desc(absolute_residual)) %>%
select(State, County, adult_obesity, fitted_obesity, residual) %>%
slice_head(n = 15)
knitr::kable(
largest_residuals,
digits = 2,
caption = "Counties with the largest absolute model residuals"
) %>%
kableExtra::kable_styling(full_width = FALSE)
Counties with the largest absolute model residuals
|
State
|
County
|
adult_obesity
|
fitted_obesity
|
residual
|
|
Virginia
|
Virginia|fallschurchcity
|
18.00
|
28.79
|
-10.79
|
|
Pennsylvania
|
Pennsylvania|montour
|
27.10
|
37.47
|
-10.37
|
|
California
|
California|sanfrancisco
|
19.00
|
29.17
|
-10.17
|
|
New York
|
New York|richmond
|
28.95
|
38.38
|
-9.43
|
|
Virginia
|
Virginia|fairfaxcity
|
22.70
|
31.66
|
-8.96
|
|
New York
|
New York|queens
|
29.10
|
37.39
|
-8.29
|
|
New York
|
New York|nassau
|
28.70
|
36.53
|
-7.83
|
|
Virginia
|
Virginia|portsmouthcity
|
45.35
|
37.73
|
7.62
|
|
Alabama
|
Alabama|marion
|
37.70
|
45.28
|
-7.58
|
|
North Carolina
|
North Carolina|orange
|
23.45
|
30.89
|
-7.44
|
|
Maryland
|
Maryland|montgomery
|
24.40
|
31.65
|
-7.25
|
|
New Mexico
|
New Mexico|mckinley
|
41.70
|
34.63
|
7.07
|
|
New York
|
New York|westchester
|
25.50
|
32.44
|
-6.94
|
|
New York
|
New York|kings
|
32.05
|
38.80
|
-6.75
|
|
North Carolina
|
North Carolina|ashe
|
32.30
|
38.83
|
-6.53
|
6. Results
6.1 County-Level
Variation in Adult Obesity
The descriptive analysis reports the distribution of the county-level
adult obesity outcome. The final interpretation should describe the
range, central tendency, and variability shown in the generated summary
and histogram.
The analysis includes 3194 counties with an
available outcome measure. The mean county-level adult obesity
prevalence is 36.94%, and the standard deviation is
4.28 percentage points.
6.2 Regression
Results
The baseline OLS model has an adjusted R-squared of
0.707. The state fixed-effects model has an adjusted
R-squared of 0.797. The corresponding RMSE values are
2.302 and 1.9 percentage points,
respectively.
The nested-model F-test evaluates whether adding the state indicators
improves model fit. Its result should be interpreted together with the
change in adjusted R-squared and RMSE, rather than relying only on the
p-value.
6.3 Geographic
Differences After Adjustment
The state fixed-effects model evaluates whether state indicators
collectively explain additional variation after accounting for the
measured county characteristics. A statistically significant
nested-model test would indicate that state indicators add explanatory
information in this sample. It would not demonstrate that every state
differs from every other state, nor would it identify the specific local
mechanisms responsible for the differences.
The residual analysis identifies counties where observed prevalence
differs most from model predictions. These residual differences may
reflect unmeasured county characteristics, measurement error,
differences in source years, model misspecification, or spatially
patterned factors.
6.4 Model
Diagnostics
The diagnostic plots and VIF results should be reviewed before final
interpretation. Potential issues include nonlinearity,
heteroscedasticity, influential observations, and multicollinearity. HC3
robust standard errors help address heteroscedasticity in coefficient
uncertainty estimates, but they do not correct spatial dependence
between neighboring counties.
7. Discussion
The purpose of this study is to determine whether geographic
differences in adult obesity prevalence remain after controlling for
measured county-level characteristics. The comparison between the
baseline OLS model and the state fixed-effects model provides the
primary evidence for evaluating the research question.
Complete this discussion after reviewing the knitted
results. Specifically, explain:
- Whether the county-level obesity outcome shows substantial
variation.
- Which measured predictors have the largest estimated associations,
including their direction, units, and confidence intervals.
- Whether the state fixed-effects model improves adjusted R-squared
and RMSE.
- Whether the nested-model F-test supports the conclusion that state
indicators add explanatory information.
- What the residual diagnostics suggest about unexplained county-level
differences.
The findings should be compared with the literature reviewed in
Section 2. Avoid describing an association as a causal effect. A
statistically significant coefficient does not necessarily indicate a
large or practically important association.
8. Limitations
Several limitations should be considered when interpreting the
findings.
First, the study uses aggregated county-level data. County-level
associations cannot automatically be generalized to individuals; doing
so would risk an ecological fallacy.
Second, the outcome is calculated as the arithmetic mean of male and
female IHME 2009 obesity estimates. It is not a population-weighted
overall prevalence estimate. This definition should be kept explicit
throughout the paper.
Third, the source datasets may represent different years. Differences
in the timing of obesity, physical activity, socioeconomic,
food-related, and environmental measurements may affect the estimated
relationships.
Fourth, the analysis relies on county-name and state-name
standardization for files without a consistently available FIPS
identifier. Although state-plus-county matching reduces ambiguity, a
verified five-digit FIPS crosswalk would be preferable for the final
data integration.
Fifth, the selected variables do not capture every factor associated
with obesity. Potentially relevant omitted characteristics include
healthcare access, transportation infrastructure, demographic
composition, housing, local policy, and neighborhood-level
resources.
Sixth, state fixed effects capture average differences between states
but do not directly test spatial autocorrelation among neighboring
counties. A separate spatial analysis using validated county geometries
and a defensible spatial-weights matrix would be needed to assess
neighboring-county dependence.
Finally, OLS estimates may be sensitive to influential observations,
multicollinearity, heteroscedasticity, and measurement error. The
diagnostic results should therefore be considered alongside the
coefficient estimates.
9. Conclusion
This study examines county-level geographic differences in adult
obesity prevalence after adjustment for measured behavioral,
socioeconomic, food-related, and environmental characteristics. It uses
a sequential modeling strategy that compares a baseline OLS regression
with a model containing state fixed effects.
The final conclusion should be completed after the data and model
outputs have been reviewed. It should state how much variation the
baseline model explains, whether the state fixed-effects model adds
explanatory value, which measured associations are most important, and
what geographic differences remain unexplained.
The findings should be interpreted as county-level observational
associations. They may help identify geographic patterns that warrant
additional public-health investigation, but they do not establish causal
effects or explain all sources of obesity differences across
communities.
10. Reproducibility
and Final Checks
The analysis is designed to be reproducible from the public project
repository. Before submission, confirm that the repository files have
not changed, that each source column was mapped correctly, and that the
final complete-case sample is appropriate for the research question.
final_checks <- tibble(
Check = c(
"Outcome variable present",
"At least 3 predictors included",
"Regression sample has at least 100 counties",
"More than one state represented",
"Baseline and state models use same observations",
"Model coefficients are finite"
),
Passed = c(
"adult_obesity" %in% names(model_data),
length(available_predictors) >= 3,
nrow(model_data) >= 100,
n_distinct(model_data$State) > 1,
nobs(model_ols) == nobs(model_state),
all(is.finite(coef(model_state)))
)
)
knitr::kable(
final_checks,
caption = "Reproducibility and model validation checks"
) %>%
kableExtra::kable_styling(full_width = FALSE)
Reproducibility and model validation checks
|
Check
|
Passed
|
|
Outcome variable present
|
TRUE
|
|
At least 3 predictors included
|
TRUE
|
|
Regression sample has at least 100 counties
|
TRUE
|
|
More than one state represented
|
TRUE
|
|
Baseline and state models use same observations
|
TRUE
|
|
Model coefficients are finite
|
TRUE
|
References
Ahern, M., Brown, C., & Dukas, S. (2011). A national study of the
association between food environments and county-level health outcomes.
The Journal of Rural Health. [Verify volume, issue, pages, and
DOI before submission.]
An, R., Li, X., & Jiang, N. (2017). Geographical variations in
the environmental determinants of physical inactivity among U.S. adults.
[Verify complete publication details before submission.]
Centers for Disease Control and Prevention. (n.d.). North America
Land Data Assimilation System (NLDAS) daily sunlight (kJ/m²),
1979–2011. https://wonder.cdc.gov/controller/datarequest/D80
Feeding America. (n.d.). Map the Meal Gap: County-level food
insecurity data. https://www.feedingamerica.org/research/map-the-meal-gap/by-county
Hammarström, A., Janlert, U., & Winefield, H. (2014). Length of
unemployment and health-related outcomes. [Verify complete publication
details before submission.]
Holick, M. F., & Wacker, M. (2013). Sunlight and vitamin
D. [Verify publisher and edition or article details before
submission.]
Institute for Health Metrics and Evaluation. (n.d.). United
States alcohol use prevalence by county, 2002–2012. Global Health
Data Exchange. http://ghdx.healthdata.org/record/ihme-data/united-states-alcohol-use-prevalence-county-2002-2012
Institute for Health Metrics and Evaluation. (n.d.). United
States physical activity and obesity prevalence by county. Global
Health Data Exchange. https://ghdx.healthdata.org/
U.S. Census Bureau. (2019). Small Area Income and Poverty
Estimates (SAIPE): State and county estimates. https://www.census.gov/data/datasets/2019/demo/saipe/2019-state-and-county.html
U.S. Department of Agriculture, Economic Research Service. (n.d.).
County-level data sets. https://www.ers.usda.gov/data-products/county-level-data-sets/download-data/
U.S. Environmental Protection Agency. (n.d.). Environmental
Quality Index (EQI), 2006–2010. https://edg.epa.gov/EPADataCommons/public/ORD/CPHEA/EQI_2006_2010/
Submission note: Complete the discussion and
conclusion using the actual output from the final knit. Verify every
literature reference’s full bibliographic details and add in-text
citations where the cited studies are discussed. The final paper should
not be submitted with unresolved source mappings, incomplete references,
or unreviewed model diagnostics.
LS0tDQp0aXRsZTogIkNvdW50eS1MZXZlbCBHZW9ncmFwaGljIERpZmZlcmVuY2VzIGluIEFkdWx0IE9iZXNpdHkgUHJldmFsZW5jZSBBZnRlciBDb250cm9sbGluZyBmb3IgS25vd24gUmlzayBGYWN0b3JzIg0KYXV0aG9yOiAiQmlrYXNoIEJob3dtaWsiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiAzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0aGVtZTogY29zbW8NCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgZWNobyA9IFRSVUUsDQogIG1lc3NhZ2UgPSBGQUxTRSwNCiAgd2FybmluZyA9IEZBTFNFLA0KICBmaWcuYWxpZ24gPSAiY2VudGVyIiwNCiAgZmlnLndpZHRoID0gOCwNCiAgZmlnLmhlaWdodCA9IDUsDQogIG91dC53aWR0aCA9ICI5NSUiDQopDQoNCnJlcXVpcmVkX3BhY2thZ2VzIDwtIGMoDQogICJ0aWR5dmVyc2UiLCAiamFuaXRvciIsICJrbml0ciIsICJrYWJsZUV4dHJhIiwNCiAgImJyb29tIiwgImNhciIsICJsbXRlc3QiLCAic2FuZHdpY2giLCAic2NhbGVzIiwNCiAgInN0cmluZ2kiDQopDQoNCm1pc3NpbmdfcGFja2FnZXMgPC0gcmVxdWlyZWRfcGFja2FnZXNbDQogICF2YXBwbHkocmVxdWlyZWRfcGFja2FnZXMsIHJlcXVpcmVOYW1lc3BhY2UsIGxvZ2ljYWwoMSksIHF1aWV0bHkgPSBUUlVFKQ0KXQ0KDQppZiAobGVuZ3RoKG1pc3NpbmdfcGFja2FnZXMpID4gMCkgew0KICBzdG9wKA0KICAgICJJbnN0YWxsIHRoZXNlIHBhY2thZ2VzIGJlZm9yZSBrbml0dGluZzogIiwNCiAgICBwYXN0ZShtaXNzaW5nX3BhY2thZ2VzLCBjb2xsYXBzZSA9ICIsICIpDQogICkNCn0NCg0KaW52aXNpYmxlKGxhcHBseShyZXF1aXJlZF9wYWNrYWdlcywgbGlicmFyeSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkNCg0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpDQpzZXQuc2VlZCg2OTgpDQpgYGANCg0KIyBBYnN0cmFjdA0KDQpBZHVsdCBvYmVzaXR5IHByZXZhbGVuY2UgdmFyaWVzIGFjcm9zcyBVLlMuIGNvdW50aWVzLiBUaGlzIHN0dWR5IGV4YW1pbmVzIHdoZXRoZXIgY291bnR5LWxldmVsIGdlb2dyYXBoaWMgZGlmZmVyZW5jZXMgcmVtYWluIGFmdGVyIGFjY291bnRpbmcgZm9yIG1lYXN1cmVkIGJlaGF2aW9yYWwsIHNvY2lvZWNvbm9taWMsIGZvb2QtcmVsYXRlZCwgYW5kIGVudmlyb25tZW50YWwgY2hhcmFjdGVyaXN0aWNzLiBDb3VudHktbGV2ZWwgZGF0YSBhcmUgYXNzZW1ibGVkIGZyb20gdGhlIElITUUgZGF0YXNldHMgYW5kIHN1cHBvcnRpbmcgcHVibGljIGRhdGEgZmlsZXMgbWFpbnRhaW5lZCBpbiB0aGUgcHJvamVjdCdzIEdpdEh1YiByZXBvc2l0b3J5LiBUaGUgcHJpbWFyeSBvdXRjb21lIGlzIGFuIGFwcHJveGltYXRlIGNvdW50eS1sZXZlbCBhZHVsdCBvYmVzaXR5IHByZXZhbGVuY2UgbWVhc3VyZSBjYWxjdWxhdGVkIGFzIHRoZSBhcml0aG1ldGljIG1lYW4gb2YgdGhlIG1hbGUgYW5kIGZlbWFsZSAyMDA5IElITUUgY291bnR5IGVzdGltYXRlcy4gUHJlZGljdG9ycyBhcmUgc2VsZWN0ZWQgZnJvbSB0aGUgYXZhaWxhYmxlIGNvdW50eS1sZXZlbCBtZWFzdXJlcyBvZiBwaHlzaWNhbCBpbmFjdGl2aXR5LCBhbGNvaG9sIHVzZSwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCwgdW5lbXBsb3ltZW50LCBob3VzZWhvbGQgaW5jb21lIG9yIHdlYWx0aCwgZm9vZCBpbnNlY3VyaXR5LCBzdW5saWdodCBleHBvc3VyZSwgZW52aXJvbm1lbnRhbCBxdWFsaXR5LCBhbmQgcG9wdWxhdGlvbi4NCg0KVGhlIGFuYWx5c2lzIHVzZXMgZGVzY3JpcHRpdmUgc3RhdGlzdGljcywgZXhwbG9yYXRvcnkgdmlzdWFsaXphdGlvbnMsIG11bHRpcGxlIG9yZGluYXJ5IGxlYXN0IHNxdWFyZXMgcmVncmVzc2lvbiwgYW5kIGEgc3RhdGUgZml4ZWQtZWZmZWN0cyBtb2RlbC4gTW9kZWwgZml0IGlzIGFzc2Vzc2VkIHVzaW5nIGFkanVzdGVkIFItc3F1YXJlZCwgcm9vdCBtZWFuIHNxdWFyZWQgZXJyb3IsIGEgbmVzdGVkLW1vZGVsIGNvbXBhcmlzb24sIGFuZCByZWdyZXNzaW9uIGRpYWdub3N0aWNzLiBCZWNhdXNlIHRoZSBkYXRhIGFyZSBvYnNlcnZhdGlvbmFsIGFuZCBhZ2dyZWdhdGVkIGF0IHRoZSBjb3VudHkgbGV2ZWwsIGFsbCBmaW5kaW5ncyBhcmUgaW50ZXJwcmV0ZWQgYXMgYXNzb2NpYXRpb25zIHJhdGhlciB0aGFuIGNhdXNhbCBlZmZlY3RzLiBUaGUgZmluYWwgaW50ZXJwcmV0YXRpb24gd2lsbCBmb2N1cyBvbiB0aGUgYW1vdW50IG9mIHZhcmlhdGlvbiBleHBsYWluZWQgYnkgbWVhc3VyZWQgY291bnR5IGNoYXJhY3RlcmlzdGljcyBhbmQgd2hldGhlciBhZGRpbmcgc3RhdGUgaW5kaWNhdG9ycyBwcm92aWRlcyBhZGRpdGlvbmFsIGV4cGxhbmF0b3J5IHZhbHVlLg0KDQoqKlRoZSBudW1lcmljYWwgZmluZGluZ3MgaW4gdGhpcyBhYnN0cmFjdCBhcmUgZ2VuZXJhdGVkIGZyb20gdGhlIGN1cnJlbnQgZGF0YSB3aGVuIHRoZSBkb2N1bWVudCBpcyBrbml0dGVkLioqIFRoZSBvdXRjb21lIGRlZmluaXRpb24gYW5kIHRoZSB5ZWFycyByZXByZXNlbnRlZCBieSBlYWNoIHNvdXJjZSBtdXN0IGJlIGNvbnNpZGVyZWQgd2hlbiBpbnRlcnByZXRpbmcgdGhlIHJlc3VsdHMuDQoNCioqS2V5d29yZHM6KiogYWR1bHQgb2Jlc2l0eSwgY291bnR5LWxldmVsIGFuYWx5c2lzLCBnZW9ncmFwaGljIHZhcmlhdGlvbiwgcGh5c2ljYWwgaW5hY3Rpdml0eSwgc29jaW9lY29ub21pYyBmYWN0b3JzLCBzdGF0ZSBmaXhlZCBlZmZlY3RzLCBzcGF0aWFsIGRpc3Bhcml0aWVzDQoNCiMgMS4gSW50cm9kdWN0aW9uDQoNCkFkdWx0IG9iZXNpdHkgaXMgYW4gaW1wb3J0YW50IHB1YmxpYy1oZWFsdGggaXNzdWUgaW4gdGhlIFVuaXRlZCBTdGF0ZXMsIGFuZCBwcmV2YWxlbmNlIGRpZmZlcnMgYWNyb3NzIGdlb2dyYXBoaWMgYXJlYXMuIE5hdGlvbmFsIGFuZCBzdGF0ZSBzdW1tYXJpZXMgY2FuIGNvbmNlYWwgc3Vic3RhbnRpYWwgdmFyaWF0aW9uIGFtb25nIGNvdW50aWVzLiBDb3VudGllcyBkaWZmZXIgaW4gZWNvbm9taWMgcmVzb3VyY2VzLCBlZHVjYXRpb25hbCBhdHRhaW5tZW50LCBlbXBsb3ltZW50IGNvbmRpdGlvbnMsIGZvb2Qgc2VjdXJpdHksIGJlaGF2aW9yYWwgcGF0dGVybnMsIGFuZCBlbnZpcm9ubWVudGFsIGNoYXJhY3RlcmlzdGljcy4gVGhlc2UgZGlmZmVyZW5jZXMgcHJvdmlkZSBhbiBpbXBvcnRhbnQgY29udGV4dCBmb3IgZXhhbWluaW5nIGNvdW50eS1sZXZlbCB2YXJpYXRpb24gaW4gYWR1bHQgb2Jlc2l0eS4NCg0KTWFueSBrbm93biBjaGFyYWN0ZXJpc3RpY3MgaGF2ZSBiZWVuIGFzc29jaWF0ZWQgd2l0aCBvYmVzaXR5LCBpbmNsdWRpbmcgcGh5c2ljYWwgYWN0aXZpdHksIHNvY2lvZWNvbm9taWMgY29uZGl0aW9ucywgYW5kIGZvb2QtcmVsYXRlZCBjaXJjdW1zdGFuY2VzLiBUaGUgcHVycG9zZSBvZiB0aGlzIHN0dWR5IGlzIG5vdCBzaW1wbHkgdG8gaWRlbnRpZnkgd2hldGhlciB0aGVzZSBlc3RhYmxpc2hlZCBmYWN0b3JzIGFyZSBhc3NvY2lhdGVkIHdpdGggb2Jlc2l0eS4gSW5zdGVhZCwgdGhlIGNlbnRyYWwgcXVlc3Rpb24gaXMgd2hldGhlciBnZW9ncmFwaGljIGRpZmZlcmVuY2VzIGFtb25nIFUuUy4gY291bnRpZXMgcmVtYWluIGFmdGVyIGFjY291bnRpbmcgZm9yIG1lYXN1cmVkIGNvdW50eS1sZXZlbCBjaGFyYWN0ZXJpc3RpY3MuDQoNClRoaXMgc3R1ZHkgY29tYmluZXMgcHVibGljbHkgYXZhaWxhYmxlIGNvdW50eS1sZXZlbCBkYXRhIGZyb20gbXVsdGlwbGUgc291cmNlcyBhbmQgdXNlcyByZWdyZXNzaW9uIG1vZGVsaW5nIHRvIGVzdGltYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhZHVsdCBvYmVzaXR5IHByZXZhbGVuY2UgYW5kIHNlbGVjdGVkIGV4cGxhbmF0b3J5IHZhcmlhYmxlcy4gQSBiYXNlbGluZSBvcmRpbmFyeSBsZWFzdCBzcXVhcmVzIChPTFMpIG1vZGVsIGlzIGNvbXBhcmVkIHdpdGggYSBtb2RlbCB0aGF0IGluY2x1ZGVzIHN0YXRlIGZpeGVkIGVmZmVjdHMuIFRoZSBjb21wYXJpc29uIGV2YWx1YXRlcyB3aGV0aGVyIHN0YXRlLWxldmVsIGdlb2dyYXBoaWMgaW5kaWNhdG9ycyBwcm92aWRlIGFkZGl0aW9uYWwgZXhwbGFuYXRvcnkgaW5mb3JtYXRpb24gYWZ0ZXIgYWRqdXN0bWVudCBmb3IgdGhlIG1lYXN1cmVkIHJpc2sgZmFjdG9ycy4NCg0KVGhlIGFuYWx5c2lzIGlzIG9ic2VydmF0aW9uYWwuIEl0IGRvZXMgbm90IGVzdGFibGlzaCB0aGF0IGNvdW50eSBsb2NhdGlvbiBvciBhbnkgaW5kaXZpZHVhbCBwcmVkaWN0b3IgY2F1c2VzIG9iZXNpdHkuIEJlY2F1c2UgdGhlIHVuaXQgb2YgYW5hbHlzaXMgaXMgdGhlIGNvdW50eSwgcmVzdWx0cyBkZXNjcmliZSBjb3VudHktbGV2ZWwgYXNzb2NpYXRpb25zIGFuZCBzaG91bGQgbm90IGJlIGludGVycHJldGVkIGFzIGluZGl2aWR1YWwtbGV2ZWwgcmVsYXRpb25zaGlwcy4NCg0KIyMgMS4xIEltcG9ydGFuY2Ugb2YgdGhlIFN0dWR5DQoNClVuZGVyc3RhbmRpbmcgZ2VvZ3JhcGhpYyBkaWZmZXJlbmNlcyBpbiBvYmVzaXR5IG1heSBoZWxwIGlkZW50aWZ5IGNvbW11bml0aWVzIHdoZXJlIG9ic2VydmVkIHByZXZhbGVuY2UgaXMgaGlnaGVyIG9yIGxvd2VyIHRoYW4gZXhwZWN0ZWQgZ2l2ZW4gbWVhc3VyZWQgY291bnR5IGNoYXJhY3RlcmlzdGljcy4gSWYgZ2VvZ3JhcGhpYyBkaWZmZXJlbmNlcyByZW1haW4gYWZ0ZXIgYWRqdXN0bWVudCwgdGhpcyBtYXkgaW5kaWNhdGUgdGhhdCBhZGRpdGlvbmFsIGNvbnRleHR1YWwsIHBvbGljeS1yZWxhdGVkLCBoZWFsdGhjYXJlLCBkZW1vZ3JhcGhpYywgb3Igc3BhdGlhbGx5IHBhdHRlcm5lZCBmYWN0b3JzIHdhcnJhbnQgaW52ZXN0aWdhdGlvbi4NCg0KVGhlIHN0dWR5IGFsc28gZGVtb25zdHJhdGVzIGhvdyBkYXRhIGZyb20gbXVsdGlwbGUgcHVibGljIHNvdXJjZXMgY2FuIGJlIGludGVncmF0ZWQgYW5kIGFuYWx5emVkIHVzaW5nIHJlcHJvZHVjaWJsZSBzdGF0aXN0aWNhbCBtZXRob2RzIGluIFIuIFRoZSBlbXBoYXNpcyBpcyBvbiBtb2RlbCBjb21wYXJpc29uLCBlZmZlY3QgZXN0aW1hdGVzLCB1bmNlcnRhaW50eSwgYW5kIGRpYWdub3N0aWMgZXZhbHVhdGlvbiByYXRoZXIgdGhhbiBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UgYWxvbmUuDQoNCiMgMi4gTGl0ZXJhdHVyZSBSZXZpZXcNCg0KIyMgMi4xIE9iZXNpdHkgYW5kIEdlb2dyYXBoaWMgRGlmZmVyZW5jZXMNCg0KUHVibGljLWhlYWx0aCByZXNlYXJjaCBoYXMgZXhhbWluZWQgb2Jlc2l0eSBpbiByZWxhdGlvbiB0byBiZWhhdmlvcmFsLCBzb2Npb2Vjb25vbWljLCBhbmQgZW52aXJvbm1lbnRhbCBjaGFyYWN0ZXJpc3RpY3MuIEEgY291bnR5LWxldmVsIHBlcnNwZWN0aXZlIGlzIHVzZWZ1bCBiZWNhdXNlIGNvdW50aWVzIHdpdGhpbiB0aGUgc2FtZSBzdGF0ZSBjYW4gZGlmZmVyIHN1YnN0YW50aWFsbHkgaW4gcG9wdWxhdGlvbiBjb21wb3NpdGlvbiwgZWNvbm9taWMgY29uZGl0aW9ucywgYWNjZXNzIHRvIHJlc291cmNlcywgYW5kIGhlYWx0aC1yZWxhdGVkIGVudmlyb25tZW50cy4gVGhlIHByZXNlbnQgc3R1ZHkgdXNlcyB0aGlzIGdlb2dyYXBoaWMgdmFyaWF0aW9uIGFzIHRoZSBmb2N1cyBvZiBpdHMgYW5hbHlzaXMuDQoNCiMjIDIuMiBCZWhhdmlvcmFsIGFuZCBTb2Npb2Vjb25vbWljIENoYXJhY3RlcmlzdGljcw0KDQpQaHlzaWNhbCBhY3Rpdml0eSBpcyBhbiBpbXBvcnRhbnQgYmVoYXZpb3JhbCBjaGFyYWN0ZXJpc3RpYyBpbiB0aGUgc3R1ZHkgb2Ygb2Jlc2l0eS4gQ291bnR5LWxldmVsIGRpZmZlcmVuY2VzIGluIHBoeXNpY2FsIGFjdGl2aXR5IG1heSBiZSBhc3NvY2lhdGVkIHdpdGggZGlmZmVyZW5jZXMgaW4gb2Jlc2l0eSBwcmV2YWxlbmNlLiBFY29ub21pYyBhbmQgZWR1Y2F0aW9uYWwgY2hhcmFjdGVyaXN0aWNzIG1heSBhbHNvIGJlIHJlbGF0ZWQgdG8gY29tbXVuaXR5IHJlc291cmNlcywgb3Bwb3J0dW5pdGllcywgYW5kIGhlYWx0aCBjb25kaXRpb25zLiBUaGlzIHN0dWR5IHRoZXJlZm9yZSBjb25zaWRlcnMgcGh5c2ljYWwgaW5hY3Rpdml0eSwgYWxjb2hvbCB1c2UsIGVkdWNhdGlvbiwgdW5lbXBsb3ltZW50LCBhbmQgaG91c2Vob2xkIGluY29tZSBvciB3ZWFsdGggYXMgcG90ZW50aWFsIGV4cGxhbmF0b3J5IG9yIGNvbnRyb2wgdmFyaWFibGVzLg0KDQojIyAyLjMgRm9vZC1SZWxhdGVkIGFuZCBFbnZpcm9ubWVudGFsIENoYXJhY3RlcmlzdGljcw0KDQpGb29kIGluc2VjdXJpdHkgaXMgaW5jbHVkZWQgYXMgYSBjb3VudHktbGV2ZWwgbWVhc3VyZSBvZiBmb29kLXJlbGF0ZWQgZWNvbm9taWMgaGFyZHNoaXAuIEVudmlyb25tZW50YWwgY2hhcmFjdGVyaXN0aWNzLCBpbmNsdWRpbmcgc3VubGlnaHQgZXhwb3N1cmUgYW5kIHRoZSBFbnZpcm9ubWVudGFsIFF1YWxpdHkgSW5kZXggd2hlcmUgYXZhaWxhYmxlLCBhcmUgY29uc2lkZXJlZCBhcyBhZGRpdGlvbmFsIGNvbnRleHR1YWwgbWVhc3VyZXMuIFRoZXNlIHZhcmlhYmxlcyBhcmUgbm90IGFzc3VtZWQgdG8gcmVwcmVzZW50IGV2ZXJ5IGFzcGVjdCBvZiB0aGUgbG9jYWwgZm9vZCBvciBwaHlzaWNhbCBlbnZpcm9ubWVudDsgdGhleSBhcmUgaW5jbHVkZWQgYmVjYXVzZSB0aGV5IGFyZSBhdmFpbGFibGUgaW4gdGhlIHByb2plY3QncyBjb21waWxlZCBwdWJsaWMgZGF0YXNldHMuDQoNCiMjIDIuNCBHZW9ncmFwaGljIGFuZCBTcGF0aWFsIFZhcmlhdGlvbg0KDQpTdGF0ZSBmaXhlZCBlZmZlY3RzIHJlcHJlc2VudCBzeXN0ZW1hdGljIGRpZmZlcmVuY2VzIGFtb25nIHN0YXRlcyB0aGF0IGFyZSBub3QgY2FwdHVyZWQgYnkgdGhlIG1lYXN1cmVkIGV4cGxhbmF0b3J5IHZhcmlhYmxlcy4gSWYgdGhlIGZpeGVkLWVmZmVjdHMgbW9kZWwgaW1wcm92ZXMgbW9kZWwgZml0LCB0aGlzIHN1Z2dlc3RzIHRoYXQgc3RhdGUgbWVtYmVyc2hpcCBwcm92aWRlcyBhZGRpdGlvbmFsIGV4cGxhbmF0b3J5IGluZm9ybWF0aW9uLiBTdGF0ZSBmaXhlZCBlZmZlY3RzIGRvIG5vdCwgYnkgdGhlbXNlbHZlcywgaWRlbnRpZnkgbG9jYWwgc3BhdGlhbCBkZXBlbmRlbmNlIGJldHdlZW4gbmVpZ2hib3JpbmcgY291bnRpZXMuIEEgc2VwYXJhdGUgc3BhdGlhbC1hdXRvY29ycmVsYXRpb24gYW5hbHlzaXMgd291bGQgYmUgcmVxdWlyZWQgdG8gYXNzZXNzIHRoYXQgcXVlc3Rpb24uDQoNCiMjIDIuNSBSZXNlYXJjaCBDb250cmlidXRpb24NCg0KVGhlIGNvbnRyaWJ1dGlvbiBvZiB0aGlzIHN0dWR5IGlzIGl0cyBmb2N1cyBvbiB0aGUgYW1vdW50IG9mIGNvdW50eS1sZXZlbCBnZW9ncmFwaGljIHZhcmlhdGlvbiB0aGF0IHJlbWFpbnMgYWZ0ZXIgYWRqdXN0bWVudCBmb3IgbWVhc3VyZWQgYmVoYXZpb3JhbCwgc29jaW9lY29ub21pYywgZm9vZC1yZWxhdGVkLCBhbmQgZW52aXJvbm1lbnRhbCBjaGFyYWN0ZXJpc3RpY3MuIFRoZSBzdHVkeSBkb2VzIG5vdCBjbGFpbSB0aGF0IHRoZSBzZWxlY3RlZCBwcmVkaWN0b3JzIG9yIHRoZSBnZW9ncmFwaGljIGFwcHJvYWNoIGFyZSB1bnByZWNlZGVudGVkLiBSYXRoZXIsIGl0IGFwcGxpZXMgYSBjb25zaXN0ZW50IGNvdW50eS1sZXZlbCBtb2RlbGluZyBmcmFtZXdvcmsgdG8gYXNzZXNzIHRoZSBhZGRpdGlvbmFsIGV4cGxhbmF0b3J5IHZhbHVlIG9mIHN0YXRlLWxldmVsIGdlb2dyYXBoaWMgaW5kaWNhdG9ycy4NCg0KIyAzLiBSZXNlYXJjaCBRdWVzdGlvbnMgYW5kIEh5cG90aGVzZXMNCg0KIyMgMy4xIFByaW1hcnkgUmVzZWFyY2ggUXVlc3Rpb24NCg0KVG8gd2hhdCBleHRlbnQgZG8gY291bnR5LWxldmVsIGdlb2dyYXBoaWMgZGlmZmVyZW5jZXMgaW4gYWR1bHQgb2Jlc2l0eSBwcmV2YWxlbmNlIHJlbWFpbiBhZnRlciBjb250cm9sbGluZyBmb3Iga25vd24gYmVoYXZpb3JhbCwgc29jaW9lY29ub21pYywgZm9vZC1yZWxhdGVkLCBhbmQgZW52aXJvbm1lbnRhbCBmYWN0b3JzPw0KDQojIyAzLjIgU3VwcG9ydGluZyBSZXNlYXJjaCBRdWVzdGlvbnMNCg0KMS4gSG93IG11Y2ggdmFyaWF0aW9uIGluIGFkdWx0IG9iZXNpdHkgcHJldmFsZW5jZSBleGlzdHMgYWNyb3NzIFUuUy4gY291bnRpZXMgYmVmb3JlIGFjY291bnRpbmcgZm9yIG90aGVyIGNvdW50eS1sZXZlbCBjaGFyYWN0ZXJpc3RpY3M/DQoyLiBUbyB3aGF0IGV4dGVudCBhcmUgbWVhc3VyZWQgYmVoYXZpb3JhbCwgc29jaW9lY29ub21pYywgZm9vZC1yZWxhdGVkLCBhbmQgZW52aXJvbm1lbnRhbCBjaGFyYWN0ZXJpc3RpY3MgYXNzb2NpYXRlZCB3aXRoIGNvdW50eS1sZXZlbCBhZHVsdCBvYmVzaXR5IHByZXZhbGVuY2U/DQozLiBEb2VzIGFkZGluZyBzdGF0ZSBmaXhlZCBlZmZlY3RzIGltcHJvdmUgdGhlIGV4cGxhbmF0b3J5IHBlcmZvcm1hbmNlIG9mIHRoZSBtb2RlbCBhZnRlciBhZGp1c3RtZW50IGZvciB0aGUgbWVhc3VyZWQgY2hhcmFjdGVyaXN0aWNzPw0KNC4gRG8gcmVzaWR1YWwgZGlhZ25vc3RpY3MgaW5kaWNhdGUgaW1wb3J0YW50IGRlcGFydHVyZXMgZnJvbSB0aGUgYXNzdW1wdGlvbnMgb2YgdGhlIE9MUyByZWdyZXNzaW9uIG1vZGVsPw0KDQojIyAzLjMgSHlwb3RoZXNlcw0KDQotICoqSDE6KiogQ291bnR5LWxldmVsIGFkdWx0IG9iZXNpdHkgcHJldmFsZW5jZSB2YXJpZXMgYWNyb3NzIFUuUy4gY291bnRpZXMuDQotICoqSDI6KiogVGhlIHNlbGVjdGVkIGJlaGF2aW9yYWwsIHNvY2lvZWNvbm9taWMsIGZvb2QtcmVsYXRlZCwgYW5kIGVudmlyb25tZW50YWwgY2hhcmFjdGVyaXN0aWNzIGpvaW50bHkgZXhwbGFpbiBhIHN0YXRpc3RpY2FsbHkgbWVhbmluZ2Z1bCBwb3J0aW9uIG9mIHRoZSB2YXJpYXRpb24gaW4gY291bnR5LWxldmVsIGFkdWx0IG9iZXNpdHkgcHJldmFsZW5jZS4NCi0gKipIMzoqKiBBZGRpbmcgc3RhdGUgZml4ZWQgZWZmZWN0cyBpbXByb3ZlcyBtb2RlbCBmaXQgYmV5b25kIHRoZSBiYXNlbGluZSBtb2RlbCBjb250YWluaW5nIG1lYXN1cmVkIGNvdW50eS1sZXZlbCBjaGFyYWN0ZXJpc3RpY3MuDQotICoqSDQ6KiogQWZ0ZXIgYWRqdXN0bWVudCwgcmVzaWR1YWxzIG1heSBzdGlsbCBleGhpYml0IHBhdHRlcm5zIHRoYXQgaW5kaWNhdGUgdW5leHBsYWluZWQgY291bnR5LWxldmVsIHZhcmlhdGlvbi4gVGhpcyBoeXBvdGhlc2lzIHdpbGwgYmUgZXZhbHVhdGVkIGRlc2NyaXB0aXZlbHk7IHN0YXRlIGZpeGVkIGVmZmVjdHMgYWxvbmUgYXJlIG5vdCBhIHRlc3Qgb2YgbmVpZ2hib3JpbmctY291bnR5IHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLg0KDQojIDQuIERhdGEgYW5kIFZhcmlhYmxlcw0KDQojIyA0LjEgRGF0YSBTb3VyY2VzDQoNClRoZSBwcm9qZWN0IHJlcG9zaXRvcnkgY29udGFpbnMgdGhlIGNvdW50eS1sZXZlbCBzb3VyY2UgZmlsZXMgdXNlZCBmb3IgdGhpcyBhbmFseXNpcy4gVGhlIGZpbGVzIGFyZSByZWFkIGRpcmVjdGx5IGZyb20gdGhlIHB1YmxpYyBHaXRIdWIgcmVwb3NpdG9yeSBzbyB0aGUgYW5hbHlzaXMgY2FuIGJlIHJlcHJvZHVjZWQuIFRoZSBwcmluY2lwYWwgc291cmNlcyBpZGVudGlmaWVkIGluIHRoZSBhcHByb3ZlZCBwcm9wb3NhbCBpbmNsdWRlIHRoZSBJbnN0aXR1dGUgZm9yIEhlYWx0aCBNZXRyaWNzIGFuZCBFdmFsdWF0aW9uIChJSE1FKSwgVS5TLiBnb3Zlcm5tZW50IGRhdGFzZXRzLCB0aGUgVS5TLiBFbnZpcm9ubWVudGFsIFByb3RlY3Rpb24gQWdlbmN5LCBGZWVkaW5nIEFtZXJpY2EsIGFuZCBDREMgZW52aXJvbm1lbnRhbCBkYXRhLg0KDQpUaGUgZGF0YSBmaWxlcyBpbmNsdWRlOg0KDQotIGBJSE1FX09iZXNpdHkuY3N2YA0KLSBgSUhNRV9QaHlzaWNhbEFjdGl2aXR5LmNzdmANCi0gYEFsY29ob2xDb25zdW1wdGlvbi5jc3ZgDQotIGBFZHVjYXRpb24uY3N2YA0KLSBgVW5lbXBsb3ltZW50LmNzdmANCi0gYFdlYWx0aC5jc3ZgDQotIGBGb29kSW5zZWN1cml0eS5jc3ZgDQotIGBTdW5saWdodC5jc3ZgDQotIGBFbnZpcm9ubWVudGFsUXVhbGl0eUluZGV4LmNzdmANCi0gYHBvcHVsYXRpb24uY3N2YA0KDQpUaGUgYW5hbHlzaXMgdXNlcyBvbmx5IHZhcmlhYmxlcyB0aGF0IGNhbiBiZSBpZGVudGlmaWVkIGFuZCBtZXJnZWQgcmVsaWFibHkgZnJvbSB0aGUgYXZhaWxhYmxlIHNvdXJjZSBmaWxlcy4gVGhlIGNvZGUgYmVsb3cgcHJpbnRzIHRoZSBzZWxlY3RlZCBzb3VyY2UgY29sdW1ucyBhbmQgcmVwb3J0cyBhbnkgb3B0aW9uYWwgbWVhc3VyZSB0aGF0IGlzIG5vdCBmb3VuZC4gTWlzc2luZyB2YXJpYWJsZXMgYXJlIG5vdCBzaWxlbnRseSByZXBsYWNlZCB3aXRoIHVucmVsYXRlZCBtZWFzdXJlcy4NCg0KIyMgNC4yIE91dGNvbWUgVmFyaWFibGUNCg0KVGhlIElITUUgb2Jlc2l0eSBmaWxlIGNvbnRhaW5zIHNlcGFyYXRlIG1hbGUgYW5kIGZlbWFsZSBjb3VudHkgcHJldmFsZW5jZSBlc3RpbWF0ZXMgZm9yIDIwMDkuIEZvciB0aGlzIGFuYWx5c2lzLCB0aGUgcHJpbWFyeSBvdXRjb21lIGlzIGRlZmluZWQgYXMgdGhlIGFyaXRobWV0aWMgbWVhbiBvZiB0aG9zZSB0d28gZXN0aW1hdGVzOg0KDQpcWw0KXHRleHR7QWR1bHQgT2Jlc2l0eX1fe2l9ID0NClxmcmFje1x0ZXh0e01hbGUgT2Jlc2l0eX1fe2ksMjAwOX0rDQpcdGV4dHtGZW1hbGUgT2Jlc2l0eX1fe2ksMjAwOX19ezJ9DQpcXQ0KDQpUaGlzIGlzIGFuIGFwcHJveGltYXRpb24sIG5vdCBhIHBvcHVsYXRpb24td2VpZ2h0ZWQgY29tYmluZWQgcHJldmFsZW5jZSBlc3RpbWF0ZS4gQSBwb3B1bGF0aW9uLXdlaWdodGVkIG92ZXJhbGwgZXN0aW1hdGUgd291bGQgcmVxdWlyZSBjb3VudHktbGV2ZWwgbWFsZSBhbmQgZmVtYWxlIHBvcHVsYXRpb24gd2VpZ2h0cyB0aGF0IGFyZSBhbGlnbmVkIHRvIHRoZSBzYW1lIHllYXIgYW5kIGRlZmluaXRpb24uIFRoZSBvdXRjb21lIGlzIGV4cHJlc3NlZCBpbiBwZXJjZW50YWdlIHBvaW50cy4NCg0KIyMgNC4zIEV4cGxhbmF0b3J5IFZhcmlhYmxlcw0KDQp8IFZhcmlhYmxlIHwgUm9sZSB8IE1lYXN1cmVtZW50IC8gaW50ZXJwcmV0YXRpb24gfA0KfDotLXw6LS18Oi0tfA0KfCBQaHlzaWNhbCBpbmFjdGl2aXR5IHwgQmVoYXZpb3JhbCB8IDEwMCBtaW51cyB0aGUgYXZlcmFnZSBtYWxlL2ZlbWFsZSBzdWZmaWNpZW50IHBoeXNpY2FsIGFjdGl2aXR5IHByZXZhbGVuY2UsIHdoZXJlIGF2YWlsYWJsZSB8DQp8IEFsY29ob2wgdXNlIHwgQmVoYXZpb3JhbCB8IENvdW50eS1sZXZlbCBhbGNvaG9sLXVzZSBtZWFzdXJlIHN1cHBsaWVkIGluIHRoZSBwcm9qZWN0IHJlcG9zaXRvcnkgfA0KfCBFZHVjYXRpb25hbCBhdHRhaW5tZW50IHwgU29jaW9lY29ub21pYyB8IENvdW50eS1sZXZlbCBjb2xsZWdlIG9yIGJhY2hlbG9yJ3MgYXR0YWlubWVudCBtZWFzdXJlIHwNCnwgVW5lbXBsb3ltZW50IHwgU29jaW9lY29ub21pYyB8IENvdW50eSB1bmVtcGxveW1lbnQgcmF0ZSB8DQp8IEhvdXNlaG9sZCBpbmNvbWUgLyB3ZWFsdGggfCBTb2Npb2Vjb25vbWljIHwgQ291bnR5LWxldmVsIGluY29tZSBvciB3ZWFsdGggbWVhc3VyZSB8DQp8IEZvb2QgaW5zZWN1cml0eSB8IEZvb2QtcmVsYXRlZCB8IENvdW50eS1sZXZlbCBmb29kLWluc2VjdXJpdHkgbWVhc3VyZSB8DQp8IFN1bmxpZ2h0IGV4cG9zdXJlIHwgRW52aXJvbm1lbnRhbCB8IEF2ZXJhZ2UgZGFpbHkgc3VubGlnaHQsIHdoZXJlIGF2YWlsYWJsZSB8DQp8IEVudmlyb25tZW50YWwgcXVhbGl0eSB8IEVudmlyb25tZW50YWwgfCBFbnZpcm9ubWVudGFsIFF1YWxpdHkgSW5kZXgsIHdoZXJlIGF2YWlsYWJsZSB8DQp8IFBvcHVsYXRpb24gfCBDb250ZXh0dWFsIHwgQ291bnR5IHBvcHVsYXRpb247IGNvbnNpZGVyZWQgYXMgbG9nIHBvcHVsYXRpb24gaW4gYSBzZW5zaXRpdml0eSBzcGVjaWZpY2F0aW9uIHwNCnwgU3RhdGUgfCBHZW9ncmFwaGljIHwgU3RhdGUgaW5kaWNhdG9yIHVzZWQgZm9yIGZpeGVkIGVmZmVjdHMgfA0KDQojIyA0LjQgR2VvZ3JhcGhpYyBEYXRhIEludGVncmF0aW9uDQoNCkNvdW50eSByZWNvcmRzIGFyZSBtYXRjaGVkIHVzaW5nIHN0YW5kYXJkaXplZCBzdGF0ZSBhbmQgY291bnR5IG5hbWVzLiBUaGUgb3JpZ2luYWwgcHJvcG9zYWwgZGVzY3JpYmVkIHRoZSB1c2Ugb2YgZml2ZS1kaWdpdCBGSVBTIGNvZGVzLiBUaGUgY3VycmVudCByZXBvc2l0b3J5IGZpbGVzIGRvIG5vdCBhbGwgZXhwb3NlIGEgY29uc2lzdGVudGx5IG5hbWVkIEZJUFMgZmllbGQsIHNvIHRoaXMgdmVyc2lvbiB1c2VzIGEgbm9ybWFsaXplZCBzdGF0ZS1wbHVzLWNvdW50eSBrZXkuIFRoaXMgYXBwcm9hY2ggYXZvaWRzIG1hdGNoaW5nIGNvdW50aWVzIHdpdGggdGhlIHNhbWUgbmFtZSBpbiBkaWZmZXJlbnQgc3RhdGVzLCBidXQgaXQgaXMgbm90IGVxdWl2YWxlbnQgdG8gYSB2ZXJpZmllZCBGSVBTIGpvaW4uIFRoZSBtZXJnZSBkaWFnbm9zdGljcyBiZWxvdyByZXBvcnQgdW5tYXRjaGVkIHJlY29yZHMgYW5kIHNob3VsZCBiZSByZXZpZXdlZCBiZWZvcmUgdGhlIHJlc3VsdHMgYXJlIGZpbmFsaXplZC4NCg0KYGBge3IgZGF0YS1pbXBvcnR9DQpyZXBvX2Jhc2UgPC0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9CSUtBU0hCSE9XTUlLMTUvRGF0YS02OTgvbWFpbi8iDQoNCnJlYWRfcHJvamVjdF9jc3YgPC0gZnVuY3Rpb24oZmlsZW5hbWUpIHsNCiAgdXJsIDwtIHBhc3RlMChyZXBvX2Jhc2UsIGZpbGVuYW1lKQ0KICB0cnlDYXRjaCgNCiAgICByZWFkcjo6cmVhZF9jc3YodXJsLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFLCBuYW1lX3JlcGFpciA9ICJ1bmlxdWUiKSwNCiAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsNCiAgICAgIHN0b3AoIkNvdWxkIG5vdCByZWFkICIsIGZpbGVuYW1lLCAiLiBDaGVjayB0aGUgcmVwb3NpdG9yeSBmaWxlbmFtZSBhbmQgaW50ZXJuZXQgY29ubmVjdGlvbi4gRGV0YWlsczogIiwNCiAgICAgICAgICAgY29uZGl0aW9uTWVzc2FnZShlKSkNCiAgICB9DQogICkNCn0NCg0Kbm9ybWFsaXplX3N0YXRlIDwtIGZ1bmN0aW9uKHgpIHsNCiAgeCA8LSBzdHJpbmdyOjpzdHJfc3F1aXNoKGFzLmNoYXJhY3Rlcih4KSkNCiAgeCA8LSBzdHJpbmdyOjpzdHJfcmVwbGFjZV9hbGwoeCwgIlxcLiIsICIiKQ0KICBhYmJyIDwtIG1hdGNoKHRvdXBwZXIoeCksIHN0YXRlLmFiYikNCiAgeFshaXMubmEoYWJicildIDwtIHN0YXRlLm5hbWVbYWJiclshaXMubmEoYWJicildXQ0KICBkcGx5cjo6Y2FzZV93aGVuKA0KICAgIHRvdXBwZXIoeCkgJWluJSBjKCJEQyIsICJESVNUUklDVCBPRiBDT0xVTUJJQSIpIH4gIkRpc3RyaWN0IG9mIENvbHVtYmlhIiwNCiAgICBUUlVFIH4gc3RyaW5ncjo6c3RyX3RvX3RpdGxlKHgpDQogICkNCn0NCg0Kbm9ybWFsaXplX2NvdW50eSA8LSBmdW5jdGlvbih4KSB7DQogIHggPC0gYXMuY2hhcmFjdGVyKHgpDQogIHggPC0gc3RyaW5naTo6c3RyaV90cmFuc19nZW5lcmFsKHgsICJMYXRpbi1BU0NJSSIpDQogIHggPC0gc3RyaW5ncjo6c3RyX3RvX2xvd2VyKHgpDQogIHggPC0gc3RyaW5ncjo6c3RyX3JlcGxhY2UoeCwgIiwuKiQiLCAiIikNCiAgeCA8LSBzdHJpbmdyOjpzdHJfcmVtb3ZlKHgsICJcXHMrKGNvdW50eXxwYXJpc2h8Ym9yb3VnaHxjZW5zdXMgYXJlYXxtdW5pY2lwYWxpdHkpJCIpDQogIHggPC0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKHgsICJbXmEtejAtOV0iLCAiIikNCiAgeA0KfQ0KDQpmaW5kX2NvbHVtbiA8LSBmdW5jdGlvbihkYXRhLCBwYXR0ZXJucywgcmVxdWlyZWQgPSBUUlVFLCBsYWJlbCA9ICJ2YXJpYWJsZSIpIHsNCiAgbm0gPC0gbmFtZXMoZGF0YSkNCiAgaGl0cyA8LSB1bmlxdWUodW5saXN0KGxhcHBseShwYXR0ZXJucywgZnVuY3Rpb24ocCkgew0KICAgIHdoaWNoKHN0cmluZ3I6OnN0cl9kZXRlY3Qobm0sIHN0cmluZ3I6OnJlZ2V4KHAsIGlnbm9yZV9jYXNlID0gVFJVRSkpKQ0KICB9KSkpDQogIGlmIChsZW5ndGgoaGl0cykgPT0gMCkgew0KICAgIGlmIChyZXF1aXJlZCkgew0KICAgICAgc3RvcCgiQ291bGQgbm90IGlkZW50aWZ5ICIsIGxhYmVsLCAiLiBBdmFpbGFibGUgY29sdW1uczogIiwNCiAgICAgICAgICAgcGFzdGUobm0sIGNvbGxhcHNlID0gIiB8ICIpKQ0KICAgIH0NCiAgICByZXR1cm4oTkFfY2hhcmFjdGVyXykNCiAgfQ0KICBubVtoaXRzWzFdXQ0KfQ0KDQpzdGFuZGFyZGl6ZV9nZW8gPC0gZnVuY3Rpb24oZGF0YSwgc291cmNlX25hbWUgPSAiZGF0YXNldCIpIHsNCg0KICBvcmlnaW5hbF9uYW1lcyA8LSBuYW1lcyhkYXRhKQ0KDQogICMgTm9ybWFsaXplIGNvbHVtbiBuYW1lczogcmVtb3ZlIHNwYWNlcywgdW5kZXJzY29yZXMsDQogICMgcHVuY3R1YXRpb24sIGFuZCBjb252ZXJ0IHRvIGxvd2VyY2FzZQ0KICBub3JtYWxpemVkX25hbWVzIDwtIHRvbG93ZXIoDQogICAgZ3N1YigiW15hLXpBLVowLTldIiwgIiIsIG9yaWdpbmFsX25hbWVzKQ0KICApDQoNCiAgIyBJZGVudGlmeSBzdGF0ZSBjb2x1bW4NCiAgc3RhdGVfaWR4IDwtIHdoaWNoKA0KICAgIG5vcm1hbGl6ZWRfbmFtZXMgJWluJSBjKCJzdGF0ZSIsICJzdGFiciIsICJzdGF0ZW5hbWUiLCAic3RuYW1lIikNCiAgKVsxXQ0KDQogICMgSWRlbnRpZnkgY291bnR5IGNvbHVtbg0KICBjb3VudHlfaWR4IDwtIHdoaWNoKA0KICAgIG5vcm1hbGl6ZWRfbmFtZXMgJWluJSBjKA0KICAgICAgImNvdW50eSIsDQogICAgICAibG9jYXRpb24iLA0KICAgICAgImFyZWFuYW1lIiwNCiAgICAgICJjb3VudHluYW1lIiwNCiAgICAgICJjb3VudHlzdGF0ZSIsDQogICAgICAiY3R5bmFtZSINCiAgICApDQogIClbMV0NCg0KICBpZiAoaXMubmEoc3RhdGVfaWR4KSkgew0KICAgIHN0b3AoDQogICAgICBwYXN0ZTAoDQogICAgICAgICJDb3VsZCBub3QgaWRlbnRpZnkgc3RhdGUgY29sdW1uIGluICIsDQogICAgICAgIHNvdXJjZV9uYW1lLA0KICAgICAgICAiLiBBdmFpbGFibGUgY29sdW1uczogIiwNCiAgICAgICAgcGFzdGUob3JpZ2luYWxfbmFtZXMsIGNvbGxhcHNlID0gIiB8ICIpDQogICAgICApDQogICAgKQ0KICB9DQoNCiAgaWYgKGlzLm5hKGNvdW50eV9pZHgpKSB7DQogICAgc3RvcCgNCiAgICAgIHBhc3RlMCgNCiAgICAgICAgIkNvdWxkIG5vdCBpZGVudGlmeSBjb3VudHkgY29sdW1uIGluICIsDQogICAgICAgIHNvdXJjZV9uYW1lLA0KICAgICAgICAiLiBBdmFpbGFibGUgY29sdW1uczogIiwNCiAgICAgICAgcGFzdGUob3JpZ2luYWxfbmFtZXMsIGNvbGxhcHNlID0gIiB8ICIpDQogICAgICApDQogICAgKQ0KICB9DQoNCiAgc3RhdGVfb3JpZ2luYWwgPC0gb3JpZ2luYWxfbmFtZXNbc3RhdGVfaWR4XQ0KICBjb3VudHlfb3JpZ2luYWwgPC0gb3JpZ2luYWxfbmFtZXNbY291bnR5X2lkeF0NCg0KICBkYXRhICU+JQ0KICAgIG11dGF0ZSgNCiAgICAgIFN0YXRlID0gc3RyaW5ncjo6c3RyX3NxdWlzaChhcy5jaGFyYWN0ZXIoLmRhdGFbW3N0YXRlX29yaWdpbmFsXV0pKSwNCiAgICAgIENvdW50eSA9IHN0cmluZ3I6OnN0cl9zcXVpc2goYXMuY2hhcmFjdGVyKC5kYXRhW1tjb3VudHlfb3JpZ2luYWxdXSkpDQogICAgKSAlPiUNCiAgICBtdXRhdGUoDQogICAgICBDb3VudHlfa2V5ID0gcGFzdGUoDQogICAgICAgIG5vcm1hbGl6ZV9zdGF0ZShTdGF0ZSksDQogICAgICAgIG5vcm1hbGl6ZV9jb3VudHkoQ291bnR5KSwNCiAgICAgICAgc2VwID0gInwiDQogICAgICApDQogICAgKQ0KfQ0KDQpudW1lcmljX3ZhbHVlIDwtIGZ1bmN0aW9uKHgpIHsNCiAgcmVhZHI6OnBhcnNlX251bWJlcihhcy5jaGFyYWN0ZXIoeCksIG5hID0gYygiIiwgIk5BIiwgIk4vQSIsICItIiwgIuKAlCIpKQ0KfQ0KDQptYWtlX29uZV92YXJpYWJsZSA8LSBmdW5jdGlvbihmaWxlbmFtZSwgb3V0cHV0X25hbWUsIHBhdHRlcm5zLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVxdWlyZWQgPSBGQUxTRSwgdHJhbnNmb3JtID0gaWRlbnRpdHkpIHsNCiAgcmF3IDwtIHJlYWRfcHJvamVjdF9jc3YoZmlsZW5hbWUpDQogIGdlbyA8LSBzdGFuZGFyZGl6ZV9nZW8ocmF3LCBmaWxlbmFtZSkNCiAgdmFsdWVfY29sIDwtIGZpbmRfY29sdW1uKA0KICAgIGdlbywgcGF0dGVybnMsIHJlcXVpcmVkID0gcmVxdWlyZWQsDQogICAgbGFiZWwgPSBwYXN0ZShvdXRwdXRfbmFtZSwgImluIiwgZmlsZW5hbWUpDQogICkNCg0KICBpZiAoaXMubmEodmFsdWVfY29sKSkgew0KICAgIG1lc3NhZ2UoIk9wdGlvbmFsIHZhcmlhYmxlIG5vdCBmb3VuZDsgb21pdHRlZDogIiwgb3V0cHV0X25hbWUsDQogICAgICAgICAgICAiICgiLCBmaWxlbmFtZSwgIikiKQ0KICAgIHJldHVybihOVUxMKQ0KICB9DQoNCiAgbWVzc2FnZSgiTWFwcGVkICIsIG91dHB1dF9uYW1lLCAiIGZyb20gIiwgZmlsZW5hbWUsICIgY29sdW1uOiAiLCB2YWx1ZV9jb2wpDQoNCiAgZ2VvICU+JQ0KICAgIHRyYW5zbXV0ZSgNCiAgICAgIFN0YXRlLCBDb3VudHlfa2V5LA0KICAgICAgISFvdXRwdXRfbmFtZSA6PSB0cmFuc2Zvcm0obnVtZXJpY192YWx1ZSguZGF0YVtbdmFsdWVfY29sXV0pKQ0KICAgICkgJT4lDQogICAgZGlzdGluY3QoU3RhdGUsIENvdW50eV9rZXksIC5rZWVwX2FsbCA9IFRSVUUpDQp9DQpgYGANCg0KIyMgNC41IENvbnN0cnVjdGluZyB0aGUgQ291bnR5LUxldmVsIEFuYWx5dGljYWwgRGF0YXNldA0KDQpgYGB7ciBidWlsZC1kYXRhc2V0fQ0KIyBPdXRjb21lOiBhdmVyYWdlIG9mIHRoZSBtYWxlIGFuZCBmZW1hbGUgMjAwOSBvYmVzaXR5IGVzdGltYXRlcy4NCm9iZXNpdHlfcmF3IDwtIHJlYWRfcHJvamVjdF9jc3YoIklITUVfT2Jlc2l0eS5jc3YiKQ0Kb2Jlc2l0eV9nZW8gPC0gc3RhbmRhcmRpemVfZ2VvKG9iZXNpdHlfcmF3LCAiSUhNRV9PYmVzaXR5LmNzdiIpDQoNCm1hbGVfb2Jlc2l0eV9jb2wgPC0gZmluZF9jb2x1bW4oDQogIG9iZXNpdHlfZ2VvLCAiXk1hbGUgb2Jlc2l0eSBwcmV2YWxlbmNlLCAyMDA5IiwNCiAgbGFiZWwgPSAibWFsZSAyMDA5IG9iZXNpdHkgcHJldmFsZW5jZSINCikNCmZlbWFsZV9vYmVzaXR5X2NvbCA8LSBmaW5kX2NvbHVtbigNCiAgb2Jlc2l0eV9nZW8sICJeRmVtYWxlXFxzK29iZXNpdHlcXHMrcHJldmFsZW5jZSxcXHMqMjAwOSIsDQogIGxhYmVsID0gImZlbWFsZSAyMDA5IG9iZXNpdHkgcHJldmFsZW5jZSINCikNCg0Kb2Jlc2l0eV9kYXRhIDwtIG9iZXNpdHlfZ2VvICU+JQ0KICB0cmFuc211dGUoDQogICAgU3RhdGUsIENvdW50eV9rZXksDQogICAgbWFsZV9vYmVzaXR5XzIwMDkgPSBudW1lcmljX3ZhbHVlKC5kYXRhW1ttYWxlX29iZXNpdHlfY29sXV0pLA0KICAgIGZlbWFsZV9vYmVzaXR5XzIwMDkgPSBudW1lcmljX3ZhbHVlKC5kYXRhW1tmZW1hbGVfb2Jlc2l0eV9jb2xdXSksDQogICAgYWR1bHRfb2Jlc2l0eSA9IHJvd01lYW5zKA0KICAgICAgY2JpbmQoDQogICAgICAgIG51bWVyaWNfdmFsdWUoLmRhdGFbW21hbGVfb2Jlc2l0eV9jb2xdXSksDQogICAgICAgIG51bWVyaWNfdmFsdWUoLmRhdGFbW2ZlbWFsZV9vYmVzaXR5X2NvbF1dKQ0KICAgICAgKSwNCiAgICAgIG5hLnJtID0gVFJVRQ0KICAgICkNCiAgKSAlPiUNCiAgbXV0YXRlKA0KICAgIGFkdWx0X29iZXNpdHkgPSBpZmVsc2UoaXMubmFuKGFkdWx0X29iZXNpdHkpLCBOQV9yZWFsXywgYWR1bHRfb2Jlc2l0eSkNCiAgKSAlPiUNCiAgZGlzdGluY3QoU3RhdGUsIENvdW50eV9rZXksIC5rZWVwX2FsbCA9IFRSVUUpDQoNCiMgUGh5c2ljYWwgaW5hY3Rpdml0eTogY29tcGxlbWVudCBvZiBzdWZmaWNpZW50IHBoeXNpY2FsIGFjdGl2aXR5IHByZXZhbGVuY2UuDQphY3Rpdml0eV9yYXcgPC0gcmVhZF9wcm9qZWN0X2NzdigiSUhNRV9QaHlzaWNhbEFjdGl2aXR5LmNzdiIpDQphY3Rpdml0eV9nZW8gPC0gc3RhbmRhcmRpemVfZ2VvKGFjdGl2aXR5X3JhdywgIklITUVfUGh5c2ljYWxBY3Rpdml0eS5jc3YiKQ0KDQptYWxlX2FjdGl2aXR5X2NvbCA8LSBmaW5kX2NvbHVtbigNCiAgYWN0aXZpdHlfZ2VvLA0KICAiXk1hbGVcXHMrc3VmZmljaWVudFxccytwaHlzaWNhbFxccythY3Rpdml0eVxccytwcmV2YWxlbmNlLFxccyoyMDA5IiwNCiAgbGFiZWwgPSAibWFsZSAyMDA5IHN1ZmZpY2llbnQgcGh5c2ljYWwgYWN0aXZpdHkiDQopDQpmZW1hbGVfYWN0aXZpdHlfY29sIDwtIGZpbmRfY29sdW1uKA0KICBhY3Rpdml0eV9nZW8sDQogICJeRmVtYWxlXFxzK3N1ZmZpY2llbnRcXHMrcGh5c2ljYWxcXHMrYWN0aXZpdHlcXHMrcHJldmFsZW5jZSxcXHMqMjAwOSIsDQogIGxhYmVsID0gImZlbWFsZSAyMDA5IHN1ZmZpY2llbnQgcGh5c2ljYWwgYWN0aXZpdHkiDQopDQoNCmFjdGl2aXR5X2RhdGEgPC0gYWN0aXZpdHlfZ2VvICU+JQ0KICB0cmFuc211dGUoDQogICAgU3RhdGUsIENvdW50eV9rZXksDQogICAgcGh5c2ljYWxfaW5hY3Rpdml0eSA9IDEwMCAtIHJvd01lYW5zKA0KICAgICAgY2JpbmQoDQogICAgICAgIG51bWVyaWNfdmFsdWUoLmRhdGFbW21hbGVfYWN0aXZpdHlfY29sXV0pLA0KICAgICAgICBudW1lcmljX3ZhbHVlKC5kYXRhW1tmZW1hbGVfYWN0aXZpdHlfY29sXV0pDQogICAgICApLA0KICAgICAgbmEucm0gPSBUUlVFDQogICAgKQ0KICApICU+JQ0KICBtdXRhdGUoDQogICAgcGh5c2ljYWxfaW5hY3Rpdml0eSA9IGlmZWxzZSgNCiAgICAgIGlzLm5hbihwaHlzaWNhbF9pbmFjdGl2aXR5KSwgTkFfcmVhbF8sIHBoeXNpY2FsX2luYWN0aXZpdHkNCiAgICApDQogICkgJT4lDQogIGRpc3RpbmN0KFN0YXRlLCBDb3VudHlfa2V5LCAua2VlcF9hbGwgPSBUUlVFKQ0KDQojIEFkZGl0aW9uYWwgY2FuZGlkYXRlIG1lYXN1cmVzLiBBIHNvdXJjZSB2YXJpYWJsZSBpcyBpbmNsdWRlZCBvbmx5IHdoZW4gYQ0KIyBjb3JyZXNwb25kaW5nIGNvdW50eS1sZXZlbCBjb2x1bW4gY2FuIGJlIGlkZW50aWZpZWQuDQpvcHRpb25hbF9zb3VyY2VzIDwtIGxpc3QoDQogIG1ha2Vfb25lX3ZhcmlhYmxlKA0KICAgICJBbGNvaG9sQ29uc3VtcHRpb24uY3N2IiwgImFsY29ob2xfdXNlIiwNCiAgICBjKCJeSHZ5JCIsICJoZWF2eS4qKHByZXZhbGVuY2V8cmF0ZSkiLCAiaGVhdnkgZHJpbmtpbmciKQ0KICApLA0KICBtYWtlX29uZV92YXJpYWJsZSgNCiAgICAiRWR1Y2F0aW9uLmNzdiIsICJjb2xsZWdlX2VkdWNhdGlvbiIsDQogICAgYygiXkNvbGxlZ2UkIiwgImJhY2hlbG9yIiwgImNvbGxlZ2UuKnBlcmNlbnQiLCAiY29sbGVnZS4qcmF0ZSIpDQogICksDQogIG1ha2Vfb25lX3ZhcmlhYmxlKA0KICAgICJVbmVtcGxveW1lbnQuY3N2IiwgInVuZW1wbG95bWVudCIsDQogICAgYygiXlVuZW1wbG95bWVudF9yYXRlXzIwMTkkIiwgIl5VbmVtcGxveW1lbnQkIiwgInVuZW1wbG95bWVudC4qMjAxOSIpDQogICksDQogIG1ha2Vfb25lX3ZhcmlhYmxlKA0KICAgICJXZWFsdGguY3N2IiwgIm1lZGlhbl9pbmNvbWUiLA0KICAgIGMoIl5JbmNvbWUkIiwgIm1lZGlhbiBob3VzZWhvbGQgaW5jb21lIiwgIm1lZGlhbi4qaW5jb21lIiwgIndlYWx0aCIpDQogICksDQogIG1ha2Vfb25lX3ZhcmlhYmxlKA0KICAgICJGb29kSW5zZWN1cml0eS5jc3YiLCAiZm9vZF9pbnNlY3VyaXR5IiwNCiAgICBjKCJeRm9vZEluc2VjdXJpdHkkIiwgImZvb2QgaW5zZWN1cml0eS4qKHJhdGV8cGVyY2VudHxwY3QpPyIsDQogICAgICAiZm9vZCBpbnNlY3VyaXR5IikNCiAgKSwNCiAgbWFrZV9vbmVfdmFyaWFibGUoDQogICAgIlN1bmxpZ2h0LmNzdiIsICJzdW5saWdodCIsDQogICAgYygiXlN1biQiLCAiQXZnIERhaWx5IFN1bmxpZ2h0IiwgImF2ZXJhZ2VfZGFpbHlfc3VubGlnaHQiLA0KICAgICAgImF2ZXJhZ2UgZGFpbHkgc3VubGlnaHQiKQ0KICApLA0KICBtYWtlX29uZV92YXJpYWJsZSgNCiAgICAiRW52aXJvbm1lbnRhbFF1YWxpdHlJbmRleC5jc3YiLCAiZW52aXJvbm1lbnRhbF9xdWFsaXR5IiwNCiAgICBjKCJeRVFJJCIsICJlbnZpcm9ubWVudGFsIHF1YWxpdHkgaW5kZXgiKQ0KICApLA0KICBtYWtlX29uZV92YXJpYWJsZSgNCiAgICAicG9wdWxhdGlvbi5jc3YiLCAicG9wdWxhdGlvbiIsDQogICAgYygiXlBvcHVsYXRpb24kIiwgIlBPUEVTVElNQVRFMjAxOSIsICJwb3B1bGF0aW9uLioyMDE5IikNCiAgKQ0KKQ0KDQpvcHRpb25hbF9zb3VyY2VzIDwtIG9wdGlvbmFsX3NvdXJjZXNbIXZhcHBseShvcHRpb25hbF9zb3VyY2VzLCBpcy5udWxsLCBsb2dpY2FsKDEpKV0NCg0KYW5hbHlzaXNfZGF0YSA8LSBvYmVzaXR5X2RhdGEgJT4lDQogIGxlZnRfam9pbihhY3Rpdml0eV9kYXRhLCBieSA9IGMoIlN0YXRlIiwgIkNvdW50eV9rZXkiKSkNCg0KZm9yIChzb3VyY2VfZGF0YSBpbiBvcHRpb25hbF9zb3VyY2VzKSB7DQogIGFuYWx5c2lzX2RhdGEgPC0gYW5hbHlzaXNfZGF0YSAlPiUNCiAgICBsZWZ0X2pvaW4oc291cmNlX2RhdGEsIGJ5ID0gYygiU3RhdGUiLCAiQ291bnR5X2tleSIpKQ0KfQ0KDQphbmFseXNpc19kYXRhIDwtIGFuYWx5c2lzX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBsb2dfcG9wdWxhdGlvbiA9IGlmICgicG9wdWxhdGlvbiIgJWluJSBuYW1lcyguKSkgew0KICAgICAgaWZlbHNlKHBvcHVsYXRpb24gPiAwLCBsb2cocG9wdWxhdGlvbiksIE5BX3JlYWxfKQ0KICAgIH0gZWxzZSB7DQogICAgICBOQV9yZWFsXw0KICAgIH0NCiAgKQ0KDQojIEtlZXAgY291bnRpZXMgd2l0aCBhIHZhbGlkIG91dGNvbWUuDQphbmFseXNpc19kYXRhIDwtIGFuYWx5c2lzX2RhdGEgJT4lDQogIGZpbHRlcihpcy5maW5pdGUoYWR1bHRfb2Jlc2l0eSkpDQoNCiMgTWVyZ2UgZGlhZ25vc3RpY3MuDQptZXJnZV9zdW1tYXJ5IDwtIHRpYmJsZSgNCiAgTWVhc3VyZSA9IGMoDQogICAgIkNvdW50aWVzIHdpdGggb2Jlc2l0eSBvdXRjb21lIiwNCiAgICAiQ291bnRpZXMgd2l0aCBwaHlzaWNhbCBpbmFjdGl2aXR5IiwNCiAgICAiQ291bnRpZXMgd2l0aCBtaXNzaW5nIHBoeXNpY2FsIGluYWN0aXZpdHkiDQogICksDQogIENvdW50ID0gYygNCiAgICBucm93KGFuYWx5c2lzX2RhdGEpLA0KICAgIHN1bSghaXMubmEoYW5hbHlzaXNfZGF0YSRwaHlzaWNhbF9pbmFjdGl2aXR5KSksDQogICAgc3VtKGlzLm5hKGFuYWx5c2lzX2RhdGEkcGh5c2ljYWxfaW5hY3Rpdml0eSkpDQogICkNCikNCg0Ka25pdHI6OmthYmxlKA0KICBtZXJnZV9zdW1tYXJ5LA0KICBjYXB0aW9uID0gIkNvdW50eS1sZXZlbCBkYXRhIGF2YWlsYWJpbGl0eSBhZnRlciBtZXJnaW5nIg0KKSAlPiUNCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UpDQoNCiMgU2hvdyBhdmFpbGFibGUgdmFyaWFibGVzIGFuZCB0aGVpciBtaXNzaW5nbmVzcy4NCm1pc3NpbmduZXNzX3RhYmxlIDwtIHRpYmJsZSgNCiAgVmFyaWFibGUgPSBuYW1lcyhhbmFseXNpc19kYXRhKSwNCiAgTm9uX01pc3NpbmcgPSB2YXBwbHkoYW5hbHlzaXNfZGF0YSwgZnVuY3Rpb24oeCkgc3VtKCFpcy5uYSh4KSksIGludGVnZXIoMSkpLA0KICBNaXNzaW5nID0gdmFwcGx5KGFuYWx5c2lzX2RhdGEsIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSksIGludGVnZXIoMSkpDQopDQoNCmtuaXRyOjprYWJsZSgNCiAgbWlzc2luZ25lc3NfdGFibGUsDQogIGNhcHRpb24gPSAiTWlzc2luZy12YWx1ZSBzdW1tYXJ5IGZvciB0aGUgbWVyZ2VkIGFuYWx5dGljYWwgZGF0YXNldCINCikgJT4lDQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFKQ0KYGBgDQoNCiMjIDQuNiBEYXRhIFF1YWxpdHkgYW5kIEFuYWx5c2lzIFNhbXBsZQ0KDQpUaGUgbnVtYmVyIG9mIGNvdW50aWVzIGF2YWlsYWJsZSBmb3IgZWFjaCBtZWFzdXJlIG1heSBkaWZmZXIgYmVjYXVzZSB0aGUgc291cmNlIGRhdGFzZXRzIG1heSBoYXZlIGRpZmZlcmVudCBnZW9ncmFwaGljIGNvdmVyYWdlIGFuZCBtaXNzaW5nIHZhbHVlcy4gVGhlIHJlZ3Jlc3Npb24gc2FtcGxlIGlzIHRoZXJlZm9yZSBkZWZpbmVkIGJ5IHRoZSBvYnNlcnZhdGlvbnMgd2l0aCBjb21wbGV0ZSBkYXRhIGZvciB0aGUgb3V0Y29tZSBhbmQgdGhlIHByZWRpY3RvcnMgaW5jbHVkZWQgaW4gdGhlIGZpbmFsIG1vZGVsLiBUaGUgZmluYWwgcGFwZXIgc2hvdWxkIHJlcG9ydCB0aGlzIHNhbXBsZSBzaXplIGFuZCBzaG91bGQgbm90IGltcGx5IHRoYXQgZXZlcnkgbW9kZWwgdXNlcyBhbGwgVS5TLiBjb3VudGllcy4NCg0KYGBge3IgZGF0YS1xdWFsaXR5fQ0Kc3VtbWFyeShhbmFseXNpc19kYXRhJGFkdWx0X29iZXNpdHkpDQoNCmNvdW50eV9jb3VudHMgPC0gYW5hbHlzaXNfZGF0YSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGNvdW50aWVzID0gbigpLA0KICAgIHN0YXRlcyA9IG5fZGlzdGluY3QoU3RhdGUpLA0KICAgIG1lYW5fb2Jlc2l0eSA9IG1lYW4oYWR1bHRfb2Jlc2l0eSwgbmEucm0gPSBUUlVFKSwNCiAgICBzZF9vYmVzaXR5ID0gc2QoYWR1bHRfb2Jlc2l0eSwgbmEucm0gPSBUUlVFKSwNCiAgICBtaW5fb2Jlc2l0eSA9IG1pbihhZHVsdF9vYmVzaXR5LCBuYS5ybSA9IFRSVUUpLA0KICAgIG1lZGlhbl9vYmVzaXR5ID0gbWVkaWFuKGFkdWx0X29iZXNpdHksIG5hLnJtID0gVFJVRSksDQogICAgbWF4X29iZXNpdHkgPSBtYXgoYWR1bHRfb2Jlc2l0eSwgbmEucm0gPSBUUlVFKQ0KICApDQoNCmtuaXRyOjprYWJsZSgNCiAgY291bnR5X2NvdW50cywNCiAgZGlnaXRzID0gMiwNCiAgY2FwdGlvbiA9ICJTdW1tYXJ5IG9mIHRoZSBjb3VudHktbGV2ZWwgb2Jlc2l0eSBvdXRjb21lIg0KKSAlPiUNCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UpDQpgYGANCg0KIyA1LiBNZXRob2RvbG9neQ0KDQojIyA1LjEgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcw0KDQpFeHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzIGlzIHVzZWQgdG8gZGVzY3JpYmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhZHVsdCBvYmVzaXR5IHByZXZhbGVuY2UgYW5kIGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcHMgYW1vbmcgdGhlIG91dGNvbWUgYW5kIGF2YWlsYWJsZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMuIERlc2NyaXB0aXZlIHN0YXRpc3RpY3MgYW5kIHZpc3VhbGl6YXRpb25zIGFyZSByZXZpZXdlZCBiZWZvcmUgZml0dGluZyByZWdyZXNzaW9uIG1vZGVscy4NCg0KYGBge3Igb2Jlc2l0eS1kaXN0cmlidXRpb259DQpnZ3Bsb3QoYW5hbHlzaXNfZGF0YSwgYWVzKHggPSBhZHVsdF9vYmVzaXR5KSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzAsIGNvbG9yID0gIndoaXRlIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBDb3VudHktTGV2ZWwgQWR1bHQgT2Jlc2l0eSBQcmV2YWxlbmNlIiwNCiAgICB4ID0gIkFkdWx0IG9iZXNpdHkgcHJldmFsZW5jZSAoJSkiLA0KICAgIHkgPSAiTnVtYmVyIG9mIGNvdW50aWVzIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KYGBge3Igc3RhdGUtZGlzdHJpYnV0aW9ufQ0Kc3RhdGVfc3VtbWFyeSA8LSBhbmFseXNpc19kYXRhICU+JQ0KICBncm91cF9ieShTdGF0ZSkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBjb3VudGllcyA9IG4oKSwNCiAgICBtZWFuX29iZXNpdHkgPSBtZWFuKGFkdWx0X29iZXNpdHksIG5hLnJtID0gVFJVRSksDQogICAgbWVkaWFuX29iZXNpdHkgPSBtZWRpYW4oYWR1bHRfb2Jlc2l0eSwgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiDQogICkgJT4lDQogIGFycmFuZ2UoZGVzYyhtZWFuX29iZXNpdHkpKQ0KDQprbml0cjo6a2FibGUoDQogIGhlYWQoc3RhdGVfc3VtbWFyeSwgMTUpLA0KICBkaWdpdHMgPSAyLA0KICBjYXB0aW9uID0gIlN0YXRlcyB3aXRoIHRoZSBoaWdoZXN0IG1lYW4gY291bnR5LWxldmVsIG9iZXNpdHkgcHJldmFsZW5jZSAodG9wIDE1KSINCikgJT4lDQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFKQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpzdGF0ZV9leHRyZW1lcyA8LSBiaW5kX3Jvd3MoDQogIHN0YXRlX3N1bW1hcnkgJT4lDQogICAgc2xpY2VfbWF4KG1lYW5fb2Jlc2l0eSwgbiA9IDEwKSAlPiUNCiAgICBtdXRhdGUoR3JvdXAgPSAiSGlnaGVzdCIpLA0KDQogIHN0YXRlX3N1bW1hcnkgJT4lDQogICAgc2xpY2VfbWluKG1lYW5fb2Jlc2l0eSwgbiA9IDEwKSAlPiUNCiAgICBtdXRhdGUoR3JvdXAgPSAiTG93ZXN0IikNCikgJT4lDQogIGFycmFuZ2UobWVhbl9vYmVzaXR5KSAlPiUNCiAgbXV0YXRlKFN0YXRlID0gZmFjdG9yKFN0YXRlLCBsZXZlbHMgPSBTdGF0ZSkpDQoNCmdncGxvdChzdGF0ZV9leHRyZW1lcywNCiAgICAgICBhZXMoeCA9IFN0YXRlLCB5ID0gbWVhbl9vYmVzaXR5LCBmaWxsID0gR3JvdXApKSArDQogIGdlb21fY29sKHdpZHRoID0gMC43KSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiU3RhdGVzIHdpdGggdGhlIEhpZ2hlc3QgYW5kIExvd2VzdCBNZWFuIENvdW50eSBPYmVzaXR5IiwNCiAgICB4ID0gTlVMTCwNCiAgICB5ID0gIk1lYW4gY291bnR5IG9iZXNpdHkgcHJldmFsZW5jZSAoJSkiLA0KICAgIGZpbGwgPSAiU3RhdGUgZ3JvdXAiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSINCiAgKQ0KYGBgDQoNCiMjIDUuMiBDb3JyZWxhdGlvbiBBbmFseXNpcw0KDQpQZWFyc29uIGNvcnJlbGF0aW9ucyBhcmUgdXNlZCBhcyBhbiBleHBsb3JhdG9yeSBtZWFzdXJlIG9mIGxpbmVhciBhc3NvY2lhdGlvbiBhbW9uZyBudW1lcmljIHZhcmlhYmxlcy4gQ29ycmVsYXRpb24gZG9lcyBub3QgZXN0YWJsaXNoIGNhdXNhdGlvbiBhbmQgZG9lcyBub3QgYWNjb3VudCBmb3Igb3RoZXIgdmFyaWFibGVzIGluIHRoZSBtb2RlbC4NCg0KYGBge3IgY29ycmVsYXRpb24tYW5hbHlzaXN9DQpudW1lcmljX2RhdGEgPC0gYW5hbHlzaXNfZGF0YSAlPiUNCiAgc2VsZWN0KHdoZXJlKGlzLm51bWVyaWMpKSAlPiUNCiAgc2VsZWN0KHdoZXJlKH4gc3VtKCFpcy5uYSgueCkpID4gMTApKQ0KDQpjb3JyZWxhdGlvbl9tYXRyaXggPC0gY29yKA0KICBudW1lcmljX2RhdGEsDQogIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiDQopDQoNCmNvcnJwbG90X2F2YWlsYWJsZSA8LSByZXF1aXJlTmFtZXNwYWNlKCJjb3JycGxvdCIsIHF1aWV0bHkgPSBUUlVFKQ0KDQppZiAoY29ycnBsb3RfYXZhaWxhYmxlKSB7DQogIGNvcnJwbG90Ojpjb3JycGxvdCgNCiAgICBjb3JyZWxhdGlvbl9tYXRyaXgsDQogICAgbWV0aG9kID0gImNvbG9yIiwNCiAgICB0eXBlID0gInVwcGVyIiwNCiAgICB0bC5jb2wgPSAiYmxhY2siLA0KICAgIHRsLmNleCA9IDAuNzUsDQogICAgYWRkQ29lZi5jb2wgPSAiYmxhY2siLA0KICAgIG51bWJlci5jZXggPSAwLjUNCiAgKQ0KfSBlbHNlIHsNCiAga25pdHI6OmthYmxlKA0KICAgIHJvdW5kKGNvcnJlbGF0aW9uX21hdHJpeCwgMiksDQogICAgY2FwdGlvbiA9ICJQZWFyc29uIGNvcnJlbGF0aW9uIG1hdHJpeCINCiAgKQ0KfQ0KYGBgDQoNCiMjIDUuMyBNdWx0aXBsZSBMaW5lYXIgUmVncmVzc2lvbg0KDQpUaGUgYmFzZWxpbmUgbW9kZWwgdXNlcyBhZHVsdCBvYmVzaXR5IHByZXZhbGVuY2UgYXMgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBhbmQgdGhlIGF2YWlsYWJsZSBjb3VudHktbGV2ZWwgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGFzIHByZWRpY3RvcnMuIFRoZSBtb2RlbCBpcyBzcGVjaWZpZWQgdXNpbmcgdGhlIHByZWRpY3RvcnMgdGhhdCBhcmUgc3VjY2Vzc2Z1bGx5IGlkZW50aWZpZWQgaW4gdGhlIHJlcG9zaXRvcnkgYW5kIGhhdmUgc3VmZmljaWVudCBub24tbWlzc2luZyBvYnNlcnZhdGlvbnMuDQoNClRoZSBnZW5lcmFsIG1vZGVsIGlzOg0KDQpcWw0KT2Jlc2l0eV9pID0gXGJldGFfMCArIFxzdW1fe2s9MX1ee0t9XGJldGFfayBYX3traX0gKyBcZXBzaWxvbl9pDQpcXQ0KDQp3aGVyZSBcKE9iZXNpdHlfaVwpIGlzIHRoZSBhZHVsdCBvYmVzaXR5IHByZXZhbGVuY2UgbWVhc3VyZSBmb3IgY291bnR5IFwoaVwpLCBcKFhfe2tpfVwpIHJlcHJlc2VudHMgdGhlIG1lYXN1cmVkIGNvdW50eS1sZXZlbCBjaGFyYWN0ZXJpc3RpY3MsIGFuZCBcKFxlcHNpbG9uX2lcKSBpcyB0aGUgZXJyb3IgdGVybS4NCg0KDQpgYGB7ciBtb2RlbC1lc3RpbWF0aW9ufQ0KY2FuZGlkYXRlX3ByZWRpY3RvcnMgPC0gYygNCiAgInBoeXNpY2FsX2luYWN0aXZpdHkiLA0KICAiYWxjb2hvbF91c2UiLA0KICAiY29sbGVnZV9lZHVjYXRpb24iLA0KICAidW5lbXBsb3ltZW50IiwNCiAgIm1lZGlhbl9pbmNvbWUiLA0KICAiZm9vZF9pbnNlY3VyaXR5IiwNCiAgInN1bmxpZ2h0IiwNCiAgImVudmlyb25tZW50YWxfcXVhbGl0eSIsDQogICJwb3B1bGF0aW9uIg0KKQ0KDQojIElkZW50aWZ5IHByZWRpY3RvcnMgYXZhaWxhYmxlIGluIHRoZSBkYXRhc2V0DQpleGlzdGluZ19wcmVkaWN0b3JzIDwtIGludGVyc2VjdCgNCiAgY2FuZGlkYXRlX3ByZWRpY3RvcnMsDQogIG5hbWVzKGFuYWx5c2lzX2RhdGEpDQopDQoNCiMgQ2hlY2sgcHJlZGljdG9yIHF1YWxpdHkNCnByZWRpY3Rvcl9kaWFnbm9zdGljcyA8LSBwdXJycjo6bWFwX2RmcigNCiAgZXhpc3RpbmdfcHJlZGljdG9ycywNCiAgZnVuY3Rpb24odikgew0KDQogICAgeCA8LSBhbmFseXNpc19kYXRhW1t2XV0NCg0KICAgIHRpYmJsZSgNCiAgICAgIFZhcmlhYmxlID0gdiwNCiAgICAgIE5vbl9NaXNzaW5nID0gc3VtKCFpcy5uYSh4KSksDQogICAgICBEaXN0aW5jdF9WYWx1ZXMgPSBkcGx5cjo6bl9kaXN0aW5jdCh4LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgRGF0YV9UeXBlID0gY2xhc3MoeClbMV0NCiAgICApDQogIH0NCikNCg0Ka25pdHI6OmthYmxlKA0KICBwcmVkaWN0b3JfZGlhZ25vc3RpY3MsDQogIGNhcHRpb24gPSAiUmVncmVzc2lvbiBwcmVkaWN0b3IgZGlhZ25vc3RpY3MiDQopICU+JQ0KICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSkNCg0KIyBTZWxlY3QgdXNhYmxlIG51bWVyaWNhbCBwcmVkaWN0b3JzDQphdmFpbGFibGVfcHJlZGljdG9ycyA8LSBwcmVkaWN0b3JfZGlhZ25vc3RpY3MgJT4lDQogIGZpbHRlcigNCiAgICBOb25fTWlzc2luZyA+PSAxMDAsDQogICAgRGlzdGluY3RfVmFsdWVzID4gMSwNCiAgICBEYXRhX1R5cGUgJWluJSBjKCJudW1lcmljIiwgImludGVnZXIiKQ0KICApICU+JQ0KICBwdWxsKFZhcmlhYmxlKQ0KDQpjYXQoIlVzYWJsZSBwcmVkaWN0b3JzOiIsDQogICAgcGFzdGUoYXZhaWxhYmxlX3ByZWRpY3RvcnMsIGNvbGxhcHNlID0gIiwgIikpDQoNCmlmIChsZW5ndGgoYXZhaWxhYmxlX3ByZWRpY3RvcnMpIDwgMykgew0KICBzdG9wKA0KICAgICJGZXdlciB0aGFuIHRocmVlIHVzYWJsZSBwcmVkaWN0b3JzLiAiLA0KICAgICJSZXZpZXcgdGhlIGRpYWdub3N0aWMgdGFibGUgYmVmb3JlIGNvbnRpbnVpbmcuIg0KICApDQp9DQoNCiMgQ3JlYXRlIGNvbXBsZXRlLWNhc2UgcmVncmVzc2lvbiBkYXRhc2V0DQptb2RlbF92YXJpYWJsZXMgPC0gYygNCiAgImFkdWx0X29iZXNpdHkiLA0KICAiU3RhdGUiLA0KICAiQ291bnR5X2tleSIsDQogIGF2YWlsYWJsZV9wcmVkaWN0b3JzDQopDQoNCm1vZGVsX2RhdGEgPC0gYW5hbHlzaXNfZGF0YSAlPiUNCiAgc2VsZWN0KGFsbF9vZihtb2RlbF92YXJpYWJsZXMpKSAlPiUNCiAgZHJvcF9uYSgpICU+JQ0KICBtdXRhdGUoU3RhdGUgPSBmYWN0b3IoU3RhdGUpKQ0KDQppZiAobnJvdyhtb2RlbF9kYXRhKSA8IDEwMCkgew0KICBzdG9wKCJSZWdyZXNzaW9uIHNhbXBsZSBjb250YWlucyBmZXdlciB0aGFuIDEwMCBjb3VudGllcy4iKQ0KfQ0KDQojIEJhc2VsaW5lIE9MUyBtb2RlbA0KYmFzZWxpbmVfZm9ybXVsYSA8LSBhcy5mb3JtdWxhKA0KICBwYXN0ZSgNCiAgICAiYWR1bHRfb2Jlc2l0eSB+IiwNCiAgICBwYXN0ZShhdmFpbGFibGVfcHJlZGljdG9ycywgY29sbGFwc2UgPSAiICsgIikNCiAgKQ0KKQ0KDQptb2RlbF9vbHMgPC0gbG0oDQogIGJhc2VsaW5lX2Zvcm11bGEsDQogIGRhdGEgPSBtb2RlbF9kYXRhDQopDQoNCiMgU3RhdGUgZml4ZWQtZWZmZWN0cyBtb2RlbA0Kc3RhdGVfZm9ybXVsYSA8LSBhcy5mb3JtdWxhKA0KICBwYXN0ZSgNCiAgICAiYWR1bHRfb2Jlc2l0eSB+IiwNCiAgICBwYXN0ZShhdmFpbGFibGVfcHJlZGljdG9ycywgY29sbGFwc2UgPSAiICsgIiksDQogICAgIisgU3RhdGUiDQogICkNCikNCg0KbW9kZWxfc3RhdGUgPC0gbG0oDQogIHN0YXRlX2Zvcm11bGEsDQogIGRhdGEgPSBtb2RlbF9kYXRhDQopDQoNCmNhdCgiXG5SZWdyZXNzaW9uIHNhbXBsZToiLA0KICAgIG5yb3cobW9kZWxfZGF0YSksICJjb3VudGllcyIpDQoNCmNhdCgiXG5TdGF0ZXMgcmVwcmVzZW50ZWQ6IiwNCiAgICBuX2Rpc3RpbmN0KG1vZGVsX2RhdGEkU3RhdGUpKQ0KDQpjYXQoIlxuQmFzZWxpbmUgYWRqdXN0ZWQgUi1zcXVhcmVkOiIsDQogICAgcm91bmQoc3VtbWFyeShtb2RlbF9vbHMpJGFkai5yLnNxdWFyZWQsIDQpKQ0KDQpjYXQoIlxuU3RhdGUgbW9kZWwgYWRqdXN0ZWQgUi1zcXVhcmVkOiIsDQogICAgcm91bmQoc3VtbWFyeShtb2RlbF9zdGF0ZSkkYWRqLnIuc3F1YXJlZCwgNCkpDQpgYGANCg0KDQoNCiMjIDUuNCBTdGF0ZSBGaXhlZC1FZmZlY3RzIE1vZGVsDQoNClRoZSBnZW9ncmFwaGljIG1vZGVsIGFkZHMgc3RhdGUgaW5kaWNhdG9ycyB0byB0aGUgYmFzZWxpbmUgcmVncmVzc2lvbjoNCg0KXFsNCk9iZXNpdHlfe2lzfSA9IFxiZXRhXzAgKyBcc3VtX3trPTF9XntLfVxiZXRhX2sgWF97a2lzfSArIFxnYW1tYV9zICsgXGVwc2lsb25fe2lzfQ0KXF0NCg0Kd2hlcmUgXChcZ2FtbWFfc1wpIHJlcHJlc2VudHMgdGhlIHN0YXRlIGZpeGVkIGVmZmVjdC4gT25lIHN0YXRlIGlzIHRyZWF0ZWQgYXMgdGhlIHJlZmVyZW5jZSBjYXRlZ29yeSBieSB0aGUgcmVncmVzc2lvbiBzb2Z0d2FyZS4NCg0KVGhlIHN0YXRlIGZpeGVkLWVmZmVjdHMgbW9kZWwgdGVzdHMgd2hldGhlciBzdGF0ZSBtZW1iZXJzaGlwIGFkZHMgZXhwbGFuYXRvcnkgaW5mb3JtYXRpb24gYWZ0ZXIgYWRqdXN0bWVudCBmb3IgdGhlIG1lYXN1cmVkIGNvdW50eS1sZXZlbCB2YXJpYWJsZXMuIEl0IGRvZXMgbm90IGVzdGFibGlzaCB0aGF0IHN0YXRlIGxvY2F0aW9uIGNhdXNlcyBkaWZmZXJlbmNlcyBpbiBvYmVzaXR5IHByZXZhbGVuY2UuDQoNCiMjIDUuNSBNb2RlbCBFdmFsdWF0aW9uDQoNClRoZSBtb2RlbHMgYXJlIGNvbXBhcmVkIHVzaW5nIGFkanVzdGVkIFItc3F1YXJlZCBhbmQgUk1TRS4gQSBuZXN0ZWQtbW9kZWwgRi10ZXN0IGV2YWx1YXRlcyB3aGV0aGVyIHRoZSBzdGF0ZSBpbmRpY2F0b3JzIGNvbGxlY3RpdmVseSBpbXByb3ZlIHRoZSBpbi1zYW1wbGUgZml0LiBUaGVzZSBtZWFzdXJlcyBkZXNjcmliZSBleHBsYW5hdG9yeSBwZXJmb3JtYW5jZSBpbiB0aGUgYW5hbHlzaXMgc2FtcGxlIGFuZCBzaG91bGQgbm90IGJlIGNvbmZ1c2VkIHdpdGggb3V0LW9mLXNhbXBsZSBwcmVkaWN0aXZlIHZhbGlkYXRpb24uDQoNCmBgYHtyIG1vZGVsLWNvbXBhcmlzb259DQpybXNlIDwtIGZ1bmN0aW9uKG1vZGVsKSB7DQogIHNxcnQobWVhbihyZXNpZHVhbHMobW9kZWwpXjIpKQ0KfQ0KDQptb2RlbF9jb21wYXJpc29uIDwtIHRpYmJsZSgNCiAgTW9kZWwgPSBjKCJCYXNlbGluZSBPTFMiLCAiT0xTIHdpdGggc3RhdGUgZml4ZWQgZWZmZWN0cyIpLA0KICBPYnNlcnZhdGlvbnMgPSBjKG5vYnMobW9kZWxfb2xzKSwgbm9icyhtb2RlbF9zdGF0ZSkpLA0KICBSX1NxdWFyZWQgPSBjKHN1bW1hcnkobW9kZWxfb2xzKSRyLnNxdWFyZWQsDQogICAgICAgICAgICAgICAgc3VtbWFyeShtb2RlbF9zdGF0ZSkkci5zcXVhcmVkKSwNCiAgQWRqdXN0ZWRfUl9TcXVhcmVkID0gYyhzdW1tYXJ5KG1vZGVsX29scykkYWRqLnIuc3F1YXJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICBzdW1tYXJ5KG1vZGVsX3N0YXRlKSRhZGouci5zcXVhcmVkKSwNCiAgUk1TRSA9IGMocm1zZShtb2RlbF9vbHMpLCBybXNlKG1vZGVsX3N0YXRlKSkNCikNCg0Ka25pdHI6OmthYmxlKA0KICBtb2RlbF9jb21wYXJpc29uLA0KICBkaWdpdHMgPSA0LA0KICBjYXB0aW9uID0gIkNvbXBhcmlzb24gb2YgYmFzZWxpbmUgYW5kIHN0YXRlIGZpeGVkLWVmZmVjdHMgbW9kZWxzIg0KKSAlPiUNCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UpDQoNCnN0YXRlX21vZGVsX3Rlc3QgPC0gYW5vdmEobW9kZWxfb2xzLCBtb2RlbF9zdGF0ZSkNCmtuaXRyOjprYWJsZSgNCiAgYnJvb206OnRpZHkoc3RhdGVfbW9kZWxfdGVzdCksDQogIGRpZ2l0cyA9IDQsDQogIGNhcHRpb24gPSAiTmVzdGVkLW1vZGVsIEYtdGVzdDogYWRkaXRpb25hbCBjb250cmlidXRpb24gb2Ygc3RhdGUgZml4ZWQgZWZmZWN0cyINCikgJT4lDQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFKQ0KYGBgDQoNCiMjIDUuNiBSZWdyZXNzaW9uIENvZWZmaWNpZW50cyBhbmQgVW5jZXJ0YWludHkNCg0KVGhlIGNvZWZmaWNpZW50cyBhcmUgaW50ZXJwcmV0ZWQgYXMgYWRqdXN0ZWQgY291bnR5LWxldmVsIGFzc29jaWF0aW9ucy4gQSBjb2VmZmljaWVudCByZXByZXNlbnRzIHRoZSBlc3RpbWF0ZWQgZGlmZmVyZW5jZSBpbiBhZHVsdCBvYmVzaXR5IHByZXZhbGVuY2UgYXNzb2NpYXRlZCB3aXRoIGEgb25lLXVuaXQgZGlmZmVyZW5jZSBpbiBhIHByZWRpY3RvciwgaG9sZGluZyB0aGUgb3RoZXIgaW5jbHVkZWQgdmFyaWFibGVzIGNvbnN0YW50LiBVbml0cyBtdXN0IGJlIGNvbnNpZGVyZWQgd2hlbiBpbnRlcnByZXRpbmcgdGhlIHNpemUgb2YgZWFjaCBjb2VmZmljaWVudC4NCg0KSGV0ZXJvc2NlZGFzdGljaXR5LWNvbnNpc3RlbnQgc3RhbmRhcmQgZXJyb3JzIChIQzMpIGFyZSByZXBvcnRlZCBhcyBhIHJvYnVzdG5lc3MgbWVhc3VyZS4NCg0KYGBge3IgY29lZmZpY2llbnQtcmVzdWx0c30NCnJvYnVzdF9yZXN1bHRzIDwtIGxtdGVzdDo6Y29lZnRlc3QoDQogIG1vZGVsX3N0YXRlLA0KICB2Y292LiA9IHNhbmR3aWNoOjp2Y292SEMobW9kZWxfc3RhdGUsIHR5cGUgPSAiSEMzIikNCikNCg0KY29lZmZpY2llbnRfdGFibGUgPC0gYnJvb206OnRpZHkocm9idXN0X3Jlc3VsdHMpICU+JQ0KICByZW5hbWUoDQogICAgRXN0aW1hdGUgPSBlc3RpbWF0ZSwNCiAgICBTdGRfRXJyb3JfSEMzID0gc3RkLmVycm9yLA0KICAgIHRfdmFsdWUgPSBzdGF0aXN0aWMsDQogICAgcF92YWx1ZSA9IHAudmFsdWUNCiAgKSAlPiUNCiAgbXV0YXRlKA0KICAgIENJX0xvd2VyID0gRXN0aW1hdGUgLSBxdCgwLjk3NSwgZGYucmVzaWR1YWwobW9kZWxfc3RhdGUpKSAqIFN0ZF9FcnJvcl9IQzMsDQogICAgQ0lfVXBwZXIgPSBFc3RpbWF0ZSArIHF0KDAuOTc1LCBkZi5yZXNpZHVhbChtb2RlbF9zdGF0ZSkpICogU3RkX0Vycm9yX0hDMw0KICApDQoNCmtuaXRyOjprYWJsZSgNCiAgY29lZmZpY2llbnRfdGFibGUsDQogIGRpZ2l0cyA9IDQsDQogIGNhcHRpb24gPSAiU3RhdGUgZml4ZWQtZWZmZWN0cyByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyB3aXRoIEhDMyByb2J1c3Qgc3RhbmRhcmQgZXJyb3JzIg0KKSAlPiUNCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGZvbnRfc2l6ZSA9IDExKQ0KYGBgDQoNCiMjIDUuNyBSZWdyZXNzaW9uIERpYWdub3N0aWNzDQoNClJlZ3Jlc3Npb24gZGlhZ25vc3RpY3MgYXJlIHVzZWQgdG8gZXZhbHVhdGUgd2hldGhlciB0aGUgZml0dGVkIG1vZGVscyBzaG93IGltcG9ydGFudCBkZXBhcnR1cmVzIGZyb20gdGhlIGFzc3VtcHRpb25zIG9mIGxpbmVhciByZWdyZXNzaW9uLiBUaGUgYW5hbHlzaXMgZXhhbWluZXMgcmVzaWR1YWwgcGF0dGVybnMsIGFwcHJveGltYXRlIG5vcm1hbGl0eSwgaGV0ZXJvc2NlZGFzdGljaXR5LCBhbmQgbXVsdGljb2xsaW5lYXJpdHkuIFN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBzaG91bGQgYmUgaW50ZXJwcmV0ZWQgY2F1dGlvdXNseSBiZWNhdXNlIGNvdW50aWVzIG1heSBub3QgYmUgc3RhdGlzdGljYWxseSBpbmRlcGVuZGVudC4NCg0KYGBge3IgZGlhZ25vc3RpYy1wbG90cywgZmlnLndpZHRoPTksIGZpZy5oZWlnaHQ9OH0NCm9sZF9wYXIgPC0gcGFyKG5vLnJlYWRvbmx5ID0gVFJVRSkNCnBhcihtZnJvdyA9IGMoMiwgMikpDQpwbG90KG1vZGVsX3N0YXRlKQ0KcGFyKG9sZF9wYXIpDQpgYGANCg0KYGBge3IgdmlmLWRpYWdub3N0aWNzfQ0KdmlmX3ZhbHVlcyA8LSB0cnlDYXRjaCgNCiAgY2FyOjp2aWYobW9kZWxfc3RhdGUpLA0KICBlcnJvciA9IGZ1bmN0aW9uKGUpIE5VTEwNCikNCg0KaWYgKCFpcy5udWxsKHZpZl92YWx1ZXMpKSB7DQogIGlmIChpcy5tYXRyaXgodmlmX3ZhbHVlcykpIHsNCiAgICB2aWZfb3V0cHV0IDwtIGFzLmRhdGEuZnJhbWUodmlmX3ZhbHVlcykgJT4lDQogICAgICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiVmFyaWFibGUiKQ0KICB9IGVsc2Ugew0KICAgIHZpZl9vdXRwdXQgPC0gdGliYmxlKA0KICAgICAgVmFyaWFibGUgPSBuYW1lcyh2aWZfdmFsdWVzKSwNCiAgICAgIFZJRiA9IGFzLm51bWVyaWModmlmX3ZhbHVlcykNCiAgICApDQogIH0NCg0KICBrbml0cjo6a2FibGUoDQogICAgdmlmX291dHB1dCwNCiAgICBkaWdpdHMgPSAzLA0KICAgIGNhcHRpb24gPSAiVmFyaWFuY2UgaW5mbGF0aW9uIGZhY3RvciBkaWFnbm9zdGljcyINCiAgKSAlPiUNCiAgICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSkNCn0gZWxzZSB7DQogIGNhdCgiVklGIGNvdWxkIG5vdCBiZSBjYWxjdWxhdGVkIGZvciB0aGlzIG1vZGVsIHNwZWNpZmljYXRpb24uIikNCn0NCmBgYA0KDQojIyA1LjggUmVzaWR1YWwgR2VvZ3JhcGhpYyBWYXJpYXRpb24NCg0KQSByZXNpZHVhbCBpcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIG9ic2VydmVkIGFuZCBtb2RlbC1wcmVkaWN0ZWQgb2Jlc2l0eSBwcmV2YWxlbmNlOg0KDQpcWw0KUmVzaWR1YWxfaSA9IE9ic2VydmVkX2kgLSBQcmVkaWN0ZWRfaQ0KXF0NCg0KUG9zaXRpdmUgcmVzaWR1YWxzIGluZGljYXRlIHRoYXQgdGhlIG9ic2VydmVkIGNvdW50eSBwcmV2YWxlbmNlIGlzIGhpZ2hlciB0aGFuIHRoZSBtb2RlbCBwcmVkaWN0cy4gTmVnYXRpdmUgcmVzaWR1YWxzIGluZGljYXRlIHRoYXQgb2JzZXJ2ZWQgcHJldmFsZW5jZSBpcyBsb3dlciB0aGFuIHByZWRpY3RlZC4gUmVzaWR1YWxzIGFyZSBleGFtaW5lZCB0byBpZGVudGlmeSBjb3VudGllcyB3aXRoIGxhcmdlciBkZXZpYXRpb25zIGZyb20gdGhlIG1vZGVsLg0KDQpgYGB7ciByZXNpZHVhbC1hbmFseXNpc30NCm1vZGVsX2RhdGEgPC0gbW9kZWxfZGF0YSAlPiUNCiAgbXV0YXRlKA0KICAgIGZpdHRlZF9vYmVzaXR5ID0gZml0dGVkKG1vZGVsX3N0YXRlKSwNCiAgICByZXNpZHVhbCA9IHJlc2lkdWFscyhtb2RlbF9zdGF0ZSksDQogICAgYWJzb2x1dGVfcmVzaWR1YWwgPSBhYnMocmVzaWR1YWwpDQogICkNCg0KcmVzaWR1YWxfc3VtbWFyeSA8LSBtb2RlbF9kYXRhICU+JQ0KICBzdW1tYXJpc2UoDQogICAgTWVhbl9yZXNpZHVhbCA9IG1lYW4ocmVzaWR1YWwpLA0KICAgIFNEX3Jlc2lkdWFsID0gc2QocmVzaWR1YWwpLA0KICAgIE1lYW5fYWJzb2x1dGVfcmVzaWR1YWwgPSBtZWFuKGFic29sdXRlX3Jlc2lkdWFsKSwNCiAgICBNaW5pbXVtX3Jlc2lkdWFsID0gbWluKHJlc2lkdWFsKSwNCiAgICBNYXhpbXVtX3Jlc2lkdWFsID0gbWF4KHJlc2lkdWFsKQ0KICApDQoNCmtuaXRyOjprYWJsZSgNCiAgcmVzaWR1YWxfc3VtbWFyeSwNCiAgZGlnaXRzID0gMywNCiAgY2FwdGlvbiA9ICJTdW1tYXJ5IG9mIHJlc2lkdWFscyBmcm9tIHRoZSBzdGF0ZSBmaXhlZC1lZmZlY3RzIG1vZGVsIg0KKSAlPiUNCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UpDQoNCmdncGxvdChtb2RlbF9kYXRhLCBhZXMoeCA9IGZpdHRlZF9vYmVzaXR5LCB5ID0gcmVzaWR1YWwpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjQ1KSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSZXNpZHVhbHMgVmVyc3VzIEZpdHRlZCBWYWx1ZXMiLA0KICAgIHggPSAiUHJlZGljdGVkIGFkdWx0IG9iZXNpdHkgcHJldmFsZW5jZSAoJSkiLA0KICAgIHkgPSAiUmVzaWR1YWwgKHBlcmNlbnRhZ2UgcG9pbnRzKSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpsYXJnZXN0X3Jlc2lkdWFscyA8LSBtb2RlbF9kYXRhICU+JQ0KICBtdXRhdGUoQ291bnR5ID0gYW5hbHlzaXNfZGF0YSRDb3VudHlfa2V5W21hdGNoKA0KICAgIHBhc3RlKFN0YXRlLCBDb3VudHlfa2V5KSwgcGFzdGUoYW5hbHlzaXNfZGF0YSRTdGF0ZSwgYW5hbHlzaXNfZGF0YSRDb3VudHlfa2V5KQ0KICApXSkgJT4lDQogIGFycmFuZ2UoZGVzYyhhYnNvbHV0ZV9yZXNpZHVhbCkpICU+JQ0KICBzZWxlY3QoU3RhdGUsIENvdW50eSwgYWR1bHRfb2Jlc2l0eSwgZml0dGVkX29iZXNpdHksIHJlc2lkdWFsKSAlPiUNCiAgc2xpY2VfaGVhZChuID0gMTUpDQoNCmtuaXRyOjprYWJsZSgNCiAgbGFyZ2VzdF9yZXNpZHVhbHMsDQogIGRpZ2l0cyA9IDIsDQogIGNhcHRpb24gPSAiQ291bnRpZXMgd2l0aCB0aGUgbGFyZ2VzdCBhYnNvbHV0ZSBtb2RlbCByZXNpZHVhbHMiDQopICU+JQ0KICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSkNCmBgYA0KDQojIDYuIFJlc3VsdHMNCg0KIyMgNi4xIENvdW50eS1MZXZlbCBWYXJpYXRpb24gaW4gQWR1bHQgT2Jlc2l0eQ0KDQpUaGUgZGVzY3JpcHRpdmUgYW5hbHlzaXMgcmVwb3J0cyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBjb3VudHktbGV2ZWwgYWR1bHQgb2Jlc2l0eSBvdXRjb21lLiBUaGUgZmluYWwgaW50ZXJwcmV0YXRpb24gc2hvdWxkIGRlc2NyaWJlIHRoZSByYW5nZSwgY2VudHJhbCB0ZW5kZW5jeSwgYW5kIHZhcmlhYmlsaXR5IHNob3duIGluIHRoZSBnZW5lcmF0ZWQgc3VtbWFyeSBhbmQgaGlzdG9ncmFtLg0KDQpUaGUgYW5hbHlzaXMgaW5jbHVkZXMgKipgciBucm93KGFuYWx5c2lzX2RhdGEpYCBjb3VudGllcyoqIHdpdGggYW4gYXZhaWxhYmxlIG91dGNvbWUgbWVhc3VyZS4gVGhlIG1lYW4gY291bnR5LWxldmVsIGFkdWx0IG9iZXNpdHkgcHJldmFsZW5jZSBpcyAqKmByIHJvdW5kKG1lYW4oYW5hbHlzaXNfZGF0YSRhZHVsdF9vYmVzaXR5LCBuYS5ybSA9IFRSVUUpLCAyKWAlKiosIGFuZCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIGlzICoqYHIgcm91bmQoc2QoYW5hbHlzaXNfZGF0YSRhZHVsdF9vYmVzaXR5LCBuYS5ybSA9IFRSVUUpLCAyKWAgcGVyY2VudGFnZSBwb2ludHMqKi4NCg0KIyMgNi4yIFJlZ3Jlc3Npb24gUmVzdWx0cw0KDQpUaGUgYmFzZWxpbmUgT0xTIG1vZGVsIGhhcyBhbiBhZGp1c3RlZCBSLXNxdWFyZWQgb2YgKipgciByb3VuZChzdW1tYXJ5KG1vZGVsX29scykkYWRqLnIuc3F1YXJlZCwgMylgKiouIFRoZSBzdGF0ZSBmaXhlZC1lZmZlY3RzIG1vZGVsIGhhcyBhbiBhZGp1c3RlZCBSLXNxdWFyZWQgb2YgKipgciByb3VuZChzdW1tYXJ5KG1vZGVsX3N0YXRlKSRhZGouci5zcXVhcmVkLCAzKWAqKi4gVGhlIGNvcnJlc3BvbmRpbmcgUk1TRSB2YWx1ZXMgYXJlICoqYHIgcm91bmQocm1zZShtb2RlbF9vbHMpLCAzKWAqKiBhbmQgKipgciByb3VuZChybXNlKG1vZGVsX3N0YXRlKSwgMylgIHBlcmNlbnRhZ2UgcG9pbnRzKiosIHJlc3BlY3RpdmVseS4NCg0KVGhlIG5lc3RlZC1tb2RlbCBGLXRlc3QgZXZhbHVhdGVzIHdoZXRoZXIgYWRkaW5nIHRoZSBzdGF0ZSBpbmRpY2F0b3JzIGltcHJvdmVzIG1vZGVsIGZpdC4gSXRzIHJlc3VsdCBzaG91bGQgYmUgaW50ZXJwcmV0ZWQgdG9nZXRoZXIgd2l0aCB0aGUgY2hhbmdlIGluIGFkanVzdGVkIFItc3F1YXJlZCBhbmQgUk1TRSwgcmF0aGVyIHRoYW4gcmVseWluZyBvbmx5IG9uIHRoZSBwLXZhbHVlLg0KDQojIyA2LjMgR2VvZ3JhcGhpYyBEaWZmZXJlbmNlcyBBZnRlciBBZGp1c3RtZW50DQoNClRoZSBzdGF0ZSBmaXhlZC1lZmZlY3RzIG1vZGVsIGV2YWx1YXRlcyB3aGV0aGVyIHN0YXRlIGluZGljYXRvcnMgY29sbGVjdGl2ZWx5IGV4cGxhaW4gYWRkaXRpb25hbCB2YXJpYXRpb24gYWZ0ZXIgYWNjb3VudGluZyBmb3IgdGhlIG1lYXN1cmVkIGNvdW50eSBjaGFyYWN0ZXJpc3RpY3MuIEEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBuZXN0ZWQtbW9kZWwgdGVzdCB3b3VsZCBpbmRpY2F0ZSB0aGF0IHN0YXRlIGluZGljYXRvcnMgYWRkIGV4cGxhbmF0b3J5IGluZm9ybWF0aW9uIGluIHRoaXMgc2FtcGxlLiBJdCB3b3VsZCBub3QgZGVtb25zdHJhdGUgdGhhdCBldmVyeSBzdGF0ZSBkaWZmZXJzIGZyb20gZXZlcnkgb3RoZXIgc3RhdGUsIG5vciB3b3VsZCBpdCBpZGVudGlmeSB0aGUgc3BlY2lmaWMgbG9jYWwgbWVjaGFuaXNtcyByZXNwb25zaWJsZSBmb3IgdGhlIGRpZmZlcmVuY2VzLg0KDQpUaGUgcmVzaWR1YWwgYW5hbHlzaXMgaWRlbnRpZmllcyBjb3VudGllcyB3aGVyZSBvYnNlcnZlZCBwcmV2YWxlbmNlIGRpZmZlcnMgbW9zdCBmcm9tIG1vZGVsIHByZWRpY3Rpb25zLiBUaGVzZSByZXNpZHVhbCBkaWZmZXJlbmNlcyBtYXkgcmVmbGVjdCB1bm1lYXN1cmVkIGNvdW50eSBjaGFyYWN0ZXJpc3RpY3MsIG1lYXN1cmVtZW50IGVycm9yLCBkaWZmZXJlbmNlcyBpbiBzb3VyY2UgeWVhcnMsIG1vZGVsIG1pc3NwZWNpZmljYXRpb24sIG9yIHNwYXRpYWxseSBwYXR0ZXJuZWQgZmFjdG9ycy4NCg0KIyMgNi40IE1vZGVsIERpYWdub3N0aWNzDQoNClRoZSBkaWFnbm9zdGljIHBsb3RzIGFuZCBWSUYgcmVzdWx0cyBzaG91bGQgYmUgcmV2aWV3ZWQgYmVmb3JlIGZpbmFsIGludGVycHJldGF0aW9uLiBQb3RlbnRpYWwgaXNzdWVzIGluY2x1ZGUgbm9ubGluZWFyaXR5LCBoZXRlcm9zY2VkYXN0aWNpdHksIGluZmx1ZW50aWFsIG9ic2VydmF0aW9ucywgYW5kIG11bHRpY29sbGluZWFyaXR5LiBIQzMgcm9idXN0IHN0YW5kYXJkIGVycm9ycyBoZWxwIGFkZHJlc3MgaGV0ZXJvc2NlZGFzdGljaXR5IGluIGNvZWZmaWNpZW50IHVuY2VydGFpbnR5IGVzdGltYXRlcywgYnV0IHRoZXkgZG8gbm90IGNvcnJlY3Qgc3BhdGlhbCBkZXBlbmRlbmNlIGJldHdlZW4gbmVpZ2hib3JpbmcgY291bnRpZXMuDQoNCiMgNy4gRGlzY3Vzc2lvbg0KDQpUaGUgcHVycG9zZSBvZiB0aGlzIHN0dWR5IGlzIHRvIGRldGVybWluZSB3aGV0aGVyIGdlb2dyYXBoaWMgZGlmZmVyZW5jZXMgaW4gYWR1bHQgb2Jlc2l0eSBwcmV2YWxlbmNlIHJlbWFpbiBhZnRlciBjb250cm9sbGluZyBmb3IgbWVhc3VyZWQgY291bnR5LWxldmVsIGNoYXJhY3RlcmlzdGljcy4gVGhlIGNvbXBhcmlzb24gYmV0d2VlbiB0aGUgYmFzZWxpbmUgT0xTIG1vZGVsIGFuZCB0aGUgc3RhdGUgZml4ZWQtZWZmZWN0cyBtb2RlbCBwcm92aWRlcyB0aGUgcHJpbWFyeSBldmlkZW5jZSBmb3IgZXZhbHVhdGluZyB0aGUgcmVzZWFyY2ggcXVlc3Rpb24uDQoNCioqQ29tcGxldGUgdGhpcyBkaXNjdXNzaW9uIGFmdGVyIHJldmlld2luZyB0aGUga25pdHRlZCByZXN1bHRzLioqIFNwZWNpZmljYWxseSwgZXhwbGFpbjoNCg0KMS4gV2hldGhlciB0aGUgY291bnR5LWxldmVsIG9iZXNpdHkgb3V0Y29tZSBzaG93cyBzdWJzdGFudGlhbCB2YXJpYXRpb24uDQoyLiBXaGljaCBtZWFzdXJlZCBwcmVkaWN0b3JzIGhhdmUgdGhlIGxhcmdlc3QgZXN0aW1hdGVkIGFzc29jaWF0aW9ucywgaW5jbHVkaW5nIHRoZWlyIGRpcmVjdGlvbiwgdW5pdHMsIGFuZCBjb25maWRlbmNlIGludGVydmFscy4NCjMuIFdoZXRoZXIgdGhlIHN0YXRlIGZpeGVkLWVmZmVjdHMgbW9kZWwgaW1wcm92ZXMgYWRqdXN0ZWQgUi1zcXVhcmVkIGFuZCBSTVNFLg0KNC4gV2hldGhlciB0aGUgbmVzdGVkLW1vZGVsIEYtdGVzdCBzdXBwb3J0cyB0aGUgY29uY2x1c2lvbiB0aGF0IHN0YXRlIGluZGljYXRvcnMgYWRkIGV4cGxhbmF0b3J5IGluZm9ybWF0aW9uLg0KNS4gV2hhdCB0aGUgcmVzaWR1YWwgZGlhZ25vc3RpY3Mgc3VnZ2VzdCBhYm91dCB1bmV4cGxhaW5lZCBjb3VudHktbGV2ZWwgZGlmZmVyZW5jZXMuDQoNClRoZSBmaW5kaW5ncyBzaG91bGQgYmUgY29tcGFyZWQgd2l0aCB0aGUgbGl0ZXJhdHVyZSByZXZpZXdlZCBpbiBTZWN0aW9uIDIuIEF2b2lkIGRlc2NyaWJpbmcgYW4gYXNzb2NpYXRpb24gYXMgYSBjYXVzYWwgZWZmZWN0LiBBIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgY29lZmZpY2llbnQgZG9lcyBub3QgbmVjZXNzYXJpbHkgaW5kaWNhdGUgYSBsYXJnZSBvciBwcmFjdGljYWxseSBpbXBvcnRhbnQgYXNzb2NpYXRpb24uDQoNCiMgOC4gTGltaXRhdGlvbnMNCg0KU2V2ZXJhbCBsaW1pdGF0aW9ucyBzaG91bGQgYmUgY29uc2lkZXJlZCB3aGVuIGludGVycHJldGluZyB0aGUgZmluZGluZ3MuDQoNCkZpcnN0LCB0aGUgc3R1ZHkgdXNlcyBhZ2dyZWdhdGVkIGNvdW50eS1sZXZlbCBkYXRhLiBDb3VudHktbGV2ZWwgYXNzb2NpYXRpb25zIGNhbm5vdCBhdXRvbWF0aWNhbGx5IGJlIGdlbmVyYWxpemVkIHRvIGluZGl2aWR1YWxzOyBkb2luZyBzbyB3b3VsZCByaXNrIGFuIGVjb2xvZ2ljYWwgZmFsbGFjeS4NCg0KU2Vjb25kLCB0aGUgb3V0Y29tZSBpcyBjYWxjdWxhdGVkIGFzIHRoZSBhcml0aG1ldGljIG1lYW4gb2YgbWFsZSBhbmQgZmVtYWxlIElITUUgMjAwOSBvYmVzaXR5IGVzdGltYXRlcy4gSXQgaXMgbm90IGEgcG9wdWxhdGlvbi13ZWlnaHRlZCBvdmVyYWxsIHByZXZhbGVuY2UgZXN0aW1hdGUuIFRoaXMgZGVmaW5pdGlvbiBzaG91bGQgYmUga2VwdCBleHBsaWNpdCB0aHJvdWdob3V0IHRoZSBwYXBlci4NCg0KVGhpcmQsIHRoZSBzb3VyY2UgZGF0YXNldHMgbWF5IHJlcHJlc2VudCBkaWZmZXJlbnQgeWVhcnMuIERpZmZlcmVuY2VzIGluIHRoZSB0aW1pbmcgb2Ygb2Jlc2l0eSwgcGh5c2ljYWwgYWN0aXZpdHksIHNvY2lvZWNvbm9taWMsIGZvb2QtcmVsYXRlZCwgYW5kIGVudmlyb25tZW50YWwgbWVhc3VyZW1lbnRzIG1heSBhZmZlY3QgdGhlIGVzdGltYXRlZCByZWxhdGlvbnNoaXBzLg0KDQpGb3VydGgsIHRoZSBhbmFseXNpcyByZWxpZXMgb24gY291bnR5LW5hbWUgYW5kIHN0YXRlLW5hbWUgc3RhbmRhcmRpemF0aW9uIGZvciBmaWxlcyB3aXRob3V0IGEgY29uc2lzdGVudGx5IGF2YWlsYWJsZSBGSVBTIGlkZW50aWZpZXIuIEFsdGhvdWdoIHN0YXRlLXBsdXMtY291bnR5IG1hdGNoaW5nIHJlZHVjZXMgYW1iaWd1aXR5LCBhIHZlcmlmaWVkIGZpdmUtZGlnaXQgRklQUyBjcm9zc3dhbGsgd291bGQgYmUgcHJlZmVyYWJsZSBmb3IgdGhlIGZpbmFsIGRhdGEgaW50ZWdyYXRpb24uDQoNCkZpZnRoLCB0aGUgc2VsZWN0ZWQgdmFyaWFibGVzIGRvIG5vdCBjYXB0dXJlIGV2ZXJ5IGZhY3RvciBhc3NvY2lhdGVkIHdpdGggb2Jlc2l0eS4gUG90ZW50aWFsbHkgcmVsZXZhbnQgb21pdHRlZCBjaGFyYWN0ZXJpc3RpY3MgaW5jbHVkZSBoZWFsdGhjYXJlIGFjY2VzcywgdHJhbnNwb3J0YXRpb24gaW5mcmFzdHJ1Y3R1cmUsIGRlbW9ncmFwaGljIGNvbXBvc2l0aW9uLCBob3VzaW5nLCBsb2NhbCBwb2xpY3ksIGFuZCBuZWlnaGJvcmhvb2QtbGV2ZWwgcmVzb3VyY2VzLg0KDQpTaXh0aCwgc3RhdGUgZml4ZWQgZWZmZWN0cyBjYXB0dXJlIGF2ZXJhZ2UgZGlmZmVyZW5jZXMgYmV0d2VlbiBzdGF0ZXMgYnV0IGRvIG5vdCBkaXJlY3RseSB0ZXN0IHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGFtb25nIG5laWdoYm9yaW5nIGNvdW50aWVzLiBBIHNlcGFyYXRlIHNwYXRpYWwgYW5hbHlzaXMgdXNpbmcgdmFsaWRhdGVkIGNvdW50eSBnZW9tZXRyaWVzIGFuZCBhIGRlZmVuc2libGUgc3BhdGlhbC13ZWlnaHRzIG1hdHJpeCB3b3VsZCBiZSBuZWVkZWQgdG8gYXNzZXNzIG5laWdoYm9yaW5nLWNvdW50eSBkZXBlbmRlbmNlLg0KDQpGaW5hbGx5LCBPTFMgZXN0aW1hdGVzIG1heSBiZSBzZW5zaXRpdmUgdG8gaW5mbHVlbnRpYWwgb2JzZXJ2YXRpb25zLCBtdWx0aWNvbGxpbmVhcml0eSwgaGV0ZXJvc2NlZGFzdGljaXR5LCBhbmQgbWVhc3VyZW1lbnQgZXJyb3IuIFRoZSBkaWFnbm9zdGljIHJlc3VsdHMgc2hvdWxkIHRoZXJlZm9yZSBiZSBjb25zaWRlcmVkIGFsb25nc2lkZSB0aGUgY29lZmZpY2llbnQgZXN0aW1hdGVzLg0KDQojIDkuIENvbmNsdXNpb24NCg0KVGhpcyBzdHVkeSBleGFtaW5lcyBjb3VudHktbGV2ZWwgZ2VvZ3JhcGhpYyBkaWZmZXJlbmNlcyBpbiBhZHVsdCBvYmVzaXR5IHByZXZhbGVuY2UgYWZ0ZXIgYWRqdXN0bWVudCBmb3IgbWVhc3VyZWQgYmVoYXZpb3JhbCwgc29jaW9lY29ub21pYywgZm9vZC1yZWxhdGVkLCBhbmQgZW52aXJvbm1lbnRhbCBjaGFyYWN0ZXJpc3RpY3MuIEl0IHVzZXMgYSBzZXF1ZW50aWFsIG1vZGVsaW5nIHN0cmF0ZWd5IHRoYXQgY29tcGFyZXMgYSBiYXNlbGluZSBPTFMgcmVncmVzc2lvbiB3aXRoIGEgbW9kZWwgY29udGFpbmluZyBzdGF0ZSBmaXhlZCBlZmZlY3RzLg0KDQpUaGUgZmluYWwgY29uY2x1c2lvbiBzaG91bGQgYmUgY29tcGxldGVkIGFmdGVyIHRoZSBkYXRhIGFuZCBtb2RlbCBvdXRwdXRzIGhhdmUgYmVlbiByZXZpZXdlZC4gSXQgc2hvdWxkIHN0YXRlIGhvdyBtdWNoIHZhcmlhdGlvbiB0aGUgYmFzZWxpbmUgbW9kZWwgZXhwbGFpbnMsIHdoZXRoZXIgdGhlIHN0YXRlIGZpeGVkLWVmZmVjdHMgbW9kZWwgYWRkcyBleHBsYW5hdG9yeSB2YWx1ZSwgd2hpY2ggbWVhc3VyZWQgYXNzb2NpYXRpb25zIGFyZSBtb3N0IGltcG9ydGFudCwgYW5kIHdoYXQgZ2VvZ3JhcGhpYyBkaWZmZXJlbmNlcyByZW1haW4gdW5leHBsYWluZWQuDQoNClRoZSBmaW5kaW5ncyBzaG91bGQgYmUgaW50ZXJwcmV0ZWQgYXMgY291bnR5LWxldmVsIG9ic2VydmF0aW9uYWwgYXNzb2NpYXRpb25zLiBUaGV5IG1heSBoZWxwIGlkZW50aWZ5IGdlb2dyYXBoaWMgcGF0dGVybnMgdGhhdCB3YXJyYW50IGFkZGl0aW9uYWwgcHVibGljLWhlYWx0aCBpbnZlc3RpZ2F0aW9uLCBidXQgdGhleSBkbyBub3QgZXN0YWJsaXNoIGNhdXNhbCBlZmZlY3RzIG9yIGV4cGxhaW4gYWxsIHNvdXJjZXMgb2Ygb2Jlc2l0eSBkaWZmZXJlbmNlcyBhY3Jvc3MgY29tbXVuaXRpZXMuDQoNCiMgMTAuIFJlcHJvZHVjaWJpbGl0eSBhbmQgRmluYWwgQ2hlY2tzDQoNClRoZSBhbmFseXNpcyBpcyBkZXNpZ25lZCB0byBiZSByZXByb2R1Y2libGUgZnJvbSB0aGUgcHVibGljIHByb2plY3QgcmVwb3NpdG9yeS4gQmVmb3JlIHN1Ym1pc3Npb24sIGNvbmZpcm0gdGhhdCB0aGUgcmVwb3NpdG9yeSBmaWxlcyBoYXZlIG5vdCBjaGFuZ2VkLCB0aGF0IGVhY2ggc291cmNlIGNvbHVtbiB3YXMgbWFwcGVkIGNvcnJlY3RseSwgYW5kIHRoYXQgdGhlIGZpbmFsIGNvbXBsZXRlLWNhc2Ugc2FtcGxlIGlzIGFwcHJvcHJpYXRlIGZvciB0aGUgcmVzZWFyY2ggcXVlc3Rpb24uDQoNCmBgYHtyIGZpbmFsLWNoZWNrc30NCmZpbmFsX2NoZWNrcyA8LSB0aWJibGUoDQogIENoZWNrID0gYygNCiAgICAiT3V0Y29tZSB2YXJpYWJsZSBwcmVzZW50IiwNCiAgICAiQXQgbGVhc3QgMyBwcmVkaWN0b3JzIGluY2x1ZGVkIiwNCiAgICAiUmVncmVzc2lvbiBzYW1wbGUgaGFzIGF0IGxlYXN0IDEwMCBjb3VudGllcyIsDQogICAgIk1vcmUgdGhhbiBvbmUgc3RhdGUgcmVwcmVzZW50ZWQiLA0KICAgICJCYXNlbGluZSBhbmQgc3RhdGUgbW9kZWxzIHVzZSBzYW1lIG9ic2VydmF0aW9ucyIsDQogICAgIk1vZGVsIGNvZWZmaWNpZW50cyBhcmUgZmluaXRlIg0KICApLA0KICBQYXNzZWQgPSBjKA0KICAgICJhZHVsdF9vYmVzaXR5IiAlaW4lIG5hbWVzKG1vZGVsX2RhdGEpLA0KICAgIGxlbmd0aChhdmFpbGFibGVfcHJlZGljdG9ycykgPj0gMywNCiAgICBucm93KG1vZGVsX2RhdGEpID49IDEwMCwNCiAgICBuX2Rpc3RpbmN0KG1vZGVsX2RhdGEkU3RhdGUpID4gMSwNCiAgICBub2JzKG1vZGVsX29scykgPT0gbm9icyhtb2RlbF9zdGF0ZSksDQogICAgYWxsKGlzLmZpbml0ZShjb2VmKG1vZGVsX3N0YXRlKSkpDQogICkNCikNCg0Ka25pdHI6OmthYmxlKA0KICBmaW5hbF9jaGVja3MsDQogIGNhcHRpb24gPSAiUmVwcm9kdWNpYmlsaXR5IGFuZCBtb2RlbCB2YWxpZGF0aW9uIGNoZWNrcyINCikgJT4lDQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFKQ0KYGBgDQoNCiMgUmVmZXJlbmNlcw0KDQpBaGVybiwgTS4sIEJyb3duLCBDLiwgJiBEdWthcywgUy4gKDIwMTEpLiBBIG5hdGlvbmFsIHN0dWR5IG9mIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGZvb2QgZW52aXJvbm1lbnRzIGFuZCBjb3VudHktbGV2ZWwgaGVhbHRoIG91dGNvbWVzLiAqVGhlIEpvdXJuYWwgb2YgUnVyYWwgSGVhbHRoKi4gW1ZlcmlmeSB2b2x1bWUsIGlzc3VlLCBwYWdlcywgYW5kIERPSSBiZWZvcmUgc3VibWlzc2lvbi5dDQoNCkFuLCBSLiwgTGksIFguLCAmIEppYW5nLCBOLiAoMjAxNykuIEdlb2dyYXBoaWNhbCB2YXJpYXRpb25zIGluIHRoZSBlbnZpcm9ubWVudGFsIGRldGVybWluYW50cyBvZiBwaHlzaWNhbCBpbmFjdGl2aXR5IGFtb25nIFUuUy4gYWR1bHRzLiBbVmVyaWZ5IGNvbXBsZXRlIHB1YmxpY2F0aW9uIGRldGFpbHMgYmVmb3JlIHN1Ym1pc3Npb24uXQ0KDQpDZW50ZXJzIGZvciBEaXNlYXNlIENvbnRyb2wgYW5kIFByZXZlbnRpb24uIChuLmQuKS4gKk5vcnRoIEFtZXJpY2EgTGFuZCBEYXRhIEFzc2ltaWxhdGlvbiBTeXN0ZW0gKE5MREFTKSBkYWlseSBzdW5saWdodCAoa0ovbcKyKSwgMTk3OeKAkzIwMTEqLiBodHRwczovL3dvbmRlci5jZGMuZ292L2NvbnRyb2xsZXIvZGF0YXJlcXVlc3QvRDgwDQoNCkZlZWRpbmcgQW1lcmljYS4gKG4uZC4pLiAqTWFwIHRoZSBNZWFsIEdhcDogQ291bnR5LWxldmVsIGZvb2QgaW5zZWN1cml0eSBkYXRhKi4gaHR0cHM6Ly93d3cuZmVlZGluZ2FtZXJpY2Eub3JnL3Jlc2VhcmNoL21hcC10aGUtbWVhbC1nYXAvYnktY291bnR5DQoNCkhhbW1hcnN0csO2bSwgQS4sIEphbmxlcnQsIFUuLCAmIFdpbmVmaWVsZCwgSC4gKDIwMTQpLiBMZW5ndGggb2YgdW5lbXBsb3ltZW50IGFuZCBoZWFsdGgtcmVsYXRlZCBvdXRjb21lcy4gW1ZlcmlmeSBjb21wbGV0ZSBwdWJsaWNhdGlvbiBkZXRhaWxzIGJlZm9yZSBzdWJtaXNzaW9uLl0NCg0KSG9saWNrLCBNLiBGLiwgJiBXYWNrZXIsIE0uICgyMDEzKS4gKlN1bmxpZ2h0IGFuZCB2aXRhbWluIEQqLiBbVmVyaWZ5IHB1Ymxpc2hlciBhbmQgZWRpdGlvbiBvciBhcnRpY2xlIGRldGFpbHMgYmVmb3JlIHN1Ym1pc3Npb24uXQ0KDQpJbnN0aXR1dGUgZm9yIEhlYWx0aCBNZXRyaWNzIGFuZCBFdmFsdWF0aW9uLiAobi5kLikuICpVbml0ZWQgU3RhdGVzIGFsY29ob2wgdXNlIHByZXZhbGVuY2UgYnkgY291bnR5LCAyMDAy4oCTMjAxMiouIEdsb2JhbCBIZWFsdGggRGF0YSBFeGNoYW5nZS4gaHR0cDovL2doZHguaGVhbHRoZGF0YS5vcmcvcmVjb3JkL2lobWUtZGF0YS91bml0ZWQtc3RhdGVzLWFsY29ob2wtdXNlLXByZXZhbGVuY2UtY291bnR5LTIwMDItMjAxMg0KDQpJbnN0aXR1dGUgZm9yIEhlYWx0aCBNZXRyaWNzIGFuZCBFdmFsdWF0aW9uLiAobi5kLikuICpVbml0ZWQgU3RhdGVzIHBoeXNpY2FsIGFjdGl2aXR5IGFuZCBvYmVzaXR5IHByZXZhbGVuY2UgYnkgY291bnR5Ki4gR2xvYmFsIEhlYWx0aCBEYXRhIEV4Y2hhbmdlLiBodHRwczovL2doZHguaGVhbHRoZGF0YS5vcmcvDQoNClUuUy4gQ2Vuc3VzIEJ1cmVhdS4gKDIwMTkpLiAqU21hbGwgQXJlYSBJbmNvbWUgYW5kIFBvdmVydHkgRXN0aW1hdGVzIChTQUlQRSk6IFN0YXRlIGFuZCBjb3VudHkgZXN0aW1hdGVzKi4gaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9kYXRhL2RhdGFzZXRzLzIwMTkvZGVtby9zYWlwZS8yMDE5LXN0YXRlLWFuZC1jb3VudHkuaHRtbA0KDQpVLlMuIERlcGFydG1lbnQgb2YgQWdyaWN1bHR1cmUsIEVjb25vbWljIFJlc2VhcmNoIFNlcnZpY2UuIChuLmQuKS4gKkNvdW50eS1sZXZlbCBkYXRhIHNldHMqLiBodHRwczovL3d3dy5lcnMudXNkYS5nb3YvZGF0YS1wcm9kdWN0cy9jb3VudHktbGV2ZWwtZGF0YS1zZXRzL2Rvd25sb2FkLWRhdGEvDQoNClUuUy4gRW52aXJvbm1lbnRhbCBQcm90ZWN0aW9uIEFnZW5jeS4gKG4uZC4pLiAqRW52aXJvbm1lbnRhbCBRdWFsaXR5IEluZGV4IChFUUkpLCAyMDA24oCTMjAxMCouIGh0dHBzOi8vZWRnLmVwYS5nb3YvRVBBRGF0YUNvbW1vbnMvcHVibGljL09SRC9DUEhFQS9FUUlfMjAwNl8yMDEwLw0KDQotLS0NCg0KKipTdWJtaXNzaW9uIG5vdGU6KiogQ29tcGxldGUgdGhlIGRpc2N1c3Npb24gYW5kIGNvbmNsdXNpb24gdXNpbmcgdGhlIGFjdHVhbCBvdXRwdXQgZnJvbSB0aGUgZmluYWwga25pdC4gVmVyaWZ5IGV2ZXJ5IGxpdGVyYXR1cmUgcmVmZXJlbmNlJ3MgZnVsbCBiaWJsaW9ncmFwaGljIGRldGFpbHMgYW5kIGFkZCBpbi10ZXh0IGNpdGF0aW9ucyB3aGVyZSB0aGUgY2l0ZWQgc3R1ZGllcyBhcmUgZGlzY3Vzc2VkLiBUaGUgZmluYWwgcGFwZXIgc2hvdWxkIG5vdCBiZSBzdWJtaXR0ZWQgd2l0aCB1bnJlc29sdmVkIHNvdXJjZSBtYXBwaW5ncywgaW5jb21wbGV0ZSByZWZlcmVuY2VzLCBvciB1bnJldmlld2VkIG1vZGVsIGRpYWdub3N0aWNzLg0K